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 C6DC915817D for ; Wed, 12 Jun 2024 10:23:34 +0000 (UTC) Received: from pigeon.gentoo.org (localhost [127.0.0.1]) by pigeon.gentoo.org (Postfix) with SMTP id 03C922BC01C; Wed, 12 Jun 2024 10:23:34 +0000 (UTC) Received: from smtp.gentoo.org (woodpecker.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)) (No client certificate requested) by pigeon.gentoo.org (Postfix) with ESMTPS id 616B12BC01C for ; Wed, 12 Jun 2024 10:23:33 +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)) (No client certificate requested) by smtp.gentoo.org (Postfix) with ESMTPS id 94C78335C96 for ; Wed, 12 Jun 2024 10:23:31 +0000 (UTC) Received: from localhost.localdomain (localhost [IPv6:::1]) by oystercatcher.gentoo.org (Postfix) with ESMTP id 2E8F51BD9 for ; Wed, 12 Jun 2024 10:23:30 +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: <1718187302.0ec884187c00ecdddf673fdfd0fca72f83445ac5.mpagano@gentoo> Subject: [gentoo-commits] proj/linux-patches:6.6 commit in: / X-VCS-Repository: proj/linux-patches X-VCS-Files: 0000_README 1032_linux-6.6.33.patch X-VCS-Directories: / X-VCS-Committer: mpagano X-VCS-Committer-Name: Mike Pagano X-VCS-Revision: 0ec884187c00ecdddf673fdfd0fca72f83445ac5 X-VCS-Branch: 6.6 Date: Wed, 12 Jun 2024 10:23:30 +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: 3f65f952-b518-4b33-9dd9-05553b48b915 X-Archives-Hash: 7863a866ff995753f9356d6af8c2e7e3 commit: 0ec884187c00ecdddf673fdfd0fca72f83445ac5 Author: Mike Pagano gentoo org> AuthorDate: Wed Jun 12 10:15:02 2024 +0000 Commit: Mike Pagano gentoo org> CommitDate: Wed Jun 12 10:15:02 2024 +0000 URL: https://gitweb.gentoo.org/proj/linux-patches.git/commit/?id=0ec88418 Linux patch 6.6.33 Signed-off-by: Mike Pagano gentoo.org> 0000_README | 4 + 1032_linux-6.6.33.patch | 38477 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 38481 insertions(+) diff --git a/0000_README b/0000_README index cb42c9a0..1535ef3d 100644 --- a/0000_README +++ b/0000_README @@ -171,6 +171,10 @@ Patch: 1031_linux-6.6.32.patch From: https://www.kernel.org Desc: Linux 6.6.32 +Patch: 1032_linux-6.6.33.patch +From: https://www.kernel.org +Desc: Linux 6.6.33 + 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/1032_linux-6.6.33.patch b/1032_linux-6.6.33.patch new file mode 100644 index 00000000..29c9d3ad --- /dev/null +++ b/1032_linux-6.6.33.patch @@ -0,0 +1,38477 @@ +diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt +index 66dfc348043d6..8d2f9ed3f1076 100644 +--- a/Documentation/admin-guide/kernel-parameters.txt ++++ b/Documentation/admin-guide/kernel-parameters.txt +@@ -3323,6 +3323,9 @@ + arch-independent options, each of which is an + aggregation of existing arch-specific options. + ++ Note, "mitigations" is supported if and only if the ++ kernel was built with CPU_MITIGATIONS=y. ++ + off + Disable all optional CPU mitigations. This + improves system performance, but it may also +diff --git a/Documentation/devicetree/bindings/iio/adc/adi,axi-adc.yaml b/Documentation/devicetree/bindings/iio/adc/adi,axi-adc.yaml +index 9996dd93f84b2..e1f450b80db27 100644 +--- a/Documentation/devicetree/bindings/iio/adc/adi,axi-adc.yaml ++++ b/Documentation/devicetree/bindings/iio/adc/adi,axi-adc.yaml +@@ -28,6 +28,9 @@ properties: + reg: + maxItems: 1 + ++ clocks: ++ maxItems: 1 ++ + dmas: + maxItems: 1 + +@@ -39,12 +42,16 @@ properties: + $ref: /schemas/types.yaml#/definitions/phandle + description: + A reference to a the actual ADC to which this FPGA ADC interfaces to. ++ deprecated: true ++ ++ '#io-backend-cells': ++ const: 0 + + required: + - compatible + - dmas + - reg +- - adi,adc-dev ++ - clocks + + additionalProperties: false + +@@ -55,7 +62,7 @@ examples: + reg = <0x44a00000 0x10000>; + dmas = <&rx_dma 0>; + dma-names = "rx"; +- +- adi,adc-dev = <&spi_adc>; ++ clocks = <&axi_clk>; ++ #io-backend-cells = <0>; + }; + ... +diff --git a/Documentation/devicetree/bindings/media/i2c/ovti,ov2680.yaml b/Documentation/devicetree/bindings/media/i2c/ovti,ov2680.yaml +index cf456f8d9ddcb..c87677f5e2a25 100644 +--- a/Documentation/devicetree/bindings/media/i2c/ovti,ov2680.yaml ++++ b/Documentation/devicetree/bindings/media/i2c/ovti,ov2680.yaml +@@ -37,15 +37,15 @@ properties: + active low. + maxItems: 1 + +- dovdd-supply: ++ DOVDD-supply: + description: + Definition of the regulator used as interface power supply. + +- avdd-supply: ++ AVDD-supply: + description: + Definition of the regulator used as analog power supply. + +- dvdd-supply: ++ DVDD-supply: + description: + Definition of the regulator used as digital power supply. + +@@ -59,9 +59,9 @@ required: + - reg + - clocks + - clock-names +- - dovdd-supply +- - avdd-supply +- - dvdd-supply ++ - DOVDD-supply ++ - AVDD-supply ++ - DVDD-supply + - reset-gpios + - port + +@@ -82,9 +82,9 @@ examples: + clock-names = "xvclk"; + reset-gpios = <&gpio1 3 GPIO_ACTIVE_LOW>; + +- dovdd-supply = <&sw2_reg>; +- dvdd-supply = <&sw2_reg>; +- avdd-supply = <®_peri_3p15v>; ++ DOVDD-supply = <&sw2_reg>; ++ DVDD-supply = <&sw2_reg>; ++ AVDD-supply = <®_peri_3p15v>; + + port { + ov2680_to_mipi: endpoint { +diff --git a/Documentation/devicetree/bindings/pci/rcar-pci-host.yaml b/Documentation/devicetree/bindings/pci/rcar-pci-host.yaml +index 8fdfbc763d704..835b6db00c279 100644 +--- a/Documentation/devicetree/bindings/pci/rcar-pci-host.yaml ++++ b/Documentation/devicetree/bindings/pci/rcar-pci-host.yaml +@@ -68,6 +68,18 @@ properties: + phy-names: + const: pcie + ++ vpcie1v5-supply: ++ description: The 1.5v regulator to use for PCIe. ++ ++ vpcie3v3-supply: ++ description: The 3.3v regulator to use for PCIe. ++ ++ vpcie12v-supply: ++ description: The 12v regulator to use for PCIe. ++ ++ iommu-map: true ++ iommu-map-mask: true ++ + required: + - compatible + - reg +@@ -121,5 +133,7 @@ examples: + clock-names = "pcie", "pcie_bus"; + power-domains = <&sysc R8A7791_PD_ALWAYS_ON>; + resets = <&cpg 319>; ++ vpcie3v3-supply = <&pcie_3v3>; ++ vpcie12v-supply = <&pcie_12v>; + }; + }; +diff --git a/Documentation/devicetree/bindings/pci/rockchip,rk3399-pcie.yaml b/Documentation/devicetree/bindings/pci/rockchip,rk3399-pcie.yaml +index 531008f0b6ac3..002b728cbc718 100644 +--- a/Documentation/devicetree/bindings/pci/rockchip,rk3399-pcie.yaml ++++ b/Documentation/devicetree/bindings/pci/rockchip,rk3399-pcie.yaml +@@ -37,6 +37,7 @@ properties: + description: This property is needed if using 24MHz OSC for RC's PHY. + + ep-gpios: ++ maxItems: 1 + description: pre-reset GPIO + + vpcie12v-supply: +diff --git a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-ufs-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-ufs-phy.yaml +index d981d77e82e40..a6244c33faf61 100644 +--- a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-ufs-phy.yaml ++++ b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-ufs-phy.yaml +@@ -71,7 +71,6 @@ required: + - reg + - clocks + - clock-names +- - power-domains + - resets + - reset-names + - vdda-phy-supply +@@ -130,6 +129,21 @@ allOf: + clock-names: + maxItems: 1 + ++ - if: ++ properties: ++ compatible: ++ contains: ++ enum: ++ - qcom,msm8996-qmp-ufs-phy ++ - qcom,msm8998-qmp-ufs-phy ++ then: ++ properties: ++ power-domains: ++ false ++ else: ++ required: ++ - power-domains ++ + additionalProperties: false + + examples: +diff --git a/Documentation/devicetree/bindings/phy/qcom,usb-snps-femto-v2.yaml b/Documentation/devicetree/bindings/phy/qcom,usb-snps-femto-v2.yaml +index 0f200e3f97a9a..fce7f8a19e9c0 100644 +--- a/Documentation/devicetree/bindings/phy/qcom,usb-snps-femto-v2.yaml ++++ b/Documentation/devicetree/bindings/phy/qcom,usb-snps-femto-v2.yaml +@@ -15,9 +15,6 @@ description: | + properties: + compatible: + oneOf: +- - enum: +- - qcom,sc8180x-usb-hs-phy +- - qcom,usb-snps-femto-v2-phy + - items: + - enum: + - qcom,sa8775p-usb-hs-phy +@@ -26,6 +23,7 @@ properties: + - items: + - enum: + - qcom,sc7280-usb-hs-phy ++ - qcom,sc8180x-usb-hs-phy + - qcom,sdx55-usb-hs-phy + - qcom,sdx65-usb-hs-phy + - qcom,sm6375-usb-hs-phy +diff --git a/Documentation/devicetree/bindings/pinctrl/mediatek,mt7622-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/mediatek,mt7622-pinctrl.yaml +index bd72a326e6e06..60f30a59f3853 100644 +--- a/Documentation/devicetree/bindings/pinctrl/mediatek,mt7622-pinctrl.yaml ++++ b/Documentation/devicetree/bindings/pinctrl/mediatek,mt7622-pinctrl.yaml +@@ -97,7 +97,8 @@ patternProperties: + then: + properties: + groups: +- enum: [emmc, emmc_rst] ++ items: ++ enum: [emmc, emmc_rst] + - if: + properties: + function: +@@ -105,8 +106,9 @@ patternProperties: + then: + properties: + groups: +- enum: [esw, esw_p0_p1, esw_p2_p3_p4, rgmii_via_esw, +- rgmii_via_gmac1, rgmii_via_gmac2, mdc_mdio] ++ items: ++ enum: [esw, esw_p0_p1, esw_p2_p3_p4, rgmii_via_esw, ++ rgmii_via_gmac1, rgmii_via_gmac2, mdc_mdio] + - if: + properties: + function: +@@ -123,10 +125,11 @@ patternProperties: + then: + properties: + groups: +- enum: [i2s_in_mclk_bclk_ws, i2s1_in_data, i2s2_in_data, +- i2s3_in_data, i2s4_in_data, i2s_out_mclk_bclk_ws, +- i2s1_out_data, i2s2_out_data, i2s3_out_data, +- i2s4_out_data] ++ items: ++ enum: [i2s_in_mclk_bclk_ws, i2s1_in_data, i2s2_in_data, ++ i2s3_in_data, i2s4_in_data, i2s_out_mclk_bclk_ws, ++ i2s1_out_data, i2s2_out_data, i2s3_out_data, ++ i2s4_out_data] + - if: + properties: + function: +@@ -159,10 +162,11 @@ patternProperties: + then: + properties: + groups: +- enum: [pcie0_0_waken, pcie0_1_waken, pcie1_0_waken, +- pcie0_0_clkreq, pcie0_1_clkreq, pcie1_0_clkreq, +- pcie0_pad_perst, pcie1_pad_perst, pcie_pereset, +- pcie_wake, pcie_clkreq] ++ items: ++ enum: [pcie0_0_waken, pcie0_1_waken, pcie1_0_waken, ++ pcie0_0_clkreq, pcie0_1_clkreq, pcie1_0_clkreq, ++ pcie0_pad_perst, pcie1_pad_perst, pcie_pereset, ++ pcie_wake, pcie_clkreq] + - if: + properties: + function: +@@ -178,11 +182,12 @@ patternProperties: + then: + properties: + groups: +- enum: [pwm_ch1_0, pwm_ch1_1, pwm_ch1_2, pwm_ch2_0, pwm_ch2_1, +- pwm_ch2_2, pwm_ch3_0, pwm_ch3_1, pwm_ch3_2, pwm_ch4_0, +- pwm_ch4_1, pwm_ch4_2, pwm_ch4_3, pwm_ch5_0, pwm_ch5_1, +- pwm_ch5_2, pwm_ch6_0, pwm_ch6_1, pwm_ch6_2, pwm_ch6_3, +- pwm_ch7_0, pwm_0, pwm_1] ++ items: ++ enum: [pwm_ch1_0, pwm_ch1_1, pwm_ch1_2, pwm_ch2_0, pwm_ch2_1, ++ pwm_ch2_2, pwm_ch3_0, pwm_ch3_1, pwm_ch3_2, pwm_ch4_0, ++ pwm_ch4_1, pwm_ch4_2, pwm_ch4_3, pwm_ch5_0, pwm_ch5_1, ++ pwm_ch5_2, pwm_ch6_0, pwm_ch6_1, pwm_ch6_2, pwm_ch6_3, ++ pwm_ch7_0, pwm_0, pwm_1] + - if: + properties: + function: +@@ -260,33 +265,34 @@ patternProperties: + pins: + description: + An array of strings. Each string contains the name of a pin. +- enum: [GPIO_A, I2S1_IN, I2S1_OUT, I2S_BCLK, I2S_WS, I2S_MCLK, TXD0, +- RXD0, SPI_WP, SPI_HOLD, SPI_CLK, SPI_MOSI, SPI_MISO, SPI_CS, +- I2C_SDA, I2C_SCL, I2S2_IN, I2S3_IN, I2S4_IN, I2S2_OUT, +- I2S3_OUT, I2S4_OUT, GPIO_B, MDC, MDIO, G2_TXD0, G2_TXD1, +- G2_TXD2, G2_TXD3, G2_TXEN, G2_TXC, G2_RXD0, G2_RXD1, G2_RXD2, +- G2_RXD3, G2_RXDV, G2_RXC, NCEB, NWEB, NREB, NDL4, NDL5, NDL6, +- NDL7, NRB, NCLE, NALE, NDL0, NDL1, NDL2, NDL3, MDI_TP_P0, +- MDI_TN_P0, MDI_RP_P0, MDI_RN_P0, MDI_TP_P1, MDI_TN_P1, +- MDI_RP_P1, MDI_RN_P1, MDI_RP_P2, MDI_RN_P2, MDI_TP_P2, +- MDI_TN_P2, MDI_TP_P3, MDI_TN_P3, MDI_RP_P3, MDI_RN_P3, +- MDI_RP_P4, MDI_RN_P4, MDI_TP_P4, MDI_TN_P4, PMIC_SCL, +- PMIC_SDA, SPIC1_CLK, SPIC1_MOSI, SPIC1_MISO, SPIC1_CS, +- GPIO_D, WATCHDOG, RTS3_N, CTS3_N, TXD3, RXD3, PERST0_N, +- PERST1_N, WLED_N, EPHY_LED0_N, AUXIN0, AUXIN1, AUXIN2, +- AUXIN3, TXD4, RXD4, RTS4_N, CST4_N, PWM1, PWM2, PWM3, PWM4, +- PWM5, PWM6, PWM7, GPIO_E, TOP_5G_CLK, TOP_5G_DATA, +- WF0_5G_HB0, WF0_5G_HB1, WF0_5G_HB2, WF0_5G_HB3, WF0_5G_HB4, +- WF0_5G_HB5, WF0_5G_HB6, XO_REQ, TOP_RST_N, SYS_WATCHDOG, +- EPHY_LED0_N_JTDO, EPHY_LED1_N_JTDI, EPHY_LED2_N_JTMS, +- EPHY_LED3_N_JTCLK, EPHY_LED4_N_JTRST_N, WF2G_LED_N, +- WF5G_LED_N, GPIO_9, GPIO_10, GPIO_11, GPIO_12, UART1_TXD, +- UART1_RXD, UART1_CTS, UART1_RTS, UART2_TXD, UART2_RXD, +- UART2_CTS, UART2_RTS, SMI_MDC, SMI_MDIO, PCIE_PERESET_N, +- PWM_0, GPIO_0, GPIO_1, GPIO_2, GPIO_3, GPIO_4, GPIO_5, +- GPIO_6, GPIO_7, GPIO_8, UART0_TXD, UART0_RXD, TOP_2G_CLK, +- TOP_2G_DATA, WF0_2G_HB0, WF0_2G_HB1, WF0_2G_HB2, WF0_2G_HB3, +- WF0_2G_HB4, WF0_2G_HB5, WF0_2G_HB6] ++ items: ++ enum: [GPIO_A, I2S1_IN, I2S1_OUT, I2S_BCLK, I2S_WS, I2S_MCLK, TXD0, ++ RXD0, SPI_WP, SPI_HOLD, SPI_CLK, SPI_MOSI, SPI_MISO, SPI_CS, ++ I2C_SDA, I2C_SCL, I2S2_IN, I2S3_IN, I2S4_IN, I2S2_OUT, ++ I2S3_OUT, I2S4_OUT, GPIO_B, MDC, MDIO, G2_TXD0, G2_TXD1, ++ G2_TXD2, G2_TXD3, G2_TXEN, G2_TXC, G2_RXD0, G2_RXD1, G2_RXD2, ++ G2_RXD3, G2_RXDV, G2_RXC, NCEB, NWEB, NREB, NDL4, NDL5, NDL6, ++ NDL7, NRB, NCLE, NALE, NDL0, NDL1, NDL2, NDL3, MDI_TP_P0, ++ MDI_TN_P0, MDI_RP_P0, MDI_RN_P0, MDI_TP_P1, MDI_TN_P1, ++ MDI_RP_P1, MDI_RN_P1, MDI_RP_P2, MDI_RN_P2, MDI_TP_P2, ++ MDI_TN_P2, MDI_TP_P3, MDI_TN_P3, MDI_RP_P3, MDI_RN_P3, ++ MDI_RP_P4, MDI_RN_P4, MDI_TP_P4, MDI_TN_P4, PMIC_SCL, ++ PMIC_SDA, SPIC1_CLK, SPIC1_MOSI, SPIC1_MISO, SPIC1_CS, ++ GPIO_D, WATCHDOG, RTS3_N, CTS3_N, TXD3, RXD3, PERST0_N, ++ PERST1_N, WLED_N, EPHY_LED0_N, AUXIN0, AUXIN1, AUXIN2, ++ AUXIN3, TXD4, RXD4, RTS4_N, CST4_N, PWM1, PWM2, PWM3, PWM4, ++ PWM5, PWM6, PWM7, GPIO_E, TOP_5G_CLK, TOP_5G_DATA, ++ WF0_5G_HB0, WF0_5G_HB1, WF0_5G_HB2, WF0_5G_HB3, WF0_5G_HB4, ++ WF0_5G_HB5, WF0_5G_HB6, XO_REQ, TOP_RST_N, SYS_WATCHDOG, ++ EPHY_LED0_N_JTDO, EPHY_LED1_N_JTDI, EPHY_LED2_N_JTMS, ++ EPHY_LED3_N_JTCLK, EPHY_LED4_N_JTRST_N, WF2G_LED_N, ++ WF5G_LED_N, GPIO_9, GPIO_10, GPIO_11, GPIO_12, UART1_TXD, ++ UART1_RXD, UART1_CTS, UART1_RTS, UART2_TXD, UART2_RXD, ++ UART2_CTS, UART2_RTS, SMI_MDC, SMI_MDIO, PCIE_PERESET_N, ++ PWM_0, GPIO_0, GPIO_1, GPIO_2, GPIO_3, GPIO_4, GPIO_5, ++ GPIO_6, GPIO_7, GPIO_8, UART0_TXD, UART0_RXD, TOP_2G_CLK, ++ TOP_2G_DATA, WF0_2G_HB0, WF0_2G_HB1, WF0_2G_HB2, WF0_2G_HB3, ++ WF0_2G_HB4, WF0_2G_HB5, WF0_2G_HB6] + + bias-disable: true + +diff --git a/Documentation/devicetree/bindings/soc/rockchip/grf.yaml b/Documentation/devicetree/bindings/soc/rockchip/grf.yaml +index e4fa6a07b4fa2..be6ffec2b0749 100644 +--- a/Documentation/devicetree/bindings/soc/rockchip/grf.yaml ++++ b/Documentation/devicetree/bindings/soc/rockchip/grf.yaml +@@ -163,6 +163,7 @@ allOf: + unevaluatedProperties: false + + pcie-phy: ++ type: object + description: + Documentation/devicetree/bindings/phy/rockchip-pcie-phy.txt + +diff --git a/Documentation/devicetree/bindings/sound/rt5645.txt b/Documentation/devicetree/bindings/sound/rt5645.txt +index 41a62fd2ae1ff..c1fa379f5f3ea 100644 +--- a/Documentation/devicetree/bindings/sound/rt5645.txt ++++ b/Documentation/devicetree/bindings/sound/rt5645.txt +@@ -20,6 +20,11 @@ Optional properties: + a GPIO spec for the external headphone detect pin. If jd-mode = 0, + we will get the JD status by getting the value of hp-detect-gpios. + ++- cbj-sleeve-gpios: ++ a GPIO spec to control the external combo jack circuit to tie the sleeve/ring2 ++ contacts to the ground or floating. It could avoid some electric noise from the ++ active speaker jacks. ++ + - realtek,in2-differential + Boolean. Indicate MIC2 input are differential, rather than single-ended. + +@@ -68,6 +73,7 @@ codec: rt5650@1a { + compatible = "realtek,rt5650"; + reg = <0x1a>; + hp-detect-gpios = <&gpio 19 0>; ++ cbj-sleeve-gpios = <&gpio 20 0>; + interrupt-parent = <&gpio>; + interrupts = <7 IRQ_TYPE_EDGE_FALLING>; + realtek,dmic-en = "true"; +diff --git a/Documentation/devicetree/bindings/spmi/hisilicon,hisi-spmi-controller.yaml b/Documentation/devicetree/bindings/spmi/hisilicon,hisi-spmi-controller.yaml +index f882903769f95..eee7c8d4cf4a2 100644 +--- a/Documentation/devicetree/bindings/spmi/hisilicon,hisi-spmi-controller.yaml ++++ b/Documentation/devicetree/bindings/spmi/hisilicon,hisi-spmi-controller.yaml +@@ -14,7 +14,7 @@ description: | + It is a MIPI System Power Management (SPMI) controller. + + The PMIC part is provided by +- ./Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml. ++ Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml. + + allOf: + - $ref: spmi.yaml# +@@ -48,7 +48,7 @@ patternProperties: + PMIC properties, which are specific to the used SPMI PMIC device(s). + When used in combination with HiSilicon 6421v600, the properties + are documented at +- drivers/staging/hikey9xx/hisilicon,hi6421-spmi-pmic.yaml. ++ Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml + + unevaluatedProperties: false + +diff --git a/Documentation/devicetree/bindings/thermal/loongson,ls2k-thermal.yaml b/Documentation/devicetree/bindings/thermal/loongson,ls2k-thermal.yaml +index 7538469997f9e..ca81c8afba79c 100644 +--- a/Documentation/devicetree/bindings/thermal/loongson,ls2k-thermal.yaml ++++ b/Documentation/devicetree/bindings/thermal/loongson,ls2k-thermal.yaml +@@ -10,28 +10,55 @@ maintainers: + - zhanghongchen + - Yinbo Zhu + ++allOf: ++ - $ref: /schemas/thermal/thermal-sensor.yaml# ++ + properties: + compatible: + oneOf: + - enum: + - loongson,ls2k1000-thermal ++ - loongson,ls2k2000-thermal + - items: + - enum: +- - loongson,ls2k2000-thermal ++ - loongson,ls2k0500-thermal + - const: loongson,ls2k1000-thermal + + reg: +- maxItems: 1 ++ minItems: 1 ++ maxItems: 2 + + interrupts: + maxItems: 1 + ++ '#thermal-sensor-cells': ++ const: 1 ++ + required: + - compatible + - reg + - interrupts ++ - '#thermal-sensor-cells' ++ ++if: ++ properties: ++ compatible: ++ contains: ++ enum: ++ - loongson,ls2k2000-thermal ++ ++then: ++ properties: ++ reg: ++ minItems: 2 ++ maxItems: 2 ++ ++else: ++ properties: ++ reg: ++ maxItems: 1 + +-additionalProperties: false ++unevaluatedProperties: false + + examples: + - | +@@ -41,4 +68,5 @@ examples: + reg = <0x1fe01500 0x30>; + interrupt-parent = <&liointc0>; + interrupts = <7 IRQ_TYPE_LEVEL_LOW>; ++ #thermal-sensor-cells = <1>; + }; +diff --git a/Documentation/driver-api/fpga/fpga-bridge.rst b/Documentation/driver-api/fpga/fpga-bridge.rst +index 6042085340953..833f68fb07008 100644 +--- a/Documentation/driver-api/fpga/fpga-bridge.rst ++++ b/Documentation/driver-api/fpga/fpga-bridge.rst +@@ -6,9 +6,12 @@ API to implement a new FPGA bridge + + * struct fpga_bridge - The FPGA Bridge structure + * struct fpga_bridge_ops - Low level Bridge driver ops +-* fpga_bridge_register() - Create and register a bridge ++* __fpga_bridge_register() - Create and register a bridge + * fpga_bridge_unregister() - Unregister a bridge + ++The helper macro ``fpga_bridge_register()`` automatically sets ++the module that registers the FPGA bridge as the owner. ++ + .. kernel-doc:: include/linux/fpga/fpga-bridge.h + :functions: fpga_bridge + +@@ -16,7 +19,7 @@ API to implement a new FPGA bridge + :functions: fpga_bridge_ops + + .. kernel-doc:: drivers/fpga/fpga-bridge.c +- :functions: fpga_bridge_register ++ :functions: __fpga_bridge_register + + .. kernel-doc:: drivers/fpga/fpga-bridge.c + :functions: fpga_bridge_unregister +diff --git a/Documentation/driver-api/fpga/fpga-mgr.rst b/Documentation/driver-api/fpga/fpga-mgr.rst +index 49c0a95126532..8d2b79f696c1f 100644 +--- a/Documentation/driver-api/fpga/fpga-mgr.rst ++++ b/Documentation/driver-api/fpga/fpga-mgr.rst +@@ -24,7 +24,8 @@ How to support a new FPGA device + -------------------------------- + + To add another FPGA manager, write a driver that implements a set of ops. The +-probe function calls fpga_mgr_register() or fpga_mgr_register_full(), such as:: ++probe function calls ``fpga_mgr_register()`` or ``fpga_mgr_register_full()``, ++such as:: + + static const struct fpga_manager_ops socfpga_fpga_ops = { + .write_init = socfpga_fpga_ops_configure_init, +@@ -69,10 +70,11 @@ probe function calls fpga_mgr_register() or fpga_mgr_register_full(), such as:: + } + + Alternatively, the probe function could call one of the resource managed +-register functions, devm_fpga_mgr_register() or devm_fpga_mgr_register_full(). +-When these functions are used, the parameter syntax is the same, but the call +-to fpga_mgr_unregister() should be removed. In the above example, the +-socfpga_fpga_remove() function would not be required. ++register functions, ``devm_fpga_mgr_register()`` or ++``devm_fpga_mgr_register_full()``. When these functions are used, the ++parameter syntax is the same, but the call to ``fpga_mgr_unregister()`` should be ++removed. In the above example, the ``socfpga_fpga_remove()`` function would not be ++required. + + The ops will implement whatever device specific register writes are needed to + do the programming sequence for this particular FPGA. These ops return 0 for +@@ -125,15 +127,19 @@ API for implementing a new FPGA Manager driver + * struct fpga_manager - the FPGA manager struct + * struct fpga_manager_ops - Low level FPGA manager driver ops + * struct fpga_manager_info - Parameter structure for fpga_mgr_register_full() +-* fpga_mgr_register_full() - Create and register an FPGA manager using the ++* __fpga_mgr_register_full() - Create and register an FPGA manager using the + fpga_mgr_info structure to provide the full flexibility of options +-* fpga_mgr_register() - Create and register an FPGA manager using standard ++* __fpga_mgr_register() - Create and register an FPGA manager using standard + arguments +-* devm_fpga_mgr_register_full() - Resource managed version of +- fpga_mgr_register_full() +-* devm_fpga_mgr_register() - Resource managed version of fpga_mgr_register() ++* __devm_fpga_mgr_register_full() - Resource managed version of ++ __fpga_mgr_register_full() ++* __devm_fpga_mgr_register() - Resource managed version of __fpga_mgr_register() + * fpga_mgr_unregister() - Unregister an FPGA manager + ++Helper macros ``fpga_mgr_register_full()``, ``fpga_mgr_register()``, ++``devm_fpga_mgr_register_full()``, and ``devm_fpga_mgr_register()`` are available ++to ease the registration. ++ + .. kernel-doc:: include/linux/fpga/fpga-mgr.h + :functions: fpga_mgr_states + +@@ -147,16 +153,16 @@ API for implementing a new FPGA Manager driver + :functions: fpga_manager_info + + .. kernel-doc:: drivers/fpga/fpga-mgr.c +- :functions: fpga_mgr_register_full ++ :functions: __fpga_mgr_register_full + + .. kernel-doc:: drivers/fpga/fpga-mgr.c +- :functions: fpga_mgr_register ++ :functions: __fpga_mgr_register + + .. kernel-doc:: drivers/fpga/fpga-mgr.c +- :functions: devm_fpga_mgr_register_full ++ :functions: __devm_fpga_mgr_register_full + + .. kernel-doc:: drivers/fpga/fpga-mgr.c +- :functions: devm_fpga_mgr_register ++ :functions: __devm_fpga_mgr_register + + .. kernel-doc:: drivers/fpga/fpga-mgr.c + :functions: fpga_mgr_unregister +diff --git a/Documentation/driver-api/fpga/fpga-region.rst b/Documentation/driver-api/fpga/fpga-region.rst +index dc55d60a0b4a5..2d03b5fb76575 100644 +--- a/Documentation/driver-api/fpga/fpga-region.rst ++++ b/Documentation/driver-api/fpga/fpga-region.rst +@@ -46,13 +46,16 @@ API to add a new FPGA region + ---------------------------- + + * struct fpga_region - The FPGA region struct +-* struct fpga_region_info - Parameter structure for fpga_region_register_full() +-* fpga_region_register_full() - Create and register an FPGA region using the ++* struct fpga_region_info - Parameter structure for __fpga_region_register_full() ++* __fpga_region_register_full() - Create and register an FPGA region using the + fpga_region_info structure to provide the full flexibility of options +-* fpga_region_register() - Create and register an FPGA region using standard ++* __fpga_region_register() - Create and register an FPGA region using standard + arguments + * fpga_region_unregister() - Unregister an FPGA region + ++Helper macros ``fpga_region_register()`` and ``fpga_region_register_full()`` ++automatically set the module that registers the FPGA region as the owner. ++ + The FPGA region's probe function will need to get a reference to the FPGA + Manager it will be using to do the programming. This usually would happen + during the region's probe function. +@@ -82,10 +85,10 @@ following APIs to handle building or tearing down that list. + :functions: fpga_region_info + + .. kernel-doc:: drivers/fpga/fpga-region.c +- :functions: fpga_region_register_full ++ :functions: __fpga_region_register_full + + .. kernel-doc:: drivers/fpga/fpga-region.c +- :functions: fpga_region_register ++ :functions: __fpga_region_register + + .. kernel-doc:: drivers/fpga/fpga-region.c + :functions: fpga_region_unregister +diff --git a/Documentation/driver-api/pwm.rst b/Documentation/driver-api/pwm.rst +index 3fdc95f7a1d15..ed5ec98165381 100644 +--- a/Documentation/driver-api/pwm.rst ++++ b/Documentation/driver-api/pwm.rst +@@ -41,7 +41,7 @@ the getter, devm_pwm_get() and devm_fwnode_pwm_get(), also exist. + + After being requested, a PWM has to be configured using:: + +- int pwm_apply_state(struct pwm_device *pwm, struct pwm_state *state); ++ int pwm_apply_might_sleep(struct pwm_device *pwm, struct pwm_state *state); + + This API controls both the PWM period/duty_cycle config and the + enable/disable state. +@@ -57,13 +57,13 @@ If supported by the driver, the signal can be optimized, for example to improve + EMI by phase shifting the individual channels of a chip. + + The pwm_config(), pwm_enable() and pwm_disable() functions are just wrappers +-around pwm_apply_state() and should not be used if the user wants to change ++around pwm_apply_might_sleep() and should not be used if the user wants to change + several parameter at once. For example, if you see pwm_config() and + pwm_{enable,disable}() calls in the same function, this probably means you +-should switch to pwm_apply_state(). ++should switch to pwm_apply_might_sleep(). + + The PWM user API also allows one to query the PWM state that was passed to the +-last invocation of pwm_apply_state() using pwm_get_state(). Note this is ++last invocation of pwm_apply_might_sleep() using pwm_get_state(). Note this is + different to what the driver has actually implemented if the request cannot be + satisfied exactly with the hardware in use. There is currently no way for + consumers to get the actually implemented settings. +diff --git a/Documentation/filesystems/f2fs.rst b/Documentation/filesystems/f2fs.rst +index d32c6209685d6..dbfbbe9ab28b1 100644 +--- a/Documentation/filesystems/f2fs.rst ++++ b/Documentation/filesystems/f2fs.rst +@@ -126,9 +126,7 @@ norecovery Disable the roll-forward recovery routine, mounted read- + discard/nodiscard Enable/disable real-time discard in f2fs, if discard is + enabled, f2fs will issue discard/TRIM commands when a + segment is cleaned. +-no_heap Disable heap-style segment allocation which finds free +- segments for data from the beginning of main area, while +- for node from the end of main area. ++heap/no_heap Deprecated. + nouser_xattr Disable Extended User Attributes. Note: xattr is enabled + by default if CONFIG_F2FS_FS_XATTR is selected. + noacl Disable POSIX Access Control List. Note: acl is enabled +@@ -228,8 +226,6 @@ mode=%s Control block allocation mode which supports "adaptive" + option for more randomness. + Please, use these options for your experiments and we strongly + recommend to re-format the filesystem after using these options. +-io_bits=%u Set the bit size of write IO requests. It should be set +- with "mode=lfs". + usrquota Enable plain user disk quota accounting. + grpquota Enable plain group disk quota accounting. + prjquota Enable plain project quota accounting. +diff --git a/MAINTAINERS b/MAINTAINERS +index 72a2880afab7a..f09415b2b3c5c 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -10157,6 +10157,14 @@ L: linux-media@vger.kernel.org + S: Maintained + F: drivers/media/rc/iguanair.c + ++IIO BACKEND FRAMEWORK ++M: Nuno Sa ++R: Olivier Moysan ++L: linux-iio@vger.kernel.org ++S: Maintained ++F: drivers/iio/industrialio-backend.c ++F: include/linux/iio/backend.h ++ + IIO DIGITAL POTENTIOMETER DAC + M: Peter Rosin + L: linux-iio@vger.kernel.org +@@ -17380,7 +17388,7 @@ F: drivers/video/backlight/pwm_bl.c + F: include/dt-bindings/pwm/ + F: include/linux/pwm.h + F: include/linux/pwm_backlight.h +-K: pwm_(config|apply_state|ops) ++K: pwm_(config|apply_might_sleep|ops) + + PXA GPIO DRIVER + M: Robert Jarzmik +diff --git a/Makefile b/Makefile +index c3b324ed985e6..813b4eb01af91 100644 +--- a/Makefile ++++ b/Makefile +@@ -1,7 +1,7 @@ + # SPDX-License-Identifier: GPL-2.0 + VERSION = 6 + PATCHLEVEL = 6 +-SUBLEVEL = 32 ++SUBLEVEL = 33 + EXTRAVERSION = + NAME = Hurr durr I'ma ninja sloth + +@@ -1317,6 +1317,14 @@ scripts_unifdef: scripts_basic + quiet_cmd_install = INSTALL $(INSTALL_PATH) + cmd_install = unset sub_make_done; $(srctree)/scripts/install.sh + ++# --------------------------------------------------------------------------- ++# vDSO install ++ ++PHONY += vdso_install ++vdso_install: export INSTALL_FILES = $(vdso-install-y) ++vdso_install: ++ $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.vdsoinst ++ + # --------------------------------------------------------------------------- + # Tools + +@@ -1560,6 +1568,7 @@ help: + @echo '* vmlinux - Build the bare kernel' + @echo '* modules - Build all modules' + @echo ' modules_install - Install all modules to INSTALL_MOD_PATH (default: /)' ++ @echo ' vdso_install - Install unstripped vdso to INSTALL_MOD_PATH (default: /)' + @echo ' dir/ - Build all files in dir and below' + @echo ' dir/file.[ois] - Build specified target only' + @echo ' dir/file.ll - Build the LLVM assembly file' +diff --git a/arch/arm/Makefile b/arch/arm/Makefile +index 547e5856eaa0d..5ba42f69f8ce0 100644 +--- a/arch/arm/Makefile ++++ b/arch/arm/Makefile +@@ -304,11 +304,7 @@ $(INSTALL_TARGETS): KBUILD_IMAGE = $(boot)/$(patsubst %install,%Image,$@) + $(INSTALL_TARGETS): + $(call cmd,install) + +-PHONY += vdso_install +-vdso_install: +-ifeq ($(CONFIG_VDSO),y) +- $(Q)$(MAKE) $(build)=arch/arm/vdso $@ +-endif ++vdso-install-$(CONFIG_VDSO) += arch/arm/vdso/vdso.so.dbg + + # My testing targets (bypasses dependencies) + bp:; $(Q)$(MAKE) $(build)=$(boot) $(boot)/bootpImage +@@ -331,7 +327,6 @@ define archhelp + echo ' Install using (your) ~/bin/$(INSTALLKERNEL) or' + echo ' (distribution) /sbin/$(INSTALLKERNEL) or' + echo ' install to $$(INSTALL_PATH) and run lilo' +- echo ' vdso_install - Install unstripped vdso.so to $$(INSTALL_MOD_PATH)/vdso' + echo + echo ' multi_v7_lpae_defconfig - multi_v7_defconfig with CONFIG_ARM_LPAE enabled' + endef +diff --git a/arch/arm/configs/sunxi_defconfig b/arch/arm/configs/sunxi_defconfig +index bddc82f789421..a83d29fed1756 100644 +--- a/arch/arm/configs/sunxi_defconfig ++++ b/arch/arm/configs/sunxi_defconfig +@@ -110,6 +110,7 @@ CONFIG_DRM_PANEL_LVDS=y + CONFIG_DRM_PANEL_SIMPLE=y + CONFIG_DRM_PANEL_EDP=y + CONFIG_DRM_SIMPLE_BRIDGE=y ++CONFIG_DRM_DW_HDMI=y + CONFIG_DRM_LIMA=y + CONFIG_FB_SIMPLE=y + CONFIG_BACKLIGHT_CLASS_DEVICE=y +diff --git a/arch/arm/vdso/Makefile b/arch/arm/vdso/Makefile +index 515ca33b854c1..d761bd2e2f407 100644 +--- a/arch/arm/vdso/Makefile ++++ b/arch/arm/vdso/Makefile +@@ -63,28 +63,3 @@ quiet_cmd_vdsold_and_vdso_check = LD $@ + + quiet_cmd_vdsomunge = MUNGE $@ + cmd_vdsomunge = $(objtree)/$(obj)/vdsomunge $< $@ +- +-# +-# Install the unstripped copy of vdso.so.dbg. If our toolchain +-# supports build-id, install .build-id links as well. +-# +-# Cribbed from arch/x86/vdso/Makefile. +-# +-quiet_cmd_vdso_install = INSTALL $< +-define cmd_vdso_install +- cp $< "$(MODLIB)/vdso/vdso.so"; \ +- if readelf -n $< | grep -q 'Build ID'; then \ +- buildid=`readelf -n $< |grep 'Build ID' |sed -e 's/^.*Build ID: \(.*\)$$/\1/'`; \ +- first=`echo $$buildid | cut -b-2`; \ +- last=`echo $$buildid | cut -b3-`; \ +- mkdir -p "$(MODLIB)/vdso/.build-id/$$first"; \ +- ln -sf "../../vdso.so" "$(MODLIB)/vdso/.build-id/$$first/$$last.debug"; \ +- fi +-endef +- +-$(MODLIB)/vdso: FORCE +- @mkdir -p $(MODLIB)/vdso +- +-PHONY += vdso_install +-vdso_install: $(obj)/vdso.so.dbg $(MODLIB)/vdso +- $(call cmd,vdso_install) +diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile +index 26b8c7630a214..9a2d3723cd0fa 100644 +--- a/arch/arm64/Makefile ++++ b/arch/arm64/Makefile +@@ -169,12 +169,6 @@ install: KBUILD_IMAGE := $(boot)/Image + install zinstall: + $(call cmd,install) + +-PHONY += vdso_install +-vdso_install: +- $(Q)$(MAKE) $(build)=arch/arm64/kernel/vdso $@ +- $(if $(CONFIG_COMPAT_VDSO), \ +- $(Q)$(MAKE) $(build)=arch/arm64/kernel/vdso32 $@) +- + archprepare: + $(Q)$(MAKE) $(build)=arch/arm64/tools kapi + ifeq ($(CONFIG_ARM64_ERRATUM_843419),y) +@@ -205,6 +199,9 @@ ifdef CONFIG_COMPAT_VDSO + endif + endif + ++vdso-install-y += arch/arm64/kernel/vdso/vdso.so.dbg ++vdso-install-$(CONFIG_COMPAT_VDSO) += arch/arm64/kernel/vdso32/vdso.so.dbg:vdso32.so ++ + include $(srctree)/scripts/Makefile.defconf + + PHONY += virtconfig +diff --git a/arch/arm64/boot/dts/amlogic/meson-s4.dtsi b/arch/arm64/boot/dts/amlogic/meson-s4.dtsi +index 55ddea6dc9f8e..a781eabe21f04 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-s4.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-s4.dtsi +@@ -61,10 +61,15 @@ xtal: xtal-clk { + #clock-cells = <0>; + }; + +- pwrc: power-controller { +- compatible = "amlogic,meson-s4-pwrc"; +- #power-domain-cells = <1>; +- status = "okay"; ++ firmware { ++ sm: secure-monitor { ++ compatible = "amlogic,meson-gxbb-sm"; ++ ++ pwrc: power-controller { ++ compatible = "amlogic,meson-s4-pwrc"; ++ #power-domain-cells = <1>; ++ }; ++ }; + }; + + soc { +diff --git a/arch/arm64/include/asm/asm-bug.h b/arch/arm64/include/asm/asm-bug.h +index c762038ba4009..6e73809f6492a 100644 +--- a/arch/arm64/include/asm/asm-bug.h ++++ b/arch/arm64/include/asm/asm-bug.h +@@ -28,6 +28,7 @@ + 14470: .long 14471f - .; \ + _BUGVERBOSE_LOCATION(__FILE__, __LINE__) \ + .short flags; \ ++ .align 2; \ + .popsection; \ + 14471: + #else +diff --git a/arch/arm64/kernel/vdso/Makefile b/arch/arm64/kernel/vdso/Makefile +index fe7a53c6781f1..8818287f10955 100644 +--- a/arch/arm64/kernel/vdso/Makefile ++++ b/arch/arm64/kernel/vdso/Makefile +@@ -78,13 +78,3 @@ include/generated/vdso-offsets.h: $(obj)/vdso.so.dbg FORCE + # Actual build commands + quiet_cmd_vdsold_and_vdso_check = LD $@ + cmd_vdsold_and_vdso_check = $(cmd_ld); $(cmd_vdso_check) +- +-# Install commands for the unstripped file +-quiet_cmd_vdso_install = INSTALL $@ +- cmd_vdso_install = cp $(obj)/$@.dbg $(MODLIB)/vdso/$@ +- +-vdso.so: $(obj)/vdso.so.dbg +- @mkdir -p $(MODLIB)/vdso +- $(call cmd,vdso_install) +- +-vdso_install: vdso.so +diff --git a/arch/arm64/kernel/vdso32/Makefile b/arch/arm64/kernel/vdso32/Makefile +index 2f73e5bca213f..1f911a76c5af3 100644 +--- a/arch/arm64/kernel/vdso32/Makefile ++++ b/arch/arm64/kernel/vdso32/Makefile +@@ -172,13 +172,3 @@ gen-vdsosym := $(srctree)/$(src)/../vdso/gen_vdso_offsets.sh + quiet_cmd_vdsosym = VDSOSYM $@ + # The AArch64 nm should be able to read an AArch32 binary + cmd_vdsosym = $(NM) $< | $(gen-vdsosym) | LC_ALL=C sort > $@ +- +-# Install commands for the unstripped file +-quiet_cmd_vdso_install = INSTALL32 $@ +- cmd_vdso_install = cp $(obj)/$@.dbg $(MODLIB)/vdso/vdso32.so +- +-vdso.so: $(obj)/vdso.so.dbg +- @mkdir -p $(MODLIB)/vdso +- $(call cmd,vdso_install) +- +-vdso_install: vdso.so +diff --git a/arch/loongarch/Makefile b/arch/loongarch/Makefile +index d423fba7c4062..81e8089c9c4f1 100644 +--- a/arch/loongarch/Makefile ++++ b/arch/loongarch/Makefile +@@ -136,9 +136,7 @@ vdso_prepare: prepare0 + $(Q)$(MAKE) $(build)=arch/loongarch/vdso include/generated/vdso-offsets.h + endif + +-PHONY += vdso_install +-vdso_install: +- $(Q)$(MAKE) $(build)=arch/loongarch/vdso $@ ++vdso-install-y += arch/loongarch/vdso/vdso.so.dbg + + all: $(notdir $(KBUILD_IMAGE)) + +diff --git a/arch/loongarch/include/asm/perf_event.h b/arch/loongarch/include/asm/perf_event.h +index 52b638059e40b..f948a0676daf8 100644 +--- a/arch/loongarch/include/asm/perf_event.h ++++ b/arch/loongarch/include/asm/perf_event.h +@@ -13,8 +13,7 @@ + + #define perf_arch_fetch_caller_regs(regs, __ip) { \ + (regs)->csr_era = (__ip); \ +- (regs)->regs[3] = current_stack_pointer; \ +- (regs)->regs[22] = (unsigned long) __builtin_frame_address(0); \ ++ (regs)->regs[3] = (unsigned long) __builtin_frame_address(0); \ + } + + #endif /* __LOONGARCH_PERF_EVENT_H__ */ +diff --git a/arch/loongarch/kernel/perf_event.c b/arch/loongarch/kernel/perf_event.c +index 0491bf453cd49..cac7cba81b65f 100644 +--- a/arch/loongarch/kernel/perf_event.c ++++ b/arch/loongarch/kernel/perf_event.c +@@ -884,4 +884,4 @@ static int __init init_hw_perf_events(void) + + return 0; + } +-early_initcall(init_hw_perf_events); ++pure_initcall(init_hw_perf_events); +diff --git a/arch/loongarch/vdso/Makefile b/arch/loongarch/vdso/Makefile +index 4305d99b33130..f597cd08a96be 100644 +--- a/arch/loongarch/vdso/Makefile ++++ b/arch/loongarch/vdso/Makefile +@@ -84,13 +84,3 @@ $(obj)/vdso.so: $(obj)/vdso.so.dbg FORCE + obj-y += vdso.o + + $(obj)/vdso.o : $(obj)/vdso.so +- +-# install commands for the unstripped file +-quiet_cmd_vdso_install = INSTALL $@ +- cmd_vdso_install = cp $(obj)/$@.dbg $(MODLIB)/vdso/$@ +- +-vdso.so: $(obj)/vdso.so.dbg +- @mkdir -p $(MODLIB)/vdso +- $(call cmd,vdso_install) +- +-vdso_install: vdso.so +diff --git a/arch/m68k/kernel/entry.S b/arch/m68k/kernel/entry.S +index 4dd2fd7acba9e..2e1e9ad4f98ca 100644 +--- a/arch/m68k/kernel/entry.S ++++ b/arch/m68k/kernel/entry.S +@@ -433,7 +433,9 @@ resume: + movec %a0,%dfc + + /* restore status register */ +- movew %a1@(TASK_THREAD+THREAD_SR),%sr ++ movew %a1@(TASK_THREAD+THREAD_SR),%d0 ++ oriw #0x0700,%d0 ++ movew %d0,%sr + + rts + +diff --git a/arch/m68k/mac/misc.c b/arch/m68k/mac/misc.c +index c7cb29f0ff016..29e06f46ab511 100644 +--- a/arch/m68k/mac/misc.c ++++ b/arch/m68k/mac/misc.c +@@ -451,30 +451,18 @@ void mac_poweroff(void) + + void mac_reset(void) + { +- if (macintosh_config->adb_type == MAC_ADB_II && +- macintosh_config->ident != MAC_MODEL_SE30) { +- /* need ROMBASE in booter */ +- /* indeed, plus need to MAP THE ROM !! */ +- +- if (mac_bi_data.rombase == 0) +- mac_bi_data.rombase = 0x40800000; +- +- /* works on some */ +- rom_reset = (void *) (mac_bi_data.rombase + 0xa); +- +- local_irq_disable(); +- rom_reset(); + #ifdef CONFIG_ADB_CUDA +- } else if (macintosh_config->adb_type == MAC_ADB_EGRET || +- macintosh_config->adb_type == MAC_ADB_CUDA) { ++ if (macintosh_config->adb_type == MAC_ADB_EGRET || ++ macintosh_config->adb_type == MAC_ADB_CUDA) { + cuda_restart(); ++ } else + #endif + #ifdef CONFIG_ADB_PMU +- } else if (macintosh_config->adb_type == MAC_ADB_PB2) { ++ if (macintosh_config->adb_type == MAC_ADB_PB2) { + pmu_restart(); ++ } else + #endif +- } else if (CPU_IS_030) { +- ++ if (CPU_IS_030) { + /* 030-specific reset routine. The idea is general, but the + * specific registers to reset are '030-specific. Until I + * have a non-030 machine, I can't test anything else. +@@ -522,6 +510,18 @@ void mac_reset(void) + "jmp %/a0@\n\t" /* jump to the reset vector */ + ".chip 68k" + : : "r" (offset), "a" (rombase) : "a0"); ++ } else { ++ /* need ROMBASE in booter */ ++ /* indeed, plus need to MAP THE ROM !! */ ++ ++ if (mac_bi_data.rombase == 0) ++ mac_bi_data.rombase = 0x40800000; ++ ++ /* works on some */ ++ rom_reset = (void *)(mac_bi_data.rombase + 0xa); ++ ++ local_irq_disable(); ++ rom_reset(); + } + + /* should never get here */ +diff --git a/arch/microblaze/kernel/Makefile b/arch/microblaze/kernel/Makefile +index 4393bee64eaf8..85c4d29ef43e9 100644 +--- a/arch/microblaze/kernel/Makefile ++++ b/arch/microblaze/kernel/Makefile +@@ -7,7 +7,6 @@ ifdef CONFIG_FUNCTION_TRACER + # Do not trace early boot code and low level code + CFLAGS_REMOVE_timer.o = -pg + CFLAGS_REMOVE_intc.o = -pg +-CFLAGS_REMOVE_early_printk.o = -pg + CFLAGS_REMOVE_ftrace.o = -pg + CFLAGS_REMOVE_process.o = -pg + endif +diff --git a/arch/microblaze/kernel/cpu/cpuinfo-static.c b/arch/microblaze/kernel/cpu/cpuinfo-static.c +index 85dbda4a08a81..03da36dc6d9c9 100644 +--- a/arch/microblaze/kernel/cpu/cpuinfo-static.c ++++ b/arch/microblaze/kernel/cpu/cpuinfo-static.c +@@ -18,7 +18,7 @@ static const char family_string[] = CONFIG_XILINX_MICROBLAZE0_FAMILY; + static const char cpu_ver_string[] = CONFIG_XILINX_MICROBLAZE0_HW_VER; + + #define err_printk(x) \ +- early_printk("ERROR: Microblaze " x "-different for kernel and DTS\n"); ++ pr_err("ERROR: Microblaze " x "-different for kernel and DTS\n"); + + void __init set_cpuinfo_static(struct cpuinfo *ci, struct device_node *cpu) + { +diff --git a/arch/openrisc/kernel/traps.c b/arch/openrisc/kernel/traps.c +index 9370888c9a7e3..90554a5558fbc 100644 +--- a/arch/openrisc/kernel/traps.c ++++ b/arch/openrisc/kernel/traps.c +@@ -180,29 +180,39 @@ asmlinkage void unhandled_exception(struct pt_regs *regs, int ea, int vector) + + asmlinkage void do_fpe_trap(struct pt_regs *regs, unsigned long address) + { +- int code = FPE_FLTUNK; +- unsigned long fpcsr = regs->fpcsr; +- +- if (fpcsr & SPR_FPCSR_IVF) +- code = FPE_FLTINV; +- else if (fpcsr & SPR_FPCSR_OVF) +- code = FPE_FLTOVF; +- else if (fpcsr & SPR_FPCSR_UNF) +- code = FPE_FLTUND; +- else if (fpcsr & SPR_FPCSR_DZF) +- code = FPE_FLTDIV; +- else if (fpcsr & SPR_FPCSR_IXF) +- code = FPE_FLTRES; +- +- /* Clear all flags */ +- regs->fpcsr &= ~SPR_FPCSR_ALLF; +- +- force_sig_fault(SIGFPE, code, (void __user *)regs->pc); ++ if (user_mode(regs)) { ++ int code = FPE_FLTUNK; ++ unsigned long fpcsr = regs->fpcsr; ++ ++ if (fpcsr & SPR_FPCSR_IVF) ++ code = FPE_FLTINV; ++ else if (fpcsr & SPR_FPCSR_OVF) ++ code = FPE_FLTOVF; ++ else if (fpcsr & SPR_FPCSR_UNF) ++ code = FPE_FLTUND; ++ else if (fpcsr & SPR_FPCSR_DZF) ++ code = FPE_FLTDIV; ++ else if (fpcsr & SPR_FPCSR_IXF) ++ code = FPE_FLTRES; ++ ++ /* Clear all flags */ ++ regs->fpcsr &= ~SPR_FPCSR_ALLF; ++ ++ force_sig_fault(SIGFPE, code, (void __user *)regs->pc); ++ } else { ++ pr_emerg("KERNEL: Illegal fpe exception 0x%.8lx\n", regs->pc); ++ die("Die:", regs, SIGFPE); ++ } + } + + asmlinkage void do_trap(struct pt_regs *regs, unsigned long address) + { +- force_sig_fault(SIGTRAP, TRAP_BRKPT, (void __user *)regs->pc); ++ if (user_mode(regs)) { ++ force_sig_fault(SIGTRAP, TRAP_BRKPT, (void __user *)regs->pc); ++ } else { ++ pr_emerg("KERNEL: Illegal trap exception 0x%.8lx\n", regs->pc); ++ die("Die:", regs, SIGILL); ++ } + } + + asmlinkage void do_unaligned_access(struct pt_regs *regs, unsigned long address) +diff --git a/arch/parisc/Makefile b/arch/parisc/Makefile +index 968ebe17494c5..920db57b6b4cc 100644 +--- a/arch/parisc/Makefile ++++ b/arch/parisc/Makefile +@@ -177,12 +177,8 @@ vdso_prepare: prepare0 + $(Q)$(MAKE) $(build)=arch/parisc/kernel/vdso32 include/generated/vdso32-offsets.h + endif + +-PHONY += vdso_install +- +-vdso_install: +- $(Q)$(MAKE) $(build)=arch/parisc/kernel/vdso $@ +- $(if $(CONFIG_COMPAT_VDSO), \ +- $(Q)$(MAKE) $(build)=arch/parisc/kernel/vdso32 $@) ++vdso-install-y += arch/parisc/kernel/vdso32/vdso32.so ++vdso-install-$(CONFIG_64BIT) += arch/parisc/kernel/vdso64/vdso64.so + + install: KBUILD_IMAGE := vmlinux + zinstall: KBUILD_IMAGE := vmlinuz +diff --git a/arch/parisc/kernel/parisc_ksyms.c b/arch/parisc/kernel/parisc_ksyms.c +index 6f0c92e8149d8..dcf61cbd31470 100644 +--- a/arch/parisc/kernel/parisc_ksyms.c ++++ b/arch/parisc/kernel/parisc_ksyms.c +@@ -22,6 +22,7 @@ EXPORT_SYMBOL(memset); + #include + EXPORT_SYMBOL(__xchg8); + EXPORT_SYMBOL(__xchg32); ++EXPORT_SYMBOL(__cmpxchg_u8); + EXPORT_SYMBOL(__cmpxchg_u32); + EXPORT_SYMBOL(__cmpxchg_u64); + #ifdef CONFIG_SMP +diff --git a/arch/powerpc/include/asm/hvcall.h b/arch/powerpc/include/asm/hvcall.h +index c099780385dd3..92ea0fa17ff41 100644 +--- a/arch/powerpc/include/asm/hvcall.h ++++ b/arch/powerpc/include/asm/hvcall.h +@@ -540,7 +540,7 @@ struct hvcall_mpp_data { + unsigned long backing_mem; + }; + +-int h_get_mpp(struct hvcall_mpp_data *); ++long h_get_mpp(struct hvcall_mpp_data *mpp_data); + + struct hvcall_mpp_x_data { + unsigned long coalesced_bytes; +diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c +index 47d9a65324472..c3585e90c6db6 100644 +--- a/arch/powerpc/platforms/pseries/lpar.c ++++ b/arch/powerpc/platforms/pseries/lpar.c +@@ -1886,10 +1886,10 @@ notrace void __trace_hcall_exit(long opcode, long retval, unsigned long *retbuf) + * h_get_mpp + * H_GET_MPP hcall returns info in 7 parms + */ +-int h_get_mpp(struct hvcall_mpp_data *mpp_data) ++long h_get_mpp(struct hvcall_mpp_data *mpp_data) + { +- int rc; +- unsigned long retbuf[PLPAR_HCALL9_BUFSIZE]; ++ unsigned long retbuf[PLPAR_HCALL9_BUFSIZE] = {0}; ++ long rc; + + rc = plpar_hcall9(H_GET_MPP, retbuf); + +diff --git a/arch/powerpc/platforms/pseries/lparcfg.c b/arch/powerpc/platforms/pseries/lparcfg.c +index 1c151d77e74b3..11d5208817b9d 100644 +--- a/arch/powerpc/platforms/pseries/lparcfg.c ++++ b/arch/powerpc/platforms/pseries/lparcfg.c +@@ -113,8 +113,8 @@ struct hvcall_ppp_data { + */ + static unsigned int h_get_ppp(struct hvcall_ppp_data *ppp_data) + { +- unsigned long rc; +- unsigned long retbuf[PLPAR_HCALL9_BUFSIZE]; ++ unsigned long retbuf[PLPAR_HCALL9_BUFSIZE] = {0}; ++ long rc; + + rc = plpar_hcall9(H_GET_PPP, retbuf); + +@@ -193,7 +193,7 @@ static void parse_ppp_data(struct seq_file *m) + struct hvcall_ppp_data ppp_data; + struct device_node *root; + const __be32 *perf_level; +- int rc; ++ long rc; + + rc = h_get_ppp(&ppp_data); + if (rc) +@@ -357,8 +357,8 @@ static int read_dt_lpar_name(struct seq_file *m) + + static void read_lpar_name(struct seq_file *m) + { +- if (read_rtas_lpar_name(m) && read_dt_lpar_name(m)) +- pr_err_once("Error can't get the LPAR name"); ++ if (read_rtas_lpar_name(m)) ++ read_dt_lpar_name(m); + } + + #define SPLPAR_MAXLENGTH 1026*(sizeof(char)) +diff --git a/arch/powerpc/sysdev/fsl_msi.c b/arch/powerpc/sysdev/fsl_msi.c +index 57978a44d55b6..ce9895633c4e0 100644 +--- a/arch/powerpc/sysdev/fsl_msi.c ++++ b/arch/powerpc/sysdev/fsl_msi.c +@@ -568,10 +568,12 @@ static const struct fsl_msi_feature ipic_msi_feature = { + .msiir_offset = 0x38, + }; + ++#ifdef CONFIG_EPAPR_PARAVIRT + static const struct fsl_msi_feature vmpic_msi_feature = { + .fsl_pic_ip = FSL_PIC_IP_VMPIC, + .msiir_offset = 0, + }; ++#endif + + static const struct of_device_id fsl_of_msi_ids[] = { + { +diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile +index b43a6bb7e4dcb..4d06f34026740 100644 +--- a/arch/riscv/Makefile ++++ b/arch/riscv/Makefile +@@ -130,12 +130,6 @@ endif + libs-y += arch/riscv/lib/ + libs-$(CONFIG_EFI_STUB) += $(objtree)/drivers/firmware/efi/libstub/lib.a + +-PHONY += vdso_install +-vdso_install: +- $(Q)$(MAKE) $(build)=arch/riscv/kernel/vdso $@ +- $(if $(CONFIG_COMPAT),$(Q)$(MAKE) \ +- $(build)=arch/riscv/kernel/compat_vdso compat_$@) +- + ifeq ($(KBUILD_EXTMOD),) + ifeq ($(CONFIG_MMU),y) + prepare: vdso_prepare +@@ -147,6 +141,9 @@ vdso_prepare: prepare0 + endif + endif + ++vdso-install-y += arch/riscv/kernel/vdso/vdso.so.dbg ++vdso-install-$(CONFIG_COMPAT) += arch/riscv/kernel/compat_vdso/compat_vdso.so.dbg:../compat_vdso/compat_vdso.so ++ + ifneq ($(CONFIG_XIP_KERNEL),y) + ifeq ($(CONFIG_RISCV_M_MODE)$(CONFIG_ARCH_CANAAN),yy) + KBUILD_IMAGE := $(boot)/loader.bin +diff --git a/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi b/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi +index 2c02358abd711..c9b212c0eaa8f 100644 +--- a/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi ++++ b/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi +@@ -440,40 +440,6 @@ GPOEN_ENABLE, + }; + }; + +- tdm_pins: tdm-0 { +- tx-pins { +- pinmux = ; +- bias-pull-up; +- drive-strength = <2>; +- input-disable; +- input-schmitt-disable; +- slew-rate = <0>; +- }; +- +- rx-pins { +- pinmux = ; +- input-enable; +- }; +- +- sync-pins { +- pinmux = ; +- input-enable; +- }; +- +- pcmclk-pins { +- pinmux = ; +- input-enable; +- }; +- }; +- + uart0_pins: uart0-0 { + tx-pins { + pinmux = ; +- status = "okay"; +-}; +- + &uart0 { + pinctrl-names = "default"; + pinctrl-0 = <&uart0_pins>; +diff --git a/arch/riscv/kernel/compat_vdso/Makefile b/arch/riscv/kernel/compat_vdso/Makefile +index b86e5e2c3aea9..62fa393b2eb2e 100644 +--- a/arch/riscv/kernel/compat_vdso/Makefile ++++ b/arch/riscv/kernel/compat_vdso/Makefile +@@ -76,13 +76,3 @@ quiet_cmd_compat_vdsold = VDSOLD $@ + # actual build commands + quiet_cmd_compat_vdsoas = VDSOAS $@ + cmd_compat_vdsoas = $(COMPAT_CC) $(a_flags) $(COMPAT_CC_FLAGS) -c -o $@ $< +- +-# install commands for the unstripped file +-quiet_cmd_compat_vdso_install = INSTALL $@ +- cmd_compat_vdso_install = cp $(obj)/$@.dbg $(MODLIB)/compat_vdso/$@ +- +-compat_vdso.so: $(obj)/compat_vdso.so.dbg +- @mkdir -p $(MODLIB)/compat_vdso +- $(call cmd,compat_vdso_install) +- +-compat_vdso_install: compat_vdso.so +diff --git a/arch/riscv/kernel/cpu_ops_sbi.c b/arch/riscv/kernel/cpu_ops_sbi.c +index efa0f0816634c..93cbc38d18057 100644 +--- a/arch/riscv/kernel/cpu_ops_sbi.c ++++ b/arch/riscv/kernel/cpu_ops_sbi.c +@@ -72,7 +72,7 @@ static int sbi_cpu_start(unsigned int cpuid, struct task_struct *tidle) + /* Make sure tidle is updated */ + smp_mb(); + bdata->task_ptr = tidle; +- bdata->stack_ptr = task_stack_page(tidle) + THREAD_SIZE; ++ bdata->stack_ptr = task_pt_regs(tidle); + /* Make sure boot data is updated */ + smp_mb(); + hsm_data = __pa(bdata); +diff --git a/arch/riscv/kernel/cpu_ops_spinwait.c b/arch/riscv/kernel/cpu_ops_spinwait.c +index d98d19226b5f5..691e0c5366d2b 100644 +--- a/arch/riscv/kernel/cpu_ops_spinwait.c ++++ b/arch/riscv/kernel/cpu_ops_spinwait.c +@@ -34,8 +34,7 @@ static void cpu_update_secondary_bootdata(unsigned int cpuid, + + /* Make sure tidle is updated */ + smp_mb(); +- WRITE_ONCE(__cpu_spinwait_stack_pointer[hartid], +- task_stack_page(tidle) + THREAD_SIZE); ++ WRITE_ONCE(__cpu_spinwait_stack_pointer[hartid], task_pt_regs(tidle)); + WRITE_ONCE(__cpu_spinwait_task_pointer[hartid], tidle); + } + +diff --git a/arch/riscv/kernel/stacktrace.c b/arch/riscv/kernel/stacktrace.c +index 64a9c093aef93..528ec7cc9a622 100644 +--- a/arch/riscv/kernel/stacktrace.c ++++ b/arch/riscv/kernel/stacktrace.c +@@ -18,6 +18,16 @@ + + extern asmlinkage void ret_from_exception(void); + ++static inline int fp_is_valid(unsigned long fp, unsigned long sp) ++{ ++ unsigned long low, high; ++ ++ low = sp + sizeof(struct stackframe); ++ high = ALIGN(sp, THREAD_SIZE); ++ ++ return !(fp < low || fp > high || fp & 0x07); ++} ++ + void notrace walk_stackframe(struct task_struct *task, struct pt_regs *regs, + bool (*fn)(void *, unsigned long), void *arg) + { +@@ -41,21 +51,19 @@ void notrace walk_stackframe(struct task_struct *task, struct pt_regs *regs, + } + + for (;;) { +- unsigned long low, high; + struct stackframe *frame; + + if (unlikely(!__kernel_text_address(pc) || (level++ >= 0 && !fn(arg, pc)))) + break; + +- /* Validate frame pointer */ +- low = sp + sizeof(struct stackframe); +- high = ALIGN(sp, THREAD_SIZE); +- if (unlikely(fp < low || fp > high || fp & 0x7)) ++ if (unlikely(!fp_is_valid(fp, sp))) + break; ++ + /* Unwind stack frame */ + frame = (struct stackframe *)fp - 1; + sp = fp; +- if (regs && (regs->epc == pc) && (frame->fp & 0x7)) { ++ if (regs && (regs->epc == pc) && fp_is_valid(frame->ra, sp)) { ++ /* We hit function where ra is not saved on the stack */ + fp = frame->ra; + pc = regs->ra; + } else { +diff --git a/arch/riscv/kernel/vdso/Makefile b/arch/riscv/kernel/vdso/Makefile +index 6b1dba11bf6dc..e8aa7c3800075 100644 +--- a/arch/riscv/kernel/vdso/Makefile ++++ b/arch/riscv/kernel/vdso/Makefile +@@ -73,13 +73,3 @@ quiet_cmd_vdsold = VDSOLD $@ + cmd_vdsold = $(LD) $(ld_flags) -T $(filter-out FORCE,$^) -o $@.tmp && \ + $(OBJCOPY) $(patsubst %, -G __vdso_%, $(vdso-syms)) $@.tmp $@ && \ + rm $@.tmp +- +-# install commands for the unstripped file +-quiet_cmd_vdso_install = INSTALL $@ +- cmd_vdso_install = cp $(obj)/$@.dbg $(MODLIB)/vdso/$@ +- +-vdso.so: $(obj)/vdso.so.dbg +- @mkdir -p $(MODLIB)/vdso +- $(call cmd,vdso_install) +- +-vdso_install: vdso.so +diff --git a/arch/riscv/net/bpf_jit_comp64.c b/arch/riscv/net/bpf_jit_comp64.c +index b3990874e4818..2f041b5cea970 100644 +--- a/arch/riscv/net/bpf_jit_comp64.c ++++ b/arch/riscv/net/bpf_jit_comp64.c +@@ -516,33 +516,33 @@ static void emit_atomic(u8 rd, u8 rs, s16 off, s32 imm, bool is64, + break; + /* src_reg = atomic_fetch_(dst_reg + off16, src_reg) */ + case BPF_ADD | BPF_FETCH: +- emit(is64 ? rv_amoadd_d(rs, rs, rd, 0, 0) : +- rv_amoadd_w(rs, rs, rd, 0, 0), ctx); ++ emit(is64 ? rv_amoadd_d(rs, rs, rd, 1, 1) : ++ rv_amoadd_w(rs, rs, rd, 1, 1), ctx); + if (!is64) + emit_zext_32(rs, ctx); + break; + case BPF_AND | BPF_FETCH: +- emit(is64 ? rv_amoand_d(rs, rs, rd, 0, 0) : +- rv_amoand_w(rs, rs, rd, 0, 0), ctx); ++ emit(is64 ? rv_amoand_d(rs, rs, rd, 1, 1) : ++ rv_amoand_w(rs, rs, rd, 1, 1), ctx); + if (!is64) + emit_zext_32(rs, ctx); + break; + case BPF_OR | BPF_FETCH: +- emit(is64 ? rv_amoor_d(rs, rs, rd, 0, 0) : +- rv_amoor_w(rs, rs, rd, 0, 0), ctx); ++ emit(is64 ? rv_amoor_d(rs, rs, rd, 1, 1) : ++ rv_amoor_w(rs, rs, rd, 1, 1), ctx); + if (!is64) + emit_zext_32(rs, ctx); + break; + case BPF_XOR | BPF_FETCH: +- emit(is64 ? rv_amoxor_d(rs, rs, rd, 0, 0) : +- rv_amoxor_w(rs, rs, rd, 0, 0), ctx); ++ emit(is64 ? rv_amoxor_d(rs, rs, rd, 1, 1) : ++ rv_amoxor_w(rs, rs, rd, 1, 1), ctx); + if (!is64) + emit_zext_32(rs, ctx); + break; + /* src_reg = atomic_xchg(dst_reg + off16, src_reg); */ + case BPF_XCHG: +- emit(is64 ? rv_amoswap_d(rs, rs, rd, 0, 0) : +- rv_amoswap_w(rs, rs, rd, 0, 0), ctx); ++ emit(is64 ? rv_amoswap_d(rs, rs, rd, 1, 1) : ++ rv_amoswap_w(rs, rs, rd, 1, 1), ctx); + if (!is64) + emit_zext_32(rs, ctx); + break; +diff --git a/arch/s390/Makefile b/arch/s390/Makefile +index a53a36ee0731b..73873e4516866 100644 +--- a/arch/s390/Makefile ++++ b/arch/s390/Makefile +@@ -138,9 +138,6 @@ bzImage: vmlinux + zfcpdump: + $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@ + +-vdso_install: +- $(Q)$(MAKE) $(build)=arch/$(ARCH)/kernel/vdso64 $@ +- + archheaders: + $(Q)$(MAKE) $(build)=$(syscalls) uapi + +@@ -160,6 +157,9 @@ vdso_prepare: prepare0 + $(if $(CONFIG_COMPAT),$(Q)$(MAKE) \ + $(build)=arch/s390/kernel/vdso32 include/generated/vdso32-offsets.h) + ++vdso-install-y += arch/s390/kernel/vdso64/vdso64.so.dbg ++vdso-install-$(CONFIG_COMPAT) += arch/s390/kernel/vdso32/vdso32.so.dbg ++ + ifdef CONFIG_EXPOLINE_EXTERN + modules_prepare: expoline_prepare + expoline_prepare: scripts +diff --git a/arch/s390/boot/startup.c b/arch/s390/boot/startup.c +index d08db5df60913..655bbcff81ffd 100644 +--- a/arch/s390/boot/startup.c ++++ b/arch/s390/boot/startup.c +@@ -31,7 +31,6 @@ unsigned long __bootdata_preserved(max_mappable); + unsigned long __bootdata(ident_map_size); + + u64 __bootdata_preserved(stfle_fac_list[16]); +-u64 __bootdata_preserved(alt_stfle_fac_list[16]); + struct oldmem_data __bootdata_preserved(oldmem_data); + + struct machine_info machine; +diff --git a/arch/s390/include/asm/gmap.h b/arch/s390/include/asm/gmap.h +index 5cc46e0dde620..9725586f42597 100644 +--- a/arch/s390/include/asm/gmap.h ++++ b/arch/s390/include/asm/gmap.h +@@ -146,7 +146,7 @@ int gmap_mprotect_notify(struct gmap *, unsigned long start, + + void gmap_sync_dirty_log_pmd(struct gmap *gmap, unsigned long dirty_bitmap[4], + unsigned long gaddr, unsigned long vmaddr); +-int gmap_mark_unmergeable(void); ++int s390_disable_cow_sharing(void); + void s390_unlist_old_asce(struct gmap *gmap); + int s390_replace_asce(struct gmap *gmap); + void s390_uv_destroy_pfns(unsigned long count, unsigned long *pfns); +diff --git a/arch/s390/include/asm/mmu.h b/arch/s390/include/asm/mmu.h +index 829d68e2c6858..a9e5db0f2836e 100644 +--- a/arch/s390/include/asm/mmu.h ++++ b/arch/s390/include/asm/mmu.h +@@ -33,6 +33,11 @@ typedef struct { + unsigned int uses_skeys:1; + /* The mmu context uses CMM. */ + unsigned int uses_cmm:1; ++ /* ++ * The mmu context allows COW-sharing of memory pages (KSM, zeropage). ++ * Note that COW-sharing during fork() is currently always allowed. ++ */ ++ unsigned int allow_cow_sharing:1; + /* The gmaps associated with this context are allowed to use huge pages. */ + unsigned int allow_gmap_hpage_1m:1; + } mm_context_t; +diff --git a/arch/s390/include/asm/mmu_context.h b/arch/s390/include/asm/mmu_context.h +index 2a38af5a00c2d..8df6d09e9ca87 100644 +--- a/arch/s390/include/asm/mmu_context.h ++++ b/arch/s390/include/asm/mmu_context.h +@@ -36,6 +36,7 @@ static inline int init_new_context(struct task_struct *tsk, + mm->context.has_pgste = 0; + mm->context.uses_skeys = 0; + mm->context.uses_cmm = 0; ++ mm->context.allow_cow_sharing = 1; + mm->context.allow_gmap_hpage_1m = 0; + #endif + switch (mm->context.asce_limit) { +diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h +index 38290b0078c56..548f8666a5ac9 100644 +--- a/arch/s390/include/asm/pgtable.h ++++ b/arch/s390/include/asm/pgtable.h +@@ -565,10 +565,20 @@ static inline pud_t set_pud_bit(pud_t pud, pgprot_t prot) + } + + /* +- * In the case that a guest uses storage keys +- * faults should no longer be backed by zero pages ++ * As soon as the guest uses storage keys or enables PV, we deduplicate all ++ * mapped shared zeropages and prevent new shared zeropages from getting ++ * mapped. + */ +-#define mm_forbids_zeropage mm_has_pgste ++#define mm_forbids_zeropage mm_forbids_zeropage ++static inline int mm_forbids_zeropage(struct mm_struct *mm) ++{ ++#ifdef CONFIG_PGSTE ++ if (!mm->context.allow_cow_sharing) ++ return 1; ++#endif ++ return 0; ++} ++ + static inline int mm_uses_skeys(struct mm_struct *mm) + { + #ifdef CONFIG_PGSTE +diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c +index 8d0b95c173129..a3d3cb39b021a 100644 +--- a/arch/s390/kernel/ipl.c ++++ b/arch/s390/kernel/ipl.c +@@ -962,8 +962,8 @@ static ssize_t reipl_nvme_scpdata_write(struct file *filp, struct kobject *kobj, + scpdata_len += padding; + } + +- reipl_block_nvme->hdr.len = IPL_BP_FCP_LEN + scpdata_len; +- reipl_block_nvme->nvme.len = IPL_BP0_FCP_LEN + scpdata_len; ++ reipl_block_nvme->hdr.len = IPL_BP_NVME_LEN + scpdata_len; ++ reipl_block_nvme->nvme.len = IPL_BP0_NVME_LEN + scpdata_len; + reipl_block_nvme->nvme.scp_data_len = scpdata_len; + + return count; +@@ -1858,9 +1858,9 @@ static int __init dump_nvme_init(void) + } + dump_block_nvme->hdr.len = IPL_BP_NVME_LEN; + dump_block_nvme->hdr.version = IPL_PARM_BLOCK_VERSION; +- dump_block_nvme->fcp.len = IPL_BP0_NVME_LEN; +- dump_block_nvme->fcp.pbt = IPL_PBT_NVME; +- dump_block_nvme->fcp.opt = IPL_PB0_NVME_OPT_DUMP; ++ dump_block_nvme->nvme.len = IPL_BP0_NVME_LEN; ++ dump_block_nvme->nvme.pbt = IPL_PBT_NVME; ++ dump_block_nvme->nvme.opt = IPL_PB0_NVME_OPT_DUMP; + dump_capabilities |= DUMP_TYPE_NVME; + return 0; + } +diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c +index de6ad0fb2328a..d48c7afe97e62 100644 +--- a/arch/s390/kernel/setup.c ++++ b/arch/s390/kernel/setup.c +@@ -155,7 +155,7 @@ unsigned int __bootdata_preserved(zlib_dfltcc_support); + EXPORT_SYMBOL(zlib_dfltcc_support); + u64 __bootdata_preserved(stfle_fac_list[16]); + EXPORT_SYMBOL(stfle_fac_list); +-u64 __bootdata_preserved(alt_stfle_fac_list[16]); ++u64 alt_stfle_fac_list[16]; + struct oldmem_data __bootdata_preserved(oldmem_data); + + unsigned long VMALLOC_START; +diff --git a/arch/s390/kernel/vdso32/Makefile b/arch/s390/kernel/vdso32/Makefile +index c4b14a8700d88..4800d80decee6 100644 +--- a/arch/s390/kernel/vdso32/Makefile ++++ b/arch/s390/kernel/vdso32/Makefile +@@ -19,8 +19,10 @@ KBUILD_AFLAGS_32 := $(filter-out -m64,$(KBUILD_AFLAGS)) + KBUILD_AFLAGS_32 += -m31 -s + + KBUILD_CFLAGS_32 := $(filter-out -m64,$(KBUILD_CFLAGS)) ++KBUILD_CFLAGS_32 := $(filter-out -mpacked-stack,$(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 ++KBUILD_CFLAGS_32 := $(filter-out -fno-asynchronous-unwind-tables,$(KBUILD_CFLAGS_32)) ++KBUILD_CFLAGS_32 += -m31 -fPIC -shared -fno-common -fno-builtin -fasynchronous-unwind-tables + + LDFLAGS_vdso32.so.dbg += -shared -soname=linux-vdso32.so.1 \ + --hash-style=both --build-id=sha1 -melf_s390 -T +@@ -61,16 +63,6 @@ quiet_cmd_vdso32as = VDSO32A $@ + quiet_cmd_vdso32cc = VDSO32C $@ + cmd_vdso32cc = $(CC) $(c_flags) -c -o $@ $< + +-# install commands for the unstripped file +-quiet_cmd_vdso_install = INSTALL $@ +- cmd_vdso_install = cp $(obj)/$@.dbg $(MODLIB)/vdso/$@ +- +-vdso32.so: $(obj)/vdso32.so.dbg +- @mkdir -p $(MODLIB)/vdso +- $(call cmd,vdso_install) +- +-vdso_install: vdso32.so +- + # Generate VDSO offsets using helper script + gen-vdsosym := $(srctree)/$(src)/gen_vdso_offsets.sh + quiet_cmd_vdsosym = VDSOSYM $@ +diff --git a/arch/s390/kernel/vdso64/Makefile b/arch/s390/kernel/vdso64/Makefile +index 11f798e6cfea7..2f2e4e997030c 100644 +--- a/arch/s390/kernel/vdso64/Makefile ++++ b/arch/s390/kernel/vdso64/Makefile +@@ -24,8 +24,11 @@ KBUILD_AFLAGS_64 := $(filter-out -m64,$(KBUILD_AFLAGS)) + KBUILD_AFLAGS_64 += -m64 + + KBUILD_CFLAGS_64 := $(filter-out -m64,$(KBUILD_CFLAGS)) ++KBUILD_CFLAGS_64 := $(filter-out -mpacked-stack,$(KBUILD_CFLAGS_64)) + KBUILD_CFLAGS_64 := $(filter-out -mno-pic-data-is-text-relative,$(KBUILD_CFLAGS_64)) +-KBUILD_CFLAGS_64 += -m64 -fPIC -fno-common -fno-builtin ++KBUILD_CFLAGS_64 := $(filter-out -munaligned-symbols,$(KBUILD_CFLAGS_64)) ++KBUILD_CFLAGS_64 := $(filter-out -fno-asynchronous-unwind-tables,$(KBUILD_CFLAGS_64)) ++KBUILD_CFLAGS_64 += -m64 -fPIC -fno-common -fno-builtin -fasynchronous-unwind-tables + ldflags-y := -shared -soname=linux-vdso64.so.1 \ + --hash-style=both --build-id=sha1 -T + +@@ -70,16 +73,6 @@ quiet_cmd_vdso64as = VDSO64A $@ + quiet_cmd_vdso64cc = VDSO64C $@ + cmd_vdso64cc = $(CC) $(c_flags) -c -o $@ $< + +-# install commands for the unstripped file +-quiet_cmd_vdso_install = INSTALL $@ +- cmd_vdso_install = cp $(obj)/$@.dbg $(MODLIB)/vdso/$@ +- +-vdso64.so: $(obj)/vdso64.so.dbg +- @mkdir -p $(MODLIB)/vdso +- $(call cmd,vdso_install) +- +-vdso_install: vdso64.so +- + # Generate VDSO offsets using helper script + gen-vdsosym := $(srctree)/$(src)/gen_vdso_offsets.sh + quiet_cmd_vdsosym = VDSOSYM $@ +diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c +index 1af55343a606b..36f60c3dae292 100644 +--- a/arch/s390/kvm/kvm-s390.c ++++ b/arch/s390/kvm/kvm-s390.c +@@ -2632,9 +2632,7 @@ static int kvm_s390_handle_pv(struct kvm *kvm, struct kvm_pv_cmd *cmd) + if (r) + break; + +- mmap_write_lock(current->mm); +- r = gmap_mark_unmergeable(); +- mmap_write_unlock(current->mm); ++ r = s390_disable_cow_sharing(); + if (r) + break; + +diff --git a/arch/s390/mm/gmap.c b/arch/s390/mm/gmap.c +index 0da54dc9430a9..1a656db09c9fe 100644 +--- a/arch/s390/mm/gmap.c ++++ b/arch/s390/mm/gmap.c +@@ -2547,41 +2547,6 @@ static inline void thp_split_mm(struct mm_struct *mm) + } + #endif /* CONFIG_TRANSPARENT_HUGEPAGE */ + +-/* +- * Remove all empty zero pages from the mapping for lazy refaulting +- * - This must be called after mm->context.has_pgste is set, to avoid +- * future creation of zero pages +- * - This must be called after THP was disabled. +- * +- * mm contracts with s390, that even if mm were to remove a page table, +- * racing with the loop below and so causing pte_offset_map_lock() to fail, +- * it will never insert a page table containing empty zero pages once +- * mm_forbids_zeropage(mm) i.e. mm->context.has_pgste is set. +- */ +-static int __zap_zero_pages(pmd_t *pmd, unsigned long start, +- unsigned long end, struct mm_walk *walk) +-{ +- unsigned long addr; +- +- for (addr = start; addr != end; addr += PAGE_SIZE) { +- pte_t *ptep; +- spinlock_t *ptl; +- +- ptep = pte_offset_map_lock(walk->mm, pmd, addr, &ptl); +- if (!ptep) +- break; +- if (is_zero_pfn(pte_pfn(*ptep))) +- ptep_xchg_direct(walk->mm, addr, ptep, __pte(_PAGE_INVALID)); +- pte_unmap_unlock(ptep, ptl); +- } +- return 0; +-} +- +-static const struct mm_walk_ops zap_zero_walk_ops = { +- .pmd_entry = __zap_zero_pages, +- .walk_lock = PGWALK_WRLOCK, +-}; +- + /* + * switch on pgstes for its userspace process (for kvm) + */ +@@ -2599,22 +2564,142 @@ int s390_enable_sie(void) + mm->context.has_pgste = 1; + /* split thp mappings and disable thp for future mappings */ + thp_split_mm(mm); +- walk_page_range(mm, 0, TASK_SIZE, &zap_zero_walk_ops, NULL); + mmap_write_unlock(mm); + return 0; + } + EXPORT_SYMBOL_GPL(s390_enable_sie); + +-int gmap_mark_unmergeable(void) ++static int find_zeropage_pte_entry(pte_t *pte, unsigned long addr, ++ unsigned long end, struct mm_walk *walk) ++{ ++ unsigned long *found_addr = walk->private; ++ ++ /* Return 1 of the page is a zeropage. */ ++ if (is_zero_pfn(pte_pfn(*pte))) { ++ /* ++ * Shared zeropage in e.g., a FS DAX mapping? We cannot do the ++ * right thing and likely don't care: FAULT_FLAG_UNSHARE ++ * currently only works in COW mappings, which is also where ++ * mm_forbids_zeropage() is checked. ++ */ ++ if (!is_cow_mapping(walk->vma->vm_flags)) ++ return -EFAULT; ++ ++ *found_addr = addr; ++ return 1; ++ } ++ return 0; ++} ++ ++static const struct mm_walk_ops find_zeropage_ops = { ++ .pte_entry = find_zeropage_pte_entry, ++ .walk_lock = PGWALK_WRLOCK, ++}; ++ ++/* ++ * Unshare all shared zeropages, replacing them by anonymous pages. Note that ++ * we cannot simply zap all shared zeropages, because this could later ++ * trigger unexpected userfaultfd missing events. ++ * ++ * This must be called after mm->context.allow_cow_sharing was ++ * set to 0, to avoid future mappings of shared zeropages. ++ * ++ * mm contracts with s390, that even if mm were to remove a page table, ++ * and racing with walk_page_range_vma() calling pte_offset_map_lock() ++ * would fail, it will never insert a page table containing empty zero ++ * pages once mm_forbids_zeropage(mm) i.e. ++ * mm->context.allow_cow_sharing is set to 0. ++ */ ++static int __s390_unshare_zeropages(struct mm_struct *mm) ++{ ++ struct vm_area_struct *vma; ++ VMA_ITERATOR(vmi, mm, 0); ++ unsigned long addr; ++ vm_fault_t fault; ++ int rc; ++ ++ for_each_vma(vmi, vma) { ++ /* ++ * We could only look at COW mappings, but it's more future ++ * proof to catch unexpected zeropages in other mappings and ++ * fail. ++ */ ++ if ((vma->vm_flags & VM_PFNMAP) || is_vm_hugetlb_page(vma)) ++ continue; ++ addr = vma->vm_start; ++ ++retry: ++ rc = walk_page_range_vma(vma, addr, vma->vm_end, ++ &find_zeropage_ops, &addr); ++ if (rc < 0) ++ return rc; ++ else if (!rc) ++ continue; ++ ++ /* addr was updated by find_zeropage_pte_entry() */ ++ fault = handle_mm_fault(vma, addr, ++ FAULT_FLAG_UNSHARE | FAULT_FLAG_REMOTE, ++ NULL); ++ if (fault & VM_FAULT_OOM) ++ return -ENOMEM; ++ /* ++ * See break_ksm(): even after handle_mm_fault() returned 0, we ++ * must start the lookup from the current address, because ++ * handle_mm_fault() may back out if there's any difficulty. ++ * ++ * VM_FAULT_SIGBUS and VM_FAULT_SIGSEGV are unexpected but ++ * maybe they could trigger in the future on concurrent ++ * truncation. In that case, the shared zeropage would be gone ++ * and we can simply retry and make progress. ++ */ ++ cond_resched(); ++ goto retry; ++ } ++ ++ return 0; ++} ++ ++static int __s390_disable_cow_sharing(struct mm_struct *mm) + { ++ int rc; ++ ++ if (!mm->context.allow_cow_sharing) ++ return 0; ++ ++ mm->context.allow_cow_sharing = 0; ++ ++ /* Replace all shared zeropages by anonymous pages. */ ++ rc = __s390_unshare_zeropages(mm); + /* + * Make sure to disable KSM (if enabled for the whole process or + * individual VMAs). Note that nothing currently hinders user space + * from re-enabling it. + */ +- return ksm_disable(current->mm); ++ if (!rc) ++ rc = ksm_disable(mm); ++ if (rc) ++ mm->context.allow_cow_sharing = 1; ++ return rc; ++} ++ ++/* ++ * Disable most COW-sharing of memory pages for the whole process: ++ * (1) Disable KSM and unmerge/unshare any KSM pages. ++ * (2) Disallow shared zeropages and unshare any zerpages that are mapped. ++ * ++ * Not that we currently don't bother with COW-shared pages that are shared ++ * with parent/child processes due to fork(). ++ */ ++int s390_disable_cow_sharing(void) ++{ ++ int rc; ++ ++ mmap_write_lock(current->mm); ++ rc = __s390_disable_cow_sharing(current->mm); ++ mmap_write_unlock(current->mm); ++ return rc; + } +-EXPORT_SYMBOL_GPL(gmap_mark_unmergeable); ++EXPORT_SYMBOL_GPL(s390_disable_cow_sharing); + + /* + * Enable storage key handling from now on and initialize the storage +@@ -2683,7 +2768,7 @@ int s390_enable_skey(void) + goto out_up; + + mm->context.uses_skeys = 1; +- rc = gmap_mark_unmergeable(); ++ rc = __s390_disable_cow_sharing(mm); + if (rc) { + mm->context.uses_skeys = 0; + goto out_up; +diff --git a/arch/s390/net/bpf_jit_comp.c b/arch/s390/net/bpf_jit_comp.c +index 8af02176f68bf..62ee557d4b499 100644 +--- a/arch/s390/net/bpf_jit_comp.c ++++ b/arch/s390/net/bpf_jit_comp.c +@@ -1311,8 +1311,12 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp, + EMIT6_DISP_LH(0xeb000000, is32 ? (op32) : (op64), \ + (insn->imm & BPF_FETCH) ? src_reg : REG_W0, \ + src_reg, dst_reg, off); \ +- if (is32 && (insn->imm & BPF_FETCH)) \ +- EMIT_ZERO(src_reg); \ ++ if (insn->imm & BPF_FETCH) { \ ++ /* bcr 14,0 - see atomic_fetch_{add,and,or,xor}() */ \ ++ _EMIT2(0x07e0); \ ++ if (is32) \ ++ EMIT_ZERO(src_reg); \ ++ } \ + } while (0) + case BPF_ADD: + case BPF_ADD | BPF_FETCH: +diff --git a/arch/sh/kernel/kprobes.c b/arch/sh/kernel/kprobes.c +index aed1ea8e2c2f0..74051b8ddf3e7 100644 +--- a/arch/sh/kernel/kprobes.c ++++ b/arch/sh/kernel/kprobes.c +@@ -44,17 +44,12 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) + if (OPCODE_RTE(opcode)) + return -EFAULT; /* Bad breakpoint */ + ++ memcpy(p->ainsn.insn, p->addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t)); + p->opcode = opcode; + + return 0; + } + +-void __kprobes arch_copy_kprobe(struct kprobe *p) +-{ +- memcpy(p->ainsn.insn, p->addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t)); +- p->opcode = *p->addr; +-} +- + void __kprobes arch_arm_kprobe(struct kprobe *p) + { + *p->addr = BREAKPOINT_INSTRUCTION; +diff --git a/arch/sh/lib/checksum.S b/arch/sh/lib/checksum.S +index 3e07074e00981..06fed5a21e8ba 100644 +--- a/arch/sh/lib/checksum.S ++++ b/arch/sh/lib/checksum.S +@@ -33,7 +33,8 @@ + */ + + /* +- * asmlinkage __wsum csum_partial(const void *buf, int len, __wsum sum); ++ * unsigned int csum_partial(const unsigned char *buf, int len, ++ * unsigned int sum); + */ + + .text +@@ -45,31 +46,11 @@ ENTRY(csum_partial) + * Fortunately, it is easy to convert 2-byte alignment to 4-byte + * alignment for the unrolled loop. + */ ++ mov r5, r1 + mov r4, r0 +- tst #3, r0 ! Check alignment. +- bt/s 2f ! Jump if alignment is ok. +- mov r4, r7 ! Keep a copy to check for alignment ++ tst #2, r0 ! Check alignment. ++ bt 2f ! Jump if alignment is ok. + ! +- tst #1, r0 ! Check alignment. +- bt 21f ! Jump if alignment is boundary of 2bytes. +- +- ! buf is odd +- tst r5, r5 +- add #-1, r5 +- bt 9f +- mov.b @r4+, r0 +- extu.b r0, r0 +- addc r0, r6 ! t=0 from previous tst +- mov r6, r0 +- shll8 r6 +- shlr16 r0 +- shlr8 r0 +- or r0, r6 +- mov r4, r0 +- tst #2, r0 +- bt 2f +-21: +- ! buf is 2 byte aligned (len could be 0) + add #-2, r5 ! Alignment uses up two bytes. + cmp/pz r5 ! + bt/s 1f ! Jump if we had at least two bytes. +@@ -77,17 +58,16 @@ ENTRY(csum_partial) + bra 6f + add #2, r5 ! r5 was < 2. Deal with it. + 1: ++ mov r5, r1 ! Save new len for later use. + mov.w @r4+, r0 + extu.w r0, r0 + addc r0, r6 + bf 2f + add #1, r6 + 2: +- ! buf is 4 byte aligned (len could be 0) +- mov r5, r1 + mov #-5, r0 +- shld r0, r1 +- tst r1, r1 ++ shld r0, r5 ++ tst r5, r5 + bt/s 4f ! if it's =0, go to 4f + clrt + .align 2 +@@ -109,31 +89,30 @@ ENTRY(csum_partial) + addc r0, r6 + addc r2, r6 + movt r0 +- dt r1 ++ dt r5 + bf/s 3b + cmp/eq #1, r0 +- ! here, we know r1==0 +- addc r1, r6 ! add carry to r6 ++ ! here, we know r5==0 ++ addc r5, r6 ! add carry to r6 + 4: +- mov r5, r0 ++ mov r1, r0 + and #0x1c, r0 + tst r0, r0 +- bt 6f +- ! 4 bytes or more remaining +- mov r0, r1 +- shlr2 r1 ++ bt/s 6f ++ mov r0, r5 ++ shlr2 r5 + mov #0, r2 + 5: + addc r2, r6 + mov.l @r4+, r2 + movt r0 +- dt r1 ++ dt r5 + bf/s 5b + cmp/eq #1, r0 + addc r2, r6 +- addc r1, r6 ! r1==0 here, so it means add carry-bit ++ addc r5, r6 ! r5==0 here, so it means add carry-bit + 6: +- ! 3 bytes or less remaining ++ mov r1, r5 + mov #3, r0 + and r0, r5 + tst r5, r5 +@@ -159,16 +138,6 @@ ENTRY(csum_partial) + mov #0, r0 + addc r0, r6 + 9: +- ! Check if the buffer was misaligned, if so realign sum +- mov r7, r0 +- tst #1, r0 +- bt 10f +- mov r6, r0 +- shll8 r6 +- shlr16 r0 +- shlr8 r0 +- or r0, r6 +-10: + rts + mov r6, r0 + +diff --git a/arch/sparc/Makefile b/arch/sparc/Makefile +index 60da865c079a2..2a03daa68f285 100644 +--- a/arch/sparc/Makefile ++++ b/arch/sparc/Makefile +@@ -76,9 +76,8 @@ install: + archheaders: + $(Q)$(MAKE) $(build)=arch/sparc/kernel/syscalls all + +-PHONY += vdso_install +-vdso_install: +- $(Q)$(MAKE) $(build)=arch/sparc/vdso $@ ++vdso-install-$(CONFIG_SPARC64) += arch/sparc/vdso/vdso64.so.dbg ++vdso-install-$(CONFIG_COMPAT) += arch/sparc/vdso/vdso32.so.dbg + + # This is the image used for packaging + KBUILD_IMAGE := $(boot)/zImage +diff --git a/arch/sparc/vdso/Makefile b/arch/sparc/vdso/Makefile +index 77d7b9032158c..d08c3a0443f3a 100644 +--- a/arch/sparc/vdso/Makefile ++++ b/arch/sparc/vdso/Makefile +@@ -116,30 +116,3 @@ quiet_cmd_vdso = VDSO $@ + + VDSO_LDFLAGS = -shared --hash-style=both --build-id=sha1 -Bsymbolic + GCOV_PROFILE := n +- +-# +-# Install the unstripped copies of vdso*.so. If our toolchain supports +-# build-id, install .build-id links as well. +-# +-quiet_cmd_vdso_install = INSTALL $(@:install_%=%) +-define cmd_vdso_install +- cp $< "$(MODLIB)/vdso/$(@:install_%=%)"; \ +- if readelf -n $< |grep -q 'Build ID'; then \ +- buildid=`readelf -n $< |grep 'Build ID' |sed -e 's/^.*Build ID: \(.*\)$$/\1/'`; \ +- first=`echo $$buildid | cut -b-2`; \ +- last=`echo $$buildid | cut -b3-`; \ +- mkdir -p "$(MODLIB)/vdso/.build-id/$$first"; \ +- ln -sf "../../$(@:install_%=%)" "$(MODLIB)/vdso/.build-id/$$first/$$last.debug"; \ +- fi +-endef +- +-vdso_img_insttargets := $(vdso_img_sodbg:%.dbg=install_%) +- +-$(MODLIB)/vdso: FORCE +- @mkdir -p $(MODLIB)/vdso +- +-$(vdso_img_insttargets): install_%: $(obj)/%.dbg $(MODLIB)/vdso FORCE +- $(call cmd,vdso_install) +- +-PHONY += vdso_install $(vdso_img_insttargets) +-vdso_install: $(vdso_img_insttargets) FORCE +diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c +index b98545f3edb50..375200e9aba9a 100644 +--- a/arch/um/drivers/line.c ++++ b/arch/um/drivers/line.c +@@ -673,24 +673,26 @@ void register_winch_irq(int fd, int tty_fd, int pid, struct tty_port *port, + goto cleanup; + } + +- *winch = ((struct winch) { .list = LIST_HEAD_INIT(winch->list), +- .fd = fd, ++ *winch = ((struct winch) { .fd = fd, + .tty_fd = tty_fd, + .pid = pid, + .port = port, + .stack = stack }); + ++ spin_lock(&winch_handler_lock); ++ list_add(&winch->list, &winch_handlers); ++ spin_unlock(&winch_handler_lock); ++ + if (um_request_irq(WINCH_IRQ, fd, IRQ_READ, winch_interrupt, + IRQF_SHARED, "winch", winch) < 0) { + printk(KERN_ERR "register_winch_irq - failed to register " + "IRQ\n"); ++ spin_lock(&winch_handler_lock); ++ list_del(&winch->list); ++ spin_unlock(&winch_handler_lock); + goto out_free; + } + +- spin_lock(&winch_handler_lock); +- list_add(&winch->list, &winch_handlers); +- spin_unlock(&winch_handler_lock); +- + return; + + out_free: +diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c +index 50206feac577d..81405aeab8bf1 100644 +--- a/arch/um/drivers/ubd_kern.c ++++ b/arch/um/drivers/ubd_kern.c +@@ -1099,7 +1099,7 @@ static int __init ubd_init(void) + + if (irq_req_buffer == NULL) { + printk(KERN_ERR "Failed to initialize ubd buffering\n"); +- return -1; ++ return -ENOMEM; + } + io_req_buffer = kmalloc_array(UBD_REQ_BUFFER_SIZE, + sizeof(struct io_thread_req *), +@@ -1110,7 +1110,7 @@ static int __init ubd_init(void) + + if (io_req_buffer == NULL) { + printk(KERN_ERR "Failed to initialize ubd buffering\n"); +- return -1; ++ return -ENOMEM; + } + platform_driver_register(&ubd_driver); + mutex_lock(&ubd_lock); +diff --git a/arch/um/drivers/vector_kern.c b/arch/um/drivers/vector_kern.c +index 131b7cb295767..94a4dfac6c236 100644 +--- a/arch/um/drivers/vector_kern.c ++++ b/arch/um/drivers/vector_kern.c +@@ -141,7 +141,7 @@ static bool get_bpf_flash(struct arglist *def) + + if (allow != NULL) { + if (kstrtoul(allow, 10, &result) == 0) +- return (allow > 0); ++ return result > 0; + } + return false; + } +diff --git a/arch/um/include/asm/kasan.h b/arch/um/include/asm/kasan.h +index 0d6547f4ec85c..f97bb1f7b8514 100644 +--- a/arch/um/include/asm/kasan.h ++++ b/arch/um/include/asm/kasan.h +@@ -24,7 +24,6 @@ + + #ifdef CONFIG_KASAN + void kasan_init(void); +-void kasan_map_memory(void *start, unsigned long len); + extern int kasan_um_is_ready; + + #ifdef CONFIG_STATIC_LINK +diff --git a/arch/um/include/asm/mmu.h b/arch/um/include/asm/mmu.h +index 5b072aba5b658..a7cb380c0b5c0 100644 +--- a/arch/um/include/asm/mmu.h ++++ b/arch/um/include/asm/mmu.h +@@ -15,8 +15,6 @@ typedef struct mm_context { + struct page *stub_pages[2]; + } mm_context_t; + +-extern void __switch_mm(struct mm_id * mm_idp); +- + /* Avoid tangled inclusion with asm/ldt.h */ + extern long init_new_ldt(struct mm_context *to_mm, struct mm_context *from_mm); + extern void free_ldt(struct mm_context *mm); +diff --git a/arch/um/include/asm/processor-generic.h b/arch/um/include/asm/processor-generic.h +index 7414154b8e9ae..d34169883dbf0 100644 +--- a/arch/um/include/asm/processor-generic.h ++++ b/arch/um/include/asm/processor-generic.h +@@ -95,7 +95,6 @@ extern struct cpuinfo_um boot_cpu_data; + #define current_cpu_data boot_cpu_data + #define cache_line_size() (boot_cpu_data.cache_alignment) + +-extern unsigned long get_thread_reg(int reg, jmp_buf *buf); + #define KSTK_REG(tsk, reg) get_thread_reg(reg, &tsk->thread.switch_buf) + extern unsigned long __get_wchan(struct task_struct *p); + +diff --git a/arch/um/include/shared/kern_util.h b/arch/um/include/shared/kern_util.h +index 444bae755b16a..7372746c16875 100644 +--- a/arch/um/include/shared/kern_util.h ++++ b/arch/um/include/shared/kern_util.h +@@ -67,4 +67,6 @@ extern void fatal_sigsegv(void) __attribute__ ((noreturn)); + + void um_idle_sleep(void); + ++void kasan_map_memory(void *start, size_t len); ++ + #endif +diff --git a/arch/um/include/shared/skas/mm_id.h b/arch/um/include/shared/skas/mm_id.h +index e82e203f5f419..92dbf727e3842 100644 +--- a/arch/um/include/shared/skas/mm_id.h ++++ b/arch/um/include/shared/skas/mm_id.h +@@ -15,4 +15,6 @@ struct mm_id { + int kill; + }; + ++void __switch_mm(struct mm_id *mm_idp); ++ + #endif +diff --git a/arch/um/os-Linux/mem.c b/arch/um/os-Linux/mem.c +index 8530b2e086049..c6c9495b14321 100644 +--- a/arch/um/os-Linux/mem.c ++++ b/arch/um/os-Linux/mem.c +@@ -15,6 +15,7 @@ + #include + #include + #include ++#include + #include + + /* +diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig +index be9248e5cb71b..82d12c93feabe 100644 +--- a/arch/x86/Kconfig ++++ b/arch/x86/Kconfig +@@ -2428,9 +2428,13 @@ menuconfig CPU_MITIGATIONS + help + Say Y here to enable options which enable mitigations for hardware + vulnerabilities (usually related to speculative execution). ++ Mitigations can be disabled or restricted to SMT systems at runtime ++ via the "mitigations" kernel parameter. + +- If you say N, all mitigations will be disabled. You really +- should know what you are doing to say so. ++ If you say N, all mitigations will be disabled. This CANNOT be ++ overridden at runtime. ++ ++ Say 'Y', unless you really know what you are doing. + + if CPU_MITIGATIONS + +diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug +index c5d614d28a759..74777a97e394a 100644 +--- a/arch/x86/Kconfig.debug ++++ b/arch/x86/Kconfig.debug +@@ -248,6 +248,7 @@ config UNWINDER_ORC + + config UNWINDER_FRAME_POINTER + bool "Frame pointer unwinder" ++ select ARCH_WANT_FRAME_POINTERS + select FRAME_POINTER + help + This option enables the frame pointer unwinder for unwinding kernel +@@ -271,7 +272,3 @@ config UNWINDER_GUESS + overhead. + + endchoice +- +-config FRAME_POINTER +- depends on !UNWINDER_ORC && !UNWINDER_GUESS +- bool +diff --git a/arch/x86/Makefile b/arch/x86/Makefile +index 5bfe5caaa444b..3ff53a2d4ff08 100644 +--- a/arch/x86/Makefile ++++ b/arch/x86/Makefile +@@ -291,9 +291,10 @@ PHONY += install + install: + $(call cmd,install) + +-PHONY += vdso_install +-vdso_install: +- $(Q)$(MAKE) $(build)=arch/x86/entry/vdso $@ ++vdso-install-$(CONFIG_X86_64) += arch/x86/entry/vdso/vdso64.so.dbg ++vdso-install-$(CONFIG_X86_X32_ABI) += arch/x86/entry/vdso/vdsox32.so.dbg ++vdso-install-$(CONFIG_X86_32) += arch/x86/entry/vdso/vdso32.so.dbg ++vdso-install-$(CONFIG_IA32_EMULATION) += arch/x86/entry/vdso/vdso32.so.dbg + + archprepare: checkbin + checkbin: +diff --git a/arch/x86/boot/compressed/head_64.S b/arch/x86/boot/compressed/head_64.S +index bf4a10a5794f1..1dcb794c5479e 100644 +--- a/arch/x86/boot/compressed/head_64.S ++++ b/arch/x86/boot/compressed/head_64.S +@@ -398,6 +398,11 @@ SYM_CODE_START(startup_64) + call sev_enable + #endif + ++ /* Preserve only the CR4 bits that must be preserved, and clear the rest */ ++ movq %cr4, %rax ++ andl $(X86_CR4_PAE | X86_CR4_MCE | X86_CR4_LA57), %eax ++ movq %rax, %cr4 ++ + /* + * configure_5level_paging() updates the number of paging levels using + * a trampoline in 32-bit addressable memory if the current number does +diff --git a/arch/x86/crypto/nh-avx2-x86_64.S b/arch/x86/crypto/nh-avx2-x86_64.S +index ef73a3ab87263..791386d9a83aa 100644 +--- a/arch/x86/crypto/nh-avx2-x86_64.S ++++ b/arch/x86/crypto/nh-avx2-x86_64.S +@@ -154,5 +154,6 @@ SYM_TYPED_FUNC_START(nh_avx2) + vpaddq T1, T0, T0 + vpaddq T4, T0, T0 + vmovdqu T0, (HASH) ++ vzeroupper + RET + SYM_FUNC_END(nh_avx2) +diff --git a/arch/x86/crypto/sha256-avx2-asm.S b/arch/x86/crypto/sha256-avx2-asm.S +index 9918212faf914..0ffb072be9561 100644 +--- a/arch/x86/crypto/sha256-avx2-asm.S ++++ b/arch/x86/crypto/sha256-avx2-asm.S +@@ -716,6 +716,7 @@ SYM_TYPED_FUNC_START(sha256_transform_rorx) + popq %r13 + popq %r12 + popq %rbx ++ vzeroupper + RET + SYM_FUNC_END(sha256_transform_rorx) + +diff --git a/arch/x86/crypto/sha512-avx2-asm.S b/arch/x86/crypto/sha512-avx2-asm.S +index f08496cd68708..24973f42c43ff 100644 +--- a/arch/x86/crypto/sha512-avx2-asm.S ++++ b/arch/x86/crypto/sha512-avx2-asm.S +@@ -680,6 +680,7 @@ SYM_TYPED_FUNC_START(sha512_transform_rorx) + pop %r12 + pop %rbx + ++ vzeroupper + RET + SYM_FUNC_END(sha512_transform_rorx) + +diff --git a/arch/x86/entry/vdso/Makefile b/arch/x86/entry/vdso/Makefile +index 6a1821bd7d5e9..c197efd829228 100644 +--- a/arch/x86/entry/vdso/Makefile ++++ b/arch/x86/entry/vdso/Makefile +@@ -190,31 +190,4 @@ GCOV_PROFILE := n + quiet_cmd_vdso_and_check = VDSO $@ + cmd_vdso_and_check = $(cmd_vdso); $(cmd_vdso_check) + +-# +-# Install the unstripped copies of vdso*.so. If our toolchain supports +-# build-id, install .build-id links as well. +-# +-quiet_cmd_vdso_install = INSTALL $(@:install_%=%) +-define cmd_vdso_install +- cp $< "$(MODLIB)/vdso/$(@:install_%=%)"; \ +- if readelf -n $< |grep -q 'Build ID'; then \ +- buildid=`readelf -n $< |grep 'Build ID' |sed -e 's/^.*Build ID: \(.*\)$$/\1/'`; \ +- first=`echo $$buildid | cut -b-2`; \ +- last=`echo $$buildid | cut -b3-`; \ +- mkdir -p "$(MODLIB)/vdso/.build-id/$$first"; \ +- ln -sf "../../$(@:install_%=%)" "$(MODLIB)/vdso/.build-id/$$first/$$last.debug"; \ +- fi +-endef +- +-vdso_img_insttargets := $(vdso_img_sodbg:%.dbg=install_%) +- +-$(MODLIB)/vdso: FORCE +- @mkdir -p $(MODLIB)/vdso +- +-$(vdso_img_insttargets): install_%: $(obj)/%.dbg $(MODLIB)/vdso +- $(call cmd,vdso_install) +- +-PHONY += vdso_install $(vdso_img_insttargets) +-vdso_install: $(vdso_img_insttargets) +- + clean-files := vdso32.so vdso32.so.dbg vdso64* vdso-image-*.c vdsox32.so* +diff --git a/arch/x86/entry/vsyscall/vsyscall_64.c b/arch/x86/entry/vsyscall/vsyscall_64.c +index e0ca8120aea87..1245000a8792f 100644 +--- a/arch/x86/entry/vsyscall/vsyscall_64.c ++++ b/arch/x86/entry/vsyscall/vsyscall_64.c +@@ -98,11 +98,6 @@ static int addr_to_vsyscall_nr(unsigned long addr) + + static bool write_ok_or_segv(unsigned long ptr, size_t size) + { +- /* +- * XXX: if access_ok, get_user, and put_user handled +- * sig_on_uaccess_err, this could go away. +- */ +- + if (!access_ok((void __user *)ptr, size)) { + struct thread_struct *thread = ¤t->thread; + +@@ -120,10 +115,8 @@ static bool write_ok_or_segv(unsigned long ptr, size_t size) + bool emulate_vsyscall(unsigned long error_code, + struct pt_regs *regs, unsigned long address) + { +- struct task_struct *tsk; + unsigned long caller; + int vsyscall_nr, syscall_nr, tmp; +- int prev_sig_on_uaccess_err; + long ret; + unsigned long orig_dx; + +@@ -172,8 +165,6 @@ bool emulate_vsyscall(unsigned long error_code, + goto sigsegv; + } + +- tsk = current; +- + /* + * Check for access_ok violations and find the syscall nr. + * +@@ -234,12 +225,8 @@ bool emulate_vsyscall(unsigned long error_code, + goto do_ret; /* skip requested */ + + /* +- * With a real vsyscall, page faults cause SIGSEGV. We want to +- * preserve that behavior to make writing exploits harder. ++ * With a real vsyscall, page faults cause SIGSEGV. + */ +- prev_sig_on_uaccess_err = current->thread.sig_on_uaccess_err; +- current->thread.sig_on_uaccess_err = 1; +- + ret = -EFAULT; + switch (vsyscall_nr) { + case 0: +@@ -262,23 +249,12 @@ bool emulate_vsyscall(unsigned long error_code, + break; + } + +- current->thread.sig_on_uaccess_err = prev_sig_on_uaccess_err; +- + check_fault: + if (ret == -EFAULT) { + /* Bad news -- userspace fed a bad pointer to a vsyscall. */ + warn_bad_vsyscall(KERN_INFO, regs, + "vsyscall fault (exploit attempt?)"); +- +- /* +- * If we failed to generate a signal for any reason, +- * generate one here. (This should be impossible.) +- */ +- if (WARN_ON_ONCE(!sigismember(&tsk->pending.signal, SIGBUS) && +- !sigismember(&tsk->pending.signal, SIGSEGV))) +- goto sigsegv; +- +- return true; /* Don't emulate the ret. */ ++ goto sigsegv; + } + + regs->ax = ret; +diff --git a/arch/x86/include/asm/cmpxchg_64.h b/arch/x86/include/asm/cmpxchg_64.h +index 44b08b53ab32f..c1d6cd58f8094 100644 +--- a/arch/x86/include/asm/cmpxchg_64.h ++++ b/arch/x86/include/asm/cmpxchg_64.h +@@ -62,7 +62,7 @@ static __always_inline u128 arch_cmpxchg128_local(volatile u128 *ptr, u128 old, + asm volatile(_lock "cmpxchg16b %[ptr]" \ + CC_SET(e) \ + : CC_OUT(e) (ret), \ +- [ptr] "+m" (*ptr), \ ++ [ptr] "+m" (*(_ptr)), \ + "+a" (o.low), "+d" (o.high) \ + : "b" (n.low), "c" (n.high) \ + : "memory"); \ +diff --git a/arch/x86/include/asm/pgtable_types.h b/arch/x86/include/asm/pgtable_types.h +index 9abb8cc4cd474..b786449626267 100644 +--- a/arch/x86/include/asm/pgtable_types.h ++++ b/arch/x86/include/asm/pgtable_types.h +@@ -567,6 +567,8 @@ static inline void update_page_count(int level, unsigned long pages) { } + extern pte_t *lookup_address(unsigned long address, unsigned int *level); + extern pte_t *lookup_address_in_pgd(pgd_t *pgd, unsigned long address, + unsigned int *level); ++pte_t *lookup_address_in_pgd_attr(pgd_t *pgd, unsigned long address, ++ unsigned int *level, bool *nx, bool *rw); + extern pmd_t *lookup_pmd_address(unsigned long address); + extern phys_addr_t slow_virt_to_phys(void *__address); + extern int __init kernel_map_pages_in_pgd(pgd_t *pgd, u64 pfn, +diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h +index 191f1d8f05061..6e19d0f226000 100644 +--- a/arch/x86/include/asm/processor.h ++++ b/arch/x86/include/asm/processor.h +@@ -464,7 +464,6 @@ struct thread_struct { + unsigned long iopl_emul; + + unsigned int iopl_warn:1; +- unsigned int sig_on_uaccess_err:1; + + /* + * Protection Keys Register for Userspace. Loaded immediately on +diff --git a/arch/x86/include/asm/sparsemem.h b/arch/x86/include/asm/sparsemem.h +index 1be13b2dfe8bf..64df897c0ee30 100644 +--- a/arch/x86/include/asm/sparsemem.h ++++ b/arch/x86/include/asm/sparsemem.h +@@ -37,8 +37,6 @@ extern int phys_to_target_node(phys_addr_t start); + #define phys_to_target_node phys_to_target_node + extern int memory_add_physaddr_to_nid(u64 start); + #define memory_add_physaddr_to_nid memory_add_physaddr_to_nid +-extern int numa_fill_memblks(u64 start, u64 end); +-#define numa_fill_memblks numa_fill_memblks + #endif + #endif /* __ASSEMBLY__ */ + +diff --git a/arch/x86/kernel/apic/vector.c b/arch/x86/kernel/apic/vector.c +index 319448d87b99a..218ef9072c0c6 100644 +--- a/arch/x86/kernel/apic/vector.c ++++ b/arch/x86/kernel/apic/vector.c +@@ -1036,7 +1036,8 @@ static void __vector_schedule_cleanup(struct apic_chip_data *apicd) + add_timer_on(&cl->timer, cpu); + } + } else { +- apicd->prev_vector = 0; ++ pr_warn("IRQ %u schedule cleanup for offline CPU %u\n", apicd->irq, cpu); ++ free_moved_vector(apicd); + } + raw_spin_unlock(&vector_lock); + } +@@ -1073,6 +1074,7 @@ void irq_complete_move(struct irq_cfg *cfg) + */ + void irq_force_complete_move(struct irq_desc *desc) + { ++ unsigned int cpu = smp_processor_id(); + struct apic_chip_data *apicd; + struct irq_data *irqd; + unsigned int vector; +@@ -1097,10 +1099,11 @@ void irq_force_complete_move(struct irq_desc *desc) + goto unlock; + + /* +- * If prev_vector is empty, no action required. ++ * If prev_vector is empty or the descriptor is neither currently ++ * nor previously on the outgoing CPU no action required. + */ + vector = apicd->prev_vector; +- if (!vector) ++ if (!vector || (apicd->cpu != cpu && apicd->prev_cpu != cpu)) + goto unlock; + + /* +diff --git a/arch/x86/kernel/tsc_sync.c b/arch/x86/kernel/tsc_sync.c +index 1123ef3ccf901..4334033658edf 100644 +--- a/arch/x86/kernel/tsc_sync.c ++++ b/arch/x86/kernel/tsc_sync.c +@@ -193,11 +193,9 @@ bool tsc_store_and_check_tsc_adjust(bool bootcpu) + cur->warned = false; + + /* +- * If a non-zero TSC value for socket 0 may be valid then the default +- * adjusted value cannot assumed to be zero either. ++ * The default adjust value cannot be assumed to be zero on any socket. + */ +- if (tsc_async_resets) +- cur->adjusted = bootval; ++ cur->adjusted = bootval; + + /* + * Check whether this CPU is the first in a package to come up. In +diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c +index 77458137cab17..ac042a9a61f57 100644 +--- a/arch/x86/kvm/cpuid.c ++++ b/arch/x86/kvm/cpuid.c +@@ -1212,9 +1212,8 @@ static inline int __do_cpuid_func(struct kvm_cpuid_array *array, u32 function) + entry->eax = entry->ebx = entry->ecx = 0; + break; + case 0x80000008: { +- unsigned g_phys_as = (entry->eax >> 16) & 0xff; +- unsigned virt_as = max((entry->eax >> 8) & 0xff, 48U); +- unsigned phys_as = entry->eax & 0xff; ++ unsigned int virt_as = max((entry->eax >> 8) & 0xff, 48U); ++ unsigned int phys_as; + + /* + * If TDP (NPT) is disabled use the adjusted host MAXPHYADDR as +@@ -1222,16 +1221,16 @@ static inline int __do_cpuid_func(struct kvm_cpuid_array *array, u32 function) + * reductions in MAXPHYADDR for memory encryption affect shadow + * paging, too. + * +- * If TDP is enabled but an explicit guest MAXPHYADDR is not +- * provided, use the raw bare metal MAXPHYADDR as reductions to +- * the HPAs do not affect GPAs. ++ * If TDP is enabled, use the raw bare metal MAXPHYADDR as ++ * reductions to the HPAs do not affect GPAs. + */ +- if (!tdp_enabled) +- g_phys_as = boot_cpu_data.x86_phys_bits; +- else if (!g_phys_as) +- g_phys_as = phys_as; ++ if (!tdp_enabled) { ++ phys_as = boot_cpu_data.x86_phys_bits; ++ } else { ++ phys_as = entry->eax & 0xff; ++ } + +- entry->eax = g_phys_as | (virt_as << 8); ++ entry->eax = phys_as | (virt_as << 8); + entry->ecx &= ~(GENMASK(31, 16) | GENMASK(11, 8)); + entry->edx = 0; + cpuid_entry_override(entry, CPUID_8000_0008_EBX); +diff --git a/arch/x86/lib/x86-opcode-map.txt b/arch/x86/lib/x86-opcode-map.txt +index 5168ee0360b24..d1ccd06c53127 100644 +--- a/arch/x86/lib/x86-opcode-map.txt ++++ b/arch/x86/lib/x86-opcode-map.txt +@@ -148,7 +148,7 @@ AVXcode: + 65: SEG=GS (Prefix) + 66: Operand-Size (Prefix) + 67: Address-Size (Prefix) +-68: PUSH Iz (d64) ++68: PUSH Iz + 69: IMUL Gv,Ev,Iz + 6a: PUSH Ib (d64) + 6b: IMUL Gv,Ev,Ib +@@ -698,10 +698,10 @@ AVXcode: 2 + 4d: vrcp14ss/d Vsd,Hpd,Wsd (66),(ev) + 4e: vrsqrt14ps/d Vpd,Wpd (66),(ev) + 4f: vrsqrt14ss/d Vsd,Hsd,Wsd (66),(ev) +-50: vpdpbusd Vx,Hx,Wx (66),(ev) +-51: vpdpbusds Vx,Hx,Wx (66),(ev) +-52: vdpbf16ps Vx,Hx,Wx (F3),(ev) | vpdpwssd Vx,Hx,Wx (66),(ev) | vp4dpwssd Vdqq,Hdqq,Wdq (F2),(ev) +-53: vpdpwssds Vx,Hx,Wx (66),(ev) | vp4dpwssds Vdqq,Hdqq,Wdq (F2),(ev) ++50: vpdpbusd Vx,Hx,Wx (66) ++51: vpdpbusds Vx,Hx,Wx (66) ++52: vdpbf16ps Vx,Hx,Wx (F3),(ev) | vpdpwssd Vx,Hx,Wx (66) | vp4dpwssd Vdqq,Hdqq,Wdq (F2),(ev) ++53: vpdpwssds Vx,Hx,Wx (66) | vp4dpwssds Vdqq,Hdqq,Wdq (F2),(ev) + 54: vpopcntb/w Vx,Wx (66),(ev) + 55: vpopcntd/q Vx,Wx (66),(ev) + 58: vpbroadcastd Vx,Wx (66),(v) +diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c +index e238517968836..6529b3e2cff3c 100644 +--- a/arch/x86/mm/fault.c ++++ b/arch/x86/mm/fault.c +@@ -717,39 +717,8 @@ kernelmode_fixup_or_oops(struct pt_regs *regs, unsigned long error_code, + WARN_ON_ONCE(user_mode(regs)); + + /* Are we prepared to handle this kernel fault? */ +- if (fixup_exception(regs, X86_TRAP_PF, error_code, address)) { +- /* +- * Any interrupt that takes a fault gets the fixup. This makes +- * the below recursive fault logic only apply to a faults from +- * task context. +- */ +- if (in_interrupt()) +- return; +- +- /* +- * Per the above we're !in_interrupt(), aka. task context. +- * +- * In this case we need to make sure we're not recursively +- * faulting through the emulate_vsyscall() logic. +- */ +- if (current->thread.sig_on_uaccess_err && signal) { +- sanitize_error_code(address, &error_code); +- +- set_signal_archinfo(address, error_code); +- +- if (si_code == SEGV_PKUERR) { +- force_sig_pkuerr((void __user *)address, pkey); +- } else { +- /* XXX: hwpoison faults will set the wrong code. */ +- force_sig_fault(signal, si_code, (void __user *)address); +- } +- } +- +- /* +- * Barring that, we can do the fixup and be happy. +- */ ++ if (fixup_exception(regs, X86_TRAP_PF, error_code, address)) + return; +- } + + /* + * AMD erratum #91 manifests as a spurious page fault on a PREFETCH +diff --git a/arch/x86/mm/numa.c b/arch/x86/mm/numa.c +index dae5c952735c7..c7fa5396c0f05 100644 +--- a/arch/x86/mm/numa.c ++++ b/arch/x86/mm/numa.c +@@ -956,6 +956,8 @@ int memory_add_physaddr_to_nid(u64 start) + } + EXPORT_SYMBOL_GPL(memory_add_physaddr_to_nid); + ++#endif ++ + static int __init cmp_memblk(const void *a, const void *b) + { + const struct numa_memblk *ma = *(const struct numa_memblk **)a; +@@ -1028,5 +1030,3 @@ int __init numa_fill_memblks(u64 start, u64 end) + } + return 0; + } +- +-#endif +diff --git a/arch/x86/mm/pat/set_memory.c b/arch/x86/mm/pat/set_memory.c +index f3c4c756fe1ee..2d850f6bae701 100644 +--- a/arch/x86/mm/pat/set_memory.c ++++ b/arch/x86/mm/pat/set_memory.c +@@ -619,7 +619,8 @@ static inline pgprot_t static_protections(pgprot_t prot, unsigned long start, + * Validate strict W^X semantics. + */ + static inline pgprot_t verify_rwx(pgprot_t old, pgprot_t new, unsigned long start, +- unsigned long pfn, unsigned long npg) ++ unsigned long pfn, unsigned long npg, ++ bool nx, bool rw) + { + unsigned long end; + +@@ -641,6 +642,10 @@ static inline pgprot_t verify_rwx(pgprot_t old, pgprot_t new, unsigned long star + if ((pgprot_val(new) & (_PAGE_RW | _PAGE_NX)) != _PAGE_RW) + return new; + ++ /* Non-leaf translation entries can disable writing or execution. */ ++ if (!rw || nx) ++ return new; ++ + end = start + npg * PAGE_SIZE - 1; + WARN_ONCE(1, "CPA detected W^X violation: %016llx -> %016llx range: 0x%016lx - 0x%016lx PFN %lx\n", + (unsigned long long)pgprot_val(old), +@@ -657,20 +662,26 @@ static inline pgprot_t verify_rwx(pgprot_t old, pgprot_t new, unsigned long star + + /* + * Lookup the page table entry for a virtual address in a specific pgd. +- * Return a pointer to the entry and the level of the mapping. ++ * Return a pointer to the entry, the level of the mapping, and the effective ++ * NX and RW bits of all page table levels. + */ +-pte_t *lookup_address_in_pgd(pgd_t *pgd, unsigned long address, +- unsigned int *level) ++pte_t *lookup_address_in_pgd_attr(pgd_t *pgd, unsigned long address, ++ unsigned int *level, bool *nx, bool *rw) + { + p4d_t *p4d; + pud_t *pud; + pmd_t *pmd; + + *level = PG_LEVEL_NONE; ++ *nx = false; ++ *rw = true; + + if (pgd_none(*pgd)) + return NULL; + ++ *nx |= pgd_flags(*pgd) & _PAGE_NX; ++ *rw &= pgd_flags(*pgd) & _PAGE_RW; ++ + p4d = p4d_offset(pgd, address); + if (p4d_none(*p4d)) + return NULL; +@@ -679,6 +690,9 @@ pte_t *lookup_address_in_pgd(pgd_t *pgd, unsigned long address, + if (p4d_large(*p4d) || !p4d_present(*p4d)) + return (pte_t *)p4d; + ++ *nx |= p4d_flags(*p4d) & _PAGE_NX; ++ *rw &= p4d_flags(*p4d) & _PAGE_RW; ++ + pud = pud_offset(p4d, address); + if (pud_none(*pud)) + return NULL; +@@ -687,6 +701,9 @@ pte_t *lookup_address_in_pgd(pgd_t *pgd, unsigned long address, + if (pud_leaf(*pud) || !pud_present(*pud)) + return (pte_t *)pud; + ++ *nx |= pud_flags(*pud) & _PAGE_NX; ++ *rw &= pud_flags(*pud) & _PAGE_RW; ++ + pmd = pmd_offset(pud, address); + if (pmd_none(*pmd)) + return NULL; +@@ -695,11 +712,26 @@ pte_t *lookup_address_in_pgd(pgd_t *pgd, unsigned long address, + if (pmd_large(*pmd) || !pmd_present(*pmd)) + return (pte_t *)pmd; + ++ *nx |= pmd_flags(*pmd) & _PAGE_NX; ++ *rw &= pmd_flags(*pmd) & _PAGE_RW; ++ + *level = PG_LEVEL_4K; + + return pte_offset_kernel(pmd, address); + } + ++/* ++ * Lookup the page table entry for a virtual address in a specific pgd. ++ * Return a pointer to the entry and the level of the mapping. ++ */ ++pte_t *lookup_address_in_pgd(pgd_t *pgd, unsigned long address, ++ unsigned int *level) ++{ ++ bool nx, rw; ++ ++ return lookup_address_in_pgd_attr(pgd, address, level, &nx, &rw); ++} ++ + /* + * Lookup the page table entry for a virtual address. Return a pointer + * to the entry and the level of the mapping. +@@ -715,13 +747,16 @@ pte_t *lookup_address(unsigned long address, unsigned int *level) + EXPORT_SYMBOL_GPL(lookup_address); + + static pte_t *_lookup_address_cpa(struct cpa_data *cpa, unsigned long address, +- unsigned int *level) ++ unsigned int *level, bool *nx, bool *rw) + { +- if (cpa->pgd) +- return lookup_address_in_pgd(cpa->pgd + pgd_index(address), +- address, level); ++ pgd_t *pgd; ++ ++ if (!cpa->pgd) ++ pgd = pgd_offset_k(address); ++ else ++ pgd = cpa->pgd + pgd_index(address); + +- return lookup_address(address, level); ++ return lookup_address_in_pgd_attr(pgd, address, level, nx, rw); + } + + /* +@@ -845,12 +880,13 @@ static int __should_split_large_page(pte_t *kpte, unsigned long address, + pgprot_t old_prot, new_prot, req_prot, chk_prot; + pte_t new_pte, *tmp; + enum pg_level level; ++ bool nx, rw; + + /* + * Check for races, another CPU might have split this page + * up already: + */ +- tmp = _lookup_address_cpa(cpa, address, &level); ++ tmp = _lookup_address_cpa(cpa, address, &level, &nx, &rw); + if (tmp != kpte) + return 1; + +@@ -961,7 +997,8 @@ static int __should_split_large_page(pte_t *kpte, unsigned long address, + new_prot = static_protections(req_prot, lpaddr, old_pfn, numpages, + psize, CPA_DETECT); + +- new_prot = verify_rwx(old_prot, new_prot, lpaddr, old_pfn, numpages); ++ new_prot = verify_rwx(old_prot, new_prot, lpaddr, old_pfn, numpages, ++ nx, rw); + + /* + * If there is a conflict, split the large page. +@@ -1042,6 +1079,7 @@ __split_large_page(struct cpa_data *cpa, pte_t *kpte, unsigned long address, + pte_t *pbase = (pte_t *)page_address(base); + unsigned int i, level; + pgprot_t ref_prot; ++ bool nx, rw; + pte_t *tmp; + + spin_lock(&pgd_lock); +@@ -1049,7 +1087,7 @@ __split_large_page(struct cpa_data *cpa, pte_t *kpte, unsigned long address, + * Check for races, another CPU might have split this page + * up for us already: + */ +- tmp = _lookup_address_cpa(cpa, address, &level); ++ tmp = _lookup_address_cpa(cpa, address, &level, &nx, &rw); + if (tmp != kpte) { + spin_unlock(&pgd_lock); + return 1; +@@ -1590,10 +1628,11 @@ static int __change_page_attr(struct cpa_data *cpa, int primary) + int do_split, err; + unsigned int level; + pte_t *kpte, old_pte; ++ bool nx, rw; + + address = __cpa_addr(cpa, cpa->curpage); + repeat: +- kpte = _lookup_address_cpa(cpa, address, &level); ++ kpte = _lookup_address_cpa(cpa, address, &level, &nx, &rw); + if (!kpte) + return __cpa_process_fault(cpa, address, primary); + +@@ -1615,7 +1654,8 @@ static int __change_page_attr(struct cpa_data *cpa, int primary) + new_prot = static_protections(new_prot, address, pfn, 1, 0, + CPA_PROTECT); + +- new_prot = verify_rwx(old_prot, new_prot, address, pfn, 1); ++ new_prot = verify_rwx(old_prot, new_prot, address, pfn, 1, ++ nx, rw); + + new_prot = pgprot_clear_protnone_bits(new_prot); + +diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c +index a6a4d3ca8ddc6..878a4c6dd7565 100644 +--- a/arch/x86/net/bpf_jit_comp.c ++++ b/arch/x86/net/bpf_jit_comp.c +@@ -1458,36 +1458,41 @@ st: if (is_imm8(insn->off)) + if (BPF_MODE(insn->code) == BPF_PROBE_MEM || + BPF_MODE(insn->code) == BPF_PROBE_MEMSX) { + /* Conservatively check that src_reg + insn->off is a kernel address: +- * src_reg + insn->off >= TASK_SIZE_MAX + PAGE_SIZE +- * src_reg is used as scratch for src_reg += insn->off and restored +- * after emit_ldx if necessary ++ * src_reg + insn->off > TASK_SIZE_MAX + PAGE_SIZE ++ * and ++ * src_reg + insn->off < VSYSCALL_ADDR + */ + +- u64 limit = TASK_SIZE_MAX + PAGE_SIZE; ++ u64 limit = TASK_SIZE_MAX + PAGE_SIZE - VSYSCALL_ADDR; + u8 *end_of_jmp; + +- /* At end of these emitted checks, insn->off will have been added +- * to src_reg, so no need to do relative load with insn->off offset +- */ +- insn_off = 0; ++ /* movabsq r10, VSYSCALL_ADDR */ ++ emit_mov_imm64(&prog, BPF_REG_AX, (long)VSYSCALL_ADDR >> 32, ++ (u32)(long)VSYSCALL_ADDR); + +- /* movabsq r11, limit */ +- EMIT2(add_1mod(0x48, AUX_REG), add_1reg(0xB8, AUX_REG)); +- EMIT((u32)limit, 4); +- EMIT(limit >> 32, 4); ++ /* mov src_reg, r11 */ ++ EMIT_mov(AUX_REG, src_reg); + + if (insn->off) { +- /* add src_reg, insn->off */ +- maybe_emit_1mod(&prog, src_reg, true); +- EMIT2_off32(0x81, add_1reg(0xC0, src_reg), insn->off); ++ /* add r11, insn->off */ ++ maybe_emit_1mod(&prog, AUX_REG, true); ++ EMIT2_off32(0x81, add_1reg(0xC0, AUX_REG), insn->off); + } + +- /* cmp src_reg, r11 */ +- maybe_emit_mod(&prog, src_reg, AUX_REG, true); +- EMIT2(0x39, add_2reg(0xC0, src_reg, AUX_REG)); ++ /* sub r11, r10 */ ++ maybe_emit_mod(&prog, AUX_REG, BPF_REG_AX, true); ++ EMIT2(0x29, add_2reg(0xC0, AUX_REG, BPF_REG_AX)); ++ ++ /* movabsq r10, limit */ ++ emit_mov_imm64(&prog, BPF_REG_AX, (long)limit >> 32, ++ (u32)(long)limit); ++ ++ /* cmp r10, r11 */ ++ maybe_emit_mod(&prog, AUX_REG, BPF_REG_AX, true); ++ EMIT2(0x39, add_2reg(0xC0, AUX_REG, BPF_REG_AX)); + +- /* if unsigned '>=', goto load */ +- EMIT2(X86_JAE, 0); ++ /* if unsigned '>', goto load */ ++ EMIT2(X86_JA, 0); + end_of_jmp = prog; + + /* xor dst_reg, dst_reg */ +@@ -1513,18 +1518,6 @@ st: if (is_imm8(insn->off)) + /* populate jmp_offset for JMP above */ + start_of_ldx[-1] = prog - start_of_ldx; + +- if (insn->off && src_reg != dst_reg) { +- /* sub src_reg, insn->off +- * Restore src_reg after "add src_reg, insn->off" in prev +- * if statement. But if src_reg == dst_reg, emit_ldx +- * above already clobbered src_reg, so no need to restore. +- * If add src_reg, insn->off was unnecessary, no need to +- * restore either. +- */ +- maybe_emit_1mod(&prog, src_reg, true); +- EMIT2_off32(0x81, add_1reg(0xE8, src_reg), insn->off); +- } +- + if (!bpf_prog->aux->extable) + break; + +diff --git a/arch/x86/pci/mmconfig-shared.c b/arch/x86/pci/mmconfig-shared.c +index e9497ee0f8547..8447d1e2e1961 100644 +--- a/arch/x86/pci/mmconfig-shared.c ++++ b/arch/x86/pci/mmconfig-shared.c +@@ -527,7 +527,34 @@ pci_mmcfg_check_reserved(struct device *dev, struct pci_mmcfg_region *cfg, int e + { + struct resource *conflict; + +- if (!early && !acpi_disabled) { ++ if (early) { ++ ++ /* ++ * Don't try to do this check unless configuration type 1 ++ * is available. How about type 2? ++ */ ++ ++ /* ++ * 946f2ee5c731 ("Check that MCFG points to an e820 ++ * reserved area") added this E820 check in 2006 to work ++ * around BIOS defects. ++ * ++ * Per PCI Firmware r3.3, sec 4.1.2, ECAM space must be ++ * reserved by a PNP0C02 resource, but it need not be ++ * mentioned in E820. Before the ACPI interpreter is ++ * available, we can't check for PNP0C02 resources, so ++ * there's no reliable way to verify the region in this ++ * early check. Keep it only for the old machines that ++ * motivated 946f2ee5c731. ++ */ ++ if (dmi_get_bios_year() < 2016 && raw_pci_ops) ++ return is_mmconf_reserved(e820__mapped_all, cfg, dev, ++ "E820 entry"); ++ ++ return true; ++ } ++ ++ if (!acpi_disabled) { + if (is_mmconf_reserved(is_acpi_reserved, cfg, dev, + "ACPI motherboard resource")) + return true; +@@ -563,16 +590,7 @@ pci_mmcfg_check_reserved(struct device *dev, struct pci_mmcfg_region *cfg, int e + * For MCFG information constructed from hotpluggable host bridge's + * _CBA method, just assume it's reserved. + */ +- if (pci_mmcfg_running_state) +- return true; +- +- /* Don't try to do this check unless configuration +- type 1 is available. how about type 2 ?*/ +- if (raw_pci_ops) +- return is_mmconf_reserved(e820__mapped_all, cfg, dev, +- "E820 entry"); +- +- return false; ++ return pci_mmcfg_running_state; + } + + static void __init pci_mmcfg_reject_broken(int early) +diff --git a/arch/x86/purgatory/Makefile b/arch/x86/purgatory/Makefile +index 08aa0f25f12a0..8d1c82795ea1d 100644 +--- a/arch/x86/purgatory/Makefile ++++ b/arch/x86/purgatory/Makefile +@@ -42,7 +42,8 @@ KCOV_INSTRUMENT := n + # make up the standalone purgatory.ro + + PURGATORY_CFLAGS_REMOVE := -mcmodel=kernel +-PURGATORY_CFLAGS := -mcmodel=large -ffreestanding -fno-zero-initialized-in-bss -g0 ++PURGATORY_CFLAGS := -mcmodel=small -ffreestanding -fno-zero-initialized-in-bss -g0 ++PURGATORY_CFLAGS += -fpic -fvisibility=hidden + PURGATORY_CFLAGS += $(DISABLE_STACKLEAK_PLUGIN) -DDISABLE_BRANCH_PROFILING + PURGATORY_CFLAGS += -fno-stack-protector + +diff --git a/arch/x86/tools/relocs.c b/arch/x86/tools/relocs.c +index e7013283640f5..a2cfd19c11eea 100644 +--- a/arch/x86/tools/relocs.c ++++ b/arch/x86/tools/relocs.c +@@ -746,6 +746,15 @@ static void walk_relocs(int (*process)(struct section *sec, Elf_Rel *rel, + if (!(sec_applies->shdr.sh_flags & SHF_ALLOC)) { + continue; + } ++ ++ /* ++ * Do not perform relocations in .notes sections; 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/arch/x86/um/shared/sysdep/archsetjmp.h b/arch/x86/um/shared/sysdep/archsetjmp.h +index 166cedbab9266..8c81d1a604a94 100644 +--- a/arch/x86/um/shared/sysdep/archsetjmp.h ++++ b/arch/x86/um/shared/sysdep/archsetjmp.h +@@ -1,6 +1,13 @@ + /* SPDX-License-Identifier: GPL-2.0 */ ++#ifndef __X86_UM_SYSDEP_ARCHSETJMP_H ++#define __X86_UM_SYSDEP_ARCHSETJMP_H ++ + #ifdef __i386__ + #include "archsetjmp_32.h" + #else + #include "archsetjmp_64.h" + #endif ++ ++unsigned long get_thread_reg(int reg, jmp_buf *buf); ++ ++#endif /* __X86_UM_SYSDEP_ARCHSETJMP_H */ +diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c +index a01ca255b0c64..b88722dfc4f86 100644 +--- a/arch/x86/xen/enlighten.c ++++ b/arch/x86/xen/enlighten.c +@@ -382,3 +382,36 @@ void __init xen_add_extra_mem(unsigned long start_pfn, unsigned long n_pfns) + + memblock_reserve(PFN_PHYS(start_pfn), PFN_PHYS(n_pfns)); + } ++ ++#ifdef CONFIG_XEN_UNPOPULATED_ALLOC ++int __init arch_xen_unpopulated_init(struct resource **res) ++{ ++ unsigned int i; ++ ++ if (!xen_domain()) ++ return -ENODEV; ++ ++ /* Must be set strictly before calling xen_free_unpopulated_pages(). */ ++ *res = &iomem_resource; ++ ++ /* ++ * Initialize with pages from the extra memory regions (see ++ * arch/x86/xen/setup.c). ++ */ ++ for (i = 0; i < XEN_EXTRA_MEM_MAX_REGIONS; i++) { ++ unsigned int j; ++ ++ for (j = 0; j < xen_extra_mem[i].n_pfns; j++) { ++ struct page *pg = ++ pfn_to_page(xen_extra_mem[i].start_pfn + j); ++ ++ xen_free_unpopulated_pages(1, &pg); ++ } ++ ++ /* Zero so region is not also added to the balloon driver. */ ++ xen_extra_mem[i].n_pfns = 0; ++ } ++ ++ return 0; ++} ++#endif +diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c +index 4c49a70b46bd1..4fb045d26bd5a 100644 +--- a/block/blk-cgroup.c ++++ b/block/blk-cgroup.c +@@ -323,6 +323,7 @@ static struct blkcg_gq *blkg_alloc(struct blkcg *blkcg, struct gendisk *disk, + blkg->q = disk->queue; + INIT_LIST_HEAD(&blkg->q_node); + blkg->blkcg = blkcg; ++ blkg->iostat.blkg = blkg; + #ifdef CONFIG_BLK_CGROUP_PUNT_BIO + spin_lock_init(&blkg->async_bio_lock); + bio_list_init(&blkg->async_bios); +@@ -619,12 +620,45 @@ static void blkg_destroy_all(struct gendisk *disk) + spin_unlock_irq(&q->queue_lock); + } + ++static void blkg_iostat_set(struct blkg_iostat *dst, struct blkg_iostat *src) ++{ ++ int i; ++ ++ for (i = 0; i < BLKG_IOSTAT_NR; i++) { ++ dst->bytes[i] = src->bytes[i]; ++ dst->ios[i] = src->ios[i]; ++ } ++} ++ ++static void __blkg_clear_stat(struct blkg_iostat_set *bis) ++{ ++ struct blkg_iostat cur = {0}; ++ unsigned long flags; ++ ++ flags = u64_stats_update_begin_irqsave(&bis->sync); ++ blkg_iostat_set(&bis->cur, &cur); ++ blkg_iostat_set(&bis->last, &cur); ++ u64_stats_update_end_irqrestore(&bis->sync, flags); ++} ++ ++static void blkg_clear_stat(struct blkcg_gq *blkg) ++{ ++ int cpu; ++ ++ for_each_possible_cpu(cpu) { ++ struct blkg_iostat_set *s = per_cpu_ptr(blkg->iostat_cpu, cpu); ++ ++ __blkg_clear_stat(s); ++ } ++ __blkg_clear_stat(&blkg->iostat); ++} ++ + static int blkcg_reset_stats(struct cgroup_subsys_state *css, + struct cftype *cftype, u64 val) + { + struct blkcg *blkcg = css_to_blkcg(css); + struct blkcg_gq *blkg; +- int i, cpu; ++ int i; + + mutex_lock(&blkcg_pol_mutex); + spin_lock_irq(&blkcg->lock); +@@ -635,18 +669,7 @@ static int blkcg_reset_stats(struct cgroup_subsys_state *css, + * anyway. If you get hit by a race, retry. + */ + hlist_for_each_entry(blkg, &blkcg->blkg_list, blkcg_node) { +- for_each_possible_cpu(cpu) { +- struct blkg_iostat_set *bis = +- per_cpu_ptr(blkg->iostat_cpu, cpu); +- memset(bis, 0, sizeof(*bis)); +- +- /* Re-initialize the cleared blkg_iostat_set */ +- u64_stats_init(&bis->sync); +- bis->blkg = blkg; +- } +- memset(&blkg->iostat, 0, sizeof(blkg->iostat)); +- u64_stats_init(&blkg->iostat.sync); +- ++ blkg_clear_stat(blkg); + for (i = 0; i < BLKCG_MAX_POLS; i++) { + struct blkcg_policy *pol = blkcg_policy[i]; + +@@ -949,16 +972,6 @@ void blkg_conf_exit(struct blkg_conf_ctx *ctx) + } + EXPORT_SYMBOL_GPL(blkg_conf_exit); + +-static void blkg_iostat_set(struct blkg_iostat *dst, struct blkg_iostat *src) +-{ +- int i; +- +- for (i = 0; i < BLKG_IOSTAT_NR; i++) { +- dst->bytes[i] = src->bytes[i]; +- dst->ios[i] = src->ios[i]; +- } +-} +- + static void blkg_iostat_add(struct blkg_iostat *dst, struct blkg_iostat *src) + { + int i; +@@ -1024,7 +1037,19 @@ static void __blkcg_rstat_flush(struct blkcg *blkcg, int cpu) + struct blkg_iostat cur; + unsigned int seq; + ++ /* ++ * Order assignment of `next_bisc` from `bisc->lnode.next` in ++ * llist_for_each_entry_safe and clearing `bisc->lqueued` for ++ * avoiding to assign `next_bisc` with new next pointer added ++ * in blk_cgroup_bio_start() in case of re-ordering. ++ * ++ * The pair barrier is implied in llist_add() in blk_cgroup_bio_start(). ++ */ ++ smp_mb(); ++ + WRITE_ONCE(bisc->lqueued, false); ++ if (bisc == &blkg->iostat) ++ goto propagate_up; /* propagate up to parent only */ + + /* fetch the current per-cpu values */ + do { +@@ -1034,10 +1059,24 @@ static void __blkcg_rstat_flush(struct blkcg *blkcg, int cpu) + + blkcg_iostat_update(blkg, &cur, &bisc->last); + ++propagate_up: + /* propagate global delta to parent (unless that's root) */ +- if (parent && parent->parent) ++ if (parent && parent->parent) { + blkcg_iostat_update(parent, &blkg->iostat.cur, + &blkg->iostat.last); ++ /* ++ * Queue parent->iostat to its blkcg's lockless ++ * list to propagate up to the grandparent if the ++ * iostat hasn't been queued yet. ++ */ ++ if (!parent->iostat.lqueued) { ++ struct llist_head *plhead; ++ ++ plhead = per_cpu_ptr(parent->blkcg->lhead, cpu); ++ llist_add(&parent->iostat.lnode, plhead); ++ parent->iostat.lqueued = true; ++ } ++ } + } + raw_spin_unlock_irqrestore(&blkg_stat_lock, flags); + out: +diff --git a/block/blk-core.c b/block/blk-core.c +index a3726d8cf8738..bf058cea9016a 100644 +--- a/block/blk-core.c ++++ b/block/blk-core.c +@@ -950,10 +950,11 @@ void update_io_ticks(struct block_device *part, unsigned long now, bool end) + unsigned long stamp; + again: + stamp = READ_ONCE(part->bd_stamp); +- if (unlikely(time_after(now, stamp))) { +- if (likely(try_cmpxchg(&part->bd_stamp, &stamp, now))) +- __part_stat_add(part, io_ticks, end ? now - stamp : 1); +- } ++ if (unlikely(time_after(now, stamp)) && ++ likely(try_cmpxchg(&part->bd_stamp, &stamp, now)) && ++ (end || part_in_flight(part))) ++ __part_stat_add(part, io_ticks, now - stamp); ++ + if (part->bd_partno) { + part = bdev_whole(part); + goto again; +diff --git a/block/blk-merge.c b/block/blk-merge.c +index 65e75efa9bd36..07bf758c523a9 100644 +--- a/block/blk-merge.c ++++ b/block/blk-merge.c +@@ -783,6 +783,8 @@ static void blk_account_io_merge_request(struct request *req) + if (blk_do_io_stat(req)) { + part_stat_lock(); + part_stat_inc(req->part, merges[op_stat_group(req_op(req))]); ++ part_stat_local_dec(req->part, ++ in_flight[op_is_write(req_op(req))]); + part_stat_unlock(); + } + } +diff --git a/block/blk-mq.c b/block/blk-mq.c +index 257b0addd47e5..4c91889affa7c 100644 +--- a/block/blk-mq.c ++++ b/block/blk-mq.c +@@ -994,6 +994,8 @@ static inline void blk_account_io_done(struct request *req, u64 now) + update_io_ticks(req->part, jiffies, true); + part_stat_inc(req->part, ios[sgrp]); + part_stat_add(req->part, nsecs[sgrp], now - req->start_time_ns); ++ part_stat_local_dec(req->part, ++ in_flight[op_is_write(req_op(req))]); + part_stat_unlock(); + } + } +@@ -1016,6 +1018,8 @@ static inline void blk_account_io_start(struct request *req) + + part_stat_lock(); + update_io_ticks(req->part, jiffies, false); ++ part_stat_local_inc(req->part, ++ in_flight[op_is_write(req_op(req))]); + part_stat_unlock(); + } + } +diff --git a/block/blk.h b/block/blk.h +index 08a358bc0919e..67915b04b3c17 100644 +--- a/block/blk.h ++++ b/block/blk.h +@@ -344,6 +344,7 @@ static inline bool blk_do_io_stat(struct request *rq) + } + + void update_io_ticks(struct block_device *part, unsigned long now, bool end); ++unsigned int part_in_flight(struct block_device *part); + + static inline void req_set_nomerge(struct request_queue *q, struct request *req) + { +diff --git a/block/fops.c b/block/fops.c +index 73e42742543f6..1df187b306792 100644 +--- a/block/fops.c ++++ b/block/fops.c +@@ -387,7 +387,7 @@ static int blkdev_iomap_begin(struct inode *inode, loff_t offset, loff_t length, + + iomap->bdev = bdev; + iomap->offset = ALIGN_DOWN(offset, bdev_logical_block_size(bdev)); +- if (iomap->offset >= isize) ++ if (offset >= isize) + return -EIO; + iomap->type = IOMAP_MAPPED; + iomap->addr = iomap->offset; +diff --git a/block/genhd.c b/block/genhd.c +index 2ef1e08d70ecd..33b1ebf6ef82d 100644 +--- a/block/genhd.c ++++ b/block/genhd.c +@@ -118,7 +118,7 @@ static void part_stat_read_all(struct block_device *part, + } + } + +-static unsigned int part_in_flight(struct block_device *part) ++unsigned int part_in_flight(struct block_device *part) + { + unsigned int inflight = 0; + int cpu; +diff --git a/block/partitions/cmdline.c b/block/partitions/cmdline.c +index c03bc105e5753..152c85df92b20 100644 +--- a/block/partitions/cmdline.c ++++ b/block/partitions/cmdline.c +@@ -70,8 +70,8 @@ static int parse_subpart(struct cmdline_subpart **subpart, char *partdef) + } + + if (*partdef == '(') { +- int length; +- char *next = strchr(++partdef, ')'); ++ partdef++; ++ char *next = strsep(&partdef, ")"); + + if (!next) { + pr_warn("cmdline partition format is invalid."); +@@ -79,11 +79,7 @@ static int parse_subpart(struct cmdline_subpart **subpart, char *partdef) + goto fail; + } + +- length = min_t(int, next - partdef, +- sizeof(new_subpart->name) - 1); +- strscpy(new_subpart->name, partdef, length); +- +- partdef = ++next; ++ strscpy(new_subpart->name, next, sizeof(new_subpart->name)); + } else + new_subpart->name[0] = '\0'; + +@@ -117,14 +113,12 @@ static void free_subpart(struct cmdline_parts *parts) + } + } + +-static int parse_parts(struct cmdline_parts **parts, const char *bdevdef) ++static int parse_parts(struct cmdline_parts **parts, char *bdevdef) + { + int ret = -EINVAL; + char *next; +- int length; + struct cmdline_subpart **next_subpart; + struct cmdline_parts *newparts; +- char buf[BDEVNAME_SIZE + 32 + 4]; + + *parts = NULL; + +@@ -132,28 +126,19 @@ static int parse_parts(struct cmdline_parts **parts, const char *bdevdef) + if (!newparts) + return -ENOMEM; + +- next = strchr(bdevdef, ':'); ++ next = strsep(&bdevdef, ":"); + if (!next) { + pr_warn("cmdline partition has no block device."); + goto fail; + } + +- length = min_t(int, next - bdevdef, sizeof(newparts->name) - 1); +- strscpy(newparts->name, bdevdef, length); ++ strscpy(newparts->name, next, sizeof(newparts->name)); + newparts->nr_subparts = 0; + + next_subpart = &newparts->subpart; + +- while (next && *(++next)) { +- bdevdef = next; +- next = strchr(bdevdef, ','); +- +- length = (!next) ? (sizeof(buf) - 1) : +- min_t(int, next - bdevdef, sizeof(buf) - 1); +- +- strscpy(buf, bdevdef, length); +- +- ret = parse_subpart(next_subpart, buf); ++ while ((next = strsep(&bdevdef, ","))) { ++ ret = parse_subpart(next_subpart, next); + if (ret) + goto fail; + +@@ -199,24 +184,17 @@ static int cmdline_parts_parse(struct cmdline_parts **parts, + + *parts = NULL; + +- next = pbuf = buf = kstrdup(cmdline, GFP_KERNEL); ++ pbuf = buf = kstrdup(cmdline, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + next_parts = parts; + +- while (next && *pbuf) { +- next = strchr(pbuf, ';'); +- if (next) +- *next = '\0'; +- +- ret = parse_parts(next_parts, pbuf); ++ while ((next = strsep(&pbuf, ";"))) { ++ ret = parse_parts(next_parts, next); + if (ret) + goto fail; + +- if (next) +- pbuf = ++next; +- + next_parts = &(*next_parts)->next_parts; + } + +@@ -250,7 +228,6 @@ static struct cmdline_parts *bdev_parts; + static int add_part(int slot, struct cmdline_subpart *subpart, + struct parsed_partitions *state) + { +- int label_min; + struct partition_meta_info *info; + char tmp[sizeof(info->volname) + 4]; + +@@ -262,9 +239,7 @@ static int add_part(int slot, struct cmdline_subpart *subpart, + + info = &state->parts[slot].info; + +- label_min = min_t(int, sizeof(info->volname) - 1, +- sizeof(subpart->name)); +- strscpy(info->volname, subpart->name, label_min); ++ strscpy(info->volname, subpart->name, sizeof(info->volname)); + + snprintf(tmp, sizeof(tmp), "(%s)", info->volname); + strlcat(state->pp_buf, tmp, PAGE_SIZE); +diff --git a/crypto/asymmetric_keys/Kconfig b/crypto/asymmetric_keys/Kconfig +index 59ec726b7c770..684767ab23e24 100644 +--- a/crypto/asymmetric_keys/Kconfig ++++ b/crypto/asymmetric_keys/Kconfig +@@ -15,6 +15,7 @@ config ASYMMETRIC_PUBLIC_KEY_SUBTYPE + select MPILIB + select CRYPTO_HASH_INFO + select CRYPTO_AKCIPHER ++ select CRYPTO_SIG + select CRYPTO_HASH + help + This option provides support for asymmetric public key type handling. +@@ -85,5 +86,7 @@ config FIPS_SIGNATURE_SELFTEST + depends on ASYMMETRIC_KEY_TYPE + depends on PKCS7_MESSAGE_PARSER=X509_CERTIFICATE_PARSER + depends on X509_CERTIFICATE_PARSER ++ depends on CRYPTO_RSA ++ depends on CRYPTO_SHA256 + + endif # ASYMMETRIC_KEY_TYPE +diff --git a/drivers/accel/ivpu/ivpu_job.c b/drivers/accel/ivpu/ivpu_job.c +index de9e69f70af7e..76f468c9f761b 100644 +--- a/drivers/accel/ivpu/ivpu_job.c ++++ b/drivers/accel/ivpu/ivpu_job.c +@@ -618,6 +618,5 @@ int ivpu_job_done_thread_init(struct ivpu_device *vdev) + + void ivpu_job_done_thread_fini(struct ivpu_device *vdev) + { +- kthread_stop(vdev->job_done_thread); +- put_task_struct(vdev->job_done_thread); ++ kthread_stop_put(vdev->job_done_thread); + } +diff --git a/drivers/accessibility/speakup/main.c b/drivers/accessibility/speakup/main.c +index 736c2eb8c0f37..f677ad2177c2f 100644 +--- a/drivers/accessibility/speakup/main.c ++++ b/drivers/accessibility/speakup/main.c +@@ -574,7 +574,7 @@ static u_long get_word(struct vc_data *vc) + } + attr_ch = get_char(vc, (u_short *)tmp_pos, &spk_attr); + buf[cnt++] = attr_ch; +- while (tmpx < vc->vc_cols - 1 && cnt < sizeof(buf) - 1) { ++ while (tmpx < vc->vc_cols - 1 && cnt < ARRAY_SIZE(buf) - 1) { + tmp_pos += 2; + tmpx++; + ch = get_char(vc, (u_short *)tmp_pos, &temp); +diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c +index a052e0ab19e4c..98a2ab3b68442 100644 +--- a/drivers/acpi/acpi_lpss.c ++++ b/drivers/acpi/acpi_lpss.c +@@ -333,6 +333,7 @@ static const struct lpss_device_desc bsw_i2c_dev_desc = { + + static const struct property_entry bsw_spi_properties[] = { + PROPERTY_ENTRY_U32("intel,spi-pxa2xx-type", LPSS_BSW_SSP), ++ PROPERTY_ENTRY_U32("num-cs", 2), + { } + }; + +diff --git a/drivers/acpi/acpica/Makefile b/drivers/acpi/acpica/Makefile +index 30f3fc13c29d1..8d18af396de92 100644 +--- a/drivers/acpi/acpica/Makefile ++++ b/drivers/acpi/acpica/Makefile +@@ -5,6 +5,7 @@ + + ccflags-y := -D_LINUX -DBUILDING_ACPICA + ccflags-$(CONFIG_ACPI_DEBUG) += -DACPI_DEBUG_OUTPUT ++CFLAGS_tbfind.o += $(call cc-disable-warning, stringop-truncation) + + # use acpi.o to put all files here into acpi.o modparam namespace + obj-y += acpi.o +diff --git a/drivers/acpi/numa/srat.c b/drivers/acpi/numa/srat.c +index b57de78fbf14f..a44c0761fd1c0 100644 +--- a/drivers/acpi/numa/srat.c ++++ b/drivers/acpi/numa/srat.c +@@ -206,6 +206,11 @@ int __init srat_disabled(void) + return acpi_numa < 0; + } + ++__weak int __init numa_fill_memblks(u64 start, u64 end) ++{ ++ return NUMA_NO_MEMBLK; ++} ++ + #if defined(CONFIG_X86) || defined(CONFIG_ARM64) || defined(CONFIG_LOONGARCH) + /* + * Callback for SLIT parsing. pxm_to_node() returns NUMA_NO_NODE for +diff --git a/drivers/base/base.h b/drivers/base/base.h +index eb4c0ace92420..a8e3d8165232f 100644 +--- a/drivers/base/base.h ++++ b/drivers/base/base.h +@@ -192,11 +192,14 @@ extern struct kset *devices_kset; + void devices_kset_move_last(struct device *dev); + + #if defined(CONFIG_MODULES) && defined(CONFIG_SYSFS) +-void module_add_driver(struct module *mod, struct device_driver *drv); ++int module_add_driver(struct module *mod, struct device_driver *drv); + void module_remove_driver(struct device_driver *drv); + #else +-static inline void module_add_driver(struct module *mod, +- struct device_driver *drv) { } ++static inline int module_add_driver(struct module *mod, ++ struct device_driver *drv) ++{ ++ return 0; ++} + static inline void module_remove_driver(struct device_driver *drv) { } + #endif + +diff --git a/drivers/base/bus.c b/drivers/base/bus.c +index 84a21084d67d1..d7c4330786cae 100644 +--- a/drivers/base/bus.c ++++ b/drivers/base/bus.c +@@ -674,7 +674,12 @@ int bus_add_driver(struct device_driver *drv) + if (error) + goto out_del_list; + } +- module_add_driver(drv->owner, drv); ++ error = module_add_driver(drv->owner, drv); ++ if (error) { ++ printk(KERN_ERR "%s: failed to create module links for %s\n", ++ __func__, drv->name); ++ goto out_detach; ++ } + + error = driver_create_file(drv, &driver_attr_uevent); + if (error) { +@@ -699,6 +704,8 @@ int bus_add_driver(struct device_driver *drv) + + return 0; + ++out_detach: ++ driver_detach(drv); + out_del_list: + klist_del(&priv->knode_bus); + out_unregister: +diff --git a/drivers/base/module.c b/drivers/base/module.c +index 46ad4d636731d..a1b55da07127d 100644 +--- a/drivers/base/module.c ++++ b/drivers/base/module.c +@@ -30,14 +30,14 @@ static void module_create_drivers_dir(struct module_kobject *mk) + mutex_unlock(&drivers_dir_mutex); + } + +-void module_add_driver(struct module *mod, struct device_driver *drv) ++int module_add_driver(struct module *mod, struct device_driver *drv) + { + char *driver_name; +- int no_warn; + struct module_kobject *mk = NULL; ++ int ret; + + if (!drv) +- return; ++ return 0; + + if (mod) + mk = &mod->mkobj; +@@ -56,17 +56,37 @@ void module_add_driver(struct module *mod, struct device_driver *drv) + } + + if (!mk) +- return; ++ return 0; ++ ++ ret = sysfs_create_link(&drv->p->kobj, &mk->kobj, "module"); ++ if (ret) ++ return ret; + +- /* Don't check return codes; these calls are idempotent */ +- no_warn = sysfs_create_link(&drv->p->kobj, &mk->kobj, "module"); + driver_name = make_driver_name(drv); +- if (driver_name) { +- module_create_drivers_dir(mk); +- no_warn = sysfs_create_link(mk->drivers_dir, &drv->p->kobj, +- driver_name); +- kfree(driver_name); ++ if (!driver_name) { ++ ret = -ENOMEM; ++ goto out; ++ } ++ ++ module_create_drivers_dir(mk); ++ if (!mk->drivers_dir) { ++ ret = -EINVAL; ++ goto out; + } ++ ++ ret = sysfs_create_link(mk->drivers_dir, &drv->p->kobj, driver_name); ++ if (ret) ++ goto out; ++ ++ kfree(driver_name); ++ ++ return 0; ++out: ++ sysfs_remove_link(&drv->p->kobj, "module"); ++ sysfs_remove_link(mk->drivers_dir, driver_name); ++ kfree(driver_name); ++ ++ return ret; + } + + void module_remove_driver(struct device_driver *drv) +diff --git a/drivers/block/null_blk/main.c b/drivers/block/null_blk/main.c +index 9544746de1683..561706fc2cd8e 100644 +--- a/drivers/block/null_blk/main.c ++++ b/drivers/block/null_blk/main.c +@@ -2352,10 +2352,13 @@ static void __exit null_exit(void) + + if (g_queue_mode == NULL_Q_MQ && shared_tags) + blk_mq_free_tag_set(&tag_set); ++ ++ mutex_destroy(&lock); + } + + module_init(null_init); + module_exit(null_exit); + + MODULE_AUTHOR("Jens Axboe "); ++MODULE_DESCRIPTION("multi queue aware block test driver"); + MODULE_LICENSE("GPL"); +diff --git a/drivers/bluetooth/btmrvl_main.c b/drivers/bluetooth/btmrvl_main.c +index 9658b33c824a7..18f34998a1204 100644 +--- a/drivers/bluetooth/btmrvl_main.c ++++ b/drivers/bluetooth/btmrvl_main.c +@@ -121,13 +121,6 @@ int btmrvl_process_event(struct btmrvl_private *priv, struct sk_buff *skb) + ((event->data[2] == MODULE_BROUGHT_UP) || + (event->data[2] == MODULE_ALREADY_UP)) ? + "Bring-up succeed" : "Bring-up failed"); +- +- if (event->length > 3 && event->data[3]) +- priv->btmrvl_dev.dev_type = HCI_AMP; +- else +- priv->btmrvl_dev.dev_type = HCI_PRIMARY; +- +- BT_DBG("dev_type: %d", priv->btmrvl_dev.dev_type); + } else if (priv->btmrvl_dev.sendcmdflag && + event->data[1] == MODULE_SHUTDOWN_REQ) { + BT_DBG("EVENT:%s", (event->data[2]) ? +@@ -686,8 +679,6 @@ int btmrvl_register_hdev(struct btmrvl_private *priv) + hdev->wakeup = btmrvl_wakeup; + SET_HCIDEV_DEV(hdev, &card->func->dev); + +- hdev->dev_type = priv->btmrvl_dev.dev_type; +- + ret = hci_register_dev(hdev); + if (ret < 0) { + BT_ERR("Can not register HCI device"); +diff --git a/drivers/bluetooth/btqca.c b/drivers/bluetooth/btqca.c +index 638074992c829..35fb26cbf2294 100644 +--- a/drivers/bluetooth/btqca.c ++++ b/drivers/bluetooth/btqca.c +@@ -148,8 +148,10 @@ static int qca_read_fw_build_info(struct hci_dev *hdev) + } + + build_label = kstrndup(&edl->data[1], build_lbl_len, GFP_KERNEL); +- if (!build_label) ++ if (!build_label) { ++ err = -ENOMEM; + goto out; ++ } + + hci_set_fw_info(hdev, "%s", build_label); + +diff --git a/drivers/bluetooth/btrsi.c b/drivers/bluetooth/btrsi.c +index 634cf8f5ed2db..0c91d7635ac39 100644 +--- a/drivers/bluetooth/btrsi.c ++++ b/drivers/bluetooth/btrsi.c +@@ -134,7 +134,6 @@ static int rsi_hci_attach(void *priv, struct rsi_proto_ops *ops) + hdev->bus = HCI_USB; + + hci_set_drvdata(hdev, h_adapter); +- hdev->dev_type = HCI_PRIMARY; + hdev->open = rsi_hci_open; + hdev->close = rsi_hci_close; + hdev->flush = rsi_hci_flush; +diff --git a/drivers/bluetooth/btsdio.c b/drivers/bluetooth/btsdio.c +index f19d31ee37ea8..fdcfe9c50313e 100644 +--- a/drivers/bluetooth/btsdio.c ++++ b/drivers/bluetooth/btsdio.c +@@ -32,9 +32,6 @@ static const struct sdio_device_id btsdio_table[] = { + /* Generic Bluetooth Type-B SDIO device */ + { SDIO_DEVICE_CLASS(SDIO_CLASS_BT_B) }, + +- /* Generic Bluetooth AMP controller */ +- { SDIO_DEVICE_CLASS(SDIO_CLASS_BT_AMP) }, +- + { } /* Terminating entry */ + }; + +@@ -319,11 +316,6 @@ static int btsdio_probe(struct sdio_func *func, + hdev->bus = HCI_SDIO; + hci_set_drvdata(hdev, data); + +- if (id->class == SDIO_CLASS_BT_AMP) +- hdev->dev_type = HCI_AMP; +- else +- hdev->dev_type = HCI_PRIMARY; +- + data->hdev = hdev; + + SET_HCIDEV_DEV(hdev, &func->dev); +diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c +index d178e1464bfd2..7c271f55a9b49 100644 +--- a/drivers/bluetooth/btusb.c ++++ b/drivers/bluetooth/btusb.c +@@ -4308,11 +4308,6 @@ static int btusb_probe(struct usb_interface *intf, + hdev->bus = HCI_USB; + hci_set_drvdata(hdev, data); + +- if (id->driver_info & BTUSB_AMP) +- hdev->dev_type = HCI_AMP; +- else +- hdev->dev_type = HCI_PRIMARY; +- + data->hdev = hdev; + + SET_HCIDEV_DEV(hdev, &intf->dev); +diff --git a/drivers/bluetooth/hci_bcm4377.c b/drivers/bluetooth/hci_bcm4377.c +index 9a7243d5db71f..0c2f15235b4cd 100644 +--- a/drivers/bluetooth/hci_bcm4377.c ++++ b/drivers/bluetooth/hci_bcm4377.c +@@ -2361,7 +2361,6 @@ static int bcm4377_probe(struct pci_dev *pdev, const struct pci_device_id *id) + bcm4377->hdev = hdev; + + hdev->bus = HCI_PCI; +- hdev->dev_type = HCI_PRIMARY; + hdev->open = bcm4377_hci_open; + hdev->close = bcm4377_hci_close; + hdev->send = bcm4377_hci_send_frame; +diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c +index a26367e9fb197..17a2f158a0dfa 100644 +--- a/drivers/bluetooth/hci_ldisc.c ++++ b/drivers/bluetooth/hci_ldisc.c +@@ -667,11 +667,6 @@ static int hci_uart_register_dev(struct hci_uart *hu) + if (!test_bit(HCI_UART_RESET_ON_INIT, &hu->hdev_flags)) + set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks); + +- if (test_bit(HCI_UART_CREATE_AMP, &hu->hdev_flags)) +- hdev->dev_type = HCI_AMP; +- else +- hdev->dev_type = HCI_PRIMARY; +- + /* Only call open() for the protocol after hdev is fully initialized as + * open() (or a timer/workqueue it starts) may attempt to reference it. + */ +@@ -722,7 +717,6 @@ static int hci_uart_set_flags(struct hci_uart *hu, unsigned long flags) + { + unsigned long valid_flags = BIT(HCI_UART_RAW_DEVICE) | + BIT(HCI_UART_RESET_ON_INIT) | +- BIT(HCI_UART_CREATE_AMP) | + BIT(HCI_UART_INIT_PENDING) | + BIT(HCI_UART_EXT_CONFIG) | + BIT(HCI_UART_VND_DETECT); +diff --git a/drivers/bluetooth/hci_serdev.c b/drivers/bluetooth/hci_serdev.c +index 611a11fbb2f3a..1165831570e3c 100644 +--- a/drivers/bluetooth/hci_serdev.c ++++ b/drivers/bluetooth/hci_serdev.c +@@ -366,11 +366,6 @@ int hci_uart_register_device_priv(struct hci_uart *hu, + if (test_bit(HCI_UART_EXT_CONFIG, &hu->hdev_flags)) + set_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks); + +- if (test_bit(HCI_UART_CREATE_AMP, &hu->hdev_flags)) +- hdev->dev_type = HCI_AMP; +- else +- hdev->dev_type = HCI_PRIMARY; +- + if (test_bit(HCI_UART_INIT_PENDING, &hu->hdev_flags)) + return 0; + +diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h +index 68c8c7e95d64d..00bf7ae82c5b7 100644 +--- a/drivers/bluetooth/hci_uart.h ++++ b/drivers/bluetooth/hci_uart.h +@@ -37,7 +37,6 @@ + + #define HCI_UART_RAW_DEVICE 0 + #define HCI_UART_RESET_ON_INIT 1 +-#define HCI_UART_CREATE_AMP 2 + #define HCI_UART_INIT_PENDING 3 + #define HCI_UART_EXT_CONFIG 4 + #define HCI_UART_VND_DETECT 5 +diff --git a/drivers/bluetooth/hci_vhci.c b/drivers/bluetooth/hci_vhci.c +index 572d68d52965f..28750a40f0ed5 100644 +--- a/drivers/bluetooth/hci_vhci.c ++++ b/drivers/bluetooth/hci_vhci.c +@@ -384,17 +384,10 @@ static int __vhci_create_device(struct vhci_data *data, __u8 opcode) + { + struct hci_dev *hdev; + struct sk_buff *skb; +- __u8 dev_type; + + if (data->hdev) + return -EBADFD; + +- /* bits 0-1 are dev_type (Primary or AMP) */ +- dev_type = opcode & 0x03; +- +- if (dev_type != HCI_PRIMARY && dev_type != HCI_AMP) +- return -EINVAL; +- + /* bits 2-5 are reserved (must be zero) */ + if (opcode & 0x3c) + return -EINVAL; +@@ -412,7 +405,6 @@ static int __vhci_create_device(struct vhci_data *data, __u8 opcode) + data->hdev = hdev; + + hdev->bus = HCI_VIRTUAL; +- hdev->dev_type = dev_type; + hci_set_drvdata(hdev, data); + + hdev->open = vhci_open_dev; +@@ -634,7 +626,7 @@ static void vhci_open_timeout(struct work_struct *work) + struct vhci_data *data = container_of(work, struct vhci_data, + open_timeout.work); + +- vhci_create_device(data, amp ? HCI_AMP : HCI_PRIMARY); ++ vhci_create_device(data, 0x00); + } + + static int vhci_open(struct inode *inode, struct file *file) +diff --git a/drivers/bluetooth/virtio_bt.c b/drivers/bluetooth/virtio_bt.c +index 2ac70b560c46d..18208e152a367 100644 +--- a/drivers/bluetooth/virtio_bt.c ++++ b/drivers/bluetooth/virtio_bt.c +@@ -274,7 +274,6 @@ static int virtbt_probe(struct virtio_device *vdev) + + switch (type) { + case VIRTIO_BT_CONFIG_TYPE_PRIMARY: +- case VIRTIO_BT_CONFIG_TYPE_AMP: + break; + default: + return -EINVAL; +@@ -303,7 +302,6 @@ static int virtbt_probe(struct virtio_device *vdev) + vbt->hdev = hdev; + + hdev->bus = HCI_VIRTIO; +- hdev->dev_type = type; + hci_set_drvdata(hdev, vbt); + + hdev->open = virtbt_open; +diff --git a/drivers/char/ppdev.c b/drivers/char/ppdev.c +index 4c188e9e477cd..58e9dcc2a3087 100644 +--- a/drivers/char/ppdev.c ++++ b/drivers/char/ppdev.c +@@ -296,28 +296,35 @@ static int register_device(int minor, struct pp_struct *pp) + if (!port) { + pr_warn("%s: no associated port!\n", name); + rc = -ENXIO; +- goto err; ++ goto err_free_name; ++ } ++ ++ index = ida_alloc(&ida_index, GFP_KERNEL); ++ if (index < 0) { ++ pr_warn("%s: failed to get index!\n", name); ++ rc = index; ++ goto err_put_port; + } + +- index = ida_simple_get(&ida_index, 0, 0, GFP_KERNEL); + memset(&ppdev_cb, 0, sizeof(ppdev_cb)); + ppdev_cb.irq_func = pp_irq; + ppdev_cb.flags = (pp->flags & PP_EXCL) ? PARPORT_FLAG_EXCL : 0; + ppdev_cb.private = pp; + pdev = parport_register_dev_model(port, name, &ppdev_cb, index); +- parport_put_port(port); + + if (!pdev) { + pr_warn("%s: failed to register device!\n", name); + rc = -ENXIO; +- ida_simple_remove(&ida_index, index); +- goto err; ++ ida_free(&ida_index, index); ++ goto err_put_port; + } + + pp->pdev = pdev; + pp->index = index; + dev_dbg(&pdev->dev, "registered pardevice\n"); +-err: ++err_put_port: ++ parport_put_port(port); ++err_free_name: + kfree(name); + return rc; + } +@@ -750,7 +757,7 @@ static int pp_release(struct inode *inode, struct file *file) + + if (pp->pdev) { + parport_unregister_device(pp->pdev); +- ida_simple_remove(&ida_index, pp->index); ++ ida_free(&ida_index, pp->index); + pp->pdev = NULL; + pr_debug(CHRDEV "%x: unregistered pardevice\n", minor); + } +diff --git a/drivers/char/tpm/tpm_tis_spi_main.c b/drivers/char/tpm/tpm_tis_spi_main.c +index c5c3197ee29f0..4bdad9e3667fa 100644 +--- a/drivers/char/tpm/tpm_tis_spi_main.c ++++ b/drivers/char/tpm/tpm_tis_spi_main.c +@@ -37,6 +37,7 @@ + #include "tpm_tis_spi.h" + + #define MAX_SPI_FRAMESIZE 64 ++#define SPI_HDRSIZE 4 + + /* + * TCG SPI flow control is documented in section 6.4 of the spec[1]. In short, +@@ -247,7 +248,7 @@ static int tpm_tis_spi_write_bytes(struct tpm_tis_data *data, u32 addr, + int tpm_tis_spi_init(struct spi_device *spi, struct tpm_tis_spi_phy *phy, + int irq, const struct tpm_tis_phy_ops *phy_ops) + { +- phy->iobuf = devm_kmalloc(&spi->dev, MAX_SPI_FRAMESIZE, GFP_KERNEL); ++ phy->iobuf = devm_kmalloc(&spi->dev, SPI_HDRSIZE + MAX_SPI_FRAMESIZE, GFP_KERNEL); + if (!phy->iobuf) + return -ENOMEM; + +diff --git a/drivers/clk/clk-renesas-pcie.c b/drivers/clk/clk-renesas-pcie.c +index 3b6ad2307a41f..b00c38469cfad 100644 +--- a/drivers/clk/clk-renesas-pcie.c ++++ b/drivers/clk/clk-renesas-pcie.c +@@ -24,10 +24,12 @@ + #define RS9_REG_SS_AMP_0V7 0x1 + #define RS9_REG_SS_AMP_0V8 0x2 + #define RS9_REG_SS_AMP_0V9 0x3 ++#define RS9_REG_SS_AMP_DEFAULT RS9_REG_SS_AMP_0V8 + #define RS9_REG_SS_AMP_MASK 0x3 + #define RS9_REG_SS_SSC_100 0 + #define RS9_REG_SS_SSC_M025 (1 << 3) + #define RS9_REG_SS_SSC_M050 (3 << 3) ++#define RS9_REG_SS_SSC_DEFAULT RS9_REG_SS_SSC_100 + #define RS9_REG_SS_SSC_MASK (3 << 3) + #define RS9_REG_SS_SSC_LOCK BIT(5) + #define RS9_REG_SR 0x2 +@@ -211,8 +213,8 @@ static int rs9_get_common_config(struct rs9_driver_data *rs9) + int ret; + + /* Set defaults */ +- rs9->pll_amplitude = RS9_REG_SS_AMP_0V7; +- rs9->pll_ssc = RS9_REG_SS_SSC_100; ++ rs9->pll_amplitude = RS9_REG_SS_AMP_DEFAULT; ++ rs9->pll_ssc = RS9_REG_SS_SSC_DEFAULT; + + /* Output clock amplitude */ + ret = of_property_read_u32(np, "renesas,out-amplitude-microvolt", +@@ -253,13 +255,13 @@ static void rs9_update_config(struct rs9_driver_data *rs9) + int i; + + /* If amplitude is non-default, update it. */ +- if (rs9->pll_amplitude != RS9_REG_SS_AMP_0V7) { ++ if (rs9->pll_amplitude != RS9_REG_SS_AMP_DEFAULT) { + regmap_update_bits(rs9->regmap, RS9_REG_SS, RS9_REG_SS_AMP_MASK, + rs9->pll_amplitude); + } + + /* If SSC is non-default, update it. */ +- if (rs9->pll_ssc != RS9_REG_SS_SSC_100) { ++ if (rs9->pll_ssc != RS9_REG_SS_SSC_DEFAULT) { + regmap_update_bits(rs9->regmap, RS9_REG_SS, RS9_REG_SS_SSC_MASK, + rs9->pll_ssc); + } +diff --git a/drivers/clk/mediatek/clk-mt8365-mm.c b/drivers/clk/mediatek/clk-mt8365-mm.c +index 01a2ef8f594ef..3f62ec7507336 100644 +--- a/drivers/clk/mediatek/clk-mt8365-mm.c ++++ b/drivers/clk/mediatek/clk-mt8365-mm.c +@@ -53,7 +53,7 @@ static const struct mtk_gate mm_clks[] = { + GATE_MM0(CLK_MM_MM_DSI0, "mm_dsi0", "mm_sel", 17), + GATE_MM0(CLK_MM_MM_DISP_RDMA1, "mm_disp_rdma1", "mm_sel", 18), + GATE_MM0(CLK_MM_MM_MDP_RDMA1, "mm_mdp_rdma1", "mm_sel", 19), +- GATE_MM0(CLK_MM_DPI0_DPI0, "mm_dpi0_dpi0", "vpll_dpix", 20), ++ GATE_MM0(CLK_MM_DPI0_DPI0, "mm_dpi0_dpi0", "dpi0_sel", 20), + GATE_MM0(CLK_MM_MM_FAKE, "mm_fake", "mm_sel", 21), + GATE_MM0(CLK_MM_MM_SMI_COMMON, "mm_smi_common", "mm_sel", 22), + GATE_MM0(CLK_MM_MM_SMI_LARB0, "mm_smi_larb0", "mm_sel", 23), +diff --git a/drivers/clk/mediatek/clk-pllfh.c b/drivers/clk/mediatek/clk-pllfh.c +index 3a2b3f90be25d..094ec8a26d668 100644 +--- a/drivers/clk/mediatek/clk-pllfh.c ++++ b/drivers/clk/mediatek/clk-pllfh.c +@@ -68,7 +68,7 @@ void fhctl_parse_dt(const u8 *compatible_node, struct mtk_pllfh_data *pllfhs, + + node = of_find_compatible_node(NULL, NULL, compatible_node); + if (!node) { +- pr_err("cannot find \"%s\"\n", compatible_node); ++ pr_warn("cannot find \"%s\"\n", compatible_node); + return; + } + +diff --git a/drivers/clk/qcom/clk-alpha-pll.c b/drivers/clk/qcom/clk-alpha-pll.c +index 892f2efc1c32c..82420e81da35b 100644 +--- a/drivers/clk/qcom/clk-alpha-pll.c ++++ b/drivers/clk/qcom/clk-alpha-pll.c +@@ -212,7 +212,6 @@ const u8 clk_alpha_pll_regs[][PLL_OFF_MAX_REGS] = { + [PLL_OFF_USER_CTL] = 0x18, + [PLL_OFF_USER_CTL_U] = 0x1c, + [PLL_OFF_CONFIG_CTL] = 0x20, +- [PLL_OFF_CONFIG_CTL_U] = 0xff, + [PLL_OFF_TEST_CTL] = 0x30, + [PLL_OFF_TEST_CTL_U] = 0x34, + [PLL_OFF_STATUS] = 0x28, +diff --git a/drivers/clk/qcom/dispcc-sm6350.c b/drivers/clk/qcom/dispcc-sm6350.c +index ea6f54ed846ec..441f042f5ea45 100644 +--- a/drivers/clk/qcom/dispcc-sm6350.c ++++ b/drivers/clk/qcom/dispcc-sm6350.c +@@ -221,26 +221,17 @@ static struct clk_rcg2 disp_cc_mdss_dp_crypto_clk_src = { + }, + }; + +-static const struct freq_tbl ftbl_disp_cc_mdss_dp_link_clk_src[] = { +- F(162000, P_DP_PHY_PLL_LINK_CLK, 1, 0, 0), +- F(270000, P_DP_PHY_PLL_LINK_CLK, 1, 0, 0), +- F(540000, P_DP_PHY_PLL_LINK_CLK, 1, 0, 0), +- F(810000, P_DP_PHY_PLL_LINK_CLK, 1, 0, 0), +- { } +-}; +- + static struct clk_rcg2 disp_cc_mdss_dp_link_clk_src = { + .cmd_rcgr = 0x10f8, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_0, +- .freq_tbl = ftbl_disp_cc_mdss_dp_link_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_dp_link_clk_src", + .parent_data = disp_cc_parent_data_0, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_byte2_ops, + }, + }; + +diff --git a/drivers/clk/qcom/dispcc-sm8450.c b/drivers/clk/qcom/dispcc-sm8450.c +index 2c4aecd75186b..239cc726c7e29 100644 +--- a/drivers/clk/qcom/dispcc-sm8450.c ++++ b/drivers/clk/qcom/dispcc-sm8450.c +@@ -309,26 +309,17 @@ static struct clk_rcg2 disp_cc_mdss_dptx0_aux_clk_src = { + }, + }; + +-static const struct freq_tbl ftbl_disp_cc_mdss_dptx0_link_clk_src[] = { +- F(162000, P_DP0_PHY_PLL_LINK_CLK, 1, 0, 0), +- F(270000, P_DP0_PHY_PLL_LINK_CLK, 1, 0, 0), +- F(540000, P_DP0_PHY_PLL_LINK_CLK, 1, 0, 0), +- F(810000, P_DP0_PHY_PLL_LINK_CLK, 1, 0, 0), +- { } +-}; +- + static struct clk_rcg2 disp_cc_mdss_dptx0_link_clk_src = { + .cmd_rcgr = 0x819c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_3, +- .freq_tbl = ftbl_disp_cc_mdss_dptx0_link_clk_src, + .clkr.hw.init = &(struct clk_init_data) { + .name = "disp_cc_mdss_dptx0_link_clk_src", + .parent_data = disp_cc_parent_data_3, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_3), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_byte2_ops, + }, + }; + +@@ -382,13 +373,12 @@ static struct clk_rcg2 disp_cc_mdss_dptx1_link_clk_src = { + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_3, +- .freq_tbl = ftbl_disp_cc_mdss_dptx0_link_clk_src, + .clkr.hw.init = &(struct clk_init_data) { + .name = "disp_cc_mdss_dptx1_link_clk_src", + .parent_data = disp_cc_parent_data_3, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_3), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_byte2_ops, + }, + }; + +@@ -442,13 +432,12 @@ static struct clk_rcg2 disp_cc_mdss_dptx2_link_clk_src = { + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_3, +- .freq_tbl = ftbl_disp_cc_mdss_dptx0_link_clk_src, + .clkr.hw.init = &(struct clk_init_data) { + .name = "disp_cc_mdss_dptx2_link_clk_src", + .parent_data = disp_cc_parent_data_3, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_3), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_byte2_ops, + }, + }; + +@@ -502,13 +491,12 @@ static struct clk_rcg2 disp_cc_mdss_dptx3_link_clk_src = { + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_3, +- .freq_tbl = ftbl_disp_cc_mdss_dptx0_link_clk_src, + .clkr.hw.init = &(struct clk_init_data) { + .name = "disp_cc_mdss_dptx3_link_clk_src", + .parent_data = disp_cc_parent_data_3, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_3), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_byte2_ops, + }, + }; + +diff --git a/drivers/clk/qcom/dispcc-sm8550.c b/drivers/clk/qcom/dispcc-sm8550.c +index 0b8f0904b339b..b9edeb2a221dc 100644 +--- a/drivers/clk/qcom/dispcc-sm8550.c ++++ b/drivers/clk/qcom/dispcc-sm8550.c +@@ -345,26 +345,17 @@ static struct clk_rcg2 disp_cc_mdss_dptx0_aux_clk_src = { + }, + }; + +-static const struct freq_tbl ftbl_disp_cc_mdss_dptx0_link_clk_src[] = { +- F(162000, P_DP0_PHY_PLL_LINK_CLK, 1, 0, 0), +- F(270000, P_DP0_PHY_PLL_LINK_CLK, 1, 0, 0), +- F(540000, P_DP0_PHY_PLL_LINK_CLK, 1, 0, 0), +- F(810000, P_DP0_PHY_PLL_LINK_CLK, 1, 0, 0), +- { } +-}; +- + static struct clk_rcg2 disp_cc_mdss_dptx0_link_clk_src = { + .cmd_rcgr = 0x8170, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_7, +- .freq_tbl = ftbl_disp_cc_mdss_dptx0_link_clk_src, + .clkr.hw.init = &(struct clk_init_data) { + .name = "disp_cc_mdss_dptx0_link_clk_src", + .parent_data = disp_cc_parent_data_7, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_7), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_byte2_ops, + }, + }; + +@@ -418,13 +409,12 @@ static struct clk_rcg2 disp_cc_mdss_dptx1_link_clk_src = { + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_3, +- .freq_tbl = ftbl_disp_cc_mdss_dptx0_link_clk_src, + .clkr.hw.init = &(struct clk_init_data) { + .name = "disp_cc_mdss_dptx1_link_clk_src", + .parent_data = disp_cc_parent_data_3, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_3), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_byte2_ops, + }, + }; + +@@ -478,13 +468,12 @@ static struct clk_rcg2 disp_cc_mdss_dptx2_link_clk_src = { + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_3, +- .freq_tbl = ftbl_disp_cc_mdss_dptx0_link_clk_src, + .clkr.hw.init = &(struct clk_init_data) { + .name = "disp_cc_mdss_dptx2_link_clk_src", + .parent_data = disp_cc_parent_data_3, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_3), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_byte2_ops, + }, + }; + +@@ -538,13 +527,12 @@ static struct clk_rcg2 disp_cc_mdss_dptx3_link_clk_src = { + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_3, +- .freq_tbl = ftbl_disp_cc_mdss_dptx0_link_clk_src, + .clkr.hw.init = &(struct clk_init_data) { + .name = "disp_cc_mdss_dptx3_link_clk_src", + .parent_data = disp_cc_parent_data_3, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_3), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_byte2_ops, + }, + }; + +diff --git a/drivers/clk/qcom/mmcc-msm8998.c b/drivers/clk/qcom/mmcc-msm8998.c +index 1180e48c687ac..275fb3b71ede4 100644 +--- a/drivers/clk/qcom/mmcc-msm8998.c ++++ b/drivers/clk/qcom/mmcc-msm8998.c +@@ -2535,6 +2535,8 @@ static struct clk_branch vmem_ahb_clk = { + + static struct gdsc video_top_gdsc = { + .gdscr = 0x1024, ++ .cxcs = (unsigned int []){ 0x1028, 0x1034, 0x1038 }, ++ .cxc_count = 3, + .pd = { + .name = "video_top", + }, +@@ -2543,20 +2545,26 @@ static struct gdsc video_top_gdsc = { + + static struct gdsc video_subcore0_gdsc = { + .gdscr = 0x1040, ++ .cxcs = (unsigned int []){ 0x1048 }, ++ .cxc_count = 1, + .pd = { + .name = "video_subcore0", + }, + .parent = &video_top_gdsc.pd, + .pwrsts = PWRSTS_OFF_ON, ++ .flags = HW_CTRL, + }; + + static struct gdsc video_subcore1_gdsc = { + .gdscr = 0x1044, ++ .cxcs = (unsigned int []){ 0x104c }, ++ .cxc_count = 1, + .pd = { + .name = "video_subcore1", + }, + .parent = &video_top_gdsc.pd, + .pwrsts = PWRSTS_OFF_ON, ++ .flags = HW_CTRL, + }; + + static struct gdsc mdss_gdsc = { +diff --git a/drivers/clk/renesas/r8a779a0-cpg-mssr.c b/drivers/clk/renesas/r8a779a0-cpg-mssr.c +index 4c2872f45387f..ff3f85e906fe1 100644 +--- a/drivers/clk/renesas/r8a779a0-cpg-mssr.c ++++ b/drivers/clk/renesas/r8a779a0-cpg-mssr.c +@@ -139,7 +139,7 @@ static const struct mssr_mod_clk r8a779a0_mod_clks[] __initconst = { + DEF_MOD("avb3", 214, R8A779A0_CLK_S3D2), + DEF_MOD("avb4", 215, R8A779A0_CLK_S3D2), + DEF_MOD("avb5", 216, R8A779A0_CLK_S3D2), +- DEF_MOD("canfd0", 328, R8A779A0_CLK_CANFD), ++ DEF_MOD("canfd0", 328, R8A779A0_CLK_S3D2), + DEF_MOD("csi40", 331, R8A779A0_CLK_CSI0), + DEF_MOD("csi41", 400, R8A779A0_CLK_CSI0), + DEF_MOD("csi42", 401, R8A779A0_CLK_CSI0), +diff --git a/drivers/clk/renesas/r9a07g043-cpg.c b/drivers/clk/renesas/r9a07g043-cpg.c +index 1a7a6d60aca44..6c6bc79b2e9ce 100644 +--- a/drivers/clk/renesas/r9a07g043-cpg.c ++++ b/drivers/clk/renesas/r9a07g043-cpg.c +@@ -250,6 +250,10 @@ static struct rzg2l_mod_clk r9a07g043_mod_clks[] = { + 0x5a8, 1), + DEF_MOD("tsu_pclk", R9A07G043_TSU_PCLK, R9A07G043_CLK_TSU, + 0x5ac, 0), ++#ifdef CONFIG_RISCV ++ DEF_MOD("nceplic_aclk", R9A07G043_NCEPLIC_ACLK, R9A07G043_CLK_P1, ++ 0x608, 0), ++#endif + }; + + static struct rzg2l_reset r9a07g043_resets[] = { +@@ -303,6 +307,10 @@ static struct rzg2l_reset r9a07g043_resets[] = { + DEF_RST(R9A07G043_ADC_PRESETN, 0x8a8, 0), + DEF_RST(R9A07G043_ADC_ADRST_N, 0x8a8, 1), + DEF_RST(R9A07G043_TSU_PRESETN, 0x8ac, 0), ++#ifdef CONFIG_RISCV ++ DEF_RST(R9A07G043_NCEPLIC_ARESETN, 0x908, 0), ++#endif ++ + }; + + static const unsigned int r9a07g043_crit_mod_clks[] __initconst = { +@@ -312,6 +320,7 @@ static const unsigned int r9a07g043_crit_mod_clks[] __initconst = { + #endif + #ifdef CONFIG_RISCV + MOD_CLK_BASE + R9A07G043_IAX45_CLK, ++ MOD_CLK_BASE + R9A07G043_NCEPLIC_ACLK, + #endif + MOD_CLK_BASE + R9A07G043_DMAC_ACLK, + }; +diff --git a/drivers/clk/samsung/clk-exynosautov9.c b/drivers/clk/samsung/clk-exynosautov9.c +index e9c06eb93e666..f04bacacab2cb 100644 +--- a/drivers/clk/samsung/clk-exynosautov9.c ++++ b/drivers/clk/samsung/clk-exynosautov9.c +@@ -352,13 +352,13 @@ static const struct samsung_pll_clock top_pll_clks[] __initconst = { + /* CMU_TOP_PURECLKCOMP */ + PLL(pll_0822x, FOUT_SHARED0_PLL, "fout_shared0_pll", "oscclk", + PLL_LOCKTIME_PLL_SHARED0, PLL_CON3_PLL_SHARED0, NULL), +- PLL(pll_0822x, FOUT_SHARED0_PLL, "fout_shared1_pll", "oscclk", ++ PLL(pll_0822x, FOUT_SHARED1_PLL, "fout_shared1_pll", "oscclk", + PLL_LOCKTIME_PLL_SHARED1, PLL_CON3_PLL_SHARED1, NULL), +- PLL(pll_0822x, FOUT_SHARED0_PLL, "fout_shared2_pll", "oscclk", ++ PLL(pll_0822x, FOUT_SHARED2_PLL, "fout_shared2_pll", "oscclk", + PLL_LOCKTIME_PLL_SHARED2, PLL_CON3_PLL_SHARED2, NULL), +- PLL(pll_0822x, FOUT_SHARED0_PLL, "fout_shared3_pll", "oscclk", ++ PLL(pll_0822x, FOUT_SHARED3_PLL, "fout_shared3_pll", "oscclk", + PLL_LOCKTIME_PLL_SHARED3, PLL_CON3_PLL_SHARED3, NULL), +- PLL(pll_0822x, FOUT_SHARED0_PLL, "fout_shared4_pll", "oscclk", ++ PLL(pll_0822x, FOUT_SHARED4_PLL, "fout_shared4_pll", "oscclk", + PLL_LOCKTIME_PLL_SHARED4, PLL_CON3_PLL_SHARED4, NULL), + }; + +diff --git a/drivers/cpufreq/brcmstb-avs-cpufreq.c b/drivers/cpufreq/brcmstb-avs-cpufreq.c +index 1a1857b0a6f48..ea8438550b490 100644 +--- a/drivers/cpufreq/brcmstb-avs-cpufreq.c ++++ b/drivers/cpufreq/brcmstb-avs-cpufreq.c +@@ -481,9 +481,12 @@ 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); ++ struct private_data *priv; ++ + if (!policy) + return 0; +- struct private_data *priv = policy->driver_data; ++ ++ priv = policy->driver_data; + + cpufreq_cpu_put(policy); + +diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c +index fe08ca419b3dc..1ba3943be8a3d 100644 +--- a/drivers/cpufreq/cppc_cpufreq.c ++++ b/drivers/cpufreq/cppc_cpufreq.c +@@ -844,10 +844,15 @@ static unsigned int cppc_cpufreq_get_rate(unsigned int cpu) + { + struct cppc_perf_fb_ctrs fb_ctrs_t0 = {0}, fb_ctrs_t1 = {0}; + struct cpufreq_policy *policy = cpufreq_cpu_get(cpu); +- struct cppc_cpudata *cpu_data = policy->driver_data; ++ struct cppc_cpudata *cpu_data; + u64 delivered_perf; + int ret; + ++ if (!policy) ++ return -ENODEV; ++ ++ cpu_data = policy->driver_data; ++ + cpufreq_cpu_put(policy); + + ret = cppc_get_perf_ctrs(cpu, &fb_ctrs_t0); +@@ -927,10 +932,15 @@ static struct cpufreq_driver cppc_cpufreq_driver = { + static unsigned int hisi_cppc_cpufreq_get_rate(unsigned int cpu) + { + struct cpufreq_policy *policy = cpufreq_cpu_get(cpu); +- struct cppc_cpudata *cpu_data = policy->driver_data; ++ struct cppc_cpudata *cpu_data; + u64 desired_perf; + int ret; + ++ if (!policy) ++ return -ENODEV; ++ ++ cpu_data = policy->driver_data; ++ + cpufreq_cpu_put(policy); + + ret = cppc_get_desired_perf(cpu, &desired_perf); +diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c +index 9177265d73b47..06e0294a17a8d 100644 +--- a/drivers/cpufreq/cpufreq.c ++++ b/drivers/cpufreq/cpufreq.c +@@ -1670,10 +1670,13 @@ static void __cpufreq_offline(unsigned int cpu, struct cpufreq_policy *policy) + */ + if (cpufreq_driver->offline) { + cpufreq_driver->offline(policy); +- } else if (cpufreq_driver->exit) { +- cpufreq_driver->exit(policy); +- policy->freq_table = NULL; ++ return; + } ++ ++ if (cpufreq_driver->exit) ++ cpufreq_driver->exit(policy); ++ ++ policy->freq_table = NULL; + } + + static int cpufreq_offline(unsigned int cpu) +@@ -1731,7 +1734,7 @@ static void cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif) + } + + /* We did light-weight exit earlier, do full tear down now */ +- if (cpufreq_driver->offline) ++ if (cpufreq_driver->offline && cpufreq_driver->exit) + cpufreq_driver->exit(policy); + + up_write(&policy->rwsem); +diff --git a/drivers/crypto/bcm/spu2.c b/drivers/crypto/bcm/spu2.c +index 07989bb8c220a..3fdc64b5a65e7 100644 +--- a/drivers/crypto/bcm/spu2.c ++++ b/drivers/crypto/bcm/spu2.c +@@ -495,7 +495,7 @@ static void spu2_dump_omd(u8 *omd, u16 hash_key_len, u16 ciph_key_len, + if (hash_iv_len) { + packet_log(" Hash IV Length %u bytes\n", hash_iv_len); + packet_dump(" hash IV: ", ptr, hash_iv_len); +- ptr += ciph_key_len; ++ ptr += hash_iv_len; + } + + if (ciph_iv_len) { +diff --git a/drivers/crypto/ccp/sp-platform.c b/drivers/crypto/ccp/sp-platform.c +index 7d79a8744f9a6..c43ad7e1acf7e 100644 +--- a/drivers/crypto/ccp/sp-platform.c ++++ b/drivers/crypto/ccp/sp-platform.c +@@ -39,44 +39,38 @@ static const struct sp_dev_vdata dev_vdata[] = { + }, + }; + +-#ifdef CONFIG_ACPI + static const struct acpi_device_id sp_acpi_match[] = { + { "AMDI0C00", (kernel_ulong_t)&dev_vdata[0] }, + { }, + }; + MODULE_DEVICE_TABLE(acpi, sp_acpi_match); +-#endif + +-#ifdef CONFIG_OF + static const struct of_device_id sp_of_match[] = { + { .compatible = "amd,ccp-seattle-v1a", + .data = (const void *)&dev_vdata[0] }, + { }, + }; + MODULE_DEVICE_TABLE(of, sp_of_match); +-#endif + + static struct sp_dev_vdata *sp_get_of_version(struct platform_device *pdev) + { +-#ifdef CONFIG_OF + const struct of_device_id *match; + + match = of_match_node(sp_of_match, pdev->dev.of_node); + if (match && match->data) + return (struct sp_dev_vdata *)match->data; +-#endif ++ + return NULL; + } + + static struct sp_dev_vdata *sp_get_acpi_version(struct platform_device *pdev) + { +-#ifdef CONFIG_ACPI + const struct acpi_device_id *match; + + match = acpi_match_device(sp_acpi_match, &pdev->dev); + if (match && match->driver_data) + return (struct sp_dev_vdata *)match->driver_data; +-#endif ++ + return NULL; + } + +@@ -214,12 +208,8 @@ static int sp_platform_resume(struct platform_device *pdev) + static struct platform_driver sp_platform_driver = { + .driver = { + .name = "ccp", +-#ifdef CONFIG_ACPI + .acpi_match_table = sp_acpi_match, +-#endif +-#ifdef CONFIG_OF + .of_match_table = sp_of_match, +-#endif + }, + .probe = sp_platform_probe, + .remove = sp_platform_remove, +diff --git a/drivers/crypto/intel/qat/qat_4xxx/adf_drv.c b/drivers/crypto/intel/qat/qat_4xxx/adf_drv.c +index 90f5c1ca7b8d8..f6f9e20f74b54 100644 +--- a/drivers/crypto/intel/qat/qat_4xxx/adf_drv.c ++++ b/drivers/crypto/intel/qat/qat_4xxx/adf_drv.c +@@ -463,7 +463,9 @@ module_pci_driver(adf_driver); + MODULE_LICENSE("Dual BSD/GPL"); + MODULE_AUTHOR("Intel"); + MODULE_FIRMWARE(ADF_4XXX_FW); ++MODULE_FIRMWARE(ADF_402XX_FW); + MODULE_FIRMWARE(ADF_4XXX_MMP); ++MODULE_FIRMWARE(ADF_402XX_MMP); + MODULE_DESCRIPTION("Intel(R) QuickAssist Technology"); + MODULE_VERSION(ADF_DRV_VERSION); + MODULE_SOFTDEP("pre: crypto-intel_qat"); +diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c +index e2a82ee4ff0cf..c65ab42546238 100644 +--- a/drivers/cxl/core/region.c ++++ b/drivers/cxl/core/region.c +@@ -2549,6 +2549,7 @@ static struct cxl_pmem_region *cxl_pmem_region_alloc(struct cxl_region *cxlr) + if (i == 0) { + cxl_nvb = cxl_find_nvdimm_bridge(cxlmd); + if (!cxl_nvb) { ++ kfree(cxlr_pmem); + cxlr_pmem = ERR_PTR(-ENODEV); + goto out; + } +diff --git a/drivers/cxl/core/trace.h b/drivers/cxl/core/trace.h +index f01d0709c9c32..bdf24867d5174 100644 +--- a/drivers/cxl/core/trace.h ++++ b/drivers/cxl/core/trace.h +@@ -252,8 +252,8 @@ TRACE_EVENT(cxl_generic_event, + * DRAM Event Record + * CXL rev 3.0 section 8.2.9.2.1.2; Table 8-44 + */ +-#define CXL_DPA_FLAGS_MASK 0x3F +-#define CXL_DPA_MASK (~CXL_DPA_FLAGS_MASK) ++#define CXL_DPA_FLAGS_MASK GENMASK(1, 0) ++#define CXL_DPA_MASK GENMASK_ULL(63, 6) + + #define CXL_DPA_VOLATILE BIT(0) + #define CXL_DPA_NOT_REPAIRABLE BIT(1) +diff --git a/drivers/dma-buf/st-dma-fence-chain.c b/drivers/dma-buf/st-dma-fence-chain.c +index 661de4add4c72..ed4b323886e43 100644 +--- a/drivers/dma-buf/st-dma-fence-chain.c ++++ b/drivers/dma-buf/st-dma-fence-chain.c +@@ -476,10 +476,9 @@ static int find_race(void *arg) + for (i = 0; i < ncpus; i++) { + int ret; + +- ret = kthread_stop(threads[i]); ++ ret = kthread_stop_put(threads[i]); + if (ret && !err) + err = ret; +- put_task_struct(threads[i]); + } + kfree(threads); + +@@ -591,8 +590,7 @@ static int wait_forward(void *arg) + for (i = 0; i < fc.chain_length; i++) + dma_fence_signal(fc.fences[i]); + +- err = kthread_stop(tsk); +- put_task_struct(tsk); ++ err = kthread_stop_put(tsk); + + err: + fence_chains_fini(&fc); +@@ -621,8 +619,7 @@ static int wait_backward(void *arg) + for (i = fc.chain_length; i--; ) + dma_fence_signal(fc.fences[i]); + +- err = kthread_stop(tsk); +- put_task_struct(tsk); ++ err = kthread_stop_put(tsk); + + err: + fence_chains_fini(&fc); +@@ -669,8 +666,7 @@ static int wait_random(void *arg) + for (i = 0; i < fc.chain_length; i++) + dma_fence_signal(fc.fences[i]); + +- err = kthread_stop(tsk); +- put_task_struct(tsk); ++ err = kthread_stop_put(tsk); + + err: + fence_chains_fini(&fc); +diff --git a/drivers/dma-buf/st-dma-fence.c b/drivers/dma-buf/st-dma-fence.c +index fb6e0a6ae2c96..b7c6f7ea9e0c8 100644 +--- a/drivers/dma-buf/st-dma-fence.c ++++ b/drivers/dma-buf/st-dma-fence.c +@@ -548,11 +548,9 @@ static int race_signal_callback(void *arg) + for (i = 0; i < ARRAY_SIZE(t); i++) { + int err; + +- err = kthread_stop(t[i].task); ++ err = kthread_stop_put(t[i].task); + if (err && !ret) + ret = err; +- +- put_task_struct(t[i].task); + } + } + +diff --git a/drivers/dma-buf/sync_debug.c b/drivers/dma-buf/sync_debug.c +index 101394f16930f..237bce21d1e72 100644 +--- a/drivers/dma-buf/sync_debug.c ++++ b/drivers/dma-buf/sync_debug.c +@@ -110,12 +110,12 @@ static void sync_print_obj(struct seq_file *s, struct sync_timeline *obj) + + seq_printf(s, "%s: %d\n", obj->name, obj->value); + +- spin_lock_irq(&obj->lock); ++ spin_lock(&obj->lock); /* Caller already disabled IRQ. */ + list_for_each(pos, &obj->pt_list) { + struct sync_pt *pt = container_of(pos, struct sync_pt, link); + sync_print_fence(s, &pt->base, false); + } +- spin_unlock_irq(&obj->lock); ++ spin_unlock(&obj->lock); + } + + static void sync_print_sync_file(struct seq_file *s, +diff --git a/drivers/dma/idma64.c b/drivers/dma/idma64.c +index f86939fa33b95..6fa797fd85017 100644 +--- a/drivers/dma/idma64.c ++++ b/drivers/dma/idma64.c +@@ -598,7 +598,9 @@ static int idma64_probe(struct idma64_chip *chip) + + idma64->dma.dev = chip->sysdev; + +- dma_set_max_seg_size(idma64->dma.dev, IDMA64C_CTLH_BLOCK_TS_MASK); ++ ret = dma_set_max_seg_size(idma64->dma.dev, IDMA64C_CTLH_BLOCK_TS_MASK); ++ if (ret) ++ return ret; + + ret = dma_async_device_register(&idma64->dma); + if (ret) +diff --git a/drivers/dma/idxd/cdev.c b/drivers/dma/idxd/cdev.c +index 26f1dedc92d38..c18633ad8455f 100644 +--- a/drivers/dma/idxd/cdev.c ++++ b/drivers/dma/idxd/cdev.c +@@ -577,7 +577,6 @@ void idxd_wq_del_cdev(struct idxd_wq *wq) + struct idxd_cdev *idxd_cdev; + + idxd_cdev = wq->idxd_cdev; +- ida_destroy(&file_ida); + wq->idxd_cdev = NULL; + cdev_device_del(&idxd_cdev->cdev, cdev_dev(idxd_cdev)); + put_device(cdev_dev(idxd_cdev)); +diff --git a/drivers/extcon/Kconfig b/drivers/extcon/Kconfig +index 8de9023c2a387..cf472e44c5ff9 100644 +--- a/drivers/extcon/Kconfig ++++ b/drivers/extcon/Kconfig +@@ -116,7 +116,8 @@ config EXTCON_MAX77843 + + config EXTCON_MAX8997 + tristate "Maxim MAX8997 EXTCON Support" +- depends on MFD_MAX8997 && IRQ_DOMAIN ++ depends on MFD_MAX8997 ++ select IRQ_DOMAIN + help + If you say yes here you get support for the MUIC device of + Maxim MAX8997 PMIC. The MAX8997 MUIC is a USB port accessory +diff --git a/drivers/firmware/dmi-id.c b/drivers/firmware/dmi-id.c +index 5f3a3e913d28f..d19c78a78ae3a 100644 +--- a/drivers/firmware/dmi-id.c ++++ b/drivers/firmware/dmi-id.c +@@ -169,9 +169,14 @@ static int dmi_dev_uevent(const struct device *dev, struct kobj_uevent_env *env) + return 0; + } + ++static void dmi_dev_release(struct device *dev) ++{ ++ kfree(dev); ++} ++ + static struct class dmi_class = { + .name = "dmi", +- .dev_release = (void(*)(struct device *)) kfree, ++ .dev_release = dmi_dev_release, + .dev_uevent = dmi_dev_uevent, + }; + +diff --git a/drivers/firmware/efi/libstub/fdt.c b/drivers/firmware/efi/libstub/fdt.c +index 70e9789ff9de0..6a337f1f8787b 100644 +--- a/drivers/firmware/efi/libstub/fdt.c ++++ b/drivers/firmware/efi/libstub/fdt.c +@@ -335,8 +335,8 @@ efi_status_t allocate_new_fdt_and_exit_boot(void *handle, + + fail: + efi_free(fdt_size, fdt_addr); +- +- efi_bs_call(free_pool, priv.runtime_map); ++ if (!efi_novamap) ++ efi_bs_call(free_pool, priv.runtime_map); + + return EFI_LOAD_ERROR; + } +diff --git a/drivers/firmware/efi/libstub/x86-stub.c b/drivers/firmware/efi/libstub/x86-stub.c +index e4ae3db727efa..8e9f2ddfbe467 100644 +--- a/drivers/firmware/efi/libstub/x86-stub.c ++++ b/drivers/firmware/efi/libstub/x86-stub.c +@@ -776,6 +776,26 @@ static void error(char *str) + efi_warn("Decompression failed: %s\n", str); + } + ++static const char *cmdline_memmap_override; ++ ++static efi_status_t parse_options(const char *cmdline) ++{ ++ static const char opts[][14] = { ++ "mem=", "memmap=", "efi_fake_mem=", "hugepages=" ++ }; ++ ++ for (int i = 0; i < ARRAY_SIZE(opts); i++) { ++ const char *p = strstr(cmdline, opts[i]); ++ ++ if (p == cmdline || (p > cmdline && isspace(p[-1]))) { ++ cmdline_memmap_override = opts[i]; ++ break; ++ } ++ } ++ ++ return efi_parse_options(cmdline); ++} ++ + static efi_status_t efi_decompress_kernel(unsigned long *kernel_entry) + { + unsigned long virt_addr = LOAD_PHYSICAL_ADDR; +@@ -807,6 +827,10 @@ static efi_status_t efi_decompress_kernel(unsigned long *kernel_entry) + !memcmp(efistub_fw_vendor(), ami, sizeof(ami))) { + efi_debug("AMI firmware v2.0 or older detected - disabling physical KASLR\n"); + seed[0] = 0; ++ } else if (cmdline_memmap_override) { ++ efi_info("%s detected on the kernel command line - disabling physical KASLR\n", ++ cmdline_memmap_override); ++ seed[0] = 0; + } + } + +@@ -881,7 +905,7 @@ void __noreturn efi_stub_entry(efi_handle_t handle, + } + + #ifdef CONFIG_CMDLINE_BOOL +- status = efi_parse_options(CONFIG_CMDLINE); ++ status = parse_options(CONFIG_CMDLINE); + if (status != EFI_SUCCESS) { + efi_err("Failed to parse options\n"); + goto fail; +@@ -890,7 +914,7 @@ void __noreturn efi_stub_entry(efi_handle_t handle, + if (!IS_ENABLED(CONFIG_CMDLINE_OVERRIDE)) { + unsigned long cmdline_paddr = ((u64)hdr->cmd_line_ptr | + ((u64)boot_params->ext_cmd_line_ptr << 32)); +- status = efi_parse_options((char *)cmdline_paddr); ++ status = parse_options((char *)cmdline_paddr); + if (status != EFI_SUCCESS) { + efi_err("Failed to parse options\n"); + goto fail; +diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c +index 69831f1d91e3f..ff7c155239e31 100644 +--- a/drivers/firmware/qcom_scm.c ++++ b/drivers/firmware/qcom_scm.c +@@ -1333,7 +1333,7 @@ static int qcom_scm_find_dload_address(struct device *dev, u64 *addr) + */ + bool qcom_scm_is_available(void) + { +- return !!__scm; ++ return !!READ_ONCE(__scm); + } + EXPORT_SYMBOL_GPL(qcom_scm_is_available); + +@@ -1414,10 +1414,12 @@ static int qcom_scm_probe(struct platform_device *pdev) + if (!scm) + return -ENOMEM; + ++ scm->dev = &pdev->dev; + ret = qcom_scm_find_dload_address(&pdev->dev, &scm->dload_mode_addr); + if (ret < 0) + return ret; + ++ init_completion(&scm->waitq_comp); + mutex_init(&scm->scm_bw_lock); + + scm->path = devm_of_icc_get(&pdev->dev, NULL); +@@ -1449,10 +1451,8 @@ static int qcom_scm_probe(struct platform_device *pdev) + if (ret) + return ret; + +- __scm = scm; +- __scm->dev = &pdev->dev; +- +- init_completion(&__scm->waitq_comp); ++ /* Let all above stores be available after this */ ++ smp_store_release(&__scm, scm); + + irq = platform_get_irq_optional(pdev, 0); + if (irq < 0) { +diff --git a/drivers/firmware/raspberrypi.c b/drivers/firmware/raspberrypi.c +index f66efaa5196d9..428ae54d3196c 100644 +--- a/drivers/firmware/raspberrypi.c ++++ b/drivers/firmware/raspberrypi.c +@@ -9,6 +9,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -97,8 +98,8 @@ int rpi_firmware_property_list(struct rpi_firmware *fw, + if (size & 3) + return -EINVAL; + +- buf = dma_alloc_coherent(fw->cl.dev, PAGE_ALIGN(size), &bus_addr, +- GFP_ATOMIC); ++ buf = dma_alloc_coherent(fw->chan->mbox->dev, PAGE_ALIGN(size), ++ &bus_addr, GFP_ATOMIC); + if (!buf) + return -ENOMEM; + +@@ -126,7 +127,7 @@ int rpi_firmware_property_list(struct rpi_firmware *fw, + ret = -EINVAL; + } + +- dma_free_coherent(fw->cl.dev, PAGE_ALIGN(size), buf, bus_addr); ++ dma_free_coherent(fw->chan->mbox->dev, PAGE_ALIGN(size), buf, bus_addr); + + return ret; + } +diff --git a/drivers/fpga/dfl-pci.c b/drivers/fpga/dfl-pci.c +index 98b8fd16183e4..80cac3a5f9767 100644 +--- a/drivers/fpga/dfl-pci.c ++++ b/drivers/fpga/dfl-pci.c +@@ -78,6 +78,7 @@ static void cci_pci_free_irq(struct pci_dev *pcidev) + #define PCIE_DEVICE_ID_SILICOM_PAC_N5011 0x1001 + #define PCIE_DEVICE_ID_INTEL_DFL 0xbcce + /* PCI Subdevice ID for PCIE_DEVICE_ID_INTEL_DFL */ ++#define PCIE_SUBDEVICE_ID_INTEL_D5005 0x138d + #define PCIE_SUBDEVICE_ID_INTEL_N6000 0x1770 + #define PCIE_SUBDEVICE_ID_INTEL_N6001 0x1771 + #define PCIE_SUBDEVICE_ID_INTEL_C6100 0x17d4 +@@ -101,6 +102,8 @@ static struct pci_device_id cci_pcie_id_tbl[] = { + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_INTEL_PAC_D5005_VF),}, + {PCI_DEVICE(PCI_VENDOR_ID_SILICOM_DENMARK, PCIE_DEVICE_ID_SILICOM_PAC_N5010),}, + {PCI_DEVICE(PCI_VENDOR_ID_SILICOM_DENMARK, PCIE_DEVICE_ID_SILICOM_PAC_N5011),}, ++ {PCI_DEVICE_SUB(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_INTEL_DFL, ++ PCI_VENDOR_ID_INTEL, PCIE_SUBDEVICE_ID_INTEL_D5005),}, + {PCI_DEVICE_SUB(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_INTEL_DFL, + PCI_VENDOR_ID_INTEL, PCIE_SUBDEVICE_ID_INTEL_N6000),}, + {PCI_DEVICE_SUB(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_INTEL_DFL_VF, +diff --git a/drivers/fpga/fpga-bridge.c b/drivers/fpga/fpga-bridge.c +index a024be2b84e29..83d35fbb82450 100644 +--- a/drivers/fpga/fpga-bridge.c ++++ b/drivers/fpga/fpga-bridge.c +@@ -55,33 +55,26 @@ int fpga_bridge_disable(struct fpga_bridge *bridge) + } + EXPORT_SYMBOL_GPL(fpga_bridge_disable); + +-static struct fpga_bridge *__fpga_bridge_get(struct device *dev, ++static struct fpga_bridge *__fpga_bridge_get(struct device *bridge_dev, + struct fpga_image_info *info) + { + struct fpga_bridge *bridge; +- int ret = -ENODEV; + +- bridge = to_fpga_bridge(dev); ++ bridge = to_fpga_bridge(bridge_dev); + + bridge->info = info; + +- if (!mutex_trylock(&bridge->mutex)) { +- ret = -EBUSY; +- goto err_dev; +- } ++ if (!mutex_trylock(&bridge->mutex)) ++ return ERR_PTR(-EBUSY); + +- if (!try_module_get(dev->parent->driver->owner)) +- goto err_ll_mod; ++ if (!try_module_get(bridge->br_ops_owner)) { ++ mutex_unlock(&bridge->mutex); ++ return ERR_PTR(-ENODEV); ++ } + + dev_dbg(&bridge->dev, "get\n"); + + return bridge; +- +-err_ll_mod: +- mutex_unlock(&bridge->mutex); +-err_dev: +- put_device(dev); +- return ERR_PTR(ret); + } + + /** +@@ -98,13 +91,18 @@ static struct fpga_bridge *__fpga_bridge_get(struct device *dev, + struct fpga_bridge *of_fpga_bridge_get(struct device_node *np, + struct fpga_image_info *info) + { +- struct device *dev; ++ struct fpga_bridge *bridge; ++ struct device *bridge_dev; + +- dev = class_find_device_by_of_node(&fpga_bridge_class, np); +- if (!dev) ++ bridge_dev = class_find_device_by_of_node(&fpga_bridge_class, np); ++ if (!bridge_dev) + return ERR_PTR(-ENODEV); + +- return __fpga_bridge_get(dev, info); ++ bridge = __fpga_bridge_get(bridge_dev, info); ++ if (IS_ERR(bridge)) ++ put_device(bridge_dev); ++ ++ return bridge; + } + EXPORT_SYMBOL_GPL(of_fpga_bridge_get); + +@@ -125,6 +123,7 @@ static int fpga_bridge_dev_match(struct device *dev, const void *data) + struct fpga_bridge *fpga_bridge_get(struct device *dev, + struct fpga_image_info *info) + { ++ struct fpga_bridge *bridge; + struct device *bridge_dev; + + bridge_dev = class_find_device(&fpga_bridge_class, NULL, dev, +@@ -132,7 +131,11 @@ struct fpga_bridge *fpga_bridge_get(struct device *dev, + if (!bridge_dev) + return ERR_PTR(-ENODEV); + +- return __fpga_bridge_get(bridge_dev, info); ++ bridge = __fpga_bridge_get(bridge_dev, info); ++ if (IS_ERR(bridge)) ++ put_device(bridge_dev); ++ ++ return bridge; + } + EXPORT_SYMBOL_GPL(fpga_bridge_get); + +@@ -146,7 +149,7 @@ void fpga_bridge_put(struct fpga_bridge *bridge) + dev_dbg(&bridge->dev, "put\n"); + + bridge->info = NULL; +- module_put(bridge->dev.parent->driver->owner); ++ module_put(bridge->br_ops_owner); + mutex_unlock(&bridge->mutex); + put_device(&bridge->dev); + } +@@ -316,18 +319,19 @@ static struct attribute *fpga_bridge_attrs[] = { + ATTRIBUTE_GROUPS(fpga_bridge); + + /** +- * fpga_bridge_register - create and register an FPGA Bridge device ++ * __fpga_bridge_register - create and register an FPGA Bridge device + * @parent: FPGA bridge device from pdev + * @name: FPGA bridge name + * @br_ops: pointer to structure of fpga bridge ops + * @priv: FPGA bridge private data ++ * @owner: owner module containing the br_ops + * + * Return: struct fpga_bridge pointer or ERR_PTR() + */ + struct fpga_bridge * +-fpga_bridge_register(struct device *parent, const char *name, +- const struct fpga_bridge_ops *br_ops, +- void *priv) ++__fpga_bridge_register(struct device *parent, const char *name, ++ const struct fpga_bridge_ops *br_ops, ++ void *priv, struct module *owner) + { + struct fpga_bridge *bridge; + int id, ret; +@@ -357,6 +361,7 @@ fpga_bridge_register(struct device *parent, const char *name, + + bridge->name = name; + bridge->br_ops = br_ops; ++ bridge->br_ops_owner = owner; + bridge->priv = priv; + + bridge->dev.groups = br_ops->groups; +@@ -386,7 +391,7 @@ fpga_bridge_register(struct device *parent, const char *name, + + return ERR_PTR(ret); + } +-EXPORT_SYMBOL_GPL(fpga_bridge_register); ++EXPORT_SYMBOL_GPL(__fpga_bridge_register); + + /** + * fpga_bridge_unregister - unregister an FPGA bridge +diff --git a/drivers/fpga/fpga-mgr.c b/drivers/fpga/fpga-mgr.c +index 06651389c5926..0f4035b089a2e 100644 +--- a/drivers/fpga/fpga-mgr.c ++++ b/drivers/fpga/fpga-mgr.c +@@ -664,20 +664,16 @@ static struct attribute *fpga_mgr_attrs[] = { + }; + ATTRIBUTE_GROUPS(fpga_mgr); + +-static struct fpga_manager *__fpga_mgr_get(struct device *dev) ++static struct fpga_manager *__fpga_mgr_get(struct device *mgr_dev) + { + struct fpga_manager *mgr; + +- mgr = to_fpga_manager(dev); ++ mgr = to_fpga_manager(mgr_dev); + +- if (!try_module_get(dev->parent->driver->owner)) +- goto err_dev; ++ if (!try_module_get(mgr->mops_owner)) ++ mgr = ERR_PTR(-ENODEV); + + return mgr; +- +-err_dev: +- put_device(dev); +- return ERR_PTR(-ENODEV); + } + + static int fpga_mgr_dev_match(struct device *dev, const void *data) +@@ -693,12 +689,18 @@ static int fpga_mgr_dev_match(struct device *dev, const void *data) + */ + struct fpga_manager *fpga_mgr_get(struct device *dev) + { +- struct device *mgr_dev = class_find_device(&fpga_mgr_class, NULL, dev, +- fpga_mgr_dev_match); ++ struct fpga_manager *mgr; ++ struct device *mgr_dev; ++ ++ mgr_dev = class_find_device(&fpga_mgr_class, NULL, dev, fpga_mgr_dev_match); + if (!mgr_dev) + return ERR_PTR(-ENODEV); + +- return __fpga_mgr_get(mgr_dev); ++ mgr = __fpga_mgr_get(mgr_dev); ++ if (IS_ERR(mgr)) ++ put_device(mgr_dev); ++ ++ return mgr; + } + EXPORT_SYMBOL_GPL(fpga_mgr_get); + +@@ -711,13 +713,18 @@ EXPORT_SYMBOL_GPL(fpga_mgr_get); + */ + struct fpga_manager *of_fpga_mgr_get(struct device_node *node) + { +- struct device *dev; ++ struct fpga_manager *mgr; ++ struct device *mgr_dev; + +- dev = class_find_device_by_of_node(&fpga_mgr_class, node); +- if (!dev) ++ mgr_dev = class_find_device_by_of_node(&fpga_mgr_class, node); ++ if (!mgr_dev) + return ERR_PTR(-ENODEV); + +- return __fpga_mgr_get(dev); ++ mgr = __fpga_mgr_get(mgr_dev); ++ if (IS_ERR(mgr)) ++ put_device(mgr_dev); ++ ++ return mgr; + } + EXPORT_SYMBOL_GPL(of_fpga_mgr_get); + +@@ -727,7 +734,7 @@ EXPORT_SYMBOL_GPL(of_fpga_mgr_get); + */ + void fpga_mgr_put(struct fpga_manager *mgr) + { +- module_put(mgr->dev.parent->driver->owner); ++ module_put(mgr->mops_owner); + put_device(&mgr->dev); + } + EXPORT_SYMBOL_GPL(fpga_mgr_put); +@@ -766,9 +773,10 @@ void fpga_mgr_unlock(struct fpga_manager *mgr) + EXPORT_SYMBOL_GPL(fpga_mgr_unlock); + + /** +- * fpga_mgr_register_full - create and register an FPGA Manager device ++ * __fpga_mgr_register_full - create and register an FPGA Manager device + * @parent: fpga manager device from pdev + * @info: parameters for fpga manager ++ * @owner: owner module containing the ops + * + * The caller of this function is responsible for calling fpga_mgr_unregister(). + * Using devm_fpga_mgr_register_full() instead is recommended. +@@ -776,7 +784,8 @@ EXPORT_SYMBOL_GPL(fpga_mgr_unlock); + * Return: pointer to struct fpga_manager pointer or ERR_PTR() + */ + struct fpga_manager * +-fpga_mgr_register_full(struct device *parent, const struct fpga_manager_info *info) ++__fpga_mgr_register_full(struct device *parent, const struct fpga_manager_info *info, ++ struct module *owner) + { + const struct fpga_manager_ops *mops = info->mops; + struct fpga_manager *mgr; +@@ -804,6 +813,8 @@ fpga_mgr_register_full(struct device *parent, const struct fpga_manager_info *in + + mutex_init(&mgr->ref_mutex); + ++ mgr->mops_owner = owner; ++ + mgr->name = info->name; + mgr->mops = info->mops; + mgr->priv = info->priv; +@@ -841,14 +852,15 @@ fpga_mgr_register_full(struct device *parent, const struct fpga_manager_info *in + + return ERR_PTR(ret); + } +-EXPORT_SYMBOL_GPL(fpga_mgr_register_full); ++EXPORT_SYMBOL_GPL(__fpga_mgr_register_full); + + /** +- * fpga_mgr_register - create and register an FPGA Manager device ++ * __fpga_mgr_register - create and register an FPGA Manager device + * @parent: fpga manager device from pdev + * @name: fpga manager name + * @mops: pointer to structure of fpga manager ops + * @priv: fpga manager private data ++ * @owner: owner module containing the ops + * + * The caller of this function is responsible for calling fpga_mgr_unregister(). + * Using devm_fpga_mgr_register() instead is recommended. This simple +@@ -859,8 +871,8 @@ EXPORT_SYMBOL_GPL(fpga_mgr_register_full); + * Return: pointer to struct fpga_manager pointer or ERR_PTR() + */ + struct fpga_manager * +-fpga_mgr_register(struct device *parent, const char *name, +- const struct fpga_manager_ops *mops, void *priv) ++__fpga_mgr_register(struct device *parent, const char *name, ++ const struct fpga_manager_ops *mops, void *priv, struct module *owner) + { + struct fpga_manager_info info = { 0 }; + +@@ -868,9 +880,9 @@ fpga_mgr_register(struct device *parent, const char *name, + info.mops = mops; + info.priv = priv; + +- return fpga_mgr_register_full(parent, &info); ++ return __fpga_mgr_register_full(parent, &info, owner); + } +-EXPORT_SYMBOL_GPL(fpga_mgr_register); ++EXPORT_SYMBOL_GPL(__fpga_mgr_register); + + /** + * fpga_mgr_unregister - unregister an FPGA manager +@@ -900,9 +912,10 @@ static void devm_fpga_mgr_unregister(struct device *dev, void *res) + } + + /** +- * devm_fpga_mgr_register_full - resource managed variant of fpga_mgr_register() ++ * __devm_fpga_mgr_register_full - resource managed variant of fpga_mgr_register() + * @parent: fpga manager device from pdev + * @info: parameters for fpga manager ++ * @owner: owner module containing the ops + * + * Return: fpga manager pointer on success, negative error code otherwise. + * +@@ -910,7 +923,8 @@ static void devm_fpga_mgr_unregister(struct device *dev, void *res) + * function will be called automatically when the managing device is detached. + */ + struct fpga_manager * +-devm_fpga_mgr_register_full(struct device *parent, const struct fpga_manager_info *info) ++__devm_fpga_mgr_register_full(struct device *parent, const struct fpga_manager_info *info, ++ struct module *owner) + { + struct fpga_mgr_devres *dr; + struct fpga_manager *mgr; +@@ -919,7 +933,7 @@ devm_fpga_mgr_register_full(struct device *parent, const struct fpga_manager_inf + if (!dr) + return ERR_PTR(-ENOMEM); + +- mgr = fpga_mgr_register_full(parent, info); ++ mgr = __fpga_mgr_register_full(parent, info, owner); + if (IS_ERR(mgr)) { + devres_free(dr); + return mgr; +@@ -930,14 +944,15 @@ devm_fpga_mgr_register_full(struct device *parent, const struct fpga_manager_inf + + return mgr; + } +-EXPORT_SYMBOL_GPL(devm_fpga_mgr_register_full); ++EXPORT_SYMBOL_GPL(__devm_fpga_mgr_register_full); + + /** +- * devm_fpga_mgr_register - resource managed variant of fpga_mgr_register() ++ * __devm_fpga_mgr_register - resource managed variant of fpga_mgr_register() + * @parent: fpga manager device from pdev + * @name: fpga manager name + * @mops: pointer to structure of fpga manager ops + * @priv: fpga manager private data ++ * @owner: owner module containing the ops + * + * Return: fpga manager pointer on success, negative error code otherwise. + * +@@ -946,8 +961,9 @@ EXPORT_SYMBOL_GPL(devm_fpga_mgr_register_full); + * device is detached. + */ + struct fpga_manager * +-devm_fpga_mgr_register(struct device *parent, const char *name, +- const struct fpga_manager_ops *mops, void *priv) ++__devm_fpga_mgr_register(struct device *parent, const char *name, ++ const struct fpga_manager_ops *mops, void *priv, ++ struct module *owner) + { + struct fpga_manager_info info = { 0 }; + +@@ -955,9 +971,9 @@ devm_fpga_mgr_register(struct device *parent, const char *name, + info.mops = mops; + info.priv = priv; + +- return devm_fpga_mgr_register_full(parent, &info); ++ return __devm_fpga_mgr_register_full(parent, &info, owner); + } +-EXPORT_SYMBOL_GPL(devm_fpga_mgr_register); ++EXPORT_SYMBOL_GPL(__devm_fpga_mgr_register); + + static void fpga_mgr_dev_release(struct device *dev) + { +diff --git a/drivers/fpga/fpga-region.c b/drivers/fpga/fpga-region.c +index b364a929425ce..753cd142503e0 100644 +--- a/drivers/fpga/fpga-region.c ++++ b/drivers/fpga/fpga-region.c +@@ -53,7 +53,7 @@ static struct fpga_region *fpga_region_get(struct fpga_region *region) + } + + get_device(dev); +- if (!try_module_get(dev->parent->driver->owner)) { ++ if (!try_module_get(region->ops_owner)) { + put_device(dev); + mutex_unlock(®ion->mutex); + return ERR_PTR(-ENODEV); +@@ -75,7 +75,7 @@ static void fpga_region_put(struct fpga_region *region) + + dev_dbg(dev, "put\n"); + +- module_put(dev->parent->driver->owner); ++ module_put(region->ops_owner); + put_device(dev); + mutex_unlock(®ion->mutex); + } +@@ -181,14 +181,16 @@ static struct attribute *fpga_region_attrs[] = { + ATTRIBUTE_GROUPS(fpga_region); + + /** +- * fpga_region_register_full - create and register an FPGA Region device ++ * __fpga_region_register_full - create and register an FPGA Region device + * @parent: device parent + * @info: parameters for FPGA Region ++ * @owner: module containing the get_bridges function + * + * Return: struct fpga_region or ERR_PTR() + */ + struct fpga_region * +-fpga_region_register_full(struct device *parent, const struct fpga_region_info *info) ++__fpga_region_register_full(struct device *parent, const struct fpga_region_info *info, ++ struct module *owner) + { + struct fpga_region *region; + int id, ret = 0; +@@ -213,6 +215,7 @@ fpga_region_register_full(struct device *parent, const struct fpga_region_info * + region->compat_id = info->compat_id; + region->priv = info->priv; + region->get_bridges = info->get_bridges; ++ region->ops_owner = owner; + + mutex_init(®ion->mutex); + INIT_LIST_HEAD(®ion->bridge_list); +@@ -241,13 +244,14 @@ fpga_region_register_full(struct device *parent, const struct fpga_region_info * + + return ERR_PTR(ret); + } +-EXPORT_SYMBOL_GPL(fpga_region_register_full); ++EXPORT_SYMBOL_GPL(__fpga_region_register_full); + + /** +- * fpga_region_register - create and register an FPGA Region device ++ * __fpga_region_register - create and register an FPGA Region device + * @parent: device parent + * @mgr: manager that programs this region + * @get_bridges: optional function to get bridges to a list ++ * @owner: module containing the get_bridges function + * + * This simple version of the register function should be sufficient for most users. + * The fpga_region_register_full() function is available for users that need to +@@ -256,17 +260,17 @@ EXPORT_SYMBOL_GPL(fpga_region_register_full); + * Return: struct fpga_region or ERR_PTR() + */ + struct fpga_region * +-fpga_region_register(struct device *parent, struct fpga_manager *mgr, +- int (*get_bridges)(struct fpga_region *)) ++__fpga_region_register(struct device *parent, struct fpga_manager *mgr, ++ int (*get_bridges)(struct fpga_region *), struct module *owner) + { + struct fpga_region_info info = { 0 }; + + info.mgr = mgr; + info.get_bridges = get_bridges; + +- return fpga_region_register_full(parent, &info); ++ return __fpga_region_register_full(parent, &info, owner); + } +-EXPORT_SYMBOL_GPL(fpga_region_register); ++EXPORT_SYMBOL_GPL(__fpga_region_register); + + /** + * fpga_region_unregister - unregister an FPGA region +diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c +index 4ab33d55aec47..b366b4ca4c40e 100644 +--- a/drivers/gpio/gpiolib-acpi.c ++++ b/drivers/gpio/gpiolib-acpi.c +@@ -128,7 +128,24 @@ static bool acpi_gpio_deferred_req_irqs_done; + + static int acpi_gpiochip_find(struct gpio_chip *gc, void *data) + { +- return device_match_acpi_handle(&gc->gpiodev->dev, data); ++ /* First check the actual GPIO device */ ++ if (device_match_acpi_handle(&gc->gpiodev->dev, data)) ++ return true; ++ ++ /* ++ * When the ACPI device is artificially split to the banks of GPIOs, ++ * where each of them is represented by a separate GPIO device, ++ * the firmware node of the physical device may not be shared among ++ * the banks as they may require different values for the same property, ++ * e.g., number of GPIOs in a certain bank. In such case the ACPI handle ++ * of a GPIO device is NULL and can not be used. Hence we have to check ++ * the parent device to be sure that there is no match before bailing ++ * out. ++ */ ++ if (gc->parent) ++ return device_match_acpi_handle(gc->parent, data); ++ ++ return false; + } + + /** +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c +index 15c5a2533ba60..704567885c7a4 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c +@@ -213,7 +213,7 @@ int amdgpu_amdkfd_reserve_mem_limit(struct amdgpu_device *adev, + (kfd_mem_limit.ttm_mem_used + ttm_mem_needed > + kfd_mem_limit.max_ttm_mem_limit) || + (adev && xcp_id >= 0 && adev->kfd.vram_used[xcp_id] + vram_needed > +- vram_size - reserved_for_pt)) { ++ vram_size - reserved_for_pt - atomic64_read(&adev->vram_pin_size))) { + ret = -ENOMEM; + goto release; + } +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c +index 15c67fa404ff9..c5c55e132af21 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c +@@ -1098,6 +1098,7 @@ void amdgpu_mes_remove_ring(struct amdgpu_device *adev, + return; + + amdgpu_mes_remove_hw_queue(adev, ring->hw_queue_id); ++ del_timer_sync(&ring->fence_drv.fallback_timer); + amdgpu_ring_fini(ring); + kfree(ring); + } +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c +index a348d320575e0..4e9ae52ef9fdb 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c +@@ -613,6 +613,8 @@ int amdgpu_bo_create(struct amdgpu_device *adev, + else + amdgpu_bo_placement_from_domain(bo, bp->domain); + if (bp->type == ttm_bo_type_kernel) ++ bo->tbo.priority = 2; ++ else if (!(bp->flags & AMDGPU_GEM_CREATE_DISCARDABLE)) + bo->tbo.priority = 1; + + if (!bp->destroy) +diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c +index 495eb4cad0e1a..3560a3f2c848e 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c +@@ -9157,7 +9157,7 @@ static const struct amdgpu_ring_funcs gfx_v10_0_ring_funcs_gfx = { + 7 + /* PIPELINE_SYNC */ + SOC15_FLUSH_GPU_TLB_NUM_WREG * 5 + + SOC15_FLUSH_GPU_TLB_NUM_REG_WAIT * 7 + +- 2 + /* VM_FLUSH */ ++ 4 + /* VM_FLUSH */ + 8 + /* FENCE for VM_FLUSH */ + 20 + /* GDS switch */ + 4 + /* double SWITCH_BUFFER, +@@ -9248,7 +9248,6 @@ static const struct amdgpu_ring_funcs gfx_v10_0_ring_funcs_kiq = { + 7 + /* gfx_v10_0_ring_emit_pipeline_sync */ + SOC15_FLUSH_GPU_TLB_NUM_WREG * 5 + + SOC15_FLUSH_GPU_TLB_NUM_REG_WAIT * 7 + +- 2 + /* gfx_v10_0_ring_emit_vm_flush */ + 8 + 8 + 8, /* gfx_v10_0_ring_emit_fence_kiq x3 for user fence, vm fence */ + .emit_ib_size = 7, /* gfx_v10_0_ring_emit_ib_compute */ + .emit_ib = gfx_v10_0_ring_emit_ib_compute, +diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c +index c9058d58c95a7..daab4c7a073ac 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c +@@ -6102,7 +6102,7 @@ static const struct amdgpu_ring_funcs gfx_v11_0_ring_funcs_gfx = { + 7 + /* PIPELINE_SYNC */ + SOC15_FLUSH_GPU_TLB_NUM_WREG * 5 + + SOC15_FLUSH_GPU_TLB_NUM_REG_WAIT * 7 + +- 2 + /* VM_FLUSH */ ++ 4 + /* VM_FLUSH */ + 8 + /* FENCE for VM_FLUSH */ + 20 + /* GDS switch */ + 5 + /* COND_EXEC */ +@@ -6187,7 +6187,6 @@ static const struct amdgpu_ring_funcs gfx_v11_0_ring_funcs_kiq = { + 7 + /* gfx_v11_0_ring_emit_pipeline_sync */ + SOC15_FLUSH_GPU_TLB_NUM_WREG * 5 + + SOC15_FLUSH_GPU_TLB_NUM_REG_WAIT * 7 + +- 2 + /* gfx_v11_0_ring_emit_vm_flush */ + 8 + 8 + 8, /* gfx_v11_0_ring_emit_fence_kiq x3 for user fence, vm fence */ + .emit_ib_size = 7, /* gfx_v11_0_ring_emit_ib_compute */ + .emit_ib = gfx_v11_0_ring_emit_ib_compute, +diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c +index d7d15b618c374..8168836a08d2e 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c +@@ -6988,7 +6988,6 @@ static const struct amdgpu_ring_funcs gfx_v9_0_ring_funcs_compute = { + 7 + /* gfx_v9_0_ring_emit_pipeline_sync */ + SOC15_FLUSH_GPU_TLB_NUM_WREG * 5 + + SOC15_FLUSH_GPU_TLB_NUM_REG_WAIT * 7 + +- 2 + /* gfx_v9_0_ring_emit_vm_flush */ + 8 + 8 + 8 + /* gfx_v9_0_ring_emit_fence x3 for user fence, vm fence */ + 7 + /* gfx_v9_0_emit_mem_sync */ + 5 + /* gfx_v9_0_emit_wave_limit for updating mmSPI_WCL_PIPE_PERCENT_GFX register */ +@@ -7026,7 +7025,6 @@ static const struct amdgpu_ring_funcs gfx_v9_0_ring_funcs_kiq = { + 7 + /* gfx_v9_0_ring_emit_pipeline_sync */ + SOC15_FLUSH_GPU_TLB_NUM_WREG * 5 + + SOC15_FLUSH_GPU_TLB_NUM_REG_WAIT * 7 + +- 2 + /* gfx_v9_0_ring_emit_vm_flush */ + 8 + 8 + 8, /* gfx_v9_0_ring_emit_fence_kiq x3 for user fence, vm fence */ + .emit_ib_size = 7, /* gfx_v9_0_ring_emit_ib_compute */ + .emit_fence = gfx_v9_0_ring_emit_fence_kiq, +diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c +index e481ef73af6e5..af46823e43367 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c ++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c +@@ -425,16 +425,16 @@ static int gfx_v9_4_3_init_cp_compute_microcode(struct amdgpu_device *adev, + + static int gfx_v9_4_3_init_microcode(struct amdgpu_device *adev) + { +- const char *chip_name; ++ char ucode_prefix[15]; + int r; + +- chip_name = "gc_9_4_3"; ++ amdgpu_ucode_ip_version_decode(adev, GC_HWIP, ucode_prefix, sizeof(ucode_prefix)); + +- r = gfx_v9_4_3_init_rlc_microcode(adev, chip_name); ++ r = gfx_v9_4_3_init_rlc_microcode(adev, ucode_prefix); + if (r) + return r; + +- r = gfx_v9_4_3_init_cp_compute_microcode(adev, chip_name); ++ r = gfx_v9_4_3_init_cp_compute_microcode(adev, ucode_prefix); + if (r) + return r; + +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c +index 659313648b200..3263b5fa182d2 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c +@@ -516,10 +516,19 @@ svm_migrate_ram_to_vram(struct svm_range *prange, uint32_t best_loc, + start = prange->start << PAGE_SHIFT; + end = (prange->last + 1) << PAGE_SHIFT; + ++ r = amdgpu_amdkfd_reserve_mem_limit(node->adev, ++ prange->npages * PAGE_SIZE, ++ KFD_IOC_ALLOC_MEM_FLAGS_VRAM, ++ node->xcp ? node->xcp->id : 0); ++ if (r) { ++ dev_dbg(node->adev->dev, "failed to reserve VRAM, r: %ld\n", r); ++ return -ENOSPC; ++ } ++ + r = svm_range_vram_node_new(node, prange, true); + if (r) { + dev_dbg(node->adev->dev, "fail %ld to alloc vram\n", r); +- return r; ++ goto out; + } + ttm_res_offset = prange->offset << PAGE_SHIFT; + +@@ -549,6 +558,11 @@ svm_migrate_ram_to_vram(struct svm_range *prange, uint32_t best_loc, + svm_range_vram_node_free(prange); + } + ++out: ++ amdgpu_amdkfd_unreserve_mem_limit(node->adev, ++ prange->npages * PAGE_SIZE, ++ KFD_IOC_ALLOC_MEM_FLAGS_VRAM, ++ node->xcp ? node->xcp->id : 0); + return r < 0 ? r : 0; + } + +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process.c b/drivers/gpu/drm/amd/amdkfd/kfd_process.c +index 7a1a574106fac..d98e45aec76b4 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_process.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_process.c +@@ -828,6 +828,14 @@ struct kfd_process *kfd_create_process(struct task_struct *thread) + if (process) { + pr_debug("Process already found\n"); + } else { ++ /* If the process just called exec(3), it is possible that the ++ * cleanup of the kfd_process (following the release of the mm ++ * of the old process image) is still in the cleanup work queue. ++ * Make sure to drain any job before trying to recreate any ++ * resource for this process. ++ */ ++ flush_workqueue(kfd_process_wq); ++ + process = create_process(thread); + if (IS_ERR(process)) + goto out; +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c +index 87e9ca65e58e0..ce76d45549984 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c +@@ -3416,7 +3416,7 @@ svm_range_trigger_migration(struct mm_struct *mm, struct svm_range *prange, + r = svm_migrate_to_vram(prange, best_loc, mm, KFD_MIGRATE_TRIGGER_PREFETCH); + *migrated = !r; + +- return r; ++ return 0; + } + + int svm_range_schedule_evict_svm_bo(struct amdgpu_amdkfd_fence *fence) +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 98dd07e3726af..7ed6bb61fe0ad 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +@@ -2956,6 +2956,7 @@ static int dm_resume(void *handle) + dc_stream_release(dm_new_crtc_state->stream); + dm_new_crtc_state->stream = NULL; + } ++ dm_new_crtc_state->base.color_mgmt_changed = true; + } + + for_each_new_plane_in_state(dm->cached_state, plane, new_plane_state, i) { +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c +index 10dd4cd6f59c9..2104511f3b863 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c +@@ -606,6 +606,9 @@ dm_dp_add_mst_connector(struct drm_dp_mst_topology_mgr *mgr, + &connector->base, + dev->mode_config.tile_property, + 0); ++ connector->colorspace_property = master->base.colorspace_property; ++ if (connector->colorspace_property) ++ drm_connector_attach_colorspace_property(connector); + + drm_connector_set_path_property(connector, pathprop); + +diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_clk_mgr.c +index 8776055bbeaae..d4d3f58a613f7 100644 +--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_clk_mgr.c ++++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_clk_mgr.c +@@ -145,6 +145,10 @@ static void dcn315_update_clocks(struct clk_mgr *clk_mgr_base, + */ + clk_mgr_base->clks.zstate_support = new_clocks->zstate_support; + if (safe_to_lower) { ++ if (clk_mgr_base->clks.dtbclk_en && !new_clocks->dtbclk_en) { ++ dcn315_smu_set_dtbclk(clk_mgr, false); ++ clk_mgr_base->clks.dtbclk_en = new_clocks->dtbclk_en; ++ } + /* check that we're not already in lower */ + if (clk_mgr_base->clks.pwr_state != DCN_PWR_STATE_LOW_POWER) { + display_count = dcn315_get_active_display_cnt_wa(dc, context); +@@ -160,6 +164,10 @@ static void dcn315_update_clocks(struct clk_mgr *clk_mgr_base, + } + } + } else { ++ if (!clk_mgr_base->clks.dtbclk_en && new_clocks->dtbclk_en) { ++ dcn315_smu_set_dtbclk(clk_mgr, true); ++ clk_mgr_base->clks.dtbclk_en = new_clocks->dtbclk_en; ++ } + /* check that we're not already in D0 */ + if (clk_mgr_base->clks.pwr_state != DCN_PWR_STATE_MISSION_MODE) { + union display_idle_optimization_u idle_info = { 0 }; +diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c +index e9345f6554dbc..2428a4763b85f 100644 +--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c ++++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c +@@ -547,8 +547,12 @@ static void dcn32_update_clocks(struct clk_mgr *clk_mgr_base, + * since we calculate mode support based on softmax being the max UCLK + * frequency. + */ +- dcn32_smu_set_hard_min_by_freq(clk_mgr, PPCLK_UCLK, +- dc->clk_mgr->bw_params->dc_mode_softmax_memclk); ++ if (dc->debug.disable_dc_mode_overwrite) { ++ dcn30_smu_set_hard_max_by_freq(clk_mgr, PPCLK_UCLK, dc->clk_mgr->bw_params->max_memclk_mhz); ++ dcn32_smu_set_hard_min_by_freq(clk_mgr, PPCLK_UCLK, dc->clk_mgr->bw_params->max_memclk_mhz); ++ } else ++ dcn32_smu_set_hard_min_by_freq(clk_mgr, PPCLK_UCLK, ++ dc->clk_mgr->bw_params->dc_mode_softmax_memclk); + } else { + dcn32_smu_set_hard_min_by_freq(clk_mgr, PPCLK_UCLK, dc->clk_mgr->bw_params->max_memclk_mhz); + } +@@ -581,8 +585,13 @@ static void dcn32_update_clocks(struct clk_mgr *clk_mgr_base, + /* set UCLK to requested value if P-State switching is supported, or to re-enable P-State switching */ + if (clk_mgr_base->clks.p_state_change_support && + (update_uclk || !clk_mgr_base->clks.prev_p_state_change_support) && +- !dc->work_arounds.clock_update_disable_mask.uclk) ++ !dc->work_arounds.clock_update_disable_mask.uclk) { ++ if (dc->clk_mgr->dc_mode_softmax_enabled && dc->debug.disable_dc_mode_overwrite) ++ dcn30_smu_set_hard_max_by_freq(clk_mgr, PPCLK_UCLK, ++ max((int)dc->clk_mgr->bw_params->dc_mode_softmax_memclk, khz_to_mhz_ceil(clk_mgr_base->clks.dramclk_khz))); ++ + dcn32_smu_set_hard_min_by_freq(clk_mgr, PPCLK_UCLK, khz_to_mhz_ceil(clk_mgr_base->clks.dramclk_khz)); ++ } + + if (clk_mgr_base->clks.num_ways != new_clocks->num_ways && + clk_mgr_base->clks.num_ways > new_clocks->num_ways) { +diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c +index 46b10ff8f6d41..72db370e2f21f 100644 +--- a/drivers/gpu/drm/amd/display/dc/core/dc.c ++++ b/drivers/gpu/drm/amd/display/dc/core/dc.c +@@ -1710,6 +1710,9 @@ bool dc_validate_boot_timing(const struct dc *dc, + return false; + } + ++ if (link->dpcd_caps.channel_coding_cap.bits.DP_128b_132b_SUPPORTED) ++ return false; ++ + if (dc->link_srv->edp_is_ilr_optimization_required(link, crtc_timing)) { + DC_LOG_EVENT_LINK_TRAINING("Seamless boot disabled to optimize eDP link rate\n"); + return false; +diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c +index 3538973bd0c6c..c0372aa4ec838 100644 +--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c ++++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c +@@ -382,6 +382,11 @@ bool cm_helper_translate_curve_to_hw_format(struct dc_context *ctx, + i += increment) { + if (j == hw_points - 1) + break; ++ if (i >= TRANSFER_FUNC_POINTS) { ++ DC_LOG_ERROR("Index out of bounds: i=%d, TRANSFER_FUNC_POINTS=%d\n", ++ i, TRANSFER_FUNC_POINTS); ++ return false; ++ } + rgb_resulted[j].red = output_tf->tf_pts.red[i]; + rgb_resulted[j].green = output_tf->tf_pts.green[i]; + rgb_resulted[j].blue = output_tf->tf_pts.blue[i]; +diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn31/dcn31_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn31/dcn31_fpu.c +index deb6d162a2d5c..7307b7b8d8ad7 100644 +--- a/drivers/gpu/drm/amd/display/dc/dml/dcn31/dcn31_fpu.c ++++ b/drivers/gpu/drm/amd/display/dc/dml/dcn31/dcn31_fpu.c +@@ -291,6 +291,7 @@ static struct _vcs_dpi_soc_bounding_box_st dcn3_15_soc = { + .do_urgent_latency_adjustment = false, + .urgent_latency_adjustment_fabric_clock_component_us = 0, + .urgent_latency_adjustment_fabric_clock_reference_mhz = 0, ++ .dispclk_dppclk_vco_speed_mhz = 2400.0, + .num_chans = 4, + .dummy_pstate_latency_us = 10.0 + }; +@@ -438,6 +439,7 @@ static struct _vcs_dpi_soc_bounding_box_st dcn3_16_soc = { + .do_urgent_latency_adjustment = false, + .urgent_latency_adjustment_fabric_clock_component_us = 0, + .urgent_latency_adjustment_fabric_clock_reference_mhz = 0, ++ .dispclk_dppclk_vco_speed_mhz = 2500.0, + }; + + void dcn31_zero_pipe_dcc_fraction(display_e2e_pipe_params_st *pipes, +diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_dpia_bw.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_dpia_bw.c +index 5491b707cec88..5a965c26bf209 100644 +--- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_dpia_bw.c ++++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_dpia_bw.c +@@ -270,7 +270,7 @@ static void set_usb4_req_bw_req(struct dc_link *link, int req_bw) + + /* Error check whether requested and allocated are equal */ + req_bw = requested_bw * (Kbps_TO_Gbps / link->dpia_bw_alloc_config.bw_granularity); +- if (req_bw == link->dpia_bw_alloc_config.allocated_bw) { ++ if (req_bw && (req_bw == link->dpia_bw_alloc_config.allocated_bw)) { + DC_LOG_ERROR("%s: Request bw equals to allocated bw for link(%d)\n", + __func__, link->link_index); + } +@@ -341,6 +341,14 @@ bool link_dp_dpia_set_dptx_usb4_bw_alloc_support(struct dc_link *link) + ret = true; + init_usb4_bw_struct(link); + link->dpia_bw_alloc_config.bw_alloc_enabled = true; ++ ++ /* ++ * During DP tunnel creation, CM preallocates BW and reduces estimated BW of other ++ * DPIA. CM release preallocation only when allocation is complete. Do zero alloc ++ * to make the CM to release preallocation and update estimated BW correctly for ++ * all DPIAs per host router ++ */ ++ link_dp_dpia_allocate_usb4_bandwidth_for_stream(link, 0); + } + } + +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 6a28f8d5bff7d..be4b7b64f8785 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 +@@ -2039,6 +2039,17 @@ static ssize_t smu_v13_0_6_get_gpu_metrics(struct smu_context *smu, void **table + return sizeof(struct gpu_metrics_v1_3); + } + ++static void smu_v13_0_6_restore_pci_config(struct smu_context *smu) ++{ ++ struct amdgpu_device *adev = smu->adev; ++ int i; ++ ++ for (i = 0; i < 16; i++) ++ pci_write_config_dword(adev->pdev, i * 4, ++ adev->pdev->saved_config_space[i]); ++ pci_restore_msi_state(adev->pdev); ++} ++ + static int smu_v13_0_6_mode2_reset(struct smu_context *smu) + { + int ret = 0, index; +@@ -2060,6 +2071,20 @@ static int smu_v13_0_6_mode2_reset(struct smu_context *smu) + /* Restore the config space saved during init */ + amdgpu_device_load_pci_state(adev->pdev); + ++ /* Certain platforms have switches which assign virtual BAR values to ++ * devices. OS uses the virtual BAR values and device behind the switch ++ * is assgined another BAR value. When device's config space registers ++ * are queried, switch returns the virtual BAR values. When mode-2 reset ++ * is performed, switch is unaware of it, and will continue to return ++ * the same virtual values to the OS.This affects ++ * pci_restore_config_space() API as it doesn't write the value saved if ++ * the current value read from config space is the same as what is ++ * saved. As a workaround, make sure the config space is restored ++ * always. ++ */ ++ if (!(adev->flags & AMD_IS_APU)) ++ smu_v13_0_6_restore_pci_config(smu); ++ + dev_dbg(smu->adev->dev, "wait for reset ack\n"); + do { + ret = smu_cmn_wait_for_response(smu); +diff --git a/drivers/gpu/drm/arm/malidp_mw.c b/drivers/gpu/drm/arm/malidp_mw.c +index 626709bec6f5f..2577f0cef8fcd 100644 +--- a/drivers/gpu/drm/arm/malidp_mw.c ++++ b/drivers/gpu/drm/arm/malidp_mw.c +@@ -72,7 +72,10 @@ static void malidp_mw_connector_reset(struct drm_connector *connector) + __drm_atomic_helper_connector_destroy_state(connector->state); + + kfree(connector->state); +- __drm_atomic_helper_connector_reset(connector, &mw_state->base); ++ connector->state = NULL; ++ ++ if (mw_state) ++ __drm_atomic_helper_connector_reset(connector, &mw_state->base); + } + + static enum drm_connector_status +diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.c b/drivers/gpu/drm/bridge/analogix/anx7625.c +index 29d91493b101a..c1191ef5e8e67 100644 +--- a/drivers/gpu/drm/bridge/analogix/anx7625.c ++++ b/drivers/gpu/drm/bridge/analogix/anx7625.c +@@ -2076,10 +2076,8 @@ static int anx7625_setup_dsi_device(struct anx7625_data *ctx) + }; + + host = of_find_mipi_dsi_host_by_node(ctx->pdata.mipi_host_node); +- if (!host) { +- DRM_DEV_ERROR(dev, "fail to find dsi host.\n"); +- return -EPROBE_DEFER; +- } ++ if (!host) ++ return dev_err_probe(dev, -EPROBE_DEFER, "fail to find dsi host.\n"); + + dsi = devm_mipi_dsi_device_register_full(dev, host, &info); + if (IS_ERR(dsi)) { +@@ -2481,15 +2479,22 @@ static void anx7625_bridge_atomic_disable(struct drm_bridge *bridge, + mutex_unlock(&ctx->aux_lock); + } + ++static void ++anx7625_audio_update_connector_status(struct anx7625_data *ctx, ++ enum drm_connector_status status); ++ + static enum drm_connector_status + anx7625_bridge_detect(struct drm_bridge *bridge) + { + struct anx7625_data *ctx = bridge_to_anx7625(bridge); + struct device *dev = ctx->dev; ++ enum drm_connector_status status; + + DRM_DEV_DEBUG_DRIVER(dev, "drm bridge detect\n"); + +- return anx7625_sink_detect(ctx); ++ status = anx7625_sink_detect(ctx); ++ anx7625_audio_update_connector_status(ctx, status); ++ return status; + } + + static struct edid *anx7625_bridge_get_edid(struct drm_bridge *bridge, +diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c +index 6af565ac307ae..858f5b6508491 100644 +--- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c ++++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c +@@ -2057,6 +2057,9 @@ static void cdns_mhdp_atomic_enable(struct drm_bridge *bridge, + mhdp_state = to_cdns_mhdp_bridge_state(new_state); + + mhdp_state->current_mode = drm_mode_duplicate(bridge->dev, mode); ++ if (!mhdp_state->current_mode) ++ return; ++ + drm_mode_set_name(mhdp_state->current_mode); + + dev_dbg(mhdp->dev, "%s: Enabling mode %s\n", __func__, mode->name); +diff --git a/drivers/gpu/drm/bridge/chipone-icn6211.c b/drivers/gpu/drm/bridge/chipone-icn6211.c +index d205e755e524a..5e295f86f2a73 100644 +--- a/drivers/gpu/drm/bridge/chipone-icn6211.c ++++ b/drivers/gpu/drm/bridge/chipone-icn6211.c +@@ -563,10 +563,8 @@ static int chipone_dsi_host_attach(struct chipone *icn) + + host = of_find_mipi_dsi_host_by_node(host_node); + of_node_put(host_node); +- if (!host) { +- dev_err(dev, "failed to find dsi host\n"); +- return -EPROBE_DEFER; +- } ++ if (!host) ++ return dev_err_probe(dev, -EPROBE_DEFER, "failed to find dsi host\n"); + + dsi = mipi_dsi_device_register_full(host, &info); + if (IS_ERR(dsi)) { +diff --git a/drivers/gpu/drm/bridge/lontium-lt8912b.c b/drivers/gpu/drm/bridge/lontium-lt8912b.c +index e5839c89a355a..0efcbc73f2a43 100644 +--- a/drivers/gpu/drm/bridge/lontium-lt8912b.c ++++ b/drivers/gpu/drm/bridge/lontium-lt8912b.c +@@ -483,10 +483,8 @@ static int lt8912_attach_dsi(struct lt8912 *lt) + }; + + host = of_find_mipi_dsi_host_by_node(lt->host_node); +- if (!host) { +- dev_err(dev, "failed to find dsi host\n"); +- return -EPROBE_DEFER; +- } ++ if (!host) ++ return dev_err_probe(dev, -EPROBE_DEFER, "failed to find dsi host\n"); + + dsi = devm_mipi_dsi_device_register_full(dev, host, &info); + if (IS_ERR(dsi)) { +diff --git a/drivers/gpu/drm/bridge/lontium-lt9611.c b/drivers/gpu/drm/bridge/lontium-lt9611.c +index 9663601ce0981..89bdd938757e1 100644 +--- a/drivers/gpu/drm/bridge/lontium-lt9611.c ++++ b/drivers/gpu/drm/bridge/lontium-lt9611.c +@@ -760,10 +760,8 @@ static struct mipi_dsi_device *lt9611_attach_dsi(struct lt9611 *lt9611, + int ret; + + host = of_find_mipi_dsi_host_by_node(dsi_node); +- if (!host) { +- dev_err(lt9611->dev, "failed to find dsi host\n"); +- return ERR_PTR(-EPROBE_DEFER); +- } ++ if (!host) ++ return ERR_PTR(dev_err_probe(lt9611->dev, -EPROBE_DEFER, "failed to find dsi host\n")); + + dsi = devm_mipi_dsi_device_register_full(dev, host, &info); + if (IS_ERR(dsi)) { +diff --git a/drivers/gpu/drm/bridge/lontium-lt9611uxc.c b/drivers/gpu/drm/bridge/lontium-lt9611uxc.c +index 6f33bb0dd32aa..c41ffd0bc0494 100644 +--- a/drivers/gpu/drm/bridge/lontium-lt9611uxc.c ++++ b/drivers/gpu/drm/bridge/lontium-lt9611uxc.c +@@ -265,10 +265,8 @@ static struct mipi_dsi_device *lt9611uxc_attach_dsi(struct lt9611uxc *lt9611uxc, + int ret; + + host = of_find_mipi_dsi_host_by_node(dsi_node); +- if (!host) { +- dev_err(dev, "failed to find dsi host\n"); +- return ERR_PTR(-EPROBE_DEFER); +- } ++ if (!host) ++ return ERR_PTR(dev_err_probe(dev, -EPROBE_DEFER, "failed to find dsi host\n")); + + dsi = devm_mipi_dsi_device_register_full(dev, host, &info); + if (IS_ERR(dsi)) { +diff --git a/drivers/gpu/drm/bridge/tc358775.c b/drivers/gpu/drm/bridge/tc358775.c +index 90a89d70d8328..c737670631929 100644 +--- a/drivers/gpu/drm/bridge/tc358775.c ++++ b/drivers/gpu/drm/bridge/tc358775.c +@@ -454,10 +454,6 @@ static void tc_bridge_enable(struct drm_bridge *bridge) + dev_dbg(tc->dev, "bus_formats %04x bpc %d\n", + connector->display_info.bus_formats[0], + tc->bpc); +- /* +- * Default hardware register settings of tc358775 configured +- * with MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA jeida-24 format +- */ + if (connector->display_info.bus_formats[0] == + MEDIA_BUS_FMT_RGB888_1X7X4_SPWG) { + /* VESA-24 */ +@@ -468,14 +464,15 @@ static void tc_bridge_enable(struct drm_bridge *bridge) + d2l_write(tc->i2c, LV_MX1619, LV_MX(LVI_B6, LVI_B7, LVI_B1, LVI_B2)); + d2l_write(tc->i2c, LV_MX2023, LV_MX(LVI_B3, LVI_B4, LVI_B5, LVI_L0)); + d2l_write(tc->i2c, LV_MX2427, LV_MX(LVI_HS, LVI_VS, LVI_DE, LVI_R6)); +- } else { /* MEDIA_BUS_FMT_RGB666_1X7X3_SPWG - JEIDA-18 */ +- d2l_write(tc->i2c, LV_MX0003, LV_MX(LVI_R0, LVI_R1, LVI_R2, LVI_R3)); +- d2l_write(tc->i2c, LV_MX0407, LV_MX(LVI_R4, LVI_L0, LVI_R5, LVI_G0)); +- d2l_write(tc->i2c, LV_MX0811, LV_MX(LVI_G1, LVI_G2, LVI_L0, LVI_L0)); +- d2l_write(tc->i2c, LV_MX1215, LV_MX(LVI_G3, LVI_G4, LVI_G5, LVI_B0)); +- d2l_write(tc->i2c, LV_MX1619, LV_MX(LVI_L0, LVI_L0, LVI_B1, LVI_B2)); +- d2l_write(tc->i2c, LV_MX2023, LV_MX(LVI_B3, LVI_B4, LVI_B5, LVI_L0)); +- d2l_write(tc->i2c, LV_MX2427, LV_MX(LVI_HS, LVI_VS, LVI_DE, LVI_L0)); ++ } else { ++ /* JEIDA-18 and JEIDA-24 */ ++ d2l_write(tc->i2c, LV_MX0003, LV_MX(LVI_R2, LVI_R3, LVI_R4, LVI_R5)); ++ d2l_write(tc->i2c, LV_MX0407, LV_MX(LVI_R6, LVI_R1, LVI_R7, LVI_G2)); ++ d2l_write(tc->i2c, LV_MX0811, LV_MX(LVI_G3, LVI_G4, LVI_G0, LVI_G1)); ++ d2l_write(tc->i2c, LV_MX1215, LV_MX(LVI_G5, LVI_G6, LVI_G7, LVI_B2)); ++ d2l_write(tc->i2c, LV_MX1619, LV_MX(LVI_B0, LVI_B1, LVI_B3, LVI_B4)); ++ d2l_write(tc->i2c, LV_MX2023, LV_MX(LVI_B5, LVI_B6, LVI_B7, LVI_L0)); ++ d2l_write(tc->i2c, LV_MX2427, LV_MX(LVI_HS, LVI_VS, LVI_DE, LVI_R0)); + } + + d2l_write(tc->i2c, VFUEN, VFUEN_EN); +@@ -610,10 +607,8 @@ static int tc_attach_host(struct tc_data *tc) + }; + + host = of_find_mipi_dsi_host_by_node(tc->host_node); +- if (!host) { +- dev_err(dev, "failed to find dsi host\n"); +- return -EPROBE_DEFER; +- } ++ if (!host) ++ return dev_err_probe(dev, -EPROBE_DEFER, "failed to find dsi host\n"); + + dsi = devm_mipi_dsi_device_register_full(dev, host, &info); + if (IS_ERR(dsi)) { +diff --git a/drivers/gpu/drm/bridge/ti-dlpc3433.c b/drivers/gpu/drm/bridge/ti-dlpc3433.c +index b65632ec7e7da..3f933ba294682 100644 +--- a/drivers/gpu/drm/bridge/ti-dlpc3433.c ++++ b/drivers/gpu/drm/bridge/ti-dlpc3433.c +@@ -319,12 +319,11 @@ static int dlpc_host_attach(struct dlpc *dlpc) + .channel = 0, + .node = NULL, + }; ++ int ret; + + host = of_find_mipi_dsi_host_by_node(dlpc->host_node); +- if (!host) { +- DRM_DEV_ERROR(dev, "failed to find dsi host\n"); +- return -EPROBE_DEFER; +- } ++ if (!host) ++ return dev_err_probe(dev, -EPROBE_DEFER, "failed to find dsi host\n"); + + dlpc->dsi = mipi_dsi_device_register_full(host, &info); + if (IS_ERR(dlpc->dsi)) { +@@ -336,7 +335,11 @@ static int dlpc_host_attach(struct dlpc *dlpc) + dlpc->dsi->format = MIPI_DSI_FMT_RGB565; + dlpc->dsi->lanes = dlpc->dsi_lanes; + +- return devm_mipi_dsi_attach(dev, dlpc->dsi); ++ ret = devm_mipi_dsi_attach(dev, dlpc->dsi); ++ if (ret) ++ DRM_DEV_ERROR(dev, "failed to attach dsi host\n"); ++ ++ return ret; + } + + static int dlpc3433_probe(struct i2c_client *client) +@@ -367,10 +370,8 @@ static int dlpc3433_probe(struct i2c_client *client) + drm_bridge_add(&dlpc->bridge); + + ret = dlpc_host_attach(dlpc); +- if (ret) { +- DRM_DEV_ERROR(dev, "failed to attach dsi host\n"); ++ if (ret) + goto err_remove_bridge; +- } + + return 0; + +diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi83.c b/drivers/gpu/drm/bridge/ti-sn65dsi83.c +index 061e8bd5915de..8a23116346a8a 100644 +--- a/drivers/gpu/drm/bridge/ti-sn65dsi83.c ++++ b/drivers/gpu/drm/bridge/ti-sn65dsi83.c +@@ -478,7 +478,6 @@ static void sn65dsi83_atomic_pre_enable(struct drm_bridge *bridge, + dev_err(ctx->dev, "failed to lock PLL, ret=%i\n", ret); + /* On failure, disable PLL again and exit. */ + regmap_write(ctx->regmap, REG_RC_PLL_EN, 0x00); +- regulator_disable(ctx->vcc); + return; + } + +diff --git a/drivers/gpu/drm/ci/build.yml b/drivers/gpu/drm/ci/build.yml +index e6503f1c5927b..17ab38304885c 100644 +--- a/drivers/gpu/drm/ci/build.yml ++++ b/drivers/gpu/drm/ci/build.yml +@@ -1,6 +1,7 @@ + .build: + extends: + - .build-rules ++ - .container+build-rules + stage: build + artifacts: + paths: +diff --git a/drivers/gpu/drm/ci/gitlab-ci.yml b/drivers/gpu/drm/ci/gitlab-ci.yml +index 2c4df53f5dfe3..3694924367480 100644 +--- a/drivers/gpu/drm/ci/gitlab-ci.yml ++++ b/drivers/gpu/drm/ci/gitlab-ci.yml +@@ -1,6 +1,6 @@ + variables: + DRM_CI_PROJECT_PATH: &drm-ci-project-path mesa/mesa +- DRM_CI_COMMIT_SHA: &drm-ci-commit-sha 0dc961645c4f0241f8512cb0ec3ad59635842072 ++ DRM_CI_COMMIT_SHA: &drm-ci-commit-sha edfbf74df1d4d6ce54ffe24566108be0e1a98c3d + + UPSTREAM_REPO: git://anongit.freedesktop.org/drm/drm + TARGET_BRANCH: drm-next +@@ -24,7 +24,9 @@ variables: + PIPELINE_ARTIFACTS_BASE: ${S3_HOST}/artifacts/${CI_PROJECT_PATH}/${CI_PIPELINE_ID} + # per-job artifact storage on MinIO + JOB_ARTIFACTS_BASE: ${PIPELINE_ARTIFACTS_BASE}/${CI_JOB_ID} +- ++ # default kernel for rootfs before injecting the current kernel tree ++ KERNEL_IMAGE_BASE: https://${S3_HOST}/mesa-lava/gfx-ci/linux/v6.4.12-for-mesa-ci-f6b4ad45f48d ++ LAVA_TAGS: subset-1-gfx + LAVA_JOB_PRIORITY: 30 + + default: +@@ -86,6 +88,17 @@ include: + - '/.gitlab-ci/container/gitlab-ci.yml' + - '/.gitlab-ci/test/gitlab-ci.yml' + - '/.gitlab-ci/lava/lava-gitlab-ci.yml' ++ - '/src/microsoft/ci/gitlab-ci-inc.yml' ++ - '/src/gallium/drivers/zink/ci/gitlab-ci-inc.yml' ++ - '/src/gallium/drivers/crocus/ci/gitlab-ci-inc.yml' ++ - '/src/gallium/drivers/softpipe/ci/gitlab-ci-inc.yml' ++ - '/src/gallium/drivers/llvmpipe/ci/gitlab-ci-inc.yml' ++ - '/src/gallium/drivers/virgl/ci/gitlab-ci-inc.yml' ++ - '/src/gallium/drivers/nouveau/ci/gitlab-ci-inc.yml' ++ - '/src/gallium/frontends/lavapipe/ci/gitlab-ci-inc.yml' ++ - '/src/intel/ci/gitlab-ci-inc.yml' ++ - '/src/freedreno/ci/gitlab-ci-inc.yml' ++ - '/src/amd/ci/gitlab-ci-inc.yml' + - drivers/gpu/drm/ci/image-tags.yml + - drivers/gpu/drm/ci/container.yml + - drivers/gpu/drm/ci/static-checks.yml +@@ -154,6 +167,11 @@ stages: + # Run automatically once all dependency jobs have passed + - when: on_success + ++# When to automatically run the CI for container jobs ++.container+build-rules: ++ rules: ++ - !reference [.no_scheduled_pipelines-rules, rules] ++ - when: manual + + .ci-deqp-artifacts: + artifacts: +diff --git a/drivers/gpu/drm/ci/image-tags.yml b/drivers/gpu/drm/ci/image-tags.yml +index f051b6c547c53..157d987149f07 100644 +--- a/drivers/gpu/drm/ci/image-tags.yml ++++ b/drivers/gpu/drm/ci/image-tags.yml +@@ -1,5 +1,5 @@ + variables: +- CONTAINER_TAG: "2023-08-10-mesa-uprev" ++ CONTAINER_TAG: "2023-10-11-mesa-uprev" + DEBIAN_X86_64_BUILD_BASE_IMAGE: "debian/x86_64_build-base" + DEBIAN_BASE_TAG: "${CONTAINER_TAG}" + +diff --git a/drivers/gpu/drm/ci/lava-submit.sh b/drivers/gpu/drm/ci/lava-submit.sh +index 0c4456b21b0fc..379f26ea87cc0 100755 +--- a/drivers/gpu/drm/ci/lava-submit.sh ++++ b/drivers/gpu/drm/ci/lava-submit.sh +@@ -22,7 +22,7 @@ cp "$SCRIPTS_DIR"/setup-test-env.sh results/job-rootfs-overlay/ + + # Prepare env vars for upload. + section_start variables "Variables passed through:" +-KERNEL_IMAGE_BASE_URL="https://${BASE_SYSTEM_HOST_PATH}" \ ++KERNEL_IMAGE_BASE="https://${BASE_SYSTEM_HOST_PATH}" \ + artifacts/ci-common/generate-env.sh | tee results/job-rootfs-overlay/set-job-env-vars.sh + section_end variables + +diff --git a/drivers/gpu/drm/ci/test.yml b/drivers/gpu/drm/ci/test.yml +index e5b7d309ca186..6f81dc10865b5 100644 +--- a/drivers/gpu/drm/ci/test.yml ++++ b/drivers/gpu/drm/ci/test.yml +@@ -86,7 +86,7 @@ msm:sc7180: + extends: + - .lava-igt:arm64 + stage: msm +- parallel: 2 ++ parallel: 4 + variables: + DRIVER_NAME: msm + DEVICE_TYPE: sc7180-trogdor-lazor-limozeen +@@ -158,7 +158,7 @@ rockchip:rk3399: + extends: + - .lava-igt:arm64 + stage: rockchip +- parallel: 3 ++ parallel: 2 + variables: + DRIVER_NAME: rockchip + DEVICE_TYPE: rk3399-gru-kevin +@@ -181,7 +181,7 @@ rockchip:rk3399: + i915:apl: + extends: + - .i915 +- parallel: 12 ++ parallel: 3 + variables: + DEVICE_TYPE: asus-C523NA-A20057-coral + GPU_VERSION: apl +@@ -190,7 +190,7 @@ i915:apl: + i915:glk: + extends: + - .i915 +- parallel: 5 ++ parallel: 2 + variables: + DEVICE_TYPE: hp-x360-12b-ca0010nr-n4020-octopus + GPU_VERSION: glk +@@ -199,7 +199,7 @@ i915:glk: + i915:amly: + extends: + - .i915 +- parallel: 8 ++ parallel: 2 + variables: + DEVICE_TYPE: asus-C433TA-AJ0005-rammus + GPU_VERSION: amly +@@ -208,7 +208,7 @@ i915:amly: + i915:kbl: + extends: + - .i915 +- parallel: 5 ++ parallel: 3 + variables: + DEVICE_TYPE: hp-x360-14-G1-sona + GPU_VERSION: kbl +@@ -217,7 +217,7 @@ i915:kbl: + i915:whl: + extends: + - .i915 +- parallel: 8 ++ parallel: 2 + variables: + DEVICE_TYPE: dell-latitude-5400-8665U-sarien + GPU_VERSION: whl +@@ -226,7 +226,7 @@ i915:whl: + i915:cml: + extends: + - .i915 +- parallel: 6 ++ parallel: 2 + variables: + DEVICE_TYPE: asus-C436FA-Flip-hatch + GPU_VERSION: cml +@@ -235,11 +235,11 @@ i915:cml: + i915:tgl: + extends: + - .i915 +- parallel: 6 ++ parallel: 5 + variables: +- DEVICE_TYPE: asus-cx9400-volteer ++ DEVICE_TYPE: acer-cp514-2h-1130g7-volteer + GPU_VERSION: tgl +- RUNNER_TAG: mesa-ci-x86-64-lava-asus-cx9400-volteer ++ RUNNER_TAG: mesa-ci-x86-64-lava-acer-cp514-2h-1130g7-volteer + + .amdgpu: + extends: +@@ -254,6 +254,7 @@ i915:tgl: + amdgpu:stoney: + extends: + - .amdgpu ++ parallel: 2 + variables: + DEVICE_TYPE: hp-11A-G6-EE-grunt + GPU_VERSION: stoney +@@ -272,6 +273,7 @@ amdgpu:stoney: + mediatek:mt8173: + extends: + - .mediatek ++ parallel: 4 + variables: + DEVICE_TYPE: mt8173-elm-hana + GPU_VERSION: mt8173 +@@ -283,6 +285,7 @@ mediatek:mt8173: + mediatek:mt8183: + extends: + - .mediatek ++ parallel: 3 + variables: + DEVICE_TYPE: mt8183-kukui-jacuzzi-juniper-sku16 + GPU_VERSION: mt8183 +@@ -292,6 +295,7 @@ mediatek:mt8183: + .mediatek:mt8192: + extends: + - .mediatek ++ parallel: 3 + variables: + DEVICE_TYPE: mt8192-asurada-spherion-r0 + GPU_VERSION: mt8192 +@@ -310,6 +314,7 @@ mediatek:mt8183: + meson:g12b: + extends: + - .meson ++ parallel: 3 + variables: + DEVICE_TYPE: meson-g12b-a311d-khadas-vim3 + GPU_VERSION: g12b +diff --git a/drivers/gpu/drm/display/drm_dp_helper.c b/drivers/gpu/drm/display/drm_dp_helper.c +index e6a78fd32380a..851f0baf94600 100644 +--- a/drivers/gpu/drm/display/drm_dp_helper.c ++++ b/drivers/gpu/drm/display/drm_dp_helper.c +@@ -532,6 +532,15 @@ static int drm_dp_dpcd_access(struct drm_dp_aux *aux, u8 request, + + mutex_lock(&aux->hw_mutex); + ++ /* ++ * If the device attached to the aux bus is powered down then there's ++ * no reason to attempt a transfer. Error out immediately. ++ */ ++ if (aux->powered_down) { ++ ret = -EBUSY; ++ goto unlock; ++ } ++ + /* + * The specification doesn't give any recommendation on how often to + * retry native transactions. We used to retry 7 times like for +@@ -599,6 +608,29 @@ int drm_dp_dpcd_probe(struct drm_dp_aux *aux, unsigned int offset) + } + EXPORT_SYMBOL(drm_dp_dpcd_probe); + ++/** ++ * drm_dp_dpcd_set_powered() - Set whether the DP device is powered ++ * @aux: DisplayPort AUX channel; for convenience it's OK to pass NULL here ++ * and the function will be a no-op. ++ * @powered: true if powered; false if not ++ * ++ * If the endpoint device on the DP AUX bus is known to be powered down ++ * then this function can be called to make future transfers fail immediately ++ * instead of needing to time out. ++ * ++ * If this function is never called then a device defaults to being powered. ++ */ ++void drm_dp_dpcd_set_powered(struct drm_dp_aux *aux, bool powered) ++{ ++ if (!aux) ++ return; ++ ++ mutex_lock(&aux->hw_mutex); ++ aux->powered_down = !powered; ++ mutex_unlock(&aux->hw_mutex); ++} ++EXPORT_SYMBOL(drm_dp_dpcd_set_powered); ++ + /** + * drm_dp_dpcd_read() - read a series of bytes from the DPCD + * @aux: DisplayPort AUX channel (SST or MST) +@@ -1855,6 +1887,9 @@ static int drm_dp_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, + struct drm_dp_aux_msg msg; + int err = 0; + ++ if (aux->powered_down) ++ return -EBUSY; ++ + dp_aux_i2c_transfer_size = clamp(dp_aux_i2c_transfer_size, 1, DP_AUX_MAX_PAYLOAD_BYTES); + + memset(&msg, 0, sizeof(msg)); +diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c +index 67354afbd7168..62d8a291c49c7 100644 +--- a/drivers/gpu/drm/drm_bridge.c ++++ b/drivers/gpu/drm/drm_bridge.c +@@ -687,11 +687,17 @@ void drm_atomic_bridge_chain_post_disable(struct drm_bridge *bridge, + */ + list_for_each_entry_from(next, &encoder->bridge_chain, + chain_node) { +- if (next->pre_enable_prev_first) { ++ if (!next->pre_enable_prev_first) { + next = list_prev_entry(next, chain_node); + limit = next; + break; + } ++ ++ if (list_is_last(&next->chain_node, ++ &encoder->bridge_chain)) { ++ limit = next; ++ break; ++ } + } + + /* Call these bridges in reverse order */ +@@ -774,7 +780,7 @@ void drm_atomic_bridge_chain_pre_enable(struct drm_bridge *bridge, + /* Found first bridge that does NOT + * request prev to be enabled first + */ +- limit = list_prev_entry(next, chain_node); ++ limit = next; + break; + } + } +diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c +index a491280ca48c8..ee3fab115c4b5 100644 +--- a/drivers/gpu/drm/drm_edid.c ++++ b/drivers/gpu/drm/drm_edid.c +@@ -7321,7 +7321,7 @@ static void drm_parse_tiled_block(struct drm_connector *connector, + static bool displayid_is_tiled_block(const struct displayid_iter *iter, + const struct displayid_block *block) + { +- return (displayid_version(iter) == DISPLAY_ID_STRUCTURE_VER_12 && ++ return (displayid_version(iter) < DISPLAY_ID_STRUCTURE_VER_20 && + block->tag == DATA_BLOCK_TILED_DISPLAY) || + (displayid_version(iter) == DISPLAY_ID_STRUCTURE_VER_20 && + block->tag == DATA_BLOCK_2_TILED_DISPLAY_TOPOLOGY); +diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c +index 843a6dbda93a0..52a93149363b4 100644 +--- a/drivers/gpu/drm/drm_mipi_dsi.c ++++ b/drivers/gpu/drm/drm_mipi_dsi.c +@@ -654,7 +654,7 @@ EXPORT_SYMBOL(mipi_dsi_set_maximum_return_packet_size); + * + * Return: 0 on success or a negative error code on failure. + */ +-ssize_t mipi_dsi_compression_mode(struct mipi_dsi_device *dsi, bool enable) ++int mipi_dsi_compression_mode(struct mipi_dsi_device *dsi, bool enable) + { + /* Note: Needs updating for non-default PPS or algorithm */ + u8 tx[2] = { enable << 0, 0 }; +@@ -679,8 +679,8 @@ EXPORT_SYMBOL(mipi_dsi_compression_mode); + * + * Return: 0 on success or a negative error code on failure. + */ +-ssize_t mipi_dsi_picture_parameter_set(struct mipi_dsi_device *dsi, +- const struct drm_dsc_picture_parameter_set *pps) ++int mipi_dsi_picture_parameter_set(struct mipi_dsi_device *dsi, ++ const struct drm_dsc_picture_parameter_set *pps) + { + struct mipi_dsi_msg msg = { + .channel = dsi->channel, +diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c +index 9276756e1397d..371e1f2733f6f 100644 +--- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c ++++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c +@@ -632,8 +632,8 @@ static void etnaviv_gpu_enable_mlcg(struct etnaviv_gpu *gpu) + /* Disable TX clock gating on affected core revisions. */ + if (etnaviv_is_model_rev(gpu, GC4000, 0x5222) || + etnaviv_is_model_rev(gpu, GC2000, 0x5108) || +- etnaviv_is_model_rev(gpu, GC2000, 0x6202) || +- etnaviv_is_model_rev(gpu, GC2000, 0x6203)) ++ etnaviv_is_model_rev(gpu, GC7000, 0x6202) || ++ etnaviv_is_model_rev(gpu, GC7000, 0x6203)) + pmc |= VIVS_PM_MODULE_CONTROLS_DISABLE_MODULE_CLOCK_GATING_TX; + + /* Disable SE and RA clock gating on affected core revisions. */ +diff --git a/drivers/gpu/drm/i915/display/intel_backlight.c b/drivers/gpu/drm/i915/display/intel_backlight.c +index 2e8f17c045222..ff9b9918b0a13 100644 +--- a/drivers/gpu/drm/i915/display/intel_backlight.c ++++ b/drivers/gpu/drm/i915/display/intel_backlight.c +@@ -274,7 +274,7 @@ static void ext_pwm_set_backlight(const struct drm_connector_state *conn_state, + struct intel_panel *panel = &to_intel_connector(conn_state->connector)->panel; + + pwm_set_relative_duty_cycle(&panel->backlight.pwm_state, level, 100); +- pwm_apply_state(panel->backlight.pwm, &panel->backlight.pwm_state); ++ pwm_apply_might_sleep(panel->backlight.pwm, &panel->backlight.pwm_state); + } + + static void +@@ -427,7 +427,7 @@ static void ext_pwm_disable_backlight(const struct drm_connector_state *old_conn + intel_backlight_set_pwm_level(old_conn_state, level); + + panel->backlight.pwm_state.enabled = false; +- pwm_apply_state(panel->backlight.pwm, &panel->backlight.pwm_state); ++ pwm_apply_might_sleep(panel->backlight.pwm, &panel->backlight.pwm_state); + } + + void intel_backlight_disable(const struct drm_connector_state *old_conn_state) +@@ -749,7 +749,7 @@ static void ext_pwm_enable_backlight(const struct intel_crtc_state *crtc_state, + + pwm_set_relative_duty_cycle(&panel->backlight.pwm_state, level, 100); + panel->backlight.pwm_state.enabled = true; +- pwm_apply_state(panel->backlight.pwm, &panel->backlight.pwm_state); ++ pwm_apply_might_sleep(panel->backlight.pwm, &panel->backlight.pwm_state); + } + + static void __intel_backlight_enable(const struct intel_crtc_state *crtc_state, +diff --git a/drivers/gpu/drm/i915/gt/intel_engine_cs.c b/drivers/gpu/drm/i915/gt/intel_engine_cs.c +index 765387639dabb..d9bb352b8baab 100644 +--- a/drivers/gpu/drm/i915/gt/intel_engine_cs.c ++++ b/drivers/gpu/drm/i915/gt/intel_engine_cs.c +@@ -923,6 +923,12 @@ static intel_engine_mask_t init_engine_mask(struct intel_gt *gt) + if (IS_DG2(gt->i915)) { + u8 first_ccs = __ffs(CCS_MASK(gt)); + ++ /* ++ * Store the number of active cslices before ++ * changing the CCS engine configuration ++ */ ++ gt->ccs.cslices = CCS_MASK(gt); ++ + /* Mask off all the CCS engine */ + info->engine_mask &= ~GENMASK(CCS3, CCS0); + /* Put back in the first CCS engine */ +diff --git a/drivers/gpu/drm/i915/gt/intel_gt_ccs_mode.c b/drivers/gpu/drm/i915/gt/intel_gt_ccs_mode.c +index 99b71bb7da0a6..3c62a44e9106c 100644 +--- a/drivers/gpu/drm/i915/gt/intel_gt_ccs_mode.c ++++ b/drivers/gpu/drm/i915/gt/intel_gt_ccs_mode.c +@@ -19,7 +19,7 @@ unsigned int intel_gt_apply_ccs_mode(struct intel_gt *gt) + + /* Build the value for the fixed CCS load balancing */ + for (cslice = 0; cslice < I915_MAX_CCS; cslice++) { +- if (CCS_MASK(gt) & BIT(cslice)) ++ if (gt->ccs.cslices & BIT(cslice)) + /* + * If available, assign the cslice + * to the first available engine... +diff --git a/drivers/gpu/drm/i915/gt/intel_gt_types.h b/drivers/gpu/drm/i915/gt/intel_gt_types.h +index def7dd0eb6f19..cfdd2ad5e9549 100644 +--- a/drivers/gpu/drm/i915/gt/intel_gt_types.h ++++ b/drivers/gpu/drm/i915/gt/intel_gt_types.h +@@ -207,6 +207,14 @@ struct intel_gt { + [MAX_ENGINE_INSTANCE + 1]; + enum intel_submission_method submission_method; + ++ struct { ++ /* ++ * Mask of the non fused CCS slices ++ * to be used for the load balancing ++ */ ++ intel_engine_mask_t cslices; ++ } ccs; ++ + /* + * Default address space (either GGTT or ppGTT depending on arch). + * +diff --git a/drivers/gpu/drm/i915/gt/selftest_migrate.c b/drivers/gpu/drm/i915/gt/selftest_migrate.c +index 3def5ca72decf..0fb07f073baa6 100644 +--- a/drivers/gpu/drm/i915/gt/selftest_migrate.c ++++ b/drivers/gpu/drm/i915/gt/selftest_migrate.c +@@ -719,11 +719,9 @@ static int threaded_migrate(struct intel_migrate *migrate, + if (IS_ERR_OR_NULL(tsk)) + continue; + +- status = kthread_stop(tsk); ++ status = kthread_stop_put(tsk); + if (status && !err) + err = status; +- +- put_task_struct(tsk); + } + + kfree(thread); +diff --git a/drivers/gpu/drm/i915/gt/uc/abi/guc_klvs_abi.h b/drivers/gpu/drm/i915/gt/uc/abi/guc_klvs_abi.h +index 58012edd4eb0e..4f4f53c42a9c5 100644 +--- a/drivers/gpu/drm/i915/gt/uc/abi/guc_klvs_abi.h ++++ b/drivers/gpu/drm/i915/gt/uc/abi/guc_klvs_abi.h +@@ -29,9 +29,9 @@ + */ + + #define GUC_KLV_LEN_MIN 1u +-#define GUC_KLV_0_KEY (0xffff << 16) +-#define GUC_KLV_0_LEN (0xffff << 0) +-#define GUC_KLV_n_VALUE (0xffffffff << 0) ++#define GUC_KLV_0_KEY (0xffffu << 16) ++#define GUC_KLV_0_LEN (0xffffu << 0) ++#define GUC_KLV_n_VALUE (0xffffffffu << 0) + + /** + * DOC: GuC Self Config KLVs +diff --git a/drivers/gpu/drm/i915/gvt/interrupt.c b/drivers/gpu/drm/i915/gvt/interrupt.c +index 68eca023bbc68..80301472ac988 100644 +--- a/drivers/gpu/drm/i915/gvt/interrupt.c ++++ b/drivers/gpu/drm/i915/gvt/interrupt.c +@@ -405,7 +405,7 @@ static void init_irq_map(struct intel_gvt_irq *irq) + #define MSI_CAP_DATA(offset) (offset + 8) + #define MSI_CAP_EN 0x1 + +-static int inject_virtual_interrupt(struct intel_vgpu *vgpu) ++static void inject_virtual_interrupt(struct intel_vgpu *vgpu) + { + unsigned long offset = vgpu->gvt->device_info.msi_cap_offset; + u16 control, data; +@@ -417,10 +417,10 @@ static int inject_virtual_interrupt(struct intel_vgpu *vgpu) + + /* Do not generate MSI if MSIEN is disabled */ + if (!(control & MSI_CAP_EN)) +- return 0; ++ return; + + if (WARN(control & GENMASK(15, 1), "only support one MSI format\n")) +- return -EINVAL; ++ return; + + trace_inject_msi(vgpu->id, addr, data); + +@@ -434,10 +434,9 @@ static int inject_virtual_interrupt(struct intel_vgpu *vgpu) + * returned and don't inject interrupt into guest. + */ + if (!test_bit(INTEL_VGPU_STATUS_ATTACHED, vgpu->status)) +- return -ESRCH; +- if (vgpu->msi_trigger && eventfd_signal(vgpu->msi_trigger, 1) != 1) +- return -EFAULT; +- return 0; ++ return; ++ if (vgpu->msi_trigger) ++ eventfd_signal(vgpu->msi_trigger, 1); + } + + static void propagate_event(struct intel_gvt_irq *irq, +diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c b/drivers/gpu/drm/mediatek/mtk_dp.c +index 4052a3133b576..af03a22772fed 100644 +--- a/drivers/gpu/drm/mediatek/mtk_dp.c ++++ b/drivers/gpu/drm/mediatek/mtk_dp.c +@@ -2080,7 +2080,7 @@ static ssize_t mtk_dp_aux_transfer(struct drm_dp_aux *mtk_aux, + + if (mtk_dp->bridge.type != DRM_MODE_CONNECTOR_eDP && + !mtk_dp->train_info.cable_plugged_in) { +- ret = -EAGAIN; ++ ret = -EIO; + goto err; + } + +diff --git a/drivers/gpu/drm/mediatek/mtk_drm_gem.c b/drivers/gpu/drm/mediatek/mtk_drm_gem.c +index 4f2e3feabc0f8..1bf229615b018 100644 +--- a/drivers/gpu/drm/mediatek/mtk_drm_gem.c ++++ b/drivers/gpu/drm/mediatek/mtk_drm_gem.c +@@ -38,6 +38,9 @@ static struct mtk_drm_gem_obj *mtk_drm_gem_init(struct drm_device *dev, + + size = round_up(size, PAGE_SIZE); + ++ if (size == 0) ++ return ERR_PTR(-EINVAL); ++ + mtk_gem_obj = kzalloc(sizeof(*mtk_gem_obj), GFP_KERNEL); + if (!mtk_gem_obj) + return ERR_PTR(-ENOMEM); +diff --git a/drivers/gpu/drm/meson/meson_dw_mipi_dsi.c b/drivers/gpu/drm/meson/meson_dw_mipi_dsi.c +index e5fe4e994f43b..72abe2057ec31 100644 +--- a/drivers/gpu/drm/meson/meson_dw_mipi_dsi.c ++++ b/drivers/gpu/drm/meson/meson_dw_mipi_dsi.c +@@ -95,6 +95,7 @@ static int dw_mipi_dsi_phy_init(void *priv_data) + return ret; + } + ++ clk_disable_unprepare(mipi_dsi->px_clk); + ret = clk_set_rate(mipi_dsi->px_clk, mipi_dsi->mode->clock * 1000); + + if (ret) { +@@ -103,6 +104,12 @@ static int dw_mipi_dsi_phy_init(void *priv_data) + return ret; + } + ++ ret = clk_prepare_enable(mipi_dsi->px_clk); ++ if (ret) { ++ dev_err(mipi_dsi->dev, "Failed to enable DSI Pixel clock (ret %d)\n", ret); ++ return ret; ++ } ++ + switch (mipi_dsi->dsi_device->format) { + case MIPI_DSI_FMT_RGB888: + dpi_data_format = DPI_COLOR_24BIT; +diff --git a/drivers/gpu/drm/meson/meson_vclk.c b/drivers/gpu/drm/meson/meson_vclk.c +index 2a82119eb58ed..2a942dc6a6dc2 100644 +--- a/drivers/gpu/drm/meson/meson_vclk.c ++++ b/drivers/gpu/drm/meson/meson_vclk.c +@@ -790,13 +790,13 @@ meson_vclk_vic_supported_freq(struct meson_drm *priv, unsigned int phy_freq, + FREQ_1000_1001(params[i].pixel_freq)); + DRM_DEBUG_DRIVER("i = %d phy_freq = %d alt = %d\n", + i, params[i].phy_freq, +- FREQ_1000_1001(params[i].phy_freq/10)*10); ++ FREQ_1000_1001(params[i].phy_freq/1000)*1000); + /* Match strict frequency */ + if (phy_freq == params[i].phy_freq && + vclk_freq == params[i].vclk_freq) + return MODE_OK; + /* Match 1000/1001 variant */ +- if (phy_freq == (FREQ_1000_1001(params[i].phy_freq/10)*10) && ++ if (phy_freq == (FREQ_1000_1001(params[i].phy_freq/1000)*1000) && + vclk_freq == FREQ_1000_1001(params[i].vclk_freq)) + return MODE_OK; + } +@@ -1070,7 +1070,7 @@ void meson_vclk_setup(struct meson_drm *priv, unsigned int target, + + for (freq = 0 ; params[freq].pixel_freq ; ++freq) { + if ((phy_freq == params[freq].phy_freq || +- phy_freq == FREQ_1000_1001(params[freq].phy_freq/10)*10) && ++ phy_freq == FREQ_1000_1001(params[freq].phy_freq/1000)*1000) && + (vclk_freq == params[freq].vclk_freq || + vclk_freq == FREQ_1000_1001(params[freq].vclk_freq))) { + if (vclk_freq != params[freq].vclk_freq) +diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c +index 522ca7fe67625..3664c1476a83a 100644 +--- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c ++++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c +@@ -2343,7 +2343,8 @@ struct msm_gpu *a6xx_gpu_init(struct drm_device *dev) + + ret = a6xx_set_supported_hw(&pdev->dev, config->info); + if (ret) { +- a6xx_destroy(&(a6xx_gpu->base.base)); ++ a6xx_llc_slices_destroy(a6xx_gpu); ++ kfree(a6xx_gpu); + return ERR_PTR(ret); + } + +diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_core_irq.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_core_irq.h +index b5b6e7031fb9e..ba06312cbb163 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_core_irq.h ++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_core_irq.h +@@ -53,7 +53,7 @@ u32 dpu_core_irq_read( + int dpu_core_irq_register_callback( + struct dpu_kms *dpu_kms, + int irq_idx, +- void (*irq_cb)(void *arg, int irq_idx), ++ void (*irq_cb)(void *arg), + void *irq_arg); + + /** +diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +index 20e118546432d..5fb7e2e10801d 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c ++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +@@ -357,8 +357,8 @@ static int dpu_encoder_helper_wait_event_timeout(int32_t drm_id, + u32 irq_idx, struct dpu_encoder_wait_info *info); + + int dpu_encoder_helper_wait_for_irq(struct dpu_encoder_phys *phys_enc, +- int irq, +- void (*func)(void *arg, int irq_idx), ++ int irq_idx, ++ void (*func)(void *arg), + struct dpu_encoder_wait_info *wait_info) + { + u32 irq_status; +@@ -372,54 +372,54 @@ int dpu_encoder_helper_wait_for_irq(struct dpu_encoder_phys *phys_enc, + + /* return EWOULDBLOCK since we know the wait isn't necessary */ + if (phys_enc->enable_state == DPU_ENC_DISABLED) { +- DRM_ERROR("encoder is disabled id=%u, callback=%ps, irq=%d\n", ++ DRM_ERROR("encoder is disabled id=%u, callback=%ps, IRQ=[%d, %d]\n", + DRMID(phys_enc->parent), func, +- irq); ++ DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx)); + return -EWOULDBLOCK; + } + +- if (irq < 0) { ++ if (irq_idx < 0) { + DRM_DEBUG_KMS("skip irq wait id=%u, callback=%ps\n", + DRMID(phys_enc->parent), func); + return 0; + } + +- DRM_DEBUG_KMS("id=%u, callback=%ps, irq=%d, pp=%d, pending_cnt=%d\n", ++ DRM_DEBUG_KMS("id=%u, callback=%ps, IRQ=[%d, %d], pp=%d, pending_cnt=%d\n", + DRMID(phys_enc->parent), func, +- irq, phys_enc->hw_pp->idx - PINGPONG_0, ++ DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx), phys_enc->hw_pp->idx - PINGPONG_0, + atomic_read(wait_info->atomic_cnt)); + + ret = dpu_encoder_helper_wait_event_timeout( + DRMID(phys_enc->parent), +- irq, ++ irq_idx, + wait_info); + + if (ret <= 0) { +- irq_status = dpu_core_irq_read(phys_enc->dpu_kms, irq); ++ irq_status = dpu_core_irq_read(phys_enc->dpu_kms, irq_idx); + if (irq_status) { + unsigned long flags; + +- DRM_DEBUG_KMS("irq not triggered id=%u, callback=%ps, irq=%d, pp=%d, atomic_cnt=%d\n", ++ DRM_DEBUG_KMS("IRQ=[%d, %d] not triggered id=%u, callback=%ps, pp=%d, atomic_cnt=%d\n", ++ DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx), + DRMID(phys_enc->parent), func, +- irq, + phys_enc->hw_pp->idx - PINGPONG_0, + atomic_read(wait_info->atomic_cnt)); + local_irq_save(flags); +- func(phys_enc, irq); ++ func(phys_enc); + local_irq_restore(flags); + ret = 0; + } else { + ret = -ETIMEDOUT; +- DRM_DEBUG_KMS("irq timeout id=%u, callback=%ps, irq=%d, pp=%d, atomic_cnt=%d\n", ++ DRM_DEBUG_KMS("IRQ=[%d, %d] timeout id=%u, callback=%ps, pp=%d, atomic_cnt=%d\n", ++ DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx), + DRMID(phys_enc->parent), func, +- irq, + phys_enc->hw_pp->idx - PINGPONG_0, + atomic_read(wait_info->atomic_cnt)); + } + } else { + ret = 0; + trace_dpu_enc_irq_wait_success(DRMID(phys_enc->parent), +- func, irq, ++ func, irq_idx, + phys_enc->hw_pp->idx - PINGPONG_0, + atomic_read(wait_info->atomic_cnt)); + } +diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h +index d48558ede488d..f91661a698882 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h ++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h +@@ -365,7 +365,7 @@ void dpu_encoder_helper_report_irq_timeout(struct dpu_encoder_phys *phys_enc, + */ + int dpu_encoder_helper_wait_for_irq(struct dpu_encoder_phys *phys_enc, + int irq, +- void (*func)(void *arg, int irq_idx), ++ void (*func)(void *arg), + struct dpu_encoder_wait_info *wait_info); + + /** +diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c +index df88358e7037b..718421306247f 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c ++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c +@@ -76,7 +76,7 @@ static void _dpu_encoder_phys_cmd_update_intf_cfg( + phys_enc->hw_intf->ops.program_intf_cmd_cfg(phys_enc->hw_intf, &cmd_mode_cfg); + } + +-static void dpu_encoder_phys_cmd_pp_tx_done_irq(void *arg, int irq_idx) ++static void dpu_encoder_phys_cmd_pp_tx_done_irq(void *arg) + { + struct dpu_encoder_phys *phys_enc = arg; + unsigned long lock_flags; +@@ -103,7 +103,7 @@ static void dpu_encoder_phys_cmd_pp_tx_done_irq(void *arg, int irq_idx) + DPU_ATRACE_END("pp_done_irq"); + } + +-static void dpu_encoder_phys_cmd_te_rd_ptr_irq(void *arg, int irq_idx) ++static void dpu_encoder_phys_cmd_te_rd_ptr_irq(void *arg) + { + struct dpu_encoder_phys *phys_enc = arg; + struct dpu_encoder_phys_cmd *cmd_enc; +@@ -126,7 +126,7 @@ static void dpu_encoder_phys_cmd_te_rd_ptr_irq(void *arg, int irq_idx) + DPU_ATRACE_END("rd_ptr_irq"); + } + +-static void dpu_encoder_phys_cmd_ctl_start_irq(void *arg, int irq_idx) ++static void dpu_encoder_phys_cmd_ctl_start_irq(void *arg) + { + struct dpu_encoder_phys *phys_enc = arg; + +@@ -139,7 +139,7 @@ static void dpu_encoder_phys_cmd_ctl_start_irq(void *arg, int irq_idx) + DPU_ATRACE_END("ctl_start_irq"); + } + +-static void dpu_encoder_phys_cmd_underrun_irq(void *arg, int irq_idx) ++static void dpu_encoder_phys_cmd_underrun_irq(void *arg) + { + struct dpu_encoder_phys *phys_enc = arg; + +@@ -449,9 +449,6 @@ static void dpu_encoder_phys_cmd_enable_helper( + + _dpu_encoder_phys_cmd_pingpong_config(phys_enc); + +- if (!dpu_encoder_phys_cmd_is_master(phys_enc)) +- return; +- + ctl = phys_enc->hw_ctl; + ctl->ops.update_pending_flush_intf(ctl, phys_enc->hw_intf->idx); + } +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 2141b81397824..aec3ca4aa0fb7 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 +@@ -300,7 +300,7 @@ static void dpu_encoder_phys_vid_setup_timing_engine( + programmable_fetch_config(phys_enc, &timing_params); + } + +-static void dpu_encoder_phys_vid_vblank_irq(void *arg, int irq_idx) ++static void dpu_encoder_phys_vid_vblank_irq(void *arg) + { + struct dpu_encoder_phys *phys_enc = arg; + struct dpu_hw_ctl *hw_ctl; +@@ -337,7 +337,7 @@ static void dpu_encoder_phys_vid_vblank_irq(void *arg, int irq_idx) + DPU_ATRACE_END("vblank_irq"); + } + +-static void dpu_encoder_phys_vid_underrun_irq(void *arg, int irq_idx) ++static void dpu_encoder_phys_vid_underrun_irq(void *arg) + { + struct dpu_encoder_phys *phys_enc = arg; + +diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c +index 78037a697633b..870a1f5060e30 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c ++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c +@@ -345,7 +345,11 @@ static void dpu_encoder_phys_wb_setup( + + } + +-static void _dpu_encoder_phys_wb_frame_done_helper(void *arg) ++/** ++ * dpu_encoder_phys_wb_done_irq - writeback interrupt handler ++ * @arg: Pointer to writeback encoder ++ */ ++static void dpu_encoder_phys_wb_done_irq(void *arg) + { + struct dpu_encoder_phys *phys_enc = arg; + struct dpu_encoder_phys_wb *wb_enc = to_dpu_encoder_phys_wb(phys_enc); +@@ -371,16 +375,6 @@ static void _dpu_encoder_phys_wb_frame_done_helper(void *arg) + wake_up_all(&phys_enc->pending_kickoff_wq); + } + +-/** +- * dpu_encoder_phys_wb_done_irq - writeback interrupt handler +- * @arg: Pointer to writeback encoder +- * @irq_idx: interrupt index +- */ +-static void dpu_encoder_phys_wb_done_irq(void *arg, int irq_idx) +-{ +- _dpu_encoder_phys_wb_frame_done_helper(arg); +-} +- + /** + * dpu_encoder_phys_wb_irq_ctrl - irq control of WB + * @phys: Pointer to physical encoder +diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c +index e3c50439f80a1..c8d7929ce5232 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c ++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c +@@ -197,8 +197,18 @@ static const struct dpu_intr_reg dpu_intr_set_7xxx[] = { + }, + }; + +-#define DPU_IRQ_REG(irq_idx) (irq_idx / 32) +-#define DPU_IRQ_MASK(irq_idx) (BIT(irq_idx % 32)) ++#define DPU_IRQ_MASK(irq_idx) (BIT(DPU_IRQ_BIT(irq_idx))) ++ ++static inline bool dpu_core_irq_is_valid(int irq_idx) ++{ ++ return irq_idx >= 0 && irq_idx < DPU_NUM_IRQS; ++} ++ ++static inline struct dpu_hw_intr_entry *dpu_core_irq_get_entry(struct dpu_hw_intr *intr, ++ int irq_idx) ++{ ++ return &intr->irq_tbl[irq_idx]; ++} + + /** + * dpu_core_irq_callback_handler - dispatch core interrupts +@@ -207,17 +217,22 @@ static const struct dpu_intr_reg dpu_intr_set_7xxx[] = { + */ + static void dpu_core_irq_callback_handler(struct dpu_kms *dpu_kms, int irq_idx) + { +- VERB("irq_idx=%d\n", irq_idx); ++ struct dpu_hw_intr_entry *irq_entry = dpu_core_irq_get_entry(dpu_kms->hw_intr, irq_idx); + +- if (!dpu_kms->hw_intr->irq_tbl[irq_idx].cb) +- DRM_ERROR("no registered cb, idx:%d\n", irq_idx); ++ VERB("IRQ=[%d, %d]\n", DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx)); + +- atomic_inc(&dpu_kms->hw_intr->irq_tbl[irq_idx].count); ++ if (!irq_entry->cb) { ++ DRM_ERROR("no registered cb, IRQ=[%d, %d]\n", ++ DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx)); ++ return; ++ } ++ ++ atomic_inc(&irq_entry->count); + + /* + * Perform registered function callback + */ +- dpu_kms->hw_intr->irq_tbl[irq_idx].cb(dpu_kms->hw_intr->irq_tbl[irq_idx].arg, irq_idx); ++ irq_entry->cb(irq_entry->arg); + } + + irqreturn_t dpu_core_irq(struct msm_kms *kms) +@@ -291,8 +306,9 @@ static int dpu_hw_intr_enable_irq_locked(struct dpu_hw_intr *intr, int irq_idx) + if (!intr) + return -EINVAL; + +- if (irq_idx < 0 || irq_idx >= intr->total_irqs) { +- pr_err("invalid IRQ index: [%d]\n", irq_idx); ++ if (!dpu_core_irq_is_valid(irq_idx)) { ++ pr_err("invalid IRQ=[%d, %d]\n", ++ DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx)); + return -EINVAL; + } + +@@ -328,7 +344,8 @@ static int dpu_hw_intr_enable_irq_locked(struct dpu_hw_intr *intr, int irq_idx) + intr->cache_irq_mask[reg_idx] = cache_irq_mask; + } + +- pr_debug("DPU IRQ %d %senabled: MASK:0x%.8lx, CACHE-MASK:0x%.8x\n", irq_idx, dbgstr, ++ pr_debug("DPU IRQ=[%d, %d] %senabled: MASK:0x%.8lx, CACHE-MASK:0x%.8x\n", ++ DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx), dbgstr, + DPU_IRQ_MASK(irq_idx), cache_irq_mask); + + return 0; +@@ -344,8 +361,9 @@ static int dpu_hw_intr_disable_irq_locked(struct dpu_hw_intr *intr, int irq_idx) + if (!intr) + return -EINVAL; + +- if (irq_idx < 0 || irq_idx >= intr->total_irqs) { +- pr_err("invalid IRQ index: [%d]\n", irq_idx); ++ if (!dpu_core_irq_is_valid(irq_idx)) { ++ pr_err("invalid IRQ=[%d, %d]\n", ++ DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx)); + return -EINVAL; + } + +@@ -377,7 +395,8 @@ static int dpu_hw_intr_disable_irq_locked(struct dpu_hw_intr *intr, int irq_idx) + intr->cache_irq_mask[reg_idx] = cache_irq_mask; + } + +- pr_debug("DPU IRQ %d %sdisabled: MASK:0x%.8lx, CACHE-MASK:0x%.8x\n", irq_idx, dbgstr, ++ pr_debug("DPU IRQ=[%d, %d] %sdisabled: MASK:0x%.8lx, CACHE-MASK:0x%.8x\n", ++ DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx), dbgstr, + DPU_IRQ_MASK(irq_idx), cache_irq_mask); + + return 0; +@@ -429,14 +448,8 @@ u32 dpu_core_irq_read(struct dpu_kms *dpu_kms, int irq_idx) + if (!intr) + return 0; + +- if (irq_idx < 0) { +- DPU_ERROR("[%pS] invalid irq_idx=%d\n", +- __builtin_return_address(0), irq_idx); +- return 0; +- } +- +- if (irq_idx < 0 || irq_idx >= intr->total_irqs) { +- pr_err("invalid IRQ index: [%d]\n", irq_idx); ++ if (!dpu_core_irq_is_valid(irq_idx)) { ++ pr_err("invalid IRQ=[%d, %d]\n", DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx)); + return 0; + } + +@@ -462,13 +475,12 @@ struct dpu_hw_intr *dpu_hw_intr_init(void __iomem *addr, + const struct dpu_mdss_cfg *m) + { + struct dpu_hw_intr *intr; +- int nirq = MDP_INTR_MAX * 32; + unsigned int i; + + if (!addr || !m) + return ERR_PTR(-EINVAL); + +- intr = kzalloc(struct_size(intr, irq_tbl, nirq), GFP_KERNEL); ++ intr = kzalloc(sizeof(*intr), GFP_KERNEL); + if (!intr) + return ERR_PTR(-ENOMEM); + +@@ -479,8 +491,6 @@ struct dpu_hw_intr *dpu_hw_intr_init(void __iomem *addr, + + intr->hw.blk_addr = addr + m->mdp[0].base; + +- intr->total_irqs = nirq; +- + intr->irq_mask = BIT(MDP_SSPP_TOP0_INTR) | + BIT(MDP_SSPP_TOP0_INTR2) | + BIT(MDP_SSPP_TOP0_HIST_INTR); +@@ -507,42 +517,47 @@ void dpu_hw_intr_destroy(struct dpu_hw_intr *intr) + } + + int dpu_core_irq_register_callback(struct dpu_kms *dpu_kms, int irq_idx, +- void (*irq_cb)(void *arg, int irq_idx), ++ void (*irq_cb)(void *arg), + void *irq_arg) + { ++ struct dpu_hw_intr_entry *irq_entry; + unsigned long irq_flags; + int ret; + + if (!irq_cb) { +- DPU_ERROR("invalid ird_idx:%d irq_cb:%ps\n", irq_idx, irq_cb); ++ DPU_ERROR("IRQ=[%d, %d] NULL callback\n", ++ DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx)); + return -EINVAL; + } + +- if (irq_idx < 0 || irq_idx >= dpu_kms->hw_intr->total_irqs) { +- DPU_ERROR("invalid IRQ index: [%d]\n", irq_idx); ++ if (!dpu_core_irq_is_valid(irq_idx)) { ++ DPU_ERROR("invalid IRQ=[%d, %d] irq_cb:%ps\n", ++ DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx), irq_cb); + return -EINVAL; + } + +- VERB("[%pS] irq_idx=%d\n", __builtin_return_address(0), irq_idx); ++ VERB("[%pS] IRQ=[%d, %d]\n", __builtin_return_address(0), ++ DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx)); + + spin_lock_irqsave(&dpu_kms->hw_intr->irq_lock, irq_flags); + +- if (unlikely(WARN_ON(dpu_kms->hw_intr->irq_tbl[irq_idx].cb))) { ++ irq_entry = dpu_core_irq_get_entry(dpu_kms->hw_intr, irq_idx); ++ if (unlikely(WARN_ON(irq_entry->cb))) { + spin_unlock_irqrestore(&dpu_kms->hw_intr->irq_lock, irq_flags); + + return -EBUSY; + } + + trace_dpu_core_irq_register_callback(irq_idx, irq_cb); +- dpu_kms->hw_intr->irq_tbl[irq_idx].arg = irq_arg; +- dpu_kms->hw_intr->irq_tbl[irq_idx].cb = irq_cb; ++ irq_entry->arg = irq_arg; ++ irq_entry->cb = irq_cb; + + ret = dpu_hw_intr_enable_irq_locked( + dpu_kms->hw_intr, + irq_idx); + if (ret) +- DPU_ERROR("Fail to enable IRQ for irq_idx:%d\n", +- irq_idx); ++ DPU_ERROR("Failed/ to enable IRQ=[%d, %d]\n", ++ DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx)); + spin_unlock_irqrestore(&dpu_kms->hw_intr->irq_lock, irq_flags); + + trace_dpu_irq_register_success(irq_idx); +@@ -552,26 +567,30 @@ int dpu_core_irq_register_callback(struct dpu_kms *dpu_kms, int irq_idx, + + int dpu_core_irq_unregister_callback(struct dpu_kms *dpu_kms, int irq_idx) + { ++ struct dpu_hw_intr_entry *irq_entry; + unsigned long irq_flags; + int ret; + +- if (irq_idx < 0 || irq_idx >= dpu_kms->hw_intr->total_irqs) { +- DPU_ERROR("invalid IRQ index: [%d]\n", irq_idx); ++ if (!dpu_core_irq_is_valid(irq_idx)) { ++ DPU_ERROR("invalid IRQ=[%d, %d]\n", ++ DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx)); + return -EINVAL; + } + +- VERB("[%pS] irq_idx=%d\n", __builtin_return_address(0), irq_idx); ++ VERB("[%pS] IRQ=[%d, %d]\n", __builtin_return_address(0), ++ DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx)); + + spin_lock_irqsave(&dpu_kms->hw_intr->irq_lock, irq_flags); + trace_dpu_core_irq_unregister_callback(irq_idx); + + ret = dpu_hw_intr_disable_irq_locked(dpu_kms->hw_intr, irq_idx); + if (ret) +- DPU_ERROR("Fail to disable IRQ for irq_idx:%d: %d\n", +- irq_idx, ret); ++ DPU_ERROR("Failed to disable IRQ=[%d, %d]: %d\n", ++ DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx), ret); + +- dpu_kms->hw_intr->irq_tbl[irq_idx].cb = NULL; +- dpu_kms->hw_intr->irq_tbl[irq_idx].arg = NULL; ++ irq_entry = dpu_core_irq_get_entry(dpu_kms->hw_intr, irq_idx); ++ irq_entry->cb = NULL; ++ irq_entry->arg = NULL; + + spin_unlock_irqrestore(&dpu_kms->hw_intr->irq_lock, irq_flags); + +@@ -584,18 +603,21 @@ int dpu_core_irq_unregister_callback(struct dpu_kms *dpu_kms, int irq_idx) + static int dpu_debugfs_core_irq_show(struct seq_file *s, void *v) + { + struct dpu_kms *dpu_kms = s->private; ++ struct dpu_hw_intr_entry *irq_entry; + unsigned long irq_flags; + int i, irq_count; + void *cb; + +- for (i = 0; i < dpu_kms->hw_intr->total_irqs; i++) { ++ for (i = 0; i < DPU_NUM_IRQS; i++) { + spin_lock_irqsave(&dpu_kms->hw_intr->irq_lock, irq_flags); +- irq_count = atomic_read(&dpu_kms->hw_intr->irq_tbl[i].count); +- cb = dpu_kms->hw_intr->irq_tbl[i].cb; ++ irq_entry = dpu_core_irq_get_entry(dpu_kms->hw_intr, i); ++ irq_count = atomic_read(&irq_entry->count); ++ cb = irq_entry->cb; + spin_unlock_irqrestore(&dpu_kms->hw_intr->irq_lock, irq_flags); + + if (irq_count || cb) +- seq_printf(s, "idx:%d irq:%d cb:%ps\n", i, irq_count, cb); ++ seq_printf(s, "IRQ=[%d, %d] count:%d cb:%ps\n", ++ DPU_IRQ_REG(i), DPU_IRQ_BIT(i), irq_count, cb); + } + + return 0; +@@ -614,6 +636,7 @@ void dpu_debugfs_core_irq_init(struct dpu_kms *dpu_kms, + void dpu_core_irq_preinstall(struct msm_kms *kms) + { + struct dpu_kms *dpu_kms = to_dpu_kms(kms); ++ struct dpu_hw_intr_entry *irq_entry; + int i; + + pm_runtime_get_sync(&dpu_kms->pdev->dev); +@@ -621,22 +644,28 @@ void dpu_core_irq_preinstall(struct msm_kms *kms) + dpu_disable_all_irqs(dpu_kms); + pm_runtime_put_sync(&dpu_kms->pdev->dev); + +- for (i = 0; i < dpu_kms->hw_intr->total_irqs; i++) +- atomic_set(&dpu_kms->hw_intr->irq_tbl[i].count, 0); ++ for (i = 0; i < DPU_NUM_IRQS; i++) { ++ irq_entry = dpu_core_irq_get_entry(dpu_kms->hw_intr, i); ++ atomic_set(&irq_entry->count, 0); ++ } + } + + void dpu_core_irq_uninstall(struct msm_kms *kms) + { + struct dpu_kms *dpu_kms = to_dpu_kms(kms); ++ struct dpu_hw_intr_entry *irq_entry; + int i; + + if (!dpu_kms->hw_intr) + return; + + pm_runtime_get_sync(&dpu_kms->pdev->dev); +- for (i = 0; i < dpu_kms->hw_intr->total_irqs; i++) +- if (dpu_kms->hw_intr->irq_tbl[i].cb) +- DPU_ERROR("irq_idx=%d still enabled/registered\n", i); ++ for (i = 0; i < DPU_NUM_IRQS; i++) { ++ irq_entry = dpu_core_irq_get_entry(dpu_kms->hw_intr, i); ++ if (irq_entry->cb) ++ DPU_ERROR("IRQ=[%d, %d] still enabled/registered\n", ++ DPU_IRQ_REG(i), DPU_IRQ_BIT(i)); ++ } + + dpu_clear_irqs(dpu_kms); + dpu_disable_all_irqs(dpu_kms); +diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h +index dab761e548636..9df5d6e737a11 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h ++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h +@@ -37,6 +37,16 @@ enum dpu_hw_intr_reg { + #define MDP_INTFn_INTR(intf) (MDP_INTF0_INTR + (intf - INTF_0)) + + #define DPU_IRQ_IDX(reg_idx, offset) (reg_idx * 32 + offset) ++#define DPU_IRQ_REG(irq_idx) (irq_idx / 32) ++#define DPU_IRQ_BIT(irq_idx) (irq_idx % 32) ++ ++#define DPU_NUM_IRQS (MDP_INTR_MAX * 32) ++ ++struct dpu_hw_intr_entry { ++ void (*cb)(void *arg); ++ void *arg; ++ atomic_t count; ++}; + + /** + * struct dpu_hw_intr: hw interrupts handling data structure +@@ -44,7 +54,6 @@ enum dpu_hw_intr_reg { + * @ops: function pointer mapping for IRQ handling + * @cache_irq_mask: array of IRQ enable masks reg storage created during init + * @save_irq_status: array of IRQ status reg storage created during init +- * @total_irqs: total number of irq_idx mapped in the hw_interrupts + * @irq_lock: spinlock for accessing IRQ resources + * @irq_cb_tbl: array of IRQ callbacks + */ +@@ -52,16 +61,11 @@ struct dpu_hw_intr { + struct dpu_hw_blk_reg_map hw; + u32 cache_irq_mask[MDP_INTR_MAX]; + u32 *save_irq_status; +- u32 total_irqs; + spinlock_t irq_lock; + unsigned long irq_mask; + const struct dpu_intr_reg *intr_set; + +- struct { +- void (*cb)(void *arg, int irq_idx); +- void *arg; +- atomic_t count; +- } irq_tbl[]; ++ struct dpu_hw_intr_entry irq_tbl[DPU_NUM_IRQS]; + }; + + /** +diff --git a/drivers/gpu/drm/msm/dp/dp_aux.c b/drivers/gpu/drm/msm/dp/dp_aux.c +index 8e3b677f35e64..559809a5cbcfb 100644 +--- a/drivers/gpu/drm/msm/dp/dp_aux.c ++++ b/drivers/gpu/drm/msm/dp/dp_aux.c +@@ -35,6 +35,7 @@ struct dp_aux_private { + bool no_send_stop; + bool initted; + bool is_edp; ++ bool enable_xfers; + u32 offset; + u32 segment; + +@@ -297,6 +298,17 @@ static ssize_t dp_aux_transfer(struct drm_dp_aux *dp_aux, + goto exit; + } + ++ /* ++ * If we're using DP and an external display isn't connected then the ++ * transfer won't succeed. Return right away. If we don't do this we ++ * can end up with long timeouts if someone tries to access the DP AUX ++ * character device when no DP device is connected. ++ */ ++ if (!aux->is_edp && !aux->enable_xfers) { ++ ret = -ENXIO; ++ goto exit; ++ } ++ + /* + * For eDP it's important to give a reasonably long wait here for HPD + * to be asserted. This is because the panel driver may have _just_ +@@ -428,6 +440,14 @@ irqreturn_t dp_aux_isr(struct drm_dp_aux *dp_aux) + return IRQ_HANDLED; + } + ++void dp_aux_enable_xfers(struct drm_dp_aux *dp_aux, bool enabled) ++{ ++ struct dp_aux_private *aux; ++ ++ aux = container_of(dp_aux, struct dp_aux_private, dp_aux); ++ aux->enable_xfers = enabled; ++} ++ + void dp_aux_reconfig(struct drm_dp_aux *dp_aux) + { + struct dp_aux_private *aux; +diff --git a/drivers/gpu/drm/msm/dp/dp_aux.h b/drivers/gpu/drm/msm/dp/dp_aux.h +index 511305da4f66d..f3052cb43306b 100644 +--- a/drivers/gpu/drm/msm/dp/dp_aux.h ++++ b/drivers/gpu/drm/msm/dp/dp_aux.h +@@ -12,6 +12,7 @@ + int dp_aux_register(struct drm_dp_aux *dp_aux); + void dp_aux_unregister(struct drm_dp_aux *dp_aux); + irqreturn_t dp_aux_isr(struct drm_dp_aux *dp_aux); ++void dp_aux_enable_xfers(struct drm_dp_aux *dp_aux, bool enabled); + void dp_aux_init(struct drm_dp_aux *dp_aux); + void dp_aux_deinit(struct drm_dp_aux *dp_aux); + void dp_aux_reconfig(struct drm_dp_aux *dp_aux); +diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c +index fb588fde298a2..780e9747be1fb 100644 +--- a/drivers/gpu/drm/msm/dp/dp_ctrl.c ++++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c +@@ -1019,14 +1019,14 @@ static int dp_ctrl_update_vx_px(struct dp_ctrl_private *ctrl) + if (ret) + return ret; + +- if (voltage_swing_level >= DP_TRAIN_VOLTAGE_SWING_MAX) { ++ if (voltage_swing_level >= DP_TRAIN_LEVEL_MAX) { + drm_dbg_dp(ctrl->drm_dev, + "max. voltage swing level reached %d\n", + voltage_swing_level); + max_level_reached |= DP_TRAIN_MAX_SWING_REACHED; + } + +- if (pre_emphasis_level >= DP_TRAIN_PRE_EMPHASIS_MAX) { ++ if (pre_emphasis_level >= DP_TRAIN_LEVEL_MAX) { + drm_dbg_dp(ctrl->drm_dev, + "max. pre-emphasis level reached %d\n", + pre_emphasis_level); +@@ -1117,7 +1117,7 @@ static int dp_ctrl_link_train_1(struct dp_ctrl_private *ctrl, + } + + if (ctrl->link->phy_params.v_level >= +- DP_TRAIN_VOLTAGE_SWING_MAX) { ++ DP_TRAIN_LEVEL_MAX) { + DRM_ERROR_RATELIMITED("max v_level reached\n"); + return -EAGAIN; + } +diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c +index eec5768aac727..ed77c957eceba 100644 +--- a/drivers/gpu/drm/msm/dp/dp_display.c ++++ b/drivers/gpu/drm/msm/dp/dp_display.c +@@ -586,6 +586,8 @@ static int dp_hpd_plug_handle(struct dp_display_private *dp, u32 data) + u32 state; + int ret; + ++ dp_aux_enable_xfers(dp->aux, true); ++ + mutex_lock(&dp->event_mutex); + + state = dp->hpd_state; +@@ -642,6 +644,8 @@ static int dp_hpd_unplug_handle(struct dp_display_private *dp, u32 data) + { + u32 state; + ++ dp_aux_enable_xfers(dp->aux, false); ++ + mutex_lock(&dp->event_mutex); + + state = dp->hpd_state; +diff --git a/drivers/gpu/drm/msm/dp/dp_link.c b/drivers/gpu/drm/msm/dp/dp_link.c +index 25950171caf3e..a198af7b2d449 100644 +--- a/drivers/gpu/drm/msm/dp/dp_link.c ++++ b/drivers/gpu/drm/msm/dp/dp_link.c +@@ -1141,6 +1141,7 @@ int dp_link_get_colorimetry_config(struct dp_link *dp_link) + int dp_link_adjust_levels(struct dp_link *dp_link, u8 *link_status) + { + int i; ++ u8 max_p_level; + int v_max = 0, p_max = 0; + struct dp_link_private *link; + +@@ -1172,30 +1173,29 @@ int dp_link_adjust_levels(struct dp_link *dp_link, u8 *link_status) + * Adjust the voltage swing and pre-emphasis level combination to within + * the allowable range. + */ +- if (dp_link->phy_params.v_level > DP_TRAIN_VOLTAGE_SWING_MAX) { ++ if (dp_link->phy_params.v_level > DP_TRAIN_LEVEL_MAX) { + drm_dbg_dp(link->drm_dev, + "Requested vSwingLevel=%d, change to %d\n", + dp_link->phy_params.v_level, +- DP_TRAIN_VOLTAGE_SWING_MAX); +- dp_link->phy_params.v_level = DP_TRAIN_VOLTAGE_SWING_MAX; ++ DP_TRAIN_LEVEL_MAX); ++ dp_link->phy_params.v_level = DP_TRAIN_LEVEL_MAX; + } + +- if (dp_link->phy_params.p_level > DP_TRAIN_PRE_EMPHASIS_MAX) { ++ if (dp_link->phy_params.p_level > DP_TRAIN_LEVEL_MAX) { + drm_dbg_dp(link->drm_dev, + "Requested preEmphasisLevel=%d, change to %d\n", + dp_link->phy_params.p_level, +- DP_TRAIN_PRE_EMPHASIS_MAX); +- dp_link->phy_params.p_level = DP_TRAIN_PRE_EMPHASIS_MAX; ++ DP_TRAIN_LEVEL_MAX); ++ dp_link->phy_params.p_level = DP_TRAIN_LEVEL_MAX; + } + +- if ((dp_link->phy_params.p_level > DP_TRAIN_PRE_EMPHASIS_LVL_1) +- && (dp_link->phy_params.v_level == +- DP_TRAIN_VOLTAGE_SWING_LVL_2)) { ++ max_p_level = DP_TRAIN_LEVEL_MAX - dp_link->phy_params.v_level; ++ if (dp_link->phy_params.p_level > max_p_level) { + drm_dbg_dp(link->drm_dev, + "Requested preEmphasisLevel=%d, change to %d\n", + dp_link->phy_params.p_level, +- DP_TRAIN_PRE_EMPHASIS_LVL_1); +- dp_link->phy_params.p_level = DP_TRAIN_PRE_EMPHASIS_LVL_1; ++ max_p_level); ++ dp_link->phy_params.p_level = max_p_level; + } + + drm_dbg_dp(link->drm_dev, "adjusted: v_level=%d, p_level=%d\n", +diff --git a/drivers/gpu/drm/msm/dp/dp_link.h b/drivers/gpu/drm/msm/dp/dp_link.h +index 9dd4dd9265304..79c3a02b8dacd 100644 +--- a/drivers/gpu/drm/msm/dp/dp_link.h ++++ b/drivers/gpu/drm/msm/dp/dp_link.h +@@ -19,19 +19,7 @@ struct dp_link_info { + unsigned long capabilities; + }; + +-enum dp_link_voltage_level { +- DP_TRAIN_VOLTAGE_SWING_LVL_0 = 0, +- DP_TRAIN_VOLTAGE_SWING_LVL_1 = 1, +- DP_TRAIN_VOLTAGE_SWING_LVL_2 = 2, +- DP_TRAIN_VOLTAGE_SWING_MAX = DP_TRAIN_VOLTAGE_SWING_LVL_2, +-}; +- +-enum dp_link_preemaphasis_level { +- DP_TRAIN_PRE_EMPHASIS_LVL_0 = 0, +- DP_TRAIN_PRE_EMPHASIS_LVL_1 = 1, +- DP_TRAIN_PRE_EMPHASIS_LVL_2 = 2, +- DP_TRAIN_PRE_EMPHASIS_MAX = DP_TRAIN_PRE_EMPHASIS_LVL_2, +-}; ++#define DP_TRAIN_LEVEL_MAX 3 + + struct dp_link_test_video { + u32 test_video_pattern; +diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c +index 470866896b9b8..ab393bdaba6cd 100644 +--- a/drivers/gpu/drm/msm/dsi/dsi_host.c ++++ b/drivers/gpu/drm/msm/dsi/dsi_host.c +@@ -366,8 +366,8 @@ int dsi_link_clk_set_rate_6g(struct msm_dsi_host *msm_host) + { + int ret; + +- DBG("Set clk rates: pclk=%d, byteclk=%lu", +- msm_host->mode->clock, msm_host->byte_clk_rate); ++ DBG("Set clk rates: pclk=%lu, byteclk=%lu", ++ msm_host->pixel_clk_rate, msm_host->byte_clk_rate); + + ret = dev_pm_opp_set_rate(&msm_host->pdev->dev, + msm_host->byte_clk_rate); +@@ -440,9 +440,9 @@ int dsi_link_clk_set_rate_v2(struct msm_dsi_host *msm_host) + { + int ret; + +- DBG("Set clk rates: pclk=%d, byteclk=%lu, esc_clk=%lu, dsi_src_clk=%lu", +- msm_host->mode->clock, msm_host->byte_clk_rate, +- msm_host->esc_clk_rate, msm_host->src_clk_rate); ++ DBG("Set clk rates: pclk=%lu, byteclk=%lu, esc_clk=%lu, dsi_src_clk=%lu", ++ msm_host->pixel_clk_rate, msm_host->byte_clk_rate, ++ msm_host->esc_clk_rate, msm_host->src_clk_rate); + + ret = clk_set_rate(msm_host->byte_clk, msm_host->byte_clk_rate); + if (ret) { +diff --git a/drivers/gpu/drm/mxsfb/lcdif_drv.c b/drivers/gpu/drm/mxsfb/lcdif_drv.c +index 18de2f17e2491..6494e82707569 100644 +--- a/drivers/gpu/drm/mxsfb/lcdif_drv.c ++++ b/drivers/gpu/drm/mxsfb/lcdif_drv.c +@@ -340,6 +340,9 @@ static int __maybe_unused lcdif_suspend(struct device *dev) + if (ret) + return ret; + ++ if (pm_runtime_suspended(dev)) ++ return 0; ++ + return lcdif_rpm_suspend(dev); + } + +@@ -347,7 +350,8 @@ static int __maybe_unused lcdif_resume(struct device *dev) + { + struct drm_device *drm = dev_get_drvdata(dev); + +- lcdif_rpm_resume(dev); ++ if (!pm_runtime_suspended(dev)) ++ lcdif_rpm_resume(dev); + + return drm_mode_config_helper_resume(drm); + } +diff --git a/drivers/gpu/drm/nouveau/nouveau_abi16.c b/drivers/gpu/drm/nouveau/nouveau_abi16.c +index 2edd7bb13faea..74b16e3913856 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_abi16.c ++++ b/drivers/gpu/drm/nouveau/nouveau_abi16.c +@@ -204,6 +204,7 @@ nouveau_abi16_ioctl_getparam(ABI16_IOCTL_ARGS) + struct nouveau_cli *cli = nouveau_cli(file_priv); + struct nouveau_drm *drm = nouveau_drm(dev); + struct nvif_device *device = &drm->client.device; ++ struct nvkm_device *nvkm_device = nvxx_device(&drm->client.device); + struct nvkm_gr *gr = nvxx_gr(device); + struct drm_nouveau_getparam *getparam = data; + struct pci_dev *pdev = to_pci_dev(dev->dev); +@@ -268,6 +269,17 @@ nouveau_abi16_ioctl_getparam(ABI16_IOCTL_ARGS) + getparam->value = nouveau_exec_push_max_from_ib_max(ib_max); + break; + } ++ case NOUVEAU_GETPARAM_VRAM_BAR_SIZE: ++ getparam->value = nvkm_device->func->resource_size(nvkm_device, 1); ++ break; ++ case NOUVEAU_GETPARAM_VRAM_USED: { ++ struct ttm_resource_manager *vram_mgr = ttm_manager_type(&drm->ttm.bdev, TTM_PL_VRAM); ++ getparam->value = (u64)ttm_resource_manager_usage(vram_mgr); ++ break; ++ } ++ case NOUVEAU_GETPARAM_HAS_VMA_TILEMODE: ++ getparam->value = 1; ++ break; + default: + NV_PRINTK(dbg, cli, "unknown parameter %lld\n", getparam->param); + return -EINVAL; +diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c +index 254d6c9ef2023..3a7f4ce34aa31 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_bo.c ++++ b/drivers/gpu/drm/nouveau/nouveau_bo.c +@@ -234,28 +234,28 @@ nouveau_bo_alloc(struct nouveau_cli *cli, u64 *size, int *align, u32 domain, + } + + nvbo->contig = !(tile_flags & NOUVEAU_GEM_TILE_NONCONTIG); +- if (!nouveau_cli_uvmm(cli) || internal) { +- /* for BO noVM allocs, don't assign kinds */ +- if (cli->device.info.family >= NV_DEVICE_INFO_V0_FERMI) { +- nvbo->kind = (tile_flags & 0x0000ff00) >> 8; +- if (!nvif_mmu_kind_valid(mmu, nvbo->kind)) { +- kfree(nvbo); +- return ERR_PTR(-EINVAL); +- } + +- nvbo->comp = mmu->kind[nvbo->kind] != nvbo->kind; +- } else if (cli->device.info.family >= NV_DEVICE_INFO_V0_TESLA) { +- nvbo->kind = (tile_flags & 0x00007f00) >> 8; +- nvbo->comp = (tile_flags & 0x00030000) >> 16; +- if (!nvif_mmu_kind_valid(mmu, nvbo->kind)) { +- kfree(nvbo); +- return ERR_PTR(-EINVAL); +- } +- } else { +- nvbo->zeta = (tile_flags & 0x00000007); ++ if (cli->device.info.family >= NV_DEVICE_INFO_V0_FERMI) { ++ nvbo->kind = (tile_flags & 0x0000ff00) >> 8; ++ if (!nvif_mmu_kind_valid(mmu, nvbo->kind)) { ++ kfree(nvbo); ++ return ERR_PTR(-EINVAL); ++ } ++ ++ nvbo->comp = mmu->kind[nvbo->kind] != nvbo->kind; ++ } else if (cli->device.info.family >= NV_DEVICE_INFO_V0_TESLA) { ++ nvbo->kind = (tile_flags & 0x00007f00) >> 8; ++ nvbo->comp = (tile_flags & 0x00030000) >> 16; ++ if (!nvif_mmu_kind_valid(mmu, nvbo->kind)) { ++ kfree(nvbo); ++ return ERR_PTR(-EINVAL); + } +- nvbo->mode = tile_mode; ++ } else { ++ nvbo->zeta = (tile_flags & 0x00000007); ++ } ++ nvbo->mode = tile_mode; + ++ if (!nouveau_cli_uvmm(cli) || internal) { + /* Determine the desirable target GPU page size for the buffer. */ + for (i = 0; i < vmm->page_nr; i++) { + /* Because we cannot currently allow VMM maps to fail +@@ -297,12 +297,6 @@ nouveau_bo_alloc(struct nouveau_cli *cli, u64 *size, int *align, u32 domain, + } + nvbo->page = vmm->page[pi].shift; + } else { +- /* reject other tile flags when in VM mode. */ +- if (tile_mode) +- return ERR_PTR(-EINVAL); +- if (tile_flags & ~NOUVEAU_GEM_TILE_NONCONTIG) +- return ERR_PTR(-EINVAL); +- + /* Determine the desirable target GPU page size for the buffer. */ + for (i = 0; i < vmm->page_nr; i++) { + /* Because we cannot currently allow VMM maps to fail +diff --git a/drivers/gpu/drm/omapdrm/Kconfig b/drivers/gpu/drm/omapdrm/Kconfig +index b715301ec79f6..6c49270cb290a 100644 +--- a/drivers/gpu/drm/omapdrm/Kconfig ++++ b/drivers/gpu/drm/omapdrm/Kconfig +@@ -4,7 +4,7 @@ config DRM_OMAP + depends on DRM && OF + depends on ARCH_OMAP2PLUS + select DRM_KMS_HELPER +- select FB_DMAMEM_HELPERS if DRM_FBDEV_EMULATION ++ select FB_DMAMEM_HELPERS_DEFERRED if DRM_FBDEV_EMULATION + select VIDEOMODE_HELPERS + select HDMI + default n +diff --git a/drivers/gpu/drm/omapdrm/omap_fbdev.c b/drivers/gpu/drm/omapdrm/omap_fbdev.c +index 6b08b137af1ad..523be34682caf 100644 +--- a/drivers/gpu/drm/omapdrm/omap_fbdev.c ++++ b/drivers/gpu/drm/omapdrm/omap_fbdev.c +@@ -51,6 +51,10 @@ static void pan_worker(struct work_struct *work) + omap_gem_roll(bo, fbi->var.yoffset * npages); + } + ++FB_GEN_DEFAULT_DEFERRED_DMAMEM_OPS(omap_fbdev, ++ drm_fb_helper_damage_range, ++ drm_fb_helper_damage_area) ++ + static int omap_fbdev_pan_display(struct fb_var_screeninfo *var, + struct fb_info *fbi) + { +@@ -78,11 +82,9 @@ static int omap_fbdev_pan_display(struct fb_var_screeninfo *var, + + static int omap_fbdev_fb_mmap(struct fb_info *info, struct vm_area_struct *vma) + { +- struct drm_fb_helper *helper = info->par; +- struct drm_framebuffer *fb = helper->fb; +- struct drm_gem_object *bo = drm_gem_fb_get_obj(fb, 0); ++ vma->vm_page_prot = pgprot_writecombine(vm_get_page_prot(vma->vm_flags)); + +- return drm_gem_mmap_obj(bo, omap_gem_mmap_size(bo), vma); ++ return fb_deferred_io_mmap(info, vma); + } + + static void omap_fbdev_fb_destroy(struct fb_info *info) +@@ -94,6 +96,7 @@ static void omap_fbdev_fb_destroy(struct fb_info *info) + + DBG(); + ++ fb_deferred_io_cleanup(info); + drm_fb_helper_fini(helper); + + omap_gem_unpin(bo); +@@ -104,15 +107,19 @@ static void omap_fbdev_fb_destroy(struct fb_info *info) + kfree(fbdev); + } + ++/* ++ * For now, we cannot use FB_DEFAULT_DEFERRED_OPS and fb_deferred_io_mmap() ++ * because we use write-combine. ++ */ + static const struct fb_ops omap_fb_ops = { + .owner = THIS_MODULE, +- __FB_DEFAULT_DMAMEM_OPS_RDWR, ++ __FB_DEFAULT_DEFERRED_OPS_RDWR(omap_fbdev), + .fb_check_var = drm_fb_helper_check_var, + .fb_set_par = drm_fb_helper_set_par, + .fb_setcmap = drm_fb_helper_setcmap, + .fb_blank = drm_fb_helper_blank, + .fb_pan_display = omap_fbdev_pan_display, +- __FB_DEFAULT_DMAMEM_OPS_DRAW, ++ __FB_DEFAULT_DEFERRED_OPS_DRAW(omap_fbdev), + .fb_ioctl = drm_fb_helper_ioctl, + .fb_mmap = omap_fbdev_fb_mmap, + .fb_destroy = omap_fbdev_fb_destroy, +@@ -213,6 +220,15 @@ static int omap_fbdev_create(struct drm_fb_helper *helper, + fbi->fix.smem_start = dma_addr; + fbi->fix.smem_len = bo->size; + ++ /* deferred I/O */ ++ helper->fbdefio.delay = HZ / 20; ++ helper->fbdefio.deferred_io = drm_fb_helper_deferred_io; ++ ++ fbi->fbdefio = &helper->fbdefio; ++ ret = fb_deferred_io_init(fbi); ++ if (ret) ++ goto fail; ++ + /* if we have DMM, then we can use it for scrolling by just + * shuffling pages around in DMM rather than doing sw blit. + */ +@@ -238,8 +254,20 @@ static int omap_fbdev_create(struct drm_fb_helper *helper, + return ret; + } + ++static int omap_fbdev_dirty(struct drm_fb_helper *helper, struct drm_clip_rect *clip) ++{ ++ if (!(clip->x1 < clip->x2 && clip->y1 < clip->y2)) ++ return 0; ++ ++ if (helper->fb->funcs->dirty) ++ return helper->fb->funcs->dirty(helper->fb, NULL, 0, 0, clip, 1); ++ ++ return 0; ++} ++ + static const struct drm_fb_helper_funcs omap_fb_helper_funcs = { + .fb_probe = omap_fbdev_create, ++ .fb_dirty = omap_fbdev_dirty, + }; + + static struct drm_fb_helper *get_fb(struct fb_info *fbi) +diff --git a/drivers/gpu/drm/panel/panel-edp.c b/drivers/gpu/drm/panel/panel-edp.c +index 70feee7876114..94fe2f3836a9a 100644 +--- a/drivers/gpu/drm/panel/panel-edp.c ++++ b/drivers/gpu/drm/panel/panel-edp.c +@@ -397,6 +397,7 @@ static int panel_edp_suspend(struct device *dev) + { + struct panel_edp *p = dev_get_drvdata(dev); + ++ drm_dp_dpcd_set_powered(p->aux, false); + gpiod_set_value_cansleep(p->enable_gpio, 0); + regulator_disable(p->supply); + p->unprepared_time = ktime_get_boottime(); +@@ -453,6 +454,7 @@ static int panel_edp_prepare_once(struct panel_edp *p) + } + + gpiod_set_value_cansleep(p->enable_gpio, 1); ++ drm_dp_dpcd_set_powered(p->aux, true); + + delay = p->desc->delay.hpd_reliable; + if (p->no_hpd) +@@ -489,6 +491,7 @@ static int panel_edp_prepare_once(struct panel_edp *p) + return 0; + + error: ++ drm_dp_dpcd_set_powered(p->aux, false); + gpiod_set_value_cansleep(p->enable_gpio, 0); + regulator_disable(p->supply); + p->unprepared_time = ktime_get_boottime(); +diff --git a/drivers/gpu/drm/panel/panel-novatek-nt35950.c b/drivers/gpu/drm/panel/panel-novatek-nt35950.c +index 412ca84d05811..4be5013330ec2 100644 +--- a/drivers/gpu/drm/panel/panel-novatek-nt35950.c ++++ b/drivers/gpu/drm/panel/panel-novatek-nt35950.c +@@ -565,10 +565,8 @@ static int nt35950_probe(struct mipi_dsi_device *dsi) + } + dsi_r_host = of_find_mipi_dsi_host_by_node(dsi_r); + of_node_put(dsi_r); +- if (!dsi_r_host) { +- dev_err(dev, "Cannot get secondary DSI host\n"); +- return -EPROBE_DEFER; +- } ++ if (!dsi_r_host) ++ return dev_err_probe(dev, -EPROBE_DEFER, "Cannot get secondary DSI host\n"); + + nt->dsi[1] = mipi_dsi_device_register_full(dsi_r_host, info); + if (!nt->dsi[1]) { +diff --git a/drivers/gpu/drm/panel/panel-samsung-atna33xc20.c b/drivers/gpu/drm/panel/panel-samsung-atna33xc20.c +index 5703f4712d96e..9c336c71562b9 100644 +--- a/drivers/gpu/drm/panel/panel-samsung-atna33xc20.c ++++ b/drivers/gpu/drm/panel/panel-samsung-atna33xc20.c +@@ -72,6 +72,7 @@ static int atana33xc20_suspend(struct device *dev) + if (p->el3_was_on) + atana33xc20_wait(p->el_on3_off_time, 150); + ++ drm_dp_dpcd_set_powered(p->aux, false); + ret = regulator_disable(p->supply); + if (ret) + return ret; +@@ -93,6 +94,7 @@ static int atana33xc20_resume(struct device *dev) + ret = regulator_enable(p->supply); + if (ret) + return ret; ++ drm_dp_dpcd_set_powered(p->aux, true); + p->powered_on_time = ktime_get_boottime(); + + if (p->no_hpd) { +@@ -107,19 +109,17 @@ static int atana33xc20_resume(struct device *dev) + if (hpd_asserted < 0) + ret = hpd_asserted; + +- if (ret) ++ if (ret) { + dev_warn(dev, "Error waiting for HPD GPIO: %d\n", ret); +- +- return ret; +- } +- +- if (p->aux->wait_hpd_asserted) { ++ goto error; ++ } ++ } else if (p->aux->wait_hpd_asserted) { + ret = p->aux->wait_hpd_asserted(p->aux, HPD_MAX_US); + +- if (ret) ++ if (ret) { + dev_warn(dev, "Controller error waiting for HPD: %d\n", ret); +- +- return ret; ++ goto error; ++ } + } + + /* +@@ -131,6 +131,12 @@ static int atana33xc20_resume(struct device *dev) + * right times. + */ + return 0; ++ ++error: ++ drm_dp_dpcd_set_powered(p->aux, false); ++ regulator_disable(p->supply); ++ ++ return ret; + } + + static int atana33xc20_disable(struct drm_panel *panel) +diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c +index 51f838befb321..e8d12ec8dbec1 100644 +--- a/drivers/gpu/drm/panel/panel-simple.c ++++ b/drivers/gpu/drm/panel/panel-simple.c +@@ -2407,6 +2407,9 @@ static const struct panel_desc innolux_g121x1_l03 = { + .unprepare = 200, + .disable = 400, + }, ++ .bus_format = MEDIA_BUS_FMT_RGB666_1X7X3_SPWG, ++ .bus_flags = DRM_BUS_FLAG_DE_HIGH, ++ .connector_type = DRM_MODE_CONNECTOR_LVDS, + }; + + static const struct display_timing innolux_g156hce_l01_timings = { +diff --git a/drivers/gpu/drm/panel/panel-sitronix-st7789v.c b/drivers/gpu/drm/panel/panel-sitronix-st7789v.c +index 88e80fe98112d..e8f385b9c6182 100644 +--- a/drivers/gpu/drm/panel/panel-sitronix-st7789v.c ++++ b/drivers/gpu/drm/panel/panel-sitronix-st7789v.c +@@ -282,15 +282,15 @@ static const struct drm_display_mode et028013dma_mode = { + static const struct drm_display_mode jt240mhqs_hwt_ek_e3_mode = { + .clock = 6000, + .hdisplay = 240, +- .hsync_start = 240 + 28, +- .hsync_end = 240 + 28 + 10, +- .htotal = 240 + 28 + 10 + 10, ++ .hsync_start = 240 + 38, ++ .hsync_end = 240 + 38 + 10, ++ .htotal = 240 + 38 + 10 + 10, + .vdisplay = 280, +- .vsync_start = 280 + 8, +- .vsync_end = 280 + 8 + 4, +- .vtotal = 280 + 8 + 4 + 4, +- .width_mm = 43, +- .height_mm = 37, ++ .vsync_start = 280 + 48, ++ .vsync_end = 280 + 48 + 4, ++ .vtotal = 280 + 48 + 4 + 4, ++ .width_mm = 37, ++ .height_mm = 43, + .flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC, + }; + +diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +index c306806aa3dea..c5ec4169616de 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c ++++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +@@ -609,6 +609,8 @@ static void vop2_setup_scale(struct vop2 *vop2, const struct vop2_win *win, + const struct drm_format_info *info; + u16 hor_scl_mode, ver_scl_mode; + u16 hscl_filter_mode, vscl_filter_mode; ++ uint16_t cbcr_src_w = src_w; ++ uint16_t cbcr_src_h = src_h; + u8 gt2 = 0; + u8 gt4 = 0; + u32 val; +@@ -666,27 +668,27 @@ static void vop2_setup_scale(struct vop2 *vop2, const struct vop2_win *win, + vop2_win_write(win, VOP2_WIN_YRGB_VSCL_FILTER_MODE, vscl_filter_mode); + + if (info->is_yuv) { +- src_w /= info->hsub; +- src_h /= info->vsub; ++ cbcr_src_w /= info->hsub; ++ cbcr_src_h /= info->vsub; + + gt4 = 0; + gt2 = 0; + +- if (src_h >= (4 * dst_h)) { ++ if (cbcr_src_h >= (4 * dst_h)) { + gt4 = 1; +- src_h >>= 2; +- } else if (src_h >= (2 * dst_h)) { ++ cbcr_src_h >>= 2; ++ } else if (cbcr_src_h >= (2 * dst_h)) { + gt2 = 1; +- src_h >>= 1; ++ cbcr_src_h >>= 1; + } + +- hor_scl_mode = scl_get_scl_mode(src_w, dst_w); +- ver_scl_mode = scl_get_scl_mode(src_h, dst_h); ++ hor_scl_mode = scl_get_scl_mode(cbcr_src_w, dst_w); ++ ver_scl_mode = scl_get_scl_mode(cbcr_src_h, dst_h); + +- val = vop2_scale_factor(src_w, dst_w); ++ val = vop2_scale_factor(cbcr_src_w, dst_w); + vop2_win_write(win, VOP2_WIN_SCALE_CBCR_X, val); + +- val = vop2_scale_factor(src_h, dst_h); ++ val = vop2_scale_factor(cbcr_src_h, dst_h); + vop2_win_write(win, VOP2_WIN_SCALE_CBCR_Y, val); + + vop2_win_write(win, VOP2_WIN_VSD_CBCR_GT4, gt4); +diff --git a/drivers/gpu/drm/solomon/ssd130x.c b/drivers/gpu/drm/solomon/ssd130x.c +index 78272b1f9d5b1..deec6acdcf646 100644 +--- a/drivers/gpu/drm/solomon/ssd130x.c ++++ b/drivers/gpu/drm/solomon/ssd130x.c +@@ -267,7 +267,7 @@ static int ssd130x_pwm_enable(struct ssd130x_device *ssd130x) + + pwm_init_state(ssd130x->pwm, &pwmstate); + pwm_set_relative_duty_cycle(&pwmstate, 50, 100); +- pwm_apply_state(ssd130x->pwm, &pwmstate); ++ pwm_apply_might_sleep(ssd130x->pwm, &pwmstate); + + /* Enable the PWM */ + pwm_enable(ssd130x->pwm); +diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c +index 4626fe9aac563..643754fa6a8ad 100644 +--- a/drivers/gpu/drm/vc4/vc4_hdmi.c ++++ b/drivers/gpu/drm/vc4/vc4_hdmi.c +@@ -2729,6 +2729,8 @@ static int vc4_hdmi_audio_init(struct vc4_hdmi *vc4_hdmi) + index = 1; + + addr = of_get_address(dev->of_node, index, NULL, NULL); ++ if (!addr) ++ return -EINVAL; + + vc4_hdmi->audio.dma_data.addr = be32_to_cpup(addr) + mai_data->offset; + vc4_hdmi->audio.dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; +diff --git a/drivers/gpu/drm/xlnx/zynqmp_dpsub.c b/drivers/gpu/drm/xlnx/zynqmp_dpsub.c +index 88eb33acd5f0d..face8d6b2a6fb 100644 +--- a/drivers/gpu/drm/xlnx/zynqmp_dpsub.c ++++ b/drivers/gpu/drm/xlnx/zynqmp_dpsub.c +@@ -256,12 +256,12 @@ static int zynqmp_dpsub_probe(struct platform_device *pdev) + if (ret) + goto err_dp; + ++ drm_bridge_add(dpsub->bridge); ++ + if (dpsub->dma_enabled) { + ret = zynqmp_dpsub_drm_init(dpsub); + if (ret) + goto err_disp; +- } else { +- drm_bridge_add(dpsub->bridge); + } + + dev_info(&pdev->dev, "ZynqMP DisplayPort Subsystem driver probed"); +@@ -288,9 +288,8 @@ static void zynqmp_dpsub_remove(struct platform_device *pdev) + + if (dpsub->drm) + zynqmp_dpsub_drm_cleanup(dpsub); +- else +- drm_bridge_remove(dpsub->bridge); + ++ drm_bridge_remove(dpsub->bridge); + zynqmp_disp_remove(dpsub); + zynqmp_dp_remove(dpsub); + +diff --git a/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_init.c b/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_init.c +index e9c6413af24a0..862ca8d072326 100644 +--- a/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_init.c ++++ b/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_init.c +@@ -210,6 +210,11 @@ static void amd_sfh_resume(struct amd_mp2_dev *mp2) + struct amd_mp2_sensor_info info; + int i, status; + ++ if (!cl_data->is_any_sensor_enabled) { ++ amd_sfh_clear_intr(mp2); ++ return; ++ } ++ + for (i = 0; i < cl_data->num_hid_devices; i++) { + if (cl_data->sensor_sts[i] == SENSOR_DISABLED) { + info.sensor_idx = cl_data->sensor_idx[i]; +@@ -235,6 +240,11 @@ static void amd_sfh_suspend(struct amd_mp2_dev *mp2) + struct amdtp_cl_data *cl_data = mp2->cl_data; + int i, status; + ++ if (!cl_data->is_any_sensor_enabled) { ++ amd_sfh_clear_intr(mp2); ++ return; ++ } ++ + for (i = 0; i < cl_data->num_hid_devices; i++) { + if (cl_data->sensor_idx[i] != HPD_IDX && + cl_data->sensor_sts[i] == SENSOR_ENABLED) { +diff --git a/drivers/hid/hid-mcp2221.c b/drivers/hid/hid-mcp2221.c +index aef0785c91cc2..c5bfca8ac5e6e 100644 +--- a/drivers/hid/hid-mcp2221.c ++++ b/drivers/hid/hid-mcp2221.c +@@ -922,9 +922,11 @@ static void mcp2221_hid_unregister(void *ptr) + /* This is needed to be sure hid_hw_stop() isn't called twice by the subsystem */ + static void mcp2221_remove(struct hid_device *hdev) + { ++#if IS_REACHABLE(CONFIG_IIO) + struct mcp2221 *mcp = hid_get_drvdata(hdev); + + cancel_delayed_work_sync(&mcp->init_work); ++#endif + } + + #if IS_REACHABLE(CONFIG_IIO) +diff --git a/drivers/hid/intel-ish-hid/ipc/pci-ish.c b/drivers/hid/intel-ish-hid/ipc/pci-ish.c +index 710fda5f19e1c..916d427163ca2 100644 +--- a/drivers/hid/intel-ish-hid/ipc/pci-ish.c ++++ b/drivers/hid/intel-ish-hid/ipc/pci-ish.c +@@ -216,6 +216,11 @@ static int ish_probe(struct pci_dev *pdev, const struct pci_device_id *ent) + + /* request and enable interrupt */ + ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES); ++ if (ret < 0) { ++ dev_err(dev, "ISH: Failed to allocate IRQ vectors\n"); ++ return ret; ++ } ++ + if (!pdev->msi_enabled && !pdev->msix_enabled) + irq_flag = IRQF_SHARED; + +diff --git a/drivers/hwmon/intel-m10-bmc-hwmon.c b/drivers/hwmon/intel-m10-bmc-hwmon.c +index 6500ca548f9c7..ca2dff1589251 100644 +--- a/drivers/hwmon/intel-m10-bmc-hwmon.c ++++ b/drivers/hwmon/intel-m10-bmc-hwmon.c +@@ -429,7 +429,7 @@ static const struct m10bmc_sdata n6000bmc_curr_tbl[] = { + }; + + static const struct m10bmc_sdata n6000bmc_power_tbl[] = { +- { 0x724, 0x0, 0x0, 0x0, 0x0, 1, "Board Power" }, ++ { 0x724, 0x0, 0x0, 0x0, 0x0, 1000, "Board Power" }, + }; + + static const struct hwmon_channel_info * const n6000bmc_hinfo[] = { +diff --git a/drivers/hwmon/pwm-fan.c b/drivers/hwmon/pwm-fan.c +index 6e4516c2ab894..b67bc9e833c01 100644 +--- a/drivers/hwmon/pwm-fan.c ++++ b/drivers/hwmon/pwm-fan.c +@@ -151,7 +151,7 @@ static int pwm_fan_power_on(struct pwm_fan_ctx *ctx) + } + + state->enabled = true; +- ret = pwm_apply_state(ctx->pwm, state); ++ ret = pwm_apply_might_sleep(ctx->pwm, state); + if (ret) { + dev_err(ctx->dev, "failed to enable PWM\n"); + goto disable_regulator; +@@ -181,7 +181,7 @@ static int pwm_fan_power_off(struct pwm_fan_ctx *ctx) + + state->enabled = false; + state->duty_cycle = 0; +- ret = pwm_apply_state(ctx->pwm, state); ++ ret = pwm_apply_might_sleep(ctx->pwm, state); + if (ret) { + dev_err(ctx->dev, "failed to disable PWM\n"); + return ret; +@@ -207,7 +207,7 @@ static int __set_pwm(struct pwm_fan_ctx *ctx, unsigned long pwm) + + period = state->period; + state->duty_cycle = DIV_ROUND_UP(pwm * (period - 1), MAX_PWM); +- ret = pwm_apply_state(ctx->pwm, state); ++ ret = pwm_apply_might_sleep(ctx->pwm, state); + if (ret) + return ret; + ret = pwm_fan_power_on(ctx); +@@ -278,7 +278,7 @@ static int pwm_fan_update_enable(struct pwm_fan_ctx *ctx, long val) + state, + &enable_regulator); + +- pwm_apply_state(ctx->pwm, state); ++ pwm_apply_might_sleep(ctx->pwm, state); + pwm_fan_switch_power(ctx, enable_regulator); + pwm_fan_update_state(ctx, 0); + } +diff --git a/drivers/hwmon/shtc1.c b/drivers/hwmon/shtc1.c +index 1f96e94967ee8..439dd3dba5fc8 100644 +--- a/drivers/hwmon/shtc1.c ++++ b/drivers/hwmon/shtc1.c +@@ -238,7 +238,7 @@ static int shtc1_probe(struct i2c_client *client) + + if (np) { + data->setup.blocking_io = of_property_read_bool(np, "sensirion,blocking-io"); +- data->setup.high_precision = !of_property_read_bool(np, "sensicon,low-precision"); ++ data->setup.high_precision = !of_property_read_bool(np, "sensirion,low-precision"); + } else { + if (client->dev.platform_data) + data->setup = *(struct shtc1_platform_data *)dev->platform_data; +diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c +index 18c4544f60454..840e4cccf8c4b 100644 +--- a/drivers/hwtracing/coresight/coresight-etm4x-core.c ++++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c +@@ -1204,6 +1204,8 @@ static void etm4_init_arch_data(void *info) + drvdata->nr_event = FIELD_GET(TRCIDR0_NUMEVENT_MASK, etmidr0); + /* QSUPP, bits[16:15] Q element support field */ + drvdata->q_support = FIELD_GET(TRCIDR0_QSUPP_MASK, etmidr0); ++ if (drvdata->q_support) ++ drvdata->q_filt = !!(etmidr0 & TRCIDR0_QFILT); + /* TSSIZE, bits[28:24] Global timestamp size field */ + drvdata->ts_size = FIELD_GET(TRCIDR0_TSSIZE_MASK, etmidr0); + +@@ -1694,16 +1696,14 @@ static int __etm4_cpu_save(struct etmv4_drvdata *drvdata) + state->trcccctlr = etm4x_read32(csa, TRCCCCTLR); + state->trcbbctlr = etm4x_read32(csa, TRCBBCTLR); + state->trctraceidr = etm4x_read32(csa, TRCTRACEIDR); +- state->trcqctlr = etm4x_read32(csa, TRCQCTLR); ++ if (drvdata->q_filt) ++ state->trcqctlr = etm4x_read32(csa, TRCQCTLR); + + state->trcvictlr = etm4x_read32(csa, TRCVICTLR); + state->trcviiectlr = etm4x_read32(csa, TRCVIIECTLR); + state->trcvissctlr = etm4x_read32(csa, TRCVISSCTLR); + if (drvdata->nr_pe_cmp) + state->trcvipcssctlr = etm4x_read32(csa, TRCVIPCSSCTLR); +- state->trcvdctlr = etm4x_read32(csa, TRCVDCTLR); +- state->trcvdsacctlr = etm4x_read32(csa, TRCVDSACCTLR); +- state->trcvdarcctlr = etm4x_read32(csa, TRCVDARCCTLR); + + for (i = 0; i < drvdata->nrseqstate - 1; i++) + state->trcseqevr[i] = etm4x_read32(csa, TRCSEQEVRn(i)); +@@ -1720,7 +1720,8 @@ static int __etm4_cpu_save(struct etmv4_drvdata *drvdata) + state->trccntvr[i] = etm4x_read32(csa, TRCCNTVRn(i)); + } + +- for (i = 0; i < drvdata->nr_resource * 2; i++) ++ /* Resource selector pair 0 is reserved */ ++ for (i = 2; i < drvdata->nr_resource * 2; i++) + state->trcrsctlr[i] = etm4x_read32(csa, TRCRSCTLRn(i)); + + for (i = 0; i < drvdata->nr_ss_cmp; i++) { +@@ -1805,8 +1806,10 @@ static void __etm4_cpu_restore(struct etmv4_drvdata *drvdata) + { + int i; + struct etmv4_save_state *state = drvdata->save_state; +- struct csdev_access tmp_csa = CSDEV_ACCESS_IOMEM(drvdata->base); +- struct csdev_access *csa = &tmp_csa; ++ struct csdev_access *csa = &drvdata->csdev->access; ++ ++ if (WARN_ON(!drvdata->csdev)) ++ return; + + etm4_cs_unlock(drvdata, csa); + etm4x_relaxed_write32(csa, state->trcclaimset, TRCCLAIMSET); +@@ -1825,16 +1828,14 @@ static void __etm4_cpu_restore(struct etmv4_drvdata *drvdata) + etm4x_relaxed_write32(csa, state->trcccctlr, TRCCCCTLR); + etm4x_relaxed_write32(csa, state->trcbbctlr, TRCBBCTLR); + etm4x_relaxed_write32(csa, state->trctraceidr, TRCTRACEIDR); +- etm4x_relaxed_write32(csa, state->trcqctlr, TRCQCTLR); ++ if (drvdata->q_filt) ++ etm4x_relaxed_write32(csa, state->trcqctlr, TRCQCTLR); + + etm4x_relaxed_write32(csa, state->trcvictlr, TRCVICTLR); + etm4x_relaxed_write32(csa, state->trcviiectlr, TRCVIIECTLR); + etm4x_relaxed_write32(csa, state->trcvissctlr, TRCVISSCTLR); + if (drvdata->nr_pe_cmp) + etm4x_relaxed_write32(csa, state->trcvipcssctlr, TRCVIPCSSCTLR); +- etm4x_relaxed_write32(csa, state->trcvdctlr, TRCVDCTLR); +- etm4x_relaxed_write32(csa, state->trcvdsacctlr, TRCVDSACCTLR); +- etm4x_relaxed_write32(csa, state->trcvdarcctlr, TRCVDARCCTLR); + + for (i = 0; i < drvdata->nrseqstate - 1; i++) + etm4x_relaxed_write32(csa, state->trcseqevr[i], TRCSEQEVRn(i)); +@@ -1851,7 +1852,8 @@ static void __etm4_cpu_restore(struct etmv4_drvdata *drvdata) + etm4x_relaxed_write32(csa, state->trccntvr[i], TRCCNTVRn(i)); + } + +- for (i = 0; i < drvdata->nr_resource * 2; i++) ++ /* Resource selector pair 0 is reserved */ ++ for (i = 2; i < drvdata->nr_resource * 2; i++) + etm4x_relaxed_write32(csa, state->trcrsctlr[i], TRCRSCTLRn(i)); + + for (i = 0; i < drvdata->nr_ss_cmp; i++) { +@@ -2175,6 +2177,9 @@ static int etm4_probe_platform_dev(struct platform_device *pdev) + ret = etm4_probe(&pdev->dev); + + pm_runtime_put(&pdev->dev); ++ if (ret) ++ pm_runtime_disable(&pdev->dev); ++ + return ret; + } + +diff --git a/drivers/hwtracing/coresight/coresight-etm4x.h b/drivers/hwtracing/coresight/coresight-etm4x.h +index da17b6c49b0f1..6b6760e49ed35 100644 +--- a/drivers/hwtracing/coresight/coresight-etm4x.h ++++ b/drivers/hwtracing/coresight/coresight-etm4x.h +@@ -43,9 +43,6 @@ + #define TRCVIIECTLR 0x084 + #define TRCVISSCTLR 0x088 + #define TRCVIPCSSCTLR 0x08C +-#define TRCVDCTLR 0x0A0 +-#define TRCVDSACCTLR 0x0A4 +-#define TRCVDARCCTLR 0x0A8 + /* Derived resources registers */ + #define TRCSEQEVRn(n) (0x100 + (n * 4)) /* n = 0-2 */ + #define TRCSEQRSTEVR 0x118 +@@ -90,9 +87,6 @@ + /* Address Comparator registers n = 0-15 */ + #define TRCACVRn(n) (0x400 + (n * 8)) + #define TRCACATRn(n) (0x480 + (n * 8)) +-/* Data Value Comparator Value registers, n = 0-7 */ +-#define TRCDVCVRn(n) (0x500 + (n * 16)) +-#define TRCDVCMRn(n) (0x580 + (n * 16)) + /* ContextID/Virtual ContextID comparators, n = 0-7 */ + #define TRCCIDCVRn(n) (0x600 + (n * 8)) + #define TRCVMIDCVRn(n) (0x640 + (n * 8)) +@@ -141,6 +135,7 @@ + #define TRCIDR0_TRCCCI BIT(7) + #define TRCIDR0_RETSTACK BIT(9) + #define TRCIDR0_NUMEVENT_MASK GENMASK(11, 10) ++#define TRCIDR0_QFILT BIT(14) + #define TRCIDR0_QSUPP_MASK GENMASK(16, 15) + #define TRCIDR0_TSSIZE_MASK GENMASK(28, 24) + +@@ -272,9 +267,6 @@ + /* List of registers accessible via System instructions */ + #define ETM4x_ONLY_SYSREG_LIST(op, val) \ + CASE_##op((val), TRCPROCSELR) \ +- CASE_##op((val), TRCVDCTLR) \ +- CASE_##op((val), TRCVDSACCTLR) \ +- CASE_##op((val), TRCVDARCCTLR) \ + CASE_##op((val), TRCOSLAR) + + #define ETM_COMMON_SYSREG_LIST(op, val) \ +@@ -422,22 +414,6 @@ + CASE_##op((val), TRCACATRn(13)) \ + CASE_##op((val), TRCACATRn(14)) \ + CASE_##op((val), TRCACATRn(15)) \ +- CASE_##op((val), TRCDVCVRn(0)) \ +- CASE_##op((val), TRCDVCVRn(1)) \ +- CASE_##op((val), TRCDVCVRn(2)) \ +- CASE_##op((val), TRCDVCVRn(3)) \ +- CASE_##op((val), TRCDVCVRn(4)) \ +- CASE_##op((val), TRCDVCVRn(5)) \ +- CASE_##op((val), TRCDVCVRn(6)) \ +- CASE_##op((val), TRCDVCVRn(7)) \ +- CASE_##op((val), TRCDVCMRn(0)) \ +- CASE_##op((val), TRCDVCMRn(1)) \ +- CASE_##op((val), TRCDVCMRn(2)) \ +- CASE_##op((val), TRCDVCMRn(3)) \ +- CASE_##op((val), TRCDVCMRn(4)) \ +- CASE_##op((val), TRCDVCMRn(5)) \ +- CASE_##op((val), TRCDVCMRn(6)) \ +- CASE_##op((val), TRCDVCMRn(7)) \ + CASE_##op((val), TRCCIDCVRn(0)) \ + CASE_##op((val), TRCCIDCVRn(1)) \ + CASE_##op((val), TRCCIDCVRn(2)) \ +@@ -907,9 +883,6 @@ struct etmv4_save_state { + u32 trcviiectlr; + u32 trcvissctlr; + u32 trcvipcssctlr; +- u32 trcvdctlr; +- u32 trcvdsacctlr; +- u32 trcvdarcctlr; + + u32 trcseqevr[ETM_MAX_SEQ_STATES]; + u32 trcseqrstevr; +@@ -982,6 +955,7 @@ struct etmv4_save_state { + * @os_unlock: True if access to management registers is allowed. + * @instrp0: Tracing of load and store instructions + * as P0 elements is supported. ++ * @q_filt: Q element filtering support, if Q elements are supported. + * @trcbb: Indicates if the trace unit supports branch broadcast tracing. + * @trccond: If the trace unit supports conditional + * instruction tracing. +@@ -1045,6 +1019,7 @@ struct etmv4_drvdata { + bool boot_enable; + bool os_unlock; + bool instrp0; ++ bool q_filt; + bool trcbb; + bool trccond; + bool retstack; +diff --git a/drivers/hwtracing/stm/core.c b/drivers/hwtracing/stm/core.c +index 534fbefc7f6aa..20895d3915623 100644 +--- a/drivers/hwtracing/stm/core.c ++++ b/drivers/hwtracing/stm/core.c +@@ -868,8 +868,11 @@ int stm_register_device(struct device *parent, struct stm_data *stm_data, + return -ENOMEM; + + stm->major = register_chrdev(0, stm_data->name, &stm_fops); +- if (stm->major < 0) +- goto err_free; ++ if (stm->major < 0) { ++ err = stm->major; ++ vfree(stm); ++ return err; ++ } + + device_initialize(&stm->dev); + stm->dev.devt = MKDEV(stm->major, 0); +@@ -913,10 +916,8 @@ int stm_register_device(struct device *parent, struct stm_data *stm_data, + err_device: + unregister_chrdev(stm->major, stm_data->name); + +- /* matches device_initialize() above */ ++ /* calls stm_device_release() */ + put_device(&stm->dev); +-err_free: +- vfree(stm); + + return err; + } +diff --git a/drivers/i2c/busses/i2c-cadence.c b/drivers/i2c/busses/i2c-cadence.c +index de3f58b60dce5..6f7d753a8197c 100644 +--- a/drivers/i2c/busses/i2c-cadence.c ++++ b/drivers/i2c/busses/i2c-cadence.c +@@ -633,6 +633,7 @@ static void cdns_i2c_mrecv(struct cdns_i2c *id) + + if (hold_clear) { + ctrl_reg &= ~CDNS_I2C_CR_HOLD; ++ ctrl_reg &= ~CDNS_I2C_CR_CLR_FIFO; + /* + * In case of Xilinx Zynq SOC, clear the HOLD bit before transfer size + * register reaches '0'. This is an IP bug which causes transfer size +diff --git a/drivers/i2c/busses/i2c-synquacer.c b/drivers/i2c/busses/i2c-synquacer.c +index bbea521b05dda..a73f5bb9a1645 100644 +--- a/drivers/i2c/busses/i2c-synquacer.c ++++ b/drivers/i2c/busses/i2c-synquacer.c +@@ -550,17 +550,13 @@ static int synquacer_i2c_probe(struct platform_device *pdev) + device_property_read_u32(&pdev->dev, "socionext,pclk-rate", + &i2c->pclkrate); + +- i2c->pclk = devm_clk_get(&pdev->dev, "pclk"); +- if (PTR_ERR(i2c->pclk) == -EPROBE_DEFER) +- return -EPROBE_DEFER; +- if (!IS_ERR_OR_NULL(i2c->pclk)) { +- dev_dbg(&pdev->dev, "clock source %p\n", i2c->pclk); +- +- ret = clk_prepare_enable(i2c->pclk); +- if (ret) +- return dev_err_probe(&pdev->dev, ret, "failed to enable clock\n"); +- i2c->pclkrate = clk_get_rate(i2c->pclk); +- } ++ i2c->pclk = devm_clk_get_enabled(&pdev->dev, "pclk"); ++ if (IS_ERR(i2c->pclk)) ++ return dev_err_probe(&pdev->dev, PTR_ERR(i2c->pclk), ++ "failed to get and enable clock\n"); ++ ++ dev_dbg(&pdev->dev, "clock source %p\n", i2c->pclk); ++ i2c->pclkrate = clk_get_rate(i2c->pclk); + + if (i2c->pclkrate < SYNQUACER_I2C_MIN_CLK_RATE || + i2c->pclkrate > SYNQUACER_I2C_MAX_CLK_RATE) +@@ -615,8 +611,6 @@ static void synquacer_i2c_remove(struct platform_device *pdev) + struct synquacer_i2c *i2c = platform_get_drvdata(pdev); + + i2c_del_adapter(&i2c->adapter); +- if (!IS_ERR(i2c->pclk)) +- clk_disable_unprepare(i2c->pclk); + }; + + static const struct of_device_id synquacer_i2c_dt_ids[] __maybe_unused = { +diff --git a/drivers/i3c/master/svc-i3c-master.c b/drivers/i3c/master/svc-i3c-master.c +index c395e52294140..e18bf9ca85197 100644 +--- a/drivers/i3c/master/svc-i3c-master.c ++++ b/drivers/i3c/master/svc-i3c-master.c +@@ -134,7 +134,8 @@ struct svc_i3c_cmd { + u8 *in; + const void *out; + unsigned int len; +- unsigned int read_len; ++ unsigned int actual_len; ++ struct i3c_priv_xfer *xfer; + bool continued; + }; + +@@ -1024,7 +1025,7 @@ static int svc_i3c_master_write(struct svc_i3c_master *master, + static int svc_i3c_master_xfer(struct svc_i3c_master *master, + bool rnw, unsigned int xfer_type, u8 addr, + u8 *in, const u8 *out, unsigned int xfer_len, +- unsigned int *read_len, bool continued) ++ unsigned int *actual_len, bool continued) + { + u32 reg; + int ret; +@@ -1037,7 +1038,7 @@ static int svc_i3c_master_xfer(struct svc_i3c_master *master, + SVC_I3C_MCTRL_IBIRESP_NACK | + SVC_I3C_MCTRL_DIR(rnw) | + SVC_I3C_MCTRL_ADDR(addr) | +- SVC_I3C_MCTRL_RDTERM(*read_len), ++ SVC_I3C_MCTRL_RDTERM(*actual_len), + master->regs + SVC_I3C_MCTRL); + + ret = readl_poll_timeout(master->regs + SVC_I3C_MSTATUS, reg, +@@ -1047,6 +1048,7 @@ static int svc_i3c_master_xfer(struct svc_i3c_master *master, + + if (readl(master->regs + SVC_I3C_MERRWARN) & SVC_I3C_MERRWARN_NACK) { + ret = -ENXIO; ++ *actual_len = 0; + goto emit_stop; + } + +@@ -1063,7 +1065,8 @@ static int svc_i3c_master_xfer(struct svc_i3c_master *master, + * and yield the above events handler. + */ + if (SVC_I3C_MSTATUS_IBIWON(reg)) { +- ret = -ENXIO; ++ ret = -EAGAIN; ++ *actual_len = 0; + goto emit_stop; + } + +@@ -1075,7 +1078,7 @@ static int svc_i3c_master_xfer(struct svc_i3c_master *master, + goto emit_stop; + + if (rnw) +- *read_len = ret; ++ *actual_len = ret; + + ret = readl_poll_timeout(master->regs + SVC_I3C_MSTATUS, reg, + SVC_I3C_MSTATUS_COMPLETE(reg), 0, 1000); +@@ -1157,8 +1160,12 @@ static void svc_i3c_master_start_xfer_locked(struct svc_i3c_master *master) + + ret = svc_i3c_master_xfer(master, cmd->rnw, xfer->type, + cmd->addr, cmd->in, cmd->out, +- cmd->len, &cmd->read_len, ++ cmd->len, &cmd->actual_len, + cmd->continued); ++ /* cmd->xfer is NULL if I2C or CCC transfer */ ++ if (cmd->xfer) ++ cmd->xfer->actual_len = cmd->actual_len; ++ + if (ret) + break; + } +@@ -1243,7 +1250,7 @@ static int svc_i3c_master_send_bdcast_ccc_cmd(struct svc_i3c_master *master, + cmd->in = NULL; + cmd->out = buf; + cmd->len = xfer_len; +- cmd->read_len = 0; ++ cmd->actual_len = 0; + cmd->continued = false; + + mutex_lock(&master->lock); +@@ -1263,7 +1270,7 @@ static int svc_i3c_master_send_direct_ccc_cmd(struct svc_i3c_master *master, + struct i3c_ccc_cmd *ccc) + { + unsigned int xfer_len = ccc->dests[0].payload.len; +- unsigned int read_len = ccc->rnw ? xfer_len : 0; ++ unsigned int actual_len = ccc->rnw ? xfer_len : 0; + struct svc_i3c_xfer *xfer; + struct svc_i3c_cmd *cmd; + int ret; +@@ -1281,7 +1288,7 @@ static int svc_i3c_master_send_direct_ccc_cmd(struct svc_i3c_master *master, + cmd->in = NULL; + cmd->out = &ccc->id; + cmd->len = 1; +- cmd->read_len = 0; ++ cmd->actual_len = 0; + cmd->continued = true; + + /* Directed message */ +@@ -1291,7 +1298,7 @@ static int svc_i3c_master_send_direct_ccc_cmd(struct svc_i3c_master *master, + cmd->in = ccc->rnw ? ccc->dests[0].payload.data : NULL; + cmd->out = ccc->rnw ? NULL : ccc->dests[0].payload.data, + cmd->len = xfer_len; +- cmd->read_len = read_len; ++ cmd->actual_len = actual_len; + cmd->continued = false; + + mutex_lock(&master->lock); +@@ -1300,8 +1307,8 @@ static int svc_i3c_master_send_direct_ccc_cmd(struct svc_i3c_master *master, + svc_i3c_master_dequeue_xfer(master, xfer); + mutex_unlock(&master->lock); + +- if (cmd->read_len != xfer_len) +- ccc->dests[0].payload.len = cmd->read_len; ++ if (cmd->actual_len != xfer_len) ++ ccc->dests[0].payload.len = cmd->actual_len; + + ret = xfer->ret; + svc_i3c_master_free_xfer(xfer); +@@ -1346,12 +1353,13 @@ static int svc_i3c_master_priv_xfers(struct i3c_dev_desc *dev, + for (i = 0; i < nxfers; i++) { + struct svc_i3c_cmd *cmd = &xfer->cmds[i]; + ++ cmd->xfer = &xfers[i]; + cmd->addr = master->addrs[data->index]; + cmd->rnw = xfers[i].rnw; + cmd->in = xfers[i].rnw ? xfers[i].data.in : NULL; + cmd->out = xfers[i].rnw ? NULL : xfers[i].data.out; + cmd->len = xfers[i].len; +- cmd->read_len = xfers[i].rnw ? xfers[i].len : 0; ++ cmd->actual_len = xfers[i].rnw ? xfers[i].len : 0; + cmd->continued = (i + 1) < nxfers; + } + +@@ -1391,7 +1399,7 @@ static int svc_i3c_master_i2c_xfers(struct i2c_dev_desc *dev, + cmd->in = cmd->rnw ? xfers[i].buf : NULL; + cmd->out = cmd->rnw ? NULL : xfers[i].buf; + cmd->len = xfers[i].len; +- cmd->read_len = cmd->rnw ? xfers[i].len : 0; ++ cmd->actual_len = cmd->rnw ? xfers[i].len : 0; + cmd->continued = (i + 1 < nxfers); + } + +diff --git a/drivers/iio/Kconfig b/drivers/iio/Kconfig +index 52eb46ef84c1b..9c351ffc7bed6 100644 +--- a/drivers/iio/Kconfig ++++ b/drivers/iio/Kconfig +@@ -71,6 +71,15 @@ config IIO_TRIGGERED_EVENT + help + Provides helper functions for setting up triggered events. + ++config IIO_BACKEND ++ tristate ++ help ++ Framework to handle complex IIO aggregate devices. The typical ++ architecture that can make use of this framework is to have one ++ device as the frontend device which can be "linked" against one or ++ multiple backend devices. The framework then makes it easy to get ++ and control such backend devices. ++ + source "drivers/iio/accel/Kconfig" + source "drivers/iio/adc/Kconfig" + source "drivers/iio/addac/Kconfig" +diff --git a/drivers/iio/Makefile b/drivers/iio/Makefile +index 9622347a1c1be..0ba0e1521ba4f 100644 +--- a/drivers/iio/Makefile ++++ b/drivers/iio/Makefile +@@ -13,6 +13,7 @@ obj-$(CONFIG_IIO_GTS_HELPER) += industrialio-gts-helper.o + obj-$(CONFIG_IIO_SW_DEVICE) += industrialio-sw-device.o + obj-$(CONFIG_IIO_SW_TRIGGER) += industrialio-sw-trigger.o + obj-$(CONFIG_IIO_TRIGGERED_EVENT) += industrialio-triggered-event.o ++obj-$(CONFIG_IIO_BACKEND) += industrialio-backend.o + + obj-y += accel/ + obj-y += adc/ +diff --git a/drivers/iio/accel/mxc4005.c b/drivers/iio/accel/mxc4005.c +index b608aa5467175..49e30b87732f5 100644 +--- a/drivers/iio/accel/mxc4005.c ++++ b/drivers/iio/accel/mxc4005.c +@@ -5,6 +5,7 @@ + * Copyright (c) 2014, Intel Corporation. + */ + ++#include + #include + #include + #include +@@ -36,6 +37,7 @@ + + #define MXC4005_REG_INT_CLR1 0x01 + #define MXC4005_REG_INT_CLR1_BIT_DRDYC 0x01 ++#define MXC4005_REG_INT_CLR1_SW_RST 0x10 + + #define MXC4005_REG_CONTROL 0x0D + #define MXC4005_REG_CONTROL_MASK_FSR GENMASK(6, 5) +@@ -43,6 +45,9 @@ + + #define MXC4005_REG_DEVICE_ID 0x0E + ++/* Datasheet does not specify a reset time, this is a conservative guess */ ++#define MXC4005_RESET_TIME_US 2000 ++ + enum mxc4005_axis { + AXIS_X, + AXIS_Y, +@@ -66,6 +71,8 @@ struct mxc4005_data { + s64 timestamp __aligned(8); + } scan; + bool trigger_enabled; ++ unsigned int control; ++ unsigned int int_mask1; + }; + + /* +@@ -349,6 +356,7 @@ static int mxc4005_set_trigger_state(struct iio_trigger *trig, + return ret; + } + ++ data->int_mask1 = val; + data->trigger_enabled = state; + mutex_unlock(&data->mutex); + +@@ -384,6 +392,13 @@ static int mxc4005_chip_init(struct mxc4005_data *data) + + dev_dbg(data->dev, "MXC4005 chip id %02x\n", reg); + ++ ret = regmap_write(data->regmap, MXC4005_REG_INT_CLR1, ++ MXC4005_REG_INT_CLR1_SW_RST); ++ if (ret < 0) ++ return dev_err_probe(data->dev, ret, "resetting chip\n"); ++ ++ fsleep(MXC4005_RESET_TIME_US); ++ + ret = regmap_write(data->regmap, MXC4005_REG_INT_MASK0, 0); + if (ret < 0) + return dev_err_probe(data->dev, ret, "writing INT_MASK0\n"); +@@ -479,6 +494,58 @@ static int mxc4005_probe(struct i2c_client *client) + return devm_iio_device_register(&client->dev, indio_dev); + } + ++static int mxc4005_suspend(struct device *dev) ++{ ++ struct iio_dev *indio_dev = dev_get_drvdata(dev); ++ struct mxc4005_data *data = iio_priv(indio_dev); ++ int ret; ++ ++ /* Save control to restore it on resume */ ++ ret = regmap_read(data->regmap, MXC4005_REG_CONTROL, &data->control); ++ if (ret < 0) ++ dev_err(data->dev, "failed to read reg_control\n"); ++ ++ return ret; ++} ++ ++static int mxc4005_resume(struct device *dev) ++{ ++ struct iio_dev *indio_dev = dev_get_drvdata(dev); ++ struct mxc4005_data *data = iio_priv(indio_dev); ++ int ret; ++ ++ ret = regmap_write(data->regmap, MXC4005_REG_INT_CLR1, ++ MXC4005_REG_INT_CLR1_SW_RST); ++ if (ret) { ++ dev_err(data->dev, "failed to reset chip: %d\n", ret); ++ return ret; ++ } ++ ++ fsleep(MXC4005_RESET_TIME_US); ++ ++ ret = regmap_write(data->regmap, MXC4005_REG_CONTROL, data->control); ++ if (ret) { ++ dev_err(data->dev, "failed to restore control register\n"); ++ return ret; ++ } ++ ++ ret = regmap_write(data->regmap, MXC4005_REG_INT_MASK0, 0); ++ if (ret) { ++ dev_err(data->dev, "failed to restore interrupt 0 mask\n"); ++ return ret; ++ } ++ ++ ret = regmap_write(data->regmap, MXC4005_REG_INT_MASK1, data->int_mask1); ++ if (ret) { ++ dev_err(data->dev, "failed to restore interrupt 1 mask\n"); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static DEFINE_SIMPLE_DEV_PM_OPS(mxc4005_pm_ops, mxc4005_suspend, mxc4005_resume); ++ + static const struct acpi_device_id mxc4005_acpi_match[] = { + {"MXC4005", 0}, + {"MXC6655", 0}, +@@ -486,6 +553,13 @@ static const struct acpi_device_id mxc4005_acpi_match[] = { + }; + MODULE_DEVICE_TABLE(acpi, mxc4005_acpi_match); + ++static const struct of_device_id mxc4005_of_match[] = { ++ { .compatible = "memsic,mxc4005", }, ++ { .compatible = "memsic,mxc6655", }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(of, mxc4005_of_match); ++ + static const struct i2c_device_id mxc4005_id[] = { + {"mxc4005", 0}, + {"mxc6655", 0}, +@@ -497,6 +571,8 @@ static struct i2c_driver mxc4005_driver = { + .driver = { + .name = MXC4005_DRV_NAME, + .acpi_match_table = ACPI_PTR(mxc4005_acpi_match), ++ .of_match_table = mxc4005_of_match, ++ .pm = pm_sleep_ptr(&mxc4005_pm_ops), + }, + .probe = mxc4005_probe, + .id_table = mxc4005_id, +diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig +index 517b3db114b8e..dfb925cfe38ef 100644 +--- a/drivers/iio/adc/Kconfig ++++ b/drivers/iio/adc/Kconfig +@@ -275,7 +275,7 @@ config AD799X + config AD9467 + tristate "Analog Devices AD9467 High Speed ADC driver" + depends on SPI +- depends on ADI_AXI_ADC ++ select IIO_BACKEND + help + Say yes here to build support for Analog Devices: + * AD9467 16-Bit, 200 MSPS/250 MSPS Analog-to-Digital Converter +@@ -292,8 +292,8 @@ config ADI_AXI_ADC + select IIO_BUFFER + select IIO_BUFFER_HW_CONSUMER + select IIO_BUFFER_DMAENGINE +- depends on HAS_IOMEM +- depends on OF ++ select REGMAP_MMIO ++ select IIO_BACKEND + help + Say yes here to build support for Analog Devices Generic + AXI ADC IP core. The IP core is used for interfacing with +diff --git a/drivers/iio/adc/ad9467.c b/drivers/iio/adc/ad9467.c +index f668313730cb6..863dca5db161e 100644 +--- a/drivers/iio/adc/ad9467.c ++++ b/drivers/iio/adc/ad9467.c +@@ -17,13 +17,12 @@ + #include + + ++#include + #include + #include + + #include + +-#include +- + /* + * ADI High-Speed ADC common spi interface registers + * See Application-Note AN-877: +@@ -101,22 +100,21 @@ + #define AD9467_DEF_OUTPUT_MODE 0x08 + #define AD9467_REG_VREF_MASK 0x0F + +-enum { +- ID_AD9265, +- ID_AD9434, +- ID_AD9467, +-}; +- + struct ad9467_chip_info { +- struct adi_axi_adc_chip_info axi_adc_info; +- unsigned int default_output_mode; +- unsigned int vref_mask; ++ const char *name; ++ unsigned int id; ++ const struct iio_chan_spec *channels; ++ unsigned int num_channels; ++ const unsigned int (*scale_table)[2]; ++ int num_scales; ++ unsigned long max_rate; ++ unsigned int default_output_mode; ++ unsigned int vref_mask; + }; + +-#define to_ad9467_chip_info(_info) \ +- container_of(_info, struct ad9467_chip_info, axi_adc_info) +- + struct ad9467_state { ++ const struct ad9467_chip_info *info; ++ struct iio_backend *back; + struct spi_device *spi; + struct clk *clk; + unsigned int output_mode; +@@ -157,10 +155,10 @@ static int ad9467_spi_write(struct spi_device *spi, unsigned int reg, + return spi_write(spi, buf, ARRAY_SIZE(buf)); + } + +-static int ad9467_reg_access(struct adi_axi_adc_conv *conv, unsigned int reg, ++static int ad9467_reg_access(struct iio_dev *indio_dev, unsigned int reg, + unsigned int writeval, unsigned int *readval) + { +- struct ad9467_state *st = adi_axi_adc_conv_priv(conv); ++ struct ad9467_state *st = iio_priv(indio_dev); + struct spi_device *spi = st->spi; + int ret; + +@@ -197,10 +195,10 @@ static const unsigned int ad9467_scale_table[][2] = { + {2300, 8}, {2400, 9}, {2500, 10}, + }; + +-static void __ad9467_get_scale(struct adi_axi_adc_conv *conv, int index, ++static void __ad9467_get_scale(struct ad9467_state *st, int index, + unsigned int *val, unsigned int *val2) + { +- const struct adi_axi_adc_chip_info *info = conv->chip_info; ++ const struct ad9467_chip_info *info = st->info; + const struct iio_chan_spec *chan = &info->channels[0]; + unsigned int tmp; + +@@ -234,50 +232,45 @@ static const struct iio_chan_spec ad9467_channels[] = { + AD9467_CHAN(0, 0, 16, 'S'), + }; + +-static const struct ad9467_chip_info ad9467_chip_tbl[] = { +- [ID_AD9265] = { +- .axi_adc_info = { +- .id = CHIPID_AD9265, +- .max_rate = 125000000UL, +- .scale_table = ad9265_scale_table, +- .num_scales = ARRAY_SIZE(ad9265_scale_table), +- .channels = ad9467_channels, +- .num_channels = ARRAY_SIZE(ad9467_channels), +- }, +- .default_output_mode = AD9265_DEF_OUTPUT_MODE, +- .vref_mask = AD9265_REG_VREF_MASK, +- }, +- [ID_AD9434] = { +- .axi_adc_info = { +- .id = CHIPID_AD9434, +- .max_rate = 500000000UL, +- .scale_table = ad9434_scale_table, +- .num_scales = ARRAY_SIZE(ad9434_scale_table), +- .channels = ad9434_channels, +- .num_channels = ARRAY_SIZE(ad9434_channels), +- }, +- .default_output_mode = AD9434_DEF_OUTPUT_MODE, +- .vref_mask = AD9434_REG_VREF_MASK, +- }, +- [ID_AD9467] = { +- .axi_adc_info = { +- .id = CHIPID_AD9467, +- .max_rate = 250000000UL, +- .scale_table = ad9467_scale_table, +- .num_scales = ARRAY_SIZE(ad9467_scale_table), +- .channels = ad9467_channels, +- .num_channels = ARRAY_SIZE(ad9467_channels), +- }, +- .default_output_mode = AD9467_DEF_OUTPUT_MODE, +- .vref_mask = AD9467_REG_VREF_MASK, +- }, ++static const struct ad9467_chip_info ad9467_chip_tbl = { ++ .name = "ad9467", ++ .id = CHIPID_AD9467, ++ .max_rate = 250000000UL, ++ .scale_table = ad9467_scale_table, ++ .num_scales = ARRAY_SIZE(ad9467_scale_table), ++ .channels = ad9467_channels, ++ .num_channels = ARRAY_SIZE(ad9467_channels), ++ .default_output_mode = AD9467_DEF_OUTPUT_MODE, ++ .vref_mask = AD9467_REG_VREF_MASK, + }; + +-static int ad9467_get_scale(struct adi_axi_adc_conv *conv, int *val, int *val2) ++static const struct ad9467_chip_info ad9434_chip_tbl = { ++ .name = "ad9434", ++ .id = CHIPID_AD9434, ++ .max_rate = 500000000UL, ++ .scale_table = ad9434_scale_table, ++ .num_scales = ARRAY_SIZE(ad9434_scale_table), ++ .channels = ad9434_channels, ++ .num_channels = ARRAY_SIZE(ad9434_channels), ++ .default_output_mode = AD9434_DEF_OUTPUT_MODE, ++ .vref_mask = AD9434_REG_VREF_MASK, ++}; ++ ++static const struct ad9467_chip_info ad9265_chip_tbl = { ++ .name = "ad9265", ++ .id = CHIPID_AD9265, ++ .max_rate = 125000000UL, ++ .scale_table = ad9265_scale_table, ++ .num_scales = ARRAY_SIZE(ad9265_scale_table), ++ .channels = ad9467_channels, ++ .num_channels = ARRAY_SIZE(ad9467_channels), ++ .default_output_mode = AD9265_DEF_OUTPUT_MODE, ++ .vref_mask = AD9265_REG_VREF_MASK, ++}; ++ ++static int ad9467_get_scale(struct ad9467_state *st, int *val, int *val2) + { +- const struct adi_axi_adc_chip_info *info = conv->chip_info; +- const struct ad9467_chip_info *info1 = to_ad9467_chip_info(info); +- struct ad9467_state *st = adi_axi_adc_conv_priv(conv); ++ const struct ad9467_chip_info *info = st->info; + unsigned int i, vref_val; + int ret; + +@@ -285,7 +278,7 @@ static int ad9467_get_scale(struct adi_axi_adc_conv *conv, int *val, int *val2) + if (ret < 0) + return ret; + +- vref_val = ret & info1->vref_mask; ++ vref_val = ret & info->vref_mask; + + for (i = 0; i < info->num_scales; i++) { + if (vref_val == info->scale_table[i][1]) +@@ -295,15 +288,14 @@ static int ad9467_get_scale(struct adi_axi_adc_conv *conv, int *val, int *val2) + if (i == info->num_scales) + return -ERANGE; + +- __ad9467_get_scale(conv, i, val, val2); ++ __ad9467_get_scale(st, i, val, val2); + + return IIO_VAL_INT_PLUS_MICRO; + } + +-static int ad9467_set_scale(struct adi_axi_adc_conv *conv, int val, int val2) ++static int ad9467_set_scale(struct ad9467_state *st, int val, int val2) + { +- const struct adi_axi_adc_chip_info *info = conv->chip_info; +- struct ad9467_state *st = adi_axi_adc_conv_priv(conv); ++ const struct ad9467_chip_info *info = st->info; + unsigned int scale_val[2]; + unsigned int i; + int ret; +@@ -312,7 +304,7 @@ static int ad9467_set_scale(struct adi_axi_adc_conv *conv, int val, int val2) + return -EINVAL; + + for (i = 0; i < info->num_scales; i++) { +- __ad9467_get_scale(conv, i, &scale_val[0], &scale_val[1]); ++ __ad9467_get_scale(st, i, &scale_val[0], &scale_val[1]); + if (scale_val[0] != val || scale_val[1] != val2) + continue; + +@@ -329,15 +321,15 @@ static int ad9467_set_scale(struct adi_axi_adc_conv *conv, int val, int val2) + return -EINVAL; + } + +-static int ad9467_read_raw(struct adi_axi_adc_conv *conv, ++static int ad9467_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long m) + { +- struct ad9467_state *st = adi_axi_adc_conv_priv(conv); ++ struct ad9467_state *st = iio_priv(indio_dev); + + switch (m) { + case IIO_CHAN_INFO_SCALE: +- return ad9467_get_scale(conv, val, val2); ++ return ad9467_get_scale(st, val, val2); + case IIO_CHAN_INFO_SAMP_FREQ: + *val = clk_get_rate(st->clk); + +@@ -347,17 +339,17 @@ static int ad9467_read_raw(struct adi_axi_adc_conv *conv, + } + } + +-static int ad9467_write_raw(struct adi_axi_adc_conv *conv, ++static int ad9467_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) + { +- const struct adi_axi_adc_chip_info *info = conv->chip_info; +- struct ad9467_state *st = adi_axi_adc_conv_priv(conv); ++ struct ad9467_state *st = iio_priv(indio_dev); ++ const struct ad9467_chip_info *info = st->info; + long r_clk; + + switch (mask) { + case IIO_CHAN_INFO_SCALE: +- return ad9467_set_scale(conv, val, val2); ++ return ad9467_set_scale(st, val, val2); + case IIO_CHAN_INFO_SAMP_FREQ: + r_clk = clk_round_rate(st->clk, val); + if (r_clk < 0 || r_clk > info->max_rate) { +@@ -372,13 +364,13 @@ static int ad9467_write_raw(struct adi_axi_adc_conv *conv, + } + } + +-static int ad9467_read_avail(struct adi_axi_adc_conv *conv, ++static int ad9467_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + const int **vals, int *type, int *length, + long mask) + { +- const struct adi_axi_adc_chip_info *info = conv->chip_info; +- struct ad9467_state *st = adi_axi_adc_conv_priv(conv); ++ struct ad9467_state *st = iio_priv(indio_dev); ++ const struct ad9467_chip_info *info = st->info; + + switch (mask) { + case IIO_CHAN_INFO_SCALE: +@@ -392,6 +384,33 @@ static int ad9467_read_avail(struct adi_axi_adc_conv *conv, + } + } + ++static int ad9467_update_scan_mode(struct iio_dev *indio_dev, ++ const unsigned long *scan_mask) ++{ ++ struct ad9467_state *st = iio_priv(indio_dev); ++ unsigned int c; ++ int ret; ++ ++ for (c = 0; c < st->info->num_channels; c++) { ++ if (test_bit(c, scan_mask)) ++ ret = iio_backend_chan_enable(st->back, c); ++ else ++ ret = iio_backend_chan_disable(st->back, c); ++ if (ret) ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static const struct iio_info ad9467_info = { ++ .read_raw = ad9467_read_raw, ++ .write_raw = ad9467_write_raw, ++ .update_scan_mode = ad9467_update_scan_mode, ++ .debugfs_reg_access = ad9467_reg_access, ++ .read_avail = ad9467_read_avail, ++}; ++ + static int ad9467_outputmode_set(struct spi_device *spi, unsigned int mode) + { + int ret; +@@ -404,10 +423,9 @@ static int ad9467_outputmode_set(struct spi_device *spi, unsigned int mode) + AN877_ADC_TRANSFER_SYNC); + } + +-static int ad9467_scale_fill(struct adi_axi_adc_conv *conv) ++static int ad9467_scale_fill(struct ad9467_state *st) + { +- const struct adi_axi_adc_chip_info *info = conv->chip_info; +- struct ad9467_state *st = adi_axi_adc_conv_priv(conv); ++ const struct ad9467_chip_info *info = st->info; + unsigned int i, val1, val2; + + st->scales = devm_kmalloc_array(&st->spi->dev, info->num_scales, +@@ -416,7 +434,7 @@ static int ad9467_scale_fill(struct adi_axi_adc_conv *conv) + return -ENOMEM; + + for (i = 0; i < info->num_scales; i++) { +- __ad9467_get_scale(conv, i, &val1, &val2); ++ __ad9467_get_scale(st, i, &val1, &val2); + st->scales[i][0] = val1; + st->scales[i][1] = val2; + } +@@ -424,11 +442,27 @@ static int ad9467_scale_fill(struct adi_axi_adc_conv *conv) + return 0; + } + +-static int ad9467_preenable_setup(struct adi_axi_adc_conv *conv) ++static int ad9467_setup(struct ad9467_state *st) + { +- struct ad9467_state *st = adi_axi_adc_conv_priv(conv); ++ struct iio_backend_data_fmt data = { ++ .sign_extend = true, ++ .enable = true, ++ }; ++ unsigned int c, mode; ++ int ret; ++ ++ mode = st->info->default_output_mode | AN877_ADC_OUTPUT_MODE_TWOS_COMPLEMENT; ++ ret = ad9467_outputmode_set(st->spi, mode); ++ if (ret) ++ return ret; ++ ++ for (c = 0; c < st->info->num_channels; c++) { ++ ret = iio_backend_data_format_set(st->back, c, &data); ++ if (ret) ++ return ret; ++ } + +- return ad9467_outputmode_set(st->spi, st->output_mode); ++ return 0; + } + + static int ad9467_reset(struct device *dev) +@@ -446,27 +480,65 @@ static int ad9467_reset(struct device *dev) + return 0; + } + ++static int ad9467_iio_backend_get(struct ad9467_state *st) ++{ ++ struct device *dev = &st->spi->dev; ++ struct device_node *__back; ++ ++ st->back = devm_iio_backend_get(dev, NULL); ++ if (!IS_ERR(st->back)) ++ return 0; ++ /* If not found, don't error out as we might have legacy DT property */ ++ if (PTR_ERR(st->back) != -ENOENT) ++ return PTR_ERR(st->back); ++ ++ /* ++ * if we don't get the backend using the normal API's, use the legacy ++ * 'adi,adc-dev' property. So we get all nodes with that property, and ++ * look for the one pointing at us. Then we directly lookup that fwnode ++ * on the backend list of registered devices. This is done so we don't ++ * make io-backends mandatory which would break DT ABI. ++ */ ++ for_each_node_with_property(__back, "adi,adc-dev") { ++ struct device_node *__me; ++ ++ __me = of_parse_phandle(__back, "adi,adc-dev", 0); ++ if (!__me) ++ continue; ++ ++ if (!device_match_of_node(dev, __me)) { ++ of_node_put(__me); ++ continue; ++ } ++ ++ of_node_put(__me); ++ st->back = __devm_iio_backend_get_from_fwnode_lookup(dev, ++ of_fwnode_handle(__back)); ++ of_node_put(__back); ++ return PTR_ERR_OR_ZERO(st->back); ++ } ++ ++ return -ENODEV; ++} ++ + static int ad9467_probe(struct spi_device *spi) + { +- const struct ad9467_chip_info *info; +- struct adi_axi_adc_conv *conv; ++ struct iio_dev *indio_dev; + struct ad9467_state *st; + unsigned int id; + int ret; + +- info = of_device_get_match_data(&spi->dev); +- if (!info) +- info = (void *)spi_get_device_id(spi)->driver_data; +- if (!info) +- return -ENODEV; +- +- conv = devm_adi_axi_adc_conv_register(&spi->dev, sizeof(*st)); +- if (IS_ERR(conv)) +- return PTR_ERR(conv); ++ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); ++ if (!indio_dev) ++ return -ENOMEM; + +- st = adi_axi_adc_conv_priv(conv); ++ st = iio_priv(indio_dev); + st->spi = spi; + ++ st->info = spi_get_device_match_data(spi); ++ if (!st->info) ++ return -ENODEV; ++ + st->clk = devm_clk_get_enabled(&spi->dev, "adc-clk"); + if (IS_ERR(st->clk)) + return PTR_ERR(st->clk); +@@ -480,43 +552,53 @@ static int ad9467_probe(struct spi_device *spi) + if (ret) + return ret; + +- conv->chip_info = &info->axi_adc_info; +- +- ret = ad9467_scale_fill(conv); ++ ret = ad9467_scale_fill(st); + if (ret) + return ret; + + id = ad9467_spi_read(spi, AN877_ADC_REG_CHIP_ID); +- if (id != conv->chip_info->id) { ++ if (id != st->info->id) { + dev_err(&spi->dev, "Mismatch CHIP_ID, got 0x%X, expected 0x%X\n", +- id, conv->chip_info->id); ++ id, st->info->id); + return -ENODEV; + } + +- conv->reg_access = ad9467_reg_access; +- conv->write_raw = ad9467_write_raw; +- conv->read_raw = ad9467_read_raw; +- conv->read_avail = ad9467_read_avail; +- conv->preenable_setup = ad9467_preenable_setup; ++ indio_dev->name = st->info->name; ++ indio_dev->channels = st->info->channels; ++ indio_dev->num_channels = st->info->num_channels; ++ indio_dev->info = &ad9467_info; + +- st->output_mode = info->default_output_mode | +- AN877_ADC_OUTPUT_MODE_TWOS_COMPLEMENT; ++ ret = ad9467_iio_backend_get(st); ++ if (ret) ++ return ret; + +- return 0; ++ ret = devm_iio_backend_request_buffer(&spi->dev, st->back, indio_dev); ++ if (ret) ++ return ret; ++ ++ ret = devm_iio_backend_enable(&spi->dev, st->back); ++ if (ret) ++ return ret; ++ ++ ret = ad9467_setup(st); ++ if (ret) ++ return ret; ++ ++ return devm_iio_device_register(&spi->dev, indio_dev); + } + + static const struct of_device_id ad9467_of_match[] = { +- { .compatible = "adi,ad9265", .data = &ad9467_chip_tbl[ID_AD9265], }, +- { .compatible = "adi,ad9434", .data = &ad9467_chip_tbl[ID_AD9434], }, +- { .compatible = "adi,ad9467", .data = &ad9467_chip_tbl[ID_AD9467], }, ++ { .compatible = "adi,ad9265", .data = &ad9265_chip_tbl, }, ++ { .compatible = "adi,ad9434", .data = &ad9434_chip_tbl, }, ++ { .compatible = "adi,ad9467", .data = &ad9467_chip_tbl, }, + {} + }; + MODULE_DEVICE_TABLE(of, ad9467_of_match); + + static const struct spi_device_id ad9467_ids[] = { +- { "ad9265", (kernel_ulong_t)&ad9467_chip_tbl[ID_AD9265] }, +- { "ad9434", (kernel_ulong_t)&ad9467_chip_tbl[ID_AD9434] }, +- { "ad9467", (kernel_ulong_t)&ad9467_chip_tbl[ID_AD9467] }, ++ { "ad9265", (kernel_ulong_t)&ad9265_chip_tbl }, ++ { "ad9434", (kernel_ulong_t)&ad9434_chip_tbl }, ++ { "ad9467", (kernel_ulong_t)&ad9467_chip_tbl }, + {} + }; + MODULE_DEVICE_TABLE(spi, ad9467_ids); +@@ -534,4 +616,4 @@ module_spi_driver(ad9467_driver); + MODULE_AUTHOR("Michael Hennerich "); + MODULE_DESCRIPTION("Analog Devices AD9467 ADC driver"); + MODULE_LICENSE("GPL v2"); +-MODULE_IMPORT_NS(IIO_ADI_AXI); ++MODULE_IMPORT_NS(IIO_BACKEND); +diff --git a/drivers/iio/adc/adi-axi-adc.c b/drivers/iio/adc/adi-axi-adc.c +index ae83ada7f9f2d..a543b91124b07 100644 +--- a/drivers/iio/adc/adi-axi-adc.c ++++ b/drivers/iio/adc/adi-axi-adc.c +@@ -8,21 +8,22 @@ + + #include + #include ++#include + #include + #include + #include + #include + #include + #include ++#include + #include + +-#include +-#include +-#include +-#include +- + #include +-#include ++ ++#include ++#include ++#include ++#include + + /* + * Register definitions: +@@ -43,6 +44,7 @@ + #define ADI_AXI_REG_CHAN_CTRL_PN_SEL_OWR BIT(10) + #define ADI_AXI_REG_CHAN_CTRL_IQCOR_EN BIT(9) + #define ADI_AXI_REG_CHAN_CTRL_DCFILT_EN BIT(8) ++#define ADI_AXI_REG_CHAN_CTRL_FMT_MASK GENMASK(6, 4) + #define ADI_AXI_REG_CHAN_CTRL_FMT_SIGNEXT BIT(6) + #define ADI_AXI_REG_CHAN_CTRL_FMT_TYPE BIT(5) + #define ADI_AXI_REG_CHAN_CTRL_FMT_EN BIT(4) +@@ -54,350 +56,170 @@ + ADI_AXI_REG_CHAN_CTRL_FMT_EN | \ + ADI_AXI_REG_CHAN_CTRL_ENABLE) + +-struct adi_axi_adc_core_info { +- unsigned int version; +-}; +- + struct adi_axi_adc_state { +- struct mutex lock; +- +- struct adi_axi_adc_client *client; +- void __iomem *regs; +-}; +- +-struct adi_axi_adc_client { +- struct list_head entry; +- struct adi_axi_adc_conv conv; +- struct adi_axi_adc_state *state; ++ struct regmap *regmap; + struct device *dev; +- const struct adi_axi_adc_core_info *info; + }; + +-static LIST_HEAD(registered_clients); +-static DEFINE_MUTEX(registered_clients_lock); +- +-static struct adi_axi_adc_client *conv_to_client(struct adi_axi_adc_conv *conv) ++static int axi_adc_enable(struct iio_backend *back) + { +- return container_of(conv, struct adi_axi_adc_client, conv); +-} ++ struct adi_axi_adc_state *st = iio_backend_get_priv(back); ++ int ret; + +-void *adi_axi_adc_conv_priv(struct adi_axi_adc_conv *conv) +-{ +- struct adi_axi_adc_client *cl = conv_to_client(conv); ++ ret = regmap_set_bits(st->regmap, ADI_AXI_REG_RSTN, ++ ADI_AXI_REG_RSTN_MMCM_RSTN); ++ if (ret) ++ return ret; + +- return (char *)cl + ALIGN(sizeof(struct adi_axi_adc_client), +- IIO_DMA_MINALIGN); ++ fsleep(10000); ++ return regmap_set_bits(st->regmap, ADI_AXI_REG_RSTN, ++ ADI_AXI_REG_RSTN_RSTN | ADI_AXI_REG_RSTN_MMCM_RSTN); + } +-EXPORT_SYMBOL_NS_GPL(adi_axi_adc_conv_priv, IIO_ADI_AXI); + +-static void adi_axi_adc_write(struct adi_axi_adc_state *st, +- unsigned int reg, +- unsigned int val) ++static void axi_adc_disable(struct iio_backend *back) + { +- iowrite32(val, st->regs + reg); +-} ++ struct adi_axi_adc_state *st = iio_backend_get_priv(back); + +-static unsigned int adi_axi_adc_read(struct adi_axi_adc_state *st, +- unsigned int reg) +-{ +- return ioread32(st->regs + reg); ++ regmap_write(st->regmap, ADI_AXI_REG_RSTN, 0); + } + +-static int adi_axi_adc_config_dma_buffer(struct device *dev, +- struct iio_dev *indio_dev) ++static int axi_adc_data_format_set(struct iio_backend *back, unsigned int chan, ++ const struct iio_backend_data_fmt *data) + { +- const char *dma_name; +- +- if (!device_property_present(dev, "dmas")) +- return 0; +- +- if (device_property_read_string(dev, "dma-names", &dma_name)) +- dma_name = "rx"; +- +- return devm_iio_dmaengine_buffer_setup(indio_dev->dev.parent, +- indio_dev, dma_name); ++ struct adi_axi_adc_state *st = iio_backend_get_priv(back); ++ u32 val; ++ ++ if (!data->enable) ++ return regmap_clear_bits(st->regmap, ++ ADI_AXI_REG_CHAN_CTRL(chan), ++ ADI_AXI_REG_CHAN_CTRL_FMT_EN); ++ ++ val = FIELD_PREP(ADI_AXI_REG_CHAN_CTRL_FMT_EN, true); ++ if (data->sign_extend) ++ val |= FIELD_PREP(ADI_AXI_REG_CHAN_CTRL_FMT_SIGNEXT, true); ++ if (data->type == IIO_BACKEND_OFFSET_BINARY) ++ val |= FIELD_PREP(ADI_AXI_REG_CHAN_CTRL_FMT_TYPE, true); ++ ++ return regmap_update_bits(st->regmap, ADI_AXI_REG_CHAN_CTRL(chan), ++ ADI_AXI_REG_CHAN_CTRL_FMT_MASK, val); + } + +-static int adi_axi_adc_read_raw(struct iio_dev *indio_dev, +- struct iio_chan_spec const *chan, +- int *val, int *val2, long mask) ++static int axi_adc_chan_enable(struct iio_backend *back, unsigned int chan) + { +- struct adi_axi_adc_state *st = iio_priv(indio_dev); +- struct adi_axi_adc_conv *conv = &st->client->conv; +- +- if (!conv->read_raw) +- return -EOPNOTSUPP; ++ struct adi_axi_adc_state *st = iio_backend_get_priv(back); + +- return conv->read_raw(conv, chan, val, val2, mask); ++ return regmap_set_bits(st->regmap, ADI_AXI_REG_CHAN_CTRL(chan), ++ ADI_AXI_REG_CHAN_CTRL_ENABLE); + } + +-static int adi_axi_adc_write_raw(struct iio_dev *indio_dev, +- struct iio_chan_spec const *chan, +- int val, int val2, long mask) ++static int axi_adc_chan_disable(struct iio_backend *back, unsigned int chan) + { +- struct adi_axi_adc_state *st = iio_priv(indio_dev); +- struct adi_axi_adc_conv *conv = &st->client->conv; +- +- if (!conv->write_raw) +- return -EOPNOTSUPP; ++ struct adi_axi_adc_state *st = iio_backend_get_priv(back); + +- return conv->write_raw(conv, chan, val, val2, mask); ++ return regmap_clear_bits(st->regmap, ADI_AXI_REG_CHAN_CTRL(chan), ++ ADI_AXI_REG_CHAN_CTRL_ENABLE); + } + +-static int adi_axi_adc_read_avail(struct iio_dev *indio_dev, +- struct iio_chan_spec const *chan, +- const int **vals, int *type, int *length, +- long mask) ++static struct iio_buffer *axi_adc_request_buffer(struct iio_backend *back, ++ struct iio_dev *indio_dev) + { +- struct adi_axi_adc_state *st = iio_priv(indio_dev); +- struct adi_axi_adc_conv *conv = &st->client->conv; +- +- if (!conv->read_avail) +- return -EOPNOTSUPP; +- +- return conv->read_avail(conv, chan, vals, type, length, mask); +-} +- +-static int adi_axi_adc_update_scan_mode(struct iio_dev *indio_dev, +- const unsigned long *scan_mask) +-{ +- struct adi_axi_adc_state *st = iio_priv(indio_dev); +- struct adi_axi_adc_conv *conv = &st->client->conv; +- unsigned int i, ctrl; +- +- for (i = 0; i < conv->chip_info->num_channels; i++) { +- ctrl = adi_axi_adc_read(st, ADI_AXI_REG_CHAN_CTRL(i)); ++ struct adi_axi_adc_state *st = iio_backend_get_priv(back); ++ struct iio_buffer *buffer; ++ const char *dma_name; ++ int ret; + +- if (test_bit(i, scan_mask)) +- ctrl |= ADI_AXI_REG_CHAN_CTRL_ENABLE; +- else +- ctrl &= ~ADI_AXI_REG_CHAN_CTRL_ENABLE; ++ if (device_property_read_string(st->dev, "dma-names", &dma_name)) ++ dma_name = "rx"; + +- adi_axi_adc_write(st, ADI_AXI_REG_CHAN_CTRL(i), ctrl); ++ buffer = iio_dmaengine_buffer_alloc(st->dev, dma_name); ++ if (IS_ERR(buffer)) { ++ dev_err(st->dev, "Could not get DMA buffer, %ld\n", ++ PTR_ERR(buffer)); ++ return ERR_CAST(buffer); + } + +- return 0; +-} +- +-static struct adi_axi_adc_conv *adi_axi_adc_conv_register(struct device *dev, +- size_t sizeof_priv) +-{ +- struct adi_axi_adc_client *cl; +- size_t alloc_size; +- +- alloc_size = ALIGN(sizeof(struct adi_axi_adc_client), IIO_DMA_MINALIGN); +- if (sizeof_priv) +- alloc_size += ALIGN(sizeof_priv, IIO_DMA_MINALIGN); +- +- cl = kzalloc(alloc_size, GFP_KERNEL); +- if (!cl) +- return ERR_PTR(-ENOMEM); +- +- mutex_lock(®istered_clients_lock); +- +- cl->dev = get_device(dev); +- +- list_add_tail(&cl->entry, ®istered_clients); +- +- mutex_unlock(®istered_clients_lock); +- +- return &cl->conv; +-} +- +-static void adi_axi_adc_conv_unregister(struct adi_axi_adc_conv *conv) +-{ +- struct adi_axi_adc_client *cl = conv_to_client(conv); +- +- mutex_lock(®istered_clients_lock); +- +- list_del(&cl->entry); +- put_device(cl->dev); +- +- mutex_unlock(®istered_clients_lock); +- +- kfree(cl); +-} +- +-static void devm_adi_axi_adc_conv_release(void *conv) +-{ +- adi_axi_adc_conv_unregister(conv); +-} +- +-struct adi_axi_adc_conv *devm_adi_axi_adc_conv_register(struct device *dev, +- size_t sizeof_priv) +-{ +- struct adi_axi_adc_conv *conv; +- int ret; +- +- conv = adi_axi_adc_conv_register(dev, sizeof_priv); +- if (IS_ERR(conv)) +- return conv; +- +- ret = devm_add_action_or_reset(dev, devm_adi_axi_adc_conv_release, +- conv); ++ indio_dev->modes |= INDIO_BUFFER_HARDWARE; ++ ret = iio_device_attach_buffer(indio_dev, buffer); + if (ret) + return ERR_PTR(ret); + +- return conv; ++ return buffer; + } +-EXPORT_SYMBOL_NS_GPL(devm_adi_axi_adc_conv_register, IIO_ADI_AXI); +- +-static const struct iio_info adi_axi_adc_info = { +- .read_raw = &adi_axi_adc_read_raw, +- .write_raw = &adi_axi_adc_write_raw, +- .update_scan_mode = &adi_axi_adc_update_scan_mode, +- .read_avail = &adi_axi_adc_read_avail, +-}; + +-static const struct adi_axi_adc_core_info adi_axi_adc_10_0_a_info = { +- .version = ADI_AXI_PCORE_VER(10, 0, 'a'), +-}; +- +-static struct adi_axi_adc_client *adi_axi_adc_attach_client(struct device *dev) ++static void axi_adc_free_buffer(struct iio_backend *back, ++ struct iio_buffer *buffer) + { +- const struct adi_axi_adc_core_info *info; +- struct adi_axi_adc_client *cl; +- struct device_node *cln; +- +- info = of_device_get_match_data(dev); +- if (!info) +- return ERR_PTR(-ENODEV); +- +- cln = of_parse_phandle(dev->of_node, "adi,adc-dev", 0); +- if (!cln) { +- dev_err(dev, "No 'adi,adc-dev' node defined\n"); +- return ERR_PTR(-ENODEV); +- } +- +- mutex_lock(®istered_clients_lock); +- +- list_for_each_entry(cl, ®istered_clients, entry) { +- if (!cl->dev) +- continue; +- +- if (cl->dev->of_node != cln) +- continue; +- +- if (!try_module_get(cl->dev->driver->owner)) { +- mutex_unlock(®istered_clients_lock); +- of_node_put(cln); +- return ERR_PTR(-ENODEV); +- } +- +- get_device(cl->dev); +- cl->info = info; +- mutex_unlock(®istered_clients_lock); +- of_node_put(cln); +- return cl; +- } +- +- mutex_unlock(®istered_clients_lock); +- of_node_put(cln); +- +- return ERR_PTR(-EPROBE_DEFER); ++ iio_dmaengine_buffer_free(buffer); + } + +-static int adi_axi_adc_setup_channels(struct device *dev, +- struct adi_axi_adc_state *st) +-{ +- struct adi_axi_adc_conv *conv = &st->client->conv; +- int i, ret; +- +- if (conv->preenable_setup) { +- ret = conv->preenable_setup(conv); +- if (ret) +- return ret; +- } +- +- for (i = 0; i < conv->chip_info->num_channels; i++) { +- adi_axi_adc_write(st, ADI_AXI_REG_CHAN_CTRL(i), +- ADI_AXI_REG_CHAN_CTRL_DEFAULTS); +- } +- +- return 0; +-} +- +-static void axi_adc_reset(struct adi_axi_adc_state *st) +-{ +- adi_axi_adc_write(st, ADI_AXI_REG_RSTN, 0); +- mdelay(10); +- adi_axi_adc_write(st, ADI_AXI_REG_RSTN, ADI_AXI_REG_RSTN_MMCM_RSTN); +- mdelay(10); +- adi_axi_adc_write(st, ADI_AXI_REG_RSTN, +- ADI_AXI_REG_RSTN_RSTN | ADI_AXI_REG_RSTN_MMCM_RSTN); +-} +- +-static void adi_axi_adc_cleanup(void *data) +-{ +- struct adi_axi_adc_client *cl = data; ++static const struct regmap_config axi_adc_regmap_config = { ++ .val_bits = 32, ++ .reg_bits = 32, ++ .reg_stride = 4, ++ .max_register = 0x0800, ++}; + +- put_device(cl->dev); +- module_put(cl->dev->driver->owner); +-} ++static const struct iio_backend_ops adi_axi_adc_generic = { ++ .enable = axi_adc_enable, ++ .disable = axi_adc_disable, ++ .data_format_set = axi_adc_data_format_set, ++ .chan_enable = axi_adc_chan_enable, ++ .chan_disable = axi_adc_chan_disable, ++ .request_buffer = axi_adc_request_buffer, ++ .free_buffer = axi_adc_free_buffer, ++}; + + static int adi_axi_adc_probe(struct platform_device *pdev) + { +- struct adi_axi_adc_conv *conv; +- struct iio_dev *indio_dev; +- struct adi_axi_adc_client *cl; ++ const unsigned int *expected_ver; + struct adi_axi_adc_state *st; ++ void __iomem *base; + unsigned int ver; + int ret; + +- cl = adi_axi_adc_attach_client(&pdev->dev); +- if (IS_ERR(cl)) +- return PTR_ERR(cl); +- +- ret = devm_add_action_or_reset(&pdev->dev, adi_axi_adc_cleanup, cl); +- if (ret) +- return ret; +- +- indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*st)); +- if (indio_dev == NULL) ++ st = devm_kzalloc(&pdev->dev, sizeof(*st), GFP_KERNEL); ++ if (!st) + return -ENOMEM; + +- st = iio_priv(indio_dev); +- st->client = cl; +- cl->state = st; +- mutex_init(&st->lock); ++ base = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(base)) ++ return PTR_ERR(base); + +- st->regs = devm_platform_ioremap_resource(pdev, 0); +- if (IS_ERR(st->regs)) +- return PTR_ERR(st->regs); ++ st->dev = &pdev->dev; ++ st->regmap = devm_regmap_init_mmio(&pdev->dev, base, ++ &axi_adc_regmap_config); ++ if (IS_ERR(st->regmap)) ++ return PTR_ERR(st->regmap); + +- conv = &st->client->conv; ++ expected_ver = device_get_match_data(&pdev->dev); ++ if (!expected_ver) ++ return -ENODEV; + +- axi_adc_reset(st); ++ /* ++ * Force disable the core. Up to the frontend to enable us. And we can ++ * still read/write registers... ++ */ ++ ret = regmap_write(st->regmap, ADI_AXI_REG_RSTN, 0); ++ if (ret) ++ return ret; + +- ver = adi_axi_adc_read(st, ADI_AXI_REG_VERSION); ++ ret = regmap_read(st->regmap, ADI_AXI_REG_VERSION, &ver); ++ if (ret) ++ return ret; + +- if (cl->info->version > ver) { ++ if (ADI_AXI_PCORE_VER_MAJOR(ver) != ADI_AXI_PCORE_VER_MAJOR(*expected_ver)) { + dev_err(&pdev->dev, +- "IP core version is too old. Expected %d.%.2d.%c, Reported %d.%.2d.%c\n", +- ADI_AXI_PCORE_VER_MAJOR(cl->info->version), +- ADI_AXI_PCORE_VER_MINOR(cl->info->version), +- ADI_AXI_PCORE_VER_PATCH(cl->info->version), ++ "Major version mismatch. Expected %d.%.2d.%c, Reported %d.%.2d.%c\n", ++ ADI_AXI_PCORE_VER_MAJOR(*expected_ver), ++ ADI_AXI_PCORE_VER_MINOR(*expected_ver), ++ ADI_AXI_PCORE_VER_PATCH(*expected_ver), + ADI_AXI_PCORE_VER_MAJOR(ver), + ADI_AXI_PCORE_VER_MINOR(ver), + ADI_AXI_PCORE_VER_PATCH(ver)); + return -ENODEV; + } + +- indio_dev->info = &adi_axi_adc_info; +- indio_dev->name = "adi-axi-adc"; +- indio_dev->modes = INDIO_DIRECT_MODE; +- indio_dev->num_channels = conv->chip_info->num_channels; +- indio_dev->channels = conv->chip_info->channels; +- +- ret = adi_axi_adc_config_dma_buffer(&pdev->dev, indio_dev); +- if (ret) +- return ret; +- +- ret = adi_axi_adc_setup_channels(&pdev->dev, st); +- if (ret) +- return ret; +- +- ret = devm_iio_device_register(&pdev->dev, indio_dev); ++ ret = devm_iio_backend_register(&pdev->dev, &adi_axi_adc_generic, st); + if (ret) + return ret; + +@@ -409,6 +231,8 @@ static int adi_axi_adc_probe(struct platform_device *pdev) + return 0; + } + ++static unsigned int adi_axi_adc_10_0_a_info = ADI_AXI_PCORE_VER(10, 0, 'a'); ++ + /* Match table for of_platform binding */ + static const struct of_device_id adi_axi_adc_of_match[] = { + { .compatible = "adi,axi-adc-10.0.a", .data = &adi_axi_adc_10_0_a_info }, +@@ -428,3 +252,5 @@ module_platform_driver(adi_axi_adc_driver); + MODULE_AUTHOR("Michael Hennerich "); + MODULE_DESCRIPTION("Analog Devices Generic AXI ADC IP core driver"); + MODULE_LICENSE("GPL v2"); ++MODULE_IMPORT_NS(IIO_DMAENGINE_BUFFER); ++MODULE_IMPORT_NS(IIO_BACKEND); +diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c +index f7613efb870d5..0b3e487440a66 100644 +--- a/drivers/iio/adc/stm32-adc.c ++++ b/drivers/iio/adc/stm32-adc.c +@@ -2234,6 +2234,7 @@ static int stm32_adc_generic_chan_init(struct iio_dev *indio_dev, + if (vin[0] != val || vin[1] >= adc_info->max_channels) { + dev_err(&indio_dev->dev, "Invalid channel in%d-in%d\n", + vin[0], vin[1]); ++ ret = -EINVAL; + goto err; + } + } else if (ret != -EINVAL) { +diff --git a/drivers/iio/buffer/industrialio-buffer-dmaengine.c b/drivers/iio/buffer/industrialio-buffer-dmaengine.c +index 5f85ba38e6f6e..0d53c0a07b0d6 100644 +--- a/drivers/iio/buffer/industrialio-buffer-dmaengine.c ++++ b/drivers/iio/buffer/industrialio-buffer-dmaengine.c +@@ -159,7 +159,7 @@ static const struct iio_dev_attr *iio_dmaengine_buffer_attrs[] = { + * Once done using the buffer iio_dmaengine_buffer_free() should be used to + * release it. + */ +-static struct iio_buffer *iio_dmaengine_buffer_alloc(struct device *dev, ++struct iio_buffer *iio_dmaengine_buffer_alloc(struct device *dev, + const char *channel) + { + struct dmaengine_buffer *dmaengine_buffer; +@@ -210,6 +210,7 @@ static struct iio_buffer *iio_dmaengine_buffer_alloc(struct device *dev, + kfree(dmaengine_buffer); + return ERR_PTR(ret); + } ++EXPORT_SYMBOL_NS_GPL(iio_dmaengine_buffer_alloc, IIO_DMAENGINE_BUFFER); + + /** + * iio_dmaengine_buffer_free() - Free dmaengine buffer +@@ -217,7 +218,7 @@ static struct iio_buffer *iio_dmaengine_buffer_alloc(struct device *dev, + * + * Frees a buffer previously allocated with iio_dmaengine_buffer_alloc(). + */ +-static void iio_dmaengine_buffer_free(struct iio_buffer *buffer) ++void iio_dmaengine_buffer_free(struct iio_buffer *buffer) + { + struct dmaengine_buffer *dmaengine_buffer = + iio_buffer_to_dmaengine_buffer(buffer); +@@ -227,6 +228,7 @@ static void iio_dmaengine_buffer_free(struct iio_buffer *buffer) + + iio_buffer_put(buffer); + } ++EXPORT_SYMBOL_NS_GPL(iio_dmaengine_buffer_free, IIO_DMAENGINE_BUFFER); + + static void __devm_iio_dmaengine_buffer_free(void *buffer) + { +@@ -288,7 +290,7 @@ int devm_iio_dmaengine_buffer_setup(struct device *dev, + + return iio_device_attach_buffer(indio_dev, buffer); + } +-EXPORT_SYMBOL_GPL(devm_iio_dmaengine_buffer_setup); ++EXPORT_SYMBOL_NS_GPL(devm_iio_dmaengine_buffer_setup, IIO_DMAENGINE_BUFFER); + + MODULE_AUTHOR("Lars-Peter Clausen "); + MODULE_DESCRIPTION("DMA buffer for the IIO framework"); +diff --git a/drivers/iio/industrialio-backend.c b/drivers/iio/industrialio-backend.c +new file mode 100644 +index 0000000000000..2fea2bbbe47fd +--- /dev/null ++++ b/drivers/iio/industrialio-backend.c +@@ -0,0 +1,418 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * Framework to handle complex IIO aggregate devices. ++ * ++ * The typical architecture is to have one device as the frontend device which ++ * can be "linked" against one or multiple backend devices. All the IIO and ++ * userspace interface is expected to be registers/managed by the frontend ++ * device which will callback into the backends when needed (to get/set some ++ * configuration that it does not directly control). ++ * ++ * ------------------------------------------------------- ++ * ------------------ | ------------ ------------ ------- FPGA| ++ * | ADC |------------------------| | ADC CORE |---------| DMA CORE |------| RAM | | ++ * | (Frontend/IIO) | Serial Data (eg: LVDS) | |(backend) |---------| |------| | | ++ * | |------------------------| ------------ ------------ ------- | ++ * ------------------ ------------------------------------------------------- ++ * ++ * The framework interface is pretty simple: ++ * - Backends should register themselves with devm_iio_backend_register() ++ * - Frontend devices should get backends with devm_iio_backend_get() ++ * ++ * Also to note that the primary target for this framework are converters like ++ * ADC/DACs so iio_backend_ops will have some operations typical of converter ++ * devices. On top of that, this is "generic" for all IIO which means any kind ++ * of device can make use of the framework. That said, If the iio_backend_ops ++ * struct begins to grow out of control, we can always refactor things so that ++ * the industrialio-backend.c is only left with the really generic stuff. Then, ++ * we can build on top of it depending on the needs. ++ * ++ * Copyright (C) 2023-2024 Analog Devices Inc. ++ */ ++#define dev_fmt(fmt) "iio-backend: " fmt ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++struct iio_backend { ++ struct list_head entry; ++ const struct iio_backend_ops *ops; ++ struct device *dev; ++ struct module *owner; ++ void *priv; ++}; ++ ++/* ++ * Helper struct for requesting buffers. This ensures that we have all data ++ * that we need to free the buffer in a device managed action. ++ */ ++struct iio_backend_buffer_pair { ++ struct iio_backend *back; ++ struct iio_buffer *buffer; ++}; ++ ++static LIST_HEAD(iio_back_list); ++static DEFINE_MUTEX(iio_back_lock); ++ ++/* ++ * Helper macros to call backend ops. Makes sure the option is supported. ++ */ ++#define iio_backend_check_op(back, op) ({ \ ++ struct iio_backend *____back = back; \ ++ int ____ret = 0; \ ++ \ ++ if (!____back->ops->op) \ ++ ____ret = -EOPNOTSUPP; \ ++ \ ++ ____ret; \ ++}) ++ ++#define iio_backend_op_call(back, op, args...) ({ \ ++ struct iio_backend *__back = back; \ ++ int __ret; \ ++ \ ++ __ret = iio_backend_check_op(__back, op); \ ++ if (!__ret) \ ++ __ret = __back->ops->op(__back, ##args); \ ++ \ ++ __ret; \ ++}) ++ ++#define iio_backend_ptr_op_call(back, op, args...) ({ \ ++ struct iio_backend *__back = back; \ ++ void *ptr_err; \ ++ int __ret; \ ++ \ ++ __ret = iio_backend_check_op(__back, op); \ ++ if (__ret) \ ++ ptr_err = ERR_PTR(__ret); \ ++ else \ ++ ptr_err = __back->ops->op(__back, ##args); \ ++ \ ++ ptr_err; \ ++}) ++ ++#define iio_backend_void_op_call(back, op, args...) { \ ++ struct iio_backend *__back = back; \ ++ int __ret; \ ++ \ ++ __ret = iio_backend_check_op(__back, op); \ ++ if (!__ret) \ ++ __back->ops->op(__back, ##args); \ ++} ++ ++/** ++ * iio_backend_chan_enable - Enable a backend channel ++ * @back: Backend device ++ * @chan: Channel number ++ * ++ * RETURNS: ++ * 0 on success, negative error number on failure. ++ */ ++int iio_backend_chan_enable(struct iio_backend *back, unsigned int chan) ++{ ++ return iio_backend_op_call(back, chan_enable, chan); ++} ++EXPORT_SYMBOL_NS_GPL(iio_backend_chan_enable, IIO_BACKEND); ++ ++/** ++ * iio_backend_chan_disable - Disable a backend channel ++ * @back: Backend device ++ * @chan: Channel number ++ * ++ * RETURNS: ++ * 0 on success, negative error number on failure. ++ */ ++int iio_backend_chan_disable(struct iio_backend *back, unsigned int chan) ++{ ++ return iio_backend_op_call(back, chan_disable, chan); ++} ++EXPORT_SYMBOL_NS_GPL(iio_backend_chan_disable, IIO_BACKEND); ++ ++static void __iio_backend_disable(void *back) ++{ ++ iio_backend_void_op_call(back, disable); ++} ++ ++/** ++ * devm_iio_backend_enable - Device managed backend enable ++ * @dev: Consumer device for the backend ++ * @back: Backend device ++ * ++ * RETURNS: ++ * 0 on success, negative error number on failure. ++ */ ++int devm_iio_backend_enable(struct device *dev, struct iio_backend *back) ++{ ++ int ret; ++ ++ ret = iio_backend_op_call(back, enable); ++ if (ret) ++ return ret; ++ ++ return devm_add_action_or_reset(dev, __iio_backend_disable, back); ++} ++EXPORT_SYMBOL_NS_GPL(devm_iio_backend_enable, IIO_BACKEND); ++ ++/** ++ * iio_backend_data_format_set - Configure the channel data format ++ * @back: Backend device ++ * @chan: Channel number ++ * @data: Data format ++ * ++ * Properly configure a channel with respect to the expected data format. A ++ * @struct iio_backend_data_fmt must be passed with the settings. ++ * ++ * RETURNS: ++ * 0 on success, negative error number on failure. ++ */ ++int iio_backend_data_format_set(struct iio_backend *back, unsigned int chan, ++ const struct iio_backend_data_fmt *data) ++{ ++ if (!data || data->type >= IIO_BACKEND_DATA_TYPE_MAX) ++ return -EINVAL; ++ ++ return iio_backend_op_call(back, data_format_set, chan, data); ++} ++EXPORT_SYMBOL_NS_GPL(iio_backend_data_format_set, IIO_BACKEND); ++ ++static void iio_backend_free_buffer(void *arg) ++{ ++ struct iio_backend_buffer_pair *pair = arg; ++ ++ iio_backend_void_op_call(pair->back, free_buffer, pair->buffer); ++} ++ ++/** ++ * devm_iio_backend_request_buffer - Device managed buffer request ++ * @dev: Consumer device for the backend ++ * @back: Backend device ++ * @indio_dev: IIO device ++ * ++ * Request an IIO buffer from the backend. The type of the buffer (typically ++ * INDIO_BUFFER_HARDWARE) is up to the backend to decide. This is because, ++ * normally, the backend dictates what kind of buffering we can get. ++ * ++ * The backend .free_buffer() hooks is automatically called on @dev detach. ++ * ++ * RETURNS: ++ * 0 on success, negative error number on failure. ++ */ ++int devm_iio_backend_request_buffer(struct device *dev, ++ struct iio_backend *back, ++ struct iio_dev *indio_dev) ++{ ++ struct iio_backend_buffer_pair *pair; ++ struct iio_buffer *buffer; ++ ++ pair = devm_kzalloc(dev, sizeof(*pair), GFP_KERNEL); ++ if (!pair) ++ return -ENOMEM; ++ ++ buffer = iio_backend_ptr_op_call(back, request_buffer, indio_dev); ++ if (IS_ERR(buffer)) ++ return PTR_ERR(buffer); ++ ++ /* weak reference should be all what we need */ ++ pair->back = back; ++ pair->buffer = buffer; ++ ++ return devm_add_action_or_reset(dev, iio_backend_free_buffer, pair); ++} ++EXPORT_SYMBOL_NS_GPL(devm_iio_backend_request_buffer, IIO_BACKEND); ++ ++static void iio_backend_release(void *arg) ++{ ++ struct iio_backend *back = arg; ++ ++ module_put(back->owner); ++} ++ ++static int __devm_iio_backend_get(struct device *dev, struct iio_backend *back) ++{ ++ struct device_link *link; ++ int ret; ++ ++ /* ++ * Make sure the provider cannot be unloaded before the consumer module. ++ * Note that device_links would still guarantee that nothing is ++ * accessible (and breaks) but this makes it explicit that the consumer ++ * module must be also unloaded. ++ */ ++ if (!try_module_get(back->owner)) ++ return dev_err_probe(dev, -ENODEV, ++ "Cannot get module reference\n"); ++ ++ ret = devm_add_action_or_reset(dev, iio_backend_release, back); ++ if (ret) ++ return ret; ++ ++ link = device_link_add(dev, back->dev, DL_FLAG_AUTOREMOVE_CONSUMER); ++ if (!link) ++ return dev_err_probe(dev, -EINVAL, ++ "Could not link to supplier(%s)\n", ++ dev_name(back->dev)); ++ ++ dev_dbg(dev, "Found backend(%s) device\n", dev_name(back->dev)); ++ ++ return 0; ++} ++ ++/** ++ * devm_iio_backend_get - Device managed backend device get ++ * @dev: Consumer device for the backend ++ * @name: Backend name ++ * ++ * Get's the backend associated with @dev. ++ * ++ * RETURNS: ++ * A backend pointer, negative error pointer otherwise. ++ */ ++struct iio_backend *devm_iio_backend_get(struct device *dev, const char *name) ++{ ++ struct fwnode_handle *fwnode; ++ struct iio_backend *back; ++ unsigned int index; ++ int ret; ++ ++ if (name) { ++ ret = device_property_match_string(dev, "io-backend-names", ++ name); ++ if (ret < 0) ++ return ERR_PTR(ret); ++ index = ret; ++ } else { ++ index = 0; ++ } ++ ++ fwnode = fwnode_find_reference(dev_fwnode(dev), "io-backends", index); ++ if (IS_ERR(fwnode)) { ++ dev_err_probe(dev, PTR_ERR(fwnode), ++ "Cannot get Firmware reference\n"); ++ return ERR_CAST(fwnode); ++ } ++ ++ guard(mutex)(&iio_back_lock); ++ list_for_each_entry(back, &iio_back_list, entry) { ++ if (!device_match_fwnode(back->dev, fwnode)) ++ continue; ++ ++ fwnode_handle_put(fwnode); ++ ret = __devm_iio_backend_get(dev, back); ++ if (ret) ++ return ERR_PTR(ret); ++ ++ return back; ++ } ++ ++ fwnode_handle_put(fwnode); ++ return ERR_PTR(-EPROBE_DEFER); ++} ++EXPORT_SYMBOL_NS_GPL(devm_iio_backend_get, IIO_BACKEND); ++ ++/** ++ * __devm_iio_backend_get_from_fwnode_lookup - Device managed fwnode backend device get ++ * @dev: Consumer device for the backend ++ * @fwnode: Firmware node of the backend device ++ * ++ * Search the backend list for a device matching @fwnode. ++ * This API should not be used and it's only present for preventing the first ++ * user of this framework to break it's DT ABI. ++ * ++ * RETURNS: ++ * A backend pointer, negative error pointer otherwise. ++ */ ++struct iio_backend * ++__devm_iio_backend_get_from_fwnode_lookup(struct device *dev, ++ struct fwnode_handle *fwnode) ++{ ++ struct iio_backend *back; ++ int ret; ++ ++ guard(mutex)(&iio_back_lock); ++ list_for_each_entry(back, &iio_back_list, entry) { ++ if (!device_match_fwnode(back->dev, fwnode)) ++ continue; ++ ++ ret = __devm_iio_backend_get(dev, back); ++ if (ret) ++ return ERR_PTR(ret); ++ ++ return back; ++ } ++ ++ return ERR_PTR(-EPROBE_DEFER); ++} ++EXPORT_SYMBOL_NS_GPL(__devm_iio_backend_get_from_fwnode_lookup, IIO_BACKEND); ++ ++/** ++ * iio_backend_get_priv - Get driver private data ++ * @back: Backend device ++ */ ++void *iio_backend_get_priv(const struct iio_backend *back) ++{ ++ return back->priv; ++} ++EXPORT_SYMBOL_NS_GPL(iio_backend_get_priv, IIO_BACKEND); ++ ++static void iio_backend_unregister(void *arg) ++{ ++ struct iio_backend *back = arg; ++ ++ guard(mutex)(&iio_back_lock); ++ list_del(&back->entry); ++} ++ ++/** ++ * devm_iio_backend_register - Device managed backend device register ++ * @dev: Backend device being registered ++ * @ops: Backend ops ++ * @priv: Device private data ++ * ++ * @ops is mandatory. Not providing it results in -EINVAL. ++ * ++ * RETURNS: ++ * 0 on success, negative error number on failure. ++ */ ++int devm_iio_backend_register(struct device *dev, ++ const struct iio_backend_ops *ops, void *priv) ++{ ++ struct iio_backend *back; ++ ++ if (!ops) ++ return dev_err_probe(dev, -EINVAL, "No backend ops given\n"); ++ ++ /* ++ * Through device_links, we guarantee that a frontend device cannot be ++ * bound/exist if the backend driver is not around. Hence, we can bind ++ * the backend object lifetime with the device being passed since ++ * removing it will tear the frontend/consumer down. ++ */ ++ back = devm_kzalloc(dev, sizeof(*back), GFP_KERNEL); ++ if (!back) ++ return -ENOMEM; ++ ++ back->ops = ops; ++ back->owner = dev->driver->owner; ++ back->dev = dev; ++ back->priv = priv; ++ scoped_guard(mutex, &iio_back_lock) ++ list_add(&back->entry, &iio_back_list); ++ ++ return devm_add_action_or_reset(dev, iio_backend_unregister, back); ++} ++EXPORT_SYMBOL_NS_GPL(devm_iio_backend_register, IIO_BACKEND); ++ ++MODULE_AUTHOR("Nuno Sa "); ++MODULE_DESCRIPTION("Framework to handle complex IIO aggregate devices"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c +index feec93adb0651..5e1a85ca12119 100644 +--- a/drivers/iio/industrialio-core.c ++++ b/drivers/iio/industrialio-core.c +@@ -1649,8 +1649,10 @@ struct iio_dev *iio_device_alloc(struct device *parent, int sizeof_priv) + return NULL; + + indio_dev = &iio_dev_opaque->indio_dev; +- indio_dev->priv = (char *)iio_dev_opaque + +- ALIGN(sizeof(struct iio_dev_opaque), IIO_DMA_MINALIGN); ++ ++ if (sizeof_priv) ++ indio_dev->priv = (char *)iio_dev_opaque + ++ ALIGN(sizeof(*iio_dev_opaque), IIO_DMA_MINALIGN); + + indio_dev->dev.parent = parent; + indio_dev->dev.type = &iio_device_type; +diff --git a/drivers/iio/pressure/dps310.c b/drivers/iio/pressure/dps310.c +index 1ff091b2f764d..d0a516d56da47 100644 +--- a/drivers/iio/pressure/dps310.c ++++ b/drivers/iio/pressure/dps310.c +@@ -730,7 +730,7 @@ static int dps310_read_pressure(struct dps310_data *data, int *val, int *val2, + } + } + +-static int dps310_calculate_temp(struct dps310_data *data) ++static int dps310_calculate_temp(struct dps310_data *data, int *val) + { + s64 c0; + s64 t; +@@ -746,7 +746,9 @@ static int dps310_calculate_temp(struct dps310_data *data) + t = c0 + ((s64)data->temp_raw * (s64)data->c1); + + /* Convert to milliCelsius and scale the temperature */ +- return (int)div_s64(t * 1000LL, kt); ++ *val = (int)div_s64(t * 1000LL, kt); ++ ++ return 0; + } + + static int dps310_read_temp(struct dps310_data *data, int *val, int *val2, +@@ -768,11 +770,10 @@ static int dps310_read_temp(struct dps310_data *data, int *val, int *val2, + if (rc) + return rc; + +- rc = dps310_calculate_temp(data); +- if (rc < 0) ++ rc = dps310_calculate_temp(data, val); ++ if (rc) + return rc; + +- *val = rc; + return IIO_VAL_INT; + + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: +diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c +index 1e2cd7c8716e8..64ace0b968f07 100644 +--- a/drivers/infiniband/core/cma.c ++++ b/drivers/infiniband/core/cma.c +@@ -715,8 +715,10 @@ cma_validate_port(struct ib_device *device, u32 port, + rcu_read_lock(); + ndev = rcu_dereference(sgid_attr->ndev); + if (!net_eq(dev_net(ndev), dev_addr->net) || +- ndev->ifindex != bound_if_index) ++ ndev->ifindex != bound_if_index) { ++ rdma_put_gid_attr(sgid_attr); + sgid_attr = ERR_PTR(-ENODEV); ++ } + rcu_read_unlock(); + goto out; + } +diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.c b/drivers/infiniband/hw/bnxt_re/ib_verbs.c +index cc466dfd792b0..fd69be982ce06 100644 +--- a/drivers/infiniband/hw/bnxt_re/ib_verbs.c ++++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.c +@@ -1184,7 +1184,8 @@ static struct bnxt_re_qp *bnxt_re_create_shadow_qp + } + + static int bnxt_re_init_rq_attr(struct bnxt_re_qp *qp, +- struct ib_qp_init_attr *init_attr) ++ struct ib_qp_init_attr *init_attr, ++ struct bnxt_re_ucontext *uctx) + { + struct bnxt_qplib_dev_attr *dev_attr; + struct bnxt_qplib_qp *qplqp; +@@ -1213,7 +1214,7 @@ static int bnxt_re_init_rq_attr(struct bnxt_re_qp *qp, + /* Allocate 1 more than what's provided so posting max doesn't + * mean empty. + */ +- entries = roundup_pow_of_two(init_attr->cap.max_recv_wr + 1); ++ entries = bnxt_re_init_depth(init_attr->cap.max_recv_wr + 1, uctx); + rq->max_wqe = min_t(u32, entries, dev_attr->max_qp_wqes + 1); + rq->q_full_delta = 0; + rq->sg_info.pgsize = PAGE_SIZE; +@@ -1243,7 +1244,7 @@ static void bnxt_re_adjust_gsi_rq_attr(struct bnxt_re_qp *qp) + + static int bnxt_re_init_sq_attr(struct bnxt_re_qp *qp, + struct ib_qp_init_attr *init_attr, +- struct ib_udata *udata) ++ struct bnxt_re_ucontext *uctx) + { + struct bnxt_qplib_dev_attr *dev_attr; + struct bnxt_qplib_qp *qplqp; +@@ -1272,7 +1273,7 @@ static int bnxt_re_init_sq_attr(struct bnxt_re_qp *qp, + /* Allocate 128 + 1 more than what's provided */ + diff = (qplqp->wqe_mode == BNXT_QPLIB_WQE_MODE_VARIABLE) ? + 0 : BNXT_QPLIB_RESERVED_QP_WRS; +- entries = roundup_pow_of_two(entries + diff + 1); ++ entries = bnxt_re_init_depth(entries + diff + 1, uctx); + sq->max_wqe = min_t(u32, entries, dev_attr->max_qp_wqes + diff + 1); + sq->q_full_delta = diff + 1; + /* +@@ -1288,7 +1289,8 @@ static int bnxt_re_init_sq_attr(struct bnxt_re_qp *qp, + } + + static void bnxt_re_adjust_gsi_sq_attr(struct bnxt_re_qp *qp, +- struct ib_qp_init_attr *init_attr) ++ struct ib_qp_init_attr *init_attr, ++ struct bnxt_re_ucontext *uctx) + { + struct bnxt_qplib_dev_attr *dev_attr; + struct bnxt_qplib_qp *qplqp; +@@ -1300,7 +1302,7 @@ static void bnxt_re_adjust_gsi_sq_attr(struct bnxt_re_qp *qp, + dev_attr = &rdev->dev_attr; + + if (!bnxt_qplib_is_chip_gen_p5(rdev->chip_ctx)) { +- entries = roundup_pow_of_two(init_attr->cap.max_send_wr + 1); ++ entries = bnxt_re_init_depth(init_attr->cap.max_send_wr + 1, uctx); + qplqp->sq.max_wqe = min_t(u32, entries, + dev_attr->max_qp_wqes + 1); + qplqp->sq.q_full_delta = qplqp->sq.max_wqe - +@@ -1338,6 +1340,7 @@ static int bnxt_re_init_qp_attr(struct bnxt_re_qp *qp, struct bnxt_re_pd *pd, + struct ib_udata *udata) + { + struct bnxt_qplib_dev_attr *dev_attr; ++ struct bnxt_re_ucontext *uctx; + struct bnxt_qplib_qp *qplqp; + struct bnxt_re_dev *rdev; + struct bnxt_re_cq *cq; +@@ -1347,6 +1350,7 @@ static int bnxt_re_init_qp_attr(struct bnxt_re_qp *qp, struct bnxt_re_pd *pd, + qplqp = &qp->qplib_qp; + dev_attr = &rdev->dev_attr; + ++ uctx = rdma_udata_to_drv_context(udata, struct bnxt_re_ucontext, ib_uctx); + /* Setup misc params */ + ether_addr_copy(qplqp->smac, rdev->netdev->dev_addr); + qplqp->pd = &pd->qplib_pd; +@@ -1388,18 +1392,18 @@ static int bnxt_re_init_qp_attr(struct bnxt_re_qp *qp, struct bnxt_re_pd *pd, + } + + /* Setup RQ/SRQ */ +- rc = bnxt_re_init_rq_attr(qp, init_attr); ++ rc = bnxt_re_init_rq_attr(qp, init_attr, uctx); + if (rc) + goto out; + if (init_attr->qp_type == IB_QPT_GSI) + bnxt_re_adjust_gsi_rq_attr(qp); + + /* Setup SQ */ +- rc = bnxt_re_init_sq_attr(qp, init_attr, udata); ++ rc = bnxt_re_init_sq_attr(qp, init_attr, uctx); + if (rc) + goto out; + if (init_attr->qp_type == IB_QPT_GSI) +- bnxt_re_adjust_gsi_sq_attr(qp, init_attr); ++ bnxt_re_adjust_gsi_sq_attr(qp, init_attr, uctx); + + if (udata) /* This will update DPI and qp_handle */ + rc = bnxt_re_init_user_qp(rdev, pd, qp, udata); +@@ -1715,6 +1719,7 @@ int bnxt_re_create_srq(struct ib_srq *ib_srq, + { + struct bnxt_qplib_dev_attr *dev_attr; + struct bnxt_qplib_nq *nq = NULL; ++ struct bnxt_re_ucontext *uctx; + struct bnxt_re_dev *rdev; + struct bnxt_re_srq *srq; + struct bnxt_re_pd *pd; +@@ -1739,13 +1744,14 @@ int bnxt_re_create_srq(struct ib_srq *ib_srq, + goto exit; + } + ++ uctx = rdma_udata_to_drv_context(udata, struct bnxt_re_ucontext, ib_uctx); + srq->rdev = rdev; + srq->qplib_srq.pd = &pd->qplib_pd; + srq->qplib_srq.dpi = &rdev->dpi_privileged; + /* Allocate 1 more than what's provided so posting max doesn't + * mean empty + */ +- entries = roundup_pow_of_two(srq_init_attr->attr.max_wr + 1); ++ entries = bnxt_re_init_depth(srq_init_attr->attr.max_wr + 1, uctx); + if (entries > dev_attr->max_srq_wqes + 1) + entries = dev_attr->max_srq_wqes + 1; + srq->qplib_srq.max_wqe = entries; +@@ -2102,6 +2108,9 @@ int bnxt_re_modify_qp(struct ib_qp *ib_qp, struct ib_qp_attr *qp_attr, + qp->qplib_qp.max_dest_rd_atomic = qp_attr->max_dest_rd_atomic; + } + if (qp_attr_mask & IB_QP_CAP) { ++ struct bnxt_re_ucontext *uctx = ++ rdma_udata_to_drv_context(udata, struct bnxt_re_ucontext, ib_uctx); ++ + qp->qplib_qp.modify_flags |= + CMDQ_MODIFY_QP_MODIFY_MASK_SQ_SIZE | + CMDQ_MODIFY_QP_MODIFY_MASK_RQ_SIZE | +@@ -2118,7 +2127,7 @@ int bnxt_re_modify_qp(struct ib_qp *ib_qp, struct ib_qp_attr *qp_attr, + "Create QP failed - max exceeded"); + return -EINVAL; + } +- entries = roundup_pow_of_two(qp_attr->cap.max_send_wr); ++ entries = bnxt_re_init_depth(qp_attr->cap.max_send_wr, uctx); + qp->qplib_qp.sq.max_wqe = min_t(u32, entries, + dev_attr->max_qp_wqes + 1); + qp->qplib_qp.sq.q_full_delta = qp->qplib_qp.sq.max_wqe - +@@ -2131,7 +2140,7 @@ int bnxt_re_modify_qp(struct ib_qp *ib_qp, struct ib_qp_attr *qp_attr, + qp->qplib_qp.sq.q_full_delta -= 1; + qp->qplib_qp.sq.max_sge = qp_attr->cap.max_send_sge; + if (qp->qplib_qp.rq.max_wqe) { +- entries = roundup_pow_of_two(qp_attr->cap.max_recv_wr); ++ entries = bnxt_re_init_depth(qp_attr->cap.max_recv_wr, uctx); + qp->qplib_qp.rq.max_wqe = + min_t(u32, entries, dev_attr->max_qp_wqes + 1); + qp->qplib_qp.rq.q_full_delta = qp->qplib_qp.rq.max_wqe - +@@ -2919,9 +2928,11 @@ int bnxt_re_destroy_cq(struct ib_cq *ib_cq, struct ib_udata *udata) + int bnxt_re_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr, + struct ib_udata *udata) + { ++ struct bnxt_re_cq *cq = container_of(ibcq, struct bnxt_re_cq, ib_cq); + struct bnxt_re_dev *rdev = to_bnxt_re_dev(ibcq->device, ibdev); ++ struct bnxt_re_ucontext *uctx = ++ rdma_udata_to_drv_context(udata, struct bnxt_re_ucontext, ib_uctx); + struct bnxt_qplib_dev_attr *dev_attr = &rdev->dev_attr; +- struct bnxt_re_cq *cq = container_of(ibcq, struct bnxt_re_cq, ib_cq); + int rc, entries; + int cqe = attr->cqe; + struct bnxt_qplib_nq *nq = NULL; +@@ -2940,7 +2951,7 @@ int bnxt_re_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr, + cq->rdev = rdev; + cq->qplib_cq.cq_handle = (u64)(unsigned long)(&cq->qplib_cq); + +- entries = roundup_pow_of_two(cqe + 1); ++ entries = bnxt_re_init_depth(cqe + 1, uctx); + if (entries > dev_attr->max_cq_wqes + 1) + entries = dev_attr->max_cq_wqes + 1; + +@@ -2948,8 +2959,6 @@ int bnxt_re_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr, + cq->qplib_cq.sg_info.pgshft = PAGE_SHIFT; + if (udata) { + struct bnxt_re_cq_req req; +- struct bnxt_re_ucontext *uctx = rdma_udata_to_drv_context( +- udata, struct bnxt_re_ucontext, ib_uctx); + if (ib_copy_from_udata(&req, udata, sizeof(req))) { + rc = -EFAULT; + goto fail; +@@ -3071,12 +3080,11 @@ int bnxt_re_resize_cq(struct ib_cq *ibcq, int cqe, struct ib_udata *udata) + return -EINVAL; + } + +- entries = roundup_pow_of_two(cqe + 1); ++ uctx = rdma_udata_to_drv_context(udata, struct bnxt_re_ucontext, ib_uctx); ++ entries = bnxt_re_init_depth(cqe + 1, uctx); + if (entries > dev_attr->max_cq_wqes + 1) + entries = dev_attr->max_cq_wqes + 1; + +- uctx = rdma_udata_to_drv_context(udata, struct bnxt_re_ucontext, +- ib_uctx); + /* uverbs consumer */ + if (ib_copy_from_udata(&req, udata, sizeof(req))) { + rc = -EFAULT; +@@ -4107,6 +4115,7 @@ int bnxt_re_alloc_ucontext(struct ib_ucontext *ctx, struct ib_udata *udata) + struct bnxt_qplib_dev_attr *dev_attr = &rdev->dev_attr; + struct bnxt_re_user_mmap_entry *entry; + struct bnxt_re_uctx_resp resp = {}; ++ struct bnxt_re_uctx_req ureq = {}; + u32 chip_met_rev_num = 0; + int rc; + +@@ -4156,6 +4165,16 @@ int bnxt_re_alloc_ucontext(struct ib_ucontext *ctx, struct ib_udata *udata) + if (rdev->pacing.dbr_pacing) + resp.comp_mask |= BNXT_RE_UCNTX_CMASK_DBR_PACING_ENABLED; + ++ if (udata->inlen >= sizeof(ureq)) { ++ rc = ib_copy_from_udata(&ureq, udata, min(udata->inlen, sizeof(ureq))); ++ if (rc) ++ goto cfail; ++ if (ureq.comp_mask & BNXT_RE_COMP_MASK_REQ_UCNTX_POW2_SUPPORT) { ++ resp.comp_mask |= BNXT_RE_UCNTX_CMASK_POW2_DISABLED; ++ uctx->cmask |= BNXT_RE_UCNTX_CMASK_POW2_DISABLED; ++ } ++ } ++ + rc = ib_copy_to_udata(udata, &resp, min(udata->outlen, sizeof(resp))); + if (rc) { + ibdev_err(ibdev, "Failed to copy user context"); +diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.h b/drivers/infiniband/hw/bnxt_re/ib_verbs.h +index 84715b7e7a4e4..98baea98fc176 100644 +--- a/drivers/infiniband/hw/bnxt_re/ib_verbs.h ++++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.h +@@ -140,6 +140,7 @@ struct bnxt_re_ucontext { + void *shpg; + spinlock_t sh_lock; /* protect shpg */ + struct rdma_user_mmap_entry *shpage_mmap; ++ u64 cmask; + }; + + enum bnxt_re_mmap_flag { +@@ -167,6 +168,12 @@ static inline u16 bnxt_re_get_rwqe_size(int nsge) + return sizeof(struct rq_wqe_hdr) + (nsge * sizeof(struct sq_sge)); + } + ++static inline u32 bnxt_re_init_depth(u32 ent, struct bnxt_re_ucontext *uctx) ++{ ++ return uctx ? (uctx->cmask & BNXT_RE_UCNTX_CMASK_POW2_DISABLED) ? ++ ent : roundup_pow_of_two(ent) : ent; ++} ++ + int bnxt_re_query_device(struct ib_device *ibdev, + struct ib_device_attr *ib_attr, + struct ib_udata *udata); +diff --git a/drivers/infiniband/hw/bnxt_re/qplib_fp.c b/drivers/infiniband/hw/bnxt_re/qplib_fp.c +index 2a62239187622..3b28878f62062 100644 +--- a/drivers/infiniband/hw/bnxt_re/qplib_fp.c ++++ b/drivers/infiniband/hw/bnxt_re/qplib_fp.c +@@ -237,18 +237,15 @@ static void clean_nq(struct bnxt_qplib_nq *nq, struct bnxt_qplib_cq *cq) + struct bnxt_qplib_hwq *hwq = &nq->hwq; + struct nq_base *nqe, **nq_ptr; + int budget = nq->budget; +- u32 sw_cons, raw_cons; + uintptr_t q_handle; + u16 type; + + spin_lock_bh(&hwq->lock); + /* Service the NQ until empty */ +- raw_cons = hwq->cons; + while (budget--) { +- sw_cons = HWQ_CMP(raw_cons, hwq); + nq_ptr = (struct nq_base **)hwq->pbl_ptr; +- nqe = &nq_ptr[NQE_PG(sw_cons)][NQE_IDX(sw_cons)]; +- if (!NQE_CMP_VALID(nqe, raw_cons, hwq->max_elements)) ++ nqe = &nq_ptr[NQE_PG(hwq->cons)][NQE_IDX(hwq->cons)]; ++ if (!NQE_CMP_VALID(nqe, nq->nq_db.dbinfo.flags)) + break; + + /* +@@ -276,7 +273,8 @@ static void clean_nq(struct bnxt_qplib_nq *nq, struct bnxt_qplib_cq *cq) + default: + break; + } +- raw_cons++; ++ bnxt_qplib_hwq_incr_cons(hwq->max_elements, &hwq->cons, ++ 1, &nq->nq_db.dbinfo.flags); + } + spin_unlock_bh(&hwq->lock); + } +@@ -302,18 +300,16 @@ static void bnxt_qplib_service_nq(struct tasklet_struct *t) + struct bnxt_qplib_hwq *hwq = &nq->hwq; + struct bnxt_qplib_cq *cq; + int budget = nq->budget; +- u32 sw_cons, raw_cons; + struct nq_base *nqe; + uintptr_t q_handle; ++ u32 hw_polled = 0; + u16 type; + + spin_lock_bh(&hwq->lock); + /* Service the NQ until empty */ +- raw_cons = hwq->cons; + while (budget--) { +- sw_cons = HWQ_CMP(raw_cons, hwq); +- nqe = bnxt_qplib_get_qe(hwq, sw_cons, NULL); +- if (!NQE_CMP_VALID(nqe, raw_cons, hwq->max_elements)) ++ nqe = bnxt_qplib_get_qe(hwq, hwq->cons, NULL); ++ if (!NQE_CMP_VALID(nqe, nq->nq_db.dbinfo.flags)) + break; + + /* +@@ -372,12 +368,12 @@ static void bnxt_qplib_service_nq(struct tasklet_struct *t) + "nqe with type = 0x%x not handled\n", type); + break; + } +- raw_cons++; ++ hw_polled++; ++ bnxt_qplib_hwq_incr_cons(hwq->max_elements, &hwq->cons, ++ 1, &nq->nq_db.dbinfo.flags); + } +- if (hwq->cons != raw_cons) { +- hwq->cons = raw_cons; ++ if (hw_polled) + bnxt_qplib_ring_nq_db(&nq->nq_db.dbinfo, nq->res->cctx, true); +- } + spin_unlock_bh(&hwq->lock); + } + +@@ -505,6 +501,7 @@ static int bnxt_qplib_map_nq_db(struct bnxt_qplib_nq *nq, u32 reg_offt) + pdev = nq->pdev; + nq_db = &nq->nq_db; + ++ nq_db->dbinfo.flags = 0; + nq_db->reg.bar_id = NQ_CONS_PCI_BAR_REGION; + nq_db->reg.bar_base = pci_resource_start(pdev, nq_db->reg.bar_id); + if (!nq_db->reg.bar_base) { +@@ -649,7 +646,7 @@ int bnxt_qplib_create_srq(struct bnxt_qplib_res *res, + rc = -ENOMEM; + goto fail; + } +- ++ srq->dbinfo.flags = 0; + bnxt_qplib_rcfw_cmd_prep((struct cmdq_base *)&req, + CMDQ_BASE_OPCODE_CREATE_SRQ, + sizeof(req)); +@@ -703,13 +700,9 @@ int bnxt_qplib_modify_srq(struct bnxt_qplib_res *res, + struct bnxt_qplib_srq *srq) + { + struct bnxt_qplib_hwq *srq_hwq = &srq->hwq; +- u32 sw_prod, sw_cons, count = 0; +- +- sw_prod = HWQ_CMP(srq_hwq->prod, srq_hwq); +- sw_cons = HWQ_CMP(srq_hwq->cons, srq_hwq); ++ u32 count; + +- count = sw_prod > sw_cons ? sw_prod - sw_cons : +- srq_hwq->max_elements - sw_cons + sw_prod; ++ count = __bnxt_qplib_get_avail(srq_hwq); + if (count > srq->threshold) { + srq->arm_req = false; + bnxt_qplib_srq_arm_db(&srq->dbinfo, srq->threshold); +@@ -762,7 +755,7 @@ int bnxt_qplib_post_srq_recv(struct bnxt_qplib_srq *srq, + struct bnxt_qplib_hwq *srq_hwq = &srq->hwq; + struct rq_wqe *srqe; + struct sq_sge *hw_sge; +- u32 sw_prod, sw_cons, count = 0; ++ u32 count = 0; + int i, next; + + spin_lock(&srq_hwq->lock); +@@ -776,8 +769,7 @@ int bnxt_qplib_post_srq_recv(struct bnxt_qplib_srq *srq, + srq->start_idx = srq->swq[next].next_idx; + spin_unlock(&srq_hwq->lock); + +- sw_prod = HWQ_CMP(srq_hwq->prod, srq_hwq); +- srqe = bnxt_qplib_get_qe(srq_hwq, sw_prod, NULL); ++ srqe = bnxt_qplib_get_qe(srq_hwq, srq_hwq->prod, NULL); + memset(srqe, 0, srq->wqe_size); + /* Calculate wqe_size16 and data_len */ + for (i = 0, hw_sge = (struct sq_sge *)srqe->data; +@@ -793,17 +785,10 @@ int bnxt_qplib_post_srq_recv(struct bnxt_qplib_srq *srq, + srqe->wr_id[0] = cpu_to_le32((u32)next); + srq->swq[next].wr_id = wqe->wr_id; + +- srq_hwq->prod++; ++ bnxt_qplib_hwq_incr_prod(&srq->dbinfo, srq_hwq, srq->dbinfo.max_slot); + + spin_lock(&srq_hwq->lock); +- sw_prod = HWQ_CMP(srq_hwq->prod, srq_hwq); +- /* retaining srq_hwq->cons for this logic +- * actually the lock is only required to +- * read srq_hwq->cons. +- */ +- sw_cons = HWQ_CMP(srq_hwq->cons, srq_hwq); +- count = sw_prod > sw_cons ? sw_prod - sw_cons : +- srq_hwq->max_elements - sw_cons + sw_prod; ++ count = __bnxt_qplib_get_avail(srq_hwq); + spin_unlock(&srq_hwq->lock); + /* Ring DB */ + bnxt_qplib_ring_prod_db(&srq->dbinfo, DBC_DBC_TYPE_SRQ); +@@ -850,6 +835,7 @@ int bnxt_qplib_create_qp1(struct bnxt_qplib_res *res, struct bnxt_qplib_qp *qp) + u32 tbl_indx; + int rc; + ++ sq->dbinfo.flags = 0; + bnxt_qplib_rcfw_cmd_prep((struct cmdq_base *)&req, + CMDQ_BASE_OPCODE_CREATE_QP1, + sizeof(req)); +@@ -886,6 +872,7 @@ int bnxt_qplib_create_qp1(struct bnxt_qplib_res *res, struct bnxt_qplib_qp *qp) + + /* RQ */ + if (rq->max_wqe) { ++ rq->dbinfo.flags = 0; + hwq_attr.res = res; + hwq_attr.sginfo = &rq->sg_info; + hwq_attr.stride = sizeof(struct sq_sge); +@@ -993,6 +980,10 @@ int bnxt_qplib_create_qp(struct bnxt_qplib_res *res, struct bnxt_qplib_qp *qp) + u32 tbl_indx; + u16 nsge; + ++ if (res->dattr) ++ qp->dev_cap_flags = res->dattr->dev_cap_flags; ++ ++ sq->dbinfo.flags = 0; + bnxt_qplib_rcfw_cmd_prep((struct cmdq_base *)&req, + CMDQ_BASE_OPCODE_CREATE_QP, + sizeof(req)); +@@ -1007,6 +998,11 @@ int bnxt_qplib_create_qp(struct bnxt_qplib_res *res, struct bnxt_qplib_qp *qp) + psn_sz = bnxt_qplib_is_chip_gen_p5(res->cctx) ? + sizeof(struct sq_psn_search_ext) : + sizeof(struct sq_psn_search); ++ ++ if (BNXT_RE_HW_RETX(qp->dev_cap_flags)) { ++ psn_sz = sizeof(struct sq_msn_search); ++ qp->msn = 0; ++ } + } + + hwq_attr.res = res; +@@ -1014,7 +1010,15 @@ int bnxt_qplib_create_qp(struct bnxt_qplib_res *res, struct bnxt_qplib_qp *qp) + hwq_attr.stride = sizeof(struct sq_sge); + hwq_attr.depth = bnxt_qplib_get_depth(sq); + hwq_attr.aux_stride = psn_sz; +- hwq_attr.aux_depth = bnxt_qplib_set_sq_size(sq, qp->wqe_mode); ++ hwq_attr.aux_depth = psn_sz ? bnxt_qplib_set_sq_size(sq, qp->wqe_mode) ++ : 0; ++ /* Update msn tbl size */ ++ if (BNXT_RE_HW_RETX(qp->dev_cap_flags) && psn_sz) { ++ hwq_attr.aux_depth = roundup_pow_of_two(bnxt_qplib_set_sq_size(sq, qp->wqe_mode)); ++ qp->msn_tbl_sz = hwq_attr.aux_depth; ++ qp->msn = 0; ++ } ++ + hwq_attr.type = HWQ_TYPE_QUEUE; + rc = bnxt_qplib_alloc_init_hwq(&sq->hwq, &hwq_attr); + if (rc) +@@ -1041,6 +1045,7 @@ int bnxt_qplib_create_qp(struct bnxt_qplib_res *res, struct bnxt_qplib_qp *qp) + + /* RQ */ + if (!qp->srq) { ++ rq->dbinfo.flags = 0; + hwq_attr.res = res; + hwq_attr.sginfo = &rq->sg_info; + hwq_attr.stride = sizeof(struct sq_sge); +@@ -1455,12 +1460,15 @@ int bnxt_qplib_query_qp(struct bnxt_qplib_res *res, struct bnxt_qplib_qp *qp) + static void __clean_cq(struct bnxt_qplib_cq *cq, u64 qp) + { + struct bnxt_qplib_hwq *cq_hwq = &cq->hwq; ++ u32 peek_flags, peek_cons; + struct cq_base *hw_cqe; + int i; + ++ peek_flags = cq->dbinfo.flags; ++ peek_cons = cq_hwq->cons; + for (i = 0; i < cq_hwq->max_elements; i++) { +- hw_cqe = bnxt_qplib_get_qe(cq_hwq, i, NULL); +- if (!CQE_CMP_VALID(hw_cqe, i, cq_hwq->max_elements)) ++ hw_cqe = bnxt_qplib_get_qe(cq_hwq, peek_cons, NULL); ++ if (!CQE_CMP_VALID(hw_cqe, peek_flags)) + continue; + /* + * The valid test of the entry must be done first before +@@ -1490,6 +1498,8 @@ static void __clean_cq(struct bnxt_qplib_cq *cq, u64 qp) + default: + break; + } ++ bnxt_qplib_hwq_incr_cons(cq_hwq->max_elements, &peek_cons, ++ 1, &peek_flags); + } + } + +@@ -1591,6 +1601,27 @@ void *bnxt_qplib_get_qp1_rq_buf(struct bnxt_qplib_qp *qp, + return NULL; + } + ++/* Fil the MSN table into the next psn row */ ++static void bnxt_qplib_fill_msn_search(struct bnxt_qplib_qp *qp, ++ struct bnxt_qplib_swqe *wqe, ++ struct bnxt_qplib_swq *swq) ++{ ++ struct sq_msn_search *msns; ++ u32 start_psn, next_psn; ++ u16 start_idx; ++ ++ msns = (struct sq_msn_search *)swq->psn_search; ++ msns->start_idx_next_psn_start_psn = 0; ++ ++ start_psn = swq->start_psn; ++ next_psn = swq->next_psn; ++ start_idx = swq->slot_idx; ++ msns->start_idx_next_psn_start_psn |= ++ bnxt_re_update_msn_tbl(start_idx, next_psn, start_psn); ++ qp->msn++; ++ qp->msn %= qp->msn_tbl_sz; ++} ++ + static void bnxt_qplib_fill_psn_search(struct bnxt_qplib_qp *qp, + struct bnxt_qplib_swqe *wqe, + struct bnxt_qplib_swq *swq) +@@ -1602,6 +1633,12 @@ static void bnxt_qplib_fill_psn_search(struct bnxt_qplib_qp *qp, + + if (!swq->psn_search) + return; ++ /* Handle MSN differently on cap flags */ ++ if (BNXT_RE_HW_RETX(qp->dev_cap_flags)) { ++ bnxt_qplib_fill_msn_search(qp, wqe, swq); ++ return; ++ } ++ psns = (struct sq_psn_search *)swq->psn_search; + psns = swq->psn_search; + psns_ext = swq->psn_ext; + +@@ -1710,8 +1747,8 @@ static u16 bnxt_qplib_required_slots(struct bnxt_qplib_qp *qp, + return slot; + } + +-static void bnxt_qplib_pull_psn_buff(struct bnxt_qplib_q *sq, +- struct bnxt_qplib_swq *swq) ++static void bnxt_qplib_pull_psn_buff(struct bnxt_qplib_qp *qp, struct bnxt_qplib_q *sq, ++ struct bnxt_qplib_swq *swq, bool hw_retx) + { + struct bnxt_qplib_hwq *hwq; + u32 pg_num, pg_indx; +@@ -1722,6 +1759,11 @@ static void bnxt_qplib_pull_psn_buff(struct bnxt_qplib_q *sq, + if (!hwq->pad_pg) + return; + tail = swq->slot_idx / sq->dbinfo.max_slot; ++ if (hw_retx) { ++ /* For HW retx use qp msn index */ ++ tail = qp->msn; ++ tail %= qp->msn_tbl_sz; ++ } + pg_num = (tail + hwq->pad_pgofft) / (PAGE_SIZE / hwq->pad_stride); + pg_indx = (tail + hwq->pad_pgofft) % (PAGE_SIZE / hwq->pad_stride); + buff = (void *)(hwq->pad_pg[pg_num] + pg_indx * hwq->pad_stride); +@@ -1746,6 +1788,7 @@ int bnxt_qplib_post_send(struct bnxt_qplib_qp *qp, + struct bnxt_qplib_swq *swq; + bool sch_handler = false; + u16 wqe_sz, qdf = 0; ++ bool msn_update; + void *base_hdr; + void *ext_hdr; + __le32 temp32; +@@ -1773,7 +1816,7 @@ int bnxt_qplib_post_send(struct bnxt_qplib_qp *qp, + } + + swq = bnxt_qplib_get_swqe(sq, &wqe_idx); +- bnxt_qplib_pull_psn_buff(sq, swq); ++ bnxt_qplib_pull_psn_buff(qp, sq, swq, BNXT_RE_HW_RETX(qp->dev_cap_flags)); + + idx = 0; + swq->slot_idx = hwq->prod; +@@ -1805,6 +1848,8 @@ int bnxt_qplib_post_send(struct bnxt_qplib_qp *qp, + &idx); + if (data_len < 0) + goto queue_err; ++ /* Make sure we update MSN table only for wired wqes */ ++ msn_update = true; + /* Specifics */ + switch (wqe->type) { + case BNXT_QPLIB_SWQE_TYPE_SEND: +@@ -1845,6 +1890,7 @@ int bnxt_qplib_post_send(struct bnxt_qplib_qp *qp, + SQ_SEND_DST_QP_MASK); + ext_sqe->avid = cpu_to_le32(wqe->send.avid & + SQ_SEND_AVID_MASK); ++ msn_update = false; + } else { + sqe->length = cpu_to_le32(data_len); + if (qp->mtu) +@@ -1902,7 +1948,7 @@ int bnxt_qplib_post_send(struct bnxt_qplib_qp *qp, + sqe->wqe_type = wqe->type; + sqe->flags = wqe->flags; + sqe->inv_l_key = cpu_to_le32(wqe->local_inv.inv_l_key); +- ++ msn_update = false; + break; + } + case BNXT_QPLIB_SWQE_TYPE_FAST_REG_MR: +@@ -1934,6 +1980,7 @@ int bnxt_qplib_post_send(struct bnxt_qplib_qp *qp, + PTU_PTE_VALID); + ext_sqe->pblptr = cpu_to_le64(wqe->frmr.pbl_dma_ptr); + ext_sqe->va = cpu_to_le64(wqe->frmr.va); ++ msn_update = false; + + break; + } +@@ -1951,6 +1998,7 @@ int bnxt_qplib_post_send(struct bnxt_qplib_qp *qp, + sqe->l_key = cpu_to_le32(wqe->bind.r_key); + ext_sqe->va = cpu_to_le64(wqe->bind.va); + ext_sqe->length_lo = cpu_to_le32(wqe->bind.length); ++ msn_update = false; + break; + } + default: +@@ -1958,11 +2006,13 @@ int bnxt_qplib_post_send(struct bnxt_qplib_qp *qp, + rc = -EINVAL; + goto done; + } +- swq->next_psn = sq->psn & BTH_PSN_MASK; +- bnxt_qplib_fill_psn_search(qp, wqe, swq); ++ if (!BNXT_RE_HW_RETX(qp->dev_cap_flags) || msn_update) { ++ swq->next_psn = sq->psn & BTH_PSN_MASK; ++ bnxt_qplib_fill_psn_search(qp, wqe, swq); ++ } + queue_err: + bnxt_qplib_swq_mod_start(sq, wqe_idx); +- bnxt_qplib_hwq_incr_prod(hwq, swq->slots); ++ bnxt_qplib_hwq_incr_prod(&sq->dbinfo, hwq, swq->slots); + qp->wqe_cnt++; + done: + if (sch_handler) { +@@ -2050,7 +2100,7 @@ int bnxt_qplib_post_recv(struct bnxt_qplib_qp *qp, + base_hdr->wr_id[0] = cpu_to_le32(wqe_idx); + queue_err: + bnxt_qplib_swq_mod_start(rq, wqe_idx); +- bnxt_qplib_hwq_incr_prod(hwq, swq->slots); ++ bnxt_qplib_hwq_incr_prod(&rq->dbinfo, hwq, swq->slots); + done: + if (sch_handler) { + nq_work = kzalloc(sizeof(*nq_work), GFP_ATOMIC); +@@ -2087,6 +2137,7 @@ int bnxt_qplib_create_cq(struct bnxt_qplib_res *res, struct bnxt_qplib_cq *cq) + return -EINVAL; + } + ++ cq->dbinfo.flags = 0; + hwq_attr.res = res; + hwq_attr.depth = cq->max_wqe; + hwq_attr.stride = sizeof(struct cq_base); +@@ -2102,7 +2153,7 @@ int bnxt_qplib_create_cq(struct bnxt_qplib_res *res, struct bnxt_qplib_cq *cq) + + req.dpi = cpu_to_le32(cq->dpi->dpi); + req.cq_handle = cpu_to_le64(cq->cq_handle); +- req.cq_size = cpu_to_le32(cq->hwq.max_elements); ++ req.cq_size = cpu_to_le32(cq->max_wqe); + pbl = &cq->hwq.pbl[PBL_LVL_0]; + pg_sz_lvl = (bnxt_qplib_base_pg_size(&cq->hwq) << + CMDQ_CREATE_CQ_PG_SIZE_SFT); +@@ -2145,6 +2196,8 @@ void bnxt_qplib_resize_cq_complete(struct bnxt_qplib_res *res, + { + bnxt_qplib_free_hwq(res, &cq->hwq); + memcpy(&cq->hwq, &cq->resize_hwq, sizeof(cq->hwq)); ++ /* Reset only the cons bit in the flags */ ++ cq->dbinfo.flags &= ~(1UL << BNXT_QPLIB_FLAG_EPOCH_CONS_SHIFT); + } + + int bnxt_qplib_resize_cq(struct bnxt_qplib_res *res, struct bnxt_qplib_cq *cq, +@@ -2241,7 +2294,8 @@ static int __flush_sq(struct bnxt_qplib_q *sq, struct bnxt_qplib_qp *qp, + cqe++; + (*budget)--; + skip_compl: +- bnxt_qplib_hwq_incr_cons(&sq->hwq, sq->swq[last].slots); ++ bnxt_qplib_hwq_incr_cons(sq->hwq.max_elements, &sq->hwq.cons, ++ sq->swq[last].slots, &sq->dbinfo.flags); + sq->swq_last = sq->swq[last].next_idx; + } + *pcqe = cqe; +@@ -2288,7 +2342,8 @@ static int __flush_rq(struct bnxt_qplib_q *rq, struct bnxt_qplib_qp *qp, + cqe->wr_id = rq->swq[last].wr_id; + cqe++; + (*budget)--; +- bnxt_qplib_hwq_incr_cons(&rq->hwq, rq->swq[last].slots); ++ bnxt_qplib_hwq_incr_cons(rq->hwq.max_elements, &rq->hwq.cons, ++ rq->swq[last].slots, &rq->dbinfo.flags); + rq->swq_last = rq->swq[last].next_idx; + } + *pcqe = cqe; +@@ -2317,7 +2372,7 @@ void bnxt_qplib_mark_qp_error(void *qp_handle) + static int do_wa9060(struct bnxt_qplib_qp *qp, struct bnxt_qplib_cq *cq, + u32 cq_cons, u32 swq_last, u32 cqe_sq_cons) + { +- u32 peek_sw_cq_cons, peek_raw_cq_cons, peek_sq_cons_idx; ++ u32 peek_sw_cq_cons, peek_sq_cons_idx, peek_flags; + struct bnxt_qplib_q *sq = &qp->sq; + struct cq_req *peek_req_hwcqe; + struct bnxt_qplib_qp *peek_qp; +@@ -2348,16 +2403,14 @@ static int do_wa9060(struct bnxt_qplib_qp *qp, struct bnxt_qplib_cq *cq, + } + if (sq->condition) { + /* Peek at the completions */ +- peek_raw_cq_cons = cq->hwq.cons; ++ peek_flags = cq->dbinfo.flags; + peek_sw_cq_cons = cq_cons; + i = cq->hwq.max_elements; + while (i--) { +- peek_sw_cq_cons = HWQ_CMP((peek_sw_cq_cons), &cq->hwq); + peek_hwcqe = bnxt_qplib_get_qe(&cq->hwq, + peek_sw_cq_cons, NULL); + /* If the next hwcqe is VALID */ +- if (CQE_CMP_VALID(peek_hwcqe, peek_raw_cq_cons, +- cq->hwq.max_elements)) { ++ if (CQE_CMP_VALID(peek_hwcqe, peek_flags)) { + /* + * The valid test of the entry must be done first before + * reading any further. +@@ -2400,8 +2453,9 @@ static int do_wa9060(struct bnxt_qplib_qp *qp, struct bnxt_qplib_cq *cq, + rc = -EINVAL; + goto out; + } +- peek_sw_cq_cons++; +- peek_raw_cq_cons++; ++ bnxt_qplib_hwq_incr_cons(cq->hwq.max_elements, ++ &peek_sw_cq_cons, ++ 1, &peek_flags); + } + dev_err(&cq->hwq.pdev->dev, + "Should not have come here! cq_cons=0x%x qp=0x%x sq cons sw=0x%x hw=0x%x\n", +@@ -2488,7 +2542,8 @@ static int bnxt_qplib_cq_process_req(struct bnxt_qplib_cq *cq, + } + } + skip: +- bnxt_qplib_hwq_incr_cons(&sq->hwq, swq->slots); ++ bnxt_qplib_hwq_incr_cons(sq->hwq.max_elements, &sq->hwq.cons, ++ swq->slots, &sq->dbinfo.flags); + sq->swq_last = swq->next_idx; + if (sq->single) + break; +@@ -2515,7 +2570,8 @@ static void bnxt_qplib_release_srqe(struct bnxt_qplib_srq *srq, u32 tag) + srq->swq[srq->last_idx].next_idx = (int)tag; + srq->last_idx = (int)tag; + srq->swq[srq->last_idx].next_idx = -1; +- srq->hwq.cons++; /* Support for SRQE counter */ ++ bnxt_qplib_hwq_incr_cons(srq->hwq.max_elements, &srq->hwq.cons, ++ srq->dbinfo.max_slot, &srq->dbinfo.flags); + spin_unlock(&srq->hwq.lock); + } + +@@ -2584,7 +2640,8 @@ static int bnxt_qplib_cq_process_res_rc(struct bnxt_qplib_cq *cq, + cqe->wr_id = swq->wr_id; + cqe++; + (*budget)--; +- bnxt_qplib_hwq_incr_cons(&rq->hwq, swq->slots); ++ bnxt_qplib_hwq_incr_cons(rq->hwq.max_elements, &rq->hwq.cons, ++ swq->slots, &rq->dbinfo.flags); + rq->swq_last = swq->next_idx; + *pcqe = cqe; + +@@ -2670,7 +2727,8 @@ static int bnxt_qplib_cq_process_res_ud(struct bnxt_qplib_cq *cq, + cqe->wr_id = swq->wr_id; + cqe++; + (*budget)--; +- bnxt_qplib_hwq_incr_cons(&rq->hwq, swq->slots); ++ bnxt_qplib_hwq_incr_cons(rq->hwq.max_elements, &rq->hwq.cons, ++ swq->slots, &rq->dbinfo.flags); + rq->swq_last = swq->next_idx; + *pcqe = cqe; + +@@ -2687,14 +2745,11 @@ static int bnxt_qplib_cq_process_res_ud(struct bnxt_qplib_cq *cq, + bool bnxt_qplib_is_cq_empty(struct bnxt_qplib_cq *cq) + { + struct cq_base *hw_cqe; +- u32 sw_cons, raw_cons; + bool rc = true; + +- raw_cons = cq->hwq.cons; +- sw_cons = HWQ_CMP(raw_cons, &cq->hwq); +- hw_cqe = bnxt_qplib_get_qe(&cq->hwq, sw_cons, NULL); ++ hw_cqe = bnxt_qplib_get_qe(&cq->hwq, cq->hwq.cons, NULL); + /* Check for Valid bit. If the CQE is valid, return false */ +- rc = !CQE_CMP_VALID(hw_cqe, raw_cons, cq->hwq.max_elements); ++ rc = !CQE_CMP_VALID(hw_cqe, cq->dbinfo.flags); + return rc; + } + +@@ -2776,7 +2831,8 @@ static int bnxt_qplib_cq_process_res_raweth_qp1(struct bnxt_qplib_cq *cq, + cqe->wr_id = swq->wr_id; + cqe++; + (*budget)--; +- bnxt_qplib_hwq_incr_cons(&rq->hwq, swq->slots); ++ bnxt_qplib_hwq_incr_cons(rq->hwq.max_elements, &rq->hwq.cons, ++ swq->slots, &rq->dbinfo.flags); + rq->swq_last = swq->next_idx; + *pcqe = cqe; + +@@ -2849,7 +2905,8 @@ static int bnxt_qplib_cq_process_terminal(struct bnxt_qplib_cq *cq, + cqe++; + (*budget)--; + } +- bnxt_qplib_hwq_incr_cons(&sq->hwq, sq->swq[swq_last].slots); ++ bnxt_qplib_hwq_incr_cons(sq->hwq.max_elements, &sq->hwq.cons, ++ sq->swq[swq_last].slots, &sq->dbinfo.flags); + sq->swq_last = sq->swq[swq_last].next_idx; + } + *pcqe = cqe; +@@ -2934,19 +2991,17 @@ int bnxt_qplib_poll_cq(struct bnxt_qplib_cq *cq, struct bnxt_qplib_cqe *cqe, + int num_cqes, struct bnxt_qplib_qp **lib_qp) + { + struct cq_base *hw_cqe; +- u32 sw_cons, raw_cons; + int budget, rc = 0; ++ u32 hw_polled = 0; + u8 type; + +- raw_cons = cq->hwq.cons; + budget = num_cqes; + + while (budget) { +- sw_cons = HWQ_CMP(raw_cons, &cq->hwq); +- hw_cqe = bnxt_qplib_get_qe(&cq->hwq, sw_cons, NULL); ++ hw_cqe = bnxt_qplib_get_qe(&cq->hwq, cq->hwq.cons, NULL); + + /* Check for Valid bit */ +- if (!CQE_CMP_VALID(hw_cqe, raw_cons, cq->hwq.max_elements)) ++ if (!CQE_CMP_VALID(hw_cqe, cq->dbinfo.flags)) + break; + + /* +@@ -2961,7 +3016,7 @@ int bnxt_qplib_poll_cq(struct bnxt_qplib_cq *cq, struct bnxt_qplib_cqe *cqe, + rc = bnxt_qplib_cq_process_req(cq, + (struct cq_req *)hw_cqe, + &cqe, &budget, +- sw_cons, lib_qp); ++ cq->hwq.cons, lib_qp); + break; + case CQ_BASE_CQE_TYPE_RES_RC: + rc = bnxt_qplib_cq_process_res_rc(cq, +@@ -3007,12 +3062,13 @@ int bnxt_qplib_poll_cq(struct bnxt_qplib_cq *cq, struct bnxt_qplib_cqe *cqe, + dev_err(&cq->hwq.pdev->dev, + "process_cqe error rc = 0x%x\n", rc); + } +- raw_cons++; ++ hw_polled++; ++ bnxt_qplib_hwq_incr_cons(cq->hwq.max_elements, &cq->hwq.cons, ++ 1, &cq->dbinfo.flags); ++ + } +- if (cq->hwq.cons != raw_cons) { +- cq->hwq.cons = raw_cons; ++ if (hw_polled) + bnxt_qplib_ring_db(&cq->dbinfo, DBC_DBC_TYPE_CQ); +- } + exit: + return num_cqes - budget; + } +diff --git a/drivers/infiniband/hw/bnxt_re/qplib_fp.h b/drivers/infiniband/hw/bnxt_re/qplib_fp.h +index 404b851091ca2..113be429f0aac 100644 +--- a/drivers/infiniband/hw/bnxt_re/qplib_fp.h ++++ b/drivers/infiniband/hw/bnxt_re/qplib_fp.h +@@ -338,6 +338,9 @@ struct bnxt_qplib_qp { + dma_addr_t rq_hdr_buf_map; + struct list_head sq_flush; + struct list_head rq_flush; ++ u32 msn; ++ u32 msn_tbl_sz; ++ u16 dev_cap_flags; + }; + + #define BNXT_QPLIB_MAX_CQE_ENTRY_SIZE sizeof(struct cq_base) +@@ -348,9 +351,21 @@ struct bnxt_qplib_qp { + #define CQE_IDX(x) ((x) & CQE_MAX_IDX_PER_PG) + + #define ROCE_CQE_CMP_V 0 +-#define CQE_CMP_VALID(hdr, raw_cons, cp_bit) \ ++#define CQE_CMP_VALID(hdr, pass) \ + (!!((hdr)->cqe_type_toggle & CQ_BASE_TOGGLE) == \ +- !((raw_cons) & (cp_bit))) ++ !((pass) & BNXT_QPLIB_FLAG_EPOCH_CONS_MASK)) ++ ++static inline u32 __bnxt_qplib_get_avail(struct bnxt_qplib_hwq *hwq) ++{ ++ int cons, prod, avail; ++ ++ cons = hwq->cons; ++ prod = hwq->prod; ++ avail = cons - prod; ++ if (cons <= prod) ++ avail += hwq->depth; ++ return avail; ++} + + static inline bool bnxt_qplib_queue_full(struct bnxt_qplib_q *que, + u8 slots) +@@ -443,9 +458,9 @@ struct bnxt_qplib_cq { + #define NQE_PG(x) (((x) & ~NQE_MAX_IDX_PER_PG) / NQE_CNT_PER_PG) + #define NQE_IDX(x) ((x) & NQE_MAX_IDX_PER_PG) + +-#define NQE_CMP_VALID(hdr, raw_cons, cp_bit) \ ++#define NQE_CMP_VALID(hdr, pass) \ + (!!(le32_to_cpu((hdr)->info63_v[0]) & NQ_BASE_V) == \ +- !((raw_cons) & (cp_bit))) ++ !((pass) & BNXT_QPLIB_FLAG_EPOCH_CONS_MASK)) + + #define BNXT_QPLIB_NQE_MAX_CNT (128 * 1024) + +@@ -614,4 +629,15 @@ static inline u16 bnxt_qplib_calc_ilsize(struct bnxt_qplib_swqe *wqe, u16 max) + + return size; + } ++ ++/* MSN table update inlin */ ++static inline __le64 bnxt_re_update_msn_tbl(u32 st_idx, u32 npsn, u32 start_psn) ++{ ++ return cpu_to_le64((((u64)(st_idx) << SQ_MSN_SEARCH_START_IDX_SFT) & ++ SQ_MSN_SEARCH_START_IDX_MASK) | ++ (((u64)(npsn) << SQ_MSN_SEARCH_NEXT_PSN_SFT) & ++ SQ_MSN_SEARCH_NEXT_PSN_MASK) | ++ (((start_psn) << SQ_MSN_SEARCH_START_PSN_SFT) & ++ SQ_MSN_SEARCH_START_PSN_MASK)); ++} + #endif /* __BNXT_QPLIB_FP_H__ */ +diff --git a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c +index e47b4ca64d33e..5680fe8b890ad 100644 +--- a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c ++++ b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c +@@ -734,17 +734,15 @@ static void bnxt_qplib_service_creq(struct tasklet_struct *t) + u32 type, budget = CREQ_ENTRY_POLL_BUDGET; + struct bnxt_qplib_hwq *hwq = &creq->hwq; + struct creq_base *creqe; +- u32 sw_cons, raw_cons; + unsigned long flags; + u32 num_wakeup = 0; ++ u32 hw_polled = 0; + + /* Service the CREQ until budget is over */ + spin_lock_irqsave(&hwq->lock, flags); +- raw_cons = hwq->cons; + while (budget > 0) { +- sw_cons = HWQ_CMP(raw_cons, hwq); +- creqe = bnxt_qplib_get_qe(hwq, sw_cons, NULL); +- if (!CREQ_CMP_VALID(creqe, raw_cons, hwq->max_elements)) ++ creqe = bnxt_qplib_get_qe(hwq, hwq->cons, NULL); ++ if (!CREQ_CMP_VALID(creqe, creq->creq_db.dbinfo.flags)) + break; + /* The valid test of the entry must be done first before + * reading any further. +@@ -775,15 +773,15 @@ static void bnxt_qplib_service_creq(struct tasklet_struct *t) + type); + break; + } +- raw_cons++; + budget--; ++ hw_polled++; ++ bnxt_qplib_hwq_incr_cons(hwq->max_elements, &hwq->cons, ++ 1, &creq->creq_db.dbinfo.flags); + } + +- if (hwq->cons != raw_cons) { +- hwq->cons = raw_cons; ++ if (hw_polled) + bnxt_qplib_ring_nq_db(&creq->creq_db.dbinfo, + rcfw->res->cctx, true); +- } + spin_unlock_irqrestore(&hwq->lock, flags); + if (num_wakeup) + wake_up_nr(&rcfw->cmdq.waitq, num_wakeup); +@@ -907,6 +905,8 @@ int bnxt_qplib_init_rcfw(struct bnxt_qplib_rcfw *rcfw, + req.max_gid_per_vf = cpu_to_le32(ctx->vf_res.max_gid_per_vf); + + skip_ctx_setup: ++ if (BNXT_RE_HW_RETX(rcfw->res->dattr->dev_cap_flags)) ++ req.flags |= cpu_to_le16(CMDQ_INITIALIZE_FW_FLAGS_HW_REQUESTER_RETX_SUPPORTED); + req.stat_ctx_id = cpu_to_le32(ctx->stats.fw_id); + bnxt_qplib_fill_cmdqmsg(&msg, &req, &resp, NULL, sizeof(req), sizeof(resp), 0); + rc = bnxt_qplib_rcfw_send_message(rcfw, &msg); +@@ -1113,6 +1113,7 @@ static int bnxt_qplib_map_creq_db(struct bnxt_qplib_rcfw *rcfw, u32 reg_offt) + pdev = rcfw->pdev; + creq_db = &rcfw->creq.creq_db; + ++ creq_db->dbinfo.flags = 0; + creq_db->reg.bar_id = RCFW_COMM_CONS_PCI_BAR_REGION; + creq_db->reg.bar_base = pci_resource_start(pdev, creq_db->reg.bar_id); + if (!creq_db->reg.bar_id) +diff --git a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.h b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.h +index 7b31bee3e0005..45996e60a0d03 100644 +--- a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.h ++++ b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.h +@@ -141,9 +141,9 @@ struct bnxt_qplib_crsbe { + /* Allocate 1 per QP for async error notification for now */ + #define BNXT_QPLIB_CREQE_MAX_CNT (64 * 1024) + #define BNXT_QPLIB_CREQE_UNITS 16 /* 16-Bytes per prod unit */ +-#define CREQ_CMP_VALID(hdr, raw_cons, cp_bit) \ ++#define CREQ_CMP_VALID(hdr, pass) \ + (!!((hdr)->v & CREQ_BASE_V) == \ +- !((raw_cons) & (cp_bit))) ++ !((pass) & BNXT_QPLIB_FLAG_EPOCH_CONS_MASK)) + #define CREQ_ENTRY_POLL_BUDGET 0x100 + + /* HWQ */ +diff --git a/drivers/infiniband/hw/bnxt_re/qplib_res.c b/drivers/infiniband/hw/bnxt_re/qplib_res.c +index 157db6b7e1193..ae2bde34e785b 100644 +--- a/drivers/infiniband/hw/bnxt_re/qplib_res.c ++++ b/drivers/infiniband/hw/bnxt_re/qplib_res.c +@@ -343,7 +343,7 @@ int bnxt_qplib_alloc_init_hwq(struct bnxt_qplib_hwq *hwq, + hwq->cons = 0; + hwq->pdev = pdev; + hwq->depth = hwq_attr->depth; +- hwq->max_elements = depth; ++ hwq->max_elements = hwq->depth; + hwq->element_size = stride; + hwq->qe_ppg = pg_size / stride; + /* For direct access to the elements */ +diff --git a/drivers/infiniband/hw/bnxt_re/qplib_res.h b/drivers/infiniband/hw/bnxt_re/qplib_res.h +index 5949f004f7856..534db462216ac 100644 +--- a/drivers/infiniband/hw/bnxt_re/qplib_res.h ++++ b/drivers/infiniband/hw/bnxt_re/qplib_res.h +@@ -186,6 +186,14 @@ struct bnxt_qplib_db_info { + struct bnxt_qplib_hwq *hwq; + u32 xid; + u32 max_slot; ++ u32 flags; ++}; ++ ++enum bnxt_qplib_db_info_flags_mask { ++ BNXT_QPLIB_FLAG_EPOCH_CONS_SHIFT = 0x0UL, ++ BNXT_QPLIB_FLAG_EPOCH_PROD_SHIFT = 0x1UL, ++ BNXT_QPLIB_FLAG_EPOCH_CONS_MASK = 0x1UL, ++ BNXT_QPLIB_FLAG_EPOCH_PROD_MASK = 0x2UL, + }; + + /* Tables */ +@@ -396,24 +404,34 @@ void bnxt_qplib_unmap_db_bar(struct bnxt_qplib_res *res); + + int bnxt_qplib_determine_atomics(struct pci_dev *dev); + +-static inline void bnxt_qplib_hwq_incr_prod(struct bnxt_qplib_hwq *hwq, u32 cnt) ++static inline void bnxt_qplib_hwq_incr_prod(struct bnxt_qplib_db_info *dbinfo, ++ struct bnxt_qplib_hwq *hwq, u32 cnt) + { +- hwq->prod = (hwq->prod + cnt) % hwq->depth; ++ /* move prod and update toggle/epoch if wrap around */ ++ hwq->prod += cnt; ++ if (hwq->prod >= hwq->depth) { ++ hwq->prod %= hwq->depth; ++ dbinfo->flags ^= 1UL << BNXT_QPLIB_FLAG_EPOCH_PROD_SHIFT; ++ } + } + +-static inline void bnxt_qplib_hwq_incr_cons(struct bnxt_qplib_hwq *hwq, +- u32 cnt) ++static inline void bnxt_qplib_hwq_incr_cons(u32 max_elements, u32 *cons, u32 cnt, ++ u32 *dbinfo_flags) + { +- hwq->cons = (hwq->cons + cnt) % hwq->depth; ++ /* move cons and update toggle/epoch if wrap around */ ++ *cons += cnt; ++ if (*cons >= max_elements) { ++ *cons %= max_elements; ++ *dbinfo_flags ^= 1UL << BNXT_QPLIB_FLAG_EPOCH_CONS_SHIFT; ++ } + } + + static inline void bnxt_qplib_ring_db32(struct bnxt_qplib_db_info *info, + bool arm) + { +- u32 key; ++ u32 key = 0; + +- key = info->hwq->cons & (info->hwq->max_elements - 1); +- key |= (CMPL_DOORBELL_IDX_VALID | ++ key |= info->hwq->cons | (CMPL_DOORBELL_IDX_VALID | + (CMPL_DOORBELL_KEY_CMPL & CMPL_DOORBELL_KEY_MASK)); + if (!arm) + key |= CMPL_DOORBELL_MASK; +@@ -427,8 +445,7 @@ static inline void bnxt_qplib_ring_db(struct bnxt_qplib_db_info *info, + + key = (info->xid & DBC_DBC_XID_MASK) | DBC_DBC_PATH_ROCE | type; + key <<= 32; +- key |= (info->hwq->cons & (info->hwq->max_elements - 1)) & +- DBC_DBC_INDEX_MASK; ++ key |= (info->hwq->cons & DBC_DBC_INDEX_MASK); + writeq(key, info->db); + } + +@@ -483,6 +500,15 @@ static inline bool _is_ext_stats_supported(u16 dev_cap_flags) + CREQ_QUERY_FUNC_RESP_SB_EXT_STATS; + } + ++static inline bool _is_hw_retx_supported(u16 dev_cap_flags) ++{ ++ return dev_cap_flags & ++ (CREQ_QUERY_FUNC_RESP_SB_HW_REQUESTER_RETX_ENABLED | ++ CREQ_QUERY_FUNC_RESP_SB_HW_RESPONDER_RETX_ENABLED); ++} ++ ++#define BNXT_RE_HW_RETX(a) _is_hw_retx_supported((a)) ++ + static inline u8 bnxt_qplib_dbr_pacing_en(struct bnxt_qplib_chip_ctx *cctx) + { + return cctx->modes.dbr_pacing; +diff --git a/drivers/infiniband/hw/bnxt_re/roce_hsi.h b/drivers/infiniband/hw/bnxt_re/roce_hsi.h +index 4a10303e03925..2909608f4b5de 100644 +--- a/drivers/infiniband/hw/bnxt_re/roce_hsi.h ++++ b/drivers/infiniband/hw/bnxt_re/roce_hsi.h +@@ -555,7 +555,12 @@ struct cmdq_modify_qp { + __le16 flags; + __le16 cookie; + u8 resp_size; +- u8 reserved8; ++ u8 qp_type; ++ #define CMDQ_MODIFY_QP_QP_TYPE_RC 0x2UL ++ #define CMDQ_MODIFY_QP_QP_TYPE_UD 0x4UL ++ #define CMDQ_MODIFY_QP_QP_TYPE_RAW_ETHERTYPE 0x6UL ++ #define CMDQ_MODIFY_QP_QP_TYPE_GSI 0x7UL ++ #define CMDQ_MODIFY_QP_QP_TYPE_LAST CMDQ_MODIFY_QP_QP_TYPE_GSI + __le64 resp_addr; + __le32 modify_mask; + #define CMDQ_MODIFY_QP_MODIFY_MASK_STATE 0x1UL +@@ -611,14 +616,12 @@ struct cmdq_modify_qp { + #define CMDQ_MODIFY_QP_NETWORK_TYPE_ROCEV2_IPV6 (0x3UL << 6) + #define CMDQ_MODIFY_QP_NETWORK_TYPE_LAST CMDQ_MODIFY_QP_NETWORK_TYPE_ROCEV2_IPV6 + u8 access; +- #define CMDQ_MODIFY_QP_ACCESS_REMOTE_ATOMIC_REMOTE_READ_REMOTE_WRITE_LOCAL_WRITE_MASK \ +- 0xffUL +- #define CMDQ_MODIFY_QP_ACCESS_REMOTE_ATOMIC_REMOTE_READ_REMOTE_WRITE_LOCAL_WRITE_SFT \ +- 0 +- #define CMDQ_MODIFY_QP_ACCESS_LOCAL_WRITE 0x1UL +- #define CMDQ_MODIFY_QP_ACCESS_REMOTE_WRITE 0x2UL +- #define CMDQ_MODIFY_QP_ACCESS_REMOTE_READ 0x4UL +- #define CMDQ_MODIFY_QP_ACCESS_REMOTE_ATOMIC 0x8UL ++ #define CMDQ_MODIFY_QP_ACCESS_REMOTE_ATOMIC_REMOTE_READ_REMOTE_WRITE_LOCAL_WRITE_MASK 0xffUL ++ #define CMDQ_MODIFY_QP_ACCESS_REMOTE_ATOMIC_REMOTE_READ_REMOTE_WRITE_LOCAL_WRITE_SFT 0 ++ #define CMDQ_MODIFY_QP_ACCESS_LOCAL_WRITE 0x1UL ++ #define CMDQ_MODIFY_QP_ACCESS_REMOTE_WRITE 0x2UL ++ #define CMDQ_MODIFY_QP_ACCESS_REMOTE_READ 0x4UL ++ #define CMDQ_MODIFY_QP_ACCESS_REMOTE_ATOMIC 0x8UL + __le16 pkey; + __le32 qkey; + __le32 dgid[4]; +@@ -673,6 +676,13 @@ struct cmdq_modify_qp { + #define CMDQ_MODIFY_QP_VLAN_PCP_SFT 13 + __le64 irrq_addr; + __le64 orrq_addr; ++ __le32 ext_modify_mask; ++ #define CMDQ_MODIFY_QP_EXT_MODIFY_MASK_EXT_STATS_CTX 0x1UL ++ #define CMDQ_MODIFY_QP_EXT_MODIFY_MASK_SCHQ_ID_VALID 0x2UL ++ __le32 ext_stats_ctx_id; ++ __le16 schq_id; ++ __le16 unused_0; ++ __le32 reserved32; + }; + + /* creq_modify_qp_resp (size:128b/16B) */ +@@ -3017,6 +3027,17 @@ struct sq_psn_search_ext { + __le32 reserved32; + }; + ++/* sq_msn_search (size:64b/8B) */ ++struct sq_msn_search { ++ __le64 start_idx_next_psn_start_psn; ++ #define SQ_MSN_SEARCH_START_PSN_MASK 0xffffffUL ++ #define SQ_MSN_SEARCH_START_PSN_SFT 0 ++ #define SQ_MSN_SEARCH_NEXT_PSN_MASK 0xffffff000000ULL ++ #define SQ_MSN_SEARCH_NEXT_PSN_SFT 24 ++ #define SQ_MSN_SEARCH_START_IDX_MASK 0xffff000000000000ULL ++ #define SQ_MSN_SEARCH_START_IDX_SFT 48 ++}; ++ + /* sq_send (size:1024b/128B) */ + struct sq_send { + u8 wqe_type; +@@ -3705,13 +3726,35 @@ struct cq_base { + #define CQ_BASE_CQE_TYPE_RES_UD (0x2UL << 1) + #define CQ_BASE_CQE_TYPE_RES_RAWETH_QP1 (0x3UL << 1) + #define CQ_BASE_CQE_TYPE_RES_UD_CFA (0x4UL << 1) ++ #define CQ_BASE_CQE_TYPE_REQ_V3 (0x8UL << 1) ++ #define CQ_BASE_CQE_TYPE_RES_RC_V3 (0x9UL << 1) ++ #define CQ_BASE_CQE_TYPE_RES_UD_V3 (0xaUL << 1) ++ #define CQ_BASE_CQE_TYPE_RES_RAWETH_QP1_V3 (0xbUL << 1) ++ #define CQ_BASE_CQE_TYPE_RES_UD_CFA_V3 (0xcUL << 1) + #define CQ_BASE_CQE_TYPE_NO_OP (0xdUL << 1) + #define CQ_BASE_CQE_TYPE_TERMINAL (0xeUL << 1) + #define CQ_BASE_CQE_TYPE_CUT_OFF (0xfUL << 1) + #define CQ_BASE_CQE_TYPE_LAST CQ_BASE_CQE_TYPE_CUT_OFF + u8 status; ++ #define CQ_BASE_STATUS_OK 0x0UL ++ #define CQ_BASE_STATUS_BAD_RESPONSE_ERR 0x1UL ++ #define CQ_BASE_STATUS_LOCAL_LENGTH_ERR 0x2UL ++ #define CQ_BASE_STATUS_HW_LOCAL_LENGTH_ERR 0x3UL ++ #define CQ_BASE_STATUS_LOCAL_QP_OPERATION_ERR 0x4UL ++ #define CQ_BASE_STATUS_LOCAL_PROTECTION_ERR 0x5UL ++ #define CQ_BASE_STATUS_LOCAL_ACCESS_ERROR 0x6UL ++ #define CQ_BASE_STATUS_MEMORY_MGT_OPERATION_ERR 0x7UL ++ #define CQ_BASE_STATUS_REMOTE_INVALID_REQUEST_ERR 0x8UL ++ #define CQ_BASE_STATUS_REMOTE_ACCESS_ERR 0x9UL ++ #define CQ_BASE_STATUS_REMOTE_OPERATION_ERR 0xaUL ++ #define CQ_BASE_STATUS_RNR_NAK_RETRY_CNT_ERR 0xbUL ++ #define CQ_BASE_STATUS_TRANSPORT_RETRY_CNT_ERR 0xcUL ++ #define CQ_BASE_STATUS_WORK_REQUEST_FLUSHED_ERR 0xdUL ++ #define CQ_BASE_STATUS_HW_FLUSH_ERR 0xeUL ++ #define CQ_BASE_STATUS_OVERFLOW_ERR 0xfUL ++ #define CQ_BASE_STATUS_LAST CQ_BASE_STATUS_OVERFLOW_ERR + __le16 reserved16; +- __le32 reserved32; ++ __le32 opaque; + }; + + /* cq_req (size:256b/32B) */ +@@ -4326,6 +4369,8 @@ struct cq_cutoff { + #define CQ_CUTOFF_CQE_TYPE_SFT 1 + #define CQ_CUTOFF_CQE_TYPE_CUT_OFF (0xfUL << 1) + #define CQ_CUTOFF_CQE_TYPE_LAST CQ_CUTOFF_CQE_TYPE_CUT_OFF ++ #define CQ_CUTOFF_RESIZE_TOGGLE_MASK 0x60UL ++ #define CQ_CUTOFF_RESIZE_TOGGLE_SFT 5 + u8 status; + #define CQ_CUTOFF_STATUS_OK 0x0UL + #define CQ_CUTOFF_STATUS_LAST CQ_CUTOFF_STATUS_OK +@@ -4377,6 +4422,8 @@ struct nq_srq_event { + #define NQ_SRQ_EVENT_TYPE_SFT 0 + #define NQ_SRQ_EVENT_TYPE_SRQ_EVENT 0x32UL + #define NQ_SRQ_EVENT_TYPE_LAST NQ_SRQ_EVENT_TYPE_SRQ_EVENT ++ #define NQ_SRQ_EVENT_TOGGLE_MASK 0xc0UL ++ #define NQ_SRQ_EVENT_TOGGLE_SFT 6 + u8 event; + #define NQ_SRQ_EVENT_EVENT_SRQ_THRESHOLD_EVENT 0x1UL + #define NQ_SRQ_EVENT_EVENT_LAST NQ_SRQ_EVENT_EVENT_SRQ_THRESHOLD_EVENT +diff --git a/drivers/infiniband/hw/hns/hns_roce_cq.c b/drivers/infiniband/hw/hns/hns_roce_cq.c +index 736dc2f993b40..ff177466de9b4 100644 +--- a/drivers/infiniband/hw/hns/hns_roce_cq.c ++++ b/drivers/infiniband/hw/hns/hns_roce_cq.c +@@ -151,7 +151,7 @@ static int alloc_cqc(struct hns_roce_dev *hr_dev, struct hns_roce_cq *hr_cq) + return ret; + } + +- ret = xa_err(xa_store(&cq_table->array, hr_cq->cqn, hr_cq, GFP_KERNEL)); ++ ret = xa_err(xa_store_irq(&cq_table->array, hr_cq->cqn, hr_cq, GFP_KERNEL)); + if (ret) { + ibdev_err(ibdev, "failed to xa_store CQ, ret = %d.\n", ret); + goto err_put; +@@ -164,7 +164,7 @@ static int alloc_cqc(struct hns_roce_dev *hr_dev, struct hns_roce_cq *hr_cq) + return 0; + + err_xa: +- xa_erase(&cq_table->array, hr_cq->cqn); ++ xa_erase_irq(&cq_table->array, hr_cq->cqn); + err_put: + hns_roce_table_put(hr_dev, &cq_table->table, hr_cq->cqn); + +@@ -183,7 +183,7 @@ static void free_cqc(struct hns_roce_dev *hr_dev, struct hns_roce_cq *hr_cq) + dev_err(dev, "DESTROY_CQ failed (%d) for CQN %06lx\n", ret, + hr_cq->cqn); + +- xa_erase(&cq_table->array, hr_cq->cqn); ++ xa_erase_irq(&cq_table->array, hr_cq->cqn); + + /* Waiting interrupt process procedure carried out */ + synchronize_irq(hr_dev->eq_table.eq[hr_cq->vector].irq); +@@ -472,13 +472,6 @@ void hns_roce_cq_event(struct hns_roce_dev *hr_dev, u32 cqn, int event_type) + struct ib_event event; + struct ib_cq *ibcq; + +- hr_cq = xa_load(&hr_dev->cq_table.array, +- cqn & (hr_dev->caps.num_cqs - 1)); +- if (!hr_cq) { +- dev_warn(dev, "async event for bogus CQ 0x%06x\n", cqn); +- return; +- } +- + if (event_type != HNS_ROCE_EVENT_TYPE_CQ_ID_INVALID && + event_type != HNS_ROCE_EVENT_TYPE_CQ_ACCESS_ERROR && + event_type != HNS_ROCE_EVENT_TYPE_CQ_OVERFLOW) { +@@ -487,7 +480,16 @@ void hns_roce_cq_event(struct hns_roce_dev *hr_dev, u32 cqn, int event_type) + return; + } + +- refcount_inc(&hr_cq->refcount); ++ xa_lock(&hr_dev->cq_table.array); ++ hr_cq = xa_load(&hr_dev->cq_table.array, ++ cqn & (hr_dev->caps.num_cqs - 1)); ++ if (hr_cq) ++ refcount_inc(&hr_cq->refcount); ++ xa_unlock(&hr_dev->cq_table.array); ++ if (!hr_cq) { ++ dev_warn(dev, "async event for bogus CQ 0x%06x\n", cqn); ++ return; ++ } + + ibcq = &hr_cq->ib_cq; + if (ibcq->event_handler) { +diff --git a/drivers/infiniband/hw/hns/hns_roce_hem.h b/drivers/infiniband/hw/hns/hns_roce_hem.h +index 7d23d3c51da46..fea6d7d508b60 100644 +--- a/drivers/infiniband/hw/hns/hns_roce_hem.h ++++ b/drivers/infiniband/hw/hns/hns_roce_hem.h +@@ -61,16 +61,16 @@ enum { + (sizeof(struct scatterlist) + sizeof(void *))) + + #define check_whether_bt_num_3(type, hop_num) \ +- (type < HEM_TYPE_MTT && hop_num == 2) ++ ((type) < HEM_TYPE_MTT && (hop_num) == 2) + + #define check_whether_bt_num_2(type, hop_num) \ +- ((type < HEM_TYPE_MTT && hop_num == 1) || \ +- (type >= HEM_TYPE_MTT && hop_num == 2)) ++ (((type) < HEM_TYPE_MTT && (hop_num) == 1) || \ ++ ((type) >= HEM_TYPE_MTT && (hop_num) == 2)) + + #define check_whether_bt_num_1(type, hop_num) \ +- ((type < HEM_TYPE_MTT && hop_num == HNS_ROCE_HOP_NUM_0) || \ +- (type >= HEM_TYPE_MTT && hop_num == 1) || \ +- (type >= HEM_TYPE_MTT && hop_num == HNS_ROCE_HOP_NUM_0)) ++ (((type) < HEM_TYPE_MTT && (hop_num) == HNS_ROCE_HOP_NUM_0) || \ ++ ((type) >= HEM_TYPE_MTT && (hop_num) == 1) || \ ++ ((type) >= HEM_TYPE_MTT && (hop_num) == HNS_ROCE_HOP_NUM_0)) + + struct hns_roce_hem_chunk { + struct list_head list; +diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +index b4799c83282e2..32fb2c00a8f26 100644 +--- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c ++++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +@@ -2088,7 +2088,7 @@ static void apply_func_caps(struct hns_roce_dev *hr_dev) + caps->gid_table_len[0] = caps->gmv_bt_num * + (HNS_HW_PAGE_SIZE / caps->gmv_entry_sz); + +- caps->gmv_entry_num = caps->gmv_bt_num * (PAGE_SIZE / ++ caps->gmv_entry_num = caps->gmv_bt_num * (HNS_HW_PAGE_SIZE / + caps->gmv_entry_sz); + } else { + u32 func_num = max_t(u32, 1, hr_dev->func_num); +@@ -3698,8 +3698,9 @@ static void get_cqe_status(struct hns_roce_dev *hr_dev, struct hns_roce_qp *qp, + wc->status == IB_WC_WR_FLUSH_ERR)) + return; + +- ibdev_err(&hr_dev->ib_dev, "error cqe status 0x%x:\n", cqe_status); +- print_hex_dump(KERN_ERR, "", DUMP_PREFIX_NONE, 16, 4, cqe, ++ ibdev_err_ratelimited(&hr_dev->ib_dev, "error cqe status 0x%x:\n", ++ cqe_status); ++ print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_NONE, 16, 4, cqe, + cq->cqe_size, false); + wc->vendor_err = hr_reg_read(cqe, CQE_SUB_STATUS); + +diff --git a/drivers/infiniband/hw/hns/hns_roce_main.c b/drivers/infiniband/hw/hns/hns_roce_main.c +index 4a9cd4d21bc99..c8c49110a3378 100644 +--- a/drivers/infiniband/hw/hns/hns_roce_main.c ++++ b/drivers/infiniband/hw/hns/hns_roce_main.c +@@ -37,6 +37,7 @@ + #include + #include + #include ++#include "hnae3.h" + #include "hns_roce_common.h" + #include "hns_roce_device.h" + #include "hns_roce_hem.h" +diff --git a/drivers/infiniband/hw/hns/hns_roce_mr.c b/drivers/infiniband/hw/hns/hns_roce_mr.c +index 14376490ac226..190e62da98e4b 100644 +--- a/drivers/infiniband/hw/hns/hns_roce_mr.c ++++ b/drivers/infiniband/hw/hns/hns_roce_mr.c +@@ -421,18 +421,18 @@ int hns_roce_map_mr_sg(struct ib_mr *ibmr, struct scatterlist *sg, int sg_nents, + struct ib_device *ibdev = &hr_dev->ib_dev; + struct hns_roce_mr *mr = to_hr_mr(ibmr); + struct hns_roce_mtr *mtr = &mr->pbl_mtr; +- int ret = 0; ++ int ret, sg_num = 0; + + mr->npages = 0; + mr->page_list = kvcalloc(mr->pbl_mtr.hem_cfg.buf_pg_count, + sizeof(dma_addr_t), GFP_KERNEL); + if (!mr->page_list) +- return ret; ++ return sg_num; + +- ret = ib_sg_to_pages(ibmr, sg, sg_nents, sg_offset, hns_roce_set_page); +- if (ret < 1) { ++ sg_num = ib_sg_to_pages(ibmr, sg, sg_nents, sg_offset, hns_roce_set_page); ++ if (sg_num < 1) { + ibdev_err(ibdev, "failed to store sg pages %u %u, cnt = %d.\n", +- mr->npages, mr->pbl_mtr.hem_cfg.buf_pg_count, ret); ++ mr->npages, mr->pbl_mtr.hem_cfg.buf_pg_count, sg_num); + goto err_page_list; + } + +@@ -443,17 +443,16 @@ int hns_roce_map_mr_sg(struct ib_mr *ibmr, struct scatterlist *sg, int sg_nents, + ret = hns_roce_mtr_map(hr_dev, mtr, mr->page_list, mr->npages); + if (ret) { + ibdev_err(ibdev, "failed to map sg mtr, ret = %d.\n", ret); +- ret = 0; ++ sg_num = 0; + } else { + mr->pbl_mtr.hem_cfg.buf_pg_shift = (u32)ilog2(ibmr->page_size); +- ret = mr->npages; + } + + err_page_list: + kvfree(mr->page_list); + mr->page_list = NULL; + +- return ret; ++ return sg_num; + } + + static void hns_roce_mw_free(struct hns_roce_dev *hr_dev, +diff --git a/drivers/infiniband/hw/hns/hns_roce_srq.c b/drivers/infiniband/hw/hns/hns_roce_srq.c +index 8dae98f827eb2..6a4923c21cbc6 100644 +--- a/drivers/infiniband/hw/hns/hns_roce_srq.c ++++ b/drivers/infiniband/hw/hns/hns_roce_srq.c +@@ -122,7 +122,7 @@ static int alloc_srqc(struct hns_roce_dev *hr_dev, struct hns_roce_srq *srq) + return ret; + } + +- ret = xa_err(xa_store(&srq_table->xa, srq->srqn, srq, GFP_KERNEL)); ++ ret = xa_err(xa_store_irq(&srq_table->xa, srq->srqn, srq, GFP_KERNEL)); + if (ret) { + ibdev_err(ibdev, "failed to store SRQC, ret = %d.\n", ret); + goto err_put; +@@ -135,7 +135,7 @@ static int alloc_srqc(struct hns_roce_dev *hr_dev, struct hns_roce_srq *srq) + return 0; + + err_xa: +- xa_erase(&srq_table->xa, srq->srqn); ++ xa_erase_irq(&srq_table->xa, srq->srqn); + err_put: + hns_roce_table_put(hr_dev, &srq_table->table, srq->srqn); + +@@ -153,7 +153,7 @@ static void free_srqc(struct hns_roce_dev *hr_dev, struct hns_roce_srq *srq) + dev_err(hr_dev->dev, "DESTROY_SRQ failed (%d) for SRQN %06lx\n", + ret, srq->srqn); + +- xa_erase(&srq_table->xa, srq->srqn); ++ xa_erase_irq(&srq_table->xa, srq->srqn); + + if (refcount_dec_and_test(&srq->refcount)) + complete(&srq->free); +diff --git a/drivers/infiniband/hw/mlx5/mem.c b/drivers/infiniband/hw/mlx5/mem.c +index 96ffbbaf0a73d..5a22be14d958f 100644 +--- a/drivers/infiniband/hw/mlx5/mem.c ++++ b/drivers/infiniband/hw/mlx5/mem.c +@@ -30,6 +30,7 @@ + * SOFTWARE. + */ + ++#include + #include + #include "mlx5_ib.h" + #include +@@ -108,7 +109,6 @@ static int post_send_nop(struct mlx5_ib_dev *dev, struct ib_qp *ibqp, u64 wr_id, + __be32 mmio_wqe[16] = {}; + unsigned long flags; + unsigned int idx; +- int i; + + if (unlikely(dev->mdev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR)) + return -EIO; +@@ -148,10 +148,8 @@ static int post_send_nop(struct mlx5_ib_dev *dev, struct ib_qp *ibqp, u64 wr_id, + * we hit doorbell + */ + wmb(); +- for (i = 0; i < 8; i++) +- mlx5_write64(&mmio_wqe[i * 2], +- bf->bfreg->map + bf->offset + i * 8); +- io_stop_wc(); ++ __iowrite64_copy(bf->bfreg->map + bf->offset, mmio_wqe, ++ sizeof(mmio_wqe) / 8); + + bf->offset ^= bf->buf_size; + +diff --git a/drivers/infiniband/hw/mlx5/mlx5_ib.h b/drivers/infiniband/hw/mlx5/mlx5_ib.h +index 16713baf0d060..6a57af8fa231b 100644 +--- a/drivers/infiniband/hw/mlx5/mlx5_ib.h ++++ b/drivers/infiniband/hw/mlx5/mlx5_ib.h +@@ -643,7 +643,7 @@ struct mlx5_ib_mkey { + unsigned int ndescs; + struct wait_queue_head wait; + refcount_t usecount; +- /* User Mkey must hold either a rb_key or a cache_ent. */ ++ /* Cacheable user Mkey must hold either a rb_key or a cache_ent. */ + struct mlx5r_cache_rb_key rb_key; + struct mlx5_cache_ent *cache_ent; + }; +diff --git a/drivers/infiniband/hw/mlx5/mr.c b/drivers/infiniband/hw/mlx5/mr.c +index e0629898c3c06..46847249b4677 100644 +--- a/drivers/infiniband/hw/mlx5/mr.c ++++ b/drivers/infiniband/hw/mlx5/mr.c +@@ -1594,7 +1594,8 @@ static bool can_use_umr_rereg_access(struct mlx5_ib_dev *dev, + unsigned int diffs = current_access_flags ^ target_access_flags; + + if (diffs & ~(IB_ACCESS_LOCAL_WRITE | IB_ACCESS_REMOTE_WRITE | +- IB_ACCESS_REMOTE_READ | IB_ACCESS_RELAXED_ORDERING)) ++ IB_ACCESS_REMOTE_READ | IB_ACCESS_RELAXED_ORDERING | ++ IB_ACCESS_REMOTE_ATOMIC)) + return false; + return mlx5r_umr_can_reconfig(dev, current_access_flags, + target_access_flags); +diff --git a/drivers/infiniband/sw/rxe/rxe_comp.c b/drivers/infiniband/sw/rxe/rxe_comp.c +index d0bdc2d8adc82..acd2172bf092b 100644 +--- a/drivers/infiniband/sw/rxe/rxe_comp.c ++++ b/drivers/infiniband/sw/rxe/rxe_comp.c +@@ -131,12 +131,12 @@ void rxe_comp_queue_pkt(struct rxe_qp *qp, struct sk_buff *skb) + { + int must_sched; + +- skb_queue_tail(&qp->resp_pkts, skb); +- +- must_sched = skb_queue_len(&qp->resp_pkts) > 1; ++ must_sched = skb_queue_len(&qp->resp_pkts) > 0; + if (must_sched != 0) + rxe_counter_inc(SKB_TO_PKT(skb)->rxe, RXE_CNT_COMPLETER_SCHED); + ++ skb_queue_tail(&qp->resp_pkts, skb); ++ + if (must_sched) + rxe_sched_task(&qp->comp.task); + else +diff --git a/drivers/infiniband/sw/rxe/rxe_net.c b/drivers/infiniband/sw/rxe/rxe_net.c +index cd59666158b18..e5827064ab1e2 100644 +--- a/drivers/infiniband/sw/rxe/rxe_net.c ++++ b/drivers/infiniband/sw/rxe/rxe_net.c +@@ -366,18 +366,10 @@ static int rxe_send(struct sk_buff *skb, struct rxe_pkt_info *pkt) + rxe_get(pkt->qp); + atomic_inc(&pkt->qp->skb_out); + +- if (skb->protocol == htons(ETH_P_IP)) { ++ if (skb->protocol == htons(ETH_P_IP)) + err = ip_local_out(dev_net(skb_dst(skb)->dev), skb->sk, skb); +- } else if (skb->protocol == htons(ETH_P_IPV6)) { ++ else + err = ip6_local_out(dev_net(skb_dst(skb)->dev), skb->sk, skb); +- } else { +- rxe_dbg_qp(pkt->qp, "Unknown layer 3 protocol: %d\n", +- skb->protocol); +- atomic_dec(&pkt->qp->skb_out); +- rxe_put(pkt->qp); +- kfree_skb(skb); +- return -EINVAL; +- } + + if (unlikely(net_xmit_eval(err))) { + rxe_dbg_qp(pkt->qp, "error sending packet: %d\n", err); +diff --git a/drivers/infiniband/sw/rxe/rxe_verbs.c b/drivers/infiniband/sw/rxe/rxe_verbs.c +index 48f86839d36a8..0930350522e38 100644 +--- a/drivers/infiniband/sw/rxe/rxe_verbs.c ++++ b/drivers/infiniband/sw/rxe/rxe_verbs.c +@@ -888,6 +888,7 @@ static int rxe_post_send_kernel(struct rxe_qp *qp, + { + int err = 0; + unsigned long flags; ++ int good = 0; + + spin_lock_irqsave(&qp->sq.sq_lock, flags); + while (ibwr) { +@@ -895,12 +896,15 @@ static int rxe_post_send_kernel(struct rxe_qp *qp, + if (err) { + *bad_wr = ibwr; + break; ++ } else { ++ good++; + } + ibwr = ibwr->next; + } + spin_unlock_irqrestore(&qp->sq.sq_lock, flags); + +- if (!err) ++ /* kickoff processing of any posted wqes */ ++ if (good) + rxe_sched_task(&qp->req.task); + + spin_lock_irqsave(&qp->state_lock, flags); +diff --git a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c +index 4bd161e86f8dd..562df2b3ef187 100644 +--- a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c ++++ b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c +@@ -184,8 +184,12 @@ int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey) + + ppriv = ipoib_priv(pdev); + +- snprintf(intf_name, sizeof(intf_name), "%s.%04x", +- ppriv->dev->name, pkey); ++ /* If you increase IFNAMSIZ, update snprintf below ++ * to allow longer names. ++ */ ++ BUILD_BUG_ON(IFNAMSIZ != 16); ++ snprintf(intf_name, sizeof(intf_name), "%.10s.%04x", ppriv->dev->name, ++ pkey); + + ndev = ipoib_intf_alloc(ppriv->ca, ppriv->port, intf_name); + if (IS_ERR(ndev)) { +diff --git a/drivers/input/input.c b/drivers/input/input.c +index 8c5fdb0f858ab..9bb1d3de723ee 100644 +--- a/drivers/input/input.c ++++ b/drivers/input/input.c +@@ -1378,19 +1378,19 @@ static int input_print_modalias_bits(char *buf, int size, + char name, const unsigned long *bm, + unsigned int min_bit, unsigned int max_bit) + { +- int len = 0, i; ++ int bit = min_bit; ++ int len = 0; + + len += snprintf(buf, max(size, 0), "%c", name); +- for (i = min_bit; i < max_bit; i++) +- if (bm[BIT_WORD(i)] & BIT_MASK(i)) +- len += snprintf(buf + len, max(size - len, 0), "%X,", i); ++ for_each_set_bit_from(bit, bm, max_bit) ++ len += snprintf(buf + len, max(size - len, 0), "%X,", bit); + return len; + } + +-static int input_print_modalias(char *buf, int size, const struct input_dev *id, +- int add_cr) ++static int input_print_modalias_parts(char *buf, int size, int full_len, ++ const struct input_dev *id) + { +- int len; ++ int len, klen, remainder, space; + + len = snprintf(buf, max(size, 0), + "input:b%04Xv%04Xp%04Xe%04X-", +@@ -1399,8 +1399,48 @@ static int input_print_modalias(char *buf, int size, const struct input_dev *id, + + len += input_print_modalias_bits(buf + len, size - len, + 'e', id->evbit, 0, EV_MAX); +- len += input_print_modalias_bits(buf + len, size - len, ++ ++ /* ++ * Calculate the remaining space in the buffer making sure we ++ * have place for the terminating 0. ++ */ ++ space = max(size - (len + 1), 0); ++ ++ klen = input_print_modalias_bits(buf + len, size - len, + 'k', id->keybit, KEY_MIN_INTERESTING, KEY_MAX); ++ len += klen; ++ ++ /* ++ * If we have more data than we can fit in the buffer, check ++ * if we can trim key data to fit in the rest. We will indicate ++ * that key data is incomplete by adding "+" sign at the end, like ++ * this: * "k1,2,3,45,+,". ++ * ++ * Note that we shortest key info (if present) is "k+," so we ++ * can only try to trim if key data is longer than that. ++ */ ++ if (full_len && size < full_len + 1 && klen > 3) { ++ remainder = full_len - len; ++ /* ++ * We can only trim if we have space for the remainder ++ * and also for at least "k+," which is 3 more characters. ++ */ ++ if (remainder <= space - 3) { ++ /* ++ * We are guaranteed to have 'k' in the buffer, so ++ * we need at least 3 additional bytes for storing ++ * "+," in addition to the remainder. ++ */ ++ for (int i = size - 1 - remainder - 3; i >= 0; i--) { ++ if (buf[i] == 'k' || buf[i] == ',') { ++ strcpy(buf + i + 1, "+,"); ++ len = i + 3; /* Not counting '\0' */ ++ break; ++ } ++ } ++ } ++ } ++ + len += input_print_modalias_bits(buf + len, size - len, + 'r', id->relbit, 0, REL_MAX); + len += input_print_modalias_bits(buf + len, size - len, +@@ -1416,12 +1456,25 @@ static int input_print_modalias(char *buf, int size, const struct input_dev *id, + len += input_print_modalias_bits(buf + len, size - len, + 'w', id->swbit, 0, SW_MAX); + +- if (add_cr) +- len += snprintf(buf + len, max(size - len, 0), "\n"); +- + return len; + } + ++static int input_print_modalias(char *buf, int size, const struct input_dev *id) ++{ ++ int full_len; ++ ++ /* ++ * Printing is done in 2 passes: first one figures out total length ++ * needed for the modalias string, second one will try to trim key ++ * data in case when buffer is too small for the entire modalias. ++ * If the buffer is too small regardless, it will fill as much as it ++ * can (without trimming key data) into the buffer and leave it to ++ * the caller to figure out what to do with the result. ++ */ ++ full_len = input_print_modalias_parts(NULL, 0, 0, id); ++ return input_print_modalias_parts(buf, size, full_len, id); ++} ++ + static ssize_t input_dev_show_modalias(struct device *dev, + struct device_attribute *attr, + char *buf) +@@ -1429,7 +1482,9 @@ static ssize_t input_dev_show_modalias(struct device *dev, + struct input_dev *id = to_input_dev(dev); + ssize_t len; + +- len = input_print_modalias(buf, PAGE_SIZE, id, 1); ++ len = input_print_modalias(buf, PAGE_SIZE, id); ++ if (len < PAGE_SIZE - 2) ++ len += snprintf(buf + len, PAGE_SIZE - len, "\n"); + + return min_t(int, len, PAGE_SIZE); + } +@@ -1641,6 +1696,23 @@ static int input_add_uevent_bm_var(struct kobj_uevent_env *env, + return 0; + } + ++/* ++ * This is a pretty gross hack. When building uevent data the driver core ++ * may try adding more environment variables to kobj_uevent_env without ++ * telling us, so we have no idea how much of the buffer we can use to ++ * avoid overflows/-ENOMEM elsewhere. To work around this let's artificially ++ * reduce amount of memory we will use for the modalias environment variable. ++ * ++ * The potential additions are: ++ * ++ * SEQNUM=18446744073709551615 - (%llu - 28 bytes) ++ * HOME=/ (6 bytes) ++ * PATH=/sbin:/bin:/usr/sbin:/usr/bin (34 bytes) ++ * ++ * 68 bytes total. Allow extra buffer - 96 bytes ++ */ ++#define UEVENT_ENV_EXTRA_LEN 96 ++ + static int input_add_uevent_modalias_var(struct kobj_uevent_env *env, + const struct input_dev *dev) + { +@@ -1650,9 +1722,11 @@ static int input_add_uevent_modalias_var(struct kobj_uevent_env *env, + return -ENOMEM; + + len = input_print_modalias(&env->buf[env->buflen - 1], +- sizeof(env->buf) - env->buflen, +- dev, 0); +- if (len >= (sizeof(env->buf) - env->buflen)) ++ (int)sizeof(env->buf) - env->buflen - ++ UEVENT_ENV_EXTRA_LEN, ++ dev); ++ if (len >= ((int)sizeof(env->buf) - env->buflen - ++ UEVENT_ENV_EXTRA_LEN)) + return -ENOMEM; + + env->buflen += len; +diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c +index 9206253422016..cd97a7a9f812d 100644 +--- a/drivers/input/joystick/xpad.c ++++ b/drivers/input/joystick/xpad.c +@@ -207,6 +207,7 @@ static const struct xpad_device { + { 0x0738, 0xcb29, "Saitek Aviator Stick AV8R02", 0, XTYPE_XBOX360 }, + { 0x0738, 0xf738, "Super SFIV FightStick TE S", 0, XTYPE_XBOX360 }, + { 0x07ff, 0xffff, "Mad Catz GamePad", 0, XTYPE_XBOX360 }, ++ { 0x0b05, 0x1a38, "ASUS ROG RAIKIRI", 0, XTYPE_XBOXONE }, + { 0x0c12, 0x0005, "Intec wireless", 0, XTYPE_XBOX }, + { 0x0c12, 0x8801, "Nyko Xbox Controller", 0, XTYPE_XBOX }, + { 0x0c12, 0x8802, "Zeroplus Xbox Controller", 0, XTYPE_XBOX }, +@@ -482,6 +483,7 @@ static const struct usb_device_id xpad_table[] = { + { USB_DEVICE(0x0738, 0x4540) }, /* Mad Catz Beat Pad */ + XPAD_XBOXONE_VENDOR(0x0738), /* Mad Catz FightStick TE 2 */ + XPAD_XBOX360_VENDOR(0x07ff), /* Mad Catz Gamepad */ ++ XPAD_XBOXONE_VENDOR(0x0b05), /* ASUS controllers */ + XPAD_XBOX360_VENDOR(0x0c12), /* Zeroplus X-Box 360 controllers */ + XPAD_XBOX360_VENDOR(0x0e6f), /* 0x0e6f Xbox 360 controllers */ + XPAD_XBOXONE_VENDOR(0x0e6f), /* 0x0e6f Xbox One controllers */ +diff --git a/drivers/input/misc/da7280.c b/drivers/input/misc/da7280.c +index ce82548916bbc..c1fa75c0f970a 100644 +--- a/drivers/input/misc/da7280.c ++++ b/drivers/input/misc/da7280.c +@@ -352,7 +352,7 @@ static int da7280_haptic_set_pwm(struct da7280_haptic *haptics, bool enabled) + state.duty_cycle = period_mag_multi; + } + +- error = pwm_apply_state(haptics->pwm_dev, &state); ++ error = pwm_apply_might_sleep(haptics->pwm_dev, &state); + if (error) + dev_err(haptics->dev, "Failed to apply pwm state: %d\n", error); + +@@ -1175,7 +1175,7 @@ static int da7280_probe(struct i2c_client *client) + /* Sync up PWM state and ensure it is off. */ + pwm_init_state(haptics->pwm_dev, &state); + state.enabled = false; +- error = pwm_apply_state(haptics->pwm_dev, &state); ++ error = pwm_apply_might_sleep(haptics->pwm_dev, &state); + if (error) { + dev_err(dev, "Failed to apply PWM state: %d\n", error); + return error; +diff --git a/drivers/input/misc/ims-pcu.c b/drivers/input/misc/ims-pcu.c +index b2f1292e27ef7..180d90e46061e 100644 +--- a/drivers/input/misc/ims-pcu.c ++++ b/drivers/input/misc/ims-pcu.c +@@ -42,8 +42,8 @@ struct ims_pcu_backlight { + #define IMS_PCU_PART_NUMBER_LEN 15 + #define IMS_PCU_SERIAL_NUMBER_LEN 8 + #define IMS_PCU_DOM_LEN 8 +-#define IMS_PCU_FW_VERSION_LEN (9 + 1) +-#define IMS_PCU_BL_VERSION_LEN (9 + 1) ++#define IMS_PCU_FW_VERSION_LEN 16 ++#define IMS_PCU_BL_VERSION_LEN 16 + #define IMS_PCU_BL_RESET_REASON_LEN (2 + 1) + + #define IMS_PCU_PCU_B_DEVICE_ID 5 +diff --git a/drivers/input/misc/pm8xxx-vibrator.c b/drivers/input/misc/pm8xxx-vibrator.c +index 5c288fe7accf1..79f478d3a9b37 100644 +--- a/drivers/input/misc/pm8xxx-vibrator.c ++++ b/drivers/input/misc/pm8xxx-vibrator.c +@@ -13,7 +13,8 @@ + + #define VIB_MAX_LEVEL_mV (3100) + #define VIB_MIN_LEVEL_mV (1200) +-#define VIB_MAX_LEVELS (VIB_MAX_LEVEL_mV - VIB_MIN_LEVEL_mV) ++#define VIB_PER_STEP_mV (100) ++#define VIB_MAX_LEVELS (VIB_MAX_LEVEL_mV - VIB_MIN_LEVEL_mV + VIB_PER_STEP_mV) + + #define MAX_FF_SPEED 0xff + +@@ -117,10 +118,10 @@ static void pm8xxx_work_handler(struct work_struct *work) + vib->active = true; + vib->level = ((VIB_MAX_LEVELS * vib->speed) / MAX_FF_SPEED) + + VIB_MIN_LEVEL_mV; +- vib->level /= 100; ++ vib->level /= VIB_PER_STEP_mV; + } else { + vib->active = false; +- vib->level = VIB_MIN_LEVEL_mV / 100; ++ vib->level = VIB_MIN_LEVEL_mV / VIB_PER_STEP_mV; + } + + pm8xxx_vib_set(vib, vib->active); +diff --git a/drivers/input/misc/pwm-beeper.c b/drivers/input/misc/pwm-beeper.c +index 1e731d8397c6f..5b9aedf4362f4 100644 +--- a/drivers/input/misc/pwm-beeper.c ++++ b/drivers/input/misc/pwm-beeper.c +@@ -39,7 +39,7 @@ static int pwm_beeper_on(struct pwm_beeper *beeper, unsigned long period) + state.period = period; + pwm_set_relative_duty_cycle(&state, 50, 100); + +- error = pwm_apply_state(beeper->pwm, &state); ++ error = pwm_apply_might_sleep(beeper->pwm, &state); + if (error) + return error; + +@@ -138,7 +138,7 @@ static int pwm_beeper_probe(struct platform_device *pdev) + /* Sync up PWM state and ensure it is off. */ + pwm_init_state(beeper->pwm, &state); + state.enabled = false; +- error = pwm_apply_state(beeper->pwm, &state); ++ error = pwm_apply_might_sleep(beeper->pwm, &state); + if (error) { + dev_err(dev, "failed to apply initial PWM state: %d\n", + error); +diff --git a/drivers/input/misc/pwm-vibra.c b/drivers/input/misc/pwm-vibra.c +index acac79c488aa1..3e5ed685ed8f5 100644 +--- a/drivers/input/misc/pwm-vibra.c ++++ b/drivers/input/misc/pwm-vibra.c +@@ -56,7 +56,7 @@ static int pwm_vibrator_start(struct pwm_vibrator *vibrator) + pwm_set_relative_duty_cycle(&state, vibrator->level, 0xffff); + state.enabled = true; + +- err = pwm_apply_state(vibrator->pwm, &state); ++ err = pwm_apply_might_sleep(vibrator->pwm, &state); + if (err) { + dev_err(pdev, "failed to apply pwm state: %d\n", err); + return err; +@@ -67,7 +67,7 @@ static int pwm_vibrator_start(struct pwm_vibrator *vibrator) + state.duty_cycle = vibrator->direction_duty_cycle; + state.enabled = true; + +- err = pwm_apply_state(vibrator->pwm_dir, &state); ++ err = pwm_apply_might_sleep(vibrator->pwm_dir, &state); + if (err) { + dev_err(pdev, "failed to apply dir-pwm state: %d\n", err); + pwm_disable(vibrator->pwm); +@@ -160,7 +160,7 @@ static int pwm_vibrator_probe(struct platform_device *pdev) + /* Sync up PWM state and ensure it is off. */ + pwm_init_state(vibrator->pwm, &state); + state.enabled = false; +- err = pwm_apply_state(vibrator->pwm, &state); ++ err = pwm_apply_might_sleep(vibrator->pwm, &state); + if (err) { + dev_err(&pdev->dev, "failed to apply initial PWM state: %d\n", + err); +@@ -174,7 +174,7 @@ static int pwm_vibrator_probe(struct platform_device *pdev) + /* Sync up PWM state and ensure it is off. */ + pwm_init_state(vibrator->pwm_dir, &state); + state.enabled = false; +- err = pwm_apply_state(vibrator->pwm_dir, &state); ++ err = pwm_apply_might_sleep(vibrator->pwm_dir, &state); + if (err) { + dev_err(&pdev->dev, "failed to apply initial PWM state: %d\n", + err); +diff --git a/drivers/input/mouse/cyapa.c b/drivers/input/mouse/cyapa.c +index 05851bc32541f..40b01cabaa337 100644 +--- a/drivers/input/mouse/cyapa.c ++++ b/drivers/input/mouse/cyapa.c +@@ -1356,10 +1356,16 @@ static int cyapa_suspend(struct device *dev) + u8 power_mode; + int error; + +- error = mutex_lock_interruptible(&cyapa->state_sync_lock); ++ error = mutex_lock_interruptible(&cyapa->input->mutex); + if (error) + return error; + ++ error = mutex_lock_interruptible(&cyapa->state_sync_lock); ++ if (error) { ++ mutex_unlock(&cyapa->input->mutex); ++ return error; ++ } ++ + /* + * Runtime PM is enable only when device is in operational mode and + * users in use, so need check it before disable it to +@@ -1394,6 +1400,8 @@ static int cyapa_suspend(struct device *dev) + cyapa->irq_wake = (enable_irq_wake(client->irq) == 0); + + mutex_unlock(&cyapa->state_sync_lock); ++ mutex_unlock(&cyapa->input->mutex); ++ + return 0; + } + +@@ -1403,6 +1411,7 @@ static int cyapa_resume(struct device *dev) + struct cyapa *cyapa = i2c_get_clientdata(client); + int error; + ++ mutex_lock(&cyapa->input->mutex); + mutex_lock(&cyapa->state_sync_lock); + + if (device_may_wakeup(dev) && cyapa->irq_wake) { +@@ -1421,6 +1430,7 @@ static int cyapa_resume(struct device *dev) + enable_irq(client->irq); + + mutex_unlock(&cyapa->state_sync_lock); ++ mutex_unlock(&cyapa->input->mutex); + return 0; + } + +diff --git a/drivers/interconnect/qcom/qcm2290.c b/drivers/interconnect/qcom/qcm2290.c +index 5bc4b7516608b..52346f7319acc 100644 +--- a/drivers/interconnect/qcom/qcm2290.c ++++ b/drivers/interconnect/qcom/qcm2290.c +@@ -161,7 +161,7 @@ static struct qcom_icc_node mas_snoc_bimc = { + .name = "mas_snoc_bimc", + .buswidth = 16, + .qos.ap_owned = true, +- .qos.qos_port = 2, ++ .qos.qos_port = 6, + .qos.qos_mode = NOC_QOS_MODE_BYPASS, + .mas_rpm_id = 164, + .slv_rpm_id = -1, +diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c +index 3a67e636287a7..3f1029c0825e9 100644 +--- a/drivers/iommu/iommu.c ++++ b/drivers/iommu/iommu.c +@@ -3369,15 +3369,26 @@ EXPORT_SYMBOL_GPL(iommu_group_dma_owner_claimed); + static int __iommu_set_group_pasid(struct iommu_domain *domain, + struct iommu_group *group, ioasid_t pasid) + { +- struct group_device *device; +- int ret = 0; ++ struct group_device *device, *last_gdev; ++ int ret; + + for_each_group_device(group, device) { + ret = domain->ops->set_dev_pasid(domain, device->dev, pasid); + if (ret) +- break; ++ goto err_revert; + } + ++ return 0; ++ ++err_revert: ++ last_gdev = device; ++ for_each_group_device(group, device) { ++ const struct iommu_ops *ops = dev_iommu_ops(device->dev); ++ ++ if (device == last_gdev) ++ break; ++ ops->remove_dev_pasid(device->dev, pasid); ++ } + return ret; + } + +@@ -3423,10 +3434,8 @@ int iommu_attach_device_pasid(struct iommu_domain *domain, + } + + ret = __iommu_set_group_pasid(domain, group, pasid); +- if (ret) { +- __iommu_remove_group_pasid(group, pasid); ++ if (ret) + xa_erase(&group->pasid_array, pasid); +- } + out_unlock: + mutex_unlock(&group->mutex); + iommu_group_put(group); +diff --git a/drivers/irqchip/irq-alpine-msi.c b/drivers/irqchip/irq-alpine-msi.c +index 9c8b1349ee17b..a1430ab60a8a3 100644 +--- a/drivers/irqchip/irq-alpine-msi.c ++++ b/drivers/irqchip/irq-alpine-msi.c +@@ -165,7 +165,7 @@ static int alpine_msix_middle_domain_alloc(struct irq_domain *domain, + return 0; + + err_sgi: +- irq_domain_free_irqs_parent(domain, virq, i - 1); ++ irq_domain_free_irqs_parent(domain, virq, i); + alpine_msix_free_sgi(priv, sgi, nr_irqs); + return err; + } +diff --git a/drivers/irqchip/irq-loongson-pch-msi.c b/drivers/irqchip/irq-loongson-pch-msi.c +index 6e1e1f011bb29..dd4d699170f4e 100644 +--- a/drivers/irqchip/irq-loongson-pch-msi.c ++++ b/drivers/irqchip/irq-loongson-pch-msi.c +@@ -136,7 +136,7 @@ static int pch_msi_middle_domain_alloc(struct irq_domain *domain, + + err_hwirq: + pch_msi_free_hwirq(priv, hwirq, nr_irqs); +- irq_domain_free_irqs_parent(domain, virq, i - 1); ++ irq_domain_free_irqs_parent(domain, virq, i); + + return err; + } +diff --git a/drivers/leds/leds-pwm.c b/drivers/leds/leds-pwm.c +index 2b3bf1353b707..e1b414b403534 100644 +--- a/drivers/leds/leds-pwm.c ++++ b/drivers/leds/leds-pwm.c +@@ -53,8 +53,14 @@ static int led_pwm_set(struct led_classdev *led_cdev, + duty = led_dat->pwmstate.period - duty; + + led_dat->pwmstate.duty_cycle = duty; +- led_dat->pwmstate.enabled = true; +- return pwm_apply_state(led_dat->pwm, &led_dat->pwmstate); ++ /* ++ * Disabling a PWM doesn't guarantee that it emits the inactive level. ++ * So keep it on. Only for suspending the PWM should be disabled because ++ * otherwise it refuses to suspend. The possible downside is that the ++ * LED might stay (or even go) on. ++ */ ++ led_dat->pwmstate.enabled = !(led_cdev->flags & LED_SUSPENDED); ++ return pwm_apply_might_sleep(led_dat->pwm, &led_dat->pwmstate); + } + + __attribute__((nonnull)) +diff --git a/drivers/leds/rgb/leds-pwm-multicolor.c b/drivers/leds/rgb/leds-pwm-multicolor.c +index 46cd062b8b24c..e1a81e0109e8a 100644 +--- a/drivers/leds/rgb/leds-pwm-multicolor.c ++++ b/drivers/leds/rgb/leds-pwm-multicolor.c +@@ -51,8 +51,8 @@ static int led_pwm_mc_set(struct led_classdev *cdev, + + priv->leds[i].state.duty_cycle = duty; + priv->leds[i].state.enabled = duty > 0; +- ret = pwm_apply_state(priv->leds[i].pwm, +- &priv->leds[i].state); ++ ret = pwm_apply_might_sleep(priv->leds[i].pwm, ++ &priv->leds[i].state); + if (ret) + break; + } +diff --git a/drivers/macintosh/via-macii.c b/drivers/macintosh/via-macii.c +index db9270da5b8e9..b6ddf1d47cb4e 100644 +--- a/drivers/macintosh/via-macii.c ++++ b/drivers/macintosh/via-macii.c +@@ -140,24 +140,19 @@ static int macii_probe(void) + /* Initialize the driver */ + static int macii_init(void) + { +- unsigned long flags; + int err; + +- local_irq_save(flags); +- + err = macii_init_via(); + if (err) +- goto out; ++ return err; + + err = request_irq(IRQ_MAC_ADB, macii_interrupt, 0, "ADB", + macii_interrupt); + if (err) +- goto out; ++ return err; + + macii_state = idle; +-out: +- local_irq_restore(flags); +- return err; ++ return 0; + } + + /* initialize the hardware */ +diff --git a/drivers/md/md-bitmap.c b/drivers/md/md-bitmap.c +index 42d4c38ba54d5..d9235ee7dcc46 100644 +--- a/drivers/md/md-bitmap.c ++++ b/drivers/md/md-bitmap.c +@@ -1427,7 +1427,7 @@ __acquires(bitmap->lock) + sector_t chunk = offset >> bitmap->chunkshift; + unsigned long page = chunk >> PAGE_COUNTER_SHIFT; + unsigned long pageoff = (chunk & PAGE_COUNTER_MASK) << COUNTER_BYTE_SHIFT; +- sector_t csize; ++ sector_t csize = ((sector_t)1) << bitmap->chunkshift; + int err; + + if (page >= bitmap->pages) { +@@ -1436,6 +1436,7 @@ __acquires(bitmap->lock) + * End-of-device while looking for a whole page or + * user set a huge number to sysfs bitmap_set_bits. + */ ++ *blocks = csize - (offset & (csize - 1)); + return NULL; + } + err = md_bitmap_checkpage(bitmap, page, create, 0); +@@ -1444,8 +1445,7 @@ __acquires(bitmap->lock) + bitmap->bp[page].map == NULL) + csize = ((sector_t)1) << (bitmap->chunkshift + + PAGE_COUNTER_SHIFT); +- else +- csize = ((sector_t)1) << bitmap->chunkshift; ++ + *blocks = csize - (offset & (csize - 1)); + + if (err < 0) +diff --git a/drivers/media/cec/core/cec-adap.c b/drivers/media/cec/core/cec-adap.c +index ed1fa07e70b57..3b67e922f9815 100644 +--- a/drivers/media/cec/core/cec-adap.c ++++ b/drivers/media/cec/core/cec-adap.c +@@ -490,6 +490,15 @@ int cec_thread_func(void *_adap) + goto unlock; + } + ++ if (adap->transmit_in_progress && ++ adap->transmit_in_progress_aborted) { ++ if (adap->transmitting) ++ cec_data_cancel(adap->transmitting, ++ CEC_TX_STATUS_ABORTED, 0); ++ adap->transmit_in_progress = false; ++ adap->transmit_in_progress_aborted = false; ++ goto unlock; ++ } + if (adap->transmit_in_progress && timeout) { + /* + * If we timeout, then log that. Normally this does +@@ -744,6 +753,7 @@ int cec_transmit_msg_fh(struct cec_adapter *adap, struct cec_msg *msg, + { + struct cec_data *data; + bool is_raw = msg_is_raw(msg); ++ int err; + + if (adap->devnode.unregistered) + return -ENODEV; +@@ -908,11 +918,13 @@ int cec_transmit_msg_fh(struct cec_adapter *adap, struct cec_msg *msg, + * Release the lock and wait, retake the lock afterwards. + */ + mutex_unlock(&adap->lock); +- wait_for_completion_killable(&data->c); +- if (!data->completed) +- cancel_delayed_work_sync(&data->work); ++ err = wait_for_completion_killable(&data->c); ++ cancel_delayed_work_sync(&data->work); + mutex_lock(&adap->lock); + ++ if (err) ++ adap->transmit_in_progress_aborted = true; ++ + /* Cancel the transmit if it was interrupted */ + if (!data->completed) { + if (data->msg.tx_status & CEC_TX_STATUS_OK) +@@ -1548,9 +1560,12 @@ static int cec_config_thread_func(void *arg) + */ + static void cec_claim_log_addrs(struct cec_adapter *adap, bool block) + { +- if (WARN_ON(adap->is_configuring || adap->is_configured)) ++ if (WARN_ON(adap->is_claiming_log_addrs || ++ adap->is_configuring || adap->is_configured)) + return; + ++ adap->is_claiming_log_addrs = true; ++ + init_completion(&adap->config_completion); + + /* Ready to kick off the thread */ +@@ -1565,6 +1580,7 @@ static void cec_claim_log_addrs(struct cec_adapter *adap, bool block) + wait_for_completion(&adap->config_completion); + mutex_lock(&adap->lock); + } ++ adap->is_claiming_log_addrs = false; + } + + /* +diff --git a/drivers/media/cec/core/cec-api.c b/drivers/media/cec/core/cec-api.c +index 67dc79ef17050..3ef9153443044 100644 +--- a/drivers/media/cec/core/cec-api.c ++++ b/drivers/media/cec/core/cec-api.c +@@ -178,7 +178,7 @@ static long cec_adap_s_log_addrs(struct cec_adapter *adap, struct cec_fh *fh, + CEC_LOG_ADDRS_FL_ALLOW_RC_PASSTHRU | + CEC_LOG_ADDRS_FL_CDC_ONLY; + mutex_lock(&adap->lock); +- if (!adap->is_configuring && ++ if (!adap->is_claiming_log_addrs && !adap->is_configuring && + (!log_addrs.num_log_addrs || !adap->is_configured) && + !cec_is_busy(adap, fh)) { + err = __cec_s_log_addrs(adap, &log_addrs, block); +@@ -664,6 +664,8 @@ static int cec_release(struct inode *inode, struct file *filp) + list_del_init(&data->xfer_list); + } + mutex_unlock(&adap->lock); ++ ++ mutex_lock(&fh->lock); + while (!list_empty(&fh->msgs)) { + struct cec_msg_entry *entry = + list_first_entry(&fh->msgs, struct cec_msg_entry, list); +@@ -681,6 +683,7 @@ static int cec_release(struct inode *inode, struct file *filp) + kfree(entry); + } + } ++ mutex_unlock(&fh->lock); + kfree(fh); + + cec_put_device(devnode); +diff --git a/drivers/media/i2c/et8ek8/et8ek8_driver.c b/drivers/media/i2c/et8ek8/et8ek8_driver.c +index d6fc843f9368e..0d6f0f8506f76 100644 +--- a/drivers/media/i2c/et8ek8/et8ek8_driver.c ++++ b/drivers/media/i2c/et8ek8/et8ek8_driver.c +@@ -1460,7 +1460,7 @@ static int et8ek8_probe(struct i2c_client *client) + return ret; + } + +-static void __exit et8ek8_remove(struct i2c_client *client) ++static void et8ek8_remove(struct i2c_client *client) + { + struct v4l2_subdev *subdev = i2c_get_clientdata(client); + struct et8ek8_sensor *sensor = to_et8ek8_sensor(subdev); +@@ -1502,7 +1502,7 @@ static struct i2c_driver et8ek8_i2c_driver = { + .of_match_table = et8ek8_of_table, + }, + .probe = et8ek8_probe, +- .remove = __exit_p(et8ek8_remove), ++ .remove = et8ek8_remove, + .id_table = et8ek8_id_table, + }; + +diff --git a/drivers/media/i2c/ov2680.c b/drivers/media/i2c/ov2680.c +index 72bab0ff8a36a..6436879f95c01 100644 +--- a/drivers/media/i2c/ov2680.c ++++ b/drivers/media/i2c/ov2680.c +@@ -1104,25 +1104,24 @@ static int ov2680_parse_dt(struct ov2680_dev *sensor) + sensor->pixel_rate = sensor->link_freq[0] * 2; + do_div(sensor->pixel_rate, 10); + +- /* Verify bus cfg */ +- if (bus_cfg.bus.mipi_csi2.num_data_lanes != 1) { +- ret = dev_err_probe(dev, -EINVAL, +- "only a 1-lane CSI2 config is supported"); +- goto out_free_bus_cfg; ++ if (!bus_cfg.nr_of_link_frequencies) { ++ dev_warn(dev, "Consider passing 'link-frequencies' in DT\n"); ++ goto skip_link_freq_validation; + } + + for (i = 0; i < bus_cfg.nr_of_link_frequencies; i++) + if (bus_cfg.link_frequencies[i] == sensor->link_freq[0]) + break; + +- if (bus_cfg.nr_of_link_frequencies == 0 || +- bus_cfg.nr_of_link_frequencies == i) { ++ if (bus_cfg.nr_of_link_frequencies == i) { + ret = dev_err_probe(dev, -EINVAL, + "supported link freq %lld not found\n", + sensor->link_freq[0]); + goto out_free_bus_cfg; + } + ++skip_link_freq_validation: ++ ret = 0; + out_free_bus_cfg: + v4l2_fwnode_endpoint_free(&bus_cfg); + return ret; +diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2.c b/drivers/media/pci/intel/ipu3/ipu3-cio2.c +index 5dd69a251b6a9..423842d2a5b2b 100644 +--- a/drivers/media/pci/intel/ipu3/ipu3-cio2.c ++++ b/drivers/media/pci/intel/ipu3/ipu3-cio2.c +@@ -1803,11 +1803,6 @@ static int cio2_pci_probe(struct pci_dev *pci_dev, + + v4l2_async_nf_init(&cio2->notifier, &cio2->v4l2_dev); + +- /* Register notifier for subdevices we care */ +- r = cio2_parse_firmware(cio2); +- if (r) +- goto fail_clean_notifier; +- + r = devm_request_irq(dev, pci_dev->irq, cio2_irq, IRQF_SHARED, + CIO2_NAME, cio2); + if (r) { +@@ -1815,6 +1810,11 @@ static int cio2_pci_probe(struct pci_dev *pci_dev, + goto fail_clean_notifier; + } + ++ /* Register notifier for subdevices we care */ ++ r = cio2_parse_firmware(cio2); ++ if (r) ++ goto fail_clean_notifier; ++ + pm_runtime_put_noidle(dev); + pm_runtime_allow(dev); + +diff --git a/drivers/media/pci/ngene/ngene-core.c b/drivers/media/pci/ngene/ngene-core.c +index 7481f553f9595..24ec576dc3bff 100644 +--- a/drivers/media/pci/ngene/ngene-core.c ++++ b/drivers/media/pci/ngene/ngene-core.c +@@ -1488,7 +1488,9 @@ static int init_channel(struct ngene_channel *chan) + } + + if (dev->ci.en && (io & NGENE_IO_TSOUT)) { +- dvb_ca_en50221_init(adapter, dev->ci.en, 0, 1); ++ ret = dvb_ca_en50221_init(adapter, dev->ci.en, 0, 1); ++ if (ret != 0) ++ goto err; + set_transfer(chan, 1); + chan->dev->channel[2].DataFormatFlags = DF_SWAP32; + set_transfer(&chan->dev->channel[2], 1); +diff --git a/drivers/media/platform/cadence/cdns-csi2rx.c b/drivers/media/platform/cadence/cdns-csi2rx.c +index f2ce458ebb1df..2d803cf31e9d1 100644 +--- a/drivers/media/platform/cadence/cdns-csi2rx.c ++++ b/drivers/media/platform/cadence/cdns-csi2rx.c +@@ -164,10 +164,6 @@ static int csi2rx_start(struct csi2rx_priv *csi2rx) + + writel(reg, csi2rx->base + CSI2RX_STATIC_CFG_REG); + +- ret = v4l2_subdev_call(csi2rx->source_subdev, video, s_stream, true); +- if (ret) +- goto err_disable_pclk; +- + /* Enable DPHY clk and data lanes. */ + if (csi2rx->dphy) { + reg = CSI2RX_DPHY_CL_EN | CSI2RX_DPHY_CL_RST; +@@ -177,6 +173,13 @@ static int csi2rx_start(struct csi2rx_priv *csi2rx) + } + + writel(reg, csi2rx->base + CSI2RX_DPHY_LANE_CTRL_REG); ++ ++ ret = csi2rx_configure_ext_dphy(csi2rx); ++ if (ret) { ++ dev_err(csi2rx->dev, ++ "Failed to configure external DPHY: %d\n", ret); ++ goto err_disable_pclk; ++ } + } + + /* +@@ -213,14 +216,9 @@ static int csi2rx_start(struct csi2rx_priv *csi2rx) + + reset_control_deassert(csi2rx->sys_rst); + +- if (csi2rx->dphy) { +- ret = csi2rx_configure_ext_dphy(csi2rx); +- if (ret) { +- dev_err(csi2rx->dev, +- "Failed to configure external DPHY: %d\n", ret); +- goto err_disable_sysclk; +- } +- } ++ ret = v4l2_subdev_call(csi2rx->source_subdev, video, s_stream, true); ++ if (ret) ++ goto err_disable_sysclk; + + clk_disable_unprepare(csi2rx->p_clk); + +@@ -234,6 +232,10 @@ static int csi2rx_start(struct csi2rx_priv *csi2rx) + clk_disable_unprepare(csi2rx->pixel_clk[i - 1]); + } + ++ if (csi2rx->dphy) { ++ writel(0, csi2rx->base + CSI2RX_DPHY_LANE_CTRL_REG); ++ phy_power_off(csi2rx->dphy); ++ } + err_disable_pclk: + clk_disable_unprepare(csi2rx->p_clk); + +diff --git a/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc.c b/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc.c +index 04948d3eb011a..eb381fa6e7d14 100644 +--- a/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc.c ++++ b/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc.c +@@ -866,7 +866,7 @@ static int vb2ops_venc_start_streaming(struct vb2_queue *q, unsigned int count) + { + struct mtk_vcodec_enc_ctx *ctx = vb2_get_drv_priv(q); + struct venc_enc_param param; +- int ret, pm_ret; ++ int ret; + int i; + + /* Once state turn into MTK_STATE_ABORT, we need stop_streaming +@@ -886,18 +886,12 @@ static int vb2ops_venc_start_streaming(struct vb2_queue *q, unsigned int count) + return 0; + } + +- ret = pm_runtime_resume_and_get(&ctx->dev->plat_dev->dev); +- if (ret < 0) { +- mtk_v4l2_venc_err(ctx, "pm_runtime_resume_and_get fail %d", ret); +- goto err_start_stream; +- } +- + mtk_venc_set_param(ctx, ¶m); + ret = venc_if_set_param(ctx, VENC_SET_PARAM_ENC, ¶m); + if (ret) { + mtk_v4l2_venc_err(ctx, "venc_if_set_param failed=%d", ret); + ctx->state = MTK_STATE_ABORT; +- goto err_set_param; ++ goto err_start_stream; + } + ctx->param_change = MTK_ENCODE_PARAM_NONE; + +@@ -910,18 +904,13 @@ static int vb2ops_venc_start_streaming(struct vb2_queue *q, unsigned int count) + if (ret) { + mtk_v4l2_venc_err(ctx, "venc_if_set_param failed=%d", ret); + ctx->state = MTK_STATE_ABORT; +- goto err_set_param; ++ goto err_start_stream; + } + ctx->state = MTK_STATE_HEADER; + } + + return 0; + +-err_set_param: +- pm_ret = pm_runtime_put(&ctx->dev->plat_dev->dev); +- if (pm_ret < 0) +- mtk_v4l2_venc_err(ctx, "pm_runtime_put fail %d", pm_ret); +- + err_start_stream: + for (i = 0; i < q->num_buffers; ++i) { + struct vb2_buffer *buf = vb2_get_buffer(q, i); +@@ -1004,10 +993,6 @@ static void vb2ops_venc_stop_streaming(struct vb2_queue *q) + if (ret) + mtk_v4l2_venc_err(ctx, "venc_if_deinit failed=%d", ret); + +- ret = pm_runtime_put(&ctx->dev->plat_dev->dev); +- if (ret < 0) +- mtk_v4l2_venc_err(ctx, "pm_runtime_put fail %d", ret); +- + ctx->state = MTK_STATE_FREE; + } + +diff --git a/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_pm.c b/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_pm.c +index 3fce936e61b9f..1a2b14a3e219c 100644 +--- a/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_pm.c ++++ b/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_pm.c +@@ -58,6 +58,26 @@ int mtk_vcodec_init_enc_clk(struct mtk_vcodec_enc_dev *mtkdev) + return 0; + } + ++int mtk_vcodec_enc_pw_on(struct mtk_vcodec_pm *pm) ++{ ++ int ret; ++ ++ ret = pm_runtime_resume_and_get(pm->dev); ++ if (ret) ++ dev_err(pm->dev, "pm_runtime_resume_and_get fail: %d", ret); ++ ++ return ret; ++} ++ ++void mtk_vcodec_enc_pw_off(struct mtk_vcodec_pm *pm) ++{ ++ int ret; ++ ++ ret = pm_runtime_put(pm->dev); ++ if (ret && ret != -EAGAIN) ++ dev_err(pm->dev, "pm_runtime_put fail %d", ret); ++} ++ + void mtk_vcodec_enc_clock_on(struct mtk_vcodec_pm *pm) + { + struct mtk_vcodec_clk *enc_clk = &pm->venc_clk; +diff --git a/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_pm.h b/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_pm.h +index e50be0575190a..2e28f25e36cc4 100644 +--- a/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_pm.h ++++ b/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_pm.h +@@ -10,7 +10,8 @@ + #include "mtk_vcodec_enc_drv.h" + + int mtk_vcodec_init_enc_clk(struct mtk_vcodec_enc_dev *dev); +- ++int mtk_vcodec_enc_pw_on(struct mtk_vcodec_pm *pm); ++void mtk_vcodec_enc_pw_off(struct mtk_vcodec_pm *pm); + void mtk_vcodec_enc_clock_on(struct mtk_vcodec_pm *pm); + void mtk_vcodec_enc_clock_off(struct mtk_vcodec_pm *pm); + +diff --git a/drivers/media/platform/mediatek/vcodec/encoder/venc_drv_if.c b/drivers/media/platform/mediatek/vcodec/encoder/venc_drv_if.c +index 1bdaecdd64a79..e83747b8d69ab 100644 +--- a/drivers/media/platform/mediatek/vcodec/encoder/venc_drv_if.c ++++ b/drivers/media/platform/mediatek/vcodec/encoder/venc_drv_if.c +@@ -32,9 +32,7 @@ int venc_if_init(struct mtk_vcodec_enc_ctx *ctx, unsigned int fourcc) + } + + mtk_venc_lock(ctx); +- mtk_vcodec_enc_clock_on(&ctx->dev->pm); + ret = ctx->enc_if->init(ctx); +- mtk_vcodec_enc_clock_off(&ctx->dev->pm); + mtk_venc_unlock(ctx); + + return ret; +@@ -46,9 +44,7 @@ int venc_if_set_param(struct mtk_vcodec_enc_ctx *ctx, + int ret = 0; + + mtk_venc_lock(ctx); +- mtk_vcodec_enc_clock_on(&ctx->dev->pm); + ret = ctx->enc_if->set_param(ctx->drv_handle, type, in); +- mtk_vcodec_enc_clock_off(&ctx->dev->pm); + mtk_venc_unlock(ctx); + + return ret; +@@ -68,15 +64,20 @@ int venc_if_encode(struct mtk_vcodec_enc_ctx *ctx, + ctx->dev->curr_ctx = ctx; + spin_unlock_irqrestore(&ctx->dev->irqlock, flags); + ++ ret = mtk_vcodec_enc_pw_on(&ctx->dev->pm); ++ if (ret) ++ goto venc_if_encode_pw_on_err; + mtk_vcodec_enc_clock_on(&ctx->dev->pm); + ret = ctx->enc_if->encode(ctx->drv_handle, opt, frm_buf, + bs_buf, result); + mtk_vcodec_enc_clock_off(&ctx->dev->pm); ++ mtk_vcodec_enc_pw_off(&ctx->dev->pm); + + spin_lock_irqsave(&ctx->dev->irqlock, flags); + ctx->dev->curr_ctx = NULL; + spin_unlock_irqrestore(&ctx->dev->irqlock, flags); + ++venc_if_encode_pw_on_err: + mtk_venc_unlock(ctx); + return ret; + } +@@ -89,9 +90,7 @@ int venc_if_deinit(struct mtk_vcodec_enc_ctx *ctx) + return 0; + + mtk_venc_lock(ctx); +- mtk_vcodec_enc_clock_on(&ctx->dev->pm); + ret = ctx->enc_if->deinit(ctx->drv_handle); +- mtk_vcodec_enc_clock_off(&ctx->dev->pm); + mtk_venc_unlock(ctx); + + ctx->drv_handle = NULL; +diff --git a/drivers/media/platform/renesas/rcar-vin/rcar-vin.h b/drivers/media/platform/renesas/rcar-vin/rcar-vin.h +index 792336dada447..997a66318a293 100644 +--- a/drivers/media/platform/renesas/rcar-vin/rcar-vin.h ++++ b/drivers/media/platform/renesas/rcar-vin/rcar-vin.h +@@ -59,7 +59,7 @@ enum rvin_isp_id { + + #define RVIN_REMOTES_MAX \ + (((unsigned int)RVIN_CSI_MAX) > ((unsigned int)RVIN_ISP_MAX) ? \ +- RVIN_CSI_MAX : RVIN_ISP_MAX) ++ (unsigned int)RVIN_CSI_MAX : (unsigned int)RVIN_ISP_MAX) + + /** + * enum rvin_dma_state - DMA states +diff --git a/drivers/media/platform/renesas/vsp1/vsp1_pipe.c b/drivers/media/platform/renesas/vsp1/vsp1_pipe.c +index f8093ba9539e9..68d05243c3ee5 100644 +--- a/drivers/media/platform/renesas/vsp1/vsp1_pipe.c ++++ b/drivers/media/platform/renesas/vsp1/vsp1_pipe.c +@@ -373,7 +373,7 @@ int vsp1_pipeline_stop(struct vsp1_pipeline *pipe) + (7 << VI6_DPR_SMPPT_TGW_SHIFT) | + (VI6_DPR_NODE_UNUSED << VI6_DPR_SMPPT_PT_SHIFT)); + +- v4l2_subdev_call(&pipe->output->entity.subdev, video, s_stream, 0); ++ vsp1_wpf_stop(pipe->output); + + return ret; + } +diff --git a/drivers/media/platform/renesas/vsp1/vsp1_rpf.c b/drivers/media/platform/renesas/vsp1/vsp1_rpf.c +index 3b17f5fa4067f..ea12c3f12c92a 100644 +--- a/drivers/media/platform/renesas/vsp1/vsp1_rpf.c ++++ b/drivers/media/platform/renesas/vsp1/vsp1_rpf.c +@@ -43,14 +43,6 @@ static inline void vsp1_rpf_write(struct vsp1_rwpf *rpf, + data); + } + +-/* ----------------------------------------------------------------------------- +- * V4L2 Subdevice Operations +- */ +- +-static const struct v4l2_subdev_ops rpf_ops = { +- .pad = &vsp1_rwpf_pad_ops, +-}; +- + /* ----------------------------------------------------------------------------- + * VSP1 Entity Operations + */ +@@ -411,7 +403,7 @@ struct vsp1_rwpf *vsp1_rpf_create(struct vsp1_device *vsp1, unsigned int index) + rpf->entity.index = index; + + sprintf(name, "rpf.%u", index); +- ret = vsp1_entity_init(vsp1, &rpf->entity, name, 2, &rpf_ops, ++ ret = vsp1_entity_init(vsp1, &rpf->entity, name, 2, &vsp1_rwpf_subdev_ops, + MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER); + if (ret < 0) + return ERR_PTR(ret); +diff --git a/drivers/media/platform/renesas/vsp1/vsp1_rwpf.c b/drivers/media/platform/renesas/vsp1/vsp1_rwpf.c +index 22a82d218152f..e0f87c8103ca5 100644 +--- a/drivers/media/platform/renesas/vsp1/vsp1_rwpf.c ++++ b/drivers/media/platform/renesas/vsp1/vsp1_rwpf.c +@@ -24,7 +24,7 @@ struct v4l2_rect *vsp1_rwpf_get_crop(struct vsp1_rwpf *rwpf, + } + + /* ----------------------------------------------------------------------------- +- * V4L2 Subdevice Pad Operations ++ * V4L2 Subdevice Operations + */ + + static int vsp1_rwpf_enum_mbus_code(struct v4l2_subdev *subdev, +@@ -243,7 +243,7 @@ static int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev, + return ret; + } + +-const struct v4l2_subdev_pad_ops vsp1_rwpf_pad_ops = { ++static const struct v4l2_subdev_pad_ops vsp1_rwpf_pad_ops = { + .init_cfg = vsp1_entity_init_cfg, + .enum_mbus_code = vsp1_rwpf_enum_mbus_code, + .enum_frame_size = vsp1_rwpf_enum_frame_size, +@@ -253,6 +253,10 @@ const struct v4l2_subdev_pad_ops vsp1_rwpf_pad_ops = { + .set_selection = vsp1_rwpf_set_selection, + }; + ++const struct v4l2_subdev_ops vsp1_rwpf_subdev_ops = { ++ .pad = &vsp1_rwpf_pad_ops, ++}; ++ + /* ----------------------------------------------------------------------------- + * Controls + */ +diff --git a/drivers/media/platform/renesas/vsp1/vsp1_rwpf.h b/drivers/media/platform/renesas/vsp1/vsp1_rwpf.h +index eac5c04c22393..e0d212c70b2f9 100644 +--- a/drivers/media/platform/renesas/vsp1/vsp1_rwpf.h ++++ b/drivers/media/platform/renesas/vsp1/vsp1_rwpf.h +@@ -79,9 +79,11 @@ static inline struct vsp1_rwpf *entity_to_rwpf(struct vsp1_entity *entity) + struct vsp1_rwpf *vsp1_rpf_create(struct vsp1_device *vsp1, unsigned int index); + struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index); + ++void vsp1_wpf_stop(struct vsp1_rwpf *wpf); ++ + int vsp1_rwpf_init_ctrls(struct vsp1_rwpf *rwpf, unsigned int ncontrols); + +-extern const struct v4l2_subdev_pad_ops vsp1_rwpf_pad_ops; ++extern const struct v4l2_subdev_ops vsp1_rwpf_subdev_ops; + + struct v4l2_rect *vsp1_rwpf_get_crop(struct vsp1_rwpf *rwpf, + struct v4l2_subdev_state *sd_state); +diff --git a/drivers/media/platform/renesas/vsp1/vsp1_wpf.c b/drivers/media/platform/renesas/vsp1/vsp1_wpf.c +index d0074ca009209..cab4445eca696 100644 +--- a/drivers/media/platform/renesas/vsp1/vsp1_wpf.c ++++ b/drivers/media/platform/renesas/vsp1/vsp1_wpf.c +@@ -186,17 +186,13 @@ static int wpf_init_controls(struct vsp1_rwpf *wpf) + } + + /* ----------------------------------------------------------------------------- +- * V4L2 Subdevice Core Operations ++ * VSP1 Entity Operations + */ + +-static int wpf_s_stream(struct v4l2_subdev *subdev, int enable) ++void vsp1_wpf_stop(struct vsp1_rwpf *wpf) + { +- struct vsp1_rwpf *wpf = to_rwpf(subdev); + struct vsp1_device *vsp1 = wpf->entity.vsp1; + +- if (enable) +- return 0; +- + /* + * Write to registers directly when stopping the stream as there will be + * no pipeline run to apply the display list. +@@ -204,27 +200,8 @@ static int wpf_s_stream(struct v4l2_subdev *subdev, int enable) + vsp1_write(vsp1, VI6_WPF_IRQ_ENB(wpf->entity.index), 0); + vsp1_write(vsp1, wpf->entity.index * VI6_WPF_OFFSET + + VI6_WPF_SRCRPF, 0); +- +- return 0; + } + +-/* ----------------------------------------------------------------------------- +- * V4L2 Subdevice Operations +- */ +- +-static const struct v4l2_subdev_video_ops wpf_video_ops = { +- .s_stream = wpf_s_stream, +-}; +- +-static const struct v4l2_subdev_ops wpf_ops = { +- .video = &wpf_video_ops, +- .pad = &vsp1_rwpf_pad_ops, +-}; +- +-/* ----------------------------------------------------------------------------- +- * VSP1 Entity Operations +- */ +- + static void vsp1_wpf_destroy(struct vsp1_entity *entity) + { + struct vsp1_rwpf *wpf = entity_to_rwpf(entity); +@@ -583,7 +560,7 @@ struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index) + wpf->entity.index = index; + + sprintf(name, "wpf.%u", index); +- ret = vsp1_entity_init(vsp1, &wpf->entity, name, 2, &wpf_ops, ++ ret = vsp1_entity_init(vsp1, &wpf->entity, name, 2, &vsp1_rwpf_subdev_ops, + MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER); + if (ret < 0) + return ERR_PTR(ret); +diff --git a/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/Kconfig b/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/Kconfig +index 47a8c0fb7eb9f..99c401e653bc4 100644 +--- a/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/Kconfig ++++ b/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/Kconfig +@@ -8,6 +8,7 @@ config VIDEO_SUN8I_A83T_MIPI_CSI2 + select VIDEO_V4L2_SUBDEV_API + select V4L2_FWNODE + select REGMAP_MMIO ++ select GENERIC_PHY + select GENERIC_PHY_MIPI_DPHY + help + Support for the Allwinner A83T MIPI CSI-2 controller and D-PHY. +diff --git a/drivers/media/radio/radio-shark2.c b/drivers/media/radio/radio-shark2.c +index f1c5c0a6a335c..e3e6aa87fe081 100644 +--- a/drivers/media/radio/radio-shark2.c ++++ b/drivers/media/radio/radio-shark2.c +@@ -62,7 +62,7 @@ struct shark_device { + #ifdef SHARK_USE_LEDS + struct work_struct led_work; + struct led_classdev leds[NO_LEDS]; +- char led_names[NO_LEDS][32]; ++ char led_names[NO_LEDS][64]; + atomic_t brightness[NO_LEDS]; + unsigned long brightness_new; + #endif +diff --git a/drivers/media/rc/ir-rx51.c b/drivers/media/rc/ir-rx51.c +index 13e81bf8005df..39a7e2db63a78 100644 +--- a/drivers/media/rc/ir-rx51.c ++++ b/drivers/media/rc/ir-rx51.c +@@ -34,13 +34,13 @@ struct ir_rx51 { + static inline void ir_rx51_on(struct ir_rx51 *ir_rx51) + { + ir_rx51->state.enabled = true; +- pwm_apply_state(ir_rx51->pwm, &ir_rx51->state); ++ pwm_apply_might_sleep(ir_rx51->pwm, &ir_rx51->state); + } + + static inline void ir_rx51_off(struct ir_rx51 *ir_rx51) + { + ir_rx51->state.enabled = false; +- pwm_apply_state(ir_rx51->pwm, &ir_rx51->state); ++ pwm_apply_might_sleep(ir_rx51->pwm, &ir_rx51->state); + } + + static int init_timing_params(struct ir_rx51 *ir_rx51) +diff --git a/drivers/media/rc/pwm-ir-tx.c b/drivers/media/rc/pwm-ir-tx.c +index 7732054c4621e..4a6fafe7a249e 100644 +--- a/drivers/media/rc/pwm-ir-tx.c ++++ b/drivers/media/rc/pwm-ir-tx.c +@@ -67,7 +67,7 @@ static int pwm_ir_tx(struct rc_dev *dev, unsigned int *txbuf, + + for (i = 0; i < count; i++) { + state.enabled = !(i % 2); +- pwm_apply_state(pwm, &state); ++ pwm_apply_might_sleep(pwm, &state); + + edge = ktime_add_us(edge, txbuf[i]); + delta = ktime_us_delta(edge, ktime_get()); +@@ -76,7 +76,7 @@ static int pwm_ir_tx(struct rc_dev *dev, unsigned int *txbuf, + } + + state.enabled = false; +- pwm_apply_state(pwm, &state); ++ pwm_apply_might_sleep(pwm, &state); + + return count; + } +diff --git a/drivers/media/usb/b2c2/flexcop-usb.c b/drivers/media/usb/b2c2/flexcop-usb.c +index 790787f0eba84..bcb24d8964981 100644 +--- a/drivers/media/usb/b2c2/flexcop-usb.c ++++ b/drivers/media/usb/b2c2/flexcop-usb.c +@@ -515,7 +515,7 @@ static int flexcop_usb_init(struct flexcop_usb *fc_usb) + + alt = fc_usb->uintf->cur_altsetting; + +- if (alt->desc.bNumEndpoints < 1) ++ if (alt->desc.bNumEndpoints < 2) + return -ENODEV; + if (!usb_endpoint_is_isoc_in(&alt->endpoint[0].desc)) + return -ENODEV; +diff --git a/drivers/media/usb/stk1160/stk1160-video.c b/drivers/media/usb/stk1160/stk1160-video.c +index 366f0e4a5dc0d..e79c45db60ab5 100644 +--- a/drivers/media/usb/stk1160/stk1160-video.c ++++ b/drivers/media/usb/stk1160/stk1160-video.c +@@ -99,7 +99,7 @@ void stk1160_buffer_done(struct stk1160 *dev) + static inline + void stk1160_copy_video(struct stk1160 *dev, u8 *src, int len) + { +- int linesdone, lineoff, lencopy; ++ int linesdone, lineoff, lencopy, offset; + int bytesperline = dev->width * 2; + struct stk1160_buffer *buf = dev->isoc_ctl.buf; + u8 *dst = buf->mem; +@@ -139,8 +139,13 @@ void stk1160_copy_video(struct stk1160 *dev, u8 *src, int len) + * Check if we have enough space left in the buffer. + * In that case, we force loop exit after copy. + */ +- if (lencopy > buf->bytesused - buf->length) { +- lencopy = buf->bytesused - buf->length; ++ offset = dst - (u8 *)buf->mem; ++ if (offset > buf->length) { ++ dev_warn_ratelimited(dev->dev, "out of bounds offset\n"); ++ return; ++ } ++ if (lencopy > buf->length - offset) { ++ lencopy = buf->length - offset; + remain = lencopy; + } + +@@ -182,8 +187,13 @@ void stk1160_copy_video(struct stk1160 *dev, u8 *src, int len) + * Check if we have enough space left in the buffer. + * In that case, we force loop exit after copy. + */ +- if (lencopy > buf->bytesused - buf->length) { +- lencopy = buf->bytesused - buf->length; ++ offset = dst - (u8 *)buf->mem; ++ if (offset > buf->length) { ++ dev_warn_ratelimited(dev->dev, "offset out of bounds\n"); ++ return; ++ } ++ if (lencopy > buf->length - offset) { ++ lencopy = buf->length - offset; + remain = lencopy; + } + +diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c +index bbd90123a4e76..91a41aa3ced24 100644 +--- a/drivers/media/usb/uvc/uvc_driver.c ++++ b/drivers/media/usb/uvc/uvc_driver.c +@@ -14,6 +14,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -2232,6 +2233,9 @@ static int uvc_probe(struct usb_interface *intf, + goto error; + } + ++ if (dev->quirks & UVC_QUIRK_NO_RESET_RESUME) ++ udev->quirks &= ~USB_QUIRK_RESET_RESUME; ++ + uvc_dbg(dev, PROBE, "UVC device initialized\n"); + usb_enable_autosuspend(udev); + return 0; +@@ -2574,6 +2578,33 @@ static const struct usb_device_id uvc_ids[] = { + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = UVC_INFO_QUIRK(UVC_QUIRK_RESTORE_CTRLS_ON_INIT) }, ++ /* Logitech Rally Bar Huddle */ ++ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE ++ | USB_DEVICE_ID_MATCH_INT_INFO, ++ .idVendor = 0x046d, ++ .idProduct = 0x087c, ++ .bInterfaceClass = USB_CLASS_VIDEO, ++ .bInterfaceSubClass = 1, ++ .bInterfaceProtocol = 0, ++ .driver_info = UVC_INFO_QUIRK(UVC_QUIRK_NO_RESET_RESUME) }, ++ /* Logitech Rally Bar */ ++ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE ++ | USB_DEVICE_ID_MATCH_INT_INFO, ++ .idVendor = 0x046d, ++ .idProduct = 0x089b, ++ .bInterfaceClass = USB_CLASS_VIDEO, ++ .bInterfaceSubClass = 1, ++ .bInterfaceProtocol = 0, ++ .driver_info = UVC_INFO_QUIRK(UVC_QUIRK_NO_RESET_RESUME) }, ++ /* Logitech Rally Bar Mini */ ++ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE ++ | USB_DEVICE_ID_MATCH_INT_INFO, ++ .idVendor = 0x046d, ++ .idProduct = 0x08d3, ++ .bInterfaceClass = USB_CLASS_VIDEO, ++ .bInterfaceSubClass = 1, ++ .bInterfaceProtocol = 0, ++ .driver_info = UVC_INFO_QUIRK(UVC_QUIRK_NO_RESET_RESUME) }, + /* Chicony CNF7129 (Asus EEE 100HE) */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, +diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h +index 6fb0a78b1b009..88218693f6f0b 100644 +--- a/drivers/media/usb/uvc/uvcvideo.h ++++ b/drivers/media/usb/uvc/uvcvideo.h +@@ -73,6 +73,7 @@ + #define UVC_QUIRK_FORCE_Y8 0x00000800 + #define UVC_QUIRK_FORCE_BPP 0x00001000 + #define UVC_QUIRK_WAKE_AUTOSUSPEND 0x00002000 ++#define UVC_QUIRK_NO_RESET_RESUME 0x00004000 + + /* Format flags */ + #define UVC_FMT_FLAG_COMPRESSED 0x00000001 +diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c +index 31752c06d1f0c..a32ef739eb449 100644 +--- a/drivers/media/v4l2-core/v4l2-subdev.c ++++ b/drivers/media/v4l2-core/v4l2-subdev.c +@@ -359,20 +359,37 @@ static int call_s_stream(struct v4l2_subdev *sd, int enable) + { + int ret; + +-#if IS_REACHABLE(CONFIG_LEDS_CLASS) +- if (!IS_ERR_OR_NULL(sd->privacy_led)) { +- if (enable) +- led_set_brightness(sd->privacy_led, +- sd->privacy_led->max_brightness); +- else +- led_set_brightness(sd->privacy_led, 0); +- } +-#endif ++ /* ++ * The .s_stream() operation must never be called to start or stop an ++ * already started or stopped subdev. Catch offenders but don't return ++ * an error yet to avoid regressions. ++ * ++ * As .s_stream() is mutually exclusive with the .enable_streams() and ++ * .disable_streams() operation, we can use the enabled_streams field ++ * to store the subdev streaming state. ++ */ ++ if (WARN_ON(!!sd->enabled_streams == !!enable)) ++ return 0; ++ + ret = sd->ops->video->s_stream(sd, enable); + + if (!enable && ret < 0) { + dev_warn(sd->dev, "disabling streaming failed (%d)\n", ret); +- return 0; ++ ret = 0; ++ } ++ ++ if (!ret) { ++ sd->enabled_streams = enable ? BIT(0) : 0; ++ ++#if IS_REACHABLE(CONFIG_LEDS_CLASS) ++ if (!IS_ERR_OR_NULL(sd->privacy_led)) { ++ if (enable) ++ led_set_brightness(sd->privacy_led, ++ sd->privacy_led->max_brightness); ++ else ++ led_set_brightness(sd->privacy_led, 0); ++ } ++#endif + } + + return ret; +@@ -664,6 +681,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg, + memset(&sel, 0, sizeof(sel)); + sel.which = crop->which; + sel.pad = crop->pad; ++ sel.stream = crop->stream; + sel.target = V4L2_SEL_TGT_CROP; + + rval = v4l2_subdev_call( +@@ -688,6 +706,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg, + memset(&sel, 0, sizeof(sel)); + sel.which = crop->which; + sel.pad = crop->pad; ++ sel.stream = crop->stream; + sel.target = V4L2_SEL_TGT_CROP; + sel.r = crop->rect; + +diff --git a/drivers/misc/lkdtm/Makefile b/drivers/misc/lkdtm/Makefile +index 95ef971b5e1cb..b28701138b4bc 100644 +--- a/drivers/misc/lkdtm/Makefile ++++ b/drivers/misc/lkdtm/Makefile +@@ -19,7 +19,7 @@ KASAN_SANITIZE_rodata.o := n + KCSAN_SANITIZE_rodata.o := n + KCOV_INSTRUMENT_rodata.o := n + OBJECT_FILES_NON_STANDARD_rodata.o := y +-CFLAGS_REMOVE_rodata.o += $(CC_FLAGS_LTO) $(RETHUNK_CFLAGS) ++CFLAGS_REMOVE_rodata.o += $(CC_FLAGS_LTO) $(RETHUNK_CFLAGS) $(CC_FLAGS_CFI) + + OBJCOPYFLAGS := + OBJCOPYFLAGS_rodata_objcopy.o := \ +diff --git a/drivers/misc/lkdtm/perms.c b/drivers/misc/lkdtm/perms.c +index b93404d656509..5b861dbff27e9 100644 +--- a/drivers/misc/lkdtm/perms.c ++++ b/drivers/misc/lkdtm/perms.c +@@ -61,7 +61,7 @@ static void *setup_function_descriptor(func_desc_t *fdesc, void *dst) + return fdesc; + } + +-static noinline void execute_location(void *dst, bool write) ++static noinline __nocfi void execute_location(void *dst, bool write) + { + void (*func)(void); + func_desc_t fdesc; +diff --git a/drivers/misc/pvpanic/pvpanic-mmio.c b/drivers/misc/pvpanic/pvpanic-mmio.c +index eb97167c03fb4..9715798acce3d 100644 +--- a/drivers/misc/pvpanic/pvpanic-mmio.c ++++ b/drivers/misc/pvpanic/pvpanic-mmio.c +@@ -24,52 +24,9 @@ MODULE_AUTHOR("Hu Tao "); + MODULE_DESCRIPTION("pvpanic-mmio device driver"); + MODULE_LICENSE("GPL"); + +-static ssize_t capability_show(struct device *dev, struct device_attribute *attr, char *buf) +-{ +- struct pvpanic_instance *pi = dev_get_drvdata(dev); +- +- return sysfs_emit(buf, "%x\n", pi->capability); +-} +-static DEVICE_ATTR_RO(capability); +- +-static ssize_t events_show(struct device *dev, struct device_attribute *attr, char *buf) +-{ +- struct pvpanic_instance *pi = dev_get_drvdata(dev); +- +- return sysfs_emit(buf, "%x\n", pi->events); +-} +- +-static ssize_t events_store(struct device *dev, struct device_attribute *attr, +- const char *buf, size_t count) +-{ +- struct pvpanic_instance *pi = dev_get_drvdata(dev); +- unsigned int tmp; +- int err; +- +- err = kstrtouint(buf, 16, &tmp); +- if (err) +- return err; +- +- if ((tmp & pi->capability) != tmp) +- return -EINVAL; +- +- pi->events = tmp; +- +- return count; +-} +-static DEVICE_ATTR_RW(events); +- +-static struct attribute *pvpanic_mmio_dev_attrs[] = { +- &dev_attr_capability.attr, +- &dev_attr_events.attr, +- NULL +-}; +-ATTRIBUTE_GROUPS(pvpanic_mmio_dev); +- + static int pvpanic_mmio_probe(struct platform_device *pdev) + { + struct device *dev = &pdev->dev; +- struct pvpanic_instance *pi; + struct resource *res; + void __iomem *base; + +@@ -92,18 +49,7 @@ static int pvpanic_mmio_probe(struct platform_device *pdev) + return -EINVAL; + } + +- pi = devm_kmalloc(dev, sizeof(*pi), GFP_KERNEL); +- if (!pi) +- return -ENOMEM; +- +- pi->base = base; +- pi->capability = PVPANIC_PANICKED | PVPANIC_CRASH_LOADED; +- +- /* initialize capability by RDPT */ +- pi->capability &= ioread8(base); +- pi->events = pi->capability; +- +- return devm_pvpanic_probe(dev, pi); ++ return devm_pvpanic_probe(dev, base); + } + + static const struct of_device_id pvpanic_mmio_match[] = { +@@ -123,7 +69,7 @@ static struct platform_driver pvpanic_mmio_driver = { + .name = "pvpanic-mmio", + .of_match_table = pvpanic_mmio_match, + .acpi_match_table = pvpanic_device_ids, +- .dev_groups = pvpanic_mmio_dev_groups, ++ .dev_groups = pvpanic_dev_groups, + }, + .probe = pvpanic_mmio_probe, + }; +diff --git a/drivers/misc/pvpanic/pvpanic-pci.c b/drivers/misc/pvpanic/pvpanic-pci.c +index 07eddb5ea30fa..2494725dfacfa 100644 +--- a/drivers/misc/pvpanic/pvpanic-pci.c ++++ b/drivers/misc/pvpanic/pvpanic-pci.c +@@ -22,51 +22,8 @@ MODULE_AUTHOR("Mihai Carabas "); + MODULE_DESCRIPTION("pvpanic device driver"); + MODULE_LICENSE("GPL"); + +-static ssize_t capability_show(struct device *dev, struct device_attribute *attr, char *buf) +-{ +- struct pvpanic_instance *pi = dev_get_drvdata(dev); +- +- return sysfs_emit(buf, "%x\n", pi->capability); +-} +-static DEVICE_ATTR_RO(capability); +- +-static ssize_t events_show(struct device *dev, struct device_attribute *attr, char *buf) +-{ +- struct pvpanic_instance *pi = dev_get_drvdata(dev); +- +- return sysfs_emit(buf, "%x\n", pi->events); +-} +- +-static ssize_t events_store(struct device *dev, struct device_attribute *attr, +- const char *buf, size_t count) +-{ +- struct pvpanic_instance *pi = dev_get_drvdata(dev); +- unsigned int tmp; +- int err; +- +- err = kstrtouint(buf, 16, &tmp); +- if (err) +- return err; +- +- if ((tmp & pi->capability) != tmp) +- return -EINVAL; +- +- pi->events = tmp; +- +- return count; +-} +-static DEVICE_ATTR_RW(events); +- +-static struct attribute *pvpanic_pci_dev_attrs[] = { +- &dev_attr_capability.attr, +- &dev_attr_events.attr, +- NULL +-}; +-ATTRIBUTE_GROUPS(pvpanic_pci_dev); +- + static int pvpanic_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) + { +- struct pvpanic_instance *pi; + void __iomem *base; + int ret; + +@@ -78,18 +35,7 @@ static int pvpanic_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e + if (!base) + return -ENOMEM; + +- pi = devm_kmalloc(&pdev->dev, sizeof(*pi), GFP_KERNEL); +- if (!pi) +- return -ENOMEM; +- +- pi->base = base; +- pi->capability = PVPANIC_PANICKED | PVPANIC_CRASH_LOADED; +- +- /* initlize capability by RDPT */ +- pi->capability &= ioread8(base); +- pi->events = pi->capability; +- +- return devm_pvpanic_probe(&pdev->dev, pi); ++ return devm_pvpanic_probe(&pdev->dev, base); + } + + static const struct pci_device_id pvpanic_pci_id_tbl[] = { +@@ -102,8 +48,6 @@ static struct pci_driver pvpanic_pci_driver = { + .name = "pvpanic-pci", + .id_table = pvpanic_pci_id_tbl, + .probe = pvpanic_pci_probe, +- .driver = { +- .dev_groups = pvpanic_pci_dev_groups, +- }, ++ .dev_groups = pvpanic_dev_groups, + }; + module_pci_driver(pvpanic_pci_driver); +diff --git a/drivers/misc/pvpanic/pvpanic.c b/drivers/misc/pvpanic/pvpanic.c +index 049a120063489..305b367e0ce34 100644 +--- a/drivers/misc/pvpanic/pvpanic.c ++++ b/drivers/misc/pvpanic/pvpanic.c +@@ -7,6 +7,7 @@ + * Copyright (C) 2021 Oracle. + */ + ++#include + #include + #include + #include +@@ -26,6 +27,13 @@ MODULE_AUTHOR("Mihai Carabas "); + MODULE_DESCRIPTION("pvpanic device driver"); + MODULE_LICENSE("GPL"); + ++struct pvpanic_instance { ++ void __iomem *base; ++ unsigned int capability; ++ unsigned int events; ++ struct list_head list; ++}; ++ + static struct list_head pvpanic_list; + static spinlock_t pvpanic_lock; + +@@ -81,11 +89,75 @@ static void pvpanic_remove(void *param) + spin_unlock(&pvpanic_lock); + } + +-int devm_pvpanic_probe(struct device *dev, struct pvpanic_instance *pi) ++static ssize_t capability_show(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ struct pvpanic_instance *pi = dev_get_drvdata(dev); ++ ++ return sysfs_emit(buf, "%x\n", pi->capability); ++} ++static DEVICE_ATTR_RO(capability); ++ ++static ssize_t events_show(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ struct pvpanic_instance *pi = dev_get_drvdata(dev); ++ ++ return sysfs_emit(buf, "%x\n", pi->events); ++} ++ ++static ssize_t events_store(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct pvpanic_instance *pi = dev_get_drvdata(dev); ++ unsigned int tmp; ++ int err; ++ ++ err = kstrtouint(buf, 16, &tmp); ++ if (err) ++ return err; ++ ++ if ((tmp & pi->capability) != tmp) ++ return -EINVAL; ++ ++ pi->events = tmp; ++ ++ return count; ++} ++static DEVICE_ATTR_RW(events); ++ ++static struct attribute *pvpanic_dev_attrs[] = { ++ &dev_attr_capability.attr, ++ &dev_attr_events.attr, ++ NULL ++}; ++ ++static const struct attribute_group pvpanic_dev_group = { ++ .attrs = pvpanic_dev_attrs, ++}; ++ ++const struct attribute_group *pvpanic_dev_groups[] = { ++ &pvpanic_dev_group, ++ NULL ++}; ++EXPORT_SYMBOL_GPL(pvpanic_dev_groups); ++ ++int devm_pvpanic_probe(struct device *dev, void __iomem *base) + { +- if (!pi || !pi->base) ++ struct pvpanic_instance *pi; ++ ++ if (!base) + return -EINVAL; + ++ pi = devm_kmalloc(dev, sizeof(*pi), GFP_KERNEL); ++ if (!pi) ++ return -ENOMEM; ++ ++ pi->base = base; ++ pi->capability = PVPANIC_PANICKED | PVPANIC_CRASH_LOADED; ++ ++ /* initlize capability by RDPT */ ++ pi->capability &= ioread8(base); ++ pi->events = pi->capability; ++ + spin_lock(&pvpanic_lock); + list_add(&pi->list, &pvpanic_list); + spin_unlock(&pvpanic_lock); +diff --git a/drivers/misc/pvpanic/pvpanic.h b/drivers/misc/pvpanic/pvpanic.h +index 4935459517548..46ffb10438adf 100644 +--- a/drivers/misc/pvpanic/pvpanic.h ++++ b/drivers/misc/pvpanic/pvpanic.h +@@ -8,13 +8,7 @@ + #ifndef PVPANIC_H_ + #define PVPANIC_H_ + +-struct pvpanic_instance { +- void __iomem *base; +- unsigned int capability; +- unsigned int events; +- struct list_head list; +-}; +- +-int devm_pvpanic_probe(struct device *dev, struct pvpanic_instance *pi); ++int devm_pvpanic_probe(struct device *dev, void __iomem *base); ++extern const struct attribute_group *pvpanic_dev_groups[]; + + #endif /* PVPANIC_H_ */ +diff --git a/drivers/misc/vmw_vmci/vmci_guest.c b/drivers/misc/vmw_vmci/vmci_guest.c +index 4f8d962bb5b2a..1300ccab3d21b 100644 +--- a/drivers/misc/vmw_vmci/vmci_guest.c ++++ b/drivers/misc/vmw_vmci/vmci_guest.c +@@ -625,7 +625,8 @@ static int vmci_guest_probe_device(struct pci_dev *pdev, + if (!vmci_dev) { + dev_err(&pdev->dev, + "Can't allocate memory for VMCI device\n"); +- return -ENOMEM; ++ error = -ENOMEM; ++ goto err_unmap_mmio_base; + } + + vmci_dev->dev = &pdev->dev; +@@ -642,7 +643,8 @@ static int vmci_guest_probe_device(struct pci_dev *pdev, + if (!vmci_dev->tx_buffer) { + dev_err(&pdev->dev, + "Can't allocate memory for datagram tx buffer\n"); +- return -ENOMEM; ++ error = -ENOMEM; ++ goto err_unmap_mmio_base; + } + + vmci_dev->data_buffer = dma_alloc_coherent(&pdev->dev, VMCI_DMA_DG_BUFFER_SIZE, +@@ -893,6 +895,10 @@ static int vmci_guest_probe_device(struct pci_dev *pdev, + err_free_data_buffers: + vmci_free_dg_buffers(vmci_dev); + ++err_unmap_mmio_base: ++ if (mmio_base != NULL) ++ pci_iounmap(pdev, mmio_base); ++ + /* The rest are managed resources and will be freed by PCI core */ + return error; + } +diff --git a/drivers/mmc/host/sdhci_am654.c b/drivers/mmc/host/sdhci_am654.c +index 967bd2dfcda1b..562034af653eb 100644 +--- a/drivers/mmc/host/sdhci_am654.c ++++ b/drivers/mmc/host/sdhci_am654.c +@@ -141,19 +141,26 @@ static const struct timing_data td[] = { + + struct sdhci_am654_data { + struct regmap *base; +- bool legacy_otapdly; + int otap_del_sel[ARRAY_SIZE(td)]; + int itap_del_sel[ARRAY_SIZE(td)]; ++ u32 itap_del_ena[ARRAY_SIZE(td)]; + int clkbuf_sel; + int trm_icp; + int drv_strength; + int strb_sel; + u32 flags; + u32 quirks; ++ bool dll_enable; + + #define SDHCI_AM654_QUIRK_FORCE_CDTEST BIT(0) + }; + ++struct window { ++ u8 start; ++ u8 end; ++ u8 length; ++}; ++ + struct sdhci_am654_driver_data { + const struct sdhci_pltfm_data *pdata; + u32 flags; +@@ -233,11 +240,13 @@ static void sdhci_am654_setup_dll(struct sdhci_host *host, unsigned int clock) + } + + static void sdhci_am654_write_itapdly(struct sdhci_am654_data *sdhci_am654, +- u32 itapdly) ++ u32 itapdly, u32 enable) + { + /* Set ITAPCHGWIN before writing to ITAPDLY */ + regmap_update_bits(sdhci_am654->base, PHY_CTRL4, ITAPCHGWIN_MASK, + 1 << ITAPCHGWIN_SHIFT); ++ regmap_update_bits(sdhci_am654->base, PHY_CTRL4, ITAPDLYENA_MASK, ++ enable << ITAPDLYENA_SHIFT); + regmap_update_bits(sdhci_am654->base, PHY_CTRL4, ITAPDLYSEL_MASK, + itapdly << ITAPDLYSEL_SHIFT); + regmap_update_bits(sdhci_am654->base, PHY_CTRL4, ITAPCHGWIN_MASK, 0); +@@ -254,8 +263,8 @@ static void sdhci_am654_setup_delay_chain(struct sdhci_am654_data *sdhci_am654, + mask = SELDLYTXCLK_MASK | SELDLYRXCLK_MASK; + regmap_update_bits(sdhci_am654->base, PHY_CTRL5, mask, val); + +- sdhci_am654_write_itapdly(sdhci_am654, +- sdhci_am654->itap_del_sel[timing]); ++ sdhci_am654_write_itapdly(sdhci_am654, sdhci_am654->itap_del_sel[timing], ++ sdhci_am654->itap_del_ena[timing]); + } + + static void sdhci_am654_set_clock(struct sdhci_host *host, unsigned int clock) +@@ -264,7 +273,6 @@ static void sdhci_am654_set_clock(struct sdhci_host *host, unsigned int clock) + struct sdhci_am654_data *sdhci_am654 = sdhci_pltfm_priv(pltfm_host); + unsigned char timing = host->mmc->ios.timing; + u32 otap_del_sel; +- u32 otap_del_ena; + u32 mask, val; + + regmap_update_bits(sdhci_am654->base, PHY_CTRL1, ENDLL_MASK, 0); +@@ -272,15 +280,10 @@ static void sdhci_am654_set_clock(struct sdhci_host *host, unsigned int clock) + sdhci_set_clock(host, clock); + + /* Setup DLL Output TAP delay */ +- if (sdhci_am654->legacy_otapdly) +- otap_del_sel = sdhci_am654->otap_del_sel[0]; +- else +- otap_del_sel = sdhci_am654->otap_del_sel[timing]; +- +- otap_del_ena = (timing > MMC_TIMING_UHS_SDR25) ? 1 : 0; ++ otap_del_sel = sdhci_am654->otap_del_sel[timing]; + + mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK; +- val = (otap_del_ena << OTAPDLYENA_SHIFT) | ++ val = (0x1 << OTAPDLYENA_SHIFT) | + (otap_del_sel << OTAPDLYSEL_SHIFT); + + /* Write to STRBSEL for HS400 speed mode */ +@@ -295,10 +298,21 @@ static void sdhci_am654_set_clock(struct sdhci_host *host, unsigned int clock) + + regmap_update_bits(sdhci_am654->base, PHY_CTRL4, mask, val); + +- if (timing > MMC_TIMING_UHS_SDR25 && clock >= CLOCK_TOO_SLOW_HZ) ++ if (timing > MMC_TIMING_UHS_SDR25 && clock >= CLOCK_TOO_SLOW_HZ) { + sdhci_am654_setup_dll(host, clock); +- else ++ sdhci_am654->dll_enable = true; ++ ++ if (timing == MMC_TIMING_MMC_HS400) { ++ sdhci_am654->itap_del_ena[timing] = 0x1; ++ sdhci_am654->itap_del_sel[timing] = sdhci_am654->itap_del_sel[timing - 1]; ++ } ++ ++ sdhci_am654_write_itapdly(sdhci_am654, sdhci_am654->itap_del_sel[timing], ++ sdhci_am654->itap_del_ena[timing]); ++ } else { + sdhci_am654_setup_delay_chain(sdhci_am654, timing); ++ sdhci_am654->dll_enable = false; ++ } + + regmap_update_bits(sdhci_am654->base, PHY_CTRL5, CLKBUFSEL_MASK, + sdhci_am654->clkbuf_sel); +@@ -311,19 +325,29 @@ static void sdhci_j721e_4bit_set_clock(struct sdhci_host *host, + struct sdhci_am654_data *sdhci_am654 = sdhci_pltfm_priv(pltfm_host); + unsigned char timing = host->mmc->ios.timing; + u32 otap_del_sel; ++ u32 itap_del_ena; ++ u32 itap_del_sel; + u32 mask, val; + + /* Setup DLL Output TAP delay */ +- if (sdhci_am654->legacy_otapdly) +- otap_del_sel = sdhci_am654->otap_del_sel[0]; +- else +- otap_del_sel = sdhci_am654->otap_del_sel[timing]; ++ otap_del_sel = sdhci_am654->otap_del_sel[timing]; + + mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK; + val = (0x1 << OTAPDLYENA_SHIFT) | + (otap_del_sel << OTAPDLYSEL_SHIFT); +- regmap_update_bits(sdhci_am654->base, PHY_CTRL4, mask, val); + ++ /* Setup Input TAP delay */ ++ itap_del_ena = sdhci_am654->itap_del_ena[timing]; ++ itap_del_sel = sdhci_am654->itap_del_sel[timing]; ++ ++ mask |= ITAPDLYENA_MASK | ITAPDLYSEL_MASK; ++ val |= (itap_del_ena << ITAPDLYENA_SHIFT) | ++ (itap_del_sel << ITAPDLYSEL_SHIFT); ++ ++ regmap_update_bits(sdhci_am654->base, PHY_CTRL4, ITAPCHGWIN_MASK, ++ 1 << ITAPCHGWIN_SHIFT); ++ regmap_update_bits(sdhci_am654->base, PHY_CTRL4, mask, val); ++ regmap_update_bits(sdhci_am654->base, PHY_CTRL4, ITAPCHGWIN_MASK, 0); + regmap_update_bits(sdhci_am654->base, PHY_CTRL5, CLKBUFSEL_MASK, + sdhci_am654->clkbuf_sel); + +@@ -416,40 +440,105 @@ static u32 sdhci_am654_cqhci_irq(struct sdhci_host *host, u32 intmask) + return 0; + } + +-#define ITAP_MAX 32 ++#define ITAPDLY_LENGTH 32 ++#define ITAPDLY_LAST_INDEX (ITAPDLY_LENGTH - 1) ++ ++static u32 sdhci_am654_calculate_itap(struct sdhci_host *host, struct window ++ *fail_window, u8 num_fails, bool circular_buffer) ++{ ++ u8 itap = 0, start_fail = 0, end_fail = 0, pass_length = 0; ++ u8 first_fail_start = 0, last_fail_end = 0; ++ struct device *dev = mmc_dev(host->mmc); ++ struct window pass_window = {0, 0, 0}; ++ int prev_fail_end = -1; ++ u8 i; ++ ++ if (!num_fails) ++ return ITAPDLY_LAST_INDEX >> 1; ++ ++ if (fail_window->length == ITAPDLY_LENGTH) { ++ dev_err(dev, "No passing ITAPDLY, return 0\n"); ++ return 0; ++ } ++ ++ first_fail_start = fail_window->start; ++ last_fail_end = fail_window[num_fails - 1].end; ++ ++ for (i = 0; i < num_fails; i++) { ++ start_fail = fail_window[i].start; ++ end_fail = fail_window[i].end; ++ pass_length = start_fail - (prev_fail_end + 1); ++ ++ if (pass_length > pass_window.length) { ++ pass_window.start = prev_fail_end + 1; ++ pass_window.length = pass_length; ++ } ++ prev_fail_end = end_fail; ++ } ++ ++ if (!circular_buffer) ++ pass_length = ITAPDLY_LAST_INDEX - last_fail_end; ++ else ++ pass_length = ITAPDLY_LAST_INDEX - last_fail_end + first_fail_start; ++ ++ if (pass_length > pass_window.length) { ++ pass_window.start = last_fail_end + 1; ++ pass_window.length = pass_length; ++ } ++ ++ if (!circular_buffer) ++ itap = pass_window.start + (pass_window.length >> 1); ++ else ++ itap = (pass_window.start + (pass_window.length >> 1)) % ITAPDLY_LENGTH; ++ ++ return (itap > ITAPDLY_LAST_INDEX) ? ITAPDLY_LAST_INDEX >> 1 : itap; ++} ++ + static int sdhci_am654_platform_execute_tuning(struct sdhci_host *host, + u32 opcode) + { + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_am654_data *sdhci_am654 = sdhci_pltfm_priv(pltfm_host); +- int cur_val, prev_val = 1, fail_len = 0, pass_window = 0, pass_len; +- u32 itap; ++ unsigned char timing = host->mmc->ios.timing; ++ struct window fail_window[ITAPDLY_LENGTH]; ++ u8 curr_pass, itap; ++ u8 fail_index = 0; ++ u8 prev_pass = 1; ++ ++ memset(fail_window, 0, sizeof(fail_window)); + + /* Enable ITAPDLY */ +- regmap_update_bits(sdhci_am654->base, PHY_CTRL4, ITAPDLYENA_MASK, +- 1 << ITAPDLYENA_SHIFT); ++ sdhci_am654->itap_del_ena[timing] = 0x1; ++ ++ for (itap = 0; itap < ITAPDLY_LENGTH; itap++) { ++ sdhci_am654_write_itapdly(sdhci_am654, itap, sdhci_am654->itap_del_ena[timing]); + +- for (itap = 0; itap < ITAP_MAX; itap++) { +- sdhci_am654_write_itapdly(sdhci_am654, itap); ++ curr_pass = !mmc_send_tuning(host->mmc, opcode, NULL); + +- cur_val = !mmc_send_tuning(host->mmc, opcode, NULL); +- if (cur_val && !prev_val) +- pass_window = itap; ++ if (!curr_pass && prev_pass) ++ fail_window[fail_index].start = itap; ++ ++ if (!curr_pass) { ++ fail_window[fail_index].end = itap; ++ fail_window[fail_index].length++; ++ } + +- if (!cur_val) +- fail_len++; ++ if (curr_pass && !prev_pass) ++ fail_index++; + +- prev_val = cur_val; ++ prev_pass = curr_pass; + } +- /* +- * Having determined the length of the failing window and start of +- * the passing window calculate the length of the passing window and +- * set the final value halfway through it considering the range as a +- * circular buffer +- */ +- pass_len = ITAP_MAX - fail_len; +- itap = (pass_window + (pass_len >> 1)) % ITAP_MAX; +- sdhci_am654_write_itapdly(sdhci_am654, itap); ++ ++ if (fail_window[fail_index].length != 0) ++ fail_index++; ++ ++ itap = sdhci_am654_calculate_itap(host, fail_window, fail_index, ++ sdhci_am654->dll_enable); ++ ++ sdhci_am654_write_itapdly(sdhci_am654, itap, sdhci_am654->itap_del_ena[timing]); ++ ++ /* Save ITAPDLY */ ++ sdhci_am654->itap_del_sel[timing] = itap; + + return 0; + } +@@ -577,32 +666,15 @@ static int sdhci_am654_get_otap_delay(struct sdhci_host *host, + int i; + int ret; + +- ret = device_property_read_u32(dev, td[MMC_TIMING_LEGACY].otap_binding, +- &sdhci_am654->otap_del_sel[MMC_TIMING_LEGACY]); +- if (ret) { +- /* +- * ti,otap-del-sel-legacy is mandatory, look for old binding +- * if not found. +- */ +- ret = device_property_read_u32(dev, "ti,otap-del-sel", +- &sdhci_am654->otap_del_sel[0]); +- if (ret) { +- dev_err(dev, "Couldn't find otap-del-sel\n"); +- +- return ret; +- } +- +- dev_info(dev, "Using legacy binding ti,otap-del-sel\n"); +- sdhci_am654->legacy_otapdly = true; +- +- return 0; +- } +- + for (i = MMC_TIMING_LEGACY; i <= MMC_TIMING_MMC_HS400; i++) { + + ret = device_property_read_u32(dev, td[i].otap_binding, + &sdhci_am654->otap_del_sel[i]); + if (ret) { ++ if (i == MMC_TIMING_LEGACY) { ++ dev_err(dev, "Couldn't find mandatory ti,otap-del-sel-legacy\n"); ++ return ret; ++ } + dev_dbg(dev, "Couldn't find %s\n", + td[i].otap_binding); + /* +@@ -615,9 +687,12 @@ static int sdhci_am654_get_otap_delay(struct sdhci_host *host, + host->mmc->caps2 &= ~td[i].capability; + } + +- if (td[i].itap_binding) +- device_property_read_u32(dev, td[i].itap_binding, +- &sdhci_am654->itap_del_sel[i]); ++ if (td[i].itap_binding) { ++ ret = device_property_read_u32(dev, td[i].itap_binding, ++ &sdhci_am654->itap_del_sel[i]); ++ if (!ret) ++ sdhci_am654->itap_del_ena[i] = 0x1; ++ } + } + + return 0; +diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c +index 5c32208b17a1d..97ca2a897f1d4 100644 +--- a/drivers/mtd/mtdcore.c ++++ b/drivers/mtd/mtdcore.c +@@ -955,8 +955,10 @@ static int mtd_otp_nvmem_add(struct mtd_info *mtd) + + if (mtd->_get_user_prot_info && mtd->_read_user_prot_reg) { + size = mtd_otp_size(mtd, true); +- if (size < 0) +- return size; ++ if (size < 0) { ++ err = size; ++ goto err; ++ } + + if (size > 0) { + nvmem = mtd_otp_nvmem_register(mtd, "user-otp", size, +diff --git a/drivers/mtd/nand/raw/nand_hynix.c b/drivers/mtd/nand/raw/nand_hynix.c +index 39076735a3fbb..9695f07b5eb26 100644 +--- a/drivers/mtd/nand/raw/nand_hynix.c ++++ b/drivers/mtd/nand/raw/nand_hynix.c +@@ -402,7 +402,7 @@ static int hynix_nand_rr_init(struct nand_chip *chip) + if (ret) + pr_warn("failed to initialize read-retry infrastructure"); + +- return 0; ++ return ret; + } + + static void hynix_nand_extract_oobsize(struct nand_chip *chip, +diff --git a/drivers/net/Makefile b/drivers/net/Makefile +index e26f98f897c55..e15939e77122b 100644 +--- a/drivers/net/Makefile ++++ b/drivers/net/Makefile +@@ -48,7 +48,9 @@ obj-$(CONFIG_ARCNET) += arcnet/ + obj-$(CONFIG_DEV_APPLETALK) += appletalk/ + obj-$(CONFIG_CAIF) += caif/ + obj-$(CONFIG_CAN) += can/ +-obj-$(CONFIG_NET_DSA) += dsa/ ++ifdef CONFIG_NET_DSA ++obj-y += dsa/ ++endif + obj-$(CONFIG_ETHERNET) += ethernet/ + obj-$(CONFIG_FDDI) += fddi/ + obj-$(CONFIG_HIPPI) += hippi/ +diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c +index 286e20f340e5c..3c2a2b5290e5b 100644 +--- a/drivers/net/dsa/microchip/ksz_common.c ++++ b/drivers/net/dsa/microchip/ksz_common.c +@@ -2864,7 +2864,7 @@ phy_interface_t ksz_get_xmii(struct ksz_device *dev, int port, bool gbit) + else + interface = PHY_INTERFACE_MODE_MII; + } else if (val == bitval[P_RMII_SEL]) { +- interface = PHY_INTERFACE_MODE_RGMII; ++ interface = PHY_INTERFACE_MODE_RMII; + } else { + interface = PHY_INTERFACE_MODE_RGMII; + if (data8 & P_RGMII_ID_EG_ENABLE) +diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c +index e5bac87941f61..9571e1b1e59ef 100644 +--- a/drivers/net/dsa/mv88e6xxx/chip.c ++++ b/drivers/net/dsa/mv88e6xxx/chip.c +@@ -3021,6 +3021,7 @@ static int mv88e6xxx_software_reset(struct mv88e6xxx_chip *chip) + static void mv88e6xxx_hardware_reset(struct mv88e6xxx_chip *chip) + { + struct gpio_desc *gpiod = chip->reset; ++ int err; + + /* If there is a GPIO connected to the reset pin, toggle it */ + if (gpiod) { +@@ -3029,17 +3030,26 @@ static void mv88e6xxx_hardware_reset(struct mv88e6xxx_chip *chip) + * mid-byte, causing the first EEPROM read after the reset + * from the wrong location resulting in the switch booting + * to wrong mode and inoperable. ++ * For this reason, switch families with EEPROM support ++ * generally wait for EEPROM loads to complete as their pre- ++ * and post-reset handlers. + */ +- if (chip->info->ops->get_eeprom) +- mv88e6xxx_g2_eeprom_wait(chip); ++ if (chip->info->ops->hardware_reset_pre) { ++ err = chip->info->ops->hardware_reset_pre(chip); ++ if (err) ++ dev_err(chip->dev, "pre-reset error: %d\n", err); ++ } + + gpiod_set_value_cansleep(gpiod, 1); + usleep_range(10000, 20000); + gpiod_set_value_cansleep(gpiod, 0); + usleep_range(10000, 20000); + +- if (chip->info->ops->get_eeprom) +- mv88e6xxx_g2_eeprom_wait(chip); ++ if (chip->info->ops->hardware_reset_post) { ++ err = chip->info->ops->hardware_reset_post(chip); ++ if (err) ++ dev_err(chip->dev, "post-reset error: %d\n", err); ++ } + } + } + +@@ -4266,6 +4276,8 @@ static const struct mv88e6xxx_ops mv88e6141_ops = { + .watchdog_ops = &mv88e6390_watchdog_ops, + .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, + .pot_clear = mv88e6xxx_g2_pot_clear, ++ .hardware_reset_pre = mv88e6xxx_g2_eeprom_wait, ++ .hardware_reset_post = mv88e6xxx_g2_eeprom_wait, + .reset = mv88e6352_g1_reset, + .rmu_disable = mv88e6390_g1_rmu_disable, + .atu_get_hash = mv88e6165_g1_atu_get_hash, +@@ -4456,6 +4468,8 @@ static const struct mv88e6xxx_ops mv88e6172_ops = { + .watchdog_ops = &mv88e6097_watchdog_ops, + .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, + .pot_clear = mv88e6xxx_g2_pot_clear, ++ .hardware_reset_pre = mv88e6xxx_g2_eeprom_wait, ++ .hardware_reset_post = mv88e6xxx_g2_eeprom_wait, + .reset = mv88e6352_g1_reset, + .rmu_disable = mv88e6352_g1_rmu_disable, + .atu_get_hash = mv88e6165_g1_atu_get_hash, +@@ -4556,6 +4570,8 @@ static const struct mv88e6xxx_ops mv88e6176_ops = { + .watchdog_ops = &mv88e6097_watchdog_ops, + .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, + .pot_clear = mv88e6xxx_g2_pot_clear, ++ .hardware_reset_pre = mv88e6xxx_g2_eeprom_wait, ++ .hardware_reset_post = mv88e6xxx_g2_eeprom_wait, + .reset = mv88e6352_g1_reset, + .rmu_disable = mv88e6352_g1_rmu_disable, + .atu_get_hash = mv88e6165_g1_atu_get_hash, +@@ -4650,6 +4666,8 @@ static const struct mv88e6xxx_ops mv88e6190_ops = { + .watchdog_ops = &mv88e6390_watchdog_ops, + .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, + .pot_clear = mv88e6xxx_g2_pot_clear, ++ .hardware_reset_pre = mv88e6xxx_g2_eeprom_wait, ++ .hardware_reset_post = mv88e6xxx_g2_eeprom_wait, + .reset = mv88e6352_g1_reset, + .rmu_disable = mv88e6390_g1_rmu_disable, + .atu_get_hash = mv88e6165_g1_atu_get_hash, +@@ -4708,6 +4726,8 @@ static const struct mv88e6xxx_ops mv88e6190x_ops = { + .watchdog_ops = &mv88e6390_watchdog_ops, + .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, + .pot_clear = mv88e6xxx_g2_pot_clear, ++ .hardware_reset_pre = mv88e6xxx_g2_eeprom_wait, ++ .hardware_reset_post = mv88e6xxx_g2_eeprom_wait, + .reset = mv88e6352_g1_reset, + .rmu_disable = mv88e6390_g1_rmu_disable, + .atu_get_hash = mv88e6165_g1_atu_get_hash, +@@ -4764,6 +4784,8 @@ static const struct mv88e6xxx_ops mv88e6191_ops = { + .watchdog_ops = &mv88e6390_watchdog_ops, + .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, + .pot_clear = mv88e6xxx_g2_pot_clear, ++ .hardware_reset_pre = mv88e6xxx_g2_eeprom_wait, ++ .hardware_reset_post = mv88e6xxx_g2_eeprom_wait, + .reset = mv88e6352_g1_reset, + .rmu_disable = mv88e6390_g1_rmu_disable, + .atu_get_hash = mv88e6165_g1_atu_get_hash, +@@ -4823,6 +4845,8 @@ static const struct mv88e6xxx_ops mv88e6240_ops = { + .watchdog_ops = &mv88e6097_watchdog_ops, + .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, + .pot_clear = mv88e6xxx_g2_pot_clear, ++ .hardware_reset_pre = mv88e6xxx_g2_eeprom_wait, ++ .hardware_reset_post = mv88e6xxx_g2_eeprom_wait, + .reset = mv88e6352_g1_reset, + .rmu_disable = mv88e6352_g1_rmu_disable, + .atu_get_hash = mv88e6165_g1_atu_get_hash, +@@ -4876,6 +4900,8 @@ static const struct mv88e6xxx_ops mv88e6250_ops = { + .watchdog_ops = &mv88e6250_watchdog_ops, + .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, + .pot_clear = mv88e6xxx_g2_pot_clear, ++ .hardware_reset_pre = mv88e6250_g1_wait_eeprom_done_prereset, ++ .hardware_reset_post = mv88e6xxx_g1_wait_eeprom_done, + .reset = mv88e6250_g1_reset, + .vtu_getnext = mv88e6185_g1_vtu_getnext, + .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge, +@@ -4923,6 +4949,8 @@ static const struct mv88e6xxx_ops mv88e6290_ops = { + .watchdog_ops = &mv88e6390_watchdog_ops, + .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, + .pot_clear = mv88e6xxx_g2_pot_clear, ++ .hardware_reset_pre = mv88e6xxx_g2_eeprom_wait, ++ .hardware_reset_post = mv88e6xxx_g2_eeprom_wait, + .reset = mv88e6352_g1_reset, + .rmu_disable = mv88e6390_g1_rmu_disable, + .atu_get_hash = mv88e6165_g1_atu_get_hash, +@@ -4982,6 +5010,8 @@ static const struct mv88e6xxx_ops mv88e6320_ops = { + .watchdog_ops = &mv88e6390_watchdog_ops, + .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, + .pot_clear = mv88e6xxx_g2_pot_clear, ++ .hardware_reset_pre = mv88e6xxx_g2_eeprom_wait, ++ .hardware_reset_post = mv88e6xxx_g2_eeprom_wait, + .reset = mv88e6352_g1_reset, + .vtu_getnext = mv88e6185_g1_vtu_getnext, + .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge, +@@ -5028,6 +5058,8 @@ static const struct mv88e6xxx_ops mv88e6321_ops = { + .set_egress_port = mv88e6095_g1_set_egress_port, + .watchdog_ops = &mv88e6390_watchdog_ops, + .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, ++ .hardware_reset_pre = mv88e6xxx_g2_eeprom_wait, ++ .hardware_reset_post = mv88e6xxx_g2_eeprom_wait, + .reset = mv88e6352_g1_reset, + .vtu_getnext = mv88e6185_g1_vtu_getnext, + .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge, +@@ -5078,6 +5110,8 @@ static const struct mv88e6xxx_ops mv88e6341_ops = { + .watchdog_ops = &mv88e6390_watchdog_ops, + .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, + .pot_clear = mv88e6xxx_g2_pot_clear, ++ .hardware_reset_pre = mv88e6xxx_g2_eeprom_wait, ++ .hardware_reset_post = mv88e6xxx_g2_eeprom_wait, + .reset = mv88e6352_g1_reset, + .rmu_disable = mv88e6390_g1_rmu_disable, + .atu_get_hash = mv88e6165_g1_atu_get_hash, +@@ -5233,6 +5267,8 @@ static const struct mv88e6xxx_ops mv88e6352_ops = { + .watchdog_ops = &mv88e6097_watchdog_ops, + .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, + .pot_clear = mv88e6xxx_g2_pot_clear, ++ .hardware_reset_pre = mv88e6xxx_g2_eeprom_wait, ++ .hardware_reset_post = mv88e6xxx_g2_eeprom_wait, + .reset = mv88e6352_g1_reset, + .rmu_disable = mv88e6352_g1_rmu_disable, + .atu_get_hash = mv88e6165_g1_atu_get_hash, +@@ -5295,6 +5331,8 @@ static const struct mv88e6xxx_ops mv88e6390_ops = { + .watchdog_ops = &mv88e6390_watchdog_ops, + .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, + .pot_clear = mv88e6xxx_g2_pot_clear, ++ .hardware_reset_pre = mv88e6xxx_g2_eeprom_wait, ++ .hardware_reset_post = mv88e6xxx_g2_eeprom_wait, + .reset = mv88e6352_g1_reset, + .rmu_disable = mv88e6390_g1_rmu_disable, + .atu_get_hash = mv88e6165_g1_atu_get_hash, +@@ -5357,6 +5395,8 @@ static const struct mv88e6xxx_ops mv88e6390x_ops = { + .watchdog_ops = &mv88e6390_watchdog_ops, + .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, + .pot_clear = mv88e6xxx_g2_pot_clear, ++ .hardware_reset_pre = mv88e6xxx_g2_eeprom_wait, ++ .hardware_reset_post = mv88e6xxx_g2_eeprom_wait, + .reset = mv88e6352_g1_reset, + .rmu_disable = mv88e6390_g1_rmu_disable, + .atu_get_hash = mv88e6165_g1_atu_get_hash, +@@ -5422,6 +5462,8 @@ static const struct mv88e6xxx_ops mv88e6393x_ops = { + .watchdog_ops = &mv88e6393x_watchdog_ops, + .mgmt_rsvd2cpu = mv88e6393x_port_mgmt_rsvd2cpu, + .pot_clear = mv88e6xxx_g2_pot_clear, ++ .hardware_reset_pre = mv88e6xxx_g2_eeprom_wait, ++ .hardware_reset_post = mv88e6xxx_g2_eeprom_wait, + .reset = mv88e6352_g1_reset, + .rmu_disable = mv88e6390_g1_rmu_disable, + .atu_get_hash = mv88e6165_g1_atu_get_hash, +diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h +index c54d305a1d831..f48a3c0ac7f96 100644 +--- a/drivers/net/dsa/mv88e6xxx/chip.h ++++ b/drivers/net/dsa/mv88e6xxx/chip.h +@@ -476,6 +476,12 @@ struct mv88e6xxx_ops { + int (*ppu_enable)(struct mv88e6xxx_chip *chip); + int (*ppu_disable)(struct mv88e6xxx_chip *chip); + ++ /* Additional handlers to run before and after hard reset, to make sure ++ * that the switch and EEPROM are in a good state. ++ */ ++ int (*hardware_reset_pre)(struct mv88e6xxx_chip *chip); ++ int (*hardware_reset_post)(struct mv88e6xxx_chip *chip); ++ + /* Switch Software Reset */ + int (*reset)(struct mv88e6xxx_chip *chip); + +diff --git a/drivers/net/dsa/mv88e6xxx/global1.c b/drivers/net/dsa/mv88e6xxx/global1.c +index 174c773b38c2b..7ef0f4426ad71 100644 +--- a/drivers/net/dsa/mv88e6xxx/global1.c ++++ b/drivers/net/dsa/mv88e6xxx/global1.c +@@ -75,6 +75,95 @@ static int mv88e6xxx_g1_wait_init_ready(struct mv88e6xxx_chip *chip) + return mv88e6xxx_g1_wait_bit(chip, MV88E6XXX_G1_STS, bit, 1); + } + ++static int mv88e6250_g1_eeprom_reload(struct mv88e6xxx_chip *chip) ++{ ++ /* MV88E6185_G1_CTL1_RELOAD_EEPROM is also valid for 88E6250 */ ++ int bit = __bf_shf(MV88E6185_G1_CTL1_RELOAD_EEPROM); ++ u16 val; ++ int err; ++ ++ err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, &val); ++ if (err) ++ return err; ++ ++ val |= MV88E6185_G1_CTL1_RELOAD_EEPROM; ++ ++ err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, val); ++ if (err) ++ return err; ++ ++ return mv88e6xxx_g1_wait_bit(chip, MV88E6XXX_G1_CTL1, bit, 0); ++} ++ ++/* Returns 0 when done, -EBUSY when waiting, other negative codes on error */ ++static int mv88e6xxx_g1_is_eeprom_done(struct mv88e6xxx_chip *chip) ++{ ++ u16 val; ++ int err; ++ ++ err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_STS, &val); ++ if (err < 0) { ++ dev_err(chip->dev, "Error reading status"); ++ return err; ++ } ++ ++ /* If the switch is still resetting, it may not ++ * respond on the bus, and so MDIO read returns ++ * 0xffff. Differentiate between that, and waiting for ++ * the EEPROM to be done by bit 0 being set. ++ */ ++ if (val == 0xffff || !(val & BIT(MV88E6XXX_G1_STS_IRQ_EEPROM_DONE))) ++ return -EBUSY; ++ ++ return 0; ++} ++ ++/* As the EEInt (EEPROM done) flag clears on read if the status register, this ++ * function must be called directly after a hard reset or EEPROM ReLoad request, ++ * or the done condition may have been missed ++ */ ++int mv88e6xxx_g1_wait_eeprom_done(struct mv88e6xxx_chip *chip) ++{ ++ const unsigned long timeout = jiffies + 1 * HZ; ++ int ret; ++ ++ /* Wait up to 1 second for the switch to finish reading the ++ * EEPROM. ++ */ ++ while (time_before(jiffies, timeout)) { ++ ret = mv88e6xxx_g1_is_eeprom_done(chip); ++ if (ret != -EBUSY) ++ return ret; ++ } ++ ++ dev_err(chip->dev, "Timeout waiting for EEPROM done"); ++ return -ETIMEDOUT; ++} ++ ++int mv88e6250_g1_wait_eeprom_done_prereset(struct mv88e6xxx_chip *chip) ++{ ++ int ret; ++ ++ ret = mv88e6xxx_g1_is_eeprom_done(chip); ++ if (ret != -EBUSY) ++ return ret; ++ ++ /* Pre-reset, we don't know the state of the switch - when ++ * mv88e6xxx_g1_is_eeprom_done() returns -EBUSY, that may be because ++ * the switch is actually busy reading the EEPROM, or because ++ * MV88E6XXX_G1_STS_IRQ_EEPROM_DONE has been cleared by an unrelated ++ * status register read already. ++ * ++ * To account for the latter case, trigger another EEPROM reload for ++ * another chance at seeing the done flag. ++ */ ++ ret = mv88e6250_g1_eeprom_reload(chip); ++ if (ret) ++ return ret; ++ ++ return mv88e6xxx_g1_wait_eeprom_done(chip); ++} ++ + /* Offset 0x01: Switch MAC Address Register Bytes 0 & 1 + * Offset 0x02: Switch MAC Address Register Bytes 2 & 3 + * Offset 0x03: Switch MAC Address Register Bytes 4 & 5 +diff --git a/drivers/net/dsa/mv88e6xxx/global1.h b/drivers/net/dsa/mv88e6xxx/global1.h +index 1095261f5b490..3dbb7a1b8fe11 100644 +--- a/drivers/net/dsa/mv88e6xxx/global1.h ++++ b/drivers/net/dsa/mv88e6xxx/global1.h +@@ -282,6 +282,8 @@ int mv88e6xxx_g1_set_switch_mac(struct mv88e6xxx_chip *chip, u8 *addr); + int mv88e6185_g1_reset(struct mv88e6xxx_chip *chip); + int mv88e6352_g1_reset(struct mv88e6xxx_chip *chip); + int mv88e6250_g1_reset(struct mv88e6xxx_chip *chip); ++int mv88e6xxx_g1_wait_eeprom_done(struct mv88e6xxx_chip *chip); ++int mv88e6250_g1_wait_eeprom_done_prereset(struct mv88e6xxx_chip *chip); + + int mv88e6185_g1_ppu_enable(struct mv88e6xxx_chip *chip); + int mv88e6185_g1_ppu_disable(struct mv88e6xxx_chip *chip); +diff --git a/drivers/net/ethernet/amazon/ena/ena_com.c b/drivers/net/ethernet/amazon/ena/ena_com.c +index 4db689372980e..276f6a8631fb1 100644 +--- a/drivers/net/ethernet/amazon/ena/ena_com.c ++++ b/drivers/net/ethernet/amazon/ena/ena_com.c +@@ -90,8 +90,7 @@ static int ena_com_admin_init_sq(struct ena_com_admin_queue *admin_queue) + struct ena_com_admin_sq *sq = &admin_queue->sq; + u16 size = ADMIN_SQ_SIZE(admin_queue->q_depth); + +- sq->entries = dma_alloc_coherent(admin_queue->q_dmadev, size, +- &sq->dma_addr, GFP_KERNEL); ++ sq->entries = dma_alloc_coherent(admin_queue->q_dmadev, size, &sq->dma_addr, GFP_KERNEL); + + if (!sq->entries) { + netdev_err(ena_dev->net_device, "Memory allocation failed\n"); +@@ -113,8 +112,7 @@ static int ena_com_admin_init_cq(struct ena_com_admin_queue *admin_queue) + struct ena_com_admin_cq *cq = &admin_queue->cq; + u16 size = ADMIN_CQ_SIZE(admin_queue->q_depth); + +- cq->entries = dma_alloc_coherent(admin_queue->q_dmadev, size, +- &cq->dma_addr, GFP_KERNEL); ++ cq->entries = dma_alloc_coherent(admin_queue->q_dmadev, size, &cq->dma_addr, GFP_KERNEL); + + if (!cq->entries) { + netdev_err(ena_dev->net_device, "Memory allocation failed\n"); +@@ -136,8 +134,7 @@ static int ena_com_admin_init_aenq(struct ena_com_dev *ena_dev, + + ena_dev->aenq.q_depth = ENA_ASYNC_QUEUE_DEPTH; + size = ADMIN_AENQ_SIZE(ENA_ASYNC_QUEUE_DEPTH); +- aenq->entries = dma_alloc_coherent(ena_dev->dmadev, size, +- &aenq->dma_addr, GFP_KERNEL); ++ aenq->entries = dma_alloc_coherent(ena_dev->dmadev, size, &aenq->dma_addr, GFP_KERNEL); + + if (!aenq->entries) { + netdev_err(ena_dev->net_device, "Memory allocation failed\n"); +@@ -155,14 +152,13 @@ static int ena_com_admin_init_aenq(struct ena_com_dev *ena_dev, + + aenq_caps = 0; + aenq_caps |= ena_dev->aenq.q_depth & ENA_REGS_AENQ_CAPS_AENQ_DEPTH_MASK; +- aenq_caps |= (sizeof(struct ena_admin_aenq_entry) +- << ENA_REGS_AENQ_CAPS_AENQ_ENTRY_SIZE_SHIFT) & +- ENA_REGS_AENQ_CAPS_AENQ_ENTRY_SIZE_MASK; ++ aenq_caps |= ++ (sizeof(struct ena_admin_aenq_entry) << ENA_REGS_AENQ_CAPS_AENQ_ENTRY_SIZE_SHIFT) & ++ ENA_REGS_AENQ_CAPS_AENQ_ENTRY_SIZE_MASK; + writel(aenq_caps, ena_dev->reg_bar + ENA_REGS_AENQ_CAPS_OFF); + + if (unlikely(!aenq_handlers)) { +- netdev_err(ena_dev->net_device, +- "AENQ handlers pointer is NULL\n"); ++ netdev_err(ena_dev->net_device, "AENQ handlers pointer is NULL\n"); + return -EINVAL; + } + +@@ -189,14 +185,12 @@ static struct ena_comp_ctx *get_comp_ctxt(struct ena_com_admin_queue *admin_queu + } + + if (unlikely(!admin_queue->comp_ctx)) { +- netdev_err(admin_queue->ena_dev->net_device, +- "Completion context is NULL\n"); ++ netdev_err(admin_queue->ena_dev->net_device, "Completion context is NULL\n"); + return NULL; + } + + if (unlikely(admin_queue->comp_ctx[command_id].occupied && capture)) { +- netdev_err(admin_queue->ena_dev->net_device, +- "Completion context is occupied\n"); ++ netdev_err(admin_queue->ena_dev->net_device, "Completion context is occupied\n"); + return NULL; + } + +@@ -226,8 +220,7 @@ static struct ena_comp_ctx *__ena_com_submit_admin_cmd(struct ena_com_admin_queu + /* In case of queue FULL */ + cnt = (u16)atomic_read(&admin_queue->outstanding_cmds); + if (cnt >= admin_queue->q_depth) { +- netdev_dbg(admin_queue->ena_dev->net_device, +- "Admin queue is full.\n"); ++ netdev_dbg(admin_queue->ena_dev->net_device, "Admin queue is full.\n"); + admin_queue->stats.out_of_space++; + return ERR_PTR(-ENOSPC); + } +@@ -274,8 +267,7 @@ static int ena_com_init_comp_ctxt(struct ena_com_admin_queue *admin_queue) + struct ena_comp_ctx *comp_ctx; + u16 i; + +- admin_queue->comp_ctx = +- devm_kzalloc(admin_queue->q_dmadev, size, GFP_KERNEL); ++ admin_queue->comp_ctx = devm_kzalloc(admin_queue->q_dmadev, size, GFP_KERNEL); + if (unlikely(!admin_queue->comp_ctx)) { + netdev_err(ena_dev->net_device, "Memory allocation failed\n"); + return -ENOMEM; +@@ -320,7 +312,6 @@ static int ena_com_init_io_sq(struct ena_com_dev *ena_dev, + struct ena_com_io_sq *io_sq) + { + size_t size; +- int dev_node = 0; + + memset(&io_sq->desc_addr, 0x0, sizeof(io_sq->desc_addr)); + +@@ -333,23 +324,17 @@ static int ena_com_init_io_sq(struct ena_com_dev *ena_dev, + size = io_sq->desc_entry_size * io_sq->q_depth; + + if (io_sq->mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_HOST) { +- dev_node = dev_to_node(ena_dev->dmadev); +- set_dev_node(ena_dev->dmadev, ctx->numa_node); + io_sq->desc_addr.virt_addr = +- dma_alloc_coherent(ena_dev->dmadev, size, +- &io_sq->desc_addr.phys_addr, ++ dma_alloc_coherent(ena_dev->dmadev, size, &io_sq->desc_addr.phys_addr, + GFP_KERNEL); +- set_dev_node(ena_dev->dmadev, dev_node); + if (!io_sq->desc_addr.virt_addr) { + io_sq->desc_addr.virt_addr = + dma_alloc_coherent(ena_dev->dmadev, size, +- &io_sq->desc_addr.phys_addr, +- GFP_KERNEL); ++ &io_sq->desc_addr.phys_addr, GFP_KERNEL); + } + + if (!io_sq->desc_addr.virt_addr) { +- netdev_err(ena_dev->net_device, +- "Memory allocation failed\n"); ++ netdev_err(ena_dev->net_device, "Memory allocation failed\n"); + return -ENOMEM; + } + } +@@ -365,18 +350,13 @@ static int ena_com_init_io_sq(struct ena_com_dev *ena_dev, + size = (size_t)io_sq->bounce_buf_ctrl.buffer_size * + io_sq->bounce_buf_ctrl.buffers_num; + +- dev_node = dev_to_node(ena_dev->dmadev); +- set_dev_node(ena_dev->dmadev, ctx->numa_node); +- io_sq->bounce_buf_ctrl.base_buffer = +- devm_kzalloc(ena_dev->dmadev, size, GFP_KERNEL); +- set_dev_node(ena_dev->dmadev, dev_node); ++ io_sq->bounce_buf_ctrl.base_buffer = devm_kzalloc(ena_dev->dmadev, size, GFP_KERNEL); + if (!io_sq->bounce_buf_ctrl.base_buffer) + io_sq->bounce_buf_ctrl.base_buffer = + devm_kzalloc(ena_dev->dmadev, size, GFP_KERNEL); + + if (!io_sq->bounce_buf_ctrl.base_buffer) { +- netdev_err(ena_dev->net_device, +- "Bounce buffer memory allocation failed\n"); ++ netdev_err(ena_dev->net_device, "Bounce buffer memory allocation failed\n"); + return -ENOMEM; + } + +@@ -410,7 +390,6 @@ static int ena_com_init_io_cq(struct ena_com_dev *ena_dev, + struct ena_com_io_cq *io_cq) + { + size_t size; +- int prev_node = 0; + + memset(&io_cq->cdesc_addr, 0x0, sizeof(io_cq->cdesc_addr)); + +@@ -422,16 +401,11 @@ static int ena_com_init_io_cq(struct ena_com_dev *ena_dev, + + size = io_cq->cdesc_entry_size_in_bytes * io_cq->q_depth; + +- prev_node = dev_to_node(ena_dev->dmadev); +- set_dev_node(ena_dev->dmadev, ctx->numa_node); + io_cq->cdesc_addr.virt_addr = +- dma_alloc_coherent(ena_dev->dmadev, size, +- &io_cq->cdesc_addr.phys_addr, GFP_KERNEL); +- set_dev_node(ena_dev->dmadev, prev_node); ++ dma_alloc_coherent(ena_dev->dmadev, size, &io_cq->cdesc_addr.phys_addr, GFP_KERNEL); + if (!io_cq->cdesc_addr.virt_addr) { + io_cq->cdesc_addr.virt_addr = +- dma_alloc_coherent(ena_dev->dmadev, size, +- &io_cq->cdesc_addr.phys_addr, ++ dma_alloc_coherent(ena_dev->dmadev, size, &io_cq->cdesc_addr.phys_addr, + GFP_KERNEL); + } + +@@ -514,8 +488,8 @@ static int ena_com_comp_status_to_errno(struct ena_com_admin_queue *admin_queue, + u8 comp_status) + { + if (unlikely(comp_status != 0)) +- netdev_err(admin_queue->ena_dev->net_device, +- "Admin command failed[%u]\n", comp_status); ++ netdev_err(admin_queue->ena_dev->net_device, "Admin command failed[%u]\n", ++ comp_status); + + switch (comp_status) { + case ENA_ADMIN_SUCCESS: +@@ -580,8 +554,7 @@ static int ena_com_wait_and_process_admin_cq_polling(struct ena_comp_ctx *comp_c + } + + if (unlikely(comp_ctx->status == ENA_CMD_ABORTED)) { +- netdev_err(admin_queue->ena_dev->net_device, +- "Command was aborted\n"); ++ netdev_err(admin_queue->ena_dev->net_device, "Command was aborted\n"); + spin_lock_irqsave(&admin_queue->q_lock, flags); + admin_queue->stats.aborted_cmd++; + spin_unlock_irqrestore(&admin_queue->q_lock, flags); +@@ -589,8 +562,7 @@ static int ena_com_wait_and_process_admin_cq_polling(struct ena_comp_ctx *comp_c + goto err; + } + +- WARN(comp_ctx->status != ENA_CMD_COMPLETED, "Invalid comp status %d\n", +- comp_ctx->status); ++ WARN(comp_ctx->status != ENA_CMD_COMPLETED, "Invalid comp status %d\n", comp_ctx->status); + + ret = ena_com_comp_status_to_errno(admin_queue, comp_ctx->comp_status); + err: +@@ -634,8 +606,7 @@ static int ena_com_set_llq(struct ena_com_dev *ena_dev) + sizeof(resp)); + + if (unlikely(ret)) +- netdev_err(ena_dev->net_device, +- "Failed to set LLQ configurations: %d\n", ret); ++ netdev_err(ena_dev->net_device, "Failed to set LLQ configurations: %d\n", ret); + + return ret; + } +@@ -658,8 +629,7 @@ static int ena_com_config_llq_info(struct ena_com_dev *ena_dev, + llq_default_cfg->llq_header_location; + } else { + netdev_err(ena_dev->net_device, +- "Invalid header location control, supported: 0x%x\n", +- supported_feat); ++ "Invalid header location control, supported: 0x%x\n", supported_feat); + return -EINVAL; + } + +@@ -681,8 +651,8 @@ static int ena_com_config_llq_info(struct ena_com_dev *ena_dev, + + netdev_err(ena_dev->net_device, + "Default llq stride ctrl is not supported, performing fallback, default: 0x%x, supported: 0x%x, used: 0x%x\n", +- llq_default_cfg->llq_stride_ctrl, +- supported_feat, llq_info->desc_stride_ctrl); ++ llq_default_cfg->llq_stride_ctrl, supported_feat, ++ llq_info->desc_stride_ctrl); + } + } else { + llq_info->desc_stride_ctrl = 0; +@@ -704,8 +674,7 @@ static int ena_com_config_llq_info(struct ena_com_dev *ena_dev, + llq_info->desc_list_entry_size = 256; + } else { + netdev_err(ena_dev->net_device, +- "Invalid entry_size_ctrl, supported: 0x%x\n", +- supported_feat); ++ "Invalid entry_size_ctrl, supported: 0x%x\n", supported_feat); + return -EINVAL; + } + +@@ -750,8 +719,8 @@ static int ena_com_config_llq_info(struct ena_com_dev *ena_dev, + + netdev_err(ena_dev->net_device, + "Default llq num descs before header is not supported, performing fallback, default: 0x%x, supported: 0x%x, used: 0x%x\n", +- llq_default_cfg->llq_num_decs_before_header, +- supported_feat, llq_info->descs_num_before_header); ++ llq_default_cfg->llq_num_decs_before_header, supported_feat, ++ llq_info->descs_num_before_header); + } + /* Check for accelerated queue supported */ + llq_accel_mode_get = llq_features->accel_mode.u.get; +@@ -767,8 +736,7 @@ static int ena_com_config_llq_info(struct ena_com_dev *ena_dev, + + rc = ena_com_set_llq(ena_dev); + if (rc) +- netdev_err(ena_dev->net_device, +- "Cannot set LLQ configuration: %d\n", rc); ++ netdev_err(ena_dev->net_device, "Cannot set LLQ configuration: %d\n", rc); + + return rc; + } +@@ -780,8 +748,7 @@ static int ena_com_wait_and_process_admin_cq_interrupts(struct ena_comp_ctx *com + int ret; + + wait_for_completion_timeout(&comp_ctx->wait_event, +- usecs_to_jiffies( +- admin_queue->completion_timeout)); ++ usecs_to_jiffies(admin_queue->completion_timeout)); + + /* In case the command wasn't completed find out the root cause. + * There might be 2 kinds of errors +@@ -797,8 +764,7 @@ static int ena_com_wait_and_process_admin_cq_interrupts(struct ena_comp_ctx *com + if (comp_ctx->status == ENA_CMD_COMPLETED) { + netdev_err(admin_queue->ena_dev->net_device, + "The ena device sent a completion but the driver didn't receive a MSI-X interrupt (cmd %d), autopolling mode is %s\n", +- comp_ctx->cmd_opcode, +- admin_queue->auto_polling ? "ON" : "OFF"); ++ comp_ctx->cmd_opcode, admin_queue->auto_polling ? "ON" : "OFF"); + /* Check if fallback to polling is enabled */ + if (admin_queue->auto_polling) + admin_queue->polling = true; +@@ -867,15 +833,13 @@ static u32 ena_com_reg_bar_read32(struct ena_com_dev *ena_dev, u16 offset) + if (unlikely(i == timeout)) { + netdev_err(ena_dev->net_device, + "Reading reg failed for timeout. expected: req id[%u] offset[%u] actual: req id[%u] offset[%u]\n", +- mmio_read->seq_num, offset, read_resp->req_id, +- read_resp->reg_off); ++ mmio_read->seq_num, offset, read_resp->req_id, read_resp->reg_off); + ret = ENA_MMIO_READ_TIMEOUT; + goto err; + } + + if (read_resp->reg_off != offset) { +- netdev_err(ena_dev->net_device, +- "Read failure: wrong offset provided\n"); ++ netdev_err(ena_dev->net_device, "Read failure: wrong offset provided\n"); + ret = ENA_MMIO_READ_TIMEOUT; + } else { + ret = read_resp->reg_val; +@@ -934,8 +898,7 @@ static int ena_com_destroy_io_sq(struct ena_com_dev *ena_dev, + sizeof(destroy_resp)); + + if (unlikely(ret && (ret != -ENODEV))) +- netdev_err(ena_dev->net_device, +- "Failed to destroy io sq error: %d\n", ret); ++ netdev_err(ena_dev->net_device, "Failed to destroy io sq error: %d\n", ret); + + return ret; + } +@@ -949,8 +912,7 @@ static void ena_com_io_queue_free(struct ena_com_dev *ena_dev, + if (io_cq->cdesc_addr.virt_addr) { + size = io_cq->cdesc_entry_size_in_bytes * io_cq->q_depth; + +- dma_free_coherent(ena_dev->dmadev, size, +- io_cq->cdesc_addr.virt_addr, ++ dma_free_coherent(ena_dev->dmadev, size, io_cq->cdesc_addr.virt_addr, + io_cq->cdesc_addr.phys_addr); + + io_cq->cdesc_addr.virt_addr = NULL; +@@ -959,8 +921,7 @@ static void ena_com_io_queue_free(struct ena_com_dev *ena_dev, + if (io_sq->desc_addr.virt_addr) { + size = io_sq->desc_entry_size * io_sq->q_depth; + +- dma_free_coherent(ena_dev->dmadev, size, +- io_sq->desc_addr.virt_addr, ++ dma_free_coherent(ena_dev->dmadev, size, io_sq->desc_addr.virt_addr, + io_sq->desc_addr.phys_addr); + + io_sq->desc_addr.virt_addr = NULL; +@@ -985,8 +946,7 @@ static int wait_for_reset_state(struct ena_com_dev *ena_dev, u32 timeout, + val = ena_com_reg_bar_read32(ena_dev, ENA_REGS_DEV_STS_OFF); + + if (unlikely(val == ENA_MMIO_READ_TIMEOUT)) { +- netdev_err(ena_dev->net_device, +- "Reg read timeout occurred\n"); ++ netdev_err(ena_dev->net_device, "Reg read timeout occurred\n"); + return -ETIME; + } + +@@ -1026,8 +986,7 @@ static int ena_com_get_feature_ex(struct ena_com_dev *ena_dev, + int ret; + + if (!ena_com_check_supported_feature_id(ena_dev, feature_id)) { +- netdev_dbg(ena_dev->net_device, "Feature %d isn't supported\n", +- feature_id); ++ netdev_dbg(ena_dev->net_device, "Feature %d isn't supported\n", feature_id); + return -EOPNOTSUPP; + } + +@@ -1064,8 +1023,7 @@ static int ena_com_get_feature_ex(struct ena_com_dev *ena_dev, + + if (unlikely(ret)) + netdev_err(ena_dev->net_device, +- "Failed to submit get_feature command %d error: %d\n", +- feature_id, ret); ++ "Failed to submit get_feature command %d error: %d\n", feature_id, ret); + + return ret; + } +@@ -1104,13 +1062,11 @@ static int ena_com_hash_key_allocate(struct ena_com_dev *ena_dev) + { + struct ena_rss *rss = &ena_dev->rss; + +- if (!ena_com_check_supported_feature_id(ena_dev, +- ENA_ADMIN_RSS_HASH_FUNCTION)) ++ if (!ena_com_check_supported_feature_id(ena_dev, ENA_ADMIN_RSS_HASH_FUNCTION)) + return -EOPNOTSUPP; + +- rss->hash_key = +- dma_alloc_coherent(ena_dev->dmadev, sizeof(*rss->hash_key), +- &rss->hash_key_dma_addr, GFP_KERNEL); ++ rss->hash_key = dma_alloc_coherent(ena_dev->dmadev, sizeof(*rss->hash_key), ++ &rss->hash_key_dma_addr, GFP_KERNEL); + + if (unlikely(!rss->hash_key)) + return -ENOMEM; +@@ -1123,8 +1079,8 @@ static void ena_com_hash_key_destroy(struct ena_com_dev *ena_dev) + struct ena_rss *rss = &ena_dev->rss; + + if (rss->hash_key) +- dma_free_coherent(ena_dev->dmadev, sizeof(*rss->hash_key), +- rss->hash_key, rss->hash_key_dma_addr); ++ dma_free_coherent(ena_dev->dmadev, sizeof(*rss->hash_key), rss->hash_key, ++ rss->hash_key_dma_addr); + rss->hash_key = NULL; + } + +@@ -1132,9 +1088,8 @@ static int ena_com_hash_ctrl_init(struct ena_com_dev *ena_dev) + { + struct ena_rss *rss = &ena_dev->rss; + +- rss->hash_ctrl = +- dma_alloc_coherent(ena_dev->dmadev, sizeof(*rss->hash_ctrl), +- &rss->hash_ctrl_dma_addr, GFP_KERNEL); ++ rss->hash_ctrl = dma_alloc_coherent(ena_dev->dmadev, sizeof(*rss->hash_ctrl), ++ &rss->hash_ctrl_dma_addr, GFP_KERNEL); + + if (unlikely(!rss->hash_ctrl)) + return -ENOMEM; +@@ -1147,8 +1102,8 @@ static void ena_com_hash_ctrl_destroy(struct ena_com_dev *ena_dev) + struct ena_rss *rss = &ena_dev->rss; + + if (rss->hash_ctrl) +- dma_free_coherent(ena_dev->dmadev, sizeof(*rss->hash_ctrl), +- rss->hash_ctrl, rss->hash_ctrl_dma_addr); ++ dma_free_coherent(ena_dev->dmadev, sizeof(*rss->hash_ctrl), rss->hash_ctrl, ++ rss->hash_ctrl_dma_addr); + rss->hash_ctrl = NULL; + } + +@@ -1177,15 +1132,13 @@ static int ena_com_indirect_table_allocate(struct ena_com_dev *ena_dev, + tbl_size = (1ULL << log_size) * + sizeof(struct ena_admin_rss_ind_table_entry); + +- rss->rss_ind_tbl = +- dma_alloc_coherent(ena_dev->dmadev, tbl_size, +- &rss->rss_ind_tbl_dma_addr, GFP_KERNEL); ++ rss->rss_ind_tbl = dma_alloc_coherent(ena_dev->dmadev, tbl_size, &rss->rss_ind_tbl_dma_addr, ++ GFP_KERNEL); + if (unlikely(!rss->rss_ind_tbl)) + goto mem_err1; + + tbl_size = (1ULL << log_size) * sizeof(u16); +- rss->host_rss_ind_tbl = +- devm_kzalloc(ena_dev->dmadev, tbl_size, GFP_KERNEL); ++ rss->host_rss_ind_tbl = devm_kzalloc(ena_dev->dmadev, tbl_size, GFP_KERNEL); + if (unlikely(!rss->host_rss_ind_tbl)) + goto mem_err2; + +@@ -1197,8 +1150,7 @@ static int ena_com_indirect_table_allocate(struct ena_com_dev *ena_dev, + tbl_size = (1ULL << log_size) * + sizeof(struct ena_admin_rss_ind_table_entry); + +- dma_free_coherent(ena_dev->dmadev, tbl_size, rss->rss_ind_tbl, +- rss->rss_ind_tbl_dma_addr); ++ dma_free_coherent(ena_dev->dmadev, tbl_size, rss->rss_ind_tbl, rss->rss_ind_tbl_dma_addr); + rss->rss_ind_tbl = NULL; + mem_err1: + rss->tbl_log_size = 0; +@@ -1261,8 +1213,7 @@ static int ena_com_create_io_sq(struct ena_com_dev *ena_dev, + &create_cmd.sq_ba, + io_sq->desc_addr.phys_addr); + if (unlikely(ret)) { +- netdev_err(ena_dev->net_device, +- "Memory address set failed\n"); ++ netdev_err(ena_dev->net_device, "Memory address set failed\n"); + return ret; + } + } +@@ -1273,8 +1224,7 @@ static int ena_com_create_io_sq(struct ena_com_dev *ena_dev, + (struct ena_admin_acq_entry *)&cmd_completion, + sizeof(cmd_completion)); + if (unlikely(ret)) { +- netdev_err(ena_dev->net_device, +- "Failed to create IO SQ. error: %d\n", ret); ++ netdev_err(ena_dev->net_device, "Failed to create IO SQ. error: %d\n", ret); + return ret; + } + +@@ -1292,8 +1242,7 @@ static int ena_com_create_io_sq(struct ena_com_dev *ena_dev, + cmd_completion.llq_descriptors_offset); + } + +- netdev_dbg(ena_dev->net_device, "Created sq[%u], depth[%u]\n", +- io_sq->idx, io_sq->q_depth); ++ netdev_dbg(ena_dev->net_device, "Created sq[%u], depth[%u]\n", io_sq->idx, io_sq->q_depth); + + return ret; + } +@@ -1420,8 +1369,7 @@ int ena_com_create_io_cq(struct ena_com_dev *ena_dev, + (struct ena_admin_acq_entry *)&cmd_completion, + sizeof(cmd_completion)); + if (unlikely(ret)) { +- netdev_err(ena_dev->net_device, +- "Failed to create IO CQ. error: %d\n", ret); ++ netdev_err(ena_dev->net_device, "Failed to create IO CQ. error: %d\n", ret); + return ret; + } + +@@ -1440,8 +1388,7 @@ int ena_com_create_io_cq(struct ena_com_dev *ena_dev, + (u32 __iomem *)((uintptr_t)ena_dev->reg_bar + + cmd_completion.numa_node_register_offset); + +- netdev_dbg(ena_dev->net_device, "Created cq[%u], depth[%u]\n", +- io_cq->idx, io_cq->q_depth); ++ netdev_dbg(ena_dev->net_device, "Created cq[%u], depth[%u]\n", io_cq->idx, io_cq->q_depth); + + return ret; + } +@@ -1451,8 +1398,7 @@ int ena_com_get_io_handlers(struct ena_com_dev *ena_dev, u16 qid, + struct ena_com_io_cq **io_cq) + { + if (qid >= ENA_TOTAL_NUM_QUEUES) { +- netdev_err(ena_dev->net_device, +- "Invalid queue number %d but the max is %d\n", qid, ++ netdev_err(ena_dev->net_device, "Invalid queue number %d but the max is %d\n", qid, + ENA_TOTAL_NUM_QUEUES); + return -EINVAL; + } +@@ -1492,8 +1438,7 @@ void ena_com_wait_for_abort_completion(struct ena_com_dev *ena_dev) + spin_lock_irqsave(&admin_queue->q_lock, flags); + while (atomic_read(&admin_queue->outstanding_cmds) != 0) { + spin_unlock_irqrestore(&admin_queue->q_lock, flags); +- ena_delay_exponential_backoff_us(exp++, +- ena_dev->ena_min_poll_delay_us); ++ ena_delay_exponential_backoff_us(exp++, ena_dev->ena_min_poll_delay_us); + spin_lock_irqsave(&admin_queue->q_lock, flags); + } + spin_unlock_irqrestore(&admin_queue->q_lock, flags); +@@ -1519,8 +1464,7 @@ int ena_com_destroy_io_cq(struct ena_com_dev *ena_dev, + sizeof(destroy_resp)); + + if (unlikely(ret && (ret != -ENODEV))) +- netdev_err(ena_dev->net_device, +- "Failed to destroy IO CQ. error: %d\n", ret); ++ netdev_err(ena_dev->net_device, "Failed to destroy IO CQ. error: %d\n", ret); + + return ret; + } +@@ -1588,8 +1532,7 @@ int ena_com_set_aenq_config(struct ena_com_dev *ena_dev, u32 groups_flag) + sizeof(resp)); + + if (unlikely(ret)) +- netdev_err(ena_dev->net_device, +- "Failed to config AENQ ret: %d\n", ret); ++ netdev_err(ena_dev->net_device, "Failed to config AENQ ret: %d\n", ret); + + return ret; + } +@@ -1610,8 +1553,7 @@ int ena_com_get_dma_width(struct ena_com_dev *ena_dev) + netdev_dbg(ena_dev->net_device, "ENA dma width: %d\n", width); + + if ((width < 32) || width > ENA_MAX_PHYS_ADDR_SIZE_BITS) { +- netdev_err(ena_dev->net_device, "DMA width illegal value: %d\n", +- width); ++ netdev_err(ena_dev->net_device, "DMA width illegal value: %d\n", width); + return -EINVAL; + } + +@@ -1633,19 +1575,16 @@ int ena_com_validate_version(struct ena_com_dev *ena_dev) + ctrl_ver = ena_com_reg_bar_read32(ena_dev, + ENA_REGS_CONTROLLER_VERSION_OFF); + +- if (unlikely((ver == ENA_MMIO_READ_TIMEOUT) || +- (ctrl_ver == ENA_MMIO_READ_TIMEOUT))) { ++ if (unlikely((ver == ENA_MMIO_READ_TIMEOUT) || (ctrl_ver == ENA_MMIO_READ_TIMEOUT))) { + netdev_err(ena_dev->net_device, "Reg read timeout occurred\n"); + return -ETIME; + } + + dev_info(ena_dev->dmadev, "ENA device version: %d.%d\n", +- (ver & ENA_REGS_VERSION_MAJOR_VERSION_MASK) >> +- ENA_REGS_VERSION_MAJOR_VERSION_SHIFT, ++ (ver & ENA_REGS_VERSION_MAJOR_VERSION_MASK) >> ENA_REGS_VERSION_MAJOR_VERSION_SHIFT, + ver & ENA_REGS_VERSION_MINOR_VERSION_MASK); + +- dev_info(ena_dev->dmadev, +- "ENA controller version: %d.%d.%d implementation version %d\n", ++ dev_info(ena_dev->dmadev, "ENA controller version: %d.%d.%d implementation version %d\n", + (ctrl_ver & ENA_REGS_CONTROLLER_VERSION_MAJOR_VERSION_MASK) >> + ENA_REGS_CONTROLLER_VERSION_MAJOR_VERSION_SHIFT, + (ctrl_ver & ENA_REGS_CONTROLLER_VERSION_MINOR_VERSION_MASK) >> +@@ -1694,20 +1633,17 @@ void ena_com_admin_destroy(struct ena_com_dev *ena_dev) + + size = ADMIN_SQ_SIZE(admin_queue->q_depth); + if (sq->entries) +- dma_free_coherent(ena_dev->dmadev, size, sq->entries, +- sq->dma_addr); ++ dma_free_coherent(ena_dev->dmadev, size, sq->entries, sq->dma_addr); + sq->entries = NULL; + + size = ADMIN_CQ_SIZE(admin_queue->q_depth); + if (cq->entries) +- dma_free_coherent(ena_dev->dmadev, size, cq->entries, +- cq->dma_addr); ++ dma_free_coherent(ena_dev->dmadev, size, cq->entries, cq->dma_addr); + cq->entries = NULL; + + size = ADMIN_AENQ_SIZE(aenq->q_depth); + if (ena_dev->aenq.entries) +- dma_free_coherent(ena_dev->dmadev, size, aenq->entries, +- aenq->dma_addr); ++ dma_free_coherent(ena_dev->dmadev, size, aenq->entries, aenq->dma_addr); + aenq->entries = NULL; + } + +@@ -1733,10 +1669,8 @@ int ena_com_mmio_reg_read_request_init(struct ena_com_dev *ena_dev) + struct ena_com_mmio_read *mmio_read = &ena_dev->mmio_read; + + spin_lock_init(&mmio_read->lock); +- mmio_read->read_resp = +- dma_alloc_coherent(ena_dev->dmadev, +- sizeof(*mmio_read->read_resp), +- &mmio_read->read_resp_dma_addr, GFP_KERNEL); ++ mmio_read->read_resp = dma_alloc_coherent(ena_dev->dmadev, sizeof(*mmio_read->read_resp), ++ &mmio_read->read_resp_dma_addr, GFP_KERNEL); + if (unlikely(!mmio_read->read_resp)) + goto err; + +@@ -1767,8 +1701,8 @@ void ena_com_mmio_reg_read_request_destroy(struct ena_com_dev *ena_dev) + writel(0x0, ena_dev->reg_bar + ENA_REGS_MMIO_RESP_LO_OFF); + writel(0x0, ena_dev->reg_bar + ENA_REGS_MMIO_RESP_HI_OFF); + +- dma_free_coherent(ena_dev->dmadev, sizeof(*mmio_read->read_resp), +- mmio_read->read_resp, mmio_read->read_resp_dma_addr); ++ dma_free_coherent(ena_dev->dmadev, sizeof(*mmio_read->read_resp), mmio_read->read_resp, ++ mmio_read->read_resp_dma_addr); + + mmio_read->read_resp = NULL; + } +@@ -1800,8 +1734,7 @@ int ena_com_admin_init(struct ena_com_dev *ena_dev, + } + + if (!(dev_sts & ENA_REGS_DEV_STS_READY_MASK)) { +- netdev_err(ena_dev->net_device, +- "Device isn't ready, abort com init\n"); ++ netdev_err(ena_dev->net_device, "Device isn't ready, abort com init\n"); + return -ENODEV; + } + +@@ -1878,8 +1811,7 @@ int ena_com_create_io_queue(struct ena_com_dev *ena_dev, + int ret; + + if (ctx->qid >= ENA_TOTAL_NUM_QUEUES) { +- netdev_err(ena_dev->net_device, +- "Qid (%d) is bigger than max num of queues (%d)\n", ++ netdev_err(ena_dev->net_device, "Qid (%d) is bigger than max num of queues (%d)\n", + ctx->qid, ENA_TOTAL_NUM_QUEUES); + return -EINVAL; + } +@@ -1905,8 +1837,7 @@ int ena_com_create_io_queue(struct ena_com_dev *ena_dev, + + if (ctx->direction == ENA_COM_IO_QUEUE_DIRECTION_TX) + /* header length is limited to 8 bits */ +- io_sq->tx_max_header_size = +- min_t(u32, ena_dev->tx_max_header_size, SZ_256); ++ io_sq->tx_max_header_size = min_t(u32, ena_dev->tx_max_header_size, SZ_256); + + ret = ena_com_init_io_sq(ena_dev, ctx, io_sq); + if (ret) +@@ -1938,8 +1869,7 @@ void ena_com_destroy_io_queue(struct ena_com_dev *ena_dev, u16 qid) + struct ena_com_io_cq *io_cq; + + if (qid >= ENA_TOTAL_NUM_QUEUES) { +- netdev_err(ena_dev->net_device, +- "Qid (%d) is bigger than max num of queues (%d)\n", ++ netdev_err(ena_dev->net_device, "Qid (%d) is bigger than max num of queues (%d)\n", + qid, ENA_TOTAL_NUM_QUEUES); + return; + } +@@ -1983,8 +1913,7 @@ int ena_com_get_dev_attr_feat(struct ena_com_dev *ena_dev, + if (rc) + return rc; + +- if (get_resp.u.max_queue_ext.version != +- ENA_FEATURE_MAX_QUEUE_EXT_VER) ++ if (get_resp.u.max_queue_ext.version != ENA_FEATURE_MAX_QUEUE_EXT_VER) + return -EINVAL; + + memcpy(&get_feat_ctx->max_queue_ext, &get_resp.u.max_queue_ext, +@@ -2025,18 +1954,15 @@ int ena_com_get_dev_attr_feat(struct ena_com_dev *ena_dev, + rc = ena_com_get_feature(ena_dev, &get_resp, ENA_ADMIN_HW_HINTS, 0); + + if (!rc) +- memcpy(&get_feat_ctx->hw_hints, &get_resp.u.hw_hints, +- sizeof(get_resp.u.hw_hints)); ++ memcpy(&get_feat_ctx->hw_hints, &get_resp.u.hw_hints, sizeof(get_resp.u.hw_hints)); + else if (rc == -EOPNOTSUPP) +- memset(&get_feat_ctx->hw_hints, 0x0, +- sizeof(get_feat_ctx->hw_hints)); ++ memset(&get_feat_ctx->hw_hints, 0x0, sizeof(get_feat_ctx->hw_hints)); + else + return rc; + + rc = ena_com_get_feature(ena_dev, &get_resp, ENA_ADMIN_LLQ, 0); + if (!rc) +- memcpy(&get_feat_ctx->llq, &get_resp.u.llq, +- sizeof(get_resp.u.llq)); ++ memcpy(&get_feat_ctx->llq, &get_resp.u.llq, sizeof(get_resp.u.llq)); + else if (rc == -EOPNOTSUPP) + memset(&get_feat_ctx->llq, 0x0, sizeof(get_feat_ctx->llq)); + else +@@ -2084,8 +2010,7 @@ void ena_com_aenq_intr_handler(struct ena_com_dev *ena_dev, void *data) + aenq_common = &aenq_e->aenq_common_desc; + + /* Go over all the events */ +- while ((READ_ONCE(aenq_common->flags) & +- ENA_ADMIN_AENQ_COMMON_DESC_PHASE_MASK) == phase) { ++ while ((READ_ONCE(aenq_common->flags) & ENA_ADMIN_AENQ_COMMON_DESC_PHASE_MASK) == phase) { + /* Make sure the phase bit (ownership) is as expected before + * reading the rest of the descriptor. + */ +@@ -2094,8 +2019,7 @@ void ena_com_aenq_intr_handler(struct ena_com_dev *ena_dev, void *data) + timestamp = (u64)aenq_common->timestamp_low | + ((u64)aenq_common->timestamp_high << 32); + +- netdev_dbg(ena_dev->net_device, +- "AENQ! Group[%x] Syndrome[%x] timestamp: [%llus]\n", ++ netdev_dbg(ena_dev->net_device, "AENQ! Group[%x] Syndrome[%x] timestamp: [%llus]\n", + aenq_common->group, aenq_common->syndrome, timestamp); + + /* Handle specific event*/ +@@ -2124,8 +2048,7 @@ void ena_com_aenq_intr_handler(struct ena_com_dev *ena_dev, void *data) + + /* write the aenq doorbell after all AENQ descriptors were read */ + mb(); +- writel_relaxed((u32)aenq->head, +- ena_dev->reg_bar + ENA_REGS_AENQ_HEAD_DB_OFF); ++ writel_relaxed((u32)aenq->head, ena_dev->reg_bar + ENA_REGS_AENQ_HEAD_DB_OFF); + } + + int ena_com_dev_reset(struct ena_com_dev *ena_dev, +@@ -2137,15 +2060,13 @@ int ena_com_dev_reset(struct ena_com_dev *ena_dev, + stat = ena_com_reg_bar_read32(ena_dev, ENA_REGS_DEV_STS_OFF); + cap = ena_com_reg_bar_read32(ena_dev, ENA_REGS_CAPS_OFF); + +- if (unlikely((stat == ENA_MMIO_READ_TIMEOUT) || +- (cap == ENA_MMIO_READ_TIMEOUT))) { ++ if (unlikely((stat == ENA_MMIO_READ_TIMEOUT) || (cap == ENA_MMIO_READ_TIMEOUT))) { + netdev_err(ena_dev->net_device, "Reg read32 timeout occurred\n"); + return -ETIME; + } + + if ((stat & ENA_REGS_DEV_STS_READY_MASK) == 0) { +- netdev_err(ena_dev->net_device, +- "Device isn't ready, can't reset device\n"); ++ netdev_err(ena_dev->net_device, "Device isn't ready, can't reset device\n"); + return -EINVAL; + } + +@@ -2168,8 +2089,7 @@ int ena_com_dev_reset(struct ena_com_dev *ena_dev, + rc = wait_for_reset_state(ena_dev, timeout, + ENA_REGS_DEV_STS_RESET_IN_PROGRESS_MASK); + if (rc != 0) { +- netdev_err(ena_dev->net_device, +- "Reset indication didn't turn on\n"); ++ netdev_err(ena_dev->net_device, "Reset indication didn't turn on\n"); + return rc; + } + +@@ -2177,8 +2097,7 @@ int ena_com_dev_reset(struct ena_com_dev *ena_dev, + writel(0, ena_dev->reg_bar + ENA_REGS_DEV_CTL_OFF); + rc = wait_for_reset_state(ena_dev, timeout, 0); + if (rc != 0) { +- netdev_err(ena_dev->net_device, +- "Reset indication didn't turn off\n"); ++ netdev_err(ena_dev->net_device, "Reset indication didn't turn off\n"); + return rc; + } + +@@ -2215,8 +2134,7 @@ static int ena_get_dev_stats(struct ena_com_dev *ena_dev, + sizeof(*get_resp)); + + if (unlikely(ret)) +- netdev_err(ena_dev->net_device, +- "Failed to get stats. error: %d\n", ret); ++ netdev_err(ena_dev->net_device, "Failed to get stats. error: %d\n", ret); + + return ret; + } +@@ -2228,8 +2146,7 @@ int ena_com_get_eni_stats(struct ena_com_dev *ena_dev, + int ret; + + if (!ena_com_get_cap(ena_dev, ENA_ADMIN_ENI_STATS)) { +- netdev_err(ena_dev->net_device, +- "Capability %d isn't supported\n", ++ netdev_err(ena_dev->net_device, "Capability %d isn't supported\n", + ENA_ADMIN_ENI_STATS); + return -EOPNOTSUPP; + } +@@ -2266,8 +2183,7 @@ int ena_com_set_dev_mtu(struct ena_com_dev *ena_dev, u32 mtu) + int ret; + + if (!ena_com_check_supported_feature_id(ena_dev, ENA_ADMIN_MTU)) { +- netdev_dbg(ena_dev->net_device, "Feature %d isn't supported\n", +- ENA_ADMIN_MTU); ++ netdev_dbg(ena_dev->net_device, "Feature %d isn't supported\n", ENA_ADMIN_MTU); + return -EOPNOTSUPP; + } + +@@ -2286,8 +2202,7 @@ int ena_com_set_dev_mtu(struct ena_com_dev *ena_dev, u32 mtu) + sizeof(resp)); + + if (unlikely(ret)) +- netdev_err(ena_dev->net_device, +- "Failed to set mtu %d. error: %d\n", mtu, ret); ++ netdev_err(ena_dev->net_device, "Failed to set mtu %d. error: %d\n", mtu, ret); + + return ret; + } +@@ -2301,8 +2216,7 @@ int ena_com_get_offload_settings(struct ena_com_dev *ena_dev, + ret = ena_com_get_feature(ena_dev, &resp, + ENA_ADMIN_STATELESS_OFFLOAD_CONFIG, 0); + if (unlikely(ret)) { +- netdev_err(ena_dev->net_device, +- "Failed to get offload capabilities %d\n", ret); ++ netdev_err(ena_dev->net_device, "Failed to get offload capabilities %d\n", ret); + return ret; + } + +@@ -2320,8 +2234,7 @@ int ena_com_set_hash_function(struct ena_com_dev *ena_dev) + struct ena_admin_get_feat_resp get_resp; + int ret; + +- if (!ena_com_check_supported_feature_id(ena_dev, +- ENA_ADMIN_RSS_HASH_FUNCTION)) { ++ if (!ena_com_check_supported_feature_id(ena_dev, ENA_ADMIN_RSS_HASH_FUNCTION)) { + netdev_dbg(ena_dev->net_device, "Feature %d isn't supported\n", + ENA_ADMIN_RSS_HASH_FUNCTION); + return -EOPNOTSUPP; +@@ -2334,8 +2247,7 @@ int ena_com_set_hash_function(struct ena_com_dev *ena_dev) + return ret; + + if (!(get_resp.u.flow_hash_func.supported_func & BIT(rss->hash_func))) { +- netdev_err(ena_dev->net_device, +- "Func hash %d isn't supported by device, abort\n", ++ netdev_err(ena_dev->net_device, "Func hash %d isn't supported by device, abort\n", + rss->hash_func); + return -EOPNOTSUPP; + } +@@ -2365,8 +2277,7 @@ int ena_com_set_hash_function(struct ena_com_dev *ena_dev) + (struct ena_admin_acq_entry *)&resp, + sizeof(resp)); + if (unlikely(ret)) { +- netdev_err(ena_dev->net_device, +- "Failed to set hash function %d. error: %d\n", ++ netdev_err(ena_dev->net_device, "Failed to set hash function %d. error: %d\n", + rss->hash_func, ret); + return -EINVAL; + } +@@ -2398,16 +2309,15 @@ int ena_com_fill_hash_function(struct ena_com_dev *ena_dev, + return rc; + + if (!(BIT(func) & get_resp.u.flow_hash_func.supported_func)) { +- netdev_err(ena_dev->net_device, +- "Flow hash function %d isn't supported\n", func); ++ netdev_err(ena_dev->net_device, "Flow hash function %d isn't supported\n", func); + return -EOPNOTSUPP; + } + + if ((func == ENA_ADMIN_TOEPLITZ) && key) { + if (key_len != sizeof(hash_key->key)) { + netdev_err(ena_dev->net_device, +- "key len (%u) doesn't equal the supported size (%zu)\n", +- key_len, sizeof(hash_key->key)); ++ "key len (%u) doesn't equal the supported size (%zu)\n", key_len, ++ sizeof(hash_key->key)); + return -EINVAL; + } + memcpy(hash_key->key, key, key_len); +@@ -2495,8 +2405,7 @@ int ena_com_set_hash_ctrl(struct ena_com_dev *ena_dev) + struct ena_admin_set_feat_resp resp; + int ret; + +- if (!ena_com_check_supported_feature_id(ena_dev, +- ENA_ADMIN_RSS_HASH_INPUT)) { ++ if (!ena_com_check_supported_feature_id(ena_dev, ENA_ADMIN_RSS_HASH_INPUT)) { + netdev_dbg(ena_dev->net_device, "Feature %d isn't supported\n", + ENA_ADMIN_RSS_HASH_INPUT); + return -EOPNOTSUPP; +@@ -2527,8 +2436,7 @@ int ena_com_set_hash_ctrl(struct ena_com_dev *ena_dev) + (struct ena_admin_acq_entry *)&resp, + sizeof(resp)); + if (unlikely(ret)) +- netdev_err(ena_dev->net_device, +- "Failed to set hash input. error: %d\n", ret); ++ netdev_err(ena_dev->net_device, "Failed to set hash input. error: %d\n", ret); + + return ret; + } +@@ -2605,8 +2513,7 @@ int ena_com_fill_hash_ctrl(struct ena_com_dev *ena_dev, + int rc; + + if (proto >= ENA_ADMIN_RSS_PROTO_NUM) { +- netdev_err(ena_dev->net_device, "Invalid proto num (%u)\n", +- proto); ++ netdev_err(ena_dev->net_device, "Invalid proto num (%u)\n", proto); + return -EINVAL; + } + +@@ -2658,8 +2565,7 @@ int ena_com_indirect_table_set(struct ena_com_dev *ena_dev) + struct ena_admin_set_feat_resp resp; + int ret; + +- if (!ena_com_check_supported_feature_id( +- ena_dev, ENA_ADMIN_RSS_INDIRECTION_TABLE_CONFIG)) { ++ if (!ena_com_check_supported_feature_id(ena_dev, ENA_ADMIN_RSS_INDIRECTION_TABLE_CONFIG)) { + netdev_dbg(ena_dev->net_device, "Feature %d isn't supported\n", + ENA_ADMIN_RSS_INDIRECTION_TABLE_CONFIG); + return -EOPNOTSUPP; +@@ -2699,8 +2605,7 @@ int ena_com_indirect_table_set(struct ena_com_dev *ena_dev) + sizeof(resp)); + + if (unlikely(ret)) +- netdev_err(ena_dev->net_device, +- "Failed to set indirect table. error: %d\n", ret); ++ netdev_err(ena_dev->net_device, "Failed to set indirect table. error: %d\n", ret); + + return ret; + } +@@ -2779,9 +2684,8 @@ int ena_com_allocate_host_info(struct ena_com_dev *ena_dev) + { + struct ena_host_attribute *host_attr = &ena_dev->host_attr; + +- host_attr->host_info = +- dma_alloc_coherent(ena_dev->dmadev, SZ_4K, +- &host_attr->host_info_dma_addr, GFP_KERNEL); ++ host_attr->host_info = dma_alloc_coherent(ena_dev->dmadev, SZ_4K, ++ &host_attr->host_info_dma_addr, GFP_KERNEL); + if (unlikely(!host_attr->host_info)) + return -ENOMEM; + +@@ -2827,8 +2731,7 @@ void ena_com_delete_debug_area(struct ena_com_dev *ena_dev) + + if (host_attr->debug_area_virt_addr) { + dma_free_coherent(ena_dev->dmadev, host_attr->debug_area_size, +- host_attr->debug_area_virt_addr, +- host_attr->debug_area_dma_addr); ++ host_attr->debug_area_virt_addr, host_attr->debug_area_dma_addr); + host_attr->debug_area_virt_addr = NULL; + } + } +@@ -2877,8 +2780,7 @@ int ena_com_set_host_attributes(struct ena_com_dev *ena_dev) + sizeof(resp)); + + if (unlikely(ret)) +- netdev_err(ena_dev->net_device, +- "Failed to set host attributes: %d\n", ret); ++ netdev_err(ena_dev->net_device, "Failed to set host attributes: %d\n", ret); + + return ret; + } +@@ -2896,8 +2798,7 @@ static int ena_com_update_nonadaptive_moderation_interval(struct ena_com_dev *en + u32 *intr_moder_interval) + { + if (!intr_delay_resolution) { +- netdev_err(ena_dev->net_device, +- "Illegal interrupt delay granularity value\n"); ++ netdev_err(ena_dev->net_device, "Illegal interrupt delay granularity value\n"); + return -EFAULT; + } + +@@ -2935,14 +2836,12 @@ int ena_com_init_interrupt_moderation(struct ena_com_dev *ena_dev) + + if (rc) { + if (rc == -EOPNOTSUPP) { +- netdev_dbg(ena_dev->net_device, +- "Feature %d isn't supported\n", ++ netdev_dbg(ena_dev->net_device, "Feature %d isn't supported\n", + ENA_ADMIN_INTERRUPT_MODERATION); + rc = 0; + } else { + netdev_err(ena_dev->net_device, +- "Failed to get interrupt moderation admin cmd. rc: %d\n", +- rc); ++ "Failed to get interrupt moderation admin cmd. rc: %d\n", rc); + } + + /* no moderation supported, disable adaptive support */ +@@ -2990,8 +2889,7 @@ int ena_com_config_dev_mode(struct ena_com_dev *ena_dev, + (llq_info->descs_num_before_header * sizeof(struct ena_eth_io_tx_desc)); + + if (unlikely(ena_dev->tx_max_header_size == 0)) { +- netdev_err(ena_dev->net_device, +- "The size of the LLQ entry is smaller than needed\n"); ++ netdev_err(ena_dev->net_device, "The size of the LLQ entry is smaller than needed\n"); + return -EINVAL; + } + +diff --git a/drivers/net/ethernet/amazon/ena/ena_eth_com.c b/drivers/net/ethernet/amazon/ena/ena_eth_com.c +index f9f886289b970..933e619b3a313 100644 +--- a/drivers/net/ethernet/amazon/ena/ena_eth_com.c ++++ b/drivers/net/ethernet/amazon/ena/ena_eth_com.c +@@ -18,8 +18,7 @@ static struct ena_eth_io_rx_cdesc_base *ena_com_get_next_rx_cdesc( + cdesc = (struct ena_eth_io_rx_cdesc_base *)(io_cq->cdesc_addr.virt_addr + + (head_masked * io_cq->cdesc_entry_size_in_bytes)); + +- desc_phase = (READ_ONCE(cdesc->status) & +- ENA_ETH_IO_RX_CDESC_BASE_PHASE_MASK) >> ++ desc_phase = (READ_ONCE(cdesc->status) & ENA_ETH_IO_RX_CDESC_BASE_PHASE_MASK) >> + ENA_ETH_IO_RX_CDESC_BASE_PHASE_SHIFT; + + if (desc_phase != expected_phase) +@@ -65,8 +64,8 @@ static int ena_com_write_bounce_buffer_to_dev(struct ena_com_io_sq *io_sq, + + io_sq->entries_in_tx_burst_left--; + netdev_dbg(ena_com_io_sq_to_ena_dev(io_sq)->net_device, +- "Decreasing entries_in_tx_burst_left of queue %d to %d\n", +- io_sq->qid, io_sq->entries_in_tx_burst_left); ++ "Decreasing entries_in_tx_burst_left of queue %d to %d\n", io_sq->qid, ++ io_sq->entries_in_tx_burst_left); + } + + /* Make sure everything was written into the bounce buffer before +@@ -75,8 +74,8 @@ static int ena_com_write_bounce_buffer_to_dev(struct ena_com_io_sq *io_sq, + wmb(); + + /* The line is completed. Copy it to dev */ +- __iowrite64_copy(io_sq->desc_addr.pbuf_dev_addr + dst_offset, +- bounce_buffer, (llq_info->desc_list_entry_size) / 8); ++ __iowrite64_copy(io_sq->desc_addr.pbuf_dev_addr + dst_offset, bounce_buffer, ++ (llq_info->desc_list_entry_size) / 8); + + io_sq->tail++; + +@@ -102,16 +101,14 @@ static int ena_com_write_header_to_bounce(struct ena_com_io_sq *io_sq, + header_offset = + llq_info->descs_num_before_header * io_sq->desc_entry_size; + +- if (unlikely((header_offset + header_len) > +- llq_info->desc_list_entry_size)) { ++ if (unlikely((header_offset + header_len) > llq_info->desc_list_entry_size)) { + netdev_err(ena_com_io_sq_to_ena_dev(io_sq)->net_device, + "Trying to write header larger than llq entry can accommodate\n"); + return -EFAULT; + } + + if (unlikely(!bounce_buffer)) { +- netdev_err(ena_com_io_sq_to_ena_dev(io_sq)->net_device, +- "Bounce buffer is NULL\n"); ++ netdev_err(ena_com_io_sq_to_ena_dev(io_sq)->net_device, "Bounce buffer is NULL\n"); + return -EFAULT; + } + +@@ -129,8 +126,7 @@ static void *get_sq_desc_llq(struct ena_com_io_sq *io_sq) + bounce_buffer = pkt_ctrl->curr_bounce_buf; + + if (unlikely(!bounce_buffer)) { +- netdev_err(ena_com_io_sq_to_ena_dev(io_sq)->net_device, +- "Bounce buffer is NULL\n"); ++ netdev_err(ena_com_io_sq_to_ena_dev(io_sq)->net_device, "Bounce buffer is NULL\n"); + return NULL; + } + +@@ -247,8 +243,7 @@ static u16 ena_com_cdesc_rx_pkt_get(struct ena_com_io_cq *io_cq, + + ena_com_cq_inc_head(io_cq); + count++; +- last = (READ_ONCE(cdesc->status) & +- ENA_ETH_IO_RX_CDESC_BASE_LAST_MASK) >> ++ last = (READ_ONCE(cdesc->status) & ENA_ETH_IO_RX_CDESC_BASE_LAST_MASK) >> + ENA_ETH_IO_RX_CDESC_BASE_LAST_SHIFT; + } while (!last); + +@@ -369,9 +364,8 @@ static void ena_com_rx_set_flags(struct ena_com_io_cq *io_cq, + + netdev_dbg(ena_com_io_cq_to_ena_dev(io_cq)->net_device, + "l3_proto %d l4_proto %d l3_csum_err %d l4_csum_err %d hash %d frag %d cdesc_status %x\n", +- ena_rx_ctx->l3_proto, ena_rx_ctx->l4_proto, +- ena_rx_ctx->l3_csum_err, ena_rx_ctx->l4_csum_err, +- ena_rx_ctx->hash, ena_rx_ctx->frag, cdesc->status); ++ ena_rx_ctx->l3_proto, ena_rx_ctx->l4_proto, ena_rx_ctx->l3_csum_err, ++ ena_rx_ctx->l4_csum_err, ena_rx_ctx->hash, ena_rx_ctx->frag, cdesc->status); + } + + /*****************************************************************************/ +@@ -403,13 +397,12 @@ int ena_com_prepare_tx(struct ena_com_io_sq *io_sq, + + if (unlikely(header_len > io_sq->tx_max_header_size)) { + netdev_err(ena_com_io_sq_to_ena_dev(io_sq)->net_device, +- "Header size is too large %d max header: %d\n", +- header_len, io_sq->tx_max_header_size); ++ "Header size is too large %d max header: %d\n", header_len, ++ io_sq->tx_max_header_size); + return -EINVAL; + } + +- if (unlikely(io_sq->mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV && +- !buffer_to_push)) { ++ if (unlikely(io_sq->mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV && !buffer_to_push)) { + netdev_err(ena_com_io_sq_to_ena_dev(io_sq)->net_device, + "Push header wasn't provided in LLQ mode\n"); + return -EINVAL; +@@ -556,13 +549,11 @@ int ena_com_rx_pkt(struct ena_com_io_cq *io_cq, + } + + netdev_dbg(ena_com_io_cq_to_ena_dev(io_cq)->net_device, +- "Fetch rx packet: queue %d completed desc: %d\n", io_cq->qid, +- nb_hw_desc); ++ "Fetch rx packet: queue %d completed desc: %d\n", io_cq->qid, nb_hw_desc); + + if (unlikely(nb_hw_desc > ena_rx_ctx->max_bufs)) { + netdev_err(ena_com_io_cq_to_ena_dev(io_cq)->net_device, +- "Too many RX cdescs (%d) > MAX(%d)\n", nb_hw_desc, +- ena_rx_ctx->max_bufs); ++ "Too many RX cdescs (%d) > MAX(%d)\n", nb_hw_desc, ena_rx_ctx->max_bufs); + return -ENOSPC; + } + +@@ -586,8 +577,8 @@ int ena_com_rx_pkt(struct ena_com_io_cq *io_cq, + io_sq->next_to_comp += nb_hw_desc; + + netdev_dbg(ena_com_io_cq_to_ena_dev(io_cq)->net_device, +- "[%s][QID#%d] Updating SQ head to: %d\n", __func__, +- io_sq->qid, io_sq->next_to_comp); ++ "[%s][QID#%d] Updating SQ head to: %d\n", __func__, io_sq->qid, ++ io_sq->next_to_comp); + + /* Get rx flags from the last pkt */ + ena_com_rx_set_flags(io_cq, ena_rx_ctx, cdesc); +@@ -624,8 +615,8 @@ int ena_com_add_single_rx_desc(struct ena_com_io_sq *io_sq, + desc->req_id = req_id; + + netdev_dbg(ena_com_io_sq_to_ena_dev(io_sq)->net_device, +- "[%s] Adding single RX desc, Queue: %u, req_id: %u\n", +- __func__, io_sq->qid, req_id); ++ "[%s] Adding single RX desc, Queue: %u, req_id: %u\n", __func__, io_sq->qid, ++ req_id); + + desc->buff_addr_lo = (u32)ena_buf->paddr; + desc->buff_addr_hi = +diff --git a/drivers/net/ethernet/amazon/ena/ena_eth_com.h b/drivers/net/ethernet/amazon/ena/ena_eth_com.h +index 372b259279eca..6eba034646525 100644 +--- a/drivers/net/ethernet/amazon/ena/ena_eth_com.h ++++ b/drivers/net/ethernet/amazon/ena/ena_eth_com.h +@@ -145,8 +145,8 @@ static inline bool ena_com_is_doorbell_needed(struct ena_com_io_sq *io_sq, + } + + netdev_dbg(ena_com_io_sq_to_ena_dev(io_sq)->net_device, +- "Queue: %d num_descs: %d num_entries_needed: %d\n", +- io_sq->qid, num_descs, num_entries_needed); ++ "Queue: %d num_descs: %d num_entries_needed: %d\n", io_sq->qid, num_descs, ++ num_entries_needed); + + return num_entries_needed > io_sq->entries_in_tx_burst_left; + } +@@ -157,15 +157,14 @@ static inline int ena_com_write_sq_doorbell(struct ena_com_io_sq *io_sq) + u16 tail = io_sq->tail; + + netdev_dbg(ena_com_io_sq_to_ena_dev(io_sq)->net_device, +- "Write submission queue doorbell for queue: %d tail: %d\n", +- io_sq->qid, tail); ++ "Write submission queue doorbell for queue: %d tail: %d\n", io_sq->qid, tail); + + writel(tail, io_sq->db_addr); + + if (is_llq_max_tx_burst_exists(io_sq)) { + netdev_dbg(ena_com_io_sq_to_ena_dev(io_sq)->net_device, +- "Reset available entries in tx burst for queue %d to %d\n", +- io_sq->qid, max_entries_in_tx_burst); ++ "Reset available entries in tx burst for queue %d to %d\n", io_sq->qid, ++ max_entries_in_tx_burst); + io_sq->entries_in_tx_burst_left = max_entries_in_tx_burst; + } + +@@ -248,8 +247,8 @@ static inline int ena_com_tx_comp_req_id_get(struct ena_com_io_cq *io_cq, + + *req_id = READ_ONCE(cdesc->req_id); + if (unlikely(*req_id >= io_cq->q_depth)) { +- netdev_err(ena_com_io_cq_to_ena_dev(io_cq)->net_device, +- "Invalid req id %d\n", cdesc->req_id); ++ netdev_err(ena_com_io_cq_to_ena_dev(io_cq)->net_device, "Invalid req id %d\n", ++ cdesc->req_id); + return -EINVAL; + } + +diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.c b/drivers/net/ethernet/amazon/ena/ena_netdev.c +index b239e473d59fa..0d201a57d7e29 100644 +--- a/drivers/net/ethernet/amazon/ena/ena_netdev.c ++++ b/drivers/net/ethernet/amazon/ena/ena_netdev.c +@@ -116,11 +116,9 @@ int ena_xmit_common(struct ena_adapter *adapter, + if (unlikely(rc)) { + netif_err(adapter, tx_queued, adapter->netdev, + "Failed to prepare tx bufs\n"); +- ena_increase_stat(&ring->tx_stats.prepare_ctx_err, 1, +- &ring->syncp); ++ ena_increase_stat(&ring->tx_stats.prepare_ctx_err, 1, &ring->syncp); + if (rc != -ENOMEM) +- ena_reset_device(adapter, +- ENA_REGS_RESET_DRIVER_INVALID_STATE); ++ ena_reset_device(adapter, ENA_REGS_RESET_DRIVER_INVALID_STATE); + return rc; + } + +@@ -484,8 +482,7 @@ static struct page *ena_alloc_map_page(struct ena_ring *rx_ring, + */ + page = dev_alloc_page(); + if (!page) { +- ena_increase_stat(&rx_ring->rx_stats.page_alloc_fail, 1, +- &rx_ring->syncp); ++ ena_increase_stat(&rx_ring->rx_stats.page_alloc_fail, 1, &rx_ring->syncp); + return ERR_PTR(-ENOSPC); + } + +@@ -544,8 +541,8 @@ static void ena_unmap_rx_buff_attrs(struct ena_ring *rx_ring, + struct ena_rx_buffer *rx_info, + unsigned long attrs) + { +- dma_unmap_page_attrs(rx_ring->dev, rx_info->dma_addr, ENA_PAGE_SIZE, +- DMA_BIDIRECTIONAL, attrs); ++ dma_unmap_page_attrs(rx_ring->dev, rx_info->dma_addr, ENA_PAGE_SIZE, DMA_BIDIRECTIONAL, ++ attrs); + } + + static void ena_free_rx_page(struct ena_ring *rx_ring, +@@ -825,8 +822,7 @@ static int ena_clean_tx_irq(struct ena_ring *tx_ring, u32 budget) + &req_id); + if (rc) { + if (unlikely(rc == -EINVAL)) +- handle_invalid_req_id(tx_ring, req_id, NULL, +- false); ++ handle_invalid_req_id(tx_ring, req_id, NULL, false); + break; + } + +@@ -1052,8 +1048,7 @@ static struct sk_buff *ena_rx_skb(struct ena_ring *rx_ring, + DMA_FROM_DEVICE); + + if (!reuse_rx_buf_page) +- ena_unmap_rx_buff_attrs(rx_ring, rx_info, +- DMA_ATTR_SKIP_CPU_SYNC); ++ ena_unmap_rx_buff_attrs(rx_ring, rx_info, DMA_ATTR_SKIP_CPU_SYNC); + + skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, rx_info->page, + page_offset + buf_offset, len, buf_len); +@@ -1326,8 +1321,7 @@ static int ena_clean_rx_irq(struct ena_ring *rx_ring, struct napi_struct *napi, + adapter = netdev_priv(rx_ring->netdev); + + if (rc == -ENOSPC) { +- ena_increase_stat(&rx_ring->rx_stats.bad_desc_num, 1, +- &rx_ring->syncp); ++ ena_increase_stat(&rx_ring->rx_stats.bad_desc_num, 1, &rx_ring->syncp); + ena_reset_device(adapter, ENA_REGS_RESET_TOO_MANY_RX_DESCS); + } else { + ena_increase_stat(&rx_ring->rx_stats.bad_req_id, 1, +@@ -1807,8 +1801,7 @@ static int ena_rss_configure(struct ena_adapter *adapter) + if (!ena_dev->rss.tbl_log_size) { + rc = ena_rss_init_default(adapter); + if (rc && (rc != -EOPNOTSUPP)) { +- netif_err(adapter, ifup, adapter->netdev, +- "Failed to init RSS rc: %d\n", rc); ++ netif_err(adapter, ifup, adapter->netdev, "Failed to init RSS rc: %d\n", rc); + return rc; + } + } +@@ -2741,8 +2734,7 @@ static void ena_config_debug_area(struct ena_adapter *adapter) + rc = ena_com_set_host_attributes(adapter->ena_dev); + if (rc) { + if (rc == -EOPNOTSUPP) +- netif_warn(adapter, drv, adapter->netdev, +- "Cannot set host attributes\n"); ++ netif_warn(adapter, drv, adapter->netdev, "Cannot set host attributes\n"); + else + netif_err(adapter, drv, adapter->netdev, + "Cannot set host attributes\n"); +@@ -3734,8 +3726,8 @@ static int ena_rss_init_default(struct ena_adapter *adapter) + } + } + +- rc = ena_com_fill_hash_function(ena_dev, ENA_ADMIN_TOEPLITZ, NULL, +- ENA_HASH_KEY_SIZE, 0xFFFFFFFF); ++ rc = ena_com_fill_hash_function(ena_dev, ENA_ADMIN_TOEPLITZ, NULL, ENA_HASH_KEY_SIZE, ++ 0xFFFFFFFF); + if (unlikely(rc && (rc != -EOPNOTSUPP))) { + dev_err(dev, "Cannot fill hash function\n"); + goto err_fill_indir; +diff --git a/drivers/net/ethernet/cisco/enic/enic_main.c b/drivers/net/ethernet/cisco/enic/enic_main.c +index 37bd38d772e80..cccf0db2fb4e5 100644 +--- a/drivers/net/ethernet/cisco/enic/enic_main.c ++++ b/drivers/net/ethernet/cisco/enic/enic_main.c +@@ -1117,18 +1117,30 @@ static int enic_set_vf_port(struct net_device *netdev, int vf, + pp->request = nla_get_u8(port[IFLA_PORT_REQUEST]); + + if (port[IFLA_PORT_PROFILE]) { ++ if (nla_len(port[IFLA_PORT_PROFILE]) != PORT_PROFILE_MAX) { ++ memcpy(pp, &prev_pp, sizeof(*pp)); ++ return -EINVAL; ++ } + pp->set |= ENIC_SET_NAME; + memcpy(pp->name, nla_data(port[IFLA_PORT_PROFILE]), + PORT_PROFILE_MAX); + } + + if (port[IFLA_PORT_INSTANCE_UUID]) { ++ if (nla_len(port[IFLA_PORT_INSTANCE_UUID]) != PORT_UUID_MAX) { ++ memcpy(pp, &prev_pp, sizeof(*pp)); ++ return -EINVAL; ++ } + pp->set |= ENIC_SET_INSTANCE; + memcpy(pp->instance_uuid, + nla_data(port[IFLA_PORT_INSTANCE_UUID]), PORT_UUID_MAX); + } + + if (port[IFLA_PORT_HOST_UUID]) { ++ if (nla_len(port[IFLA_PORT_HOST_UUID]) != PORT_UUID_MAX) { ++ memcpy(pp, &prev_pp, sizeof(*pp)); ++ return -EINVAL; ++ } + pp->set |= ENIC_SET_HOST; + memcpy(pp->host_uuid, + nla_data(port[IFLA_PORT_HOST_UUID]), PORT_UUID_MAX); +diff --git a/drivers/net/ethernet/cortina/gemini.c b/drivers/net/ethernet/cortina/gemini.c +index 636949737d72f..f69d974a23a1f 100644 +--- a/drivers/net/ethernet/cortina/gemini.c ++++ b/drivers/net/ethernet/cortina/gemini.c +@@ -1108,10 +1108,13 @@ static void gmac_tx_irq_enable(struct net_device *netdev, + { + struct gemini_ethernet_port *port = netdev_priv(netdev); + struct gemini_ethernet *geth = port->geth; ++ unsigned long flags; + u32 val, mask; + + netdev_dbg(netdev, "%s device %d\n", __func__, netdev->dev_id); + ++ spin_lock_irqsave(&geth->irq_lock, flags); ++ + mask = GMAC0_IRQ0_TXQ0_INTS << (6 * netdev->dev_id + txq); + + if (en) +@@ -1120,6 +1123,8 @@ static void gmac_tx_irq_enable(struct net_device *netdev, + val = readl(geth->base + GLOBAL_INTERRUPT_ENABLE_0_REG); + val = en ? val | mask : val & ~mask; + writel(val, geth->base + GLOBAL_INTERRUPT_ENABLE_0_REG); ++ ++ spin_unlock_irqrestore(&geth->irq_lock, flags); + } + + static void gmac_tx_irq(struct net_device *netdev, unsigned int txq_num) +@@ -1426,15 +1431,19 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) + union gmac_rxdesc_3 word3; + struct page *page = NULL; + unsigned int page_offs; ++ unsigned long flags; + unsigned short r, w; + union dma_rwptr rw; + dma_addr_t mapping; + int frag_nr = 0; + ++ spin_lock_irqsave(&geth->irq_lock, flags); + rw.bits32 = readl(ptr_reg); + /* Reset interrupt as all packages until here are taken into account */ + writel(DEFAULT_Q0_INT_BIT << netdev->dev_id, + geth->base + GLOBAL_INTERRUPT_STATUS_1_REG); ++ spin_unlock_irqrestore(&geth->irq_lock, flags); ++ + r = rw.bits.rptr; + w = rw.bits.wptr; + +@@ -1737,10 +1746,9 @@ static irqreturn_t gmac_irq(int irq, void *data) + gmac_update_hw_stats(netdev); + + if (val & (GMAC0_RX_OVERRUN_INT_BIT << (netdev->dev_id * 8))) { ++ spin_lock(&geth->irq_lock); + writel(GMAC0_RXDERR_INT_BIT << (netdev->dev_id * 8), + geth->base + GLOBAL_INTERRUPT_STATUS_4_REG); +- +- spin_lock(&geth->irq_lock); + u64_stats_update_begin(&port->ir_stats_syncp); + ++port->stats.rx_fifo_errors; + u64_stats_update_end(&port->ir_stats_syncp); +diff --git a/drivers/net/ethernet/freescale/enetc/enetc.c b/drivers/net/ethernet/freescale/enetc/enetc.c +index b92e3aa7cd041..0f5a4ec505ddb 100644 +--- a/drivers/net/ethernet/freescale/enetc/enetc.c ++++ b/drivers/net/ethernet/freescale/enetc/enetc.c +@@ -2769,7 +2769,7 @@ static int enetc_setup_xdp_prog(struct net_device *ndev, struct bpf_prog *prog, + if (priv->min_num_stack_tx_queues + num_xdp_tx_queues > + priv->num_tx_rings) { + NL_SET_ERR_MSG_FMT_MOD(extack, +- "Reserving %d XDP TXQs does not leave a minimum of %d for stack (total %d)", ++ "Reserving %d XDP TXQs leaves under %d for stack (total %d)", + num_xdp_tx_queues, + priv->min_num_stack_tx_queues, + priv->num_tx_rings); +diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c +index 7ca8cd78d5574..d675f9d5f3612 100644 +--- a/drivers/net/ethernet/freescale/fec_main.c ++++ b/drivers/net/ethernet/freescale/fec_main.c +@@ -3657,29 +3657,6 @@ fec_set_mac_address(struct net_device *ndev, void *p) + return 0; + } + +-#ifdef CONFIG_NET_POLL_CONTROLLER +-/** +- * fec_poll_controller - FEC Poll controller function +- * @dev: The FEC network adapter +- * +- * Polled functionality used by netconsole and others in non interrupt mode +- * +- */ +-static void fec_poll_controller(struct net_device *dev) +-{ +- int i; +- struct fec_enet_private *fep = netdev_priv(dev); +- +- for (i = 0; i < FEC_IRQ_NUM; i++) { +- if (fep->irq[i] > 0) { +- disable_irq(fep->irq[i]); +- fec_enet_interrupt(fep->irq[i], dev); +- enable_irq(fep->irq[i]); +- } +- } +-} +-#endif +- + static inline void fec_enet_set_netdev_features(struct net_device *netdev, + netdev_features_t features) + { +@@ -3986,9 +3963,6 @@ static const struct net_device_ops fec_netdev_ops = { + .ndo_tx_timeout = fec_timeout, + .ndo_set_mac_address = fec_set_mac_address, + .ndo_eth_ioctl = phy_do_ioctl_running, +-#ifdef CONFIG_NET_POLL_CONTROLLER +- .ndo_poll_controller = fec_poll_controller, +-#endif + .ndo_set_features = fec_set_features, + .ndo_bpf = fec_enet_bpf, + .ndo_xdp_xmit = fec_enet_xdp_xmit, +@@ -4139,6 +4113,14 @@ static int fec_enet_init(struct net_device *ndev) + return ret; + } + ++static void fec_enet_deinit(struct net_device *ndev) ++{ ++ struct fec_enet_private *fep = netdev_priv(ndev); ++ ++ netif_napi_del(&fep->napi); ++ fec_enet_free_queue(ndev); ++} ++ + #ifdef CONFIG_OF + static int fec_reset_phy(struct platform_device *pdev) + { +@@ -4535,6 +4517,7 @@ fec_probe(struct platform_device *pdev) + fec_enet_mii_remove(fep); + failed_mii_init: + failed_irq: ++ fec_enet_deinit(ndev); + failed_init: + fec_ptp_stop(pdev); + failed_reset: +@@ -4598,6 +4581,7 @@ fec_drv_remove(struct platform_device *pdev) + pm_runtime_put_noidle(&pdev->dev); + pm_runtime_disable(&pdev->dev); + ++ fec_enet_deinit(ndev); + free_netdev(ndev); + } + +diff --git a/drivers/net/ethernet/freescale/fec_ptp.c b/drivers/net/ethernet/freescale/fec_ptp.c +index 181d9bfbee220..e32f6724f5681 100644 +--- a/drivers/net/ethernet/freescale/fec_ptp.c ++++ b/drivers/net/ethernet/freescale/fec_ptp.c +@@ -104,14 +104,13 @@ static int fec_ptp_enable_pps(struct fec_enet_private *fep, uint enable) + struct timespec64 ts; + u64 ns; + +- if (fep->pps_enable == enable) +- return 0; +- +- fep->pps_channel = DEFAULT_PPS_CHANNEL; +- fep->reload_period = PPS_OUPUT_RELOAD_PERIOD; +- + spin_lock_irqsave(&fep->tmreg_lock, flags); + ++ if (fep->pps_enable == enable) { ++ spin_unlock_irqrestore(&fep->tmreg_lock, flags); ++ return 0; ++ } ++ + if (enable) { + /* clear capture or output compare interrupt status if have. + */ +@@ -532,6 +531,9 @@ static int fec_ptp_enable(struct ptp_clock_info *ptp, + int ret = 0; + + if (rq->type == PTP_CLK_REQ_PPS) { ++ fep->pps_channel = DEFAULT_PPS_CHANNEL; ++ fep->reload_period = PPS_OUPUT_RELOAD_PERIOD; ++ + ret = fec_ptp_enable_pps(fep, on); + + return ret; +diff --git a/drivers/net/ethernet/intel/ice/ice_ethtool.c b/drivers/net/ethernet/intel/ice/ice_ethtool.c +index 9be13e9840917..39b5f24be7e4f 100644 +--- a/drivers/net/ethernet/intel/ice/ice_ethtool.c ++++ b/drivers/net/ethernet/intel/ice/ice_ethtool.c +@@ -3429,7 +3429,6 @@ static int ice_set_channels(struct net_device *dev, struct ethtool_channels *ch) + struct ice_pf *pf = vsi->back; + int new_rx = 0, new_tx = 0; + bool locked = false; +- u32 curr_combined; + int ret = 0; + + /* do not support changing channels in Safe Mode */ +@@ -3451,22 +3450,8 @@ static int ice_set_channels(struct net_device *dev, struct ethtool_channels *ch) + return -EOPNOTSUPP; + } + +- curr_combined = ice_get_combined_cnt(vsi); +- +- /* these checks are for cases where user didn't specify a particular +- * value on cmd line but we get non-zero value anyway via +- * get_channels(); look at ethtool.c in ethtool repository (the user +- * space part), particularly, do_schannels() routine +- */ +- if (ch->rx_count == vsi->num_rxq - curr_combined) +- ch->rx_count = 0; +- if (ch->tx_count == vsi->num_txq - curr_combined) +- ch->tx_count = 0; +- if (ch->combined_count == curr_combined) +- ch->combined_count = 0; +- +- if (!(ch->combined_count || (ch->rx_count && ch->tx_count))) { +- netdev_err(dev, "Please specify at least 1 Rx and 1 Tx channel\n"); ++ if (ch->rx_count && ch->tx_count) { ++ netdev_err(dev, "Dedicated RX or TX channels cannot be used simultaneously\n"); + return -EINVAL; + } + +diff --git a/drivers/net/ethernet/intel/ice/ice_vsi_vlan_lib.c b/drivers/net/ethernet/intel/ice/ice_vsi_vlan_lib.c +index 8307902115ff2..3ecab12baea33 100644 +--- a/drivers/net/ethernet/intel/ice/ice_vsi_vlan_lib.c ++++ b/drivers/net/ethernet/intel/ice/ice_vsi_vlan_lib.c +@@ -45,14 +45,15 @@ int ice_vsi_add_vlan(struct ice_vsi *vsi, struct ice_vlan *vlan) + return -EINVAL; + + err = ice_fltr_add_vlan(vsi, vlan); +- if (err && err != -EEXIST) { ++ if (!err) ++ vsi->num_vlan++; ++ else if (err == -EEXIST) ++ err = 0; ++ else + dev_err(ice_pf_to_dev(vsi->back), "Failure Adding VLAN %d on VSI %i, status %d\n", + vlan->vid, vsi->vsi_num, err); +- return err; +- } + +- vsi->num_vlan++; +- return 0; ++ return err; + } + + /** +diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h +index 61b9774b3d31e..c24a72d1e2737 100644 +--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h ++++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h +@@ -3673,9 +3673,7 @@ struct ixgbe_info { + #define IXGBE_KRM_LINK_S1(P) ((P) ? 0x8200 : 0x4200) + #define IXGBE_KRM_LINK_CTRL_1(P) ((P) ? 0x820C : 0x420C) + #define IXGBE_KRM_AN_CNTL_1(P) ((P) ? 0x822C : 0x422C) +-#define IXGBE_KRM_AN_CNTL_4(P) ((P) ? 0x8238 : 0x4238) + #define IXGBE_KRM_AN_CNTL_8(P) ((P) ? 0x8248 : 0x4248) +-#define IXGBE_KRM_PCS_KX_AN(P) ((P) ? 0x9918 : 0x5918) + #define IXGBE_KRM_SGMII_CTRL(P) ((P) ? 0x82A0 : 0x42A0) + #define IXGBE_KRM_LP_BASE_PAGE_HIGH(P) ((P) ? 0x836C : 0x436C) + #define IXGBE_KRM_DSP_TXFFE_STATE_4(P) ((P) ? 0x8634 : 0x4634) +@@ -3685,7 +3683,6 @@ struct ixgbe_info { + #define IXGBE_KRM_PMD_FLX_MASK_ST20(P) ((P) ? 0x9054 : 0x5054) + #define IXGBE_KRM_TX_COEFF_CTRL_1(P) ((P) ? 0x9520 : 0x5520) + #define IXGBE_KRM_RX_ANA_CTL(P) ((P) ? 0x9A00 : 0x5A00) +-#define IXGBE_KRM_FLX_TMRS_CTRL_ST31(P) ((P) ? 0x9180 : 0x5180) + + #define IXGBE_KRM_PMD_FLX_MASK_ST20_SFI_10G_DA ~(0x3 << 20) + #define IXGBE_KRM_PMD_FLX_MASK_ST20_SFI_10G_SR BIT(20) +diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c +index c1adc94a5a657..f806fbf25ec7c 100644 +--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c ++++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c +@@ -1722,59 +1722,9 @@ static s32 ixgbe_setup_sfi_x550a(struct ixgbe_hw *hw, ixgbe_link_speed *speed) + return -EINVAL; + } + +- (void)mac->ops.write_iosf_sb_reg(hw, +- IXGBE_KRM_PMD_FLX_MASK_ST20(hw->bus.lan_id), +- IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val); +- +- /* change mode enforcement rules to hybrid */ +- (void)mac->ops.read_iosf_sb_reg(hw, +- IXGBE_KRM_FLX_TMRS_CTRL_ST31(hw->bus.lan_id), +- IXGBE_SB_IOSF_TARGET_KR_PHY, ®_val); +- reg_val |= 0x0400; +- +- (void)mac->ops.write_iosf_sb_reg(hw, +- IXGBE_KRM_FLX_TMRS_CTRL_ST31(hw->bus.lan_id), +- IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val); +- +- /* manually control the config */ +- (void)mac->ops.read_iosf_sb_reg(hw, +- IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id), +- IXGBE_SB_IOSF_TARGET_KR_PHY, ®_val); +- reg_val |= 0x20002240; +- +- (void)mac->ops.write_iosf_sb_reg(hw, +- IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id), +- IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val); +- +- /* move the AN base page values */ +- (void)mac->ops.read_iosf_sb_reg(hw, +- IXGBE_KRM_PCS_KX_AN(hw->bus.lan_id), +- IXGBE_SB_IOSF_TARGET_KR_PHY, ®_val); +- reg_val |= 0x1; +- +- (void)mac->ops.write_iosf_sb_reg(hw, +- IXGBE_KRM_PCS_KX_AN(hw->bus.lan_id), +- IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val); +- +- /* set the AN37 over CB mode */ +- (void)mac->ops.read_iosf_sb_reg(hw, +- IXGBE_KRM_AN_CNTL_4(hw->bus.lan_id), +- IXGBE_SB_IOSF_TARGET_KR_PHY, ®_val); +- reg_val |= 0x20000000; +- +- (void)mac->ops.write_iosf_sb_reg(hw, +- IXGBE_KRM_AN_CNTL_4(hw->bus.lan_id), +- IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val); +- +- /* restart AN manually */ +- (void)mac->ops.read_iosf_sb_reg(hw, +- IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id), +- IXGBE_SB_IOSF_TARGET_KR_PHY, ®_val); +- reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_AN_RESTART; +- +- (void)mac->ops.write_iosf_sb_reg(hw, +- IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id), +- IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val); ++ status = mac->ops.write_iosf_sb_reg(hw, ++ IXGBE_KRM_PMD_FLX_MASK_ST20(hw->bus.lan_id), ++ IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val); + + /* Toggle port SW reset by AN reset. */ + status = ixgbe_restart_an_internal_phy_x550em(hw); +diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/qos.c b/drivers/net/ethernet/marvell/octeontx2/nic/qos.c +index 1723e9912ae07..6cddb4da85b71 100644 +--- a/drivers/net/ethernet/marvell/octeontx2/nic/qos.c ++++ b/drivers/net/ethernet/marvell/octeontx2/nic/qos.c +@@ -1407,7 +1407,10 @@ static int otx2_qos_leaf_to_inner(struct otx2_nic *pfvf, u16 classid, + otx2_qos_read_txschq_cfg(pfvf, node, old_cfg); + + /* delete the txschq nodes allocated for this node */ ++ otx2_qos_disable_sq(pfvf, qid); ++ otx2_qos_free_hw_node_schq(pfvf, node); + otx2_qos_free_sw_node_schq(pfvf, node); ++ pfvf->qos.qid_to_sqmap[qid] = OTX2_QOS_INVALID_SQ; + + /* mark this node as htb inner node */ + WRITE_ONCE(node->qid, OTX2_QOS_QID_INNER); +@@ -1554,6 +1557,7 @@ static int otx2_qos_leaf_del_last(struct otx2_nic *pfvf, u16 classid, bool force + dwrr_del_node = true; + + /* destroy the leaf node */ ++ otx2_qos_disable_sq(pfvf, qid); + otx2_qos_destroy_node(pfvf, node); + pfvf->qos.qid_to_sqmap[qid] = OTX2_QOS_INVALID_SQ; + +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c +index 55efb932ab2cf..48dc4ae87af09 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c +@@ -967,19 +967,32 @@ static void cmd_work_handler(struct work_struct *work) + bool poll_cmd = ent->polling; + struct mlx5_cmd_layout *lay; + struct mlx5_core_dev *dev; +- unsigned long cb_timeout; +- struct semaphore *sem; ++ unsigned long timeout; + unsigned long flags; + int alloc_ret; + int cmd_mode; + ++ complete(&ent->handling); ++ + dev = container_of(cmd, struct mlx5_core_dev, cmd); +- cb_timeout = msecs_to_jiffies(mlx5_tout_ms(dev, CMD)); ++ timeout = msecs_to_jiffies(mlx5_tout_ms(dev, CMD)); + +- complete(&ent->handling); +- sem = ent->page_queue ? &cmd->vars.pages_sem : &cmd->vars.sem; +- down(sem); + if (!ent->page_queue) { ++ if (down_timeout(&cmd->vars.sem, timeout)) { ++ mlx5_core_warn(dev, "%s(0x%x) timed out while waiting for a slot.\n", ++ mlx5_command_str(ent->op), ent->op); ++ if (ent->callback) { ++ ent->callback(-EBUSY, ent->context); ++ mlx5_free_cmd_msg(dev, ent->out); ++ free_msg(dev, ent->in); ++ cmd_ent_put(ent); ++ } else { ++ ent->ret = -EBUSY; ++ complete(&ent->done); ++ } ++ complete(&ent->slotted); ++ return; ++ } + alloc_ret = cmd_alloc_index(cmd, ent); + if (alloc_ret < 0) { + mlx5_core_err_rl(dev, "failed to allocate command entry\n"); +@@ -992,10 +1005,11 @@ static void cmd_work_handler(struct work_struct *work) + ent->ret = -EAGAIN; + complete(&ent->done); + } +- up(sem); ++ up(&cmd->vars.sem); + return; + } + } else { ++ down(&cmd->vars.pages_sem); + ent->idx = cmd->vars.max_reg_cmds; + spin_lock_irqsave(&cmd->alloc_lock, flags); + clear_bit(ent->idx, &cmd->vars.bitmask); +@@ -1003,6 +1017,8 @@ static void cmd_work_handler(struct work_struct *work) + spin_unlock_irqrestore(&cmd->alloc_lock, flags); + } + ++ complete(&ent->slotted); ++ + lay = get_inst(cmd, ent->idx); + ent->lay = lay; + memset(lay, 0, sizeof(*lay)); +@@ -1021,7 +1037,7 @@ static void cmd_work_handler(struct work_struct *work) + ent->ts1 = ktime_get_ns(); + cmd_mode = cmd->mode; + +- if (ent->callback && schedule_delayed_work(&ent->cb_timeout_work, cb_timeout)) ++ if (ent->callback && schedule_delayed_work(&ent->cb_timeout_work, timeout)) + cmd_ent_get(ent); + set_bit(MLX5_CMD_ENT_STATE_PENDING_COMP, &ent->state); + +@@ -1141,6 +1157,9 @@ static int wait_func(struct mlx5_core_dev *dev, struct mlx5_cmd_work_ent *ent) + ent->ret = -ECANCELED; + goto out_err; + } ++ ++ wait_for_completion(&ent->slotted); ++ + if (cmd->mode == CMD_MODE_POLLING || ent->polling) + wait_for_completion(&ent->done); + else if (!wait_for_completion_timeout(&ent->done, timeout)) +@@ -1155,6 +1174,9 @@ static int wait_func(struct mlx5_core_dev *dev, struct mlx5_cmd_work_ent *ent) + } else if (err == -ECANCELED) { + mlx5_core_warn(dev, "%s(0x%x) canceled on out of queue timeout.\n", + mlx5_command_str(ent->op), ent->op); ++ } else if (err == -EBUSY) { ++ mlx5_core_warn(dev, "%s(0x%x) timeout while waiting for command semaphore.\n", ++ mlx5_command_str(ent->op), ent->op); + } + mlx5_core_dbg(dev, "err %d, delivery status %s(%d)\n", + err, deliv_status_to_str(ent->status), ent->status); +@@ -1206,6 +1228,7 @@ static int mlx5_cmd_invoke(struct mlx5_core_dev *dev, struct mlx5_cmd_msg *in, + ent->polling = force_polling; + + init_completion(&ent->handling); ++ init_completion(&ent->slotted); + if (!callback) + init_completion(&ent->done); + +@@ -1223,7 +1246,7 @@ static int mlx5_cmd_invoke(struct mlx5_core_dev *dev, struct mlx5_cmd_msg *in, + return 0; /* mlx5_cmd_comp_handler() will put(ent) */ + + err = wait_func(dev, ent); +- if (err == -ETIMEDOUT || err == -ECANCELED) ++ if (err == -ETIMEDOUT || err == -ECANCELED || err == -EBUSY) + goto out_free; + + ds = ent->ts2 - ent->ts1; +@@ -1609,6 +1632,9 @@ static int cmd_comp_notifier(struct notifier_block *nb, + dev = container_of(cmd, struct mlx5_core_dev, cmd); + eqe = data; + ++ if (dev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR) ++ return NOTIFY_DONE; ++ + mlx5_cmd_comp_handler(dev, be32_to_cpu(eqe->data.cmd.vector), false); + + return NOTIFY_OK; +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/xsk/setup.c b/drivers/net/ethernet/mellanox/mlx5/core/en/xsk/setup.c +index 36826b5824847..78739fe138ca4 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/en/xsk/setup.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/en/xsk/setup.c +@@ -28,8 +28,10 @@ bool mlx5e_validate_xsk_param(struct mlx5e_params *params, + struct mlx5e_xsk_param *xsk, + struct mlx5_core_dev *mdev) + { +- /* AF_XDP doesn't support frames larger than PAGE_SIZE. */ +- if (xsk->chunk_size > PAGE_SIZE || xsk->chunk_size < MLX5E_MIN_XSK_CHUNK_SIZE) { ++ /* AF_XDP doesn't support frames larger than PAGE_SIZE, ++ * and xsk->chunk_size is limited to 65535 bytes. ++ */ ++ if ((size_t)xsk->chunk_size > PAGE_SIZE || xsk->chunk_size < MLX5E_MIN_XSK_CHUNK_SIZE) { + mlx5_core_err(mdev, "XSK chunk size %u out of bounds [%u, %lu]\n", xsk->chunk_size, + MLX5E_MIN_XSK_CHUNK_SIZE, PAGE_SIZE); + return false; +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/en_accel.h b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/en_accel.h +index caa34b9c161e5..33e32584b07f5 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/en_accel.h ++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/en_accel.h +@@ -102,8 +102,14 @@ static inline void + mlx5e_udp_gso_handle_tx_skb(struct sk_buff *skb) + { + int payload_len = skb_shinfo(skb)->gso_size + sizeof(struct udphdr); ++ struct udphdr *udphdr; + +- udp_hdr(skb)->len = htons(payload_len); ++ if (skb->encapsulation) ++ udphdr = (struct udphdr *)skb_inner_transport_header(skb); ++ else ++ udphdr = udp_hdr(skb); ++ ++ udphdr->len = htons(payload_len); + } + + struct mlx5e_accel_tx_state { +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_fs.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_fs.c +index 81e6aa6434cf2..61288066830d9 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_fs.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_fs.c +@@ -512,8 +512,7 @@ static int rx_create(struct mlx5_core_dev *mdev, struct mlx5e_ipsec *ipsec, + err_fs_ft: + if (rx->allow_tunnel_mode) + mlx5_eswitch_unblock_encap(mdev); +- mlx5_del_flow_rules(rx->status.rule); +- mlx5_modify_header_dealloc(mdev, rx->status.modify_hdr); ++ mlx5_ipsec_rx_status_destroy(ipsec, rx); + err_add: + mlx5_destroy_flow_table(rx->ft.status); + err_fs_ft_status: +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_rxtx.h b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_rxtx.h +index 9ee014a8ad24a..ff59c6adbb963 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_rxtx.h ++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_rxtx.h +@@ -99,18 +99,11 @@ mlx5e_ipsec_feature_check(struct sk_buff *skb, netdev_features_t features) + if (!x || !x->xso.offload_handle) + goto out_disable; + +- if (xo->inner_ipproto) { +- /* Cannot support tunnel packet over IPsec tunnel mode +- * because we cannot offload three IP header csum +- */ +- if (x->props.mode == XFRM_MODE_TUNNEL) +- goto out_disable; +- +- /* Only support UDP or TCP L4 checksum */ +- if (xo->inner_ipproto != IPPROTO_UDP && +- xo->inner_ipproto != IPPROTO_TCP) +- goto out_disable; +- } ++ /* Only support UDP or TCP L4 checksum */ ++ if (xo->inner_ipproto && ++ xo->inner_ipproto != IPPROTO_UDP && ++ xo->inner_ipproto != IPPROTO_TCP) ++ goto out_disable; + + return features; + +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +index d49c348f89d28..455907b1167a0 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +@@ -3756,7 +3756,7 @@ mlx5e_get_stats(struct net_device *dev, struct rtnl_link_stats64 *stats) + mlx5e_fold_sw_stats64(priv, stats); + } + +- stats->rx_dropped = priv->stats.qcnt.rx_out_of_buffer; ++ stats->rx_missed_errors = priv->stats.qcnt.rx_out_of_buffer; + + stats->rx_length_errors = + PPORT_802_3_GET(pstats, a_in_range_length_errors) + +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c +index 24cbd44dae93c..3001a52e1ac2e 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c +@@ -153,7 +153,11 @@ mlx5e_tx_get_gso_ihs(struct mlx5e_txqsq *sq, struct sk_buff *skb, int *hopbyhop) + + *hopbyhop = 0; + if (skb->encapsulation) { +- ihs = skb_inner_tcp_all_headers(skb); ++ if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_L4) ++ ihs = skb_inner_transport_offset(skb) + ++ sizeof(struct udphdr); ++ else ++ ihs = skb_inner_tcp_all_headers(skb); + stats->tso_inner_packets++; + stats->tso_inner_bytes += skb->len - ihs; + } else { +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/esw/bridge.c b/drivers/net/ethernet/mellanox/mlx5/core/esw/bridge.c +index 1b9bc32efd6fa..c5ea1d1d2b035 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/esw/bridge.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/esw/bridge.c +@@ -1874,7 +1874,7 @@ int mlx5_esw_bridge_port_mdb_add(struct net_device *dev, u16 vport_num, u16 esw_ + "Failed to lookup bridge port vlan metadata to create MDB (MAC=%pM,vid=%u,vport=%u)\n", + addr, vid, vport_num); + NL_SET_ERR_MSG_FMT_MOD(extack, +- "Failed to lookup bridge port vlan metadata to create MDB (MAC=%pM,vid=%u,vport=%u)\n", ++ "Failed to lookup vlan metadata for MDB (MAC=%pM,vid=%u,vport=%u)\n", + addr, vid, vport_num); + return -EINVAL; + } +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h +index b4eb17141edf3..9b771b572593b 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h ++++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h +@@ -840,7 +840,7 @@ int mlx5_eswitch_offloads_single_fdb_add_one(struct mlx5_eswitch *master_esw, + struct mlx5_eswitch *slave_esw, int max_slaves); + void mlx5_eswitch_offloads_single_fdb_del_one(struct mlx5_eswitch *master_esw, + struct mlx5_eswitch *slave_esw); +-int mlx5_eswitch_reload_reps(struct mlx5_eswitch *esw); ++int mlx5_eswitch_reload_ib_reps(struct mlx5_eswitch *esw); + + bool mlx5_eswitch_block_encap(struct mlx5_core_dev *dev); + void mlx5_eswitch_unblock_encap(struct mlx5_core_dev *dev); +@@ -932,7 +932,7 @@ mlx5_eswitch_offloads_single_fdb_del_one(struct mlx5_eswitch *master_esw, + static inline int mlx5_eswitch_get_npeers(struct mlx5_eswitch *esw) { return 0; } + + static inline int +-mlx5_eswitch_reload_reps(struct mlx5_eswitch *esw) ++mlx5_eswitch_reload_ib_reps(struct mlx5_eswitch *esw) + { + return 0; + } +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +index e3cce110e52fd..58529d1a98b37 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +@@ -2501,6 +2501,16 @@ void esw_offloads_cleanup(struct mlx5_eswitch *esw) + esw_offloads_cleanup_reps(esw); + } + ++static int __esw_offloads_load_rep(struct mlx5_eswitch *esw, ++ struct mlx5_eswitch_rep *rep, u8 rep_type) ++{ ++ if (atomic_cmpxchg(&rep->rep_data[rep_type].state, ++ REP_REGISTERED, REP_LOADED) == REP_REGISTERED) ++ return esw->offloads.rep_ops[rep_type]->load(esw->dev, rep); ++ ++ return 0; ++} ++ + static void __esw_offloads_unload_rep(struct mlx5_eswitch *esw, + struct mlx5_eswitch_rep *rep, u8 rep_type) + { +@@ -2525,13 +2535,11 @@ static int mlx5_esw_offloads_rep_load(struct mlx5_eswitch *esw, u16 vport_num) + int err; + + rep = mlx5_eswitch_get_rep(esw, vport_num); +- for (rep_type = 0; rep_type < NUM_REP_TYPES; rep_type++) +- if (atomic_cmpxchg(&rep->rep_data[rep_type].state, +- REP_REGISTERED, REP_LOADED) == REP_REGISTERED) { +- err = esw->offloads.rep_ops[rep_type]->load(esw->dev, rep); +- if (err) +- goto err_reps; +- } ++ for (rep_type = 0; rep_type < NUM_REP_TYPES; rep_type++) { ++ err = __esw_offloads_load_rep(esw, rep, rep_type); ++ if (err) ++ goto err_reps; ++ } + + return 0; + +@@ -3276,7 +3284,7 @@ static void esw_destroy_offloads_acl_tables(struct mlx5_eswitch *esw) + esw_vport_destroy_offloads_acl_tables(esw, vport); + } + +-int mlx5_eswitch_reload_reps(struct mlx5_eswitch *esw) ++int mlx5_eswitch_reload_ib_reps(struct mlx5_eswitch *esw) + { + struct mlx5_eswitch_rep *rep; + unsigned long i; +@@ -3289,13 +3297,13 @@ int mlx5_eswitch_reload_reps(struct mlx5_eswitch *esw) + if (atomic_read(&rep->rep_data[REP_ETH].state) != REP_LOADED) + return 0; + +- ret = mlx5_esw_offloads_rep_load(esw, MLX5_VPORT_UPLINK); ++ ret = __esw_offloads_load_rep(esw, rep, REP_IB); + if (ret) + return ret; + + mlx5_esw_for_each_rep(esw, i, rep) { + if (atomic_read(&rep->rep_data[REP_ETH].state) == REP_LOADED) +- mlx5_esw_offloads_rep_load(esw, rep->vport); ++ __esw_offloads_load_rep(esw, rep, REP_IB); + } + + return 0; +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c +index e51cac1e1811e..dfc2ba6f780a2 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c +@@ -720,6 +720,7 @@ bool mlx5_lag_check_prereq(struct mlx5_lag *ldev) + struct mlx5_core_dev *dev; + u8 mode; + #endif ++ bool roce_support; + int i; + + for (i = 0; i < ldev->ports; i++) +@@ -746,6 +747,11 @@ bool mlx5_lag_check_prereq(struct mlx5_lag *ldev) + if (mlx5_sriov_is_enabled(ldev->pf[i].dev)) + return false; + #endif ++ roce_support = mlx5_get_roce_state(ldev->pf[MLX5_LAG_P1].dev); ++ for (i = 1; i < ldev->ports; i++) ++ if (mlx5_get_roce_state(ldev->pf[i].dev) != roce_support) ++ return false; ++ + return true; + } + +@@ -814,7 +820,7 @@ void mlx5_disable_lag(struct mlx5_lag *ldev) + if (shared_fdb) + for (i = 0; i < ldev->ports; i++) + if (!(ldev->pf[i].dev->priv.flags & MLX5_PRIV_FLAGS_DISABLE_ALL_ADEV)) +- mlx5_eswitch_reload_reps(ldev->pf[i].dev->priv.eswitch); ++ mlx5_eswitch_reload_ib_reps(ldev->pf[i].dev->priv.eswitch); + } + + static bool mlx5_shared_fdb_supported(struct mlx5_lag *ldev) +@@ -913,8 +919,10 @@ static void mlx5_do_bond(struct mlx5_lag *ldev) + } else if (roce_lag) { + dev0->priv.flags &= ~MLX5_PRIV_FLAGS_DISABLE_IB_ADEV; + mlx5_rescan_drivers_locked(dev0); +- for (i = 1; i < ldev->ports; i++) +- mlx5_nic_vport_enable_roce(ldev->pf[i].dev); ++ for (i = 1; i < ldev->ports; i++) { ++ if (mlx5_get_roce_state(ldev->pf[i].dev)) ++ mlx5_nic_vport_enable_roce(ldev->pf[i].dev); ++ } + } else if (shared_fdb) { + int i; + +@@ -922,7 +930,7 @@ static void mlx5_do_bond(struct mlx5_lag *ldev) + mlx5_rescan_drivers_locked(dev0); + + for (i = 0; i < ldev->ports; i++) { +- err = mlx5_eswitch_reload_reps(ldev->pf[i].dev->priv.eswitch); ++ err = mlx5_eswitch_reload_ib_reps(ldev->pf[i].dev->priv.eswitch); + if (err) + break; + } +@@ -933,7 +941,7 @@ static void mlx5_do_bond(struct mlx5_lag *ldev) + mlx5_deactivate_lag(ldev); + mlx5_lag_add_devices(ldev); + for (i = 0; i < ldev->ports; i++) +- mlx5_eswitch_reload_reps(ldev->pf[i].dev->priv.eswitch); ++ mlx5_eswitch_reload_ib_reps(ldev->pf[i].dev->priv.eswitch); + mlx5_core_err(dev0, "Failed to enable lag\n"); + return; + } +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/mpesw.c b/drivers/net/ethernet/mellanox/mlx5/core/lag/mpesw.c +index 4bf15391525c5..6b0413a3987ce 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/lag/mpesw.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/mpesw.c +@@ -65,12 +65,12 @@ static int mlx5_mpesw_metadata_set(struct mlx5_lag *ldev) + return err; + } + +-#define MLX5_LAG_MPESW_OFFLOADS_SUPPORTED_PORTS 2 ++#define MLX5_LAG_MPESW_OFFLOADS_SUPPORTED_PORTS 4 + static int enable_mpesw(struct mlx5_lag *ldev) + { + struct mlx5_core_dev *dev0 = ldev->pf[MLX5_LAG_P1].dev; +- struct mlx5_core_dev *dev1 = ldev->pf[MLX5_LAG_P2].dev; + int err; ++ int i; + + if (ldev->mode != MLX5_LAG_MODE_NONE) + return -EINVAL; +@@ -98,11 +98,11 @@ static int enable_mpesw(struct mlx5_lag *ldev) + + dev0->priv.flags &= ~MLX5_PRIV_FLAGS_DISABLE_IB_ADEV; + mlx5_rescan_drivers_locked(dev0); +- err = mlx5_eswitch_reload_reps(dev0->priv.eswitch); +- if (!err) +- err = mlx5_eswitch_reload_reps(dev1->priv.eswitch); +- if (err) +- goto err_rescan_drivers; ++ for (i = 0; i < ldev->ports; i++) { ++ err = mlx5_eswitch_reload_ib_reps(ldev->pf[i].dev->priv.eswitch); ++ if (err) ++ goto err_rescan_drivers; ++ } + + return 0; + +@@ -112,8 +112,8 @@ static int enable_mpesw(struct mlx5_lag *ldev) + mlx5_deactivate_lag(ldev); + err_add_devices: + mlx5_lag_add_devices(ldev); +- mlx5_eswitch_reload_reps(dev0->priv.eswitch); +- mlx5_eswitch_reload_reps(dev1->priv.eswitch); ++ for (i = 0; i < ldev->ports; i++) ++ mlx5_eswitch_reload_ib_reps(ldev->pf[i].dev->priv.eswitch); + mlx5_mpesw_metadata_cleanup(ldev); + return err; + } +diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_main.c b/drivers/net/ethernet/microchip/lan966x/lan966x_main.c +index 0d6e79af24106..c3f6c10bc2393 100644 +--- a/drivers/net/ethernet/microchip/lan966x/lan966x_main.c ++++ b/drivers/net/ethernet/microchip/lan966x/lan966x_main.c +@@ -474,14 +474,14 @@ static int lan966x_port_hwtstamp_set(struct net_device *dev, + cfg->source != HWTSTAMP_SOURCE_PHYLIB) + return -EOPNOTSUPP; + ++ if (cfg->source == HWTSTAMP_SOURCE_NETDEV && !port->lan966x->ptp) ++ return -EOPNOTSUPP; ++ + err = lan966x_ptp_setup_traps(port, cfg); + if (err) + return err; + + if (cfg->source == HWTSTAMP_SOURCE_NETDEV) { +- if (!port->lan966x->ptp) +- return -EOPNOTSUPP; +- + err = lan966x_ptp_hwtstamp_set(port, cfg, extack); + if (err) { + lan966x_ptp_del_traps(port); +@@ -1088,8 +1088,6 @@ static int lan966x_probe(struct platform_device *pdev) + platform_set_drvdata(pdev, lan966x); + lan966x->dev = &pdev->dev; + +- lan966x->debugfs_root = debugfs_create_dir("lan966x", NULL); +- + if (!device_get_mac_address(&pdev->dev, mac_addr)) { + ether_addr_copy(lan966x->base_mac, mac_addr); + } else { +@@ -1180,6 +1178,8 @@ static int lan966x_probe(struct platform_device *pdev) + return dev_err_probe(&pdev->dev, -ENODEV, + "no ethernet-ports child found\n"); + ++ lan966x->debugfs_root = debugfs_create_dir("lan966x", NULL); ++ + /* init switch */ + lan966x_init(lan966x); + lan966x_stats_init(lan966x); +@@ -1258,6 +1258,8 @@ static int lan966x_probe(struct platform_device *pdev) + destroy_workqueue(lan966x->stats_queue); + mutex_destroy(&lan966x->stats_lock); + ++ debugfs_remove_recursive(lan966x->debugfs_root); ++ + return err; + } + +diff --git a/drivers/net/ethernet/microsoft/mana/hw_channel.c b/drivers/net/ethernet/microsoft/mana/hw_channel.c +index 9d1cd3bfcf662..01fed4fe84185 100644 +--- a/drivers/net/ethernet/microsoft/mana/hw_channel.c ++++ b/drivers/net/ethernet/microsoft/mana/hw_channel.c +@@ -847,7 +847,7 @@ int mana_hwc_send_request(struct hw_channel_context *hwc, u32 req_len, + } + + if (!wait_for_completion_timeout(&ctx->comp_event, +- (msecs_to_jiffies(hwc->hwc_timeout) * HZ))) { ++ (msecs_to_jiffies(hwc->hwc_timeout)))) { + dev_err(hwc->dev, "HWC: Request timed out!\n"); + err = -ETIMEDOUT; + goto out; +diff --git a/drivers/net/ethernet/qlogic/qed/qed_main.c b/drivers/net/ethernet/qlogic/qed/qed_main.c +index c278f8893042b..8159b4c315b5d 100644 +--- a/drivers/net/ethernet/qlogic/qed/qed_main.c ++++ b/drivers/net/ethernet/qlogic/qed/qed_main.c +@@ -1206,7 +1206,6 @@ static void qed_slowpath_task(struct work_struct *work) + static int qed_slowpath_wq_start(struct qed_dev *cdev) + { + struct qed_hwfn *hwfn; +- char name[NAME_SIZE]; + int i; + + if (IS_VF(cdev)) +@@ -1215,11 +1214,11 @@ static int qed_slowpath_wq_start(struct qed_dev *cdev) + for_each_hwfn(cdev, i) { + hwfn = &cdev->hwfns[i]; + +- snprintf(name, NAME_SIZE, "slowpath-%02x:%02x.%02x", +- cdev->pdev->bus->number, +- PCI_SLOT(cdev->pdev->devfn), hwfn->abs_pf_id); ++ hwfn->slowpath_wq = alloc_workqueue("slowpath-%02x:%02x.%02x", ++ 0, 0, cdev->pdev->bus->number, ++ PCI_SLOT(cdev->pdev->devfn), ++ hwfn->abs_pf_id); + +- hwfn->slowpath_wq = alloc_workqueue(name, 0, 0); + if (!hwfn->slowpath_wq) { + DP_NOTICE(hwfn, "Cannot create slowpath workqueue\n"); + return -ENOMEM; +diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c +index e6f1da66c4500..d759f3373b175 100644 +--- a/drivers/net/ethernet/realtek/r8169_main.c ++++ b/drivers/net/ethernet/realtek/r8169_main.c +@@ -4246,11 +4246,11 @@ static void rtl8169_doorbell(struct rtl8169_private *tp) + static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb, + struct net_device *dev) + { +- unsigned int frags = skb_shinfo(skb)->nr_frags; + struct rtl8169_private *tp = netdev_priv(dev); + unsigned int entry = tp->cur_tx % NUM_TX_DESC; + struct TxDesc *txd_first, *txd_last; + bool stop_queue, door_bell; ++ unsigned int frags; + u32 opts[2]; + + if (unlikely(!rtl_tx_slots_avail(tp))) { +@@ -4273,6 +4273,7 @@ static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb, + + txd_first = tp->TxDescArray + entry; + ++ frags = skb_shinfo(skb)->nr_frags; + if (frags) { + if (rtl8169_xmit_frags(tp, skb, opts, entry)) + goto err_dma_1; +@@ -4566,10 +4567,8 @@ static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance) + rtl_schedule_task(tp, RTL_FLAG_TASK_RESET_PENDING); + } + +- if (napi_schedule_prep(&tp->napi)) { +- rtl_irq_disable(tp); +- __napi_schedule(&tp->napi); +- } ++ rtl_irq_disable(tp); ++ napi_schedule(&tp->napi); + out: + rtl_ack_events(tp, status); + +diff --git a/drivers/net/ethernet/smsc/smc91x.h b/drivers/net/ethernet/smsc/smc91x.h +index c521ea8f94f2f..9c74d25421414 100644 +--- a/drivers/net/ethernet/smsc/smc91x.h ++++ b/drivers/net/ethernet/smsc/smc91x.h +@@ -175,8 +175,8 @@ static inline void mcf_outsw(void *a, unsigned char *p, int l) + writew(*wp++, a); + } + +-#define SMC_inw(a, r) _swapw(readw((a) + (r))) +-#define SMC_outw(lp, v, a, r) writew(_swapw(v), (a) + (r)) ++#define SMC_inw(a, r) ioread16be((a) + (r)) ++#define SMC_outw(lp, v, a, r) iowrite16be(v, (a) + (r)) + #define SMC_insw(a, r, p, l) mcf_insw(a + r, p, l) + #define SMC_outsw(a, r, p, l) mcf_outsw(a + r, p, l) + +diff --git a/drivers/net/ethernet/sun/sungem.c b/drivers/net/ethernet/sun/sungem.c +index 9bd1df8308d24..d3a2fbb14140e 100644 +--- a/drivers/net/ethernet/sun/sungem.c ++++ b/drivers/net/ethernet/sun/sungem.c +@@ -949,17 +949,6 @@ static irqreturn_t gem_interrupt(int irq, void *dev_id) + return IRQ_HANDLED; + } + +-#ifdef CONFIG_NET_POLL_CONTROLLER +-static void gem_poll_controller(struct net_device *dev) +-{ +- struct gem *gp = netdev_priv(dev); +- +- disable_irq(gp->pdev->irq); +- gem_interrupt(gp->pdev->irq, dev); +- enable_irq(gp->pdev->irq); +-} +-#endif +- + static void gem_tx_timeout(struct net_device *dev, unsigned int txqueue) + { + struct gem *gp = netdev_priv(dev); +@@ -2839,9 +2828,6 @@ static const struct net_device_ops gem_netdev_ops = { + .ndo_change_mtu = gem_change_mtu, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = gem_set_mac_address, +-#ifdef CONFIG_NET_POLL_CONTROLLER +- .ndo_poll_controller = gem_poll_controller, +-#endif + }; + + static int gem_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) +diff --git a/drivers/net/ethernet/ti/icssg/icssg_classifier.c b/drivers/net/ethernet/ti/icssg/icssg_classifier.c +index 6df53ab17fbc5..902a2717785cb 100644 +--- a/drivers/net/ethernet/ti/icssg/icssg_classifier.c ++++ b/drivers/net/ethernet/ti/icssg/icssg_classifier.c +@@ -360,7 +360,7 @@ void icssg_ft1_set_mac_addr(struct regmap *miig_rt, int slice, u8 *mac_addr) + { + const u8 mask_addr[] = { 0, 0, 0, 0, 0, 0, }; + +- rx_class_ft1_set_start_len(miig_rt, slice, 0, 6); ++ rx_class_ft1_set_start_len(miig_rt, slice, ETH_ALEN, ETH_ALEN); + rx_class_ft1_set_da(miig_rt, slice, 0, mac_addr); + rx_class_ft1_set_da_mask(miig_rt, slice, 0, mask_addr); + rx_class_ft1_cfg_set_type(miig_rt, slice, 0, FT1_CFG_TYPE_EQ); +diff --git a/drivers/net/ethernet/ti/icssg/icssg_prueth.c b/drivers/net/ethernet/ti/icssg/icssg_prueth.c +index 925044c16c6ae..fb120baee5532 100644 +--- a/drivers/net/ethernet/ti/icssg/icssg_prueth.c ++++ b/drivers/net/ethernet/ti/icssg/icssg_prueth.c +@@ -2136,7 +2136,12 @@ static int prueth_probe(struct platform_device *pdev) + + prueth->registered_netdevs[PRUETH_MAC0] = prueth->emac[PRUETH_MAC0]->ndev; + +- emac_phy_connect(prueth->emac[PRUETH_MAC0]); ++ ret = emac_phy_connect(prueth->emac[PRUETH_MAC0]); ++ if (ret) { ++ dev_err(dev, ++ "can't connect to MII0 PHY, error -%d", ret); ++ goto netdev_unregister; ++ } + phy_attached_info(prueth->emac[PRUETH_MAC0]->ndev->phydev); + } + +@@ -2148,7 +2153,12 @@ static int prueth_probe(struct platform_device *pdev) + } + + prueth->registered_netdevs[PRUETH_MAC1] = prueth->emac[PRUETH_MAC1]->ndev; +- emac_phy_connect(prueth->emac[PRUETH_MAC1]); ++ ret = emac_phy_connect(prueth->emac[PRUETH_MAC1]); ++ if (ret) { ++ dev_err(dev, ++ "can't connect to MII1 PHY, error %d", ret); ++ goto netdev_unregister; ++ } + phy_attached_info(prueth->emac[PRUETH_MAC1]->ndev->phydev); + } + +diff --git a/drivers/net/ethernet/wangxun/libwx/wx_lib.c b/drivers/net/ethernet/wangxun/libwx/wx_lib.c +index be434c833c69c..e9310d9ca67c9 100644 +--- a/drivers/net/ethernet/wangxun/libwx/wx_lib.c ++++ b/drivers/net/ethernet/wangxun/libwx/wx_lib.c +@@ -2646,12 +2646,14 @@ int wx_set_features(struct net_device *netdev, netdev_features_t features) + else + wr32m(wx, WX_RDB_RA_CTL, WX_RDB_RA_CTL_RSS_EN, 0); + ++ netdev->features = features; ++ + if (changed & + (NETIF_F_HW_VLAN_CTAG_RX | + NETIF_F_HW_VLAN_STAG_RX)) + wx_set_rx_mode(netdev); + +- return 1; ++ return 0; + } + EXPORT_SYMBOL(wx_set_features); + +diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c +index ad5c213dac077..4159c84035fdc 100644 +--- a/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c ++++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c +@@ -20,8 +20,6 @@ + #include "txgbe_phy.h" + #include "txgbe_hw.h" + +-#define TXGBE_I2C_CLK_DEV_NAME "i2c_dw" +- + static int txgbe_swnodes_register(struct txgbe *txgbe) + { + struct txgbe_nodes *nodes = &txgbe->nodes; +@@ -553,8 +551,8 @@ static int txgbe_clock_register(struct txgbe *txgbe) + char clk_name[32]; + struct clk *clk; + +- snprintf(clk_name, sizeof(clk_name), "%s.%d", +- TXGBE_I2C_CLK_DEV_NAME, pci_dev_id(pdev)); ++ snprintf(clk_name, sizeof(clk_name), "i2c_designware.%d", ++ pci_dev_id(pdev)); + + clk = clk_register_fixed_rate(NULL, clk_name, NULL, 0, 156250000); + if (IS_ERR(clk)) +@@ -616,7 +614,7 @@ static int txgbe_i2c_register(struct txgbe *txgbe) + + info.parent = &pdev->dev; + info.fwnode = software_node_fwnode(txgbe->nodes.group[SWNODE_I2C]); +- info.name = TXGBE_I2C_CLK_DEV_NAME; ++ info.name = "i2c_designware"; + info.id = pci_dev_id(pdev); + + info.res = &DEFINE_RES_IRQ(pdev->irq); +diff --git a/drivers/net/ipvlan/ipvlan_core.c b/drivers/net/ipvlan/ipvlan_core.c +index 2d5b021b4ea60..fef4eff7753a7 100644 +--- a/drivers/net/ipvlan/ipvlan_core.c ++++ b/drivers/net/ipvlan/ipvlan_core.c +@@ -439,7 +439,7 @@ static noinline_for_stack int ipvlan_process_v4_outbound(struct sk_buff *skb) + + memset(IPCB(skb), 0, sizeof(*IPCB(skb))); + +- err = ip_local_out(net, skb->sk, skb); ++ err = ip_local_out(net, NULL, skb); + if (unlikely(net_xmit_eval(err))) + DEV_STATS_INC(dev, tx_errors); + else +@@ -494,7 +494,7 @@ static int ipvlan_process_v6_outbound(struct sk_buff *skb) + + memset(IP6CB(skb), 0, sizeof(*IP6CB(skb))); + +- err = ip6_local_out(dev_net(dev), skb->sk, skb); ++ err = ip6_local_out(dev_net(dev), NULL, skb); + if (unlikely(net_xmit_eval(err))) + DEV_STATS_INC(dev, tx_errors); + else +diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c +index cbd98ea4a84af..fc31fcfb0cdb4 100644 +--- a/drivers/net/phy/micrel.c ++++ b/drivers/net/phy/micrel.c +@@ -3450,7 +3450,7 @@ static int lan8841_config_intr(struct phy_device *phydev) + + if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { + err = phy_read(phydev, LAN8814_INTS); +- if (err) ++ if (err < 0) + return err; + + /* Enable / disable interrupts. It is OK to enable PTP interrupt +@@ -3466,6 +3466,14 @@ static int lan8841_config_intr(struct phy_device *phydev) + return err; + + err = phy_read(phydev, LAN8814_INTS); ++ if (err < 0) ++ return err; ++ ++ /* Getting a positive value doesn't mean that is an error, it ++ * just indicates what was the status. Therefore make sure to ++ * clear the value and say that there is no error. ++ */ ++ err = 0; + } + + return err; +@@ -4612,7 +4620,8 @@ static int lan8841_suspend(struct phy_device *phydev) + struct kszphy_priv *priv = phydev->priv; + struct kszphy_ptp_priv *ptp_priv = &priv->ptp_priv; + +- ptp_cancel_worker_sync(ptp_priv->ptp_clock); ++ if (ptp_priv->ptp_clock) ++ ptp_cancel_worker_sync(ptp_priv->ptp_clock); + + return genphy_suspend(phydev); + } +@@ -4749,6 +4758,7 @@ static struct phy_driver ksphy_driver[] = { + /* PHY_BASIC_FEATURES */ + .probe = kszphy_probe, + .config_init = ksz8061_config_init, ++ .soft_reset = genphy_soft_reset, + .config_intr = kszphy_config_intr, + .handle_interrupt = kszphy_handle_interrupt, + .suspend = kszphy_suspend, +diff --git a/drivers/net/usb/aqc111.c b/drivers/net/usb/aqc111.c +index 7b8afa589a53c..284375f662f1e 100644 +--- a/drivers/net/usb/aqc111.c ++++ b/drivers/net/usb/aqc111.c +@@ -1141,17 +1141,15 @@ static int aqc111_rx_fixup(struct usbnet *dev, struct sk_buff *skb) + continue; + } + +- /* Clone SKB */ +- new_skb = skb_clone(skb, GFP_ATOMIC); ++ new_skb = netdev_alloc_skb_ip_align(dev->net, pkt_len); + + if (!new_skb) + goto err; + +- new_skb->len = pkt_len; ++ skb_put(new_skb, pkt_len); ++ memcpy(new_skb->data, skb->data, pkt_len); + skb_pull(new_skb, AQ_RX_HW_PAD); +- skb_set_tail_pointer(new_skb, new_skb->len); + +- new_skb->truesize = SKB_TRUESIZE(new_skb->len); + if (aqc111_data->rx_checksum) + aqc111_rx_checksum(new_skb, pkt_desc); + +diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c +index edc34402e787f..a5469cf5cf670 100644 +--- a/drivers/net/usb/qmi_wwan.c ++++ b/drivers/net/usb/qmi_wwan.c +@@ -1368,6 +1368,9 @@ static const struct usb_device_id products[] = { + {QMI_QUIRK_SET_DTR(0x1bc7, 0x1060, 2)}, /* Telit LN920 */ + {QMI_QUIRK_SET_DTR(0x1bc7, 0x1070, 2)}, /* Telit FN990 */ + {QMI_QUIRK_SET_DTR(0x1bc7, 0x1080, 2)}, /* Telit FE990 */ ++ {QMI_QUIRK_SET_DTR(0x1bc7, 0x10a0, 0)}, /* Telit FN920C04 */ ++ {QMI_QUIRK_SET_DTR(0x1bc7, 0x10a4, 0)}, /* Telit FN920C04 */ ++ {QMI_QUIRK_SET_DTR(0x1bc7, 0x10a9, 0)}, /* Telit FN920C04 */ + {QMI_FIXED_INTF(0x1bc7, 0x1100, 3)}, /* Telit ME910 */ + {QMI_FIXED_INTF(0x1bc7, 0x1101, 3)}, /* Telit ME910 dual modem */ + {QMI_FIXED_INTF(0x1bc7, 0x1200, 5)}, /* Telit LE920 */ +diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c +index 2fa46baa589e5..8e82184be5e7d 100644 +--- a/drivers/net/usb/smsc95xx.c ++++ b/drivers/net/usb/smsc95xx.c +@@ -879,7 +879,7 @@ static int smsc95xx_start_rx_path(struct usbnet *dev) + static int smsc95xx_reset(struct usbnet *dev) + { + struct smsc95xx_priv *pdata = dev->driver_priv; +- u32 read_buf, write_buf, burst_cap; ++ u32 read_buf, burst_cap; + int ret = 0, timeout; + + netif_dbg(dev, ifup, dev->net, "entering smsc95xx_reset\n"); +@@ -1003,10 +1003,13 @@ static int smsc95xx_reset(struct usbnet *dev) + return ret; + netif_dbg(dev, ifup, dev->net, "ID_REV = 0x%08x\n", read_buf); + ++ ret = smsc95xx_read_reg(dev, LED_GPIO_CFG, &read_buf); ++ if (ret < 0) ++ return ret; + /* Configure GPIO pins as LED outputs */ +- write_buf = LED_GPIO_CFG_SPD_LED | LED_GPIO_CFG_LNK_LED | +- LED_GPIO_CFG_FDX_LED; +- ret = smsc95xx_write_reg(dev, LED_GPIO_CFG, write_buf); ++ read_buf |= LED_GPIO_CFG_SPD_LED | LED_GPIO_CFG_LNK_LED | ++ LED_GPIO_CFG_FDX_LED; ++ ret = smsc95xx_write_reg(dev, LED_GPIO_CFG, read_buf); + if (ret < 0) + return ret; + +@@ -1810,9 +1813,11 @@ static int smsc95xx_reset_resume(struct usb_interface *intf) + + static void smsc95xx_rx_csum_offload(struct sk_buff *skb) + { +- skb->csum = *(u16 *)(skb_tail_pointer(skb) - 2); ++ u16 *csum_ptr = (u16 *)(skb_tail_pointer(skb) - 2); ++ ++ skb->csum = (__force __wsum)get_unaligned(csum_ptr); + skb->ip_summed = CHECKSUM_COMPLETE; +- skb_trim(skb, skb->len - 2); ++ skb_trim(skb, skb->len - 2); /* remove csum */ + } + + static int smsc95xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb) +@@ -1870,25 +1875,22 @@ static int smsc95xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb) + if (dev->net->features & NETIF_F_RXCSUM) + smsc95xx_rx_csum_offload(skb); + skb_trim(skb, skb->len - 4); /* remove fcs */ +- skb->truesize = size + sizeof(struct sk_buff); + + return 1; + } + +- ax_skb = skb_clone(skb, GFP_ATOMIC); ++ ax_skb = netdev_alloc_skb_ip_align(dev->net, size); + if (unlikely(!ax_skb)) { + netdev_warn(dev->net, "Error allocating skb\n"); + return 0; + } + +- ax_skb->len = size; +- ax_skb->data = packet; +- skb_set_tail_pointer(ax_skb, size); ++ skb_put(ax_skb, size); ++ memcpy(ax_skb->data, packet, size); + + if (dev->net->features & NETIF_F_RXCSUM) + smsc95xx_rx_csum_offload(ax_skb); + skb_trim(ax_skb, ax_skb->len - 4); /* remove fcs */ +- ax_skb->truesize = size + sizeof(struct sk_buff); + + usbnet_skb_return(dev, ax_skb); + } +diff --git a/drivers/net/usb/sr9700.c b/drivers/net/usb/sr9700.c +index 3164451e1010c..0a662e42ed965 100644 +--- a/drivers/net/usb/sr9700.c ++++ b/drivers/net/usb/sr9700.c +@@ -421,19 +421,15 @@ static int sr9700_rx_fixup(struct usbnet *dev, struct sk_buff *skb) + skb_pull(skb, 3); + skb->len = len; + skb_set_tail_pointer(skb, len); +- skb->truesize = len + sizeof(struct sk_buff); + return 2; + } + +- /* skb_clone is used for address align */ +- sr_skb = skb_clone(skb, GFP_ATOMIC); ++ sr_skb = netdev_alloc_skb_ip_align(dev->net, len); + if (!sr_skb) + return 0; + +- sr_skb->len = len; +- sr_skb->data = skb->data + 3; +- skb_set_tail_pointer(sr_skb, len); +- sr_skb->truesize = len + sizeof(struct sk_buff); ++ skb_put(sr_skb, len); ++ memcpy(sr_skb->data, skb->data + 3, len); + usbnet_skb_return(dev, sr_skb); + + skb_pull(skb, len + SR_RX_OVERHEAD); +diff --git a/drivers/net/wireless/ath/ar5523/ar5523.c b/drivers/net/wireless/ath/ar5523/ar5523.c +index 19f61225a7085..5d82edf8a59d5 100644 +--- a/drivers/net/wireless/ath/ar5523/ar5523.c ++++ b/drivers/net/wireless/ath/ar5523/ar5523.c +@@ -1590,6 +1590,20 @@ static int ar5523_probe(struct usb_interface *intf, + struct ar5523 *ar; + int error = -ENOMEM; + ++ static const u8 bulk_ep_addr[] = { ++ AR5523_CMD_TX_PIPE | USB_DIR_OUT, ++ AR5523_DATA_TX_PIPE | USB_DIR_OUT, ++ AR5523_CMD_RX_PIPE | USB_DIR_IN, ++ AR5523_DATA_RX_PIPE | USB_DIR_IN, ++ 0}; ++ ++ if (!usb_check_bulk_endpoints(intf, bulk_ep_addr)) { ++ dev_err(&dev->dev, ++ "Could not find all expected endpoints\n"); ++ error = -ENODEV; ++ goto out; ++ } ++ + /* + * Load firmware if the device requires it. This will return + * -ENXIO on success and we'll get called back afer the usb +diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c +index 6cdb225b7eacc..81058be3598f1 100644 +--- a/drivers/net/wireless/ath/ath10k/core.c ++++ b/drivers/net/wireless/ath/ath10k/core.c +@@ -704,6 +704,9 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { + .max_spatial_stream = 4, + .fw = { + .dir = WCN3990_HW_1_0_FW_DIR, ++ .board = WCN3990_HW_1_0_BOARD_DATA_FILE, ++ .board_size = WCN3990_BOARD_DATA_SZ, ++ .board_ext_size = WCN3990_BOARD_EXT_DATA_SZ, + }, + .sw_decrypt_mcast_mgmt = true, + .rx_desc_ops = &wcn3990_rx_desc_ops, +diff --git a/drivers/net/wireless/ath/ath10k/debugfs_sta.c b/drivers/net/wireless/ath/ath10k/debugfs_sta.c +index 87a3365330ff8..5598cf706daab 100644 +--- a/drivers/net/wireless/ath/ath10k/debugfs_sta.c ++++ b/drivers/net/wireless/ath/ath10k/debugfs_sta.c +@@ -438,7 +438,7 @@ ath10k_dbg_sta_write_peer_debug_trigger(struct file *file, + } + out: + mutex_unlock(&ar->conf_mutex); +- return count; ++ return ret ?: count; + } + + static const struct file_operations fops_peer_debug_trigger = { +diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h +index 9643031a4427a..7ecdd0011cfa4 100644 +--- a/drivers/net/wireless/ath/ath10k/hw.h ++++ b/drivers/net/wireless/ath/ath10k/hw.h +@@ -132,6 +132,7 @@ enum qca9377_chip_id_rev { + /* WCN3990 1.0 definitions */ + #define WCN3990_HW_1_0_DEV_VERSION ATH10K_HW_WCN3990 + #define WCN3990_HW_1_0_FW_DIR ATH10K_FW_DIR "/WCN3990/hw1.0" ++#define WCN3990_HW_1_0_BOARD_DATA_FILE "board.bin" + + #define ATH10K_FW_FILE_BASE "firmware" + #define ATH10K_FW_API_MAX 6 +diff --git a/drivers/net/wireless/ath/ath10k/targaddrs.h b/drivers/net/wireless/ath/ath10k/targaddrs.h +index ec556bb88d658..ba37e6c7ced08 100644 +--- a/drivers/net/wireless/ath/ath10k/targaddrs.h ++++ b/drivers/net/wireless/ath/ath10k/targaddrs.h +@@ -491,4 +491,7 @@ struct host_interest { + #define QCA4019_BOARD_DATA_SZ 12064 + #define QCA4019_BOARD_EXT_DATA_SZ 0 + ++#define WCN3990_BOARD_DATA_SZ 26328 ++#define WCN3990_BOARD_EXT_DATA_SZ 0 ++ + #endif /* __TARGADDRS_H__ */ +diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c +index 05fa7d4c0e1ab..ee08a4c668f7a 100644 +--- a/drivers/net/wireless/ath/ath10k/wmi.c ++++ b/drivers/net/wireless/ath/ath10k/wmi.c +@@ -1762,12 +1762,32 @@ void ath10k_wmi_put_wmi_channel(struct ath10k *ar, struct wmi_channel *ch, + + int ath10k_wmi_wait_for_service_ready(struct ath10k *ar) + { +- unsigned long time_left; ++ unsigned long time_left, i; + + time_left = wait_for_completion_timeout(&ar->wmi.service_ready, + WMI_SERVICE_READY_TIMEOUT_HZ); +- if (!time_left) +- return -ETIMEDOUT; ++ if (!time_left) { ++ /* Sometimes the PCI HIF doesn't receive interrupt ++ * for the service ready message even if the buffer ++ * was completed. PCIe sniffer shows that it's ++ * because the corresponding CE ring doesn't fires ++ * it. Workaround here by polling CE rings once. ++ */ ++ ath10k_warn(ar, "failed to receive service ready completion, polling..\n"); ++ ++ for (i = 0; i < CE_COUNT; i++) ++ ath10k_hif_send_complete_check(ar, i, 1); ++ ++ time_left = wait_for_completion_timeout(&ar->wmi.service_ready, ++ WMI_SERVICE_READY_TIMEOUT_HZ); ++ if (!time_left) { ++ ath10k_warn(ar, "polling timed out\n"); ++ return -ETIMEDOUT; ++ } ++ ++ ath10k_warn(ar, "service ready completion received, continuing normally\n"); ++ } ++ + return 0; + } + +diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c +index b75cb49c27466..445f59ad1fc08 100644 +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -1233,14 +1233,7 @@ static int ath11k_mac_vif_setup_ps(struct ath11k_vif *arvif) + + enable_ps = arvif->ps; + +- if (!arvif->is_started) { +- /* mac80211 can update vif powersave state while disconnected. +- * Firmware doesn't behave nicely and consumes more power than +- * necessary if PS is disabled on a non-started vdev. Hence +- * force-enable PS for non-running vdevs. +- */ +- psmode = WMI_STA_PS_MODE_ENABLED; +- } else if (enable_ps) { ++ if (enable_ps) { + psmode = WMI_STA_PS_MODE_ENABLED; + param = WMI_STA_PS_PARAM_INACTIVITY_TIME; + +diff --git a/drivers/net/wireless/ath/ath12k/qmi.c b/drivers/net/wireless/ath/ath12k/qmi.c +index 87de25b87196d..e68accbc837f4 100644 +--- a/drivers/net/wireless/ath/ath12k/qmi.c ++++ b/drivers/net/wireless/ath/ath12k/qmi.c +@@ -2935,6 +2935,9 @@ static const struct qmi_msg_handler ath12k_qmi_msg_handlers[] = { + .decoded_size = sizeof(struct qmi_wlanfw_fw_ready_ind_msg_v01), + .fn = ath12k_qmi_msg_fw_ready_cb, + }, ++ ++ /* end of list */ ++ {}, + }; + + static int ath12k_qmi_ops_new_server(struct qmi_handle *qmi_hdl, +diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c +index d308a0e7f1871..cd89032fa25e1 100644 +--- a/drivers/net/wireless/ath/ath12k/wmi.c ++++ b/drivers/net/wireless/ath/ath12k/wmi.c +@@ -1834,7 +1834,7 @@ static void ath12k_wmi_copy_peer_flags(struct wmi_peer_assoc_complete_cmd *cmd, + if (arg->bw_160) + cmd->peer_flags |= cpu_to_le32(WMI_PEER_160MHZ); + if (arg->bw_320) +- cmd->peer_flags |= cpu_to_le32(WMI_PEER_EXT_320MHZ); ++ cmd->peer_flags_ext |= cpu_to_le32(WMI_PEER_EXT_320MHZ); + + /* Typically if STBC is enabled for VHT it should be enabled + * for HT as well +diff --git a/drivers/net/wireless/ath/carl9170/tx.c b/drivers/net/wireless/ath/carl9170/tx.c +index 6bb9aa2bfe654..88ef6e023f826 100644 +--- a/drivers/net/wireless/ath/carl9170/tx.c ++++ b/drivers/net/wireless/ath/carl9170/tx.c +@@ -280,7 +280,8 @@ static void carl9170_tx_release(struct kref *ref) + * carl9170_tx_fill_rateinfo() has filled the rate information + * before we get to this point. + */ +- memset_after(&txinfo->status, 0, rates); ++ memset(&txinfo->pad, 0, sizeof(txinfo->pad)); ++ memset(&txinfo->rate_driver_data, 0, sizeof(txinfo->rate_driver_data)); + + if (atomic_read(&ar->tx_total_queued)) + ar->tx_schedule = true; +diff --git a/drivers/net/wireless/ath/carl9170/usb.c b/drivers/net/wireless/ath/carl9170/usb.c +index e4eb666c6eea4..a5265997b5767 100644 +--- a/drivers/net/wireless/ath/carl9170/usb.c ++++ b/drivers/net/wireless/ath/carl9170/usb.c +@@ -1069,6 +1069,38 @@ static int carl9170_usb_probe(struct usb_interface *intf, + ar->usb_ep_cmd_is_bulk = true; + } + ++ /* Verify that all expected endpoints are present */ ++ if (ar->usb_ep_cmd_is_bulk) { ++ u8 bulk_ep_addr[] = { ++ AR9170_USB_EP_RX | USB_DIR_IN, ++ AR9170_USB_EP_TX | USB_DIR_OUT, ++ AR9170_USB_EP_CMD | USB_DIR_OUT, ++ 0}; ++ u8 int_ep_addr[] = { ++ AR9170_USB_EP_IRQ | USB_DIR_IN, ++ 0}; ++ if (!usb_check_bulk_endpoints(intf, bulk_ep_addr) || ++ !usb_check_int_endpoints(intf, int_ep_addr)) ++ err = -ENODEV; ++ } else { ++ u8 bulk_ep_addr[] = { ++ AR9170_USB_EP_RX | USB_DIR_IN, ++ AR9170_USB_EP_TX | USB_DIR_OUT, ++ 0}; ++ u8 int_ep_addr[] = { ++ AR9170_USB_EP_IRQ | USB_DIR_IN, ++ AR9170_USB_EP_CMD | USB_DIR_OUT, ++ 0}; ++ if (!usb_check_bulk_endpoints(intf, bulk_ep_addr) || ++ !usb_check_int_endpoints(intf, int_ep_addr)) ++ err = -ENODEV; ++ } ++ ++ if (err) { ++ carl9170_free(ar); ++ return err; ++ } ++ + usb_set_intfdata(intf, ar); + SET_IEEE80211_DEV(ar->hw, &intf->dev); + +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +index 80220685f5e45..a43af82691401 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +@@ -1675,6 +1675,15 @@ struct brcmf_random_seed_footer { + #define BRCMF_RANDOM_SEED_MAGIC 0xfeedc0de + #define BRCMF_RANDOM_SEED_LENGTH 0x100 + ++static noinline_for_stack void ++brcmf_pcie_provide_random_bytes(struct brcmf_pciedev_info *devinfo, u32 address) ++{ ++ u8 randbuf[BRCMF_RANDOM_SEED_LENGTH]; ++ ++ get_random_bytes(randbuf, BRCMF_RANDOM_SEED_LENGTH); ++ memcpy_toio(devinfo->tcm + address, randbuf, BRCMF_RANDOM_SEED_LENGTH); ++} ++ + static int brcmf_pcie_download_fw_nvram(struct brcmf_pciedev_info *devinfo, + const struct firmware *fw, void *nvram, + u32 nvram_len) +@@ -1717,7 +1726,6 @@ static int brcmf_pcie_download_fw_nvram(struct brcmf_pciedev_info *devinfo, + .length = cpu_to_le32(rand_len), + .magic = cpu_to_le32(BRCMF_RANDOM_SEED_MAGIC), + }; +- void *randbuf; + + /* Some Apple chips/firmwares expect a buffer of random + * data to be present before NVRAM +@@ -1729,10 +1737,7 @@ static int brcmf_pcie_download_fw_nvram(struct brcmf_pciedev_info *devinfo, + sizeof(footer)); + + address -= rand_len; +- randbuf = kzalloc(rand_len, GFP_KERNEL); +- get_random_bytes(randbuf, rand_len); +- memcpy_toio(devinfo->tcm + address, randbuf, rand_len); +- kfree(randbuf); ++ brcmf_pcie_provide_random_bytes(devinfo, address); + } + } else { + brcmf_dbg(PCIE, "No matching NVRAM file found %s\n", +diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +index ee9d14250a261..375f401b14535 100644 +--- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c ++++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +@@ -1513,6 +1513,17 @@ static int iwl_mvm_alloc_bcast_mcast_sta(struct iwl_mvm *mvm, + IWL_STA_MULTICAST); + } + ++void iwl_mvm_mac_init_mvmvif(struct iwl_mvm *mvm, struct iwl_mvm_vif *mvmvif) ++{ ++ lockdep_assert_held(&mvm->mutex); ++ ++ if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) ++ return; ++ ++ INIT_DELAYED_WORK(&mvmvif->csa_work, ++ iwl_mvm_channel_switch_disconnect_wk); ++} ++ + static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) + { +@@ -1522,6 +1533,8 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, + + mutex_lock(&mvm->mutex); + ++ iwl_mvm_mac_init_mvmvif(mvm, mvmvif); ++ + mvmvif->mvm = mvm; + + /* the first link always points to the default one */ +@@ -1595,8 +1608,6 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, + mvm->p2p_device_vif = vif; + + iwl_mvm_tcm_add_vif(mvm, vif); +- INIT_DELAYED_WORK(&mvmvif->csa_work, +- iwl_mvm_channel_switch_disconnect_wk); + + if (vif->type == NL80211_IFTYPE_MONITOR) { + mvm->monitor_on = true; +@@ -1638,6 +1649,8 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, + void iwl_mvm_prepare_mac_removal(struct iwl_mvm *mvm, + struct ieee80211_vif *vif) + { ++ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); ++ + if (vif->type == NL80211_IFTYPE_P2P_DEVICE) { + /* + * Flush the ROC worker which will flush the OFFCHANNEL queue. +@@ -1646,6 +1659,8 @@ void iwl_mvm_prepare_mac_removal(struct iwl_mvm *mvm, + */ + flush_work(&mvm->roc_done_wk); + } ++ ++ cancel_delayed_work_sync(&mvmvif->csa_work); + } + + /* This function is doing the common part of removing the interface for +diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c +index 2d1fd7ac8577f..aef8824469e1e 100644 +--- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c ++++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c +@@ -13,6 +13,8 @@ static int iwl_mvm_mld_mac_add_interface(struct ieee80211_hw *hw, + + mutex_lock(&mvm->mutex); + ++ iwl_mvm_mac_init_mvmvif(mvm, mvmvif); ++ + mvmvif->mvm = mvm; + + /* Not much to do here. The stack will not allow interface +@@ -296,13 +298,8 @@ __iwl_mvm_mld_assign_vif_chanctx(struct iwl_mvm *mvm, + * this needs the phy context assigned (and in FW?), and we cannot + * do it later because it needs to be initialized as soon as we're + * able to TX on the link, i.e. when active. +- * +- * Firmware restart isn't quite correct yet for MLO, but we don't +- * need to do it in that case anyway since it will happen from the +- * normal station state callback. + */ +- if (mvmvif->ap_sta && +- !test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) { ++ if (mvmvif->ap_sta) { + struct ieee80211_link_sta *link_sta; + + rcu_read_lock(); +diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c +index 278454c116fee..121da93e99c6a 100644 +--- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c ++++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c +@@ -9,7 +9,9 @@ + u32 iwl_mvm_sta_fw_id_mask(struct iwl_mvm *mvm, struct ieee80211_sta *sta, + int filter_link_id) + { ++ struct ieee80211_link_sta *link_sta; + struct iwl_mvm_sta *mvmsta; ++ struct ieee80211_vif *vif; + unsigned int link_id; + u32 result = 0; + +@@ -17,26 +19,27 @@ u32 iwl_mvm_sta_fw_id_mask(struct iwl_mvm *mvm, struct ieee80211_sta *sta, + return 0; + + mvmsta = iwl_mvm_sta_from_mac80211(sta); ++ vif = mvmsta->vif; + + /* it's easy when the STA is not an MLD */ + if (!sta->valid_links) + return BIT(mvmsta->deflink.sta_id); + + /* but if it is an MLD, get the mask of all the FW STAs it has ... */ +- for (link_id = 0; link_id < ARRAY_SIZE(mvmsta->link); link_id++) { +- struct iwl_mvm_link_sta *link_sta; ++ for_each_sta_active_link(vif, sta, link_sta, link_id) { ++ struct iwl_mvm_link_sta *mvm_link_sta; + + /* unless we have a specific link in mind */ + if (filter_link_id >= 0 && link_id != filter_link_id) + continue; + +- link_sta = ++ mvm_link_sta = + rcu_dereference_check(mvmsta->link[link_id], + lockdep_is_held(&mvm->mutex)); +- if (!link_sta) ++ if (!mvm_link_sta) + continue; + +- result |= BIT(link_sta->sta_id); ++ result |= BIT(mvm_link_sta->sta_id); + } + + return result; +@@ -582,14 +585,14 @@ static int iwl_mvm_mld_alloc_sta_links(struct iwl_mvm *mvm, + struct ieee80211_sta *sta) + { + struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta); ++ struct ieee80211_link_sta *link_sta; + unsigned int link_id; + int ret; + + lockdep_assert_held(&mvm->mutex); + +- for (link_id = 0; link_id < ARRAY_SIZE(sta->link); link_id++) { +- if (!rcu_access_pointer(sta->link[link_id]) || +- mvm_sta->link[link_id]) ++ for_each_sta_active_link(vif, sta, link_sta, link_id) { ++ if (WARN_ON(mvm_sta->link[link_id])) + continue; + + ret = iwl_mvm_mld_alloc_sta_link(mvm, vif, sta, link_id); +diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +index 218f3bc31104b..c780e5ffcd596 100644 +--- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h ++++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +@@ -1737,6 +1737,8 @@ int iwl_mvm_load_d3_fw(struct iwl_mvm *mvm); + + int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm); + ++void iwl_mvm_mac_init_mvmvif(struct iwl_mvm *mvm, struct iwl_mvm_vif *mvmvif); ++ + /* + * FW notifications / CMD responses handlers + * Convention: iwl_mvm_rx_ +diff --git a/drivers/net/wireless/marvell/mwl8k.c b/drivers/net/wireless/marvell/mwl8k.c +index 13bcb123d1223..c0ecd769ada76 100644 +--- a/drivers/net/wireless/marvell/mwl8k.c ++++ b/drivers/net/wireless/marvell/mwl8k.c +@@ -2718,7 +2718,7 @@ __mwl8k_cmd_mac_multicast_adr(struct ieee80211_hw *hw, int allmulti, + cmd->action |= cpu_to_le16(MWL8K_ENABLE_RX_MULTICAST); + cmd->numaddr = cpu_to_le16(mc_count); + netdev_hw_addr_list_for_each(ha, mc_list) { +- memcpy(cmd->addr[i], ha->addr, ETH_ALEN); ++ memcpy(cmd->addr[i++], ha->addr, ETH_ALEN); + } + } + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/dma.c b/drivers/net/wireless/mediatek/mt76/mt7603/dma.c +index 03ba11a61c90c..b3a61b0ddd03d 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7603/dma.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7603/dma.c +@@ -4,6 +4,13 @@ + #include "mac.h" + #include "../dma.h" + ++static const u8 wmm_queue_map[] = { ++ [IEEE80211_AC_BK] = 0, ++ [IEEE80211_AC_BE] = 1, ++ [IEEE80211_AC_VI] = 2, ++ [IEEE80211_AC_VO] = 3, ++}; ++ + static void + mt7603_rx_loopback_skb(struct mt7603_dev *dev, struct sk_buff *skb) + { +@@ -22,10 +29,10 @@ mt7603_rx_loopback_skb(struct mt7603_dev *dev, struct sk_buff *skb) + struct ieee80211_sta *sta; + struct mt7603_sta *msta; + struct mt76_wcid *wcid; ++ u8 tid = 0, hwq = 0; + void *priv; + int idx; + u32 val; +- u8 tid = 0; + + if (skb->len < MT_TXD_SIZE + sizeof(struct ieee80211_hdr)) + goto free; +@@ -42,19 +49,36 @@ mt7603_rx_loopback_skb(struct mt7603_dev *dev, struct sk_buff *skb) + goto free; + + priv = msta = container_of(wcid, struct mt7603_sta, wcid); +- val = le32_to_cpu(txd[0]); +- val &= ~(MT_TXD0_P_IDX | MT_TXD0_Q_IDX); +- val |= FIELD_PREP(MT_TXD0_Q_IDX, MT_TX_HW_QUEUE_MGMT); +- txd[0] = cpu_to_le32(val); + + sta = container_of(priv, struct ieee80211_sta, drv_priv); + hdr = (struct ieee80211_hdr *)&skb->data[MT_TXD_SIZE]; +- if (ieee80211_is_data_qos(hdr->frame_control)) ++ ++ hwq = wmm_queue_map[IEEE80211_AC_BE]; ++ if (ieee80211_is_data_qos(hdr->frame_control)) { + tid = *ieee80211_get_qos_ctl(hdr) & +- IEEE80211_QOS_CTL_TAG1D_MASK; +- skb_set_queue_mapping(skb, tid_to_ac[tid]); ++ IEEE80211_QOS_CTL_TAG1D_MASK; ++ u8 qid = tid_to_ac[tid]; ++ hwq = wmm_queue_map[qid]; ++ skb_set_queue_mapping(skb, qid); ++ } else if (ieee80211_is_data(hdr->frame_control)) { ++ skb_set_queue_mapping(skb, IEEE80211_AC_BE); ++ hwq = wmm_queue_map[IEEE80211_AC_BE]; ++ } else { ++ skb_pull(skb, MT_TXD_SIZE); ++ if (!ieee80211_is_bufferable_mmpdu(skb)) ++ goto free; ++ skb_push(skb, MT_TXD_SIZE); ++ skb_set_queue_mapping(skb, MT_TXQ_PSD); ++ hwq = MT_TX_HW_QUEUE_MGMT; ++ } ++ + ieee80211_sta_set_buffered(sta, tid, true); + ++ val = le32_to_cpu(txd[0]); ++ val &= ~(MT_TXD0_P_IDX | MT_TXD0_Q_IDX); ++ val |= FIELD_PREP(MT_TXD0_Q_IDX, hwq); ++ txd[0] = cpu_to_le32(val); ++ + spin_lock_bh(&dev->ps_lock); + __skb_queue_tail(&msta->psq, skb); + if (skb_queue_len(&msta->psq) >= 64) { +@@ -151,12 +175,6 @@ static int mt7603_poll_tx(struct napi_struct *napi, int budget) + + int mt7603_dma_init(struct mt7603_dev *dev) + { +- static const u8 wmm_queue_map[] = { +- [IEEE80211_AC_BK] = 0, +- [IEEE80211_AC_BE] = 1, +- [IEEE80211_AC_VI] = 2, +- [IEEE80211_AC_VO] = 3, +- }; + int ret; + int i; + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c +index cf21d06257e53..dc8a77f0a1cc4 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c +@@ -1393,6 +1393,7 @@ void mt7603_pse_client_reset(struct mt7603_dev *dev) + MT_CLIENT_RESET_TX_R_E_2_S); + + /* Start PSE client TX abort */ ++ mt76_set(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_FORCE_TX_EOF); + mt76_set(dev, addr, MT_CLIENT_RESET_TX_R_E_1); + mt76_poll_msec(dev, addr, MT_CLIENT_RESET_TX_R_E_1_S, + MT_CLIENT_RESET_TX_R_E_1_S, 500); +diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c +index 6c3696c8c7002..450f4d221184b 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c +@@ -1049,6 +1049,7 @@ static ssize_t + mt7915_rate_txpower_set(struct file *file, const char __user *user_buf, + size_t count, loff_t *ppos) + { ++ int i, ret, pwr, pwr160 = 0, pwr80 = 0, pwr40 = 0, pwr20 = 0; + struct mt7915_phy *phy = file->private_data; + struct mt7915_dev *dev = phy->dev; + struct mt76_phy *mphy = phy->mt76; +@@ -1057,7 +1058,6 @@ mt7915_rate_txpower_set(struct file *file, const char __user *user_buf, + .band_idx = phy->mt76->band_idx, + }; + char buf[100]; +- int i, ret, pwr160 = 0, pwr80 = 0, pwr40 = 0, pwr20 = 0; + enum mac80211_rx_encoding mode; + u32 offs = 0, len = 0; + +@@ -1130,8 +1130,8 @@ mt7915_rate_txpower_set(struct file *file, const char __user *user_buf, + if (ret) + goto out; + +- mphy->txpower_cur = max(mphy->txpower_cur, +- max(pwr160, max(pwr80, max(pwr40, pwr20)))); ++ pwr = max3(pwr80, pwr40, pwr20); ++ mphy->txpower_cur = max3(mphy->txpower_cur, pwr160, pwr); + out: + mutex_unlock(&dev->mt76.mutex); + +diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c +index fc3bb63b9ac3e..acf310e58f7e2 100644 +--- a/drivers/net/xen-netback/interface.c ++++ b/drivers/net/xen-netback/interface.c +@@ -668,8 +668,7 @@ int xenvif_connect_ctrl(struct xenvif *vif, grant_ref_t ring_ref, + static void xenvif_disconnect_queue(struct xenvif_queue *queue) + { + if (queue->task) { +- kthread_stop(queue->task); +- put_task_struct(queue->task); ++ kthread_stop_put(queue->task); + queue->task = NULL; + } + +diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c +index 2db71e222fa7d..94a0916f9cb78 100644 +--- a/drivers/nvme/host/core.c ++++ b/drivers/nvme/host/core.c +@@ -377,7 +377,7 @@ static inline void nvme_end_req_zoned(struct request *req) + le64_to_cpu(nvme_req(req)->result.u64)); + } + +-static inline void nvme_end_req(struct request *req) ++void nvme_end_req(struct request *req) + { + blk_status_t status = nvme_error_status(nvme_req(req)->status); + +@@ -587,27 +587,6 @@ bool nvme_change_ctrl_state(struct nvme_ctrl *ctrl, + } + EXPORT_SYMBOL_GPL(nvme_change_ctrl_state); + +-/* +- * Returns true for sink states that can't ever transition back to live. +- */ +-static bool nvme_state_terminal(struct nvme_ctrl *ctrl) +-{ +- switch (nvme_ctrl_state(ctrl)) { +- case NVME_CTRL_NEW: +- case NVME_CTRL_LIVE: +- case NVME_CTRL_RESETTING: +- case NVME_CTRL_CONNECTING: +- return false; +- case NVME_CTRL_DELETING: +- case NVME_CTRL_DELETING_NOIO: +- case NVME_CTRL_DEAD: +- return true; +- default: +- WARN_ONCE(1, "Unhandled ctrl state:%d", ctrl->state); +- return true; +- } +-} +- + /* + * Waits for the controller state to be resetting, or returns false if it is + * not possible to ever transition to that state. +diff --git a/drivers/nvme/host/multipath.c b/drivers/nvme/host/multipath.c +index 0a88d7bdc5e37..3ac0cc22207dc 100644 +--- a/drivers/nvme/host/multipath.c ++++ b/drivers/nvme/host/multipath.c +@@ -118,7 +118,8 @@ void nvme_failover_req(struct request *req) + blk_steal_bios(&ns->head->requeue_list, req); + spin_unlock_irqrestore(&ns->head->requeue_lock, flags); + +- blk_mq_end_request(req, 0); ++ nvme_req(req)->status = 0; ++ nvme_end_req(req); + kblockd_schedule_work(&ns->head->requeue_work); + } + +@@ -246,7 +247,8 @@ static struct nvme_ns *__nvme_find_path(struct nvme_ns_head *head, int node) + if (nvme_path_is_disabled(ns)) + continue; + +- if (READ_ONCE(head->subsys->iopolicy) == NVME_IOPOLICY_NUMA) ++ if (ns->ctrl->numa_node != NUMA_NO_NODE && ++ READ_ONCE(head->subsys->iopolicy) == NVME_IOPOLICY_NUMA) + distance = node_distance(node, ns->ctrl->numa_node); + else + distance = LOCAL_DISTANCE; +diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h +index 176e372a5a796..fd67240795e3a 100644 +--- a/drivers/nvme/host/nvme.h ++++ b/drivers/nvme/host/nvme.h +@@ -740,6 +740,28 @@ static inline bool nvme_is_aen_req(u16 qid, __u16 command_id) + nvme_tag_from_cid(command_id) >= NVME_AQ_BLK_MQ_DEPTH; + } + ++/* ++ * Returns true for sink states that can't ever transition back to live. ++ */ ++static inline bool nvme_state_terminal(struct nvme_ctrl *ctrl) ++{ ++ switch (nvme_ctrl_state(ctrl)) { ++ case NVME_CTRL_NEW: ++ case NVME_CTRL_LIVE: ++ case NVME_CTRL_RESETTING: ++ case NVME_CTRL_CONNECTING: ++ return false; ++ case NVME_CTRL_DELETING: ++ case NVME_CTRL_DELETING_NOIO: ++ case NVME_CTRL_DEAD: ++ return true; ++ default: ++ WARN_ONCE(1, "Unhandled ctrl state:%d", ctrl->state); ++ return true; ++ } ++} ++ ++void nvme_end_req(struct request *req); + void nvme_complete_rq(struct request *req); + void nvme_complete_batch_req(struct request *req); + +diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c +index e47172bd84efe..8d5ed4cb35d96 100644 +--- a/drivers/nvme/host/pci.c ++++ b/drivers/nvme/host/pci.c +@@ -1286,6 +1286,9 @@ static enum blk_eh_timer_return nvme_timeout(struct request *req) + struct nvme_command cmd = { }; + u32 csts = readl(dev->bar + NVME_REG_CSTS); + ++ if (nvme_state_terminal(&dev->ctrl)) ++ goto disable; ++ + /* If PCI error recovery process is happening, we cannot reset or + * the recovery mechanism will surely fail. + */ +@@ -1388,8 +1391,11 @@ static enum blk_eh_timer_return nvme_timeout(struct request *req) + return BLK_EH_RESET_TIMER; + + disable: +- if (!nvme_change_ctrl_state(&dev->ctrl, NVME_CTRL_RESETTING)) ++ if (!nvme_change_ctrl_state(&dev->ctrl, NVME_CTRL_RESETTING)) { ++ if (nvme_state_terminal(&dev->ctrl)) ++ nvme_dev_disable(dev, true); + return BLK_EH_DONE; ++ } + + nvme_dev_disable(dev, false); + if (nvme_try_sched_reset(&dev->ctrl)) +diff --git a/drivers/nvme/target/auth.c b/drivers/nvme/target/auth.c +index 4dcddcf95279b..e900525b78665 100644 +--- a/drivers/nvme/target/auth.c ++++ b/drivers/nvme/target/auth.c +@@ -284,9 +284,9 @@ int nvmet_auth_host_hash(struct nvmet_req *req, u8 *response, + } + + if (shash_len != crypto_shash_digestsize(shash_tfm)) { +- pr_debug("%s: hash len mismatch (len %d digest %d)\n", +- __func__, shash_len, +- crypto_shash_digestsize(shash_tfm)); ++ pr_err("%s: hash len mismatch (len %d digest %d)\n", ++ __func__, shash_len, ++ crypto_shash_digestsize(shash_tfm)); + ret = -EINVAL; + goto out_free_tfm; + } +@@ -368,7 +368,7 @@ int nvmet_auth_host_hash(struct nvmet_req *req, u8 *response, + kfree_sensitive(host_response); + out_free_tfm: + crypto_free_shash(shash_tfm); +- return 0; ++ return ret; + } + + int nvmet_auth_ctrl_hash(struct nvmet_req *req, u8 *response, +diff --git a/drivers/nvme/target/configfs.c b/drivers/nvme/target/configfs.c +index 01b2a3d1a5e6c..384cd2b540d0c 100644 +--- a/drivers/nvme/target/configfs.c ++++ b/drivers/nvme/target/configfs.c +@@ -538,10 +538,18 @@ static ssize_t nvmet_ns_enable_store(struct config_item *item, + if (kstrtobool(page, &enable)) + return -EINVAL; + ++ /* ++ * take a global nvmet_config_sem because the disable routine has a ++ * window where it releases the subsys-lock, giving a chance to ++ * a parallel enable to concurrently execute causing the disable to ++ * have a misaccounting of the ns percpu_ref. ++ */ ++ down_write(&nvmet_config_sem); + if (enable) + ret = nvmet_ns_enable(ns); + else + nvmet_ns_disable(ns); ++ up_write(&nvmet_config_sem); + + return ret ? ret : count; + } +@@ -616,6 +624,18 @@ static struct configfs_attribute *nvmet_ns_attrs[] = { + NULL, + }; + ++bool nvmet_subsys_nsid_exists(struct nvmet_subsys *subsys, u32 nsid) ++{ ++ struct config_item *ns_item; ++ char name[12]; ++ ++ snprintf(name, sizeof(name), "%u", nsid); ++ mutex_lock(&subsys->namespaces_group.cg_subsys->su_mutex); ++ ns_item = config_group_find_item(&subsys->namespaces_group, name); ++ mutex_unlock(&subsys->namespaces_group.cg_subsys->su_mutex); ++ return ns_item != NULL; ++} ++ + static void nvmet_ns_release(struct config_item *item) + { + struct nvmet_ns *ns = to_nvmet_ns(item); +diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c +index 3935165048e74..ce7e945cb4f7e 100644 +--- a/drivers/nvme/target/core.c ++++ b/drivers/nvme/target/core.c +@@ -425,10 +425,13 @@ void nvmet_stop_keep_alive_timer(struct nvmet_ctrl *ctrl) + u16 nvmet_req_find_ns(struct nvmet_req *req) + { + u32 nsid = le32_to_cpu(req->cmd->common.nsid); ++ struct nvmet_subsys *subsys = nvmet_req_subsys(req); + +- req->ns = xa_load(&nvmet_req_subsys(req)->namespaces, nsid); ++ req->ns = xa_load(&subsys->namespaces, nsid); + if (unlikely(!req->ns)) { + req->error_loc = offsetof(struct nvme_common_command, nsid); ++ if (nvmet_subsys_nsid_exists(subsys, nsid)) ++ return NVME_SC_INTERNAL_PATH_ERROR; + return NVME_SC_INVALID_NS | NVME_SC_DNR; + } + +diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h +index 8cfd60f3b5648..15b00ed7be16a 100644 +--- a/drivers/nvme/target/nvmet.h ++++ b/drivers/nvme/target/nvmet.h +@@ -530,6 +530,7 @@ void nvmet_subsys_disc_changed(struct nvmet_subsys *subsys, + struct nvmet_host *host); + void nvmet_add_async_event(struct nvmet_ctrl *ctrl, u8 event_type, + u8 event_info, u8 log_page); ++bool nvmet_subsys_nsid_exists(struct nvmet_subsys *subsys, u32 nsid); + + #define NVMET_QUEUE_SIZE 1024 + #define NVMET_NR_QUEUES 128 +diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c +index 8e5d547aa16cb..3d302815c6f36 100644 +--- a/drivers/nvme/target/tcp.c ++++ b/drivers/nvme/target/tcp.c +@@ -324,6 +324,7 @@ static int nvmet_tcp_check_ddgst(struct nvmet_tcp_queue *queue, void *pdu) + return 0; + } + ++/* If cmd buffers are NULL, no operation is performed */ + static void nvmet_tcp_free_cmd_buffers(struct nvmet_tcp_cmd *cmd) + { + kfree(cmd->iov); +@@ -1476,13 +1477,9 @@ static void nvmet_tcp_free_cmd_data_in_buffers(struct nvmet_tcp_queue *queue) + struct nvmet_tcp_cmd *cmd = queue->cmds; + int i; + +- for (i = 0; i < queue->nr_cmds; i++, cmd++) { +- if (nvmet_tcp_need_data_in(cmd)) +- nvmet_tcp_free_cmd_buffers(cmd); +- } +- +- if (!queue->nr_cmds && nvmet_tcp_need_data_in(&queue->connect)) +- nvmet_tcp_free_cmd_buffers(&queue->connect); ++ for (i = 0; i < queue->nr_cmds; i++, cmd++) ++ nvmet_tcp_free_cmd_buffers(cmd); ++ nvmet_tcp_free_cmd_buffers(&queue->connect); + } + + static void nvmet_tcp_release_queue_work(struct work_struct *w) +diff --git a/drivers/of/module.c b/drivers/of/module.c +index f58e624953a20..780fd82a7ecc5 100644 +--- a/drivers/of/module.c ++++ b/drivers/of/module.c +@@ -29,14 +29,15 @@ ssize_t of_modalias(const struct device_node *np, char *str, ssize_t len) + csize = snprintf(str, len, "of:N%pOFn%c%s", np, 'T', + of_node_get_device_type(np)); + tsize = csize; ++ if (csize >= len) ++ csize = len > 0 ? len - 1 : 0; + len -= csize; +- if (str) +- str += csize; ++ str += csize; + + of_property_for_each_string(np, "compatible", p, compat) { + csize = strlen(compat) + 1; + tsize += csize; +- if (csize > len) ++ if (csize >= len) + continue; + + csize = snprintf(str, len, "C%s", compat); +diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c +index 248cd9347e8fd..416d6b45d1fe8 100644 +--- a/drivers/pci/controller/dwc/pcie-tegra194.c ++++ b/drivers/pci/controller/dwc/pcie-tegra194.c +@@ -2272,11 +2272,14 @@ static int tegra_pcie_dw_probe(struct platform_device *pdev) + ret = tegra_pcie_config_ep(pcie, pdev); + if (ret < 0) + goto fail; ++ else ++ return 0; + break; + + default: + dev_err(dev, "Invalid PCIe device type %d\n", + pcie->of_data->mode); ++ ret = -EINVAL; + } + + fail: +diff --git a/drivers/pci/of_property.c b/drivers/pci/of_property.c +index c2c7334152bc0..03539e5053720 100644 +--- a/drivers/pci/of_property.c ++++ b/drivers/pci/of_property.c +@@ -238,6 +238,8 @@ static int of_pci_prop_intr_map(struct pci_dev *pdev, struct of_changeset *ocs, + return 0; + + int_map = kcalloc(map_sz, sizeof(u32), GFP_KERNEL); ++ if (!int_map) ++ return -ENOMEM; + mapp = int_map; + + list_for_each_entry(child, &pdev->subordinate->devices, bus_list) { +diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c +index dddd30deea32b..6ea01007031a4 100644 +--- a/drivers/pci/pci.c ++++ b/drivers/pci/pci.c +@@ -4986,7 +4986,7 @@ int pcie_retrain_link(struct pci_dev *pdev, bool use_lt) + * avoid LTSSM race as recommended in Implementation Note at the + * end of PCIe r6.0.1 sec 7.5.3.7. + */ +- rc = pcie_wait_for_link_status(pdev, use_lt, !use_lt); ++ rc = pcie_wait_for_link_status(pdev, true, false); + if (rc) + return rc; + +diff --git a/drivers/pci/pcie/edr.c b/drivers/pci/pcie/edr.c +index 5f4914d313a17..e86298dbbcff6 100644 +--- a/drivers/pci/pcie/edr.c ++++ b/drivers/pci/pcie/edr.c +@@ -32,10 +32,10 @@ static int acpi_enable_dpc(struct pci_dev *pdev) + int status = 0; + + /* +- * Behavior when calling unsupported _DSM functions is undefined, +- * so check whether EDR_PORT_DPC_ENABLE_DSM is supported. ++ * Per PCI Firmware r3.3, sec 4.6.12, EDR_PORT_DPC_ENABLE_DSM is ++ * optional. Return success if it's not implemented. + */ +- if (!acpi_check_dsm(adev->handle, &pci_acpi_dsm_guid, 5, ++ if (!acpi_check_dsm(adev->handle, &pci_acpi_dsm_guid, 6, + 1ULL << EDR_PORT_DPC_ENABLE_DSM)) + return 0; + +@@ -46,12 +46,7 @@ static int acpi_enable_dpc(struct pci_dev *pdev) + argv4.package.count = 1; + argv4.package.elements = &req; + +- /* +- * Per Downstream Port Containment Related Enhancements ECN to PCI +- * Firmware Specification r3.2, sec 4.6.12, EDR_PORT_DPC_ENABLE_DSM is +- * optional. Return success if it's not implemented. +- */ +- obj = acpi_evaluate_dsm(adev->handle, &pci_acpi_dsm_guid, 5, ++ obj = acpi_evaluate_dsm(adev->handle, &pci_acpi_dsm_guid, 6, + EDR_PORT_DPC_ENABLE_DSM, &argv4); + if (!obj) + return 0; +@@ -85,8 +80,9 @@ static struct pci_dev *acpi_dpc_port_get(struct pci_dev *pdev) + u16 port; + + /* +- * Behavior when calling unsupported _DSM functions is undefined, +- * so check whether EDR_PORT_DPC_ENABLE_DSM is supported. ++ * If EDR_PORT_LOCATE_DSM is not implemented under the target of ++ * EDR, the target is the port that experienced the containment ++ * event (PCI Firmware r3.3, sec 4.6.13). + */ + if (!acpi_check_dsm(adev->handle, &pci_acpi_dsm_guid, 5, + 1ULL << EDR_PORT_LOCATE_DSM)) +@@ -103,6 +99,16 @@ static struct pci_dev *acpi_dpc_port_get(struct pci_dev *pdev) + return NULL; + } + ++ /* ++ * Bit 31 represents the success/failure of the operation. If bit ++ * 31 is set, the operation failed. ++ */ ++ if (obj->integer.value & BIT(31)) { ++ ACPI_FREE(obj); ++ pci_err(pdev, "Locate Port _DSM failed\n"); ++ return NULL; ++ } ++ + /* + * Firmware returns DPC port BDF details in following format: + * 15:8 = bus +diff --git a/drivers/perf/arm_dmc620_pmu.c b/drivers/perf/arm_dmc620_pmu.c +index 30cea68595747..b6a677224d682 100644 +--- a/drivers/perf/arm_dmc620_pmu.c ++++ b/drivers/perf/arm_dmc620_pmu.c +@@ -542,12 +542,16 @@ static int dmc620_pmu_event_init(struct perf_event *event) + if (event->cpu < 0) + return -EINVAL; + ++ hwc->idx = -1; ++ ++ if (event->group_leader == event) ++ return 0; ++ + /* + * We can't atomically disable all HW counters so only one event allowed, + * although software events are acceptable. + */ +- if (event->group_leader != event && +- !is_software_event(event->group_leader)) ++ if (!is_software_event(event->group_leader)) + return -EINVAL; + + for_each_sibling_event(sibling, event->group_leader) { +@@ -556,7 +560,6 @@ static int dmc620_pmu_event_init(struct perf_event *event) + return -EINVAL; + } + +- hwc->idx = -1; + return 0; + } + +diff --git a/drivers/perf/hisilicon/hisi_pcie_pmu.c b/drivers/perf/hisilicon/hisi_pcie_pmu.c +index 051efffc44c82..430ca15373fe2 100644 +--- a/drivers/perf/hisilicon/hisi_pcie_pmu.c ++++ b/drivers/perf/hisilicon/hisi_pcie_pmu.c +@@ -337,15 +337,27 @@ static bool hisi_pcie_pmu_validate_event_group(struct perf_event *event) + return false; + + for (num = 0; num < counters; num++) { ++ /* ++ * If we find a related event, then it's a valid group ++ * since we don't need to allocate a new counter for it. ++ */ + if (hisi_pcie_pmu_cmp_event(event_group[num], sibling)) + break; + } + ++ /* ++ * Otherwise it's a new event but if there's no available counter, ++ * fail the check since we cannot schedule all the events in ++ * the group simultaneously. ++ */ ++ if (num == HISI_PCIE_MAX_COUNTERS) ++ return false; ++ + if (num == counters) + event_group[counters++] = sibling; + } + +- return counters <= HISI_PCIE_MAX_COUNTERS; ++ return true; + } + + static int hisi_pcie_pmu_event_init(struct perf_event *event) +diff --git a/drivers/perf/hisilicon/hns3_pmu.c b/drivers/perf/hisilicon/hns3_pmu.c +index 16869bf5bf4cc..60062eaa342aa 100644 +--- a/drivers/perf/hisilicon/hns3_pmu.c ++++ b/drivers/perf/hisilicon/hns3_pmu.c +@@ -1085,15 +1085,27 @@ static bool hns3_pmu_validate_event_group(struct perf_event *event) + return false; + + for (num = 0; num < counters; num++) { ++ /* ++ * If we find a related event, then it's a valid group ++ * since we don't need to allocate a new counter for it. ++ */ + if (hns3_pmu_cmp_event(event_group[num], sibling)) + break; + } + ++ /* ++ * Otherwise it's a new event but if there's no available counter, ++ * fail the check since we cannot schedule all the events in ++ * the group simultaneously. ++ */ ++ if (num == HNS3_PMU_MAX_HW_EVENTS) ++ return false; ++ + if (num == counters) + event_group[counters++] = sibling; + } + +- return counters <= HNS3_PMU_MAX_HW_EVENTS; ++ return true; + } + + static u32 hns3_pmu_get_filter_condition(struct perf_event *event) +@@ -1515,7 +1527,7 @@ static int hns3_pmu_irq_register(struct pci_dev *pdev, + return ret; + } + +- ret = devm_add_action(&pdev->dev, hns3_pmu_free_irq, pdev); ++ ret = devm_add_action_or_reset(&pdev->dev, hns3_pmu_free_irq, pdev); + if (ret) { + pci_err(pdev, "failed to add free irq action, ret = %d.\n", ret); + return ret; +diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c +index dce002e232ee9..54fb5fca1c422 100644 +--- a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c ++++ b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c +@@ -2334,8 +2334,6 @@ static int qmp_v4_configure_dp_phy(struct qmp_combo *qmp) + writel(0x20, qmp->dp_tx2 + cfg->regs[QPHY_TX_TX_EMP_POST1_LVL]); + + return 0; +- +- return 0; + } + + /* +diff --git a/drivers/pinctrl/qcom/pinctrl-sm7150.c b/drivers/pinctrl/qcom/pinctrl-sm7150.c +index 33657cf98fb9d..edb5984cd3519 100644 +--- a/drivers/pinctrl/qcom/pinctrl-sm7150.c ++++ b/drivers/pinctrl/qcom/pinctrl-sm7150.c +@@ -65,7 +65,7 @@ enum { + .intr_detection_width = 2, \ + } + +-#define SDC_QDSD_PINGROUP(pg_name, ctl, pull, drv) \ ++#define SDC_QDSD_PINGROUP(pg_name, _tile, ctl, pull, drv) \ + { \ + .grp = PINCTRL_PINGROUP(#pg_name, \ + pg_name##_pins, \ +@@ -75,7 +75,7 @@ enum { + .intr_cfg_reg = 0, \ + .intr_status_reg = 0, \ + .intr_target_reg = 0, \ +- .tile = SOUTH, \ ++ .tile = _tile, \ + .mux_bit = -1, \ + .pull_bit = pull, \ + .drv_bit = drv, \ +@@ -101,7 +101,7 @@ enum { + .intr_cfg_reg = 0, \ + .intr_status_reg = 0, \ + .intr_target_reg = 0, \ +- .tile = SOUTH, \ ++ .tile = WEST, \ + .mux_bit = -1, \ + .pull_bit = 3, \ + .drv_bit = 0, \ +@@ -1199,13 +1199,13 @@ static const struct msm_pingroup sm7150_groups[] = { + [117] = PINGROUP(117, NORTH, _, _, _, _, _, _, _, _, _), + [118] = PINGROUP(118, NORTH, _, _, _, _, _, _, _, _, _), + [119] = UFS_RESET(ufs_reset, 0x9f000), +- [120] = SDC_QDSD_PINGROUP(sdc1_rclk, 0x9a000, 15, 0), +- [121] = SDC_QDSD_PINGROUP(sdc1_clk, 0x9a000, 13, 6), +- [122] = SDC_QDSD_PINGROUP(sdc1_cmd, 0x9a000, 11, 3), +- [123] = SDC_QDSD_PINGROUP(sdc1_data, 0x9a000, 9, 0), +- [124] = SDC_QDSD_PINGROUP(sdc2_clk, 0x98000, 14, 6), +- [125] = SDC_QDSD_PINGROUP(sdc2_cmd, 0x98000, 11, 3), +- [126] = SDC_QDSD_PINGROUP(sdc2_data, 0x98000, 9, 0), ++ [120] = SDC_QDSD_PINGROUP(sdc1_rclk, WEST, 0x9a000, 15, 0), ++ [121] = SDC_QDSD_PINGROUP(sdc1_clk, WEST, 0x9a000, 13, 6), ++ [122] = SDC_QDSD_PINGROUP(sdc1_cmd, WEST, 0x9a000, 11, 3), ++ [123] = SDC_QDSD_PINGROUP(sdc1_data, WEST, 0x9a000, 9, 0), ++ [124] = SDC_QDSD_PINGROUP(sdc2_clk, SOUTH, 0x98000, 14, 6), ++ [125] = SDC_QDSD_PINGROUP(sdc2_cmd, SOUTH, 0x98000, 11, 3), ++ [126] = SDC_QDSD_PINGROUP(sdc2_data, SOUTH, 0x98000, 9, 0), + }; + + static const struct msm_gpio_wakeirq_map sm7150_pdc_map[] = { +diff --git a/drivers/platform/x86/intel/speed_select_if/isst_if_common.c b/drivers/platform/x86/intel/speed_select_if/isst_if_common.c +index 30951f7131cd9..1accdaaf282c5 100644 +--- a/drivers/platform/x86/intel/speed_select_if/isst_if_common.c ++++ b/drivers/platform/x86/intel/speed_select_if/isst_if_common.c +@@ -721,6 +721,7 @@ static struct miscdevice isst_if_char_driver = { + static const struct x86_cpu_id hpm_cpu_ids[] = { + X86_MATCH_INTEL_FAM6_MODEL(GRANITERAPIDS_D, NULL), + X86_MATCH_INTEL_FAM6_MODEL(GRANITERAPIDS_X, NULL), ++ X86_MATCH_INTEL_FAM6_MODEL(ATOM_CRESTMONT, NULL), + X86_MATCH_INTEL_FAM6_MODEL(ATOM_CRESTMONT_X, NULL), + {} + }; +diff --git a/drivers/platform/x86/intel/tpmi.c b/drivers/platform/x86/intel/tpmi.c +index 6676eae144f31..4c42c28bdd3d4 100644 +--- a/drivers/platform/x86/intel/tpmi.c ++++ b/drivers/platform/x86/intel/tpmi.c +@@ -733,8 +733,11 @@ static int intel_vsec_tpmi_init(struct auxiliary_device *auxdev) + * when actual device nodes created outside this + * loop via tpmi_create_devices(). + */ +- if (pfs->pfs_header.tpmi_id == TPMI_INFO_ID) +- tpmi_process_info(tpmi_info, pfs); ++ if (pfs->pfs_header.tpmi_id == TPMI_INFO_ID) { ++ ret = tpmi_process_info(tpmi_info, pfs); ++ if (ret) ++ return ret; ++ } + + if (pfs->pfs_header.tpmi_id == TPMI_CONTROL_ID) + tpmi_set_control_base(auxdev, tpmi_info, pfs); +diff --git a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c +index 7d0a67f8b517a..1050221645482 100644 +--- a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c ++++ b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c +@@ -234,6 +234,7 @@ static int uncore_probe(struct auxiliary_device *auxdev, const struct auxiliary_ + { + struct intel_tpmi_plat_info *plat_info; + struct tpmi_uncore_struct *tpmi_uncore; ++ bool uncore_sysfs_added = false; + int ret, i, pkg = 0; + int num_resources; + +@@ -359,9 +360,15 @@ static int uncore_probe(struct auxiliary_device *auxdev, const struct auxiliary_ + } + /* Point to next cluster offset */ + cluster_offset >>= UNCORE_MAX_CLUSTER_PER_DOMAIN; ++ uncore_sysfs_added = true; + } + } + ++ if (!uncore_sysfs_added) { ++ ret = -ENODEV; ++ goto remove_clusters; ++ } ++ + auxiliary_set_drvdata(auxdev, tpmi_uncore); + + tpmi_uncore->root_cluster.root_domain = true; +diff --git a/drivers/platform/x86/lenovo-yogabook.c b/drivers/platform/x86/lenovo-yogabook.c +index b8d0239192cbf..fd62bf746ebde 100644 +--- a/drivers/platform/x86/lenovo-yogabook.c ++++ b/drivers/platform/x86/lenovo-yogabook.c +@@ -435,7 +435,7 @@ static int yogabook_pdev_set_kbd_backlight(struct yogabook_data *data, u8 level) + .enabled = level, + }; + +- pwm_apply_state(data->kbd_bl_pwm, &state); ++ pwm_apply_might_sleep(data->kbd_bl_pwm, &state); + gpiod_set_value(data->kbd_bl_led_enable, level ? 1 : 0); + return 0; + } +diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c +index 89c37a83d7fcd..5b1f08eabd923 100644 +--- a/drivers/platform/x86/thinkpad_acpi.c ++++ b/drivers/platform/x86/thinkpad_acpi.c +@@ -3042,10 +3042,9 @@ static void tpacpi_send_radiosw_update(void) + + static void hotkey_exit(void) + { +-#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL + mutex_lock(&hotkey_mutex); ++#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL + hotkey_poll_stop_sync(); +- mutex_unlock(&hotkey_mutex); + #endif + dbg_printk(TPACPI_DBG_EXIT | TPACPI_DBG_HKEY, + "restoring original HKEY status and mask\n"); +@@ -3055,6 +3054,8 @@ static void hotkey_exit(void) + hotkey_mask_set(hotkey_orig_mask)) | + hotkey_status_set(false)) != 0) + pr_err("failed to restore hot key mask to BIOS defaults\n"); ++ ++ mutex_unlock(&hotkey_mutex); + } + + static void __init hotkey_unmap(const unsigned int scancode) +diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c +index 0c8c63239adbf..a1a355ba23837 100644 +--- a/drivers/pwm/core.c ++++ b/drivers/pwm/core.c +@@ -382,8 +382,8 @@ struct pwm_device *pwm_request_from_chip(struct pwm_chip *chip, + } + EXPORT_SYMBOL_GPL(pwm_request_from_chip); + +-static void pwm_apply_state_debug(struct pwm_device *pwm, +- const struct pwm_state *state) ++static void pwm_apply_debug(struct pwm_device *pwm, ++ const struct pwm_state *state) + { + struct pwm_state *last = &pwm->last; + struct pwm_chip *chip = pwm->chip; +@@ -489,11 +489,11 @@ static void pwm_apply_state_debug(struct pwm_device *pwm, + } + + /** +- * pwm_apply_state() - atomically apply a new state to a PWM device ++ * pwm_apply_might_sleep() - atomically apply a new state to a PWM device + * @pwm: PWM device + * @state: new state to apply + */ +-int pwm_apply_state(struct pwm_device *pwm, const struct pwm_state *state) ++int pwm_apply_might_sleep(struct pwm_device *pwm, const struct pwm_state *state) + { + struct pwm_chip *chip; + int err; +@@ -501,7 +501,7 @@ int pwm_apply_state(struct pwm_device *pwm, const struct pwm_state *state) + /* + * Some lowlevel driver's implementations of .apply() make use of + * mutexes, also with some drivers only returning when the new +- * configuration is active calling pwm_apply_state() from atomic context ++ * configuration is active calling pwm_apply_might_sleep() from atomic context + * is a bad idea. So make it explicit that calling this function might + * sleep. + */ +@@ -531,11 +531,11 @@ int pwm_apply_state(struct pwm_device *pwm, const struct pwm_state *state) + * only do this after pwm->state was applied as some + * implementations of .get_state depend on this + */ +- pwm_apply_state_debug(pwm, state); ++ pwm_apply_debug(pwm, state); + + return 0; + } +-EXPORT_SYMBOL_GPL(pwm_apply_state); ++EXPORT_SYMBOL_GPL(pwm_apply_might_sleep); + + /** + * pwm_capture() - capture and report a PWM signal +@@ -593,7 +593,7 @@ int pwm_adjust_config(struct pwm_device *pwm) + state.period = pargs.period; + state.polarity = pargs.polarity; + +- return pwm_apply_state(pwm, &state); ++ return pwm_apply_might_sleep(pwm, &state); + } + + /* +@@ -616,7 +616,7 @@ int pwm_adjust_config(struct pwm_device *pwm) + state.duty_cycle = state.period - state.duty_cycle; + } + +- return pwm_apply_state(pwm, &state); ++ return pwm_apply_might_sleep(pwm, &state); + } + EXPORT_SYMBOL_GPL(pwm_adjust_config); + +diff --git a/drivers/pwm/pwm-sti.c b/drivers/pwm/pwm-sti.c +index c782378dff5e5..a0467f0b549c2 100644 +--- a/drivers/pwm/pwm-sti.c ++++ b/drivers/pwm/pwm-sti.c +@@ -571,6 +571,7 @@ static int sti_pwm_probe(struct platform_device *pdev) + { + struct device *dev = &pdev->dev; + struct sti_pwm_compat_data *cdata; ++ struct pwm_chip *chip; + struct sti_pwm_chip *pc; + unsigned int i; + int irq, ret; +@@ -578,6 +579,7 @@ static int sti_pwm_probe(struct platform_device *pdev) + pc = devm_kzalloc(dev, sizeof(*pc), GFP_KERNEL); + if (!pc) + return -ENOMEM; ++ chip = &pc->chip; + + cdata = devm_kzalloc(dev, sizeof(*cdata), GFP_KERNEL); + if (!cdata) +@@ -623,40 +625,28 @@ static int sti_pwm_probe(struct platform_device *pdev) + return ret; + + if (cdata->pwm_num_devs) { +- pc->pwm_clk = of_clk_get_by_name(dev->of_node, "pwm"); ++ pc->pwm_clk = devm_clk_get_prepared(dev, "pwm"); + if (IS_ERR(pc->pwm_clk)) { + dev_err(dev, "failed to get PWM clock\n"); + return PTR_ERR(pc->pwm_clk); + } +- +- ret = clk_prepare(pc->pwm_clk); +- if (ret) { +- dev_err(dev, "failed to prepare clock\n"); +- return ret; +- } + } + + if (cdata->cpt_num_devs) { +- pc->cpt_clk = of_clk_get_by_name(dev->of_node, "capture"); ++ pc->cpt_clk = devm_clk_get_prepared(dev, "capture"); + if (IS_ERR(pc->cpt_clk)) { + dev_err(dev, "failed to get PWM capture clock\n"); + return PTR_ERR(pc->cpt_clk); + } + +- ret = clk_prepare(pc->cpt_clk); +- if (ret) { +- dev_err(dev, "failed to prepare clock\n"); +- return ret; +- } +- + cdata->ddata = devm_kzalloc(dev, cdata->cpt_num_devs * sizeof(*cdata->ddata), GFP_KERNEL); + if (!cdata->ddata) + return -ENOMEM; + } + +- pc->chip.dev = dev; +- pc->chip.ops = &sti_pwm_ops; +- pc->chip.npwm = max(cdata->pwm_num_devs, cdata->cpt_num_devs); ++ chip->dev = dev; ++ chip->ops = &sti_pwm_ops; ++ 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]; +@@ -665,26 +655,7 @@ static int sti_pwm_probe(struct platform_device *pdev) + mutex_init(&ddata->lock); + } + +- ret = pwmchip_add(&pc->chip); +- if (ret < 0) { +- clk_unprepare(pc->pwm_clk); +- clk_unprepare(pc->cpt_clk); +- return ret; +- } +- +- platform_set_drvdata(pdev, pc); +- +- return 0; +-} +- +-static void sti_pwm_remove(struct platform_device *pdev) +-{ +- struct sti_pwm_chip *pc = platform_get_drvdata(pdev); +- +- pwmchip_remove(&pc->chip); +- +- clk_unprepare(pc->pwm_clk); +- clk_unprepare(pc->cpt_clk); ++ return devm_pwmchip_add(dev, chip); + } + + static const struct of_device_id sti_pwm_of_match[] = { +@@ -699,7 +670,6 @@ static struct platform_driver sti_pwm_driver = { + .of_match_table = sti_pwm_of_match, + }, + .probe = sti_pwm_probe, +- .remove_new = sti_pwm_remove, + }; + module_platform_driver(sti_pwm_driver); + +diff --git a/drivers/pwm/pwm-twl-led.c b/drivers/pwm/pwm-twl-led.c +index 8fb84b4418538..65205449ed79c 100644 +--- a/drivers/pwm/pwm-twl-led.c ++++ b/drivers/pwm/pwm-twl-led.c +@@ -172,7 +172,7 @@ static int twl4030_pwmled_apply(struct pwm_chip *chip, struct pwm_device *pwm, + * We cannot skip calling ->config even if state->period == + * pwm->state.period && state->duty_cycle == pwm->state.duty_cycle + * because we might have exited early in the last call to +- * pwm_apply_state because of !state->enabled and so the two values in ++ * pwm_apply_might_sleep because of !state->enabled and so the two values in + * pwm->state might not be configured in hardware. + */ + ret = twl4030_pwmled_config(pwm->chip, pwm, +diff --git a/drivers/pwm/pwm-vt8500.c b/drivers/pwm/pwm-vt8500.c +index 6d46db51daacc..ba1204e18afbb 100644 +--- a/drivers/pwm/pwm-vt8500.c ++++ b/drivers/pwm/pwm-vt8500.c +@@ -206,7 +206,7 @@ static int vt8500_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, + * We cannot skip calling ->config even if state->period == + * pwm->state.period && state->duty_cycle == pwm->state.duty_cycle + * because we might have exited early in the last call to +- * pwm_apply_state because of !state->enabled and so the two values in ++ * pwm_apply_might_sleep because of !state->enabled and so the two values in + * pwm->state might not be configured in hardware. + */ + err = vt8500_pwm_config(pwm->chip, pwm, state->duty_cycle, state->period); +diff --git a/drivers/pwm/sysfs.c b/drivers/pwm/sysfs.c +index 8d1254761e4dd..052ccadbdabfe 100644 +--- a/drivers/pwm/sysfs.c ++++ b/drivers/pwm/sysfs.c +@@ -62,7 +62,7 @@ static ssize_t period_store(struct device *child, + mutex_lock(&export->lock); + pwm_get_state(pwm, &state); + state.period = val; +- ret = pwm_apply_state(pwm, &state); ++ ret = pwm_apply_might_sleep(pwm, &state); + mutex_unlock(&export->lock); + + return ret ? : size; +@@ -97,7 +97,7 @@ static ssize_t duty_cycle_store(struct device *child, + mutex_lock(&export->lock); + pwm_get_state(pwm, &state); + state.duty_cycle = val; +- ret = pwm_apply_state(pwm, &state); ++ ret = pwm_apply_might_sleep(pwm, &state); + mutex_unlock(&export->lock); + + return ret ? : size; +@@ -144,7 +144,7 @@ static ssize_t enable_store(struct device *child, + goto unlock; + } + +- ret = pwm_apply_state(pwm, &state); ++ ret = pwm_apply_might_sleep(pwm, &state); + + unlock: + mutex_unlock(&export->lock); +@@ -194,7 +194,7 @@ static ssize_t polarity_store(struct device *child, + mutex_lock(&export->lock); + pwm_get_state(pwm, &state); + state.polarity = polarity; +- ret = pwm_apply_state(pwm, &state); ++ ret = pwm_apply_might_sleep(pwm, &state); + mutex_unlock(&export->lock); + + return ret ? : size; +@@ -401,7 +401,7 @@ static int pwm_class_apply_state(struct pwm_export *export, + struct pwm_device *pwm, + struct pwm_state *state) + { +- int ret = pwm_apply_state(pwm, state); ++ int ret = pwm_apply_might_sleep(pwm, state); + + /* release lock taken in pwm_class_get_state */ + mutex_unlock(&export->lock); +diff --git a/drivers/regulator/bd71828-regulator.c b/drivers/regulator/bd71828-regulator.c +index 08d4ee369287e..dd871ffe979c3 100644 +--- a/drivers/regulator/bd71828-regulator.c ++++ b/drivers/regulator/bd71828-regulator.c +@@ -206,14 +206,11 @@ static const struct bd71828_regulator_data bd71828_rdata[] = { + .suspend_reg = BD71828_REG_BUCK1_SUSP_VOLT, + .suspend_mask = BD71828_MASK_BUCK1267_VOLT, + .suspend_on_mask = BD71828_MASK_SUSP_EN, +- .lpsr_on_mask = BD71828_MASK_LPSR_EN, + /* + * LPSR voltage is same as SUSPEND voltage. Allow +- * setting it so that regulator can be set enabled at +- * LPSR state ++ * only enabling/disabling regulator for LPSR state + */ +- .lpsr_reg = BD71828_REG_BUCK1_SUSP_VOLT, +- .lpsr_mask = BD71828_MASK_BUCK1267_VOLT, ++ .lpsr_on_mask = BD71828_MASK_LPSR_EN, + }, + .reg_inits = buck1_inits, + .reg_init_amnt = ARRAY_SIZE(buck1_inits), +@@ -288,13 +285,7 @@ static const struct bd71828_regulator_data bd71828_rdata[] = { + ROHM_DVS_LEVEL_SUSPEND | + ROHM_DVS_LEVEL_LPSR, + .run_reg = BD71828_REG_BUCK3_VOLT, +- .idle_reg = BD71828_REG_BUCK3_VOLT, +- .suspend_reg = BD71828_REG_BUCK3_VOLT, +- .lpsr_reg = BD71828_REG_BUCK3_VOLT, + .run_mask = BD71828_MASK_BUCK3_VOLT, +- .idle_mask = BD71828_MASK_BUCK3_VOLT, +- .suspend_mask = BD71828_MASK_BUCK3_VOLT, +- .lpsr_mask = BD71828_MASK_BUCK3_VOLT, + .idle_on_mask = BD71828_MASK_IDLE_EN, + .suspend_on_mask = BD71828_MASK_SUSP_EN, + .lpsr_on_mask = BD71828_MASK_LPSR_EN, +@@ -329,13 +320,7 @@ static const struct bd71828_regulator_data bd71828_rdata[] = { + ROHM_DVS_LEVEL_SUSPEND | + ROHM_DVS_LEVEL_LPSR, + .run_reg = BD71828_REG_BUCK4_VOLT, +- .idle_reg = BD71828_REG_BUCK4_VOLT, +- .suspend_reg = BD71828_REG_BUCK4_VOLT, +- .lpsr_reg = BD71828_REG_BUCK4_VOLT, + .run_mask = BD71828_MASK_BUCK4_VOLT, +- .idle_mask = BD71828_MASK_BUCK4_VOLT, +- .suspend_mask = BD71828_MASK_BUCK4_VOLT, +- .lpsr_mask = BD71828_MASK_BUCK4_VOLT, + .idle_on_mask = BD71828_MASK_IDLE_EN, + .suspend_on_mask = BD71828_MASK_SUSP_EN, + .lpsr_on_mask = BD71828_MASK_LPSR_EN, +@@ -370,13 +355,7 @@ static const struct bd71828_regulator_data bd71828_rdata[] = { + ROHM_DVS_LEVEL_SUSPEND | + ROHM_DVS_LEVEL_LPSR, + .run_reg = BD71828_REG_BUCK5_VOLT, +- .idle_reg = BD71828_REG_BUCK5_VOLT, +- .suspend_reg = BD71828_REG_BUCK5_VOLT, +- .lpsr_reg = BD71828_REG_BUCK5_VOLT, + .run_mask = BD71828_MASK_BUCK5_VOLT, +- .idle_mask = BD71828_MASK_BUCK5_VOLT, +- .suspend_mask = BD71828_MASK_BUCK5_VOLT, +- .lpsr_mask = BD71828_MASK_BUCK5_VOLT, + .idle_on_mask = BD71828_MASK_IDLE_EN, + .suspend_on_mask = BD71828_MASK_SUSP_EN, + .lpsr_on_mask = BD71828_MASK_LPSR_EN, +@@ -493,13 +472,7 @@ static const struct bd71828_regulator_data bd71828_rdata[] = { + ROHM_DVS_LEVEL_SUSPEND | + ROHM_DVS_LEVEL_LPSR, + .run_reg = BD71828_REG_LDO1_VOLT, +- .idle_reg = BD71828_REG_LDO1_VOLT, +- .suspend_reg = BD71828_REG_LDO1_VOLT, +- .lpsr_reg = BD71828_REG_LDO1_VOLT, + .run_mask = BD71828_MASK_LDO_VOLT, +- .idle_mask = BD71828_MASK_LDO_VOLT, +- .suspend_mask = BD71828_MASK_LDO_VOLT, +- .lpsr_mask = BD71828_MASK_LDO_VOLT, + .idle_on_mask = BD71828_MASK_IDLE_EN, + .suspend_on_mask = BD71828_MASK_SUSP_EN, + .lpsr_on_mask = BD71828_MASK_LPSR_EN, +@@ -533,13 +506,7 @@ static const struct bd71828_regulator_data bd71828_rdata[] = { + ROHM_DVS_LEVEL_SUSPEND | + ROHM_DVS_LEVEL_LPSR, + .run_reg = BD71828_REG_LDO2_VOLT, +- .idle_reg = BD71828_REG_LDO2_VOLT, +- .suspend_reg = BD71828_REG_LDO2_VOLT, +- .lpsr_reg = BD71828_REG_LDO2_VOLT, + .run_mask = BD71828_MASK_LDO_VOLT, +- .idle_mask = BD71828_MASK_LDO_VOLT, +- .suspend_mask = BD71828_MASK_LDO_VOLT, +- .lpsr_mask = BD71828_MASK_LDO_VOLT, + .idle_on_mask = BD71828_MASK_IDLE_EN, + .suspend_on_mask = BD71828_MASK_SUSP_EN, + .lpsr_on_mask = BD71828_MASK_LPSR_EN, +@@ -573,13 +540,7 @@ static const struct bd71828_regulator_data bd71828_rdata[] = { + ROHM_DVS_LEVEL_SUSPEND | + ROHM_DVS_LEVEL_LPSR, + .run_reg = BD71828_REG_LDO3_VOLT, +- .idle_reg = BD71828_REG_LDO3_VOLT, +- .suspend_reg = BD71828_REG_LDO3_VOLT, +- .lpsr_reg = BD71828_REG_LDO3_VOLT, + .run_mask = BD71828_MASK_LDO_VOLT, +- .idle_mask = BD71828_MASK_LDO_VOLT, +- .suspend_mask = BD71828_MASK_LDO_VOLT, +- .lpsr_mask = BD71828_MASK_LDO_VOLT, + .idle_on_mask = BD71828_MASK_IDLE_EN, + .suspend_on_mask = BD71828_MASK_SUSP_EN, + .lpsr_on_mask = BD71828_MASK_LPSR_EN, +@@ -614,13 +575,7 @@ static const struct bd71828_regulator_data bd71828_rdata[] = { + ROHM_DVS_LEVEL_SUSPEND | + ROHM_DVS_LEVEL_LPSR, + .run_reg = BD71828_REG_LDO4_VOLT, +- .idle_reg = BD71828_REG_LDO4_VOLT, +- .suspend_reg = BD71828_REG_LDO4_VOLT, +- .lpsr_reg = BD71828_REG_LDO4_VOLT, + .run_mask = BD71828_MASK_LDO_VOLT, +- .idle_mask = BD71828_MASK_LDO_VOLT, +- .suspend_mask = BD71828_MASK_LDO_VOLT, +- .lpsr_mask = BD71828_MASK_LDO_VOLT, + .idle_on_mask = BD71828_MASK_IDLE_EN, + .suspend_on_mask = BD71828_MASK_SUSP_EN, + .lpsr_on_mask = BD71828_MASK_LPSR_EN, +@@ -655,13 +610,7 @@ static const struct bd71828_regulator_data bd71828_rdata[] = { + ROHM_DVS_LEVEL_SUSPEND | + ROHM_DVS_LEVEL_LPSR, + .run_reg = BD71828_REG_LDO5_VOLT, +- .idle_reg = BD71828_REG_LDO5_VOLT, +- .suspend_reg = BD71828_REG_LDO5_VOLT, +- .lpsr_reg = BD71828_REG_LDO5_VOLT, + .run_mask = BD71828_MASK_LDO_VOLT, +- .idle_mask = BD71828_MASK_LDO_VOLT, +- .suspend_mask = BD71828_MASK_LDO_VOLT, +- .lpsr_mask = BD71828_MASK_LDO_VOLT, + .idle_on_mask = BD71828_MASK_IDLE_EN, + .suspend_on_mask = BD71828_MASK_SUSP_EN, + .lpsr_on_mask = BD71828_MASK_LPSR_EN, +@@ -720,9 +669,6 @@ static const struct bd71828_regulator_data bd71828_rdata[] = { + .suspend_reg = BD71828_REG_LDO7_VOLT, + .lpsr_reg = BD71828_REG_LDO7_VOLT, + .run_mask = BD71828_MASK_LDO_VOLT, +- .idle_mask = BD71828_MASK_LDO_VOLT, +- .suspend_mask = BD71828_MASK_LDO_VOLT, +- .lpsr_mask = BD71828_MASK_LDO_VOLT, + .idle_on_mask = BD71828_MASK_IDLE_EN, + .suspend_on_mask = BD71828_MASK_SUSP_EN, + .lpsr_on_mask = BD71828_MASK_LPSR_EN, +diff --git a/drivers/regulator/helpers.c b/drivers/regulator/helpers.c +index d492683365532..6e1ace660b8cf 100644 +--- a/drivers/regulator/helpers.c ++++ b/drivers/regulator/helpers.c +@@ -161,6 +161,32 @@ int regulator_get_voltage_sel_pickable_regmap(struct regulator_dev *rdev) + } + EXPORT_SYMBOL_GPL(regulator_get_voltage_sel_pickable_regmap); + ++static int write_separate_vsel_and_range(struct regulator_dev *rdev, ++ unsigned int sel, unsigned int range) ++{ ++ bool range_updated; ++ int ret; ++ ++ ret = regmap_update_bits_base(rdev->regmap, rdev->desc->vsel_range_reg, ++ rdev->desc->vsel_range_mask, ++ range, &range_updated, false, false); ++ if (ret) ++ return ret; ++ ++ /* ++ * Some PMICs treat the vsel_reg same as apply-bit. Force it to be ++ * written if the range changed, even if the old selector was same as ++ * the new one ++ */ ++ if (rdev->desc->range_applied_by_vsel && range_updated) ++ return regmap_write_bits(rdev->regmap, ++ rdev->desc->vsel_reg, ++ rdev->desc->vsel_mask, sel); ++ ++ return regmap_update_bits(rdev->regmap, rdev->desc->vsel_reg, ++ rdev->desc->vsel_mask, sel); ++} ++ + /** + * regulator_set_voltage_sel_pickable_regmap - pickable range set_voltage_sel + * +@@ -199,21 +225,12 @@ int regulator_set_voltage_sel_pickable_regmap(struct regulator_dev *rdev, + range = rdev->desc->linear_range_selectors_bitfield[i]; + range <<= ffs(rdev->desc->vsel_range_mask) - 1; + +- if (rdev->desc->vsel_reg == rdev->desc->vsel_range_reg) { +- ret = regmap_update_bits(rdev->regmap, +- rdev->desc->vsel_reg, ++ if (rdev->desc->vsel_reg == rdev->desc->vsel_range_reg) ++ ret = regmap_update_bits(rdev->regmap, rdev->desc->vsel_reg, + rdev->desc->vsel_range_mask | + rdev->desc->vsel_mask, sel | range); +- } else { +- ret = regmap_update_bits(rdev->regmap, +- rdev->desc->vsel_range_reg, +- rdev->desc->vsel_range_mask, range); +- if (ret) +- return ret; +- +- ret = regmap_update_bits(rdev->regmap, rdev->desc->vsel_reg, +- rdev->desc->vsel_mask, sel); +- } ++ else ++ ret = write_separate_vsel_and_range(rdev, sel, range); + + if (ret) + return ret; +diff --git a/drivers/regulator/irq_helpers.c b/drivers/regulator/irq_helpers.c +index fe7ae0f3f46af..5ab1a0befe12f 100644 +--- a/drivers/regulator/irq_helpers.c ++++ b/drivers/regulator/irq_helpers.c +@@ -352,6 +352,9 @@ void *regulator_irq_helper(struct device *dev, + + h->irq = irq; + h->desc = *d; ++ h->desc.name = devm_kstrdup(dev, d->name, GFP_KERNEL); ++ if (!h->desc.name) ++ return ERR_PTR(-ENOMEM); + + ret = init_rdev_state(dev, h, rdev, common_errs, per_rdev_errs, + rdev_amount); +diff --git a/drivers/regulator/pwm-regulator.c b/drivers/regulator/pwm-regulator.c +index e33d10df7a763..226ca4c62673f 100644 +--- a/drivers/regulator/pwm-regulator.c ++++ b/drivers/regulator/pwm-regulator.c +@@ -90,7 +90,7 @@ static int pwm_regulator_set_voltage_sel(struct regulator_dev *rdev, + pwm_set_relative_duty_cycle(&pstate, + drvdata->duty_cycle_table[selector].dutycycle, 100); + +- ret = pwm_apply_state(drvdata->pwm, &pstate); ++ ret = pwm_apply_might_sleep(drvdata->pwm, &pstate); + if (ret) { + dev_err(&rdev->dev, "Failed to configure PWM: %d\n", ret); + return ret; +@@ -219,7 +219,7 @@ static int pwm_regulator_set_voltage(struct regulator_dev *rdev, + + pwm_set_relative_duty_cycle(&pstate, dutycycle, duty_unit); + +- ret = pwm_apply_state(drvdata->pwm, &pstate); ++ ret = pwm_apply_might_sleep(drvdata->pwm, &pstate); + if (ret) { + dev_err(&rdev->dev, "Failed to configure PWM: %d\n", ret); + return ret; +diff --git a/drivers/regulator/qcom-refgen-regulator.c b/drivers/regulator/qcom-refgen-regulator.c +index 656fe330d38f0..063e12c08e75f 100644 +--- a/drivers/regulator/qcom-refgen-regulator.c ++++ b/drivers/regulator/qcom-refgen-regulator.c +@@ -140,6 +140,7 @@ static const struct of_device_id qcom_refgen_match_table[] = { + { .compatible = "qcom,sm8250-refgen-regulator", .data = &sm8250_refgen_desc }, + { } + }; ++MODULE_DEVICE_TABLE(of, qcom_refgen_match_table); + + static struct platform_driver qcom_refgen_driver = { + .probe = qcom_refgen_probe, +diff --git a/drivers/regulator/tps6287x-regulator.c b/drivers/regulator/tps6287x-regulator.c +index 9b7c3d77789e3..3c9d79e003e4b 100644 +--- a/drivers/regulator/tps6287x-regulator.c ++++ b/drivers/regulator/tps6287x-regulator.c +@@ -115,6 +115,7 @@ static struct regulator_desc tps6287x_reg = { + .vsel_mask = 0xFF, + .vsel_range_reg = TPS6287X_CTRL2, + .vsel_range_mask = TPS6287X_CTRL2_VRANGE, ++ .range_applied_by_vsel = true, + .ramp_reg = TPS6287X_CTRL1, + .ramp_mask = TPS6287X_CTRL1_VRAMP, + .ramp_delay_table = tps6287x_ramp_table, +diff --git a/drivers/regulator/tps6594-regulator.c b/drivers/regulator/tps6594-regulator.c +index b7f0c87797577..5fad61785e72f 100644 +--- a/drivers/regulator/tps6594-regulator.c ++++ b/drivers/regulator/tps6594-regulator.c +@@ -287,30 +287,30 @@ static struct tps6594_regulator_irq_type *tps6594_ldos_irq_types[] = { + static const struct regulator_desc multi_regs[] = { + TPS6594_REGULATOR("BUCK12", "buck12", TPS6594_BUCK_1, + REGULATOR_VOLTAGE, tps6594_bucks_ops, TPS6594_MASK_BUCKS_VSET, +- TPS6594_REG_BUCKX_VOUT_1(1), ++ TPS6594_REG_BUCKX_VOUT_1(0), + TPS6594_MASK_BUCKS_VSET, +- TPS6594_REG_BUCKX_CTRL(1), ++ TPS6594_REG_BUCKX_CTRL(0), + TPS6594_BIT_BUCK_EN, 0, 0, bucks_ranges, + 4, 4000, 0, NULL, 0, 0), + TPS6594_REGULATOR("BUCK34", "buck34", TPS6594_BUCK_3, + REGULATOR_VOLTAGE, tps6594_bucks_ops, TPS6594_MASK_BUCKS_VSET, +- TPS6594_REG_BUCKX_VOUT_1(3), ++ TPS6594_REG_BUCKX_VOUT_1(2), + TPS6594_MASK_BUCKS_VSET, +- TPS6594_REG_BUCKX_CTRL(3), ++ TPS6594_REG_BUCKX_CTRL(2), + TPS6594_BIT_BUCK_EN, 0, 0, bucks_ranges, + 4, 0, 0, NULL, 0, 0), + TPS6594_REGULATOR("BUCK123", "buck123", TPS6594_BUCK_1, + REGULATOR_VOLTAGE, tps6594_bucks_ops, TPS6594_MASK_BUCKS_VSET, +- TPS6594_REG_BUCKX_VOUT_1(1), ++ TPS6594_REG_BUCKX_VOUT_1(0), + TPS6594_MASK_BUCKS_VSET, +- TPS6594_REG_BUCKX_CTRL(1), ++ TPS6594_REG_BUCKX_CTRL(0), + TPS6594_BIT_BUCK_EN, 0, 0, bucks_ranges, + 4, 4000, 0, NULL, 0, 0), + TPS6594_REGULATOR("BUCK1234", "buck1234", TPS6594_BUCK_1, + REGULATOR_VOLTAGE, tps6594_bucks_ops, TPS6594_MASK_BUCKS_VSET, +- TPS6594_REG_BUCKX_VOUT_1(1), ++ TPS6594_REG_BUCKX_VOUT_1(0), + TPS6594_MASK_BUCKS_VSET, +- TPS6594_REG_BUCKX_CTRL(1), ++ TPS6594_REG_BUCKX_CTRL(0), + TPS6594_BIT_BUCK_EN, 0, 0, bucks_ranges, + 4, 4000, 0, NULL, 0, 0), + }; +diff --git a/drivers/regulator/vqmmc-ipq4019-regulator.c b/drivers/regulator/vqmmc-ipq4019-regulator.c +index 086da36abc0b4..4955616517ce9 100644 +--- a/drivers/regulator/vqmmc-ipq4019-regulator.c ++++ b/drivers/regulator/vqmmc-ipq4019-regulator.c +@@ -84,6 +84,7 @@ static const struct of_device_id regulator_ipq4019_of_match[] = { + { .compatible = "qcom,vqmmc-ipq4019-regulator", }, + {}, + }; ++MODULE_DEVICE_TABLE(of, regulator_ipq4019_of_match); + + static struct platform_driver ipq4019_regulator_driver = { + .probe = ipq4019_regulator_probe, +diff --git a/drivers/s390/cio/trace.h b/drivers/s390/cio/trace.h +index 86993de253451..a4c5c6736b310 100644 +--- a/drivers/s390/cio/trace.h ++++ b/drivers/s390/cio/trace.h +@@ -50,7 +50,7 @@ DECLARE_EVENT_CLASS(s390_class_schib, + __entry->devno = schib->pmcw.dev; + __entry->schib = *schib; + __entry->pmcw_ena = schib->pmcw.ena; +- __entry->pmcw_st = schib->pmcw.ena; ++ __entry->pmcw_st = schib->pmcw.st; + __entry->pmcw_dnv = schib->pmcw.dnv; + __entry->pmcw_dev = schib->pmcw.dev; + __entry->pmcw_lpm = schib->pmcw.lpm; +diff --git a/drivers/scsi/bfa/bfad_debugfs.c b/drivers/scsi/bfa/bfad_debugfs.c +index 52db147d9979d..f6dd077d47c9a 100644 +--- a/drivers/scsi/bfa/bfad_debugfs.c ++++ b/drivers/scsi/bfa/bfad_debugfs.c +@@ -250,7 +250,7 @@ bfad_debugfs_write_regrd(struct file *file, const char __user *buf, + unsigned long flags; + void *kern_buf; + +- kern_buf = memdup_user(buf, nbytes); ++ kern_buf = memdup_user_nul(buf, nbytes); + if (IS_ERR(kern_buf)) + return PTR_ERR(kern_buf); + +@@ -317,7 +317,7 @@ bfad_debugfs_write_regwr(struct file *file, const char __user *buf, + unsigned long flags; + void *kern_buf; + +- kern_buf = memdup_user(buf, nbytes); ++ kern_buf = memdup_user_nul(buf, nbytes); + if (IS_ERR(kern_buf)) + return PTR_ERR(kern_buf); + +diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c +index af18d20f30794..49c57a9c110b5 100644 +--- a/drivers/scsi/hpsa.c ++++ b/drivers/scsi/hpsa.c +@@ -5850,7 +5850,7 @@ static int hpsa_scsi_host_alloc(struct ctlr_info *h) + { + struct Scsi_Host *sh; + +- sh = scsi_host_alloc(&hpsa_driver_template, sizeof(struct ctlr_info)); ++ sh = scsi_host_alloc(&hpsa_driver_template, sizeof(struct ctlr_info *)); + if (sh == NULL) { + dev_err(&h->pdev->dev, "scsi_host_alloc failed\n"); + return -ENOMEM; +diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c +index f6e6db8b8aba9..e97f4e01a865a 100644 +--- a/drivers/scsi/libsas/sas_expander.c ++++ b/drivers/scsi/libsas/sas_expander.c +@@ -239,8 +239,7 @@ static void sas_set_ex_phy(struct domain_device *dev, int phy_id, + /* help some expanders that fail to zero sas_address in the 'no + * device' case + */ +- if (phy->attached_dev_type == SAS_PHY_UNUSED || +- phy->linkrate < SAS_LINK_RATE_1_5_GBPS) ++ if (phy->attached_dev_type == SAS_PHY_UNUSED) + memset(phy->attached_sas_addr, 0, SAS_ADDR_SIZE); + else + memcpy(phy->attached_sas_addr, dr->attached_sas_addr, SAS_ADDR_SIZE); +diff --git a/drivers/scsi/qedf/qedf_debugfs.c b/drivers/scsi/qedf/qedf_debugfs.c +index 451fd236bfd05..96174353e3898 100644 +--- a/drivers/scsi/qedf/qedf_debugfs.c ++++ b/drivers/scsi/qedf/qedf_debugfs.c +@@ -170,7 +170,7 @@ qedf_dbg_debug_cmd_write(struct file *filp, const char __user *buffer, + if (!count || *ppos) + return 0; + +- kern_buf = memdup_user(buffer, count); ++ kern_buf = memdup_user_nul(buffer, count); + if (IS_ERR(kern_buf)) + return PTR_ERR(kern_buf); + +diff --git a/drivers/scsi/qla2xxx/qla_dfs.c b/drivers/scsi/qla2xxx/qla_dfs.c +index a7a364760b800..081af4d420a05 100644 +--- a/drivers/scsi/qla2xxx/qla_dfs.c ++++ b/drivers/scsi/qla2xxx/qla_dfs.c +@@ -274,7 +274,7 @@ qla_dfs_fw_resource_cnt_show(struct seq_file *s, void *unused) + seq_printf(s, "Driver: estimate iocb used [%d] high water limit [%d]\n", + iocbs_used, ha->base_qpair->fwres.iocbs_limit); + +- seq_printf(s, "estimate exchange used[%d] high water limit [%d] n", ++ seq_printf(s, "estimate exchange used[%d] high water limit [%d]\n", + exch_used, ha->base_qpair->fwres.exch_limit); + + if (ql2xenforce_iocb_limit == 2) { +diff --git a/drivers/soc/mediatek/mtk-cmdq-helper.c b/drivers/soc/mediatek/mtk-cmdq-helper.c +index b0cd071c4719b..0b2e5690dacfa 100644 +--- a/drivers/soc/mediatek/mtk-cmdq-helper.c ++++ b/drivers/soc/mediatek/mtk-cmdq-helper.c +@@ -14,7 +14,8 @@ + #define CMDQ_POLL_ENABLE_MASK BIT(0) + #define CMDQ_EOC_IRQ_EN BIT(0) + #define CMDQ_REG_TYPE 1 +-#define CMDQ_JUMP_RELATIVE 1 ++#define CMDQ_JUMP_RELATIVE 0 ++#define CMDQ_JUMP_ABSOLUTE 1 + + struct cmdq_instruction { + union { +@@ -397,7 +398,7 @@ int cmdq_pkt_jump(struct cmdq_pkt *pkt, dma_addr_t addr) + struct cmdq_instruction inst = {}; + + inst.op = CMDQ_CODE_JUMP; +- inst.offset = CMDQ_JUMP_RELATIVE; ++ inst.offset = CMDQ_JUMP_ABSOLUTE; + inst.value = addr >> + cmdq_get_shift_pa(((struct cmdq_client *)pkt->cl)->chan); + return cmdq_pkt_append_command(pkt, inst); +diff --git a/drivers/soc/qcom/pmic_glink.c b/drivers/soc/qcom/pmic_glink.c +index d5a4e71633ed6..61a359938b6c4 100644 +--- a/drivers/soc/qcom/pmic_glink.c ++++ b/drivers/soc/qcom/pmic_glink.c +@@ -11,6 +11,7 @@ + #include + #include + #include ++#include + + enum { + PMIC_GLINK_CLIENT_BATT = 0, +@@ -39,7 +40,7 @@ struct pmic_glink { + unsigned int pdr_state; + + /* serializing clients list updates */ +- struct mutex client_lock; ++ spinlock_t client_lock; + struct list_head clients; + }; + +@@ -61,10 +62,11 @@ static void _devm_pmic_glink_release_client(struct device *dev, void *res) + { + struct pmic_glink_client *client = (struct pmic_glink_client *)res; + struct pmic_glink *pg = client->pg; ++ unsigned long flags; + +- mutex_lock(&pg->client_lock); ++ spin_lock_irqsave(&pg->client_lock, flags); + list_del(&client->node); +- mutex_unlock(&pg->client_lock); ++ spin_unlock_irqrestore(&pg->client_lock, flags); + } + + struct pmic_glink_client *devm_pmic_glink_register_client(struct device *dev, +@@ -75,6 +77,7 @@ struct pmic_glink_client *devm_pmic_glink_register_client(struct device *dev, + { + struct pmic_glink_client *client; + struct pmic_glink *pg = dev_get_drvdata(dev->parent); ++ unsigned long flags; + + client = devres_alloc(_devm_pmic_glink_release_client, sizeof(*client), GFP_KERNEL); + if (!client) +@@ -86,9 +89,14 @@ struct pmic_glink_client *devm_pmic_glink_register_client(struct device *dev, + client->pdr_notify = pdr; + client->priv = priv; + +- mutex_lock(&pg->client_lock); ++ mutex_lock(&pg->state_lock); ++ spin_lock_irqsave(&pg->client_lock, flags); ++ + list_add(&client->node, &pg->clients); +- mutex_unlock(&pg->client_lock); ++ client->pdr_notify(client->priv, pg->client_state); ++ ++ spin_unlock_irqrestore(&pg->client_lock, flags); ++ mutex_unlock(&pg->state_lock); + + devres_add(dev, client); + +@@ -110,6 +118,7 @@ static int pmic_glink_rpmsg_callback(struct rpmsg_device *rpdev, void *data, + struct pmic_glink_client *client; + struct pmic_glink_hdr *hdr; + struct pmic_glink *pg = dev_get_drvdata(&rpdev->dev); ++ unsigned long flags; + + if (len < sizeof(*hdr)) { + dev_warn(pg->dev, "ignoring truncated message\n"); +@@ -118,10 +127,12 @@ static int pmic_glink_rpmsg_callback(struct rpmsg_device *rpdev, void *data, + + hdr = data; + ++ spin_lock_irqsave(&pg->client_lock, flags); + list_for_each_entry(client, &pg->clients, node) { + if (client->id == le32_to_cpu(hdr->owner)) + client->cb(data, len, client->priv); + } ++ spin_unlock_irqrestore(&pg->client_lock, flags); + + return 0; + } +@@ -161,6 +172,7 @@ static void pmic_glink_state_notify_clients(struct pmic_glink *pg) + { + struct pmic_glink_client *client; + unsigned int new_state = pg->client_state; ++ unsigned long flags; + + if (pg->client_state != SERVREG_SERVICE_STATE_UP) { + if (pg->pdr_state == SERVREG_SERVICE_STATE_UP && pg->ept) +@@ -171,8 +183,10 @@ static void pmic_glink_state_notify_clients(struct pmic_glink *pg) + } + + if (new_state != pg->client_state) { ++ spin_lock_irqsave(&pg->client_lock, flags); + list_for_each_entry(client, &pg->clients, node) + client->pdr_notify(client->priv, new_state); ++ spin_unlock_irqrestore(&pg->client_lock, flags); + pg->client_state = new_state; + } + } +@@ -259,7 +273,7 @@ static int pmic_glink_probe(struct platform_device *pdev) + pg->dev = &pdev->dev; + + INIT_LIST_HEAD(&pg->clients); +- mutex_init(&pg->client_lock); ++ spin_lock_init(&pg->client_lock); + mutex_init(&pg->state_lock); + + match_data = (unsigned long *)of_device_get_match_data(&pdev->dev); +diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c +index 0efc1c3bee5f5..3e7cf04aaf2a6 100644 +--- a/drivers/soundwire/cadence_master.c ++++ b/drivers/soundwire/cadence_master.c +@@ -1880,7 +1880,7 @@ struct sdw_cdns_pdi *sdw_cdns_alloc_pdi(struct sdw_cdns *cdns, + + /* check if we found a PDI, else find in bi-directional */ + if (!pdi) +- pdi = cdns_find_pdi(cdns, 2, stream->num_bd, stream->bd, ++ pdi = cdns_find_pdi(cdns, 0, stream->num_bd, stream->bd, + dai_id); + + if (pdi) { +diff --git a/drivers/spi/spi-stm32.c b/drivers/spi/spi-stm32.c +index ef665f470c5b5..40680b5fffc9a 100644 +--- a/drivers/spi/spi-stm32.c ++++ b/drivers/spi/spi-stm32.c +@@ -898,7 +898,7 @@ static irqreturn_t stm32h7_spi_irq_thread(int irq, void *dev_id) + mask |= STM32H7_SPI_SR_TXP | STM32H7_SPI_SR_RXP; + + if (!(sr & mask)) { +- dev_warn(spi->dev, "spurious IT (sr=0x%08x, ier=0x%08x)\n", ++ dev_vdbg(spi->dev, "spurious IT (sr=0x%08x, ier=0x%08x)\n", + sr, ier); + spin_unlock_irqrestore(&spi->lock, flags); + return IRQ_NONE; +diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c +index 76383ddbd6a6f..da15c3f388d1f 100644 +--- a/drivers/spi/spi.c ++++ b/drivers/spi/spi.c +@@ -1128,6 +1128,7 @@ static int __spi_map_msg(struct spi_controller *ctlr, struct spi_message *msg) + else + rx_dev = ctlr->dev.parent; + ++ ret = -ENOMSG; + list_for_each_entry(xfer, &msg->transfers, transfer_list) { + /* The sync is done before each transfer. */ + unsigned long attrs = DMA_ATTR_SKIP_CPU_SYNC; +@@ -1157,6 +1158,9 @@ static int __spi_map_msg(struct spi_controller *ctlr, struct spi_message *msg) + } + } + } ++ /* No transfer has been mapped, bail out with success */ ++ if (ret) ++ return 0; + + ctlr->cur_rx_dma_dev = rx_dev; + ctlr->cur_tx_dma_dev = tx_dev; +diff --git a/drivers/staging/greybus/arche-apb-ctrl.c b/drivers/staging/greybus/arche-apb-ctrl.c +index 8541995008da8..aa6f266b62a14 100644 +--- a/drivers/staging/greybus/arche-apb-ctrl.c ++++ b/drivers/staging/greybus/arche-apb-ctrl.c +@@ -466,6 +466,7 @@ static const struct of_device_id arche_apb_ctrl_of_match[] = { + { .compatible = "usbffff,2", }, + { }, + }; ++MODULE_DEVICE_TABLE(of, arche_apb_ctrl_of_match); + + static struct platform_driver arche_apb_ctrl_device_driver = { + .probe = arche_apb_ctrl_probe, +diff --git a/drivers/staging/greybus/arche-platform.c b/drivers/staging/greybus/arche-platform.c +index 891b75327d7f7..b33977ccd5271 100644 +--- a/drivers/staging/greybus/arche-platform.c ++++ b/drivers/staging/greybus/arche-platform.c +@@ -619,14 +619,7 @@ static const struct of_device_id arche_platform_of_match[] = { + { .compatible = "google,arche-platform", }, + { }, + }; +- +-static const struct of_device_id arche_combined_id[] = { +- /* Use PID/VID of SVC device */ +- { .compatible = "google,arche-platform", }, +- { .compatible = "usbffff,2", }, +- { }, +-}; +-MODULE_DEVICE_TABLE(of, arche_combined_id); ++MODULE_DEVICE_TABLE(of, arche_platform_of_match); + + static struct platform_driver arche_platform_device_driver = { + .probe = arche_platform_probe, +diff --git a/drivers/staging/greybus/light.c b/drivers/staging/greybus/light.c +index c6bd86a5335ab..9999f84016992 100644 +--- a/drivers/staging/greybus/light.c ++++ b/drivers/staging/greybus/light.c +@@ -147,6 +147,9 @@ static int __gb_lights_flash_brightness_set(struct gb_channel *channel) + channel = get_channel_from_mode(channel->light, + GB_CHANNEL_MODE_TORCH); + ++ if (!channel) ++ return -EINVAL; ++ + /* For not flash we need to convert brightness to intensity */ + intensity = channel->intensity_uA.min + + (channel->intensity_uA.step * channel->led->brightness); +@@ -549,7 +552,10 @@ static int gb_lights_light_v4l2_register(struct gb_light *light) + } + + channel_flash = get_channel_from_mode(light, GB_CHANNEL_MODE_FLASH); +- WARN_ON(!channel_flash); ++ if (!channel_flash) { ++ dev_err(dev, "failed to get flash channel from mode\n"); ++ return -EINVAL; ++ } + + fled = &channel_flash->fled; + +diff --git a/drivers/staging/media/atomisp/pci/sh_css.c b/drivers/staging/media/atomisp/pci/sh_css.c +index 4b3fa6d93fe0a..d8a1d4a58db6a 100644 +--- a/drivers/staging/media/atomisp/pci/sh_css.c ++++ b/drivers/staging/media/atomisp/pci/sh_css.c +@@ -4737,6 +4737,7 @@ static int load_video_binaries(struct ia_css_pipe *pipe) + sizeof(struct ia_css_binary), + GFP_KERNEL); + if (!mycs->yuv_scaler_binary) { ++ mycs->num_yuv_scaler = 0; + err = -ENOMEM; + return err; + } +diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c +index 98c356acfe983..ee22672471e81 100644 +--- a/drivers/thermal/qcom/tsens.c ++++ b/drivers/thermal/qcom/tsens.c +@@ -264,7 +264,7 @@ void compute_intercept_slope(struct tsens_priv *priv, u32 *p1, + for (i = 0; i < priv->num_sensors; i++) { + dev_dbg(priv->dev, + "%s: sensor%d - data_point1:%#x data_point2:%#x\n", +- __func__, i, p1[i], p2[i]); ++ __func__, i, p1[i], p2 ? p2[i] : 0); + + if (!priv->sensor[i].slope) + priv->sensor[i].slope = SLOPE_DEFAULT; +diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c +index 0ee7531c92017..5fc8540a83e31 100644 +--- a/drivers/tty/n_gsm.c ++++ b/drivers/tty/n_gsm.c +@@ -244,16 +244,18 @@ enum gsm_encoding { + + enum gsm_mux_state { + GSM_SEARCH, +- GSM_START, +- GSM_ADDRESS, +- GSM_CONTROL, +- GSM_LEN, +- GSM_DATA, +- GSM_FCS, +- GSM_OVERRUN, +- GSM_LEN0, +- GSM_LEN1, +- GSM_SSOF, ++ GSM0_ADDRESS, ++ GSM0_CONTROL, ++ GSM0_LEN0, ++ GSM0_LEN1, ++ GSM0_DATA, ++ GSM0_FCS, ++ GSM0_SSOF, ++ GSM1_START, ++ GSM1_ADDRESS, ++ GSM1_CONTROL, ++ GSM1_DATA, ++ GSM1_OVERRUN, + }; + + /* +@@ -2846,6 +2848,30 @@ static void gsm_queue(struct gsm_mux *gsm) + return; + } + ++/** ++ * gsm0_receive_state_check_and_fix - check and correct receive state ++ * @gsm: gsm data for this ldisc instance ++ * ++ * Ensures that the current receive state is valid for basic option mode. ++ */ ++ ++static void gsm0_receive_state_check_and_fix(struct gsm_mux *gsm) ++{ ++ switch (gsm->state) { ++ case GSM_SEARCH: ++ case GSM0_ADDRESS: ++ case GSM0_CONTROL: ++ case GSM0_LEN0: ++ case GSM0_LEN1: ++ case GSM0_DATA: ++ case GSM0_FCS: ++ case GSM0_SSOF: ++ break; ++ default: ++ gsm->state = GSM_SEARCH; ++ break; ++ } ++} + + /** + * gsm0_receive - perform processing for non-transparency +@@ -2859,26 +2885,27 @@ static void gsm0_receive(struct gsm_mux *gsm, unsigned char c) + { + unsigned int len; + ++ gsm0_receive_state_check_and_fix(gsm); + switch (gsm->state) { + case GSM_SEARCH: /* SOF marker */ + if (c == GSM0_SOF) { +- gsm->state = GSM_ADDRESS; ++ gsm->state = GSM0_ADDRESS; + gsm->address = 0; + gsm->len = 0; + gsm->fcs = INIT_FCS; + } + break; +- case GSM_ADDRESS: /* Address EA */ ++ case GSM0_ADDRESS: /* Address EA */ + gsm->fcs = gsm_fcs_add(gsm->fcs, c); + if (gsm_read_ea(&gsm->address, c)) +- gsm->state = GSM_CONTROL; ++ gsm->state = GSM0_CONTROL; + break; +- case GSM_CONTROL: /* Control Byte */ ++ case GSM0_CONTROL: /* Control Byte */ + gsm->fcs = gsm_fcs_add(gsm->fcs, c); + gsm->control = c; +- gsm->state = GSM_LEN0; ++ gsm->state = GSM0_LEN0; + break; +- case GSM_LEN0: /* Length EA */ ++ case GSM0_LEN0: /* Length EA */ + gsm->fcs = gsm_fcs_add(gsm->fcs, c); + if (gsm_read_ea(&gsm->len, c)) { + if (gsm->len > gsm->mru) { +@@ -2888,14 +2915,14 @@ static void gsm0_receive(struct gsm_mux *gsm, unsigned char c) + } + gsm->count = 0; + if (!gsm->len) +- gsm->state = GSM_FCS; ++ gsm->state = GSM0_FCS; + else +- gsm->state = GSM_DATA; ++ gsm->state = GSM0_DATA; + break; + } +- gsm->state = GSM_LEN1; ++ gsm->state = GSM0_LEN1; + break; +- case GSM_LEN1: ++ case GSM0_LEN1: + gsm->fcs = gsm_fcs_add(gsm->fcs, c); + len = c; + gsm->len |= len << 7; +@@ -2906,26 +2933,29 @@ static void gsm0_receive(struct gsm_mux *gsm, unsigned char c) + } + gsm->count = 0; + if (!gsm->len) +- gsm->state = GSM_FCS; ++ gsm->state = GSM0_FCS; + else +- gsm->state = GSM_DATA; ++ gsm->state = GSM0_DATA; + break; +- case GSM_DATA: /* Data */ ++ case GSM0_DATA: /* Data */ + gsm->buf[gsm->count++] = c; +- if (gsm->count == gsm->len) { ++ if (gsm->count >= MAX_MRU) { ++ gsm->bad_size++; ++ gsm->state = GSM_SEARCH; ++ } else if (gsm->count >= gsm->len) { + /* Calculate final FCS for UI frames over all data */ + if ((gsm->control & ~PF) != UIH) { + gsm->fcs = gsm_fcs_add_block(gsm->fcs, gsm->buf, + gsm->count); + } +- gsm->state = GSM_FCS; ++ gsm->state = GSM0_FCS; + } + break; +- case GSM_FCS: /* FCS follows the packet */ ++ case GSM0_FCS: /* FCS follows the packet */ + gsm->fcs = gsm_fcs_add(gsm->fcs, c); +- gsm->state = GSM_SSOF; ++ gsm->state = GSM0_SSOF; + break; +- case GSM_SSOF: ++ case GSM0_SSOF: + gsm->state = GSM_SEARCH; + if (c == GSM0_SOF) + gsm_queue(gsm); +@@ -2938,6 +2968,29 @@ static void gsm0_receive(struct gsm_mux *gsm, unsigned char c) + } + } + ++/** ++ * gsm1_receive_state_check_and_fix - check and correct receive state ++ * @gsm: gsm data for this ldisc instance ++ * ++ * Ensures that the current receive state is valid for advanced option mode. ++ */ ++ ++static void gsm1_receive_state_check_and_fix(struct gsm_mux *gsm) ++{ ++ switch (gsm->state) { ++ case GSM_SEARCH: ++ case GSM1_START: ++ case GSM1_ADDRESS: ++ case GSM1_CONTROL: ++ case GSM1_DATA: ++ case GSM1_OVERRUN: ++ break; ++ default: ++ gsm->state = GSM_SEARCH; ++ break; ++ } ++} ++ + /** + * gsm1_receive - perform processing for non-transparency + * @gsm: gsm data for this ldisc instance +@@ -2948,6 +3001,7 @@ static void gsm0_receive(struct gsm_mux *gsm, unsigned char c) + + static void gsm1_receive(struct gsm_mux *gsm, unsigned char c) + { ++ gsm1_receive_state_check_and_fix(gsm); + /* handle XON/XOFF */ + if ((c & ISO_IEC_646_MASK) == XON) { + gsm->constipated = true; +@@ -2960,11 +3014,11 @@ static void gsm1_receive(struct gsm_mux *gsm, unsigned char c) + } + if (c == GSM1_SOF) { + /* EOF is only valid in frame if we have got to the data state */ +- if (gsm->state == GSM_DATA) { ++ if (gsm->state == GSM1_DATA) { + if (gsm->count < 1) { + /* Missing FSC */ + gsm->malformed++; +- gsm->state = GSM_START; ++ gsm->state = GSM1_START; + return; + } + /* Remove the FCS from data */ +@@ -2980,14 +3034,14 @@ static void gsm1_receive(struct gsm_mux *gsm, unsigned char c) + gsm->fcs = gsm_fcs_add(gsm->fcs, gsm->buf[gsm->count]); + gsm->len = gsm->count; + gsm_queue(gsm); +- gsm->state = GSM_START; ++ gsm->state = GSM1_START; + return; + } + /* Any partial frame was a runt so go back to start */ +- if (gsm->state != GSM_START) { ++ if (gsm->state != GSM1_START) { + if (gsm->state != GSM_SEARCH) + gsm->malformed++; +- gsm->state = GSM_START; ++ gsm->state = GSM1_START; + } + /* A SOF in GSM_START means we are still reading idling or + framing bytes */ +@@ -3008,30 +3062,30 @@ static void gsm1_receive(struct gsm_mux *gsm, unsigned char c) + gsm->escape = false; + } + switch (gsm->state) { +- case GSM_START: /* First byte after SOF */ ++ case GSM1_START: /* First byte after SOF */ + gsm->address = 0; +- gsm->state = GSM_ADDRESS; ++ gsm->state = GSM1_ADDRESS; + gsm->fcs = INIT_FCS; + fallthrough; +- case GSM_ADDRESS: /* Address continuation */ ++ case GSM1_ADDRESS: /* Address continuation */ + gsm->fcs = gsm_fcs_add(gsm->fcs, c); + if (gsm_read_ea(&gsm->address, c)) +- gsm->state = GSM_CONTROL; ++ gsm->state = GSM1_CONTROL; + break; +- case GSM_CONTROL: /* Control Byte */ ++ case GSM1_CONTROL: /* Control Byte */ + gsm->fcs = gsm_fcs_add(gsm->fcs, c); + gsm->control = c; + gsm->count = 0; +- gsm->state = GSM_DATA; ++ gsm->state = GSM1_DATA; + break; +- case GSM_DATA: /* Data */ +- if (gsm->count > gsm->mru) { /* Allow one for the FCS */ +- gsm->state = GSM_OVERRUN; ++ case GSM1_DATA: /* Data */ ++ if (gsm->count > gsm->mru || gsm->count > MAX_MRU) { /* Allow one for the FCS */ ++ gsm->state = GSM1_OVERRUN; + gsm->bad_size++; + } else + gsm->buf[gsm->count++] = c; + break; +- case GSM_OVERRUN: /* Over-long - eg a dropped SOF */ ++ case GSM1_OVERRUN: /* Over-long - eg a dropped SOF */ + break; + default: + pr_debug("%s: unhandled state: %d\n", __func__, gsm->state); +diff --git a/drivers/tty/serial/8250/8250_bcm7271.c b/drivers/tty/serial/8250/8250_bcm7271.c +index aa5aff046756b..9afd5979c9e0d 100644 +--- a/drivers/tty/serial/8250/8250_bcm7271.c ++++ b/drivers/tty/serial/8250/8250_bcm7271.c +@@ -676,18 +676,46 @@ static void init_real_clk_rates(struct device *dev, struct brcmuart_priv *priv) + clk_set_rate(priv->baud_mux_clk, priv->default_mux_rate); + } + ++static u32 find_quot(struct device *dev, u32 freq, u32 baud, u32 *percent) ++{ ++ u32 quot; ++ u32 rate; ++ u64 hires_rate; ++ u64 hires_baud; ++ u64 hires_err; ++ ++ rate = freq / 16; ++ quot = DIV_ROUND_CLOSEST(rate, baud); ++ if (!quot) ++ return 0; ++ ++ /* increase resolution to get xx.xx percent */ ++ hires_rate = div_u64((u64)rate * 10000, (u64)quot); ++ hires_baud = (u64)baud * 10000; ++ ++ /* get the delta */ ++ if (hires_rate > hires_baud) ++ hires_err = (hires_rate - hires_baud); ++ else ++ hires_err = (hires_baud - hires_rate); ++ ++ *percent = (unsigned long)DIV_ROUND_CLOSEST_ULL(hires_err, baud); ++ ++ dev_dbg(dev, "Baud rate: %u, MUX Clk: %u, Error: %u.%u%%\n", ++ baud, freq, *percent / 100, *percent % 100); ++ ++ return quot; ++} ++ + static void set_clock_mux(struct uart_port *up, struct brcmuart_priv *priv, + u32 baud) + { + u32 percent; + u32 best_percent = UINT_MAX; + u32 quot; ++ u32 freq; + u32 best_quot = 1; +- u32 rate; +- int best_index = -1; +- u64 hires_rate; +- u64 hires_baud; +- u64 hires_err; ++ u32 best_freq = 0; + int rc; + int i; + int real_baud; +@@ -696,44 +724,35 @@ static void set_clock_mux(struct uart_port *up, struct brcmuart_priv *priv, + if (priv->baud_mux_clk == NULL) + return; + +- /* Find the closest match for specified baud */ +- for (i = 0; i < ARRAY_SIZE(priv->real_rates); i++) { +- if (priv->real_rates[i] == 0) +- continue; +- rate = priv->real_rates[i] / 16; +- quot = DIV_ROUND_CLOSEST(rate, baud); +- if (!quot) +- continue; +- +- /* increase resolution to get xx.xx percent */ +- hires_rate = (u64)rate * 10000; +- hires_baud = (u64)baud * 10000; +- +- hires_err = div_u64(hires_rate, (u64)quot); +- +- /* get the delta */ +- if (hires_err > hires_baud) +- hires_err = (hires_err - hires_baud); +- else +- hires_err = (hires_baud - hires_err); +- +- percent = (unsigned long)DIV_ROUND_CLOSEST_ULL(hires_err, baud); +- dev_dbg(up->dev, +- "Baud rate: %u, MUX Clk: %u, Error: %u.%u%%\n", +- baud, priv->real_rates[i], percent / 100, +- percent % 100); +- if (percent < best_percent) { +- best_percent = percent; +- best_index = i; +- best_quot = quot; ++ /* Try default_mux_rate first */ ++ quot = find_quot(up->dev, priv->default_mux_rate, baud, &percent); ++ if (quot) { ++ best_percent = percent; ++ best_freq = priv->default_mux_rate; ++ best_quot = quot; ++ } ++ /* If more than 1% error, find the closest match for specified baud */ ++ if (best_percent > 100) { ++ for (i = 0; i < ARRAY_SIZE(priv->real_rates); i++) { ++ freq = priv->real_rates[i]; ++ if (freq == 0 || freq == priv->default_mux_rate) ++ continue; ++ quot = find_quot(up->dev, freq, baud, &percent); ++ if (!quot) ++ continue; ++ ++ if (percent < best_percent) { ++ best_percent = percent; ++ best_freq = freq; ++ best_quot = quot; ++ } + } + } +- if (best_index == -1) { ++ if (!best_freq) { + dev_err(up->dev, "Error, %d BAUD rate is too fast.\n", baud); + return; + } +- rate = priv->real_rates[best_index]; +- rc = clk_set_rate(priv->baud_mux_clk, rate); ++ rc = clk_set_rate(priv->baud_mux_clk, best_freq); + if (rc) + dev_err(up->dev, "Error selecting BAUD MUX clock\n"); + +@@ -742,8 +761,8 @@ static void set_clock_mux(struct uart_port *up, struct brcmuart_priv *priv, + dev_err(up->dev, "Error, baud: %d has %u.%u%% error\n", + baud, percent / 100, percent % 100); + +- real_baud = rate / 16 / best_quot; +- dev_dbg(up->dev, "Selecting BAUD MUX rate: %u\n", rate); ++ real_baud = best_freq / 16 / best_quot; ++ dev_dbg(up->dev, "Selecting BAUD MUX rate: %u\n", best_freq); + dev_dbg(up->dev, "Requested baud: %u, Actual baud: %u\n", + baud, real_baud); + +@@ -752,7 +771,7 @@ static void set_clock_mux(struct uart_port *up, struct brcmuart_priv *priv, + i += (i / 2); + priv->char_wait = ns_to_ktime(i); + +- up->uartclk = rate; ++ up->uartclk = best_freq; + } + + static void brcmstb_set_termios(struct uart_port *up, +diff --git a/drivers/tty/serial/8250/8250_mtk.c b/drivers/tty/serial/8250/8250_mtk.c +index 74da5676ce67d..28f9a2679a20e 100644 +--- a/drivers/tty/serial/8250/8250_mtk.c ++++ b/drivers/tty/serial/8250/8250_mtk.c +@@ -209,15 +209,19 @@ static int mtk8250_startup(struct uart_port *port) + + static void mtk8250_shutdown(struct uart_port *port) + { +-#ifdef CONFIG_SERIAL_8250_DMA + struct uart_8250_port *up = up_to_u8250p(port); + struct mtk8250_data *data = port->private_data; ++ int irq = data->rx_wakeup_irq; + ++#ifdef CONFIG_SERIAL_8250_DMA + if (up->dma) + data->rx_status = DMA_RX_SHUTDOWN; + #endif + +- return serial8250_do_shutdown(port); ++ serial8250_do_shutdown(port); ++ ++ if (irq >= 0) ++ serial8250_do_set_mctrl(&up->port, TIOCM_RTS); + } + + static void mtk8250_disable_intrs(struct uart_8250_port *up, int mask) +diff --git a/drivers/tty/serial/max3100.c b/drivers/tty/serial/max3100.c +index 5efb2b593be33..3d2b83d6ab51a 100644 +--- a/drivers/tty/serial/max3100.c ++++ b/drivers/tty/serial/max3100.c +@@ -45,6 +45,9 @@ + #include + #include + #include ++#include ++ ++#include + + #include + +@@ -191,7 +194,7 @@ static void max3100_timeout(struct timer_list *t) + static int max3100_sr(struct max3100_port *s, u16 tx, u16 *rx) + { + struct spi_message message; +- u16 etx, erx; ++ __be16 etx, erx; + int status; + struct spi_transfer tran = { + .tx_buf = &etx, +@@ -213,7 +216,7 @@ static int max3100_sr(struct max3100_port *s, u16 tx, u16 *rx) + return 0; + } + +-static int max3100_handlerx(struct max3100_port *s, u16 rx) ++static int max3100_handlerx_unlocked(struct max3100_port *s, u16 rx) + { + unsigned int status = 0; + int ret = 0, cts; +@@ -254,6 +257,17 @@ static int max3100_handlerx(struct max3100_port *s, u16 rx) + return ret; + } + ++static int max3100_handlerx(struct max3100_port *s, u16 rx) ++{ ++ unsigned long flags; ++ int ret; ++ ++ uart_port_lock_irqsave(&s->port, &flags); ++ ret = max3100_handlerx_unlocked(s, rx); ++ uart_port_unlock_irqrestore(&s->port, flags); ++ return ret; ++} ++ + static void max3100_work(struct work_struct *w) + { + struct max3100_port *s = container_of(w, struct max3100_port, work); +@@ -738,13 +752,14 @@ static int max3100_probe(struct spi_device *spi) + mutex_lock(&max3100s_lock); + + if (!uart_driver_registered) { +- uart_driver_registered = 1; + retval = uart_register_driver(&max3100_uart_driver); + if (retval) { + printk(KERN_ERR "Couldn't register max3100 uart driver\n"); + mutex_unlock(&max3100s_lock); + return retval; + } ++ ++ uart_driver_registered = 1; + } + + for (i = 0; i < MAX_MAX3100; i++) +@@ -830,6 +845,7 @@ static void max3100_remove(struct spi_device *spi) + } + pr_debug("removing max3100 driver\n"); + uart_unregister_driver(&max3100_uart_driver); ++ uart_driver_registered = 0; + + mutex_unlock(&max3100s_lock); + } +diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c +index f75b8bceb8ca2..7a9924d9b294e 100644 +--- a/drivers/tty/serial/sc16is7xx.c ++++ b/drivers/tty/serial/sc16is7xx.c +@@ -18,6 +18,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -25,7 +26,6 @@ + #include + #include + #include +-#include + + #define SC16IS7XX_NAME "sc16is7xx" + #define SC16IS7XX_MAX_DEVS 8 +@@ -482,16 +482,28 @@ static bool sc16is7xx_regmap_noinc(struct device *dev, unsigned int reg) + return reg == SC16IS7XX_RHR_REG; + } + ++/* ++ * Configure programmable baud rate generator (divisor) according to the ++ * desired baud rate. ++ * ++ * From the datasheet, the divisor is computed according to: ++ * ++ * XTAL1 input frequency ++ * ----------------------- ++ * prescaler ++ * divisor = --------------------------- ++ * baud-rate x sampling-rate ++ */ + static int sc16is7xx_set_baud(struct uart_port *port, int baud) + { + struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); + u8 lcr; +- u8 prescaler = 0; ++ unsigned int prescaler = 1; + unsigned long clk = port->uartclk, div = clk / 16 / baud; + +- if (div > 0xffff) { +- prescaler = SC16IS7XX_MCR_CLKSEL_BIT; +- div /= 4; ++ if (div >= BIT(16)) { ++ prescaler = 4; ++ div /= prescaler; + } + + /* In an amazing feat of design, the Enhanced Features Register shares +@@ -528,9 +540,10 @@ static int sc16is7xx_set_baud(struct uart_port *port, int baud) + + mutex_unlock(&one->efr_lock); + ++ /* If bit MCR_CLKSEL is set, the divide by 4 prescaler is activated. */ + sc16is7xx_port_update(port, SC16IS7XX_MCR_REG, + SC16IS7XX_MCR_CLKSEL_BIT, +- prescaler); ++ prescaler == 1 ? 0 : SC16IS7XX_MCR_CLKSEL_BIT); + + /* Open the LCR divisors for configuration */ + sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, +@@ -545,7 +558,7 @@ static int sc16is7xx_set_baud(struct uart_port *port, int baud) + /* Put LCR back to the normal mode */ + sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, lcr); + +- return DIV_ROUND_CLOSEST(clk / 16, div); ++ return DIV_ROUND_CLOSEST((clk / prescaler) / 16, div); + } + + static void sc16is7xx_handle_rx(struct uart_port *port, unsigned int rxlen, +diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c +index a560b729fa3b7..f793624fd5018 100644 +--- a/drivers/tty/serial/sh-sci.c ++++ b/drivers/tty/serial/sh-sci.c +@@ -1272,9 +1272,14 @@ static void sci_dma_rx_chan_invalidate(struct sci_port *s) + static void sci_dma_rx_release(struct sci_port *s) + { + struct dma_chan *chan = s->chan_rx_saved; ++ struct uart_port *port = &s->port; ++ unsigned long flags; + ++ uart_port_lock_irqsave(port, &flags); + s->chan_rx_saved = NULL; + sci_dma_rx_chan_invalidate(s); ++ uart_port_unlock_irqrestore(port, flags); ++ + dmaengine_terminate_sync(chan); + dma_free_coherent(chan->device->dev, s->buf_len_rx * 2, s->rx_buf[0], + sg_dma_address(&s->sg_rx[0])); +diff --git a/drivers/ufs/core/ufs-mcq.c b/drivers/ufs/core/ufs-mcq.c +index c873fd8239427..7ae3096814282 100644 +--- a/drivers/ufs/core/ufs-mcq.c ++++ b/drivers/ufs/core/ufs-mcq.c +@@ -597,8 +597,7 @@ static bool ufshcd_mcq_sqe_search(struct ufs_hba *hba, + addr = le64_to_cpu(cmd_desc_base_addr) & CQE_UCD_BA; + + while (sq_head_slot != hwq->sq_tail_slot) { +- utrd = hwq->sqe_base_addr + +- sq_head_slot * sizeof(struct utp_transfer_req_desc); ++ utrd = hwq->sqe_base_addr + sq_head_slot; + match = le64_to_cpu(utrd->command_desc_base_addr) & CQE_UCD_BA; + if (addr == match) { + ufshcd_mcq_nullify_sqe(utrd); +diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c +index 344806330be16..589c90f4d4021 100644 +--- a/drivers/ufs/core/ufshcd.c ++++ b/drivers/ufs/core/ufshcd.c +@@ -4136,7 +4136,7 @@ static int ufshcd_uic_pwr_ctrl(struct ufs_hba *hba, struct uic_command *cmd) + * Make sure UIC command completion interrupt is disabled before + * issuing UIC command. + */ +- wmb(); ++ ufshcd_readl(hba, REG_INTERRUPT_ENABLE); + reenable_intr = true; + } + spin_unlock_irqrestore(hba->host->host_lock, flags); +@@ -10152,7 +10152,7 @@ int ufshcd_system_restore(struct device *dev) + * are updated with the latest queue addresses. Only after + * updating these addresses, we can queue the new commands. + */ +- mb(); ++ ufshcd_readl(hba, REG_UTP_TASK_REQ_LIST_BASE_H); + + /* Resuming from hibernate, assume that link was OFF */ + ufshcd_set_link_off(hba); +@@ -10369,7 +10369,7 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) + * Make sure that UFS interrupts are disabled and any pending interrupt + * status is cleared before registering UFS interrupt handler. + */ +- mb(); ++ ufshcd_readl(hba, REG_INTERRUPT_ENABLE); + + /* IRQ registration */ + err = devm_request_irq(dev, irq, ufshcd_intr, IRQF_SHARED, UFSHCD, hba); +diff --git a/drivers/ufs/host/cdns-pltfrm.c b/drivers/ufs/host/cdns-pltfrm.c +index 2491e7e870283..56014ef302b49 100644 +--- a/drivers/ufs/host/cdns-pltfrm.c ++++ b/drivers/ufs/host/cdns-pltfrm.c +@@ -136,7 +136,7 @@ static int cdns_ufs_set_hclkdiv(struct ufs_hba *hba) + * Make sure the register was updated, + * UniPro layer will not work with an incorrect value. + */ +- mb(); ++ ufshcd_readl(hba, CDNS_UFS_REG_HCLKDIV); + + return 0; + } +diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c +index 797219db026bc..922ae1d76d909 100644 +--- a/drivers/ufs/host/ufs-qcom.c ++++ b/drivers/ufs/host/ufs-qcom.c +@@ -373,9 +373,6 @@ static void ufs_qcom_select_unipro_mode(struct ufs_qcom_host *host) + + if (host->hw_ver.major >= 0x05) + ufshcd_rmwl(host->hba, QUNIPRO_G4_SEL, 0, REG_UFS_CFG0); +- +- /* make sure above configuration is applied before we return */ +- mb(); + } + + /* +@@ -501,7 +498,7 @@ static void ufs_qcom_enable_hw_clk_gating(struct ufs_hba *hba) + REG_UFS_CFG2); + + /* Ensure that HW clock gating is enabled before next operations */ +- mb(); ++ ufshcd_readl(hba, REG_UFS_CFG2); + } + + static int ufs_qcom_hce_enable_notify(struct ufs_hba *hba, +@@ -597,7 +594,7 @@ static int ufs_qcom_cfg_timers(struct ufs_hba *hba, u32 gear, + * make sure above write gets applied before we return from + * this function. + */ +- mb(); ++ ufshcd_readl(hba, REG_UFS_SYS1CLK_1US); + } + + if (ufs_qcom_cap_qunipro(host)) +diff --git a/drivers/ufs/host/ufs-qcom.h b/drivers/ufs/host/ufs-qcom.h +index d6f8e74bd5381..532667d8e6f0e 100644 +--- a/drivers/ufs/host/ufs-qcom.h ++++ b/drivers/ufs/host/ufs-qcom.h +@@ -149,10 +149,10 @@ static inline void ufs_qcom_assert_reset(struct ufs_hba *hba) + REG_UFS_CFG1); + + /* +- * Make sure assertion of ufs phy reset is written to +- * register before returning ++ * Dummy read to ensure the write takes effect before doing any sort ++ * of delay + */ +- mb(); ++ ufshcd_readl(hba, REG_UFS_CFG1); + } + + static inline void ufs_qcom_deassert_reset(struct ufs_hba *hba) +@@ -161,10 +161,10 @@ static inline void ufs_qcom_deassert_reset(struct ufs_hba *hba) + REG_UFS_CFG1); + + /* +- * Make sure de-assertion of ufs phy reset is written to +- * register before returning ++ * Dummy read to ensure the write takes effect before doing any sort ++ * of delay + */ +- mb(); ++ ufshcd_readl(hba, REG_UFS_CFG1); + } + + /* Host controller hardware version: major.minor.step */ +diff --git a/drivers/usb/fotg210/fotg210-core.c b/drivers/usb/fotg210/fotg210-core.c +index 958fc40eae86b..0655afe7f9779 100644 +--- a/drivers/usb/fotg210/fotg210-core.c ++++ b/drivers/usb/fotg210/fotg210-core.c +@@ -95,6 +95,7 @@ static int fotg210_gemini_init(struct fotg210 *fotg, struct resource *res, + + /** + * fotg210_vbus() - Called by gadget driver to enable/disable VBUS ++ * @fotg: pointer to a private fotg210 object + * @enable: true to enable VBUS, false to disable VBUS + */ + void fotg210_vbus(struct fotg210 *fotg, bool enable) +diff --git a/drivers/usb/gadget/function/u_audio.c b/drivers/usb/gadget/function/u_audio.c +index 4a42574b4a7fe..ec1dceb087293 100644 +--- a/drivers/usb/gadget/function/u_audio.c ++++ b/drivers/usb/gadget/function/u_audio.c +@@ -57,13 +57,13 @@ struct uac_rtd_params { + + /* Volume/Mute controls and their state */ + int fu_id; /* Feature Unit ID */ +- struct snd_kcontrol *snd_kctl_volume; +- struct snd_kcontrol *snd_kctl_mute; ++ struct snd_ctl_elem_id snd_kctl_volume_id; ++ struct snd_ctl_elem_id snd_kctl_mute_id; + s16 volume_min, volume_max, volume_res; + s16 volume; + int mute; + +- struct snd_kcontrol *snd_kctl_rate; /* read-only current rate */ ++ struct snd_ctl_elem_id snd_kctl_rate_id; /* read-only current rate */ + int srate; /* selected samplerate */ + int active; /* playback/capture running */ + +@@ -494,14 +494,13 @@ static inline void free_ep_fback(struct uac_rtd_params *prm, struct usb_ep *ep) + static void set_active(struct uac_rtd_params *prm, bool active) + { + // notifying through the Rate ctrl +- struct snd_kcontrol *kctl = prm->snd_kctl_rate; + unsigned long flags; + + spin_lock_irqsave(&prm->lock, flags); + if (prm->active != active) { + prm->active = active; + snd_ctl_notify(prm->uac->card, SNDRV_CTL_EVENT_MASK_VALUE, +- &kctl->id); ++ &prm->snd_kctl_rate_id); + } + spin_unlock_irqrestore(&prm->lock, flags); + } +@@ -807,7 +806,7 @@ int u_audio_set_volume(struct g_audio *audio_dev, int playback, s16 val) + + if (change) + snd_ctl_notify(uac->card, SNDRV_CTL_EVENT_MASK_VALUE, +- &prm->snd_kctl_volume->id); ++ &prm->snd_kctl_volume_id); + + return 0; + } +@@ -856,7 +855,7 @@ int u_audio_set_mute(struct g_audio *audio_dev, int playback, int val) + + if (change) + snd_ctl_notify(uac->card, SNDRV_CTL_EVENT_MASK_VALUE, +- &prm->snd_kctl_mute->id); ++ &prm->snd_kctl_mute_id); + + return 0; + } +@@ -1331,7 +1330,7 @@ int g_audio_setup(struct g_audio *g_audio, const char *pcm_name, + err = snd_ctl_add(card, kctl); + if (err < 0) + goto snd_fail; +- prm->snd_kctl_mute = kctl; ++ prm->snd_kctl_mute_id = kctl->id; + prm->mute = 0; + } + +@@ -1359,7 +1358,7 @@ int g_audio_setup(struct g_audio *g_audio, const char *pcm_name, + err = snd_ctl_add(card, kctl); + if (err < 0) + goto snd_fail; +- prm->snd_kctl_volume = kctl; ++ prm->snd_kctl_volume_id = kctl->id; + prm->volume = fu->volume_max; + prm->volume_max = fu->volume_max; + prm->volume_min = fu->volume_min; +@@ -1383,7 +1382,7 @@ int g_audio_setup(struct g_audio *g_audio, const char *pcm_name, + err = snd_ctl_add(card, kctl); + if (err < 0) + goto snd_fail; +- prm->snd_kctl_rate = kctl; ++ prm->snd_kctl_rate_id = kctl->id; + } + + strscpy(card->driver, card_name, sizeof(card->driver)); +@@ -1420,6 +1419,8 @@ void g_audio_cleanup(struct g_audio *g_audio) + return; + + uac = g_audio->uac; ++ g_audio->uac = NULL; ++ + card = uac->card; + if (card) + snd_card_free_when_closed(card); +diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c +index 7d2ca39ad7622..7f575b9b3debe 100644 +--- a/drivers/usb/typec/ucsi/ucsi.c ++++ b/drivers/usb/typec/ucsi/ucsi.c +@@ -694,12 +694,6 @@ static int ucsi_register_partner_pdos(struct ucsi_connector *con) + return PTR_ERR(cap); + + con->partner_source_caps = cap; +- +- ret = typec_partner_set_usb_power_delivery(con->partner, con->partner_pd); +- if (ret) { +- usb_power_delivery_unregister_capabilities(con->partner_source_caps); +- return ret; +- } + } + + ret = ucsi_get_pdos(con, TYPEC_SINK, 1, caps.pdo); +@@ -714,15 +708,9 @@ static int ucsi_register_partner_pdos(struct ucsi_connector *con) + return PTR_ERR(cap); + + con->partner_sink_caps = cap; +- +- ret = typec_partner_set_usb_power_delivery(con->partner, con->partner_pd); +- if (ret) { +- usb_power_delivery_unregister_capabilities(con->partner_sink_caps); +- return ret; +- } + } + +- return 0; ++ return typec_partner_set_usb_power_delivery(con->partner, con->partner_pd); + } + + static void ucsi_unregister_partner_pdos(struct ucsi_connector *con) +@@ -1297,7 +1285,6 @@ static int ucsi_register_port(struct ucsi *ucsi, struct ucsi_connector *con) + } + + con->port_source_caps = pd_cap; +- typec_port_set_usb_power_delivery(con->port, con->pd); + } + + memset(&pd_caps, 0, sizeof(pd_caps)); +@@ -1314,9 +1301,10 @@ static int ucsi_register_port(struct ucsi *ucsi, struct ucsi_connector *con) + } + + con->port_sink_caps = pd_cap; +- typec_port_set_usb_power_delivery(con->port, con->pd); + } + ++ typec_port_set_usb_power_delivery(con->port, con->pd); ++ + /* Alternate modes */ + ret = ucsi_register_altmodes(con, UCSI_RECIPIENT_CON); + if (ret) { +diff --git a/drivers/usb/usbip/usbip_common.h b/drivers/usb/usbip/usbip_common.h +index d8cbd2dfc2c25..282efca64a012 100644 +--- a/drivers/usb/usbip/usbip_common.h ++++ b/drivers/usb/usbip/usbip_common.h +@@ -298,12 +298,6 @@ struct usbip_device { + __k; \ + }) + +-#define kthread_stop_put(k) \ +- do { \ +- kthread_stop(k); \ +- put_task_struct(k); \ +- } while (0) +- + /* usbip_common.c */ + void usbip_dump_urb(struct urb *purb); + void usbip_dump_header(struct usbip_header *pdu); +diff --git a/drivers/vfio/pci/vfio_pci_intrs.c b/drivers/vfio/pci/vfio_pci_intrs.c +index 99bbd647e5d81..620134041b488 100644 +--- a/drivers/vfio/pci/vfio_pci_intrs.c ++++ b/drivers/vfio/pci/vfio_pci_intrs.c +@@ -277,8 +277,10 @@ static int vfio_intx_enable(struct vfio_pci_core_device *vdev, + return -ENOMEM; + + ctx = vfio_irq_ctx_alloc(vdev, 0); +- if (!ctx) ++ if (!ctx) { ++ kfree(name); + return -ENOMEM; ++ } + + ctx->name = name; + ctx->trigger = trigger; +diff --git a/drivers/video/backlight/lm3630a_bl.c b/drivers/video/backlight/lm3630a_bl.c +index 7115d7bb2a141..26ff4178cc161 100644 +--- a/drivers/video/backlight/lm3630a_bl.c ++++ b/drivers/video/backlight/lm3630a_bl.c +@@ -180,7 +180,7 @@ static int lm3630a_pwm_ctrl(struct lm3630a_chip *pchip, int br, int br_max) + + pchip->pwmd_state.enabled = pchip->pwmd_state.duty_cycle ? true : false; + +- return pwm_apply_state(pchip->pwmd, &pchip->pwmd_state); ++ return pwm_apply_might_sleep(pchip->pwmd, &pchip->pwmd_state); + } + + /* update and get brightness */ +diff --git a/drivers/video/backlight/lp855x_bl.c b/drivers/video/backlight/lp855x_bl.c +index da1f124db69c0..7075bfab59c4d 100644 +--- a/drivers/video/backlight/lp855x_bl.c ++++ b/drivers/video/backlight/lp855x_bl.c +@@ -234,7 +234,7 @@ static int lp855x_pwm_ctrl(struct lp855x *lp, int br, int max_br) + state.duty_cycle = div_u64(br * state.period, max_br); + state.enabled = state.duty_cycle; + +- return pwm_apply_state(lp->pwm, &state); ++ return pwm_apply_might_sleep(lp->pwm, &state); + } + + static int lp855x_bl_update_status(struct backlight_device *bl) +diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c +index 289bd9ce4d36d..35c716e9043c3 100644 +--- a/drivers/video/backlight/pwm_bl.c ++++ b/drivers/video/backlight/pwm_bl.c +@@ -103,7 +103,7 @@ static int pwm_backlight_update_status(struct backlight_device *bl) + pwm_get_state(pb->pwm, &state); + state.duty_cycle = compute_duty_cycle(pb, brightness, &state); + state.enabled = true; +- pwm_apply_state(pb->pwm, &state); ++ pwm_apply_might_sleep(pb->pwm, &state); + + pwm_backlight_power_on(pb); + } else { +@@ -120,7 +120,7 @@ static int pwm_backlight_update_status(struct backlight_device *bl) + * inactive output. + */ + state.enabled = !pb->power_supply && !pb->enable_gpio; +- pwm_apply_state(pb->pwm, &state); ++ pwm_apply_might_sleep(pb->pwm, &state); + } + + if (pb->notify_after) +@@ -528,7 +528,7 @@ static int pwm_backlight_probe(struct platform_device *pdev) + if (!state.period && (data->pwm_period_ns > 0)) + state.period = data->pwm_period_ns; + +- ret = pwm_apply_state(pb->pwm, &state); ++ ret = pwm_apply_might_sleep(pb->pwm, &state); + if (ret) { + dev_err(&pdev->dev, "failed to apply initial PWM state: %d\n", + ret); +@@ -633,7 +633,7 @@ static void pwm_backlight_remove(struct platform_device *pdev) + pwm_get_state(pb->pwm, &state); + state.duty_cycle = 0; + state.enabled = false; +- pwm_apply_state(pb->pwm, &state); ++ pwm_apply_might_sleep(pb->pwm, &state); + + if (pb->exit) + pb->exit(&pdev->dev); +@@ -649,7 +649,7 @@ static void pwm_backlight_shutdown(struct platform_device *pdev) + pwm_get_state(pb->pwm, &state); + state.duty_cycle = 0; + state.enabled = false; +- pwm_apply_state(pb->pwm, &state); ++ pwm_apply_might_sleep(pb->pwm, &state); + } + + #ifdef CONFIG_PM_SLEEP +@@ -673,7 +673,7 @@ static int pwm_backlight_suspend(struct device *dev) + pwm_get_state(pb->pwm, &state); + state.duty_cycle = 0; + state.enabled = false; +- pwm_apply_state(pb->pwm, &state); ++ pwm_apply_might_sleep(pb->pwm, &state); + + if (pb->notify_after) + pb->notify_after(pb->dev, 0); +diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig +index c29754b65c0ec..325298573e120 100644 +--- a/drivers/video/fbdev/Kconfig ++++ b/drivers/video/fbdev/Kconfig +@@ -1761,8 +1761,8 @@ config FB_COBALT + depends on FB && MIPS_COBALT + + config FB_SH7760 +- bool "SH7760/SH7763/SH7720/SH7721 LCDC support" +- depends on FB=y && (CPU_SUBTYPE_SH7760 || CPU_SUBTYPE_SH7763 \ ++ tristate "SH7760/SH7763/SH7720/SH7721 LCDC support" ++ depends on FB && (CPU_SUBTYPE_SH7760 || CPU_SUBTYPE_SH7763 \ + || CPU_SUBTYPE_SH7720 || CPU_SUBTYPE_SH7721) + select FB_IOMEM_HELPERS + help +diff --git a/drivers/video/fbdev/core/Kconfig b/drivers/video/fbdev/core/Kconfig +index 5ac1b06375311..acb19045d3046 100644 +--- a/drivers/video/fbdev/core/Kconfig ++++ b/drivers/video/fbdev/core/Kconfig +@@ -4,6 +4,7 @@ + # + + config FB_CORE ++ select FB_IOMEM_FOPS + select VIDEO_CMDLINE + tristate + +@@ -144,12 +145,23 @@ config FB_DMAMEM_HELPERS + select FB_SYS_FOPS + select FB_SYS_IMAGEBLIT + ++config FB_DMAMEM_HELPERS_DEFERRED ++ bool ++ depends on FB_CORE ++ select FB_DEFERRED_IO ++ select FB_DMAMEM_HELPERS ++ ++config FB_IOMEM_FOPS ++ tristate ++ depends on FB_CORE ++ + config FB_IOMEM_HELPERS + bool + depends on FB_CORE + select FB_CFB_COPYAREA + select FB_CFB_FILLRECT + select FB_CFB_IMAGEBLIT ++ select FB_IOMEM_FOPS + + config FB_SYSMEM_HELPERS + bool +diff --git a/drivers/video/fbdev/core/Makefile b/drivers/video/fbdev/core/Makefile +index edfde2948e5c8..d165055ec3fc5 100644 +--- a/drivers/video/fbdev/core/Makefile ++++ b/drivers/video/fbdev/core/Makefile +@@ -3,7 +3,7 @@ obj-$(CONFIG_FB_NOTIFY) += fb_notify.o + obj-$(CONFIG_FB_CORE) += fb.o + fb-y := fb_info.o \ + fbmem.o fbcmap.o \ +- modedb.o fbcvt.o fb_cmdline.o fb_io_fops.o ++ modedb.o fbcvt.o fb_cmdline.o + ifdef CONFIG_FB + fb-y += fb_backlight.o fbmon.o + endif +@@ -26,6 +26,7 @@ endif + obj-$(CONFIG_FB_CFB_FILLRECT) += cfbfillrect.o + obj-$(CONFIG_FB_CFB_COPYAREA) += cfbcopyarea.o + obj-$(CONFIG_FB_CFB_IMAGEBLIT) += cfbimgblt.o ++obj-$(CONFIG_FB_IOMEM_FOPS) += fb_io_fops.o + obj-$(CONFIG_FB_SYS_FILLRECT) += sysfillrect.o + obj-$(CONFIG_FB_SYS_COPYAREA) += syscopyarea.o + obj-$(CONFIG_FB_SYS_IMAGEBLIT) += sysimgblt.o +diff --git a/drivers/video/fbdev/core/fb_io_fops.c b/drivers/video/fbdev/core/fb_io_fops.c +index 5985e5e1b040c..871b829521af3 100644 +--- a/drivers/video/fbdev/core/fb_io_fops.c ++++ b/drivers/video/fbdev/core/fb_io_fops.c +@@ -131,3 +131,6 @@ ssize_t fb_io_write(struct fb_info *info, const char __user *buf, size_t count, + return (cnt) ? cnt : err; + } + EXPORT_SYMBOL(fb_io_write); ++ ++MODULE_DESCRIPTION("Fbdev helpers for framebuffers in I/O memory"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/video/fbdev/sh_mobile_lcdcfb.c b/drivers/video/fbdev/sh_mobile_lcdcfb.c +index 1364dafaadb1d..2a4794ec19473 100644 +--- a/drivers/video/fbdev/sh_mobile_lcdcfb.c ++++ b/drivers/video/fbdev/sh_mobile_lcdcfb.c +@@ -1575,7 +1575,7 @@ sh_mobile_lcdc_overlay_fb_init(struct sh_mobile_lcdc_overlay *ovl) + */ + info->fix = sh_mobile_lcdc_overlay_fix; + snprintf(info->fix.id, sizeof(info->fix.id), +- "SH Mobile LCDC Overlay %u", ovl->index); ++ "SHMobile ovl %u", ovl->index); + info->fix.smem_start = ovl->dma_handle; + info->fix.smem_len = ovl->fb_size; + info->fix.line_length = ovl->pitch; +diff --git a/drivers/video/fbdev/sis/init301.c b/drivers/video/fbdev/sis/init301.c +index a8fb41f1a2580..09329072004f4 100644 +--- a/drivers/video/fbdev/sis/init301.c ++++ b/drivers/video/fbdev/sis/init301.c +@@ -172,7 +172,7 @@ static const unsigned char SiS_HiTVGroup3_2[] = { + }; + + /* 301C / 302ELV extended Part2 TV registers (4 tap scaler) */ +- ++#ifdef CONFIG_FB_SIS_315 + static const unsigned char SiS_Part2CLVX_1[] = { + 0x00,0x00, + 0x00,0x20,0x00,0x00,0x7F,0x20,0x02,0x7F,0x7D,0x20,0x04,0x7F,0x7D,0x1F,0x06,0x7E, +@@ -245,7 +245,6 @@ static const unsigned char SiS_Part2CLVX_6[] = { /* 1080i */ + 0xFF,0xFF, + }; + +-#ifdef CONFIG_FB_SIS_315 + /* 661 et al LCD data structure (2.03.00) */ + static const unsigned char SiS_LCDStruct661[] = { + /* 1024x768 */ +diff --git a/drivers/video/fbdev/ssd1307fb.c b/drivers/video/fbdev/ssd1307fb.c +index 5ae48e36fccb4..1a4f90ea7d5a8 100644 +--- a/drivers/video/fbdev/ssd1307fb.c ++++ b/drivers/video/fbdev/ssd1307fb.c +@@ -347,7 +347,7 @@ static int ssd1307fb_init(struct ssd1307fb_par *par) + + pwm_init_state(par->pwm, &pwmstate); + pwm_set_relative_duty_cycle(&pwmstate, 50, 100); +- pwm_apply_state(par->pwm, &pwmstate); ++ pwm_apply_might_sleep(par->pwm, &pwmstate); + + /* Enable the PWM */ + pwm_enable(par->pwm); +diff --git a/drivers/virt/acrn/mm.c b/drivers/virt/acrn/mm.c +index b4ad8d452e9a1..8ef49d7be453c 100644 +--- a/drivers/virt/acrn/mm.c ++++ b/drivers/virt/acrn/mm.c +@@ -155,43 +155,83 @@ int acrn_vm_memseg_unmap(struct acrn_vm *vm, struct acrn_vm_memmap *memmap) + int acrn_vm_ram_map(struct acrn_vm *vm, struct acrn_vm_memmap *memmap) + { + struct vm_memory_region_batch *regions_info; +- int nr_pages, i = 0, order, nr_regions = 0; ++ int nr_pages, i, order, nr_regions = 0; + struct vm_memory_mapping *region_mapping; + struct vm_memory_region_op *vm_region; + struct page **pages = NULL, *page; + void *remap_vaddr; + int ret, pinned; + u64 user_vm_pa; +- unsigned long pfn; + struct vm_area_struct *vma; + + if (!vm || !memmap) + return -EINVAL; + ++ /* Get the page number of the map region */ ++ nr_pages = memmap->len >> PAGE_SHIFT; ++ if (!nr_pages) ++ return -EINVAL; ++ + mmap_read_lock(current->mm); + vma = vma_lookup(current->mm, memmap->vma_base); + if (vma && ((vma->vm_flags & VM_PFNMAP) != 0)) { ++ unsigned long start_pfn, cur_pfn; ++ spinlock_t *ptl; ++ bool writable; ++ pte_t *ptep; ++ + if ((memmap->vma_base + memmap->len) > vma->vm_end) { + mmap_read_unlock(current->mm); + return -EINVAL; + } + +- ret = follow_pfn(vma, memmap->vma_base, &pfn); ++ for (i = 0; i < nr_pages; i++) { ++ ret = follow_pte(vma->vm_mm, ++ memmap->vma_base + i * PAGE_SIZE, ++ &ptep, &ptl); ++ if (ret) ++ break; ++ ++ cur_pfn = pte_pfn(ptep_get(ptep)); ++ if (i == 0) ++ start_pfn = cur_pfn; ++ writable = !!pte_write(ptep_get(ptep)); ++ pte_unmap_unlock(ptep, ptl); ++ ++ /* Disallow write access if the PTE is not writable. */ ++ if (!writable && ++ (memmap->attr & ACRN_MEM_ACCESS_WRITE)) { ++ ret = -EFAULT; ++ break; ++ } ++ ++ /* Disallow refcounted pages. */ ++ if (pfn_valid(cur_pfn) && ++ !PageReserved(pfn_to_page(cur_pfn))) { ++ ret = -EFAULT; ++ break; ++ } ++ ++ /* Disallow non-contiguous ranges. */ ++ if (cur_pfn != start_pfn + i) { ++ ret = -EINVAL; ++ break; ++ } ++ } + mmap_read_unlock(current->mm); +- if (ret < 0) { ++ ++ if (ret) { + dev_dbg(acrn_dev.this_device, + "Failed to lookup PFN at VMA:%pK.\n", (void *)memmap->vma_base); + return ret; + } + + return acrn_mm_region_add(vm, memmap->user_vm_pa, +- PFN_PHYS(pfn), memmap->len, ++ PFN_PHYS(start_pfn), memmap->len, + ACRN_MEM_TYPE_WB, memmap->attr); + } + mmap_read_unlock(current->mm); + +- /* Get the page number of the map region */ +- nr_pages = memmap->len >> PAGE_SHIFT; + pages = vzalloc(array_size(nr_pages, sizeof(*pages))); + if (!pages) + return -ENOMEM; +@@ -235,12 +275,11 @@ int acrn_vm_ram_map(struct acrn_vm *vm, struct acrn_vm_memmap *memmap) + mutex_unlock(&vm->regions_mapping_lock); + + /* Calculate count of vm_memory_region_op */ +- while (i < nr_pages) { ++ for (i = 0; i < nr_pages; i += 1 << order) { + page = pages[i]; + VM_BUG_ON_PAGE(PageTail(page), page); + order = compound_order(page); + nr_regions++; +- i += 1 << order; + } + + /* Prepare the vm_memory_region_batch */ +@@ -257,8 +296,7 @@ int acrn_vm_ram_map(struct acrn_vm *vm, struct acrn_vm_memmap *memmap) + regions_info->regions_num = nr_regions; + regions_info->regions_gpa = virt_to_phys(vm_region); + user_vm_pa = memmap->user_vm_pa; +- i = 0; +- while (i < nr_pages) { ++ for (i = 0; i < nr_pages; i += 1 << order) { + u32 region_size; + + page = pages[i]; +@@ -274,7 +312,6 @@ int acrn_vm_ram_map(struct acrn_vm *vm, struct acrn_vm_memmap *memmap) + + vm_region++; + user_vm_pa += region_size; +- i += 1 << order; + } + + /* Inform the ACRN Hypervisor to set up EPT mappings */ +diff --git a/drivers/virtio/virtio_pci_common.c b/drivers/virtio/virtio_pci_common.c +index c2524a7207cfa..64dfa54d702f1 100644 +--- a/drivers/virtio/virtio_pci_common.c ++++ b/drivers/virtio/virtio_pci_common.c +@@ -345,8 +345,10 @@ static int vp_find_vqs_msix(struct virtio_device *vdev, unsigned int nvqs, + vring_interrupt, 0, + vp_dev->msix_names[msix_vec], + vqs[i]); +- if (err) ++ if (err) { ++ vp_del_vq(vqs[i]); + goto error_find; ++ } + } + return 0; + +diff --git a/drivers/watchdog/bd9576_wdt.c b/drivers/watchdog/bd9576_wdt.c +index 4a20e07fbb699..f00ea1b4e40b6 100644 +--- a/drivers/watchdog/bd9576_wdt.c ++++ b/drivers/watchdog/bd9576_wdt.c +@@ -29,7 +29,6 @@ struct bd9576_wdt_priv { + struct gpio_desc *gpiod_en; + struct device *dev; + struct regmap *regmap; +- bool always_running; + struct watchdog_device wdd; + }; + +@@ -62,10 +61,7 @@ static int bd9576_wdt_stop(struct watchdog_device *wdd) + { + struct bd9576_wdt_priv *priv = watchdog_get_drvdata(wdd); + +- if (!priv->always_running) +- bd9576_wdt_disable(priv); +- else +- set_bit(WDOG_HW_RUNNING, &wdd->status); ++ bd9576_wdt_disable(priv); + + return 0; + } +@@ -264,9 +260,6 @@ static int bd9576_wdt_probe(struct platform_device *pdev) + if (ret) + return ret; + +- priv->always_running = device_property_read_bool(dev->parent, +- "always-running"); +- + watchdog_set_drvdata(&priv->wdd, priv); + + priv->wdd.info = &bd957x_wdt_ident; +@@ -281,9 +274,6 @@ static int bd9576_wdt_probe(struct platform_device *pdev) + + watchdog_stop_on_reboot(&priv->wdd); + +- if (priv->always_running) +- bd9576_wdt_start(&priv->wdd); +- + return devm_watchdog_register_device(dev, &priv->wdd); + } + +diff --git a/drivers/watchdog/cpu5wdt.c b/drivers/watchdog/cpu5wdt.c +index 688b112e712ba..9f279c0e13a66 100644 +--- a/drivers/watchdog/cpu5wdt.c ++++ b/drivers/watchdog/cpu5wdt.c +@@ -252,7 +252,7 @@ static void cpu5wdt_exit(void) + if (cpu5wdt_device.queue) { + cpu5wdt_device.queue = 0; + wait_for_completion(&cpu5wdt_device.stop); +- del_timer(&cpu5wdt_device.timer); ++ timer_shutdown_sync(&cpu5wdt_device.timer); + } + + misc_deregister(&cpu5wdt_misc); +diff --git a/drivers/watchdog/sa1100_wdt.c b/drivers/watchdog/sa1100_wdt.c +index 5d2df008b92a5..34a917221e316 100644 +--- a/drivers/watchdog/sa1100_wdt.c ++++ b/drivers/watchdog/sa1100_wdt.c +@@ -191,9 +191,8 @@ static int sa1100dog_probe(struct platform_device *pdev) + if (!res) + return -ENXIO; + reg_base = devm_ioremap(&pdev->dev, res->start, resource_size(res)); +- ret = PTR_ERR_OR_ZERO(reg_base); +- if (ret) +- return ret; ++ if (!reg_base) ++ return -ENOMEM; + + clk = clk_get(NULL, "OSTIMER0"); + if (IS_ERR(clk)) { +diff --git a/drivers/xen/xenbus/xenbus_probe.c b/drivers/xen/xenbus/xenbus_probe.c +index 3205e5d724c8c..1a9ded0cddcb0 100644 +--- a/drivers/xen/xenbus/xenbus_probe.c ++++ b/drivers/xen/xenbus/xenbus_probe.c +@@ -65,13 +65,17 @@ + #include "xenbus.h" + + +-static int xs_init_irq; ++static int xs_init_irq = -1; + int xen_store_evtchn; + EXPORT_SYMBOL_GPL(xen_store_evtchn); + + struct xenstore_domain_interface *xen_store_interface; + EXPORT_SYMBOL_GPL(xen_store_interface); + ++#define XS_INTERFACE_READY \ ++ ((xen_store_interface != NULL) && \ ++ (xen_store_interface->connection == XENSTORE_CONNECTED)) ++ + enum xenstore_init xen_store_domain_type; + EXPORT_SYMBOL_GPL(xen_store_domain_type); + +@@ -751,19 +755,19 @@ static void xenbus_probe(void) + { + xenstored_ready = 1; + +- if (!xen_store_interface) { ++ if (!xen_store_interface) + xen_store_interface = memremap(xen_store_gfn << XEN_PAGE_SHIFT, + XEN_PAGE_SIZE, MEMREMAP_WB); +- /* +- * Now it is safe to free the IRQ used for xenstore late +- * initialization. No need to unbind: it is about to be +- * bound again from xb_init_comms. Note that calling +- * unbind_from_irqhandler now would result in xen_evtchn_close() +- * being called and the event channel not being enabled again +- * afterwards, resulting in missed event notifications. +- */ ++ /* ++ * Now it is safe to free the IRQ used for xenstore late ++ * initialization. No need to unbind: it is about to be ++ * bound again from xb_init_comms. Note that calling ++ * unbind_from_irqhandler now would result in xen_evtchn_close() ++ * being called and the event channel not being enabled again ++ * afterwards, resulting in missed event notifications. ++ */ ++ if (xs_init_irq >= 0) + free_irq(xs_init_irq, &xb_waitq); +- } + + /* + * In the HVM case, xenbus_init() deferred its call to +@@ -822,7 +826,7 @@ static int __init xenbus_probe_initcall(void) + if (xen_store_domain_type == XS_PV || + (xen_store_domain_type == XS_HVM && + !xs_hvm_defer_init_for_callback() && +- xen_store_interface != NULL)) ++ XS_INTERFACE_READY)) + xenbus_probe(); + + /* +@@ -831,7 +835,7 @@ static int __init xenbus_probe_initcall(void) + * started, then probe. It will be triggered when communication + * starts happening, by waiting on xb_waitq. + */ +- if (xen_store_domain_type == XS_LOCAL || xen_store_interface == NULL) { ++ if (xen_store_domain_type == XS_LOCAL || !XS_INTERFACE_READY) { + struct task_struct *probe_task; + + probe_task = kthread_run(xenbus_probe_thread, NULL, +@@ -1014,6 +1018,12 @@ static int __init xenbus_init(void) + xen_store_interface = + memremap(xen_store_gfn << XEN_PAGE_SHIFT, + XEN_PAGE_SIZE, MEMREMAP_WB); ++ if (!xen_store_interface) { ++ pr_err("%s: cannot map HVM_PARAM_STORE_PFN=%llx\n", ++ __func__, v); ++ err = -EINVAL; ++ goto out_error; ++ } + if (xen_store_interface->connection != XENSTORE_CONNECTED) + wait = true; + } +diff --git a/fs/dlm/ast.c b/fs/dlm/ast.c +index 1f2f70a1b824e..decedc4ee15f6 100644 +--- a/fs/dlm/ast.c ++++ b/fs/dlm/ast.c +@@ -12,6 +12,7 @@ + #include + + #include "dlm_internal.h" ++#include "lvb_table.h" + #include "memory.h" + #include "lock.h" + #include "user.h" +@@ -42,6 +43,7 @@ int dlm_enqueue_lkb_callback(struct dlm_lkb *lkb, uint32_t flags, int mode, + struct dlm_ls *ls = lkb->lkb_resource->res_ls; + int rv = DLM_ENQUEUE_CALLBACK_SUCCESS; + struct dlm_callback *cb; ++ int copy_lvb = 0; + int prev_mode; + + if (flags & DLM_CB_BAST) { +@@ -73,6 +75,17 @@ int dlm_enqueue_lkb_callback(struct dlm_lkb *lkb, uint32_t flags, int mode, + goto out; + } + } ++ } else if (flags & DLM_CB_CAST) { ++ if (test_bit(DLM_DFL_USER_BIT, &lkb->lkb_dflags)) { ++ if (lkb->lkb_last_cast) ++ prev_mode = lkb->lkb_last_cb->mode; ++ else ++ prev_mode = -1; ++ ++ if (!status && lkb->lkb_lksb->sb_lvbptr && ++ dlm_lvb_operations[prev_mode + 1][mode + 1]) ++ copy_lvb = 1; ++ } + } + + cb = dlm_allocate_cb(); +@@ -85,6 +98,7 @@ int dlm_enqueue_lkb_callback(struct dlm_lkb *lkb, uint32_t flags, int mode, + cb->mode = mode; + cb->sb_status = status; + cb->sb_flags = (sbflags & 0x000000FF); ++ cb->copy_lvb = copy_lvb; + kref_init(&cb->ref); + if (!test_and_set_bit(DLM_IFL_CB_PENDING_BIT, &lkb->lkb_iflags)) + rv = DLM_ENQUEUE_CALLBACK_NEED_SCHED; +diff --git a/fs/dlm/dlm_internal.h b/fs/dlm/dlm_internal.h +index dfc444dad3298..511d0b984f580 100644 +--- a/fs/dlm/dlm_internal.h ++++ b/fs/dlm/dlm_internal.h +@@ -222,6 +222,7 @@ struct dlm_callback { + int sb_status; /* copy to lksb status */ + uint8_t sb_flags; /* copy to lksb flags */ + int8_t mode; /* rq mode of bast, gr mode of cast */ ++ int copy_lvb; + + struct list_head list; + struct kref ref; +diff --git a/fs/dlm/user.c b/fs/dlm/user.c +index 9f9b68448830e..12a483deeef5e 100644 +--- a/fs/dlm/user.c ++++ b/fs/dlm/user.c +@@ -21,7 +21,6 @@ + #include "dlm_internal.h" + #include "lockspace.h" + #include "lock.h" +-#include "lvb_table.h" + #include "user.h" + #include "ast.h" + #include "config.h" +@@ -806,8 +805,7 @@ static ssize_t device_read(struct file *file, char __user *buf, size_t count, + struct dlm_lkb *lkb; + DECLARE_WAITQUEUE(wait, current); + struct dlm_callback *cb; +- int rv, ret, copy_lvb = 0; +- int old_mode, new_mode; ++ int rv, ret; + + if (count == sizeof(struct dlm_device_version)) { + rv = copy_version_to_user(buf, count); +@@ -864,9 +862,6 @@ static ssize_t device_read(struct file *file, char __user *buf, size_t count, + + lkb = list_first_entry(&proc->asts, struct dlm_lkb, lkb_cb_list); + +- /* rem_lkb_callback sets a new lkb_last_cast */ +- old_mode = lkb->lkb_last_cast->mode; +- + rv = dlm_dequeue_lkb_callback(lkb, &cb); + switch (rv) { + case DLM_DEQUEUE_CALLBACK_EMPTY: +@@ -895,12 +890,6 @@ static ssize_t device_read(struct file *file, char __user *buf, size_t count, + if (cb->flags & DLM_CB_BAST) { + trace_dlm_bast(lkb->lkb_resource->res_ls, lkb, cb->mode); + } else if (cb->flags & DLM_CB_CAST) { +- new_mode = cb->mode; +- +- if (!cb->sb_status && lkb->lkb_lksb->sb_lvbptr && +- dlm_lvb_operations[old_mode + 1][new_mode + 1]) +- copy_lvb = 1; +- + lkb->lkb_lksb->sb_status = cb->sb_status; + lkb->lkb_lksb->sb_flags = cb->sb_flags; + trace_dlm_ast(lkb->lkb_resource->res_ls, lkb); +@@ -908,7 +897,7 @@ static ssize_t device_read(struct file *file, char __user *buf, size_t count, + + ret = copy_result_to_user(lkb->lkb_ua, + test_bit(DLM_PROC_FLAGS_COMPAT, &proc->flags), +- cb->flags, cb->mode, copy_lvb, buf, count); ++ cb->flags, cb->mode, cb->copy_lvb, buf, count); + + kref_put(&cb->ref, dlm_release_callback); + +diff --git a/fs/ecryptfs/keystore.c b/fs/ecryptfs/keystore.c +index 3fe41964c0d8d..7f9f68c00ef63 100644 +--- a/fs/ecryptfs/keystore.c ++++ b/fs/ecryptfs/keystore.c +@@ -300,9 +300,11 @@ write_tag_66_packet(char *signature, u8 cipher_code, + * | Key Identifier Size | 1 or 2 bytes | + * | Key Identifier | arbitrary | + * | File Encryption Key Size | 1 or 2 bytes | ++ * | Cipher Code | 1 byte | + * | File Encryption Key | arbitrary | ++ * | Checksum | 2 bytes | + */ +- data_len = (5 + ECRYPTFS_SIG_SIZE_HEX + crypt_stat->key_size); ++ data_len = (8 + ECRYPTFS_SIG_SIZE_HEX + crypt_stat->key_size); + *packet = kmalloc(data_len, GFP_KERNEL); + message = *packet; + if (!message) { +diff --git a/fs/eventpoll.c b/fs/eventpoll.c +index 1d9a71a0c4c16..0ed73bc7d4652 100644 +--- a/fs/eventpoll.c ++++ b/fs/eventpoll.c +@@ -876,6 +876,34 @@ static __poll_t __ep_eventpoll_poll(struct file *file, poll_table *wait, int dep + return res; + } + ++/* ++ * The ffd.file pointer may be in the process of being torn down due to ++ * being closed, but we may not have finished eventpoll_release() yet. ++ * ++ * Normally, even with the atomic_long_inc_not_zero, the file may have ++ * been free'd and then gotten re-allocated to something else (since ++ * files are not RCU-delayed, they are SLAB_TYPESAFE_BY_RCU). ++ * ++ * But for epoll, users hold the ep->mtx mutex, and as such any file in ++ * the process of being free'd will block in eventpoll_release_file() ++ * and thus the underlying file allocation will not be free'd, and the ++ * file re-use cannot happen. ++ * ++ * For the same reason we can avoid a rcu_read_lock() around the ++ * operation - 'ffd.file' cannot go away even if the refcount has ++ * reached zero (but we must still not call out to ->poll() functions ++ * etc). ++ */ ++static struct file *epi_fget(const struct epitem *epi) ++{ ++ struct file *file; ++ ++ file = epi->ffd.file; ++ if (!atomic_long_inc_not_zero(&file->f_count)) ++ file = NULL; ++ return file; ++} ++ + /* + * Differs from ep_eventpoll_poll() in that internal callers already have + * the ep->mtx so we need to start from depth=1, such that mutex_lock_nested() +@@ -884,14 +912,22 @@ static __poll_t __ep_eventpoll_poll(struct file *file, poll_table *wait, int dep + static __poll_t ep_item_poll(const struct epitem *epi, poll_table *pt, + int depth) + { +- struct file *file = epi->ffd.file; ++ struct file *file = epi_fget(epi); + __poll_t res; + ++ /* ++ * We could return EPOLLERR | EPOLLHUP or something, but let's ++ * treat this more as "file doesn't exist, poll didn't happen". ++ */ ++ if (!file) ++ return 0; ++ + pt->_key = epi->event.events; + if (!is_file_epoll(file)) + res = vfs_poll(file, pt); + else + res = __ep_eventpoll_poll(file, pt, depth); ++ fput(file); + return res & epi->event.events; + } + +diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c +index d7732320431ac..abb49f6c6ff45 100644 +--- a/fs/ext4/inode.c ++++ b/fs/ext4/inode.c +@@ -2895,9 +2895,6 @@ static int ext4_da_write_begin(struct file *file, struct address_space *mapping, + if (IS_ERR(folio)) + return PTR_ERR(folio); + +- /* In case writeback began while the folio was unlocked */ +- folio_wait_stable(folio); +- + #ifdef CONFIG_FS_ENCRYPTION + ret = ext4_block_write_begin(folio, pos, len, ext4_da_get_block_prep); + #else +diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c +index a8a3ea2fd690f..aadfeb0f5b7f3 100644 +--- a/fs/ext4/mballoc.c ++++ b/fs/ext4/mballoc.c +@@ -6144,6 +6144,7 @@ ext4_mb_new_blocks_simple(struct ext4_allocation_request *ar, int *errp) + ext4_mb_mark_bb(sb, block, 1, 1); + ar->len = 1; + ++ *errp = 0; + return block; + } + +diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c +index bbda587f76b85..a2ee882e5ebb0 100644 +--- a/fs/ext4/namei.c ++++ b/fs/ext4/namei.c +@@ -2901,7 +2901,7 @@ static int ext4_tmpfile(struct mnt_idmap *idmap, struct inode *dir, + inode = ext4_new_inode_start_handle(idmap, dir, mode, + NULL, 0, NULL, + EXT4_HT_DIR, +- EXT4_MAXQUOTAS_INIT_BLOCKS(dir->i_sb) + ++ EXT4_MAXQUOTAS_TRANS_BLOCKS(dir->i_sb) + + 4 + EXT4_XATTR_TRANS_BLOCKS); + handle = ext4_journal_current_handle(); + err = PTR_ERR(inode); +diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c +index 9afc8d24dc369..58ce751da92bf 100644 +--- a/fs/f2fs/checkpoint.c ++++ b/fs/f2fs/checkpoint.c +@@ -889,7 +889,7 @@ static struct page *validate_checkpoint(struct f2fs_sb_info *sbi, + + cp_blocks = le32_to_cpu(cp_block->cp_pack_total_block_count); + +- if (cp_blocks > sbi->blocks_per_seg || cp_blocks <= F2FS_CP_PACKS) { ++ if (cp_blocks > BLKS_PER_SEG(sbi) || cp_blocks <= F2FS_CP_PACKS) { + f2fs_warn(sbi, "invalid cp_pack_total_block_count:%u", + le32_to_cpu(cp_block->cp_pack_total_block_count)); + goto invalid_cp; +@@ -1324,7 +1324,7 @@ static void update_ckpt_flags(struct f2fs_sb_info *sbi, struct cp_control *cpc) + + if (cpc->reason & CP_UMOUNT) { + if (le32_to_cpu(ckpt->cp_pack_total_block_count) + +- NM_I(sbi)->nat_bits_blocks > sbi->blocks_per_seg) { ++ NM_I(sbi)->nat_bits_blocks > BLKS_PER_SEG(sbi)) { + clear_ckpt_flags(sbi, CP_NAT_BITS_FLAG); + f2fs_notice(sbi, "Disable nat_bits due to no space"); + } else if (!is_set_ckpt_flags(sbi, CP_NAT_BITS_FLAG) && +@@ -1527,7 +1527,7 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) + cp_ver |= ((__u64)crc32 << 32); + *(__le64 *)nm_i->nat_bits = cpu_to_le64(cp_ver); + +- blk = start_blk + sbi->blocks_per_seg - nm_i->nat_bits_blocks; ++ blk = start_blk + BLKS_PER_SEG(sbi) - nm_i->nat_bits_blocks; + for (i = 0; i < nm_i->nat_bits_blocks; i++) + f2fs_update_meta_page(sbi, nm_i->nat_bits + + (i << F2FS_BLKSIZE_BITS), blk + i); +@@ -1731,9 +1731,9 @@ void f2fs_init_ino_entry_info(struct f2fs_sb_info *sbi) + im->ino_num = 0; + } + +- sbi->max_orphans = (sbi->blocks_per_seg - F2FS_CP_PACKS - ++ sbi->max_orphans = (BLKS_PER_SEG(sbi) - F2FS_CP_PACKS - + NR_CURSEG_PERSIST_TYPE - __cp_payload(sbi)) * +- F2FS_ORPHANS_PER_BLOCK; ++ F2FS_ORPHANS_PER_BLOCK; + } + + int __init f2fs_create_checkpoint_caches(void) +diff --git a/fs/f2fs/compress.c b/fs/f2fs/compress.c +index a7037644b9324..c07fe6b840a09 100644 +--- a/fs/f2fs/compress.c ++++ b/fs/f2fs/compress.c +@@ -198,8 +198,8 @@ static int lzo_compress_pages(struct compress_ctx *cc) + ret = lzo1x_1_compress(cc->rbuf, cc->rlen, cc->cbuf->cdata, + &cc->clen, cc->private); + if (ret != LZO_E_OK) { +- printk_ratelimited("%sF2FS-fs (%s): lzo compress failed, ret:%d\n", +- KERN_ERR, F2FS_I_SB(cc->inode)->sb->s_id, ret); ++ f2fs_err_ratelimited(F2FS_I_SB(cc->inode), ++ "lzo compress failed, ret:%d", ret); + return -EIO; + } + return 0; +@@ -212,17 +212,15 @@ static int lzo_decompress_pages(struct decompress_io_ctx *dic) + ret = lzo1x_decompress_safe(dic->cbuf->cdata, dic->clen, + dic->rbuf, &dic->rlen); + if (ret != LZO_E_OK) { +- printk_ratelimited("%sF2FS-fs (%s): lzo decompress failed, ret:%d\n", +- KERN_ERR, F2FS_I_SB(dic->inode)->sb->s_id, ret); ++ f2fs_err_ratelimited(F2FS_I_SB(dic->inode), ++ "lzo decompress failed, ret:%d", ret); + return -EIO; + } + + if (dic->rlen != PAGE_SIZE << dic->log_cluster_size) { +- printk_ratelimited("%sF2FS-fs (%s): lzo invalid rlen:%zu, " +- "expected:%lu\n", KERN_ERR, +- F2FS_I_SB(dic->inode)->sb->s_id, +- dic->rlen, +- PAGE_SIZE << dic->log_cluster_size); ++ f2fs_err_ratelimited(F2FS_I_SB(dic->inode), ++ "lzo invalid rlen:%zu, expected:%lu", ++ dic->rlen, PAGE_SIZE << dic->log_cluster_size); + return -EIO; + } + return 0; +@@ -294,16 +292,15 @@ static int lz4_decompress_pages(struct decompress_io_ctx *dic) + ret = LZ4_decompress_safe(dic->cbuf->cdata, dic->rbuf, + dic->clen, dic->rlen); + if (ret < 0) { +- printk_ratelimited("%sF2FS-fs (%s): lz4 decompress failed, ret:%d\n", +- KERN_ERR, F2FS_I_SB(dic->inode)->sb->s_id, ret); ++ f2fs_err_ratelimited(F2FS_I_SB(dic->inode), ++ "lz4 decompress failed, ret:%d", ret); + return -EIO; + } + + if (ret != PAGE_SIZE << dic->log_cluster_size) { +- printk_ratelimited("%sF2FS-fs (%s): lz4 invalid ret:%d, " +- "expected:%lu\n", KERN_ERR, +- F2FS_I_SB(dic->inode)->sb->s_id, ret, +- PAGE_SIZE << dic->log_cluster_size); ++ f2fs_err_ratelimited(F2FS_I_SB(dic->inode), ++ "lz4 invalid ret:%d, expected:%lu", ++ ret, PAGE_SIZE << dic->log_cluster_size); + return -EIO; + } + return 0; +@@ -350,9 +347,8 @@ static int zstd_init_compress_ctx(struct compress_ctx *cc) + + stream = zstd_init_cstream(¶ms, 0, workspace, workspace_size); + if (!stream) { +- printk_ratelimited("%sF2FS-fs (%s): %s zstd_init_cstream failed\n", +- KERN_ERR, F2FS_I_SB(cc->inode)->sb->s_id, +- __func__); ++ f2fs_err_ratelimited(F2FS_I_SB(cc->inode), ++ "%s zstd_init_cstream failed", __func__); + kvfree(workspace); + return -EIO; + } +@@ -390,16 +386,16 @@ static int zstd_compress_pages(struct compress_ctx *cc) + + ret = zstd_compress_stream(stream, &outbuf, &inbuf); + if (zstd_is_error(ret)) { +- printk_ratelimited("%sF2FS-fs (%s): %s zstd_compress_stream failed, ret: %d\n", +- KERN_ERR, F2FS_I_SB(cc->inode)->sb->s_id, ++ f2fs_err_ratelimited(F2FS_I_SB(cc->inode), ++ "%s zstd_compress_stream failed, ret: %d", + __func__, zstd_get_error_code(ret)); + return -EIO; + } + + ret = zstd_end_stream(stream, &outbuf); + if (zstd_is_error(ret)) { +- printk_ratelimited("%sF2FS-fs (%s): %s zstd_end_stream returned %d\n", +- KERN_ERR, F2FS_I_SB(cc->inode)->sb->s_id, ++ f2fs_err_ratelimited(F2FS_I_SB(cc->inode), ++ "%s zstd_end_stream returned %d", + __func__, zstd_get_error_code(ret)); + return -EIO; + } +@@ -432,9 +428,8 @@ static int zstd_init_decompress_ctx(struct decompress_io_ctx *dic) + + stream = zstd_init_dstream(max_window_size, workspace, workspace_size); + if (!stream) { +- printk_ratelimited("%sF2FS-fs (%s): %s zstd_init_dstream failed\n", +- KERN_ERR, F2FS_I_SB(dic->inode)->sb->s_id, +- __func__); ++ f2fs_err_ratelimited(F2FS_I_SB(dic->inode), ++ "%s zstd_init_dstream failed", __func__); + kvfree(workspace); + return -EIO; + } +@@ -469,16 +464,15 @@ static int zstd_decompress_pages(struct decompress_io_ctx *dic) + + ret = zstd_decompress_stream(stream, &outbuf, &inbuf); + if (zstd_is_error(ret)) { +- printk_ratelimited("%sF2FS-fs (%s): %s zstd_decompress_stream failed, ret: %d\n", +- KERN_ERR, F2FS_I_SB(dic->inode)->sb->s_id, ++ f2fs_err_ratelimited(F2FS_I_SB(dic->inode), ++ "%s zstd_decompress_stream failed, ret: %d", + __func__, zstd_get_error_code(ret)); + return -EIO; + } + + if (dic->rlen != outbuf.pos) { +- printk_ratelimited("%sF2FS-fs (%s): %s ZSTD invalid rlen:%zu, " +- "expected:%lu\n", KERN_ERR, +- F2FS_I_SB(dic->inode)->sb->s_id, ++ f2fs_err_ratelimited(F2FS_I_SB(dic->inode), ++ "%s ZSTD invalid rlen:%zu, expected:%lu", + __func__, dic->rlen, + PAGE_SIZE << dic->log_cluster_size); + return -EIO; +@@ -512,8 +506,8 @@ static int lzorle_compress_pages(struct compress_ctx *cc) + ret = lzorle1x_1_compress(cc->rbuf, cc->rlen, cc->cbuf->cdata, + &cc->clen, cc->private); + if (ret != LZO_E_OK) { +- printk_ratelimited("%sF2FS-fs (%s): lzo-rle compress failed, ret:%d\n", +- KERN_ERR, F2FS_I_SB(cc->inode)->sb->s_id, ret); ++ f2fs_err_ratelimited(F2FS_I_SB(cc->inode), ++ "lzo-rle compress failed, ret:%d", ret); + return -EIO; + } + return 0; +@@ -780,9 +774,9 @@ void f2fs_decompress_cluster(struct decompress_io_ctx *dic, bool in_task) + if (provided != calculated) { + if (!is_inode_flag_set(dic->inode, FI_COMPRESS_CORRUPT)) { + set_inode_flag(dic->inode, FI_COMPRESS_CORRUPT); +- printk_ratelimited( +- "%sF2FS-fs (%s): checksum invalid, nid = %lu, %x vs %x", +- KERN_INFO, sbi->sb->s_id, dic->inode->i_ino, ++ f2fs_info_ratelimited(sbi, ++ "checksum invalid, nid = %lu, %x vs %x", ++ dic->inode->i_ino, + provided, calculated); + } + set_sbi_flag(sbi, SBI_NEED_FSCK); +diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c +index 5805b77d925e3..2c4cb801899e8 100644 +--- a/fs/f2fs/data.c ++++ b/fs/f2fs/data.c +@@ -338,17 +338,6 @@ static void f2fs_write_end_io(struct bio *bio) + struct page *page = bvec->bv_page; + enum count_type type = WB_DATA_TYPE(page, false); + +- if (page_private_dummy(page)) { +- clear_page_private_dummy(page); +- unlock_page(page); +- mempool_free(page, sbi->write_io_dummy); +- +- if (unlikely(bio->bi_status)) +- f2fs_stop_checkpoint(sbi, true, +- STOP_CP_REASON_WRITE_FAIL); +- continue; +- } +- + fscrypt_finalize_bounce_page(&page); + + #ifdef CONFIG_F2FS_FS_COMPRESSION +@@ -522,50 +511,13 @@ void f2fs_submit_read_bio(struct f2fs_sb_info *sbi, struct bio *bio, + submit_bio(bio); + } + +-static void f2fs_align_write_bio(struct f2fs_sb_info *sbi, struct bio *bio) +-{ +- unsigned int start = +- (bio->bi_iter.bi_size >> F2FS_BLKSIZE_BITS) % F2FS_IO_SIZE(sbi); +- +- if (start == 0) +- return; +- +- /* fill dummy pages */ +- for (; start < F2FS_IO_SIZE(sbi); start++) { +- struct page *page = +- mempool_alloc(sbi->write_io_dummy, +- GFP_NOIO | __GFP_NOFAIL); +- f2fs_bug_on(sbi, !page); +- +- lock_page(page); +- +- zero_user_segment(page, 0, PAGE_SIZE); +- set_page_private_dummy(page); +- +- if (bio_add_page(bio, page, PAGE_SIZE, 0) < PAGE_SIZE) +- f2fs_bug_on(sbi, 1); +- } +-} +- + static void f2fs_submit_write_bio(struct f2fs_sb_info *sbi, struct bio *bio, + enum page_type type) + { + WARN_ON_ONCE(is_read_io(bio_op(bio))); + +- if (type == DATA || type == NODE) { +- if (f2fs_lfs_mode(sbi) && current->plug) +- blk_finish_plug(current->plug); +- +- if (F2FS_IO_ALIGNED(sbi)) { +- f2fs_align_write_bio(sbi, bio); +- /* +- * In the NODE case, we lose next block address chain. +- * So, we need to do checkpoint in f2fs_sync_file. +- */ +- if (type == NODE) +- set_sbi_flag(sbi, SBI_NEED_CP); +- } +- } ++ if (f2fs_lfs_mode(sbi) && current->plug && PAGE_TYPE_ON_MAIN(type)) ++ blk_finish_plug(current->plug); + + trace_f2fs_submit_write_bio(sbi->sb, type, bio); + iostat_update_submit_ctx(bio, type); +@@ -794,16 +746,6 @@ static bool io_is_mergeable(struct f2fs_sb_info *sbi, struct bio *bio, + block_t last_blkaddr, + block_t cur_blkaddr) + { +- if (F2FS_IO_ALIGNED(sbi) && (fio->type == DATA || fio->type == NODE)) { +- unsigned int filled_blocks = +- F2FS_BYTES_TO_BLK(bio->bi_iter.bi_size); +- unsigned int io_size = F2FS_IO_SIZE(sbi); +- unsigned int left_vecs = bio->bi_max_vecs - bio->bi_vcnt; +- +- /* IOs in bio is aligned and left space of vectors is not enough */ +- if (!(filled_blocks % io_size) && left_vecs < io_size) +- return false; +- } + if (!page_is_mergeable(sbi, bio, last_blkaddr, cur_blkaddr)) + return false; + return io_type_is_mergeable(io, fio); +@@ -1055,14 +997,6 @@ void f2fs_submit_page_write(struct f2fs_io_info *fio) + __submit_merged_bio(io); + alloc_new: + if (io->bio == NULL) { +- 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, +- fio->compressed_page)); +- fio->retry = 1; +- goto skip; +- } + io->bio = __bio_alloc(fio, BIO_MAX_VECS); + f2fs_set_bio_crypt_ctx(io->bio, fio->page->mapping->host, + bio_page->index, fio, GFP_NOIO); +@@ -1092,7 +1026,6 @@ void f2fs_submit_page_write(struct f2fs_io_info *fio) + __submit_merged_bio(io); + } + #endif +-skip: + if (fio->in_list) + goto next; + out: +@@ -2666,8 +2599,6 @@ bool f2fs_should_update_outplace(struct inode *inode, struct f2fs_io_info *fio) + if (fio) { + if (page_private_gcing(fio->page)) + return true; +- if (page_private_dummy(fio->page)) +- return true; + if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED) && + f2fs_is_checkpointed_data(sbi, fio->old_blkaddr))) + return true; +@@ -3905,25 +3836,34 @@ static int f2fs_migrate_blocks(struct inode *inode, block_t start_blk, + unsigned int blkofs; + unsigned int blk_per_sec = BLKS_PER_SEC(sbi); + unsigned int secidx = start_blk / blk_per_sec; +- unsigned int end_sec = secidx + blkcnt / blk_per_sec; ++ unsigned int end_sec; + int ret = 0; + ++ if (!blkcnt) ++ return 0; ++ end_sec = secidx + (blkcnt - 1) / blk_per_sec; ++ + f2fs_down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]); + filemap_invalidate_lock(inode->i_mapping); + + set_inode_flag(inode, FI_ALIGNED_WRITE); + set_inode_flag(inode, FI_OPU_WRITE); + +- for (; secidx < end_sec; secidx++) { ++ for (; secidx <= end_sec; secidx++) { ++ unsigned int blkofs_end = secidx == end_sec ? ++ (blkcnt - 1) % blk_per_sec : blk_per_sec - 1; ++ + f2fs_down_write(&sbi->pin_sem); + +- f2fs_lock_op(sbi); +- f2fs_allocate_new_section(sbi, CURSEG_COLD_DATA_PINNED, false); +- f2fs_unlock_op(sbi); ++ ret = f2fs_allocate_pinning_section(sbi); ++ if (ret) { ++ f2fs_up_write(&sbi->pin_sem); ++ break; ++ } + + set_inode_flag(inode, FI_SKIP_WRITES); + +- for (blkofs = 0; blkofs < blk_per_sec; blkofs++) { ++ for (blkofs = 0; blkofs <= blkofs_end; blkofs++) { + struct page *page; + unsigned int blkidx = secidx * blk_per_sec + blkofs; + +@@ -3965,15 +3905,14 @@ static int check_swap_activate(struct swap_info_struct *sis, + struct address_space *mapping = swap_file->f_mapping; + struct inode *inode = mapping->host; + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); +- sector_t cur_lblock; +- sector_t last_lblock; +- sector_t pblock; +- sector_t lowest_pblock = -1; +- sector_t highest_pblock = 0; ++ block_t cur_lblock; ++ block_t last_lblock; ++ block_t pblock; ++ block_t lowest_pblock = -1; ++ block_t highest_pblock = 0; + int nr_extents = 0; +- unsigned long nr_pblocks; ++ unsigned int nr_pblocks; + unsigned int blks_per_sec = BLKS_PER_SEC(sbi); +- unsigned int sec_blks_mask = BLKS_PER_SEC(sbi) - 1; + unsigned int not_aligned = 0; + int ret = 0; + +@@ -4011,28 +3950,35 @@ static int check_swap_activate(struct swap_info_struct *sis, + pblock = map.m_pblk; + nr_pblocks = map.m_len; + +- if ((pblock - SM_I(sbi)->main_blkaddr) & sec_blks_mask || +- nr_pblocks & sec_blks_mask) { ++ if ((pblock - SM_I(sbi)->main_blkaddr) % blks_per_sec || ++ nr_pblocks % blks_per_sec || ++ !f2fs_valid_pinned_area(sbi, pblock)) { ++ bool last_extent = false; ++ + not_aligned++; + + nr_pblocks = roundup(nr_pblocks, blks_per_sec); + if (cur_lblock + nr_pblocks > sis->max) + nr_pblocks -= blks_per_sec; + ++ /* this extent is last one */ + if (!nr_pblocks) { +- /* this extent is last one */ +- nr_pblocks = map.m_len; +- f2fs_warn(sbi, "Swapfile: last extent is not aligned to section"); +- goto next; ++ nr_pblocks = last_lblock - cur_lblock; ++ last_extent = true; + } + + ret = f2fs_migrate_blocks(inode, cur_lblock, + nr_pblocks); +- if (ret) ++ if (ret) { ++ if (ret == -ENOENT) ++ ret = -EINVAL; + goto out; +- goto retry; ++ } ++ ++ if (!last_extent) ++ goto retry; + } +-next: ++ + if (cur_lblock + nr_pblocks >= sis->max) + nr_pblocks = sis->max - cur_lblock; + +@@ -4070,17 +4016,17 @@ static int f2fs_swap_activate(struct swap_info_struct *sis, struct file *file, + sector_t *span) + { + struct inode *inode = file_inode(file); ++ struct f2fs_sb_info *sbi = F2FS_I_SB(inode); + int ret; + + if (!S_ISREG(inode->i_mode)) + return -EINVAL; + +- if (f2fs_readonly(F2FS_I_SB(inode)->sb)) ++ if (f2fs_readonly(sbi->sb)) + return -EROFS; + +- if (f2fs_lfs_mode(F2FS_I_SB(inode))) { +- f2fs_err(F2FS_I_SB(inode), +- "Swapfile not supported in LFS mode"); ++ if (f2fs_lfs_mode(sbi) && !f2fs_sb_has_blkzoned(sbi)) { ++ f2fs_err(sbi, "Swapfile not supported in LFS mode"); + return -EINVAL; + } + +@@ -4093,13 +4039,17 @@ static int f2fs_swap_activate(struct swap_info_struct *sis, struct file *file, + + f2fs_precache_extents(inode); + ++ ret = filemap_fdatawrite(inode->i_mapping); ++ if (ret < 0) ++ return ret; ++ + ret = check_swap_activate(sis, file, span); + if (ret < 0) + return ret; + + stat_inc_swapfile_inode(inode); + set_inode_flag(inode, FI_PIN_FILE); +- f2fs_update_time(F2FS_I_SB(inode), REQ_TIME); ++ f2fs_update_time(sbi, REQ_TIME); + return ret; + } + +@@ -4243,7 +4193,7 @@ static int f2fs_iomap_begin(struct inode *inode, loff_t offset, loff_t length, + if (WARN_ON_ONCE(map.m_pblk == COMPRESS_ADDR)) + return -EINVAL; + +- if (map.m_pblk != NULL_ADDR) { ++ if (map.m_flags & F2FS_MAP_MAPPED) { + iomap->length = blks_to_bytes(inode, map.m_len); + iomap->type = IOMAP_MAPPED; + iomap->flags |= IOMAP_F_MERGED; +diff --git a/fs/f2fs/debug.c b/fs/f2fs/debug.c +index fdbf994f12718..0d02224b99b72 100644 +--- a/fs/f2fs/debug.c ++++ b/fs/f2fs/debug.c +@@ -41,7 +41,7 @@ void f2fs_update_sit_info(struct f2fs_sb_info *sbi) + total_vblocks = 0; + blks_per_sec = CAP_BLKS_PER_SEC(sbi); + hblks_per_sec = blks_per_sec / 2; +- for (segno = 0; segno < MAIN_SEGS(sbi); segno += sbi->segs_per_sec) { ++ for (segno = 0; segno < MAIN_SEGS(sbi); segno += SEGS_PER_SEC(sbi)) { + vblocks = get_valid_blocks(sbi, segno, true); + dist = abs(vblocks - hblks_per_sec); + bimodal += dist * dist; +@@ -135,7 +135,7 @@ static void update_general_status(struct f2fs_sb_info *sbi) + si->cur_ckpt_time = sbi->cprc_info.cur_time; + si->peak_ckpt_time = sbi->cprc_info.peak_time; + spin_unlock(&sbi->cprc_info.stat_lock); +- si->total_count = (int)sbi->user_block_count / sbi->blocks_per_seg; ++ si->total_count = (int)sbi->user_block_count / BLKS_PER_SEG(sbi); + si->rsvd_segs = reserved_segments(sbi); + si->overp_segs = overprovision_segments(sbi); + si->valid_count = valid_user_blocks(sbi); +@@ -208,7 +208,7 @@ static void update_general_status(struct f2fs_sb_info *sbi) + if (!blks) + continue; + +- if (blks == sbi->blocks_per_seg) ++ if (blks == BLKS_PER_SEG(sbi)) + si->full_seg[type]++; + else + si->dirty_seg[type]++; +diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c +index e792d35304796..c624ffff6f19a 100644 +--- a/fs/f2fs/dir.c ++++ b/fs/f2fs/dir.c +@@ -996,9 +996,8 @@ int f2fs_fill_dentries(struct dir_context *ctx, struct f2fs_dentry_ptr *d, + de = &d->dentry[bit_pos]; + if (de->name_len == 0) { + if (found_valid_dirent || !bit_pos) { +- printk_ratelimited( +- "%sF2FS-fs (%s): invalid namelen(0), ino:%u, run fsck to fix.", +- KERN_WARNING, sbi->sb->s_id, ++ f2fs_warn_ratelimited(sbi, ++ "invalid namelen(0), ino:%u, run fsck to fix.", + le32_to_cpu(de->ino)); + set_sbi_flag(sbi, SBI_NEED_FSCK); + } +diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h +index f37907f015873..f1fbfa7fb279e 100644 +--- a/fs/f2fs/f2fs.h ++++ b/fs/f2fs/f2fs.h +@@ -147,7 +147,6 @@ struct f2fs_rwsem { + + struct f2fs_mount_info { + unsigned int opt; +- int write_io_size_bits; /* Write IO size bits */ + block_t root_reserved_blocks; /* root reserved blocks */ + kuid_t s_resuid; /* reserved blocks for uid */ + kgid_t s_resgid; /* reserved blocks for gid */ +@@ -1109,6 +1108,7 @@ enum count_type { + * ... Only can be used with META. + */ + #define PAGE_TYPE_OF_BIO(type) ((type) > META ? META : (type)) ++#define PAGE_TYPE_ON_MAIN(type) ((type) == DATA || (type) == NODE) + enum page_type { + DATA = 0, + NODE = 1, /* should not change this */ +@@ -1203,7 +1203,6 @@ struct f2fs_io_info { + unsigned int submitted:1; /* indicate IO submission */ + unsigned int in_list:1; /* indicate fio is in io_list */ + unsigned int is_por:1; /* indicate IO is from recovery or not */ +- unsigned int retry:1; /* need to reallocate block address */ + unsigned int encrypted:1; /* indicate file is encrypted */ + unsigned int post_read:1; /* require post read */ + enum iostat_type io_type; /* io type */ +@@ -1404,18 +1403,16 @@ static inline void f2fs_clear_bit(unsigned int nr, char *addr); + * Layout A: lowest bit should be 1 + * | bit0 = 1 | bit1 | bit2 | ... | bit MAX | private data .... | + * bit 0 PAGE_PRIVATE_NOT_POINTER +- * bit 1 PAGE_PRIVATE_DUMMY_WRITE +- * bit 2 PAGE_PRIVATE_ONGOING_MIGRATION +- * bit 3 PAGE_PRIVATE_INLINE_INODE +- * bit 4 PAGE_PRIVATE_REF_RESOURCE +- * bit 5- f2fs private data ++ * bit 1 PAGE_PRIVATE_ONGOING_MIGRATION ++ * bit 2 PAGE_PRIVATE_INLINE_INODE ++ * bit 3 PAGE_PRIVATE_REF_RESOURCE ++ * bit 4- f2fs private data + * + * Layout B: lowest bit should be 0 + * page.private is a wrapped pointer. + */ + enum { + PAGE_PRIVATE_NOT_POINTER, /* private contains non-pointer data */ +- PAGE_PRIVATE_DUMMY_WRITE, /* data page for padding aligned IO */ + PAGE_PRIVATE_ONGOING_MIGRATION, /* data page which is on-going migrating */ + PAGE_PRIVATE_INLINE_INODE, /* inode page contains inline data */ + PAGE_PRIVATE_REF_RESOURCE, /* dirty page has referenced resources */ +@@ -1562,7 +1559,6 @@ struct f2fs_sb_info { + struct f2fs_bio_info *write_io[NR_PAGE_TYPE]; /* for write bios */ + /* keep migration IO order for LFS mode */ + struct f2fs_rwsem io_order_lock; +- mempool_t *write_io_dummy; /* Dummy pages */ + pgoff_t page_eio_ofs[NR_PAGE_TYPE]; /* EIO page offset */ + int page_eio_cnt[NR_PAGE_TYPE]; /* EIO count */ + +@@ -1808,6 +1804,35 @@ struct f2fs_sb_info { + #endif + }; + ++/* Definitions to access f2fs_sb_info */ ++#define BLKS_PER_SEG(sbi) \ ++ ((sbi)->blocks_per_seg) ++#define BLKS_PER_SEC(sbi) \ ++ ((sbi)->segs_per_sec << (sbi)->log_blocks_per_seg) ++#define SEGS_PER_SEC(sbi) \ ++ ((sbi)->segs_per_sec) ++ ++__printf(3, 4) ++void f2fs_printk(struct f2fs_sb_info *sbi, bool limit_rate, const char *fmt, ...); ++ ++#define f2fs_err(sbi, fmt, ...) \ ++ f2fs_printk(sbi, false, KERN_ERR fmt, ##__VA_ARGS__) ++#define f2fs_warn(sbi, fmt, ...) \ ++ f2fs_printk(sbi, false, KERN_WARNING fmt, ##__VA_ARGS__) ++#define f2fs_notice(sbi, fmt, ...) \ ++ f2fs_printk(sbi, false, KERN_NOTICE fmt, ##__VA_ARGS__) ++#define f2fs_info(sbi, fmt, ...) \ ++ f2fs_printk(sbi, false, KERN_INFO fmt, ##__VA_ARGS__) ++#define f2fs_debug(sbi, fmt, ...) \ ++ f2fs_printk(sbi, false, KERN_DEBUG fmt, ##__VA_ARGS__) ++ ++#define f2fs_err_ratelimited(sbi, fmt, ...) \ ++ f2fs_printk(sbi, true, KERN_ERR fmt, ##__VA_ARGS__) ++#define f2fs_warn_ratelimited(sbi, fmt, ...) \ ++ f2fs_printk(sbi, true, KERN_WARNING fmt, ##__VA_ARGS__) ++#define f2fs_info_ratelimited(sbi, fmt, ...) \ ++ f2fs_printk(sbi, true, KERN_INFO fmt, ##__VA_ARGS__) ++ + #ifdef CONFIG_F2FS_FAULT_INJECTION + #define time_to_inject(sbi, type) __time_to_inject(sbi, type, __func__, \ + __builtin_return_address(0)) +@@ -1825,9 +1850,8 @@ static inline bool __time_to_inject(struct f2fs_sb_info *sbi, int type, + atomic_inc(&ffi->inject_ops); + if (atomic_read(&ffi->inject_ops) >= ffi->inject_rate) { + atomic_set(&ffi->inject_ops, 0); +- printk_ratelimited("%sF2FS-fs (%s) : inject %s in %s of %pS\n", +- KERN_INFO, sbi->sb->s_id, f2fs_fault_name[type], +- func, parent_func); ++ f2fs_info_ratelimited(sbi, "inject %s in %s of %pS", ++ f2fs_fault_name[type], func, parent_func); + return true; + } + return false; +@@ -2247,11 +2271,32 @@ static inline bool __allow_reserved_blocks(struct f2fs_sb_info *sbi, + return false; + } + ++static inline unsigned int get_available_block_count(struct f2fs_sb_info *sbi, ++ struct inode *inode, bool cap) ++{ ++ block_t avail_user_block_count; ++ ++ avail_user_block_count = sbi->user_block_count - ++ sbi->current_reserved_blocks; ++ ++ if (!__allow_reserved_blocks(sbi, inode, cap)) ++ avail_user_block_count -= F2FS_OPTION(sbi).root_reserved_blocks; ++ ++ if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED))) { ++ if (avail_user_block_count > sbi->unusable_block_count) ++ avail_user_block_count -= sbi->unusable_block_count; ++ else ++ avail_user_block_count = 0; ++ } ++ ++ return avail_user_block_count; ++} ++ + 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, bool partial) + { +- blkcnt_t diff = 0, release = 0; ++ long long diff = 0, release = 0; + block_t avail_user_block_count; + int ret; + +@@ -2271,40 +2316,27 @@ static inline int inc_valid_block_count(struct f2fs_sb_info *sbi, + percpu_counter_add(&sbi->alloc_valid_block_count, (*count)); + + spin_lock(&sbi->stat_lock); +- sbi->total_valid_block_count += (block_t)(*count); +- avail_user_block_count = sbi->user_block_count - +- sbi->current_reserved_blocks; + +- if (!__allow_reserved_blocks(sbi, inode, true)) +- avail_user_block_count -= F2FS_OPTION(sbi).root_reserved_blocks; +- +- if (F2FS_IO_ALIGNED(sbi)) +- avail_user_block_count -= sbi->blocks_per_seg * +- SM_I(sbi)->additional_reserved_segments; +- +- if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED))) { +- if (avail_user_block_count > sbi->unusable_block_count) +- avail_user_block_count -= sbi->unusable_block_count; +- else +- avail_user_block_count = 0; +- } +- if (unlikely(sbi->total_valid_block_count > avail_user_block_count)) { ++ avail_user_block_count = get_available_block_count(sbi, inode, true); ++ diff = (long long)sbi->total_valid_block_count + *count - ++ avail_user_block_count; ++ if (unlikely(diff > 0)) { + if (!partial) { + spin_unlock(&sbi->stat_lock); ++ release = *count; + goto enospc; + } +- +- diff = sbi->total_valid_block_count - avail_user_block_count; + if (diff > *count) + diff = *count; + *count -= diff; + release = diff; +- sbi->total_valid_block_count -= diff; + if (!*count) { + spin_unlock(&sbi->stat_lock); + goto enospc; + } + } ++ sbi->total_valid_block_count += (block_t)(*count); ++ + spin_unlock(&sbi->stat_lock); + + if (unlikely(release)) { +@@ -2321,20 +2353,6 @@ static inline int inc_valid_block_count(struct f2fs_sb_info *sbi, + return -ENOSPC; + } + +-__printf(2, 3) +-void f2fs_printk(struct f2fs_sb_info *sbi, const char *fmt, ...); +- +-#define f2fs_err(sbi, fmt, ...) \ +- f2fs_printk(sbi, KERN_ERR fmt, ##__VA_ARGS__) +-#define f2fs_warn(sbi, fmt, ...) \ +- f2fs_printk(sbi, KERN_WARNING fmt, ##__VA_ARGS__) +-#define f2fs_notice(sbi, fmt, ...) \ +- f2fs_printk(sbi, KERN_NOTICE fmt, ##__VA_ARGS__) +-#define f2fs_info(sbi, fmt, ...) \ +- f2fs_printk(sbi, KERN_INFO fmt, ##__VA_ARGS__) +-#define f2fs_debug(sbi, fmt, ...) \ +- f2fs_printk(sbi, KERN_DEBUG fmt, ##__VA_ARGS__) +- + #define PAGE_PRIVATE_GET_FUNC(name, flagname) \ + static inline bool page_private_##name(struct page *page) \ + { \ +@@ -2363,17 +2381,14 @@ static inline void clear_page_private_##name(struct page *page) \ + PAGE_PRIVATE_GET_FUNC(nonpointer, NOT_POINTER); + PAGE_PRIVATE_GET_FUNC(inline, INLINE_INODE); + PAGE_PRIVATE_GET_FUNC(gcing, ONGOING_MIGRATION); +-PAGE_PRIVATE_GET_FUNC(dummy, DUMMY_WRITE); + + PAGE_PRIVATE_SET_FUNC(reference, REF_RESOURCE); + PAGE_PRIVATE_SET_FUNC(inline, INLINE_INODE); + PAGE_PRIVATE_SET_FUNC(gcing, ONGOING_MIGRATION); +-PAGE_PRIVATE_SET_FUNC(dummy, DUMMY_WRITE); + + PAGE_PRIVATE_CLEAR_FUNC(reference, REF_RESOURCE); + PAGE_PRIVATE_CLEAR_FUNC(inline, INLINE_INODE); + PAGE_PRIVATE_CLEAR_FUNC(gcing, ONGOING_MIGRATION); +-PAGE_PRIVATE_CLEAR_FUNC(dummy, DUMMY_WRITE); + + static inline unsigned long get_page_private_data(struct page *page) + { +@@ -2507,11 +2522,8 @@ static inline int get_dirty_pages(struct inode *inode) + + static inline int get_blocktype_secs(struct f2fs_sb_info *sbi, int block_type) + { +- unsigned int pages_per_sec = sbi->segs_per_sec * sbi->blocks_per_seg; +- unsigned int segs = (get_pages(sbi, block_type) + pages_per_sec - 1) >> +- sbi->log_blocks_per_seg; +- +- return segs / sbi->segs_per_sec; ++ return div_u64(get_pages(sbi, block_type) + BLKS_PER_SEC(sbi) - 1, ++ BLKS_PER_SEC(sbi)); + } + + static inline block_t valid_user_blocks(struct f2fs_sb_info *sbi) +@@ -2575,7 +2587,7 @@ static inline block_t __start_cp_addr(struct f2fs_sb_info *sbi) + block_t start_addr = le32_to_cpu(F2FS_RAW_SUPER(sbi)->cp_blkaddr); + + if (sbi->cur_cp_pack == 2) +- start_addr += sbi->blocks_per_seg; ++ start_addr += BLKS_PER_SEG(sbi); + return start_addr; + } + +@@ -2584,7 +2596,7 @@ static inline block_t __start_cp_next_addr(struct f2fs_sb_info *sbi) + block_t start_addr = le32_to_cpu(F2FS_RAW_SUPER(sbi)->cp_blkaddr); + + if (sbi->cur_cp_pack == 1) +- start_addr += sbi->blocks_per_seg; ++ start_addr += BLKS_PER_SEG(sbi); + return start_addr; + } + +@@ -2603,7 +2615,8 @@ static inline int inc_valid_node_count(struct f2fs_sb_info *sbi, + struct inode *inode, bool is_inode) + { + block_t valid_block_count; +- unsigned int valid_node_count, user_block_count; ++ unsigned int valid_node_count; ++ unsigned int avail_user_block_count; + int err; + + if (is_inode) { +@@ -2623,21 +2636,10 @@ static inline int inc_valid_node_count(struct f2fs_sb_info *sbi, + + spin_lock(&sbi->stat_lock); + +- valid_block_count = sbi->total_valid_block_count + +- sbi->current_reserved_blocks + 1; +- +- if (!__allow_reserved_blocks(sbi, inode, false)) +- valid_block_count += F2FS_OPTION(sbi).root_reserved_blocks; +- +- if (F2FS_IO_ALIGNED(sbi)) +- valid_block_count += sbi->blocks_per_seg * +- SM_I(sbi)->additional_reserved_segments; ++ valid_block_count = sbi->total_valid_block_count + 1; ++ avail_user_block_count = get_available_block_count(sbi, inode, false); + +- user_block_count = sbi->user_block_count; +- if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED))) +- user_block_count -= sbi->unusable_block_count; +- +- if (unlikely(valid_block_count > user_block_count)) { ++ if (unlikely(valid_block_count > avail_user_block_count)) { + spin_unlock(&sbi->stat_lock); + goto enospc; + } +@@ -3457,7 +3459,7 @@ static inline __le32 *get_dnode_addr(struct inode *inode, + sizeof((f2fs_inode)->field)) \ + <= (F2FS_OLD_ATTRIBUTE_SIZE + (extra_isize))) \ + +-#define __is_large_section(sbi) ((sbi)->segs_per_sec > 1) ++#define __is_large_section(sbi) (SEGS_PER_SEC(sbi) > 1) + + #define __is_meta_io(fio) (PAGE_TYPE_OF_BIO((fio)->type) == META) + +@@ -3693,7 +3695,8 @@ void f2fs_get_new_segment(struct f2fs_sb_info *sbi, + unsigned int *newseg, bool new_sec, int dir); + void f2fs_allocate_segment_for_resize(struct f2fs_sb_info *sbi, int type, + unsigned int start, unsigned int end); +-void f2fs_allocate_new_section(struct f2fs_sb_info *sbi, int type, bool force); ++int f2fs_allocate_new_section(struct f2fs_sb_info *sbi, int type, bool force); ++int f2fs_allocate_pinning_section(struct f2fs_sb_info *sbi); + void f2fs_allocate_new_segments(struct f2fs_sb_info *sbi); + int f2fs_trim_fs(struct f2fs_sb_info *sbi, struct fstrim_range *range); + bool f2fs_exist_trim_candidates(struct f2fs_sb_info *sbi, +@@ -3869,6 +3872,9 @@ void f2fs_stop_gc_thread(struct f2fs_sb_info *sbi); + block_t f2fs_start_bidx_of_node(unsigned int node_ofs, struct inode *inode); + int f2fs_gc(struct f2fs_sb_info *sbi, struct f2fs_gc_control *gc_control); + void f2fs_build_gc_manager(struct f2fs_sb_info *sbi); ++int f2fs_gc_range(struct f2fs_sb_info *sbi, ++ unsigned int start_seg, unsigned int end_seg, ++ bool dry_run, unsigned int dry_run_sections); + int f2fs_resize_fs(struct file *filp, __u64 block_count); + int __init f2fs_create_garbage_collection_cache(void); + void f2fs_destroy_garbage_collection_cache(void); +@@ -4525,6 +4531,17 @@ static inline bool f2fs_lfs_mode(struct f2fs_sb_info *sbi) + return F2FS_OPTION(sbi).fs_mode == FS_MODE_LFS; + } + ++static inline bool f2fs_valid_pinned_area(struct f2fs_sb_info *sbi, ++ block_t blkaddr) ++{ ++ if (f2fs_sb_has_blkzoned(sbi)) { ++ int devi = f2fs_target_device_index(sbi, blkaddr); ++ ++ return !bdev_is_zoned(FDEV(devi).bdev); ++ } ++ return true; ++} ++ + static inline bool f2fs_low_mem_mode(struct f2fs_sb_info *sbi) + { + return F2FS_OPTION(sbi).memory_mode == MEMORY_MODE_LOW; +diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c +index ee5df9adaf775..154c55c1a0f47 100644 +--- a/fs/f2fs/file.c ++++ b/fs/f2fs/file.c +@@ -813,8 +813,6 @@ static bool f2fs_force_buffered_io(struct inode *inode, int rw) + */ + if (f2fs_sb_has_blkzoned(sbi) && (rw == WRITE)) + return true; +- if (f2fs_lfs_mode(sbi) && rw == WRITE && F2FS_IO_ALIGNED(sbi)) +- return true; + if (is_sbi_flag_set(sbi, SBI_CP_DISABLED)) + return true; + +@@ -931,9 +929,14 @@ int f2fs_setattr(struct mnt_idmap *idmap, struct dentry *dentry, + ATTR_GID | ATTR_TIMES_SET)))) + return -EPERM; + +- if ((attr->ia_valid & ATTR_SIZE) && +- !f2fs_is_compress_backend_ready(inode)) +- return -EOPNOTSUPP; ++ if ((attr->ia_valid & ATTR_SIZE)) { ++ if (!f2fs_is_compress_backend_ready(inode)) ++ return -EOPNOTSUPP; ++ if (is_inode_flag_set(inode, FI_COMPRESS_RELEASED) && ++ !IS_ALIGNED(attr->ia_size, ++ F2FS_BLK_TO_BYTES(F2FS_I(inode)->i_cluster_size))) ++ return -EINVAL; ++ } + + err = setattr_prepare(idmap, dentry, attr); + if (err) +@@ -1305,6 +1308,9 @@ static int __clone_blkaddrs(struct inode *src_inode, struct inode *dst_inode, + f2fs_put_page(psrc, 1); + return PTR_ERR(pdst); + } ++ ++ f2fs_wait_on_page_writeback(pdst, DATA, true, true); ++ + memcpy_page(pdst, 0, psrc, 0, PAGE_SIZE); + set_page_dirty(pdst); + set_page_private_gcing(pdst); +@@ -1726,9 +1732,11 @@ static int f2fs_expand_inode_data(struct inode *inode, loff_t offset, + + f2fs_down_write(&sbi->pin_sem); + +- f2fs_lock_op(sbi); +- f2fs_allocate_new_section(sbi, CURSEG_COLD_DATA_PINNED, false); +- f2fs_unlock_op(sbi); ++ err = f2fs_allocate_pinning_section(sbi); ++ if (err) { ++ f2fs_up_write(&sbi->pin_sem); ++ goto out_err; ++ } + + map.m_seg_type = CURSEG_COLD_DATA_PINNED; + err = f2fs_map_blocks(inode, &map, F2FS_GET_BLOCK_PRE_DIO); +@@ -1794,15 +1802,6 @@ static long f2fs_fallocate(struct file *file, int mode, + (mode & (FALLOC_FL_COLLAPSE_RANGE | FALLOC_FL_INSERT_RANGE))) + return -EOPNOTSUPP; + +- /* +- * Pinned file should not support partial truncation since the block +- * can be used by applications. +- */ +- if ((f2fs_compressed_file(inode) || f2fs_is_pinned_file(inode)) && +- (mode & (FALLOC_FL_PUNCH_HOLE | FALLOC_FL_COLLAPSE_RANGE | +- FALLOC_FL_ZERO_RANGE | FALLOC_FL_INSERT_RANGE))) +- return -EOPNOTSUPP; +- + if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE | + FALLOC_FL_COLLAPSE_RANGE | FALLOC_FL_ZERO_RANGE | + FALLOC_FL_INSERT_RANGE)) +@@ -1810,6 +1809,17 @@ static long f2fs_fallocate(struct file *file, int mode, + + inode_lock(inode); + ++ /* ++ * Pinned file should not support partial truncation since the block ++ * can be used by applications. ++ */ ++ if ((f2fs_compressed_file(inode) || f2fs_is_pinned_file(inode)) && ++ (mode & (FALLOC_FL_PUNCH_HOLE | FALLOC_FL_COLLAPSE_RANGE | ++ FALLOC_FL_ZERO_RANGE | FALLOC_FL_INSERT_RANGE))) { ++ ret = -EOPNOTSUPP; ++ goto out; ++ } ++ + ret = file_modified(file); + if (ret) + goto out; +@@ -2573,7 +2583,6 @@ static int f2fs_defragment_range(struct f2fs_sb_info *sbi, + .m_may_create = false }; + struct extent_info ei = {}; + pgoff_t pg_start, pg_end, next_pgofs; +- unsigned int blk_per_seg = sbi->blocks_per_seg; + unsigned int total = 0, sec_num; + block_t blk_end = 0; + bool fragmented = false; +@@ -2682,7 +2691,8 @@ static int f2fs_defragment_range(struct f2fs_sb_info *sbi, + set_inode_flag(inode, FI_SKIP_WRITES); + + idx = map.m_lblk; +- while (idx < map.m_lblk + map.m_len && cnt < blk_per_seg) { ++ while (idx < map.m_lblk + map.m_len && ++ cnt < BLKS_PER_SEG(sbi)) { + struct page *page; + + page = f2fs_get_lock_data_page(inode, idx, true); +@@ -2702,7 +2712,7 @@ static int f2fs_defragment_range(struct f2fs_sb_info *sbi, + + map.m_lblk = idx; + check: +- if (map.m_lblk < pg_end && cnt < blk_per_seg) ++ if (map.m_lblk < pg_end && cnt < BLKS_PER_SEG(sbi)) + goto do_map; + + clear_inode_flag(inode, FI_SKIP_WRITES); +@@ -2808,7 +2818,8 @@ static int f2fs_move_file_range(struct file *file_in, loff_t pos_in, + goto out; + } + +- if (f2fs_compressed_file(src) || f2fs_compressed_file(dst)) { ++ if (f2fs_compressed_file(src) || f2fs_compressed_file(dst) || ++ f2fs_is_pinned_file(src) || f2fs_is_pinned_file(dst)) { + ret = -EOPNOTSUPP; + goto out_unlock; + } +@@ -2971,8 +2982,8 @@ static int f2fs_ioc_flush_device(struct file *filp, unsigned long arg) + + if (!f2fs_is_multi_device(sbi) || sbi->s_ndevs - 1 <= range.dev_num || + __is_large_section(sbi)) { +- f2fs_warn(sbi, "Can't flush %u in %d for segs_per_sec %u != 1", +- range.dev_num, sbi->s_ndevs, sbi->segs_per_sec); ++ f2fs_warn(sbi, "Can't flush %u in %d for SEGS_PER_SEC %u != 1", ++ range.dev_num, sbi->s_ndevs, SEGS_PER_SEC(sbi)); + return -EINVAL; + } + +@@ -3178,6 +3189,7 @@ int f2fs_pin_file_control(struct inode *inode, bool inc) + static int f2fs_ioc_set_pin_file(struct file *filp, unsigned long arg) + { + struct inode *inode = file_inode(filp); ++ struct f2fs_sb_info *sbi = F2FS_I_SB(inode); + __u32 pin; + int ret = 0; + +@@ -3187,7 +3199,7 @@ static int f2fs_ioc_set_pin_file(struct file *filp, unsigned long arg) + if (!S_ISREG(inode->i_mode)) + return -EINVAL; + +- if (f2fs_readonly(F2FS_I_SB(inode)->sb)) ++ if (f2fs_readonly(sbi->sb)) + return -EROFS; + + ret = mnt_want_write_file(filp); +@@ -3200,9 +3212,18 @@ static int f2fs_ioc_set_pin_file(struct file *filp, unsigned long arg) + clear_inode_flag(inode, FI_PIN_FILE); + f2fs_i_gc_failures_write(inode, 0); + goto done; ++ } else if (f2fs_is_pinned_file(inode)) { ++ goto done; ++ } ++ ++ if (f2fs_sb_has_blkzoned(sbi) && F2FS_HAS_BLOCKS(inode)) { ++ ret = -EFBIG; ++ goto out; + } + +- if (f2fs_should_update_outplace(inode, NULL)) { ++ /* Let's allow file pinning on zoned device. */ ++ if (!f2fs_sb_has_blkzoned(sbi) && ++ f2fs_should_update_outplace(inode, NULL)) { + ret = -EINVAL; + goto out; + } +@@ -3224,7 +3245,7 @@ static int f2fs_ioc_set_pin_file(struct file *filp, unsigned long arg) + set_inode_flag(inode, FI_PIN_FILE); + ret = F2FS_I(inode)->i_gc_failures[GC_FAILURE_PIN]; + done: +- f2fs_update_time(F2FS_I_SB(inode), REQ_TIME); ++ f2fs_update_time(sbi, REQ_TIME); + out: + inode_unlock(inode); + mnt_drop_write_file(filp); +@@ -3485,9 +3506,6 @@ static int f2fs_release_compress_blocks(struct file *filp, unsigned long arg) + if (!f2fs_sb_has_compression(sbi)) + return -EOPNOTSUPP; + +- if (!f2fs_compressed_file(inode)) +- return -EINVAL; +- + if (f2fs_readonly(sbi->sb)) + return -EROFS; + +@@ -3506,7 +3524,8 @@ static int f2fs_release_compress_blocks(struct file *filp, unsigned long arg) + goto out; + } + +- if (is_inode_flag_set(inode, FI_COMPRESS_RELEASED)) { ++ if (!f2fs_compressed_file(inode) || ++ is_inode_flag_set(inode, FI_COMPRESS_RELEASED)) { + ret = -EINVAL; + goto out; + } +@@ -3533,9 +3552,12 @@ static int f2fs_release_compress_blocks(struct file *filp, unsigned long arg) + struct dnode_of_data dn; + pgoff_t end_offset, count; + ++ f2fs_lock_op(sbi); ++ + set_new_dnode(&dn, inode, NULL, NULL, 0); + ret = f2fs_get_dnode_of_data(&dn, page_idx, LOOKUP_NODE); + if (ret) { ++ f2fs_unlock_op(sbi); + if (ret == -ENOENT) { + page_idx = f2fs_get_next_page_offset(&dn, + page_idx); +@@ -3553,6 +3575,8 @@ static int f2fs_release_compress_blocks(struct file *filp, unsigned long arg) + + f2fs_put_dnode(&dn); + ++ f2fs_unlock_op(sbi); ++ + if (ret < 0) + break; + +@@ -3606,7 +3630,8 @@ static int reserve_compress_blocks(struct dnode_of_data *dn, pgoff_t count, + + while (count) { + int compr_blocks = 0; +- blkcnt_t reserved; ++ blkcnt_t reserved = 0; ++ blkcnt_t to_reserved; + int ret; + + for (i = 0; i < cluster_size; i++) { +@@ -3626,20 +3651,26 @@ static int reserve_compress_blocks(struct dnode_of_data *dn, pgoff_t count, + * fails in release_compress_blocks(), so NEW_ADDR + * is a possible case. + */ +- if (blkaddr == NEW_ADDR || +- __is_valid_data_blkaddr(blkaddr)) { ++ if (blkaddr == NEW_ADDR) { ++ reserved++; ++ continue; ++ } ++ if (__is_valid_data_blkaddr(blkaddr)) { + compr_blocks++; + continue; + } + } + +- reserved = cluster_size - compr_blocks; ++ to_reserved = cluster_size - compr_blocks - reserved; + + /* for the case all blocks in cluster were reserved */ +- if (reserved == 1) ++ if (to_reserved == 1) { ++ dn->ofs_in_node += cluster_size; + goto next; ++ } + +- ret = inc_valid_block_count(sbi, dn->inode, &reserved, false); ++ ret = inc_valid_block_count(sbi, dn->inode, ++ &to_reserved, false); + if (unlikely(ret)) + return ret; + +@@ -3650,7 +3681,7 @@ static int reserve_compress_blocks(struct dnode_of_data *dn, pgoff_t count, + + f2fs_i_compr_blocks_update(dn->inode, compr_blocks, true); + +- *reserved_blocks += reserved; ++ *reserved_blocks += to_reserved; + next: + count -= cluster_size; + } +@@ -3669,9 +3700,6 @@ static int f2fs_reserve_compress_blocks(struct file *filp, unsigned long arg) + if (!f2fs_sb_has_compression(sbi)) + return -EOPNOTSUPP; + +- if (!f2fs_compressed_file(inode)) +- return -EINVAL; +- + if (f2fs_readonly(sbi->sb)) + return -EROFS; + +@@ -3683,7 +3711,8 @@ static int f2fs_reserve_compress_blocks(struct file *filp, unsigned long arg) + + inode_lock(inode); + +- if (!is_inode_flag_set(inode, FI_COMPRESS_RELEASED)) { ++ if (!f2fs_compressed_file(inode) || ++ !is_inode_flag_set(inode, FI_COMPRESS_RELEASED)) { + ret = -EINVAL; + goto unlock_inode; + } +@@ -3700,9 +3729,12 @@ static int f2fs_reserve_compress_blocks(struct file *filp, unsigned long arg) + struct dnode_of_data dn; + pgoff_t end_offset, count; + ++ f2fs_lock_op(sbi); ++ + set_new_dnode(&dn, inode, NULL, NULL, 0); + ret = f2fs_get_dnode_of_data(&dn, page_idx, LOOKUP_NODE); + if (ret) { ++ f2fs_unlock_op(sbi); + if (ret == -ENOENT) { + page_idx = f2fs_get_next_page_offset(&dn, + page_idx); +@@ -3720,6 +3752,8 @@ static int f2fs_reserve_compress_blocks(struct file *filp, unsigned long arg) + + f2fs_put_dnode(&dn); + ++ f2fs_unlock_op(sbi); ++ + if (ret < 0) + break; + +@@ -4076,7 +4110,6 @@ static int f2fs_ioc_decompress_file(struct file *filp) + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); + struct f2fs_inode_info *fi = F2FS_I(inode); + pgoff_t page_idx = 0, last_idx; +- unsigned int blk_per_seg = sbi->blocks_per_seg; + int cluster_size = fi->i_cluster_size; + int count, ret; + +@@ -4087,9 +4120,6 @@ static int f2fs_ioc_decompress_file(struct file *filp) + if (!(filp->f_mode & FMODE_WRITE)) + return -EBADF; + +- if (!f2fs_compressed_file(inode)) +- return -EINVAL; +- + f2fs_balance_fs(sbi, true); + + file_start_write(filp); +@@ -4100,7 +4130,8 @@ static int f2fs_ioc_decompress_file(struct file *filp) + goto out; + } + +- if (is_inode_flag_set(inode, FI_COMPRESS_RELEASED)) { ++ if (!f2fs_compressed_file(inode) || ++ is_inode_flag_set(inode, FI_COMPRESS_RELEASED)) { + ret = -EINVAL; + goto out; + } +@@ -4120,7 +4151,7 @@ static int f2fs_ioc_decompress_file(struct file *filp) + if (ret < 0) + break; + +- if (get_dirty_pages(inode) >= blk_per_seg) { ++ if (get_dirty_pages(inode) >= BLKS_PER_SEG(sbi)) { + ret = filemap_fdatawrite(inode->i_mapping); + if (ret < 0) + break; +@@ -4155,7 +4186,6 @@ static int f2fs_ioc_compress_file(struct file *filp) + struct inode *inode = file_inode(filp); + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); + pgoff_t page_idx = 0, last_idx; +- unsigned int blk_per_seg = sbi->blocks_per_seg; + int cluster_size = F2FS_I(inode)->i_cluster_size; + int count, ret; + +@@ -4166,9 +4196,6 @@ static int f2fs_ioc_compress_file(struct file *filp) + if (!(filp->f_mode & FMODE_WRITE)) + return -EBADF; + +- if (!f2fs_compressed_file(inode)) +- return -EINVAL; +- + f2fs_balance_fs(sbi, true); + + file_start_write(filp); +@@ -4179,7 +4206,8 @@ static int f2fs_ioc_compress_file(struct file *filp) + goto out; + } + +- if (is_inode_flag_set(inode, FI_COMPRESS_RELEASED)) { ++ if (!f2fs_compressed_file(inode) || ++ is_inode_flag_set(inode, FI_COMPRESS_RELEASED)) { + ret = -EINVAL; + goto out; + } +@@ -4198,7 +4226,7 @@ static int f2fs_ioc_compress_file(struct file *filp) + if (ret < 0) + break; + +- if (get_dirty_pages(inode) >= blk_per_seg) { ++ if (get_dirty_pages(inode) >= BLKS_PER_SEG(sbi)) { + ret = filemap_fdatawrite(inode->i_mapping); + if (ret < 0) + break; +diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c +index 405a6077bd83b..3f0632dd9d2e6 100644 +--- a/fs/f2fs/gc.c ++++ b/fs/f2fs/gc.c +@@ -259,7 +259,7 @@ static void select_policy(struct f2fs_sb_info *sbi, int gc_type, + p->ofs_unit = 1; + } else { + p->gc_mode = select_gc_type(sbi, gc_type); +- p->ofs_unit = sbi->segs_per_sec; ++ p->ofs_unit = SEGS_PER_SEC(sbi); + if (__is_large_section(sbi)) { + p->dirty_bitmap = dirty_i->dirty_secmap; + p->max_search = count_bits(p->dirty_bitmap, +@@ -280,11 +280,11 @@ static void select_policy(struct f2fs_sb_info *sbi, int gc_type, + p->max_search > sbi->max_victim_search) + p->max_search = sbi->max_victim_search; + +- /* let's select beginning hot/small space first in no_heap mode*/ ++ /* let's select beginning hot/small space first. */ + if (f2fs_need_rand_seg(sbi)) +- p->offset = get_random_u32_below(MAIN_SECS(sbi) * sbi->segs_per_sec); +- else if (test_opt(sbi, NOHEAP) && +- (type == CURSEG_HOT_DATA || IS_NODESEG(type))) ++ p->offset = get_random_u32_below(MAIN_SECS(sbi) * ++ SEGS_PER_SEC(sbi)); ++ else if (type == CURSEG_HOT_DATA || IS_NODESEG(type)) + p->offset = 0; + else + p->offset = SIT_I(sbi)->last_victim[p->gc_mode]; +@@ -295,13 +295,13 @@ static unsigned int get_max_cost(struct f2fs_sb_info *sbi, + { + /* SSR allocates in a segment unit */ + if (p->alloc_mode == SSR) +- return sbi->blocks_per_seg; ++ return BLKS_PER_SEG(sbi); + else if (p->alloc_mode == AT_SSR) + return UINT_MAX; + + /* LFS */ + if (p->gc_mode == GC_GREEDY) +- return 2 * sbi->blocks_per_seg * p->ofs_unit; ++ return 2 * BLKS_PER_SEG(sbi) * p->ofs_unit; + else if (p->gc_mode == GC_CB) + return UINT_MAX; + else if (p->gc_mode == GC_AT) +@@ -496,9 +496,9 @@ static void add_victim_entry(struct f2fs_sb_info *sbi, + return; + } + +- for (i = 0; i < sbi->segs_per_sec; i++) ++ for (i = 0; i < SEGS_PER_SEC(sbi); i++) + mtime += get_seg_entry(sbi, start + i)->mtime; +- mtime = div_u64(mtime, sbi->segs_per_sec); ++ mtime = div_u64(mtime, SEGS_PER_SEC(sbi)); + + /* Handle if the system time has changed by the user */ + if (mtime < sit_i->min_mtime) +@@ -599,7 +599,6 @@ static void atssr_lookup_victim(struct f2fs_sb_info *sbi, + unsigned long long age; + unsigned long long max_mtime = sit_i->dirty_max_mtime; + unsigned long long min_mtime = sit_i->dirty_min_mtime; +- unsigned int seg_blocks = sbi->blocks_per_seg; + unsigned int vblocks; + unsigned int dirty_threshold = max(am->max_candidate_count, + am->candidate_ratio * +@@ -629,7 +628,7 @@ static void atssr_lookup_victim(struct f2fs_sb_info *sbi, + f2fs_bug_on(sbi, !vblocks); + + /* rare case */ +- if (vblocks == seg_blocks) ++ if (vblocks == BLKS_PER_SEG(sbi)) + goto skip_node; + + iter++; +@@ -755,7 +754,7 @@ int f2fs_get_victim(struct f2fs_sb_info *sbi, unsigned int *result, + int ret = 0; + + mutex_lock(&dirty_i->seglist_lock); +- last_segment = MAIN_SECS(sbi) * sbi->segs_per_sec; ++ last_segment = MAIN_SECS(sbi) * SEGS_PER_SEC(sbi); + + p.alloc_mode = alloc_mode; + p.age = age; +@@ -896,7 +895,7 @@ int f2fs_get_victim(struct f2fs_sb_info *sbi, unsigned int *result, + else + sm->last_victim[p.gc_mode] = segno + p.ofs_unit; + sm->last_victim[p.gc_mode] %= +- (MAIN_SECS(sbi) * sbi->segs_per_sec); ++ (MAIN_SECS(sbi) * SEGS_PER_SEC(sbi)); + break; + } + } +@@ -1184,7 +1183,6 @@ static int ra_data_block(struct inode *inode, pgoff_t index) + .op_flags = 0, + .encrypted_page = NULL, + .in_list = 0, +- .retry = 0, + }; + int err; + +@@ -1273,7 +1271,6 @@ static int move_data_block(struct inode *inode, block_t bidx, + .op_flags = 0, + .encrypted_page = NULL, + .in_list = 0, +- .retry = 0, + }; + struct dnode_of_data dn; + struct f2fs_summary sum; +@@ -1393,18 +1390,12 @@ static int move_data_block(struct inode *inode, block_t bidx, + fio.op_flags = REQ_SYNC; + fio.new_blkaddr = newaddr; + f2fs_submit_page_write(&fio); +- if (fio.retry) { +- err = -EAGAIN; +- if (PageWriteback(fio.encrypted_page)) +- end_page_writeback(fio.encrypted_page); +- goto put_page_out; +- } + + f2fs_update_iostat(fio.sbi, NULL, FS_GC_DATA_IO, F2FS_BLKSIZE); + + f2fs_update_data_blkaddr(&dn, newaddr); + set_inode_flag(inode, FI_APPEND_WRITE); +-put_page_out: ++ + f2fs_put_page(fio.encrypted_page, 1); + recover_block: + if (err) +@@ -1560,10 +1551,15 @@ static int gc_data_segment(struct f2fs_sb_info *sbi, struct f2fs_summary *sum, + int err; + + inode = f2fs_iget(sb, dni.ino); +- if (IS_ERR(inode) || is_bad_inode(inode) || +- special_file(inode->i_mode)) ++ if (IS_ERR(inode)) + continue; + ++ if (is_bad_inode(inode) || ++ special_file(inode->i_mode)) { ++ iput(inode); ++ continue; ++ } ++ + err = f2fs_gc_pinned_control(inode, gc_type, segno); + if (err == -EAGAIN) { + iput(inode); +@@ -1678,7 +1674,7 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi, + struct f2fs_summary_block *sum; + struct blk_plug plug; + unsigned int segno = start_segno; +- unsigned int end_segno = start_segno + sbi->segs_per_sec; ++ unsigned int end_segno = start_segno + SEGS_PER_SEC(sbi); + int seg_freed = 0, migrated = 0; + unsigned char type = IS_DATASEG(get_seg_entry(sbi, segno)->type) ? + SUM_TYPE_DATA : SUM_TYPE_NODE; +@@ -1686,7 +1682,7 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi, + int submitted = 0; + + if (__is_large_section(sbi)) +- end_segno = rounddown(end_segno, sbi->segs_per_sec); ++ end_segno = rounddown(end_segno, SEGS_PER_SEC(sbi)); + + /* + * zone-capacity can be less than zone-size in zoned devices, +@@ -1694,7 +1690,7 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi, + * calculate the end segno in the zone which can be garbage collected + */ + if (f2fs_sb_has_blkzoned(sbi)) +- end_segno -= sbi->segs_per_sec - ++ end_segno -= SEGS_PER_SEC(sbi) - + f2fs_usable_segs_in_sec(sbi, segno); + + sanity_check_seg_type(sbi, get_seg_entry(sbi, segno)->type); +@@ -1980,10 +1976,40 @@ void f2fs_build_gc_manager(struct f2fs_sb_info *sbi) + init_atgc_management(sbi); + } + ++int f2fs_gc_range(struct f2fs_sb_info *sbi, ++ unsigned int start_seg, unsigned int end_seg, ++ bool dry_run, unsigned int dry_run_sections) ++{ ++ unsigned int segno; ++ unsigned int gc_secs = dry_run_sections; ++ ++ for (segno = start_seg; segno <= end_seg; segno += SEGS_PER_SEC(sbi)) { ++ struct gc_inode_list gc_list = { ++ .ilist = LIST_HEAD_INIT(gc_list.ilist), ++ .iroot = RADIX_TREE_INIT(gc_list.iroot, GFP_NOFS), ++ }; ++ ++ do_garbage_collect(sbi, segno, &gc_list, FG_GC, ++ dry_run_sections == 0); ++ put_gc_inode(&gc_list); ++ ++ if (!dry_run && get_valid_blocks(sbi, segno, true)) ++ return -EAGAIN; ++ if (dry_run && dry_run_sections && ++ !get_valid_blocks(sbi, segno, true) && --gc_secs == 0) ++ break; ++ ++ if (fatal_signal_pending(current)) ++ return -ERESTARTSYS; ++ } ++ ++ return 0; ++} ++ + static int free_segment_range(struct f2fs_sb_info *sbi, +- unsigned int secs, bool gc_only) ++ unsigned int secs, bool dry_run) + { +- unsigned int segno, next_inuse, start, end; ++ unsigned int next_inuse, start, end; + struct cp_control cpc = { CP_RESIZE, 0, 0, 0 }; + int gc_mode, gc_type; + int err = 0; +@@ -1991,7 +2017,7 @@ static int free_segment_range(struct f2fs_sb_info *sbi, + + /* Force block allocation for GC */ + MAIN_SECS(sbi) -= secs; +- start = MAIN_SECS(sbi) * sbi->segs_per_sec; ++ start = MAIN_SECS(sbi) * SEGS_PER_SEC(sbi); + end = MAIN_SEGS(sbi) - 1; + + mutex_lock(&DIRTY_I(sbi)->seglist_lock); +@@ -2009,25 +2035,8 @@ static int free_segment_range(struct f2fs_sb_info *sbi, + f2fs_allocate_segment_for_resize(sbi, type, start, end); + + /* do GC to move out valid blocks in the range */ +- for (segno = start; segno <= end; segno += sbi->segs_per_sec) { +- struct gc_inode_list gc_list = { +- .ilist = LIST_HEAD_INIT(gc_list.ilist), +- .iroot = RADIX_TREE_INIT(gc_list.iroot, GFP_NOFS), +- }; +- +- do_garbage_collect(sbi, segno, &gc_list, FG_GC, true); +- put_gc_inode(&gc_list); +- +- if (!gc_only && get_valid_blocks(sbi, segno, true)) { +- err = -EAGAIN; +- goto out; +- } +- if (fatal_signal_pending(current)) { +- err = -ERESTARTSYS; +- goto out; +- } +- } +- if (gc_only) ++ err = f2fs_gc_range(sbi, start, end, dry_run, 0); ++ if (err || dry_run) + goto out; + + stat_inc_cp_call_count(sbi, TOTAL_CALL); +@@ -2053,7 +2062,7 @@ static void update_sb_metadata(struct f2fs_sb_info *sbi, int secs) + int segment_count; + int segment_count_main; + long long block_count; +- int segs = secs * sbi->segs_per_sec; ++ int segs = secs * SEGS_PER_SEC(sbi); + + f2fs_down_write(&sbi->sb_lock); + +@@ -2066,7 +2075,7 @@ static void update_sb_metadata(struct f2fs_sb_info *sbi, int secs) + raw_sb->segment_count = cpu_to_le32(segment_count + segs); + raw_sb->segment_count_main = cpu_to_le32(segment_count_main + segs); + raw_sb->block_count = cpu_to_le64(block_count + +- (long long)segs * sbi->blocks_per_seg); ++ (long long)(segs << sbi->log_blocks_per_seg)); + if (f2fs_is_multi_device(sbi)) { + int last_dev = sbi->s_ndevs - 1; + int dev_segs = +@@ -2081,8 +2090,8 @@ static void update_sb_metadata(struct f2fs_sb_info *sbi, int secs) + + static void update_fs_metadata(struct f2fs_sb_info *sbi, int secs) + { +- int segs = secs * sbi->segs_per_sec; +- long long blks = (long long)segs * sbi->blocks_per_seg; ++ int segs = secs * SEGS_PER_SEC(sbi); ++ long long blks = (long long)segs << sbi->log_blocks_per_seg; + long long user_block_count = + le64_to_cpu(F2FS_CKPT(sbi)->user_block_count); + +@@ -2124,7 +2133,7 @@ int f2fs_resize_fs(struct file *filp, __u64 block_count) + int last_dev = sbi->s_ndevs - 1; + __u64 last_segs = FDEV(last_dev).total_segments; + +- if (block_count + last_segs * sbi->blocks_per_seg <= ++ if (block_count + (last_segs << sbi->log_blocks_per_seg) <= + old_block_count) + return -EINVAL; + } +diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c +index cdd890dbd5e34..c765bda3beaac 100644 +--- a/fs/f2fs/node.c ++++ b/fs/f2fs/node.c +@@ -1319,6 +1319,7 @@ struct page *f2fs_new_node_page(struct dnode_of_data *dn, unsigned int ofs) + } + if (unlikely(new_ni.blk_addr != NULL_ADDR)) { + err = -EFSCORRUPTED; ++ dec_valid_node_count(sbi, dn->inode, !ofs); + set_sbi_flag(sbi, SBI_NEED_FSCK); + f2fs_handle_error(sbi, ERROR_INVALID_BLKADDR); + goto fail; +@@ -1345,7 +1346,6 @@ struct page *f2fs_new_node_page(struct dnode_of_data *dn, unsigned int ofs) + if (ofs == 0) + inc_valid_inode_count(sbi); + return page; +- + fail: + clear_node_page_dirty(page); + f2fs_put_page(page, 1); +@@ -2849,7 +2849,7 @@ int f2fs_restore_node_summary(struct f2fs_sb_info *sbi, + int i, idx, last_offset, nrpages; + + /* scan the node segment */ +- last_offset = sbi->blocks_per_seg; ++ last_offset = BLKS_PER_SEG(sbi); + addr = START_BLOCK(sbi, segno); + sum_entry = &sum->entries[0]; + +@@ -3166,7 +3166,7 @@ static int __get_nat_bitmaps(struct f2fs_sb_info *sbi) + if (!is_set_ckpt_flags(sbi, CP_NAT_BITS_FLAG)) + return 0; + +- nat_bits_addr = __start_cp_addr(sbi) + sbi->blocks_per_seg - ++ nat_bits_addr = __start_cp_addr(sbi) + BLKS_PER_SEG(sbi) - + nm_i->nat_bits_blocks; + for (i = 0; i < nm_i->nat_bits_blocks; i++) { + struct page *page; +diff --git a/fs/f2fs/node.h b/fs/f2fs/node.h +index 5bd16a95eef8f..6aea13024ac16 100644 +--- a/fs/f2fs/node.h ++++ b/fs/f2fs/node.h +@@ -208,10 +208,10 @@ static inline pgoff_t current_nat_addr(struct f2fs_sb_info *sbi, nid_t start) + + block_addr = (pgoff_t)(nm_i->nat_blkaddr + + (block_off << 1) - +- (block_off & (sbi->blocks_per_seg - 1))); ++ (block_off & (BLKS_PER_SEG(sbi) - 1))); + + if (f2fs_test_bit(block_off, nm_i->nat_bitmap)) +- block_addr += sbi->blocks_per_seg; ++ block_addr += BLKS_PER_SEG(sbi); + + return block_addr; + } +diff --git a/fs/f2fs/recovery.c b/fs/f2fs/recovery.c +index 23077cdfde367..f8852aa526408 100644 +--- a/fs/f2fs/recovery.c ++++ b/fs/f2fs/recovery.c +@@ -354,7 +354,7 @@ static unsigned int adjust_por_ra_blocks(struct f2fs_sb_info *sbi, + if (blkaddr + 1 == next_blkaddr) + ra_blocks = min_t(unsigned int, RECOVERY_MAX_RA_BLOCKS, + ra_blocks * 2); +- else if (next_blkaddr % sbi->blocks_per_seg) ++ else if (next_blkaddr % BLKS_PER_SEG(sbi)) + ra_blocks = max_t(unsigned int, RECOVERY_MIN_RA_BLOCKS, + ra_blocks / 2); + return ra_blocks; +diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c +index 4549964819731..b578ce3757ef8 100644 +--- a/fs/f2fs/segment.c ++++ b/fs/f2fs/segment.c +@@ -450,8 +450,8 @@ static inline bool excess_dirty_threshold(struct f2fs_sb_info *sbi) + unsigned int nodes = get_pages(sbi, F2FS_DIRTY_NODES); + unsigned int meta = get_pages(sbi, F2FS_DIRTY_META); + unsigned int imeta = get_pages(sbi, F2FS_DIRTY_IMETA); +- unsigned int threshold = sbi->blocks_per_seg * factor * +- DEFAULT_DIRTY_THRESHOLD; ++ unsigned int threshold = (factor * DEFAULT_DIRTY_THRESHOLD) << ++ sbi->log_blocks_per_seg; + unsigned int global_threshold = threshold * 3 / 2; + + if (dents >= threshold || qdata >= threshold || +@@ -1103,9 +1103,8 @@ static void __remove_discard_cmd(struct f2fs_sb_info *sbi, + dc->error = 0; + + if (dc->error) +- printk_ratelimited( +- "%sF2FS-fs (%s): Issue discard(%u, %u, %u) failed, ret: %d", +- KERN_INFO, sbi->sb->s_id, ++ f2fs_info_ratelimited(sbi, ++ "Issue discard(%u, %u, %u) failed, ret: %d", + dc->di.lstart, dc->di.start, dc->di.len, dc->error); + __detach_discard_cmd(dcc, dc); + } +@@ -1134,8 +1133,7 @@ static void __check_sit_bitmap(struct f2fs_sb_info *sbi, + struct seg_entry *sentry; + unsigned int segno; + block_t blk = start; +- unsigned long offset, size, max_blocks = sbi->blocks_per_seg; +- unsigned long *map; ++ unsigned long offset, size, *map; + + while (blk < end) { + segno = GET_SEGNO(sbi, blk); +@@ -1145,7 +1143,7 @@ static void __check_sit_bitmap(struct f2fs_sb_info *sbi, + if (end < START_BLOCK(sbi, segno + 1)) + size = GET_BLKOFF_FROM_SEG0(sbi, end); + else +- size = max_blocks; ++ size = BLKS_PER_SEG(sbi); + map = (unsigned long *)(sentry->cur_valid_map); + offset = __find_rev_next_bit(map, size, offset); + f2fs_bug_on(sbi, offset != size); +@@ -2043,7 +2041,6 @@ static bool add_discard_addrs(struct f2fs_sb_info *sbi, struct cp_control *cpc, + bool check_only) + { + int entries = SIT_VBLOCK_MAP_SIZE / sizeof(unsigned long); +- int max_blocks = sbi->blocks_per_seg; + struct seg_entry *se = get_seg_entry(sbi, cpc->trim_start); + unsigned long *cur_map = (unsigned long *)se->cur_valid_map; + unsigned long *ckpt_map = (unsigned long *)se->ckpt_valid_map; +@@ -2055,8 +2052,9 @@ static bool add_discard_addrs(struct f2fs_sb_info *sbi, struct cp_control *cpc, + struct list_head *head = &SM_I(sbi)->dcc_info->entry_list; + int i; + +- if (se->valid_blocks == max_blocks || !f2fs_hw_support_discard(sbi) || +- !f2fs_block_unit_discard(sbi)) ++ if (se->valid_blocks == BLKS_PER_SEG(sbi) || ++ !f2fs_hw_support_discard(sbi) || ++ !f2fs_block_unit_discard(sbi)) + return false; + + if (!force) { +@@ -2073,13 +2071,14 @@ static bool add_discard_addrs(struct f2fs_sb_info *sbi, struct cp_control *cpc, + + while (force || SM_I(sbi)->dcc_info->nr_discards <= + SM_I(sbi)->dcc_info->max_discards) { +- start = __find_rev_next_bit(dmap, max_blocks, end + 1); +- if (start >= max_blocks) ++ start = __find_rev_next_bit(dmap, BLKS_PER_SEG(sbi), end + 1); ++ if (start >= BLKS_PER_SEG(sbi)) + break; + +- end = __find_rev_next_zero_bit(dmap, max_blocks, start + 1); +- if (force && start && end != max_blocks +- && (end - start) < cpc->trim_minlen) ++ end = __find_rev_next_zero_bit(dmap, ++ BLKS_PER_SEG(sbi), start + 1); ++ if (force && start && end != BLKS_PER_SEG(sbi) && ++ (end - start) < cpc->trim_minlen) + continue; + + if (check_only) +@@ -2161,8 +2160,8 @@ void f2fs_clear_prefree_segments(struct f2fs_sb_info *sbi, + start + 1); + + if (section_alignment) { +- start = rounddown(start, sbi->segs_per_sec); +- end = roundup(end, sbi->segs_per_sec); ++ start = rounddown(start, SEGS_PER_SEC(sbi)); ++ end = roundup(end, SEGS_PER_SEC(sbi)); + } + + for (i = start; i < end; i++) { +@@ -2190,9 +2189,9 @@ void f2fs_clear_prefree_segments(struct f2fs_sb_info *sbi, + if (!IS_CURSEC(sbi, secno) && + !get_valid_blocks(sbi, start, true)) + f2fs_issue_discard(sbi, START_BLOCK(sbi, start_segno), +- sbi->segs_per_sec << sbi->log_blocks_per_seg); ++ BLKS_PER_SEC(sbi)); + +- start = start_segno + sbi->segs_per_sec; ++ start = start_segno + SEGS_PER_SEC(sbi); + if (start < end) + goto next; + else +@@ -2211,7 +2210,7 @@ void f2fs_clear_prefree_segments(struct f2fs_sb_info *sbi, + find_next: + if (is_valid) { + next_pos = find_next_zero_bit_le(entry->discard_map, +- sbi->blocks_per_seg, cur_pos); ++ BLKS_PER_SEG(sbi), cur_pos); + len = next_pos - cur_pos; + + if (f2fs_sb_has_blkzoned(sbi) || +@@ -2223,13 +2222,13 @@ void f2fs_clear_prefree_segments(struct f2fs_sb_info *sbi, + total_len += len; + } else { + next_pos = find_next_bit_le(entry->discard_map, +- sbi->blocks_per_seg, cur_pos); ++ BLKS_PER_SEG(sbi), cur_pos); + } + skip: + cur_pos = next_pos; + is_valid = !is_valid; + +- if (cur_pos < sbi->blocks_per_seg) ++ if (cur_pos < BLKS_PER_SEG(sbi)) + goto find_next; + + release_discard_addr(entry); +@@ -2277,7 +2276,7 @@ static int create_discard_cmd_control(struct f2fs_sb_info *sbi) + dcc->discard_granularity = DEFAULT_DISCARD_GRANULARITY; + dcc->max_ordered_discard = DEFAULT_MAX_ORDERED_DISCARD_GRANULARITY; + if (F2FS_OPTION(sbi).discard_unit == DISCARD_UNIT_SEGMENT) +- dcc->discard_granularity = sbi->blocks_per_seg; ++ dcc->discard_granularity = BLKS_PER_SEG(sbi); + else if (F2FS_OPTION(sbi).discard_unit == DISCARD_UNIT_SECTION) + dcc->discard_granularity = BLKS_PER_SEC(sbi); + +@@ -2540,7 +2539,7 @@ static unsigned short f2fs_curseg_valid_blocks(struct f2fs_sb_info *sbi, int typ + struct curseg_info *curseg = CURSEG_I(sbi, type); + + if (sbi->ckpt->alloc_type[type] == SSR) +- return sbi->blocks_per_seg; ++ return BLKS_PER_SEG(sbi); + return curseg->next_blkoff; + } + +@@ -2628,7 +2627,7 @@ static int is_next_segment_free(struct f2fs_sb_info *sbi, + unsigned int segno = curseg->segno + 1; + struct free_segmap_info *free_i = FREE_I(sbi); + +- if (segno < MAIN_SEGS(sbi) && segno % sbi->segs_per_sec) ++ if (segno < MAIN_SEGS(sbi) && segno % SEGS_PER_SEC(sbi)) + return !test_bit(segno, free_i->free_segmap); + return 0; + } +@@ -2638,53 +2637,41 @@ static int is_next_segment_free(struct f2fs_sb_info *sbi, + * This function should be returned with success, otherwise BUG + */ + static void get_new_segment(struct f2fs_sb_info *sbi, +- unsigned int *newseg, bool new_sec, int dir) ++ unsigned int *newseg, bool new_sec, bool pinning) + { + struct free_segmap_info *free_i = FREE_I(sbi); + unsigned int segno, secno, zoneno; + unsigned int total_zones = MAIN_SECS(sbi) / sbi->secs_per_zone; + unsigned int hint = GET_SEC_FROM_SEG(sbi, *newseg); + unsigned int old_zoneno = GET_ZONE_FROM_SEG(sbi, *newseg); +- unsigned int left_start = hint; + bool init = true; +- int go_left = 0; + int i; + + spin_lock(&free_i->segmap_lock); + +- if (!new_sec && ((*newseg + 1) % sbi->segs_per_sec)) { ++ if (!new_sec && ((*newseg + 1) % SEGS_PER_SEC(sbi))) { + segno = find_next_zero_bit(free_i->free_segmap, + GET_SEG_FROM_SEC(sbi, hint + 1), *newseg + 1); + if (segno < GET_SEG_FROM_SEC(sbi, hint + 1)) + goto got_it; + } ++ ++ /* ++ * If we format f2fs on zoned storage, let's try to get pinned sections ++ * from beginning of the storage, which should be a conventional one. ++ */ ++ if (f2fs_sb_has_blkzoned(sbi)) { ++ segno = pinning ? 0 : max(first_zoned_segno(sbi), *newseg); ++ hint = GET_SEC_FROM_SEG(sbi, segno); ++ } ++ + find_other_zone: + secno = find_next_zero_bit(free_i->free_secmap, MAIN_SECS(sbi), hint); + if (secno >= MAIN_SECS(sbi)) { +- if (dir == ALLOC_RIGHT) { +- secno = find_first_zero_bit(free_i->free_secmap, ++ secno = find_first_zero_bit(free_i->free_secmap, + MAIN_SECS(sbi)); +- f2fs_bug_on(sbi, secno >= MAIN_SECS(sbi)); +- } else { +- go_left = 1; +- left_start = hint - 1; +- } ++ f2fs_bug_on(sbi, secno >= MAIN_SECS(sbi)); + } +- if (go_left == 0) +- goto skip_left; +- +- while (test_bit(left_start, free_i->free_secmap)) { +- if (left_start > 0) { +- left_start--; +- continue; +- } +- left_start = find_first_zero_bit(free_i->free_secmap, +- MAIN_SECS(sbi)); +- f2fs_bug_on(sbi, left_start >= MAIN_SECS(sbi)); +- break; +- } +- secno = left_start; +-skip_left: + segno = GET_SEG_FROM_SEC(sbi, secno); + zoneno = GET_ZONE_FROM_SEC(sbi, secno); + +@@ -2695,21 +2682,13 @@ static void get_new_segment(struct f2fs_sb_info *sbi, + goto got_it; + if (zoneno == old_zoneno) + goto got_it; +- if (dir == ALLOC_LEFT) { +- if (!go_left && zoneno + 1 >= total_zones) +- goto got_it; +- if (go_left && zoneno == 0) +- goto got_it; +- } + for (i = 0; i < NR_CURSEG_TYPE; i++) + if (CURSEG_I(sbi, i)->zone == zoneno) + break; + + if (i < NR_CURSEG_TYPE) { + /* zone is in user, try another */ +- if (go_left) +- hint = zoneno * sbi->secs_per_zone - 1; +- else if (zoneno + 1 >= total_zones) ++ if (zoneno + 1 >= total_zones) + hint = 0; + else + hint = (zoneno + 1) * sbi->secs_per_zone; +@@ -2755,9 +2734,8 @@ static unsigned int __get_next_segno(struct f2fs_sb_info *sbi, int type) + + sanity_check_seg_type(sbi, seg_type); + if (f2fs_need_rand_seg(sbi)) +- return get_random_u32_below(MAIN_SECS(sbi) * sbi->segs_per_sec); ++ return get_random_u32_below(MAIN_SECS(sbi) * SEGS_PER_SEC(sbi)); + +- /* if segs_per_sec is large than 1, we need to keep original policy. */ + if (__is_large_section(sbi)) + return curseg->segno; + +@@ -2768,8 +2746,7 @@ static unsigned int __get_next_segno(struct f2fs_sb_info *sbi, int type) + if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED))) + return 0; + +- if (test_opt(sbi, NOHEAP) && +- (seg_type == CURSEG_HOT_DATA || IS_NODESEG(seg_type))) ++ if (seg_type == CURSEG_HOT_DATA || IS_NODESEG(seg_type)) + return 0; + + if (SIT_I(sbi)->last_victim[ALLOC_NEXT]) +@@ -2786,30 +2763,30 @@ static unsigned int __get_next_segno(struct f2fs_sb_info *sbi, int type) + * Allocate a current working segment. + * This function always allocates a free segment in LFS manner. + */ +-static void new_curseg(struct f2fs_sb_info *sbi, int type, bool new_sec) ++static int new_curseg(struct f2fs_sb_info *sbi, int type, bool new_sec) + { + struct curseg_info *curseg = CURSEG_I(sbi, type); +- unsigned short seg_type = curseg->seg_type; + unsigned int segno = curseg->segno; +- int dir = ALLOC_LEFT; ++ bool pinning = type == CURSEG_COLD_DATA_PINNED; + + if (curseg->inited) +- write_sum_page(sbi, curseg->sum_blk, +- GET_SUM_BLOCK(sbi, segno)); +- if (seg_type == CURSEG_WARM_DATA || seg_type == CURSEG_COLD_DATA) +- dir = ALLOC_RIGHT; +- +- if (test_opt(sbi, NOHEAP)) +- dir = ALLOC_RIGHT; ++ write_sum_page(sbi, curseg->sum_blk, GET_SUM_BLOCK(sbi, segno)); + + segno = __get_next_segno(sbi, type); +- get_new_segment(sbi, &segno, new_sec, dir); ++ get_new_segment(sbi, &segno, new_sec, pinning); ++ if (new_sec && pinning && ++ !f2fs_valid_pinned_area(sbi, START_BLOCK(sbi, segno))) { ++ __set_free(sbi, segno); ++ return -EAGAIN; ++ } ++ + curseg->next_segno = segno; + reset_curseg(sbi, type, 1); + curseg->alloc_type = LFS; + if (F2FS_OPTION(sbi).fs_mode == FS_MODE_FRAGMENT_BLK) + curseg->fragment_remained_chunk = + get_random_u32_inclusive(1, sbi->max_fragment_chunk); ++ return 0; + } + + static int __next_free_blkoff(struct f2fs_sb_info *sbi, +@@ -2825,7 +2802,7 @@ static int __next_free_blkoff(struct f2fs_sb_info *sbi, + for (i = 0; i < entries; i++) + target_map[i] = ckpt_map[i] | cur_map[i]; + +- return __find_rev_next_zero_bit(target_map, sbi->blocks_per_seg, start); ++ return __find_rev_next_zero_bit(target_map, BLKS_PER_SEG(sbi), start); + } + + static int f2fs_find_next_ssr_block(struct f2fs_sb_info *sbi, +@@ -2836,7 +2813,7 @@ static int f2fs_find_next_ssr_block(struct f2fs_sb_info *sbi, + + bool f2fs_segment_has_free_slot(struct f2fs_sb_info *sbi, int segno) + { +- return __next_free_blkoff(sbi, segno, 0) < sbi->blocks_per_seg; ++ return __next_free_blkoff(sbi, segno, 0) < BLKS_PER_SEG(sbi); + } + + /* +@@ -3082,7 +3059,7 @@ void f2fs_allocate_segment_for_resize(struct f2fs_sb_info *sbi, int type, + f2fs_up_read(&SM_I(sbi)->curseg_lock); + } + +-static void __allocate_new_segment(struct f2fs_sb_info *sbi, int type, ++static int __allocate_new_segment(struct f2fs_sb_info *sbi, int type, + bool new_sec, bool force) + { + struct curseg_info *curseg = CURSEG_I(sbi, type); +@@ -3092,21 +3069,49 @@ static void __allocate_new_segment(struct f2fs_sb_info *sbi, int type, + !curseg->next_blkoff && + !get_valid_blocks(sbi, curseg->segno, new_sec) && + !get_ckpt_valid_blocks(sbi, curseg->segno, new_sec)) +- return; ++ return 0; + + old_segno = curseg->segno; +- new_curseg(sbi, type, true); ++ if (new_curseg(sbi, type, true)) ++ return -EAGAIN; + stat_inc_seg_type(sbi, curseg); + locate_dirty_segment(sbi, old_segno); ++ return 0; + } + +-void f2fs_allocate_new_section(struct f2fs_sb_info *sbi, int type, bool force) ++int f2fs_allocate_new_section(struct f2fs_sb_info *sbi, int type, bool force) + { ++ int ret; ++ + f2fs_down_read(&SM_I(sbi)->curseg_lock); + down_write(&SIT_I(sbi)->sentry_lock); +- __allocate_new_segment(sbi, type, true, force); ++ ret = __allocate_new_segment(sbi, type, true, force); + up_write(&SIT_I(sbi)->sentry_lock); + f2fs_up_read(&SM_I(sbi)->curseg_lock); ++ ++ return ret; ++} ++ ++int f2fs_allocate_pinning_section(struct f2fs_sb_info *sbi) ++{ ++ int err; ++ bool gc_required = true; ++ ++retry: ++ f2fs_lock_op(sbi); ++ err = f2fs_allocate_new_section(sbi, CURSEG_COLD_DATA_PINNED, false); ++ f2fs_unlock_op(sbi); ++ ++ if (f2fs_sb_has_blkzoned(sbi) && err && gc_required) { ++ f2fs_down_write(&sbi->gc_lock); ++ f2fs_gc_range(sbi, 0, GET_SEGNO(sbi, FDEV(0).end_blk), true, 1); ++ f2fs_up_write(&sbi->gc_lock); ++ ++ gc_required = false; ++ goto retry; ++ } ++ ++ return err; + } + + void f2fs_allocate_new_segments(struct f2fs_sb_info *sbi) +@@ -3236,8 +3241,8 @@ int f2fs_trim_fs(struct f2fs_sb_info *sbi, struct fstrim_range *range) + end_segno = (end >= MAX_BLKADDR(sbi)) ? MAIN_SEGS(sbi) - 1 : + GET_SEGNO(sbi, end); + if (need_align) { +- start_segno = rounddown(start_segno, sbi->segs_per_sec); +- end_segno = roundup(end_segno + 1, sbi->segs_per_sec) - 1; ++ start_segno = rounddown(start_segno, SEGS_PER_SEC(sbi)); ++ end_segno = roundup(end_segno + 1, SEGS_PER_SEC(sbi)) - 1; + } + + cpc.reason = CP_DISCARD; +@@ -3435,7 +3440,7 @@ void f2fs_allocate_data_block(struct f2fs_sb_info *sbi, struct page *page, + } + *new_blkaddr = NEXT_FREE_BLKADDR(sbi, curseg); + +- f2fs_bug_on(sbi, curseg->next_blkoff >= sbi->blocks_per_seg); ++ f2fs_bug_on(sbi, curseg->next_blkoff >= BLKS_PER_SEG(sbi)); + + f2fs_wait_discard_bio(sbi, *new_blkaddr); + +@@ -3472,6 +3477,13 @@ void f2fs_allocate_data_block(struct f2fs_sb_info *sbi, struct page *page, + * new segment. + */ + if (segment_full) { ++ if (type == CURSEG_COLD_DATA_PINNED && ++ !((curseg->segno + 1) % sbi->segs_per_sec)) { ++ write_sum_page(sbi, curseg->sum_blk, ++ GET_SUM_BLOCK(sbi, curseg->segno)); ++ goto skip_new_segment; ++ } ++ + if (from_gc) { + get_atssr_segment(sbi, type, se->type, + AT_SSR, se->mtime); +@@ -3483,6 +3495,8 @@ void f2fs_allocate_data_block(struct f2fs_sb_info *sbi, struct page *page, + stat_inc_seg_type(sbi, curseg); + } + } ++ ++skip_new_segment: + /* + * segment dirty status should be updated after segment allocation, + * so we just need to update status only one time after previous +@@ -3505,9 +3519,6 @@ void f2fs_allocate_data_block(struct f2fs_sb_info *sbi, struct page *page, + if (fio) { + struct f2fs_bio_info *io; + +- if (F2FS_IO_ALIGNED(sbi)) +- fio->retry = 0; +- + INIT_LIST_HEAD(&fio->list); + fio->in_list = 1; + io = sbi->write_io[fio->type] + fio->temp; +@@ -3555,7 +3566,7 @@ static void do_write_page(struct f2fs_summary *sum, struct f2fs_io_info *fio) + + if (keep_order) + f2fs_down_read(&fio->sbi->io_order_lock); +-reallocate: ++ + f2fs_allocate_data_block(fio->sbi, fio->page, fio->old_blkaddr, + &fio->new_blkaddr, sum, type, fio); + if (GET_SEGNO(fio->sbi, fio->old_blkaddr) != NULL_SEGNO) +@@ -3563,10 +3574,6 @@ static void do_write_page(struct f2fs_summary *sum, struct f2fs_io_info *fio) + + /* writeout dirty page into bdev */ + f2fs_submit_page_write(fio); +- if (fio->retry) { +- fio->old_blkaddr = fio->new_blkaddr; +- goto reallocate; +- } + + f2fs_update_device_state(fio->sbi, fio->ino, fio->new_blkaddr, 1); + +@@ -3885,7 +3892,7 @@ static int read_compacted_summaries(struct f2fs_sb_info *sbi) + seg_i->next_blkoff = blk_off; + + if (seg_i->alloc_type == SSR) +- blk_off = sbi->blocks_per_seg; ++ blk_off = BLKS_PER_SEG(sbi); + + for (j = 0; j < blk_off; j++) { + struct f2fs_summary *s; +@@ -3953,7 +3960,7 @@ static int read_normal_summaries(struct f2fs_sb_info *sbi, int type) + struct f2fs_summary *ns = &sum->entries[0]; + int i; + +- for (i = 0; i < sbi->blocks_per_seg; i++, ns++) { ++ for (i = 0; i < BLKS_PER_SEG(sbi); i++, ns++) { + ns->version = 0; + ns->ofs_in_node = 0; + } +@@ -4586,21 +4593,20 @@ static int build_sit_entries(struct f2fs_sb_info *sbi) + + sit_valid_blocks[SE_PAGETYPE(se)] += se->valid_blocks; + +- if (f2fs_block_unit_discard(sbi)) { +- /* build discard map only one time */ +- if (is_set_ckpt_flags(sbi, CP_TRIMMED_FLAG)) { +- memset(se->discard_map, 0xff, ++ if (!f2fs_block_unit_discard(sbi)) ++ goto init_discard_map_done; ++ ++ /* build discard map only one time */ ++ if (is_set_ckpt_flags(sbi, CP_TRIMMED_FLAG)) { ++ memset(se->discard_map, 0xff, + SIT_VBLOCK_MAP_SIZE); +- } else { +- memcpy(se->discard_map, +- se->cur_valid_map, ++ goto init_discard_map_done; ++ } ++ memcpy(se->discard_map, se->cur_valid_map, + SIT_VBLOCK_MAP_SIZE); +- sbi->discard_blks += +- sbi->blocks_per_seg - ++ sbi->discard_blks += BLKS_PER_SEG(sbi) - + se->valid_blocks; +- } +- } +- ++init_discard_map_done: + if (__is_large_section(sbi)) + get_sec_entry(sbi, start)->valid_blocks += + se->valid_blocks; +@@ -4740,7 +4746,7 @@ static void init_dirty_segmap(struct f2fs_sb_info *sbi) + return; + + mutex_lock(&dirty_i->seglist_lock); +- for (segno = 0; segno < MAIN_SEGS(sbi); segno += sbi->segs_per_sec) { ++ for (segno = 0; segno < MAIN_SEGS(sbi); segno += SEGS_PER_SEC(sbi)) { + valid_blocks = get_valid_blocks(sbi, segno, true); + secno = GET_SEC_FROM_SEG(sbi, segno); + +@@ -4839,7 +4845,7 @@ static int sanity_check_curseg(struct f2fs_sb_info *sbi) + if (curseg->alloc_type == SSR) + continue; + +- for (blkofs += 1; blkofs < sbi->blocks_per_seg; blkofs++) { ++ for (blkofs += 1; blkofs < BLKS_PER_SEG(sbi); blkofs++) { + if (!f2fs_test_bit(blkofs, se->cur_valid_map)) + continue; + out: +@@ -5138,7 +5144,7 @@ static inline unsigned int f2fs_usable_zone_blks_in_seg( + unsigned int secno; + + if (!sbi->unusable_blocks_per_sec) +- return sbi->blocks_per_seg; ++ return BLKS_PER_SEG(sbi); + + secno = GET_SEC_FROM_SEG(sbi, segno); + seg_start = START_BLOCK(sbi, segno); +@@ -5153,10 +5159,10 @@ static inline unsigned int f2fs_usable_zone_blks_in_seg( + */ + if (seg_start >= sec_cap_blkaddr) + return 0; +- if (seg_start + sbi->blocks_per_seg > sec_cap_blkaddr) ++ if (seg_start + BLKS_PER_SEG(sbi) > sec_cap_blkaddr) + return sec_cap_blkaddr - seg_start; + +- return sbi->blocks_per_seg; ++ return BLKS_PER_SEG(sbi); + } + #else + int f2fs_fix_curseg_write_pointer(struct f2fs_sb_info *sbi) +@@ -5182,7 +5188,7 @@ unsigned int f2fs_usable_blks_in_seg(struct f2fs_sb_info *sbi, + if (f2fs_sb_has_blkzoned(sbi)) + return f2fs_usable_zone_blks_in_seg(sbi, segno); + +- return sbi->blocks_per_seg; ++ return BLKS_PER_SEG(sbi); + } + + unsigned int f2fs_usable_segs_in_sec(struct f2fs_sb_info *sbi, +@@ -5191,7 +5197,7 @@ unsigned int f2fs_usable_segs_in_sec(struct f2fs_sb_info *sbi, + if (f2fs_sb_has_blkzoned(sbi)) + return CAP_SEGS_PER_SEC(sbi); + +- return sbi->segs_per_sec; ++ return SEGS_PER_SEC(sbi); + } + + /* +@@ -5206,14 +5212,14 @@ static void init_min_max_mtime(struct f2fs_sb_info *sbi) + + sit_i->min_mtime = ULLONG_MAX; + +- for (segno = 0; segno < MAIN_SEGS(sbi); segno += sbi->segs_per_sec) { ++ for (segno = 0; segno < MAIN_SEGS(sbi); segno += SEGS_PER_SEC(sbi)) { + unsigned int i; + unsigned long long mtime = 0; + +- for (i = 0; i < sbi->segs_per_sec; i++) ++ for (i = 0; i < SEGS_PER_SEC(sbi); i++) + mtime += get_seg_entry(sbi, segno + i)->mtime; + +- mtime = div_u64(mtime, sbi->segs_per_sec); ++ mtime = div_u64(mtime, SEGS_PER_SEC(sbi)); + + if (sit_i->min_mtime > mtime) + sit_i->min_mtime = mtime; +@@ -5252,7 +5258,7 @@ int f2fs_build_segment_manager(struct f2fs_sb_info *sbi) + sm_info->ipu_policy = BIT(F2FS_IPU_FSYNC); + sm_info->min_ipu_util = DEF_MIN_IPU_UTIL; + sm_info->min_fsync_blocks = DEF_MIN_FSYNC_BLOCKS; +- sm_info->min_seq_blocks = sbi->blocks_per_seg; ++ sm_info->min_seq_blocks = BLKS_PER_SEG(sbi); + sm_info->min_hot_blocks = DEF_MIN_HOT_BLOCKS; + sm_info->min_ssr_sections = reserved_sections(sbi); + +diff --git a/fs/f2fs/segment.h b/fs/f2fs/segment.h +index 20580ebd24138..4595f1cc03828 100644 +--- a/fs/f2fs/segment.h ++++ b/fs/f2fs/segment.h +@@ -48,21 +48,21 @@ static inline void sanity_check_seg_type(struct f2fs_sb_info *sbi, + + #define IS_CURSEC(sbi, secno) \ + (((secno) == CURSEG_I(sbi, CURSEG_HOT_DATA)->segno / \ +- (sbi)->segs_per_sec) || \ ++ SEGS_PER_SEC(sbi)) || \ + ((secno) == CURSEG_I(sbi, CURSEG_WARM_DATA)->segno / \ +- (sbi)->segs_per_sec) || \ ++ SEGS_PER_SEC(sbi)) || \ + ((secno) == CURSEG_I(sbi, CURSEG_COLD_DATA)->segno / \ +- (sbi)->segs_per_sec) || \ ++ SEGS_PER_SEC(sbi)) || \ + ((secno) == CURSEG_I(sbi, CURSEG_HOT_NODE)->segno / \ +- (sbi)->segs_per_sec) || \ ++ SEGS_PER_SEC(sbi)) || \ + ((secno) == CURSEG_I(sbi, CURSEG_WARM_NODE)->segno / \ +- (sbi)->segs_per_sec) || \ ++ SEGS_PER_SEC(sbi)) || \ + ((secno) == CURSEG_I(sbi, CURSEG_COLD_NODE)->segno / \ +- (sbi)->segs_per_sec) || \ ++ SEGS_PER_SEC(sbi)) || \ + ((secno) == CURSEG_I(sbi, CURSEG_COLD_DATA_PINNED)->segno / \ +- (sbi)->segs_per_sec) || \ ++ SEGS_PER_SEC(sbi)) || \ + ((secno) == CURSEG_I(sbi, CURSEG_ALL_DATA_ATGC)->segno / \ +- (sbi)->segs_per_sec)) ++ SEGS_PER_SEC(sbi))) + + #define MAIN_BLKADDR(sbi) \ + (SM_I(sbi) ? SM_I(sbi)->main_blkaddr : \ +@@ -93,26 +93,24 @@ static inline void sanity_check_seg_type(struct f2fs_sb_info *sbi, + #define GET_SEGNO_FROM_SEG0(sbi, blk_addr) \ + (GET_SEGOFF_FROM_SEG0(sbi, blk_addr) >> (sbi)->log_blocks_per_seg) + #define GET_BLKOFF_FROM_SEG0(sbi, blk_addr) \ +- (GET_SEGOFF_FROM_SEG0(sbi, blk_addr) & ((sbi)->blocks_per_seg - 1)) ++ (GET_SEGOFF_FROM_SEG0(sbi, blk_addr) & (BLKS_PER_SEG(sbi) - 1)) + + #define GET_SEGNO(sbi, blk_addr) \ + ((!__is_valid_data_blkaddr(blk_addr)) ? \ + NULL_SEGNO : GET_L2R_SEGNO(FREE_I(sbi), \ + GET_SEGNO_FROM_SEG0(sbi, blk_addr))) +-#define BLKS_PER_SEC(sbi) \ +- ((sbi)->segs_per_sec * (sbi)->blocks_per_seg) + #define CAP_BLKS_PER_SEC(sbi) \ +- ((sbi)->segs_per_sec * (sbi)->blocks_per_seg - \ ++ (SEGS_PER_SEC(sbi) * BLKS_PER_SEG(sbi) - \ + (sbi)->unusable_blocks_per_sec) + #define CAP_SEGS_PER_SEC(sbi) \ +- ((sbi)->segs_per_sec - ((sbi)->unusable_blocks_per_sec >>\ ++ (SEGS_PER_SEC(sbi) - ((sbi)->unusable_blocks_per_sec >> \ + (sbi)->log_blocks_per_seg)) + #define GET_SEC_FROM_SEG(sbi, segno) \ +- (((segno) == -1) ? -1: (segno) / (sbi)->segs_per_sec) ++ (((segno) == -1) ? -1 : (segno) / SEGS_PER_SEC(sbi)) + #define GET_SEG_FROM_SEC(sbi, secno) \ +- ((secno) * (sbi)->segs_per_sec) ++ ((secno) * SEGS_PER_SEC(sbi)) + #define GET_ZONE_FROM_SEC(sbi, secno) \ +- (((secno) == -1) ? -1: (secno) / (sbi)->secs_per_zone) ++ (((secno) == -1) ? -1 : (secno) / (sbi)->secs_per_zone) + #define GET_ZONE_FROM_SEG(sbi, segno) \ + GET_ZONE_FROM_SEC(sbi, GET_SEC_FROM_SEG(sbi, segno)) + +@@ -138,16 +136,6 @@ static inline void sanity_check_seg_type(struct f2fs_sb_info *sbi, + #define SECTOR_TO_BLOCK(sectors) \ + ((sectors) >> F2FS_LOG_SECTORS_PER_BLOCK) + +-/* +- * indicate a block allocation direction: RIGHT and LEFT. +- * RIGHT means allocating new sections towards the end of volume. +- * LEFT means the opposite direction. +- */ +-enum { +- ALLOC_RIGHT = 0, +- ALLOC_LEFT +-}; +- + /* + * In the victim_sel_policy->alloc_mode, there are three block allocation modes. + * LFS writes data sequentially with cleaning operations. +@@ -364,7 +352,7 @@ static inline unsigned int get_ckpt_valid_blocks(struct f2fs_sb_info *sbi, + unsigned int blocks = 0; + int i; + +- for (i = 0; i < sbi->segs_per_sec; i++, start_segno++) { ++ for (i = 0; i < SEGS_PER_SEC(sbi); i++, start_segno++) { + struct seg_entry *se = get_seg_entry(sbi, start_segno); + + blocks += se->ckpt_valid_blocks; +@@ -449,7 +437,7 @@ static inline void __set_free(struct f2fs_sb_info *sbi, unsigned int segno) + free_i->free_segments++; + + next = find_next_bit(free_i->free_segmap, +- start_segno + sbi->segs_per_sec, start_segno); ++ start_segno + SEGS_PER_SEC(sbi), start_segno); + if (next >= start_segno + usable_segs) { + clear_bit(secno, free_i->free_secmap); + free_i->free_sections++; +@@ -485,7 +473,7 @@ static inline void __set_test_and_free(struct f2fs_sb_info *sbi, + if (!inmem && IS_CURSEC(sbi, secno)) + goto skip_free; + next = find_next_bit(free_i->free_segmap, +- start_segno + sbi->segs_per_sec, start_segno); ++ start_segno + SEGS_PER_SEC(sbi), start_segno); + if (next >= start_segno + usable_segs) { + if (test_and_clear_bit(secno, free_i->free_secmap)) + free_i->free_sections++; +@@ -792,10 +780,10 @@ static inline int check_block_count(struct f2fs_sb_info *sbi, + return -EFSCORRUPTED; + } + +- if (usable_blks_per_seg < sbi->blocks_per_seg) ++ if (usable_blks_per_seg < BLKS_PER_SEG(sbi)) + f2fs_bug_on(sbi, find_next_bit_le(&raw_sit->valid_map, +- sbi->blocks_per_seg, +- usable_blks_per_seg) != sbi->blocks_per_seg); ++ BLKS_PER_SEG(sbi), ++ usable_blks_per_seg) != BLKS_PER_SEG(sbi)); + + /* check segment usage, and check boundary of a given segment number */ + if (unlikely(GET_SIT_VBLOCKS(raw_sit) > usable_blks_per_seg +@@ -914,9 +902,9 @@ static inline int nr_pages_to_skip(struct f2fs_sb_info *sbi, int type) + return 0; + + if (type == DATA) +- return sbi->blocks_per_seg; ++ return BLKS_PER_SEG(sbi); + else if (type == NODE) +- return 8 * sbi->blocks_per_seg; ++ return 8 * BLKS_PER_SEG(sbi); + else if (type == META) + return 8 * BIO_MAX_VECS; + else +@@ -968,3 +956,13 @@ static inline void wake_up_discard_thread(struct f2fs_sb_info *sbi, bool force) + dcc->discard_wake = true; + wake_up_interruptible_all(&dcc->discard_wait_queue); + } ++ ++static inline unsigned int first_zoned_segno(struct f2fs_sb_info *sbi) ++{ ++ int devi; ++ ++ for (devi = 0; devi < sbi->s_ndevs; devi++) ++ if (bdev_is_zoned(FDEV(devi).bdev)) ++ return GET_SEGNO(sbi, FDEV(devi).start_blk); ++ return 0; ++} +diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c +index ab437022ea56f..ce2293e13fadd 100644 +--- a/fs/f2fs/super.c ++++ b/fs/f2fs/super.c +@@ -122,7 +122,6 @@ enum { + Opt_resgid, + Opt_resuid, + Opt_mode, +- Opt_io_size_bits, + Opt_fault_injection, + Opt_fault_type, + Opt_lazytime, +@@ -201,7 +200,6 @@ static match_table_t f2fs_tokens = { + {Opt_resgid, "resgid=%u"}, + {Opt_resuid, "resuid=%u"}, + {Opt_mode, "mode=%s"}, +- {Opt_io_size_bits, "io_bits=%u"}, + {Opt_fault_injection, "fault_injection=%u"}, + {Opt_fault_type, "fault_type=%u"}, + {Opt_lazytime, "lazytime"}, +@@ -248,7 +246,8 @@ static match_table_t f2fs_tokens = { + {Opt_err, NULL}, + }; + +-void f2fs_printk(struct f2fs_sb_info *sbi, const char *fmt, ...) ++void f2fs_printk(struct f2fs_sb_info *sbi, bool limit_rate, ++ const char *fmt, ...) + { + struct va_format vaf; + va_list args; +@@ -259,8 +258,12 @@ void f2fs_printk(struct f2fs_sb_info *sbi, const char *fmt, ...) + level = printk_get_level(fmt); + vaf.fmt = printk_skip_level(fmt); + vaf.va = &args; +- printk("%c%cF2FS-fs (%s): %pV\n", +- KERN_SOH_ASCII, level, sbi->sb->s_id, &vaf); ++ if (limit_rate) ++ printk_ratelimited("%c%cF2FS-fs (%s): %pV\n", ++ KERN_SOH_ASCII, level, sbi->sb->s_id, &vaf); ++ else ++ printk("%c%cF2FS-fs (%s): %pV\n", ++ KERN_SOH_ASCII, level, sbi->sb->s_id, &vaf); + + va_end(args); + } +@@ -328,46 +331,6 @@ static inline void limit_reserve_root(struct f2fs_sb_info *sbi) + F2FS_OPTION(sbi).s_resgid)); + } + +-static inline int adjust_reserved_segment(struct f2fs_sb_info *sbi) +-{ +- unsigned int sec_blks = sbi->blocks_per_seg * sbi->segs_per_sec; +- unsigned int avg_vblocks; +- unsigned int wanted_reserved_segments; +- block_t avail_user_block_count; +- +- if (!F2FS_IO_ALIGNED(sbi)) +- return 0; +- +- /* average valid block count in section in worst case */ +- avg_vblocks = sec_blks / F2FS_IO_SIZE(sbi); +- +- /* +- * we need enough free space when migrating one section in worst case +- */ +- wanted_reserved_segments = (F2FS_IO_SIZE(sbi) / avg_vblocks) * +- reserved_segments(sbi); +- wanted_reserved_segments -= reserved_segments(sbi); +- +- avail_user_block_count = sbi->user_block_count - +- sbi->current_reserved_blocks - +- F2FS_OPTION(sbi).root_reserved_blocks; +- +- if (wanted_reserved_segments * sbi->blocks_per_seg > +- avail_user_block_count) { +- f2fs_err(sbi, "IO align feature can't grab additional reserved segment: %u, available segments: %u", +- wanted_reserved_segments, +- avail_user_block_count >> sbi->log_blocks_per_seg); +- return -ENOSPC; +- } +- +- SM_I(sbi)->additional_reserved_segments = wanted_reserved_segments; +- +- f2fs_info(sbi, "IO align feature needs additional reserved segment: %u", +- wanted_reserved_segments); +- +- return 0; +-} +- + static inline void adjust_unusable_cap_perc(struct f2fs_sb_info *sbi) + { + if (!F2FS_OPTION(sbi).unusable_cap_perc) +@@ -754,10 +717,8 @@ static int parse_options(struct super_block *sb, char *options, bool is_remount) + clear_opt(sbi, DISCARD); + break; + case Opt_noheap: +- set_opt(sbi, NOHEAP); +- break; + case Opt_heap: +- clear_opt(sbi, NOHEAP); ++ f2fs_warn(sbi, "heap/no_heap options were deprecated"); + break; + #ifdef CONFIG_F2FS_FS_XATTR + case Opt_user_xattr: +@@ -904,16 +865,6 @@ static int parse_options(struct super_block *sb, char *options, bool is_remount) + } + kfree(name); + break; +- case Opt_io_size_bits: +- if (args->from && match_int(args, &arg)) +- return -EINVAL; +- if (arg <= 0 || arg > __ilog2_u32(BIO_MAX_VECS)) { +- f2fs_warn(sbi, "Not support %ld, larger than %d", +- BIT(arg), BIO_MAX_VECS); +- return -EINVAL; +- } +- F2FS_OPTION(sbi).write_io_size_bits = arg; +- break; + #ifdef CONFIG_F2FS_FAULT_INJECTION + case Opt_fault_injection: + if (args->from && match_int(args, &arg)) +@@ -1383,12 +1334,6 @@ static int parse_options(struct super_block *sb, char *options, bool is_remount) + } + #endif + +- if (F2FS_IO_SIZE_BITS(sbi) && !f2fs_lfs_mode(sbi)) { +- f2fs_err(sbi, "Should set mode=lfs with %luKB-sized IO", +- F2FS_IO_SIZE_KB(sbi)); +- return -EINVAL; +- } +- + if (test_opt(sbi, INLINE_XATTR_SIZE)) { + int min_size, max_size; + +@@ -1716,7 +1661,6 @@ static void f2fs_put_super(struct super_block *sb) + destroy_device_list(sbi); + f2fs_destroy_page_array_cache(sbi); + f2fs_destroy_xattr_caches(sbi); +- mempool_destroy(sbi->write_io_dummy); + #ifdef CONFIG_QUOTA + for (i = 0; i < MAXQUOTAS; i++) + kfree(F2FS_OPTION(sbi).s_qf_names[i]); +@@ -2008,10 +1952,6 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root) + } else { + seq_puts(seq, ",nodiscard"); + } +- if (test_opt(sbi, NOHEAP)) +- seq_puts(seq, ",no_heap"); +- else +- seq_puts(seq, ",heap"); + #ifdef CONFIG_F2FS_FS_XATTR + if (test_opt(sbi, XATTR_USER)) + seq_puts(seq, ",user_xattr"); +@@ -2077,9 +2017,6 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root) + F2FS_OPTION(sbi).s_resuid), + from_kgid_munged(&init_user_ns, + F2FS_OPTION(sbi).s_resgid)); +- if (F2FS_IO_SIZE_BITS(sbi)) +- seq_printf(seq, ",io_bits=%u", +- F2FS_OPTION(sbi).write_io_size_bits); + #ifdef CONFIG_F2FS_FAULT_INJECTION + if (test_opt(sbi, FAULT_INJECTION)) { + seq_printf(seq, ",fault_injection=%u", +@@ -2191,7 +2128,6 @@ static void default_options(struct f2fs_sb_info *sbi, bool remount) + set_opt(sbi, INLINE_XATTR); + set_opt(sbi, INLINE_DATA); + set_opt(sbi, INLINE_DENTRY); +- set_opt(sbi, NOHEAP); + set_opt(sbi, MERGE_CHECKPOINT); + F2FS_OPTION(sbi).unusable_cap = 0; + sbi->sb->s_flags |= SB_LAZYTIME; +@@ -2331,7 +2267,6 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data) + bool no_read_extent_cache = !test_opt(sbi, READ_EXTENT_CACHE); + bool no_age_extent_cache = !test_opt(sbi, AGE_EXTENT_CACHE); + bool enable_checkpoint = !test_opt(sbi, DISABLE_CHECKPOINT); +- bool no_io_align = !F2FS_IO_ALIGNED(sbi); + bool no_atgc = !test_opt(sbi, ATGC); + bool no_discard = !test_opt(sbi, DISCARD); + bool no_compress_cache = !test_opt(sbi, COMPRESS_CACHE); +@@ -2439,12 +2374,6 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data) + goto restore_opts; + } + +- if (no_io_align == !!F2FS_IO_ALIGNED(sbi)) { +- err = -EINVAL; +- f2fs_warn(sbi, "switch io_bits option is not allowed"); +- goto restore_opts; +- } +- + if (no_compress_cache == !!test_opt(sbi, COMPRESS_CACHE)) { + err = -EINVAL; + f2fs_warn(sbi, "switch compress_cache option is not allowed"); +@@ -3696,7 +3625,7 @@ int f2fs_sanity_check_ckpt(struct f2fs_sb_info *sbi) + } + + main_segs = le32_to_cpu(raw_super->segment_count_main); +- blocks_per_seg = sbi->blocks_per_seg; ++ blocks_per_seg = BLKS_PER_SEG(sbi); + + for (i = 0; i < NR_CURSEG_NODE_TYPE; i++) { + if (le32_to_cpu(ckpt->cur_node_segno[i]) >= main_segs || +@@ -3809,8 +3738,8 @@ static void init_sb_info(struct f2fs_sb_info *sbi) + sbi->secs_per_zone = le32_to_cpu(raw_super->secs_per_zone); + sbi->total_sections = le32_to_cpu(raw_super->section_count); + sbi->total_node_count = +- (le32_to_cpu(raw_super->segment_count_nat) / 2) +- * sbi->blocks_per_seg * NAT_ENTRY_PER_BLOCK; ++ ((le32_to_cpu(raw_super->segment_count_nat) / 2) * ++ NAT_ENTRY_PER_BLOCK) << sbi->log_blocks_per_seg; + F2FS_ROOT_INO(sbi) = le32_to_cpu(raw_super->root_ino); + F2FS_NODE_INO(sbi) = le32_to_cpu(raw_super->node_ino); + F2FS_META_INO(sbi) = le32_to_cpu(raw_super->meta_ino); +@@ -3819,7 +3748,7 @@ static void init_sb_info(struct f2fs_sb_info *sbi) + sbi->next_victim_seg[BG_GC] = NULL_SEGNO; + sbi->next_victim_seg[FG_GC] = NULL_SEGNO; + sbi->max_victim_search = DEF_MAX_VICTIM_SEARCH; +- sbi->migration_granularity = sbi->segs_per_sec; ++ sbi->migration_granularity = SEGS_PER_SEC(sbi); + sbi->seq_file_ra_mul = MIN_RA_MUL; + sbi->max_fragment_chunk = DEF_FRAGMENT_SIZE; + sbi->max_fragment_hole = DEF_FRAGMENT_SIZE; +@@ -4292,8 +4221,6 @@ static int f2fs_scan_devices(struct f2fs_sb_info *sbi) + FDEV(i).total_segments, + FDEV(i).start_blk, FDEV(i).end_blk); + } +- f2fs_info(sbi, +- "IO Block Size: %8ld KB", F2FS_IO_SIZE_KB(sbi)); + return 0; + } + +@@ -4506,19 +4433,10 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) + if (err) + goto free_iostat; + +- if (F2FS_IO_ALIGNED(sbi)) { +- sbi->write_io_dummy = +- mempool_create_page_pool(2 * (F2FS_IO_SIZE(sbi) - 1), 0); +- if (!sbi->write_io_dummy) { +- err = -ENOMEM; +- goto free_percpu; +- } +- } +- + /* init per sbi slab cache */ + err = f2fs_init_xattr_caches(sbi); + if (err) +- goto free_io_dummy; ++ goto free_percpu; + err = f2fs_init_page_array_cache(sbi); + if (err) + goto free_xattr_cache; +@@ -4606,10 +4524,6 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) + goto free_nm; + } + +- err = adjust_reserved_segment(sbi); +- if (err) +- goto free_nm; +- + /* For write statistics */ + sbi->sectors_written_start = f2fs_get_sectors_written(sbi); + +@@ -4841,8 +4755,6 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) + f2fs_destroy_page_array_cache(sbi); + free_xattr_cache: + f2fs_destroy_xattr_caches(sbi); +-free_io_dummy: +- mempool_destroy(sbi->write_io_dummy); + free_percpu: + destroy_percpu_info(sbi); + free_iostat: +diff --git a/fs/f2fs/sysfs.c b/fs/f2fs/sysfs.c +index 417fae96890f6..6347a55020c6e 100644 +--- a/fs/f2fs/sysfs.c ++++ b/fs/f2fs/sysfs.c +@@ -466,8 +466,8 @@ static ssize_t __sbi_store(struct f2fs_attr *a, + spin_lock(&sbi->stat_lock); + if (t > (unsigned long)(sbi->user_block_count - + F2FS_OPTION(sbi).root_reserved_blocks - +- sbi->blocks_per_seg * +- SM_I(sbi)->additional_reserved_segments)) { ++ (SM_I(sbi)->additional_reserved_segments << ++ sbi->log_blocks_per_seg))) { + spin_unlock(&sbi->stat_lock); + return -EINVAL; + } +@@ -517,7 +517,7 @@ static ssize_t __sbi_store(struct f2fs_attr *a, + } + + if (!strcmp(a->attr.name, "migration_granularity")) { +- if (t == 0 || t > sbi->segs_per_sec) ++ if (t == 0 || t > SEGS_PER_SEC(sbi)) + return -EINVAL; + } + +diff --git a/fs/gfs2/acl.h b/fs/gfs2/acl.h +index d4deb2b199595..82f5b09c04e66 100644 +--- a/fs/gfs2/acl.h ++++ b/fs/gfs2/acl.h +@@ -11,9 +11,9 @@ + + #define GFS2_ACL_MAX_ENTRIES(sdp) ((300 << (sdp)->sd_sb.sb_bsize_shift) >> 12) + +-extern struct posix_acl *gfs2_get_acl(struct inode *inode, int type, bool rcu); +-extern int __gfs2_set_acl(struct inode *inode, struct posix_acl *acl, int type); +-extern int gfs2_set_acl(struct mnt_idmap *idmap, struct dentry *dentry, +- struct posix_acl *acl, int type); ++struct posix_acl *gfs2_get_acl(struct inode *inode, int type, bool rcu); ++int __gfs2_set_acl(struct inode *inode, struct posix_acl *acl, int type); ++int gfs2_set_acl(struct mnt_idmap *idmap, struct dentry *dentry, ++ struct posix_acl *acl, int type); + + #endif /* __ACL_DOT_H__ */ +diff --git a/fs/gfs2/aops.c b/fs/gfs2/aops.c +index c26d48355cc27..6097db9a7ebf3 100644 +--- a/fs/gfs2/aops.c ++++ b/fs/gfs2/aops.c +@@ -464,7 +464,7 @@ static int gfs2_read_folio(struct file *file, struct folio *folio) + error = mpage_read_folio(folio, gfs2_block_map); + } + +- if (unlikely(gfs2_withdrawn(sdp))) ++ if (gfs2_withdrawing_or_withdrawn(sdp)) + return -EIO; + + return error; +@@ -479,31 +479,29 @@ static int gfs2_read_folio(struct file *file, struct folio *folio) + * + */ + +-int gfs2_internal_read(struct gfs2_inode *ip, char *buf, loff_t *pos, +- unsigned size) ++ssize_t gfs2_internal_read(struct gfs2_inode *ip, char *buf, loff_t *pos, ++ size_t size) + { + struct address_space *mapping = ip->i_inode.i_mapping; + unsigned long index = *pos >> PAGE_SHIFT; +- unsigned offset = *pos & (PAGE_SIZE - 1); +- unsigned copied = 0; +- unsigned amt; +- struct page *page; ++ size_t copied = 0; + + do { +- page = read_cache_page(mapping, index, gfs2_read_folio, NULL); +- if (IS_ERR(page)) { +- if (PTR_ERR(page) == -EINTR) ++ size_t offset, chunk; ++ struct folio *folio; ++ ++ folio = read_cache_folio(mapping, index, gfs2_read_folio, NULL); ++ if (IS_ERR(folio)) { ++ if (PTR_ERR(folio) == -EINTR) + continue; +- return PTR_ERR(page); ++ return PTR_ERR(folio); + } +- amt = size - copied; +- if (offset + size > PAGE_SIZE) +- amt = PAGE_SIZE - offset; +- memcpy_from_page(buf + copied, page, offset, amt); +- put_page(page); +- copied += amt; +- index++; +- offset = 0; ++ offset = *pos + copied - folio_pos(folio); ++ chunk = min(size - copied, folio_size(folio) - offset); ++ memcpy_from_folio(buf + copied, folio, offset, chunk); ++ index = folio_next_index(folio); ++ folio_put(folio); ++ copied += chunk; + } while(copied < size); + (*pos) += size; + return size; +diff --git a/fs/gfs2/aops.h b/fs/gfs2/aops.h +index f08322ef41cfd..a10c4334d2489 100644 +--- a/fs/gfs2/aops.h ++++ b/fs/gfs2/aops.h +@@ -8,8 +8,8 @@ + + #include "incore.h" + +-extern void adjust_fs_space(struct inode *inode); +-extern void gfs2_trans_add_databufs(struct gfs2_inode *ip, struct folio *folio, +- size_t from, size_t len); ++void adjust_fs_space(struct inode *inode); ++void gfs2_trans_add_databufs(struct gfs2_inode *ip, struct folio *folio, ++ size_t from, size_t len); + + #endif /* __AOPS_DOT_H__ */ +diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c +index 2b578615607e4..7ed276a8f599d 100644 +--- a/fs/gfs2/bmap.c ++++ b/fs/gfs2/bmap.c +@@ -106,7 +106,7 @@ static int __gfs2_unstuff_inode(struct gfs2_inode *ip, struct page *page) + and write it out to disk */ + + unsigned int n = 1; +- error = gfs2_alloc_blocks(ip, &block, &n, 0, NULL); ++ error = gfs2_alloc_blocks(ip, &block, &n, 0); + if (error) + goto out_brelse; + if (isdir) { +@@ -702,7 +702,7 @@ static int __gfs2_iomap_alloc(struct inode *inode, struct iomap *iomap, + i = mp->mp_aheight; + do { + n = blks - alloced; +- ret = gfs2_alloc_blocks(ip, &bn, &n, 0, NULL); ++ ret = gfs2_alloc_blocks(ip, &bn, &n, 0); + if (ret) + goto out; + alloced += n; +diff --git a/fs/gfs2/bmap.h b/fs/gfs2/bmap.h +index e5b7d17131ed3..4e8b1e8ebdf39 100644 +--- a/fs/gfs2/bmap.h ++++ b/fs/gfs2/bmap.h +@@ -46,24 +46,24 @@ static inline void gfs2_write_calc_reserv(const struct gfs2_inode *ip, + extern const struct iomap_ops gfs2_iomap_ops; + extern const struct iomap_writeback_ops gfs2_writeback_ops; + +-extern int gfs2_unstuff_dinode(struct gfs2_inode *ip); +-extern int gfs2_block_map(struct inode *inode, sector_t lblock, +- struct buffer_head *bh, int create); +-extern int gfs2_iomap_get(struct inode *inode, loff_t pos, loff_t length, +- struct iomap *iomap); +-extern int gfs2_iomap_alloc(struct inode *inode, loff_t pos, loff_t length, +- struct iomap *iomap); +-extern int gfs2_get_extent(struct inode *inode, u64 lblock, u64 *dblock, +- unsigned int *extlen); +-extern int gfs2_alloc_extent(struct inode *inode, u64 lblock, u64 *dblock, +- unsigned *extlen, bool *new); +-extern int gfs2_setattr_size(struct inode *inode, u64 size); +-extern int gfs2_truncatei_resume(struct gfs2_inode *ip); +-extern int gfs2_file_dealloc(struct gfs2_inode *ip); +-extern int gfs2_write_alloc_required(struct gfs2_inode *ip, u64 offset, +- unsigned int len); +-extern int gfs2_map_journal_extents(struct gfs2_sbd *sdp, struct gfs2_jdesc *jd); +-extern void gfs2_free_journal_extents(struct gfs2_jdesc *jd); +-extern int __gfs2_punch_hole(struct file *file, loff_t offset, loff_t length); ++int gfs2_unstuff_dinode(struct gfs2_inode *ip); ++int gfs2_block_map(struct inode *inode, sector_t lblock, ++ struct buffer_head *bh, int create); ++int gfs2_iomap_get(struct inode *inode, loff_t pos, loff_t length, ++ struct iomap *iomap); ++int gfs2_iomap_alloc(struct inode *inode, loff_t pos, loff_t length, ++ struct iomap *iomap); ++int gfs2_get_extent(struct inode *inode, u64 lblock, u64 *dblock, ++ unsigned int *extlen); ++int gfs2_alloc_extent(struct inode *inode, u64 lblock, u64 *dblock, ++ unsigned *extlen, bool *new); ++int gfs2_setattr_size(struct inode *inode, u64 size); ++int gfs2_truncatei_resume(struct gfs2_inode *ip); ++int gfs2_file_dealloc(struct gfs2_inode *ip); ++int gfs2_write_alloc_required(struct gfs2_inode *ip, u64 offset, ++ unsigned int len); ++int gfs2_map_journal_extents(struct gfs2_sbd *sdp, struct gfs2_jdesc *jd); ++void gfs2_free_journal_extents(struct gfs2_jdesc *jd); ++int __gfs2_punch_hole(struct file *file, loff_t offset, loff_t length); + + #endif /* __BMAP_DOT_H__ */ +diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c +index 1a2afa88f8bea..3a2a10d6d43d1 100644 +--- a/fs/gfs2/dir.c ++++ b/fs/gfs2/dir.c +@@ -868,7 +868,7 @@ static struct gfs2_leaf *new_leaf(struct inode *inode, struct buffer_head **pbh, + struct gfs2_dirent *dent; + struct timespec64 tv = current_time(inode); + +- error = gfs2_alloc_blocks(ip, &bn, &n, 0, NULL); ++ error = gfs2_alloc_blocks(ip, &bn, &n, 0); + if (error) + return NULL; + bh = gfs2_meta_new(ip->i_gl, bn); +diff --git a/fs/gfs2/dir.h b/fs/gfs2/dir.h +index 5b76480c17c9e..25a857c78b538 100644 +--- a/fs/gfs2/dir.h ++++ b/fs/gfs2/dir.h +@@ -23,32 +23,32 @@ struct gfs2_diradd { + int save_loc; + }; + +-extern struct inode *gfs2_dir_search(struct inode *dir, +- const struct qstr *filename, +- bool fail_on_exist); +-extern int gfs2_dir_check(struct inode *dir, const struct qstr *filename, +- const struct gfs2_inode *ip); +-extern int gfs2_dir_add(struct inode *inode, const struct qstr *filename, +- const struct gfs2_inode *ip, struct gfs2_diradd *da); ++struct inode *gfs2_dir_search(struct inode *dir, ++ const struct qstr *filename, ++ bool fail_on_exist); ++int gfs2_dir_check(struct inode *dir, const struct qstr *filename, ++ const struct gfs2_inode *ip); ++int gfs2_dir_add(struct inode *inode, const struct qstr *filename, ++ const struct gfs2_inode *ip, struct gfs2_diradd *da); + static inline void gfs2_dir_no_add(struct gfs2_diradd *da) + { + brelse(da->bh); + da->bh = NULL; + } +-extern int gfs2_dir_del(struct gfs2_inode *dip, const struct dentry *dentry); +-extern int gfs2_dir_read(struct inode *inode, struct dir_context *ctx, +- struct file_ra_state *f_ra); +-extern int gfs2_dir_mvino(struct gfs2_inode *dip, const struct qstr *filename, +- const struct gfs2_inode *nip, unsigned int new_type); ++int gfs2_dir_del(struct gfs2_inode *dip, const struct dentry *dentry); ++int gfs2_dir_read(struct inode *inode, struct dir_context *ctx, ++ struct file_ra_state *f_ra); ++int gfs2_dir_mvino(struct gfs2_inode *dip, const struct qstr *filename, ++ const struct gfs2_inode *nip, unsigned int new_type); + +-extern int gfs2_dir_exhash_dealloc(struct gfs2_inode *dip); ++int gfs2_dir_exhash_dealloc(struct gfs2_inode *dip); + +-extern int gfs2_diradd_alloc_required(struct inode *dir, +- const struct qstr *filename, +- struct gfs2_diradd *da); +-extern int gfs2_dir_get_new_buffer(struct gfs2_inode *ip, u64 block, +- struct buffer_head **bhp); +-extern void gfs2_dir_hash_inval(struct gfs2_inode *ip); ++int gfs2_diradd_alloc_required(struct inode *dir, ++ const struct qstr *filename, ++ struct gfs2_diradd *da); ++int gfs2_dir_get_new_buffer(struct gfs2_inode *ip, u64 block, ++ struct buffer_head **bhp); ++void gfs2_dir_hash_inval(struct gfs2_inode *ip); + + static inline u32 gfs2_disk_hash(const char *data, int len) + { +diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c +index f2700477a3001..9296e0e282bcd 100644 +--- a/fs/gfs2/file.c ++++ b/fs/gfs2/file.c +@@ -1436,7 +1436,7 @@ static int gfs2_lock(struct file *file, int cmd, struct file_lock *fl) + + if (!(fl->fl_flags & FL_POSIX)) + return -ENOLCK; +- if (unlikely(gfs2_withdrawn(sdp))) { ++ if (gfs2_withdrawing_or_withdrawn(sdp)) { + if (fl->fl_type == F_UNLCK) + locks_lock_file_wait(file, fl); + return -EIO; +diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c +index 4a280be229a65..685e3ef9e9008 100644 +--- a/fs/gfs2/glock.c ++++ b/fs/gfs2/glock.c +@@ -156,7 +156,7 @@ static bool glock_blocked_by_withdraw(struct gfs2_glock *gl) + { + struct gfs2_sbd *sdp = gl->gl_name.ln_sbd; + +- if (likely(!gfs2_withdrawn(sdp))) ++ if (!gfs2_withdrawing_or_withdrawn(sdp)) + return false; + if (gl->gl_ops->go_flags & GLOF_NONDISK) + return false; +@@ -166,19 +166,45 @@ static bool glock_blocked_by_withdraw(struct gfs2_glock *gl) + return true; + } + +-void gfs2_glock_free(struct gfs2_glock *gl) ++static void __gfs2_glock_free(struct gfs2_glock *gl) + { +- struct gfs2_sbd *sdp = gl->gl_name.ln_sbd; +- +- gfs2_glock_assert_withdraw(gl, atomic_read(&gl->gl_revokes) == 0); + rhashtable_remove_fast(&gl_hash_table, &gl->gl_node, ht_parms); + smp_mb(); + wake_up_glock(gl); + call_rcu(&gl->gl_rcu, gfs2_glock_dealloc); ++} ++ ++void gfs2_glock_free(struct gfs2_glock *gl) { ++ struct gfs2_sbd *sdp = gl->gl_name.ln_sbd; ++ ++ __gfs2_glock_free(gl); ++ if (atomic_dec_and_test(&sdp->sd_glock_disposal)) ++ wake_up(&sdp->sd_kill_wait); ++} ++ ++void gfs2_glock_free_later(struct gfs2_glock *gl) { ++ struct gfs2_sbd *sdp = gl->gl_name.ln_sbd; ++ ++ spin_lock(&lru_lock); ++ list_add(&gl->gl_lru, &sdp->sd_dead_glocks); ++ spin_unlock(&lru_lock); + if (atomic_dec_and_test(&sdp->sd_glock_disposal)) + wake_up(&sdp->sd_kill_wait); + } + ++static void gfs2_free_dead_glocks(struct gfs2_sbd *sdp) ++{ ++ struct list_head *list = &sdp->sd_dead_glocks; ++ ++ while(!list_empty(list)) { ++ struct gfs2_glock *gl; ++ ++ gl = list_first_entry(list, struct gfs2_glock, gl_lru); ++ list_del_init(&gl->gl_lru); ++ __gfs2_glock_free(gl); ++ } ++} ++ + /** + * gfs2_glock_hold() - increment reference count on glock + * @gl: The glock to hold +@@ -278,7 +304,7 @@ static void __gfs2_glock_put(struct gfs2_glock *gl) + GLOCK_BUG_ON(gl, !list_empty(&gl->gl_holders)); + if (mapping) { + truncate_inode_pages_final(mapping); +- if (!gfs2_withdrawn(sdp)) ++ if (!gfs2_withdrawing_or_withdrawn(sdp)) + GLOCK_BUG_ON(gl, !mapping_empty(mapping)); + } + trace_gfs2_glock_put(gl); +@@ -574,7 +600,6 @@ static void finish_xmote(struct gfs2_glock *gl, unsigned int ret) + struct gfs2_holder *gh; + unsigned state = ret & LM_OUT_ST_MASK; + +- spin_lock(&gl->gl_lockref.lock); + trace_gfs2_glock_state_change(gl, state); + state_change(gl, state); + gh = find_first_waiter(gl); +@@ -622,7 +647,6 @@ static void finish_xmote(struct gfs2_glock *gl, unsigned int ret) + gl->gl_target, state); + GLOCK_BUG_ON(gl, 1); + } +- spin_unlock(&gl->gl_lockref.lock); + return; + } + +@@ -645,7 +669,6 @@ static void finish_xmote(struct gfs2_glock *gl, unsigned int ret) + } + out: + clear_bit(GLF_LOCK, &gl->gl_flags); +- spin_unlock(&gl->gl_lockref.lock); + } + + static bool is_system_glock(struct gfs2_glock *gl) +@@ -673,6 +696,7 @@ __acquires(&gl->gl_lockref.lock) + { + const struct gfs2_glock_operations *glops = gl->gl_ops; + struct gfs2_sbd *sdp = gl->gl_name.ln_sbd; ++ struct lm_lockstruct *ls = &sdp->sd_lockstruct; + unsigned int lck_flags = (unsigned int)(gh ? gh->gh_flags : 0); + int ret; + +@@ -701,6 +725,9 @@ __acquires(&gl->gl_lockref.lock) + (gl->gl_state == LM_ST_EXCLUSIVE) || + (lck_flags & (LM_FLAG_TRY|LM_FLAG_TRY_1CB))) + clear_bit(GLF_BLOCKING, &gl->gl_flags); ++ if (!glops->go_inval && !glops->go_sync) ++ goto skip_inval; ++ + spin_unlock(&gl->gl_lockref.lock); + if (glops->go_sync) { + ret = glops->go_sync(gl); +@@ -713,6 +740,7 @@ __acquires(&gl->gl_lockref.lock) + fs_err(sdp, "Error %d syncing glock \n", ret); + gfs2_dump_glock(NULL, gl, true); + } ++ spin_lock(&gl->gl_lockref.lock); + goto skip_inval; + } + } +@@ -733,9 +761,10 @@ __acquires(&gl->gl_lockref.lock) + glops->go_inval(gl, target == LM_ST_DEFERRED ? 0 : DIO_METADATA); + clear_bit(GLF_INVALIDATE_IN_PROGRESS, &gl->gl_flags); + } ++ spin_lock(&gl->gl_lockref.lock); + + skip_inval: +- gfs2_glock_hold(gl); ++ gl->gl_lockref.count++; + /* + * Check for an error encountered since we called go_sync and go_inval. + * If so, we can't withdraw from the glock code because the withdraw +@@ -757,7 +786,7 @@ __acquires(&gl->gl_lockref.lock) + * gfs2_gl_hash_clear calls clear_glock) and recovery is complete + * then it's okay to tell dlm to unlock it. + */ +- if (unlikely(sdp->sd_log_error && !gfs2_withdrawn(sdp))) ++ if (unlikely(sdp->sd_log_error) && !gfs2_withdrawing_or_withdrawn(sdp)) + gfs2_withdraw_delayed(sdp); + if (glock_blocked_by_withdraw(gl) && + (target != LM_ST_UNLOCKED || +@@ -777,31 +806,37 @@ __acquires(&gl->gl_lockref.lock) + */ + clear_bit(GLF_LOCK, &gl->gl_flags); + clear_bit(GLF_DEMOTE_IN_PROGRESS, &gl->gl_flags); +- gfs2_glock_queue_work(gl, GL_GLOCK_DFT_HOLD); +- goto out; ++ __gfs2_glock_queue_work(gl, GL_GLOCK_DFT_HOLD); ++ return; + } else { + clear_bit(GLF_INVALIDATE_IN_PROGRESS, &gl->gl_flags); + } + } + +- if (sdp->sd_lockstruct.ls_ops->lm_lock) { +- /* lock_dlm */ +- ret = sdp->sd_lockstruct.ls_ops->lm_lock(gl, target, lck_flags); ++ if (ls->ls_ops->lm_lock) { ++ spin_unlock(&gl->gl_lockref.lock); ++ ret = ls->ls_ops->lm_lock(gl, target, lck_flags); ++ spin_lock(&gl->gl_lockref.lock); ++ + if (ret == -EINVAL && gl->gl_target == LM_ST_UNLOCKED && + target == LM_ST_UNLOCKED && +- test_bit(SDF_SKIP_DLM_UNLOCK, &sdp->sd_flags)) { +- finish_xmote(gl, target); +- gfs2_glock_queue_work(gl, 0); ++ test_bit(DFL_UNMOUNT, &ls->ls_recover_flags)) { ++ /* ++ * The lockspace has been released and the lock has ++ * been unlocked implicitly. ++ */ + } else if (ret) { + fs_err(sdp, "lm_lock ret %d\n", ret); +- GLOCK_BUG_ON(gl, !gfs2_withdrawn(sdp)); ++ target = gl->gl_state | LM_OUT_ERROR; ++ } else { ++ /* The operation will be completed asynchronously. */ ++ return; + } +- } else { /* lock_nolock */ +- finish_xmote(gl, target); +- gfs2_glock_queue_work(gl, 0); + } +-out: +- spin_lock(&gl->gl_lockref.lock); ++ ++ /* Complete the operation now. */ ++ finish_xmote(gl, target); ++ __gfs2_glock_queue_work(gl, 0); + } + + /** +@@ -1054,11 +1089,12 @@ static void glock_work_func(struct work_struct *work) + struct gfs2_glock *gl = container_of(work, struct gfs2_glock, gl_work.work); + unsigned int drop_refs = 1; + +- if (test_and_clear_bit(GLF_REPLY_PENDING, &gl->gl_flags)) { ++ spin_lock(&gl->gl_lockref.lock); ++ if (test_bit(GLF_REPLY_PENDING, &gl->gl_flags)) { ++ clear_bit(GLF_REPLY_PENDING, &gl->gl_flags); + finish_xmote(gl, gl->gl_reply); + drop_refs++; + } +- spin_lock(&gl->gl_lockref.lock); + if (test_bit(GLF_PENDING_DEMOTE, &gl->gl_flags) && + gl->gl_state != LM_ST_UNLOCKED && + gl->gl_demote_state != LM_ST_EXCLUSIVE) { +@@ -2116,8 +2152,11 @@ static void thaw_glock(struct gfs2_glock *gl) + return; + if (!lockref_get_not_dead(&gl->gl_lockref)) + return; ++ ++ spin_lock(&gl->gl_lockref.lock); + set_bit(GLF_REPLY_PENDING, &gl->gl_flags); +- gfs2_glock_queue_work(gl, 0); ++ __gfs2_glock_queue_work(gl, 0); ++ spin_unlock(&gl->gl_lockref.lock); + } + + /** +@@ -2193,6 +2232,8 @@ void gfs2_gl_hash_clear(struct gfs2_sbd *sdp) + wait_event_timeout(sdp->sd_kill_wait, + atomic_read(&sdp->sd_glock_disposal) == 0, + HZ * 600); ++ gfs2_lm_unmount(sdp); ++ gfs2_free_dead_glocks(sdp); + glock_hash_walk(dump_glock_func, sdp); + } + +diff --git a/fs/gfs2/glock.h b/fs/gfs2/glock.h +index c8685ca7d2a26..f7ee9ca948eee 100644 +--- a/fs/gfs2/glock.h ++++ b/fs/gfs2/glock.h +@@ -181,40 +181,40 @@ static inline struct address_space *gfs2_glock2aspace(struct gfs2_glock *gl) + return NULL; + } + +-extern int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number, +- const struct gfs2_glock_operations *glops, +- int create, struct gfs2_glock **glp); +-extern struct gfs2_glock *gfs2_glock_hold(struct gfs2_glock *gl); +-extern void gfs2_glock_put(struct gfs2_glock *gl); +-extern void gfs2_glock_queue_put(struct gfs2_glock *gl); +- +-extern void __gfs2_holder_init(struct gfs2_glock *gl, unsigned int state, +- u16 flags, struct gfs2_holder *gh, +- unsigned long ip); ++int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number, ++ const struct gfs2_glock_operations *glops, ++ int create, struct gfs2_glock **glp); ++struct gfs2_glock *gfs2_glock_hold(struct gfs2_glock *gl); ++void gfs2_glock_put(struct gfs2_glock *gl); ++void gfs2_glock_queue_put(struct gfs2_glock *gl); ++ ++void __gfs2_holder_init(struct gfs2_glock *gl, unsigned int state, ++ u16 flags, struct gfs2_holder *gh, ++ unsigned long ip); + static inline void gfs2_holder_init(struct gfs2_glock *gl, unsigned int state, + u16 flags, struct gfs2_holder *gh) { + __gfs2_holder_init(gl, state, flags, gh, _RET_IP_); + } + +-extern void gfs2_holder_reinit(unsigned int state, u16 flags, +- struct gfs2_holder *gh); +-extern void gfs2_holder_uninit(struct gfs2_holder *gh); +-extern int gfs2_glock_nq(struct gfs2_holder *gh); +-extern int gfs2_glock_poll(struct gfs2_holder *gh); +-extern int gfs2_instantiate(struct gfs2_holder *gh); +-extern int gfs2_glock_holder_ready(struct gfs2_holder *gh); +-extern int gfs2_glock_wait(struct gfs2_holder *gh); +-extern int gfs2_glock_async_wait(unsigned int num_gh, struct gfs2_holder *ghs); +-extern void gfs2_glock_dq(struct gfs2_holder *gh); +-extern void gfs2_glock_dq_wait(struct gfs2_holder *gh); +-extern void gfs2_glock_dq_uninit(struct gfs2_holder *gh); +-extern int gfs2_glock_nq_num(struct gfs2_sbd *sdp, u64 number, +- const struct gfs2_glock_operations *glops, +- unsigned int state, u16 flags, +- struct gfs2_holder *gh); +-extern int gfs2_glock_nq_m(unsigned int num_gh, struct gfs2_holder *ghs); +-extern void gfs2_glock_dq_m(unsigned int num_gh, struct gfs2_holder *ghs); +-extern void gfs2_dump_glock(struct seq_file *seq, struct gfs2_glock *gl, ++void gfs2_holder_reinit(unsigned int state, u16 flags, ++ struct gfs2_holder *gh); ++void gfs2_holder_uninit(struct gfs2_holder *gh); ++int gfs2_glock_nq(struct gfs2_holder *gh); ++int gfs2_glock_poll(struct gfs2_holder *gh); ++int gfs2_instantiate(struct gfs2_holder *gh); ++int gfs2_glock_holder_ready(struct gfs2_holder *gh); ++int gfs2_glock_wait(struct gfs2_holder *gh); ++int gfs2_glock_async_wait(unsigned int num_gh, struct gfs2_holder *ghs); ++void gfs2_glock_dq(struct gfs2_holder *gh); ++void gfs2_glock_dq_wait(struct gfs2_holder *gh); ++void gfs2_glock_dq_uninit(struct gfs2_holder *gh); ++int gfs2_glock_nq_num(struct gfs2_sbd *sdp, u64 number, ++ const struct gfs2_glock_operations *glops, ++ unsigned int state, u16 flags, ++ struct gfs2_holder *gh); ++int gfs2_glock_nq_m(unsigned int num_gh, struct gfs2_holder *ghs); ++void gfs2_glock_dq_m(unsigned int num_gh, struct gfs2_holder *ghs); ++void gfs2_dump_glock(struct seq_file *seq, struct gfs2_glock *gl, + bool fsid); + #define GLOCK_BUG_ON(gl,x) do { if (unlikely(x)) { \ + gfs2_dump_glock(NULL, gl, true); \ +@@ -228,7 +228,7 @@ extern void gfs2_dump_glock(struct seq_file *seq, struct gfs2_glock *gl, + gfs2_assert_withdraw((gl)->gl_name.ln_sbd, (x)); } } \ + while (0) + +-extern __printf(2, 3) ++__printf(2, 3) + void gfs2_print_dbg(struct seq_file *seq, const char *fmt, ...); + + /** +@@ -256,27 +256,28 @@ static inline int gfs2_glock_nq_init(struct gfs2_glock *gl, + return error; + } + +-extern void gfs2_glock_cb(struct gfs2_glock *gl, unsigned int state); +-extern void gfs2_glock_complete(struct gfs2_glock *gl, int ret); +-extern bool gfs2_queue_try_to_evict(struct gfs2_glock *gl); +-extern void gfs2_cancel_delete_work(struct gfs2_glock *gl); +-extern void gfs2_flush_delete_work(struct gfs2_sbd *sdp); +-extern void gfs2_gl_hash_clear(struct gfs2_sbd *sdp); +-extern void gfs2_gl_dq_holders(struct gfs2_sbd *sdp); +-extern void gfs2_glock_thaw(struct gfs2_sbd *sdp); +-extern void gfs2_glock_add_to_lru(struct gfs2_glock *gl); +-extern void gfs2_glock_free(struct gfs2_glock *gl); +- +-extern int __init gfs2_glock_init(void); +-extern void gfs2_glock_exit(void); +- +-extern void gfs2_create_debugfs_file(struct gfs2_sbd *sdp); +-extern void gfs2_delete_debugfs_file(struct gfs2_sbd *sdp); +-extern void gfs2_register_debugfs(void); +-extern void gfs2_unregister_debugfs(void); +- +-extern void glock_set_object(struct gfs2_glock *gl, void *object); +-extern void glock_clear_object(struct gfs2_glock *gl, void *object); ++void gfs2_glock_cb(struct gfs2_glock *gl, unsigned int state); ++void gfs2_glock_complete(struct gfs2_glock *gl, int ret); ++bool gfs2_queue_try_to_evict(struct gfs2_glock *gl); ++void gfs2_cancel_delete_work(struct gfs2_glock *gl); ++void gfs2_flush_delete_work(struct gfs2_sbd *sdp); ++void gfs2_gl_hash_clear(struct gfs2_sbd *sdp); ++void gfs2_gl_dq_holders(struct gfs2_sbd *sdp); ++void gfs2_glock_thaw(struct gfs2_sbd *sdp); ++void gfs2_glock_add_to_lru(struct gfs2_glock *gl); ++void gfs2_glock_free(struct gfs2_glock *gl); ++void gfs2_glock_free_later(struct gfs2_glock *gl); ++ ++int __init gfs2_glock_init(void); ++void gfs2_glock_exit(void); ++ ++void gfs2_create_debugfs_file(struct gfs2_sbd *sdp); ++void gfs2_delete_debugfs_file(struct gfs2_sbd *sdp); ++void gfs2_register_debugfs(void); ++void gfs2_unregister_debugfs(void); ++ ++void glock_set_object(struct gfs2_glock *gl, void *object); ++void glock_clear_object(struct gfs2_glock *gl, void *object); + + extern const struct lm_lockops gfs2_dlm_ops; + +@@ -295,7 +296,7 @@ static inline bool gfs2_holder_queued(struct gfs2_holder *gh) + return !list_empty(&gh->gh_list); + } + +-extern void gfs2_inode_remember_delete(struct gfs2_glock *gl, u64 generation); +-extern bool gfs2_inode_already_deleted(struct gfs2_glock *gl, u64 generation); ++void gfs2_inode_remember_delete(struct gfs2_glock *gl, u64 generation); ++bool gfs2_inode_already_deleted(struct gfs2_glock *gl, u64 generation); + + #endif /* __GLOCK_DOT_H__ */ +diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c +index f41ca89d216bc..1c854d4e2d491 100644 +--- a/fs/gfs2/glops.c ++++ b/fs/gfs2/glops.c +@@ -82,6 +82,9 @@ static void __gfs2_ail_flush(struct gfs2_glock *gl, bool fsync, + GLOCK_BUG_ON(gl, !fsync && atomic_read(&gl->gl_ail_count)); + spin_unlock(&sdp->sd_ail_lock); + gfs2_log_unlock(sdp); ++ ++ if (gfs2_withdrawing(sdp)) ++ gfs2_withdraw(sdp); + } + + +@@ -174,7 +177,7 @@ static int gfs2_rgrp_metasync(struct gfs2_glock *gl) + + filemap_fdatawrite_range(metamapping, start, end); + error = filemap_fdatawait_range(metamapping, start, end); +- WARN_ON_ONCE(error && !gfs2_withdrawn(sdp)); ++ WARN_ON_ONCE(error && !gfs2_withdrawing_or_withdrawn(sdp)); + mapping_set_error(metamapping, error); + if (error) + gfs2_io_error(sdp); +diff --git a/fs/gfs2/glops.h b/fs/gfs2/glops.h +index 695898afcaf1f..9341423798df8 100644 +--- a/fs/gfs2/glops.h ++++ b/fs/gfs2/glops.h +@@ -22,7 +22,7 @@ extern const struct gfs2_glock_operations gfs2_quota_glops; + extern const struct gfs2_glock_operations gfs2_journal_glops; + extern const struct gfs2_glock_operations *gfs2_glops_list[]; + +-extern int gfs2_inode_metasync(struct gfs2_glock *gl); +-extern void gfs2_ail_flush(struct gfs2_glock *gl, bool fsync); ++int gfs2_inode_metasync(struct gfs2_glock *gl); ++void gfs2_ail_flush(struct gfs2_glock *gl, bool fsync); + + #endif /* __GLOPS_DOT_H__ */ +diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h +index a8c95c5293c6c..60abd7050c998 100644 +--- a/fs/gfs2/incore.h ++++ b/fs/gfs2/incore.h +@@ -838,6 +838,7 @@ struct gfs2_sbd { + /* For quiescing the filesystem */ + struct gfs2_holder sd_freeze_gh; + struct mutex sd_freeze_mutex; ++ struct list_head sd_dead_glocks; + + char sd_fsname[GFS2_FSNAME_LEN + 3 * sizeof(int) + 2]; + char sd_table_name[GFS2_FSNAME_LEN]; +@@ -863,7 +864,7 @@ static inline void gfs2_sbstats_inc(const struct gfs2_glock *gl, int which) + preempt_enable(); + } + +-extern struct gfs2_rgrpd *gfs2_glock2rgrp(struct gfs2_glock *gl); ++struct gfs2_rgrpd *gfs2_glock2rgrp(struct gfs2_glock *gl); + + static inline unsigned gfs2_max_stuffed_size(const struct gfs2_inode *ip) + { +diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c +index 4e63fbb63151c..3de0d8ab42eaf 100644 +--- a/fs/gfs2/inode.c ++++ b/fs/gfs2/inode.c +@@ -265,17 +265,18 @@ struct inode *gfs2_lookup_by_inum(struct gfs2_sbd *sdp, u64 no_addr, + } + + +-struct inode *gfs2_lookup_simple(struct inode *dip, const char *name) ++/** ++ * gfs2_lookup_meta - Look up an inode in a metadata directory ++ * @dip: The directory ++ * @name: The name of the inode ++ */ ++struct inode *gfs2_lookup_meta(struct inode *dip, const char *name) + { + struct qstr qstr; + struct inode *inode; ++ + gfs2_str2qstr(&qstr, name); + inode = gfs2_lookupi(dip, &qstr, 1); +- /* gfs2_lookupi has inconsistent callers: vfs +- * related routines expect NULL for no entry found, +- * gfs2_lookup_simple callers expect ENOENT +- * and do not check for NULL. +- */ + if (IS_ERR_OR_NULL(inode)) + return inode ? inode : ERR_PTR(-ENOENT); + +@@ -417,7 +418,7 @@ static int alloc_dinode(struct gfs2_inode *ip, u32 flags, unsigned *dblocks) + if (error) + goto out_ipreserv; + +- error = gfs2_alloc_blocks(ip, &ip->i_no_addr, dblocks, 1, &ip->i_generation); ++ error = gfs2_alloc_blocks(ip, &ip->i_no_addr, dblocks, 1); + if (error) + goto out_trans_end; + +diff --git a/fs/gfs2/inode.h b/fs/gfs2/inode.h +index c8c5814e7295d..ce70cf26b497d 100644 +--- a/fs/gfs2/inode.h ++++ b/fs/gfs2/inode.h +@@ -13,9 +13,9 @@ + #include "util.h" + + bool gfs2_release_folio(struct folio *folio, gfp_t gfp_mask); +-extern int gfs2_internal_read(struct gfs2_inode *ip, +- char *buf, loff_t *pos, unsigned size); +-extern void gfs2_set_aops(struct inode *inode); ++ssize_t gfs2_internal_read(struct gfs2_inode *ip, ++ char *buf, loff_t *pos, size_t size); ++void gfs2_set_aops(struct inode *inode); + + static inline int gfs2_is_stuffed(const struct gfs2_inode *ip) + { +@@ -88,33 +88,33 @@ static inline int gfs2_check_internal_file_size(struct inode *inode, + return -EIO; + } + +-extern struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned type, +- u64 no_addr, u64 no_formal_ino, +- unsigned int blktype); +-extern struct inode *gfs2_lookup_by_inum(struct gfs2_sbd *sdp, u64 no_addr, +- u64 no_formal_ino, +- unsigned int blktype); +- +-extern int gfs2_inode_refresh(struct gfs2_inode *ip); +- +-extern struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name, +- int is_root); +-extern int gfs2_permission(struct mnt_idmap *idmap, +- struct inode *inode, int mask); +-extern struct inode *gfs2_lookup_simple(struct inode *dip, const char *name); +-extern void gfs2_dinode_out(const struct gfs2_inode *ip, void *buf); +-extern int gfs2_open_common(struct inode *inode, struct file *file); +-extern loff_t gfs2_seek_data(struct file *file, loff_t offset); +-extern loff_t gfs2_seek_hole(struct file *file, loff_t offset); ++struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned type, ++ u64 no_addr, u64 no_formal_ino, ++ unsigned int blktype); ++struct inode *gfs2_lookup_by_inum(struct gfs2_sbd *sdp, u64 no_addr, ++ u64 no_formal_ino, ++ unsigned int blktype); ++ ++int gfs2_inode_refresh(struct gfs2_inode *ip); ++ ++struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name, ++ int is_root); ++int gfs2_permission(struct mnt_idmap *idmap, ++ struct inode *inode, int mask); ++struct inode *gfs2_lookup_meta(struct inode *dip, const char *name); ++void gfs2_dinode_out(const struct gfs2_inode *ip, void *buf); ++int gfs2_open_common(struct inode *inode, struct file *file); ++loff_t gfs2_seek_data(struct file *file, loff_t offset); ++loff_t gfs2_seek_hole(struct file *file, loff_t offset); + + extern const struct file_operations gfs2_file_fops_nolock; + extern const struct file_operations gfs2_dir_fops_nolock; + +-extern int gfs2_fileattr_get(struct dentry *dentry, struct fileattr *fa); +-extern int gfs2_fileattr_set(struct mnt_idmap *idmap, +- struct dentry *dentry, struct fileattr *fa); +-extern void gfs2_set_inode_flags(struct inode *inode); +- ++int gfs2_fileattr_get(struct dentry *dentry, struct fileattr *fa); ++int gfs2_fileattr_set(struct mnt_idmap *idmap, ++ struct dentry *dentry, struct fileattr *fa); ++void gfs2_set_inode_flags(struct inode *inode); ++ + #ifdef CONFIG_GFS2_FS_LOCKING_DLM + extern const struct file_operations gfs2_file_fops; + extern const struct file_operations gfs2_dir_fops; +diff --git a/fs/gfs2/lock_dlm.c b/fs/gfs2/lock_dlm.c +index 59ab18c798890..e028e55e67d95 100644 +--- a/fs/gfs2/lock_dlm.c ++++ b/fs/gfs2/lock_dlm.c +@@ -121,6 +121,11 @@ static void gdlm_ast(void *arg) + struct gfs2_glock *gl = arg; + unsigned ret = gl->gl_state; + ++ /* If the glock is dead, we only react to a dlm_unlock() reply. */ ++ if (__lockref_is_dead(&gl->gl_lockref) && ++ gl->gl_lksb.sb_status != -DLM_EUNLOCK) ++ return; ++ + gfs2_update_reply_times(gl); + BUG_ON(gl->gl_lksb.sb_flags & DLM_SBF_DEMOTED); + +@@ -171,6 +176,9 @@ static void gdlm_bast(void *arg, int mode) + { + struct gfs2_glock *gl = arg; + ++ if (__lockref_is_dead(&gl->gl_lockref)) ++ return; ++ + switch (mode) { + case DLM_LOCK_EX: + gfs2_glock_cb(gl, LM_ST_UNLOCKED); +@@ -291,8 +299,12 @@ static void gdlm_put_lock(struct gfs2_glock *gl) + struct lm_lockstruct *ls = &sdp->sd_lockstruct; + int error; + +- if (gl->gl_lksb.sb_lkid == 0) +- goto out_free; ++ BUG_ON(!__lockref_is_dead(&gl->gl_lockref)); ++ ++ if (gl->gl_lksb.sb_lkid == 0) { ++ gfs2_glock_free(gl); ++ return; ++ } + + clear_bit(GLF_BLOCKING, &gl->gl_flags); + gfs2_glstats_inc(gl, GFS2_LKS_DCOUNT); +@@ -300,13 +312,17 @@ static void gdlm_put_lock(struct gfs2_glock *gl) + gfs2_update_request_times(gl); + + /* don't want to call dlm if we've unmounted the lock protocol */ +- if (test_bit(DFL_UNMOUNT, &ls->ls_recover_flags)) +- goto out_free; ++ if (test_bit(DFL_UNMOUNT, &ls->ls_recover_flags)) { ++ gfs2_glock_free(gl); ++ return; ++ } + /* don't want to skip dlm_unlock writing the lvb when lock has one */ + + if (test_bit(SDF_SKIP_DLM_UNLOCK, &sdp->sd_flags) && +- !gl->gl_lksb.sb_lvbptr) +- goto out_free; ++ !gl->gl_lksb.sb_lvbptr) { ++ gfs2_glock_free_later(gl); ++ return; ++ } + + again: + error = dlm_unlock(ls->ls_dlm, gl->gl_lksb.sb_lkid, DLM_LKF_VALBLK, +@@ -321,10 +337,6 @@ static void gdlm_put_lock(struct gfs2_glock *gl) + gl->gl_name.ln_type, + (unsigned long long)gl->gl_name.ln_number, error); + } +- return; +- +-out_free: +- gfs2_glock_free(gl); + } + + static void gdlm_cancel(struct gfs2_glock *gl) +@@ -1122,7 +1134,7 @@ static void gdlm_recover_prep(void *arg) + struct gfs2_sbd *sdp = arg; + struct lm_lockstruct *ls = &sdp->sd_lockstruct; + +- if (gfs2_withdrawn(sdp)) { ++ if (gfs2_withdrawing_or_withdrawn(sdp)) { + fs_err(sdp, "recover_prep ignored due to withdraw.\n"); + return; + } +@@ -1148,7 +1160,7 @@ static void gdlm_recover_slot(void *arg, struct dlm_slot *slot) + struct lm_lockstruct *ls = &sdp->sd_lockstruct; + int jid = slot->slot - 1; + +- if (gfs2_withdrawn(sdp)) { ++ if (gfs2_withdrawing_or_withdrawn(sdp)) { + fs_err(sdp, "recover_slot jid %d ignored due to withdraw.\n", + jid); + return; +@@ -1177,7 +1189,7 @@ static void gdlm_recover_done(void *arg, struct dlm_slot *slots, int num_slots, + struct gfs2_sbd *sdp = arg; + struct lm_lockstruct *ls = &sdp->sd_lockstruct; + +- if (gfs2_withdrawn(sdp)) { ++ if (gfs2_withdrawing_or_withdrawn(sdp)) { + fs_err(sdp, "recover_done ignored due to withdraw.\n"); + return; + } +@@ -1208,7 +1220,7 @@ static void gdlm_recovery_result(struct gfs2_sbd *sdp, unsigned int jid, + { + struct lm_lockstruct *ls = &sdp->sd_lockstruct; + +- if (gfs2_withdrawn(sdp)) { ++ if (gfs2_withdrawing_or_withdrawn(sdp)) { + fs_err(sdp, "recovery_result jid %d ignored due to withdraw.\n", + jid); + return; +diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c +index e5271ae87d1c4..88bc9b1b22650 100644 +--- a/fs/gfs2/log.c ++++ b/fs/gfs2/log.c +@@ -126,7 +126,7 @@ __acquires(&sdp->sd_ail_lock) + } + } + +- if (gfs2_withdrawn(sdp)) { ++ if (gfs2_withdrawing_or_withdrawn(sdp)) { + gfs2_remove_from_ail(bd); + continue; + } +@@ -841,7 +841,7 @@ void gfs2_write_log_header(struct gfs2_sbd *sdp, struct gfs2_jdesc *jd, + struct super_block *sb = sdp->sd_vfs; + u64 dblock; + +- if (gfs2_withdrawn(sdp)) ++ if (gfs2_withdrawing_or_withdrawn(sdp)) + return; + + page = mempool_alloc(gfs2_page_pool, GFP_NOIO); +@@ -1047,7 +1047,8 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, u32 flags) + * Do this check while holding the log_flush_lock to prevent new + * buffers from being added to the ail via gfs2_pin() + */ +- if (gfs2_withdrawn(sdp) || !test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags)) ++ if (gfs2_withdrawing_or_withdrawn(sdp) || ++ !test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags)) + goto out; + + /* Log might have been flushed while we waited for the flush lock */ +@@ -1096,13 +1097,13 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, u32 flags) + goto out_withdraw; + + gfs2_ordered_write(sdp); +- if (gfs2_withdrawn(sdp)) ++ if (gfs2_withdrawing_or_withdrawn(sdp)) + goto out_withdraw; + lops_before_commit(sdp, tr); +- if (gfs2_withdrawn(sdp)) ++ if (gfs2_withdrawing_or_withdrawn(sdp)) + goto out_withdraw; + gfs2_log_submit_bio(&sdp->sd_jdesc->jd_log_bio, REQ_OP_WRITE); +- if (gfs2_withdrawn(sdp)) ++ if (gfs2_withdrawing_or_withdrawn(sdp)) + goto out_withdraw; + + if (sdp->sd_log_head != sdp->sd_log_flush_head) { +@@ -1110,7 +1111,7 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, u32 flags) + } else if (sdp->sd_log_tail != sdp->sd_log_flush_tail && !sdp->sd_log_idle) { + log_write_header(sdp, flags); + } +- if (gfs2_withdrawn(sdp)) ++ if (gfs2_withdrawing_or_withdrawn(sdp)) + goto out_withdraw; + lops_after_commit(sdp, tr); + +@@ -1128,7 +1129,7 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, u32 flags) + if (!(flags & GFS2_LOG_HEAD_FLUSH_NORMAL)) { + if (!sdp->sd_log_idle) { + empty_ail1_list(sdp); +- if (gfs2_withdrawn(sdp)) ++ if (gfs2_withdrawing_or_withdrawn(sdp)) + goto out_withdraw; + log_write_header(sdp, flags); + } +@@ -1298,7 +1299,7 @@ int gfs2_logd(void *data) + unsigned long t = 1; + + while (!kthread_should_stop()) { +- if (gfs2_withdrawn(sdp)) ++ if (gfs2_withdrawing_or_withdrawn(sdp)) + break; + + /* Check for errors writing to the journal */ +@@ -1337,7 +1338,7 @@ int gfs2_logd(void *data) + gfs2_ail_flush_reqd(sdp) || + gfs2_jrnl_flush_reqd(sdp) || + sdp->sd_log_error || +- gfs2_withdrawn(sdp) || ++ gfs2_withdrawing_or_withdrawn(sdp) || + kthread_should_stop(), + t); + } +diff --git a/fs/gfs2/log.h b/fs/gfs2/log.h +index 653cffcbf8694..c27b05099c1e4 100644 +--- a/fs/gfs2/log.h ++++ b/fs/gfs2/log.h +@@ -70,29 +70,29 @@ static inline void gfs2_ordered_add_inode(struct gfs2_inode *ip) + } + } + +-extern void gfs2_ordered_del_inode(struct gfs2_inode *ip); +-extern unsigned int gfs2_struct2blk(struct gfs2_sbd *sdp, unsigned int nstruct); +-extern void gfs2_remove_from_ail(struct gfs2_bufdata *bd); +-extern bool gfs2_log_is_empty(struct gfs2_sbd *sdp); +-extern void gfs2_log_release_revokes(struct gfs2_sbd *sdp, unsigned int revokes); +-extern void gfs2_log_release(struct gfs2_sbd *sdp, unsigned int blks); +-extern bool gfs2_log_try_reserve(struct gfs2_sbd *sdp, struct gfs2_trans *tr, +- unsigned int *extra_revokes); +-extern void gfs2_log_reserve(struct gfs2_sbd *sdp, struct gfs2_trans *tr, +- unsigned int *extra_revokes); +-extern void gfs2_write_log_header(struct gfs2_sbd *sdp, struct gfs2_jdesc *jd, +- u64 seq, u32 tail, u32 lblock, u32 flags, +- blk_opf_t op_flags); +-extern void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, +- u32 type); +-extern void gfs2_log_commit(struct gfs2_sbd *sdp, struct gfs2_trans *trans); +-extern void gfs2_ail1_flush(struct gfs2_sbd *sdp, struct writeback_control *wbc); +-extern void log_flush_wait(struct gfs2_sbd *sdp); ++void gfs2_ordered_del_inode(struct gfs2_inode *ip); ++unsigned int gfs2_struct2blk(struct gfs2_sbd *sdp, unsigned int nstruct); ++void gfs2_remove_from_ail(struct gfs2_bufdata *bd); ++bool gfs2_log_is_empty(struct gfs2_sbd *sdp); ++void gfs2_log_release_revokes(struct gfs2_sbd *sdp, unsigned int revokes); ++void gfs2_log_release(struct gfs2_sbd *sdp, unsigned int blks); ++bool gfs2_log_try_reserve(struct gfs2_sbd *sdp, struct gfs2_trans *tr, ++ unsigned int *extra_revokes); ++void gfs2_log_reserve(struct gfs2_sbd *sdp, struct gfs2_trans *tr, ++ unsigned int *extra_revokes); ++void gfs2_write_log_header(struct gfs2_sbd *sdp, struct gfs2_jdesc *jd, ++ u64 seq, u32 tail, u32 lblock, u32 flags, ++ blk_opf_t op_flags); ++void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, ++ u32 type); ++void gfs2_log_commit(struct gfs2_sbd *sdp, struct gfs2_trans *trans); ++void gfs2_ail1_flush(struct gfs2_sbd *sdp, struct writeback_control *wbc); ++void log_flush_wait(struct gfs2_sbd *sdp); + +-extern int gfs2_logd(void *data); +-extern void gfs2_add_revoke(struct gfs2_sbd *sdp, struct gfs2_bufdata *bd); +-extern void gfs2_glock_remove_revoke(struct gfs2_glock *gl); +-extern void gfs2_flush_revokes(struct gfs2_sbd *sdp); +-extern void gfs2_ail_drain(struct gfs2_sbd *sdp); ++int gfs2_logd(void *data); ++void gfs2_add_revoke(struct gfs2_sbd *sdp, struct gfs2_bufdata *bd); ++void gfs2_glock_remove_revoke(struct gfs2_glock *gl); ++void gfs2_flush_revokes(struct gfs2_sbd *sdp); ++void gfs2_ail_drain(struct gfs2_sbd *sdp); + + #endif /* __LOG_DOT_H__ */ +diff --git a/fs/gfs2/lops.h b/fs/gfs2/lops.h +index 1412ffba1d444..07890c7b145d8 100644 +--- a/fs/gfs2/lops.h ++++ b/fs/gfs2/lops.h +@@ -11,16 +11,18 @@ + #include "incore.h" + + extern const struct gfs2_log_operations *gfs2_log_ops[]; +-extern void gfs2_log_incr_head(struct gfs2_sbd *sdp); +-extern u64 gfs2_log_bmap(struct gfs2_jdesc *jd, unsigned int lbn); +-extern void gfs2_log_write(struct gfs2_sbd *sdp, struct gfs2_jdesc *jd, +- struct page *page, unsigned size, unsigned offset, +- u64 blkno); +-extern void gfs2_log_submit_bio(struct bio **biop, blk_opf_t opf); +-extern void gfs2_pin(struct gfs2_sbd *sdp, struct buffer_head *bh); +-extern int gfs2_find_jhead(struct gfs2_jdesc *jd, +- struct gfs2_log_header_host *head, bool keep_cache); +-extern void gfs2_drain_revokes(struct gfs2_sbd *sdp); ++ ++void gfs2_log_incr_head(struct gfs2_sbd *sdp); ++u64 gfs2_log_bmap(struct gfs2_jdesc *jd, unsigned int lbn); ++void gfs2_log_write(struct gfs2_sbd *sdp, struct gfs2_jdesc *jd, ++ struct page *page, unsigned size, unsigned offset, ++ u64 blkno); ++void gfs2_log_submit_bio(struct bio **biop, blk_opf_t opf); ++void gfs2_pin(struct gfs2_sbd *sdp, struct buffer_head *bh); ++int gfs2_find_jhead(struct gfs2_jdesc *jd, ++ struct gfs2_log_header_host *head, bool keep_cache); ++void gfs2_drain_revokes(struct gfs2_sbd *sdp); ++ + static inline unsigned int buf_limit(struct gfs2_sbd *sdp) + { + return sdp->sd_ldptrs; +diff --git a/fs/gfs2/meta_io.c b/fs/gfs2/meta_io.c +index 924361fa510b1..1f42eae112fb8 100644 +--- a/fs/gfs2/meta_io.c ++++ b/fs/gfs2/meta_io.c +@@ -257,7 +257,8 @@ int gfs2_meta_read(struct gfs2_glock *gl, u64 blkno, int flags, + struct buffer_head *bh, *bhs[2]; + int num = 0; + +- if (unlikely(gfs2_withdrawn(sdp)) && !gfs2_withdraw_in_prog(sdp)) { ++ if (gfs2_withdrawing_or_withdrawn(sdp) && ++ !gfs2_withdraw_in_prog(sdp)) { + *bhp = NULL; + return -EIO; + } +@@ -315,7 +316,8 @@ int gfs2_meta_read(struct gfs2_glock *gl, u64 blkno, int flags, + + int gfs2_meta_wait(struct gfs2_sbd *sdp, struct buffer_head *bh) + { +- if (unlikely(gfs2_withdrawn(sdp)) && !gfs2_withdraw_in_prog(sdp)) ++ if (gfs2_withdrawing_or_withdrawn(sdp) && ++ !gfs2_withdraw_in_prog(sdp)) + return -EIO; + + wait_on_buffer(bh); +@@ -326,7 +328,8 @@ int gfs2_meta_wait(struct gfs2_sbd *sdp, struct buffer_head *bh) + gfs2_io_error_bh_wd(sdp, bh); + return -EIO; + } +- if (unlikely(gfs2_withdrawn(sdp)) && !gfs2_withdraw_in_prog(sdp)) ++ if (gfs2_withdrawing_or_withdrawn(sdp) && ++ !gfs2_withdraw_in_prog(sdp)) + return -EIO; + + return 0; +diff --git a/fs/gfs2/meta_io.h b/fs/gfs2/meta_io.h +index d0a58cdd433a9..831d988c2ceb7 100644 +--- a/fs/gfs2/meta_io.h ++++ b/fs/gfs2/meta_io.h +@@ -50,21 +50,21 @@ static inline struct gfs2_sbd *gfs2_mapping2sbd(struct address_space *mapping) + return inode->i_sb->s_fs_info; + } + +-extern struct buffer_head *gfs2_meta_new(struct gfs2_glock *gl, u64 blkno); +-extern int gfs2_meta_read(struct gfs2_glock *gl, u64 blkno, int flags, +- int rahead, struct buffer_head **bhp); +-extern int gfs2_meta_wait(struct gfs2_sbd *sdp, struct buffer_head *bh); +-extern struct buffer_head *gfs2_getbuf(struct gfs2_glock *gl, u64 blkno, +- int create); ++struct buffer_head *gfs2_meta_new(struct gfs2_glock *gl, u64 blkno); ++int gfs2_meta_read(struct gfs2_glock *gl, u64 blkno, int flags, ++ int rahead, struct buffer_head **bhp); ++int gfs2_meta_wait(struct gfs2_sbd *sdp, struct buffer_head *bh); ++struct buffer_head *gfs2_getbuf(struct gfs2_glock *gl, u64 blkno, ++ int create); + enum { + REMOVE_JDATA = 0, + REMOVE_META = 1, + }; + +-extern void gfs2_remove_from_journal(struct buffer_head *bh, int meta); +-extern void gfs2_journal_wipe(struct gfs2_inode *ip, u64 bstart, u32 blen); +-extern int gfs2_meta_buffer(struct gfs2_inode *ip, u32 mtype, u64 num, +- struct buffer_head **bhp); ++void gfs2_remove_from_journal(struct buffer_head *bh, int meta); ++void gfs2_journal_wipe(struct gfs2_inode *ip, u64 bstart, u32 blen); ++int gfs2_meta_buffer(struct gfs2_inode *ip, u32 mtype, u64 num, ++ struct buffer_head **bhp); + + static inline int gfs2_meta_inode_buffer(struct gfs2_inode *ip, + struct buffer_head **bhp) +diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c +index dd64140ae6d7b..f4c066aa24b96 100644 +--- a/fs/gfs2/ops_fstype.c ++++ b/fs/gfs2/ops_fstype.c +@@ -136,6 +136,7 @@ static struct gfs2_sbd *init_sbd(struct super_block *sb) + atomic_set(&sdp->sd_log_in_flight, 0); + init_waitqueue_head(&sdp->sd_log_flush_wait); + mutex_init(&sdp->sd_freeze_mutex); ++ INIT_LIST_HEAD(&sdp->sd_dead_glocks); + + return sdp; + +@@ -648,7 +649,7 @@ static int init_statfs(struct gfs2_sbd *sdp) + struct gfs2_jdesc *jd; + struct gfs2_inode *ip; + +- sdp->sd_statfs_inode = gfs2_lookup_simple(master, "statfs"); ++ sdp->sd_statfs_inode = gfs2_lookup_meta(master, "statfs"); + if (IS_ERR(sdp->sd_statfs_inode)) { + error = PTR_ERR(sdp->sd_statfs_inode); + fs_err(sdp, "can't read in statfs inode: %d\n", error); +@@ -657,7 +658,7 @@ static int init_statfs(struct gfs2_sbd *sdp) + if (sdp->sd_args.ar_spectator) + goto out; + +- pn = gfs2_lookup_simple(master, "per_node"); ++ pn = gfs2_lookup_meta(master, "per_node"); + if (IS_ERR(pn)) { + error = PTR_ERR(pn); + fs_err(sdp, "can't find per_node directory: %d\n", error); +@@ -674,7 +675,7 @@ static int init_statfs(struct gfs2_sbd *sdp) + goto free_local; + } + sprintf(buf, "statfs_change%u", jd->jd_jid); +- lsi->si_sc_inode = gfs2_lookup_simple(pn, buf); ++ lsi->si_sc_inode = gfs2_lookup_meta(pn, buf); + if (IS_ERR(lsi->si_sc_inode)) { + error = PTR_ERR(lsi->si_sc_inode); + fs_err(sdp, "can't find local \"sc\" file#%u: %d\n", +@@ -739,7 +740,7 @@ static int init_journal(struct gfs2_sbd *sdp, int undo) + if (undo) + goto fail_statfs; + +- sdp->sd_jindex = gfs2_lookup_simple(master, "jindex"); ++ sdp->sd_jindex = gfs2_lookup_meta(master, "jindex"); + if (IS_ERR(sdp->sd_jindex)) { + fs_err(sdp, "can't lookup journal index: %d\n", error); + return PTR_ERR(sdp->sd_jindex); +@@ -888,7 +889,7 @@ static int init_inodes(struct gfs2_sbd *sdp, int undo) + goto fail; + + /* Read in the resource index inode */ +- sdp->sd_rindex = gfs2_lookup_simple(master, "rindex"); ++ sdp->sd_rindex = gfs2_lookup_meta(master, "rindex"); + if (IS_ERR(sdp->sd_rindex)) { + error = PTR_ERR(sdp->sd_rindex); + fs_err(sdp, "can't get resource index inode: %d\n", error); +@@ -897,7 +898,7 @@ static int init_inodes(struct gfs2_sbd *sdp, int undo) + sdp->sd_rindex_uptodate = 0; + + /* Read in the quota inode */ +- sdp->sd_quota_inode = gfs2_lookup_simple(master, "quota"); ++ sdp->sd_quota_inode = gfs2_lookup_meta(master, "quota"); + if (IS_ERR(sdp->sd_quota_inode)) { + error = PTR_ERR(sdp->sd_quota_inode); + fs_err(sdp, "can't get quota file inode: %d\n", error); +@@ -941,7 +942,7 @@ static int init_per_node(struct gfs2_sbd *sdp, int undo) + if (undo) + goto fail_qc_gh; + +- pn = gfs2_lookup_simple(master, "per_node"); ++ pn = gfs2_lookup_meta(master, "per_node"); + if (IS_ERR(pn)) { + error = PTR_ERR(pn); + fs_err(sdp, "can't find per_node directory: %d\n", error); +@@ -949,7 +950,7 @@ static int init_per_node(struct gfs2_sbd *sdp, int undo) + } + + sprintf(buf, "quota_change%u", sdp->sd_jdesc->jd_jid); +- sdp->sd_qc_inode = gfs2_lookup_simple(pn, buf); ++ sdp->sd_qc_inode = gfs2_lookup_meta(pn, buf); + if (IS_ERR(sdp->sd_qc_inode)) { + error = PTR_ERR(sdp->sd_qc_inode); + fs_err(sdp, "can't find local \"qc\" file: %d\n", error); +@@ -1074,7 +1075,7 @@ static int gfs2_lm_mount(struct gfs2_sbd *sdp, int silent) + void gfs2_lm_unmount(struct gfs2_sbd *sdp) + { + const struct lm_lockops *lm = sdp->sd_lockstruct.ls_ops; +- if (likely(!gfs2_withdrawn(sdp)) && lm->lm_unmount) ++ if (!gfs2_withdrawing_or_withdrawn(sdp) && lm->lm_unmount) + lm->lm_unmount(sdp); + } + +@@ -1126,8 +1127,7 @@ static int init_threads(struct gfs2_sbd *sdp) + return 0; + + fail: +- kthread_stop(sdp->sd_logd_process); +- put_task_struct(sdp->sd_logd_process); ++ kthread_stop_put(sdp->sd_logd_process); + sdp->sd_logd_process = NULL; + return error; + } +@@ -1135,13 +1135,11 @@ static int init_threads(struct gfs2_sbd *sdp) + void gfs2_destroy_threads(struct gfs2_sbd *sdp) + { + if (sdp->sd_logd_process) { +- kthread_stop(sdp->sd_logd_process); +- put_task_struct(sdp->sd_logd_process); ++ kthread_stop_put(sdp->sd_logd_process); + sdp->sd_logd_process = NULL; + } + if (sdp->sd_quotad_process) { +- kthread_stop(sdp->sd_quotad_process); +- put_task_struct(sdp->sd_quotad_process); ++ kthread_stop_put(sdp->sd_quotad_process); + sdp->sd_quotad_process = NULL; + } + } +diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c +index f689847bab40f..892b1c44de531 100644 +--- a/fs/gfs2/quota.c ++++ b/fs/gfs2/quota.c +@@ -128,7 +128,7 @@ static void gfs2_qd_dispose(struct gfs2_quota_data *qd) + hlist_bl_del_rcu(&qd->qd_hlist); + spin_unlock_bucket(qd->qd_hash); + +- if (!gfs2_withdrawn(sdp)) { ++ if (!gfs2_withdrawing_or_withdrawn(sdp)) { + gfs2_assert_warn(sdp, !qd->qd_change); + gfs2_assert_warn(sdp, !qd->qd_slot_ref); + gfs2_assert_warn(sdp, !qd->qd_bh_count); +@@ -1528,7 +1528,7 @@ static void quotad_error(struct gfs2_sbd *sdp, const char *msg, int error) + { + if (error == 0 || error == -EROFS) + return; +- if (!gfs2_withdrawn(sdp)) { ++ if (!gfs2_withdrawing_or_withdrawn(sdp)) { + if (!cmpxchg(&sdp->sd_log_error, 0, error)) + fs_err(sdp, "gfs2_quotad: %s error %d\n", msg, error); + wake_up(&sdp->sd_logd_waitq); +@@ -1572,7 +1572,7 @@ int gfs2_quotad(void *data) + unsigned long t = 0; + + while (!kthread_should_stop()) { +- if (gfs2_withdrawn(sdp)) ++ if (gfs2_withdrawing_or_withdrawn(sdp)) + break; + + /* Update the master statfs file */ +@@ -1596,7 +1596,7 @@ int gfs2_quotad(void *data) + + t = wait_event_interruptible_timeout(sdp->sd_quota_wait, + sdp->sd_statfs_force_sync || +- gfs2_withdrawn(sdp) || ++ gfs2_withdrawing_or_withdrawn(sdp) || + kthread_should_stop(), + t); + +diff --git a/fs/gfs2/quota.h b/fs/gfs2/quota.h +index 1429945215a03..e4a2fdb552cd7 100644 +--- a/fs/gfs2/quota.h ++++ b/fs/gfs2/quota.h +@@ -15,27 +15,27 @@ struct gfs2_sbd; + #define NO_UID_QUOTA_CHANGE INVALID_UID + #define NO_GID_QUOTA_CHANGE INVALID_GID + +-extern int gfs2_qa_get(struct gfs2_inode *ip); +-extern void gfs2_qa_put(struct gfs2_inode *ip); +-extern int gfs2_quota_hold(struct gfs2_inode *ip, kuid_t uid, kgid_t gid); +-extern void gfs2_quota_unhold(struct gfs2_inode *ip); ++int gfs2_qa_get(struct gfs2_inode *ip); ++void gfs2_qa_put(struct gfs2_inode *ip); ++int gfs2_quota_hold(struct gfs2_inode *ip, kuid_t uid, kgid_t gid); ++void gfs2_quota_unhold(struct gfs2_inode *ip); + +-extern int gfs2_quota_lock(struct gfs2_inode *ip, kuid_t uid, kgid_t gid); +-extern void gfs2_quota_unlock(struct gfs2_inode *ip); ++int gfs2_quota_lock(struct gfs2_inode *ip, kuid_t uid, kgid_t gid); ++void gfs2_quota_unlock(struct gfs2_inode *ip); + +-extern int gfs2_quota_check(struct gfs2_inode *ip, kuid_t uid, kgid_t gid, +- struct gfs2_alloc_parms *ap); +-extern void gfs2_quota_change(struct gfs2_inode *ip, s64 change, +- kuid_t uid, kgid_t gid); ++int gfs2_quota_check(struct gfs2_inode *ip, kuid_t uid, kgid_t gid, ++ struct gfs2_alloc_parms *ap); ++void gfs2_quota_change(struct gfs2_inode *ip, s64 change, ++ kuid_t uid, kgid_t gid); + +-extern int gfs2_quota_sync(struct super_block *sb, int type); +-extern int gfs2_quota_refresh(struct gfs2_sbd *sdp, struct kqid qid); ++int gfs2_quota_sync(struct super_block *sb, int type); ++int gfs2_quota_refresh(struct gfs2_sbd *sdp, struct kqid qid); + +-extern int gfs2_quota_init(struct gfs2_sbd *sdp); +-extern void gfs2_quota_cleanup(struct gfs2_sbd *sdp); +-extern int gfs2_quotad(void *data); ++int gfs2_quota_init(struct gfs2_sbd *sdp); ++void gfs2_quota_cleanup(struct gfs2_sbd *sdp); ++int gfs2_quotad(void *data); + +-extern void gfs2_wake_up_statfs(struct gfs2_sbd *sdp); ++void gfs2_wake_up_statfs(struct gfs2_sbd *sdp); + + static inline int gfs2_quota_lock_check(struct gfs2_inode *ip, + struct gfs2_alloc_parms *ap) +@@ -62,6 +62,7 @@ static inline int gfs2_quota_lock_check(struct gfs2_inode *ip, + extern const struct quotactl_ops gfs2_quotactl_ops; + extern struct shrinker gfs2_qd_shrinker; + extern struct list_lru gfs2_qd_lru; +-extern void __init gfs2_quota_hash_init(void); ++ ++void __init gfs2_quota_hash_init(void); + + #endif /* __QUOTA_DOT_H__ */ +diff --git a/fs/gfs2/recovery.c b/fs/gfs2/recovery.c +index 5aae02669a409..f4fe7039f725b 100644 +--- a/fs/gfs2/recovery.c ++++ b/fs/gfs2/recovery.c +@@ -411,7 +411,7 @@ void gfs2_recover_func(struct work_struct *work) + int error = 0; + int jlocked = 0; + +- if (gfs2_withdrawn(sdp)) { ++ if (gfs2_withdrawing_or_withdrawn(sdp)) { + fs_err(sdp, "jid=%u: Recovery not attempted due to withdraw.\n", + jd->jd_jid); + goto fail; +diff --git a/fs/gfs2/recovery.h b/fs/gfs2/recovery.h +index 7a0c9d0b7503f..6a0fd42e1120f 100644 +--- a/fs/gfs2/recovery.h ++++ b/fs/gfs2/recovery.h +@@ -17,18 +17,18 @@ static inline void gfs2_replay_incr_blk(struct gfs2_jdesc *jd, u32 *blk) + *blk = 0; + } + +-extern int gfs2_replay_read_block(struct gfs2_jdesc *jd, unsigned int blk, ++int gfs2_replay_read_block(struct gfs2_jdesc *jd, unsigned int blk, + struct buffer_head **bh); + +-extern int gfs2_revoke_add(struct gfs2_jdesc *jd, u64 blkno, unsigned int where); +-extern int gfs2_revoke_check(struct gfs2_jdesc *jd, u64 blkno, unsigned int where); +-extern void gfs2_revoke_clean(struct gfs2_jdesc *jd); ++int gfs2_revoke_add(struct gfs2_jdesc *jd, u64 blkno, unsigned int where); ++int gfs2_revoke_check(struct gfs2_jdesc *jd, u64 blkno, unsigned int where); ++void gfs2_revoke_clean(struct gfs2_jdesc *jd); + +-extern int gfs2_recover_journal(struct gfs2_jdesc *gfs2_jd, bool wait); +-extern void gfs2_recover_func(struct work_struct *work); +-extern int __get_log_header(struct gfs2_sbd *sdp, +- const struct gfs2_log_header *lh, unsigned int blkno, +- struct gfs2_log_header_host *head); ++int gfs2_recover_journal(struct gfs2_jdesc *gfs2_jd, bool wait); ++void gfs2_recover_func(struct work_struct *work); ++int __get_log_header(struct gfs2_sbd *sdp, ++ const struct gfs2_log_header *lh, unsigned int blkno, ++ struct gfs2_log_header_host *head); + + #endif /* __RECOVERY_DOT_H__ */ + +diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c +index 307b952a41f8f..396d0f4a259d5 100644 +--- a/fs/gfs2/rgrp.c ++++ b/fs/gfs2/rgrp.c +@@ -2411,13 +2411,12 @@ static void gfs2_set_alloc_start(struct gfs2_rbm *rbm, + * @bn: Used to return the starting block number + * @nblocks: requested number of blocks/extent length (value/result) + * @dinode: 1 if we're allocating a dinode block, else 0 +- * @generation: the generation number of the inode + * + * Returns: 0 or error + */ + + int gfs2_alloc_blocks(struct gfs2_inode *ip, u64 *bn, unsigned int *nblocks, +- bool dinode, u64 *generation) ++ bool dinode) + { + struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); + struct buffer_head *dibh; +@@ -2477,10 +2476,13 @@ int gfs2_alloc_blocks(struct gfs2_inode *ip, u64 *bn, unsigned int *nblocks, + rbm.rgd->rd_free -= *nblocks; + spin_unlock(&rbm.rgd->rd_rsspin); + if (dinode) { ++ u64 generation; ++ + rbm.rgd->rd_dinodes++; +- *generation = rbm.rgd->rd_igeneration++; +- if (*generation == 0) +- *generation = rbm.rgd->rd_igeneration++; ++ generation = rbm.rgd->rd_igeneration++; ++ if (generation == 0) ++ generation = rbm.rgd->rd_igeneration++; ++ ip->i_generation = generation; + } + + gfs2_trans_add_meta(rbm.rgd->rd_gl, rbm.rgd->rd_bits[0].bi_bh); +diff --git a/fs/gfs2/rgrp.h b/fs/gfs2/rgrp.h +index 00b30cf893af2..8d20e99385db4 100644 +--- a/fs/gfs2/rgrp.h ++++ b/fs/gfs2/rgrp.h +@@ -22,38 +22,38 @@ struct gfs2_rgrpd; + struct gfs2_sbd; + struct gfs2_holder; + +-extern void gfs2_rgrp_verify(struct gfs2_rgrpd *rgd); ++void gfs2_rgrp_verify(struct gfs2_rgrpd *rgd); + +-extern struct gfs2_rgrpd *gfs2_blk2rgrpd(struct gfs2_sbd *sdp, u64 blk, bool exact); +-extern struct gfs2_rgrpd *gfs2_rgrpd_get_first(struct gfs2_sbd *sdp); +-extern struct gfs2_rgrpd *gfs2_rgrpd_get_next(struct gfs2_rgrpd *rgd); ++struct gfs2_rgrpd *gfs2_blk2rgrpd(struct gfs2_sbd *sdp, u64 blk, bool exact); ++struct gfs2_rgrpd *gfs2_rgrpd_get_first(struct gfs2_sbd *sdp); ++struct gfs2_rgrpd *gfs2_rgrpd_get_next(struct gfs2_rgrpd *rgd); + +-extern void gfs2_clear_rgrpd(struct gfs2_sbd *sdp); +-extern int gfs2_rindex_update(struct gfs2_sbd *sdp); +-extern void gfs2_free_clones(struct gfs2_rgrpd *rgd); +-extern int gfs2_rgrp_go_instantiate(struct gfs2_glock *gl); +-extern void gfs2_rgrp_brelse(struct gfs2_rgrpd *rgd); ++void gfs2_clear_rgrpd(struct gfs2_sbd *sdp); ++int gfs2_rindex_update(struct gfs2_sbd *sdp); ++void gfs2_free_clones(struct gfs2_rgrpd *rgd); ++int gfs2_rgrp_go_instantiate(struct gfs2_glock *gl); ++void gfs2_rgrp_brelse(struct gfs2_rgrpd *rgd); + +-extern struct gfs2_alloc *gfs2_alloc_get(struct gfs2_inode *ip); ++struct gfs2_alloc *gfs2_alloc_get(struct gfs2_inode *ip); + + #define GFS2_AF_ORLOV 1 +-extern int gfs2_inplace_reserve(struct gfs2_inode *ip, +- struct gfs2_alloc_parms *ap); +-extern void gfs2_inplace_release(struct gfs2_inode *ip); +- +-extern int gfs2_alloc_blocks(struct gfs2_inode *ip, u64 *bn, unsigned int *n, +- bool dinode, u64 *generation); +- +-extern void gfs2_rs_deltree(struct gfs2_blkreserv *rs); +-extern void gfs2_rs_delete(struct gfs2_inode *ip); +-extern void __gfs2_free_blocks(struct gfs2_inode *ip, struct gfs2_rgrpd *rgd, +- u64 bstart, u32 blen, int meta); +-extern void gfs2_free_meta(struct gfs2_inode *ip, struct gfs2_rgrpd *rgd, +- u64 bstart, u32 blen); +-extern void gfs2_free_di(struct gfs2_rgrpd *rgd, struct gfs2_inode *ip); +-extern void gfs2_unlink_di(struct inode *inode); +-extern int gfs2_check_blk_type(struct gfs2_sbd *sdp, u64 no_addr, +- unsigned int type); ++int gfs2_inplace_reserve(struct gfs2_inode *ip, ++ struct gfs2_alloc_parms *ap); ++void gfs2_inplace_release(struct gfs2_inode *ip); ++ ++int gfs2_alloc_blocks(struct gfs2_inode *ip, u64 *bn, unsigned int *n, ++ bool dinode); ++ ++void gfs2_rs_deltree(struct gfs2_blkreserv *rs); ++void gfs2_rs_delete(struct gfs2_inode *ip); ++void __gfs2_free_blocks(struct gfs2_inode *ip, struct gfs2_rgrpd *rgd, ++ u64 bstart, u32 blen, int meta); ++void gfs2_free_meta(struct gfs2_inode *ip, struct gfs2_rgrpd *rgd, ++ u64 bstart, u32 blen); ++void gfs2_free_di(struct gfs2_rgrpd *rgd, struct gfs2_inode *ip); ++void gfs2_unlink_di(struct inode *inode); ++int gfs2_check_blk_type(struct gfs2_sbd *sdp, u64 no_addr, ++ unsigned int type); + + struct gfs2_rgrp_list { + unsigned int rl_rgrps; +@@ -62,18 +62,19 @@ struct gfs2_rgrp_list { + struct gfs2_holder *rl_ghs; + }; + +-extern void gfs2_rlist_add(struct gfs2_inode *ip, struct gfs2_rgrp_list *rlist, +- u64 block); +-extern void gfs2_rlist_alloc(struct gfs2_rgrp_list *rlist, +- unsigned int state, u16 flags); +-extern void gfs2_rlist_free(struct gfs2_rgrp_list *rlist); +-extern u64 gfs2_ri_total(struct gfs2_sbd *sdp); +-extern void gfs2_rgrp_dump(struct seq_file *seq, struct gfs2_rgrpd *rgd, +- const char *fs_id_buf); +-extern int gfs2_rgrp_send_discards(struct gfs2_sbd *sdp, u64 offset, +- struct buffer_head *bh, +- const struct gfs2_bitmap *bi, unsigned minlen, u64 *ptrimmed); +-extern int gfs2_fitrim(struct file *filp, void __user *argp); ++void gfs2_rlist_add(struct gfs2_inode *ip, struct gfs2_rgrp_list *rlist, ++ u64 block); ++void gfs2_rlist_alloc(struct gfs2_rgrp_list *rlist, ++ unsigned int state, u16 flags); ++void gfs2_rlist_free(struct gfs2_rgrp_list *rlist); ++u64 gfs2_ri_total(struct gfs2_sbd *sdp); ++void gfs2_rgrp_dump(struct seq_file *seq, struct gfs2_rgrpd *rgd, ++ const char *fs_id_buf); ++int gfs2_rgrp_send_discards(struct gfs2_sbd *sdp, u64 offset, ++ struct buffer_head *bh, ++ const struct gfs2_bitmap *bi, unsigned minlen, ++ u64 *ptrimmed); ++int gfs2_fitrim(struct file *filp, void __user *argp); + + /* This is how to tell if a reservation is in the rgrp tree: */ + static inline bool gfs2_rs_active(const struct gfs2_blkreserv *rs) +@@ -88,9 +89,9 @@ static inline int rgrp_contains_block(struct gfs2_rgrpd *rgd, u64 block) + return first <= block && block < last; + } + +-extern void check_and_update_goal(struct gfs2_inode *ip); ++void check_and_update_goal(struct gfs2_inode *ip); + +-extern void rgrp_lock_local(struct gfs2_rgrpd *rgd); +-extern void rgrp_unlock_local(struct gfs2_rgrpd *rgd); ++void rgrp_lock_local(struct gfs2_rgrpd *rgd); ++void rgrp_unlock_local(struct gfs2_rgrpd *rgd); + + #endif /* __RGRP_DOT_H__ */ +diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c +index 5f4ebe279aaae..2e1d1eca4d14a 100644 +--- a/fs/gfs2/super.c ++++ b/fs/gfs2/super.c +@@ -134,7 +134,7 @@ int gfs2_make_fs_rw(struct gfs2_sbd *sdp) + int error; + + j_gl->gl_ops->go_inval(j_gl, DIO_METADATA); +- if (gfs2_withdrawn(sdp)) ++ if (gfs2_withdrawing_or_withdrawn(sdp)) + return -EIO; + + error = gfs2_find_jhead(sdp->sd_jdesc, &head, false); +@@ -153,7 +153,7 @@ int gfs2_make_fs_rw(struct gfs2_sbd *sdp) + gfs2_log_pointers_init(sdp, head.lh_blkno); + + error = gfs2_quota_init(sdp); +- if (!error && gfs2_withdrawn(sdp)) ++ if (!error && gfs2_withdrawing_or_withdrawn(sdp)) + error = -EIO; + if (!error) + set_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags); +@@ -499,7 +499,7 @@ static void gfs2_dirty_inode(struct inode *inode, int flags) + return; + } + +- if (unlikely(gfs2_withdrawn(sdp))) ++ if (gfs2_withdrawing_or_withdrawn(sdp)) + return; + if (!gfs2_glock_is_locked_by_me(ip->i_gl)) { + ret = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh); +@@ -605,7 +605,7 @@ static void gfs2_put_super(struct super_block *sb) + if (!sb_rdonly(sb)) + gfs2_make_fs_ro(sdp); + else { +- if (gfs2_withdrawn(sdp)) ++ if (gfs2_withdrawing_or_withdrawn(sdp)) + gfs2_destroy_threads(sdp); + + gfs2_quota_cleanup(sdp); +@@ -646,10 +646,7 @@ static void gfs2_put_super(struct super_block *sb) + gfs2_gl_hash_clear(sdp); + truncate_inode_pages_final(&sdp->sd_aspace); + gfs2_delete_debugfs_file(sdp); +- /* Unmount the locking protocol */ +- gfs2_lm_unmount(sdp); + +- /* At this point, we're through participating in the lockspace */ + gfs2_sys_fs_del(sdp); + free_sbd(sdp); + } +@@ -685,7 +682,7 @@ static int gfs2_freeze_locally(struct gfs2_sbd *sdp) + if (test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags)) { + gfs2_log_flush(sdp, NULL, GFS2_LOG_HEAD_FLUSH_FREEZE | + GFS2_LFC_FREEZE_GO_SYNC); +- if (gfs2_withdrawn(sdp)) { ++ if (gfs2_withdrawing_or_withdrawn(sdp)) { + error = thaw_super(sb, FREEZE_HOLDER_USERSPACE); + if (error) + return error; +@@ -1578,7 +1575,7 @@ static void gfs2_free_inode(struct inode *inode) + kmem_cache_free(gfs2_inode_cachep, GFS2_I(inode)); + } + +-extern void free_local_statfs_inodes(struct gfs2_sbd *sdp) ++void free_local_statfs_inodes(struct gfs2_sbd *sdp) + { + struct local_statfs_inode *lsi, *safe; + +@@ -1593,8 +1590,8 @@ extern void free_local_statfs_inodes(struct gfs2_sbd *sdp) + } + } + +-extern struct inode *find_local_statfs_inode(struct gfs2_sbd *sdp, +- unsigned int index) ++struct inode *find_local_statfs_inode(struct gfs2_sbd *sdp, ++ unsigned int index) + { + struct local_statfs_inode *lsi; + +diff --git a/fs/gfs2/super.h b/fs/gfs2/super.h +index ab9c83106932d..e1f7ef9264468 100644 +--- a/fs/gfs2/super.h ++++ b/fs/gfs2/super.h +@@ -15,7 +15,7 @@ + #define GFS2_FS_FORMAT_MIN (1801) + #define GFS2_FS_FORMAT_MAX (1802) + +-extern void gfs2_lm_unmount(struct gfs2_sbd *sdp); ++void gfs2_lm_unmount(struct gfs2_sbd *sdp); + + static inline unsigned int gfs2_jindex_size(struct gfs2_sbd *sdp) + { +@@ -26,33 +26,33 @@ static inline unsigned int gfs2_jindex_size(struct gfs2_sbd *sdp) + return x; + } + +-extern void gfs2_jindex_free(struct gfs2_sbd *sdp); ++void gfs2_jindex_free(struct gfs2_sbd *sdp); + +-extern struct gfs2_jdesc *gfs2_jdesc_find(struct gfs2_sbd *sdp, unsigned int jid); +-extern int gfs2_jdesc_check(struct gfs2_jdesc *jd); +-extern int gfs2_lookup_in_master_dir(struct gfs2_sbd *sdp, char *filename, +- struct gfs2_inode **ipp); ++struct gfs2_jdesc *gfs2_jdesc_find(struct gfs2_sbd *sdp, unsigned int jid); ++int gfs2_jdesc_check(struct gfs2_jdesc *jd); ++int gfs2_lookup_in_master_dir(struct gfs2_sbd *sdp, char *filename, ++ struct gfs2_inode **ipp); + +-extern int gfs2_make_fs_rw(struct gfs2_sbd *sdp); +-extern void gfs2_make_fs_ro(struct gfs2_sbd *sdp); +-extern void gfs2_online_uevent(struct gfs2_sbd *sdp); +-extern void gfs2_destroy_threads(struct gfs2_sbd *sdp); +-extern int gfs2_statfs_init(struct gfs2_sbd *sdp); +-extern void gfs2_statfs_change(struct gfs2_sbd *sdp, s64 total, s64 free, +- s64 dinodes); +-extern void gfs2_statfs_change_in(struct gfs2_statfs_change_host *sc, +- const void *buf); +-extern void gfs2_statfs_change_out(const struct gfs2_statfs_change_host *sc, +- void *buf); +-extern void update_statfs(struct gfs2_sbd *sdp, struct buffer_head *m_bh); +-extern int gfs2_statfs_sync(struct super_block *sb, int type); +-extern void gfs2_freeze_func(struct work_struct *work); +-extern void gfs2_thaw_freeze_initiator(struct super_block *sb); ++int gfs2_make_fs_rw(struct gfs2_sbd *sdp); ++void gfs2_make_fs_ro(struct gfs2_sbd *sdp); ++void gfs2_online_uevent(struct gfs2_sbd *sdp); ++void gfs2_destroy_threads(struct gfs2_sbd *sdp); ++int gfs2_statfs_init(struct gfs2_sbd *sdp); ++void gfs2_statfs_change(struct gfs2_sbd *sdp, s64 total, s64 free, ++ s64 dinodes); ++void gfs2_statfs_change_in(struct gfs2_statfs_change_host *sc, ++ const void *buf); ++void gfs2_statfs_change_out(const struct gfs2_statfs_change_host *sc, ++ void *buf); ++void update_statfs(struct gfs2_sbd *sdp, struct buffer_head *m_bh); ++int gfs2_statfs_sync(struct super_block *sb, int type); ++void gfs2_freeze_func(struct work_struct *work); ++void gfs2_thaw_freeze_initiator(struct super_block *sb); + +-extern void free_local_statfs_inodes(struct gfs2_sbd *sdp); +-extern struct inode *find_local_statfs_inode(struct gfs2_sbd *sdp, +- unsigned int index); +-extern void free_sbd(struct gfs2_sbd *sdp); ++void free_local_statfs_inodes(struct gfs2_sbd *sdp); ++struct inode *find_local_statfs_inode(struct gfs2_sbd *sdp, ++ unsigned int index); ++void free_sbd(struct gfs2_sbd *sdp); + + extern struct file_system_type gfs2_fs_type; + extern struct file_system_type gfs2meta_fs_type; +diff --git a/fs/gfs2/sys.c b/fs/gfs2/sys.c +index 60a0206890c54..250f340cb44d6 100644 +--- a/fs/gfs2/sys.c ++++ b/fs/gfs2/sys.c +@@ -193,7 +193,7 @@ static ssize_t freeze_store(struct gfs2_sbd *sdp, const char *buf, size_t len) + + static ssize_t withdraw_show(struct gfs2_sbd *sdp, char *buf) + { +- unsigned int b = gfs2_withdrawn(sdp); ++ unsigned int b = gfs2_withdrawing_or_withdrawn(sdp); + return snprintf(buf, PAGE_SIZE, "%u\n", b); + } + +diff --git a/fs/gfs2/trans.c b/fs/gfs2/trans.c +index 7e835be7032d0..192213c7359af 100644 +--- a/fs/gfs2/trans.c ++++ b/fs/gfs2/trans.c +@@ -268,7 +268,7 @@ void gfs2_trans_add_meta(struct gfs2_glock *gl, struct buffer_head *bh) + (unsigned long long)bd->bd_bh->b_blocknr); + BUG(); + } +- if (unlikely(gfs2_withdrawn(sdp))) { ++ if (gfs2_withdrawing_or_withdrawn(sdp)) { + fs_info(sdp, "GFS2:adding buf while withdrawn! 0x%llx\n", + (unsigned long long)bd->bd_bh->b_blocknr); + goto out_unlock; +diff --git a/fs/gfs2/trans.h b/fs/gfs2/trans.h +index c76ad9a4c75a9..f8ce5302280d3 100644 +--- a/fs/gfs2/trans.h ++++ b/fs/gfs2/trans.h +@@ -34,17 +34,17 @@ static inline unsigned int gfs2_rg_blocks(const struct gfs2_inode *ip, unsigned + return rgd->rd_length; + } + +-extern int __gfs2_trans_begin(struct gfs2_trans *tr, struct gfs2_sbd *sdp, +- unsigned int blocks, unsigned int revokes, +- unsigned long ip); +-extern int gfs2_trans_begin(struct gfs2_sbd *sdp, unsigned int blocks, +- unsigned int revokes); +- +-extern void gfs2_trans_end(struct gfs2_sbd *sdp); +-extern void gfs2_trans_add_data(struct gfs2_glock *gl, struct buffer_head *bh); +-extern void gfs2_trans_add_meta(struct gfs2_glock *gl, struct buffer_head *bh); +-extern void gfs2_trans_add_revoke(struct gfs2_sbd *sdp, struct gfs2_bufdata *bd); +-extern void gfs2_trans_remove_revoke(struct gfs2_sbd *sdp, u64 blkno, unsigned int len); +-extern void gfs2_trans_free(struct gfs2_sbd *sdp, struct gfs2_trans *tr); ++int __gfs2_trans_begin(struct gfs2_trans *tr, struct gfs2_sbd *sdp, ++ unsigned int blocks, unsigned int revokes, ++ unsigned long ip); ++int gfs2_trans_begin(struct gfs2_sbd *sdp, unsigned int blocks, ++ unsigned int revokes); ++ ++void gfs2_trans_end(struct gfs2_sbd *sdp); ++void gfs2_trans_add_data(struct gfs2_glock *gl, struct buffer_head *bh); ++void gfs2_trans_add_meta(struct gfs2_glock *gl, struct buffer_head *bh); ++void gfs2_trans_add_revoke(struct gfs2_sbd *sdp, struct gfs2_bufdata *bd); ++void gfs2_trans_remove_revoke(struct gfs2_sbd *sdp, u64 blkno, unsigned int len); ++void gfs2_trans_free(struct gfs2_sbd *sdp, struct gfs2_trans *tr); + + #endif /* __TRANS_DOT_H__ */ +diff --git a/fs/gfs2/util.c b/fs/gfs2/util.c +index da29fafb62728..fc3ecb180ac53 100644 +--- a/fs/gfs2/util.c ++++ b/fs/gfs2/util.c +@@ -350,7 +350,6 @@ int gfs2_withdraw(struct gfs2_sbd *sdp) + fs_err(sdp, "telling LM to unmount\n"); + lm->lm_unmount(sdp); + } +- set_bit(SDF_SKIP_DLM_UNLOCK, &sdp->sd_flags); + fs_err(sdp, "File system withdrawn\n"); + dump_stack(); + clear_bit(SDF_WITHDRAW_IN_PROG, &sdp->sd_flags); +@@ -372,7 +371,7 @@ void gfs2_assert_withdraw_i(struct gfs2_sbd *sdp, char *assertion, + const char *function, char *file, unsigned int line, + bool delayed) + { +- if (gfs2_withdrawn(sdp)) ++ if (gfs2_withdrawing_or_withdrawn(sdp)) + return; + + fs_err(sdp, +@@ -548,7 +547,7 @@ void gfs2_io_error_bh_i(struct gfs2_sbd *sdp, struct buffer_head *bh, + const char *function, char *file, unsigned int line, + bool withdraw) + { +- if (gfs2_withdrawn(sdp)) ++ if (gfs2_withdrawing_or_withdrawn(sdp)) + return; + + fs_err(sdp, "fatal: I/O error\n" +diff --git a/fs/gfs2/util.h b/fs/gfs2/util.h +index cdb839529175d..ba071998461fd 100644 +--- a/fs/gfs2/util.h ++++ b/fs/gfs2/util.h +@@ -147,10 +147,10 @@ static inline void gfs2_metatype_set(struct buffer_head *bh, u16 type, + int gfs2_io_error_i(struct gfs2_sbd *sdp, const char *function, + char *file, unsigned int line); + +-extern int check_journal_clean(struct gfs2_sbd *sdp, struct gfs2_jdesc *jd, +- bool verbose); +-extern int gfs2_freeze_lock_shared(struct gfs2_sbd *sdp); +-extern void gfs2_freeze_unlock(struct gfs2_holder *freeze_gh); ++int check_journal_clean(struct gfs2_sbd *sdp, struct gfs2_jdesc *jd, ++ bool verbose); ++int gfs2_freeze_lock_shared(struct gfs2_sbd *sdp); ++void gfs2_freeze_unlock(struct gfs2_holder *freeze_gh); + + #define gfs2_io_error(sdp) \ + gfs2_io_error_i((sdp), __func__, __FILE__, __LINE__) +@@ -198,13 +198,14 @@ static inline void gfs2_withdraw_delayed(struct gfs2_sbd *sdp) + } + + /** +- * gfs2_withdrawn - test whether the file system is withdrawing or withdrawn ++ * gfs2_withdrawing_or_withdrawn - test whether the file system is withdrawing ++ * or withdrawn + * @sdp: the superblock + */ +-static inline bool gfs2_withdrawn(struct gfs2_sbd *sdp) ++static inline bool gfs2_withdrawing_or_withdrawn(struct gfs2_sbd *sdp) + { +- return test_bit(SDF_WITHDRAWN, &sdp->sd_flags) || +- test_bit(SDF_WITHDRAWING, &sdp->sd_flags); ++ return unlikely(test_bit(SDF_WITHDRAWN, &sdp->sd_flags) || ++ test_bit(SDF_WITHDRAWING, &sdp->sd_flags)); + } + + /** +@@ -213,13 +214,13 @@ static inline bool gfs2_withdrawn(struct gfs2_sbd *sdp) + */ + static inline bool gfs2_withdrawing(struct gfs2_sbd *sdp) + { +- return test_bit(SDF_WITHDRAWING, &sdp->sd_flags) && +- !test_bit(SDF_WITHDRAWN, &sdp->sd_flags); ++ return unlikely(test_bit(SDF_WITHDRAWING, &sdp->sd_flags) && ++ !test_bit(SDF_WITHDRAWN, &sdp->sd_flags)); + } + + static inline bool gfs2_withdraw_in_prog(struct gfs2_sbd *sdp) + { +- return test_bit(SDF_WITHDRAW_IN_PROG, &sdp->sd_flags); ++ return unlikely(test_bit(SDF_WITHDRAW_IN_PROG, &sdp->sd_flags)); + } + + #define gfs2_tune_get(sdp, field) \ +diff --git a/fs/gfs2/xattr.c b/fs/gfs2/xattr.c +index 4fea70c0fe3d1..2117011c8c577 100644 +--- a/fs/gfs2/xattr.c ++++ b/fs/gfs2/xattr.c +@@ -639,7 +639,7 @@ static int ea_alloc_blk(struct gfs2_inode *ip, struct buffer_head **bhp) + u64 block; + int error; + +- error = gfs2_alloc_blocks(ip, &block, &n, 0, NULL); ++ error = gfs2_alloc_blocks(ip, &block, &n, 0); + if (error) + return error; + gfs2_trans_remove_revoke(sdp, block, 1); +@@ -701,7 +701,7 @@ static int ea_write(struct gfs2_inode *ip, struct gfs2_ea_header *ea, + int mh_size = sizeof(struct gfs2_meta_header); + unsigned int n = 1; + +- error = gfs2_alloc_blocks(ip, &block, &n, 0, NULL); ++ error = gfs2_alloc_blocks(ip, &block, &n, 0); + if (error) + return error; + gfs2_trans_remove_revoke(sdp, block, 1); +@@ -1002,7 +1002,7 @@ static int ea_set_block(struct gfs2_inode *ip, struct gfs2_ea_request *er, + } else { + u64 blk; + unsigned int n = 1; +- error = gfs2_alloc_blocks(ip, &blk, &n, 0, NULL); ++ error = gfs2_alloc_blocks(ip, &blk, &n, 0); + if (error) + return error; + gfs2_trans_remove_revoke(sdp, blk, 1); +diff --git a/fs/gfs2/xattr.h b/fs/gfs2/xattr.h +index 2aed9d7d483d5..eb12eb7e37c19 100644 +--- a/fs/gfs2/xattr.h ++++ b/fs/gfs2/xattr.h +@@ -50,14 +50,14 @@ struct gfs2_ea_location { + struct gfs2_ea_header *el_prev; + }; + +-extern int __gfs2_xattr_set(struct inode *inode, const char *name, +- const void *value, size_t size, +- int flags, int type); +-extern ssize_t gfs2_listxattr(struct dentry *dentry, char *buffer, size_t size); +-extern int gfs2_ea_dealloc(struct gfs2_inode *ip); ++int __gfs2_xattr_set(struct inode *inode, const char *name, ++ const void *value, size_t size, ++ int flags, int type); ++ssize_t gfs2_listxattr(struct dentry *dentry, char *buffer, size_t size); ++int gfs2_ea_dealloc(struct gfs2_inode *ip); + + /* Exported to acl.c */ + +-extern int gfs2_xattr_acl_get(struct gfs2_inode *ip, const char *name, char **data); ++int gfs2_xattr_acl_get(struct gfs2_inode *ip, const char *name, char **data); + + #endif /* __EATTR_DOT_H__ */ +diff --git a/fs/jffs2/xattr.c b/fs/jffs2/xattr.c +index 3b6bdc9a49e1b..23c1f6a120f0c 100644 +--- a/fs/jffs2/xattr.c ++++ b/fs/jffs2/xattr.c +@@ -1110,6 +1110,9 @@ int do_jffs2_setxattr(struct inode *inode, int xprefix, const char *xname, + return rc; + + request = PAD(sizeof(struct jffs2_raw_xattr) + strlen(xname) + 1 + size); ++ if (request > c->sector_size - c->cleanmarker_size) ++ return -ERANGE; ++ + rc = jffs2_reserve_space(c, request, &length, + ALLOC_NORMAL, JFFS2_SUMMARY_XATTR_SIZE); + if (rc) { +diff --git a/fs/nfs/filelayout/filelayout.c b/fs/nfs/filelayout/filelayout.c +index ce8f8934bca51..569ae4ec60845 100644 +--- a/fs/nfs/filelayout/filelayout.c ++++ b/fs/nfs/filelayout/filelayout.c +@@ -883,7 +883,7 @@ filelayout_pg_init_read(struct nfs_pageio_descriptor *pgio, + NFS4_MAX_UINT64, + IOMODE_READ, + false, +- GFP_KERNEL); ++ nfs_io_gfp_mask()); + if (IS_ERR(pgio->pg_lseg)) { + pgio->pg_error = PTR_ERR(pgio->pg_lseg); + pgio->pg_lseg = NULL; +@@ -907,7 +907,7 @@ filelayout_pg_init_write(struct nfs_pageio_descriptor *pgio, + NFS4_MAX_UINT64, + IOMODE_RW, + false, +- GFP_NOFS); ++ nfs_io_gfp_mask()); + if (IS_ERR(pgio->pg_lseg)) { + pgio->pg_error = PTR_ERR(pgio->pg_lseg); + pgio->pg_lseg = NULL; +diff --git a/fs/nfs/fs_context.c b/fs/nfs/fs_context.c +index 853e8d609bb3b..41126d6dcd760 100644 +--- a/fs/nfs/fs_context.c ++++ b/fs/nfs/fs_context.c +@@ -1111,9 +1111,12 @@ static int nfs23_parse_monolithic(struct fs_context *fc, + ctx->acdirmax = data->acdirmax; + ctx->need_mount = false; + +- memcpy(sap, &data->addr, sizeof(data->addr)); +- ctx->nfs_server.addrlen = sizeof(data->addr); +- ctx->nfs_server.port = ntohs(data->addr.sin_port); ++ if (!is_remount_fc(fc)) { ++ memcpy(sap, &data->addr, sizeof(data->addr)); ++ ctx->nfs_server.addrlen = sizeof(data->addr); ++ ctx->nfs_server.port = ntohs(data->addr.sin_port); ++ } ++ + if (sap->ss_family != AF_INET || + !nfs_verify_server_address(sap)) + goto out_no_address; +diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c +index 9a5d911a7edc7..c95c50328ced8 100644 +--- a/fs/nfs/nfs4state.c ++++ b/fs/nfs/nfs4state.c +@@ -2117,6 +2117,7 @@ static int nfs4_try_migration(struct nfs_server *server, const struct cred *cred + { + struct nfs_client *clp = server->nfs_client; + struct nfs4_fs_locations *locations = NULL; ++ struct nfs_fattr *fattr; + struct inode *inode; + struct page *page; + int status, result; +@@ -2126,19 +2127,16 @@ static int nfs4_try_migration(struct nfs_server *server, const struct cred *cred + (unsigned long long)server->fsid.minor, + clp->cl_hostname); + +- result = 0; + page = alloc_page(GFP_KERNEL); + locations = kmalloc(sizeof(struct nfs4_fs_locations), GFP_KERNEL); +- if (page == NULL || locations == NULL) { +- dprintk("<-- %s: no memory\n", __func__); +- goto out; +- } +- locations->fattr = nfs_alloc_fattr(); +- if (locations->fattr == NULL) { ++ fattr = nfs_alloc_fattr(); ++ if (page == NULL || locations == NULL || fattr == NULL) { + dprintk("<-- %s: no memory\n", __func__); ++ result = 0; + goto out; + } + ++ locations->fattr = fattr; + inode = d_inode(server->super->s_root); + result = nfs4_proc_get_locations(server, NFS_FH(inode), locations, + page, cred); +diff --git a/fs/nilfs2/ioctl.c b/fs/nilfs2/ioctl.c +index 40ffade49f389..53022bfe0b72d 100644 +--- a/fs/nilfs2/ioctl.c ++++ b/fs/nilfs2/ioctl.c +@@ -60,7 +60,7 @@ static int nilfs_ioctl_wrap_copy(struct the_nilfs *nilfs, + if (argv->v_nmembs == 0) + return 0; + +- if (argv->v_size > PAGE_SIZE) ++ if ((size_t)argv->v_size > PAGE_SIZE) + return -EINVAL; + + /* +diff --git a/fs/nilfs2/segment.c b/fs/nilfs2/segment.c +index a03e37207f487..2d74fb2297990 100644 +--- a/fs/nilfs2/segment.c ++++ b/fs/nilfs2/segment.c +@@ -2161,8 +2161,10 @@ static void nilfs_segctor_start_timer(struct nilfs_sc_info *sci) + { + spin_lock(&sci->sc_state_lock); + if (!(sci->sc_state & NILFS_SEGCTOR_COMMIT)) { +- sci->sc_timer.expires = jiffies + sci->sc_interval; +- add_timer(&sci->sc_timer); ++ if (sci->sc_task) { ++ sci->sc_timer.expires = jiffies + sci->sc_interval; ++ add_timer(&sci->sc_timer); ++ } + sci->sc_state |= NILFS_SEGCTOR_COMMIT; + } + spin_unlock(&sci->sc_state_lock); +@@ -2209,19 +2211,36 @@ static int nilfs_segctor_sync(struct nilfs_sc_info *sci) + struct nilfs_segctor_wait_request wait_req; + int err = 0; + +- spin_lock(&sci->sc_state_lock); + init_wait(&wait_req.wq); + wait_req.err = 0; + atomic_set(&wait_req.done, 0); ++ init_waitqueue_entry(&wait_req.wq, current); ++ ++ /* ++ * To prevent a race issue where completion notifications from the ++ * log writer thread are missed, increment the request sequence count ++ * "sc_seq_request" and insert a wait queue entry using the current ++ * sequence number into the "sc_wait_request" queue at the same time ++ * within the lock section of "sc_state_lock". ++ */ ++ spin_lock(&sci->sc_state_lock); + wait_req.seq = ++sci->sc_seq_request; ++ add_wait_queue(&sci->sc_wait_request, &wait_req.wq); + spin_unlock(&sci->sc_state_lock); + +- init_waitqueue_entry(&wait_req.wq, current); +- add_wait_queue(&sci->sc_wait_request, &wait_req.wq); +- set_current_state(TASK_INTERRUPTIBLE); + wake_up(&sci->sc_wait_daemon); + + for (;;) { ++ set_current_state(TASK_INTERRUPTIBLE); ++ ++ /* ++ * Synchronize only while the log writer thread is alive. ++ * Leave flushing out after the log writer thread exits to ++ * the cleanup work in nilfs_segctor_destroy(). ++ */ ++ if (!sci->sc_task) ++ break; ++ + if (atomic_read(&wait_req.done)) { + err = wait_req.err; + break; +@@ -2237,7 +2256,7 @@ static int nilfs_segctor_sync(struct nilfs_sc_info *sci) + return err; + } + +-static void nilfs_segctor_wakeup(struct nilfs_sc_info *sci, int err) ++static void nilfs_segctor_wakeup(struct nilfs_sc_info *sci, int err, bool force) + { + struct nilfs_segctor_wait_request *wrq, *n; + unsigned long flags; +@@ -2245,7 +2264,7 @@ static void nilfs_segctor_wakeup(struct nilfs_sc_info *sci, int err) + spin_lock_irqsave(&sci->sc_wait_request.lock, flags); + list_for_each_entry_safe(wrq, n, &sci->sc_wait_request.head, wq.entry) { + if (!atomic_read(&wrq->done) && +- nilfs_cnt32_ge(sci->sc_seq_done, wrq->seq)) { ++ (force || nilfs_cnt32_ge(sci->sc_seq_done, wrq->seq))) { + wrq->err = err; + atomic_set(&wrq->done, 1); + } +@@ -2363,10 +2382,21 @@ int nilfs_construct_dsync_segment(struct super_block *sb, struct inode *inode, + */ + static void nilfs_segctor_accept(struct nilfs_sc_info *sci) + { ++ bool thread_is_alive; ++ + spin_lock(&sci->sc_state_lock); + sci->sc_seq_accepted = sci->sc_seq_request; ++ thread_is_alive = (bool)sci->sc_task; + spin_unlock(&sci->sc_state_lock); +- del_timer_sync(&sci->sc_timer); ++ ++ /* ++ * This function does not race with the log writer thread's ++ * termination. Therefore, deleting sc_timer, which should not be ++ * done after the log writer thread exits, can be done safely outside ++ * the area protected by sc_state_lock. ++ */ ++ if (thread_is_alive) ++ del_timer_sync(&sci->sc_timer); + } + + /** +@@ -2383,7 +2413,7 @@ static void nilfs_segctor_notify(struct nilfs_sc_info *sci, int mode, int err) + if (mode == SC_LSEG_SR) { + sci->sc_state &= ~NILFS_SEGCTOR_COMMIT; + sci->sc_seq_done = sci->sc_seq_accepted; +- nilfs_segctor_wakeup(sci, err); ++ nilfs_segctor_wakeup(sci, err, false); + sci->sc_flush_request = 0; + } else { + if (mode == SC_FLUSH_FILE) +@@ -2392,7 +2422,7 @@ static void nilfs_segctor_notify(struct nilfs_sc_info *sci, int mode, int err) + sci->sc_flush_request &= ~FLUSH_DAT_BIT; + + /* re-enable timer if checkpoint creation was not done */ +- if ((sci->sc_state & NILFS_SEGCTOR_COMMIT) && ++ if ((sci->sc_state & NILFS_SEGCTOR_COMMIT) && sci->sc_task && + time_before(jiffies, sci->sc_timer.expires)) + add_timer(&sci->sc_timer); + } +@@ -2582,6 +2612,7 @@ static int nilfs_segctor_thread(void *arg) + int timeout = 0; + + sci->sc_timer_task = current; ++ timer_setup(&sci->sc_timer, nilfs_construction_timeout, 0); + + /* start sync. */ + sci->sc_task = current; +@@ -2648,6 +2679,7 @@ static int nilfs_segctor_thread(void *arg) + end_thread: + /* end sync. */ + sci->sc_task = NULL; ++ timer_shutdown_sync(&sci->sc_timer); + wake_up(&sci->sc_wait_task); /* for nilfs_segctor_kill_thread() */ + spin_unlock(&sci->sc_state_lock); + return 0; +@@ -2711,7 +2743,6 @@ static struct nilfs_sc_info *nilfs_segctor_new(struct super_block *sb, + INIT_LIST_HEAD(&sci->sc_gc_inodes); + INIT_LIST_HEAD(&sci->sc_iput_queue); + INIT_WORK(&sci->sc_iput_work, nilfs_iput_work_func); +- timer_setup(&sci->sc_timer, nilfs_construction_timeout, 0); + + sci->sc_interval = HZ * NILFS_SC_DEFAULT_TIMEOUT; + sci->sc_mjcp_freq = HZ * NILFS_SC_DEFAULT_SR_FREQ; +@@ -2765,6 +2796,13 @@ static void nilfs_segctor_destroy(struct nilfs_sc_info *sci) + || sci->sc_seq_request != sci->sc_seq_done); + spin_unlock(&sci->sc_state_lock); + ++ /* ++ * Forcibly wake up tasks waiting in nilfs_segctor_sync(), which can ++ * be called from delayed iput() via nilfs_evict_inode() and can race ++ * with the above log writer thread termination. ++ */ ++ nilfs_segctor_wakeup(sci, 0, true); ++ + if (flush_work(&sci->sc_iput_work)) + flag = true; + +@@ -2790,7 +2828,6 @@ static void nilfs_segctor_destroy(struct nilfs_sc_info *sci) + + down_write(&nilfs->ns_segctor_sem); + +- timer_shutdown_sync(&sci->sc_timer); + kfree(sci); + } + +diff --git a/fs/ntfs3/dir.c b/fs/ntfs3/dir.c +index 2c73ca469d514..ac8eb8657f1a9 100644 +--- a/fs/ntfs3/dir.c ++++ b/fs/ntfs3/dir.c +@@ -475,6 +475,7 @@ static int ntfs_readdir(struct file *file, struct dir_context *ctx) + vbo = (u64)bit << index_bits; + if (vbo >= i_size) { + ntfs_inode_err(dir, "Looks like your dir is corrupt"); ++ ctx->pos = eod; + err = -EINVAL; + goto out; + } +diff --git a/fs/ntfs3/fslog.c b/fs/ntfs3/fslog.c +index 855519713bf79..4085fe30bf481 100644 +--- a/fs/ntfs3/fslog.c ++++ b/fs/ntfs3/fslog.c +@@ -1184,7 +1184,8 @@ static int read_log_page(struct ntfs_log *log, u32 vbo, + static int log_read_rst(struct ntfs_log *log, bool first, + struct restart_info *info) + { +- u32 skip, vbo; ++ u32 skip; ++ u64 vbo; + struct RESTART_HDR *r_page = NULL; + + /* Determine which restart area we are looking for. */ +diff --git a/fs/ntfs3/index.c b/fs/ntfs3/index.c +index daabaad63aaf6..14284f0ed46aa 100644 +--- a/fs/ntfs3/index.c ++++ b/fs/ntfs3/index.c +@@ -1533,6 +1533,11 @@ static int indx_add_allocate(struct ntfs_index *indx, struct ntfs_inode *ni, + goto out1; + } + ++ if (data_size <= le64_to_cpu(alloc->nres.data_size)) { ++ /* Reuse index. */ ++ goto out; ++ } ++ + /* Increase allocation. */ + err = attr_set_size(ni, ATTR_ALLOC, in->name, in->name_len, + &indx->alloc_run, data_size, &data_size, true, +@@ -1546,6 +1551,7 @@ static int indx_add_allocate(struct ntfs_index *indx, struct ntfs_inode *ni, + if (in->name == I30_NAME) + i_size_write(&ni->vfs_inode, data_size); + ++out: + *vbn = bit << indx->idx2vbn_bits; + + return 0; +diff --git a/fs/ntfs3/inode.c b/fs/ntfs3/inode.c +index 34f2e16f3f5b6..6af705ccba65a 100644 +--- a/fs/ntfs3/inode.c ++++ b/fs/ntfs3/inode.c +@@ -37,7 +37,7 @@ static struct inode *ntfs_read_mft(struct inode *inode, + bool is_dir; + unsigned long ino = inode->i_ino; + u32 rp_fa = 0, asize, t32; +- u16 roff, rsize, names = 0; ++ u16 roff, rsize, names = 0, links = 0; + const struct ATTR_FILE_NAME *fname = NULL; + const struct INDEX_ROOT *root; + struct REPARSE_DATA_BUFFER rp; // 0x18 bytes +@@ -198,11 +198,12 @@ static struct inode *ntfs_read_mft(struct inode *inode, + rsize < SIZEOF_ATTRIBUTE_FILENAME) + goto out; + ++ names += 1; + fname = Add2Ptr(attr, roff); + if (fname->type == FILE_NAME_DOS) + goto next_attr; + +- names += 1; ++ links += 1; + if (name && name->len == fname->name_len && + !ntfs_cmp_names_cpu(name, (struct le_str *)&fname->name_len, + NULL, false)) +@@ -429,7 +430,7 @@ static struct inode *ntfs_read_mft(struct inode *inode, + ni->mi.dirty = true; + } + +- set_nlink(inode, names); ++ set_nlink(inode, links); + + if (S_ISDIR(mode)) { + ni->std_fa |= FILE_ATTRIBUTE_DIRECTORY; +@@ -570,13 +571,18 @@ static noinline int ntfs_get_block_vbo(struct inode *inode, u64 vbo, + clear_buffer_uptodate(bh); + + if (is_resident(ni)) { +- ni_lock(ni); +- err = attr_data_read_resident(ni, &folio->page); +- ni_unlock(ni); +- +- if (!err) +- set_buffer_uptodate(bh); ++ bh->b_blocknr = RESIDENT_LCN; + bh->b_size = block_size; ++ if (!folio) { ++ err = 0; ++ } else { ++ ni_lock(ni); ++ err = attr_data_read_resident(ni, &folio->page); ++ ni_unlock(ni); ++ ++ if (!err) ++ set_buffer_uptodate(bh); ++ } + return err; + } + +diff --git a/fs/ntfs3/ntfs.h b/fs/ntfs3/ntfs.h +index f61f5b3adb03a..b70288cc5f6fa 100644 +--- a/fs/ntfs3/ntfs.h ++++ b/fs/ntfs3/ntfs.h +@@ -59,7 +59,7 @@ struct GUID { + struct cpu_str { + u8 len; + u8 unused; +- u16 name[10]; ++ u16 name[]; + }; + + struct le_str { +diff --git a/fs/ntfs3/record.c b/fs/ntfs3/record.c +index 6aa3a9d44df1b..6c76503edc200 100644 +--- a/fs/ntfs3/record.c ++++ b/fs/ntfs3/record.c +@@ -534,16 +534,9 @@ bool mi_remove_attr(struct ntfs_inode *ni, struct mft_inode *mi, + if (aoff + asize > used) + return false; + +- if (ni && is_attr_indexed(attr)) { ++ if (ni && is_attr_indexed(attr) && attr->type == ATTR_NAME) { + u16 links = le16_to_cpu(ni->mi.mrec->hard_links); +- struct ATTR_FILE_NAME *fname = +- attr->type != ATTR_NAME ? +- NULL : +- resident_data_ex(attr, +- SIZEOF_ATTRIBUTE_FILENAME); +- if (fname && fname->type == FILE_NAME_DOS) { +- /* Do not decrease links count deleting DOS name. */ +- } else if (!links) { ++ if (!links) { + /* minor error. Not critical. */ + } else { + ni->mi.mrec->hard_links = cpu_to_le16(links - 1); +diff --git a/fs/ntfs3/super.c b/fs/ntfs3/super.c +index eb50602297406..10659817f98c7 100644 +--- a/fs/ntfs3/super.c ++++ b/fs/ntfs3/super.c +@@ -1804,8 +1804,6 @@ static int __init init_ntfs_fs(void) + { + int err; + +- pr_info("ntfs3: Max link count %u\n", NTFS_LINK_MAX); +- + if (IS_ENABLED(CONFIG_NTFS3_FS_POSIX_ACL)) + pr_info("ntfs3: Enabled Linux POSIX ACLs support\n"); + if (IS_ENABLED(CONFIG_NTFS3_64BIT_CLUSTER)) +diff --git a/fs/openpromfs/inode.c b/fs/openpromfs/inode.c +index b2457cb97fa00..e62e809a55265 100644 +--- a/fs/openpromfs/inode.c ++++ b/fs/openpromfs/inode.c +@@ -355,10 +355,10 @@ static struct inode *openprom_iget(struct super_block *sb, ino_t ino) + return inode; + } + +-static int openprom_remount(struct super_block *sb, int *flags, char *data) ++static int openpromfs_reconfigure(struct fs_context *fc) + { +- sync_filesystem(sb); +- *flags |= SB_NOATIME; ++ sync_filesystem(fc->root->d_sb); ++ fc->sb_flags |= SB_NOATIME; + return 0; + } + +@@ -366,7 +366,6 @@ static const struct super_operations openprom_sops = { + .alloc_inode = openprom_alloc_inode, + .free_inode = openprom_free_inode, + .statfs = simple_statfs, +- .remount_fs = openprom_remount, + }; + + static int openprom_fill_super(struct super_block *s, struct fs_context *fc) +@@ -415,6 +414,7 @@ static int openpromfs_get_tree(struct fs_context *fc) + + static const struct fs_context_operations openpromfs_context_ops = { + .get_tree = openpromfs_get_tree, ++ .reconfigure = openpromfs_reconfigure, + }; + + static int openpromfs_init_fs_context(struct fs_context *fc) +diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c +index 033fc0458a3d8..54602f0bed8be 100644 +--- a/fs/overlayfs/dir.c ++++ b/fs/overlayfs/dir.c +@@ -327,9 +327,6 @@ static int ovl_create_upper(struct dentry *dentry, struct inode *inode, + struct dentry *newdentry; + int err; + +- if (!attr->hardlink && !IS_POSIXACL(udir)) +- attr->mode &= ~current_umask(); +- + inode_lock_nested(udir, I_MUTEX_PARENT); + newdentry = ovl_create_real(ofs, udir, + ovl_lookup_upper(ofs, dentry->d_name.name, +diff --git a/fs/smb/server/mgmt/share_config.c b/fs/smb/server/mgmt/share_config.c +index a2f0a2edceb8a..e0a6b758094fc 100644 +--- a/fs/smb/server/mgmt/share_config.c ++++ b/fs/smb/server/mgmt/share_config.c +@@ -165,8 +165,12 @@ static struct ksmbd_share_config *share_config_request(struct unicode_map *um, + + share->path = kstrndup(ksmbd_share_config_path(resp), path_len, + GFP_KERNEL); +- if (share->path) ++ if (share->path) { + share->path_sz = strlen(share->path); ++ while (share->path_sz > 1 && ++ share->path[share->path_sz - 1] == '/') ++ share->path[--share->path_sz] = '\0'; ++ } + share->create_mask = resp->create_mask; + share->directory_mask = resp->directory_mask; + share->force_create_mode = resp->force_create_mode; +diff --git a/fs/smb/server/oplock.c b/fs/smb/server/oplock.c +index b7adb6549aa0f..7d17a14378e33 100644 +--- a/fs/smb/server/oplock.c ++++ b/fs/smb/server/oplock.c +@@ -614,19 +614,24 @@ static int oplock_break_pending(struct oplock_info *opinfo, int req_op_level) + if (opinfo->op_state == OPLOCK_CLOSING) + return -ENOENT; + else if (opinfo->level <= req_op_level) { +- if (opinfo->is_lease && +- opinfo->o_lease->state != +- (SMB2_LEASE_HANDLE_CACHING_LE | +- SMB2_LEASE_READ_CACHING_LE)) ++ if (opinfo->is_lease == false) ++ return 1; ++ ++ if (opinfo->o_lease->state != ++ (SMB2_LEASE_HANDLE_CACHING_LE | ++ SMB2_LEASE_READ_CACHING_LE)) + return 1; + } + } + + if (opinfo->level <= req_op_level) { +- if (opinfo->is_lease && +- opinfo->o_lease->state != +- (SMB2_LEASE_HANDLE_CACHING_LE | +- SMB2_LEASE_READ_CACHING_LE)) { ++ if (opinfo->is_lease == false) { ++ wake_up_oplock_break(opinfo); ++ return 1; ++ } ++ if (opinfo->o_lease->state != ++ (SMB2_LEASE_HANDLE_CACHING_LE | ++ SMB2_LEASE_READ_CACHING_LE)) { + wake_up_oplock_break(opinfo); + return 1; + } +diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c +index 1e536ae277618..6a15c5d64f415 100644 +--- a/fs/smb/server/smb2pdu.c ++++ b/fs/smb/server/smb2pdu.c +@@ -1926,7 +1926,7 @@ int smb2_tree_connect(struct ksmbd_work *work) + struct ksmbd_session *sess = work->sess; + char *treename = NULL, *name = NULL; + struct ksmbd_tree_conn_status status; +- struct ksmbd_share_config *share; ++ struct ksmbd_share_config *share = NULL; + int rc = -EINVAL; + + WORK_BUFFERS(work, req, rsp); +@@ -1988,7 +1988,7 @@ int smb2_tree_connect(struct ksmbd_work *work) + write_unlock(&sess->tree_conns_lock); + rsp->StructureSize = cpu_to_le16(16); + out_err1: +- if (server_conf.flags & KSMBD_GLOBAL_FLAG_DURABLE_HANDLE && ++ if (server_conf.flags & KSMBD_GLOBAL_FLAG_DURABLE_HANDLE && share && + test_share_config_flag(share, + KSMBD_SHARE_FLAG_CONTINUOUS_AVAILABILITY)) + rsp->Capabilities = SMB2_SHARE_CAP_CONTINUOUS_AVAILABILITY; +diff --git a/fs/tracefs/event_inode.c b/fs/tracefs/event_inode.c +index 56d1741fe0413..3b785f4ca95e4 100644 +--- a/fs/tracefs/event_inode.c ++++ b/fs/tracefs/event_inode.c +@@ -35,6 +35,18 @@ static DEFINE_MUTEX(eventfs_mutex); + /* Choose something "unique" ;-) */ + #define EVENTFS_FILE_INODE_INO 0x12c4e37 + ++struct eventfs_root_inode { ++ struct eventfs_inode ei; ++ struct inode *parent_inode; ++ struct dentry *events_dir; ++}; ++ ++static struct eventfs_root_inode *get_root_inode(struct eventfs_inode *ei) ++{ ++ WARN_ON_ONCE(!ei->is_events); ++ return container_of(ei, struct eventfs_root_inode, ei); ++} ++ + /* Just try to make something consistent and unique */ + static int eventfs_dir_ino(struct eventfs_inode *ei) + { +@@ -57,11 +69,25 @@ enum { + EVENTFS_SAVE_MODE = BIT(16), + EVENTFS_SAVE_UID = BIT(17), + EVENTFS_SAVE_GID = BIT(18), +- EVENTFS_TOPLEVEL = BIT(19), + }; + + #define EVENTFS_MODE_MASK (EVENTFS_SAVE_MODE - 1) + ++static void free_ei_rcu(struct rcu_head *rcu) ++{ ++ struct eventfs_inode *ei = container_of(rcu, struct eventfs_inode, rcu); ++ struct eventfs_root_inode *rei; ++ ++ kfree(ei->entry_attrs); ++ kfree_const(ei->name); ++ if (ei->is_events) { ++ rei = get_root_inode(ei); ++ kfree(rei); ++ } else { ++ kfree(ei); ++ } ++} ++ + /* + * eventfs_inode reference count management. + * +@@ -73,12 +99,17 @@ enum { + static void release_ei(struct kref *ref) + { + struct eventfs_inode *ei = container_of(ref, struct eventfs_inode, kref); ++ const struct eventfs_entry *entry; + + WARN_ON_ONCE(!ei->is_freed); + +- kfree(ei->entry_attrs); +- kfree_const(ei->name); +- kfree_rcu(ei, rcu); ++ for (int i = 0; i < ei->nr_entries; i++) { ++ entry = &ei->entries[i]; ++ if (entry->release) ++ entry->release(entry->name, ei->data); ++ } ++ ++ call_rcu(&ei->rcu, free_ei_rcu); + } + + static inline void put_ei(struct eventfs_inode *ei) +@@ -95,6 +126,18 @@ static inline void free_ei(struct eventfs_inode *ei) + } + } + ++/* ++ * Called when creation of an ei fails, do not call release() functions. ++ */ ++static inline void cleanup_ei(struct eventfs_inode *ei) ++{ ++ if (ei) { ++ /* Set nr_entries to 0 to prevent release() function being called */ ++ ei->nr_entries = 0; ++ free_ei(ei); ++ } ++} ++ + static inline struct eventfs_inode *get_ei(struct eventfs_inode *ei) + { + if (ei) +@@ -182,18 +225,25 @@ static int eventfs_set_attr(struct mnt_idmap *idmap, struct dentry *dentry, + return ret; + } + +-static void update_top_events_attr(struct eventfs_inode *ei, struct super_block *sb) ++static void update_events_attr(struct eventfs_inode *ei, struct super_block *sb) + { +- struct inode *root; ++ struct eventfs_root_inode *rei; ++ struct inode *parent; + +- /* Only update if the "events" was on the top level */ +- if (!ei || !(ei->attr.mode & EVENTFS_TOPLEVEL)) +- return; ++ rei = get_root_inode(ei); ++ ++ /* Use the parent inode permissions unless root set its permissions */ ++ parent = rei->parent_inode; ++ ++ if (rei->ei.attr.mode & EVENTFS_SAVE_UID) ++ ei->attr.uid = rei->ei.attr.uid; ++ else ++ ei->attr.uid = parent->i_uid; + +- /* Get the tracefs root inode. */ +- root = d_inode(sb->s_root); +- ei->attr.uid = root->i_uid; +- ei->attr.gid = root->i_gid; ++ if (rei->ei.attr.mode & EVENTFS_SAVE_GID) ++ ei->attr.gid = rei->ei.attr.gid; ++ else ++ ei->attr.gid = parent->i_gid; + } + + static void set_top_events_ownership(struct inode *inode) +@@ -202,10 +252,10 @@ static void set_top_events_ownership(struct inode *inode) + struct eventfs_inode *ei = ti->private; + + /* The top events directory doesn't get automatically updated */ +- if (!ei || !ei->is_events || !(ei->attr.mode & EVENTFS_TOPLEVEL)) ++ if (!ei || !ei->is_events) + return; + +- update_top_events_attr(ei, inode->i_sb); ++ update_events_attr(ei, inode->i_sb); + + if (!(ei->attr.mode & EVENTFS_SAVE_UID)) + inode->i_uid = ei->attr.uid; +@@ -234,7 +284,7 @@ static int eventfs_permission(struct mnt_idmap *idmap, + return generic_permission(idmap, inode, mask); + } + +-static const struct inode_operations eventfs_root_dir_inode_operations = { ++static const struct inode_operations eventfs_dir_inode_operations = { + .lookup = eventfs_root_lookup, + .setattr = eventfs_set_attr, + .getattr = eventfs_get_attr, +@@ -302,7 +352,7 @@ static struct eventfs_inode *eventfs_find_events(struct dentry *dentry) + // Walk upwards until you find the events inode + } while (!ei->is_events); + +- update_top_events_attr(ei, dentry->d_sb); ++ update_events_attr(ei, dentry->d_sb); + + return ei; + } +@@ -406,7 +456,7 @@ static struct dentry *lookup_dir_entry(struct dentry *dentry, + update_inode_attr(dentry, inode, &ei->attr, + S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO); + +- inode->i_op = &eventfs_root_dir_inode_operations; ++ inode->i_op = &eventfs_dir_inode_operations; + inode->i_fop = &eventfs_file_operations; + + /* All directories will have the same inode number */ +@@ -423,19 +473,43 @@ static struct dentry *lookup_dir_entry(struct dentry *dentry, + return NULL; + } + ++static inline struct eventfs_inode *init_ei(struct eventfs_inode *ei, const char *name) ++{ ++ ei->name = kstrdup_const(name, GFP_KERNEL); ++ if (!ei->name) ++ return NULL; ++ kref_init(&ei->kref); ++ return ei; ++} ++ + static inline struct eventfs_inode *alloc_ei(const char *name) + { + struct eventfs_inode *ei = kzalloc(sizeof(*ei), GFP_KERNEL); ++ struct eventfs_inode *result; + + if (!ei) + return NULL; + +- ei->name = kstrdup_const(name, GFP_KERNEL); +- if (!ei->name) { ++ result = init_ei(ei, name); ++ if (!result) + kfree(ei); ++ ++ return result; ++} ++ ++static inline struct eventfs_inode *alloc_root_ei(const char *name) ++{ ++ struct eventfs_root_inode *rei = kzalloc(sizeof(*rei), GFP_KERNEL); ++ struct eventfs_inode *ei; ++ ++ if (!rei) + return NULL; +- } +- kref_init(&ei->kref); ++ ++ rei->ei.is_events = 1; ++ ei = init_ei(&rei->ei, name); ++ if (!ei) ++ kfree(rei); ++ + return ei; + } + +@@ -701,7 +775,7 @@ struct eventfs_inode *eventfs_create_dir(const char *name, struct eventfs_inode + + /* Was the parent freed? */ + if (list_empty(&ei->list)) { +- free_ei(ei); ++ cleanup_ei(ei); + ei = NULL; + } + return ei; +@@ -724,6 +798,7 @@ struct eventfs_inode *eventfs_create_events_dir(const char *name, struct dentry + int size, void *data) + { + struct dentry *dentry = tracefs_start_creating(name, parent); ++ struct eventfs_root_inode *rei; + struct eventfs_inode *ei; + struct tracefs_inode *ti; + struct inode *inode; +@@ -736,7 +811,7 @@ struct eventfs_inode *eventfs_create_events_dir(const char *name, struct dentry + if (IS_ERR(dentry)) + return ERR_CAST(dentry); + +- ei = alloc_ei(name); ++ ei = alloc_root_ei(name); + if (!ei) + goto fail; + +@@ -745,39 +820,38 @@ struct eventfs_inode *eventfs_create_events_dir(const char *name, struct dentry + goto fail; + + // Note: we have a ref to the dentry from tracefs_start_creating() +- ei->events_dir = dentry; ++ rei = get_root_inode(ei); ++ rei->events_dir = dentry; ++ rei->parent_inode = d_inode(dentry->d_sb->s_root); ++ + ei->entries = entries; + ei->nr_entries = size; +- ei->is_events = 1; + ei->data = data; + + /* Save the ownership of this directory */ + uid = d_inode(dentry->d_parent)->i_uid; + gid = d_inode(dentry->d_parent)->i_gid; + +- /* +- * If the events directory is of the top instance, then parent +- * is NULL. Set the attr.mode to reflect this and its permissions will +- * default to the tracefs root dentry. +- */ +- if (!parent) +- ei->attr.mode = EVENTFS_TOPLEVEL; +- +- /* This is used as the default ownership of the files and directories */ + ei->attr.uid = uid; + ei->attr.gid = gid; + ++ /* ++ * When the "events" directory is created, it takes on the ++ * permissions of its parent. But can be reset on remount. ++ */ ++ ei->attr.mode |= EVENTFS_SAVE_UID | EVENTFS_SAVE_GID; ++ + INIT_LIST_HEAD(&ei->children); + INIT_LIST_HEAD(&ei->list); + + ti = get_tracefs(inode); +- ti->flags |= TRACEFS_EVENT_INODE | TRACEFS_EVENT_TOP_INODE; ++ ti->flags |= TRACEFS_EVENT_INODE; + ti->private = ei; + + inode->i_mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO; + inode->i_uid = uid; + inode->i_gid = gid; +- inode->i_op = &eventfs_root_dir_inode_operations; ++ inode->i_op = &eventfs_dir_inode_operations; + inode->i_fop = &eventfs_file_operations; + + dentry->d_fsdata = get_ei(ei); +@@ -800,7 +874,7 @@ struct eventfs_inode *eventfs_create_events_dir(const char *name, struct dentry + return ei; + + fail: +- free_ei(ei); ++ cleanup_ei(ei); + tracefs_failed_creating(dentry); + return ERR_PTR(-ENOMEM); + } +@@ -859,13 +933,15 @@ void eventfs_remove_dir(struct eventfs_inode *ei) + */ + void eventfs_remove_events_dir(struct eventfs_inode *ei) + { ++ struct eventfs_root_inode *rei; + struct dentry *dentry; + +- dentry = ei->events_dir; ++ rei = get_root_inode(ei); ++ dentry = rei->events_dir; + if (!dentry) + return; + +- ei->events_dir = NULL; ++ rei->events_dir = NULL; + eventfs_remove_dir(ei); + + /* +diff --git a/fs/tracefs/internal.h b/fs/tracefs/internal.h +index 824cbe83679cc..f704d8348357e 100644 +--- a/fs/tracefs/internal.h ++++ b/fs/tracefs/internal.h +@@ -4,10 +4,9 @@ + + enum { + TRACEFS_EVENT_INODE = BIT(1), +- TRACEFS_EVENT_TOP_INODE = BIT(2), +- TRACEFS_GID_PERM_SET = BIT(3), +- TRACEFS_UID_PERM_SET = BIT(4), +- TRACEFS_INSTANCE_INODE = BIT(5), ++ TRACEFS_GID_PERM_SET = BIT(2), ++ TRACEFS_UID_PERM_SET = BIT(3), ++ TRACEFS_INSTANCE_INODE = BIT(4), + }; + + struct tracefs_inode { +@@ -40,7 +39,6 @@ struct eventfs_attr { + * @children: link list into the child eventfs_inode + * @entries: the array of entries representing the files in the directory + * @name: the name of the directory to create +- * @events_dir: the dentry of the events directory + * @entry_attrs: Saved mode and ownership of the @d_children + * @data: The private data to pass to the callbacks + * @attr: Saved mode and ownership of eventfs_inode itself +@@ -58,7 +56,6 @@ struct eventfs_inode { + struct list_head children; + const struct eventfs_entry *entries; + const char *name; +- struct dentry *events_dir; + struct eventfs_attr *entry_attrs; + void *data; + struct eventfs_attr attr; +diff --git a/fs/udf/inode.c b/fs/udf/inode.c +index a17a6184cc39e..1ff8c1f17f9e6 100644 +--- a/fs/udf/inode.c ++++ b/fs/udf/inode.c +@@ -341,7 +341,7 @@ const struct address_space_operations udf_aops = { + */ + int udf_expand_file_adinicb(struct inode *inode) + { +- struct page *page; ++ struct folio *folio; + struct udf_inode_info *iinfo = UDF_I(inode); + int err; + +@@ -357,12 +357,13 @@ int udf_expand_file_adinicb(struct inode *inode) + return 0; + } + +- page = find_or_create_page(inode->i_mapping, 0, GFP_NOFS); +- if (!page) +- return -ENOMEM; ++ folio = __filemap_get_folio(inode->i_mapping, 0, ++ FGP_LOCK | FGP_ACCESSED | FGP_CREAT, GFP_KERNEL); ++ if (IS_ERR(folio)) ++ return PTR_ERR(folio); + +- if (!PageUptodate(page)) +- udf_adinicb_readpage(page); ++ if (!folio_test_uptodate(folio)) ++ udf_adinicb_readpage(&folio->page); + down_write(&iinfo->i_data_sem); + memset(iinfo->i_data + iinfo->i_lenEAttr, 0x00, + iinfo->i_lenAlloc); +@@ -371,22 +372,22 @@ int udf_expand_file_adinicb(struct inode *inode) + iinfo->i_alloc_type = ICBTAG_FLAG_AD_SHORT; + else + iinfo->i_alloc_type = ICBTAG_FLAG_AD_LONG; +- set_page_dirty(page); +- unlock_page(page); ++ folio_mark_dirty(folio); ++ folio_unlock(folio); + up_write(&iinfo->i_data_sem); + err = filemap_fdatawrite(inode->i_mapping); + if (err) { + /* Restore everything back so that we don't lose data... */ +- lock_page(page); ++ folio_lock(folio); + down_write(&iinfo->i_data_sem); +- memcpy_to_page(page, 0, iinfo->i_data + iinfo->i_lenEAttr, +- inode->i_size); +- unlock_page(page); ++ memcpy_from_folio(iinfo->i_data + iinfo->i_lenEAttr, ++ folio, 0, inode->i_size); ++ folio_unlock(folio); + iinfo->i_alloc_type = ICBTAG_FLAG_AD_IN_ICB; + iinfo->i_lenAlloc = inode->i_size; + up_write(&iinfo->i_data_sem); + } +- put_page(page); ++ folio_put(folio); + mark_inode_dirty(inode); + + return err; +diff --git a/include/drm/display/drm_dp_helper.h b/include/drm/display/drm_dp_helper.h +index 86f24a759268a..65d76f9e84305 100644 +--- a/include/drm/display/drm_dp_helper.h ++++ b/include/drm/display/drm_dp_helper.h +@@ -449,9 +449,15 @@ struct drm_dp_aux { + * @is_remote: Is this AUX CH actually using sideband messaging. + */ + bool is_remote; ++ ++ /** ++ * @powered_down: If true then the remote endpoint is powered down. ++ */ ++ bool powered_down; + }; + + int drm_dp_dpcd_probe(struct drm_dp_aux *aux, unsigned int offset); ++void drm_dp_dpcd_set_powered(struct drm_dp_aux *aux, bool powered); + ssize_t drm_dp_dpcd_read(struct drm_dp_aux *aux, unsigned int offset, + void *buffer, size_t size); + ssize_t drm_dp_dpcd_write(struct drm_dp_aux *aux, unsigned int offset, +diff --git a/include/drm/drm_displayid.h b/include/drm/drm_displayid.h +index 566497eeb3b81..bc1f6b378195f 100644 +--- a/include/drm/drm_displayid.h ++++ b/include/drm/drm_displayid.h +@@ -30,7 +30,6 @@ struct drm_edid; + #define VESA_IEEE_OUI 0x3a0292 + + /* DisplayID Structure versions */ +-#define DISPLAY_ID_STRUCTURE_VER_12 0x12 + #define DISPLAY_ID_STRUCTURE_VER_20 0x20 + + /* DisplayID Structure v1r2 Data Blocks */ +diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h +index c0aec0d4d664e..3011d33eccbd2 100644 +--- a/include/drm/drm_mipi_dsi.h ++++ b/include/drm/drm_mipi_dsi.h +@@ -241,9 +241,9 @@ int mipi_dsi_shutdown_peripheral(struct mipi_dsi_device *dsi); + int mipi_dsi_turn_on_peripheral(struct mipi_dsi_device *dsi); + int mipi_dsi_set_maximum_return_packet_size(struct mipi_dsi_device *dsi, + u16 value); +-ssize_t mipi_dsi_compression_mode(struct mipi_dsi_device *dsi, bool enable); +-ssize_t mipi_dsi_picture_parameter_set(struct mipi_dsi_device *dsi, +- const struct drm_dsc_picture_parameter_set *pps); ++int mipi_dsi_compression_mode(struct mipi_dsi_device *dsi, bool enable); ++int mipi_dsi_picture_parameter_set(struct mipi_dsi_device *dsi, ++ const struct drm_dsc_picture_parameter_set *pps); + + ssize_t mipi_dsi_generic_write(struct mipi_dsi_device *dsi, const void *payload, + size_t size); +diff --git a/include/linux/acpi.h b/include/linux/acpi.h +index afd94c9b8b8af..1b76d2f83eac6 100644 +--- a/include/linux/acpi.h ++++ b/include/linux/acpi.h +@@ -571,8 +571,8 @@ acpi_status acpi_run_osc(acpi_handle handle, struct acpi_osc_context *context); + #define OSC_SB_PCLPI_SUPPORT 0x00000080 + #define OSC_SB_OSLPI_SUPPORT 0x00000100 + #define OSC_SB_CPC_DIVERSE_HIGH_SUPPORT 0x00001000 +-#define OSC_SB_GENERIC_INITIATOR_SUPPORT 0x00002000 + #define OSC_SB_CPC_FLEXIBLE_ADR_SPACE 0x00004000 ++#define OSC_SB_GENERIC_INITIATOR_SUPPORT 0x00020000 + #define OSC_SB_NATIVE_USB4_SUPPORT 0x00040000 + #define OSC_SB_PRM_SUPPORT 0x00200000 + #define OSC_SB_FFH_OPR_SUPPORT 0x00400000 +diff --git a/include/linux/bitops.h b/include/linux/bitops.h +index 2ba557e067fe6..f7f5a783da2aa 100644 +--- a/include/linux/bitops.h ++++ b/include/linux/bitops.h +@@ -80,6 +80,7 @@ __check_bitop_pr(__test_and_set_bit); + __check_bitop_pr(__test_and_clear_bit); + __check_bitop_pr(__test_and_change_bit); + __check_bitop_pr(test_bit); ++__check_bitop_pr(test_bit_acquire); + + #undef __check_bitop_pr + +diff --git a/include/linux/counter.h b/include/linux/counter.h +index 702e9108bbb44..b767b5c821f58 100644 +--- a/include/linux/counter.h ++++ b/include/linux/counter.h +@@ -359,7 +359,6 @@ struct counter_ops { + * @num_counts: number of Counts specified in @counts + * @ext: optional array of Counter device extensions + * @num_ext: number of Counter device extensions specified in @ext +- * @priv: optional private data supplied by driver + * @dev: internal device structure + * @chrdev: internal character device structure + * @events_list: list of current watching Counter events +diff --git a/include/linux/cpu.h b/include/linux/cpu.h +index e990c180282e7..a7d91a167a8b6 100644 +--- a/include/linux/cpu.h ++++ b/include/linux/cpu.h +@@ -214,7 +214,18 @@ void cpuhp_report_idle_dead(void); + static inline void cpuhp_report_idle_dead(void) { } + #endif /* #ifdef CONFIG_HOTPLUG_CPU */ + ++#ifdef CONFIG_CPU_MITIGATIONS + extern bool cpu_mitigations_off(void); + extern bool cpu_mitigations_auto_nosmt(void); ++#else ++static inline bool cpu_mitigations_off(void) ++{ ++ return true; ++} ++static inline bool cpu_mitigations_auto_nosmt(void) ++{ ++ return false; ++} ++#endif + + #endif /* _LINUX_CPU_H_ */ +diff --git a/include/linux/dev_printk.h b/include/linux/dev_printk.h +index 6bfe70decc9fb..ae80a303c216b 100644 +--- a/include/linux/dev_printk.h ++++ b/include/linux/dev_printk.h +@@ -129,6 +129,16 @@ void _dev_info(const struct device *dev, const char *fmt, ...) + _dev_printk(level, dev, fmt, ##__VA_ARGS__); \ + }) + ++/* ++ * Dummy dev_printk for disabled debugging statements to use whilst maintaining ++ * gcc's format checking. ++ */ ++#define dev_no_printk(level, dev, fmt, ...) \ ++ ({ \ ++ if (0) \ ++ _dev_printk(level, dev, fmt, ##__VA_ARGS__); \ ++ }) ++ + /* + * #defines for all the dev_ macros to prefix with whatever + * possible use of #define dev_fmt(fmt) ... +@@ -158,10 +168,7 @@ void _dev_info(const struct device *dev, const char *fmt, ...) + dev_printk(KERN_DEBUG, dev, dev_fmt(fmt), ##__VA_ARGS__) + #else + #define dev_dbg(dev, fmt, ...) \ +-({ \ +- if (0) \ +- dev_printk(KERN_DEBUG, dev, dev_fmt(fmt), ##__VA_ARGS__); \ +-}) ++ dev_no_printk(KERN_DEBUG, dev, dev_fmt(fmt), ##__VA_ARGS__) + #endif + + #ifdef CONFIG_PRINTK +@@ -247,20 +254,14 @@ do { \ + } while (0) + #else + #define dev_dbg_ratelimited(dev, fmt, ...) \ +-do { \ +- if (0) \ +- dev_printk(KERN_DEBUG, dev, dev_fmt(fmt), ##__VA_ARGS__); \ +-} while (0) ++ dev_no_printk(KERN_DEBUG, dev, dev_fmt(fmt), ##__VA_ARGS__) + #endif + + #ifdef VERBOSE_DEBUG + #define dev_vdbg dev_dbg + #else + #define dev_vdbg(dev, fmt, ...) \ +-({ \ +- if (0) \ +- dev_printk(KERN_DEBUG, dev, dev_fmt(fmt), ##__VA_ARGS__); \ +-}) ++ dev_no_printk(KERN_DEBUG, dev, dev_fmt(fmt), ##__VA_ARGS__) + #endif + + /* +diff --git a/include/linux/f2fs_fs.h b/include/linux/f2fs_fs.h +index 5aa00bcd42fe9..3b04657787d09 100644 +--- a/include/linux/f2fs_fs.h ++++ b/include/linux/f2fs_fs.h +@@ -41,12 +41,6 @@ + + #define F2FS_ENC_UTF8_12_1 1 + +-#define F2FS_IO_SIZE(sbi) BIT(F2FS_OPTION(sbi).write_io_size_bits) /* Blocks */ +-#define F2FS_IO_SIZE_KB(sbi) BIT(F2FS_OPTION(sbi).write_io_size_bits + 2) /* KB */ +-#define F2FS_IO_SIZE_BITS(sbi) (F2FS_OPTION(sbi).write_io_size_bits) /* power of 2 */ +-#define F2FS_IO_SIZE_MASK(sbi) (F2FS_IO_SIZE(sbi) - 1) +-#define F2FS_IO_ALIGNED(sbi) (F2FS_IO_SIZE(sbi) > 1) +- + /* This flag is used by node and meta inodes, and by recovery */ + #define GFP_F2FS_ZERO (GFP_NOFS | __GFP_ZERO) + +diff --git a/include/linux/fb.h b/include/linux/fb.h +index c14576458228a..322b4d20afa55 100644 +--- a/include/linux/fb.h ++++ b/include/linux/fb.h +@@ -690,6 +690,10 @@ extern int fb_deferred_io_fsync(struct file *file, loff_t start, + __FB_GEN_DEFAULT_DEFERRED_OPS_RDWR(__prefix, __damage_range, sys) \ + __FB_GEN_DEFAULT_DEFERRED_OPS_DRAW(__prefix, __damage_area, sys) + ++#define FB_GEN_DEFAULT_DEFERRED_DMAMEM_OPS(__prefix, __damage_range, __damage_area) \ ++ __FB_GEN_DEFAULT_DEFERRED_OPS_RDWR(__prefix, __damage_range, sys) \ ++ __FB_GEN_DEFAULT_DEFERRED_OPS_DRAW(__prefix, __damage_area, sys) ++ + /* + * Initializes struct fb_ops for deferred I/O. + */ +diff --git a/include/linux/fortify-string.h b/include/linux/fortify-string.h +index da51a83b28293..f7e1895367fa1 100644 +--- a/include/linux/fortify-string.h ++++ b/include/linux/fortify-string.h +@@ -31,17 +31,30 @@ void __write_overflow_field(size_t avail, size_t wanted) __compiletime_warning(" + __ret; \ + }) + +-#if defined(CONFIG_KASAN_GENERIC) || defined(CONFIG_KASAN_SW_TAGS) ++#if defined(__SANITIZE_ADDRESS__) ++ ++#if !defined(CONFIG_CC_HAS_KASAN_MEMINTRINSIC_PREFIX) && !defined(CONFIG_GENERIC_ENTRY) ++extern void *__underlying_memset(void *p, int c, __kernel_size_t size) __RENAME(memset); ++extern void *__underlying_memmove(void *p, const void *q, __kernel_size_t size) __RENAME(memmove); ++extern void *__underlying_memcpy(void *p, const void *q, __kernel_size_t size) __RENAME(memcpy); ++#elif defined(CONFIG_KASAN_GENERIC) ++extern void *__underlying_memset(void *p, int c, __kernel_size_t size) __RENAME(__asan_memset); ++extern void *__underlying_memmove(void *p, const void *q, __kernel_size_t size) __RENAME(__asan_memmove); ++extern void *__underlying_memcpy(void *p, const void *q, __kernel_size_t size) __RENAME(__asan_memcpy); ++#else /* CONFIG_KASAN_SW_TAGS */ ++extern void *__underlying_memset(void *p, int c, __kernel_size_t size) __RENAME(__hwasan_memset); ++extern void *__underlying_memmove(void *p, const void *q, __kernel_size_t size) __RENAME(__hwasan_memmove); ++extern void *__underlying_memcpy(void *p, const void *q, __kernel_size_t size) __RENAME(__hwasan_memcpy); ++#endif ++ + extern void *__underlying_memchr(const void *p, int c, __kernel_size_t size) __RENAME(memchr); + extern int __underlying_memcmp(const void *p, const void *q, __kernel_size_t size) __RENAME(memcmp); +-extern void *__underlying_memcpy(void *p, const void *q, __kernel_size_t size) __RENAME(memcpy); +-extern void *__underlying_memmove(void *p, const void *q, __kernel_size_t size) __RENAME(memmove); +-extern void *__underlying_memset(void *p, int c, __kernel_size_t size) __RENAME(memset); + extern char *__underlying_strcat(char *p, const char *q) __RENAME(strcat); + extern char *__underlying_strcpy(char *p, const char *q) __RENAME(strcpy); + extern __kernel_size_t __underlying_strlen(const char *p) __RENAME(strlen); + extern char *__underlying_strncat(char *p, const char *q, __kernel_size_t count) __RENAME(strncat); + extern char *__underlying_strncpy(char *p, const char *q, __kernel_size_t size) __RENAME(strncpy); ++ + #else + + #if defined(__SANITIZE_MEMORY__) +@@ -66,6 +79,7 @@ extern char *__underlying_strncpy(char *p, const char *q, __kernel_size_t size) + #define __underlying_strlen __builtin_strlen + #define __underlying_strncat __builtin_strncat + #define __underlying_strncpy __builtin_strncpy ++ + #endif + + /** +diff --git a/include/linux/fpga/fpga-bridge.h b/include/linux/fpga/fpga-bridge.h +index 223da48a6d18b..94c4edd047e54 100644 +--- a/include/linux/fpga/fpga-bridge.h ++++ b/include/linux/fpga/fpga-bridge.h +@@ -45,6 +45,7 @@ struct fpga_bridge_info { + * @dev: FPGA bridge device + * @mutex: enforces exclusive reference to bridge + * @br_ops: pointer to struct of FPGA bridge ops ++ * @br_ops_owner: module containing the br_ops + * @info: fpga image specific information + * @node: FPGA bridge list node + * @priv: low level driver private date +@@ -54,6 +55,7 @@ struct fpga_bridge { + struct device dev; + struct mutex mutex; /* for exclusive reference to bridge */ + const struct fpga_bridge_ops *br_ops; ++ struct module *br_ops_owner; + struct fpga_image_info *info; + struct list_head node; + void *priv; +@@ -79,10 +81,12 @@ int of_fpga_bridge_get_to_list(struct device_node *np, + struct fpga_image_info *info, + struct list_head *bridge_list); + ++#define fpga_bridge_register(parent, name, br_ops, priv) \ ++ __fpga_bridge_register(parent, name, br_ops, priv, THIS_MODULE) + struct fpga_bridge * +-fpga_bridge_register(struct device *parent, const char *name, +- const struct fpga_bridge_ops *br_ops, +- void *priv); ++__fpga_bridge_register(struct device *parent, const char *name, ++ const struct fpga_bridge_ops *br_ops, void *priv, ++ struct module *owner); + void fpga_bridge_unregister(struct fpga_bridge *br); + + #endif /* _LINUX_FPGA_BRIDGE_H */ +diff --git a/include/linux/fpga/fpga-mgr.h b/include/linux/fpga/fpga-mgr.h +index 54f63459efd6e..0d4fe068f3d8a 100644 +--- a/include/linux/fpga/fpga-mgr.h ++++ b/include/linux/fpga/fpga-mgr.h +@@ -201,6 +201,7 @@ struct fpga_manager_ops { + * @state: state of fpga manager + * @compat_id: FPGA manager id for compatibility check. + * @mops: pointer to struct of fpga manager ops ++ * @mops_owner: module containing the mops + * @priv: low level driver private date + */ + struct fpga_manager { +@@ -210,6 +211,7 @@ struct fpga_manager { + enum fpga_mgr_states state; + struct fpga_compat_id *compat_id; + const struct fpga_manager_ops *mops; ++ struct module *mops_owner; + void *priv; + }; + +@@ -230,18 +232,30 @@ struct fpga_manager *fpga_mgr_get(struct device *dev); + + void fpga_mgr_put(struct fpga_manager *mgr); + ++#define fpga_mgr_register_full(parent, info) \ ++ __fpga_mgr_register_full(parent, info, THIS_MODULE) + struct fpga_manager * +-fpga_mgr_register_full(struct device *parent, const struct fpga_manager_info *info); ++__fpga_mgr_register_full(struct device *parent, const struct fpga_manager_info *info, ++ struct module *owner); + ++#define fpga_mgr_register(parent, name, mops, priv) \ ++ __fpga_mgr_register(parent, name, mops, priv, THIS_MODULE) + struct fpga_manager * +-fpga_mgr_register(struct device *parent, const char *name, +- const struct fpga_manager_ops *mops, void *priv); ++__fpga_mgr_register(struct device *parent, const char *name, ++ const struct fpga_manager_ops *mops, void *priv, struct module *owner); ++ + void fpga_mgr_unregister(struct fpga_manager *mgr); + ++#define devm_fpga_mgr_register_full(parent, info) \ ++ __devm_fpga_mgr_register_full(parent, info, THIS_MODULE) + struct fpga_manager * +-devm_fpga_mgr_register_full(struct device *parent, const struct fpga_manager_info *info); ++__devm_fpga_mgr_register_full(struct device *parent, const struct fpga_manager_info *info, ++ struct module *owner); ++#define devm_fpga_mgr_register(parent, name, mops, priv) \ ++ __devm_fpga_mgr_register(parent, name, mops, priv, THIS_MODULE) + struct fpga_manager * +-devm_fpga_mgr_register(struct device *parent, const char *name, +- const struct fpga_manager_ops *mops, void *priv); ++__devm_fpga_mgr_register(struct device *parent, const char *name, ++ const struct fpga_manager_ops *mops, void *priv, ++ struct module *owner); + + #endif /*_LINUX_FPGA_MGR_H */ +diff --git a/include/linux/fpga/fpga-region.h b/include/linux/fpga/fpga-region.h +index 9d4d32909340a..5fbc05fe70a6b 100644 +--- a/include/linux/fpga/fpga-region.h ++++ b/include/linux/fpga/fpga-region.h +@@ -36,6 +36,7 @@ struct fpga_region_info { + * @mgr: FPGA manager + * @info: FPGA image info + * @compat_id: FPGA region id for compatibility check. ++ * @ops_owner: module containing the get_bridges function + * @priv: private data + * @get_bridges: optional function to get bridges to a list + */ +@@ -46,6 +47,7 @@ struct fpga_region { + struct fpga_manager *mgr; + struct fpga_image_info *info; + struct fpga_compat_id *compat_id; ++ struct module *ops_owner; + void *priv; + int (*get_bridges)(struct fpga_region *region); + }; +@@ -58,12 +60,17 @@ fpga_region_class_find(struct device *start, const void *data, + + int fpga_region_program_fpga(struct fpga_region *region); + ++#define fpga_region_register_full(parent, info) \ ++ __fpga_region_register_full(parent, info, THIS_MODULE) + struct fpga_region * +-fpga_region_register_full(struct device *parent, const struct fpga_region_info *info); ++__fpga_region_register_full(struct device *parent, const struct fpga_region_info *info, ++ struct module *owner); + ++#define fpga_region_register(parent, mgr, get_bridges) \ ++ __fpga_region_register(parent, mgr, get_bridges, THIS_MODULE) + struct fpga_region * +-fpga_region_register(struct device *parent, struct fpga_manager *mgr, +- int (*get_bridges)(struct fpga_region *)); ++__fpga_region_register(struct device *parent, struct fpga_manager *mgr, ++ int (*get_bridges)(struct fpga_region *), struct module *owner); + void fpga_region_unregister(struct fpga_region *region); + + #endif /* _FPGA_REGION_H */ +diff --git a/include/linux/i3c/device.h b/include/linux/i3c/device.h +index 90fa83464f003..ef6217da8253b 100644 +--- a/include/linux/i3c/device.h ++++ b/include/linux/i3c/device.h +@@ -54,6 +54,7 @@ enum i3c_hdr_mode { + * struct i3c_priv_xfer - I3C SDR private transfer + * @rnw: encodes the transfer direction. true for a read, false for a write + * @len: transfer length in bytes of the transfer ++ * @actual_len: actual length in bytes are transferred by the controller + * @data: input/output buffer + * @data.in: input buffer. Must point to a DMA-able buffer + * @data.out: output buffer. Must point to a DMA-able buffer +@@ -62,6 +63,7 @@ enum i3c_hdr_mode { + struct i3c_priv_xfer { + u8 rnw; + u16 len; ++ u16 actual_len; + union { + void *in; + const void *out; +diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h +index 2fa186258e359..aaaa5b90bfe25 100644 +--- a/include/linux/ieee80211.h ++++ b/include/linux/ieee80211.h +@@ -5081,7 +5081,7 @@ static inline bool ieee80211_mle_basic_sta_prof_size_ok(const u8 *data, + info_len += 1; + + return prof->sta_info_len >= info_len && +- fixed + prof->sta_info_len <= len; ++ fixed + prof->sta_info_len - 1 <= len; + } + + /** +diff --git a/include/linux/iio/adc/adi-axi-adc.h b/include/linux/iio/adc/adi-axi-adc.h +deleted file mode 100644 +index b7904992d5619..0000000000000 +--- a/include/linux/iio/adc/adi-axi-adc.h ++++ /dev/null +@@ -1,68 +0,0 @@ +-/* SPDX-License-Identifier: GPL-2.0 */ +-/* +- * Analog Devices Generic AXI ADC IP core driver/library +- * Link: https://wiki.analog.com/resources/fpga/docs/axi_adc_ip +- * +- * Copyright 2012-2020 Analog Devices Inc. +- */ +-#ifndef __ADI_AXI_ADC_H__ +-#define __ADI_AXI_ADC_H__ +- +-struct device; +-struct iio_chan_spec; +- +-/** +- * struct adi_axi_adc_chip_info - Chip specific information +- * @name Chip name +- * @id Chip ID (usually product ID) +- * @channels Channel specifications of type @struct iio_chan_spec +- * @num_channels Number of @channels +- * @scale_table Supported scales by the chip; tuples of 2 ints +- * @num_scales Number of scales in the table +- * @max_rate Maximum sampling rate supported by the device +- */ +-struct adi_axi_adc_chip_info { +- const char *name; +- unsigned int id; +- +- const struct iio_chan_spec *channels; +- unsigned int num_channels; +- +- const unsigned int (*scale_table)[2]; +- int num_scales; +- +- unsigned long max_rate; +-}; +- +-/** +- * struct adi_axi_adc_conv - data of the ADC attached to the AXI ADC +- * @chip_info chip info details for the client ADC +- * @preenable_setup op to run in the client before enabling the AXI ADC +- * @reg_access IIO debugfs_reg_access hook for the client ADC +- * @read_raw IIO read_raw hook for the client ADC +- * @write_raw IIO write_raw hook for the client ADC +- * @read_avail IIO read_avail hook for the client ADC +- */ +-struct adi_axi_adc_conv { +- const struct adi_axi_adc_chip_info *chip_info; +- +- int (*preenable_setup)(struct adi_axi_adc_conv *conv); +- int (*reg_access)(struct adi_axi_adc_conv *conv, unsigned int reg, +- unsigned int writeval, unsigned int *readval); +- int (*read_raw)(struct adi_axi_adc_conv *conv, +- struct iio_chan_spec const *chan, +- int *val, int *val2, long mask); +- int (*write_raw)(struct adi_axi_adc_conv *conv, +- struct iio_chan_spec const *chan, +- int val, int val2, long mask); +- int (*read_avail)(struct adi_axi_adc_conv *conv, +- struct iio_chan_spec const *chan, +- const int **val, int *type, int *length, long mask); +-}; +- +-struct adi_axi_adc_conv *devm_adi_axi_adc_conv_register(struct device *dev, +- size_t sizeof_priv); +- +-void *adi_axi_adc_conv_priv(struct adi_axi_adc_conv *conv); +- +-#endif +diff --git a/include/linux/iio/backend.h b/include/linux/iio/backend.h +new file mode 100644 +index 0000000000000..a6d79381866ec +--- /dev/null ++++ b/include/linux/iio/backend.h +@@ -0,0 +1,72 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++#ifndef _IIO_BACKEND_H_ ++#define _IIO_BACKEND_H_ ++ ++#include ++ ++struct fwnode_handle; ++struct iio_backend; ++struct device; ++struct iio_dev; ++ ++enum iio_backend_data_type { ++ IIO_BACKEND_TWOS_COMPLEMENT, ++ IIO_BACKEND_OFFSET_BINARY, ++ IIO_BACKEND_DATA_TYPE_MAX ++}; ++ ++/** ++ * struct iio_backend_data_fmt - Backend data format ++ * @type: Data type. ++ * @sign_extend: Bool to tell if the data is sign extended. ++ * @enable: Enable/Disable the data format module. If disabled, ++ * not formatting will happen. ++ */ ++struct iio_backend_data_fmt { ++ enum iio_backend_data_type type; ++ bool sign_extend; ++ bool enable; ++}; ++ ++/** ++ * struct iio_backend_ops - operations structure for an iio_backend ++ * @enable: Enable backend. ++ * @disable: Disable backend. ++ * @chan_enable: Enable one channel. ++ * @chan_disable: Disable one channel. ++ * @data_format_set: Configure the data format for a specific channel. ++ * @request_buffer: Request an IIO buffer. ++ * @free_buffer: Free an IIO buffer. ++ **/ ++struct iio_backend_ops { ++ int (*enable)(struct iio_backend *back); ++ void (*disable)(struct iio_backend *back); ++ int (*chan_enable)(struct iio_backend *back, unsigned int chan); ++ int (*chan_disable)(struct iio_backend *back, unsigned int chan); ++ int (*data_format_set)(struct iio_backend *back, unsigned int chan, ++ const struct iio_backend_data_fmt *data); ++ struct iio_buffer *(*request_buffer)(struct iio_backend *back, ++ struct iio_dev *indio_dev); ++ void (*free_buffer)(struct iio_backend *back, ++ struct iio_buffer *buffer); ++}; ++ ++int iio_backend_chan_enable(struct iio_backend *back, unsigned int chan); ++int iio_backend_chan_disable(struct iio_backend *back, unsigned int chan); ++int devm_iio_backend_enable(struct device *dev, struct iio_backend *back); ++int iio_backend_data_format_set(struct iio_backend *back, unsigned int chan, ++ const struct iio_backend_data_fmt *data); ++int devm_iio_backend_request_buffer(struct device *dev, ++ struct iio_backend *back, ++ struct iio_dev *indio_dev); ++ ++void *iio_backend_get_priv(const struct iio_backend *conv); ++struct iio_backend *devm_iio_backend_get(struct device *dev, const char *name); ++struct iio_backend * ++__devm_iio_backend_get_from_fwnode_lookup(struct device *dev, ++ struct fwnode_handle *fwnode); ++ ++int devm_iio_backend_register(struct device *dev, ++ const struct iio_backend_ops *ops, void *priv); ++ ++#endif +diff --git a/include/linux/iio/buffer-dmaengine.h b/include/linux/iio/buffer-dmaengine.h +index 5c355be898149..cbb8ba957fade 100644 +--- a/include/linux/iio/buffer-dmaengine.h ++++ b/include/linux/iio/buffer-dmaengine.h +@@ -10,6 +10,9 @@ + struct iio_dev; + struct device; + ++struct iio_buffer *iio_dmaengine_buffer_alloc(struct device *dev, ++ const char *channel); ++void iio_dmaengine_buffer_free(struct iio_buffer *buffer); + int devm_iio_dmaengine_buffer_setup(struct device *dev, + struct iio_dev *indio_dev, + const char *channel); +diff --git a/include/linux/kthread.h b/include/linux/kthread.h +index 2c30ade43bc87..b11f53c1ba2e6 100644 +--- a/include/linux/kthread.h ++++ b/include/linux/kthread.h +@@ -86,6 +86,7 @@ void free_kthread_struct(struct task_struct *k); + void kthread_bind(struct task_struct *k, unsigned int cpu); + void kthread_bind_mask(struct task_struct *k, const struct cpumask *mask); + int kthread_stop(struct task_struct *k); ++int kthread_stop_put(struct task_struct *k); + bool kthread_should_stop(void); + bool kthread_should_park(void); + bool kthread_should_stop_or_park(void); +diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h +index 5ca4e085d8133..ffb98bc43b2db 100644 +--- a/include/linux/mlx5/driver.h ++++ b/include/linux/mlx5/driver.h +@@ -852,6 +852,7 @@ struct mlx5_cmd_work_ent { + void *context; + int idx; + struct completion handling; ++ struct completion slotted; + struct completion done; + struct mlx5_cmd *cmd; + struct work_struct work; +diff --git a/include/linux/mlx5/mlx5_ifc.h b/include/linux/mlx5/mlx5_ifc.h +index 58128de5dbdda..3d1cd726df347 100644 +--- a/include/linux/mlx5/mlx5_ifc.h ++++ b/include/linux/mlx5/mlx5_ifc.h +@@ -10158,9 +10158,9 @@ struct mlx5_ifc_mcam_access_reg_bits { + u8 mfrl[0x1]; + u8 regs_39_to_32[0x8]; + +- u8 regs_31_to_10[0x16]; ++ u8 regs_31_to_11[0x15]; + u8 mtmp[0x1]; +- u8 regs_8_to_0[0x9]; ++ u8 regs_9_to_0[0xa]; + }; + + struct mlx5_ifc_mcam_access_reg_bits1 { +diff --git a/include/linux/numa.h b/include/linux/numa.h +index a904861de8000..1d43371fafd2f 100644 +--- a/include/linux/numa.h ++++ b/include/linux/numa.h +@@ -1,6 +1,7 @@ + /* SPDX-License-Identifier: GPL-2.0 */ + #ifndef _LINUX_NUMA_H + #define _LINUX_NUMA_H ++#include + #include + + #ifdef CONFIG_NODES_SHIFT +@@ -22,34 +23,21 @@ + #endif + + #ifdef CONFIG_NUMA +-#include + #include + + /* Generic implementation available */ + int numa_nearest_node(int node, unsigned int state); + + #ifndef memory_add_physaddr_to_nid +-static inline int memory_add_physaddr_to_nid(u64 start) +-{ +- pr_info_once("Unknown online node for memory at 0x%llx, assuming node 0\n", +- start); +- return 0; +-} ++int memory_add_physaddr_to_nid(u64 start); + #endif ++ + #ifndef phys_to_target_node +-static inline int phys_to_target_node(u64 start) +-{ +- pr_info_once("Unknown target node for memory at 0x%llx, assuming node 0\n", +- start); +- return 0; +-} +-#endif +-#ifndef numa_fill_memblks +-static inline int __init numa_fill_memblks(u64 start, u64 end) +-{ +- return NUMA_NO_MEMBLK; +-} ++int phys_to_target_node(u64 start); + #endif ++ ++int numa_fill_memblks(u64 start, u64 end); ++ + #else /* !CONFIG_NUMA */ + static inline int numa_nearest_node(int node, unsigned int state) + { +diff --git a/include/linux/nvme-tcp.h b/include/linux/nvme-tcp.h +index 57ebe1267f7fb..e07e8978d691b 100644 +--- a/include/linux/nvme-tcp.h ++++ b/include/linux/nvme-tcp.h +@@ -18,6 +18,12 @@ enum nvme_tcp_pfv { + NVME_TCP_PFV_1_0 = 0x0, + }; + ++enum nvme_tcp_tls_cipher { ++ NVME_TCP_TLS_CIPHER_INVALID = 0, ++ NVME_TCP_TLS_CIPHER_SHA256 = 1, ++ NVME_TCP_TLS_CIPHER_SHA384 = 2, ++}; ++ + enum nvme_tcp_fatal_error_status { + NVME_TCP_FES_INVALID_PDU_HDR = 0x01, + NVME_TCP_FES_PDU_SEQ_ERR = 0x02, +diff --git a/include/linux/printk.h b/include/linux/printk.h +index 8ef499ab3c1ed..e4878bb58f663 100644 +--- a/include/linux/printk.h ++++ b/include/linux/printk.h +@@ -126,7 +126,7 @@ struct va_format { + #define no_printk(fmt, ...) \ + ({ \ + if (0) \ +- printk(fmt, ##__VA_ARGS__); \ ++ _printk(fmt, ##__VA_ARGS__); \ + 0; \ + }) + +diff --git a/include/linux/pwm.h b/include/linux/pwm.h +index fe0f38ce1bdee..63426d8255e4a 100644 +--- a/include/linux/pwm.h ++++ b/include/linux/pwm.h +@@ -95,8 +95,8 @@ struct pwm_device { + * @state: state to fill with the current PWM state + * + * The returned PWM state represents the state that was applied by a previous call to +- * pwm_apply_state(). Drivers may have to slightly tweak that state before programming it to +- * hardware. If pwm_apply_state() was never called, this returns either the current hardware ++ * pwm_apply_might_sleep(). Drivers may have to slightly tweak that state before programming it to ++ * hardware. If pwm_apply_might_sleep() was never called, this returns either the current hardware + * state (if supported) or the default settings. + */ + static inline void pwm_get_state(const struct pwm_device *pwm, +@@ -160,20 +160,20 @@ static inline void pwm_get_args(const struct pwm_device *pwm, + } + + /** +- * pwm_init_state() - prepare a new state to be applied with pwm_apply_state() ++ * pwm_init_state() - prepare a new state to be applied with pwm_apply_might_sleep() + * @pwm: PWM device + * @state: state to fill with the prepared PWM state + * + * This functions prepares a state that can later be tweaked and applied +- * to the PWM device with pwm_apply_state(). This is a convenient function ++ * to the PWM device with pwm_apply_might_sleep(). This is a convenient function + * that first retrieves the current PWM state and the replaces the period + * and polarity fields with the reference values defined in pwm->args. + * Once the function returns, you can adjust the ->enabled and ->duty_cycle +- * fields according to your needs before calling pwm_apply_state(). ++ * fields according to your needs before calling pwm_apply_might_sleep(). + * + * ->duty_cycle is initially set to zero to avoid cases where the current + * ->duty_cycle value exceed the pwm_args->period one, which would trigger +- * an error if the user calls pwm_apply_state() without adjusting ->duty_cycle ++ * an error if the user calls pwm_apply_might_sleep() without adjusting ->duty_cycle + * first. + */ + static inline void pwm_init_state(const struct pwm_device *pwm, +@@ -229,7 +229,7 @@ pwm_get_relative_duty_cycle(const struct pwm_state *state, unsigned int scale) + * + * pwm_init_state(pwm, &state); + * pwm_set_relative_duty_cycle(&state, 50, 100); +- * pwm_apply_state(pwm, &state); ++ * pwm_apply_might_sleep(pwm, &state); + * + * This functions returns -EINVAL if @duty_cycle and/or @scale are + * inconsistent (@scale == 0 or @duty_cycle > @scale). +@@ -309,7 +309,7 @@ struct pwm_chip { + + #if IS_ENABLED(CONFIG_PWM) + /* PWM user APIs */ +-int pwm_apply_state(struct pwm_device *pwm, const struct pwm_state *state); ++int pwm_apply_might_sleep(struct pwm_device *pwm, const struct pwm_state *state); + int pwm_adjust_config(struct pwm_device *pwm); + + /** +@@ -337,7 +337,7 @@ static inline int pwm_config(struct pwm_device *pwm, int duty_ns, + + state.duty_cycle = duty_ns; + state.period = period_ns; +- return pwm_apply_state(pwm, &state); ++ return pwm_apply_might_sleep(pwm, &state); + } + + /** +@@ -358,7 +358,7 @@ static inline int pwm_enable(struct pwm_device *pwm) + return 0; + + state.enabled = true; +- return pwm_apply_state(pwm, &state); ++ return pwm_apply_might_sleep(pwm, &state); + } + + /** +@@ -377,7 +377,7 @@ static inline void pwm_disable(struct pwm_device *pwm) + return; + + state.enabled = false; +- pwm_apply_state(pwm, &state); ++ pwm_apply_might_sleep(pwm, &state); + } + + /* PWM provider APIs */ +@@ -408,8 +408,8 @@ struct pwm_device *devm_fwnode_pwm_get(struct device *dev, + struct fwnode_handle *fwnode, + const char *con_id); + #else +-static inline int pwm_apply_state(struct pwm_device *pwm, +- const struct pwm_state *state) ++static inline int pwm_apply_might_sleep(struct pwm_device *pwm, ++ const struct pwm_state *state) + { + might_sleep(); + return -ENOTSUPP; +@@ -536,7 +536,7 @@ static inline void pwm_apply_args(struct pwm_device *pwm) + state.period = pwm->args.period; + state.usage_power = false; + +- pwm_apply_state(pwm, &state); ++ pwm_apply_might_sleep(pwm, &state); + } + + struct pwm_lookup { +diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h +index 4b7eceb3828b0..2dbf87233f85a 100644 +--- a/include/linux/regulator/driver.h ++++ b/include/linux/regulator/driver.h +@@ -304,6 +304,8 @@ enum regulator_type { + * @vsel_range_reg: Register for range selector when using pickable ranges + * and ``regulator_map_*_voltage_*_pickable`` functions. + * @vsel_range_mask: Mask for register bitfield used for range selector ++ * @range_applied_by_vsel: A flag to indicate that changes to vsel_range_reg ++ * are only effective after vsel_reg is written + * @vsel_reg: Register for selector when using ``regulator_map_*_voltage_*`` + * @vsel_mask: Mask for register bitfield used for selector + * @vsel_step: Specify the resolution of selector stepping when setting +@@ -394,6 +396,7 @@ struct regulator_desc { + + unsigned int vsel_range_reg; + unsigned int vsel_range_mask; ++ bool range_applied_by_vsel; + unsigned int vsel_reg; + unsigned int vsel_mask; + unsigned int vsel_step; +diff --git a/include/linux/tracefs.h b/include/linux/tracefs.h +index 7a5fe17b6bf9c..d03f746587167 100644 +--- a/include/linux/tracefs.h ++++ b/include/linux/tracefs.h +@@ -62,6 +62,8 @@ struct eventfs_file; + typedef int (*eventfs_callback)(const char *name, umode_t *mode, void **data, + const struct file_operations **fops); + ++typedef void (*eventfs_release)(const char *name, void *data); ++ + /** + * struct eventfs_entry - dynamically created eventfs file call back handler + * @name: Then name of the dynamic file in an eventfs directory +@@ -72,6 +74,7 @@ typedef int (*eventfs_callback)(const char *name, umode_t *mode, void **data, + struct eventfs_entry { + const char *name; + eventfs_callback callback; ++ eventfs_release release; + }; + + struct eventfs_inode; +diff --git a/include/media/cec.h b/include/media/cec.h +index 9c007f83569aa..ffd17371302ca 100644 +--- a/include/media/cec.h ++++ b/include/media/cec.h +@@ -247,6 +247,7 @@ struct cec_adapter { + u16 phys_addr; + bool needs_hpd; + bool is_enabled; ++ bool is_claiming_log_addrs; + bool is_configuring; + bool must_reconfigure; + bool is_configured; +diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h +index d9fca929c10b5..ab2a7ef61d420 100644 +--- a/include/media/v4l2-subdev.h ++++ b/include/media/v4l2-subdev.h +@@ -446,7 +446,9 @@ enum v4l2_subdev_pre_streamon_flags { + * @s_stream: start (enabled == 1) or stop (enabled == 0) streaming on the + * sub-device. Failure on stop will remove any resources acquired in + * streaming start, while the error code is still returned by the driver. +- * Also see call_s_stream wrapper in v4l2-subdev.c. ++ * The caller shall track the subdev state, and shall not start or stop an ++ * already started or stopped subdev. Also see call_s_stream wrapper in ++ * v4l2-subdev.c. + * + * @g_pixelaspect: callback to return the pixelaspect ratio. + * +diff --git a/include/net/ax25.h b/include/net/ax25.h +index 0d939e5aee4ec..c2a85fd3f5ea4 100644 +--- a/include/net/ax25.h ++++ b/include/net/ax25.h +@@ -216,7 +216,7 @@ typedef struct { + struct ctl_table; + + typedef struct ax25_dev { +- struct ax25_dev *next; ++ struct list_head list; + + struct net_device *dev; + netdevice_tracker dev_tracker; +@@ -330,7 +330,6 @@ int ax25_addr_size(const ax25_digi *); + void ax25_digi_invert(const ax25_digi *, ax25_digi *); + + /* ax25_dev.c */ +-extern ax25_dev *ax25_dev_list; + extern spinlock_t ax25_dev_lock; + + #if IS_ENABLED(CONFIG_AX25) +diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h +index 7367ef7e92f52..d2a280a42f3b8 100644 +--- a/include/net/bluetooth/hci.h ++++ b/include/net/bluetooth/hci.h +@@ -33,9 +33,6 @@ + #define HCI_MAX_FRAME_SIZE (HCI_MAX_ACL_SIZE + 4) + + #define HCI_LINK_KEY_SIZE 16 +-#define HCI_AMP_LINK_KEY_SIZE (2 * HCI_LINK_KEY_SIZE) +- +-#define HCI_MAX_AMP_ASSOC_SIZE 672 + + #define HCI_MAX_CPB_DATA_SIZE 252 + +@@ -71,26 +68,6 @@ + #define HCI_SMD 9 + #define HCI_VIRTIO 10 + +-/* HCI controller types */ +-#define HCI_PRIMARY 0x00 +-#define HCI_AMP 0x01 +- +-/* First BR/EDR Controller shall have ID = 0 */ +-#define AMP_ID_BREDR 0x00 +- +-/* AMP controller types */ +-#define AMP_TYPE_BREDR 0x00 +-#define AMP_TYPE_80211 0x01 +- +-/* AMP controller status */ +-#define AMP_STATUS_POWERED_DOWN 0x00 +-#define AMP_STATUS_BLUETOOTH_ONLY 0x01 +-#define AMP_STATUS_NO_CAPACITY 0x02 +-#define AMP_STATUS_LOW_CAPACITY 0x03 +-#define AMP_STATUS_MEDIUM_CAPACITY 0x04 +-#define AMP_STATUS_HIGH_CAPACITY 0x05 +-#define AMP_STATUS_FULL_CAPACITY 0x06 +- + /* HCI device quirks */ + enum { + /* When this quirk is set, the HCI Reset command is send when +@@ -526,7 +503,6 @@ enum { + #define ESCO_LINK 0x02 + /* Low Energy links do not have defined link type. Use invented one */ + #define LE_LINK 0x80 +-#define AMP_LINK 0x81 + #define ISO_LINK 0x82 + #define INVALID_LINK 0xff + +@@ -940,56 +916,6 @@ struct hci_cp_io_capability_neg_reply { + __u8 reason; + } __packed; + +-#define HCI_OP_CREATE_PHY_LINK 0x0435 +-struct hci_cp_create_phy_link { +- __u8 phy_handle; +- __u8 key_len; +- __u8 key_type; +- __u8 key[HCI_AMP_LINK_KEY_SIZE]; +-} __packed; +- +-#define HCI_OP_ACCEPT_PHY_LINK 0x0436 +-struct hci_cp_accept_phy_link { +- __u8 phy_handle; +- __u8 key_len; +- __u8 key_type; +- __u8 key[HCI_AMP_LINK_KEY_SIZE]; +-} __packed; +- +-#define HCI_OP_DISCONN_PHY_LINK 0x0437 +-struct hci_cp_disconn_phy_link { +- __u8 phy_handle; +- __u8 reason; +-} __packed; +- +-struct ext_flow_spec { +- __u8 id; +- __u8 stype; +- __le16 msdu; +- __le32 sdu_itime; +- __le32 acc_lat; +- __le32 flush_to; +-} __packed; +- +-#define HCI_OP_CREATE_LOGICAL_LINK 0x0438 +-#define HCI_OP_ACCEPT_LOGICAL_LINK 0x0439 +-struct hci_cp_create_accept_logical_link { +- __u8 phy_handle; +- struct ext_flow_spec tx_flow_spec; +- struct ext_flow_spec rx_flow_spec; +-} __packed; +- +-#define HCI_OP_DISCONN_LOGICAL_LINK 0x043a +-struct hci_cp_disconn_logical_link { +- __le16 log_handle; +-} __packed; +- +-#define HCI_OP_LOGICAL_LINK_CANCEL 0x043b +-struct hci_cp_logical_link_cancel { +- __u8 phy_handle; +- __u8 flow_spec_id; +-} __packed; +- + #define HCI_OP_ENHANCED_SETUP_SYNC_CONN 0x043d + struct hci_coding_format { + __u8 id; +@@ -1611,46 +1537,6 @@ struct hci_rp_read_enc_key_size { + __u8 key_size; + } __packed; + +-#define HCI_OP_READ_LOCAL_AMP_INFO 0x1409 +-struct hci_rp_read_local_amp_info { +- __u8 status; +- __u8 amp_status; +- __le32 total_bw; +- __le32 max_bw; +- __le32 min_latency; +- __le32 max_pdu; +- __u8 amp_type; +- __le16 pal_cap; +- __le16 max_assoc_size; +- __le32 max_flush_to; +- __le32 be_flush_to; +-} __packed; +- +-#define HCI_OP_READ_LOCAL_AMP_ASSOC 0x140a +-struct hci_cp_read_local_amp_assoc { +- __u8 phy_handle; +- __le16 len_so_far; +- __le16 max_len; +-} __packed; +-struct hci_rp_read_local_amp_assoc { +- __u8 status; +- __u8 phy_handle; +- __le16 rem_len; +- __u8 frag[]; +-} __packed; +- +-#define HCI_OP_WRITE_REMOTE_AMP_ASSOC 0x140b +-struct hci_cp_write_remote_amp_assoc { +- __u8 phy_handle; +- __le16 len_so_far; +- __le16 rem_len; +- __u8 frag[]; +-} __packed; +-struct hci_rp_write_remote_amp_assoc { +- __u8 status; +- __u8 phy_handle; +-} __packed; +- + #define HCI_OP_GET_MWS_TRANSPORT_CONFIG 0x140c + + #define HCI_OP_ENABLE_DUT_MODE 0x1803 +diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h +index b5b0a1e1bba02..f786d2d62fa5e 100644 +--- a/include/net/bluetooth/hci_core.h ++++ b/include/net/bluetooth/hci_core.h +@@ -126,7 +126,6 @@ enum suspended_state { + struct hci_conn_hash { + struct list_head list; + unsigned int acl_num; +- unsigned int amp_num; + unsigned int sco_num; + unsigned int iso_num; + unsigned int le_num; +@@ -341,14 +340,6 @@ struct adv_monitor { + /* Default authenticated payload timeout 30s */ + #define DEFAULT_AUTH_PAYLOAD_TIMEOUT 0x0bb8 + +-struct amp_assoc { +- __u16 len; +- __u16 offset; +- __u16 rem_len; +- __u16 len_so_far; +- __u8 data[HCI_MAX_AMP_ASSOC_SIZE]; +-}; +- + #define HCI_MAX_PAGES 3 + + struct hci_dev { +@@ -361,7 +352,6 @@ struct hci_dev { + unsigned long flags; + __u16 id; + __u8 bus; +- __u8 dev_type; + bdaddr_t bdaddr; + bdaddr_t setup_addr; + bdaddr_t public_addr; +@@ -467,21 +457,6 @@ struct hci_dev { + __u16 sniff_min_interval; + __u16 sniff_max_interval; + +- __u8 amp_status; +- __u32 amp_total_bw; +- __u32 amp_max_bw; +- __u32 amp_min_latency; +- __u32 amp_max_pdu; +- __u8 amp_type; +- __u16 amp_pal_cap; +- __u16 amp_assoc_size; +- __u32 amp_max_flush_to; +- __u32 amp_be_flush_to; +- +- struct amp_assoc loc_assoc; +- +- __u8 flow_ctl_mode; +- + unsigned int auto_accept_delay; + + unsigned long quirks; +@@ -501,11 +476,6 @@ struct hci_dev { + unsigned int le_pkts; + unsigned int iso_pkts; + +- __u16 block_len; +- __u16 block_mtu; +- __u16 num_blocks; +- __u16 block_cnt; +- + unsigned long acl_last_tx; + unsigned long sco_last_tx; + unsigned long le_last_tx; +@@ -776,7 +746,6 @@ struct hci_conn { + void *l2cap_data; + void *sco_data; + void *iso_data; +- struct amp_mgr *amp_mgr; + + struct list_head link_list; + struct hci_conn *parent; +@@ -803,7 +772,6 @@ struct hci_chan { + struct sk_buff_head data_q; + unsigned int sent; + __u8 state; +- bool amp; + }; + + struct hci_conn_params { +@@ -1012,9 +980,6 @@ static inline void hci_conn_hash_add(struct hci_dev *hdev, struct hci_conn *c) + case ACL_LINK: + h->acl_num++; + break; +- case AMP_LINK: +- h->amp_num++; +- break; + case LE_LINK: + h->le_num++; + if (c->role == HCI_ROLE_SLAVE) +@@ -1041,9 +1006,6 @@ static inline void hci_conn_hash_del(struct hci_dev *hdev, struct hci_conn *c) + case ACL_LINK: + h->acl_num--; + break; +- case AMP_LINK: +- h->amp_num--; +- break; + case LE_LINK: + h->le_num--; + if (c->role == HCI_ROLE_SLAVE) +@@ -1065,8 +1027,6 @@ static inline unsigned int hci_conn_num(struct hci_dev *hdev, __u8 type) + switch (type) { + case ACL_LINK: + return h->acl_num; +- case AMP_LINK: +- return h->amp_num; + case LE_LINK: + return h->le_num; + case SCO_LINK: +@@ -1083,7 +1043,7 @@ static inline unsigned int hci_conn_count(struct hci_dev *hdev) + { + struct hci_conn_hash *c = &hdev->conn_hash; + +- return c->acl_num + c->amp_num + c->sco_num + c->le_num + c->iso_num; ++ return c->acl_num + c->sco_num + c->le_num + c->iso_num; + } + + static inline __u8 hci_conn_lookup_type(struct hci_dev *hdev, __u16 handle) +@@ -1569,10 +1529,6 @@ static inline void hci_conn_drop(struct hci_conn *conn) + } + break; + +- case AMP_LINK: +- timeo = conn->disc_timeout; +- break; +- + default: + timeo = 0; + break; +diff --git a/include/net/bluetooth/hci_sync.h b/include/net/bluetooth/hci_sync.h +index 268145efbe4cb..e2582c2425449 100644 +--- a/include/net/bluetooth/hci_sync.h ++++ b/include/net/bluetooth/hci_sync.h +@@ -80,6 +80,8 @@ int hci_start_per_adv_sync(struct hci_dev *hdev, u8 instance, u8 data_len, + u8 *data, u32 flags, u16 min_interval, + u16 max_interval, u16 sync_interval); + ++int hci_disable_per_advertising_sync(struct hci_dev *hdev, u8 instance); ++ + int hci_remove_advertising_sync(struct hci_dev *hdev, struct sock *sk, + u8 instance, bool force); + int hci_disable_advertising_sync(struct hci_dev *hdev); +diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h +index 92d7197f9a563..d2a1154121d0d 100644 +--- a/include/net/bluetooth/l2cap.h ++++ b/include/net/bluetooth/l2cap.h +@@ -548,6 +548,9 @@ struct l2cap_chan { + __u16 tx_credits; + __u16 rx_credits; + ++ /* estimated available receive buffer space or -1 if unknown */ ++ ssize_t rx_avail; ++ + __u8 tx_state; + __u8 rx_state; + +@@ -682,10 +685,15 @@ struct l2cap_user { + /* ----- L2CAP socket info ----- */ + #define l2cap_pi(sk) ((struct l2cap_pinfo *) sk) + ++struct l2cap_rx_busy { ++ struct list_head list; ++ struct sk_buff *skb; ++}; ++ + struct l2cap_pinfo { + struct bt_sock bt; + struct l2cap_chan *chan; +- struct sk_buff *rx_busy_skb; ++ struct list_head rx_busy; + }; + + enum { +@@ -943,6 +951,7 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, + int l2cap_chan_reconfigure(struct l2cap_chan *chan, __u16 mtu); + int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len); + void l2cap_chan_busy(struct l2cap_chan *chan, int busy); ++void l2cap_chan_rx_avail(struct l2cap_chan *chan, ssize_t rx_avail); + int l2cap_chan_check_security(struct l2cap_chan *chan, bool initiator); + void l2cap_chan_set_defaults(struct l2cap_chan *chan); + int l2cap_ertm_init(struct l2cap_chan *chan); +diff --git a/include/net/mac80211.h b/include/net/mac80211.h +index 7c707358d15c8..a39bd4169f292 100644 +--- a/include/net/mac80211.h ++++ b/include/net/mac80211.h +@@ -936,6 +936,8 @@ enum mac80211_tx_info_flags { + * of their QoS TID or other priority field values. + * @IEEE80211_TX_CTRL_MCAST_MLO_FIRST_TX: first MLO TX, used mostly internally + * for sequence number assignment ++ * @IEEE80211_TX_CTRL_SCAN_TX: Indicates that this frame is transmitted ++ * due to scanning, not in normal operation on the interface. + * @IEEE80211_TX_CTRL_MLO_LINK: If not @IEEE80211_LINK_UNSPECIFIED, this + * frame should be transmitted on the specific link. This really is + * only relevant for frames that do not have data present, and is +@@ -956,6 +958,7 @@ enum mac80211_tx_control_flags { + IEEE80211_TX_CTRL_NO_SEQNO = BIT(7), + IEEE80211_TX_CTRL_DONT_REORDER = BIT(8), + IEEE80211_TX_CTRL_MCAST_MLO_FIRST_TX = BIT(9), ++ IEEE80211_TX_CTRL_SCAN_TX = BIT(10), + IEEE80211_TX_CTRL_MLO_LINK = 0xf0000000, + }; + +diff --git a/include/net/tcp.h b/include/net/tcp.h +index a3840a2749c19..690770321a6e3 100644 +--- a/include/net/tcp.h ++++ b/include/net/tcp.h +@@ -1460,13 +1460,14 @@ static inline int tcp_space_from_win(const struct sock *sk, int win) + return __tcp_space_from_win(tcp_sk(sk)->scaling_ratio, win); + } + ++/* Assume a 50% default for skb->len/skb->truesize ratio. ++ * This may be adjusted later in tcp_measure_rcv_mss(). ++ */ ++#define TCP_DEFAULT_SCALING_RATIO (1 << (TCP_RMEM_TO_WIN_SCALE - 1)) ++ + static inline void tcp_scaling_ratio_init(struct sock *sk) + { +- /* Assume a conservative default of 1200 bytes of payload per 4K page. +- * This may be adjusted later in tcp_measure_rcv_mss(). +- */ +- tcp_sk(sk)->scaling_ratio = (1200 << TCP_RMEM_TO_WIN_SCALE) / +- SKB_TRUESIZE(4096); ++ tcp_sk(sk)->scaling_ratio = TCP_DEFAULT_SCALING_RATIO; + } + + /* Note: caller must be prepared to deal with negative returns */ +diff --git a/include/sound/cs35l56.h b/include/sound/cs35l56.h +index 3950322bf3cbb..4e5f35dc042a1 100644 +--- a/include/sound/cs35l56.h ++++ b/include/sound/cs35l56.h +@@ -273,6 +273,7 @@ extern const char * const cs35l56_tx_input_texts[CS35L56_NUM_INPUT_SRC]; + extern const unsigned int cs35l56_tx_input_values[CS35L56_NUM_INPUT_SRC]; + + int cs35l56_set_patch(struct cs35l56_base *cs35l56_base); ++int cs35l56_force_sync_asp1_registers_from_cache(struct cs35l56_base *cs35l56_base); + int cs35l56_mbox_send(struct cs35l56_base *cs35l56_base, unsigned int command); + int cs35l56_firmware_shutdown(struct cs35l56_base *cs35l56_base); + int cs35l56_wait_for_firmware_boot(struct cs35l56_base *cs35l56_base); +diff --git a/include/sound/soc-acpi-intel-match.h b/include/sound/soc-acpi-intel-match.h +index e49b97d9e3ff2..845e7608ac375 100644 +--- a/include/sound/soc-acpi-intel-match.h ++++ b/include/sound/soc-acpi-intel-match.h +@@ -32,6 +32,7 @@ extern struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_machines[]; + extern struct snd_soc_acpi_mach snd_soc_acpi_intel_rpl_machines[]; + extern struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_machines[]; + extern struct snd_soc_acpi_mach snd_soc_acpi_intel_lnl_machines[]; ++extern struct snd_soc_acpi_mach snd_soc_acpi_intel_arl_machines[]; + + extern struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_sdw_machines[]; + extern struct snd_soc_acpi_mach snd_soc_acpi_intel_cfl_sdw_machines[]; +@@ -42,6 +43,7 @@ extern struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_sdw_machines[]; + extern struct snd_soc_acpi_mach snd_soc_acpi_intel_rpl_sdw_machines[]; + extern struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_sdw_machines[]; + extern struct snd_soc_acpi_mach snd_soc_acpi_intel_lnl_sdw_machines[]; ++extern struct snd_soc_acpi_mach snd_soc_acpi_intel_arl_sdw_machines[]; + + /* + * generic table used for HDA codec-based platforms, possibly with +diff --git a/include/sound/tas2781-dsp.h b/include/sound/tas2781-dsp.h +index bd1b72bf47a5e..4ef0f5c6fe6c0 100644 +--- a/include/sound/tas2781-dsp.h ++++ b/include/sound/tas2781-dsp.h +@@ -2,7 +2,7 @@ + // + // ALSA SoC Texas Instruments TAS2781 Audio Smart Amplifier + // +-// Copyright (C) 2022 - 2023 Texas Instruments Incorporated ++// Copyright (C) 2022 - 2024 Texas Instruments Incorporated + // https://www.ti.com + // + // The TAS2781 driver implements a flexible and configurable +@@ -13,8 +13,8 @@ + // Author: Kevin Lu + // + +-#ifndef __TASDEVICE_DSP_H__ +-#define __TASDEVICE_DSP_H__ ++#ifndef __TAS2781_DSP_H__ ++#define __TAS2781_DSP_H__ + + #define MAIN_ALL_DEVICES 0x0d + #define MAIN_DEVICE_A 0x01 +@@ -175,7 +175,6 @@ void tasdevice_calbin_remove(void *context); + int tasdevice_select_tuningprm_cfg(void *context, int prm, + int cfg_no, int rca_conf_no); + int tasdevice_prmg_load(void *context, int prm_no); +-int tasdevice_prmg_calibdata_load(void *context, int prm_no); + void tasdevice_tuning_switch(void *context, int state); + int tas2781_load_calibration(void *context, char *file_name, + unsigned short i); +diff --git a/include/trace/events/asoc.h b/include/trace/events/asoc.h +index 4d8ef71090af1..97a434d021356 100644 +--- a/include/trace/events/asoc.h ++++ b/include/trace/events/asoc.h +@@ -12,6 +12,8 @@ + #define DAPM_DIRECT "(direct)" + #define DAPM_ARROW(dir) (((dir) == SND_SOC_DAPM_DIR_OUT) ? "->" : "<-") + ++TRACE_DEFINE_ENUM(SND_SOC_DAPM_DIR_OUT); ++ + struct snd_soc_jack; + struct snd_soc_card; + struct snd_soc_dapm_widget; +diff --git a/include/uapi/drm/nouveau_drm.h b/include/uapi/drm/nouveau_drm.h +index 0bade1592f34f..c3d8dc7512971 100644 +--- a/include/uapi/drm/nouveau_drm.h ++++ b/include/uapi/drm/nouveau_drm.h +@@ -54,6 +54,27 @@ extern "C" { + */ + #define NOUVEAU_GETPARAM_EXEC_PUSH_MAX 17 + ++/* ++ * NOUVEAU_GETPARAM_VRAM_BAR_SIZE - query bar size ++ * ++ * Query the VRAM BAR size. ++ */ ++#define NOUVEAU_GETPARAM_VRAM_BAR_SIZE 18 ++ ++/* ++ * NOUVEAU_GETPARAM_VRAM_USED ++ * ++ * Get remaining VRAM size. ++ */ ++#define NOUVEAU_GETPARAM_VRAM_USED 19 ++ ++/* ++ * NOUVEAU_GETPARAM_HAS_VMA_TILEMODE ++ * ++ * Query whether tile mode and PTE kind are accepted with VM allocs or not. ++ */ ++#define NOUVEAU_GETPARAM_HAS_VMA_TILEMODE 20 ++ + struct drm_nouveau_getparam { + __u64 param; + __u64 value; +diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h +index 366df8a1a5fc8..fb09fd1767f28 100644 +--- a/include/uapi/linux/bpf.h ++++ b/include/uapi/linux/bpf.h +@@ -6994,7 +6994,7 @@ struct bpf_fib_lookup { + + /* output: MTU value */ + __u16 mtu_result; +- }; ++ } __attribute__((packed, aligned(2))); + /* input: L3 device index for lookup + * output: device index from FIB lookup + */ +diff --git a/include/uapi/linux/user_events.h b/include/uapi/linux/user_events.h +index 2984aae4a2b4f..f74f3aedd49ce 100644 +--- a/include/uapi/linux/user_events.h ++++ b/include/uapi/linux/user_events.h +@@ -17,6 +17,15 @@ + /* Create dynamic location entry within a 32-bit value */ + #define DYN_LOC(offset, size) ((size) << 16 | (offset)) + ++/* List of supported registration flags */ ++enum user_reg_flag { ++ /* Event will not delete upon last reference closing */ ++ USER_EVENT_REG_PERSIST = 1U << 0, ++ ++ /* This value or above is currently non-ABI */ ++ USER_EVENT_REG_MAX = 1U << 1, ++}; ++ + /* + * Describes an event registration and stores the results of the registration. + * This structure is passed to the DIAG_IOCSREG ioctl, callers at a minimum +@@ -33,7 +42,7 @@ struct user_reg { + /* Input: Enable size in bytes at address */ + __u8 enable_size; + +- /* Input: Flags for future use, set to 0 */ ++ /* Input: Flags to use, if any */ + __u16 flags; + + /* Input: Address to update when enabled */ +diff --git a/include/uapi/linux/virtio_bt.h b/include/uapi/linux/virtio_bt.h +index af798f4c96804..3cc7d633456b6 100644 +--- a/include/uapi/linux/virtio_bt.h ++++ b/include/uapi/linux/virtio_bt.h +@@ -13,7 +13,6 @@ + + enum virtio_bt_config_type { + VIRTIO_BT_CONFIG_TYPE_PRIMARY = 0, +- VIRTIO_BT_CONFIG_TYPE_AMP = 1, + }; + + enum virtio_bt_config_vendor { +diff --git a/include/uapi/rdma/bnxt_re-abi.h b/include/uapi/rdma/bnxt_re-abi.h +index 6e7c67a0cca3a..3342276aeac13 100644 +--- a/include/uapi/rdma/bnxt_re-abi.h ++++ b/include/uapi/rdma/bnxt_re-abi.h +@@ -54,6 +54,8 @@ enum { + BNXT_RE_UCNTX_CMASK_HAVE_MODE = 0x02ULL, + BNXT_RE_UCNTX_CMASK_WC_DPI_ENABLED = 0x04ULL, + BNXT_RE_UCNTX_CMASK_DBR_PACING_ENABLED = 0x08ULL, ++ BNXT_RE_UCNTX_CMASK_POW2_DISABLED = 0x10ULL, ++ BNXT_RE_COMP_MASK_UCNTX_HW_RETX_ENABLED = 0x40, + }; + + enum bnxt_re_wqe_mode { +@@ -62,6 +64,14 @@ enum bnxt_re_wqe_mode { + BNXT_QPLIB_WQE_MODE_INVALID = 0x02, + }; + ++enum { ++ BNXT_RE_COMP_MASK_REQ_UCNTX_POW2_SUPPORT = 0x01, ++}; ++ ++struct bnxt_re_uctx_req { ++ __aligned_u64 comp_mask; ++}; ++ + struct bnxt_re_uctx_resp { + __u32 dev_id; + __u32 max_qp; +diff --git a/io_uring/io-wq.c b/io_uring/io-wq.c +index 522196dfb0ff5..318ed067dbf64 100644 +--- a/io_uring/io-wq.c ++++ b/io_uring/io-wq.c +@@ -564,10 +564,7 @@ static void io_worker_handle_work(struct io_wq_acct *acct, + * clear the stalled flag. + */ + work = io_get_next_work(acct, worker); +- raw_spin_unlock(&acct->lock); + if (work) { +- __io_worker_busy(wq, worker); +- + /* + * Make sure cancelation can find this, even before + * it becomes the active work. That avoids a window +@@ -578,9 +575,15 @@ static void io_worker_handle_work(struct io_wq_acct *acct, + raw_spin_lock(&worker->lock); + worker->next_work = work; + raw_spin_unlock(&worker->lock); +- } else { +- break; + } ++ ++ raw_spin_unlock(&acct->lock); ++ ++ if (!work) ++ break; ++ ++ __io_worker_busy(wq, worker); ++ + io_assign_current_work(worker, work); + __set_current_state(TASK_RUNNING); + +diff --git a/io_uring/io_uring.h b/io_uring/io_uring.h +index 411c883b37a95..19ac1b2f1ea45 100644 +--- a/io_uring/io_uring.h ++++ b/io_uring/io_uring.h +@@ -304,7 +304,7 @@ static inline int io_run_task_work(void) + + static inline bool io_task_work_pending(struct io_ring_ctx *ctx) + { +- return task_work_pending(current) || !wq_list_empty(&ctx->work_llist); ++ return task_work_pending(current) || !llist_empty(&ctx->work_llist); + } + + static inline void io_tw_lock(struct io_ring_ctx *ctx, struct io_tw_state *ts) +diff --git a/io_uring/nop.c b/io_uring/nop.c +index d956599a3c1b8..1a4e312dfe510 100644 +--- a/io_uring/nop.c ++++ b/io_uring/nop.c +@@ -12,6 +12,8 @@ + + int io_nop_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe) + { ++ if (READ_ONCE(sqe->rw_flags)) ++ return -EINVAL; + return 0; + } + +diff --git a/kernel/Makefile b/kernel/Makefile +index 3947122d618bf..ce105a5558fcf 100644 +--- a/kernel/Makefile ++++ b/kernel/Makefile +@@ -114,6 +114,7 @@ obj-$(CONFIG_SHADOW_CALL_STACK) += scs.o + obj-$(CONFIG_HAVE_STATIC_CALL) += static_call.o + obj-$(CONFIG_HAVE_STATIC_CALL_INLINE) += static_call_inline.o + obj-$(CONFIG_CFI_CLANG) += cfi.o ++obj-$(CONFIG_NUMA) += numa.o + + obj-$(CONFIG_PERF_EVENTS) += events/ + +diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c +index 4902a7487f076..e886157a9efbb 100644 +--- a/kernel/bpf/syscall.c ++++ b/kernel/bpf/syscall.c +@@ -3809,6 +3809,11 @@ static int bpf_prog_attach_check_attach_type(const struct bpf_prog *prog, + * check permissions at attach time. + */ + return -EPERM; ++ ++ ptype = attach_type_to_prog_type(attach_type); ++ if (prog->type != ptype) ++ return -EINVAL; ++ + return prog->enforce_expected_attach_type && + prog->expected_attach_type != attach_type ? + -EINVAL : 0; +diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c +index 818bac019d0d3..24d7a32f1710e 100644 +--- a/kernel/bpf/verifier.c ++++ b/kernel/bpf/verifier.c +@@ -2539,6 +2539,8 @@ static void mark_btf_ld_reg(struct bpf_verifier_env *env, + regs[regno].type = PTR_TO_BTF_ID | flag; + regs[regno].btf = btf; + regs[regno].btf_id = btf_id; ++ if (type_may_be_null(flag)) ++ regs[regno].id = ++env->id_gen; + } + + #define DEF_NOT_SUBREG (0) +@@ -3679,7 +3681,8 @@ static int backtrack_insn(struct bpf_verifier_env *env, int idx, int subseq_idx, + * sreg needs precision before this insn + */ + bt_clear_reg(bt, dreg); +- bt_set_reg(bt, sreg); ++ if (sreg != BPF_REG_FP) ++ bt_set_reg(bt, sreg); + } else { + /* dreg = K + * dreg needs precision after this insn. +@@ -3695,7 +3698,8 @@ static int backtrack_insn(struct bpf_verifier_env *env, int idx, int subseq_idx, + * both dreg and sreg need precision + * before this insn + */ +- bt_set_reg(bt, sreg); ++ if (sreg != BPF_REG_FP) ++ bt_set_reg(bt, sreg); + } /* else dreg += K + * dreg still needs precision before this insn + */ +@@ -5371,8 +5375,6 @@ static int check_map_kptr_access(struct bpf_verifier_env *env, u32 regno, + rcu_safe_kptr(kptr_field) && in_rcu_cs(env) ? + PTR_MAYBE_NULL | MEM_RCU : + PTR_MAYBE_NULL | PTR_UNTRUSTED); +- /* For mark_ptr_or_null_reg */ +- val_reg->id = ++env->id_gen; + } else if (class == BPF_STX) { + val_reg = reg_state(env, value_regno); + if (!register_is_null(val_reg) && +@@ -5682,7 +5684,8 @@ static bool is_trusted_reg(const struct bpf_reg_state *reg) + return true; + + /* Types listed in the reg2btf_ids are always trusted */ +- if (reg2btf_ids[base_type(reg->type)]) ++ if (reg2btf_ids[base_type(reg->type)] && ++ !bpf_type_has_unsafe_modifiers(reg->type)) + return true; + + /* If a register is not referenced, it is trusted if it has the +@@ -6261,6 +6264,7 @@ static int bpf_map_direct_read(struct bpf_map *map, int off, int size, u64 *val, + #define BTF_TYPE_SAFE_RCU(__type) __PASTE(__type, __safe_rcu) + #define BTF_TYPE_SAFE_RCU_OR_NULL(__type) __PASTE(__type, __safe_rcu_or_null) + #define BTF_TYPE_SAFE_TRUSTED(__type) __PASTE(__type, __safe_trusted) ++#define BTF_TYPE_SAFE_TRUSTED_OR_NULL(__type) __PASTE(__type, __safe_trusted_or_null) + + /* + * Allow list few fields as RCU trusted or full trusted. +@@ -6324,7 +6328,7 @@ BTF_TYPE_SAFE_TRUSTED(struct dentry) { + struct inode *d_inode; + }; + +-BTF_TYPE_SAFE_TRUSTED(struct socket) { ++BTF_TYPE_SAFE_TRUSTED_OR_NULL(struct socket) { + struct sock *sk; + }; + +@@ -6359,11 +6363,20 @@ static bool type_is_trusted(struct bpf_verifier_env *env, + BTF_TYPE_EMIT(BTF_TYPE_SAFE_TRUSTED(struct linux_binprm)); + BTF_TYPE_EMIT(BTF_TYPE_SAFE_TRUSTED(struct file)); + BTF_TYPE_EMIT(BTF_TYPE_SAFE_TRUSTED(struct dentry)); +- BTF_TYPE_EMIT(BTF_TYPE_SAFE_TRUSTED(struct socket)); + + return btf_nested_type_is_trusted(&env->log, reg, field_name, btf_id, "__safe_trusted"); + } + ++static bool type_is_trusted_or_null(struct bpf_verifier_env *env, ++ struct bpf_reg_state *reg, ++ const char *field_name, u32 btf_id) ++{ ++ BTF_TYPE_EMIT(BTF_TYPE_SAFE_TRUSTED_OR_NULL(struct socket)); ++ ++ return btf_nested_type_is_trusted(&env->log, reg, field_name, btf_id, ++ "__safe_trusted_or_null"); ++} ++ + static int check_ptr_to_btf_access(struct bpf_verifier_env *env, + struct bpf_reg_state *regs, + int regno, int off, int size, +@@ -6472,6 +6485,8 @@ static int check_ptr_to_btf_access(struct bpf_verifier_env *env, + */ + if (type_is_trusted(env, reg, field_name, btf_id)) { + flag |= PTR_TRUSTED; ++ } else if (type_is_trusted_or_null(env, reg, field_name, btf_id)) { ++ flag |= PTR_TRUSTED | PTR_MAYBE_NULL; + } else if (in_rcu_cs(env) && !type_may_be_null(reg->type)) { + if (type_is_rcu(env, reg, field_name, btf_id)) { + /* ignore __rcu tag and mark it MEM_RCU */ +@@ -8727,7 +8742,8 @@ static bool may_update_sockmap(struct bpf_verifier_env *env, int func_id) + enum bpf_attach_type eatype = env->prog->expected_attach_type; + enum bpf_prog_type type = resolve_prog_type(env->prog); + +- if (func_id != BPF_FUNC_map_update_elem) ++ if (func_id != BPF_FUNC_map_update_elem && ++ func_id != BPF_FUNC_map_delete_elem) + return false; + + /* It's not possible to get access to a locked struct sock in these +@@ -8738,6 +8754,11 @@ static bool may_update_sockmap(struct bpf_verifier_env *env, int func_id) + if (eatype == BPF_TRACE_ITER) + return true; + break; ++ case BPF_PROG_TYPE_SOCK_OPS: ++ /* map_update allowed only via dedicated helpers with event type checks */ ++ if (func_id == BPF_FUNC_map_delete_elem) ++ return true; ++ break; + case BPF_PROG_TYPE_SOCKET_FILTER: + case BPF_PROG_TYPE_SCHED_CLS: + case BPF_PROG_TYPE_SCHED_ACT: +@@ -8833,7 +8854,6 @@ static int check_map_func_compatibility(struct bpf_verifier_env *env, + case BPF_MAP_TYPE_SOCKMAP: + if (func_id != BPF_FUNC_sk_redirect_map && + func_id != BPF_FUNC_sock_map_update && +- func_id != BPF_FUNC_map_delete_elem && + func_id != BPF_FUNC_msg_redirect_map && + func_id != BPF_FUNC_sk_select_reuseport && + func_id != BPF_FUNC_map_lookup_elem && +@@ -8843,7 +8863,6 @@ static int check_map_func_compatibility(struct bpf_verifier_env *env, + case BPF_MAP_TYPE_SOCKHASH: + if (func_id != BPF_FUNC_sk_redirect_hash && + func_id != BPF_FUNC_sock_hash_update && +- func_id != BPF_FUNC_map_delete_elem && + func_id != BPF_FUNC_msg_redirect_hash && + func_id != BPF_FUNC_sk_select_reuseport && + func_id != BPF_FUNC_map_lookup_elem && +diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c +index 1c2543edefeeb..679460ebccfbf 100644 +--- a/kernel/cgroup/cpuset.c ++++ b/kernel/cgroup/cpuset.c +@@ -2229,7 +2229,7 @@ bool current_cpuset_is_being_rebound(void) + static int update_relax_domain_level(struct cpuset *cs, s64 val) + { + #ifdef CONFIG_SMP +- if (val < -1 || val >= sched_domain_level_max) ++ if (val < -1 || val > sched_domain_level_max + 1) + return -EINVAL; + #endif + +diff --git a/kernel/cpu.c b/kernel/cpu.c +index 2dd2fd300e916..4f453226fcf48 100644 +--- a/kernel/cpu.c ++++ b/kernel/cpu.c +@@ -3197,6 +3197,7 @@ void __init boot_cpu_hotplug_init(void) + this_cpu_write(cpuhp_state.target, CPUHP_ONLINE); + } + ++#ifdef CONFIG_CPU_MITIGATIONS + /* + * These are used for a global "mitigations=" cmdline option for toggling + * optional CPU mitigations. +@@ -3207,9 +3208,7 @@ enum cpu_mitigations { + CPU_MITIGATIONS_AUTO_NOSMT, + }; + +-static enum cpu_mitigations cpu_mitigations __ro_after_init = +- IS_ENABLED(CONFIG_CPU_MITIGATIONS) ? CPU_MITIGATIONS_AUTO : +- CPU_MITIGATIONS_OFF; ++static enum cpu_mitigations cpu_mitigations __ro_after_init = CPU_MITIGATIONS_AUTO; + + static int __init mitigations_parse_cmdline(char *arg) + { +@@ -3225,7 +3224,6 @@ static int __init mitigations_parse_cmdline(char *arg) + + return 0; + } +-early_param("mitigations", mitigations_parse_cmdline); + + /* mitigations=off */ + bool cpu_mitigations_off(void) +@@ -3240,3 +3238,11 @@ bool cpu_mitigations_auto_nosmt(void) + return cpu_mitigations == CPU_MITIGATIONS_AUTO_NOSMT; + } + EXPORT_SYMBOL_GPL(cpu_mitigations_auto_nosmt); ++#else ++static int __init mitigations_parse_cmdline(char *arg) ++{ ++ pr_crit("Kernel compiled without mitigations, ignoring 'mitigations'; system may still be vulnerable\n"); ++ return 0; ++} ++#endif ++early_param("mitigations", mitigations_parse_cmdline); +diff --git a/kernel/dma/map_benchmark.c b/kernel/dma/map_benchmark.c +index 02205ab53b7e9..f7f3d14fa69a7 100644 +--- a/kernel/dma/map_benchmark.c ++++ b/kernel/dma/map_benchmark.c +@@ -101,7 +101,6 @@ static int do_map_benchmark(struct map_benchmark_data *map) + struct task_struct **tsk; + int threads = map->bparam.threads; + int node = map->bparam.node; +- const cpumask_t *cpu_mask = cpumask_of_node(node); + u64 loops; + int ret = 0; + int i; +@@ -118,11 +117,13 @@ static int do_map_benchmark(struct map_benchmark_data *map) + if (IS_ERR(tsk[i])) { + pr_err("create dma_map thread failed\n"); + ret = PTR_ERR(tsk[i]); ++ while (--i >= 0) ++ kthread_stop(tsk[i]); + goto out; + } + + if (node != NUMA_NO_NODE) +- kthread_bind_mask(tsk[i], cpu_mask); ++ kthread_bind_mask(tsk[i], cpumask_of_node(node)); + } + + /* clear the old value in the previous benchmark */ +@@ -139,13 +140,17 @@ static int do_map_benchmark(struct map_benchmark_data *map) + + msleep_interruptible(map->bparam.seconds * 1000); + +- /* wait for the completion of benchmark threads */ ++ /* wait for the completion of all started benchmark threads */ + for (i = 0; i < threads; i++) { +- ret = kthread_stop(tsk[i]); +- if (ret) +- goto out; ++ int kthread_ret = kthread_stop_put(tsk[i]); ++ ++ if (kthread_ret) ++ ret = kthread_ret; + } + ++ if (ret) ++ goto out; ++ + loops = atomic64_read(&map->loops); + if (likely(loops > 0)) { + u64 map_variance, unmap_variance; +@@ -170,8 +175,6 @@ static int do_map_benchmark(struct map_benchmark_data *map) + } + + out: +- for (i = 0; i < threads; i++) +- put_task_struct(tsk[i]); + put_device(map->dev); + kfree(tsk); + return ret; +@@ -208,7 +211,8 @@ static long map_benchmark_ioctl(struct file *file, unsigned int cmd, + } + + if (map->bparam.node != NUMA_NO_NODE && +- !node_possible(map->bparam.node)) { ++ (map->bparam.node < 0 || map->bparam.node >= MAX_NUMNODES || ++ !node_possible(map->bparam.node))) { + pr_err("invalid numa node\n"); + return -EINVAL; + } +diff --git a/kernel/gen_kheaders.sh b/kernel/gen_kheaders.sh +index 6d443ea22bb73..4ba5fd3d73ae2 100755 +--- a/kernel/gen_kheaders.sh ++++ b/kernel/gen_kheaders.sh +@@ -14,7 +14,12 @@ include/ + arch/$SRCARCH/include/ + " + +-type cpio > /dev/null ++if ! command -v cpio >/dev/null; then ++ echo >&2 "***" ++ echo >&2 "*** 'cpio' could not be found." ++ echo >&2 "***" ++ exit 1 ++fi + + # Support incremental builds by skipping archive generation + # if timestamps of files being archived are not changed. +diff --git a/kernel/irq/cpuhotplug.c b/kernel/irq/cpuhotplug.c +index 1ed2b1739363b..5ecd072a34fe7 100644 +--- a/kernel/irq/cpuhotplug.c ++++ b/kernel/irq/cpuhotplug.c +@@ -69,6 +69,14 @@ static bool migrate_one_irq(struct irq_desc *desc) + return false; + } + ++ /* ++ * Complete an eventually pending irq move cleanup. If this ++ * interrupt was moved in hard irq context, then the vectors need ++ * to be cleaned up. It can't wait until this interrupt actually ++ * happens and this CPU was involved. ++ */ ++ irq_force_complete_move(desc); ++ + /* + * No move required, if: + * - Interrupt is per cpu +@@ -87,14 +95,6 @@ static bool migrate_one_irq(struct irq_desc *desc) + return false; + } + +- /* +- * Complete an eventually pending irq move cleanup. If this +- * interrupt was moved in hard irq context, then the vectors need +- * to be cleaned up. It can't wait until this interrupt actually +- * happens and this CPU was involved. +- */ +- irq_force_complete_move(desc); +- + /* + * If there is a setaffinity pending, then try to reuse the pending + * mask, so the last change of the affinity does not get lost. If +diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c +index d309ba84e08a9..1782f90cd8c6c 100644 +--- a/kernel/irq/manage.c ++++ b/kernel/irq/manage.c +@@ -1852,15 +1852,13 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new) + struct task_struct *t = new->thread; + + new->thread = NULL; +- kthread_stop(t); +- put_task_struct(t); ++ kthread_stop_put(t); + } + if (new->secondary && new->secondary->thread) { + struct task_struct *t = new->secondary->thread; + + new->secondary->thread = NULL; +- kthread_stop(t); +- put_task_struct(t); ++ kthread_stop_put(t); + } + out_mput: + module_put(desc->owner); +@@ -1971,12 +1969,9 @@ static struct irqaction *__free_irq(struct irq_desc *desc, void *dev_id) + * the same bit to a newly requested action. + */ + if (action->thread) { +- kthread_stop(action->thread); +- put_task_struct(action->thread); +- if (action->secondary && action->secondary->thread) { +- kthread_stop(action->secondary->thread); +- put_task_struct(action->secondary->thread); +- } ++ kthread_stop_put(action->thread); ++ if (action->secondary && action->secondary->thread) ++ kthread_stop_put(action->secondary->thread); + } + + /* Last action releases resources */ +diff --git a/kernel/kthread.c b/kernel/kthread.c +index 1eea53050babc..290cbc845225e 100644 +--- a/kernel/kthread.c ++++ b/kernel/kthread.c +@@ -715,6 +715,24 @@ int kthread_stop(struct task_struct *k) + } + EXPORT_SYMBOL(kthread_stop); + ++/** ++ * kthread_stop_put - stop a thread and put its task struct ++ * @k: thread created by kthread_create(). ++ * ++ * Stops a thread created by kthread_create() and put its task_struct. ++ * Only use when holding an extra task struct reference obtained by ++ * calling get_task_struct(). ++ */ ++int kthread_stop_put(struct task_struct *k) ++{ ++ int ret; ++ ++ ret = kthread_stop(k); ++ put_task_struct(k); ++ return ret; ++} ++EXPORT_SYMBOL(kthread_stop_put); ++ + int kthreadd(void *unused) + { + struct task_struct *tsk = current; +diff --git a/kernel/numa.c b/kernel/numa.c +new file mode 100644 +index 0000000000000..67ca6b8585c06 +--- /dev/null ++++ b/kernel/numa.c +@@ -0,0 +1,26 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++ ++#include ++#include ++ ++/* Stub functions: */ ++ ++#ifndef memory_add_physaddr_to_nid ++int memory_add_physaddr_to_nid(u64 start) ++{ ++ pr_info_once("Unknown online node for memory at 0x%llx, assuming node 0\n", ++ start); ++ return 0; ++} ++EXPORT_SYMBOL_GPL(memory_add_physaddr_to_nid); ++#endif ++ ++#ifndef phys_to_target_node ++int phys_to_target_node(u64 start) ++{ ++ pr_info_once("Unknown target node for memory at 0x%llx, assuming node 0\n", ++ start); ++ return 0; ++} ++EXPORT_SYMBOL_GPL(phys_to_target_node); ++#endif +diff --git a/kernel/rcu/tasks.h b/kernel/rcu/tasks.h +index 65e000ca332cc..305e960c08ac5 100644 +--- a/kernel/rcu/tasks.h ++++ b/kernel/rcu/tasks.h +@@ -1938,7 +1938,7 @@ void show_rcu_tasks_trace_gp_kthread(void) + { + char buf[64]; + +- sprintf(buf, "N%lu h:%lu/%lu/%lu", ++ snprintf(buf, sizeof(buf), "N%lu h:%lu/%lu/%lu", + data_race(n_trc_holdouts), + data_race(n_heavy_reader_ofl_updates), + data_race(n_heavy_reader_updates), +diff --git a/kernel/rcu/tree_stall.h b/kernel/rcu/tree_stall.h +index e09f4f624261e..11a1fac3a5898 100644 +--- a/kernel/rcu/tree_stall.h ++++ b/kernel/rcu/tree_stall.h +@@ -503,7 +503,8 @@ static void print_cpu_stall_info(int cpu) + rcu_dynticks_in_eqs(rcu_dynticks_snap(cpu)); + rcuc_starved = rcu_is_rcuc_kthread_starving(rdp, &j); + if (rcuc_starved) +- sprintf(buf, " rcuc=%ld jiffies(starved)", j); ++ // Print signed value, as negative values indicate a probable bug. ++ snprintf(buf, sizeof(buf), " rcuc=%ld jiffies(starved)", j); + pr_err("\t%d-%c%c%c%c: (%lu %s) idle=%04x/%ld/%#lx softirq=%u/%u fqs=%ld%s%s\n", + cpu, + "O."[!!cpu_online(cpu)], +diff --git a/kernel/sched/core.c b/kernel/sched/core.c +index 1f91e2c12731e..dcb30e304871a 100644 +--- a/kernel/sched/core.c ++++ b/kernel/sched/core.c +@@ -11429,7 +11429,7 @@ static ssize_t cpu_max_write(struct kernfs_open_file *of, + { + struct task_group *tg = css_tg(of_css(of)); + u64 period = tg_get_cfs_period(tg); +- u64 burst = tg_get_cfs_burst(tg); ++ u64 burst = tg->cfs_bandwidth.burst; + u64 quota; + int ret; + +diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c +index 397ef27c9bdb1..01b3fc97ddc27 100644 +--- a/kernel/sched/fair.c ++++ b/kernel/sched/fair.c +@@ -6564,22 +6564,42 @@ static inline void hrtick_update(struct rq *rq) + #ifdef CONFIG_SMP + static inline bool cpu_overutilized(int cpu) + { +- unsigned long rq_util_min = uclamp_rq_get(cpu_rq(cpu), UCLAMP_MIN); +- unsigned long rq_util_max = uclamp_rq_get(cpu_rq(cpu), UCLAMP_MAX); ++ unsigned long rq_util_min, rq_util_max; ++ ++ if (!sched_energy_enabled()) ++ return false; ++ ++ rq_util_min = uclamp_rq_get(cpu_rq(cpu), UCLAMP_MIN); ++ rq_util_max = uclamp_rq_get(cpu_rq(cpu), UCLAMP_MAX); + + /* Return true only if the utilization doesn't fit CPU's capacity */ + return !util_fits_cpu(cpu_util_cfs(cpu), rq_util_min, rq_util_max, cpu); + } + +-static inline void update_overutilized_status(struct rq *rq) ++static inline void set_rd_overutilized_status(struct root_domain *rd, ++ unsigned int status) + { +- if (!READ_ONCE(rq->rd->overutilized) && cpu_overutilized(rq->cpu)) { +- WRITE_ONCE(rq->rd->overutilized, SG_OVERUTILIZED); +- trace_sched_overutilized_tp(rq->rd, SG_OVERUTILIZED); +- } ++ if (!sched_energy_enabled()) ++ return; ++ ++ WRITE_ONCE(rd->overutilized, status); ++ trace_sched_overutilized_tp(rd, !!status); ++} ++ ++static inline void check_update_overutilized_status(struct rq *rq) ++{ ++ /* ++ * overutilized field is used for load balancing decisions only ++ * if energy aware scheduler is being used ++ */ ++ if (!sched_energy_enabled()) ++ return; ++ ++ if (!READ_ONCE(rq->rd->overutilized) && cpu_overutilized(rq->cpu)) ++ set_rd_overutilized_status(rq->rd, SG_OVERUTILIZED); + } + #else +-static inline void update_overutilized_status(struct rq *rq) { } ++static inline void check_update_overutilized_status(struct rq *rq) { } + #endif + + /* Runqueue only has SCHED_IDLE tasks enqueued */ +@@ -6680,7 +6700,7 @@ enqueue_task_fair(struct rq *rq, struct task_struct *p, int flags) + * and the following generally works well enough in practice. + */ + if (!task_new) +- update_overutilized_status(rq); ++ check_update_overutilized_status(rq); + + enqueue_throttle: + assert_list_leaf_cfs_rq(rq); +@@ -10500,19 +10520,14 @@ static inline void update_sd_lb_stats(struct lb_env *env, struct sd_lb_stats *sd + env->fbq_type = fbq_classify_group(&sds->busiest_stat); + + if (!env->sd->parent) { +- struct root_domain *rd = env->dst_rq->rd; +- + /* update overload indicator if we are at root domain */ +- WRITE_ONCE(rd->overload, sg_status & SG_OVERLOAD); ++ WRITE_ONCE(env->dst_rq->rd->overload, sg_status & SG_OVERLOAD); + + /* Update over-utilization (tipping point, U >= 0) indicator */ +- WRITE_ONCE(rd->overutilized, sg_status & SG_OVERUTILIZED); +- trace_sched_overutilized_tp(rd, sg_status & SG_OVERUTILIZED); ++ set_rd_overutilized_status(env->dst_rq->rd, ++ sg_status & SG_OVERUTILIZED); + } else if (sg_status & SG_OVERUTILIZED) { +- struct root_domain *rd = env->dst_rq->rd; +- +- WRITE_ONCE(rd->overutilized, SG_OVERUTILIZED); +- trace_sched_overutilized_tp(rd, SG_OVERUTILIZED); ++ set_rd_overutilized_status(env->dst_rq->rd, SG_OVERUTILIZED); + } + + update_idle_cpu_scan(env, sum_util); +@@ -12503,7 +12518,7 @@ static void task_tick_fair(struct rq *rq, struct task_struct *curr, int queued) + task_tick_numa(rq, curr); + + update_misfit_status(curr, rq); +- update_overutilized_status(task_rq(curr)); ++ check_update_overutilized_status(task_rq(curr)); + + task_tick_core(rq, curr); + } +diff --git a/kernel/sched/isolation.c b/kernel/sched/isolation.c +index 373d42c707bc5..82e2f7fc7c267 100644 +--- a/kernel/sched/isolation.c ++++ b/kernel/sched/isolation.c +@@ -109,6 +109,7 @@ static void __init housekeeping_setup_type(enum hk_type type, + static int __init housekeeping_setup(char *str, unsigned long flags) + { + cpumask_var_t non_housekeeping_mask, housekeeping_staging; ++ unsigned int first_cpu; + int err = 0; + + if ((flags & HK_FLAG_TICK) && !(housekeeping.flags & HK_FLAG_TICK)) { +@@ -129,7 +130,8 @@ static int __init housekeeping_setup(char *str, unsigned long flags) + cpumask_andnot(housekeeping_staging, + cpu_possible_mask, non_housekeeping_mask); + +- if (!cpumask_intersects(cpu_present_mask, housekeeping_staging)) { ++ first_cpu = cpumask_first_and(cpu_present_mask, housekeeping_staging); ++ if (first_cpu >= nr_cpu_ids || first_cpu >= setup_max_cpus) { + __cpumask_set_cpu(smp_processor_id(), housekeeping_staging); + __cpumask_clear_cpu(smp_processor_id(), non_housekeeping_mask); + if (!housekeeping.flags) { +@@ -138,6 +140,9 @@ static int __init housekeeping_setup(char *str, unsigned long flags) + } + } + ++ if (cpumask_empty(non_housekeeping_mask)) ++ goto free_housekeeping_staging; ++ + if (!housekeeping.flags) { + /* First setup call ("nohz_full=" or "isolcpus=") */ + enum hk_type type; +diff --git a/kernel/sched/topology.c b/kernel/sched/topology.c +index 423d08947962c..8c1e183329d97 100644 +--- a/kernel/sched/topology.c ++++ b/kernel/sched/topology.c +@@ -1452,7 +1452,7 @@ static void set_domain_attribute(struct sched_domain *sd, + } else + request = attr->relax_domain_level; + +- if (sd->level > request) { ++ if (sd->level >= request) { + /* Turn off idle balance on this domain: */ + sd->flags &= ~(SD_BALANCE_WAKE|SD_BALANCE_NEWIDLE); + } +diff --git a/kernel/smpboot.c b/kernel/smpboot.c +index f47d8f375946b..1992b62e980b7 100644 +--- a/kernel/smpboot.c ++++ b/kernel/smpboot.c +@@ -272,8 +272,7 @@ static void smpboot_destroy_threads(struct smp_hotplug_thread *ht) + struct task_struct *tsk = *per_cpu_ptr(ht->store, cpu); + + if (tsk) { +- kthread_stop(tsk); +- put_task_struct(tsk); ++ kthread_stop_put(tsk); + *per_cpu_ptr(ht->store, cpu) = NULL; + } + } +diff --git a/kernel/softirq.c b/kernel/softirq.c +index 210cf5f8d92c2..bd9716d7bb638 100644 +--- a/kernel/softirq.c ++++ b/kernel/softirq.c +@@ -507,7 +507,7 @@ static inline bool lockdep_softirq_start(void) { return false; } + static inline void lockdep_softirq_end(bool in_hardirq) { } + #endif + +-asmlinkage __visible void __softirq_entry __do_softirq(void) ++static void handle_softirqs(bool ksirqd) + { + unsigned long end = jiffies + MAX_SOFTIRQ_TIME; + unsigned long old_flags = current->flags; +@@ -562,8 +562,7 @@ asmlinkage __visible void __softirq_entry __do_softirq(void) + pending >>= softirq_bit; + } + +- if (!IS_ENABLED(CONFIG_PREEMPT_RT) && +- __this_cpu_read(ksoftirqd) == current) ++ if (!IS_ENABLED(CONFIG_PREEMPT_RT) && ksirqd) + rcu_softirq_qs(); + + local_irq_disable(); +@@ -583,6 +582,11 @@ asmlinkage __visible void __softirq_entry __do_softirq(void) + current_restore_flags(old_flags, PF_MEMALLOC); + } + ++asmlinkage __visible void __softirq_entry __do_softirq(void) ++{ ++ handle_softirqs(false); ++} ++ + /** + * irq_enter_rcu - Enter an interrupt context with RCU watching + */ +@@ -918,7 +922,7 @@ static void run_ksoftirqd(unsigned int cpu) + * We can safely run softirq on inline stack, as we are not deep + * in the task stack here. + */ +- __do_softirq(); ++ handle_softirqs(true); + ksoftirqd_run_end(); + cond_resched(); + return; +diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c +index 83ba342aef31f..2f80239348f5d 100644 +--- a/kernel/trace/ftrace.c ++++ b/kernel/trace/ftrace.c +@@ -1595,12 +1595,15 @@ static struct dyn_ftrace *lookup_rec(unsigned long start, unsigned long end) + unsigned long ftrace_location_range(unsigned long start, unsigned long end) + { + struct dyn_ftrace *rec; ++ unsigned long ip = 0; + ++ rcu_read_lock(); + rec = lookup_rec(start, end); + if (rec) +- return rec->ip; ++ ip = rec->ip; ++ rcu_read_unlock(); + +- return 0; ++ return ip; + } + + /** +@@ -1613,25 +1616,22 @@ unsigned long ftrace_location_range(unsigned long start, unsigned long end) + */ + unsigned long ftrace_location(unsigned long ip) + { +- struct dyn_ftrace *rec; ++ unsigned long loc; + unsigned long offset; + unsigned long size; + +- rec = lookup_rec(ip, ip); +- if (!rec) { ++ loc = ftrace_location_range(ip, ip); ++ if (!loc) { + if (!kallsyms_lookup_size_offset(ip, &size, &offset)) + goto out; + + /* map sym+0 to __fentry__ */ + if (!offset) +- rec = lookup_rec(ip, ip + size - 1); ++ loc = ftrace_location_range(ip, ip + size - 1); + } + +- if (rec) +- return rec->ip; +- + out: +- return 0; ++ return loc; + } + + /** +@@ -6593,6 +6593,8 @@ static int ftrace_process_locs(struct module *mod, + /* We should have used all pages unless we skipped some */ + if (pg_unuse) { + WARN_ON(!skipped); ++ /* Need to synchronize with ftrace_location_range() */ ++ synchronize_rcu(); + ftrace_free_pages(pg_unuse); + } + return ret; +@@ -6806,6 +6808,9 @@ void ftrace_release_mod(struct module *mod) + out_unlock: + mutex_unlock(&ftrace_lock); + ++ /* Need to synchronize with ftrace_location_range() */ ++ if (tmp_page) ++ synchronize_rcu(); + for (pg = tmp_page; pg; pg = tmp_page) { + + /* Needs to be called outside of ftrace_lock */ +@@ -7139,6 +7144,7 @@ void ftrace_free_mem(struct module *mod, void *start_ptr, void *end_ptr) + unsigned long start = (unsigned long)(start_ptr); + unsigned long end = (unsigned long)(end_ptr); + struct ftrace_page **last_pg = &ftrace_pages_start; ++ struct ftrace_page *tmp_page = NULL; + struct ftrace_page *pg; + struct dyn_ftrace *rec; + struct dyn_ftrace key; +@@ -7180,12 +7186,8 @@ void ftrace_free_mem(struct module *mod, void *start_ptr, void *end_ptr) + ftrace_update_tot_cnt--; + if (!pg->index) { + *last_pg = pg->next; +- if (pg->records) { +- free_pages((unsigned long)pg->records, pg->order); +- ftrace_number_of_pages -= 1 << pg->order; +- } +- ftrace_number_of_groups--; +- kfree(pg); ++ pg->next = tmp_page; ++ tmp_page = pg; + pg = container_of(last_pg, struct ftrace_page, next); + if (!(*last_pg)) + ftrace_pages = pg; +@@ -7202,6 +7204,11 @@ void ftrace_free_mem(struct module *mod, void *start_ptr, void *end_ptr) + clear_func_from_hashes(func); + kfree(func); + } ++ /* Need to synchronize with ftrace_location_range() */ ++ if (tmp_page) { ++ synchronize_rcu(); ++ ftrace_free_pages(tmp_page); ++ } + } + + void __init ftrace_free_init_mem(void) +diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c +index 4461bf43589d5..61caff3d4091f 100644 +--- a/kernel/trace/ring_buffer.c ++++ b/kernel/trace/ring_buffer.c +@@ -1592,6 +1592,11 @@ static void rb_check_bpage(struct ring_buffer_per_cpu *cpu_buffer, + * + * As a safety measure we check to make sure the data pages have not + * been corrupted. ++ * ++ * Callers of this function need to guarantee that the list of pages doesn't get ++ * modified during the check. In particular, if it's possible that the function ++ * is invoked with concurrent readers which can swap in a new reader page then ++ * the caller should take cpu_buffer->reader_lock. + */ + static void rb_check_pages(struct ring_buffer_per_cpu *cpu_buffer) + { +@@ -2331,8 +2336,12 @@ int ring_buffer_resize(struct trace_buffer *buffer, unsigned long size, + */ + synchronize_rcu(); + for_each_buffer_cpu(buffer, cpu) { ++ unsigned long flags; ++ + cpu_buffer = buffer->buffers[cpu]; ++ raw_spin_lock_irqsave(&cpu_buffer->reader_lock, flags); + rb_check_pages(cpu_buffer); ++ raw_spin_unlock_irqrestore(&cpu_buffer->reader_lock, flags); + } + atomic_dec(&buffer->record_disabled); + } +diff --git a/kernel/trace/rv/rv.c b/kernel/trace/rv/rv.c +index 2f68e93fff0bc..df0745a42a3f3 100644 +--- a/kernel/trace/rv/rv.c ++++ b/kernel/trace/rv/rv.c +@@ -245,6 +245,7 @@ static int __rv_disable_monitor(struct rv_monitor_def *mdef, bool sync) + + /** + * rv_disable_monitor - disable a given runtime monitor ++ * @mdef: Pointer to the monitor definition structure. + * + * Returns 0 on success. + */ +@@ -256,6 +257,7 @@ int rv_disable_monitor(struct rv_monitor_def *mdef) + + /** + * rv_enable_monitor - enable a given runtime monitor ++ * @mdef: Pointer to the monitor definition structure. + * + * Returns 0 on success, error otherwise. + */ +diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c +index 99f1308122866..2ae0f2807438a 100644 +--- a/kernel/trace/trace_events.c ++++ b/kernel/trace/trace_events.c +@@ -2518,6 +2518,14 @@ static int event_callback(const char *name, umode_t *mode, void **data, + return 0; + } + ++/* The file is incremented on creation and freeing the enable file decrements it */ ++static void event_release(const char *name, void *data) ++{ ++ struct trace_event_file *file = data; ++ ++ event_file_put(file); ++} ++ + static int + event_create_dir(struct eventfs_inode *parent, struct trace_event_file *file) + { +@@ -2532,6 +2540,7 @@ event_create_dir(struct eventfs_inode *parent, struct trace_event_file *file) + { + .name = "enable", + .callback = event_callback, ++ .release = event_release, + }, + { + .name = "filter", +@@ -2600,6 +2609,9 @@ event_create_dir(struct eventfs_inode *parent, struct trace_event_file *file) + return ret; + } + ++ /* Gets decremented on freeing of the "enable" file */ ++ event_file_get(file); ++ + return 0; + } + +diff --git a/kernel/trace/trace_events_user.c b/kernel/trace/trace_events_user.c +index b87f41187c6a9..2461786b1e4d2 100644 +--- a/kernel/trace/trace_events_user.c ++++ b/kernel/trace/trace_events_user.c +@@ -49,18 +49,6 @@ + #define EVENT_STATUS_PERF BIT(1) + #define EVENT_STATUS_OTHER BIT(7) + +-/* +- * User register flags are not allowed yet, keep them here until we are +- * ready to expose them out to the user ABI. +- */ +-enum user_reg_flag { +- /* Event will not delete upon last reference closing */ +- USER_EVENT_REG_PERSIST = 1U << 0, +- +- /* This value or above is currently non-ABI */ +- USER_EVENT_REG_MAX = 1U << 1, +-}; +- + /* + * Stores the system name, tables, and locks for a group of events. This + * allows isolation for events by various means. +@@ -214,12 +202,25 @@ static struct user_event_mm *user_event_mm_get(struct user_event_mm *mm); + static struct user_event_mm *user_event_mm_get_all(struct user_event *user); + static void user_event_mm_put(struct user_event_mm *mm); + static int destroy_user_event(struct user_event *user); ++static bool user_fields_match(struct user_event *user, int argc, ++ const char **argv); + + static u32 user_event_key(char *name) + { + return jhash(name, strlen(name), 0); + } + ++static bool user_event_capable(u16 reg_flags) ++{ ++ /* Persistent events require CAP_PERFMON / CAP_SYS_ADMIN */ ++ if (reg_flags & USER_EVENT_REG_PERSIST) { ++ if (!perfmon_capable()) ++ return false; ++ } ++ ++ return true; ++} ++ + static struct user_event *user_event_get(struct user_event *user) + { + refcount_inc(&user->refcnt); +@@ -1494,17 +1495,24 @@ static int destroy_user_event(struct user_event *user) + } + + static struct user_event *find_user_event(struct user_event_group *group, +- char *name, u32 *outkey) ++ char *name, int argc, const char **argv, ++ u32 flags, u32 *outkey) + { + struct user_event *user; + u32 key = user_event_key(name); + + *outkey = key; + +- hash_for_each_possible(group->register_table, user, node, key) +- if (!strcmp(EVENT_NAME(user), name)) ++ hash_for_each_possible(group->register_table, user, node, key) { ++ if (strcmp(EVENT_NAME(user), name)) ++ continue; ++ ++ if (user_fields_match(user, argc, argv)) + return user_event_get(user); + ++ return ERR_PTR(-EADDRINUSE); ++ } ++ + return NULL; + } + +@@ -1811,6 +1819,9 @@ static int user_event_free(struct dyn_event *ev) + if (!user_event_last_ref(user)) + return -EBUSY; + ++ if (!user_event_capable(user->reg_flags)) ++ return -EPERM; ++ + return destroy_user_event(user); + } + +@@ -1858,6 +1869,9 @@ static bool user_fields_match(struct user_event *user, int argc, + struct list_head *head = &user->fields; + int i = 0; + ++ if (argc == 0) ++ return list_empty(head); ++ + list_for_each_entry_reverse(field, head, link) { + if (!user_field_match(field, argc, argv, &i)) + return false; +@@ -1878,10 +1892,8 @@ static bool user_event_match(const char *system, const char *event, + match = strcmp(EVENT_NAME(user), event) == 0 && + (!system || strcmp(system, USER_EVENTS_SYSTEM) == 0); + +- if (match && argc > 0) ++ if (match) + match = user_fields_match(user, argc, argv); +- else if (match && argc == 0) +- match = list_empty(&user->fields); + + return match; + } +@@ -1911,6 +1923,80 @@ static int user_event_trace_register(struct user_event *user) + return ret; + } + ++/* ++ * Counts how many ';' without a trailing space are in the args. ++ */ ++static int count_semis_no_space(char *args) ++{ ++ int count = 0; ++ ++ while ((args = strchr(args, ';'))) { ++ args++; ++ ++ if (!isspace(*args)) ++ count++; ++ } ++ ++ return count; ++} ++ ++/* ++ * Copies the arguments while ensuring all ';' have a trailing space. ++ */ ++static char *insert_space_after_semis(char *args, int count) ++{ ++ char *fixed, *pos; ++ int len; ++ ++ len = strlen(args) + count; ++ fixed = kmalloc(len + 1, GFP_KERNEL); ++ ++ if (!fixed) ++ return NULL; ++ ++ pos = fixed; ++ ++ /* Insert a space after ';' if there is no trailing space. */ ++ while (*args) { ++ *pos = *args++; ++ ++ if (*pos++ == ';' && !isspace(*args)) ++ *pos++ = ' '; ++ } ++ ++ *pos = '\0'; ++ ++ return fixed; ++} ++ ++static char **user_event_argv_split(char *args, int *argc) ++{ ++ char **split; ++ char *fixed; ++ int count; ++ ++ /* Count how many ';' without a trailing space */ ++ count = count_semis_no_space(args); ++ ++ /* No fixup is required */ ++ if (!count) ++ return argv_split(GFP_KERNEL, args, argc); ++ ++ /* We must fixup 'field;field' to 'field; field' */ ++ fixed = insert_space_after_semis(args, count); ++ ++ if (!fixed) ++ return NULL; ++ ++ /* We do a normal split afterwards */ ++ split = argv_split(GFP_KERNEL, fixed, argc); ++ ++ /* We can free since argv_split makes a copy */ ++ kfree(fixed); ++ ++ return split; ++} ++ + /* + * Parses the event name, arguments and flags then registers if successful. + * The name buffer lifetime is owned by this method for success cases only. +@@ -1920,51 +2006,47 @@ static int user_event_parse(struct user_event_group *group, char *name, + char *args, char *flags, + struct user_event **newuser, int reg_flags) + { +- int ret; +- u32 key; + struct user_event *user; ++ char **argv = NULL; + int argc = 0; +- char **argv; ++ int ret; ++ u32 key; + +- /* User register flags are not ready yet */ +- if (reg_flags != 0 || flags != NULL) ++ /* Currently don't support any text based flags */ ++ if (flags != NULL) + return -EINVAL; + ++ if (!user_event_capable(reg_flags)) ++ return -EPERM; ++ ++ if (args) { ++ argv = user_event_argv_split(args, &argc); ++ ++ if (!argv) ++ return -ENOMEM; ++ } ++ + /* Prevent dyn_event from racing */ + mutex_lock(&event_mutex); +- user = find_user_event(group, name, &key); ++ user = find_user_event(group, name, argc, (const char **)argv, ++ reg_flags, &key); + mutex_unlock(&event_mutex); + +- if (user) { +- if (args) { +- argv = argv_split(GFP_KERNEL, args, &argc); +- if (!argv) { +- ret = -ENOMEM; +- goto error; +- } ++ if (argv) ++ argv_free(argv); + +- ret = user_fields_match(user, argc, (const char **)argv); +- argv_free(argv); +- +- } else +- ret = list_empty(&user->fields); +- +- if (ret) { +- *newuser = user; +- /* +- * Name is allocated by caller, free it since it already exists. +- * Caller only worries about failure cases for freeing. +- */ +- kfree(name); +- } else { +- ret = -EADDRINUSE; +- goto error; +- } ++ if (IS_ERR(user)) ++ return PTR_ERR(user); ++ ++ if (user) { ++ *newuser = user; ++ /* ++ * Name is allocated by caller, free it since it already exists. ++ * Caller only worries about failure cases for freeing. ++ */ ++ kfree(name); + + return 0; +-error: +- user_event_put(user, false); +- return ret; + } + + user = kzalloc(sizeof(*user), GFP_KERNEL_ACCOUNT); +@@ -2047,22 +2129,33 @@ static int user_event_parse(struct user_event_group *group, char *name, + } + + /* +- * Deletes a previously created event if it is no longer being used. ++ * Deletes previously created events if they are no longer being used. + */ + static int delete_user_event(struct user_event_group *group, char *name) + { +- u32 key; +- struct user_event *user = find_user_event(group, name, &key); ++ struct user_event *user; ++ struct hlist_node *tmp; ++ u32 key = user_event_key(name); ++ int ret = -ENOENT; + +- if (!user) +- return -ENOENT; ++ /* Attempt to delete all event(s) with the name passed in */ ++ hash_for_each_possible_safe(group->register_table, user, tmp, node, key) { ++ if (strcmp(EVENT_NAME(user), name)) ++ continue; + +- user_event_put(user, true); ++ if (!user_event_last_ref(user)) ++ return -EBUSY; + +- if (!user_event_last_ref(user)) +- return -EBUSY; ++ if (!user_event_capable(user->reg_flags)) ++ return -EPERM; + +- return destroy_user_event(user); ++ ret = destroy_user_event(user); ++ ++ if (ret) ++ goto out; ++ } ++out: ++ return ret; + } + + /* +diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c +index 34289f9c67076..ae162ba36a480 100644 +--- a/kernel/trace/trace_probe.c ++++ b/kernel/trace/trace_probe.c +@@ -553,6 +553,10 @@ static int parse_btf_field(char *fieldname, const struct btf_type *type, + anon_offs = 0; + field = btf_find_struct_member(ctx->btf, type, fieldname, + &anon_offs); ++ if (IS_ERR(field)) { ++ trace_probe_log_err(ctx->offset, BAD_BTF_TID); ++ return PTR_ERR(field); ++ } + if (!field) { + trace_probe_log_err(ctx->offset, NO_BTF_FIELD); + return -ENOENT; +diff --git a/lib/fortify_kunit.c b/lib/fortify_kunit.c +index c8c33cbaae9ec..24f8d6fda2b3b 100644 +--- a/lib/fortify_kunit.c ++++ b/lib/fortify_kunit.c +@@ -228,28 +228,28 @@ DEFINE_ALLOC_SIZE_TEST_PAIR(vmalloc) + \ + checker((expected_pages) * PAGE_SIZE, \ + kvmalloc((alloc_pages) * PAGE_SIZE, gfp), \ +- vfree(p)); \ ++ kvfree(p)); \ + checker((expected_pages) * PAGE_SIZE, \ + kvmalloc_node((alloc_pages) * PAGE_SIZE, gfp, NUMA_NO_NODE), \ +- vfree(p)); \ ++ kvfree(p)); \ + checker((expected_pages) * PAGE_SIZE, \ + kvzalloc((alloc_pages) * PAGE_SIZE, gfp), \ +- vfree(p)); \ ++ kvfree(p)); \ + checker((expected_pages) * PAGE_SIZE, \ + kvzalloc_node((alloc_pages) * PAGE_SIZE, gfp, NUMA_NO_NODE), \ +- vfree(p)); \ ++ kvfree(p)); \ + checker((expected_pages) * PAGE_SIZE, \ + kvcalloc(1, (alloc_pages) * PAGE_SIZE, gfp), \ +- vfree(p)); \ ++ kvfree(p)); \ + checker((expected_pages) * PAGE_SIZE, \ + kvcalloc((alloc_pages) * PAGE_SIZE, 1, gfp), \ +- vfree(p)); \ ++ kvfree(p)); \ + checker((expected_pages) * PAGE_SIZE, \ + kvmalloc_array(1, (alloc_pages) * PAGE_SIZE, gfp), \ +- vfree(p)); \ ++ kvfree(p)); \ + checker((expected_pages) * PAGE_SIZE, \ + kvmalloc_array((alloc_pages) * PAGE_SIZE, 1, gfp), \ +- vfree(p)); \ ++ kvfree(p)); \ + \ + prev_size = (expected_pages) * PAGE_SIZE; \ + orig = kvmalloc(prev_size, gfp); \ +diff --git a/lib/kunit/try-catch.c b/lib/kunit/try-catch.c +index f7825991d576a..d9d1df28cc52e 100644 +--- a/lib/kunit/try-catch.c ++++ b/lib/kunit/try-catch.c +@@ -11,6 +11,7 @@ + #include + #include + #include ++#include + + #include "try-catch-impl.h" + +@@ -65,13 +66,14 @@ void kunit_try_catch_run(struct kunit_try_catch *try_catch, void *context) + try_catch->context = context; + try_catch->try_completion = &try_completion; + try_catch->try_result = 0; +- task_struct = kthread_run(kunit_generic_run_threadfn_adapter, +- try_catch, +- "kunit_try_catch_thread"); ++ task_struct = kthread_create(kunit_generic_run_threadfn_adapter, ++ try_catch, "kunit_try_catch_thread"); + if (IS_ERR(task_struct)) { + try_catch->catch(try_catch->context); + return; + } ++ get_task_struct(task_struct); ++ wake_up_process(task_struct); + + time_remaining = wait_for_completion_timeout(&try_completion, + kunit_test_timeout()); +@@ -81,6 +83,7 @@ void kunit_try_catch_run(struct kunit_try_catch *try_catch, void *context) + kthread_stop(task_struct); + } + ++ put_task_struct(task_struct); + exit_code = try_catch->try_result; + + if (!exit_code) +diff --git a/lib/slub_kunit.c b/lib/slub_kunit.c +index d4a3730b08fa7..4ce9604388069 100644 +--- a/lib/slub_kunit.c ++++ b/lib/slub_kunit.c +@@ -55,7 +55,7 @@ static void test_next_pointer(struct kunit *test) + + ptr_addr = (unsigned long *)(p + s->offset); + tmp = *ptr_addr; +- p[s->offset] = 0x12; ++ p[s->offset] = ~p[s->offset]; + + /* + * Expecting three errors. +diff --git a/lib/test_hmm.c b/lib/test_hmm.c +index 717dcb8301273..b823ba7cb6a15 100644 +--- a/lib/test_hmm.c ++++ b/lib/test_hmm.c +@@ -1226,8 +1226,8 @@ static void dmirror_device_evict_chunk(struct dmirror_chunk *chunk) + unsigned long *src_pfns; + unsigned long *dst_pfns; + +- src_pfns = kcalloc(npages, sizeof(*src_pfns), GFP_KERNEL); +- dst_pfns = kcalloc(npages, sizeof(*dst_pfns), GFP_KERNEL); ++ src_pfns = kvcalloc(npages, sizeof(*src_pfns), GFP_KERNEL | __GFP_NOFAIL); ++ dst_pfns = kvcalloc(npages, sizeof(*dst_pfns), GFP_KERNEL | __GFP_NOFAIL); + + migrate_device_range(src_pfns, start_pfn, npages); + for (i = 0; i < npages; i++) { +@@ -1250,8 +1250,8 @@ static void dmirror_device_evict_chunk(struct dmirror_chunk *chunk) + } + migrate_device_pages(src_pfns, dst_pfns, npages); + migrate_device_finalize(src_pfns, dst_pfns, npages); +- kfree(src_pfns); +- kfree(dst_pfns); ++ kvfree(src_pfns); ++ kvfree(dst_pfns); + } + + /* Removes free pages from the free list so they can't be re-allocated */ +diff --git a/mm/damon/core.c b/mm/damon/core.c +index aff611b6eafe1..38e206075143a 100644 +--- a/mm/damon/core.c ++++ b/mm/damon/core.c +@@ -708,8 +708,7 @@ static int __damon_stop(struct damon_ctx *ctx) + if (tsk) { + get_task_struct(tsk); + mutex_unlock(&ctx->kdamond_lock); +- kthread_stop(tsk); +- put_task_struct(tsk); ++ kthread_stop_put(tsk); + return 0; + } + mutex_unlock(&ctx->kdamond_lock); +diff --git a/mm/userfaultfd.c b/mm/userfaultfd.c +index cd5ad448ac2f0..e76faba102797 100644 +--- a/mm/userfaultfd.c ++++ b/mm/userfaultfd.c +@@ -213,6 +213,38 @@ static int mfill_atomic_pte_copy(pmd_t *dst_pmd, + goto out; + } + ++static int mfill_atomic_pte_zeroed_folio(pmd_t *dst_pmd, ++ struct vm_area_struct *dst_vma, ++ unsigned long dst_addr) ++{ ++ struct folio *folio; ++ int ret = -ENOMEM; ++ ++ folio = vma_alloc_zeroed_movable_folio(dst_vma, dst_addr); ++ if (!folio) ++ return ret; ++ ++ if (mem_cgroup_charge(folio, dst_vma->vm_mm, GFP_KERNEL)) ++ goto out_put; ++ ++ /* ++ * The memory barrier inside __folio_mark_uptodate makes sure that ++ * zeroing out the folio become visible before mapping the page ++ * using set_pte_at(). See do_anonymous_page(). ++ */ ++ __folio_mark_uptodate(folio); ++ ++ ret = mfill_atomic_install_pte(dst_pmd, dst_vma, dst_addr, ++ &folio->page, true, 0); ++ if (ret) ++ goto out_put; ++ ++ return 0; ++out_put: ++ folio_put(folio); ++ return ret; ++} ++ + static int mfill_atomic_pte_zeropage(pmd_t *dst_pmd, + struct vm_area_struct *dst_vma, + unsigned long dst_addr) +@@ -221,6 +253,9 @@ static int mfill_atomic_pte_zeropage(pmd_t *dst_pmd, + spinlock_t *ptl; + int ret; + ++ if (mm_forbids_zeropage(dst_vma->vm_mm)) ++ return mfill_atomic_pte_zeroed_folio(dst_pmd, dst_vma, dst_addr); ++ + _dst_pte = pte_mkspecial(pfn_pte(my_zero_pfn(dst_addr), + dst_vma->vm_page_prot)); + ret = -EAGAIN; +diff --git a/net/ax25/ax25_dev.c b/net/ax25/ax25_dev.c +index 282ec581c0720..c9d55b99a7a57 100644 +--- a/net/ax25/ax25_dev.c ++++ b/net/ax25/ax25_dev.c +@@ -22,11 +22,12 @@ + #include + #include + #include ++#include + #include + #include + #include + +-ax25_dev *ax25_dev_list; ++static LIST_HEAD(ax25_dev_list); + DEFINE_SPINLOCK(ax25_dev_lock); + + ax25_dev *ax25_addr_ax25dev(ax25_address *addr) +@@ -34,10 +35,11 @@ ax25_dev *ax25_addr_ax25dev(ax25_address *addr) + ax25_dev *ax25_dev, *res = NULL; + + spin_lock_bh(&ax25_dev_lock); +- for (ax25_dev = ax25_dev_list; ax25_dev != NULL; ax25_dev = ax25_dev->next) ++ list_for_each_entry(ax25_dev, &ax25_dev_list, list) + if (ax25cmp(addr, (const ax25_address *)ax25_dev->dev->dev_addr) == 0) { + res = ax25_dev; + ax25_dev_hold(ax25_dev); ++ break; + } + spin_unlock_bh(&ax25_dev_lock); + +@@ -59,7 +61,6 @@ void ax25_dev_device_up(struct net_device *dev) + } + + refcount_set(&ax25_dev->refcount, 1); +- dev->ax25_ptr = ax25_dev; + ax25_dev->dev = dev; + netdev_hold(dev, &ax25_dev->dev_tracker, GFP_KERNEL); + ax25_dev->forward = NULL; +@@ -85,10 +86,9 @@ void ax25_dev_device_up(struct net_device *dev) + #endif + + spin_lock_bh(&ax25_dev_lock); +- ax25_dev->next = ax25_dev_list; +- ax25_dev_list = ax25_dev; ++ list_add(&ax25_dev->list, &ax25_dev_list); ++ dev->ax25_ptr = ax25_dev; + spin_unlock_bh(&ax25_dev_lock); +- ax25_dev_hold(ax25_dev); + + ax25_register_dev_sysctl(ax25_dev); + } +@@ -111,32 +111,19 @@ void ax25_dev_device_down(struct net_device *dev) + /* + * Remove any packet forwarding that points to this device. + */ +- for (s = ax25_dev_list; s != NULL; s = s->next) ++ list_for_each_entry(s, &ax25_dev_list, list) + if (s->forward == dev) + s->forward = NULL; + +- if ((s = ax25_dev_list) == ax25_dev) { +- ax25_dev_list = s->next; +- goto unlock_put; +- } +- +- while (s != NULL && s->next != NULL) { +- if (s->next == ax25_dev) { +- s->next = ax25_dev->next; +- goto unlock_put; ++ list_for_each_entry(s, &ax25_dev_list, list) { ++ if (s == ax25_dev) { ++ list_del(&s->list); ++ break; + } +- +- s = s->next; + } +- spin_unlock_bh(&ax25_dev_lock); +- dev->ax25_ptr = NULL; +- ax25_dev_put(ax25_dev); +- return; + +-unlock_put: +- spin_unlock_bh(&ax25_dev_lock); +- ax25_dev_put(ax25_dev); + dev->ax25_ptr = NULL; ++ spin_unlock_bh(&ax25_dev_lock); + netdev_put(dev, &ax25_dev->dev_tracker); + ax25_dev_put(ax25_dev); + } +@@ -200,16 +187,13 @@ struct net_device *ax25_fwd_dev(struct net_device *dev) + */ + void __exit ax25_dev_free(void) + { +- ax25_dev *s, *ax25_dev; ++ ax25_dev *s, *n; + + spin_lock_bh(&ax25_dev_lock); +- ax25_dev = ax25_dev_list; +- while (ax25_dev != NULL) { +- s = ax25_dev; +- netdev_put(ax25_dev->dev, &ax25_dev->dev_tracker); +- ax25_dev = ax25_dev->next; ++ list_for_each_entry_safe(s, n, &ax25_dev_list, list) { ++ netdev_put(s->dev, &s->dev_tracker); ++ list_del(&s->list); + kfree(s); + } +- ax25_dev_list = NULL; + spin_unlock_bh(&ax25_dev_lock); + } +diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c +index aea7f06c107eb..163b56a68bb04 100644 +--- a/net/bluetooth/hci_conn.c ++++ b/net/bluetooth/hci_conn.c +@@ -759,6 +759,7 @@ static int terminate_big_sync(struct hci_dev *hdev, void *data) + + bt_dev_dbg(hdev, "big 0x%2.2x bis 0x%2.2x", d->big, d->bis); + ++ hci_disable_per_advertising_sync(hdev, d->bis); + hci_remove_ext_adv_instance_sync(hdev, d->bis, NULL); + + /* Only terminate BIG if it has been created */ +@@ -1199,8 +1200,7 @@ struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src, uint8_t src_type) + + list_for_each_entry(d, &hci_dev_list, list) { + if (!test_bit(HCI_UP, &d->flags) || +- hci_dev_test_flag(d, HCI_USER_CHANNEL) || +- d->dev_type != HCI_PRIMARY) ++ hci_dev_test_flag(d, HCI_USER_CHANNEL)) + continue; + + /* Simple routing: +@@ -1279,6 +1279,12 @@ void hci_conn_failed(struct hci_conn *conn, u8 status) + break; + } + ++ /* In case of BIG/PA sync failed, clear conn flags so that ++ * the conns will be correctly cleaned up by ISO layer ++ */ ++ test_and_clear_bit(HCI_CONN_BIG_SYNC_FAILED, &conn->flags); ++ test_and_clear_bit(HCI_CONN_PA_SYNC_FAILED, &conn->flags); ++ + conn->state = BT_CLOSED; + hci_connect_cfm(conn, status); + hci_conn_del(conn); +diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c +index befe645d3f9bf..3817d6369f0cc 100644 +--- a/net/bluetooth/hci_core.c ++++ b/net/bluetooth/hci_core.c +@@ -395,11 +395,6 @@ int hci_inquiry(void __user *arg) + goto done; + } + +- if (hdev->dev_type != HCI_PRIMARY) { +- err = -EOPNOTSUPP; +- goto done; +- } +- + if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) { + err = -EOPNOTSUPP; + goto done; +@@ -752,11 +747,6 @@ int hci_dev_cmd(unsigned int cmd, void __user *arg) + goto done; + } + +- if (hdev->dev_type != HCI_PRIMARY) { +- err = -EOPNOTSUPP; +- goto done; +- } +- + if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) { + err = -EOPNOTSUPP; + goto done; +@@ -910,7 +900,7 @@ int hci_get_dev_info(void __user *arg) + + strscpy(di.name, hdev->name, sizeof(di.name)); + di.bdaddr = hdev->bdaddr; +- di.type = (hdev->bus & 0x0f) | ((hdev->dev_type & 0x03) << 4); ++ di.type = (hdev->bus & 0x0f); + di.flags = flags; + di.pkt_type = hdev->pkt_type; + if (lmp_bredr_capable(hdev)) { +@@ -995,8 +985,7 @@ static void hci_power_on(struct work_struct *work) + */ + if (hci_dev_test_flag(hdev, HCI_RFKILLED) || + hci_dev_test_flag(hdev, HCI_UNCONFIGURED) || +- (hdev->dev_type == HCI_PRIMARY && +- !bacmp(&hdev->bdaddr, BDADDR_ANY) && ++ (!bacmp(&hdev->bdaddr, BDADDR_ANY) && + !bacmp(&hdev->static_addr, BDADDR_ANY))) { + hci_dev_clear_flag(hdev, HCI_AUTO_OFF); + hci_dev_do_close(hdev); +@@ -2604,20 +2593,7 @@ int hci_register_dev(struct hci_dev *hdev) + if (!hdev->open || !hdev->close || !hdev->send) + return -EINVAL; + +- /* Do not allow HCI_AMP devices to register at index 0, +- * so the index can be used as the AMP controller ID. +- */ +- switch (hdev->dev_type) { +- case HCI_PRIMARY: +- id = ida_simple_get(&hci_index_ida, 0, HCI_MAX_ID, GFP_KERNEL); +- break; +- case HCI_AMP: +- id = ida_simple_get(&hci_index_ida, 1, HCI_MAX_ID, GFP_KERNEL); +- break; +- default: +- return -EINVAL; +- } +- ++ id = ida_alloc_max(&hci_index_ida, HCI_MAX_ID - 1, GFP_KERNEL); + if (id < 0) + return id; + +@@ -2669,12 +2645,10 @@ int hci_register_dev(struct hci_dev *hdev) + hci_dev_set_flag(hdev, HCI_SETUP); + hci_dev_set_flag(hdev, HCI_AUTO_OFF); + +- if (hdev->dev_type == HCI_PRIMARY) { +- /* Assume BR/EDR support until proven otherwise (such as +- * through reading supported features during init. +- */ +- hci_dev_set_flag(hdev, HCI_BREDR_ENABLED); +- } ++ /* Assume BR/EDR support until proven otherwise (such as ++ * through reading supported features during init. ++ */ ++ hci_dev_set_flag(hdev, HCI_BREDR_ENABLED); + + write_lock(&hci_dev_list_lock); + list_add(&hdev->list, &hci_dev_list); +@@ -2711,7 +2685,7 @@ int hci_register_dev(struct hci_dev *hdev) + destroy_workqueue(hdev->workqueue); + destroy_workqueue(hdev->req_workqueue); + err: +- ida_simple_remove(&hci_index_ida, hdev->id); ++ ida_free(&hci_index_ida, hdev->id); + + return error; + } +@@ -2793,7 +2767,7 @@ void hci_release_dev(struct hci_dev *hdev) + hci_dev_unlock(hdev); + + ida_destroy(&hdev->unset_handle_ida); +- ida_simple_remove(&hci_index_ida, hdev->id); ++ ida_free(&hci_index_ida, hdev->id); + kfree_skb(hdev->sent_cmd); + kfree_skb(hdev->req_skb); + kfree_skb(hdev->recv_event); +@@ -3210,17 +3184,7 @@ static void hci_queue_acl(struct hci_chan *chan, struct sk_buff_head *queue, + + hci_skb_pkt_type(skb) = HCI_ACLDATA_PKT; + +- switch (hdev->dev_type) { +- case HCI_PRIMARY: +- hci_add_acl_hdr(skb, conn->handle, flags); +- break; +- case HCI_AMP: +- hci_add_acl_hdr(skb, chan->handle, flags); +- break; +- default: +- bt_dev_err(hdev, "unknown dev_type %d", hdev->dev_type); +- return; +- } ++ hci_add_acl_hdr(skb, conn->handle, flags); + + list = skb_shinfo(skb)->frag_list; + if (!list) { +@@ -3380,9 +3344,6 @@ static inline void hci_quote_sent(struct hci_conn *conn, int num, int *quote) + case ACL_LINK: + cnt = hdev->acl_cnt; + break; +- case AMP_LINK: +- cnt = hdev->block_cnt; +- break; + case SCO_LINK: + case ESCO_LINK: + cnt = hdev->sco_cnt; +@@ -3580,12 +3541,6 @@ static void hci_prio_recalculate(struct hci_dev *hdev, __u8 type) + + } + +-static inline int __get_blocks(struct hci_dev *hdev, struct sk_buff *skb) +-{ +- /* Calculate count of blocks used by this packet */ +- return DIV_ROUND_UP(skb->len - HCI_ACL_HDR_SIZE, hdev->block_len); +-} +- + static void __check_timeout(struct hci_dev *hdev, unsigned int cnt, u8 type) + { + unsigned long last_tx; +@@ -3699,81 +3654,15 @@ static void hci_sched_acl_pkt(struct hci_dev *hdev) + hci_prio_recalculate(hdev, ACL_LINK); + } + +-static void hci_sched_acl_blk(struct hci_dev *hdev) +-{ +- unsigned int cnt = hdev->block_cnt; +- struct hci_chan *chan; +- struct sk_buff *skb; +- int quote; +- u8 type; +- +- BT_DBG("%s", hdev->name); +- +- if (hdev->dev_type == HCI_AMP) +- type = AMP_LINK; +- else +- type = ACL_LINK; +- +- __check_timeout(hdev, cnt, type); +- +- while (hdev->block_cnt > 0 && +- (chan = hci_chan_sent(hdev, type, "e))) { +- u32 priority = (skb_peek(&chan->data_q))->priority; +- while (quote > 0 && (skb = skb_peek(&chan->data_q))) { +- int blocks; +- +- BT_DBG("chan %p skb %p len %d priority %u", chan, skb, +- skb->len, skb->priority); +- +- /* Stop if priority has changed */ +- if (skb->priority < priority) +- break; +- +- skb = skb_dequeue(&chan->data_q); +- +- blocks = __get_blocks(hdev, skb); +- if (blocks > hdev->block_cnt) +- return; +- +- hci_conn_enter_active_mode(chan->conn, +- bt_cb(skb)->force_active); +- +- hci_send_frame(hdev, skb); +- hdev->acl_last_tx = jiffies; +- +- hdev->block_cnt -= blocks; +- quote -= blocks; +- +- chan->sent += blocks; +- chan->conn->sent += blocks; +- } +- } +- +- if (cnt != hdev->block_cnt) +- hci_prio_recalculate(hdev, type); +-} +- + static void hci_sched_acl(struct hci_dev *hdev) + { + BT_DBG("%s", hdev->name); + + /* No ACL link over BR/EDR controller */ +- if (!hci_conn_num(hdev, ACL_LINK) && hdev->dev_type == HCI_PRIMARY) +- return; +- +- /* No AMP link over AMP controller */ +- if (!hci_conn_num(hdev, AMP_LINK) && hdev->dev_type == HCI_AMP) ++ if (!hci_conn_num(hdev, ACL_LINK)) + return; + +- switch (hdev->flow_ctl_mode) { +- case HCI_FLOW_CTL_MODE_PACKET_BASED: +- hci_sched_acl_pkt(hdev); +- break; +- +- case HCI_FLOW_CTL_MODE_BLOCK_BASED: +- hci_sched_acl_blk(hdev); +- break; +- } ++ hci_sched_acl_pkt(hdev); + } + + static void hci_sched_le(struct hci_dev *hdev) +diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c +index 361e2c68a51a1..6ce4f812503f4 100644 +--- a/net/bluetooth/hci_event.c ++++ b/net/bluetooth/hci_event.c +@@ -917,21 +917,6 @@ static u8 hci_cc_read_local_ext_features(struct hci_dev *hdev, void *data, + return rp->status; + } + +-static u8 hci_cc_read_flow_control_mode(struct hci_dev *hdev, void *data, +- struct sk_buff *skb) +-{ +- struct hci_rp_read_flow_control_mode *rp = data; +- +- bt_dev_dbg(hdev, "status 0x%2.2x", rp->status); +- +- if (rp->status) +- return rp->status; +- +- hdev->flow_ctl_mode = rp->mode; +- +- return rp->status; +-} +- + static u8 hci_cc_read_buffer_size(struct hci_dev *hdev, void *data, + struct sk_buff *skb) + { +@@ -1075,28 +1060,6 @@ static u8 hci_cc_write_page_scan_type(struct hci_dev *hdev, void *data, + return rp->status; + } + +-static u8 hci_cc_read_data_block_size(struct hci_dev *hdev, void *data, +- struct sk_buff *skb) +-{ +- struct hci_rp_read_data_block_size *rp = data; +- +- bt_dev_dbg(hdev, "status 0x%2.2x", rp->status); +- +- if (rp->status) +- return rp->status; +- +- hdev->block_mtu = __le16_to_cpu(rp->max_acl_len); +- hdev->block_len = __le16_to_cpu(rp->block_len); +- hdev->num_blocks = __le16_to_cpu(rp->num_blocks); +- +- hdev->block_cnt = hdev->num_blocks; +- +- BT_DBG("%s blk mtu %d cnt %d len %d", hdev->name, hdev->block_mtu, +- hdev->block_cnt, hdev->block_len); +- +- return rp->status; +-} +- + static u8 hci_cc_read_clock(struct hci_dev *hdev, void *data, + struct sk_buff *skb) + { +@@ -1131,30 +1094,6 @@ static u8 hci_cc_read_clock(struct hci_dev *hdev, void *data, + return rp->status; + } + +-static u8 hci_cc_read_local_amp_info(struct hci_dev *hdev, void *data, +- struct sk_buff *skb) +-{ +- struct hci_rp_read_local_amp_info *rp = data; +- +- bt_dev_dbg(hdev, "status 0x%2.2x", rp->status); +- +- if (rp->status) +- return rp->status; +- +- hdev->amp_status = rp->amp_status; +- hdev->amp_total_bw = __le32_to_cpu(rp->total_bw); +- hdev->amp_max_bw = __le32_to_cpu(rp->max_bw); +- hdev->amp_min_latency = __le32_to_cpu(rp->min_latency); +- hdev->amp_max_pdu = __le32_to_cpu(rp->max_pdu); +- hdev->amp_type = rp->amp_type; +- hdev->amp_pal_cap = __le16_to_cpu(rp->pal_cap); +- hdev->amp_assoc_size = __le16_to_cpu(rp->max_assoc_size); +- hdev->amp_be_flush_to = __le32_to_cpu(rp->be_flush_to); +- hdev->amp_max_flush_to = __le32_to_cpu(rp->max_flush_to); +- +- return rp->status; +-} +- + static u8 hci_cc_read_inq_rsp_tx_power(struct hci_dev *hdev, void *data, + struct sk_buff *skb) + { +@@ -4134,12 +4073,6 @@ static const struct hci_cc { + HCI_CC(HCI_OP_READ_PAGE_SCAN_TYPE, hci_cc_read_page_scan_type, + sizeof(struct hci_rp_read_page_scan_type)), + HCI_CC_STATUS(HCI_OP_WRITE_PAGE_SCAN_TYPE, hci_cc_write_page_scan_type), +- HCI_CC(HCI_OP_READ_DATA_BLOCK_SIZE, hci_cc_read_data_block_size, +- sizeof(struct hci_rp_read_data_block_size)), +- HCI_CC(HCI_OP_READ_FLOW_CONTROL_MODE, hci_cc_read_flow_control_mode, +- sizeof(struct hci_rp_read_flow_control_mode)), +- HCI_CC(HCI_OP_READ_LOCAL_AMP_INFO, hci_cc_read_local_amp_info, +- sizeof(struct hci_rp_read_local_amp_info)), + HCI_CC(HCI_OP_READ_CLOCK, hci_cc_read_clock, + sizeof(struct hci_rp_read_clock)), + HCI_CC(HCI_OP_READ_ENC_KEY_SIZE, hci_cc_read_enc_key_size, +@@ -4474,11 +4407,6 @@ static void hci_num_comp_pkts_evt(struct hci_dev *hdev, void *data, + flex_array_size(ev, handles, ev->num))) + return; + +- if (hdev->flow_ctl_mode != HCI_FLOW_CTL_MODE_PACKET_BASED) { +- bt_dev_err(hdev, "wrong event for mode %d", hdev->flow_ctl_mode); +- return; +- } +- + bt_dev_dbg(hdev, "num %d", ev->num); + + for (i = 0; i < ev->num; i++) { +@@ -4546,78 +4474,6 @@ static void hci_num_comp_pkts_evt(struct hci_dev *hdev, void *data, + queue_work(hdev->workqueue, &hdev->tx_work); + } + +-static struct hci_conn *__hci_conn_lookup_handle(struct hci_dev *hdev, +- __u16 handle) +-{ +- struct hci_chan *chan; +- +- switch (hdev->dev_type) { +- case HCI_PRIMARY: +- return hci_conn_hash_lookup_handle(hdev, handle); +- case HCI_AMP: +- chan = hci_chan_lookup_handle(hdev, handle); +- if (chan) +- return chan->conn; +- break; +- default: +- bt_dev_err(hdev, "unknown dev_type %d", hdev->dev_type); +- break; +- } +- +- return NULL; +-} +- +-static void hci_num_comp_blocks_evt(struct hci_dev *hdev, void *data, +- struct sk_buff *skb) +-{ +- struct hci_ev_num_comp_blocks *ev = data; +- int i; +- +- if (!hci_ev_skb_pull(hdev, skb, HCI_EV_NUM_COMP_BLOCKS, +- flex_array_size(ev, handles, ev->num_hndl))) +- return; +- +- if (hdev->flow_ctl_mode != HCI_FLOW_CTL_MODE_BLOCK_BASED) { +- bt_dev_err(hdev, "wrong event for mode %d", +- hdev->flow_ctl_mode); +- return; +- } +- +- bt_dev_dbg(hdev, "num_blocks %d num_hndl %d", ev->num_blocks, +- ev->num_hndl); +- +- for (i = 0; i < ev->num_hndl; i++) { +- struct hci_comp_blocks_info *info = &ev->handles[i]; +- struct hci_conn *conn = NULL; +- __u16 handle, block_count; +- +- handle = __le16_to_cpu(info->handle); +- block_count = __le16_to_cpu(info->blocks); +- +- conn = __hci_conn_lookup_handle(hdev, handle); +- if (!conn) +- continue; +- +- conn->sent -= block_count; +- +- switch (conn->type) { +- case ACL_LINK: +- case AMP_LINK: +- hdev->block_cnt += block_count; +- if (hdev->block_cnt > hdev->num_blocks) +- hdev->block_cnt = hdev->num_blocks; +- break; +- +- default: +- bt_dev_err(hdev, "unknown type %d conn %p", +- conn->type, conn); +- break; +- } +- } +- +- queue_work(hdev->workqueue, &hdev->tx_work); +-} +- + static void hci_mode_change_evt(struct hci_dev *hdev, void *data, + struct sk_buff *skb) + { +@@ -5710,150 +5566,6 @@ static void hci_remote_oob_data_request_evt(struct hci_dev *hdev, void *edata, + hci_dev_unlock(hdev); + } + +-#if IS_ENABLED(CONFIG_BT_HS) +-static void hci_chan_selected_evt(struct hci_dev *hdev, void *data, +- struct sk_buff *skb) +-{ +- struct hci_ev_channel_selected *ev = data; +- struct hci_conn *hcon; +- +- bt_dev_dbg(hdev, "handle 0x%2.2x", ev->phy_handle); +- +- hcon = hci_conn_hash_lookup_handle(hdev, ev->phy_handle); +- if (!hcon) +- return; +- +- amp_read_loc_assoc_final_data(hdev, hcon); +-} +- +-static void hci_phy_link_complete_evt(struct hci_dev *hdev, void *data, +- struct sk_buff *skb) +-{ +- struct hci_ev_phy_link_complete *ev = data; +- struct hci_conn *hcon, *bredr_hcon; +- +- bt_dev_dbg(hdev, "handle 0x%2.2x status 0x%2.2x", ev->phy_handle, +- ev->status); +- +- hci_dev_lock(hdev); +- +- hcon = hci_conn_hash_lookup_handle(hdev, ev->phy_handle); +- if (!hcon) +- goto unlock; +- +- if (!hcon->amp_mgr) +- goto unlock; +- +- if (ev->status) { +- hci_conn_del(hcon); +- goto unlock; +- } +- +- bredr_hcon = hcon->amp_mgr->l2cap_conn->hcon; +- +- hcon->state = BT_CONNECTED; +- bacpy(&hcon->dst, &bredr_hcon->dst); +- +- hci_conn_hold(hcon); +- hcon->disc_timeout = HCI_DISCONN_TIMEOUT; +- hci_conn_drop(hcon); +- +- hci_debugfs_create_conn(hcon); +- hci_conn_add_sysfs(hcon); +- +- amp_physical_cfm(bredr_hcon, hcon); +- +-unlock: +- hci_dev_unlock(hdev); +-} +- +-static void hci_loglink_complete_evt(struct hci_dev *hdev, void *data, +- struct sk_buff *skb) +-{ +- struct hci_ev_logical_link_complete *ev = data; +- struct hci_conn *hcon; +- struct hci_chan *hchan; +- struct amp_mgr *mgr; +- +- bt_dev_dbg(hdev, "log_handle 0x%4.4x phy_handle 0x%2.2x status 0x%2.2x", +- le16_to_cpu(ev->handle), ev->phy_handle, ev->status); +- +- hcon = hci_conn_hash_lookup_handle(hdev, ev->phy_handle); +- if (!hcon) +- return; +- +- /* Create AMP hchan */ +- hchan = hci_chan_create(hcon); +- if (!hchan) +- return; +- +- hchan->handle = le16_to_cpu(ev->handle); +- hchan->amp = true; +- +- BT_DBG("hcon %p mgr %p hchan %p", hcon, hcon->amp_mgr, hchan); +- +- mgr = hcon->amp_mgr; +- if (mgr && mgr->bredr_chan) { +- struct l2cap_chan *bredr_chan = mgr->bredr_chan; +- +- l2cap_chan_lock(bredr_chan); +- +- bredr_chan->conn->mtu = hdev->block_mtu; +- l2cap_logical_cfm(bredr_chan, hchan, 0); +- hci_conn_hold(hcon); +- +- l2cap_chan_unlock(bredr_chan); +- } +-} +- +-static void hci_disconn_loglink_complete_evt(struct hci_dev *hdev, void *data, +- struct sk_buff *skb) +-{ +- struct hci_ev_disconn_logical_link_complete *ev = data; +- struct hci_chan *hchan; +- +- bt_dev_dbg(hdev, "handle 0x%4.4x status 0x%2.2x", +- le16_to_cpu(ev->handle), ev->status); +- +- if (ev->status) +- return; +- +- hci_dev_lock(hdev); +- +- hchan = hci_chan_lookup_handle(hdev, le16_to_cpu(ev->handle)); +- if (!hchan || !hchan->amp) +- goto unlock; +- +- amp_destroy_logical_link(hchan, ev->reason); +- +-unlock: +- hci_dev_unlock(hdev); +-} +- +-static void hci_disconn_phylink_complete_evt(struct hci_dev *hdev, void *data, +- struct sk_buff *skb) +-{ +- struct hci_ev_disconn_phy_link_complete *ev = data; +- struct hci_conn *hcon; +- +- bt_dev_dbg(hdev, "status 0x%2.2x", ev->status); +- +- if (ev->status) +- return; +- +- hci_dev_lock(hdev); +- +- hcon = hci_conn_hash_lookup_handle(hdev, ev->phy_handle); +- if (hcon && hcon->type == AMP_LINK) { +- hcon->state = BT_CLOSED; +- hci_disconn_cfm(hcon, ev->reason); +- hci_conn_del(hcon); +- } +- +- hci_dev_unlock(hdev); +-} +-#endif +- + static void le_conn_update_addr(struct hci_conn *conn, bdaddr_t *bdaddr, + u8 bdaddr_type, bdaddr_t *local_rpa) + { +@@ -7675,28 +7387,6 @@ static const struct hci_ev { + /* [0x3e = HCI_EV_LE_META] */ + HCI_EV_REQ_VL(HCI_EV_LE_META, hci_le_meta_evt, + sizeof(struct hci_ev_le_meta), HCI_MAX_EVENT_SIZE), +-#if IS_ENABLED(CONFIG_BT_HS) +- /* [0x40 = HCI_EV_PHY_LINK_COMPLETE] */ +- HCI_EV(HCI_EV_PHY_LINK_COMPLETE, hci_phy_link_complete_evt, +- sizeof(struct hci_ev_phy_link_complete)), +- /* [0x41 = HCI_EV_CHANNEL_SELECTED] */ +- HCI_EV(HCI_EV_CHANNEL_SELECTED, hci_chan_selected_evt, +- sizeof(struct hci_ev_channel_selected)), +- /* [0x42 = HCI_EV_DISCONN_PHY_LINK_COMPLETE] */ +- HCI_EV(HCI_EV_DISCONN_LOGICAL_LINK_COMPLETE, +- hci_disconn_loglink_complete_evt, +- sizeof(struct hci_ev_disconn_logical_link_complete)), +- /* [0x45 = HCI_EV_LOGICAL_LINK_COMPLETE] */ +- HCI_EV(HCI_EV_LOGICAL_LINK_COMPLETE, hci_loglink_complete_evt, +- sizeof(struct hci_ev_logical_link_complete)), +- /* [0x46 = HCI_EV_DISCONN_LOGICAL_LINK_COMPLETE] */ +- HCI_EV(HCI_EV_DISCONN_PHY_LINK_COMPLETE, +- hci_disconn_phylink_complete_evt, +- sizeof(struct hci_ev_disconn_phy_link_complete)), +-#endif +- /* [0x48 = HCI_EV_NUM_COMP_BLOCKS] */ +- HCI_EV(HCI_EV_NUM_COMP_BLOCKS, hci_num_comp_blocks_evt, +- sizeof(struct hci_ev_num_comp_blocks)), + /* [0xff = HCI_EV_VENDOR] */ + HCI_EV_VL(HCI_EV_VENDOR, msft_vendor_evt, 0, HCI_MAX_EVENT_SIZE), + }; +diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c +index 3e7cd330d731a..3d904ca92e9e8 100644 +--- a/net/bluetooth/hci_sock.c ++++ b/net/bluetooth/hci_sock.c +@@ -101,7 +101,7 @@ static bool hci_sock_gen_cookie(struct sock *sk) + int id = hci_pi(sk)->cookie; + + if (!id) { +- id = ida_simple_get(&sock_cookie_ida, 1, 0, GFP_KERNEL); ++ id = ida_alloc_min(&sock_cookie_ida, 1, GFP_KERNEL); + if (id < 0) + id = 0xffffffff; + +@@ -119,7 +119,7 @@ static void hci_sock_free_cookie(struct sock *sk) + + if (id) { + hci_pi(sk)->cookie = 0xffffffff; +- ida_simple_remove(&sock_cookie_ida, id); ++ ida_free(&sock_cookie_ida, id); + } + } + +@@ -485,7 +485,7 @@ static struct sk_buff *create_monitor_event(struct hci_dev *hdev, int event) + return NULL; + + ni = skb_put(skb, HCI_MON_NEW_INDEX_SIZE); +- ni->type = hdev->dev_type; ++ ni->type = 0x00; /* Old hdev->dev_type */ + ni->bus = hdev->bus; + bacpy(&ni->bdaddr, &hdev->bdaddr); + memcpy_and_pad(ni->name, sizeof(ni->name), hdev->name, +@@ -1007,9 +1007,6 @@ static int hci_sock_bound_ioctl(struct sock *sk, unsigned int cmd, + if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) + return -EOPNOTSUPP; + +- if (hdev->dev_type != HCI_PRIMARY) +- return -EOPNOTSUPP; +- + switch (cmd) { + case HCISETRAW: + if (!capable(CAP_NET_ADMIN)) +diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c +index 1bc58b324b73e..d7ca5bd8ba3b0 100644 +--- a/net/bluetooth/hci_sync.c ++++ b/net/bluetooth/hci_sync.c +@@ -1321,7 +1321,7 @@ int hci_start_ext_adv_sync(struct hci_dev *hdev, u8 instance) + return hci_enable_ext_advertising_sync(hdev, instance); + } + +-static int hci_disable_per_advertising_sync(struct hci_dev *hdev, u8 instance) ++int hci_disable_per_advertising_sync(struct hci_dev *hdev, u8 instance) + { + struct hci_cp_le_set_per_adv_enable cp; + struct adv_info *adv = NULL; +@@ -3440,10 +3440,6 @@ static int hci_unconf_init_sync(struct hci_dev *hdev) + /* Read Local Supported Features. */ + static int hci_read_local_features_sync(struct hci_dev *hdev) + { +- /* Not all AMP controllers support this command */ +- if (hdev->dev_type == HCI_AMP && !(hdev->commands[14] & 0x20)) +- return 0; +- + return __hci_cmd_sync_status(hdev, HCI_OP_READ_LOCAL_FEATURES, + 0, NULL, HCI_CMD_TIMEOUT); + } +@@ -3478,51 +3474,6 @@ static int hci_read_local_cmds_sync(struct hci_dev *hdev) + return 0; + } + +-/* Read Local AMP Info */ +-static int hci_read_local_amp_info_sync(struct hci_dev *hdev) +-{ +- return __hci_cmd_sync_status(hdev, HCI_OP_READ_LOCAL_AMP_INFO, +- 0, NULL, HCI_CMD_TIMEOUT); +-} +- +-/* Read Data Blk size */ +-static int hci_read_data_block_size_sync(struct hci_dev *hdev) +-{ +- return __hci_cmd_sync_status(hdev, HCI_OP_READ_DATA_BLOCK_SIZE, +- 0, NULL, HCI_CMD_TIMEOUT); +-} +- +-/* Read Flow Control Mode */ +-static int hci_read_flow_control_mode_sync(struct hci_dev *hdev) +-{ +- return __hci_cmd_sync_status(hdev, HCI_OP_READ_FLOW_CONTROL_MODE, +- 0, NULL, HCI_CMD_TIMEOUT); +-} +- +-/* Read Location Data */ +-static int hci_read_location_data_sync(struct hci_dev *hdev) +-{ +- return __hci_cmd_sync_status(hdev, HCI_OP_READ_LOCATION_DATA, +- 0, NULL, HCI_CMD_TIMEOUT); +-} +- +-/* AMP Controller init stage 1 command sequence */ +-static const struct hci_init_stage amp_init1[] = { +- /* HCI_OP_READ_LOCAL_VERSION */ +- HCI_INIT(hci_read_local_version_sync), +- /* HCI_OP_READ_LOCAL_COMMANDS */ +- HCI_INIT(hci_read_local_cmds_sync), +- /* HCI_OP_READ_LOCAL_AMP_INFO */ +- HCI_INIT(hci_read_local_amp_info_sync), +- /* HCI_OP_READ_DATA_BLOCK_SIZE */ +- HCI_INIT(hci_read_data_block_size_sync), +- /* HCI_OP_READ_FLOW_CONTROL_MODE */ +- HCI_INIT(hci_read_flow_control_mode_sync), +- /* HCI_OP_READ_LOCATION_DATA */ +- HCI_INIT(hci_read_location_data_sync), +- {} +-}; +- + static int hci_init1_sync(struct hci_dev *hdev) + { + int err; +@@ -3536,28 +3487,9 @@ static int hci_init1_sync(struct hci_dev *hdev) + return err; + } + +- switch (hdev->dev_type) { +- case HCI_PRIMARY: +- hdev->flow_ctl_mode = HCI_FLOW_CTL_MODE_PACKET_BASED; +- return hci_init_stage_sync(hdev, br_init1); +- case HCI_AMP: +- hdev->flow_ctl_mode = HCI_FLOW_CTL_MODE_BLOCK_BASED; +- return hci_init_stage_sync(hdev, amp_init1); +- default: +- bt_dev_err(hdev, "Unknown device type %d", hdev->dev_type); +- break; +- } +- +- return 0; ++ return hci_init_stage_sync(hdev, br_init1); + } + +-/* AMP Controller init stage 2 command sequence */ +-static const struct hci_init_stage amp_init2[] = { +- /* HCI_OP_READ_LOCAL_FEATURES */ +- HCI_INIT(hci_read_local_features_sync), +- {} +-}; +- + /* Read Buffer Size (ACL mtu, max pkt, etc.) */ + static int hci_read_buffer_size_sync(struct hci_dev *hdev) + { +@@ -3815,9 +3747,6 @@ static int hci_init2_sync(struct hci_dev *hdev) + + bt_dev_dbg(hdev, ""); + +- if (hdev->dev_type == HCI_AMP) +- return hci_init_stage_sync(hdev, amp_init2); +- + err = hci_init_stage_sync(hdev, hci_init2); + if (err) + return err; +@@ -4655,13 +4584,6 @@ static int hci_init_sync(struct hci_dev *hdev) + if (err < 0) + return err; + +- /* HCI_PRIMARY covers both single-mode LE, BR/EDR and dual-mode +- * BR/EDR/LE type controllers. AMP controllers only need the +- * first two stages of init. +- */ +- if (hdev->dev_type != HCI_PRIMARY) +- return 0; +- + err = hci_init3_sync(hdev); + if (err < 0) + return err; +@@ -4890,12 +4812,8 @@ int hci_dev_open_sync(struct hci_dev *hdev) + * In case of user channel usage, it is not important + * if a public address or static random address is + * available. +- * +- * This check is only valid for BR/EDR controllers +- * since AMP controllers do not have an address. + */ + if (!hci_dev_test_flag(hdev, HCI_USER_CHANNEL) && +- hdev->dev_type == HCI_PRIMARY && + !bacmp(&hdev->bdaddr, BDADDR_ANY) && + !bacmp(&hdev->static_addr, BDADDR_ANY)) { + ret = -EADDRNOTAVAIL; +@@ -4930,8 +4848,7 @@ int hci_dev_open_sync(struct hci_dev *hdev) + !hci_dev_test_flag(hdev, HCI_CONFIG) && + !hci_dev_test_flag(hdev, HCI_UNCONFIGURED) && + !hci_dev_test_flag(hdev, HCI_USER_CHANNEL) && +- hci_dev_test_flag(hdev, HCI_MGMT) && +- hdev->dev_type == HCI_PRIMARY) { ++ hci_dev_test_flag(hdev, HCI_MGMT)) { + ret = hci_powered_update_sync(hdev); + mgmt_power_on(hdev, ret); + } +@@ -5077,8 +4994,7 @@ int hci_dev_close_sync(struct hci_dev *hdev) + + auto_off = hci_dev_test_and_clear_flag(hdev, HCI_AUTO_OFF); + +- if (!auto_off && hdev->dev_type == HCI_PRIMARY && +- !hci_dev_test_flag(hdev, HCI_USER_CHANNEL) && ++ if (!auto_off && !hci_dev_test_flag(hdev, HCI_USER_CHANNEL) && + hci_dev_test_flag(hdev, HCI_MGMT)) + __mgmt_power_off(hdev); + +@@ -5140,9 +5056,6 @@ int hci_dev_close_sync(struct hci_dev *hdev) + hdev->flags &= BIT(HCI_RAW); + hci_dev_clear_volatile_flags(hdev); + +- /* Controller radio is available but is currently powered down */ +- hdev->amp_status = AMP_STATUS_POWERED_DOWN; +- + memset(hdev->eir, 0, sizeof(hdev->eir)); + memset(hdev->dev_class, 0, sizeof(hdev->dev_class)); + bacpy(&hdev->random_addr, BDADDR_ANY); +@@ -5179,8 +5092,7 @@ static int hci_power_on_sync(struct hci_dev *hdev) + */ + if (hci_dev_test_flag(hdev, HCI_RFKILLED) || + hci_dev_test_flag(hdev, HCI_UNCONFIGURED) || +- (hdev->dev_type == HCI_PRIMARY && +- !bacmp(&hdev->bdaddr, BDADDR_ANY) && ++ (!bacmp(&hdev->bdaddr, BDADDR_ANY) && + !bacmp(&hdev->static_addr, BDADDR_ANY))) { + hci_dev_clear_flag(hdev, HCI_AUTO_OFF); + hci_dev_close_sync(hdev); +@@ -5283,26 +5195,21 @@ int hci_stop_discovery_sync(struct hci_dev *hdev) + return 0; + } + +-static int hci_disconnect_phy_link_sync(struct hci_dev *hdev, u16 handle, +- u8 reason) +-{ +- struct hci_cp_disconn_phy_link cp; +- +- memset(&cp, 0, sizeof(cp)); +- cp.phy_handle = HCI_PHY_HANDLE(handle); +- cp.reason = reason; +- +- return __hci_cmd_sync_status(hdev, HCI_OP_DISCONN_PHY_LINK, +- sizeof(cp), &cp, HCI_CMD_TIMEOUT); +-} +- + static int hci_disconnect_sync(struct hci_dev *hdev, struct hci_conn *conn, + u8 reason) + { + struct hci_cp_disconnect cp; + +- if (conn->type == AMP_LINK) +- return hci_disconnect_phy_link_sync(hdev, conn->handle, reason); ++ if (test_bit(HCI_CONN_BIG_CREATED, &conn->flags)) { ++ /* This is a BIS connection, hci_conn_del will ++ * do the necessary cleanup. ++ */ ++ hci_dev_lock(hdev); ++ hci_conn_failed(conn, reason); ++ hci_dev_unlock(hdev); ++ ++ return 0; ++ } + + memset(&cp, 0, sizeof(cp)); + cp.handle = cpu_to_le16(conn->handle); +@@ -5456,21 +5363,6 @@ int hci_abort_conn_sync(struct hci_dev *hdev, struct hci_conn *conn, u8 reason) + err = hci_reject_conn_sync(hdev, conn, reason); + break; + case BT_OPEN: +- hci_dev_lock(hdev); +- +- /* Cleanup bis or pa sync connections */ +- if (test_and_clear_bit(HCI_CONN_BIG_SYNC_FAILED, &conn->flags) || +- test_and_clear_bit(HCI_CONN_PA_SYNC_FAILED, &conn->flags)) { +- hci_conn_failed(conn, reason); +- } else if (test_bit(HCI_CONN_PA_SYNC, &conn->flags) || +- test_bit(HCI_CONN_BIG_SYNC, &conn->flags)) { +- conn->state = BT_CLOSED; +- hci_disconn_cfm(conn, reason); +- hci_conn_del(conn); +- } +- +- hci_dev_unlock(hdev); +- return 0; + case BT_BOUND: + break; + default: +diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c +index ab5d0204086fb..37210567fbfbe 100644 +--- a/net/bluetooth/l2cap_core.c ++++ b/net/bluetooth/l2cap_core.c +@@ -457,6 +457,9 @@ struct l2cap_chan *l2cap_chan_create(void) + /* Set default lock nesting level */ + atomic_set(&chan->nesting, L2CAP_NESTING_NORMAL); + ++ /* Available receive buffer space is initially unknown */ ++ chan->rx_avail = -1; ++ + write_lock(&chan_list_lock); + list_add(&chan->global_l, &chan_list); + write_unlock(&chan_list_lock); +@@ -538,6 +541,28 @@ void l2cap_chan_set_defaults(struct l2cap_chan *chan) + } + EXPORT_SYMBOL_GPL(l2cap_chan_set_defaults); + ++static __u16 l2cap_le_rx_credits(struct l2cap_chan *chan) ++{ ++ size_t sdu_len = chan->sdu ? chan->sdu->len : 0; ++ ++ if (chan->mps == 0) ++ return 0; ++ ++ /* If we don't know the available space in the receiver buffer, give ++ * enough credits for a full packet. ++ */ ++ if (chan->rx_avail == -1) ++ return (chan->imtu / chan->mps) + 1; ++ ++ /* If we know how much space is available in the receive buffer, give ++ * out as many credits as would fill the buffer. ++ */ ++ if (chan->rx_avail <= sdu_len) ++ return 0; ++ ++ return DIV_ROUND_UP(chan->rx_avail - sdu_len, chan->mps); ++} ++ + static void l2cap_le_flowctl_init(struct l2cap_chan *chan, u16 tx_credits) + { + chan->sdu = NULL; +@@ -546,8 +571,7 @@ static void l2cap_le_flowctl_init(struct l2cap_chan *chan, u16 tx_credits) + chan->tx_credits = tx_credits; + /* Derive MPS from connection MTU to stop HCI fragmentation */ + chan->mps = min_t(u16, chan->imtu, chan->conn->mtu - L2CAP_HDR_SIZE); +- /* Give enough credits for a full packet */ +- chan->rx_credits = (chan->imtu / chan->mps) + 1; ++ chan->rx_credits = l2cap_le_rx_credits(chan); + + skb_queue_head_init(&chan->tx_q); + } +@@ -559,7 +583,7 @@ static void l2cap_ecred_init(struct l2cap_chan *chan, u16 tx_credits) + /* L2CAP implementations shall support a minimum MPS of 64 octets */ + if (chan->mps < L2CAP_ECRED_MIN_MPS) { + chan->mps = L2CAP_ECRED_MIN_MPS; +- chan->rx_credits = (chan->imtu / chan->mps) + 1; ++ chan->rx_credits = l2cap_le_rx_credits(chan); + } + } + +@@ -3906,7 +3930,7 @@ static inline int l2cap_command_rej(struct l2cap_conn *conn, + } + + static void l2cap_connect(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, +- u8 *data, u8 rsp_code, u8 amp_id) ++ u8 *data, u8 rsp_code) + { + struct l2cap_conn_req *req = (struct l2cap_conn_req *) data; + struct l2cap_conn_rsp rsp; +@@ -3985,17 +4009,8 @@ static void l2cap_connect(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, + status = L2CAP_CS_AUTHOR_PEND; + chan->ops->defer(chan); + } else { +- /* Force pending result for AMP controllers. +- * The connection will succeed after the +- * physical link is up. +- */ +- if (amp_id == AMP_ID_BREDR) { +- l2cap_state_change(chan, BT_CONFIG); +- result = L2CAP_CR_SUCCESS; +- } else { +- l2cap_state_change(chan, BT_CONNECT2); +- result = L2CAP_CR_PEND; +- } ++ l2cap_state_change(chan, BT_CONNECT2); ++ result = L2CAP_CR_PEND; + status = L2CAP_CS_NO_INFO; + } + } else { +@@ -4060,7 +4075,7 @@ static int l2cap_connect_req(struct l2cap_conn *conn, + mgmt_device_connected(hdev, hcon, NULL, 0); + hci_dev_unlock(hdev); + +- l2cap_connect(conn, cmd, data, L2CAP_CONN_RSP, 0); ++ l2cap_connect(conn, cmd, data, L2CAP_CONN_RSP); + return 0; + } + +@@ -6513,9 +6528,7 @@ static void l2cap_chan_le_send_credits(struct l2cap_chan *chan) + { + struct l2cap_conn *conn = chan->conn; + struct l2cap_le_credits pkt; +- u16 return_credits; +- +- return_credits = (chan->imtu / chan->mps) + 1; ++ u16 return_credits = l2cap_le_rx_credits(chan); + + if (chan->rx_credits >= return_credits) + return; +@@ -6534,6 +6547,19 @@ static void l2cap_chan_le_send_credits(struct l2cap_chan *chan) + l2cap_send_cmd(conn, chan->ident, L2CAP_LE_CREDITS, sizeof(pkt), &pkt); + } + ++void l2cap_chan_rx_avail(struct l2cap_chan *chan, ssize_t rx_avail) ++{ ++ if (chan->rx_avail == rx_avail) ++ return; ++ ++ BT_DBG("chan %p has %zd bytes avail for rx", chan, rx_avail); ++ ++ chan->rx_avail = rx_avail; ++ ++ if (chan->state == BT_CONNECTED) ++ l2cap_chan_le_send_credits(chan); ++} ++ + static int l2cap_ecred_recv(struct l2cap_chan *chan, struct sk_buff *skb) + { + int err; +@@ -6543,6 +6569,12 @@ static int l2cap_ecred_recv(struct l2cap_chan *chan, struct sk_buff *skb) + /* Wait recv to confirm reception before updating the credits */ + err = chan->ops->recv(chan, skb); + ++ if (err < 0 && chan->rx_avail != -1) { ++ BT_ERR("Queueing received LE L2CAP data failed"); ++ l2cap_send_disconn_req(chan, ECONNRESET); ++ return err; ++ } ++ + /* Update credits whenever an SDU is received */ + l2cap_chan_le_send_credits(chan); + +@@ -6565,7 +6597,8 @@ static int l2cap_ecred_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb) + } + + chan->rx_credits--; +- BT_DBG("rx_credits %u -> %u", chan->rx_credits + 1, chan->rx_credits); ++ BT_DBG("chan %p: rx_credits %u -> %u", ++ chan, chan->rx_credits + 1, chan->rx_credits); + + /* Update if remote had run out of credits, this should only happens + * if the remote is not using the entire MPS. +@@ -7455,10 +7488,6 @@ void l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags) + struct l2cap_conn *conn = hcon->l2cap_data; + int len; + +- /* For AMP controller do not create l2cap conn */ +- if (!conn && hcon->hdev->dev_type != HCI_PRIMARY) +- goto drop; +- + if (!conn) + conn = l2cap_conn_add(hcon); + +diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c +index d647bd15d5009..97d0a0f5829a6 100644 +--- a/net/bluetooth/l2cap_sock.c ++++ b/net/bluetooth/l2cap_sock.c +@@ -1142,6 +1142,34 @@ static int l2cap_sock_sendmsg(struct socket *sock, struct msghdr *msg, + return err; + } + ++static void l2cap_publish_rx_avail(struct l2cap_chan *chan) ++{ ++ struct sock *sk = chan->data; ++ ssize_t avail = sk->sk_rcvbuf - atomic_read(&sk->sk_rmem_alloc); ++ int expected_skbs, skb_overhead; ++ ++ if (avail <= 0) { ++ l2cap_chan_rx_avail(chan, 0); ++ return; ++ } ++ ++ if (!chan->mps) { ++ l2cap_chan_rx_avail(chan, -1); ++ return; ++ } ++ ++ /* Correct available memory by estimated sk_buff overhead. ++ * This is significant due to small transfer sizes. However, accept ++ * at least one full packet if receive space is non-zero. ++ */ ++ expected_skbs = DIV_ROUND_UP(avail, chan->mps); ++ skb_overhead = expected_skbs * sizeof(struct sk_buff); ++ if (skb_overhead < avail) ++ l2cap_chan_rx_avail(chan, avail - skb_overhead); ++ else ++ l2cap_chan_rx_avail(chan, -1); ++} ++ + static int l2cap_sock_recvmsg(struct socket *sock, struct msghdr *msg, + size_t len, int flags) + { +@@ -1178,28 +1206,33 @@ static int l2cap_sock_recvmsg(struct socket *sock, struct msghdr *msg, + else + err = bt_sock_recvmsg(sock, msg, len, flags); + +- if (pi->chan->mode != L2CAP_MODE_ERTM) ++ if (pi->chan->mode != L2CAP_MODE_ERTM && ++ pi->chan->mode != L2CAP_MODE_LE_FLOWCTL && ++ pi->chan->mode != L2CAP_MODE_EXT_FLOWCTL) + return err; + +- /* Attempt to put pending rx data in the socket buffer */ +- + lock_sock(sk); + +- if (!test_bit(CONN_LOCAL_BUSY, &pi->chan->conn_state)) +- goto done; ++ l2cap_publish_rx_avail(pi->chan); + +- if (pi->rx_busy_skb) { +- if (!__sock_queue_rcv_skb(sk, pi->rx_busy_skb)) +- pi->rx_busy_skb = NULL; +- else ++ /* Attempt to put pending rx data in the socket buffer */ ++ while (!list_empty(&pi->rx_busy)) { ++ struct l2cap_rx_busy *rx_busy = ++ list_first_entry(&pi->rx_busy, ++ struct l2cap_rx_busy, ++ list); ++ if (__sock_queue_rcv_skb(sk, rx_busy->skb) < 0) + goto done; ++ list_del(&rx_busy->list); ++ kfree(rx_busy); + } + + /* Restore data flow when half of the receive buffer is + * available. This avoids resending large numbers of + * frames. + */ +- if (atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf >> 1) ++ if (test_bit(CONN_LOCAL_BUSY, &pi->chan->conn_state) && ++ atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf >> 1) + l2cap_chan_busy(pi->chan, 0); + + done: +@@ -1460,17 +1493,20 @@ static struct l2cap_chan *l2cap_sock_new_connection_cb(struct l2cap_chan *chan) + static int l2cap_sock_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb) + { + struct sock *sk = chan->data; ++ struct l2cap_pinfo *pi = l2cap_pi(sk); + int err; + + lock_sock(sk); + +- if (l2cap_pi(sk)->rx_busy_skb) { ++ if (chan->mode == L2CAP_MODE_ERTM && !list_empty(&pi->rx_busy)) { + err = -ENOMEM; + goto done; + } + + if (chan->mode != L2CAP_MODE_ERTM && +- chan->mode != L2CAP_MODE_STREAMING) { ++ chan->mode != L2CAP_MODE_STREAMING && ++ chan->mode != L2CAP_MODE_LE_FLOWCTL && ++ chan->mode != L2CAP_MODE_EXT_FLOWCTL) { + /* Even if no filter is attached, we could potentially + * get errors from security modules, etc. + */ +@@ -1481,7 +1517,9 @@ static int l2cap_sock_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb) + + err = __sock_queue_rcv_skb(sk, skb); + +- /* For ERTM, handle one skb that doesn't fit into the recv ++ l2cap_publish_rx_avail(chan); ++ ++ /* For ERTM and LE, handle a skb that doesn't fit into the recv + * buffer. This is important to do because the data frames + * have already been acked, so the skb cannot be discarded. + * +@@ -1490,8 +1528,18 @@ static int l2cap_sock_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb) + * acked and reassembled until there is buffer space + * available. + */ +- if (err < 0 && chan->mode == L2CAP_MODE_ERTM) { +- l2cap_pi(sk)->rx_busy_skb = skb; ++ if (err < 0 && ++ (chan->mode == L2CAP_MODE_ERTM || ++ chan->mode == L2CAP_MODE_LE_FLOWCTL || ++ chan->mode == L2CAP_MODE_EXT_FLOWCTL)) { ++ struct l2cap_rx_busy *rx_busy = ++ kmalloc(sizeof(*rx_busy), GFP_KERNEL); ++ if (!rx_busy) { ++ err = -ENOMEM; ++ goto done; ++ } ++ rx_busy->skb = skb; ++ list_add_tail(&rx_busy->list, &pi->rx_busy); + l2cap_chan_busy(chan, 1); + err = 0; + } +@@ -1717,6 +1765,8 @@ static const struct l2cap_ops l2cap_chan_ops = { + + static void l2cap_sock_destruct(struct sock *sk) + { ++ struct l2cap_rx_busy *rx_busy, *next; ++ + BT_DBG("sk %p", sk); + + if (l2cap_pi(sk)->chan) { +@@ -1724,9 +1774,10 @@ static void l2cap_sock_destruct(struct sock *sk) + l2cap_chan_put(l2cap_pi(sk)->chan); + } + +- if (l2cap_pi(sk)->rx_busy_skb) { +- kfree_skb(l2cap_pi(sk)->rx_busy_skb); +- l2cap_pi(sk)->rx_busy_skb = NULL; ++ list_for_each_entry_safe(rx_busy, next, &l2cap_pi(sk)->rx_busy, list) { ++ kfree_skb(rx_busy->skb); ++ list_del(&rx_busy->list); ++ kfree(rx_busy); + } + + skb_queue_purge(&sk->sk_receive_queue); +@@ -1810,6 +1861,8 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent) + + chan->data = sk; + chan->ops = &l2cap_chan_ops; ++ ++ l2cap_publish_rx_avail(chan); + } + + static struct proto l2cap_proto = { +@@ -1831,6 +1884,8 @@ static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, + sk->sk_destruct = l2cap_sock_destruct; + sk->sk_sndtimeo = L2CAP_CONN_TIMEOUT; + ++ INIT_LIST_HEAD(&l2cap_pi(sk)->rx_busy); ++ + chan = l2cap_chan_create(); + if (!chan) { + sk_free(sk); +diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c +index ac693e64f1f9f..0ca6593a029c0 100644 +--- a/net/bluetooth/mgmt.c ++++ b/net/bluetooth/mgmt.c +@@ -443,8 +443,7 @@ static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data, + + count = 0; + list_for_each_entry(d, &hci_dev_list, list) { +- if (d->dev_type == HCI_PRIMARY && +- !hci_dev_test_flag(d, HCI_UNCONFIGURED)) ++ if (!hci_dev_test_flag(d, HCI_UNCONFIGURED)) + count++; + } + +@@ -468,8 +467,7 @@ static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data, + if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks)) + continue; + +- if (d->dev_type == HCI_PRIMARY && +- !hci_dev_test_flag(d, HCI_UNCONFIGURED)) { ++ if (!hci_dev_test_flag(d, HCI_UNCONFIGURED)) { + rp->index[count++] = cpu_to_le16(d->id); + bt_dev_dbg(hdev, "Added hci%u", d->id); + } +@@ -503,8 +501,7 @@ static int read_unconf_index_list(struct sock *sk, struct hci_dev *hdev, + + count = 0; + list_for_each_entry(d, &hci_dev_list, list) { +- if (d->dev_type == HCI_PRIMARY && +- hci_dev_test_flag(d, HCI_UNCONFIGURED)) ++ if (hci_dev_test_flag(d, HCI_UNCONFIGURED)) + count++; + } + +@@ -528,8 +525,7 @@ static int read_unconf_index_list(struct sock *sk, struct hci_dev *hdev, + if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks)) + continue; + +- if (d->dev_type == HCI_PRIMARY && +- hci_dev_test_flag(d, HCI_UNCONFIGURED)) { ++ if (hci_dev_test_flag(d, HCI_UNCONFIGURED)) { + rp->index[count++] = cpu_to_le16(d->id); + bt_dev_dbg(hdev, "Added hci%u", d->id); + } +@@ -561,10 +557,8 @@ static int read_ext_index_list(struct sock *sk, struct hci_dev *hdev, + read_lock(&hci_dev_list_lock); + + count = 0; +- list_for_each_entry(d, &hci_dev_list, list) { +- if (d->dev_type == HCI_PRIMARY || d->dev_type == HCI_AMP) +- count++; +- } ++ list_for_each_entry(d, &hci_dev_list, list) ++ count++; + + rp = kmalloc(struct_size(rp, entry, count), GFP_ATOMIC); + if (!rp) { +@@ -585,16 +579,10 @@ static int read_ext_index_list(struct sock *sk, struct hci_dev *hdev, + if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks)) + continue; + +- if (d->dev_type == HCI_PRIMARY) { +- if (hci_dev_test_flag(d, HCI_UNCONFIGURED)) +- rp->entry[count].type = 0x01; +- else +- rp->entry[count].type = 0x00; +- } else if (d->dev_type == HCI_AMP) { +- rp->entry[count].type = 0x02; +- } else { +- continue; +- } ++ if (hci_dev_test_flag(d, HCI_UNCONFIGURED)) ++ rp->entry[count].type = 0x01; ++ else ++ rp->entry[count].type = 0x00; + + rp->entry[count].bus = d->bus; + rp->entry[count++].index = cpu_to_le16(d->id); +@@ -9324,23 +9312,14 @@ void mgmt_index_added(struct hci_dev *hdev) + if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks)) + return; + +- switch (hdev->dev_type) { +- case HCI_PRIMARY: +- if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) { +- mgmt_index_event(MGMT_EV_UNCONF_INDEX_ADDED, hdev, +- NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS); +- ev.type = 0x01; +- } else { +- mgmt_index_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, +- HCI_MGMT_INDEX_EVENTS); +- ev.type = 0x00; +- } +- break; +- case HCI_AMP: +- ev.type = 0x02; +- break; +- default: +- return; ++ if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) { ++ mgmt_index_event(MGMT_EV_UNCONF_INDEX_ADDED, hdev, NULL, 0, ++ HCI_MGMT_UNCONF_INDEX_EVENTS); ++ ev.type = 0x01; ++ } else { ++ mgmt_index_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, ++ HCI_MGMT_INDEX_EVENTS); ++ ev.type = 0x00; + } + + ev.bus = hdev->bus; +@@ -9357,25 +9336,16 @@ void mgmt_index_removed(struct hci_dev *hdev) + if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks)) + return; + +- switch (hdev->dev_type) { +- case HCI_PRIMARY: +- mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status); ++ mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status); + +- if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) { +- mgmt_index_event(MGMT_EV_UNCONF_INDEX_REMOVED, hdev, +- NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS); +- ev.type = 0x01; +- } else { +- mgmt_index_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, +- HCI_MGMT_INDEX_EVENTS); +- ev.type = 0x00; +- } +- break; +- case HCI_AMP: +- ev.type = 0x02; +- break; +- default: +- return; ++ if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) { ++ mgmt_index_event(MGMT_EV_UNCONF_INDEX_REMOVED, hdev, NULL, 0, ++ HCI_MGMT_UNCONF_INDEX_EVENTS); ++ ev.type = 0x01; ++ } else { ++ mgmt_index_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, ++ HCI_MGMT_INDEX_EVENTS); ++ ev.type = 0x00; + } + + ev.bus = hdev->bus; +diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c +index 9a5ea06236bd7..42d4c3727bf76 100644 +--- a/net/bridge/br_device.c ++++ b/net/bridge/br_device.c +@@ -27,6 +27,7 @@ EXPORT_SYMBOL_GPL(nf_br_ops); + /* net device transmit always called with BH disabled */ + netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev) + { ++ enum skb_drop_reason reason = pskb_may_pull_reason(skb, ETH_HLEN); + struct net_bridge_mcast_port *pmctx_null = NULL; + struct net_bridge *br = netdev_priv(dev); + struct net_bridge_mcast *brmctx = &br->multicast_ctx; +@@ -38,6 +39,11 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev) + const unsigned char *dest; + u16 vid = 0; + ++ if (unlikely(reason != SKB_NOT_DROPPED_YET)) { ++ kfree_skb_reason(skb, reason); ++ return NETDEV_TX_OK; ++ } ++ + memset(skb->cb, 0, sizeof(struct br_input_skb_cb)); + br_tc_skb_miss_set(skb, false); + +diff --git a/net/bridge/br_mst.c b/net/bridge/br_mst.c +index ee680adcee179..3c66141d34d62 100644 +--- a/net/bridge/br_mst.c ++++ b/net/bridge/br_mst.c +@@ -78,7 +78,7 @@ static void br_mst_vlan_set_state(struct net_bridge_port *p, struct net_bridge_v + { + struct net_bridge_vlan_group *vg = nbp_vlan_group(p); + +- if (v->state == state) ++ if (br_vlan_get_state(v) == state) + return; + + br_vlan_set_state(v, state); +@@ -100,11 +100,12 @@ int br_mst_set_state(struct net_bridge_port *p, u16 msti, u8 state, + }; + struct net_bridge_vlan_group *vg; + struct net_bridge_vlan *v; +- int err; ++ int err = 0; + ++ rcu_read_lock(); + vg = nbp_vlan_group(p); + if (!vg) +- return 0; ++ goto out; + + /* MSTI 0 (CST) state changes are notified via the regular + * SWITCHDEV_ATTR_ID_PORT_STP_STATE. +@@ -112,17 +113,20 @@ int br_mst_set_state(struct net_bridge_port *p, u16 msti, u8 state, + if (msti) { + err = switchdev_port_attr_set(p->dev, &attr, extack); + if (err && err != -EOPNOTSUPP) +- return err; ++ goto out; + } + +- list_for_each_entry(v, &vg->vlan_list, vlist) { ++ err = 0; ++ list_for_each_entry_rcu(v, &vg->vlan_list, vlist) { + if (v->brvlan->msti != msti) + continue; + + br_mst_vlan_set_state(p, v, state); + } + +- return 0; ++out: ++ rcu_read_unlock(); ++ return err; + } + + static void br_mst_vlan_sync_state(struct net_bridge_vlan *pv, u16 msti) +diff --git a/net/core/dev.c b/net/core/dev.c +index 1f6c8945f2eca..5a5bd339f11eb 100644 +--- a/net/core/dev.c ++++ b/net/core/dev.c +@@ -10430,8 +10430,9 @@ static struct net_device *netdev_wait_allrefs_any(struct list_head *list) + rebroadcast_time = jiffies; + } + ++ rcu_barrier(); ++ + if (!wait) { +- rcu_barrier(); + wait = WAIT_REFS_MIN_MSECS; + } else { + msleep(wait); +diff --git a/net/core/pktgen.c b/net/core/pktgen.c +index 4d1696677c48c..0e472f6fab853 100644 +--- a/net/core/pktgen.c ++++ b/net/core/pktgen.c +@@ -3982,8 +3982,7 @@ static void __net_exit pg_net_exit(struct net *net) + list_for_each_safe(q, n, &list) { + t = list_entry(q, struct pktgen_thread, th_list); + list_del(&t->th_list); +- kthread_stop(t->tsk); +- put_task_struct(t->tsk); ++ kthread_stop_put(t->tsk); + kfree(t); + } + +diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c +index b50308105551f..3feff7f738a48 100644 +--- a/net/ipv4/af_inet.c ++++ b/net/ipv4/af_inet.c +@@ -757,7 +757,9 @@ void __inet_accept(struct socket *sock, struct socket *newsock, struct sock *new + sock_rps_record_flow(newsk); + WARN_ON(!((1 << newsk->sk_state) & + (TCPF_ESTABLISHED | TCPF_SYN_RECV | +- TCPF_CLOSE_WAIT | TCPF_CLOSE))); ++ TCPF_FIN_WAIT1 | TCPF_FIN_WAIT2 | ++ TCPF_CLOSING | TCPF_CLOSE_WAIT | ++ TCPF_CLOSE))); + + if (test_bit(SOCK_SUPPORT_ZC, &sock->flags)) + set_bit(SOCK_SUPPORT_ZC, &newsock->flags); +diff --git a/net/ipv4/netfilter/nf_tproxy_ipv4.c b/net/ipv4/netfilter/nf_tproxy_ipv4.c +index 69e3317996043..73e66a088e25e 100644 +--- a/net/ipv4/netfilter/nf_tproxy_ipv4.c ++++ b/net/ipv4/netfilter/nf_tproxy_ipv4.c +@@ -58,6 +58,8 @@ __be32 nf_tproxy_laddr4(struct sk_buff *skb, __be32 user_laddr, __be32 daddr) + + laddr = 0; + indev = __in_dev_get_rcu(skb->dev); ++ if (!indev) ++ return daddr; + + in_dev_for_each_ifa_rcu(ifa, indev) { + if (ifa->ifa_flags & IFA_F_SECONDARY) +diff --git a/net/ipv4/tcp_dctcp.c b/net/ipv4/tcp_dctcp.c +index bb23bb5b387a0..8ad62713b0ba2 100644 +--- a/net/ipv4/tcp_dctcp.c ++++ b/net/ipv4/tcp_dctcp.c +@@ -58,7 +58,18 @@ struct dctcp { + }; + + static unsigned int dctcp_shift_g __read_mostly = 4; /* g = 1/2^4 */ +-module_param(dctcp_shift_g, uint, 0644); ++ ++static int dctcp_shift_g_set(const char *val, const struct kernel_param *kp) ++{ ++ return param_set_uint_minmax(val, kp, 0, 10); ++} ++ ++static const struct kernel_param_ops dctcp_shift_g_ops = { ++ .set = dctcp_shift_g_set, ++ .get = param_get_uint, ++}; ++ ++module_param_cb(dctcp_shift_g, &dctcp_shift_g_ops, &dctcp_shift_g, 0644); + MODULE_PARM_DESC(dctcp_shift_g, "parameter g for updating dctcp_alpha"); + + static unsigned int dctcp_alpha_on_init __read_mostly = DCTCP_MAX_ALPHA; +diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c +index c464ced7137ee..7c2ca4df0daa3 100644 +--- a/net/ipv4/tcp_ipv4.c ++++ b/net/ipv4/tcp_ipv4.c +@@ -1822,7 +1822,7 @@ int tcp_v4_early_demux(struct sk_buff *skb) + bool tcp_add_backlog(struct sock *sk, struct sk_buff *skb, + enum skb_drop_reason *reason) + { +- u32 limit, tail_gso_size, tail_gso_segs; ++ u32 tail_gso_size, tail_gso_segs; + struct skb_shared_info *shinfo; + const struct tcphdr *th; + struct tcphdr *thtail; +@@ -1831,6 +1831,7 @@ bool tcp_add_backlog(struct sock *sk, struct sk_buff *skb, + bool fragstolen; + u32 gso_segs; + u32 gso_size; ++ u64 limit; + int delta; + + /* In case all data was pulled from skb frags (in __pskb_pull_tail()), +@@ -1928,7 +1929,13 @@ bool tcp_add_backlog(struct sock *sk, struct sk_buff *skb, + __skb_push(skb, hdrlen); + + no_coalesce: +- limit = (u32)READ_ONCE(sk->sk_rcvbuf) + (u32)(READ_ONCE(sk->sk_sndbuf) >> 1); ++ /* sk->sk_backlog.len is reset only at the end of __release_sock(). ++ * Both sk->sk_backlog.len and sk->sk_rmem_alloc could reach ++ * sk_rcvbuf in normal conditions. ++ */ ++ limit = ((u64)READ_ONCE(sk->sk_rcvbuf)) << 1; ++ ++ limit += ((u32)READ_ONCE(sk->sk_sndbuf)) >> 1; + + /* Only socket owner can try to collapse/prune rx queues + * to reduce memory overhead, so add a little headroom here. +@@ -1936,6 +1943,8 @@ bool tcp_add_backlog(struct sock *sk, struct sk_buff *skb, + */ + limit += 64 * 1024; + ++ limit = min_t(u64, limit, UINT_MAX); ++ + if (unlikely(sk_add_backlog(sk, skb, limit))) { + bh_unlock_sock(sk); + *reason = SKB_DROP_REASON_SOCKET_BACKLOG; +diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c +index ca576587f6d21..16ca211c8619d 100644 +--- a/net/ipv4/udp.c ++++ b/net/ipv4/udp.c +@@ -429,15 +429,21 @@ static struct sock *udp4_lib_lookup2(struct net *net, + { + struct sock *sk, *result; + int score, badness; ++ bool need_rescore; + + result = NULL; + badness = 0; + udp_portaddr_for_each_entry_rcu(sk, &hslot2->head) { +- score = compute_score(sk, net, saddr, sport, +- daddr, hnum, dif, sdif); ++ need_rescore = false; ++rescore: ++ score = compute_score(need_rescore ? result : sk, net, saddr, ++ sport, daddr, hnum, dif, sdif); + if (score > badness) { + badness = score; + ++ if (need_rescore) ++ continue; ++ + if (sk->sk_state == TCP_ESTABLISHED) { + result = sk; + continue; +@@ -458,9 +464,14 @@ static struct sock *udp4_lib_lookup2(struct net *net, + if (IS_ERR(result)) + continue; + +- badness = compute_score(result, net, saddr, sport, +- daddr, hnum, dif, sdif); +- ++ /* compute_score is too long of a function to be ++ * inlined, and calling it again here yields ++ * measureable overhead for some ++ * workloads. Work around it by jumping ++ * backwards to rescore 'result'. ++ */ ++ need_rescore = true; ++ goto rescore; + } + } + return result; +diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c +index 5ebc47da1000c..2af98edef87ee 100644 +--- a/net/ipv6/reassembly.c ++++ b/net/ipv6/reassembly.c +@@ -369,7 +369,7 @@ static int ipv6_frag_rcv(struct sk_buff *skb) + * the source of the fragment, with the Pointer field set to zero. + */ + nexthdr = hdr->nexthdr; +- if (ipv6frag_thdr_truncated(skb, skb_transport_offset(skb), &nexthdr)) { ++ if (ipv6frag_thdr_truncated(skb, skb_network_offset(skb) + sizeof(struct ipv6hdr), &nexthdr)) { + __IP6_INC_STATS(net, __in6_dev_get_safely(skb->dev), + IPSTATS_MIB_INHDRERRORS); + icmpv6_param_prob(skb, ICMPV6_HDR_INCOMP, 0); +diff --git a/net/ipv6/seg6.c b/net/ipv6/seg6.c +index 35508abd76f43..a31521e270f78 100644 +--- a/net/ipv6/seg6.c ++++ b/net/ipv6/seg6.c +@@ -551,6 +551,8 @@ int __init seg6_init(void) + #endif + #ifdef CONFIG_IPV6_SEG6_LWTUNNEL + out_unregister_genl: ++#endif ++#if IS_ENABLED(CONFIG_IPV6_SEG6_LWTUNNEL) || IS_ENABLED(CONFIG_IPV6_SEG6_HMAC) + genl_unregister_family(&seg6_genl_family); + #endif + out_unregister_pernet: +@@ -564,8 +566,9 @@ void seg6_exit(void) + seg6_hmac_exit(); + #endif + #ifdef CONFIG_IPV6_SEG6_LWTUNNEL ++ seg6_local_exit(); + seg6_iptunnel_exit(); + #endif +- unregister_pernet_subsys(&ip6_segments_ops); + genl_unregister_family(&seg6_genl_family); ++ unregister_pernet_subsys(&ip6_segments_ops); + } +diff --git a/net/ipv6/seg6_hmac.c b/net/ipv6/seg6_hmac.c +index d43c50a7310d6..3c3800223e0e0 100644 +--- a/net/ipv6/seg6_hmac.c ++++ b/net/ipv6/seg6_hmac.c +@@ -354,6 +354,7 @@ static int seg6_hmac_init_algo(void) + struct crypto_shash *tfm; + struct shash_desc *shash; + int i, alg_count, cpu; ++ int ret = -ENOMEM; + + alg_count = ARRAY_SIZE(hmac_algos); + +@@ -364,12 +365,14 @@ static int seg6_hmac_init_algo(void) + algo = &hmac_algos[i]; + algo->tfms = alloc_percpu(struct crypto_shash *); + if (!algo->tfms) +- return -ENOMEM; ++ goto error_out; + + for_each_possible_cpu(cpu) { + tfm = crypto_alloc_shash(algo->name, 0, 0); +- if (IS_ERR(tfm)) +- return PTR_ERR(tfm); ++ if (IS_ERR(tfm)) { ++ ret = PTR_ERR(tfm); ++ goto error_out; ++ } + p_tfm = per_cpu_ptr(algo->tfms, cpu); + *p_tfm = tfm; + } +@@ -381,18 +384,22 @@ static int seg6_hmac_init_algo(void) + + algo->shashs = alloc_percpu(struct shash_desc *); + if (!algo->shashs) +- return -ENOMEM; ++ goto error_out; + + for_each_possible_cpu(cpu) { + shash = kzalloc_node(shsize, GFP_KERNEL, + cpu_to_node(cpu)); + if (!shash) +- return -ENOMEM; ++ goto error_out; + *per_cpu_ptr(algo->shashs, cpu) = shash; + } + } + + return 0; ++ ++error_out: ++ seg6_hmac_exit(); ++ return ret; + } + + int __init seg6_hmac_init(void) +@@ -410,22 +417,29 @@ int __net_init seg6_hmac_net_init(struct net *net) + void seg6_hmac_exit(void) + { + struct seg6_hmac_algo *algo = NULL; ++ struct crypto_shash *tfm; ++ struct shash_desc *shash; + int i, alg_count, cpu; + + alg_count = ARRAY_SIZE(hmac_algos); + for (i = 0; i < alg_count; i++) { + algo = &hmac_algos[i]; +- for_each_possible_cpu(cpu) { +- struct crypto_shash *tfm; +- struct shash_desc *shash; + +- shash = *per_cpu_ptr(algo->shashs, cpu); +- kfree(shash); +- tfm = *per_cpu_ptr(algo->tfms, cpu); +- crypto_free_shash(tfm); ++ if (algo->shashs) { ++ for_each_possible_cpu(cpu) { ++ shash = *per_cpu_ptr(algo->shashs, cpu); ++ kfree(shash); ++ } ++ free_percpu(algo->shashs); ++ } ++ ++ if (algo->tfms) { ++ for_each_possible_cpu(cpu) { ++ tfm = *per_cpu_ptr(algo->tfms, cpu); ++ crypto_free_shash(tfm); ++ } ++ free_percpu(algo->tfms); + } +- free_percpu(algo->tfms); +- free_percpu(algo->shashs); + } + } + EXPORT_SYMBOL(seg6_hmac_exit); +diff --git a/net/ipv6/seg6_iptunnel.c b/net/ipv6/seg6_iptunnel.c +index 03b877ff45588..a75df2ec8db0d 100644 +--- a/net/ipv6/seg6_iptunnel.c ++++ b/net/ipv6/seg6_iptunnel.c +@@ -459,10 +459,8 @@ static int seg6_input_core(struct net *net, struct sock *sk, + int err; + + err = seg6_do_srh(skb); +- if (unlikely(err)) { +- kfree_skb(skb); +- return err; +- } ++ if (unlikely(err)) ++ goto drop; + + slwt = seg6_lwt_lwtunnel(orig_dst->lwtstate); + +@@ -486,7 +484,7 @@ static int seg6_input_core(struct net *net, struct sock *sk, + + err = skb_cow_head(skb, LL_RESERVED_SPACE(dst->dev)); + if (unlikely(err)) +- return err; ++ goto drop; + + if (static_branch_unlikely(&nf_hooks_lwtunnel_enabled)) + return NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, +@@ -494,6 +492,9 @@ static int seg6_input_core(struct net *net, struct sock *sk, + skb_dst(skb)->dev, seg6_input_finish); + + return seg6_input_finish(dev_net(skb->dev), NULL, skb); ++drop: ++ kfree_skb(skb); ++ return err; + } + + static int seg6_input_nf(struct sk_buff *skb) +diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c +index 124cf2bb2a6d7..c77ee9a3cde24 100644 +--- a/net/ipv6/udp.c ++++ b/net/ipv6/udp.c +@@ -171,15 +171,21 @@ static struct sock *udp6_lib_lookup2(struct net *net, + { + struct sock *sk, *result; + int score, badness; ++ bool need_rescore; + + result = NULL; + badness = -1; + udp_portaddr_for_each_entry_rcu(sk, &hslot2->head) { +- score = compute_score(sk, net, saddr, sport, +- daddr, hnum, dif, sdif); ++ need_rescore = false; ++rescore: ++ score = compute_score(need_rescore ? result : sk, net, saddr, ++ sport, daddr, hnum, dif, sdif); + if (score > badness) { + badness = score; + ++ if (need_rescore) ++ continue; ++ + if (sk->sk_state == TCP_ESTABLISHED) { + result = sk; + continue; +@@ -200,8 +206,14 @@ static struct sock *udp6_lib_lookup2(struct net *net, + if (IS_ERR(result)) + continue; + +- badness = compute_score(sk, net, saddr, sport, +- daddr, hnum, dif, sdif); ++ /* compute_score is too long of a function to be ++ * inlined, and calling it again here yields ++ * measureable overhead for some ++ * workloads. Work around it by jumping ++ * backwards to rescore 'result'. ++ */ ++ need_rescore = true; ++ goto rescore; + } + } + return result; +diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c +index cf01f1f298a3b..42e2c84ed2484 100644 +--- a/net/mac80211/mlme.c ++++ b/net/mac80211/mlme.c +@@ -5979,7 +5979,8 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_link_data *link, + link->u.mgd.dtim_period = elems->dtim_period; + link->u.mgd.have_beacon = true; + ifmgd->assoc_data->need_beacon = false; +- if (ieee80211_hw_check(&local->hw, TIMING_BEACON_ONLY)) { ++ if (ieee80211_hw_check(&local->hw, TIMING_BEACON_ONLY) && ++ !ieee80211_is_s1g_beacon(hdr->frame_control)) { + link->conf->sync_tsf = + le64_to_cpu(mgmt->u.beacon.timestamp); + link->conf->sync_device_ts = +diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c +index 9d33fd2377c88..a2bc9c5d92b8b 100644 +--- a/net/mac80211/rate.c ++++ b/net/mac80211/rate.c +@@ -877,6 +877,7 @@ void ieee80211_get_tx_rates(struct ieee80211_vif *vif, + struct ieee80211_sub_if_data *sdata; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_supported_band *sband; ++ u32 mask = ~0; + + rate_control_fill_sta_table(sta, info, dest, max_rates); + +@@ -889,9 +890,12 @@ void ieee80211_get_tx_rates(struct ieee80211_vif *vif, + if (ieee80211_is_tx_data(skb)) + rate_control_apply_mask(sdata, sta, sband, dest, max_rates); + ++ if (!(info->control.flags & IEEE80211_TX_CTRL_SCAN_TX)) ++ mask = sdata->rc_rateidx_mask[info->band]; ++ + if (dest[0].idx < 0) + __rate_control_send_low(&sdata->local->hw, sband, sta, info, +- sdata->rc_rateidx_mask[info->band]); ++ mask); + + if (sta) + rate_fixup_ratelist(vif, sband, info, dest, max_rates); +diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c +index a52813f2b08cb..b68214f159838 100644 +--- a/net/mac80211/scan.c ++++ b/net/mac80211/scan.c +@@ -636,6 +636,7 @@ static void ieee80211_send_scan_probe_req(struct ieee80211_sub_if_data *sdata, + cpu_to_le16(IEEE80211_SN_TO_SEQ(sn)); + } + IEEE80211_SKB_CB(skb)->flags |= tx_flags; ++ IEEE80211_SKB_CB(skb)->control.flags |= IEEE80211_TX_CTRL_SCAN_TX; + ieee80211_tx_skb_tid_band(sdata, skb, 7, channel->band); + } + } +diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c +index 5c6c5254d987f..46b02a6ae0a36 100644 +--- a/net/mac80211/tx.c ++++ b/net/mac80211/tx.c +@@ -705,11 +705,16 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx) + txrc.bss_conf = &tx->sdata->vif.bss_conf; + txrc.skb = tx->skb; + txrc.reported_rate.idx = -1; +- txrc.rate_idx_mask = tx->sdata->rc_rateidx_mask[info->band]; + +- if (tx->sdata->rc_has_mcs_mask[info->band]) +- txrc.rate_idx_mcs_mask = +- tx->sdata->rc_rateidx_mcs_mask[info->band]; ++ if (unlikely(info->control.flags & IEEE80211_TX_CTRL_SCAN_TX)) { ++ txrc.rate_idx_mask = ~0; ++ } else { ++ txrc.rate_idx_mask = tx->sdata->rc_rateidx_mask[info->band]; ++ ++ if (tx->sdata->rc_has_mcs_mask[info->band]) ++ txrc.rate_idx_mcs_mask = ++ tx->sdata->rc_rateidx_mcs_mask[info->band]; ++ } + + txrc.bss = (tx->sdata->vif.type == NL80211_IFTYPE_AP || + tx->sdata->vif.type == NL80211_IFTYPE_MESH_POINT || +diff --git a/net/mptcp/sockopt.c b/net/mptcp/sockopt.c +index 116e3008231bd..1afa8245f27c0 100644 +--- a/net/mptcp/sockopt.c ++++ b/net/mptcp/sockopt.c +@@ -181,8 +181,6 @@ static int mptcp_setsockopt_sol_socket_int(struct mptcp_sock *msk, int optname, + + switch (optname) { + case SO_KEEPALIVE: +- mptcp_sol_socket_sync_intval(msk, optname, val); +- return 0; + case SO_DEBUG: + case SO_MARK: + case SO_PRIORITY: +diff --git a/net/netfilter/ipset/ip_set_list_set.c b/net/netfilter/ipset/ip_set_list_set.c +index 6c3f28bc59b32..54e2a1dd7f5f5 100644 +--- a/net/netfilter/ipset/ip_set_list_set.c ++++ b/net/netfilter/ipset/ip_set_list_set.c +@@ -549,6 +549,9 @@ list_set_cancel_gc(struct ip_set *set) + + if (SET_WITH_TIMEOUT(set)) + timer_shutdown_sync(&map->gc); ++ ++ /* Flush list to drop references to other ipsets */ ++ list_set_flush(set); + } + + static const struct ip_set_type_variant set_variant = { +diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c +index 556bc902af00f..dfc856b3e1fa4 100644 +--- a/net/netfilter/nfnetlink_queue.c ++++ b/net/netfilter/nfnetlink_queue.c +@@ -169,7 +169,9 @@ instance_destroy_rcu(struct rcu_head *head) + struct nfqnl_instance *inst = container_of(head, struct nfqnl_instance, + rcu); + ++ rcu_read_lock(); + nfqnl_flush(inst, NULL, 0); ++ rcu_read_unlock(); + kfree(inst); + module_put(THIS_MODULE); + } +diff --git a/net/netfilter/nft_fib.c b/net/netfilter/nft_fib.c +index ca905aa8227e5..bf825f6cb974e 100644 +--- a/net/netfilter/nft_fib.c ++++ b/net/netfilter/nft_fib.c +@@ -35,11 +35,9 @@ int nft_fib_validate(const struct nft_ctx *ctx, const struct nft_expr *expr, + switch (priv->result) { + case NFT_FIB_RESULT_OIF: + case NFT_FIB_RESULT_OIFNAME: +- hooks = (1 << NF_INET_PRE_ROUTING); +- if (priv->flags & NFTA_FIB_F_IIF) { +- hooks |= (1 << NF_INET_LOCAL_IN) | +- (1 << NF_INET_FORWARD); +- } ++ hooks = (1 << NF_INET_PRE_ROUTING) | ++ (1 << NF_INET_LOCAL_IN) | ++ (1 << NF_INET_FORWARD); + break; + case NFT_FIB_RESULT_ADDRTYPE: + if (priv->flags & NFTA_FIB_F_IIF) +diff --git a/net/netfilter/nft_payload.c b/net/netfilter/nft_payload.c +index 0a689c8e0295d..0c43d748e23ae 100644 +--- a/net/netfilter/nft_payload.c ++++ b/net/netfilter/nft_payload.c +@@ -45,36 +45,27 @@ nft_payload_copy_vlan(u32 *d, const struct sk_buff *skb, u8 offset, u8 len) + int mac_off = skb_mac_header(skb) - skb->data; + u8 *vlanh, *dst_u8 = (u8 *) d; + struct vlan_ethhdr veth; +- u8 vlan_hlen = 0; +- +- if ((skb->protocol == htons(ETH_P_8021AD) || +- skb->protocol == htons(ETH_P_8021Q)) && +- offset >= VLAN_ETH_HLEN && offset < VLAN_ETH_HLEN + VLAN_HLEN) +- vlan_hlen += VLAN_HLEN; + + vlanh = (u8 *) &veth; +- if (offset < VLAN_ETH_HLEN + vlan_hlen) { ++ if (offset < VLAN_ETH_HLEN) { + u8 ethlen = len; + +- if (vlan_hlen && +- skb_copy_bits(skb, mac_off, &veth, VLAN_ETH_HLEN) < 0) +- return false; +- else if (!nft_payload_rebuild_vlan_hdr(skb, mac_off, &veth)) ++ if (!nft_payload_rebuild_vlan_hdr(skb, mac_off, &veth)) + return false; + +- if (offset + len > VLAN_ETH_HLEN + vlan_hlen) +- ethlen -= offset + len - VLAN_ETH_HLEN - vlan_hlen; ++ if (offset + len > VLAN_ETH_HLEN) ++ ethlen -= offset + len - VLAN_ETH_HLEN; + +- memcpy(dst_u8, vlanh + offset - vlan_hlen, ethlen); ++ memcpy(dst_u8, vlanh + offset, ethlen); + + len -= ethlen; + if (len == 0) + return true; + + dst_u8 += ethlen; +- offset = ETH_HLEN + vlan_hlen; ++ offset = ETH_HLEN; + } else { +- offset -= VLAN_HLEN + vlan_hlen; ++ offset -= VLAN_HLEN; + } + + return skb_copy_bits(skb, offset + mac_off, dst_u8, len) == 0; +@@ -154,12 +145,12 @@ int nft_payload_inner_offset(const struct nft_pktinfo *pkt) + return pkt->inneroff; + } + +-static bool nft_payload_need_vlan_copy(const struct nft_payload *priv) ++static bool nft_payload_need_vlan_adjust(u32 offset, u32 len) + { +- unsigned int len = priv->offset + priv->len; ++ unsigned int boundary = offset + len; + + /* data past ether src/dst requested, copy needed */ +- if (len > offsetof(struct ethhdr, h_proto)) ++ if (boundary > offsetof(struct ethhdr, h_proto)) + return true; + + return false; +@@ -183,7 +174,7 @@ void nft_payload_eval(const struct nft_expr *expr, + goto err; + + if (skb_vlan_tag_present(skb) && +- nft_payload_need_vlan_copy(priv)) { ++ nft_payload_need_vlan_adjust(priv->offset, priv->len)) { + if (!nft_payload_copy_vlan(dest, skb, + priv->offset, priv->len)) + goto err; +@@ -810,21 +801,79 @@ struct nft_payload_set { + u8 csum_flags; + }; + ++/* This is not struct vlan_hdr. */ ++struct nft_payload_vlan_hdr { ++ __be16 h_vlan_proto; ++ __be16 h_vlan_TCI; ++}; ++ ++static bool ++nft_payload_set_vlan(const u32 *src, struct sk_buff *skb, u8 offset, u8 len, ++ int *vlan_hlen) ++{ ++ struct nft_payload_vlan_hdr *vlanh; ++ __be16 vlan_proto; ++ u16 vlan_tci; ++ ++ if (offset >= offsetof(struct vlan_ethhdr, h_vlan_encapsulated_proto)) { ++ *vlan_hlen = VLAN_HLEN; ++ return true; ++ } ++ ++ switch (offset) { ++ case offsetof(struct vlan_ethhdr, h_vlan_proto): ++ if (len == 2) { ++ vlan_proto = nft_reg_load_be16(src); ++ skb->vlan_proto = vlan_proto; ++ } else if (len == 4) { ++ vlanh = (struct nft_payload_vlan_hdr *)src; ++ __vlan_hwaccel_put_tag(skb, vlanh->h_vlan_proto, ++ ntohs(vlanh->h_vlan_TCI)); ++ } else { ++ return false; ++ } ++ break; ++ case offsetof(struct vlan_ethhdr, h_vlan_TCI): ++ if (len != 2) ++ return false; ++ ++ vlan_tci = ntohs(nft_reg_load_be16(src)); ++ skb->vlan_tci = vlan_tci; ++ break; ++ default: ++ return false; ++ } ++ ++ return true; ++} ++ + static void nft_payload_set_eval(const struct nft_expr *expr, + struct nft_regs *regs, + const struct nft_pktinfo *pkt) + { + const struct nft_payload_set *priv = nft_expr_priv(expr); +- struct sk_buff *skb = pkt->skb; + const u32 *src = ®s->data[priv->sreg]; +- int offset, csum_offset; ++ int offset, csum_offset, vlan_hlen = 0; ++ struct sk_buff *skb = pkt->skb; + __wsum fsum, tsum; + + switch (priv->base) { + case NFT_PAYLOAD_LL_HEADER: + if (!skb_mac_header_was_set(skb)) + goto err; +- offset = skb_mac_header(skb) - skb->data; ++ ++ if (skb_vlan_tag_present(skb) && ++ nft_payload_need_vlan_adjust(priv->offset, priv->len)) { ++ if (!nft_payload_set_vlan(src, skb, ++ priv->offset, priv->len, ++ &vlan_hlen)) ++ goto err; ++ ++ if (!vlan_hlen) ++ return; ++ } ++ ++ offset = skb_mac_header(skb) - skb->data - vlan_hlen; + break; + case NFT_PAYLOAD_NETWORK_HEADER: + offset = skb_network_offset(skb); +diff --git a/net/netrom/nr_route.c b/net/netrom/nr_route.c +index 70480869ad1c5..bd2b17b219ae9 100644 +--- a/net/netrom/nr_route.c ++++ b/net/netrom/nr_route.c +@@ -285,22 +285,14 @@ static int __must_check nr_add_node(ax25_address *nr, const char *mnemonic, + return 0; + } + +-static inline void __nr_remove_node(struct nr_node *nr_node) ++static void nr_remove_node_locked(struct nr_node *nr_node) + { ++ lockdep_assert_held(&nr_node_list_lock); ++ + hlist_del_init(&nr_node->node_node); + nr_node_put(nr_node); + } + +-#define nr_remove_node_locked(__node) \ +- __nr_remove_node(__node) +- +-static void nr_remove_node(struct nr_node *nr_node) +-{ +- spin_lock_bh(&nr_node_list_lock); +- __nr_remove_node(nr_node); +- spin_unlock_bh(&nr_node_list_lock); +-} +- + static inline void __nr_remove_neigh(struct nr_neigh *nr_neigh) + { + hlist_del_init(&nr_neigh->neigh_node); +@@ -339,6 +331,7 @@ static int nr_del_node(ax25_address *callsign, ax25_address *neighbour, struct n + return -EINVAL; + } + ++ spin_lock_bh(&nr_node_list_lock); + nr_node_lock(nr_node); + for (i = 0; i < nr_node->count; i++) { + if (nr_node->routes[i].neighbour == nr_neigh) { +@@ -352,7 +345,7 @@ static int nr_del_node(ax25_address *callsign, ax25_address *neighbour, struct n + nr_node->count--; + + if (nr_node->count == 0) { +- nr_remove_node(nr_node); ++ nr_remove_node_locked(nr_node); + } else { + switch (i) { + case 0: +@@ -367,12 +360,14 @@ static int nr_del_node(ax25_address *callsign, ax25_address *neighbour, struct n + nr_node_put(nr_node); + } + nr_node_unlock(nr_node); ++ spin_unlock_bh(&nr_node_list_lock); + + return 0; + } + } + nr_neigh_put(nr_neigh); + nr_node_unlock(nr_node); ++ spin_unlock_bh(&nr_node_list_lock); + nr_node_put(nr_node); + + return -EINVAL; +diff --git a/net/nfc/nci/core.c b/net/nfc/nci/core.c +index 5d708af0fcfd3..c4d2932c59032 100644 +--- a/net/nfc/nci/core.c ++++ b/net/nfc/nci/core.c +@@ -1463,6 +1463,19 @@ int nci_core_ntf_packet(struct nci_dev *ndev, __u16 opcode, + ndev->ops->n_core_ops); + } + ++static bool nci_valid_size(struct sk_buff *skb) ++{ ++ BUILD_BUG_ON(NCI_CTRL_HDR_SIZE != NCI_DATA_HDR_SIZE); ++ unsigned int hdr_size = NCI_CTRL_HDR_SIZE; ++ ++ if (skb->len < hdr_size || ++ !nci_plen(skb->data) || ++ skb->len < hdr_size + nci_plen(skb->data)) { ++ return false; ++ } ++ return true; ++} ++ + /* ---- NCI TX Data worker thread ---- */ + + static void nci_tx_work(struct work_struct *work) +@@ -1516,10 +1529,9 @@ static void nci_rx_work(struct work_struct *work) + nfc_send_to_raw_sock(ndev->nfc_dev, skb, + RAW_PAYLOAD_NCI, NFC_DIRECTION_RX); + +- if (!nci_plen(skb->data)) { ++ if (!nci_valid_size(skb)) { + kfree_skb(skb); +- kcov_remote_stop(); +- break; ++ continue; + } + + /* Process frame */ +diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c +index fd66014d8a76a..4f5cbcaa38386 100644 +--- a/net/openvswitch/actions.c ++++ b/net/openvswitch/actions.c +@@ -929,6 +929,12 @@ static void do_output(struct datapath *dp, struct sk_buff *skb, int out_port, + pskb_trim(skb, ovs_mac_header_len(key)); + } + ++ /* Need to set the pkt_type to involve the routing layer. The ++ * packet movement through the OVS datapath doesn't generally ++ * use routing, but this is needed for tunnel cases. ++ */ ++ skb->pkt_type = PACKET_OUTGOING; ++ + if (likely(!mru || + (skb->len <= mru + vport->dev->hard_header_len))) { + ovs_vport_send(vport, skb, ovs_key_mac_proto(key)); +diff --git a/net/openvswitch/flow.c b/net/openvswitch/flow.c +index 33b21a0c05481..8a848ce72e291 100644 +--- a/net/openvswitch/flow.c ++++ b/net/openvswitch/flow.c +@@ -561,7 +561,6 @@ static int parse_icmpv6(struct sk_buff *skb, struct sw_flow_key *key, + */ + key->tp.src = htons(icmp->icmp6_type); + key->tp.dst = htons(icmp->icmp6_code); +- memset(&key->ipv6.nd, 0, sizeof(key->ipv6.nd)); + + if (icmp->icmp6_code == 0 && + (icmp->icmp6_type == NDISC_NEIGHBOUR_SOLICITATION || +@@ -570,6 +569,8 @@ static int parse_icmpv6(struct sk_buff *skb, struct sw_flow_key *key, + struct nd_msg *nd; + int offset; + ++ memset(&key->ipv6.nd, 0, sizeof(key->ipv6.nd)); ++ + /* In order to process neighbor discovery options, we need the + * entire packet. + */ +diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c +index f017d7d33da39..ff1ddf544e179 100644 +--- a/net/packet/af_packet.c ++++ b/net/packet/af_packet.c +@@ -2528,8 +2528,7 @@ static void tpacket_destruct_skb(struct sk_buff *skb) + ts = __packet_set_timestamp(po, ph, skb); + __packet_set_status(po, ph, TP_STATUS_AVAILABLE | ts); + +- if (!packet_read_pending(&po->tx_ring)) +- complete(&po->skb_completion); ++ complete(&po->skb_completion); + } + + sock_wfree(skb); +diff --git a/net/qrtr/ns.c b/net/qrtr/ns.c +index abb0c70ffc8b0..654a3cc0d3479 100644 +--- a/net/qrtr/ns.c ++++ b/net/qrtr/ns.c +@@ -725,6 +725,24 @@ int qrtr_ns_init(void) + if (ret < 0) + goto err_wq; + ++ /* As the qrtr ns socket owner and creator is the same module, we have ++ * to decrease the qrtr module reference count to guarantee that it ++ * remains zero after the ns socket is created, otherwise, executing ++ * "rmmod" command is unable to make the qrtr module deleted after the ++ * qrtr module is inserted successfully. ++ * ++ * However, the reference count is increased twice in ++ * sock_create_kern(): one is to increase the reference count of owner ++ * of qrtr socket's proto_ops struct; another is to increment the ++ * reference count of owner of qrtr proto struct. Therefore, we must ++ * decrement the module reference count twice to ensure that it keeps ++ * zero after server's listening socket is created. Of course, we ++ * must bump the module reference count twice as well before the socket ++ * is closed. ++ */ ++ module_put(qrtr_ns.sock->ops->owner); ++ module_put(qrtr_ns.sock->sk->sk_prot_creator->owner); ++ + return 0; + + err_wq: +@@ -739,6 +757,15 @@ void qrtr_ns_remove(void) + { + cancel_work_sync(&qrtr_ns.work); + destroy_workqueue(qrtr_ns.workqueue); ++ ++ /* sock_release() expects the two references that were put during ++ * qrtr_ns_init(). This function is only called during module remove, ++ * so try_stop_module() has already set the refcnt to 0. Use ++ * __module_get() instead of try_module_get() to successfully take two ++ * references. ++ */ ++ __module_get(qrtr_ns.sock->ops->owner); ++ __module_get(qrtr_ns.sock->sk->sk_prot_creator->owner); + sock_release(qrtr_ns.sock); + } + EXPORT_SYMBOL_GPL(qrtr_ns_remove); +diff --git a/net/sched/sch_taprio.c b/net/sched/sch_taprio.c +index 87d8070fffbe7..a315748a5e531 100644 +--- a/net/sched/sch_taprio.c ++++ b/net/sched/sch_taprio.c +@@ -1161,11 +1161,6 @@ static int parse_taprio_schedule(struct taprio_sched *q, struct nlattr **tb, + list_for_each_entry(entry, &new->entries, list) + cycle = ktime_add_ns(cycle, entry->interval); + +- if (!cycle) { +- NL_SET_ERR_MSG(extack, "'cycle_time' can never be 0"); +- return -EINVAL; +- } +- + if (cycle < 0 || cycle > INT_MAX) { + NL_SET_ERR_MSG(extack, "'cycle_time' is too big"); + return -EINVAL; +@@ -1174,6 +1169,11 @@ static int parse_taprio_schedule(struct taprio_sched *q, struct nlattr **tb, + new->cycle_time = cycle; + } + ++ if (new->cycle_time < new->num_entries * length_to_duration(q, ETH_ZLEN)) { ++ NL_SET_ERR_MSG(extack, "'cycle_time' is too small"); ++ return -EINVAL; ++ } ++ + taprio_calculate_gate_durations(q, new); + + return 0; +@@ -1871,6 +1871,9 @@ static int taprio_change(struct Qdisc *sch, struct nlattr *opt, + + q->flags = err; + ++ /* Needed for length_to_duration() during netlink attribute parsing */ ++ taprio_set_picos_per_byte(dev, q); ++ + err = taprio_parse_mqprio_opt(dev, mqprio, extack, q->flags); + if (err < 0) + return err; +@@ -1930,7 +1933,6 @@ static int taprio_change(struct Qdisc *sch, struct nlattr *opt, + if (err < 0) + goto free_sched; + +- taprio_set_picos_per_byte(dev, q); + taprio_update_queue_max_sdu(q, new_admin, stab); + + if (FULL_OFFLOAD_IS_ENABLED(q->flags)) +diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c +index 18734e70c5ddb..cf30bd649e270 100644 +--- a/net/sunrpc/auth_gss/svcauth_gss.c ++++ b/net/sunrpc/auth_gss/svcauth_gss.c +@@ -1043,17 +1043,11 @@ svcauth_gss_proc_init_verf(struct cache_detail *cd, struct svc_rqst *rqstp, + + static void gss_free_in_token_pages(struct gssp_in_token *in_token) + { +- u32 inlen; + int i; + + i = 0; +- inlen = in_token->page_len; +- while (inlen) { +- if (in_token->pages[i]) +- put_page(in_token->pages[i]); +- inlen -= inlen > PAGE_SIZE ? PAGE_SIZE : inlen; +- } +- ++ while (in_token->pages[i]) ++ put_page(in_token->pages[i++]); + kfree(in_token->pages); + in_token->pages = NULL; + } +@@ -1085,7 +1079,7 @@ static int gss_read_proxy_verf(struct svc_rqst *rqstp, + goto out_denied_free; + + pages = DIV_ROUND_UP(inlen, PAGE_SIZE); +- in_token->pages = kcalloc(pages, sizeof(struct page *), GFP_KERNEL); ++ in_token->pages = kcalloc(pages + 1, sizeof(struct page *), GFP_KERNEL); + if (!in_token->pages) + goto out_denied_free; + in_token->page_base = 0; +diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c +index f4d32cf2cd16a..d3c917c0c8d59 100644 +--- a/net/sunrpc/clnt.c ++++ b/net/sunrpc/clnt.c +@@ -1056,6 +1056,7 @@ struct rpc_clnt *rpc_bind_new_program(struct rpc_clnt *old, + .authflavor = old->cl_auth->au_flavor, + .cred = old->cl_cred, + .stats = old->cl_stats, ++ .timeout = old->cl_timeout, + }; + struct rpc_clnt *clnt; + int err; +diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c +index 812fda9d45dd6..691499d1d2315 100644 +--- a/net/sunrpc/svc.c ++++ b/net/sunrpc/svc.c +@@ -1265,8 +1265,6 @@ svc_generic_init_request(struct svc_rqst *rqstp, + if (rqstp->rq_proc >= versp->vs_nproc) + goto err_bad_proc; + rqstp->rq_procinfo = procp = &versp->vs_proc[rqstp->rq_proc]; +- if (!procp) +- goto err_bad_proc; + + /* Initialize storage for argp and resp */ + memset(rqstp->rq_argp, 0, procp->pc_argzero); +diff --git a/net/sunrpc/xprtrdma/verbs.c b/net/sunrpc/xprtrdma/verbs.c +index 28c0771c4e8c3..4f71627ba39ce 100644 +--- a/net/sunrpc/xprtrdma/verbs.c ++++ b/net/sunrpc/xprtrdma/verbs.c +@@ -244,7 +244,11 @@ rpcrdma_cm_event_handler(struct rdma_cm_id *id, struct rdma_cm_event *event) + case RDMA_CM_EVENT_DEVICE_REMOVAL: + pr_info("rpcrdma: removing device %s for %pISpc\n", + ep->re_id->device->name, sap); +- fallthrough; ++ switch (xchg(&ep->re_connect_status, -ENODEV)) { ++ case 0: goto wake_connect_worker; ++ case 1: goto disconnected; ++ } ++ return 0; + case RDMA_CM_EVENT_ADDR_CHANGE: + ep->re_connect_status = -ENODEV; + goto disconnected; +diff --git a/net/tls/tls_main.c b/net/tls/tls_main.c +index e97fcb502115e..0a67b93a52ec2 100644 +--- a/net/tls/tls_main.c ++++ b/net/tls/tls_main.c +@@ -814,9 +814,17 @@ struct tls_context *tls_ctx_create(struct sock *sk) + return NULL; + + mutex_init(&ctx->tx_lock); +- rcu_assign_pointer(icsk->icsk_ulp_data, ctx); + ctx->sk_proto = READ_ONCE(sk->sk_prot); + ctx->sk = sk; ++ /* Release semantic of rcu_assign_pointer() ensures that ++ * ctx->sk_proto is visible before changing sk->sk_prot in ++ * update_sk_prot(), and prevents reading uninitialized value in ++ * tls_{getsockopt, setsockopt}. Note that we do not need a ++ * read barrier in tls_{getsockopt,setsockopt} as there is an ++ * address dependency between sk->sk_proto->{getsockopt,setsockopt} ++ * and ctx->sk_proto. ++ */ ++ rcu_assign_pointer(icsk->icsk_ulp_data, ctx); + return ctx; + } + +diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c +index 6eab35a5e2f3b..d01314dc86ecb 100644 +--- a/net/unix/af_unix.c ++++ b/net/unix/af_unix.c +@@ -732,7 +732,7 @@ static int unix_listen(struct socket *sock, int backlog) + if (sock->type != SOCK_STREAM && sock->type != SOCK_SEQPACKET) + goto out; /* Only stream/seqpacket sockets accept */ + err = -EINVAL; +- if (!u->addr) ++ if (!READ_ONCE(u->addr)) + goto out; /* No listens on an unbound socket */ + unix_state_lock(sk); + if (sk->sk_state != TCP_CLOSE && sk->sk_state != TCP_LISTEN) +@@ -1145,8 +1145,8 @@ static struct sock *unix_find_other(struct net *net, + + static int unix_autobind(struct sock *sk) + { +- unsigned int new_hash, old_hash = sk->sk_hash; + struct unix_sock *u = unix_sk(sk); ++ unsigned int new_hash, old_hash; + struct net *net = sock_net(sk); + struct unix_address *addr; + u32 lastnum, ordernum; +@@ -1169,6 +1169,7 @@ static int unix_autobind(struct sock *sk) + addr->name->sun_family = AF_UNIX; + refcount_set(&addr->refcnt, 1); + ++ old_hash = sk->sk_hash; + ordernum = get_random_u32(); + lastnum = ordernum & 0xFFFFF; + retry: +@@ -1209,8 +1210,8 @@ static int unix_bind_bsd(struct sock *sk, struct sockaddr_un *sunaddr, + { + umode_t mode = S_IFSOCK | + (SOCK_INODE(sk->sk_socket)->i_mode & ~current_umask()); +- unsigned int new_hash, old_hash = sk->sk_hash; + struct unix_sock *u = unix_sk(sk); ++ unsigned int new_hash, old_hash; + struct net *net = sock_net(sk); + struct mnt_idmap *idmap; + struct unix_address *addr; +@@ -1248,6 +1249,7 @@ static int unix_bind_bsd(struct sock *sk, struct sockaddr_un *sunaddr, + if (u->addr) + goto out_unlock; + ++ old_hash = sk->sk_hash; + new_hash = unix_bsd_hash(d_backing_inode(dentry)); + unix_table_double_lock(net, old_hash, new_hash); + u->path.mnt = mntget(parent.mnt); +@@ -1275,8 +1277,8 @@ static int unix_bind_bsd(struct sock *sk, struct sockaddr_un *sunaddr, + static int unix_bind_abstract(struct sock *sk, struct sockaddr_un *sunaddr, + int addr_len) + { +- unsigned int new_hash, old_hash = sk->sk_hash; + struct unix_sock *u = unix_sk(sk); ++ unsigned int new_hash, old_hash; + struct net *net = sock_net(sk); + struct unix_address *addr; + int err; +@@ -1294,6 +1296,7 @@ static int unix_bind_abstract(struct sock *sk, struct sockaddr_un *sunaddr, + goto out_mutex; + } + ++ old_hash = sk->sk_hash; + new_hash = unix_abstract_hash(addr->name, addr->len, sk->sk_type); + unix_table_double_lock(net, old_hash, new_hash); + +@@ -1379,7 +1382,7 @@ static int unix_dgram_connect(struct socket *sock, struct sockaddr *addr, + + if ((test_bit(SOCK_PASSCRED, &sock->flags) || + test_bit(SOCK_PASSPIDFD, &sock->flags)) && +- !unix_sk(sk)->addr) { ++ !READ_ONCE(unix_sk(sk)->addr)) { + err = unix_autobind(sk); + if (err) + goto out; +@@ -1487,7 +1490,8 @@ static int unix_stream_connect(struct socket *sock, struct sockaddr *uaddr, + goto out; + + if ((test_bit(SOCK_PASSCRED, &sock->flags) || +- test_bit(SOCK_PASSPIDFD, &sock->flags)) && !u->addr) { ++ test_bit(SOCK_PASSPIDFD, &sock->flags)) && ++ !READ_ONCE(u->addr)) { + err = unix_autobind(sk); + if (err) + goto out; +@@ -1927,7 +1931,8 @@ static int unix_dgram_sendmsg(struct socket *sock, struct msghdr *msg, + } + + if ((test_bit(SOCK_PASSCRED, &sock->flags) || +- test_bit(SOCK_PASSPIDFD, &sock->flags)) && !u->addr) { ++ test_bit(SOCK_PASSPIDFD, &sock->flags)) && ++ !READ_ONCE(u->addr)) { + err = unix_autobind(sk); + if (err) + goto out; +@@ -2147,13 +2152,15 @@ static int queue_oob(struct socket *sock, struct msghdr *msg, struct sock *other + maybe_add_creds(skb, sock, other); + skb_get(skb); + ++ scm_stat_add(other, skb); ++ ++ spin_lock(&other->sk_receive_queue.lock); + if (ousk->oob_skb) + consume_skb(ousk->oob_skb); +- + WRITE_ONCE(ousk->oob_skb, skb); ++ __skb_queue_tail(&other->sk_receive_queue, skb); ++ spin_unlock(&other->sk_receive_queue.lock); + +- scm_stat_add(other, skb); +- skb_queue_tail(&other->sk_receive_queue, skb); + sk_send_sigurg(other); + unix_state_unlock(other); + other->sk_data_ready(other); +@@ -2199,7 +2206,7 @@ static int unix_stream_sendmsg(struct socket *sock, struct msghdr *msg, + goto out_err; + } + +- if (sk->sk_shutdown & SEND_SHUTDOWN) ++ if (READ_ONCE(sk->sk_shutdown) & SEND_SHUTDOWN) + goto pipe_err; + + while (sent < len) { +@@ -2538,8 +2545,10 @@ static int unix_stream_recv_urg(struct unix_stream_read_state *state) + + mutex_lock(&u->iolock); + unix_state_lock(sk); ++ spin_lock(&sk->sk_receive_queue.lock); + + if (sock_flag(sk, SOCK_URGINLINE) || !u->oob_skb) { ++ spin_unlock(&sk->sk_receive_queue.lock); + unix_state_unlock(sk); + mutex_unlock(&u->iolock); + return -EINVAL; +@@ -2551,6 +2560,8 @@ static int unix_stream_recv_urg(struct unix_stream_read_state *state) + WRITE_ONCE(u->oob_skb, NULL); + else + skb_get(oob_skb); ++ ++ spin_unlock(&sk->sk_receive_queue.lock); + unix_state_unlock(sk); + + chunk = state->recv_actor(oob_skb, 0, chunk, state); +@@ -2579,6 +2590,10 @@ static struct sk_buff *manage_oob(struct sk_buff *skb, struct sock *sk, + consume_skb(skb); + skb = NULL; + } else { ++ struct sk_buff *unlinked_skb = NULL; ++ ++ spin_lock(&sk->sk_receive_queue.lock); ++ + if (skb == u->oob_skb) { + if (copied) { + skb = NULL; +@@ -2590,13 +2605,19 @@ static struct sk_buff *manage_oob(struct sk_buff *skb, struct sock *sk, + } else if (flags & MSG_PEEK) { + skb = NULL; + } else { +- skb_unlink(skb, &sk->sk_receive_queue); ++ __skb_unlink(skb, &sk->sk_receive_queue); + WRITE_ONCE(u->oob_skb, NULL); +- if (!WARN_ON_ONCE(skb_unref(skb))) +- kfree_skb(skb); ++ unlinked_skb = skb; + skb = skb_peek(&sk->sk_receive_queue); + } + } ++ ++ spin_unlock(&sk->sk_receive_queue.lock); ++ ++ if (unlinked_skb) { ++ WARN_ON_ONCE(skb_unref(unlinked_skb)); ++ kfree_skb(unlinked_skb); ++ } + } + return skb; + } +diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c +index c4f08f7eb741d..8f8f077e6cd40 100644 +--- a/net/wireless/nl80211.c ++++ b/net/wireless/nl80211.c +@@ -9153,6 +9153,7 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) + struct wiphy *wiphy; + int err, tmp, n_ssids = 0, n_channels, i; + size_t ie_len, size; ++ size_t ssids_offset, ie_offset; + + wiphy = &rdev->wiphy; + +@@ -9198,21 +9199,20 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) + return -EINVAL; + + size = struct_size(request, channels, n_channels); ++ ssids_offset = size; + size = size_add(size, array_size(sizeof(*request->ssids), n_ssids)); ++ ie_offset = size; + size = size_add(size, ie_len); + request = kzalloc(size, GFP_KERNEL); + if (!request) + return -ENOMEM; ++ request->n_channels = n_channels; + + if (n_ssids) +- request->ssids = (void *)&request->channels[n_channels]; ++ request->ssids = (void *)request + ssids_offset; + request->n_ssids = n_ssids; +- if (ie_len) { +- if (n_ssids) +- request->ie = (void *)(request->ssids + n_ssids); +- else +- request->ie = (void *)(request->channels + n_channels); +- } ++ if (ie_len) ++ request->ie = (void *)request + ie_offset; + + i = 0; + if (scan_freqs) { +diff --git a/net/wireless/trace.h b/net/wireless/trace.h +index e89443173c7b4..df92ee4d91d1d 100644 +--- a/net/wireless/trace.h ++++ b/net/wireless/trace.h +@@ -1747,7 +1747,7 @@ TRACE_EVENT(rdev_return_void_tx_rx, + + DECLARE_EVENT_CLASS(tx_rx_evt, + TP_PROTO(struct wiphy *wiphy, u32 tx, u32 rx), +- TP_ARGS(wiphy, rx, tx), ++ TP_ARGS(wiphy, tx, rx), + TP_STRUCT__entry( + WIPHY_ENTRY + __field(u32, tx) +@@ -1764,7 +1764,7 @@ DECLARE_EVENT_CLASS(tx_rx_evt, + + DEFINE_EVENT(tx_rx_evt, rdev_set_antenna, + TP_PROTO(struct wiphy *wiphy, u32 tx, u32 rx), +- TP_ARGS(wiphy, rx, tx) ++ TP_ARGS(wiphy, tx, rx) + ); + + DECLARE_EVENT_CLASS(wiphy_netdev_id_evt, +diff --git a/scripts/Makefile.vdsoinst b/scripts/Makefile.vdsoinst +new file mode 100644 +index 0000000000000..a81ca735003e4 +--- /dev/null ++++ b/scripts/Makefile.vdsoinst +@@ -0,0 +1,45 @@ ++# SPDX-License-Identifier: GPL-2.0-only ++# ========================================================================== ++# Install unstripped copies of vDSO ++# ========================================================================== ++ ++PHONY := __default ++__default: ++ @: ++ ++include $(srctree)/scripts/Kbuild.include ++ ++install-dir := $(MODLIB)/vdso ++ ++define gen_install_rules ++ ++src := $$(firstword $$(subst :,$(space),$(1))) ++dest := $(install-dir)/$$(or $$(word 2,$$(subst :,$(space),$(1))),$$(patsubst %.dbg,%,$$(notdir $(1)))) ++ ++__default: $$(dest) ++$$(dest): $$(src) FORCE ++ $$(call cmd,install) ++ ++# Some architectures create .build-id symlinks ++ifneq ($(filter arm s390 sparc x86, $(SRCARCH)),) ++link := $(install-dir)/.build-id/$$(shell $(READELF) -n $$(src) | sed -n 's@^.*Build ID: \(..\)\(.*\)@\1/\2@p').debug ++ ++__default: $$(link) ++$$(link): $$(dest) FORCE ++ $$(call cmd,symlink) ++endif ++ ++endef ++ ++$(foreach x, $(sort $(INSTALL_FILES)), $(eval $(call gen_install_rules,$(x)))) ++ ++quiet_cmd_install = INSTALL $@ ++ cmd_install = mkdir -p $(dir $@); cp $< $@ ++ ++quiet_cmd_symlink = SYMLINK $@ ++ cmd_symlink = mkdir -p $(dir $@); ln -sf --relative $< $@ ++ ++PHONY += FORCE ++FORCE: ++ ++.PHONY: $(PHONY) +diff --git a/scripts/kconfig/symbol.c b/scripts/kconfig/symbol.c +index a76925b46ce63..7b1df55b01767 100644 +--- a/scripts/kconfig/symbol.c ++++ b/scripts/kconfig/symbol.c +@@ -13,18 +13,21 @@ + + struct symbol symbol_yes = { + .name = "y", ++ .type = S_TRISTATE, + .curr = { "y", yes }, + .flags = SYMBOL_CONST|SYMBOL_VALID, + }; + + struct symbol symbol_mod = { + .name = "m", ++ .type = S_TRISTATE, + .curr = { "m", mod }, + .flags = SYMBOL_CONST|SYMBOL_VALID, + }; + + struct symbol symbol_no = { + .name = "n", ++ .type = S_TRISTATE, + .curr = { "n", no }, + .flags = SYMBOL_CONST|SYMBOL_VALID, + }; +@@ -775,8 +778,7 @@ const char *sym_get_string_value(struct symbol *sym) + case no: + return "n"; + case mod: +- sym_calc_value(modules_sym); +- return (modules_sym->curr.tri == no) ? "n" : "m"; ++ return "m"; + case yes: + return "y"; + } +diff --git a/scripts/module.lds.S b/scripts/module.lds.S +index bf5bcf2836d81..89ff01a22634f 100644 +--- a/scripts/module.lds.S ++++ b/scripts/module.lds.S +@@ -13,6 +13,7 @@ SECTIONS { + /DISCARD/ : { + *(.discard) + *(.discard.*) ++ *(.export_symbol) + } + + __ksymtab 0 : { *(SORT(___ksymtab+*)) } +diff --git a/sound/core/init.c b/sound/core/init.c +index 22c0d217b8608..b2b7e50ff4cc3 100644 +--- a/sound/core/init.c ++++ b/sound/core/init.c +@@ -312,8 +312,8 @@ static int snd_card_init(struct snd_card *card, struct device *parent, + card->number = idx; + #ifdef MODULE + WARN_ON(!module); +- card->module = module; + #endif ++ card->module = module; + INIT_LIST_HEAD(&card->devices); + init_rwsem(&card->controls_rwsem); + rwlock_init(&card->ctl_files_rwlock); +@@ -523,6 +523,14 @@ void snd_card_disconnect(struct snd_card *card) + } + spin_unlock(&card->files_lock); + ++#ifdef CONFIG_PM ++ /* wake up sleepers here before other callbacks for avoiding potential ++ * deadlocks with other locks (e.g. in kctls); ++ * then this notifies the shutdown and sleepers would abort immediately ++ */ ++ wake_up_all(&card->power_sleep); ++#endif ++ + /* notify all connected devices about disconnection */ + /* at this point, they cannot respond to any calls except release() */ + +@@ -538,6 +546,11 @@ void snd_card_disconnect(struct snd_card *card) + synchronize_irq(card->sync_irq); + + snd_info_card_disconnect(card); ++#ifdef CONFIG_SND_DEBUG ++ debugfs_remove(card->debugfs_root); ++ card->debugfs_root = NULL; ++#endif ++ + if (card->registered) { + device_del(&card->card_dev); + card->registered = false; +@@ -550,7 +563,6 @@ void snd_card_disconnect(struct snd_card *card) + mutex_unlock(&snd_card_mutex); + + #ifdef CONFIG_PM +- wake_up(&card->power_sleep); + snd_power_sync_ref(card); + #endif + } +@@ -591,10 +603,6 @@ static int snd_card_do_free(struct snd_card *card) + dev_warn(card->dev, "unable to free card info\n"); + /* Not fatal error */ + } +-#ifdef CONFIG_SND_DEBUG +- debugfs_remove(card->debugfs_root); +- card->debugfs_root = NULL; +-#endif + if (card->release_completion) + complete(card->release_completion); + if (!card->managed) +diff --git a/sound/core/jack.c b/sound/core/jack.c +index e0f034e7275cd..e4bcecdf89b7e 100644 +--- a/sound/core/jack.c ++++ b/sound/core/jack.c +@@ -37,16 +37,18 @@ static const int jack_switch_types[SND_JACK_SWITCH_TYPES] = { + }; + #endif /* CONFIG_SND_JACK_INPUT_DEV */ + ++static void snd_jack_remove_debugfs(struct snd_jack *jack); ++ + static int snd_jack_dev_disconnect(struct snd_device *device) + { +-#ifdef CONFIG_SND_JACK_INPUT_DEV + struct snd_jack *jack = device->device_data; + +- mutex_lock(&jack->input_dev_lock); +- if (!jack->input_dev) { +- mutex_unlock(&jack->input_dev_lock); ++ snd_jack_remove_debugfs(jack); ++ ++#ifdef CONFIG_SND_JACK_INPUT_DEV ++ guard(mutex)(&jack->input_dev_lock); ++ if (!jack->input_dev) + return 0; +- } + + /* If the input device is registered with the input subsystem + * then we need to use a different deallocator. */ +@@ -55,7 +57,6 @@ static int snd_jack_dev_disconnect(struct snd_device *device) + else + input_free_device(jack->input_dev); + jack->input_dev = NULL; +- mutex_unlock(&jack->input_dev_lock); + #endif /* CONFIG_SND_JACK_INPUT_DEV */ + return 0; + } +@@ -92,11 +93,9 @@ static int snd_jack_dev_register(struct snd_device *device) + snprintf(jack->name, sizeof(jack->name), "%s %s", + card->shortname, jack->id); + +- mutex_lock(&jack->input_dev_lock); +- if (!jack->input_dev) { +- mutex_unlock(&jack->input_dev_lock); ++ guard(mutex)(&jack->input_dev_lock); ++ if (!jack->input_dev) + return 0; +- } + + jack->input_dev->name = jack->name; + +@@ -121,7 +120,6 @@ static int snd_jack_dev_register(struct snd_device *device) + if (err == 0) + jack->registered = 1; + +- mutex_unlock(&jack->input_dev_lock); + return err; + } + #endif /* CONFIG_SND_JACK_INPUT_DEV */ +@@ -387,10 +385,14 @@ static int snd_jack_debugfs_add_inject_node(struct snd_jack *jack, + return 0; + } + +-static void snd_jack_debugfs_clear_inject_node(struct snd_jack_kctl *jack_kctl) ++static void snd_jack_remove_debugfs(struct snd_jack *jack) + { +- debugfs_remove(jack_kctl->jack_debugfs_root); +- jack_kctl->jack_debugfs_root = NULL; ++ struct snd_jack_kctl *jack_kctl; ++ ++ list_for_each_entry(jack_kctl, &jack->kctl_list, list) { ++ debugfs_remove(jack_kctl->jack_debugfs_root); ++ jack_kctl->jack_debugfs_root = NULL; ++ } + } + #else /* CONFIG_SND_JACK_INJECTION_DEBUG */ + static int snd_jack_debugfs_add_inject_node(struct snd_jack *jack, +@@ -399,7 +401,7 @@ static int snd_jack_debugfs_add_inject_node(struct snd_jack *jack, + return 0; + } + +-static void snd_jack_debugfs_clear_inject_node(struct snd_jack_kctl *jack_kctl) ++static void snd_jack_remove_debugfs(struct snd_jack *jack) + { + } + #endif /* CONFIG_SND_JACK_INJECTION_DEBUG */ +@@ -410,7 +412,6 @@ static void snd_jack_kctl_private_free(struct snd_kcontrol *kctl) + + jack_kctl = kctl->private_data; + if (jack_kctl) { +- snd_jack_debugfs_clear_inject_node(jack_kctl); + list_del(&jack_kctl->list); + kfree(jack_kctl); + } +@@ -503,8 +504,8 @@ int snd_jack_new(struct snd_card *card, const char *id, int type, + .dev_free = snd_jack_dev_free, + #ifdef CONFIG_SND_JACK_INPUT_DEV + .dev_register = snd_jack_dev_register, +- .dev_disconnect = snd_jack_dev_disconnect, + #endif /* CONFIG_SND_JACK_INPUT_DEV */ ++ .dev_disconnect = snd_jack_dev_disconnect, + }; + + if (initial_kctl) { +@@ -586,14 +587,9 @@ EXPORT_SYMBOL(snd_jack_new); + void snd_jack_set_parent(struct snd_jack *jack, struct device *parent) + { + WARN_ON(jack->registered); +- mutex_lock(&jack->input_dev_lock); +- if (!jack->input_dev) { +- mutex_unlock(&jack->input_dev_lock); +- return; +- } +- +- jack->input_dev->dev.parent = parent; +- mutex_unlock(&jack->input_dev_lock); ++ guard(mutex)(&jack->input_dev_lock); ++ if (jack->input_dev) ++ jack->input_dev->dev.parent = parent; + } + EXPORT_SYMBOL(snd_jack_set_parent); + +diff --git a/sound/core/seq/seq_ump_convert.c b/sound/core/seq/seq_ump_convert.c +index ee6ac649df836..9bfba69b2a709 100644 +--- a/sound/core/seq/seq_ump_convert.c ++++ b/sound/core/seq/seq_ump_convert.c +@@ -157,7 +157,7 @@ static void ump_system_to_one_param_ev(const union snd_ump_midi1_msg *val, + static void ump_system_to_songpos_ev(const union snd_ump_midi1_msg *val, + struct snd_seq_event *ev) + { +- ev->data.control.value = (val->system.parm1 << 7) | val->system.parm2; ++ ev->data.control.value = (val->system.parm2 << 7) | val->system.parm1; + } + + /* Encoders for 0xf0 - 0xff */ +@@ -368,6 +368,7 @@ static int cvt_ump_midi1_to_midi2(struct snd_seq_client *dest, + struct snd_seq_ump_event ev_cvt; + const union snd_ump_midi1_msg *midi1 = (const union snd_ump_midi1_msg *)event->ump; + union snd_ump_midi2_msg *midi2 = (union snd_ump_midi2_msg *)ev_cvt.ump; ++ struct snd_seq_ump_midi2_bank *cc; + + ev_cvt = *event; + memset(&ev_cvt.ump, 0, sizeof(ev_cvt.ump)); +@@ -387,11 +388,29 @@ static int cvt_ump_midi1_to_midi2(struct snd_seq_client *dest, + midi2->paf.data = upscale_7_to_32bit(midi1->paf.data); + break; + case UMP_MSG_STATUS_CC: ++ cc = &dest_port->midi2_bank[midi1->note.channel]; ++ switch (midi1->cc.index) { ++ case UMP_CC_BANK_SELECT: ++ cc->bank_set = 1; ++ cc->cc_bank_msb = midi1->cc.data; ++ return 0; // skip ++ case UMP_CC_BANK_SELECT_LSB: ++ cc->bank_set = 1; ++ cc->cc_bank_lsb = midi1->cc.data; ++ return 0; // skip ++ } + midi2->cc.index = midi1->cc.index; + midi2->cc.data = upscale_7_to_32bit(midi1->cc.data); + break; + case UMP_MSG_STATUS_PROGRAM: + midi2->pg.program = midi1->pg.program; ++ cc = &dest_port->midi2_bank[midi1->note.channel]; ++ if (cc->bank_set) { ++ midi2->pg.bank_valid = 1; ++ midi2->pg.bank_msb = cc->cc_bank_msb; ++ midi2->pg.bank_lsb = cc->cc_bank_lsb; ++ cc->bank_set = 0; ++ } + break; + case UMP_MSG_STATUS_CHANNEL_PRESSURE: + midi2->caf.data = upscale_7_to_32bit(midi1->caf.data); +@@ -419,6 +438,7 @@ static int cvt_ump_midi2_to_midi1(struct snd_seq_client *dest, + struct snd_seq_ump_event ev_cvt; + union snd_ump_midi1_msg *midi1 = (union snd_ump_midi1_msg *)ev_cvt.ump; + const union snd_ump_midi2_msg *midi2 = (const union snd_ump_midi2_msg *)event->ump; ++ int err; + u16 v; + + ev_cvt = *event; +@@ -443,6 +463,24 @@ static int cvt_ump_midi2_to_midi1(struct snd_seq_client *dest, + midi1->cc.data = downscale_32_to_7bit(midi2->cc.data); + break; + case UMP_MSG_STATUS_PROGRAM: ++ if (midi2->pg.bank_valid) { ++ midi1->cc.status = UMP_MSG_STATUS_CC; ++ midi1->cc.index = UMP_CC_BANK_SELECT; ++ midi1->cc.data = midi2->pg.bank_msb; ++ err = __snd_seq_deliver_single_event(dest, dest_port, ++ (struct snd_seq_event *)&ev_cvt, ++ atomic, hop); ++ if (err < 0) ++ return err; ++ midi1->cc.index = UMP_CC_BANK_SELECT_LSB; ++ midi1->cc.data = midi2->pg.bank_lsb; ++ err = __snd_seq_deliver_single_event(dest, dest_port, ++ (struct snd_seq_event *)&ev_cvt, ++ atomic, hop); ++ if (err < 0) ++ return err; ++ midi1->note.status = midi2->note.status; ++ } + midi1->pg.program = midi2->pg.program; + break; + case UMP_MSG_STATUS_CHANNEL_PRESSURE: +@@ -691,6 +729,7 @@ static int system_ev_to_ump_midi1(const struct snd_seq_event *event, + union snd_ump_midi1_msg *data, + unsigned char status) + { ++ data->system.type = UMP_MSG_TYPE_SYSTEM; // override + data->system.status = status; + return 1; + } +@@ -713,8 +752,8 @@ static int system_2p_ev_to_ump_midi1(const struct snd_seq_event *event, + unsigned char status) + { + data->system.status = status; +- data->system.parm1 = (event->data.control.value >> 7) & 0x7f; +- data->system.parm2 = event->data.control.value & 0x7f; ++ data->system.parm1 = event->data.control.value & 0x7f; ++ data->system.parm2 = (event->data.control.value >> 7) & 0x7f; + return 1; + } + +@@ -854,7 +893,6 @@ static int pgm_ev_to_ump_midi2(const struct snd_seq_event *event, + data->pg.bank_msb = cc->cc_bank_msb; + data->pg.bank_lsb = cc->cc_bank_lsb; + cc->bank_set = 0; +- cc->cc_bank_msb = cc->cc_bank_lsb = 0; + } + return 1; + } +diff --git a/sound/core/timer.c b/sound/core/timer.c +index e6e551d4a29e0..a0b515981ee9b 100644 +--- a/sound/core/timer.c ++++ b/sound/core/timer.c +@@ -553,6 +553,16 @@ static int snd_timer_start1(struct snd_timer_instance *timeri, + goto unlock; + } + ++ /* check the actual time for the start tick; ++ * bail out as error if it's way too low (< 100us) ++ */ ++ if (start) { ++ if ((u64)snd_timer_hw_resolution(timer) * ticks < 100000) { ++ result = -EINVAL; ++ goto unlock; ++ } ++ } ++ + if (start) + timeri->ticks = timeri->cticks = ticks; + else if (!timeri->cticks) +diff --git a/sound/hda/intel-dsp-config.c b/sound/hda/intel-dsp-config.c +index 6a384b922e4fa..d1f6cdcf1866e 100644 +--- a/sound/hda/intel-dsp-config.c ++++ b/sound/hda/intel-dsp-config.c +@@ -557,9 +557,32 @@ static const struct config_entry *snd_intel_dsp_find_config + if (table->codec_hid) { + int i; + +- for (i = 0; i < table->codec_hid->num_codecs; i++) +- if (acpi_dev_present(table->codec_hid->codecs[i], NULL, -1)) ++ for (i = 0; i < table->codec_hid->num_codecs; i++) { ++ struct nhlt_acpi_table *nhlt; ++ bool ssp_found = false; ++ ++ if (!acpi_dev_present(table->codec_hid->codecs[i], NULL, -1)) ++ continue; ++ ++ nhlt = intel_nhlt_init(&pci->dev); ++ if (!nhlt) { ++ dev_warn(&pci->dev, "%s: NHLT table not found, skipped HID %s\n", ++ __func__, table->codec_hid->codecs[i]); ++ continue; ++ } ++ ++ if (intel_nhlt_has_endpoint_type(nhlt, NHLT_LINK_SSP) && ++ intel_nhlt_ssp_endpoint_mask(nhlt, NHLT_DEVICE_I2S)) ++ ssp_found = true; ++ ++ intel_nhlt_free(nhlt); ++ ++ if (ssp_found) + break; ++ ++ dev_warn(&pci->dev, "%s: no valid SSP found for HID %s, skipped\n", ++ __func__, table->codec_hid->codecs[i]); ++ } + if (i == table->codec_hid->num_codecs) + continue; + } +diff --git a/sound/pci/emu10k1/io.c b/sound/pci/emu10k1/io.c +index 74df2330015f6..5cb8acf5b158c 100644 +--- a/sound/pci/emu10k1/io.c ++++ b/sound/pci/emu10k1/io.c +@@ -285,6 +285,7 @@ static void snd_emu1010_fpga_write_locked(struct snd_emu10k1 *emu, u32 reg, u32 + outw(value, emu->port + A_GPIO); + udelay(10); + outw(value | 0x80 , emu->port + A_GPIO); /* High bit clocks the value into the fpga. */ ++ udelay(10); + } + + void snd_emu1010_fpga_write(struct snd_emu10k1 *emu, u32 reg, u32 value) +diff --git a/sound/pci/hda/cs35l56_hda.c b/sound/pci/hda/cs35l56_hda.c +index 27848d6469636..15e20d9261393 100644 +--- a/sound/pci/hda/cs35l56_hda.c ++++ b/sound/pci/hda/cs35l56_hda.c +@@ -29,14 +29,23 @@ + * ASP1_RX_WL = 24 bits per sample + * ASP1_TX_WL = 24 bits per sample + * ASP1_RXn_EN 1..3 and ASP1_TXn_EN 1..4 disabled ++ * ++ * Override any Windows-specific mixer settings applied by the firmware. + */ + static const struct reg_sequence cs35l56_hda_dai_config[] = { + { CS35L56_ASP1_CONTROL1, 0x00000021 }, + { CS35L56_ASP1_CONTROL2, 0x20200200 }, + { CS35L56_ASP1_CONTROL3, 0x00000003 }, ++ { CS35L56_ASP1_FRAME_CONTROL1, 0x03020100 }, ++ { CS35L56_ASP1_FRAME_CONTROL5, 0x00020100 }, + { CS35L56_ASP1_DATA_CONTROL5, 0x00000018 }, + { CS35L56_ASP1_DATA_CONTROL1, 0x00000018 }, + { CS35L56_ASP1_ENABLES1, 0x00000000 }, ++ { CS35L56_ASP1TX1_INPUT, 0x00000018 }, ++ { CS35L56_ASP1TX2_INPUT, 0x00000019 }, ++ { CS35L56_ASP1TX3_INPUT, 0x00000020 }, ++ { CS35L56_ASP1TX4_INPUT, 0x00000028 }, ++ + }; + + static void cs35l56_hda_play(struct cs35l56_hda *cs35l56) +@@ -132,6 +141,10 @@ static int cs35l56_hda_runtime_resume(struct device *dev) + } + } + ++ ret = cs35l56_force_sync_asp1_registers_from_cache(&cs35l56->base); ++ if (ret) ++ goto err; ++ + return 0; + + err: +@@ -603,6 +616,8 @@ static int cs35l56_hda_fw_load(struct cs35l56_hda *cs35l56) + ret = cs35l56_wait_for_firmware_boot(&cs35l56->base); + if (ret) + goto err_powered_up; ++ ++ regcache_cache_only(cs35l56->base.regmap, false); + } + + /* Disable auto-hibernate so that runtime_pm has control */ +@@ -684,8 +699,6 @@ static void cs35l56_hda_unbind(struct device *dev, struct device *master, void * + if (cs35l56->base.fw_patched) + cs_dsp_power_down(&cs35l56->cs_dsp); + +- cs_dsp_remove(&cs35l56->cs_dsp); +- + if (comps[cs35l56->index].dev == dev) + memset(&comps[cs35l56->index], 0, sizeof(*comps)); + +@@ -942,6 +955,8 @@ int cs35l56_hda_common_probe(struct cs35l56_hda *cs35l56, int id) + if (ret) + goto err; + ++ regcache_cache_only(cs35l56->base.regmap, false); ++ + ret = cs35l56_set_patch(&cs35l56->base); + if (ret) + goto err; +@@ -965,6 +980,9 @@ int cs35l56_hda_common_probe(struct cs35l56_hda *cs35l56, int id) + + regmap_multi_reg_write(cs35l56->base.regmap, cs35l56_hda_dai_config, + ARRAY_SIZE(cs35l56_hda_dai_config)); ++ ret = cs35l56_force_sync_asp1_registers_from_cache(&cs35l56->base); ++ if (ret) ++ goto dsp_err; + + /* + * By default only enable one ASP1TXn, where n=amplifier index, +@@ -990,6 +1008,8 @@ int cs35l56_hda_common_probe(struct cs35l56_hda *cs35l56, int id) + + pm_err: + pm_runtime_disable(cs35l56->base.dev); ++dsp_err: ++ cs_dsp_remove(&cs35l56->cs_dsp); + err: + gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0); + +@@ -1007,6 +1027,8 @@ void cs35l56_hda_remove(struct device *dev) + + component_del(cs35l56->base.dev, &cs35l56_hda_comp_ops); + ++ cs_dsp_remove(&cs35l56->cs_dsp); ++ + kfree(cs35l56->system_name); + pm_runtime_put_noidle(cs35l56->base.dev); + +diff --git a/sound/pci/hda/hda_cs_dsp_ctl.c b/sound/pci/hda/hda_cs_dsp_ctl.c +index 463ca06036bfe..9db45d7c17e5f 100644 +--- a/sound/pci/hda/hda_cs_dsp_ctl.c ++++ b/sound/pci/hda/hda_cs_dsp_ctl.c +@@ -8,6 +8,7 @@ + + #include + #include ++#include + #include + #include + #include "hda_cs_dsp_ctl.h" +@@ -97,11 +98,23 @@ static unsigned int wmfw_convert_flags(unsigned int in) + return out; + } + +-static void hda_cs_dsp_add_kcontrol(struct hda_cs_dsp_coeff_ctl *ctl, const char *name) ++static void hda_cs_dsp_free_kcontrol(struct snd_kcontrol *kctl) + { ++ struct hda_cs_dsp_coeff_ctl *ctl = (struct hda_cs_dsp_coeff_ctl *)snd_kcontrol_chip(kctl); + struct cs_dsp_coeff_ctl *cs_ctl = ctl->cs_ctl; ++ ++ /* NULL priv to prevent a double-free in hda_cs_dsp_control_remove() */ ++ cs_ctl->priv = NULL; ++ kfree(ctl); ++} ++ ++static void hda_cs_dsp_add_kcontrol(struct cs_dsp_coeff_ctl *cs_ctl, ++ const struct hda_cs_dsp_ctl_info *info, ++ const char *name) ++{ + struct snd_kcontrol_new kcontrol = {0}; + struct snd_kcontrol *kctl; ++ struct hda_cs_dsp_coeff_ctl *ctl __free(kfree) = NULL; + int ret = 0; + + if (cs_ctl->len > ADSP_MAX_STD_CTRL_SIZE) { +@@ -110,6 +123,13 @@ static void hda_cs_dsp_add_kcontrol(struct hda_cs_dsp_coeff_ctl *ctl, const char + return; + } + ++ ctl = kzalloc(sizeof(*ctl), GFP_KERNEL); ++ if (!ctl) ++ return; ++ ++ ctl->cs_ctl = cs_ctl; ++ ctl->card = info->card; ++ + kcontrol.name = name; + kcontrol.info = hda_cs_dsp_coeff_info; + kcontrol.iface = SNDRV_CTL_ELEM_IFACE_MIXER; +@@ -117,20 +137,22 @@ static void hda_cs_dsp_add_kcontrol(struct hda_cs_dsp_coeff_ctl *ctl, const char + kcontrol.get = hda_cs_dsp_coeff_get; + kcontrol.put = hda_cs_dsp_coeff_put; + +- /* Save ctl inside private_data, ctl is owned by cs_dsp, +- * and will be freed when cs_dsp removes the control */ + kctl = snd_ctl_new1(&kcontrol, (void *)ctl); + if (!kctl) + return; + +- ret = snd_ctl_add(ctl->card, kctl); ++ kctl->private_free = hda_cs_dsp_free_kcontrol; ++ ctl->kctl = kctl; ++ ++ /* snd_ctl_add() calls our private_free on error, which will kfree(ctl) */ ++ cs_ctl->priv = no_free_ptr(ctl); ++ ret = snd_ctl_add(info->card, kctl); + if (ret) { + dev_err(cs_ctl->dsp->dev, "Failed to add KControl %s = %d\n", kcontrol.name, ret); + return; + } + + dev_dbg(cs_ctl->dsp->dev, "Added KControl: %s\n", kcontrol.name); +- ctl->kctl = kctl; + } + + static void hda_cs_dsp_control_add(struct cs_dsp_coeff_ctl *cs_ctl, +@@ -138,7 +160,6 @@ static void hda_cs_dsp_control_add(struct cs_dsp_coeff_ctl *cs_ctl, + { + struct cs_dsp *cs_dsp = cs_ctl->dsp; + char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; +- struct hda_cs_dsp_coeff_ctl *ctl; + const char *region_name; + int ret; + +@@ -163,15 +184,7 @@ static void hda_cs_dsp_control_add(struct cs_dsp_coeff_ctl *cs_ctl, + " %.*s", cs_ctl->subname_len - skip, cs_ctl->subname + skip); + } + +- ctl = kzalloc(sizeof(*ctl), GFP_KERNEL); +- if (!ctl) +- return; +- +- ctl->cs_ctl = cs_ctl; +- ctl->card = info->card; +- cs_ctl->priv = ctl; +- +- hda_cs_dsp_add_kcontrol(ctl, name); ++ hda_cs_dsp_add_kcontrol(cs_ctl, info, name); + } + + void hda_cs_dsp_add_controls(struct cs_dsp *dsp, const struct hda_cs_dsp_ctl_info *info) +@@ -203,7 +216,9 @@ void hda_cs_dsp_control_remove(struct cs_dsp_coeff_ctl *cs_ctl) + { + struct hda_cs_dsp_coeff_ctl *ctl = cs_ctl->priv; + +- kfree(ctl); ++ /* ctl and kctl may already have been removed by ALSA private_free */ ++ if (ctl && ctl->kctl) ++ snd_ctl_remove(ctl->card, ctl->kctl); + } + EXPORT_SYMBOL_NS_GPL(hda_cs_dsp_control_remove, SND_HDA_CS_DSP_CONTROLS); + +diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c +index 47e404bde4241..2151fb1bd0de7 100644 +--- a/sound/pci/hda/patch_realtek.c ++++ b/sound/pci/hda/patch_realtek.c +@@ -9959,8 +9959,11 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { + SND_PCI_QUIRK(0x103c, 0x8c70, "HP EliteBook 835 G11", ALC287_FIXUP_CS35L41_I2C_2_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8c71, "HP EliteBook 845 G11", ALC287_FIXUP_CS35L41_I2C_2_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8c72, "HP EliteBook 865 G11", ALC287_FIXUP_CS35L41_I2C_2_HP_GPIO_LED), ++ SND_PCI_QUIRK(0x103c, 0x8c89, "HP ProBook 460 G11", ALC236_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8c8a, "HP EliteBook 630", ALC236_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8c8c, "HP EliteBook 660", ALC236_FIXUP_HP_GPIO_LED), ++ SND_PCI_QUIRK(0x103c, 0x8c8d, "HP ProBook 440 G11", ALC236_FIXUP_HP_GPIO_LED), ++ SND_PCI_QUIRK(0x103c, 0x8c8e, "HP ProBook 460 G11", ALC236_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8c90, "HP EliteBook 640", ALC236_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8c91, "HP EliteBook 660", ALC236_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8c96, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF), +@@ -10054,7 +10057,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { + SND_PCI_QUIRK(0x1043, 0x3030, "ASUS ZN270IE", ALC256_FIXUP_ASUS_AIO_GPIO2), + SND_PCI_QUIRK(0x1043, 0x3a20, "ASUS G614JZR", ALC245_FIXUP_CS35L41_SPI_2), + SND_PCI_QUIRK(0x1043, 0x3a30, "ASUS G814JVR/JIR", ALC245_FIXUP_CS35L41_SPI_2), +- SND_PCI_QUIRK(0x1043, 0x3a40, "ASUS G814JZR", ALC245_FIXUP_CS35L41_SPI_2), ++ SND_PCI_QUIRK(0x1043, 0x3a40, "ASUS G814JZR", ALC285_FIXUP_ASUS_SPI_REAR_SPEAKERS), + SND_PCI_QUIRK(0x1043, 0x3a50, "ASUS G834JYR/JZR", ALC245_FIXUP_CS35L41_SPI_2), + SND_PCI_QUIRK(0x1043, 0x3a60, "ASUS G634JYR/JZR", ALC245_FIXUP_CS35L41_SPI_2), + SND_PCI_QUIRK(0x1043, 0x831a, "ASUS P901", ALC269_FIXUP_STEREO_DMIC), +diff --git a/sound/soc/amd/yc/acp6x-mach.c b/sound/soc/amd/yc/acp6x-mach.c +index 69c68d8e7a6b5..1760b5d42460a 100644 +--- a/sound/soc/amd/yc/acp6x-mach.c ++++ b/sound/soc/amd/yc/acp6x-mach.c +@@ -430,6 +430,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = { + DMI_MATCH(DMI_BOARD_NAME, "MRID6"), + } + }, ++ { ++ .driver_data = &acp6x_card, ++ .matches = { ++ DMI_MATCH(DMI_BOARD_VENDOR, "MDC"), ++ DMI_MATCH(DMI_BOARD_NAME, "Herbag_MDU"), ++ } ++ }, + { + .driver_data = &acp6x_card, + .matches = { +diff --git a/sound/soc/codecs/cs35l41.c b/sound/soc/codecs/cs35l41.c +index 5456e6bfa242f..bc541293089f0 100644 +--- a/sound/soc/codecs/cs35l41.c ++++ b/sound/soc/codecs/cs35l41.c +@@ -1095,6 +1095,7 @@ static int cs35l41_handle_pdata(struct device *dev, struct cs35l41_hw_cfg *hw_cf + static int cs35l41_dsp_init(struct cs35l41_private *cs35l41) + { + struct wm_adsp *dsp; ++ uint32_t dsp1rx5_src; + int ret; + + dsp = &cs35l41->dsp; +@@ -1114,16 +1115,29 @@ static int cs35l41_dsp_init(struct cs35l41_private *cs35l41) + return ret; + } + +- ret = regmap_write(cs35l41->regmap, CS35L41_DSP1_RX5_SRC, +- CS35L41_INPUT_SRC_VPMON); ++ switch (cs35l41->hw_cfg.bst_type) { ++ case CS35L41_INT_BOOST: ++ case CS35L41_SHD_BOOST_ACTV: ++ dsp1rx5_src = CS35L41_INPUT_SRC_VPMON; ++ break; ++ case CS35L41_EXT_BOOST: ++ case CS35L41_SHD_BOOST_PASS: ++ dsp1rx5_src = CS35L41_INPUT_SRC_VBSTMON; ++ break; ++ default: ++ dev_err(cs35l41->dev, "wm_halo_init failed - Invalid Boost Type: %d\n", ++ cs35l41->hw_cfg.bst_type); ++ goto err_dsp; ++ } ++ ++ ret = regmap_write(cs35l41->regmap, CS35L41_DSP1_RX5_SRC, dsp1rx5_src); + if (ret < 0) { +- dev_err(cs35l41->dev, "Write INPUT_SRC_VPMON failed: %d\n", ret); ++ dev_err(cs35l41->dev, "Write DSP1RX5_SRC: %d failed: %d\n", dsp1rx5_src, ret); + goto err_dsp; + } +- ret = regmap_write(cs35l41->regmap, CS35L41_DSP1_RX6_SRC, +- CS35L41_INPUT_SRC_CLASSH); ++ ret = regmap_write(cs35l41->regmap, CS35L41_DSP1_RX6_SRC, CS35L41_INPUT_SRC_VBSTMON); + if (ret < 0) { +- dev_err(cs35l41->dev, "Write INPUT_SRC_CLASSH failed: %d\n", ret); ++ dev_err(cs35l41->dev, "Write CS35L41_INPUT_SRC_VBSTMON failed: %d\n", ret); + goto err_dsp; + } + ret = regmap_write(cs35l41->regmap, CS35L41_DSP1_RX7_SRC, +diff --git a/sound/soc/codecs/cs35l56-shared.c b/sound/soc/codecs/cs35l56-shared.c +index afd12d853ce4c..12291242362b4 100644 +--- a/sound/soc/codecs/cs35l56-shared.c ++++ b/sound/soc/codecs/cs35l56-shared.c +@@ -194,6 +194,47 @@ static bool cs35l56_volatile_reg(struct device *dev, unsigned int reg) + } + } + ++/* ++ * The firmware boot sequence can overwrite the ASP1 config registers so that ++ * they don't match regmap's view of their values. Rewrite the values from the ++ * regmap cache into the hardware registers. ++ */ ++int cs35l56_force_sync_asp1_registers_from_cache(struct cs35l56_base *cs35l56_base) ++{ ++ struct reg_sequence asp1_regs[] = { ++ { .reg = CS35L56_ASP1_ENABLES1 }, ++ { .reg = CS35L56_ASP1_CONTROL1 }, ++ { .reg = CS35L56_ASP1_CONTROL2 }, ++ { .reg = CS35L56_ASP1_CONTROL3 }, ++ { .reg = CS35L56_ASP1_FRAME_CONTROL1 }, ++ { .reg = CS35L56_ASP1_FRAME_CONTROL5 }, ++ { .reg = CS35L56_ASP1_DATA_CONTROL1 }, ++ { .reg = CS35L56_ASP1_DATA_CONTROL5 }, ++ }; ++ int i, ret; ++ ++ /* Read values from regmap cache into a write sequence */ ++ for (i = 0; i < ARRAY_SIZE(asp1_regs); ++i) { ++ ret = regmap_read(cs35l56_base->regmap, asp1_regs[i].reg, &asp1_regs[i].def); ++ if (ret) ++ goto err; ++ } ++ ++ /* Write the values cache-bypassed so that they will be written to silicon */ ++ ret = regmap_multi_reg_write_bypassed(cs35l56_base->regmap, asp1_regs, ++ ARRAY_SIZE(asp1_regs)); ++ if (ret) ++ goto err; ++ ++ return 0; ++ ++err: ++ dev_err(cs35l56_base->dev, "Failed to sync ASP1 registers: %d\n", ret); ++ ++ return ret; ++} ++EXPORT_SYMBOL_NS_GPL(cs35l56_force_sync_asp1_registers_from_cache, SND_SOC_CS35L56_SHARED); ++ + int cs35l56_mbox_send(struct cs35l56_base *cs35l56_base, unsigned int command) + { + unsigned int val; +diff --git a/sound/soc/codecs/cs35l56.c b/sound/soc/codecs/cs35l56.c +index 530f6e06b41d5..c855ef3ec665e 100644 +--- a/sound/soc/codecs/cs35l56.c ++++ b/sound/soc/codecs/cs35l56.c +@@ -277,6 +277,21 @@ static SOC_VALUE_ENUM_SINGLE_DECL(cs35l56_sdw1tx4_enum, + static const struct snd_kcontrol_new sdw1_tx4_mux = + SOC_DAPM_ENUM("SDW1TX4 SRC", cs35l56_sdw1tx4_enum); + ++static int cs35l56_asp1_cfg_event(struct snd_soc_dapm_widget *w, ++ struct snd_kcontrol *kcontrol, int event) ++{ ++ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); ++ struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(component); ++ ++ switch (event) { ++ case SND_SOC_DAPM_PRE_PMU: ++ /* Override register values set by firmware boot */ ++ return cs35l56_force_sync_asp1_registers_from_cache(&cs35l56->base); ++ default: ++ return 0; ++ } ++} ++ + static int cs35l56_play_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) + { +@@ -313,6 +328,9 @@ static const struct snd_soc_dapm_widget cs35l56_dapm_widgets[] = { + SND_SOC_DAPM_REGULATOR_SUPPLY("VDD_B", 0, 0), + SND_SOC_DAPM_REGULATOR_SUPPLY("VDD_AMP", 0, 0), + ++ SND_SOC_DAPM_SUPPLY("ASP1 CFG", SND_SOC_NOPM, 0, 0, cs35l56_asp1_cfg_event, ++ SND_SOC_DAPM_PRE_PMU), ++ + SND_SOC_DAPM_SUPPLY("PLAY", SND_SOC_NOPM, 0, 0, cs35l56_play_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + +@@ -380,6 +398,9 @@ static const struct snd_soc_dapm_route cs35l56_audio_map[] = { + { "AMP", NULL, "VDD_B" }, + { "AMP", NULL, "VDD_AMP" }, + ++ { "ASP1 Playback", NULL, "ASP1 CFG" }, ++ { "ASP1 Capture", NULL, "ASP1 CFG" }, ++ + { "ASP1 Playback", NULL, "PLAY" }, + { "SDW1 Playback", NULL, "PLAY" }, + +diff --git a/sound/soc/codecs/cs42l43.c b/sound/soc/codecs/cs42l43.c +index 8015f4b7a5b32..1443eb1dc0b17 100644 +--- a/sound/soc/codecs/cs42l43.c ++++ b/sound/soc/codecs/cs42l43.c +@@ -220,8 +220,9 @@ static int cs42l43_startup(struct snd_pcm_substream *substream, struct snd_soc_d + struct snd_soc_component *component = dai->component; + struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component); + struct cs42l43 *cs42l43 = priv->core; +- int provider = !!regmap_test_bits(cs42l43->regmap, CS42L43_ASP_CLK_CONFIG2, +- CS42L43_ASP_MASTER_MODE_MASK); ++ int provider = !dai->id || !!regmap_test_bits(cs42l43->regmap, ++ CS42L43_ASP_CLK_CONFIG2, ++ CS42L43_ASP_MASTER_MODE_MASK); + + if (provider) + priv->constraint.mask = CS42L43_PROVIDER_RATE_MASK; +diff --git a/sound/soc/codecs/da7219-aad.c b/sound/soc/codecs/da7219-aad.c +index 8537c96307a97..9b0c470181706 100644 +--- a/sound/soc/codecs/da7219-aad.c ++++ b/sound/soc/codecs/da7219-aad.c +@@ -671,8 +671,10 @@ static struct da7219_aad_pdata *da7219_aad_fw_to_pdata(struct device *dev) + return NULL; + + aad_pdata = devm_kzalloc(dev, sizeof(*aad_pdata), GFP_KERNEL); +- if (!aad_pdata) ++ if (!aad_pdata) { ++ fwnode_handle_put(aad_np); + return NULL; ++ } + + aad_pdata->irq = i2c->irq; + +@@ -753,6 +755,8 @@ static struct da7219_aad_pdata *da7219_aad_fw_to_pdata(struct device *dev) + else + aad_pdata->adc_1bit_rpt = DA7219_AAD_ADC_1BIT_RPT_1; + ++ fwnode_handle_put(aad_np); ++ + return aad_pdata; + } + +diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c +index e0da151508309..b69f6afa0ae40 100644 +--- a/sound/soc/codecs/rt5645.c ++++ b/sound/soc/codecs/rt5645.c +@@ -441,6 +441,7 @@ struct rt5645_priv { + struct regmap *regmap; + struct i2c_client *i2c; + struct gpio_desc *gpiod_hp_det; ++ struct gpio_desc *gpiod_cbj_sleeve; + struct snd_soc_jack *hp_jack; + struct snd_soc_jack *mic_jack; + struct snd_soc_jack *btn_jack; +@@ -3183,6 +3184,9 @@ static int rt5645_jack_detect(struct snd_soc_component *component, int jack_inse + regmap_update_bits(rt5645->regmap, RT5645_IN1_CTRL2, + RT5645_CBJ_MN_JD, 0); + ++ if (rt5645->gpiod_cbj_sleeve) ++ gpiod_set_value(rt5645->gpiod_cbj_sleeve, 1); ++ + msleep(600); + regmap_read(rt5645->regmap, RT5645_IN1_CTRL3, &val); + val &= 0x7; +@@ -3199,6 +3203,8 @@ static int rt5645_jack_detect(struct snd_soc_component *component, int jack_inse + snd_soc_dapm_disable_pin(dapm, "Mic Det Power"); + snd_soc_dapm_sync(dapm); + rt5645->jack_type = SND_JACK_HEADPHONE; ++ if (rt5645->gpiod_cbj_sleeve) ++ gpiod_set_value(rt5645->gpiod_cbj_sleeve, 0); + } + if (rt5645->pdata.level_trigger_irq) + regmap_update_bits(rt5645->regmap, RT5645_IRQ_CTRL2, +@@ -3226,6 +3232,9 @@ static int rt5645_jack_detect(struct snd_soc_component *component, int jack_inse + if (rt5645->pdata.level_trigger_irq) + regmap_update_bits(rt5645->regmap, RT5645_IRQ_CTRL2, + RT5645_JD_1_1_MASK, RT5645_JD_1_1_INV); ++ ++ if (rt5645->gpiod_cbj_sleeve) ++ gpiod_set_value(rt5645->gpiod_cbj_sleeve, 0); + } + + return rt5645->jack_type; +@@ -3958,6 +3967,16 @@ static int rt5645_i2c_probe(struct i2c_client *i2c) + return ret; + } + ++ rt5645->gpiod_cbj_sleeve = devm_gpiod_get_optional(&i2c->dev, "cbj-sleeve", ++ GPIOD_OUT_LOW); ++ ++ if (IS_ERR(rt5645->gpiod_cbj_sleeve)) { ++ ret = PTR_ERR(rt5645->gpiod_cbj_sleeve); ++ dev_info(&i2c->dev, "failed to initialize gpiod, ret=%d\n", ret); ++ if (ret != -ENOENT) ++ return ret; ++ } ++ + for (i = 0; i < ARRAY_SIZE(rt5645->supplies); i++) + rt5645->supplies[i].supply = rt5645_supply_names[i]; + +@@ -4205,6 +4224,9 @@ static void rt5645_i2c_remove(struct i2c_client *i2c) + cancel_delayed_work_sync(&rt5645->jack_detect_work); + cancel_delayed_work_sync(&rt5645->rcclock_work); + ++ if (rt5645->gpiod_cbj_sleeve) ++ gpiod_set_value(rt5645->gpiod_cbj_sleeve, 0); ++ + regulator_bulk_disable(ARRAY_SIZE(rt5645->supplies), rt5645->supplies); + } + +@@ -4220,6 +4242,9 @@ static void rt5645_i2c_shutdown(struct i2c_client *i2c) + 0); + msleep(20); + regmap_write(rt5645->regmap, RT5645_RESET, 0); ++ ++ if (rt5645->gpiod_cbj_sleeve) ++ gpiod_set_value(rt5645->gpiod_cbj_sleeve, 0); + } + + static int __maybe_unused rt5645_sys_suspend(struct device *dev) +diff --git a/sound/soc/codecs/rt715-sdca.c b/sound/soc/codecs/rt715-sdca.c +index 9fa96fd83d4aa..84f1dc453e971 100644 +--- a/sound/soc/codecs/rt715-sdca.c ++++ b/sound/soc/codecs/rt715-sdca.c +@@ -316,7 +316,7 @@ static int rt715_sdca_set_amp_gain_8ch_get(struct snd_kcontrol *kcontrol, + return 0; + } + +-static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -17625, 375, 0); ++static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -1725, 75, 0); + static const DECLARE_TLV_DB_SCALE(mic_vol_tlv, 0, 1000, 0); + + static int rt715_sdca_get_volsw(struct snd_kcontrol *kcontrol, +@@ -477,7 +477,7 @@ static const struct snd_kcontrol_new rt715_sdca_snd_controls[] = { + RT715_SDCA_FU_VOL_CTRL, CH_01), + SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC7_27_VOL, + RT715_SDCA_FU_VOL_CTRL, CH_02), +- 0x2f, 0x7f, 0, ++ 0x2f, 0x3f, 0, + rt715_sdca_set_amp_gain_get, rt715_sdca_set_amp_gain_put, + in_vol_tlv), + RT715_SDCA_EXT_TLV("FU02 Capture Volume", +@@ -485,13 +485,13 @@ static const struct snd_kcontrol_new rt715_sdca_snd_controls[] = { + RT715_SDCA_FU_VOL_CTRL, CH_01), + rt715_sdca_set_amp_gain_4ch_get, + rt715_sdca_set_amp_gain_4ch_put, +- in_vol_tlv, 4, 0x7f), ++ in_vol_tlv, 4, 0x3f), + RT715_SDCA_EXT_TLV("FU06 Capture Volume", + SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC10_11_VOL, + RT715_SDCA_FU_VOL_CTRL, CH_01), + rt715_sdca_set_amp_gain_4ch_get, + rt715_sdca_set_amp_gain_4ch_put, +- in_vol_tlv, 4, 0x7f), ++ in_vol_tlv, 4, 0x3f), + /* MIC Boost Control */ + RT715_SDCA_BOOST_EXT_TLV("FU0E Boost", + SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN, +diff --git a/sound/soc/codecs/rt715-sdw.c b/sound/soc/codecs/rt715-sdw.c +index 21f37babd148a..376585f5a8dd8 100644 +--- a/sound/soc/codecs/rt715-sdw.c ++++ b/sound/soc/codecs/rt715-sdw.c +@@ -111,6 +111,7 @@ static bool rt715_readable_register(struct device *dev, unsigned int reg) + case 0x839d: + case 0x83a7: + case 0x83a9: ++ case 0x752001: + case 0x752039: + return true; + default: +diff --git a/sound/soc/codecs/rt722-sdca.c b/sound/soc/codecs/rt722-sdca.c +index 0e1c65a20392a..9ff607984ea19 100644 +--- a/sound/soc/codecs/rt722-sdca.c ++++ b/sound/soc/codecs/rt722-sdca.c +@@ -1329,7 +1329,7 @@ static struct snd_soc_dai_driver rt722_sdca_dai[] = { + .capture = { + .stream_name = "DP6 DMic Capture", + .channels_min = 1, +- .channels_max = 2, ++ .channels_max = 4, + .rates = RT722_STEREO_RATES, + .formats = RT722_FORMATS, + }, +@@ -1438,9 +1438,12 @@ static void rt722_sdca_jack_preset(struct rt722_sdca_priv *rt722) + int loop_check, chk_cnt = 100, ret; + unsigned int calib_status = 0; + +- /* Read eFuse */ +- rt722_sdca_index_write(rt722, RT722_VENDOR_SPK_EFUSE, RT722_DC_CALIB_CTRL, +- 0x4808); ++ /* Config analog bias */ ++ rt722_sdca_index_write(rt722, RT722_VENDOR_REG, RT722_ANALOG_BIAS_CTL3, ++ 0xa081); ++ /* GE related settings */ ++ rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL, RT722_GE_RELATED_CTL2, ++ 0xa009); + /* Button A, B, C, D bypass mode */ + rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL, RT722_UMP_HID_CTL4, + 0xcf00); +@@ -1474,9 +1477,6 @@ static void rt722_sdca_jack_preset(struct rt722_sdca_priv *rt722) + if ((calib_status & 0x0040) == 0x0) + break; + } +- /* Release HP-JD, EN_CBJ_TIE_GL/R open, en_osw gating auto done bit */ +- rt722_sdca_index_write(rt722, RT722_VENDOR_REG, RT722_DIGITAL_MISC_CTRL4, +- 0x0010); + /* Set ADC09 power entity floating control */ + rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL, RT722_ADC0A_08_PDE_FLOAT_CTL, + 0x2a12); +@@ -1489,8 +1489,21 @@ static void rt722_sdca_jack_preset(struct rt722_sdca_priv *rt722) + /* Set DAC03 and HP power entity floating control */ + rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL, RT722_DAC03_HP_PDE_FLOAT_CTL, + 0x4040); ++ rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL, RT722_ENT_FLOAT_CTRL_1, ++ 0x4141); ++ rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL, RT722_FLOAT_CTRL_1, ++ 0x0101); + /* Fine tune PDE40 latency */ + regmap_write(rt722->regmap, 0x2f58, 0x07); ++ regmap_write(rt722->regmap, 0x2f03, 0x06); ++ /* MIC VRefo */ ++ rt722_sdca_index_update_bits(rt722, RT722_VENDOR_REG, ++ RT722_COMBO_JACK_AUTO_CTL1, 0x0200, 0x0200); ++ rt722_sdca_index_update_bits(rt722, RT722_VENDOR_REG, ++ RT722_VREFO_GAT, 0x4000, 0x4000); ++ /* Release HP-JD, EN_CBJ_TIE_GL/R open, en_osw gating auto done bit */ ++ rt722_sdca_index_write(rt722, RT722_VENDOR_REG, RT722_DIGITAL_MISC_CTRL4, ++ 0x0010); + } + + int rt722_sdca_io_init(struct device *dev, struct sdw_slave *slave) +diff --git a/sound/soc/codecs/rt722-sdca.h b/sound/soc/codecs/rt722-sdca.h +index 44af8901352eb..2464361a7958c 100644 +--- a/sound/soc/codecs/rt722-sdca.h ++++ b/sound/soc/codecs/rt722-sdca.h +@@ -69,6 +69,7 @@ struct rt722_sdca_dmic_kctrl_priv { + #define RT722_COMBO_JACK_AUTO_CTL2 0x46 + #define RT722_COMBO_JACK_AUTO_CTL3 0x47 + #define RT722_DIGITAL_MISC_CTRL4 0x4a ++#define RT722_VREFO_GAT 0x63 + #define RT722_FSM_CTL 0x67 + #define RT722_SDCA_INTR_REC 0x82 + #define RT722_SW_CONFIG1 0x8a +@@ -127,6 +128,8 @@ struct rt722_sdca_dmic_kctrl_priv { + #define RT722_UMP_HID_CTL6 0x66 + #define RT722_UMP_HID_CTL7 0x67 + #define RT722_UMP_HID_CTL8 0x68 ++#define RT722_FLOAT_CTRL_1 0x70 ++#define RT722_ENT_FLOAT_CTRL_1 0x76 + + /* Parameter & Verb control 01 (0x1a)(NID:20h) */ + #define RT722_HIDDEN_REG_SW_RESET (0x1 << 14) +diff --git a/sound/soc/codecs/tas2552.c b/sound/soc/codecs/tas2552.c +index 8c9dc318b0e82..c65a4219ecd6c 100644 +--- a/sound/soc/codecs/tas2552.c ++++ b/sound/soc/codecs/tas2552.c +@@ -2,7 +2,8 @@ + /* + * tas2552.c - ALSA SoC Texas Instruments TAS2552 Mono Audio Amplifier + * +- * Copyright (C) 2014 Texas Instruments Incorporated - https://www.ti.com ++ * Copyright (C) 2014 - 2024 Texas Instruments Incorporated - ++ * https://www.ti.com + * + * Author: Dan Murphy + */ +@@ -119,12 +120,14 @@ static const struct snd_soc_dapm_widget tas2552_dapm_widgets[] = + &tas2552_input_mux_control), + + SND_SOC_DAPM_AIF_IN("DAC IN", "DAC Playback", 0, SND_SOC_NOPM, 0, 0), ++ SND_SOC_DAPM_AIF_OUT("ASI OUT", "DAC Capture", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_DAC("DAC", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_OUT_DRV("ClassD", TAS2552_CFG_2, 7, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("PLL", TAS2552_CFG_2, 3, 0, NULL, 0), + SND_SOC_DAPM_POST("Post Event", tas2552_post_event), + +- SND_SOC_DAPM_OUTPUT("OUT") ++ SND_SOC_DAPM_OUTPUT("OUT"), ++ SND_SOC_DAPM_INPUT("DMIC") + }; + + static const struct snd_soc_dapm_route tas2552_audio_map[] = { +@@ -134,6 +137,7 @@ static const struct snd_soc_dapm_route tas2552_audio_map[] = { + {"ClassD", NULL, "Input selection"}, + {"OUT", NULL, "ClassD"}, + {"ClassD", NULL, "PLL"}, ++ {"ASI OUT", NULL, "DMIC"} + }; + + #ifdef CONFIG_PM +@@ -538,6 +542,13 @@ static struct snd_soc_dai_driver tas2552_dai[] = { + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = TAS2552_FORMATS, + }, ++ .capture = { ++ .stream_name = "Capture", ++ .channels_min = 2, ++ .channels_max = 2, ++ .rates = SNDRV_PCM_RATE_8000_192000, ++ .formats = TAS2552_FORMATS, ++ }, + .ops = &tas2552_speaker_dai_ops, + }, + }; +diff --git a/sound/soc/codecs/tas2781-fmwlib.c b/sound/soc/codecs/tas2781-fmwlib.c +index 61b05629a9a9c..c6c47297a4fe7 100644 +--- a/sound/soc/codecs/tas2781-fmwlib.c ++++ b/sound/soc/codecs/tas2781-fmwlib.c +@@ -1,8 +1,8 @@ + // SPDX-License-Identifier: GPL-2.0 + // +-// tasdevice-fmw.c -- TASDEVICE firmware support ++// tas2781-fmwlib.c -- TASDEVICE firmware support + // +-// Copyright 2023 Texas Instruments, Inc. ++// Copyright 2023 - 2024 Texas Instruments, Inc. + // + // Author: Shenghao Ding + +@@ -1908,7 +1908,7 @@ int tas2781_load_calibration(void *context, char *file_name, + { + struct tasdevice_priv *tas_priv = (struct tasdevice_priv *)context; + struct tasdevice *tasdev = &(tas_priv->tasdevice[i]); +- const struct firmware *fw_entry; ++ const struct firmware *fw_entry = NULL; + struct tasdevice_fw *tas_fmw; + struct firmware fmw; + int offset = 0; +@@ -2181,6 +2181,24 @@ static int tasdevice_load_data(struct tasdevice_priv *tas_priv, + return ret; + } + ++static void tasdev_load_calibrated_data(struct tasdevice_priv *priv, int i) ++{ ++ struct tasdevice_calibration *cal; ++ struct tasdevice_fw *cal_fmw; ++ ++ cal_fmw = priv->tasdevice[i].cali_data_fmw; ++ ++ /* No calibrated data for current devices, playback will go ahead. */ ++ if (!cal_fmw) ++ return; ++ ++ cal = cal_fmw->calibrations; ++ if (cal) ++ return; ++ ++ load_calib_data(priv, &cal->dev_data); ++} ++ + int tasdevice_select_tuningprm_cfg(void *context, int prm_no, + int cfg_no, int rca_conf_no) + { +@@ -2240,21 +2258,9 @@ int tasdevice_select_tuningprm_cfg(void *context, int prm_no, + for (i = 0; i < tas_priv->ndev; i++) { + if (tas_priv->tasdevice[i].is_loaderr == true) + continue; +- else if (tas_priv->tasdevice[i].is_loaderr == false +- && tas_priv->tasdevice[i].is_loading == true) { +- struct tasdevice_fw *cal_fmw = +- tas_priv->tasdevice[i].cali_data_fmw; +- +- if (cal_fmw) { +- struct tasdevice_calibration +- *cal = cal_fmw->calibrations; +- +- if (cal) +- load_calib_data(tas_priv, +- &(cal->dev_data)); +- } ++ if (tas_priv->tasdevice[i].is_loaderr == false && ++ tas_priv->tasdevice[i].is_loading == true) + tas_priv->tasdevice[i].cur_prog = prm_no; +- } + } + } + +@@ -2275,11 +2281,15 @@ int tasdevice_select_tuningprm_cfg(void *context, int prm_no, + tasdevice_load_data(tas_priv, &(conf->dev_data)); + for (i = 0; i < tas_priv->ndev; i++) { + if (tas_priv->tasdevice[i].is_loaderr == true) { +- status |= 1 << (i + 4); ++ status |= BIT(i + 4); + continue; +- } else if (tas_priv->tasdevice[i].is_loaderr == false +- && tas_priv->tasdevice[i].is_loading == true) ++ } ++ ++ if (tas_priv->tasdevice[i].is_loaderr == false && ++ tas_priv->tasdevice[i].is_loading == true) { ++ tasdev_load_calibrated_data(tas_priv, i); + tas_priv->tasdevice[i].cur_conf = cfg_no; ++ } + } + } else + dev_dbg(tas_priv->dev, "%s: Unneeded loading dsp conf %d\n", +@@ -2338,65 +2348,6 @@ int tasdevice_prmg_load(void *context, int prm_no) + } + EXPORT_SYMBOL_NS_GPL(tasdevice_prmg_load, SND_SOC_TAS2781_FMWLIB); + +-int tasdevice_prmg_calibdata_load(void *context, int prm_no) +-{ +- struct tasdevice_priv *tas_priv = (struct tasdevice_priv *) context; +- struct tasdevice_fw *tas_fmw = tas_priv->fmw; +- struct tasdevice_prog *program; +- int prog_status = 0; +- int i; +- +- if (!tas_fmw) { +- dev_err(tas_priv->dev, "%s: Firmware is NULL\n", __func__); +- goto out; +- } +- +- if (prm_no >= tas_fmw->nr_programs) { +- dev_err(tas_priv->dev, +- "%s: prm(%d) is not in range of Programs %u\n", +- __func__, prm_no, tas_fmw->nr_programs); +- goto out; +- } +- +- for (i = 0, prog_status = 0; i < tas_priv->ndev; i++) { +- if (prm_no >= 0 && tas_priv->tasdevice[i].cur_prog != prm_no) { +- tas_priv->tasdevice[i].cur_conf = -1; +- tas_priv->tasdevice[i].is_loading = true; +- prog_status++; +- } +- tas_priv->tasdevice[i].is_loaderr = false; +- } +- +- if (prog_status) { +- program = &(tas_fmw->programs[prm_no]); +- tasdevice_load_data(tas_priv, &(program->dev_data)); +- for (i = 0; i < tas_priv->ndev; i++) { +- if (tas_priv->tasdevice[i].is_loaderr == true) +- continue; +- else if (tas_priv->tasdevice[i].is_loaderr == false +- && tas_priv->tasdevice[i].is_loading == true) { +- struct tasdevice_fw *cal_fmw = +- tas_priv->tasdevice[i].cali_data_fmw; +- +- if (cal_fmw) { +- struct tasdevice_calibration *cal = +- cal_fmw->calibrations; +- +- if (cal) +- load_calib_data(tas_priv, +- &(cal->dev_data)); +- } +- tas_priv->tasdevice[i].cur_prog = prm_no; +- } +- } +- } +- +-out: +- return prog_status; +-} +-EXPORT_SYMBOL_NS_GPL(tasdevice_prmg_calibdata_load, +- SND_SOC_TAS2781_FMWLIB); +- + void tasdevice_tuning_switch(void *context, int state) + { + struct tasdevice_priv *tas_priv = (struct tasdevice_priv *) context; +diff --git a/sound/soc/codecs/tas2781-i2c.c b/sound/soc/codecs/tas2781-i2c.c +index 2f7f8b18c36fa..7327e9dcc8c02 100644 +--- a/sound/soc/codecs/tas2781-i2c.c ++++ b/sound/soc/codecs/tas2781-i2c.c +@@ -2,7 +2,7 @@ + // + // ALSA SoC Texas Instruments TAS2781 Audio Smart Amplifier + // +-// Copyright (C) 2022 - 2023 Texas Instruments Incorporated ++// Copyright (C) 2022 - 2024 Texas Instruments Incorporated + // https://www.ti.com + // + // The TAS2781 driver implements a flexible and configurable +@@ -412,7 +412,7 @@ static void tasdevice_fw_ready(const struct firmware *fmw, + __func__, tas_priv->cal_binaryname[i]); + } + +- tasdevice_prmg_calibdata_load(tas_priv, 0); ++ tasdevice_prmg_load(tas_priv, 0); + tas_priv->cur_prog = 0; + out: + if (tas_priv->fw_state == TASDEVICE_DSP_FW_FAIL) { +diff --git a/sound/soc/intel/avs/boards/ssm4567.c b/sound/soc/intel/avs/boards/ssm4567.c +index 7324869d61327..7db1b89b0d9e9 100644 +--- a/sound/soc/intel/avs/boards/ssm4567.c ++++ b/sound/soc/intel/avs/boards/ssm4567.c +@@ -166,7 +166,6 @@ static int avs_ssm4567_probe(struct platform_device *pdev) + card->dapm_routes = card_base_routes; + card->num_dapm_routes = ARRAY_SIZE(card_base_routes); + card->fully_routed = true; +- card->disable_route_checks = true; + + ret = snd_soc_fixup_dai_links_platform_name(card, pname); + if (ret) +diff --git a/sound/soc/intel/avs/cldma.c b/sound/soc/intel/avs/cldma.c +index d7a9390b5e483..585579840b646 100644 +--- a/sound/soc/intel/avs/cldma.c ++++ b/sound/soc/intel/avs/cldma.c +@@ -35,7 +35,7 @@ struct hda_cldma { + + unsigned int buffer_size; + unsigned int num_periods; +- unsigned int stream_tag; ++ unsigned char stream_tag; + void __iomem *sd_addr; + + struct snd_dma_buffer dmab_data; +diff --git a/sound/soc/intel/avs/path.c b/sound/soc/intel/avs/path.c +index adbe23a47847b..a4b9e209f2230 100644 +--- a/sound/soc/intel/avs/path.c ++++ b/sound/soc/intel/avs/path.c +@@ -368,6 +368,7 @@ static int avs_asrc_create(struct avs_dev *adev, struct avs_path_module *mod) + struct avs_tplg_module *t = mod->template; + struct avs_asrc_cfg cfg; + ++ memset(&cfg, 0, sizeof(cfg)); + cfg.base.cpc = t->cfg_base->cpc; + cfg.base.ibs = t->cfg_base->ibs; + cfg.base.obs = t->cfg_base->obs; +diff --git a/sound/soc/intel/avs/probes.c b/sound/soc/intel/avs/probes.c +index 4cab8c6c45766..341773ec49072 100644 +--- a/sound/soc/intel/avs/probes.c ++++ b/sound/soc/intel/avs/probes.c +@@ -19,8 +19,11 @@ static int avs_dsp_init_probe(struct avs_dev *adev, union avs_connector_node_id + struct avs_probe_cfg cfg = {{0}}; + struct avs_module_entry mentry; + u8 dummy; ++ int ret; + +- avs_get_module_entry(adev, &AVS_PROBE_MOD_UUID, &mentry); ++ ret = avs_get_module_entry(adev, &AVS_PROBE_MOD_UUID, &mentry); ++ if (ret) ++ return ret; + + /* + * Probe module uses no cycles, audio data format and input and output +@@ -39,11 +42,12 @@ static int avs_dsp_init_probe(struct avs_dev *adev, union avs_connector_node_id + static void avs_dsp_delete_probe(struct avs_dev *adev) + { + struct avs_module_entry mentry; ++ int ret; + +- avs_get_module_entry(adev, &AVS_PROBE_MOD_UUID, &mentry); +- +- /* There is only ever one probe module instance. */ +- avs_dsp_delete_module(adev, mentry.module_id, 0, INVALID_PIPELINE_ID, 0); ++ ret = avs_get_module_entry(adev, &AVS_PROBE_MOD_UUID, &mentry); ++ if (!ret) ++ /* There is only ever one probe module instance. */ ++ avs_dsp_delete_module(adev, mentry.module_id, 0, INVALID_PIPELINE_ID, 0); + } + + static inline struct hdac_ext_stream *avs_compr_get_host_stream(struct snd_compr_stream *cstream) +diff --git a/sound/soc/intel/boards/bxt_da7219_max98357a.c b/sound/soc/intel/boards/bxt_da7219_max98357a.c +index cbfff466c5c86..b6e6601b30c21 100644 +--- a/sound/soc/intel/boards/bxt_da7219_max98357a.c ++++ b/sound/soc/intel/boards/bxt_da7219_max98357a.c +@@ -768,6 +768,7 @@ static struct snd_soc_card broxton_audio_card = { + .dapm_routes = audio_map, + .num_dapm_routes = ARRAY_SIZE(audio_map), + .fully_routed = true, ++ .disable_route_checks = true, + .late_probe = bxt_card_late_probe, + }; + +diff --git a/sound/soc/intel/boards/bxt_rt298.c b/sound/soc/intel/boards/bxt_rt298.c +index bf89fe80423d0..4275c40e8114d 100644 +--- a/sound/soc/intel/boards/bxt_rt298.c ++++ b/sound/soc/intel/boards/bxt_rt298.c +@@ -574,6 +574,7 @@ static struct snd_soc_card broxton_rt298 = { + .dapm_routes = broxton_rt298_map, + .num_dapm_routes = ARRAY_SIZE(broxton_rt298_map), + .fully_routed = true, ++ .disable_route_checks = true, + .late_probe = bxt_card_late_probe, + + }; +diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c +index e609249cc38d5..651408c6f399d 100644 +--- a/sound/soc/intel/boards/bytcr_rt5640.c ++++ b/sound/soc/intel/boards/bytcr_rt5640.c +@@ -636,28 +636,30 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = { + BYT_RT5640_USE_AMCR0F28), + }, + { ++ /* Asus T100TAF, unlike other T100TA* models this one has a mono speaker */ + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), +- DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T100TA"), ++ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T100TAF"), + }, + .driver_data = (void *)(BYT_RT5640_IN1_MAP | + BYT_RT5640_JD_SRC_JD2_IN4N | + BYT_RT5640_OVCD_TH_2000UA | + BYT_RT5640_OVCD_SF_0P75 | ++ BYT_RT5640_MONO_SPEAKER | ++ BYT_RT5640_DIFF_MIC | ++ BYT_RT5640_SSP0_AIF2 | + BYT_RT5640_MCLK_EN), + }, + { ++ /* Asus T100TA and T100TAM, must come after T100TAF (mono spk) match */ + .matches = { +- DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), +- DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T100TAF"), ++ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), ++ DMI_MATCH(DMI_PRODUCT_NAME, "T100TA"), + }, + .driver_data = (void *)(BYT_RT5640_IN1_MAP | + BYT_RT5640_JD_SRC_JD2_IN4N | + BYT_RT5640_OVCD_TH_2000UA | + BYT_RT5640_OVCD_SF_0P75 | +- BYT_RT5640_MONO_SPEAKER | +- BYT_RT5640_DIFF_MIC | +- BYT_RT5640_SSP0_AIF2 | + BYT_RT5640_MCLK_EN), + }, + { +diff --git a/sound/soc/intel/boards/glk_rt5682_max98357a.c b/sound/soc/intel/boards/glk_rt5682_max98357a.c +index cf0f89db3e204..0f9bbb970b230 100644 +--- a/sound/soc/intel/boards/glk_rt5682_max98357a.c ++++ b/sound/soc/intel/boards/glk_rt5682_max98357a.c +@@ -649,6 +649,8 @@ static int geminilake_audio_probe(struct platform_device *pdev) + card = &glk_audio_card_rt5682_m98357a; + card->dev = &pdev->dev; + snd_soc_card_set_drvdata(card, ctx); ++ if (!snd_soc_acpi_sof_parent(&pdev->dev)) ++ card->disable_route_checks = true; + + /* override platform name, if required */ + mach = pdev->dev.platform_data; +diff --git a/sound/soc/intel/boards/kbl_da7219_max98357a.c b/sound/soc/intel/boards/kbl_da7219_max98357a.c +index 97149513076f9..a7868e5735bcb 100644 +--- a/sound/soc/intel/boards/kbl_da7219_max98357a.c ++++ b/sound/soc/intel/boards/kbl_da7219_max98357a.c +@@ -639,6 +639,7 @@ static struct snd_soc_card kabylake_audio_card_da7219_m98357a = { + .dapm_routes = kabylake_map, + .num_dapm_routes = ARRAY_SIZE(kabylake_map), + .fully_routed = true, ++ .disable_route_checks = true, + .late_probe = kabylake_card_late_probe, + }; + +diff --git a/sound/soc/intel/boards/kbl_da7219_max98927.c b/sound/soc/intel/boards/kbl_da7219_max98927.c +index a1f8234c77bd2..2e75070eb9216 100644 +--- a/sound/soc/intel/boards/kbl_da7219_max98927.c ++++ b/sound/soc/intel/boards/kbl_da7219_max98927.c +@@ -1036,6 +1036,7 @@ static struct snd_soc_card kbl_audio_card_da7219_m98927 = { + .codec_conf = max98927_codec_conf, + .num_configs = ARRAY_SIZE(max98927_codec_conf), + .fully_routed = true, ++ .disable_route_checks = true, + .late_probe = kabylake_card_late_probe, + }; + +@@ -1054,6 +1055,7 @@ static struct snd_soc_card kbl_audio_card_max98927 = { + .codec_conf = max98927_codec_conf, + .num_configs = ARRAY_SIZE(max98927_codec_conf), + .fully_routed = true, ++ .disable_route_checks = true, + .late_probe = kabylake_card_late_probe, + }; + +@@ -1071,6 +1073,7 @@ static struct snd_soc_card kbl_audio_card_da7219_m98373 = { + .codec_conf = max98373_codec_conf, + .num_configs = ARRAY_SIZE(max98373_codec_conf), + .fully_routed = true, ++ .disable_route_checks = true, + .late_probe = kabylake_card_late_probe, + }; + +@@ -1088,6 +1091,7 @@ static struct snd_soc_card kbl_audio_card_max98373 = { + .codec_conf = max98373_codec_conf, + .num_configs = ARRAY_SIZE(max98373_codec_conf), + .fully_routed = true, ++ .disable_route_checks = true, + .late_probe = kabylake_card_late_probe, + }; + +diff --git a/sound/soc/intel/boards/kbl_rt5660.c b/sound/soc/intel/boards/kbl_rt5660.c +index 2c7a547f63c90..358d606228121 100644 +--- a/sound/soc/intel/boards/kbl_rt5660.c ++++ b/sound/soc/intel/boards/kbl_rt5660.c +@@ -518,6 +518,7 @@ static struct snd_soc_card kabylake_audio_card_rt5660 = { + .dapm_routes = kabylake_rt5660_map, + .num_dapm_routes = ARRAY_SIZE(kabylake_rt5660_map), + .fully_routed = true, ++ .disable_route_checks = true, + .late_probe = kabylake_card_late_probe, + }; + +diff --git a/sound/soc/intel/boards/kbl_rt5663_max98927.c b/sound/soc/intel/boards/kbl_rt5663_max98927.c +index 2d4224c5b1520..d110ebd10bca2 100644 +--- a/sound/soc/intel/boards/kbl_rt5663_max98927.c ++++ b/sound/soc/intel/boards/kbl_rt5663_max98927.c +@@ -966,6 +966,7 @@ static struct snd_soc_card kabylake_audio_card_rt5663_m98927 = { + .codec_conf = max98927_codec_conf, + .num_configs = ARRAY_SIZE(max98927_codec_conf), + .fully_routed = true, ++ .disable_route_checks = true, + .late_probe = kabylake_card_late_probe, + }; + +@@ -982,6 +983,7 @@ static struct snd_soc_card kabylake_audio_card_rt5663 = { + .dapm_routes = kabylake_5663_map, + .num_dapm_routes = ARRAY_SIZE(kabylake_5663_map), + .fully_routed = true, ++ .disable_route_checks = true, + .late_probe = kabylake_card_late_probe, + }; + +diff --git a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c +index 2c79fca57b19e..a15d2c30b6c46 100644 +--- a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c ++++ b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c +@@ -791,6 +791,7 @@ static struct snd_soc_card kabylake_audio_card = { + .codec_conf = max98927_codec_conf, + .num_configs = ARRAY_SIZE(max98927_codec_conf), + .fully_routed = true, ++ .disable_route_checks = true, + .late_probe = kabylake_card_late_probe, + }; + +diff --git a/sound/soc/intel/boards/skl_hda_dsp_generic.c b/sound/soc/intel/boards/skl_hda_dsp_generic.c +index 70c806cc5b2ee..da6079c61f88d 100644 +--- a/sound/soc/intel/boards/skl_hda_dsp_generic.c ++++ b/sound/soc/intel/boards/skl_hda_dsp_generic.c +@@ -227,6 +227,8 @@ static int skl_hda_audio_probe(struct platform_device *pdev) + ctx->common_hdmi_codec_drv = mach->mach_params.common_hdmi_codec_drv; + + hda_soc_card.dev = &pdev->dev; ++ if (!snd_soc_acpi_sof_parent(&pdev->dev)) ++ hda_soc_card.disable_route_checks = true; + + if (mach->mach_params.dmic_num > 0) { + snprintf(hda_soc_components, sizeof(hda_soc_components), +diff --git a/sound/soc/intel/boards/skl_nau88l25_max98357a.c b/sound/soc/intel/boards/skl_nau88l25_max98357a.c +index e13a5a4d8f7e9..2d424e3e2abd8 100644 +--- a/sound/soc/intel/boards/skl_nau88l25_max98357a.c ++++ b/sound/soc/intel/boards/skl_nau88l25_max98357a.c +@@ -654,6 +654,7 @@ static struct snd_soc_card skylake_audio_card = { + .dapm_routes = skylake_map, + .num_dapm_routes = ARRAY_SIZE(skylake_map), + .fully_routed = true, ++ .disable_route_checks = true, + .late_probe = skylake_card_late_probe, + }; + +diff --git a/sound/soc/intel/boards/skl_rt286.c b/sound/soc/intel/boards/skl_rt286.c +index 4f3d655e2bfa8..0a4795a94a768 100644 +--- a/sound/soc/intel/boards/skl_rt286.c ++++ b/sound/soc/intel/boards/skl_rt286.c +@@ -523,6 +523,7 @@ static struct snd_soc_card skylake_rt286 = { + .dapm_routes = skylake_rt286_map, + .num_dapm_routes = ARRAY_SIZE(skylake_rt286_map), + .fully_routed = true, ++ .disable_route_checks = true, + .late_probe = skylake_card_late_probe, + }; + +diff --git a/sound/soc/intel/common/Makefile b/sound/soc/intel/common/Makefile +index 07aa37dd90e99..f7370e5b4e9e4 100644 +--- a/sound/soc/intel/common/Makefile ++++ b/sound/soc/intel/common/Makefile +@@ -10,6 +10,7 @@ snd-soc-acpi-intel-match-objs := soc-acpi-intel-byt-match.o soc-acpi-intel-cht-m + soc-acpi-intel-tgl-match.o soc-acpi-intel-ehl-match.o \ + soc-acpi-intel-jsl-match.o soc-acpi-intel-adl-match.o \ + soc-acpi-intel-rpl-match.o soc-acpi-intel-mtl-match.o \ ++ soc-acpi-intel-arl-match.o \ + soc-acpi-intel-lnl-match.o \ + soc-acpi-intel-hda-match.o \ + soc-acpi-intel-sdw-mockup-match.o +diff --git a/sound/soc/intel/common/soc-acpi-intel-arl-match.c b/sound/soc/intel/common/soc-acpi-intel-arl-match.c +new file mode 100644 +index 0000000000000..e52797aae6e65 +--- /dev/null ++++ b/sound/soc/intel/common/soc-acpi-intel-arl-match.c +@@ -0,0 +1,51 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * soc-apci-intel-arl-match.c - tables and support for ARL ACPI enumeration. ++ * ++ * Copyright (c) 2023 Intel Corporation. ++ */ ++ ++#include ++#include ++ ++static const struct snd_soc_acpi_endpoint single_endpoint = { ++ .num = 0, ++ .aggregated = 0, ++ .group_position = 0, ++ .group_id = 0, ++}; ++ ++static const struct snd_soc_acpi_adr_device rt711_0_adr[] = { ++ { ++ .adr = 0x000020025D071100ull, ++ .num_endpoints = 1, ++ .endpoints = &single_endpoint, ++ .name_prefix = "rt711" ++ } ++}; ++ ++static const struct snd_soc_acpi_link_adr arl_rvp[] = { ++ { ++ .mask = BIT(0), ++ .num_adr = ARRAY_SIZE(rt711_0_adr), ++ .adr_d = rt711_0_adr, ++ }, ++ {} ++}; ++ ++struct snd_soc_acpi_mach snd_soc_acpi_intel_arl_machines[] = { ++ {}, ++}; ++EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_arl_machines); ++ ++/* this table is used when there is no I2S codec present */ ++struct snd_soc_acpi_mach snd_soc_acpi_intel_arl_sdw_machines[] = { ++ { ++ .link_mask = 0x1, /* link0 required */ ++ .links = arl_rvp, ++ .drv_name = "sof_sdw", ++ .sof_tplg_filename = "sof-arl-rt711.tplg", ++ }, ++ {}, ++}; ++EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_arl_sdw_machines); +diff --git a/sound/soc/kirkwood/kirkwood-dma.c b/sound/soc/kirkwood/kirkwood-dma.c +index 640cebd2983e2..16d2c9acc33a6 100644 +--- a/sound/soc/kirkwood/kirkwood-dma.c ++++ b/sound/soc/kirkwood/kirkwood-dma.c +@@ -182,6 +182,9 @@ static int kirkwood_dma_hw_params(struct snd_soc_component *component, + const struct mbus_dram_target_info *dram = mv_mbus_dram_info(); + unsigned long addr = substream->runtime->dma_addr; + ++ if (!dram) ++ return 0; ++ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + kirkwood_dma_conf_mbus_windows(priv->io, + KIRKWOOD_PLAYBACK_WIN, addr, dram); +diff --git a/sound/soc/mediatek/common/mtk-soundcard-driver.c b/sound/soc/mediatek/common/mtk-soundcard-driver.c +index a58e1e3674dec..000a086a8cf44 100644 +--- a/sound/soc/mediatek/common/mtk-soundcard-driver.c ++++ b/sound/soc/mediatek/common/mtk-soundcard-driver.c +@@ -22,7 +22,11 @@ static int set_card_codec_info(struct snd_soc_card *card, + + codec_node = of_get_child_by_name(sub_node, "codec"); + if (!codec_node) { +- dev_dbg(dev, "%s no specified codec\n", dai_link->name); ++ dev_dbg(dev, "%s no specified codec: setting dummy.\n", dai_link->name); ++ ++ dai_link->codecs = &snd_soc_dummy_dlc; ++ dai_link->num_codecs = 1; ++ dai_link->dynamic = 1; + return 0; + } + +diff --git a/sound/soc/mediatek/mt8192/mt8192-dai-tdm.c b/sound/soc/mediatek/mt8192/mt8192-dai-tdm.c +index 9ce06821c7d0f..49440db370af0 100644 +--- a/sound/soc/mediatek/mt8192/mt8192-dai-tdm.c ++++ b/sound/soc/mediatek/mt8192/mt8192-dai-tdm.c +@@ -566,10 +566,10 @@ static int mtk_dai_tdm_hw_params(struct snd_pcm_substream *substream, + tdm_con |= 1 << DELAY_DATA_SFT; + tdm_con |= get_tdm_lrck_width(format) << LRCK_TDM_WIDTH_SFT; + } else if (tdm_priv->tdm_out_mode == TDM_OUT_DSP_A) { +- tdm_con |= 0 << DELAY_DATA_SFT; ++ tdm_con |= 1 << DELAY_DATA_SFT; + tdm_con |= 0 << LRCK_TDM_WIDTH_SFT; + } else if (tdm_priv->tdm_out_mode == TDM_OUT_DSP_B) { +- tdm_con |= 1 << DELAY_DATA_SFT; ++ tdm_con |= 0 << DELAY_DATA_SFT; + tdm_con |= 0 << LRCK_TDM_WIDTH_SFT; + } + +diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h +index 5c517ec57d4a2..0f0cfd0f85a3f 100644 +--- a/sound/soc/sof/intel/hda.h ++++ b/sound/soc/sof/intel/hda.h +@@ -876,6 +876,7 @@ extern const struct sof_intel_dsp_desc ehl_chip_info; + extern const struct sof_intel_dsp_desc jsl_chip_info; + extern const struct sof_intel_dsp_desc adls_chip_info; + extern const struct sof_intel_dsp_desc mtl_chip_info; ++extern const struct sof_intel_dsp_desc arl_s_chip_info; + extern const struct sof_intel_dsp_desc lnl_chip_info; + + /* Probes support */ +diff --git a/sound/soc/sof/intel/lnl.c b/sound/soc/sof/intel/lnl.c +index db94b45e53af8..822f857723208 100644 +--- a/sound/soc/sof/intel/lnl.c ++++ b/sound/soc/sof/intel/lnl.c +@@ -16,6 +16,7 @@ + #include "hda-ipc.h" + #include "../sof-audio.h" + #include "mtl.h" ++#include "lnl.h" + #include + + /* LunarLake ops */ +@@ -172,7 +173,7 @@ const struct sof_intel_dsp_desc lnl_chip_info = { + .ipc_ack = MTL_DSP_REG_HFIPCXIDA, + .ipc_ack_mask = MTL_DSP_REG_HFIPCXIDA_DONE, + .ipc_ctl = MTL_DSP_REG_HFIPCXCTL, +- .rom_status_reg = MTL_DSP_ROM_STS, ++ .rom_status_reg = LNL_DSP_REG_HFDSC, + .rom_init_timeout = 300, + .ssp_count = MTL_SSP_COUNT, + .d0i3_offset = MTL_HDA_VS_D0I3C, +diff --git a/sound/soc/sof/intel/lnl.h b/sound/soc/sof/intel/lnl.h +new file mode 100644 +index 0000000000000..4f4734fe7e089 +--- /dev/null ++++ b/sound/soc/sof/intel/lnl.h +@@ -0,0 +1,15 @@ ++/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */ ++/* ++ * This file is provided under a dual BSD/GPLv2 license. When using or ++ * redistributing this file, you may do so under either license. ++ * ++ * Copyright(c) 2024 Intel Corporation. All rights reserved. ++ */ ++ ++#ifndef __SOF_INTEL_LNL_H ++#define __SOF_INTEL_LNL_H ++ ++#define LNL_DSP_REG_HFDSC 0x160200 /* DSP core0 status */ ++#define LNL_DSP_REG_HFDEC 0x160204 /* DSP core0 error */ ++ ++#endif /* __SOF_INTEL_LNL_H */ +diff --git a/sound/soc/sof/intel/mtl.c b/sound/soc/sof/intel/mtl.c +index f9412517eaf29..7d7a017c2e1f7 100644 +--- a/sound/soc/sof/intel/mtl.c ++++ b/sound/soc/sof/intel/mtl.c +@@ -436,8 +436,9 @@ int mtl_dsp_cl_init(struct snd_sof_dev *sdev, int stream_tag, bool imr_boot) + { + struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; + const struct sof_intel_dsp_desc *chip = hda->desc; +- unsigned int status; +- u32 ipc_hdr; ++ unsigned int status, target_status; ++ u32 ipc_hdr, flags; ++ char *dump_msg; + int ret; + + /* step 1: purge FW request */ +@@ -481,17 +482,55 @@ int mtl_dsp_cl_init(struct snd_sof_dev *sdev, int stream_tag, bool imr_boot) + + mtl_enable_ipc_interrupts(sdev); + ++ if (chip->rom_status_reg == MTL_DSP_ROM_STS) { ++ /* ++ * Workaround: when the ROM status register is pointing to ++ * the SRAM window (MTL_DSP_ROM_STS) the platform cannot catch ++ * ROM_INIT_DONE because of a very short timing window. ++ * Follow the recommendations and skip target state waiting. ++ */ ++ return 0; ++ } ++ + /* +- * ACE workaround: don't wait for ROM INIT. +- * The platform cannot catch ROM_INIT_DONE because of a very short +- * timing window. Follow the recommendations and skip this part. ++ * step 7: ++ * - Cold/Full boot: wait for ROM init to proceed to download the firmware ++ * - IMR boot: wait for ROM firmware entered (firmware booted up from IMR) + */ ++ if (imr_boot) ++ target_status = FSR_STATE_FW_ENTERED; ++ else ++ target_status = FSR_STATE_INIT_DONE; + +- return 0; ++ ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, ++ chip->rom_status_reg, status, ++ (FSR_TO_STATE_CODE(status) == target_status), ++ HDA_DSP_REG_POLL_INTERVAL_US, ++ chip->rom_init_timeout * ++ USEC_PER_MSEC); ++ ++ if (!ret) ++ return 0; ++ ++ if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS) ++ dev_err(sdev->dev, ++ "%s: timeout with rom_status_reg (%#x) read\n", ++ __func__, chip->rom_status_reg); + + err: +- snd_sof_dsp_dbg_dump(sdev, "MTL DSP init fail", 0); ++ flags = SOF_DBG_DUMP_PCI | SOF_DBG_DUMP_MBOX | SOF_DBG_DUMP_OPTIONAL; ++ ++ /* after max boot attempts make sure that the dump is printed */ ++ if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS) ++ flags &= ~SOF_DBG_DUMP_OPTIONAL; ++ ++ dump_msg = kasprintf(GFP_KERNEL, "Boot iteration failed: %d/%d", ++ hda->boot_iteration, HDA_FW_BOOT_ATTEMPTS); ++ snd_sof_dsp_dbg_dump(sdev, dump_msg, flags); ++ mtl_enable_interrupts(sdev, false); + mtl_dsp_core_power_down(sdev, SOF_DSP_PRIMARY_CORE); ++ ++ kfree(dump_msg); + return ret; + } + +@@ -725,7 +764,7 @@ const struct sof_intel_dsp_desc mtl_chip_info = { + .ipc_ack = MTL_DSP_REG_HFIPCXIDA, + .ipc_ack_mask = MTL_DSP_REG_HFIPCXIDA_DONE, + .ipc_ctl = MTL_DSP_REG_HFIPCXCTL, +- .rom_status_reg = MTL_DSP_ROM_STS, ++ .rom_status_reg = MTL_DSP_REG_HFFLGPXQWY, + .rom_init_timeout = 300, + .ssp_count = MTL_SSP_COUNT, + .ssp_base_offset = CNL_SSP_BASE_OFFSET, +@@ -743,3 +782,31 @@ const struct sof_intel_dsp_desc mtl_chip_info = { + .hw_ip_version = SOF_INTEL_ACE_1_0, + }; + EXPORT_SYMBOL_NS(mtl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON); ++ ++const struct sof_intel_dsp_desc arl_s_chip_info = { ++ .cores_num = 2, ++ .init_core_mask = BIT(0), ++ .host_managed_cores_mask = BIT(0), ++ .ipc_req = MTL_DSP_REG_HFIPCXIDR, ++ .ipc_req_mask = MTL_DSP_REG_HFIPCXIDR_BUSY, ++ .ipc_ack = MTL_DSP_REG_HFIPCXIDA, ++ .ipc_ack_mask = MTL_DSP_REG_HFIPCXIDA_DONE, ++ .ipc_ctl = MTL_DSP_REG_HFIPCXCTL, ++ .rom_status_reg = MTL_DSP_REG_HFFLGPXQWY, ++ .rom_init_timeout = 300, ++ .ssp_count = MTL_SSP_COUNT, ++ .ssp_base_offset = CNL_SSP_BASE_OFFSET, ++ .sdw_shim_base = SDW_SHIM_BASE_ACE, ++ .sdw_alh_base = SDW_ALH_BASE_ACE, ++ .d0i3_offset = MTL_HDA_VS_D0I3C, ++ .read_sdw_lcount = hda_sdw_check_lcount_common, ++ .enable_sdw_irq = mtl_enable_sdw_irq, ++ .check_sdw_irq = mtl_dsp_check_sdw_irq, ++ .check_sdw_wakeen_irq = hda_sdw_check_wakeen_irq_common, ++ .check_ipc_irq = mtl_dsp_check_ipc_irq, ++ .cl_init = mtl_dsp_cl_init, ++ .power_down_dsp = mtl_power_down_dsp, ++ .disable_interrupts = mtl_dsp_disable_interrupts, ++ .hw_ip_version = SOF_INTEL_ACE_1_0, ++}; ++EXPORT_SYMBOL_NS(arl_s_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON); +diff --git a/sound/soc/sof/intel/mtl.h b/sound/soc/sof/intel/mtl.h +index 95696b3d7c4cf..fab28d5f68915 100644 +--- a/sound/soc/sof/intel/mtl.h ++++ b/sound/soc/sof/intel/mtl.h +@@ -76,8 +76,8 @@ + #define MTL_DSP_ROM_STS MTL_SRAM_WINDOW_OFFSET(0) /* ROM status */ + #define MTL_DSP_ROM_ERROR (MTL_SRAM_WINDOW_OFFSET(0) + 0x4) /* ROM error code */ + +-#define MTL_DSP_REG_HFFLGPXQWY 0x163200 /* ROM debug status */ +-#define MTL_DSP_REG_HFFLGPXQWY_ERROR 0x163204 /* ROM debug error code */ ++#define MTL_DSP_REG_HFFLGPXQWY 0x163200 /* DSP core0 status */ ++#define MTL_DSP_REG_HFFLGPXQWY_ERROR 0x163204 /* DSP core0 error */ + #define MTL_DSP_REG_HfIMRIS1 0x162088 + #define MTL_DSP_REG_HfIMRIS1_IU_MASK BIT(0) + +diff --git a/sound/soc/sof/intel/pci-mtl.c b/sound/soc/sof/intel/pci-mtl.c +index 7868b0827e844..7d00e469f58ce 100644 +--- a/sound/soc/sof/intel/pci-mtl.c ++++ b/sound/soc/sof/intel/pci-mtl.c +@@ -50,9 +50,40 @@ static const struct sof_dev_desc mtl_desc = { + .ops_free = hda_ops_free, + }; + ++static const struct sof_dev_desc arl_s_desc = { ++ .use_acpi_target_states = true, ++ .machines = snd_soc_acpi_intel_arl_machines, ++ .alt_machines = snd_soc_acpi_intel_arl_sdw_machines, ++ .resindex_lpe_base = 0, ++ .resindex_pcicfg_base = -1, ++ .resindex_imr_base = -1, ++ .irqindex_host_ipc = -1, ++ .chip_info = &arl_s_chip_info, ++ .ipc_supported_mask = BIT(SOF_IPC_TYPE_4), ++ .ipc_default = SOF_IPC_TYPE_4, ++ .dspless_mode_supported = true, /* Only supported for HDaudio */ ++ .default_fw_path = { ++ [SOF_IPC_TYPE_4] = "intel/sof-ipc4/arl-s", ++ }, ++ .default_lib_path = { ++ [SOF_IPC_TYPE_4] = "intel/sof-ipc4-lib/arl-s", ++ }, ++ .default_tplg_path = { ++ [SOF_IPC_TYPE_4] = "intel/sof-ace-tplg", ++ }, ++ .default_fw_filename = { ++ [SOF_IPC_TYPE_4] = "sof-arl-s.ri", ++ }, ++ .nocodec_tplg_filename = "sof-arl-nocodec.tplg", ++ .ops = &sof_mtl_ops, ++ .ops_init = sof_mtl_ops_init, ++ .ops_free = hda_ops_free, ++}; ++ + /* PCI IDs */ + static const struct pci_device_id sof_pci_ids[] = { + { PCI_DEVICE_DATA(INTEL, HDA_MTL, &mtl_desc) }, ++ { PCI_DEVICE_DATA(INTEL, HDA_ARL_S, &arl_s_desc) }, + { 0, } + }; + MODULE_DEVICE_TABLE(pci, sof_pci_ids); +diff --git a/sound/soc/sof/ipc3-pcm.c b/sound/soc/sof/ipc3-pcm.c +index cb58ee8c158a5..720bd9bd2667a 100644 +--- a/sound/soc/sof/ipc3-pcm.c ++++ b/sound/soc/sof/ipc3-pcm.c +@@ -398,4 +398,5 @@ const struct sof_ipc_pcm_ops ipc3_pcm_ops = { + .trigger = sof_ipc3_pcm_trigger, + .dai_link_fixup = sof_ipc3_pcm_dai_link_fixup, + .reset_hw_params_during_stop = true, ++ .d0i3_supported_in_s0ix = true, + }; +diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c +index d778717cab10b..8e602e42afee2 100644 +--- a/sound/soc/sof/pcm.c ++++ b/sound/soc/sof/pcm.c +@@ -325,14 +325,13 @@ static int sof_pcm_trigger(struct snd_soc_component *component, + ipc_first = true; + break; + case SNDRV_PCM_TRIGGER_SUSPEND: +- if (sdev->system_suspend_target == SOF_SUSPEND_S0IX && ++ /* ++ * If DSP D0I3 is allowed during S0iX, set the suspend_ignored flag for ++ * D0I3-compatible streams to keep the firmware pipeline running ++ */ ++ if (pcm_ops && pcm_ops->d0i3_supported_in_s0ix && ++ sdev->system_suspend_target == SOF_SUSPEND_S0IX && + spcm->stream[substream->stream].d0i3_compatible) { +- /* +- * trap the event, not sending trigger stop to +- * prevent the FW pipelines from being stopped, +- * and mark the flag to ignore the upcoming DAPM +- * PM events. +- */ + spcm->stream[substream->stream].suspend_ignored = true; + return 0; + } +diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h +index a6d6bcd00ceec..3606595a7500c 100644 +--- a/sound/soc/sof/sof-audio.h ++++ b/sound/soc/sof/sof-audio.h +@@ -113,6 +113,7 @@ struct snd_sof_dai_config_data { + * triggers. The FW keeps the host DMA running in this case and + * therefore the host must do the same and should stop the DMA during + * hw_free. ++ * @d0i3_supported_in_s0ix: Allow DSP D0I3 during S0iX + */ + struct sof_ipc_pcm_ops { + int (*hw_params)(struct snd_soc_component *component, struct snd_pcm_substream *substream, +@@ -129,6 +130,7 @@ struct sof_ipc_pcm_ops { + bool reset_hw_params_during_stop; + bool ipc_first_on_start; + bool platform_stop_during_hw_free; ++ bool d0i3_supported_in_s0ix; + }; + + /** +diff --git a/tools/arch/x86/intel_sdsi/intel_sdsi.c b/tools/arch/x86/intel_sdsi/intel_sdsi.c +index 2cd92761f1714..ba2a6b6645ae8 100644 +--- a/tools/arch/x86/intel_sdsi/intel_sdsi.c ++++ b/tools/arch/x86/intel_sdsi/intel_sdsi.c +@@ -43,7 +43,6 @@ + #define METER_CERT_MAX_SIZE 4096 + #define STATE_MAX_NUM_LICENSES 16 + #define STATE_MAX_NUM_IN_BUNDLE (uint32_t)8 +-#define METER_MAX_NUM_BUNDLES 8 + + #define __round_mask(x, y) ((__typeof__(x))((y) - 1)) + #define round_up(x, y) ((((x) - 1) | __round_mask(x, y)) + 1) +@@ -154,11 +153,12 @@ struct bundle_encoding { + }; + + struct meter_certificate { +- uint32_t block_signature; +- uint32_t counter_unit; ++ uint32_t signature; ++ uint32_t version; + uint64_t ppin; ++ uint32_t counter_unit; + uint32_t bundle_length; +- uint32_t reserved; ++ uint64_t reserved; + uint32_t mmrc_encoding; + uint32_t mmrc_counter; + }; +@@ -167,6 +167,11 @@ struct bundle_encoding_counter { + uint32_t encoding; + uint32_t counter; + }; ++#define METER_BUNDLE_SIZE sizeof(struct bundle_encoding_counter) ++#define BUNDLE_COUNT(length) ((length) / METER_BUNDLE_SIZE) ++#define METER_MAX_NUM_BUNDLES \ ++ ((METER_CERT_MAX_SIZE - sizeof(struct meter_certificate)) / \ ++ sizeof(struct bundle_encoding_counter)) + + struct sdsi_dev { + struct sdsi_regs regs; +@@ -334,6 +339,7 @@ static int sdsi_meter_cert_show(struct sdsi_dev *s) + uint32_t count = 0; + FILE *cert_ptr; + int ret, size; ++ char name[4]; + + ret = sdsi_update_registers(s); + if (ret) +@@ -375,32 +381,40 @@ static int sdsi_meter_cert_show(struct sdsi_dev *s) + printf("\n"); + printf("Meter certificate for device %s\n", s->dev_name); + printf("\n"); +- printf("Block Signature: 0x%x\n", mc->block_signature); +- printf("Count Unit: %dms\n", mc->counter_unit); +- printf("PPIN: 0x%lx\n", mc->ppin); +- printf("Feature Bundle Length: %d\n", mc->bundle_length); +- printf("MMRC encoding: %d\n", mc->mmrc_encoding); +- printf("MMRC counter: %d\n", mc->mmrc_counter); +- if (mc->bundle_length % 8) { ++ ++ get_feature(mc->signature, name); ++ printf("Signature: %.4s\n", name); ++ ++ printf("Version: %d\n", mc->version); ++ printf("Count Unit: %dms\n", mc->counter_unit); ++ printf("PPIN: 0x%lx\n", mc->ppin); ++ printf("Feature Bundle Length: %d\n", mc->bundle_length); ++ ++ get_feature(mc->mmrc_encoding, name); ++ printf("MMRC encoding: %.4s\n", name); ++ ++ printf("MMRC counter: %d\n", mc->mmrc_counter); ++ if (mc->bundle_length % METER_BUNDLE_SIZE) { + fprintf(stderr, "Invalid bundle length\n"); + return -1; + } + +- if (mc->bundle_length > METER_MAX_NUM_BUNDLES * 8) { +- fprintf(stderr, "More than %d bundles: %d\n", +- METER_MAX_NUM_BUNDLES, mc->bundle_length / 8); ++ if (mc->bundle_length > METER_MAX_NUM_BUNDLES * METER_BUNDLE_SIZE) { ++ fprintf(stderr, "More than %ld bundles: actual %ld\n", ++ METER_MAX_NUM_BUNDLES, BUNDLE_COUNT(mc->bundle_length)); + return -1; + } + +- bec = (void *)(mc) + sizeof(mc); ++ bec = (struct bundle_encoding_counter *)(mc + 1); + +- printf("Number of Feature Counters: %d\n", mc->bundle_length / 8); +- while (count++ < mc->bundle_length / 8) { ++ printf("Number of Feature Counters: %ld\n", BUNDLE_COUNT(mc->bundle_length)); ++ while (count < BUNDLE_COUNT(mc->bundle_length)) { + char feature[5]; + + feature[4] = '\0'; + get_feature(bec[count].encoding, feature); + printf(" %s: %d\n", feature, bec[count].counter); ++ ++count; + } + + return 0; +diff --git a/tools/arch/x86/lib/x86-opcode-map.txt b/tools/arch/x86/lib/x86-opcode-map.txt +index 5168ee0360b24..d1ccd06c53127 100644 +--- a/tools/arch/x86/lib/x86-opcode-map.txt ++++ b/tools/arch/x86/lib/x86-opcode-map.txt +@@ -148,7 +148,7 @@ AVXcode: + 65: SEG=GS (Prefix) + 66: Operand-Size (Prefix) + 67: Address-Size (Prefix) +-68: PUSH Iz (d64) ++68: PUSH Iz + 69: IMUL Gv,Ev,Iz + 6a: PUSH Ib (d64) + 6b: IMUL Gv,Ev,Ib +@@ -698,10 +698,10 @@ AVXcode: 2 + 4d: vrcp14ss/d Vsd,Hpd,Wsd (66),(ev) + 4e: vrsqrt14ps/d Vpd,Wpd (66),(ev) + 4f: vrsqrt14ss/d Vsd,Hsd,Wsd (66),(ev) +-50: vpdpbusd Vx,Hx,Wx (66),(ev) +-51: vpdpbusds Vx,Hx,Wx (66),(ev) +-52: vdpbf16ps Vx,Hx,Wx (F3),(ev) | vpdpwssd Vx,Hx,Wx (66),(ev) | vp4dpwssd Vdqq,Hdqq,Wdq (F2),(ev) +-53: vpdpwssds Vx,Hx,Wx (66),(ev) | vp4dpwssds Vdqq,Hdqq,Wdq (F2),(ev) ++50: vpdpbusd Vx,Hx,Wx (66) ++51: vpdpbusds Vx,Hx,Wx (66) ++52: vdpbf16ps Vx,Hx,Wx (F3),(ev) | vpdpwssd Vx,Hx,Wx (66) | vp4dpwssd Vdqq,Hdqq,Wdq (F2),(ev) ++53: vpdpwssds Vx,Hx,Wx (66) | vp4dpwssds Vdqq,Hdqq,Wdq (F2),(ev) + 54: vpopcntb/w Vx,Wx (66),(ev) + 55: vpopcntd/q Vx,Wx (66),(ev) + 58: vpbroadcastd Vx,Wx (66),(v) +diff --git a/tools/bpf/bpftool/common.c b/tools/bpf/bpftool/common.c +index cc6e6aae2447d..958e92acca8e2 100644 +--- a/tools/bpf/bpftool/common.c ++++ b/tools/bpf/bpftool/common.c +@@ -244,29 +244,101 @@ int open_obj_pinned_any(const char *path, enum bpf_obj_type exp_type) + return fd; + } + +-int mount_bpffs_for_pin(const char *name, bool is_dir) ++int create_and_mount_bpffs_dir(const char *dir_name) + { + char err_str[ERR_MAX_LEN]; +- char *file; +- char *dir; ++ bool dir_exists; + int err = 0; + +- if (is_dir && is_bpffs(name)) ++ if (is_bpffs(dir_name)) + return err; + +- file = malloc(strlen(name) + 1); +- if (!file) { ++ dir_exists = access(dir_name, F_OK) == 0; ++ ++ if (!dir_exists) { ++ char *temp_name; ++ char *parent_name; ++ ++ temp_name = strdup(dir_name); ++ if (!temp_name) { ++ p_err("mem alloc failed"); ++ return -1; ++ } ++ ++ parent_name = dirname(temp_name); ++ ++ if (is_bpffs(parent_name)) { ++ /* nothing to do if already mounted */ ++ free(temp_name); ++ return err; ++ } ++ ++ if (access(parent_name, F_OK) == -1) { ++ p_err("can't create dir '%s' to pin BPF object: parent dir '%s' doesn't exist", ++ dir_name, parent_name); ++ free(temp_name); ++ return -1; ++ } ++ ++ free(temp_name); ++ } ++ ++ if (block_mount) { ++ p_err("no BPF file system found, not mounting it due to --nomount option"); ++ return -1; ++ } ++ ++ if (!dir_exists) { ++ err = mkdir(dir_name, S_IRWXU); ++ if (err) { ++ p_err("failed to create dir '%s': %s", dir_name, strerror(errno)); ++ return err; ++ } ++ } ++ ++ err = mnt_fs(dir_name, "bpf", err_str, ERR_MAX_LEN); ++ if (err) { ++ err_str[ERR_MAX_LEN - 1] = '\0'; ++ p_err("can't mount BPF file system on given dir '%s': %s", ++ dir_name, err_str); ++ ++ if (!dir_exists) ++ rmdir(dir_name); ++ } ++ ++ return err; ++} ++ ++int mount_bpffs_for_file(const char *file_name) ++{ ++ char err_str[ERR_MAX_LEN]; ++ char *temp_name; ++ char *dir; ++ int err = 0; ++ ++ if (access(file_name, F_OK) != -1) { ++ p_err("can't pin BPF object: path '%s' already exists", file_name); ++ return -1; ++ } ++ ++ temp_name = strdup(file_name); ++ if (!temp_name) { + p_err("mem alloc failed"); + return -1; + } + +- strcpy(file, name); +- dir = dirname(file); ++ dir = dirname(temp_name); + + if (is_bpffs(dir)) + /* nothing to do if already mounted */ + goto out_free; + ++ if (access(dir, F_OK) == -1) { ++ p_err("can't pin BPF object: dir '%s' doesn't exist", dir); ++ err = -1; ++ goto out_free; ++ } ++ + if (block_mount) { + p_err("no BPF file system found, not mounting it due to --nomount option"); + err = -1; +@@ -276,12 +348,12 @@ int mount_bpffs_for_pin(const char *name, bool is_dir) + err = mnt_fs(dir, "bpf", err_str, ERR_MAX_LEN); + if (err) { + err_str[ERR_MAX_LEN - 1] = '\0'; +- p_err("can't mount BPF file system to pin the object (%s): %s", +- name, err_str); ++ p_err("can't mount BPF file system to pin the object '%s': %s", ++ file_name, err_str); + } + + out_free: +- free(file); ++ free(temp_name); + return err; + } + +@@ -289,7 +361,7 @@ int do_pin_fd(int fd, const char *name) + { + int err; + +- err = mount_bpffs_for_pin(name, false); ++ err = mount_bpffs_for_file(name); + if (err) + return err; + +diff --git a/tools/bpf/bpftool/iter.c b/tools/bpf/bpftool/iter.c +index 6b0e5202ca7a9..5c39c2ed36a2b 100644 +--- a/tools/bpf/bpftool/iter.c ++++ b/tools/bpf/bpftool/iter.c +@@ -76,7 +76,7 @@ static int do_pin(int argc, char **argv) + goto close_obj; + } + +- err = mount_bpffs_for_pin(path, false); ++ err = mount_bpffs_for_file(path); + if (err) + goto close_link; + +diff --git a/tools/bpf/bpftool/main.h b/tools/bpf/bpftool/main.h +index b8bb08d10dec9..9eb764fe4cc8b 100644 +--- a/tools/bpf/bpftool/main.h ++++ b/tools/bpf/bpftool/main.h +@@ -142,7 +142,8 @@ const char *get_fd_type_name(enum bpf_obj_type type); + char *get_fdinfo(int fd, const char *key); + int open_obj_pinned(const char *path, bool quiet); + int open_obj_pinned_any(const char *path, enum bpf_obj_type exp_type); +-int mount_bpffs_for_pin(const char *name, bool is_dir); ++int mount_bpffs_for_file(const char *file_name); ++int create_and_mount_bpffs_dir(const char *dir_name); + int do_pin_any(int argc, char **argv, int (*get_fd_by_id)(int *, char ***)); + int do_pin_fd(int fd, const char *name); + +diff --git a/tools/bpf/bpftool/prog.c b/tools/bpf/bpftool/prog.c +index f186f1cee465b..086b93939ce93 100644 +--- a/tools/bpf/bpftool/prog.c ++++ b/tools/bpf/bpftool/prog.c +@@ -1774,7 +1774,10 @@ static int load_with_options(int argc, char **argv, bool first_prog_only) + goto err_close_obj; + } + +- err = mount_bpffs_for_pin(pinfile, !first_prog_only); ++ if (first_prog_only) ++ err = mount_bpffs_for_file(pinfile); ++ else ++ err = create_and_mount_bpffs_dir(pinfile); + if (err) + goto err_close_obj; + +diff --git a/tools/bpf/bpftool/skeleton/pid_iter.bpf.c b/tools/bpf/bpftool/skeleton/pid_iter.bpf.c +index 26004f0c5a6ae..7bdbcac3cf628 100644 +--- a/tools/bpf/bpftool/skeleton/pid_iter.bpf.c ++++ b/tools/bpf/bpftool/skeleton/pid_iter.bpf.c +@@ -102,8 +102,8 @@ int iter(struct bpf_iter__task_file *ctx) + BPF_LINK_TYPE_PERF_EVENT___local)) { + struct bpf_link *link = (struct bpf_link *) file->private_data; + +- if (link->type == bpf_core_enum_value(enum bpf_link_type___local, +- BPF_LINK_TYPE_PERF_EVENT___local)) { ++ if (BPF_CORE_READ(link, type) == bpf_core_enum_value(enum bpf_link_type___local, ++ BPF_LINK_TYPE_PERF_EVENT___local)) { + e.has_bpf_cookie = true; + e.bpf_cookie = get_bpf_cookie(link); + } +diff --git a/tools/bpf/bpftool/struct_ops.c b/tools/bpf/bpftool/struct_ops.c +index 3ebc9fe91e0e1..d110c6ad8175c 100644 +--- a/tools/bpf/bpftool/struct_ops.c ++++ b/tools/bpf/bpftool/struct_ops.c +@@ -509,7 +509,7 @@ static int do_register(int argc, char **argv) + if (argc == 1) + linkdir = GET_ARG(); + +- if (linkdir && mount_bpffs_for_pin(linkdir, true)) { ++ if (linkdir && create_and_mount_bpffs_dir(linkdir)) { + p_err("can't mount bpffs for pinning"); + return -1; + } +diff --git a/tools/bpf/resolve_btfids/main.c b/tools/bpf/resolve_btfids/main.c +index d9520cb826b31..af393c7dee1f1 100644 +--- a/tools/bpf/resolve_btfids/main.c ++++ b/tools/bpf/resolve_btfids/main.c +@@ -728,7 +728,7 @@ static int sets_patch(struct object *obj) + + static int symbols_patch(struct object *obj) + { +- int err; ++ off_t err; + + if (__symbols_patch(obj, &obj->structs) || + __symbols_patch(obj, &obj->unions) || +diff --git a/tools/include/nolibc/stdlib.h b/tools/include/nolibc/stdlib.h +index bacfd35c51565..5be9d3c7435a8 100644 +--- a/tools/include/nolibc/stdlib.h ++++ b/tools/include/nolibc/stdlib.h +@@ -185,7 +185,7 @@ void *realloc(void *old_ptr, size_t new_size) + if (__builtin_expect(!ret, 0)) + return NULL; + +- memcpy(ret, heap->user_p, heap->len); ++ memcpy(ret, heap->user_p, user_p_len); + munmap(heap, heap->len); + return ret; + } +diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h +index 366df8a1a5fc8..fb09fd1767f28 100644 +--- a/tools/include/uapi/linux/bpf.h ++++ b/tools/include/uapi/linux/bpf.h +@@ -6994,7 +6994,7 @@ struct bpf_fib_lookup { + + /* output: MTU value */ + __u16 mtu_result; +- }; ++ } __attribute__((packed, aligned(2))); + /* input: L3 device index for lookup + * output: device index from FIB lookup + */ +diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c +index e238e6b824393..de35b9a21dad7 100644 +--- a/tools/lib/bpf/libbpf.c ++++ b/tools/lib/bpf/libbpf.c +@@ -10985,7 +10985,7 @@ static int attach_kprobe_multi(const struct bpf_program *prog, long cookie, stru + + n = sscanf(spec, "%m[a-zA-Z0-9_.*?]", &pattern); + if (n < 1) { +- pr_warn("kprobe multi pattern is invalid: %s\n", pattern); ++ pr_warn("kprobe multi pattern is invalid: %s\n", spec); + return -EINVAL; + } + +diff --git a/tools/lib/perf/evlist.c b/tools/lib/perf/evlist.c +index ceb34123f38ed..fad607789d1e5 100644 +--- a/tools/lib/perf/evlist.c ++++ b/tools/lib/perf/evlist.c +@@ -744,3 +744,12 @@ int perf_evlist__nr_groups(struct perf_evlist *evlist) + } + return nr_groups; + } ++ ++void perf_evlist__go_system_wide(struct perf_evlist *evlist, struct perf_evsel *evsel) ++{ ++ if (!evsel->system_wide) { ++ evsel->system_wide = true; ++ if (evlist->needs_map_propagation) ++ __perf_evlist__propagate_maps(evlist, evsel); ++ } ++} +diff --git a/tools/lib/perf/include/internal/evlist.h b/tools/lib/perf/include/internal/evlist.h +index 79e11d71072a0..f43bdb9b6227c 100644 +--- a/tools/lib/perf/include/internal/evlist.h ++++ b/tools/lib/perf/include/internal/evlist.h +@@ -135,4 +135,6 @@ int perf_evlist__id_add_fd(struct perf_evlist *evlist, + void perf_evlist__reset_id_hash(struct perf_evlist *evlist); + + void __perf_evlist__set_leader(struct list_head *list, struct perf_evsel *leader); ++ ++void perf_evlist__go_system_wide(struct perf_evlist *evlist, struct perf_evsel *evsel); + #endif /* __LIBPERF_INTERNAL_EVLIST_H */ +diff --git a/tools/lib/subcmd/parse-options.c b/tools/lib/subcmd/parse-options.c +index 9fa75943f2ed1..d943d78b787ed 100644 +--- a/tools/lib/subcmd/parse-options.c ++++ b/tools/lib/subcmd/parse-options.c +@@ -633,11 +633,10 @@ int parse_options_subcommand(int argc, const char **argv, const struct option *o + const char *const subcommands[], const char *usagestr[], int flags) + { + struct parse_opt_ctx_t ctx; ++ char *buf = NULL; + + /* build usage string if it's not provided */ + if (subcommands && !usagestr[0]) { +- char *buf = NULL; +- + astrcatf(&buf, "%s %s [] {", subcmd_config.exec_name, argv[0]); + + for (int i = 0; subcommands[i]; i++) { +@@ -679,7 +678,10 @@ int parse_options_subcommand(int argc, const char **argv, const struct option *o + astrcatf(&error_buf, "unknown switch `%c'", *ctx.opt); + usage_with_options(usagestr, options); + } +- ++ if (buf) { ++ usagestr[0] = NULL; ++ free(buf); ++ } + return parse_options_end(&ctx); + } + +diff --git a/tools/perf/Documentation/perf-list.txt b/tools/perf/Documentation/perf-list.txt +index d5f78e125efed..69c6d5e46ad88 100644 +--- a/tools/perf/Documentation/perf-list.txt ++++ b/tools/perf/Documentation/perf-list.txt +@@ -67,6 +67,7 @@ counted. The following modifiers exist: + D - pin the event to the PMU + W - group is weak and will fallback to non-group if not schedulable, + e - group or event are exclusive and do not share the PMU ++ b - use BPF aggregration (see perf stat --bpf-counters) + + The 'p' modifier can be used for specifying how precise the instruction + address should be. The 'p' modifier can be specified multiple times: +diff --git a/tools/perf/arch/arm64/util/pmu.c b/tools/perf/arch/arm64/util/pmu.c +index 615084eb88d8c..3d9330feebd28 100644 +--- a/tools/perf/arch/arm64/util/pmu.c ++++ b/tools/perf/arch/arm64/util/pmu.c +@@ -10,7 +10,7 @@ + + const struct pmu_metrics_table *pmu_metrics_table__find(void) + { +- struct perf_pmu *pmu = pmu__find_core_pmu(); ++ struct perf_pmu *pmu = perf_pmus__find_core_pmu(); + + if (pmu) + return perf_pmu__find_metrics_table(pmu); +@@ -20,7 +20,7 @@ const struct pmu_metrics_table *pmu_metrics_table__find(void) + + const struct pmu_events_table *pmu_events_table__find(void) + { +- struct perf_pmu *pmu = pmu__find_core_pmu(); ++ struct perf_pmu *pmu = perf_pmus__find_core_pmu(); + + if (pmu) + return perf_pmu__find_events_table(pmu); +@@ -32,7 +32,7 @@ double perf_pmu__cpu_slots_per_cycle(void) + { + char path[PATH_MAX]; + unsigned long long slots = 0; +- struct perf_pmu *pmu = pmu__find_core_pmu(); ++ struct perf_pmu *pmu = perf_pmus__find_core_pmu(); + + if (pmu) { + perf_pmu__pathname_scnprintf(path, sizeof(path), +diff --git a/tools/perf/bench/inject-buildid.c b/tools/perf/bench/inject-buildid.c +index 49331743c7439..a759eb2328bea 100644 +--- a/tools/perf/bench/inject-buildid.c ++++ b/tools/perf/bench/inject-buildid.c +@@ -362,7 +362,7 @@ static int inject_build_id(struct bench_data *data, u64 *max_rss) + return -1; + + for (i = 0; i < nr_mmaps; i++) { +- int idx = rand() % (nr_dsos - 1); ++ int idx = rand() % nr_dsos; + struct bench_dso *dso = &dsos[idx]; + u64 timestamp = rand() % 1000000; + +diff --git a/tools/perf/bench/uprobe.c b/tools/perf/bench/uprobe.c +index 914c0817fe8ad..e8e0afa13f049 100644 +--- a/tools/perf/bench/uprobe.c ++++ b/tools/perf/bench/uprobe.c +@@ -47,7 +47,7 @@ static const char * const bench_uprobe_usage[] = { + #define bench_uprobe__attach_uprobe(prog) \ + skel->links.prog = bpf_program__attach_uprobe_opts(/*prog=*/skel->progs.prog, \ + /*pid=*/-1, \ +- /*binary_path=*/"/lib64/libc.so.6", \ ++ /*binary_path=*/"libc.so.6", \ + /*func_offset=*/0, \ + /*opts=*/&uprobe_opts); \ + if (!skel->links.prog) { \ +diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c +index aeeb801f1ed7b..92973420c0a5a 100644 +--- a/tools/perf/builtin-annotate.c ++++ b/tools/perf/builtin-annotate.c +@@ -45,7 +45,6 @@ + struct perf_annotate { + struct perf_tool tool; + struct perf_session *session; +- struct annotation_options opts; + #ifdef HAVE_SLANG_SUPPORT + bool use_tui; + #endif +@@ -315,9 +314,9 @@ static int hist_entry__tty_annotate(struct hist_entry *he, + struct perf_annotate *ann) + { + if (!ann->use_stdio2) +- return symbol__tty_annotate(&he->ms, evsel, &ann->opts); ++ return symbol__tty_annotate(&he->ms, evsel); + +- return symbol__tty_annotate2(&he->ms, evsel, &ann->opts); ++ return symbol__tty_annotate2(&he->ms, evsel); + } + + static void hists__find_annotations(struct hists *hists, +@@ -363,7 +362,6 @@ static void hists__find_annotations(struct hists *hists, + int ret; + int (*annotate)(struct hist_entry *he, + struct evsel *evsel, +- struct annotation_options *options, + struct hist_browser_timer *hbt); + + annotate = dlsym(perf_gtk_handle, +@@ -373,14 +371,14 @@ static void hists__find_annotations(struct hists *hists, + return; + } + +- ret = annotate(he, evsel, &ann->opts, NULL); ++ ret = annotate(he, evsel, NULL); + if (!ret || !ann->skip_missing) + return; + + /* skip missing symbols */ + nd = rb_next(nd); + } else if (use_browser == 1) { +- key = hist_entry__tui_annotate(he, evsel, NULL, &ann->opts); ++ key = hist_entry__tui_annotate(he, evsel, NULL, &annotate_opts); + + switch (key) { + case -1: +@@ -422,9 +420,9 @@ static int __cmd_annotate(struct perf_annotate *ann) + goto out; + } + +- if (!ann->opts.objdump_path) { ++ if (!annotate_opts.objdump_path) { + ret = perf_env__lookup_objdump(&session->header.env, +- &ann->opts.objdump_path); ++ &annotate_opts.objdump_path); + if (ret) + goto out; + } +@@ -558,9 +556,9 @@ int cmd_annotate(int argc, const char **argv) + "file", "vmlinux pathname"), + OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules, + "load module symbols - WARNING: use only with -k and LIVE kernel"), +- OPT_BOOLEAN('l', "print-line", &annotate.opts.print_lines, ++ OPT_BOOLEAN('l', "print-line", &annotate_opts.print_lines, + "print matching source lines (may be slow)"), +- OPT_BOOLEAN('P', "full-paths", &annotate.opts.full_path, ++ OPT_BOOLEAN('P', "full-paths", &annotate_opts.full_path, + "Don't shorten the displayed pathnames"), + OPT_BOOLEAN(0, "skip-missing", &annotate.skip_missing, + "Skip symbols that cannot be annotated"), +@@ -571,15 +569,15 @@ int cmd_annotate(int argc, const char **argv) + OPT_CALLBACK(0, "symfs", NULL, "directory", + "Look for files with symbols relative to this directory", + symbol__config_symfs), +- OPT_BOOLEAN(0, "source", &annotate.opts.annotate_src, ++ OPT_BOOLEAN(0, "source", &annotate_opts.annotate_src, + "Interleave source code with assembly code (default)"), +- OPT_BOOLEAN(0, "asm-raw", &annotate.opts.show_asm_raw, ++ OPT_BOOLEAN(0, "asm-raw", &annotate_opts.show_asm_raw, + "Display raw encoding of assembly instructions (default)"), + OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style", + "Specify disassembler style (e.g. -M intel for intel syntax)"), +- OPT_STRING(0, "prefix", &annotate.opts.prefix, "prefix", ++ OPT_STRING(0, "prefix", &annotate_opts.prefix, "prefix", + "Add prefix to source file path names in programs (with --prefix-strip)"), +- OPT_STRING(0, "prefix-strip", &annotate.opts.prefix_strip, "N", ++ OPT_STRING(0, "prefix-strip", &annotate_opts.prefix_strip, "N", + "Strip first N entries of source file path name in programs (with --prefix)"), + OPT_STRING(0, "objdump", &objdump_path, "path", + "objdump binary to use for disassembly and annotations"), +@@ -589,8 +587,6 @@ int cmd_annotate(int argc, const char **argv) + "Enable symbol demangling"), + OPT_BOOLEAN(0, "demangle-kernel", &symbol_conf.demangle_kernel, + "Enable kernel symbol demangling"), +- OPT_BOOLEAN(0, "group", &symbol_conf.event_group, +- "Show event group information together"), + OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period, + "Show a column with the sum of periods"), + OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples, +@@ -598,7 +594,7 @@ int cmd_annotate(int argc, const char **argv) + OPT_CALLBACK_DEFAULT(0, "stdio-color", NULL, "mode", + "'always' (default), 'never' or 'auto' only applicable to --stdio mode", + stdio__config_color, "always"), +- OPT_CALLBACK(0, "percent-type", &annotate.opts, "local-period", ++ OPT_CALLBACK(0, "percent-type", &annotate_opts, "local-period", + "Set percent type local/global-period/hits", + annotate_parse_percent_type), + OPT_CALLBACK(0, "percent-limit", &annotate, "percent", +@@ -614,13 +610,13 @@ int cmd_annotate(int argc, const char **argv) + set_option_flag(options, 0, "show-total-period", PARSE_OPT_EXCLUSIVE); + set_option_flag(options, 0, "show-nr-samples", PARSE_OPT_EXCLUSIVE); + +- annotation_options__init(&annotate.opts); ++ annotation_options__init(&annotate_opts); + + ret = hists__init(); + if (ret < 0) + return ret; + +- annotation_config__init(&annotate.opts); ++ annotation_config__init(&annotate_opts); + + argc = parse_options(argc, argv, options, annotate_usage, 0); + if (argc) { +@@ -635,13 +631,13 @@ int cmd_annotate(int argc, const char **argv) + } + + if (disassembler_style) { +- annotate.opts.disassembler_style = strdup(disassembler_style); +- if (!annotate.opts.disassembler_style) ++ annotate_opts.disassembler_style = strdup(disassembler_style); ++ if (!annotate_opts.disassembler_style) + return -ENOMEM; + } + if (objdump_path) { +- annotate.opts.objdump_path = strdup(objdump_path); +- if (!annotate.opts.objdump_path) ++ annotate_opts.objdump_path = strdup(objdump_path); ++ if (!annotate_opts.objdump_path) + return -ENOMEM; + } + if (addr2line_path) { +@@ -650,7 +646,7 @@ int cmd_annotate(int argc, const char **argv) + return -ENOMEM; + } + +- if (annotate_check_args(&annotate.opts) < 0) ++ if (annotate_check_args(&annotate_opts) < 0) + return -EINVAL; + + #ifdef HAVE_GTK2_SUPPORT +@@ -731,7 +727,7 @@ int cmd_annotate(int argc, const char **argv) + #ifndef NDEBUG + perf_session__delete(annotate.session); + #endif +- annotation_options__exit(&annotate.opts); ++ annotation_options__exit(&annotate_opts); + + return ret; + } +diff --git a/tools/perf/builtin-daemon.c b/tools/perf/builtin-daemon.c +index 83954af36753a..de76bbc50bfbc 100644 +--- a/tools/perf/builtin-daemon.c ++++ b/tools/perf/builtin-daemon.c +@@ -523,7 +523,7 @@ static int daemon_session__control(struct daemon_session *session, + session->base, SESSION_CONTROL); + + control = open(control_path, O_WRONLY|O_NONBLOCK); +- if (!control) ++ if (control < 0) + return -1; + + if (do_ack) { +@@ -532,7 +532,7 @@ static int daemon_session__control(struct daemon_session *session, + session->base, SESSION_ACK); + + ack = open(ack_path, O_RDONLY, O_NONBLOCK); +- if (!ack) { ++ if (ack < 0) { + close(control); + return -1; + } +diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c +index c8cf2fdd9cff9..eb3ef5c24b662 100644 +--- a/tools/perf/builtin-inject.c ++++ b/tools/perf/builtin-inject.c +@@ -2265,6 +2265,12 @@ int cmd_inject(int argc, const char **argv) + "perf inject []", + NULL + }; ++ ++ if (!inject.itrace_synth_opts.set) { ++ /* Disable eager loading of kernel symbols that adds overhead to perf inject. */ ++ symbol_conf.lazy_load_kernel_maps = true; ++ } ++ + #ifndef HAVE_JITDUMP + set_option_nobuild(options, 'j', "jit", "NO_LIBELF=1", true); + #endif +diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c +index c40460e936ccd..b94ae33a343c2 100644 +--- a/tools/perf/builtin-record.c ++++ b/tools/perf/builtin-record.c +@@ -906,6 +906,37 @@ static int record__config_off_cpu(struct record *rec) + return off_cpu_prepare(rec->evlist, &rec->opts.target, &rec->opts); + } + ++static int record__config_tracking_events(struct record *rec) ++{ ++ struct record_opts *opts = &rec->opts; ++ struct evlist *evlist = rec->evlist; ++ struct evsel *evsel; ++ ++ /* ++ * For initial_delay, system wide or a hybrid system, we need to add ++ * tracking event so that we can track PERF_RECORD_MMAP to cover the ++ * delay of waiting or event synthesis. ++ */ ++ if (opts->target.initial_delay || target__has_cpu(&opts->target) || ++ perf_pmus__num_core_pmus() > 1) { ++ evsel = evlist__findnew_tracking_event(evlist, false); ++ if (!evsel) ++ return -ENOMEM; ++ ++ /* ++ * Enable the tracking event when the process is forked for ++ * initial_delay, immediately for system wide. ++ */ ++ if (opts->target.initial_delay && !evsel->immediate && ++ !target__has_cpu(&opts->target)) ++ evsel->core.attr.enable_on_exec = 1; ++ else ++ evsel->immediate = 1; ++ } ++ ++ return 0; ++} ++ + static bool record__kcore_readable(struct machine *machine) + { + char kcore[PATH_MAX]; +@@ -1286,35 +1317,6 @@ static int record__open(struct record *rec) + struct record_opts *opts = &rec->opts; + int rc = 0; + +- /* +- * For initial_delay, system wide or a hybrid system, we need to add a +- * dummy event so that we can track PERF_RECORD_MMAP to cover the delay +- * of waiting or event synthesis. +- */ +- if (opts->target.initial_delay || target__has_cpu(&opts->target) || +- perf_pmus__num_core_pmus() > 1) { +- pos = evlist__get_tracking_event(evlist); +- if (!evsel__is_dummy_event(pos)) { +- /* Set up dummy event. */ +- if (evlist__add_dummy(evlist)) +- return -ENOMEM; +- pos = evlist__last(evlist); +- evlist__set_tracking_event(evlist, pos); +- } +- +- /* +- * Enable the dummy event when the process is forked for +- * initial_delay, immediately for system wide. +- */ +- if (opts->target.initial_delay && !pos->immediate && +- !target__has_cpu(&opts->target)) +- pos->core.attr.enable_on_exec = 1; +- else +- pos->immediate = 1; +- } +- +- evlist__config(evlist, opts, &callchain_param); +- + evlist__for_each_entry(evlist, pos) { + try_again: + if (evsel__open(pos, pos->core.cpus, pos->core.threads) < 0) { +@@ -2424,6 +2426,8 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) + + evlist__uniquify_name(rec->evlist); + ++ evlist__config(rec->evlist, opts, &callchain_param); ++ + /* Debug message used by test scripts */ + pr_debug3("perf record opening and mmapping events\n"); + if (record__open(rec) != 0) { +@@ -2822,10 +2826,10 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) + } + #endif + zstd_fini(&session->zstd_data); +- perf_session__delete(session); +- + if (!opts->no_bpf_event) + evlist__stop_sb_thread(rec->sb_evlist); ++ ++ perf_session__delete(session); + return status; + } + +@@ -3936,6 +3940,8 @@ int cmd_record(int argc, const char **argv) + # undef set_nobuild + #endif + ++ /* Disable eager loading of kernel symbols that adds overhead to perf record. */ ++ symbol_conf.lazy_load_kernel_maps = true; + rec->opts.affinity = PERF_AFFINITY_SYS; + + rec->evlist = evlist__new(); +@@ -4174,6 +4180,12 @@ int cmd_record(int argc, const char **argv) + goto out; + } + ++ err = record__config_tracking_events(rec); ++ if (err) { ++ pr_err("record__config_tracking_events failed, error %d\n", err); ++ goto out; ++ } ++ + err = record__init_thread_masks(rec); + if (err) { + pr_err("Failed to initialize parallel data streaming masks\n"); +diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c +index dcedfe00f04db..2a8889c6d7f97 100644 +--- a/tools/perf/builtin-report.c ++++ b/tools/perf/builtin-report.c +@@ -98,7 +98,6 @@ struct report { + bool skip_empty; + int max_stack; + struct perf_read_values show_threads_values; +- struct annotation_options annotation_opts; + const char *pretty_printing_style; + const char *cpu_list; + const char *symbol_filter_str; +@@ -427,7 +426,7 @@ static int report__setup_sample_type(struct report *rep) + * compatibility, set the bit if it's an old perf data file. + */ + evlist__for_each_entry(session->evlist, evsel) { +- if (strstr(evsel->name, "arm_spe") && ++ if (strstr(evsel__name(evsel), "arm_spe") && + !(sample_type & PERF_SAMPLE_DATA_SRC)) { + evsel->core.attr.sample_type |= PERF_SAMPLE_DATA_SRC; + sample_type |= PERF_SAMPLE_DATA_SRC; +@@ -542,7 +541,7 @@ static int evlist__tui_block_hists_browse(struct evlist *evlist, struct report * + ret = report__browse_block_hists(&rep->block_reports[i++].hist, + rep->min_percent, pos, + &rep->session->header.env, +- &rep->annotation_opts); ++ &annotate_opts); + if (ret != 0) + return ret; + } +@@ -670,7 +669,7 @@ static int report__browse_hists(struct report *rep) + } + + ret = evlist__tui_browse_hists(evlist, help, NULL, rep->min_percent, +- &session->header.env, true, &rep->annotation_opts); ++ &session->header.env, true, &annotate_opts); + /* + * Usually "ret" is the last pressed key, and we only + * care if the key notifies us to switch data file. +@@ -730,7 +729,7 @@ static int hists__resort_cb(struct hist_entry *he, void *arg) + if (rep->symbol_ipc && sym && !sym->annotate2) { + struct evsel *evsel = hists_to_evsel(he->hists); + +- symbol__annotate2(&he->ms, evsel, &rep->annotation_opts, NULL); ++ symbol__annotate2(&he->ms, evsel, NULL); + } + + return 0; +@@ -1326,15 +1325,15 @@ int cmd_report(int argc, const char **argv) + "list of cpus to profile"), + OPT_BOOLEAN('I', "show-info", &report.show_full_info, + "Display extended information about perf.data file"), +- OPT_BOOLEAN(0, "source", &report.annotation_opts.annotate_src, ++ OPT_BOOLEAN(0, "source", &annotate_opts.annotate_src, + "Interleave source code with assembly code (default)"), +- OPT_BOOLEAN(0, "asm-raw", &report.annotation_opts.show_asm_raw, ++ OPT_BOOLEAN(0, "asm-raw", &annotate_opts.show_asm_raw, + "Display raw encoding of assembly instructions (default)"), + OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style", + "Specify disassembler style (e.g. -M intel for intel syntax)"), +- OPT_STRING(0, "prefix", &report.annotation_opts.prefix, "prefix", ++ OPT_STRING(0, "prefix", &annotate_opts.prefix, "prefix", + "Add prefix to source file path names in programs (with --prefix-strip)"), +- OPT_STRING(0, "prefix-strip", &report.annotation_opts.prefix_strip, "N", ++ OPT_STRING(0, "prefix-strip", &annotate_opts.prefix_strip, "N", + "Strip first N entries of source file path name in programs (with --prefix)"), + OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period, + "Show a column with the sum of periods"), +@@ -1386,7 +1385,7 @@ int cmd_report(int argc, const char **argv) + "Time span of interest (start,stop)"), + OPT_BOOLEAN(0, "inline", &symbol_conf.inline_name, + "Show inline function"), +- OPT_CALLBACK(0, "percent-type", &report.annotation_opts, "local-period", ++ OPT_CALLBACK(0, "percent-type", &annotate_opts, "local-period", + "Set percent type local/global-period/hits", + annotate_parse_percent_type), + OPT_BOOLEAN(0, "ns", &symbol_conf.nanosecs, "Show times in nanosecs"), +@@ -1411,7 +1410,14 @@ int cmd_report(int argc, const char **argv) + if (ret < 0) + goto exit; + +- annotation_options__init(&report.annotation_opts); ++ /* ++ * tasks_mode require access to exited threads to list those that are in ++ * the data file. Off-cpu events are synthesized after other events and ++ * reference exited threads. ++ */ ++ symbol_conf.keep_exited_threads = true; ++ ++ annotation_options__init(&annotate_opts); + + ret = perf_config(report__config, &report); + if (ret) +@@ -1430,13 +1436,13 @@ int cmd_report(int argc, const char **argv) + } + + if (disassembler_style) { +- report.annotation_opts.disassembler_style = strdup(disassembler_style); +- if (!report.annotation_opts.disassembler_style) ++ annotate_opts.disassembler_style = strdup(disassembler_style); ++ if (!annotate_opts.disassembler_style) + return -ENOMEM; + } + if (objdump_path) { +- report.annotation_opts.objdump_path = strdup(objdump_path); +- if (!report.annotation_opts.objdump_path) ++ annotate_opts.objdump_path = strdup(objdump_path); ++ if (!annotate_opts.objdump_path) + return -ENOMEM; + } + if (addr2line_path) { +@@ -1445,7 +1451,7 @@ int cmd_report(int argc, const char **argv) + return -ENOMEM; + } + +- if (annotate_check_args(&report.annotation_opts) < 0) { ++ if (annotate_check_args(&annotate_opts) < 0) { + ret = -EINVAL; + goto exit; + } +@@ -1677,7 +1683,7 @@ int cmd_report(int argc, const char **argv) + */ + symbol_conf.priv_size += sizeof(u32); + } +- annotation_config__init(&report.annotation_opts); ++ annotation_config__init(&annotate_opts); + } + + if (symbol__init(&session->header.env) < 0) +@@ -1731,7 +1737,7 @@ int cmd_report(int argc, const char **argv) + zstd_fini(&(session->zstd_data)); + perf_session__delete(session); + exit: +- annotation_options__exit(&report.annotation_opts); ++ annotation_options__exit(&annotate_opts); + free(sort_order_help); + free(field_order_help); + return ret; +diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c +index 9ab300b6f131f..f21a655dd7f95 100644 +--- a/tools/perf/builtin-sched.c ++++ b/tools/perf/builtin-sched.c +@@ -3000,8 +3000,11 @@ static int timehist_check_attr(struct perf_sched *sched, + return -1; + } + +- if (sched->show_callchain && !evsel__has_callchain(evsel)) { +- pr_info("Samples do not have callchains.\n"); ++ /* only need to save callchain related to sched_switch event */ ++ if (sched->show_callchain && ++ evsel__name_is(evsel, "sched:sched_switch") && ++ !evsel__has_callchain(evsel)) { ++ pr_info("Samples of sched_switch event do not have callchains.\n"); + sched->show_callchain = 0; + symbol_conf.use_callchain = 0; + } +diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c +index cd64ae44ccbde..6ac17763de0e0 100644 +--- a/tools/perf/builtin-top.c ++++ b/tools/perf/builtin-top.c +@@ -147,7 +147,7 @@ static int perf_top__parse_source(struct perf_top *top, struct hist_entry *he) + return err; + } + +- err = symbol__annotate(&he->ms, evsel, &top->annotation_opts, NULL); ++ err = symbol__annotate(&he->ms, evsel, NULL); + if (err == 0) { + top->sym_filter_entry = he; + } else { +@@ -261,9 +261,9 @@ static void perf_top__show_details(struct perf_top *top) + goto out_unlock; + + printf("Showing %s for %s\n", evsel__name(top->sym_evsel), symbol->name); +- printf(" Events Pcnt (>=%d%%)\n", top->annotation_opts.min_pcnt); ++ printf(" Events Pcnt (>=%d%%)\n", annotate_opts.min_pcnt); + +- more = symbol__annotate_printf(&he->ms, top->sym_evsel, &top->annotation_opts); ++ more = symbol__annotate_printf(&he->ms, top->sym_evsel); + + if (top->evlist->enabled) { + if (top->zero) +@@ -450,7 +450,7 @@ static void perf_top__print_mapped_keys(struct perf_top *top) + + fprintf(stdout, "\t[f] profile display filter (count). \t(%d)\n", top->count_filter); + +- fprintf(stdout, "\t[F] annotate display filter (percent). \t(%d%%)\n", top->annotation_opts.min_pcnt); ++ fprintf(stdout, "\t[F] annotate display filter (percent). \t(%d%%)\n", annotate_opts.min_pcnt); + fprintf(stdout, "\t[s] annotate symbol. \t(%s)\n", name?: "NULL"); + fprintf(stdout, "\t[S] stop annotation.\n"); + +@@ -553,7 +553,7 @@ static bool perf_top__handle_keypress(struct perf_top *top, int c) + prompt_integer(&top->count_filter, "Enter display event count filter"); + break; + case 'F': +- prompt_percent(&top->annotation_opts.min_pcnt, ++ prompt_percent(&annotate_opts.min_pcnt, + "Enter details display event filter (percent)"); + break; + case 'K': +@@ -647,7 +647,7 @@ static void *display_thread_tui(void *arg) + + ret = evlist__tui_browse_hists(top->evlist, help, &hbt, top->min_percent, + &top->session->header.env, !top->record_opts.overwrite, +- &top->annotation_opts); ++ &annotate_opts); + if (ret == K_RELOAD) { + top->zero = true; + goto repeat; +@@ -1241,9 +1241,9 @@ static int __cmd_top(struct perf_top *top) + pthread_t thread, thread_process; + int ret; + +- if (!top->annotation_opts.objdump_path) { ++ if (!annotate_opts.objdump_path) { + ret = perf_env__lookup_objdump(&top->session->header.env, +- &top->annotation_opts.objdump_path); ++ &annotate_opts.objdump_path); + if (ret) + return ret; + } +@@ -1537,9 +1537,9 @@ int cmd_top(int argc, const char **argv) + "only consider symbols in these comms"), + OPT_STRING(0, "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]", + "only consider these symbols"), +- OPT_BOOLEAN(0, "source", &top.annotation_opts.annotate_src, ++ OPT_BOOLEAN(0, "source", &annotate_opts.annotate_src, + "Interleave source code with assembly code (default)"), +- OPT_BOOLEAN(0, "asm-raw", &top.annotation_opts.show_asm_raw, ++ OPT_BOOLEAN(0, "asm-raw", &annotate_opts.show_asm_raw, + "Display raw encoding of assembly instructions (default)"), + OPT_BOOLEAN(0, "demangle-kernel", &symbol_conf.demangle_kernel, + "Enable kernel symbol demangling"), +@@ -1550,9 +1550,9 @@ int cmd_top(int argc, const char **argv) + "addr2line binary to use for line numbers"), + OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style", + "Specify disassembler style (e.g. -M intel for intel syntax)"), +- OPT_STRING(0, "prefix", &top.annotation_opts.prefix, "prefix", ++ OPT_STRING(0, "prefix", &annotate_opts.prefix, "prefix", + "Add prefix to source file path names in programs (with --prefix-strip)"), +- OPT_STRING(0, "prefix-strip", &top.annotation_opts.prefix_strip, "N", ++ OPT_STRING(0, "prefix-strip", &annotate_opts.prefix_strip, "N", + "Strip first N entries of source file path name in programs (with --prefix)"), + OPT_STRING('u', "uid", &target->uid_str, "user", "user to profile"), + OPT_CALLBACK(0, "percent-limit", &top, "percent", +@@ -1610,10 +1610,10 @@ int cmd_top(int argc, const char **argv) + if (status < 0) + return status; + +- annotation_options__init(&top.annotation_opts); ++ annotation_options__init(&annotate_opts); + +- top.annotation_opts.min_pcnt = 5; +- top.annotation_opts.context = 4; ++ annotate_opts.min_pcnt = 5; ++ annotate_opts.context = 4; + + top.evlist = evlist__new(); + if (top.evlist == NULL) +@@ -1643,13 +1643,13 @@ int cmd_top(int argc, const char **argv) + usage_with_options(top_usage, options); + + if (disassembler_style) { +- top.annotation_opts.disassembler_style = strdup(disassembler_style); +- if (!top.annotation_opts.disassembler_style) ++ annotate_opts.disassembler_style = strdup(disassembler_style); ++ if (!annotate_opts.disassembler_style) + return -ENOMEM; + } + if (objdump_path) { +- top.annotation_opts.objdump_path = strdup(objdump_path); +- if (!top.annotation_opts.objdump_path) ++ annotate_opts.objdump_path = strdup(objdump_path); ++ if (!annotate_opts.objdump_path) + return -ENOMEM; + } + if (addr2line_path) { +@@ -1662,7 +1662,7 @@ int cmd_top(int argc, const char **argv) + if (status) + goto out_delete_evlist; + +- if (annotate_check_args(&top.annotation_opts) < 0) ++ if (annotate_check_args(&annotate_opts) < 0) + goto out_delete_evlist; + + if (!top.evlist->core.nr_entries) { +@@ -1788,7 +1788,7 @@ int cmd_top(int argc, const char **argv) + if (status < 0) + goto out_delete_evlist; + +- annotation_config__init(&top.annotation_opts); ++ annotation_config__init(&annotate_opts); + + symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL); + status = symbol__init(NULL); +@@ -1841,7 +1841,7 @@ int cmd_top(int argc, const char **argv) + out_delete_evlist: + evlist__delete(top.evlist); + perf_session__delete(top.session); +- annotation_options__exit(&top.annotation_opts); ++ annotation_options__exit(&annotate_opts); + + return status; + } +diff --git a/tools/perf/pmu-events/arch/s390/cf_z16/transaction.json b/tools/perf/pmu-events/arch/s390/cf_z16/transaction.json +index ec2ff78e2b5f2..3ab1d3a6638c4 100644 +--- a/tools/perf/pmu-events/arch/s390/cf_z16/transaction.json ++++ b/tools/perf/pmu-events/arch/s390/cf_z16/transaction.json +@@ -2,71 +2,71 @@ + { + "BriefDescription": "Transaction count", + "MetricName": "transaction", +- "MetricExpr": "TX_C_TEND + TX_NC_TEND + TX_NC_TABORT + TX_C_TABORT_SPECIAL + TX_C_TABORT_NO_SPECIAL" ++ "MetricExpr": "TX_C_TEND + TX_NC_TEND + TX_NC_TABORT + TX_C_TABORT_SPECIAL + TX_C_TABORT_NO_SPECIAL if has_event(TX_C_TEND) else 0" + }, + { + "BriefDescription": "Cycles per Instruction", + "MetricName": "cpi", +- "MetricExpr": "CPU_CYCLES / INSTRUCTIONS" ++ "MetricExpr": "CPU_CYCLES / INSTRUCTIONS if has_event(INSTRUCTIONS) else 0" + }, + { + "BriefDescription": "Problem State Instruction Ratio", + "MetricName": "prbstate", +- "MetricExpr": "(PROBLEM_STATE_INSTRUCTIONS / INSTRUCTIONS) * 100" ++ "MetricExpr": "(PROBLEM_STATE_INSTRUCTIONS / INSTRUCTIONS) * 100 if has_event(INSTRUCTIONS) else 0" + }, + { + "BriefDescription": "Level One Miss per 100 Instructions", + "MetricName": "l1mp", +- "MetricExpr": "((L1I_DIR_WRITES + L1D_DIR_WRITES) / INSTRUCTIONS) * 100" ++ "MetricExpr": "((L1I_DIR_WRITES + L1D_DIR_WRITES) / INSTRUCTIONS) * 100 if has_event(INSTRUCTIONS) else 0" + }, + { + "BriefDescription": "Percentage sourced from Level 2 cache", + "MetricName": "l2p", +- "MetricExpr": "((DCW_REQ + DCW_REQ_IV + ICW_REQ + ICW_REQ_IV) / (L1I_DIR_WRITES + L1D_DIR_WRITES)) * 100" ++ "MetricExpr": "((DCW_REQ + DCW_REQ_IV + ICW_REQ + ICW_REQ_IV) / (L1I_DIR_WRITES + L1D_DIR_WRITES)) * 100 if has_event(DCW_REQ) else 0" + }, + { + "BriefDescription": "Percentage sourced from Level 3 on same chip cache", + "MetricName": "l3p", +- "MetricExpr": "((DCW_REQ_CHIP_HIT + DCW_ON_CHIP + DCW_ON_CHIP_IV + DCW_ON_CHIP_CHIP_HIT + ICW_REQ_CHIP_HIT + ICW_ON_CHIP + ICW_ON_CHIP_IV + ICW_ON_CHIP_CHIP_HIT) / (L1I_DIR_WRITES + L1D_DIR_WRITES)) * 100" ++ "MetricExpr": "((DCW_REQ_CHIP_HIT + DCW_ON_CHIP + DCW_ON_CHIP_IV + DCW_ON_CHIP_CHIP_HIT + ICW_REQ_CHIP_HIT + ICW_ON_CHIP + ICW_ON_CHIP_IV + ICW_ON_CHIP_CHIP_HIT) / (L1I_DIR_WRITES + L1D_DIR_WRITES)) * 100 if has_event(DCW_REQ_CHIP_HIT) else 0" + }, + { + "BriefDescription": "Percentage sourced from Level 4 Local cache on same book", + "MetricName": "l4lp", +- "MetricExpr": "((DCW_REQ_DRAWER_HIT + DCW_ON_CHIP_DRAWER_HIT + DCW_ON_MODULE + DCW_ON_DRAWER + IDCW_ON_MODULE_IV + IDCW_ON_MODULE_CHIP_HIT + IDCW_ON_MODULE_DRAWER_HIT + IDCW_ON_DRAWER_IV + IDCW_ON_DRAWER_CHIP_HIT + IDCW_ON_DRAWER_DRAWER_HIT + ICW_REQ_DRAWER_HIT + ICW_ON_CHIP_DRAWER_HIT + ICW_ON_MODULE + ICW_ON_DRAWER) / (L1I_DIR_WRITES + L1D_DIR_WRITES)) * 100" ++ "MetricExpr": "((DCW_REQ_DRAWER_HIT + DCW_ON_CHIP_DRAWER_HIT + DCW_ON_MODULE + DCW_ON_DRAWER + IDCW_ON_MODULE_IV + IDCW_ON_MODULE_CHIP_HIT + IDCW_ON_MODULE_DRAWER_HIT + IDCW_ON_DRAWER_IV + IDCW_ON_DRAWER_CHIP_HIT + IDCW_ON_DRAWER_DRAWER_HIT + ICW_REQ_DRAWER_HIT + ICW_ON_CHIP_DRAWER_HIT + ICW_ON_MODULE + ICW_ON_DRAWER) / (L1I_DIR_WRITES + L1D_DIR_WRITES)) * 100 if has_event(DCW_REQ_DRAWER_HIT) else 0" + }, + { + "BriefDescription": "Percentage sourced from Level 4 Remote cache on different book", + "MetricName": "l4rp", +- "MetricExpr": "((DCW_OFF_DRAWER + IDCW_OFF_DRAWER_IV + IDCW_OFF_DRAWER_CHIP_HIT + IDCW_OFF_DRAWER_DRAWER_HIT + ICW_OFF_DRAWER) / (L1I_DIR_WRITES + L1D_DIR_WRITES)) * 100" ++ "MetricExpr": "((DCW_OFF_DRAWER + IDCW_OFF_DRAWER_IV + IDCW_OFF_DRAWER_CHIP_HIT + IDCW_OFF_DRAWER_DRAWER_HIT + ICW_OFF_DRAWER) / (L1I_DIR_WRITES + L1D_DIR_WRITES)) * 100 if has_event(DCW_OFF_DRAWER) else 0" + }, + { + "BriefDescription": "Percentage sourced from memory", + "MetricName": "memp", +- "MetricExpr": "((DCW_ON_CHIP_MEMORY + DCW_ON_MODULE_MEMORY + DCW_ON_DRAWER_MEMORY + DCW_OFF_DRAWER_MEMORY + ICW_ON_CHIP_MEMORY + ICW_ON_MODULE_MEMORY + ICW_ON_DRAWER_MEMORY + ICW_OFF_DRAWER_MEMORY) / (L1I_DIR_WRITES + L1D_DIR_WRITES)) * 100" ++ "MetricExpr": "((DCW_ON_CHIP_MEMORY + DCW_ON_MODULE_MEMORY + DCW_ON_DRAWER_MEMORY + DCW_OFF_DRAWER_MEMORY + ICW_ON_CHIP_MEMORY + ICW_ON_MODULE_MEMORY + ICW_ON_DRAWER_MEMORY + ICW_OFF_DRAWER_MEMORY) / (L1I_DIR_WRITES + L1D_DIR_WRITES)) * 100 if has_event(DCW_ON_CHIP_MEMORY) else 0" + }, + { + "BriefDescription": "Cycles per Instructions from Finite cache/memory", + "MetricName": "finite_cpi", +- "MetricExpr": "L1C_TLB2_MISSES / INSTRUCTIONS" ++ "MetricExpr": "L1C_TLB2_MISSES / INSTRUCTIONS if has_event(L1C_TLB2_MISSES) else 0" + }, + { + "BriefDescription": "Estimated Instruction Complexity CPI infinite Level 1", + "MetricName": "est_cpi", +- "MetricExpr": "(CPU_CYCLES / INSTRUCTIONS) - (L1C_TLB2_MISSES / INSTRUCTIONS)" ++ "MetricExpr": "(CPU_CYCLES / INSTRUCTIONS) - (L1C_TLB2_MISSES / INSTRUCTIONS) if has_event(INSTRUCTIONS) else 0" + }, + { + "BriefDescription": "Estimated Sourcing Cycles per Level 1 Miss", + "MetricName": "scpl1m", +- "MetricExpr": "L1C_TLB2_MISSES / (L1I_DIR_WRITES + L1D_DIR_WRITES)" ++ "MetricExpr": "L1C_TLB2_MISSES / (L1I_DIR_WRITES + L1D_DIR_WRITES) if has_event(L1C_TLB2_MISSES) else 0" + }, + { + "BriefDescription": "Estimated TLB CPU percentage of Total CPU", + "MetricName": "tlb_percent", +- "MetricExpr": "((DTLB2_MISSES + ITLB2_MISSES) / CPU_CYCLES) * (L1C_TLB2_MISSES / (L1I_PENALTY_CYCLES + L1D_PENALTY_CYCLES)) * 100" ++ "MetricExpr": "((DTLB2_MISSES + ITLB2_MISSES) / CPU_CYCLES) * (L1C_TLB2_MISSES / (L1I_PENALTY_CYCLES + L1D_PENALTY_CYCLES)) * 100 if has_event(CPU_CYCLES) else 0" + }, + { + "BriefDescription": "Estimated Cycles per TLB Miss", + "MetricName": "tlb_miss", +- "MetricExpr": "((DTLB2_MISSES + ITLB2_MISSES) / (DTLB2_WRITES + ITLB2_WRITES)) * (L1C_TLB2_MISSES / (L1I_PENALTY_CYCLES + L1D_PENALTY_CYCLES))" ++ "MetricExpr": "((DTLB2_MISSES + ITLB2_MISSES) / (DTLB2_WRITES + ITLB2_WRITES)) * (L1C_TLB2_MISSES / (L1I_PENALTY_CYCLES + L1D_PENALTY_CYCLES)) if has_event(DTLB2_MISSES) else 0" + } + ] +diff --git a/tools/perf/tests/Build b/tools/perf/tests/Build +index 63d5e6d5f165b..2b45ffa462a6c 100644 +--- a/tools/perf/tests/Build ++++ b/tools/perf/tests/Build +@@ -66,6 +66,7 @@ perf-y += dlfilter-test.o + perf-y += sigtrap.o + perf-y += event_groups.o + perf-y += symbols.o ++perf-y += util.o + + ifeq ($(SRCARCH),$(filter $(SRCARCH),x86 arm arm64 powerpc)) + perf-$(CONFIG_DWARF_UNWIND) += dwarf-unwind.o +diff --git a/tools/perf/tests/attr/system-wide-dummy b/tools/perf/tests/attr/system-wide-dummy +index 2f3e3eb728eb4..a1e1d6a263bf1 100644 +--- a/tools/perf/tests/attr/system-wide-dummy ++++ b/tools/perf/tests/attr/system-wide-dummy +@@ -9,8 +9,10 @@ flags=8 + type=1 + size=136 + config=9 +-sample_period=4000 +-sample_type=455 ++sample_period=1 ++# PERF_SAMPLE_IP | PERF_SAMPLE_TID | PERF_SAMPLE_TIME | ++# PERF_SAMPLE_CPU | PERF_SAMPLE_IDENTIFIER ++sample_type=65671 + read_format=4|20 + # Event will be enabled right away. + disabled=0 +@@ -18,12 +20,12 @@ inherit=1 + pinned=0 + exclusive=0 + exclude_user=0 +-exclude_kernel=0 +-exclude_hv=0 ++exclude_kernel=1 ++exclude_hv=1 + exclude_idle=0 + mmap=1 + comm=1 +-freq=1 ++freq=0 + inherit_stat=0 + enable_on_exec=0 + task=1 +@@ -32,7 +34,7 @@ precise_ip=0 + mmap_data=0 + sample_id_all=1 + exclude_host=0 +-exclude_guest=0 ++exclude_guest=1 + exclude_callchain_kernel=0 + exclude_callchain_user=0 + mmap2=1 +diff --git a/tools/perf/tests/attr/test-record-C0 b/tools/perf/tests/attr/test-record-C0 +index 317730b906dd3..198e8429a1bf8 100644 +--- a/tools/perf/tests/attr/test-record-C0 ++++ b/tools/perf/tests/attr/test-record-C0 +@@ -10,9 +10,9 @@ cpu=0 + enable_on_exec=0 + + # PERF_SAMPLE_IP | PERF_SAMPLE_TID | PERF_SAMPLE_TIME | +-# PERF_SAMPLE_ID | PERF_SAMPLE_PERIOD ++# PERF_SAMPLE_PERIOD | PERF_SAMPLE_IDENTIFIER + # + PERF_SAMPLE_CPU added by -C 0 +-sample_type=455 ++sample_type=65927 + + # Dummy event handles mmaps, comm and task. + mmap=0 +diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c +index 0ad18cf6dd226..cb6f1dd00dc48 100644 +--- a/tools/perf/tests/builtin-test.c ++++ b/tools/perf/tests/builtin-test.c +@@ -123,6 +123,7 @@ static struct test_suite *generic_tests[] = { + &suite__sigtrap, + &suite__event_groups, + &suite__symbols, ++ &suite__util, + NULL, + }; + +diff --git a/tools/perf/tests/code-reading.c b/tools/perf/tests/code-reading.c +index ed3815163d1be..ff249555ca57a 100644 +--- a/tools/perf/tests/code-reading.c ++++ b/tools/perf/tests/code-reading.c +@@ -657,11 +657,11 @@ static int do_test_code_reading(bool try_kcore) + + evlist__config(evlist, &opts, NULL); + +- evsel = evlist__first(evlist); +- +- evsel->core.attr.comm = 1; +- evsel->core.attr.disabled = 1; +- evsel->core.attr.enable_on_exec = 0; ++ evlist__for_each_entry(evlist, evsel) { ++ evsel->core.attr.comm = 1; ++ evsel->core.attr.disabled = 1; ++ evsel->core.attr.enable_on_exec = 0; ++ } + + ret = evlist__open(evlist); + if (ret < 0) { +diff --git a/tools/perf/tests/expr.c b/tools/perf/tests/expr.c +index 81229fa4f1e96..cea4a506197db 100644 +--- a/tools/perf/tests/expr.c ++++ b/tools/perf/tests/expr.c +@@ -9,6 +9,7 @@ + #include + #include + #include ++#include + #include + + static int test_ids_union(void) +@@ -74,10 +75,13 @@ static int test__expr(struct test_suite *t __maybe_unused, int subtest __maybe_u + int ret; + struct expr_parse_ctx *ctx; + bool is_intel = false; +- char buf[128]; ++ char strcmp_cpuid_buf[256]; ++ struct perf_pmu *pmu = perf_pmus__find_core_pmu(); ++ char *cpuid = perf_pmu__getcpuid(pmu); ++ char *escaped_cpuid1, *escaped_cpuid2; + +- if (!get_cpuid(buf, sizeof(buf))) +- is_intel = strstr(buf, "Intel") != NULL; ++ TEST_ASSERT_VAL("get_cpuid", cpuid); ++ is_intel = strstr(cpuid, "Intel") != NULL; + + TEST_ASSERT_EQUAL("ids_union", test_ids_union(), 0); + +@@ -257,9 +261,28 @@ static int test__expr(struct test_suite *t __maybe_unused, int subtest __maybe_u + TEST_ASSERT_VAL("source count", hashmap__size(ctx->ids) == 1); + TEST_ASSERT_VAL("source count", hashmap__find(ctx->ids, "EVENT1", &val_ptr)); + ++ ++ /* Test no cpuid match */ ++ ret = test(ctx, "strcmp_cpuid_str(0x0)", 0); ++ ++ /* ++ * Test cpuid match with current cpuid. Special chars have to be ++ * escaped. ++ */ ++ escaped_cpuid1 = strreplace_chars('-', cpuid, "\\-"); ++ free(cpuid); ++ escaped_cpuid2 = strreplace_chars(',', escaped_cpuid1, "\\,"); ++ free(escaped_cpuid1); ++ escaped_cpuid1 = strreplace_chars('=', escaped_cpuid2, "\\="); ++ free(escaped_cpuid2); ++ scnprintf(strcmp_cpuid_buf, sizeof(strcmp_cpuid_buf), ++ "strcmp_cpuid_str(%s)", escaped_cpuid1); ++ free(escaped_cpuid1); ++ ret |= test(ctx, strcmp_cpuid_buf, 1); ++ + /* has_event returns 1 when an event exists. */ + expr__add_id_val(ctx, strdup("cycles"), 2); +- ret = test(ctx, "has_event(cycles)", 1); ++ ret |= test(ctx, "has_event(cycles)", 1); + + expr__ctx_free(ctx); + +diff --git a/tools/perf/tests/shell/test_arm_coresight.sh b/tools/perf/tests/shell/test_arm_coresight.sh +index f1bf5621160fb..4d4e685775303 100755 +--- a/tools/perf/tests/shell/test_arm_coresight.sh ++++ b/tools/perf/tests/shell/test_arm_coresight.sh +@@ -186,7 +186,7 @@ arm_cs_etm_snapshot_test() { + + arm_cs_etm_basic_test() { + echo "Recording trace with '$*'" +- perf record -o ${perfdata} "$@" -- ls > /dev/null 2>&1 ++ perf record -o ${perfdata} "$@" -m,8M -- ls > /dev/null 2>&1 + + perf_script_branch_samples ls && + perf_report_branch_samples ls && +diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h +index f33cfc3c19a48..b394f3ac2d667 100644 +--- a/tools/perf/tests/tests.h ++++ b/tools/perf/tests/tests.h +@@ -145,6 +145,7 @@ DECLARE_SUITE(dlfilter); + DECLARE_SUITE(sigtrap); + DECLARE_SUITE(event_groups); + DECLARE_SUITE(symbols); ++DECLARE_SUITE(util); + + /* + * PowerPC and S390 do not support creation of instruction breakpoints using the +diff --git a/tools/perf/tests/util.c b/tools/perf/tests/util.c +new file mode 100644 +index 0000000000000..6366db5cbf8ce +--- /dev/null ++++ b/tools/perf/tests/util.c +@@ -0,0 +1,31 @@ ++// SPDX-License-Identifier: GPL-2.0 ++#include "tests.h" ++#include "util/debug.h" ++ ++#include ++#include ++#include ++ ++static int test_strreplace(char needle, const char *haystack, ++ const char *replace, const char *expected) ++{ ++ char *new = strreplace_chars(needle, haystack, replace); ++ int ret = strcmp(new, expected); ++ ++ free(new); ++ return ret == 0; ++} ++ ++static int test__util(struct test_suite *t __maybe_unused, int subtest __maybe_unused) ++{ ++ TEST_ASSERT_VAL("empty string", test_strreplace(' ', "", "123", "")); ++ TEST_ASSERT_VAL("no match", test_strreplace('5', "123", "4", "123")); ++ TEST_ASSERT_VAL("replace 1", test_strreplace('3', "123", "4", "124")); ++ TEST_ASSERT_VAL("replace 2", test_strreplace('a', "abcabc", "ef", "efbcefbc")); ++ TEST_ASSERT_VAL("replace long", test_strreplace('a', "abcabc", "longlong", ++ "longlongbclonglongbc")); ++ ++ return 0; ++} ++ ++DEFINE_SUITE("util", util); +diff --git a/tools/perf/tests/workloads/datasym.c b/tools/perf/tests/workloads/datasym.c +index ddd40bc63448a..8e08fc75a973e 100644 +--- a/tools/perf/tests/workloads/datasym.c ++++ b/tools/perf/tests/workloads/datasym.c +@@ -16,6 +16,22 @@ static int datasym(int argc __maybe_unused, const char **argv __maybe_unused) + { + for (;;) { + buf1.data1++; ++ if (buf1.data1 == 123) { ++ /* ++ * Add some 'noise' in the loop to work around errata ++ * 1694299 on Arm N1. ++ * ++ * Bias exists in SPE sampling which can cause the load ++ * and store instructions to be skipped entirely. This ++ * comes and goes randomly depending on the offset the ++ * linker places the datasym loop at in the Perf binary. ++ * With an extra branch in the middle of the loop that ++ * isn't always taken, the instruction stream is no ++ * longer a continuous repeating pattern that interacts ++ * badly with the bias. ++ */ ++ buf1.data1++; ++ } + buf1.data2 += buf1.data1; + } + return 0; +diff --git a/tools/perf/ui/browser.c b/tools/perf/ui/browser.c +index 603d11283cbdc..19503e8387385 100644 +--- a/tools/perf/ui/browser.c ++++ b/tools/perf/ui/browser.c +@@ -203,7 +203,7 @@ void ui_browser__refresh_dimensions(struct ui_browser *browser) + void ui_browser__handle_resize(struct ui_browser *browser) + { + ui__refresh_dimensions(false); +- ui_browser__show(browser, browser->title, ui_helpline__current); ++ ui_browser__show(browser, browser->title ?: "", ui_helpline__current); + ui_browser__refresh(browser); + } + +@@ -287,7 +287,8 @@ int ui_browser__show(struct ui_browser *browser, const char *title, + mutex_lock(&ui__lock); + __ui_browser__show_title(browser, title); + +- browser->title = title; ++ free(browser->title); ++ browser->title = strdup(title); + zfree(&browser->helpline); + + va_start(ap, helpline); +@@ -304,6 +305,7 @@ void ui_browser__hide(struct ui_browser *browser) + mutex_lock(&ui__lock); + ui_helpline__pop(); + zfree(&browser->helpline); ++ zfree(&browser->title); + mutex_unlock(&ui__lock); + } + +diff --git a/tools/perf/ui/browser.h b/tools/perf/ui/browser.h +index 510ce45540501..6e98d5f8f71cc 100644 +--- a/tools/perf/ui/browser.h ++++ b/tools/perf/ui/browser.h +@@ -21,7 +21,7 @@ struct ui_browser { + u8 extra_title_lines; + int current_color; + void *priv; +- const char *title; ++ char *title; + char *helpline; + const char *no_samples_msg; + void (*refresh_dimensions)(struct ui_browser *browser); +diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c +index ccdb2cd11fbf0..d9f9fa254a71f 100644 +--- a/tools/perf/ui/browsers/annotate.c ++++ b/tools/perf/ui/browsers/annotate.c +@@ -114,7 +114,7 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int + if (!browser->navkeypressed) + ops.width += 1; + +- annotation_line__write(al, notes, &ops, ab->opts); ++ annotation_line__write(al, notes, &ops); + + if (ops.current_entry) + ab->selection = al; +@@ -337,7 +337,7 @@ static void annotate_browser__calc_percent(struct annotate_browser *browser, + max_percent = percent; + } + +- if (max_percent < 0.01 && pos->al.ipc == 0) { ++ if (max_percent < 0.01 && (!pos->al.cycles || pos->al.cycles->ipc == 0)) { + RB_CLEAR_NODE(&pos->al.rb_node); + continue; + } +@@ -884,7 +884,7 @@ static int annotate_browser__run(struct annotate_browser *browser, + continue; + } + case 'P': +- map_symbol__annotation_dump(ms, evsel, browser->opts); ++ map_symbol__annotation_dump(ms, evsel); + continue; + case 't': + if (symbol_conf.show_total_period) { +@@ -979,7 +979,7 @@ int symbol__tui_annotate(struct map_symbol *ms, struct evsel *evsel, + return -1; + + if (not_annotated) { +- err = symbol__annotate2(ms, evsel, opts, &browser.arch); ++ err = symbol__annotate2(ms, evsel, &browser.arch); + if (err) { + char msg[BUFSIZ]; + dso->annotate_warned = true; +diff --git a/tools/perf/ui/gtk/annotate.c b/tools/perf/ui/gtk/annotate.c +index 2effac77ca8c6..394861245fd3e 100644 +--- a/tools/perf/ui/gtk/annotate.c ++++ b/tools/perf/ui/gtk/annotate.c +@@ -162,7 +162,6 @@ static int perf_gtk__annotate_symbol(GtkWidget *window, struct map_symbol *ms, + } + + static int symbol__gtk_annotate(struct map_symbol *ms, struct evsel *evsel, +- struct annotation_options *options, + struct hist_browser_timer *hbt) + { + struct dso *dso = map__dso(ms->map); +@@ -176,7 +175,7 @@ static int symbol__gtk_annotate(struct map_symbol *ms, struct evsel *evsel, + if (dso->annotate_warned) + return -1; + +- err = symbol__annotate(ms, evsel, options, NULL); ++ err = symbol__annotate(ms, evsel, NULL); + if (err) { + char msg[BUFSIZ]; + dso->annotate_warned = true; +@@ -244,10 +243,9 @@ static int symbol__gtk_annotate(struct map_symbol *ms, struct evsel *evsel, + + int hist_entry__gtk_annotate(struct hist_entry *he, + struct evsel *evsel, +- struct annotation_options *options, + struct hist_browser_timer *hbt) + { +- return symbol__gtk_annotate(&he->ms, evsel, options, hbt); ++ return symbol__gtk_annotate(&he->ms, evsel, hbt); + } + + void perf_gtk__show_annotations(void) +diff --git a/tools/perf/ui/gtk/gtk.h b/tools/perf/ui/gtk/gtk.h +index 1e84dceb52671..a2b497f03fd6e 100644 +--- a/tools/perf/ui/gtk/gtk.h ++++ b/tools/perf/ui/gtk/gtk.h +@@ -56,13 +56,11 @@ struct evsel; + struct evlist; + struct hist_entry; + struct hist_browser_timer; +-struct annotation_options; + + int evlist__gtk_browse_hists(struct evlist *evlist, const char *help, + struct hist_browser_timer *hbt, float min_pcnt); + int hist_entry__gtk_annotate(struct hist_entry *he, + struct evsel *evsel, +- struct annotation_options *options, + struct hist_browser_timer *hbt); + void perf_gtk__show_annotations(void); + +diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c +index 82956adf99632..83da2bceb5959 100644 +--- a/tools/perf/util/annotate.c ++++ b/tools/perf/util/annotate.c +@@ -57,6 +57,9 @@ + + #include + ++/* global annotation options */ ++struct annotation_options annotate_opts; ++ + static regex_t file_lineno; + + static struct ins_ops *ins__find(struct arch *arch, const char *name); +@@ -1100,8 +1103,8 @@ static void annotation__count_and_fill(struct annotation *notes, u64 start, u64 + for (offset = start; offset <= end; offset++) { + struct annotation_line *al = notes->offsets[offset]; + +- if (al && al->ipc == 0.0) { +- al->ipc = ipc; ++ if (al && al->cycles && al->cycles->ipc == 0.0) { ++ al->cycles->ipc = ipc; + cover_insn++; + } + } +@@ -1114,12 +1117,13 @@ static void annotation__count_and_fill(struct annotation *notes, u64 start, u64 + } + } + +-void annotation__compute_ipc(struct annotation *notes, size_t size) ++static int annotation__compute_ipc(struct annotation *notes, size_t size) + { ++ int err = 0; + s64 offset; + + if (!notes->src || !notes->src->cycles_hist) +- return; ++ return 0; + + notes->total_insn = annotation__count_insn(notes, 0, size - 1); + notes->hit_cycles = 0; +@@ -1134,18 +1138,39 @@ void annotation__compute_ipc(struct annotation *notes, size_t size) + if (ch && ch->cycles) { + struct annotation_line *al; + ++ al = notes->offsets[offset]; ++ if (al && al->cycles == NULL) { ++ al->cycles = zalloc(sizeof(*al->cycles)); ++ if (al->cycles == NULL) { ++ err = ENOMEM; ++ break; ++ } ++ } + if (ch->have_start) + annotation__count_and_fill(notes, ch->start, offset, ch); +- al = notes->offsets[offset]; + if (al && ch->num_aggr) { +- al->cycles = ch->cycles_aggr / ch->num_aggr; +- al->cycles_max = ch->cycles_max; +- al->cycles_min = ch->cycles_min; ++ al->cycles->avg = ch->cycles_aggr / ch->num_aggr; ++ al->cycles->max = ch->cycles_max; ++ al->cycles->min = ch->cycles_min; + } + notes->have_cycles = true; + } + } ++ ++ if (err) { ++ while (++offset < (s64)size) { ++ struct cyc_hist *ch = ¬es->src->cycles_hist[offset]; ++ ++ if (ch && ch->cycles) { ++ struct annotation_line *al = notes->offsets[offset]; ++ if (al) ++ zfree(&al->cycles); ++ } ++ } ++ } ++ + annotation__unlock(notes); ++ return 0; + } + + int addr_map_symbol__inc_samples(struct addr_map_symbol *ams, struct perf_sample *sample, +@@ -1225,6 +1250,7 @@ static void annotation_line__exit(struct annotation_line *al) + { + zfree_srcline(&al->path); + zfree(&al->line); ++ zfree(&al->cycles); + } + + static size_t disasm_line_size(int nr) +@@ -1817,7 +1843,6 @@ static int symbol__disassemble_bpf(struct symbol *sym, + struct annotate_args *args) + { + struct annotation *notes = symbol__annotation(sym); +- struct annotation_options *opts = args->options; + struct bpf_prog_linfo *prog_linfo = NULL; + struct bpf_prog_info_node *info_node; + int len = sym->end - sym->start; +@@ -1927,7 +1952,7 @@ static int symbol__disassemble_bpf(struct symbol *sym, + prev_buf_size = buf_size; + fflush(s); + +- if (!opts->hide_src_code && srcline) { ++ if (!annotate_opts.hide_src_code && srcline) { + args->offset = -1; + args->line = strdup(srcline); + args->line_nr = 0; +@@ -2050,7 +2075,7 @@ static char *expand_tabs(char *line, char **storage, size_t *storage_len) + + static int symbol__disassemble(struct symbol *sym, struct annotate_args *args) + { +- struct annotation_options *opts = args->options; ++ struct annotation_options *opts = &annotate_opts; + struct map *map = args->ms.map; + struct dso *dso = map__dso(map); + char *command; +@@ -2300,13 +2325,13 @@ void symbol__calc_percent(struct symbol *sym, struct evsel *evsel) + } + + int symbol__annotate(struct map_symbol *ms, struct evsel *evsel, +- struct annotation_options *options, struct arch **parch) ++ struct arch **parch) + { + struct symbol *sym = ms->sym; + struct annotation *notes = symbol__annotation(sym); + struct annotate_args args = { + .evsel = evsel, +- .options = options, ++ .options = &annotate_opts, + }; + struct perf_env *env = evsel__env(evsel); + const char *arch_name = perf_env__arch(env); +@@ -2334,7 +2359,7 @@ int symbol__annotate(struct map_symbol *ms, struct evsel *evsel, + } + + args.ms = *ms; +- if (notes->options && notes->options->full_addr) ++ if (annotate_opts.full_addr) + notes->start = map__objdump_2mem(ms->map, ms->sym->start); + else + notes->start = map__rip_2objdump(ms->map, ms->sym->start); +@@ -2342,12 +2367,12 @@ int symbol__annotate(struct map_symbol *ms, struct evsel *evsel, + return symbol__disassemble(sym, &args); + } + +-static void insert_source_line(struct rb_root *root, struct annotation_line *al, +- struct annotation_options *opts) ++static void insert_source_line(struct rb_root *root, struct annotation_line *al) + { + struct annotation_line *iter; + struct rb_node **p = &root->rb_node; + struct rb_node *parent = NULL; ++ unsigned int percent_type = annotate_opts.percent_type; + int i, ret; + + while (*p != NULL) { +@@ -2358,7 +2383,7 @@ static void insert_source_line(struct rb_root *root, struct annotation_line *al, + if (ret == 0) { + for (i = 0; i < al->data_nr; i++) { + iter->data[i].percent_sum += annotation_data__percent(&al->data[i], +- opts->percent_type); ++ percent_type); + } + return; + } +@@ -2371,7 +2396,7 @@ static void insert_source_line(struct rb_root *root, struct annotation_line *al, + + for (i = 0; i < al->data_nr; i++) { + al->data[i].percent_sum = annotation_data__percent(&al->data[i], +- opts->percent_type); ++ percent_type); + } + + rb_link_node(&al->rb_node, parent, p); +@@ -2493,8 +2518,7 @@ static int annotated_source__addr_fmt_width(struct list_head *lines, u64 start) + return 0; + } + +-int symbol__annotate_printf(struct map_symbol *ms, struct evsel *evsel, +- struct annotation_options *opts) ++int symbol__annotate_printf(struct map_symbol *ms, struct evsel *evsel) + { + struct map *map = ms->map; + struct symbol *sym = ms->sym; +@@ -2505,6 +2529,7 @@ int symbol__annotate_printf(struct map_symbol *ms, struct evsel *evsel, + struct annotation *notes = symbol__annotation(sym); + struct sym_hist *h = annotation__histogram(notes, evsel->core.idx); + struct annotation_line *pos, *queue = NULL; ++ struct annotation_options *opts = &annotate_opts; + u64 start = map__rip_2objdump(map, sym->start); + int printed = 2, queue_len = 0, addr_fmt_width; + int more = 0; +@@ -2633,8 +2658,7 @@ static void FILE__write_graph(void *fp, int graph) + fputs(s, fp); + } + +-static int symbol__annotate_fprintf2(struct symbol *sym, FILE *fp, +- struct annotation_options *opts) ++static int symbol__annotate_fprintf2(struct symbol *sym, FILE *fp) + { + struct annotation *notes = symbol__annotation(sym); + struct annotation_write_ops wops = { +@@ -2651,7 +2675,7 @@ static int symbol__annotate_fprintf2(struct symbol *sym, FILE *fp, + list_for_each_entry(al, ¬es->src->source, node) { + if (annotation_line__filter(al, notes)) + continue; +- annotation_line__write(al, notes, &wops, opts); ++ annotation_line__write(al, notes, &wops); + fputc('\n', fp); + wops.first_line = false; + } +@@ -2659,8 +2683,7 @@ static int symbol__annotate_fprintf2(struct symbol *sym, FILE *fp, + return 0; + } + +-int map_symbol__annotation_dump(struct map_symbol *ms, struct evsel *evsel, +- struct annotation_options *opts) ++int map_symbol__annotation_dump(struct map_symbol *ms, struct evsel *evsel) + { + const char *ev_name = evsel__name(evsel); + char buf[1024]; +@@ -2682,7 +2705,7 @@ int map_symbol__annotation_dump(struct map_symbol *ms, struct evsel *evsel, + + fprintf(fp, "%s() %s\nEvent: %s\n\n", + ms->sym->name, map__dso(ms->map)->long_name, ev_name); +- symbol__annotate_fprintf2(ms->sym, fp, opts); ++ symbol__annotate_fprintf2(ms->sym, fp); + + fclose(fp); + err = 0; +@@ -2858,24 +2881,24 @@ void annotation__init_column_widths(struct annotation *notes, struct symbol *sym + + void annotation__update_column_widths(struct annotation *notes) + { +- if (notes->options->use_offset) ++ if (annotate_opts.use_offset) + notes->widths.target = notes->widths.min_addr; +- else if (notes->options->full_addr) ++ else if (annotate_opts.full_addr) + notes->widths.target = BITS_PER_LONG / 4; + else + notes->widths.target = notes->widths.max_addr; + + notes->widths.addr = notes->widths.target; + +- if (notes->options->show_nr_jumps) ++ if (annotate_opts.show_nr_jumps) + notes->widths.addr += notes->widths.jumps + 1; + } + + void annotation__toggle_full_addr(struct annotation *notes, struct map_symbol *ms) + { +- notes->options->full_addr = !notes->options->full_addr; ++ annotate_opts.full_addr = !annotate_opts.full_addr; + +- if (notes->options->full_addr) ++ if (annotate_opts.full_addr) + notes->start = map__objdump_2mem(ms->map, ms->sym->start); + else + notes->start = map__rip_2objdump(ms->map, ms->sym->start); +@@ -2883,22 +2906,22 @@ void annotation__toggle_full_addr(struct annotation *notes, struct map_symbol *m + annotation__update_column_widths(notes); + } + +-static void annotation__calc_lines(struct annotation *notes, struct map *map, +- struct rb_root *root, +- struct annotation_options *opts) ++static void annotation__calc_lines(struct annotation *notes, struct map_symbol *ms, ++ struct rb_root *root) + { + struct annotation_line *al; + struct rb_root tmp_root = RB_ROOT; + + list_for_each_entry(al, ¬es->src->source, node) { + double percent_max = 0.0; ++ u64 addr; + int i; + + for (i = 0; i < al->data_nr; i++) { + double percent; + + percent = annotation_data__percent(&al->data[i], +- opts->percent_type); ++ annotate_opts.percent_type); + + if (percent > percent_max) + percent_max = percent; +@@ -2907,24 +2930,23 @@ static void annotation__calc_lines(struct annotation *notes, struct map *map, + if (percent_max <= 0.5) + continue; + +- al->path = get_srcline(map__dso(map), notes->start + al->offset, NULL, +- false, true, notes->start + al->offset); +- insert_source_line(&tmp_root, al, opts); ++ addr = map__rip_2objdump(ms->map, ms->sym->start); ++ al->path = get_srcline(map__dso(ms->map), addr + al->offset, NULL, ++ false, true, ms->sym->start + al->offset); ++ insert_source_line(&tmp_root, al); + } + + resort_source_line(root, &tmp_root); + } + +-static void symbol__calc_lines(struct map_symbol *ms, struct rb_root *root, +- struct annotation_options *opts) ++static void symbol__calc_lines(struct map_symbol *ms, struct rb_root *root) + { + struct annotation *notes = symbol__annotation(ms->sym); + +- annotation__calc_lines(notes, ms->map, root, opts); ++ annotation__calc_lines(notes, ms, root); + } + +-int symbol__tty_annotate2(struct map_symbol *ms, struct evsel *evsel, +- struct annotation_options *opts) ++int symbol__tty_annotate2(struct map_symbol *ms, struct evsel *evsel) + { + struct dso *dso = map__dso(ms->map); + struct symbol *sym = ms->sym; +@@ -2933,7 +2955,7 @@ int symbol__tty_annotate2(struct map_symbol *ms, struct evsel *evsel, + char buf[1024]; + int err; + +- err = symbol__annotate2(ms, evsel, opts, NULL); ++ err = symbol__annotate2(ms, evsel, NULL); + if (err) { + char msg[BUFSIZ]; + +@@ -2943,31 +2965,31 @@ int symbol__tty_annotate2(struct map_symbol *ms, struct evsel *evsel, + return -1; + } + +- if (opts->print_lines) { +- srcline_full_filename = opts->full_path; +- symbol__calc_lines(ms, &source_line, opts); ++ if (annotate_opts.print_lines) { ++ srcline_full_filename = annotate_opts.full_path; ++ symbol__calc_lines(ms, &source_line); + print_summary(&source_line, dso->long_name); + } + + hists__scnprintf_title(hists, buf, sizeof(buf)); + fprintf(stdout, "%s, [percent: %s]\n%s() %s\n", +- buf, percent_type_str(opts->percent_type), sym->name, dso->long_name); +- symbol__annotate_fprintf2(sym, stdout, opts); ++ buf, percent_type_str(annotate_opts.percent_type), sym->name, ++ dso->long_name); ++ symbol__annotate_fprintf2(sym, stdout); + + annotated_source__purge(symbol__annotation(sym)->src); + + return 0; + } + +-int symbol__tty_annotate(struct map_symbol *ms, struct evsel *evsel, +- struct annotation_options *opts) ++int symbol__tty_annotate(struct map_symbol *ms, struct evsel *evsel) + { + struct dso *dso = map__dso(ms->map); + struct symbol *sym = ms->sym; + struct rb_root source_line = RB_ROOT; + int err; + +- err = symbol__annotate(ms, evsel, opts, NULL); ++ err = symbol__annotate(ms, evsel, NULL); + if (err) { + char msg[BUFSIZ]; + +@@ -2979,13 +3001,13 @@ int symbol__tty_annotate(struct map_symbol *ms, struct evsel *evsel, + + symbol__calc_percent(sym, evsel); + +- if (opts->print_lines) { +- srcline_full_filename = opts->full_path; +- symbol__calc_lines(ms, &source_line, opts); ++ if (annotate_opts.print_lines) { ++ srcline_full_filename = annotate_opts.full_path; ++ symbol__calc_lines(ms, &source_line); + print_summary(&source_line, dso->long_name); + } + +- symbol__annotate_printf(ms, evsel, opts); ++ symbol__annotate_printf(ms, evsel); + + annotated_source__purge(symbol__annotation(sym)->src); + +@@ -3046,7 +3068,7 @@ static void disasm_line__write(struct disasm_line *dl, struct annotation *notes, + obj__printf(obj, " "); + } + +- disasm_line__scnprintf(dl, bf, size, !notes->options->use_offset, notes->widths.max_ins_name); ++ disasm_line__scnprintf(dl, bf, size, !annotate_opts.use_offset, notes->widths.max_ins_name); + } + + static void ipc_coverage_string(char *bf, int size, struct annotation *notes) +@@ -3083,8 +3105,8 @@ static void __annotation_line__write(struct annotation_line *al, struct annotati + int printed; + + if (first_line && (al->offset == -1 || percent_max == 0.0)) { +- if (notes->have_cycles) { +- if (al->ipc == 0.0 && al->cycles == 0) ++ if (notes->have_cycles && al->cycles) { ++ if (al->cycles->ipc == 0.0 && al->cycles->avg == 0) + show_title = true; + } else + show_title = true; +@@ -3121,17 +3143,17 @@ static void __annotation_line__write(struct annotation_line *al, struct annotati + } + + if (notes->have_cycles) { +- if (al->ipc) +- obj__printf(obj, "%*.2f ", ANNOTATION__IPC_WIDTH - 1, al->ipc); ++ if (al->cycles && al->cycles->ipc) ++ obj__printf(obj, "%*.2f ", ANNOTATION__IPC_WIDTH - 1, al->cycles->ipc); + else if (!show_title) + obj__printf(obj, "%*s", ANNOTATION__IPC_WIDTH, " "); + else + obj__printf(obj, "%*s ", ANNOTATION__IPC_WIDTH - 1, "IPC"); + +- if (!notes->options->show_minmax_cycle) { +- if (al->cycles) ++ if (!annotate_opts.show_minmax_cycle) { ++ if (al->cycles && al->cycles->avg) + obj__printf(obj, "%*" PRIu64 " ", +- ANNOTATION__CYCLES_WIDTH - 1, al->cycles); ++ ANNOTATION__CYCLES_WIDTH - 1, al->cycles->avg); + else if (!show_title) + obj__printf(obj, "%*s", + ANNOTATION__CYCLES_WIDTH, " "); +@@ -3145,8 +3167,8 @@ static void __annotation_line__write(struct annotation_line *al, struct annotati + + scnprintf(str, sizeof(str), + "%" PRIu64 "(%" PRIu64 "/%" PRIu64 ")", +- al->cycles, al->cycles_min, +- al->cycles_max); ++ al->cycles->avg, al->cycles->min, ++ al->cycles->max); + + obj__printf(obj, "%*s ", + ANNOTATION__MINMAX_CYCLES_WIDTH - 1, +@@ -3172,7 +3194,7 @@ static void __annotation_line__write(struct annotation_line *al, struct annotati + if (!*al->line) + obj__printf(obj, "%-*s", width - pcnt_width - cycles_width, " "); + else if (al->offset == -1) { +- if (al->line_nr && notes->options->show_linenr) ++ if (al->line_nr && annotate_opts.show_linenr) + printed = scnprintf(bf, sizeof(bf), "%-*d ", notes->widths.addr + 1, al->line_nr); + else + printed = scnprintf(bf, sizeof(bf), "%-*s ", notes->widths.addr, " "); +@@ -3182,15 +3204,15 @@ static void __annotation_line__write(struct annotation_line *al, struct annotati + u64 addr = al->offset; + int color = -1; + +- if (!notes->options->use_offset) ++ if (!annotate_opts.use_offset) + addr += notes->start; + +- if (!notes->options->use_offset) { ++ if (!annotate_opts.use_offset) { + printed = scnprintf(bf, sizeof(bf), "%" PRIx64 ": ", addr); + } else { + if (al->jump_sources && +- notes->options->offset_level >= ANNOTATION__OFFSET_JUMP_TARGETS) { +- if (notes->options->show_nr_jumps) { ++ annotate_opts.offset_level >= ANNOTATION__OFFSET_JUMP_TARGETS) { ++ if (annotate_opts.show_nr_jumps) { + int prev; + printed = scnprintf(bf, sizeof(bf), "%*d ", + notes->widths.jumps, +@@ -3204,9 +3226,9 @@ static void __annotation_line__write(struct annotation_line *al, struct annotati + printed = scnprintf(bf, sizeof(bf), "%*" PRIx64 ": ", + notes->widths.target, addr); + } else if (ins__is_call(&disasm_line(al)->ins) && +- notes->options->offset_level >= ANNOTATION__OFFSET_CALL) { ++ annotate_opts.offset_level >= ANNOTATION__OFFSET_CALL) { + goto print_addr; +- } else if (notes->options->offset_level == ANNOTATION__MAX_OFFSET_LEVEL) { ++ } else if (annotate_opts.offset_level == ANNOTATION__MAX_OFFSET_LEVEL) { + goto print_addr; + } else { + printed = scnprintf(bf, sizeof(bf), "%-*s ", +@@ -3228,19 +3250,18 @@ static void __annotation_line__write(struct annotation_line *al, struct annotati + } + + void annotation_line__write(struct annotation_line *al, struct annotation *notes, +- struct annotation_write_ops *wops, +- struct annotation_options *opts) ++ struct annotation_write_ops *wops) + { + __annotation_line__write(al, notes, wops->first_line, wops->current_entry, + wops->change_color, wops->width, wops->obj, +- opts->percent_type, ++ annotate_opts.percent_type, + wops->set_color, wops->set_percent_color, + wops->set_jumps_percent_color, wops->printf, + wops->write_graph); + } + + int symbol__annotate2(struct map_symbol *ms, struct evsel *evsel, +- struct annotation_options *options, struct arch **parch) ++ struct arch **parch) + { + struct symbol *sym = ms->sym; + struct annotation *notes = symbol__annotation(sym); +@@ -3254,17 +3275,21 @@ int symbol__annotate2(struct map_symbol *ms, struct evsel *evsel, + if (evsel__is_group_event(evsel)) + nr_pcnt = evsel->core.nr_members; + +- err = symbol__annotate(ms, evsel, options, parch); ++ err = symbol__annotate(ms, evsel, parch); + if (err) + goto out_free_offsets; + +- notes->options = options; ++ notes->options = &annotate_opts; + + symbol__calc_percent(sym, evsel); + + annotation__set_offsets(notes, size); + annotation__mark_jump_targets(notes, sym); +- annotation__compute_ipc(notes, size); ++ ++ err = annotation__compute_ipc(notes, size); ++ if (err) ++ goto out_free_offsets; ++ + annotation__init_column_widths(notes, sym); + notes->nr_events = nr_pcnt; + +@@ -3382,10 +3407,9 @@ static unsigned int parse_percent_type(char *str1, char *str2) + return type; + } + +-int annotate_parse_percent_type(const struct option *opt, const char *_str, ++int annotate_parse_percent_type(const struct option *opt __maybe_unused, const char *_str, + int unset __maybe_unused) + { +- struct annotation_options *opts = opt->value; + unsigned int type; + char *str1, *str2; + int err = -1; +@@ -3404,7 +3428,7 @@ int annotate_parse_percent_type(const struct option *opt, const char *_str, + if (type == (unsigned int) -1) + type = parse_percent_type(str2, str1); + if (type != (unsigned int) -1) { +- opts->percent_type = type; ++ annotate_opts.percent_type = type; + err = 0; + } + +diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h +index 9627805591760..0fa72eb559ac4 100644 +--- a/tools/perf/util/annotate.h ++++ b/tools/perf/util/annotate.h +@@ -101,6 +101,8 @@ struct annotation_options { + unsigned int percent_type; + }; + ++extern struct annotation_options annotate_opts; ++ + enum { + ANNOTATION__OFFSET_JUMP_TARGETS = 1, + ANNOTATION__OFFSET_CALL, +@@ -130,6 +132,13 @@ struct annotation_data { + struct sym_hist_entry he; + }; + ++struct cycles_info { ++ float ipc; ++ u64 avg; ++ u64 max; ++ u64 min; ++}; ++ + struct annotation_line { + struct list_head node; + struct rb_node rb_node; +@@ -137,12 +146,9 @@ struct annotation_line { + char *line; + int line_nr; + char *fileloc; +- int jump_sources; +- float ipc; +- u64 cycles; +- u64 cycles_max; +- u64 cycles_min; + char *path; ++ struct cycles_info *cycles; ++ int jump_sources; + u32 idx; + int idx_asm; + int data_nr; +@@ -214,8 +220,7 @@ struct annotation_write_ops { + }; + + void annotation_line__write(struct annotation_line *al, struct annotation *notes, +- struct annotation_write_ops *ops, +- struct annotation_options *opts); ++ struct annotation_write_ops *ops); + + int __annotation__scnprintf_samples_period(struct annotation *notes, + char *bf, size_t size, +@@ -325,7 +330,6 @@ static inline bool annotation_line__filter(struct annotation_line *al, struct an + } + + void annotation__set_offsets(struct annotation *notes, s64 size); +-void annotation__compute_ipc(struct annotation *notes, size_t size); + void annotation__mark_jump_targets(struct annotation *notes, struct symbol *sym); + void annotation__update_column_widths(struct annotation *notes); + void annotation__init_column_widths(struct annotation *notes, struct symbol *sym); +@@ -361,11 +365,9 @@ void symbol__annotate_zero_histograms(struct symbol *sym); + + int symbol__annotate(struct map_symbol *ms, + struct evsel *evsel, +- struct annotation_options *options, + struct arch **parch); + int symbol__annotate2(struct map_symbol *ms, + struct evsel *evsel, +- struct annotation_options *options, + struct arch **parch); + + enum symbol_disassemble_errno { +@@ -392,20 +394,18 @@ enum symbol_disassemble_errno { + + int symbol__strerror_disassemble(struct map_symbol *ms, int errnum, char *buf, size_t buflen); + +-int symbol__annotate_printf(struct map_symbol *ms, struct evsel *evsel, +- struct annotation_options *options); ++int symbol__annotate_printf(struct map_symbol *ms, struct evsel *evsel); + void symbol__annotate_zero_histogram(struct symbol *sym, int evidx); + void symbol__annotate_decay_histogram(struct symbol *sym, int evidx); + void annotated_source__purge(struct annotated_source *as); + +-int map_symbol__annotation_dump(struct map_symbol *ms, struct evsel *evsel, +- struct annotation_options *opts); ++int map_symbol__annotation_dump(struct map_symbol *ms, struct evsel *evsel); + + bool ui__has_annotation(void); + +-int symbol__tty_annotate(struct map_symbol *ms, struct evsel *evsel, struct annotation_options *opts); ++int symbol__tty_annotate(struct map_symbol *ms, struct evsel *evsel); + +-int symbol__tty_annotate2(struct map_symbol *ms, struct evsel *evsel, struct annotation_options *opts); ++int symbol__tty_annotate2(struct map_symbol *ms, struct evsel *evsel); + + #ifdef HAVE_SLANG_SUPPORT + int symbol__tui_annotate(struct map_symbol *ms, struct evsel *evsel, +diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c +index 923c0fb151222..68f45e9e63b6e 100644 +--- a/tools/perf/util/event.c ++++ b/tools/perf/util/event.c +@@ -617,13 +617,13 @@ struct map *thread__find_map(struct thread *thread, u8 cpumode, u64 addr, + if (cpumode == PERF_RECORD_MISC_KERNEL && perf_host) { + al->level = 'k'; + maps = machine__kernel_maps(machine); +- load_map = true; ++ load_map = !symbol_conf.lazy_load_kernel_maps; + } else if (cpumode == PERF_RECORD_MISC_USER && perf_host) { + al->level = '.'; + } else if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL && perf_guest) { + al->level = 'g'; + maps = machine__kernel_maps(machine); +- load_map = true; ++ load_map = !symbol_conf.lazy_load_kernel_maps; + } else if (cpumode == PERF_RECORD_MISC_GUEST_USER && perf_guest) { + al->level = 'u'; + } else { +diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c +index 8bf537a29809a..eb1dd29c538d5 100644 +--- a/tools/perf/util/evlist.c ++++ b/tools/perf/util/evlist.c +@@ -1702,6 +1702,24 @@ void evlist__set_tracking_event(struct evlist *evlist, struct evsel *tracking_ev + tracking_evsel->tracking = true; + } + ++struct evsel *evlist__findnew_tracking_event(struct evlist *evlist, bool system_wide) ++{ ++ struct evsel *evsel; ++ ++ evsel = evlist__get_tracking_event(evlist); ++ if (!evsel__is_dummy_event(evsel)) { ++ evsel = evlist__add_aux_dummy(evlist, system_wide); ++ if (!evsel) ++ return NULL; ++ ++ evlist__set_tracking_event(evlist, evsel); ++ } else if (system_wide) { ++ perf_evlist__go_system_wide(&evlist->core, &evsel->core); ++ } ++ ++ return evsel; ++} ++ + struct evsel *evlist__find_evsel_by_str(struct evlist *evlist, const char *str) + { + struct evsel *evsel; +diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h +index d63486261fd2a..cb91dc9117a27 100644 +--- a/tools/perf/util/evlist.h ++++ b/tools/perf/util/evlist.h +@@ -387,6 +387,7 @@ bool evlist_cpu_iterator__end(const struct evlist_cpu_iterator *evlist_cpu_itr); + + struct evsel *evlist__get_tracking_event(struct evlist *evlist); + void evlist__set_tracking_event(struct evlist *evlist, struct evsel *tracking_evsel); ++struct evsel *evlist__findnew_tracking_event(struct evlist *evlist, bool system_wide); + + struct evsel *evlist__find_evsel_by_str(struct evlist *evlist, const char *str); + +diff --git a/tools/perf/util/expr.c b/tools/perf/util/expr.c +index 80cf2478f98fc..b8875aac8f870 100644 +--- a/tools/perf/util/expr.c ++++ b/tools/perf/util/expr.c +@@ -527,7 +527,7 @@ double expr__strcmp_cpuid_str(const struct expr_parse_ctx *ctx __maybe_unused, + bool compute_ids __maybe_unused, const char *test_id) + { + double ret; +- struct perf_pmu *pmu = pmu__find_core_pmu(); ++ struct perf_pmu *pmu = perf_pmus__find_core_pmu(); + char *cpuid = perf_pmu__getcpuid(pmu); + + if (!cpuid) +diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c +index b450178e3420b..e733f6b1f7ac5 100644 +--- a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c ++++ b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c +@@ -1319,6 +1319,8 @@ static bool intel_pt_fup_event(struct intel_pt_decoder *decoder, bool no_tip) + bool ret = false; + + decoder->state.type &= ~INTEL_PT_BRANCH; ++ decoder->state.insn_op = INTEL_PT_OP_OTHER; ++ decoder->state.insn_len = 0; + + if (decoder->set_fup_cfe_ip || decoder->set_fup_cfe) { + bool ip = decoder->set_fup_cfe_ip; +diff --git a/tools/perf/util/intel-pt.c b/tools/perf/util/intel-pt.c +index f38893e0b0369..4db9a098f5926 100644 +--- a/tools/perf/util/intel-pt.c ++++ b/tools/perf/util/intel-pt.c +@@ -764,6 +764,7 @@ static int intel_pt_walk_next_insn(struct intel_pt_insn *intel_pt_insn, + + addr_location__init(&al); + intel_pt_insn->length = 0; ++ intel_pt_insn->op = INTEL_PT_OP_OTHER; + + if (to_ip && *ip == to_ip) + goto out_no_cache; +@@ -898,6 +899,7 @@ static int intel_pt_walk_next_insn(struct intel_pt_insn *intel_pt_insn, + + if (to_ip && *ip == to_ip) { + intel_pt_insn->length = 0; ++ intel_pt_insn->op = INTEL_PT_OP_OTHER; + goto out_no_cache; + } + +diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c +index e6a8d758f6fe4..7c6874804660e 100644 +--- a/tools/perf/util/machine.c ++++ b/tools/perf/util/machine.c +@@ -2158,9 +2158,13 @@ int machine__process_exit_event(struct machine *machine, union perf_event *event + if (dump_trace) + perf_event__fprintf_task(event, stdout); + +- if (thread != NULL) +- thread__put(thread); +- ++ if (thread != NULL) { ++ if (symbol_conf.keep_exited_threads) ++ thread__set_exited(thread, /*exited=*/true); ++ else ++ machine__remove_thread(machine, thread); ++ } ++ thread__put(thread); + return 0; + } + +diff --git a/tools/perf/util/maps.c b/tools/perf/util/maps.c +index 233438c95b531..9a011aed4b754 100644 +--- a/tools/perf/util/maps.c ++++ b/tools/perf/util/maps.c +@@ -475,3 +475,241 @@ struct map_rb_node *map_rb_node__next(struct map_rb_node *node) + + return rb_entry(next, struct map_rb_node, rb_node); + } ++ ++static int map__strcmp(const void *a, const void *b) ++{ ++ const struct map *map_a = *(const struct map **)a; ++ const struct map *map_b = *(const struct map **)b; ++ const struct dso *dso_a = map__dso(map_a); ++ const struct dso *dso_b = map__dso(map_b); ++ int ret = strcmp(dso_a->short_name, dso_b->short_name); ++ ++ if (ret == 0 && map_a != map_b) { ++ /* ++ * Ensure distinct but name equal maps have an order in part to ++ * aid reference counting. ++ */ ++ ret = (int)map__start(map_a) - (int)map__start(map_b); ++ if (ret == 0) ++ ret = (int)((intptr_t)map_a - (intptr_t)map_b); ++ } ++ ++ return ret; ++} ++ ++static int map__strcmp_name(const void *name, const void *b) ++{ ++ const struct dso *dso = map__dso(*(const struct map **)b); ++ ++ return strcmp(name, dso->short_name); ++} ++ ++void __maps__sort_by_name(struct maps *maps) ++{ ++ qsort(maps__maps_by_name(maps), maps__nr_maps(maps), sizeof(struct map *), map__strcmp); ++} ++ ++static int map__groups__sort_by_name_from_rbtree(struct maps *maps) ++{ ++ struct map_rb_node *rb_node; ++ struct map **maps_by_name = realloc(maps__maps_by_name(maps), ++ maps__nr_maps(maps) * sizeof(struct map *)); ++ int i = 0; ++ ++ if (maps_by_name == NULL) ++ return -1; ++ ++ up_read(maps__lock(maps)); ++ down_write(maps__lock(maps)); ++ ++ RC_CHK_ACCESS(maps)->maps_by_name = maps_by_name; ++ RC_CHK_ACCESS(maps)->nr_maps_allocated = maps__nr_maps(maps); ++ ++ maps__for_each_entry(maps, rb_node) ++ maps_by_name[i++] = map__get(rb_node->map); ++ ++ __maps__sort_by_name(maps); ++ ++ up_write(maps__lock(maps)); ++ down_read(maps__lock(maps)); ++ ++ return 0; ++} ++ ++static struct map *__maps__find_by_name(struct maps *maps, const char *name) ++{ ++ struct map **mapp; ++ ++ if (maps__maps_by_name(maps) == NULL && ++ map__groups__sort_by_name_from_rbtree(maps)) ++ return NULL; ++ ++ mapp = bsearch(name, maps__maps_by_name(maps), maps__nr_maps(maps), ++ sizeof(*mapp), map__strcmp_name); ++ if (mapp) ++ return *mapp; ++ return NULL; ++} ++ ++struct map *maps__find_by_name(struct maps *maps, const char *name) ++{ ++ struct map_rb_node *rb_node; ++ struct map *map; ++ ++ down_read(maps__lock(maps)); ++ ++ ++ if (RC_CHK_ACCESS(maps)->last_search_by_name) { ++ const struct dso *dso = map__dso(RC_CHK_ACCESS(maps)->last_search_by_name); ++ ++ if (strcmp(dso->short_name, name) == 0) { ++ map = RC_CHK_ACCESS(maps)->last_search_by_name; ++ goto out_unlock; ++ } ++ } ++ /* ++ * If we have maps->maps_by_name, then the name isn't in the rbtree, ++ * as maps->maps_by_name mirrors the rbtree when lookups by name are ++ * made. ++ */ ++ map = __maps__find_by_name(maps, name); ++ if (map || maps__maps_by_name(maps) != NULL) ++ goto out_unlock; ++ ++ /* Fallback to traversing the rbtree... */ ++ maps__for_each_entry(maps, rb_node) { ++ struct dso *dso; ++ ++ map = rb_node->map; ++ dso = map__dso(map); ++ if (strcmp(dso->short_name, name) == 0) { ++ RC_CHK_ACCESS(maps)->last_search_by_name = map; ++ goto out_unlock; ++ } ++ } ++ map = NULL; ++ ++out_unlock: ++ up_read(maps__lock(maps)); ++ return map; ++} ++ ++void maps__fixup_end(struct maps *maps) ++{ ++ struct map_rb_node *prev = NULL, *curr; ++ ++ down_write(maps__lock(maps)); ++ ++ maps__for_each_entry(maps, curr) { ++ if (prev != NULL && !map__end(prev->map)) ++ map__set_end(prev->map, map__start(curr->map)); ++ ++ prev = curr; ++ } ++ ++ /* ++ * We still haven't the actual symbols, so guess the ++ * last map final address. ++ */ ++ if (curr && !map__end(curr->map)) ++ map__set_end(curr->map, ~0ULL); ++ ++ up_write(maps__lock(maps)); ++} ++ ++/* ++ * Merges map into maps by splitting the new map within the existing map ++ * regions. ++ */ ++int maps__merge_in(struct maps *kmaps, struct map *new_map) ++{ ++ struct map_rb_node *rb_node; ++ LIST_HEAD(merged); ++ int err = 0; ++ ++ maps__for_each_entry(kmaps, rb_node) { ++ struct map *old_map = rb_node->map; ++ ++ /* no overload with this one */ ++ if (map__end(new_map) < map__start(old_map) || ++ map__start(new_map) >= map__end(old_map)) ++ continue; ++ ++ if (map__start(new_map) < map__start(old_map)) { ++ /* ++ * |new...... ++ * |old.... ++ */ ++ if (map__end(new_map) < map__end(old_map)) { ++ /* ++ * |new......| -> |new..| ++ * |old....| -> |old....| ++ */ ++ map__set_end(new_map, map__start(old_map)); ++ } else { ++ /* ++ * |new.............| -> |new..| |new..| ++ * |old....| -> |old....| ++ */ ++ struct map_list_node *m = map_list_node__new(); ++ ++ if (!m) { ++ err = -ENOMEM; ++ goto out; ++ } ++ ++ m->map = map__clone(new_map); ++ if (!m->map) { ++ free(m); ++ err = -ENOMEM; ++ goto out; ++ } ++ ++ map__set_end(m->map, map__start(old_map)); ++ list_add_tail(&m->node, &merged); ++ map__add_pgoff(new_map, map__end(old_map) - map__start(new_map)); ++ map__set_start(new_map, map__end(old_map)); ++ } ++ } else { ++ /* ++ * |new...... ++ * |old.... ++ */ ++ if (map__end(new_map) < map__end(old_map)) { ++ /* ++ * |new..| -> x ++ * |old.........| -> |old.........| ++ */ ++ map__put(new_map); ++ new_map = NULL; ++ break; ++ } else { ++ /* ++ * |new......| -> |new...| ++ * |old....| -> |old....| ++ */ ++ map__add_pgoff(new_map, map__end(old_map) - map__start(new_map)); ++ map__set_start(new_map, map__end(old_map)); ++ } ++ } ++ } ++ ++out: ++ while (!list_empty(&merged)) { ++ struct map_list_node *old_node; ++ ++ old_node = list_entry(merged.next, struct map_list_node, node); ++ list_del_init(&old_node->node); ++ if (!err) ++ err = maps__insert(kmaps, old_node->map); ++ map__put(old_node->map); ++ free(old_node); ++ } ++ ++ if (new_map) { ++ if (!err) ++ err = maps__insert(kmaps, new_map); ++ map__put(new_map); ++ } ++ return err; ++} +diff --git a/tools/perf/util/maps.h b/tools/perf/util/maps.h +index 83144e0645ed4..a689149be8c43 100644 +--- a/tools/perf/util/maps.h ++++ b/tools/perf/util/maps.h +@@ -21,6 +21,16 @@ struct map_rb_node { + struct map *map; + }; + ++struct map_list_node { ++ struct list_head node; ++ struct map *map; ++}; ++ ++static inline struct map_list_node *map_list_node__new(void) ++{ ++ return malloc(sizeof(struct map_list_node)); ++} ++ + struct map_rb_node *maps__first(struct maps *maps); + struct map_rb_node *map_rb_node__next(struct map_rb_node *node); + struct map_rb_node *maps__find_node(struct maps *maps, struct map *map); +@@ -133,4 +143,6 @@ int maps__merge_in(struct maps *kmaps, struct map *new_map); + + void __maps__sort_by_name(struct maps *maps); + ++void maps__fixup_end(struct maps *maps); ++ + #endif // __PERF_MAPS_H +diff --git a/tools/perf/util/perf_event_attr_fprintf.c b/tools/perf/util/perf_event_attr_fprintf.c +index 2247991451f3a..1c1582688f037 100644 +--- a/tools/perf/util/perf_event_attr_fprintf.c ++++ b/tools/perf/util/perf_event_attr_fprintf.c +@@ -7,6 +7,8 @@ + #include + #include + #include "util/evsel_fprintf.h" ++#include "util/pmu.h" ++#include "util/pmus.h" + #include "trace-event.h" + + struct bit_names { +@@ -74,9 +76,12 @@ static void __p_read_format(char *buf, size_t size, u64 value) + } + + #define ENUM_ID_TO_STR_CASE(x) case x: return (#x); +-static const char *stringify_perf_type_id(u64 value) ++static const char *stringify_perf_type_id(struct perf_pmu *pmu, u32 type) + { +- switch (value) { ++ if (pmu) ++ return pmu->name; ++ ++ switch (type) { + ENUM_ID_TO_STR_CASE(PERF_TYPE_HARDWARE) + ENUM_ID_TO_STR_CASE(PERF_TYPE_SOFTWARE) + ENUM_ID_TO_STR_CASE(PERF_TYPE_TRACEPOINT) +@@ -174,9 +179,9 @@ do { \ + #define print_id_unsigned(_s) PRINT_ID(_s, "%"PRIu64) + #define print_id_hex(_s) PRINT_ID(_s, "%#"PRIx64) + +-static void __p_type_id(char *buf, size_t size, u64 value) ++static void __p_type_id(struct perf_pmu *pmu, char *buf, size_t size, u64 value) + { +- print_id_unsigned(stringify_perf_type_id(value)); ++ print_id_unsigned(stringify_perf_type_id(pmu, value)); + } + + static void __p_config_hw_id(char *buf, size_t size, u64 value) +@@ -216,8 +221,14 @@ static void __p_config_tracepoint_id(char *buf, size_t size, u64 value) + } + #endif + +-static void __p_config_id(char *buf, size_t size, u32 type, u64 value) ++static void __p_config_id(struct perf_pmu *pmu, char *buf, size_t size, u32 type, u64 value) + { ++ const char *name = perf_pmu__name_from_config(pmu, value); ++ ++ if (name) { ++ print_id_hex(name); ++ return; ++ } + switch (type) { + case PERF_TYPE_HARDWARE: + return __p_config_hw_id(buf, size, value); +@@ -245,8 +256,8 @@ static void __p_config_id(char *buf, size_t size, u32 type, u64 value) + #define p_sample_type(val) __p_sample_type(buf, BUF_SIZE, val) + #define p_branch_sample_type(val) __p_branch_sample_type(buf, BUF_SIZE, val) + #define p_read_format(val) __p_read_format(buf, BUF_SIZE, val) +-#define p_type_id(val) __p_type_id(buf, BUF_SIZE, val) +-#define p_config_id(val) __p_config_id(buf, BUF_SIZE, attr->type, val) ++#define p_type_id(val) __p_type_id(pmu, buf, BUF_SIZE, val) ++#define p_config_id(val) __p_config_id(pmu, buf, BUF_SIZE, attr->type, val) + + #define PRINT_ATTRn(_n, _f, _p, _a) \ + do { \ +@@ -261,6 +272,7 @@ do { \ + int perf_event_attr__fprintf(FILE *fp, struct perf_event_attr *attr, + attr__fprintf_f attr__fprintf, void *priv) + { ++ struct perf_pmu *pmu = perf_pmus__find_by_type(attr->type); + char buf[BUF_SIZE]; + int ret = 0; + +diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c +index 86bfdf5db2135..27393e4327922 100644 +--- a/tools/perf/util/pmu.c ++++ b/tools/perf/util/pmu.c +@@ -28,6 +28,7 @@ + #include "strbuf.h" + #include "fncache.h" + #include "util/evsel_config.h" ++#include + + struct perf_pmu perf_pmu__fake = { + .name = "fake", +@@ -35,6 +36,18 @@ struct perf_pmu perf_pmu__fake = { + + #define UNIT_MAX_LEN 31 /* max length for event unit name */ + ++enum event_source { ++ /* An event loaded from /sys/devices//events. */ ++ EVENT_SRC_SYSFS, ++ /* An event loaded from a CPUID matched json file. */ ++ EVENT_SRC_CPU_JSON, ++ /* ++ * An event loaded from a /sys/devices//identifier matched json ++ * file. ++ */ ++ EVENT_SRC_SYS_JSON, ++}; ++ + /** + * struct perf_pmu_alias - An event either read from sysfs or builtin in + * pmu-events.c, created by parsing the pmu-events json files. +@@ -424,9 +437,30 @@ static struct perf_pmu_alias *perf_pmu__find_alias(struct perf_pmu *pmu, + { + struct perf_pmu_alias *alias; + +- if (load && !pmu->sysfs_aliases_loaded) +- pmu_aliases_parse(pmu); ++ if (load && !pmu->sysfs_aliases_loaded) { ++ bool has_sysfs_event; ++ char event_file_name[FILENAME_MAX + 8]; + ++ /* ++ * Test if alias/event 'name' exists in the PMU's sysfs/events ++ * directory. If not skip parsing the sysfs aliases. Sysfs event ++ * name must be all lower or all upper case. ++ */ ++ scnprintf(event_file_name, sizeof(event_file_name), "events/%s", name); ++ for (size_t i = 7, n = 7 + strlen(name); i < n; i++) ++ event_file_name[i] = tolower(event_file_name[i]); ++ ++ has_sysfs_event = perf_pmu__file_exists(pmu, event_file_name); ++ if (!has_sysfs_event) { ++ for (size_t i = 7, n = 7 + strlen(name); i < n; i++) ++ event_file_name[i] = toupper(event_file_name[i]); ++ ++ has_sysfs_event = perf_pmu__file_exists(pmu, event_file_name); ++ } ++ if (has_sysfs_event) ++ pmu_aliases_parse(pmu); ++ ++ } + list_for_each_entry(alias, &pmu->aliases, list) { + if (!strcasecmp(alias->name, name)) + return alias; +@@ -499,7 +533,7 @@ static int update_alias(const struct pmu_event *pe, + + static int perf_pmu__new_alias(struct perf_pmu *pmu, const char *name, + const char *desc, const char *val, FILE *val_fd, +- const struct pmu_event *pe) ++ const struct pmu_event *pe, enum event_source src) + { + struct perf_pmu_alias *alias; + int ret; +@@ -551,25 +585,30 @@ static int perf_pmu__new_alias(struct perf_pmu *pmu, const char *name, + } + snprintf(alias->unit, sizeof(alias->unit), "%s", unit); + } +- if (!pe) { +- /* Update an event from sysfs with json data. */ +- struct update_alias_data data = { +- .pmu = pmu, +- .alias = alias, +- }; +- ++ switch (src) { ++ default: ++ case EVENT_SRC_SYSFS: + alias->from_sysfs = true; + if (pmu->events_table) { ++ /* Update an event from sysfs with json data. */ ++ struct update_alias_data data = { ++ .pmu = pmu, ++ .alias = alias, ++ }; + if (pmu_events_table__find_event(pmu->events_table, pmu, name, + update_alias, &data) == 0) +- pmu->loaded_json_aliases++; ++ pmu->cpu_json_aliases++; + } +- } +- +- if (!pe) + pmu->sysfs_aliases++; +- else +- pmu->loaded_json_aliases++; ++ break; ++ case EVENT_SRC_CPU_JSON: ++ pmu->cpu_json_aliases++; ++ break; ++ case EVENT_SRC_SYS_JSON: ++ pmu->sys_json_aliases++; ++ break; ++ ++ } + list_add_tail(&alias->list, &pmu->aliases); + return 0; + } +@@ -645,7 +684,8 @@ static int pmu_aliases_parse(struct perf_pmu *pmu) + } + + if (perf_pmu__new_alias(pmu, name, /*desc=*/ NULL, +- /*val=*/ NULL, file, /*pe=*/ NULL) < 0) ++ /*val=*/ NULL, file, /*pe=*/ NULL, ++ EVENT_SRC_SYSFS) < 0) + pr_debug("Cannot set up %s\n", name); + fclose(file); + } +@@ -874,13 +914,36 @@ static bool pmu_uncore_alias_match(const char *pmu_name, const char *name) + return res; + } + ++bool pmu_uncore_identifier_match(const char *compat, const char *id) ++{ ++ regex_t re; ++ regmatch_t pmatch[1]; ++ int match; ++ ++ if (regcomp(&re, compat, REG_EXTENDED) != 0) { ++ /* Warn unable to generate match particular string. */ ++ pr_info("Invalid regular expression %s\n", compat); ++ return false; ++ } ++ ++ match = !regexec(&re, id, 1, pmatch, 0); ++ if (match) { ++ /* Ensure a full match. */ ++ match = pmatch[0].rm_so == 0 && (size_t)pmatch[0].rm_eo == strlen(id); ++ } ++ regfree(&re); ++ ++ return match; ++} ++ + static int pmu_add_cpu_aliases_map_callback(const struct pmu_event *pe, + const struct pmu_events_table *table __maybe_unused, + void *vdata) + { + struct perf_pmu *pmu = vdata; + +- perf_pmu__new_alias(pmu, pe->name, pe->desc, pe->event, /*val_fd=*/ NULL, pe); ++ perf_pmu__new_alias(pmu, pe->name, pe->desc, pe->event, /*val_fd=*/ NULL, ++ pe, EVENT_SRC_CPU_JSON); + return 0; + } + +@@ -914,14 +977,15 @@ static int pmu_add_sys_aliases_iter_fn(const struct pmu_event *pe, + if (!pe->compat || !pe->pmu) + return 0; + +- if (!strcmp(pmu->id, pe->compat) && +- pmu_uncore_alias_match(pe->pmu, pmu->name)) { ++ if (pmu_uncore_alias_match(pe->pmu, pmu->name) && ++ pmu_uncore_identifier_match(pe->compat, pmu->id)) { + perf_pmu__new_alias(pmu, + pe->name, + pe->desc, + pe->event, + /*val_fd=*/ NULL, +- pe); ++ pe, ++ EVENT_SRC_SYS_JSON); + } + + return 0; +@@ -1011,6 +1075,12 @@ struct perf_pmu *perf_pmu__lookup(struct list_head *pmus, int dirfd, const char + pmu->id = pmu_id(name); + pmu->max_precise = pmu_max_precise(dirfd, pmu); + pmu->events_table = perf_pmu__find_events_table(pmu); ++ /* ++ * Load the sys json events/aliases when loading the PMU as each event ++ * may have a different compat regular expression. We therefore can't ++ * know the number of sys json events/aliases without computing the ++ * regular expressions for them all. ++ */ + pmu_add_sys_aliases(pmu); + list_add_tail(&pmu->list, pmus); + +@@ -1604,15 +1674,15 @@ size_t perf_pmu__num_events(struct perf_pmu *pmu) + { + size_t nr; + +- if (!pmu->sysfs_aliases_loaded) +- pmu_aliases_parse(pmu); +- +- nr = pmu->sysfs_aliases; ++ pmu_aliases_parse(pmu); ++ nr = pmu->sysfs_aliases + pmu->sys_json_aliases;; + + if (pmu->cpu_aliases_added) +- nr += pmu->loaded_json_aliases; ++ nr += pmu->cpu_json_aliases; + else if (pmu->events_table) +- nr += pmu_events_table__num_events(pmu->events_table, pmu) - pmu->loaded_json_aliases; ++ nr += pmu_events_table__num_events(pmu->events_table, pmu) - pmu->cpu_json_aliases; ++ else ++ assert(pmu->cpu_json_aliases == 0); + + return pmu->selectable ? nr + 1 : nr; + } +@@ -1665,6 +1735,7 @@ int perf_pmu__for_each_event(struct perf_pmu *pmu, bool skip_duplicate_pmus, + struct strbuf sb; + + strbuf_init(&sb, /*hint=*/ 0); ++ pmu_aliases_parse(pmu); + pmu_add_cpu_aliases(pmu); + list_for_each_entry(event, &pmu->aliases, list) { + size_t buf_used; +@@ -2059,19 +2130,21 @@ void perf_pmu__delete(struct perf_pmu *pmu) + free(pmu); + } + +-struct perf_pmu *pmu__find_core_pmu(void) ++const char *perf_pmu__name_from_config(struct perf_pmu *pmu, u64 config) + { +- struct perf_pmu *pmu = NULL; ++ struct perf_pmu_alias *event; + +- while ((pmu = perf_pmus__scan_core(pmu))) { +- /* +- * The cpumap should cover all CPUs. Otherwise, some CPUs may +- * not support some events or have different event IDs. +- */ +- if (RC_CHK_ACCESS(pmu->cpus)->nr != cpu__max_cpu().cpu) +- return NULL; ++ if (!pmu) ++ return NULL; ++ ++ pmu_aliases_parse(pmu); ++ pmu_add_cpu_aliases(pmu); ++ list_for_each_entry(event, &pmu->aliases, list) { ++ struct perf_event_attr attr = {.config = 0,}; ++ int ret = perf_pmu__config(pmu, &attr, &event->terms, NULL); + +- return pmu; ++ if (ret == 0 && config == attr.config) ++ return event->name; + } + return NULL; + } +diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h +index 6a4e170c61d6b..aca4238f06a65 100644 +--- a/tools/perf/util/pmu.h ++++ b/tools/perf/util/pmu.h +@@ -120,8 +120,10 @@ struct perf_pmu { + const struct pmu_events_table *events_table; + /** @sysfs_aliases: Number of sysfs aliases loaded. */ + uint32_t sysfs_aliases; +- /** @sysfs_aliases: Number of json event aliases loaded. */ +- uint32_t loaded_json_aliases; ++ /** @cpu_json_aliases: Number of json event aliases loaded specific to the CPUID. */ ++ uint32_t cpu_json_aliases; ++ /** @sys_json_aliases: Number of json event aliases loaded matching the PMU's identifier. */ ++ uint32_t sys_json_aliases; + /** @sysfs_aliases_loaded: Are sysfs aliases loaded from disk? */ + bool sysfs_aliases_loaded; + /** +@@ -240,6 +242,7 @@ void pmu_add_cpu_aliases_table(struct perf_pmu *pmu, + char *perf_pmu__getcpuid(struct perf_pmu *pmu); + const struct pmu_events_table *pmu_events_table__find(void); + const struct pmu_metrics_table *pmu_metrics_table__find(void); ++bool pmu_uncore_identifier_match(const char *compat, const char *id); + + int perf_pmu__convert_scale(const char *scale, char **end, double *sval); + +@@ -264,6 +267,7 @@ int perf_pmu__pathname_fd(int dirfd, const char *pmu_name, const char *filename, + struct perf_pmu *perf_pmu__lookup(struct list_head *pmus, int dirfd, const char *lookup_name); + struct perf_pmu *perf_pmu__create_placeholder_core_pmu(struct list_head *core_pmus); + void perf_pmu__delete(struct perf_pmu *pmu); +-struct perf_pmu *pmu__find_core_pmu(void); ++struct perf_pmu *perf_pmus__find_core_pmu(void); ++const char *perf_pmu__name_from_config(struct perf_pmu *pmu, u64 config); + + #endif /* __PMU_H */ +diff --git a/tools/perf/util/pmus.c b/tools/perf/util/pmus.c +index 6631367c756fd..cec869cbe163a 100644 +--- a/tools/perf/util/pmus.c ++++ b/tools/perf/util/pmus.c +@@ -10,6 +10,7 @@ + #include + #include + #include ++#include "cpumap.h" + #include "debug.h" + #include "evsel.h" + #include "pmus.h" +@@ -268,7 +269,7 @@ struct perf_pmu *perf_pmus__scan_core(struct perf_pmu *pmu) + { + if (!pmu) { + pmu_read_sysfs(/*core_only=*/true); +- pmu = list_prepare_entry(pmu, &core_pmus, list); ++ return list_first_entry_or_null(&core_pmus, typeof(*pmu), list); + } + list_for_each_entry_continue(pmu, &core_pmus, list) + return pmu; +@@ -592,3 +593,20 @@ struct perf_pmu *evsel__find_pmu(const struct evsel *evsel) + } + return pmu; + } ++ ++struct perf_pmu *perf_pmus__find_core_pmu(void) ++{ ++ struct perf_pmu *pmu = NULL; ++ ++ while ((pmu = perf_pmus__scan_core(pmu))) { ++ /* ++ * The cpumap should cover all CPUs. Otherwise, some CPUs may ++ * not support some events or have different event IDs. ++ */ ++ if (RC_CHK_ACCESS(pmu->cpus)->nr != cpu__max_cpu().cpu) ++ return NULL; ++ ++ return pmu; ++ } ++ return NULL; ++} +diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c +index 1a5b7fa459b23..4026cea9fc3a2 100644 +--- a/tools/perf/util/probe-event.c ++++ b/tools/perf/util/probe-event.c +@@ -11,6 +11,7 @@ + #include + #include + #include ++#include + #include + #include + #include +diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c +index c29f5f0bb552c..b01b0e5510563 100644 +--- a/tools/perf/util/python.c ++++ b/tools/perf/util/python.c +@@ -103,6 +103,16 @@ int perf_pmu__scan_file(struct perf_pmu *pmu, const char *name, const char *fmt, + return EOF; + } + ++const char *perf_pmu__name_from_config(struct perf_pmu *pmu __maybe_unused, u64 config __maybe_unused) ++{ ++ return NULL; ++} ++ ++struct perf_pmu *perf_pmus__find_by_type(unsigned int type __maybe_unused) ++{ ++ return NULL; ++} ++ + int perf_pmus__num_core_pmus(void) + { + return 1; +diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c +index 1e9aa8ed15b64..c6afba7ab1a51 100644 +--- a/tools/perf/util/session.c ++++ b/tools/perf/util/session.c +@@ -115,6 +115,11 @@ static int perf_session__open(struct perf_session *session, int repipe_fd) + return -1; + } + ++ if (perf_header__has_feat(&session->header, HEADER_AUXTRACE)) { ++ /* Auxiliary events may reference exited threads, hold onto dead ones. */ ++ symbol_conf.keep_exited_threads = true; ++ } ++ + if (perf_data__is_pipe(data)) + return 0; + +diff --git a/tools/perf/util/stat-display.c b/tools/perf/util/stat-display.c +index 969ce40096330..0abe35388ab15 100644 +--- a/tools/perf/util/stat-display.c ++++ b/tools/perf/util/stat-display.c +@@ -1207,6 +1207,9 @@ static void print_metric_headers(struct perf_stat_config *config, + + /* Print metrics headers only */ + evlist__for_each_entry(evlist, counter) { ++ if (config->aggr_mode != AGGR_NONE && counter->metric_leader != counter) ++ continue; ++ + os.evsel = counter; + + perf_stat__print_shadow_stats(config, counter, 0, +diff --git a/tools/perf/util/string.c b/tools/perf/util/string.c +index cf05b0b56c57b..116a642ad99d1 100644 +--- a/tools/perf/util/string.c ++++ b/tools/perf/util/string.c +@@ -301,3 +301,51 @@ unsigned int hex(char c) + return c - 'a' + 10; + return c - 'A' + 10; + } ++ ++/* ++ * Replace all occurrences of character 'needle' in string 'haystack' with ++ * string 'replace' ++ * ++ * The new string could be longer so a new string is returned which must be ++ * freed. ++ */ ++char *strreplace_chars(char needle, const char *haystack, const char *replace) ++{ ++ int replace_len = strlen(replace); ++ char *new_s, *to; ++ const char *loc = strchr(haystack, needle); ++ const char *from = haystack; ++ int num = 0; ++ ++ /* Count occurrences */ ++ while (loc) { ++ loc = strchr(loc + 1, needle); ++ num++; ++ } ++ ++ /* Allocate enough space for replacements and reset first location */ ++ new_s = malloc(strlen(haystack) + (num * (replace_len - 1) + 1)); ++ if (!new_s) ++ return NULL; ++ loc = strchr(haystack, needle); ++ to = new_s; ++ ++ while (loc) { ++ /* Copy original string up to found char and update positions */ ++ memcpy(to, from, 1 + loc - from); ++ to += loc - from; ++ from = loc + 1; ++ ++ /* Copy replacement string and update positions */ ++ memcpy(to, replace, replace_len); ++ to += replace_len; ++ ++ /* needle next occurrence or end of string */ ++ loc = strchr(from, needle); ++ } ++ ++ /* Copy any remaining chars + null */ ++ strcpy(to, from); ++ ++ return new_s; ++} +diff --git a/tools/perf/util/string2.h b/tools/perf/util/string2.h +index 56c30fef9682f..52cb8ba057c77 100644 +--- a/tools/perf/util/string2.h ++++ b/tools/perf/util/string2.h +@@ -39,5 +39,6 @@ char *strpbrk_esc(char *str, const char *stopset); + char *strdup_esc(const char *str); + + unsigned int hex(char c); ++char *strreplace_chars(char needle, const char *haystack, const char *replace); + + #endif /* PERF_STRING_H */ +diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c +index 3f36675b7c8ff..ea24f21aafc3e 100644 +--- a/tools/perf/util/symbol.c ++++ b/tools/perf/util/symbol.c +@@ -48,11 +48,6 @@ static bool symbol__is_idle(const char *name); + int vmlinux_path__nr_entries; + char **vmlinux_path; + +-struct map_list_node { +- struct list_head node; +- struct map *map; +-}; +- + struct symbol_conf symbol_conf = { + .nanosecs = false, + .use_modules = true, +@@ -90,11 +85,6 @@ static enum dso_binary_type binary_type_symtab[] = { + + #define DSO_BINARY_TYPE__SYMTAB_CNT ARRAY_SIZE(binary_type_symtab) + +-static struct map_list_node *map_list_node__new(void) +-{ +- return malloc(sizeof(struct map_list_node)); +-} +- + static bool symbol_type__filter(char symbol_type) + { + symbol_type = toupper(symbol_type); +@@ -271,29 +261,6 @@ void symbols__fixup_end(struct rb_root_cached *symbols, bool is_kallsyms) + curr->end = roundup(curr->start, 4096) + 4096; + } + +-void maps__fixup_end(struct maps *maps) +-{ +- struct map_rb_node *prev = NULL, *curr; +- +- down_write(maps__lock(maps)); +- +- maps__for_each_entry(maps, curr) { +- if (prev != NULL && !map__end(prev->map)) +- map__set_end(prev->map, map__start(curr->map)); +- +- prev = curr; +- } +- +- /* +- * We still haven't the actual symbols, so guess the +- * last map final address. +- */ +- if (curr && !map__end(curr->map)) +- map__set_end(curr->map, ~0ULL); +- +- up_write(maps__lock(maps)); +-} +- + struct symbol *symbol__new(u64 start, u64 len, u8 binding, u8 type, const char *name) + { + size_t namelen = strlen(name) + 1; +@@ -1271,103 +1238,6 @@ static int kcore_mapfn(u64 start, u64 len, u64 pgoff, void *data) + return 0; + } + +-/* +- * Merges map into maps by splitting the new map within the existing map +- * regions. +- */ +-int maps__merge_in(struct maps *kmaps, struct map *new_map) +-{ +- struct map_rb_node *rb_node; +- LIST_HEAD(merged); +- int err = 0; +- +- maps__for_each_entry(kmaps, rb_node) { +- struct map *old_map = rb_node->map; +- +- /* no overload with this one */ +- if (map__end(new_map) < map__start(old_map) || +- map__start(new_map) >= map__end(old_map)) +- continue; +- +- if (map__start(new_map) < map__start(old_map)) { +- /* +- * |new...... +- * |old.... +- */ +- if (map__end(new_map) < map__end(old_map)) { +- /* +- * |new......| -> |new..| +- * |old....| -> |old....| +- */ +- map__set_end(new_map, map__start(old_map)); +- } else { +- /* +- * |new.............| -> |new..| |new..| +- * |old....| -> |old....| +- */ +- struct map_list_node *m = map_list_node__new(); +- +- if (!m) { +- err = -ENOMEM; +- goto out; +- } +- +- m->map = map__clone(new_map); +- if (!m->map) { +- free(m); +- err = -ENOMEM; +- goto out; +- } +- +- map__set_end(m->map, map__start(old_map)); +- list_add_tail(&m->node, &merged); +- map__add_pgoff(new_map, map__end(old_map) - map__start(new_map)); +- map__set_start(new_map, map__end(old_map)); +- } +- } else { +- /* +- * |new...... +- * |old.... +- */ +- if (map__end(new_map) < map__end(old_map)) { +- /* +- * |new..| -> x +- * |old.........| -> |old.........| +- */ +- map__put(new_map); +- new_map = NULL; +- break; +- } else { +- /* +- * |new......| -> |new...| +- * |old....| -> |old....| +- */ +- map__add_pgoff(new_map, map__end(old_map) - map__start(new_map)); +- map__set_start(new_map, map__end(old_map)); +- } +- } +- } +- +-out: +- while (!list_empty(&merged)) { +- struct map_list_node *old_node; +- +- old_node = list_entry(merged.next, struct map_list_node, node); +- list_del_init(&old_node->node); +- if (!err) +- err = maps__insert(kmaps, old_node->map); +- map__put(old_node->map); +- free(old_node); +- } +- +- if (new_map) { +- if (!err) +- err = maps__insert(kmaps, new_map); +- map__put(new_map); +- } +- return err; +-} +- + static int dso__load_kcore(struct dso *dso, struct map *map, + const char *kallsyms_filename) + { +@@ -2065,124 +1935,10 @@ int dso__load(struct dso *dso, struct map *map) + return ret; + } + +-static int map__strcmp(const void *a, const void *b) +-{ +- const struct map *map_a = *(const struct map **)a; +- const struct map *map_b = *(const struct map **)b; +- const struct dso *dso_a = map__dso(map_a); +- const struct dso *dso_b = map__dso(map_b); +- int ret = strcmp(dso_a->short_name, dso_b->short_name); +- +- if (ret == 0 && map_a != map_b) { +- /* +- * Ensure distinct but name equal maps have an order in part to +- * aid reference counting. +- */ +- ret = (int)map__start(map_a) - (int)map__start(map_b); +- if (ret == 0) +- ret = (int)((intptr_t)map_a - (intptr_t)map_b); +- } +- +- return ret; +-} +- +-static int map__strcmp_name(const void *name, const void *b) +-{ +- const struct dso *dso = map__dso(*(const struct map **)b); +- +- return strcmp(name, dso->short_name); +-} +- +-void __maps__sort_by_name(struct maps *maps) +-{ +- qsort(maps__maps_by_name(maps), maps__nr_maps(maps), sizeof(struct map *), map__strcmp); +-} +- +-static int map__groups__sort_by_name_from_rbtree(struct maps *maps) +-{ +- struct map_rb_node *rb_node; +- struct map **maps_by_name = realloc(maps__maps_by_name(maps), +- maps__nr_maps(maps) * sizeof(struct map *)); +- int i = 0; +- +- if (maps_by_name == NULL) +- return -1; +- +- up_read(maps__lock(maps)); +- down_write(maps__lock(maps)); +- +- RC_CHK_ACCESS(maps)->maps_by_name = maps_by_name; +- RC_CHK_ACCESS(maps)->nr_maps_allocated = maps__nr_maps(maps); +- +- maps__for_each_entry(maps, rb_node) +- maps_by_name[i++] = map__get(rb_node->map); +- +- __maps__sort_by_name(maps); +- +- up_write(maps__lock(maps)); +- down_read(maps__lock(maps)); +- +- return 0; +-} +- +-static struct map *__maps__find_by_name(struct maps *maps, const char *name) +-{ +- struct map **mapp; +- +- if (maps__maps_by_name(maps) == NULL && +- map__groups__sort_by_name_from_rbtree(maps)) +- return NULL; +- +- mapp = bsearch(name, maps__maps_by_name(maps), maps__nr_maps(maps), +- sizeof(*mapp), map__strcmp_name); +- if (mapp) +- return *mapp; +- return NULL; +-} +- +-struct map *maps__find_by_name(struct maps *maps, const char *name) +-{ +- struct map_rb_node *rb_node; +- struct map *map; +- +- down_read(maps__lock(maps)); +- +- +- if (RC_CHK_ACCESS(maps)->last_search_by_name) { +- const struct dso *dso = map__dso(RC_CHK_ACCESS(maps)->last_search_by_name); +- +- if (strcmp(dso->short_name, name) == 0) { +- map = RC_CHK_ACCESS(maps)->last_search_by_name; +- goto out_unlock; +- } +- } +- /* +- * If we have maps->maps_by_name, then the name isn't in the rbtree, +- * as maps->maps_by_name mirrors the rbtree when lookups by name are +- * made. +- */ +- map = __maps__find_by_name(maps, name); +- if (map || maps__maps_by_name(maps) != NULL) +- goto out_unlock; +- +- /* Fallback to traversing the rbtree... */ +- maps__for_each_entry(maps, rb_node) { +- struct dso *dso; +- +- map = rb_node->map; +- dso = map__dso(map); +- if (strcmp(dso->short_name, name) == 0) { +- RC_CHK_ACCESS(maps)->last_search_by_name = map; +- goto out_unlock; +- } +- } +- map = NULL; +- +-out_unlock: +- up_read(maps__lock(maps)); +- return map; +-} +- ++/* ++ * Always takes ownership of vmlinux when vmlinux_allocated == true, even if ++ * it returns an error. ++ */ + int dso__load_vmlinux(struct dso *dso, struct map *map, + const char *vmlinux, bool vmlinux_allocated) + { +@@ -2201,8 +1957,11 @@ int dso__load_vmlinux(struct dso *dso, struct map *map, + else + symtab_type = DSO_BINARY_TYPE__VMLINUX; + +- if (symsrc__init(&ss, dso, symfs_vmlinux, symtab_type)) ++ if (symsrc__init(&ss, dso, symfs_vmlinux, symtab_type)) { ++ if (vmlinux_allocated) ++ free((char *) vmlinux); + return -1; ++ } + + /* + * dso__load_sym() may copy 'dso' which will result in the copies having +@@ -2245,7 +2004,6 @@ int dso__load_vmlinux_path(struct dso *dso, struct map *map) + err = dso__load_vmlinux(dso, map, filename, true); + if (err > 0) + goto out; +- free(filename); + } + out: + return err; +@@ -2397,7 +2155,6 @@ static int dso__load_kernel_sym(struct dso *dso, struct map *map) + err = dso__load_vmlinux(dso, map, filename, true); + if (err > 0) + return err; +- free(filename); + } + + if (!symbol_conf.ignore_vmlinux && vmlinux_path != NULL) { +diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h +index af87c46b3f89e..071837ddce2ac 100644 +--- a/tools/perf/util/symbol.h ++++ b/tools/perf/util/symbol.h +@@ -189,7 +189,6 @@ void __symbols__insert(struct rb_root_cached *symbols, struct symbol *sym, + void symbols__insert(struct rb_root_cached *symbols, struct symbol *sym); + void symbols__fixup_duplicate(struct rb_root_cached *symbols); + void symbols__fixup_end(struct rb_root_cached *symbols, bool is_kallsyms); +-void maps__fixup_end(struct maps *maps); + + typedef int (*mapfn_t)(u64 start, u64 len, u64 pgoff, void *data); + int file__read_maps(int fd, bool exe, mapfn_t mapfn, void *data, +diff --git a/tools/perf/util/symbol_conf.h b/tools/perf/util/symbol_conf.h +index 0b589570d1d09..6040286e07a65 100644 +--- a/tools/perf/util/symbol_conf.h ++++ b/tools/perf/util/symbol_conf.h +@@ -42,7 +42,9 @@ struct symbol_conf { + inline_name, + disable_add2line_warn, + buildid_mmap2, +- guest_code; ++ guest_code, ++ lazy_load_kernel_maps, ++ keep_exited_threads; + const char *vmlinux_name, + *kallsyms_name, + *source_prefix, +diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c +index fe5e6991ae4b4..61e9f449c7258 100644 +--- a/tools/perf/util/thread.c ++++ b/tools/perf/util/thread.c +@@ -39,12 +39,13 @@ int thread__init_maps(struct thread *thread, struct machine *machine) + + struct thread *thread__new(pid_t pid, pid_t tid) + { +- char *comm_str; +- struct comm *comm; + RC_STRUCT(thread) *_thread = zalloc(sizeof(*_thread)); + struct thread *thread; + + if (ADD_RC_CHK(thread, _thread) != NULL) { ++ struct comm *comm; ++ char comm_str[32]; ++ + thread__set_pid(thread, pid); + thread__set_tid(thread, tid); + thread__set_ppid(thread, -1); +@@ -56,13 +57,8 @@ struct thread *thread__new(pid_t pid, pid_t tid) + init_rwsem(thread__namespaces_lock(thread)); + init_rwsem(thread__comm_lock(thread)); + +- comm_str = malloc(32); +- if (!comm_str) +- goto err_thread; +- +- snprintf(comm_str, 32, ":%d", tid); ++ snprintf(comm_str, sizeof(comm_str), ":%d", tid); + comm = comm__new(comm_str, 0, false); +- free(comm_str); + if (!comm) + goto err_thread; + +@@ -76,7 +72,7 @@ struct thread *thread__new(pid_t pid, pid_t tid) + return thread; + + err_thread: +- free(thread); ++ thread__delete(thread); + return NULL; + } + +diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h +index e79225a0ea46b..0df775b5c1105 100644 +--- a/tools/perf/util/thread.h ++++ b/tools/perf/util/thread.h +@@ -36,13 +36,22 @@ struct thread_rb_node { + }; + + DECLARE_RC_STRUCT(thread) { ++ /** @maps: mmaps associated with this thread. */ + struct maps *maps; + pid_t pid_; /* Not all tools update this */ ++ /** @tid: thread ID number unique to a machine. */ + pid_t tid; ++ /** @ppid: parent process of the process this thread belongs to. */ + pid_t ppid; + int cpu; + int guest_cpu; /* For QEMU thread */ + refcount_t refcnt; ++ /** ++ * @exited: Has the thread had an exit event. Such threads are usually ++ * removed from the machine's threads but some events/tools require ++ * access to dead threads. ++ */ ++ bool exited; + bool comm_set; + int comm_len; + struct list_head namespaces_list; +@@ -189,6 +198,11 @@ static inline refcount_t *thread__refcnt(struct thread *thread) + return &RC_CHK_ACCESS(thread)->refcnt; + } + ++static inline void thread__set_exited(struct thread *thread, bool exited) ++{ ++ RC_CHK_ACCESS(thread)->exited = exited; ++} ++ + static inline bool thread__comm_set(const struct thread *thread) + { + return RC_CHK_ACCESS(thread)->comm_set; +diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h +index a8b0d79bd96cf..4c5588dbb1317 100644 +--- a/tools/perf/util/top.h ++++ b/tools/perf/util/top.h +@@ -21,7 +21,6 @@ struct perf_top { + struct perf_tool tool; + struct evlist *evlist, *sb_evlist; + struct record_opts record_opts; +- struct annotation_options annotation_opts; + struct evswitch evswitch; + /* + * Symbols will be added here in perf_event__process_sample and will +diff --git a/tools/testing/selftests/bpf/network_helpers.c b/tools/testing/selftests/bpf/network_helpers.c +index da72a3a662300..0877b60ec81f6 100644 +--- a/tools/testing/selftests/bpf/network_helpers.c ++++ b/tools/testing/selftests/bpf/network_helpers.c +@@ -427,6 +427,8 @@ struct nstoken *open_netns(const char *name) + + return token; + fail: ++ if (token->orig_netns_fd != -1) ++ close(token->orig_netns_fd); + free(token); + return NULL; + } +diff --git a/tools/testing/selftests/bpf/prog_tests/xdp_do_redirect.c b/tools/testing/selftests/bpf/prog_tests/xdp_do_redirect.c +index 498d3bdaa4b0b..bad0ea167be70 100644 +--- a/tools/testing/selftests/bpf/prog_tests/xdp_do_redirect.c ++++ b/tools/testing/selftests/bpf/prog_tests/xdp_do_redirect.c +@@ -107,8 +107,8 @@ void test_xdp_do_redirect(void) + .attach_point = BPF_TC_INGRESS); + + memcpy(&data[sizeof(__u64)], &pkt_udp, sizeof(pkt_udp)); +- *((__u32 *)data) = 0x42; /* metadata test value */ +- *((__u32 *)data + 4) = 0; ++ ((__u32 *)data)[0] = 0x42; /* metadata test value */ ++ ((__u32 *)data)[1] = 0; + + skel = test_xdp_do_redirect__open(); + if (!ASSERT_OK_PTR(skel, "skel")) +diff --git a/tools/testing/selftests/bpf/progs/bench_local_storage_create.c b/tools/testing/selftests/bpf/progs/bench_local_storage_create.c +index e4bfbba6c1936..c8ec0d0368e4a 100644 +--- a/tools/testing/selftests/bpf/progs/bench_local_storage_create.c ++++ b/tools/testing/selftests/bpf/progs/bench_local_storage_create.c +@@ -61,14 +61,15 @@ SEC("lsm.s/socket_post_create") + int BPF_PROG(socket_post_create, struct socket *sock, int family, int type, + int protocol, int kern) + { ++ struct sock *sk = sock->sk; + struct storage *stg; + __u32 pid; + + pid = bpf_get_current_pid_tgid() >> 32; +- if (pid != bench_pid) ++ if (pid != bench_pid || !sk) + return 0; + +- stg = bpf_sk_storage_get(&sk_storage_map, sock->sk, NULL, ++ stg = bpf_sk_storage_get(&sk_storage_map, sk, NULL, + BPF_LOCAL_STORAGE_GET_F_CREATE); + + if (stg) +diff --git a/tools/testing/selftests/bpf/progs/local_storage.c b/tools/testing/selftests/bpf/progs/local_storage.c +index bc8ea56671a16..3bf75f4ea690a 100644 +--- a/tools/testing/selftests/bpf/progs/local_storage.c ++++ b/tools/testing/selftests/bpf/progs/local_storage.c +@@ -140,11 +140,12 @@ int BPF_PROG(socket_bind, struct socket *sock, struct sockaddr *address, + { + __u32 pid = bpf_get_current_pid_tgid() >> 32; + struct local_storage *storage; ++ struct sock *sk = sock->sk; + +- if (pid != monitored_pid) ++ if (pid != monitored_pid || !sk) + return 0; + +- storage = bpf_sk_storage_get(&sk_storage_map, sock->sk, 0, 0); ++ storage = bpf_sk_storage_get(&sk_storage_map, sk, 0, 0); + if (!storage) + return 0; + +@@ -155,24 +156,24 @@ int BPF_PROG(socket_bind, struct socket *sock, struct sockaddr *address, + /* This tests that we can associate multiple elements + * with the local storage. + */ +- storage = bpf_sk_storage_get(&sk_storage_map2, sock->sk, 0, ++ storage = bpf_sk_storage_get(&sk_storage_map2, sk, 0, + BPF_LOCAL_STORAGE_GET_F_CREATE); + if (!storage) + return 0; + +- if (bpf_sk_storage_delete(&sk_storage_map2, sock->sk)) ++ if (bpf_sk_storage_delete(&sk_storage_map2, sk)) + return 0; + +- storage = bpf_sk_storage_get(&sk_storage_map2, sock->sk, 0, ++ storage = bpf_sk_storage_get(&sk_storage_map2, sk, 0, + BPF_LOCAL_STORAGE_GET_F_CREATE); + if (!storage) + return 0; + +- if (bpf_sk_storage_delete(&sk_storage_map, sock->sk)) ++ if (bpf_sk_storage_delete(&sk_storage_map, sk)) + return 0; + + /* Ensure that the sk_storage_map is disconnected from the storage. */ +- if (!sock->sk->sk_bpf_storage || sock->sk->sk_bpf_storage->smap) ++ if (!sk->sk_bpf_storage || sk->sk_bpf_storage->smap) + return 0; + + sk_storage_result = 0; +@@ -185,11 +186,12 @@ int BPF_PROG(socket_post_create, struct socket *sock, int family, int type, + { + __u32 pid = bpf_get_current_pid_tgid() >> 32; + struct local_storage *storage; ++ struct sock *sk = sock->sk; + +- if (pid != monitored_pid) ++ if (pid != monitored_pid || !sk) + return 0; + +- storage = bpf_sk_storage_get(&sk_storage_map, sock->sk, 0, ++ storage = bpf_sk_storage_get(&sk_storage_map, sk, 0, + BPF_LOCAL_STORAGE_GET_F_CREATE); + if (!storage) + return 0; +diff --git a/tools/testing/selftests/bpf/progs/lsm_cgroup.c b/tools/testing/selftests/bpf/progs/lsm_cgroup.c +index 02c11d16b692a..d7598538aa2da 100644 +--- a/tools/testing/selftests/bpf/progs/lsm_cgroup.c ++++ b/tools/testing/selftests/bpf/progs/lsm_cgroup.c +@@ -103,11 +103,15 @@ static __always_inline int real_bind(struct socket *sock, + int addrlen) + { + struct sockaddr_ll sa = {}; ++ struct sock *sk = sock->sk; + +- if (sock->sk->__sk_common.skc_family != AF_PACKET) ++ if (!sk) ++ return 1; ++ ++ if (sk->__sk_common.skc_family != AF_PACKET) + return 1; + +- if (sock->sk->sk_kern_sock) ++ if (sk->sk_kern_sock) + return 1; + + bpf_probe_read_kernel(&sa, sizeof(sa), address); +diff --git a/tools/testing/selftests/bpf/test_sockmap.c b/tools/testing/selftests/bpf/test_sockmap.c +index 024a0faafb3be..43612de44fbf5 100644 +--- a/tools/testing/selftests/bpf/test_sockmap.c ++++ b/tools/testing/selftests/bpf/test_sockmap.c +@@ -2104,9 +2104,9 @@ int main(int argc, char **argv) + free(options.whitelist); + if (options.blacklist) + free(options.blacklist); ++ close(cg_fd); + if (cg_created) + cleanup_cgroup_environment(); +- close(cg_fd); + return err; + } + +diff --git a/tools/testing/selftests/cgroup/cgroup_util.c b/tools/testing/selftests/cgroup/cgroup_util.c +index 0340d4ca8f51c..432db923bced0 100644 +--- a/tools/testing/selftests/cgroup/cgroup_util.c ++++ b/tools/testing/selftests/cgroup/cgroup_util.c +@@ -195,10 +195,10 @@ int cg_write_numeric(const char *cgroup, const char *control, long value) + return cg_write(cgroup, control, buf); + } + +-int cg_find_unified_root(char *root, size_t len) ++int cg_find_unified_root(char *root, size_t len, bool *nsdelegate) + { + char buf[10 * PAGE_SIZE]; +- char *fs, *mount, *type; ++ char *fs, *mount, *type, *options; + const char delim[] = "\n\t "; + + if (read_text("/proc/self/mounts", buf, sizeof(buf)) <= 0) +@@ -211,12 +211,14 @@ int cg_find_unified_root(char *root, size_t len) + for (fs = strtok(buf, delim); fs; fs = strtok(NULL, delim)) { + mount = strtok(NULL, delim); + type = strtok(NULL, delim); +- strtok(NULL, delim); ++ options = strtok(NULL, delim); + strtok(NULL, delim); + strtok(NULL, delim); + + if (strcmp(type, "cgroup2") == 0) { + strncpy(root, mount, len); ++ if (nsdelegate) ++ *nsdelegate = !!strstr(options, "nsdelegate"); + return 0; + } + } +diff --git a/tools/testing/selftests/cgroup/cgroup_util.h b/tools/testing/selftests/cgroup/cgroup_util.h +index 1df7f202214af..89e8519fb2719 100644 +--- a/tools/testing/selftests/cgroup/cgroup_util.h ++++ b/tools/testing/selftests/cgroup/cgroup_util.h +@@ -21,7 +21,7 @@ static inline int values_close(long a, long b, int err) + return abs(a - b) <= (a + b) / 100 * err; + } + +-extern int cg_find_unified_root(char *root, size_t len); ++extern int cg_find_unified_root(char *root, size_t len, bool *nsdelegate); + extern char *cg_name(const char *root, const char *name); + extern char *cg_name_indexed(const char *root, const char *name, int index); + extern char *cg_control(const char *cgroup, const char *control); +diff --git a/tools/testing/selftests/cgroup/test_core.c b/tools/testing/selftests/cgroup/test_core.c +index 80aa6b2373b96..a5672a91d273c 100644 +--- a/tools/testing/selftests/cgroup/test_core.c ++++ b/tools/testing/selftests/cgroup/test_core.c +@@ -18,6 +18,8 @@ + #include "../kselftest.h" + #include "cgroup_util.h" + ++static bool nsdelegate; ++ + static int touch_anon(char *buf, size_t size) + { + int fd; +@@ -775,6 +777,9 @@ static int test_cgcore_lesser_ns_open(const char *root) + pid_t pid; + int status; + ++ if (!nsdelegate) ++ return KSFT_SKIP; ++ + cg_test_a = cg_name(root, "cg_test_a"); + cg_test_b = cg_name(root, "cg_test_b"); + +@@ -862,7 +867,7 @@ int main(int argc, char *argv[]) + char root[PATH_MAX]; + int i, ret = EXIT_SUCCESS; + +- if (cg_find_unified_root(root, sizeof(root))) ++ if (cg_find_unified_root(root, sizeof(root), &nsdelegate)) + ksft_exit_skip("cgroup v2 isn't mounted\n"); + + if (cg_read_strstr(root, "cgroup.subtree_control", "memory")) +diff --git a/tools/testing/selftests/cgroup/test_cpu.c b/tools/testing/selftests/cgroup/test_cpu.c +index 24020a2c68dcd..186bf96f6a284 100644 +--- a/tools/testing/selftests/cgroup/test_cpu.c ++++ b/tools/testing/selftests/cgroup/test_cpu.c +@@ -700,7 +700,7 @@ int main(int argc, char *argv[]) + char root[PATH_MAX]; + int i, ret = EXIT_SUCCESS; + +- if (cg_find_unified_root(root, sizeof(root))) ++ if (cg_find_unified_root(root, sizeof(root), NULL)) + ksft_exit_skip("cgroup v2 isn't mounted\n"); + + if (cg_read_strstr(root, "cgroup.subtree_control", "cpu")) +diff --git a/tools/testing/selftests/cgroup/test_cpuset.c b/tools/testing/selftests/cgroup/test_cpuset.c +index b061ed1e05b4d..4034d14ba69ac 100644 +--- a/tools/testing/selftests/cgroup/test_cpuset.c ++++ b/tools/testing/selftests/cgroup/test_cpuset.c +@@ -249,7 +249,7 @@ int main(int argc, char *argv[]) + char root[PATH_MAX]; + int i, ret = EXIT_SUCCESS; + +- if (cg_find_unified_root(root, sizeof(root))) ++ if (cg_find_unified_root(root, sizeof(root), NULL)) + ksft_exit_skip("cgroup v2 isn't mounted\n"); + + if (cg_read_strstr(root, "cgroup.subtree_control", "cpuset")) +diff --git a/tools/testing/selftests/cgroup/test_freezer.c b/tools/testing/selftests/cgroup/test_freezer.c +index ff519029f6f43..969e9f0f495c3 100644 +--- a/tools/testing/selftests/cgroup/test_freezer.c ++++ b/tools/testing/selftests/cgroup/test_freezer.c +@@ -827,7 +827,7 @@ int main(int argc, char *argv[]) + char root[PATH_MAX]; + int i, ret = EXIT_SUCCESS; + +- if (cg_find_unified_root(root, sizeof(root))) ++ if (cg_find_unified_root(root, sizeof(root), NULL)) + ksft_exit_skip("cgroup v2 isn't mounted\n"); + for (i = 0; i < ARRAY_SIZE(tests); i++) { + switch (tests[i].fn(root)) { +diff --git a/tools/testing/selftests/cgroup/test_kill.c b/tools/testing/selftests/cgroup/test_kill.c +index 6153690319c9c..0e5bb6c7307a5 100644 +--- a/tools/testing/selftests/cgroup/test_kill.c ++++ b/tools/testing/selftests/cgroup/test_kill.c +@@ -276,7 +276,7 @@ int main(int argc, char *argv[]) + char root[PATH_MAX]; + int i, ret = EXIT_SUCCESS; + +- if (cg_find_unified_root(root, sizeof(root))) ++ if (cg_find_unified_root(root, sizeof(root), NULL)) + ksft_exit_skip("cgroup v2 isn't mounted\n"); + for (i = 0; i < ARRAY_SIZE(tests); i++) { + switch (tests[i].fn(root)) { +diff --git a/tools/testing/selftests/cgroup/test_kmem.c b/tools/testing/selftests/cgroup/test_kmem.c +index c82f974b85c94..137506db03127 100644 +--- a/tools/testing/selftests/cgroup/test_kmem.c ++++ b/tools/testing/selftests/cgroup/test_kmem.c +@@ -420,7 +420,7 @@ int main(int argc, char **argv) + char root[PATH_MAX]; + int i, ret = EXIT_SUCCESS; + +- if (cg_find_unified_root(root, sizeof(root))) ++ if (cg_find_unified_root(root, sizeof(root), NULL)) + ksft_exit_skip("cgroup v2 isn't mounted\n"); + + /* +diff --git a/tools/testing/selftests/cgroup/test_memcontrol.c b/tools/testing/selftests/cgroup/test_memcontrol.c +index c7c9572003a8c..b462416b38061 100644 +--- a/tools/testing/selftests/cgroup/test_memcontrol.c ++++ b/tools/testing/selftests/cgroup/test_memcontrol.c +@@ -1314,7 +1314,7 @@ int main(int argc, char **argv) + char root[PATH_MAX]; + int i, proc_status, ret = EXIT_SUCCESS; + +- if (cg_find_unified_root(root, sizeof(root))) ++ if (cg_find_unified_root(root, sizeof(root), NULL)) + ksft_exit_skip("cgroup v2 isn't mounted\n"); + + /* +diff --git a/tools/testing/selftests/cgroup/test_zswap.c b/tools/testing/selftests/cgroup/test_zswap.c +index 49def87a909bd..6927b4a06dee6 100644 +--- a/tools/testing/selftests/cgroup/test_zswap.c ++++ b/tools/testing/selftests/cgroup/test_zswap.c +@@ -250,7 +250,7 @@ int main(int argc, char **argv) + char root[PATH_MAX]; + int i, ret = EXIT_SUCCESS; + +- if (cg_find_unified_root(root, sizeof(root))) ++ if (cg_find_unified_root(root, sizeof(root), NULL)) + ksft_exit_skip("cgroup v2 isn't mounted\n"); + + if (!zswap_configured()) +diff --git a/tools/testing/selftests/filesystems/binderfs/Makefile b/tools/testing/selftests/filesystems/binderfs/Makefile +index c2f7cef919c04..eb4c3b4119348 100644 +--- a/tools/testing/selftests/filesystems/binderfs/Makefile ++++ b/tools/testing/selftests/filesystems/binderfs/Makefile +@@ -3,6 +3,4 @@ + CFLAGS += $(KHDR_INCLUDES) -pthread + TEST_GEN_PROGS := binderfs_test + +-binderfs_test: binderfs_test.c ../../kselftest.h ../../kselftest_harness.h +- + include ../../lib.mk +diff --git a/tools/testing/selftests/ftrace/test.d/dynevent/add_remove_btfarg.tc b/tools/testing/selftests/ftrace/test.d/dynevent/add_remove_btfarg.tc +index b9c21a81d2481..c0cdad4c400e8 100644 +--- a/tools/testing/selftests/ftrace/test.d/dynevent/add_remove_btfarg.tc ++++ b/tools/testing/selftests/ftrace/test.d/dynevent/add_remove_btfarg.tc +@@ -53,7 +53,7 @@ fi + + echo > dynamic_events + +-if [ "$FIELDS" ] ; then ++if [ "$FIELDS" -a "$FPROBES" ] ; then + echo "t:tpevent ${TP2} obj_size=s->object_size" >> dynamic_events + echo "f:fpevent ${TP3}%return path=\$retval->name:string" >> dynamic_events + echo "t:tpevent2 ${TP4} p->se.group_node.next->prev" >> dynamic_events +diff --git a/tools/testing/selftests/kcmp/kcmp_test.c b/tools/testing/selftests/kcmp/kcmp_test.c +index 25110c7c0b3ed..d7a8e321bb16b 100644 +--- a/tools/testing/selftests/kcmp/kcmp_test.c ++++ b/tools/testing/selftests/kcmp/kcmp_test.c +@@ -91,7 +91,7 @@ int main(int argc, char **argv) + ksft_print_header(); + ksft_set_plan(3); + +- fd2 = open(kpath, O_RDWR, 0644); ++ fd2 = open(kpath, O_RDWR); + if (fd2 < 0) { + perror("Can't open file"); + ksft_exit_fail(); +diff --git a/tools/testing/selftests/kvm/aarch64/vgic_init.c b/tools/testing/selftests/kvm/aarch64/vgic_init.c +index eef816b80993f..4ac4d3ea976ec 100644 +--- a/tools/testing/selftests/kvm/aarch64/vgic_init.c ++++ b/tools/testing/selftests/kvm/aarch64/vgic_init.c +@@ -6,6 +6,7 @@ + */ + #define _GNU_SOURCE + #include ++#include + #include + #include + #include +@@ -84,6 +85,18 @@ static struct vm_gic vm_gic_create_with_vcpus(uint32_t gic_dev_type, + return v; + } + ++static struct vm_gic vm_gic_create_barebones(uint32_t gic_dev_type) ++{ ++ struct vm_gic v; ++ ++ v.gic_dev_type = gic_dev_type; ++ v.vm = vm_create_barebones(); ++ v.gic_fd = kvm_create_device(v.vm, gic_dev_type); ++ ++ return v; ++} ++ ++ + static void vm_gic_destroy(struct vm_gic *v) + { + close(v->gic_fd); +@@ -357,6 +370,40 @@ static void test_vcpus_then_vgic(uint32_t gic_dev_type) + vm_gic_destroy(&v); + } + ++#define KVM_VGIC_V2_ATTR(offset, cpu) \ ++ (FIELD_PREP(KVM_DEV_ARM_VGIC_OFFSET_MASK, offset) | \ ++ FIELD_PREP(KVM_DEV_ARM_VGIC_CPUID_MASK, cpu)) ++ ++#define GIC_CPU_CTRL 0x00 ++ ++static void test_v2_uaccess_cpuif_no_vcpus(void) ++{ ++ struct vm_gic v; ++ u64 val = 0; ++ int ret; ++ ++ v = vm_gic_create_barebones(KVM_DEV_TYPE_ARM_VGIC_V2); ++ subtest_dist_rdist(&v); ++ ++ ret = __kvm_has_device_attr(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_CPU_REGS, ++ KVM_VGIC_V2_ATTR(GIC_CPU_CTRL, 0)); ++ TEST_ASSERT(ret && errno == EINVAL, ++ "accessed non-existent CPU interface, want errno: %i", ++ EINVAL); ++ ret = __kvm_device_attr_get(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_CPU_REGS, ++ KVM_VGIC_V2_ATTR(GIC_CPU_CTRL, 0), &val); ++ TEST_ASSERT(ret && errno == EINVAL, ++ "accessed non-existent CPU interface, want errno: %i", ++ EINVAL); ++ ret = __kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_CPU_REGS, ++ KVM_VGIC_V2_ATTR(GIC_CPU_CTRL, 0), &val); ++ TEST_ASSERT(ret && errno == EINVAL, ++ "accessed non-existent CPU interface, want errno: %i", ++ EINVAL); ++ ++ vm_gic_destroy(&v); ++} ++ + static void test_v3_new_redist_regions(void) + { + struct kvm_vcpu *vcpus[NR_VCPUS]; +@@ -675,6 +722,9 @@ void run_tests(uint32_t gic_dev_type) + test_vcpus_then_vgic(gic_dev_type); + test_vgic_then_vcpus(gic_dev_type); + ++ if (VGIC_DEV_IS_V2(gic_dev_type)) ++ test_v2_uaccess_cpuif_no_vcpus(); ++ + if (VGIC_DEV_IS_V3(gic_dev_type)) { + test_v3_new_redist_regions(); + test_v3_typer_accesses(); +diff --git a/tools/testing/selftests/lib.mk b/tools/testing/selftests/lib.mk +index aa646e0661f36..a8f0442a36bca 100644 +--- a/tools/testing/selftests/lib.mk ++++ b/tools/testing/selftests/lib.mk +@@ -7,6 +7,8 @@ else ifneq ($(filter -%,$(LLVM)),) + LLVM_SUFFIX := $(LLVM) + endif + ++CLANG := $(LLVM_PREFIX)clang$(LLVM_SUFFIX) ++ + CLANG_TARGET_FLAGS_arm := arm-linux-gnueabi + CLANG_TARGET_FLAGS_arm64 := aarch64-linux-gnu + CLANG_TARGET_FLAGS_hexagon := hexagon-linux-musl +@@ -18,7 +20,13 @@ CLANG_TARGET_FLAGS_riscv := riscv64-linux-gnu + CLANG_TARGET_FLAGS_s390 := s390x-linux-gnu + CLANG_TARGET_FLAGS_x86 := x86_64-linux-gnu + CLANG_TARGET_FLAGS_x86_64 := x86_64-linux-gnu +-CLANG_TARGET_FLAGS := $(CLANG_TARGET_FLAGS_$(ARCH)) ++ ++# Default to host architecture if ARCH is not explicitly given. ++ifeq ($(ARCH),) ++CLANG_TARGET_FLAGS := $(shell $(CLANG) -print-target-triple) ++else ++CLANG_TARGET_FLAGS := $(CLANG_TARGET_FLAGS_$(ARCH)) ++endif + + ifeq ($(CROSS_COMPILE),) + ifeq ($(CLANG_TARGET_FLAGS),) +@@ -30,7 +38,7 @@ else + CLANG_FLAGS += --target=$(notdir $(CROSS_COMPILE:%-=%)) + endif # CROSS_COMPILE + +-CC := $(LLVM_PREFIX)clang$(LLVM_SUFFIX) $(CLANG_FLAGS) -fintegrated-as ++CC := $(CLANG) $(CLANG_FLAGS) -fintegrated-as + else + CC := $(CROSS_COMPILE)gcc + endif # LLVM +diff --git a/tools/testing/selftests/net/amt.sh b/tools/testing/selftests/net/amt.sh +index 75528788cb95e..7e7ed6c558da9 100755 +--- a/tools/testing/selftests/net/amt.sh ++++ b/tools/testing/selftests/net/amt.sh +@@ -77,6 +77,7 @@ readonly LISTENER=$(mktemp -u listener-XXXXXXXX) + readonly GATEWAY=$(mktemp -u gateway-XXXXXXXX) + readonly RELAY=$(mktemp -u relay-XXXXXXXX) + readonly SOURCE=$(mktemp -u source-XXXXXXXX) ++readonly SMCROUTEDIR="$(mktemp -d)" + ERR=4 + err=0 + +@@ -85,6 +86,11 @@ exit_cleanup() + for ns in "$@"; do + ip netns delete "${ns}" 2>/dev/null || true + done ++ if [ -f "$SMCROUTEDIR/amt.pid" ]; then ++ smcpid=$(< $SMCROUTEDIR/amt.pid) ++ kill $smcpid ++ fi ++ rm -rf $SMCROUTEDIR + + exit $ERR + } +@@ -167,7 +173,7 @@ setup_iptables() + + setup_mcast_routing() + { +- ip netns exec "${RELAY}" smcrouted ++ ip netns exec "${RELAY}" smcrouted -P $SMCROUTEDIR/amt.pid + ip netns exec "${RELAY}" smcroutectl a relay_src \ + 172.17.0.2 239.0.0.1 amtr + ip netns exec "${RELAY}" smcroutectl a relay_src \ +@@ -210,8 +216,8 @@ check_features() + + test_ipv4_forward() + { +- RESULT4=$(ip netns exec "${LISTENER}" nc -w 1 -l -u 239.0.0.1 4000) +- if [ "$RESULT4" == "172.17.0.2" ]; then ++ RESULT4=$(ip netns exec "${LISTENER}" timeout 15 socat - UDP4-LISTEN:4000,readbytes=128 || true) ++ if echo "$RESULT4" | grep -q "172.17.0.2"; then + printf "TEST: %-60s [ OK ]\n" "IPv4 amt multicast forwarding" + exit 0 + else +@@ -222,8 +228,8 @@ test_ipv4_forward() + + test_ipv6_forward() + { +- RESULT6=$(ip netns exec "${LISTENER}" nc -w 1 -l -u ff0e::5:6 6000) +- if [ "$RESULT6" == "2001:db8:3::2" ]; then ++ RESULT6=$(ip netns exec "${LISTENER}" timeout 15 socat - UDP6-LISTEN:6000,readbytes=128 || true) ++ if echo "$RESULT6" | grep -q "2001:db8:3::2"; then + printf "TEST: %-60s [ OK ]\n" "IPv6 amt multicast forwarding" + exit 0 + else +@@ -236,14 +242,14 @@ send_mcast4() + { + sleep 2 + ip netns exec "${SOURCE}" bash -c \ +- 'echo 172.17.0.2 | nc -w 1 -u 239.0.0.1 4000' & ++ 'printf "%s %128s" 172.17.0.2 | nc -w 1 -u 239.0.0.1 4000' & + } + + send_mcast6() + { + sleep 2 + ip netns exec "${SOURCE}" bash -c \ +- 'echo 2001:db8:3::2 | nc -w 1 -u ff0e::5:6 6000' & ++ 'printf "%s %128s" 2001:db8:3::2 | nc -w 1 -u ff0e::5:6 6000' & + } + + check_features +diff --git a/tools/testing/selftests/net/config b/tools/testing/selftests/net/config +index 3b749addd3640..04de7a6ba6f31 100644 +--- a/tools/testing/selftests/net/config ++++ b/tools/testing/selftests/net/config +@@ -24,10 +24,15 @@ CONFIG_IFB=y + CONFIG_INET_DIAG=y + CONFIG_INET_ESP=y + CONFIG_INET_ESP_OFFLOAD=y ++CONFIG_NET_FOU=y ++CONFIG_NET_FOU_IP_TUNNELS=y + CONFIG_IP_GRE=m + CONFIG_NETFILTER=y + CONFIG_NETFILTER_ADVANCED=y + CONFIG_NF_CONNTRACK=m ++CONFIG_IPV6_MROUTE=y ++CONFIG_IPV6_SIT=y ++CONFIG_IP_DCCP=m + CONFIG_NF_NAT=m + CONFIG_IP6_NF_IPTABLES=m + CONFIG_IP_NF_IPTABLES=m +@@ -62,6 +67,7 @@ CONFIG_NET_CLS_MATCHALL=m + CONFIG_NET_CLS_U32=m + CONFIG_NET_IPGRE_DEMUX=m + CONFIG_NET_IPGRE=m ++CONFIG_NET_IPIP=y + CONFIG_NET_SCH_FQ_CODEL=m + CONFIG_NET_SCH_HTB=m + CONFIG_NET_SCH_FQ=m +@@ -78,7 +84,6 @@ CONFIG_TLS=m + CONFIG_TRACEPOINTS=y + CONFIG_NET_DROP_MONITOR=m + CONFIG_NETDEVSIM=m +-CONFIG_NET_FOU=m + CONFIG_MPLS_ROUTING=m + CONFIG_MPLS_IPTUNNEL=m + CONFIG_NET_SCH_INGRESS=m +diff --git a/tools/testing/selftests/net/forwarding/bridge_igmp.sh b/tools/testing/selftests/net/forwarding/bridge_igmp.sh +index 2aa66d2a1702b..e6a3e04fd83f3 100755 +--- a/tools/testing/selftests/net/forwarding/bridge_igmp.sh ++++ b/tools/testing/selftests/net/forwarding/bridge_igmp.sh +@@ -478,10 +478,10 @@ v3exc_timeout_test() + RET=0 + local X=("192.0.2.20" "192.0.2.30") + +- # GMI should be 3 seconds ++ # GMI should be 5 seconds + ip link set dev br0 type bridge mcast_query_interval 100 \ + mcast_query_response_interval 100 \ +- mcast_membership_interval 300 ++ mcast_membership_interval 500 + + v3exclude_prepare $h1 $ALL_MAC $ALL_GROUP + ip link set dev br0 type bridge mcast_query_interval 500 \ +@@ -489,7 +489,7 @@ v3exc_timeout_test() + mcast_membership_interval 1500 + + $MZ $h1 -c 1 -b $ALL_MAC -B $ALL_GROUP -t ip "proto=2,p=$MZPKT_ALLOW2" -q +- sleep 3 ++ sleep 5 + bridge -j -d -s mdb show dev br0 \ + | jq -e ".[].mdb[] | \ + select(.grp == \"$TEST_GROUP\" and \ +diff --git a/tools/testing/selftests/net/forwarding/bridge_mld.sh b/tools/testing/selftests/net/forwarding/bridge_mld.sh +index e2b9ff773c6b6..f84ab2e657547 100755 +--- a/tools/testing/selftests/net/forwarding/bridge_mld.sh ++++ b/tools/testing/selftests/net/forwarding/bridge_mld.sh +@@ -478,10 +478,10 @@ mldv2exc_timeout_test() + RET=0 + local X=("2001:db8:1::20" "2001:db8:1::30") + +- # GMI should be 3 seconds ++ # GMI should be 5 seconds + ip link set dev br0 type bridge mcast_query_interval 100 \ + mcast_query_response_interval 100 \ +- mcast_membership_interval 300 ++ mcast_membership_interval 500 + + mldv2exclude_prepare $h1 + ip link set dev br0 type bridge mcast_query_interval 500 \ +@@ -489,7 +489,7 @@ mldv2exc_timeout_test() + mcast_membership_interval 1500 + + $MZ $h1 -c 1 $MZPKT_ALLOW2 -q +- sleep 3 ++ sleep 5 + bridge -j -d -s mdb show dev br0 \ + | jq -e ".[].mdb[] | \ + select(.grp == \"$TEST_GROUP\" and \ +diff --git a/tools/testing/selftests/net/mptcp/mptcp_join.sh b/tools/testing/selftests/net/mptcp/mptcp_join.sh +index 371583009a662..6e684a9a3c616 100755 +--- a/tools/testing/selftests/net/mptcp/mptcp_join.sh ++++ b/tools/testing/selftests/net/mptcp/mptcp_join.sh +@@ -133,8 +133,8 @@ init_shapers() + { + local i + for i in $(seq 1 4); do +- tc -n $ns1 qdisc add dev ns1eth$i root netem rate 20mbit delay 1 +- tc -n $ns2 qdisc add dev ns2eth$i root netem rate 20mbit delay 1 ++ tc -n $ns1 qdisc add dev ns1eth$i root netem rate 20mbit delay 1ms ++ tc -n $ns2 qdisc add dev ns2eth$i root netem rate 20mbit delay 1ms + done + } + +@@ -3261,6 +3261,7 @@ fail_tests() + { + # single subflow + if reset_with_fail "Infinite map" 1; then ++ MPTCP_LIB_SUBTEST_FLAKY=1 + test_linkfail=128 \ + run_tests $ns1 $ns2 10.0.1.1 + chk_join_nr 0 0 0 +1 +0 1 0 1 "$(pedit_action_pkts)" +@@ -3269,7 +3270,8 @@ fail_tests() + + # multiple subflows + if reset_with_fail "MP_FAIL MP_RST" 2; then +- tc -n $ns2 qdisc add dev ns2eth1 root netem rate 1mbit delay 5 ++ MPTCP_LIB_SUBTEST_FLAKY=1 ++ tc -n $ns2 qdisc add dev ns2eth1 root netem rate 1mbit delay 5ms + pm_nl_set_limits $ns1 0 1 + pm_nl_set_limits $ns2 0 1 + pm_nl_add_endpoint $ns2 10.0.2.2 dev ns2eth2 flags subflow +diff --git a/tools/testing/selftests/net/mptcp/simult_flows.sh b/tools/testing/selftests/net/mptcp/simult_flows.sh +index 25693b37f820d..be97a7ed09503 100755 +--- a/tools/testing/selftests/net/mptcp/simult_flows.sh ++++ b/tools/testing/selftests/net/mptcp/simult_flows.sh +@@ -235,8 +235,8 @@ run_test() + shift 4 + local msg=$* + +- [ $delay1 -gt 0 ] && delay1="delay $delay1" || delay1="" +- [ $delay2 -gt 0 ] && delay2="delay $delay2" || delay2="" ++ [ $delay1 -gt 0 ] && delay1="delay ${delay1}ms" || delay1="" ++ [ $delay2 -gt 0 ] && delay2="delay ${delay2}ms" || delay2="" + + for dev in ns1eth1 ns1eth2; do + tc -n $ns1 qdisc del dev $dev root >/dev/null 2>&1 +@@ -262,7 +262,7 @@ run_test() + do_transfer $small $large $time + lret=$? + mptcp_lib_result_code "${lret}" "${msg}" +- if [ $lret -ne 0 ]; then ++ if [ $lret -ne 0 ] && ! mptcp_lib_subtest_is_flaky; then + ret=$lret + [ $bail -eq 0 ] || exit $ret + fi +@@ -272,7 +272,7 @@ run_test() + do_transfer $large $small $time + lret=$? + mptcp_lib_result_code "${lret}" "${msg}" +- if [ $lret -ne 0 ]; then ++ if [ $lret -ne 0 ] && ! mptcp_lib_subtest_is_flaky; then + ret=$lret + [ $bail -eq 0 ] || exit $ret + fi +@@ -305,7 +305,7 @@ run_test 10 10 0 0 "balanced bwidth" + run_test 10 10 1 25 "balanced bwidth with unbalanced delay" + + # we still need some additional infrastructure to pass the following test-cases +-run_test 10 3 0 0 "unbalanced bwidth" ++MPTCP_LIB_SUBTEST_FLAKY=1 run_test 10 3 0 0 "unbalanced bwidth" + run_test 10 3 1 25 "unbalanced bwidth with unbalanced delay" + run_test 10 3 25 1 "unbalanced bwidth with opposed, unbalanced delay" + +diff --git a/tools/testing/selftests/powerpc/dexcr/Makefile b/tools/testing/selftests/powerpc/dexcr/Makefile +index 76210f2bcec3c..829ad075b4a44 100644 +--- a/tools/testing/selftests/powerpc/dexcr/Makefile ++++ b/tools/testing/selftests/powerpc/dexcr/Makefile +@@ -3,7 +3,7 @@ TEST_GEN_FILES := lsdexcr + + include ../../lib.mk + +-$(OUTPUT)/hashchk_test: CFLAGS += -fno-pie $(call cc-option,-mno-rop-protect) ++$(OUTPUT)/hashchk_test: CFLAGS += -fno-pie -no-pie $(call cc-option,-mno-rop-protect) + + $(TEST_GEN_PROGS): ../harness.c ../utils.c ./dexcr.c + $(TEST_GEN_FILES): ../utils.c ./dexcr.c +diff --git a/tools/testing/selftests/resctrl/Makefile b/tools/testing/selftests/resctrl/Makefile +index 2deac2031de9e..021863f86053a 100644 +--- a/tools/testing/selftests/resctrl/Makefile ++++ b/tools/testing/selftests/resctrl/Makefile +@@ -5,6 +5,8 @@ CFLAGS += $(KHDR_INCLUDES) + + TEST_GEN_PROGS := resctrl_tests + ++LOCAL_HDRS += $(wildcard *.h) ++ + include ../lib.mk + +-$(OUTPUT)/resctrl_tests: $(wildcard *.[ch]) ++$(OUTPUT)/resctrl_tests: $(wildcard *.c) +diff --git a/tools/testing/selftests/syscall_user_dispatch/sud_test.c b/tools/testing/selftests/syscall_user_dispatch/sud_test.c +index b5d592d4099e8..d975a67673299 100644 +--- a/tools/testing/selftests/syscall_user_dispatch/sud_test.c ++++ b/tools/testing/selftests/syscall_user_dispatch/sud_test.c +@@ -158,6 +158,20 @@ static void handle_sigsys(int sig, siginfo_t *info, void *ucontext) + + /* In preparation for sigreturn. */ + SYSCALL_DISPATCH_OFF(glob_sel); ++ ++ /* ++ * The tests for argument handling assume that `syscall(x) == x`. This ++ * is a NOP on x86 because the syscall number is passed in %rax, which ++ * happens to also be the function ABI return register. Other ++ * architectures may need to swizzle the arguments around. ++ */ ++#if defined(__riscv) ++/* REG_A7 is not defined in libc headers */ ++# define REG_A7 (REG_A0 + 7) ++ ++ ((ucontext_t *)ucontext)->uc_mcontext.__gregs[REG_A0] = ++ ((ucontext_t *)ucontext)->uc_mcontext.__gregs[REG_A7]; ++#endif + } + + TEST(dispatch_and_return) +diff --git a/tools/testing/selftests/tc-testing/tc-tests/qdiscs/taprio.json b/tools/testing/selftests/tc-testing/tc-tests/qdiscs/taprio.json +index 0599635c4bc65..6a6f61ac48587 100644 +--- a/tools/testing/selftests/tc-testing/tc-tests/qdiscs/taprio.json ++++ b/tools/testing/selftests/tc-testing/tc-tests/qdiscs/taprio.json +@@ -132,6 +132,50 @@ + "echo \"1\" > /sys/bus/netdevsim/del_device" + ] + }, ++ { ++ "id": "6f62", ++ "name": "Add taprio Qdisc with too short interval", ++ "category": [ ++ "qdisc", ++ "taprio" ++ ], ++ "plugins": { ++ "requires": "nsPlugin" ++ }, ++ "setup": [ ++ "echo \"1 1 8\" > /sys/bus/netdevsim/new_device" ++ ], ++ "cmdUnderTest": "$TC qdisc add dev $ETH root handle 1: taprio num_tc 2 queues 1@0 1@1 sched-entry S 01 300 sched-entry S 02 1700 clockid CLOCK_TAI", ++ "expExitCode": "2", ++ "verifyCmd": "$TC qdisc show dev $ETH", ++ "matchPattern": "qdisc taprio 1: root refcnt", ++ "matchCount": "0", ++ "teardown": [ ++ "echo \"1\" > /sys/bus/netdevsim/del_device" ++ ] ++ }, ++ { ++ "id": "831f", ++ "name": "Add taprio Qdisc with too short cycle-time", ++ "category": [ ++ "qdisc", ++ "taprio" ++ ], ++ "plugins": { ++ "requires": "nsPlugin" ++ }, ++ "setup": [ ++ "echo \"1 1 8\" > /sys/bus/netdevsim/new_device" ++ ], ++ "cmdUnderTest": "$TC qdisc add dev $ETH root handle 1: taprio num_tc 2 queues 1@0 1@1 sched-entry S 01 200000 sched-entry S 02 200000 cycle-time 100 clockid CLOCK_TAI", ++ "expExitCode": "2", ++ "verifyCmd": "$TC qdisc show dev $ETH", ++ "matchPattern": "qdisc taprio 1: root refcnt", ++ "matchCount": "0", ++ "teardown": [ ++ "echo \"1\" > /sys/bus/netdevsim/del_device" ++ ] ++ }, + { + "id": "3e1e", + "name": "Add taprio Qdisc with an invalid cycle-time", +diff --git a/tools/tracing/latency/latency-collector.c b/tools/tracing/latency/latency-collector.c +index 0fd9c747d396d..cf263fe9deaf4 100644 +--- a/tools/tracing/latency/latency-collector.c ++++ b/tools/tracing/latency/latency-collector.c +@@ -935,12 +935,12 @@ static void show_available(void) + } + + if (!tracers) { +- warnx(no_tracer_msg); ++ warnx("%s", no_tracer_msg); + return; + } + + if (!found) { +- warnx(no_latency_tr_msg); ++ warnx("%s", no_latency_tr_msg); + tracefs_list_free(tracers); + return; + } +@@ -983,7 +983,7 @@ static const char *find_default_tracer(void) + for (i = 0; relevant_tracers[i]; i++) { + valid = tracer_valid(relevant_tracers[i], ¬racer); + if (notracer) +- errx(EXIT_FAILURE, no_tracer_msg); ++ errx(EXIT_FAILURE, "%s", no_tracer_msg); + if (valid) + return relevant_tracers[i]; + } +@@ -1878,7 +1878,7 @@ static void scan_arguments(int argc, char *argv[]) + } + valid = tracer_valid(current_tracer, ¬racer); + if (notracer) +- errx(EXIT_FAILURE, no_tracer_msg); ++ errx(EXIT_FAILURE, "%s", no_tracer_msg); + if (!valid) + errx(EXIT_FAILURE, + "The tracer %s is not supported by your kernel!\n", current_tracer);