From 219530647416b7349b498e32caadea3bfc0dcf78 Mon Sep 17 00:00:00 2001 From: Shuai Zhang Date: Tue, 8 Jul 2025 14:55:00 +0800 Subject: [PATCH 0001/2333] FROMLIST: driver: bluetooth: hci_qca: fix ssr fail when BT_EN is consistently pulled up by hardware If BT_EN is consistently pulled up by hardware, the QCA_SSR_TRIGGERED and QCA_IBS_DISABLED bits cannot be cleared by qca_setup during SSR. This leads to a failure to send commands due to the error state. To address this, clear QCA_SSR_TRIGGERED and QCA_IBS_DISABLED bits after the coredump collection is complete. Also, add a delay to wait for controller to complete SSR. Signed-off-by: Shuai Zhang Link: https://lore.kernel.org/all/20250825113858.4017780-1-quic_shuaz@quicinc.com/ --- drivers/bluetooth/hci_qca.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c index 33c43503714b8..907d4ca794dfb 100644 --- a/drivers/bluetooth/hci_qca.c +++ b/drivers/bluetooth/hci_qca.c @@ -1653,6 +1653,23 @@ static void qca_hw_error(struct hci_dev *hdev, u8 code) } clear_bit(QCA_HW_ERROR_EVENT, &qca->flags); + + /* + * If the SoC always enables the bt_en pin via hardware and the driver + * cannot control the bt_en pin of the SoC chip, then during SSR, + * the QCA_SSR_TRIGGERED and QCA_IBS_DISABLED bits cannot be cleared. + * This leads to a reset command timeout failure. + * + * To address this, clear QCA_SSR_TRIGGERED and QCA_IBS_DISABLED bits + * after the coredump collection is complete. + * Also, add msleep delay to wait for controller to complete SSR. + */ + if (!hci_test_quirk(hu->hdev, HCI_QUIRK_NON_PERSISTENT_SETUP)) { + clear_bit(QCA_SSR_TRIGGERED, &qca->flags); + clear_bit(QCA_IBS_DISABLED, &qca->flags); + qca->tx_ibs_state = HCI_IBS_TX_AWAKE; + msleep(50); + } } static void qca_reset(struct hci_dev *hdev) From b5902f2daf61ad3eed61a9fbf3d75ba3748cf53e Mon Sep 17 00:00:00 2001 From: Shuai Zhang Date: Tue, 8 Jul 2025 14:59:40 +0800 Subject: [PATCH 0002/2333] FROMLIST: driver: bluetooth: hci_qca: Multiple triggers of SSR only generate one coredump file Multiple triggers of SSR only first generate coredump file, duo to memcoredump_flag no clear. add clear coredump flag when ssr completed. Signed-off-by: Shuai Zhang Link: https://lore.kernel.org/all/20250825113858.4017780-1-quic_shuaz@quicinc.com/ --- drivers/bluetooth/hci_qca.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c index 907d4ca794dfb..29e391058fee5 100644 --- a/drivers/bluetooth/hci_qca.c +++ b/drivers/bluetooth/hci_qca.c @@ -1668,6 +1668,7 @@ static void qca_hw_error(struct hci_dev *hdev, u8 code) clear_bit(QCA_SSR_TRIGGERED, &qca->flags); clear_bit(QCA_IBS_DISABLED, &qca->flags); qca->tx_ibs_state = HCI_IBS_TX_AWAKE; + qca->memdump_state = QCA_MEMDUMP_IDLE; msleep(50); } } From eb36d9dbce445b0a2032775a5668ba02dd4b67cb Mon Sep 17 00:00:00 2001 From: Komal Bajaj Date: Thu, 31 Jul 2025 14:31:32 +0530 Subject: [PATCH 0003/2333] FROMLIST: usb: misc: qcom_eud: Access EUD_MODE_MANAGER2 through secure calls EUD_MODE_MANAGER2 register is mapped to a memory region that is marked as read-only for operating system running at EL1, enforcing access restrictions that prohibit direct memory-mapped writes via writel(). Attempts to write to this region from HLOS can result in silent failures or memory access violations, particularly when toggling EUD (Embedded USB Debugger) state. To ensure secure register access, modify the driver to use qcom_scm_io_writel(), which routes the write operation to Qualcomm Secure Channel Monitor (SCM). SCM has the necessary permissions to access protected memory regions, enabling reliable control over EUD state. SC7280, the only user of EUD is also affected, indicating that this could never have worked on a properly fused device. Link: https://lore.kernel.org/r/20250731-eud_mode_manager_secure_access-v8-1-4a5dcbb79f41@oss.qualcomm.com Fixes: 9a1bf58ccd44 ("usb: misc: eud: Add driver support for Embedded USB Debugger(EUD)") Signed-off-by: Melody Olvera Reviewed-by: Konrad Dybcio Reviewed-by: Dmitry Baryshkov Reviewed-by: Souradeep Chowdhury Signed-off-by: Komal Bajaj --- drivers/usb/misc/Kconfig | 1 + drivers/usb/misc/qcom_eud.c | 33 ++++++++++++++++++++++++--------- 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig index 6497c4e81e951..9bf8fc6247bac 100644 --- a/drivers/usb/misc/Kconfig +++ b/drivers/usb/misc/Kconfig @@ -147,6 +147,7 @@ config USB_APPLEDISPLAY config USB_QCOM_EUD tristate "QCOM Embedded USB Debugger(EUD) Driver" depends on ARCH_QCOM || COMPILE_TEST + select QCOM_SCM select USB_ROLE_SWITCH help This module enables support for Qualcomm Technologies, Inc. diff --git a/drivers/usb/misc/qcom_eud.c b/drivers/usb/misc/qcom_eud.c index 83079c414b4f2..05c8bdc943a88 100644 --- a/drivers/usb/misc/qcom_eud.c +++ b/drivers/usb/misc/qcom_eud.c @@ -15,6 +15,7 @@ #include #include #include +#include #define EUD_REG_INT1_EN_MASK 0x0024 #define EUD_REG_INT_STATUS_1 0x0044 @@ -34,7 +35,7 @@ struct eud_chip { struct device *dev; struct usb_role_switch *role_sw; void __iomem *base; - void __iomem *mode_mgr; + phys_addr_t mode_mgr; unsigned int int_status; int irq; bool enabled; @@ -43,18 +44,29 @@ struct eud_chip { static int enable_eud(struct eud_chip *priv) { + int ret; + + ret = qcom_scm_io_writel(priv->mode_mgr + EUD_REG_EUD_EN2, 1); + if (ret) + return ret; + writel(EUD_ENABLE, priv->base + EUD_REG_CSR_EUD_EN); writel(EUD_INT_VBUS | EUD_INT_SAFE_MODE, priv->base + EUD_REG_INT1_EN_MASK); - writel(1, priv->mode_mgr + EUD_REG_EUD_EN2); return usb_role_switch_set_role(priv->role_sw, USB_ROLE_DEVICE); } -static void disable_eud(struct eud_chip *priv) +static int disable_eud(struct eud_chip *priv) { + int ret; + + ret = qcom_scm_io_writel(priv->mode_mgr + EUD_REG_EUD_EN2, 0); + if (ret) + return ret; + writel(0, priv->base + EUD_REG_CSR_EUD_EN); - writel(0, priv->mode_mgr + EUD_REG_EUD_EN2); + return 0; } static ssize_t enable_show(struct device *dev, @@ -82,11 +94,12 @@ static ssize_t enable_store(struct device *dev, chip->enabled = enable; else disable_eud(chip); + } else { - disable_eud(chip); + ret = disable_eud(chip); } - return count; + return ret < 0 ? ret : count; } static DEVICE_ATTR_RW(enable); @@ -178,6 +191,7 @@ static void eud_role_switch_release(void *data) static int eud_probe(struct platform_device *pdev) { struct eud_chip *chip; + struct resource *res; int ret; chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); @@ -200,9 +214,10 @@ static int eud_probe(struct platform_device *pdev) if (IS_ERR(chip->base)) return PTR_ERR(chip->base); - chip->mode_mgr = devm_platform_ioremap_resource(pdev, 1); - if (IS_ERR(chip->mode_mgr)) - return PTR_ERR(chip->mode_mgr); + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (!res) + return -ENODEV; + chip->mode_mgr = res->start; chip->irq = platform_get_irq(pdev, 0); if (chip->irq < 0) From 70642b53d2ea7beb5e5d0d7d7078e7e80691ccee Mon Sep 17 00:00:00 2001 From: "Yu Zhang(Yuriy)" Date: Fri, 19 Sep 2025 17:17:18 +0800 Subject: [PATCH 0004/2333] FROMLIST: arm64: dts: qcom: qcs615-ride: Set drive strength for wlan-en-state pin Set the drive-strength to 16mA for gpio98 used as wlan-en-state in the QCS615 ride platform device tree. This ensures sufficient output strength for controlling the WLAN enable signal reliably. Signed-off-by: Yu Zhang(Yuriy) Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/all/20250918112729.3512516-1-yu.zhang@oss.qualcomm.com/ --- arch/arm64/boot/dts/qcom/qcs615-ride.dts | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/boot/dts/qcom/qcs615-ride.dts b/arch/arm64/boot/dts/qcom/qcs615-ride.dts index 705ea71b07a10..618279dd32329 100644 --- a/arch/arm64/boot/dts/qcom/qcs615-ride.dts +++ b/arch/arm64/boot/dts/qcom/qcs615-ride.dts @@ -397,6 +397,7 @@ wlan_en_state: wlan-en-state { pins = "gpio98"; function = "gpio"; + drive-strength = <16>; bias-pull-down; output-low; }; From 27d67265598c4bfde858988e044e5bca42bd847a Mon Sep 17 00:00:00 2001 From: Li Liu Date: Wed, 3 Sep 2025 18:49:28 +0800 Subject: [PATCH 0005/2333] FROMLIST: arm64: dts: qcom: Add display support for QCS615 Add display MDSS and DSI configuration for QCS615 platform. QCS615 has a DP port, and DP support will be added in a later patch. Link: https://lore.kernel.org/all/20250903-add-display-support-for-qcs615-platform-v8-1-7971c05d1262@oss.qualcomm.com/ Reviewed-by: Dmitry Baryshkov Signed-off-by: Li Liu Signed-off-by: Fange Zhang Reviewed-by: Konrad Dybcio --- arch/arm64/boot/dts/qcom/sm6150.dtsi | 182 ++++++++++++++++++++++++++- 1 file changed, 180 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm6150.dtsi b/arch/arm64/boot/dts/qcom/sm6150.dtsi index 3d2a1cb02b628..6128d8c48f9c0 100644 --- a/arch/arm64/boot/dts/qcom/sm6150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150.dtsi @@ -3,6 +3,7 @@ * Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. */ +#include #include #include #include @@ -3657,14 +3658,191 @@ #power-domain-cells = <1>; }; + mdss: display-subsystem@ae00000 { + compatible = "qcom,sm6150-mdss"; + reg = <0x0 0x0ae00000 0x0 0x1000>; + reg-names = "mdss"; + + interconnects = <&mmss_noc MASTER_MDP0 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ACTIVE_ONLY + &config_noc SLAVE_DISPLAY_CFG QCOM_ICC_TAG_ACTIVE_ONLY>; + interconnect-names = "mdp0-mem", + "cpu-cfg"; + + power-domains = <&dispcc MDSS_CORE_GDSC>; + + clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>, + <&gcc GCC_DISP_HF_AXI_CLK>, + <&dispcc DISP_CC_MDSS_MDP_CLK>; + + interrupts = ; + interrupt-controller; + #interrupt-cells = <1>; + + iommus = <&apps_smmu 0x800 0x0>; + + #address-cells = <2>; + #size-cells = <2>; + ranges; + + status = "disabled"; + + mdss_mdp: display-controller@ae01000 { + compatible = "qcom,sm6150-dpu"; + reg = <0x0 0x0ae01000 0x0 0x8f000>, + <0x0 0x0aeb0000 0x0 0x2008>; + reg-names = "mdp", + "vbif"; + + clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>, + <&gcc GCC_DISP_HF_AXI_CLK>, + <&dispcc DISP_CC_MDSS_MDP_CLK>, + <&dispcc DISP_CC_MDSS_VSYNC_CLK>; + clock-names = "iface", + "bus", + "core", + "vsync"; + + operating-points-v2 = <&mdp_opp_table>; + power-domains = <&rpmhpd RPMHPD_CX>; + + interrupts-extended = <&mdss 0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + dpu_intf0_out: endpoint { + }; + }; + + port@1 { + reg = <1>; + + dpu_intf1_out: endpoint { + remote-endpoint = <&mdss_dsi0_in>; + }; + }; + }; + + mdp_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-192000000 { + opp-hz = /bits/ 64 <192000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + + opp-256000000 { + opp-hz = /bits/ 64 <256000000>; + required-opps = <&rpmhpd_opp_svs>; + }; + + opp-307200000 { + opp-hz = /bits/ 64 <307200000>; + required-opps = <&rpmhpd_opp_nom>; + }; + }; + }; + + mdss_dsi0: dsi@ae94000 { + compatible = "qcom,sm6150-dsi-ctrl", "qcom,mdss-dsi-ctrl"; + reg = <0x0 0x0ae94000 0x0 0x400>; + reg-names = "dsi_ctrl"; + + interrupts-extended = <&mdss 4>; + + clocks = <&dispcc DISP_CC_MDSS_BYTE0_CLK>, + <&dispcc DISP_CC_MDSS_BYTE0_INTF_CLK>, + <&dispcc DISP_CC_MDSS_PCLK0_CLK>, + <&dispcc DISP_CC_MDSS_ESC0_CLK>, + <&dispcc DISP_CC_MDSS_AHB_CLK>, + <&gcc GCC_DISP_HF_AXI_CLK>; + clock-names = "byte", + "byte_intf", + "pixel", + "core", + "iface", + "bus"; + + assigned-clocks = <&dispcc DISP_CC_MDSS_BYTE0_CLK_SRC>, + <&dispcc DISP_CC_MDSS_PCLK0_CLK_SRC>; + assigned-clock-parents = <&mdss_dsi0_phy DSI_BYTE_PLL_CLK>, + <&mdss_dsi0_phy DSI_PIXEL_PLL_CLK>; + + operating-points-v2 = <&dsi0_opp_table>; + power-domains = <&rpmhpd RPMHPD_CX>; + + phys = <&mdss_dsi0_phy>; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + + dsi0_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-164000000 { + opp-hz = /bits/ 64 <164000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + }; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + mdss_dsi0_in: endpoint { + remote-endpoint = <&dpu_intf1_out>; + }; + }; + + port@1 { + reg = <1>; + + mdss_dsi0_out: endpoint { + }; + }; + }; + }; + + mdss_dsi0_phy: phy@ae94400 { + compatible = "qcom,sm6150-dsi-phy-14nm"; + reg = <0x0 0x0ae94400 0x0 0x100>, + <0x0 0x0ae94500 0x0 0x300>, + <0x0 0x0ae94800 0x0 0x124>; + reg-names = "dsi_phy", + "dsi_phy_lane", + "dsi_pll"; + + #clock-cells = <1>; + #phy-cells = <0>; + + clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>, + <&rpmhcc RPMH_CXO_CLK>; + clock-names = "iface", + "ref"; + + status = "disabled"; + }; + }; + dispcc: clock-controller@af00000 { compatible = "qcom,qcs615-dispcc"; reg = <0 0x0af00000 0 0x20000>; clocks = <&rpmhcc RPMH_CXO_CLK>, <&gcc GCC_DISP_GPLL0_DIV_CLK_SRC>, - <0>, - <0>, + <&mdss_dsi0_phy DSI_BYTE_PLL_CLK>, + <&mdss_dsi0_phy DSI_PIXEL_PLL_CLK>, <0>, <0>, <0>; From 740223014f43c7b1e77f02ddd43bb3ad40ecb6c9 Mon Sep 17 00:00:00 2001 From: Li Liu Date: Wed, 3 Sep 2025 18:49:29 +0800 Subject: [PATCH 0006/2333] FROMLIST: arm64: dts: qcom: Add display support for QCS615 RIDE board Add display MDSS and DSI configuration for QCS615 RIDE board. QCS615 has a DP port, and DP support will be added in a later patch. Link: https://lore.kernel.org/all/20250903-add-display-support-for-qcs615-platform-v8-2-7971c05d1262@oss.qualcomm.com/ Reviewed-by: Dmitry Baryshkov Signed-off-by: Li Liu Signed-off-by: Fange Zhang --- arch/arm64/boot/dts/qcom/qcs615-ride.dts | 150 +++++++++++++++++++++++ 1 file changed, 150 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/qcs615-ride.dts b/arch/arm64/boot/dts/qcom/qcs615-ride.dts index 618279dd32329..d0092a7299e68 100644 --- a/arch/arm64/boot/dts/qcom/qcs615-ride.dts +++ b/arch/arm64/boot/dts/qcom/qcs615-ride.dts @@ -39,6 +39,18 @@ }; }; + dp-dsi0-connector { + compatible = "dp-connector"; + label = "DSI0"; + type = "mini"; + + port { + dp_dsi0_connector_in: endpoint { + remote-endpoint = <&dsi2dp_bridge_out>; + }; + }; + }; + vreg_conn_1p8: regulator-conn-1p8 { compatible = "regulator-fixed"; regulator-name = "vreg_conn_1p8"; @@ -65,6 +77,64 @@ regulator-always-on; }; + vreg_12p0: regulator-vreg-12p0 { + compatible = "regulator-fixed"; + regulator-name = "VREG_12P0"; + + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <12000000>; + regulator-max-microvolt = <12000000>; + }; + + vreg_1p0: regulator-vreg-1p0 { + compatible = "regulator-fixed"; + regulator-name = "VREG_1P0"; + + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1000000>; + + vin-supply = <&vreg_1p8>; + }; + + vreg_1p8: regulator-vreg-1p8 { + compatible = "regulator-fixed"; + regulator-name = "VREG_1P8"; + + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + + vin-supply = <&vreg_5p0>; + }; + + vreg_3p0: regulator-vreg-3p0 { + compatible = "regulator-fixed"; + regulator-name = "VREG_3P0"; + + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; + + vin-supply = <&vreg_12p0>; + }; + + vreg_5p0: regulator-vreg-5p0 { + compatible = "regulator-fixed"; + regulator-name = "VREG_5P0"; + + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + + vin-supply = <&vreg_12p0>; + }; + wcn6855-pmu { compatible = "qcom,wcn6855-pmu"; @@ -288,6 +358,86 @@ }; }; +&i2c2 { + clock-frequency = <400000>; + status = "okay"; + + io_expander: pinctrl@3e { + compatible = "semtech,sx1509q"; + reg = <0x3e>; + interrupts-extended = <&tlmm 58 IRQ_TYPE_EDGE_FALLING>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + semtech,probe-reset; + }; + + i2c-mux@77 { + compatible = "nxp,pca9542"; + reg = <0x77>; + #address-cells = <1>; + #size-cells = <0>; + + i2c@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + + bridge@58 { + compatible = "analogix,anx7625"; + reg = <0x58>; + interrupts-extended = <&io_expander 0 IRQ_TYPE_EDGE_FALLING>; + enable-gpios = <&tlmm 4 GPIO_ACTIVE_HIGH>; + reset-gpios = <&tlmm 5 GPIO_ACTIVE_HIGH>; + vdd10-supply = <&vreg_1p0>; + vdd18-supply = <&vreg_1p8>; + vdd33-supply = <&vreg_3p0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + dsi2dp_bridge_in: endpoint { + remote-endpoint = <&mdss_dsi0_out>; + }; + }; + + port@1 { + reg = <1>; + + dsi2dp_bridge_out: endpoint { + remote-endpoint = <&dp_dsi0_connector_in>; + }; + }; + }; + }; + }; + }; +}; + +&mdss { + status = "okay"; +}; + +&mdss_dsi0 { + vdda-supply = <&vreg_l11a>; + status = "okay"; +}; + +&mdss_dsi0_out { + remote-endpoint = <&dsi2dp_bridge_in>; + data-lanes = <0 1 2 3>; +}; + +&mdss_dsi0_phy { + vcca-supply = <&vreg_l5a>; + status = "okay"; +}; + &pcie { perst-gpios = <&tlmm 101 GPIO_ACTIVE_LOW>; wake-gpios = <&tlmm 100 GPIO_ACTIVE_HIGH>; From b879f8a11b8ec146249e66e98499769873d5711b Mon Sep 17 00:00:00 2001 From: Song Xue Date: Mon, 22 Sep 2025 19:10:24 +0530 Subject: [PATCH 0007/2333] FROMLIST: arm64: dts: qcom: qcs615-ride: Add PSCI SYSTEM_RESET2 types Add support for SYSTEM_RESET2 vendor-specific resets in qcs615-ride as reboot-modes. Describe the resets: "bootloader" will cause device to reboot and stop in the bootloader's fastboot mode. "edl" will cause device to reboot into "emergency download mode", which permits loading images via the Firehose protocol. Link: https://lore.kernel.org/r/20250922-arm-psci-system_reset2-vendor-reboots-v15-14-7ce3a08878f1@oss.qualcomm.com Signed-off-by: Song Xue Signed-off-by: Shivendra Pratap --- arch/arm64/boot/dts/qcom/qcs615-ride.dts | 7 +++++++ arch/arm64/boot/dts/qcom/sm6150.dtsi | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/qcs615-ride.dts b/arch/arm64/boot/dts/qcom/qcs615-ride.dts index d0092a7299e68..ba1c1d6cfeebe 100644 --- a/arch/arm64/boot/dts/qcom/qcs615-ride.dts +++ b/arch/arm64/boot/dts/qcom/qcs615-ride.dts @@ -493,6 +493,13 @@ status = "okay"; }; +&psci { + reboot-mode { + mode-bootloader = <0x10001 0x2>; + mode-edl = <0 0x1>; + }; +}; + &qupv3_id_0 { status = "okay"; }; diff --git a/arch/arm64/boot/dts/qcom/sm6150.dtsi b/arch/arm64/boot/dts/qcom/sm6150.dtsi index 6128d8c48f9c0..37aa684768588 100644 --- a/arch/arm64/boot/dts/qcom/sm6150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150.dtsi @@ -417,7 +417,7 @@ }; }; - psci { + psci: psci { compatible = "arm,psci-1.0"; method = "smc"; From 318d871b124f204199bf3bf1b88d8ace436b44e6 Mon Sep 17 00:00:00 2001 From: Ekansh Gupta Date: Mon, 1 Sep 2025 11:03:34 +0530 Subject: [PATCH 0008/2333] FROMLIST: misc: fastrpc: Move fdlist to invoke context structure FD list is part of meta buffer which is calculated during put args. Move fdlist to invoke context structure for better maintenance and to avoid code duplicacy for calculation of critical meta buffer contents that are used by fastrpc driver. Link: https://lore.kernel.org/all/20250901053336.3939595-2-ekansh.gupta@oss.qualcomm.com/ Signed-off-by: Ekansh Gupta --- drivers/misc/fastrpc.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c index 621bce7e101c1..0991ac487192f 100644 --- a/drivers/misc/fastrpc.c +++ b/drivers/misc/fastrpc.c @@ -233,6 +233,7 @@ struct fastrpc_invoke_ctx { int pid; int client_id; u32 sc; + u64 *fdlist; u32 *crc; u64 ctxid; u64 msg_sz; @@ -985,6 +986,7 @@ static int fastrpc_get_args(u32 kernel, struct fastrpc_invoke_ctx *ctx) rpra = ctx->buf->virt; list = fastrpc_invoke_buf_start(rpra, ctx->nscalars); pages = fastrpc_phy_page_start(list, ctx->nscalars); + ctx->fdlist = (u64 *)(pages + ctx->nscalars); args = (uintptr_t)ctx->buf->virt + metalen; rlen = pkt_size - metalen; ctx->rpra = rpra; @@ -1087,18 +1089,10 @@ static int fastrpc_put_args(struct fastrpc_invoke_ctx *ctx, union fastrpc_remote_arg *rpra = ctx->rpra; struct fastrpc_user *fl = ctx->fl; struct fastrpc_map *mmap = NULL; - struct fastrpc_invoke_buf *list; - struct fastrpc_phy_page *pages; - u64 *fdlist; - int i, inbufs, outbufs, handles; + int i, inbufs; int ret = 0; inbufs = REMOTE_SCALARS_INBUFS(ctx->sc); - outbufs = REMOTE_SCALARS_OUTBUFS(ctx->sc); - handles = REMOTE_SCALARS_INHANDLES(ctx->sc) + REMOTE_SCALARS_OUTHANDLES(ctx->sc); - list = fastrpc_invoke_buf_start(rpra, ctx->nscalars); - pages = fastrpc_phy_page_start(list, ctx->nscalars); - fdlist = (uint64_t *)(pages + inbufs + outbufs + handles); for (i = inbufs; i < ctx->nbufs; ++i) { if (!ctx->maps[i]) { @@ -1120,9 +1114,9 @@ static int fastrpc_put_args(struct fastrpc_invoke_ctx *ctx, cleanup_fdlist: /* Clean up fdlist which is updated by DSP */ for (i = 0; i < FASTRPC_MAX_FDLIST; i++) { - if (!fdlist[i]) + if (!ctx->fdlist[i]) break; - if (!fastrpc_map_lookup(fl, (int)fdlist[i], &mmap)) + if (!fastrpc_map_lookup(fl, (int)ctx->fdlist[i], &mmap)) fastrpc_map_put(mmap); } From 3a8075ec5cd16681b6d7beafdb9e8e592cfd579f Mon Sep 17 00:00:00 2001 From: Ekansh Gupta Date: Mon, 1 Sep 2025 11:03:35 +0530 Subject: [PATCH 0009/2333] FROMLIST: misc: fastrpc: Update context ID mask for polling mode support Current fastrpc message context uses a 12-bit mask where the upper 8 bits are context ID from idr_alloc_cyclic and the lower 4 bits represent PD type. This design works for normal fastrpc calls but doesn't work as expected for polling mode. To enable polling mode support from DSP(DSP writes to poll memory), DSP expects a 16-bit context where the upper 8 bits are context ID, the lower 4 bits are PD type and the 5th bit from the end denotes async mode(not yet upstreamed). If this bit is set, DSP disables polling. With the current design, odd context IDs set this bit, causing DSP to skip poll memory updates. Update the context mask to ensure a hole which won't get populated, ensuring polling mode works as expected. Link: https://lore.kernel.org/all/20250901053336.3939595-3-ekansh.gupta@oss.qualcomm.com/ Signed-off-by: Ekansh Gupta --- drivers/misc/fastrpc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c index 0991ac487192f..57e118de6e4ac 100644 --- a/drivers/misc/fastrpc.c +++ b/drivers/misc/fastrpc.c @@ -37,7 +37,7 @@ #define FASTRPC_CTX_MAX (256) #define FASTRPC_INIT_HANDLE 1 #define FASTRPC_DSP_UTILITIES_HANDLE 2 -#define FASTRPC_CTXID_MASK (0xFF0) +#define FASTRPC_CTXID_MASK (0xFF00) #define INIT_FILELEN_MAX (2 * 1024 * 1024) #define INIT_FILE_NAMELEN_MAX (128) #define FASTRPC_DEVICE_NAME "fastrpc" @@ -487,7 +487,7 @@ static void fastrpc_context_free(struct kref *ref) fastrpc_buf_free(ctx->buf); spin_lock_irqsave(&cctx->lock, flags); - idr_remove(&cctx->ctx_idr, ctx->ctxid >> 4); + idr_remove(&cctx->ctx_idr, ctx->ctxid >> 8); spin_unlock_irqrestore(&cctx->lock, flags); kfree(ctx->maps); @@ -623,7 +623,7 @@ static struct fastrpc_invoke_ctx *fastrpc_context_alloc( spin_unlock_irqrestore(&cctx->lock, flags); goto err_idr; } - ctx->ctxid = ret << 4; + ctx->ctxid = ret << 8; spin_unlock_irqrestore(&cctx->lock, flags); kref_init(&ctx->refcount); @@ -2449,7 +2449,7 @@ static int fastrpc_rpmsg_callback(struct rpmsg_device *rpdev, void *data, if (len < sizeof(*rsp)) return -EINVAL; - ctxid = ((rsp->ctx & FASTRPC_CTXID_MASK) >> 4); + ctxid = ((rsp->ctx & FASTRPC_CTXID_MASK) >> 8); spin_lock_irqsave(&cctx->lock, flags); ctx = idr_find(&cctx->ctx_idr, ctxid); From dba4eb255febb4cc38d2e340978c58f8f21ff6cc Mon Sep 17 00:00:00 2001 From: Ekansh Gupta Date: Mon, 1 Sep 2025 11:03:36 +0530 Subject: [PATCH 0010/2333] FROMLIST: misc: fastrpc: Add polling mode support for fastRPC driver For any remote call to DSP, after sending an invocation message, fastRPC driver waits for glink response and during this time the CPU can go into low power modes. This adds latency to overall fastrpc call as CPU wakeup and scheduling latencies are included. Adding a polling mode support with which fastRPC driver will poll continuously on a memory after sending a message to remote subsystem which will eliminate CPU wakeup and scheduling latencies and reduce fastRPC overhead. Link: https://lore.kernel.org/all/20250901053336.3939595-4-ekansh.gupta@oss.qualcomm.com/ Signed-off-by: Ekansh Gupta --- drivers/misc/fastrpc.c | 121 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 114 insertions(+), 7 deletions(-) diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c index 57e118de6e4ac..939a3e3d29e29 100644 --- a/drivers/misc/fastrpc.c +++ b/drivers/misc/fastrpc.c @@ -22,6 +22,8 @@ #include #include #include +#include +#include #define ADSP_DOMAIN_ID (0) #define MDSP_DOMAIN_ID (1) @@ -37,6 +39,7 @@ #define FASTRPC_CTX_MAX (256) #define FASTRPC_INIT_HANDLE 1 #define FASTRPC_DSP_UTILITIES_HANDLE 2 +#define FASTRPC_MAX_STATIC_HANDLE (20) #define FASTRPC_CTXID_MASK (0xFF00) #define INIT_FILELEN_MAX (2 * 1024 * 1024) #define INIT_FILE_NAMELEN_MAX (128) @@ -105,6 +108,20 @@ #define miscdev_to_fdevice(d) container_of(d, struct fastrpc_device, miscdev) +/* Poll response number from remote processor for call completion */ +#define FASTRPC_POLL_RESPONSE (0xdecaf) + +/* Polling mode timeout limit */ +#define FASTRPC_POLL_MAX_TIMEOUT_US (10000) + +/* Response types supported for RPC calls */ +enum fastrpc_response_flags { + /* normal job completion glink response */ + NORMAL_RESPONSE = 0, + /* process updates poll memory instead of glink response */ + POLL_MODE = 1, +}; + struct fastrpc_phy_page { u64 addr; /* physical address */ u64 size; /* size of contiguous region */ @@ -235,8 +252,14 @@ struct fastrpc_invoke_ctx { u32 sc; u64 *fdlist; u32 *crc; + /* Poll memory that DSP updates */ + u32 *poll; u64 ctxid; u64 msg_sz; + /* work done status flag */ + bool is_work_done; + /* response flags from remote processor */ + enum fastrpc_response_flags rsp_flags; struct kref refcount; struct list_head node; /* list of ctxs */ struct completion work; @@ -891,7 +914,8 @@ static int fastrpc_get_meta_size(struct fastrpc_invoke_ctx *ctx) sizeof(struct fastrpc_invoke_buf) + sizeof(struct fastrpc_phy_page)) * ctx->nscalars + sizeof(u64) * FASTRPC_MAX_FDLIST + - sizeof(u32) * FASTRPC_MAX_CRCLIST; + sizeof(u32) * FASTRPC_MAX_CRCLIST + + sizeof(u32); return size; } @@ -987,6 +1011,8 @@ static int fastrpc_get_args(u32 kernel, struct fastrpc_invoke_ctx *ctx) list = fastrpc_invoke_buf_start(rpra, ctx->nscalars); pages = fastrpc_phy_page_start(list, ctx->nscalars); ctx->fdlist = (u64 *)(pages + ctx->nscalars); + ctx->crc = (u32 *)(ctx->fdlist + FASTRPC_MAX_FDLIST); + ctx->poll = (u32 *)(ctx->crc + FASTRPC_MAX_CRCLIST); args = (uintptr_t)ctx->buf->virt + metalen; rlen = pkt_size - metalen; ctx->rpra = rpra; @@ -1155,6 +1181,83 @@ static int fastrpc_invoke_send(struct fastrpc_session_ctx *sctx, } +static inline u32 fastrpc_poll_op(void *p) +{ + struct fastrpc_invoke_ctx *ctx = p; + + dma_rmb(); + return READ_ONCE(*ctx->poll); +} + +static int poll_for_remote_response(struct fastrpc_invoke_ctx *ctx) +{ + u32 val; + int ret; + + /* + * Poll until DSP writes FASTRPC_POLL_RESPONSE into *ctx->poll + * or until another path marks the work done. + */ + ret = read_poll_timeout_atomic(fastrpc_poll_op, val, + (val == FASTRPC_POLL_RESPONSE) || + ctx->is_work_done, 1, + FASTRPC_POLL_MAX_TIMEOUT_US, false, ctx); + + if (!ret && val == FASTRPC_POLL_RESPONSE) { + ctx->is_work_done = true; + ctx->retval = 0; + } + + if (ret == -ETIMEDOUT) + ret = -EIO; + + return ret; +} + +static inline int fastrpc_wait_for_response(struct fastrpc_invoke_ctx *ctx, + u32 kernel) +{ + int err = 0; + + if (kernel) { + if (!wait_for_completion_timeout(&ctx->work, 10 * HZ)) + err = -ETIMEDOUT; + } else { + err = wait_for_completion_interruptible(&ctx->work); + } + + return err; +} + +static int fastrpc_wait_for_completion(struct fastrpc_invoke_ctx *ctx, + u32 kernel) +{ + int err; + + do { + switch (ctx->rsp_flags) { + case NORMAL_RESPONSE: + err = fastrpc_wait_for_response(ctx, kernel); + if (err || ctx->is_work_done) + return err; + break; + case POLL_MODE: + err = poll_for_remote_response(ctx); + /* If polling timed out, move to normal response mode */ + if (err) + ctx->rsp_flags = NORMAL_RESPONSE; + break; + default: + err = -EBADR; + dev_dbg(ctx->fl->sctx->dev, + "unsupported response type:0x%x\n", ctx->rsp_flags); + break; + } + } while (!ctx->is_work_done); + + return err; +} + static int fastrpc_internal_invoke(struct fastrpc_user *fl, u32 kernel, u32 handle, u32 sc, struct fastrpc_invoke_args *args) @@ -1190,16 +1293,19 @@ static int fastrpc_internal_invoke(struct fastrpc_user *fl, u32 kernel, if (err) goto bail; - if (kernel) { - if (!wait_for_completion_timeout(&ctx->work, 10 * HZ)) - err = -ETIMEDOUT; - } else { - err = wait_for_completion_interruptible(&ctx->work); - } + if (handle > FASTRPC_MAX_STATIC_HANDLE && fl->pd == USER_PD) + ctx->rsp_flags = POLL_MODE; + err = fastrpc_wait_for_completion(ctx, kernel); if (err) goto bail; + if (!ctx->is_work_done) { + err = -ETIMEDOUT; + dev_dbg(fl->sctx->dev, "Invalid workdone state for handle 0x%x, sc 0x%x\n", + handle, sc); + goto bail; + } /* make sure that all memory writes by DSP are seen by CPU */ dma_rmb(); /* populate all the output buffers with results */ @@ -2462,6 +2568,7 @@ static int fastrpc_rpmsg_callback(struct rpmsg_device *rpdev, void *data, ctx->retval = rsp->retval; complete(&ctx->work); + ctx->is_work_done = true; /* * The DMA buffer associated with the context cannot be freed in From 8b47388bfa7ce580eb9439795091eb0b0aaff5b8 Mon Sep 17 00:00:00 2001 From: Puranam V G Tejaswi Date: Wed, 10 Sep 2025 16:55:23 +0530 Subject: [PATCH 0011/2333] FROMLIST: arm64: dts: qcom: sa8775p: Add gpu and gmu nodes Add gpu and gmu nodes for sa8775p chipset. Also, add the speedbin qfprom node and wire it up with GPU node. Link: https://lore.kernel.org/r/20250910-a663-gpu-support-v6-3-5da15827b249@oss.qualcomm.com Signed-off-by: Puranam V G Tejaswi Signed-off-by: Akhil P Oommen Reviewed-by: Dmitry Baryshkov --- arch/arm64/boot/dts/qcom/lemans.dtsi | 119 +++++++++++++++++++++++++++ 1 file changed, 119 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/lemans.dtsi b/arch/arm64/boot/dts/qcom/lemans.dtsi index cf685cb186edc..4da1f69729f7c 100644 --- a/arch/arm64/boot/dts/qcom/lemans.dtsi +++ b/arch/arm64/boot/dts/qcom/lemans.dtsi @@ -1098,6 +1098,18 @@ #mbox-cells = <2>; }; + qfprom: efuse@784000 { + compatible = "qcom,sa8775p-qfprom", "qcom,qfprom"; + reg = <0x0 0x00784000 0x0 0x3000>; + #address-cells = <1>; + #size-cells = <1>; + + gpu_speed_bin: gpu_speed_bin@240c { + reg = <0x240c 0x1>; + bits = <0 8>; + }; + }; + gpi_dma2: dma-controller@800000 { compatible = "qcom,sa8775p-gpi-dma", "qcom,sm6350-gpi-dma"; reg = <0x0 0x00800000 0x0 0x60000>; @@ -4128,6 +4140,113 @@ reg = <0x0 0x1fc0000 0x0 0x30000>; }; + gpu: gpu@3d00000 { + compatible = "qcom,adreno-663.0", "qcom,adreno"; + reg = <0x0 0x03d00000 0x0 0x40000>, + <0x0 0x03d9e000 0x0 0x1000>, + <0x0 0x03d61000 0x0 0x800>; + reg-names = "kgsl_3d0_reg_memory", + "cx_mem", + "cx_dbgc"; + interrupts = ; + iommus = <&adreno_smmu 0 0xc00>, + <&adreno_smmu 1 0xc00>; + operating-points-v2 = <&gpu_opp_table>; + qcom,gmu = <&gmu>; + interconnects = <&gem_noc MASTER_GFX3D QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "gfx-mem"; + #cooling-cells = <2>; + + nvmem-cells = <&gpu_speed_bin>; + nvmem-cell-names = "speed_bin"; + + status = "disabled"; + + gpu_zap_shader: zap-shader { + memory-region = <&pil_gpu_mem>; + }; + + gpu_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-405000000 { + opp-hz = /bits/ 64 <405000000>; + opp-level = ; + opp-peak-kBps = <5285156>; + opp-supported-hw = <0x3>; + }; + + opp-530000000 { + opp-hz = /bits/ 64 <530000000>; + opp-level = ; + opp-peak-kBps = <12484375>; + opp-supported-hw = <0x2>; + }; + + opp-676000000 { + opp-hz = /bits/ 64 <676000000>; + opp-level = ; + opp-peak-kBps = <8171875>; + opp-supported-hw = <0x1>; + }; + + opp-778000000 { + opp-hz = /bits/ 64 <778000000>; + opp-level = ; + opp-peak-kBps = <10687500>; + opp-supported-hw = <0x1>; + }; + + opp-800000000 { + opp-hz = /bits/ 64 <800000000>; + opp-level = ; + opp-peak-kBps = <12484375>; + opp-supported-hw = <0x1>; + }; + }; + }; + + gmu: gmu@3d6a000 { + compatible = "qcom,adreno-gmu-663.0", "qcom,adreno-gmu"; + reg = <0x0 0x03d6a000 0x0 0x34000>, + <0x0 0x03de0000 0x0 0x10000>, + <0x0 0x0b290000 0x0 0x10000>; + reg-names = "gmu", "rscc", "gmu_pdc"; + interrupts = , + ; + interrupt-names = "hfi", "gmu"; + clocks = <&gpucc GPU_CC_CX_GMU_CLK>, + <&gpucc GPU_CC_CXO_CLK>, + <&gcc GCC_DDRSS_GPU_AXI_CLK>, + <&gcc GCC_GPU_MEMNOC_GFX_CLK>, + <&gpucc GPU_CC_AHB_CLK>, + <&gpucc GPU_CC_HUB_CX_INT_CLK>, + <&gpucc GPU_CC_HLOS1_VOTE_GPU_SMMU_CLK>; + clock-names = "gmu", + "cxo", + "axi", + "memnoc", + "ahb", + "hub", + "smmu_vote"; + power-domains = <&gpucc GPU_CC_CX_GDSC>, + <&gpucc GPU_CC_GX_GDSC>; + power-domain-names = "cx", + "gx"; + iommus = <&adreno_smmu 5 0xc00>; + operating-points-v2 = <&gmu_opp_table>; + + gmu_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-500000000 { + opp-hz = /bits/ 64 <500000000>; + opp-level = ; + }; + }; + }; + gpucc: clock-controller@3d90000 { compatible = "qcom,sa8775p-gpucc"; reg = <0x0 0x03d90000 0x0 0xa000>; From 8b2358c47f37ea455e4e5f58e21f97fca4ada171 Mon Sep 17 00:00:00 2001 From: Gaurav Kohli Date: Wed, 10 Sep 2025 16:55:24 +0530 Subject: [PATCH 0012/2333] FROMLIST: arm64: dts: qcom: lemans: Add GPU cooling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Unlike the CPU, the GPU does not throttle its speed automatically when it reaches high temperatures. Set up GPU cooling by throttling the GPU speed when reaching 105°C. Link: https://lore.kernel.org/r/20250910-a663-gpu-support-v6-4-5da15827b249@oss.qualcomm.com Signed-off-by: Gaurav Kohli Signed-off-by: Akhil P Oommen Reviewed-by: Konrad Dybcio --- arch/arm64/boot/dts/qcom/lemans.dtsi | 55 +++++++++++++++++++++++++--- 1 file changed, 49 insertions(+), 6 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/lemans.dtsi b/arch/arm64/boot/dts/qcom/lemans.dtsi index 4da1f69729f7c..0e093715b7e98 100644 --- a/arch/arm64/boot/dts/qcom/lemans.dtsi +++ b/arch/arm64/boot/dts/qcom/lemans.dtsi @@ -21,6 +21,7 @@ #include #include #include +#include / { interrupt-parent = <&intc>; @@ -7501,8 +7502,15 @@ thermal-sensors = <&tsens0 5>; + cooling-maps { + map0 { + trip = <&gpuss0_alert0>; + cooling-device = <&gpu THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + }; + trips { - trip-point0 { + gpuss0_alert0: trip-point0 { temperature = <105000>; hysteresis = <5000>; type = "passive"; @@ -7521,8 +7529,15 @@ thermal-sensors = <&tsens0 6>; + cooling-maps { + map0 { + trip = <&gpuss1_alert0>; + cooling-device = <&gpu THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + }; + trips { - trip-point0 { + gpuss1_alert0: trip-point0 { temperature = <105000>; hysteresis = <5000>; type = "passive"; @@ -7541,8 +7556,15 @@ thermal-sensors = <&tsens0 7>; + cooling-maps { + map0 { + trip = <&gpuss2_alert0>; + cooling-device = <&gpu THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + }; + trips { - trip-point0 { + gpuss2_alert0: trip-point0 { temperature = <105000>; hysteresis = <5000>; type = "passive"; @@ -7731,8 +7753,15 @@ thermal-sensors = <&tsens1 5>; + cooling-maps { + map0 { + trip = <&gpuss3_alert0>; + cooling-device = <&gpu THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + }; + trips { - trip-point0 { + gpuss3_alert0: trip-point0 { temperature = <105000>; hysteresis = <5000>; type = "passive"; @@ -7751,8 +7780,15 @@ thermal-sensors = <&tsens1 6>; + cooling-maps { + map0 { + trip = <&gpuss4_alert0>; + cooling-device = <&gpu THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + }; + trips { - trip-point0 { + gpuss4_alert0: trip-point0 { temperature = <105000>; hysteresis = <5000>; type = "passive"; @@ -7771,8 +7807,15 @@ thermal-sensors = <&tsens1 7>; + cooling-maps { + map0 { + trip = <&gpuss5_alert0>; + cooling-device = <&gpu THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + }; + trips { - trip-point0 { + gpuss5_alert0: trip-point0 { temperature = <105000>; hysteresis = <5000>; type = "passive"; From 38820795f45e859d49ffd68da94989654f1b3020 Mon Sep 17 00:00:00 2001 From: Akhil P Oommen Date: Wed, 10 Sep 2025 16:55:25 +0530 Subject: [PATCH 0013/2333] FROMLIST: arm64: dts: qcom: lemans-evk: Enable Adreno 663 GPU Enable GPU for lemans-evk platform and provide path for zap shader. Link: https://lore.kernel.org/r/20250910-a663-gpu-support-v6-5-5da15827b249@oss.qualcomm.com Reviewed-by: Dmitry Baryshkov Signed-off-by: Akhil P Oommen --- arch/arm64/boot/dts/qcom/lemans-evk.dts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/lemans-evk.dts b/arch/arm64/boot/dts/qcom/lemans-evk.dts index c7dc9b8f44578..74f7589806d04 100644 --- a/arch/arm64/boot/dts/qcom/lemans-evk.dts +++ b/arch/arm64/boot/dts/qcom/lemans-evk.dts @@ -453,6 +453,14 @@ status = "okay"; }; +&gpu { + status = "okay"; +}; + +&gpu_zap_shader { + firmware-name = "qcom/sa8775p/a663_zap.mbn"; +}; + &i2c18 { status = "okay"; From 0010e0f9b2fdf01842a52e876b4f3c030e934251 Mon Sep 17 00:00:00 2001 From: Akhil P Oommen Date: Wed, 10 Sep 2025 16:55:26 +0530 Subject: [PATCH 0014/2333] FROMLIST: arm64: dts: qcom: qcs9100-ride: Enable Adreno 663 GPU Enable GPU on both qcs9100-ride platforms and provide the path for zap shader. Link: https://lore.kernel.org/r/20250910-a663-gpu-support-v6-6-5da15827b249@oss.qualcomm.com Reviewed-by: Dmitry Baryshkov Signed-off-by: Akhil P Oommen --- arch/arm64/boot/dts/qcom/lemans-ride-common.dtsi | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/lemans-ride-common.dtsi b/arch/arm64/boot/dts/qcom/lemans-ride-common.dtsi index c69aa2f41ce29..8fb7d1fc6d563 100644 --- a/arch/arm64/boot/dts/qcom/lemans-ride-common.dtsi +++ b/arch/arm64/boot/dts/qcom/lemans-ride-common.dtsi @@ -436,6 +436,14 @@ }; }; +&gpu { + status = "okay"; +}; + +&gpu_zap_shader { + firmware-name = "qcom/sa8775p/a663_zap.mbn"; +}; + &i2c11 { clock-frequency = <400000>; status = "okay"; From f10d6d1ed9dfb03e8c929826f14f7e454c55e24c Mon Sep 17 00:00:00 2001 From: Elliot Berman Date: Wed, 15 Oct 2025 10:08:25 +0530 Subject: [PATCH 0015/2333] FROMLIST: arm64: dts: qcom: lemans-ride: Add PSCI SYSTEM_RESET2 types Add support for SYSTEM_RESET2 vendor-specific resets in lemans-ride as reboot-modes. Describe the resets: "bootloader" will cause device to reboot and stop in the bootloader's fastboot mode. "edl" will cause device to reboot into "emergency download mode", which permits loading images via the Firehose protocol. Link: https://lore.kernel.org/r/20251015-arm-psci-system_reset2-vendor-reboots-v16-10-b98aedaa23ee@oss.qualcomm.com Reviewed-by: Konrad Dybcio Signed-off-by: Elliot Berman Signed-off-by: Shivendra Pratap --- arch/arm64/boot/dts/qcom/lemans-ride-common.dtsi | 7 +++++++ arch/arm64/boot/dts/qcom/lemans.dtsi | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/lemans-ride-common.dtsi b/arch/arm64/boot/dts/qcom/lemans-ride-common.dtsi index 8fb7d1fc6d563..357008250c7fb 100644 --- a/arch/arm64/boot/dts/qcom/lemans-ride-common.dtsi +++ b/arch/arm64/boot/dts/qcom/lemans-ride-common.dtsi @@ -730,6 +730,13 @@ "GNSS_BOOT_MODE"; }; +&psci { + reboot-mode { + mode-bootloader = <0x10001 0x2>; + mode-edl = <0 0x1>; + }; +}; + &qupv3_id_1 { status = "okay"; }; diff --git a/arch/arm64/boot/dts/qcom/lemans.dtsi b/arch/arm64/boot/dts/qcom/lemans.dtsi index 0e093715b7e98..0873830a39aa2 100644 --- a/arch/arm64/boot/dts/qcom/lemans.dtsi +++ b/arch/arm64/boot/dts/qcom/lemans.dtsi @@ -623,7 +623,7 @@ interrupts = ; }; - psci { + psci: psci { compatible = "arm,psci-1.0"; method = "smc"; From 89ac1103b67c5cb7a7005ae93c8524d0d305c288 Mon Sep 17 00:00:00 2001 From: Shivendra Pratap Date: Wed, 15 Oct 2025 10:08:26 +0530 Subject: [PATCH 0016/2333] FROMLIST: arm64: dts: qcom: lemans-evk: Add PSCI SYSTEM_RESET2 types Add support for SYSTEM_RESET2 vendor-specific resets in lemans-evk as reboot-modes. Describe the resets: "bootloader" will cause device to reboot and stop in the bootloader's fastboot mode. "edl" will cause device to reboot into "emergency download mode", which permits loading images via the Firehose protocol. Link: https://lore.kernel.org/r/20251015-arm-psci-system_reset2-vendor-reboots-v16-11-b98aedaa23ee@oss.qualcomm.com Signed-off-by: Shivendra Pratap --- arch/arm64/boot/dts/qcom/lemans-evk.dts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/lemans-evk.dts b/arch/arm64/boot/dts/qcom/lemans-evk.dts index 74f7589806d04..01100bda93c2d 100644 --- a/arch/arm64/boot/dts/qcom/lemans-evk.dts +++ b/arch/arm64/boot/dts/qcom/lemans-evk.dts @@ -595,6 +595,13 @@ status = "okay"; }; +&psci { + reboot-mode { + mode-bootloader = <0x10001 0x2>; + mode-edl = <0 0x1>; + }; +}; + &qupv3_id_0 { status = "okay"; }; From b87798a84a4eafe5f2ace612c1f3ccd5e153cb49 Mon Sep 17 00:00:00 2001 From: Mukesh Ojha Date: Mon, 13 Oct 2025 15:33:17 +0530 Subject: [PATCH 0017/2333] FROMLIST: arm64: dts: qcom: Add EL2 overlay for Lemans All the Lemans IOT variants boards are using Gunyah hypervisor which means that, so far, Linux-based OS could only boot in EL1 on those devices. However, it is possible for us to boot Linux at EL2 on these devices [1]. When running under Gunyah, remote processor firmware IOMMU streams is controlled by the Gunyah however when Linux take ownership of it in EL2, It need to configure it properly to use remote processor. Add a EL2-specific DT overlay and apply it to Lemans IOT variant devices to create -el2.dtb for each of them alongside "normal" dtb. [1] https://docs.qualcomm.com/bundle/publicresource/topics/80-70020-4/boot-developer-touchpoints.html#uefi Link: https://lore.kernel.org/r/20251013-kvm_rprocv5-v5-13-d609ed766061@oss.qualcomm.com Signed-off-by: Mukesh Ojha --- arch/arm64/boot/dts/qcom/Makefile | 8 +++++ arch/arm64/boot/dts/qcom/lemans-el2.dtso | 41 ++++++++++++++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/lemans-el2.dtso diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile index 296688f7cb265..e0791f987ff9a 100644 --- a/arch/arm64/boot/dts/qcom/Makefile +++ b/arch/arm64/boot/dts/qcom/Makefile @@ -33,8 +33,10 @@ dtb-$(CONFIG_ARCH_QCOM) += ipq9574-rdp454.dtb dtb-$(CONFIG_ARCH_QCOM) += lemans-evk.dtb lemans-evk-camera-csi1-imx577-dtbs := lemans-evk.dtb lemans-evk-camera-csi1-imx577.dtbo +lemans-evk-el2-dtbs := lemans-evk.dtb lemans-el2.dtbo dtb-$(CONFIG_ARCH_QCOM) += lemans-evk-camera-csi1-imx577.dtb +dtb-$(CONFIG_ARCH_QCOM) += lemans-evk-el2.dtb dtb-$(CONFIG_ARCH_QCOM) += monaco-evk.dtb dtb-$(CONFIG_ARCH_QCOM) += msm8216-samsung-fortuna3g.dtb dtb-$(CONFIG_ARCH_QCOM) += msm8916-acer-a1-724.dtb @@ -137,6 +139,12 @@ dtb-$(CONFIG_ARCH_QCOM) += qcs8300-ride.dtb dtb-$(CONFIG_ARCH_QCOM) += qcs8550-aim300-aiot.dtb dtb-$(CONFIG_ARCH_QCOM) += qcs9100-ride.dtb dtb-$(CONFIG_ARCH_QCOM) += qcs9100-ride-r3.dtb + +qcs9100-ride-el2-dtbs := qcs9100-ride.dtb lemans-el2.dtbo +qcs9100-ride-r3-el2-dtbs := qcs9100-ride-r3.dtb lemans-el2.dtbo + +dtb-$(CONFIG_ARCH_QCOM) += qcs9100-ride-el2.dtb +dtb-$(CONFIG_ARCH_QCOM) += qcs9100-ride-r3-el2.dtb dtb-$(CONFIG_ARCH_QCOM) += qdu1000-idp.dtb dtb-$(CONFIG_ARCH_QCOM) += qrb2210-rb1.dtb dtb-$(CONFIG_ARCH_QCOM) += qrb4210-rb2.dtb diff --git a/arch/arm64/boot/dts/qcom/lemans-el2.dtso b/arch/arm64/boot/dts/qcom/lemans-el2.dtso new file mode 100644 index 0000000000000..af35039946e30 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/lemans-el2.dtso @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +/* + * Lemans specific modifications required to boot in EL2. + */ + +/dts-v1/; +/plugin/; + +&iris { + /* More driver work is needed */ + status = "disabled"; +}; + +/* + * When running under Gunyah, remote processor firmware IOMMU streams is + * controlled by the Gunyah however when we take ownership of it in EL2, + * we need to configure it properly to use remote processor. + */ +&remoteproc_adsp { + iommus = <&apps_smmu 0x3000 0x0>; +}; + +&remoteproc_cdsp0 { + iommus = <&apps_smmu 0x21c0 0x0400>; +}; + +&remoteproc_cdsp1 { + iommus = <&apps_smmu 0x29c0 0x0400>; +}; + +&remoteproc_gpdsp0 { + iommus = <&apps_smmu 0x38a0 0x0>; +}; + +&remoteproc_gpdsp1 { + iommus = <&apps_smmu 0x38c0 0x0>; +}; From f75c31875e21700a4a84b024a34458d32cfc3d81 Mon Sep 17 00:00:00 2001 From: Yongxing Mou Date: Wed, 17 Sep 2025 14:09:47 +0800 Subject: [PATCH 0018/2333] FROMLIST: arm64: dts: qcom: qcs8300: add display dt nodes for MDSS, DPU, DisplayPort and eDP PHY Add devicetree changes to enable MDSS display-subsystem, display-controller(DPU), DisplayPort controller and eDP PHY for Qualcomm QCS8300 platform. Link: https://lore.kernel.org/r/20250917-dts_qcs8300-v6-1-5c862aa80f64@oss.qualcomm.com Reviewed-by: Konrad Dybcio Signed-off-by: Yongxing Mou --- arch/arm64/boot/dts/qcom/qcs8300.dtsi | 220 +++++++++++++++++++++++++- 1 file changed, 219 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/qcs8300.dtsi b/arch/arm64/boot/dts/qcom/qcs8300.dtsi index 8d78ccac411e4..e0e1f63fc45b0 100644 --- a/arch/arm64/boot/dts/qcom/qcs8300.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs8300.dtsi @@ -4782,6 +4782,222 @@ #power-domain-cells = <1>; }; + mdss: display-subsystem@ae00000 { + compatible = "qcom,qcs8300-mdss"; + reg = <0x0 0x0ae00000 0x0 0x1000>; + reg-names = "mdss"; + + interrupts = ; + + clocks = <&dispcc MDSS_DISP_CC_MDSS_AHB_CLK>, + <&gcc GCC_DISP_HF_AXI_CLK>, + <&dispcc MDSS_DISP_CC_MDSS_MDP_CLK>; + + resets = <&dispcc MDSS_DISP_CC_MDSS_CORE_BCR>; + + interconnects = <&mmss_noc MASTER_MDP0 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>, + <&mmss_noc MASTER_MDP1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ACTIVE_ONLY + &config_noc SLAVE_DISPLAY_CFG QCOM_ICC_TAG_ACTIVE_ONLY>; + interconnect-names = "mdp0-mem", + "mdp1-mem", + "cpu-cfg"; + + power-domains = <&dispcc MDSS_DISP_CC_MDSS_CORE_GDSC>; + + iommus = <&apps_smmu 0x1000 0x402>; + + interrupt-controller; + #interrupt-cells = <1>; + + #address-cells = <2>; + #size-cells = <2>; + ranges; + + status = "disabled"; + + mdss_mdp: display-controller@ae01000 { + compatible = "qcom,qcs8300-dpu", "qcom,sa8775p-dpu"; + reg = <0x0 0x0ae01000 0x0 0x8f000>, + <0x0 0x0aeb0000 0x0 0x2008>; + reg-names = "mdp", "vbif"; + + interrupts-extended = <&mdss 0>; + + clocks = <&gcc GCC_DISP_HF_AXI_CLK>, + <&dispcc MDSS_DISP_CC_MDSS_AHB_CLK>, + <&dispcc MDSS_DISP_CC_MDSS_MDP_LUT_CLK>, + <&dispcc MDSS_DISP_CC_MDSS_MDP_CLK>, + <&dispcc MDSS_DISP_CC_MDSS_VSYNC_CLK>; + clock-names = "nrt_bus", + "iface", + "lut", + "core", + "vsync"; + + assigned-clocks = <&dispcc MDSS_DISP_CC_MDSS_VSYNC_CLK>; + assigned-clock-rates = <19200000>; + + operating-points-v2 = <&mdp_opp_table>; + power-domains = <&rpmhpd RPMHPD_MMCX>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + dpu_intf0_out: endpoint { + remote-endpoint = <&mdss_dp0_in>; + }; + }; + }; + + mdp_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-375000000 { + opp-hz = /bits/ 64 <375000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-500000000 { + opp-hz = /bits/ 64 <500000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + + opp-575000000 { + opp-hz = /bits/ 64 <575000000>; + required-opps = <&rpmhpd_opp_turbo>; + }; + + opp-650000000 { + opp-hz = /bits/ 64 <650000000>; + required-opps = <&rpmhpd_opp_turbo_l1>; + }; + }; + }; + + mdss_dp0_phy: phy@aec2a00 { + compatible = "qcom,qcs8300-edp-phy", "qcom,sa8775p-edp-phy"; + + reg = <0x0 0x0aec2a00 0x0 0x19c>, + <0x0 0x0aec2200 0x0 0xec>, + <0x0 0x0aec2600 0x0 0xec>, + <0x0 0x0aec2000 0x0 0x1c8>; + + clocks = <&dispcc MDSS_DISP_CC_MDSS_DPTX0_AUX_CLK>, + <&dispcc MDSS_DISP_CC_MDSS_AHB_CLK>; + clock-names = "aux", + "cfg_ahb"; + + power-domains = <&rpmhpd RPMHPD_MX>; + + #clock-cells = <1>; + #phy-cells = <0>; + + status = "disabled"; + }; + + mdss_dp0: displayport-controller@af54000 { + compatible = "qcom,qcs8300-dp", "qcom,sa8775p-dp"; + + reg = <0x0 0x0af54000 0x0 0x200>, + <0x0 0x0af54200 0x0 0x200>, + <0x0 0x0af55000 0x0 0xc00>, + <0x0 0x0af56000 0x0 0x09c>, + <0x0 0x0af57000 0x0 0x09c>, + <0x0 0x0af58000 0x0 0x09c>, + <0x0 0x0af59000 0x0 0x09c>, + <0x0 0x0af5a000 0x0 0x23c>, + <0x0 0x0af5b000 0x0 0x23c>; + + interrupts-extended = <&mdss 12>; + + clocks = <&dispcc MDSS_DISP_CC_MDSS_AHB_CLK>, + <&dispcc MDSS_DISP_CC_MDSS_DPTX0_AUX_CLK>, + <&dispcc MDSS_DISP_CC_MDSS_DPTX0_LINK_CLK>, + <&dispcc MDSS_DISP_CC_MDSS_DPTX0_LINK_INTF_CLK>, + <&dispcc MDSS_DISP_CC_MDSS_DPTX0_PIXEL0_CLK>, + <&dispcc MDSS_DISP_CC_MDSS_DPTX0_PIXEL1_CLK>, + <&dispcc MDSS_DISP_CC_MDSS_DPTX0_PIXEL2_CLK>, + <&dispcc MDSS_DISP_CC_MDSS_DPTX0_PIXEL3_CLK>; + clock-names = "core_iface", + "core_aux", + "ctrl_link", + "ctrl_link_iface", + "stream_pixel", + "stream_1_pixel", + "stream_2_pixel", + "stream_3_pixel"; + assigned-clocks = <&dispcc MDSS_DISP_CC_MDSS_DPTX0_LINK_CLK_SRC>, + <&dispcc MDSS_DISP_CC_MDSS_DPTX0_PIXEL0_CLK_SRC>, + <&dispcc MDSS_DISP_CC_MDSS_DPTX0_PIXEL1_CLK_SRC>, + <&dispcc MDSS_DISP_CC_MDSS_DPTX0_PIXEL2_CLK_SRC>, + <&dispcc MDSS_DISP_CC_MDSS_DPTX0_PIXEL3_CLK_SRC>; + assigned-clock-parents = <&mdss_dp0_phy 0>, + <&mdss_dp0_phy 1>, + <&mdss_dp0_phy 1>, + <&mdss_dp0_phy 1>, + <&mdss_dp0_phy 1>; + phys = <&mdss_dp0_phy>; + phy-names = "dp"; + + operating-points-v2 = <&dp_opp_table>; + power-domains = <&rpmhpd RPMHPD_MMCX>; + + #sound-dai-cells = <0>; + + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + mdss_dp0_in: endpoint { + remote-endpoint = <&dpu_intf0_out>; + }; + }; + + port@1 { + reg = <1>; + + mdss_dp0_out: endpoint { }; + }; + }; + + dp_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-160000000 { + opp-hz = /bits/ 64 <160000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + + opp-270000000 { + opp-hz = /bits/ 64 <270000000>; + required-opps = <&rpmhpd_opp_svs>; + }; + + opp-540000000 { + opp-hz = /bits/ 64 <540000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-810000000 { + opp-hz = /bits/ 64 <810000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + }; + }; + }; + dispcc: clock-controller@af00000 { compatible = "qcom,sa8775p-dispcc0"; reg = <0x0 0x0af00000 0x0 0x20000>; @@ -4789,7 +5005,9 @@ <&rpmhcc RPMH_CXO_CLK>, <&rpmhcc RPMH_CXO_CLK_A>, <&sleep_clk>, - <0>, <0>, <0>, <0>, + <&mdss_dp0_phy 0>, + <&mdss_dp0_phy 1>, + <0>, <0>, <0>, <0>, <0>, <0>; power-domains = <&rpmhpd RPMHPD_MMCX>; #clock-cells = <1>; From 04e2940af5000f4bf84278b36273cb7e2ed2688d Mon Sep 17 00:00:00 2001 From: Yongxing Mou Date: Wed, 17 Sep 2025 14:09:48 +0800 Subject: [PATCH 0019/2333] FROMLIST: arm64: dts: qcom: qcs8300-ride: Enable Display Port Enable DPTX0 along with their corresponding PHYs for qcs8300-ride platform. Link: https://lore.kernel.org/r/20250917-dts_qcs8300-v6-2-5c862aa80f64@oss.qualcomm.com Reviewed-by: Konrad Dybcio Signed-off-by: Yongxing Mou --- arch/arm64/boot/dts/qcom/qcs8300-ride.dts | 42 +++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/qcs8300-ride.dts b/arch/arm64/boot/dts/qcom/qcs8300-ride.dts index cabb3f508704b..891e49602c970 100644 --- a/arch/arm64/boot/dts/qcom/qcs8300-ride.dts +++ b/arch/arm64/boot/dts/qcom/qcs8300-ride.dts @@ -24,6 +24,18 @@ stdout-path = "serial0:115200n8"; }; + dp0-connector { + compatible = "dp-connector"; + label = "DP0"; + type = "full-size"; + + port { + dp0_connector_in: endpoint { + remote-endpoint = <&mdss_dp0_out>; + }; + }; + }; + regulator-usb2-vbus { compatible = "regulator-fixed"; regulator-name = "USB2_VBUS"; @@ -317,6 +329,30 @@ status = "okay"; }; +&mdss { + status = "okay"; +}; + +&mdss_dp0 { + pinctrl-0 = <&dp_hot_plug_det>; + pinctrl-names = "default"; + + status = "okay"; +}; + +&mdss_dp0_out { + data-lanes = <0 1 2 3>; + link-frequencies = /bits/ 64 <1620000000 2700000000 5400000000 8100000000>; + remote-endpoint = <&dp0_connector_in>; +}; + +&mdss_dp0_phy { + vdda-phy-supply = <&vreg_l5a>; + vdda-pll-supply = <&vreg_l4a>; + + status = "okay"; +}; + &qupv3_id_0 { status = "okay"; }; @@ -377,6 +413,12 @@ bias-pull-up; }; }; + + dp_hot_plug_det: dp-hot-plug-det-state { + pins = "gpio94"; + function = "edp0_hot"; + bias-disable; + }; }; &uart7 { From f5b9ce1286fe0f68230c3c7c0bf029790895bdf8 Mon Sep 17 00:00:00 2001 From: Gaurav Kohli Date: Fri, 22 Aug 2025 09:53:15 +0530 Subject: [PATCH 0020/2333] FROMLIST: dt-bindings: thermal: tsens: Add QCS8300 compatible Add compatibility string for the thermal sensors on QCS8300 platform. Link: https://lore.kernel.org/r/20250822042316.1762153-2-quic_gkohli@quicinc.com Signed-off-by: Gaurav Kohli Acked-by: Rob Herring (Arm) --- Documentation/devicetree/bindings/thermal/qcom-tsens.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml b/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml index 78e2f6573b96f..89a93644e093b 100644 --- a/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml +++ b/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml @@ -56,6 +56,7 @@ properties: - qcom,msm8998-tsens - qcom,qcm2290-tsens - qcom,qcs615-tsens + - qcom,qcs8300-tsens - qcom,sa8255p-tsens - qcom,sa8775p-tsens - qcom,sar2130p-tsens From d43bddf6476be617574f6ead850310257ef76ab5 Mon Sep 17 00:00:00 2001 From: Gaurav Kohli Date: Fri, 22 Aug 2025 09:53:16 +0530 Subject: [PATCH 0021/2333] FROMLIST: arm64: dts: qcom: qcs8300: Enable TSENS support for QCS8300 SoC Add TSENS and thermal devicetree node for QCS8300 SoC. Link: https://lore.kernel.org/r/20250822042316.1762153-3-quic_gkohli@quicinc.com Signed-off-by: Gaurav Kohli --- arch/arm64/boot/dts/qcom/qcs8300.dtsi | 526 ++++++++++++++++++++++++++ 1 file changed, 526 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/qcs8300.dtsi b/arch/arm64/boot/dts/qcom/qcs8300.dtsi index e0e1f63fc45b0..0f5823858fec0 100644 --- a/arch/arm64/boot/dts/qcom/qcs8300.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs8300.dtsi @@ -6429,6 +6429,532 @@ }; }; }; + + tsens2: thermal-sensor@c251000 { + compatible = "qcom,qcs8300-tsens", "qcom,tsens-v2"; + reg = <0x0 0x0c251000 0x0 0x1000>, + <0x0 0x0c224000 0x0 0x1000>; + interrupts = , + ; + interrupt-names = "uplow", "critical"; + #qcom,sensors = <10>; + #thermal-sensor-cells = <1>; + }; + + tsens3: thermal-sensor@c252000 { + compatible = "qcom,qcs8300-tsens", "qcom,tsens-v2"; + reg = <0x0 0x0c252000 0x0 0x1000>, + <0x0 0x0c225000 0x0 0x1000>; + interrupts = , + ; + interrupt-names = "uplow", "critical"; + #qcom,sensors = <10>; + #thermal-sensor-cells = <1>; + }; + + tsens0: thermal-sensor@c263000 { + compatible = "qcom,qcs8300-tsens", "qcom,tsens-v2"; + reg = <0x0 0x0c263000 0x0 0x1000>, + <0x0 0x0c222000 0x0 0x1000>; + interrupts = , + ; + interrupt-names = "uplow", "critical"; + #qcom,sensors = <10>; + #thermal-sensor-cells = <1>; + }; + + tsens1: thermal-sensor@c265000 { + compatible = "qcom,qcs8300-tsens", "qcom,tsens-v2"; + reg = <0x0 0x0c265000 0x0 0x1000>, + <0x0 0x0c223000 0x0 0x1000>; + interrupts = , + ; + interrupt-names = "uplow", "critical"; + #qcom,sensors = <10>; + #thermal-sensor-cells = <1>; + }; + }; + + thermal_zones: thermal-zones { + aoss-0-thermal { + thermal-sensors = <&tsens0 0>; + + trips { + aoss0-critical { + temperature = <125000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + }; + + cpu-0-0-0-thermal { + thermal-sensors = <&tsens0 1>; + + trips { + cpu-critical { + temperature = <125000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + }; + + cpu-0-1-0-thermal { + thermal-sensors = <&tsens0 2>; + + trips { + cpu-critical { + temperature = <125000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + }; + + cpu-0-2-0-thermal { + thermal-sensors = <&tsens0 3>; + + trips { + cpu-critical { + temperature = <125000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + }; + + cpu-0-3-0-thermal { + thermal-sensors = <&tsens0 4>; + + trips { + cpu-critical { + temperature = <125000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + }; + + gpuss-0-thermal { + thermal-sensors = <&tsens0 5>; + + trips { + gpuss0-critical { + temperature = <125000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + }; + + audio-thermal { + thermal-sensors = <&tsens0 6>; + + trips { + audio-critical { + temperature = <125000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + }; + + camss-0-thermal { + thermal-sensors = <&tsens0 7>; + + trips { + camss-critical { + temperature = <125000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + }; + + pcie-0-thermal { + thermal-sensors = <&tsens0 8>; + + trips { + pcie-critical { + temperature = <125000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + }; + + cpuss-0-0-thermal { + thermal-sensors = <&tsens0 9>; + + trips { + cpuss0-critical { + temperature = <125000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + }; + + aoss-1-thermal { + thermal-sensors = <&tsens1 0>; + + trips { + aoss1-critical { + temperature = <125000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + }; + + cpu-0-0-1-thermal { + thermal-sensors = <&tsens1 1>; + + trips { + cpu-critical { + temperature = <125000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + }; + + cpu-0-1-1-thermal { + thermal-sensors = <&tsens1 2>; + + trips { + cpu-critical { + temperature = <125000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + }; + + cpu-0-2-1-thermal { + thermal-sensors = <&tsens1 3>; + + trips { + cpu-critical { + temperature = <125000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + }; + + cpu-0-3-1-thermal { + thermal-sensors = <&tsens1 4>; + + trips { + cpu-critical { + temperature = <125000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + }; + + gpuss-1-thermal { + thermal-sensors = <&tsens1 5>; + + trips { + gpuss1-critical { + temperature = <125000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + }; + + video-thermal { + thermal-sensors = <&tsens1 6>; + + trips { + video-critical { + temperature = <125000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + }; + + camss-1-thermal { + thermal-sensors = <&tsens1 7>; + + trips { + camss1-critical { + temperature = <125000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + }; + + pcie-1-thermal { + thermal-sensors = <&tsens1 8>; + + trips { + pcie-critical { + temperature = <125000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + }; + + cpuss-0-1-thermal { + thermal-sensors = <&tsens1 9>; + + trips { + cpuss0-critical { + temperature = <125000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + }; + + aoss-2-thermal { + thermal-sensors = <&tsens2 0>; + + trips { + aoss2-critical { + temperature = <125000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + }; + + cpu-1-0-0-thermal { + thermal-sensors = <&tsens2 1>; + + trips { + cpu-critical { + temperature = <125000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + }; + + cpu-1-1-0-thermal { + thermal-sensors = <&tsens2 2>; + + trips { + cpu-critical { + temperature = <125000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + }; + + cpu-1-2-0-thermal { + thermal-sensors = <&tsens2 3>; + + trips { + cpu-critical { + temperature = <125000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + }; + + cpu-1-3-0-thermal { + thermal-sensors = <&tsens2 4>; + + trips { + cpu-critical { + temperature = <125000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + }; + + nsp-0-0-0-thermal { + thermal-sensors = <&tsens2 5>; + + trips { + nsp-critical { + temperature = <125000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + }; + + nsp-0-1-0-thermal { + thermal-sensors = <&tsens2 6>; + + trips { + nsp-critical { + temperature = <125000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + }; + + nsp-0-2-0-thermal { + thermal-sensors = <&tsens2 7>; + + trips { + nsp-critical { + temperature = <125000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + }; + + ddrss-0-thermal { + thermal-sensors = <&tsens2 8>; + + trips { + ddrss-critical { + temperature = <125000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + }; + + cpuss-1-0-thermal { + thermal-sensors = <&tsens2 9>; + + trips { + cpuss1-critical { + temperature = <125000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + }; + + aoss-3-thermal { + thermal-sensors = <&tsens3 0>; + + trips { + aoss3-critical { + temperature = <125000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + }; + + cpu-1-0-1-thermal { + thermal-sensors = <&tsens3 1>; + + trips { + cpu-critical { + temperature = <125000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + }; + + cpu-1-1-1-thermal { + thermal-sensors = <&tsens3 2>; + + trips { + cpu-critical { + temperature = <125000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + }; + + cpu-1-2-1-thermal { + thermal-sensors = <&tsens3 3>; + + trips { + cpu-critical { + temperature = <125000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + }; + + cpu-1-3-1-thermal { + thermal-sensors = <&tsens3 4>; + + trips { + cpu-critical { + temperature = <125000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + }; + + nsp-0-0-1-thermal { + thermal-sensors = <&tsens3 5>; + + trips { + nsp-critical { + temperature = <125000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + }; + + nsp-0-1-1-thermal { + thermal-sensors = <&tsens3 6>; + + trips { + nsp-critical { + temperature = <125000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + }; + + nsp-0-2-1-thermal { + thermal-sensors = <&tsens3 7>; + + trips { + nsp-critical { + temperature = <125000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + }; + + ddrss-1-thermal { + thermal-sensors = <&tsens3 8>; + + trips { + ddrss-critical { + temperature = <125000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + }; + + cpuss-1-1-thermal { + thermal-sensors = <&tsens3 9>; + + trips { + cpuss1-critical { + temperature = <125000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + }; }; timer { From 90322921170d2c94c5f1da0a0525d4354c413add Mon Sep 17 00:00:00 2001 From: Gaurav Kohli Date: Wed, 3 Sep 2025 12:49:55 +0530 Subject: [PATCH 0022/2333] FROMLIST: arm64: dts: qcom: qcs8300: Add GPU cooling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Unlike the CPU, the GPU does not throttle its speed automatically when it reaches high temperatures. Set up GPU cooling by throttling the GPU speed when reaching 115°C. Link: https://lore.kernel.org/r/20250903-a623-gpu-support-v5-4-5398585e2981@oss.qualcomm.com Signed-off-by: Gaurav Kohli Signed-off-by: Akhil P Oommen --- arch/arm64/boot/dts/qcom/qcs8300.dtsi | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/qcs8300.dtsi b/arch/arm64/boot/dts/qcom/qcs8300.dtsi index 0f5823858fec0..c31a394b33119 100644 --- a/arch/arm64/boot/dts/qcom/qcs8300.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs8300.dtsi @@ -20,6 +20,7 @@ #include #include #include +#include / { interrupt-parent = <&intc>; @@ -6540,12 +6541,25 @@ thermal-sensors = <&tsens0 5>; trips { + gpuss0_alert0: trip-point0 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + gpuss0-critical { temperature = <125000>; hysteresis = <1000>; type = "critical"; }; }; + + cooling-maps { + map0 { + trip = <&gpuss0_alert0>; + cooling-device = <&gpu THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + }; }; audio-thermal { @@ -6660,12 +6674,25 @@ thermal-sensors = <&tsens1 5>; trips { + gpuss1_alert0: trip-point0 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + gpuss1-critical { temperature = <125000>; hysteresis = <1000>; type = "critical"; }; }; + + cooling-maps { + map0 { + trip = <&gpuss1_alert0>; + cooling-device = <&gpu THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + }; }; video-thermal { From 7b4924c4515a13f700023745b268ed882a78cb79 Mon Sep 17 00:00:00 2001 From: Shivendra Pratap Date: Wed, 15 Oct 2025 10:08:27 +0530 Subject: [PATCH 0023/2333] FROMLIST: arm64: dts: qcom: qcs8300-ride: Add PSCI SYSTEM_RESET2 types Add support for SYSTEM_RESET2 vendor-specific resets in qcs8300-ride as reboot-modes. Describe the resets: "bootloader" will cause device to reboot and stop in the bootloader's fastboot mode. "edl" will cause device to reboot into "emergency download mode", which permits loading images via the Firehose protocol. Link: https://lore.kernel.org/r/20251015-arm-psci-system_reset2-vendor-reboots-v16-12-b98aedaa23ee@oss.qualcomm.com Signed-off-by: Shivendra Pratap --- arch/arm64/boot/dts/qcom/qcs8300-ride.dts | 7 +++++++ arch/arm64/boot/dts/qcom/qcs8300.dtsi | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/qcs8300-ride.dts b/arch/arm64/boot/dts/qcom/qcs8300-ride.dts index 891e49602c970..36c1f5a8526c1 100644 --- a/arch/arm64/boot/dts/qcom/qcs8300-ride.dts +++ b/arch/arm64/boot/dts/qcom/qcs8300-ride.dts @@ -353,6 +353,13 @@ status = "okay"; }; +&psci { + reboot-mode { + mode-bootloader = <0x10001 0x2>; + mode-edl = <0 0x1>; + }; +}; + &qupv3_id_0 { status = "okay"; }; diff --git a/arch/arm64/boot/dts/qcom/qcs8300.dtsi b/arch/arm64/boot/dts/qcom/qcs8300.dtsi index c31a394b33119..078c60a6fb44e 100644 --- a/arch/arm64/boot/dts/qcom/qcs8300.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs8300.dtsi @@ -664,7 +664,7 @@ interrupts = ; }; - psci { + psci: psci { compatible = "arm,psci-1.0"; method = "smc"; From 80742f390cd79a712ce4da02f2112dfe18b94e00 Mon Sep 17 00:00:00 2001 From: Shivendra Pratap Date: Wed, 15 Oct 2025 10:08:28 +0530 Subject: [PATCH 0024/2333] FROMLIST: arm64: dts: qcom: monaco-evk: Add PSCI SYSTEM_RESET2 types Add support for SYSTEM_RESET2 vendor-specific resets in monaco-evk as reboot-modes. Describe the resets: "bootloader" will cause device to reboot and stop in the bootloader's fastboot mode. "edl" will cause device to reboot into "emergency download mode", which permits loading images via the Firehose protocol. Link: https://lore.kernel.org/r/20251015-arm-psci-system_reset2-vendor-reboots-v16-13-b98aedaa23ee@oss.qualcomm.com Signed-off-by: Shivendra Pratap --- arch/arm64/boot/dts/qcom/monaco-evk.dts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/monaco-evk.dts b/arch/arm64/boot/dts/qcom/monaco-evk.dts index e72cf6725a52c..87d613094e551 100644 --- a/arch/arm64/boot/dts/qcom/monaco-evk.dts +++ b/arch/arm64/boot/dts/qcom/monaco-evk.dts @@ -400,6 +400,13 @@ status = "okay"; }; +&psci { + reboot-mode { + mode-bootloader = <0x10001 0x2>; + mode-edl = <0 0x1>; + }; +}; + &qupv3_id_0 { status = "okay"; }; From a50509268f7141d013b5e802730178959d170f6a Mon Sep 17 00:00:00 2001 From: Elliot Berman Date: Wed, 15 Oct 2025 10:08:21 +0530 Subject: [PATCH 0025/2333] FROMLIST: dt-bindings: arm: Document reboot mode magic Add bindings to describe vendor-specific reboot modes. Values here correspond to valid parameters to vendor-specific reset types in PSCI SYSTEM_RESET2 call. Link: https://lore.kernel.org/r/20251015-arm-psci-system_reset2-vendor-reboots-v16-6-b98aedaa23ee@oss.qualcomm.com Reviewed-by: Rob Herring (Arm) Signed-off-by: Elliot Berman Signed-off-by: Shivendra Pratap --- .../devicetree/bindings/arm/psci.yaml | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/Documentation/devicetree/bindings/arm/psci.yaml b/Documentation/devicetree/bindings/arm/psci.yaml index 7360a2849b5bd..eca38f8747d32 100644 --- a/Documentation/devicetree/bindings/arm/psci.yaml +++ b/Documentation/devicetree/bindings/arm/psci.yaml @@ -98,6 +98,27 @@ properties: [1] Kernel documentation - ARM idle states bindings Documentation/devicetree/bindings/cpu/idle-states.yaml + reboot-mode: + type: object + $ref: /schemas/power/reset/reboot-mode.yaml# + unevaluatedProperties: false + properties: + # "mode-normal" is just SYSTEM_RESET + mode-normal: false + patternProperties: + "^mode-.*$": + minItems: 1 + maxItems: 2 + description: | + Describes a vendor-specific reset type. The string after "mode-" + maps a reboot mode to the parameters in the PSCI SYSTEM_RESET2 call. + + Parameters are named mode-xxx = , where xxx + is the name of the magic reboot mode, type is the lower 31 bits + of the reset_type, and, optionally, the cookie value. If the cookie + is not provided, it is defaulted to zero. + The 31st bit (vendor-resets) will be implicitly set by the driver. + patternProperties: "^power-domain-": $ref: /schemas/power/power-domain.yaml# @@ -137,6 +158,15 @@ allOf: required: - cpu_off - cpu_on + - if: + not: + properties: + compatible: + contains: + const: arm,psci-1.0 + then: + properties: + reboot-mode: false additionalProperties: false @@ -261,4 +291,17 @@ examples: domain-idle-states = <&cluster_ret>, <&cluster_pwrdn>; }; }; + + - |+ + + // Case 5: SYSTEM_RESET2 vendor resets + psci { + compatible = "arm,psci-1.0"; + method = "smc"; + + reboot-mode { + mode-edl = <0>; + mode-bootloader = <1 2>; + }; + }; ... From 5c850a982dcd1ce0c2ae03895134f6c01ca8dd45 Mon Sep 17 00:00:00 2001 From: Elliot Berman Date: Wed, 15 Oct 2025 10:08:23 +0530 Subject: [PATCH 0026/2333] FROMLIST: arm64: dts: qcom: qcm6490-idp: Add PSCI SYSTEM_RESET2 types Add support for SYSTEM_RESET2 vendor-specific resets in qcm6490-idp as reboot-modes. Describe the resets: "bootloader" will cause device to reboot and stop in the bootloader's fastboot mode. "edl" will cause device to reboot into "emergency download mode", which permits loading images via the Firehose protocol. Link: https://lore.kernel.org/r/20251015-arm-psci-system_reset2-vendor-reboots-v16-8-b98aedaa23ee@oss.qualcomm.com Reviewed-by: Konrad Dybcio Signed-off-by: Elliot Berman Signed-off-by: Shivendra Pratap --- arch/arm64/boot/dts/qcom/qcm6490-idp.dts | 7 +++++++ arch/arm64/boot/dts/qcom/sc7280.dtsi | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/qcm6490-idp.dts b/arch/arm64/boot/dts/qcom/qcm6490-idp.dts index 73fce639370cd..84322b74917f3 100644 --- a/arch/arm64/boot/dts/qcom/qcm6490-idp.dts +++ b/arch/arm64/boot/dts/qcom/qcm6490-idp.dts @@ -695,6 +695,13 @@ status = "okay"; }; +&psci { + reboot-mode { + mode-bootloader = <0x10001 0x2>; + mode-edl = <0 0x1>; + }; +}; + &qupv3_id_0 { status = "okay"; }; diff --git a/arch/arm64/boot/dts/qcom/sc7280.dtsi b/arch/arm64/boot/dts/qcom/sc7280.dtsi index 4b04dea57ec8c..211c2f223a03c 100644 --- a/arch/arm64/boot/dts/qcom/sc7280.dtsi +++ b/arch/arm64/boot/dts/qcom/sc7280.dtsi @@ -858,7 +858,7 @@ interrupts = ; }; - psci { + psci: psci { compatible = "arm,psci-1.0"; method = "smc"; From b28df75f320f6f0fe306ca5c6a0fec87816f8959 Mon Sep 17 00:00:00 2001 From: Elliot Berman Date: Wed, 15 Oct 2025 10:08:24 +0530 Subject: [PATCH 0027/2333] FROMLIST: arm64: dts: qcom: qcs6490-rb3gen2: Add PSCI SYSTEM_RESET2 types Add support for SYSTEM_RESET2 vendor-specific resets in qcs6490-rb3gen2 as reboot-modes. Describe the resets: "bootloader" will cause device to reboot and stop in the bootloader's fastboot mode. "edl" will cause device to reboot into "emergency download mode", which permits loading images via the Firehose protocol. Link: https://lore.kernel.org/r/20251015-arm-psci-system_reset2-vendor-reboots-v16-9-b98aedaa23ee@oss.qualcomm.com Reviewed-by: Konrad Dybcio Signed-off-by: Elliot Berman Signed-off-by: Shivendra Pratap --- arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts b/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts index 18cea88120014..f38fa2e52a635 100644 --- a/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts +++ b/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts @@ -975,6 +975,13 @@ status = "okay"; }; +&psci { + reboot-mode { + mode-bootloader = <0x10001 0x2>; + mode-edl = <0 0x1>; + }; +}; + &qup_uart7_cts { /* * Configure a bias-bus-hold on CTS to lower power From 90671a19c6c95f4acd18702dde28e82212cfd5d5 Mon Sep 17 00:00:00 2001 From: Krishna Chaitanya Chundru Date: Thu, 28 Aug 2025 17:38:59 +0530 Subject: [PATCH 0028/2333] FROMLIST: arm64: dts: qcom: qcs6490-rb3gen2: Add TC9563 PCIe switch node Add a node for the TC9563 PCIe switch, which has three downstream ports. Two embedded Ethernet devices are present on one of the downstream ports. As all these ports are present in the node represent the downstream ports and embedded endpoints. Power to the TC9563 is supplied through two LDO regulators, controlled by two GPIOs, which are added as fixed regulators. Configure the TC9563 through I2C. Link: https://lore.kernel.org/r/20250828-qps615_v4_1-v6-2-985f90a7dd03@oss.qualcomm.com Signed-off-by: Krishna Chaitanya Chundru Reviewed-by: Bjorn Andersson Acked-by: Manivannan Sadhasivam Reviewed-by: Dmitry Baryshkov --- arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts | 128 +++++++++++++++++++ arch/arm64/boot/dts/qcom/sc7280.dtsi | 2 +- 2 files changed, 129 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts b/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts index f38fa2e52a635..b368ceb75cf90 100644 --- a/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts +++ b/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts @@ -262,6 +262,30 @@ regulator-max-microvolt = <3700000>; }; + vdd_ntn_0p9: regulator-vdd-ntn-0p9 { + compatible = "regulator-fixed"; + regulator-name = "VDD_NTN_0P9"; + gpio = <&pm8350c_gpios 2 GPIO_ACTIVE_HIGH>; + regulator-min-microvolt = <899400>; + regulator-max-microvolt = <899400>; + enable-active-high; + pinctrl-0 = <&ntn_0p9_en>; + pinctrl-names = "default"; + regulator-enable-ramp-delay = <4300>; + }; + + vdd_ntn_1p8: regulator-vdd-ntn-1p8 { + compatible = "regulator-fixed"; + regulator-name = "VDD_NTN_1P8"; + gpio = <&pm8350c_gpios 3 GPIO_ACTIVE_HIGH>; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + enable-active-high; + pinctrl-0 = <&ntn_1p8_en>; + pinctrl-names = "default"; + regulator-enable-ramp-delay = <10000>; + }; + wcn6750-pmu { compatible = "qcom,wcn6750-pmu"; pinctrl-0 = <&bt_en>; @@ -843,6 +867,78 @@ status = "okay"; }; +&pcie1_port0 { + pcie@0,0 { + compatible = "pci1179,0623"; + reg = <0x10000 0x0 0x0 0x0 0x0>; + #address-cells = <3>; + #size-cells = <2>; + + device_type = "pci"; + ranges; + bus-range = <0x2 0xff>; + + vddc-supply = <&vdd_ntn_0p9>; + vdd18-supply = <&vdd_ntn_1p8>; + vdd09-supply = <&vdd_ntn_0p9>; + vddio1-supply = <&vdd_ntn_1p8>; + vddio2-supply = <&vdd_ntn_1p8>; + vddio18-supply = <&vdd_ntn_1p8>; + + i2c-parent = <&i2c0 0x77>; + + reset-gpios = <&pm8350c_gpios 1 GPIO_ACTIVE_LOW>; + + pinctrl-0 = <&tc9563_rsex_n>; + pinctrl-names = "default"; + + pcie@1,0 { + reg = <0x20800 0x0 0x0 0x0 0x0>; + #address-cells = <3>; + #size-cells = <2>; + + device_type = "pci"; + ranges; + bus-range = <0x3 0xff>; + }; + + pcie@2,0 { + reg = <0x21000 0x0 0x0 0x0 0x0>; + #address-cells = <3>; + #size-cells = <2>; + + device_type = "pci"; + ranges; + bus-range = <0x4 0xff>; + }; + + pcie@3,0 { + reg = <0x21800 0x0 0x0 0x0 0x0>; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + ranges; + bus-range = <0x5 0xff>; + + pci@0,0 { + reg = <0x50000 0x0 0x0 0x0 0x0>; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + ranges; + }; + + pci@0,1 { + reg = <0x50100 0x0 0x0 0x0 0x0>; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + ranges; + }; + }; + }; +}; + &pm7325_gpios { kypd_vol_up_n: kypd-vol-up-n-state { pins = "gpio6"; @@ -853,6 +949,38 @@ }; }; +&pm8350c_gpios { + ntn_0p9_en: ntn-0p9-en-state { + pins = "gpio2"; + function = "normal"; + + bias-disable; + input-disable; + output-enable; + power-source = <0>; + }; + + ntn_1p8_en: ntn-1p8-en-state { + pins = "gpio3"; + function = "normal"; + + bias-disable; + input-disable; + output-enable; + power-source = <0>; + }; + + tc9563_rsex_n: tc9563-resx-state { + pins = "gpio1"; + function = "normal"; + + bias-disable; + input-disable; + output-enable; + power-source = <0>; + }; +}; + &pm7325_temp_alarm { io-channels = <&pmk8350_vadc PM7325_ADC7_DIE_TEMP>; io-channel-names = "thermal"; diff --git a/arch/arm64/boot/dts/qcom/sc7280.dtsi b/arch/arm64/boot/dts/qcom/sc7280.dtsi index 211c2f223a03c..4bb3981bf6ea1 100644 --- a/arch/arm64/boot/dts/qcom/sc7280.dtsi +++ b/arch/arm64/boot/dts/qcom/sc7280.dtsi @@ -2424,7 +2424,7 @@ status = "disabled"; - pcie@0 { + pcie1_port0: pcie@0 { device_type = "pci"; reg = <0x0 0x0 0x0 0x0 0x0>; bus-range = <0x01 0xff>; From c26b0ea4cb7b25554d943449bb45a0d1c6bf7ac5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Tue, 14 Oct 2025 19:36:02 +0300 Subject: [PATCH 0029/2333] FROMLIST: PCI: Revert early bridge resource set up MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The commit a43ac325c7cb ("PCI: Set up bridge resources earlier") moved bridge window resources set up earlier than before. The change was necessary to support another change that got pulled on the last minute due to breaking s390 and other systems. The presence of valid bridge window resources earlier than before allows pci_assign_unassigned_root_bus_resources() call from pci_host_probe() assign the bridge windows. Some host bridges, however, have to wait first for the link up event before they can enumerate successfully (see e.g. qcom_pcie_global_irq_thread()) and thus the bus has not been enumerated yet while calling pci_host_probe(). Calling pci_assign_unassigned_root_bus_resources() without results from enumeration can result in sizing bridge windows with too small sizes which cannot be later corrected after the enumeration has completed because bridge windows have become pinned in place by the other resources. Interestingly, it seems pci_read_bridge_bases() is not called at all in the problematic case and the bridge window resource type setup is done by pci_bridge_check_ranges() and sizing by the usual resource fitting logic. The root problem behind all this looks pretty generic. If resource fitting is called too early, the hotplug reservation and old size lower bounding cause the bridge windows to be assigned without children but with non-zero size, which leads to these pinning problems. As such, this can likely be solved on the general level but the solution does not look trivial. As the commit a43ac325c7cb ("PCI: Set up bridge resources earlier") was prequisite for other change that did not end up into kernel yet, revert it to resolve the resource assignment failures and give time to code and test a generic solution. Reported-by: Val Packett Reported-by: Guenter Roeck Fixes: a43ac325c7cb ("PCI: Set up bridge resources earlier") Signed-off-by: Ilpo Järvinen Link: https://patch.msgid.link/20251014163602.17138-1-ilpo.jarvinen@linux.intel.com --- drivers/pci/probe.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index c83e75a0ec126..0ce98e18b5a87 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -538,14 +538,10 @@ static void pci_read_bridge_windows(struct pci_dev *bridge) } if (io) { bridge->io_window = 1; - pci_read_bridge_io(bridge, - pci_resource_n(bridge, PCI_BRIDGE_IO_WINDOW), - true); + pci_read_bridge_io(bridge, &res, true); } - pci_read_bridge_mmio(bridge, - pci_resource_n(bridge, PCI_BRIDGE_MEM_WINDOW), - true); + pci_read_bridge_mmio(bridge, &res, true); /* * DECchip 21050 pass 2 errata: the bridge may miss an address @@ -583,10 +579,7 @@ static void pci_read_bridge_windows(struct pci_dev *bridge) bridge->pref_64_window = 1; } - pci_read_bridge_mmio_pref(bridge, - pci_resource_n(bridge, - PCI_BRIDGE_PREF_MEM_WINDOW), - true); + pci_read_bridge_mmio_pref(bridge, &res, true); } void pci_read_bridge_bases(struct pci_bus *child) From c98806448225f1fc6d5a46bb8aa6d141e705adc2 Mon Sep 17 00:00:00 2001 From: Vikram Sharma Date: Wed, 15 Oct 2025 18:31:30 +0530 Subject: [PATCH 0030/2333] FROMLIST: arm64: dts: qcom: qcs8300: Add support for camss Add changes to support the camera subsystem on the QCS8300. Reviewed-by: Konrad Dybcio Reviewed-by: Bryan O'Donoghue Signed-off-by: Vikram Sharma Link: https://lore.kernel.org/all/20251015130130.2790829-1-quic_vikramsa@quicinc.com --- arch/arm64/boot/dts/qcom/qcs8300.dtsi | 171 ++++++++++++++++++++++++++ 1 file changed, 171 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/qcs8300.dtsi b/arch/arm64/boot/dts/qcom/qcs8300.dtsi index 078c60a6fb44e..e19c71b80dd2e 100644 --- a/arch/arm64/boot/dts/qcom/qcs8300.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs8300.dtsi @@ -4770,6 +4770,177 @@ #power-domain-cells = <1>; }; + camss: isp@ac78000 { + compatible = "qcom,qcs8300-camss"; + + reg = <0x0 0xac78000 0x0 0x1000>, + <0x0 0xac7a000 0x0 0xf00>, + <0x0 0xac7c000 0x0 0xf00>, + <0x0 0xac84000 0x0 0xf00>, + <0x0 0xac88000 0x0 0xf00>, + <0x0 0xac8c000 0x0 0xf00>, + <0x0 0xac90000 0x0 0xf00>, + <0x0 0xac94000 0x0 0xf00>, + <0x0 0xac9c000 0x0 0x2000>, + <0x0 0xac9e000 0x0 0x2000>, + <0x0 0xaca0000 0x0 0x2000>, + <0x0 0xacac000 0x0 0x400>, + <0x0 0xacad000 0x0 0x400>, + <0x0 0xacae000 0x0 0x400>, + <0x0 0xac4d000 0x0 0xf000>, + <0x0 0xac60000 0x0 0xf000>, + <0x0 0xac85000 0x0 0xd00>, + <0x0 0xac89000 0x0 0xd00>, + <0x0 0xac8d000 0x0 0xd00>, + <0x0 0xac91000 0x0 0xd00>, + <0x0 0xac95000 0x0 0xd00>; + reg-names = "csid_wrapper", + "csid0", + "csid1", + "csid_lite0", + "csid_lite1", + "csid_lite2", + "csid_lite3", + "csid_lite4", + "csiphy0", + "csiphy1", + "csiphy2", + "tpg0", + "tpg1", + "tpg2", + "vfe0", + "vfe1", + "vfe_lite0", + "vfe_lite1", + "vfe_lite2", + "vfe_lite3", + "vfe_lite4"; + + clocks = <&camcc CAM_CC_CAMNOC_AXI_CLK>, + <&camcc CAM_CC_CORE_AHB_CLK>, + <&camcc CAM_CC_CPAS_AHB_CLK>, + <&camcc CAM_CC_CPAS_FAST_AHB_CLK>, + <&camcc CAM_CC_CPAS_IFE_LITE_CLK>, + <&camcc CAM_CC_CPAS_IFE_0_CLK>, + <&camcc CAM_CC_CPAS_IFE_1_CLK>, + <&camcc CAM_CC_CSID_CLK>, + <&camcc CAM_CC_CSIPHY0_CLK>, + <&camcc CAM_CC_CSI0PHYTIMER_CLK>, + <&camcc CAM_CC_CSIPHY1_CLK>, + <&camcc CAM_CC_CSI1PHYTIMER_CLK>, + <&camcc CAM_CC_CSIPHY2_CLK>, + <&camcc CAM_CC_CSI2PHYTIMER_CLK>, + <&camcc CAM_CC_CSID_CSIPHY_RX_CLK>, + <&gcc GCC_CAMERA_HF_AXI_CLK>, + <&gcc GCC_CAMERA_SF_AXI_CLK>, + <&camcc CAM_CC_ICP_AHB_CLK>, + <&camcc CAM_CC_IFE_0_CLK>, + <&camcc CAM_CC_IFE_0_FAST_AHB_CLK>, + <&camcc CAM_CC_IFE_1_CLK>, + <&camcc CAM_CC_IFE_1_FAST_AHB_CLK>, + <&camcc CAM_CC_IFE_LITE_CLK>, + <&camcc CAM_CC_IFE_LITE_AHB_CLK>, + <&camcc CAM_CC_IFE_LITE_CPHY_RX_CLK>, + <&camcc CAM_CC_IFE_LITE_CSID_CLK>; + clock-names = "camnoc_axi", + "core_ahb", + "cpas_ahb", + "cpas_fast_ahb_clk", + "cpas_vfe_lite", + "cpas_vfe0", + "cpas_vfe1", + "csid", + "csiphy0", + "csiphy0_timer", + "csiphy1", + "csiphy1_timer", + "csiphy2", + "csiphy2_timer", + "csiphy_rx", + "gcc_axi_hf", + "gcc_axi_sf", + "icp_ahb", + "vfe0", + "vfe0_fast_ahb", + "vfe1", + "vfe1_fast_ahb", + "vfe_lite", + "vfe_lite_ahb", + "vfe_lite_cphy_rx", + "vfe_lite_csid"; + + interrupts = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + interrupt-names = "csid0", + "csid1", + "csid_lite0", + "csid_lite1", + "csid_lite2", + "csid_lite3", + "csid_lite4", + "csiphy0", + "csiphy1", + "csiphy2", + "tpg0", + "tpg1", + "tpg2", + "vfe0", + "vfe1", + "vfe_lite0", + "vfe_lite1", + "vfe_lite2", + "vfe_lite3", + "vfe_lite4"; + + interconnects = <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ACTIVE_ONLY + &config_noc SLAVE_CAMERA_CFG QCOM_ICC_TAG_ACTIVE_ONLY>, + <&mmss_noc MASTER_CAMNOC_HF QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "ahb", + "hf_0"; + + iommus = <&apps_smmu 0x2400 0x20>; + + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + power-domain-names = "top"; + + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + }; + + port@1 { + reg = <1>; + }; + + port@2 { + reg = <2>; + }; + }; + }; + camcc: clock-controller@ade0000 { compatible = "qcom,qcs8300-camcc"; reg = <0x0 0x0ade0000 0x0 0x20000>; From b4e2704e759c5661b178eee32e106a4062c8eb2f Mon Sep 17 00:00:00 2001 From: Nihal Kumar Gupta Date: Wed, 15 Oct 2025 18:43:02 +0530 Subject: [PATCH 0031/2333] FROMLIST: arm64: dts: qcom: qcs8300: Add CCI definitions Qualcomm QCS8300 SoC contains 3 Camera Control Interface (CCI). Compared to lemans, the key difference is in SDA/SCL GPIO assignments and number of CCIs. Co-developed-by: Ravi Shankar Signed-off-by: Ravi Shankar Co-developed-by: Vishal Verma Signed-off-by: Vishal Verma Co-developed-by: Suresh Vankadara Signed-off-by: Suresh Vankadara Signed-off-by: Nihal Kumar Gupta Signed-off-by: Vikram Sharma Reviewed-by: Vladimir Zapolskiy Reviewed-by: Bryan O'Donoghue Link: https://lore.kernel.org/all/20251015131303.2797800-1-quic_vikramsa@quicinc.com --- arch/arm64/boot/dts/qcom/qcs8300.dtsi | 303 ++++++++++++++++++++++++++ 1 file changed, 303 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/qcs8300.dtsi b/arch/arm64/boot/dts/qcom/qcs8300.dtsi index e19c71b80dd2e..9f8e87e028c39 100644 --- a/arch/arm64/boot/dts/qcom/qcs8300.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs8300.dtsi @@ -4770,6 +4770,117 @@ #power-domain-cells = <1>; }; + cci0: cci@ac13000 { + compatible = "qcom,qcs8300-cci", "qcom,msm8996-cci"; + reg = <0x0 0x0ac13000 0x0 0x1000>; + + interrupts = ; + + clocks = <&camcc CAM_CC_CPAS_AHB_CLK>, + <&camcc CAM_CC_CCI_0_CLK>; + clock-names = "cpas_ahb", + "cci"; + + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + + pinctrl-0 = <&cci0_i2c0_default &cci0_i2c1_default>; + pinctrl-1 = <&cci0_i2c0_sleep &cci0_i2c1_sleep>; + pinctrl-names = "default", "sleep"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + + cci0_i2c0: i2c-bus@0 { + reg = <0>; + clock-frequency = <1000000>; + #address-cells = <1>; + #size-cells = <0>; + }; + + cci0_i2c1: i2c-bus@1 { + reg = <1>; + clock-frequency = <1000000>; + #address-cells = <1>; + #size-cells = <0>; + }; + }; + + cci1: cci@ac14000 { + compatible = "qcom,qcs8300-cci", "qcom,msm8996-cci"; + reg = <0x0 0x0ac14000 0x0 0x1000>; + + interrupts = ; + + clocks = <&camcc CAM_CC_CPAS_AHB_CLK>, + <&camcc CAM_CC_CCI_1_CLK>; + clock-names = "cpas_ahb", + "cci"; + + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + + pinctrl-0 = <&cci1_i2c0_default &cci1_i2c1_default>; + pinctrl-1 = <&cci1_i2c0_sleep &cci1_i2c1_sleep>; + pinctrl-names = "default", "sleep"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + + cci1_i2c0: i2c-bus@0 { + reg = <0>; + clock-frequency = <1000000>; + #address-cells = <1>; + #size-cells = <0>; + }; + + cci1_i2c1: i2c-bus@1 { + reg = <1>; + clock-frequency = <1000000>; + #address-cells = <1>; + #size-cells = <0>; + }; + }; + + cci2: cci@ac15000 { + compatible = "qcom,qcs8300-cci", "qcom,msm8996-cci"; + reg = <0x0 0x0ac15000 0x0 0x1000>; + + interrupts = ; + + clocks = <&camcc CAM_CC_CPAS_AHB_CLK>, + <&camcc CAM_CC_CCI_2_CLK>; + clock-names = "cpas_ahb", + "cci"; + + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + + pinctrl-0 = <&cci2_i2c0_default &cci2_i2c1_default>; + pinctrl-1 = <&cci2_i2c0_sleep &cci2_i2c1_sleep>; + pinctrl-names = "default", "sleep"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + + cci2_i2c0: i2c-bus@0 { + reg = <0>; + clock-frequency = <1000000>; + #address-cells = <1>; + #size-cells = <0>; + }; + + cci2_i2c1: i2c-bus@1 { + reg = <1>; + clock-frequency = <1000000>; + #address-cells = <1>; + #size-cells = <0>; + }; + }; + camss: isp@ac78000 { compatible = "qcom,qcs8300-camss"; @@ -5282,6 +5393,198 @@ #interrupt-cells = <2>; wakeup-parent = <&pdc>; + cci0_i2c0_default: cci0-0-default-state { + sda-pins { + pins = "gpio57"; + function = "cci_i2c_sda"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + + scl-pins { + pins = "gpio58"; + function = "cci_i2c_scl"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + }; + + cci0_i2c0_sleep: cci0-0-sleep-state { + sda-pins { + pins = "gpio57"; + function = "cci_i2c_sda"; + drive-strength = <2>; + bias-pull-down; + }; + + scl-pins { + pins = "gpio58"; + function = "cci_i2c_scl"; + drive-strength = <2>; + bias-pull-down; + }; + }; + + cci0_i2c1_default: cci0-1-default-state { + sda-pins { + pins = "gpio29"; + function = "cci_i2c_sda"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + + scl-pins { + pins = "gpio30"; + function = "cci_i2c_scl"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + }; + + cci0_i2c1_sleep: cci0-1-sleep-state { + sda-pins { + pins = "gpio29"; + function = "cci_i2c_sda"; + drive-strength = <2>; + bias-pull-down; + }; + + scl-pins { + pins = "gpio30"; + function = "cci_i2c_scl"; + drive-strength = <2>; + bias-pull-down; + }; + }; + + cci1_i2c0_default: cci1-0-default-state { + sda-pins { + pins = "gpio59"; + function = "cci_i2c_sda"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + + scl-pins { + pins = "gpio60"; + function = "cci_i2c_scl"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + }; + + cci1_i2c0_sleep: cci1-0-sleep-state { + sda-pins { + pins = "gpio59"; + function = "cci_i2c_sda"; + drive-strength = <2>; + bias-pull-down; + }; + + scl-pins { + pins = "gpio60"; + function = "cci_i2c_scl"; + drive-strength = <2>; + bias-pull-down; + }; + }; + + cci1_i2c1_default: cci1-1-default-state { + sda-pins { + pins = "gpio31"; + function = "cci_i2c_sda"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + + scl-pins { + pins = "gpio32"; + function = "cci_i2c_scl"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + }; + + cci1_i2c1_sleep: cci1-1-sleep-state { + sda-pins { + pins = "gpio31"; + function = "cci_i2c_sda"; + drive-strength = <2>; + bias-pull-down; + }; + + scl-pins { + pins = "gpio32"; + function = "cci_i2c_scl"; + drive-strength = <2>; + bias-pull-down; + }; + }; + + cci2_i2c0_default: cci2-0-default-state { + sda-pins { + pins = "gpio61"; + function = "cci_i2c_sda"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + + scl-pins { + pins = "gpio62"; + function = "cci_i2c_scl"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + }; + + cci2_i2c0_sleep: cci2-0-sleep-state { + sda-pins { + pins = "gpio61"; + function = "cci_i2c_sda"; + drive-strength = <2>; + bias-pull-down; + }; + + scl-pins { + pins = "gpio62"; + function = "cci_i2c_scl"; + drive-strength = <2>; + bias-pull-down; + }; + }; + + cci2_i2c1_default: cci2-1-default-state { + sda-pins { + pins = "gpio54"; + function = "cci_i2c_sda"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + + scl-pins { + pins = "gpio55"; + function = "cci_i2c_scl"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + }; + + cci2_i2c1_sleep: cci2-1-sleep-state { + sda-pins { + pins = "gpio54"; + function = "cci_i2c_sda"; + drive-strength = <2>; + bias-pull-down; + }; + + scl-pins { + pins = "gpio55"; + function = "cci_i2c_scl"; + drive-strength = <2>; + bias-pull-down; + }; + }; + hs0_mi2s_active: hs0-mi2s-active-state { pins = "gpio106", "gpio107", "gpio108", "gpio109"; function = "hs0_mi2s"; From 1b489cae41db2c9d9660ca43bddab462d3b92440 Mon Sep 17 00:00:00 2001 From: Nihal Kumar Gupta Date: Wed, 15 Oct 2025 18:43:03 +0530 Subject: [PATCH 0032/2333] FROMLIST: arm64: dts: qcom: monaco-evk-camera: Add DT overlay Monaco EVK board does not include a camera sensor in its default hardware configuration. Introducing a device tree overlay to support optional integration of the IMX577 sensor via CSIPHY1. Camera reset is handled through an I2C expander, and power is enabled via TLMM GPIO74. An example media-ctl pipeline for the imx577 is: media-ctl --reset media-ctl -V '"imx577 3-001a":0[fmt:SRGGB10/4056x3040 field:none]' media-ctl -V '"msm_csiphy1":0[fmt:SRGGB10/4056x3040]' media-ctl -V '"msm_csid0":0[fmt:SRGGB10/4056x3040]' media-ctl -V '"msm_vfe0_rdi0":0[fmt:SRGGB10/4056x3040]' media-ctl -l '"msm_csiphy1":1->"msm_csid0":0[1]' media-ctl -l '"msm_csid0":1->"msm_vfe0_rdi0":0[1]' yavta -B capture-mplane -c -I -n 5 -f SRGGB10P -s 4056x3040 -F /dev/video1 Co-developed-by: Ravi Shankar Signed-off-by: Ravi Shankar Co-developed-by: Vishal Verma Signed-off-by: Vishal Verma Signed-off-by: Nihal Kumar Gupta Signed-off-by: Vikram Sharma Reviewed-by: Vladimir Zapolskiy Link: https://lore.kernel.org/all/20251015131303.2797800-1-quic_vikramsa@quicinc.com --- arch/arm64/boot/dts/qcom/Makefile | 4 + .../dts/qcom/monaco-evk-camera-imx577.dtso | 96 +++++++++++++++++++ 2 files changed, 100 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/monaco-evk-camera-imx577.dtso diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile index 296688f7cb265..4df3044639a45 100644 --- a/arch/arm64/boot/dts/qcom/Makefile +++ b/arch/arm64/boot/dts/qcom/Makefile @@ -36,6 +36,10 @@ lemans-evk-camera-csi1-imx577-dtbs := lemans-evk.dtb lemans-evk-camera-csi1-imx5 dtb-$(CONFIG_ARCH_QCOM) += lemans-evk-camera-csi1-imx577.dtb dtb-$(CONFIG_ARCH_QCOM) += monaco-evk.dtb + +monaco-evk-camera-imx577-dtbs := monaco-evk.dtb monaco-evk-camera-imx577.dtbo +dtb-$(CONFIG_ARCH_QCOM) += monaco-evk-camera-imx577.dtb + dtb-$(CONFIG_ARCH_QCOM) += msm8216-samsung-fortuna3g.dtb dtb-$(CONFIG_ARCH_QCOM) += msm8916-acer-a1-724.dtb dtb-$(CONFIG_ARCH_QCOM) += msm8916-alcatel-idol347.dtb diff --git a/arch/arm64/boot/dts/qcom/monaco-evk-camera-imx577.dtso b/arch/arm64/boot/dts/qcom/monaco-evk-camera-imx577.dtso new file mode 100644 index 0000000000000..2237f0fc4a141 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/monaco-evk-camera-imx577.dtso @@ -0,0 +1,96 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +/dts-v1/; +/plugin/; + +#include +#include + +&{/} { + vreg_cam1_2p8: vreg-cam1-2p8 { + compatible = "regulator-fixed"; + regulator-name = "vreg_cam1_2p8"; + startup-delay-us = <10000>; + enable-active-high; + gpio = <&tlmm 74 GPIO_ACTIVE_HIGH>; + }; +}; + +&camss { + vdda-phy-supply = <&vreg_l4a>; + vdda-pll-supply = <&vreg_l5a>; + + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@1 { + reg = <1>; + + csiphy1_ep: endpoint { + clock-lanes = <7>; + data-lanes = <0 1 2 3>; + remote-endpoint = <&imx577_ep1>; + }; + }; + }; +}; + +&cci1 { + pinctrl-0 = <&cci1_i2c0_default>; + pinctrl-1 = <&cci1_i2c0_sleep>; + + status = "okay"; +}; + +&cci1_i2c0 { + #address-cells = <1>; + #size-cells = <0>; + + camera@1a { + compatible = "sony,imx577"; + reg = <0x1a>; + + reset-gpios = <&expander2 1 GPIO_ACTIVE_LOW>; + pinctrl-0 = <&cam1_default>; + pinctrl-names = "default"; + + clocks = <&camcc CAM_CC_MCLK1_CLK>; + assigned-clocks = <&camcc CAM_CC_MCLK1_CLK>; + assigned-clock-rates = <24000000>; + + avdd-supply = <&vreg_cam1_2p8>; + + port { + imx577_ep1: endpoint { + clock-lanes = <7>; + link-frequencies = /bits/ 64 <600000000>; + data-lanes = <0 1 2 3>; + remote-endpoint = <&csiphy1_ep>; + }; + }; + }; +}; + +&tlmm { + cam1_default: cam1-default-state { + mclk-pins { + pins = "gpio68"; + function = "cam_mclk"; + drive-strength = <2>; + bias-disable; + }; + + ldo-avdd-pins { + pins = "gpio74"; + function = "gpio"; + drive-strength = <2>; + bias-disable; + }; + }; +}; From e04c6109138276f70fa575ea98511011deeca423 Mon Sep 17 00:00:00 2001 From: Vikram Sharma Date: Wed, 15 Oct 2025 18:31:29 +0530 Subject: [PATCH 0033/2333] FROMLIST: dt-bindings: media: qcom,qcs8300-camss: Add missing power supplies Add support for vdda-phy-supply and vdda-pll-supply in the QCS8300 CAMSS binding to reflect camera sensor hardware requirements. Co-developed-by: Nihal Kumar Gupta Signed-off-by: Nihal Kumar Gupta Signed-off-by: Vikram Sharma Link: https://lore.kernel.org/all/20251015130130.2790829-1-quic_vikramsa@quicinc.com --- .../bindings/media/qcom,qcs8300-camss.yaml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Documentation/devicetree/bindings/media/qcom,qcs8300-camss.yaml b/Documentation/devicetree/bindings/media/qcom,qcs8300-camss.yaml index 80a4540a22dc2..dce0a1fcb10c6 100644 --- a/Documentation/devicetree/bindings/media/qcom,qcs8300-camss.yaml +++ b/Documentation/devicetree/bindings/media/qcom,qcs8300-camss.yaml @@ -120,6 +120,14 @@ properties: items: - const: top + vdda-phy-supply: + description: + Phandle to a regulator supply to PHY core block. + + vdda-pll-supply: + description: + Phandle to 1.8V regulator supply to PHY refclk pll block. + ports: $ref: /schemas/graph.yaml#/properties/ports @@ -160,6 +168,8 @@ required: - power-domains - power-domain-names - ports + - vdda-phy-supply + - vdda-pll-supply additionalProperties: false @@ -328,6 +338,9 @@ examples: power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; power-domain-names = "top"; + vdda-phy-supply = <&vreg_l4a_0p88>; + vdda-pll-supply = <&vreg_l1c_1p2>; + ports { #address-cells = <1>; #size-cells = <0>; From aefdaf1da39e9d68b4e448f08efe09ba1a4b3289 Mon Sep 17 00:00:00 2001 From: Nihal Kumar Gupta Date: Wed, 15 Oct 2025 18:43:01 +0530 Subject: [PATCH 0034/2333] FROMLIST: dt-bindings: i2c: qcom-cci: Document qcs8300 compatible The three instances of CCI found on the QCS8300 are functionally the same as on a number of existing Qualcomm SoCs. Introduce a new SoC-specific compatible string "qcom,qcs8300-cci" with a common fallback. Signed-off-by: Nihal Kumar Gupta Signed-off-by: Vikram Sharma Reviewed-by: Bryan O'Donoghue Acked-by: Rob Herring (Arm) Reviewed-by: Vladimir Zapolskiy Link: https://lore.kernel.org/all/20251015131303.2797800-1-quic_vikramsa@quicinc.com --- Documentation/devicetree/bindings/i2c/qcom,i2c-cci.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/i2c/qcom,i2c-cci.yaml b/Documentation/devicetree/bindings/i2c/qcom,i2c-cci.yaml index 9bc99d736343f..ef6af05f7585b 100644 --- a/Documentation/devicetree/bindings/i2c/qcom,i2c-cci.yaml +++ b/Documentation/devicetree/bindings/i2c/qcom,i2c-cci.yaml @@ -26,6 +26,7 @@ properties: - items: - enum: - qcom,qcm2290-cci + - qcom,qcs8300-cci - qcom,sa8775p-cci - qcom,sc7280-cci - qcom,sc8280xp-cci @@ -129,6 +130,7 @@ allOf: contains: enum: - qcom,qcm2290-cci + - qcom,qcs8300-cci then: properties: clocks: From 64e22f081596fba52c3d25e94298ef2a6c25c6a5 Mon Sep 17 00:00:00 2001 From: Ritesh Kumar Date: Fri, 10 Oct 2025 17:01:21 +0530 Subject: [PATCH 0035/2333] FROMLIST: arm64: dts: qcom: lemans: Add edp reference clock for edp phy Add edp reference clock for edp phy on lemans chipset. Link:https://lore.kernel.org/all/20251013104806.6599-4-quic_riteshk@quicinc.com/ Signed-off-by: Ritesh Kumar --- arch/arm64/boot/dts/qcom/lemans.dtsi | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/lemans.dtsi b/arch/arm64/boot/dts/qcom/lemans.dtsi index 0873830a39aa2..8b77e2a5ef01f 100644 --- a/arch/arm64/boot/dts/qcom/lemans.dtsi +++ b/arch/arm64/boot/dts/qcom/lemans.dtsi @@ -5154,9 +5154,11 @@ <0x0 0x0aec2000 0x0 0x1c8>; clocks = <&dispcc0 MDSS_DISP_CC_MDSS_DPTX0_AUX_CLK>, - <&dispcc0 MDSS_DISP_CC_MDSS_AHB_CLK>; + <&dispcc0 MDSS_DISP_CC_MDSS_AHB_CLK>, + <&gcc GCC_EDP_REF_CLKREF_EN>; clock-names = "aux", - "cfg_ahb"; + "cfg_ahb", + "ref"; #clock-cells = <1>; #phy-cells = <0>; @@ -5173,9 +5175,11 @@ <0x0 0x0aec5000 0x0 0x1c8>; clocks = <&dispcc0 MDSS_DISP_CC_MDSS_DPTX1_AUX_CLK>, - <&dispcc0 MDSS_DISP_CC_MDSS_AHB_CLK>; + <&dispcc0 MDSS_DISP_CC_MDSS_AHB_CLK>, + <&gcc GCC_EDP_REF_CLKREF_EN>; clock-names = "aux", - "cfg_ahb"; + "cfg_ahb", + "ref"; #clock-cells = <1>; #phy-cells = <0>; From 0920c03e1cd9216cd256234adf845c0b71811630 Mon Sep 17 00:00:00 2001 From: Viken Dadhaniya Date: Tue, 23 Sep 2025 21:41:07 +0530 Subject: [PATCH 0036/2333] FROMLIST: arm64: dts: qcom: qcs6490-rb3gen2: Add firmware-name to QUPv3 nodes Traditionally, firmware loading for Serial Engines (SE) in the QUP hardware of Qualcomm SoCs has been managed by TrustZone (TZ). While this approach ensures secure SE assignment and access control, it limits flexibility for developers who need to enable various protocols on different SEs. Add the firmware-name property to QUPv3 nodes in the device tree to enable firmware loading from the Linux environment. Handle SE assignments and access control permissions directly within Linux, removing the dependency on TrustZone. Link: https://lore.kernel.org/all/20250923161107.3541698-1-viken.dadhaniya@oss.qualcomm.com/ Signed-off-by: Viken Dadhaniya Reviewed-by: Dmitry Baryshkov --- arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts b/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts index b368ceb75cf90..c146161e4bb41 100644 --- a/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts +++ b/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts @@ -1144,10 +1144,12 @@ }; &qupv3_id_0 { + firmware-name = "qcom/qcs6490/qupv3fw.elf"; status = "okay"; }; &qupv3_id_1 { + firmware-name = "qcom/qcs6490/qupv3fw.elf"; status = "okay"; }; From 7cd17f093a050dcb686600f1fbcb3dd5aba9df00 Mon Sep 17 00:00:00 2001 From: Viken Dadhaniya Date: Wed, 24 Sep 2025 09:24:09 +0530 Subject: [PATCH 0037/2333] FROMLIST: arm64: dts: qcom: lemans-evk: Add firmware-name to QUPv3 nodes Traditionally, firmware loading for Serial Engines (SE) in the QUP hardware of Qualcomm SoCs has been managed by TrustZone (TZ). While this approach ensures secure SE assignment and access control, it limits flexibility for developers who need to enable various protocols on different SEs. Add the firmware-name property to QUPv3 nodes in the device tree to enable firmware loading from the Linux environment. Handle SE assignments and access control permissions directly within Linux, removing the dependency on TrustZone. Link: https://lore.kernel.org/all/20250924035409.3976652-1-viken.dadhaniya@oss.qualcomm.com/ Signed-off-by: Viken Dadhaniya Reviewed-by: Dmitry Baryshkov Acked-by: Mukesh Kumar Savaliya --- arch/arm64/boot/dts/qcom/lemans-evk.dts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/lemans-evk.dts b/arch/arm64/boot/dts/qcom/lemans-evk.dts index 01100bda93c2d..fd72920121734 100644 --- a/arch/arm64/boot/dts/qcom/lemans-evk.dts +++ b/arch/arm64/boot/dts/qcom/lemans-evk.dts @@ -603,14 +603,17 @@ }; &qupv3_id_0 { + firmware-name = "qcom/sa8775p/qupv3fw.elf"; status = "okay"; }; &qupv3_id_1 { + firmware-name = "qcom/sa8775p/qupv3fw.elf"; status = "okay"; }; &qupv3_id_2 { + firmware-name = "qcom/sa8775p/qupv3fw.elf"; status = "okay"; }; From e79281bf1d56da63f0f9d19b0ac35352096ac6e9 Mon Sep 17 00:00:00 2001 From: Viken Dadhaniya Date: Thu, 25 Sep 2025 09:56:05 +0530 Subject: [PATCH 0038/2333] FROMLIST: arm64: dts: qcom: monaco-evk: Add firmware-name to QUPv3 nodes Traditionally, firmware loading for Serial Engines (SE) in the QUP hardware of Qualcomm SoCs has been managed by TrustZone (TZ). While this approach ensures secure SE assignment and access control, it limits flexibility for developers who need to enable various protocols on different SEs. Add the firmware-name property to QUPv3 nodes in the device tree to enable firmware loading from the Linux environment. Handle SE assignments and access control permissions directly within Linux, removing the dependency on TrustZone. Link: https://lore.kernel.org/all/20250925042605.1388951-1-viken.dadhaniya@oss.qualcomm.com/ Signed-off-by: Viken Dadhaniya --- arch/arm64/boot/dts/qcom/monaco-evk.dts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/monaco-evk.dts b/arch/arm64/boot/dts/qcom/monaco-evk.dts index 87d613094e551..93ce2852f689b 100644 --- a/arch/arm64/boot/dts/qcom/monaco-evk.dts +++ b/arch/arm64/boot/dts/qcom/monaco-evk.dts @@ -408,10 +408,12 @@ }; &qupv3_id_0 { + firmware-name = "qcom/qcs8300/qupv3fw.elf"; status = "okay"; }; &qupv3_id_1 { + firmware-name = "qcom/qcs8300/qupv3fw.elf"; status = "okay"; }; From c6470d3008cc56cd5d87e4516f10f14cbcdc3a35 Mon Sep 17 00:00:00 2001 From: Chandan Kumar Jha Date: Fri, 17 Oct 2025 11:25:35 +0530 Subject: [PATCH 0039/2333] QCLINUX: arm64: dts: qcom: Add camera DT binding Add the camera DT binding header, which will be utilized by the camera downstream drivers and DTSI files. Signed-off-by: Chandan Kumar Jha --- include/dt-bindings/camera/msm-camera.h | 155 ++++++++++++++++++++++++ 1 file changed, 155 insertions(+) create mode 100644 include/dt-bindings/camera/msm-camera.h diff --git a/include/dt-bindings/camera/msm-camera.h b/include/dt-bindings/camera/msm-camera.h new file mode 100644 index 0000000000000..97228c26e7040 --- /dev/null +++ b/include/dt-bindings/camera/msm-camera.h @@ -0,0 +1,155 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#ifndef __MSM_CAMERA_H +#define __MSM_CAMERA_H + +/* CPAS path data types */ +#define CAM_CPAS_PATH_DATA_IFE_START_OFFSET 0 +#define CAM_CPAS_PATH_DATA_IFE_LINEAR (CAM_CPAS_PATH_DATA_IFE_START_OFFSET + 0) +#define CAM_CPAS_PATH_DATA_IFE_VID (CAM_CPAS_PATH_DATA_IFE_START_OFFSET + 1) +#define CAM_CPAS_PATH_DATA_IFE_DISP (CAM_CPAS_PATH_DATA_IFE_START_OFFSET + 2) +#define CAM_CPAS_PATH_DATA_IFE_STATS (CAM_CPAS_PATH_DATA_IFE_START_OFFSET + 3) +#define CAM_CPAS_PATH_DATA_IFE_RDI0 (CAM_CPAS_PATH_DATA_IFE_START_OFFSET + 4) +#define CAM_CPAS_PATH_DATA_IFE_RDI1 (CAM_CPAS_PATH_DATA_IFE_START_OFFSET + 5) +#define CAM_CPAS_PATH_DATA_IFE_RDI2 (CAM_CPAS_PATH_DATA_IFE_START_OFFSET + 6) +#define CAM_CPAS_PATH_DATA_IFE_RDI3 (CAM_CPAS_PATH_DATA_IFE_START_OFFSET + 7) +#define CAM_CPAS_PATH_DATA_IFE_PDAF (CAM_CPAS_PATH_DATA_IFE_START_OFFSET + 8) +#define CAM_CPAS_PATH_DATA_IFE_PIXEL_RAW (CAM_CPAS_PATH_DATA_IFE_START_OFFSET + 9) +#define CAM_CPAS_PATH_DATA_IFE_MAX_OFFSET (CAM_CPAS_PATH_DATA_IFE_START_OFFSET + 31) + +#define CAM_CPAS_PATH_DATA_IPE_START_OFFSET 32 +#define CAM_CPAS_PATH_DATA_IPE_RD_IN (CAM_CPAS_PATH_DATA_IPE_START_OFFSET + 0) +#define CAM_CPAS_PATH_DATA_IPE_RD_REF (CAM_CPAS_PATH_DATA_IPE_START_OFFSET + 1) +#define CAM_CPAS_PATH_DATA_IPE_WR_VID (CAM_CPAS_PATH_DATA_IPE_START_OFFSET + 2) +#define CAM_CPAS_PATH_DATA_IPE_WR_DISP (CAM_CPAS_PATH_DATA_IPE_START_OFFSET + 3) +#define CAM_CPAS_PATH_DATA_IPE_WR_REF (CAM_CPAS_PATH_DATA_IPE_START_OFFSET + 4) +#define CAM_CPAS_PATH_DATA_IPE_WR_APP (CAM_CPAS_PATH_DATA_IPE_START_OFFSET + 5) +#define CAM_CPAS_PATH_DATA_IPE_MAX_OFFSET (CAM_CPAS_PATH_DATA_IPE_START_OFFSET + 31) + +#define CAM_CPAS_PATH_DATA_OPE_START_OFFSET 64 +#define CAM_CPAS_PATH_DATA_OPE_RD_IN (CAM_CPAS_PATH_DATA_OPE_START_OFFSET + 0) +#define CAM_CPAS_PATH_DATA_OPE_RD_REF (CAM_CPAS_PATH_DATA_OPE_START_OFFSET + 1) +#define CAM_CPAS_PATH_DATA_OPE_WR_VID (CAM_CPAS_PATH_DATA_OPE_START_OFFSET + 2) +#define CAM_CPAS_PATH_DATA_OPE_WR_DISP (CAM_CPAS_PATH_DATA_OPE_START_OFFSET + 3) +#define CAM_CPAS_PATH_DATA_OPE_WR_REF (CAM_CPAS_PATH_DATA_OPE_START_OFFSET + 4) +#define CAM_CPAS_PATH_DATA_OPE_MAX_OFFSET (CAM_CPAS_PATH_DATA_OPE_START_OFFSET + 31) + +#define CAM_CPAS_PATH_DATA_SFE_START_OFFSET 96 +#define CAM_CPAS_PATH_DATA_SFE_NRDI (CAM_CPAS_PATH_DATA_SFE_START_OFFSET + 0) +#define CAM_CPAS_PATH_DATA_SFE_RDI0 (CAM_CPAS_PATH_DATA_SFE_START_OFFSET + 1) +#define CAM_CPAS_PATH_DATA_SFE_RDI1 (CAM_CPAS_PATH_DATA_SFE_START_OFFSET + 2) +#define CAM_CPAS_PATH_DATA_SFE_RDI2 (CAM_CPAS_PATH_DATA_SFE_START_OFFSET + 3) +#define CAM_CPAS_PATH_DATA_SFE_RDI3 (CAM_CPAS_PATH_DATA_SFE_START_OFFSET + 4) +#define CAM_CPAS_PATH_DATA_SFE_RDI4 (CAM_CPAS_PATH_DATA_SFE_START_OFFSET + 5) +#define CAM_CPAS_PATH_DATA_SFE_STATS (CAM_CPAS_PATH_DATA_SFE_START_OFFSET + 6) +#define CAM_CPAS_PATH_DATA_SFE_MAX_OFFSET (CAM_CPAS_PATH_DATA_SFE_START_OFFSET + 31) + +#define CAM_CPAS_PATH_DATA_CRE_START_OFFSET (CAM_CPAS_PATH_DATA_SFE_MAX_OFFSET + 1) +#define CAM_CPAS_PATH_DATA_CRE_RD_IN (CAM_CPAS_PATH_DATA_CRE_START_OFFSET + 0) +#define CAM_CPAS_PATH_DATA_CRE_WR_OUT (CAM_CPAS_PATH_DATA_CRE_START_OFFSET + 1) +#define CAM_CPAS_PATH_DATA_CRE_MAX_OFFSET (CAM_CPAS_PATH_DATA_CRE_START_OFFSET + 31) + +#define CAM_CPAS_PATH_DATA_OFE_START_OFFSET (CAM_CPAS_PATH_DATA_CRE_MAX_OFFSET + 1) +#define CAM_CPAS_PATH_DATA_OFE_RD_EXT (CAM_CPAS_PATH_DATA_OFE_START_OFFSET + 0) +#define CAM_CPAS_PATH_DATA_OFE_RD_INT_PDI (CAM_CPAS_PATH_DATA_OFE_START_OFFSET + 1) +#define CAM_CPAS_PATH_DATA_OFE_RD_INT_HDR (CAM_CPAS_PATH_DATA_OFE_START_OFFSET + 2) +#define CAM_CPAS_PATH_DATA_OFE_WR_VID (CAM_CPAS_PATH_DATA_OFE_START_OFFSET + 3) +#define CAM_CPAS_PATH_DATA_OFE_WR_DISP (CAM_CPAS_PATH_DATA_OFE_START_OFFSET + 4) +#define CAM_CPAS_PATH_DATA_OFE_WR_IR (CAM_CPAS_PATH_DATA_OFE_START_OFFSET + 5) +#define CAM_CPAS_PATH_DATA_OFE_WR_HDR_LTM (CAM_CPAS_PATH_DATA_OFE_START_OFFSET + 6) +#define CAM_CPAS_PATH_DATA_OFE_WR_DC4 (CAM_CPAS_PATH_DATA_OFE_START_OFFSET + 7) +#define CAM_CPAS_PATH_DATA_OFE_WR_AI (CAM_CPAS_PATH_DATA_OFE_START_OFFSET + 8) +#define CAM_CPAS_PATH_DATA_OFE_WR_PDI (CAM_CPAS_PATH_DATA_OFE_START_OFFSET + 9) +#define CAM_CPAS_PATH_DATA_OFE_WR_IDEALRAW (CAM_CPAS_PATH_DATA_OFE_START_OFFSET + 10) +#define CAM_CPAS_PATH_DATA_OFE_WR_STATS (CAM_CPAS_PATH_DATA_OFE_START_OFFSET + 11) +#define CAM_CPAS_PATH_DATA_OFE_MAX_OFFSET (CAM_CPAS_PATH_DATA_OFE_START_OFFSET + 31) + +#define CAM_CPAS_PATH_DATA_CONSO_OFFSET 256 +#define CAM_CPAS_PATH_DATA_ALL (CAM_CPAS_PATH_DATA_CONSO_OFFSET + 0) + +/* IFE consolidated paths */ +#define CAM_CPAS_PATH_DATA_IFE_LINEAR_PDAF (CAM_CPAS_PATH_DATA_CONSO_OFFSET + 1) +#define CAM_CPAS_PATH_DATA_IFE_UBWC_STATS (CAM_CPAS_PATH_DATA_CONSO_OFFSET + 2) +#define CAM_CPAS_PATH_DATA_IFE_PIXEL_ALL (CAM_CPAS_PATH_DATA_CONSO_OFFSET + 3) +#define CAM_CPAS_PATH_DATA_IFE_RDI_PIXEL_RAW (CAM_CPAS_PATH_DATA_CONSO_OFFSET + 4) +#define CAM_CPAS_PATH_DATA_IFE_RDI_ALL (CAM_CPAS_PATH_DATA_CONSO_OFFSET + 5) +#define CAM_CPAS_PATH_DATA_IFE_UBWC (CAM_CPAS_PATH_DATA_CONSO_OFFSET + 6) +#define CAM_CPAS_PATH_DATA_IFE_LINEAR_STATS (CAM_CPAS_PATH_DATA_CONSO_OFFSET + 7) +#define CAM_CPAS_PATH_DATA_IFE_UBWC_LINEAR (CAM_CPAS_PATH_DATA_CONSO_OFFSET + 8) +#define CAM_CPAS_PATH_DATA_IFE_PDAF_LINEAR (CAM_CPAS_PATH_DATA_CONSO_OFFSET + 9) + +/* IPE Consolidated paths */ +#define CAM_CPAS_PATH_DATA_IPE_WR_VID_DISP (CAM_CPAS_PATH_DATA_CONSO_OFFSET + 1) + +/* CPAS transaction types */ +#define CAM_CPAS_TRANSACTION_READ 0 +#define CAM_CPAS_TRANSACTION_WRITE 1 + +/* CPAS traffic merge types */ +#define CAM_CPAS_TRAFFIC_MERGE_SUM 0 +#define CAM_CPAS_TRAFFIC_MERGE_SUM_INTERLEAVE 1 + +/* Feature bit type */ +#define CAM_CPAS_FEATURE_TYPE_DISABLE 0 +#define CAM_CPAS_FEATURE_TYPE_ENABLE 1 +#define CAM_CPAS_FEATURE_TYPE_VALUE 2 + +/* Feature support bit positions in feature fuse register*/ +#define CAM_CPAS_QCFA_BINNING_ENABLE 0 +#define CAM_CPAS_SECURE_CAMERA_ENABLE 1 +#define CAM_CPAS_MF_HDR_ENABLE 2 +#define CAM_CPAS_MP_LIMIT_FUSE 3 +#define CAM_CPAS_ISP_FUSE 4 +#define CAM_CPAS_ISP_PIX_FUSE 5 +#define CAM_CPAS_ISP_LITE_FUSE 6 +#define CAM_CPAS_CSIPHY_FUSE 7 +#define CAM_CPAS_IPE_VID_OUT_8BPP_LIMIT_ENABLE 8 +#define CAM_CPAS_SFE_FUSE 9 +#define CAM_CPAS_CUSTOM_FUSE 10 +#define CAM_CPAS_CAM_FUSE 11 +#define CAM_CPAS_SHDR_FUSE 12 +#define CAM_CPAS_RT_OT_FUSE 13 +#define CAM_CPAS_FUSE_FEATURE_MAX 14 + +/* Flash type*/ +#define CAM_FLASH_TYPE_PMIC 0 +#define CAM_FLASH_TYPE_I2C 1 +#define CAM_FLASH_TYPE_GPIO 2 + +/* CCI master */ +#define CCI_MASTER_0 0 +#define CCI_MASTER_1 1 +#define CCI_MASTER_MAX 2 + +/* AON Camera IDs*/ +#define AON_CAM1 0 +#define AON_CAM2 1 +#define MAX_AON_CAM 2 +#define NOT_AON_CAM 255 + +/* Camera DRV enable masks */ +#define CAM_DDR_DRV 0x1 +#define CAM_CLK_DRV 0x2 + +/* Port index for BW voting */ +#define CAM_CPAS_PORT_HLOS_DRV 0 +#define CAM_CPAS_PORT_DRV_0 1 +#define CAM_CPAS_PORT_DRV_1 2 +#define CAM_CPAS_PORT_DRV_2 3 +#define CAM_CPAS_PORT_DRV_DYN 32 + +/* Domain ID types */ +#define CAM_CPAS_NON_SECURE_DOMAIN 0 +#define CAM_CPAS_SECURE_DOMAIN 1 + +/* Debug bypass driver */ +#define CAM_BYPASS_RGLTR 0x1 +#define CAM_BYPASS_RGLTR_MODE 0x2 +#define CAM_BYPASS_CLKS 0x4 +#define CAM_BYPASS_CESTA 0x8 +#define CAM_BYPASS_ICC 0x10 + +#endif From 5094920fca20a7538417a53dd6bee0fbe128d6fd Mon Sep 17 00:00:00 2001 From: Chandan Kumar Jha Date: Fri, 10 Oct 2025 16:51:48 +0530 Subject: [PATCH 0040/2333] QCLINUX: arm64: dts: qcom: Add lemans camx overlay dts Add CAMX overlay dts file for lemans boards. This change also enables the compilation of the CAMX overlay on Lemans boards. Co-developed-by: Vikram Sharma Signed-off-by: Vikram Sharma Signed-off-by: Chandan Kumar Jha --- arch/arm64/boot/dts/qcom/Makefile | 25 + .../boot/dts/qcom/lemans-camera-sensor.dtsi | 502 ++++ arch/arm64/boot/dts/qcom/lemans-camera.dtsi | 2559 +++++++++++++++++ .../dts/qcom/lemans-evk-camera-sensor.dtsi | 736 +++++ arch/arm64/boot/dts/qcom/lemans-evk-camx.dtso | 138 + .../boot/dts/qcom/sa8775p-ride-camx.dtso | 16 + 6 files changed, 3976 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/lemans-camera-sensor.dtsi create mode 100644 arch/arm64/boot/dts/qcom/lemans-camera.dtsi create mode 100644 arch/arm64/boot/dts/qcom/lemans-evk-camera-sensor.dtsi create mode 100644 arch/arm64/boot/dts/qcom/lemans-evk-camx.dtso create mode 100644 arch/arm64/boot/dts/qcom/sa8775p-ride-camx.dtso diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile index 296688f7cb265..b9f9e659b95fe 100644 --- a/arch/arm64/boot/dts/qcom/Makefile +++ b/arch/arm64/boot/dts/qcom/Makefile @@ -35,6 +35,11 @@ dtb-$(CONFIG_ARCH_QCOM) += lemans-evk.dtb lemans-evk-camera-csi1-imx577-dtbs := lemans-evk.dtb lemans-evk-camera-csi1-imx577.dtbo dtb-$(CONFIG_ARCH_QCOM) += lemans-evk-camera-csi1-imx577.dtb + +lemans-evk-camx-dtbs := lemans-evk.dtb lemans-evk-camx.dtbo + +dtb-$(CONFIG_ARCH_QCOM) += lemans-evk-camx.dtb + dtb-$(CONFIG_ARCH_QCOM) += monaco-evk.dtb dtb-$(CONFIG_ARCH_QCOM) += msm8216-samsung-fortuna3g.dtb dtb-$(CONFIG_ARCH_QCOM) += msm8916-acer-a1-724.dtb @@ -136,7 +141,17 @@ dtb-$(CONFIG_ARCH_QCOM) += qcs6490-rb3gen2-vision-mezzanine.dtb dtb-$(CONFIG_ARCH_QCOM) += qcs8300-ride.dtb dtb-$(CONFIG_ARCH_QCOM) += qcs8550-aim300-aiot.dtb dtb-$(CONFIG_ARCH_QCOM) += qcs9100-ride.dtb + +qcs9100-ride-camx-dtbs:= qcs9100-ride.dtb sa8775p-ride-camx.dtbo + +dtb-$(CONFIG_ARCH_QCOM) += qcs9100-ride-camx.dtb + dtb-$(CONFIG_ARCH_QCOM) += qcs9100-ride-r3.dtb + +qcs9100-ride-r3-camx-dtbs:= qcs9100-ride-r3.dtb sa8775p-ride-camx.dtbo + +dtb-$(CONFIG_ARCH_QCOM) += qcs9100-ride-r3-camx.dtb + dtb-$(CONFIG_ARCH_QCOM) += qdu1000-idp.dtb dtb-$(CONFIG_ARCH_QCOM) += qrb2210-rb1.dtb dtb-$(CONFIG_ARCH_QCOM) += qrb4210-rb2.dtb @@ -150,7 +165,17 @@ dtb-$(CONFIG_ARCH_QCOM) += sa8155p-adp.dtb dtb-$(CONFIG_ARCH_QCOM) += sa8295p-adp.dtb dtb-$(CONFIG_ARCH_QCOM) += sa8540p-ride.dtb dtb-$(CONFIG_ARCH_QCOM) += sa8775p-ride.dtb + +sa8775p-ride-camx-dtbs:= sa8775p-ride.dtb sa8775p-ride-camx.dtbo + +dtb-$(CONFIG_ARCH_QCOM) += sa8775p-ride-camx.dtb + dtb-$(CONFIG_ARCH_QCOM) += sa8775p-ride-r3.dtb + +sa8775p-ride-r3-camx-dtbs:= sa8775p-ride-r3.dtb sa8775p-ride-camx.dtbo + +dtb-$(CONFIG_ARCH_QCOM) += sa8775p-ride-r3-camx.dtb + sc7180-acer-aspire1-el2-dtbs := sc7180-acer-aspire1.dtb sc7180-el2.dtbo dtb-$(CONFIG_ARCH_QCOM) += sc7180-acer-aspire1.dtb sc7180-acer-aspire1-el2.dtb dtb-$(CONFIG_ARCH_QCOM) += sc7180-idp.dtb diff --git a/arch/arm64/boot/dts/qcom/lemans-camera-sensor.dtsi b/arch/arm64/boot/dts/qcom/lemans-camera-sensor.dtsi new file mode 100644 index 0000000000000..d531f89dda08e --- /dev/null +++ b/arch/arm64/boot/dts/qcom/lemans-camera-sensor.dtsi @@ -0,0 +1,502 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#include + +&cam_cci0 { + /* GMSL deserializer 0 */ + qcom,cam-gmsl-deserializer0 { + cell-index = <0>; + csiphy-sd-index = <0>; + sensor-position-roll = <0>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + cam_vio-supply = <&vreg_s4a>; + regulator-names = "cam_vio"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000>; + rgltr-max-voltage = <1800000>; + rgltr-load-current = <120000>; + gpio-no-mux = <0>; + pinctrl-0 = <&cam_sensor_mclk0_active>; + pinctrl-1 = <&cam_sensor_mclk0_suspend>; + pinctrl-names = "cam_default", "cam_suspend"; + gpios = <&pmm8654au_0_gpios 7 0>; + gpio-reset = <0>; + gpio-req-tbl-num = <0>; + gpio-req-tbl-flags = <0>; + gpio-req-tbl-label = "CAM_RESET0"; + cci-master = <0>; + clocks = <&camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "nominal"; + clock-rates = <24000000>; + status = "ok"; + + port@0 { + reg = <0>; + + deser0_port0: endpoint { + remote-endpoint = <&gmsl_sensor0_ep>; + }; + }; + + port@1 { + reg = <1>; + + deser0_port1: endpoint { + remote-endpoint = <&gmsl_sensor1_ep>; + }; + }; + + port@2 { + reg = <0>; + + deser0_port2: endpoint { + remote-endpoint = <&gmsl_sensor2_ep>; + }; + }; + + port@3 { + reg = <1>; + + deser0_port3: endpoint { + remote-endpoint = <&gmsl_sensor3_ep>; + }; + }; + }; + + /* GMSL deserializer 0 sensor 0 */ + qcom,cam-gmsl-sensor0 { + compatible = "qcom,cam-gmsl-sensor"; + cell-index = <0>; + csiphy-sd-index = <0>; + status = "ok"; + + port { + gmsl_sensor0_ep: endpoint { + remote-endpoint = <&deser0_port0>; + }; + }; + }; + + /* GMSL deserializer 0 sensor 1 */ + qcom,cam-gmsl-sensor1 { + compatible = "qcom,cam-gmsl-sensor"; + cell-index = <1>; + csiphy-sd-index = <0>; + status = "ok"; + + port { + gmsl_sensor1_ep: endpoint { + remote-endpoint = <&deser0_port1>; + }; + }; + }; + + /* GMSL deserializer 0 sensor 2 */ + qcom,cam-gmsl-sensor2 { + compatible = "qcom,cam-gmsl-sensor"; + cell-index = <2>; + csiphy-sd-index = <0>; + status = "ok"; + + port { + gmsl_sensor2_ep: endpoint { + remote-endpoint = <&deser0_port2>; + }; + }; + }; + + /* GMSL deserializer 0 sensor 3 */ + qcom,cam-gmsl-sensor3 { + compatible = "qcom,cam-gmsl-sensor"; + cell-index = <3>; + csiphy-sd-index = <0>; + status = "ok"; + + port { + gmsl_sensor3_ep: endpoint { + remote-endpoint = <&deser0_port3>; + }; + }; + }; +}; + +&cam_cci1 { + /* GMSL deserializer 1 */ + qcom,cam-gmsl-deserializer1 { + cell-index = <1>; + csiphy-sd-index = <1>; + sensor-position-roll = <0>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + cam_vio-supply = <&vreg_s4a>; + regulator-names = "cam_vio"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000>; + rgltr-max-voltage = <1800000>; + rgltr-load-current = <120000>; + gpio-no-mux = <0>; + pinctrl-0 = <&cam_sensor_mclk1_active>; + pinctrl-1 = <&cam_sensor_mclk1_suspend>; + pinctrl-names = "cam_default", "cam_suspend"; + gpios = <&pmm8654au_0_gpios 8 0>; + gpio-reset = <0>; + gpio-req-tbl-num = <0>; + gpio-req-tbl-flags = <0>; + gpio-req-tbl-label = "CAM_RESET1"; + cci-master = <0>; + clocks = <&camcc CAM_CC_MCLK1_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "nominal"; + clock-rates = <24000000>; + status = "ok"; + + port@0 { + reg = <0>; + + deser1_port0: endpoint { + remote-endpoint = <&gmsl_sensor4_ep>; + }; + }; + + port@1 { + reg = <1>; + + deser1_port1: endpoint { + remote-endpoint = <&gmsl_sensor5_ep>; + }; + }; + + port@2 { + reg = <0>; + + deser1_port2: endpoint { + remote-endpoint = <&gmsl_sensor6_ep>; + }; + }; + + port@3 { + reg = <1>; + + deser1_port3: endpoint { + remote-endpoint = <&gmsl_sensor7_ep>; + }; + }; + }; + + /* GMSL deserializer 1 sensor 0 */ + qcom,cam-gmsl-sensor4 { + compatible = "qcom,cam-gmsl-sensor"; + cell-index = <4>; + csiphy-sd-index = <1>; + status = "ok"; + + port { + gmsl_sensor4_ep: endpoint { + remote-endpoint = <&deser1_port0>; + }; + }; + }; + + /* GMSL deserializer 1 sensor 1 */ + qcom,cam-gmsl-sensor5 { + compatible = "qcom,cam-gmsl-sensor"; + cell-index = <5>; + csiphy-sd-index = <1>; + status = "ok"; + + port { + gmsl_sensor5_ep: endpoint { + remote-endpoint = <&deser1_port1>; + }; + }; + }; + + /* GMSL deserializer 1 sensor 2 */ + qcom,cam-gmsl-sensor6 { + compatible = "qcom,cam-gmsl-sensor"; + cell-index = <6>; + csiphy-sd-index = <1>; + status = "ok"; + + port { + gmsl_sensor6_ep: endpoint { + remote-endpoint = <&deser1_port2>; + }; + }; + }; + + /* GMSL deserializer 1 sensor 3 */ + qcom,cam-gmsl-sensor7 { + compatible = "qcom,cam-gmsl-sensor"; + cell-index = <7>; + csiphy-sd-index = <1>; + status = "ok"; + + port { + gmsl_sensor7_ep: endpoint { + remote-endpoint = <&deser1_port3>; + }; + }; + }; +}; + +&cam_cci2 { + /* GMSL deserializer 2 */ + qcom,cam-gmsl-deserializer2 { + cell-index = <2>; + csiphy-sd-index = <2>; + sensor-position-roll = <0>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + cam_vio-supply = <&vreg_s4a>; + regulator-names = "cam_vio"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000>; + rgltr-max-voltage = <1800000>; + rgltr-load-current = <120000>; + gpio-no-mux = <0>; + pinctrl-0 = <&cam_sensor_mclk2_active>; + pinctrl-1 = <&cam_sensor_mclk2_suspend>; + pinctrl-names = "cam_default", "cam_suspend"; + gpios = <&pmm8654au_0_gpios 9 0>; + gpio-reset = <0>; + gpio-req-tbl-num = <0>; + gpio-req-tbl-flags = <0>; + gpio-req-tbl-label = "CAM_RESET2"; + cci-master = <0>; + clocks = <&camcc CAM_CC_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "nominal"; + clock-rates = <24000000>; + status = "ok"; + + port@0 { + reg = <0>; + + deser2_port0: endpoint { + remote-endpoint = <&gmsl_sensor8_ep>; + }; + }; + + port@1 { + reg = <1>; + + deser2_port1: endpoint { + remote-endpoint = <&gmsl_sensor9_ep>; + }; + }; + + port@2 { + reg = <0>; + + deser2_port2: endpoint { + remote-endpoint = <&gmsl_sensor10_ep>; + }; + }; + + port@3 { + reg = <1>; + + deser2_port3: endpoint { + remote-endpoint = <&gmsl_sensor11_ep>; + }; + }; + }; + + /* GMSL deserializer 2 sensor 0 */ + qcom,cam-gmsl-sensor8 { + compatible = "qcom,cam-gmsl-sensor"; + cell-index = <8>; + csiphy-sd-index = <2>; + status = "ok"; + + port { + gmsl_sensor8_ep: endpoint { + remote-endpoint = <&deser2_port0>; + }; + }; + }; + + /* GMSL deserializer 2 sensor 1 */ + qcom,cam-gmsl-sensor9 { + compatible = "qcom,cam-gmsl-sensor"; + cell-index = <9>; + csiphy-sd-index = <2>; + status = "ok"; + + port { + gmsl_sensor9_ep: endpoint { + remote-endpoint = <&deser2_port1>; + }; + }; + }; + + /* GMSL deserializer 2 sensor 2 */ + qcom,cam-gmsl-sensor10 { + compatible = "qcom,cam-gmsl-sensor"; + cell-index = <10>; + csiphy-sd-index = <2>; + status = "ok"; + + port { + gmsl_sensor10_ep: endpoint { + remote-endpoint = <&deser2_port2>; + }; + }; + }; + + /* GMSL deserializer 2 sensor 3 */ + qcom,cam-gmsl-sensor11 { + compatible = "qcom,cam-gmsl-sensor"; + cell-index = <11>; + csiphy-sd-index = <2>; + status = "ok"; + + port { + gmsl_sensor11_ep: endpoint { + remote-endpoint = <&deser2_port3>; + }; + }; + }; +}; + +&cam_cci3 { + /* GMSL deserializer 3 */ + qcom,cam-gmsl-deserializer3 { + cell-index = <3>; + csiphy-sd-index = <3>; + sensor-position-roll = <0>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + cam_vio-supply = <&vreg_s4a>; + regulator-names = "cam_vio"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000>; + rgltr-max-voltage = <1800000>; + rgltr-load-current = <120000>; + gpio-no-mux = <0>; + pinctrl-0 = <&cam_sensor_mclk3_active>; + pinctrl-1 = <&cam_sensor_mclk3_suspend>; + pinctrl-names = "cam_default", "cam_suspend"; + gpios = <&pmm8654au_0_gpios 10 0>; + gpio-reset = <0>; + gpio-req-tbl-num = <0>; + gpio-req-tbl-flags = <0>; + gpio-req-tbl-label = "CAM_RESET3"; + cci-master = <0>; + clocks = <&camcc CAM_CC_MCLK3_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "nominal"; + clock-rates = <24000000>; + status = "ok"; + + port@0 { + reg = <0>; + + deser3_port0: endpoint { + remote-endpoint = <&gmsl_sensor12_ep>; + }; + }; + + port@1 { + reg = <1>; + + deser3_port1: endpoint { + remote-endpoint = <&gmsl_sensor13_ep>; + }; + }; + + port@2 { + reg = <0>; + + deser3_port2: endpoint { + remote-endpoint = <&gmsl_sensor14_ep>; + }; + }; + + port@3 { + reg = <1>; + + deser3_port3: endpoint { + remote-endpoint = <&gmsl_sensor15_ep>; + }; + }; + }; + + /* GMSL deserializer 3 sensor 0 */ + qcom,cam-gmsl-sensor12 { + compatible = "qcom,cam-gmsl-sensor"; + cell-index = <12>; + csiphy-sd-index = <3>; + status = "ok"; + + port { + gmsl_sensor12_ep: endpoint { + remote-endpoint = <&deser3_port0>; + }; + }; + }; + + /* GMSL deserializer 3 sensor 1 */ + qcom,cam-gmsl-sensor13 { + compatible = "qcom,cam-gmsl-sensor"; + cell-index = <13>; + csiphy-sd-index = <3>; + status = "ok"; + + port { + gmsl_sensor13_ep: endpoint { + remote-endpoint = <&deser3_port1>; + }; + }; + }; + + /* GMSL deserializer 3 sensor 2 */ + qcom,cam-gmsl-sensor14 { + compatible = "qcom,cam-gmsl-sensor"; + cell-index = <14>; + csiphy-sd-index = <3>; + status = "ok"; + + port { + gmsl_sensor14_ep: endpoint { + remote-endpoint = <&deser3_port2>; + }; + }; + }; + + /* GMSL deserializer 3 sensor 3 */ + qcom,cam-gmsl-sensor15 { + compatible = "qcom,cam-gmsl-sensor"; + cell-index = <15>; + csiphy-sd-index = <3>; + status = "ok"; + + port { + gmsl_sensor15_ep: endpoint { + remote-endpoint = <&deser3_port3>; + }; + }; + }; +}; + +&soc { + qcom,cam-res-mgr { + compatible = "qcom,cam-res-mgr"; + gpios-shared = <518 519 520 521>; + status = "ok"; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/lemans-camera.dtsi b/arch/arm64/boot/dts/qcom/lemans-camera.dtsi new file mode 100644 index 0000000000000..18d78926b1f17 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/lemans-camera.dtsi @@ -0,0 +1,2559 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#include + +&soc { + cam_cci0: qcom,cci0@ac13000 { + compatible = "qcom,cci", "simple-bus"; + reg = <0x0 0xac13000 0x0 0x1000>; + reg-names = "cci"; + reg-cam-base = <0x13000>; + interrupts = ; + interrupt-names = "CCI0"; + operating-points-v2 = <&cci0_opp_table>; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + clocks = <&camcc CAM_CC_CCI_0_CLK_SRC>, + <&camcc CAM_CC_CCI_0_CLK>; + clock-names = "cci_0_clk_src", + "cci_0_clk"; + clock-rates = <37500000 0>; + clock-cntl-level = "lowsvs"; + src-clock-name = "cci_0_clk_src"; + pctrl-idx-mapping = ; + pctrl-map-names = "m0", "m1"; + pinctrl-0 = <&cci0_active>; + pinctrl-1 = <&cci0_suspend>; + pinctrl-2 = <&cci1_active>; + pinctrl-3 = <&cci1_suspend>; + pinctrl-names = "m0_active", "m0_suspend", + "m1_active", "m1_suspend"; + cell-index = <0>; + status = "ok"; + + cci0_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-37500000 { + opp-hz = /bits/ 64 <37500000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + }; + + i2c_freq_custom_cci0: qcom,i2c-custom-mode { + hw-thigh = <16>; + hw-tlow = <22>; + hw-tsu-sto = <17>; + hw-tsu-sta = <18>; + hw-thd-dat = <16>; + hw-thd-sta = <15>; + hw-tbuf = <24>; + hw-scl-stretch-en = <1>; + hw-trdhld = <3>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + + i2c_freq_400Khz_cci0: qcom,i2c-fast-mode { + hw-thigh = <38>; + hw-tlow = <56>; + hw-tsu-sto = <40>; + hw-tsu-sta = <40>; + hw-thd-dat = <22>; + hw-thd-sta = <35>; + hw-tbuf = <62>; + hw-scl-stretch-en = <1>; + hw-trdhld = <6>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + + i2c_freq_1Mhz_cci0: qcom,i2c-fast-plus-mode { + hw-thigh = <16>; + hw-tlow = <22>; + hw-tsu-sto = <17>; + hw-tsu-sta = <18>; + hw-thd-dat = <16>; + hw-thd-sta = <15>; + hw-tbuf = <24>; + hw-scl-stretch-en = <1>; + hw-trdhld = <3>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + + i2c_freq_100Khz_cci0: qcom,i2c-standard-mode { + hw-thigh = <201>; + hw-tlow = <174>; + hw-tsu-sto = <204>; + hw-tsu-sta = <231>; + hw-thd-dat = <22>; + hw-thd-sta = <162>; + hw-tbuf = <227>; + hw-scl-stretch-en = <0>; + hw-trdhld = <6>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + }; + + cam_cci1: qcom,cci1@ac14000 { + compatible = "qcom,cci", "simple-bus"; + reg = <0x0 0xac14000 0x0 0x1000>; + reg-names = "cci"; + reg-cam-base = <0x14000>; + interrupts = ; + interrupt-names = "CCI1"; + operating-points-v2 = <&cci1_opp_table>; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + clocks = <&camcc CAM_CC_CCI_1_CLK_SRC>, + <&camcc CAM_CC_CCI_1_CLK>; + clock-names = "cci_1_clk_src", + "cci_1_clk"; + clock-rates = <37500000 0>; + clock-cntl-level = "lowsvs"; + src-clock-name = "cci_1_clk_src"; + pctrl-idx-mapping = ; + pctrl-map-names = "m0", "m1"; + pinctrl-0 = <&cci2_active>; + pinctrl-1 = <&cci2_suspend>; + pinctrl-2 = <&cci3_active>; + pinctrl-3 = <&cci3_suspend>; + pinctrl-names = "m0_active", "m0_suspend", + "m1_active", "m1_suspend"; + cell-index = <1>; + status = "ok"; + + cci1_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-37500000 { + opp-hz = /bits/ 64 <37500000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + }; + + i2c_freq_custom_cci1: qcom,i2c-custom-mode { + hw-thigh = <16>; + hw-tlow = <22>; + hw-tsu-sto = <17>; + hw-tsu-sta = <18>; + hw-thd-dat = <16>; + hw-thd-sta = <15>; + hw-tbuf = <24>; + hw-scl-stretch-en = <1>; + hw-trdhld = <3>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + + i2c_freq_400Khz_cci1: qcom,i2c-fast-mode { + hw-thigh = <38>; + hw-tlow = <56>; + hw-tsu-sto = <40>; + hw-tsu-sta = <40>; + hw-thd-dat = <22>; + hw-thd-sta = <35>; + hw-tbuf = <62>; + hw-scl-stretch-en = <1>; + hw-trdhld = <6>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + + i2c_freq_1Mhz_cci1: qcom,i2c-fast-plus-mode { + hw-thigh = <16>; + hw-tlow = <22>; + hw-tsu-sto = <17>; + hw-tsu-sta = <18>; + hw-thd-dat = <16>; + hw-thd-sta = <15>; + hw-tbuf = <24>; + hw-scl-stretch-en = <1>; + hw-trdhld = <3>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + + i2c_freq_100Khz_cci1: qcom,i2c-standard-mode { + hw-thigh = <201>; + hw-tlow = <174>; + hw-tsu-sto = <204>; + hw-tsu-sta = <231>; + hw-thd-dat = <22>; + hw-thd-sta = <162>; + hw-tbuf = <227>; + hw-scl-stretch-en = <0>; + hw-trdhld = <6>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + }; + + cam_cci2: qcom,cci2@ac15000 { + compatible = "qcom,cci", "simple-bus"; + reg = <0x0 0xac15000 0x0 0x1000>; + reg-names = "cci"; + reg-cam-base = <0x15000>; + interrupts = ; + interrupt-names = "CCI2"; + operating-points-v2 = <&cci2_opp_table>; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + clocks = <&camcc CAM_CC_CCI_2_CLK_SRC>, + <&camcc CAM_CC_CCI_2_CLK>; + clock-names = "cci_2_clk_src", + "cci_2_clk"; + clock-rates = <37500000 0>; + clock-cntl-level = "lowsvs"; + src-clock-name = "cci_2_clk_src"; + pctrl-idx-mapping = ; + pctrl-map-names = "m0", "m1"; + pinctrl-0 = <&cci4_active>; + pinctrl-1 = <&cci4_suspend>; + pinctrl-2 = <&cci5_active>; + pinctrl-3 = <&cci5_suspend>; + pinctrl-names = "m0_active", "m0_suspend", + "m1_active", "m1_suspend"; + cell-index = <2>; + status = "ok"; + + cci2_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-37500000 { + opp-hz = /bits/ 64 <37500000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + }; + + i2c_freq_custom_cci2: qcom,i2c-custom-mode { + hw-thigh = <16>; + hw-tlow = <22>; + hw-tsu-sto = <17>; + hw-tsu-sta = <18>; + hw-thd-dat = <16>; + hw-thd-sta = <15>; + hw-tbuf = <24>; + hw-scl-stretch-en = <1>; + hw-trdhld = <3>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + + i2c_freq_400Khz_cci2: qcom,i2c-fast-mode { + hw-thigh = <38>; + hw-tlow = <56>; + hw-tsu-sto = <40>; + hw-tsu-sta = <40>; + hw-thd-dat = <22>; + hw-thd-sta = <35>; + hw-tbuf = <62>; + hw-scl-stretch-en = <1>; + hw-trdhld = <6>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + + i2c_freq_1Mhz_cci2: qcom,i2c-fast-plus-mode { + hw-thigh = <16>; + hw-tlow = <22>; + hw-tsu-sto = <17>; + hw-tsu-sta = <18>; + hw-thd-dat = <16>; + hw-thd-sta = <15>; + hw-tbuf = <24>; + hw-scl-stretch-en = <1>; + hw-trdhld = <3>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + + i2c_freq_100Khz_cci2: qcom,i2c-standard-mode { + hw-thigh = <201>; + hw-tlow = <174>; + hw-tsu-sto = <204>; + hw-tsu-sta = <231>; + hw-thd-dat = <22>; + hw-thd-sta = <162>; + hw-tbuf = <227>; + hw-scl-stretch-en = <0>; + hw-trdhld = <6>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + }; + + cam_cci3: qcom,cci3@ac16000 { + compatible = "qcom,cci", "simple-bus"; + reg = <0x0 0xac16000 0x0 0x1000>; + reg-names = "cci"; + reg-cam-base = <0x16000>; + interrupts = ; + interrupt-names = "CCI3"; + operating-points-v2 = <&cci3_opp_table>; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + clocks = <&camcc CAM_CC_CCI_3_CLK_SRC>, + <&camcc CAM_CC_CCI_3_CLK>; + clock-names = "cci_3_clk_src", + "cci_3_clk"; + clock-rates = <37500000 0>; + clock-cntl-level = "lowsvs"; + src-clock-name = "cci_3_clk_src"; + pctrl-idx-mapping = ; + pctrl-map-names = "m0", "m1"; + pinctrl-0 = <&cci6_active>; + pinctrl-1 = <&cci6_suspend>; + pinctrl-2 = <&cci7_active>; + pinctrl-3 = <&cci7_suspend>; + pinctrl-names = "m0_active", "m0_suspend", + "m1_active", "m1_suspend"; + cell-index = <3>; + status = "ok"; + + cci3_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-37500000 { + opp-hz = /bits/ 64 <37500000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + }; + + i2c_freq_custom_cci3: qcom,i2c-custom-mode { + hw-thigh = <16>; + hw-tlow = <22>; + hw-tsu-sto = <17>; + hw-tsu-sta = <18>; + hw-thd-dat = <16>; + hw-thd-sta = <15>; + hw-tbuf = <24>; + hw-scl-stretch-en = <1>; + hw-trdhld = <3>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + + i2c_freq_400Khz_cci3: qcom,i2c-fast-mode { + hw-thigh = <38>; + hw-tlow = <56>; + hw-tsu-sto = <40>; + hw-tsu-sta = <40>; + hw-thd-dat = <22>; + hw-thd-sta = <35>; + hw-tbuf = <62>; + hw-scl-stretch-en = <1>; + hw-trdhld = <6>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + + i2c_freq_1Mhz_cci3: qcom,i2c-fast-plus-mode { + hw-thigh = <16>; + hw-tlow = <22>; + hw-tsu-sto = <17>; + hw-tsu-sta = <18>; + hw-thd-dat = <16>; + hw-thd-sta = <15>; + hw-tbuf = <24>; + hw-scl-stretch-en = <1>; + hw-trdhld = <3>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + + i2c_freq_100Khz_cci3: qcom,i2c-standard-mode { + hw-thigh = <201>; + hw-tlow = <174>; + hw-tsu-sto = <204>; + hw-tsu-sta = <231>; + hw-thd-dat = <22>; + hw-thd-sta = <162>; + hw-tbuf = <227>; + hw-scl-stretch-en = <0>; + hw-trdhld = <6>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + }; + + cam_csiphy0: qcom,csiphy0@ac9c000 { + compatible = "qcom,csiphy-v1.3.0", "qcom,csiphy"; + reg = <0x0 0x0ac9c000 0x0 0x2000>; + reg-names = "csiphy"; + operating-points-v2 = <&csiphy0_opp_table>; + reg-cam-base = <0x9c000>; + interrupts = ; + interrupt-names = "CSIPHY0"; + csi-vdd-1p2-supply = <&vreg_l1c>; + csi-vdd-0p9-supply = <&vreg_l4a>; + regulator-names = "csi-vdd-1p2", "csi-vdd-0p9"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + rgltr-cntrl-support; + rgltr-min-voltage = <1140000 831000>; + rgltr-max-voltage = <1260000 920000>; + rgltr-load-current = <8900 15900>; + shared-clks = <1 0 0 0>; + clocks = <&camcc CAM_CC_CPHY_RX_CLK_SRC>, + <&camcc CAM_CC_CSIPHY0_CLK>, + <&camcc CAM_CC_CSI0PHYTIMER_CLK_SRC>, + <&camcc CAM_CC_CSI0PHYTIMER_CLK>; + clock-names = "cphy_rx_clk_src", + "csiphy0_clk", + "csi0phytimer_clk_src", + "csi0phytimer_clk"; + src-clock-name = "cphy_rx_clk_src"; + clock-cntl-level = "lowsvs"; + clock-rates = <400000000 0 400000000 0>; + aggregator-rx; + cell-index = <0>; + status = "ok"; + + csiphy0_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-400000000 { + opp-hz = /bits/ 64 <400000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + }; + }; + + cam_csiphy1: qcom,csiphy1@ac9e000 { + compatible = "qcom,csiphy-v1.3.0", "qcom,csiphy"; + reg = <0x0 0xac9e000 0x0 0x2000>; + reg-names = "csiphy"; + operating-points-v2 = <&csiphy1_opp_table>; + reg-cam-base = <0x9e000>; + interrupts = ; + interrupt-names = "CSIPHY1"; + csi-vdd-1p2-supply = <&vreg_l1c>; + csi-vdd-0p9-supply = <&vreg_l4a>; + regulator-names = "csi-vdd-1p2", "csi-vdd-0p9"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + rgltr-cntrl-support; + rgltr-min-voltage = <1140000 831000>; + rgltr-max-voltage = <1260000 920000>; + rgltr-load-current = <8900 15900>; + shared-clks = <1 0 0 0>; + clocks = <&camcc CAM_CC_CPHY_RX_CLK_SRC>, + <&camcc CAM_CC_CSIPHY1_CLK>, + <&camcc CAM_CC_CSI1PHYTIMER_CLK_SRC>, + <&camcc CAM_CC_CSI1PHYTIMER_CLK>; + clock-names = "cphy_rx_clk_src", + "csiphy1_clk", + "csi1phytimer_clk_src", + "csi1phytimer_clk"; + src-clock-name = "cphy_rx_clk_src"; + clock-cntl-level = "lowsvs"; + clock-rates = <400000000 0 400000000 0>; + cell-index = <1>; + aggregator-rx; + status = "ok"; + + csiphy1_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-400000000 { + opp-hz = /bits/ 64 <400000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + }; + }; + + cam_csiphy2: qcom,csiphy2@aca0000 { + compatible = "qcom,csiphy-v1.3.0", "qcom,csiphy"; + reg = <0x0 0xaca0000 0x0 0x2000>; + reg-names = "csiphy"; + operating-points-v2 = <&csiphy2_opp_table>; + reg-cam-base = <0xa0000>; + interrupts = ; + interrupt-names = "CSIPHY2"; + csi-vdd-1p2-supply = <&vreg_l1c>; + csi-vdd-0p9-supply = <&vreg_l4a>; + regulator-names = "csi-vdd-1p2", "csi-vdd-0p9"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + rgltr-cntrl-support; + rgltr-min-voltage = <1140000 831000>; + rgltr-max-voltage = <1260000 920000>; + rgltr-load-current = <8900 15900>; + shared-clks = <1 0 0 0>; + clocks = <&camcc CAM_CC_CPHY_RX_CLK_SRC>, + <&camcc CAM_CC_CSIPHY2_CLK>, + <&camcc CAM_CC_CSI2PHYTIMER_CLK_SRC>, + <&camcc CAM_CC_CSI2PHYTIMER_CLK>; + clock-names = "cphy_rx_clk_src", + "csiphy2_clk", + "csi2phytimer_clk_src", + "csi2phytimer_clk"; + src-clock-name = "cphy_rx_clk_src"; + clock-cntl-level = "lowsvs"; + clock-rates = <400000000 0 400000000 0>; + cell-index = <2>; + aggregator-rx; + status = "ok"; + + csiphy2_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-400000000 { + opp-hz = /bits/ 64 <400000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + }; + }; + + cam_csiphy3: qcom,csiphy3@aca2000 { + compatible = "qcom,csiphy-v1.3.0", "qcom,csiphy"; + reg = <0x0 0xaca2000 0x0 0x2000>; + reg-names = "csiphy"; + operating-points-v2 = <&csiphy3_opp_table>; + reg-cam-base = <0xa2000>; + interrupts = ; + interrupt-names = "CSIPHY3"; + csi-vdd-1p2-supply = <&vreg_l1c>; + csi-vdd-0p9-supply = <&vreg_l4a>; + regulator-names = "csi-vdd-1p2", "csi-vdd-0p9"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + rgltr-cntrl-support; + rgltr-min-voltage = <1140000 831000>; + rgltr-max-voltage = <1260000 920000>; + rgltr-load-current = <8900 15900>; + shared-clks = <1 0 0 0>; + clocks = <&camcc CAM_CC_CPHY_RX_CLK_SRC>, + <&camcc CAM_CC_CSIPHY3_CLK>, + <&camcc CAM_CC_CSI3PHYTIMER_CLK_SRC>, + <&camcc CAM_CC_CSI3PHYTIMER_CLK>; + clock-names = "cphy_rx_clk_src", + "csiphy3_clk", + "csi3phytimer_clk_src", + "csi3phytimer_clk"; + src-clock-name = "cphy_rx_clk_src"; + clock-cntl-level = "lowsvs"; + clock-rates = <400000000 0 400000000 0>; + cell-index = <3>; + aggregator-rx; + status = "ok"; + + csiphy3_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-400000000 { + opp-hz = /bits/ 64 <400000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + }; + }; + + cam_csiphy_tpg17: qcom,tpg17@acac000 { + compatible = "qcom,cam-tpg1031"; + reg = <0x0 0xacac000 0x0 0x400>, + <0x0 0xac11000 0x0 0x1000>; + reg-names = "tpg0", "cam_cpas_top"; + reg-cam-base = <0xac000 0x11000>; + operating-points-v2 = <&csiphy_tpg0_opp_table>; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + interrupts = ; + interrupt-names = "tpg0"; + shared-clks = <1 0>; + clocks = <&camcc CAM_CC_CPHY_RX_CLK_SRC>, + <&camcc CAM_CC_CSID_CSIPHY_RX_CLK>; + clock-names = "cphy_rx_clk_src", + "csid_csiphy_rx_clk"; + clock-rates = <400000000 0>; + clock-cntl-level = "lowsvs"; + src-clock-name = "cphy_rx_clk_src"; + cell-index = <17>; + phy-id = <0>; + status = "ok"; + + csiphy_tpg0_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-400000000 { + opp-hz = /bits/ 64 <400000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + }; + }; + + cam_csiphy_tpg18: qcom,tpg18@acad000 { + compatible = "qcom,cam-tpg1031"; + reg = <0x0 0xacad000 0x0 0x400>, + <0x0 0xac11000 0x0 0x1000>; + reg-names = "tpg1", "cam_cpas_top"; + reg-cam-base = <0xad000 0x11000>; + operating-points-v2 = <&csiphy_tpg1_opp_table>; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + interrupts = ; + interrupt-names = "tpg1"; + shared-clks = <1 0>; + clocks = <&camcc CAM_CC_CPHY_RX_CLK_SRC>, + <&camcc CAM_CC_CSID_CSIPHY_RX_CLK>; + clock-names = "cphy_rx_clk_src", + "csid_csiphy_rx_clk"; + clock-rates = <400000000 0>; + clock-cntl-level = "lowsvs"; + src-clock-name = "cphy_rx_clk_src"; + cell-index = <18>; + phy-id = <1>; + status = "ok"; + + csiphy_tpg1_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-400000000 { + opp-hz = /bits/ 64 <400000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + }; + }; + + cam_csiphy_tpg19: qcom,tpg19@acae000 { + compatible = "qcom,cam-tpg1031"; + reg = <0x0 0xacae000 0x0 0x400>, + <0x0 0xac11000 0x0 0x1000>; + reg-names = "tpg2", "cam_cpas_top"; + reg-cam-base = <0xae000 0x11000>; + operating-points-v2 = <&csiphy_tpg2_opp_table>; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + interrupts = ; + interrupt-names = "tpg2"; + shared-clks = <1 0>; + clocks = <&camcc CAM_CC_CPHY_RX_CLK_SRC>, + <&camcc CAM_CC_CSID_CSIPHY_RX_CLK>; + clock-names = "cphy_rx_clk_src", + "csid_csiphy_rx_clk"; + clock-rates = <400000000 0>; + clock-cntl-level = "lowsvs"; + src-clock-name = "cphy_rx_clk_src"; + cell-index = <19>; + phy-id = <2>; + status = "ok"; + + csiphy_tpg2_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-400000000 { + opp-hz = /bits/ 64 <400000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + }; + }; + + qcom,cam-cdm-intf { + compatible = "qcom,cam-cdm-intf"; + cell-index = <0>; + label = "cam-cdm-intf"; + num-hw-cdm = <1>; + cdm-client-names = "vfe"; + status = "ok"; + }; + + qcom,cam-cpas { + compatible = "qcom,cam-cpas"; + label = "cpas"; + arch-compat = "cpas_top"; + reg = <0x0 0xac11000 0x0 0x1000>, + <0x0 0xac1A000 0x0 0x9400>, + <0x0 0xbbf0000 0x0 0x1f00>; + reg-names = "cam_cpas_top", "cam_camnoc", "cam_rpmh"; + reg-cam-base = <0x11000 0x1A000 0x0bbf0000>; + interrupts = ; + interrupt-names = "cpas_camnoc"; + camnoc-axi-min-ib-bw = <3000000000>; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + clocks = <&gcc GCC_CAMERA_AHB_CLK>, + <&gcc GCC_CAMERA_HF_AXI_CLK>, + <&gcc GCC_CAMERA_SF_AXI_CLK>, + <&camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&camcc CAM_CC_CPAS_AHB_CLK>, + <&camcc CAM_CC_CORE_AHB_CLK>, + <&camcc CAM_CC_FAST_AHB_CLK_SRC>, + <&camcc CAM_CC_CPAS_FAST_AHB_CLK>, + <&camcc CAM_CC_CAMNOC_AXI_CLK_SRC>, + <&camcc CAM_CC_CAMNOC_AXI_CLK>, + <&camcc CAM_CC_QDSS_DEBUG_XO_CLK>; + clock-names = "gcc_camera_ahb_clk", + "gcc_camera_hf_axi_clk", + "gcc_camera_sf_axi_clk", + "cam_cc_slow_ahb_clk_src", + "cam_cc_cpas_ahb_clk", + "cam_cc_core_ahb_clk", + "cam_cc_fast_ahb_clk_src", + "cam_cc_cpas_fast_ahb_clk", + "cam_cc_camnoc_axi_clk_src", + "cam_cc_camnoc_axi_clk", + "cam_cc_qdss_debug_xo_clk"; + src-clock-name = "cam_cc_fast_ahb_clk_src"; + clock-rates = <0 0 0 0 0 0 0 0 0 0 0>, + <0 0 0 80000000 0 0 300000000 0 400000000 0 0>, + <0 0 0 80000000 0 0 400000000 0 400000000 0 0>; + clock-cntl-level = "suspend", "svs_l1", "nominal"; + clock-names-option = "cam_icp_clk"; + clocks-option = <&camcc CAM_CC_ICP_CLK>; + clock-rates-option = <480000000>; + operating-points-v2 = <&cpas_opp_table>; + control-camnoc-axi-clk; + camnoc-bus-width = <32>; + camnoc-axi-clk-bw-margin-perc = <20>; + cam-icc-path-names = "cam_ahb"; + interconnects = <&gem_noc MASTER_APPSS_PROC 0 &config_noc SLAVE_CAMERA_CFG 0>, + <&mmss_noc MASTER_CAMNOC_HF 0 &mc_virt SLAVE_EBI1 0>, + <&mmss_noc MASTER_CAMNOC_SF 0 &mc_virt SLAVE_EBI1 0>, + <&mmss_noc MASTER_CAMNOC_ICP 0 &mc_virt SLAVE_EBI1 0>; + interconnect-names = "cam_ahb", "cam_hf_0", "cam_sf_0", "cam_sf_icp"; + cam-ahb-num-cases = <7>; + cam-ahb-bw-KBps = <0 0>, <0 76800>, <0 150000>, <0 150000>, + <0 300000>, <0 300000>, <0 300000>; + vdd-corners = ; + vdd-corner-ahb-mapping = "suspend", "lowsvs", "lowsvs", "svs", "svs_l1", + "nominal", "nominal", "nominal", "turbo", "turbo"; + client-id-based; + client-names = "csiphy0", "csiphy1", "csiphy2", "csiphy3", + "cci0", "cci1", "cci2", "cci3","csid0", "csid1", + "csid2", "csid3", "csid4", "csid5", "csid6", + "ife0", "ife1", "ife2", "ife3", "ife4", + "ife5", "ife6", "ipe0", "sfe0", "sfe1", + "cam-cdm-intf0", "rt-cdm0", "rt-cdm1", "rt-cdm2", + "rt-cdm3", "icp0", "tpg17", "tpg18", "tpg19"; + + enable-secure-qos-update; + cell-index = <0>; + status = "ok"; + + cpas_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-300000000 { + opp-hz = /bits/ 64 <300000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-400000000 { + opp-hz = /bits/ 64 <400000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + }; + + camera-bus-nodes { + level0-nodes { + level-index = <0>; + + icp_all_rd: icp-all-rd { + cell-index = <0>; + node-name = "icp-all-rd"; + client-name = "icp0"; + traffic-data = ; + traffic-transaction-type = ; + parent-node = <&level2_icp_rd>; + }; + + ife_0_wr_0: ife-0-wr-0 { + cell-index = <1>; + node-name = "ife-0-wr-0"; + client-name = "ife0"; + traffic-data = ; + traffic-transaction-type = ; + constituent-paths = ; + parent-node = <&level1_rt_wr0>; + }; + + ife_0_wr_1: ife-0-wr-1 { + cell-index = <2>; + node-name = "ife-0-wr-1"; + client-name = "ife0"; + traffic-data = ; + traffic-transaction-type = ; + constituent-paths = ; + parent-node = <&level1_rt_wr1>; + }; + + ife_1_wr_0: ife-1-wr-0 { + cell-index = <3>; + node-name = "ife-1-wr-0"; + client-name = "ife1"; + traffic-data = ; + traffic-transaction-type = ; + constituent-paths = ; + parent-node = <&level1_rt_wr0>; + }; + + + ife_1_wr_1: ife-1-wr-1 { + cell-index = <4>; + node-name = "ife-1-wr-1"; + client-name = "ife1"; + traffic-data = ; + traffic-transaction-type = ; + constituent-paths = ; + parent-node = <&level1_rt_wr1>; + }; + + ife_lite_0_wr_0: ife-lite-0-wr-0 { + cell-index = <5>; + node-name = "ife-lite-0-wr-0"; + client-name = "ife2"; + traffic-data = ; + traffic-transaction-type = ; + constituent-paths = ; + parent-node = <&level1_rt_wr0>; + }; + + ife_lite_1_wr_0: ife-lite-1-wr-0 { + cell-index = <6>; + node-name = "ife-lite-1-wr-0"; + client-name = "ife3"; + traffic-data = ; + traffic-transaction-type = ; + constituent-paths = ; + parent-node = <&level1_rt_wr0>; + }; + + ife_lite_2_wr_0: ife-lite-2-wr-0 { + cell-index = <7>; + node-name = "ife-lite-2-wr-0"; + client-name = "ife4"; + traffic-data = ; + traffic-transaction-type = ; + constituent-paths = ; + parent-node = <&level1_rt_wr0>; + }; + + ife_lite_3_wr_0: ife-lite-3-wr-0 { + cell-index = <8>; + node-name = "ife-lite-3-wr-0"; + client-name = "ife5"; + traffic-data = ; + traffic-transaction-type = ; + constituent-paths = ; + parent-node = <&level1_rt_wr0>; + }; + + ife_lite_4_wr_0: ife-lite-4-wr-0 { + cell-index = <9>; + node-name = "ife-lite-4-wr-0"; + client-name = "ife6"; + traffic-data = ; + traffic-transaction-type = ; + constituent-paths = ; + parent-node = <&level1_rt_wr0>; + }; + + ipe_0_rd_all: ipe-0-rd-all { + cell-index = <10>; + node-name = "ipe-0-rd-all"; + client-name = "ipe0"; + traffic-data = ; + traffic-transaction-type = ; + constituent-paths = ; + parent-node = <&level2_nrt_rd1>; + }; + + ipe_0_wr_2: ipe-0-wr-2 { + cell-index = <11>; + node-name = "ipe-0-wr-2"; + client-name = "ipe0"; + traffic-data = ; + traffic-transaction-type = ; + constituent-paths = ; + parent-node = <&level2_nrt_wr2>; + }; + + ipe_cdm0_all_rd: ipe-cdm0-all-rd { + cell-index = <12>; + node-name = "ipe-cdm0-all-rd"; + client-name = "ipe0"; + traffic-data = ; + traffic-transaction-type = ; + parent-node = <&level1_nrt_rd2>; + }; + + rt_cdm0_all_rd_2: rt-cdm0-all-rd-2 { + cell-index = <13>; + node-name = "rt-cdm0-all-rd-2"; + client-name = "rt-cdm0"; + traffic-data = ; + traffic-transaction-type = ; + parent-node = <&level1_nrt_rd2>; + }; + + rt_cdm1_all_rd_2: rt-cdm1-all-rd-2 { + cell-index = <14>; + node-name = "rt-cdm1-all-rd-2"; + client-name = "rt-cdm1"; + traffic-data = ; + traffic-transaction-type = ; + parent-node = <&level1_nrt_rd2>; + }; + + rt_cdm2_all_rd_2: rt-cdm2-all-rd-2 { + cell-index = <15>; + node-name = "rt-cdm2-all-rd-2"; + client-name = "rt-cdm2"; + traffic-data = ; + traffic-transaction-type = + ; + parent-node = <&level1_nrt_rd2>; + }; + + rt_cdm3_all_rd_2: rt-cdm3-all-rd-2 { + cell-index = <16>; + node-name = "rt-cdm3-all-rd-2"; + client-name = "rt-cdm3"; + traffic-data = ; + traffic-transaction-type = ; + parent-node = <&level1_nrt_rd2>; + }; + + sfe_0_rd_0: sfe-0-rd-0 { + cell-index = <17>; + node-name = "sfe-0-rd-0"; + client-name = "sfe0"; + traffic-data = ; + traffic-transaction-type = ; + constituent-paths = ; + parent-node = <&level1_rt_rd0>; + }; + + sfe_1_rd_0: sfe-1-rd-0 { + cell-index = <18>; + node-name = "sfe-1-rd-0"; + client-name = "sfe1"; + traffic-data = ; + traffic-transaction-type = ; + constituent-paths = ; + parent-node = <&level1_rt_rd0>; + }; + }; + + level1-nodes { + level-index = <1>; + camnoc-max-needed; + + level1_nrt_rd2: level1-nrt-rd2 { + cell-index = <19>; + node-name = "level1-nrt-rd2"; + parent-node = <&level2_nrt_rd2>; + traffic-merge-type = ; + }; + + level1_rt_rd0: level1-rt-read0 { + cell-index = <20>; + node-name = "level1-rt-rd0"; + parent-node = <&level2_rt_rd0>; + traffic-merge-type = ; + }; + + level1_rt_wr0: level1-rt-wr0 { + cell-index = <21>; + node-name = "level1-rt-wr0"; + parent-node = <&level2_rt_wr0>; + traffic-merge-type = ; + }; + + level1_rt_wr1: level1-rt-wr1 { + cell-index = <22>; + node-name = "level1-rt-wr1"; + parent-node = <&level2_rt_wr1>; + traffic-merge-type = ; + }; + }; + + level2-nodes { + level-index = <2>; + camnoc-max-needed; + + level2_icp_rd: level2-icp-rd { + cell-index = <23>; + node-name = "level2-icp-rd"; + parent-node = <&level3_nrt1_rd_wr_sum>; + traffic-merge-type = ; + }; + + level2_nrt_rd1: level2-nrt-rd1 { + cell-index = <24>; + node-name = "level2-nrt-rd1"; + parent-node = <&level3_nrt0_rd_wr_sum>; + traffic-merge-type = ; + }; + + level2_nrt_rd2: level2-nrt-rd2 { + cell-index = <25>; + node-name = "level2-nrt-rd2"; + parent-node = <&level3_nrt0_rd_wr_sum>; + traffic-merge-type = ; + }; + + level2_nrt_wr2: level2-nrt-wr2 { + cell-index = <26>; + node-name = "level2-nrt-wr2"; + parent-node = <&level3_nrt0_rd_wr_sum>; + traffic-merge-type = ; + }; + + level2_rt_rd0: level2-rt-read0 { + cell-index = <27>; + node-name = "level2-rt-rd0"; + parent-node = <&level3_rt_rd_wr_sum>; + traffic-merge-type = ; + }; + + level2_rt_wr0: level2-rt-wr0 { + cell-index = <28>; + node-name = "level2-rt-wr0"; + parent-node = <&level3_rt_rd_wr_sum>; + traffic-merge-type = ; + }; + + level2_rt_wr1: level2-rt-wr1 { + cell-index = <29>; + node-name = "level2-rt-wr1"; + parent-node = <&level3_rt_rd_wr_sum>; + traffic-merge-type = ; + }; + }; + + level3-nodes { + level-index = <3>; + + level3_nrt0_rd_wr_sum: level3-nrt0-rd-wr-sum { + cell-index = <30>; + node-name = "level3-nrt0-rd-wr-sum"; + traffic-merge-type = + ; + + qcom,axi-port-mnoc { + cam-icc-path-names = "cam_sf_0"; + }; + }; + + level3_nrt1_rd_wr_sum: level3-nrt1-rd-wr-sum { + cell-index = <31>; + node-name = "level3-nrt1-rd-wr-sum"; + traffic-merge-type = + ; + + qcom,axi-port-mnoc { + cam-icc-path-names = "cam_sf_icp"; + }; + }; + + level3_rt_rd_wr_sum: level3-rt-rd-wr-sum { + cell-index = <32>; + node-name = "level3-rt-rd-wr-sum"; + traffic-merge-type = + ; + ib-bw-voting-needed; + + qcom,axi-port-mnoc { + cam-icc-path-names = "cam_hf_0"; + }; + }; + }; + }; + }; + + qcom,cam-icp { + compatible = "qcom,cam-icp"; + compat-hw-name = "qcom,icp", "qcom,ipe0"; + num-icp = <1>; + num-ipe = <1>; + icp_use_pil; + status = "ok"; + }; + + qcom,cam-i3c-id-table { + i3c-sensor-id-table = <0x1B0 0x0766>; + i3c-eeprom-id-table = <>; + i3c-actuator-id-table = <>; + i3c-ois-id-table = <>; + status = "disabled"; + }; + + qcom,cam-isp { + compatible = "qcom,cam-isp"; + arch-compat = "ife"; + status = "ok"; + }; + + qcom,cam-req-mgr { + compatible = "qcom,cam-req-mgr"; + status = "ok"; + }; + + qcom,cam-sync { + compatible = "qcom,cam-sync"; + status = "ok"; + }; + + qcom,cam-smmu { + compatible = "qcom,msm-cam-smmu", "simple-bus"; + force_cache_allocs; + status = "ok"; + + msm-cam-smmu-cdm { + compatible = "qcom,msm-cam-smmu-cb"; + iommus = <&apps_smmu 0x0860 0x400>, + <&apps_smmu 0x0C60 0x400>; + cam-smmu-label = "rt-cdm"; + dma-coherent; + multiple-client-devices; + + rt_cdm_iova_mem_map: iova-mem-map { + iova-mem-region-io { + /* IO region is approximately 4.0 GB */ + iova-region-name = "io"; + /* 1 MB pad for start */ + iova-region-start = <0x100000>; + /* 1 MB pad for end */ + iova-region-len = <0xffe00000>; + iova-region-id = <0x3>; + status = "ok"; + }; + }; + }; + + msm-cam-smmu-icp { + compatible = "qcom,msm-cam-smmu-cb"; + iommus = <&apps_smmu 0x0800 0x400>, + <&apps_smmu 0x0840 0x480>, + <&apps_smmu 0x08C0 0x480>, + <&apps_smmu 0x0C00 0x400>, + <&apps_smmu 0x0C40 0x480>, + <&apps_smmu 0x0CC0 0x480>; + cam-smmu-label = "icp"; + qcom,iommu-faults = "stall-disable", "non-fatal"; + iova-region-discard = <0xe0000000 0x800000>; + dma-coherent; + + icp_iova_mem_map: iova-mem-map { + iova-mem-region-fwuncached-region { + /* FW uncached region is 7MB long */ + iova-region-name = "fw_uncached"; + iova-region-start = <0x10400000>; + iova-region-len = <0x700000>; + iova-region-id = <0x6>; + subregion_support; + status = "ok"; + + /* Used for HFI queues/sec heap */ + iova-mem-region-generic-region { + iova-region-name = "icp_hfi"; + iova-region-start = <0x10400000>; + iova-region-len = <0x200000>; + iova-region-id = <0x0>; + }; + }; + + iova-mem-region-io { + /* IO region is approximately 3.8 GB */ + iova-region-name = "io"; + iova-region-start = <0x10c00000>; + iova-region-len = <0xee300000>; + iova-region-id = <0x3>; + iova-region-discard = <0xe0000000 0x800000>; + status = "ok"; + }; + + iova-mem-region-qdss { + /* QDSS region is appropriate 1MB */ + iova-region-name = "qdss"; + iova-region-start = <0x10b00000>; + iova-region-len = <0x100000>; + iova-region-id = <0x5>; + qdss-phy-addr = <0x16790000>; + status = "ok"; + }; + + iova-mem-region-shared { + /* Shared region is ~250MB long */ + iova-region-name = "shared"; + iova-region-start = <0x800000>; + iova-region-len = <0xfc00000>; + iova-region-id = <0x1>; + status = "ok"; + }; + }; + }; + + msm-cam-smmu-ife { + compatible = "qcom,msm-cam-smmu-cb"; + iommus = <&apps_smmu 0x3400 0x0020>, + <&apps_smmu 0x3420 0x0020>; + cam-smmu-label = "ife", "sfe"; + multiple-client-devices; + dma-coherent; + + ife_iova_mem_map: iova-mem-map { + /* IO region is approximately 64 GB */ + iova-mem-region-io { + iova-region-name = "io"; + /* start address: 0x100000 */ + /* leaving 1 MB pad at start */ + iova-region-start = <0x100000>; + /* Length: 0xfffe00000 */ + /* leaving 1 MB pad at end */ + iova-region-len = <0xffe00000>; + iova-region-id = <0x3>; + status = "ok"; + }; + }; + }; + + msm-cam-smmu-secure { + compatible = "qcom,msm-cam-smmu-cb"; + cam-smmu-label = "cam-secure"; + qcom,secure-cb; + }; + }; + + qcom,camera-main { + compatible = "qcom,camera"; + status = "ok"; + }; + + cam_csid0: qcom,csid0 { + compatible = "qcom,csid690"; + reg = <0x0 0xac7a000 0x0 0xf01>, + <0x0 0xac78000 0x0 0x1000>; + reg-names = "csid0", "csid_top"; + reg-cam-base = <0x7a000 0x78000>; + rt-wrapper-base = <0x4d000>; + interrupts = ; + interrupt-names = "csid0"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + clocks = <&camcc CAM_CC_CSID_CLK_SRC>, + <&camcc CAM_CC_CSID_CLK>, + <&camcc CAM_CC_CSID_CSIPHY_RX_CLK>; + clock-names = "cam_cc_csid_clk_src", + "cam_cc_csid_clk", + "cam_cc_csid_csiphy_rx_clk"; + clock-rates = <400000000 0 0>; + clock-cntl-level = "svs_l1"; + src-clock-name = "cam_cc_csid_clk_src"; + operating-points-v2 = <&csid0_opp_table>; + clock-control-debugfs = "true"; + cell-index = <0>; + status = "ok"; + + csid0_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-400000000 { + opp-hz = /bits/ 64 <400000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + }; + }; + + cam_csid1: qcom,csid1 { + compatible = "qcom,csid690"; + reg = <0x0 0xac7c000 0x0 0xf01>, + <0x0 0xac78000 0x0 0x1000>; + reg-names = "csid1", "csid_top"; + reg-cam-base = <0x7c000 0x78000>; + rt-wrapper-base = <0x4d000>; + interrupts = ; + interrupt-names = "csid0"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + clocks = <&camcc CAM_CC_CSID_CLK_SRC>, + <&camcc CAM_CC_CSID_CLK>, + <&camcc CAM_CC_CSID_CSIPHY_RX_CLK>; + clock-names = "cam_cc_csid_clk_src", + "cam_cc_csid_clk", + "cam_cc_csid_csiphy_rx_clk"; + clock-rates = <400000000 0 0>; + clock-cntl-level = "svs_l1"; + src-clock-name = "cam_cc_csid_clk_src"; + operating-points-v2 = <&csid1_opp_table>; + clock-control-debugfs = "true"; + cell-index = <1>; + status = "ok"; + + csid1_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-400000000 { + opp-hz = /bits/ 64 <400000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + }; + }; + + cam_csid_lite0: qcom,csid-lite0 { + compatible = "qcom,csid-lite690"; + reg = <0x0 0xac84000 0x0 0xf01>; + reg-names = "csid-lite0"; + reg-cam-base = <0x84000>; + rt-wrapper-base = <0x83000>; + interrupts = ; + interrupt-names = "csid-lite0"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + clocks = <&camcc CAM_CC_CPAS_IFE_LITE_CLK>, + <&camcc CAM_CC_IFE_LITE_AHB_CLK>, + <&camcc CAM_CC_IFE_LITE_CSID_CLK_SRC>, + <&camcc CAM_CC_IFE_LITE_CSID_CLK>, + <&camcc CAM_CC_IFE_LITE_CPHY_RX_CLK>, + <&camcc CAM_CC_IFE_LITE_CLK_SRC>, + <&camcc CAM_CC_IFE_LITE_CLK>; + clock-names = "cam_cc_cpas_ife_lite_clk", + "cam_cc_ife_lite_ahb_clk", + "cam_cc_ife_lite_csid_clk_src", + "cam_cc_ife_lite_csid_clk", + "cam_cc_ife_lite_cphy_rx_clk", + "cam_cc_ife_lite_clk_src", + "cam_cc_ife_lite_clk"; + clock-rates = <0 0 400000000 0 0 400000000 0>, + <0 0 400000000 0 0 480000000 0>; + clock-cntl-level = "svs_l1", "nominal"; + src-clock-name = "cam_cc_ife_lite_csid_clk_src"; + operating-points-v2 = <&csid_lite0_opp_table>; + clock-control-debugfs = "true"; + cell-index = <2>; + status = "ok"; + + csid_lite0_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-400000000 { + opp-hz = /bits/ 64 <400000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-480000000 { + opp-hz = /bits/ 64 <480000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + }; + }; + + cam_csid_lite1: qcom,csid-lite1 { + compatible = "qcom,csid-lite690"; + reg = <0x0 0xac88000 0x0 0xf01>; + reg-names = "csid-lite1"; + reg-cam-base = <0x88000>; + rt-wrapper-base = <0x83000>; + interrupts = ; + interrupt-names = "csid-lite1"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + clocks = <&camcc CAM_CC_CPAS_IFE_LITE_CLK>, + <&camcc CAM_CC_IFE_LITE_AHB_CLK>, + <&camcc CAM_CC_IFE_LITE_CSID_CLK_SRC>, + <&camcc CAM_CC_IFE_LITE_CSID_CLK>, + <&camcc CAM_CC_IFE_LITE_CPHY_RX_CLK>, + <&camcc CAM_CC_IFE_LITE_CLK_SRC>, + <&camcc CAM_CC_IFE_LITE_CLK>; + clock-names = "cam_cc_cpas_ife_lite_clk", + "cam_cc_ife_lite_ahb_clk", + "cam_cc_ife_lite_csid_clk_src", + "cam_cc_ife_lite_csid_clk", + "cam_cc_ife_lite_cphy_rx_clk", + "cam_cc_ife_lite_clk_src", + "cam_cc_ife_lite_clk"; + clock-rates = <0 0 400000000 0 0 400000000 0>, + <0 0 400000000 0 0 480000000 0>; + clock-cntl-level = "svs_l1", "nominal"; + src-clock-name = "cam_cc_ife_lite_csid_clk_src"; + operating-points-v2 = <&csid_lite1_opp_table>; + clock-control-debugfs = "true"; + cell-index = <3>; + status = "ok"; + + csid_lite1_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-400000000 { + opp-hz = /bits/ 64 <400000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-480000000 { + opp-hz = /bits/ 64 <480000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + }; + }; + + cam_csid_lite2: qcom,csid-lite2 { + compatible = "qcom,csid-lite690"; + reg = <0x0 0xac8c000 0x0 0xf01>; + reg-names = "csid-lite2"; + reg-cam-base = <0x8c000>; + rt-wrapper-base = <0x83000>; + interrupts = ; + interrupt-names = "csid-lite2"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + clocks = <&camcc CAM_CC_CPAS_IFE_LITE_CLK>, + <&camcc CAM_CC_IFE_LITE_AHB_CLK>, + <&camcc CAM_CC_IFE_LITE_CSID_CLK_SRC>, + <&camcc CAM_CC_IFE_LITE_CSID_CLK>, + <&camcc CAM_CC_IFE_LITE_CPHY_RX_CLK>, + <&camcc CAM_CC_IFE_LITE_CLK_SRC>, + <&camcc CAM_CC_IFE_LITE_CLK>; + clock-names = "cam_cc_cpas_ife_lite_clk", + "cam_cc_ife_lite_ahb_clk", + "cam_cc_ife_lite_csid_clk_src", + "cam_cc_ife_lite_csid_clk", + "cam_cc_ife_lite_cphy_rx_clk", + "cam_cc_ife_lite_clk_src", + "cam_cc_ife_lite_clk"; + clock-rates = <0 0 400000000 0 0 400000000 0>, + <0 0 400000000 0 0 480000000 0>; + clock-cntl-level = "svs_l1", "nominal"; + src-clock-name = "cam_cc_ife_lite_csid_clk_src"; + operating-points-v2 = <&csid_lite2_opp_table>; + clock-control-debugfs = "true"; + cell-index = <4>; + status = "ok"; + + csid_lite2_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-400000000 { + opp-hz = /bits/ 64 <400000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-480000000 { + opp-hz = /bits/ 64 <480000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + }; + }; + + cam_csid_lite3: qcom,csid-lite3 { + compatible = "qcom,csid-lite690"; + reg = <0x0 0xac90000 0x0 0xf01>; + reg-names = "csid-lite3"; + reg-cam-base = <0x90000>; + rt-wrapper-base = <0x83000>; + interrupts = ; + interrupt-names = "csid-lite3"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + clocks = <&camcc CAM_CC_CPAS_IFE_LITE_CLK>, + <&camcc CAM_CC_IFE_LITE_AHB_CLK>, + <&camcc CAM_CC_IFE_LITE_CSID_CLK_SRC>, + <&camcc CAM_CC_IFE_LITE_CSID_CLK>, + <&camcc CAM_CC_IFE_LITE_CPHY_RX_CLK>, + <&camcc CAM_CC_IFE_LITE_CLK_SRC>, + <&camcc CAM_CC_IFE_LITE_CLK>; + clock-names = "cam_cc_cpas_ife_lite_clk", + "cam_cc_ife_lite_ahb_clk", + "cam_cc_ife_lite_csid_clk_src", + "cam_cc_ife_lite_csid_clk", + "cam_cc_ife_lite_cphy_rx_clk", + "cam_cc_ife_lite_clk_src", + "cam_cc_ife_lite_clk"; + clock-rates = <0 0 400000000 0 0 400000000 0>, + <0 0 400000000 0 0 480000000 0>; + clock-cntl-level = "svs_l1", "nominal"; + src-clock-name = "cam_cc_ife_lite_csid_clk_src"; + operating-points-v2 = <&csid_lite3_opp_table>; + clock-control-debugfs = "true"; + cell-index = <5>; + status = "ok"; + + csid_lite3_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-400000000 { + opp-hz = /bits/ 64 <400000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-480000000 { + opp-hz = /bits/ 64 <480000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + }; + }; + + cam_csid_lite4: qcom,csid-lite4 { + compatible = "qcom,csid-lite690"; + reg = <0x0 0xac94000 0x0 0xf01>; + reg-names = "csid-lite4"; + reg-cam-base = <0x94000>; + rt-wrapper-base = <0x83000>; + interrupts = ; + interrupt-names = "csid-lite4"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + clock-names = "cam_cc_cpas_ife_lite_clk", + "cam_cc_ife_lite_ahb_clk", + "cam_cc_ife_lite_csid_clk_src", + "cam_cc_ife_lite_csid_clk", + "cam_cc_ife_lite_cphy_rx_clk", + "cam_cc_ife_lite_clk_src", + "cam_cc_ife_lite_clk"; + clocks = <&camcc CAM_CC_CPAS_IFE_LITE_CLK>, + <&camcc CAM_CC_IFE_LITE_AHB_CLK>, + <&camcc CAM_CC_IFE_LITE_CSID_CLK_SRC>, + <&camcc CAM_CC_IFE_LITE_CSID_CLK>, + <&camcc CAM_CC_IFE_LITE_CPHY_RX_CLK>, + <&camcc CAM_CC_IFE_LITE_CLK_SRC>, + <&camcc CAM_CC_IFE_LITE_CLK>; + clock-rates = <0 0 400000000 0 0 400000000 0>, + <0 0 400000000 0 0 480000000 0>; + clock-cntl-level = "svs_l1", "nominal"; + src-clock-name = "cam_cc_ife_lite_csid_clk_src"; + operating-points-v2 = <&csid_lite4_opp_table>; + clock-control-debugfs = "true"; + cell-index = <6>; + status = "ok"; + + csid_lite4_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-400000000 { + opp-hz = /bits/ 64 <400000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-480000000 { + opp-hz = /bits/ 64 <480000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + }; + }; + + cam_icp: qcom,icp { + compatible = "qcom,cam-icp_v3_0"; + reg = <0x0 0xac01000 0x0 0x400>, + <0x0 0xac01800 0x0 0x400>, + <0x0 0xac04000 0x0 0x1000>; + reg-names ="icp_csr", "icp_cirq", "icp_wd0"; + reg-cam-base = <0x1000 0x1800 0x4000>; + interrupts = ; + interrupt-names = "icp"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + memory-region = <&pil_camera_mem>; + src-clock-name = "cam_cc_icp_clk_src"; + clocks = <&camcc CAM_CC_FAST_AHB_CLK_SRC>, + <&camcc CAM_CC_ICP_AHB_CLK>, + <&camcc CAM_CC_ICP_CLK_SRC>, + <&camcc CAM_CC_ICP_CLK>; + clock-names = "cam_cc_soc_fast_ahb_clk_src", + "cam_cc_icp_ahb_clk", + "cam_cc_icp_clk_src", + "cam_cc_icp_clk"; + clock-rates = <300000000 0 480000000 0>, + <400000000 0 600000000 0>; + clock-cntl-level = "svs_l1", "nominal"; + nrt-device; + fw_name = "CAMERA_ICP"; + ubwc-ipe-fetch-cfg = <0x707b 0x7083>; + ubwc-ipe-write-cfg = <0x161ef 0x1620f>; + qos-val = <0xa0a>; + operating-points-v2 = <&icp_opp_table>; + icp-version = <0x0300>; + cam_hw_pid = <12>; + cell-index = <0>; + status = "ok"; + + icp_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-480000000 { + opp-hz = /bits/ 64 <480000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-600000000 { + opp-hz = /bits/ 64 <600000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + }; + }; + + cam_vfe0: qcom,ife0 { + compatible = "qcom,vfe690"; + reg = <0x0 0xac4d000 0x0 0xd000>, + <0x0 0xac1a000 0x0 0x9400>; + reg-names = "ife0", "cam_camnoc"; + reg-cam-base = <0x4d000 0x1a000>; + rt-wrapper-base = <0x4d000>; + interrupts = ; + interrupt-names = "ife0"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + clocks = <&camcc CAM_CC_CPAS_IFE_0_CLK>, + <&camcc CAM_CC_IFE_0_CLK>, + <&camcc CAM_CC_IFE_0_CLK_SRC>, + <&camcc CAM_CC_IFE_0_FAST_AHB_CLK>; + clock-names = "cam_cc_cpas_ife_0_clk", + "cam_cc_ife_0_clk", + "cam_cc_ife_0_clk_src", + "cam_cc_ife_0_fast_ahb_clk"; + clock-rates = <0 0 480000000 0>, + <0 0 600000000 0>; + clock-cntl-level = "svs_l1", "nominal"; + src-clock-name = "cam_cc_ife_0_clk_src"; + operating-points-v2 = <&vfe0_opp_table>; + clock-control-debugfs = "true"; + ubwc-static-cfg = <0x1026 0x1036>; + cam_hw_pid = <8 16>; + cell-index = <0>; + status = "ok"; + + vfe0_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-480000000 { + opp-hz = /bits/ 64 <480000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-600000000 { + opp-hz = /bits/ 64 <600000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + }; + }; + + cam_vfe1: qcom,ife1 { + compatible = "qcom,vfe690"; + reg = <0x0 0xac5a000 0x0 0xd000>, + <0x0 0xac1a000 0x0 0x9400>; + reg-names = "ife1", "cam_camnoc"; + reg-cam-base = <0x5a000 0x1a000>; + rt-wrapper-base = <0x4d000>; + interrupts = ; + interrupt-names = "ife1"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + clocks = <&camcc CAM_CC_CPAS_IFE_1_CLK>, + <&camcc CAM_CC_IFE_1_CLK>, + <&camcc CAM_CC_IFE_1_CLK_SRC>, + <&camcc CAM_CC_IFE_1_FAST_AHB_CLK>; + clock-names = "cam_cc_cpas_ife_1_clk", + "cam_cc_ife_1_clk", + "cam_cc_ife_1_clk_src", + "cam_cc_ife_1_fast_ahb_clk"; + clock-rates = <0 0 480000000 0>, + <0 0 600000000 0>; + clock-cntl-level = "svs_l1", "nominal"; + src-clock-name = "cam_cc_ife_1_clk_src"; + operating-points-v2 = <&vfe1_opp_table>; + clock-control-debugfs = "true"; + ubwc-static-cfg = <0x1026 0x1036>; + cam_hw_pid = <9 17>; + cell-index = <1>; + status = "ok"; + + vfe1_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-480000000 { + opp-hz = /bits/ 64 <480000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-600000000 { + opp-hz = /bits/ 64 <600000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + }; + }; + + cam_vfe_lite0: qcom,ife-lite0 { + compatible = "qcom,vfe-lite690"; + reg = <0x0 0xac84000 0x0 0x1d00>; + reg-names = "ife-lite0"; + reg-cam-base = <0x84000>; + rt-wrapper-base = <0x83000>; + interrupts = ; + interrupt-names = "ife-lite0"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + clocks = <&camcc CAM_CC_CPAS_IFE_LITE_CLK>, + <&camcc CAM_CC_IFE_LITE_AHB_CLK>, + <&camcc CAM_CC_IFE_LITE_CSID_CLK_SRC>, + <&camcc CAM_CC_IFE_LITE_CSID_CLK>, + <&camcc CAM_CC_IFE_LITE_CPHY_RX_CLK>, + <&camcc CAM_CC_IFE_LITE_CLK_SRC>, + <&camcc CAM_CC_IFE_LITE_CLK>; + clock-names = "cam_cc_cpas_ife_lite_clk", + "cam_cc_ife_lite_ahb_clk", + "cam_cc_ife_lite_csid_clk_src", + "cam_cc_ife_lite_csid_clk", + "cam_cc_ife_lite_cphy_rx_clk", + "cam_cc_ife_lite_clk_src", + "cam_cc_ife_lite_clk"; + clock-rates = <0 0 400000000 0 0 400000000 0>, + <0 0 400000000 0 0 480000000 0>; + clock-cntl-level = "svs_l1", "nominal"; + src-clock-name = "cam_cc_ife_lite_clk_src"; + operating-points-v2 = <&vfe_lite0_opp_table>; + clock-control-debugfs = "true"; + cam_hw_pid = <27>; + cell-index = <2>; + status = "ok"; + + vfe_lite0_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-400000000 { + opp-hz = /bits/ 64 <400000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-480000000 { + opp-hz = /bits/ 64 <480000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + }; + }; + + cam_vfe_lite1: qcom,ife-lite1 { + compatible = "qcom,vfe-lite690"; + reg = <0x0 0xac88000 0x0 0x1d00>; + reg-names = "ife-lite1"; + reg-cam-base = <0x88000>; + rt-wrapper-base = <0x83000>; + interrupts = ; + interrupt-names = "ife-lite1"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + clocks = <&camcc CAM_CC_CPAS_IFE_LITE_CLK>, + <&camcc CAM_CC_IFE_LITE_AHB_CLK>, + <&camcc CAM_CC_IFE_LITE_CSID_CLK_SRC>, + <&camcc CAM_CC_IFE_LITE_CSID_CLK>, + <&camcc CAM_CC_IFE_LITE_CPHY_RX_CLK>, + <&camcc CAM_CC_IFE_LITE_CLK_SRC>, + <&camcc CAM_CC_IFE_LITE_CLK>; + clock-names = "cam_cc_cpas_ife_lite_clk", + "cam_cc_ife_lite_ahb_clk", + "cam_cc_ife_lite_csid_clk_src", + "cam_cc_ife_lite_csid_clk", + "cam_cc_ife_lite_cphy_rx_clk", + "cam_cc_ife_lite_clk_src", + "cam_cc_ife_lite_clk"; + clock-rates = <0 0 400000000 0 0 400000000 0>, + <0 0 400000000 0 0 480000000 0>; + clock-cntl-level = "svs_l1", "nominal"; + src-clock-name = "cam_cc_ife_lite_clk_src"; + operating-points-v2 = <&vfe_lite1_opp_table>; + clock-control-debugfs = "true"; + cam_hw_pid = <27>; + cell-index = <3>; + status = "ok"; + + vfe_lite1_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-400000000 { + opp-hz = /bits/ 64 <400000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-480000000 { + opp-hz = /bits/ 64 <480000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + }; + }; + + cam_vfe_lite2: qcom,ife-lite2 { + compatible = "qcom,vfe-lite690"; + reg = <0x0 0xac8c000 0x0 0x1d00>; + reg-names = "ife-lite2"; + reg-cam-base = <0x8c000>; + rt-wrapper-base = <0x83000>; + interrupts = ; + interrupt-names = "ife-lite2"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + clocks = <&camcc CAM_CC_CPAS_IFE_LITE_CLK>, + <&camcc CAM_CC_IFE_LITE_AHB_CLK>, + <&camcc CAM_CC_IFE_LITE_CSID_CLK_SRC>, + <&camcc CAM_CC_IFE_LITE_CSID_CLK>, + <&camcc CAM_CC_IFE_LITE_CPHY_RX_CLK>, + <&camcc CAM_CC_IFE_LITE_CLK_SRC>, + <&camcc CAM_CC_IFE_LITE_CLK>; + clock-names = "cam_cc_cpas_ife_lite_clk", + "cam_cc_ife_lite_ahb_clk", + "cam_cc_ife_lite_csid_clk_src", + "cam_cc_ife_lite_csid_clk", + "cam_cc_ife_lite_cphy_rx_clk", + "cam_cc_ife_lite_clk_src", + "cam_cc_ife_lite_clk"; + clock-rates = <0 0 400000000 0 0 400000000 0>, + <0 0 400000000 0 0 480000000 0>; + clock-cntl-level = "svs_l1", "nominal"; + src-clock-name = "cam_cc_ife_lite_clk_src"; + operating-points-v2 = <&vfe_lite2_opp_table>; + clock-control-debugfs = "true"; + cam_hw_pid = <27>; + cell-index = <4>; + status = "ok"; + + vfe_lite2_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-400000000 { + opp-hz = /bits/ 64 <400000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-480000000 { + opp-hz = /bits/ 64 <480000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + }; + }; + + cam_vfe_lite3: qcom,ife-lite3 { + compatible = "qcom,vfe-lite690"; + reg = <0x0 0xac90000 0x0 0x1d00>; + reg-names = "ife-lite3"; + reg-cam-base = <0x90000>; + rt-wrapper-base = <0x83000>; + interrupts = ; + interrupt-names = "ife-lite3"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + clocks = <&camcc CAM_CC_CPAS_IFE_LITE_CLK>, + <&camcc CAM_CC_IFE_LITE_AHB_CLK>, + <&camcc CAM_CC_IFE_LITE_CSID_CLK_SRC>, + <&camcc CAM_CC_IFE_LITE_CSID_CLK>, + <&camcc CAM_CC_IFE_LITE_CPHY_RX_CLK>, + <&camcc CAM_CC_IFE_LITE_CLK_SRC>, + <&camcc CAM_CC_IFE_LITE_CLK>; + clock-names = "cam_cc_cpas_ife_lite_clk", + "cam_cc_ife_lite_ahb_clk", + "cam_cc_ife_lite_csid_clk_src", + "cam_cc_ife_lite_csid_clk", + "cam_cc_ife_lite_cphy_rx_clk", + "cam_cc_ife_lite_clk_src", + "cam_cc_ife_lite_clk"; + clock-rates = <0 0 400000000 0 0 400000000 0>, + <0 0 400000000 0 0 480000000 0>; + clock-cntl-level = "svs_l1", "nominal"; + src-clock-name = "cam_cc_ife_lite_clk_src"; + operating-points-v2 = <&vfe_lite3_opp_table>; + clock-control-debugfs = "true"; + cam_hw_pid = <27>; + cell-index = <5>; + status = "ok"; + + vfe_lite3_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-400000000 { + opp-hz = /bits/ 64 <400000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-480000000 { + opp-hz = /bits/ 64 <480000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + }; + }; + + cam_vfe_lite4: qcom,ife-lite4 { + compatible = "qcom,vfe-lite690"; + reg = <0x0 0xac94000 0x0 0x1d00>; + reg-names = "ife-lite4"; + reg-cam-base = <0x94000>; + rt-wrapper-base = <0x83000>; + interrupts = ; + interrupt-names = "ife-lite4"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + clocks = <&camcc CAM_CC_CPAS_IFE_LITE_CLK>, + <&camcc CAM_CC_IFE_LITE_AHB_CLK>, + <&camcc CAM_CC_IFE_LITE_CSID_CLK_SRC>, + <&camcc CAM_CC_IFE_LITE_CSID_CLK>, + <&camcc CAM_CC_IFE_LITE_CPHY_RX_CLK>, + <&camcc CAM_CC_IFE_LITE_CLK_SRC>, + <&camcc CAM_CC_IFE_LITE_CLK>; + clock-names = "cam_cc_cpas_ife_lite_clk", + "cam_cc_ife_lite_ahb_clk", + "cam_cc_ife_lite_csid_clk_src", + "cam_cc_ife_lite_csid_clk", + "cam_cc_ife_lite_cphy_rx_clk", + "cam_cc_ife_lite_clk_src", + "cam_cc_ife_lite_clk"; + clock-rates = <0 0 400000000 0 0 400000000 0>, + <0 0 400000000 0 0 480000000 0>; + clock-cntl-level = "svs_l1", "nominal"; + src-clock-name = "cam_cc_ife_lite_clk_src"; + operating-points-v2 = <&vfe_lite4_opp_table>; + clock-control-debugfs = "true"; + cam_hw_pid = <27>; + cell-index = <6>; + status = "ok"; + + vfe_lite4_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-400000000 { + opp-hz = /bits/ 64 <400000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-480000000 { + opp-hz = /bits/ 64 <480000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + }; + }; + + cam_ipe0: qcom,ipe0 { + compatible = "qcom,cam-ipe"; + reg = <0x0 0xac2d000 0x0 0x18000>; + reg-names = "ipe0_top"; + reg-cam-base = <0x2d000>; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + src-clock-name = "cam_cc_ipe_clk_src"; + clocks = <&camcc CAM_CC_CPAS_IPE_CLK>, + <&camcc CAM_CC_IPE_AHB_CLK>, + <&camcc CAM_CC_IPE_CLK>, + <&camcc CAM_CC_IPE_CLK_SRC>, + <&camcc CAM_CC_IPE_FAST_AHB_CLK>, + <&camcc CAM_CC_FAST_AHB_CLK_SRC>; + clock-names = "cam_cc_cpas_ipe_clk", + "cam_cc_ipe_ahb_clk", + "cam_cc_ipe_clk", + "cam_cc_ipe_clk_src", + "cam_cc_ipe_fast_ahb_clk", + "cam_cc_fast_ahb_clk_src"; + clock-rates = <0 0 0 480000000 0 300000000>, + <0 0 0 600000000 0 400000000>; + clock-cntl-level = "svs_l1", "nominal"; + operating-points-v2 = <&ipe0_opp_table>; + nrt-device; + cam_hw_pid = <14 15>; + cell-index = <0>; + status = "ok"; + + ipe0_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-480000000 { + opp-hz = /bits/ 64 <480000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-600000000 { + opp-hz = /bits/ 64 <600000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + }; + + }; + + qcom,rt-cdm0 { + compatible = "qcom,cam-rt-cdm2_1"; + label = "rt-cdm"; + reg = <0x0 0xac26000 0x0 0x1000>; + reg-names = "rt-cdm0"; + reg-cam-base = <0x26000>; + interrupts = ; + interrupt-names = "rt-cdm0"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + clocks = <&camcc CAM_CC_FAST_AHB_CLK_SRC>, + <&camcc CAM_CC_CPAS_AHB_CLK>; + clock-names = "cam_cc_fast_ahb_clk_src", + "cam_cc_cpas_ahb_clk"; + src-clock-name = "cam_cc_fast_ahb_clk_src"; + clock-rates = <300000000 0>; + operating-points-v2 = <&cdm_cpas_opp_table0>; + clock-cntl-level = "svs"; + cdm-client-names = "ife0", "dualife0"; + single-context-cdm; + cell-index = <0>; + status = "ok"; + + cdm_cpas_opp_table0: opp-table { + compatible = "operating-points-v2"; + + opp-300000000 { + opp-hz = /bits/ 64 <300000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + }; + }; + + qcom,rt-cdm1 { + compatible = "qcom,cam-rt-cdm2_1"; + label = "rt-cdm"; + reg = <0x0 0xac27000 0x0 0x1000>; + reg-names = "rt-cdm1"; + reg-cam-base = <0x27000>; + interrupts = ; + interrupt-names = "rt-cdm1"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + clocks = <&camcc CAM_CC_FAST_AHB_CLK_SRC>, + <&camcc CAM_CC_CPAS_AHB_CLK>; + clock-names = "cam_cc_fast_ahb_clk_src", + "cam_cc_cpas_ahb_clk"; + src-clock-name = "cam_cc_fast_ahb_clk_src"; + clock-rates = <300000000 0>; + operating-points-v2 = <&cdm_cpas_opp_table1>; + clock-cntl-level = "svs_l1"; + cdm-client-names = "ife1", "dualife1"; + single-context-cdm; + cell-index = <1>; + status = "ok"; + + cdm_cpas_opp_table1: opp-table { + compatible = "operating-points-v2"; + + opp-300000000 { + opp-hz = /bits/ 64 <300000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + }; + }; + + qcom,rt-cdm2 { + compatible = "qcom,cam-rt-cdm2_1"; + label = "rt-cdm"; + reg = <0x0 0xac28000 0x0 0x1000>; + reg-names = "rt-cdm2"; + reg-cam-base = <0x28000>; + interrupts = ; + interrupt-names = "rt-cdm2"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + clocks = <&camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&camcc CAM_CC_CPAS_AHB_CLK>; + clock-names = "cam_cc_slow_ahb_clk_src", + "cam_cc_cpas_ahb_clk"; + src-clock-name = "cam_cc_slow_ahb_clk_src"; + clock-rates = <80000000 0>; + operating-points-v2 = <&cdm_cpas_opp_table2>; + clock-cntl-level = "svs_l1"; + cdm-client-names = "ife2", "ife3", "ife4", "ife5", "ife6"; + single-context-cdm; + cell-index = <2>; + status = "ok"; + + cdm_cpas_opp_table2: opp-table { + compatible = "operating-points-v2"; + + opp-80000000 { + opp-hz = /bits/ 64 <80000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + }; + }; + + qcom,rt-cdm3 { + compatible = "qcom,cam-rt-cdm2_1"; + label = "rt-cdm"; + reg = <0x0 0xac29000 0x0 0x1000>; + reg-names = "rt-cdm3"; + reg-cam-base = <0x29000>; + interrupts = ; + interrupt-names = "rt-cdm3"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + clocks = <&camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&camcc CAM_CC_CPAS_AHB_CLK>; + clock-names = "cam_cc_slow_ahb_clk_src", + "cam_cc_cpas_ahb_clk"; + src-clock-name = "cam_cc_slow_ahb_clk_src"; + clock-rates = <80000000 0>; + operating-points-v2 = <&cdm_cpas_opp_table3>; + clock-cntl-level = "svs"; + cdm-client-names = "ife2", "ife3", "ife4", "ife5", "ife6"; + single-context-cdm; + cell-index = <3>; + status = "ok"; + + cdm_cpas_opp_table3: opp-table { + compatible = "operating-points-v2"; + + opp-80000000 { + opp-hz = /bits/ 64 <80000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + }; + }; + + cam_sfe_lite0: qcom,sfe-lite0 { + compatible = "qcom,sfe-lite690"; + reg = <0x0 0xac74000 0x0 0x1000>; + reg-names = "sfe-lite0"; + reg-cam-base = <0x74000>; + rt-wrapper-base = <0x4d000>; + interrupts = ; + interrupt-names = "sfe-lite0"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + clock-names = "cam_cc_sfe_lite_0_fast_ahb_clk", + "cam_cc_sfe_lite_0_clk", + "cam_cc_cpas_sfe_lite_0_clk"; + clocks = <&camcc CAM_CC_SFE_LITE_0_FAST_AHB_CLK>, + <&camcc CAM_CC_SFE_LITE_0_CLK>, + <&camcc CAM_CC_CPAS_SFE_LITE_0_CLK>; + clock-rates = <0 480000000 300000000>, + <0 600000000 400000000>; + clock-cntl-level = "svs_l1", "nominal"; + src-clock-name = "cam_cc_sfe_lite_0_clk"; + operating-points-v2 = <&cam_sfe_lite_opp_table0>; + cam_hw_pid = <4>; + clock-control-debugfs = "true"; + cell-index = <0>; + status = "ok"; + + cam_sfe_lite_opp_table0: opp-table { + compatible = "operating-points-v2"; + + opp-480000000 { + opp-hz = /bits/ 64 <480000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-600000000 { + opp-hz = /bits/ 64 <600000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + }; + }; + + cam_sfe_lite1: qcom,sfe-lite1 { + compatible = "qcom,sfe-lite690"; + reg = <0x0 0xac75000 0x0 0x1000>; + reg-names = "sfe-lite1"; + reg-cam-base = <0x75000>; + rt-wrapper-base = <0x4d000>; + interrupts = ; + interrupt-names = "sfe-lite1"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + clocks = <&camcc CAM_CC_SFE_LITE_1_FAST_AHB_CLK>, + <&camcc CAM_CC_SFE_LITE_1_CLK>, + <&camcc CAM_CC_CPAS_SFE_LITE_1_CLK>; + clock-names = "cam_cc_sfe_lite_1_fast_ahb_clk", + "cam_cc_sfe_lite_1_clk", + "cam_cc_cpas_sfe_1_clk"; + clock-rates = <0 480000000 300000000>, + <0 600000000 400000000>; + clock-cntl-level = "svs_l1", "nominal"; + src-clock-name = "cam_cc_sfe_lite_1_clk"; + operating-points-v2 = <&cam_sfe_lite_opp_table1>; + cam_hw_pid = <5>; + clock-control-debugfs = "true"; + cell-index = <1>; + status = "ok"; + + cam_sfe_lite_opp_table1: opp-table { + compatible = "operating-points-v2"; + + opp-480000000 { + opp-hz = /bits/ 64 <480000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-600000000 { + opp-hz = /bits/ 64 <600000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + }; + }; +}; + +&tlmm { + cam_sensor_mclk0_active: cam-sensor-mclk0-active { + /* MCLK0 */ + mux { + pins = "gpio72"; + function = "cam_mclk"; + }; + + config { + pins = "gpio72"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk0_suspend: cam-sensor-mclk0-suspend { + /* MCLK0 */ + mux { + pins = "gpio72"; + function = "cam_mclk"; + }; + + config { + pins = "gpio72"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk1_active: cam-sensor-mclk1-active { + /* MCLK1 */ + mux { + pins = "gpio73"; + function = "cam_mclk"; + }; + + config { + pins = "gpio73"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk1_suspend: cam-sensor-mclk1-suspend { + /* MCLK1 */ + mux { + pins = "gpio73"; + function = "cam_mclk"; + }; + + config { + pins = "gpio73"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk2_active: cam-sensor-mclk2-active { + /* MCLK2 */ + mux { + pins = "gpio74"; + function = "cam_mclk"; + }; + + config { + pins = "gpio74"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk2_suspend: cam-sensor-mclk2-suspend { + /* MCLK2 */ + mux { + pins = "gpio74"; + function = "cam_mclk"; + }; + + config { + pins = "gpio74"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk3_active: cam-sensor-mclk3-active { + /* MCLK3 */ + mux { + pins = "gpio75"; + function = "cam_mclk"; + }; + + config { + pins = "gpio75"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk3_suspend: cam-sensor-mclk3-suspend { + /* MCLK3 */ + mux { + pins = "gpio75"; + function = "cam_mclk"; + }; + + config { + pins = "gpio75"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cci0_active: cci0-active { + mux { + /* CLK, DATA */ + pins = "gpio61","gpio60"; + function = "cci_i2c"; + }; + + config { + pins = "gpio61","gpio60"; + bias-pull-up; /* PULL UP*/ + drive-strength = <2>; /* 2 MA */ + qcom,i2c_pull; /* I2C PULL */ + }; + }; + + cci0_suspend: cci0-suspend { + mux { + /* CLK, DATA */ + pins = "gpio61","gpio60"; + function = "cci_i2c"; + }; + + config { + pins = "gpio61","gpio60"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cci1_active: cci1-active { + mux { + /* CLK, DATA */ + pins = "gpio53","gpio52"; + function = "cci_i2c"; + }; + + config { + pins = "gpio53","gpio52"; + bias-pull-up; /* PULL UP*/ + drive-strength = <2>; /* 2 MA */ + qcom,i2c_pull; /* I2C PULL */ + }; + }; + + cci1_suspend: cci1-suspend { + mux { + /* CLK, DATA */ + pins = "gpio53","gpio52"; + function = "cci_i2c"; + }; + + config { + pins = "gpio53","gpio52"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cci2_active: cci2-active { + mux { + /* CLK, DATA */ + pins = "gpio63","gpio62"; + function = "cci_i2c"; + }; + + config { + pins = "gpio63","gpio62"; + bias-pull-up; /* PULL UP*/ + drive-strength = <2>; /* 2 MA */ + qcom,i2c_pull; /* I2C PULL */ + }; + }; + + cci2_suspend: cci2-suspend { + mux { + /* CLK, DATA */ + pins = "gpio63","gpio62"; + function = "cci_i2c"; + }; + + config { + pins = "gpio63","gpio62"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cci3_active: cci3-active { + mux { + /* CLK, DATA */ + pins = "gpio55","gpio54"; + function = "cci_i2c"; + }; + + config { + pins = "gpio55","gpio54"; + bias-pull-up; /* PULL UP*/ + drive-strength = <2>; /* 2 MA */ + qcom,i2c_pull; /* I2C PULL */ + }; + }; + + cci3_suspend: cci3-suspend { + mux { + /* CLK, DATA */ + pins = "gpio55","gpio54"; + function = "cci_i2c"; + }; + + config { + pins = "gpio55","gpio54"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cci4_active: cci4-active { + mux { + /* CLK, DATA */ + pins = "gpio65","gpio64"; + function = "cci_i2c"; + }; + + config { + pins = "gpio65","gpio64"; + bias-pull-up; /* PULL UP*/ + drive-strength = <2>; /* 2 MA */ + qcom,i2c_pull; /* I2C PULL */ + }; + }; + + cci4_suspend: cci4-suspend { + mux { + /* CLK, DATA */ + pins = "gpio65","gpio64"; + function = "cci_i2c"; + }; + + config { + pins = "gpio65","gpio64"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cci5_active: cci5-active { + mux { + /* CLK, DATA */ + pins = "gpio57","gpio56"; + function = "cci_i2c"; + }; + + config { + pins = "gpio57","gpio56"; + bias-pull-up; /* PULL UP*/ + drive-strength = <2>; /* 2 MA */ + qcom,i2c_pull; /* I2C PULL */ + }; + }; + + cci5_suspend: cci5-suspend { + mux { + /* CLK, DATA */ + pins = "gpio57","gpio56"; + function = "cci_i2c"; + }; + + config { + pins = "gpio57","gpio56"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cci6_active: cci6-active { + mux { + /* CLK, DATA */ + pins = "gpio67","gpio66"; + function = "cci_i2c"; + }; + + config { + pins = "gpio67","gpio66"; + bias-pull-up; /* PULL UP*/ + drive-strength = <2>; /* 2 MA */ + qcom,i2c_pull; /* I2C PULL */ + }; + }; + + cci6_suspend: cci6-suspend { + mux { + /* CLK, DATA */ + pins = "gpio67","gpio66"; + function = "cci_i2c"; + }; + + config { + pins = "gpio67","gpio66"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cci7_active: cci7-active { + mux { + /* CLK, DATA */ + pins = "gpio59","gpio58"; + function = "cci_i2c"; + }; + + config { + pins = "gpio59","gpio58"; + bias-pull-up; /* PULL UP*/ + drive-strength = <2>; /* 2 MA */ + qcom,i2c_pull; /* I2C PULL */ + }; + }; + + cci7_suspend: cci7-suspend { + mux { + /* CLK, DATA */ + pins = "gpio59","gpio58"; + function = "cci_i2c"; + }; + + config { + pins = "gpio59","gpio58"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/lemans-evk-camera-sensor.dtsi b/arch/arm64/boot/dts/qcom/lemans-evk-camera-sensor.dtsi new file mode 100644 index 0000000000000..8eb1026e7da1b --- /dev/null +++ b/arch/arm64/boot/dts/qcom/lemans-evk-camera-sensor.dtsi @@ -0,0 +1,736 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#include + +&cam_cci0 { + /* GMSL deserializer 0 */ + qcom,cam-gmsl-deserializer0 { + cell-index = <0>; + csiphy-sd-index = <0>; + sensor-position-roll = <0>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + cam_vio-supply = <&vreg_s4a>; + regulator-names = "cam_vio"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000>; + rgltr-max-voltage = <1800000>; + rgltr-load-current = <120000>; + gpio-no-mux = <0>; + pinctrl-0 = <&cam_sensor_mclk0_active>; + pinctrl-1 = <&cam_sensor_mclk0_suspend>; + pinctrl-names = "cam_default", "cam_suspend"; + gpios = <&pmm8654au_0_gpios 7 0>; + gpio-reset = <0>; + gpio-req-tbl-num = <0>; + gpio-req-tbl-flags = <0>; + gpio-req-tbl-label = "CAM_RESET0"; + cci-master = <0>; + clocks = <&camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "nominal"; + clock-rates = <24000000>; + status = "ok"; + + port@0 { + reg = <0>; + + deser0_port0: endpoint { + remote-endpoint = <&gmsl_sensor0_ep>; + }; + }; + + port@1 { + reg = <1>; + + deser0_port1: endpoint { + remote-endpoint = <&gmsl_sensor1_ep>; + }; + }; + + port@2 { + reg = <0>; + deser0_port2: endpoint { + remote-endpoint = <&gmsl_sensor2_ep>; + }; + }; + + port@3 { + reg = <1>; + deser0_port3: endpoint { + remote-endpoint = <&gmsl_sensor3_ep>; + }; + }; + }; + + /* GMSL deserializer 0 sensor 0 */ + qcom,cam-gmsl-sensor0 { + compatible = "qcom,cam-gmsl-sensor"; + cell-index = <0>; + csiphy-sd-index = <0>; + status = "ok"; + + port { + gmsl_sensor0_ep: endpoint { + remote-endpoint = <&deser0_port0>; + }; + }; + }; + + /* GMSL deserializer 0 sensor 1 */ + qcom,cam-gmsl-sensor1 { + compatible = "qcom,cam-gmsl-sensor"; + cell-index = <1>; + csiphy-sd-index = <0>; + status = "ok"; + + port { + gmsl_sensor1_ep: endpoint { + remote-endpoint = <&deser0_port1>; + }; + }; + }; + + /* GMSL deserializer 0 sensor 2 */ + qcom,cam-gmsl-sensor2 { + compatible = "qcom,cam-gmsl-sensor"; + cell-index = <2>; + csiphy-sd-index = <0>; + status = "ok"; + + port { + gmsl_sensor2_ep: endpoint { + remote-endpoint = <&deser0_port2>; + }; + }; + }; + + /* GMSL deserializer 0 sensor 3 */ + qcom,cam-gmsl-sensor3 { + compatible = "qcom,cam-gmsl-sensor"; + cell-index = <3>; + csiphy-sd-index = <0>; + status = "ok"; + + port { + gmsl_sensor3_ep: endpoint { + remote-endpoint = <&deser0_port3>; + }; + }; + }; + + /*cam0a-ov9282*/ + qcom,cam-sensor1 { + compatible = "qcom,cam-sensor"; + csiphy-sd-index = <0>; + sensor-position-roll = <0>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + cam_vio-supply = <&vreg_s4a>; + regulator-names = "cam_vio"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000>; + rgltr-max-voltage = <1800000>; + rgltr-load-current = <120000>; + gpio-no-mux = <0>; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_active_rst0>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_suspend_rst0>; + pinctrl-names = "cam_default", "cam_suspend"; + gpios = <&tlmm 72 0>, + <&tlmm 132 0>, + <&pmm8654au_0_gpios 7 0>; + gpio-reset = <1>; + gpio-custom1 = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAM_MCLK0", + "CAMIF_RESET0", + "CAM_CUSTOM1"; + cci-master = <0>; + clocks = <&camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "nominal"; + clock-rates = <24000000>; + cell-index = <20>; + status = "ok"; + }; + + /*cam24-ov13858*/ + qcom,cam-sensor24 { + compatible = "qcom,cam-sensor"; + csiphy-sd-index = <0>; + sensor-position-roll = <0>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + eeprom-src = <&eeprom_cam24>; + cam_vio-supply = <&vreg_s4a>; + regulator-names = "cam_vio"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000>; + rgltr-max-voltage = <1800000>; + rgltr-load-current = <120000>; + gpio-no-mux = <0>; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_active_rst0>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_suspend_rst0>; + pinctrl-names = "cam_default", "cam_suspend"; + gpios = <&tlmm 72 0>, + <&tlmm 132 0>, + <&pmm8654au_0_gpios 7 0>; + gpio-reset = <1>; + gpio-custom1 = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAM_MCLK0", + "CAMIF_RESET0", + "CAM_CUSTOM1"; + cci-master = <0>; + clocks = <&camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "nominal"; + clock-rates = <24000000>; + cell-index = <24>; + status = "ok"; + }; + + eeprom_cam24: qcom,eeprom24 { + compatible = "qcom,eeprom"; + cam_vio-supply = <&vreg_s4a>; + regulator-names = "cam_vio"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000>; + rgltr-max-voltage = <1800000>; + rgltr-load-current = <120000>; + gpio-no-mux = <0>; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_active_rst0>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_suspend_rst0>; + pinctrl-names = "cam_default", "cam_suspend"; + gpios = <&tlmm 72 0>, + <&tlmm 132 0>, + <&pmm8654au_0_gpios 7 0>; + gpio-reset = <1>; + gpio-custom1 = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAM_MCLK0", + "CAMIF_RESET0", + "CAM_CUSTOM1"; + cci-master = <0>; + clocks = <&camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "nominal"; + clock-rates = <24000000>; + cell-index = <24>; + status = "ok"; + }; +}; + +&cam_cci1 { + /* GMSL deserializer 1 */ + qcom,cam-gmsl-deserializer1 { + cell-index = <1>; + csiphy-sd-index = <1>; + sensor-position-roll = <0>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + cam_vio-supply = <&vreg_s4a>; + regulator-names = "cam_vio"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000>; + rgltr-max-voltage = <1800000>; + rgltr-load-current = <120000>; + gpio-no-mux = <0>; + pinctrl-0 = <&cam_sensor_mclk1_active>; + pinctrl-1 = <&cam_sensor_mclk1_suspend>; + pinctrl-names = "cam_default", "cam_suspend"; + gpios = <&pmm8654au_0_gpios 8 0>; + gpio-reset = <0>; + gpio-req-tbl-num = <0>; + gpio-req-tbl-flags = <0>; + gpio-req-tbl-label = "CAM_RESET1"; + cci-master = <0>; + clocks = <&camcc CAM_CC_MCLK1_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "nominal"; + clock-rates = <24000000>; + status = "ok"; + + port@0 { + reg = <0>; + + deser1_port0: endpoint { + remote-endpoint = <&gmsl_sensor4_ep>; + }; + }; + + port@1 { + reg = <1>; + + deser1_port1: endpoint { + remote-endpoint = <&gmsl_sensor5_ep>; + }; + }; + + port@2 { + reg = <0>; + + deser1_port2: endpoint { + remote-endpoint = <&gmsl_sensor6_ep>; + }; + }; + + port@3 { + reg = <1>; + + deser1_port3: endpoint { + remote-endpoint = <&gmsl_sensor7_ep>; + }; + }; + }; + + /* GMSL deserializer 1 sensor 0 */ + qcom,cam-gmsl-sensor4 { + compatible = "qcom,cam-gmsl-sensor"; + cell-index = <4>; + csiphy-sd-index = <1>; + status = "ok"; + + port { + gmsl_sensor4_ep: endpoint { + remote-endpoint = <&deser1_port0>; + }; + }; + }; + + /* GMSL deserializer 1 sensor 1 */ + qcom,cam-gmsl-sensor5 { + compatible = "qcom,cam-gmsl-sensor"; + cell-index = <5>; + csiphy-sd-index = <1>; + status = "ok"; + + port { + gmsl_sensor5_ep: endpoint { + remote-endpoint = <&deser1_port1>; + }; + }; + }; + + /* GMSL deserializer 1 sensor 2 */ + qcom,cam-gmsl-sensor6 { + compatible = "qcom,cam-gmsl-sensor"; + cell-index = <6>; + csiphy-sd-index = <1>; + status = "ok"; + + port { + gmsl_sensor6_ep: endpoint { + remote-endpoint = <&deser1_port2>; + }; + }; + }; + + /* GMSL deserializer 1 sensor 3 */ + qcom,cam-gmsl-sensor7 { + compatible = "qcom,cam-gmsl-sensor"; + cell-index = <7>; + csiphy-sd-index = <1>; + status = "ok"; + + port { + gmsl_sensor7_ep: endpoint { + remote-endpoint = <&deser1_port3>; + }; + }; + }; + + /*cam1-ov9282*/ + qcom,cam-sensor21 { + compatible = "qcom,cam-sensor"; + csiphy-sd-index = <1>; + sensor-position-roll = <0>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + cam_vio-supply = <&vreg_s4a>; + regulator-names = "cam_vio"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000>; + rgltr-max-voltage = <1800000>; + rgltr-load-current = <120000>; + gpio-no-mux = <0>; + pinctrl-0 = <&cam_sensor_mclk1_active + &cam_sensor_active_rst1>; + pinctrl-1 = <&cam_sensor_mclk1_suspend + &cam_sensor_suspend_rst1>; + pinctrl-names = "cam_default", "cam_suspend"; + gpios = <&tlmm 73 0>, + <&tlmm 133 0>, + <&pmm8654au_0_gpios 8 0>; + gpio-reset = <1>; + gpio-custom1 = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAM_MCLK1", + "CAMIF_RESET1", + "CAM_CUSTOM1"; + cci-master = <0>; + clocks = <&camcc CAM_CC_MCLK1_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "nominal"; + clock-rates = <24000000>; + cell-index = <21>; + status = "ok"; + }; +}; + +&cam_cci2 { + /* GMSL deserializer 2 */ + qcom,cam-gmsl-deserializer2 { + cell-index = <2>; + csiphy-sd-index = <2>; + sensor-position-roll = <0>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + cam_vio-supply = <&vreg_s4a>; + regulator-names = "cam_vio"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000>; + rgltr-max-voltage = <1800000>; + rgltr-load-current = <120000>; + gpio-no-mux = <0>; + pinctrl-0 = <&cam_sensor_mclk2_active>; + pinctrl-1 = <&cam_sensor_mclk2_suspend>; + pinctrl-names = "cam_default", "cam_suspend"; + gpios = <&pmm8654au_0_gpios 9 0>; + gpio-reset = <0>; + gpio-req-tbl-num = <0>; + gpio-req-tbl-flags = <0>; + gpio-req-tbl-label = "CAM_RESET2"; + cci-master = <0>; + clocks = <&camcc CAM_CC_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "nominal"; + clock-rates = <24000000>; + status = "ok"; + + port@0 { + reg = <0>; + + deser2_port0: endpoint { + remote-endpoint = <&gmsl_sensor8_ep>; + }; + }; + + port@1 { + reg = <1>; + + deser2_port1: endpoint { + remote-endpoint = <&gmsl_sensor9_ep>; + }; + }; + + port@2 { + reg = <0>; + + deser2_port2: endpoint { + remote-endpoint = <&gmsl_sensor10_ep>; + }; + }; + + port@3 { + reg = <1>; + + deser2_port3: endpoint { + remote-endpoint = <&gmsl_sensor11_ep>; + }; + }; + }; + + /* GMSL deserializer 2 sensor 0 */ + qcom,cam-gmsl-sensor8 { + compatible = "qcom,cam-gmsl-sensor"; + cell-index = <8>; + csiphy-sd-index = <2>; + status = "ok"; + + port { + gmsl_sensor8_ep: endpoint { + remote-endpoint = <&deser2_port0>; + }; + }; + }; + + /* GMSL deserializer 2 sensor 1 */ + qcom,cam-gmsl-sensor9 { + compatible = "qcom,cam-gmsl-sensor"; + cell-index = <9>; + csiphy-sd-index = <2>; + status = "ok"; + + port { + gmsl_sensor9_ep: endpoint { + remote-endpoint = <&deser2_port1>; + }; + }; + }; + + /* GMSL deserializer 2 sensor 2 */ + qcom,cam-gmsl-sensor10 { + compatible = "qcom,cam-gmsl-sensor"; + cell-index = <10>; + csiphy-sd-index = <2>; + status = "ok"; + + port { + gmsl_sensor10_ep: endpoint { + remote-endpoint = <&deser2_port2>; + }; + }; + }; + + /* GMSL deserializer 2 sensor 3 */ + qcom,cam-gmsl-sensor11 { + compatible = "qcom,cam-gmsl-sensor"; + cell-index = <11>; + csiphy-sd-index = <2>; + status = "ok"; + + port { + gmsl_sensor11_ep: endpoint { + remote-endpoint = <&deser2_port3>; + }; + }; + }; + + /*cam2-ov9282*/ + qcom,cam-sensor22 { + compatible = "qcom,cam-sensor"; + csiphy-sd-index = <2>; + sensor-position-roll = <0>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + cam_vio-supply = <&vreg_s4a>; + regulator-names = "cam_vio"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000>; + rgltr-max-voltage = <1800000>; + rgltr-load-current = <120000>; + gpio-no-mux = <0>; + pinctrl-0 = <&cam_sensor_mclk2_active + &cam_sensor_active_rst2>; + pinctrl-1 = <&cam_sensor_mclk2_suspend + &cam_sensor_suspend_rst2>; + pinctrl-names = "cam_default", "cam_suspend"; + gpios = <&tlmm 74 0>, + <&tlmm 134 0>, + <&pmm8654au_0_gpios 9 0>; + gpio-reset = <1>; + gpio-custom1 = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAM_MCLK2", + "CAMIF_RESET2", + "CAM_CUSTOM1"; + cci-master = <0>; + clocks = <&camcc CAM_CC_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "nominal"; + clock-rates = <24000000>; + cell-index = <22>; + status = "ok"; + }; +}; + +&cam_cci3 { + /* GMSL deserializer 3 */ + qcom,cam-gmsl-deserializer3 { + cell-index = <3>; + csiphy-sd-index = <3>; + sensor-position-roll = <0>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + cam_vio-supply = <&vreg_s4a>; + regulator-names = "cam_vio"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000>; + rgltr-max-voltage = <1800000>; + rgltr-load-current = <120000>; + gpio-no-mux = <0>; + pinctrl-0 = <&cam_sensor_mclk3_active>; + pinctrl-1 = <&cam_sensor_mclk3_suspend>; + pinctrl-names = "cam_default", "cam_suspend"; + gpios = <&pmm8654au_0_gpios 10 0>; + gpio-reset = <0>; + gpio-req-tbl-num = <0>; + gpio-req-tbl-flags = <0>; + gpio-req-tbl-label = "CAM_RESET3"; + cci-master = <0>; + clocks = <&camcc CAM_CC_MCLK3_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "nominal"; + clock-rates = <24000000>; + status = "ok"; + + port@0 { + reg = <0>; + + deser3_port0: endpoint { + remote-endpoint = <&gmsl_sensor12_ep>; + }; + }; + + port@1 { + reg = <1>; + + deser3_port1: endpoint { + remote-endpoint = <&gmsl_sensor13_ep>; + }; + }; + + port@2 { + reg = <0>; + + deser3_port2: endpoint { + remote-endpoint = <&gmsl_sensor14_ep>; + }; + }; + + port@3 { + reg = <1>; + + deser3_port3: endpoint { + remote-endpoint = <&gmsl_sensor15_ep>; + }; + }; + }; + + /* GMSL deserializer 3 sensor 0 */ + qcom,cam-gmsl-sensor12 { + compatible = "qcom,cam-gmsl-sensor"; + cell-index = <12>; + csiphy-sd-index = <3>; + status = "ok"; + + port { + gmsl_sensor12_ep: endpoint { + remote-endpoint = <&deser3_port0>; + }; + }; + }; + + /* GMSL deserializer 3 sensor 1 */ + qcom,cam-gmsl-sensor13 { + compatible = "qcom,cam-gmsl-sensor"; + cell-index = <13>; + csiphy-sd-index = <3>; + status = "ok"; + + port { + gmsl_sensor13_ep: endpoint { + remote-endpoint = <&deser3_port1>; + }; + }; + }; + + /* GMSL deserializer 3 sensor 2 */ + qcom,cam-gmsl-sensor14 { + compatible = "qcom,cam-gmsl-sensor"; + cell-index = <14>; + csiphy-sd-index = <3>; + status = "ok"; + + port { + gmsl_sensor14_ep: endpoint { + remote-endpoint = <&deser3_port2>; + }; + }; + }; + + /* GMSL deserializer 3 sensor 3 */ + qcom,cam-gmsl-sensor15 { + cell-index = <15>; + compatible = "qcom,cam-gmsl-sensor"; + csiphy-sd-index = <3>; + status = "ok"; + + port { + gmsl_sensor15_ep: endpoint { + remote-endpoint = <&deser3_port3>; + }; + }; + }; + + /*cam3-ov9282*/ + qcom,cam-sensor23 { + compatible = "qcom,cam-sensor"; + csiphy-sd-index = <3>; + sensor-position-roll = <0>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + cam_vio-supply = <&vreg_s4a>; + regulator-names = "cam_vio"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000>; + rgltr-max-voltage = <1800000>; + rgltr-load-current = <120000>; + gpio-no-mux = <0>; + pinctrl-0 = <&cam_sensor_mclk3_active + &cam_sensor_active_rst3>; + pinctrl-1 = <&cam_sensor_mclk3_suspend + &cam_sensor_suspend_rst3>; + pinctrl-names = "cam_default", "cam_suspend"; + gpios = <&tlmm 75 0>, + <&tlmm 135 0>, + <&pmm8654au_0_gpios 10 0>; + gpio-reset = <1>; + gpio-custom1 = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAM_MCLK3", + "CAMIF_RESET3", + "CAM_CUSTOM1"; + cci-master = <0>; + clocks = <&camcc CAM_CC_MCLK3_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "nominal"; + clock-rates = <24000000>; + cell-index = <23>; + status = "ok"; + }; +}; + +&soc { + qcom,cam-res-mgr { + compatible = "qcom,cam-res-mgr"; + gpios-shared = <518 519 520 521>; + status = "ok"; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/lemans-evk-camx.dtso b/arch/arm64/boot/dts/qcom/lemans-evk-camx.dtso new file mode 100644 index 0000000000000..520fb14660142 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/lemans-evk-camx.dtso @@ -0,0 +1,138 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +/dts-v1/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "lemans-camera.dtsi" +#include "lemans-evk-camera-sensor.dtsi" + +&camss { + status = "disabled"; +}; + +&tlmm { + cam_sensor_active_rst0: cam-sensor-active-rst0 { + /* RESET */ + mux { + pins = "gpio132"; + function = "gpio"; + }; + + config { + pins = "gpio132"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_active_rst1: cam-sensor-active-rst1 { + /* RESET */ + mux { + pins = "gpio133"; + function = "gpio"; + }; + + config { + pins = "gpio133"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_active_rst2: cam-sensor-active-rst2 { + /* RESET */ + mux { + pins = "gpio134"; + function = "gpio"; + }; + + config { + pins = "gpio134"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_active_rst3: cam-sensor-active-rst3 { + /* RESET */ + mux { + pins = "gpio135"; + function = "gpio"; + }; + + config { + pins = "gpio135"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_suspend_rst0: cam-sensor-suspend-rst0 { + /* RESET */ + mux { + pins = "gpio132"; + function = "gpio"; + }; + + config { + pins = "gpio132"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; + }; + + cam_sensor_suspend_rst1: cam-sensor-suspend-rst1 { + /* RESET */ + mux { + pins = "gpio133"; + function = "gpio"; + }; + + config { + pins = "gpio133"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; + }; + + cam_sensor_suspend_rst2: cam-sensor-suspend-rst2 { + /* RESET */ + mux { + pins = "gpio134"; + function = "gpio"; + }; + + config { + pins = "gpio134"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; + }; + + cam_sensor_suspend_rst3: cam-sensor-suspend-rst3 { + /* RESET */ + mux { + pins = "gpio135"; + function = "gpio"; + }; + + config { + pins = "gpio135"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sa8775p-ride-camx.dtso b/arch/arm64/boot/dts/qcom/sa8775p-ride-camx.dtso new file mode 100644 index 0000000000000..f81fa6565f281 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sa8775p-ride-camx.dtso @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +/dts-v1/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "lemans-camera.dtsi" +#include "lemans-camera-sensor.dtsi" From 298c165b45a1daa74a1fcfd36794fe21cdbfc9ef Mon Sep 17 00:00:00 2001 From: Chandan Kumar Jha Date: Fri, 17 Oct 2025 11:25:35 +0530 Subject: [PATCH 0041/2333] QCLINUX: arm64: dts: qcom: Add rb3gen2 camx overlay dts Add CAMX overlay dts file for rb3gen2 vision mezzanine board. This change also enables the compilation of the CAMX overlay for Kodiak rb3gen2 vision mezzanine board. Signed-off-by: Chandan Kumar Jha --- arch/arm64/boot/dts/qcom/Makefile | 6 + arch/arm64/boot/dts/qcom/qcs6490-camera.dtsi | 2471 +++++++++++++++++ .../qcom/qcs6490-rb3gen2-camera-sensor.dtsi | 551 ++++ ...qcs6490-rb3gen2-vision-mezzanine-camx.dtso | 24 + 4 files changed, 3052 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/qcs6490-camera.dtsi create mode 100644 arch/arm64/boot/dts/qcom/qcs6490-rb3gen2-camera-sensor.dtsi create mode 100644 arch/arm64/boot/dts/qcom/qcs6490-rb3gen2-vision-mezzanine-camx.dtso diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile index b9f9e659b95fe..dac4d11eb46df 100644 --- a/arch/arm64/boot/dts/qcom/Makefile +++ b/arch/arm64/boot/dts/qcom/Makefile @@ -138,6 +138,12 @@ qcs6490-rb3gen2-industrial-mezzanine-dtbs := qcs6490-rb3gen2.dtb qcs6490-rb3gen2 dtb-$(CONFIG_ARCH_QCOM) += qcs6490-rb3gen2-industrial-mezzanine.dtb dtb-$(CONFIG_ARCH_QCOM) += qcs6490-rb3gen2-vision-mezzanine.dtb + +qcs6490-rb3gen2-vision-mezzanine-camx-dtbs := qcs6490-rb3gen2-vision-mezzanine.dtb \ + qcs6490-rb3gen2-vision-mezzanine-camx.dtbo + +dtb-$(CONFIG_ARCH_QCOM) += qcs6490-rb3gen2-vision-mezzanine-camx.dtb + dtb-$(CONFIG_ARCH_QCOM) += qcs8300-ride.dtb dtb-$(CONFIG_ARCH_QCOM) += qcs8550-aim300-aiot.dtb dtb-$(CONFIG_ARCH_QCOM) += qcs9100-ride.dtb diff --git a/arch/arm64/boot/dts/qcom/qcs6490-camera.dtsi b/arch/arm64/boot/dts/qcom/qcs6490-camera.dtsi new file mode 100644 index 0000000000000..f6af6827784bd --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcs6490-camera.dtsi @@ -0,0 +1,2471 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#include + +&soc { + cam_a5: qcom,a5 { + compatible = "qcom,cam-a5"; + cell-index = <0>; + reg = <0x0 0xac00000 0x0 0x6000>, + <0x0 0xac10000 0x0 0x8000>, + <0x0 0xac18000 0x0 0x3000>; + reg-names = "a5_qgic", "a5_sierra", "a5_csr"; + reg-cam-base = <0x00000 0x10000 0x18000>; + interrupts = ; + interrupt-names = "a5"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + clocks = <&camcc CAM_CC_FAST_AHB_CLK_SRC>, + <&camcc CAM_CC_ICP_AHB_CLK>, + <&camcc CAM_CC_ICP_CLK_SRC>, + <&camcc CAM_CC_ICP_CLK>; + clock-names = "soc_fast_ahb", + "icp_ahb_clk", + "icp_clk_src", + "icp_clk"; + clock-rates = <100000000 0 400000000 0>, + <200000000 0 400000000 0>, + <300000000 0 600000000 0>, + <400000000 0 600000000 0>; + clock-cntl-level = "lowsvs", "svs", "svs_l1", "nominal"; + src-clock-name = "soc_fast_ahb"; + operating-points-v2 = <&a5_opp_table>; + fw_name = "CAMERA_ICP_170.elf"; + ubwc-ipe-fetch-cfg = <0x7073 0x707b>; + ubwc-ipe-write-cfg = <0x161cf 0x161ef>; + ubwc-bps-fetch-cfg = <0x7073 0x707b>; + ubwc-bps-write-cfg = <0x161cf 0x161ef>; + qos-val = <0x00000A0A>; + status = "ok"; + + a5_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-100000000 { + opp-hz = /bits/ 64 <100000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + + opp-200000000 { + opp-hz = /bits/ 64 <200000000>; + required-opps = <&rpmhpd_opp_svs>; + }; + + opp-300000000 { + opp-hz = /bits/ 64 <300000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-400000000 { + opp-hz = /bits/ 64 <400000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + }; + }; + + cam_bps: qcom,bps { + compatible = "qcom,cam-bps"; + cell-index = <0>; + reg = <0x0 0xac6f000 0x0 0x8000>; + reg-names = "bps_top"; + reg-cam-base = <0x6f000>; + power-domains = <&camcc CAM_CC_BPS_GDSC>; + clocks = <&camcc CAM_CC_BPS_AHB_CLK>, + <&camcc CAM_CC_BPS_AREG_CLK>, + <&camcc CAM_CC_BPS_AXI_CLK>, + <&camcc CAM_CC_BPS_CLK_SRC>, + <&camcc CAM_CC_BPS_CLK>; + clock-names = "bps_ahb_clk", + "bps_areg_clk", + "bps_axi_clk", + "bps_clk_src", + "bps_clk"; + clock-rates = <0 0 0 200000000 0>, + <0 0 0 400000000 0>, + <0 0 0 480000000 0>, + <0 0 0 600000000 0>, + <0 0 0 600000000 0>; + clock-cntl-level = "lowsvs", "svs", "svs_l1", + "nominal", "turbo"; + src-clock-name = "bps_clk_src"; + operating-points-v2 = <&bps_opp_table>; + clock-control-debugfs = "true"; + status = "ok"; + + bps_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-200000000 { + opp-hz = /bits/ 64 <200000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + + opp-400000000 { + opp-hz = /bits/ 64 <400000000>; + required-opps = <&rpmhpd_opp_svs>; + }; + + opp-480000000 { + opp-hz = /bits/ 64 <480000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-600000000 { + opp-hz = /bits/ 64 <600000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + }; + }; + + qcom,cam-cdm-intf { + compatible = "qcom,cam-cdm-intf"; + cell-index = <0>; + label = "cam-cdm-intf"; + num-hw-cdm = <1>; + cdm-client-names = "vfe", + "jpegdma", + "jpegenc", + "lrmecdm"; + status = "ok"; + }; + + qcom,cam-cpas { + compatible = "qcom,cam-cpas"; + cell-index = <0>; + label = "cpas"; + arch-compat = "cpas_top"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x0 0x0ac40000 0x0 0x1000>, + <0x0 0x0ac9f000 0x0 0x10000>; + reg-names = "cam_cpas_top", "cam_camnoc"; + reg-cam-base = <0x40000 0x9f000>; + cam_hw_fuse = , + , + , + , + , + ; + interrupts = ; + interrupt-names = "cpas_camnoc"; + camnoc-axi-min-ib-bw = <3000000000>; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + clocks = <&gcc GCC_CAMERA_HF_AXI_CLK>, + <&gcc GCC_CAMERA_SF_AXI_CLK>, + <&camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&camcc CAM_CC_CPAS_AHB_CLK>, + <&camcc CAM_CC_CAMNOC_AXI_CLK_SRC>, + <&camcc CAM_CC_CAMNOC_AXI_CLK>, + <&camcc CAM_CC_ICP_AHB_CLK>, + <&camcc CAM_CC_ICP_CLK>; + clock-names = "gcc_camera_hf_axi_clk", + "gcc_camera_sf_axi_clk", + "cam_cc_slow_ahb_clk_src", + "cam_cc_cpas_ahb_clk", + "cam_cc_camnoc_axi_clk_src", + "cam_cc_camnoc_axi_clk", + "cam_cc_icp_ahb_clk", + "cam_cc_icp_clk"; + src-clock-name = "cam_cc_camnoc_axi_clk_src"; + clock-rates = <0 0 0 0 0 0 0 0>, + <0 0 80000000 0 150000000 0 0 0>, + <0 0 80000000 0 240000000 0 0 0>, + <0 0 80000000 0 320000000 0 0 0>, + <0 0 80000000 0 400000000 0 0 0>, + <0 0 80000000 0 480000000 0 0 0>; + clock-cntl-level = "suspend", "lowsvs", "svs", + "svs_l1", "nominal", "turbo"; + operating-points-v2 = <&cpas_opp_table>; + control-camnoc-axi-clk; + camnoc-bus-width = <32>; + camnoc-axi-clk-bw-margin-perc = <20>; + interconnects = <&gem_noc MASTER_APPSS_PROC 0 &cnoc2 SLAVE_CAMERA_CFG 0>, + <&mmss_noc MASTER_CAMNOC_HF 0 &mc_virt SLAVE_EBI1 0>, + <&mmss_noc MASTER_CAMNOC_SF 0 &mc_virt SLAVE_EBI1 0>, + <&mmss_noc MASTER_CAMNOC_ICP 0 &mc_virt SLAVE_EBI1 0>; + interconnect-names = "cam_ahb", "cam_hf_0", "cam_sf_0", "cam_sf_icp"; + cam-ahb-num-cases = <7>; + cam-ahb-bw-KBps = <0 0>, <0 76800>, <0 150000>, <0 150000>, + <0 300000>, <0 300000>, <0 300000>; + vdd-corners = ; + vdd-corner-ahb-mapping = "suspend", "lowsvs", "lowsvs", "svs", "svs_l1", + "nominal", "nominal", "nominal", "turbo", "turbo"; + client-id-based; + client-names = "csiphy0", "csiphy1", "csiphy2", "csiphy3", + "csiphy4", "cci0", "cci1", "csid0", "csid1", + "csid2", "csid3", "csid4", "ife0", "ife1", + "ife2", "ife3", "ife4", "ipe0", "cam-cdm-intf0", + "cpas-cdm0", "bps0", "icp0", "jpeg-dma0", "jpeg-enc0", + "lrmecpas0"; + status = "ok"; + + cpas_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-150000000 { + opp-hz = /bits/ 64 <150000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + + opp-240000000 { + opp-hz = /bits/ 64 <240000000>; + required-opps = <&rpmhpd_opp_svs>; + }; + + opp-320000000 { + opp-hz = /bits/ 64 <320000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-400000000 { + opp-hz = /bits/ 64 <400000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + + opp-480000000 { + opp-hz = /bits/ 64 <480000000>; + required-opps = <&rpmhpd_opp_turbo>; + }; + }; + + camera-bus-nodes { + level0-nodes { + level-index = <0>; + + bps0_all_rd: bps0-all-rd { + cell-index = <0>; + node-name = "bps0-all-rd"; + client-name = "bps0"; + traffic-data = ; + traffic-transaction-type = ; + parent-node = <&level1_nrt0_read0>; + }; + + bps0_all_wr: bps0-all-wr { + cell-index = <1>; + node-name = "bps0-all-wr"; + client-name = "bps0"; + traffic-data = ; + traffic-transaction-type = ; + parent-node = <&level1_nrt0_write0>; + }; + + cpas_cdm0_all_rd: cpas-cdm0-all-rd { + cell-index = <2>; + node-name = "cpas-cdm0-all-rd"; + client-name = "cpas-cdm0"; + traffic-data = ; + traffic-transaction-type = ; + parent-node = <&level2_nrt0_read0>; + }; + + icp0_all_rd: icp0-all-rd { + cell-index = <3>; + node-name = "icp0-all-rd"; + client-name = "icp0"; + traffic-data = ; + traffic-transaction-type = ; + parent-node = <&level2_nrt1_read0>; + }; + + ife0_pixelall_wr: ife0-pixelall-wr { + cell-index = <4>; + node-name = "ife0-pixelall-wr"; + client-name = "ife0"; + traffic-data = ; + traffic-transaction-type = ; + constituent-paths = ; + parent-node = <&level1_rt1_write0>; + }; + + ife0_rdi_wr: ife0-rdi-wr { + cell-index = <5>; + node-name = "ife0-rdi-wr"; + client-name = "ife0"; + traffic-data = ; + traffic-transaction-type = ; + constituent-paths = ; + parent-node = <&level1_rt0_write0>; + }; + + ife1_pixelall_wr: ife1-pixelall-wr { + cell-index = <6>; + node-name = "ife1-pixelall-wr"; + client-name = "ife1"; + traffic-data = ; + traffic-transaction-type = ; + constituent-paths = ; + parent-node = <&level1_rt1_write0>; + }; + + ife1_rdi_wr: ife1-rdi-wr { + cell-index = <7>; + node-name = "ife1-rdi-wr"; + client-name = "ife1"; + traffic-data = ; + traffic-transaction-type = ; + constituent-paths = ; + parent-node = <&level1_rt0_write0>; + }; + + ife2_pixelall_wr: ife2-pixelall-wr { + cell-index = <8>; + node-name = "ife2-pixelall-wr"; + client-name = "ife2"; + traffic-data = ; + traffic-transaction-type = ; + constituent-paths = ; + parent-node = <&level1_rt1_write1>; + }; + + ife2_rdi_wr: ife2-rdi-wr { + cell-index = <9>; + node-name = "ife2-rdi-wr"; + client-name = "ife2"; + traffic-data = ; + traffic-transaction-type = ; + constituent-paths = ; + parent-node = <&level1_rt0_write0>; + }; + + ife3_rdi_wr: ife3-rdi-wr { + cell-index = <10>; + node-name = "ife3-rdi-wr"; + client-name = "ife3"; + traffic-data = ; + traffic-transaction-type = ; + constituent-paths = ; + parent-node = <&level1_rt0_write0>; + }; + + ife4_rdi_wr: ife4-rdi-wr { + cell-index = <11>; + node-name = "ife4-rdi-wr"; + client-name = "ife4"; + traffic-data = ; + traffic-transaction-type = ; + constituent-paths = ; + parent-node = <&level1_rt0_write0>; + }; + + ipe0_all_rd: ipe0-all-rd { + cell-index = <12>; + node-name = "ipe0-all-rd"; + client-name = "ipe0"; + traffic-data = ; + traffic-transaction-type = ; + constituent-paths = ; + parent-node = <&level1_nrt0_read0>; + }; + + ipe0_ref_wr: ipe0-ref-wr { + cell-index = <13>; + node-name = "ipe0-ref-wr"; + client-name = "ipe0"; + traffic-data = ; + traffic-transaction-type = ; + parent-node = <&level1_nrt0_write0>; + }; + + ipe0_viddisp_wr: ipe0-viddisp-wr { + cell-index = <14>; + node-name = "ipe0-viddisp-wr"; + client-name = "ipe0"; + traffic-data = ; + traffic-transaction-type = ; + constituent-paths = ; + parent-node = <&level1_nrt0_write0>; + }; + + jpeg_dma0_all_rd: jpeg-dma0-all-rd { + cell-index = <15>; + node-name = "jpeg-dma0-all-rd"; + client-name = "jpeg-dma0"; + traffic-data = ; + traffic-transaction-type = ; + parent-node = <&level1_nrt1_read0>; + }; + + jpeg_dma0_all_wr: jpeg-dma0-all-wr { + cell-index = <16>; + node-name = "jpeg-dma0-all-wr"; + client-name = "jpeg-dma0"; + traffic-data = ; + traffic-transaction-type = ; + parent-node = <&level1_nrt1_write0>; + }; + + jpeg_enc0_all_rd: jpeg-enc0-all-rd { + cell-index = <17>; + node-name = "jpeg-enc0-all-rd"; + client-name = "jpeg-enc0"; + traffic-data = ; + traffic-transaction-type = ; + parent-node = <&level1_nrt1_read0>; + }; + + jpeg_enc0_all_wr: jpeg-enc0-all-wr { + cell-index = <18>; + node-name = "jpeg-enc0-all-wr"; + client-name = "jpeg-enc0"; + traffic-data = ; + traffic-transaction-type = ; + parent-node = <&level1_nrt1_write0>; + }; + + lrme0_all_rd: lrme0-all-rd { + cell-index = <19>; + node-name = "lrme0-all-rd"; + client-name = "lrmecpas0"; + traffic-data = ; + traffic-transaction-type = ; + parent-node = <&level1_nrt0_read0>; + }; + + lrme0_all_wr: lrme0-all-wr { + cell-index = <20>; + node-name = "lrme0-all-wr"; + client-name = "lrmecpas0"; + traffic-data = ; + traffic-transaction-type = ; + parent-node = <&level1_nrt0_write0>; + }; + }; + + level1-nodes { + level-index = <1>; + camnoc-max-needed; + + level1_nrt0_write0: level1-nrt0-write0 { + cell-index = <21>; + node-name = "level1-nrt0-write0"; + parent-node = <&level2_nrt0_write0>; + traffic-merge-type = ; + }; + + level1_nrt0_read0: level1-nrt0-read0 { + cell-index = <22>; + node-name = "level1-nrt0-read0"; + parent-node = <&level2_nrt0_read0>; + traffic-merge-type = ; + }; + + level1_nrt1_write0: level1-nrt1-write0 { + cell-index = <23>; + node-name = "level1-nrt1-write0"; + parent-node = <&level2_nrt0_write0>; + traffic-merge-type = ; + }; + + level1_nrt1_read0: level1-nrt1-read0 { + cell-index = <24>; + node-name = "level1-nrt1-read0"; + parent-node = <&level2_nrt0_read0>; + traffic-merge-type = ; + }; + + level1_rt0_write0: level1-rt0-write0 { + cell-index = <25>; + node-name = "level1-rt0-write0"; + parent-node = <&level2_rt0_write0>; + traffic-merge-type = ; + }; + + level1_rt1_write0: level1-rt1-write0 { + cell-index = <26>; + node-name = "level1-rt1-write0"; + parent-node = <&level2_rt1_write0>; + traffic-merge-type = ; + }; + + level1_rt1_write1: level1-rt1-write1 { + cell-index = <27>; + node-name = "level1-rt1-write1"; + parent-node = <&level2_rt1_write0>; + traffic-merge-type = ; + }; + }; + + level2-nodes { + level-index = <3>; + camnoc-max-needed; + + level2_nrt0_write0: level2-nrt0-write0 { + cell-index = <28>; + node-name = "level2-nrt0-write0"; + parent-node = <&level3_nrt0_rd_wr_sum>; + traffic-merge-type = ; + }; + + level2_nrt0_read0: level2-nrt0-read0 { + cell-index = <29>; + node-name = "level2-nrt0-read0"; + parent-node = <&level3_nrt0_rd_wr_sum>; + traffic-merge-type = ; + }; + + level2_nrt1_read0: level2-nrt1-read0 { + cell-index = <30>; + node-name = "level2-nrt1-read0"; + parent-node = <&level3_nrt1_rd_sum>; + traffic-merge-type = + ; + bus-width-factor = <4>; + }; + + level2_rt0_write0: level2-rt0-write0 { + cell-index = <31>; + node-name = "level2-rt0-write0"; + parent-node = <&level3_rt0_wr_sum>; + traffic-merge-type = ; + }; + + level2_rt1_write0: level2-rt1-write0 { + cell-index = <32>; + node-name = "level2-rt1-write0"; + parent-node = <&level3_rt0_wr_sum>; + traffic-merge-type = ; + }; + }; + + level3-nodes { + level-index = <3>; + + level3_nrt0_rd_wr_sum: level3-nrt0-rd-wr-sum { + cell-index = <33>; + node-name = "level3-nrt0-rd-wr-sum"; + traffic-merge-type = ; + + qcom,axi-port-mnoc { + interconnect-names = "cam_sf_0"; + interconnects = + <&mmss_noc MASTER_CAMNOC_SF 0 + &mc_virt SLAVE_EBI1 0>; + }; + }; + + level3_nrt1_rd_sum: level3-nrt1-rd-sum { + cell-index = <34>; + node-name = "level3-nrt1-rd-sum"; + traffic-merge-type = ; + + qcom,axi-port-mnoc { + interconnect-names = "cam_sf_icp"; + interconnects = + <&mmss_noc MASTER_CAMNOC_ICP 0 + &mc_virt SLAVE_EBI1 0>; + }; + }; + + level3_rt0_wr_sum: level3-rt0-wr-sum { + cell-index = <35>; + node-name = "level3-rt0-wr-sum"; + traffic-merge-type = ; + ib-bw-voting-needed; + + qcom,axi-port-mnoc { + interconnect-names = "cam_hf_0"; + interconnects = + <&mmss_noc MASTER_CAMNOC_HF 0 + &mc_virt SLAVE_EBI1 0>; + }; + }; + }; + }; + }; + + qcom,cam-icp { + compatible = "qcom,cam-icp"; + compat-hw-name = "qcom,a5", + "qcom,ipe0", + "qcom,bps"; + num-a5 = <1>; + num-ipe = <1>; + num-bps = <1>; + icp_pc_en; + status = "ok"; + }; + + qcom,cam-isp { + compatible = "qcom,cam-isp"; + arch-compat = "ife"; + status = "ok"; + }; + + qcom,cam-req-mgr { + compatible = "qcom,cam-req-mgr"; + status = "ok"; + }; + + qcom,cam-jpeg { + compatible = "qcom,cam-jpeg"; + compat-hw-name = "qcom,jpegenc", + "qcom,jpegdma"; + num-jpeg-enc = <1>; + num-jpeg-dma = <1>; + status = "ok"; + }; + + qcom,cam-lrme { + compatible = "qcom,cam-lrme"; + arch-compat = "lrme"; + status = "ok"; + }; + + qcom,camera-main { + compatible = "qcom,camera_kt"; + status = "ok"; + }; + + qcom,cam-smmu { + compatible = "qcom,msm-cam-smmu", "simple-bus"; + force_cache_allocs; + status = "ok"; + + msm-cam-icp-fw { + compatible = "qcom,msm-cam-smmu-fw-dev"; + label="icp"; + memory-region = <&camera_mem>; + }; + + msm-cam-smmu-cpas-cdm { + compatible = "qcom,msm-cam-smmu-cb"; + iommus = <&apps_smmu 0x2040 0x0>; + cam-smmu-label = "cpas-cdm"; + dma-coherent; + + cpas_cdm_iova_mem_map: iova-mem-map { + iova-mem-region-io { + /* IO region is approximately 3.4 GB */ + iova-region-name = "io"; + iova-region-start = <0x100000>; + iova-region-len = <0xffe00000>; + iova-region-id = <0x3>; + status = "ok"; + }; + }; + }; + + msm_cam_smmu_icp { + compatible = "qcom,msm-cam-smmu-cb"; + iommus = <&apps_smmu 0x2000 0x20>, + <&apps_smmu 0x2020 0x20>, + <&apps_smmu 0x2062 0x0>, + <&apps_smmu 0x2080 0x20>, + <&apps_smmu 0x20A0 0x20>, + <&apps_smmu 0x2140 0x0>; + cam-smmu-label = "icp"; + dma-coherent; + + icp_iova_mem_map: iova-mem-map { + iova-mem-region-firmware { + /* Firmware region is 5MB */ + iova-region-name = "firmware"; + iova-region-start = <0x0>; + iova-region-len = <0x500000>; + iova-region-id = <0x0>; + status = "ok"; + }; + + iova-mem-region-io { + /* IO region is approximately 3.7 GB */ + iova-region-name = "io"; + iova-region-start = <0x10c00000>; + iova-region-len = <0xcf300000>; + iova-region-id = <0x3>; + status = "ok"; + }; + + iova-mem-region-qdss { + /* QDSS region is appropriate 1MB */ + iova-region-name = "qdss"; + iova-region-start = <0x10b00000>; + iova-region-len = <0x100000>; + iova-region-id = <0x5>; + qdss-phy-addr = <0x16790000>; + status = "ok"; + }; + + iova-mem-region-secondary-heap { + /* Secondary heap region is 1MB long */ + iova-region-name = "secheap"; + iova-region-start = <0x10a00000>; + iova-region-len = <0x100000>; + iova-region-id = <0x4>; + status = "ok"; + }; + + iova-mem-region-shared { + /* Shared region is 150MB long */ + iova-region-name = "shared"; + iova-region-start = <0x7400000>; + iova-region-len = <0x9600000>; + iova-region-id = <0x1>; + status = "ok"; + }; + }; + }; + + msm-cam-smmu-ife { + compatible = "qcom,msm-cam-smmu-cb"; + iommus = <&apps_smmu 0x800 0x4E0>, + <&apps_smmu 0x820 0x4E0>, + <&apps_smmu 0x840 0x4E0>, + <&apps_smmu 0x860 0x4E0>, + <&apps_smmu 0x880 0x4E0>, + <&apps_smmu 0x8A0 0x4E0>, + <&apps_smmu 0x8C0 0x4E0>, + <&apps_smmu 0x8E0 0x4E0>, + <&apps_smmu 0xC00 0x4E0>, + <&apps_smmu 0xC20 0x4E0>, + <&apps_smmu 0xC40 0x4E0>, + <&apps_smmu 0xC60 0x4E0>, + <&apps_smmu 0xC80 0x4E0>, + <&apps_smmu 0xCA0 0x4E0>, + <&apps_smmu 0xCC0 0x4E0>, + <&apps_smmu 0xCE0 0x4E0>; + cam-smmu-label = "ife"; + multiple-client-devices; + dma-coherent; + + ife_iova_mem_map: iova-mem-map { + /* IO region is approximately 4 GB */ + iova-mem-region-io { + iova-region-name = "io"; + iova-region-start = <0x100000>; + iova-region-len = <0xffe00000>; + iova-region-id = <0x3>; + status = "ok"; + }; + }; + }; + + msm-cam-smmu-jpeg { + compatible = "qcom,msm-cam-smmu-cb"; + iommus = <&apps_smmu 0x20C0 0x20>, + <&apps_smmu 0x20E0 0x20>; + cam-smmu-label = "jpeg"; + dma-coherent; + + jpeg_iova_mem_map: iova-mem-map { + /* IO region is approximately 3.4 GB */ + iova-mem-region-io { + iova-region-name = "io"; + iova-region-start = <0x100000>; + iova-region-len = <0xffe00000>; + iova-region-id = <0x3>; + status = "ok"; + }; + }; + }; + + msm-cam-smmu-lrme { + compatible = "qcom,msm-cam-smmu-cb"; + iommus = <&apps_smmu 0x2100 0x20>, + <&apps_smmu 0x2120 0x20>; + cam-smmu-label = "lrme"; + dma-coherent; + + lrme_iova_mem_map: iova-mem-map { + iova-mem-region-shared { + /* Shared region is 100MB long */ + iova-region-name = "shared"; + iova-region-start = <0x7400000>; + iova-region-len = <0x6400000>; + iova-region-id = <0x1>; + status = "ok"; + }; + + /* IO region is approximately 3.3 GB */ + iova-mem-region-io { + iova-region-name = "io"; + iova-region-start = <0x100000>; + iova-region-len = <0xffe00000>; + iova-region-id = <0x3>; + status = "ok"; + }; + }; + }; + + msm-cam-smmu-secure { + compatible = "qcom,msm-cam-smmu-cb"; + cam-smmu-label = "cam-secure"; + qcom,secure-cb; + }; + }; + + qcom,cam-sync { + compatible = "qcom,cam-sync"; + status = "ok"; + }; + + cam_cci0: qcom,cci0 { + compatible = "qcom,cci", "simple-bus"; + reg = <0x0 0xac4a000 0x0 0x1000>; + reg-names = "cci"; + reg-cam-base = <0x4a000>; + interrupts = ; + interrupt-names = "cci"; + operating-points-v2 = <&cci0_opp_table>; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + clocks = <&camcc CAM_CC_CCI_0_CLK_SRC>, + <&camcc CAM_CC_CCI_0_CLK>; + clock-names = "cci_0_clk_src", + "cci_0_clk"; + clock-rates = <37500000 0>; + clock-cntl-level = "lowsvs"; + src-clock-name = "cci_0_clk_src"; + pinctrl-0 = <&cci0_active &cci1_active>; + pinctrl-1 = <&cci0_suspend &cci1_suspend>; + pinctrl-names = "cam_default", "cam_suspend"; + gpios = <&tlmm 69 0>, + <&tlmm 70 0>, + <&tlmm 71 0>, + <&tlmm 72 0>; + gpio-req-tbl-num = <0 1 2 3>; + gpio-req-tbl-flags = <1 1 1 1>; + gpio-req-tbl-label = "CCI_I2C_DATA0", + "CCI_I2C_CLK0", + "CCI_I2C_DATA1", + "CCI_I2C_CLK1"; + cell-index = <0>; + status = "ok"; + + cci0_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-37500000 { + opp-hz = /bits/ 64 <37500000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + }; + + i2c_freq_custom_cci0: qcom,i2c-custom-mode { + hw-thigh = <38>; + hw-tlow = <56>; + hw-tsu-sto = <40>; + hw-tsu-sta = <40>; + hw-thd-dat = <22>; + hw-thd-sta = <35>; + hw-tbuf = <62>; + hw-scl-stretch-en = <1>; + hw-trdhld = <6>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + + i2c_freq_400Khz_cci0: qcom,i2c-fast-mode { + hw-thigh = <38>; + hw-tlow = <56>; + hw-tsu-sto = <40>; + hw-tsu-sta = <40>; + hw-thd-dat = <22>; + hw-thd-sta = <35>; + hw-tbuf = <62>; + hw-scl-stretch-en = <0>; + hw-trdhld = <6>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + + i2c_freq_1Mhz_cci0: qcom,i2c-fast-plus-mode { + hw-thigh = <16>; + hw-tlow = <22>; + hw-tsu-sto = <17>; + hw-tsu-sta = <18>; + hw-thd-dat = <16>; + hw-thd-sta = <15>; + hw-tbuf = <24>; + hw-scl-stretch-en = <0>; + hw-trdhld = <3>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + + i2c_freq_100Khz_cci0: qcom,i2c-standard-mode { + hw-thigh = <201>; + hw-tlow = <174>; + hw-tsu-sto = <204>; + hw-tsu-sta = <231>; + hw-thd-dat = <22>; + hw-thd-sta = <162>; + hw-tbuf = <227>; + hw-scl-stretch-en = <0>; + hw-trdhld = <6>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + }; + + cam_cci1: qcom,cci1 { + compatible = "qcom,cci", "simple-bus"; + reg = <0x0 0xac4b000 0x0 0x1000>; + reg-names = "cci"; + reg-cam-base = <0x4b000>; + interrupts = ; + interrupt-names = "cci"; + operating-points-v2 = <&cci1_opp_table>; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + clocks = <&camcc CAM_CC_CCI_1_CLK_SRC>, + <&camcc CAM_CC_CCI_1_CLK>; + clock-names = "cci_1_clk_src", + "cci_1_clk"; + clock-rates = <37500000 0>; + clock-cntl-level = "lowsvs"; + src-clock-name = "cci_1_clk_src"; + pinctrl-0 = <&cci2_active &cci3_active>; + pinctrl-1 = <&cci2_suspend &cci3_suspend>; + pinctrl-names = "cam_default", "cam_suspend"; + gpios = <&tlmm 73 0>, + <&tlmm 74 0>, + <&tlmm 75 0>, + <&tlmm 76 0>; + gpio-req-tbl-num = <0 1 2 3>; + gpio-req-tbl-flags = <1 1 1 1>; + gpio-req-tbl-label = "CCI_I2C_DATA2", + "CCI_I2C_CLK2", + "CCI_I2C_DATA3", + "CCI_I2C_CLK3"; + cell-index = <1>; + status = "ok"; + + cci1_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-37500000 { + opp-hz = /bits/ 64 <37500000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + }; + + i2c_freq_custom_cci1: qcom,i2c-custom-mode { + hw-thigh = <38>; + hw-tlow = <56>; + hw-tsu-sto = <40>; + hw-tsu-sta = <40>; + hw-thd-dat = <22>; + hw-thd-sta = <35>; + hw-tbuf = <62>; + hw-scl-stretch-en = <1>; + hw-trdhld = <6>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + + i2c_freq_400Khz_cci1: qcom,i2c-fast-mode { + hw-thigh = <38>; + hw-tlow = <56>; + hw-tsu-sto = <40>; + hw-tsu-sta = <40>; + hw-thd-dat = <22>; + hw-thd-sta = <35>; + hw-tbuf = <62>; + hw-scl-stretch-en = <0>; + hw-trdhld = <6>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + + i2c_freq_1Mhz_cci1: qcom,i2c-fast-plus-mode { + hw-thigh = <16>; + hw-tlow = <22>; + hw-tsu-sto = <17>; + hw-tsu-sta = <18>; + hw-thd-dat = <16>; + hw-thd-sta = <15>; + hw-tbuf = <24>; + hw-scl-stretch-en = <0>; + hw-trdhld = <3>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + + i2c_freq_100Khz_cci1: qcom,i2c-standard-mode { + hw-thigh = <201>; + hw-tlow = <174>; + hw-tsu-sto = <204>; + hw-tsu-sta = <231>; + hw-thd-dat = <22>; + hw-thd-sta = <162>; + hw-tbuf = <227>; + hw-scl-stretch-en = <0>; + hw-trdhld = <6>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + }; + + qcom,cpas-cdm0 { + compatible = "qcom,cam170-cpas-cdm0"; + cell-index = <0>; + label = "cpas-cdm"; + reg = <0x0 0xac48000 0x0 0x1000>; + reg-names = "cpas-cdm"; + reg-cam-base = <0x48000>; + interrupts = ; + interrupt-names = "cpas-cdm"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + clocks = <&camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&camcc CAM_CC_CPAS_AHB_CLK>; + clock-names = "cam_cc_slow_ahb_clk_src", + "cam_cc_cpas_ahb_clk"; + clock-rates = <80000000 0>; + clock-cntl-level = "svs"; + src-clock-name = "cam_cc_slow_ahb_clk_src"; + operating-points-v2 = <&cdm_cpas_opp_table>; + cdm-client-names = "ife0", "ife1", "ife2", + "ife3", "ife4", "dualife"; + status = "ok"; + + cdm_cpas_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-80000000 { + opp-hz = /bits/ 64 <80000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + }; + }; + + cam_csid0: qcom,csid0 { + compatible = "qcom,csid165_204"; + cell-index = <0>; + reg = <0x0 0xacb3000 0x0 0x1000>; + reg-names = "csid"; + reg-cam-base = <0xb3000>; + interrupts = ; + interrupt-names = "csid0"; + power-domains = <&camcc CAM_CC_IFE_0_GDSC>; + clocks = <&camcc CAM_CC_IFE_0_CSID_CLK_SRC>, + <&camcc CAM_CC_IFE_0_CSID_CLK>, + <&camcc CAM_CC_IFE_0_CPHY_RX_CLK>, + <&camcc CAM_CC_IFE_0_CLK_SRC>, + <&camcc CAM_CC_IFE_0_CLK>, + <&camcc CAM_CC_IFE_0_AXI_CLK>; + clock-names = "ife_csid_clk_src", + "ife_csid_clk", + "ife_cphy_rx_clk", + "ife_clk_src", + "ife_clk", + "ife_axi_clk"; + clock-rates = <300000000 0 0 380000000 0 0>, + <400000000 0 0 510000000 0 0>, + <400000000 0 0 637000000 0 0>, + <400000000 0 0 760000000 0 0>; + clock-cntl-level = "lowsvs", "svs", "svs_l1", "turbo"; + src-clock-name = "ife_csid_clk_src"; + operating-points-v2 = <&csid0_opp_table>; + clock-control-debugfs = "true"; + status = "ok"; + + csid0_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-380000000 { + opp-hz = /bits/ 64 <380000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + + opp-510000000 { + opp-hz = /bits/ 64 <510000000>; + required-opps = <&rpmhpd_opp_svs>; + }; + + opp-637000000 { + opp-hz = /bits/ 64 <637000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-760000000 { + opp-hz = /bits/ 64 <760000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + }; + }; + + cam_csid1: qcom,csid1 { + compatible = "qcom,csid165_204"; + cell-index = <1>; + reg = <0x0 0xacba000 0x0 0x1000>; + reg-names = "csid"; + reg-cam-base = <0xba000>; + interrupts = ; + interrupt-names = "csid1"; + power-domains = <&camcc CAM_CC_IFE_1_GDSC>; + clocks = <&camcc CAM_CC_IFE_1_CSID_CLK_SRC>, + <&camcc CAM_CC_IFE_1_CSID_CLK>, + <&camcc CAM_CC_IFE_1_CPHY_RX_CLK>, + <&camcc CAM_CC_IFE_1_CLK_SRC>, + <&camcc CAM_CC_IFE_1_CLK>, + <&camcc CAM_CC_IFE_1_AXI_CLK>; + clock-names = "ife_csid_clk_src", + "ife_csid_clk", + "ife_cphy_rx_clk", + "ife_clk_src", + "ife_clk", + "ife_axi_clk"; + clock-rates = <300000000 0 0 380000000 0 0>, + <400000000 0 0 510000000 0 0>, + <400000000 0 0 637000000 0 0>, + <400000000 0 0 760000000 0 0>; + clock-cntl-level = "lowsvs", "svs", "svs_l1", "turbo"; + src-clock-name = "ife_csid_clk_src"; + operating-points-v2 = <&csid1_opp_table>; + clock-control-debugfs = "true"; + status = "ok"; + + csid1_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-380000000 { + opp-hz = /bits/ 64 <380000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + + opp-510000000 { + opp-hz = /bits/ 64 <510000000>; + required-opps = <&rpmhpd_opp_svs>; + }; + + opp-637000000 { + opp-hz = /bits/ 64 <637000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-760000000 { + opp-hz = /bits/ 64 <760000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + }; + }; + + cam_csid2: qcom,csid2 { + compatible = "qcom,csid165_204"; + cell-index = <2>; + reg = <0x0 0x0acc1000 0x0 0x1000>; + reg-names = "csid"; + reg-cam-base = <0xc1000>; + interrupts = ; + interrupt-names = "csid2"; + power-domains = <&camcc CAM_CC_IFE_2_GDSC>; + clocks = <&camcc CAM_CC_IFE_2_CSID_CLK_SRC>, + <&camcc CAM_CC_IFE_2_CSID_CLK>, + <&camcc CAM_CC_IFE_2_CPHY_RX_CLK>, + <&camcc CAM_CC_IFE_2_CLK_SRC>, + <&camcc CAM_CC_IFE_2_CLK>, + <&camcc CAM_CC_IFE_2_AXI_CLK>; + clock-names = "ife_csid_clk_src", + "ife_csid_clk", + "ife_cphy_rx_clk", + "ife_clk_src", + "ife_clk", + "ife_axi_clk"; + clock-rates = <300000000 0 0 380000000 0 0>, + <400000000 0 0 510000000 0 0>, + <400000000 0 0 637000000 0 0>, + <400000000 0 0 760000000 0 0>; + clock-cntl-level = "lowsvs", "svs", "svs_l1", "turbo"; + src-clock-name = "ife_csid_clk_src"; + operating-points-v2 = <&csid2_opp_table>; + clock-control-debugfs = "true"; + status = "ok"; + + csid2_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-380000000 { + opp-hz = /bits/ 64 <380000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + + opp-510000000 { + opp-hz = /bits/ 64 <510000000>; + required-opps = <&rpmhpd_opp_svs>; + }; + + opp-637000000 { + opp-hz = /bits/ 64 <637000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-760000000 { + opp-hz = /bits/ 64 <760000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + }; + }; + + cam_csid_lite0: qcom,csid-lite0 { + compatible = "qcom,csid-lite165"; + cell-index = <3>; + reg = <0x0 0xacc8000 0x0 0x1000>; + reg-names = "csid-lite"; + reg-cam-base = <0xc8000>; + interrupts = ; + interrupt-names = "csid-lite0"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + clocks = <&camcc CAM_CC_IFE_LITE_0_CSID_CLK_SRC>, + <&camcc CAM_CC_IFE_LITE_0_CSID_CLK>, + <&camcc CAM_CC_IFE_LITE_0_CPHY_RX_CLK>, + <&camcc CAM_CC_IFE_LITE_0_CLK_SRC>, + <&camcc CAM_CC_IFE_LITE_0_CLK>; + clock-names = "ife_csid_clk_src", + "ife_csid_clk", + "ife_cphy_rx_clk", + "ife_clk_src", + "ife_clk"; + clock-rates = <300000000 0 0 320000000 0>, + <400000000 0 0 400000000 0>, + <400000000 0 0 480000000 0>, + <400000000 0 0 600000000 0>; + clock-cntl-level = "lowsvs", "svs", "svs_l1", "turbo"; + src-clock-name = "ife_csid_clk_src"; + operating-points-v2 = <&csid_lite0_opp_table>; + clock-control-debugfs = "true"; + status = "ok"; + + csid_lite0_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-320000000 { + opp-hz = /bits/ 64 <320000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + + opp-400000000 { + opp-hz = /bits/ 64 <400000000>; + required-opps = <&rpmhpd_opp_svs>; + }; + + opp-480000000 { + opp-hz = /bits/ 64 <480000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-600000000 { + opp-hz = /bits/ 64 <600000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + }; + }; + + cam_csid_lite1: qcom,csid-lite1 { + compatible = "qcom,csid-lite165"; + cell-index = <4>; + reg = <0x0 0x0accf000 0x0 0x1000>; + reg-names = "csid-lite"; + reg-cam-base = <0xcf000>; + interrupts = ; + interrupt-names = "csid-lite1"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + clocks = <&camcc CAM_CC_IFE_LITE_1_CSID_CLK_SRC>, + <&camcc CAM_CC_IFE_LITE_1_CSID_CLK>, + <&camcc CAM_CC_IFE_LITE_1_CPHY_RX_CLK>, + <&camcc CAM_CC_IFE_LITE_1_CLK_SRC>, + <&camcc CAM_CC_IFE_LITE_1_CLK>; + clock-names = "ife_csid_clk_src", + "ife_csid_clk", + "ife_cphy_rx_clk", + "ife_clk_src", + "ife_clk"; + clock-rates = <300000000 0 0 320000000 0>, + <400000000 0 0 400000000 0>, + <400000000 0 0 480000000 0>, + <400000000 0 0 600000000 0>; + clock-cntl-level = "lowsvs", "svs", "svs_l1", "turbo"; + src-clock-name = "ife_csid_clk_src"; + operating-points-v2 = <&csid_lite1_opp_table>; + clock-control-debugfs = "true"; + status = "ok"; + + csid_lite1_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-320000000 { + opp-hz = /bits/ 64 <320000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + + opp-400000000 { + opp-hz = /bits/ 64 <400000000>; + required-opps = <&rpmhpd_opp_svs>; + }; + + opp-480000000 { + opp-hz = /bits/ 64 <480000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-600000000 { + opp-hz = /bits/ 64 <600000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + }; + }; + + cam_csiphy0: qcom,csiphy0 { + compatible = "qcom,csiphy-v1.2.1", "qcom,csiphy"; + cell-index = <0>; + reg = <0x0 0x0ace0000 0x0 0x2000>; + reg-names = "csiphy"; + reg-cam-base = <0xe0000>; + interrupts = ; + interrupt-names = "csiphy0"; + operating-points-v2 = <&csiphy0_opp_table>; + csi-vdd-1p2-supply = <&vreg_l6b_1p2>; + csi-vdd-0p9-supply = <&vreg_l10c_0p88>; + regulator-names = "csi-vdd-1p2", "csi-vdd-0p9"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + rgltr-cntrl-support; + rgltr-min-voltage = <1200000 880000>; + rgltr-max-voltage = <1260000 1050000>; + rgltr-load-current = <54000 96400>; + clocks = <&camcc CAM_CC_CPHY_RX_CLK_SRC>, + <&camcc CAM_CC_CSIPHY0_CLK>, + <&camcc CAM_CC_CSI0PHYTIMER_CLK_SRC>, + <&camcc CAM_CC_CSI0PHYTIMER_CLK>; + clock-names = "cphy_rx_clk_src", + "csiphy0_clk", + "csi0phytimer_clk_src", + "csi0phytimer_clk"; + clock-rates = <300000000 0 300000000 0>, + <400000000 0 300000000 0>; + clock-cntl-level = "lowsvs", "svs"; + src-clock-name = "csi0phytimer_clk_src"; + status = "ok"; + + csiphy0_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-300000000 { + opp-hz = /bits/ 64 <300000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + + opp-400000000 { + opp-hz = /bits/ 64 <400000000>; + required-opps = <&rpmhpd_opp_svs>; + }; + }; + }; + + cam_csiphy1: qcom,csiphy1 { + cell-index = <1>; + compatible = "qcom,csiphy-v1.2.1", "qcom,csiphy"; + reg = <0x0 0xace2000 0x0 0x2000>; + reg-names = "csiphy"; + reg-cam-base = <0xe2000>; + interrupts = ; + interrupt-names = "csiphy1"; + operating-points-v2 = <&csiphy1_opp_table>; + csi-vdd-1p2-supply = <&vreg_l6b_1p2>; + csi-vdd-0p9-supply = <&vreg_l10c_0p88>; + regulator-names = "csi-vdd-1p2", "csi-vdd-0p9"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + rgltr-cntrl-support; + rgltr-min-voltage = <1200000 880000>; + rgltr-max-voltage = <1260000 1050000>; + rgltr-load-current = <54000 96400>; + clocks = <&camcc CAM_CC_CPHY_RX_CLK_SRC>, + <&camcc CAM_CC_CSIPHY1_CLK>, + <&camcc CAM_CC_CSI1PHYTIMER_CLK_SRC>, + <&camcc CAM_CC_CSI1PHYTIMER_CLK>; + clock-names = "cphy_rx_clk_src", + "csiphy1_clk", + "csi1phytimer_clk_src", + "csi1phytimer_clk"; + src-clock-name = "csi1phytimer_clk_src"; + clock-cntl-level = "lowsvs", "svs"; + clock-rates = <300000000 0 300000000 0>, + <400000000 0 300000000 0>; + status = "ok"; + + csiphy1_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-300000000 { + opp-hz = /bits/ 64 <300000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + + opp-400000000 { + opp-hz = /bits/ 64 <400000000>; + required-opps = <&rpmhpd_opp_svs>; + }; + }; + }; + + cam_csiphy2: qcom,csiphy2 { + cell-index = <2>; + compatible = "qcom,csiphy-v1.2.1", "qcom,csiphy"; + reg = <0x0 0xace4000 0x0 0x2000>; + reg-names = "csiphy"; + reg-cam-base = <0xe4000>; + interrupts = ; + interrupt-names = "csiphy2"; + operating-points-v2 = <&csiphy2_opp_table>; + csi-vdd-1p2-supply = <&vreg_l6b_1p2>; + csi-vdd-0p9-supply = <&vreg_l10c_0p88>; + regulator-names = "csi-vdd-1p2", "csi-vdd-0p9"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + rgltr-cntrl-support; + rgltr-min-voltage = <1200000 880000>; + rgltr-max-voltage = <1260000 1050000>; + rgltr-load-current = <54000 96400>; + clocks = <&camcc CAM_CC_CPHY_RX_CLK_SRC>, + <&camcc CAM_CC_CSIPHY2_CLK>, + <&camcc CAM_CC_CSI2PHYTIMER_CLK_SRC>, + <&camcc CAM_CC_CSI2PHYTIMER_CLK>; + clock-names = "cphy_rx_clk_src", + "csiphy2_clk", + "csi2phytimer_clk_src", + "csi2phytimer_clk"; + src-clock-name = "csi2phytimer_clk_src"; + clock-cntl-level = "lowsvs", "svs"; + clock-rates = <300000000 0 300000000 0>, + <400000000 0 300000000 0>; + status = "ok"; + + csiphy2_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-300000000 { + opp-hz = /bits/ 64 <300000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + + opp-400000000 { + opp-hz = /bits/ 64 <400000000>; + required-opps = <&rpmhpd_opp_svs>; + }; + }; + }; + + cam_csiphy3: qcom,csiphy3 { + cell-index = <3>; + compatible = "qcom,csiphy-v1.2.1", "qcom,csiphy"; + reg = <0x0 0xace6000 0x0 0x2000>; + reg-names = "csiphy"; + reg-cam-base = <0xe6000>; + interrupts = ; + interrupt-names = "csiphy3"; + operating-points-v2 = <&csiphy3_opp_table>; + csi-vdd-1p2-supply = <&vreg_l6b_1p2>; + csi-vdd-0p9-supply = <&vreg_l10c_0p88>; + regulator-names = "csi-vdd-1p2", "csi-vdd-0p9"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + rgltr-cntrl-support; + rgltr-min-voltage = <1200000 880000>; + rgltr-max-voltage = <1260000 1050000>; + rgltr-load-current = <54000 96400>; + clocks = <&camcc CAM_CC_CPHY_RX_CLK_SRC>, + <&camcc CAM_CC_CSIPHY3_CLK>, + <&camcc CAM_CC_CSI3PHYTIMER_CLK_SRC>, + <&camcc CAM_CC_CSI3PHYTIMER_CLK>; + clock-names = "cphy_rx_clk_src", + "csiphy3_clk", + "csi3phytimer_clk_src", + "csi3phytimer_clk"; + src-clock-name = "csi3phytimer_clk_src"; + clock-cntl-level = "lowsvs", "svs"; + clock-rates = <300000000 0 300000000 0>, + <400000000 0 300000000 0>; + status = "ok"; + + csiphy3_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-300000000 { + opp-hz = /bits/ 64 <300000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + + opp-400000000 { + opp-hz = /bits/ 64 <400000000>; + required-opps = <&rpmhpd_opp_svs>; + }; + }; + }; + + cam_csiphy4: qcom,csiphy4 { + cell-index = <4>; + compatible = "qcom,csiphy-v1.2.1", "qcom,csiphy"; + reg = <0x0 0xace8000 0x0 0x2000>; + reg-names = "csiphy"; + reg-cam-base = <0xe8000>; + interrupts = ; + interrupt-names = "csiphy4"; + operating-points-v2 = <&csiphy4_opp_table>; + csi-vdd-1p2-supply = <&vreg_l6b_1p2>; + csi-vdd-0p9-supply = <&vreg_l10c_0p88>; + regulator-names = "csi-vdd-1p2", "csi-vdd-0p9"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + rgltr-cntrl-support; + rgltr-min-voltage = <1200000 880000>; + rgltr-max-voltage = <1260000 1050000>; + rgltr-load-current = <54000 96400>; + clocks = <&camcc CAM_CC_CPHY_RX_CLK_SRC>, + <&camcc CAM_CC_CSIPHY4_CLK>, + <&camcc CAM_CC_CSI4PHYTIMER_CLK_SRC>, + <&camcc CAM_CC_CSI4PHYTIMER_CLK>; + clock-names = "cphy_rx_clk_src", + "csiphy4_clk", + "csi4phytimer_clk_src", + "csi4phytimer_clk"; + src-clock-name = "csi4phytimer_clk_src"; + clock-cntl-level = "lowsvs", "svs"; + clock-rates = <300000000 0 300000000 0>, + <400000000 0 300000000 0>; + status = "ok"; + + csiphy4_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-300000000 { + opp-hz = /bits/ 64 <300000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + + opp-400000000 { + opp-hz = /bits/ 64 <400000000>; + required-opps = <&rpmhpd_opp_svs>; + }; + }; + }; + + cam_ipe0: qcom,ipe0 { + compatible = "qcom,cam-ipe"; + cell-index = <0>; + reg = <0x0 0xac87000 0x0 0xa000>; + reg-names = "ipe0_top"; + reg-cam-base = <0x87000>; + power-domains = <&camcc CAM_CC_IPE_0_GDSC>; + clocks = <&camcc CAM_CC_IPE_0_AHB_CLK>, + <&camcc CAM_CC_IPE_0_AREG_CLK>, + <&camcc CAM_CC_IPE_0_AXI_CLK>, + <&camcc CAM_CC_IPE_0_CLK_SRC>, + <&camcc CAM_CC_IPE_0_CLK>; + clock-names = "ipe_0_ahb_clk", + "ipe_0_areg_clk", + "ipe_0_axi_clk", + "ipe_0_clk_src", + "ipe_0_clk"; + clock-rates = <0 0 0 300000000 0>, + <0 0 0 430000000 0>, + <0 0 0 520000000 0>, + <0 0 0 600000000 0>, + <0 0 0 600000000 0>; + clock-cntl-level = "lowsvs", "svs", "svs_l1", + "nominal", "turbo"; + src-clock-name = "ipe_0_clk_src"; + operating-points-v2 = <&ipe0_opp_table>; + clock-control-debugfs = "true"; + status = "ok"; + + ipe0_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-300000000 { + opp-hz = /bits/ 64 <300000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + + opp-430000000 { + opp-hz = /bits/ 64 <430000000>; + required-opps = <&rpmhpd_opp_svs>; + }; + + opp-520000000 { + opp-hz = /bits/ 64 <520000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-600000000 { + opp-hz = /bits/ 64 <600000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + }; + }; + + cam_jpeg_dma: qcom,jpegdma { + compatible = "qcom,cam_jpeg_dma_165"; + cell-index = <0>; + reg = <0x0 0xac52000 0x0 0x4000>, + <0x0 0x0ac9f000 0x0 0x10000>; + reg-names = "jpegdma_hw", "cam_camnoc"; + reg-cam-base = <0x52000 0x9f000>; + interrupts = ; + interrupt-names = "jpegdma"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + clocks = <&camcc CAM_CC_JPEG_CLK_SRC>, + <&camcc CAM_CC_JPEG_CLK>; + clock-names = "jpegdma_clk_src", + "jpegdma_clk"; + clock-rates = <600000000 0>; + clock-cntl-level = "nominal"; + src-clock-name = "jpegdma_clk_src"; + operating-points-v2 = <&jpeg_dma_opp_table>; + cam_hw_pid = <20 21>; + cam_hw_rd_mid = <0>; + cam_hw_wr_mid = <2>; + status = "ok"; + + jpeg_dma_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-600000000 { + opp-hz = /bits/ 64 <600000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + }; + }; + + cam_jpeg_enc: qcom,jpegenc { + compatible = "qcom,cam_jpeg_enc_165"; + cell-index = <0>; + reg = <0x0 0xac4e000 0x0 0x4000>, + <0x0 0x0ac9f000 0x0 0x10000>; + reg-names = "jpege_hw", "cam_camnoc"; + reg-cam-base = <0x4e000 0x9f000>; + interrupts = ; + interrupt-names = "jpeg"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + clocks = <&camcc CAM_CC_JPEG_CLK_SRC>, + <&camcc CAM_CC_JPEG_CLK>; + clock-names = "jpegenc_clk_src", + "jpegenc_clk"; + clock-rates = <600000000 0>; + clock-cntl-level = "nominal"; + src-clock-name = "jpegenc_clk_src"; + operating-points-v2 = <&jpeg_enc_opp_table>; + cam_hw_pid = <22 23>; + cam_hw_rd_mid = <0>; + cam_hw_wr_mid = <2>; + status = "ok"; + + jpeg_enc_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-600000000 { + opp-hz = /bits/ 64 <600000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + }; + }; + + cam_lrme: qcom,lrme { + compatible = "qcom,lrme"; + cell-index = <0>; + reg = <0x0 0xac6b000 0x0 0x1000>; + reg-names = "lrme"; + reg-cam-base = <0x6b000>; + interrupts = ; + interrupt-names = "lrme"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + clocks = <&camcc CAM_CC_LRME_CLK_SRC>, + <&camcc CAM_CC_LRME_CLK>; + clock-names = "lrme_clk_src", + "lrme_clk"; + clock-rates = <240000000 0>, + <300000000 0>, + <320000000 0>, + <400000000 0>; + clock-cntl-level = "lowsvs", "svs", "svs_l1", "nominal"; + src-clock-name = "lrme_clk_src"; + operating-points-v2 = <&lrme_opp_table>; + status = "ok"; + + lrme_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-240000000 { + opp-hz = /bits/ 64 <240000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + + opp-300000000 { + opp-hz = /bits/ 64 <300000000>; + required-opps = <&rpmhpd_opp_svs>; + }; + + opp-320000000 { + opp-hz = /bits/ 64 <320000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-400000000 { + opp-hz = /bits/ 64 <400000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + }; + }; + + cam_vfe0: qcom,vfe0 { + compatible = "qcom,vfe165_160"; + reg = <0x0 0xacaf000 0x0 0x5200>; + reg-names = "ife"; + reg-cam-base = <0xaf000>; + interrupts = ; + interrupt-names = "ife0"; + power-domains = <&camcc CAM_CC_IFE_0_GDSC>; + clocks = <&camcc CAM_CC_IFE_0_CLK_SRC>, + <&camcc CAM_CC_IFE_0_CLK>, + <&camcc CAM_CC_IFE_0_AXI_CLK>; + clock-names = "ife_clk_src", + "ife_clk", + "ife_axi_clk"; + clock-rates = <380000000 0 0>, + <510000000 0 0>, + <637000000 0 0>, + <760000000 0 0>; + clock-cntl-level = "lowsvs", "svs", "svs_l1", "turbo"; + src-clock-name = "ife_clk_src"; + operating-points-v2 = <&vfe0_opp_table>; + clock-control-debugfs = "true"; + clock-names-option = "ife_dsp_clk"; + clocks-option = <&camcc CAM_CC_IFE_0_DSP_CLK>; + clock-rates-option = <760000000>; + cam_hw_pid = <24 8>; + cell-index = <0>; + status = "ok"; + + vfe0_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-380000000 { + opp-hz = /bits/ 64 <380000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + + opp-510000000 { + opp-hz = /bits/ 64 <510000000>; + required-opps = <&rpmhpd_opp_svs>; + }; + + opp-637000000 { + opp-hz = /bits/ 64 <637000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-760000000 { + opp-hz = /bits/ 64 <760000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + }; + }; + + cam_vfe1: qcom,vfe1 { + compatible = "qcom,vfe165_160"; + reg = <0x0 0xacb6000 0x0 0x5200>; + reg-names = "ife"; + reg-cam-base = <0xb6000>; + interrupts = ; + interrupt-names = "ife1"; + power-domains = <&camcc CAM_CC_IFE_1_GDSC>; + clocks = <&camcc CAM_CC_IFE_1_CLK_SRC>, + <&camcc CAM_CC_IFE_1_CLK>, + <&camcc CAM_CC_IFE_1_AXI_CLK>; + clock-names = "ife_clk_src", + "ife_clk", + "ife_axi_clk"; + clock-rates = <380000000 0 0>, + <510000000 0 0>, + <637000000 0 0>, + <760000000 0 0>; + clock-cntl-level = "lowsvs", "svs", "svs_l1", "turbo"; + src-clock-name = "ife_clk_src"; + operating-points-v2 = <&vfe1_opp_table>; + clock-control-debugfs = "true"; + clock-names-option = "ife_dsp_clk"; + clocks-option = <&camcc CAM_CC_IFE_1_DSP_CLK>; + clock-rates-option = <760000000>; + cam_hw_pid = <25 9>; + cell-index = <1>; + status = "ok"; + + vfe1_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-380000000 { + opp-hz = /bits/ 64 <380000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + + opp-510000000 { + opp-hz = /bits/ 64 <510000000>; + required-opps = <&rpmhpd_opp_svs>; + }; + + opp-637000000 { + opp-hz = /bits/ 64 <637000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-760000000 { + opp-hz = /bits/ 64 <760000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + }; + }; + + + cam_vfe2: qcom,vfe2 { + compatible = "qcom,vfe165_160"; + reg = <0x0 0x0acbd000 0x0 0x5200>; + reg-names = "ife"; + reg-cam-base = <0xbd000>; + interrupts = ; + interrupt-names = "ife2"; + power-domains = <&camcc CAM_CC_IFE_2_GDSC>; + clocks = <&camcc CAM_CC_IFE_2_CLK_SRC>, + <&camcc CAM_CC_IFE_2_CLK>, + <&camcc CAM_CC_IFE_2_AXI_CLK>; + clock-names = "ife_clk_src", + "ife_clk", + "ife_axi_clk"; + clock-rates = <380000000 0 0>, + <510000000 0 0>, + <637000000 0 0>, + <760000000 0 0>; + clock-cntl-level = "lowsvs", "svs", "svs_l1", "turbo"; + src-clock-name = "ife_clk_src"; + operating-points-v2 = <&vfe2_opp_table>; + clock-control-debugfs = "true"; + clock-names-option = "ife_dsp_clk"; + clocks-option = <&camcc CAM_CC_IFE_2_DSP_CLK>; + clock-rates-option = <760000000>; + cam_hw_pid = <3 10>; + cell-index = <2>; + status = "ok"; + + vfe2_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-380000000 { + opp-hz = /bits/ 64 <380000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + + opp-510000000 { + opp-hz = /bits/ 64 <510000000>; + required-opps = <&rpmhpd_opp_svs>; + }; + + opp-637000000 { + opp-hz = /bits/ 64 <637000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-760000000 { + opp-hz = /bits/ 64 <760000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + }; + }; + + cam_vfe_lite0: qcom,vfe-lite0 { + compatible = "qcom,vfe-lite165"; + cell-index = <3>; + reg = <0x0 0xacc4000 0x0 0x5000>; + reg-names = "ife-lite"; + reg-cam-base = <0xc4000>; + interrupts = ; + interrupt-names = "ife-lite0"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + clocks = <&camcc CAM_CC_IFE_LITE_0_CLK_SRC>, + <&camcc CAM_CC_IFE_LITE_0_CLK>; + clock-names = "ife_clk_src", + "ife_clk"; + clock-rates = <320000000 0>, + <400000000 0>, + <480000000 0>, + <600000000 0>; + clock-cntl-level = "lowsvs", "svs", "svs_l1", "turbo"; + src-clock-name = "ife_clk_src"; + operating-points-v2 = <&vfe_lite0_opp_table>; + clock-control-debugfs = "true"; + cam_hw_pid = <11>; + status = "ok"; + + vfe_lite0_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-320000000 { + opp-hz = /bits/ 64 <320000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + + opp-400000000 { + opp-hz = /bits/ 64 <400000000>; + required-opps = <&rpmhpd_opp_svs>; + }; + + opp-480000000 { + opp-hz = /bits/ 64 <480000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-600000000 { + opp-hz = /bits/ 64 <600000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + }; + }; + + cam_vfe_lite1: qcom,vfe-lite1 { + compatible = "qcom,vfe-lite165"; + reg = <0x0 0x0accb000 0x0 0x5000>; + reg-names = "ife-lite"; + reg-cam-base = <0xcb000>; + interrupts = ; + interrupt-names = "ife-lite1"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + clocks = <&camcc CAM_CC_IFE_LITE_1_CLK_SRC>, + <&camcc CAM_CC_IFE_LITE_1_CLK>; + clock-names = "ife_clk_src", + "ife_clk"; + clock-rates = <320000000 0>, + <400000000 0>, + <480000000 0>, + <600000000 0>; + clock-cntl-level = "lowsvs", "svs", "svs_l1", "turbo"; + src-clock-name = "ife_clk_src"; + operating-points-v2 = <&vfe_lite1_opp_table>; + clock-control-debugfs = "true"; + cam_hw_pid = <12>; + cell-index = <4>; + status = "ok"; + + vfe_lite1_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-320000000 { + opp-hz = /bits/ 64 <320000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + + opp-400000000 { + opp-hz = /bits/ 64 <400000000>; + required-opps = <&rpmhpd_opp_svs>; + }; + + opp-480000000 { + opp-hz = /bits/ 64 <480000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-600000000 { + opp-hz = /bits/ 64 <600000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + }; + }; +}; + +&tlmm { + cam_sensor_active_mux: cam-sensor-active-mux { + /* GC630 bypass mux */ + mux { + pins = "gpio1"; + function = "gpio"; + }; + + config { + pins = "gpio1"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_active_rst0: cam-sensor-active-rst0 { + /* RESET REAR */ + mux { + pins = "gpio20"; + function = "gpio"; + }; + + config { + pins = "gpio20"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_active_rst1: cam-sensor-active-rst1 { + /* RESET REARAUX */ + mux { + pins = "gpio21"; + function = "gpio"; + }; + + config { + pins = "gpio21"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_active_rst2: cam-sensor-active-rst2 { + /* RESET 2 */ + mux { + pins = "gpio77"; + function = "gpio"; + }; + + config { + pins = "gpio77"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_active_rst3: cam-sensor-active-rst3 { + /* RESET 3 */ + mux { + pins = "gpio78"; + function = "gpio"; + }; + + config { + pins = "gpio78"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_active_rst4: cam-sensor-active-rst4 { + /* RESET 4 */ + mux { + pins = "gpio79"; + function = "gpio"; + }; + + config { + pins = "gpio79"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk0_active: cam_sensor-mclk0-active { + /* MCLK0 */ + mux { + pins = "gpio64"; + function = "cam_mclk"; + }; + + config { + pins = "gpio64"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk0_suspend: cam-sensor-mclk0-suspend { + /* MCLK0 */ + mux { + pins = "gpio64"; + function = "cam_mclk"; + }; + + config { + pins = "gpio64"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk1_active: cam-sensor-mclk1-active { + /* MCLK1 */ + mux { + pins = "gpio65"; + function = "cam_mclk"; + }; + + config { + pins = "gpio65"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk1_suspend: cam-sensor-mclk1-suspend { + /* MCLK1 */ + mux { + pins = "gpio65"; + function = "cam_mclk"; + }; + + config { + pins = "gpio65"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk2_active: cam-sensor-mclk2-active { + /* MCLK2 */ + mux { + pins = "gpio66"; + function = "cam_mclk"; + }; + + config { + pins = "gpio66"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk2_suspend: cam-sensor-mclk2-suspend { + /* MCLK2 */ + mux { + pins = "gpio66"; + function = "cam_mclk"; + }; + + config { + pins = "gpio66"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk3_active: cam-sensor-mclk3-active { + /* MCLK3 */ + mux { + pins = "gpio67"; + function = "cam_mclk"; + }; + + config { + pins = "gpio67"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk3_suspend: cam-sensor-mclk3-suspend { + /* MCLK3 */ + mux { + pins = "gpio67"; + function = "cam_mclk"; + }; + + config { + pins = "gpio67"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk4_active: cam-sensor-mclk4-active { + /* MCLK4 */ + mux { + pins = "gpio68"; + function = "cam_mclk"; + }; + + config { + pins = "gpio68"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk4_suspend: cam-sensor-mclk4-suspend { + /* MCLK4 */ + mux { + pins = "gpio68"; + function = "cam_mclk"; + }; + + config { + pins = "gpio68"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk5_active: cam-sensor-mclk5-active { + /* MCLK5 */ + mux { + pins = "gpio98"; + function = "cam_mclk"; + }; + + config { + pins = "gpio98"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk5_suspend: cam-sensor-mclk5-suspend { + /* MCLK5 */ + mux { + pins = "gpio98"; + function = "cam_mclk"; + }; + + config { + pins = "gpio98"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_suspend_mux: cam-sensor-suspend-mux { + /* GC630 bypass mux */ + mux { + pins = "gpio1"; + function = "gpio"; + }; + + config { + pins = "gpio1"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; + }; + + cam_sensor_suspend_rst0: cam_sensor-suspend-rst0 { + /* RESET REAR */ + mux { + pins = "gpio20"; + function = "gpio"; + }; + + config { + pins = "gpio20"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; + }; + + cam_sensor_suspend_rst1: cam-sensor-suspend-rst1 { + /* RESET REARAUX */ + mux { + pins = "gpio21"; + function = "gpio"; + }; + + config { + pins = "gpio21"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; + }; + + cam_sensor_suspend_rst2: cam-sensor-suspend-rst2 { + /* RESET 2 */ + mux { + pins = "gpio77"; + function = "gpio"; + }; + + config { + pins = "gpio77"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; + }; + + cam_sensor_suspend_rst3: cam-sensor-suspend-rst3 { + /* RESET 3 */ + mux { + pins = "gpio78"; + function = "gpio"; + }; + + config { + pins = "gpio78"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; + }; + + cam_sensor_suspend_rst4: cam-sensor-suspend-rst4 { + /* RESET 4 */ + mux { + pins = "gpio79"; + function = "gpio"; + }; + + config { + pins = "gpio79"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; + }; + + cci0_active: cci0-active { + mux { + /* DATA, CLK */ + pins = "gpio69","gpio70"; // Only 2 + function = "cci_i2c"; + }; + + config { + pins = "gpio69","gpio70"; + bias-pull-up; /* PULL UP*/ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cci0_suspend: cci0-suspend { + mux { + /* DATA, CLK */ + pins = "gpio69","gpio70"; + function = "cci_i2c"; + }; + + config { + pins = "gpio69","gpio70"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cci1_active: cci1-active { + mux { + /* DATA, CLK */ + pins = "gpio71","gpio72"; + function = "cci_i2c"; + }; + + config { + pins = "gpio71","gpio72"; + bias-pull-up; /* PULL UP*/ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cci1_suspend: cci1-suspend { + mux { + /* DATA, CLK */ + pins = "gpio71","gpio72"; + function = "cci_i2c"; + }; + + config { + pins = "gpio71","gpio72"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cci2_active: cci2-active { + mux { + /* DATA, CLK */ + pins = "gpio73","gpio74"; + function = "cci_i2c"; + }; + + config { + pins = "gpio73","gpio74"; + bias-pull-up; /* PULL UP*/ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cci2_suspend: cci2-suspend { + mux { + /* DATA, CLK */ + pins = "gpio73","gpio74"; + function = "cci_i2c"; + }; + + config { + pins = "gpio73","gpio74"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cci3_active: cci3-active { + mux { + /* DATA, CLK */ + pins = "gpio75","gpio76"; + function = "cci_i2c"; + }; + + config { + pins = "gpio75","gpio76"; + bias-pull-up; /* PULL UP*/ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cci3_suspend: cci3-suspend { + mux { + /* DATA, CLK */ + pins = "gpio75","gpio76"; + function = "cci_i2c"; + }; + + config { + pins = "gpio75","gpio76"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + + }; +}; diff --git a/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2-camera-sensor.dtsi b/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2-camera-sensor.dtsi new file mode 100644 index 0000000000000..8b75b1a441db4 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2-camera-sensor.dtsi @@ -0,0 +1,551 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#include + +&cam_cci0 { + //cam1 interpose on dk csi0 + actuator_rear_cam11: qcom,actuator11 { + compatible = "qcom,actuator"; + cell-index = <11>; + cci-master = <1>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2856000>; + rgltr-max-voltage = <3104000>; + rgltr-load-current = <100000>; + }; + + eeprom_rear_cam11: qcom,eeprom11 { + compatible = "qcom,eeprom"; + cell-index = <11>; + cam_vio-supply = <&vreg_l18b_1p8>; + regulator-names = "cam_vio", "cam_clk"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 0>; + rgltr-max-voltage = <1800000 0>; + rgltr-load-current = <120000 0>; + gpio-no-mux = <0>; + pinctrl-0 = <&cam_sensor_mclk1_active + &cam_sensor_active_rst1>; + pinctrl-1 = <&cam_sensor_mclk1_suspend + &cam_sensor_suspend_rst1>; + pinctrl-names = "cam_default", "cam_suspend"; + gpios = <&tlmm 65 0>, + <&tlmm 21 0>, + <&pm7250b_gpios 3 0>; + gpio-reset = <1>; + gpio-custom1 = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAMIF_MCLK1", + "CAM_RESET1", + "CAM_CUSTOM1"; + sensor-mode = <0>; + cci-master = <1>; + clocks = <&camcc CAM_CC_MCLK1_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "nominal"; + clock-rates = <24000000>; + status = "ok"; + }; + + /*cam0a-ov9282*/ + qcom,cam-sensor1 { + compatible = "qcom,cam-sensor"; + cell-index = <1>; + csiphy-sd-index = <0>; + sensor-position-roll = <0>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + cam_vio-supply = <&vreg_l18b_1p8>; + regulator-names = "cam_vio"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000>; + rgltr-max-voltage = <1800000>; + rgltr-load-current = <120000>; + gpio-no-mux = <0>; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_active_rst0>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_suspend_rst0>; + pinctrl-names = "cam_default", "cam_suspend"; + gpios = <&tlmm 64 0>, + <&tlmm 20 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET0"; + cci-master = <0>; + clocks = <&camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "nominal"; + clock-rates = <24000000>; + status = "ok"; + }; + + /*cam1-ov9282*/ + qcom,cam-sensor6 { + compatible = "qcom,cam-sensor"; + cell-index = <6>; + csiphy-sd-index = <1>; + sensor-position-roll = <0>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + cam_vio-supply = <&vreg_l18b_1p8>; + regulator-names = "cam_vio"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000>; + rgltr-max-voltage = <1800000>; + rgltr-load-current = <120000>; + gpio-no-mux = <0>; + pinctrl-0 = <&cam_sensor_mclk1_active + &cam_sensor_active_rst1>; + pinctrl-1 = <&cam_sensor_mclk1_suspend + &cam_sensor_suspend_rst1>; + pinctrl-names = "cam_default", "cam_suspend"; + gpios = <&tlmm 65 0>, + <&tlmm 21 0>, + <&pm7250b_gpios 3 0>; + gpio-reset = <1>; + gpio-custom1 = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAMIF_MCLK1", + "CAM_RESET1", + "CAM_CUSTOM1"; + sensor-mode = <0>; + cci-master = <1>; + clocks = <&camcc CAM_CC_MCLK1_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "nominal"; + clock-rates = <24000000>; + status = "ok"; + }; + + /*cam1-imx586/imx686*/ + qcom,cam-sensor11 { + compatible = "qcom,cam-sensor"; + cell-index = <11>; + csiphy-sd-index = <1>; + sensor-position-roll = <0>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + actuator-src = <&actuator_rear_cam11>; + eeprom-src = <&eeprom_rear_cam11>; + cam_vio-supply = <&vreg_l18b_1p8>; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + regulator-names = "cam_vio", "cam_clk"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 0>; + rgltr-max-voltage = <1800000 0>; + rgltr-load-current = <120000 0>; + gpio-no-mux = <0>; + pinctrl-0 = <&cam_sensor_mclk1_active + &cam_sensor_active_rst1>; + pinctrl-1 = <&cam_sensor_mclk1_suspend + &cam_sensor_suspend_rst1>; + pinctrl-names = "cam_default", "cam_suspend"; + gpios = <&tlmm 65 0>, + <&tlmm 21 0>, + <&pm7250b_gpios 3 0>; + gpio-reset = <1>; + gpio-custom1 = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAMIF_MCLK1", + "CAM_RESET1", + "CAM_CUSTOM1"; + sensor-mode = <0>; + cci-master = <1>; + clocks = <&camcc CAM_CC_MCLK1_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "nominal"; + clock-rates = <24000000>; + status = "ok"; + }; + +}; + +&cam_cci1 { + eeprom_cam2: qcom,eeprom0 { + compatible = "qcom,eeprom"; + cell-index = <8>; + cam_vio-supply = <&vreg_l18b_1p8>; + regulator-names = "cam_vio"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000>; + rgltr-max-voltage = <1800000>; + rgltr-load-current = <120000>; + gpio-no-mux = <0>; + pinctrl-0 = <&cam_sensor_mclk2_active + &cam_sensor_active_rst2>; + pinctrl-1 = <&cam_sensor_mclk2_suspend + &cam_sensor_suspend_rst2>; + pinctrl-names = "cam_default", "cam_suspend"; + gpios = <&tlmm 66 0>, + <&tlmm 77 0>, + <&pm7250b_gpios 7 0>; + gpio-reset = <1>; + gpio-custom1 = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET2", + "CAM_CUSTOM1"; + sensor-mode = <0>; + cci-master = <0>; + clocks = <&camcc CAM_CC_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "nominal"; + clock-rates = <24000000>; + status = "ok"; + }; + + eeprom_cam3: qcom,eeprom3 { + compatible = "qcom,eeprom"; + cell-index = <0>; + cam_vio-supply = <&vreg_l18b_1p8>; + regulator-names = "cam_vio"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000>; + rgltr-max-voltage = <1800000>; + rgltr-load-current = <120000>; + gpio-no-mux = <0>; + pinctrl-0 = <&cam_sensor_mclk3_active + &cam_sensor_active_rst3>; + pinctrl-1 = <&cam_sensor_mclk3_suspend + &cam_sensor_suspend_rst3>; + pinctrl-names = "cam_default", "cam_suspend"; + gpios = <&tlmm 67 0>, + <&tlmm 78 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK3", + "CAM_RESET3"; + sensor-position = <1>; + sensor-mode = <0>; + cci-master = <1>; + qcom,cam-power-seq-type ="cam_reset","cam_vio", + "cam_clk","cam_reset"; + qcom,cam-power-seq-val = "cam_reset","cam_vio", + "cam_mclk","cam_reset"; + qcom,cam-power-seq-cfg-val = <0 1 24000000 1>; + qcom,cam-power-seq-delay = <1 0 1 18>; + clocks = <&camcc CAM_CC_MCLK3_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "nominal"; + clock-rates = <24000000>; + status = "ok"; + }; + + /*cam3-imx577*/ + qcom,cam-sensor0 { + compatible = "qcom,cam-sensor"; + cell-index = <0>; + csiphy-sd-index = <3>; + eeprom-src = <&eeprom_cam3>; + sensor-position-roll = <0>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + cam_vio-supply = <&vreg_l18b_1p8>; + regulator-names = "cam_vio"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000>; + rgltr-max-voltage = <1800000>; + rgltr-load-current = <120000>; + gpio-no-mux = <0>; + pinctrl-0 = <&cam_sensor_mclk3_active + &cam_sensor_active_rst3>; + pinctrl-1 = <&cam_sensor_mclk3_suspend + &cam_sensor_suspend_rst3>; + pinctrl-names = "cam_default", "cam_suspend"; + gpios = <&tlmm 67 0>, + <&tlmm 78 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK3", + "CAM_RESET3"; + sensor-mode = <0>; + cci-master = <1>; + clocks = <&camcc CAM_CC_MCLK3_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "nominal"; + clock-rates = <24000000>; + status = "ok"; + }; + + /* GMSL 1 */ + qcom,cam-sensor4 { + compatible = "qcom,cam-sensor"; + cell-index = <4>; + csiphy-sd-index = <4>; + sensor-position-roll = <0>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + cam_vio-supply = <&vreg_l18b_1p8>; + regulator-names = "cam_vio"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000>; + rgltr-max-voltage = <1800000>; + rgltr-load-current = <120000>; + gpio-no-mux = <0>; + gpios = <&tlmm 93 0>; + gpio-reset = <0>; + gpio-req-tbl-num = <0>; + gpio-req-tbl-flags = <0>; + gpio-req-tbl-label = "CAM_4"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + }; + + /* GMSL 2 */ + qcom,cam-sensor5 { + compatible = "qcom,cam-sensor"; + cell-index = <5>; + csiphy-sd-index = <3>; + sensor-position-roll = <0>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + cam_vio-supply = <&vreg_l18b_1p8>; + regulator-names = "cam_vio"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000>; + rgltr-max-voltage = <1800000>; + rgltr-load-current = <120000>; + gpio-no-mux = <0>; + gpios = <&tlmm 93 0>; + gpio-reset = <0>; + gpio-req-tbl-num = <0>; + gpio-req-tbl-flags = <0>; + gpio-req-tbl-label = "CAM_5"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + }; + + /*cam0b-ov9282*/ + qcom,cam-sensor7 { + compatible = "qcom,cam-sensor"; + cell-index = <7>; + csiphy-sd-index = <0>; + sensor-position-roll = <0>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + cam_vio-supply = <&vreg_l18b_1p8>; + regulator-names = "cam_vio"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000>; + rgltr-max-voltage = <1800000>; + rgltr-load-current = <120000>; + gpio-no-mux = <0>; + pinctrl-0 = <&cam_sensor_mclk4_active + &cam_sensor_active_rst5>; + pinctrl-1 = <&cam_sensor_mclk4_suspend + &cam_sensor_suspend_rst5>; + pinctrl-names = "cam_default", "cam_suspend"; + gpios = <&tlmm 68 0>, + <&tlmm 149 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK4", + "CAM_RESET5"; + sensor-mode = <0>; + cci-master = <0>; + clocks = <&camcc CAM_CC_MCLK4_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "nominal"; + clock-rates = <24000000>; + status = "ok"; + }; + + /*cam2-imx577*/ + qcom,cam-sensor8 { + compatible = "qcom,cam-sensor"; + cell-index = <8>; + csiphy-sd-index = <2>; + sensor-position-roll = <0>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + eeprom-src = <&eeprom_cam2>; + cam_vio-supply = <&vreg_l18b_1p8>; + regulator-names = "cam_vio"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000>; + rgltr-max-voltage = <1800000>; + rgltr-load-current = <120000>; + gpio-no-mux = <0>; + pinctrl-0 = <&cam_sensor_mclk2_active + &cam_sensor_active_rst2>; + pinctrl-1 = <&cam_sensor_mclk2_suspend + &cam_sensor_suspend_rst2>; + pinctrl-names = "cam_default", "cam_suspend"; + gpios = <&tlmm 66 0>, + <&tlmm 77 0>, + <&pm7250b_gpios 7 0>; + gpio-reset = <1>; + gpio-custom1 = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET2", + "CAM_CUSTOM1"; + sensor-mode = <0>; + cci-master = <0>; + clocks = <&camcc CAM_CC_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "nominal"; + clock-rates = <24000000>; + status = "ok"; + }; + + /* GMSL 3 */ + qcom,cam-sensor9 { + compatible = "qcom,cam-sensor"; + cell-index = <9>; + csiphy-sd-index = <4>; + sensor-position-roll = <0>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + cam_vio-supply = <&vreg_l18b_1p8>; + regulator-names = "cam_vio"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000>; + rgltr-max-voltage = <1800000>; + rgltr-load-current = <120000>; + gpio-no-mux = <0>; + gpios = <&tlmm 93 0>; + gpio-reset = <0>; + gpio-req-tbl-num = <0>; + gpio-req-tbl-flags = <0>; + gpio-req-tbl-label = "CAM_9"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + }; + + /* GMSL 4 */ + qcom,cam-sensor10 { + compatible = "qcom,cam-sensor"; + cell-index = <10>; + csiphy-sd-index = <4>; + sensor-position-roll = <0>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + cam_vio-supply = <&vreg_l18b_1p8>; + regulator-names = "cam_vio"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000>; + rgltr-max-voltage = <1800000>; + rgltr-load-current = <120000>; + gpio-no-mux = <0>; + gpios = <&tlmm 93 0>; + gpio-reset = <0>; + gpio-req-tbl-num = <0>; + gpio-req-tbl-flags = <0>; + gpio-req-tbl-label = "CAM_10"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + }; +}; + +&soc { + qcom,cam-res-mgr { + compatible = "qcom,cam-res-mgr"; + gpios-shared-pinctrl = <640>; + shared-pctrl-gpio-names = "gmsl"; + pinctrl-0 = <&cam_sensor_active_gmsl>; + pinctrl-1 = <&cam_sensor_suspend_gmsl>; + pinctrl-names = "gmsl_active", "gmsl_suspend"; + status = "ok"; + }; +}; + +&tlmm { + cam_sensor_active_gmsl: cam-sensor-active-gmsl { + /* GMSL_ENABLE */ + mux { + pins = "gpio93"; + function = "gpio"; + }; + + config { + pins = "gpio93"; + bias-pull-up; + drive-strength = <2>; /* 2 MA */ + output-high; + }; + }; + + cam_sensor_active_rst5: cam-sensor-active-rst5 { + /* RESET 5 */ + mux { + pins = "gpio115"; + function = "gpio"; + }; + + config { + pins = "gpio115"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_suspend_gmsl: cam-sensor-suspend-gmsl { + /* GMSL_ENABLE */ + mux { + pins = "gpio93"; + function = "gpio"; + }; + + config { + pins = "gpio93"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; + }; + + cam_sensor_suspend_rst5: cam-sensor-suspend-rst5 { + /* RESET 5 */ + mux { + pins = "gpio115"; + function = "gpio"; + }; + + config { + pins = "gpio115"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2-vision-mezzanine-camx.dtso b/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2-vision-mezzanine-camx.dtso new file mode 100644 index 0000000000000..eb183d7dbd3d5 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2-vision-mezzanine-camx.dtso @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +/dts-v1/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "qcs6490-camera.dtsi" +#include "qcs6490-rb3gen2-camera-sensor.dtsi" + +&camss { + status = "disabled"; +}; + +&cci1 { + status = "disabled"; +}; From e5afe759f9914670fd7e10a7370f8313fbfbcaf8 Mon Sep 17 00:00:00 2001 From: Chandan Kumar Jha Date: Sun, 19 Oct 2025 11:20:50 +0530 Subject: [PATCH 0042/2333] QCLINUX: arm64: dts: qcom: Add monaco camx overlay dts Add CAMX overlay dts file for Monaco boards. This change also enables the compilation of the CAMX overlay for Monaco boards. Signed-off-by: Chandan Kumar Jha --- arch/arm64/boot/dts/qcom/Makefile | 10 + .../boot/dts/qcom/monaco-camera-sensor.dtsi | 380 +++ arch/arm64/boot/dts/qcom/monaco-camera.dtsi | 2505 +++++++++++++++++ .../dts/qcom/monaco-evk-camera-sensor.dtsi | 794 ++++++ arch/arm64/boot/dts/qcom/monaco-evk-camx.dtso | 107 + .../boot/dts/qcom/qcs8300-ride-camx.dtso | 16 + 6 files changed, 3812 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/monaco-camera-sensor.dtsi create mode 100644 arch/arm64/boot/dts/qcom/monaco-camera.dtsi create mode 100644 arch/arm64/boot/dts/qcom/monaco-evk-camera-sensor.dtsi create mode 100644 arch/arm64/boot/dts/qcom/monaco-evk-camx.dtso create mode 100644 arch/arm64/boot/dts/qcom/qcs8300-ride-camx.dtso diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile index dac4d11eb46df..3f49be01d7d57 100644 --- a/arch/arm64/boot/dts/qcom/Makefile +++ b/arch/arm64/boot/dts/qcom/Makefile @@ -41,6 +41,11 @@ lemans-evk-camx-dtbs := lemans-evk.dtb lemans-evk-camx.dtbo dtb-$(CONFIG_ARCH_QCOM) += lemans-evk-camx.dtb dtb-$(CONFIG_ARCH_QCOM) += monaco-evk.dtb + +monaco-evk-camx-dtbs := monaco-evk.dtb monaco-evk-camx.dtbo + +dtb-$(CONFIG_ARCH_QCOM) += monaco-evk-camx.dtb + dtb-$(CONFIG_ARCH_QCOM) += msm8216-samsung-fortuna3g.dtb dtb-$(CONFIG_ARCH_QCOM) += msm8916-acer-a1-724.dtb dtb-$(CONFIG_ARCH_QCOM) += msm8916-alcatel-idol347.dtb @@ -145,6 +150,11 @@ qcs6490-rb3gen2-vision-mezzanine-camx-dtbs := qcs6490-rb3gen2-vision-mezzanine.d dtb-$(CONFIG_ARCH_QCOM) += qcs6490-rb3gen2-vision-mezzanine-camx.dtb dtb-$(CONFIG_ARCH_QCOM) += qcs8300-ride.dtb + +qcs8300-ride-camx-dtbs:= qcs8300-ride.dtb qcs8300-ride-camx.dtbo + +dtb-$(CONFIG_ARCH_QCOM) += qcs8300-ride-camx.dtb + dtb-$(CONFIG_ARCH_QCOM) += qcs8550-aim300-aiot.dtb dtb-$(CONFIG_ARCH_QCOM) += qcs9100-ride.dtb diff --git a/arch/arm64/boot/dts/qcom/monaco-camera-sensor.dtsi b/arch/arm64/boot/dts/qcom/monaco-camera-sensor.dtsi new file mode 100644 index 0000000000000..0023c97edce91 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/monaco-camera-sensor.dtsi @@ -0,0 +1,380 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#include + +&cam_cci0 { + /* GMSL deserializer 0 */ + qcom,cam-gmsl-deserializer0 { + cell-index = <0>; + csiphy-sd-index = <0>; + sensor-position-roll = <0>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + cam_vio-supply = <&vreg_s4a>; + regulator-names = "cam_vio"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000>; + rgltr-max-voltage = <1800000>; + rgltr-load-current = <120000>; + gpio-no-mux = <0>; + pinctrl-0 = <&cam_sensor_mclk0_active>; + pinctrl-1 = <&cam_sensor_mclk0_suspend>; + pinctrl-names = "cam_default", "cam_suspend"; + gpios = <&tlmm 73 0>; + gpio-reset = <0>; + gpio-req-tbl-num = <0>; + gpio-req-tbl-flags = <0>; + gpio-req-tbl-label = "CAM_RESET0"; + cci-master = <0>; + clocks = <&camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "nominal"; + clock-rates = <24000000>; + status = "ok"; + + port@0 { + reg = <0>; + + deser0_port0: endpoint { + remote-endpoint = <&gmsl_sensor0_ep>; + }; + }; + + port@1 { + reg = <1>; + + deser0_port1: endpoint { + remote-endpoint = <&gmsl_sensor1_ep>; + }; + }; + + port@2 { + reg = <0>; + + deser0_port2: endpoint { + remote-endpoint = <&gmsl_sensor2_ep>; + }; + }; + + port@3 { + reg = <1>; + + deser0_port3: endpoint { + remote-endpoint = <&gmsl_sensor3_ep>; + }; + }; + }; + + /* GMSL deserializer 0 sensor 0 */ + qcom,cam-gmsl-sensor0 { + compatible = "qcom,cam-gmsl-sensor"; + cell-index = <0>; + csiphy-sd-index = <0>; + status = "ok"; + + port { + gmsl_sensor0_ep: endpoint { + remote-endpoint = <&deser0_port0>; + }; + }; + }; + + /* GMSL deserializer 0 sensor 1 */ + qcom,cam-gmsl-sensor1 { + compatible = "qcom,cam-gmsl-sensor"; + cell-index = <1>; + csiphy-sd-index = <0>; + status = "ok"; + + port { + gmsl_sensor1_ep: endpoint { + remote-endpoint = <&deser0_port1>; + }; + }; + }; + + /* GMSL deserializer 0 sensor 2 */ + qcom,cam-gmsl-sensor2 { + compatible = "qcom,cam-gmsl-sensor"; + cell-index = <2>; + csiphy-sd-index = <0>; + status = "ok"; + + port { + gmsl_sensor2_ep: endpoint { + remote-endpoint = <&deser0_port2>; + }; + }; + }; + + /* GMSL deserializer 0 sensor 3 */ + qcom,cam-gmsl-sensor3 { + compatible = "qcom,cam-gmsl-sensor"; + cell-index = <3>; + csiphy-sd-index = <0>; + status = "ok"; + + port { + gmsl_sensor3_ep: endpoint { + remote-endpoint = <&deser0_port3>; + }; + }; + }; +}; + +&cam_cci1 { + /* GMSL deserializer 1 */ + qcom,cam-gmsl-deserializer1 { + cell-index = <1>; + csiphy-sd-index = <1>; + sensor-position-roll = <0>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + cam_vio-supply = <&vreg_s4a>; + regulator-names = "cam_vio"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000>; + rgltr-max-voltage = <1800000>; + rgltr-load-current = <120000>; + gpio-no-mux = <0>; + pinctrl-0 = <&cam_sensor_mclk1_active>; + pinctrl-1 = <&cam_sensor_mclk1_suspend>; + pinctrl-names = "cam_default", "cam_suspend"; + gpios = <&tlmm 74 0>; + gpio-reset = <0>; + gpio-req-tbl-num = <0>; + gpio-req-tbl-flags = <0>; + gpio-req-tbl-label = "CAM_RESET1"; + cci-master = <0>; + clocks = <&camcc CAM_CC_MCLK1_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "nominal"; + clock-rates = <24000000>; + status = "ok"; + + port@0 { + reg = <0>; + + deser1_port0: endpoint { + remote-endpoint = <&gmsl_sensor4_ep>; + }; + }; + + port@1 { + reg = <1>; + + deser1_port1: endpoint { + remote-endpoint = <&gmsl_sensor5_ep>; + }; + }; + + port@2 { + reg = <0>; + + deser1_port2: endpoint { + remote-endpoint = <&gmsl_sensor6_ep>; + }; + }; + + port@3 { + reg = <1>; + + deser1_port3: endpoint { + remote-endpoint = <&gmsl_sensor7_ep>; + }; + }; + }; + + /* GMSL deserializer 1 sensor 0 */ + qcom,cam-gmsl-sensor4 { + compatible = "qcom,cam-gmsl-sensor"; + cell-index = <4>; + csiphy-sd-index = <1>; + status = "ok"; + + port { + gmsl_sensor4_ep: endpoint { + remote-endpoint = <&deser1_port0>; + }; + }; + }; + + /* GMSL deserializer 1 sensor 1 */ + qcom,cam-gmsl-sensor5 { + compatible = "qcom,cam-gmsl-sensor"; + cell-index = <5>; + csiphy-sd-index = <1>; + status = "ok"; + + port { + gmsl_sensor5_ep: endpoint { + remote-endpoint = <&deser1_port1>; + }; + }; + }; + + /* GMSL deserializer 1 sensor 2 */ + qcom,cam-gmsl-sensor6 { + compatible = "qcom,cam-gmsl-sensor"; + cell-index = <6>; + csiphy-sd-index = <1>; + status = "ok"; + + port { + gmsl_sensor6_ep: endpoint { + remote-endpoint = <&deser1_port2>; + }; + }; + }; + + /* GMSL deserializer 1 sensor 3 */ + qcom,cam-gmsl-sensor7 { + compatible = "qcom,cam-gmsl-sensor"; + cell-index = <7>; + csiphy-sd-index = <1>; + status = "ok"; + + port { + gmsl_sensor7_ep: endpoint { + remote-endpoint = <&deser1_port3>; + }; + }; + }; +}; + +&cam_cci2 { + /* GMSL deserializer 2 */ + qcom,cam-gmsl-deserializer2 { + cell-index = <2>; + csiphy-sd-index = <2>; + sensor-position-roll = <0>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + cam_vio-supply = <&vreg_s4a>; + regulator-names = "cam_vio"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000>; + rgltr-max-voltage = <1800000>; + rgltr-load-current = <120000>; + gpio-no-mux = <0>; + pinctrl-0 = <&cam_sensor_mclk2_active>; + pinctrl-1 = <&cam_sensor_mclk2_suspend>; + pinctrl-names = "cam_default", "cam_suspend"; + gpios = <&tlmm 75 0>; + gpio-reset = <0>; + gpio-req-tbl-num = <0>; + gpio-req-tbl-flags = <0>; + gpio-req-tbl-label = "CAM_RESET2"; + cci-master = <0>; + clocks = <&camcc CAM_CC_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "nominal"; + clock-rates = <24000000>; + status = "ok"; + + port@0 { + reg = <0>; + + deser2_port0: endpoint { + remote-endpoint = <&gmsl_sensor8_ep>; + }; + }; + + port@1 { + reg = <1>; + + deser2_port1: endpoint { + remote-endpoint = <&gmsl_sensor9_ep>; + }; + }; + + port@2 { + reg = <0>; + + deser2_port2: endpoint { + remote-endpoint = <&gmsl_sensor10_ep>; + }; + }; + + port@3 { + reg = <1>; + + deser2_port3: endpoint { + remote-endpoint = <&gmsl_sensor11_ep>; + }; + }; + }; + + /* GMSL deserializer 2 sensor 0 */ + qcom,cam-gmsl-sensor8 { + compatible = "qcom,cam-gmsl-sensor"; + cell-index = <8>; + csiphy-sd-index = <2>; + status = "ok"; + + port { + gmsl_sensor8_ep: endpoint { + remote-endpoint = <&deser2_port0>; + }; + }; + }; + + /* GMSL deserializer 2 sensor 1 */ + qcom,cam-gmsl-sensor9 { + compatible = "qcom,cam-gmsl-sensor"; + cell-index = <9>; + csiphy-sd-index = <2>; + status = "ok"; + + port { + gmsl_sensor9_ep: endpoint { + remote-endpoint = <&deser2_port1>; + }; + }; + }; + + /* GMSL deserializer 2 sensor 2 */ + qcom,cam-gmsl-sensor10 { + compatible = "qcom,cam-gmsl-sensor"; + cell-index = <10>; + csiphy-sd-index = <2>; + status = "ok"; + + port { + gmsl_sensor10_ep: endpoint { + remote-endpoint = <&deser2_port2>; + }; + }; + }; + + /* GMSL deserializer 2 sensor 3 */ + qcom,cam-gmsl-sensor11 { + compatible = "qcom,cam-gmsl-sensor"; + cell-index = <11>; + csiphy-sd-index = <2>; + status = "ok"; + + port { + gmsl_sensor11_ep: endpoint { + remote-endpoint = <&deser2_port3>; + }; + }; + }; +}; + +&soc { + qcom,cam-res-mgr { + compatible = "qcom,cam-res-mgr"; + gpios-shared = <518 519 520 521>; + status = "ok"; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/monaco-camera.dtsi b/arch/arm64/boot/dts/qcom/monaco-camera.dtsi new file mode 100644 index 0000000000000..bd619b507831f --- /dev/null +++ b/arch/arm64/boot/dts/qcom/monaco-camera.dtsi @@ -0,0 +1,2505 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#include + +&soc { + cam_cci0: qcom,cci0@ac13000 { + compatible = "qcom,cci", "simple-bus"; + reg = <0x0 0xac13000 0x0 0x1000>; + reg-names = "cci"; + reg-cam-base = <0x13000>; + interrupts = ; + interrupt-names = "CCI0"; + operating-points-v2 = <&cci0_opp_table>; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + clocks = <&camcc CAM_CC_CCI_0_CLK_SRC>, + <&camcc CAM_CC_CCI_0_CLK>; + clock-names = "cci_0_clk_src", + "cci_0_clk"; + clock-rates = <37500000 0>; + clock-cntl-level = "lowsvs"; + src-clock-name = "cci_0_clk_src"; + pctrl-idx-mapping = ; + pctrl-map-names = "m0", "m1"; + pinctrl-0 = <&cci_i2c_scl0_active &cci_i2c_sda0_active>; + pinctrl-1 = <&cci_i2c_scl0_suspend &cci_i2c_sda0_suspend>; + pinctrl-2 = <&cci_i2c_scl1_active &cci_i2c_sda1_active>; + pinctrl-3 = <&cci_i2c_scl1_suspend &cci_i2c_sda1_suspend>; + pinctrl-names = "m0_active", "m0_suspend", + "m1_active", "m1_suspend"; + cell-index = <0>; + status = "ok"; + + cci0_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-37500000 { + opp-hz = /bits/ 64 <37500000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + }; + + i2c_freq_custom_cci0: qcom,i2c-custom-mode { + hw-thigh = <16>; + hw-tlow = <22>; + hw-tsu-sto = <17>; + hw-tsu-sta = <18>; + hw-thd-dat = <16>; + hw-thd-sta = <15>; + hw-tbuf = <24>; + hw-scl-stretch-en = <1>; + hw-trdhld = <3>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + + i2c_freq_400Khz_cci0: qcom,i2c-fast-mode { + hw-thigh = <38>; + hw-tlow = <56>; + hw-tsu-sto = <40>; + hw-tsu-sta = <40>; + hw-thd-dat = <22>; + hw-thd-sta = <35>; + hw-tbuf = <62>; + hw-scl-stretch-en = <1>; + hw-trdhld = <6>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + + i2c_freq_1Mhz_cci0: qcom,i2c-fast-plus-mode { + hw-thigh = <16>; + hw-tlow = <22>; + hw-tsu-sto = <17>; + hw-tsu-sta = <18>; + hw-thd-dat = <16>; + hw-thd-sta = <15>; + hw-tbuf = <24>; + hw-scl-stretch-en = <1>; + hw-trdhld = <3>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + + i2c_freq_100Khz_cci0: qcom,i2c-standard-mode { + hw-thigh = <201>; + hw-tlow = <174>; + hw-tsu-sto = <204>; + hw-tsu-sta = <231>; + hw-thd-dat = <22>; + hw-thd-sta = <162>; + hw-tbuf = <227>; + hw-scl-stretch-en = <0>; + hw-trdhld = <6>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + }; + + cam_cci1: qcom,cci1@ac14000 { + compatible = "qcom,cci", "simple-bus"; + reg = <0x0 0xac14000 0x0 0x1000>; + reg-names = "cci"; + reg-cam-base = <0x14000>; + interrupts = ; + interrupt-names = "CCI1"; + operating-points-v2 = <&cci1_opp_table>; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + clocks = <&camcc CAM_CC_CCI_1_CLK_SRC>, + <&camcc CAM_CC_CCI_1_CLK>; + clock-names = "cci_1_clk_src", + "cci_1_clk"; + clock-rates = <37500000 0>; + clock-cntl-level = "lowsvs"; + src-clock-name = "cci_1_clk_src"; + pctrl-idx-mapping = ; + pctrl-map-names = "m0", "m1"; + pinctrl-0 = <&cci_i2c_scl2_active &cci_i2c_sda2_active>; + pinctrl-1 = <&cci_i2c_scl2_suspend &cci_i2c_sda2_suspend>; + pinctrl-2 = <&cci_i2c_scl3_active &cci_i2c_sda3_active>; + pinctrl-3 = <&cci_i2c_scl3_suspend &cci_i2c_sda3_suspend>; + pinctrl-names = "m0_active", "m0_suspend", + "m1_active", "m1_suspend"; + cell-index = <1>; + status = "ok"; + + cci1_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-37500000 { + opp-hz = /bits/ 64 <37500000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + }; + + i2c_freq_custom_cci1: qcom,i2c-custom-mode { + hw-thigh = <16>; + hw-tlow = <22>; + hw-tsu-sto = <17>; + hw-tsu-sta = <18>; + hw-thd-dat = <16>; + hw-thd-sta = <15>; + hw-tbuf = <24>; + hw-scl-stretch-en = <1>; + hw-trdhld = <3>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + + i2c_freq_400Khz_cci1: qcom,i2c-fast-mode { + hw-thigh = <38>; + hw-tlow = <56>; + hw-tsu-sto = <40>; + hw-tsu-sta = <40>; + hw-thd-dat = <22>; + hw-thd-sta = <35>; + hw-tbuf = <62>; + hw-scl-stretch-en = <1>; + hw-trdhld = <6>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + + i2c_freq_1Mhz_cci1: qcom,i2c-fast-plus-mode { + hw-thigh = <16>; + hw-tlow = <22>; + hw-tsu-sto = <17>; + hw-tsu-sta = <18>; + hw-thd-dat = <16>; + hw-thd-sta = <15>; + hw-tbuf = <24>; + hw-scl-stretch-en = <1>; + hw-trdhld = <3>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + + i2c_freq_100Khz_cci1: qcom,i2c-standard-mode { + hw-thigh = <201>; + hw-tlow = <174>; + hw-tsu-sto = <204>; + hw-tsu-sta = <231>; + hw-thd-dat = <22>; + hw-thd-sta = <162>; + hw-tbuf = <227>; + hw-scl-stretch-en = <0>; + hw-trdhld = <6>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + }; + + cam_cci2: qcom,cci2@ac15000 { + compatible = "qcom,cci", "simple-bus"; + reg = <0x0 0xac15000 0x0 0x1000>; + reg-names = "cci"; + reg-cam-base = <0x15000>; + interrupts = ; + interrupt-names = "CCI2"; + operating-points-v2 = <&cci2_opp_table>; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + clocks = <&camcc CAM_CC_CCI_2_CLK_SRC>, + <&camcc CAM_CC_CCI_2_CLK>; + clock-names = "cci_2_clk_src", + "cci_2_clk"; + clock-rates = <37500000 0>; + clock-cntl-level = "lowsvs"; + src-clock-name = "cci_2_clk_src"; + pctrl-idx-mapping = ; + pctrl-map-names = "m0", "m1"; + pinctrl-0 = <&cci_i2c_scl4_active &cci_i2c_sda4_active>; + pinctrl-1 = <&cci_i2c_scl4_suspend &cci_i2c_sda4_suspend>; + pinctrl-2 = <&cci_i2c_scl5_active &cci_i2c_sda5_active>; + pinctrl-3 = <&cci_i2c_scl5_suspend &cci_i2c_sda5_suspend>; + pinctrl-names = "m0_active", "m0_suspend", + "m1_active", "m1_suspend"; + cell-index = <2>; + status = "ok"; + + cci2_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-37500000 { + opp-hz = /bits/ 64 <37500000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + }; + + i2c_freq_custom_cci2: qcom,i2c-custom-mode { + hw-thigh = <16>; + hw-tlow = <22>; + hw-tsu-sto = <17>; + hw-tsu-sta = <18>; + hw-thd-dat = <16>; + hw-thd-sta = <15>; + hw-tbuf = <24>; + hw-scl-stretch-en = <1>; + hw-trdhld = <3>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + + i2c_freq_400Khz_cci2: qcom,i2c-fast-mode { + hw-thigh = <38>; + hw-tlow = <56>; + hw-tsu-sto = <40>; + hw-tsu-sta = <40>; + hw-thd-dat = <22>; + hw-thd-sta = <35>; + hw-tbuf = <62>; + hw-scl-stretch-en = <1>; + hw-trdhld = <6>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + + i2c_freq_1Mhz_cci2: qcom,i2c-fast-plus-mode { + hw-thigh = <16>; + hw-tlow = <22>; + hw-tsu-sto = <17>; + hw-tsu-sta = <18>; + hw-thd-dat = <16>; + hw-thd-sta = <15>; + hw-tbuf = <24>; + hw-scl-stretch-en = <1>; + hw-trdhld = <3>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + + i2c_freq_100Khz_cci2: qcom,i2c-standard-mode { + hw-thigh = <201>; + hw-tlow = <174>; + hw-tsu-sto = <204>; + hw-tsu-sta = <231>; + hw-thd-dat = <22>; + hw-thd-sta = <162>; + hw-tbuf = <227>; + hw-scl-stretch-en = <0>; + hw-trdhld = <6>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + }; + + cam_csiphy0: qcom,csiphy0@ac9c000 { + compatible = "qcom,csiphy-v1.3.0", "qcom,csiphy"; + reg = <0x0 0x0ac9c000 0x0 0x2000>; + reg-names = "csiphy"; + operating-points-v2 = <&csiphy0_opp_table>; + reg-cam-base = <0x9c000>; + interrupts = ; + interrupt-names = "CSIPHY0"; + csi-vdd-1p2-supply = <&vreg_l5a>; + csi-vdd-0p9-supply = <&vreg_l4a>; + regulator-names = "csi-vdd-1p2", "csi-vdd-0p9"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + rgltr-cntrl-support; + rgltr-min-voltage = <1200000 880000>; + rgltr-max-voltage = <1200000 912000>; + rgltr-load-current = <8900 15900>; + shared-clks = <1 0 0 0>; + clocks = <&camcc CAM_CC_CPHY_RX_CLK_SRC>, + <&camcc CAM_CC_CSIPHY0_CLK>, + <&camcc CAM_CC_CSI0PHYTIMER_CLK_SRC>, + <&camcc CAM_CC_CSI0PHYTIMER_CLK>; + clock-names = "cphy_rx_clk_src", + "csiphy0_clk", + "csi0phytimer_clk_src", + "csi0phytimer_clk"; + src-clock-name = "cphy_rx_clk_src"; + clock-cntl-level = "lowsvs"; + clock-rates = <400000000 0 400000000 0>; + cell-index = <0>; + aggregator-rx; + status = "ok"; + + csiphy0_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-400000000 { + opp-hz = /bits/ 64 <400000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + }; + }; + + cam_csiphy1: qcom,csiphy1@ac9e000 { + compatible = "qcom,csiphy-v1.3.0", "qcom,csiphy"; + reg = <0x0 0xac9e000 0x0 0x2000>; + reg-names = "csiphy"; + operating-points-v2 = <&csiphy1_opp_table>; + reg-cam-base = <0x9e000>; + interrupts = ; + interrupt-names = "CSIPHY1"; + csi-vdd-1p2-supply = <&vreg_l5a>; + csi-vdd-0p9-supply = <&vreg_l4a>; + regulator-names = "csi-vdd-1p2", "csi-vdd-0p9"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + rgltr-cntrl-support; + rgltr-min-voltage = <1200000 880000>; + rgltr-max-voltage = <1200000 912000>; + rgltr-load-current = <8900 15900>; + shared-clks = <1 0 0 0>; + clocks = <&camcc CAM_CC_CPHY_RX_CLK_SRC>, + <&camcc CAM_CC_CSIPHY1_CLK>, + <&camcc CAM_CC_CSI1PHYTIMER_CLK_SRC>, + <&camcc CAM_CC_CSI1PHYTIMER_CLK>; + clock-names = "cphy_rx_clk_src", + "csiphy1_clk", + "csi1phytimer_clk_src", + "csi1phytimer_clk"; + src-clock-name = "cphy_rx_clk_src"; + clock-cntl-level = "lowsvs"; + clock-rates = <400000000 0 400000000 0>; + cell-index = <1>; + aggregator-rx; + status = "ok"; + + csiphy1_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-400000000 { + opp-hz = /bits/ 64 <400000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + }; + }; + + cam_csiphy2: qcom,csiphy2@aca0000 { + compatible = "qcom,csiphy-v1.3.0", "qcom,csiphy"; + reg = <0x0 0xaca0000 0x0 0x2000>; + reg-names = "csiphy"; + operating-points-v2 = <&csiphy2_opp_table>; + reg-cam-base = <0xa0000>; + interrupts = ; + interrupt-names = "CSIPHY2"; + csi-vdd-1p2-supply = <&vreg_l5a>; + csi-vdd-0p9-supply = <&vreg_l4a>; + regulator-names = "csi-vdd-1p2", "csi-vdd-0p9"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + rgltr-cntrl-support; + rgltr-min-voltage = <1200000 880000>; + rgltr-max-voltage = <1200000 912000>; + rgltr-load-current = <8900 15900>; + shared-clks = <1 0 0 0>; + clocks = <&camcc CAM_CC_CPHY_RX_CLK_SRC>, + <&camcc CAM_CC_CSIPHY2_CLK>, + <&camcc CAM_CC_CSI2PHYTIMER_CLK_SRC>, + <&camcc CAM_CC_CSI2PHYTIMER_CLK>; + clock-names = "cphy_rx_clk_src", + "csiphy2_clk", + "csi2phytimer_clk_src", + "csi2phytimer_clk"; + src-clock-name = "cphy_rx_clk_src"; + clock-cntl-level = "lowsvs"; + clock-rates = <400000000 0 400000000 0>; + cell-index = <2>; + aggregator-rx; + status = "ok"; + + csiphy2_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-400000000 { + opp-hz = /bits/ 64 <400000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + }; + }; + + cam_csiphy_tpg13: qcom,tpg13@acac000 { + compatible = "qcom,cam-tpg1031"; + reg = <0x0 0xacac000 0x0 0x400>, + <0x0 0xac11000 0x0 0x1000>; + reg-names = "tpg0", "cam_cpas_top"; + reg-cam-base = <0xac000 0x11000>; + operating-points-v2 = <&csiphy_tpg0_opp_table>; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + interrupts = ; + interrupt-names = "tpg0"; + shared-clks = <1 0>; + clocks = <&camcc CAM_CC_CPHY_RX_CLK_SRC>, + <&camcc CAM_CC_CSID_CSIPHY_RX_CLK>; + clock-names = "cphy_rx_clk_src", + "csid_csiphy_rx_clk"; + clock-rates = <400000000 0>; + clock-cntl-level = "lowsvs"; + src-clock-name = "cphy_rx_clk_src"; + cell-index = <13>; + phy-id = <0>; + status = "ok"; + + csiphy_tpg0_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-400000000 { + opp-hz = /bits/ 64 <400000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + }; + }; + + cam_csiphy_tpg14: qcom,tpg14@acad000 { + compatible = "qcom,cam-tpg1031"; + reg = <0x0 0xacad000 0x0 0x400>, + <0x0 0xac11000 0x0 0x1000>; + reg-names = "tpg1", "cam_cpas_top"; + reg-cam-base = <0xad000 0x11000>; + operating-points-v2 = <&csiphy_tpg1_opp_table>; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + interrupts = ; + interrupt-names = "tpg1"; + shared-clks = <1 0>; + clocks = <&camcc CAM_CC_CPHY_RX_CLK_SRC>, + <&camcc CAM_CC_CSID_CSIPHY_RX_CLK>; + clock-names = "cphy_rx_clk_src", + "csid_csiphy_rx_clk"; + clock-rates = <400000000 0>; + clock-cntl-level = "lowsvs"; + src-clock-name = "cphy_rx_clk_src"; + cell-index = <14>; + phy-id = <1>; + status = "ok"; + + csiphy_tpg1_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-400000000 { + opp-hz = /bits/ 64 <400000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + }; + }; + + cam_csiphy_tpg15: qcom,tpg15@acae000 { + compatible = "qcom,cam-tpg1031"; + reg = <0x0 0xacae000 0x0 0x400>, + <0x0 0xac11000 0x0 0x1000>; + reg-names = "tpg2", "cam_cpas_top"; + reg-cam-base = <0xae000 0x11000>; + operating-points-v2 = <&csiphy_tpg2_opp_table>; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + interrupts = ; + interrupt-names = "tpg2"; + shared-clks = <1 0>; + clocks = <&camcc CAM_CC_CPHY_RX_CLK_SRC>, + <&camcc CAM_CC_CSID_CSIPHY_RX_CLK>; + clock-names = "cphy_rx_clk_src", + "csid_csiphy_rx_clk"; + clock-rates = <400000000 0>; + clock-cntl-level = "lowsvs"; + src-clock-name = "cphy_rx_clk_src"; + cell-index = <15>; + phy-id = <2>; + status = "ok"; + + csiphy_tpg2_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-400000000 { + opp-hz = /bits/ 64 <400000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + }; + }; + + qcom,cam-cdm-intf { + compatible = "qcom,cam-cdm-intf"; + cell-index = <0>; + label = "cam-cdm-intf"; + num-hw-cdm = <1>; + cdm-client-names = "vfe"; + status = "ok"; + }; + + qcom,cam-cpas { + compatible = "qcom,cam-cpas"; + label = "cpas"; + arch-compat = "cpas_top"; + reg = <0x0 0xac11000 0x0 0x1000>, + <0x0 0xac1A000 0x0 0x9400>, + <0x0 0xbbf0000 0x0 0x1f00>; + reg-names = "cam_cpas_top", "cam_camnoc", "cam_rpmh"; + reg-cam-base = <0x11000 0x1A000 0x0bbf0000>; + interrupts = ; + interrupt-names = "cpas_camnoc"; + camnoc-axi-min-ib-bw = <3000000000>; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + clocks = <&gcc GCC_CAMERA_AHB_CLK>, + <&gcc GCC_CAMERA_HF_AXI_CLK>, + <&gcc GCC_CAMERA_SF_AXI_CLK>, + <&camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&camcc CAM_CC_CPAS_AHB_CLK>, + <&camcc CAM_CC_CORE_AHB_CLK>, + <&camcc CAM_CC_FAST_AHB_CLK_SRC>, + <&camcc CAM_CC_CPAS_FAST_AHB_CLK>, + <&camcc CAM_CC_CAMNOC_AXI_CLK_SRC>, + <&camcc CAM_CC_CAMNOC_AXI_CLK>, + <&camcc CAM_CC_QDSS_DEBUG_XO_CLK>; + clock-names = "gcc_camera_ahb_clk", + "gcc_camera_hf_axi_clk", + "gcc_camera_sf_axi_clk", + "cam_cc_slow_ahb_clk_src", + "cam_cc_cpas_ahb_clk", + "cam_cc_core_ahb_clk", + "cam_cc_fast_ahb_clk_src", + "cam_cc_cpas_fast_ahb_clk", + "cam_cc_camnoc_axi_clk_src", + "cam_cc_camnoc_axi_clk", + "cam_cc_qdss_debug_xo_clk"; + src-clock-name = "cam_cc_fast_ahb_clk_src"; + clock-rates = <0 0 0 0 0 0 0 0 0 0 0>, + <0 0 0 80000000 0 0 300000000 0 400000000 0 0>, + <0 0 0 80000000 0 0 400000000 0 400000000 0 0>; + clock-cntl-level = "suspend", "svs_l1", "nominal"; + clock-names-option = "cam_icp_clk"; + clocks-option = <&camcc CAM_CC_ICP_CLK>; + clock-rates-option = <480000000>; + operating-points-v2 = <&cpas_opp_table>; + control-camnoc-axi-clk; + camnoc-bus-width = <32>; + camnoc-axi-clk-bw-margin-perc = <20>; + cam-icc-path-names = "cam_ahb"; + interconnects = <&gem_noc MASTER_APPSS_PROC 0 &config_noc SLAVE_CAMERA_CFG 0>, + <&mmss_noc MASTER_CAMNOC_HF 0 &mc_virt SLAVE_EBI1 0>, + <&mmss_noc MASTER_CAMNOC_SF 0 &mc_virt SLAVE_EBI1 0>, + <&mmss_noc MASTER_CAMNOC_ICP 0 &mc_virt SLAVE_EBI1 0>; + interconnect-names = "cam_ahb", "cam_hf_0", "cam_sf_0", "cam_sf_icp"; + cam-ahb-num-cases = <7>; + cam-ahb-bw-KBps = <0 0>, <0 76800>, <0 150000>, <0 150000>, + <0 300000>, <0 300000>, <0 300000>; + vdd-corners = ; + vdd-corner-ahb-mapping = "suspend", "lowsvs", "lowsvs", "svs", "svs_l1", + "nominal", "nominal", "nominal", "turbo", "turbo"; + client-id-based; + client-names = "csiphy0", "csiphy1", "csiphy2", + "cci0", "cci1", "cci2", + "csid0", "csid1", "csid2", "csid3", + "csid4", "csid5", "csid6", "ife0", + "ife1", "ife2", "ife3", "ife4", + "ife5", "ife6", "ipe0", "sfe0", "sfe1", + "cam-cdm-intf0", "rt-cdm0", "rt-cdm1", "rt-cdm2", + "rt-cdm3", "icp0", "tpg13", "tpg14", "tpg15"; + enable-secure-qos-update; + cell-index = <0>; + status = "ok"; + + cpas_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-300000000 { + opp-hz = /bits/ 64 <300000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-400000000 { + opp-hz = /bits/ 64 <400000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + }; + + camera-bus-nodes { + level0-nodes { + level-index = <0>; + + icp_all_rd: icp-all-rd { + cell-index = <0>; + node-name = "icp-all-rd"; + client-name = "icp0"; + traffic-data = ; + traffic-transaction-type = ; + parent-node = <&level2_icp_rd>; + }; + + ife_0_wr_0: ife-0-wr-0 { + cell-index = <1>; + node-name = "ife-0-wr-0"; + client-name = "ife0"; + traffic-data = ; + traffic-transaction-type = ; + constituent-paths = ; + parent-node = <&level1_rt_wr0>; + }; + + ife_0_wr_1: ife-0-wr-1 { + cell-index = <2>; + node-name = "ife-0-wr-1"; + client-name = "ife0"; + traffic-data = ; + traffic-transaction-type = ; + constituent-paths = ; + parent-node = <&level1_rt_wr1>; + }; + + ife_1_wr_0: ife-1-wr-0 { + cell-index = <3>; + node-name = "ife-1-wr-0"; + client-name = "ife1"; + traffic-data = ; + traffic-transaction-type = ; + constituent-paths = ; + parent-node = <&level1_rt_wr0>; + }; + + ife_1_wr_1: ife-1-wr-1 { + cell-index = <3>; + node-name = "ife-1-wr-1"; + client-name = "ife1"; + traffic-data = ; + traffic-transaction-type = ; + constituent-paths = ; + parent-node = <&level1_rt_wr1>; + }; + + ife_lite_0_wr_0: ife-lite-0-wr-0 { + cell-index = <4>; + node-name = "ife-lite-0-wr-0"; + client-name = "ife2"; + traffic-data = ; + traffic-transaction-type = ; + constituent-paths = ; + parent-node = <&level1_rt_wr0>; + }; + + ife_lite_1_wr_0: ife-lite-1-wr-0 { + cell-index = <5>; + node-name = "ife-lite-1-wr-0"; + client-name = "ife3"; + traffic-data = ; + traffic-transaction-type = ; + constituent-paths = ; + parent-node = <&level1_rt_wr0>; + }; + + ife_lite_2_wr_0: ife-lite-2-wr-0 { + cell-index = <6>; + node-name = "ife-lite-2-wr-0"; + client-name = "ife4"; + traffic-data = ; + traffic-transaction-type = ; + constituent-paths = ; + parent-node = <&level1_rt_wr0>; + }; + + ife_lite_3_wr_0: ife-lite-3-wr-0 { + cell-index = <7>; + node-name = "ife-lite-3-wr-0"; + client-name = "ife5"; + traffic-data = ; + traffic-transaction-type = ; + constituent-paths = ; + parent-node = <&level1_rt_wr0>; + }; + + ife_lite_4_wr_0: ife-lite-4-wr-0 { + cell-index = <8>; + node-name = "ife-lite-4-wr-0"; + client-name = "ife6"; + traffic-data = ; + traffic-transaction-type = ; + constituent-paths = ; + parent-node = <&level1_rt_wr0>; + }; + + ipe_0_rd_all: ipe-0-rd-all { + cell-index = <9>; + node-name = "ipe-0-rd-all"; + client-name = "ipe0"; + traffic-data = ; + traffic-transaction-type = ; + constituent-paths = ; + parent-node = <&level2_nrt_rd1>; + }; + + ipe_0_wr_2: ipe-0-wr-2 { + cell-index = <10>; + node-name = "ipe-0-wr-2"; + client-name = "ipe0"; + traffic-data = ; + traffic-transaction-type = ; + constituent-paths = ; + parent-node = <&level2_nrt_wr2>; + }; + + ipe_cdm0_all_rd: ipe-cdm0-all-rd { + cell-index = <11>; + node-name = "ipe-cdm0-all-rd"; + client-name = "ipe0"; + traffic-data = ; + traffic-transaction-type = ; + parent-node = <&level1_nrt_rd2>; + }; + + rt_cdm0_all_rd_2: rt-cdm0-all-rd-2 { + cell-index = <12>; + node-name = "rt-cdm0-all-rd-2"; + client-name = "rt-cdm0"; + traffic-data = ; + traffic-transaction-type = ; + parent-node = <&level1_nrt_rd2>; + }; + + rt_cdm1_all_rd_2: rt-cdm1-all-rd-2 { + cell-index = <13>; + node-name = "rt-cdm1-all-rd-2"; + client-name = "rt-cdm1"; + traffic-data = ; + traffic-transaction-type = ; + parent-node = <&level1_nrt_rd2>; + }; + + rt_cdm2_all_rd_2: rt-cdm2-all-rd-2 { + cell-index = <14>; + node-name = "rt-cdm2-all-rd-2"; + client-name = "rt-cdm2"; + traffic-data = ; + traffic-transaction-type = ; + parent-node = <&level1_nrt_rd2>; + }; + + rt_cdm3_all_rd_2: rt-cdm3-all-rd-2 { + cell-index = <15>; + node-name = "rt-cdm3-all-rd-2"; + client-name = "rt-cdm3"; + traffic-data = ; + traffic-transaction-type = ; + parent-node = <&level1_nrt_rd2>; + }; + + sfe_0_rd_0: sfe-0-rd-0 { + cell-index = <16>; + node-name = "sfe-0-rd-0"; + client-name = "sfe0"; + traffic-data = ; + traffic-transaction-type = ; + constituent-paths = ; + parent-node = <&level1_rt_rd0>; + }; + + sfe_1_rd_0: sfe-1-rd-0 { + cell-index = <17>; + node-name = "sfe-1-rd-0"; + client-name = "sfe1"; + traffic-data = ; + traffic-transaction-type = ; + constituent-paths = ; + parent-node = <&level1_rt_rd0>; + }; + }; + + level1-nodes { + level-index = <1>; + camnoc-max-needed; + + level1_nrt_rd2: level1-nrt-rd2 { + cell-index = <22>; + node-name = "level1-nrt-rd2"; + parent-node = <&level2_nrt_rd2>; + traffic-merge-type = ; + }; + + level1_rt_rd0: level1-rt-read0 { + cell-index = <21>; + node-name = "level1-rt-rd0"; + parent-node = <&level2_rt_rd0>; + traffic-merge-type = ; + }; + + level1_rt_wr0: level1-rt-wr0 { + cell-index = <19>; + node-name = "level1-rt-wr0"; + parent-node = <&level2_rt_wr0>; + traffic-merge-type = ; + }; + + level1_rt_wr1: level1-rt-wr1 { + cell-index = <20>; + node-name = "level1-rt-wr1"; + parent-node = <&level2_rt_wr1>; + traffic-merge-type = ; + }; + }; + + level2-nodes { + level-index = <2>; + camnoc-max-needed; + + level2_icp_rd: level2-icp-rd { + cell-index = <23>; + node-name = "level2-icp-rd"; + parent-node = <&level3_nrt1_rd_wr_sum>; + traffic-merge-type = ; + }; + + level2_nrt_rd1: level2-nrt-rd1 { + cell-index = <24>; + node-name = "level2-nrt-rd1"; + parent-node = <&level3_nrt0_rd_wr_sum>; + traffic-merge-type = ; + }; + + level2_nrt_rd2: level2-nrt-rd2 { + cell-index = <25>; + node-name = "level2-nrt-rd2"; + parent-node = <&level3_nrt0_rd_wr_sum>; + traffic-merge-type = ; + }; + + level2_nrt_wr2: level2-nrt-wr2 { + cell-index = <26>; + node-name = "level2-nrt-wr2"; + parent-node = <&level3_nrt0_rd_wr_sum>; + traffic-merge-type = ; + }; + + level2_rt_rd0: level2-rt-read0 { + cell-index = <27>; + node-name = "level2-rt-rd0"; + parent-node = <&level3_rt_rd_wr_sum>; + traffic-merge-type = ; + }; + + level2_rt_wr0: level2-rt-wr0 { + cell-index = <28>; + node-name = "level2-rt-wr0"; + parent-node = <&level3_rt_rd_wr_sum>; + traffic-merge-type = ; + }; + + level2_rt_wr1: level2-rt-wr1 { + cell-index = <29>; + node-name = "level2-rt-wr1"; + parent-node = <&level3_rt_rd_wr_sum>; + traffic-merge-type = ; + }; + }; + + level3-nodes { + level-index = <3>; + + level3_nrt0_rd_wr_sum: level3-nrt0-rd-wr-sum { + cell-index = <30>; + node-name = "level3-nrt0-rd-wr-sum"; + traffic-merge-type = ; + + qcom,axi-port-mnoc { + cam-icc-path-names = "cam_sf_0"; + }; + }; + + level3_nrt1_rd_wr_sum: level3-nrt1-rd-wr-sum { + cell-index = <31>; + node-name = "level3-nrt1-rd-wr-sum"; + traffic-merge-type = ; + + qcom,axi-port-mnoc { + cam-icc-path-names = "cam_sf_icp"; + }; + }; + + level3_rt_rd_wr_sum: level3-rt-rd-wr-sum { + cell-index = <32>; + node-name = "level3-rt-rd-wr-sum"; + traffic-merge-type = ; + ib-bw-voting-needed; + + qcom,axi-port-mnoc { + cam-icc-path-names = "cam_hf_0"; + }; + }; + }; + }; + }; + + qcom,cam-icp { + compatible = "qcom,cam-icp"; + compat-hw-name = "qcom,icp", + "qcom,ipe0"; + num-icp = <1>; + num-ipe = <1>; + icp_use_pil; + status = "ok"; + }; + + qcom,cam-i3c-id-table { + compatible = "qcom,cam-i3c-id-table"; + i3c-sensor-id-table = <0x1B0 0x0766>; + i3c-eeprom-id-table = <>; + i3c-actuator-id-table = <>; + i3c-ois-id-table = <>; + status = "disabled"; + }; + + qcom,cam-isp { + compatible = "qcom,cam-isp"; + arch-compat = "ife"; + status = "ok"; + }; + + qcom,cam-req-mgr { + compatible = "qcom,cam-req-mgr"; + status = "ok"; + }; + + qcom,camera-main { + compatible = "qcom,camera"; + status = "ok"; + }; + + qcom,cam-smmu { + compatible = "qcom,msm-cam-smmu", "simple-bus"; + force_cache_allocs; + status = "ok"; + + msm-cam-smmu-cdm { + compatible = "qcom,msm-cam-smmu-cb"; + iommus = <&apps_smmu 0x0860 0x400>, + <&apps_smmu 0x0C60 0x400>; + cam-smmu-label = "rt-cdm"; + dma-coherent; + multiple-client-devices; + rt_cdm_iova_mem_map: iova-mem-map { + iova-mem-region-io { + /* IO region is approximately 4.0 GB */ + iova-region-name = "io"; + /* 1 MB pad for start */ + iova-region-start = <0x100000>; + /* 1 MB pad for end */ + iova-region-len = <0xffe00000>; + iova-region-id = <0x3>; + status = "ok"; + }; + }; + }; + + msm-cam-smmu-icp { + compatible = "qcom,msm-cam-smmu-cb"; + iommus = <&apps_smmu 0x0800 0x400>, + <&apps_smmu 0x0840 0x480>, + <&apps_smmu 0x08C0 0x480>, + <&apps_smmu 0x0C00 0x400>, + <&apps_smmu 0x0C40 0x480>, + <&apps_smmu 0x0CC0 0x480>; + cam-smmu-label = "icp"; + qcom,iommu-faults = "stall-disable", "non-fatal"; + iova-region-discard = <0xe0000000 0x800000>; + dma-coherent; + + icp_iova_mem_map: iova-mem-map { + iova-mem-region-fwuncached-region { + /* FW uncached region is 7MB long */ + iova-region-name = "fw_uncached"; + iova-region-start = <0x10400000>; + iova-region-len = <0x700000>; + iova-region-id = <0x6>; + subregion_support; + status = "ok"; + /* Used for HFI queues/sec heap */ + iova-mem-region-generic-region { + iova-region-name = "icp_hfi"; + iova-region-start = <0x10400000>; + iova-region-len = <0x200000>; + iova-region-id = <0x0>; + }; + }; + + iova-mem-region-io { + /* IO region is approximately 3.8 GB */ + iova-region-name = "io"; + iova-region-start = <0x10c00000>; + iova-region-len = <0xee300000>; + iova-region-id = <0x3>; + iova-region-discard = <0xe0000000 0x800000>; + status = "ok"; + }; + + iova-mem-region-qdss { + /* QDSS region is appropriate 1MB */ + iova-region-name = "qdss"; + iova-region-start = <0x10b00000>; + iova-region-len = <0x100000>; + iova-region-id = <0x5>; + qdss-phy-addr = <0x16790000>; + status = "ok"; + }; + + iova-mem-region-shared { + /* Shared region is ~250MB long */ + iova-region-name = "shared"; + iova-region-start = <0x800000>; + iova-region-len = <0xfc00000>; + iova-region-id = <0x1>; + status = "ok"; + }; + + }; + }; + + msm-cam-smmu-ife { + compatible = "qcom,msm-cam-smmu-cb"; + iommus = <&apps_smmu 0x2400 0x0020>, + <&apps_smmu 0x2420 0x0020>; + cam-smmu-label = "ife", "sfe"; + multiple-client-devices; + dma-coherent; + + ife_iova_mem_map: iova-mem-map { + /* IO region is approximately 64 GB */ + iova-mem-region-io { + iova-region-name = "io"; + /* start address: 0x100000 */ + /* leaving 1 MB pad at start */ + iova-region-start = <0x100000>; + /* Length: 0xfffe00000 */ + /* leaving 1 MB pad at end */ + iova-region-len = <0xffe00000>; + iova-region-id = <0x3>; + status = "ok"; + }; + }; + }; + + msm-cam-smmu-secure { + compatible = "qcom,msm-cam-smmu-cb"; + cam-smmu-label = "cam-secure"; + qcom,secure-cb; + }; + }; + + qcom,cam-sync { + compatible = "qcom,cam-sync"; + status = "ok"; + }; + + cam_csid0: qcom,csid0 { + compatible = "qcom,csid692"; + reg = <0x0 0xac7a000 0x0 0xf01>, + <0x0 0xac78000 0x0 0x1000>; + reg-names = "csid0", "csid_top"; + reg-cam-base = <0x7a000 0x78000>; + rt-wrapper-base = <0x4d000>; + interrupts = ; + interrupt-names = "csid0"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + clocks = <&camcc CAM_CC_CSID_CLK_SRC>, + <&camcc CAM_CC_CSID_CLK>, + <&camcc CAM_CC_CSID_CSIPHY_RX_CLK>; + clock-names = "cam_cc_csid_clk_src", + "cam_cc_csid_clk", + "cam_cc_csid_csiphy_rx_clk"; + clock-rates = <400000000 0 0>; + clock-cntl-level = "svs_l1"; + src-clock-name = "cam_cc_csid_clk_src"; + operating-points-v2 = <&csid0_opp_table>; + clock-control-debugfs = "true"; + cell-index = <0>; + status = "ok"; + + csid0_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-400000000 { + opp-hz = /bits/ 64 <400000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + }; + }; + + cam_csid1: qcom,csid1 { + compatible = "qcom,csid692"; + reg = <0x0 0xac7c000 0x0 0xf01>, + <0x0 0xac78000 0x0 0x1000>; + reg-names = "csid1", "csid_top"; + reg-cam-base = <0x7c000 0x78000>; + rt-wrapper-base = <0x4d000>; + interrupts = ; + interrupt-names = "csid1"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + clocks = <&camcc CAM_CC_CSID_CLK_SRC>, + <&camcc CAM_CC_CSID_CLK>, + <&camcc CAM_CC_CSID_CSIPHY_RX_CLK>; + clock-names = "cam_cc_csid_clk_src", + "cam_cc_csid_clk", + "cam_cc_csid_csiphy_rx_clk"; + clock-rates = <400000000 0 0>; + clock-cntl-level = "svs_l1"; + src-clock-name = "cam_cc_csid_clk_src"; + operating-points-v2 = <&csid1_opp_table>; + clock-control-debugfs = "true"; + cell-index = <1>; + status = "ok"; + + csid1_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-400000000 { + opp-hz = /bits/ 64 <400000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + }; + }; + + cam_csid_lite0: qcom,csid-lite0 { + compatible = "qcom,csid-lite692"; + reg = <0x0 0xac84000 0x0 0xf01>; + reg-names = "csid-lite0"; + reg-cam-base = <0x84000>; + rt-wrapper-base = <0x83000>; + interrupts = ; + interrupt-names = "csid-lite0"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + clocks = <&camcc CAM_CC_CPAS_IFE_LITE_CLK>, + <&camcc CAM_CC_IFE_LITE_AHB_CLK>, + <&camcc CAM_CC_IFE_LITE_CSID_CLK_SRC>, + <&camcc CAM_CC_IFE_LITE_CSID_CLK>, + <&camcc CAM_CC_IFE_LITE_CPHY_RX_CLK>, + <&camcc CAM_CC_IFE_LITE_CLK_SRC>, + <&camcc CAM_CC_IFE_LITE_CLK>; + clock-names = "cam_cc_cpas_ife_lite_clk", + "cam_cc_ife_lite_ahb_clk", + "cam_cc_ife_lite_csid_clk_src", + "cam_cc_ife_lite_csid_clk", + "cam_cc_ife_lite_cphy_rx_clk", + "cam_cc_ife_lite_clk_src", + "cam_cc_ife_lite_clk"; + clock-rates = <0 0 400000000 0 0 400000000 0>, + <0 0 400000000 0 0 480000000 0>; + clock-cntl-level = "svs_l1", "nominal"; + src-clock-name = "cam_cc_ife_lite_csid_clk_src"; + operating-points-v2 = <&csid_lite0_opp_table>; + clock-control-debugfs = "true"; + cell-index = <2>; + status = "ok"; + + csid_lite0_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-400000000 { + opp-hz = /bits/ 64 <400000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-480000000 { + opp-hz = /bits/ 64 <480000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + }; + }; + + cam_csid_lite1: qcom,csid-lite1 { + compatible = "qcom,csid-lite692"; + reg = <0x0 0xac88000 0x0 0xf01>; + reg-names = "csid-lite1"; + reg-cam-base = <0x88000>; + rt-wrapper-base = <0x83000>; + interrupts = ; + interrupt-names = "csid-lite1"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + clocks = <&camcc CAM_CC_CPAS_IFE_LITE_CLK>, + <&camcc CAM_CC_IFE_LITE_AHB_CLK>, + <&camcc CAM_CC_IFE_LITE_CSID_CLK_SRC>, + <&camcc CAM_CC_IFE_LITE_CSID_CLK>, + <&camcc CAM_CC_IFE_LITE_CPHY_RX_CLK>, + <&camcc CAM_CC_IFE_LITE_CLK_SRC>, + <&camcc CAM_CC_IFE_LITE_CLK>; + clock-names = "cam_cc_cpas_ife_lite_clk", + "cam_cc_ife_lite_ahb_clk", + "cam_cc_ife_lite_csid_clk_src", + "cam_cc_ife_lite_csid_clk", + "cam_cc_ife_lite_cphy_rx_clk", + "cam_cc_ife_lite_clk_src", + "cam_cc_ife_lite_clk"; + clock-rates = <0 0 400000000 0 0 400000000 0>, + <0 0 400000000 0 0 480000000 0>; + clock-cntl-level = "svs_l1", "nominal"; + src-clock-name = "cam_cc_ife_lite_csid_clk_src"; + operating-points-v2 = <&csid_lite1_opp_table>; + clock-control-debugfs = "true"; + cell-index = <3>; + status = "ok"; + + csid_lite1_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-400000000 { + opp-hz = /bits/ 64 <400000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-480000000 { + opp-hz = /bits/ 64 <480000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + }; + }; + + cam_csid_lite3: qcom,csid-lite3 { + cell-index = <5>; + compatible = "qcom,csid-lite692"; + reg-names = "csid-lite3"; + reg = <0x0 0xac90000 0x0 0xf01>; + reg-cam-base = <0x90000>; + rt-wrapper-base = <0x83000>; + interrupt-names = "csid-lite3"; + interrupts = ; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + clock-names = + "cam_cc_cpas_ife_lite_clk", + "cam_cc_ife_lite_ahb_clk", + "cam_cc_ife_lite_csid_clk_src", + "cam_cc_ife_lite_csid_clk", + "cam_cc_ife_lite_cphy_rx_clk", + "cam_cc_ife_lite_clk_src", + "cam_cc_ife_lite_clk"; + clocks = + <&camcc CAM_CC_CPAS_IFE_LITE_CLK>, + <&camcc CAM_CC_IFE_LITE_AHB_CLK>, + <&camcc CAM_CC_IFE_LITE_CSID_CLK_SRC>, + <&camcc CAM_CC_IFE_LITE_CSID_CLK>, + <&camcc CAM_CC_IFE_LITE_CPHY_RX_CLK>, + <&camcc CAM_CC_IFE_LITE_CLK_SRC>, + <&camcc CAM_CC_IFE_LITE_CLK>; + clock-rates = + <0 0 400000000 0 0 400000000 0>, + <0 0 400000000 0 0 480000000 0>; + clock-cntl-level = "svs_l1", "nominal"; + src-clock-name = "cam_cc_ife_lite_csid_clk_src"; + operating-points-v2 = <&csid_lite3_opp_table>; + + clock-control-debugfs = "true"; + status = "ok"; + + csid_lite3_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-400000000 { + opp-hz = /bits/ 64 <400000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + opp-480000000 { + opp-hz = /bits/ 64 <480000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + }; + }; + + cam_csid_lite2: qcom,csid-lite2 { + cell-index = <4>; + compatible = "qcom,csid-lite692"; + reg-names = "csid-lite2"; + reg = <0x0 0xac8c000 0x0 0xf01>; + reg-cam-base = <0x8c000>; + rt-wrapper-base = <0x83000>; + interrupt-names = "csid-lite2"; + interrupts = ; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + clock-names = + "cam_cc_cpas_ife_lite_clk", + "cam_cc_ife_lite_ahb_clk", + "cam_cc_ife_lite_csid_clk_src", + "cam_cc_ife_lite_csid_clk", + "cam_cc_ife_lite_cphy_rx_clk", + "cam_cc_ife_lite_clk_src", + "cam_cc_ife_lite_clk"; + clocks = + <&camcc CAM_CC_CPAS_IFE_LITE_CLK>, + <&camcc CAM_CC_IFE_LITE_AHB_CLK>, + <&camcc CAM_CC_IFE_LITE_CSID_CLK_SRC>, + <&camcc CAM_CC_IFE_LITE_CSID_CLK>, + <&camcc CAM_CC_IFE_LITE_CPHY_RX_CLK>, + <&camcc CAM_CC_IFE_LITE_CLK_SRC>, + <&camcc CAM_CC_IFE_LITE_CLK>; + clock-rates = + <0 0 400000000 0 0 400000000 0>, + <0 0 400000000 0 0 480000000 0>; + clock-cntl-level = "svs_l1", "nominal"; + src-clock-name = "cam_cc_ife_lite_csid_clk_src"; + operating-points-v2 = <&csid_lite2_opp_table>; + + clock-control-debugfs = "true"; + status = "ok"; + + csid_lite2_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-400000000 { + opp-hz = /bits/ 64 <400000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + opp-480000000 { + opp-hz = /bits/ 64 <480000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + }; + }; + + cam_csid_lite4: qcom,csid-lite4 { + cell-index = <6>; + compatible = "qcom,csid-lite692"; + reg-names = "csid-lite4"; + reg = <0x0 0xac94000 0x0 0xf01>; + reg-cam-base = <0x94000>; + rt-wrapper-base = <0x83000>; + interrupt-names = "csid-lite4"; + interrupts = ; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + clock-names = + "cam_cc_cpas_ife_lite_clk", + "cam_cc_ife_lite_ahb_clk", + "cam_cc_ife_lite_csid_clk_src", + "cam_cc_ife_lite_csid_clk", + "cam_cc_ife_lite_cphy_rx_clk", + "cam_cc_ife_lite_clk_src", + "cam_cc_ife_lite_clk"; + clocks = + <&camcc CAM_CC_CPAS_IFE_LITE_CLK>, + <&camcc CAM_CC_IFE_LITE_AHB_CLK>, + <&camcc CAM_CC_IFE_LITE_CSID_CLK_SRC>, + <&camcc CAM_CC_IFE_LITE_CSID_CLK>, + <&camcc CAM_CC_IFE_LITE_CPHY_RX_CLK>, + <&camcc CAM_CC_IFE_LITE_CLK_SRC>, + <&camcc CAM_CC_IFE_LITE_CLK>; + clock-rates = + <0 0 400000000 0 0 400000000 0>, + <0 0 400000000 0 0 480000000 0>; + clock-cntl-level = "svs_l1", "nominal"; + src-clock-name = "cam_cc_ife_lite_csid_clk_src"; + operating-points-v2 = <&csid_lite4_opp_table>; + + clock-control-debugfs = "true"; + status = "ok"; + + csid_lite4_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-400000000 { + opp-hz = /bits/ 64 <400000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + opp-480000000 { + opp-hz = /bits/ 64 <480000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + }; + }; + + cam_icp: qcom,icp { + compatible = "qcom,cam-icp_v3_0"; + reg = <0x0 0xac01000 0x0 0x400>, + <0x0 0xac01800 0x0 0x400>, + <0x0 0xac04000 0x0 0x1000>; + reg-names ="icp_csr", "icp_cirq", "icp_wd0"; + reg-cam-base = <0x1000 0x1800 0x4000>; + interrupts = ; + interrupt-names = "icp"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + memory-region = <&camera_mem>; + src-clock-name = "cam_cc_icp_clk_src"; + clocks = <&camcc CAM_CC_FAST_AHB_CLK_SRC>, + <&camcc CAM_CC_ICP_AHB_CLK>, + <&camcc CAM_CC_ICP_CLK_SRC>, + <&camcc CAM_CC_ICP_CLK>; + clock-names = "cam_cc_soc_fast_ahb_clk_src", + "cam_cc_icp_ahb_clk", + "cam_cc_icp_clk_src", + "cam_cc_icp_clk"; + clock-rates = <300000000 0 480000000 0>, + <400000000 0 600000000 0>; + clock-cntl-level = "svs_l1", "nominal"; + nrt-device; + fw_name = "CAMERA_ICP"; + ubwc-ipe-fetch-cfg = <0x707b 0x7083>; + ubwc-ipe-write-cfg = <0x161ef 0x1620f>; + qos-val = <0xa0a>; + operating-points-v2 = <&icp_opp_table>; + icp-version = <0x0300>; + cam_hw_pid = <12>; + cell-index = <0>; + status = "ok"; + + icp_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-480000000 { + opp-hz = /bits/ 64 <480000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + opp-600000000 { + opp-hz = /bits/ 64 <600000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + }; + }; + + cam_vfe0: qcom,ife0 { + compatible = "qcom,vfe692"; + reg = <0x0 0xac4d000 0x0 0xf000>, + <0x0 0xac1a000 0x0 0x9400>; + reg-names = "ife0", "cam_camnoc"; + reg-cam-base = <0x4d000 0x1a000>; + rt-wrapper-base = <0x4d000>; + interrupts = ; + interrupt-names = "ife0"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + clocks = <&camcc CAM_CC_CPAS_IFE_0_CLK>, + <&camcc CAM_CC_IFE_0_CLK>, + <&camcc CAM_CC_IFE_0_CLK_SRC>, + <&camcc CAM_CC_IFE_0_FAST_AHB_CLK>; + clock-names = "cam_cc_cpas_ife_0_clk", + "cam_cc_ife_0_clk", + "cam_cc_ife_0_clk_src", + "cam_cc_ife_0_fast_ahb_clk"; + clock-rates = <0 0 480000000 0>, + <0 0 600000000 0>; + clock-cntl-level = "svs_l1", "nominal"; + src-clock-name = "cam_cc_ife_0_clk_src"; + operating-points-v2 = <&vfe0_opp_table>; + clock-control-debugfs = "true"; + ubwc-static-cfg = <0x1026 0x1036>; + cam_hw_pid = <8 16>; + cell-index = <0>; + status = "ok"; + + vfe0_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-480000000 { + opp-hz = /bits/ 64 <480000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + opp-600000000 { + opp-hz = /bits/ 64 <600000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + }; + }; + + cam_vfe1: qcom,ife1 { + compatible = "qcom,vfe692"; + reg = <0x0 0xac60000 0x0 0xf000>, + <0x0 0xac1a000 0x0 0x9400>; + reg-names = "ife1", "cam_camnoc"; + reg-cam-base = <0x60000 0x1a000>; + rt-wrapper-base = <0x4d000>; + interrupts = ; + interrupt-names = "ife1"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + clocks = <&camcc CAM_CC_CPAS_IFE_1_CLK>, + <&camcc CAM_CC_IFE_1_CLK>, + <&camcc CAM_CC_IFE_1_CLK_SRC>, + <&camcc CAM_CC_IFE_1_FAST_AHB_CLK>; + clock-names = "cam_cc_cpas_ife_1_clk", + "cam_cc_ife_1_clk", + "cam_cc_ife_1_clk_src", + "cam_cc_ife_1_fast_ahb_clk"; + clock-rates = <0 0 480000000 0>, + <0 0 600000000 0>; + clock-cntl-level = "svs_l1", "nominal"; + src-clock-name = "cam_cc_ife_1_clk_src"; + operating-points-v2 = <&vfe1_opp_table>; + clock-control-debugfs = "true"; + ubwc-static-cfg = <0x1026 0x1036>; + cam_hw_pid = <9 17>; + cell-index = <1>; + status = "ok"; + + vfe1_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-480000000 { + opp-hz = /bits/ 64 <480000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + opp-600000000 { + opp-hz = /bits/ 64 <600000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + }; + }; + + cam_vfe_lite0: qcom,ife-lite0 { + compatible = "qcom,vfe-lite692"; + reg = <0x0 0xac84000 0x0 0x1d00>; + reg-names = "ife-lite0"; + reg-cam-base = <0x84000>; + rt-wrapper-base = <0x83000>; + interrupts = ; + interrupt-names = "ife-lite0"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + clocks = <&camcc CAM_CC_CPAS_IFE_LITE_CLK>, + <&camcc CAM_CC_IFE_LITE_AHB_CLK>, + <&camcc CAM_CC_IFE_LITE_CSID_CLK_SRC>, + <&camcc CAM_CC_IFE_LITE_CSID_CLK>, + <&camcc CAM_CC_IFE_LITE_CPHY_RX_CLK>, + <&camcc CAM_CC_IFE_LITE_CLK_SRC>, + <&camcc CAM_CC_IFE_LITE_CLK>; + clock-names = "cam_cc_cpas_ife_lite_clk", + "cam_cc_ife_lite_ahb_clk", + "cam_cc_ife_lite_csid_clk_src", + "cam_cc_ife_lite_csid_clk", + "cam_cc_ife_lite_cphy_rx_clk", + "cam_cc_ife_lite_clk_src", + "cam_cc_ife_lite_clk"; + clock-rates = <0 0 400000000 0 0 400000000 0>, + <0 0 400000000 0 0 480000000 0>; + clock-cntl-level = "svs_l1", "nominal"; + src-clock-name = "cam_cc_ife_lite_clk_src"; + operating-points-v2 = <&vfe_lite0_opp_table>; + clock-control-debugfs = "true"; + cam_hw_pid = <27>; + cell-index = <2>; + status = "ok"; + + vfe_lite0_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-400000000 { + opp-hz = /bits/ 64 <400000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-480000000 { + opp-hz = /bits/ 64 <480000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + }; + }; + + cam_vfe_lite1: qcom,ife-lite1 { + compatible = "qcom,vfe-lite692"; + reg = <0x0 0xac88000 0x0 0x1d00>; + reg-names = "ife-lite1"; + reg-cam-base = <0x88000>; + rt-wrapper-base = <0x83000>; + interrupts = ; + interrupt-names = "ife-lite1"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + clocks = <&camcc CAM_CC_CPAS_IFE_LITE_CLK>, + <&camcc CAM_CC_IFE_LITE_AHB_CLK>, + <&camcc CAM_CC_IFE_LITE_CSID_CLK_SRC>, + <&camcc CAM_CC_IFE_LITE_CSID_CLK>, + <&camcc CAM_CC_IFE_LITE_CPHY_RX_CLK>, + <&camcc CAM_CC_IFE_LITE_CLK_SRC>, + <&camcc CAM_CC_IFE_LITE_CLK>; + clock-names = "cam_cc_cpas_ife_lite_clk", + "cam_cc_ife_lite_ahb_clk", + "cam_cc_ife_lite_csid_clk_src", + "cam_cc_ife_lite_csid_clk", + "cam_cc_ife_lite_cphy_rx_clk", + "cam_cc_ife_lite_clk_src", + "cam_cc_ife_lite_clk"; + clock-rates = <0 0 400000000 0 0 400000000 0>, + <0 0 400000000 0 0 480000000 0>; + clock-cntl-level = "svs_l1", "nominal"; + src-clock-name = "cam_cc_ife_lite_clk_src"; + operating-points-v2 = <&vfe_lite1_opp_table>; + clock-control-debugfs = "true"; + cam_hw_pid = <27>; + cell-index = <3>; + status = "ok"; + + vfe_lite1_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-400000000 { + opp-hz = /bits/ 64 <400000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-480000000 { + opp-hz = /bits/ 64 <480000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + }; + }; + + cam_vfe_lite2: qcom,ife-lite2 { + compatible = "qcom,vfe-lite692"; + reg = <0x0 0xac8c000 0x0 0x1d00>; + reg-names = "ife-lite2"; + reg-cam-base = <0x8c000>; + rt-wrapper-base = <0x83000>; + interrupts = ; + interrupt-names = "ife-lite2"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + clocks = <&camcc CAM_CC_CPAS_IFE_LITE_CLK>, + <&camcc CAM_CC_IFE_LITE_AHB_CLK>, + <&camcc CAM_CC_IFE_LITE_CSID_CLK_SRC>, + <&camcc CAM_CC_IFE_LITE_CSID_CLK>, + <&camcc CAM_CC_IFE_LITE_CPHY_RX_CLK>, + <&camcc CAM_CC_IFE_LITE_CLK_SRC>, + <&camcc CAM_CC_IFE_LITE_CLK>; + clock-names = "cam_cc_cpas_ife_lite_clk", + "cam_cc_ife_lite_ahb_clk", + "cam_cc_ife_lite_csid_clk_src", + "cam_cc_ife_lite_csid_clk", + "cam_cc_ife_lite_cphy_rx_clk", + "cam_cc_ife_lite_clk_src", + "cam_cc_ife_lite_clk"; + clock-rates = <0 0 400000000 0 0 400000000 0>, + <0 0 400000000 0 0 480000000 0>; + clock-cntl-level = "svs_l1", "nominal"; + src-clock-name = "cam_cc_ife_lite_clk_src"; + operating-points-v2 = <&vfe_lite2_opp_table>; + clock-control-debugfs = "true"; + cam_hw_pid = <27>; + cell-index = <4>; + status = "ok"; + + vfe_lite2_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-400000000 { + opp-hz = /bits/ 64 <400000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-480000000 { + opp-hz = /bits/ 64 <480000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + }; + }; + + cam_vfe_lite3: qcom,ife-lite3 { + compatible = "qcom,vfe-lite692"; + reg = <0x0 0xac90000 0x0 0x1d00>; + reg-names = "ife-lite3"; + reg-cam-base = <0x90000>; + rt-wrapper-base = <0x83000>; + interrupts = ; + interrupt-names = "ife-lite3"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + clocks = <&camcc CAM_CC_CPAS_IFE_LITE_CLK>, + <&camcc CAM_CC_IFE_LITE_AHB_CLK>, + <&camcc CAM_CC_IFE_LITE_CSID_CLK_SRC>, + <&camcc CAM_CC_IFE_LITE_CSID_CLK>, + <&camcc CAM_CC_IFE_LITE_CPHY_RX_CLK>, + <&camcc CAM_CC_IFE_LITE_CLK_SRC>, + <&camcc CAM_CC_IFE_LITE_CLK>; + clock-names = "cam_cc_cpas_ife_lite_clk", + "cam_cc_ife_lite_ahb_clk", + "cam_cc_ife_lite_csid_clk_src", + "cam_cc_ife_lite_csid_clk", + "cam_cc_ife_lite_cphy_rx_clk", + "cam_cc_ife_lite_clk_src", + "cam_cc_ife_lite_clk"; + clock-rates = <0 0 400000000 0 0 400000000 0>, + <0 0 400000000 0 0 480000000 0>; + clock-cntl-level = "svs_l1", "nominal"; + src-clock-name = "cam_cc_ife_lite_clk_src"; + operating-points-v2 = <&vfe_lite3_opp_table>; + clock-control-debugfs = "true"; + cam_hw_pid = <27>; + cell-index = <5>; + status = "ok"; + + vfe_lite3_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-400000000 { + opp-hz = /bits/ 64 <400000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-480000000 { + opp-hz = /bits/ 64 <480000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + }; + }; + + cam_vfe_lite4: qcom,ife-lite4 { + compatible = "qcom,vfe-lite692"; + reg = <0x0 0xac94000 0x0 0x1d00>; + reg-names = "ife-lite4"; + reg-cam-base = <0x94000>; + rt-wrapper-base = <0x83000>; + interrupts = ; + interrupt-names = "ife-lite4"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + clocks = <&camcc CAM_CC_CPAS_IFE_LITE_CLK>, + <&camcc CAM_CC_IFE_LITE_AHB_CLK>, + <&camcc CAM_CC_IFE_LITE_CSID_CLK_SRC>, + <&camcc CAM_CC_IFE_LITE_CSID_CLK>, + <&camcc CAM_CC_IFE_LITE_CPHY_RX_CLK>, + <&camcc CAM_CC_IFE_LITE_CLK_SRC>, + <&camcc CAM_CC_IFE_LITE_CLK>; + clock-names = "cam_cc_cpas_ife_lite_clk", + "cam_cc_ife_lite_ahb_clk", + "cam_cc_ife_lite_csid_clk_src", + "cam_cc_ife_lite_csid_clk", + "cam_cc_ife_lite_cphy_rx_clk", + "cam_cc_ife_lite_clk_src", + "cam_cc_ife_lite_clk"; + clock-rates = <0 0 400000000 0 0 400000000 0>, + <0 0 400000000 0 0 480000000 0>; + clock-cntl-level = "svs_l1", "nominal"; + src-clock-name = "cam_cc_ife_lite_clk_src"; + operating-points-v2 = <&vfe_lite4_opp_table>; + clock-control-debugfs = "true"; + cam_hw_pid = <27>; + cell-index = <6>; + status = "ok"; + + vfe_lite4_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-400000000 { + opp-hz = /bits/ 64 <400000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-480000000 { + opp-hz = /bits/ 64 <480000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + }; + }; + + cam_ipe0: qcom,ipe0 { + compatible = "qcom,cam-ipe"; + reg = <0x0 0xac2d000 0x0 0x18000>; + reg-names = "ipe0_top"; + reg-cam-base = <0x2d000>; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + src-clock-name = "cam_cc_ipe_clk_src"; + clocks = <&camcc CAM_CC_CPAS_IPE_CLK>, + <&camcc CAM_CC_IPE_AHB_CLK>, + <&camcc CAM_CC_IPE_CLK>, + <&camcc CAM_CC_IPE_CLK_SRC>, + <&camcc CAM_CC_IPE_FAST_AHB_CLK>, + <&camcc CAM_CC_FAST_AHB_CLK_SRC>; + clock-names = "cam_cc_cpas_ipe_clk", + "cam_cc_ipe_ahb_clk", + "cam_cc_ipe_clk", + "cam_cc_ipe_clk_src", + "cam_cc_ipe_fast_ahb_clk", + "cam_cc_fast_ahb_clk_src"; + clock-rates = <0 0 0 480000000 0 300000000>, + <0 0 0 600000000 0 400000000>; + clock-cntl-level = "svs_l1", "nominal"; + operating-points-v2 = <&ipe0_opp_table>; + nrt-device; + cam_hw_pid = <14 15>; + cell-index = <0>; + status = "ok"; + + ipe0_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-480000000 { + opp-hz = /bits/ 64 <480000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-600000000 { + opp-hz = /bits/ 64 <600000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + }; + }; + + qcom,rt-cdm0 { + compatible = "qcom,cam-rt-cdm2_1"; + label = "rt-cdm"; + reg = <0x0 0xac26000 0x0 0x1000>; + reg-names = "rt-cdm0"; + reg-cam-base = <0x26000>; + interrupts = ; + interrupt-names = "rt-cdm0"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + clocks = <&camcc CAM_CC_FAST_AHB_CLK_SRC>, + <&camcc CAM_CC_CPAS_AHB_CLK>; + clock-names = "cam_cc_fast_ahb_clk_src", + "cam_cc_cpas_ahb_clk"; + src-clock-name = "cam_cc_fast_ahb_clk_src"; + clock-rates = <300000000 0>; + operating-points-v2 = <&cdm_cpas_opp_table0>; + clock-cntl-level = "svs"; + cdm-client-names = "ife0", "dualife0"; + single-context-cdm; + cell-index = <0>; + status = "ok"; + + cdm_cpas_opp_table0: opp-table { + compatible = "operating-points-v2"; + + opp-300000000 { + opp-hz = /bits/ 64 <300000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + }; + }; + + qcom,rt-cdm1 { + compatible = "qcom,cam-rt-cdm2_1"; + label = "rt-cdm"; + reg = <0x0 0xac27000 0x0 0x1000>; + reg-names = "rt-cdm1"; + reg-cam-base = <0x27000>; + interrupts = ; + interrupt-names = "rt-cdm1"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + clocks = <&camcc CAM_CC_FAST_AHB_CLK_SRC>, + <&camcc CAM_CC_CPAS_AHB_CLK>; + clock-names = "cam_cc_fast_ahb_clk_src", + "cam_cc_cpas_ahb_clk"; + src-clock-name = "cam_cc_fast_ahb_clk_src"; + clock-rates = <300000000 0>; + operating-points-v2 = <&cdm_cpas_opp_table1>; + clock-cntl-level = "svs_l1"; + cdm-client-names = "ife1", "dualife1"; + single-context-cdm; + cell-index = <1>; + status = "ok"; + + cdm_cpas_opp_table1: opp-table { + compatible = "operating-points-v2"; + + opp-300000000 { + opp-hz = /bits/ 64 <300000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + }; + }; + + qcom,rt-cdm2 { + compatible = "qcom,cam-rt-cdm2_1"; + label = "rt-cdm"; + reg = <0x0 0xac28000 0x0 0x1000>; + reg-names = "rt-cdm2"; + reg-cam-base = <0x28000>; + interrupts = ; + interrupt-names = "rt-cdm2"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + clocks = <&camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&camcc CAM_CC_CPAS_AHB_CLK>; + clock-names = "cam_cc_slow_ahb_clk_src", + "cam_cc_cpas_ahb_clk"; + src-clock-name = "cam_cc_slow_ahb_clk_src"; + clock-rates = <80000000 0>; + operating-points-v2 = <&cdm_cpas_opp_table2>; + clock-cntl-level = "svs_l1"; + cdm-client-names = "ife2", "ife3", "ife4", "ife5", "ife6"; + single-context-cdm; + cell-index = <2>; + status = "ok"; + + cdm_cpas_opp_table2: opp-table { + compatible = "operating-points-v2"; + + opp-80000000 { + opp-hz = /bits/ 64 <80000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + }; + }; + + qcom,rt-cdm3 { + compatible = "qcom,cam-rt-cdm2_1"; + label = "rt-cdm"; + reg = <0x0 0xac29000 0x0 0x1000>; + reg-names = "rt-cdm3"; + reg-cam-base = <0x29000>; + interrupts = ; + interrupt-names = "rt-cdm3"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + clocks = <&camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&camcc CAM_CC_CPAS_AHB_CLK>; + clock-names = "cam_cc_slow_ahb_clk_src", + "cam_cc_cpas_ahb_clk"; + src-clock-name = "cam_cc_slow_ahb_clk_src"; + clock-rates = <80000000 0>; + operating-points-v2 = <&cdm_cpas_opp_table3>; + clock-cntl-level = "svs"; + cdm-client-names = "ife2", "ife3", "ife4", "ife5", "ife6"; + single-context-cdm; + cell-index = <3>; + status = "ok"; + + cdm_cpas_opp_table3: opp-table { + compatible = "operating-points-v2"; + + opp-80000000 { + opp-hz = /bits/ 64 <80000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + }; + }; + + cam_sfe_lite0: qcom,sfe-lite0 { + compatible = "qcom,sfe-lite692"; + reg = <0x0 0xac74000 0x0 0x1000>; + reg-names = "sfe-lite0"; + reg-cam-base = <0x74000>; + rt-wrapper-base = <0x4d000>; + interrupts = ; + interrupt-names = "sfe-lite0"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + clocks = <&camcc CAM_CC_SFE_LITE_0_FAST_AHB_CLK>, + <&camcc CAM_CC_SFE_LITE_0_CLK>, + <&camcc CAM_CC_CPAS_SFE_LITE_0_CLK>; + clock-names = "cam_cc_sfe_lite_0_fast_ahb_clk", + "cam_cc_sfe_lite_0_clk", + "cam_cc_cpas_sfe_lite_0_clk"; + clock-rates = <0 480000000 300000000>, + <0 600000000 400000000>; + clock-cntl-level = "svs_l1", "nominal"; + src-clock-name = "cam_cc_sfe_lite_0_clk"; + operating-points-v2 = <&cam_sfe_lite_opp_table0>; + cam_hw_pid = <4>; + clock-control-debugfs = "true"; + cell-index = <0>; + status = "ok"; + + cam_sfe_lite_opp_table0: opp-table { + compatible = "operating-points-v2"; + + opp-480000000 { + opp-hz = /bits/ 64 <480000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-600000000 { + opp-hz = /bits/ 64 <600000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + }; + }; + + cam_sfe_lite1: qcom,sfe-lite1 { + compatible = "qcom,sfe-lite692"; + reg = <0x0 0xac75000 0x0 0x1000>; + reg-names = "sfe-lite1"; + reg-cam-base = <0x75000>; + rt-wrapper-base = <0x4d000>; + interrupts = ; + interrupt-names = "sfe-lite1"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + clocks = <&camcc CAM_CC_SFE_LITE_1_FAST_AHB_CLK>, + <&camcc CAM_CC_SFE_LITE_1_CLK>, + <&camcc CAM_CC_CPAS_SFE_LITE_1_CLK>; + clock-names = "cam_cc_sfe_lite_1_fast_ahb_clk", + "cam_cc_sfe_lite_1_clk", + "cam_cc_cpas_sfe_1_clk"; + clock-rates = <0 480000000 300000000>, + <0 600000000 400000000>; + clock-cntl-level = "svs_l1", "nominal"; + src-clock-name = "cam_cc_sfe_lite_1_clk"; + operating-points-v2 = <&cam_sfe_lite_opp_table1>; + cam_hw_pid = <5>; + clock-control-debugfs = "true"; + cell-index = <1>; + status = "ok"; + + cam_sfe_lite_opp_table1: opp-table { + compatible = "operating-points-v2"; + + opp-480000000 { + opp-hz = /bits/ 64 <480000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-600000000 { + opp-hz = /bits/ 64 <600000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + }; + }; +}; + +&tlmm { + cam_sensor_mclk0_active: cam-sensor-mclk0-active { + /* MCLK0 */ + mux { + pins = "gpio67"; + function = "cam_mclk"; + }; + + config { + pins = "gpio67"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk0_suspend: cam-sensor-mclk0-suspend { + /* MCLK0 */ + mux { + pins = "gpio67"; + function = "cam_mclk"; + }; + + config { + pins = "gpio67"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk1_active: cam-sensor-mclk1-active { + /* MCLK1 */ + mux { + pins = "gpio68"; + function = "cam_mclk"; + }; + + config { + pins = "gpio68"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk1_suspend: cam-sensor-mclk1-suspend { + /* MCLK1 */ + mux { + pins = "gpio68"; + function = "cam_mclk"; + }; + + config { + pins = "gpio68"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk2_active: cam-sensor-mclk2-active { + /* MCLK2 */ + mux { + pins = "gpio69"; + function = "cam_mclk"; + }; + + config { + pins = "gpio69"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk2_suspend: cam-sensor-mclk2-suspend { + /* MCLK2 */ + mux { + pins = "gpio69"; + function = "cam_mclk"; + }; + + config { + pins = "gpio69"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cci_i2c_scl0_active: cci-i2c-scl0-active { + mux { + /* CLK, DATA */ + pins = "gpio58"; + function = "cci_i2c_scl"; + }; + + config { + pins = "gpio58"; + bias-pull-up; /* PULL UP*/ + drive-strength = <2>; /* 2 MA */ + qcom,i2c_pull; + }; + }; + + cci_i2c_scl0_suspend: cci-i2c-scl0-suspend { + mux { + /* CLK, DATA */ + pins = "gpio58"; + function = "cci_i2c_scl"; + }; + + config { + pins = "gpio58"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cci_i2c_scl1_active: cci-i2c-scl1-active { + mux { + /* CLK, DATA */ + pins = "gpio30"; + function = "cci_i2c_scl"; + }; + + config { + pins = "gpio30"; + bias-pull-up; /* PULL UP*/ + drive-strength = <2>; /* 2 MA */ + qcom,i2c_pull; + }; + }; + + cci_i2c_scl1_suspend: cci-i2c-scl1-suspend { + mux { + /* CLK, DATA */ + pins = "gpio30"; + function = "cci_i2c_scl"; + }; + + config { + pins = "gpio30"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cci_i2c_scl2_active: cci-i2c-scl2-active { + mux { + /* CLK, DATA */ + pins = "gpio60"; + function = "cci_i2c_scl"; + }; + + config { + pins = "gpio60"; + bias-pull-up; /* PULL UP*/ + drive-strength = <2>; /* 2 MA */ + qcom,i2c_pull; + }; + }; + + cci_i2c_scl2_suspend: cci-i2c-scl2-suspend { + mux { + /* CLK, DATA */ + pins = "gpio60"; + function = "cci_i2c_scl"; + }; + + config { + pins = "gpio60"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cci_i2c_scl3_active: cci-i2c-scl3-active { + mux { + pins = "gpio32"; + function = "cci_i2c_scl"; + }; + + config { + pins = "gpio32"; + bias-pull-up; /* PULL UP*/ + drive-strength = <2>; /* 2 MA */ + qcom,i2c_pull; + }; + }; + + cci_i2c_scl3_suspend: cci-i2c-scl3-suspend { + mux { + pins = "gpio32"; + function = "cci_i2c_scl"; + }; + + config { + pins = "gpio32"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cci_i2c_scl4_active: cci-i2c-scl4-active { + mux { + /* CLK, DATA */ + pins = "gpio62"; + function = "cci_i2c_scl"; + }; + + config { + pins = "gpio62"; + bias-pull-up; /* PULL UP*/ + drive-strength = <2>; /* 2 MA */ + qcom,i2c_pull; + }; + }; + + cci_i2c_scl4_suspend: cci-i2c-scl4-suspend { + mux { + /* CLK, DATA */ + pins = "gpio62"; + function = "cci_i2c_scl"; + }; + + config { + pins = "gpio62"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cci_i2c_scl5_active: cci-i2c-scl5-active { + mux { + /* CLK, DATA */ + pins = "gpio55"; + function = "cci_i2c_scl"; + }; + + config { + pins = "gpio55"; + bias-pull-up; /* PULL UP*/ + drive-strength = <2>; /* 2 MA */ + qcom,i2c_pull; + }; + }; + + cci_i2c_scl5_suspend: cci-i2c-scl5-suspend { + mux { + /* CLK, DATA */ + pins = "gpio55"; + function = "cci_i2c_scl"; + }; + + config { + pins = "gpio55"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cci_i2c_sda0_active: cci-i2c-sda0-active { + mux { + /* CLK, DATA */ + pins = "gpio57"; + function = "cci_i2c_sda"; + }; + + config { + pins = "gpio57"; + bias-pull-up; /* PULL UP*/ + drive-strength = <2>; /* 2 MA */ + qcom,i2c_pull; + }; + }; + + cci_i2c_sda0_suspend: cci-i2c-sda0-suspend { + mux { + /* CLK, DATA */ + pins = "gpio57"; + function = "cci_i2c_sda"; + }; + + config { + pins = "gpio57"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cci_i2c_sda1_active: cci-i2c-sda1-active { + mux { + /* CLK, DATA */ + pins = "gpio29"; + function = "cci_i2c_sda"; + }; + + config { + pins = "gpio29"; + bias-pull-up; /* PULL UP*/ + drive-strength = <2>; /* 2 MA */ + qcom,i2c_pull; + }; + }; + + cci_i2c_sda1_suspend: cci-i2c-sda1-suspend { + mux { + /* CLK, DATA */ + pins = "gpio29"; + function = "cci_i2c_sda"; + }; + + config { + pins = "gpio29"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cci_i2c_sda2_active: cci-i2c-sda2-active { + mux { + /* CLK, DATA */ + pins = "gpio59"; + function = "cci_i2c_sda"; + }; + + config { + pins = "gpio59"; + bias-pull-up; /* PULL UP*/ + drive-strength = <2>; /* 2 MA */ + qcom,i2c_pull; + }; + }; + + cci_i2c_sda2_suspend: cci-i2c-sda2-suspend { + mux { + /* CLK, DATA */ + pins = "gpio59"; + function = "cci_i2c_sda"; + }; + + config { + pins = "gpio59"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cci_i2c_sda3_active: cci-i2c-sda3-active { + mux { + pins = "gpio31"; + function = "cci_i2c_sda"; + }; + + config { + pins = "gpio31"; + bias-pull-up; /* PULL UP*/ + drive-strength = <2>; /* 2 MA */ + qcom,i2c_pull; + }; + }; + + cci_i2c_sda3_suspend: cci-i2c-sda3-suspend { + mux { + pins = "gpio31"; + function = "cci_i2c_sda"; + }; + + config { + pins = "gpio31"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cci_i2c_sda4_active: cci-i2c-sda4-active { + mux { + /* CLK, DATA */ + pins = "gpio61"; + function = "cci_i2c_sda"; + }; + + config { + pins = "gpio61"; + bias-pull-up; /* PULL UP*/ + drive-strength = <2>; /* 2 MA */ + qcom,i2c_pull; + }; + }; + + cci_i2c_sda4_suspend: cci-i2c-sda4-suspend { + mux { + /* CLK, DATA */ + pins = "gpio61"; + function = "cci_i2c_sda"; + }; + + config { + pins = "gpio61"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cci_i2c_sda5_active: cci-i2c-sda5-active { + mux { + /* CLK, DATA */ + pins = "gpio54"; + function = "cci_i2c_sda"; + }; + + config { + pins = "gpio54"; + bias-pull-up; /* PULL UP*/ + drive-strength = <2>; /* 2 MA */ + qcom,i2c_pull; + }; + }; + + cci_i2c_sda5_suspend: cci-i2c-sda5-suspend { + mux { + /* CLK, DATA */ + pins = "gpio54"; + function = "cci_i2c_sda"; + }; + + config { + pins = "gpio54"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/monaco-evk-camera-sensor.dtsi b/arch/arm64/boot/dts/qcom/monaco-evk-camera-sensor.dtsi new file mode 100644 index 0000000000000..167b85c0e8844 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/monaco-evk-camera-sensor.dtsi @@ -0,0 +1,794 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#include + +&cam_cci0 { + /* GMSL deserializer 0 */ + qcom,cam-gmsl-deserializer0 { + cell-index = <0>; + csiphy-sd-index = <0>; + sensor-position-roll = <0>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + regulator-names = "cam_vio"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000>; + rgltr-max-voltage = <1800000>; + rgltr-load-current = <120000>; + gpio-no-mux = <0>; + pinctrl-0 = <&cam_sensor_mclk0_active>; + pinctrl-1 = <&cam_sensor_mclk0_suspend>; + pinctrl-names = "cam_default", "cam_suspend"; + gpios = <&tlmm 73 0>; + gpio-reset = <0>; + gpio-req-tbl-num = <0>; + gpio-req-tbl-flags = <0>; + gpio-req-tbl-label = "CAM_RESET0"; + cci-master = <0>; + clocks = <&camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "nominal"; + clock-rates = <24000000>; + status = "ok"; + + port@0 { + reg = <0>; + + deser0_port0: endpoint { + remote-endpoint = <&gmsl_sensor0_ep>; + }; + }; + + port@1 { + reg = <1>; + + deser0_port1: endpoint { + remote-endpoint = <&gmsl_sensor1_ep>; + }; + }; + + port@2 { + reg = <0>; + + deser0_port2: endpoint { + remote-endpoint = <&gmsl_sensor2_ep>; + }; + }; + + port@3 { + reg = <1>; + + deser0_port3: endpoint { + remote-endpoint = <&gmsl_sensor3_ep>; + }; + }; + }; + + /* GMSL deserializer 0 sensor 0 */ + qcom,cam-gmsl-sensor0 { + compatible = "qcom,cam-gmsl-sensor"; + cell-index = <0>; + csiphy-sd-index = <0>; + status = "ok"; + + port { + gmsl_sensor0_ep: endpoint { + remote-endpoint = <&deser0_port0>; + }; + }; + }; + + /* GMSL deserializer 0 sensor 1 */ + qcom,cam-gmsl-sensor1 { + compatible = "qcom,cam-gmsl-sensor"; + cell-index = <1>; + csiphy-sd-index = <0>; + status = "ok"; + + port { + gmsl_sensor1_ep: endpoint { + remote-endpoint = <&deser0_port1>; + }; + }; + }; + + /* GMSL deserializer 0 sensor 2 */ + qcom,cam-gmsl-sensor2 { + compatible = "qcom,cam-gmsl-sensor"; + cell-index = <2>; + csiphy-sd-index = <0>; + status = "ok"; + + port { + gmsl_sensor2_ep: endpoint { + remote-endpoint = <&deser0_port2>; + }; + }; + }; + + /* GMSL deserializer 0 sensor 3 */ + qcom,cam-gmsl-sensor3 { + compatible = "qcom,cam-gmsl-sensor"; + cell-index = <3>; + csiphy-sd-index = <0>; + status = "ok"; + + port { + gmsl_sensor3_ep: endpoint { + remote-endpoint = <&deser0_port3>; + }; + }; + }; + + /*cam0-ov9282*/ + rb4_slot0: qcom,cam-sensor16 { + compatible = "qcom,cam-sensor"; + cell-index = <16>; + csiphy-sd-index = <0>; + sensor-position-roll = <0>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + regulator-names = "cam_vio"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000>; + rgltr-max-voltage = <1800000>; + rgltr-load-current = <120000>; + gpio-no-mux = <0>; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_active_rst0>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_suspend_rst0>; + pinctrl-names = "cam_default", "cam_suspend"; + gpios = <&tlmm 67 0>, + <&tlmm 73 0>, + <&expander2 0 0>; + gpio-reset = <1>; + gpio-custom1 = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAM_MCLK0", + "CAMIF_RESET0", + "CAM_CUSTOM1"; + cci-master = <0>; + clocks = <&camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "nominal"; + clock-rates = <24000000>; + status = "ok"; + }; + + /*cam0-imx577*/ + qcom,cam-sensor20 { + compatible = "qcom,cam-sensor"; + cell-index = <20>; + csiphy-sd-index = <0>; + sensor-position-roll = <0>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + eeprom-src = <&eeprom_cam20>; + regulator-names = "cam_vio"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000>; + rgltr-max-voltage = <1800000>; + rgltr-load-current = <120000>; + gpio-no-mux = <0>; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_active_rst0>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_suspend_rst0>; + pinctrl-names = "cam_default", "cam_suspend"; + gpios = <&tlmm 67 0>, + <&tlmm 73 0>, + <&expander2 0 0>; + gpio-reset = <1>; + gpio-custom1 = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAM_MCLK0", + "CAMIF_RESET0", + "CAM_CUSTOM1"; + cci-master = <0>; + clocks = <&camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "nominal"; + clock-rates = <24000000>; + status = "ok"; + }; + + eeprom_cam20: qcom,eeprom20 { + cell-index = <20>; + compatible = "qcom,eeprom"; + regulator-names = "cam_vio"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000>; + rgltr-max-voltage = <1800000>; + rgltr-load-current = <120000>; + gpio-no-mux = <0>; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_active_rst0>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_suspend_rst0>; + pinctrl-names = "cam_default", "cam_suspend"; + gpios = <&tlmm 67 0>, + <&tlmm 73 0>, + <&expander2 0 0>; + gpio-reset = <1>; + gpio-custom1 = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAM_MCLK0", + "CAMIF_RESET0", + "CAM_CUSTOM1"; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "nominal"; + clock-rates = <24000000>; + }; +}; + +&cam_cci1 { + /* GMSL deserializer 1 */ + qcom,cam-gmsl-deserializer1 { + cell-index = <1>; + csiphy-sd-index = <1>; + sensor-position-roll = <0>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + regulator-names = "cam_vio"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000>; + rgltr-max-voltage = <1800000>; + rgltr-load-current = <120000>; + gpio-no-mux = <0>; + pinctrl-0 = <&cam_sensor_mclk1_active>; + pinctrl-1 = <&cam_sensor_mclk1_suspend>; + pinctrl-names = "cam_default", "cam_suspend"; + gpios = <&tlmm 74 0>; + gpio-reset = <0>; + gpio-req-tbl-num = <0>; + gpio-req-tbl-flags = <0>; + gpio-req-tbl-label = "CAM_RESET1"; + cci-master = <0>; + clocks = <&camcc CAM_CC_MCLK1_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "nominal"; + clock-rates = <24000000>; + status = "ok"; + + port@0 { + reg = <0>; + + deser1_port0: endpoint { + remote-endpoint = <&gmsl_sensor4_ep>; + }; + }; + + port@1 { + reg = <1>; + + deser1_port1: endpoint { + remote-endpoint = <&gmsl_sensor5_ep>; + }; + }; + + port@2 { + reg = <0>; + + deser1_port2: endpoint { + remote-endpoint = <&gmsl_sensor6_ep>; + }; + }; + + port@3 { + reg = <1>; + + deser1_port3: endpoint { + remote-endpoint = <&gmsl_sensor7_ep>; + }; + }; + }; + + /* GMSL deserializer 1 sensor 0 */ + qcom,cam-gmsl-sensor4 { + compatible = "qcom,cam-gmsl-sensor"; + cell-index = <4>; + csiphy-sd-index = <1>; + status = "ok"; + + port { + gmsl_sensor4_ep: endpoint { + remote-endpoint = <&deser1_port0>; + }; + }; + }; + + /* GMSL deserializer 1 sensor 1 */ + qcom,cam-gmsl-sensor5 { + compatible = "qcom,cam-gmsl-sensor"; + cell-index = <5>; + csiphy-sd-index = <1>; + status = "ok"; + + port { + gmsl_sensor5_ep: endpoint { + remote-endpoint = <&deser1_port1>; + }; + }; + }; + + /* GMSL deserializer 1 sensor 2 */ + qcom,cam-gmsl-sensor6 { + compatible = "qcom,cam-gmsl-sensor"; + cell-index = <6>; + csiphy-sd-index = <1>; + status = "ok"; + + port { + gmsl_sensor6_ep: endpoint { + remote-endpoint = <&deser1_port2>; + }; + }; + }; + + /* GMSL deserializer 1 sensor 3 */ + qcom,cam-gmsl-sensor7 { + compatible = "qcom,cam-gmsl-sensor"; + cell-index = <7>; + csiphy-sd-index = <1>; + status = "ok"; + + port { + gmsl_sensor7_ep: endpoint { + remote-endpoint = <&deser1_port3>; + }; + }; + }; + + /*cam1-ov9282*/ + rb4_slot1: qcom,cam-sensor17 { + compatible = "qcom,cam-sensor"; + cell-index = <17>; + csiphy-sd-index = <1>; + sensor-position-roll = <0>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + regulator-names = "cam_vio"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000>; + rgltr-max-voltage = <1800000>; + rgltr-load-current = <120000>; + gpio-no-mux = <0>; + pinctrl-0 = <&cam_sensor_mclk1_active + &cam_sensor_active_rst1>; + pinctrl-1 = <&cam_sensor_mclk1_suspend + &cam_sensor_suspend_rst1>; + pinctrl-names = "cam_default", "cam_suspend"; + gpios = <&tlmm 68 0>, + <&tlmm 74 0>, + <&expander2 1 0>; + gpio-reset = <1>; + gpio-custom1 = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAM_MCLK1", + "CAMIF_RESET1", + "CAM_CUSTOM1"; + cci-master = <0>; + clocks = <&camcc CAM_CC_MCLK1_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "nominal"; + clock-rates = <24000000>; + status = "ok"; + }; + + /*cam0-imx577*/ + qcom,cam-sensor19 { + compatible = "qcom,cam-sensor"; + cell-index = <19>; + csiphy-sd-index = <1>; + sensor-position-roll = <0>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + eeprom-src = <&eeprom_cam19>; + regulator-names = "cam_vio"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000>; + rgltr-max-voltage = <1800000>; + rgltr-load-current = <120000>; + gpio-no-mux = <0>; + pinctrl-0 = <&cam_sensor_mclk1_active + &cam_sensor_active_rst1>; + pinctrl-1 = <&cam_sensor_mclk1_suspend + &cam_sensor_suspend_rst1>; + pinctrl-names = "cam_default", "cam_suspend"; + gpios = <&tlmm 68 0>, + <&tlmm 74 0>, + <&expander2 1 0>; + gpio-reset = <1>; + gpio-custom1 = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAM_MCLK1", + "CAMIF_RESET1", + "CAM_CUSTOM1"; + cci-master = <0>; + clocks = <&camcc CAM_CC_MCLK1_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "nominal"; + clock-rates = <24000000>; + status = "ok"; + }; + + /*cam0-imx577*/ + qcom,cam-sensor21 { + compatible = "qcom,cam-sensor"; + cell-index = <21>; + csiphy-sd-index = <1>; + sensor-position-roll = <0>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + eeprom-src = <&eeprom_cam21>; + regulator-names = "cam_vio"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000>; + rgltr-max-voltage = <1800000>; + rgltr-load-current = <120000>; + gpio-no-mux = <0>; + pinctrl-0 = <&cam_sensor_mclk1_active + &cam_sensor_active_rst1>; + pinctrl-1 = <&cam_sensor_mclk1_suspend + &cam_sensor_suspend_rst1>; + pinctrl-names = "cam_default", "cam_suspend"; + gpios = <&tlmm 68 0>, + <&tlmm 74 0>, + <&expander2 1 0>; + gpio-reset = <1>; + gpio-custom1 = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAM_MCLK1", + "CAMIF_RESET1", + "CAM_CUSTOM1"; + cci-master = <0>; + clocks = <&camcc CAM_CC_MCLK1_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "nominal"; + clock-rates = <24000000>; + status = "ok"; + }; + + eeprom_cam19: qcom,eeprom19 { + compatible = "qcom,eeprom"; + cell-index = <19>; + regulator-names = "cam_vio"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000>; + rgltr-max-voltage = <1800000>; + rgltr-load-current = <120000>; + gpio-no-mux = <0>; + pinctrl-0 = <&cam_sensor_mclk1_active + &cam_sensor_active_rst1>; + pinctrl-1 = <&cam_sensor_mclk1_suspend + &cam_sensor_suspend_rst1>; + pinctrl-names = "cam_default", "cam_suspend"; + gpios = <&tlmm 68 0>, + <&tlmm 74 0>, + <&expander2 1 0>; + gpio-reset = <1>; + gpio-custom1 = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAM_MCLK1", + "CAMIF_RESET1", + "CAM_CUSTOM1"; + sensor-mode = <0>; + cci-master = <0>; + clocks = <&camcc CAM_CC_MCLK1_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "nominal"; + clock-rates = <24000000>; + status = "ok"; + }; + + eeprom_cam21: qcom,eeprom21 { + compatible = "qcom,eeprom"; + cell-index = <21>; + regulator-names = "cam_vio"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000>; + rgltr-max-voltage = <1800000>; + rgltr-load-current = <120000>; + gpio-no-mux = <0>; + pinctrl-0 = <&cam_sensor_mclk1_active + &cam_sensor_active_rst1>; + pinctrl-1 = <&cam_sensor_mclk1_suspend + &cam_sensor_suspend_rst1>; + pinctrl-names = "cam_default", "cam_suspend"; + gpios = <&tlmm 68 0>, + <&tlmm 74 0>, + <&expander2 1 0>; + gpio-reset = <1>; + gpio-custom1 = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAM_MCLK1", + "CAMIF_RESET1", + "CAM_CUSTOM1"; + sensor-mode = <0>; + cci-master = <0>; + clocks = <&camcc CAM_CC_MCLK1_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "nominal"; + clock-rates = <24000000>; + status = "ok"; + }; +}; + +&cam_cci2 { + /* GMSL deserializer 2 */ + qcom,cam-gmsl-deserializer2 { + cell-index = <2>; + csiphy-sd-index = <2>; + sensor-position-roll = <0>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + regulator-names = "cam_vio"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000>; + rgltr-max-voltage = <1800000>; + rgltr-load-current = <120000>; + gpio-no-mux = <0>; + pinctrl-0 = <&cam_sensor_mclk2_active>; + pinctrl-1 = <&cam_sensor_mclk2_suspend>; + pinctrl-names = "cam_default", "cam_suspend"; + gpios = <&tlmm 75 0>; + gpio-reset = <0>; + gpio-req-tbl-num = <0>; + gpio-req-tbl-flags = <0>; + gpio-req-tbl-label = "CAM_RESET2"; + cci-master = <0>; + clocks = <&camcc CAM_CC_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "nominal"; + clock-rates = <24000000>; + status = "ok"; + + port@0 { + reg = <0>; + + deser2_port0: endpoint { + remote-endpoint = <&gmsl_sensor8_ep>; + }; + }; + + port@1 { + reg = <1>; + + deser2_port1: endpoint { + remote-endpoint = <&gmsl_sensor9_ep>; + }; + }; + + port@2 { + reg = <0>; + + deser2_port2: endpoint { + remote-endpoint = <&gmsl_sensor10_ep>; + }; + }; + + port@3 { + reg = <1>; + + deser2_port3: endpoint { + remote-endpoint = <&gmsl_sensor11_ep>; + }; + }; + }; + + /* GMSL deserializer 2 sensor 0 */ + qcom,cam-gmsl-sensor8 { + compatible = "qcom,cam-gmsl-sensor"; + cell-index = <8>; + csiphy-sd-index = <2>; + status = "ok"; + + port { + gmsl_sensor8_ep: endpoint { + remote-endpoint = <&deser2_port0>; + }; + }; + }; + + /* GMSL deserializer 2 sensor 1 */ + qcom,cam-gmsl-sensor9 { + compatible = "qcom,cam-gmsl-sensor"; + cell-index = <9>; + csiphy-sd-index = <2>; + status = "ok"; + + port { + gmsl_sensor9_ep: endpoint { + remote-endpoint = <&deser2_port1>; + }; + }; + }; + + /* GMSL deserializer 2 sensor 2 */ + qcom,cam-gmsl-sensor10 { + compatible = "qcom,cam-gmsl-sensor"; + cell-index = <10>; + csiphy-sd-index = <2>; + status = "ok"; + + port { + gmsl_sensor10_ep: endpoint { + remote-endpoint = <&deser2_port2>; + }; + }; + }; + + /* GMSL deserializer 2 sensor 3 */ + qcom,cam-gmsl-sensor11 { + compatible = "qcom,cam-gmsl-sensor"; + cell-index = <11>; + csiphy-sd-index = <2>; + status = "ok"; + + port { + gmsl_sensor11_ep: endpoint { + remote-endpoint = <&deser2_port3>; + }; + }; + }; + + /*cam2-ov9282*/ + rb4_slot2: qcom,cam-sensor18 { + compatible = "qcom,cam-sensor"; + cell-index = <18>; + csiphy-sd-index = <2>; + sensor-position-roll = <0>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + regulator-names = "cam_vio"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000>; + rgltr-max-voltage = <1800000>; + rgltr-load-current = <120000>; + gpio-no-mux = <0>; + pinctrl-0 = <&cam_sensor_mclk2_active + &cam_sensor_active_rst2>; + pinctrl-1 = <&cam_sensor_mclk2_suspend + &cam_sensor_suspend_rst2>; + pinctrl-names = "cam_default", "cam_suspend"; + gpios = <&tlmm 69 0>, + <&tlmm 75 0>, + <&expander2 2 0>; + gpio-reset = <1>; + gpio-custom1 = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAM_MCLK2", + "CAMIF_RESET2", + "CAM_CUSTOM1"; + cci-master = <0>; + clocks = <&camcc CAM_CC_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "nominal"; + clock-rates = <24000000>; + status = "ok"; + }; + + /*cam2-imx577*/ + qcom,cam-sensor22 { + compatible = "qcom,cam-sensor"; + cell-index = <22>; + csiphy-sd-index = <2>; + sensor-position-roll = <0>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + eeprom-src = <&eeprom_cam22>; + regulator-names = "cam_vio"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000>; + rgltr-max-voltage = <1800000>; + rgltr-load-current = <120000>; + gpio-no-mux = <0>; + pinctrl-0 = <&cam_sensor_mclk2_active + &cam_sensor_active_rst2>; + pinctrl-1 = <&cam_sensor_mclk2_suspend + &cam_sensor_suspend_rst2>; + pinctrl-names = "cam_default", "cam_suspend"; + gpios = <&tlmm 69 0>, + <&tlmm 75 0>, + <&expander2 2 0>; + gpio-reset = <1>; + gpio-custom1 = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAM_MCLK2", + "CAMIF_RESET2", + "CAM_CUSTOM1"; + cci-master = <0>; + clocks = <&camcc CAM_CC_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "nominal"; + clock-rates = <24000000>; + status = "ok"; + }; + + eeprom_cam22: qcom,eeprom22 { + compatible = "qcom,eeprom"; + cell-index = <22>; + regulator-names = "cam_vio"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000>; + rgltr-max-voltage = <1800000>; + rgltr-load-current = <120000>; + gpio-no-mux = <0>; + pinctrl-0 = <&cam_sensor_mclk2_active + &cam_sensor_active_rst2>; + pinctrl-1 = <&cam_sensor_mclk2_suspend + &cam_sensor_suspend_rst2>; + pinctrl-names = "cam_default", "cam_suspend"; + gpios = <&tlmm 69 0>, + <&tlmm 75 0>, + <&expander2 2 0>; + gpio-reset = <1>; + gpio-custom1 = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAM_MCLK2", + "CAMIF_RESET2", + "CAM_CUSTOM1"; + sensor-mode = <0>; + cci-master = <0>; + clocks = <&camcc CAM_CC_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "nominal"; + clock-rates = <24000000>; + status = "ok"; + }; +}; + +&soc { + qcom,cam-res-mgr { + compatible = "qcom,cam-res-mgr"; + status = "ok"; + gpios-shared = <609 610 611>; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/monaco-evk-camx.dtso b/arch/arm64/boot/dts/qcom/monaco-evk-camx.dtso new file mode 100644 index 0000000000000..3945c77528ccb --- /dev/null +++ b/arch/arm64/boot/dts/qcom/monaco-evk-camx.dtso @@ -0,0 +1,107 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +/dts-v1/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "monaco-camera.dtsi" +#include "monaco-evk-camera-sensor.dtsi" + +&camss { + status = "disabled"; +}; + +&tlmm { + cam_sensor_active_rst0: cam-sensor-active-rst0 { + /* RESET */ + mux { + pins = "gpio73"; + function = "gpio"; + }; + + config { + pins = "gpio73"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_active_rst1: cam-sensor-active-rst1 { + /* RESET */ + mux { + pins = "gpio74"; + function = "gpio"; + }; + + config { + pins = "gpio74"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_active_rst2: cam-sensor-active-rst2 { + /* RESET */ + mux { + pins = "gpio75"; + function = "gpio"; + }; + + config { + pins = "gpio75"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_suspend_rst0: cam-sensor-suspend-rst0 { + /* RESET */ + mux { + pins = "gpio73"; + function = "gpio"; + }; + + config { + pins = "gpio73"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; + }; + + cam_sensor_suspend_rst1: cam-sensor-suspend-rst1 { + /* RESET */ + mux { + pins = "gpio74"; + function = "gpio"; + }; + config { + pins = "gpio74"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; + }; + + cam_sensor_suspend_rst2: cam-sensor-suspend-rst2 { + /* RESET */ + mux { + pins = "gpio75"; + function = "gpio"; + }; + config { + pins = "gpio75"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/qcs8300-ride-camx.dtso b/arch/arm64/boot/dts/qcom/qcs8300-ride-camx.dtso new file mode 100644 index 0000000000000..8f26e6dc070b0 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcs8300-ride-camx.dtso @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +/dts-v1/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "monaco-camera.dtsi" +#include "monaco-camera-sensor.dtsi" From aef67efa5220448137126e06b4824d48a2943132 Mon Sep 17 00:00:00 2001 From: Krishna Chaitanya Chundru Date: Thu, 28 Aug 2025 17:38:58 +0530 Subject: [PATCH 0043/2333] FROMLIST: dt-bindings: PCI: Add binding for Toshiba TC9563 PCIe switch Add a device tree binding for the Toshiba TC9563 PCIe switch, which provides an Ethernet MAC integrated to the 3rd downstream port and two downstream PCIe ports. Reviewed-by: Rob Herring (Arm) Link: https://lore.kernel.org/r/20250828-qps615_v4_1-v6-1-985f90a7dd03@oss.qualcomm.com Signed-off-by: Krishna Chaitanya Chundru --- .../bindings/pci/toshiba,tc9563.yaml | 178 ++++++++++++++++++ 1 file changed, 178 insertions(+) create mode 100644 Documentation/devicetree/bindings/pci/toshiba,tc9563.yaml diff --git a/Documentation/devicetree/bindings/pci/toshiba,tc9563.yaml b/Documentation/devicetree/bindings/pci/toshiba,tc9563.yaml new file mode 100644 index 0000000000000..82c902b67852d --- /dev/null +++ b/Documentation/devicetree/bindings/pci/toshiba,tc9563.yaml @@ -0,0 +1,178 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/pci/toshiba,tc9563.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Toshiba TC9563 PCIe switch + +maintainers: + - Krishna chaitanya chundru + +description: | + Toshiba TC9563 PCIe switch has one upstream and three downstream ports. + The 3rd downstream port has integrated endpoint device of Ethernet MAC. + Other two downstream ports are supposed to connect to external device. + + The TC9563 PCIe switch can be configured through I2C interface before + PCIe link is established to change FTS, ASPM related entry delays, + tx amplitude etc for better power efficiency and functionality. + +properties: + compatible: + enum: + - pci1179,0623 + + reg: + maxItems: 1 + + reset-gpios: + maxItems: 1 + description: + GPIO controlling the RESX# pin. + + vdd18-supply: true + + vdd09-supply: true + + vddc-supply: true + + vddio1-supply: true + + vddio2-supply: true + + vddio18-supply: true + + i2c-parent: + $ref: /schemas/types.yaml#/definitions/phandle-array + description: + A phandle to the parent I2C node and the slave address of the device + used to do configure tc9563 to change FTS, tx amplitude etc. + items: + - description: Phandle to the I2C controller node + - description: I2C slave address + +patternProperties: + "^pcie@[1-3],0$": + description: + child nodes describing the internal downstream ports + the tc9563 switch. + type: object + allOf: + - $ref: "#/$defs/tc9563-node" + - $ref: /schemas/pci/pci-pci-bridge.yaml# + unevaluatedProperties: false + +$defs: + tc9563-node: + type: object + + properties: + toshiba,tx-amplitude-microvolt: + description: + Change Tx Margin setting for low power consumption. + + toshiba,no-dfe-support: + type: boolean + description: + Disable DFE (Decision Feedback Equalizer), which mitigates + intersymbol interference and some reflections caused by impedance mismatches. + +required: + - reset-gpios + - vdd18-supply + - vdd09-supply + - vddc-supply + - vddio1-supply + - vddio2-supply + - vddio18-supply + - i2c-parent + +allOf: + - $ref: "#/$defs/tc9563-node" + - $ref: /schemas/pci/pci-bus-common.yaml# + +unevaluatedProperties: false + +examples: + - | + #include + + pcie { + #address-cells = <3>; + #size-cells = <2>; + + pcie@0 { + device_type = "pci"; + reg = <0x0 0x0 0x0 0x0 0x0>; + + #address-cells = <3>; + #size-cells = <2>; + ranges; + bus-range = <0x01 0xff>; + + pcie@0,0 { + compatible = "pci1179,0623"; + + reg = <0x10000 0x0 0x0 0x0 0x0>; + device_type = "pci"; + #address-cells = <3>; + #size-cells = <2>; + ranges; + bus-range = <0x02 0xff>; + + i2c-parent = <&qup_i2c 0x77>; + + vdd18-supply = <&vdd>; + vdd09-supply = <&vdd>; + vddc-supply = <&vdd>; + vddio1-supply = <&vdd>; + vddio2-supply = <&vdd>; + vddio18-supply = <&vdd>; + + reset-gpios = <&gpio 1 GPIO_ACTIVE_LOW>; + + pcie@1,0 { + compatible = "pciclass,0604"; + reg = <0x20800 0x0 0x0 0x0 0x0>; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + ranges; + bus-range = <0x03 0xff>; + + toshiba,no-dfe-support; + }; + + pcie@2,0 { + compatible = "pciclass,0604"; + reg = <0x21000 0x0 0x0 0x0 0x0>; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + ranges; + bus-range = <0x04 0xff>; + }; + + pcie@3,0 { + compatible = "pciclass,0604"; + reg = <0x21800 0x0 0x0 0x0 0x0>; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + ranges; + bus-range = <0x05 0xff>; + + toshiba,tx-amplitude-microvolt = <10>; + + ethernet@0,0 { + reg = <0x50000 0x0 0x0 0x0 0x0>; + }; + + ethernet@0,1 { + reg = <0x50100 0x0 0x0 0x0 0x0>; + }; + }; + }; + }; + }; From fa9614f3861a8afa3fe8c7d81d009e8b55f628bb Mon Sep 17 00:00:00 2001 From: Krishna Chaitanya Chundru Date: Thu, 28 Aug 2025 17:39:00 +0530 Subject: [PATCH 0044/2333] FROMLIST: PCI: Add new start_link() & stop_link function ops First controller driver probes, enables link training and scans the bus. When the PCI bridge is found, its child DT nodes will be scanned and pwrctrl devices will be created if needed. By the time pwrctrl driver probe gets called link training is already enabled by controller driver. Certain devices like TC956x which uses PCI pwrctl framework needs to configure the device before PCI link is up. As the controller driver already enables link training as part of its probe, the moment device is powered on, controller and device participates in the link training and link can come up immediately and may not have time to configure the device. So we need to stop the link training by using stop_link() and enable them back after device is configured by using start_link(). Link: https://lore.kernel.org/r/20250828-qps615_v4_1-v6-3-985f90a7dd03@oss.qualcomm.com Signed-off-by: Krishna Chaitanya Chundru --- include/linux/pci.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/linux/pci.h b/include/linux/pci.h index d1fdf81fbe1e4..baff8a22c9535 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -829,6 +829,8 @@ struct pci_ops { void __iomem *(*map_bus)(struct pci_bus *bus, unsigned int devfn, int where); int (*read)(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *val); int (*write)(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 val); + int (*start_link)(struct pci_bus *bus); + void (*stop_link)(struct pci_bus *bus); }; /* From cbaab6d2a992776385dbbe2a55f5b4e6e70fa9df Mon Sep 17 00:00:00 2001 From: Krishna Chaitanya Chundru Date: Thu, 28 Aug 2025 17:39:01 +0530 Subject: [PATCH 0045/2333] FROMLIST: PCI: dwc: Add host_start_link() & host_start_link() hooks for dwc glue drivers Add host_start_link() and host_stop_link() functions to dwc glue drivers to register with start_link() and stop_link() of pci ops, allowing for better control over the link initialization and shutdown process. Link: https://lore.kernel.org/r/20250828-qps615_v4_1-v6-4-985f90a7dd03@oss.qualcomm.com Signed-off-by: Krishna Chaitanya Chundru --- drivers/pci/controller/dwc/pcie-designware.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index e995f692a1ecd..5e7bfff3e93e0 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -485,6 +485,8 @@ struct dw_pcie_ops { enum dw_pcie_ltssm (*get_ltssm)(struct dw_pcie *pcie); int (*start_link)(struct dw_pcie *pcie); void (*stop_link)(struct dw_pcie *pcie); + int (*host_start_link)(struct dw_pcie *pcie); + void (*host_stop_link)(struct dw_pcie *pcie); }; struct debugfs_info { @@ -787,6 +789,20 @@ static inline void dw_pcie_stop_link(struct dw_pcie *pci) pci->ops->stop_link(pci); } +static inline int dw_pcie_host_start_link(struct dw_pcie *pci) +{ + if (pci->ops && pci->ops->host_start_link) + return pci->ops->host_start_link(pci); + + return 0; +} + +static inline void dw_pcie_host_stop_link(struct dw_pcie *pci) +{ + if (pci->ops && pci->ops->host_stop_link) + pci->ops->host_stop_link(pci); +} + static inline enum dw_pcie_ltssm dw_pcie_get_ltssm(struct dw_pcie *pci) { u32 val; From eab34c8d7710f4e847e60cbba2da9ca383f55376 Mon Sep 17 00:00:00 2001 From: Krishna Chaitanya Chundru Date: Thu, 28 Aug 2025 17:39:02 +0530 Subject: [PATCH 0046/2333] FROMLIST: PCI: dwc: Implement .start_link(), .stop_link() hooks Implement stop_link() and start_link() function op for dwc drivers. Link: https://lore.kernel.org/r/20250828-qps615_v4_1-v6-5-985f90a7dd03@oss.qualcomm.com Signed-off-by: Krishna Chaitanya Chundru --- .../pci/controller/dwc/pcie-designware-host.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c index e92513c5bda51..4bca571309e3f 100644 --- a/drivers/pci/controller/dwc/pcie-designware-host.c +++ b/drivers/pci/controller/dwc/pcie-designware-host.c @@ -856,10 +856,28 @@ static void __iomem *dw_pcie_ecam_conf_map_bus(struct pci_bus *bus, unsigned int return pci->dbi_base + where; } +static int dw_pcie_op_start_link(struct pci_bus *bus) +{ + struct dw_pcie_rp *pp = bus->sysdata; + struct dw_pcie *pci = to_dw_pcie_from_pp(pp); + + return dw_pcie_host_start_link(pci); +} + +static void dw_pcie_op_stop_link(struct pci_bus *bus) +{ + struct dw_pcie_rp *pp = bus->sysdata; + struct dw_pcie *pci = to_dw_pcie_from_pp(pp); + + dw_pcie_host_stop_link(pci); +} + static struct pci_ops dw_pcie_ops = { .map_bus = dw_pcie_own_conf_map_bus, .read = pci_generic_config_read, .write = pci_generic_config_write, + .start_link = dw_pcie_op_start_link, + .stop_link = dw_pcie_op_stop_link, }; static struct pci_ops dw_pcie_ecam_ops = { From fddebfa200a0637c5f2115c59d4cfec927cc411a Mon Sep 17 00:00:00 2001 From: Krishna Chaitanya Chundru Date: Thu, 28 Aug 2025 17:39:03 +0530 Subject: [PATCH 0047/2333] FROMLIST: PCI: qcom: Add support for host_stop_link() & host_start_link() Add support for host_stop_link() and host_start_link() for switches like TC956x, which require configuration before the PCIe link is established. Assert PERST# and disable LTSSM bit to prevent the PCIe controller from participating in link training during host_stop_link(). De-assert PERST# and enable LTSSM bit during host_start_link(). Introduce ltssm_disable function op to stop link training. For the switches like TC956x, which needs to configure it before the PCIe link is established. Link: https://lore.kernel.org/r/20250828-qps615_v4_1-v6-6-985f90a7dd03@oss.qualcomm.com Signed-off-by: Krishna Chaitanya Chundru --- drivers/pci/controller/dwc/pcie-qcom.c | 35 ++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c index 6948824642dcd..1d4d8bcce14f4 100644 --- a/drivers/pci/controller/dwc/pcie-qcom.c +++ b/drivers/pci/controller/dwc/pcie-qcom.c @@ -249,6 +249,7 @@ struct qcom_pcie_ops { int (*post_init)(struct qcom_pcie *pcie); void (*deinit)(struct qcom_pcie *pcie); void (*ltssm_enable)(struct qcom_pcie *pcie); + void (*ltssm_disable)(struct qcom_pcie *pcie); int (*config_sid)(struct qcom_pcie *pcie); }; @@ -640,6 +641,37 @@ static int qcom_pcie_post_init_1_0_0(struct qcom_pcie *pcie) return 0; } +static int qcom_pcie_host_start_link(struct dw_pcie *pci) +{ + struct qcom_pcie *pcie = to_qcom_pcie(pci); + + qcom_ep_reset_deassert(pcie); + + if (pcie->cfg->ops->ltssm_enable) + pcie->cfg->ops->ltssm_enable(pcie); + + return 0; +} + +static void qcom_pcie_host_stop_link(struct dw_pcie *pci) +{ + struct qcom_pcie *pcie = to_qcom_pcie(pci); + + qcom_ep_reset_assert(pcie); + + if (pcie->cfg->ops->ltssm_disable) + pcie->cfg->ops->ltssm_disable(pcie); +} + +static void qcom_pcie_2_3_2_ltssm_disable(struct qcom_pcie *pcie) +{ + u32 val; + + val = readl(pcie->parf + PARF_LTSSM); + val &= ~LTSSM_EN; + writel(val, pcie->parf + PARF_LTSSM); +} + static void qcom_pcie_2_3_2_ltssm_enable(struct qcom_pcie *pcie) { u32 val; @@ -1378,6 +1410,7 @@ static const struct qcom_pcie_ops ops_1_9_0 = { .post_init = qcom_pcie_post_init_2_7_0, .deinit = qcom_pcie_deinit_2_7_0, .ltssm_enable = qcom_pcie_2_3_2_ltssm_enable, + .ltssm_disable = qcom_pcie_2_3_2_ltssm_disable, .config_sid = qcom_pcie_config_sid_1_9_0, }; @@ -1448,6 +1481,8 @@ static const struct qcom_pcie_cfg cfg_fw_managed = { static const struct dw_pcie_ops dw_pcie_ops = { .link_up = qcom_pcie_link_up, .start_link = qcom_pcie_start_link, + .host_start_link = qcom_pcie_host_start_link, + .host_stop_link = qcom_pcie_host_stop_link, }; static int qcom_pcie_icc_init(struct qcom_pcie *pcie) From 499dae1ccbb3ee9422363dfd183c20a83b201793 Mon Sep 17 00:00:00 2001 From: Krishna Chaitanya Chundru Date: Thu, 28 Aug 2025 17:39:04 +0530 Subject: [PATCH 0048/2333] FROMLIST: PCI: Add pcie_link_is_active() to determine if the link is active Add pcie_link_is_active() a common API to check if the PCIe link is active, replacing duplicate code in multiple locations. Signed-off-by: Shawn Anastasio Signed-off-by: Timothy Pearson Reviewed-by: Lukas Wunner Link: https://lore.kernel.org/r/20250828-qps615_v4_1-v6-7-985f90a7dd03@oss.qualcomm.com Signed-off-by: Krishna Chaitanya Chundru --- drivers/pci/hotplug/pciehp.h | 1 - drivers/pci/hotplug/pciehp_ctrl.c | 2 +- drivers/pci/hotplug/pciehp_hpc.c | 35 ++++--------------------------- drivers/pci/pci.c | 28 ++++++++++++++++++++++--- drivers/pci/pci.h | 1 + 5 files changed, 31 insertions(+), 36 deletions(-) diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h index debc79b0adfb2..79df49cc99463 100644 --- a/drivers/pci/hotplug/pciehp.h +++ b/drivers/pci/hotplug/pciehp.h @@ -186,7 +186,6 @@ int pciehp_query_power_fault(struct controller *ctrl); int pciehp_card_present(struct controller *ctrl); int pciehp_card_present_or_link_active(struct controller *ctrl); int pciehp_check_link_status(struct controller *ctrl); -int pciehp_check_link_active(struct controller *ctrl); bool pciehp_device_replaced(struct controller *ctrl); void pciehp_release_ctrl(struct controller *ctrl); diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c index bcc938d4420f3..6cc1b27b3b11a 100644 --- a/drivers/pci/hotplug/pciehp_ctrl.c +++ b/drivers/pci/hotplug/pciehp_ctrl.c @@ -260,7 +260,7 @@ void pciehp_handle_presence_or_link_change(struct controller *ctrl, u32 events) /* Turn the slot on if it's occupied or link is up */ mutex_lock(&ctrl->state_lock); present = pciehp_card_present(ctrl); - link_active = pciehp_check_link_active(ctrl); + link_active = pcie_link_is_active(ctrl->pcie->port); if (present <= 0 && link_active <= 0) { if (ctrl->state == BLINKINGON_STATE) { ctrl->state = OFF_STATE; diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index bcc51b26d03d5..2905ae7c9bbf7 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -221,33 +221,6 @@ static void pcie_write_cmd_nowait(struct controller *ctrl, u16 cmd, u16 mask) pcie_do_write_cmd(ctrl, cmd, mask, false); } -/** - * pciehp_check_link_active() - Is the link active - * @ctrl: PCIe hotplug controller - * - * Check whether the downstream link is currently active. Note it is - * possible that the card is removed immediately after this so the - * caller may need to take it into account. - * - * If the hotplug controller itself is not available anymore returns - * %-ENODEV. - */ -int pciehp_check_link_active(struct controller *ctrl) -{ - struct pci_dev *pdev = ctrl_dev(ctrl); - u16 lnk_status; - int ret; - - ret = pcie_capability_read_word(pdev, PCI_EXP_LNKSTA, &lnk_status); - if (ret == PCIBIOS_DEVICE_NOT_FOUND || PCI_POSSIBLE_ERROR(lnk_status)) - return -ENODEV; - - ret = !!(lnk_status & PCI_EXP_LNKSTA_DLLLA); - ctrl_dbg(ctrl, "%s: lnk_status = %x\n", __func__, lnk_status); - - return ret; -} - static bool pci_bus_check_dev(struct pci_bus *bus, int devfn) { u32 l; @@ -467,7 +440,7 @@ int pciehp_card_present_or_link_active(struct controller *ctrl) if (ret) return ret; - return pciehp_check_link_active(ctrl); + return pcie_link_is_active(ctrl_dev(ctrl)); } int pciehp_query_power_fault(struct controller *ctrl) @@ -614,8 +587,8 @@ static void pciehp_ignore_link_change(struct controller *ctrl, * Synthesize it to ensure that it is acted on. */ down_read_nested(&ctrl->reset_lock, ctrl->depth); - if (!pciehp_check_link_active(ctrl) || pciehp_device_replaced(ctrl)) - pciehp_request(ctrl, ignored_events); + if (!pcie_link_is_active(ctrl_dev(ctrl)) || pciehp_device_replaced(ctrl)) + pciehp_request(ctrl, PCI_EXP_SLTSTA_DLLSC); up_read(&ctrl->reset_lock); } @@ -921,7 +894,7 @@ int pciehp_slot_reset(struct pcie_device *dev) pcie_capability_write_word(dev->port, PCI_EXP_SLTSTA, PCI_EXP_SLTSTA_DLLSC); - if (!pciehp_check_link_active(ctrl)) + if (!pcie_link_is_active(ctrl_dev(ctrl))) pciehp_request(ctrl, PCI_EXP_SLTSTA_DLLSC); return 0; diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index b14dd064006cc..4cd2a214088e2 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -4868,7 +4868,6 @@ int pci_bridge_wait_for_secondary_bus(struct pci_dev *dev, char *reset_type) return 0; if (pcie_get_speed_cap(dev) <= PCIE_SPEED_5_0GT) { - u16 status; pci_dbg(dev, "waiting %d ms for downstream link\n", delay); msleep(delay); @@ -4884,8 +4883,7 @@ int pci_bridge_wait_for_secondary_bus(struct pci_dev *dev, char *reset_type) if (!dev->link_active_reporting) return -ENOTTY; - pcie_capability_read_word(dev, PCI_EXP_LNKSTA, &status); - if (!(status & PCI_EXP_LNKSTA_DLLLA)) + if (pcie_link_is_active(dev) <= 0) return -ENOTTY; return pci_dev_wait(child, reset_type, @@ -6194,6 +6192,30 @@ void pcie_print_link_status(struct pci_dev *dev) } EXPORT_SYMBOL(pcie_print_link_status); +/** + * pcie_link_is_active() - Checks if the link is active or not + * @pdev: PCI device to query + * + * Check whether the downstream link is currently active. Note it is + * possible that the card is removed immediately after this so the + * caller may need to take it into account. + * + * Return: true if link is active, or -ENODEV if the config read fails. + */ +int pcie_link_is_active(struct pci_dev *pdev) +{ + u16 lnk_status; + int ret; + + ret = pcie_capability_read_word(pdev, PCI_EXP_LNKSTA, &lnk_status); + if (ret == PCIBIOS_DEVICE_NOT_FOUND || PCI_POSSIBLE_ERROR(lnk_status)) + return -ENODEV; + + pci_dbg(pdev, "lnk_status = %#06x\n", lnk_status); + return !!(lnk_status & PCI_EXP_LNKSTA_DLLLA); +} +EXPORT_SYMBOL(pcie_link_is_active); + /** * pci_select_bars - Make BAR mask from the type of resource * @dev: the PCI device for which BAR mask is made diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 4492b809094b5..4a9457be867c3 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -320,6 +320,7 @@ static inline int pci_proc_detach_bus(struct pci_bus *bus) { return 0; } /* Functions for PCI Hotplug drivers to use */ int pci_hp_add_bridge(struct pci_dev *dev); bool pci_hp_spurious_link_change(struct pci_dev *pdev); +int pcie_link_is_active(struct pci_dev *dev); #if defined(CONFIG_SYSFS) && defined(HAVE_PCI_LEGACY) void pci_create_legacy_files(struct pci_bus *bus); From c36944ebc50ed5d40b3c550cbe5792b93c32dc27 Mon Sep 17 00:00:00 2001 From: Krishna Chaitanya Chundru Date: Thu, 28 Aug 2025 17:39:05 +0530 Subject: [PATCH 0049/2333] FROMLIST: PCI: pwrctrl: Add power control driver for tc9563 TC9563 is a PCIe switch which has one upstream and three downstream ports. To one of the downstream ports integrated ethernet MAC is connected as endpoint device. Other two downstream ports are supposed to connect to external device. One Host can connect to TC9563 by upstream port. TC9563 switch needs to be configured after powering on and before the PCIe link was up. The PCIe controller driver already enables link training at the host side even before this driver probe happens, due to this when driver enables power to the switch it participates in the link training and PCIe link may come up before configuring the switch through i2c. Once the link is up the configuration done through i2c will not have any affect.To prevent the host from participating in link training, disable link training on the host side to ensure the link does not come up before the switch is configured via I2C. Based up on dt property and type of the port, tc9563 is configured through i2c. Reviewed-by: Bjorn Andersson Reviewed-by: Bartosz Golaszewski Link: https://lore.kernel.org/r/20250828-qps615_v4_1-v6-8-985f90a7dd03@oss.qualcomm.com Signed-off-by: Krishna Chaitanya Chundru --- drivers/pci/pwrctrl/Kconfig | 13 + drivers/pci/pwrctrl/Makefile | 2 + drivers/pci/pwrctrl/pci-pwrctrl-tc9563.c | 637 +++++++++++++++++++++++ 3 files changed, 652 insertions(+) create mode 100644 drivers/pci/pwrctrl/pci-pwrctrl-tc9563.c diff --git a/drivers/pci/pwrctrl/Kconfig b/drivers/pci/pwrctrl/Kconfig index 6956c18548114..32e3c72755293 100644 --- a/drivers/pci/pwrctrl/Kconfig +++ b/drivers/pci/pwrctrl/Kconfig @@ -22,6 +22,19 @@ config PCI_PWRCTRL_SLOT PCI slots. The voltage regulators powering the rails of the PCI slots are expected to be defined in the devicetree node of the PCI bridge. +config PCI_PWRCTRL_TC9563 + tristate "PCI Power Control driver for TC9563 PCIe switch" + select PCI_PWRCTRL + help + Say Y here to enable the PCI Power Control driver of TC9563 PCIe + switch. + + This driver enables power and configures the TC9563 PCIe switch + through i2c.TC9563 is a PCIe switch which has one upstream and three + downstream ports. To one of the downstream ports integrated ethernet + MAC is connected as endpoint device. Other two downstream ports are + supposed to connect to external device. + # deprecated config HAVE_PWRCTL bool diff --git a/drivers/pci/pwrctrl/Makefile b/drivers/pci/pwrctrl/Makefile index a4e5808d7850c..13b02282106c2 100644 --- a/drivers/pci/pwrctrl/Makefile +++ b/drivers/pci/pwrctrl/Makefile @@ -7,3 +7,5 @@ obj-$(CONFIG_PCI_PWRCTRL_PWRSEQ) += pci-pwrctrl-pwrseq.o obj-$(CONFIG_PCI_PWRCTRL_SLOT) += pci-pwrctrl-slot.o pci-pwrctrl-slot-y := slot.o + +obj-$(CONFIG_PCI_PWRCTRL_TC9563) += pci-pwrctrl-tc9563.o diff --git a/drivers/pci/pwrctrl/pci-pwrctrl-tc9563.c b/drivers/pci/pwrctrl/pci-pwrctrl-tc9563.c new file mode 100644 index 0000000000000..63e719fa3589a --- /dev/null +++ b/drivers/pci/pwrctrl/pci-pwrctrl-tc9563.c @@ -0,0 +1,637 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../pci.h" + +#define TC9563_GPIO_CONFIG 0x801208 +#define TC9563_RESET_GPIO 0x801210 + +#define TC9563_PORT_L0S_DELAY 0x82496c +#define TC9563_PORT_L1_DELAY 0x824970 + +#define TC9563_EMBEDDED_ETH_DELAY 0x8200d8 +#define TC9563_ETH_L1_DELAY_MASK GENMASK(27, 18) +#define TC9563_ETH_L1_DELAY_VALUE(x) FIELD_PREP(TC9563_ETH_L1_DELAY_MASK, x) +#define TC9563_ETH_L0S_DELAY_MASK GENMASK(17, 13) +#define TC9563_ETH_L0S_DELAY_VALUE(x) FIELD_PREP(TC9563_ETH_L0S_DELAY_MASK, x) + +#define TC9563_NFTS_2_5_GT 0x824978 +#define TC9563_NFTS_5_GT 0x82497c + +#define TC9563_PORT_LANE_ACCESS_ENABLE 0x828000 + +#define TC9563_PHY_RATE_CHANGE_OVERRIDE 0x828040 +#define TC9563_PHY_RATE_CHANGE 0x828050 + +#define TC9563_TX_MARGIN 0x828234 + +#define TC9563_DFE_ENABLE 0x828a04 +#define TC9563_DFE_EQ0_MODE 0x828a08 +#define TC9563_DFE_EQ1_MODE 0x828a0c +#define TC9563_DFE_EQ2_MODE 0x828a14 +#define TC9563_DFE_PD_MASK 0x828254 + +#define TC9563_PORT_SELECT 0x82c02c +#define TC9563_PORT_ACCESS_ENABLE 0x82c030 + +#define TC9563_POWER_CONTROL 0x82b09c +#define TC9563_POWER_CONTROL_OVREN 0x82b2c8 + +#define TC9563_GPIO_MASK 0xfffffff3 + +#define TC9563_TX_MARGIN_MIN_VAL 400000 + +struct tc9563_pwrctrl_reg_setting { + unsigned int offset; + unsigned int val; +}; + +enum tc9563_pwrctrl_ports { + TC9563_USP, + TC9563_DSP1, + TC9563_DSP2, + TC9563_DSP3, + TC9563_ETHERNET, + TC9563_MAX +}; + +struct tc9563_pwrctrl_cfg { + u32 l0s_delay; + u32 l1_delay; + u32 tx_amp; + u8 nfts[2]; /* GEN1 & GEN2 */ + bool disable_dfe; + bool disable_port; +}; + +#define TC9563_PWRCTL_MAX_SUPPLY 6 + +static const char *const tc9563_supply_names[TC9563_PWRCTL_MAX_SUPPLY] = { + "vddc", + "vdd18", + "vdd09", + "vddio1", + "vddio2", + "vddio18", +}; + +struct tc9563_pwrctrl_ctx { + struct regulator_bulk_data supplies[TC9563_PWRCTL_MAX_SUPPLY]; + struct tc9563_pwrctrl_cfg cfg[TC9563_MAX]; + struct gpio_desc *reset_gpio; + struct i2c_adapter *adapter; + struct i2c_client *client; + struct pci_pwrctrl pwrctrl; +}; + +/* + * downstream port power off sequence, hardcoding the address + * as we don't know register names for these register offsets. + */ +static const struct tc9563_pwrctrl_reg_setting common_pwroff_seq[] = { + {0x82900c, 0x1}, + {0x829010, 0x1}, + {0x829018, 0x0}, + {0x829020, 0x1}, + {0x82902c, 0x1}, + {0x829030, 0x1}, + {0x82903c, 0x1}, + {0x829058, 0x0}, + {0x82905c, 0x1}, + {0x829060, 0x1}, + {0x8290cc, 0x1}, + {0x8290d0, 0x1}, + {0x8290d8, 0x1}, + {0x8290e0, 0x1}, + {0x8290e8, 0x1}, + {0x8290ec, 0x1}, + {0x8290f4, 0x1}, + {0x82910c, 0x1}, + {0x829110, 0x1}, + {0x829114, 0x1}, +}; + +static const struct tc9563_pwrctrl_reg_setting dsp1_pwroff_seq[] = { + {TC9563_PORT_ACCESS_ENABLE, 0x2}, + {TC9563_PORT_LANE_ACCESS_ENABLE, 0x3}, + {TC9563_POWER_CONTROL, 0x014f4804}, + {TC9563_POWER_CONTROL_OVREN, 0x1}, + {TC9563_PORT_ACCESS_ENABLE, 0x4}, +}; + +static const struct tc9563_pwrctrl_reg_setting dsp2_pwroff_seq[] = { + {TC9563_PORT_ACCESS_ENABLE, 0x8}, + {TC9563_PORT_LANE_ACCESS_ENABLE, 0x1}, + {TC9563_POWER_CONTROL, 0x014f4804}, + {TC9563_POWER_CONTROL_OVREN, 0x1}, + {TC9563_PORT_ACCESS_ENABLE, 0x8}, +}; + +/* + * Since all transfers are initiated by the probe, no locks are necessary, + * as there are no concurrent calls. + */ +static int tc9563_pwrctrl_i2c_write(struct i2c_client *client, + u32 reg_addr, u32 reg_val) +{ + struct i2c_msg msg; + u8 msg_buf[7]; + int ret; + + msg.addr = client->addr; + msg.len = 7; + msg.flags = 0; + + /* Big Endian for reg addr */ + put_unaligned_be24(reg_addr, &msg_buf[0]); + + /* Little Endian for reg val */ + put_unaligned_le32(reg_val, &msg_buf[3]); + + msg.buf = msg_buf; + ret = i2c_transfer(client->adapter, &msg, 1); + return ret == 1 ? 0 : ret; +} + +static int tc9563_pwrctrl_i2c_read(struct i2c_client *client, + u32 reg_addr, u32 *reg_val) +{ + struct i2c_msg msg[2]; + u8 wr_data[3]; + u32 rd_data; + int ret; + + msg[0].addr = client->addr; + msg[0].len = 3; + msg[0].flags = 0; + + /* Big Endian for reg addr */ + put_unaligned_be24(reg_addr, &wr_data[0]); + + msg[0].buf = wr_data; + + msg[1].addr = client->addr; + msg[1].len = 4; + msg[1].flags = I2C_M_RD; + + msg[1].buf = (u8 *)&rd_data; + + ret = i2c_transfer(client->adapter, &msg[0], 2); + if (ret == 2) { + *reg_val = get_unaligned_le32(&rd_data); + return 0; + } + + /* If only one message successfully completed, return -EIO */ + return ret == 1 ? -EIO : ret; +} + +static int tc9563_pwrctrl_i2c_bulk_write(struct i2c_client *client, + const struct tc9563_pwrctrl_reg_setting *seq, int len) +{ + int ret, i; + + for (i = 0; i < len; i++) { + ret = tc9563_pwrctrl_i2c_write(client, seq[i].offset, seq[i].val); + if (ret) + return ret; + } + + return 0; +} + +static int tc9563_pwrctrl_disable_port(struct tc9563_pwrctrl_ctx *ctx, + enum tc9563_pwrctrl_ports port) +{ + struct tc9563_pwrctrl_cfg *cfg = &ctx->cfg[port]; + const struct tc9563_pwrctrl_reg_setting *seq; + int ret, len; + + if (!cfg->disable_port) + return 0; + + if (port == TC9563_DSP1) { + seq = dsp1_pwroff_seq; + len = ARRAY_SIZE(dsp1_pwroff_seq); + } else { + seq = dsp2_pwroff_seq; + len = ARRAY_SIZE(dsp2_pwroff_seq); + } + + ret = tc9563_pwrctrl_i2c_bulk_write(ctx->client, seq, len); + if (ret) + return ret; + + return tc9563_pwrctrl_i2c_bulk_write(ctx->client, + common_pwroff_seq, ARRAY_SIZE(common_pwroff_seq)); +} + +static int tc9563_pwrctrl_set_l0s_l1_entry_delay(struct tc9563_pwrctrl_ctx *ctx, + enum tc9563_pwrctrl_ports port, bool is_l1, u32 ns) +{ + u32 rd_val, units; + int ret; + + if (ns < 256) + return 0; + + /* convert to units of 256ns */ + units = ns / 256; + + if (port == TC9563_ETHERNET) { + ret = tc9563_pwrctrl_i2c_read(ctx->client, TC9563_EMBEDDED_ETH_DELAY, &rd_val); + if (ret) + return ret; + + if (is_l1) + rd_val = u32_replace_bits(rd_val, units, TC9563_ETH_L1_DELAY_MASK); + else + rd_val = u32_replace_bits(rd_val, units, TC9563_ETH_L0S_DELAY_MASK); + + return tc9563_pwrctrl_i2c_write(ctx->client, TC9563_EMBEDDED_ETH_DELAY, rd_val); + } + + ret = tc9563_pwrctrl_i2c_write(ctx->client, TC9563_PORT_SELECT, BIT(port)); + if (ret) + return ret; + + return tc9563_pwrctrl_i2c_write(ctx->client, + is_l1 ? TC9563_PORT_L1_DELAY : TC9563_PORT_L0S_DELAY, units); +} + +static int tc9563_pwrctrl_set_tx_amplitude(struct tc9563_pwrctrl_ctx *ctx, + enum tc9563_pwrctrl_ports port, u32 amp) +{ + int port_access; + + if (amp < TC9563_TX_MARGIN_MIN_VAL) + return 0; + + /* txmargin = (Amp(uV) - 400000) / 3125 */ + amp = (amp - TC9563_TX_MARGIN_MIN_VAL) / 3125; + + switch (port) { + case TC9563_USP: + port_access = 0x1; + break; + case TC9563_DSP1: + port_access = 0x2; + break; + case TC9563_DSP2: + port_access = 0x8; + break; + default: + return -EINVAL; + }; + + struct tc9563_pwrctrl_reg_setting tx_amp_seq[] = { + {TC9563_PORT_ACCESS_ENABLE, port_access}, + {TC9563_PORT_LANE_ACCESS_ENABLE, 0x3}, + {TC9563_TX_MARGIN, amp}, + }; + + return tc9563_pwrctrl_i2c_bulk_write(ctx->client, tx_amp_seq, ARRAY_SIZE(tx_amp_seq)); +} + +static int tc9563_pwrctrl_disable_dfe(struct tc9563_pwrctrl_ctx *ctx, + enum tc9563_pwrctrl_ports port) +{ + struct tc9563_pwrctrl_cfg *cfg = &ctx->cfg[port]; + int port_access, lane_access = 0x3; + u32 phy_rate = 0x21; + + if (!cfg->disable_dfe) + return 0; + + switch (port) { + case TC9563_USP: + phy_rate = 0x1; + port_access = 0x1; + break; + case TC9563_DSP1: + port_access = 0x2; + break; + case TC9563_DSP2: + port_access = 0x8; + lane_access = 0x1; + break; + default: + return -EINVAL; + }; + + struct tc9563_pwrctrl_reg_setting disable_dfe_seq[] = { + {TC9563_PORT_ACCESS_ENABLE, port_access}, + {TC9563_PORT_LANE_ACCESS_ENABLE, lane_access}, + {TC9563_DFE_ENABLE, 0x0}, + {TC9563_DFE_EQ0_MODE, 0x411}, + {TC9563_DFE_EQ1_MODE, 0x11}, + {TC9563_DFE_EQ2_MODE, 0x11}, + {TC9563_DFE_PD_MASK, 0x7}, + {TC9563_PHY_RATE_CHANGE_OVERRIDE, 0x10}, + {TC9563_PHY_RATE_CHANGE, phy_rate}, + {TC9563_PHY_RATE_CHANGE, 0x0}, + {TC9563_PHY_RATE_CHANGE_OVERRIDE, 0x0}, + }; + + return tc9563_pwrctrl_i2c_bulk_write(ctx->client, + disable_dfe_seq, ARRAY_SIZE(disable_dfe_seq)); +} + +static int tc9563_pwrctrl_set_nfts(struct tc9563_pwrctrl_ctx *ctx, + enum tc9563_pwrctrl_ports port, u8 *nfts) +{ + struct tc9563_pwrctrl_reg_setting nfts_seq[] = { + {TC9563_NFTS_2_5_GT, nfts[0]}, + {TC9563_NFTS_5_GT, nfts[1]}, + }; + int ret; + + if (!nfts[0]) + return 0; + + ret = tc9563_pwrctrl_i2c_write(ctx->client, TC9563_PORT_SELECT, BIT(port)); + if (ret) + return ret; + + return tc9563_pwrctrl_i2c_bulk_write(ctx->client, nfts_seq, ARRAY_SIZE(nfts_seq)); +} + +static int tc9563_pwrctrl_assert_deassert_reset(struct tc9563_pwrctrl_ctx *ctx, bool deassert) +{ + int ret, val; + + ret = tc9563_pwrctrl_i2c_write(ctx->client, TC9563_GPIO_CONFIG, TC9563_GPIO_MASK); + if (ret) + return ret; + + val = deassert ? 0xc : 0; + + return tc9563_pwrctrl_i2c_write(ctx->client, TC9563_RESET_GPIO, val); +} + +static int tc9563_pwrctrl_parse_device_dt(struct tc9563_pwrctrl_ctx *ctx, struct device_node *node, + enum tc9563_pwrctrl_ports port) +{ + struct tc9563_pwrctrl_cfg *cfg; + int ret; + + cfg = &ctx->cfg[port]; + + /* Disable port if the status of the port is disabled. */ + if (!of_device_is_available(node)) { + cfg->disable_port = true; + return 0; + }; + + ret = of_property_read_u32(node, "aspm-l0s-entry-delay-ns", &cfg->l0s_delay); + if (ret && ret != -EINVAL) + return ret; + + ret = of_property_read_u32(node, "aspm-l1-entry-delay-ns", &cfg->l1_delay); + if (ret && ret != -EINVAL) + return ret; + + ret = of_property_read_u32(node, "qcom,tx-amplitude-microvolt", &cfg->tx_amp); + if (ret && ret != -EINVAL) + return ret; + + ret = of_property_read_u8_array(node, "n-fts", cfg->nfts, 2); + if (ret && ret != -EINVAL) + return ret; + + cfg->disable_dfe = of_property_read_bool(node, "qcom,no-dfe-support"); + + return 0; +} + +static void tc9563_pwrctrl_power_off(struct tc9563_pwrctrl_ctx *ctx) +{ + gpiod_set_value(ctx->reset_gpio, 1); + + regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies); +} + +static int tc9563_pwrctrl_bring_up(struct tc9563_pwrctrl_ctx *ctx) +{ + struct tc9563_pwrctrl_cfg *cfg; + int ret, i; + + ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies); + if (ret < 0) + return dev_err_probe(ctx->pwrctrl.dev, ret, "cannot enable regulators\n"); + + gpiod_set_value(ctx->reset_gpio, 0); + + /* + * From TC9563 PORSYS rev 0.2, figure 1.1 POR boot sequence + * wait for 10ms for the internal osc frequency to stabilize. + */ + usleep_range(10000, 10500); + + ret = tc9563_pwrctrl_assert_deassert_reset(ctx, false); + if (ret) + goto power_off; + + for (i = 0; i < TC9563_MAX; i++) { + cfg = &ctx->cfg[i]; + ret = tc9563_pwrctrl_disable_port(ctx, i); + if (ret) { + dev_err(ctx->pwrctrl.dev, "Disabling port failed\n"); + goto power_off; + } + + ret = tc9563_pwrctrl_set_l0s_l1_entry_delay(ctx, i, false, cfg->l0s_delay); + if (ret) { + dev_err(ctx->pwrctrl.dev, "Setting L0s entry delay failed\n"); + goto power_off; + } + + ret = tc9563_pwrctrl_set_l0s_l1_entry_delay(ctx, i, true, cfg->l1_delay); + if (ret) { + dev_err(ctx->pwrctrl.dev, "Setting L1 entry delay failed\n"); + goto power_off; + } + + ret = tc9563_pwrctrl_set_tx_amplitude(ctx, i, cfg->tx_amp); + if (ret) { + dev_err(ctx->pwrctrl.dev, "Setting Tx amplitude failed\n"); + goto power_off; + } + + ret = tc9563_pwrctrl_set_nfts(ctx, i, cfg->nfts); + if (ret) { + dev_err(ctx->pwrctrl.dev, "Setting N_FTS failed\n"); + goto power_off; + } + + ret = tc9563_pwrctrl_disable_dfe(ctx, i); + if (ret) { + dev_err(ctx->pwrctrl.dev, "Disabling DFE failed\n"); + goto power_off; + } + } + + ret = tc9563_pwrctrl_assert_deassert_reset(ctx, true); + if (!ret) + return 0; + +power_off: + tc9563_pwrctrl_power_off(ctx); + return ret; +} + +static int tc9563_pwrctrl_probe(struct platform_device *pdev) +{ + struct pci_host_bridge *bridge = to_pci_host_bridge(pdev->dev.parent); + struct pci_dev *pci_dev = to_pci_dev(pdev->dev.parent); + struct pci_bus *bus = bridge->bus; + struct device *dev = &pdev->dev; + enum tc9563_pwrctrl_ports port; + struct tc9563_pwrctrl_ctx *ctx; + struct device_node *i2c_node; + int ret, addr; + + ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + ret = of_property_read_u32_index(pdev->dev.of_node, "i2c-parent", 1, &addr); + if (ret) + return dev_err_probe(dev, ret, "Failed to read i2c-parent property\n"); + + i2c_node = of_parse_phandle(dev->of_node, "i2c-parent", 0); + ctx->adapter = of_find_i2c_adapter_by_node(i2c_node); + of_node_put(i2c_node); + if (!ctx->adapter) + return dev_err_probe(dev, -EPROBE_DEFER, "Failed to find I2C adapter\n"); + + ctx->client = i2c_new_dummy_device(ctx->adapter, addr); + if (IS_ERR(ctx->client)) { + dev_err(dev, "Failed to create I2C client\n"); + i2c_put_adapter(ctx->adapter); + return PTR_ERR(ctx->client); + } + + for (int i = 0; i < TC9563_PWRCTL_MAX_SUPPLY; i++) + ctx->supplies[i].supply = tc9563_supply_names[i]; + + ret = devm_regulator_bulk_get(dev, TC9563_PWRCTL_MAX_SUPPLY, ctx->supplies); + if (ret) { + dev_err_probe(dev, ret, + "failed to get supply regulator\n"); + goto remove_i2c; + } + + ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(ctx->reset_gpio)) { + ret = dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), "failed to get reset GPIO\n"); + goto remove_i2c; + } + + pci_pwrctrl_init(&ctx->pwrctrl, dev); + + port = TC9563_USP; + ret = tc9563_pwrctrl_parse_device_dt(ctx, pdev->dev.of_node, port); + if (ret) { + dev_err(dev, "failed to parse device tree properties: %d\n", ret); + goto remove_i2c; + } + + /* + * Downstream ports are always children of the upstream port. + * The first node represents DSP1, the second node represents DSP2, and so on. + */ + for_each_child_of_node_scoped(pdev->dev.of_node, child) { + ret = tc9563_pwrctrl_parse_device_dt(ctx, child, port++); + if (ret) + break; + /* Embedded ethernet device are under DSP3 */ + if (port == TC9563_DSP3) + for_each_child_of_node_scoped(child, child1) { + ret = tc9563_pwrctrl_parse_device_dt(ctx, child1, port++); + if (ret) + break; + } + } + if (ret) { + dev_err(dev, "failed to parse device tree properties: %d\n", ret); + goto remove_i2c; + } + + if (!pcie_link_is_active(pci_dev) && bridge->ops->stop_link) + bridge->ops->stop_link(bus); + + ret = tc9563_pwrctrl_bring_up(ctx); + if (ret) + goto remove_i2c; + + if (!pcie_link_is_active(pci_dev) && bridge->ops->start_link) { + ret = bridge->ops->start_link(bus); + if (ret) + goto power_off; + } + + ret = devm_pci_pwrctrl_device_set_ready(dev, &ctx->pwrctrl); + if (ret) + goto power_off; + + platform_set_drvdata(pdev, ctx); + + return 0; + +power_off: + tc9563_pwrctrl_power_off(ctx); +remove_i2c: + i2c_unregister_device(ctx->client); + i2c_put_adapter(ctx->adapter); + return ret; +} + +static void tc9563_pwrctrl_remove(struct platform_device *pdev) +{ + struct tc9563_pwrctrl_ctx *ctx = platform_get_drvdata(pdev); + + tc9563_pwrctrl_power_off(ctx); + i2c_unregister_device(ctx->client); + i2c_put_adapter(ctx->adapter); +} + +static const struct of_device_id tc9563_pwrctrl_of_match[] = { + { .compatible = "pci1179,0623"}, + { } +}; +MODULE_DEVICE_TABLE(of, tc9563_pwrctrl_of_match); + +static struct platform_driver tc9563_pwrctrl_driver = { + .driver = { + .name = "pwrctrl-tc9563", + .of_match_table = tc9563_pwrctrl_of_match, + .probe_type = PROBE_PREFER_ASYNCHRONOUS, + }, + .probe = tc9563_pwrctrl_probe, + .remove = tc9563_pwrctrl_remove, +}; +module_platform_driver(tc9563_pwrctrl_driver); + +MODULE_AUTHOR("Krishna chaitanya chundru "); +MODULE_DESCRIPTION("TC956x power control driver"); +MODULE_LICENSE("GPL"); From ca3c40b68a99e57446d11c6ec274f6082a2ef4f0 Mon Sep 17 00:00:00 2001 From: Debraj Mukhopadhyay Date: Fri, 18 Jul 2025 16:32:17 +0530 Subject: [PATCH 0050/2333] FROMLIST: mmc: Avoid reprogram all keys to Inline Crypto Engine for MMC runtime suspend resume Crypto reprogram all keys is called for each MMC runtime suspend/resume in current upstream design. If this is implemented as a non-interruptible call to TEE for security, the cpu core is blocked for execution while this call executes although the crypto engine already has the keys. For example, glitches in audio/video streaming applications have been observed due to this. Add the flag MMC_CAP2_CRYPTO_NO_REPROG as part of host->caps2 to control reprogramming keys to crypto engine for socs which dont require this feature. Link: https://lore.kernel.org/r/20250718110217.1929526-1-quic_dmukhopa@quicinc.com Signed-off-by: Seshu Madhavi Puppala Co-developed-by: Ram Prakash Gupta Signed-off-by: Ram Prakash Gupta Co-developed-by: Sarthak Garg Signed-off-by: Sarthak Garg Signed-off-by: Debraj Mukhopadhyay --- drivers/mmc/core/crypto.c | 2 +- drivers/mmc/host/sdhci-msm.c | 6 ++++++ include/linux/mmc/host.h | 5 +++++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/core/crypto.c b/drivers/mmc/core/crypto.c index fec4fbf16a5b6..a5a90bfc634ee 100644 --- a/drivers/mmc/core/crypto.c +++ b/drivers/mmc/core/crypto.c @@ -15,7 +15,7 @@ void mmc_crypto_set_initial_state(struct mmc_host *host) { /* Reset might clear all keys, so reprogram all the keys. */ - if (host->caps2 & MMC_CAP2_CRYPTO) + if ((host->caps2 & MMC_CAP2_CRYPTO) && !(host->caps2 & MMC_CAP2_CRYPTO_NO_REPROG)) blk_crypto_reprogram_all_keys(&host->crypto_profile); } diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index 4e5edbf2fc9b6..2ccb63dde9c19 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -1949,6 +1949,7 @@ static int sdhci_msm_ice_init(struct sdhci_msm_host *msm_host, } mmc->caps2 |= MMC_CAP2_CRYPTO; + mmc->caps2 |= MMC_CAP2_CRYPTO_NO_REPROG; return 0; } @@ -2526,6 +2527,11 @@ static int sdhci_msm_gcc_reset(struct device *dev, struct sdhci_host *host) usleep_range(200, 210); reset_control_put(reset); +#ifdef CONFIG_MMC_CRYPTO + if (host->mmc->caps2 & MMC_CAP2_CRYPTO) + blk_crypto_reprogram_all_keys(&host->mmc->crypto_profile); +#endif + return ret; } diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index e0e2c265e5d10..ff439d30704c4 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -463,6 +463,11 @@ struct mmc_host { #define MMC_CAP2_CRYPTO 0 #endif #define MMC_CAP2_ALT_GPT_TEGRA (1 << 28) /* Host with eMMC that has GPT entry at a non-standard location */ +#ifdef CONFIG_MMC_CRYPTO +#define MMC_CAP2_CRYPTO_NO_REPROG (1 << 29) /* Host handles inline crypto key reprogramming */ +#else +#define MMC_CAP2_CRYPTO_NO_REPROG 0 +#endif bool uhs2_sd_tran; /* UHS-II flag for SD_TRAN state */ bool uhs2_app_cmd; /* UHS-II flag for APP command */ From deba4cd6e590f8e026dff1b6ad90c746766aceef Mon Sep 17 00:00:00 2001 From: Wesley Cheng Date: Tue, 21 Oct 2025 13:30:01 +0530 Subject: [PATCH 0051/2333] FROMLIST: arm64: dts: qcom: sm8750: Add USB support to SM8750 SoCs SM8750 chipset contains a single DWC3 USB3 controller (rev. 200a), SS QMP PHY (rev. v8) and M31 eUSB2 PHY. The major difference for SM8750 is the transition to using the M31 eUSB2 PHY compared to previous SoCs. Enable USB support on SM8750 MTP and QRD variants. SM8750 has a QMP combo PHY for the SSUSB path, and a M31 eUSB2 PHY for the HSUSB path. Link: https://lore.kernel.org/all/20251024151521.2365845-2-krishna.kurapati@oss.qualcomm.com/ Signed-off-by: Wesley Cheng [Konrad: Provided diff to flattened USB node] Signed-off-by: Konrad Dybcio Signed-off-by: Krishna Kurapati --- arch/arm64/boot/dts/qcom/sm8750.dtsi | 158 +++++++++++++++++++++++++++ 1 file changed, 158 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm8750.dtsi b/arch/arm64/boot/dts/qcom/sm8750.dtsi index 4643705021c6c..ee39b8e2cdd67 100644 --- a/arch/arm64/boot/dts/qcom/sm8750.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8750.dtsi @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -2581,6 +2582,163 @@ }; }; + usb_1_hsphy: phy@88e3000 { + compatible = "qcom,sm8750-m31-eusb2-phy"; + reg = <0x0 0x88e3000 0x0 0x29c>; + + clocks = <&tcsrcc TCSR_USB2_CLKREF_EN>; + clock-names = "ref"; + + resets = <&gcc GCC_QUSB2PHY_PRIM_BCR>; + + #phy-cells = <0>; + + status = "disabled"; + }; + + usb_dp_qmpphy: phy@88e8000 { + compatible = "qcom,sm8750-qmp-usb3-dp-phy"; + reg = <0x0 0x088e8000 0x0 0x4000>; + + clocks = <&gcc GCC_USB3_PRIM_PHY_AUX_CLK>, + <&tcsrcc TCSR_USB3_CLKREF_EN>, + <&gcc GCC_USB3_PRIM_PHY_COM_AUX_CLK>, + <&gcc GCC_USB3_PRIM_PHY_PIPE_CLK>; + clock-names = "aux", + "ref", + "com_aux", + "usb3_pipe"; + + resets = <&gcc GCC_USB3_PHY_PRIM_BCR>, + <&gcc GCC_USB3_DP_PHY_PRIM_BCR>; + reset-names = "phy", + "common"; + + power-domains = <&gcc GCC_USB3_PHY_GDSC>; + + #clock-cells = <1>; + #phy-cells = <1>; + + orientation-switch; + + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + usb_dp_qmpphy_out: endpoint { + }; + }; + + port@1 { + reg = <1>; + + usb_dp_qmpphy_usb_ss_in: endpoint { + remote-endpoint = <&usb_1_dwc3_ss>; + }; + }; + + port@2 { + reg = <2>; + + usb_dp_qmpphy_dp_in: endpoint { + }; + }; + }; + }; + + usb_1: usb@a600000 { + compatible = "qcom,sm8750-dwc3", "qcom,snps-dwc3"; + reg = <0x0 0x0a600000 0x0 0xfc100>; + + clocks = <&gcc GCC_CFG_NOC_USB3_PRIM_AXI_CLK>, + <&gcc GCC_USB30_PRIM_MASTER_CLK>, + <&gcc GCC_AGGRE_USB3_PRIM_AXI_CLK>, + <&gcc GCC_USB30_PRIM_SLEEP_CLK>, + <&gcc GCC_USB30_PRIM_MOCK_UTMI_CLK>; + clock-names = "cfg_noc", + "core", + "iface", + "sleep", + "mock_utmi"; + + assigned-clocks = <&gcc GCC_USB30_PRIM_MOCK_UTMI_CLK>, + <&gcc GCC_USB30_PRIM_MASTER_CLK>; + assigned-clock-rates = <19200000>, + <200000000>; + + interrupts-extended = <&intc GIC_SPI 133 IRQ_TYPE_LEVEL_HIGH>, + <&intc GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>, + <&intc GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 14 IRQ_TYPE_EDGE_BOTH>, + <&pdc 15 IRQ_TYPE_EDGE_BOTH>, + <&pdc 17 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "dwc_usb3", + "pwr_event", + "hs_phy_irq", + "dp_hs_phy_irq", + "dm_hs_phy_irq", + "ss_phy_irq"; + + power-domains = <&gcc GCC_USB30_PRIM_GDSC>; + required-opps = <&rpmhpd_opp_nom>; + + resets = <&gcc GCC_USB30_PRIM_BCR>; + + interconnects = <&aggre1_noc MASTER_USB3_0 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ACTIVE_ONLY + &config_noc SLAVE_USB3_0 QCOM_ICC_TAG_ACTIVE_ONLY>; + interconnect-names = "usb-ddr", "apps-usb"; + + iommus = <&apps_smmu 0x40 0x0>; + + phys = <&usb_1_hsphy>, + <&usb_dp_qmpphy QMP_USB43DP_USB3_PHY>; + phy-names = "usb2-phy", + "usb3-phy"; + + snps,hird-threshold = /bits/ 8 <0x0>; + snps,usb2-gadget-lpm-disable; + snps,dis_u2_susphy_quirk; + snps,dis_enblslpm_quirk; + snps,dis-u1-entry-quirk; + snps,dis-u2-entry-quirk; + snps,is-utmi-l1-suspend; + snps,usb3_lpm_capable; + snps,usb2-lpm-disable; + snps,has-lpm-erratum; + tx-fifo-resize; + + dma-coherent; + + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + usb_1_dwc3_hs: endpoint { + }; + }; + + port@1 { + reg = <1>; + + usb_1_dwc3_ss: endpoint { + remote-endpoint = <&usb_dp_qmpphy_usb_ss_in>; + }; + }; + }; + }; + pdc: interrupt-controller@b220000 { compatible = "qcom,sm8750-pdc", "qcom,pdc"; reg = <0x0 0x0b220000 0x0 0x10000>, <0x0 0x164400f0 0x0 0x64>; From e6e1fdb5da85c4389e4a3e0f40dd8a54e1ea73a7 Mon Sep 17 00:00:00 2001 From: Wesley Cheng Date: Tue, 21 Oct 2025 13:33:08 +0530 Subject: [PATCH 0052/2333] FROMLIST: arm64: dts: qcom: sm8750: Add USB support for SM8750 MTP platform Enable USB support on SM8750 MTP variants. The current definition will start the USB controller in peripheral mode by default until dependencies are added, such as USB role detection. Link: https://lore.kernel.org/all/20251024151521.2365845-3-krishna.kurapati@oss.qualcomm.com/ Signed-off-by: Wesley Cheng [Konrad: Provided diff to flatten USB node on MTP] Signed-off-by: Konrad Dybcio Signed-off-by: Krishna Kurapati --- arch/arm64/boot/dts/qcom/sm8750-mtp.dts | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm8750-mtp.dts b/arch/arm64/boot/dts/qcom/sm8750-mtp.dts index 75cfbb510be57..96cb12c4d372c 100644 --- a/arch/arm64/boot/dts/qcom/sm8750-mtp.dts +++ b/arch/arm64/boot/dts/qcom/sm8750-mtp.dts @@ -1047,3 +1047,25 @@ status = "okay"; }; + +&usb_1 { + dr_mode = "peripheral"; + + status = "okay"; +}; + +&usb_1_hsphy { + vdd-supply = <&vreg_l2d_0p88>; + vdda12-supply = <&vreg_l3g_1p2>; + + phys = <&pmih0108_eusb2_repeater>; + + status = "okay"; +}; + +&usb_dp_qmpphy { + vdda-phy-supply = <&vreg_l3g_1p2>; + vdda-pll-supply = <&vreg_l2d_0p88>; + + status = "okay"; +}; From cecb64e5acfb2f16df5cb4b9beab8621c2207cba Mon Sep 17 00:00:00 2001 From: Wesley Cheng Date: Tue, 21 Oct 2025 13:35:23 +0530 Subject: [PATCH 0053/2333] FROMLIST: arm64: dts: qcom: sm8750: Add USB support for SM8750 QRD platform Enable USB support on SM8750 QRD variant. The current definition will start the USB controller in peripheral mode by default until dependencies are added, such as USB role detection. Link: https://lore.kernel.org/all/20251024151521.2365845-4-krishna.kurapati@oss.qualcomm.com/ Signed-off-by: Wesley Cheng [Krishna: Flattened usb node QRD DTS] Signed-off-by: Krishna Kurapati --- arch/arm64/boot/dts/qcom/sm8750-qrd.dts | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm8750-qrd.dts b/arch/arm64/boot/dts/qcom/sm8750-qrd.dts index 13c7b9664c89c..fc5d12bb41a53 100644 --- a/arch/arm64/boot/dts/qcom/sm8750-qrd.dts +++ b/arch/arm64/boot/dts/qcom/sm8750-qrd.dts @@ -1054,3 +1054,25 @@ status = "okay"; }; + +&usb_1 { + dr_mode = "peripheral"; + + status = "okay"; +}; + +&usb_1_hsphy { + vdd-supply = <&vreg_l2d_0p88>; + vdda12-supply = <&vreg_l3g_1p2>; + + phys = <&pmih0108_eusb2_repeater>; + + status = "okay"; +}; + +&usb_dp_qmpphy { + vdda-phy-supply = <&vreg_l3g_1p2>; + vdda-pll-supply = <&vreg_l2d_0p88>; + + status = "okay"; +}; From 03e0b7b70b8df2b6b498a1f7ed565c2bc4a0833b Mon Sep 17 00:00:00 2001 From: Umang Chheda Date: Thu, 30 Oct 2025 00:58:58 +0530 Subject: [PATCH 0054/2333] PENDING: arm64: dts: qcom: qcs8300: Update camera PIL region to 7MB The camera firmware size for IoT variant qcs8300 SoC is more than 5MB. Update the PIL memory region size of camera to 7MB to accomodate the same. Signed-off-by: Umang Chheda --- arch/arm64/boot/dts/qcom/qcs8300.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/qcs8300.dtsi b/arch/arm64/boot/dts/qcom/qcs8300.dtsi index 8d78ccac411e4..e0816bb6ebc06 100644 --- a/arch/arm64/boot/dts/qcom/qcs8300.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs8300.dtsi @@ -767,7 +767,7 @@ }; camera_mem: camera-region@95200000 { - reg = <0x0 0x95200000 0x0 0x500000>; + reg = <0x0 0x95200000 0x0 0x700000>; no-map; }; From c29f570c16249b9ae1472b08a3570f2985fa5532 Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Tue, 21 Oct 2025 10:39:54 +0530 Subject: [PATCH 0055/2333] UPSTREAM: dt-bindings: usb: qcom,snps-dwc3: Add the SM8750 compatible Add qcom,sm8750-dwc3 compatible to flattened implementation binding. Link: https://lore.kernel.org/all/20251021050954.3462613-1-krishna.kurapati@oss.qualcomm.com/ Signed-off-by: Konrad Dybcio Signed-off-by: Krishna Kurapati Reviewed-by: Krzysztof Kozlowski --- Documentation/devicetree/bindings/usb/qcom,snps-dwc3.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/usb/qcom,snps-dwc3.yaml b/Documentation/devicetree/bindings/usb/qcom,snps-dwc3.yaml index d49a58d5478ff..301e873684ae9 100644 --- a/Documentation/devicetree/bindings/usb/qcom,snps-dwc3.yaml +++ b/Documentation/devicetree/bindings/usb/qcom,snps-dwc3.yaml @@ -67,6 +67,7 @@ properties: - qcom,sm8450-dwc3 - qcom,sm8550-dwc3 - qcom,sm8650-dwc3 + - qcom,sm8750-dwc3 - qcom,x1e80100-dwc3 - qcom,x1e80100-dwc3-mp - const: qcom,snps-dwc3 @@ -213,6 +214,7 @@ allOf: - qcom,sdx65-dwc3 - qcom,sdx75-dwc3 - qcom,sm6350-dwc3 + - qcom,sm8750-dwc3 then: properties: clocks: @@ -501,6 +503,7 @@ allOf: - qcom,sm8450-dwc3 - qcom,sm8550-dwc3 - qcom,sm8650-dwc3 + - qcom,sm8750-dwc3 then: properties: interrupts: From e3244f2b752b6c9e73dac1af4bbf5601d55c75d2 Mon Sep 17 00:00:00 2001 From: Gaurav Kohli Date: Fri, 17 Oct 2025 10:32:56 +0530 Subject: [PATCH 0056/2333] FROMGIT: arm64: dts: qcom: lemans-evk: Enable AMC6821 fan controller Enable AMC6821 fan controller for lemans-evk platform and configure pwm polarity as inverted. Link: https://lore.kernel.org/r/20251017050256.987660-1-gaurav.kohli@oss.qualcomm.com Signed-off-by: Gaurav Kohli --- arch/arm64/boot/dts/qcom/lemans-evk.dts | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/lemans-evk.dts b/arch/arm64/boot/dts/qcom/lemans-evk.dts index fd72920121734..f5ad7ff5e5381 100644 --- a/arch/arm64/boot/dts/qcom/lemans-evk.dts +++ b/arch/arm64/boot/dts/qcom/lemans-evk.dts @@ -6,6 +6,7 @@ /dts-v1/; #include +#include #include #include @@ -509,6 +510,20 @@ }; }; +&i2c19 { + status = "okay"; + + fan_controller: fan@18 { + compatible = "ti,amc6821"; + reg = <0x18>; + #pwm-cells = <2>; + + fan { + pwms = <&fan_controller 40000 PWM_POLARITY_INVERTED>; + }; + }; +}; + &iris { firmware-name = "qcom/vpu/vpu30_p4_s6_16mb.mbn"; @@ -602,6 +617,11 @@ }; }; +&qup_i2c19_default { + drive-strength = <2>; + bias-pull-up; +}; + &qupv3_id_0 { firmware-name = "qcom/sa8775p/qupv3fw.elf"; status = "okay"; From eb2915193759f4e6898b17ea064858a931b93750 Mon Sep 17 00:00:00 2001 From: Taniya Das Date: Thu, 30 Oct 2025 16:39:04 +0530 Subject: [PATCH 0057/2333] FROMLIST: dt-bindings: clock: qcom-rpmhcc: Add RPMHCC for Kaanapali Update the documentation for RPMH clock controller for Kaanapali SoC. Signed-off-by: Jingyi Wang Reviewed-by: Krzysztof Kozlowski Signed-off-by: Taniya Das --- Documentation/devicetree/bindings/clock/qcom,rpmhcc.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/clock/qcom,rpmhcc.yaml b/Documentation/devicetree/bindings/clock/qcom,rpmhcc.yaml index 78fa057266857..3f5f1336262ee 100644 --- a/Documentation/devicetree/bindings/clock/qcom,rpmhcc.yaml +++ b/Documentation/devicetree/bindings/clock/qcom,rpmhcc.yaml @@ -18,6 +18,7 @@ properties: compatible: enum: - qcom,glymur-rpmh-clk + - qcom,kaanapali-rpmh-clk - qcom,milos-rpmh-clk - qcom,qcs615-rpmh-clk - qcom,qdu1000-rpmh-clk From 47438f6959afda8401f9b48ff1ed2c91f8111552 Mon Sep 17 00:00:00 2001 From: Taniya Das Date: Thu, 30 Oct 2025 16:39:05 +0530 Subject: [PATCH 0058/2333] FROMLIST: dt-bindings: clock: qcom: Document the Kaanapali TCSR Clock Controller Add bindings documentation for TCSR Clock Controller for Kaanapali SoC. Signed-off-by: Jingyi Wang Reviewed-by: Krzysztof Kozlowski Signed-off-by: Taniya Das --- Documentation/devicetree/bindings/clock/qcom,sm8550-tcsr.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/clock/qcom,sm8550-tcsr.yaml b/Documentation/devicetree/bindings/clock/qcom,sm8550-tcsr.yaml index 2c992b3437f29..784fef8306812 100644 --- a/Documentation/devicetree/bindings/clock/qcom,sm8550-tcsr.yaml +++ b/Documentation/devicetree/bindings/clock/qcom,sm8550-tcsr.yaml @@ -25,6 +25,7 @@ properties: items: - enum: - qcom,glymur-tcsr + - qcom,kaanapali-tcsr - qcom,milos-tcsr - qcom,sar2130p-tcsr - qcom,sm8550-tcsr From f0e3226c91e1929f00c70999fc1ccb35a3bfbddd Mon Sep 17 00:00:00 2001 From: Taniya Das Date: Thu, 30 Oct 2025 16:39:06 +0530 Subject: [PATCH 0059/2333] FROMLIST: dt-bindings: clock: qcom: Add Kaanapali Global clock controller Add device tree bindings for the global clock controller on Qualcomm Kaanapali platform. Signed-off-by: Jingyi Wang Reviewed-by: Krzysztof Kozlowski Signed-off-by: Taniya Das --- .../bindings/clock/qcom,sm8750-gcc.yaml | 8 +- .../dt-bindings/clock/qcom,kaanapali-gcc.h | 241 ++++++++++++++++++ 2 files changed, 247 insertions(+), 2 deletions(-) create mode 100644 include/dt-bindings/clock/qcom,kaanapali-gcc.h diff --git a/Documentation/devicetree/bindings/clock/qcom,sm8750-gcc.yaml b/Documentation/devicetree/bindings/clock/qcom,sm8750-gcc.yaml index aab7039fd28db..0114d347b26ff 100644 --- a/Documentation/devicetree/bindings/clock/qcom,sm8750-gcc.yaml +++ b/Documentation/devicetree/bindings/clock/qcom,sm8750-gcc.yaml @@ -13,11 +13,15 @@ description: | Qualcomm global clock control module provides the clocks, resets and power domains on SM8750 - See also: include/dt-bindings/clock/qcom,sm8750-gcc.h + See also: + include/dt-bindings/clock/qcom,kaanapali-gcc.h + include/dt-bindings/clock/qcom,sm8750-gcc.h properties: compatible: - const: qcom,sm8750-gcc + enum: + - qcom,kaanapali-gcc + - qcom,sm8750-gcc clocks: items: diff --git a/include/dt-bindings/clock/qcom,kaanapali-gcc.h b/include/dt-bindings/clock/qcom,kaanapali-gcc.h new file mode 100644 index 0000000000000..890e48709f09f --- /dev/null +++ b/include/dt-bindings/clock/qcom,kaanapali-gcc.h @@ -0,0 +1,241 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#ifndef _DT_BINDINGS_CLK_QCOM_GCC_KAANAPALI_H +#define _DT_BINDINGS_CLK_QCOM_GCC_KAANAPALI_H + +/* GCC clocks */ +#define GCC_AGGRE_NOC_PCIE_AXI_CLK 0 +#define GCC_AGGRE_UFS_PHY_AXI_CLK 1 +#define GCC_AGGRE_USB3_PRIM_AXI_CLK 2 +#define GCC_BOOT_ROM_AHB_CLK 3 +#define GCC_CAM_BIST_MCLK_AHB_CLK 4 +#define GCC_CAMERA_AHB_CLK 5 +#define GCC_CAMERA_HF_AXI_CLK 6 +#define GCC_CAMERA_SF_AXI_CLK 7 +#define GCC_CAMERA_XO_CLK 8 +#define GCC_CFG_NOC_PCIE_ANOC_AHB_CLK 9 +#define GCC_CFG_NOC_USB3_PRIM_AXI_CLK 10 +#define GCC_CNOC_PCIE_SF_AXI_CLK 11 +#define GCC_DDRSS_PCIE_SF_QTB_CLK 12 +#define GCC_QMIP_CAMERA_CMD_AHB_CLK 13 +#define GCC_DISP_HF_AXI_CLK 14 +#define GCC_DISP_SF_AXI_CLK 15 +#define GCC_EVA_AHB_CLK 16 +#define GCC_EVA_AXI0_CLK 17 +#define GCC_EVA_AXI0C_CLK 18 +#define GCC_EVA_XO_CLK 19 +#define GCC_GP1_CLK 20 +#define GCC_GP1_CLK_SRC 21 +#define GCC_GP2_CLK 22 +#define GCC_GP2_CLK_SRC 23 +#define GCC_GP3_CLK 24 +#define GCC_GP3_CLK_SRC 25 +#define GCC_GPLL0 26 +#define GCC_GPLL0_OUT_EVEN 27 +#define GCC_GPLL1 28 +#define GCC_GPLL4 29 +#define GCC_GPLL7 30 +#define GCC_GPLL9 31 +#define GCC_GPU_CFG_AHB_CLK 32 +#define GCC_GPU_GEMNOC_GFX_CLK 33 +#define GCC_GPU_GPLL0_CLK_SRC 34 +#define GCC_GPU_GPLL0_DIV_CLK_SRC 35 +#define GCC_QMIP_VIDEO_VCODEC_AHB_CLK 36 +#define GCC_QMIP_GPU_AHB_CLK 37 +#define GCC_PCIE_0_AUX_CLK 38 +#define GCC_PCIE_0_AUX_CLK_SRC 39 +#define GCC_PCIE_0_CFG_AHB_CLK 40 +#define GCC_PCIE_0_MSTR_AXI_CLK 41 +#define GCC_PCIE_0_PHY_AUX_CLK 42 +#define GCC_PCIE_0_PHY_AUX_CLK_SRC 43 +#define GCC_PCIE_0_PHY_RCHNG_CLK 44 +#define GCC_PCIE_0_PHY_RCHNG_CLK_SRC 45 +#define GCC_PCIE_0_PIPE_CLK 46 +#define GCC_PCIE_0_PIPE_CLK_SRC 47 +#define GCC_PCIE_0_SLV_AXI_CLK 48 +#define GCC_PCIE_0_SLV_Q2A_AXI_CLK 49 +#define GCC_PCIE_RSCC_CFG_AHB_CLK 50 +#define GCC_PCIE_RSCC_XO_CLK 51 +#define GCC_PDM2_CLK 52 +#define GCC_PDM2_CLK_SRC 53 +#define GCC_PDM_AHB_CLK 54 +#define GCC_PDM_XO4_CLK 55 +#define GCC_QUPV3_I2C_CORE_CLK 56 +#define GCC_QUPV3_I2C_S0_CLK 57 +#define GCC_QUPV3_I2C_S0_CLK_SRC 58 +#define GCC_QUPV3_I2C_S1_CLK 59 +#define GCC_QUPV3_I2C_S1_CLK_SRC 60 +#define GCC_QUPV3_I2C_S2_CLK 61 +#define GCC_QUPV3_I2C_S2_CLK_SRC 62 +#define GCC_QUPV3_I2C_S3_CLK 63 +#define GCC_QUPV3_I2C_S3_CLK_SRC 64 +#define GCC_QUPV3_I2C_S4_CLK 65 +#define GCC_QUPV3_I2C_S4_CLK_SRC 66 +#define GCC_QUPV3_I2C_S_AHB_CLK 67 +#define GCC_QUPV3_WRAP1_CORE_2X_CLK 68 +#define GCC_QUPV3_WRAP1_CORE_CLK 69 +#define GCC_QUPV3_WRAP1_QSPI_REF_CLK 70 +#define GCC_QUPV3_WRAP1_QSPI_REF_CLK_SRC 71 +#define GCC_QUPV3_WRAP1_S0_CLK 72 +#define GCC_QUPV3_WRAP1_S0_CLK_SRC 73 +#define GCC_QUPV3_WRAP1_S1_CLK 74 +#define GCC_QUPV3_WRAP1_S1_CLK_SRC 75 +#define GCC_QUPV3_WRAP1_S2_CLK 76 +#define GCC_QUPV3_WRAP1_S2_CLK_SRC 77 +#define GCC_QUPV3_WRAP1_S3_CLK 78 +#define GCC_QUPV3_WRAP1_S3_CLK_SRC 79 +#define GCC_QUPV3_WRAP1_S4_CLK 80 +#define GCC_QUPV3_WRAP1_S4_CLK_SRC 81 +#define GCC_QUPV3_WRAP1_S5_CLK 82 +#define GCC_QUPV3_WRAP1_S5_CLK_SRC 83 +#define GCC_QUPV3_WRAP1_S6_CLK 84 +#define GCC_QUPV3_WRAP1_S6_CLK_SRC 85 +#define GCC_QUPV3_WRAP1_S7_CLK 86 +#define GCC_QUPV3_WRAP1_S7_CLK_SRC 87 +#define GCC_QUPV3_WRAP2_CORE_2X_CLK 88 +#define GCC_QUPV3_WRAP2_CORE_CLK 89 +#define GCC_QUPV3_WRAP2_S0_CLK 90 +#define GCC_QUPV3_WRAP2_S0_CLK_SRC 91 +#define GCC_QUPV3_WRAP2_S1_CLK 92 +#define GCC_QUPV3_WRAP2_S1_CLK_SRC 93 +#define GCC_QUPV3_WRAP2_S2_CLK 94 +#define GCC_QUPV3_WRAP2_S2_CLK_SRC 95 +#define GCC_QUPV3_WRAP2_S3_CLK 96 +#define GCC_QUPV3_WRAP2_S3_CLK_SRC 97 +#define GCC_QUPV3_WRAP2_S4_CLK 98 +#define GCC_QUPV3_WRAP2_S4_CLK_SRC 99 +#define GCC_QUPV3_WRAP3_CORE_2X_CLK 100 +#define GCC_QUPV3_WRAP3_CORE_CLK 101 +#define GCC_QUPV3_WRAP3_IBI_CTRL_0_CLK_SRC 102 +#define GCC_QUPV3_WRAP3_IBI_CTRL_1_CLK 103 +#define GCC_QUPV3_WRAP3_IBI_CTRL_2_CLK 104 +#define GCC_QUPV3_WRAP3_S0_CLK 105 +#define GCC_QUPV3_WRAP3_S0_CLK_SRC 106 +#define GCC_QUPV3_WRAP3_S1_CLK 107 +#define GCC_QUPV3_WRAP3_S1_CLK_SRC 108 +#define GCC_QUPV3_WRAP3_S2_CLK 109 +#define GCC_QUPV3_WRAP3_S2_CLK_SRC 110 +#define GCC_QUPV3_WRAP3_S3_CLK 111 +#define GCC_QUPV3_WRAP3_S3_CLK_SRC 112 +#define GCC_QUPV3_WRAP3_S4_CLK 113 +#define GCC_QUPV3_WRAP3_S4_CLK_SRC 114 +#define GCC_QUPV3_WRAP3_S5_CLK 115 +#define GCC_QUPV3_WRAP3_S5_CLK_SRC 116 +#define GCC_QUPV3_WRAP4_CORE_2X_CLK 117 +#define GCC_QUPV3_WRAP4_CORE_CLK 118 +#define GCC_QUPV3_WRAP4_S0_CLK 119 +#define GCC_QUPV3_WRAP4_S0_CLK_SRC 120 +#define GCC_QUPV3_WRAP4_S1_CLK 121 +#define GCC_QUPV3_WRAP4_S1_CLK_SRC 122 +#define GCC_QUPV3_WRAP4_S2_CLK 123 +#define GCC_QUPV3_WRAP4_S2_CLK_SRC 124 +#define GCC_QUPV3_WRAP4_S3_CLK 125 +#define GCC_QUPV3_WRAP4_S3_CLK_SRC 126 +#define GCC_QUPV3_WRAP4_S4_CLK 127 +#define GCC_QUPV3_WRAP4_S4_CLK_SRC 128 +#define GCC_QUPV3_WRAP_1_M_AXI_CLK 129 +#define GCC_QUPV3_WRAP_1_S_AHB_CLK 130 +#define GCC_QUPV3_WRAP_2_M_AHB_CLK 131 +#define GCC_QUPV3_WRAP_2_S_AHB_CLK 132 +#define GCC_QUPV3_WRAP_3_IBI_1_AHB_CLK 133 +#define GCC_QUPV3_WRAP_3_IBI_2_AHB_CLK 134 +#define GCC_QUPV3_WRAP_3_M_AHB_CLK 135 +#define GCC_QUPV3_WRAP_3_S_AHB_CLK 136 +#define GCC_QUPV3_WRAP_4_M_AHB_CLK 137 +#define GCC_QUPV3_WRAP_4_S_AHB_CLK 138 +#define GCC_SDCC2_AHB_CLK 139 +#define GCC_SDCC2_APPS_CLK 140 +#define GCC_SDCC2_APPS_CLK_SRC 141 +#define GCC_SDCC4_AHB_CLK 142 +#define GCC_SDCC4_APPS_CLK 143 +#define GCC_SDCC4_APPS_CLK_SRC 144 +#define GCC_UFS_PHY_AHB_CLK 145 +#define GCC_UFS_PHY_AXI_CLK 146 +#define GCC_UFS_PHY_AXI_CLK_SRC 147 +#define GCC_UFS_PHY_ICE_CORE_CLK 148 +#define GCC_UFS_PHY_ICE_CORE_CLK_SRC 149 +#define GCC_UFS_PHY_PHY_AUX_CLK 150 +#define GCC_UFS_PHY_PHY_AUX_CLK_SRC 151 +#define GCC_UFS_PHY_RX_SYMBOL_0_CLK 152 +#define GCC_UFS_PHY_RX_SYMBOL_0_CLK_SRC 153 +#define GCC_UFS_PHY_RX_SYMBOL_1_CLK 154 +#define GCC_UFS_PHY_RX_SYMBOL_1_CLK_SRC 155 +#define GCC_UFS_PHY_TX_SYMBOL_0_CLK 156 +#define GCC_UFS_PHY_TX_SYMBOL_0_CLK_SRC 157 +#define GCC_UFS_PHY_UNIPRO_CORE_CLK 158 +#define GCC_UFS_PHY_UNIPRO_CORE_CLK_SRC 159 +#define GCC_USB30_PRIM_MASTER_CLK 160 +#define GCC_USB30_PRIM_MASTER_CLK_SRC 161 +#define GCC_USB30_PRIM_MOCK_UTMI_CLK 162 +#define GCC_USB30_PRIM_MOCK_UTMI_CLK_SRC 163 +#define GCC_USB30_PRIM_MOCK_UTMI_POSTDIV_CLK_SRC 164 +#define GCC_USB30_PRIM_SLEEP_CLK 165 +#define GCC_USB3_PRIM_PHY_AUX_CLK 166 +#define GCC_USB3_PRIM_PHY_AUX_CLK_SRC 167 +#define GCC_USB3_PRIM_PHY_COM_AUX_CLK 168 +#define GCC_USB3_PRIM_PHY_PIPE_CLK 169 +#define GCC_USB3_PRIM_PHY_PIPE_CLK_SRC 170 +#define GCC_VIDEO_AHB_CLK 171 +#define GCC_VIDEO_AXI0_CLK 172 +#define GCC_VIDEO_AXI1_CLK 173 +#define GCC_VIDEO_XO_CLK 174 +#define GCC_QMIP_CAMERA_NRT_AHB_CLK 175 +#define GCC_QMIP_CAMERA_RT_AHB_CLK 176 +#define GCC_QMIP_DISP_DCP_SF_AHB_CLK 177 +#define GCC_QMIP_PCIE_AHB_CLK 178 +#define GCC_QMIP_VIDEO_CV_CPU_AHB_CLK 179 +#define GCC_QMIP_VIDEO_CVP_AHB_CLK 180 +#define GCC_QMIP_VIDEO_V_CPU_AHB_CLK 181 +#define GCC_DISP_AHB_CLK 182 + +/* GCC power domains */ +#define GCC_PCIE_0_GDSC 0 +#define GCC_PCIE_0_PHY_GDSC 1 +#define GCC_UFS_MEM_PHY_GDSC 2 +#define GCC_UFS_PHY_GDSC 3 +#define GCC_USB30_PRIM_GDSC 4 +#define GCC_USB3_PHY_GDSC 5 + +/* GCC resets */ +#define GCC_CAMERA_BCR 0 +#define GCC_DISPLAY_BCR 1 +#define GCC_EVA_AXI0_CLK_ARES 2 +#define GCC_EVA_AXI0C_CLK_ARES 3 +#define GCC_EVA_BCR 4 +#define GCC_GPU_BCR 5 +#define GCC_PCIE_0_BCR 6 +#define GCC_PCIE_0_LINK_DOWN_BCR 7 +#define GCC_PCIE_0_NOCSR_COM_PHY_BCR 8 +#define GCC_PCIE_0_PHY_BCR 9 +#define GCC_PCIE_0_PHY_NOCSR_COM_PHY_BCR 10 +#define GCC_PCIE_PHY_BCR 11 +#define GCC_PCIE_PHY_CFG_AHB_BCR 12 +#define GCC_PCIE_PHY_COM_BCR 13 +#define GCC_PCIE_RSCC_BCR 14 +#define GCC_PDM_BCR 15 +#define GCC_QUPV3_WRAPPER_1_BCR 16 +#define GCC_QUPV3_WRAPPER_2_BCR 17 +#define GCC_QUPV3_WRAPPER_3_BCR 18 +#define GCC_QUPV3_WRAPPER_4_BCR 19 +#define GCC_QUPV3_WRAPPER_I2C_BCR 20 +#define GCC_QUSB2PHY_PRIM_BCR 21 +#define GCC_QUSB2PHY_SEC_BCR 22 +#define GCC_SDCC2_BCR 23 +#define GCC_SDCC4_BCR 24 +#define GCC_UFS_PHY_BCR 25 +#define GCC_USB30_PRIM_BCR 26 +#define GCC_USB3_DP_PHY_PRIM_BCR 27 +#define GCC_USB3_DP_PHY_SEC_BCR 28 +#define GCC_USB3_PHY_PRIM_BCR 29 +#define GCC_USB3_PHY_SEC_BCR 30 +#define GCC_USB3PHY_PHY_PRIM_BCR 31 +#define GCC_USB3PHY_PHY_SEC_BCR 32 +#define GCC_VIDEO_AXI0_CLK_ARES 33 +#define GCC_VIDEO_AXI1_CLK_ARES 34 +#define GCC_VIDEO_BCR 35 +#define GCC_VIDEO_XO_CLK_ARES 36 + +#endif From 2e0cb9bfea95c9c4396902018453406170215df9 Mon Sep 17 00:00:00 2001 From: Taniya Das Date: Thu, 30 Oct 2025 16:39:07 +0530 Subject: [PATCH 0060/2333] FROMLIST: clk: qcom: rpmh: Add support for Kaanapali rpmh clocks Add the RPMH clocks present in Kaanapali SoC. Signed-off-by: Jingyi Wang Signed-off-by: Taniya Das --- drivers/clk/qcom/clk-rpmh.c | 42 +++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/drivers/clk/qcom/clk-rpmh.c b/drivers/clk/qcom/clk-rpmh.c index 63c38cb47bc45..d8cf716a1dec7 100644 --- a/drivers/clk/qcom/clk-rpmh.c +++ b/drivers/clk/qcom/clk-rpmh.c @@ -395,6 +395,19 @@ DEFINE_CLK_RPMH_VRM(clk4, _a, "C4A_E0", 1); DEFINE_CLK_RPMH_VRM(clk5, _a, "C5A_E0", 1); DEFINE_CLK_RPMH_VRM(clk8, _a, "C8A_E0", 1); +DEFINE_CLK_RPMH_VRM(ln_bb_clk1, _a2_e0, "C6A_E0", 2); +DEFINE_CLK_RPMH_VRM(ln_bb_clk2, _a2_e0, "C7A_E0", 2); +DEFINE_CLK_RPMH_VRM(ln_bb_clk3, _a2_e0, "C8A_E0", 2); + +DEFINE_CLK_RPMH_VRM(rf_clk1, _a_e0, "C1A_E0", 1); +DEFINE_CLK_RPMH_VRM(rf_clk2, _a_e0, "C2A_E0", 1); + +DEFINE_CLK_RPMH_VRM(rf_clk3, _a2_e0, "C3A_E0", 2); +DEFINE_CLK_RPMH_VRM(rf_clk4, _a2_e0, "C4A_E0", 2); +DEFINE_CLK_RPMH_VRM(rf_clk5, _a2_e0, "C5A_E0", 2); + +DEFINE_CLK_RPMH_VRM(div_clk1, _a4_e0, "C11A_E0", 4); + DEFINE_CLK_RPMH_BCM(ce, "CE0"); DEFINE_CLK_RPMH_BCM(hwkm, "HK0"); DEFINE_CLK_RPMH_BCM(ipa, "IP0"); @@ -900,6 +913,34 @@ static const struct clk_rpmh_desc clk_rpmh_glymur = { .num_clks = ARRAY_SIZE(glymur_rpmh_clocks), }; +static struct clk_hw *kaanapali_rpmh_clocks[] = { + [RPMH_CXO_CLK] = &clk_rpmh_bi_tcxo_div2.hw, + [RPMH_CXO_CLK_A] = &clk_rpmh_bi_tcxo_div2_ao.hw, + [RPMH_DIV_CLK1] = &clk_rpmh_div_clk1_a4_e0.hw, + [RPMH_LN_BB_CLK1] = &clk_rpmh_ln_bb_clk1_a2_e0.hw, + [RPMH_LN_BB_CLK1_A] = &clk_rpmh_ln_bb_clk1_a2_e0_ao.hw, + [RPMH_LN_BB_CLK2] = &clk_rpmh_ln_bb_clk2_a2_e0.hw, + [RPMH_LN_BB_CLK2_A] = &clk_rpmh_ln_bb_clk2_a2_e0_ao.hw, + [RPMH_LN_BB_CLK3] = &clk_rpmh_ln_bb_clk3_a2_e0.hw, + [RPMH_LN_BB_CLK3_A] = &clk_rpmh_ln_bb_clk3_a2_e0_ao.hw, + [RPMH_RF_CLK1] = &clk_rpmh_rf_clk1_a_e0.hw, + [RPMH_RF_CLK1_A] = &clk_rpmh_rf_clk1_a_e0_ao.hw, + [RPMH_RF_CLK2] = &clk_rpmh_rf_clk2_a_e0.hw, + [RPMH_RF_CLK2_A] = &clk_rpmh_rf_clk2_a_e0_ao.hw, + [RPMH_RF_CLK3] = &clk_rpmh_rf_clk3_a2_e0.hw, + [RPMH_RF_CLK3_A] = &clk_rpmh_rf_clk3_a2_e0_ao.hw, + [RPMH_RF_CLK4] = &clk_rpmh_rf_clk4_a2_e0.hw, + [RPMH_RF_CLK4] = &clk_rpmh_rf_clk4_a2_e0_ao.hw, + [RPMH_RF_CLK5_A] = &clk_rpmh_rf_clk5_a2_e0.hw, + [RPMH_RF_CLK5_A] = &clk_rpmh_rf_clk5_a2_e0_ao.hw, + [RPMH_IPA_CLK] = &clk_rpmh_ipa.hw, +}; + +static const struct clk_rpmh_desc clk_rpmh_kaanapali = { + .clks = kaanapali_rpmh_clocks, + .num_clks = ARRAY_SIZE(kaanapali_rpmh_clocks), +}; + static struct clk_hw *of_clk_rpmh_hw_get(struct of_phandle_args *clkspec, void *data) { @@ -990,6 +1031,7 @@ static int clk_rpmh_probe(struct platform_device *pdev) static const struct of_device_id clk_rpmh_match_table[] = { { .compatible = "qcom,glymur-rpmh-clk", .data = &clk_rpmh_glymur}, + { .compatible = "qcom,kaanapali-rpmh-clk", .data = &clk_rpmh_kaanapali}, { .compatible = "qcom,milos-rpmh-clk", .data = &clk_rpmh_milos}, { .compatible = "qcom,qcs615-rpmh-clk", .data = &clk_rpmh_qcs615}, { .compatible = "qcom,qdu1000-rpmh-clk", .data = &clk_rpmh_qdu1000}, From 74292d56d5792e628aee0c327725792daff9b447 Mon Sep 17 00:00:00 2001 From: Taniya Das Date: Thu, 30 Oct 2025 16:39:08 +0530 Subject: [PATCH 0061/2333] FROMLIST: clk: qcom: Add TCSR clock driver for Kaanapali Add the TCSR clock controller that provides the refclks on Kaanapali platform for PCIe, USB and UFS subsystems. Signed-off-by: Jingyi Wang Signed-off-by: Taniya Das --- drivers/clk/qcom/Kconfig | 8 ++ drivers/clk/qcom/Makefile | 1 + drivers/clk/qcom/tcsrcc-kaanapali.c | 141 ++++++++++++++++++++++++++++ 3 files changed, 150 insertions(+) create mode 100644 drivers/clk/qcom/tcsrcc-kaanapali.c diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index 78a3038426136..14d57bd5fac7d 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -46,6 +46,14 @@ config CLK_GLYMUR_TCSRCC Support for the TCSR clock controller on GLYMUR devices. Say Y if you want to use peripheral devices such as USB/PCIe/EDP. +config CLK_KAANAPALI_TCSRCC + tristate "KAANAPALI TCSR Clock Controller" + depends on ARM64 || COMPILE_TEST + select QCOM_GDSC + help + Support for the TCSR clock controller on Kaanapali devices. + Say Y if you want to use peripheral devices such as PCIe, USB, UFS. + config CLK_X1E80100_CAMCC tristate "X1E80100 Camera Clock Controller" depends on ARM64 || COMPILE_TEST diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index 8051d481c439b..527312def7da7 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -24,6 +24,7 @@ obj-$(CONFIG_CLK_GFM_LPASS_SM8250) += lpass-gfm-sm8250.o obj-$(CONFIG_CLK_GLYMUR_DISPCC) += dispcc-glymur.o obj-$(CONFIG_CLK_GLYMUR_GCC) += gcc-glymur.o obj-$(CONFIG_CLK_GLYMUR_TCSRCC) += tcsrcc-glymur.o +obj-$(CONFIG_CLK_KAANAPALI_TCSRCC) += tcsrcc-kaanapali.o obj-$(CONFIG_CLK_X1E80100_CAMCC) += camcc-x1e80100.o obj-$(CONFIG_CLK_X1E80100_DISPCC) += dispcc-x1e80100.o obj-$(CONFIG_CLK_X1E80100_GCC) += gcc-x1e80100.o diff --git a/drivers/clk/qcom/tcsrcc-kaanapali.c b/drivers/clk/qcom/tcsrcc-kaanapali.c new file mode 100644 index 0000000000000..14cfa75e892cc --- /dev/null +++ b/drivers/clk/qcom/tcsrcc-kaanapali.c @@ -0,0 +1,141 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#include +#include +#include +#include +#include + +#include + +#include "clk-branch.h" +#include "clk-regmap.h" +#include "clk-regmap-divider.h" +#include "clk-regmap-mux.h" +#include "common.h" + +enum { + DT_BI_TCXO_PAD, +}; + +static struct clk_branch tcsr_pcie_0_clkref_en = { + .halt_reg = 0x0, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x0, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "tcsr_pcie_0_clkref_en", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch tcsr_ufs_clkref_en = { + .halt_reg = 0x10, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x10, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "tcsr_ufs_clkref_en", + .parent_data = &(const struct clk_parent_data){ + .index = DT_BI_TCXO_PAD, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch tcsr_usb2_clkref_en = { + .halt_reg = 0x18, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x18, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "tcsr_usb2_clkref_en", + .parent_data = &(const struct clk_parent_data){ + .index = DT_BI_TCXO_PAD, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch tcsr_usb3_clkref_en = { + .halt_reg = 0x8, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x8, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "tcsr_usb3_clkref_en", + .parent_data = &(const struct clk_parent_data){ + .index = DT_BI_TCXO_PAD, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_regmap *tcsr_cc_kaanapali_clocks[] = { + [TCSR_PCIE_0_CLKREF_EN] = &tcsr_pcie_0_clkref_en.clkr, + [TCSR_UFS_CLKREF_EN] = &tcsr_ufs_clkref_en.clkr, + [TCSR_USB2_CLKREF_EN] = &tcsr_usb2_clkref_en.clkr, + [TCSR_USB3_CLKREF_EN] = &tcsr_usb3_clkref_en.clkr, +}; + +static const struct regmap_config tcsr_cc_kaanapali_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x18, + .fast_io = true, +}; + +static const struct qcom_cc_desc tcsr_cc_kaanapali_desc = { + .config = &tcsr_cc_kaanapali_regmap_config, + .clks = tcsr_cc_kaanapali_clocks, + .num_clks = ARRAY_SIZE(tcsr_cc_kaanapali_clocks), +}; + +static const struct of_device_id tcsr_cc_kaanapali_match_table[] = { + { .compatible = "qcom,kaanapali-tcsr" }, + { } +}; +MODULE_DEVICE_TABLE(of, tcsr_cc_kaanapali_match_table); + +static int tcsr_cc_kaanapali_probe(struct platform_device *pdev) +{ + return qcom_cc_probe(pdev, &tcsr_cc_kaanapali_desc); +} + +static struct platform_driver tcsr_cc_kaanapali_driver = { + .probe = tcsr_cc_kaanapali_probe, + .driver = { + .name = "tcsr_cc-kaanapali", + .of_match_table = tcsr_cc_kaanapali_match_table, + }, +}; + +static int __init tcsr_cc_kaanapali_init(void) +{ + return platform_driver_register(&tcsr_cc_kaanapali_driver); +} +subsys_initcall(tcsr_cc_kaanapali_init); + +static void __exit tcsr_cc_kaanapali_exit(void) +{ + platform_driver_unregister(&tcsr_cc_kaanapali_driver); +} +module_exit(tcsr_cc_kaanapali_exit); + +MODULE_DESCRIPTION("QTI TCSR_CC KAANAPALI Driver"); +MODULE_LICENSE("GPL"); From 069f197a43fdbcab323389612336899f7ec73006 Mon Sep 17 00:00:00 2001 From: Taniya Das Date: Thu, 30 Oct 2025 16:39:09 +0530 Subject: [PATCH 0062/2333] FROMLIST: clk: qcom: Add support for Global clock controller on Kaanapali Add support for Global clock controller for Kaanapali Qualcomm SoC. Signed-off-by: Jingyi Wang Reviewed-by: Dmitry Baryshkov Signed-off-by: Taniya Das --- drivers/clk/qcom/Kconfig | 9 + drivers/clk/qcom/Makefile | 1 + drivers/clk/qcom/gcc-kaanapali.c | 3541 ++++++++++++++++++++++++++++++ 3 files changed, 3551 insertions(+) create mode 100644 drivers/clk/qcom/gcc-kaanapali.c diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index 14d57bd5fac7d..54dceec8021cc 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -46,6 +46,15 @@ config CLK_GLYMUR_TCSRCC Support for the TCSR clock controller on GLYMUR devices. Say Y if you want to use peripheral devices such as USB/PCIe/EDP. +config CLK_KAANAPALI_GCC + tristate "KAANAPALI Global Clock Controller" + depends on ARM64 || COMPILE_TEST + select QCOM_GDSC + help + Support for the global clock controller on Kaanapali devices. + Say Y if you want to use peripheral devices such as UART, + SPI, I2C, USB, SD/UFS, PCIe etc. + config CLK_KAANAPALI_TCSRCC tristate "KAANAPALI TCSR Clock Controller" depends on ARM64 || COMPILE_TEST diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index 527312def7da7..55f3141431314 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -24,6 +24,7 @@ obj-$(CONFIG_CLK_GFM_LPASS_SM8250) += lpass-gfm-sm8250.o obj-$(CONFIG_CLK_GLYMUR_DISPCC) += dispcc-glymur.o obj-$(CONFIG_CLK_GLYMUR_GCC) += gcc-glymur.o obj-$(CONFIG_CLK_GLYMUR_TCSRCC) += tcsrcc-glymur.o +obj-$(CONFIG_CLK_KAANAPALI_GCC) += gcc-kaanapali.o obj-$(CONFIG_CLK_KAANAPALI_TCSRCC) += tcsrcc-kaanapali.o obj-$(CONFIG_CLK_X1E80100_CAMCC) += camcc-x1e80100.o obj-$(CONFIG_CLK_X1E80100_DISPCC) += dispcc-x1e80100.o diff --git a/drivers/clk/qcom/gcc-kaanapali.c b/drivers/clk/qcom/gcc-kaanapali.c new file mode 100644 index 0000000000000..1790e54df7b3a --- /dev/null +++ b/drivers/clk/qcom/gcc-kaanapali.c @@ -0,0 +1,3541 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include "clk-alpha-pll.h" +#include "clk-branch.h" +#include "clk-pll.h" +#include "clk-rcg.h" +#include "clk-regmap.h" +#include "clk-regmap-divider.h" +#include "clk-regmap-mux.h" +#include "clk-regmap-phy-mux.h" +#include "common.h" +#include "gdsc.h" +#include "reset.h" + +enum { + DT_BI_TCXO, + DT_BI_TCXO_AO, + DT_SLEEP_CLK, + DT_PCIE_0_PIPE_CLK, + DT_UFS_PHY_RX_SYMBOL_0_CLK, + DT_UFS_PHY_RX_SYMBOL_1_CLK, + DT_UFS_PHY_TX_SYMBOL_0_CLK, + DT_USB3_PHY_WRAPPER_GCC_USB30_PIPE_CLK, +}; + +enum { + P_BI_TCXO, + P_GCC_GPLL0_OUT_EVEN, + P_GCC_GPLL0_OUT_MAIN, + P_GCC_GPLL1_OUT_MAIN, + P_GCC_GPLL4_OUT_MAIN, + P_GCC_GPLL7_OUT_MAIN, + P_GCC_GPLL9_OUT_MAIN, + P_PCIE_0_PIPE_CLK, + P_SLEEP_CLK, + P_UFS_PHY_RX_SYMBOL_0_CLK, + P_UFS_PHY_RX_SYMBOL_1_CLK, + P_UFS_PHY_TX_SYMBOL_0_CLK, + P_USB3_PHY_WRAPPER_GCC_USB30_PIPE_CLK, +}; + +static struct clk_alpha_pll gcc_gpll0 = { + .offset = 0x0, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_TAYCAN_EKO_T], + .clkr = { + .enable_reg = 0x52020, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpll0", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_taycan_eko_t_ops, + }, + }, +}; + +static const struct clk_div_table post_div_table_gcc_gpll0_out_even[] = { + { 0x1, 2 }, + { } +}; + +static struct clk_alpha_pll_postdiv gcc_gpll0_out_even = { + .offset = 0x0, + .post_div_shift = 10, + .post_div_table = post_div_table_gcc_gpll0_out_even, + .num_post_div = ARRAY_SIZE(post_div_table_gcc_gpll0_out_even), + .width = 4, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_TAYCAN_EKO_T], + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_gpll0_out_even", + .parent_hws = (const struct clk_hw*[]) { + &gcc_gpll0.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_postdiv_taycan_eko_t_ops, + }, +}; + +static struct clk_alpha_pll gcc_gpll1 = { + .offset = 0x1000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_TAYCAN_EKO_T], + .clkr = { + .enable_reg = 0x52020, + .enable_mask = BIT(1), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpll1", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_taycan_eko_t_ops, + }, + }, +}; + +static struct clk_alpha_pll gcc_gpll4 = { + .offset = 0x4000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_TAYCAN_EKO_T], + .clkr = { + .enable_reg = 0x52020, + .enable_mask = BIT(4), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpll4", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_taycan_eko_t_ops, + }, + }, +}; + +static struct clk_alpha_pll gcc_gpll7 = { + .offset = 0x7000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_TAYCAN_EKO_T], + .clkr = { + .enable_reg = 0x52020, + .enable_mask = BIT(7), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpll7", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_taycan_eko_t_ops, + }, + }, +}; + +static struct clk_alpha_pll gcc_gpll9 = { + .offset = 0x9000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_TAYCAN_EKO_T], + .clkr = { + .enable_reg = 0x52020, + .enable_mask = BIT(9), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpll9", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_taycan_eko_t_ops, + }, + }, +}; + +static const struct parent_map gcc_parent_map_0[] = { + { P_BI_TCXO, 0 }, + { P_GCC_GPLL0_OUT_MAIN, 1 }, + { P_GCC_GPLL0_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data gcc_parent_data_0[] = { + { .index = DT_BI_TCXO }, + { .hw = &gcc_gpll0.clkr.hw }, + { .hw = &gcc_gpll0_out_even.clkr.hw }, +}; + +static const struct parent_map gcc_parent_map_1[] = { + { P_BI_TCXO, 0 }, + { P_GCC_GPLL0_OUT_MAIN, 1 }, + { P_GCC_GPLL1_OUT_MAIN, 4 }, + { P_GCC_GPLL4_OUT_MAIN, 5 }, + { P_GCC_GPLL0_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data gcc_parent_data_1[] = { + { .index = DT_BI_TCXO }, + { .hw = &gcc_gpll0.clkr.hw }, + { .hw = &gcc_gpll1.clkr.hw }, + { .hw = &gcc_gpll4.clkr.hw }, + { .hw = &gcc_gpll0_out_even.clkr.hw }, +}; + +static const struct parent_map gcc_parent_map_2[] = { + { P_BI_TCXO, 0 }, + { P_GCC_GPLL0_OUT_MAIN, 1 }, + { P_SLEEP_CLK, 5 }, + { P_GCC_GPLL0_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data gcc_parent_data_2[] = { + { .index = DT_BI_TCXO }, + { .hw = &gcc_gpll0.clkr.hw }, + { .index = DT_SLEEP_CLK }, + { .hw = &gcc_gpll0_out_even.clkr.hw }, +}; + +static const struct parent_map gcc_parent_map_3[] = { + { P_BI_TCXO, 0 }, + { P_GCC_GPLL0_OUT_MAIN, 1 }, + { P_GCC_GPLL4_OUT_MAIN, 5 }, + { P_GCC_GPLL0_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data gcc_parent_data_3[] = { + { .index = DT_BI_TCXO }, + { .hw = &gcc_gpll0.clkr.hw }, + { .hw = &gcc_gpll4.clkr.hw }, + { .hw = &gcc_gpll0_out_even.clkr.hw }, +}; + +static const struct parent_map gcc_parent_map_4[] = { + { P_BI_TCXO, 0 }, +}; + +static const struct clk_parent_data gcc_parent_data_4[] = { + { .index = DT_BI_TCXO }, +}; + +static const struct parent_map gcc_parent_map_5[] = { + { P_BI_TCXO, 0 }, + { P_GCC_GPLL0_OUT_MAIN, 1 }, + { P_GCC_GPLL7_OUT_MAIN, 2 }, + { P_GCC_GPLL0_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data gcc_parent_data_5[] = { + { .index = DT_BI_TCXO }, + { .hw = &gcc_gpll0.clkr.hw }, + { .hw = &gcc_gpll7.clkr.hw }, + { .hw = &gcc_gpll0_out_even.clkr.hw }, +}; + +static const struct parent_map gcc_parent_map_6[] = { + { P_BI_TCXO, 0 }, + { P_SLEEP_CLK, 5 }, +}; + +static const struct clk_parent_data gcc_parent_data_6[] = { + { .index = DT_BI_TCXO }, + { .index = DT_SLEEP_CLK }, +}; + +static const struct parent_map gcc_parent_map_8[] = { + { P_BI_TCXO, 0 }, + { P_GCC_GPLL0_OUT_MAIN, 1 }, + { P_GCC_GPLL9_OUT_MAIN, 2 }, + { P_GCC_GPLL4_OUT_MAIN, 5 }, + { P_GCC_GPLL0_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data gcc_parent_data_8[] = { + { .index = DT_BI_TCXO }, + { .hw = &gcc_gpll0.clkr.hw }, + { .hw = &gcc_gpll9.clkr.hw }, + { .hw = &gcc_gpll4.clkr.hw }, + { .hw = &gcc_gpll0_out_even.clkr.hw }, +}; + +static const struct parent_map gcc_parent_map_12[] = { + { P_USB3_PHY_WRAPPER_GCC_USB30_PIPE_CLK, 0 }, + { P_BI_TCXO, 2 }, +}; + +static const struct clk_parent_data gcc_parent_data_12[] = { + { .index = DT_USB3_PHY_WRAPPER_GCC_USB30_PIPE_CLK }, + { .index = DT_BI_TCXO }, +}; + +static struct clk_regmap_phy_mux gcc_pcie_0_pipe_clk_src = { + .reg = 0x6b090, + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_0_pipe_clk_src", + .parent_data = &(const struct clk_parent_data){ + .index = DT_PCIE_0_PIPE_CLK, + }, + .num_parents = 1, + .ops = &clk_regmap_phy_mux_ops, + }, + }, +}; + +static struct clk_regmap_phy_mux gcc_ufs_phy_rx_symbol_0_clk_src = { + .reg = 0x77068, + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_rx_symbol_0_clk_src", + .parent_data = &(const struct clk_parent_data){ + .index = DT_UFS_PHY_RX_SYMBOL_0_CLK, + }, + .num_parents = 1, + .ops = &clk_regmap_phy_mux_ops, + }, + }, +}; + +static struct clk_regmap_phy_mux gcc_ufs_phy_rx_symbol_1_clk_src = { + .reg = 0x770ec, + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_rx_symbol_1_clk_src", + .parent_data = &(const struct clk_parent_data){ + .index = DT_UFS_PHY_RX_SYMBOL_1_CLK, + }, + .num_parents = 1, + .ops = &clk_regmap_phy_mux_ops, + }, + }, +}; + +static struct clk_regmap_phy_mux gcc_ufs_phy_tx_symbol_0_clk_src = { + .reg = 0x77058, + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_tx_symbol_0_clk_src", + .parent_data = &(const struct clk_parent_data){ + .index = DT_UFS_PHY_TX_SYMBOL_0_CLK, + }, + .num_parents = 1, + .ops = &clk_regmap_phy_mux_ops, + }, + }, +}; + +static struct clk_regmap_mux gcc_usb3_prim_phy_pipe_clk_src = { + .reg = 0x39074, + .shift = 0, + .width = 2, + .parent_map = gcc_parent_map_12, + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb3_prim_phy_pipe_clk_src", + .parent_data = gcc_parent_data_12, + .num_parents = ARRAY_SIZE(gcc_parent_data_12), + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + +static const struct freq_tbl ftbl_gcc_gp1_clk_src[] = { + F(50000000, P_GCC_GPLL0_OUT_EVEN, 6, 0, 0), + F(100000000, P_GCC_GPLL0_OUT_MAIN, 6, 0, 0), + F(200000000, P_GCC_GPLL0_OUT_MAIN, 3, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_gp1_clk_src = { + .cmd_rcgr = 0x64004, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_2, + .freq_tbl = ftbl_gcc_gp1_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_gp1_clk_src", + .parent_data = gcc_parent_data_2, + .num_parents = ARRAY_SIZE(gcc_parent_data_2), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 gcc_gp2_clk_src = { + .cmd_rcgr = 0x65004, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_2, + .freq_tbl = ftbl_gcc_gp1_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_gp2_clk_src", + .parent_data = gcc_parent_data_2, + .num_parents = ARRAY_SIZE(gcc_parent_data_2), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 gcc_gp3_clk_src = { + .cmd_rcgr = 0x66004, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_2, + .freq_tbl = ftbl_gcc_gp1_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_gp3_clk_src", + .parent_data = gcc_parent_data_2, + .num_parents = ARRAY_SIZE(gcc_parent_data_2), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_pcie_0_aux_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_pcie_0_aux_clk_src = { + .cmd_rcgr = 0x6b094, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_6, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_0_aux_clk_src", + .parent_data = gcc_parent_data_6, + .num_parents = ARRAY_SIZE(gcc_parent_data_6), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, + }, +}; + +static struct clk_rcg2 gcc_pcie_0_phy_aux_clk_src = { + .cmd_rcgr = 0x6b0ac, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_0_phy_aux_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_pcie_0_phy_rchng_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(100000000, P_GCC_GPLL0_OUT_EVEN, 3, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_pcie_0_phy_rchng_clk_src = { + .cmd_rcgr = 0x6b078, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_pcie_0_phy_rchng_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_0_phy_rchng_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_pdm2_clk_src[] = { + F(60000000, P_GCC_GPLL0_OUT_MAIN, 10, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_pdm2_clk_src = { + .cmd_rcgr = 0x33010, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_pdm2_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pdm2_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, + }, +}; + +static struct clk_rcg2 gcc_qupv3_i2c_s0_clk_src = { + .cmd_rcgr = 0x17008, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_i2c_s0_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, + }, +}; + +static struct clk_rcg2 gcc_qupv3_i2c_s1_clk_src = { + .cmd_rcgr = 0x17024, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_i2c_s1_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, + }, +}; + +static struct clk_rcg2 gcc_qupv3_i2c_s2_clk_src = { + .cmd_rcgr = 0x17040, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_i2c_s2_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, + }, +}; + +static struct clk_rcg2 gcc_qupv3_i2c_s3_clk_src = { + .cmd_rcgr = 0x1705c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_i2c_s3_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, + }, +}; + +static struct clk_rcg2 gcc_qupv3_i2c_s4_clk_src = { + .cmd_rcgr = 0x17078, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_i2c_s4_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_qupv3_wrap1_qspi_ref_clk_src[] = { + F(7372800, P_GCC_GPLL0_OUT_EVEN, 1, 384, 15625), + F(14745600, P_GCC_GPLL0_OUT_EVEN, 1, 768, 15625), + F(19200000, P_BI_TCXO, 1, 0, 0), + F(29491200, P_GCC_GPLL0_OUT_EVEN, 1, 1536, 15625), + F(32000000, P_GCC_GPLL0_OUT_EVEN, 1, 8, 75), + F(48000000, P_GCC_GPLL0_OUT_EVEN, 1, 4, 25), + F(51200000, P_GCC_GPLL0_OUT_EVEN, 1, 64, 375), + F(64000000, P_GCC_GPLL0_OUT_EVEN, 1, 16, 75), + F(66666667, P_GCC_GPLL0_OUT_MAIN, 9, 0, 0), + F(75000000, P_GCC_GPLL0_OUT_EVEN, 4, 0, 0), + F(80000000, P_GCC_GPLL0_OUT_EVEN, 1, 4, 15), + F(96000000, P_GCC_GPLL0_OUT_EVEN, 1, 8, 25), + F(100000000, P_GCC_GPLL0_OUT_MAIN, 6, 0, 0), + F(102400000, P_GCC_GPLL0_OUT_EVEN, 1, 128, 375), + F(112000000, P_GCC_GPLL0_OUT_EVEN, 1, 28, 75), + F(117964800, P_GCC_GPLL0_OUT_EVEN, 1, 6144, 15625), + F(120000000, P_GCC_GPLL0_OUT_MAIN, 5, 0, 0), + F(150000000, P_GCC_GPLL0_OUT_EVEN, 2, 0, 0), + F(250000000, P_GCC_GPLL7_OUT_MAIN, 2, 0, 0), + { } +}; + +static struct clk_init_data gcc_qupv3_wrap1_qspi_ref_clk_src_init = { + .name = "gcc_qupv3_wrap1_qspi_ref_clk_src", + .parent_data = gcc_parent_data_5, + .num_parents = ARRAY_SIZE(gcc_parent_data_5), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap1_qspi_ref_clk_src = { + .cmd_rcgr = 0x188c0, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_5, + .freq_tbl = ftbl_gcc_qupv3_wrap1_qspi_ref_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap1_qspi_ref_clk_src_init, +}; + +static const struct freq_tbl ftbl_gcc_qupv3_wrap1_s0_clk_src[] = { + F(7372800, P_GCC_GPLL0_OUT_EVEN, 1, 384, 15625), + F(14745600, P_GCC_GPLL0_OUT_EVEN, 1, 768, 15625), + F(19200000, P_BI_TCXO, 1, 0, 0), + F(29491200, P_GCC_GPLL0_OUT_EVEN, 1, 1536, 15625), + F(32000000, P_GCC_GPLL0_OUT_EVEN, 1, 8, 75), + F(48000000, P_GCC_GPLL0_OUT_EVEN, 1, 4, 25), + F(51200000, P_GCC_GPLL0_OUT_EVEN, 1, 64, 375), + F(60000000, P_GCC_GPLL0_OUT_EVEN, 5, 0, 0), + F(64000000, P_GCC_GPLL0_OUT_EVEN, 1, 16, 75), + F(66666667, P_GCC_GPLL0_OUT_MAIN, 9, 0, 0), + F(75000000, P_GCC_GPLL0_OUT_EVEN, 4, 0, 0), + F(80000000, P_GCC_GPLL0_OUT_EVEN, 1, 4, 15), + F(96000000, P_GCC_GPLL0_OUT_EVEN, 1, 8, 25), + F(100000000, P_GCC_GPLL0_OUT_MAIN, 6, 0, 0), + { } +}; + +static struct clk_init_data gcc_qupv3_wrap1_s0_clk_src_init = { + .name = "gcc_qupv3_wrap1_s0_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap1_s0_clk_src = { + .cmd_rcgr = 0x18014, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap1_s0_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap1_s0_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap1_s1_clk_src_init = { + .name = "gcc_qupv3_wrap1_s1_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap1_s1_clk_src = { + .cmd_rcgr = 0x18150, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap1_s0_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap1_s1_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap1_s3_clk_src_init = { + .name = "gcc_qupv3_wrap1_s3_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap1_s3_clk_src = { + .cmd_rcgr = 0x182a0, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap1_s0_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap1_s3_clk_src_init, +}; + +static const struct freq_tbl ftbl_gcc_qupv3_wrap1_s4_clk_src[] = { + F(7372800, P_GCC_GPLL0_OUT_EVEN, 1, 384, 15625), + F(14745600, P_GCC_GPLL0_OUT_EVEN, 1, 768, 15625), + F(19200000, P_BI_TCXO, 1, 0, 0), + F(29491200, P_GCC_GPLL0_OUT_EVEN, 1, 1536, 15625), + F(32000000, P_GCC_GPLL0_OUT_EVEN, 1, 8, 75), + F(48000000, P_GCC_GPLL0_OUT_EVEN, 1, 4, 25), + F(51200000, P_GCC_GPLL0_OUT_EVEN, 1, 64, 375), + F(60000000, P_GCC_GPLL0_OUT_EVEN, 5, 0, 0), + F(64000000, P_GCC_GPLL0_OUT_EVEN, 1, 16, 75), + F(66666667, P_GCC_GPLL0_OUT_MAIN, 9, 0, 0), + F(75000000, P_GCC_GPLL0_OUT_EVEN, 4, 0, 0), + F(80000000, P_GCC_GPLL0_OUT_EVEN, 1, 4, 15), + F(96000000, P_GCC_GPLL0_OUT_EVEN, 1, 8, 25), + F(100000000, P_GCC_GPLL0_OUT_MAIN, 6, 0, 0), + F(102400000, P_GCC_GPLL0_OUT_EVEN, 1, 128, 375), + F(112000000, P_GCC_GPLL0_OUT_EVEN, 1, 28, 75), + F(117964800, P_GCC_GPLL0_OUT_EVEN, 1, 6144, 15625), + F(120000000, P_GCC_GPLL0_OUT_MAIN, 5, 0, 0), + { } +}; + +static struct clk_init_data gcc_qupv3_wrap1_s4_clk_src_init = { + .name = "gcc_qupv3_wrap1_s4_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap1_s4_clk_src = { + .cmd_rcgr = 0x183dc, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap1_s4_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap1_s4_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap1_s5_clk_src_init = { + .name = "gcc_qupv3_wrap1_s5_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap1_s5_clk_src = { + .cmd_rcgr = 0x18518, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap1_s0_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap1_s5_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap1_s6_clk_src_init = { + .name = "gcc_qupv3_wrap1_s6_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap1_s6_clk_src = { + .cmd_rcgr = 0x18654, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap1_s0_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap1_s6_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap1_s7_clk_src_init = { + .name = "gcc_qupv3_wrap1_s7_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap1_s7_clk_src = { + .cmd_rcgr = 0x18790, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap1_s4_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap1_s7_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap2_s0_clk_src_init = { + .name = "gcc_qupv3_wrap2_s0_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap2_s0_clk_src = { + .cmd_rcgr = 0x1e014, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap1_s4_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap2_s0_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap2_s1_clk_src_init = { + .name = "gcc_qupv3_wrap2_s1_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap2_s1_clk_src = { + .cmd_rcgr = 0x1e150, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap1_s4_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap2_s1_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap2_s2_clk_src_init = { + .name = "gcc_qupv3_wrap2_s2_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap2_s2_clk_src = { + .cmd_rcgr = 0x1e28c, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap1_s4_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap2_s2_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap2_s3_clk_src_init = { + .name = "gcc_qupv3_wrap2_s3_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap2_s3_clk_src = { + .cmd_rcgr = 0x1e3c8, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap1_s0_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap2_s3_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap2_s4_clk_src_init = { + .name = "gcc_qupv3_wrap2_s4_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap2_s4_clk_src = { + .cmd_rcgr = 0x1e504, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap1_s0_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap2_s4_clk_src_init, +}; + +static const struct freq_tbl ftbl_gcc_qupv3_wrap3_ibi_ctrl_0_clk_src[] = { + F(37500000, P_GCC_GPLL0_OUT_EVEN, 8, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_qupv3_wrap3_ibi_ctrl_0_clk_src = { + .cmd_rcgr = 0xa877c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_1, + .freq_tbl = ftbl_gcc_qupv3_wrap3_ibi_ctrl_0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap3_ibi_ctrl_0_clk_src", + .parent_data = gcc_parent_data_1, + .num_parents = ARRAY_SIZE(gcc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, + }, +}; + +static struct clk_init_data gcc_qupv3_wrap3_s0_clk_src_init = { + .name = "gcc_qupv3_wrap3_s0_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap3_s0_clk_src = { + .cmd_rcgr = 0xa8014, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap1_s0_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap3_s0_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap3_s1_clk_src_init = { + .name = "gcc_qupv3_wrap3_s1_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap3_s1_clk_src = { + .cmd_rcgr = 0xa8150, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap1_s4_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap3_s1_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap3_s2_clk_src_init = { + .name = "gcc_qupv3_wrap3_s2_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap3_s2_clk_src = { + .cmd_rcgr = 0xa828c, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap1_s4_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap3_s2_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap3_s3_clk_src_init = { + .name = "gcc_qupv3_wrap3_s3_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap3_s3_clk_src = { + .cmd_rcgr = 0xa83c8, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap1_s0_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap3_s3_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap3_s4_clk_src_init = { + .name = "gcc_qupv3_wrap3_s4_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap3_s4_clk_src = { + .cmd_rcgr = 0xa8504, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap1_s0_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap3_s4_clk_src_init, +}; + +static const struct freq_tbl ftbl_gcc_qupv3_wrap3_s5_clk_src[] = { + F(7372800, P_GCC_GPLL0_OUT_EVEN, 1, 384, 15625), + F(14745600, P_GCC_GPLL0_OUT_EVEN, 1, 768, 15625), + F(19200000, P_BI_TCXO, 1, 0, 0), + F(29491200, P_GCC_GPLL0_OUT_EVEN, 1, 1536, 15625), + F(32000000, P_GCC_GPLL0_OUT_EVEN, 1, 8, 75), + F(48000000, P_GCC_GPLL0_OUT_EVEN, 1, 4, 25), + F(51200000, P_GCC_GPLL0_OUT_EVEN, 1, 64, 375), + F(60000000, P_GCC_GPLL0_OUT_EVEN, 5, 0, 0), + F(64000000, P_GCC_GPLL0_OUT_EVEN, 1, 16, 75), + F(66666667, P_GCC_GPLL0_OUT_MAIN, 9, 0, 0), + F(75000000, P_GCC_GPLL0_OUT_EVEN, 4, 0, 0), + F(80000000, P_GCC_GPLL0_OUT_EVEN, 1, 4, 15), + F(96000000, P_GCC_GPLL0_OUT_EVEN, 1, 8, 25), + F(100000000, P_GCC_GPLL0_OUT_MAIN, 6, 0, 0), + F(102400000, P_GCC_GPLL0_OUT_EVEN, 1, 128, 375), + F(112000000, P_GCC_GPLL0_OUT_EVEN, 1, 28, 75), + F(117964800, P_GCC_GPLL0_OUT_EVEN, 1, 6144, 15625), + F(120000000, P_GCC_GPLL0_OUT_MAIN, 5, 0, 0), + F(128000000, P_GCC_GPLL0_OUT_MAIN, 1, 16, 75), + { } +}; + +static struct clk_init_data gcc_qupv3_wrap3_s5_clk_src_init = { + .name = "gcc_qupv3_wrap3_s5_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap3_s5_clk_src = { + .cmd_rcgr = 0xa8640, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap3_s5_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap3_s5_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap4_s0_clk_src_init = { + .name = "gcc_qupv3_wrap4_s0_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap4_s0_clk_src = { + .cmd_rcgr = 0xa9014, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap1_s4_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap4_s0_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap4_s1_clk_src_init = { + .name = "gcc_qupv3_wrap4_s1_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap4_s1_clk_src = { + .cmd_rcgr = 0xa9150, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap1_s4_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap4_s1_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap4_s2_clk_src_init = { + .name = "gcc_qupv3_wrap4_s2_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap4_s2_clk_src = { + .cmd_rcgr = 0xa928c, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap1_s4_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap4_s2_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap4_s3_clk_src_init = { + .name = "gcc_qupv3_wrap4_s3_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap4_s3_clk_src = { + .cmd_rcgr = 0xa93c8, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap1_s0_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap4_s3_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap4_s4_clk_src_init = { + .name = "gcc_qupv3_wrap4_s4_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap4_s4_clk_src = { + .cmd_rcgr = 0xa9504, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap1_s0_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap4_s4_clk_src_init, +}; + +static const struct freq_tbl ftbl_gcc_sdcc2_apps_clk_src[] = { + F(400000, P_BI_TCXO, 12, 1, 4), + F(25000000, P_GCC_GPLL0_OUT_EVEN, 12, 0, 0), + F(50000000, P_GCC_GPLL0_OUT_EVEN, 6, 0, 0), + F(75000000, P_GCC_GPLL0_OUT_EVEN, 4, 0, 0), + F(100000000, P_GCC_GPLL0_OUT_EVEN, 3, 0, 0), + F(202000000, P_GCC_GPLL9_OUT_MAIN, 4, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_sdcc2_apps_clk_src = { + .cmd_rcgr = 0x1401c, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_8, + .freq_tbl = ftbl_gcc_sdcc2_apps_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_sdcc2_apps_clk_src", + .parent_data = gcc_parent_data_8, + .num_parents = ARRAY_SIZE(gcc_parent_data_8), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_sdcc4_apps_clk_src[] = { + F(400000, P_BI_TCXO, 12, 1, 4), + F(25000000, P_GCC_GPLL0_OUT_EVEN, 12, 0, 0), + F(75000000, P_GCC_GPLL0_OUT_EVEN, 4, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_sdcc4_apps_clk_src = { + .cmd_rcgr = 0x1601c, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_sdcc4_apps_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_sdcc4_apps_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_ufs_phy_axi_clk_src[] = { + F(25000000, P_GCC_GPLL0_OUT_EVEN, 12, 0, 0), + F(75000000, P_GCC_GPLL0_OUT_EVEN, 4, 0, 0), + F(100000000, P_GCC_GPLL0_OUT_EVEN, 3, 0, 0), + F(201500000, P_GCC_GPLL4_OUT_MAIN, 4, 0, 0), + F(403000000, P_GCC_GPLL4_OUT_MAIN, 2, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_ufs_phy_axi_clk_src = { + .cmd_rcgr = 0x77034, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_3, + .freq_tbl = ftbl_gcc_ufs_phy_axi_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_axi_clk_src", + .parent_data = gcc_parent_data_3, + .num_parents = ARRAY_SIZE(gcc_parent_data_3), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_ufs_phy_ice_core_clk_src[] = { + F(75000000, P_GCC_GPLL0_OUT_EVEN, 4, 0, 0), + F(100000000, P_GCC_GPLL0_OUT_EVEN, 3, 0, 0), + F(201500000, P_GCC_GPLL4_OUT_MAIN, 4, 0, 0), + F(403000000, P_GCC_GPLL4_OUT_MAIN, 2, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_ufs_phy_ice_core_clk_src = { + .cmd_rcgr = 0x7708c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_3, + .freq_tbl = ftbl_gcc_ufs_phy_ice_core_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_ice_core_clk_src", + .parent_data = gcc_parent_data_3, + .num_parents = ARRAY_SIZE(gcc_parent_data_3), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_ufs_phy_phy_aux_clk_src[] = { + F(9600000, P_BI_TCXO, 2, 0, 0), + F(19200000, P_BI_TCXO, 1, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_ufs_phy_phy_aux_clk_src = { + .cmd_rcgr = 0x770c0, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_4, + .freq_tbl = ftbl_gcc_ufs_phy_phy_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_phy_aux_clk_src", + .parent_data = gcc_parent_data_4, + .num_parents = ARRAY_SIZE(gcc_parent_data_4), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, + }, +}; + +static struct clk_rcg2 gcc_ufs_phy_unipro_core_clk_src = { + .cmd_rcgr = 0x770a4, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_3, + .freq_tbl = ftbl_gcc_ufs_phy_ice_core_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_unipro_core_clk_src", + .parent_data = gcc_parent_data_3, + .num_parents = ARRAY_SIZE(gcc_parent_data_3), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_usb30_prim_master_clk_src[] = { + F(66666667, P_GCC_GPLL0_OUT_EVEN, 4.5, 0, 0), + F(133333333, P_GCC_GPLL0_OUT_MAIN, 4.5, 0, 0), + F(200000000, P_GCC_GPLL0_OUT_MAIN, 3, 0, 0), + F(240000000, P_GCC_GPLL0_OUT_MAIN, 2.5, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_usb30_prim_master_clk_src = { + .cmd_rcgr = 0x39034, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_usb30_prim_master_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb30_prim_master_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, + }, +}; + +static struct clk_rcg2 gcc_usb30_prim_mock_utmi_clk_src = { + .cmd_rcgr = 0x3904c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb30_prim_mock_utmi_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, + }, +}; + +static struct clk_rcg2 gcc_usb3_prim_phy_aux_clk_src = { + .cmd_rcgr = 0x39078, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_6, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb3_prim_phy_aux_clk_src", + .parent_data = gcc_parent_data_6, + .num_parents = ARRAY_SIZE(gcc_parent_data_6), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, + }, +}; + +static struct clk_regmap_div gcc_qupv3_wrap1_s2_clk_src = { + .reg = 0x1828c, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap1_s2_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap1_qspi_ref_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div gcc_usb30_prim_mock_utmi_postdiv_clk_src = { + .reg = 0x39064, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb30_prim_mock_utmi_postdiv_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb30_prim_mock_utmi_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_branch gcc_aggre_noc_pcie_axi_clk = { + .halt_reg = 0x10068, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x10068, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52000, + .enable_mask = BIT(12), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_aggre_noc_pcie_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_aggre_ufs_phy_axi_clk = { + .halt_reg = 0x770f0, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x770f0, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x770f0, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_aggre_ufs_phy_axi_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_ufs_phy_axi_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_aggre_usb3_prim_axi_clk = { + .halt_reg = 0x39094, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x39094, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x39094, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_aggre_usb3_prim_axi_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb30_prim_master_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_boot_rom_ahb_clk = { + .halt_reg = 0x38004, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x38004, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(18), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_boot_rom_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_camera_hf_axi_clk = { + .halt_reg = 0x26014, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x26014, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x26014, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_camera_hf_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_camera_sf_axi_clk = { + .halt_reg = 0x26028, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x26028, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x26028, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_camera_sf_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_cfg_noc_pcie_anoc_ahb_clk = { + .halt_reg = 0x10050, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x10050, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52000, + .enable_mask = BIT(20), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_cfg_noc_pcie_anoc_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_cfg_noc_usb3_prim_axi_clk = { + .halt_reg = 0x39090, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x39090, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x39090, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_cfg_noc_usb3_prim_axi_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb30_prim_master_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_cnoc_pcie_sf_axi_clk = { + .halt_reg = 0x10058, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(6), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_cnoc_pcie_sf_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ddrss_pcie_sf_qtb_clk = { + .halt_reg = 0x1007c, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x1007c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52000, + .enable_mask = BIT(19), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ddrss_pcie_sf_qtb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_disp_hf_axi_clk = { + .halt_reg = 0x2701c, + .halt_check = BRANCH_HALT_SKIP, + .clkr = { + .enable_reg = 0x2701c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_disp_hf_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_disp_sf_axi_clk = { + .halt_reg = 0x27008, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x27008, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x27008, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_disp_sf_axi_clk", + .ops = &clk_branch2_aon_ops, + }, + }, +}; + +static struct clk_branch gcc_eva_axi0_clk = { + .halt_reg = 0x9f008, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x9f008, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x9f008, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_eva_axi0_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_eva_axi0c_clk = { + .halt_reg = 0x9f01c, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x9f01c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x9f01c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_eva_axi0c_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_gp1_clk = { + .halt_reg = 0x64000, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x64000, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gp1_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_gp1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_gp2_clk = { + .halt_reg = 0x65000, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x65000, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gp2_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_gp2_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_gp3_clk = { + .halt_reg = 0x66000, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x66000, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gp3_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_gp3_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_gpu_gemnoc_gfx_clk = { + .halt_reg = 0x71010, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x71010, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x71010, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpu_gemnoc_gfx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_gpu_gpll0_clk_src = { + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x52000, + .enable_mask = BIT(15), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpu_gpll0_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &gcc_gpll0.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_gpu_gpll0_div_clk_src = { + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x52000, + .enable_mask = BIT(16), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpu_gpll0_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &gcc_gpll0_out_even.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_0_aux_clk = { + .halt_reg = 0x6b044, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(3), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_0_aux_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_0_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_0_cfg_ahb_clk = { + .halt_reg = 0x6b040, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x6b040, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(2), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_0_cfg_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_0_mstr_axi_clk = { + .halt_reg = 0x6b030, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x6b030, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(1), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_0_mstr_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_0_phy_aux_clk = { + .halt_reg = 0x6b054, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52018, + .enable_mask = BIT(31), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_0_phy_aux_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_0_phy_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_0_phy_rchng_clk = { + .halt_reg = 0x6b074, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52000, + .enable_mask = BIT(22), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_0_phy_rchng_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_0_phy_rchng_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_0_pipe_clk = { + .halt_reg = 0x6b064, + .halt_check = BRANCH_HALT_SKIP, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(4), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_0_pipe_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_0_pipe_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_0_slv_axi_clk = { + .halt_reg = 0x6b020, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x6b020, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_0_slv_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_0_slv_q2a_axi_clk = { + .halt_reg = 0x6b01c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(5), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_0_slv_q2a_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pdm2_clk = { + .halt_reg = 0x3300c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x3300c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pdm2_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pdm2_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pdm_ahb_clk = { + .halt_reg = 0x33004, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x33004, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x33004, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pdm_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pdm_xo4_clk = { + .halt_reg = 0x33008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x33008, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pdm_xo4_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qmip_camera_cmd_ahb_clk = { + .halt_reg = 0x26010, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x26010, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x26010, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qmip_camera_cmd_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qmip_camera_nrt_ahb_clk = { + .halt_reg = 0x26008, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x26008, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x26008, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qmip_camera_nrt_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qmip_camera_rt_ahb_clk = { + .halt_reg = 0x2600c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x2600c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x2600c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qmip_camera_rt_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qmip_disp_dcp_sf_ahb_clk = { + .halt_reg = 0x27030, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x27030, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x27030, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qmip_disp_dcp_sf_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qmip_gpu_ahb_clk = { + .halt_reg = 0x71008, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x71008, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x71008, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qmip_gpu_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qmip_pcie_ahb_clk = { + .halt_reg = 0x6b018, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x6b018, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(19), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qmip_pcie_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qmip_video_cv_cpu_ahb_clk = { + .halt_reg = 0x32014, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x32014, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x32014, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qmip_video_cv_cpu_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qmip_video_cvp_ahb_clk = { + .halt_reg = 0x32008, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x32008, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x32008, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qmip_video_cvp_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qmip_video_v_cpu_ahb_clk = { + .halt_reg = 0x32010, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x32010, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x32010, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qmip_video_v_cpu_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qmip_video_vcodec_ahb_clk = { + .halt_reg = 0x3200c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x3200c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x3200c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qmip_video_vcodec_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_i2c_core_clk = { + .halt_reg = 0x23004, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(8), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_i2c_core_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_i2c_s0_clk = { + .halt_reg = 0x17004, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(10), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_i2c_s0_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_i2c_s0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_i2c_s1_clk = { + .halt_reg = 0x17020, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(11), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_i2c_s1_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_i2c_s1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_i2c_s2_clk = { + .halt_reg = 0x1703c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(12), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_i2c_s2_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_i2c_s2_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_i2c_s3_clk = { + .halt_reg = 0x17058, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(13), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_i2c_s3_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_i2c_s3_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_i2c_s4_clk = { + .halt_reg = 0x17074, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(14), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_i2c_s4_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_i2c_s4_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_i2c_s_ahb_clk = { + .halt_reg = 0x23000, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x23000, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(7), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_i2c_s_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap1_core_2x_clk = { + .halt_reg = 0x2315c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(18), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap1_core_2x_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap1_core_clk = { + .halt_reg = 0x23148, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(19), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap1_core_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap1_qspi_ref_clk = { + .halt_reg = 0x188bc, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(29), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap1_qspi_ref_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap1_qspi_ref_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap1_s0_clk = { + .halt_reg = 0x18004, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(22), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap1_s0_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap1_s0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap1_s1_clk = { + .halt_reg = 0x18140, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(23), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap1_s1_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap1_s1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap1_s2_clk = { + .halt_reg = 0x1827c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(24), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap1_s2_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap1_s2_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap1_s3_clk = { + .halt_reg = 0x18290, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(25), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap1_s3_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap1_s3_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap1_s4_clk = { + .halt_reg = 0x183cc, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(26), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap1_s4_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap1_s4_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap1_s5_clk = { + .halt_reg = 0x18508, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(27), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap1_s5_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap1_s5_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap1_s6_clk = { + .halt_reg = 0x18644, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(28), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap1_s6_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap1_s6_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap1_s7_clk = { + .halt_reg = 0x18780, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(16), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap1_s7_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap1_s7_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap2_core_2x_clk = { + .halt_reg = 0x232b4, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(3), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap2_core_2x_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap2_core_clk = { + .halt_reg = 0x232a0, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap2_core_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap2_s0_clk = { + .halt_reg = 0x1e004, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(4), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap2_s0_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap2_s0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap2_s1_clk = { + .halt_reg = 0x1e140, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(5), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap2_s1_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap2_s1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap2_s2_clk = { + .halt_reg = 0x1e27c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(6), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap2_s2_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap2_s2_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap2_s3_clk = { + .halt_reg = 0x1e3b8, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(7), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap2_s3_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap2_s3_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap2_s4_clk = { + .halt_reg = 0x1e4f4, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(8), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap2_s4_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap2_s4_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap3_core_2x_clk = { + .halt_reg = 0x2340c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52018, + .enable_mask = BIT(11), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap3_core_2x_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap3_core_clk = { + .halt_reg = 0x233f8, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52018, + .enable_mask = BIT(10), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap3_core_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap3_ibi_ctrl_1_clk = { + .halt_reg = 0xa8774, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0xa8774, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52018, + .enable_mask = BIT(20), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap3_ibi_ctrl_1_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap3_ibi_ctrl_0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap3_ibi_ctrl_2_clk = { + .halt_reg = 0xa8778, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0xa8778, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52018, + .enable_mask = BIT(21), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap3_ibi_ctrl_2_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap3_ibi_ctrl_0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap3_s0_clk = { + .halt_reg = 0xa8004, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52018, + .enable_mask = BIT(12), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap3_s0_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap3_s0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap3_s1_clk = { + .halt_reg = 0xa8140, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52018, + .enable_mask = BIT(13), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap3_s1_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap3_s1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap3_s2_clk = { + .halt_reg = 0xa827c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52018, + .enable_mask = BIT(14), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap3_s2_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap3_s2_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap3_s3_clk = { + .halt_reg = 0xa83b8, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52018, + .enable_mask = BIT(15), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap3_s3_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap3_s3_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap3_s4_clk = { + .halt_reg = 0xa84f4, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52018, + .enable_mask = BIT(16), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap3_s4_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap3_s4_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap3_s5_clk = { + .halt_reg = 0xa8630, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52018, + .enable_mask = BIT(17), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap3_s5_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap3_s5_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap4_core_2x_clk = { + .halt_reg = 0x23564, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52018, + .enable_mask = BIT(25), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap4_core_2x_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap4_core_clk = { + .halt_reg = 0x23550, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52018, + .enable_mask = BIT(24), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap4_core_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap4_s0_clk = { + .halt_reg = 0xa9004, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52018, + .enable_mask = BIT(26), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap4_s0_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap4_s0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap4_s1_clk = { + .halt_reg = 0xa9140, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52018, + .enable_mask = BIT(27), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap4_s1_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap4_s1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap4_s2_clk = { + .halt_reg = 0xa927c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52018, + .enable_mask = BIT(28), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap4_s2_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap4_s2_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap4_s3_clk = { + .halt_reg = 0xa93b8, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52018, + .enable_mask = BIT(29), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap4_s3_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap4_s3_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap4_s4_clk = { + .halt_reg = 0xa94f4, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52018, + .enable_mask = BIT(30), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap4_s4_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap4_s4_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap_1_m_axi_clk = { + .halt_reg = 0x23140, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x23140, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(20), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap_1_m_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap_1_s_ahb_clk = { + .halt_reg = 0x23144, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x23144, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(21), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap_1_s_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap_2_m_ahb_clk = { + .halt_reg = 0x23298, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x23298, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(2), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap_2_m_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap_2_s_ahb_clk = { + .halt_reg = 0x2329c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x2329c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(1), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap_2_s_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap_3_ibi_1_ahb_clk = { + .halt_reg = 0xa876c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0xa876c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52018, + .enable_mask = BIT(18), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap_3_ibi_1_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap_3_ibi_2_ahb_clk = { + .halt_reg = 0xa8770, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0xa8770, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52018, + .enable_mask = BIT(19), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap_3_ibi_2_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap_3_m_ahb_clk = { + .halt_reg = 0x233f0, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x233f0, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52018, + .enable_mask = BIT(8), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap_3_m_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap_3_s_ahb_clk = { + .halt_reg = 0x233f4, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x233f4, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52018, + .enable_mask = BIT(9), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap_3_s_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap_4_m_ahb_clk = { + .halt_reg = 0x23548, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x23548, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52018, + .enable_mask = BIT(22), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap_4_m_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap_4_s_ahb_clk = { + .halt_reg = 0x2354c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x2354c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52018, + .enable_mask = BIT(23), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap_4_s_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sdcc2_ahb_clk = { + .halt_reg = 0x14014, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x14014, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_sdcc2_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sdcc2_apps_clk = { + .halt_reg = 0x14004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x14004, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_sdcc2_apps_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_sdcc2_apps_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sdcc4_ahb_clk = { + .halt_reg = 0x16014, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x16014, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_sdcc4_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sdcc4_apps_clk = { + .halt_reg = 0x16004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x16004, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_sdcc4_apps_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_sdcc4_apps_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_phy_ahb_clk = { + .halt_reg = 0x77028, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x77028, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x77028, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_phy_axi_clk = { + .halt_reg = 0x77018, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x77018, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x77018, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_axi_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_ufs_phy_axi_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_phy_ice_core_clk = { + .halt_reg = 0x7707c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x7707c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x7707c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_ice_core_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_ufs_phy_ice_core_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_phy_phy_aux_clk = { + .halt_reg = 0x770bc, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x770bc, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x770bc, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_phy_aux_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_ufs_phy_phy_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_phy_rx_symbol_0_clk = { + .halt_reg = 0x77030, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x77030, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_rx_symbol_0_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_ufs_phy_rx_symbol_0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_phy_rx_symbol_1_clk = { + .halt_reg = 0x770d8, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x770d8, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_rx_symbol_1_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_ufs_phy_rx_symbol_1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_phy_tx_symbol_0_clk = { + .halt_reg = 0x7702c, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x7702c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_tx_symbol_0_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_ufs_phy_tx_symbol_0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_phy_unipro_core_clk = { + .halt_reg = 0x7706c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x7706c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x7706c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_unipro_core_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_ufs_phy_unipro_core_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb30_prim_master_clk = { + .halt_reg = 0x39018, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x39018, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb30_prim_master_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb30_prim_master_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb30_prim_mock_utmi_clk = { + .halt_reg = 0x3902c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x3902c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb30_prim_mock_utmi_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb30_prim_mock_utmi_postdiv_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb30_prim_sleep_clk = { + .halt_reg = 0x39028, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x39028, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb30_prim_sleep_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb3_prim_phy_aux_clk = { + .halt_reg = 0x39068, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x39068, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb3_prim_phy_aux_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb3_prim_phy_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb3_prim_phy_com_aux_clk = { + .halt_reg = 0x3906c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x3906c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb3_prim_phy_com_aux_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb3_prim_phy_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb3_prim_phy_pipe_clk = { + .halt_reg = 0x39070, + .halt_check = BRANCH_HALT_DELAY, + .hwcg_reg = 0x39070, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x39070, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb3_prim_phy_pipe_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb3_prim_phy_pipe_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_video_axi0_clk = { + .halt_reg = 0x32018, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x32018, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x32018, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_video_axi0_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_video_axi1_clk = { + .halt_reg = 0x3202c, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x3202c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x3202c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_video_axi1_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct gdsc gcc_pcie_0_gdsc = { + .gdscr = 0x6b004, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0xf, + .collapse_ctrl = 0x5214c, + .collapse_mask = BIT(0), + .pd = { + .name = "gcc_pcie_0_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | VOTABLE, +}; + +static struct gdsc gcc_pcie_0_phy_gdsc = { + .gdscr = 0x6c000, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0x2, + .collapse_ctrl = 0x5214c, + .collapse_mask = BIT(2), + .pd = { + .name = "gcc_pcie_0_phy_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | VOTABLE, +}; + +static struct gdsc gcc_ufs_mem_phy_gdsc = { + .gdscr = 0x9e000, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0x2, + .pd = { + .name = "gcc_ufs_mem_phy_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, +}; + +static struct gdsc gcc_ufs_phy_gdsc = { + .gdscr = 0x77004, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0xf, + .pd = { + .name = "gcc_ufs_phy_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, +}; + +static struct gdsc gcc_usb30_prim_gdsc = { + .gdscr = 0x39004, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0xf, + .pd = { + .name = "gcc_usb30_prim_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, +}; + +static struct gdsc gcc_usb3_phy_gdsc = { + .gdscr = 0x50018, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0x2, + .pd = { + .name = "gcc_usb3_phy_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, +}; + +static struct clk_regmap *gcc_kaanapali_clocks[] = { + [GCC_AGGRE_NOC_PCIE_AXI_CLK] = &gcc_aggre_noc_pcie_axi_clk.clkr, + [GCC_AGGRE_UFS_PHY_AXI_CLK] = &gcc_aggre_ufs_phy_axi_clk.clkr, + [GCC_AGGRE_USB3_PRIM_AXI_CLK] = &gcc_aggre_usb3_prim_axi_clk.clkr, + [GCC_BOOT_ROM_AHB_CLK] = &gcc_boot_rom_ahb_clk.clkr, + [GCC_CAMERA_HF_AXI_CLK] = &gcc_camera_hf_axi_clk.clkr, + [GCC_CAMERA_SF_AXI_CLK] = &gcc_camera_sf_axi_clk.clkr, + [GCC_CFG_NOC_PCIE_ANOC_AHB_CLK] = &gcc_cfg_noc_pcie_anoc_ahb_clk.clkr, + [GCC_CFG_NOC_USB3_PRIM_AXI_CLK] = &gcc_cfg_noc_usb3_prim_axi_clk.clkr, + [GCC_CNOC_PCIE_SF_AXI_CLK] = &gcc_cnoc_pcie_sf_axi_clk.clkr, + [GCC_DDRSS_PCIE_SF_QTB_CLK] = &gcc_ddrss_pcie_sf_qtb_clk.clkr, + [GCC_DISP_HF_AXI_CLK] = &gcc_disp_hf_axi_clk.clkr, + [GCC_DISP_SF_AXI_CLK] = &gcc_disp_sf_axi_clk.clkr, + [GCC_EVA_AXI0_CLK] = &gcc_eva_axi0_clk.clkr, + [GCC_EVA_AXI0C_CLK] = &gcc_eva_axi0c_clk.clkr, + [GCC_GP1_CLK] = &gcc_gp1_clk.clkr, + [GCC_GP1_CLK_SRC] = &gcc_gp1_clk_src.clkr, + [GCC_GP2_CLK] = &gcc_gp2_clk.clkr, + [GCC_GP2_CLK_SRC] = &gcc_gp2_clk_src.clkr, + [GCC_GP3_CLK] = &gcc_gp3_clk.clkr, + [GCC_GP3_CLK_SRC] = &gcc_gp3_clk_src.clkr, + [GCC_GPLL0] = &gcc_gpll0.clkr, + [GCC_GPLL0_OUT_EVEN] = &gcc_gpll0_out_even.clkr, + [GCC_GPLL1] = &gcc_gpll1.clkr, + [GCC_GPLL4] = &gcc_gpll4.clkr, + [GCC_GPLL7] = &gcc_gpll7.clkr, + [GCC_GPLL9] = &gcc_gpll9.clkr, + [GCC_GPU_GEMNOC_GFX_CLK] = &gcc_gpu_gemnoc_gfx_clk.clkr, + [GCC_GPU_GPLL0_CLK_SRC] = &gcc_gpu_gpll0_clk_src.clkr, + [GCC_GPU_GPLL0_DIV_CLK_SRC] = &gcc_gpu_gpll0_div_clk_src.clkr, + [GCC_PCIE_0_AUX_CLK] = &gcc_pcie_0_aux_clk.clkr, + [GCC_PCIE_0_AUX_CLK_SRC] = &gcc_pcie_0_aux_clk_src.clkr, + [GCC_PCIE_0_CFG_AHB_CLK] = &gcc_pcie_0_cfg_ahb_clk.clkr, + [GCC_PCIE_0_MSTR_AXI_CLK] = &gcc_pcie_0_mstr_axi_clk.clkr, + [GCC_PCIE_0_PHY_AUX_CLK] = &gcc_pcie_0_phy_aux_clk.clkr, + [GCC_PCIE_0_PHY_AUX_CLK_SRC] = &gcc_pcie_0_phy_aux_clk_src.clkr, + [GCC_PCIE_0_PHY_RCHNG_CLK] = &gcc_pcie_0_phy_rchng_clk.clkr, + [GCC_PCIE_0_PHY_RCHNG_CLK_SRC] = &gcc_pcie_0_phy_rchng_clk_src.clkr, + [GCC_PCIE_0_PIPE_CLK] = &gcc_pcie_0_pipe_clk.clkr, + [GCC_PCIE_0_PIPE_CLK_SRC] = &gcc_pcie_0_pipe_clk_src.clkr, + [GCC_PCIE_0_SLV_AXI_CLK] = &gcc_pcie_0_slv_axi_clk.clkr, + [GCC_PCIE_0_SLV_Q2A_AXI_CLK] = &gcc_pcie_0_slv_q2a_axi_clk.clkr, + [GCC_PDM2_CLK] = &gcc_pdm2_clk.clkr, + [GCC_PDM2_CLK_SRC] = &gcc_pdm2_clk_src.clkr, + [GCC_PDM_AHB_CLK] = &gcc_pdm_ahb_clk.clkr, + [GCC_PDM_XO4_CLK] = &gcc_pdm_xo4_clk.clkr, + [GCC_QUPV3_I2C_CORE_CLK] = &gcc_qupv3_i2c_core_clk.clkr, + [GCC_QUPV3_I2C_S0_CLK] = &gcc_qupv3_i2c_s0_clk.clkr, + [GCC_QUPV3_I2C_S0_CLK_SRC] = &gcc_qupv3_i2c_s0_clk_src.clkr, + [GCC_QUPV3_I2C_S1_CLK] = &gcc_qupv3_i2c_s1_clk.clkr, + [GCC_QUPV3_I2C_S1_CLK_SRC] = &gcc_qupv3_i2c_s1_clk_src.clkr, + [GCC_QUPV3_I2C_S2_CLK] = &gcc_qupv3_i2c_s2_clk.clkr, + [GCC_QUPV3_I2C_S2_CLK_SRC] = &gcc_qupv3_i2c_s2_clk_src.clkr, + [GCC_QUPV3_I2C_S3_CLK] = &gcc_qupv3_i2c_s3_clk.clkr, + [GCC_QUPV3_I2C_S3_CLK_SRC] = &gcc_qupv3_i2c_s3_clk_src.clkr, + [GCC_QUPV3_I2C_S4_CLK] = &gcc_qupv3_i2c_s4_clk.clkr, + [GCC_QUPV3_I2C_S4_CLK_SRC] = &gcc_qupv3_i2c_s4_clk_src.clkr, + [GCC_QUPV3_I2C_S_AHB_CLK] = &gcc_qupv3_i2c_s_ahb_clk.clkr, + [GCC_QUPV3_WRAP1_CORE_2X_CLK] = &gcc_qupv3_wrap1_core_2x_clk.clkr, + [GCC_QUPV3_WRAP1_CORE_CLK] = &gcc_qupv3_wrap1_core_clk.clkr, + [GCC_QUPV3_WRAP1_QSPI_REF_CLK] = &gcc_qupv3_wrap1_qspi_ref_clk.clkr, + [GCC_QUPV3_WRAP1_QSPI_REF_CLK_SRC] = &gcc_qupv3_wrap1_qspi_ref_clk_src.clkr, + [GCC_QUPV3_WRAP1_S0_CLK] = &gcc_qupv3_wrap1_s0_clk.clkr, + [GCC_QUPV3_WRAP1_S0_CLK_SRC] = &gcc_qupv3_wrap1_s0_clk_src.clkr, + [GCC_QUPV3_WRAP1_S1_CLK] = &gcc_qupv3_wrap1_s1_clk.clkr, + [GCC_QUPV3_WRAP1_S1_CLK_SRC] = &gcc_qupv3_wrap1_s1_clk_src.clkr, + [GCC_QUPV3_WRAP1_S2_CLK] = &gcc_qupv3_wrap1_s2_clk.clkr, + [GCC_QUPV3_WRAP1_S2_CLK_SRC] = &gcc_qupv3_wrap1_s2_clk_src.clkr, + [GCC_QUPV3_WRAP1_S3_CLK] = &gcc_qupv3_wrap1_s3_clk.clkr, + [GCC_QUPV3_WRAP1_S3_CLK_SRC] = &gcc_qupv3_wrap1_s3_clk_src.clkr, + [GCC_QUPV3_WRAP1_S4_CLK] = &gcc_qupv3_wrap1_s4_clk.clkr, + [GCC_QUPV3_WRAP1_S4_CLK_SRC] = &gcc_qupv3_wrap1_s4_clk_src.clkr, + [GCC_QUPV3_WRAP1_S5_CLK] = &gcc_qupv3_wrap1_s5_clk.clkr, + [GCC_QUPV3_WRAP1_S5_CLK_SRC] = &gcc_qupv3_wrap1_s5_clk_src.clkr, + [GCC_QUPV3_WRAP1_S6_CLK] = &gcc_qupv3_wrap1_s6_clk.clkr, + [GCC_QUPV3_WRAP1_S6_CLK_SRC] = &gcc_qupv3_wrap1_s6_clk_src.clkr, + [GCC_QUPV3_WRAP1_S7_CLK] = &gcc_qupv3_wrap1_s7_clk.clkr, + [GCC_QUPV3_WRAP1_S7_CLK_SRC] = &gcc_qupv3_wrap1_s7_clk_src.clkr, + [GCC_QUPV3_WRAP2_CORE_2X_CLK] = &gcc_qupv3_wrap2_core_2x_clk.clkr, + [GCC_QUPV3_WRAP2_CORE_CLK] = &gcc_qupv3_wrap2_core_clk.clkr, + [GCC_QUPV3_WRAP2_S0_CLK] = &gcc_qupv3_wrap2_s0_clk.clkr, + [GCC_QUPV3_WRAP2_S0_CLK_SRC] = &gcc_qupv3_wrap2_s0_clk_src.clkr, + [GCC_QUPV3_WRAP2_S1_CLK] = &gcc_qupv3_wrap2_s1_clk.clkr, + [GCC_QUPV3_WRAP2_S1_CLK_SRC] = &gcc_qupv3_wrap2_s1_clk_src.clkr, + [GCC_QUPV3_WRAP2_S2_CLK] = &gcc_qupv3_wrap2_s2_clk.clkr, + [GCC_QUPV3_WRAP2_S2_CLK_SRC] = &gcc_qupv3_wrap2_s2_clk_src.clkr, + [GCC_QUPV3_WRAP2_S3_CLK] = &gcc_qupv3_wrap2_s3_clk.clkr, + [GCC_QUPV3_WRAP2_S3_CLK_SRC] = &gcc_qupv3_wrap2_s3_clk_src.clkr, + [GCC_QUPV3_WRAP2_S4_CLK] = &gcc_qupv3_wrap2_s4_clk.clkr, + [GCC_QUPV3_WRAP2_S4_CLK_SRC] = &gcc_qupv3_wrap2_s4_clk_src.clkr, + [GCC_QUPV3_WRAP3_CORE_2X_CLK] = &gcc_qupv3_wrap3_core_2x_clk.clkr, + [GCC_QUPV3_WRAP3_CORE_CLK] = &gcc_qupv3_wrap3_core_clk.clkr, + [GCC_QUPV3_WRAP3_IBI_CTRL_0_CLK_SRC] = &gcc_qupv3_wrap3_ibi_ctrl_0_clk_src.clkr, + [GCC_QUPV3_WRAP3_IBI_CTRL_1_CLK] = &gcc_qupv3_wrap3_ibi_ctrl_1_clk.clkr, + [GCC_QUPV3_WRAP3_IBI_CTRL_2_CLK] = &gcc_qupv3_wrap3_ibi_ctrl_2_clk.clkr, + [GCC_QUPV3_WRAP3_S0_CLK] = &gcc_qupv3_wrap3_s0_clk.clkr, + [GCC_QUPV3_WRAP3_S0_CLK_SRC] = &gcc_qupv3_wrap3_s0_clk_src.clkr, + [GCC_QUPV3_WRAP3_S1_CLK] = &gcc_qupv3_wrap3_s1_clk.clkr, + [GCC_QUPV3_WRAP3_S1_CLK_SRC] = &gcc_qupv3_wrap3_s1_clk_src.clkr, + [GCC_QUPV3_WRAP3_S2_CLK] = &gcc_qupv3_wrap3_s2_clk.clkr, + [GCC_QUPV3_WRAP3_S2_CLK_SRC] = &gcc_qupv3_wrap3_s2_clk_src.clkr, + [GCC_QUPV3_WRAP3_S3_CLK] = &gcc_qupv3_wrap3_s3_clk.clkr, + [GCC_QUPV3_WRAP3_S3_CLK_SRC] = &gcc_qupv3_wrap3_s3_clk_src.clkr, + [GCC_QUPV3_WRAP3_S4_CLK] = &gcc_qupv3_wrap3_s4_clk.clkr, + [GCC_QUPV3_WRAP3_S4_CLK_SRC] = &gcc_qupv3_wrap3_s4_clk_src.clkr, + [GCC_QUPV3_WRAP3_S5_CLK] = &gcc_qupv3_wrap3_s5_clk.clkr, + [GCC_QUPV3_WRAP3_S5_CLK_SRC] = &gcc_qupv3_wrap3_s5_clk_src.clkr, + [GCC_QUPV3_WRAP4_CORE_2X_CLK] = &gcc_qupv3_wrap4_core_2x_clk.clkr, + [GCC_QUPV3_WRAP4_CORE_CLK] = &gcc_qupv3_wrap4_core_clk.clkr, + [GCC_QUPV3_WRAP4_S0_CLK] = &gcc_qupv3_wrap4_s0_clk.clkr, + [GCC_QUPV3_WRAP4_S0_CLK_SRC] = &gcc_qupv3_wrap4_s0_clk_src.clkr, + [GCC_QUPV3_WRAP4_S1_CLK] = &gcc_qupv3_wrap4_s1_clk.clkr, + [GCC_QUPV3_WRAP4_S1_CLK_SRC] = &gcc_qupv3_wrap4_s1_clk_src.clkr, + [GCC_QUPV3_WRAP4_S2_CLK] = &gcc_qupv3_wrap4_s2_clk.clkr, + [GCC_QUPV3_WRAP4_S2_CLK_SRC] = &gcc_qupv3_wrap4_s2_clk_src.clkr, + [GCC_QUPV3_WRAP4_S3_CLK] = &gcc_qupv3_wrap4_s3_clk.clkr, + [GCC_QUPV3_WRAP4_S3_CLK_SRC] = &gcc_qupv3_wrap4_s3_clk_src.clkr, + [GCC_QUPV3_WRAP4_S4_CLK] = &gcc_qupv3_wrap4_s4_clk.clkr, + [GCC_QUPV3_WRAP4_S4_CLK_SRC] = &gcc_qupv3_wrap4_s4_clk_src.clkr, + [GCC_QUPV3_WRAP_1_M_AXI_CLK] = &gcc_qupv3_wrap_1_m_axi_clk.clkr, + [GCC_QUPV3_WRAP_1_S_AHB_CLK] = &gcc_qupv3_wrap_1_s_ahb_clk.clkr, + [GCC_QUPV3_WRAP_2_M_AHB_CLK] = &gcc_qupv3_wrap_2_m_ahb_clk.clkr, + [GCC_QUPV3_WRAP_2_S_AHB_CLK] = &gcc_qupv3_wrap_2_s_ahb_clk.clkr, + [GCC_QUPV3_WRAP_3_IBI_1_AHB_CLK] = &gcc_qupv3_wrap_3_ibi_1_ahb_clk.clkr, + [GCC_QUPV3_WRAP_3_IBI_2_AHB_CLK] = &gcc_qupv3_wrap_3_ibi_2_ahb_clk.clkr, + [GCC_QUPV3_WRAP_3_M_AHB_CLK] = &gcc_qupv3_wrap_3_m_ahb_clk.clkr, + [GCC_QUPV3_WRAP_3_S_AHB_CLK] = &gcc_qupv3_wrap_3_s_ahb_clk.clkr, + [GCC_QUPV3_WRAP_4_M_AHB_CLK] = &gcc_qupv3_wrap_4_m_ahb_clk.clkr, + [GCC_QUPV3_WRAP_4_S_AHB_CLK] = &gcc_qupv3_wrap_4_s_ahb_clk.clkr, + [GCC_SDCC2_AHB_CLK] = &gcc_sdcc2_ahb_clk.clkr, + [GCC_SDCC2_APPS_CLK] = &gcc_sdcc2_apps_clk.clkr, + [GCC_SDCC2_APPS_CLK_SRC] = &gcc_sdcc2_apps_clk_src.clkr, + [GCC_SDCC4_AHB_CLK] = &gcc_sdcc4_ahb_clk.clkr, + [GCC_SDCC4_APPS_CLK] = &gcc_sdcc4_apps_clk.clkr, + [GCC_SDCC4_APPS_CLK_SRC] = &gcc_sdcc4_apps_clk_src.clkr, + [GCC_UFS_PHY_AHB_CLK] = &gcc_ufs_phy_ahb_clk.clkr, + [GCC_UFS_PHY_AXI_CLK] = &gcc_ufs_phy_axi_clk.clkr, + [GCC_UFS_PHY_AXI_CLK_SRC] = &gcc_ufs_phy_axi_clk_src.clkr, + [GCC_UFS_PHY_ICE_CORE_CLK] = &gcc_ufs_phy_ice_core_clk.clkr, + [GCC_UFS_PHY_ICE_CORE_CLK_SRC] = &gcc_ufs_phy_ice_core_clk_src.clkr, + [GCC_UFS_PHY_PHY_AUX_CLK] = &gcc_ufs_phy_phy_aux_clk.clkr, + [GCC_UFS_PHY_PHY_AUX_CLK_SRC] = &gcc_ufs_phy_phy_aux_clk_src.clkr, + [GCC_UFS_PHY_RX_SYMBOL_0_CLK] = &gcc_ufs_phy_rx_symbol_0_clk.clkr, + [GCC_UFS_PHY_RX_SYMBOL_0_CLK_SRC] = &gcc_ufs_phy_rx_symbol_0_clk_src.clkr, + [GCC_UFS_PHY_RX_SYMBOL_1_CLK] = &gcc_ufs_phy_rx_symbol_1_clk.clkr, + [GCC_UFS_PHY_RX_SYMBOL_1_CLK_SRC] = &gcc_ufs_phy_rx_symbol_1_clk_src.clkr, + [GCC_UFS_PHY_TX_SYMBOL_0_CLK] = &gcc_ufs_phy_tx_symbol_0_clk.clkr, + [GCC_UFS_PHY_TX_SYMBOL_0_CLK_SRC] = &gcc_ufs_phy_tx_symbol_0_clk_src.clkr, + [GCC_UFS_PHY_UNIPRO_CORE_CLK] = &gcc_ufs_phy_unipro_core_clk.clkr, + [GCC_UFS_PHY_UNIPRO_CORE_CLK_SRC] = &gcc_ufs_phy_unipro_core_clk_src.clkr, + [GCC_USB30_PRIM_MASTER_CLK] = &gcc_usb30_prim_master_clk.clkr, + [GCC_USB30_PRIM_MASTER_CLK_SRC] = &gcc_usb30_prim_master_clk_src.clkr, + [GCC_USB30_PRIM_MOCK_UTMI_CLK] = &gcc_usb30_prim_mock_utmi_clk.clkr, + [GCC_USB30_PRIM_MOCK_UTMI_CLK_SRC] = &gcc_usb30_prim_mock_utmi_clk_src.clkr, + [GCC_USB30_PRIM_MOCK_UTMI_POSTDIV_CLK_SRC] = &gcc_usb30_prim_mock_utmi_postdiv_clk_src.clkr, + [GCC_USB30_PRIM_SLEEP_CLK] = &gcc_usb30_prim_sleep_clk.clkr, + [GCC_USB3_PRIM_PHY_AUX_CLK] = &gcc_usb3_prim_phy_aux_clk.clkr, + [GCC_USB3_PRIM_PHY_AUX_CLK_SRC] = &gcc_usb3_prim_phy_aux_clk_src.clkr, + [GCC_USB3_PRIM_PHY_COM_AUX_CLK] = &gcc_usb3_prim_phy_com_aux_clk.clkr, + [GCC_USB3_PRIM_PHY_PIPE_CLK] = &gcc_usb3_prim_phy_pipe_clk.clkr, + [GCC_USB3_PRIM_PHY_PIPE_CLK_SRC] = &gcc_usb3_prim_phy_pipe_clk_src.clkr, + [GCC_VIDEO_AXI0_CLK] = &gcc_video_axi0_clk.clkr, + [GCC_VIDEO_AXI1_CLK] = &gcc_video_axi1_clk.clkr, + [GCC_QMIP_CAMERA_CMD_AHB_CLK] = &gcc_qmip_camera_cmd_ahb_clk.clkr, + [GCC_QMIP_VIDEO_VCODEC_AHB_CLK] = &gcc_qmip_video_vcodec_ahb_clk.clkr, + [GCC_QMIP_GPU_AHB_CLK] = &gcc_qmip_gpu_ahb_clk.clkr, + [GCC_QMIP_CAMERA_NRT_AHB_CLK] = &gcc_qmip_camera_nrt_ahb_clk.clkr, + [GCC_QMIP_CAMERA_RT_AHB_CLK] = &gcc_qmip_camera_rt_ahb_clk.clkr, + [GCC_QMIP_DISP_DCP_SF_AHB_CLK] = &gcc_qmip_disp_dcp_sf_ahb_clk.clkr, + [GCC_QMIP_PCIE_AHB_CLK] = &gcc_qmip_pcie_ahb_clk.clkr, + [GCC_QMIP_VIDEO_CV_CPU_AHB_CLK] = &gcc_qmip_video_cv_cpu_ahb_clk.clkr, + [GCC_QMIP_VIDEO_CVP_AHB_CLK] = &gcc_qmip_video_cvp_ahb_clk.clkr, + [GCC_QMIP_VIDEO_V_CPU_AHB_CLK] = &gcc_qmip_video_v_cpu_ahb_clk.clkr, + [GCC_QMIP_VIDEO_VCODEC_AHB_CLK] = &gcc_qmip_video_vcodec_ahb_clk.clkr, +}; + +static struct gdsc *gcc_kaanapali_gdscs[] = { + [GCC_PCIE_0_GDSC] = &gcc_pcie_0_gdsc, + [GCC_PCIE_0_PHY_GDSC] = &gcc_pcie_0_phy_gdsc, + [GCC_UFS_MEM_PHY_GDSC] = &gcc_ufs_mem_phy_gdsc, + [GCC_UFS_PHY_GDSC] = &gcc_ufs_phy_gdsc, + [GCC_USB30_PRIM_GDSC] = &gcc_usb30_prim_gdsc, + [GCC_USB3_PHY_GDSC] = &gcc_usb3_phy_gdsc, +}; + +static const struct qcom_reset_map gcc_kaanapali_resets[] = { + [GCC_CAMERA_BCR] = { 0x26000 }, + [GCC_DISPLAY_BCR] = { 0x27000 }, + [GCC_EVA_AXI0_CLK_ARES] = { 0x9f008, 2 }, + [GCC_EVA_AXI0C_CLK_ARES] = { 0x9f01c, 2 }, + [GCC_EVA_BCR] = { 0x9f000 }, + [GCC_GPU_BCR] = { 0x71000 }, + [GCC_PCIE_0_BCR] = { 0x6b000 }, + [GCC_PCIE_0_LINK_DOWN_BCR] = { 0x6c014 }, + [GCC_PCIE_0_NOCSR_COM_PHY_BCR] = { 0x6c020 }, + [GCC_PCIE_0_PHY_BCR] = { 0x6c01c }, + [GCC_PCIE_0_PHY_NOCSR_COM_PHY_BCR] = { 0x6c028 }, + [GCC_PCIE_PHY_BCR] = { 0x6f000 }, + [GCC_PCIE_PHY_CFG_AHB_BCR] = { 0x6f00c }, + [GCC_PCIE_PHY_COM_BCR] = { 0x6f010 }, + [GCC_PCIE_RSCC_BCR] = { 0x11000 }, + [GCC_PDM_BCR] = { 0x33000 }, + [GCC_QUPV3_WRAPPER_1_BCR] = { 0x18000 }, + [GCC_QUPV3_WRAPPER_2_BCR] = { 0x1e000 }, + [GCC_QUPV3_WRAPPER_3_BCR] = { 0xa8000 }, + [GCC_QUPV3_WRAPPER_4_BCR] = { 0xa9000 }, + [GCC_QUPV3_WRAPPER_I2C_BCR] = { 0x17000 }, + [GCC_QUSB2PHY_PRIM_BCR] = { 0x12000 }, + [GCC_QUSB2PHY_SEC_BCR] = { 0x12004 }, + [GCC_SDCC2_BCR] = { 0x14000 }, + [GCC_SDCC4_BCR] = { 0x16000 }, + [GCC_UFS_PHY_BCR] = { 0x77000 }, + [GCC_USB30_PRIM_BCR] = { 0x39000 }, + [GCC_USB3_DP_PHY_PRIM_BCR] = { 0x50008 }, + [GCC_USB3_DP_PHY_SEC_BCR] = { 0x50014 }, + [GCC_USB3_PHY_PRIM_BCR] = { 0x50000 }, + [GCC_USB3_PHY_SEC_BCR] = { 0x5000c }, + [GCC_USB3PHY_PHY_PRIM_BCR] = { 0x50004 }, + [GCC_USB3PHY_PHY_SEC_BCR] = { 0x50010 }, + [GCC_VIDEO_AXI0_CLK_ARES] = { 0x32018, 2 }, + [GCC_VIDEO_AXI1_CLK_ARES] = { 0x3202c, 2 }, + [GCC_VIDEO_BCR] = { 0x32000 }, + [GCC_VIDEO_XO_CLK_ARES] = { 0x32040, 2 }, +}; + +static const struct clk_rcg_dfs_data gcc_dfs_clocks[] = { + DEFINE_RCG_DFS(gcc_qupv3_wrap1_qspi_ref_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap1_s0_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap1_s1_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap1_s3_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap1_s4_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap1_s5_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap1_s6_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap1_s7_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap2_s0_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap2_s1_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap2_s2_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap2_s3_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap2_s4_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap3_s0_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap3_s1_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap3_s2_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap3_s3_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap3_s4_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap3_s5_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap4_s0_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap4_s1_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap4_s2_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap4_s3_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap4_s4_clk_src), +}; + +static u32 gcc_kaanapali_critical_cbcrs[] = { + 0xa0004, /* GCC_CAM_BIST_MCLK_AHB_CLK */ + 0x26004, /* GCC_CAMERA_AHB_CLK */ + 0x2603c, /* GCC_CAMERA_XO_CLK */ + 0x27004, /* GCC_DISP_AHB_CLK */ + 0x9f004, /* GCC_EVA_AHB_CLK */ + 0x9f024, /* GCC_EVA_XO_CLK */ + 0x71004, /* GCC_GPU_CFG_AHB_CLK */ + 0x52010, /* GCC_PCIE_RSCC_CFG_AHB_CLK */ + 0x52010, /* GCC_PCIE_RSCC_XO_CLK */ + 0x32004, /* GCC_VIDEO_AHB_CLK */ + 0x32040, /* GCC_VIDEO_XO_CLK */ +}; + +static const struct regmap_config gcc_kaanapali_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x1f41f0, + .fast_io = true, +}; + +static void clk_kaanapali_regs_configure(struct device *dev, struct regmap *regmap) +{ + /* FORCE_MEM_CORE_ON for ufs phy ice core clocks */ + qcom_branch_set_force_mem_core(regmap, gcc_ufs_phy_ice_core_clk, true); +} + +static struct qcom_cc_driver_data gcc_kaanapali_driver_data = { + .clk_cbcrs = gcc_kaanapali_critical_cbcrs, + .num_clk_cbcrs = ARRAY_SIZE(gcc_kaanapali_critical_cbcrs), + .dfs_rcgs = gcc_dfs_clocks, + .num_dfs_rcgs = ARRAY_SIZE(gcc_dfs_clocks), + .clk_regs_configure = clk_kaanapali_regs_configure, +}; + +static const struct qcom_cc_desc gcc_kaanapali_desc = { + .config = &gcc_kaanapali_regmap_config, + .clks = gcc_kaanapali_clocks, + .num_clks = ARRAY_SIZE(gcc_kaanapali_clocks), + .resets = gcc_kaanapali_resets, + .num_resets = ARRAY_SIZE(gcc_kaanapali_resets), + .gdscs = gcc_kaanapali_gdscs, + .num_gdscs = ARRAY_SIZE(gcc_kaanapali_gdscs), + .driver_data = &gcc_kaanapali_driver_data, +}; + +static const struct of_device_id gcc_kaanapali_match_table[] = { + { .compatible = "qcom,kaanapali-gcc" }, + { } +}; +MODULE_DEVICE_TABLE(of, gcc_kaanapali_match_table); + +static int gcc_kaanapali_probe(struct platform_device *pdev) +{ + return qcom_cc_probe(pdev, &gcc_kaanapali_desc); +} + +static struct platform_driver gcc_kaanapali_driver = { + .probe = gcc_kaanapali_probe, + .driver = { + .name = "gcc-kaanapali", + .of_match_table = gcc_kaanapali_match_table, + }, +}; + +static int __init gcc_kaanapali_init(void) +{ + return platform_driver_register(&gcc_kaanapali_driver); +} +subsys_initcall(gcc_kaanapali_init); + +static void __exit gcc_kaanapali_exit(void) +{ + platform_driver_unregister(&gcc_kaanapali_driver); +} +module_exit(gcc_kaanapali_exit); + +MODULE_DESCRIPTION("QTI GCC KAANAPALI Driver"); +MODULE_LICENSE("GPL"); From 0790912f403d40df2331bd57684eb3a595387130 Mon Sep 17 00:00:00 2001 From: Jingyi Wang Date: Wed, 24 Sep 2025 16:16:04 -0700 Subject: [PATCH 0063/2333] FROMGIT: pinctrl: qcom: add the tlmm driver for Kaanapali platforms Add support for Kaanapali TLMM configuration and control via the pinctrl framework. Signed-off-by: Jingyi Wang Reviewed-by: Bartosz Golaszewski Reviewed-by: Bjorn Andersson Reviewed-by: Konrad Dybcio Signed-off-by: Yijie Yang Link: https://lore.kernel.org/all/20250924-knp-tlmm-v1-2-acabb59ae48c@oss.qualcomm.com/ --- drivers/pinctrl/qcom/Kconfig.msm | 8 + drivers/pinctrl/qcom/Makefile | 1 + drivers/pinctrl/qcom/pinctrl-kaanapali.c | 1803 ++++++++++++++++++++++ 3 files changed, 1812 insertions(+) create mode 100644 drivers/pinctrl/qcom/pinctrl-kaanapali.c diff --git a/drivers/pinctrl/qcom/Kconfig.msm b/drivers/pinctrl/qcom/Kconfig.msm index 69a5b47adedc2..3e9e02774001b 100644 --- a/drivers/pinctrl/qcom/Kconfig.msm +++ b/drivers/pinctrl/qcom/Kconfig.msm @@ -92,6 +92,14 @@ config PINCTRL_IPQ9574 Qualcomm Technologies Inc. IPQ9574 platform. Select this for IPQ9574. +config PINCTRL_KAANAPALI + tristate "Qualcomm Technologies Inc Kaanapali pin controller driver" + depends on ARM64 || COMPILE_TEST + help + This is the pinctrl, pinmux, pinconf and gpiolib driver for the + Qualcomm Technologies Inc TLMM block found on the Qualcomm + Technologies Inc Kaanapali platform. + config PINCTRL_MSM8226 tristate "Qualcomm 8226 pin controller driver" depends on ARM || COMPILE_TEST diff --git a/drivers/pinctrl/qcom/Makefile b/drivers/pinctrl/qcom/Makefile index 567d3051e760d..748b17a77b2cc 100644 --- a/drivers/pinctrl/qcom/Makefile +++ b/drivers/pinctrl/qcom/Makefile @@ -12,6 +12,7 @@ obj-$(CONFIG_PINCTRL_IPQ5424) += pinctrl-ipq5424.o obj-$(CONFIG_PINCTRL_IPQ8074) += pinctrl-ipq8074.o obj-$(CONFIG_PINCTRL_IPQ6018) += pinctrl-ipq6018.o obj-$(CONFIG_PINCTRL_IPQ9574) += pinctrl-ipq9574.o +obj-$(CONFIG_PINCTRL_KAANAPALI) += pinctrl-kaanapali.o obj-$(CONFIG_PINCTRL_MSM8226) += pinctrl-msm8226.o obj-$(CONFIG_PINCTRL_MSM8660) += pinctrl-msm8660.o obj-$(CONFIG_PINCTRL_MSM8960) += pinctrl-msm8960.o diff --git a/drivers/pinctrl/qcom/pinctrl-kaanapali.c b/drivers/pinctrl/qcom/pinctrl-kaanapali.c new file mode 100644 index 0000000000000..364e6d997337e --- /dev/null +++ b/drivers/pinctrl/qcom/pinctrl-kaanapali.c @@ -0,0 +1,1803 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#include +#include +#include + +#include "pinctrl-msm.h" + +#define REG_SIZE 0x1000 +#define PINGROUP(id, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11) \ + { \ + .grp = PINCTRL_PINGROUP("gpio" #id, \ + gpio##id##_pins, \ + ARRAY_SIZE(gpio##id##_pins)), \ + .funcs = (int[]){ \ + msm_mux_gpio, /* gpio mode */ \ + msm_mux_##f1, \ + msm_mux_##f2, \ + msm_mux_##f3, \ + msm_mux_##f4, \ + msm_mux_##f5, \ + msm_mux_##f6, \ + msm_mux_##f7, \ + msm_mux_##f8, \ + msm_mux_##f9, \ + msm_mux_##f10, \ + msm_mux_##f11 /* egpio mode */ \ + }, \ + .nfuncs = 12, \ + .ctl_reg = REG_SIZE * id, \ + .io_reg = 0x4 + REG_SIZE * id, \ + .intr_cfg_reg = 0x8 + REG_SIZE * id, \ + .intr_status_reg = 0xc + REG_SIZE * id, \ + .intr_target_reg = 0x8 + REG_SIZE * id, \ + .mux_bit = 2, \ + .pull_bit = 0, \ + .drv_bit = 6, \ + .egpio_enable = 12, \ + .egpio_present = 11, \ + .oe_bit = 9, \ + .in_bit = 0, \ + .out_bit = 1, \ + .intr_enable_bit = 0, \ + .intr_status_bit = 0, \ + .intr_wakeup_present_bit = 6, \ + .intr_wakeup_enable_bit = 7, \ + .intr_target_bit = 8, \ + .intr_target_kpss_val = 3, \ + .intr_raw_status_bit = 4, \ + .intr_polarity_bit = 1, \ + .intr_detection_bit = 2, \ + .intr_detection_width = 2, \ + } + +#define SDC_QDSD_PINGROUP(pg_name, ctl, pull, drv) \ + { \ + .grp = PINCTRL_PINGROUP(#pg_name, \ + pg_name##_pins, \ + ARRAY_SIZE(pg_name##_pins)), \ + .ctl_reg = ctl, \ + .io_reg = 0, \ + .intr_cfg_reg = 0, \ + .intr_status_reg = 0, \ + .intr_target_reg = 0, \ + .mux_bit = -1, \ + .pull_bit = pull, \ + .drv_bit = drv, \ + .oe_bit = -1, \ + .in_bit = -1, \ + .out_bit = -1, \ + .intr_enable_bit = -1, \ + .intr_status_bit = -1, \ + .intr_target_bit = -1, \ + .intr_raw_status_bit = -1, \ + .intr_polarity_bit = -1, \ + .intr_detection_bit = -1, \ + .intr_detection_width = -1, \ + } + +#define UFS_RESET(pg_name, ctl, io) \ + { \ + .grp = PINCTRL_PINGROUP(#pg_name, \ + pg_name##_pins, \ + ARRAY_SIZE(pg_name##_pins)), \ + .ctl_reg = ctl, \ + .io_reg = io, \ + .intr_cfg_reg = 0, \ + .intr_status_reg = 0, \ + .intr_target_reg = 0, \ + .mux_bit = -1, \ + .pull_bit = 3, \ + .drv_bit = 0, \ + .oe_bit = -1, \ + .in_bit = -1, \ + .out_bit = 0, \ + .intr_enable_bit = -1, \ + .intr_status_bit = -1, \ + .intr_target_bit = -1, \ + .intr_raw_status_bit = -1, \ + .intr_polarity_bit = -1, \ + .intr_detection_bit = -1, \ + .intr_detection_width = -1, \ + } + +static const struct pinctrl_pin_desc kaanapali_pins[] = { + PINCTRL_PIN(0, "GPIO_0"), + PINCTRL_PIN(1, "GPIO_1"), + PINCTRL_PIN(2, "GPIO_2"), + PINCTRL_PIN(3, "GPIO_3"), + PINCTRL_PIN(4, "GPIO_4"), + PINCTRL_PIN(5, "GPIO_5"), + PINCTRL_PIN(6, "GPIO_6"), + PINCTRL_PIN(7, "GPIO_7"), + PINCTRL_PIN(8, "GPIO_8"), + PINCTRL_PIN(9, "GPIO_9"), + PINCTRL_PIN(10, "GPIO_10"), + PINCTRL_PIN(11, "GPIO_11"), + PINCTRL_PIN(12, "GPIO_12"), + PINCTRL_PIN(13, "GPIO_13"), + PINCTRL_PIN(14, "GPIO_14"), + PINCTRL_PIN(15, "GPIO_15"), + PINCTRL_PIN(16, "GPIO_16"), + PINCTRL_PIN(17, "GPIO_17"), + PINCTRL_PIN(18, "GPIO_18"), + PINCTRL_PIN(19, "GPIO_19"), + PINCTRL_PIN(20, "GPIO_20"), + PINCTRL_PIN(21, "GPIO_21"), + PINCTRL_PIN(22, "GPIO_22"), + PINCTRL_PIN(23, "GPIO_23"), + PINCTRL_PIN(24, "GPIO_24"), + PINCTRL_PIN(25, "GPIO_25"), + PINCTRL_PIN(26, "GPIO_26"), + PINCTRL_PIN(27, "GPIO_27"), + PINCTRL_PIN(28, "GPIO_28"), + PINCTRL_PIN(29, "GPIO_29"), + PINCTRL_PIN(30, "GPIO_30"), + PINCTRL_PIN(31, "GPIO_31"), + PINCTRL_PIN(32, "GPIO_32"), + PINCTRL_PIN(33, "GPIO_33"), + PINCTRL_PIN(34, "GPIO_34"), + PINCTRL_PIN(35, "GPIO_35"), + PINCTRL_PIN(36, "GPIO_36"), + PINCTRL_PIN(37, "GPIO_37"), + PINCTRL_PIN(38, "GPIO_38"), + PINCTRL_PIN(39, "GPIO_39"), + PINCTRL_PIN(40, "GPIO_40"), + PINCTRL_PIN(41, "GPIO_41"), + PINCTRL_PIN(42, "GPIO_42"), + PINCTRL_PIN(43, "GPIO_43"), + PINCTRL_PIN(44, "GPIO_44"), + PINCTRL_PIN(45, "GPIO_45"), + PINCTRL_PIN(46, "GPIO_46"), + PINCTRL_PIN(47, "GPIO_47"), + PINCTRL_PIN(48, "GPIO_48"), + PINCTRL_PIN(49, "GPIO_49"), + PINCTRL_PIN(50, "GPIO_50"), + PINCTRL_PIN(51, "GPIO_51"), + PINCTRL_PIN(52, "GPIO_52"), + PINCTRL_PIN(53, "GPIO_53"), + PINCTRL_PIN(54, "GPIO_54"), + PINCTRL_PIN(55, "GPIO_55"), + PINCTRL_PIN(56, "GPIO_56"), + PINCTRL_PIN(57, "GPIO_57"), + PINCTRL_PIN(58, "GPIO_58"), + PINCTRL_PIN(59, "GPIO_59"), + PINCTRL_PIN(60, "GPIO_60"), + PINCTRL_PIN(61, "GPIO_61"), + PINCTRL_PIN(62, "GPIO_62"), + PINCTRL_PIN(63, "GPIO_63"), + PINCTRL_PIN(64, "GPIO_64"), + PINCTRL_PIN(65, "GPIO_65"), + PINCTRL_PIN(66, "GPIO_66"), + PINCTRL_PIN(67, "GPIO_67"), + PINCTRL_PIN(68, "GPIO_68"), + PINCTRL_PIN(69, "GPIO_69"), + PINCTRL_PIN(70, "GPIO_70"), + PINCTRL_PIN(71, "GPIO_71"), + PINCTRL_PIN(72, "GPIO_72"), + PINCTRL_PIN(73, "GPIO_73"), + PINCTRL_PIN(74, "GPIO_74"), + PINCTRL_PIN(75, "GPIO_75"), + PINCTRL_PIN(76, "GPIO_76"), + PINCTRL_PIN(77, "GPIO_77"), + PINCTRL_PIN(78, "GPIO_78"), + PINCTRL_PIN(79, "GPIO_79"), + PINCTRL_PIN(80, "GPIO_80"), + PINCTRL_PIN(81, "GPIO_81"), + PINCTRL_PIN(82, "GPIO_82"), + PINCTRL_PIN(83, "GPIO_83"), + PINCTRL_PIN(84, "GPIO_84"), + PINCTRL_PIN(85, "GPIO_85"), + PINCTRL_PIN(86, "GPIO_86"), + PINCTRL_PIN(87, "GPIO_87"), + PINCTRL_PIN(88, "GPIO_88"), + PINCTRL_PIN(89, "GPIO_89"), + PINCTRL_PIN(90, "GPIO_90"), + PINCTRL_PIN(91, "GPIO_91"), + PINCTRL_PIN(92, "GPIO_92"), + PINCTRL_PIN(93, "GPIO_93"), + PINCTRL_PIN(94, "GPIO_94"), + PINCTRL_PIN(95, "GPIO_95"), + PINCTRL_PIN(96, "GPIO_96"), + PINCTRL_PIN(97, "GPIO_97"), + PINCTRL_PIN(98, "GPIO_98"), + PINCTRL_PIN(99, "GPIO_99"), + PINCTRL_PIN(100, "GPIO_100"), + PINCTRL_PIN(101, "GPIO_101"), + PINCTRL_PIN(102, "GPIO_102"), + PINCTRL_PIN(103, "GPIO_103"), + PINCTRL_PIN(104, "GPIO_104"), + PINCTRL_PIN(105, "GPIO_105"), + PINCTRL_PIN(106, "GPIO_106"), + PINCTRL_PIN(107, "GPIO_107"), + PINCTRL_PIN(108, "GPIO_108"), + PINCTRL_PIN(109, "GPIO_109"), + PINCTRL_PIN(110, "GPIO_110"), + PINCTRL_PIN(111, "GPIO_111"), + PINCTRL_PIN(112, "GPIO_112"), + PINCTRL_PIN(113, "GPIO_113"), + PINCTRL_PIN(114, "GPIO_114"), + PINCTRL_PIN(115, "GPIO_115"), + PINCTRL_PIN(116, "GPIO_116"), + PINCTRL_PIN(117, "GPIO_117"), + PINCTRL_PIN(118, "GPIO_118"), + PINCTRL_PIN(119, "GPIO_119"), + PINCTRL_PIN(120, "GPIO_120"), + PINCTRL_PIN(121, "GPIO_121"), + PINCTRL_PIN(122, "GPIO_122"), + PINCTRL_PIN(123, "GPIO_123"), + PINCTRL_PIN(124, "GPIO_124"), + PINCTRL_PIN(125, "GPIO_125"), + PINCTRL_PIN(126, "GPIO_126"), + PINCTRL_PIN(127, "GPIO_127"), + PINCTRL_PIN(128, "GPIO_128"), + PINCTRL_PIN(129, "GPIO_129"), + PINCTRL_PIN(130, "GPIO_130"), + PINCTRL_PIN(131, "GPIO_131"), + PINCTRL_PIN(132, "GPIO_132"), + PINCTRL_PIN(133, "GPIO_133"), + PINCTRL_PIN(134, "GPIO_134"), + PINCTRL_PIN(135, "GPIO_135"), + PINCTRL_PIN(136, "GPIO_136"), + PINCTRL_PIN(137, "GPIO_137"), + PINCTRL_PIN(138, "GPIO_138"), + PINCTRL_PIN(139, "GPIO_139"), + PINCTRL_PIN(140, "GPIO_140"), + PINCTRL_PIN(141, "GPIO_141"), + PINCTRL_PIN(142, "GPIO_142"), + PINCTRL_PIN(143, "GPIO_143"), + PINCTRL_PIN(144, "GPIO_144"), + PINCTRL_PIN(145, "GPIO_145"), + PINCTRL_PIN(146, "GPIO_146"), + PINCTRL_PIN(147, "GPIO_147"), + PINCTRL_PIN(148, "GPIO_148"), + PINCTRL_PIN(149, "GPIO_149"), + PINCTRL_PIN(150, "GPIO_150"), + PINCTRL_PIN(151, "GPIO_151"), + PINCTRL_PIN(152, "GPIO_152"), + PINCTRL_PIN(153, "GPIO_153"), + PINCTRL_PIN(154, "GPIO_154"), + PINCTRL_PIN(155, "GPIO_155"), + PINCTRL_PIN(156, "GPIO_156"), + PINCTRL_PIN(157, "GPIO_157"), + PINCTRL_PIN(158, "GPIO_158"), + PINCTRL_PIN(159, "GPIO_159"), + PINCTRL_PIN(160, "GPIO_160"), + PINCTRL_PIN(161, "GPIO_161"), + PINCTRL_PIN(162, "GPIO_162"), + PINCTRL_PIN(163, "GPIO_163"), + PINCTRL_PIN(164, "GPIO_164"), + PINCTRL_PIN(165, "GPIO_165"), + PINCTRL_PIN(166, "GPIO_166"), + PINCTRL_PIN(167, "GPIO_167"), + PINCTRL_PIN(168, "GPIO_168"), + PINCTRL_PIN(169, "GPIO_169"), + PINCTRL_PIN(170, "GPIO_170"), + PINCTRL_PIN(171, "GPIO_171"), + PINCTRL_PIN(172, "GPIO_172"), + PINCTRL_PIN(173, "GPIO_173"), + PINCTRL_PIN(174, "GPIO_174"), + PINCTRL_PIN(175, "GPIO_175"), + PINCTRL_PIN(176, "GPIO_176"), + PINCTRL_PIN(177, "GPIO_177"), + PINCTRL_PIN(178, "GPIO_178"), + PINCTRL_PIN(179, "GPIO_179"), + PINCTRL_PIN(180, "GPIO_180"), + PINCTRL_PIN(181, "GPIO_181"), + PINCTRL_PIN(182, "GPIO_182"), + PINCTRL_PIN(183, "GPIO_183"), + PINCTRL_PIN(184, "GPIO_184"), + PINCTRL_PIN(185, "GPIO_185"), + PINCTRL_PIN(186, "GPIO_186"), + PINCTRL_PIN(187, "GPIO_187"), + PINCTRL_PIN(188, "GPIO_188"), + PINCTRL_PIN(189, "GPIO_189"), + PINCTRL_PIN(190, "GPIO_190"), + PINCTRL_PIN(191, "GPIO_191"), + PINCTRL_PIN(192, "GPIO_192"), + PINCTRL_PIN(193, "GPIO_193"), + PINCTRL_PIN(194, "GPIO_194"), + PINCTRL_PIN(195, "GPIO_195"), + PINCTRL_PIN(196, "GPIO_196"), + PINCTRL_PIN(197, "GPIO_197"), + PINCTRL_PIN(198, "GPIO_198"), + PINCTRL_PIN(199, "GPIO_199"), + PINCTRL_PIN(200, "GPIO_200"), + PINCTRL_PIN(201, "GPIO_201"), + PINCTRL_PIN(202, "GPIO_202"), + PINCTRL_PIN(203, "GPIO_203"), + PINCTRL_PIN(204, "GPIO_204"), + PINCTRL_PIN(205, "GPIO_205"), + PINCTRL_PIN(206, "GPIO_206"), + PINCTRL_PIN(207, "GPIO_207"), + PINCTRL_PIN(208, "GPIO_208"), + PINCTRL_PIN(209, "GPIO_209"), + PINCTRL_PIN(210, "GPIO_210"), + PINCTRL_PIN(211, "GPIO_211"), + PINCTRL_PIN(212, "GPIO_212"), + PINCTRL_PIN(213, "GPIO_213"), + PINCTRL_PIN(214, "GPIO_214"), + PINCTRL_PIN(215, "GPIO_215"), + PINCTRL_PIN(216, "GPIO_216"), + PINCTRL_PIN(217, "UFS_RESET"), + PINCTRL_PIN(218, "SDC2_CLK"), + PINCTRL_PIN(219, "SDC2_CMD"), + PINCTRL_PIN(220, "SDC2_DATA"), +}; + +#define DECLARE_MSM_GPIO_PINS(pin) \ + static const unsigned int gpio##pin##_pins[] = { pin } +DECLARE_MSM_GPIO_PINS(0); +DECLARE_MSM_GPIO_PINS(1); +DECLARE_MSM_GPIO_PINS(2); +DECLARE_MSM_GPIO_PINS(3); +DECLARE_MSM_GPIO_PINS(4); +DECLARE_MSM_GPIO_PINS(5); +DECLARE_MSM_GPIO_PINS(6); +DECLARE_MSM_GPIO_PINS(7); +DECLARE_MSM_GPIO_PINS(8); +DECLARE_MSM_GPIO_PINS(9); +DECLARE_MSM_GPIO_PINS(10); +DECLARE_MSM_GPIO_PINS(11); +DECLARE_MSM_GPIO_PINS(12); +DECLARE_MSM_GPIO_PINS(13); +DECLARE_MSM_GPIO_PINS(14); +DECLARE_MSM_GPIO_PINS(15); +DECLARE_MSM_GPIO_PINS(16); +DECLARE_MSM_GPIO_PINS(17); +DECLARE_MSM_GPIO_PINS(18); +DECLARE_MSM_GPIO_PINS(19); +DECLARE_MSM_GPIO_PINS(20); +DECLARE_MSM_GPIO_PINS(21); +DECLARE_MSM_GPIO_PINS(22); +DECLARE_MSM_GPIO_PINS(23); +DECLARE_MSM_GPIO_PINS(24); +DECLARE_MSM_GPIO_PINS(25); +DECLARE_MSM_GPIO_PINS(26); +DECLARE_MSM_GPIO_PINS(27); +DECLARE_MSM_GPIO_PINS(28); +DECLARE_MSM_GPIO_PINS(29); +DECLARE_MSM_GPIO_PINS(30); +DECLARE_MSM_GPIO_PINS(31); +DECLARE_MSM_GPIO_PINS(32); +DECLARE_MSM_GPIO_PINS(33); +DECLARE_MSM_GPIO_PINS(34); +DECLARE_MSM_GPIO_PINS(35); +DECLARE_MSM_GPIO_PINS(36); +DECLARE_MSM_GPIO_PINS(37); +DECLARE_MSM_GPIO_PINS(38); +DECLARE_MSM_GPIO_PINS(39); +DECLARE_MSM_GPIO_PINS(40); +DECLARE_MSM_GPIO_PINS(41); +DECLARE_MSM_GPIO_PINS(42); +DECLARE_MSM_GPIO_PINS(43); +DECLARE_MSM_GPIO_PINS(44); +DECLARE_MSM_GPIO_PINS(45); +DECLARE_MSM_GPIO_PINS(46); +DECLARE_MSM_GPIO_PINS(47); +DECLARE_MSM_GPIO_PINS(48); +DECLARE_MSM_GPIO_PINS(49); +DECLARE_MSM_GPIO_PINS(50); +DECLARE_MSM_GPIO_PINS(51); +DECLARE_MSM_GPIO_PINS(52); +DECLARE_MSM_GPIO_PINS(53); +DECLARE_MSM_GPIO_PINS(54); +DECLARE_MSM_GPIO_PINS(55); +DECLARE_MSM_GPIO_PINS(56); +DECLARE_MSM_GPIO_PINS(57); +DECLARE_MSM_GPIO_PINS(58); +DECLARE_MSM_GPIO_PINS(59); +DECLARE_MSM_GPIO_PINS(60); +DECLARE_MSM_GPIO_PINS(61); +DECLARE_MSM_GPIO_PINS(62); +DECLARE_MSM_GPIO_PINS(63); +DECLARE_MSM_GPIO_PINS(64); +DECLARE_MSM_GPIO_PINS(65); +DECLARE_MSM_GPIO_PINS(66); +DECLARE_MSM_GPIO_PINS(67); +DECLARE_MSM_GPIO_PINS(68); +DECLARE_MSM_GPIO_PINS(69); +DECLARE_MSM_GPIO_PINS(70); +DECLARE_MSM_GPIO_PINS(71); +DECLARE_MSM_GPIO_PINS(72); +DECLARE_MSM_GPIO_PINS(73); +DECLARE_MSM_GPIO_PINS(74); +DECLARE_MSM_GPIO_PINS(75); +DECLARE_MSM_GPIO_PINS(76); +DECLARE_MSM_GPIO_PINS(77); +DECLARE_MSM_GPIO_PINS(78); +DECLARE_MSM_GPIO_PINS(79); +DECLARE_MSM_GPIO_PINS(80); +DECLARE_MSM_GPIO_PINS(81); +DECLARE_MSM_GPIO_PINS(82); +DECLARE_MSM_GPIO_PINS(83); +DECLARE_MSM_GPIO_PINS(84); +DECLARE_MSM_GPIO_PINS(85); +DECLARE_MSM_GPIO_PINS(86); +DECLARE_MSM_GPIO_PINS(87); +DECLARE_MSM_GPIO_PINS(88); +DECLARE_MSM_GPIO_PINS(89); +DECLARE_MSM_GPIO_PINS(90); +DECLARE_MSM_GPIO_PINS(91); +DECLARE_MSM_GPIO_PINS(92); +DECLARE_MSM_GPIO_PINS(93); +DECLARE_MSM_GPIO_PINS(94); +DECLARE_MSM_GPIO_PINS(95); +DECLARE_MSM_GPIO_PINS(96); +DECLARE_MSM_GPIO_PINS(97); +DECLARE_MSM_GPIO_PINS(98); +DECLARE_MSM_GPIO_PINS(99); +DECLARE_MSM_GPIO_PINS(100); +DECLARE_MSM_GPIO_PINS(101); +DECLARE_MSM_GPIO_PINS(102); +DECLARE_MSM_GPIO_PINS(103); +DECLARE_MSM_GPIO_PINS(104); +DECLARE_MSM_GPIO_PINS(105); +DECLARE_MSM_GPIO_PINS(106); +DECLARE_MSM_GPIO_PINS(107); +DECLARE_MSM_GPIO_PINS(108); +DECLARE_MSM_GPIO_PINS(109); +DECLARE_MSM_GPIO_PINS(110); +DECLARE_MSM_GPIO_PINS(111); +DECLARE_MSM_GPIO_PINS(112); +DECLARE_MSM_GPIO_PINS(113); +DECLARE_MSM_GPIO_PINS(114); +DECLARE_MSM_GPIO_PINS(115); +DECLARE_MSM_GPIO_PINS(116); +DECLARE_MSM_GPIO_PINS(117); +DECLARE_MSM_GPIO_PINS(118); +DECLARE_MSM_GPIO_PINS(119); +DECLARE_MSM_GPIO_PINS(120); +DECLARE_MSM_GPIO_PINS(121); +DECLARE_MSM_GPIO_PINS(122); +DECLARE_MSM_GPIO_PINS(123); +DECLARE_MSM_GPIO_PINS(124); +DECLARE_MSM_GPIO_PINS(125); +DECLARE_MSM_GPIO_PINS(126); +DECLARE_MSM_GPIO_PINS(127); +DECLARE_MSM_GPIO_PINS(128); +DECLARE_MSM_GPIO_PINS(129); +DECLARE_MSM_GPIO_PINS(130); +DECLARE_MSM_GPIO_PINS(131); +DECLARE_MSM_GPIO_PINS(132); +DECLARE_MSM_GPIO_PINS(133); +DECLARE_MSM_GPIO_PINS(134); +DECLARE_MSM_GPIO_PINS(135); +DECLARE_MSM_GPIO_PINS(136); +DECLARE_MSM_GPIO_PINS(137); +DECLARE_MSM_GPIO_PINS(138); +DECLARE_MSM_GPIO_PINS(139); +DECLARE_MSM_GPIO_PINS(140); +DECLARE_MSM_GPIO_PINS(141); +DECLARE_MSM_GPIO_PINS(142); +DECLARE_MSM_GPIO_PINS(143); +DECLARE_MSM_GPIO_PINS(144); +DECLARE_MSM_GPIO_PINS(145); +DECLARE_MSM_GPIO_PINS(146); +DECLARE_MSM_GPIO_PINS(147); +DECLARE_MSM_GPIO_PINS(148); +DECLARE_MSM_GPIO_PINS(149); +DECLARE_MSM_GPIO_PINS(150); +DECLARE_MSM_GPIO_PINS(151); +DECLARE_MSM_GPIO_PINS(152); +DECLARE_MSM_GPIO_PINS(153); +DECLARE_MSM_GPIO_PINS(154); +DECLARE_MSM_GPIO_PINS(155); +DECLARE_MSM_GPIO_PINS(156); +DECLARE_MSM_GPIO_PINS(157); +DECLARE_MSM_GPIO_PINS(158); +DECLARE_MSM_GPIO_PINS(159); +DECLARE_MSM_GPIO_PINS(160); +DECLARE_MSM_GPIO_PINS(161); +DECLARE_MSM_GPIO_PINS(162); +DECLARE_MSM_GPIO_PINS(163); +DECLARE_MSM_GPIO_PINS(164); +DECLARE_MSM_GPIO_PINS(165); +DECLARE_MSM_GPIO_PINS(166); +DECLARE_MSM_GPIO_PINS(167); +DECLARE_MSM_GPIO_PINS(168); +DECLARE_MSM_GPIO_PINS(169); +DECLARE_MSM_GPIO_PINS(170); +DECLARE_MSM_GPIO_PINS(171); +DECLARE_MSM_GPIO_PINS(172); +DECLARE_MSM_GPIO_PINS(173); +DECLARE_MSM_GPIO_PINS(174); +DECLARE_MSM_GPIO_PINS(175); +DECLARE_MSM_GPIO_PINS(176); +DECLARE_MSM_GPIO_PINS(177); +DECLARE_MSM_GPIO_PINS(178); +DECLARE_MSM_GPIO_PINS(179); +DECLARE_MSM_GPIO_PINS(180); +DECLARE_MSM_GPIO_PINS(181); +DECLARE_MSM_GPIO_PINS(182); +DECLARE_MSM_GPIO_PINS(183); +DECLARE_MSM_GPIO_PINS(184); +DECLARE_MSM_GPIO_PINS(185); +DECLARE_MSM_GPIO_PINS(186); +DECLARE_MSM_GPIO_PINS(187); +DECLARE_MSM_GPIO_PINS(188); +DECLARE_MSM_GPIO_PINS(189); +DECLARE_MSM_GPIO_PINS(190); +DECLARE_MSM_GPIO_PINS(191); +DECLARE_MSM_GPIO_PINS(192); +DECLARE_MSM_GPIO_PINS(193); +DECLARE_MSM_GPIO_PINS(194); +DECLARE_MSM_GPIO_PINS(195); +DECLARE_MSM_GPIO_PINS(196); +DECLARE_MSM_GPIO_PINS(197); +DECLARE_MSM_GPIO_PINS(198); +DECLARE_MSM_GPIO_PINS(199); +DECLARE_MSM_GPIO_PINS(200); +DECLARE_MSM_GPIO_PINS(201); +DECLARE_MSM_GPIO_PINS(202); +DECLARE_MSM_GPIO_PINS(203); +DECLARE_MSM_GPIO_PINS(204); +DECLARE_MSM_GPIO_PINS(205); +DECLARE_MSM_GPIO_PINS(206); +DECLARE_MSM_GPIO_PINS(207); +DECLARE_MSM_GPIO_PINS(208); +DECLARE_MSM_GPIO_PINS(209); +DECLARE_MSM_GPIO_PINS(210); +DECLARE_MSM_GPIO_PINS(211); +DECLARE_MSM_GPIO_PINS(212); +DECLARE_MSM_GPIO_PINS(213); +DECLARE_MSM_GPIO_PINS(214); +DECLARE_MSM_GPIO_PINS(215); +DECLARE_MSM_GPIO_PINS(216); + +static const unsigned int ufs_reset_pins[] = { 217 }; +static const unsigned int sdc2_clk_pins[] = { 218 }; +static const unsigned int sdc2_cmd_pins[] = { 219 }; +static const unsigned int sdc2_data_pins[] = { 220 }; + +enum kaanapali_functions { + msm_mux_gpio, + msm_mux_aoss_cti, + msm_mux_atest_char, + msm_mux_atest_usb, + msm_mux_audio_ext_mclk0, + msm_mux_audio_ext_mclk1, + msm_mux_audio_ref_clk, + msm_mux_cam_asc_mclk2, + msm_mux_cam_asc_mclk4, + msm_mux_cam_mclk, + msm_mux_cci_async_in, + msm_mux_cci_i2c_scl, + msm_mux_cci_i2c_sda, + msm_mux_cci_timer, + msm_mux_cmu_rng, + msm_mux_coex_uart1_rx, + msm_mux_coex_uart1_tx, + msm_mux_coex_uart2_rx, + msm_mux_coex_uart2_tx, + msm_mux_dbg_out_clk, + msm_mux_ddr_bist_complete, + msm_mux_ddr_bist_fail, + msm_mux_ddr_bist_start, + msm_mux_ddr_bist_stop, + msm_mux_ddr_pxi0, + msm_mux_ddr_pxi1, + msm_mux_ddr_pxi2, + msm_mux_ddr_pxi3, + msm_mux_dp_hot, + msm_mux_egpio, + msm_mux_gcc_gp1, + msm_mux_gcc_gp2, + msm_mux_gcc_gp3, + msm_mux_gnss_adc0, + msm_mux_gnss_adc1, + msm_mux_i2chub0_se0, + msm_mux_i2chub0_se1, + msm_mux_i2chub0_se2, + msm_mux_i2chub0_se3, + msm_mux_i2chub0_se4, + msm_mux_i2s0_data0, + msm_mux_i2s0_data1, + msm_mux_i2s0_sck, + msm_mux_i2s0_ws, + msm_mux_i2s1_data0, + msm_mux_i2s1_data1, + msm_mux_i2s1_sck, + msm_mux_i2s1_ws, + msm_mux_ibi_i3c, + msm_mux_jitter_bist, + msm_mux_mdp_esync0_out, + msm_mux_mdp_esync1_out, + msm_mux_mdp_vsync, + msm_mux_mdp_vsync0_out, + msm_mux_mdp_vsync1_out, + msm_mux_mdp_vsync2_out, + msm_mux_mdp_vsync3_out, + msm_mux_mdp_vsync5_out, + msm_mux_mdp_vsync_e, + msm_mux_nav_gpio0, + msm_mux_nav_gpio1, + msm_mux_nav_gpio2, + msm_mux_nav_gpio3, + msm_mux_pcie0_clk_req_n, + msm_mux_phase_flag, + msm_mux_pll_bist_sync, + msm_mux_pll_clk_aux, + msm_mux_prng_rosc0, + msm_mux_prng_rosc1, + msm_mux_prng_rosc2, + msm_mux_prng_rosc3, + msm_mux_qdss_cti, + msm_mux_qdss_gpio_traceclk, + msm_mux_qdss_gpio_tracectl, + msm_mux_qdss_gpio_tracedata, + msm_mux_qlink_big_enable, + msm_mux_qlink_big_request, + msm_mux_qlink_little_enable, + msm_mux_qlink_little_request, + msm_mux_qlink_wmss, + msm_mux_qspi0, + msm_mux_qspi1, + msm_mux_qspi2, + msm_mux_qspi3, + msm_mux_qspi_clk, + msm_mux_qspi_cs, + msm_mux_qup1_se0, + msm_mux_qup1_se1, + msm_mux_qup1_se2, + msm_mux_qup1_se3, + msm_mux_qup1_se4, + msm_mux_qup1_se5, + msm_mux_qup1_se6, + msm_mux_qup1_se7, + msm_mux_qup2_se0, + msm_mux_qup2_se1, + msm_mux_qup2_se2, + msm_mux_qup2_se3, + msm_mux_qup2_se4, + msm_mux_qup3_se0, + msm_mux_qup3_se1, + msm_mux_qup3_se2, + msm_mux_qup3_se3, + msm_mux_qup3_se4, + msm_mux_qup3_se5, + msm_mux_qup4_se0, + msm_mux_qup4_se1, + msm_mux_qup4_se2, + msm_mux_qup4_se3, + msm_mux_qup4_se4, + msm_mux_sd_write_protect, + msm_mux_sdc40, + msm_mux_sdc41, + msm_mux_sdc42, + msm_mux_sdc43, + msm_mux_sdc4_clk, + msm_mux_sdc4_cmd, + msm_mux_sys_throttle, + msm_mux_tb_trig_sdc2, + msm_mux_tb_trig_sdc4, + msm_mux_tmess_prng0, + msm_mux_tmess_prng1, + msm_mux_tmess_prng2, + msm_mux_tmess_prng3, + msm_mux_tsense_pwm1, + msm_mux_tsense_pwm2, + msm_mux_tsense_pwm3, + msm_mux_tsense_pwm4, + msm_mux_tsense_pwm5, + msm_mux_tsense_pwm6, + msm_mux_tsense_pwm7, + msm_mux_uim0_clk, + msm_mux_uim0_data, + msm_mux_uim0_present, + msm_mux_uim0_reset, + msm_mux_uim1_clk, + msm_mux_uim1_data, + msm_mux_uim1_present, + msm_mux_uim1_reset, + msm_mux_usb0_hs, + msm_mux_usb_phy, + msm_mux_vfr_0, + msm_mux_vfr_1, + msm_mux_vsense_trigger_mirnat, + msm_mux_wcn_sw, + msm_mux_wcn_sw_ctrl, + msm_mux__, +}; + +static const char *const gpio_groups[] = { + "gpio0", "gpio1", "gpio2", "gpio3", "gpio4", "gpio5", + "gpio6", "gpio7", "gpio8", "gpio9", "gpio10", "gpio11", + "gpio12", "gpio13", "gpio14", "gpio15", "gpio16", "gpio17", + "gpio18", "gpio19", "gpio20", "gpio21", "gpio22", "gpio23", + "gpio24", "gpio25", "gpio26", "gpio27", "gpio28", "gpio29", + "gpio30", "gpio31", "gpio32", "gpio33", "gpio34", "gpio35", + "gpio36", "gpio37", "gpio38", "gpio39", "gpio40", "gpio41", + "gpio42", "gpio43", "gpio44", "gpio45", "gpio46", "gpio47", + "gpio48", "gpio49", "gpio50", "gpio51", "gpio52", "gpio53", + "gpio54", "gpio55", "gpio56", "gpio57", "gpio58", "gpio59", + "gpio60", "gpio61", "gpio62", "gpio63", "gpio64", "gpio65", + "gpio66", "gpio67", "gpio68", "gpio69", "gpio70", "gpio71", + "gpio72", "gpio73", "gpio74", "gpio75", "gpio76", "gpio77", + "gpio78", "gpio79", "gpio80", "gpio81", "gpio82", "gpio83", + "gpio84", "gpio85", "gpio86", "gpio87", "gpio88", "gpio89", + "gpio90", "gpio91", "gpio92", "gpio93", "gpio94", "gpio95", + "gpio96", "gpio97", "gpio98", "gpio99", "gpio100", "gpio101", + "gpio102", "gpio103", "gpio104", "gpio105", "gpio106", "gpio107", + "gpio108", "gpio109", "gpio110", "gpio111", "gpio112", "gpio113", + "gpio114", "gpio115", "gpio116", "gpio117", "gpio118", "gpio119", + "gpio120", "gpio121", "gpio122", "gpio123", "gpio124", "gpio125", + "gpio126", "gpio127", "gpio128", "gpio129", "gpio130", "gpio131", + "gpio132", "gpio133", "gpio134", "gpio135", "gpio136", "gpio137", + "gpio138", "gpio139", "gpio140", "gpio141", "gpio142", "gpio143", + "gpio144", "gpio145", "gpio146", "gpio147", "gpio148", "gpio149", + "gpio150", "gpio151", "gpio152", "gpio153", "gpio154", "gpio155", + "gpio156", "gpio157", "gpio158", "gpio159", "gpio160", "gpio161", + "gpio162", "gpio163", "gpio164", "gpio165", "gpio166", "gpio167", + "gpio168", "gpio169", "gpio170", "gpio171", "gpio172", "gpio173", + "gpio174", "gpio175", "gpio176", "gpio177", "gpio178", "gpio179", + "gpio180", "gpio181", "gpio182", "gpio183", "gpio184", "gpio185", + "gpio186", "gpio187", "gpio188", "gpio189", "gpio190", "gpio191", + "gpio192", "gpio193", "gpio194", "gpio195", "gpio196", "gpio197", + "gpio198", "gpio199", "gpio200", "gpio201", "gpio202", "gpio203", + "gpio204", "gpio205", "gpio206", "gpio207", "gpio208", "gpio209", + "gpio210", "gpio211", "gpio212", "gpio213", "gpio214", "gpio215", + "gpio216", +}; + +static const char *const aoss_cti_groups[] = { + "gpio74", "gpio75", "gpio76", "gpio77", +}; + +static const char *const atest_char_groups[] = { + "gpio126", "gpio127", "gpio128", "gpio129", "gpio133", +}; + +static const char *const atest_usb_groups[] = { + "gpio70", "gpio71", "gpio72", "gpio73", "gpio129", +}; + +static const char *const audio_ext_mclk0_groups[] = { + "gpio121", +}; + +static const char *const audio_ext_mclk1_groups[] = { + "gpio120", +}; + +static const char *const audio_ref_clk_groups[] = { + "gpio120", +}; + +static const char *const cam_asc_mclk2_groups[] = { + "gpio91", +}; + +static const char *const cam_asc_mclk4_groups[] = { + "gpio93", +}; + +static const char *const cam_mclk_groups[] = { + "gpio89", "gpio90", "gpio92", "gpio94", "gpio95", "gpio96", +}; + +static const char *const cci_async_in_groups[] = { + "gpio10", "gpio11", "gpio15", +}; + +static const char *const cci_i2c_scl_groups[] = { + "gpio110", "gpio112", "gpio114", "gpio116", "gpio149", "gpio160", +}; + +static const char *const cci_i2c_sda_groups[] = { + "gpio107", "gpio108", "gpio109", "gpio111", "gpio113", "gpio115", +}; + +static const char *const cci_timer_groups[] = { + "gpio105", "gpio106", "gpio107", "gpio159", "gpio160", +}; + +static const char *const cmu_rng_groups[] = { + "gpio40", "gpio41", "gpio42", "gpio43", "gpio144", "gpio145", + "gpio146", "gpio147", +}; + +static const char *const coex_uart1_rx_groups[] = { + "gpio144", +}; + +static const char *const coex_uart1_tx_groups[] = { + "gpio145", +}; + +static const char *const coex_uart2_rx_groups[] = { + "gpio146", +}; + +static const char *const coex_uart2_tx_groups[] = { + "gpio147", +}; + +static const char *const dbg_out_clk_groups[] = { + "gpio42", +}; + +static const char *const ddr_bist_complete_groups[] = { + "gpio44", +}; + +static const char *const ddr_bist_fail_groups[] = { + "gpio40", +}; + +static const char *const ddr_bist_start_groups[] = { + "gpio41", +}; + +static const char *const ddr_bist_stop_groups[] = { + "gpio45", +}; + +static const char *const ddr_pxi0_groups[] = { + "gpio54", "gpio55", +}; + +static const char *const ddr_pxi1_groups[] = { + "gpio44", "gpio45", +}; + +static const char *const ddr_pxi2_groups[] = { + "gpio43", "gpio52", +}; + +static const char *const ddr_pxi3_groups[] = { + "gpio46", "gpio53", +}; + +static const char *const dp_hot_groups[] = { + "gpio47", +}; + +static const char *const egpio_groups[] = { + "gpio0", "gpio1", "gpio2", "gpio3", "gpio4", "gpio5", + "gpio6", "gpio7", "gpio28", "gpio29", "gpio48", "gpio49", + "gpio50", "gpio51", "gpio163", "gpio164", "gpio165", "gpio166", + "gpio167", "gpio168", "gpio169", "gpio170", "gpio171", "gpio172", + "gpio173", "gpio174", "gpio175", "gpio176", "gpio177", "gpio178", + "gpio179", "gpio180", "gpio181", "gpio182", "gpio183", "gpio184", + "gpio185", "gpio186", "gpio187", "gpio188", "gpio189", "gpio190", + "gpio191", "gpio192", "gpio193", "gpio194", "gpio195", "gpio196", + "gpio197", "gpio198", "gpio199", "gpio200", "gpio201", "gpio202", + "gpio203", "gpio204", "gpio205", "gpio206", "gpio207", "gpio208", + "gpio209", "gpio210", "gpio211", "gpio212", "gpio213", "gpio214", + "gpio215", "gpio216", +}; + +static const char *const gcc_gp1_groups[] = { + "gpio130", "gpio158", +}; + +static const char *const gcc_gp2_groups[] = { + "gpio86", "gpio131", +}; + +static const char *const gcc_gp3_groups[] = { + "gpio87", "gpio132", +}; + +static const char *const gnss_adc0_groups[] = { + "gpio40", "gpio41", +}; + +static const char *const gnss_adc1_groups[] = { + "gpio42", "gpio77", +}; + +static const char *const i2chub0_se0_groups[] = { + "gpio66", "gpio67", +}; + +static const char *const i2chub0_se1_groups[] = { + "gpio78", "gpio79", +}; + +static const char *const i2chub0_se2_groups[] = { + "gpio68", "gpio69", +}; + +static const char *const i2chub0_se3_groups[] = { + "gpio70", "gpio71", +}; + +static const char *const i2chub0_se4_groups[] = { + "gpio72", "gpio73", +}; + +static const char *const i2s0_data0_groups[] = { + "gpio123", +}; + +static const char *const i2s0_data1_groups[] = { + "gpio124", +}; + +static const char *const i2s0_sck_groups[] = { + "gpio122", +}; + +static const char *const i2s0_ws_groups[] = { + "gpio125", +}; + +static const char *const i2s1_data0_groups[] = { + "gpio118", +}; + +static const char *const i2s1_data1_groups[] = { + "gpio120", +}; + +static const char *const i2s1_sck_groups[] = { + "gpio117", +}; + +static const char *const i2s1_ws_groups[] = { + "gpio119", +}; + +static const char *const ibi_i3c_groups[] = { + "gpio0", "gpio1", "gpio4", "gpio5", "gpio8", "gpio9", + "gpio12", "gpio13", "gpio28", "gpio29", "gpio32", "gpio33", + "gpio36", "gpio37", "gpio48", "gpio49", "gpio60", "gpio61", +}; + +static const char *const jitter_bist_groups[] = { + "gpio73", +}; + +static const char *const mdp_esync0_out_groups[] = { + "gpio88", +}; + +static const char *const mdp_esync1_out_groups[] = { + "gpio100", +}; + +static const char *const mdp_vsync_groups[] = { + "gpio86", "gpio87", "gpio97", "gpio98", +}; + +static const char *const mdp_vsync0_out_groups[] = { + "gpio86", +}; + +static const char *const mdp_vsync1_out_groups[] = { + "gpio86", +}; + +static const char *const mdp_vsync2_out_groups[] = { + "gpio87", +}; + +static const char *const mdp_vsync3_out_groups[] = { + "gpio87", +}; + +static const char *const mdp_vsync5_out_groups[] = { + "gpio87", +}; + +static const char *const mdp_vsync_e_groups[] = { + "gpio88", +}; + +static const char *const nav_gpio0_groups[] = { + "gpio150", +}; + +static const char *const nav_gpio1_groups[] = { + "gpio151", +}; + +static const char *const nav_gpio2_groups[] = { + "gpio148", +}; + +static const char *const nav_gpio3_groups[] = { + "gpio150", +}; + +static const char *const pcie0_clk_req_n_groups[] = { + "gpio103", +}; + +static const char *const phase_flag_groups[] = { + "gpio117", "gpio118", "gpio119", "gpio123", "gpio124", "gpio125", + "gpio169", "gpio170", "gpio171", "gpio172", "gpio173", "gpio175", + "gpio176", "gpio179", "gpio180", "gpio181", "gpio184", "gpio185", + "gpio192", "gpio196", "gpio197", "gpio198", "gpio199", "gpio204", + "gpio206", "gpio207", "gpio208", "gpio210", "gpio211", "gpio214", + "gpio215", "gpio216", +}; + +static const char *const pll_bist_sync_groups[] = { + "gpio104", +}; + +static const char *const pll_clk_aux_groups[] = { + "gpio94", +}; + +static const char *const prng_rosc0_groups[] = { + "gpio85", +}; + +static const char *const prng_rosc1_groups[] = { + "gpio64", +}; + +static const char *const prng_rosc2_groups[] = { + "gpio65", +}; + +static const char *const prng_rosc3_groups[] = { + "gpio66", +}; + +static const char *const qdss_cti_groups[] = { + "gpio27", "gpio31", "gpio72", "gpio73", "gpio82", "gpio83", + "gpio155", "gpio158", +}; + +static const char *const qdss_gpio_traceclk_groups[] = { + "gpio128", +}; + +static const char *const qdss_gpio_tracectl_groups[] = { + "gpio127", +}; + +static const char *const qdss_gpio_tracedata_groups[] = { + "gpio38", "gpio39", "gpio40", "gpio41", "gpio42", "gpio43", + "gpio62", "gpio63", "gpio68", "gpio69", "gpio126", "gpio129", + "gpio130", "gpio131", "gpio132", "gpio133", +}; + +static const char *const qlink_big_enable_groups[] = { + "gpio156", +}; + +static const char *const qlink_big_request_groups[] = { + "gpio155", +}; + +static const char *const qlink_little_enable_groups[] = { + "gpio153", +}; + +static const char *const qlink_little_request_groups[] = { + "gpio152", +}; + +static const char *const qlink_wmss_groups[] = { + "gpio154", +}; + +static const char *const qspi0_groups[] = { + "gpio80", +}; + +static const char *const qspi1_groups[] = { + "gpio147", +}; + +static const char *const qspi2_groups[] = { + "gpio81", +}; + +static const char *const qspi3_groups[] = { + "gpio82", +}; + +static const char *const qspi_clk_groups[] = { + "gpio83", +}; + +static const char *const qspi_cs_groups[] = { + "gpio146", "gpio148", +}; + +static const char *const qup1_se0_groups[] = { + "gpio80", "gpio81", "gpio82", "gpio83", +}; + +static const char *const qup1_se1_groups[] = { + "gpio74", "gpio75", "gpio76", "gpio77", +}; + +static const char *const qup1_se2_groups[] = { + "gpio40", "gpio41", "gpio42", "gpio43", "gpio130", "gpio131", "gpio132", +}; + +static const char *const qup1_se3_groups[] = { + "gpio44", "gpio45", "gpio46", "gpio47", +}; + +static const char *const qup1_se4_groups[] = { + "gpio36", "gpio37", "gpio38", "gpio39", +}; + +static const char *const qup1_se5_groups[] = { + "gpio52", "gpio53", "gpio54", "gpio55", +}; + +static const char *const qup1_se6_groups[] = { + "gpio56", "gpio57", "gpio58", "gpio59", +}; + +static const char *const qup1_se7_groups[] = { + "gpio60", "gpio61", "gpio62", "gpio63", +}; + +static const char *const qup2_se0_groups[] = { + "gpio0", "gpio1", "gpio2", "gpio3", +}; + +static const char *const qup2_se1_groups[] = { + "gpio4", "gpio5", "gpio6", "gpio7", +}; + +static const char *const qup2_se2_groups[] = { + "gpio117", "gpio118", "gpio119", "gpio120", +}; + +static const char *const qup2_se3_groups[] = { + "gpio122", "gpio123", "gpio124", "gpio125", +}; + +static const char *const qup2_se4_groups[] = { + "gpio208", "gpio209", +}; + +static const char *const qup3_se0_groups[] = { + "gpio64", "gpio65", +}; + +static const char *const qup3_se1_groups[] = { + "gpio8", "gpio9", "gpio10", "gpio11", "gpio12", "gpio13", "gpio15", +}; + +static const char *const qup3_se2_groups[] = { + "gpio12", "gpio13", "gpio14", "gpio15", +}; + +static const char *const qup3_se3_groups[] = { + "gpio16", "gpio17", "gpio18", "gpio19", +}; + +static const char *const qup3_se4_groups[] = { + "gpio20", "gpio21", "gpio22", "gpio23", +}; + +static const char *const qup3_se5_groups[] = { + "gpio24", "gpio25", "gpio26", "gpio27", +}; + +static const char *const qup4_se0_groups[] = { + "gpio48", "gpio49", "gpio50", "gpio51", +}; + +static const char *const qup4_se1_groups[] = { + "gpio28", "gpio29", "gpio30", "gpio31", +}; + +static const char *const qup4_se2_groups[] = { + "gpio32", "gpio33", "gpio34", "gpio35", +}; + +static const char *const qup4_se3_groups[] = { + "gpio84", "gpio121", +}; + +static const char *const qup4_se4_groups[] = { + "gpio161", "gpio162", +}; + +static const char *const sd_write_protect_groups[] = { + "gpio85", +}; + +static const char *const sdc40_groups[] = { + "gpio80", +}; + +static const char *const sdc41_groups[] = { + "gpio147", +}; + +static const char *const sdc42_groups[] = { + "gpio81", +}; + +static const char *const sdc43_groups[] = { + "gpio82", +}; + +static const char *const sdc4_clk_groups[] = { + "gpio83", +}; + +static const char *const sdc4_cmd_groups[] = { + "gpio148", +}; + +static const char *const sys_throttle_groups[] = { + "gpio99", +}; + +static const char *const tb_trig_sdc2_groups[] = { + "gpio88", +}; + +static const char *const tb_trig_sdc4_groups[] = { + "gpio146", +}; + +static const char *const tmess_prng0_groups[] = { + "gpio85", +}; + +static const char *const tmess_prng1_groups[] = { + "gpio64", +}; + +static const char *const tmess_prng2_groups[] = { + "gpio65", +}; + +static const char *const tmess_prng3_groups[] = { + "gpio66", +}; + +static const char *const tsense_pwm1_groups[] = { + "gpio87", +}; + +static const char *const tsense_pwm2_groups[] = { + "gpio10", +}; + +static const char *const tsense_pwm3_groups[] = { + "gpio97", +}; + +static const char *const tsense_pwm4_groups[] = { + "gpio99", +}; + +static const char *const tsense_pwm5_groups[] = { + "gpio105", +}; + +static const char *const tsense_pwm6_groups[] = { + "gpio106", +}; + +static const char *const tsense_pwm7_groups[] = { + "gpio159", +}; + +static const char *const uim0_clk_groups[] = { + "gpio127", +}; + +static const char *const uim0_data_groups[] = { + "gpio126", +}; + +static const char *const uim0_present_groups[] = { + "gpio129", +}; + +static const char *const uim0_reset_groups[] = { + "gpio128", +}; + +static const char *const uim1_clk_groups[] = { + "gpio37", "gpio55", "gpio71", "gpio131", +}; + +static const char *const uim1_data_groups[] = { + "gpio36", "gpio54", "gpio70", "gpio130", +}; + +static const char *const uim1_present_groups[] = { + "gpio133", +}; + +static const char *const uim1_reset_groups[] = { + "gpio39", "gpio56", "gpio72", "gpio132", +}; + +static const char *const usb0_hs_groups[] = { + "gpio79", +}; + +static const char *const usb_phy_groups[] = { + "gpio59", "gpio60", +}; + +static const char *const vfr_0_groups[] = { + "gpio146", +}; + +static const char *const vfr_1_groups[] = { + "gpio151", +}; + +static const char *const vsense_trigger_mirnat_groups[] = { + "gpio59", +}; + +static const char *const wcn_sw_groups[] = { + "gpio19", +}; + +static const char *const wcn_sw_ctrl_groups[] = { + "gpio18", +}; + +static const struct pinfunction kaanapali_functions[] = { + MSM_GPIO_PIN_FUNCTION(gpio), + MSM_PIN_FUNCTION(aoss_cti), + MSM_PIN_FUNCTION(atest_char), + MSM_PIN_FUNCTION(atest_usb), + MSM_PIN_FUNCTION(audio_ext_mclk0), + MSM_PIN_FUNCTION(audio_ext_mclk1), + MSM_PIN_FUNCTION(audio_ref_clk), + MSM_PIN_FUNCTION(cam_asc_mclk2), + MSM_PIN_FUNCTION(cam_asc_mclk4), + MSM_PIN_FUNCTION(cam_mclk), + MSM_PIN_FUNCTION(cci_async_in), + MSM_PIN_FUNCTION(cci_i2c_scl), + MSM_PIN_FUNCTION(cci_i2c_sda), + MSM_PIN_FUNCTION(cci_timer), + MSM_PIN_FUNCTION(cmu_rng), + MSM_PIN_FUNCTION(coex_uart1_rx), + MSM_PIN_FUNCTION(coex_uart1_tx), + MSM_PIN_FUNCTION(coex_uart2_rx), + MSM_PIN_FUNCTION(coex_uart2_tx), + MSM_PIN_FUNCTION(dbg_out_clk), + MSM_PIN_FUNCTION(ddr_bist_complete), + MSM_PIN_FUNCTION(ddr_bist_fail), + MSM_PIN_FUNCTION(ddr_bist_start), + MSM_PIN_FUNCTION(ddr_bist_stop), + MSM_PIN_FUNCTION(ddr_pxi0), + MSM_PIN_FUNCTION(ddr_pxi1), + MSM_PIN_FUNCTION(ddr_pxi2), + MSM_PIN_FUNCTION(ddr_pxi3), + MSM_PIN_FUNCTION(dp_hot), + MSM_PIN_FUNCTION(egpio), + MSM_PIN_FUNCTION(gcc_gp1), + MSM_PIN_FUNCTION(gcc_gp2), + MSM_PIN_FUNCTION(gcc_gp3), + MSM_PIN_FUNCTION(gnss_adc0), + MSM_PIN_FUNCTION(gnss_adc1), + MSM_PIN_FUNCTION(i2chub0_se0), + MSM_PIN_FUNCTION(i2chub0_se1), + MSM_PIN_FUNCTION(i2chub0_se2), + MSM_PIN_FUNCTION(i2chub0_se3), + MSM_PIN_FUNCTION(i2chub0_se4), + MSM_PIN_FUNCTION(i2s0_data0), + MSM_PIN_FUNCTION(i2s0_data1), + MSM_PIN_FUNCTION(i2s0_sck), + MSM_PIN_FUNCTION(i2s0_ws), + MSM_PIN_FUNCTION(i2s1_data0), + MSM_PIN_FUNCTION(i2s1_data1), + MSM_PIN_FUNCTION(i2s1_sck), + MSM_PIN_FUNCTION(i2s1_ws), + MSM_PIN_FUNCTION(ibi_i3c), + MSM_PIN_FUNCTION(jitter_bist), + MSM_PIN_FUNCTION(mdp_esync0_out), + MSM_PIN_FUNCTION(mdp_esync1_out), + MSM_PIN_FUNCTION(mdp_vsync), + MSM_PIN_FUNCTION(mdp_vsync0_out), + MSM_PIN_FUNCTION(mdp_vsync1_out), + MSM_PIN_FUNCTION(mdp_vsync2_out), + MSM_PIN_FUNCTION(mdp_vsync3_out), + MSM_PIN_FUNCTION(mdp_vsync5_out), + MSM_PIN_FUNCTION(mdp_vsync_e), + MSM_PIN_FUNCTION(nav_gpio0), + MSM_PIN_FUNCTION(nav_gpio1), + MSM_PIN_FUNCTION(nav_gpio2), + MSM_PIN_FUNCTION(nav_gpio3), + MSM_PIN_FUNCTION(pcie0_clk_req_n), + MSM_PIN_FUNCTION(phase_flag), + MSM_PIN_FUNCTION(pll_bist_sync), + MSM_PIN_FUNCTION(pll_clk_aux), + MSM_PIN_FUNCTION(prng_rosc0), + MSM_PIN_FUNCTION(prng_rosc1), + MSM_PIN_FUNCTION(prng_rosc2), + MSM_PIN_FUNCTION(prng_rosc3), + MSM_PIN_FUNCTION(qdss_cti), + MSM_PIN_FUNCTION(qdss_gpio_traceclk), + MSM_PIN_FUNCTION(qdss_gpio_tracectl), + MSM_PIN_FUNCTION(qdss_gpio_tracedata), + MSM_PIN_FUNCTION(qlink_big_enable), + MSM_PIN_FUNCTION(qlink_big_request), + MSM_PIN_FUNCTION(qlink_little_enable), + MSM_PIN_FUNCTION(qlink_little_request), + MSM_PIN_FUNCTION(qlink_wmss), + MSM_PIN_FUNCTION(qspi0), + MSM_PIN_FUNCTION(qspi1), + MSM_PIN_FUNCTION(qspi2), + MSM_PIN_FUNCTION(qspi3), + MSM_PIN_FUNCTION(qspi_clk), + MSM_PIN_FUNCTION(qspi_cs), + MSM_PIN_FUNCTION(qup1_se0), + MSM_PIN_FUNCTION(qup1_se1), + MSM_PIN_FUNCTION(qup1_se2), + MSM_PIN_FUNCTION(qup1_se3), + MSM_PIN_FUNCTION(qup1_se4), + MSM_PIN_FUNCTION(qup1_se5), + MSM_PIN_FUNCTION(qup1_se6), + MSM_PIN_FUNCTION(qup1_se7), + MSM_PIN_FUNCTION(qup2_se0), + MSM_PIN_FUNCTION(qup2_se1), + MSM_PIN_FUNCTION(qup2_se2), + MSM_PIN_FUNCTION(qup2_se3), + MSM_PIN_FUNCTION(qup2_se4), + MSM_PIN_FUNCTION(qup3_se0), + MSM_PIN_FUNCTION(qup3_se1), + MSM_PIN_FUNCTION(qup3_se2), + MSM_PIN_FUNCTION(qup3_se3), + MSM_PIN_FUNCTION(qup3_se4), + MSM_PIN_FUNCTION(qup3_se5), + MSM_PIN_FUNCTION(qup4_se0), + MSM_PIN_FUNCTION(qup4_se1), + MSM_PIN_FUNCTION(qup4_se2), + MSM_PIN_FUNCTION(qup4_se3), + MSM_PIN_FUNCTION(qup4_se4), + MSM_PIN_FUNCTION(sd_write_protect), + MSM_PIN_FUNCTION(sdc40), + MSM_PIN_FUNCTION(sdc41), + MSM_PIN_FUNCTION(sdc42), + MSM_PIN_FUNCTION(sdc43), + MSM_PIN_FUNCTION(sdc4_clk), + MSM_PIN_FUNCTION(sdc4_cmd), + MSM_PIN_FUNCTION(sys_throttle), + MSM_PIN_FUNCTION(tb_trig_sdc2), + MSM_PIN_FUNCTION(tb_trig_sdc4), + MSM_PIN_FUNCTION(tmess_prng0), + MSM_PIN_FUNCTION(tmess_prng1), + MSM_PIN_FUNCTION(tmess_prng2), + MSM_PIN_FUNCTION(tmess_prng3), + MSM_PIN_FUNCTION(tsense_pwm1), + MSM_PIN_FUNCTION(tsense_pwm2), + MSM_PIN_FUNCTION(tsense_pwm3), + MSM_PIN_FUNCTION(tsense_pwm4), + MSM_PIN_FUNCTION(tsense_pwm5), + MSM_PIN_FUNCTION(tsense_pwm6), + MSM_PIN_FUNCTION(tsense_pwm7), + MSM_PIN_FUNCTION(uim0_clk), + MSM_PIN_FUNCTION(uim0_data), + MSM_PIN_FUNCTION(uim0_present), + MSM_PIN_FUNCTION(uim0_reset), + MSM_PIN_FUNCTION(uim1_clk), + MSM_PIN_FUNCTION(uim1_data), + MSM_PIN_FUNCTION(uim1_present), + MSM_PIN_FUNCTION(uim1_reset), + MSM_PIN_FUNCTION(usb0_hs), + MSM_PIN_FUNCTION(usb_phy), + MSM_PIN_FUNCTION(vfr_0), + MSM_PIN_FUNCTION(vfr_1), + MSM_PIN_FUNCTION(vsense_trigger_mirnat), + MSM_PIN_FUNCTION(wcn_sw), + MSM_PIN_FUNCTION(wcn_sw_ctrl), +}; + +/* Every pin is maintained as a single group, and missing or non-existing pin + * would be maintained as dummy group to synchronize pin group index with + * pin descriptor registered with pinctrl core. + * Clients would not be able to request these dummy pin groups. + */ +static const struct msm_pingroup kaanapali_groups[] = { + [0] = PINGROUP(0, qup2_se0, ibi_i3c, _, _, _, _, _, _, _, _, egpio), + [1] = PINGROUP(1, qup2_se0, ibi_i3c, _, _, _, _, _, _, _, _, egpio), + [2] = PINGROUP(2, qup2_se0, _, _, _, _, _, _, _, _, _, egpio), + [3] = PINGROUP(3, qup2_se0, _, _, _, _, _, _, _, _, _, egpio), + [4] = PINGROUP(4, qup2_se1, ibi_i3c, _, _, _, _, _, _, _, _, egpio), + [5] = PINGROUP(5, qup2_se1, ibi_i3c, _, _, _, _, _, _, _, _, egpio), + [6] = PINGROUP(6, qup2_se1, _, _, _, _, _, _, _, _, _, egpio), + [7] = PINGROUP(7, qup2_se1, _, _, _, _, _, _, _, _, _, egpio), + [8] = PINGROUP(8, qup3_se1, ibi_i3c, _, _, _, _, _, _, _, _, _), + [9] = PINGROUP(9, qup3_se1, ibi_i3c, _, _, _, _, _, _, _, _, _), + [10] = PINGROUP(10, qup3_se1, cci_async_in, _, tsense_pwm2, _, _, _, _, _, _, _), + [11] = PINGROUP(11, qup3_se1, cci_async_in, _, _, _, _, _, _, _, _, _), + [12] = PINGROUP(12, qup3_se2, ibi_i3c, qup3_se1, _, _, _, _, _, _, _, _), + [13] = PINGROUP(13, qup3_se2, ibi_i3c, qup3_se1, _, _, _, _, _, _, _, _), + [14] = PINGROUP(14, qup3_se2, _, _, _, _, _, _, _, _, _, _), + [15] = PINGROUP(15, qup3_se2, cci_async_in, qup3_se1, _, _, _, _, _, _, _, _), + [16] = PINGROUP(16, qup3_se3, _, _, _, _, _, _, _, _, _, _), + [17] = PINGROUP(17, qup3_se3, _, _, _, _, _, _, _, _, _, _), + [18] = PINGROUP(18, wcn_sw_ctrl, qup3_se3, _, _, _, _, _, _, _, _, _), + [19] = PINGROUP(19, wcn_sw, qup3_se3, _, _, _, _, _, _, _, _, _), + [20] = PINGROUP(20, qup3_se4, _, _, _, _, _, _, _, _, _, _), + [21] = PINGROUP(21, qup3_se4, _, _, _, _, _, _, _, _, _, _), + [22] = PINGROUP(22, qup3_se4, _, _, _, _, _, _, _, _, _, _), + [23] = PINGROUP(23, qup3_se4, _, _, _, _, _, _, _, _, _, _), + [24] = PINGROUP(24, qup3_se5, _, _, _, _, _, _, _, _, _, _), + [25] = PINGROUP(25, qup3_se5, _, _, _, _, _, _, _, _, _, _), + [26] = PINGROUP(26, qup3_se5, _, _, _, _, _, _, _, _, _, _), + [27] = PINGROUP(27, qup3_se5, qdss_cti, _, _, _, _, _, _, _, _, _), + [28] = PINGROUP(28, qup4_se1, ibi_i3c, _, _, _, _, _, _, _, _, egpio), + [29] = PINGROUP(29, qup4_se1, ibi_i3c, _, _, _, _, _, _, _, _, egpio), + [30] = PINGROUP(30, qup4_se1, _, _, _, _, _, _, _, _, _, _), + [31] = PINGROUP(31, qup4_se1, qdss_cti, _, _, _, _, _, _, _, _, _), + [32] = PINGROUP(32, qup4_se2, ibi_i3c, _, _, _, _, _, _, _, _, _), + [33] = PINGROUP(33, qup4_se2, ibi_i3c, _, _, _, _, _, _, _, _, _), + [34] = PINGROUP(34, qup4_se2, _, _, _, _, _, _, _, _, _, _), + [35] = PINGROUP(35, qup4_se2, _, _, _, _, _, _, _, _, _, _), + [36] = PINGROUP(36, qup1_se4, uim1_data, ibi_i3c, _, _, _, _, _, _, _, _), + [37] = PINGROUP(37, qup1_se4, uim1_clk, ibi_i3c, _, _, _, _, _, _, _, _), + [38] = PINGROUP(38, qup1_se4, qdss_gpio_tracedata, _, _, _, _, _, _, _, _, _), + [39] = PINGROUP(39, qup1_se4, uim1_reset, qdss_gpio_tracedata, _, _, _, _, _, _, _, _), + [40] = PINGROUP(40, qup1_se2, cmu_rng, ddr_bist_fail, _, qdss_gpio_tracedata, gnss_adc0, + _, _, _, _, _), + [41] = PINGROUP(41, qup1_se2, cmu_rng, ddr_bist_start, _, qdss_gpio_tracedata, gnss_adc0, + _, _, _, _, _), + [42] = PINGROUP(42, qup1_se2, cmu_rng, dbg_out_clk, qdss_gpio_tracedata, gnss_adc1, _, _, + _, _, _, _), + [43] = PINGROUP(43, qup1_se2, cmu_rng, _, qdss_gpio_tracedata, ddr_pxi2, _, _, _, _, _, _), + [44] = PINGROUP(44, qup1_se3, ddr_bist_complete, ddr_pxi1, _, _, _, _, _, _, _, _), + [45] = PINGROUP(45, qup1_se3, ddr_bist_stop, ddr_pxi1, _, _, _, _, _, _, _, _), + [46] = PINGROUP(46, qup1_se3, ddr_pxi3, _, _, _, _, _, _, _, _, _), + [47] = PINGROUP(47, qup1_se3, dp_hot, _, _, _, _, _, _, _, _, _), + [48] = PINGROUP(48, qup4_se0, ibi_i3c, _, _, _, _, _, _, _, _, egpio), + [49] = PINGROUP(49, qup4_se0, ibi_i3c, _, _, _, _, _, _, _, _, egpio), + [50] = PINGROUP(50, qup4_se0, _, _, _, _, _, _, _, _, _, egpio), + [51] = PINGROUP(51, qup4_se0, _, _, _, _, _, _, _, _, _, egpio), + [52] = PINGROUP(52, qup1_se5, ddr_pxi2, _, _, _, _, _, _, _, _, _), + [53] = PINGROUP(53, qup1_se5, _, ddr_pxi3, _, _, _, _, _, _, _, _), + [54] = PINGROUP(54, qup1_se5, uim1_data, ddr_pxi0, _, _, _, _, _, _, _, _), + [55] = PINGROUP(55, qup1_se5, uim1_clk, ddr_pxi0, _, _, _, _, _, _, _, _), + [56] = PINGROUP(56, qup1_se6, uim1_reset, _, _, _, _, _, _, _, _, _), + [57] = PINGROUP(57, qup1_se6, _, _, _, _, _, _, _, _, _, _), + [58] = PINGROUP(58, qup1_se6, _, _, _, _, _, _, _, _, _, _), + [59] = PINGROUP(59, qup1_se6, usb_phy, vsense_trigger_mirnat, _, _, _, _, _, _, _, _), + [60] = PINGROUP(60, qup1_se7, usb_phy, ibi_i3c, _, _, _, _, _, _, _, _), + [61] = PINGROUP(61, qup1_se7, ibi_i3c, _, _, _, _, _, _, _, _, _), + [62] = PINGROUP(62, qup1_se7, qdss_gpio_tracedata, _, _, _, _, _, _, _, _, _), + [63] = PINGROUP(63, qup1_se7, qdss_gpio_tracedata, _, _, _, _, _, _, _, _, _), + [64] = PINGROUP(64, qup3_se0, _, prng_rosc1, tmess_prng1, _, _, _, _, _, _, _), + [65] = PINGROUP(65, qup3_se0, _, prng_rosc2, tmess_prng2, _, _, _, _, _, _, _), + [66] = PINGROUP(66, i2chub0_se0, prng_rosc3, tmess_prng3, _, _, _, _, _, _, _, _), + [67] = PINGROUP(67, i2chub0_se0, _, _, _, _, _, _, _, _, _, _), + [68] = PINGROUP(68, i2chub0_se2, qdss_gpio_tracedata, _, _, _, _, _, _, _, _, _), + [69] = PINGROUP(69, i2chub0_se2, qdss_gpio_tracedata, _, _, _, _, _, _, _, _, _), + [70] = PINGROUP(70, i2chub0_se3, uim1_data, _, atest_usb, _, _, _, _, _, _, _), + [71] = PINGROUP(71, i2chub0_se3, uim1_clk, _, atest_usb, _, _, _, _, _, _, _), + [72] = PINGROUP(72, i2chub0_se4, uim1_reset, qdss_cti, _, atest_usb, _, _, _, _, _, _), + [73] = PINGROUP(73, i2chub0_se4, qdss_cti, jitter_bist, atest_usb, _, _, _, _, _, _, _), + [74] = PINGROUP(74, qup1_se1, aoss_cti, _, _, _, _, _, _, _, _, _), + [75] = PINGROUP(75, qup1_se1, aoss_cti, _, _, _, _, _, _, _, _, _), + [76] = PINGROUP(76, qup1_se1, aoss_cti, _, _, _, _, _, _, _, _, _), + [77] = PINGROUP(77, qup1_se1, aoss_cti, gnss_adc1, _, _, _, _, _, _, _, _), + [78] = PINGROUP(78, i2chub0_se1, _, _, _, _, _, _, _, _, _, _), + [79] = PINGROUP(79, i2chub0_se1, usb0_hs, _, _, _, _, _, _, _, _, _), + [80] = PINGROUP(80, qup1_se0, sdc40, qspi0, _, _, _, _, _, _, _, _), + [81] = PINGROUP(81, qup1_se0, sdc42, qspi2, _, _, _, _, _, _, _, _), + [82] = PINGROUP(82, qup1_se0, sdc43, qdss_cti, qspi3, _, _, _, _, _, _, _), + [83] = PINGROUP(83, qup1_se0, sdc4_clk, qdss_cti, qspi_clk, _, _, _, _, _, _, _), + [84] = PINGROUP(84, qup4_se3, _, _, _, _, _, _, _, _, _, _), + [85] = PINGROUP(85, sd_write_protect, prng_rosc0, tmess_prng0, _, _, _, _, _, _, _, _), + [86] = PINGROUP(86, mdp_vsync, mdp_vsync0_out, mdp_vsync1_out, gcc_gp2, _, _, _, _, _, _, + _), + [87] = PINGROUP(87, mdp_vsync, mdp_vsync2_out, mdp_vsync3_out, mdp_vsync5_out, gcc_gp3, _, + tsense_pwm1, _, _, _, _), + [88] = PINGROUP(88, mdp_vsync_e, mdp_esync0_out, tb_trig_sdc2, _, _, _, _, _, _, _, _), + [89] = PINGROUP(89, cam_mclk, _, _, _, _, _, _, _, _, _, _), + [90] = PINGROUP(90, cam_mclk, _, _, _, _, _, _, _, _, _, _), + [91] = PINGROUP(91, cam_asc_mclk2, _, _, _, _, _, _, _, _, _, _), + [92] = PINGROUP(92, cam_mclk, _, _, _, _, _, _, _, _, _, _), + [93] = PINGROUP(93, cam_asc_mclk4, _, _, _, _, _, _, _, _, _, _), + [94] = PINGROUP(94, cam_mclk, pll_clk_aux, _, _, _, _, _, _, _, _, _), + [95] = PINGROUP(95, cam_mclk, _, _, _, _, _, _, _, _, _, _), + [96] = PINGROUP(96, cam_mclk, _, _, _, _, _, _, _, _, _, _), + [97] = PINGROUP(97, mdp_vsync, tsense_pwm3, _, _, _, _, _, _, _, _, _), + [98] = PINGROUP(98, mdp_vsync, _, _, _, _, _, _, _, _, _, _), + [99] = PINGROUP(99, sys_throttle, tsense_pwm4, _, _, _, _, _, _, _, _, _), + [100] = PINGROUP(100, mdp_esync1_out, _, _, _, _, _, _, _, _, _, _), + [101] = PINGROUP(101, _, _, _, _, _, _, _, _, _, _, _), + [102] = PINGROUP(102, _, _, _, _, _, _, _, _, _, _, _), + [103] = PINGROUP(103, pcie0_clk_req_n, _, _, _, _, _, _, _, _, _, _), + [104] = PINGROUP(104, pll_bist_sync, _, _, _, _, _, _, _, _, _, _), + [105] = PINGROUP(105, cci_timer, tsense_pwm5, _, _, _, _, _, _, _, _, _), + [106] = PINGROUP(106, cci_timer, tsense_pwm6, _, _, _, _, _, _, _, _, _), + [107] = PINGROUP(107, cci_timer, cci_i2c_sda, _, _, _, _, _, _, _, _, _), + [108] = PINGROUP(108, cci_i2c_sda, _, _, _, _, _, _, _, _, _, _), + [109] = PINGROUP(109, cci_i2c_sda, _, _, _, _, _, _, _, _, _, _), + [110] = PINGROUP(110, cci_i2c_scl, _, _, _, _, _, _, _, _, _, _), + [111] = PINGROUP(111, cci_i2c_sda, _, _, _, _, _, _, _, _, _, _), + [112] = PINGROUP(112, cci_i2c_scl, _, _, _, _, _, _, _, _, _, _), + [113] = PINGROUP(113, cci_i2c_sda, _, _, _, _, _, _, _, _, _, _), + [114] = PINGROUP(114, cci_i2c_scl, _, _, _, _, _, _, _, _, _, _), + [115] = PINGROUP(115, cci_i2c_sda, _, _, _, _, _, _, _, _, _, _), + [116] = PINGROUP(116, cci_i2c_scl, _, _, _, _, _, _, _, _, _, _), + [117] = PINGROUP(117, i2s1_sck, qup2_se2, phase_flag, _, _, _, _, _, _, _, _), + [118] = PINGROUP(118, i2s1_data0, qup2_se2, phase_flag, _, _, _, _, _, _, _, _), + [119] = PINGROUP(119, i2s1_ws, qup2_se2, phase_flag, _, _, _, _, _, _, _, _), + [120] = PINGROUP(120, i2s1_data1, qup2_se2, audio_ext_mclk1, audio_ref_clk, _, _, _, _, _, + _, _), + [121] = PINGROUP(121, audio_ext_mclk0, qup4_se3, _, _, _, _, _, _, _, _, _), + [122] = PINGROUP(122, i2s0_sck, qup2_se3, _, _, _, _, _, _, _, _, _), + [123] = PINGROUP(123, i2s0_data0, qup2_se3, _, phase_flag, _, _, _, _, _, _, _), + [124] = PINGROUP(124, i2s0_data1, qup2_se3, _, phase_flag, _, _, _, _, _, _, _), + [125] = PINGROUP(125, i2s0_ws, qup2_se3, phase_flag, _, _, _, _, _, _, _, _), + [126] = PINGROUP(126, uim0_data, qdss_gpio_tracedata, atest_char, _, _, _, _, _, _, _, _), + [127] = PINGROUP(127, uim0_clk, qdss_gpio_tracectl, atest_char, _, _, _, _, _, _, _, _), + [128] = PINGROUP(128, uim0_reset, qdss_gpio_traceclk, atest_char, _, _, _, _, _, _, _, _), + [129] = PINGROUP(129, uim0_present, qdss_gpio_tracedata, atest_usb, atest_char, _, _, _, _, + _, _, _), + [130] = PINGROUP(130, uim1_data, qup1_se2, gcc_gp1, qdss_gpio_tracedata, _, _, _, _, _, _, + _), + [131] = PINGROUP(131, uim1_clk, qup1_se2, gcc_gp2, qdss_gpio_tracedata, _, _, _, _, _, _, + _), + [132] = PINGROUP(132, uim1_reset, qup1_se2, gcc_gp3, qdss_gpio_tracedata, _, _, _, _, _, _, + _), + [133] = PINGROUP(133, uim1_present, qdss_gpio_tracedata, atest_char, _, _, _, _, _, _, _, + _), + [134] = PINGROUP(134, _, _, _, _, _, _, _, _, _, _, _), + [135] = PINGROUP(135, _, _, _, _, _, _, _, _, _, _, _), + [136] = PINGROUP(136, _, _, _, _, _, _, _, _, _, _, _), + [137] = PINGROUP(137, _, _, _, _, _, _, _, _, _, _, _), + [138] = PINGROUP(138, _, _, _, _, _, _, _, _, _, _, _), + [139] = PINGROUP(139, _, _, _, _, _, _, _, _, _, _, _), + [140] = PINGROUP(140, _, _, _, _, _, _, _, _, _, _, _), + [141] = PINGROUP(141, _, _, _, _, _, _, _, _, _, _, _), + [142] = PINGROUP(142, _, _, _, _, _, _, _, _, _, _, _), + [143] = PINGROUP(143, _, _, _, _, _, _, _, _, _, _, _), + [144] = PINGROUP(144, coex_uart1_rx, cmu_rng, _, _, _, _, _, _, _, _, _), + [145] = PINGROUP(145, coex_uart1_tx, cmu_rng, _, _, _, _, _, _, _, _, _), + [146] = PINGROUP(146, _, vfr_0, coex_uart2_rx, cmu_rng, tb_trig_sdc4, qspi_cs, _, _, _, _, + _), + [147] = PINGROUP(147, _, coex_uart2_tx, cmu_rng, sdc41, qspi1, _, _, _, _, _, _), + [148] = PINGROUP(148, nav_gpio2, _, sdc4_cmd, qspi_cs, _, _, _, _, _, _, _), + [149] = PINGROUP(149, cci_i2c_scl, _, _, _, _, _, _, _, _, _, _), + [150] = PINGROUP(150, nav_gpio0, nav_gpio3, _, _, _, _, _, _, _, _, _), + [151] = PINGROUP(151, nav_gpio1, vfr_1, _, _, _, _, _, _, _, _, _), + [152] = PINGROUP(152, qlink_little_request, _, _, _, _, _, _, _, _, _, _), + [153] = PINGROUP(153, qlink_little_enable, _, _, _, _, _, _, _, _, _, _), + [154] = PINGROUP(154, qlink_wmss, _, _, _, _, _, _, _, _, _, _), + [155] = PINGROUP(155, qlink_big_request, qdss_cti, _, _, _, _, _, _, _, _, _), + [156] = PINGROUP(156, qlink_big_enable, _, _, _, _, _, _, _, _, _, _), + [157] = PINGROUP(157, _, _, _, _, _, _, _, _, _, _, _), + [158] = PINGROUP(158, qdss_cti, gcc_gp1, _, _, _, _, _, _, _, _, _), + [159] = PINGROUP(159, cci_timer, tsense_pwm7, _, _, _, _, _, _, _, _, _), + [160] = PINGROUP(160, cci_timer, cci_i2c_scl, _, _, _, _, _, _, _, _, _), + [161] = PINGROUP(161, qup4_se4, _, _, _, _, _, _, _, _, _, _), + [162] = PINGROUP(162, qup4_se4, _, _, _, _, _, _, _, _, _, _), + [163] = PINGROUP(163, _, _, _, _, _, _, _, _, _, _, egpio), + [164] = PINGROUP(164, _, _, _, _, _, _, _, _, _, _, egpio), + [165] = PINGROUP(165, _, _, _, _, _, _, _, _, _, _, egpio), + [166] = PINGROUP(166, _, _, _, _, _, _, _, _, _, _, egpio), + [167] = PINGROUP(167, _, _, _, _, _, _, _, _, _, _, egpio), + [168] = PINGROUP(168, _, _, _, _, _, _, _, _, _, _, egpio), + [169] = PINGROUP(169, phase_flag, _, _, _, _, _, _, _, _, _, egpio), + [170] = PINGROUP(170, phase_flag, _, _, _, _, _, _, _, _, _, egpio), + [171] = PINGROUP(171, phase_flag, _, _, _, _, _, _, _, _, _, egpio), + [172] = PINGROUP(172, phase_flag, _, _, _, _, _, _, _, _, _, egpio), + [173] = PINGROUP(173, phase_flag, _, _, _, _, _, _, _, _, _, egpio), + [174] = PINGROUP(174, _, _, _, _, _, _, _, _, _, _, egpio), + [175] = PINGROUP(175, phase_flag, _, _, _, _, _, _, _, _, _, egpio), + [176] = PINGROUP(176, phase_flag, _, _, _, _, _, _, _, _, _, egpio), + [177] = PINGROUP(177, _, _, _, _, _, _, _, _, _, _, egpio), + [178] = PINGROUP(178, _, _, _, _, _, _, _, _, _, _, egpio), + [179] = PINGROUP(179, phase_flag, _, _, _, _, _, _, _, _, _, egpio), + [180] = PINGROUP(180, phase_flag, _, _, _, _, _, _, _, _, _, egpio), + [181] = PINGROUP(181, phase_flag, _, _, _, _, _, _, _, _, _, egpio), + [182] = PINGROUP(182, _, _, _, _, _, _, _, _, _, _, egpio), + [183] = PINGROUP(183, _, _, _, _, _, _, _, _, _, _, egpio), + [184] = PINGROUP(184, phase_flag, _, _, _, _, _, _, _, _, _, egpio), + [185] = PINGROUP(185, phase_flag, _, _, _, _, _, _, _, _, _, egpio), + [186] = PINGROUP(186, _, _, _, _, _, _, _, _, _, _, egpio), + [187] = PINGROUP(187, _, _, _, _, _, _, _, _, _, _, egpio), + [188] = PINGROUP(188, _, _, _, _, _, _, _, _, _, _, egpio), + [189] = PINGROUP(189, _, _, _, _, _, _, _, _, _, _, egpio), + [190] = PINGROUP(190, _, _, _, _, _, _, _, _, _, _, egpio), + [191] = PINGROUP(191, _, _, _, _, _, _, _, _, _, _, egpio), + [192] = PINGROUP(192, phase_flag, _, _, _, _, _, _, _, _, _, egpio), + [193] = PINGROUP(193, _, _, _, _, _, _, _, _, _, _, egpio), + [194] = PINGROUP(194, _, _, _, _, _, _, _, _, _, _, egpio), + [195] = PINGROUP(195, _, _, _, _, _, _, _, _, _, _, egpio), + [196] = PINGROUP(196, phase_flag, _, _, _, _, _, _, _, _, _, egpio), + [197] = PINGROUP(197, phase_flag, _, _, _, _, _, _, _, _, _, egpio), + [198] = PINGROUP(198, phase_flag, _, _, _, _, _, _, _, _, _, egpio), + [199] = PINGROUP(199, phase_flag, _, _, _, _, _, _, _, _, _, egpio), + [200] = PINGROUP(200, _, _, _, _, _, _, _, _, _, _, egpio), + [201] = PINGROUP(201, _, _, _, _, _, _, _, _, _, _, egpio), + [202] = PINGROUP(202, _, _, _, _, _, _, _, _, _, _, egpio), + [203] = PINGROUP(203, _, _, _, _, _, _, _, _, _, _, egpio), + [204] = PINGROUP(204, phase_flag, _, _, _, _, _, _, _, _, _, egpio), + [205] = PINGROUP(205, _, _, _, _, _, _, _, _, _, _, egpio), + [206] = PINGROUP(206, phase_flag, _, _, _, _, _, _, _, _, _, egpio), + [207] = PINGROUP(207, phase_flag, _, _, _, _, _, _, _, _, _, egpio), + [208] = PINGROUP(208, qup2_se4, _, phase_flag, _, _, _, _, _, _, _, egpio), + [209] = PINGROUP(209, qup2_se4, _, _, _, _, _, _, _, _, _, egpio), + [210] = PINGROUP(210, phase_flag, _, _, _, _, _, _, _, _, _, egpio), + [211] = PINGROUP(211, phase_flag, _, _, _, _, _, _, _, _, _, egpio), + [212] = PINGROUP(212, _, _, _, _, _, _, _, _, _, _, egpio), + [213] = PINGROUP(213, _, _, _, _, _, _, _, _, _, _, egpio), + [214] = PINGROUP(214, phase_flag, _, _, _, _, _, _, _, _, _, egpio), + [215] = PINGROUP(215, phase_flag, _, _, _, _, _, _, _, _, _, egpio), + [216] = PINGROUP(216, phase_flag, _, _, _, _, _, _, _, _, _, egpio), + [217] = UFS_RESET(ufs_reset, 0xe8004, 0xe9000), + [218] = SDC_QDSD_PINGROUP(sdc2_clk, 0xdd000, 14, 6), + [219] = SDC_QDSD_PINGROUP(sdc2_cmd, 0xdd000, 11, 3), + [220] = SDC_QDSD_PINGROUP(sdc2_data, 0xdd000, 9, 0), +}; + +static const struct msm_gpio_wakeirq_map kaanapali_pdc_map[] = { + { 0, 89 }, { 3, 97 }, { 4, 90 }, { 7, 91 }, { 8, 92 }, { 11, 93 }, + { 12, 101 }, { 15, 115 }, { 17, 125 }, { 18, 127 }, { 19, 96 }, { 23, 99 }, + { 24, 100 }, { 27, 102 }, { 28, 103 }, { 31, 111 }, { 32, 109 }, { 35, 85 }, + { 36, 110 }, { 39, 112 }, { 43, 113 }, { 47, 138 }, { 48, 114 }, { 51, 98 }, + { 55, 88 }, { 57, 120 }, { 59, 121 }, { 60, 122 }, { 63, 108 }, { 64, 94 }, + { 65, 107 }, { 67, 116 }, { 68, 129 }, { 69, 130 }, { 75, 135 }, { 77, 123 }, + { 78, 119 }, { 79, 131 }, { 80, 139 }, { 81, 132 }, { 84, 118 }, { 85, 133 }, + { 86, 140 }, { 87, 141 }, { 88, 142 }, { 95, 143 }, { 96, 144 }, { 97, 117 }, + { 98, 134 }, { 99, 95 }, { 101, 145 }, { 102, 146 }, { 103, 147 }, { 104, 148 }, + { 120, 149 }, { 125, 150 }, { 129, 137 }, { 133, 84 }, { 144, 151 }, { 146, 152 }, + { 151, 153 }, { 152, 154 }, { 155, 106 }, { 158, 104 }, { 162, 126 }, { 164, 155 }, + { 167, 156 }, { 169, 157 }, { 170, 158 }, { 172, 159 }, { 174, 160 }, { 175, 161 }, + { 179, 162 }, { 180, 163 }, { 183, 164 }, { 186, 165 }, { 188, 128 }, { 189, 166 }, + { 190, 105 }, { 191, 167 }, { 194, 168 }, { 195, 169 }, { 196, 170 }, { 197, 171 }, + { 199, 136 }, { 200, 86 }, { 201, 172 }, { 202, 173 }, { 203, 174 }, { 205, 124 }, + { 209, 175 }, { 213, 87 }, { 216, 176 }, +}; + +static const struct msm_pinctrl_soc_data kaanapali_tlmm = { + .pins = kaanapali_pins, + .npins = ARRAY_SIZE(kaanapali_pins), + .functions = kaanapali_functions, + .nfunctions = ARRAY_SIZE(kaanapali_functions), + .groups = kaanapali_groups, + .ngroups = ARRAY_SIZE(kaanapali_groups), + .ngpios = 218, + .wakeirq_map = kaanapali_pdc_map, + .nwakeirq_map = ARRAY_SIZE(kaanapali_pdc_map), + .egpio_func = 11, +}; + +static int kaanapali_tlmm_probe(struct platform_device *pdev) +{ + return msm_pinctrl_probe(pdev, &kaanapali_tlmm); +} + +static const struct of_device_id kaanapali_tlmm_of_match[] = { + { .compatible = "qcom,kaanapali-tlmm",}, + {}, +}; + +static struct platform_driver kaanapali_tlmm_driver = { + .driver = { + .name = "kaanapali-tlmm", + .of_match_table = kaanapali_tlmm_of_match, + }, + .probe = kaanapali_tlmm_probe, +}; + +static int __init kaanapali_tlmm_init(void) +{ + return platform_driver_register(&kaanapali_tlmm_driver); +} +arch_initcall(kaanapali_tlmm_init); + +static void __exit kaanapali_tlmm_exit(void) +{ + platform_driver_unregister(&kaanapali_tlmm_driver); +} +module_exit(kaanapali_tlmm_exit); + +MODULE_DESCRIPTION("QTI Kaanapali TLMM driver"); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(of, kaanapali_tlmm_of_match); From 9a297f4d9e88c69bd9a650364126da4d2dbb658f Mon Sep 17 00:00:00 2001 From: Jingyi Wang Date: Wed, 24 Sep 2025 16:16:03 -0700 Subject: [PATCH 0064/2333] FROMGIT: dt-bindings: pinctrl: describe Kaanapali TLMM The Top Level Mode Multiplexer (TLMM) in the Kaanapali SoC provide GPIO and pinctrl functionality for UFS, SDC and 217 GPIO pins. Add a DeviceTree binding to describe the Kaanapali TLMM block. Signed-off-by: Jingyi Wang Reviewed-by: Krzysztof Kozlowski Reviewed-by: Bjorn Andersson Signed-off-by: Yijie Yang Link: https://lore.kernel.org/all/20250924-knp-tlmm-v1-1-acabb59ae48c@oss.qualcomm.com/ --- .../bindings/pinctrl/qcom,kaanapali-tlmm.yaml | 127 ++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100644 Documentation/devicetree/bindings/pinctrl/qcom,kaanapali-tlmm.yaml diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,kaanapali-tlmm.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,kaanapali-tlmm.yaml new file mode 100644 index 0000000000000..53534a07a1f0e --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/qcom,kaanapali-tlmm.yaml @@ -0,0 +1,127 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/pinctrl/qcom,kaanapali-tlmm.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm Technologies, Inc. Kaanapali TLMM block + +maintainers: + - Jingyi Wang + +description: + Top Level Mode Multiplexer pin controller in Qualcomm Kaanapali SoC. + +allOf: + - $ref: /schemas/pinctrl/qcom,tlmm-common.yaml# + +properties: + compatible: + const: qcom,kaanapali-tlmm + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + gpio-reserved-ranges: + minItems: 1 + maxItems: 109 + + gpio-line-names: + maxItems: 217 + +patternProperties: + "-state$": + oneOf: + - $ref: "#/$defs/qcom-kaanapali-tlmm-state" + - patternProperties: + "-pins$": + $ref: "#/$defs/qcom-kaanapali-tlmm-state" + additionalProperties: false + +$defs: + qcom-kaanapali-tlmm-state: + type: object + description: + Pinctrl node's client devices use subnodes for desired pin configuration. + Client device subnodes use below standard properties. + $ref: qcom,tlmm-common.yaml#/$defs/qcom-tlmm-state + unevaluatedProperties: false + + properties: + pins: + description: + List of gpio pins affected by the properties specified in this + subnode. + items: + oneOf: + - pattern: "^gpio([0-9]|[1-9][0-9]|1[0-9][0-9]|20[0-9]|21[0-6])$" + - enum: [ ufs_reset, sdc2_clk, sdc2_cmd, sdc2_data ] + minItems: 1 + maxItems: 36 + + function: + description: + Specify the alternative function to be configured for the specified + pins. + enum: [ gpio, aoss_cti, atest_char, atest_usb, audio_ext_mclk0, + audio_ext_mclk1, audio_ref_clk, cam_asc_mclk2, cam_asc_mclk4, + cam_mclk, cci_async_in, cci_i2c_scl, cci_i2c_sda, cci_timer, + cmu_rng, coex_uart1_rx, coex_uart1_tx, coex_uart2_rx, + coex_uart2_tx, dbg_out_clk, ddr_bist_complete, ddr_bist_fail, + ddr_bist_start, ddr_bist_stop, ddr_pxi0, ddr_pxi1, ddr_pxi2, + ddr_pxi3, dp_hot, egpio, gcc_gp1, gcc_gp2, gcc_gp3, gnss_adc0, + gnss_adc1, i2chub0_se0, i2chub0_se1, i2chub0_se2, i2chub0_se3, + i2chub0_se4, i2s0_data0, i2s0_data1, i2s0_sck, i2s0_ws, + i2s1_data0, i2s1_data1, i2s1_sck, i2s1_ws, ibi_i3c, jitter_bist, + mdp_esync0_out, mdp_esync1_out, mdp_vsync, mdp_vsync0_out, + mdp_vsync1_out, mdp_vsync2_out, mdp_vsync3_out, mdp_vsync5_out, + mdp_vsync_e, nav_gpio0, nav_gpio1, nav_gpio2, nav_gpio3, + pcie0_clk_req_n, phase_flag, pll_bist_sync, pll_clk_aux, + prng_rosc0, prng_rosc1, prng_rosc2, prng_rosc3, qdss_cti, + qdss_gpio_traceclk, qdss_gpio_tracectl, qdss_gpio_tracedata, + qlink_big_enable, qlink_big_request, qlink_little_enable, + qlink_little_request, qlink_wmss, qspi0, qspi1, qspi2, qspi3, + qspi_clk, qspi_cs, qup1_se0, qup1_se1, qup1_se2, qup1_se3, + qup1_se4, qup1_se5, qup1_se6, qup1_se7, qup2_se0, qup2_se1, + qup2_se2, qup2_se3, qup2_se4, qup3_se0, qup3_se1, qup3_se2, + qup3_se3, qup3_se4, qup3_se5, qup4_se0, qup4_se1, qup4_se2, + qup4_se3, qup4_se4, sd_write_protect, sdc40, sdc41, sdc42, sdc43, + sdc4_clk, sdc4_cmd, sys_throttle, tb_trig_sdc2, tb_trig_sdc4, + tmess_prng0, tmess_prng1, tmess_prng2, tmess_prng3, tsense_pwm1, + tsense_pwm2, tsense_pwm3, tsense_pwm4, tsense_pwm5, tsense_pwm6, + tsense_pwm7, uim0_clk, uim0_data, uim0_present, uim0_reset, uim1_clk, + uim1_data, uim1_present, uim1_reset, usb0_hs, usb_phy, vfr_0, vfr_1, + vsense_trigger_mirnat, wcn_sw, wcn_sw_ctrl ] + + required: + - pins + +required: + - compatible + - reg + +unevaluatedProperties: false + +examples: + - | + #include + + tlmm: pinctrl@f100000 { + compatible = "qcom,kaanapali-tlmm"; + reg = <0x0f100000 0x300000>; + interrupts = ; + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&tlmm 0 0 218>; + interrupt-controller; + #interrupt-cells = <2>; + + qup-uart7-state { + pins = "gpio62", "gpio63"; + function = "qup1_se7"; + }; + }; +... From 2ea01e7aff318d107c569a77d074a39cd46ba3ec Mon Sep 17 00:00:00 2001 From: Songwei Chai Date: Wed, 9 Jul 2025 03:41:08 -0700 Subject: [PATCH 0065/2333] FROMLIST: dt-bindings: arm: Add support for Coresight TGU trace The Trigger Generation Unit (TGU) is designed to detect patterns or sequences within a specific region of the System on Chip (SoC). Once configured and activated, it monitors sense inputs and can detect a pre-programmed state or sequence across clock cycles, subsequently producing a trigger. TGU configuration space offset table x-------------------------x | | | | | | Step configuration | | space layout | coresight management | x-------------x | registers | |---> | | | | | | reserve | | | | | | |-------------------------| | |-------------| | | | | priority[3] | | step[7] |<-- | |-------------| |-------------------------| | | | priority[2] | | | | | |-------------| | ... | |Steps region | | priority[1] | | | | | |-------------| |-------------------------| | | | priority[0] | | |<-- | |-------------| | step[0] |--------------------> | | |-------------------------| | condition | | | | | | control and status | x-------------x | space | | | x-------------------------x |Timer/Counter| | | x-------------x TGU Configuration in Hardware The TGU provides a step region for user configuration, similar to a flow chart. Each step region consists of three register clusters: 1.Priority Region: Sets the required signals with priority. 2.Condition Region: Defines specific requirements (e.g., signal A reaches three times) and the subsequent action once the requirement is met. 3.Timer/Counter (Optional): Provides timing or counting functionality. Add a new coresight-tgu.yaml file to describe the bindings required to define the TGU in the device trees. Link: https://lore.kernel.org/all/20250709104114.22240-2-songchai@qti.qualcomm.com/ Signed-off-by: Songwei Chai Reviewed-by: Rob Herring (Arm) --- .../bindings/arm/qcom,coresight-tgu.yaml | 92 +++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 Documentation/devicetree/bindings/arm/qcom,coresight-tgu.yaml diff --git a/Documentation/devicetree/bindings/arm/qcom,coresight-tgu.yaml b/Documentation/devicetree/bindings/arm/qcom,coresight-tgu.yaml new file mode 100644 index 0000000000000..3576d38711261 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/qcom,coresight-tgu.yaml @@ -0,0 +1,92 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +# Copyright (c) 2025 Qualcomm Innovation Center, Inc. All rights reserved. +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/arm/qcom,coresight-tgu.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Trigger Generation Unit - TGU + +description: | + The Trigger Generation Unit (TGU) is a Data Engine which can be utilized + to sense a plurality of signals and create a trigger into the CTI or + generate interrupts to processors. The TGU is like the trigger circuit + of a Logic Analyzer. The corresponding trigger logic can be realized by + configuring the conditions for each step after sensing the signal. + Once setup and enabled, it will observe sense inputs and based upon + the activity of those inputs, even over clock cycles, may detect a + preprogrammed state/sequence and then produce a trigger or interrupt. + + The primary use case of the TGU is to detect patterns or sequences on a + given set of signals within some region to indentify the issue in time + once there is abnormal behavior in the subsystem. + +maintainers: + - Mao Jinlong + - Sam Chai + +# Need a custom select here or 'arm,primecell' will match on lots of nodes +select: + properties: + compatible: + contains: + enum: + - qcom,coresight-tgu + required: + - compatible + +properties: + compatible: + items: + - const: qcom,coresight-tgu + - const: arm,primecell + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + + clock-names: + items: + - const: apb_pclk + + in-ports: + $ref: /schemas/graph.yaml#/properties/ports + additionalProperties: false + + properties: + port: + description: + The port mechanism here ensures the relationship between TGU and + TPDM, as TPDM is one of the inputs for TGU. It will allow TGU to + function as TPDM's helper and enable TGU when the connected + TPDM is enabled. + $ref: /schemas/graph.yaml#/properties/port + +required: + - compatible + - reg + - clocks + - clock-names + +additionalProperties: false + +examples: + - | + tgu@10b0e000 { + compatible = "qcom,coresight-tgu", "arm,primecell"; + reg = <0x10b0e000 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + + in-ports { + port { + tgu_in_tpdm_swao: endpoint{ + remote-endpoint = <&tpdm_swao_out_tgu>; + }; + }; + }; + }; +... From 9584fedeeac26274c52def10c0771050527c1a0b Mon Sep 17 00:00:00 2001 From: Songwei Chai Date: Wed, 9 Jul 2025 03:41:09 -0700 Subject: [PATCH 0066/2333] FROMLIST: coresight: Add coresight TGU driver Add driver to support Coresight device TGU (Trigger Generation Unit). TGU is a Data Engine which can be utilized to sense a plurality of signals and create a trigger into the CTI or generate interrupts to processors. Add probe/enable/disable functions for tgu. Link: https://lore.kernel.org/all/20250709104114.22240-3-songchai@qti.qualcomm.com/ Signed-off-by: Songwei Chai --- .../testing/sysfs-bus-coresight-devices-tgu | 9 + drivers/hwtracing/coresight/Kconfig | 11 + drivers/hwtracing/coresight/Makefile | 1 + drivers/hwtracing/coresight/coresight-tgu.c | 209 ++++++++++++++++++ drivers/hwtracing/coresight/coresight-tgu.h | 37 ++++ 5 files changed, 267 insertions(+) create mode 100644 Documentation/ABI/testing/sysfs-bus-coresight-devices-tgu create mode 100644 drivers/hwtracing/coresight/coresight-tgu.c create mode 100644 drivers/hwtracing/coresight/coresight-tgu.h diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tgu b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tgu new file mode 100644 index 0000000000000..31553776f037c --- /dev/null +++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tgu @@ -0,0 +1,9 @@ +What: /sys/bus/coresight/devices//enable_tgu +Date: July 2025 +KernelVersion 6.16 +Contact: Jinlong Mao (QUIC) , Songwei Chai (QUIC) +Description: + (RW) Set/Get the enable/disable status of TGU + Accepts only one of the 2 values - 0 or 1. + 0 : disable TGU. + 1 : enable TGU. diff --git a/drivers/hwtracing/coresight/Kconfig b/drivers/hwtracing/coresight/Kconfig index 6a4239ebb582e..5b0974e0e942b 100644 --- a/drivers/hwtracing/coresight/Kconfig +++ b/drivers/hwtracing/coresight/Kconfig @@ -20,6 +20,17 @@ menuconfig CORESIGHT module will be called coresight. if CORESIGHT +config CORESIGHT_TGU + tristate "CoreSight Trigger Generation Unit driver" + help + This driver provides support for Trigger Generation Unit that is + used to detect patterns or sequences on a given set of signals. + TGU is used to monitor a particular bus within a given region to + detect illegal transaction sequences or slave responses. It is also + used to monitor a data stream to detect protocol violations and to + provide a trigger point for centering data around a specific event + within the trace data buffer. + config CORESIGHT_LINKS_AND_SINKS tristate "CoreSight Link and Sink drivers" help diff --git a/drivers/hwtracing/coresight/Makefile b/drivers/hwtracing/coresight/Makefile index ab16d06783a57..a40c8bbb8c323 100644 --- a/drivers/hwtracing/coresight/Makefile +++ b/drivers/hwtracing/coresight/Makefile @@ -54,6 +54,7 @@ coresight-cti-y := coresight-cti-core.o coresight-cti-platform.o \ coresight-cti-sysfs.o obj-$(CONFIG_ULTRASOC_SMB) += ultrasoc-smb.o obj-$(CONFIG_CORESIGHT_DUMMY) += coresight-dummy.o +obj-$(CONFIG_CORESIGHT_TGU) += coresight-tgu.o obj-$(CONFIG_CORESIGHT_CTCU) += coresight-ctcu.o coresight-ctcu-y := coresight-ctcu-core.o obj-$(CONFIG_CORESIGHT_KUNIT_TESTS) += coresight-kunit-tests.o diff --git a/drivers/hwtracing/coresight/coresight-tgu.c b/drivers/hwtracing/coresight/coresight-tgu.c new file mode 100644 index 0000000000000..1d237d14d3c91 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-tgu.c @@ -0,0 +1,209 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2024-2025 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "coresight-priv.h" +#include "coresight-tgu.h" + +DEFINE_CORESIGHT_DEVLIST(tgu_devs, "tgu"); + +static void tgu_write_all_hw_regs(struct tgu_drvdata *drvdata) +{ + CS_UNLOCK(drvdata->base); + /* Enable TGU to program the triggers */ + tgu_writel(drvdata, 1, TGU_CONTROL); + CS_LOCK(drvdata->base); +} + +static int tgu_enable(struct coresight_device *csdev, enum cs_mode mode, + void *data) +{ + struct tgu_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); + + guard(spinlock)(&drvdata->spinlock); + if (drvdata->enable) + return -EBUSY; + + tgu_write_all_hw_regs(drvdata); + drvdata->enable = true; + + return 0; +} + +static int tgu_disable(struct coresight_device *csdev, void *data) +{ + struct tgu_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); + + spin_lock(&drvdata->spinlock); + if (drvdata->enable) { + CS_UNLOCK(drvdata->base); + tgu_writel(drvdata, 0, TGU_CONTROL); + CS_LOCK(drvdata->base); + + drvdata->enable = false; + } + spin_unlock(&drvdata->spinlock); + return 0; +} + +static ssize_t enable_tgu_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + bool enabled; + struct tgu_drvdata *drvdata = dev_get_drvdata(dev->parent); + + spin_lock(&drvdata->spinlock); + enabled = drvdata->enable; + spin_unlock(&drvdata->spinlock); + + return sysfs_emit(buf, "%d\n", enabled); +} + +/* enable_tgu_store - Configure Trace and Gating Unit (TGU) triggers. */ +static ssize_t enable_tgu_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t size) +{ + int ret = 0; + unsigned long val; + struct tgu_drvdata *drvdata = dev_get_drvdata(dev->parent); + + ret = kstrtoul(buf, 0, &val); + if (ret) + return ret; + + if (val) { + ret = pm_runtime_resume_and_get(dev->parent); + if (ret) + return ret; + ret = tgu_enable(drvdata->csdev, CS_MODE_SYSFS, NULL); + if (ret) + pm_runtime_put(dev->parent); + } else { + ret = tgu_disable(drvdata->csdev, NULL); + pm_runtime_put(dev->parent); + } + + if (ret) + return ret; + return size; +} +static DEVICE_ATTR_RW(enable_tgu); + +static const struct coresight_ops_helper tgu_helper_ops = { + .enable = tgu_enable, + .disable = tgu_disable, +}; + +static const struct coresight_ops tgu_ops = { + .helper_ops = &tgu_helper_ops, +}; + +static struct attribute *tgu_common_attrs[] = { + &dev_attr_enable_tgu.attr, + NULL, +}; + +static const struct attribute_group tgu_common_grp = { + .attrs = tgu_common_attrs, + { NULL }, +}; + +static const struct attribute_group *tgu_attr_groups[] = { + &tgu_common_grp, + NULL, +}; + +static int tgu_probe(struct amba_device *adev, const struct amba_id *id) +{ + int ret = 0; + struct device *dev = &adev->dev; + struct coresight_desc desc = { 0 }; + struct coresight_platform_data *pdata; + struct tgu_drvdata *drvdata; + + desc.name = coresight_alloc_device_name(&tgu_devs, dev); + if (!desc.name) + return -ENOMEM; + + pdata = coresight_get_platform_data(dev); + if (IS_ERR(pdata)) + return PTR_ERR(pdata); + + adev->dev.platform_data = pdata; + + drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL); + if (!drvdata) + return -ENOMEM; + + drvdata->dev = &adev->dev; + dev_set_drvdata(dev, drvdata); + + drvdata->base = devm_ioremap_resource(dev, &adev->res); + if (!drvdata->base) + return -ENOMEM; + + spin_lock_init(&drvdata->spinlock); + + drvdata->enable = false; + desc.type = CORESIGHT_DEV_TYPE_HELPER; + desc.pdata = adev->dev.platform_data; + desc.dev = &adev->dev; + desc.ops = &tgu_ops; + desc.groups = tgu_attr_groups; + + drvdata->csdev = coresight_register(&desc); + if (IS_ERR(drvdata->csdev)) { + ret = PTR_ERR(drvdata->csdev); + goto err; + } + + pm_runtime_put(&adev->dev); + return 0; +err: + pm_runtime_put(&adev->dev); + return ret; +} + +static void tgu_remove(struct amba_device *adev) +{ + struct tgu_drvdata *drvdata = dev_get_drvdata(&adev->dev); + + coresight_unregister(drvdata->csdev); +} + +static const struct amba_id tgu_ids[] = { + { + .id = 0x000f0e00, + .mask = 0x000fffff, + .data = "TGU", + }, + { 0, 0, NULL }, +}; + +MODULE_DEVICE_TABLE(amba, tgu_ids); + +static struct amba_driver tgu_driver = { + .drv = { + .name = "coresight-tgu", + .suppress_bind_attrs = true, + }, + .probe = tgu_probe, + .remove = tgu_remove, + .id_table = tgu_ids, +}; + +module_amba_driver(tgu_driver); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("CoreSight TGU driver"); diff --git a/drivers/hwtracing/coresight/coresight-tgu.h b/drivers/hwtracing/coresight/coresight-tgu.h new file mode 100644 index 0000000000000..6c849a2f78faf --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-tgu.h @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2024-2025 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef _CORESIGHT_TGU_H +#define _CORESIGHT_TGU_H + +/* Register addresses */ +#define TGU_CONTROL 0x0000 + +/* Register read/write */ +#define tgu_writel(drvdata, val, off) __raw_writel((val), drvdata->base + off) +#define tgu_readl(drvdata, off) __raw_readl(drvdata->base + off) + +/** + * struct tgu_drvdata - Data structure for a TGU (Trigger Generator Unit) + * @base: Memory-mapped base address of the TGU device + * @dev: Pointer to the associated device structure + * @csdev: Pointer to the associated coresight device + * @spinlock: Spinlock for handling concurrent access + * @enable: Flag indicating whether the TGU device is enabled + * + * This structure defines the data associated with a TGU device, + * including its base address, device pointers, clock, spinlock for + * synchronization, trigger data pointers, maximum limits for various + * trigger-related parameters, and enable status. + */ +struct tgu_drvdata { + void __iomem *base; + struct device *dev; + struct coresight_device *csdev; + spinlock_t spinlock; + bool enable; +}; + +#endif From 2e7b6a1c32c846d7e02cea801c40e3b7e2d23c44 Mon Sep 17 00:00:00 2001 From: Songwei Chai Date: Wed, 9 Jul 2025 03:41:10 -0700 Subject: [PATCH 0067/2333] FROMLIST: coresight-tgu: Add signal priority support Like circuit of a Logic analyzer, in TGU, the requirement could be configured in each step and the trigger will be created once the requirements are met. Add priority functionality here to sort the signals into different priorities. The signal which is wanted could be configured in each step's priority node, the larger number means the higher priority and the signal with higher priority will be sensed more preferentially. Link: https://lore.kernel.org/all/20250709104114.22240-4-songchai@qti.qualcomm.com/ Signed-off-by: Songwei Chai --- .../testing/sysfs-bus-coresight-devices-tgu | 7 + drivers/hwtracing/coresight/coresight-tgu.c | 163 ++++++++++++++++++ drivers/hwtracing/coresight/coresight-tgu.h | 111 ++++++++++++ 3 files changed, 281 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tgu b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tgu index 31553776f037c..4132f5912308d 100644 --- a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tgu +++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tgu @@ -7,3 +7,10 @@ Description: Accepts only one of the 2 values - 0 or 1. 0 : disable TGU. 1 : enable TGU. + +What: /sys/bus/coresight/devices//step[0:7]_priority[0:3]/reg[0:17] +Date: July 2025 +KernelVersion 6.16 +Contact: Jinlong Mao (QUIC) , Songwei Chai (QUIC) +Description: + (RW) Set/Get the sensed signal with specific step and priority for TGU. diff --git a/drivers/hwtracing/coresight/coresight-tgu.c b/drivers/hwtracing/coresight/coresight-tgu.c index 1d237d14d3c91..901409bef2c57 100644 --- a/drivers/hwtracing/coresight/coresight-tgu.c +++ b/drivers/hwtracing/coresight/coresight-tgu.c @@ -17,14 +17,128 @@ DEFINE_CORESIGHT_DEVLIST(tgu_devs, "tgu"); +static int calculate_array_location(struct tgu_drvdata *drvdata, + int step_index, int operation_index, + int reg_index) +{ + int ret; + + ret = operation_index * (drvdata->max_step) * + (drvdata->max_reg) + + step_index * (drvdata->max_reg) + reg_index; + + return ret; +} + +static ssize_t tgu_dataset_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct tgu_drvdata *drvdata = dev_get_drvdata(dev->parent); + struct tgu_attribute *tgu_attr = + container_of(attr, struct tgu_attribute, attr); + + return sysfs_emit(buf, "0x%x\n", + drvdata->value_table->priority[ + calculate_array_location( + drvdata, tgu_attr->step_index, + tgu_attr->operation_index, + tgu_attr->reg_num)]); +} + +static ssize_t tgu_dataset_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + unsigned long val; + + struct tgu_drvdata *tgu_drvdata = dev_get_drvdata(dev->parent); + struct tgu_attribute *tgu_attr = + container_of(attr, struct tgu_attribute, attr); + + if (kstrtoul(buf, 0, &val)) + return -EINVAL; + + guard(spinlock)(&tgu_drvdata->spinlock); + tgu_drvdata->value_table->priority[calculate_array_location( + tgu_drvdata, tgu_attr->step_index, tgu_attr->operation_index, + tgu_attr->reg_num)] = val; + + return size; +} + +static umode_t tgu_node_visible(struct kobject *kobject, + struct attribute *attr, + int n) +{ + struct device *dev = kobj_to_dev(kobject); + struct tgu_drvdata *drvdata = dev_get_drvdata(dev->parent); + int ret = SYSFS_GROUP_INVISIBLE; + + struct device_attribute *dev_attr = + container_of(attr, struct device_attribute, attr); + struct tgu_attribute *tgu_attr = + container_of(dev_attr, struct tgu_attribute, attr); + + if (tgu_attr->step_index < drvdata->max_step) { + ret = (tgu_attr->reg_num < drvdata->max_reg) ? + attr->mode : + 0; + } + return ret; +} + static void tgu_write_all_hw_regs(struct tgu_drvdata *drvdata) { + int i, j, k; + CS_UNLOCK(drvdata->base); + + for (i = 0; i < drvdata->max_step; i++) { + for (j = 0; j < MAX_PRIORITY; j++) { + for (k = 0; k < drvdata->max_reg; k++) { + tgu_writel(drvdata, + drvdata->value_table->priority + [calculate_array_location( + drvdata, i, j, k)], + PRIORITY_REG_STEP(i, j, k)); + } + } + } + /* Enable TGU to program the triggers */ tgu_writel(drvdata, 1, TGU_CONTROL); CS_LOCK(drvdata->base); } +static void tgu_set_reg_number(struct tgu_drvdata *drvdata) +{ + int num_sense_input; + int num_reg; + u32 devid; + + devid = readl_relaxed(drvdata->base + CORESIGHT_DEVID); + + num_sense_input = TGU_DEVID_SENSE_INPUT(devid); + if (((num_sense_input * NUMBER_BITS_EACH_SIGNAL) % LENGTH_REGISTER) == 0) + num_reg = (num_sense_input * NUMBER_BITS_EACH_SIGNAL) / LENGTH_REGISTER; + else + num_reg = ((num_sense_input * NUMBER_BITS_EACH_SIGNAL) / LENGTH_REGISTER) + 1; + drvdata->max_reg = num_reg; +} + +static void tgu_set_steps(struct tgu_drvdata *drvdata) +{ + int num_steps; + u32 devid; + + devid = readl_relaxed(drvdata->base + CORESIGHT_DEVID); + + num_steps = TGU_DEVID_STEPS(devid); + + drvdata->max_step = num_steps; +} + static int tgu_enable(struct coresight_device *csdev, enum cs_mode mode, void *data) { @@ -121,6 +235,38 @@ static const struct attribute_group tgu_common_grp = { static const struct attribute_group *tgu_attr_groups[] = { &tgu_common_grp, + PRIORITY_ATTRIBUTE_GROUP_INIT(0, 0), + PRIORITY_ATTRIBUTE_GROUP_INIT(0, 1), + PRIORITY_ATTRIBUTE_GROUP_INIT(0, 2), + PRIORITY_ATTRIBUTE_GROUP_INIT(0, 3), + PRIORITY_ATTRIBUTE_GROUP_INIT(1, 0), + PRIORITY_ATTRIBUTE_GROUP_INIT(1, 1), + PRIORITY_ATTRIBUTE_GROUP_INIT(1, 2), + PRIORITY_ATTRIBUTE_GROUP_INIT(1, 3), + PRIORITY_ATTRIBUTE_GROUP_INIT(2, 0), + PRIORITY_ATTRIBUTE_GROUP_INIT(2, 1), + PRIORITY_ATTRIBUTE_GROUP_INIT(2, 2), + PRIORITY_ATTRIBUTE_GROUP_INIT(2, 3), + PRIORITY_ATTRIBUTE_GROUP_INIT(3, 0), + PRIORITY_ATTRIBUTE_GROUP_INIT(3, 1), + PRIORITY_ATTRIBUTE_GROUP_INIT(3, 2), + PRIORITY_ATTRIBUTE_GROUP_INIT(3, 3), + PRIORITY_ATTRIBUTE_GROUP_INIT(4, 0), + PRIORITY_ATTRIBUTE_GROUP_INIT(4, 1), + PRIORITY_ATTRIBUTE_GROUP_INIT(4, 2), + PRIORITY_ATTRIBUTE_GROUP_INIT(4, 3), + PRIORITY_ATTRIBUTE_GROUP_INIT(5, 0), + PRIORITY_ATTRIBUTE_GROUP_INIT(5, 1), + PRIORITY_ATTRIBUTE_GROUP_INIT(5, 2), + PRIORITY_ATTRIBUTE_GROUP_INIT(5, 3), + PRIORITY_ATTRIBUTE_GROUP_INIT(6, 0), + PRIORITY_ATTRIBUTE_GROUP_INIT(6, 1), + PRIORITY_ATTRIBUTE_GROUP_INIT(6, 2), + PRIORITY_ATTRIBUTE_GROUP_INIT(6, 3), + PRIORITY_ATTRIBUTE_GROUP_INIT(7, 0), + PRIORITY_ATTRIBUTE_GROUP_INIT(7, 1), + PRIORITY_ATTRIBUTE_GROUP_INIT(7, 2), + PRIORITY_ATTRIBUTE_GROUP_INIT(7, 3), NULL, }; @@ -155,6 +301,23 @@ static int tgu_probe(struct amba_device *adev, const struct amba_id *id) spin_lock_init(&drvdata->spinlock); + tgu_set_reg_number(drvdata); + tgu_set_steps(drvdata); + + drvdata->value_table = + devm_kzalloc(dev, sizeof(*drvdata->value_table), GFP_KERNEL); + if (!drvdata->value_table) + return -ENOMEM; + + drvdata->value_table->priority = devm_kzalloc( + dev, + MAX_PRIORITY * drvdata->max_reg * drvdata->max_step * + sizeof(*(drvdata->value_table->priority)), + GFP_KERNEL); + + if (!drvdata->value_table->priority) + return -ENOMEM; + drvdata->enable = false; desc.type = CORESIGHT_DEV_TYPE_HELPER; desc.pdata = adev->dev.platform_data; diff --git a/drivers/hwtracing/coresight/coresight-tgu.h b/drivers/hwtracing/coresight/coresight-tgu.h index 6c849a2f78faf..9b79106c92eaa 100644 --- a/drivers/hwtracing/coresight/coresight-tgu.h +++ b/drivers/hwtracing/coresight/coresight-tgu.h @@ -13,6 +13,111 @@ #define tgu_writel(drvdata, val, off) __raw_writel((val), drvdata->base + off) #define tgu_readl(drvdata, off) __raw_readl(drvdata->base + off) +#define TGU_DEVID_SENSE_INPUT(devid_val) ((int) BMVAL(devid_val, 10, 17)) +#define TGU_DEVID_STEPS(devid_val) ((int)BMVAL(devid_val, 3, 6)) +#define NUMBER_BITS_EACH_SIGNAL 4 +#define LENGTH_REGISTER 32 + +/* + * TGU configuration space Step configuration + * offset table space layout + * x-------------------------x$ x-------------x$ + * | |$ | |$ + * | | | reserve |$ + * | | | |$ + * |coresight management | |-------------|base+n*0x1D8+0x1F4$ + * | registe | |---> |prioroty[3] |$ + * | | | |-------------|base+n*0x1D8+0x194$ + * | | | |prioroty[2] |$ + * |-------------------------| | |-------------|base+n*0x1D8+0x134$ + * | | | |prioroty[1] |$ + * | step[7] | | |-------------|base+n*0x1D8+0xD4$ + * |-------------------------|->base+0x40+7*0x1D8 | |prioroty[0] |$ + * | | | |-------------|base+n*0x1D8+0x74$ + * | ... | | | condition |$ + * | | | | select |$ + * |-------------------------|->base+0x40+1*0x1D8 | |-------------|base+n*0x1D8+0x60$ + * | | | | condition |$ + * | step[0] |--------------------> | decode |$ + * |-------------------------|-> base+0x40 |-------------|base+n*0x1D8+0x50$ + * | | | |$ + * | Control and status space| |Timer/Counter|$ + * | space | | |$ + * x-------------------------x->base x-------------x base+n*0x1D8+0x40$ + * + */ +#define STEP_OFFSET 0x1D8 +#define PRIORITY_START_OFFSET 0x0074 +#define PRIORITY_OFFSET 0x60 +#define REG_OFFSET 0x4 + +/* Calculate compare step addresses */ +#define PRIORITY_REG_STEP(step, priority, reg)\ + (PRIORITY_START_OFFSET + PRIORITY_OFFSET * priority +\ + REG_OFFSET * reg + STEP_OFFSET * step) + +#define tgu_dataset_rw(name, step_index, type, reg_num) \ + (&((struct tgu_attribute[]){ { \ + __ATTR(name, 0644, tgu_dataset_show, tgu_dataset_store), \ + step_index, \ + type, \ + reg_num, \ + } })[0].attr.attr) + +#define STEP_PRIORITY(step_index, reg_num, priority) \ + tgu_dataset_rw(reg##reg_num, step_index, TGU_PRIORITY##priority, \ + reg_num) + +#define STEP_PRIORITY_LIST(step_index, priority) \ + {STEP_PRIORITY(step_index, 0, priority), \ + STEP_PRIORITY(step_index, 1, priority), \ + STEP_PRIORITY(step_index, 2, priority), \ + STEP_PRIORITY(step_index, 3, priority), \ + STEP_PRIORITY(step_index, 4, priority), \ + STEP_PRIORITY(step_index, 5, priority), \ + STEP_PRIORITY(step_index, 6, priority), \ + STEP_PRIORITY(step_index, 7, priority), \ + STEP_PRIORITY(step_index, 8, priority), \ + STEP_PRIORITY(step_index, 9, priority), \ + STEP_PRIORITY(step_index, 10, priority), \ + STEP_PRIORITY(step_index, 11, priority), \ + STEP_PRIORITY(step_index, 12, priority), \ + STEP_PRIORITY(step_index, 13, priority), \ + STEP_PRIORITY(step_index, 14, priority), \ + STEP_PRIORITY(step_index, 15, priority), \ + STEP_PRIORITY(step_index, 16, priority), \ + STEP_PRIORITY(step_index, 17, priority), \ + NULL \ + } + +#define PRIORITY_ATTRIBUTE_GROUP_INIT(step, priority)\ + (&(const struct attribute_group){\ + .attrs = (struct attribute*[])STEP_PRIORITY_LIST(step, priority),\ + .is_visible = tgu_node_visible,\ + .name = "step" #step "_priority" #priority \ + }) + +enum operation_index { + TGU_PRIORITY0, + TGU_PRIORITY1, + TGU_PRIORITY2, + TGU_PRIORITY3, +}; + +/* Maximum priority that TGU supports */ +#define MAX_PRIORITY 4 + +struct tgu_attribute { + struct device_attribute attr; + u32 step_index; + enum operation_index operation_index; + u32 reg_num; +}; + +struct value_table { + unsigned int *priority; +}; + /** * struct tgu_drvdata - Data structure for a TGU (Trigger Generator Unit) * @base: Memory-mapped base address of the TGU device @@ -20,6 +125,9 @@ * @csdev: Pointer to the associated coresight device * @spinlock: Spinlock for handling concurrent access * @enable: Flag indicating whether the TGU device is enabled + * @value_table: Store given value based on relevant parameters. + * @max_reg: Maximum number of registers + * @max_step: Maximum step size * * This structure defines the data associated with a TGU device, * including its base address, device pointers, clock, spinlock for @@ -32,6 +140,9 @@ struct tgu_drvdata { struct coresight_device *csdev; spinlock_t spinlock; bool enable; + struct value_table *value_table; + int max_reg; + int max_step; }; #endif From c247e91d89d225af8465219a742e3d6c235ff672 Mon Sep 17 00:00:00 2001 From: Songwei Chai Date: Wed, 9 Jul 2025 03:41:11 -0700 Subject: [PATCH 0068/2333] FROMLIST: coresight-tgu: Add TGU decode support Decoding is when all the potential pieces for creating a trigger are brought together for a given step. Example - there may be a counter keeping track of some occurrences and a priority-group that is being used to detect a pattern on the sense inputs. These 2 inputs to condition_decode must be programmed, for a given step, to establish the condition for the trigger, or movement to another steps. Link: https://lore.kernel.org/all/20250709104114.22240-5-songchai@qti.qualcomm.com/ Signed-off-by: Songwei Chai --- .../testing/sysfs-bus-coresight-devices-tgu | 7 + drivers/hwtracing/coresight/coresight-tgu.c | 186 +++++++++++++++--- drivers/hwtracing/coresight/coresight-tgu.h | 27 +++ 3 files changed, 195 insertions(+), 25 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tgu b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tgu index 4132f5912308d..7530fff3338be 100644 --- a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tgu +++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tgu @@ -14,3 +14,10 @@ KernelVersion 6.16 Contact: Jinlong Mao (QUIC) , Songwei Chai (QUIC) Description: (RW) Set/Get the sensed signal with specific step and priority for TGU. + +What: /sys/bus/coresight/devices//step[0:7]_condition_decode/reg[0:3] +Date: July 2025 +KernelVersion 6.16 +Contact: Jinlong Mao (QUIC) , Songwei Chai (QUIC) +Description: + (RW) Set/Get the decode mode with specific step for TGU. diff --git a/drivers/hwtracing/coresight/coresight-tgu.c b/drivers/hwtracing/coresight/coresight-tgu.c index 901409bef2c57..f123ae0825553 100644 --- a/drivers/hwtracing/coresight/coresight-tgu.c +++ b/drivers/hwtracing/coresight/coresight-tgu.c @@ -21,13 +21,35 @@ static int calculate_array_location(struct tgu_drvdata *drvdata, int step_index, int operation_index, int reg_index) { - int ret; + int ret = -EINVAL; + + switch (operation_index) { + case TGU_PRIORITY0: + case TGU_PRIORITY1: + case TGU_PRIORITY2: + case TGU_PRIORITY3: + ret = operation_index * (drvdata->max_step) * + (drvdata->max_reg) + + step_index * (drvdata->max_reg) + reg_index; + break; + case TGU_CONDITION_DECODE: + ret = step_index * (drvdata->max_condition_decode) + + reg_index; + break; + default: + break; + } + return ret; +} - ret = operation_index * (drvdata->max_step) * - (drvdata->max_reg) + - step_index * (drvdata->max_reg) + reg_index; +static int check_array_location(struct tgu_drvdata *drvdata, int step, + int ops, int reg) +{ + int result = calculate_array_location(drvdata, step, ops, reg); - return ret; + if (result == -EINVAL) + dev_err(&drvdata->csdev->dev, "%s - Fail\n", __func__); + return result; } static ssize_t tgu_dataset_show(struct device *dev, @@ -36,13 +58,33 @@ static ssize_t tgu_dataset_show(struct device *dev, struct tgu_drvdata *drvdata = dev_get_drvdata(dev->parent); struct tgu_attribute *tgu_attr = container_of(attr, struct tgu_attribute, attr); + int ret = 0; + + ret = check_array_location(drvdata, tgu_attr->step_index, + tgu_attr->operation_index, tgu_attr->reg_num); + if (ret == -EINVAL) + return ret; - return sysfs_emit(buf, "0x%x\n", - drvdata->value_table->priority[ - calculate_array_location( - drvdata, tgu_attr->step_index, - tgu_attr->operation_index, - tgu_attr->reg_num)]); + switch (tgu_attr->operation_index) { + case TGU_PRIORITY0: + case TGU_PRIORITY1: + case TGU_PRIORITY2: + case TGU_PRIORITY3: + return sysfs_emit(buf, "0x%x\n", + drvdata->value_table->priority[calculate_array_location( + drvdata, tgu_attr->step_index, + tgu_attr->operation_index, + tgu_attr->reg_num)]); + case TGU_CONDITION_DECODE: + return sysfs_emit(buf, "0x%x\n", + drvdata->value_table->condition_decode[calculate_array_location( + drvdata, tgu_attr->step_index, + tgu_attr->operation_index, + tgu_attr->reg_num)]); + default: + break; + } + return -EINVAL; } static ssize_t tgu_dataset_store(struct device *dev, @@ -51,20 +93,44 @@ static ssize_t tgu_dataset_store(struct device *dev, size_t size) { unsigned long val; + int ret = -EINVAL; struct tgu_drvdata *tgu_drvdata = dev_get_drvdata(dev->parent); struct tgu_attribute *tgu_attr = container_of(attr, struct tgu_attribute, attr); if (kstrtoul(buf, 0, &val)) - return -EINVAL; + return ret; - guard(spinlock)(&tgu_drvdata->spinlock); - tgu_drvdata->value_table->priority[calculate_array_location( - tgu_drvdata, tgu_attr->step_index, tgu_attr->operation_index, - tgu_attr->reg_num)] = val; + ret = check_array_location(tgu_drvdata, tgu_attr->step_index, + tgu_attr->operation_index, tgu_attr->reg_num); - return size; + if (ret == -EINVAL) + return ret; + + guard(spinlock)(&tgu_drvdata->spinlock); + switch (tgu_attr->operation_index) { + case TGU_PRIORITY0: + case TGU_PRIORITY1: + case TGU_PRIORITY2: + case TGU_PRIORITY3: + tgu_drvdata->value_table->priority[calculate_array_location( + tgu_drvdata, tgu_attr->step_index, + tgu_attr->operation_index, + tgu_attr->reg_num)] = val; + ret = size; + break; + case TGU_CONDITION_DECODE: + tgu_drvdata->value_table->condition_decode[calculate_array_location( + tgu_drvdata, tgu_attr->step_index, + tgu_attr->operation_index, + tgu_attr->reg_num)] = val; + ret = size; + break; + default: + break; + } + return ret; } static umode_t tgu_node_visible(struct kobject *kobject, @@ -81,34 +147,70 @@ static umode_t tgu_node_visible(struct kobject *kobject, container_of(dev_attr, struct tgu_attribute, attr); if (tgu_attr->step_index < drvdata->max_step) { - ret = (tgu_attr->reg_num < drvdata->max_reg) ? - attr->mode : - 0; + switch (tgu_attr->operation_index) { + case TGU_PRIORITY0: + case TGU_PRIORITY1: + case TGU_PRIORITY2: + case TGU_PRIORITY3: + ret = (tgu_attr->reg_num < drvdata->max_reg) ? + attr->mode : + 0; + break; + case TGU_CONDITION_DECODE: + ret = (tgu_attr->reg_num < + drvdata->max_condition_decode) ? + attr->mode : + 0; + break; + default: + break; + } } return ret; } -static void tgu_write_all_hw_regs(struct tgu_drvdata *drvdata) +static ssize_t tgu_write_all_hw_regs(struct tgu_drvdata *drvdata) { - int i, j, k; + int i, j, k, ret; CS_UNLOCK(drvdata->base); for (i = 0; i < drvdata->max_step; i++) { for (j = 0; j < MAX_PRIORITY; j++) { for (k = 0; k < drvdata->max_reg; k++) { + + ret = check_array_location(drvdata, i, j, k); + if (ret == -EINVAL) + goto exit; + tgu_writel(drvdata, drvdata->value_table->priority [calculate_array_location( - drvdata, i, j, k)], + drvdata, i, j, k)], PRIORITY_REG_STEP(i, j, k)); } } } + for (i = 0; i < drvdata->max_step; i++) { + for (j = 0; j < drvdata->max_condition_decode; j++) { + ret = check_array_location(drvdata, i, TGU_CONDITION_DECODE, j); + if (ret == -EINVAL) + goto exit; + + tgu_writel(drvdata, + drvdata->value_table->condition_decode + [calculate_array_location( + drvdata, i, + TGU_CONDITION_DECODE, j)], + CONDITION_DECODE_STEP(i, j)); + } + } /* Enable TGU to program the triggers */ tgu_writel(drvdata, 1, TGU_CONTROL); +exit: CS_LOCK(drvdata->base); + return ret >= 0 ? 0 : ret; } static void tgu_set_reg_number(struct tgu_drvdata *drvdata) @@ -139,19 +241,35 @@ static void tgu_set_steps(struct tgu_drvdata *drvdata) drvdata->max_step = num_steps; } +static void tgu_set_conditions(struct tgu_drvdata *drvdata) +{ + int num_conditions; + u32 devid; + + devid = readl_relaxed(drvdata->base + CORESIGHT_DEVID); + + num_conditions = TGU_DEVID_CONDITIONS(devid); + drvdata->max_condition_decode = num_conditions; +} + static int tgu_enable(struct coresight_device *csdev, enum cs_mode mode, void *data) { + int ret = 0; struct tgu_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); guard(spinlock)(&drvdata->spinlock); if (drvdata->enable) return -EBUSY; - tgu_write_all_hw_regs(drvdata); + ret = tgu_write_all_hw_regs(drvdata); + + if (ret == -EINVAL) + goto exit; drvdata->enable = true; - return 0; +exit: + return ret; } static int tgu_disable(struct coresight_device *csdev, void *data) @@ -267,6 +385,14 @@ static const struct attribute_group *tgu_attr_groups[] = { PRIORITY_ATTRIBUTE_GROUP_INIT(7, 1), PRIORITY_ATTRIBUTE_GROUP_INIT(7, 2), PRIORITY_ATTRIBUTE_GROUP_INIT(7, 3), + CONDITION_DECODE_ATTRIBUTE_GROUP_INIT(0), + CONDITION_DECODE_ATTRIBUTE_GROUP_INIT(1), + CONDITION_DECODE_ATTRIBUTE_GROUP_INIT(2), + CONDITION_DECODE_ATTRIBUTE_GROUP_INIT(3), + CONDITION_DECODE_ATTRIBUTE_GROUP_INIT(4), + CONDITION_DECODE_ATTRIBUTE_GROUP_INIT(5), + CONDITION_DECODE_ATTRIBUTE_GROUP_INIT(6), + CONDITION_DECODE_ATTRIBUTE_GROUP_INIT(7), NULL, }; @@ -303,6 +429,7 @@ static int tgu_probe(struct amba_device *adev, const struct amba_id *id) tgu_set_reg_number(drvdata); tgu_set_steps(drvdata); + tgu_set_conditions(drvdata); drvdata->value_table = devm_kzalloc(dev, sizeof(*drvdata->value_table), GFP_KERNEL); @@ -318,6 +445,15 @@ static int tgu_probe(struct amba_device *adev, const struct amba_id *id) if (!drvdata->value_table->priority) return -ENOMEM; + drvdata->value_table->condition_decode = devm_kzalloc( + dev, + drvdata->max_condition_decode * drvdata->max_step * + sizeof(*(drvdata->value_table->condition_decode)), + GFP_KERNEL); + + if (!drvdata->value_table->condition_decode) + return -ENOMEM; + drvdata->enable = false; desc.type = CORESIGHT_DEV_TYPE_HELPER; desc.pdata = adev->dev.platform_data; diff --git a/drivers/hwtracing/coresight/coresight-tgu.h b/drivers/hwtracing/coresight/coresight-tgu.h index 9b79106c92eaa..8d3c6ddc19ed1 100644 --- a/drivers/hwtracing/coresight/coresight-tgu.h +++ b/drivers/hwtracing/coresight/coresight-tgu.h @@ -15,6 +15,7 @@ #define TGU_DEVID_SENSE_INPUT(devid_val) ((int) BMVAL(devid_val, 10, 17)) #define TGU_DEVID_STEPS(devid_val) ((int)BMVAL(devid_val, 3, 6)) +#define TGU_DEVID_CONDITIONS(devid_val) ((int)BMVAL(devid_val, 0, 2)) #define NUMBER_BITS_EACH_SIGNAL 4 #define LENGTH_REGISTER 32 @@ -48,6 +49,7 @@ */ #define STEP_OFFSET 0x1D8 #define PRIORITY_START_OFFSET 0x0074 +#define CONDITION_DECODE_OFFSET 0x0050 #define PRIORITY_OFFSET 0x60 #define REG_OFFSET 0x4 @@ -56,6 +58,9 @@ (PRIORITY_START_OFFSET + PRIORITY_OFFSET * priority +\ REG_OFFSET * reg + STEP_OFFSET * step) +#define CONDITION_DECODE_STEP(step, decode) \ + (CONDITION_DECODE_OFFSET + REG_OFFSET * decode + STEP_OFFSET * step) + #define tgu_dataset_rw(name, step_index, type, reg_num) \ (&((struct tgu_attribute[]){ { \ __ATTR(name, 0644, tgu_dataset_show, tgu_dataset_store), \ @@ -68,6 +73,9 @@ tgu_dataset_rw(reg##reg_num, step_index, TGU_PRIORITY##priority, \ reg_num) +#define STEP_DECODE(step_index, reg_num) \ + tgu_dataset_rw(reg##reg_num, step_index, TGU_CONDITION_DECODE, reg_num) + #define STEP_PRIORITY_LIST(step_index, priority) \ {STEP_PRIORITY(step_index, 0, priority), \ STEP_PRIORITY(step_index, 1, priority), \ @@ -90,6 +98,14 @@ NULL \ } +#define STEP_DECODE_LIST(n) \ + {STEP_DECODE(n, 0), \ + STEP_DECODE(n, 1), \ + STEP_DECODE(n, 2), \ + STEP_DECODE(n, 3), \ + NULL \ + } + #define PRIORITY_ATTRIBUTE_GROUP_INIT(step, priority)\ (&(const struct attribute_group){\ .attrs = (struct attribute*[])STEP_PRIORITY_LIST(step, priority),\ @@ -97,11 +113,19 @@ .name = "step" #step "_priority" #priority \ }) +#define CONDITION_DECODE_ATTRIBUTE_GROUP_INIT(step)\ + (&(const struct attribute_group){\ + .attrs = (struct attribute*[])STEP_DECODE_LIST(step),\ + .is_visible = tgu_node_visible,\ + .name = "step" #step "_condition_decode" \ + }) + enum operation_index { TGU_PRIORITY0, TGU_PRIORITY1, TGU_PRIORITY2, TGU_PRIORITY3, + TGU_CONDITION_DECODE, }; /* Maximum priority that TGU supports */ @@ -116,6 +140,7 @@ struct tgu_attribute { struct value_table { unsigned int *priority; + unsigned int *condition_decode; }; /** @@ -128,6 +153,7 @@ struct value_table { * @value_table: Store given value based on relevant parameters. * @max_reg: Maximum number of registers * @max_step: Maximum step size + * @max_condition_decode: Maximum number of condition_decode * * This structure defines the data associated with a TGU device, * including its base address, device pointers, clock, spinlock for @@ -143,6 +169,7 @@ struct tgu_drvdata { struct value_table *value_table; int max_reg; int max_step; + int max_condition_decode; }; #endif From 78172ff966101276aa3805305ff692e41cf2aa62 Mon Sep 17 00:00:00 2001 From: Songwei Chai Date: Wed, 9 Jul 2025 03:41:12 -0700 Subject: [PATCH 0069/2333] FROMLIST: coresight-tgu: add support to configure next action Add "select" node for each step to determine if another step is taken, trigger(s) are generated, counters/timers incremented/decremented, etc. Link: https://lore.kernel.org/all/20250709104114.22240-6-songchai@qti.qualcomm.com/ Signed-off-by: Songwei Chai --- .../testing/sysfs-bus-coresight-devices-tgu | 7 +++ drivers/hwtracing/coresight/coresight-tgu.c | 59 +++++++++++++++++++ drivers/hwtracing/coresight/coresight-tgu.h | 27 +++++++++ 3 files changed, 93 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tgu b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tgu index 7530fff3338be..5ca91e122500e 100644 --- a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tgu +++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tgu @@ -21,3 +21,10 @@ KernelVersion 6.16 Contact: Jinlong Mao (QUIC) , Songwei Chai (QUIC) Description: (RW) Set/Get the decode mode with specific step for TGU. + +What: /sys/bus/coresight/devices//step[0:7]_condition_select/reg[0:3] +Date: July 2025 +KernelVersion 6.16 +Contact: Jinlong Mao (QUIC) , Songwei Chai (QUIC) +Description: + (RW) Set/Get the next action with specific step for TGU. diff --git a/drivers/hwtracing/coresight/coresight-tgu.c b/drivers/hwtracing/coresight/coresight-tgu.c index f123ae0825553..71436fbdcc3e2 100644 --- a/drivers/hwtracing/coresight/coresight-tgu.c +++ b/drivers/hwtracing/coresight/coresight-tgu.c @@ -36,6 +36,9 @@ static int calculate_array_location(struct tgu_drvdata *drvdata, ret = step_index * (drvdata->max_condition_decode) + reg_index; break; + case TGU_CONDITION_SELECT: + ret = step_index * (drvdata->max_condition_select) + reg_index; + break; default: break; } @@ -81,6 +84,12 @@ static ssize_t tgu_dataset_show(struct device *dev, drvdata, tgu_attr->step_index, tgu_attr->operation_index, tgu_attr->reg_num)]); + case TGU_CONDITION_SELECT: + return sysfs_emit(buf, "0x%x\n", + drvdata->value_table->condition_select[calculate_array_location( + drvdata, tgu_attr->step_index, + tgu_attr->operation_index, + tgu_attr->reg_num)]); default: break; } @@ -127,6 +136,13 @@ static ssize_t tgu_dataset_store(struct device *dev, tgu_attr->reg_num)] = val; ret = size; break; + case TGU_CONDITION_SELECT: + tgu_drvdata->value_table->condition_select[calculate_array_location( + tgu_drvdata, tgu_attr->step_index, + tgu_attr->operation_index, + tgu_attr->reg_num)] = val; + ret = size; + break; default: break; } @@ -162,6 +178,16 @@ static umode_t tgu_node_visible(struct kobject *kobject, attr->mode : 0; break; + case TGU_CONDITION_SELECT: + /* 'default' register is at the end of 'select' region */ + if (tgu_attr->reg_num == + drvdata->max_condition_select - 1) + attr->name = "default"; + ret = (tgu_attr->reg_num < + drvdata->max_condition_select) ? + attr->mode : + 0; + break; default: break; } @@ -206,6 +232,20 @@ static ssize_t tgu_write_all_hw_regs(struct tgu_drvdata *drvdata) CONDITION_DECODE_STEP(i, j)); } } + + for (i = 0; i < drvdata->max_step; i++) { + for (j = 0; j < drvdata->max_condition_select; j++) { + ret = check_array_location(drvdata, i, TGU_CONDITION_SELECT, j); + if (ret == -EINVAL) + goto exit; + + tgu_writel(drvdata, + drvdata->value_table->condition_select + [calculate_array_location(drvdata, i, + TGU_CONDITION_SELECT, j)], + CONDITION_SELECT_STEP(i, j)); + } + } /* Enable TGU to program the triggers */ tgu_writel(drvdata, 1, TGU_CONTROL); exit: @@ -250,6 +290,8 @@ static void tgu_set_conditions(struct tgu_drvdata *drvdata) num_conditions = TGU_DEVID_CONDITIONS(devid); drvdata->max_condition_decode = num_conditions; + /* select region has an additional 'default' register */ + drvdata->max_condition_select = num_conditions + 1; } static int tgu_enable(struct coresight_device *csdev, enum cs_mode mode, @@ -393,6 +435,14 @@ static const struct attribute_group *tgu_attr_groups[] = { CONDITION_DECODE_ATTRIBUTE_GROUP_INIT(5), CONDITION_DECODE_ATTRIBUTE_GROUP_INIT(6), CONDITION_DECODE_ATTRIBUTE_GROUP_INIT(7), + CONDITION_SELECT_ATTRIBUTE_GROUP_INIT(0), + CONDITION_SELECT_ATTRIBUTE_GROUP_INIT(1), + CONDITION_SELECT_ATTRIBUTE_GROUP_INIT(2), + CONDITION_SELECT_ATTRIBUTE_GROUP_INIT(3), + CONDITION_SELECT_ATTRIBUTE_GROUP_INIT(4), + CONDITION_SELECT_ATTRIBUTE_GROUP_INIT(5), + CONDITION_SELECT_ATTRIBUTE_GROUP_INIT(6), + CONDITION_SELECT_ATTRIBUTE_GROUP_INIT(7), NULL, }; @@ -454,6 +504,15 @@ static int tgu_probe(struct amba_device *adev, const struct amba_id *id) if (!drvdata->value_table->condition_decode) return -ENOMEM; + drvdata->value_table->condition_select = devm_kzalloc( + dev, + drvdata->max_condition_select * drvdata->max_step * + sizeof(*(drvdata->value_table->condition_select)), + GFP_KERNEL); + + if (!drvdata->value_table->condition_select) + return -ENOMEM; + drvdata->enable = false; desc.type = CORESIGHT_DEV_TYPE_HELPER; desc.pdata = adev->dev.platform_data; diff --git a/drivers/hwtracing/coresight/coresight-tgu.h b/drivers/hwtracing/coresight/coresight-tgu.h index 8d3c6ddc19ed1..29f6fcf4d2be8 100644 --- a/drivers/hwtracing/coresight/coresight-tgu.h +++ b/drivers/hwtracing/coresight/coresight-tgu.h @@ -50,6 +50,7 @@ #define STEP_OFFSET 0x1D8 #define PRIORITY_START_OFFSET 0x0074 #define CONDITION_DECODE_OFFSET 0x0050 +#define CONDITION_SELECT_OFFSET 0x0060 #define PRIORITY_OFFSET 0x60 #define REG_OFFSET 0x4 @@ -61,6 +62,9 @@ #define CONDITION_DECODE_STEP(step, decode) \ (CONDITION_DECODE_OFFSET + REG_OFFSET * decode + STEP_OFFSET * step) +#define CONDITION_SELECT_STEP(step, select) \ + (CONDITION_SELECT_OFFSET + REG_OFFSET * select + STEP_OFFSET * step) + #define tgu_dataset_rw(name, step_index, type, reg_num) \ (&((struct tgu_attribute[]){ { \ __ATTR(name, 0644, tgu_dataset_show, tgu_dataset_store), \ @@ -76,6 +80,9 @@ #define STEP_DECODE(step_index, reg_num) \ tgu_dataset_rw(reg##reg_num, step_index, TGU_CONDITION_DECODE, reg_num) +#define STEP_SELECT(step_index, reg_num) \ + tgu_dataset_rw(reg##reg_num, step_index, TGU_CONDITION_SELECT, reg_num) + #define STEP_PRIORITY_LIST(step_index, priority) \ {STEP_PRIORITY(step_index, 0, priority), \ STEP_PRIORITY(step_index, 1, priority), \ @@ -106,6 +113,15 @@ NULL \ } +#define STEP_SELECT_LIST(n) \ + {STEP_SELECT(n, 0), \ + STEP_SELECT(n, 1), \ + STEP_SELECT(n, 2), \ + STEP_SELECT(n, 3), \ + STEP_SELECT(n, 4), \ + NULL \ + } + #define PRIORITY_ATTRIBUTE_GROUP_INIT(step, priority)\ (&(const struct attribute_group){\ .attrs = (struct attribute*[])STEP_PRIORITY_LIST(step, priority),\ @@ -120,12 +136,20 @@ .name = "step" #step "_condition_decode" \ }) +#define CONDITION_SELECT_ATTRIBUTE_GROUP_INIT(step)\ + (&(const struct attribute_group){\ + .attrs = (struct attribute*[])STEP_SELECT_LIST(step),\ + .is_visible = tgu_node_visible,\ + .name = "step" #step "_condition_select" \ + }) + enum operation_index { TGU_PRIORITY0, TGU_PRIORITY1, TGU_PRIORITY2, TGU_PRIORITY3, TGU_CONDITION_DECODE, + TGU_CONDITION_SELECT, }; /* Maximum priority that TGU supports */ @@ -141,6 +165,7 @@ struct tgu_attribute { struct value_table { unsigned int *priority; unsigned int *condition_decode; + unsigned int *condition_select; }; /** @@ -154,6 +179,7 @@ struct value_table { * @max_reg: Maximum number of registers * @max_step: Maximum step size * @max_condition_decode: Maximum number of condition_decode + * @max_condition_select: Maximum number of condition_select * * This structure defines the data associated with a TGU device, * including its base address, device pointers, clock, spinlock for @@ -170,6 +196,7 @@ struct tgu_drvdata { int max_reg; int max_step; int max_condition_decode; + int max_condition_select; }; #endif From aee7a587b21d6aeab97fe4a6b7e1ee745900b764 Mon Sep 17 00:00:00 2001 From: Songwei Chai Date: Wed, 9 Jul 2025 03:41:13 -0700 Subject: [PATCH 0070/2333] FROMLIST: coresight-tgu: add timer/counter functionality for TGU Add counter and timer node for each step which could be programed if they are to be utilized in trigger event/sequence. Link: https://lore.kernel.org/all/20250709104114.22240-7-songchai@qti.qualcomm.com/ Signed-off-by: Songwei Chai --- .../testing/sysfs-bus-coresight-devices-tgu | 14 ++ drivers/hwtracing/coresight/coresight-tgu.c | 134 ++++++++++++++++++ drivers/hwtracing/coresight/coresight-tgu.h | 55 ++++++- 3 files changed, 202 insertions(+), 1 deletion(-) diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tgu b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tgu index 5ca91e122500e..f0d7db72b61c4 100644 --- a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tgu +++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tgu @@ -28,3 +28,17 @@ KernelVersion 6.16 Contact: Jinlong Mao (QUIC) , Songwei Chai (QUIC) Description: (RW) Set/Get the next action with specific step for TGU. + +What: /sys/bus/coresight/devices//step[0:7]_timer/reg[0:1] +Date: July 2025 +KernelVersion 6.16 +Contact: Jinlong Mao (QUIC) , Songwei Chai (QUIC) +Description: + (RW) Set/Get the timer value with specific step for TGU. + +What: /sys/bus/coresight/devices//step[0:7]_counter/reg[0:1] +Date: July 2025 +KernelVersion 6.16 +Contact: Jinlong Mao (QUIC) , Songwei Chai (QUIC) +Description: + (RW) Set/Get the counter value with specific step for TGU. diff --git a/drivers/hwtracing/coresight/coresight-tgu.c b/drivers/hwtracing/coresight/coresight-tgu.c index 71436fbdcc3e2..303698a9d5ab4 100644 --- a/drivers/hwtracing/coresight/coresight-tgu.c +++ b/drivers/hwtracing/coresight/coresight-tgu.c @@ -39,6 +39,12 @@ static int calculate_array_location(struct tgu_drvdata *drvdata, case TGU_CONDITION_SELECT: ret = step_index * (drvdata->max_condition_select) + reg_index; break; + case TGU_COUNTER: + ret = step_index * (drvdata->max_counter) + reg_index; + break; + case TGU_TIMER: + ret = step_index * (drvdata->max_timer) + reg_index; + break; default: break; } @@ -90,6 +96,16 @@ static ssize_t tgu_dataset_show(struct device *dev, drvdata, tgu_attr->step_index, tgu_attr->operation_index, tgu_attr->reg_num)]); + case TGU_TIMER: + return sysfs_emit(buf, "0x%x\n", + drvdata->value_table->timer[calculate_array_location( + drvdata, tgu_attr->step_index, tgu_attr->operation_index, + tgu_attr->reg_num)]); + case TGU_COUNTER: + return sysfs_emit(buf, "0x%x\n", + drvdata->value_table->counter[calculate_array_location( + drvdata, tgu_attr->step_index, tgu_attr->operation_index, + tgu_attr->reg_num)]); default: break; } @@ -143,6 +159,18 @@ static ssize_t tgu_dataset_store(struct device *dev, tgu_attr->reg_num)] = val; ret = size; break; + case TGU_TIMER: + tgu_drvdata->value_table->timer[calculate_array_location( + tgu_drvdata, tgu_attr->step_index, tgu_attr->operation_index, + tgu_attr->reg_num)] = val; + ret = size; + break; + case TGU_COUNTER: + tgu_drvdata->value_table->counter[calculate_array_location( + tgu_drvdata, tgu_attr->step_index, tgu_attr->operation_index, + tgu_attr->reg_num)] = val; + ret = size; + break; default: break; } @@ -188,6 +216,24 @@ static umode_t tgu_node_visible(struct kobject *kobject, attr->mode : 0; break; + case TGU_COUNTER: + if (drvdata->max_counter == 0) + ret = SYSFS_GROUP_INVISIBLE; + else + ret = (tgu_attr->reg_num < + drvdata->max_counter) ? + attr->mode : + 0; + break; + case TGU_TIMER: + if (drvdata->max_timer == 0) + ret = SYSFS_GROUP_INVISIBLE; + else + ret = (tgu_attr->reg_num < + drvdata->max_timer) ? + attr->mode : + 0; + break; default: break; } @@ -246,6 +292,34 @@ static ssize_t tgu_write_all_hw_regs(struct tgu_drvdata *drvdata) CONDITION_SELECT_STEP(i, j)); } } + + for (i = 0; i < drvdata->max_step; i++) { + for (j = 0; j < drvdata->max_timer; j++) { + ret = check_array_location(drvdata, i, TGU_TIMER, j); + if (ret == -EINVAL) + goto exit; + + tgu_writel(drvdata, + drvdata->value_table->timer + [calculate_array_location(drvdata, i, + TGU_TIMER, j)], + TIMER_COMPARE_STEP(i, j)); + } + } + + for (i = 0; i < drvdata->max_step; i++) { + for (j = 0; j < drvdata->max_counter; j++) { + ret = check_array_location(drvdata, i, TGU_COUNTER, j); + if (ret == -EINVAL) + goto exit; + + tgu_writel(drvdata, + drvdata->value_table->counter + [calculate_array_location(drvdata, i, + TGU_COUNTER, j)], + COUNTER_COMPARE_STEP(i, j)); + } + } /* Enable TGU to program the triggers */ tgu_writel(drvdata, 1, TGU_CONTROL); exit: @@ -294,6 +368,31 @@ static void tgu_set_conditions(struct tgu_drvdata *drvdata) drvdata->max_condition_select = num_conditions + 1; } +static void tgu_set_timer_counter(struct tgu_drvdata *drvdata) +{ + int num_timers, num_counters; + u32 devid2; + + devid2 = readl_relaxed(drvdata->base + CORESIGHT_DEVID2); + + if (TGU_DEVID2_TIMER0(devid2) && TGU_DEVID2_TIMER1(devid2)) + num_timers = 2; + else if (TGU_DEVID2_TIMER0(devid2) || TGU_DEVID2_TIMER1(devid2)) + num_timers = 1; + else + num_timers = 0; + + if (TGU_DEVID2_COUNTER0(devid2) && TGU_DEVID2_COUNTER1(devid2)) + num_counters = 2; + else if (TGU_DEVID2_COUNTER0(devid2) || TGU_DEVID2_COUNTER1(devid2)) + num_counters = 1; + else + num_counters = 0; + + drvdata->max_timer = num_timers; + drvdata->max_counter = num_counters; +} + static int tgu_enable(struct coresight_device *csdev, enum cs_mode mode, void *data) { @@ -443,6 +542,22 @@ static const struct attribute_group *tgu_attr_groups[] = { CONDITION_SELECT_ATTRIBUTE_GROUP_INIT(5), CONDITION_SELECT_ATTRIBUTE_GROUP_INIT(6), CONDITION_SELECT_ATTRIBUTE_GROUP_INIT(7), + TIMER_ATTRIBUTE_GROUP_INIT(0), + TIMER_ATTRIBUTE_GROUP_INIT(1), + TIMER_ATTRIBUTE_GROUP_INIT(2), + TIMER_ATTRIBUTE_GROUP_INIT(3), + TIMER_ATTRIBUTE_GROUP_INIT(4), + TIMER_ATTRIBUTE_GROUP_INIT(5), + TIMER_ATTRIBUTE_GROUP_INIT(6), + TIMER_ATTRIBUTE_GROUP_INIT(7), + COUNTER_ATTRIBUTE_GROUP_INIT(0), + COUNTER_ATTRIBUTE_GROUP_INIT(1), + COUNTER_ATTRIBUTE_GROUP_INIT(2), + COUNTER_ATTRIBUTE_GROUP_INIT(3), + COUNTER_ATTRIBUTE_GROUP_INIT(4), + COUNTER_ATTRIBUTE_GROUP_INIT(5), + COUNTER_ATTRIBUTE_GROUP_INIT(6), + COUNTER_ATTRIBUTE_GROUP_INIT(7), NULL, }; @@ -480,6 +595,7 @@ static int tgu_probe(struct amba_device *adev, const struct amba_id *id) tgu_set_reg_number(drvdata); tgu_set_steps(drvdata); tgu_set_conditions(drvdata); + tgu_set_timer_counter(drvdata); drvdata->value_table = devm_kzalloc(dev, sizeof(*drvdata->value_table), GFP_KERNEL); @@ -513,6 +629,24 @@ static int tgu_probe(struct amba_device *adev, const struct amba_id *id) if (!drvdata->value_table->condition_select) return -ENOMEM; + drvdata->value_table->timer = devm_kzalloc( + dev, + drvdata->max_step * drvdata->max_timer * + sizeof(*(drvdata->value_table->timer)), + GFP_KERNEL); + + if (!drvdata->value_table->timer) + return -ENOMEM; + + drvdata->value_table->counter = devm_kzalloc( + dev, + drvdata->max_step * drvdata->max_counter * + sizeof(*(drvdata->value_table->counter)), + GFP_KERNEL); + + if (!drvdata->value_table->counter) + return -ENOMEM; + drvdata->enable = false; desc.type = CORESIGHT_DEV_TYPE_HELPER; desc.pdata = adev->dev.platform_data; diff --git a/drivers/hwtracing/coresight/coresight-tgu.h b/drivers/hwtracing/coresight/coresight-tgu.h index 29f6fcf4d2be8..be9c87ec7e3ce 100644 --- a/drivers/hwtracing/coresight/coresight-tgu.h +++ b/drivers/hwtracing/coresight/coresight-tgu.h @@ -8,7 +8,7 @@ /* Register addresses */ #define TGU_CONTROL 0x0000 - +#define CORESIGHT_DEVID2 0xfc0 /* Register read/write */ #define tgu_writel(drvdata, val, off) __raw_writel((val), drvdata->base + off) #define tgu_readl(drvdata, off) __raw_readl(drvdata->base + off) @@ -16,6 +16,11 @@ #define TGU_DEVID_SENSE_INPUT(devid_val) ((int) BMVAL(devid_val, 10, 17)) #define TGU_DEVID_STEPS(devid_val) ((int)BMVAL(devid_val, 3, 6)) #define TGU_DEVID_CONDITIONS(devid_val) ((int)BMVAL(devid_val, 0, 2)) +#define TGU_DEVID2_TIMER0(devid_val) ((int)BMVAL(devid_val, 18, 23)) +#define TGU_DEVID2_TIMER1(devid_val) ((int)BMVAL(devid_val, 13, 17)) +#define TGU_DEVID2_COUNTER0(devid_val) ((int)BMVAL(devid_val, 6, 11)) +#define TGU_DEVID2_COUNTER1(devid_val) ((int)BMVAL(devid_val, 0, 5)) + #define NUMBER_BITS_EACH_SIGNAL 4 #define LENGTH_REGISTER 32 @@ -51,6 +56,8 @@ #define PRIORITY_START_OFFSET 0x0074 #define CONDITION_DECODE_OFFSET 0x0050 #define CONDITION_SELECT_OFFSET 0x0060 +#define TIMER_START_OFFSET 0x0040 +#define COUNTER_START_OFFSET 0x0048 #define PRIORITY_OFFSET 0x60 #define REG_OFFSET 0x4 @@ -62,6 +69,12 @@ #define CONDITION_DECODE_STEP(step, decode) \ (CONDITION_DECODE_OFFSET + REG_OFFSET * decode + STEP_OFFSET * step) +#define TIMER_COMPARE_STEP(step, timer) \ + (TIMER_START_OFFSET + REG_OFFSET * timer + STEP_OFFSET * step) + +#define COUNTER_COMPARE_STEP(step, counter) \ + (COUNTER_START_OFFSET + REG_OFFSET * counter + STEP_OFFSET * step) + #define CONDITION_SELECT_STEP(step, select) \ (CONDITION_SELECT_OFFSET + REG_OFFSET * select + STEP_OFFSET * step) @@ -83,6 +96,12 @@ #define STEP_SELECT(step_index, reg_num) \ tgu_dataset_rw(reg##reg_num, step_index, TGU_CONDITION_SELECT, reg_num) +#define STEP_TIMER(step_index, reg_num) \ + tgu_dataset_rw(reg##reg_num, step_index, TGU_TIMER, reg_num) + +#define STEP_COUNTER(step_index, reg_num) \ + tgu_dataset_rw(reg##reg_num, step_index, TGU_COUNTER, reg_num) + #define STEP_PRIORITY_LIST(step_index, priority) \ {STEP_PRIORITY(step_index, 0, priority), \ STEP_PRIORITY(step_index, 1, priority), \ @@ -122,6 +141,18 @@ NULL \ } +#define STEP_TIMER_LIST(n) \ + {STEP_TIMER(n, 0), \ + STEP_TIMER(n, 1), \ + NULL \ + } + +#define STEP_COUNTER_LIST(n) \ + {STEP_COUNTER(n, 0), \ + STEP_COUNTER(n, 1), \ + NULL \ + } + #define PRIORITY_ATTRIBUTE_GROUP_INIT(step, priority)\ (&(const struct attribute_group){\ .attrs = (struct attribute*[])STEP_PRIORITY_LIST(step, priority),\ @@ -143,6 +174,20 @@ .name = "step" #step "_condition_select" \ }) +#define TIMER_ATTRIBUTE_GROUP_INIT(step)\ + (&(const struct attribute_group){\ + .attrs = (struct attribute*[])STEP_TIMER_LIST(step),\ + .is_visible = tgu_node_visible,\ + .name = "step" #step "_timer" \ + }) + +#define COUNTER_ATTRIBUTE_GROUP_INIT(step)\ + (&(const struct attribute_group){\ + .attrs = (struct attribute*[])STEP_COUNTER_LIST(step),\ + .is_visible = tgu_node_visible,\ + .name = "step" #step "_counter" \ + }) + enum operation_index { TGU_PRIORITY0, TGU_PRIORITY1, @@ -150,6 +195,8 @@ enum operation_index { TGU_PRIORITY3, TGU_CONDITION_DECODE, TGU_CONDITION_SELECT, + TGU_TIMER, + TGU_COUNTER }; /* Maximum priority that TGU supports */ @@ -166,6 +213,8 @@ struct value_table { unsigned int *priority; unsigned int *condition_decode; unsigned int *condition_select; + unsigned int *timer; + unsigned int *counter; }; /** @@ -180,6 +229,8 @@ struct value_table { * @max_step: Maximum step size * @max_condition_decode: Maximum number of condition_decode * @max_condition_select: Maximum number of condition_select + * @max_timer: Maximum number of timers + * @max_counter: Maximum number of counters * * This structure defines the data associated with a TGU device, * including its base address, device pointers, clock, spinlock for @@ -197,6 +248,8 @@ struct tgu_drvdata { int max_step; int max_condition_decode; int max_condition_select; + int max_timer; + int max_counter; }; #endif From e6d6870c501390e5151db0d1f91910ffd00500f3 Mon Sep 17 00:00:00 2001 From: Songwei Chai Date: Wed, 9 Jul 2025 03:41:14 -0700 Subject: [PATCH 0071/2333] FROMLIST: coresight-tgu: add reset node to initialize Add reset node to initialize the value of priority/condition_decode/condition_select/timer/counter nodes. Link: https://lore.kernel.org/all/20250709104114.22240-8-songchai@qti.qualcomm.com/ Signed-off-by: Songwei Chai --- .../testing/sysfs-bus-coresight-devices-tgu | 7 ++ drivers/hwtracing/coresight/coresight-tgu.c | 75 +++++++++++++++++++ 2 files changed, 82 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tgu b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tgu index f0d7db72b61c4..4ff5ec9be733e 100644 --- a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tgu +++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tgu @@ -42,3 +42,10 @@ KernelVersion 6.16 Contact: Jinlong Mao (QUIC) , Songwei Chai (QUIC) Description: (RW) Set/Get the counter value with specific step for TGU. + +What: /sys/bus/coresight/devices//reset_tgu +Date: July 2025 +KernelVersion 6.16 +Contact: Jinlong Mao (QUIC) , Songwei Chai (QUIC) +Description: + (Write) Write 1 to reset the dataset for TGU. diff --git a/drivers/hwtracing/coresight/coresight-tgu.c b/drivers/hwtracing/coresight/coresight-tgu.c index 303698a9d5ab4..35c97f31639e3 100644 --- a/drivers/hwtracing/coresight/coresight-tgu.c +++ b/drivers/hwtracing/coresight/coresight-tgu.c @@ -473,6 +473,80 @@ static ssize_t enable_tgu_store(struct device *dev, } static DEVICE_ATTR_RW(enable_tgu); +/* reset_tgu_store - Reset Trace and Gating Unit (TGU) configuration. */ +static ssize_t reset_tgu_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t size) +{ + unsigned long value; + struct tgu_drvdata *drvdata = dev_get_drvdata(dev->parent); + int i, j, ret; + + if (kstrtoul(buf, 0, &value) || value == 0) + return -EINVAL; + + if (!drvdata->enable) { + ret = pm_runtime_get_sync(drvdata->dev); + if (ret < 0) { + pm_runtime_put(drvdata->dev); + return ret; + } + } + + spin_lock(&drvdata->spinlock); + CS_UNLOCK(drvdata->base); + + tgu_writel(drvdata, 0, TGU_CONTROL); + + if (drvdata->value_table->priority) + memset(drvdata->value_table->priority, 0, + MAX_PRIORITY * drvdata->max_step * + drvdata->max_reg * sizeof(unsigned int)); + + if (drvdata->value_table->condition_decode) + memset(drvdata->value_table->condition_decode, 0, + drvdata->max_condition_decode * drvdata->max_step * + sizeof(unsigned int)); + + /* Initialize all condition registers to NOT(value=0x1000000) */ + for (i = 0; i < drvdata->max_step; i++) { + for (j = 0; j < drvdata->max_condition_decode; j++) { + drvdata->value_table + ->condition_decode[calculate_array_location( + drvdata, i, TGU_CONDITION_DECODE, j)] = + 0x1000000; + } + } + + if (drvdata->value_table->condition_select) + memset(drvdata->value_table->condition_select, 0, + drvdata->max_condition_select * drvdata->max_step * + sizeof(unsigned int)); + + if (drvdata->value_table->timer) + memset(drvdata->value_table->timer, 0, + (drvdata->max_step) * + (drvdata->max_timer) * + sizeof(unsigned int)); + + if (drvdata->value_table->counter) + memset(drvdata->value_table->counter, 0, + (drvdata->max_step) * + (drvdata->max_counter) * + sizeof(unsigned int)); + + dev_dbg(dev, "Coresight-TGU reset complete\n"); + + CS_LOCK(drvdata->base); + + drvdata->enable = false; + spin_unlock(&drvdata->spinlock); + pm_runtime_put(drvdata->dev); + + return size; +} +static DEVICE_ATTR_WO(reset_tgu); + static const struct coresight_ops_helper tgu_helper_ops = { .enable = tgu_enable, .disable = tgu_disable, @@ -484,6 +558,7 @@ static const struct coresight_ops tgu_ops = { static struct attribute *tgu_common_attrs[] = { &dev_attr_enable_tgu.attr, + &dev_attr_reset_tgu.attr, NULL, }; From f2fbe399cf1556e0624d4a292b3e38db9b57949c Mon Sep 17 00:00:00 2001 From: Yingchao Deng Date: Tue, 22 Jul 2025 01:14:04 -0700 Subject: [PATCH 0072/2333] FROMLIST: dt-bindings: arm: Add Qualcomm extended CTI Add Qualcomm extended CTI support in CTI binding file. Qualcomm extended CTI supports up to 128 triggers. Link: https://lore.kernel.org/all/20250722081405.2947294-2-quic_jinlmao@quicinc.com/ Signed-off-by: Yingchao Deng Signed-off-by: Mao Jinlong --- Documentation/devicetree/bindings/arm/arm,coresight-cti.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/arm/arm,coresight-cti.yaml b/Documentation/devicetree/bindings/arm/arm,coresight-cti.yaml index 2a91670ccb8cd..16b30ecb9e4ab 100644 --- a/Documentation/devicetree/bindings/arm/arm,coresight-cti.yaml +++ b/Documentation/devicetree/bindings/arm/arm,coresight-cti.yaml @@ -84,7 +84,9 @@ properties: - const: arm,coresight-cti - const: arm,primecell - items: - - const: arm,coresight-cti-v8-arch + - enum: + - arm,coresight-cti-v8-arch + - qcom,coresight-cti-extended - const: arm,coresight-cti - const: arm,primecell From 727fb4852e5d9db33d62fa08c7bf920e003ee49f Mon Sep 17 00:00:00 2001 From: Yingchao Deng Date: Tue, 22 Jul 2025 01:14:05 -0700 Subject: [PATCH 0073/2333] FROMLIST: coresight: cti: Add Qualcomm extended CTI support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The QCOM extended CTI is a heavily parameterized version of ARM’s CSCTI. It allows a debugger to send to trigger events to a processor or to send a trigger event to one or more processors when a trigger event occurs on another processor on the same SoC, or even between SoCs. For Qualcomm extended CTI, it supports up to 128 triggers. Link: https://lore.kernel.org/all/20250722081405.2947294-3-quic_jinlmao@quicinc.com/ Signed-off-by: Yingchao Deng Signed-off-by: Mao Jinlong --- .../hwtracing/coresight/coresight-cti-core.c | 127 +++++++++++++---- .../coresight/coresight-cti-platform.c | 16 ++- .../hwtracing/coresight/coresight-cti-sysfs.c | 128 ++++++++++++++---- drivers/hwtracing/coresight/coresight-cti.h | 75 +++++----- 4 files changed, 245 insertions(+), 101 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-cti-core.c b/drivers/hwtracing/coresight/coresight-cti-core.c index 8fb30dd73fd20..d6a28df484846 100644 --- a/drivers/hwtracing/coresight/coresight-cti-core.c +++ b/drivers/hwtracing/coresight/coresight-cti-core.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -22,6 +23,54 @@ #include "coresight-priv.h" #include "coresight-cti.h" +#define CTI_EXTENDED "qcom,coresight-cti-extended" + +static const int cti_normal_offset[] = { + [CTIINTACK] = 0x010, + [CTIAPPSET] = 0x014, + [CTIAPPCLEAR] = 0x018, + [CTIAPPPULSE] = 0x01C, + [CTIINEN] = 0x020, + [CTIOUTEN] = 0x0A0, + [CTITRIGINSTATUS] = 0x130, + [CTITRIGOUTSTATUS] = 0x134, + [CTICHINSTATUS] = 0x138, + [CTICHOUTSTATUS] = 0x13C, + [CTIGATE] = 0x140, + [ASICCTL] = 0x144, + [ITCHINACK] = 0xEDC, + [ITTRIGINACK] = 0xEE0, + [ITCHOUT] = 0xEE4, + [ITTRIGOUT] = 0xEE8, + [ITCHOUTACK] = 0xEEC, + [ITTRIGOUTACK] = 0xEF0, + [ITCHIN] = 0xEF4, + [ITTRIGIN] = 0xEF8, +}; + +static const int cti_extended_offset[] = { + [CTIINTACK] = 0x020, + [CTIAPPSET] = 0x004, + [CTIAPPCLEAR] = 0x008, + [CTIAPPPULSE] = 0x00C, + [CTIINEN] = 0x400, + [CTIOUTEN] = 0x800, + [CTITRIGINSTATUS] = 0x040, + [CTITRIGOUTSTATUS] = 0x060, + [CTICHINSTATUS] = 0x080, + [CTICHOUTSTATUS] = 0x084, + [CTIGATE] = 0x088, + [ASICCTL] = 0x08c, + [ITCHINACK] = 0xE70, + [ITTRIGINACK] = 0xE80, + [ITCHOUT] = 0xE74, + [ITTRIGOUT] = 0xEA0, + [ITCHOUTACK] = 0xE78, + [ITTRIGOUTACK] = 0xEC0, + [ITCHIN] = 0xE7C, + [ITTRIGIN] = 0xEE0, +}; + /* * CTI devices can be associated with a PE, or be connected to CoreSight * hardware. We have a list of all CTIs irrespective of CPU bound or @@ -57,6 +106,12 @@ static struct cti_drvdata *cti_cpu_drvdata[NR_CPUS]; */ DEFINE_CORESIGHT_DEVLIST(cti_sys_devs, "cti_sys"); +u32 cti_offset(struct cti_drvdata *drvdata, int index, int num) +{ + return (drvdata->is_extended_cti ? cti_extended_offset[index] + : cti_normal_offset[index]) + (4 * num); +} + /* write set of regs to hardware - call with spinlock claimed */ void cti_write_all_hw_regs(struct cti_drvdata *drvdata) { @@ -70,15 +125,15 @@ void cti_write_all_hw_regs(struct cti_drvdata *drvdata) /* write the CTI trigger registers */ for (i = 0; i < config->nr_trig_max; i++) { - writel_relaxed(config->ctiinen[i], drvdata->base + CTIINEN(i)); + writel_relaxed(config->ctiinen[i], drvdata->base + cti_offset(drvdata, CTIINEN, i)); writel_relaxed(config->ctiouten[i], - drvdata->base + CTIOUTEN(i)); + drvdata->base + cti_offset(drvdata, CTIOUTEN, i)); } /* other regs */ - writel_relaxed(config->ctigate, drvdata->base + CTIGATE); - writel_relaxed(config->asicctl, drvdata->base + ASICCTL); - writel_relaxed(config->ctiappset, drvdata->base + CTIAPPSET); + writel_relaxed(config->ctigate, drvdata->base + cti_offset(drvdata, CTIGATE, 0)); + writel_relaxed(config->asicctl, drvdata->base + cti_offset(drvdata, ASICCTL, 0)); + writel_relaxed(config->ctiappset, drvdata->base + cti_offset(drvdata, CTIAPPSET, 0)); /* re-enable CTI */ writel_relaxed(1, drvdata->base + CTICONTROL); @@ -99,10 +154,13 @@ static int cti_enable_hw(struct cti_drvdata *drvdata) if (config->hw_enabled || !config->hw_powered) goto cti_state_unchanged; - /* claim the device */ - rc = coresight_claim_device(drvdata->csdev); - if (rc) - goto cti_err_not_enabled; + /* There is no relationship between the CLR and SET pair for extended CTI. */ + if (!drvdata->is_extended_cti) { + /* claim the device */ + rc = coresight_claim_device(drvdata->csdev); + if (rc) + goto cti_err_not_enabled; + } cti_write_all_hw_regs(drvdata); @@ -175,7 +233,8 @@ static int cti_disable_hw(struct cti_drvdata *drvdata) writel_relaxed(0, drvdata->base + CTICONTROL); config->hw_enabled = false; - coresight_disclaim_device_unlocked(csdev); + if (!drvdata->is_extended_cti) + coresight_disclaim_device_unlocked(csdev); CS_LOCK(drvdata->base); raw_spin_unlock(&drvdata->spinlock); return ret; @@ -270,8 +329,10 @@ int cti_add_connection_entry(struct device *dev, struct cti_drvdata *drvdata, cti_dev->nr_trig_con++; /* add connection usage bit info to overall info */ - drvdata->config.trig_in_use |= tc->con_in->used_mask; - drvdata->config.trig_out_use |= tc->con_out->used_mask; + bitmap_or(drvdata->config.trig_in_use, drvdata->config.trig_in_use, + tc->con_in->used_mask, drvdata->config.nr_trig_max); + bitmap_or(drvdata->config.trig_out_use, drvdata->config.trig_out_use, + tc->con_out->used_mask, drvdata->config.nr_trig_max); return 0; } @@ -314,7 +375,6 @@ int cti_add_default_connection(struct device *dev, struct cti_drvdata *drvdata) { int ret = 0; int n_trigs = drvdata->config.nr_trig_max; - u32 n_trig_mask = GENMASK(n_trigs - 1, 0); struct cti_trig_con *tc = NULL; /* @@ -325,8 +385,9 @@ int cti_add_default_connection(struct device *dev, struct cti_drvdata *drvdata) if (!tc) return -ENOMEM; - tc->con_in->used_mask = n_trig_mask; - tc->con_out->used_mask = n_trig_mask; + bitmap_fill(tc->con_in->used_mask, n_trigs); + bitmap_fill(tc->con_out->used_mask, n_trigs); + ret = cti_add_connection_entry(dev, drvdata, tc, NULL, "default"); return ret; } @@ -339,7 +400,6 @@ int cti_channel_trig_op(struct device *dev, enum cti_chan_op op, { struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent); struct cti_config *config = &drvdata->config; - u32 trig_bitmask; u32 chan_bitmask; u32 reg_value; int reg_offset; @@ -349,25 +409,23 @@ int cti_channel_trig_op(struct device *dev, enum cti_chan_op op, (trigger_idx >= config->nr_trig_max)) return -EINVAL; - trig_bitmask = BIT(trigger_idx); - /* ensure registered triggers and not out filtered */ if (direction == CTI_TRIG_IN) { - if (!(trig_bitmask & config->trig_in_use)) + if (!(test_bit(trigger_idx, config->trig_in_use))) return -EINVAL; } else { - if (!(trig_bitmask & config->trig_out_use)) + if (!(test_bit(trigger_idx, config->trig_out_use))) return -EINVAL; if ((config->trig_filter_enable) && - (config->trig_out_filter & trig_bitmask)) + test_bit(trigger_idx, config->trig_out_filter)) return -EINVAL; } /* update the local register values */ chan_bitmask = BIT(channel_idx); - reg_offset = (direction == CTI_TRIG_IN ? CTIINEN(trigger_idx) : - CTIOUTEN(trigger_idx)); + reg_offset = (direction == CTI_TRIG_IN ? cti_offset(drvdata, CTIINEN, trigger_idx) : + cti_offset(drvdata, CTIOUTEN, trigger_idx)); raw_spin_lock(&drvdata->spinlock); @@ -451,19 +509,19 @@ int cti_channel_setop(struct device *dev, enum cti_chan_set_op op, case CTI_CHAN_SET: config->ctiappset |= chan_bitmask; reg_value = config->ctiappset; - reg_offset = CTIAPPSET; + reg_offset = cti_offset(drvdata, CTIAPPSET, 0); break; case CTI_CHAN_CLR: config->ctiappset &= ~chan_bitmask; reg_value = chan_bitmask; - reg_offset = CTIAPPCLEAR; + reg_offset = cti_offset(drvdata, CTIAPPCLEAR, 0); break; case CTI_CHAN_PULSE: config->ctiappset &= ~chan_bitmask; reg_value = chan_bitmask; - reg_offset = CTIAPPPULSE; + reg_offset = cti_offset(drvdata, CTIAPPPULSE, 0); break; default: @@ -857,6 +915,19 @@ static void cti_remove(struct amba_device *adev) coresight_unregister(drvdata->csdev); } +static bool of_is_extended_cti(struct device *dev) +{ + struct fwnode_handle *fwnode = dev_fwnode(dev); + + if (is_of_node(fwnode)) { + if (of_device_is_compatible(to_of_node(fwnode), + CTI_EXTENDED)) + return true; + } + + return false; +} + static int cti_probe(struct amba_device *adev, const struct amba_id *id) { int ret = 0; @@ -950,9 +1021,11 @@ static int cti_probe(struct amba_device *adev, const struct amba_id *id) drvdata->csdev_release = drvdata->csdev->dev.release; drvdata->csdev->dev.release = cti_device_release; + drvdata->is_extended_cti = of_is_extended_cti(dev); + /* all done - dec pm refcount */ pm_runtime_put(&adev->dev); - dev_info(&drvdata->csdev->dev, "CTI initialized\n"); + dev_info(&drvdata->csdev->dev, "CTI initialized %d\n", drvdata->is_extended_cti); return 0; pm_release: diff --git a/drivers/hwtracing/coresight/coresight-cti-platform.c b/drivers/hwtracing/coresight/coresight-cti-platform.c index d0ae10bf61281..4bef860a0484d 100644 --- a/drivers/hwtracing/coresight/coresight-cti-platform.c +++ b/drivers/hwtracing/coresight/coresight-cti-platform.c @@ -136,8 +136,8 @@ static int cti_plat_create_v8_etm_connection(struct device *dev, goto create_v8_etm_out; /* build connection data */ - tc->con_in->used_mask = 0xF0; /* sigs <4,5,6,7> */ - tc->con_out->used_mask = 0xF0; /* sigs <4,5,6,7> */ + bitmap_set(tc->con_in->used_mask, 4, 4); /* sigs <4,5,6,7> */ + bitmap_set(tc->con_out->used_mask, 4, 4); /* sigs <4,5,6,7> */ /* * The EXTOUT type signals from the ETM are connected to a set of input @@ -194,10 +194,10 @@ static int cti_plat_create_v8_connections(struct device *dev, goto of_create_v8_out; /* Set the v8 PE CTI connection data */ - tc->con_in->used_mask = 0x3; /* sigs <0 1> */ + bitmap_set(tc->con_in->used_mask, 0, 2); /* sigs <0 1> */ tc->con_in->sig_types[0] = PE_DBGTRIGGER; tc->con_in->sig_types[1] = PE_PMUIRQ; - tc->con_out->used_mask = 0x7; /* sigs <0 1 2 > */ + bitmap_set(tc->con_out->used_mask, 0, 3); /* sigs <0 1 2 > */ tc->con_out->sig_types[0] = PE_EDBGREQ; tc->con_out->sig_types[1] = PE_DBGRESTART; tc->con_out->sig_types[2] = PE_CTIIRQ; @@ -213,7 +213,7 @@ static int cti_plat_create_v8_connections(struct device *dev, goto of_create_v8_out; /* filter pe_edbgreq - PE trigout sig <0> */ - drvdata->config.trig_out_filter |= 0x1; + set_bit(0, drvdata->config.trig_out_filter); of_create_v8_out: return ret; @@ -257,7 +257,7 @@ static int cti_plat_read_trig_group(struct cti_trig_grp *tgrp, if (!err) { /* set the signal usage mask */ for (idx = 0; idx < tgrp->nr_sigs; idx++) - tgrp->used_mask |= BIT(values[idx]); + set_bit(values[idx], tgrp->used_mask); } kfree(values); @@ -331,7 +331,9 @@ static int cti_plat_process_filter_sigs(struct cti_drvdata *drvdata, err = cti_plat_read_trig_group(tg, fwnode, CTI_DT_FILTER_OUT_SIGS); if (!err) - drvdata->config.trig_out_filter |= tg->used_mask; + bitmap_or(drvdata->config.trig_out_filter, + drvdata->config.trig_out_filter, + tg->used_mask, drvdata->config.nr_trig_max); kfree(tg); return err; diff --git a/drivers/hwtracing/coresight/coresight-cti-sysfs.c b/drivers/hwtracing/coresight/coresight-cti-sysfs.c index 572b80ee96fbf..cc680a4b900a7 100644 --- a/drivers/hwtracing/coresight/coresight-cti-sysfs.c +++ b/drivers/hwtracing/coresight/coresight-cti-sysfs.c @@ -172,9 +172,8 @@ static struct attribute *coresight_cti_attrs[] = { /* register based attributes */ -/* Read registers with power check only (no enable check). */ -static ssize_t coresight_cti_reg_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t coresight_cti_mgmt_reg_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent); struct cs_off_attribute *cti_attr = container_of(attr, struct cs_off_attribute, attr); @@ -189,6 +188,53 @@ static ssize_t coresight_cti_reg_show(struct device *dev, return sysfs_emit(buf, "0x%x\n", val); } +/* Read registers with power check only (no enable check). */ +static ssize_t coresight_cti_reg_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent); + struct cs_off_attribute *cti_attr = container_of(attr, struct cs_off_attribute, attr); + struct cti_config *cfg = &drvdata->config; + u32 val = 0; + int i, num; + ssize_t size = 0; + + pm_runtime_get_sync(dev->parent); + raw_spin_lock(&drvdata->spinlock); + if (drvdata->config.hw_powered) { + switch (cti_attr->off) { + case CTICHINSTATUS: + case CTICHOUTSTATUS: + case ITCHINACK: + case ITCHOUT: + case ITCHOUTACK: + case ITCHIN: + val = readl_relaxed(drvdata->base + cti_offset(drvdata, cti_attr->off, 0)); + size += sysfs_emit(buf, "0x%x\n", val); + break; + + case CTITRIGINSTATUS: + case CTITRIGOUTSTATUS: + case ITTRIGINACK: + case ITTRIGOUT: + case ITTRIGOUTACK: + case ITTRIGIN: + num = (cfg->nr_trig_max - 1) / 32; + for (i = 0; i <= num; i++) { + val = readl_relaxed(drvdata->base + + cti_offset(drvdata, cti_attr->off, i)); + size += sysfs_emit_at(buf, size, "0x%x ", val); + } + if (size > 0) + buf[size - 1] = '\n'; + break; + } + } + raw_spin_unlock(&drvdata->spinlock); + pm_runtime_put_sync(dev->parent); + return size; +} + /* Write registers with power check only (no enable check). */ static __maybe_unused ssize_t coresight_cti_reg_store(struct device *dev, struct device_attribute *attr, @@ -197,19 +243,45 @@ static __maybe_unused ssize_t coresight_cti_reg_store(struct device *dev, struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent); struct cs_off_attribute *cti_attr = container_of(attr, struct cs_off_attribute, attr); unsigned long val = 0; + int num, i; if (kstrtoul(buf, 0, &val)) return -EINVAL; pm_runtime_get_sync(dev->parent); raw_spin_lock(&drvdata->spinlock); - if (drvdata->config.hw_powered) - cti_write_single_reg(drvdata, cti_attr->off, val); + if (drvdata->config.hw_powered) { + switch (cti_attr->off) { + case ITCHINACK: + case ITCHOUT: + cti_write_single_reg(drvdata, cti_offset(drvdata, cti_attr->off, 0), val); + break; + + case ITTRIGINACK: + case ITTRIGOUT: + case ITTRIGOUTACK: + num = val / 32; + i = val % 32; + for (i = 0; i <= num; i++) + cti_write_single_reg(drvdata, + cti_offset(drvdata, cti_attr->off, i), BIT(i)); + break; + } + } + raw_spin_unlock(&drvdata->spinlock); pm_runtime_put_sync(dev->parent); return size; } +#define coresight_cti_mgmt_reg(name, offset) \ + (&((struct cs_off_attribute[]) { \ + { \ + __ATTR(name, 0444, coresight_cti_mgmt_reg_show, NULL), \ + offset \ + } \ + })[0].attr.attr) + #define coresight_cti_reg(name, offset) \ (&((struct cs_off_attribute[]) { \ { \ @@ -237,17 +309,17 @@ static __maybe_unused ssize_t coresight_cti_reg_store(struct device *dev, /* coresight management registers */ static struct attribute *coresight_cti_mgmt_attrs[] = { - coresight_cti_reg(devaff0, CTIDEVAFF0), - coresight_cti_reg(devaff1, CTIDEVAFF1), - coresight_cti_reg(authstatus, CORESIGHT_AUTHSTATUS), - coresight_cti_reg(devarch, CORESIGHT_DEVARCH), - coresight_cti_reg(devid, CORESIGHT_DEVID), - coresight_cti_reg(devtype, CORESIGHT_DEVTYPE), - coresight_cti_reg(pidr0, CORESIGHT_PERIPHIDR0), - coresight_cti_reg(pidr1, CORESIGHT_PERIPHIDR1), - coresight_cti_reg(pidr2, CORESIGHT_PERIPHIDR2), - coresight_cti_reg(pidr3, CORESIGHT_PERIPHIDR3), - coresight_cti_reg(pidr4, CORESIGHT_PERIPHIDR4), + coresight_cti_mgmt_reg(devaff0, CTIDEVAFF0), + coresight_cti_mgmt_reg(devaff1, CTIDEVAFF1), + coresight_cti_mgmt_reg(authstatus, CORESIGHT_AUTHSTATUS), + coresight_cti_mgmt_reg(devarch, CORESIGHT_DEVARCH), + coresight_cti_mgmt_reg(devid, CORESIGHT_DEVID), + coresight_cti_mgmt_reg(devtype, CORESIGHT_DEVTYPE), + coresight_cti_mgmt_reg(pidr0, CORESIGHT_PERIPHIDR0), + coresight_cti_mgmt_reg(pidr1, CORESIGHT_PERIPHIDR1), + coresight_cti_mgmt_reg(pidr2, CORESIGHT_PERIPHIDR2), + coresight_cti_mgmt_reg(pidr3, CORESIGHT_PERIPHIDR3), + coresight_cti_mgmt_reg(pidr4, CORESIGHT_PERIPHIDR4), NULL, }; @@ -284,11 +356,12 @@ static ssize_t cti_reg32_show(struct device *dev, char *buf, * if reg_offset >= 0 then write through if enabled. */ static ssize_t cti_reg32_store(struct device *dev, const char *buf, - size_t size, u32 *pcached_val, int reg_offset) + size_t size, u32 *pcached_val, int index) { unsigned long val; struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent); struct cti_config *config = &drvdata->config; + int reg_offset; if (kstrtoul(buf, 0, &val)) return -EINVAL; @@ -298,6 +371,7 @@ static ssize_t cti_reg32_store(struct device *dev, const char *buf, if (pcached_val) *pcached_val = (u32)val; + reg_offset = cti_offset(drvdata, index, 0); /* write through if offset and enabled */ if ((reg_offset >= 0) && cti_active(config)) cti_write_single_reg(drvdata, reg_offset, val); @@ -306,14 +380,14 @@ static ssize_t cti_reg32_store(struct device *dev, const char *buf, } /* Standard macro for simple rw cti config registers */ -#define cti_config_reg32_rw(name, cfgname, offset) \ +#define cti_config_reg32_rw(name, cfgname, index) \ static ssize_t name##_show(struct device *dev, \ struct device_attribute *attr, \ char *buf) \ { \ struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent); \ return cti_reg32_show(dev, buf, \ - &drvdata->config.cfgname, offset); \ + &drvdata->config.cfgname, index); \ } \ \ static ssize_t name##_store(struct device *dev, \ @@ -322,7 +396,7 @@ static ssize_t name##_store(struct device *dev, \ { \ struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent); \ return cti_reg32_store(dev, buf, size, \ - &drvdata->config.cfgname, offset); \ + &drvdata->config.cfgname, index); \ } \ static DEVICE_ATTR_RW(name) @@ -389,7 +463,7 @@ static ssize_t inen_store(struct device *dev, /* write through if enabled */ if (cti_active(config)) - cti_write_single_reg(drvdata, CTIINEN(index), val); + cti_write_single_reg(drvdata, cti_offset(drvdata, CTIINEN, index), val); raw_spin_unlock(&drvdata->spinlock); return size; } @@ -428,7 +502,7 @@ static ssize_t outen_store(struct device *dev, /* write through if enabled */ if (cti_active(config)) - cti_write_single_reg(drvdata, CTIOUTEN(index), val); + cti_write_single_reg(drvdata, cti_offset(drvdata, CTIOUTEN, index), val); raw_spin_unlock(&drvdata->spinlock); return size; } @@ -711,10 +785,8 @@ static ssize_t trigout_filtered_show(struct device *dev, struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent); struct cti_config *cfg = &drvdata->config; int size = 0, nr_trig_max = cfg->nr_trig_max; - unsigned long mask = cfg->trig_out_filter; - if (mask) - size = bitmap_print_to_pagebuf(true, buf, &mask, nr_trig_max); + size = bitmap_print_to_pagebuf(true, buf, cfg->trig_out_filter, nr_trig_max); return size; } static DEVICE_ATTR_RO(trigout_filtered); @@ -926,9 +998,8 @@ static ssize_t trigin_sig_show(struct device *dev, struct cti_trig_con *con = (struct cti_trig_con *)ext_attr->var; struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent); struct cti_config *cfg = &drvdata->config; - unsigned long mask = con->con_in->used_mask; - return bitmap_print_to_pagebuf(true, buf, &mask, cfg->nr_trig_max); + return bitmap_print_to_pagebuf(true, buf, con->con_in->used_mask, cfg->nr_trig_max); } static ssize_t trigout_sig_show(struct device *dev, @@ -940,9 +1011,8 @@ static ssize_t trigout_sig_show(struct device *dev, struct cti_trig_con *con = (struct cti_trig_con *)ext_attr->var; struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent); struct cti_config *cfg = &drvdata->config; - unsigned long mask = con->con_out->used_mask; - return bitmap_print_to_pagebuf(true, buf, &mask, cfg->nr_trig_max); + return bitmap_print_to_pagebuf(true, buf, con->con_out->used_mask, cfg->nr_trig_max); } /* convert a sig type id to a name */ diff --git a/drivers/hwtracing/coresight/coresight-cti.h b/drivers/hwtracing/coresight/coresight-cti.h index 8362a47c939c6..7d052e76d116d 100644 --- a/drivers/hwtracing/coresight/coresight-cti.h +++ b/drivers/hwtracing/coresight/coresight-cti.h @@ -18,46 +18,42 @@ struct fwnode_handle; -/* - * Device registers - * 0x000 - 0x144: CTI programming and status - * 0xEDC - 0xEF8: CTI integration test. - * 0xF00 - 0xFFC: Coresight management registers. - */ -/* CTI programming registers */ -#define CTICONTROL 0x000 -#define CTIINTACK 0x010 -#define CTIAPPSET 0x014 -#define CTIAPPCLEAR 0x018 -#define CTIAPPPULSE 0x01C -#define CTIINEN(n) (0x020 + (4 * n)) -#define CTIOUTEN(n) (0x0A0 + (4 * n)) -#define CTITRIGINSTATUS 0x130 -#define CTITRIGOUTSTATUS 0x134 -#define CTICHINSTATUS 0x138 -#define CTICHOUTSTATUS 0x13C -#define CTIGATE 0x140 -#define ASICCTL 0x144 -/* Integration test registers */ -#define ITCHINACK 0xEDC /* WO CTI CSSoc 400 only*/ -#define ITTRIGINACK 0xEE0 /* WO CTI CSSoc 400 only*/ -#define ITCHOUT 0xEE4 /* WO RW-600 */ -#define ITTRIGOUT 0xEE8 /* WO RW-600 */ -#define ITCHOUTACK 0xEEC /* RO CTI CSSoc 400 only*/ -#define ITTRIGOUTACK 0xEF0 /* RO CTI CSSoc 400 only*/ -#define ITCHIN 0xEF4 /* RO */ -#define ITTRIGIN 0xEF8 /* RO */ -/* management registers */ -#define CTIDEVAFF0 0xFA8 -#define CTIDEVAFF1 0xFAC - /* * CTI CSSoc 600 has a max of 32 trigger signals per direction. * CTI CSSoc 400 has 8 IO triggers - other CTIs can be impl def. * Max of in and out defined in the DEVID register. * - pick up actual number used from .dts parameters if present. */ -#define CTIINOUTEN_MAX 32 +#define CTIINOUTEN_MAX 128 + +#define CTICONTROL 0x000 + +/* management registers */ +#define CTIDEVAFF0 0xFA8 +#define CTIDEVAFF1 0xFAC + +enum cti_offset_index { + CTIINTACK, + CTIAPPSET, + CTIAPPCLEAR, + CTIAPPPULSE, + CTIINEN, + CTIOUTEN, + CTITRIGINSTATUS, + CTITRIGOUTSTATUS, + CTICHINSTATUS, + CTICHOUTSTATUS, + CTIGATE, + ASICCTL, + ITCHINACK, + ITTRIGINACK, + ITCHOUT, + ITTRIGOUT, + ITCHOUTACK, + ITTRIGOUTACK, + ITCHIN, + ITTRIGIN, +}; /** * Group of related trigger signals @@ -68,7 +64,7 @@ struct fwnode_handle; */ struct cti_trig_grp { int nr_sigs; - u32 used_mask; + DECLARE_BITMAP(used_mask, CTIINOUTEN_MAX); int sig_types[]; }; @@ -147,9 +143,10 @@ struct cti_config { bool hw_powered; /* registered triggers and filtering */ - u32 trig_in_use; - u32 trig_out_use; - u32 trig_out_filter; + DECLARE_BITMAP(trig_in_use, CTIINOUTEN_MAX); + DECLARE_BITMAP(trig_out_use, CTIINOUTEN_MAX); + DECLARE_BITMAP(trig_out_filter, CTIINOUTEN_MAX); + bool trig_filter_enable; u8 xtrig_rchan_sel; @@ -180,6 +177,7 @@ struct cti_drvdata { struct cti_config config; struct list_head node; void (*csdev_release)(struct device *dev); + bool is_extended_cti; }; /* @@ -232,6 +230,7 @@ int cti_create_cons_sysfs(struct device *dev, struct cti_drvdata *drvdata); struct coresight_platform_data * coresight_cti_get_platform_data(struct device *dev); const char *cti_plat_get_node_name(struct fwnode_handle *fwnode); +u32 cti_offset(struct cti_drvdata *drvdata, int index, int num); /* cti powered and enabled */ static inline bool cti_active(struct cti_config *cfg) From 6f36d44bd451d7535ebc879b00a474c9a4ad5a0b Mon Sep 17 00:00:00 2001 From: Jie Gan Date: Fri, 22 Aug 2025 18:30:07 +0800 Subject: [PATCH 0074/2333] FROMLIST: coresight: tpdm: add static tpdm support The static TPDM function as a dummy source, however, it is essential to enable the port connected to the TPDA and configure the element size. Without this, the TPDA cannot correctly receive trace data from the static TPDM. Since the static TPDM does not require MMIO mapping to access its registers, a clock controller is not mandatory for its operation. Link: https://lore.kernel.org/all/20250822103008.1029-3-jie.gan@oss.qualcomm.com/ Signed-off-by: Jie Gan --- drivers/hwtracing/coresight/coresight-tpda.c | 9 ++ drivers/hwtracing/coresight/coresight-tpdm.c | 148 ++++++++++++++----- drivers/hwtracing/coresight/coresight-tpdm.h | 8 + 3 files changed, 131 insertions(+), 34 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-tpda.c b/drivers/hwtracing/coresight/coresight-tpda.c index 333b3cb236859..4e93fa5bace48 100644 --- a/drivers/hwtracing/coresight/coresight-tpda.c +++ b/drivers/hwtracing/coresight/coresight-tpda.c @@ -68,6 +68,15 @@ static int tpdm_read_element_size(struct tpda_drvdata *drvdata, int rc = -EINVAL; struct tpdm_drvdata *tpdm_data = dev_get_drvdata(csdev->dev.parent); + if (coresight_is_static_tpdm(csdev)) { + rc = fwnode_property_read_u32(dev_fwnode(csdev->dev.parent), + "qcom,dsb-element-bits", &drvdata->dsb_esize); + rc &= fwnode_property_read_u32(dev_fwnode(csdev->dev.parent), + "qcom,cmb-element-bits", &drvdata->cmb_esize); + + goto out; + } + if (tpdm_data->dsb) { rc = fwnode_property_read_u32(dev_fwnode(csdev->dev.parent), "qcom,dsb-element-bits", &drvdata->dsb_esize); diff --git a/drivers/hwtracing/coresight/coresight-tpdm.c b/drivers/hwtracing/coresight/coresight-tpdm.c index 7214e65097ec9..1766b01828192 100644 --- a/drivers/hwtracing/coresight/coresight-tpdm.c +++ b/drivers/hwtracing/coresight/coresight-tpdm.c @@ -495,7 +495,9 @@ static int tpdm_enable(struct coresight_device *csdev, struct perf_event *event, return -EBUSY; } - __tpdm_enable(drvdata); + if (!coresight_is_static_tpdm(csdev)) + __tpdm_enable(drvdata); + drvdata->enable = true; spin_unlock(&drvdata->spinlock); @@ -551,7 +553,9 @@ static void tpdm_disable(struct coresight_device *csdev, return; } - __tpdm_disable(drvdata); + if (!coresight_is_static_tpdm(csdev)) + __tpdm_disable(drvdata); + coresight_set_mode(csdev, CS_MODE_DISABLED); drvdata->enable = false; spin_unlock(&drvdata->spinlock); @@ -1342,10 +1346,9 @@ static const struct attribute_group *tpdm_attr_grps[] = { NULL, }; -static int tpdm_probe(struct amba_device *adev, const struct amba_id *id) +static int tpdm_probe(struct device *dev, struct resource *res) { void __iomem *base; - struct device *dev = &adev->dev; struct coresight_platform_data *pdata; struct tpdm_drvdata *drvdata; struct coresight_desc desc = { 0 }; @@ -1354,32 +1357,33 @@ static int tpdm_probe(struct amba_device *adev, const struct amba_id *id) pdata = coresight_get_platform_data(dev); if (IS_ERR(pdata)) return PTR_ERR(pdata); - adev->dev.platform_data = pdata; + dev->platform_data = pdata; /* driver data*/ drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL); if (!drvdata) return -ENOMEM; - drvdata->dev = &adev->dev; + drvdata->dev = dev; dev_set_drvdata(dev, drvdata); - base = devm_ioremap_resource(dev, &adev->res); - if (IS_ERR(base)) - return PTR_ERR(base); + if (res) { + base = devm_ioremap_resource(dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); - drvdata->base = base; + drvdata->base = base; + ret = tpdm_datasets_setup(drvdata); + if (ret) + return ret; - ret = tpdm_datasets_setup(drvdata); - if (ret) - return ret; + if (drvdata && tpdm_has_dsb_dataset(drvdata)) + of_property_read_u32(drvdata->dev->of_node, + "qcom,dsb-msrs-num", &drvdata->dsb_msr_num); - if (drvdata && tpdm_has_dsb_dataset(drvdata)) - of_property_read_u32(drvdata->dev->of_node, - "qcom,dsb-msrs-num", &drvdata->dsb_msr_num); - - if (drvdata && tpdm_has_cmb_dataset(drvdata)) - of_property_read_u32(drvdata->dev->of_node, - "qcom,cmb-msrs-num", &drvdata->cmb_msr_num); + if (drvdata && tpdm_has_cmb_dataset(drvdata)) + of_property_read_u32(drvdata->dev->of_node, + "qcom,cmb-msrs-num", &drvdata->cmb_msr_num); + } /* Set up coresight component description */ desc.name = coresight_alloc_device_name(&tpdm_devs, dev); @@ -1388,34 +1392,51 @@ static int tpdm_probe(struct amba_device *adev, const struct amba_id *id) desc.type = CORESIGHT_DEV_TYPE_SOURCE; desc.subtype.source_subtype = CORESIGHT_DEV_SUBTYPE_SOURCE_TPDM; desc.ops = &tpdm_cs_ops; - desc.pdata = adev->dev.platform_data; - desc.dev = &adev->dev; + desc.pdata = dev->platform_data; + desc.dev = dev; desc.access = CSDEV_ACCESS_IOMEM(base); - desc.groups = tpdm_attr_grps; + if (res) + desc.groups = tpdm_attr_grps; drvdata->csdev = coresight_register(&desc); if (IS_ERR(drvdata->csdev)) return PTR_ERR(drvdata->csdev); spin_lock_init(&drvdata->spinlock); - /* Decrease pm refcount when probe is done.*/ - pm_runtime_put(&adev->dev); - return 0; } -static void tpdm_remove(struct amba_device *adev) +static int tpdm_remove(struct device *dev) { - struct tpdm_drvdata *drvdata = dev_get_drvdata(&adev->dev); + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev); coresight_unregister(drvdata->csdev); + + return 0; +} + +static int dynamic_tpdm_probe(struct amba_device *adev, + const struct amba_id *id) +{ + int ret; + + ret = tpdm_probe(&adev->dev, &adev->res); + if (!ret) + pm_runtime_put(&adev->dev); + + return ret; +} + +static void dynamic_tpdm_remove(struct amba_device *adev) +{ + tpdm_remove(&adev->dev); } /* * Different TPDM has different periph id. * The difference is 0-7 bits' value. So ignore 0-7 bits. */ -static const struct amba_id tpdm_ids[] = { +static const struct amba_id dynamic_tpdm_ids[] = { { .id = 0x001f0e00, .mask = 0x00ffff00, @@ -1423,17 +1444,76 @@ static const struct amba_id tpdm_ids[] = { { 0, 0, NULL }, }; -static struct amba_driver tpdm_driver = { +MODULE_DEVICE_TABLE(amba, dynamic_tpdm_ids); + +static struct amba_driver dynamic_tpdm_driver = { .drv = { .name = "coresight-tpdm", .suppress_bind_attrs = true, }, - .probe = tpdm_probe, - .id_table = tpdm_ids, - .remove = tpdm_remove, + .probe = dynamic_tpdm_probe, + .id_table = dynamic_tpdm_ids, + .remove = dynamic_tpdm_remove, }; -module_amba_driver(tpdm_driver); +static int tpdm_platform_probe(struct platform_device *pdev) +{ + struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + int ret; + + pm_runtime_get_noresume(&pdev->dev); + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + + ret = tpdm_probe(&pdev->dev, res); + pm_runtime_put(&pdev->dev); + if (ret) + pm_runtime_disable(&pdev->dev); + + return ret; +} + +static void tpdm_platform_remove(struct platform_device *pdev) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(&pdev->dev); + + if (WARN_ON(!drvdata)) + return; + + tpdm_remove(&pdev->dev); + pm_runtime_disable(&pdev->dev); +} + +static const struct of_device_id static_tpdm_match[] = { + {.compatible = "qcom,coresight-static-tpdm"}, + {} +}; + +MODULE_DEVICE_TABLE(of, static_tpdm_match); + +static struct platform_driver static_tpdm_driver = { + .probe = tpdm_platform_probe, + .remove = tpdm_platform_remove, + .driver = { + .name = "coresight-static-tpdm", + .of_match_table = static_tpdm_match, + .suppress_bind_attrs = true, + }, +}; + +static int __init tpdm_init(void) +{ + return coresight_init_driver("tpdm", &dynamic_tpdm_driver, &static_tpdm_driver, + THIS_MODULE); +} + +static void __exit tpdm_exit(void) +{ + coresight_remove_driver(&dynamic_tpdm_driver, &static_tpdm_driver); +} + +module_init(tpdm_init); +module_exit(tpdm_exit); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Trace, Profiling & Diagnostic Monitor driver"); diff --git a/drivers/hwtracing/coresight/coresight-tpdm.h b/drivers/hwtracing/coresight/coresight-tpdm.h index b117543897344..9f52c88ce5c12 100644 --- a/drivers/hwtracing/coresight/coresight-tpdm.h +++ b/drivers/hwtracing/coresight/coresight-tpdm.h @@ -343,4 +343,12 @@ struct tpdm_dataset_attribute { enum dataset_mem mem; u32 idx; }; + +static inline bool coresight_is_static_tpdm(struct coresight_device *csdev) +{ + struct device_node *node = csdev->dev.parent->of_node; + + return (csdev && + of_device_is_compatible(node, "qcom,coresight-static-tpdm")); +} #endif /* _CORESIGHT_CORESIGHT_TPDM_H */ From e5d64529ff0fc90003fdae0659ea42186a812d13 Mon Sep 17 00:00:00 2001 From: Tao Zhang Date: Wed, 27 Aug 2025 18:55:43 +0800 Subject: [PATCH 0075/2333] FROMLIST: coresight: tpda: add sysfs nodes for tpda cross-trigger configuration Introduce sysfs nodes to configure cross-trigger parameters for TPDA. These registers define the characteristics of cross-trigger packets, including generation frequency and flag values. Link: https://lore.kernel.org/all/20250827105545.7140-2-jie.gan@oss.qualcomm.com/ Signed-off-by: Tao Zhang Co-developed-by: Jie Gan Signed-off-by: Jie Gan Reviewed-by: James Clark --- .../testing/sysfs-bus-coresight-devices-tpda | 43 ++++ drivers/hwtracing/coresight/coresight-tpda.c | 230 ++++++++++++++++++ drivers/hwtracing/coresight/coresight-tpda.h | 27 +- 3 files changed, 299 insertions(+), 1 deletion(-) create mode 100644 Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda new file mode 100644 index 0000000000000..fb651aebeb317 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda @@ -0,0 +1,43 @@ +What: /sys/bus/coresight/devices//trig_async_enable +Date: August 2025 +KernelVersion: 6.17 +Contact: Jinlong Mao , Tao Zhang , Jie Gan +Description: + (RW) Enable/disable cross trigger synchronization sequence interface. + +What: /sys/bus/coresight/devices//trig_flag_ts_enable +Date: August 2025 +KernelVersion: 6.17 +Contact: Jinlong Mao , Tao Zhang , Jie Gan +Description: + (RW) Enable/disable cross trigger FLAG packet request interface. + +What: /sys/bus/coresight/devices//trig_freq_enable +Date: August 2025 +KernelVersion: 6.17 +Contact: Jinlong Mao , Tao Zhang , Jie Gan +Description: + (RW) Enable/disable cross trigger FREQ packet request interface. + +What: /sys/bus/coresight/devices//freq_ts_enable +Date: August 2025 +KernelVersion: 6.17 +Contact: Jinlong Mao , Tao Zhang , Jie Gan +Description: + (RW) Enable/disable the timestamp for all FREQ packets. + +What: /sys/bus/coresight/devices//global_flush_req +Date: August 2025 +KernelVersion: 6.17 +Contact: Jinlong Mao , Tao Zhang , Jie Gan +Description: + (RW) Set global (all ports) flush request bit. The bit remains set until a + global flush request sequence completes. + +What: /sys/bus/coresight/devices//cmbchan_mode +Date: August 2025 +KernelVersion: 6.17 +Contact: Jinlong Mao , Tao Zhang , Jie Gan +Description: + (RW) Configure the CMB/MCMB channel mode for all enabled ports. + Value 0 means raw channel mapping mode. Value 1 means channel pair marking mode. diff --git a/drivers/hwtracing/coresight/coresight-tpda.c b/drivers/hwtracing/coresight/coresight-tpda.c index 4e93fa5bace48..d4d1def5ec151 100644 --- a/drivers/hwtracing/coresight/coresight-tpda.c +++ b/drivers/hwtracing/coresight/coresight-tpda.c @@ -156,9 +156,37 @@ static void tpda_enable_pre_port(struct tpda_drvdata *drvdata) u32 val; val = readl_relaxed(drvdata->base + TPDA_CR); + val &= ~TPDA_CR_MID; val &= ~TPDA_CR_ATID; val |= FIELD_PREP(TPDA_CR_ATID, drvdata->atid); + if (drvdata->trig_async) + val |= TPDA_CR_SRIE; + else + val &= ~TPDA_CR_SRIE; + if (drvdata->trig_flag_ts) + val |= TPDA_CR_FLRIE; + else + val &= ~TPDA_CR_FLRIE; + if (drvdata->trig_freq) + val |= TPDA_CR_FRIE; + else + val &= ~TPDA_CR_FRIE; + if (drvdata->freq_ts) + val |= TPDA_CR_FREQTS; + else + val &= ~TPDA_CR_FREQTS; + if (drvdata->cmbchan_mode) + val |= TPDA_CR_CMBCHANMODE; + else + val &= ~TPDA_CR_CMBCHANMODE; writel_relaxed(val, drvdata->base + TPDA_CR); + + /* + * If FLRIE bit is set, set the master and channel + * id as zero + */ + if (drvdata->trig_flag_ts) + writel_relaxed(0x0, drvdata->base + TPDA_FPID_CR); } static int tpda_enable_port(struct tpda_drvdata *drvdata, int port) @@ -274,6 +302,206 @@ static const struct coresight_ops tpda_cs_ops = { .link_ops = &tpda_link_ops, }; +static ssize_t trig_async_enable_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent); + + return sysfs_emit(buf, "%u\n", (unsigned int)drvdata->trig_async); +} + +static ssize_t trig_async_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val; + + if (kstrtoul(buf, 0, &val)) + return -EINVAL; + + guard(spinlock)(&drvdata->spinlock); + drvdata->trig_async = !!val; + + return size; +} +static DEVICE_ATTR_RW(trig_async_enable); + +static ssize_t trig_flag_ts_enable_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent); + + return sysfs_emit(buf, "%u\n", (unsigned int)drvdata->trig_flag_ts); +} + +static ssize_t trig_flag_ts_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val; + + if (kstrtoul(buf, 0, &val)) + return -EINVAL; + + guard(spinlock)(&drvdata->spinlock); + drvdata->trig_flag_ts = !!val; + + return size; +} +static DEVICE_ATTR_RW(trig_flag_ts_enable); + +static ssize_t trig_freq_enable_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent); + + return sysfs_emit(buf, "%u\n", (unsigned int)drvdata->trig_freq); +} + +static ssize_t trig_freq_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val; + + if (kstrtoul(buf, 0, &val)) + return -EINVAL; + + guard(spinlock)(&drvdata->spinlock); + drvdata->trig_freq = !!val; + + return size; +} +static DEVICE_ATTR_RW(trig_freq_enable); + +static ssize_t freq_ts_enable_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent); + + return sysfs_emit(buf, "%u\n", (unsigned int)drvdata->freq_ts); +} + +static ssize_t freq_ts_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val; + + if (kstrtoul(buf, 0, &val)) + return -EINVAL; + + guard(spinlock)(&drvdata->spinlock); + drvdata->freq_ts = !!val; + + return size; +} +static DEVICE_ATTR_RW(freq_ts_enable); + +static ssize_t global_flush_req_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val; + + if (!drvdata->csdev->refcnt) + return -EINVAL; + + guard(spinlock)(&drvdata->spinlock); + CS_UNLOCK(drvdata->base); + val = readl_relaxed(drvdata->base + TPDA_CR); + CS_LOCK(drvdata->base); + /* Only read value for bit 0 */ + val &= BIT(0); + + return sysfs_emit(buf, "%lu\n", val); +} + +static ssize_t global_flush_req_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val; + + if (kstrtoul(buf, 0, &val)) + return -EINVAL; + + if (!drvdata->csdev->refcnt || !val) + return -EINVAL; + + guard(spinlock)(&drvdata->spinlock); + CS_UNLOCK(drvdata->base); + val = readl_relaxed(drvdata->base + TPDA_CR); + /* Only set bit 0 */ + val |= BIT(0); + writel_relaxed(val, drvdata->base + TPDA_CR); + CS_LOCK(drvdata->base); + + return size; +} +static DEVICE_ATTR_RW(global_flush_req); + +static ssize_t cmbchan_mode_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent); + + return sysfs_emit(buf, "%u\n", (unsigned int)drvdata->cmbchan_mode); +} + +static ssize_t cmbchan_mode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val; + + if (kstrtoul(buf, 0, &val)) + return -EINVAL; + + guard(spinlock)(&drvdata->spinlock); + drvdata->cmbchan_mode = !!val; + + return size; +} +static DEVICE_ATTR_RW(cmbchan_mode); + +static struct attribute *tpda_attrs[] = { + &dev_attr_trig_async_enable.attr, + &dev_attr_trig_flag_ts_enable.attr, + &dev_attr_trig_freq_enable.attr, + &dev_attr_freq_ts_enable.attr, + &dev_attr_global_flush_req.attr, + &dev_attr_cmbchan_mode.attr, + NULL, +}; + +static struct attribute_group tpda_attr_grp = { + .attrs = tpda_attrs, +}; + +static const struct attribute_group *tpda_attr_grps[] = { + &tpda_attr_grp, + NULL, +}; + static int tpda_init_default_data(struct tpda_drvdata *drvdata) { int atid; @@ -289,6 +517,7 @@ static int tpda_init_default_data(struct tpda_drvdata *drvdata) return atid; drvdata->atid = atid; + drvdata->freq_ts = true; return 0; } @@ -332,6 +561,7 @@ static int tpda_probe(struct amba_device *adev, const struct amba_id *id) desc.ops = &tpda_cs_ops; desc.pdata = adev->dev.platform_data; desc.dev = &adev->dev; + desc.groups = tpda_attr_grps; desc.access = CSDEV_ACCESS_IOMEM(base); drvdata->csdev = coresight_register(&desc); if (IS_ERR(drvdata->csdev)) diff --git a/drivers/hwtracing/coresight/coresight-tpda.h b/drivers/hwtracing/coresight/coresight-tpda.h index c6af3d2da3efe..0be625fb52fdf 100644 --- a/drivers/hwtracing/coresight/coresight-tpda.h +++ b/drivers/hwtracing/coresight/coresight-tpda.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* - * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2023,2025 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _CORESIGHT_CORESIGHT_TPDA_H @@ -8,6 +8,19 @@ #define TPDA_CR (0x000) #define TPDA_Pn_CR(n) (0x004 + (n * 4)) +#define TPDA_FPID_CR (0x084) + +/* Cross trigger FREQ packets timestamp bit */ +#define TPDA_CR_FREQTS BIT(2) +/* Cross trigger FREQ packet request bit */ +#define TPDA_CR_FRIE BIT(3) +/* Cross trigger FLAG packet request interface bit */ +#define TPDA_CR_FLRIE BIT(4) +/* Cross trigger synchronization bit */ +#define TPDA_CR_SRIE BIT(5) +/* Packetize CMB/MCMB traffic bit */ +#define TPDA_CR_CMBCHANMODE BIT(20) + /* Aggregator port enable bit */ #define TPDA_Pn_CR_ENA BIT(0) /* Aggregator port CMB data set element size bit */ @@ -19,6 +32,8 @@ /* Bits 6 ~ 12 is for atid value */ #define TPDA_CR_ATID GENMASK(12, 6) +/* Bits 13 ~ 19 is for mid value */ +#define TPDA_CR_MID GENMASK(19, 13) /** * struct tpda_drvdata - specifics associated to an TPDA component @@ -29,6 +44,11 @@ * @enable: enable status of the component. * @dsb_esize Record the DSB element size. * @cmb_esize Record the CMB element size. + * @trig_async: Enable/disable cross trigger synchronization sequence interface. + * @trig_flag_ts: Enable/disable cross trigger FLAG packet request interface. + * @trig_freq: Enable/disable cross trigger FREQ packet request interface. + * @freq_ts: Enable/disable the timestamp for all FREQ packets. + * @cmbchan_mode: Configure the CMB/MCMB channel mode. */ struct tpda_drvdata { void __iomem *base; @@ -38,6 +58,11 @@ struct tpda_drvdata { u8 atid; u32 dsb_esize; u32 cmb_esize; + bool trig_async; + bool trig_flag_ts; + bool trig_freq; + bool freq_ts; + bool cmbchan_mode; }; #endif /* _CORESIGHT_CORESIGHT_TPDA_H */ From efcf3ed3a0e33112eda878064072e30b62de63c7 Mon Sep 17 00:00:00 2001 From: Tao Zhang Date: Wed, 27 Aug 2025 18:55:44 +0800 Subject: [PATCH 0076/2333] FROMLIST: coresight: tpda: add logic to configure TPDA_SYNCR register The TPDA_SYNCR register defines the frequency at which TPDA generates ASYNC packets, enabling userspace tools to accurately parse each valid packet. Link: https://lore.kernel.org/all/20250827105545.7140-3-jie.gan@oss.qualcomm.com/ Signed-off-by: Tao Zhang Co-developed-by: Jie Gan Signed-off-by: Jie Gan Reviewed-by: James Clark --- drivers/hwtracing/coresight/coresight-tpda.c | 7 +++++++ drivers/hwtracing/coresight/coresight-tpda.h | 5 +++++ 2 files changed, 12 insertions(+) diff --git a/drivers/hwtracing/coresight/coresight-tpda.c b/drivers/hwtracing/coresight/coresight-tpda.c index d4d1def5ec151..a1393962b04d3 100644 --- a/drivers/hwtracing/coresight/coresight-tpda.c +++ b/drivers/hwtracing/coresight/coresight-tpda.c @@ -187,6 +187,13 @@ static void tpda_enable_pre_port(struct tpda_drvdata *drvdata) */ if (drvdata->trig_flag_ts) writel_relaxed(0x0, drvdata->base + TPDA_FPID_CR); + + /* Program the counter value for TPDA_SYNCR */ + val = readl_relaxed(drvdata->base + TPDA_SYNCR); + /* Clear the mode */ + val &= ~TPDA_SYNCR_MODE_CTRL; + val |= TPDA_SYNCR_COUNTER_MASK; + writel_relaxed(val, drvdata->base + TPDA_SYNCR); } static int tpda_enable_port(struct tpda_drvdata *drvdata, int port) diff --git a/drivers/hwtracing/coresight/coresight-tpda.h b/drivers/hwtracing/coresight/coresight-tpda.h index 0be625fb52fdf..0c9bf2fade565 100644 --- a/drivers/hwtracing/coresight/coresight-tpda.h +++ b/drivers/hwtracing/coresight/coresight-tpda.h @@ -9,6 +9,7 @@ #define TPDA_CR (0x000) #define TPDA_Pn_CR(n) (0x004 + (n * 4)) #define TPDA_FPID_CR (0x084) +#define TPDA_SYNCR (0x08C) /* Cross trigger FREQ packets timestamp bit */ #define TPDA_CR_FREQTS BIT(2) @@ -27,6 +28,10 @@ #define TPDA_Pn_CR_CMBSIZE GENMASK(7, 6) /* Aggregator port DSB data set element size bit */ #define TPDA_Pn_CR_DSBSIZE BIT(8) +/* TPDA_SYNCR mode control bit */ +#define TPDA_SYNCR_MODE_CTRL BIT(12) +/* TPDA_SYNCR counter mask */ +#define TPDA_SYNCR_COUNTER_MASK GENMASK(11, 0) #define TPDA_MAX_INPORTS 32 From 9dcfdbd9f0a1f97eb475602581fc8a30cb76e4e2 Mon Sep 17 00:00:00 2001 From: Tao Zhang Date: Wed, 27 Aug 2025 18:55:45 +0800 Subject: [PATCH 0077/2333] FROMLIST: coresight: tpda: add sysfs node to flush specific port Setting bit i in the TPDA_FLUSH_CR register initiates a flush request for port i, forcing the data to synchronize and be transmitted to the sink device. Link: https://lore.kernel.org/all/20250827105545.7140-4-jie.gan@oss.qualcomm.com/ Signed-off-by: Tao Zhang Co-developed-by: Jie Gan Signed-off-by: Jie Gan Reviewed-by: James Clark --- .../testing/sysfs-bus-coresight-devices-tpda | 7 ++++ drivers/hwtracing/coresight/coresight-tpda.c | 41 +++++++++++++++++++ drivers/hwtracing/coresight/coresight-tpda.h | 1 + 3 files changed, 49 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda index fb651aebeb317..2cf2dcfc13c81 100644 --- a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda +++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda @@ -41,3 +41,10 @@ Contact: Jinlong Mao , Tao Zhang /port_flush_req +Date: August 2025 +KernelVersion: 6.17 +Contact: Jinlong Mao , Tao Zhang , Jie Gan +Description: + (RW) Configure the bit i to requests a flush operation of port i on the TPDA. diff --git a/drivers/hwtracing/coresight/coresight-tpda.c b/drivers/hwtracing/coresight/coresight-tpda.c index a1393962b04d3..e9e2736071fb5 100644 --- a/drivers/hwtracing/coresight/coresight-tpda.c +++ b/drivers/hwtracing/coresight/coresight-tpda.c @@ -490,6 +490,46 @@ static ssize_t cmbchan_mode_store(struct device *dev, } static DEVICE_ATTR_RW(cmbchan_mode); +static ssize_t port_flush_req_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val; + + if (!drvdata->csdev->refcnt) + return -EINVAL; + + guard(spinlock)(&drvdata->spinlock); + CS_UNLOCK(drvdata->base); + val = readl_relaxed(drvdata->base + TPDA_FLUSH_CR); + CS_LOCK(drvdata->base); + return sysfs_emit(buf, "0x%lx\n", val); +} + +static ssize_t port_flush_req_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent); + u32 val; + + if (kstrtou32(buf, 0, &val)) + return -EINVAL; + + if (!drvdata->csdev->refcnt || !val) + return -EINVAL; + + guard(spinlock)(&drvdata->spinlock); + CS_UNLOCK(drvdata->base); + writel_relaxed(val, drvdata->base + TPDA_FLUSH_CR); + CS_LOCK(drvdata->base); + + return size; +} +static DEVICE_ATTR_RW(port_flush_req); + static struct attribute *tpda_attrs[] = { &dev_attr_trig_async_enable.attr, &dev_attr_trig_flag_ts_enable.attr, @@ -497,6 +537,7 @@ static struct attribute *tpda_attrs[] = { &dev_attr_freq_ts_enable.attr, &dev_attr_global_flush_req.attr, &dev_attr_cmbchan_mode.attr, + &dev_attr_port_flush_req.attr, NULL, }; diff --git a/drivers/hwtracing/coresight/coresight-tpda.h b/drivers/hwtracing/coresight/coresight-tpda.h index 0c9bf2fade565..284ac63699ad6 100644 --- a/drivers/hwtracing/coresight/coresight-tpda.h +++ b/drivers/hwtracing/coresight/coresight-tpda.h @@ -10,6 +10,7 @@ #define TPDA_Pn_CR(n) (0x004 + (n * 4)) #define TPDA_FPID_CR (0x084) #define TPDA_SYNCR (0x08C) +#define TPDA_FLUSH_CR (0x090) /* Cross trigger FREQ packets timestamp bit */ #define TPDA_CR_FREQTS BIT(2) From 52d2d19a15dad5fd7338b5bdeb25a80faa2c1fad Mon Sep 17 00:00:00 2001 From: Yuanfang Zhang Date: Mon, 27 Oct 2025 23:28:03 -0700 Subject: [PATCH 0078/2333] FROMLIST: dt-bindings: arm: coresight: Add cpu cluster tmc/funnel/replicator support Add the following compatible strings to the bindings: - arm,coresight-cpu-funnel - arm,coresight-cpu-replicator - arm,coresight-cpu-tmc Each requires 'power-domains' when used. Link: https://lore.kernel.org/all/20251027-cpu_cluster_component_pm-v1-1-31355ac588c2@oss.qualcomm.com/ Signed-off-by: Yuanfang Zhang --- .../arm/arm,coresight-dynamic-funnel.yaml | 23 +++++++++++++++---- .../arm/arm,coresight-dynamic-replicator.yaml | 22 ++++++++++++++---- .../bindings/arm/arm,coresight-tmc.yaml | 22 ++++++++++++++---- 3 files changed, 54 insertions(+), 13 deletions(-) diff --git a/Documentation/devicetree/bindings/arm/arm,coresight-dynamic-funnel.yaml b/Documentation/devicetree/bindings/arm/arm,coresight-dynamic-funnel.yaml index b74db15e5f8af..8f32d4e3bbb75 100644 --- a/Documentation/devicetree/bindings/arm/arm,coresight-dynamic-funnel.yaml +++ b/Documentation/devicetree/bindings/arm/arm,coresight-dynamic-funnel.yaml @@ -28,19 +28,32 @@ select: properties: compatible: contains: - const: arm,coresight-dynamic-funnel + enum: + - arm,coresight-dynamic-funnel + - arm,coresight-cpu-funnel required: - compatible allOf: - $ref: /schemas/arm/primecell.yaml# + - if: + properties: + compatible: + contains: + const: arm,coresight-cpu-funnel + then: + required: + - power-domains + properties: compatible: - items: - - const: arm,coresight-dynamic-funnel - - const: arm,primecell - + oneOf: + - items: + - const: arm,coresight-dynamic-funnel + - const: arm,primecell + - items: + - const: arm,coresight-cpu-funnel reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/arm/arm,coresight-dynamic-replicator.yaml b/Documentation/devicetree/bindings/arm/arm,coresight-dynamic-replicator.yaml index 17ea936b796fd..5ce30c4e9c415 100644 --- a/Documentation/devicetree/bindings/arm/arm,coresight-dynamic-replicator.yaml +++ b/Documentation/devicetree/bindings/arm/arm,coresight-dynamic-replicator.yaml @@ -28,18 +28,32 @@ select: properties: compatible: contains: - const: arm,coresight-dynamic-replicator + enum: + - arm,coresight-dynamic-replicator + - arm,coresight-cpu-replicator required: - compatible allOf: - $ref: /schemas/arm/primecell.yaml# + - if: + properties: + compatible: + contains: + const: arm,coresight-cpu-replicator + then: + required: + - power-domains + properties: compatible: - items: - - const: arm,coresight-dynamic-replicator - - const: arm,primecell + oneOf: + - items: + - const: arm,coresight-dynamic-replicator + - const: arm,primecell + - items: + - const: arm,coresight-cpu-replicator reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/arm/arm,coresight-tmc.yaml b/Documentation/devicetree/bindings/arm/arm,coresight-tmc.yaml index 96dd5b5f771a3..d7c0b618fe98a 100644 --- a/Documentation/devicetree/bindings/arm/arm,coresight-tmc.yaml +++ b/Documentation/devicetree/bindings/arm/arm,coresight-tmc.yaml @@ -29,18 +29,32 @@ select: properties: compatible: contains: - const: arm,coresight-tmc + enum: + - arm,coresight-tmc + - arm,coresight-cpu-tmc required: - compatible allOf: - $ref: /schemas/arm/primecell.yaml# + - if: + properties: + compatible: + contains: + const: arm,coresight-cpu-tmc + then: + required: + - power-domains + properties: compatible: - items: - - const: arm,coresight-tmc - - const: arm,primecell + oneOf: + - items: + - const: arm,coresight-tmc + - const: arm,primecell + - items: + - const: arm,coresight-cpu-tmc reg: maxItems: 1 From 5f15f92af939aaa3e5c0691bb5730b3e90e0c3eb Mon Sep 17 00:00:00 2001 From: Yuanfang Zhang Date: Mon, 27 Oct 2025 23:28:04 -0700 Subject: [PATCH 0079/2333] FROMLIST: coresight-funnel: Add support for CPU cluster funnel The CPU cluster funnel is a type of CoreSight funnel that resides inside the CPU cluster's power domain. Unlike dynamic funnels, CPU funnels are coupled with CPU clusters and share their power management characteristics. When the CPU cluster enters low-power mode (LPM), the funnel's registers become inaccessible. Moreover, runtime PM operations alone cannot bring the CPU cluster out of LPM, making standard register access unreliable. This patch enhances the existing CoreSight funnel platform driver to support CPU cluster funnels by: - Add cpumask to funnel_drvdata to store CPU cluster's mask for CPU cluster funnel. - Retrieving the associated CPU cluster's cpumask from the power domain. - Using smp_call_function_single() to do clear self claim tag operation. - Refactoring funnel_enable function. For cluster funnels, use smp_call_function_single() to ensure register visibility. - Encapsulating coresight registration in funnel_add_coresight_dev(). - Reusing the existing platform driver infrastructure to minimize duplication and maintain compatibility with static funnel devices. This ensures funnel operations are safe and functional even when the CPU cluster is in low-power mode. Link: https://lore.kernel.org/all/20251027-cpu_cluster_component_pm-v1-2-31355ac588c2@oss.qualcomm.com/ Signed-off-by: Yuanfang Zhang --- .../hwtracing/coresight/coresight-funnel.c | 185 +++++++++++++++--- 1 file changed, 154 insertions(+), 31 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-funnel.c b/drivers/hwtracing/coresight/coresight-funnel.c index 3b248e54471a3..12c29eb98b212 100644 --- a/drivers/hwtracing/coresight/coresight-funnel.c +++ b/drivers/hwtracing/coresight/coresight-funnel.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -40,6 +41,7 @@ DEFINE_CORESIGHT_DEVLIST(funnel_devs, "funnel"); * @csdev: component vitals needed by the framework. * @priority: port selection order. * @spinlock: serialize enable/disable operations. + * @cpumask: CPU mask representing the CPUs related to this funnel. */ struct funnel_drvdata { void __iomem *base; @@ -48,6 +50,13 @@ struct funnel_drvdata { struct coresight_device *csdev; unsigned long priority; raw_spinlock_t spinlock; + struct cpumask *cpumask; +}; + +struct funnel_smp_arg { + struct funnel_drvdata *drvdata; + int port; + int rc; }; static int dynamic_funnel_enable_hw(struct funnel_drvdata *drvdata, int port) @@ -76,6 +85,33 @@ static int dynamic_funnel_enable_hw(struct funnel_drvdata *drvdata, int port) return rc; } +static void funnel_enable_hw_smp_call(void *info) +{ + struct funnel_smp_arg *arg = info; + + arg->rc = dynamic_funnel_enable_hw(arg->drvdata, arg->port); +} + +static int funnel_enable_hw(struct funnel_drvdata *drvdata, int port) +{ + int cpu, ret; + struct funnel_smp_arg arg = { 0 }; + + if (!drvdata->cpumask) + return dynamic_funnel_enable_hw(drvdata, port); + + arg.drvdata = drvdata; + arg.port = port; + + for_each_cpu(cpu, drvdata->cpumask) { + ret = smp_call_function_single(cpu, + funnel_enable_hw_smp_call, &arg, 1); + if (!ret) + return arg.rc; + } + return ret; +} + static int funnel_enable(struct coresight_device *csdev, struct coresight_connection *in, struct coresight_connection *out) @@ -86,19 +122,24 @@ static int funnel_enable(struct coresight_device *csdev, bool first_enable = false; raw_spin_lock_irqsave(&drvdata->spinlock, flags); - if (in->dest_refcnt == 0) { - if (drvdata->base) - rc = dynamic_funnel_enable_hw(drvdata, in->dest_port); - if (!rc) - first_enable = true; - } - if (!rc) + + if (in->dest_refcnt == 0) + first_enable = true; + else in->dest_refcnt++; + raw_spin_unlock_irqrestore(&drvdata->spinlock, flags); - if (first_enable) - dev_dbg(&csdev->dev, "FUNNEL inport %d enabled\n", - in->dest_port); + if (first_enable) { + if (drvdata->base) + rc = funnel_enable_hw(drvdata, in->dest_port); + if (!rc) { + in->dest_refcnt++; + dev_dbg(&csdev->dev, "FUNNEL inport %d enabled\n", + in->dest_port); + } + } + return rc; } @@ -188,15 +229,39 @@ static u32 get_funnel_ctrl_hw(struct funnel_drvdata *drvdata) return functl; } +static void get_funnel_ctrl_smp_call(void *info) +{ + struct funnel_smp_arg *arg = info; + + arg->rc = get_funnel_ctrl_hw(arg->drvdata); +} + static ssize_t funnel_ctrl_show(struct device *dev, struct device_attribute *attr, char *buf) { u32 val; + int cpu, ret; struct funnel_drvdata *drvdata = dev_get_drvdata(dev->parent); + struct funnel_smp_arg arg = { 0 }; pm_runtime_get_sync(dev->parent); - - val = get_funnel_ctrl_hw(drvdata); + if (!drvdata->cpumask) { + val = get_funnel_ctrl_hw(drvdata); + } else { + arg.drvdata = drvdata; + for_each_cpu(cpu, drvdata->cpumask) { + ret = smp_call_function_single(cpu, + get_funnel_ctrl_smp_call, &arg, 1); + if (!ret) + break; + } + if (!ret) { + val = arg.rc; + } else { + pm_runtime_put(dev->parent); + return ret; + } + } pm_runtime_put(dev->parent); @@ -211,22 +276,68 @@ static struct attribute *coresight_funnel_attrs[] = { }; ATTRIBUTE_GROUPS(coresight_funnel); +static void funnel_clear_self_claim_tag(struct funnel_drvdata *drvdata) +{ + struct csdev_access access = CSDEV_ACCESS_IOMEM(drvdata->base); + + coresight_clear_self_claim_tag(&access); +} + +static void funnel_init_on_cpu(void *info) +{ + struct funnel_drvdata *drvdata = info; + + funnel_clear_self_claim_tag(drvdata); +} + +static int funnel_add_coresight_dev(struct device *dev) +{ + struct coresight_desc desc = { 0 }; + struct funnel_drvdata *drvdata = dev_get_drvdata(dev); + + if (drvdata->base) { + desc.groups = coresight_funnel_groups; + desc.access = CSDEV_ACCESS_IOMEM(drvdata->base); + } + + desc.name = coresight_alloc_device_name(&funnel_devs, dev); + if (!desc.name) + return -ENOMEM; + + desc.type = CORESIGHT_DEV_TYPE_LINK; + desc.subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_MERG; + desc.ops = &funnel_cs_ops; + desc.pdata = dev->platform_data; + desc.dev = dev; + + drvdata->csdev = coresight_register(&desc); + if (IS_ERR(drvdata->csdev)) + return PTR_ERR(drvdata->csdev); + return 0; +} + +static struct cpumask *funnel_get_cpumask(struct device *dev) +{ + struct generic_pm_domain *pd; + + pd = pd_to_genpd(dev->pm_domain); + if (pd) + return pd->cpus; + + return NULL; +} + static int funnel_probe(struct device *dev, struct resource *res) { void __iomem *base; struct coresight_platform_data *pdata = NULL; struct funnel_drvdata *drvdata; - struct coresight_desc desc = { 0 }; - int ret; + int cpu, ret; if (is_of_node(dev_fwnode(dev)) && of_device_is_compatible(dev->of_node, "arm,coresight-funnel")) dev_warn_once(dev, "Uses OBSOLETE CoreSight funnel binding\n"); - desc.name = coresight_alloc_device_name(&funnel_devs, dev); - if (!desc.name) - return -ENOMEM; - drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL); if (!drvdata) return -ENOMEM; @@ -244,9 +355,6 @@ static int funnel_probe(struct device *dev, struct resource *res) if (IS_ERR(base)) return PTR_ERR(base); drvdata->base = base; - desc.groups = coresight_funnel_groups; - desc.access = CSDEV_ACCESS_IOMEM(base); - coresight_clear_self_claim_tag(&desc.access); } dev_set_drvdata(dev, drvdata); @@ -258,23 +366,37 @@ static int funnel_probe(struct device *dev, struct resource *res) dev->platform_data = pdata; raw_spin_lock_init(&drvdata->spinlock); - desc.type = CORESIGHT_DEV_TYPE_LINK; - desc.subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_MERG; - desc.ops = &funnel_cs_ops; - desc.pdata = pdata; - desc.dev = dev; - drvdata->csdev = coresight_register(&desc); - if (IS_ERR(drvdata->csdev)) - return PTR_ERR(drvdata->csdev); - return 0; + if (is_of_node(dev_fwnode(dev)) && + of_device_is_compatible(dev->of_node, "arm,coresight-cpu-funnel")) { + drvdata->cpumask = funnel_get_cpumask(dev); + if (!drvdata->cpumask) + return -EINVAL; + + cpus_read_lock(); + for_each_cpu(cpu, drvdata->cpumask) { + ret = smp_call_function_single(cpu, + funnel_init_on_cpu, drvdata, 1); + if (!ret) + break; + } + cpus_read_unlock(); + + if (ret) + return 0; + } else if (res) { + funnel_clear_self_claim_tag(drvdata); + } + + return funnel_add_coresight_dev(dev); } static int funnel_remove(struct device *dev) { struct funnel_drvdata *drvdata = dev_get_drvdata(dev); - coresight_unregister(drvdata->csdev); + if (drvdata->csdev) + coresight_unregister(drvdata->csdev); return 0; } @@ -341,6 +463,7 @@ static void funnel_platform_remove(struct platform_device *pdev) static const struct of_device_id funnel_match[] = { {.compatible = "arm,coresight-static-funnel"}, + {.compatible = "arm,coresight-cpu-funnel"}, {} }; From 812f78b949e33ce4d2b0207d306aed6fb0cc486f Mon Sep 17 00:00:00 2001 From: Yuanfang Zhang Date: Mon, 27 Oct 2025 23:28:05 -0700 Subject: [PATCH 0080/2333] FROMLIST: coresight-funnel: Handle delay probe for CPU cluster funnel Delay probe the cpu cluster funnel when all CPUs of this cluster are offline, re-probe the funnel when any CPU in the cluster comes online. Key changes: - Introduce a global list to track delayed funnels waiting for CPU online. - Add CPU hotplug callback to retry registration when the CPU comes up. Link: https://lore.kernel.org/all/20251027-cpu_cluster_component_pm-v1-3-31355ac588c2@oss.qualcomm.com/ Signed-off-by: Yuanfang Zhang --- .../hwtracing/coresight/coresight-funnel.c | 62 +++++++++++++++++-- 1 file changed, 57 insertions(+), 5 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-funnel.c b/drivers/hwtracing/coresight/coresight-funnel.c index 12c29eb98b212..43b9287a865eb 100644 --- a/drivers/hwtracing/coresight/coresight-funnel.c +++ b/drivers/hwtracing/coresight/coresight-funnel.c @@ -32,6 +32,9 @@ #define FUNNEL_ENSx_MASK 0xff DEFINE_CORESIGHT_DEVLIST(funnel_devs, "funnel"); +static LIST_HEAD(funnel_delay_probe); +static enum cpuhp_state hp_online; +static DEFINE_SPINLOCK(delay_lock); /** * struct funnel_drvdata - specifics associated to a funnel component @@ -42,6 +45,8 @@ DEFINE_CORESIGHT_DEVLIST(funnel_devs, "funnel"); * @priority: port selection order. * @spinlock: serialize enable/disable operations. * @cpumask: CPU mask representing the CPUs related to this funnel. + * @dev: pointer to the device associated with this funnel. + * @link: list node for adding this funnel to the delayed probe list. */ struct funnel_drvdata { void __iomem *base; @@ -51,6 +56,8 @@ struct funnel_drvdata { unsigned long priority; raw_spinlock_t spinlock; struct cpumask *cpumask; + struct device *dev; + struct list_head link; }; struct funnel_smp_arg { @@ -372,7 +379,7 @@ static int funnel_probe(struct device *dev, struct resource *res) drvdata->cpumask = funnel_get_cpumask(dev); if (!drvdata->cpumask) return -EINVAL; - + drvdata->dev = dev; cpus_read_lock(); for_each_cpu(cpu, drvdata->cpumask) { ret = smp_call_function_single(cpu, @@ -380,10 +387,15 @@ static int funnel_probe(struct device *dev, struct resource *res) if (!ret) break; } - cpus_read_unlock(); - if (ret) + if (ret) { + scoped_guard(spinlock, &delay_lock) + list_add(&drvdata->link, &funnel_delay_probe); + cpus_read_unlock(); return 0; + } + + cpus_read_unlock(); } else if (res) { funnel_clear_self_claim_tag(drvdata); } @@ -395,9 +407,12 @@ static int funnel_remove(struct device *dev) { struct funnel_drvdata *drvdata = dev_get_drvdata(dev); - if (drvdata->csdev) + if (drvdata->csdev) { coresight_unregister(drvdata->csdev); - + } else { + scoped_guard(spinlock, &delay_lock) + list_del(&drvdata->link); + } return 0; } @@ -535,8 +550,41 @@ static struct amba_driver dynamic_funnel_driver = { .id_table = dynamic_funnel_ids, }; +static int funnel_online_cpu(unsigned int cpu) +{ + struct funnel_drvdata *drvdata, *tmp; + int ret; + + list_for_each_entry_safe(drvdata, tmp, &funnel_delay_probe, link) { + if (cpumask_test_cpu(cpu, drvdata->cpumask)) { + scoped_guard(spinlock, &delay_lock) + list_del(&drvdata->link); + + ret = pm_runtime_resume_and_get(drvdata->dev); + if (ret < 0) + return 0; + + funnel_clear_self_claim_tag(drvdata); + funnel_add_coresight_dev(drvdata->dev); + pm_runtime_put(drvdata->dev); + } + } + return 0; +} + static int __init funnel_init(void) { + int ret; + + ret = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN, + "arm/coresight-funnel:online", + funnel_online_cpu, NULL); + + if (ret > 0) + hp_online = ret; + else + return ret; + return coresight_init_driver("funnel", &dynamic_funnel_driver, &funnel_driver, THIS_MODULE); } @@ -544,6 +592,10 @@ static int __init funnel_init(void) static void __exit funnel_exit(void) { coresight_remove_driver(&dynamic_funnel_driver, &funnel_driver); + if (hp_online) { + cpuhp_remove_state_nocalls(hp_online); + hp_online = 0; + } } module_init(funnel_init); From 148ad323d05f64ac5a22c0f33bdadb1b40cbb5c0 Mon Sep 17 00:00:00 2001 From: Yuanfang Zhang Date: Mon, 27 Oct 2025 23:28:06 -0700 Subject: [PATCH 0081/2333] FROMLIST: coresight-replicator: Add support for CPU cluster replicator The CPU cluster replicator is a type of CoreSight replicator that resides inside the CPU cluster's power domain. Unlike system-wide replicators, CPU replicators are tightly coupled with CPU clusters and inherit their power management characteristics. When the CPU cluster enters low-power mode (LPM), the replicator registers become inaccessible. Moreover, runtime PM alone cannot bring the CPU cluster out of LPM, making standard register access unreliable. This patch enhances the existing CoreSight replicator platform driver to support CPU cluster replicators by: - Adding replicator_claim/disclaim_device_unlocked() to handle device claim/disclaim before CoreSight device registration. - Wrapping replicator_reset and clear_clear_tag in replicator_init_hw. For cluster replicators, use smp_call_function_single() to ensure register visibility. - Encapsulating csdev registration in replicator_add_coresight_dev(). - Refactoring replicator_enable function. For cluster replicators, use smp_call_function_single() to ensure register visibility. - Maintaining compatibility with existing static/dynamic replicators while minimizing duplication. This ensures replicator operations remain safe and functional even when the CPU cluster is in low-power states. Link: https://lore.kernel.org/all/20251027-cpu_cluster_component_pm-v1-4-31355ac588c2@oss.qualcomm.com/ Signed-off-by: Yuanfang Zhang --- .../coresight/coresight-replicator.c | 202 +++++++++++++++--- 1 file changed, 169 insertions(+), 33 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-replicator.c b/drivers/hwtracing/coresight/coresight-replicator.c index e6472658235dc..c5a9c7a2adfa9 100644 --- a/drivers/hwtracing/coresight/coresight-replicator.c +++ b/drivers/hwtracing/coresight/coresight-replicator.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -35,6 +36,7 @@ DEFINE_CORESIGHT_DEVLIST(replicator_devs, "replicator"); * @csdev: component vitals needed by the framework * @spinlock: serialize enable/disable operations. * @check_idfilter_val: check if the context is lost upon clock removal. + * @cpumask: CPU mask representing the CPUs related to this replicator. */ struct replicator_drvdata { void __iomem *base; @@ -43,18 +45,61 @@ struct replicator_drvdata { struct coresight_device *csdev; raw_spinlock_t spinlock; bool check_idfilter_val; + struct cpumask *cpumask; }; -static void dynamic_replicator_reset(struct replicator_drvdata *drvdata) +struct replicator_smp_arg { + struct replicator_drvdata *drvdata; + int outport; + int rc; +}; + +static void replicator_clear_self_claim_tag(struct replicator_drvdata *drvdata) +{ + struct csdev_access access = CSDEV_ACCESS_IOMEM(drvdata->base); + + coresight_clear_self_claim_tag(&access); +} + +static int replicator_claim_device_unlocked(struct replicator_drvdata *drvdata) +{ + struct coresight_device *csdev = drvdata->csdev; + struct csdev_access access = CSDEV_ACCESS_IOMEM(drvdata->base); + u32 claim_tag; + + if (csdev) + return coresight_claim_device_unlocked(csdev); + + writel_relaxed(CORESIGHT_CLAIM_SELF_HOSTED, drvdata->base + CORESIGHT_CLAIMSET); + + claim_tag = readl_relaxed(drvdata->base + CORESIGHT_CLAIMCLR); + if (claim_tag != CORESIGHT_CLAIM_SELF_HOSTED) { + coresight_clear_self_claim_tag_unlocked(&access); + return -EBUSY; + } + + return 0; +} + +static void replicator_disclaim_device_unlocked(struct replicator_drvdata *drvdata) { struct coresight_device *csdev = drvdata->csdev; + struct csdev_access access = CSDEV_ACCESS_IOMEM(drvdata->base); + + if (csdev) + return coresight_disclaim_device_unlocked(csdev); + coresight_clear_self_claim_tag_unlocked(&access); +} + +static void dynamic_replicator_reset(struct replicator_drvdata *drvdata) +{ CS_UNLOCK(drvdata->base); - if (!coresight_claim_device_unlocked(csdev)) { + if (!replicator_claim_device_unlocked(drvdata)) { writel_relaxed(0xff, drvdata->base + REPLICATOR_IDFILTER0); writel_relaxed(0xff, drvdata->base + REPLICATOR_IDFILTER1); - coresight_disclaim_device_unlocked(csdev); + replicator_disclaim_device_unlocked(drvdata); } CS_LOCK(drvdata->base); @@ -116,6 +161,34 @@ static int dynamic_replicator_enable(struct replicator_drvdata *drvdata, return rc; } +static void replicator_enable_hw_smp_call(void *info) +{ + struct replicator_smp_arg *arg = info; + + arg->rc = dynamic_replicator_enable(arg->drvdata, 0, arg->outport); +} + +static int replicator_enable_hw(struct replicator_drvdata *drvdata, + int inport, int outport) +{ + int cpu, ret; + struct replicator_smp_arg arg = { 0 }; + + if (!drvdata->cpumask) + return dynamic_replicator_enable(drvdata, 0, outport); + + arg.drvdata = drvdata; + arg.outport = outport; + + for_each_cpu(cpu, drvdata->cpumask) { + ret = smp_call_function_single(cpu, replicator_enable_hw_smp_call, &arg, 1); + if (!ret) + return arg.rc; + } + + return ret; +} + static int replicator_enable(struct coresight_device *csdev, struct coresight_connection *in, struct coresight_connection *out) @@ -126,19 +199,24 @@ static int replicator_enable(struct coresight_device *csdev, bool first_enable = false; raw_spin_lock_irqsave(&drvdata->spinlock, flags); - if (out->src_refcnt == 0) { - if (drvdata->base) - rc = dynamic_replicator_enable(drvdata, in->dest_port, - out->src_port); - if (!rc) - first_enable = true; - } - if (!rc) + + if (out->src_refcnt == 0) + first_enable = true; + else out->src_refcnt++; raw_spin_unlock_irqrestore(&drvdata->spinlock, flags); - if (first_enable) - dev_dbg(&csdev->dev, "REPLICATOR enabled\n"); + if (first_enable) { + if (drvdata->base) + rc = replicator_enable_hw(drvdata, in->dest_port, + out->src_port); + if (!rc) { + out->src_refcnt++; + dev_dbg(&csdev->dev, "REPLICATOR enabled\n"); + return rc; + } + } + return rc; } @@ -217,23 +295,69 @@ static const struct attribute_group *replicator_groups[] = { NULL, }; +static int replicator_add_coresight_dev(struct device *dev) +{ + struct coresight_desc desc = { 0 }; + struct replicator_drvdata *drvdata = dev_get_drvdata(dev); + + if (drvdata->base) { + desc.groups = replicator_groups; + desc.access = CSDEV_ACCESS_IOMEM(drvdata->base); + } + + desc.name = coresight_alloc_device_name(&replicator_devs, dev); + if (!desc.name) + return -ENOMEM; + + desc.type = CORESIGHT_DEV_TYPE_LINK; + desc.subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_SPLIT; + desc.ops = &replicator_cs_ops; + desc.pdata = dev->platform_data; + desc.dev = dev; + + drvdata->csdev = coresight_register(&desc); + if (IS_ERR(drvdata->csdev)) + return PTR_ERR(drvdata->csdev); + + return 0; +} + +static void replicator_init_hw(struct replicator_drvdata *drvdata) +{ + replicator_clear_self_claim_tag(drvdata); + replicator_reset(drvdata); +} + +static void replicator_init_on_cpu(void *info) +{ + struct replicator_drvdata *drvdata = info; + + replicator_init_hw(drvdata); +} + +static struct cpumask *replicator_get_cpumask(struct device *dev) +{ + struct generic_pm_domain *pd; + + pd = pd_to_genpd(dev->pm_domain); + if (pd) + return pd->cpus; + + return NULL; +} + static int replicator_probe(struct device *dev, struct resource *res) { struct coresight_platform_data *pdata = NULL; struct replicator_drvdata *drvdata; - struct coresight_desc desc = { 0 }; void __iomem *base; - int ret; + int cpu, ret; if (is_of_node(dev_fwnode(dev)) && of_device_is_compatible(dev->of_node, "arm,coresight-replicator")) dev_warn_once(dev, "Uses OBSOLETE CoreSight replicator binding\n"); - desc.name = coresight_alloc_device_name(&replicator_devs, dev); - if (!desc.name) - return -ENOMEM; - drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL); if (!drvdata) return -ENOMEM; @@ -251,9 +375,6 @@ static int replicator_probe(struct device *dev, struct resource *res) if (IS_ERR(base)) return PTR_ERR(base); drvdata->base = base; - desc.groups = replicator_groups; - desc.access = CSDEV_ACCESS_IOMEM(base); - coresight_clear_self_claim_tag(&desc.access); } if (fwnode_property_present(dev_fwnode(dev), @@ -268,25 +389,39 @@ static int replicator_probe(struct device *dev, struct resource *res) dev->platform_data = pdata; raw_spin_lock_init(&drvdata->spinlock); - desc.type = CORESIGHT_DEV_TYPE_LINK; - desc.subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_SPLIT; - desc.ops = &replicator_cs_ops; - desc.pdata = dev->platform_data; - desc.dev = dev; - drvdata->csdev = coresight_register(&desc); - if (IS_ERR(drvdata->csdev)) - return PTR_ERR(drvdata->csdev); + if (is_of_node(dev_fwnode(dev)) && + of_device_is_compatible(dev->of_node, "arm,coresight-cpu-replicator")) { + drvdata->cpumask = replicator_get_cpumask(dev); + if (!drvdata->cpumask) + return -EINVAL; + + cpus_read_lock(); + for_each_cpu(cpu, drvdata->cpumask) { + ret = smp_call_function_single(cpu, + replicator_init_on_cpu, drvdata, 1); + if (!ret) + break; + } + cpus_read_unlock(); - replicator_reset(drvdata); - return 0; + if (ret) + return 0; + } else if (res) { + replicator_init_hw(drvdata); + } + + ret = replicator_add_coresight_dev(dev); + + return ret; } static int replicator_remove(struct device *dev) { struct replicator_drvdata *drvdata = dev_get_drvdata(dev); - coresight_unregister(drvdata->csdev); + if (drvdata->csdev) + coresight_unregister(drvdata->csdev); return 0; } @@ -354,6 +489,7 @@ static const struct dev_pm_ops replicator_dev_pm_ops = { static const struct of_device_id replicator_match[] = { {.compatible = "arm,coresight-replicator"}, {.compatible = "arm,coresight-static-replicator"}, + {.compatible = "arm,coresight-cpu-replicator"}, {} }; From efa882936c04ea8612c18bfab868dffa76b6eafd Mon Sep 17 00:00:00 2001 From: Yuanfang Zhang Date: Mon, 27 Oct 2025 23:28:07 -0700 Subject: [PATCH 0082/2333] FROMLIST: coresight-replicator: Handle delayed probe for CPU cluster replicator Delay probe the CPU cluster replicator when all CPUs of the cluster are offline, and re-probe the replicator when any CPU in the cluster comes online. Key changes: - Maintain a global list to track delayed replicators waiting for CPU online. - Add a CPU hotplug callback to retry registration on CPU online events. Link: https://lore.kernel.org/all/20251027-cpu_cluster_component_pm-v1-5-31355ac588c2@oss.qualcomm.com/ Signed-off-by: Yuanfang Zhang --- .../coresight/coresight-replicator.c | 65 +++++++++++++++++-- 1 file changed, 61 insertions(+), 4 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-replicator.c b/drivers/hwtracing/coresight/coresight-replicator.c index c5a9c7a2adfa9..1dfe11940cd60 100644 --- a/drivers/hwtracing/coresight/coresight-replicator.c +++ b/drivers/hwtracing/coresight/coresight-replicator.c @@ -26,6 +26,9 @@ #define REPLICATOR_IDFILTER1 0x004 DEFINE_CORESIGHT_DEVLIST(replicator_devs, "replicator"); +static LIST_HEAD(replicator_delay_probe); +static enum cpuhp_state hp_online; +static DEFINE_SPINLOCK(delay_lock); /** * struct replicator_drvdata - specifics associated to a replicator component @@ -37,6 +40,8 @@ DEFINE_CORESIGHT_DEVLIST(replicator_devs, "replicator"); * @spinlock: serialize enable/disable operations. * @check_idfilter_val: check if the context is lost upon clock removal. * @cpumask: CPU mask representing the CPUs related to this replicator. + * @dev: pointer to the device associated with this replicator. + * @link: link to the delay_probed list. */ struct replicator_drvdata { void __iomem *base; @@ -46,6 +51,8 @@ struct replicator_drvdata { raw_spinlock_t spinlock; bool check_idfilter_val; struct cpumask *cpumask; + struct device *dev; + struct list_head link; }; struct replicator_smp_arg { @@ -395,7 +402,7 @@ static int replicator_probe(struct device *dev, struct resource *res) drvdata->cpumask = replicator_get_cpumask(dev); if (!drvdata->cpumask) return -EINVAL; - + drvdata->dev = dev; cpus_read_lock(); for_each_cpu(cpu, drvdata->cpumask) { ret = smp_call_function_single(cpu, @@ -403,10 +410,15 @@ static int replicator_probe(struct device *dev, struct resource *res) if (!ret) break; } - cpus_read_unlock(); - if (ret) + if (ret) { + scoped_guard(spinlock, &delay_lock) + list_add(&drvdata->link, &replicator_delay_probe); + cpus_read_unlock(); return 0; + } + + cpus_read_unlock(); } else if (res) { replicator_init_hw(drvdata); } @@ -420,8 +432,13 @@ static int replicator_remove(struct device *dev) { struct replicator_drvdata *drvdata = dev_get_drvdata(dev); - if (drvdata->csdev) + if (drvdata->csdev) { coresight_unregister(drvdata->csdev); + } else { + scoped_guard(spinlock, &delay_lock) + list_del(&drvdata->link); + } + return 0; } @@ -554,8 +571,44 @@ static struct amba_driver dynamic_replicator_driver = { .id_table = dynamic_replicator_ids, }; +static int replicator_online_cpu(unsigned int cpu) +{ + struct replicator_drvdata *drvdata, *tmp; + int ret; + + spin_lock(&delay_lock); + list_for_each_entry_safe(drvdata, tmp, &replicator_delay_probe, link) { + if (cpumask_test_cpu(cpu, drvdata->cpumask)) { + list_del(&drvdata->link); + spin_unlock(&delay_lock); + ret = pm_runtime_resume_and_get(drvdata->dev); + if (ret < 0) + return 0; + + replicator_clear_self_claim_tag(drvdata); + replicator_reset(drvdata); + replicator_add_coresight_dev(drvdata->dev); + pm_runtime_put(drvdata->dev); + spin_lock(&delay_lock); + } + } + spin_unlock(&delay_lock); + return 0; +} + static int __init replicator_init(void) { + int ret; + + ret = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN, + "arm/coresight-replicator:online", + replicator_online_cpu, NULL); + + if (ret > 0) + hp_online = ret; + else + return ret; + return coresight_init_driver("replicator", &dynamic_replicator_driver, &replicator_driver, THIS_MODULE); } @@ -563,6 +616,10 @@ static int __init replicator_init(void) static void __exit replicator_exit(void) { coresight_remove_driver(&dynamic_replicator_driver, &replicator_driver); + if (hp_online) { + cpuhp_remove_state_nocalls(hp_online); + hp_online = 0; + } } module_init(replicator_init); From 1c4429e07d7dad7f7d3032375b3c76b71b9703cd Mon Sep 17 00:00:00 2001 From: Yuanfang Zhang Date: Mon, 27 Oct 2025 23:28:08 -0700 Subject: [PATCH 0083/2333] FROMLIST: coresight-replicator: Update mgmt_attrs for CPU cluster replicator compatibility This patch refactors the sysfs interfaces to ensure compatibility with CPU cluster replicators. For CPU cluster replicators, register reads are performed via smp_call_function_single(). Link: https://lore.kernel.org/all/20251027-cpu_cluster_component_pm-v1-6-31355ac588c2@oss.qualcomm.com/ Signed-off-by: Yuanfang Zhang --- .../coresight/coresight-replicator.c | 61 ++++++++++++++++++- 1 file changed, 59 insertions(+), 2 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-replicator.c b/drivers/hwtracing/coresight/coresight-replicator.c index 1dfe11940cd60..22c9bc71817d2 100644 --- a/drivers/hwtracing/coresight/coresight-replicator.c +++ b/drivers/hwtracing/coresight/coresight-replicator.c @@ -58,6 +58,7 @@ struct replicator_drvdata { struct replicator_smp_arg { struct replicator_drvdata *drvdata; int outport; + u32 offset; int rc; }; @@ -286,9 +287,65 @@ static const struct coresight_ops replicator_cs_ops = { .link_ops = &replicator_link_ops, }; +static void replicator_read_register_smp_call(void *info) +{ + struct replicator_smp_arg *arg = info; + + arg->rc = readl_relaxed(arg->drvdata->base + arg->offset); +} + +static ssize_t coresight_replicator_reg32_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct replicator_drvdata *drvdata = dev_get_drvdata(dev->parent); + struct cs_off_attribute *cs_attr = container_of(attr, struct cs_off_attribute, attr); + unsigned long flags; + struct replicator_smp_arg arg = { 0 }; + u32 val; + int ret, cpu; + + pm_runtime_get_sync(dev->parent); + + if (!drvdata->cpumask) { + raw_spin_lock_irqsave(&drvdata->spinlock, flags); + val = readl_relaxed(drvdata->base + cs_attr->off); + raw_spin_unlock_irqrestore(&drvdata->spinlock, flags); + + } else { + arg.drvdata = drvdata; + arg.offset = cs_attr->off; + for_each_cpu(cpu, drvdata->cpumask) { + ret = smp_call_function_single(cpu, + replicator_read_register_smp_call, + &arg, 1); + if (!ret) + break; + } + if (!ret) { + val = arg.rc; + } else { + pm_runtime_put_sync(dev->parent); + return ret; + } + } + + pm_runtime_put_sync(dev->parent); + + return sysfs_emit(buf, "0x%x\n", val); +} + +#define coresight_replicator_reg32(name, offset) \ + (&((struct cs_off_attribute[]) { \ + { \ + __ATTR(name, 0444, coresight_replicator_reg32_show, NULL), \ + offset \ + } \ + })[0].attr.attr) + static struct attribute *replicator_mgmt_attrs[] = { - coresight_simple_reg32(idfilter0, REPLICATOR_IDFILTER0), - coresight_simple_reg32(idfilter1, REPLICATOR_IDFILTER1), + coresight_replicator_reg32(idfilter0, REPLICATOR_IDFILTER0), + coresight_replicator_reg32(idfilter1, REPLICATOR_IDFILTER1), NULL, }; From 892fc985063b189eebc1dea947e88b27cf58ea82 Mon Sep 17 00:00:00 2001 From: Yuanfang Zhang Date: Mon, 27 Oct 2025 23:28:09 -0700 Subject: [PATCH 0084/2333] FROMLIST: coresight-tmc: Add support for CPU cluster ETF and refactor probe flow The CPU cluster ETF is a type of Coresight ETF that resides inside the CPU cluster's power domain. Unlike system-level ETFs, these devices share the CPU cluster's power management behavior: when the cluster enters low-power mode, ETF registers become inaccessible. Runtime PM alone cannot bring the cluster out of LPM, making standard register access unreliable. This patch adds support for CPU cluster ETF and restructures the probe sequence to handle such cases safely: - Wrap hardware access in tmc_init_hw_config(). For cluster TMCs, use smp_call_function_single() to ensure register visibility. - Encapsulate CoreSight device registration and misc_register setup in tmc_add_coresight_dev(). This ensures TMC initialization and runtime operations remain safe even when the CPU cluster is in low-power states, while maintaining compatibility with existing system-level TMCs. Link: https://lore.kernel.org/all/20251027-cpu_cluster_component_pm-v1-7-31355ac588c2@oss.qualcomm.com/ Signed-off-by: Yuanfang Zhang --- .../hwtracing/coresight/coresight-tmc-core.c | 204 ++++++++++++------ drivers/hwtracing/coresight/coresight-tmc.h | 6 + 2 files changed, 141 insertions(+), 69 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-tmc-core.c b/drivers/hwtracing/coresight/coresight-tmc-core.c index 36599c431be62..d00f23f9a479e 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-core.c +++ b/drivers/hwtracing/coresight/coresight-tmc-core.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -769,56 +770,14 @@ static void register_crash_dev_interface(struct tmc_drvdata *drvdata, "Valid crash tracedata found\n"); } -static int __tmc_probe(struct device *dev, struct resource *res) +static int tmc_add_coresight_dev(struct device *dev) { - int ret = 0; - u32 devid; - void __iomem *base; - struct coresight_platform_data *pdata = NULL; - struct tmc_drvdata *drvdata; + struct tmc_drvdata *drvdata = dev_get_drvdata(dev); struct coresight_desc desc = { 0 }; struct coresight_dev_list *dev_list = NULL; + int ret = 0; - drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL); - if (!drvdata) - return -ENOMEM; - - dev_set_drvdata(dev, drvdata); - - ret = coresight_get_enable_clocks(dev, &drvdata->pclk, &drvdata->atclk); - if (ret) - return ret; - - ret = -ENOMEM; - - /* Validity for the resource is already checked by the AMBA core */ - base = devm_ioremap_resource(dev, res); - if (IS_ERR(base)) { - ret = PTR_ERR(base); - goto out; - } - - drvdata->base = base; - desc.access = CSDEV_ACCESS_IOMEM(base); - - raw_spin_lock_init(&drvdata->spinlock); - - devid = readl_relaxed(drvdata->base + CORESIGHT_DEVID); - drvdata->config_type = BMVAL(devid, 6, 7); - drvdata->memwidth = tmc_get_memwidth(devid); - /* This device is not associated with a session */ - drvdata->pid = -1; - drvdata->etr_mode = ETR_MODE_AUTO; - - if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) { - drvdata->size = tmc_etr_get_default_buffer_size(dev); - drvdata->max_burst_size = tmc_etr_get_max_burst_size(dev); - } else { - drvdata->size = readl_relaxed(drvdata->base + TMC_RSZ) * 4; - } - - tmc_get_reserved_region(dev); - + desc.access = CSDEV_ACCESS_IOMEM(drvdata->base); desc.dev = dev; switch (drvdata->config_type) { @@ -834,9 +793,9 @@ static int __tmc_probe(struct device *dev, struct resource *res) desc.type = CORESIGHT_DEV_TYPE_SINK; desc.subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_SYSMEM; desc.ops = &tmc_etr_cs_ops; - ret = tmc_etr_setup_caps(dev, devid, &desc.access); + ret = tmc_etr_setup_caps(dev, drvdata->devid, &desc.access); if (ret) - goto out; + return ret; idr_init(&drvdata->idr); mutex_init(&drvdata->idr_mutex); dev_list = &etr_devs; @@ -851,44 +810,142 @@ static int __tmc_probe(struct device *dev, struct resource *res) break; default: pr_err("%s: Unsupported TMC config\n", desc.name); - ret = -EINVAL; - goto out; + return -EINVAL; } desc.name = coresight_alloc_device_name(dev_list, dev); - if (!desc.name) { - ret = -ENOMEM; + if (!desc.name) + return -ENOMEM; + + drvdata->desc_name = desc.name; + + desc.pdata = dev->platform_data; + + drvdata->csdev = coresight_register(&desc); + if (IS_ERR(drvdata->csdev)) + return PTR_ERR(drvdata->csdev); + + drvdata->miscdev.name = desc.name; + drvdata->miscdev.minor = MISC_DYNAMIC_MINOR; + drvdata->miscdev.fops = &tmc_fops; + ret = misc_register(&drvdata->miscdev); + if (ret) + coresight_unregister(drvdata->csdev); + + return ret; +} + +static void tmc_clear_self_claim_tag(struct tmc_drvdata *drvdata) +{ + struct csdev_access access = CSDEV_ACCESS_IOMEM(drvdata->base); + + coresight_clear_self_claim_tag(&access); +} + +static void tmc_init_hw_config(struct tmc_drvdata *drvdata) +{ + u32 devid; + + devid = readl_relaxed(drvdata->base + CORESIGHT_DEVID); + drvdata->config_type = BMVAL(devid, 6, 7); + drvdata->memwidth = tmc_get_memwidth(devid); + drvdata->devid = devid; + drvdata->size = readl_relaxed(drvdata->base + TMC_RSZ) * 4; + tmc_clear_self_claim_tag(drvdata); +} + +static void tmc_init_on_cpu(void *info) +{ + struct tmc_drvdata *drvdata = info; + + tmc_init_hw_config(drvdata); +} + +static struct cpumask *tmc_get_cpumask(struct device *dev) +{ + struct generic_pm_domain *pd; + + pd = pd_to_genpd(dev->pm_domain); + if (pd) + return pd->cpus; + + return NULL; +} + +static int __tmc_probe(struct device *dev, struct resource *res) +{ + int cpu, ret = 0; + void __iomem *base; + struct coresight_platform_data *pdata = NULL; + struct tmc_drvdata *drvdata; + + drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL); + if (!drvdata) + return -ENOMEM; + + dev_set_drvdata(dev, drvdata); + + ret = coresight_get_enable_clocks(dev, &drvdata->pclk, &drvdata->atclk); + if (ret) + return ret; + + ret = -ENOMEM; + + /* Validity for the resource is already checked by the AMBA core */ + base = devm_ioremap_resource(dev, res); + if (IS_ERR(base)) { + ret = PTR_ERR(base); goto out; } + drvdata->base = base; + + raw_spin_lock_init(&drvdata->spinlock); + /* This device is not associated with a session */ + drvdata->pid = -1; + drvdata->etr_mode = ETR_MODE_AUTO; + tmc_get_reserved_region(dev); + pdata = coresight_get_platform_data(dev); if (IS_ERR(pdata)) { ret = PTR_ERR(pdata); goto out; } dev->platform_data = pdata; - desc.pdata = pdata; - coresight_clear_self_claim_tag(&desc.access); - drvdata->csdev = coresight_register(&desc); - if (IS_ERR(drvdata->csdev)) { - ret = PTR_ERR(drvdata->csdev); - goto out; + if (is_of_node(dev_fwnode(dev)) && + of_device_is_compatible(dev->of_node, "arm,coresight-cpu-tmc")) { + drvdata->cpumask = tmc_get_cpumask(dev); + if (!drvdata->cpumask) + return -EINVAL; + + cpus_read_lock(); + for_each_cpu(cpu, drvdata->cpumask) { + ret = smp_call_function_single(cpu, + tmc_init_on_cpu, drvdata, 1); + if (!ret) + break; + } + cpus_read_unlock(); + if (ret) { + ret = 0; + goto out; + } + } else { + tmc_init_hw_config(drvdata); } - drvdata->miscdev.name = desc.name; - drvdata->miscdev.minor = MISC_DYNAMIC_MINOR; - drvdata->miscdev.fops = &tmc_fops; - ret = misc_register(&drvdata->miscdev); - if (ret) { - coresight_unregister(drvdata->csdev); - goto out; + if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) { + drvdata->size = tmc_etr_get_default_buffer_size(dev); + drvdata->max_burst_size = tmc_etr_get_max_burst_size(dev); } + ret = tmc_add_coresight_dev(dev); + out: if (is_tmc_crashdata_valid(drvdata) && !tmc_prepare_crashdata(drvdata)) - register_crash_dev_interface(drvdata, desc.name); + register_crash_dev_interface(drvdata, drvdata->desc_name); return ret; } @@ -934,10 +991,12 @@ static void __tmc_remove(struct device *dev) * etb fops in this case, device is there until last file * handler to this device is closed. */ - misc_deregister(&drvdata->miscdev); + if (!drvdata->cpumask) + misc_deregister(&drvdata->miscdev); if (drvdata->crashdev.fops) misc_deregister(&drvdata->crashdev); - coresight_unregister(drvdata->csdev); + if (drvdata->csdev) + coresight_unregister(drvdata->csdev); } static void tmc_remove(struct amba_device *adev) @@ -992,7 +1051,6 @@ static void tmc_platform_remove(struct platform_device *pdev) if (WARN_ON(!drvdata)) return; - __tmc_remove(&pdev->dev); pm_runtime_disable(&pdev->dev); } @@ -1029,6 +1087,13 @@ static const struct dev_pm_ops tmc_dev_pm_ops = { SET_RUNTIME_PM_OPS(tmc_runtime_suspend, tmc_runtime_resume, NULL) }; +static const struct of_device_id tmc_match[] = { + {.compatible = "arm,coresight-cpu-tmc"}, + {} +}; + +MODULE_DEVICE_TABLE(of, tmc_match); + #ifdef CONFIG_ACPI static const struct acpi_device_id tmc_acpi_ids[] = { {"ARMHC501", 0, 0, 0}, /* ARM CoreSight ETR */ @@ -1043,6 +1108,7 @@ static struct platform_driver tmc_platform_driver = { .remove = tmc_platform_remove, .driver = { .name = "coresight-tmc-platform", + .of_match_table = tmc_match, .acpi_match_table = ACPI_PTR(tmc_acpi_ids), .suppress_bind_attrs = true, .pm = &tmc_dev_pm_ops, diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h index cbb4ba4391585..f5c76ca2dc973 100644 --- a/drivers/hwtracing/coresight/coresight-tmc.h +++ b/drivers/hwtracing/coresight/coresight-tmc.h @@ -243,6 +243,9 @@ struct tmc_resrv_buf { * (after crash) by default. * @crash_mdata: Reserved memory for storing tmc crash metadata. * Used by ETR/ETF. + * @cpumask: CPU mask representing the CPUs related to this TMC. + * @devid: TMC variant ID inferred from the device configuration register. + * @desc_name: Name to be used while creating crash interface. */ struct tmc_drvdata { struct clk *atclk; @@ -273,6 +276,9 @@ struct tmc_drvdata { struct etr_buf *perf_buf; struct tmc_resrv_buf resrv_buf; struct tmc_resrv_buf crash_mdata; + struct cpumask *cpumask; + u32 devid; + const char *desc_name; }; struct etr_buf_operations { From 1ac94755e2096fcc1b85483c08ddaae919644eb0 Mon Sep 17 00:00:00 2001 From: Yuanfang Zhang Date: Mon, 27 Oct 2025 23:28:10 -0700 Subject: [PATCH 0085/2333] FROMLIST: coresight-tmc-etf: Refactor enable function for CPU cluster ETF support CPU cluster TMC instances share the cluster's power domain, so register access must occur on a CPU that keeps the domain powered. To ensure safe ETF enable sequences on such devices, split tmc_etf/etb_enable_hw function into two variants: - tmc_etf/etb_enable_hw_local: replaces the old tmc_etf/etb_enable_hw for normal ETF cases - tmc_etf/etb_enable_hw_smp_call: executes CPU cluster ETF enable on a CPU within the cluster via smp_call_function_single Also add a check to ensure the current CPU belongs to the cluster before calling tmc_etb_enable_hw_local for CPU cluster ETF. Link: https://lore.kernel.org/all/20251027-cpu_cluster_component_pm-v1-8-31355ac588c2@oss.qualcomm.com/ Signed-off-by: Yuanfang Zhang --- .../hwtracing/coresight/coresight-tmc-etf.c | 86 ++++++++++++++++--- 1 file changed, 76 insertions(+), 10 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c b/drivers/hwtracing/coresight/coresight-tmc-etf.c index 0f45ab5e52499..b8a1c10d4b4c4 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-etf.c +++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c @@ -47,7 +47,7 @@ static int __tmc_etb_enable_hw(struct tmc_drvdata *drvdata) return rc; } -static int tmc_etb_enable_hw(struct tmc_drvdata *drvdata) +static int tmc_etb_enable_hw_local(struct tmc_drvdata *drvdata) { int rc = coresight_claim_device(drvdata->csdev); @@ -60,6 +60,36 @@ static int tmc_etb_enable_hw(struct tmc_drvdata *drvdata) return rc; } +struct tmc_smp_arg { + struct tmc_drvdata *drvdata; + int rc; +}; + +static void tmc_etb_enable_hw_smp_call(void *info) +{ + struct tmc_smp_arg *arg = info; + + arg->rc = tmc_etb_enable_hw_local(arg->drvdata); +} + +static int tmc_etb_enable_hw(struct tmc_drvdata *drvdata) +{ + int cpu, ret; + struct tmc_smp_arg arg = { 0 }; + + if (!drvdata->cpumask) + return tmc_etb_enable_hw_local(drvdata); + + arg.drvdata = drvdata; + for_each_cpu(cpu, drvdata->cpumask) { + ret = smp_call_function_single(cpu, + tmc_etb_enable_hw_smp_call, &arg, 1); + if (!ret) + return arg.rc; + } + return ret; +} + static void tmc_etb_dump_hw(struct tmc_drvdata *drvdata) { char *bufp; @@ -130,7 +160,7 @@ static int __tmc_etf_enable_hw(struct tmc_drvdata *drvdata) return rc; } -static int tmc_etf_enable_hw(struct tmc_drvdata *drvdata) +static int tmc_etf_enable_hw_local(struct tmc_drvdata *drvdata) { int rc = coresight_claim_device(drvdata->csdev); @@ -143,6 +173,32 @@ static int tmc_etf_enable_hw(struct tmc_drvdata *drvdata) return rc; } +static void tmc_etf_enable_hw_smp_call(void *info) +{ + struct tmc_smp_arg *arg = info; + + arg->rc = tmc_etf_enable_hw_local(arg->drvdata); +} + +static int tmc_etf_enable_hw(struct tmc_drvdata *drvdata) +{ + int cpu, ret; + struct tmc_smp_arg arg = { 0 }; + + if (!drvdata->cpumask) + return tmc_etf_enable_hw_local(drvdata); + + arg.drvdata = drvdata; + + for_each_cpu(cpu, drvdata->cpumask) { + ret = smp_call_function_single(cpu, + tmc_etf_enable_hw_smp_call, &arg, 1); + if (!ret) + return arg.rc; + } + return ret; +} + static void tmc_etf_disable_hw(struct tmc_drvdata *drvdata) { struct coresight_device *csdev = drvdata->csdev; @@ -228,7 +284,11 @@ static int tmc_enable_etf_sink_sysfs(struct coresight_device *csdev) used = true; drvdata->buf = buf; } + raw_spin_unlock_irqrestore(&drvdata->spinlock, flags); + ret = tmc_etb_enable_hw(drvdata); + + raw_spin_lock_irqsave(&drvdata->spinlock, flags); if (!ret) { coresight_set_mode(csdev, CS_MODE_SYSFS); csdev->refcnt++; @@ -290,7 +350,10 @@ static int tmc_enable_etf_sink_perf(struct coresight_device *csdev, void *data) break; } - ret = tmc_etb_enable_hw(drvdata); + if (drvdata->cpumask && !cpumask_test_cpu(smp_processor_id(), drvdata->cpumask)) + break; + + ret = tmc_etb_enable_hw_local(drvdata); if (!ret) { /* Associate with monitored process. */ drvdata->pid = pid; @@ -374,19 +437,22 @@ static int tmc_enable_etf_link(struct coresight_device *csdev, return -EBUSY; } - if (csdev->refcnt == 0) { + if (csdev->refcnt == 0) + first_enable = true; + + if (!first_enable) + csdev->refcnt++; + + raw_spin_unlock_irqrestore(&drvdata->spinlock, flags); + if (first_enable) { ret = tmc_etf_enable_hw(drvdata); if (!ret) { coresight_set_mode(csdev, CS_MODE_SYSFS); - first_enable = true; + csdev->refcnt++; + dev_dbg(&csdev->dev, "TMC-ETF enabled\n"); } } - if (!ret) - csdev->refcnt++; - raw_spin_unlock_irqrestore(&drvdata->spinlock, flags); - if (first_enable) - dev_dbg(&csdev->dev, "TMC-ETF enabled\n"); return ret; } From a2de861a7702bff7ebfb18b9cd9bb2e01a29b5b3 Mon Sep 17 00:00:00 2001 From: Yuanfang Zhang Date: Mon, 27 Oct 2025 23:28:11 -0700 Subject: [PATCH 0086/2333] FROMLIST: coresight-tmc: Update tmc_mgmt_attrs for CPU cluster TMC compatibility This patch refactors the sysfs interfaces to ensure compatibility with CPU cluster TMC. When operating on a CPU cluster TMC, register reads are performed via `smp_call_function_single()`. Link: https://lore.kernel.org/all/20251027-cpu_cluster_component_pm-v1-9-31355ac588c2@oss.qualcomm.com/ Signed-off-by: Yuanfang Zhang --- .../hwtracing/coresight/coresight-tmc-core.c | 137 ++++++++++++++++-- 1 file changed, 123 insertions(+), 14 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-tmc-core.c b/drivers/hwtracing/coresight/coresight-tmc-core.c index d00f23f9a479e..685a64d8ba1b5 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-core.c +++ b/drivers/hwtracing/coresight/coresight-tmc-core.c @@ -458,21 +458,130 @@ static enum tmc_mem_intf_width tmc_get_memwidth(u32 devid) return memwidth; } +struct tmc_smp_arg { + struct tmc_drvdata *drvdata; + u32 offset; + int rc; +}; + +static void tmc_read_reg_smp_call(void *info) +{ + struct tmc_smp_arg *arg = info; + + arg->rc = readl_relaxed(arg->drvdata->base + arg->offset); +} + +static u32 cpu_tmc_read_reg(struct tmc_drvdata *drvdata, u32 offset) +{ + struct tmc_smp_arg arg = { + .drvdata = drvdata, + .offset = offset, + }; + int cpu, ret = 0; + + for_each_cpu(cpu, drvdata->cpumask) { + ret = smp_call_function_single(cpu, + tmc_read_reg_smp_call, &arg, 1); + if (!ret) + return arg.rc; + } + + return ret; +} + +static ssize_t coresight_tmc_reg32_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tmc_drvdata *drvdata = dev_get_drvdata(dev->parent); + struct cs_off_attribute *cs_attr = container_of(attr, struct cs_off_attribute, attr); + int ret; + u32 val; + + ret = pm_runtime_resume_and_get(dev->parent); + if (ret < 0) + return ret; + + if (!drvdata->cpumask) + val = readl_relaxed(drvdata->base + cs_attr->off); + else + val = cpu_tmc_read_reg(drvdata, cs_attr->off); + + pm_runtime_put(dev->parent); + + if (ret < 0) + return ret; + else + return sysfs_emit(buf, "0x%x\n", val); +} + +static ssize_t coresight_tmc_reg64_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tmc_drvdata *drvdata = dev_get_drvdata(dev->parent); + struct cs_pair_attribute *cs_attr = container_of(attr, struct cs_pair_attribute, attr); + int ret; + u64 val; + + ret = pm_runtime_resume_and_get(dev->parent); + if (ret < 0) + return ret; + if (!drvdata->cpumask) { + val = readl_relaxed(drvdata->base + cs_attr->lo_off) | + ((u64)readl_relaxed(drvdata->base + cs_attr->hi_off) << 32); + } else { + ret = cpu_tmc_read_reg(drvdata, cs_attr->lo_off); + + if (ret < 0) + goto out; + + val = ret; + + ret = cpu_tmc_read_reg(drvdata, cs_attr->hi_off); + if (ret < 0) + goto out; + + val |= ((u64)ret << 32); + } + +out: + pm_runtime_put_sync(dev->parent); + if (ret < 0) + return ret; + else + return sysfs_emit(buf, "0x%llx\n", val); +} + +#define coresight_tmc_reg32(name, offset) \ + (&((struct cs_off_attribute[]) { \ + { \ + __ATTR(name, 0444, coresight_tmc_reg32_show, NULL), \ + offset \ + } \ + })[0].attr.attr) +#define coresight_tmc_reg64(name, lo_off, hi_off) \ + (&((struct cs_pair_attribute[]) { \ + { \ + __ATTR(name, 0444, coresight_tmc_reg64_show, NULL), \ + lo_off, hi_off \ + } \ + })[0].attr.attr) static struct attribute *coresight_tmc_mgmt_attrs[] = { - coresight_simple_reg32(rsz, TMC_RSZ), - coresight_simple_reg32(sts, TMC_STS), - coresight_simple_reg64(rrp, TMC_RRP, TMC_RRPHI), - coresight_simple_reg64(rwp, TMC_RWP, TMC_RWPHI), - coresight_simple_reg32(trg, TMC_TRG), - coresight_simple_reg32(ctl, TMC_CTL), - coresight_simple_reg32(ffsr, TMC_FFSR), - coresight_simple_reg32(ffcr, TMC_FFCR), - coresight_simple_reg32(mode, TMC_MODE), - coresight_simple_reg32(pscr, TMC_PSCR), - coresight_simple_reg32(devid, CORESIGHT_DEVID), - coresight_simple_reg64(dba, TMC_DBALO, TMC_DBAHI), - coresight_simple_reg32(axictl, TMC_AXICTL), - coresight_simple_reg32(authstatus, TMC_AUTHSTATUS), + coresight_tmc_reg32(rsz, TMC_RSZ), + coresight_tmc_reg32(sts, TMC_STS), + coresight_tmc_reg64(rrp, TMC_RRP, TMC_RRPHI), + coresight_tmc_reg64(rwp, TMC_RWP, TMC_RWPHI), + coresight_tmc_reg32(trg, TMC_TRG), + coresight_tmc_reg32(ctl, TMC_CTL), + coresight_tmc_reg32(ffsr, TMC_FFSR), + coresight_tmc_reg32(ffcr, TMC_FFCR), + coresight_tmc_reg32(mode, TMC_MODE), + coresight_tmc_reg32(pscr, TMC_PSCR), + coresight_tmc_reg32(devid, CORESIGHT_DEVID), + coresight_tmc_reg64(dba, TMC_DBALO, TMC_DBAHI), + coresight_tmc_reg32(axictl, TMC_AXICTL), + coresight_tmc_reg32(authstatus, TMC_AUTHSTATUS), NULL, }; From a64e607b1ebf657adffbd1fd33b55e5f2abd895b Mon Sep 17 00:00:00 2001 From: Yuanfang Zhang Date: Mon, 27 Oct 2025 23:28:12 -0700 Subject: [PATCH 0087/2333] FROMLIST: coresight-tmc: Handle delayed probe for CPU cluster TMC Delay probe the cpu cluster TMC when all CPUs of this cluster are offline, re-probe the funnel when any CPU in the cluster comes online. Key changes: - Introduce a global list to track delayed TMCs waiting for CPU online. - Add CPU hotplug callback to retry registration when the CPU comes up. Link: https://lore.kernel.org/all/20251027-cpu_cluster_component_pm-v1-10-31355ac588c2@oss.qualcomm.com/ Signed-off-by: Yuanfang Zhang --- .../hwtracing/coresight/coresight-tmc-core.c | 59 ++++++++++++++++++- drivers/hwtracing/coresight/coresight-tmc.h | 4 ++ 2 files changed, 61 insertions(+), 2 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-tmc-core.c b/drivers/hwtracing/coresight/coresight-tmc-core.c index 685a64d8ba1b5..7274ad07c2b20 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-core.c +++ b/drivers/hwtracing/coresight/coresight-tmc-core.c @@ -36,6 +36,9 @@ DEFINE_CORESIGHT_DEVLIST(etb_devs, "tmc_etb"); DEFINE_CORESIGHT_DEVLIST(etf_devs, "tmc_etf"); DEFINE_CORESIGHT_DEVLIST(etr_devs, "tmc_etr"); +static LIST_HEAD(tmc_delay_probe); +static enum cpuhp_state hp_online; +static DEFINE_SPINLOCK(delay_lock); int tmc_wait_for_tmcready(struct tmc_drvdata *drvdata) { @@ -1028,6 +1031,8 @@ static int __tmc_probe(struct device *dev, struct resource *res) if (!drvdata->cpumask) return -EINVAL; + drvdata->dev = dev; + cpus_read_lock(); for_each_cpu(cpu, drvdata->cpumask) { ret = smp_call_function_single(cpu, @@ -1035,11 +1040,16 @@ static int __tmc_probe(struct device *dev, struct resource *res) if (!ret) break; } - cpus_read_unlock(); + if (ret) { + scoped_guard(spinlock, &delay_lock) + list_add(&drvdata->link, &tmc_delay_probe); + cpus_read_unlock(); ret = 0; goto out; } + + cpus_read_unlock(); } else { tmc_init_hw_config(drvdata); } @@ -1104,8 +1114,12 @@ static void __tmc_remove(struct device *dev) misc_deregister(&drvdata->miscdev); if (drvdata->crashdev.fops) misc_deregister(&drvdata->crashdev); - if (drvdata->csdev) + if (drvdata->csdev) { coresight_unregister(drvdata->csdev); + } else { + scoped_guard(spinlock, &delay_lock) + list_del(&drvdata->link); + } } static void tmc_remove(struct amba_device *adev) @@ -1224,14 +1238,55 @@ static struct platform_driver tmc_platform_driver = { }, }; +static int tmc_online_cpu(unsigned int cpu) +{ + struct tmc_drvdata *drvdata, *tmp; + int ret; + + spin_lock(&delay_lock); + list_for_each_entry_safe(drvdata, tmp, &tmc_delay_probe, link) { + if (cpumask_test_cpu(cpu, drvdata->cpumask)) { + list_del(&drvdata->link); + + spin_unlock(&delay_lock); + ret = pm_runtime_resume_and_get(drvdata->dev); + if (ret < 0) + return 0; + + tmc_init_hw_config(drvdata); + tmc_clear_self_claim_tag(drvdata); + tmc_add_coresight_dev(drvdata->dev); + pm_runtime_put(drvdata->dev); + spin_lock(&delay_lock); + } + } + spin_unlock(&delay_lock); + return 0; +} + static int __init tmc_init(void) { + int ret; + + ret = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN, + "arm/coresight-tmc:online", + tmc_online_cpu, NULL); + + if (ret > 0) + hp_online = ret; + else + return ret; + return coresight_init_driver("tmc", &tmc_driver, &tmc_platform_driver, THIS_MODULE); } static void __exit tmc_exit(void) { coresight_remove_driver(&tmc_driver, &tmc_platform_driver); + if (hp_online) { + cpuhp_remove_state_nocalls(hp_online); + hp_online = 0; + } } module_init(tmc_init); module_exit(tmc_exit); diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h index f5c76ca2dc973..29ccf0b7f4fe9 100644 --- a/drivers/hwtracing/coresight/coresight-tmc.h +++ b/drivers/hwtracing/coresight/coresight-tmc.h @@ -246,6 +246,8 @@ struct tmc_resrv_buf { * @cpumask: CPU mask representing the CPUs related to this TMC. * @devid: TMC variant ID inferred from the device configuration register. * @desc_name: Name to be used while creating crash interface. + * @dev: pointer to the device associated with this TMC. + * @link: link to the delay_probed list. */ struct tmc_drvdata { struct clk *atclk; @@ -279,6 +281,8 @@ struct tmc_drvdata { struct cpumask *cpumask; u32 devid; const char *desc_name; + struct device *dev; + struct list_head link; }; struct etr_buf_operations { From 96e5287bdd0698d5a5709fa2e872abdfeb9ee98c Mon Sep 17 00:00:00 2001 From: Yuanfang Zhang Date: Mon, 27 Oct 2025 23:28:13 -0700 Subject: [PATCH 0088/2333] FROMLIST: coresight: add 'cs_mode' to link enable functions Extend the coresight link enable interfaces to accept an `enum cs_mode` argument. This allows link drivers to distinguish between sysfs and perf coresight modes when enabling links. This change is necessary because enabling CPU cluster links may involve calling `smp_call_function_single()`, which is unsafe in perf mode due to context constraints. By passing the tracing mode explicitly, link drivers can apply mode-specific logic to avoid unsafe operations. Link: https://lore.kernel.org/all/20251027-cpu_cluster_component_pm-v1-11-31355ac588c2@oss.qualcomm.com/ Signed-off-by: Yuanfang Zhang --- drivers/hwtracing/coresight/coresight-core.c | 7 +++--- .../hwtracing/coresight/coresight-funnel.c | 21 ++++++++++++++++- .../coresight/coresight-replicator.c | 23 ++++++++++++++++++- .../hwtracing/coresight/coresight-tmc-etf.c | 19 ++++++++++++++- drivers/hwtracing/coresight/coresight-tnoc.c | 3 ++- drivers/hwtracing/coresight/coresight-tpda.c | 3 ++- include/linux/coresight.h | 3 ++- 7 files changed, 70 insertions(+), 9 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c index 3267192f0c1c6..2e62005655dbc 100644 --- a/drivers/hwtracing/coresight/coresight-core.c +++ b/drivers/hwtracing/coresight/coresight-core.c @@ -313,7 +313,8 @@ static void coresight_disable_sink(struct coresight_device *csdev) static int coresight_enable_link(struct coresight_device *csdev, struct coresight_device *parent, struct coresight_device *child, - struct coresight_device *source) + struct coresight_device *source, + enum cs_mode mode) { int link_subtype; struct coresight_connection *inconn, *outconn; @@ -330,7 +331,7 @@ static int coresight_enable_link(struct coresight_device *csdev, if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT && IS_ERR(outconn)) return PTR_ERR(outconn); - return link_ops(csdev)->enable(csdev, inconn, outconn); + return link_ops(csdev)->enable(csdev, inconn, outconn, mode); } static void coresight_disable_link(struct coresight_device *csdev, @@ -546,7 +547,7 @@ int coresight_enable_path(struct coresight_path *path, enum cs_mode mode, case CORESIGHT_DEV_TYPE_LINK: parent = list_prev_entry(nd, link)->csdev; child = list_next_entry(nd, link)->csdev; - ret = coresight_enable_link(csdev, parent, child, source); + ret = coresight_enable_link(csdev, parent, child, source, mode); if (ret) goto err_disable_helpers; break; diff --git a/drivers/hwtracing/coresight/coresight-funnel.c b/drivers/hwtracing/coresight/coresight-funnel.c index 43b9287a865eb..fd8dcd541454b 100644 --- a/drivers/hwtracing/coresight/coresight-funnel.c +++ b/drivers/hwtracing/coresight/coresight-funnel.c @@ -121,7 +121,8 @@ static int funnel_enable_hw(struct funnel_drvdata *drvdata, int port) static int funnel_enable(struct coresight_device *csdev, struct coresight_connection *in, - struct coresight_connection *out) + struct coresight_connection *out, + enum cs_mode mode) { int rc = 0; struct funnel_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); @@ -135,6 +136,23 @@ static int funnel_enable(struct coresight_device *csdev, else in->dest_refcnt++; + if (mode == CS_MODE_PERF) { + if (first_enable) { + if (drvdata->cpumask && + !cpumask_test_cpu(smp_processor_id(), drvdata->cpumask)) { + raw_spin_unlock_irqrestore(&drvdata->spinlock, flags); + return -EINVAL; + } + + if (drvdata->base) + rc = dynamic_funnel_enable_hw(drvdata, in->dest_port); + if (!rc) + in->dest_refcnt++; + } + raw_spin_unlock_irqrestore(&drvdata->spinlock, flags); + return rc; + } + raw_spin_unlock_irqrestore(&drvdata->spinlock, flags); if (first_enable) { @@ -183,6 +201,7 @@ static void funnel_disable(struct coresight_device *csdev, dynamic_funnel_disable_hw(drvdata, in->dest_port); last_disable = true; } + raw_spin_unlock_irqrestore(&drvdata->spinlock, flags); if (last_disable) diff --git a/drivers/hwtracing/coresight/coresight-replicator.c b/drivers/hwtracing/coresight/coresight-replicator.c index 22c9bc71817d2..6cb57763f9b10 100644 --- a/drivers/hwtracing/coresight/coresight-replicator.c +++ b/drivers/hwtracing/coresight/coresight-replicator.c @@ -199,7 +199,8 @@ static int replicator_enable_hw(struct replicator_drvdata *drvdata, static int replicator_enable(struct coresight_device *csdev, struct coresight_connection *in, - struct coresight_connection *out) + struct coresight_connection *out, + enum cs_mode mode) { int rc = 0; struct replicator_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); @@ -212,6 +213,25 @@ static int replicator_enable(struct coresight_device *csdev, first_enable = true; else out->src_refcnt++; + + if (mode == CS_MODE_PERF) { + if (first_enable) { + if (drvdata->cpumask && + !cpumask_test_cpu(smp_processor_id(), drvdata->cpumask)) { + raw_spin_unlock_irqrestore(&drvdata->spinlock, flags); + return -EINVAL; + } + + if (drvdata->base) + rc = dynamic_replicator_enable(drvdata, in->dest_port, + out->src_port); + if (!rc) + out->src_refcnt++; + } + raw_spin_unlock_irqrestore(&drvdata->spinlock, flags); + return rc; + } + raw_spin_unlock_irqrestore(&drvdata->spinlock, flags); if (first_enable) { @@ -272,6 +292,7 @@ static void replicator_disable(struct coresight_device *csdev, out->src_port); last_disable = true; } + raw_spin_unlock_irqrestore(&drvdata->spinlock, flags); if (last_disable) diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c b/drivers/hwtracing/coresight/coresight-tmc-etf.c index b8a1c10d4b4c4..281c3b316dc3c 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-etf.c +++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c @@ -424,7 +424,8 @@ static int tmc_disable_etf_sink(struct coresight_device *csdev) static int tmc_enable_etf_link(struct coresight_device *csdev, struct coresight_connection *in, - struct coresight_connection *out) + struct coresight_connection *out, + enum cs_mode mode) { int ret = 0; unsigned long flags; @@ -443,6 +444,22 @@ static int tmc_enable_etf_link(struct coresight_device *csdev, if (!first_enable) csdev->refcnt++; + if (mode == CS_MODE_PERF) { + if (first_enable) { + if (drvdata->cpumask && + !cpumask_test_cpu(smp_processor_id(), drvdata->cpumask)) { + raw_spin_unlock_irqrestore(&drvdata->spinlock, flags); + return -EINVAL; + } + + ret = tmc_etf_enable_hw_local(drvdata); + if (!ret) + csdev->refcnt++; + } + raw_spin_unlock_irqrestore(&drvdata->spinlock, flags); + return ret; + } + raw_spin_unlock_irqrestore(&drvdata->spinlock, flags); if (first_enable) { ret = tmc_etf_enable_hw(drvdata); diff --git a/drivers/hwtracing/coresight/coresight-tnoc.c b/drivers/hwtracing/coresight/coresight-tnoc.c index ff9a0a9cfe96e..48e9e685b9439 100644 --- a/drivers/hwtracing/coresight/coresight-tnoc.c +++ b/drivers/hwtracing/coresight/coresight-tnoc.c @@ -73,7 +73,8 @@ static void trace_noc_enable_hw(struct trace_noc_drvdata *drvdata) } static int trace_noc_enable(struct coresight_device *csdev, struct coresight_connection *inport, - struct coresight_connection *outport) + struct coresight_connection *outport, + enum cs_mode mode) { struct trace_noc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); diff --git a/drivers/hwtracing/coresight/coresight-tpda.c b/drivers/hwtracing/coresight/coresight-tpda.c index e9e2736071fb5..03eb6c7fc84f4 100644 --- a/drivers/hwtracing/coresight/coresight-tpda.c +++ b/drivers/hwtracing/coresight/coresight-tpda.c @@ -241,7 +241,8 @@ static int __tpda_enable(struct tpda_drvdata *drvdata, int port) static int tpda_enable(struct coresight_device *csdev, struct coresight_connection *in, - struct coresight_connection *out) + struct coresight_connection *out, + enum cs_mode mode) { struct tpda_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); int ret = 0; diff --git a/include/linux/coresight.h b/include/linux/coresight.h index 6de59ce8ef8ca..f4d522dc096cb 100644 --- a/include/linux/coresight.h +++ b/include/linux/coresight.h @@ -385,7 +385,8 @@ struct coresight_ops_sink { struct coresight_ops_link { int (*enable)(struct coresight_device *csdev, struct coresight_connection *in, - struct coresight_connection *out); + struct coresight_connection *out, + enum cs_mode mode); void (*disable)(struct coresight_device *csdev, struct coresight_connection *in, struct coresight_connection *out); From 6001cdfa47e6836e0faebfdd58b9caa93333188f Mon Sep 17 00:00:00 2001 From: Jie Gan Date: Mon, 3 Nov 2025 16:44:09 +0800 Subject: [PATCH 0089/2333] FROMLIST: arm64: dts: qcom: kodiak: add coresight nodes Add TPDM, TPDA, CTI and funnel coresight devices for AOSS and QDSS blocks. Link: https://lore.kernel.org/all/20251103-add-coresight-nodes-for-sc7280-v1-1-13d503123c07@oss.qualcomm.com/ Signed-off-by: Jie Gan --- arch/arm64/boot/dts/qcom/sc7280.dtsi | 290 +++++++++++++++++++++++++++ 1 file changed, 290 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sc7280.dtsi b/arch/arm64/boot/dts/qcom/sc7280.dtsi index 4bb3981bf6ea1..b7122566d36b0 100644 --- a/arch/arm64/boot/dts/qcom/sc7280.dtsi +++ b/arch/arm64/boot/dts/qcom/sc7280.dtsi @@ -3338,6 +3338,85 @@ }; }; + tpda@6004000 { + compatible = "qcom,coresight-tpda", "arm,primecell"; + reg = <0x0 0x06004000 0x0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + + in-ports { + #address-cells = <1>; + #size-cells = <0>; + + port@1c { + reg = <28>; + qdss_tpda_in28: endpoint { + remote-endpoint = <&spdm_tpdm_out>; + }; + }; + }; + + out-ports { + port { + qdss_tpda_out: endpoint { + remote-endpoint = <&qdss_dl_funnel_in0>; + }; + }; + }; + }; + + funnel@6005000 { + compatible = "arm,coresight-dynamic-funnel", "arm,primecell"; + reg = <0x0 0x06005000 0x0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + + in-ports { + port { + qdss_dl_funnel_in0: endpoint { + remote-endpoint = <&qdss_tpda_out>; + }; + }; + }; + + out-ports { + port { + qdss_dl_funnel_out: endpoint { + remote-endpoint = <&funnel0_in6>; + }; + }; + }; + }; + + tpdm@600f000 { + compatible = "qcom,coresight-tpdm", "arm,primecell"; + reg = <0x0 0x0600f000 0x0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + + qcom,cmb-element-bits = <32>; + qcom,cmb-msrs-num = <32>; + + out-ports { + port { + spdm_tpdm_out: endpoint { + remote-endpoint = <&qdss_tpda_in28>; + }; + }; + }; + }; + + cti@6010000 { + compatible = "arm,coresight-cti", "arm,primecell"; + reg = <0x0 0x06010000 0x0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + }; + funnel@6041000 { compatible = "arm,coresight-dynamic-funnel", "arm,primecell"; reg = <0 0x06041000 0 0x1000>; @@ -3357,6 +3436,14 @@ #address-cells = <1>; #size-cells = <0>; + port@6 { + reg = <6>; + + funnel0_in6: endpoint { + remote-endpoint = <&qdss_dl_funnel_out>; + }; + }; + port@7 { reg = <7>; funnel0_in7: endpoint { @@ -3471,6 +3558,38 @@ }; }; + cti@6b00000 { + compatible = "arm,coresight-cti", "arm,primecell"; + reg = <0x0 0x06b00000 0x0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + }; + + cti@6b01000 { + compatible = "arm,coresight-cti", "arm,primecell"; + reg = <0x0 0x06b01000 0x0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + }; + + cti@6b02000 { + compatible = "arm,coresight-cti", "arm,primecell"; + reg = <0x0 0x06b02000 0x0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + }; + + cti@6b03000 { + compatible = "arm,coresight-cti", "arm,primecell"; + reg = <0x0 0x06b03000 0x0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + }; + funnel@6b04000 { compatible = "arm,coresight-dynamic-funnel", "arm,primecell"; reg = <0 0x06b04000 0 0x1000>; @@ -3490,6 +3609,13 @@ #address-cells = <1>; #size-cells = <0>; + port@6 { + reg = <6>; + swao_funnel_in6: endpoint { + remote-endpoint = <&aoss_tpda_out>; + }; + }; + port@7 { reg = <7>; swao_funnel_in: endpoint { @@ -3548,6 +3674,170 @@ }; }; + tpda@6b08000 { + compatible = "qcom,coresight-tpda", "arm,primecell"; + reg = <0x0 0x06b08000 0x0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + + in-ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + aoss_tpda_in0: endpoint { + remote-endpoint = <&swao_prio0_tpdm_out>; + }; + }; + + port@1 { + reg = <1>; + + aoss_tpda_in1: endpoint { + remote-endpoint = <&swao_prio1_tpdm_out>; + }; + }; + + port@2 { + reg = <2>; + + aoss_tpda_in2: endpoint { + remote-endpoint = <&swao_prio2_tpdm_out>; + }; + }; + + port@3 { + reg = <3>; + + aoss_tpda_in3: endpoint { + remote-endpoint = <&swao_prio3_tpdm_out>; + }; + }; + + port@4 { + reg = <4>; + + aoss_tpda_in4: endpoint { + remote-endpoint = <&swao_tpdm_out>; + }; + }; + }; + + out-ports { + port { + aoss_tpda_out: endpoint { + remote-endpoint = <&swao_funnel_in6>; + }; + }; + }; + }; + + tpdm@6b09000 { + compatible = "qcom,coresight-tpdm", "arm,primecell"; + reg = <0x0 0x06b09000 0x0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + + qcom,cmb-element-bits = <64>; + qcom,cmb-msrs-num = <32>; + + out-ports { + port { + swao_prio0_tpdm_out: endpoint { + remote-endpoint = <&aoss_tpda_in0>; + }; + }; + }; + }; + + tpdm@6b0a000 { + compatible = "qcom,coresight-tpdm", "arm,primecell"; + reg = <0x0 0x06b0a000 0x0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + + qcom,cmb-element-bits = <64>; + qcom,cmb-msrs-num = <32>; + + out-ports { + port { + swao_prio1_tpdm_out: endpoint { + remote-endpoint = <&aoss_tpda_in1>; + }; + }; + }; + }; + + tpdm@6b0b000 { + compatible = "qcom,coresight-tpdm", "arm,primecell"; + reg = <0x0 0x06b0b000 0x0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + + qcom,cmb-element-bits = <64>; + qcom,cmb-msrs-num = <32>; + + out-ports { + port { + swao_prio2_tpdm_out: endpoint { + remote-endpoint = <&aoss_tpda_in2>; + }; + }; + }; + }; + + tpdm@6b0c000 { + compatible = "qcom,coresight-tpdm", "arm,primecell"; + reg = <0x0 0x06b0c000 0x0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + + qcom,cmb-element-bits = <64>; + qcom,cmb-msrs-num = <32>; + + out-ports { + port { + swao_prio3_tpdm_out: endpoint { + remote-endpoint = <&aoss_tpda_in3>; + }; + }; + }; + }; + + tpdm@6b0d000 { + compatible = "qcom,coresight-tpdm", "arm,primecell"; + reg = <0x0 0x06b0d000 0x0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + + qcom,dsb-element-bits = <32>; + qcom,dsb-msrs-num = <32>; + + out-ports { + port { + swao_tpdm_out: endpoint { + remote-endpoint = <&aoss_tpda_in4>; + }; + }; + }; + }; + + cti@6b11000 { + compatible = "arm,coresight-cti", "arm,primecell"; + reg = <0x0 0x06b11000 0x0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + }; + etm@7040000 { compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0 0x07040000 0 0x1000>; From 37e24ac9af02ba14cf3ff5e8a2fa7457018d0579 Mon Sep 17 00:00:00 2001 From: Yuanfang Zhang Date: Mon, 27 Oct 2025 23:28:14 -0700 Subject: [PATCH 0090/2333] FROMLIST: arm64: dts: qcom: x1e80100: add Coresight nodes for APSS debug block Add below Coresight devices for APSS debug block: -ETM -TMC ETF -Funnel -Replicator Link: https://lore.kernel.org/all/20251027-cpu_cluster_component_pm-v1-12-31355ac588c2@oss.qualcomm.com/ Signed-off-by: Yuanfang Zhang Signed-off-by: Jie Gan --- arch/arm64/boot/dts/qcom/x1e80100.dtsi | 885 +++++++++++++++++++++++++ arch/arm64/boot/dts/qcom/x1p42100.dtsi | 12 + 2 files changed, 897 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/x1e80100.dtsi b/arch/arm64/boot/dts/qcom/x1e80100.dtsi index 51576d9c935de..f4b59f0163351 100644 --- a/arch/arm64/boot/dts/qcom/x1e80100.dtsi +++ b/arch/arm64/boot/dts/qcom/x1e80100.dtsi @@ -6785,6 +6785,14 @@ }; }; + port@4 { + reg = <4>; + + funnel1_in4: endpoint { + remote-endpoint = <&apss_funnel_out>; + }; + }; + port@5 { reg = <5>; @@ -8075,6 +8083,883 @@ }; }; + apss_funnel: funnel@12080000 { + compatible = "arm,coresight-dynamic-funnel", "arm,primecell"; + reg = <0x0 0x12080000 0x0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + + in-ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + apss_funnel_in0: endpoint { + remote-endpoint = <&ncc0_etf_out>; + }; + }; + + port@1 { + reg = <1>; + + apss_funnel_in1: endpoint { + remote-endpoint = <&ncc1_etf_out>; + }; + }; + + port@2 { + reg = <2>; + + apss_funnel_in2: endpoint { + remote-endpoint = <&ncc2_etf_out>; + }; + }; + }; + + out-ports { + port { + apss_funnel_out: endpoint { + remote-endpoint = + <&funnel1_in4>; + }; + }; + }; + }; + + etm@13021000 { + compatible = "arm,coresight-etm4x-sysreg"; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + cpu = <&cpu0>; + qcom,skip-power-up; + + out-ports { + port { + etm0_out: endpoint { + remote-endpoint = <&ncc0_0_rep_in>; + }; + }; + }; + }; + + etm@13121000 { + compatible = "arm,coresight-etm4x-sysreg"; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + cpu = <&cpu1>; + qcom,skip-power-up; + + out-ports { + port { + etm1_out: endpoint { + remote-endpoint = <&ncc0_1_rep_in>; + }; + }; + }; + }; + + etm@13221000 { + compatible = "arm,coresight-etm4x-sysreg"; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + cpu = <&cpu2>; + qcom,skip-power-up; + + out-ports { + port { + etm2_out: endpoint { + remote-endpoint = <&ncc0_2_rep_in>; + }; + }; + }; + }; + + etm@13321000 { + compatible = "arm,coresight-etm4x-sysreg"; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + cpu = <&cpu3>; + qcom,skip-power-up; + + out-ports { + port { + etm3_out: endpoint { + remote-endpoint = <&ncc0_3_rep_in>; + }; + }; + }; + }; + + funnel@13401000 { + compatible = "arm,coresight-cpu-funnel"; + reg = <0x0 0x13401000 0x0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + power-domains = <&cluster_pd0>; + + in-ports { + #address-cells = <1>; + #size-cells = <0>; + + port@2 { + reg = <2>; + + ncc0_2_funnel_in2: endpoint { + remote-endpoint = <&ncc0_1_funnel_out>; + }; + }; + }; + + out-ports { + port { + ncc0_2_funnel_out: endpoint { + remote-endpoint = <&ncc0_etf_in>; + }; + }; + }; + }; + + tmc@13409000 { + compatible = "arm,coresight-cpu-tmc"; + reg = <0x0 0x13409000 0x0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + power-domains = <&cluster_pd0>; + + in-ports { + port { + ncc0_etf_in: endpoint { + remote-endpoint = <&ncc0_2_funnel_out>; + }; + }; + }; + + out-ports { + port { + ncc0_etf_out: endpoint { + remote-endpoint = <&apss_funnel_in0>; + }; + }; + }; + }; + + replicator@13490000 { + compatible = "arm,coresight-cpu-replicator"; + reg = <0x0 0x13490000 0x0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + power-domains = <&cluster_pd0>; + + in-ports { + port { + ncc0_0_rep_in: endpoint { + remote-endpoint = <&etm0_out>; + }; + }; + }; + + out-ports { + port { + ncc0_0_rep_out: endpoint { + remote-endpoint = <&ncc0_1_funnel_in0>; + }; + }; + }; + }; + + replicator@134a0000 { + compatible = "arm,coresight-cpu-replicator"; + reg = <0x0 0x134a0000 0x0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + power-domains = <&cluster_pd0>; + + in-ports { + port { + ncc0_1_rep_in: endpoint { + remote-endpoint = <&etm1_out>; + }; + }; + }; + + out-ports { + port { + ncc0_1_rep_out: endpoint { + remote-endpoint = <&ncc0_1_funnel_in1>; + }; + }; + }; + }; + + replicator@134b0000 { + compatible = "arm,coresight-cpu-replicator"; + reg = <0x0 0x134b0000 0x0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + power-domains = <&cluster_pd0>; + + in-ports { + port { + ncc0_2_rep_in: endpoint { + remote-endpoint = <&etm2_out>; + }; + }; + }; + + out-ports { + port { + ncc0_2_rep_out: endpoint { + remote-endpoint = <&ncc0_1_funnel_in2>; + }; + }; + }; + }; + + replicator@134c0000 { + compatible = "arm,coresight-cpu-replicator"; + reg = <0x0 0x134c0000 0x0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + power-domains = <&cluster_pd0>; + + in-ports { + port { + ncc0_3_rep_in: endpoint { + remote-endpoint = <&etm3_out>; + }; + }; + }; + + out-ports { + port { + ncc0_3_rep_out: endpoint { + remote-endpoint = <&ncc0_1_funnel_in3>; + }; + }; + }; + }; + + funnel@134d0000 { + compatible = "arm,coresight-cpu-funnel"; + reg = <0x0 0x134d0000 0x0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + power-domains = <&cluster_pd0>; + + in-ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + ncc0_1_funnel_in0: endpoint { + remote-endpoint = <&ncc0_0_rep_out>; + }; + }; + + port@1 { + reg = <1>; + + ncc0_1_funnel_in1: endpoint { + remote-endpoint = <&ncc0_1_rep_out>; + }; + }; + + port@2 { + reg = <2>; + + ncc0_1_funnel_in2: endpoint { + remote-endpoint = <&ncc0_2_rep_out>; + }; + }; + + port@3 { + reg = <3>; + + ncc0_1_funnel_in3: endpoint { + remote-endpoint = <&ncc0_3_rep_out>; + }; + }; + }; + + out-ports { + port { + ncc0_1_funnel_out: endpoint { + remote-endpoint = <&ncc0_2_funnel_in2>; + }; + }; + }; + }; + + etm@13521000 { + compatible = "arm,coresight-etm4x-sysreg"; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + cpu = <&cpu4>; + qcom,skip-power-up; + + out-ports { + port { + etm4_out: endpoint { + remote-endpoint = <&ncc1_0_rep_in>; + }; + }; + }; + }; + + etm@13621000 { + compatible = "arm,coresight-etm4x-sysreg"; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + cpu = <&cpu5>; + qcom,skip-power-up; + + out-ports { + port { + etm5_out: endpoint { + remote-endpoint = <&ncc1_1_rep_in>; + }; + }; + }; + }; + + etm@13721000 { + compatible = "arm,coresight-etm4x-sysreg"; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + cpu = <&cpu6>; + qcom,skip-power-up; + + out-ports { + port { + etm6_out: endpoint { + remote-endpoint = <&ncc1_2_rep_in>; + }; + }; + }; + }; + + etm@13821000 { + compatible = "arm,coresight-etm4x-sysreg"; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + cpu = <&cpu7>; + qcom,skip-power-up; + + out-ports { + port { + etm7_out: endpoint { + remote-endpoint = <&ncc1_3_rep_in>; + }; + }; + }; + }; + + funnel@13901000 { + compatible = "arm,coresight-cpu-funnel"; + reg = <0x0 0x13901000 0x0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + power-domains = <&cluster_pd1>; + + in-ports { + #address-cells = <1>; + #size-cells = <0>; + + port@2 { + reg = <2>; + + ncc1_2_funnel_in2: endpoint { + remote-endpoint = <&ncc1_1_funnel_out>; + }; + }; + }; + + out-ports { + port { + ncc1_2_funnel_out: endpoint { + remote-endpoint = <&ncc1_etf_in>; + }; + }; + }; + }; + + tmc@13909000 { + compatible = "arm,coresight-cpu-tmc"; + reg = <0x0 0x13909000 0x0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + power-domains = <&cluster_pd1>; + + in-ports { + port { + ncc1_etf_in: endpoint { + remote-endpoint = <&ncc1_2_funnel_out>; + }; + }; + }; + + out-ports { + port { + ncc1_etf_out: endpoint { + remote-endpoint = <&apss_funnel_in1>; + }; + }; + }; + }; + + replicator@13990000 { + compatible = "arm,coresight-cpu-replicator"; + reg = <0x0 0x13990000 0x0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + power-domains = <&cluster_pd1>; + + in-ports { + port { + ncc1_0_rep_in: endpoint { + remote-endpoint = <&etm4_out>; + }; + }; + }; + + out-ports { + port { + ncc1_0_rep_out: endpoint { + remote-endpoint = <&ncc1_1_funnel_in0>; + }; + }; + }; + }; + + replicator@139a0000 { + compatible = "arm,coresight-cpu-replicator"; + reg = <0x0 0x139a0000 0x0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + power-domains = <&cluster_pd1>; + + in-ports { + port { + ncc1_1_rep_in: endpoint { + remote-endpoint = <&etm5_out>; + }; + }; + }; + + out-ports { + port { + ncc1_1_rep_out: endpoint { + remote-endpoint = <&ncc1_1_funnel_in1>; + }; + }; + }; + }; + + replicator@139b0000 { + compatible = "arm,coresight-cpu-replicator"; + reg = <0x0 0x139b0000 0x0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + power-domains = <&cluster_pd1>; + + in-ports { + port { + ncc1_2_rep_in: endpoint { + remote-endpoint = <&etm6_out>; + }; + }; + }; + + out-ports { + port { + ncc1_2_rep_out: endpoint { + remote-endpoint = <&ncc1_1_funnel_in2>; + }; + }; + }; + }; + + replicator@139c0000 { + compatible = "arm,coresight-cpu-replicator"; + reg = <0x0 0x139c0000 0x0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + power-domains = <&cluster_pd1>; + + in-ports { + port { + ncc1_3_rep_in: endpoint { + remote-endpoint = <&etm7_out>; + }; + }; + }; + + out-ports { + port { + ncc1_3_rep_out: endpoint { + remote-endpoint = <&ncc1_1_funnel_in3>; + }; + }; + }; + }; + + funnel@139d0000 { + compatible = "arm,coresight-cpu-funnel"; + reg = <0x0 0x139d0000 0x0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + power-domains = <&cluster_pd1>; + + in-ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + ncc1_1_funnel_in0: endpoint { + remote-endpoint = <&ncc1_0_rep_out>; + }; + }; + + port@1 { + reg = <1>; + + ncc1_1_funnel_in1: endpoint { + remote-endpoint = <&ncc1_1_rep_out>; + }; + }; + + port@2 { + reg = <2>; + + ncc1_1_funnel_in2: endpoint { + remote-endpoint = <&ncc1_2_rep_out>; + }; + }; + + port@3 { + reg = <3>; + + ncc1_1_funnel_in3: endpoint { + remote-endpoint = <&ncc1_3_rep_out>; + }; + }; + }; + + out-ports { + port { + ncc1_1_funnel_out: endpoint { + remote-endpoint = <&ncc1_2_funnel_in2>; + }; + }; + }; + }; + + etm8: etm@13a21000 { + compatible = "arm,coresight-etm4x-sysreg"; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + cpu = <&cpu8>; + qcom,skip-power-up; + + out-ports { + port { + etm8_out: endpoint { + remote-endpoint = <&ncc2_0_rep_in>; + }; + }; + }; + }; + + etm9: etm@13b21000 { + compatible = "arm,coresight-etm4x-sysreg"; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + cpu = <&cpu9>; + qcom,skip-power-up; + + out-ports { + port { + etm9_out: endpoint { + remote-endpoint = <&ncc2_1_rep_in>; + }; + }; + }; + }; + + etm10: etm@13c21000 { + compatible = "arm,coresight-etm4x-sysreg"; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + cpu = <&cpu10>; + qcom,skip-power-up; + + out-ports { + port { + etm10_out: endpoint { + remote-endpoint = <&ncc2_2_rep_in>; + }; + }; + }; + }; + + etm11: etm@13d21000 { + compatible = "arm,coresight-etm4x-sysreg"; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + cpu = <&cpu11>; + qcom,skip-power-up; + + out-ports { + port { + etm11_out: endpoint { + remote-endpoint = <&ncc2_3_rep_in>; + }; + }; + }; + }; + + cluster2_funnel_l2: funnel@13e01000 { + compatible = "arm,coresight-cpu-funnel"; + reg = <0x0 0x13e01000 0x0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + power-domains = <&cluster_pd2>; + + in-ports { + #address-cells = <1>; + #size-cells = <0>; + + port@2 { + reg = <2>; + + ncc2_2_funnel_in2: endpoint { + remote-endpoint = <&ncc2_1_funnel_out>; + }; + }; + }; + + out-ports { + port { + ncc2_2_funnel_out: endpoint { + remote-endpoint = <&ncc2_etf_in>; + }; + }; + }; + }; + + cluster2_etf: tmc@13e09000 { + compatible = "arm,coresight-cpu-tmc"; + reg = <0x0 0x13e09000 0x0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + power-domains = <&cluster_pd2>; + + in-ports { + port { + ncc2_etf_in: endpoint { + remote-endpoint = <&ncc2_2_funnel_out>; + }; + }; + }; + + out-ports { + port { + ncc2_etf_out: endpoint { + remote-endpoint = <&apss_funnel_in2>; + }; + }; + }; + }; + + cluster2_rep_2_0: replicator@13e90000 { + compatible = "arm,coresight-cpu-replicator"; + reg = <0x0 0x13e90000 0x0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + power-domains = <&cluster_pd2>; + + in-ports { + port { + ncc2_0_rep_in: endpoint { + remote-endpoint = <&etm8_out>; + }; + }; + }; + + out-ports { + port { + ncc2_0_rep_out: endpoint { + remote-endpoint = <&ncc2_1_funnel_in0>; + }; + }; + }; + }; + + cluster2_rep_2_1: replicator@13ea0000 { + compatible = "arm,coresight-cpu-replicator"; + reg = <0x0 0x13ea0000 0x0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + power-domains = <&cluster_pd2>; + + in-ports { + port { + ncc2_1_rep_in: endpoint { + remote-endpoint = <&etm9_out>; + }; + }; + }; + + out-ports { + port { + ncc2_1_rep_out: endpoint { + remote-endpoint = <&ncc2_1_funnel_in1>; + }; + }; + }; + }; + + cluster2_rep_2_2: replicator@13eb0000 { + compatible = "arm,coresight-cpu-replicator"; + reg = <0x0 0x13eb0000 0x0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + power-domains = <&cluster_pd2>; + + in-ports { + port { + ncc2_2_rep_in: endpoint { + remote-endpoint = <&etm10_out>; + }; + }; + }; + + out-ports { + port { + ncc2_2_rep_out: endpoint { + remote-endpoint = <&ncc2_1_funnel_in2>; + }; + }; + }; + }; + + cluster2_rep_2_3: replicator@13ec0000 { + compatible = "arm,coresight-cpu-replicator"; + reg = <0x0 0x13ec0000 0x0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + power-domains = <&cluster_pd2>; + + in-ports { + port { + ncc2_3_rep_in: endpoint { + remote-endpoint = <&etm11_out>; + }; + }; + }; + + out-ports { + port { + ncc2_3_rep_out: endpoint { + remote-endpoint = <&ncc2_1_funnel_in3>; + }; + }; + }; + }; + + cluster2_funnel_l1: funnel@13ed0000 { + compatible = "arm,coresight-cpu-funnel"; + reg = <0x0 0x13ed0000 0x0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + power-domains = <&cluster_pd2>; + + in-ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + ncc2_1_funnel_in0: endpoint { + remote-endpoint = <&ncc2_0_rep_out>; + }; + }; + + port@1 { + reg = <1>; + + ncc2_1_funnel_in1: endpoint { + remote-endpoint = <&ncc2_1_rep_out>; + }; + }; + + port@2 { + reg = <2>; + + ncc2_1_funnel_in2: endpoint { + remote-endpoint = <&ncc2_2_rep_out>; + }; + }; + + port@3 { + reg = <3>; + + ncc2_1_funnel_in3: endpoint { + remote-endpoint = <&ncc2_3_rep_out>; + }; + }; + }; + + out-ports { + port { + ncc2_1_funnel_out: endpoint { + remote-endpoint = <&ncc2_2_funnel_in2>; + }; + }; + }; + }; + apps_smmu: iommu@15000000 { compatible = "qcom,x1e80100-smmu-500", "qcom,smmu-500", "arm,mmu-500"; reg = <0 0x15000000 0 0x100000>; diff --git a/arch/arm64/boot/dts/qcom/x1p42100.dtsi b/arch/arm64/boot/dts/qcom/x1p42100.dtsi index 10d26958d3c66..686b3a6b82cf5 100644 --- a/arch/arm64/boot/dts/qcom/x1p42100.dtsi +++ b/arch/arm64/boot/dts/qcom/x1p42100.dtsi @@ -21,6 +21,18 @@ /delete-node/ &gpu_speed_bin; /delete-node/ &pcie3_phy; /delete-node/ &thermal_zones; +/delete-node/ &etm8; +/delete-node/ &etm9; +/delete-node/ &etm10; +/delete-node/ &etm11; +/delete-node/ &cluster2_funnel_l1; +/delete-node/ &cluster2_funnel_l2; +/delete-node/ &cluster2_etf; +/delete-node/ &cluster2_rep_2_0; +/delete-node/ &cluster2_rep_2_1; +/delete-node/ &cluster2_rep_2_2; +/delete-node/ &cluster2_rep_2_3; +/delete-node/ &apss_funnel_in2; &gcc { compatible = "qcom,x1p42100-gcc", "qcom,x1e80100-gcc"; From 53398510c562c5a1df4d8ecb19d154e9f4d13dca Mon Sep 17 00:00:00 2001 From: Yongxing Mou Date: Thu, 16 Oct 2025 18:28:57 +0800 Subject: [PATCH 0091/2333] FROMLIST: arm64: dts: qcom: Add backlight support for eDP panel Previously, the eDP panel backlight was enabled via UEFI. Added backlight control node in kernel DTS due to some meta may not enable the backlight. Aligned with other x1e80100-based platforms: the PWM signal is controlled by PMK8550, and the backlight enable signal is handled by PMC8380. Link: https://lore.kernel.org/all/20251028-hamoa_dvt_backlight-v1-1-97ecb8d0ad01@oss.qualcomm.com/ Signed-off-by: Yongxing Mou --- arch/arm64/boot/dts/qcom/hamoa-iot-evk.dts | 55 ++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/hamoa-iot-evk.dts b/arch/arm64/boot/dts/qcom/hamoa-iot-evk.dts index df8d6e5c1f45e..7556ec640f1a1 100644 --- a/arch/arm64/boot/dts/qcom/hamoa-iot-evk.dts +++ b/arch/arm64/boot/dts/qcom/hamoa-iot-evk.dts @@ -17,6 +17,16 @@ serial1 = &uart14; }; + backlight: backlight { + compatible = "pwm-backlight"; + pwms = <&pmk8550_pwm 0 5000000>; + enable-gpios = <&pmc8380_3_gpios 4 GPIO_ACTIVE_HIGH>; + power-supply = <&vreg_edp_bl>; + + pinctrl-0 = <&edp_bl_en>, <&edp_bl_pwm>; + pinctrl-names = "default"; + }; + wcd938x: audio-codec { compatible = "qcom,wcd9385-codec"; @@ -183,6 +193,22 @@ regulator-boot-on; }; + vreg_edp_bl: regulator-edp-bl { + compatible = "regulator-fixed"; + + regulator-name = "VBL9"; + regulator-min-microvolt = <3600000>; + regulator-max-microvolt = <3600000>; + + gpio = <&pmc8380_3_gpios 10 GPIO_ACTIVE_HIGH>; + enable-active-high; + + pinctrl-names = "default"; + pinctrl-0 = <&edp_bl_reg_en>; + + regulator-boot-on; + }; + vreg_nvme: regulator-nvme { compatible = "regulator-fixed"; @@ -807,6 +833,8 @@ aux-bus { panel { compatible = "edp-panel"; + + backlight = <&backlight>; power-supply = <&vreg_edp_3p3>; port { @@ -867,6 +895,22 @@ }; }; +&pmc8380_3_gpios { + edp_bl_en: edp-bl-en-state { + pins = "gpio4"; + function = "normal"; + power-source = <1>; + input-disable; + output-enable; + }; + + edp_bl_reg_en: edp-bl-reg-en-state { + pins = "gpio10"; + function = "normal"; + }; + +}; + &pmc8380_5_gpios { usb0_pwr_1p15_reg_en: usb0-pwr-1p15-reg-en-state { pins = "gpio8"; @@ -878,6 +922,17 @@ }; }; +&pmk8550_gpios { + edp_bl_pwm: edp-bl-pwm-state { + pins = "gpio5"; + function = "func3"; + }; +}; + +&pmk8550_pwm { + status = "okay"; +}; + &smb2360_0 { status = "okay"; }; From bbfed333bd67dd8df953f89c742ceec6946c01d0 Mon Sep 17 00:00:00 2001 From: Raviteja Laggyshetty Date: Mon, 3 Nov 2025 08:51:18 +0000 Subject: [PATCH 0092/2333] FROMLIST: dt-bindings: interconnect: document the RPMh Network-On-Chip interconnect in Kaanapali SoC Document the RPMh Network-On-Chip Interconnect of the Kaanapali platform. Change-Id: I5da9581cdbde62328daa241feff6dcac031853c9 Co-developed-by: Odelu Kukatla Signed-off-by: Odelu Kukatla Reviewed-by: Krzysztof Kozlowski Signed-off-by: Raviteja Laggyshetty --- .../interconnect/qcom,kaanapali-rpmh.yaml | 124 +++++++++++++++ .../interconnect/qcom,kaanapali-rpmh.h | 149 ++++++++++++++++++ 2 files changed, 273 insertions(+) create mode 100644 Documentation/devicetree/bindings/interconnect/qcom,kaanapali-rpmh.yaml create mode 100644 include/dt-bindings/interconnect/qcom,kaanapali-rpmh.h diff --git a/Documentation/devicetree/bindings/interconnect/qcom,kaanapali-rpmh.yaml b/Documentation/devicetree/bindings/interconnect/qcom,kaanapali-rpmh.yaml new file mode 100644 index 0000000000000..2808acc0191f3 --- /dev/null +++ b/Documentation/devicetree/bindings/interconnect/qcom,kaanapali-rpmh.yaml @@ -0,0 +1,124 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/interconnect/qcom,kaanapali-rpmh.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm RPMh Network-On-Chip Interconnect on Kaanapali SoC + +maintainers: + - Raviteja Laggyshetty + +description: | + RPMh interconnect providers support system bandwidth requirements through + RPMh hardware accelerators known as Bus Clock Manager (BCM). The provider is + able to communicate with the BCM through the Resource State Coordinator (RSC) + associated with each execution environment. Provider nodes must point to at + least one RPMh device child node pertaining to their RSC and each provider + can map to multiple RPMh resources. + + See also: include/dt-bindings/interconnect/qcom,kaanapali-rpmh.h + +properties: + compatible: + enum: + - qcom,kaanapali-aggre-noc + - qcom,kaanapali-clk-virt + - qcom,kaanapali-cnoc-main + - qcom,kaanapali-cnoc-cfg + - qcom,kaanapali-gem-noc + - qcom,kaanapali-lpass-ag-noc + - qcom,kaanapali-lpass-lpiaon-noc + - qcom,kaanapali-lpass-lpicx-noc + - qcom,kaanapali-mc-virt + - qcom,kaanapali-mmss-noc + - qcom,kaanapali-nsp-noc + - qcom,kaanapali-pcie-anoc + - qcom,kaanapali-system-noc + + reg: + maxItems: 1 + + clocks: + minItems: 2 + maxItems: 3 + +required: + - compatible + +allOf: + - $ref: qcom,rpmh-common.yaml# + - if: + properties: + compatible: + contains: + enum: + - qcom,kaanapali-clk-virt + - qcom,kaanapali-mc-virt + then: + properties: + reg: false + else: + required: + - reg + + - if: + properties: + compatible: + contains: + enum: + - qcom,kaanapali-pcie-anoc + then: + properties: + clocks: + items: + - description: aggre-NOC PCIe AXI clock + - description: cfg-NOC PCIe a-NOC AHB clock + + - if: + properties: + compatible: + contains: + enum: + - qcom,kaanapali-aggre-noc + then: + properties: + clocks: + items: + - description: aggre UFS PHY AXI clock + - description: aggre USB3 PRIM AXI clock + - description: RPMH CC IPA clock + + - if: + properties: + compatible: + contains: + enum: + - qcom,kaanapali-aggre-noc + - qcom,kaanapali-pcie-anoc + then: + required: + - clocks + else: + properties: + clocks: false + +unevaluatedProperties: false + +examples: + - | + clk_virt: interconnect-0 { + compatible = "qcom,kaanapali-clk-virt"; + #interconnect-cells = <2>; + qcom,bcm-voters = <&apps_bcm_voter>; + }; + + aggre_noc: interconnect@16e0000 { + compatible = "qcom,kaanapali-aggre-noc"; + reg = <0x016e0000 0x42400>; + #interconnect-cells = <2>; + clocks = <&gcc_aggre_ufs_phy_axi_clk>, + <&gcc_aggre_usb3_prim_axi_clk>, + <&rpmhcc_ipa_clk>; + qcom,bcm-voters = <&apps_bcm_voter>; + }; diff --git a/include/dt-bindings/interconnect/qcom,kaanapali-rpmh.h b/include/dt-bindings/interconnect/qcom,kaanapali-rpmh.h new file mode 100644 index 0000000000000..dde3f9abd6776 --- /dev/null +++ b/include/dt-bindings/interconnect/qcom,kaanapali-rpmh.h @@ -0,0 +1,149 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#ifndef __DT_BINDINGS_INTERCONNECT_QCOM_KAANAPALI_H +#define __DT_BINDINGS_INTERCONNECT_QCOM_KAANAPALI_H + +#define MASTER_QSPI_0 0 +#define MASTER_CRYPTO 1 +#define MASTER_QUP_1 2 +#define MASTER_SDCC_4 3 +#define MASTER_UFS_MEM 4 +#define MASTER_USB3 5 +#define MASTER_QUP_2 6 +#define MASTER_QUP_3 7 +#define MASTER_QUP_4 8 +#define MASTER_IPA 9 +#define MASTER_SOCCP_PROC 10 +#define MASTER_SP 11 +#define MASTER_QDSS_ETR 12 +#define MASTER_QDSS_ETR_1 13 +#define MASTER_SDCC_2 14 +#define SLAVE_A1NOC_SNOC 15 +#define SLAVE_A2NOC_SNOC 16 + +#define MASTER_QUP_CORE_0 0 +#define MASTER_QUP_CORE_1 1 +#define MASTER_QUP_CORE_2 2 +#define MASTER_QUP_CORE_3 3 +#define MASTER_QUP_CORE_4 4 +#define SLAVE_QUP_CORE_0 5 +#define SLAVE_QUP_CORE_1 6 +#define SLAVE_QUP_CORE_2 7 +#define SLAVE_QUP_CORE_3 8 +#define SLAVE_QUP_CORE_4 9 + +#define MASTER_CNOC_CFG 0 +#define SLAVE_AHB2PHY_SOUTH 1 +#define SLAVE_AHB2PHY_NORTH 2 +#define SLAVE_CAMERA_CFG 3 +#define SLAVE_CLK_CTL 4 +#define SLAVE_CRYPTO_0_CFG 5 +#define SLAVE_DISPLAY_CFG 6 +#define SLAVE_EVA_CFG 7 +#define SLAVE_GFX3D_CFG 8 +#define SLAVE_I2C 9 +#define SLAVE_I3C_IBI0_CFG 10 +#define SLAVE_I3C_IBI1_CFG 11 +#define SLAVE_IMEM_CFG 12 +#define SLAVE_IPC_ROUTER_CFG 13 +#define SLAVE_CNOC_MSS 14 +#define SLAVE_PCIE_CFG 15 +#define SLAVE_PRNG 16 +#define SLAVE_QDSS_CFG 17 +#define SLAVE_QSPI_0 18 +#define SLAVE_QUP_1 19 +#define SLAVE_QUP_2 20 +#define SLAVE_QUP_3 21 +#define SLAVE_QUP_4 22 +#define SLAVE_SDCC_2 23 +#define SLAVE_SDCC_4 24 +#define SLAVE_SPSS_CFG 25 +#define SLAVE_TCSR 26 +#define SLAVE_TLMM 27 +#define SLAVE_UFS_MEM_CFG 28 +#define SLAVE_USB3 29 +#define SLAVE_VENUS_CFG 30 +#define SLAVE_VSENSE_CTRL_CFG 31 +#define SLAVE_CNOC_MNOC_CFG 32 +#define SLAVE_PCIE_ANOC_CFG 33 +#define SLAVE_QDSS_STM 34 +#define SLAVE_TCU 35 + +#define MASTER_GEM_NOC_CNOC 0 +#define MASTER_GEM_NOC_PCIE_SNOC 1 +#define SLAVE_AOSS 2 +#define SLAVE_IPA_CFG 3 +#define SLAVE_IPC_ROUTER_FENCE 4 +#define SLAVE_SOCCP 5 +#define SLAVE_TME_CFG 6 +#define SLAVE_APPSS 7 +#define SLAVE_CNOC_CFG 8 +#define SLAVE_DDRSS_CFG 9 +#define SLAVE_BOOT_IMEM 10 +#define SLAVE_IMEM 11 +#define SLAVE_PCIE_0 12 + +#define MASTER_GPU_TCU 0 +#define MASTER_SYS_TCU 1 +#define MASTER_APPSS_PROC 2 +#define MASTER_GFX3D 3 +#define MASTER_LPASS_GEM_NOC 4 +#define MASTER_MSS_PROC 5 +#define MASTER_MNOC_HF_MEM_NOC 6 +#define MASTER_MNOC_SF_MEM_NOC 7 +#define MASTER_COMPUTE_NOC 8 +#define MASTER_ANOC_PCIE_GEM_NOC 9 +#define MASTER_QPACE 10 +#define MASTER_SNOC_SF_MEM_NOC 11 +#define MASTER_WLAN_Q6 12 +#define MASTER_GIC 13 +#define SLAVE_GEM_NOC_CNOC 14 +#define SLAVE_LLCC 15 +#define SLAVE_MEM_NOC_PCIE_SNOC 16 + +#define MASTER_LPIAON_NOC 0 +#define SLAVE_LPASS_GEM_NOC 1 + +#define MASTER_LPASS_LPINOC 0 +#define SLAVE_LPIAON_NOC_LPASS_AG_NOC 1 + +#define MASTER_LPASS_PROC 0 +#define SLAVE_LPICX_NOC_LPIAON_NOC 1 + +#define MASTER_LLCC 0 +#define SLAVE_EBI1 1 + +#define MASTER_CAMNOC_HF 0 +#define MASTER_CAMNOC_NRT_ICP_SF 1 +#define MASTER_CAMNOC_RT_CDM_SF 2 +#define MASTER_CAMNOC_SF 3 +#define MASTER_MDP 4 +#define MASTER_MDSS_DCP 5 +#define MASTER_CDSP_HCP 6 +#define MASTER_VIDEO_CV_PROC 7 +#define MASTER_VIDEO_EVA 8 +#define MASTER_VIDEO_MVP 9 +#define MASTER_VIDEO_V_PROC 10 +#define MASTER_CNOC_MNOC_CFG 11 +#define SLAVE_MNOC_HF_MEM_NOC 12 +#define SLAVE_MNOC_SF_MEM_NOC 13 +#define SLAVE_SERVICE_MNOC 14 + +#define MASTER_CDSP_PROC 0 +#define SLAVE_CDSP_MEM_NOC 1 + +#define MASTER_PCIE_ANOC_CFG 0 +#define MASTER_PCIE_0 1 +#define SLAVE_ANOC_PCIE_GEM_NOC 2 +#define SLAVE_SERVICE_PCIE_ANOC 3 + +#define MASTER_A1NOC_SNOC 0 +#define MASTER_A2NOC_SNOC 1 +#define MASTER_APSS_NOC 2 +#define MASTER_CNOC_SNOC 3 +#define SLAVE_SNOC_GEM_NOC_SF 4 + +#endif From 938409e3faa500839cfe2db3a2e3becfd9fb7fc6 Mon Sep 17 00:00:00 2001 From: Raviteja Laggyshetty Date: Mon, 3 Nov 2025 08:51:19 +0000 Subject: [PATCH 0093/2333] FROMLIST: interconnect: qcom: add Kaanapali interconnect provider driver Add driver for the Qualcomm interconnect buses found in Kaanapali based platforms. The topology consists of several NoCs that are controlled by a remote processor that collects the aggregated bandwidth for each master-slave pairs. Change-Id: I6995fd4a2ec678a03bacd0206a2631733ed2e1c4 Co-developed-by: Odelu Kukatla Signed-off-by: Odelu Kukatla Reviewed-by: Dmitry Baryshkov Signed-off-by: Raviteja Laggyshetty --- drivers/interconnect/qcom/Kconfig | 9 + drivers/interconnect/qcom/Makefile | 2 + drivers/interconnect/qcom/kaanapali.c | 1868 +++++++++++++++++++++++++ 3 files changed, 1879 insertions(+) create mode 100644 drivers/interconnect/qcom/kaanapali.c diff --git a/drivers/interconnect/qcom/Kconfig b/drivers/interconnect/qcom/Kconfig index 5b4bb9f1382b2..bb1cb8a640c17 100644 --- a/drivers/interconnect/qcom/Kconfig +++ b/drivers/interconnect/qcom/Kconfig @@ -17,6 +17,15 @@ config INTERCONNECT_QCOM_GLYMUR This is a driver for the Qualcomm Network-on-Chip on glymur-based platforms. +config INTERCONNECT_QCOM_KAANAPALI + tristate "Qualcomm KAANAPALI interconnect driver" + depends on INTERCONNECT_QCOM_RPMH_POSSIBLE + select INTERCONNECT_QCOM_RPMH + select INTERCONNECT_QCOM_BCM_VOTER + help + This is a driver for the Qualcomm Network-on-Chip on kaanapali-based + platforms. + config INTERCONNECT_QCOM_MSM8909 tristate "Qualcomm MSM8909 interconnect driver" depends on INTERCONNECT_QCOM diff --git a/drivers/interconnect/qcom/Makefile b/drivers/interconnect/qcom/Makefile index cf8cba73ee3e6..6eedff043b412 100644 --- a/drivers/interconnect/qcom/Makefile +++ b/drivers/interconnect/qcom/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_INTERCONNECT_QCOM) += interconnect_qcom.o interconnect_qcom-y := icc-common.o icc-bcm-voter-objs := bcm-voter.o qnoc-glymur-objs := glymur.o +qnoc-kaanapali-objs := kaanapali.o qnoc-milos-objs := milos.o qnoc-msm8909-objs := msm8909.o qnoc-msm8916-objs := msm8916.o @@ -48,6 +49,7 @@ icc-smd-rpm-objs := smd-rpm.o icc-rpm.o icc-rpm-clocks.o obj-$(CONFIG_INTERCONNECT_QCOM_BCM_VOTER) += icc-bcm-voter.o obj-$(CONFIG_INTERCONNECT_QCOM_GLYMUR) += qnoc-glymur.o +obj-$(CONFIG_INTERCONNECT_QCOM_KAANAPALI) += qnoc-kaanapali.o obj-$(CONFIG_INTERCONNECT_QCOM_MILOS) += qnoc-milos.o obj-$(CONFIG_INTERCONNECT_QCOM_MSM8909) += qnoc-msm8909.o obj-$(CONFIG_INTERCONNECT_QCOM_MSM8916) += qnoc-msm8916.o diff --git a/drivers/interconnect/qcom/kaanapali.c b/drivers/interconnect/qcom/kaanapali.c new file mode 100644 index 0000000000000..c6b4902e057f5 --- /dev/null +++ b/drivers/interconnect/qcom/kaanapali.c @@ -0,0 +1,1868 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * + */ + +#include +#include +#include +#include +#include +#include + +#include "bcm-voter.h" +#include "icc-rpmh.h" + +static struct qcom_icc_node qup0_core_slave = { + .name = "qup0_core_slave", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qup1_core_slave = { + .name = "qup1_core_slave", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qup2_core_slave = { + .name = "qup2_core_slave", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qup3_core_slave = { + .name = "qup3_core_slave", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qup4_core_slave = { + .name = "qup4_core_slave", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qhs_ahb2phy0 = { + .name = "qhs_ahb2phy0", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qhs_ahb2phy1 = { + .name = "qhs_ahb2phy1", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qhs_camera_cfg = { + .name = "qhs_camera_cfg", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qhs_clk_ctl = { + .name = "qhs_clk_ctl", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qhs_crypto0_cfg = { + .name = "qhs_crypto0_cfg", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qhs_display_cfg = { + .name = "qhs_display_cfg", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qhs_eva_cfg = { + .name = "qhs_eva_cfg", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qhs_gpuss_cfg = { + .name = "qhs_gpuss_cfg", + .channels = 1, + .buswidth = 8, +}; + +static struct qcom_icc_node qhs_i2c = { + .name = "qhs_i2c", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qhs_i3c_ibi0_cfg = { + .name = "qhs_i3c_ibi0_cfg", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qhs_i3c_ibi1_cfg = { + .name = "qhs_i3c_ibi1_cfg", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qhs_imem_cfg = { + .name = "qhs_imem_cfg", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qhs_ipc_router = { + .name = "qhs_ipc_router", + .channels = 4, + .buswidth = 4, +}; + +static struct qcom_icc_node qhs_mss_cfg = { + .name = "qhs_mss_cfg", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qhs_pcie_cfg = { + .name = "qhs_pcie_cfg", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qhs_prng = { + .name = "qhs_prng", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qhs_qdss_cfg = { + .name = "qhs_qdss_cfg", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qhs_qspi = { + .name = "qhs_qspi", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qhs_qup1 = { + .name = "qhs_qup1", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qhs_qup2 = { + .name = "qhs_qup2", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qhs_qup3 = { + .name = "qhs_qup3", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qhs_qup4 = { + .name = "qhs_qup4", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qhs_sdc2 = { + .name = "qhs_sdc2", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qhs_sdc4 = { + .name = "qhs_sdc4", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qhs_spss_cfg = { + .name = "qhs_spss_cfg", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qhs_tcsr = { + .name = "qhs_tcsr", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qhs_tlmm = { + .name = "qhs_tlmm", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qhs_ufs_mem_cfg = { + .name = "qhs_ufs_mem_cfg", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qhs_usb3 = { + .name = "qhs_usb3", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qhs_venus_cfg = { + .name = "qhs_venus_cfg", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qhs_vsense_ctrl_cfg = { + .name = "qhs_vsense_ctrl_cfg", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node xs_qdss_stm = { + .name = "xs_qdss_stm", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node xs_sys_tcu_cfg = { + .name = "xs_sys_tcu_cfg", + .channels = 1, + .buswidth = 8, +}; + +static struct qcom_icc_node qhs_aoss = { + .name = "qhs_aoss", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qhs_ipa = { + .name = "qhs_ipa", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qhs_ipc_router_fence = { + .name = "qhs_ipc_router_fence", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qhs_soccp = { + .name = "qhs_soccp", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qhs_tme_cfg = { + .name = "qhs_tme_cfg", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qns_apss = { + .name = "qns_apss", + .channels = 1, + .buswidth = 8, +}; + +static struct qcom_icc_node qss_ddrss_cfg = { + .name = "qss_ddrss_cfg", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qxs_boot_imem = { + .name = "qxs_boot_imem", + .channels = 1, + .buswidth = 16, +}; + +static struct qcom_icc_node qxs_imem = { + .name = "qxs_imem", + .channels = 1, + .buswidth = 8, +}; + +static struct qcom_icc_node xs_pcie = { + .name = "xs_pcie", + .channels = 1, + .buswidth = 16, +}; + +static struct qcom_icc_node ebi = { + .name = "ebi", + .channels = 4, + .buswidth = 4, +}; + +static struct qcom_icc_node srvc_mnoc = { + .name = "srvc_mnoc", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node srvc_pcie_aggre_noc = { + .name = "srvc_pcie_aggre_noc", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qup0_core_master = { + .name = "qup0_core_master", + .channels = 1, + .buswidth = 4, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qup0_core_slave }, +}; + +static struct qcom_icc_node qup1_core_master = { + .name = "qup1_core_master", + .channels = 1, + .buswidth = 4, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qup1_core_slave }, +}; + +static struct qcom_icc_node qup2_core_master = { + .name = "qup2_core_master", + .channels = 1, + .buswidth = 4, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qup2_core_slave }, +}; + +static struct qcom_icc_node qup3_core_master = { + .name = "qup3_core_master", + .channels = 1, + .buswidth = 4, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qup3_core_slave }, +}; + +static struct qcom_icc_node qup4_core_master = { + .name = "qup4_core_master", + .channels = 1, + .buswidth = 4, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qup4_core_slave }, +}; + +static struct qcom_icc_node qnm_gemnoc_pcie = { + .name = "qnm_gemnoc_pcie", + .channels = 1, + .buswidth = 8, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &xs_pcie }, +}; + +static struct qcom_icc_node llcc_mc = { + .name = "llcc_mc", + .channels = 4, + .buswidth = 4, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &ebi }, +}; + +static struct qcom_icc_node qsm_mnoc_cfg = { + .name = "qsm_mnoc_cfg", + .channels = 1, + .buswidth = 4, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &srvc_mnoc }, +}; + +static struct qcom_icc_node qsm_pcie_anoc_cfg = { + .name = "qsm_pcie_anoc_cfg", + .channels = 1, + .buswidth = 4, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &srvc_pcie_aggre_noc }, +}; + +static struct qcom_icc_node qss_mnoc_cfg = { + .name = "qss_mnoc_cfg", + .channels = 1, + .buswidth = 4, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qsm_mnoc_cfg }, +}; + +static struct qcom_icc_node qss_pcie_anoc_cfg = { + .name = "qss_pcie_anoc_cfg", + .channels = 1, + .buswidth = 4, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qsm_pcie_anoc_cfg }, +}; + +static struct qcom_icc_node qns_llcc = { + .name = "qns_llcc", + .channels = 4, + .buswidth = 16, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &llcc_mc }, +}; + +static struct qcom_icc_node qns_pcie = { + .name = "qns_pcie", + .channels = 1, + .buswidth = 8, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qnm_gemnoc_pcie }, +}; + +static struct qcom_icc_node qsm_cfg = { + .name = "qsm_cfg", + .channels = 1, + .buswidth = 4, + .num_links = 35, + .link_nodes = (struct qcom_icc_node *[]) { &qhs_ahb2phy0, &qhs_ahb2phy1, + &qhs_camera_cfg, &qhs_clk_ctl, + &qhs_crypto0_cfg, &qhs_display_cfg, + &qhs_eva_cfg, &qhs_gpuss_cfg, + &qhs_i2c, &qhs_i3c_ibi0_cfg, + &qhs_i3c_ibi1_cfg, &qhs_imem_cfg, + &qhs_ipc_router, &qhs_mss_cfg, + &qhs_pcie_cfg, &qhs_prng, + &qhs_qdss_cfg, &qhs_qspi, + &qhs_qup1, &qhs_qup2, + &qhs_qup3, &qhs_qup4, + &qhs_sdc2, &qhs_sdc4, + &qhs_spss_cfg, &qhs_tcsr, + &qhs_tlmm, &qhs_ufs_mem_cfg, + &qhs_usb3, &qhs_venus_cfg, + &qhs_vsense_ctrl_cfg, &qss_mnoc_cfg, + &qss_pcie_anoc_cfg, &xs_qdss_stm, + &xs_sys_tcu_cfg }, +}; + +static struct qcom_icc_node qnm_qpace = { + .name = "qnm_qpace", + .channels = 1, + .buswidth = 32, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0x14e000 }, + .prio = 0, + .urg_fwd = 1, + .prio_fwd_disable = 0, + }, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_llcc }, +}; + +static struct qcom_icc_node xm_gic = { + .name = "xm_gic", + .channels = 1, + .buswidth = 8, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0x145000 }, + .prio = 4, + .urg_fwd = 0, + .prio_fwd_disable = 1, + }, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_llcc }, +}; + +static struct qcom_icc_node qss_cfg = { + .name = "qss_cfg", + .channels = 1, + .buswidth = 4, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qsm_cfg }, +}; + +static struct qcom_icc_node qnm_gemnoc_cnoc = { + .name = "qnm_gemnoc_cnoc", + .channels = 1, + .buswidth = 16, + .num_links = 10, + .link_nodes = (struct qcom_icc_node *[]) { &qhs_aoss, &qhs_ipa, + &qhs_ipc_router_fence, &qhs_soccp, + &qhs_tme_cfg, &qns_apss, + &qss_cfg, &qss_ddrss_cfg, + &qxs_boot_imem, &qxs_imem }, +}; + +static struct qcom_icc_node qns_gem_noc_cnoc = { + .name = "qns_gem_noc_cnoc", + .channels = 1, + .buswidth = 16, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qnm_gemnoc_cnoc }, +}; + +static struct qcom_icc_node alm_gpu_tcu = { + .name = "alm_gpu_tcu", + .channels = 1, + .buswidth = 8, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0x13d000 }, + .prio = 1, + .urg_fwd = 0, + .prio_fwd_disable = 1, + }, + .num_links = 2, + .link_nodes = (struct qcom_icc_node *[]) { &qns_gem_noc_cnoc, &qns_llcc }, +}; + +static struct qcom_icc_node alm_sys_tcu = { + .name = "alm_sys_tcu", + .channels = 1, + .buswidth = 8, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0x13f000 }, + .prio = 6, + .urg_fwd = 0, + .prio_fwd_disable = 1, + }, + .num_links = 2, + .link_nodes = (struct qcom_icc_node *[]) { &qns_gem_noc_cnoc, &qns_llcc }, +}; + +static struct qcom_icc_node chm_apps = { + .name = "chm_apps", + .channels = 4, + .buswidth = 32, + .num_links = 3, + .link_nodes = (struct qcom_icc_node *[]) { &qns_gem_noc_cnoc, &qns_llcc, + &qns_pcie }, +}; + +static struct qcom_icc_node qnm_gpu = { + .name = "qnm_gpu", + .channels = 2, + .buswidth = 32, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 2, + .port_offsets = { 0x31000, 0xb1000 }, + .prio = 0, + .urg_fwd = 1, + .prio_fwd_disable = 1, + }, + .num_links = 3, + .link_nodes = (struct qcom_icc_node *[]) { &qns_gem_noc_cnoc, &qns_llcc, + &qns_pcie }, +}; + +static struct qcom_icc_node qnm_lpass_gemnoc = { + .name = "qnm_lpass_gemnoc", + .channels = 1, + .buswidth = 16, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0x141000 }, + .prio = 0, + .urg_fwd = 1, + .prio_fwd_disable = 0, + }, + .num_links = 3, + .link_nodes = (struct qcom_icc_node *[]) { &qns_gem_noc_cnoc, &qns_llcc, + &qns_pcie }, +}; + +static struct qcom_icc_node qnm_mdsp = { + .name = "qnm_mdsp", + .channels = 1, + .buswidth = 16, + .num_links = 3, + .link_nodes = (struct qcom_icc_node *[]) { &qns_gem_noc_cnoc, &qns_llcc, + &qns_pcie }, +}; + +static struct qcom_icc_node qnm_mnoc_hf = { + .name = "qnm_mnoc_hf", + .channels = 2, + .buswidth = 32, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 2, + .port_offsets = { 0x33000, 0xb3000 }, + .prio = 0, + .urg_fwd = 1, + .prio_fwd_disable = 0, + }, + .num_links = 3, + .link_nodes = (struct qcom_icc_node *[]) { &qns_gem_noc_cnoc, &qns_llcc, + &qns_pcie }, +}; + +static struct qcom_icc_node qnm_mnoc_sf = { + .name = "qnm_mnoc_sf", + .channels = 2, + .buswidth = 32, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 2, + .port_offsets = { 0x35000, 0xb5000 }, + .prio = 0, + .urg_fwd = 1, + .prio_fwd_disable = 0, + }, + .num_links = 3, + .link_nodes = (struct qcom_icc_node *[]) { &qns_gem_noc_cnoc, &qns_llcc, + &qns_pcie }, +}; + +static struct qcom_icc_node qnm_nsp_gemnoc = { + .name = "qnm_nsp_gemnoc", + .channels = 2, + .buswidth = 32, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 2, + .port_offsets = { 0x37000, 0xb7000 }, + .prio = 0, + .urg_fwd = 1, + .prio_fwd_disable = 1, + }, + .num_links = 3, + .link_nodes = (struct qcom_icc_node *[]) { &qns_gem_noc_cnoc, &qns_llcc, + &qns_pcie }, +}; + +static struct qcom_icc_node qnm_pcie = { + .name = "qnm_pcie", + .channels = 1, + .buswidth = 16, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0x143000 }, + .prio = 2, + .urg_fwd = 1, + .prio_fwd_disable = 0, + }, + .num_links = 2, + .link_nodes = (struct qcom_icc_node *[]) { &qns_gem_noc_cnoc, &qns_llcc }, +}; + +static struct qcom_icc_node qnm_snoc_sf = { + .name = "qnm_snoc_sf", + .channels = 1, + .buswidth = 16, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0x147000 }, + .prio = 0, + .urg_fwd = 1, + .prio_fwd_disable = 0, + }, + .num_links = 3, + .link_nodes = (struct qcom_icc_node *[]) { &qns_gem_noc_cnoc, &qns_llcc, + &qns_pcie }, +}; + +static struct qcom_icc_node qnm_wlan_q6 = { + .name = "qnm_wlan_q6", + .channels = 1, + .buswidth = 8, + .num_links = 3, + .link_nodes = (struct qcom_icc_node *[]) { &qns_gem_noc_cnoc, &qns_llcc, + &qns_pcie }, +}; + +static struct qcom_icc_node qns_lpass_ag_noc_gemnoc = { + .name = "qns_lpass_ag_noc_gemnoc", + .channels = 1, + .buswidth = 16, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qnm_lpass_gemnoc }, +}; + +static struct qcom_icc_node qns_mem_noc_hf = { + .name = "qns_mem_noc_hf", + .channels = 2, + .buswidth = 32, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qnm_mnoc_hf }, +}; + +static struct qcom_icc_node qns_mem_noc_sf = { + .name = "qns_mem_noc_sf", + .channels = 2, + .buswidth = 32, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qnm_mnoc_sf }, +}; + +static struct qcom_icc_node qns_nsp_gemnoc = { + .name = "qns_nsp_gemnoc", + .channels = 2, + .buswidth = 32, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qnm_nsp_gemnoc }, +}; + +static struct qcom_icc_node qns_pcie_gemnoc = { + .name = "qns_pcie_gemnoc", + .channels = 1, + .buswidth = 16, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qnm_pcie }, +}; + +static struct qcom_icc_node qns_gemnoc_sf = { + .name = "qns_gemnoc_sf", + .channels = 1, + .buswidth = 16, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qnm_snoc_sf }, +}; + +static struct qcom_icc_node qnm_lpiaon_noc = { + .name = "qnm_lpiaon_noc", + .channels = 1, + .buswidth = 16, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_lpass_ag_noc_gemnoc }, +}; + +static struct qcom_icc_node qnm_camnoc_hf = { + .name = "qnm_camnoc_hf", + .channels = 2, + .buswidth = 32, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 2, + .port_offsets = { 0x2a000, 0x2b000 }, + .prio = 0, + .urg_fwd = 1, + .prio_fwd_disable = 0, + }, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_mem_noc_hf }, +}; + +static struct qcom_icc_node qnm_camnoc_nrt_icp_sf = { + .name = "qnm_camnoc_nrt_icp_sf", + .channels = 1, + .buswidth = 8, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0x2c000 }, + .prio = 4, + .urg_fwd = 1, + .prio_fwd_disable = 1, + }, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_mem_noc_sf }, +}; + +static struct qcom_icc_node qnm_camnoc_rt_cdm_sf = { + .name = "qnm_camnoc_rt_cdm_sf", + .channels = 1, + .buswidth = 8, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0x38000 }, + .prio = 2, + .urg_fwd = 1, + .prio_fwd_disable = 1, + }, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_mem_noc_sf }, +}; + +static struct qcom_icc_node qnm_camnoc_sf = { + .name = "qnm_camnoc_sf", + .channels = 2, + .buswidth = 32, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 2, + .port_offsets = { 0x2d000, 0x2e000 }, + .prio = 0, + .urg_fwd = 1, + .prio_fwd_disable = 0, + }, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_mem_noc_sf }, +}; + +static struct qcom_icc_node qnm_mdp = { + .name = "qnm_mdp", + .channels = 2, + .buswidth = 32, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 2, + .port_offsets = { 0x2f000, 0x30000 }, + .prio = 0, + .urg_fwd = 1, + .prio_fwd_disable = 0, + }, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_mem_noc_hf }, +}; + +static struct qcom_icc_node qnm_mdss_dcp = { + .name = "qnm_mdss_dcp", + .channels = 1, + .buswidth = 8, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0x39000 }, + .prio = 0, + .urg_fwd = 1, + .prio_fwd_disable = 0, + }, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_mem_noc_sf }, +}; + +static struct qcom_icc_node qnm_vapss_hcp = { + .name = "qnm_vapss_hcp", + .channels = 1, + .buswidth = 32, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_mem_noc_sf }, +}; + +static struct qcom_icc_node qnm_video_cv_cpu = { + .name = "qnm_video_cv_cpu", + .channels = 1, + .buswidth = 8, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0x34000 }, + .prio = 4, + .urg_fwd = 1, + .prio_fwd_disable = 1, + }, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_mem_noc_sf }, +}; + +static struct qcom_icc_node qnm_video_eva = { + .name = "qnm_video_eva", + .channels = 2, + .buswidth = 32, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 2, + .port_offsets = { 0x35000, 0x36000 }, + .prio = 0, + .urg_fwd = 1, + .prio_fwd_disable = 0, + }, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_mem_noc_sf }, +}; + +static struct qcom_icc_node qnm_video_mvp = { + .name = "qnm_video_mvp", + .channels = 2, + .buswidth = 32, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 2, + .port_offsets = { 0x32000, 0x33000 }, + .prio = 0, + .urg_fwd = 1, + .prio_fwd_disable = 0, + }, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_mem_noc_sf }, +}; + +static struct qcom_icc_node qnm_video_v_cpu = { + .name = "qnm_video_v_cpu", + .channels = 1, + .buswidth = 8, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0x37000 }, + .prio = 4, + .urg_fwd = 1, + .prio_fwd_disable = 1, + }, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_mem_noc_sf }, +}; + +static struct qcom_icc_node qnm_nsp = { + .name = "qnm_nsp", + .channels = 2, + .buswidth = 32, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_nsp_gemnoc }, +}; + +static struct qcom_icc_node xm_pcie = { + .name = "xm_pcie", + .channels = 1, + .buswidth = 16, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0xb000 }, + .prio = 3, + .urg_fwd = 0, + .prio_fwd_disable = 1, + }, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_pcie_gemnoc }, +}; + +static struct qcom_icc_node qnm_aggre1_noc = { + .name = "qnm_aggre1_noc", + .channels = 1, + .buswidth = 16, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_gemnoc_sf }, +}; + +static struct qcom_icc_node qnm_aggre2_noc = { + .name = "qnm_aggre2_noc", + .channels = 1, + .buswidth = 16, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_gemnoc_sf }, +}; + +static struct qcom_icc_node qnm_apss_noc = { + .name = "qnm_apss_noc", + .channels = 1, + .buswidth = 8, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0x1e000 }, + .prio = 2, + .urg_fwd = 1, + .prio_fwd_disable = 1, + }, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_gemnoc_sf }, +}; + +static struct qcom_icc_node qnm_cnoc_data = { + .name = "qnm_cnoc_data", + .channels = 1, + .buswidth = 8, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0x1f000 }, + .prio = 2, + .urg_fwd = 0, + .prio_fwd_disable = 1, + }, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_gemnoc_sf }, +}; + +static struct qcom_icc_node qns_a1noc_snoc = { + .name = "qns_a1noc_snoc", + .channels = 1, + .buswidth = 16, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qnm_aggre1_noc }, +}; + +static struct qcom_icc_node qns_a2noc_snoc = { + .name = "qns_a2noc_snoc", + .channels = 1, + .buswidth = 16, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qnm_aggre2_noc }, +}; + +static struct qcom_icc_node qns_lpass_aggnoc = { + .name = "qns_lpass_aggnoc", + .channels = 1, + .buswidth = 16, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qnm_lpiaon_noc }, +}; + +static struct qcom_icc_node qhm_qspi = { + .name = "qhm_qspi", + .channels = 1, + .buswidth = 4, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0xc000 }, + .prio = 2, + .urg_fwd = 0, + .prio_fwd_disable = 1, + }, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_a1noc_snoc }, +}; + +static struct qcom_icc_node qxm_crypto = { + .name = "qxm_crypto", + .channels = 1, + .buswidth = 16, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0x36000 }, + .prio = 2, + .urg_fwd = 1, + .prio_fwd_disable = 1, + }, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_a1noc_snoc }, +}; + +static struct qcom_icc_node qxm_qup1 = { + .name = "qxm_qup1", + .channels = 1, + .buswidth = 8, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0x11000 }, + .prio = 2, + .urg_fwd = 1, + .prio_fwd_disable = 1, + }, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_a1noc_snoc }, +}; + +static struct qcom_icc_node xm_sdc4 = { + .name = "xm_sdc4", + .channels = 1, + .buswidth = 8, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0xe000 }, + .prio = 2, + .urg_fwd = 0, + .prio_fwd_disable = 1, + }, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_a1noc_snoc }, +}; + +static struct qcom_icc_node xm_ufs_mem = { + .name = "xm_ufs_mem", + .channels = 1, + .buswidth = 16, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0xf000 }, + .prio = 2, + .urg_fwd = 0, + .prio_fwd_disable = 1, + }, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_a1noc_snoc }, +}; + +static struct qcom_icc_node xm_usb3 = { + .name = "xm_usb3", + .channels = 1, + .buswidth = 8, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0x10000 }, + .prio = 2, + .urg_fwd = 0, + .prio_fwd_disable = 1, + }, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_a1noc_snoc }, +}; + +static struct qcom_icc_node qhm_qup2 = { + .name = "qhm_qup2", + .channels = 1, + .buswidth = 4, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0x35000 }, + .prio = 2, + .urg_fwd = 0, + .prio_fwd_disable = 1, + }, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_a2noc_snoc }, +}; + +static struct qcom_icc_node qhm_qup3 = { + .name = "qhm_qup3", + .channels = 1, + .buswidth = 4, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0x3c000 }, + .prio = 2, + .urg_fwd = 0, + .prio_fwd_disable = 1, + }, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_a2noc_snoc }, +}; + +static struct qcom_icc_node qhm_qup4 = { + .name = "qhm_qup4", + .channels = 1, + .buswidth = 4, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0x3d000 }, + .prio = 2, + .urg_fwd = 0, + .prio_fwd_disable = 1, + }, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_a2noc_snoc }, +}; + +static struct qcom_icc_node qxm_ipa = { + .name = "qxm_ipa", + .channels = 1, + .buswidth = 8, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0x37000 }, + .prio = 2, + .urg_fwd = 1, + .prio_fwd_disable = 1, + }, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_a2noc_snoc }, +}; + +static struct qcom_icc_node qxm_soccp = { + .name = "qxm_soccp", + .channels = 1, + .buswidth = 8, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0x3b000 }, + .prio = 2, + .urg_fwd = 1, + .prio_fwd_disable = 1, + }, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_a2noc_snoc }, +}; + +static struct qcom_icc_node qxm_sp = { + .name = "qxm_sp", + .channels = 1, + .buswidth = 8, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_a2noc_snoc }, +}; + +static struct qcom_icc_node xm_qdss_etr_0 = { + .name = "xm_qdss_etr_0", + .channels = 1, + .buswidth = 8, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0x38000 }, + .prio = 2, + .urg_fwd = 0, + .prio_fwd_disable = 1, + }, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_a2noc_snoc }, +}; + +static struct qcom_icc_node xm_qdss_etr_1 = { + .name = "xm_qdss_etr_1", + .channels = 1, + .buswidth = 8, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0x39000 }, + .prio = 2, + .urg_fwd = 0, + .prio_fwd_disable = 1, + }, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_a2noc_snoc }, +}; + +static struct qcom_icc_node xm_sdc2 = { + .name = "xm_sdc2", + .channels = 1, + .buswidth = 8, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0x3a000 }, + .prio = 2, + .urg_fwd = 0, + .prio_fwd_disable = 1, + }, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_a2noc_snoc }, +}; + +static struct qcom_icc_node qnm_lpass_lpinoc = { + .name = "qnm_lpass_lpinoc", + .channels = 1, + .buswidth = 16, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_lpass_aggnoc }, +}; + +static struct qcom_icc_node qns_lpi_aon_noc = { + .name = "qns_lpi_aon_noc", + .channels = 1, + .buswidth = 16, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qnm_lpass_lpinoc }, +}; + +static struct qcom_icc_node qnm_lpinoc_dsp_qns4m = { + .name = "qnm_lpinoc_dsp_qns4m", + .channels = 1, + .buswidth = 16, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_lpi_aon_noc }, +}; + +static struct qcom_icc_bcm bcm_acv = { + .name = "ACV", + .enable_mask = BIT(3), + .num_nodes = 1, + .nodes = { &ebi }, +}; + +static struct qcom_icc_bcm bcm_ce0 = { + .name = "CE0", + .num_nodes = 1, + .nodes = { &qxm_crypto }, +}; + +static struct qcom_icc_bcm bcm_cn0 = { + .name = "CN0", + .enable_mask = BIT(0), + .keepalive = true, + .num_nodes = 43, + .nodes = { &qsm_cfg, &qhs_ahb2phy0, + &qhs_ahb2phy1, &qhs_camera_cfg, + &qhs_clk_ctl, &qhs_crypto0_cfg, + &qhs_eva_cfg, &qhs_gpuss_cfg, + &qhs_i3c_ibi0_cfg, &qhs_i3c_ibi1_cfg, + &qhs_imem_cfg, &qhs_ipc_router, + &qhs_mss_cfg, &qhs_pcie_cfg, + &qhs_prng, &qhs_qdss_cfg, + &qhs_qspi, &qhs_sdc2, + &qhs_sdc4, &qhs_spss_cfg, + &qhs_tcsr, &qhs_tlmm, + &qhs_ufs_mem_cfg, &qhs_usb3, + &qhs_venus_cfg, &qhs_vsense_ctrl_cfg, + &qss_mnoc_cfg, &qss_pcie_anoc_cfg, + &xs_qdss_stm, &xs_sys_tcu_cfg, + &qnm_gemnoc_cnoc, &qnm_gemnoc_pcie, + &qhs_aoss, &qhs_ipa, + &qhs_ipc_router_fence, &qhs_soccp, + &qhs_tme_cfg, &qns_apss, + &qss_cfg, &qss_ddrss_cfg, + &qxs_boot_imem, &qxs_imem, + &xs_pcie }, +}; + +static struct qcom_icc_bcm bcm_cn1 = { + .name = "CN1", + .num_nodes = 6, + .nodes = { &qhs_display_cfg, &qhs_i2c, + &qhs_qup1, &qhs_qup2, + &qhs_qup3, &qhs_qup4 }, +}; + +static struct qcom_icc_bcm bcm_co0 = { + .name = "CO0", + .enable_mask = BIT(0), + .num_nodes = 2, + .nodes = { &qnm_nsp, &qns_nsp_gemnoc }, +}; + +static struct qcom_icc_bcm bcm_lp0 = { + .name = "LP0", + .num_nodes = 2, + .nodes = { &qnm_lpass_lpinoc, &qns_lpass_aggnoc }, +}; + +static struct qcom_icc_bcm bcm_mc0 = { + .name = "MC0", + .keepalive = true, + .num_nodes = 1, + .nodes = { &ebi }, +}; + +static struct qcom_icc_bcm bcm_mm0 = { + .name = "MM0", + .num_nodes = 1, + .nodes = { &qns_mem_noc_hf }, +}; + +static struct qcom_icc_bcm bcm_mm1 = { + .name = "MM1", + .enable_mask = BIT(0), + .num_nodes = 9, + .nodes = { &qnm_camnoc_hf, &qnm_camnoc_nrt_icp_sf, + &qnm_camnoc_rt_cdm_sf, &qnm_camnoc_sf, + &qnm_vapss_hcp, &qnm_video_cv_cpu, + &qnm_video_mvp, &qnm_video_v_cpu, + &qns_mem_noc_sf }, +}; + +static struct qcom_icc_bcm bcm_qpc0 = { + .name = "QPC0", + .num_nodes = 1, + .nodes = { &qnm_qpace }, +}; + +static struct qcom_icc_bcm bcm_qup0 = { + .name = "QUP0", + .keepalive = true, + .vote_scale = 1, + .num_nodes = 1, + .nodes = { &qup0_core_slave }, +}; + +static struct qcom_icc_bcm bcm_qup1 = { + .name = "QUP1", + .keepalive = true, + .vote_scale = 1, + .num_nodes = 1, + .nodes = { &qup1_core_slave }, +}; + +static struct qcom_icc_bcm bcm_qup2 = { + .name = "QUP2", + .keepalive = true, + .vote_scale = 1, + .num_nodes = 1, + .nodes = { &qup2_core_slave }, +}; + +static struct qcom_icc_bcm bcm_qup3 = { + .name = "QUP3", + .keepalive = true, + .vote_scale = 1, + .num_nodes = 1, + .nodes = { &qup3_core_slave }, +}; + +static struct qcom_icc_bcm bcm_qup4 = { + .name = "QUP4", + .keepalive = true, + .vote_scale = 1, + .num_nodes = 1, + .nodes = { &qup4_core_slave }, +}; + +static struct qcom_icc_bcm bcm_sh0 = { + .name = "SH0", + .keepalive = true, + .num_nodes = 1, + .nodes = { &qns_llcc }, +}; + +static struct qcom_icc_bcm bcm_sh1 = { + .name = "SH1", + .enable_mask = BIT(0), + .num_nodes = 14, + .nodes = { &alm_gpu_tcu, &alm_sys_tcu, + &chm_apps, &qnm_gpu, + &qnm_mdsp, &qnm_mnoc_hf, + &qnm_mnoc_sf, &qnm_nsp_gemnoc, + &qnm_pcie, &qnm_snoc_sf, + &qnm_wlan_q6, &xm_gic, + &qns_gem_noc_cnoc, &qns_pcie }, +}; + +static struct qcom_icc_bcm bcm_sn0 = { + .name = "SN0", + .keepalive = true, + .num_nodes = 1, + .nodes = { &qns_gemnoc_sf }, +}; + +static struct qcom_icc_bcm bcm_sn2 = { + .name = "SN2", + .num_nodes = 1, + .nodes = { &qnm_aggre1_noc }, +}; + +static struct qcom_icc_bcm bcm_sn3 = { + .name = "SN3", + .num_nodes = 1, + .nodes = { &qnm_aggre2_noc }, +}; + +static struct qcom_icc_bcm bcm_sn4 = { + .name = "SN4", + .num_nodes = 1, + .nodes = { &qns_pcie_gemnoc }, +}; + +static struct qcom_icc_bcm * const aggre_noc_bcms[] = { + &bcm_ce0, +}; + +static struct qcom_icc_node * const aggre_noc_nodes[] = { + [MASTER_QSPI_0] = &qhm_qspi, + [MASTER_CRYPTO] = &qxm_crypto, + [MASTER_QUP_1] = &qxm_qup1, + [MASTER_SDCC_4] = &xm_sdc4, + [MASTER_UFS_MEM] = &xm_ufs_mem, + [MASTER_USB3] = &xm_usb3, + [MASTER_QUP_2] = &qhm_qup2, + [MASTER_QUP_3] = &qhm_qup3, + [MASTER_QUP_4] = &qhm_qup4, + [MASTER_IPA] = &qxm_ipa, + [MASTER_SOCCP_PROC] = &qxm_soccp, + [MASTER_SP] = &qxm_sp, + [MASTER_QDSS_ETR] = &xm_qdss_etr_0, + [MASTER_QDSS_ETR_1] = &xm_qdss_etr_1, + [MASTER_SDCC_2] = &xm_sdc2, + [SLAVE_A1NOC_SNOC] = &qns_a1noc_snoc, + [SLAVE_A2NOC_SNOC] = &qns_a2noc_snoc, +}; + +static const struct regmap_config kaanapali_aggre_noc_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x42400, + .fast_io = true, +}; + +static const struct qcom_icc_desc kaanapali_aggre_noc = { + .config = &kaanapali_aggre_noc_regmap_config, + .nodes = aggre_noc_nodes, + .num_nodes = ARRAY_SIZE(aggre_noc_nodes), + .bcms = aggre_noc_bcms, + .num_bcms = ARRAY_SIZE(aggre_noc_bcms), + .qos_requires_clocks = true, + .alloc_dyn_id = true, +}; + +static struct qcom_icc_bcm * const clk_virt_bcms[] = { + &bcm_qup0, + &bcm_qup1, + &bcm_qup2, + &bcm_qup3, + &bcm_qup4, +}; + +static struct qcom_icc_node * const clk_virt_nodes[] = { + [MASTER_QUP_CORE_0] = &qup0_core_master, + [MASTER_QUP_CORE_1] = &qup1_core_master, + [MASTER_QUP_CORE_2] = &qup2_core_master, + [MASTER_QUP_CORE_3] = &qup3_core_master, + [MASTER_QUP_CORE_4] = &qup4_core_master, + [SLAVE_QUP_CORE_0] = &qup0_core_slave, + [SLAVE_QUP_CORE_1] = &qup1_core_slave, + [SLAVE_QUP_CORE_2] = &qup2_core_slave, + [SLAVE_QUP_CORE_3] = &qup3_core_slave, + [SLAVE_QUP_CORE_4] = &qup4_core_slave, +}; + +static const struct qcom_icc_desc kaanapali_clk_virt = { + .nodes = clk_virt_nodes, + .num_nodes = ARRAY_SIZE(clk_virt_nodes), + .bcms = clk_virt_bcms, + .num_bcms = ARRAY_SIZE(clk_virt_bcms), + .alloc_dyn_id = true, +}; + +static struct qcom_icc_bcm * const cnoc_cfg_bcms[] = { + &bcm_cn0, + &bcm_cn1, +}; + +static struct qcom_icc_node * const cnoc_cfg_nodes[] = { + [MASTER_CNOC_CFG] = &qsm_cfg, + [SLAVE_AHB2PHY_SOUTH] = &qhs_ahb2phy0, + [SLAVE_AHB2PHY_NORTH] = &qhs_ahb2phy1, + [SLAVE_CAMERA_CFG] = &qhs_camera_cfg, + [SLAVE_CLK_CTL] = &qhs_clk_ctl, + [SLAVE_CRYPTO_0_CFG] = &qhs_crypto0_cfg, + [SLAVE_DISPLAY_CFG] = &qhs_display_cfg, + [SLAVE_EVA_CFG] = &qhs_eva_cfg, + [SLAVE_GFX3D_CFG] = &qhs_gpuss_cfg, + [SLAVE_I2C] = &qhs_i2c, + [SLAVE_I3C_IBI0_CFG] = &qhs_i3c_ibi0_cfg, + [SLAVE_I3C_IBI1_CFG] = &qhs_i3c_ibi1_cfg, + [SLAVE_IMEM_CFG] = &qhs_imem_cfg, + [SLAVE_IPC_ROUTER_CFG] = &qhs_ipc_router, + [SLAVE_CNOC_MSS] = &qhs_mss_cfg, + [SLAVE_PCIE_CFG] = &qhs_pcie_cfg, + [SLAVE_PRNG] = &qhs_prng, + [SLAVE_QDSS_CFG] = &qhs_qdss_cfg, + [SLAVE_QSPI_0] = &qhs_qspi, + [SLAVE_QUP_1] = &qhs_qup1, + [SLAVE_QUP_2] = &qhs_qup2, + [SLAVE_QUP_3] = &qhs_qup3, + [SLAVE_QUP_4] = &qhs_qup4, + [SLAVE_SDCC_2] = &qhs_sdc2, + [SLAVE_SDCC_4] = &qhs_sdc4, + [SLAVE_SPSS_CFG] = &qhs_spss_cfg, + [SLAVE_TCSR] = &qhs_tcsr, + [SLAVE_TLMM] = &qhs_tlmm, + [SLAVE_UFS_MEM_CFG] = &qhs_ufs_mem_cfg, + [SLAVE_USB3] = &qhs_usb3, + [SLAVE_VENUS_CFG] = &qhs_venus_cfg, + [SLAVE_VSENSE_CTRL_CFG] = &qhs_vsense_ctrl_cfg, + [SLAVE_CNOC_MNOC_CFG] = &qss_mnoc_cfg, + [SLAVE_PCIE_ANOC_CFG] = &qss_pcie_anoc_cfg, + [SLAVE_QDSS_STM] = &xs_qdss_stm, + [SLAVE_TCU] = &xs_sys_tcu_cfg, +}; + +static const struct regmap_config kaanapali_cnoc_cfg_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x6200, + .fast_io = true, +}; + +static const struct qcom_icc_desc kaanapali_cnoc_cfg = { + .config = &kaanapali_cnoc_cfg_regmap_config, + .nodes = cnoc_cfg_nodes, + .num_nodes = ARRAY_SIZE(cnoc_cfg_nodes), + .bcms = cnoc_cfg_bcms, + .num_bcms = ARRAY_SIZE(cnoc_cfg_bcms), + .alloc_dyn_id = true, +}; + +static struct qcom_icc_bcm * const cnoc_main_bcms[] = { + &bcm_cn0, +}; + +static struct qcom_icc_node * const cnoc_main_nodes[] = { + [MASTER_GEM_NOC_CNOC] = &qnm_gemnoc_cnoc, + [MASTER_GEM_NOC_PCIE_SNOC] = &qnm_gemnoc_pcie, + [SLAVE_AOSS] = &qhs_aoss, + [SLAVE_IPA_CFG] = &qhs_ipa, + [SLAVE_IPC_ROUTER_FENCE] = &qhs_ipc_router_fence, + [SLAVE_SOCCP] = &qhs_soccp, + [SLAVE_TME_CFG] = &qhs_tme_cfg, + [SLAVE_APPSS] = &qns_apss, + [SLAVE_CNOC_CFG] = &qss_cfg, + [SLAVE_DDRSS_CFG] = &qss_ddrss_cfg, + [SLAVE_BOOT_IMEM] = &qxs_boot_imem, + [SLAVE_IMEM] = &qxs_imem, + [SLAVE_PCIE_0] = &xs_pcie, +}; + +static const struct regmap_config kaanapali_cnoc_main_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x1a080, + .fast_io = true, +}; + +static const struct qcom_icc_desc kaanapali_cnoc_main = { + .config = &kaanapali_cnoc_main_regmap_config, + .nodes = cnoc_main_nodes, + .num_nodes = ARRAY_SIZE(cnoc_main_nodes), + .bcms = cnoc_main_bcms, + .num_bcms = ARRAY_SIZE(cnoc_main_bcms), + .alloc_dyn_id = true, +}; + +static struct qcom_icc_bcm * const gem_noc_bcms[] = { + &bcm_qpc0, + &bcm_sh0, + &bcm_sh1, +}; + +static struct qcom_icc_node * const gem_noc_nodes[] = { + [MASTER_GPU_TCU] = &alm_gpu_tcu, + [MASTER_SYS_TCU] = &alm_sys_tcu, + [MASTER_APPSS_PROC] = &chm_apps, + [MASTER_GFX3D] = &qnm_gpu, + [MASTER_LPASS_GEM_NOC] = &qnm_lpass_gemnoc, + [MASTER_MSS_PROC] = &qnm_mdsp, + [MASTER_MNOC_HF_MEM_NOC] = &qnm_mnoc_hf, + [MASTER_MNOC_SF_MEM_NOC] = &qnm_mnoc_sf, + [MASTER_COMPUTE_NOC] = &qnm_nsp_gemnoc, + [MASTER_ANOC_PCIE_GEM_NOC] = &qnm_pcie, + [MASTER_QPACE] = &qnm_qpace, + [MASTER_SNOC_SF_MEM_NOC] = &qnm_snoc_sf, + [MASTER_WLAN_Q6] = &qnm_wlan_q6, + [MASTER_GIC] = &xm_gic, + [SLAVE_GEM_NOC_CNOC] = &qns_gem_noc_cnoc, + [SLAVE_LLCC] = &qns_llcc, + [SLAVE_MEM_NOC_PCIE_SNOC] = &qns_pcie, +}; + +static const struct regmap_config kaanapali_gem_noc_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x153080, + .fast_io = true, +}; + +static const struct qcom_icc_desc kaanapali_gem_noc = { + .config = &kaanapali_gem_noc_regmap_config, + .nodes = gem_noc_nodes, + .num_nodes = ARRAY_SIZE(gem_noc_nodes), + .bcms = gem_noc_bcms, + .num_bcms = ARRAY_SIZE(gem_noc_bcms), + .alloc_dyn_id = true, +}; + +static struct qcom_icc_node * const lpass_ag_noc_nodes[] = { + [MASTER_LPIAON_NOC] = &qnm_lpiaon_noc, + [SLAVE_LPASS_GEM_NOC] = &qns_lpass_ag_noc_gemnoc, +}; + +static const struct regmap_config kaanapali_lpass_ag_noc_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0xe080, + .fast_io = true, +}; + +static const struct qcom_icc_desc kaanapali_lpass_ag_noc = { + .config = &kaanapali_lpass_ag_noc_regmap_config, + .nodes = lpass_ag_noc_nodes, + .num_nodes = ARRAY_SIZE(lpass_ag_noc_nodes), + .alloc_dyn_id = true, +}; + +static struct qcom_icc_bcm * const lpass_lpiaon_noc_bcms[] = { + &bcm_lp0, +}; + +static struct qcom_icc_node * const lpass_lpiaon_noc_nodes[] = { + [MASTER_LPASS_LPINOC] = &qnm_lpass_lpinoc, + [SLAVE_LPIAON_NOC_LPASS_AG_NOC] = &qns_lpass_aggnoc, +}; + +static const struct regmap_config kaanapali_lpass_lpiaon_noc_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x19080, + .fast_io = true, +}; + +static const struct qcom_icc_desc kaanapali_lpass_lpiaon_noc = { + .config = &kaanapali_lpass_lpiaon_noc_regmap_config, + .nodes = lpass_lpiaon_noc_nodes, + .num_nodes = ARRAY_SIZE(lpass_lpiaon_noc_nodes), + .bcms = lpass_lpiaon_noc_bcms, + .num_bcms = ARRAY_SIZE(lpass_lpiaon_noc_bcms), + .alloc_dyn_id = true, +}; + +static struct qcom_icc_node * const lpass_lpicx_noc_nodes[] = { + [MASTER_LPASS_PROC] = &qnm_lpinoc_dsp_qns4m, + [SLAVE_LPICX_NOC_LPIAON_NOC] = &qns_lpi_aon_noc, +}; + +static const struct regmap_config kaanapali_lpass_lpicx_noc_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x44080, + .fast_io = true, +}; + +static const struct qcom_icc_desc kaanapali_lpass_lpicx_noc = { + .config = &kaanapali_lpass_lpicx_noc_regmap_config, + .nodes = lpass_lpicx_noc_nodes, + .num_nodes = ARRAY_SIZE(lpass_lpicx_noc_nodes), + .alloc_dyn_id = true, +}; + +static struct qcom_icc_bcm * const mc_virt_bcms[] = { + &bcm_acv, + &bcm_mc0, +}; + +static struct qcom_icc_node * const mc_virt_nodes[] = { + [MASTER_LLCC] = &llcc_mc, + [SLAVE_EBI1] = &ebi, +}; + +static const struct qcom_icc_desc kaanapali_mc_virt = { + .nodes = mc_virt_nodes, + .num_nodes = ARRAY_SIZE(mc_virt_nodes), + .bcms = mc_virt_bcms, + .num_bcms = ARRAY_SIZE(mc_virt_bcms), + .alloc_dyn_id = true, +}; + +static struct qcom_icc_bcm * const mmss_noc_bcms[] = { + &bcm_mm0, + &bcm_mm1, +}; + +static struct qcom_icc_node * const mmss_noc_nodes[] = { + [MASTER_CAMNOC_HF] = &qnm_camnoc_hf, + [MASTER_CAMNOC_NRT_ICP_SF] = &qnm_camnoc_nrt_icp_sf, + [MASTER_CAMNOC_RT_CDM_SF] = &qnm_camnoc_rt_cdm_sf, + [MASTER_CAMNOC_SF] = &qnm_camnoc_sf, + [MASTER_MDP] = &qnm_mdp, + [MASTER_MDSS_DCP] = &qnm_mdss_dcp, + [MASTER_CDSP_HCP] = &qnm_vapss_hcp, + [MASTER_VIDEO_CV_PROC] = &qnm_video_cv_cpu, + [MASTER_VIDEO_EVA] = &qnm_video_eva, + [MASTER_VIDEO_MVP] = &qnm_video_mvp, + [MASTER_VIDEO_V_PROC] = &qnm_video_v_cpu, + [MASTER_CNOC_MNOC_CFG] = &qsm_mnoc_cfg, + [SLAVE_MNOC_HF_MEM_NOC] = &qns_mem_noc_hf, + [SLAVE_MNOC_SF_MEM_NOC] = &qns_mem_noc_sf, + [SLAVE_SERVICE_MNOC] = &srvc_mnoc, +}; + +static const struct regmap_config kaanapali_mmss_noc_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x5b800, + .fast_io = true, +}; + +static const struct qcom_icc_desc kaanapali_mmss_noc = { + .config = &kaanapali_mmss_noc_regmap_config, + .nodes = mmss_noc_nodes, + .num_nodes = ARRAY_SIZE(mmss_noc_nodes), + .bcms = mmss_noc_bcms, + .num_bcms = ARRAY_SIZE(mmss_noc_bcms), + .alloc_dyn_id = true, +}; + +static struct qcom_icc_bcm * const nsp_noc_bcms[] = { + &bcm_co0, +}; + +static struct qcom_icc_node * const nsp_noc_nodes[] = { + [MASTER_CDSP_PROC] = &qnm_nsp, + [SLAVE_CDSP_MEM_NOC] = &qns_nsp_gemnoc, +}; + +static const struct regmap_config kaanapali_nsp_noc_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x21280, + .fast_io = true, +}; + +static const struct qcom_icc_desc kaanapali_nsp_noc = { + .config = &kaanapali_nsp_noc_regmap_config, + .nodes = nsp_noc_nodes, + .num_nodes = ARRAY_SIZE(nsp_noc_nodes), + .bcms = nsp_noc_bcms, + .num_bcms = ARRAY_SIZE(nsp_noc_bcms), + .alloc_dyn_id = true, +}; + +static struct qcom_icc_bcm * const pcie_anoc_bcms[] = { + &bcm_sn4, +}; + +static struct qcom_icc_node * const pcie_anoc_nodes[] = { + [MASTER_PCIE_ANOC_CFG] = &qsm_pcie_anoc_cfg, + [MASTER_PCIE_0] = &xm_pcie, + [SLAVE_ANOC_PCIE_GEM_NOC] = &qns_pcie_gemnoc, + [SLAVE_SERVICE_PCIE_ANOC] = &srvc_pcie_aggre_noc, +}; + +static const struct regmap_config kaanapali_pcie_anoc_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x11400, + .fast_io = true, +}; + +static const struct qcom_icc_desc kaanapali_pcie_anoc = { + .config = &kaanapali_pcie_anoc_regmap_config, + .nodes = pcie_anoc_nodes, + .num_nodes = ARRAY_SIZE(pcie_anoc_nodes), + .bcms = pcie_anoc_bcms, + .num_bcms = ARRAY_SIZE(pcie_anoc_bcms), + .qos_requires_clocks = true, + .alloc_dyn_id = true, +}; + +static struct qcom_icc_bcm * const system_noc_bcms[] = { + &bcm_sn0, + &bcm_sn2, + &bcm_sn3, +}; + +static struct qcom_icc_node * const system_noc_nodes[] = { + [MASTER_A1NOC_SNOC] = &qnm_aggre1_noc, + [MASTER_A2NOC_SNOC] = &qnm_aggre2_noc, + [MASTER_APSS_NOC] = &qnm_apss_noc, + [MASTER_CNOC_SNOC] = &qnm_cnoc_data, + [SLAVE_SNOC_GEM_NOC_SF] = &qns_gemnoc_sf, +}; + +static const struct regmap_config kaanapali_system_noc_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x1f080, + .fast_io = true, +}; + +static const struct qcom_icc_desc kaanapali_system_noc = { + .config = &kaanapali_system_noc_regmap_config, + .nodes = system_noc_nodes, + .num_nodes = ARRAY_SIZE(system_noc_nodes), + .bcms = system_noc_bcms, + .num_bcms = ARRAY_SIZE(system_noc_bcms), + .alloc_dyn_id = true, +}; + +static const struct of_device_id qnoc_of_match[] = { + { .compatible = "qcom,kaanapali-aggre-noc", .data = &kaanapali_aggre_noc }, + { .compatible = "qcom,kaanapali-clk-virt", .data = &kaanapali_clk_virt }, + { .compatible = "qcom,kaanapali-cnoc-cfg", .data = &kaanapali_cnoc_cfg }, + { .compatible = "qcom,kaanapali-cnoc-main", .data = &kaanapali_cnoc_main }, + { .compatible = "qcom,kaanapali-gem-noc", .data = &kaanapali_gem_noc }, + { .compatible = "qcom,kaanapali-lpass-ag-noc", .data = &kaanapali_lpass_ag_noc }, + { .compatible = "qcom,kaanapali-lpass-lpiaon-noc", .data = &kaanapali_lpass_lpiaon_noc }, + { .compatible = "qcom,kaanapali-lpass-lpicx-noc", .data = &kaanapali_lpass_lpicx_noc }, + { .compatible = "qcom,kaanapali-mc-virt", .data = &kaanapali_mc_virt }, + { .compatible = "qcom,kaanapali-mmss-noc", .data = &kaanapali_mmss_noc }, + { .compatible = "qcom,kaanapali-nsp-noc", .data = &kaanapali_nsp_noc }, + { .compatible = "qcom,kaanapali-pcie-anoc", .data = &kaanapali_pcie_anoc }, + { .compatible = "qcom,kaanapali-system-noc", .data = &kaanapali_system_noc }, + { } +}; +MODULE_DEVICE_TABLE(of, qnoc_of_match); + +static struct platform_driver qnoc_driver = { + .probe = qcom_icc_rpmh_probe, + .remove = qcom_icc_rpmh_remove, + .driver = { + .name = "qnoc-kaanapali", + .of_match_table = qnoc_of_match, + .sync_state = icc_sync_state, + }, +}; + +static int __init qnoc_driver_init(void) +{ + return platform_driver_register(&qnoc_driver); +} +core_initcall(qnoc_driver_init); + +static void __exit qnoc_driver_exit(void) +{ + platform_driver_unregister(&qnoc_driver); +} +module_exit(qnoc_driver_exit); + +MODULE_DESCRIPTION("Qualcomm Kaanapali NoC driver"); +MODULE_LICENSE("GPL"); From 91ce69531a9a1e0e371ca4df8657100df9e036ac Mon Sep 17 00:00:00 2001 From: Jie Gan Date: Tue, 4 Nov 2025 15:36:13 +0800 Subject: [PATCH 0094/2333] FROMLIST: arm64: dts: qcom: hamoa: enable ETR and CTCU devices Embedded Trace Router(ETR) is working as a DDR memory sink to collect tracing data from source device. The CTCU serves as the control unit for the ETR device, managing its behavior to determine how trace data is collected. Link: https://lore.kernel.org/all/20251104-enable-etr-and-ctcu-for-hamoa-v1-2-af552cfb902c@oss.qualcomm.com/ Signed-off-by: Jie Gan --- arch/arm64/boot/dts/qcom/x1e80100.dtsi | 160 ++++++++++++++++++++++++- 1 file changed, 159 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/x1e80100.dtsi b/arch/arm64/boot/dts/qcom/x1e80100.dtsi index f4b59f0163351..ff544ac35cc8c 100644 --- a/arch/arm64/boot/dts/qcom/x1e80100.dtsi +++ b/arch/arm64/boot/dts/qcom/x1e80100.dtsi @@ -6634,6 +6634,35 @@ }; }; + ctcu@10001000 { + compatible = "qcom,hamoa-ctcu", "qcom,sa8775p-ctcu"; + reg = <0x0 0x10001000 0x0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb"; + + in-ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + ctcu_in0: endpoint { + remote-endpoint = <&etr0_out>; + }; + }; + + port@1 { + reg = <1>; + + ctcu_in1: endpoint { + remote-endpoint = <&etr1_out>; + }; + }; + }; + }; + stm@10002000 { compatible = "arm,coresight-stm", "arm,primecell"; reg = <0x0 0x10002000 0x0 0x1000>, @@ -6856,6 +6885,122 @@ }; }; + replicator@10046000 { + compatible = "arm,coresight-dynamic-replicator", "arm,primecell"; + reg = <0x0 0x10046000 0x0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + + in-ports { + port { + qdss_rep_in: endpoint { + remote-endpoint = <&swao_rep_out0>; + }; + }; + }; + + out-ports { + port { + qdss_rep_out0: endpoint { + remote-endpoint = <&etr_rep_in>; + }; + }; + }; + }; + + tmc_etr: tmc@10048000 { + compatible = "arm,coresight-tmc", "arm,primecell"; + reg = <0x0 0x10048000 0x0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + iommus = <&apps_smmu 0x04e0 0x0>; + + arm,scatter-gather; + + in-ports { + port { + etr0_in: endpoint { + remote-endpoint = <&etr_rep_out0>; + }; + }; + }; + + out-ports { + port { + etr0_out: endpoint { + remote-endpoint = <&ctcu_in0>; + }; + }; + }; + }; + + replicator@1004e000 { + compatible = "arm,coresight-dynamic-replicator", "arm,primecell"; + reg = <0x0 0x1004e000 0x0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + + in-ports { + port { + etr_rep_in: endpoint { + remote-endpoint = <&qdss_rep_out0>; + }; + }; + }; + + out-ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + etr_rep_out0: endpoint { + remote-endpoint = <&etr0_in>; + }; + }; + + port@1 { + reg = <1>; + + etr_rep_out1: endpoint { + remote-endpoint = <&etr1_in>; + }; + }; + }; + }; + + tmc_etr1: tmc@1004f000 { + compatible = "arm,coresight-tmc", "arm,primecell"; + reg = <0x0 0x1004f000 0x0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + iommus = <&apps_smmu 0x0500 0x0>; + + arm,scatter-gather; + arm,buffer-size = <0x400000>; + + in-ports { + port { + etr1_in: endpoint { + remote-endpoint = <&etr_rep_out1>; + }; + }; + }; + + out-ports { + port { + etr1_out: endpoint { + remote-endpoint = <&ctcu_in1>; + }; + }; + }; + }; + tpdm@10800000 { compatible = "qcom,coresight-tpdm", "arm,primecell"; reg = <0x0 0x10800000 0x0 0x1000>; @@ -7169,7 +7314,20 @@ }; out-ports { - port { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + swao_rep_out0: endpoint { + remote-endpoint = <&qdss_rep_in>; + }; + }; + + port@1 { + reg = <1>; + swao_rep_out1: endpoint { remote-endpoint = <&eud_in>; }; From 6d172a082ffe1607aa774f40b1b9807497642289 Mon Sep 17 00:00:00 2001 From: Shivendra Pratap Date: Mon, 22 Sep 2025 19:10:11 +0530 Subject: [PATCH 0095/2333] FROMLIST: power: reset: reboot-mode: Synchronize list traversal List traversals must be synchronized to prevent race conditions and data corruption. The reboot-mode list is not protected by a lock currently, which can lead to concurrent access and race. Introduce a mutex lock to guard all operations on the reboot-mode list and ensure thread-safe access. The change prevents unsafe concurrent access on reboot-mode list. Fixes: 4fcd504edbf7 ("power: reset: add reboot mode driver") Fixes: ca3d2ea52314 ("power: reset: reboot-mode: better compatibility with DT (replace ' ,/')") Link: https://lore.kernel.org/r/20250922-arm-psci-system_reset2-vendor-reboots-v15-1-7ce3a08878f1@oss.qualcomm.com Signed-off-by: Shivendra Pratap --- drivers/power/reset/reboot-mode.c | 96 +++++++++++++++++-------------- include/linux/reboot-mode.h | 4 ++ 2 files changed, 57 insertions(+), 43 deletions(-) diff --git a/drivers/power/reset/reboot-mode.c b/drivers/power/reset/reboot-mode.c index fba53f638da04..8fc3e14638ea7 100644 --- a/drivers/power/reset/reboot-mode.c +++ b/drivers/power/reset/reboot-mode.c @@ -29,9 +29,11 @@ static unsigned int get_reboot_mode_magic(struct reboot_mode_driver *reboot, if (!cmd) cmd = normal; - list_for_each_entry(info, &reboot->head, list) - if (!strcmp(info->mode, cmd)) - return info->magic; + scoped_guard(mutex, &reboot->rb_lock) { + list_for_each_entry(info, &reboot->head, list) + if (!strcmp(info->mode, cmd)) + return info->magic; + } /* try to match again, replacing characters impossible in DT */ if (strscpy(cmd_, cmd, sizeof(cmd_)) == -E2BIG) @@ -41,9 +43,11 @@ static unsigned int get_reboot_mode_magic(struct reboot_mode_driver *reboot, strreplace(cmd_, ',', '-'); strreplace(cmd_, '/', '-'); - list_for_each_entry(info, &reboot->head, list) - if (!strcmp(info->mode, cmd_)) - return info->magic; + scoped_guard(mutex, &reboot->rb_lock) { + list_for_each_entry(info, &reboot->head, list) + if (!strcmp(info->mode, cmd_)) + return info->magic; + } return 0; } @@ -78,46 +82,50 @@ int reboot_mode_register(struct reboot_mode_driver *reboot) INIT_LIST_HEAD(&reboot->head); - for_each_property_of_node(np, prop) { - if (strncmp(prop->name, PREFIX, len)) - continue; - - info = devm_kzalloc(reboot->dev, sizeof(*info), GFP_KERNEL); - if (!info) { - ret = -ENOMEM; - goto error; - } - - if (of_property_read_u32(np, prop->name, &info->magic)) { - dev_err(reboot->dev, "reboot mode %s without magic number\n", - info->mode); - devm_kfree(reboot->dev, info); - continue; - } - - info->mode = kstrdup_const(prop->name + len, GFP_KERNEL); - if (!info->mode) { - ret = -ENOMEM; - goto error; - } else if (info->mode[0] == '\0') { - kfree_const(info->mode); - ret = -EINVAL; - dev_err(reboot->dev, "invalid mode name(%s): too short!\n", - prop->name); - goto error; + mutex_init(&reboot->rb_lock); + + scoped_guard(mutex, &reboot->rb_lock) { + for_each_property_of_node(np, prop) { + if (strncmp(prop->name, PREFIX, len)) + continue; + + info = devm_kzalloc(reboot->dev, sizeof(*info), GFP_KERNEL); + if (!info) { + ret = -ENOMEM; + goto error; + } + + if (of_property_read_u32(np, prop->name, &info->magic)) { + dev_err(reboot->dev, "reboot mode %s without magic number\n", + info->mode); + devm_kfree(reboot->dev, info); + continue; + } + + info->mode = kstrdup_const(prop->name + len, GFP_KERNEL); + if (!info->mode) { + ret = -ENOMEM; + goto error; + } else if (info->mode[0] == '\0') { + kfree_const(info->mode); + ret = -EINVAL; + dev_err(reboot->dev, "invalid mode name(%s): too short!\n", + prop->name); + goto error; + } + + list_add_tail(&info->list, &reboot->head); } - list_add_tail(&info->list, &reboot->head); - } - - reboot->reboot_notifier.notifier_call = reboot_mode_notify; - register_reboot_notifier(&reboot->reboot_notifier); + reboot->reboot_notifier.notifier_call = reboot_mode_notify; + register_reboot_notifier(&reboot->reboot_notifier); - return 0; + return 0; error: - list_for_each_entry(info, &reboot->head, list) - kfree_const(info->mode); + list_for_each_entry(info, &reboot->head, list) + kfree_const(info->mode); + } return ret; } @@ -133,8 +141,10 @@ int reboot_mode_unregister(struct reboot_mode_driver *reboot) unregister_reboot_notifier(&reboot->reboot_notifier); - list_for_each_entry(info, &reboot->head, list) - kfree_const(info->mode); + scoped_guard(mutex, &reboot->rb_lock) { + list_for_each_entry(info, &reboot->head, list) + kfree_const(info->mode); + } return 0; } diff --git a/include/linux/reboot-mode.h b/include/linux/reboot-mode.h index 4a2abb38d1d61..b73f807081976 100644 --- a/include/linux/reboot-mode.h +++ b/include/linux/reboot-mode.h @@ -2,11 +2,15 @@ #ifndef __REBOOT_MODE_H__ #define __REBOOT_MODE_H__ +#include + struct reboot_mode_driver { struct device *dev; struct list_head head; int (*write)(struct reboot_mode_driver *reboot, unsigned int magic); struct notifier_block reboot_notifier; + /*Protects access to reboot mode list*/ + struct mutex rb_lock; }; int reboot_mode_register(struct reboot_mode_driver *reboot); From 891d5c09fb3d27e0b2e66a18577c42148b8f0e65 Mon Sep 17 00:00:00 2001 From: Shivendra Pratap Date: Mon, 22 Sep 2025 19:10:12 +0530 Subject: [PATCH 0096/2333] FROMLIST: power: reset: reboot-mode: Add device tree node-based registration The reboot-mode driver does not have a strict requirement for device-based registration. It primarily uses the device's of_node to read mode- properties and the device pointer for logging. Remove the dependency on struct device and introduce support for firmware node (fwnode) based registration. This enables drivers that are not associated with a struct device to leverage the reboot-mode framework. Link: https://lore.kernel.org/r/20250922-arm-psci-system_reset2-vendor-reboots-v15-2-7ce3a08878f1@oss.qualcomm.com Signed-off-by: Shivendra Pratap --- drivers/power/reset/reboot-mode.c | 45 +++++++++++++++++++++++-------- include/linux/reboot-mode.h | 3 ++- 2 files changed, 36 insertions(+), 12 deletions(-) diff --git a/drivers/power/reset/reboot-mode.c b/drivers/power/reset/reboot-mode.c index 8fc3e14638ea7..c8f71e6f661ae 100644 --- a/drivers/power/reset/reboot-mode.c +++ b/drivers/power/reset/reboot-mode.c @@ -3,13 +3,17 @@ * Copyright (c) 2016, Fuzhou Rockchip Electronics Co., Ltd */ +#define pr_fmt(fmt) "reboot-mode: " fmt + #include #include #include +#include #include #include #include #include +#include #define PREFIX "mode-" @@ -69,17 +73,26 @@ static int reboot_mode_notify(struct notifier_block *this, /** * reboot_mode_register - register a reboot mode driver * @reboot: reboot mode driver + * @fwnode: Firmware node with reboot-mode configuration * * Returns: 0 on success or a negative error code on failure. */ -int reboot_mode_register(struct reboot_mode_driver *reboot) +int reboot_mode_register(struct reboot_mode_driver *reboot, struct fwnode_handle *fwnode) { struct mode_info *info; + struct mode_info *next; + struct device_node *np; struct property *prop; - struct device_node *np = reboot->dev->of_node; size_t len = strlen(PREFIX); int ret; + if (!fwnode) + return -EINVAL; + + np = to_of_node(fwnode); + if (!np) + return -EINVAL; + INIT_LIST_HEAD(&reboot->head); mutex_init(&reboot->rb_lock); @@ -89,28 +102,28 @@ int reboot_mode_register(struct reboot_mode_driver *reboot) if (strncmp(prop->name, PREFIX, len)) continue; - info = devm_kzalloc(reboot->dev, sizeof(*info), GFP_KERNEL); + info = kzalloc(sizeof(*info), GFP_KERNEL); if (!info) { ret = -ENOMEM; goto error; } if (of_property_read_u32(np, prop->name, &info->magic)) { - dev_err(reboot->dev, "reboot mode %s without magic number\n", - info->mode); - devm_kfree(reboot->dev, info); + pr_err("reboot mode %s without magic number\n", info->mode); + kfree(info); continue; } info->mode = kstrdup_const(prop->name + len, GFP_KERNEL); if (!info->mode) { ret = -ENOMEM; + kfree(info); goto error; } else if (info->mode[0] == '\0') { kfree_const(info->mode); + kfree(info); ret = -EINVAL; - dev_err(reboot->dev, "invalid mode name(%s): too short!\n", - prop->name); + pr_err("invalid mode name(%s): too short!\n", prop->name); goto error; } @@ -123,8 +136,11 @@ int reboot_mode_register(struct reboot_mode_driver *reboot) return 0; error: - list_for_each_entry(info, &reboot->head, list) + list_for_each_entry_safe(info, next, &reboot->head, list) { + list_del(&info->list); kfree_const(info->mode); + kfree(info); + } } return ret; @@ -138,12 +154,16 @@ EXPORT_SYMBOL_GPL(reboot_mode_register); int reboot_mode_unregister(struct reboot_mode_driver *reboot) { struct mode_info *info; + struct mode_info *next; unregister_reboot_notifier(&reboot->reboot_notifier); scoped_guard(mutex, &reboot->rb_lock) { - list_for_each_entry(info, &reboot->head, list) + list_for_each_entry_safe(info, next, &reboot->head, list) { + list_del(&info->list); kfree_const(info->mode); + kfree(info); + } } return 0; @@ -168,11 +188,14 @@ int devm_reboot_mode_register(struct device *dev, struct reboot_mode_driver **dr; int rc; + if (!reboot->dev || !reboot->dev->of_node) + return -EINVAL; + dr = devres_alloc(devm_reboot_mode_release, sizeof(*dr), GFP_KERNEL); if (!dr) return -ENOMEM; - rc = reboot_mode_register(reboot); + rc = reboot_mode_register(reboot, of_fwnode_handle(reboot->dev->of_node)); if (rc) { devres_free(dr); return rc; diff --git a/include/linux/reboot-mode.h b/include/linux/reboot-mode.h index b73f807081976..7f05fd873e95c 100644 --- a/include/linux/reboot-mode.h +++ b/include/linux/reboot-mode.h @@ -2,6 +2,7 @@ #ifndef __REBOOT_MODE_H__ #define __REBOOT_MODE_H__ +#include #include struct reboot_mode_driver { @@ -13,7 +14,7 @@ struct reboot_mode_driver { struct mutex rb_lock; }; -int reboot_mode_register(struct reboot_mode_driver *reboot); +int reboot_mode_register(struct reboot_mode_driver *reboot, struct fwnode_handle *fwnode); int reboot_mode_unregister(struct reboot_mode_driver *reboot); int devm_reboot_mode_register(struct device *dev, struct reboot_mode_driver *reboot); From ec343f00e57ac66abadd1401055a7d33f0dc8ef6 Mon Sep 17 00:00:00 2001 From: Shivendra Pratap Date: Mon, 22 Sep 2025 19:10:13 +0530 Subject: [PATCH 0097/2333] FROMLIST: power: reset: reboot-mode: Add support for 64 bit magic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Current reboot-mode supports a single 32-bit argument for any supported mode. Some reboot-mode based drivers may require passing two independent 32-bit arguments during a reboot sequence, for uses-cases, where a mode requires an additional argument. Such drivers may not be able to use the reboot-mode driver. For example, ARM PSCI vendor-specific resets, need two arguments for its operation – reset_type and cookie, to complete the reset operation. If a driver wants to implement this firmware-based reset, it cannot use reboot-mode framework. Introduce 64-bit magic values in reboot-mode driver to accommodate dual 32-bit arguments when specified via device tree. In cases, where no second argument is passed from device tree, keep the upper 32-bit of magic un-changed(0) to maintain backward compatibility. Update the current drivers using reboot-mode for a 64-bit magic value. Link: https://lore.kernel.org/r/20250922-arm-psci-system_reset2-vendor-reboots-v15-3-7ce3a08878f1@oss.qualcomm.com Signed-off-by: Shivendra Pratap --- drivers/power/reset/nvmem-reboot-mode.c | 13 +++++++++---- drivers/power/reset/qcom-pon.c | 11 ++++++++--- drivers/power/reset/reboot-mode.c | 19 +++++++++++++------ drivers/power/reset/syscon-reboot-mode.c | 11 ++++++++--- include/linux/reboot-mode.h | 3 ++- 5 files changed, 40 insertions(+), 17 deletions(-) diff --git a/drivers/power/reset/nvmem-reboot-mode.c b/drivers/power/reset/nvmem-reboot-mode.c index 41530b70cfc48..5d73dde585b1f 100644 --- a/drivers/power/reset/nvmem-reboot-mode.c +++ b/drivers/power/reset/nvmem-reboot-mode.c @@ -16,15 +16,20 @@ struct nvmem_reboot_mode { struct nvmem_cell *cell; }; -static int nvmem_reboot_mode_write(struct reboot_mode_driver *reboot, - unsigned int magic) +static int nvmem_reboot_mode_write(struct reboot_mode_driver *reboot, u64 magic) { - int ret; struct nvmem_reboot_mode *nvmem_rbm; + u32 magic_32; + int ret; + + if (magic > U32_MAX) + return -EINVAL; + + magic_32 = magic; nvmem_rbm = container_of(reboot, struct nvmem_reboot_mode, reboot); - ret = nvmem_cell_write(nvmem_rbm->cell, &magic, sizeof(magic)); + ret = nvmem_cell_write(nvmem_rbm->cell, &magic_32, sizeof(magic_32)); if (ret < 0) dev_err(reboot->dev, "update reboot mode bits failed\n"); diff --git a/drivers/power/reset/qcom-pon.c b/drivers/power/reset/qcom-pon.c index 7e108982a582e..d0ed9431a0231 100644 --- a/drivers/power/reset/qcom-pon.c +++ b/drivers/power/reset/qcom-pon.c @@ -27,17 +27,22 @@ struct qcom_pon { long reason_shift; }; -static int qcom_pon_reboot_mode_write(struct reboot_mode_driver *reboot, - unsigned int magic) +static int qcom_pon_reboot_mode_write(struct reboot_mode_driver *reboot, u64 magic) { struct qcom_pon *pon = container_of (reboot, struct qcom_pon, reboot_mode); + u32 magic_32; int ret; + if (magic > U32_MAX || (magic << pon->reason_shift) > U32_MAX) + return -EINVAL; + + magic_32 = magic << pon->reason_shift; + ret = regmap_update_bits(pon->regmap, pon->baseaddr + PON_SOFT_RB_SPARE, GENMASK(7, pon->reason_shift), - magic << pon->reason_shift); + magic_32); if (ret < 0) dev_err(pon->dev, "update reboot mode bits failed\n"); diff --git a/drivers/power/reset/reboot-mode.c b/drivers/power/reset/reboot-mode.c index c8f71e6f661ae..79763a839c9b0 100644 --- a/drivers/power/reset/reboot-mode.c +++ b/drivers/power/reset/reboot-mode.c @@ -19,12 +19,11 @@ struct mode_info { const char *mode; - u32 magic; + u64 magic; struct list_head list; }; -static unsigned int get_reboot_mode_magic(struct reboot_mode_driver *reboot, - const char *cmd) +static u64 get_reboot_mode_magic(struct reboot_mode_driver *reboot, const char *cmd) { const char *normal = "normal"; struct mode_info *info; @@ -60,7 +59,7 @@ static int reboot_mode_notify(struct notifier_block *this, unsigned long mode, void *cmd) { struct reboot_mode_driver *reboot; - unsigned int magic; + u64 magic; reboot = container_of(this, struct reboot_mode_driver, reboot_notifier); magic = get_reboot_mode_magic(reboot, cmd); @@ -84,6 +83,8 @@ int reboot_mode_register(struct reboot_mode_driver *reboot, struct fwnode_handle struct device_node *np; struct property *prop; size_t len = strlen(PREFIX); + u32 magic_arg1; + u32 magic_arg2; int ret; if (!fwnode) @@ -108,12 +109,18 @@ int reboot_mode_register(struct reboot_mode_driver *reboot, struct fwnode_handle goto error; } - if (of_property_read_u32(np, prop->name, &info->magic)) { - pr_err("reboot mode %s without magic number\n", info->mode); + if (of_property_read_u32(np, prop->name, &magic_arg1)) { + pr_err("reboot mode without magic number\n"); kfree(info); continue; } + if (of_property_read_u32_index(np, prop->name, 1, &magic_arg2)) + magic_arg2 = 0; + + info->magic = magic_arg2; + info->magic = (info->magic << 32) | magic_arg1; + info->mode = kstrdup_const(prop->name + len, GFP_KERNEL); if (!info->mode) { ret = -ENOMEM; diff --git a/drivers/power/reset/syscon-reboot-mode.c b/drivers/power/reset/syscon-reboot-mode.c index e0772c9f70f7a..3cbd000c51223 100644 --- a/drivers/power/reset/syscon-reboot-mode.c +++ b/drivers/power/reset/syscon-reboot-mode.c @@ -20,16 +20,21 @@ struct syscon_reboot_mode { u32 mask; }; -static int syscon_reboot_mode_write(struct reboot_mode_driver *reboot, - unsigned int magic) +static int syscon_reboot_mode_write(struct reboot_mode_driver *reboot, u64 magic) { struct syscon_reboot_mode *syscon_rbm; + u32 magic_32; int ret; + if (magic > U32_MAX) + return -EINVAL; + + magic_32 = magic; + syscon_rbm = container_of(reboot, struct syscon_reboot_mode, reboot); ret = regmap_update_bits(syscon_rbm->map, syscon_rbm->offset, - syscon_rbm->mask, magic); + syscon_rbm->mask, magic_32); if (ret < 0) dev_err(reboot->dev, "update reboot mode bits failed\n"); diff --git a/include/linux/reboot-mode.h b/include/linux/reboot-mode.h index 7f05fd873e95c..3a14df2ddd1db 100644 --- a/include/linux/reboot-mode.h +++ b/include/linux/reboot-mode.h @@ -4,11 +4,12 @@ #include #include +#include struct reboot_mode_driver { struct device *dev; struct list_head head; - int (*write)(struct reboot_mode_driver *reboot, unsigned int magic); + int (*write)(struct reboot_mode_driver *reboot, u64 magic); struct notifier_block reboot_notifier; /*Protects access to reboot mode list*/ struct mutex rb_lock; From 5cf0e4f61e68c3545bb286e661ed93d22a3b3cca Mon Sep 17 00:00:00 2001 From: Shivendra Pratap Date: Mon, 22 Sep 2025 19:10:14 +0530 Subject: [PATCH 0098/2333] FROMLIST: Documentation: ABI: Add sysfs-class-reboot-mode-reboot_modes Add ABI documentation for /sys/class/reboot-mode/*/reboot_modes, a read-only sysfs attribute exposing the list of supported reboot-mode arguments. This file is created by reboot-mode framework and provides a user-readable interface to query available reboot-mode arguments. Link: https://lore.kernel.org/r/20250922-arm-psci-system_reset2-vendor-reboots-v15-4-7ce3a08878f1@oss.qualcomm.com Reviewed-by: Sebastian Reichel Signed-off-by: Shivendra Pratap --- .../sysfs-class-reboot-mode-reboot_modes | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 Documentation/ABI/testing/sysfs-class-reboot-mode-reboot_modes diff --git a/Documentation/ABI/testing/sysfs-class-reboot-mode-reboot_modes b/Documentation/ABI/testing/sysfs-class-reboot-mode-reboot_modes new file mode 100644 index 0000000000000..6a3fc379afae3 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-class-reboot-mode-reboot_modes @@ -0,0 +1,39 @@ +What: /sys/class/reboot-mode//reboot_modes +Date: August 2025 +KernelVersion: 6.17.0-rc1 +Contact: linux-pm@vger.kernel.org + Description: + This interface exposes the reboot-mode arguments + registered with the reboot-mode framework. It is + a read-only interface and provides a space + separated list of reboot-mode arguments supported + on the current platform. + Example: + recovery fastboot bootloader + + The exact sysfs path may vary depending on the + name of the driver that registers the arguments. + Example: + /sys/class/reboot-mode/nvmem-reboot-mode/reboot_modes + /sys/class/reboot-mode/syscon-reboot-mode/reboot_modes + /sys/class/reboot-mode/qcom-pon/reboot_modes + + The supported arguments can be used by userspace + to invoke device reset using the reboot() system + call, with the "argument" as string to "*arg" + parameter along with LINUX_REBOOT_CMD_RESTART2. + Example: + reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, + LINUX_REBOOT_CMD_RESTART2, "bootloader"); + + A driver can expose the supported arguments by + registering them with the reboot-mode framework + using the property names that follow the + mode- format. + Example: + mode-bootloader, mode-recovery. + + This attribute is useful for scripts or initramfs + logic that need to programmatically determine + which reboot-mode arguments are valid before + triggering a reboot. From 3fec1ce8e38466ab4da5cb01d7de6655f5b2f5c6 Mon Sep 17 00:00:00 2001 From: Shivendra Pratap Date: Mon, 22 Sep 2025 19:10:15 +0530 Subject: [PATCH 0099/2333] FROMLIST: power: reset: reboot-mode: Expose sysfs for registered reboot_modes Currently, there is no standardized mechanism for userspace to discover which reboot-modes are supported on a given platform. This limitation forces tools and scripts to rely on hardcoded assumptions about the supported reboot-modes. Create a class 'reboot-mode' and a device under it to expose a sysfs interface to show the available reboot mode arguments to userspace. Use the driver_name field of the struct reboot_mode_driver to create the device. For device-based drivers, configure the device driver name as driver_name. This results in the creation of: /sys/class/reboot-mode//reboot_modes This read-only sysfs file will exposes the list of supported reboot modes arguments provided by the driver, enabling userspace to query the list of arguments. Align the clean up path to maintain backward compatibility for existing reboot-mode based drivers. Link: https://lore.kernel.org/r/20250922-arm-psci-system_reset2-vendor-reboots-v15-5-7ce3a08878f1@oss.qualcomm.com Signed-off-by: Shivendra Pratap --- drivers/power/reset/reboot-mode.c | 127 ++++++++++++++++++++++++------ include/linux/reboot-mode.h | 2 + 2 files changed, 103 insertions(+), 26 deletions(-) diff --git a/drivers/power/reset/reboot-mode.c b/drivers/power/reset/reboot-mode.c index 79763a839c9b0..1e78eb3d0fe51 100644 --- a/drivers/power/reset/reboot-mode.c +++ b/drivers/power/reset/reboot-mode.c @@ -6,6 +6,7 @@ #define pr_fmt(fmt) "reboot-mode: " fmt #include +#include #include #include #include @@ -23,6 +24,8 @@ struct mode_info { struct list_head list; }; +static struct class *rb_class; + static u64 get_reboot_mode_magic(struct reboot_mode_driver *reboot, const char *cmd) { const char *normal = "normal"; @@ -69,6 +72,89 @@ static int reboot_mode_notify(struct notifier_block *this, return NOTIFY_DONE; } +static void release_reboot_mode_device(struct device *dev, void *res); + +static ssize_t reboot_modes_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct reboot_mode_driver **devres_reboot; + struct reboot_mode_driver *reboot; + struct mode_info *info; + ssize_t size = 0; + + devres_reboot = devres_find(dev, release_reboot_mode_device, NULL, NULL); + if (!devres_reboot || !(*devres_reboot)) + return -ENODATA; + + reboot = *devres_reboot; + scoped_guard(mutex, &reboot->rb_lock) { + list_for_each_entry(info, &reboot->head, list) + size += sysfs_emit_at(buf, size, "%s ", info->mode); + } + + if (size) { + size += sysfs_emit_at(buf, size - 1, "\n"); + return size; + } + + return -ENODATA; +} +static DEVICE_ATTR_RO(reboot_modes); + +static void release_reboot_mode_device(struct device *dev, void *res) +{ + struct reboot_mode_driver *reboot = *(struct reboot_mode_driver **)res; + struct mode_info *info; + struct mode_info *next; + + unregister_reboot_notifier(&reboot->reboot_notifier); + + scoped_guard(mutex, &reboot->rb_lock) { + list_for_each_entry_safe(info, next, &reboot->head, list) { + list_del(&info->list); + kfree_const(info->mode); + kfree(info); + } + } + + device_remove_file(reboot->reboot_dev, &dev_attr_reboot_modes); +} + +static int create_reboot_mode_device(struct reboot_mode_driver *reboot) +{ + struct reboot_mode_driver **dr; + int ret = 0; + + if (!rb_class) { + rb_class = class_create("reboot-mode"); + if (IS_ERR(rb_class)) + return PTR_ERR(rb_class); + } + + reboot->reboot_dev = device_create(rb_class, NULL, 0, NULL, reboot->driver_name); + if (IS_ERR(reboot->reboot_dev)) + return PTR_ERR(reboot->reboot_dev); + + ret = device_create_file(reboot->reboot_dev, &dev_attr_reboot_modes); + if (ret) + goto create_file_err; + + dr = devres_alloc(release_reboot_mode_device, sizeof(*dr), GFP_KERNEL); + if (!dr) { + ret = -ENOMEM; + goto devres_alloc_error; + } + + *dr = reboot; + devres_add(reboot->reboot_dev, dr); + return ret; + +devres_alloc_error: + device_remove_file(reboot->reboot_dev, &dev_attr_reboot_modes); +create_file_err: + device_unregister(reboot->reboot_dev); + return ret; +} + /** * reboot_mode_register - register a reboot mode driver * @reboot: reboot mode driver @@ -79,7 +165,6 @@ static int reboot_mode_notify(struct notifier_block *this, int reboot_mode_register(struct reboot_mode_driver *reboot, struct fwnode_handle *fwnode) { struct mode_info *info; - struct mode_info *next; struct device_node *np; struct property *prop; size_t len = strlen(PREFIX); @@ -87,13 +172,17 @@ int reboot_mode_register(struct reboot_mode_driver *reboot, struct fwnode_handle u32 magic_arg2; int ret; - if (!fwnode) + if (!fwnode || !reboot->driver_name) return -EINVAL; np = to_of_node(fwnode); if (!np) return -EINVAL; + ret = create_reboot_mode_device(reboot); + if (ret) + return ret; + INIT_LIST_HEAD(&reboot->head); mutex_init(&reboot->rb_lock); @@ -136,20 +225,15 @@ int reboot_mode_register(struct reboot_mode_driver *reboot, struct fwnode_handle list_add_tail(&info->list, &reboot->head); } + } - reboot->reboot_notifier.notifier_call = reboot_mode_notify; - register_reboot_notifier(&reboot->reboot_notifier); + reboot->reboot_notifier.notifier_call = reboot_mode_notify; + register_reboot_notifier(&reboot->reboot_notifier); - return 0; + return 0; error: - list_for_each_entry_safe(info, next, &reboot->head, list) { - list_del(&info->list); - kfree_const(info->mode); - kfree(info); - } - } - + device_unregister(reboot->reboot_dev); return ret; } EXPORT_SYMBOL_GPL(reboot_mode_register); @@ -160,26 +244,16 @@ EXPORT_SYMBOL_GPL(reboot_mode_register); */ int reboot_mode_unregister(struct reboot_mode_driver *reboot) { - struct mode_info *info; - struct mode_info *next; - - unregister_reboot_notifier(&reboot->reboot_notifier); - - scoped_guard(mutex, &reboot->rb_lock) { - list_for_each_entry_safe(info, next, &reboot->head, list) { - list_del(&info->list); - kfree_const(info->mode); - kfree(info); - } - } - + device_unregister(reboot->reboot_dev); return 0; } EXPORT_SYMBOL_GPL(reboot_mode_unregister); static void devm_reboot_mode_release(struct device *dev, void *res) { - reboot_mode_unregister(*(struct reboot_mode_driver **)res); + struct reboot_mode_driver *reboot = *(struct reboot_mode_driver **)res; + + device_unregister(reboot->reboot_dev); } /** @@ -202,6 +276,7 @@ int devm_reboot_mode_register(struct device *dev, if (!dr) return -ENOMEM; + reboot->driver_name = reboot->dev->driver->name; rc = reboot_mode_register(reboot, of_fwnode_handle(reboot->dev->of_node)); if (rc) { devres_free(dr); diff --git a/include/linux/reboot-mode.h b/include/linux/reboot-mode.h index 3a14df2ddd1db..c68a671f6947f 100644 --- a/include/linux/reboot-mode.h +++ b/include/linux/reboot-mode.h @@ -8,6 +8,8 @@ struct reboot_mode_driver { struct device *dev; + struct device *reboot_dev; + const char *driver_name; struct list_head head; int (*write)(struct reboot_mode_driver *reboot, u64 magic); struct notifier_block reboot_notifier; From d32f982db311e3ac9042f356edac71c0bdffbdaf Mon Sep 17 00:00:00 2001 From: Shivendra Pratap Date: Mon, 22 Sep 2025 19:10:17 +0530 Subject: [PATCH 0100/2333] FROMLIST: firmware: psci: Implement vendor-specific resets as reboot-mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SoC vendors have different types of resets which are controlled through various hardware registers. For instance, Qualcomm SoC may have a requirement that reboot with “bootloader” command should reboot the device to bootloader flashing mode and reboot with “edl” should reboot the device into Emergency flashing mode. Setting up such reboots on Qualcomm devices can be inconsistent across SoC platforms and may require setting different HW registers, where some of these registers may not be accessible to HLOS. These knobs evolve over product generations and require more drivers. PSCI spec defines, SYSTEM_RESET2, vendor-specific reset which can help align this requirement. Add support for PSCI SYSTEM_RESET2, vendor-specific resets and align the implementation to allow user-space initiated reboots to trigger these resets. Implement the PSCI vendor-specific resets by registering to the reboot-mode framework. As psci init is done at early kernel init, reboot-mode registration cannot be done at the time of psci init. This is because reboot-mode creates a “reboot-mode” class for exposing sysfs, which can fail at early kernel init. To overcome this, introduce a late_initcall to register PSCI vendor-specific resets as reboot modes. Implement a reboot-mode write function that sets reset_type and cookie values during the reboot notifier callback. Introduce a firmware-based call for SYSTEM_RESET2 vendor-specific reset in the psci_sys_reset path, using reset_type and cookie if supported by secure firmware. Register a panic notifier and clear vendor_reset valid status during panic. This is needed for any kernel panic that occurs post reboot_notifiers. By using the above implementation, userspace will be able to issue such resets using the reboot() system call with the "*arg" parameter as a string based command. The commands can be defined in PSCI device tree node under “reboot-mode” and are based on the reboot-mode based commands. Link: https://lore.kernel.org/r/20250922-arm-psci-system_reset2-vendor-reboots-v15-7-7ce3a08878f1@oss.qualcomm.com Signed-off-by: Shivendra Pratap Reviewed-by: Kathiravan Thirumoorthy --- drivers/firmware/psci/Kconfig | 2 + drivers/firmware/psci/psci.c | 89 ++++++++++++++++++++++++++++++++++- 2 files changed, 90 insertions(+), 1 deletion(-) diff --git a/drivers/firmware/psci/Kconfig b/drivers/firmware/psci/Kconfig index 97944168b5e66..93ff7b071a0c3 100644 --- a/drivers/firmware/psci/Kconfig +++ b/drivers/firmware/psci/Kconfig @@ -1,6 +1,8 @@ # SPDX-License-Identifier: GPL-2.0-only config ARM_PSCI_FW bool + select POWER_RESET + select REBOOT_MODE config ARM_PSCI_CHECKER bool "ARM PSCI checker" diff --git a/drivers/firmware/psci/psci.c b/drivers/firmware/psci/psci.c index 38ca190d4a22d..40a27bc2cc3a3 100644 --- a/drivers/firmware/psci/psci.c +++ b/drivers/firmware/psci/psci.c @@ -13,10 +13,12 @@ #include #include #include +#include #include #include #include #include +#include #include #include @@ -51,6 +53,24 @@ static int resident_cpu = -1; struct psci_operations psci_ops; static enum arm_smccc_conduit psci_conduit = SMCCC_CONDUIT_NONE; +struct psci_vendor_sysreset2 { + u32 reset_type; + u32 cookie; + bool valid; +}; + +static struct psci_vendor_sysreset2 vendor_reset; + +static int psci_panic_event(struct notifier_block *nb, unsigned long v, void *p) +{ + vendor_reset.valid = false; + return NOTIFY_DONE; +} + +static struct notifier_block psci_panic_block = { + .notifier_call = psci_panic_event +}; + bool psci_tos_resident_on(int cpu) { return cpu == resident_cpu; @@ -309,7 +329,10 @@ static int get_set_conduit_method(const struct device_node *np) static int psci_sys_reset(struct notifier_block *nb, unsigned long action, void *data) { - if ((reboot_mode == REBOOT_WARM || reboot_mode == REBOOT_SOFT) && + if (vendor_reset.valid && psci_system_reset2_supported) { + invoke_psci_fn(PSCI_FN_NATIVE(1_1, SYSTEM_RESET2), vendor_reset.reset_type, + vendor_reset.cookie, 0); + } else if ((reboot_mode == REBOOT_WARM || reboot_mode == REBOOT_SOFT) && psci_system_reset2_supported) { /* * reset_type[31] = 0 (architectural) @@ -547,6 +570,70 @@ static const struct platform_suspend_ops psci_suspend_ops = { .enter = psci_system_suspend_enter, }; +static int psci_set_vendor_sys_reset2(struct reboot_mode_driver *reboot, u64 magic) +{ + u32 magic_32; + + if (psci_system_reset2_supported) { + magic_32 = magic & 0xffffffff; + vendor_reset.reset_type = PSCI_1_1_RESET_TYPE_VENDOR_START | magic_32; + vendor_reset.cookie = (magic >> 32) & 0xffffffff; + vendor_reset.valid = true; + } + + return NOTIFY_DONE; +} + +static int __init psci_init_vendor_reset(void) +{ + struct reboot_mode_driver *reboot; + struct device_node *psci_np; + struct device_node *np; + int ret; + + if (!psci_system_reset2_supported) + return -EINVAL; + + psci_np = of_find_compatible_node(NULL, NULL, "arm,psci-1.0"); + if (!psci_np) + return -ENODEV; + + np = of_find_node_by_name(psci_np, "reboot-mode"); + if (!np) { + of_node_put(psci_np); + return -ENODEV; + } + + ret = atomic_notifier_chain_register(&panic_notifier_list, &psci_panic_block); + if (ret) + goto err_notifier; + + reboot = kzalloc(sizeof(*reboot), GFP_KERNEL); + if (!reboot) { + ret = -ENOMEM; + goto err_kzalloc; + } + + reboot->write = psci_set_vendor_sys_reset2; + reboot->driver_name = "psci"; + + ret = reboot_mode_register(reboot, of_fwnode_handle(np)); + if (ret) + goto err_register; + + return 0; + +err_register: + kfree(reboot); +err_kzalloc: + atomic_notifier_chain_unregister(&panic_notifier_list, &psci_panic_block); +err_notifier: + of_node_put(psci_np); + of_node_put(np); + return ret; +} +late_initcall(psci_init_vendor_reset) + static void __init psci_init_system_reset2(void) { int ret; From 9fe45cfe84f7873accec2689b312180897cb56d0 Mon Sep 17 00:00:00 2001 From: Jingyi Wang Date: Tue, 21 Oct 2025 23:00:26 -0700 Subject: [PATCH 0101/2333] FROMLIST: dt-bindings: qcom,pdc: document Kaanapali Power Domain Controller Add a compatible for the Power Domain Controller on Kaanapali platforms. Signed-off-by: Jingyi Wang Reviewed-by: Krzysztof Kozlowski Signed-off-by: Yijie Yang Link: https://lore.kernel.org/all/20251021-knp-pdc-v2-1-a38767f5bb8e@oss.qualcomm.com/ --- .../devicetree/bindings/interrupt-controller/qcom,pdc.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/interrupt-controller/qcom,pdc.yaml b/Documentation/devicetree/bindings/interrupt-controller/qcom,pdc.yaml index 38d0c2d57dd6d..b26246de31862 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/qcom,pdc.yaml +++ b/Documentation/devicetree/bindings/interrupt-controller/qcom,pdc.yaml @@ -27,6 +27,7 @@ properties: items: - enum: - qcom,glymur-pdc + - qcom,kaanapali-pdc - qcom,qcs615-pdc - qcom,qcs8300-pdc - qcom,qdu1000-pdc From 2d881b7a158d67e98f2d05745cdc6bf3ec6922c4 Mon Sep 17 00:00:00 2001 From: Jishnu Prakash Date: Wed, 24 Sep 2025 16:17:06 -0700 Subject: [PATCH 0102/2333] FROMGIT: dt-bindings: power: qcom,rpmpd: document the Kaanapali RPMh Power Domains Document the RPMh Power Domains on the Kaanapali Platform. Signed-off-by: Jishnu Prakash Signed-off-by: Jingyi Wang Signed-off-by: Yijie Yang Link: https://lore.kernel.org/all/20250924-knp-pd-v1-1-b78444125c91@oss.qualcomm.com/ --- Documentation/devicetree/bindings/power/qcom,rpmpd.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/power/qcom,rpmpd.yaml b/Documentation/devicetree/bindings/power/qcom,rpmpd.yaml index af5fef872529b..27af5b8aa1340 100644 --- a/Documentation/devicetree/bindings/power/qcom,rpmpd.yaml +++ b/Documentation/devicetree/bindings/power/qcom,rpmpd.yaml @@ -18,6 +18,7 @@ properties: oneOf: - enum: - qcom,glymur-rpmhpd + - qcom,kaanapali-rpmhpd - qcom,mdm9607-rpmpd - qcom,milos-rpmhpd - qcom,msm8226-rpmpd From d74d8b20abf33003c9b8f647dd11ddf08cf07c34 Mon Sep 17 00:00:00 2001 From: Jishnu Prakash Date: Wed, 24 Sep 2025 16:17:07 -0700 Subject: [PATCH 0103/2333] FROMGIT: dt-bindings: power: qcom,rpmpd: add new RPMH levels Add constants for voltage levels: LOW_SVS_D2_1, LOW_SVS_D1_1 and LOW_SVS_L0. Signed-off-by: Jishnu Prakash Signed-off-by: Jingyi Wang Signed-off-by: Yijie Yang Link: https://lore.kernel.org/all/20250924-knp-pd-v1-2-b78444125c91@oss.qualcomm.com/ --- include/dt-bindings/power/qcom,rpmhpd.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/dt-bindings/power/qcom,rpmhpd.h b/include/dt-bindings/power/qcom,rpmhpd.h index 73cceb88953f7..50e7c886709d0 100644 --- a/include/dt-bindings/power/qcom,rpmhpd.h +++ b/include/dt-bindings/power/qcom,rpmhpd.h @@ -33,11 +33,14 @@ #define RPMH_REGULATOR_LEVEL_RETENTION 16 #define RPMH_REGULATOR_LEVEL_MIN_SVS 48 #define RPMH_REGULATOR_LEVEL_LOW_SVS_D3 50 +#define RPMH_REGULATOR_LEVEL_LOW_SVS_D2_1 51 #define RPMH_REGULATOR_LEVEL_LOW_SVS_D2 52 +#define RPMH_REGULATOR_LEVEL_LOW_SVS_D1_1 54 #define RPMH_REGULATOR_LEVEL_LOW_SVS_D1 56 #define RPMH_REGULATOR_LEVEL_LOW_SVS_D0 60 #define RPMH_REGULATOR_LEVEL_LOW_SVS 64 #define RPMH_REGULATOR_LEVEL_LOW_SVS_P1 72 +#define RPMH_REGULATOR_LEVEL_LOW_SVS_L0 76 #define RPMH_REGULATOR_LEVEL_LOW_SVS_L1 80 #define RPMH_REGULATOR_LEVEL_LOW_SVS_L2 96 #define RPMH_REGULATOR_LEVEL_SVS 128 From c2e58ee4e1ed72c4fe6fb6a48d8d83d4ea2269fc Mon Sep 17 00:00:00 2001 From: Jishnu Prakash Date: Wed, 24 Sep 2025 16:17:08 -0700 Subject: [PATCH 0104/2333] FROMGIT: pmdomain: qcom: rpmhpd: Add RPMh power domain support for Kaanapali Add the RPMh power domains present in Kaanapali SoCs. Also increase the maximum allowed number of levels for ARC resources from 16 to 32, as needed starting on the Kaanapali SoC where the ARC vote registers have been expanded from 4 to 5 bits. Signed-off-by: Jishnu Prakash Signed-off-by: Jingyi Wang Reviewed-by: Konrad Dybcio Reviewed-by: Dmitry Baryshkov Signed-off-by: Yijie Yang Link: https://lore.kernel.org/all/20250924-knp-pd-v1-3-b78444125c91@oss.qualcomm.com/ --- drivers/pmdomain/qcom/rpmhpd.c | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/drivers/pmdomain/qcom/rpmhpd.c b/drivers/pmdomain/qcom/rpmhpd.c index 4faa8a2561862..a8b37037c6fea 100644 --- a/drivers/pmdomain/qcom/rpmhpd.c +++ b/drivers/pmdomain/qcom/rpmhpd.c @@ -19,7 +19,7 @@ #define domain_to_rpmhpd(domain) container_of(domain, struct rpmhpd, pd) -#define RPMH_ARC_MAX_LEVELS 16 +#define RPMH_ARC_MAX_LEVELS 32 /** * struct rpmhpd - top level RPMh power domain resource data structure @@ -595,6 +595,31 @@ static const struct rpmhpd_desc sm8750_desc = { .num_pds = ARRAY_SIZE(sm8750_rpmhpds), }; +/* KAANAPALI RPMH powerdomains */ +static struct rpmhpd *kaanapali_rpmhpds[] = { + [RPMHPD_CX] = &cx, + [RPMHPD_CX_AO] = &cx_ao, + [RPMHPD_EBI] = &ebi, + [RPMHPD_GFX] = &gfx, + [RPMHPD_GMXC] = &gmxc, + [RPMHPD_LCX] = &lcx, + [RPMHPD_LMX] = &lmx, + [RPMHPD_MX] = &mx, + [RPMHPD_MX_AO] = &mx_ao, + [RPMHPD_MMCX] = &mmcx, + [RPMHPD_MMCX_AO] = &mmcx_ao, + [RPMHPD_MSS] = &mss, + [RPMHPD_MXC] = &mxc, + [RPMHPD_MXC_AO] = &mxc_ao, + [RPMHPD_NSP] = &nsp, + [RPMHPD_NSP2] = &nsp2, +}; + +static const struct rpmhpd_desc kaanapali_desc = { + .rpmhpds = kaanapali_rpmhpds, + .num_pds = ARRAY_SIZE(kaanapali_rpmhpds), +}; + /* QDU1000/QRU1000 RPMH powerdomains */ static struct rpmhpd *qdu1000_rpmhpds[] = { [QDU1000_CX] = &cx, @@ -767,6 +792,7 @@ static const struct rpmhpd_desc qcs615_desc = { static const struct of_device_id rpmhpd_match_table[] = { { .compatible = "qcom,glymur-rpmhpd", .data = &glymur_desc }, + { .compatible = "qcom,kaanapali-rpmhpd", .data = &kaanapali_desc }, { .compatible = "qcom,milos-rpmhpd", .data = &milos_desc }, { .compatible = "qcom,qcs615-rpmhpd", .data = &qcs615_desc }, { .compatible = "qcom,qcs8300-rpmhpd", .data = &qcs8300_desc }, From 52884dc4b5b9a2b896f08f4b6c54efbe8316653f Mon Sep 17 00:00:00 2001 From: Nitin Rawat Date: Wed, 24 Sep 2025 16:29:00 -0700 Subject: [PATCH 0105/2333] FROMLIST: dt-bindings: ufs: qcom: Document the Kaanapali UFS controller Document the UFS Controller on the Kaanapali Platform. Signed-off-by: Nitin Rawat Signed-off-by: Jingyi Wang Signed-off-by: Yijie Yang Link: https://lore.kernel.org/all/20250924-knp-ufs-v1-1-42e0955a1f7c@oss.qualcomm.com/ --- Documentation/devicetree/bindings/ufs/qcom,sm8650-ufshc.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/ufs/qcom,sm8650-ufshc.yaml b/Documentation/devicetree/bindings/ufs/qcom,sm8650-ufshc.yaml index aaa0bbb5bfe16..cea84ab2204f4 100644 --- a/Documentation/devicetree/bindings/ufs/qcom,sm8650-ufshc.yaml +++ b/Documentation/devicetree/bindings/ufs/qcom,sm8650-ufshc.yaml @@ -15,6 +15,7 @@ select: compatible: contains: enum: + - qcom,kaanapali-ufshc - qcom,sm8650-ufshc - qcom,sm8750-ufshc required: @@ -24,6 +25,7 @@ properties: compatible: items: - enum: + - qcom,kaanapali-ufshc - qcom,sm8650-ufshc - qcom,sm8750-ufshc - const: qcom,ufshc From d014dd667acd564c6f2a403d7465999bc679be37 Mon Sep 17 00:00:00 2001 From: Jingyi Wang Date: Wed, 24 Sep 2025 16:29:01 -0700 Subject: [PATCH 0106/2333] FROMLIST: dt-bindings: phy: Add QMP UFS PHY compatible for Kaanapali Document the QMP UFS PHY compatible for Qualcomm Kaanapali to support physical layer functionality for UFS found on the SoC. Use fallback to indicate the compatibility of the QMP UFS PHY on the Kaanapali with that on the SM8750. Signed-off-by: Jingyi Wang Acked-by: Konrad Dybcio Signed-off-by: Yijie Yang Link: https://lore.kernel.org/all/20250924-knp-ufs-v1-2-42e0955a1f7c@oss.qualcomm.com/ --- .../devicetree/bindings/phy/qcom,sc8280xp-qmp-ufs-phy.yaml | 4 ++++ 1 file changed, 4 insertions(+) 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 a58370a6a5d38..fba7b2549ddee 100644 --- a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-ufs-phy.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-ufs-phy.yaml @@ -24,6 +24,10 @@ properties: - enum: - qcom,qcs8300-qmp-ufs-phy - const: qcom,sa8775p-qmp-ufs-phy + - items: + - enum: + - qcom,kaanapali-qmp-ufs-phy + - const: qcom,sm8750-qmp-ufs-phy - enum: - qcom,msm8996-qmp-ufs-phy - qcom,msm8998-qmp-ufs-phy From 029a799fee1a3fcad683f1c186fa3eceeef33b1e Mon Sep 17 00:00:00 2001 From: Manish Pandey Date: Wed, 24 Sep 2025 16:34:08 -0700 Subject: [PATCH 0107/2333] FROMGIT: dt-bindings: mmc: sdhci-msm: Add Kaanapali compatible Document the compatible string for the SDHCI controller on the Kaanapali platform. Signed-off-by: Manish Pandey Signed-off-by: Jingyi Wang Reviewed-by: Krzysztof Kozlowski Signed-off-by: Ulf Hansson Link: https://lore.kernel.org/all/20250924-knp-sdcard-v1-1-fc54940066f1@oss.qualcomm.com/ Signed-off-by: Yijie Yang --- Documentation/devicetree/bindings/mmc/sdhci-msm.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/mmc/sdhci-msm.yaml b/Documentation/devicetree/bindings/mmc/sdhci-msm.yaml index 594bd174ff211..474afc98c8f64 100644 --- a/Documentation/devicetree/bindings/mmc/sdhci-msm.yaml +++ b/Documentation/devicetree/bindings/mmc/sdhci-msm.yaml @@ -42,6 +42,7 @@ properties: - qcom,ipq5424-sdhci - qcom,ipq6018-sdhci - qcom,ipq9574-sdhci + - qcom,kaanapali-sdhci - qcom,milos-sdhci - qcom,qcm2290-sdhci - qcom,qcs404-sdhci From fc1b59c1f4305fd3630a4205d2db8f680626ef5c Mon Sep 17 00:00:00 2001 From: Jingyi Wang Date: Tue, 21 Oct 2025 23:15:54 -0700 Subject: [PATCH 0108/2333] FROMLIST: dt-bindings: arm-smmu: Add compatible for Kaanapali and Glymur SoCs Qualcomm Kaanapali and Glymur SoCs include apps smmu that implements arm,mmu-500, which is used to translate device-visible virtual addresses to physical addresses. Add compatible for these items. Co-developed-by: Pankaj Patil Signed-off-by: Pankaj Patil Signed-off-by: Jingyi Wang Reviewed-by: Krzysztof Kozlowski Signed-off-by: Yijie Yang Link: https://lore.kernel.org/all/20251021-b4-knp-smmu-v2-1-88774e6d2def@oss.qualcomm.com/ --- Documentation/devicetree/bindings/iommu/arm,smmu.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu.yaml b/Documentation/devicetree/bindings/iommu/arm,smmu.yaml index 89495f094d52b..2ffc48a276dfb 100644 --- a/Documentation/devicetree/bindings/iommu/arm,smmu.yaml +++ b/Documentation/devicetree/bindings/iommu/arm,smmu.yaml @@ -35,6 +35,8 @@ properties: - description: Qcom SoCs implementing "qcom,smmu-500" and "arm,mmu-500" items: - enum: + - qcom,glymur-smmu-500 + - qcom,kaanapali-smmu-500 - qcom,milos-smmu-500 - qcom,qcm2290-smmu-500 - qcom,qcs615-smmu-500 From 4cec0342668634b5f5d9ef1720d2852bd61a2955 Mon Sep 17 00:00:00 2001 From: Ziyue Zhang Date: Fri, 24 Oct 2025 17:56:05 +0800 Subject: [PATCH 0109/2333] FROMLIST: dt-bindings: phy: qcom,sc8280xp-qmp-pcie-phy: Update pcie phy bindings for qcs8300 The gcc_aux_clk is not required by the PCIe PHY on qcs8300 and is not specified in the device tree node. Hence, move the qcs8300 phy compatibility entry into the list of PHYs that require six clocks. Removed the phy_aux clock from the PCIe PHY binding as it is no longer used by any instance. Link: https://lore.kernel.org/all/20251024095609.48096-2-ziyue.zhang@oss.qualcomm.com/ Fixes: e46e59b77a9e ("dt-bindings: phy: qcom,sc8280xp-qmp-pcie-phy: Document the QCS8300 QMP PCIe PHY Gen4 x2") Signed-off-by: Ziyue Zhang Acked-by: Rob Herring (Arm) Reviewed-by: Johan Hovold --- .../phy/qcom,sc8280xp-qmp-pcie-phy.yaml | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-pcie-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-pcie-phy.yaml index 119b4ff36dbd6..d94d08752cec6 100644 --- a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-pcie-phy.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-pcie-phy.yaml @@ -55,7 +55,7 @@ properties: clocks: minItems: 5 - maxItems: 7 + maxItems: 6 clock-names: minItems: 5 @@ -66,7 +66,6 @@ properties: - enum: [rchng, refgen] - const: pipe - const: pipediv2 - - const: phy_aux power-domains: maxItems: 1 @@ -178,6 +177,7 @@ allOf: compatible: contains: enum: + - qcom,qcs8300-qmp-gen4x2-pcie-phy - qcom,sa8775p-qmp-gen4x2-pcie-phy - qcom,sa8775p-qmp-gen4x4-pcie-phy - qcom,sc8280xp-qmp-gen3x1-pcie-phy @@ -195,19 +195,6 @@ allOf: clock-names: minItems: 6 - - if: - properties: - compatible: - contains: - enum: - - qcom,qcs8300-qmp-gen4x2-pcie-phy - then: - properties: - clocks: - minItems: 7 - clock-names: - minItems: 7 - - if: properties: compatible: From f52cd30df92c55cc2bd9b0bf4617a862eb4fb2f1 Mon Sep 17 00:00:00 2001 From: Jie Gan Date: Mon, 13 Oct 2025 13:49:10 +0800 Subject: [PATCH 0110/2333] FROMLIST: coresight: core: Refactoring ctcu_get_active_port and make it generic Remove ctcu_get_active_port from CTCU module and add it to the core framework. The port number is crucial for the CTCU device to identify which ETR it serves. With the port number we can correctly get required parameters of the CTCU device in TMC module. Link: https://lore.kernel.org/all/20251013-enable-byte-cntr-for-ctcu-v7-1-e1e8f41e15dd@oss.qualcomm.com/ Reviewed-by: Mike Leach Signed-off-by: Jie Gan --- drivers/hwtracing/coresight/coresight-core.c | 24 +++++++++++++++++++ .../hwtracing/coresight/coresight-ctcu-core.c | 19 +-------------- drivers/hwtracing/coresight/coresight-priv.h | 2 ++ 3 files changed, 27 insertions(+), 18 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c index 2e62005655dbc..d6ee71424e82c 100644 --- a/drivers/hwtracing/coresight/coresight-core.c +++ b/drivers/hwtracing/coresight/coresight-core.c @@ -582,6 +582,30 @@ struct coresight_device *coresight_get_sink(struct coresight_path *path) } EXPORT_SYMBOL_GPL(coresight_get_sink); +/** + * coresight_get_in_port_dest: get the in-port number of the dest device + * that is connected to the src device. + * + * @src: csdev of the source device. + * @dest: csdev of the destination device. + * + * Return: port number upon success or -EINVAL for fail. + */ +int coresight_get_in_port_dest(struct coresight_device *src, + struct coresight_device *dest) +{ + struct coresight_platform_data *pdata = dest->pdata; + int i; + + for (i = 0; i < pdata->nr_inconns; ++i) { + if (pdata->in_conns[i]->src_dev == src) + return pdata->in_conns[i]->dest_port; + } + + return -EINVAL; +} +EXPORT_SYMBOL_GPL(coresight_get_in_port_dest); + u32 coresight_get_sink_id(struct coresight_device *csdev) { if (!csdev->ea) diff --git a/drivers/hwtracing/coresight/coresight-ctcu-core.c b/drivers/hwtracing/coresight/coresight-ctcu-core.c index c586495e9a088..a23ff6a6f83d6 100644 --- a/drivers/hwtracing/coresight/coresight-ctcu-core.c +++ b/drivers/hwtracing/coresight/coresight-ctcu-core.c @@ -118,23 +118,6 @@ static int __ctcu_set_etr_traceid(struct coresight_device *csdev, u8 traceid, in return 0; } -/* - * Searching the sink device from helper's view in case there are multiple helper devices - * connected to the sink device. - */ -static int ctcu_get_active_port(struct coresight_device *sink, struct coresight_device *helper) -{ - struct coresight_platform_data *pdata = helper->pdata; - int i; - - for (i = 0; i < pdata->nr_inconns; ++i) { - if (pdata->in_conns[i]->src_dev == sink) - return pdata->in_conns[i]->dest_port; - } - - return -EINVAL; -} - static int ctcu_set_etr_traceid(struct coresight_device *csdev, struct coresight_path *path, bool enable) { @@ -147,7 +130,7 @@ static int ctcu_set_etr_traceid(struct coresight_device *csdev, struct coresight return -EINVAL; } - port_num = ctcu_get_active_port(sink, csdev); + port_num = coresight_get_in_port_dest(sink, csdev); if (port_num < 0) return -EINVAL; diff --git a/drivers/hwtracing/coresight/coresight-priv.h b/drivers/hwtracing/coresight/coresight-priv.h index 33e22b1ba0432..e51b22b8ebde2 100644 --- a/drivers/hwtracing/coresight/coresight-priv.h +++ b/drivers/hwtracing/coresight/coresight-priv.h @@ -156,6 +156,8 @@ void coresight_remove_links(struct coresight_device *orig, u32 coresight_get_sink_id(struct coresight_device *csdev); void coresight_path_assign_trace_id(struct coresight_path *path, enum cs_mode mode); +int coresight_get_in_port_dest(struct coresight_device *src, + struct coresight_device *dest); #if IS_ENABLED(CONFIG_CORESIGHT_SOURCE_ETM3X) int etm_readl_cp14(u32 off, unsigned int *val); From 3ebcf6444a14da53c4ecb9039e1ee4e9349b3a0c Mon Sep 17 00:00:00 2001 From: Jie Gan Date: Mon, 13 Oct 2025 13:49:11 +0800 Subject: [PATCH 0111/2333] FROMLIST: coresight: core: add a new API to retrieve the helper device Retrieving the helper device of the specific coresight device based on its helper_subtype because a single coresight device may has multiple types of the helper devices. Link: https://lore.kernel.org/all/20251013-enable-byte-cntr-for-ctcu-v7-2-e1e8f41e15dd@oss.qualcomm.com/ Reviewed-by: Mike Leach Signed-off-by: Jie Gan --- drivers/hwtracing/coresight/coresight-core.c | 35 ++++++++++++++++++++ drivers/hwtracing/coresight/coresight-priv.h | 2 ++ 2 files changed, 37 insertions(+) diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c index d6ee71424e82c..7db1801d74320 100644 --- a/drivers/hwtracing/coresight/coresight-core.c +++ b/drivers/hwtracing/coresight/coresight-core.c @@ -582,6 +582,41 @@ struct coresight_device *coresight_get_sink(struct coresight_path *path) } EXPORT_SYMBOL_GPL(coresight_get_sink); +/** + * coresight_get_helper: find the helper device of the assigned csdev. + * + * @csdev: The csdev the helper device is conntected to. + * @type: helper_subtype of the expected helper device. + * + * Retrieve the helper device for the specific csdev based on its + * helper_subtype. + * + * Return: the helper's csdev upon success or NULL for fail. + */ +struct coresight_device *coresight_get_helper(struct coresight_device *csdev, + int type) +{ + int i; + struct coresight_device *helper; + + /* protect the connections */ + mutex_lock(&coresight_mutex); + for (i = 0; i < csdev->pdata->nr_outconns; ++i) { + helper = csdev->pdata->out_conns[i]->dest_dev; + if (!helper || !coresight_is_helper(helper)) + continue; + + if (helper->subtype.helper_subtype == type) { + mutex_unlock(&coresight_mutex); + return helper; + } + } + mutex_unlock(&coresight_mutex); + + return NULL; +} +EXPORT_SYMBOL_GPL(coresight_get_helper); + /** * coresight_get_in_port_dest: get the in-port number of the dest device * that is connected to the src device. diff --git a/drivers/hwtracing/coresight/coresight-priv.h b/drivers/hwtracing/coresight/coresight-priv.h index e51b22b8ebde2..f80122827934d 100644 --- a/drivers/hwtracing/coresight/coresight-priv.h +++ b/drivers/hwtracing/coresight/coresight-priv.h @@ -158,6 +158,8 @@ void coresight_path_assign_trace_id(struct coresight_path *path, enum cs_mode mode); int coresight_get_in_port_dest(struct coresight_device *src, struct coresight_device *dest); +struct coresight_device *coresight_get_helper(struct coresight_device *csdev, + int type); #if IS_ENABLED(CONFIG_CORESIGHT_SOURCE_ETM3X) int etm_readl_cp14(u32 off, unsigned int *val); From 76dc5da5613225dfa9a65f2b74e8d5875b4f97b5 Mon Sep 17 00:00:00 2001 From: Jie Gan Date: Mon, 13 Oct 2025 13:49:12 +0800 Subject: [PATCH 0112/2333] FROMLIST: coresight: tmc: add etr_buf_list to store allocated etr_buf Add a list to store allocated etr_buf. The byte-cntr functionality requires two etr_buf to receive trace data. The active etr_buf collects the trace data from source device, while the byte-cntr reading function accesses the deactivated etr_buf after is has been filled and synced, transferring data to the userspace. Link: https://lore.kernel.org/all/20251013-enable-byte-cntr-for-ctcu-v7-3-e1e8f41e15dd@oss.qualcomm.com/ Signed-off-by: Jie Gan --- .../hwtracing/coresight/coresight-tmc-core.c | 1 + drivers/hwtracing/coresight/coresight-tmc.h | 17 +++++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/drivers/hwtracing/coresight/coresight-tmc-core.c b/drivers/hwtracing/coresight/coresight-tmc-core.c index 7274ad07c2b20..4fb94a09d5355 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-core.c +++ b/drivers/hwtracing/coresight/coresight-tmc-core.c @@ -911,6 +911,7 @@ static int tmc_add_coresight_dev(struct device *dev) idr_init(&drvdata->idr); mutex_init(&drvdata->idr_mutex); dev_list = &etr_devs; + INIT_LIST_HEAD(&drvdata->etr_buf_list); break; case TMC_CONFIG_TYPE_ETF: desc.groups = coresight_etf_groups; diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h index 29ccf0b7f4fe9..5ea53d044d837 100644 --- a/drivers/hwtracing/coresight/coresight-tmc.h +++ b/drivers/hwtracing/coresight/coresight-tmc.h @@ -208,6 +208,19 @@ struct tmc_resrv_buf { s64 len; }; +/** + * @sysfs_buf: Allocated sysfs_buf. + * @is_free: Indicates whether the buffer is free to choose. + * @pos: Position of the buffer. + * @node: Node in etr_buf_list. + */ +struct etr_buf_node { + struct etr_buf *sysfs_buf; + bool is_free; + loff_t pos; + struct list_head node; +}; + /** * struct tmc_drvdata - specifics associated to an TMC component * @atclk: optional clock for the core parts of the TMC. @@ -248,6 +261,8 @@ struct tmc_resrv_buf { * @desc_name: Name to be used while creating crash interface. * @dev: pointer to the device associated with this TMC. * @link: link to the delay_probed list. + * @etr_buf_list: List that is used to manage allocated etr_buf. + * @reading_node: Available buffer_node for byte-cntr reading. */ struct tmc_drvdata { struct clk *atclk; @@ -283,6 +298,8 @@ struct tmc_drvdata { const char *desc_name; struct device *dev; struct list_head link; + struct list_head etr_buf_list; + struct etr_buf_node *reading_node; }; struct etr_buf_operations { From 4617e2a268a263ecfb7d01ba1c015fd167e6a22b Mon Sep 17 00:00:00 2001 From: Jie Gan Date: Mon, 13 Oct 2025 13:49:13 +0800 Subject: [PATCH 0113/2333] FROMLIST: coresight: tmc: add create/clean functions for etr_buf_list Create and insert or remove the etr_buf_node to/from the etr_buf_list. Link: https://lore.kernel.org/all/20251013-enable-byte-cntr-for-ctcu-v7-4-e1e8f41e15dd@oss.qualcomm.com/ Signed-off-by: Jie Gan --- .../hwtracing/coresight/coresight-tmc-etr.c | 94 +++++++++++++++++++ drivers/hwtracing/coresight/coresight-tmc.h | 2 + 2 files changed, 96 insertions(+) diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c index b07fcdb3fe1a8..ed15991b32173 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c @@ -1909,6 +1909,100 @@ const struct coresight_ops tmc_etr_cs_ops = { .panic_ops = &tmc_etr_sync_ops, }; +/** + * tmc_clean_etr_buf_list - clean the etr_buf_list. + * @drvdata: driver data of the TMC device. + * + * Remove the allocated node from the list and free the extra buffer. + */ +void tmc_clean_etr_buf_list(struct tmc_drvdata *drvdata) +{ + struct etr_buf_node *nd, *next; + + list_for_each_entry_safe(nd, next, &drvdata->etr_buf_list, node) { + if (nd->sysfs_buf == drvdata->sysfs_buf) { + if (coresight_get_mode(drvdata->csdev) == CS_MODE_DISABLED) { + drvdata->sysfs_buf = NULL; + tmc_free_etr_buf(nd->sysfs_buf); + nd->sysfs_buf = NULL; + } + list_del(&nd->node); + kfree(nd); + } else { + /* Free allocated buffers which are not utilized by ETR */ + list_del(&nd->node); + tmc_free_etr_buf(nd->sysfs_buf); + nd->sysfs_buf = NULL; + kfree(nd); + } + } +} +EXPORT_SYMBOL_GPL(tmc_clean_etr_buf_list); + +/** + * tmc_create_etr_buf_list - create a list to manage the etr_buf_node. + * @drvdata: driver data of the TMC device. + * @num_nodes: number of nodes want to create with the list. + * + * Return 0 upon success and return the error number if fail. + */ +int tmc_create_etr_buf_list(struct tmc_drvdata *drvdata, int num_nodes) +{ + struct etr_buf_node *new_node; + struct etr_buf *sysfs_buf; + int i = 0, ret = 0; + + /* We dont need a list if there is only one node */ + if (num_nodes < 2) + return -EINVAL; + + /* We expect that sysfs_buf in drvdata has already been allocated. */ + if (drvdata->sysfs_buf) { + /* Directly insert the allocated sysfs_buf into the list first */ + new_node = kzalloc(sizeof(struct etr_buf_node), GFP_KERNEL); + if (IS_ERR(new_node)) + return PTR_ERR(new_node); + + new_node->sysfs_buf = drvdata->sysfs_buf; + new_node->is_free = false; + list_add(&new_node->node, &drvdata->etr_buf_list); + i++; + } + + while (i < num_nodes) { + new_node = kzalloc(sizeof(struct etr_buf_node), GFP_KERNEL); + if (IS_ERR(new_node)) { + ret = PTR_ERR(new_node); + break; + } + + sysfs_buf = tmc_alloc_etr_buf(drvdata, drvdata->size, 0, cpu_to_node(0), NULL); + if (IS_ERR(sysfs_buf)) { + kfree(new_node); + ret = PTR_ERR(new_node); + break; + } + + /* We dont have a available sysfs_buf in drvdata, setup one */ + if (!drvdata->sysfs_buf) { + drvdata->sysfs_buf = sysfs_buf; + new_node->is_free = false; + } else + new_node->is_free = true; + + new_node->sysfs_buf = sysfs_buf; + list_add(&new_node->node, &drvdata->etr_buf_list); + i++; + } + + /* Clean the list if there is an error */ + if (ret) + tmc_clean_etr_buf_list(drvdata); + + return ret; +} +EXPORT_SYMBOL_GPL(tmc_create_etr_buf_list); + int tmc_read_prepare_etr(struct tmc_drvdata *drvdata) { int ret = 0; diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h index 5ea53d044d837..8e0b14c9e1be3 100644 --- a/drivers/hwtracing/coresight/coresight-tmc.h +++ b/drivers/hwtracing/coresight/coresight-tmc.h @@ -471,5 +471,7 @@ void tmc_etr_remove_catu_ops(void); struct etr_buf *tmc_etr_get_buffer(struct coresight_device *csdev, enum cs_mode mode, void *data); extern const struct attribute_group coresight_etr_group; +void tmc_clean_etr_buf_list(struct tmc_drvdata *drvdata); +int tmc_create_etr_buf_list(struct tmc_drvdata *drvdata, int num_nodes); #endif From 083ec20ea7ac516de1e39618194221178038b9ae Mon Sep 17 00:00:00 2001 From: Jie Gan Date: Mon, 13 Oct 2025 13:49:14 +0800 Subject: [PATCH 0114/2333] FROMLIST: coresight: tmc: Introduce sysfs_read_ops to wrap sysfs read operations Introduce sysfs_read_ops as a wrapper, wrap sysfs read operations, for reading trace data from the TMC buffer. Link: https://lore.kernel.org/all/20251013-enable-byte-cntr-for-ctcu-v7-5-e1e8f41e15dd@oss.qualcomm.com/ Reviewed-by: Mike Leach Signed-off-by: Jie Gan --- .../hwtracing/coresight/coresight-tmc-core.c | 50 +++++++++---------- drivers/hwtracing/coresight/coresight-tmc.h | 17 +++++++ 2 files changed, 40 insertions(+), 27 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-tmc-core.c b/drivers/hwtracing/coresight/coresight-tmc-core.c index 4fb94a09d5355..78137dc5f8d8f 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-core.c +++ b/drivers/hwtracing/coresight/coresight-tmc-core.c @@ -236,17 +236,10 @@ static int tmc_read_prepare(struct tmc_drvdata *drvdata) { int ret = 0; - switch (drvdata->config_type) { - case TMC_CONFIG_TYPE_ETB: - case TMC_CONFIG_TYPE_ETF: - ret = tmc_read_prepare_etb(drvdata); - break; - case TMC_CONFIG_TYPE_ETR: - ret = tmc_read_prepare_etr(drvdata); - break; - default: + if (drvdata->sysfs_ops) + ret = drvdata->sysfs_ops->read_prepare(drvdata); + else ret = -EINVAL; - } if (!ret) dev_dbg(&drvdata->csdev->dev, "TMC read start\n"); @@ -258,17 +251,10 @@ static int tmc_read_unprepare(struct tmc_drvdata *drvdata) { int ret = 0; - switch (drvdata->config_type) { - case TMC_CONFIG_TYPE_ETB: - case TMC_CONFIG_TYPE_ETF: - ret = tmc_read_unprepare_etb(drvdata); - break; - case TMC_CONFIG_TYPE_ETR: - ret = tmc_read_unprepare_etr(drvdata); - break; - default: + if (drvdata->sysfs_ops) + ret = drvdata->sysfs_ops->read_unprepare(drvdata); + else ret = -EINVAL; - } if (!ret) dev_dbg(&drvdata->csdev->dev, "TMC read end\n"); @@ -295,13 +281,8 @@ static int tmc_open(struct inode *inode, struct file *file) static ssize_t tmc_get_sysfs_trace(struct tmc_drvdata *drvdata, loff_t pos, size_t len, char **bufpp) { - switch (drvdata->config_type) { - case TMC_CONFIG_TYPE_ETB: - case TMC_CONFIG_TYPE_ETF: - return tmc_etb_get_sysfs_trace(drvdata, pos, len, bufpp); - case TMC_CONFIG_TYPE_ETR: - return tmc_etr_get_sysfs_trace(drvdata, pos, len, bufpp); - } + if (drvdata->sysfs_ops) + return drvdata->sysfs_ops->get_trace_data(drvdata, pos, len, bufpp); return -EINVAL; } @@ -882,6 +863,18 @@ static void register_crash_dev_interface(struct tmc_drvdata *drvdata, "Valid crash tracedata found\n"); } +static const struct sysfs_read_ops tmc_etb_sysfs_read_ops = { + .read_prepare = tmc_read_prepare_etb, + .read_unprepare = tmc_read_unprepare_etb, + .get_trace_data = tmc_etb_get_sysfs_trace, +}; + +static const struct sysfs_read_ops tmc_etr_sysfs_read_ops = { + .read_prepare = tmc_read_prepare_etr, + .read_unprepare = tmc_read_unprepare_etr, + .get_trace_data = tmc_etr_get_sysfs_trace, +}; + static int tmc_add_coresight_dev(struct device *dev) { struct tmc_drvdata *drvdata = dev_get_drvdata(dev); @@ -899,6 +892,7 @@ static int tmc_add_coresight_dev(struct device *dev) desc.subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_BUFFER; desc.ops = &tmc_etb_cs_ops; dev_list = &etb_devs; + drvdata->sysfs_ops = &tmc_etb_sysfs_read_ops; break; case TMC_CONFIG_TYPE_ETR: desc.groups = coresight_etr_groups; @@ -912,6 +906,7 @@ static int tmc_add_coresight_dev(struct device *dev) mutex_init(&drvdata->idr_mutex); dev_list = &etr_devs; INIT_LIST_HEAD(&drvdata->etr_buf_list); + drvdata->sysfs_ops = &tmc_etr_sysfs_read_ops; break; case TMC_CONFIG_TYPE_ETF: desc.groups = coresight_etf_groups; @@ -920,6 +915,7 @@ static int tmc_add_coresight_dev(struct device *dev) desc.subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_FIFO; desc.ops = &tmc_etf_cs_ops; dev_list = &etf_devs; + drvdata->sysfs_ops = &tmc_etb_sysfs_read_ops; break; default: pr_err("%s: Unsupported TMC config\n", desc.name); diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h index 8e0b14c9e1be3..9a548e1a4d94b 100644 --- a/drivers/hwtracing/coresight/coresight-tmc.h +++ b/drivers/hwtracing/coresight/coresight-tmc.h @@ -221,6 +221,8 @@ struct etr_buf_node { struct list_head node; }; +struct sysfs_read_ops; + /** * struct tmc_drvdata - specifics associated to an TMC component * @atclk: optional clock for the core parts of the TMC. @@ -263,6 +265,7 @@ struct etr_buf_node { * @link: link to the delay_probed list. * @etr_buf_list: List that is used to manage allocated etr_buf. * @reading_node: Available buffer_node for byte-cntr reading. + * @sysfs_ops: Read operations for sysfs mode. */ struct tmc_drvdata { struct clk *atclk; @@ -300,6 +303,20 @@ struct tmc_drvdata { struct list_head link; struct list_head etr_buf_list; struct etr_buf_node *reading_node; + const struct sysfs_read_ops *sysfs_ops; +}; + +/** + * struct sysfs_read_ops - read operations for TMC and its helper devices + * @read_prepare: prepare operation. + * @read_unprepare: unprepare operation. + * @get_trace_data: read operation. + */ +struct sysfs_read_ops { + int (*read_prepare)(struct tmc_drvdata *drvdata); + int (*read_unprepare)(struct tmc_drvdata *drvdata); + ssize_t (*get_trace_data)(struct tmc_drvdata *drvdata, loff_t pos, + size_t len, char **bufpp); }; struct etr_buf_operations { From f91b1ff88bae1b61b7fd7de9ef03437f4d14d857 Mon Sep 17 00:00:00 2001 From: Jie Gan Date: Mon, 13 Oct 2025 13:49:15 +0800 Subject: [PATCH 0115/2333] FROMLIST: dt-bindings: arm: add an interrupt property for Coresight CTCU Add an interrupt property to CTCU device. The interrupt will be triggered when the data size in the ETR buffer exceeds the threshold of the BYTECNTRVAL register. Programming a threshold in the BYTECNTRVAL register of CTCU device will enable the interrupt. Link: https://lore.kernel.org/all/20251013-enable-byte-cntr-for-ctcu-v7-6-e1e8f41e15dd@oss.qualcomm.com/ Acked-by: Krzysztof Kozlowski Signed-off-by: Jie Gan --- .../bindings/arm/qcom,coresight-ctcu.yaml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/Documentation/devicetree/bindings/arm/qcom,coresight-ctcu.yaml b/Documentation/devicetree/bindings/arm/qcom,coresight-ctcu.yaml index c969c16c21ef7..02797e5f3b586 100644 --- a/Documentation/devicetree/bindings/arm/qcom,coresight-ctcu.yaml +++ b/Documentation/devicetree/bindings/arm/qcom,coresight-ctcu.yaml @@ -39,6 +39,16 @@ properties: items: - const: apb + interrupts: + items: + - description: Byte cntr interrupt for etr0 + - description: Byte cntr interrupt for etr1 + + interrupt-names: + items: + - const: etr0 + - const: etr1 + label: description: Description of a coresight device. @@ -60,6 +70,8 @@ additionalProperties: false examples: - | + #include + ctcu@1001000 { compatible = "qcom,sa8775p-ctcu"; reg = <0x1001000 0x1000>; @@ -67,6 +79,11 @@ examples: clocks = <&aoss_qmp>; clock-names = "apb"; + interrupts = , + ; + interrupt-names = "etr0", + "etr1"; + in-ports { #address-cells = <1>; #size-cells = <0>; From 068e79e6487b03904c18deb385ff51c672922e6b Mon Sep 17 00:00:00 2001 From: Jie Gan Date: Mon, 13 Oct 2025 13:49:16 +0800 Subject: [PATCH 0116/2333] FROMLIST: coresight: ctcu: enable byte-cntr for TMC ETR devices The byte-cntr function provided by the CTCU device is used to transfer data from the ETR buffer to the userspace. An interrupt is triggered if the data size exceeds the threshold set in the BYTECNTRVAL register. The interrupt handler counts the number of triggered interruptions and the read function will read the data from the synced ETR buffer. Switching the sysfs_buf when current buffer is full or the timeout is triggered and resets rrp and rwp registers after switched the buffer. The synced buffer will become available for reading after the switch. Link: https://lore.kernel.org/all/20251013-enable-byte-cntr-for-ctcu-v7-7-e1e8f41e15dd@oss.qualcomm.com/ Signed-off-by: Jie Gan --- .../testing/sysfs-bus-coresight-devices-ctcu | 6 + drivers/hwtracing/coresight/Makefile | 2 +- .../coresight/coresight-ctcu-byte-cntr.c | 368 ++++++++++++++++++ .../hwtracing/coresight/coresight-ctcu-core.c | 89 ++++- drivers/hwtracing/coresight/coresight-ctcu.h | 62 ++- .../hwtracing/coresight/coresight-tmc-etr.c | 18 + drivers/hwtracing/coresight/coresight-tmc.h | 1 + 7 files changed, 533 insertions(+), 13 deletions(-) create mode 100644 Documentation/ABI/testing/sysfs-bus-coresight-devices-ctcu create mode 100644 drivers/hwtracing/coresight/coresight-ctcu-byte-cntr.c diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-ctcu b/Documentation/ABI/testing/sysfs-bus-coresight-devices-ctcu new file mode 100644 index 0000000000000..fa64ea8e6e69b --- /dev/null +++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-ctcu @@ -0,0 +1,6 @@ +What: /sys/bus/coresight/devices//irq_threshold +Date: Oct. 2025 +KernelVersion: 6.19 +Contact: Tingwei Zhang ; Jinlong Mao ; Jie Gan +Description: + (RW) Configure the IRQ value for byte-cntr register. diff --git a/drivers/hwtracing/coresight/Makefile b/drivers/hwtracing/coresight/Makefile index a40c8bbb8c323..e5f143f91d698 100644 --- a/drivers/hwtracing/coresight/Makefile +++ b/drivers/hwtracing/coresight/Makefile @@ -56,5 +56,5 @@ obj-$(CONFIG_ULTRASOC_SMB) += ultrasoc-smb.o obj-$(CONFIG_CORESIGHT_DUMMY) += coresight-dummy.o obj-$(CONFIG_CORESIGHT_TGU) += coresight-tgu.o obj-$(CONFIG_CORESIGHT_CTCU) += coresight-ctcu.o -coresight-ctcu-y := coresight-ctcu-core.o +coresight-ctcu-y := coresight-ctcu-core.o coresight-ctcu-byte-cntr.o obj-$(CONFIG_CORESIGHT_KUNIT_TESTS) += coresight-kunit-tests.o diff --git a/drivers/hwtracing/coresight/coresight-ctcu-byte-cntr.c b/drivers/hwtracing/coresight/coresight-ctcu-byte-cntr.c new file mode 100644 index 0000000000000..d611d26f6e8e7 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-ctcu-byte-cntr.c @@ -0,0 +1,368 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#include +#include +#include +#include +#include +#include + +#include "coresight-ctcu.h" +#include "coresight-priv.h" +#include "coresight-tmc.h" + +static irqreturn_t byte_cntr_handler(int irq, void *data) +{ + struct ctcu_byte_cntr *byte_cntr_data = (struct ctcu_byte_cntr *)data; + + atomic_inc(&byte_cntr_data->irq_cnt); + wake_up(&byte_cntr_data->wq); + + return IRQ_HANDLED; +} + +static void ctcu_reset_sysfs_buf(struct tmc_drvdata *drvdata) +{ + u32 sts; + + CS_UNLOCK(drvdata->base); + tmc_write_rrp(drvdata, drvdata->sysfs_buf->hwaddr); + tmc_write_rwp(drvdata, drvdata->sysfs_buf->hwaddr); + sts = readl_relaxed(drvdata->base + TMC_STS) & ~TMC_STS_FULL; + writel_relaxed(sts, drvdata->base + TMC_STS); + CS_LOCK(drvdata->base); +} + +static void ctcu_cfg_byte_cntr_reg(struct tmc_drvdata *drvdata, u32 val, u32 offset) +{ + struct ctcu_drvdata *ctcu_drvdata; + struct coresight_device *helper; + + helper = coresight_get_helper(drvdata->csdev, CORESIGHT_DEV_SUBTYPE_HELPER_CTCU); + if (!helper) + return; + + ctcu_drvdata = dev_get_drvdata(helper->dev.parent); + /* A one value for IRQCTRL register represents 8 bytes */ + ctcu_program_register(ctcu_drvdata, val / 8, offset); +} + +static struct ctcu_byte_cntr *ctcu_get_byte_cntr_data(struct tmc_drvdata *drvdata) +{ + struct ctcu_byte_cntr *byte_cntr_data; + struct ctcu_drvdata *ctcu_drvdata; + struct coresight_device *helper; + int port; + + helper = coresight_get_helper(drvdata->csdev, CORESIGHT_DEV_SUBTYPE_HELPER_CTCU); + if (!helper) + return NULL; + + port = coresight_get_in_port_dest(drvdata->csdev, helper); + if (port < 0) + return NULL; + + ctcu_drvdata = dev_get_drvdata(helper->dev.parent); + byte_cntr_data = &ctcu_drvdata->byte_cntr_data[port]; + return byte_cntr_data; +} + +static bool ctcu_byte_cntr_switch_buffer(struct tmc_drvdata *drvdata, + struct ctcu_byte_cntr *byte_cntr_data) +{ + struct etr_buf_node *nd, *next, *curr_node, *picked_node; + struct etr_buf *curr_buf = drvdata->sysfs_buf; + bool found_free_buf = false; + + if (WARN_ON(!drvdata || !byte_cntr_data)) + return found_free_buf; + + /* Stop the ETR before we start the switch */ + if (coresight_get_mode(drvdata->csdev) != CS_MODE_DISABLED) + tmc_etr_enable_disable_hw(drvdata, false); + + list_for_each_entry_safe(nd, next, &drvdata->etr_buf_list, node) { + /* curr_buf is free for next round */ + if (nd->sysfs_buf == curr_buf) { + nd->is_free = true; + curr_node = nd; + } + + if (!found_free_buf && nd->is_free && nd->sysfs_buf != curr_buf) { + picked_node = nd; + found_free_buf = true; + } + } + + if (found_free_buf) { + curr_node->pos = 0; + drvdata->reading_node = curr_node; + drvdata->sysfs_buf = picked_node->sysfs_buf; + drvdata->etr_buf = picked_node->sysfs_buf; + picked_node->is_free = false; + /* Reset irq_cnt for next etr_buf */ + atomic_set(&byte_cntr_data->irq_cnt, 0); + /* Reset rrp and rwp when the system has switched the buffer*/ + ctcu_reset_sysfs_buf(drvdata); + /* Restart the ETR when we find a free buffer */ + if (coresight_get_mode(drvdata->csdev) != CS_MODE_DISABLED) + tmc_etr_enable_disable_hw(drvdata, true); + } + + return found_free_buf; +} + +/* + * ctcu_byte_cntr_get_data() - reads data from the deactivated and filled buffer. + * The byte-cntr reading work reads data from the deactivated and filled buffer. + * The read operation waits for a buffer to become available, either filled or + * upon timeout, and then reads trace data from the synced buffer. + */ +static ssize_t ctcu_byte_cntr_get_data(struct tmc_drvdata *drvdata, loff_t pos, + size_t len, char **bufpp) +{ + struct etr_buf *sysfs_buf = drvdata->sysfs_buf; + struct device *dev = &drvdata->csdev->dev; + ssize_t actual, size = sysfs_buf->size; + struct ctcu_byte_cntr *byte_cntr_data; + size_t thresh_val; + atomic_t *irq_cnt; + int ret; + + byte_cntr_data = ctcu_get_byte_cntr_data(drvdata); + if (!byte_cntr_data) + return -EINVAL; + + thresh_val = byte_cntr_data->thresh_val; + irq_cnt = &byte_cntr_data->irq_cnt; + +wait_buffer: + if (!byte_cntr_data->reading_buf) { + ret = wait_event_interruptible_timeout(byte_cntr_data->wq, + ((atomic_read(irq_cnt) + 1) * thresh_val >= size) || + !byte_cntr_data->enable, + BYTE_CNTR_TIMEOUT); + if (ret < 0) + return ret; + /* + * The current etr_buf is almost full or timeout is triggered, + * so switch the buffer and mark the switched buffer as reading. + */ + if (byte_cntr_data->enable) { + if (!ctcu_byte_cntr_switch_buffer(drvdata, byte_cntr_data)) { + dev_err(dev, "Switch buffer failed for byte-cntr\n"); + return -EINVAL; + } + + byte_cntr_data->reading_buf = true; + } else { + /* + * TMC-ETR has been disabled, so directly reads data from + * the drvdata->sysfs_buf. + */ + actual = drvdata->sysfs_ops->get_trace_data(drvdata, pos, len, bufpp); + if (actual > 0) { + byte_cntr_data->total_size += actual; + return actual; + } + + /* Exit byte-cntr reading */ + return 0; + } + } + + /* Check the status of current etr_buf*/ + if ((atomic_read(irq_cnt) + 1) * thresh_val >= size) + /* + * Unlikely to find a free buffer to switch, so just disable + * the ETR for a while. + */ + if (!ctcu_byte_cntr_switch_buffer(drvdata, byte_cntr_data)) + dev_warn(dev, "No available buffer to store data, disable ETR\n"); + + pos = drvdata->reading_node->pos; + actual = drvdata->sysfs_ops->get_trace_data(drvdata, pos, len, bufpp); + if (actual <= 0) { + /* Reset flags upon reading is finished or failed */ + byte_cntr_data->reading_buf = false; + drvdata->reading_node = NULL; + + /* + * Nothing in the buffer, waiting for the next buffer + * to be filled. + */ + if (actual == 0) + goto wait_buffer; + } else + byte_cntr_data->total_size += actual; + + return actual; +} + +static int ctcu_read_prepare_byte_cntr(struct tmc_drvdata *drvdata) +{ + struct ctcu_byte_cntr *byte_cntr_data; + unsigned long flags; + int ret = 0; + + /* config types are set a boot time and never change */ + if (WARN_ON_ONCE(drvdata->config_type != TMC_CONFIG_TYPE_ETR)) + return -EINVAL; + + /* + * Byte counter reading should start only after the TMC-ETR has been + * enabled, which implies that the sysfs_buf has already been setup + * in drvdata. + */ + if (!drvdata->sysfs_buf) + return -EINVAL; + + byte_cntr_data = ctcu_get_byte_cntr_data(drvdata); + if (!byte_cntr_data) + return -EINVAL; + + /* + * The threshold value must not exceed the buffer size. + * A margin should be maintained between the two values to account + * for the time gap between the interrupt and buffer switching. + */ + if (byte_cntr_data->thresh_val + SZ_16K >= drvdata->size) { + dev_err(&drvdata->csdev->dev, "The threshold value is too large\n"); + return -EINVAL; + } + + raw_spin_lock_irqsave(&drvdata->spinlock, flags); + if (byte_cntr_data->reading) { + ret = -EBUSY; + goto out_unlock; + } + + byte_cntr_data->reading = true; + raw_spin_unlock_irqrestore(&drvdata->spinlock, flags); + /* Setup an available etr_buf_list for byte-cntr */ + ret = tmc_create_etr_buf_list(drvdata, 2); + if (ret) + goto out; + + raw_spin_lock_irqsave(&drvdata->spinlock, flags); + atomic_set(&byte_cntr_data->irq_cnt, 0); + /* Configure the byte-cntr register to enable IRQ */ + ctcu_cfg_byte_cntr_reg(drvdata, byte_cntr_data->thresh_val, + byte_cntr_data->irq_ctrl_offset); + enable_irq_wake(byte_cntr_data->irq); + byte_cntr_data->total_size = 0; + +out_unlock: + raw_spin_unlock_irqrestore(&drvdata->spinlock, flags); + +out: + return ret; +} + +static int ctcu_read_unprepare_byte_cntr(struct tmc_drvdata *drvdata) +{ + struct device *dev = &drvdata->csdev->dev; + struct ctcu_byte_cntr *byte_cntr_data; + unsigned long flags; + + byte_cntr_data = ctcu_get_byte_cntr_data(drvdata); + if (!byte_cntr_data) + return -EINVAL; + + raw_spin_lock_irqsave(&drvdata->spinlock, flags); + /* Configure the byte-cntr register to disable IRQ */ + ctcu_cfg_byte_cntr_reg(drvdata, 0, byte_cntr_data->irq_ctrl_offset); + disable_irq_wake(byte_cntr_data->irq); + byte_cntr_data->reading = false; + byte_cntr_data->reading_buf = false; + drvdata->reading_node = NULL; + raw_spin_unlock_irqrestore(&drvdata->spinlock, flags); + dev_dbg(dev, "send data total size:%llu bytes\n", byte_cntr_data->total_size); + tmc_clean_etr_buf_list(drvdata); + + return 0; +} + +static const struct sysfs_read_ops byte_cntr_sysfs_read_ops = { + .read_prepare = ctcu_read_prepare_byte_cntr, + .read_unprepare = ctcu_read_unprepare_byte_cntr, + .get_trace_data = ctcu_byte_cntr_get_data, +}; + +/* Start the byte-cntr function when the path is enabled. */ +void ctcu_byte_cntr_start(struct coresight_device *csdev, struct coresight_path *path) +{ + struct ctcu_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); + struct coresight_device *sink = coresight_get_sink(path); + struct ctcu_byte_cntr *byte_cntr_data; + int port_num; + + if (!sink) + return; + + port_num = coresight_get_in_port_dest(sink, csdev); + if (port_num < 0) + return; + + byte_cntr_data = &drvdata->byte_cntr_data[port_num]; + /* Don't start byte-cntr function when threshold is not set. */ + if (!byte_cntr_data->thresh_val || byte_cntr_data->enable) + return; + + guard(raw_spinlock_irqsave)(&byte_cntr_data->spin_lock); + byte_cntr_data->enable = true; + byte_cntr_data->reading_buf = false; +} + +/* Stop the byte-cntr function when the path is disabled. */ +void ctcu_byte_cntr_stop(struct coresight_device *csdev, struct coresight_path *path) +{ + struct ctcu_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); + struct coresight_device *sink = coresight_get_sink(path); + struct ctcu_byte_cntr *byte_cntr_data; + int port_num; + + if (!sink || coresight_get_mode(sink) == CS_MODE_SYSFS) + return; + + port_num = coresight_get_in_port_dest(sink, csdev); + if (port_num < 0) + return; + + byte_cntr_data = &drvdata->byte_cntr_data[port_num]; + guard(raw_spinlock_irqsave)(&byte_cntr_data->spin_lock); + byte_cntr_data->enable = false; +} + +void ctcu_byte_cntr_init(struct device *dev, struct ctcu_drvdata *drvdata, int etr_num) +{ + struct ctcu_byte_cntr *byte_cntr_data; + struct device_node *nd = dev->of_node; + int irq_num, ret, i; + + drvdata->byte_cntr_sysfs_read_ops = &byte_cntr_sysfs_read_ops; + for (i = 0; i < etr_num; i++) { + byte_cntr_data = &drvdata->byte_cntr_data[i]; + irq_num = of_irq_get_byname(nd, byte_cntr_data->irq_name); + if (irq_num < 0) { + dev_err(dev, "Failed to get IRQ from DT for %s\n", + byte_cntr_data->irq_name); + continue; + } + + ret = devm_request_irq(dev, irq_num, byte_cntr_handler, + IRQF_TRIGGER_RISING | IRQF_SHARED, + dev_name(dev), byte_cntr_data); + if (ret) { + dev_err(dev, "Failed to register IRQ for %s\n", + byte_cntr_data->irq_name); + continue; + } + + byte_cntr_data->irq = irq_num; + init_waitqueue_head(&byte_cntr_data->wq); + } +} diff --git a/drivers/hwtracing/coresight/coresight-ctcu-core.c b/drivers/hwtracing/coresight/coresight-ctcu-core.c index a23ff6a6f83d6..46e71319adc79 100644 --- a/drivers/hwtracing/coresight/coresight-ctcu-core.c +++ b/drivers/hwtracing/coresight/coresight-ctcu-core.c @@ -15,6 +15,7 @@ #include #include #include +#include #include "coresight-ctcu.h" #include "coresight-priv.h" @@ -45,17 +46,23 @@ DEFINE_CORESIGHT_DEVLIST(ctcu_devs, "ctcu"); #define CTCU_ATID_REG_BIT(traceid) (traceid % 32) #define CTCU_ATID_REG_SIZE 0x10 +#define CTCU_ETR0_IRQCTRL 0x6c +#define CTCU_ETR1_IRQCTRL 0x70 #define CTCU_ETR0_ATID0 0xf8 #define CTCU_ETR1_ATID0 0x108 static const struct ctcu_etr_config sa8775p_etr_cfgs[] = { { - .atid_offset = CTCU_ETR0_ATID0, - .port_num = 0, + .atid_offset = CTCU_ETR0_ATID0, + .irq_ctrl_offset = CTCU_ETR0_IRQCTRL, + .irq_name = "etr0", + .port_num = 0, }, { - .atid_offset = CTCU_ETR1_ATID0, - .port_num = 1, + .atid_offset = CTCU_ETR1_ATID0, + .irq_ctrl_offset = CTCU_ETR1_IRQCTRL, + .irq_name = "etr1", + .port_num = 1, }, }; @@ -64,6 +71,71 @@ static const struct ctcu_config sa8775p_cfgs = { .num_etr_config = ARRAY_SIZE(sa8775p_etr_cfgs), }; +void ctcu_program_register(struct ctcu_drvdata *drvdata, u32 val, u32 offset) +{ + CS_UNLOCK(drvdata->base); + ctcu_writel(drvdata, val, offset); + CS_LOCK(drvdata->base); +} + +static ssize_t irq_threshold_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct ctcu_drvdata *drvdata = dev_get_drvdata(dev->parent); + int i, len = 0; + + for (i = 0; i < ETR_MAX_NUM; i++) { + if (drvdata->byte_cntr_data[i].irq_ctrl_offset) + len += scnprintf(buf + len, PAGE_SIZE - len, "%u ", + drvdata->byte_cntr_data[i].thresh_val); + } + + len += scnprintf(buf + len, PAGE_SIZE - len, "\n"); + + return len; +} + +/* Program a valid value into IRQCTRL register will enable byte-cntr interrupt */ +static ssize_t irq_threshold_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t size) +{ + struct ctcu_drvdata *drvdata = dev_get_drvdata(dev->parent); + u32 thresh_vals[ETR_MAX_NUM] = { 0 }; + int num, i; + + num = sscanf(buf, "%i %i", &thresh_vals[0], &thresh_vals[1]); + if (num <= 0 || num > ETR_MAX_NUM) + return -EINVAL; + + /* Threshold 0 disables the interruption. */ + guard(raw_spinlock_irqsave)(&drvdata->spin_lock); + for (i = 0; i < num; i++) { + /* A small threshold will result in a large number of interruptions */ + if (thresh_vals[i] && thresh_vals[i] < SZ_4K) + return -EINVAL; + + if (drvdata->byte_cntr_data[i].irq_ctrl_offset) + drvdata->byte_cntr_data[i].thresh_val = thresh_vals[i]; + } + + return size; +} +static DEVICE_ATTR_RW(irq_threshold); + +static struct attribute *ctcu_attrs[] = { + &dev_attr_irq_threshold.attr, + NULL, +}; + +static struct attribute_group ctcu_attr_grp = { + .attrs = ctcu_attrs, +}; + +static const struct attribute_group *ctcu_attr_grps[] = { + &ctcu_attr_grp, + NULL, +}; + static void ctcu_program_atid_register(struct ctcu_drvdata *drvdata, u32 reg_offset, u8 bit, bool enable) { @@ -143,6 +215,8 @@ static int ctcu_enable(struct coresight_device *csdev, enum cs_mode mode, void * { struct coresight_path *path = (struct coresight_path *)data; + ctcu_byte_cntr_start(csdev, path); + return ctcu_set_etr_traceid(csdev, path, true); } @@ -150,6 +224,8 @@ static int ctcu_disable(struct coresight_device *csdev, void *data) { struct coresight_path *path = (struct coresight_path *)data; + ctcu_byte_cntr_stop(csdev, path); + return ctcu_set_etr_traceid(csdev, path, false); } @@ -200,7 +276,11 @@ static int ctcu_probe(struct platform_device *pdev) for (i = 0; i < cfgs->num_etr_config; i++) { etr_cfg = &cfgs->etr_cfgs[i]; drvdata->atid_offset[i] = etr_cfg->atid_offset; + drvdata->byte_cntr_data[i].irq_name = etr_cfg->irq_name; + drvdata->byte_cntr_data[i].irq_ctrl_offset = + etr_cfg->irq_ctrl_offset; } + ctcu_byte_cntr_init(dev, drvdata, cfgs->num_etr_config); } } @@ -212,6 +292,7 @@ static int ctcu_probe(struct platform_device *pdev) desc.subtype.helper_subtype = CORESIGHT_DEV_SUBTYPE_HELPER_CTCU; desc.pdata = pdata; desc.dev = dev; + desc.groups = ctcu_attr_grps; desc.ops = &ctcu_ops; desc.access = CSDEV_ACCESS_IOMEM(base); diff --git a/drivers/hwtracing/coresight/coresight-ctcu.h b/drivers/hwtracing/coresight/coresight-ctcu.h index e9594c38dd91c..21938a201dbb1 100644 --- a/drivers/hwtracing/coresight/coresight-ctcu.h +++ b/drivers/hwtracing/coresight/coresight-ctcu.h @@ -5,19 +5,28 @@ #ifndef _CORESIGHT_CTCU_H #define _CORESIGHT_CTCU_H + +#include #include "coresight-trace-id.h" +#include "coresight-tmc.h" /* Maximum number of supported ETR devices for a single CTCU. */ #define ETR_MAX_NUM 2 +#define BYTE_CNTR_TIMEOUT (5 * HZ) + /** * struct ctcu_etr_config * @atid_offset: offset to the ATID0 Register. - * @port_num: in-port number of CTCU device that connected to ETR. + * @port_num: in-port number of the CTCU device that connected to ETR. + * @irq_ctrl_offset: offset to the BYTECNTRVAL register. + * @irq_name: IRQ name in dt node. */ struct ctcu_etr_config { const u32 atid_offset; const u32 port_num; + const u32 irq_ctrl_offset; + const char *irq_name; }; struct ctcu_config { @@ -25,15 +34,52 @@ struct ctcu_config { int num_etr_config; }; -struct ctcu_drvdata { - void __iomem *base; - struct clk *apb_clk; - struct device *dev; - struct coresight_device *csdev; +/** + * struct ctcu_byte_cntr + * @enable: indicates that byte_cntr function is enabled or not. + * @reading: indicates that byte-cntr reading is started. + * @reading_buf: indicates that byte-cntr is reading data from the buffer. + * @thresh_val: threshold to trigger a interruption. + * @total_size: total size of transferred data. + * @irq: allocated number of the IRQ. + * @irq_cnt: IRQ count number for triggered interruptions. + * @wq: waitqueue for reading data from ETR buffer. + * @spin_lock: spinlock of byte_cntr_data. + * @irq_ctrl_offset: offset to the BYTECNTVAL Register. + * @irq_name: IRQ name defined in DT. + */ +struct ctcu_byte_cntr { + bool enable; + bool reading; + bool reading_buf; + u32 thresh_val; + u64 total_size; + int irq; + atomic_t irq_cnt; + wait_queue_head_t wq; raw_spinlock_t spin_lock; - u32 atid_offset[ETR_MAX_NUM]; + u32 irq_ctrl_offset; + const char *irq_name; +}; + +struct ctcu_drvdata { + void __iomem *base; + struct clk *apb_clk; + struct device *dev; + struct coresight_device *csdev; + struct ctcu_byte_cntr byte_cntr_data[ETR_MAX_NUM]; + raw_spinlock_t spin_lock; + u32 atid_offset[ETR_MAX_NUM]; /* refcnt for each traceid of each sink */ - u8 traceid_refcnt[ETR_MAX_NUM][CORESIGHT_TRACE_ID_RES_TOP]; + u8 traceid_refcnt[ETR_MAX_NUM][CORESIGHT_TRACE_ID_RES_TOP]; + const struct sysfs_read_ops *byte_cntr_sysfs_read_ops; }; +void ctcu_program_register(struct ctcu_drvdata *drvdata, u32 val, u32 offset); + +/* Byte-cntr functions */ +void ctcu_byte_cntr_start(struct coresight_device *csdev, struct coresight_path *path); +void ctcu_byte_cntr_stop(struct coresight_device *csdev, struct coresight_path *path); +void ctcu_byte_cntr_init(struct device *dev, struct ctcu_drvdata *drvdata, int port_num); + #endif diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c index ed15991b32173..24031a6620acd 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c @@ -1163,6 +1163,10 @@ ssize_t tmc_etr_get_sysfs_trace(struct tmc_drvdata *drvdata, ssize_t actual = len; struct etr_buf *etr_buf = drvdata->sysfs_buf; + /* Reading the buffer from the buf_node if it exists*/ + if (drvdata->reading_node) + etr_buf = drvdata->reading_node->sysfs_buf; + if (pos + actual > etr_buf->len) actual = etr_buf->len - pos; if (actual <= 0) @@ -1226,6 +1230,20 @@ static void __tmc_etr_disable_hw(struct tmc_drvdata *drvdata) } +/** + * tmc_etr_enable_disable_hw - enable/disable the ETR hw. + * @drvdata: drvdata of the TMC device. + * @enable: indicates enable/disable. + */ +void tmc_etr_enable_disable_hw(struct tmc_drvdata *drvdata, bool enable) +{ + if (enable) + __tmc_etr_enable_hw(drvdata); + else + __tmc_etr_disable_hw(drvdata); +} +EXPORT_SYMBOL_GPL(tmc_etr_enable_disable_hw); + void tmc_etr_disable_hw(struct tmc_drvdata *drvdata) { __tmc_etr_disable_hw(drvdata); diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h index 9a548e1a4d94b..a5c8783bfc8d1 100644 --- a/drivers/hwtracing/coresight/coresight-tmc.h +++ b/drivers/hwtracing/coresight/coresight-tmc.h @@ -490,5 +490,6 @@ struct etr_buf *tmc_etr_get_buffer(struct coresight_device *csdev, extern const struct attribute_group coresight_etr_group; void tmc_clean_etr_buf_list(struct tmc_drvdata *drvdata); int tmc_create_etr_buf_list(struct tmc_drvdata *drvdata, int num_nodes); +void tmc_etr_enable_disable_hw(struct tmc_drvdata *drvdata, bool enable); #endif From b5bd672f854162ee6caeca48c47bf12741b64a7f Mon Sep 17 00:00:00 2001 From: Jie Gan Date: Mon, 13 Oct 2025 13:49:17 +0800 Subject: [PATCH 0117/2333] FROMLIST: coresight: tmc: integrate byte-cntr's read_ops with sysfs file_ops Add code logic to invoke byte-cntr's sysfs_read_ops if the byte-cntr is enabled. Link: https://lore.kernel.org/all/20251013-enable-byte-cntr-for-ctcu-v7-8-e1e8f41e15dd@oss.qualcomm.com/ Signed-off-by: Jie Gan --- .../hwtracing/coresight/coresight-tmc-core.c | 53 ++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/drivers/hwtracing/coresight/coresight-tmc-core.c b/drivers/hwtracing/coresight/coresight-tmc-core.c index 78137dc5f8d8f..984be10c10fd2 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-core.c +++ b/drivers/hwtracing/coresight/coresight-tmc-core.c @@ -32,6 +32,7 @@ #include "coresight-priv.h" #include "coresight-tmc.h" +#include "coresight-ctcu.h" DEFINE_CORESIGHT_DEVLIST(etb_devs, "tmc_etb"); DEFINE_CORESIGHT_DEVLIST(etf_devs, "tmc_etf"); @@ -232,15 +233,47 @@ static int tmc_prepare_crashdata(struct tmc_drvdata *drvdata) return 0; } +/* Return the byte-cntr's sysfs_read_ops if in use */ +static const struct sysfs_read_ops *tmc_get_byte_cntr_sysfs_ops(struct tmc_drvdata *drvdata) +{ + struct ctcu_byte_cntr *byte_cntr_data; + struct ctcu_drvdata *ctcu_drvdata; + struct coresight_device *helper; + int port; + + helper = coresight_get_helper(drvdata->csdev, CORESIGHT_DEV_SUBTYPE_HELPER_CTCU); + if (!helper) + return NULL; + + port = coresight_get_in_port_dest(drvdata->csdev, helper); + if (port < 0) + return NULL; + + ctcu_drvdata = dev_get_drvdata(helper->dev.parent); + byte_cntr_data = &ctcu_drvdata->byte_cntr_data[port]; + if (byte_cntr_data && byte_cntr_data->thresh_val) + return ctcu_drvdata->byte_cntr_sysfs_read_ops; + + return NULL; +} + static int tmc_read_prepare(struct tmc_drvdata *drvdata) { + const struct sysfs_read_ops *byte_cntr_sysfs_read_ops; int ret = 0; + byte_cntr_sysfs_read_ops = tmc_get_byte_cntr_sysfs_ops(drvdata); + if (byte_cntr_sysfs_read_ops) { + ret = byte_cntr_sysfs_read_ops->read_prepare(drvdata); + goto out; + } + if (drvdata->sysfs_ops) ret = drvdata->sysfs_ops->read_prepare(drvdata); else ret = -EINVAL; +out: if (!ret) dev_dbg(&drvdata->csdev->dev, "TMC read start\n"); @@ -249,13 +282,21 @@ static int tmc_read_prepare(struct tmc_drvdata *drvdata) static int tmc_read_unprepare(struct tmc_drvdata *drvdata) { + const struct sysfs_read_ops *byte_cntr_sysfs_read_ops; int ret = 0; + byte_cntr_sysfs_read_ops = tmc_get_byte_cntr_sysfs_ops(drvdata); + if (byte_cntr_sysfs_read_ops) { + ret = byte_cntr_sysfs_read_ops->read_unprepare(drvdata); + goto out; + } + if (drvdata->sysfs_ops) ret = drvdata->sysfs_ops->read_unprepare(drvdata); else ret = -EINVAL; +out: if (!ret) dev_dbg(&drvdata->csdev->dev, "TMC read end\n"); @@ -281,6 +322,12 @@ static int tmc_open(struct inode *inode, struct file *file) static ssize_t tmc_get_sysfs_trace(struct tmc_drvdata *drvdata, loff_t pos, size_t len, char **bufpp) { + const struct sysfs_read_ops *byte_cntr_sysfs_read_ops; + + byte_cntr_sysfs_read_ops = tmc_get_byte_cntr_sysfs_ops(drvdata); + if (byte_cntr_sysfs_read_ops) + return byte_cntr_sysfs_read_ops->get_trace_data(drvdata, pos, len, bufpp); + if (drvdata->sysfs_ops) return drvdata->sysfs_ops->get_trace_data(drvdata, pos, len, bufpp); @@ -304,7 +351,11 @@ static ssize_t tmc_read(struct file *file, char __user *data, size_t len, return -EFAULT; } - *ppos += actual; + if (drvdata->reading_node) + drvdata->reading_node->pos += actual; + else + *ppos += actual; + dev_dbg(&drvdata->csdev->dev, "%zu bytes copied\n", actual); return actual; From 37c2a79aa374fdeb7a05e1e8eeb7530f0ef7863b Mon Sep 17 00:00:00 2001 From: Ziyue Zhang Date: Mon, 8 Sep 2025 15:38:44 +0800 Subject: [PATCH 0118/2333] FROMLIST: arm64: dts: qcom: qcs8300: enable pcie0 Add configurations in devicetree for PCIe0, including registers, clocks, interrupts and phy setting sequence. Add PCIe lane equalization preset properties for 8 GT/s and 16GT/s Link: https://lore.kernel.org/all/20251024095609.48096-3-ziyue.zhang@oss.qualcomm.com/ Reviewed-by: Manivannan Sadhasivam Reviewed-by: Konrad Dybcio Signed-off-by: Ziyue Zhang --- arch/arm64/boot/dts/qcom/qcs8300.dtsi | 179 +++++++++++++++++++++++++- 1 file changed, 178 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/qcs8300.dtsi b/arch/arm64/boot/dts/qcom/qcs8300.dtsi index 9f8e87e028c39..b9792db07b6aa 100644 --- a/arch/arm64/boot/dts/qcom/qcs8300.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs8300.dtsi @@ -904,7 +904,7 @@ #power-domain-cells = <1>; clocks = <&rpmhcc RPMH_CXO_CLK>, <&sleep_clk>, - <0>, + <&pcie0_phy>, <0>, <0>, <0>, @@ -2256,6 +2256,183 @@ qcom,bcm-voters = <&apps_bcm_voter>; }; + pcie0: pci@1c00000 { + device_type = "pci"; + compatible = "qcom,pcie-qcs8300", "qcom,pcie-sa8775p"; + reg = <0x0 0x01c00000 0x0 0x3000>, + <0x0 0x40000000 0x0 0xf20>, + <0x0 0x40000f20 0x0 0xa8>, + <0x0 0x40001000 0x0 0x4000>, + <0x0 0x40100000 0x0 0x100000>, + <0x0 0x01c03000 0x0 0x1000>; + reg-names = "parf", + "dbi", + "elbi", + "atu", + "config", + "mhi"; + #address-cells = <3>; + #size-cells = <2>; + ranges = <0x01000000 0x0 0x00000000 0x0 0x40200000 0x0 0x100000>, + <0x02000000 0x0 0x40300000 0x0 0x40300000 0x0 0x1fd00000>; + bus-range = <0x00 0xff>; + + dma-coherent; + + linux,pci-domain = <0>; + num-lanes = <2>; + + interrupts = , + , + , + , + , + , + , + , + ; + interrupt-names = "msi0", + "msi1", + "msi2", + "msi3", + "msi4", + "msi5", + "msi6", + "msi7", + "global"; + + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 0x7>; + interrupt-map = <0 0 0 1 &intc GIC_SPI 434 IRQ_TYPE_LEVEL_HIGH>, + <0 0 0 2 &intc GIC_SPI 435 IRQ_TYPE_LEVEL_HIGH>, + <0 0 0 3 &intc GIC_SPI 438 IRQ_TYPE_LEVEL_HIGH>, + <0 0 0 4 &intc GIC_SPI 439 IRQ_TYPE_LEVEL_HIGH>; + + clocks = <&gcc GCC_PCIE_0_AUX_CLK>, + <&gcc GCC_PCIE_0_CFG_AHB_CLK>, + <&gcc GCC_PCIE_0_MSTR_AXI_CLK>, + <&gcc GCC_PCIE_0_SLV_AXI_CLK>, + <&gcc GCC_PCIE_0_SLV_Q2A_AXI_CLK>; + clock-names = "aux", + "cfg", + "bus_master", + "bus_slave", + "slave_q2a"; + + assigned-clocks = <&gcc GCC_PCIE_0_AUX_CLK>; + assigned-clock-rates = <19200000>; + + interconnects = <&pcie_anoc MASTER_PCIE_0 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ACTIVE_ONLY + &config_noc SLAVE_PCIE_0 QCOM_ICC_TAG_ACTIVE_ONLY>; + interconnect-names = "pcie-mem", + "cpu-pcie"; + + iommu-map = <0x0 &pcie_smmu 0x0000 0x1>, + <0x100 &pcie_smmu 0x0001 0x1>; + + resets = <&gcc GCC_PCIE_0_BCR>, + <&gcc GCC_PCIE_0_LINK_DOWN_BCR>; + reset-names = "pci", + "link_down"; + + power-domains = <&gcc GCC_PCIE_0_GDSC>; + + eq-presets-8gts = /bits/ 16 <0x5555 0x5555>; + eq-presets-16gts = /bits/ 8 <0x55 0x55>; + + status = "disabled"; + + pcie3_opp_table: opp-table { + compatible = "operating-points-v2"; + + /* GEN 1 x1 */ + opp-2500000 { + opp-hz = /bits/ 64 <2500000>; + required-opps = <&rpmhpd_opp_svs_l1>; + opp-peak-kBps = <250000 1>; + }; + + /* GEN 1 x2 and GEN 2 x1 */ + opp-5000000 { + opp-hz = /bits/ 64 <5000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + opp-peak-kBps = <500000 1>; + }; + + /* GEN 2 x2 */ + opp-10000000 { + opp-hz = /bits/ 64 <10000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + opp-peak-kBps = <1000000 1>; + }; + + /* GEN 3 x1 */ + opp-8000000 { + opp-hz = /bits/ 64 <8000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + opp-peak-kBps = <984500 1>; + }; + + /* GEN 3 x2 and GEN 4 x1 */ + opp-16000000 { + opp-hz = /bits/ 64 <16000000>; + required-opps = <&rpmhpd_opp_nom>; + opp-peak-kBps = <1969000 1>; + }; + + /* GEN 4 x2 */ + opp-32000000 { + opp-hz = /bits/ 64 <32000000>; + required-opps = <&rpmhpd_opp_nom>; + opp-peak-kBps = <3938000 1>; + }; + }; + + pcieport0: pcie@0 { + device_type = "pci"; + reg = <0x0 0x0 0x0 0x0 0x0>; + bus-range = <0x01 0xff>; + + #address-cells = <3>; + #size-cells = <2>; + ranges; + phys = <&pcie0_phy>; + }; + }; + + pcie0_phy: phy@1c04000 { + compatible = "qcom,qcs8300-qmp-gen4x2-pcie-phy"; + reg = <0x0 0x01c04000 0x0 0x2000>; + + clocks = <&gcc GCC_PCIE_0_PHY_AUX_CLK>, + <&gcc GCC_PCIE_0_CFG_AHB_CLK>, + <&gcc GCC_PCIE_CLKREF_EN>, + <&gcc GCC_PCIE_0_PHY_RCHNG_CLK>, + <&gcc GCC_PCIE_0_PIPE_CLK>, + <&gcc GCC_PCIE_0_PIPEDIV2_CLK>; + clock-names = "aux", + "cfg_ahb", + "ref", + "rchng", + "pipe", + "pipediv2"; + + resets = <&gcc GCC_PCIE_0_PHY_BCR>; + reset-names = "phy"; + + assigned-clocks = <&gcc GCC_PCIE_0_PHY_RCHNG_CLK>; + assigned-clock-rates = <100000000>; + + #clock-cells = <0>; + clock-output-names = "pcie_0_pipe_clk"; + + #phy-cells = <0>; + + status = "disabled"; + }; + ufs_mem_hc: ufs@1d84000 { compatible = "qcom,qcs8300-ufshc", "qcom,ufshc", "jedec,ufs-2.0"; reg = <0x0 0x01d84000 0x0 0x3000>; From 1abde3e1dea7cc1a7d46b3e6dc124e0e17f36e5b Mon Sep 17 00:00:00 2001 From: Ziyue Zhang Date: Mon, 8 Sep 2025 15:38:45 +0800 Subject: [PATCH 0119/2333] FROMLIST: arm64: dts: qcom: qcs8300-ride: enable pcie0 interface Add configurations in devicetree for PCIe0, board related gpios, PMIC regulators, etc for qcs8300-ride board. Link: https://lore.kernel.org/all/20251024095609.48096-4-ziyue.zhang@oss.qualcomm.com/ Reviewed-by: Manivannan Sadhasivam Reviewed-by: Konrad Dybcio Signed-off-by: Ziyue Zhang --- arch/arm64/boot/dts/qcom/qcs8300-ride.dts | 42 +++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/qcs8300-ride.dts b/arch/arm64/boot/dts/qcom/qcs8300-ride.dts index 36c1f5a8526c1..5cef4b4d1801e 100644 --- a/arch/arm64/boot/dts/qcom/qcs8300-ride.dts +++ b/arch/arm64/boot/dts/qcom/qcs8300-ride.dts @@ -353,6 +353,25 @@ status = "okay"; }; +&pcie0 { + pinctrl-0 = <&pcie0_default_state>; + pinctrl-names = "default"; + + status = "okay"; +}; + +&pcieport0 { + reset-gpios = <&tlmm 2 GPIO_ACTIVE_LOW>; + wake-gpios = <&tlmm 0 GPIO_ACTIVE_HIGH>; +}; + +&pcie0_phy { + vdda-phy-supply = <&vreg_l6a>; + vdda-pll-supply = <&vreg_l5a>; + + status = "okay"; +}; + &psci { reboot-mode { mode-bootloader = <0x10001 0x2>; @@ -426,6 +445,29 @@ function = "edp0_hot"; bias-disable; }; + + pcie0_default_state: pcie0-default-state { + wake-pins { + pins = "gpio0"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + + clkreq-pins { + pins = "gpio1"; + function = "pcie0_clkreq"; + drive-strength = <2>; + bias-pull-up; + }; + + perst-pins { + pins = "gpio2"; + function = "gpio"; + drive-strength = <2>; + bias-pull-down; + }; + }; }; &uart7 { From 2b05d0d816e3ace3fd14a2df26ffb368ddfb4e33 Mon Sep 17 00:00:00 2001 From: Ziyue Zhang Date: Mon, 8 Sep 2025 15:38:46 +0800 Subject: [PATCH 0120/2333] FROMLIST: arm64: dts: qcom: qcs8300: enable pcie1 Add configurations in devicetree for PCIe1, including registers, clocks, interrupts and phy setting sequence. Add PCIe lane equalization preset properties for 8 GT/s and 16GT/s. Link: https://lore.kernel.org/all/20251024095609.48096-5-ziyue.zhang@oss.qualcomm.com/ Acked-by: Konrad Dybcio Reviewed-by: Manivannan Sadhasivam Signed-off-by: Ziyue Zhang --- arch/arm64/boot/dts/qcom/qcs8300.dtsi | 131 +++++++++++++++++++++++++- 1 file changed, 130 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/qcs8300.dtsi b/arch/arm64/boot/dts/qcom/qcs8300.dtsi index b9792db07b6aa..4781cdbb4efb0 100644 --- a/arch/arm64/boot/dts/qcom/qcs8300.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs8300.dtsi @@ -905,7 +905,7 @@ clocks = <&rpmhcc RPMH_CXO_CLK>, <&sleep_clk>, <&pcie0_phy>, - <0>, + <&pcie1_phy>, <0>, <0>, <0>, @@ -2433,6 +2433,135 @@ status = "disabled"; }; + pcie1: pci@1c10000 { + device_type = "pci"; + compatible = "qcom,pcie-qcs8300", "qcom,pcie-sa8775p"; + reg = <0x0 0x01c10000 0x0 0x3000>, + <0x0 0x60000000 0x0 0xf20>, + <0x0 0x60000f20 0x0 0xa8>, + <0x0 0x60001000 0x0 0x4000>, + <0x0 0x60100000 0x0 0x100000>, + <0x0 0x01c13000 0x0 0x1000>; + reg-names = "parf", + "dbi", + "elbi", + "atu", + "config", + "mhi"; + #address-cells = <3>; + #size-cells = <2>; + ranges = <0x01000000 0x0 0x00000000 0x0 0x60200000 0x0 0x100000>, + <0x02000000 0x0 0x60300000 0x0 0x60300000 0x0 0x1fd00000>; + bus-range = <0x00 0xff>; + + dma-coherent; + + linux,pci-domain = <1>; + num-lanes = <4>; + + interrupts = , + , + , + , + , + , + , + , + ; + interrupt-names = "msi0", + "msi1", + "msi2", + "msi3", + "msi4", + "msi5", + "msi6", + "msi7", + "global"; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 0x7>; + interrupt-map = <0 0 0 1 &intc GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>, + <0 0 0 2 &intc GIC_SPI 149 IRQ_TYPE_LEVEL_HIGH>, + <0 0 0 3 &intc GIC_SPI 150 IRQ_TYPE_LEVEL_HIGH>, + <0 0 0 4 &intc GIC_SPI 151 IRQ_TYPE_LEVEL_HIGH>; + + clocks = <&gcc GCC_PCIE_1_AUX_CLK>, + <&gcc GCC_PCIE_1_CFG_AHB_CLK>, + <&gcc GCC_PCIE_1_MSTR_AXI_CLK>, + <&gcc GCC_PCIE_1_SLV_AXI_CLK>, + <&gcc GCC_PCIE_1_SLV_Q2A_AXI_CLK>; + clock-names = "aux", + "cfg", + "bus_master", + "bus_slave", + "slave_q2a"; + + assigned-clocks = <&gcc GCC_PCIE_1_AUX_CLK>; + assigned-clock-rates = <19200000>; + + interconnects = <&pcie_anoc MASTER_PCIE_1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ACTIVE_ONLY + &config_noc SLAVE_PCIE_1 QCOM_ICC_TAG_ACTIVE_ONLY>; + interconnect-names = "pcie-mem", "cpu-pcie"; + + iommu-map = <0x0 &pcie_smmu 0x0080 0x1>, + <0x100 &pcie_smmu 0x0081 0x1>; + + resets = <&gcc GCC_PCIE_1_BCR>, + <&gcc GCC_PCIE_1_LINK_DOWN_BCR>; + reset-names = "pci", + "link_down"; + + power-domains = <&gcc GCC_PCIE_1_GDSC>; + + eq-presets-8gts = /bits/ 16 <0x5555 0x5555 0x5555 0x5555>; + eq-presets-16gts = /bits/ 8 <0x55 0x55 0x55 0x55>; + + status = "disabled"; + + pcieport1: pcie@0 { + device_type = "pci"; + reg = <0x0 0x0 0x0 0x0 0x0>; + bus-range = <0x01 0xff>; + + #address-cells = <3>; + #size-cells = <2>; + ranges; + phys = <&pcie1_phy>; + }; + }; + + pcie1_phy: phy@1c14000 { + compatible = "qcom,sa8775p-qmp-gen4x4-pcie-phy"; + reg = <0x0 0x01c14000 0x0 0x4000>; + + clocks = <&gcc GCC_PCIE_1_PHY_AUX_CLK>, + <&gcc GCC_PCIE_1_CFG_AHB_CLK>, + <&gcc GCC_PCIE_CLKREF_EN>, + <&gcc GCC_PCIE_1_PHY_RCHNG_CLK>, + <&gcc GCC_PCIE_1_PIPE_CLK>, + <&gcc GCC_PCIE_1_PIPEDIV2_CLK>; + clock-names = "aux", + "cfg_ahb", + "ref", + "rchng", + "pipe", + "pipediv2"; + + assigned-clocks = <&gcc GCC_PCIE_1_PHY_RCHNG_CLK>; + assigned-clock-rates = <100000000>; + + resets = <&gcc GCC_PCIE_1_PHY_BCR>; + reset-names = "phy"; + + #clock-cells = <0>; + clock-output-names = "pcie_1_pipe_clk"; + + #phy-cells = <0>; + + status = "disabled"; + }; + ufs_mem_hc: ufs@1d84000 { compatible = "qcom,qcs8300-ufshc", "qcom,ufshc", "jedec,ufs-2.0"; reg = <0x0 0x01d84000 0x0 0x3000>; From bed25ea6bbd5566ad9ee233ed4842e860ffd1bc8 Mon Sep 17 00:00:00 2001 From: Ziyue Zhang Date: Mon, 8 Sep 2025 15:38:47 +0800 Subject: [PATCH 0121/2333] FROMLIST: arm64: dts: qcom: qcs8300-ride: enable pcie1 interface Add configurations in devicetree for PCIe1, board related gpios, PMIC regulators, etc for qcs8300-ride platform. Link: https://lore.kernel.org/all/20251024095609.48096-6-ziyue.zhang@oss.qualcomm.com/ Reviewed-by: Konrad Dybcio Signed-off-by: Ziyue Zhang --- arch/arm64/boot/dts/qcom/qcs8300-ride.dts | 42 +++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/qcs8300-ride.dts b/arch/arm64/boot/dts/qcom/qcs8300-ride.dts index 5cef4b4d1801e..59374d2442b2d 100644 --- a/arch/arm64/boot/dts/qcom/qcs8300-ride.dts +++ b/arch/arm64/boot/dts/qcom/qcs8300-ride.dts @@ -372,6 +372,25 @@ status = "okay"; }; +&pcie1 { + pinctrl-0 = <&pcie1_default_state>; + pinctrl-names = "default"; + + status = "okay"; +}; + +&pcieport1 { + reset-gpios = <&tlmm 23 GPIO_ACTIVE_LOW>; + wake-gpios = <&tlmm 21 GPIO_ACTIVE_HIGH>; +}; + +&pcie1_phy { + vdda-phy-supply = <&vreg_l6a>; + vdda-pll-supply = <&vreg_l5a>; + + status = "okay"; +}; + &psci { reboot-mode { mode-bootloader = <0x10001 0x2>; @@ -468,6 +487,29 @@ bias-pull-down; }; }; + + pcie1_default_state: pcie1-default-state { + wake-pins { + pins = "gpio21"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + + clkreq-pins { + pins = "gpio22"; + function = "pcie1_clkreq"; + drive-strength = <2>; + bias-pull-up; + }; + + perst-pins { + pins = "gpio23"; + function = "gpio"; + drive-strength = <2>; + bias-pull-down; + }; + }; }; &uart7 { From d9d228be17f4375afa3aadade48b92e606537e2d Mon Sep 17 00:00:00 2001 From: Prudhvi Yarlagadda Date: Mon, 3 Nov 2025 23:56:24 -0800 Subject: [PATCH 0122/2333] FROMLIST: dt-bindings: phy: qcom,sc8280xp-qmp-pcie-phy: Document the Glymur QMP PCIe PHY The fifth PCIe instance on Glymur has a Gen5 4-lane PHY. Document it as a separate compatible. Link: https://lore.kernel.org/all/20251103-glymur-pcie-upstream-v6-1-18a5e0a538dc@oss.qualcomm.com/ Signed-off-by: Prudhvi Yarlagadda Signed-off-by: Wenbin Yao Acked-by: Rob Herring (Arm) Signed-off-by: Qiang Yu --- .../devicetree/bindings/phy/qcom,sc8280xp-qmp-pcie-phy.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-pcie-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-pcie-phy.yaml index d94d08752cec6..3e2480df9db72 100644 --- a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-pcie-phy.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-pcie-phy.yaml @@ -16,6 +16,7 @@ description: properties: compatible: enum: + - qcom,glymur-qmp-gen5x4-pcie-phy - qcom,qcs615-qmp-gen3x1-pcie-phy - qcom,qcs8300-qmp-gen4x2-pcie-phy - qcom,sa8775p-qmp-gen4x2-pcie-phy @@ -177,6 +178,7 @@ allOf: compatible: contains: enum: + - qcom,glymur-qmp-gen5x4-pcie-phy - qcom,qcs8300-qmp-gen4x2-pcie-phy - qcom,sa8775p-qmp-gen4x2-pcie-phy - qcom,sa8775p-qmp-gen4x4-pcie-phy @@ -200,6 +202,7 @@ allOf: compatible: contains: enum: + - qcom,glymur-qmp-gen5x4-pcie-phy - qcom,sm8550-qmp-gen4x2-pcie-phy - qcom,sm8650-qmp-gen4x2-pcie-phy - qcom,x1e80100-qmp-gen4x2-pcie-phy From 77be826a23721ed96bc1b79df361f32494c0c75c Mon Sep 17 00:00:00 2001 From: Prudhvi Yarlagadda Date: Mon, 3 Nov 2025 23:56:24 -0800 Subject: [PATCH 0123/2333] FROMLIST: phy: qcom-qmp: pcs: Add v8.50 register offsets The new Glymur SoC bumps up the HW version of QMP phy to v8.50 for PCIE g5x4. Add the new PCS offsets in a dedicated header file. Link: https://lore.kernel.org/all/20251103-glymur-pcie-upstream-v6-2-18a5e0a538dc@oss.qualcomm.com/ Signed-off-by: Prudhvi Yarlagadda Signed-off-by: Wenbin Yao Reviewed-by: Dmitry Baryshkov Signed-off-by: Qiang Yu --- drivers/phy/qualcomm/phy-qcom-qmp-pcs-v8_50.h | 13 +++++++++++++ drivers/phy/qualcomm/phy-qcom-qmp.h | 2 ++ 2 files changed, 15 insertions(+) create mode 100644 drivers/phy/qualcomm/phy-qcom-qmp-pcs-v8_50.h diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-v8_50.h b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-v8_50.h new file mode 100644 index 0000000000000..325c127e8eb7a --- /dev/null +++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-v8_50.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#ifndef QCOM_PHY_QMP_PCS_V8_50_H_ +#define QCOM_PHY_QMP_PCS_V8_50_H_ + +#define QPHY_V8_50_PCS_STATUS1 0x010 +#define QPHY_V8_50_PCS_START_CONTROL 0x05c +#define QPHY_V8_50_PCS_POWER_DOWN_CONTROL 0x64 + +#endif diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.h b/drivers/phy/qualcomm/phy-qcom-qmp.h index f58c82b2dd23e..da2a7ad2cdcce 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp.h +++ b/drivers/phy/qualcomm/phy-qcom-qmp.h @@ -58,6 +58,8 @@ #include "phy-qcom-qmp-pcs-v8.h" +#include "phy-qcom-qmp-pcs-v8_50.h" + /* QPHY_SW_RESET bit */ #define SW_RESET BIT(0) /* QPHY_POWER_DOWN_CONTROL */ From 8c010cf4d650e8ec71356aa860e9eaa6c87274e2 Mon Sep 17 00:00:00 2001 From: Prudhvi Yarlagadda Date: Mon, 3 Nov 2025 23:56:24 -0800 Subject: [PATCH 0124/2333] FROMLIST: phy: qcom: qmp-pcie: Add support for Glymur PCIe Gen5x4 PHY Add support for Gen5 x4 PCIe QMP PHY found on Glymur platform. Link: https://lore.kernel.org/all/20251103-glymur-pcie-upstream-v6-3-18a5e0a538dc@oss.qualcomm.com/ Signed-off-by: Prudhvi Yarlagadda Signed-off-by: Wenbin Yao Reviewed-by: Dmitry Baryshkov Acked-by: Manivannan Sadhasivam Signed-off-by: Qiang Yu --- drivers/phy/qualcomm/phy-qcom-qmp-pcie.c | 32 ++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c index 62b1c845b6275..86b1b7e2da86a 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c @@ -100,6 +100,12 @@ static const unsigned int pciephy_v7_regs_layout[QPHY_LAYOUT_SIZE] = { [QPHY_PCS_POWER_DOWN_CONTROL] = QPHY_V7_PCS_POWER_DOWN_CONTROL, }; +static const unsigned int pciephy_v8_50_regs_layout[QPHY_LAYOUT_SIZE] = { + [QPHY_START_CTRL] = QPHY_V8_50_PCS_START_CONTROL, + [QPHY_PCS_STATUS] = QPHY_V8_50_PCS_STATUS1, + [QPHY_PCS_POWER_DOWN_CONTROL] = QPHY_V8_50_PCS_POWER_DOWN_CONTROL, +}; + static const struct qmp_phy_init_tbl msm8998_pcie_serdes_tbl[] = { QMP_PHY_INIT_CFG(QSERDES_V3_COM_BIAS_EN_CLKBUFLR_EN, 0x14), QMP_PHY_INIT_CFG(QSERDES_V3_COM_CLK_SELECT, 0x30), @@ -3072,6 +3078,7 @@ struct qmp_pcie_offsets { u16 rx2; u16 txz; u16 rxz; + u16 txrxz; u16 ln_shrd; }; @@ -3356,6 +3363,12 @@ static const struct qmp_pcie_offsets qmp_pcie_offsets_v6_30 = { .ln_shrd = 0x8000, }; +static const struct qmp_pcie_offsets qmp_pcie_offsets_v8_50 = { + .serdes = 0x8000, + .pcs = 0x9000, + .txrxz = 0xd000, +}; + static const struct qmp_phy_cfg ipq8074_pciephy_cfg = { .lanes = 1, @@ -4412,6 +4425,22 @@ static const struct qmp_phy_cfg qmp_v6_gen4x4_pciephy_cfg = { .phy_status = PHYSTATUS_4_20, }; +static const struct qmp_phy_cfg glymur_qmp_gen5x4_pciephy_cfg = { + .lanes = 4, + + .offsets = &qmp_pcie_offsets_v8_50, + + .reset_list = sdm845_pciephy_reset_l, + .num_resets = ARRAY_SIZE(sdm845_pciephy_reset_l), + .vreg_list = qmp_phy_vreg_l, + .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), + + .regs = pciephy_v8_50_regs_layout, + + .pwrdn_ctrl = SW_PWRDN | REFCLK_DRV_DSBL, + .phy_status = PHYSTATUS_4_20, +}; + static void qmp_pcie_init_port_b(struct qmp_pcie *qmp, const struct qmp_phy_cfg_tbls *tbls) { const struct qmp_phy_cfg *cfg = qmp->cfg; @@ -5163,6 +5192,9 @@ static int qmp_pcie_probe(struct platform_device *pdev) static const struct of_device_id qmp_pcie_of_match_table[] = { { + .compatible = "qcom,glymur-qmp-gen5x4-pcie-phy", + .data = &glymur_qmp_gen5x4_pciephy_cfg, + }, { .compatible = "qcom,ipq6018-qmp-pcie-phy", .data = &ipq6018_pciephy_cfg, }, { From ab488645ab7854ff44195d148bc1073a075c8289 Mon Sep 17 00:00:00 2001 From: Neeraj Soni Date: Thu, 30 Oct 2025 21:40:12 +0530 Subject: [PATCH 0125/2333] FROMLIST: soc: qcom: ice: Add HWKM v1 support for wrapped keys HWKM v1 and v2 differ slightly in wrapped key size and the bit fields for certain status registers and operating mode (legacy or standard). Add support to select HWKM version based on the major and minor revisions. Use this HWKM version to select wrapped key size and to configure the bit fields in registers for operating modes and hardware status. Support for SCM calls for wrapped keys is being added in the TrustZone for few SoCs with HWKM v1. Existing check of qcom_scm_has_wrapped_key_support() API ensures that HWKM is used only if these SCM calls are supported in TrustZone for that SoC. Link: https://lore.kernel.org/lkml/176222149538.1132260.9122814994642806453.b4-ty@kernel.org/ Signed-off-by: Neeraj Soni Reviewed-by: Konrad Dybcio Signed-off-by: Neeraj Soni --- drivers/soc/qcom/ice.c | 81 ++++++++++++++++++++++++++++++------------ 1 file changed, 58 insertions(+), 23 deletions(-) diff --git a/drivers/soc/qcom/ice.c b/drivers/soc/qcom/ice.c index c467b55b41744..b203bc685cadd 100644 --- a/drivers/soc/qcom/ice.c +++ b/drivers/soc/qcom/ice.c @@ -22,7 +22,18 @@ #include #define AES_256_XTS_KEY_SIZE 64 /* for raw keys only */ -#define QCOM_ICE_HWKM_WRAPPED_KEY_SIZE 100 /* assuming HWKM v2 */ + +#define QCOM_ICE_HWKM_V1 1 /* HWKM version 1 */ +#define QCOM_ICE_HWKM_V2 2 /* HWKM version 2 */ + +#define QCOM_ICE_HWKM_MAX_WRAPPED_KEY_SIZE 100 /* Maximum HWKM wrapped key size */ + +/* + * Wrapped key size depends upon HWKM version: + * HWKM version 1 supports 68 bytes + * HWKM version 2 supports 100 bytes + */ +#define QCOM_ICE_HWKM_WRAPPED_KEY_SIZE(v) ((v) == QCOM_ICE_HWKM_V1 ? 68 : 100) /* QCOM ICE registers */ @@ -62,13 +73,15 @@ union crypto_cfg { #define QCOM_ICE_REG_HWKM_TZ_KM_CTL (HWKM_OFFSET + 0x1000) #define QCOM_ICE_HWKM_DISABLE_CRC_CHECKS_VAL (BIT(1) | BIT(2)) +/* In HWKM v1 the ICE legacy mode is controlled from HWKM register space */ +#define QCOM_ICE_HWKM_ICE_LEGACY_MODE_ENABLED BIT(5) #define QCOM_ICE_REG_HWKM_TZ_KM_STATUS (HWKM_OFFSET + 0x1004) #define QCOM_ICE_HWKM_KT_CLEAR_DONE BIT(0) #define QCOM_ICE_HWKM_BOOT_CMD_LIST0_DONE BIT(1) #define QCOM_ICE_HWKM_BOOT_CMD_LIST1_DONE BIT(2) -#define QCOM_ICE_HWKM_CRYPTO_BIST_DONE_V2 BIT(7) -#define QCOM_ICE_HWKM_BIST_DONE_V2 BIT(9) +#define QCOM_ICE_HWKM_CRYPTO_BIST_DONE(v) (((v) == QCOM_ICE_HWKM_V1) ? BIT(14) : BIT(7)) +#define QCOM_ICE_HWKM_BIST_DONE(v) (((v) == QCOM_ICE_HWKM_V1) ? BIT(16) : BIT(9)) #define QCOM_ICE_REG_HWKM_BANK0_BANKN_IRQ_STATUS (HWKM_OFFSET + 0x2008) #define QCOM_ICE_HWKM_RSP_FIFO_CLEAR_VAL BIT(3) @@ -97,6 +110,7 @@ struct qcom_ice { struct clk *core_clk; bool use_hwkm; bool hwkm_init_complete; + u8 hwkm_version; }; static bool qcom_ice_check_supported(struct qcom_ice *ice) @@ -114,9 +128,24 @@ static bool qcom_ice_check_supported(struct qcom_ice *ice) return false; } + /* HWKM version v2 is present from ICE 3.2.1 onwards while version v1 + * is present only in ICE 3.2.0. Earlier ICE version don't have HWKM. + */ + if (major > 3 || + (major == 3 && (minor >= 3 || (minor == 2 && step >= 1)))) + ice->hwkm_version = QCOM_ICE_HWKM_V2; + else if ((major == 3) && (minor == 2)) + ice->hwkm_version = QCOM_ICE_HWKM_V1; + else + ice->hwkm_version = 0; + dev_info(dev, "Found QC Inline Crypto Engine (ICE) v%d.%d.%d\n", major, minor, step); + if (ice->hwkm_version) + dev_info(dev, "QC Hardware Key Manager (HWKM) version v%d\n", + ice->hwkm_version); + /* If fuses are blown, ICE might not work in the standard way. */ regval = qcom_ice_readl(ice, QCOM_ICE_REG_FUSE_SETTING); if (regval & (QCOM_ICE_FUSE_SETTING_MASK | @@ -131,19 +160,18 @@ static bool qcom_ice_check_supported(struct qcom_ice *ice) * v3.2.1 and later have HWKM v2. ICE v3.2.0 has HWKM v1. Earlier ICE * versions don't have HWKM at all. However, for HWKM to be fully * usable by Linux, the TrustZone software also needs to support certain - * SCM calls including the ones to generate and prepare keys. That - * effectively makes the earliest supported SoC be SM8650, which has - * HWKM v2. Therefore, this driver doesn't include support for HWKM v1, - * and it checks for the SCM call support before it decides to use HWKM. + * SCM calls including the ones to generate and prepare keys. Support + * for these SCM calls is present for SoCs with HWKM v2 and is being + * added for SoCs with HWKM v1 as well but not every SoC with HWKM v1 + * currently supports this. So, this driver checks for the SCM call + * support before it decides to use HWKM. * * Also, since HWKM and legacy mode are mutually exclusive, and * ICE-capable storage driver(s) need to know early on whether to * advertise support for raw keys or wrapped keys, HWKM cannot be used * unconditionally. A module parameter is used to opt into using it. */ - if ((major >= 4 || - (major == 3 && (minor >= 3 || (minor == 2 && step >= 1)))) && - qcom_scm_has_wrapped_key_support()) { + if (ice->hwkm_version && qcom_scm_has_wrapped_key_support()) { if (qcom_ice_use_wrapped_keys) { dev_info(dev, "Using HWKM. Supporting wrapped keys only.\n"); ice->use_hwkm = true; @@ -212,8 +240,8 @@ static int qcom_ice_wait_bist_status(struct qcom_ice *ice) (QCOM_ICE_HWKM_KT_CLEAR_DONE | QCOM_ICE_HWKM_BOOT_CMD_LIST0_DONE | QCOM_ICE_HWKM_BOOT_CMD_LIST1_DONE | - QCOM_ICE_HWKM_CRYPTO_BIST_DONE_V2 | - QCOM_ICE_HWKM_BIST_DONE_V2)) { + QCOM_ICE_HWKM_CRYPTO_BIST_DONE(ice->hwkm_version) | + QCOM_ICE_HWKM_BIST_DONE(ice->hwkm_version))) { dev_err(ice->dev, "HWKM self-test error!\n"); /* * Too late to revoke use_hwkm here, as it was already @@ -230,7 +258,7 @@ static void qcom_ice_hwkm_init(struct qcom_ice *ice) if (!ice->use_hwkm) return; - BUILD_BUG_ON(QCOM_ICE_HWKM_WRAPPED_KEY_SIZE > + BUILD_BUG_ON(QCOM_ICE_HWKM_MAX_WRAPPED_KEY_SIZE > BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE); /* * When ICE is in HWKM mode, it only supports wrapped keys. @@ -238,9 +266,15 @@ static void qcom_ice_hwkm_init(struct qcom_ice *ice) * * Put ICE in HWKM mode. ICE defaults to legacy mode. */ - regval = qcom_ice_readl(ice, QCOM_ICE_REG_CONTROL); - regval &= ~QCOM_ICE_LEGACY_MODE_ENABLED; - qcom_ice_writel(ice, regval, QCOM_ICE_REG_CONTROL); + if (ice->hwkm_version == QCOM_ICE_HWKM_V2) { + regval = qcom_ice_readl(ice, QCOM_ICE_REG_CONTROL); + regval &= ~QCOM_ICE_LEGACY_MODE_ENABLED; + qcom_ice_writel(ice, regval, QCOM_ICE_REG_CONTROL); + } else if (ice->hwkm_version == QCOM_ICE_HWKM_V1) { + regval = qcom_ice_readl(ice, QCOM_ICE_REG_HWKM_TZ_KM_CTL); + regval &= ~QCOM_ICE_HWKM_ICE_LEGACY_MODE_ENABLED; + qcom_ice_writel(ice, regval, QCOM_ICE_REG_HWKM_TZ_KM_CTL); + } /* Disable CRC checks. This HWKM feature is not used. */ qcom_ice_writel(ice, QCOM_ICE_HWKM_DISABLE_CRC_CHECKS_VAL, @@ -298,7 +332,7 @@ EXPORT_SYMBOL_GPL(qcom_ice_suspend); static unsigned int translate_hwkm_slot(struct qcom_ice *ice, unsigned int slot) { - return slot * 2; + return ice->hwkm_version == QCOM_ICE_HWKM_V1 ? slot : slot * 2; } static int qcom_ice_program_wrapped_key(struct qcom_ice *ice, unsigned int slot, @@ -451,11 +485,12 @@ int qcom_ice_generate_key(struct qcom_ice *ice, { int err; - err = qcom_scm_generate_ice_key(lt_key, QCOM_ICE_HWKM_WRAPPED_KEY_SIZE); + err = qcom_scm_generate_ice_key(lt_key, + QCOM_ICE_HWKM_WRAPPED_KEY_SIZE(ice->hwkm_version)); if (err) return err; - return QCOM_ICE_HWKM_WRAPPED_KEY_SIZE; + return QCOM_ICE_HWKM_WRAPPED_KEY_SIZE(ice->hwkm_version); } EXPORT_SYMBOL_GPL(qcom_ice_generate_key); @@ -478,13 +513,13 @@ int qcom_ice_prepare_key(struct qcom_ice *ice, int err; err = qcom_scm_prepare_ice_key(lt_key, lt_key_size, - eph_key, QCOM_ICE_HWKM_WRAPPED_KEY_SIZE); + eph_key, QCOM_ICE_HWKM_WRAPPED_KEY_SIZE(ice->hwkm_version)); if (err == -EIO || err == -EINVAL) err = -EBADMSG; /* probably invalid key */ if (err) return err; - return QCOM_ICE_HWKM_WRAPPED_KEY_SIZE; + return QCOM_ICE_HWKM_WRAPPED_KEY_SIZE(ice->hwkm_version); } EXPORT_SYMBOL_GPL(qcom_ice_prepare_key); @@ -506,11 +541,11 @@ int qcom_ice_import_key(struct qcom_ice *ice, int err; err = qcom_scm_import_ice_key(raw_key, raw_key_size, - lt_key, QCOM_ICE_HWKM_WRAPPED_KEY_SIZE); + lt_key, QCOM_ICE_HWKM_WRAPPED_KEY_SIZE(ice->hwkm_version)); if (err) return err; - return QCOM_ICE_HWKM_WRAPPED_KEY_SIZE; + return QCOM_ICE_HWKM_WRAPPED_KEY_SIZE(ice->hwkm_version); } EXPORT_SYMBOL_GPL(qcom_ice_import_key); From 8d9dc964ad1778ee8a42f02cd43b6c4aa10db375 Mon Sep 17 00:00:00 2001 From: Xueyao An Date: Mon, 27 Oct 2025 15:09:53 +0800 Subject: [PATCH 0126/2333] FROMLIST: arm64: dts: qcom: hamoa-iot-som: Unreserve GPIOs blocking SPI11 access GPIOs 44-47 were previously reserved, preventing Linux from accessing SPI11 (qupv1_se3). Since there is no TZ use case for these pins on Linux, they can be safely unreserved. Removing them from the reserved list resolves the SPI11 access issue for Linux. Link: https://lore.kernel.org/linux-arm-msm/20251106102448.3585332-1-xueyao.an@oss.qualcomm.com/ Signed-off-by: Xueyao An --- arch/arm64/boot/dts/qcom/hamoa-iot-som.dtsi | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/hamoa-iot-som.dtsi b/arch/arm64/boot/dts/qcom/hamoa-iot-som.dtsi index 1aead50b8920b..107ea8045f552 100644 --- a/arch/arm64/boot/dts/qcom/hamoa-iot-som.dtsi +++ b/arch/arm64/boot/dts/qcom/hamoa-iot-som.dtsi @@ -451,8 +451,7 @@ }; &tlmm { - gpio-reserved-ranges = <34 2>, /* TPM LP & INT */ - <44 4>; /* SPI (TPM) */ + gpio-reserved-ranges = <34 2>; /* TPM LP & INT */ pcie4_default: pcie4-default-state { clkreq-n-pins { From b7a0a546af4d100b99c3260f70dfe6f95b51efe3 Mon Sep 17 00:00:00 2001 From: Khalid Faisal Ansari Date: Tue, 11 Nov 2025 21:10:52 +0530 Subject: [PATCH 0127/2333] FROMLIST: arm64: dts: qcom: hamoa-iot-evk: Enable TPM (ST33) on SPI11 Enable ST33HTPM TPM over SPI11 on the Hamoa IoT EVK by adding the required SPI and TPM nodes. Link: https://lore.kernel.org/all/20251112-arm64-dts-qcom-hamoa-iot-evk-enable-st33-tpm-on-spi11-v3-1-39b19eb55cc3@oss.qualcomm.com/ Signed-off-by: Khalid Faisal Ansari --- arch/arm64/boot/dts/qcom/hamoa-iot-evk.dts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/hamoa-iot-evk.dts b/arch/arm64/boot/dts/qcom/hamoa-iot-evk.dts index 7556ec640f1a1..bcc249d33beea 100644 --- a/arch/arm64/boot/dts/qcom/hamoa-iot-evk.dts +++ b/arch/arm64/boot/dts/qcom/hamoa-iot-evk.dts @@ -960,6 +960,16 @@ vdd3-supply = <&vreg_l8b_3p0>; }; +&spi11 { + status = "okay"; + + tpm@0 { + compatible = "st,st33htpm-spi", "tcg,tpm_tis-spi"; + reg = <0>; + spi-max-frequency = <20000000>; + }; +}; + &swr0 { status = "okay"; From e6140349dfc670e22f2507bb8f053be15b353ddd Mon Sep 17 00:00:00 2001 From: Gaurav Kashyap Date: Wed, 24 Sep 2025 16:29:37 -0700 Subject: [PATCH 0128/2333] FROMGIT: dt-bindings: crypto: qcom,inline-crypto-engine: Document the kaanapali ICE Document the Inline Crypto Engine (ICE) on the kaanapali platform. Signed-off-by: Gaurav Kashyap Signed-off-by: Jingyi Wang Reviewed-by: Eugen Hristev Reviewed-by: Krzysztof Kozlowski Signed-off-by: Yijie Yang Link: https://lore.kernel.org/all/20250924-knp-ice-v1-1-1adfc2d9e83c@oss.qualcomm.com/ --- .../devicetree/bindings/crypto/qcom,inline-crypto-engine.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/crypto/qcom,inline-crypto-engine.yaml b/Documentation/devicetree/bindings/crypto/qcom,inline-crypto-engine.yaml index 08fe6a707a371..c3408dcf5d205 100644 --- a/Documentation/devicetree/bindings/crypto/qcom,inline-crypto-engine.yaml +++ b/Documentation/devicetree/bindings/crypto/qcom,inline-crypto-engine.yaml @@ -13,6 +13,7 @@ properties: compatible: items: - enum: + - qcom,kaanapali-inline-crypto-engine - qcom,qcs8300-inline-crypto-engine - qcom,sa8775p-inline-crypto-engine - qcom,sc7180-inline-crypto-engine From a83ff0190ba2cd904e93dc3cafa005a4567d941c Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Thu, 6 Nov 2025 12:33:57 +0100 Subject: [PATCH 0129/2333] FROMLIST: dmaengine: Add DMA_PREP_LOCK/DMA_PREP_UNLOCK flags Some DMA engines may be accessed from linux and the TrustZone simultaneously. In order to allow synchronization, add lock and unlock flags for the command descriptor that allow the caller to request the controller to be locked for the duration of the transaction in an implementation-dependent way. Link: https://lore.kernel.org/lkml/20251106-qcom-qce-cmd-descr-v8-1-ecddca23ca26@linaro.org/ Signed-off-by: Bartosz Golaszewski --- Documentation/driver-api/dmaengine/provider.rst | 9 +++++++++ include/linux/dmaengine.h | 6 ++++++ 2 files changed, 15 insertions(+) diff --git a/Documentation/driver-api/dmaengine/provider.rst b/Documentation/driver-api/dmaengine/provider.rst index 1594598b33178..6428211405472 100644 --- a/Documentation/driver-api/dmaengine/provider.rst +++ b/Documentation/driver-api/dmaengine/provider.rst @@ -630,6 +630,15 @@ DMA_CTRL_REUSE - This flag is only supported if the channel reports the DMA_LOAD_EOT capability. +- DMA_PREP_LOCK + + - If set, the DMA controller will be locked for the duration of the current + transaction. + +- DMA_PREP_UNLOCK + + - If set, DMA will release he controller lock. + General Design Notes ==================== diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h index 6de7c05d6bd8c..2a2b97fd43ac4 100644 --- a/include/linux/dmaengine.h +++ b/include/linux/dmaengine.h @@ -200,6 +200,10 @@ struct dma_vec { * transaction is marked with DMA_PREP_REPEAT will cause the new transaction * to never be processed and stay in the issued queue forever. The flag is * ignored if the previous transaction is not a repeated transaction. + * @DMA_PREP_LOCK: tell the driver that there is a lock bit set on command + * descriptor. + * @DMA_PREP_UNLOCK: tell the driver that there is a un-lock bit set on command + * descriptor. */ enum dma_ctrl_flags { DMA_PREP_INTERRUPT = (1 << 0), @@ -212,6 +216,8 @@ enum dma_ctrl_flags { DMA_PREP_CMD = (1 << 7), DMA_PREP_REPEAT = (1 << 8), DMA_PREP_LOAD_EOT = (1 << 9), + DMA_PREP_LOCK = (1 << 10), + DMA_PREP_UNLOCK = (1 << 11), }; /** From 0cdf5c8caee21a637a5da6369bbacc9129701de3 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Thu, 6 Nov 2025 12:33:58 +0100 Subject: [PATCH 0130/2333] FROMLIST: dmaengine: qcom: bam_dma: Extend the driver's device match data In preparation for supporting the pipe locking feature flag, extend the amount of information we can carry in device match data: create a separate structure and make the register information one of its fields. This way, in subsequent patches, it will be just a matter of adding a new field to the device data. Link: https://lore.kernel.org/lkml/20251106-qcom-qce-cmd-descr-v8-2-ecddca23ca26@linaro.org/ Reviewed-by: Dmitry Baryshkov Signed-off-by: Bartosz Golaszewski --- drivers/dma/qcom/bam_dma.c | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/drivers/dma/qcom/bam_dma.c b/drivers/dma/qcom/bam_dma.c index bbc3276992bb0..39a700fe98054 100644 --- a/drivers/dma/qcom/bam_dma.c +++ b/drivers/dma/qcom/bam_dma.c @@ -111,6 +111,10 @@ struct reg_offset_data { unsigned int pipe_mult, evnt_mult, ee_mult; }; +struct bam_device_data { + const struct reg_offset_data *reg_info; +}; + static const struct reg_offset_data bam_v1_3_reg_info[] = { [BAM_CTRL] = { 0x0F80, 0x00, 0x00, 0x00 }, [BAM_REVISION] = { 0x0F84, 0x00, 0x00, 0x00 }, @@ -140,6 +144,10 @@ static const struct reg_offset_data bam_v1_3_reg_info[] = { [BAM_P_FIFO_SIZES] = { 0x1020, 0x00, 0x40, 0x00 }, }; +static const struct bam_device_data bam_v1_3_data = { + .reg_info = bam_v1_3_reg_info, +}; + static const struct reg_offset_data bam_v1_4_reg_info[] = { [BAM_CTRL] = { 0x0000, 0x00, 0x00, 0x00 }, [BAM_REVISION] = { 0x0004, 0x00, 0x00, 0x00 }, @@ -169,6 +177,10 @@ static const struct reg_offset_data bam_v1_4_reg_info[] = { [BAM_P_FIFO_SIZES] = { 0x1820, 0x00, 0x1000, 0x00 }, }; +static const struct bam_device_data bam_v1_4_data = { + .reg_info = bam_v1_4_reg_info, +}; + static const struct reg_offset_data bam_v1_7_reg_info[] = { [BAM_CTRL] = { 0x00000, 0x00, 0x00, 0x00 }, [BAM_REVISION] = { 0x01000, 0x00, 0x00, 0x00 }, @@ -198,6 +210,10 @@ static const struct reg_offset_data bam_v1_7_reg_info[] = { [BAM_P_FIFO_SIZES] = { 0x13820, 0x00, 0x1000, 0x00 }, }; +static const struct bam_device_data bam_v1_7_data = { + .reg_info = bam_v1_7_reg_info, +}; + /* BAM CTRL */ #define BAM_SW_RST BIT(0) #define BAM_EN BIT(1) @@ -391,7 +407,7 @@ struct bam_device { bool powered_remotely; u32 active_channels; - const struct reg_offset_data *layout; + const struct bam_device_data *dev_data; struct clk *bamclk; int irq; @@ -409,7 +425,7 @@ struct bam_device { static inline void __iomem *bam_addr(struct bam_device *bdev, u32 pipe, enum bam_reg reg) { - const struct reg_offset_data r = bdev->layout[reg]; + const struct reg_offset_data r = bdev->dev_data->reg_info[reg]; return bdev->regs + r.base_offset + r.pipe_mult * pipe + @@ -1225,9 +1241,9 @@ static void bam_channel_init(struct bam_device *bdev, struct bam_chan *bchan, } static const struct of_device_id bam_of_match[] = { - { .compatible = "qcom,bam-v1.3.0", .data = &bam_v1_3_reg_info }, - { .compatible = "qcom,bam-v1.4.0", .data = &bam_v1_4_reg_info }, - { .compatible = "qcom,bam-v1.7.0", .data = &bam_v1_7_reg_info }, + { .compatible = "qcom,bam-v1.3.0", .data = &bam_v1_3_data }, + { .compatible = "qcom,bam-v1.4.0", .data = &bam_v1_4_data }, + { .compatible = "qcom,bam-v1.7.0", .data = &bam_v1_7_data }, {} }; @@ -1251,7 +1267,7 @@ static int bam_dma_probe(struct platform_device *pdev) return -ENODEV; } - bdev->layout = match->data; + bdev->dev_data = match->data; bdev->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(bdev->regs)) From 8c73677b93d34e31b7d32ebe42e6f85371d30f39 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Thu, 6 Nov 2025 12:33:59 +0100 Subject: [PATCH 0131/2333] FROMLIST: dmaengine: qcom: bam_dma: Add bam_pipe_lock flag support Extend the device match data with a flag indicating whether the IP supports the BAM lock/unlock feature. Set it to true on BAM IP versions 1.4.0 and above. Link: https://lore.kernel.org/lkml/20251106-qcom-qce-cmd-descr-v8-3-ecddca23ca26@linaro.org/ Signed-off-by: Bartosz Golaszewski --- drivers/dma/qcom/bam_dma.c | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/drivers/dma/qcom/bam_dma.c b/drivers/dma/qcom/bam_dma.c index 39a700fe98054..2d94794a9466b 100644 --- a/drivers/dma/qcom/bam_dma.c +++ b/drivers/dma/qcom/bam_dma.c @@ -58,6 +58,8 @@ struct bam_desc_hw { #define DESC_FLAG_EOB BIT(13) #define DESC_FLAG_NWD BIT(12) #define DESC_FLAG_CMD BIT(11) +#define DESC_FLAG_LOCK BIT(10) +#define DESC_FLAG_UNLOCK BIT(9) struct bam_async_desc { struct virt_dma_desc vd; @@ -113,6 +115,7 @@ struct reg_offset_data { struct bam_device_data { const struct reg_offset_data *reg_info; + bool bam_pipe_lock; }; static const struct reg_offset_data bam_v1_3_reg_info[] = { @@ -179,6 +182,7 @@ static const struct reg_offset_data bam_v1_4_reg_info[] = { static const struct bam_device_data bam_v1_4_data = { .reg_info = bam_v1_4_reg_info, + .bam_pipe_lock = true, }; static const struct reg_offset_data bam_v1_7_reg_info[] = { @@ -212,6 +216,7 @@ static const struct reg_offset_data bam_v1_7_reg_info[] = { static const struct bam_device_data bam_v1_7_data = { .reg_info = bam_v1_7_reg_info, + .bam_pipe_lock = true, }; /* BAM CTRL */ @@ -386,6 +391,9 @@ struct bam_chan { struct list_head desc_list; struct list_head node; + + /* Is the BAM currently locked? */ + bool locked; }; static inline struct bam_chan *to_bam_chan(struct dma_chan *common) @@ -667,6 +675,7 @@ static struct dma_async_tx_descriptor *bam_prep_slave_sg(struct dma_chan *chan, { struct bam_chan *bchan = to_bam_chan(chan); struct bam_device *bdev = bchan->bdev; + const struct bam_device_data *bdata = bdev->dev_data; struct bam_async_desc *async_desc; struct scatterlist *sg; u32 i; @@ -707,9 +716,34 @@ static struct dma_async_tx_descriptor *bam_prep_slave_sg(struct dma_chan *chan, unsigned int curr_offset = 0; do { - if (flags & DMA_PREP_CMD) + if (flags & DMA_PREP_CMD) { + if (!bdata->bam_pipe_lock && + (flags & (DMA_PREP_LOCK | DMA_PREP_UNLOCK))) { + dev_err(bdev->dev, "Device doesn't support BAM locking\n"); + return NULL; + } + desc->flags |= cpu_to_le16(DESC_FLAG_CMD); + if (bdata->bam_pipe_lock && (flags & DMA_PREP_LOCK)) { + if (bchan->locked) { + dev_err(bdev->dev, "BAM already locked\n"); + return NULL; + } + + desc->flags |= cpu_to_le16(DESC_FLAG_LOCK); + bchan->locked = true; + } else if (bdata->bam_pipe_lock && (flags & DMA_PREP_UNLOCK)) { + if (!bchan->locked) { + dev_err(bdev->dev, "BAM is not locked\n"); + return NULL; + } + + desc->flags |= cpu_to_le16(DESC_FLAG_UNLOCK); + bchan->locked = false; + } + } + desc->addr = cpu_to_le32(sg_dma_address(sg) + curr_offset); From 5c3f316019055b0659180bb929712428cd0fe36f Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Thu, 6 Nov 2025 12:34:00 +0100 Subject: [PATCH 0132/2333] FROMLIST: crypto: qce - Include algapi.h in the core.h header The header defines a struct embedding struct crypto_queue whose size needs to be known and which is defined in crypto/algapi.h. Move the inclusion from core.c to core.h. Link: https://lore.kernel.org/lkml/20251106-qcom-qce-cmd-descr-v8-4-ecddca23ca26@linaro.org/ Signed-off-by: Bartosz Golaszewski --- drivers/crypto/qce/core.c | 1 - drivers/crypto/qce/core.h | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/crypto/qce/core.c b/drivers/crypto/qce/core.c index e95e84486d9ae..3114b7f458de0 100644 --- a/drivers/crypto/qce/core.c +++ b/drivers/crypto/qce/core.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include "core.h" diff --git a/drivers/crypto/qce/core.h b/drivers/crypto/qce/core.h index eb6fa7a8b64a8..f092ce2d3b04a 100644 --- a/drivers/crypto/qce/core.h +++ b/drivers/crypto/qce/core.h @@ -8,6 +8,7 @@ #include #include +#include #include "dma.h" From 8510eeef7dfdacfb3367b75492c37ea3f07b02e8 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Thu, 6 Nov 2025 12:34:01 +0100 Subject: [PATCH 0133/2333] FROMLIST: crypto: qce - Remove unused ignore_buf It's unclear what the purpose of this field is. It has been here since the initial commit but without any explanation. The driver works fine without it. We still keep allocating more space in the result buffer, we just don't need to store its address. While at it: move the QCE_IGNORE_BUF_SZ definition into dma.c as it's not used outside of this compilation unit. Link: https://lore.kernel.org/lkml/20251106-qcom-qce-cmd-descr-v8-5-ecddca23ca26@linaro.org/ Signed-off-by: Bartosz Golaszewski --- drivers/crypto/qce/dma.c | 4 ++-- drivers/crypto/qce/dma.h | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/crypto/qce/dma.c b/drivers/crypto/qce/dma.c index 1dec7aea852dd..f9581d53fe403 100644 --- a/drivers/crypto/qce/dma.c +++ b/drivers/crypto/qce/dma.c @@ -9,6 +9,8 @@ #include "dma.h" +#define QCE_IGNORE_BUF_SZ (2 * QCE_BAM_BURST_SIZE) + static void qce_dma_release(void *data) { struct qce_dma_data *dma = data; @@ -39,8 +41,6 @@ int devm_qce_dma_request(struct device *dev, struct qce_dma_data *dma) goto error_nomem; } - dma->ignore_buf = dma->result_buf + QCE_RESULT_BUF_SZ; - return devm_add_action_or_reset(dev, qce_dma_release, dma); error_nomem: diff --git a/drivers/crypto/qce/dma.h b/drivers/crypto/qce/dma.h index 31629185000e1..fc337c435cd14 100644 --- a/drivers/crypto/qce/dma.h +++ b/drivers/crypto/qce/dma.h @@ -23,7 +23,6 @@ struct qce_result_dump { u32 status2; }; -#define QCE_IGNORE_BUF_SZ (2 * QCE_BAM_BURST_SIZE) #define QCE_RESULT_BUF_SZ \ ALIGN(sizeof(struct qce_result_dump), QCE_BAM_BURST_SIZE) @@ -31,7 +30,6 @@ struct qce_dma_data { struct dma_chan *txchan; struct dma_chan *rxchan; struct qce_result_dump *result_buf; - void *ignore_buf; }; int devm_qce_dma_request(struct device *dev, struct qce_dma_data *dma); From 98e75fcdb05b7a04c4f8e4be4ee23ae35a6d6eda Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Thu, 6 Nov 2025 12:34:02 +0100 Subject: [PATCH 0134/2333] FROMLIST: crypto: qce - Simplify arguments of devm_qce_dma_request() This function can extract all the information it needs from struct qce_device alone so simplify its arguments. This is done in preparation for adding support for register I/O over DMA which will require accessing even more fields from struct qce_device. Link: https://lore.kernel.org/lkml/20251106-qcom-qce-cmd-descr-v8-6-ecddca23ca26@linaro.org/ Signed-off-by: Bartosz Golaszewski --- drivers/crypto/qce/core.c | 2 +- drivers/crypto/qce/dma.c | 5 ++++- drivers/crypto/qce/dma.h | 4 +++- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/crypto/qce/core.c b/drivers/crypto/qce/core.c index 3114b7f458de0..aac65041f5852 100644 --- a/drivers/crypto/qce/core.c +++ b/drivers/crypto/qce/core.c @@ -227,7 +227,7 @@ static int qce_crypto_probe(struct platform_device *pdev) if (ret) return ret; - ret = devm_qce_dma_request(qce->dev, &qce->dma); + ret = devm_qce_dma_request(qce); if (ret) return ret; diff --git a/drivers/crypto/qce/dma.c b/drivers/crypto/qce/dma.c index f9581d53fe403..4c15dd8bbeb85 100644 --- a/drivers/crypto/qce/dma.c +++ b/drivers/crypto/qce/dma.c @@ -7,6 +7,7 @@ #include #include +#include "core.h" #include "dma.h" #define QCE_IGNORE_BUF_SZ (2 * QCE_BAM_BURST_SIZE) @@ -20,8 +21,10 @@ static void qce_dma_release(void *data) kfree(dma->result_buf); } -int devm_qce_dma_request(struct device *dev, struct qce_dma_data *dma) +int devm_qce_dma_request(struct qce_device *qce) { + struct qce_dma_data *dma = &qce->dma; + struct device *dev = qce->dev; int ret; dma->txchan = dma_request_chan(dev, "tx"); diff --git a/drivers/crypto/qce/dma.h b/drivers/crypto/qce/dma.h index fc337c435cd14..483789d9fa98e 100644 --- a/drivers/crypto/qce/dma.h +++ b/drivers/crypto/qce/dma.h @@ -8,6 +8,8 @@ #include +struct qce_device; + /* maximum data transfer block size between BAM and CE */ #define QCE_BAM_BURST_SIZE 64 @@ -32,7 +34,7 @@ struct qce_dma_data { struct qce_result_dump *result_buf; }; -int devm_qce_dma_request(struct device *dev, struct qce_dma_data *dma); +int devm_qce_dma_request(struct qce_device *qce); int qce_dma_prep_sgs(struct qce_dma_data *dma, struct scatterlist *sg_in, int in_ents, struct scatterlist *sg_out, int out_ents, dma_async_tx_callback cb, void *cb_param); From ca60d4f14a1953f60694b1fac7bbb4483a37f487 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Thu, 6 Nov 2025 12:34:03 +0100 Subject: [PATCH 0135/2333] FROMLIST: crypto: qce - Use existing devres APIs in devm_qce_dma_request() Switch to devm_kmalloc() and devm_dma_alloc_chan() in devm_qce_dma_request(). This allows us to drop two labels and shrink the function. Link: https://lore.kernel.org/lkml/20251106-qcom-qce-cmd-descr-v8-7-ecddca23ca26@linaro.org/ Signed-off-by: Bartosz Golaszewski --- drivers/crypto/qce/dma.c | 37 ++++++++----------------------------- 1 file changed, 8 insertions(+), 29 deletions(-) diff --git a/drivers/crypto/qce/dma.c b/drivers/crypto/qce/dma.c index 4c15dd8bbeb85..bfa54d3401ca0 100644 --- a/drivers/crypto/qce/dma.c +++ b/drivers/crypto/qce/dma.c @@ -12,45 +12,24 @@ #define QCE_IGNORE_BUF_SZ (2 * QCE_BAM_BURST_SIZE) -static void qce_dma_release(void *data) -{ - struct qce_dma_data *dma = data; - - dma_release_channel(dma->txchan); - dma_release_channel(dma->rxchan); - kfree(dma->result_buf); -} - int devm_qce_dma_request(struct qce_device *qce) { struct qce_dma_data *dma = &qce->dma; struct device *dev = qce->dev; - int ret; - dma->txchan = dma_request_chan(dev, "tx"); + dma->txchan = devm_dma_request_chan(dev, "tx"); if (IS_ERR(dma->txchan)) return PTR_ERR(dma->txchan); - dma->rxchan = dma_request_chan(dev, "rx"); - if (IS_ERR(dma->rxchan)) { - ret = PTR_ERR(dma->rxchan); - goto error_rx; - } - - dma->result_buf = kmalloc(QCE_RESULT_BUF_SZ + QCE_IGNORE_BUF_SZ, - GFP_KERNEL); - if (!dma->result_buf) { - ret = -ENOMEM; - goto error_nomem; - } + dma->rxchan = devm_dma_request_chan(dev, "rx"); + if (IS_ERR(dma->rxchan)) + return PTR_ERR(dma->rxchan); - return devm_add_action_or_reset(dev, qce_dma_release, dma); + dma->result_buf = devm_kmalloc(dev, QCE_RESULT_BUF_SZ + QCE_IGNORE_BUF_SZ, GFP_KERNEL); + if (!dma->result_buf) + return -ENOMEM; -error_nomem: - dma_release_channel(dma->rxchan); -error_rx: - dma_release_channel(dma->txchan); - return ret; + return 0; } struct scatterlist * From 605c3eb0f498a858a34f1c91d9b9e26e6210ef4b Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Thu, 6 Nov 2025 12:34:04 +0100 Subject: [PATCH 0136/2333] FROMLIST: crypto: qce - Map crypto memory for DMA As the first step in converting the driver to using DMA for register I/O, let's map the crypto memory range. Link: https://lore.kernel.org/lkml/20251106-qcom-qce-cmd-descr-v8-8-ecddca23ca26@linaro.org/ Signed-off-by: Bartosz Golaszewski --- drivers/crypto/qce/core.c | 25 +++++++++++++++++++++++-- drivers/crypto/qce/core.h | 6 ++++++ 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/drivers/crypto/qce/core.c b/drivers/crypto/qce/core.c index aac65041f5852..e486d366c0d63 100644 --- a/drivers/crypto/qce/core.c +++ b/drivers/crypto/qce/core.c @@ -186,10 +186,19 @@ static int qce_check_version(struct qce_device *qce) return 0; } +static void qce_crypto_unmap_dma(void *data) +{ + struct qce_device *qce = data; + + dma_unmap_resource(qce->dev, qce->base_dma, qce->dma_size, + DMA_BIDIRECTIONAL, 0); +} + static int qce_crypto_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct qce_device *qce; + struct resource *res; int ret; qce = devm_kzalloc(dev, sizeof(*qce), GFP_KERNEL); @@ -199,7 +208,7 @@ static int qce_crypto_probe(struct platform_device *pdev) qce->dev = dev; platform_set_drvdata(pdev, qce); - qce->base = devm_platform_ioremap_resource(pdev, 0); + qce->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(qce->base)) return PTR_ERR(qce->base); @@ -245,7 +254,19 @@ static int qce_crypto_probe(struct platform_device *pdev) qce->async_req_enqueue = qce_async_request_enqueue; qce->async_req_done = qce_async_request_done; - return devm_qce_register_algs(qce); + ret = devm_qce_register_algs(qce); + if (ret) + return ret; + + qce->dma_size = resource_size(res); + qce->base_dma = dma_map_resource(dev, res->start, qce->dma_size, + DMA_BIDIRECTIONAL, 0); + qce->base_phys = res->start; + ret = dma_mapping_error(dev, qce->base_dma); + if (ret) + return ret; + + return devm_add_action_or_reset(qce->dev, qce_crypto_unmap_dma, qce); } static const struct of_device_id qce_crypto_of_match[] = { diff --git a/drivers/crypto/qce/core.h b/drivers/crypto/qce/core.h index f092ce2d3b04a..a80e12eac6c87 100644 --- a/drivers/crypto/qce/core.h +++ b/drivers/crypto/qce/core.h @@ -27,6 +27,9 @@ * @dma: pointer to dma data * @burst_size: the crypto burst size * @pipe_pair_id: which pipe pair id the device using + * @base_dma: base DMA address + * @base_phys: base physical address + * @dma_size: size of memory mapped for DMA * @async_req_enqueue: invoked by every algorithm to enqueue a request * @async_req_done: invoked by every algorithm to finish its request */ @@ -43,6 +46,9 @@ struct qce_device { struct qce_dma_data dma; int burst_size; unsigned int pipe_pair_id; + dma_addr_t base_dma; + phys_addr_t base_phys; + size_t dma_size; int (*async_req_enqueue)(struct qce_device *qce, struct crypto_async_request *req); void (*async_req_done)(struct qce_device *qce, int ret); From 8e41df4b2596102b4eefb4674ac1231d7731e105 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Thu, 6 Nov 2025 12:34:05 +0100 Subject: [PATCH 0137/2333] FROMLIST: crypto: qce - Add BAM DMA support for crypto register I/O Implement the infrastructure for performing register I/O over BAM DMA, not CPU. No functional change yet. Link: https://lore.kernel.org/lkml/20251106-qcom-qce-cmd-descr-v8-9-ecddca23ca26@linaro.org/ Signed-off-by: Bartosz Golaszewski --- drivers/crypto/qce/core.h | 4 ++ drivers/crypto/qce/dma.c | 109 ++++++++++++++++++++++++++++++++++++++ drivers/crypto/qce/dma.h | 5 ++ 3 files changed, 118 insertions(+) diff --git a/drivers/crypto/qce/core.h b/drivers/crypto/qce/core.h index a80e12eac6c87..d238097f834e4 100644 --- a/drivers/crypto/qce/core.h +++ b/drivers/crypto/qce/core.h @@ -30,6 +30,8 @@ * @base_dma: base DMA address * @base_phys: base physical address * @dma_size: size of memory mapped for DMA + * @read_buf: Buffer for DMA to write back to + * @read_buf_dma: Mapped address of the read buffer * @async_req_enqueue: invoked by every algorithm to enqueue a request * @async_req_done: invoked by every algorithm to finish its request */ @@ -49,6 +51,8 @@ struct qce_device { dma_addr_t base_dma; phys_addr_t base_phys; size_t dma_size; + __le32 *read_buf; + dma_addr_t read_buf_dma; int (*async_req_enqueue)(struct qce_device *qce, struct crypto_async_request *req); void (*async_req_done)(struct qce_device *qce, int ret); diff --git a/drivers/crypto/qce/dma.c b/drivers/crypto/qce/dma.c index bfa54d3401ca0..9bb9a8246cb05 100644 --- a/drivers/crypto/qce/dma.c +++ b/drivers/crypto/qce/dma.c @@ -4,6 +4,8 @@ */ #include +#include +#include #include #include @@ -11,6 +13,98 @@ #include "dma.h" #define QCE_IGNORE_BUF_SZ (2 * QCE_BAM_BURST_SIZE) +#define QCE_BAM_CMD_SGL_SIZE 128 +#define QCE_BAM_CMD_ELEMENT_SIZE 128 +#define QCE_MAX_REG_READ 8 + +struct qce_desc_info { + struct dma_async_tx_descriptor *dma_desc; + enum dma_data_direction dir; +}; + +struct qce_bam_transaction { + struct bam_cmd_element bam_ce[QCE_BAM_CMD_ELEMENT_SIZE]; + struct scatterlist wr_sgl[QCE_BAM_CMD_SGL_SIZE]; + struct qce_desc_info *desc; + u32 bam_ce_idx; + u32 pre_bam_ce_idx; + u32 wr_sgl_cnt; +}; + +void qce_clear_bam_transaction(struct qce_device *qce) +{ + struct qce_bam_transaction *bam_txn = qce->dma.bam_txn; + + bam_txn->bam_ce_idx = 0; + bam_txn->wr_sgl_cnt = 0; + bam_txn->bam_ce_idx = 0; + bam_txn->pre_bam_ce_idx = 0; +} + +int qce_submit_cmd_desc(struct qce_device *qce) +{ + struct qce_desc_info *qce_desc = qce->dma.bam_txn->desc; + struct qce_bam_transaction *bam_txn = qce->dma.bam_txn; + struct dma_async_tx_descriptor *dma_desc; + struct dma_chan *chan = qce->dma.rxchan; + unsigned long attrs = DMA_PREP_CMD; + dma_cookie_t cookie; + unsigned int mapped; + int ret; + + mapped = dma_map_sg_attrs(qce->dev, bam_txn->wr_sgl, bam_txn->wr_sgl_cnt, + DMA_TO_DEVICE, attrs); + if (!mapped) + return -ENOMEM; + + dma_desc = dmaengine_prep_slave_sg(chan, bam_txn->wr_sgl, bam_txn->wr_sgl_cnt, + DMA_MEM_TO_DEV, attrs); + if (!dma_desc) { + dma_unmap_sg(qce->dev, bam_txn->wr_sgl, bam_txn->wr_sgl_cnt, DMA_TO_DEVICE); + return -ENOMEM; + } + + qce_desc->dma_desc = dma_desc; + cookie = dmaengine_submit(qce_desc->dma_desc); + + ret = dma_submit_error(cookie); + if (ret) + return ret; + + qce_dma_issue_pending(&qce->dma); + + return 0; +} + +static void qce_prep_dma_cmd_desc(struct qce_device *qce, struct qce_dma_data *dma, + unsigned int addr, void *buf) +{ + struct qce_bam_transaction *bam_txn = dma->bam_txn; + struct bam_cmd_element *bam_ce_buf; + int bam_ce_size, cnt, idx; + + idx = bam_txn->bam_ce_idx; + bam_ce_buf = &bam_txn->bam_ce[idx]; + bam_prep_ce_le32(bam_ce_buf, addr, BAM_WRITE_COMMAND, *((__le32 *)buf)); + + bam_ce_buf = &bam_txn->bam_ce[bam_txn->pre_bam_ce_idx]; + bam_txn->bam_ce_idx++; + bam_ce_size = (bam_txn->bam_ce_idx - bam_txn->pre_bam_ce_idx) * sizeof(*bam_ce_buf); + + cnt = bam_txn->wr_sgl_cnt; + + sg_set_buf(&bam_txn->wr_sgl[cnt], bam_ce_buf, bam_ce_size); + + ++bam_txn->wr_sgl_cnt; + bam_txn->pre_bam_ce_idx = bam_txn->bam_ce_idx; +} + +void qce_write_dma(struct qce_device *qce, unsigned int offset, u32 val) +{ + unsigned int reg_addr = ((unsigned int)(qce->base_phys) + offset); + + qce_prep_dma_cmd_desc(qce, &qce->dma, reg_addr, &val); +} int devm_qce_dma_request(struct qce_device *qce) { @@ -29,6 +123,21 @@ int devm_qce_dma_request(struct qce_device *qce) if (!dma->result_buf) return -ENOMEM; + dma->bam_txn = devm_kzalloc(dev, sizeof(*dma->bam_txn), GFP_KERNEL); + if (!dma->bam_txn) + return -ENOMEM; + + dma->bam_txn->desc = devm_kzalloc(dev, sizeof(*dma->bam_txn->desc), GFP_KERNEL); + if (!dma->bam_txn->desc) + return -ENOMEM; + + sg_init_table(dma->bam_txn->wr_sgl, QCE_BAM_CMD_SGL_SIZE); + + qce->read_buf = dmam_alloc_coherent(qce->dev, QCE_MAX_REG_READ * sizeof(*qce->read_buf), + &qce->read_buf_dma, GFP_KERNEL); + if (!qce->read_buf) + return -ENOMEM; + return 0; } diff --git a/drivers/crypto/qce/dma.h b/drivers/crypto/qce/dma.h index 483789d9fa98e..f05dfa9e6b25b 100644 --- a/drivers/crypto/qce/dma.h +++ b/drivers/crypto/qce/dma.h @@ -8,6 +8,7 @@ #include +struct qce_bam_transaction; struct qce_device; /* maximum data transfer block size between BAM and CE */ @@ -32,6 +33,7 @@ struct qce_dma_data { struct dma_chan *txchan; struct dma_chan *rxchan; struct qce_result_dump *result_buf; + struct qce_bam_transaction *bam_txn; }; int devm_qce_dma_request(struct qce_device *qce); @@ -43,5 +45,8 @@ int qce_dma_terminate_all(struct qce_dma_data *dma); struct scatterlist * qce_sgtable_add(struct sg_table *sgt, struct scatterlist *sg_add, unsigned int max_len); +void qce_write_dma(struct qce_device *qce, unsigned int offset, u32 val); +int qce_submit_cmd_desc(struct qce_device *qce); +void qce_clear_bam_transaction(struct qce_device *qce); #endif /* _DMA_H_ */ From cb614677618f6e52ce95ca6ec2b284277f776b11 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Thu, 6 Nov 2025 12:34:06 +0100 Subject: [PATCH 0138/2333] FROMLIST: crypto: qce - Add support for BAM locking Implement the infrastructure for using the new DMA controller lock/unlock feature of the BAM driver. No functional change for now. Link: https://lore.kernel.org/lkml/20251106-qcom-qce-cmd-descr-v8-10-ecddca23ca26@linaro.org/ Signed-off-by: Bartosz Golaszewski --- drivers/crypto/qce/common.c | 18 ++++++++++++++++++ drivers/crypto/qce/dma.c | 19 +++++++++++++++++-- drivers/crypto/qce/dma.h | 4 ++++ 3 files changed, 39 insertions(+), 2 deletions(-) diff --git a/drivers/crypto/qce/common.c b/drivers/crypto/qce/common.c index 04253a8d33409..74756c222fed6 100644 --- a/drivers/crypto/qce/common.c +++ b/drivers/crypto/qce/common.c @@ -593,3 +593,21 @@ void qce_get_version(struct qce_device *qce, u32 *major, u32 *minor, u32 *step) *minor = (val & CORE_MINOR_REV_MASK) >> CORE_MINOR_REV_SHIFT; *step = (val & CORE_STEP_REV_MASK) >> CORE_STEP_REV_SHIFT; } + +int qce_bam_lock(struct qce_device *qce) +{ + qce_clear_bam_transaction(qce); + /* Dummy write to acquire the lock on the BAM pipe. */ + qce_write(qce, REG_AUTH_SEG_CFG, 0); + + return qce_submit_cmd_desc_lock(qce); +} + +int qce_bam_unlock(struct qce_device *qce) +{ + qce_clear_bam_transaction(qce); + /* Dummy write to release the lock on the BAM pipe. */ + qce_write(qce, REG_AUTH_SEG_CFG, 0); + + return qce_submit_cmd_desc_unlock(qce); +} diff --git a/drivers/crypto/qce/dma.c b/drivers/crypto/qce/dma.c index 9bb9a8246cb05..bfdc1397a289b 100644 --- a/drivers/crypto/qce/dma.c +++ b/drivers/crypto/qce/dma.c @@ -41,13 +41,13 @@ void qce_clear_bam_transaction(struct qce_device *qce) bam_txn->pre_bam_ce_idx = 0; } -int qce_submit_cmd_desc(struct qce_device *qce) +static int qce_do_submit_cmd_desc(struct qce_device *qce, unsigned long flags) { struct qce_desc_info *qce_desc = qce->dma.bam_txn->desc; struct qce_bam_transaction *bam_txn = qce->dma.bam_txn; struct dma_async_tx_descriptor *dma_desc; struct dma_chan *chan = qce->dma.rxchan; - unsigned long attrs = DMA_PREP_CMD; + unsigned long attrs = DMA_PREP_CMD | flags; dma_cookie_t cookie; unsigned int mapped; int ret; @@ -76,6 +76,21 @@ int qce_submit_cmd_desc(struct qce_device *qce) return 0; } +int qce_submit_cmd_desc(struct qce_device *qce) +{ + return qce_do_submit_cmd_desc(qce, 0); +} + +int qce_submit_cmd_desc_lock(struct qce_device *qce) +{ + return qce_do_submit_cmd_desc(qce, DMA_PREP_LOCK); +} + +int qce_submit_cmd_desc_unlock(struct qce_device *qce) +{ + return qce_do_submit_cmd_desc(qce, DMA_PREP_UNLOCK); +} + static void qce_prep_dma_cmd_desc(struct qce_device *qce, struct qce_dma_data *dma, unsigned int addr, void *buf) { diff --git a/drivers/crypto/qce/dma.h b/drivers/crypto/qce/dma.h index f05dfa9e6b25b..4b3ee17db72e2 100644 --- a/drivers/crypto/qce/dma.h +++ b/drivers/crypto/qce/dma.h @@ -47,6 +47,10 @@ qce_sgtable_add(struct sg_table *sgt, struct scatterlist *sg_add, unsigned int max_len); void qce_write_dma(struct qce_device *qce, unsigned int offset, u32 val); int qce_submit_cmd_desc(struct qce_device *qce); +int qce_submit_cmd_desc_lock(struct qce_device *qce); +int qce_submit_cmd_desc_unlock(struct qce_device *qce); void qce_clear_bam_transaction(struct qce_device *qce); +int qce_bam_lock(struct qce_device *qce); +int qce_bam_unlock(struct qce_device *qce); #endif /* _DMA_H_ */ From 0ff2ae7f2e708a083b489a9a4a34c07bd701aec1 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Thu, 6 Nov 2025 12:34:07 +0100 Subject: [PATCH 0139/2333] FROMLIST: crypto: qce - Switch to using BAM DMA for crypto I/O With everything else in place, we can now switch to actually using the BAM DMA for register I/O with DMA engine locking. Link: https://lore.kernel.org/lkml/20251106-qcom-qce-cmd-descr-v8-11-ecddca23ca26@linaro.org/ Signed-off-by: Bartosz Golaszewski --- drivers/crypto/qce/aead.c | 10 ++++++++++ drivers/crypto/qce/common.c | 21 ++++++++++----------- drivers/crypto/qce/sha.c | 8 ++++++++ drivers/crypto/qce/skcipher.c | 7 +++++++ 4 files changed, 35 insertions(+), 11 deletions(-) diff --git a/drivers/crypto/qce/aead.c b/drivers/crypto/qce/aead.c index 97b56e92ea33f..1e6e1f5bcca45 100644 --- a/drivers/crypto/qce/aead.c +++ b/drivers/crypto/qce/aead.c @@ -63,6 +63,10 @@ static void qce_aead_done(void *data) sg_free_table(&rctx->dst_tbl); } + error = qce_bam_unlock(qce); + if (error) + dev_err(qce->dev, "aead: failed to unlock the BAM\n"); + error = qce_check_status(qce, &status); if (error < 0 && (error != -EBADMSG)) dev_err(qce->dev, "aead operation error (%x)\n", status); @@ -188,6 +192,8 @@ qce_aead_ccm_prepare_buf_assoclen(struct aead_request *req) struct crypto_aead *tfm = crypto_aead_reqtfm(req); struct qce_aead_reqctx *rctx = aead_request_ctx_dma(req); struct qce_aead_ctx *ctx = crypto_aead_ctx(tfm); + struct qce_alg_template *tmpl = to_aead_tmpl(crypto_aead_reqtfm(req)); + struct qce_device *qce = tmpl->qce; unsigned int assoclen = rctx->assoclen; unsigned int adata_header_len, cryptlen, totallen; gfp_t gfp; @@ -200,6 +206,10 @@ qce_aead_ccm_prepare_buf_assoclen(struct aead_request *req) cryptlen = rctx->cryptlen; totallen = cryptlen + req->assoclen; + ret = qce_bam_lock(qce); + if (ret) + return ret; + /* Get the msg */ msg_sg = scatterwalk_ffwd(__sg, req->src, req->assoclen); diff --git a/drivers/crypto/qce/common.c b/drivers/crypto/qce/common.c index 74756c222fed6..930006aaba4ac 100644 --- a/drivers/crypto/qce/common.c +++ b/drivers/crypto/qce/common.c @@ -14,6 +14,7 @@ #include "cipher.h" #include "common.h" #include "core.h" +#include "dma.h" #include "regs-v5.h" #include "sha.h" #include "aead.h" @@ -25,7 +26,7 @@ static inline u32 qce_read(struct qce_device *qce, u32 offset) static inline void qce_write(struct qce_device *qce, u32 offset, u32 val) { - writel(val, qce->base + offset); + qce_write_dma(qce, offset, val); } static inline void qce_write_array(struct qce_device *qce, u32 offset, @@ -82,6 +83,8 @@ static void qce_setup_config(struct qce_device *qce) { u32 config; + qce_clear_bam_transaction(qce); + /* get big endianness */ config = qce_config_reg(qce, 0); @@ -90,12 +93,14 @@ static void qce_setup_config(struct qce_device *qce) qce_write(qce, REG_CONFIG, config); } -static inline void qce_crypto_go(struct qce_device *qce, bool result_dump) +static int qce_crypto_go(struct qce_device *qce, bool result_dump) { if (result_dump) qce_write(qce, REG_GOPROC, BIT(GO_SHIFT) | BIT(RESULTS_DUMP_SHIFT)); else qce_write(qce, REG_GOPROC, BIT(GO_SHIFT)); + + return qce_submit_cmd_desc(qce); } #if defined(CONFIG_CRYPTO_DEV_QCE_SHA) || defined(CONFIG_CRYPTO_DEV_QCE_AEAD) @@ -223,9 +228,7 @@ static int qce_setup_regs_ahash(struct crypto_async_request *async_req) config = qce_config_reg(qce, 1); qce_write(qce, REG_CONFIG, config); - qce_crypto_go(qce, true); - - return 0; + return qce_crypto_go(qce, true); } #endif @@ -386,9 +389,7 @@ static int qce_setup_regs_skcipher(struct crypto_async_request *async_req) config = qce_config_reg(qce, 1); qce_write(qce, REG_CONFIG, config); - qce_crypto_go(qce, true); - - return 0; + return qce_crypto_go(qce, true); } #endif @@ -535,9 +536,7 @@ static int qce_setup_regs_aead(struct crypto_async_request *async_req) qce_write(qce, REG_CONFIG, config); /* Start the process */ - qce_crypto_go(qce, !IS_CCM(flags)); - - return 0; + return qce_crypto_go(qce, !IS_CCM(flags)); } #endif diff --git a/drivers/crypto/qce/sha.c b/drivers/crypto/qce/sha.c index 71b748183cfa8..a9db92b741c90 100644 --- a/drivers/crypto/qce/sha.c +++ b/drivers/crypto/qce/sha.c @@ -60,6 +60,10 @@ static void qce_ahash_done(void *data) rctx->byte_count[0] = cpu_to_be32(result->auth_byte_count[0]); rctx->byte_count[1] = cpu_to_be32(result->auth_byte_count[1]); + error = qce_bam_unlock(qce); + if (error) + dev_err(qce->dev, "ahash: failed to unlock the BAM\n"); + error = qce_check_status(qce, &status); if (error < 0) dev_dbg(qce->dev, "ahash operation error (%x)\n", status); @@ -90,6 +94,10 @@ static int qce_ahash_async_req_handle(struct crypto_async_request *async_req) rctx->authklen = AES_KEYSIZE_128; } + ret = qce_bam_lock(qce); + if (ret) + return ret; + rctx->src_nents = sg_nents_for_len(req->src, req->nbytes); if (rctx->src_nents < 0) { dev_err(qce->dev, "Invalid numbers of src SG.\n"); diff --git a/drivers/crypto/qce/skcipher.c b/drivers/crypto/qce/skcipher.c index ffb334eb5b346..a34a0b14a959b 100644 --- a/drivers/crypto/qce/skcipher.c +++ b/drivers/crypto/qce/skcipher.c @@ -51,6 +51,9 @@ static void qce_skcipher_done(void *data) dma_unmap_sg(qce->dev, rctx->dst_sg, rctx->dst_nents, dir_dst); sg_free_table(&rctx->dst_tbl); + error = qce_bam_unlock(qce); + if (error) + dev_err(qce->dev, "skcipher: failed to unlock the BAM\n"); error = qce_check_status(qce, &status); if (error < 0) @@ -78,6 +81,10 @@ qce_skcipher_async_req_handle(struct crypto_async_request *async_req) rctx->ivsize = crypto_skcipher_ivsize(skcipher); rctx->cryptlen = req->cryptlen; + ret = qce_bam_lock(qce); + if (ret) + return ret; + diff_dst = (req->src != req->dst) ? true : false; dir_src = diff_dst ? DMA_TO_DEVICE : DMA_BIDIRECTIONAL; dir_dst = diff_dst ? DMA_FROM_DEVICE : DMA_BIDIRECTIONAL; From 6a60721fad889618c50f563bda3d8fc61e6d7fd5 Mon Sep 17 00:00:00 2001 From: Ziyue Zhang Date: Mon, 22 Sep 2025 15:55:06 +0800 Subject: [PATCH 0140/2333] FROMLIST: arm64: dts: qcom: Add PCIe3 and PCIe5 support for HAMOA-IOT-SOM platform HAMOA IoT SOM requires PCIe3 and PCIe5 connectivity for SATA controller and SDX65. Add the required sideband signals (PERST#, WAKE#, CLKREQ#), pinctrl states and power supply properties in the device tree, which PCIe3 and PCIe5 require. Link: https://lore.kernel.org/all/20251112090316.936187-2-ziyue.zhang@oss.qualcomm.com/ Signed-off-by: Ziyue Zhang Reviewed-by: Krishna Chaitanya Chundru --- arch/arm64/boot/dts/qcom/hamoa-iot-som.dtsi | 79 +++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/hamoa-iot-som.dtsi b/arch/arm64/boot/dts/qcom/hamoa-iot-som.dtsi index 107ea8045f552..8bb43e4e1dcbc 100644 --- a/arch/arm64/boot/dts/qcom/hamoa-iot-som.dtsi +++ b/arch/arm64/boot/dts/qcom/hamoa-iot-som.dtsi @@ -390,6 +390,22 @@ firmware-name = "qcom/x1e80100/gen70500_zap.mbn"; }; +&pcie3 { + pinctrl-names = "default"; + pinctrl-0 = <&pcie3_default>; + perst-gpios = <&tlmm 143 GPIO_ACTIVE_LOW>; + wake-gpios = <&tlmm 145 GPIO_ACTIVE_LOW>; + + status = "okay"; +}; + +&pcie3_phy { + vdda-phy-supply = <&vreg_l3c_0p8>; + vdda-pll-supply = <&vreg_l3e_1p2>; + + status = "okay"; +}; + &pcie4 { perst-gpios = <&tlmm 146 GPIO_ACTIVE_LOW>; wake-gpios = <&tlmm 148 GPIO_ACTIVE_LOW>; @@ -407,6 +423,23 @@ status = "okay"; }; +&pcie5 { + perst-gpios = <&tlmm 149 GPIO_ACTIVE_LOW>; + wake-gpios = <&tlmm 151 GPIO_ACTIVE_LOW>; + + pinctrl-0 = <&pcie5_default>; + pinctrl-names = "default"; + + status = "okay"; +}; + +&pcie5_phy { + vdda-phy-supply = <&vreg_l3i_0p8>; + vdda-pll-supply = <&vreg_l3e_1p2>; + + status = "okay"; +}; + &pcie6a { perst-gpios = <&tlmm 152 GPIO_ACTIVE_LOW>; wake-gpios = <&tlmm 154 GPIO_ACTIVE_LOW>; @@ -453,6 +486,29 @@ &tlmm { gpio-reserved-ranges = <34 2>; /* TPM LP & INT */ + pcie3_default: pcie3-default-state { + clkreq-n-pins { + pins = "gpio144"; + function = "pcie3_clk"; + drive-strength = <2>; + bias-pull-up; + }; + + perst-n-pins { + pins = "gpio143"; + function = "gpio"; + drive-strength = <2>; + bias-disable; + }; + + wake-n-pins { + pins = "gpio145"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; + pcie4_default: pcie4-default-state { clkreq-n-pins { pins = "gpio147"; @@ -476,6 +532,29 @@ }; }; + pcie5_default: pcie5-default-state { + clkreq-n-pins { + pins = "gpio150"; + function = "pcie5_clk"; + drive-strength = <2>; + bias-pull-up; + }; + + perst-n-pins { + pins = "gpio149"; + function = "gpio"; + drive-strength = <2>; + bias-disable; + }; + + wake-n-pins { + pins = "gpio151"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; + pcie6a_default: pcie6a-default-state { clkreq-n-pins { pins = "gpio153"; From 85bf4e6cc25178294e99ce9ec8885395ed820178 Mon Sep 17 00:00:00 2001 From: Ziyue Zhang Date: Mon, 22 Sep 2025 15:55:07 +0800 Subject: [PATCH 0141/2333] FROMLIST: arm64: dts: qcom: Add PCIe3 and PCIe5 regulators for HAMAO-IOT-EVK board HAMAO IoT EVK uses PCIe5 to connect an SDX65 module for WWAN functionality and PCIe3 to connect a SATA controller. These interfaces require multiple voltage rails: PCIe5 needs 3.3V supplied by vreg_wwan, while PCIe3 requires 12V, 3.3V, and 3.3V AUX rails, controlled via PMIC GPIOs. Add the required fixed regulators with related pin configuration, and connect them to the PCIe3 and PCIe5 ports to ensure proper power for the SDX65 module and SATA controller. Link: https://lore.kernel.org/all/20251112090316.936187-3-ziyue.zhang@oss.qualcomm.com/ Signed-off-by: Ziyue Zhang Reviewed-by: Krishna Chaitanya Chundru --- arch/arm64/boot/dts/qcom/hamoa-iot-evk.dts | 80 ++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/hamoa-iot-evk.dts b/arch/arm64/boot/dts/qcom/hamoa-iot-evk.dts index bcc249d33beea..c892622d081cd 100644 --- a/arch/arm64/boot/dts/qcom/hamoa-iot-evk.dts +++ b/arch/arm64/boot/dts/qcom/hamoa-iot-evk.dts @@ -225,6 +225,48 @@ regulator-boot-on; }; + vreg_pcie_12v: regulator-pcie-12v { + compatible = "regulator-fixed"; + + regulator-name = "VREG_PCIE_12V"; + regulator-min-microvolt = <12000000>; + regulator-max-microvolt = <12000000>; + + gpio = <&pm8550ve_8_gpios 8 GPIO_ACTIVE_HIGH>; + enable-active-high; + + pinctrl-0 = <&pcie_x8_12v>; + pinctrl-names = "default"; + }; + + vreg_pcie_3v3: regulator-pcie-3v3 { + compatible = "regulator-fixed"; + + regulator-name = "VREG_PCIE_3P3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + + gpio = <&pmc8380_3_gpios 6 GPIO_ACTIVE_HIGH>; + enable-active-high; + + pinctrl-0 = <&pm_sde7_main_3p3_en>; + pinctrl-names = "default"; + }; + + vreg_pcie_3v3_aux: regulator-pcie-3v3-aux { + compatible = "regulator-fixed"; + + regulator-name = "VREG_PCIE_3P3_AUX"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + + gpio = <&pmc8380_3_gpios 8 GPIO_ACTIVE_HIGH>; + enable-active-high; + + pinctrl-0 = <&pm_sde7_aux_3p3_en>; + pinctrl-names = "default"; + }; + /* Left unused as the retimer is not used on this board. */ vreg_rtmr0_1p15: regulator-rtmr0-1p15 { compatible = "regulator-fixed"; @@ -860,6 +902,16 @@ status = "okay"; }; +&pcie3_port { + vpcie12v-supply = <&vreg_pcie_12v>; + vpcie3v3-supply = <&vreg_pcie_3v3>; + vpcie3v3aux-supply = <&vreg_pcie_3v3_aux>; +}; + +&pcie5 { + vddpe-3v3-supply = <&vreg_wwan>; +}; + &pcie6a { vddpe-3v3-supply = <&vreg_nvme>; }; @@ -884,6 +936,17 @@ }; }; +&pm8550ve_8_gpios { + pcie_x8_12v: pcie-12v-default-state { + pins = "gpio8"; + function = "normal"; + output-enable; + output-high; + bias-pull-down; + power-source = <0>; + }; +}; + &pm8550ve_9_gpios { usb0_1p8_reg_en: usb0-1p8-reg-en-state { pins = "gpio8"; @@ -909,6 +972,23 @@ function = "normal"; }; + pm_sde7_aux_3p3_en: pcie-aux-3p3-default-state { + pins = "gpio8"; + function = "normal"; + output-enable; + output-high; + bias-pull-down; + power-source = <0>; + }; + + pm_sde7_main_3p3_en: pcie-main-3p3-default-state { + pins = "gpio6"; + function = "normal"; + output-enable; + output-high; + bias-pull-down; + power-source = <0>; + }; }; &pmc8380_5_gpios { From ede3ae7c56a3f09f3dedc2665d12b51dbbeec899 Mon Sep 17 00:00:00 2001 From: Sushrut Shree Trivedi Date: Tue, 11 Nov 2025 15:38:16 +0530 Subject: [PATCH 0142/2333] FROMLIST: arm64: dts: qcom: monaco-evk: Enable PCIe0 and PCIe1 on monaco-evk Enables PCIe0 and PCIe1 controller and phy-nodes. PCIe0 is routed to an m.2 E key connector on the mainboard for wifi attaches while PCIe1 routes to a standard PCIe x4 expansion slot. Link: https://lore.kernel.org/all/20251111-monaco-evk-pci-v1-1-8013d0d6a7ca@quicinc.com/ Signed-off-by: Sushrut Shree Trivedi --- arch/arm64/boot/dts/qcom/monaco-evk.dts | 84 +++++++++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/monaco-evk.dts b/arch/arm64/boot/dts/qcom/monaco-evk.dts index 93ce2852f689b..764fdb5545aaf 100644 --- a/arch/arm64/boot/dts/qcom/monaco-evk.dts +++ b/arch/arm64/boot/dts/qcom/monaco-evk.dts @@ -417,6 +417,44 @@ status = "okay"; }; +&pcie0 { + pinctrl-0 = <&pcie0_default_state>; + pinctrl-names = "default"; + + status = "okay"; +}; + +&pcieport0 { + reset-gpios = <&tlmm 2 GPIO_ACTIVE_LOW>; + wake-gpios = <&tlmm 0 GPIO_ACTIVE_HIGH>; +}; + +&pcie0_phy { + vdda-phy-supply = <&vreg_l6a>; + vdda-pll-supply = <&vreg_l5a>; + + status = "okay"; +}; + +&pcie1 { + pinctrl-0 = <&pcie1_default_state>; + pinctrl-names = "default"; + + status = "okay"; +}; + +&pcieport1 { + reset-gpios = <&tlmm 23 GPIO_ACTIVE_LOW>; + wake-gpios = <&tlmm 21 GPIO_ACTIVE_HIGH>; +}; + +&pcie1_phy { + vdda-phy-supply = <&vreg_l6a>; + vdda-pll-supply = <&vreg_l5a>; + + status = "okay"; +}; + &remoteproc_adsp { firmware-name = "qcom/qcs8300/adsp.mbn"; @@ -458,6 +496,52 @@ }; }; + pcie0_default_state: pcie0-default-state { + wake-pins { + pins = "gpio0"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + + clkreq-pins { + pins = "gpio1"; + function = "pcie0_clkreq"; + drive-strength = <2>; + bias-pull-up; + }; + + perst-pins { + pins = "gpio2"; + function = "gpio"; + drive-strength = <2>; + bias-pull-down; + }; + }; + + pcie1_default_state: pcie1-default-state { + wake-pins { + pins = "gpio21"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + + clkreq-pins { + pins = "gpio22"; + function = "pcie1_clkreq"; + drive-strength = <2>; + bias-pull-up; + }; + + perst-pins { + pins = "gpio23"; + function = "gpio"; + drive-strength = <2>; + bias-pull-down; + }; + }; + qup_i2c1_default: qup-i2c1-state { pins = "gpio19", "gpio20"; function = "qup0_se1"; From 44337c6b3cc9cd6a7346d07c5c06b27f469f0829 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Tue, 23 Sep 2025 14:01:56 +0300 Subject: [PATCH 0143/2333] FROMGIT: arm64: dts: qcom: rename sm6150 to talos SM6150 and QCS615 are two names for the same die, collectively known as 'talos'. Follow the example of other platforms and rename SM6150 to talos.dtsi. Link: https://lore.kernel.org/r/20250923-rename-dts-v1-3-21888b68c781@oss.qualcomm.com Signed-off-by: Dmitry Baryshkov --- arch/arm64/boot/dts/qcom/qcs615-ride.dts | 2 +- arch/arm64/boot/dts/qcom/{sm6150.dtsi => talos.dtsi} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/arm64/boot/dts/qcom/{sm6150.dtsi => talos.dtsi} (100%) diff --git a/arch/arm64/boot/dts/qcom/qcs615-ride.dts b/arch/arm64/boot/dts/qcom/qcs615-ride.dts index ba1c1d6cfeebe..54733ce0ba171 100644 --- a/arch/arm64/boot/dts/qcom/qcs615-ride.dts +++ b/arch/arm64/boot/dts/qcom/qcs615-ride.dts @@ -7,7 +7,7 @@ #include #include #include -#include "sm6150.dtsi" +#include "talos.dtsi" #include "pm8150.dtsi" / { model = "Qualcomm Technologies, Inc. QCS615 Ride"; diff --git a/arch/arm64/boot/dts/qcom/sm6150.dtsi b/arch/arm64/boot/dts/qcom/talos.dtsi similarity index 100% rename from arch/arm64/boot/dts/qcom/sm6150.dtsi rename to arch/arm64/boot/dts/qcom/talos.dtsi From 8c6c11b222aa3defc553190fada2d0db68a480b9 Mon Sep 17 00:00:00 2001 From: Viken Dadhaniya Date: Tue, 11 Nov 2025 22:33:50 +0530 Subject: [PATCH 0144/2333] FROMLIST: arm64: dts: qcom: talos: Drop opp-shared from QUP OPP table QUP devices are currently marked with opp-shared in their OPP table, causing the kernel to treat them as part of a shared OPP domain. This leads to the qcom_geni_serial driver failing to probe with error -EBUSY (-16). Remove the opp-shared property to ensure the OPP framework treats the QUP OPP table as device-specific, allowing the serial driver to probe successfully Link: https://lore.kernel.org/all/20251111170350.525832-1-viken.dadhaniya@oss.qualcomm.com/ Fixes: f6746dc9e379 ("arm64: dts: qcom: qcs615: Add QUPv3 configuration") Signed-off-by: Viken Dadhaniya --- arch/arm64/boot/dts/qcom/talos.dtsi | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/talos.dtsi b/arch/arm64/boot/dts/qcom/talos.dtsi index 37aa684768588..579c5758ff657 100644 --- a/arch/arm64/boot/dts/qcom/talos.dtsi +++ b/arch/arm64/boot/dts/qcom/talos.dtsi @@ -399,7 +399,6 @@ qup_opp_table: opp-table-qup { compatible = "operating-points-v2"; - opp-shared; opp-75000000 { opp-hz = /bits/ 64 <75000000>; From 272ed25e7b342241777573e5e4cc557d6fa7bcc1 Mon Sep 17 00:00:00 2001 From: Wei Zhang Date: Thu, 13 Nov 2025 14:30:37 +0800 Subject: [PATCH 0145/2333] FROMLIST: arm64: dts: qcom: qcs8300-ride: enable WLAN on qcs8300-ride Enable WLAN on qcs8300-ride by adding a node for the PMU module of the WCN6855 and assigning its LDO power outputs to the existing WiFi module. On the qcs8300-ride platform, the corresponding firmware and BDF are QCA6698AQ instead of WCN6855, which have been added in the 20250211 release. Link: https://lore.kernel.org/all/20251113055148.2729943-1-wei.zhang@oss.qualcomm.com/ Reviewed-by: Konrad Dybcio Signed-off-by: Wei Zhang --- arch/arm64/boot/dts/qcom/qcs8300-ride.dts | 108 ++++++++++++++++++++++ 1 file changed, 108 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/qcs8300-ride.dts b/arch/arm64/boot/dts/qcom/qcs8300-ride.dts index 59374d2442b2d..1d69d79572d56 100644 --- a/arch/arm64/boot/dts/qcom/qcs8300-ride.dts +++ b/arch/arm64/boot/dts/qcom/qcs8300-ride.dts @@ -45,6 +45,88 @@ enable-active-high; regulator-always-on; }; + + vreg_conn_1p8: vreg-conn-1p8 { + compatible = "regulator-fixed"; + regulator-name = "vreg_conn_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + startup-delay-us = <4000>; + enable-active-high; + gpio = <&pmm8650au_1_gpios 4 GPIO_ACTIVE_HIGH>; + }; + + vreg_conn_pa: vreg-conn-pa { + compatible = "regulator-fixed"; + regulator-name = "vreg_conn_pa"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + startup-delay-us = <4000>; + enable-active-high; + gpio = <&pmm8650au_1_gpios 6 GPIO_ACTIVE_HIGH>; + }; + + wcn6855-pmu { + compatible = "qcom,wcn6855-pmu"; + + pinctrl-0 = <&wlan_en_state>; + pinctrl-names = "default"; + + vddio-supply = <&vreg_conn_pa>; + vddaon-supply = <&vreg_conn_1p8>; + vddpmu-supply = <&vreg_conn_pa>; + vddpmumx-supply = <&vreg_conn_1p8>; + vddpmucx-supply = <&vreg_conn_pa>; + vddrfa0p95-supply = <&vreg_conn_1p8>; + vddrfa1p3-supply = <&vreg_conn_pa>; + vddrfa1p9-supply = <&vreg_conn_1p8>; + vddpcie1p3-supply = <&vreg_conn_pa>; + vddpcie1p9-supply = <&vreg_conn_1p8>; + + wlan-enable-gpios = <&tlmm 54 GPIO_ACTIVE_HIGH>; + + regulators { + vreg_pmu_rfa_cmn: ldo0 { + regulator-name = "vreg_pmu_rfa_cmn"; + }; + + vreg_pmu_aon_0p59: ldo1 { + regulator-name = "vreg_pmu_aon_0p59"; + }; + + vreg_pmu_wlcx_0p8: ldo2 { + regulator-name = "vreg_pmu_wlcx_0p8"; + }; + + vreg_pmu_wlmx_0p85: ldo3 { + regulator-name = "vreg_pmu_wlmx_0p85"; + }; + + vreg_pmu_btcmx_0p85: ldo4 { + regulator-name = "vreg_pmu_btcmx_0p85"; + }; + + vreg_pmu_rfa_0p8: ldo5 { + regulator-name = "vreg_pmu_rfa_0p8"; + }; + + vreg_pmu_rfa_1p2: ldo6 { + regulator-name = "vreg_pmu_rfa_1p2"; + }; + + vreg_pmu_rfa_1p7: ldo7 { + regulator-name = "vreg_pmu_rfa_1p7"; + }; + + vreg_pmu_pcie_0p9: ldo8 { + regulator-name = "vreg_pmu_pcie_0p9"; + }; + + vreg_pmu_pcie_1p8: ldo9 { + regulator-name = "vreg_pmu_pcie_1p8"; + }; + }; + }; }; &apps_rsc { @@ -391,6 +473,25 @@ status = "okay"; }; +&pcieport0 { + wifi@0 { + compatible = "pci17cb,1103"; + reg = <0x10000 0x0 0x0 0x0 0x0>; + + vddrfacmn-supply = <&vreg_pmu_rfa_cmn>; + vddaon-supply = <&vreg_pmu_aon_0p59>; + vddwlcx-supply = <&vreg_pmu_wlcx_0p8>; + vddwlmx-supply = <&vreg_pmu_wlmx_0p85>; + vddrfa0p8-supply = <&vreg_pmu_rfa_0p8>; + vddrfa1p2-supply = <&vreg_pmu_rfa_1p2>; + vddrfa1p8-supply = <&vreg_pmu_rfa_1p7>; + vddpcie0p9-supply = <&vreg_pmu_pcie_0p9>; + vddpcie1p8-supply = <&vreg_pmu_pcie_1p8>; + + qcom,calibration-variant = "QC_QCS8300_Ride"; + }; +}; + &psci { reboot-mode { mode-bootloader = <0x10001 0x2>; @@ -510,6 +611,13 @@ bias-pull-down; }; }; + + wlan_en_state: wlan-en-state { + pins = "gpio54"; + function = "gpio"; + bias-pull-up; + output-low; + }; }; &uart7 { From a34887185be7741ebfc38926dbf1101c6e6769f7 Mon Sep 17 00:00:00 2001 From: Wei Deng Date: Wed, 12 Nov 2025 12:08:26 +0530 Subject: [PATCH 0146/2333] FROMLIST: arm64: dts: qcom: lemans-evk: Enable Bluetooth support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There's a WCN6855 WiFi/Bluetooth module on an M.2 card. To make Bluetooth work, we need to define the necessary device tree nodes, including UART configuration and power supplies. Since there is no standard M.2 binding in the device tree at present, the PMU is described using dedicated PMU nodes to represent the internal regulators required by the module. The module provides a 3.3V supply, which originates from the main board’s 12V rail. To represent this power hierarchy in the device tree, add a fixed 12V regulator node as the DC-IN source and link it to the 3.3V regulator node. Link: https://lore.kernel.org/all/20251112071147.1450258-2-wei.deng@oss.qualcomm.com/ Signed-off-by: Wei Deng --- arch/arm64/boot/dts/qcom/lemans-evk.dts | 99 +++++++++++++++++++++++++ 1 file changed, 99 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/lemans-evk.dts b/arch/arm64/boot/dts/qcom/lemans-evk.dts index f5ad7ff5e5381..3b31baf197d6b 100644 --- a/arch/arm64/boot/dts/qcom/lemans-evk.dts +++ b/arch/arm64/boot/dts/qcom/lemans-evk.dts @@ -21,6 +21,7 @@ ethernet0 = ðernet0; mmc1 = &sdhc; serial0 = &uart10; + serial1 = &uart17; }; dmic: audio-codec-0 { @@ -110,6 +111,17 @@ regulator-max-microvolt = <2950000>; }; + vreg_dcin_12v: regulator-dcin-12v { + compatible = "regulator-fixed"; + + regulator-name = "VREG_DCIN_12V"; + regulator-min-microvolt = <12000000>; + regulator-max-microvolt = <12000000>; + + regulator-boot-on; + regulator-always-on; + }; + vreg_sdc: regulator-vreg-sdc { compatible = "regulator-gpio"; @@ -123,6 +135,75 @@ startup-delay-us = <100>; }; + + vreg_wcn_3p3: regulator-wcn-3p3 { + compatible = "regulator-fixed"; + + regulator-name = "VREG_WCN_3P3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + + vin-supply = <&vreg_dcin_12v>; + + regulator-boot-on; + }; + + wcn6855-pmu { + compatible = "qcom,wcn6855-pmu"; + + vddio-supply = <&vreg_wcn_3p3>; + vddaon-supply = <&vreg_wcn_3p3>; + vddpmu-supply = <&vreg_wcn_3p3>; + vddpmumx-supply = <&vreg_wcn_3p3>; + vddpmucx-supply = <&vreg_wcn_3p3>; + vddrfa0p95-supply = <&vreg_wcn_3p3>; + vddrfa1p3-supply = <&vreg_wcn_3p3>; + vddrfa1p9-supply = <&vreg_wcn_3p3>; + vddpcielp3-supply = <&vreg_wcn_3p3>; + vddpcielp9-supply = <&vreg_wcn_3p3>; + + regulators { + vreg_pmu_rfa_cmn: ldo0 { + regulator-name = "vreg_pmu_rfa_cmn"; + }; + + vreg_pmu_aon_0p59: ldo1 { + regulator-name = "vreg_pmu_aon_0p59"; + }; + + vreg_pmu_wlcx_0p8: ldo2 { + regulator-name = "vreg_pmu_wlcx_0p8"; + }; + + vreg_pmu_wlmx_0p85: ldo3 { + regulator-name = "vreg_pmu_wlmx_0p85"; + }; + + vreg_pmu_btcmx_0p85: ldo4 { + regulator-name = "vreg_pmu_btcmx_0p85"; + }; + + vreg_pmu_rfa_0p8: ldo5 { + regulator-name = "vreg_pmu_rfa_0p8"; + }; + + vreg_pmu_rfa_1p2: ldo6 { + regulator-name = "vreg_pmu_rfa_1p2"; + }; + + vreg_pmu_rfa_1p8: ldo7 { + regulator-name = "vreg_pmu_rfa_1p8"; + }; + + vreg_pmu_pcie_0p9: ldo8 { + regulator-name = "vreg_pmu_pcie_0p9"; + }; + + vreg_pmu_pcie_1p8: ldo9 { + regulator-name = "vreg_pmu_pcie_1p8"; + }; + }; + }; }; &apps_rsc { @@ -771,6 +852,24 @@ status = "okay"; }; +&uart17 { + status = "okay"; + + bluetooth: bluetooth { + compatible = "qcom,wcn6855-bt"; + max-speed = <3200000>; + + vddrfacmn-supply = <&vreg_pmu_rfa_cmn>; + vddaon-supply = <&vreg_pmu_aon_0p59>; + vddwlcx-supply = <&vreg_pmu_wlcx_0p8>; + vddwlmx-supply = <&vreg_pmu_wlmx_0p85>; + vddbtcmx-supply = <&vreg_pmu_btcmx_0p85>; + vddrfa0p8-supply = <&vreg_pmu_rfa_0p8>; + vddrfa1p2-supply = <&vreg_pmu_rfa_1p2>; + vddrfa1p8-supply = <&vreg_pmu_rfa_1p8>; + }; +}; + &ufs_mem_hc { reset-gpios = <&tlmm 149 GPIO_ACTIVE_LOW>; vcc-supply = <&vreg_l8a>; From 829c78b71ef815f34cfadc407ddf7438d396ef1d Mon Sep 17 00:00:00 2001 From: Jingyi Wang Date: Wed, 22 Oct 2025 00:28:43 -0700 Subject: [PATCH 0147/2333] FROMLIST: dt-bindings: firmware: qcom,scm: Document SCM on Kaanapali SOC Document scm compatible for the Qualcomm Kaanapali SoC. Reviewed-by: Eugen Hristev Signed-off-by: Jingyi Wang Acked-by: Rob Herring (Arm) Signed-off-by: Yijie Yang Link: https://lore.kernel.org/all/20251022-knp-soc-binding-v2-3-3cd3f390f3e2@oss.qualcomm.com/ --- Documentation/devicetree/bindings/firmware/qcom,scm.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/firmware/qcom,scm.yaml b/Documentation/devicetree/bindings/firmware/qcom,scm.yaml index ef97faac7e47c..340b754e63226 100644 --- a/Documentation/devicetree/bindings/firmware/qcom,scm.yaml +++ b/Documentation/devicetree/bindings/firmware/qcom,scm.yaml @@ -31,6 +31,7 @@ properties: - qcom,scm-ipq806x - qcom,scm-ipq8074 - qcom,scm-ipq9574 + - qcom,scm-kaanapali - qcom,scm-mdm9607 - qcom,scm-milos - qcom,scm-msm8226 @@ -202,6 +203,7 @@ allOf: compatible: contains: enum: + - qcom,scm-kaanapali - qcom,scm-milos - qcom,scm-sm8450 - qcom,scm-sm8550 From ce9c02af2e71b3787af82cde1e7163db883deec6 Mon Sep 17 00:00:00 2001 From: Wei Deng Date: Thu, 13 Nov 2025 18:35:19 +0530 Subject: [PATCH 0148/2333] FROMLIST: arm64: dts: qcom: monaco-evk: Enable Bluetooth support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There's a WCN6855 WiFi/Bluetooth module on an M.2 card. To make Bluetooth work, we need to define the necessary device tree nodes, including UART configuration and power supplies. Since there is no standard M.2 binding in the device tree at present, the PMU is described using dedicated PMU nodes to represent the internal regulators required by the module. The module provides a 3.3V supply, which originates from the main board’s 12V rail. To represent this power hierarchy in the device tree, add a fixed 12V regulator node as the DC-IN source and link it to the 3.3V regulator node. Link: https://lore.kernel.org/all/20251113130519.2647081-1-wei.deng@oss.qualcomm.com/ Reviewed-by: Dmitry Baryshkov Signed-off-by: Wei Deng --- arch/arm64/boot/dts/qcom/monaco-evk.dts | 99 +++++++++++++++++++++++++ 1 file changed, 99 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/monaco-evk.dts b/arch/arm64/boot/dts/qcom/monaco-evk.dts index 764fdb5545aaf..4f6bcfeb49ab4 100644 --- a/arch/arm64/boot/dts/qcom/monaco-evk.dts +++ b/arch/arm64/boot/dts/qcom/monaco-evk.dts @@ -20,6 +20,7 @@ ethernet0 = ðernet0; i2c1 = &i2c1; serial0 = &uart7; + serial1 = &uart2; }; chosen { @@ -76,6 +77,86 @@ }; }; }; + + vreg_dcin_12v: regulator-dcin-12v { + compatible = "regulator-fixed"; + + regulator-name = "VREG_DCIN_12V"; + regulator-min-microvolt = <12000000>; + regulator-max-microvolt = <12000000>; + + regulator-boot-on; + regulator-always-on; + }; + + vreg_wcn_3p3: regulator-wcn-3p3 { + compatible = "regulator-fixed"; + + regulator-name = "VREG_WCN_3P3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + + vin-supply = <&vreg_dcin_12v>; + + regulator-boot-on; + }; + + wcn6855-pmu { + compatible = "qcom,wcn6855-pmu"; + + vddio-supply = <&vreg_wcn_3p3>; + vddaon-supply = <&vreg_wcn_3p3>; + vddpmu-supply = <&vreg_wcn_3p3>; + vddpmumx-supply = <&vreg_wcn_3p3>; + vddpmucx-supply = <&vreg_wcn_3p3>; + vddrfa0p95-supply = <&vreg_wcn_3p3>; + vddrfa1p3-supply = <&vreg_wcn_3p3>; + vddrfa1p9-supply = <&vreg_wcn_3p3>; + vddpcielp3-supply = <&vreg_wcn_3p3>; + vddpcielp9-supply = <&vreg_wcn_3p3>; + + regulators { + vreg_pmu_rfa_cmn: ldo0 { + regulator-name = "vreg_pmu_rfa_cmn"; + }; + + vreg_pmu_aon_0p59: ldo1 { + regulator-name = "vreg_pmu_aon_0p59"; + }; + + vreg_pmu_wlcx_0p8: ldo2 { + regulator-name = "vreg_pmu_wlcx_0p8"; + }; + + vreg_pmu_wlmx_0p85: ldo3 { + regulator-name = "vreg_pmu_wlmx_0p85"; + }; + + vreg_pmu_btcmx_0p85: ldo4 { + regulator-name = "vreg_pmu_btcmx_0p85"; + }; + + vreg_pmu_rfa_0p8: ldo5 { + regulator-name = "vreg_pmu_rfa_0p8"; + }; + + vreg_pmu_rfa_1p2: ldo6 { + regulator-name = "vreg_pmu_rfa_1p2"; + }; + + vreg_pmu_rfa_1p8: ldo7 { + regulator-name = "vreg_pmu_rfa_1p8"; + }; + + vreg_pmu_pcie_0p9: ldo8 { + regulator-name = "vreg_pmu_pcie_0p9"; + }; + + vreg_pmu_pcie_1p8: ldo9 { + regulator-name = "vreg_pmu_pcie_1p8"; + }; + }; + }; }; &apps_rsc { @@ -557,6 +638,24 @@ }; }; +&uart2 { + status = "okay"; + + bluetooth: bluetooth { + compatible = "qcom,wcn6855-bt"; + max-speed = <3200000>; + + vddrfacmn-supply = <&vreg_pmu_rfa_cmn>; + vddaon-supply = <&vreg_pmu_aon_0p59>; + vddwlcx-supply = <&vreg_pmu_wlcx_0p8>; + vddwlmx-supply = <&vreg_pmu_wlmx_0p85>; + vddbtcmx-supply = <&vreg_pmu_btcmx_0p85>; + vddrfa0p8-supply = <&vreg_pmu_rfa_0p8>; + vddrfa1p2-supply = <&vreg_pmu_rfa_1p2>; + vddrfa1p8-supply = <&vreg_pmu_rfa_1p8>; + }; +}; + &uart7 { status = "okay"; }; From 51621ab3d046170d46222fab623c8c8122dac8bd Mon Sep 17 00:00:00 2001 From: Akhil P Oommen Date: Wed, 10 Sep 2025 16:55:22 +0530 Subject: [PATCH 0149/2333] FROMLIST: dt-bindings: nvmem: qfprom: Add sa8775p compatible Document compatible string for the QFPROM on Lemans platform. Link: https://lore.kernel.org/all/20250910-a663-gpu-support-v6-2-5da15827b249@oss.qualcomm.com/ Acked-by: Krzysztof Kozlowski Signed-off-by: Akhil P Oommen Signed-off-by: Haitao Xu --- Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml b/Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml index 3f6dc6a3a9f1a..7d1612acca48d 100644 --- a/Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml +++ b/Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml @@ -39,6 +39,7 @@ properties: - qcom,qcs404-qfprom - qcom,qcs615-qfprom - qcom,qcs8300-qfprom + - qcom,sa8775p-qfprom - qcom,sar2130p-qfprom - qcom,sc7180-qfprom - qcom,sc7280-qfprom From 66e31064fee4eca6f3afa26a8db511bb160d2647 Mon Sep 17 00:00:00 2001 From: Jie Zhang Date: Fri, 7 Nov 2025 02:20:06 +0530 Subject: [PATCH 0150/2333] FROMLIST: drm/msm/a6xx: Add support for Adreno 612 Add support for Adreno 612 GPU found in SM6150/QCS615 chipsets. A612 falls under ADRENO_6XX_GEN1 family and is a cut down version of A615 GPU. A612 has a new IP called Reduced Graphics Management Unit or RGMU which is a small state machine which helps to toggle GX GDSC (connected to CX rail) to implement IFPC feature. It doesn't support any other features of a full fledged GMU like clock control, resource voting to rpmh etc. So we need linux clock driver support like other gmu-wrapper implementations to control gpu core clock and gpu GX gdsc. This patch skips RGMU core initialization and act more like a gmu-wrapper case. Signed-off-by: Jie Zhang Signed-off-by: Akhil P Oommen Link: https://lore.kernel.org/all/20251107-qcs615-spin-2-v2-1-a2d7c4fbf6e6@oss.qualcomm.com/ --- drivers/gpu/drm/msm/adreno/a6xx_catalog.c | 16 ++++++++ drivers/gpu/drm/msm/adreno/a6xx_gmu.c | 23 ++++++++++- drivers/gpu/drm/msm/adreno/a6xx_gpu.c | 45 ++++++++++++++++----- drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c | 3 +- drivers/gpu/drm/msm/adreno/adreno_gpu.c | 1 + drivers/gpu/drm/msm/adreno/adreno_gpu.h | 16 ++++++-- 6 files changed, 90 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/msm/adreno/a6xx_catalog.c b/drivers/gpu/drm/msm/adreno/a6xx_catalog.c index 44df6410bce17..5db01fa2ed441 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_catalog.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_catalog.c @@ -705,6 +705,22 @@ static const struct adreno_info a6xx_gpus[] = { { 157, 3 }, { 127, 4 }, ), + }, { + .chip_ids = ADRENO_CHIP_IDS(0x06010200), + .family = ADRENO_6XX_GEN1, + .fw = { + [ADRENO_FW_SQE] = "a630_sqe.fw", + [ADRENO_FW_GMU] = "a612_rgmu.bin", + }, + .gmem = (SZ_128K + SZ_4K), + .inactive_period = DRM_MSM_INACTIVE_PERIOD, + .init = a6xx_gpu_init, + .a6xx = &(const struct a6xx_info) { + .hwcg = a612_hwcg, + .protect = &a630_protect, + .gmu_cgc_mode = 0x00000022, + .prim_fifo_threshold = 0x00080000, + }, }, { .chip_ids = ADRENO_CHIP_IDS(0x06010500), .family = ADRENO_6XX_GEN1, diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c index 4e6dc16e4a4c4..d9ffe9e93ad9d 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c @@ -350,12 +350,18 @@ static const struct a6xx_gmu_oob_bits a6xx_gmu_oob_bits[] = { /* Trigger a OOB (out of band) request to the GMU */ int a6xx_gmu_set_oob(struct a6xx_gmu *gmu, enum a6xx_gmu_oob_state state) { + struct a6xx_gpu *a6xx_gpu = container_of(gmu, struct a6xx_gpu, gmu); + struct adreno_gpu *adreno_gpu = &a6xx_gpu->base; int ret; u32 val; int request, ack; WARN_ON_ONCE(!mutex_is_locked(&gmu->lock)); + /* Skip OOB calls since RGMU is not enabled */ + if (adreno_has_rgmu(adreno_gpu)) + return 0; + if (state >= ARRAY_SIZE(a6xx_gmu_oob_bits)) return -EINVAL; @@ -395,10 +401,16 @@ int a6xx_gmu_set_oob(struct a6xx_gmu *gmu, enum a6xx_gmu_oob_state state) /* Clear a pending OOB state in the GMU */ void a6xx_gmu_clear_oob(struct a6xx_gmu *gmu, enum a6xx_gmu_oob_state state) { + struct a6xx_gpu *a6xx_gpu = container_of(gmu, struct a6xx_gpu, gmu); + struct adreno_gpu *adreno_gpu = &a6xx_gpu->base; int bit; WARN_ON_ONCE(!mutex_is_locked(&gmu->lock)); + /* Skip OOB calls since RGMU is not enabled */ + if (adreno_has_rgmu(adreno_gpu)) + return; + if (state >= ARRAY_SIZE(a6xx_gmu_oob_bits)) return; @@ -1900,7 +1912,8 @@ void a6xx_gmu_remove(struct a6xx_gpu *a6xx_gpu) gmu->mmio = NULL; gmu->rscc = NULL; - if (!adreno_has_gmu_wrapper(adreno_gpu)) { + if (!adreno_has_gmu_wrapper(adreno_gpu) && + !adreno_has_rgmu(adreno_gpu)) { a6xx_gmu_memory_free(gmu); free_irq(gmu->gmu_irq, gmu); @@ -1942,6 +1955,13 @@ int a6xx_gmu_wrapper_init(struct a6xx_gpu *a6xx_gpu, struct device_node *node) /* Mark legacy for manual SPTPRAC control */ gmu->legacy = true; + /* RGMU requires clocks */ + ret = devm_clk_bulk_get_all(gmu->dev, &gmu->clocks); + if (ret < 0) + goto err_clk; + + gmu->nr_clocks = ret; + /* Map the GMU registers */ gmu->mmio = a6xx_gmu_get_mmio(pdev, "gmu"); if (IS_ERR(gmu->mmio)) { @@ -1981,6 +2001,7 @@ int a6xx_gmu_wrapper_init(struct a6xx_gpu *a6xx_gpu, struct device_node *node) err_mmio: iounmap(gmu->mmio); +err_clk: /* Drop reference taken in of_find_device_by_node */ put_device(gmu->dev); diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c index b8f8ae940b55f..779c1da7c46df 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c @@ -612,15 +612,26 @@ static void a6xx_set_hwcg(struct msm_gpu *gpu, bool state) if (adreno_is_a630(adreno_gpu)) clock_cntl_on = 0x8aa8aa02; - else if (adreno_is_a610(adreno_gpu)) + else if (adreno_is_a610(adreno_gpu) || adreno_is_a612(adreno_gpu)) clock_cntl_on = 0xaaa8aa82; else if (adreno_is_a702(adreno_gpu)) clock_cntl_on = 0xaaaaaa82; else clock_cntl_on = 0x8aa8aa82; - cgc_delay = adreno_is_a615_family(adreno_gpu) ? 0x111 : 0x10111; - cgc_hyst = adreno_is_a615_family(adreno_gpu) ? 0x555 : 0x5555; + if (adreno_is_a612(adreno_gpu)) + cgc_delay = 0x11; + else if (adreno_is_a615_family(adreno_gpu)) + cgc_delay = 0x111; + else + cgc_delay = 0x10111; + + if (adreno_is_a612(adreno_gpu)) + cgc_hyst = 0x55; + else if (adreno_is_a615_family(adreno_gpu)) + cgc_hyst = 0x555; + else + cgc_hyst = 0x5555; gmu_write(&a6xx_gpu->gmu, REG_A6XX_GPU_GMU_AO_GMU_CGC_MODE_CNTL, state ? adreno_gpu->info->a6xx->gmu_cgc_mode : 0); @@ -714,6 +725,9 @@ static int a6xx_calc_ubwc_config(struct adreno_gpu *gpu) cfg->ubwc_swizzle = 0x7; } + if (adreno_is_a612(gpu)) + cfg->highest_bank_bit = 14; + if (adreno_is_a618(gpu)) cfg->highest_bank_bit = 14; @@ -1288,7 +1302,7 @@ static int hw_init(struct msm_gpu *gpu) gpu_write(gpu, REG_A6XX_CP_LPAC_PROG_FIFO_SIZE, 0x00000020); /* Setting the mem pool size */ - if (adreno_is_a610(adreno_gpu)) { + if (adreno_is_a610(adreno_gpu) || adreno_is_a612(adreno_gpu)) { gpu_write(gpu, REG_A6XX_CP_MEM_POOL_SIZE, 48); gpu_write(gpu, REG_A6XX_CP_MEM_POOL_DBG_ADDR, 47); } else if (adreno_is_a702(adreno_gpu)) { @@ -1321,7 +1335,8 @@ static int hw_init(struct msm_gpu *gpu) a6xx_set_ubwc_config(gpu); /* Enable fault detection */ - if (adreno_is_a730(adreno_gpu) || + if (adreno_is_a612(adreno_gpu) || + adreno_is_a730(adreno_gpu) || adreno_is_a740_family(adreno_gpu)) gpu_write(gpu, REG_A6XX_RBBM_INTERFACE_HANG_INT_CNTL, (1 << 30) | 0xcfffff); else if (adreno_is_a690(adreno_gpu)) @@ -1576,7 +1591,7 @@ static void a6xx_recover(struct msm_gpu *gpu) */ gpu->active_submits = 0; - if (adreno_has_gmu_wrapper(adreno_gpu)) { + if (adreno_has_gmu_wrapper(adreno_gpu) || adreno_has_rgmu(adreno_gpu)) { /* Drain the outstanding traffic on memory buses */ a6xx_bus_clear_pending_transactions(adreno_gpu, true); @@ -2229,6 +2244,12 @@ static int a6xx_pm_resume(struct msm_gpu *gpu) if (ret) goto err_bulk_clk; + ret = clk_bulk_prepare_enable(gmu->nr_clocks, gmu->clocks); + if (ret) { + clk_bulk_disable_unprepare(gpu->nr_clocks, gpu->grp_clks); + goto err_bulk_clk; + } + if (adreno_is_a619_holi(adreno_gpu)) a6xx_sptprac_enable(gmu); @@ -2242,8 +2263,10 @@ static int a6xx_pm_resume(struct msm_gpu *gpu) err_set_opp: mutex_unlock(&a6xx_gpu->gmu.lock); - if (!ret) + if (!ret) { msm_devfreq_resume(gpu); + a6xx_llc_activate(a6xx_gpu); + } return ret; } @@ -2284,6 +2307,8 @@ static int a6xx_pm_suspend(struct msm_gpu *gpu) trace_msm_gpu_suspend(0); + a6xx_llc_deactivate(a6xx_gpu); + msm_devfreq_suspend(gpu); mutex_lock(&a6xx_gpu->gmu.lock); @@ -2295,6 +2320,7 @@ static int a6xx_pm_suspend(struct msm_gpu *gpu) a6xx_sptprac_disable(gmu); clk_bulk_disable_unprepare(gpu->nr_clocks, gpu->grp_clks); + clk_bulk_disable_unprepare(gmu->nr_clocks, gmu->clocks); pm_runtime_put_sync(gmu->gxpd); dev_pm_opp_set_opp(&gpu->pdev->dev, NULL); @@ -2673,7 +2699,8 @@ struct msm_gpu *a6xx_gpu_init(struct drm_device *dev) ret = adreno_gpu_init(dev, pdev, adreno_gpu, &funcs_a7xx, 4); else if (is_a7xx) ret = adreno_gpu_init(dev, pdev, adreno_gpu, &funcs_a7xx, 1); - else if (adreno_has_gmu_wrapper(adreno_gpu)) + else if (adreno_has_gmu_wrapper(adreno_gpu) || + of_device_is_compatible(node, "qcom,adreno-rgmu")) ret = adreno_gpu_init(dev, pdev, adreno_gpu, &funcs_gmuwrapper, 1); else ret = adreno_gpu_init(dev, pdev, adreno_gpu, &funcs, 1); @@ -2689,7 +2716,7 @@ struct msm_gpu *a6xx_gpu_init(struct drm_device *dev) if (adreno_is_a618(adreno_gpu) || adreno_is_7c3(adreno_gpu)) priv->gpu_clamp_to_idle = true; - if (adreno_has_gmu_wrapper(adreno_gpu)) + if (adreno_has_gmu_wrapper(adreno_gpu) || adreno_has_rgmu(adreno_gpu)) ret = a6xx_gmu_wrapper_init(a6xx_gpu, node); else ret = a6xx_gmu_init(a6xx_gpu, node); diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c index 4c7f3c642f6ac..838150ff49ab1 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c @@ -1596,7 +1596,8 @@ struct msm_gpu_state *a6xx_gpu_state_get(struct msm_gpu *gpu) /* Get the generic state from the adreno core */ adreno_gpu_state_get(gpu, &a6xx_state->base); - if (!adreno_has_gmu_wrapper(adreno_gpu)) { + if (!adreno_has_gmu_wrapper(adreno_gpu) && + !adreno_has_rgmu(adreno_gpu)) { a6xx_get_gmu_registers(gpu, a6xx_state); a6xx_state->gmu_log = a6xx_snapshot_gmu_bo(a6xx_state, &a6xx_gpu->gmu.log); diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c index 4b5a4edd07028..71400d8999c97 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c @@ -1189,6 +1189,7 @@ int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev, /* Only handle the core clock when GMU is not in use (or is absent). */ if (adreno_has_gmu_wrapper(adreno_gpu) || + adreno_has_rgmu(adreno_gpu) || adreno_gpu->info->family < ADRENO_6XX_GEN1) { /* * This can only be done before devm_pm_opp_of_add_table(), or diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.h b/drivers/gpu/drm/msm/adreno/adreno_gpu.h index 390fa6720d9b0..25ee6b277fe2d 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.h +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.h @@ -392,6 +392,16 @@ static inline int adreno_is_a610(const struct adreno_gpu *gpu) return adreno_is_revn(gpu, 610); } +static inline int adreno_is_a612(const struct adreno_gpu *gpu) +{ + return gpu->info->chip_ids[0] == 0x06010200; +} + +static inline bool adreno_has_rgmu(const struct adreno_gpu *gpu) +{ + return adreno_is_a612(gpu); +} + static inline int adreno_is_a618(const struct adreno_gpu *gpu) { return adreno_is_revn(gpu, 618); @@ -466,9 +476,9 @@ static inline int adreno_is_a610_family(const struct adreno_gpu *gpu) { if (WARN_ON_ONCE(!gpu->info)) return false; - - /* TODO: A612 */ - return adreno_is_a610(gpu) || adreno_is_a702(gpu); + return adreno_is_a610(gpu) || + adreno_is_a612(gpu) || + adreno_is_a702(gpu); } /* TODO: 615/616 */ From 6671f72916da02127417a7b69093764886b8e641 Mon Sep 17 00:00:00 2001 From: Yingchao Deng Date: Fri, 24 Oct 2025 15:05:31 +0800 Subject: [PATCH 0151/2333] FROMLIST: stm: class: Add MIPI OST protocol support Add MIPI OST(Open System Trace) protocol support for stm to format the traces. The OST Protocol abstracts the underlying layers from the sending and receiving applications, thus removing dependencies on the connection media and platform implementation. OST over STP packet consists of Header/Payload/End. Header is designed to include the information required by all OST packets. Information that is not shared by all packets is left to the higher layer protocols. Thus, the OST Protocol Header can be regarded as the first part of a complete OST Packet Header, while a higher layer header can be regarded as an extension designed for a specific purpose. +--------+--------+--------+--------+ | start |version |entity |protocol| +--------+--------+--------+--------+ | stm version | magic | +-----------------------------------+ | cpu | +-----------------------------------+ | timestamp | | | +-----------------------------------+ | tgid | | | +-----------------------------------+ | payload | +-----------------------------------+ | ... | end | +-----------------------------------+ In header, there will be STARTSIMPLE/VERSION/ENTITY/PROTOCOL. STARTSIMPLE is used to signal the beginning of a simplified OST protocol. The Version field is a one byte, unsigned number identifying the version of the OST Protocol. The Entity ID field is a one byte unsigned number that identifies the source. The Protocol ID field is a one byte unsigned number identifying the higher layer protocol of the OST Packet, i.e. identifying the format of the data after the OST Protocol Header. OST Control Protocol ID value represents the common control protocol, the remaining Protocol ID values may be used by any higher layer protocols capable of being transported by the OST Protocol. Link: https://lore.kernel.org/all/20251024-p_ost-v4-1-3652a06fd055@oss.qualcomm.com/ Signed-off-by: Tingwei Zhang Signed-off-by: Yuanfang Zhang Signed-off-by: Jinlong Mao Signed-off-by: Yingchao Deng --- .../ABI/testing/configfs-stp-policy-p_ost | 6 + Documentation/trace/p_ost.rst | 36 +++ drivers/hwtracing/stm/Kconfig | 14 ++ drivers/hwtracing/stm/Makefile | 2 + drivers/hwtracing/stm/p_ost.c | 236 ++++++++++++++++++ 5 files changed, 294 insertions(+) create mode 100644 Documentation/ABI/testing/configfs-stp-policy-p_ost create mode 100644 Documentation/trace/p_ost.rst create mode 100644 drivers/hwtracing/stm/p_ost.c diff --git a/Documentation/ABI/testing/configfs-stp-policy-p_ost b/Documentation/ABI/testing/configfs-stp-policy-p_ost new file mode 100644 index 0000000000000..498739b49da06 --- /dev/null +++ b/Documentation/ABI/testing/configfs-stp-policy-p_ost @@ -0,0 +1,6 @@ +What: /config/stp-policy/:p_ost.//entity +Date: Oct 2025 +KernelVersion: 6.18 +Description: + Set the entity which is to identify the source, RW. + diff --git a/Documentation/trace/p_ost.rst b/Documentation/trace/p_ost.rst new file mode 100644 index 0000000000000..df93b889eb4ce --- /dev/null +++ b/Documentation/trace/p_ost.rst @@ -0,0 +1,36 @@ +.. SPDX-License-Identifier: GPL-2.0 + +=================== +MIPI OST over STP +=================== + +The OST(Open System Trace) driver is used with STM class devices to +generate standardized trace stream. Trace sources can be identified +by different entity ids. + +CONFIG_STM_PROTO_OST is for p_ost driver enablement. Once this config +is enabled, you can select the p_ost protocol by command below: + +# mkdir /sys/kernel/config/stp-policy/stm0:p_ost.policy + +The policy name format is extended like this: + :. + +With coresight-stm device, it will be look like "stm0:p_ost.policy". + +With MIPI OST protocol driver, the attributes for each protocol node is: +# mkdir /sys/kernel/config/stp-policy/stm0:p_ost.policy/default +# ls /sys/kernel/config/stp-policy/stm0:p_ost.policy/default +channels entity masters + +The entity here is the set the entity that p_ost supports. Currently +p_ost supports ftrace, console and diag entity. + +Set entity: +# echo 'ftrace' > /sys/kernel/config/stp-policy/stm0:p_ost.policy/default/entity + +Get available and currently selected (shown in square brackets) entity that p_ost supports: +# cat /sys/kernel/config/stp-policy/stm0:p_ost.policy/default/entity +[ftrace] console diag + +See Documentation/ABI/testing/configfs-stp-policy-p_ost for more details. diff --git a/drivers/hwtracing/stm/Kconfig b/drivers/hwtracing/stm/Kconfig index eda6b11d40a1f..daa4aa09f64dc 100644 --- a/drivers/hwtracing/stm/Kconfig +++ b/drivers/hwtracing/stm/Kconfig @@ -40,6 +40,20 @@ config STM_PROTO_SYS_T If you don't know what this is, say N. +config STM_PROTO_OST + tristate "MIPI OST STM framing protocol driver" + default CONFIG_STM + help + This is an implementation of MIPI OST protocol to be used + over the STP transport. In addition to the data payload, it + also carries additional metadata for entity, better + means of trace source identification, etc. + + The receiving side must be able to decode this protocol in + addition to the MIPI STP, in order to extract the data. + + If you don't know what this is, say N. + config STM_DUMMY tristate "Dummy STM driver" help diff --git a/drivers/hwtracing/stm/Makefile b/drivers/hwtracing/stm/Makefile index 1692fcd292779..d9c8615849b95 100644 --- a/drivers/hwtracing/stm/Makefile +++ b/drivers/hwtracing/stm/Makefile @@ -5,9 +5,11 @@ stm_core-y := core.o policy.o obj-$(CONFIG_STM_PROTO_BASIC) += stm_p_basic.o obj-$(CONFIG_STM_PROTO_SYS_T) += stm_p_sys-t.o +obj-$(CONFIG_STM_PROTO_OST) += stm_p_ost.o stm_p_basic-y := p_basic.o stm_p_sys-t-y := p_sys-t.o +stm_p_ost-y := p_ost.o obj-$(CONFIG_STM_DUMMY) += dummy_stm.o diff --git a/drivers/hwtracing/stm/p_ost.c b/drivers/hwtracing/stm/p_ost.c new file mode 100644 index 0000000000000..ac9492ed5c2c0 --- /dev/null +++ b/drivers/hwtracing/stm/p_ost.c @@ -0,0 +1,236 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2025 Qualcomm Innovation Center, Inc. All rights reserved. + * + * MIPI OST framing protocol for STM devices. + */ + +#include +#include +#include +#include +#include "stm.h" + +/* + * OST Base Protocol Header + * + * Position Bits Field Name + * 0 8 STARTSIMPLE + * 1 8 Version + * 2 8 Entity ID + * 3 8 protocol ID + */ +#define OST_FIELD_STARTSIMPLE 0 +#define OST_FIELD_VERSION 8 +#define OST_FIELD_ENTITY 16 +#define OST_FIELD_PROTOCOL 24 + +#define OST_TOKEN_STARTSIMPLE 0x10 +#define OST_VERSION_MIPI1 0x10 + +/* entity id to identify the source*/ +#define OST_ENTITY_FTRACE 0x01 +#define OST_ENTITY_CONSOLE 0x02 +#define OST_ENTITY_DIAG 0xEE + +#define OST_CONTROL_PROTOCOL 0x0 + +#define DATA_HEADER ((OST_TOKEN_STARTSIMPLE << OST_FIELD_STARTSIMPLE) | \ + (OST_VERSION_MIPI1 << OST_FIELD_PROTOCOL) | \ + (OST_CONTROL_PROTOCOL << OST_FIELD_PROTOCOL)) + +#define STM_MAKE_VERSION(ma, mi) (((ma) << 8) | (mi)) +#define STM_HEADER_MAGIC (0x5953) + +enum ost_entity_type { + OST_ENTITY_TYPE_NONE, + OST_ENTITY_TYPE_FTRACE, + OST_ENTITY_TYPE_CONSOLE, + OST_ENTITY_TYPE_DIAG, +}; + +static const char * const str_ost_entity_type[] = { + [OST_ENTITY_TYPE_NONE] = "none", + [OST_ENTITY_TYPE_FTRACE] = "ftrace", + [OST_ENTITY_TYPE_CONSOLE] = "console", + [OST_ENTITY_TYPE_DIAG] = "diag", +}; + +static const u32 ost_entity_value[] = { + [OST_ENTITY_TYPE_NONE] = 0, + [OST_ENTITY_TYPE_FTRACE] = OST_ENTITY_FTRACE, + [OST_ENTITY_TYPE_CONSOLE] = OST_ENTITY_CONSOLE, + [OST_ENTITY_TYPE_DIAG] = OST_ENTITY_DIAG, +}; + +struct ost_policy_node { + enum ost_entity_type entity_type; +}; + +struct ost_output { + struct ost_policy_node node; +}; + +/* Set default entity type as none */ +static void ost_policy_node_init(void *priv) +{ + struct ost_policy_node *pn = priv; + + pn->entity_type = OST_ENTITY_TYPE_NONE; +} + +static int ost_output_open(void *priv, struct stm_output *output) +{ + struct ost_policy_node *pn = priv; + struct ost_output *opriv; + + opriv = kzalloc(sizeof(*opriv), GFP_ATOMIC); + if (!opriv) + return -ENOMEM; + + memcpy(&opriv->node, pn, sizeof(opriv->node)); + output->pdrv_private = opriv; + return 0; +} + +static void ost_output_close(struct stm_output *output) +{ + kfree(output->pdrv_private); +} + +static ssize_t ost_t_policy_entity_show(struct config_item *item, + char *page) +{ + struct ost_policy_node *pn = to_pdrv_policy_node(item); + ssize_t sz = 0; + int i; + + for (i = 1; i < ARRAY_SIZE(str_ost_entity_type); i++) { + if (i == pn->entity_type) + sz += sysfs_emit_at(page, sz, "[%s] ", str_ost_entity_type[i]); + else + sz += sysfs_emit_at(page, sz, "%s ", str_ost_entity_type[i]); + } + + sz += sysfs_emit_at(page, sz, "\n"); + return sz; +} + +static int entity_index(const char *str) +{ + int i; + + for (i = 1; i < ARRAY_SIZE(str_ost_entity_type); i++) { + if (sysfs_streq(str, str_ost_entity_type[i])) + return i; + } + + return 0; +} + +static ssize_t +ost_t_policy_entity_store(struct config_item *item, const char *page, + size_t count) +{ + struct ost_policy_node *pn = to_pdrv_policy_node(item); + int i; + + i = entity_index(page); + if (i) + pn->entity_type = i; + else + return -EINVAL; + + return count; +} +CONFIGFS_ATTR(ost_t_policy_, entity); + +static struct configfs_attribute *ost_t_policy_attrs[] = { + &ost_t_policy_attr_entity, + NULL, +}; + +static ssize_t +notrace ost_write(struct stm_data *data, struct stm_output *output, + unsigned int chan, const char *buf, size_t count, + struct stm_source_data *source) +{ + struct ost_output *op = output->pdrv_private; + unsigned int c = output->channel + chan; + unsigned int m = output->master; + const unsigned char nil = 0; + u32 header = DATA_HEADER; + struct trc_hdr { + u16 version; + u16 magic; + u32 cpu; + u64 timestamp; + u64 tgid; + } hdr; + ssize_t sz; + + /* + * Identify the source by entity type. + * If entity type is not set, return error value. + */ + if (op->node.entity_type) + header |= ost_entity_value[op->node.entity_type]; + else + return -EINVAL; + + /* + * STP framing rules for OST frames: + * * the first packet of the OST frame is marked; + * * the last packet is a FLAG with timestamped tag. + */ + /* Message layout: HEADER / DATA / TAIL */ + /* HEADER */ + sz = data->packet(data, m, c, STP_PACKET_DATA, STP_PACKET_MARKED, + 4, (u8 *)&header); + if (sz <= 0) + return sz; + + /* DATA */ + hdr.version = STM_MAKE_VERSION(0, 3); + hdr.magic = STM_HEADER_MAGIC; + hdr.cpu = raw_smp_processor_id(); + hdr.timestamp = sched_clock(); + hdr.tgid = task_tgid_nr(current); + sz = stm_data_write(data, m, c, false, &hdr, sizeof(hdr)); + if (sz <= 0) + return sz; + + sz = stm_data_write(data, m, c, false, buf, count); + + /* TAIL */ + if (sz > 0) + data->packet(data, m, c, STP_PACKET_FLAG, + STP_PACKET_TIMESTAMPED, 0, &nil); + + return sz; +} + +static const struct stm_protocol_driver ost_pdrv = { + .owner = THIS_MODULE, + .name = "p_ost", + .write = ost_write, + .policy_attr = ost_t_policy_attrs, + .output_open = ost_output_open, + .output_close = ost_output_close, + .policy_node_init = ost_policy_node_init, +}; + +static int ost_stm_init(void) +{ + return stm_register_protocol(&ost_pdrv); +} +module_init(ost_stm_init); + +static void ost_stm_exit(void) +{ + stm_unregister_protocol(&ost_pdrv); +} +module_exit(ost_stm_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("MIPI Open System Trace STM framing protocol driver"); From b7200f79230e01edbe2b005497c029deba397160 Mon Sep 17 00:00:00 2001 From: Khalid Faisal Ansari Date: Sat, 15 Nov 2025 14:28:29 +0530 Subject: [PATCH 0152/2333] FROMLIST: arm64: dts: qcom: lemans-evk: Enable TPM (ST33) Enable ST33HTPM TPM over SPI16 on the LeMans IoT EVK by adding the required SPI and TPM nodes. Link: https://lore.kernel.org/all/20251114-enable-tpm-lemans-v1-1-c8d8b580ace7@oss.qualcomm.com/ Signed-off-by: Khalid Faisal Ansari --- arch/arm64/boot/dts/qcom/lemans-evk.dts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/lemans-evk.dts b/arch/arm64/boot/dts/qcom/lemans-evk.dts index 3b31baf197d6b..dd50ed58d1b7e 100644 --- a/arch/arm64/boot/dts/qcom/lemans-evk.dts +++ b/arch/arm64/boot/dts/qcom/lemans-evk.dts @@ -748,6 +748,16 @@ status = "okay"; }; +&spi16 { + status = "okay"; + + tpm@0 { + compatible = "st,st33htpm-spi", "tcg,tpm_tis-spi"; + reg = <0>; + spi-max-frequency = <20000000>; + }; +}; + &sdhc { vmmc-supply = <&vmmc_sdc>; vqmmc-supply = <&vreg_sdc>; From 0dc3b9e7fe2e0d9568fe8b337d89a1567e9f6e85 Mon Sep 17 00:00:00 2001 From: Khalid Faisal Ansari Date: Sat, 15 Nov 2025 14:45:57 +0530 Subject: [PATCH 0153/2333] FROMLIST: arm64: dts: qcom: monaco-evk: Enable TPM (ST33) Enable ST33HTPM TPM over SPI10 on the Monaco IoT EVK by adding the required SPI and TPM nodes. Link: https://lore.kernel.org/all/20251114-enable-tpm-monaco-v1-1-4ed566838698@oss.qualcomm.com/ Signed-off-by: Khalid Faisal Ansari --- arch/arm64/boot/dts/qcom/monaco-evk.dts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/monaco-evk.dts b/arch/arm64/boot/dts/qcom/monaco-evk.dts index 4f6bcfeb49ab4..492b6407651be 100644 --- a/arch/arm64/boot/dts/qcom/monaco-evk.dts +++ b/arch/arm64/boot/dts/qcom/monaco-evk.dts @@ -560,6 +560,16 @@ status = "okay"; }; +&spi10 { + status = "okay"; + + tpm@0 { + compatible = "st,st33htpm-spi", "tcg,tpm_tis-spi"; + reg = <0>; + spi-max-frequency = <20000000>; + }; +}; + &tlmm { ethernet0_default: ethernet0-default-state { ethernet0_mdc: ethernet0-mdc-pins { From 77748f75daa66e09c008ca52570d923c78ad9f6f Mon Sep 17 00:00:00 2001 From: Jingyi Wang Date: Wed, 22 Oct 2025 00:28:42 -0700 Subject: [PATCH 0154/2333] FROMLIST: dt-bindings: soc: qcom,aoss-qmp: Document the Kaanapali AOSS channel Document the Always-On Subsystem side channel on the Qualcomm Kaanapali platform for communication with client found on the SoC such as remoteprocs. Reviewed-by: Eugen Hristev Signed-off-by: Jingyi Wang Acked-by: Rob Herring (Arm) Signed-off-by: Yijie Yang Link: https://lore.kernel.org/all/20251022-knp-soc-binding-v2-2-3cd3f390f3e2@oss.qualcomm.com/ --- Documentation/devicetree/bindings/soc/qcom/qcom,aoss-qmp.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,aoss-qmp.yaml b/Documentation/devicetree/bindings/soc/qcom/qcom,aoss-qmp.yaml index 851a1260f8dc8..57aa819939f00 100644 --- a/Documentation/devicetree/bindings/soc/qcom/qcom,aoss-qmp.yaml +++ b/Documentation/devicetree/bindings/soc/qcom/qcom,aoss-qmp.yaml @@ -25,6 +25,7 @@ properties: compatible: items: - enum: + - qcom,kaanapali-aoss-qmp - qcom,milos-aoss-qmp - qcom,qcs615-aoss-qmp - qcom,qcs8300-aoss-qmp From 6f257ae4c4d991dd1d9fbd42f79f305db9f0ef19 Mon Sep 17 00:00:00 2001 From: Sibi Sankar Date: Wed, 22 Oct 2025 00:28:44 -0700 Subject: [PATCH 0155/2333] FROMLIST: dt-bindings: soc: qcom,aoss-qmp: Document the Glymur AOSS side channel Document the Always-on Subsystem side channel on the Glymur SoC. Signed-off-by: Sibi Sankar Signed-off-by: Jingyi Wang Acked-by: Rob Herring (Arm) Signed-off-by: Yijie Yang Link: https://lore.kernel.org/all/20251022-knp-soc-binding-v2-4-3cd3f390f3e2@oss.qualcomm.com/ --- Documentation/devicetree/bindings/soc/qcom/qcom,aoss-qmp.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,aoss-qmp.yaml b/Documentation/devicetree/bindings/soc/qcom/qcom,aoss-qmp.yaml index 57aa819939f00..c5c1bac2db013 100644 --- a/Documentation/devicetree/bindings/soc/qcom/qcom,aoss-qmp.yaml +++ b/Documentation/devicetree/bindings/soc/qcom/qcom,aoss-qmp.yaml @@ -25,6 +25,7 @@ properties: compatible: items: - enum: + - qcom,glymur-aoss-qmp - qcom,kaanapali-aoss-qmp - qcom,milos-aoss-qmp - qcom,qcs615-aoss-qmp From 91a5f259df1c65b4981c51e7d825a26617afbd50 Mon Sep 17 00:00:00 2001 From: Jianping Li Date: Tue, 18 Nov 2025 11:42:05 +0800 Subject: [PATCH 0156/2333] FROMLIST: arm64: dts: qcom: sc7280: Add memory region for audiopd Add reserved memory region for audio PD dynamic loading and remote heap requirement. Also add LPASS and ADSP_HEAP VMIDs. Link: https://lore.kernel.org/all/20251117070819.492-1-jianping.li@oss.qualcomm.com/ Signed-off-by: Jianping Li --- arch/arm64/boot/dts/qcom/sc7280.dtsi | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sc7280.dtsi b/arch/arm64/boot/dts/qcom/sc7280.dtsi index b7122566d36b0..4cc459802b9a4 100644 --- a/arch/arm64/boot/dts/qcom/sc7280.dtsi +++ b/arch/arm64/boot/dts/qcom/sc7280.dtsi @@ -190,6 +190,11 @@ qcom,client-id = <1>; qcom,vmid = ; }; + + adsp_rpc_remote_heap_mem: adsp-rpc-remote-heap@9cb80000 { + reg = <0x0 0x9cb80000 0x0 0x800000>; + no-map; + }; }; cpus { @@ -4423,6 +4428,9 @@ qcom,glink-channels = "fastrpcglink-apps-dsp"; label = "adsp"; qcom,non-secure-domain; + memory-region = <&adsp_rpc_remote_heap_mem>; + qcom,vmids = ; #address-cells = <1>; #size-cells = <0>; From 961640988eb239085e7643c0ec26e627d8389049 Mon Sep 17 00:00:00 2001 From: Jie Gan Date: Tue, 28 Oct 2025 18:11:40 +0800 Subject: [PATCH 0157/2333] FROMLIST: dt-bindings: arm: document the static TPDM compatible The static TPDM device is intended for sources that do not require MMIO mapping. Its compatible string should be documented clearly, along with an example illustrating how to define a static TPDM node in the DT. Link: https://lore.kernel.org/all/20251028-add_static_tpdm_support-v4-1-84e21b98e727@oss.qualcomm.com/ Reviewed-by: Rob Herring (Arm) Signed-off-by: Jie Gan --- .../bindings/arm/qcom,coresight-tpdm.yaml | 23 ++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/arm/qcom,coresight-tpdm.yaml b/Documentation/devicetree/bindings/arm/qcom,coresight-tpdm.yaml index 4edc47483851f..c349306f0d520 100644 --- a/Documentation/devicetree/bindings/arm/qcom,coresight-tpdm.yaml +++ b/Documentation/devicetree/bindings/arm/qcom,coresight-tpdm.yaml @@ -36,9 +36,12 @@ properties: $nodename: pattern: "^tpdm(@[0-9a-f]+)$" compatible: - items: - - const: qcom,coresight-tpdm - - const: arm,primecell + oneOf: + - items: + - const: qcom,coresight-static-tpdm + - items: + - const: qcom,coresight-tpdm + - const: arm,primecell reg: maxItems: 1 @@ -147,4 +150,18 @@ examples: }; }; }; + + turing-llm-tpdm { + compatible = "qcom,coresight-static-tpdm"; + + qcom,cmb-element-bits = <32>; + + out-ports { + port { + turing_llm_tpdm_out: endpoint { + remote-endpoint = <&turing0_funnel_in1>; + }; + }; + }; + }; ... From e0326f1e866dc1c82669249763e1c76fd60f49f0 Mon Sep 17 00:00:00 2001 From: Jie Gan Date: Mon, 17 Nov 2025 16:42:03 +0800 Subject: [PATCH 0158/2333] FROMLIST: arm64: qcom: dts: sm8750: add coresight nodes Add CoreSight DT nodes for AOSS, QDSS, Turing, and Modem blocks to enable the STM and TPDM sources to route trace data to the ETF for debugging. Link: https://lore.kernel.org/all/20251117-add-coresight-nodes-for-pakala-v1-1-d26bfaa44fe7@oss.qualcomm.com/ Signed-off-by: Jie Gan --- arch/arm64/boot/dts/qcom/sm8750.dtsi | 981 +++++++++++++++++++++++++++ 1 file changed, 981 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm8750.dtsi b/arch/arm64/boot/dts/qcom/sm8750.dtsi index ee39b8e2cdd67..22d57ac341a01 100644 --- a/arch/arm64/boot/dts/qcom/sm8750.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8750.dtsi @@ -3312,6 +3312,948 @@ #reset-cells = <1>; }; + stm@10002000 { + compatible = "arm,coresight-stm", "arm,primecell"; + reg = <0x0 0x10002000 0x0 0x1000>, + <0x0 0x37280000 0x0 0x180000>; + reg-names = "stm-base", + "stm-stimulus-base"; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + + out-ports { + port { + stm_out: endpoint { + remote-endpoint = <&funnel_in0_in7>; + }; + }; + }; + }; + + tpda@10004000 { + compatible = "qcom,coresight-tpda", "arm,primecell"; + reg = <0x0 0x10004000 0x0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + + in-ports { + #address-cells = <1>; + #size-cells = <0>; + + port@1 { + reg = <1>; + + tpda_qdss_in1: endpoint { + remote-endpoint = <&tpdm_spdm_out>; + }; + }; + + }; + + out-ports { + port { + tpda_qdss_out: endpoint { + remote-endpoint = <&funnel_in0_in6>; + }; + }; + }; + }; + + tpdm@1000f000 { + compatible = "qcom,coresight-tpdm", "arm,primecell"; + reg = <0x0 0x1000f000 0x0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + + qcom,cmb-element-bits = <64>; + qcom,cmb-msrs-num = <32>; + + out-ports { + port { + tpdm_spdm_out: endpoint { + remote-endpoint = <&tpda_qdss_in1>; + }; + }; + }; + }; + + funnel@10041000 { + compatible = "arm,coresight-dynamic-funnel", "arm,primecell"; + reg = <0x0 0x10041000 0x0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + + in-ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + funnel_in0_in0: endpoint { + remote-endpoint = + <&tn_ag_out>; + }; + }; + + port@6 { + reg = <6>; + + funnel_in0_in6: endpoint { + remote-endpoint = <&tpda_qdss_out>; + }; + }; + + port@7 { + reg = <7>; + + funnel_in0_in7: endpoint { + remote-endpoint = <&stm_out>; + }; + }; + }; + + out-ports { + port { + funnel_in0_out: endpoint { + remote-endpoint = <&funnel_aoss_in7>; + }; + }; + }; + }; + + tpdm@10800000 { + compatible = "qcom,coresight-tpdm", "arm,primecell"; + reg = <0x0 0x10800000 0x0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + + qcom,dsb-element-bits = <32>; + qcom,dsb-msrs-num = <32>; + + out-ports { + port { + tpdm_modem0_out: endpoint { + remote-endpoint = <&tpda_modem_in0>; + }; + }; + }; + }; + + tpda@10803000 { + compatible = "qcom,coresight-tpda", "arm,primecell"; + reg = <0x0 0x10803000 0x0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + + in-ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + tpda_modem_in0: endpoint { + remote-endpoint = <&tpdm_modem0_out>; + }; + }; + + port@1 { + reg = <1>; + + tpda_modem_in1: endpoint { + remote-endpoint = <&tpdm_modem1_out>; + }; + }; + }; + + out-ports { + port { + tpda_modem_out: endpoint { + remote-endpoint = <&funnel_modem_dl_in0>; + }; + }; + }; + }; + + funnel@10804000 { + compatible = "arm,coresight-dynamic-funnel", "arm,primecell"; + reg = <0x0 0x10804000 0x0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + + in-ports { + port { + funnel_modem_dl_in0: endpoint { + remote-endpoint = <&tpda_modem_out>; + }; + }; + }; + + out-ports { + port { + funnel_modem_dl_out: endpoint { + remote-endpoint = <&tn_ag_in13>; + }; + }; + }; + }; + + cti@1080b000 { + compatible = "arm,coresight-cti", "arm,primecell"; + reg = <0x0 0x1080b000 0x0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + }; + + tpdm@1082c000 { + compatible = "qcom,coresight-tpdm", "arm,primecell"; + reg = <0x0 0x1082c000 0x0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + + qcom,dsb-msrs-num = <32>; + + out-ports { + port { + tpdm_gcc_out: endpoint { + remote-endpoint = <&tn_ag_in17>; + }; + }; + }; + }; + + tpdm@10841000 { + compatible = "qcom,coresight-tpdm", "arm,primecell"; + reg = <0x0 0x10841000 0x0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + + qcom,cmb-msrs-num = <32>; + + out-ports { + port { + tpdm_prng_out: endpoint { + remote-endpoint = <&tn_ag_in18>; + }; + }; + }; + }; + + tpdm@1084e000 { + compatible = "qcom,coresight-tpdm", "arm,primecell"; + reg = <0x0 0x1084e000 0x0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + + qcom,cmb-element-bits = <32>; + qcom,cmb-msrs-num = <32>; + + out-ports { + port { + tpdm_mm_bcv_out: endpoint { + remote-endpoint = <&tpda_mm_in0>; + }; + }; + }; + }; + + tpdm@1084f000 { + compatible = "qcom,coresight-tpdm", "arm,primecell"; + reg = <0x0 0x1084f000 0x0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + + qcom,cmb-element-bits = <32>; + qcom,cmb-msrs-num = <32>; + + out-ports { + port { + tpdm_mm_lmh_out: endpoint { + remote-endpoint = <&tpda_mm_in1>; + }; + }; + }; + }; + + tpdm@10850000 { + compatible = "qcom,coresight-tpdm", "arm,primecell"; + reg = <0x0 0x10850000 0x0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + + qcom,cmb-element-bits = <64>; + qcom,cmb-msrs-num = <32>; + + out-ports { + port { + tpdm_mm_dpm_out: endpoint { + remote-endpoint = <&tpda_mm_in2>; + }; + }; + }; + }; + + tpda@10851000 { + compatible = "qcom,coresight-tpda", "arm,primecell"; + reg = <0x0 0x10851000 0x0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + + in-ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + tpda_mm_in0: endpoint { + remote-endpoint = <&tpdm_mm_bcv_out>; + }; + }; + + port@1 { + reg = <1>; + + tpda_mm_in1: endpoint { + remote-endpoint = <&tpdm_mm_lmh_out>; + }; + }; + + port@2 { + reg = <2>; + + tpda_mm_in2: endpoint { + remote-endpoint = <&tpdm_mm_dpm_out>; + }; + }; + }; + + out-ports { + port { + tpda_mm_out: endpoint { + remote-endpoint = <&tn_ag_in4>; + }; + }; + }; + }; + + tpdm@10980000 { + compatible = "qcom,coresight-tpdm", "arm,primecell"; + reg = <0x0 0x10980000 0x0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + + qcom,dsb-element-bits = <32>; + qcom,dsb-msrs-num = <32>; + + out-ports { + port { + tpdm_turing_out: endpoint { + remote-endpoint = <&tpda_turing_in0>; + }; + }; + }; + }; + + tpda@10986000 { + compatible = "qcom,coresight-tpda", "arm,primecell"; + reg = <0x0 0x10986000 0x0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + + in-ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + tpda_turing_in0: endpoint { + remote-endpoint = <&tpdm_turing_out>; + }; + }; + + port@1 { + reg = <1>; + + tpda_turing_in1: endpoint { + remote-endpoint = <&tpdm_turing_llm_out>; + }; + }; + + port@2 { + reg = <2>; + + tpda_turing_in2: endpoint { + remote-endpoint = <&tpdm_turing_llm2_out>; + }; + }; + }; + + out-ports { + port { + tpda_turing_out: endpoint { + remote-endpoint = <&funnel_turing_in0>; + }; + }; + }; + }; + + funnel@10987000 { + compatible = "arm,coresight-dynamic-funnel", "arm,primecell"; + reg = <0x0 0x10987000 0x0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + + in-ports { + port { + funnel_turing_in0: endpoint { + remote-endpoint = <&tpda_turing_out>; + }; + }; + }; + + out-ports { + port { + funnel_turing_out: endpoint { + remote-endpoint = <&tn_ag_in16>; + }; + }; + }; + }; + + cti@1098b000 { + compatible = "arm,coresight-cti", "arm,primecell"; + reg = <0x0 0x1098b000 0x0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + }; + + tpdm@109a3000 { + compatible = "qcom,coresight-tpdm", "arm,primecell"; + reg = <0x0 0x109a3000 0x0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + + qcom,cmb-msrs-num = <32>; + qcom,dsb-msrs-num = <32>; + + out-ports { + port { + tpdm_pmu_out: endpoint { + remote-endpoint = <&tn_ag_in29>; + }; + }; + }; + }; + + tpdm@109a4000 { + compatible = "qcom,coresight-tpdm", "arm,primecell"; + reg = <0x0 0x109a4000 0x0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + + qcom,cmb-msrs-num = <32>; + + out-ports { + port { + tpdm_ipcc_cmb_out: endpoint { + remote-endpoint = <&tn_ag_in28>; + }; + }; + }; + }; + + tpdm@109a5000 { + compatible = "qcom,coresight-tpdm", "arm,primecell"; + reg = <0x0 0x109a5000 0x0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + + qcom,dsb-msrs-num = <32>; + + out-ports { + port { + tpdm_dl_mm_out: endpoint { + remote-endpoint = <&tn_ag_in25>; + }; + }; + }; + }; + + tpdm@109a6000 { + compatible = "qcom,coresight-tpdm", "arm,primecell"; + reg = <0x0 0x109a6000 0x0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + + qcom,dsb-msrs-num = <32>; + + out-ports { + port { + tpdm_north_dsb_out: endpoint { + remote-endpoint = <&tn_ag_in26>; + }; + }; + }; + }; + + tpdm@109a7000 { + compatible = "qcom,coresight-tpdm", "arm,primecell"; + reg = <0x0 0x109a7000 0x0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + + qcom,dsb-msrs-num = <32>; + + out-ports { + port { + tpdm_south_dsb_out: endpoint { + remote-endpoint = <&tn_ag_in27>; + }; + }; + }; + }; + + tpdm@109a8000 { + compatible = "qcom,coresight-tpdm", "arm,primecell"; + reg = <0x0 0x109a8000 0x0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + + qcom,cmb-msrs-num = <32>; + + out-ports { + port { + tpdm_rdpm_cmb0_out: endpoint { + remote-endpoint = <&tn_ag_in30>; + }; + }; + }; + }; + + tpdm@109a9000 { + compatible = "qcom,coresight-tpdm", "arm,primecell"; + reg = <0x0 0x109a9000 0x0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + + qcom,cmb-msrs-num = <32>; + + out-ports { + port { + tpdm_rdpm_cmb1_out: endpoint { + remote-endpoint = <&tn_ag_in31>; + }; + }; + }; + }; + + tpdm@109aa000 { + compatible = "qcom,coresight-tpdm", "arm,primecell"; + reg = <0x0 0x109aa000 0x0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + + qcom,cmb-msrs-num = <32>; + + out-ports { + port { + tpdm_rdpm_cmb2_out: endpoint { + remote-endpoint = <&tn_ag_in32>; + }; + }; + }; + }; + + tn@109ab000 { + compatible = "qcom,coresight-tnoc", "arm,primecell"; + reg = <0x0 0x109ab000 0x0 0x4200>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + + in-ports { + #address-cells = <1>; + #size-cells = <0>; + + port@4 { + reg = <4>; + + tn_ag_in4: endpoint { + remote-endpoint = <&tpda_mm_out>; + }; + }; + + port@d { + reg = <0xd>; + + tn_ag_in13: endpoint { + remote-endpoint = <&funnel_modem_dl_out>; + }; + }; + + port@10 { + reg = <0x10>; + + tn_ag_in16: endpoint { + remote-endpoint = <&funnel_turing_out>; + }; + }; + + port@11 { + reg = <0x11>; + + tn_ag_in17: endpoint { + remote-endpoint = <&tpdm_gcc_out>; + }; + }; + + port@12 { + reg = <0x12>; + + tn_ag_in18: endpoint { + remote-endpoint = <&tpdm_prng_out>; + }; + }; + + port@13 { + reg = <0x13>; + + tn_ag_in19: endpoint { + remote-endpoint = <&tpdm_qm_out>; + }; + }; + + port@19 { + reg = <0x19>; + + tn_ag_in25: endpoint { + remote-endpoint = <&tpdm_dl_mm_out>; + }; + }; + + port@1a { + reg = <0x1a>; + + tn_ag_in26: endpoint { + remote-endpoint = <&tpdm_north_dsb_out>; + }; + }; + + port@1b { + reg = <0x1b>; + + tn_ag_in27: endpoint { + remote-endpoint = <&tpdm_south_dsb_out>; + }; + }; + + port@1c { + reg = <0x1c>; + + tn_ag_in28: endpoint { + remote-endpoint = <&tpdm_ipcc_cmb_out>; + }; + }; + + port@1d { + reg = <0x1d>; + + tn_ag_in29: endpoint { + remote-endpoint = <&tpdm_pmu_out>; + }; + }; + + port@1e { + reg = <0x1e>; + + tn_ag_in30: endpoint { + remote-endpoint = <&tpdm_rdpm_cmb0_out>; + }; + }; + + port@1f { + reg = <0x1f>; + + tn_ag_in31: endpoint { + remote-endpoint = <&tpdm_rdpm_cmb1_out>; + }; + }; + + port@20 { + reg = <0x20>; + + tn_ag_in32: endpoint { + remote-endpoint = <&tpdm_rdpm_cmb2_out>; + }; + }; + }; + + out-ports { + port { + tn_ag_out: endpoint { + remote-endpoint = <&funnel_in0_in0>; + }; + }; + }; + }; + + tpdm@109d0000 { + compatible = "qcom,coresight-tpdm", "arm,primecell"; + reg = <0x0 0x109d0000 0x0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + + qcom,dsb-msrs-num = <32>; + + out-ports { + port { + tpdm_qm_out: endpoint { + remote-endpoint = <&tn_ag_in19>; + }; + }; + }; + }; + + funnel@10b04000 { + compatible = "arm,coresight-dynamic-funnel", "arm,primecell"; + reg = <0x0 0x10b04000 0x0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + + in-ports { + #address-cells = <1>; + #size-cells = <0>; + + port@6 { + reg = <6>; + + funnel_aoss_in6: endpoint { + remote-endpoint = <&tpda_aoss_out>; + }; + }; + + port@7 { + reg = <7>; + + funnel_aoss_in7: endpoint { + remote-endpoint = <&funnel_in0_out>; + }; + }; + + }; + + out-ports { + port { + funnel_aoss_out: endpoint { + remote-endpoint = <&tmc_etf_in>; + }; + }; + }; + }; + + tmc@10b05000 { + compatible = "arm,coresight-tmc", "arm,primecell"; + reg = <0x0 0x10b05000 0x0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + + in-ports { + port { + tmc_etf_in: endpoint { + remote-endpoint = <&funnel_aoss_out>; + }; + }; + }; + }; + + tpda@10b08000 { + compatible = "qcom,coresight-tpda", "arm,primecell"; + reg = <0x0 0x10b08000 0x0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + + in-ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + tpda_aoss_in0: endpoint { + remote-endpoint = <&tpdm_swao_prio0_out>; + }; + }; + + port@1 { + reg = <1>; + + tpda_aoss_in1: endpoint { + remote-endpoint = <&tpdm_swao_prio1_out>; + }; + }; + + port@2 { + reg = <2>; + + tpda_aoss_in2: endpoint { + remote-endpoint = <&tpdm_swao_prio2_out>; + }; + }; + + port@3 { + reg = <3>; + + tpda_aoss_in3: endpoint { + remote-endpoint = <&tpdm_swao_prio3_out>; + }; + }; + + port@4 { + reg = <4>; + + tpda_aoss_in4: endpoint { + remote-endpoint =<&tpdm_swao_out>; + }; + }; + }; + + out-ports { + port { + tpda_aoss_out: endpoint { + remote-endpoint = <&funnel_aoss_in6>; + }; + }; + }; + }; + + tpdm@10b09000 { + compatible = "qcom,coresight-tpdm", "arm,primecell"; + reg = <0x0 0x10b09000 0x0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + + qcom,cmb-element-bits = <64>; + qcom,cmb-msrs-num = <32>; + + out-ports { + port { + tpdm_swao_prio0_out: endpoint { + remote-endpoint = <&tpda_aoss_in0>; + }; + }; + }; + }; + + tpdm@10b0a000 { + compatible = "qcom,coresight-tpdm", "arm,primecell"; + reg = <0x0 0x10b0a000 0x0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + + qcom,cmb-element-bits = <64>; + qcom,cmb-msrs-num = <32>; + + out-ports { + port { + tpdm_swao_prio1_out: endpoint { + remote-endpoint = <&tpda_aoss_in1>; + }; + }; + }; + }; + + tpdm@10b0b000 { + compatible = "qcom,coresight-tpdm", "arm,primecell"; + reg = <0x0 0x10b0b000 0x0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + + qcom,cmb-element-bits = <64>; + qcom,cmb-msrs-num = <32>; + + out-ports { + port { + tpdm_swao_prio2_out: endpoint { + remote-endpoint = <&tpda_aoss_in2>; + }; + }; + }; + }; + + tpdm@10b0c000 { + compatible = "qcom,coresight-tpdm", "arm,primecell"; + reg = <0x0 0x10b0c000 0x0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + + qcom,cmb-element-bits = <64>; + qcom,cmb-msrs-num = <32>; + + out-ports { + port { + tpdm_swao_prio3_out: endpoint { + remote-endpoint = <&tpda_aoss_in3>; + }; + }; + }; + }; + + tpdm@10b0d000 { + compatible = "qcom,coresight-tpdm", "arm,primecell"; + reg = <0x0 0x10b0d000 0x0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + + qcom,dsb-element-bits = <32>; + qcom,dsb-msrs-num = <32>; + + out-ports { + port { + tpdm_swao_out: endpoint { + remote-endpoint = <&tpda_aoss_in4>; + }; + }; + }; + }; + apps_smmu: iommu@15000000 { compatible = "qcom,sm8750-smmu-500", "qcom,smmu-500", "arm,mmu-500"; reg = <0x0 0x15000000 0x0 0x100000>; @@ -3984,4 +4926,43 @@ , ; }; + + tpdm_llm { + compatible = "qcom,coresight-static-tpdm"; + qcom,cmb-element-bits = <32>; + + out-ports { + port { + tpdm_turing_llm_out: endpoint { + remote-endpoint = <&tpda_turing_in1>; + }; + }; + }; + }; + + tpdm_llm2 { + compatible = "qcom,coresight-static-tpdm"; + qcom,cmb-element-bits = <32>; + + out-ports { + port { + tpdm_turing_llm2_out: endpoint { + remote-endpoint = <&tpda_turing_in2>; + }; + }; + }; + }; + + tpdm_modem1 { + compatible = "qcom,coresight-static-tpdm"; + qcom,dsb-element-bits = <32>; + + out-ports { + port { + tpdm_modem1_out: endpoint { + remote-endpoint = <&tpda_modem_in1>; + }; + }; + }; + }; }; From 85e5961627457ccaeb772e570ac11c0a7bf78a28 Mon Sep 17 00:00:00 2001 From: Abel Vesa Date: Wed, 15 Oct 2025 16:42:54 +0300 Subject: [PATCH 0159/2333] FROMLIST: dt-bindings: phy: sc8280xp-qmp-pcie: Document Glymur PCIe Gen4 2-lanes PHY The fourth and sixth PCIe instances on Glymur are both Gen4 2-lane PHY. So document the compatible. Link: https://lore.kernel.org/all/20251015-phy-qcom-pcie-add-glymur-v1-1-1af8fd14f033@linaro.org/ Signed-off-by: Abel Vesa Reviewed-by: Krzysztof Kozlowski --- .../devicetree/bindings/phy/qcom,sc8280xp-qmp-pcie-phy.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-pcie-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-pcie-phy.yaml index 3e2480df9db72..fae9360cc3954 100644 --- a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-pcie-phy.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-pcie-phy.yaml @@ -16,6 +16,7 @@ description: properties: compatible: enum: + - qcom,glymur-qmp-gen4x2-pcie-phy - qcom,glymur-qmp-gen5x4-pcie-phy - qcom,qcs615-qmp-gen3x1-pcie-phy - qcom,qcs8300-qmp-gen4x2-pcie-phy @@ -178,6 +179,7 @@ allOf: compatible: contains: enum: + - qcom,glymur-qmp-gen4x2-pcie-phy - qcom,glymur-qmp-gen5x4-pcie-phy - qcom,qcs8300-qmp-gen4x2-pcie-phy - qcom,sa8775p-qmp-gen4x2-pcie-phy @@ -202,6 +204,7 @@ allOf: compatible: contains: enum: + - qcom,glymur-qmp-gen4x2-pcie-phy - qcom,glymur-qmp-gen5x4-pcie-phy - qcom,sm8550-qmp-gen4x2-pcie-phy - qcom,sm8650-qmp-gen4x2-pcie-phy From 4490847265d4793f82a141c92a05f536ed00f2b5 Mon Sep 17 00:00:00 2001 From: Abel Vesa Date: Wed, 15 Oct 2025 16:42:55 +0300 Subject: [PATCH 0160/2333] FROMLIST: phy: qcom: qmp-pcie: Add support for Glymur PCIe Gen4x2 PHY Glymur platform has two Gen4 2-lanes controllers, the fourth and sixth instances. Add support for their PHYs. Link: https://lore.kernel.org/all/20251015-phy-qcom-pcie-add-glymur-v1-2-1af8fd14f033@linaro.org/ Signed-off-by: Abel Vesa --- drivers/phy/qualcomm/phy-qcom-qmp-pcie.c | 34 ++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c index 86b1b7e2da86a..5b53f03771d8f 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c @@ -100,6 +100,12 @@ static const unsigned int pciephy_v7_regs_layout[QPHY_LAYOUT_SIZE] = { [QPHY_PCS_POWER_DOWN_CONTROL] = QPHY_V7_PCS_POWER_DOWN_CONTROL, }; +static const unsigned int pciephy_v8_regs_layout[QPHY_LAYOUT_SIZE] = { + [QPHY_START_CTRL] = QPHY_V8_PCS_START_CONTROL, + [QPHY_PCS_STATUS] = QPHY_V8_PCS_PCS_STATUS1, + [QPHY_PCS_POWER_DOWN_CONTROL] = QPHY_V8_PCS_POWER_DOWN_CONTROL, +}; + static const unsigned int pciephy_v8_50_regs_layout[QPHY_LAYOUT_SIZE] = { [QPHY_START_CTRL] = QPHY_V8_50_PCS_START_CONTROL, [QPHY_PCS_STATUS] = QPHY_V8_50_PCS_STATUS1, @@ -3363,6 +3369,15 @@ static const struct qmp_pcie_offsets qmp_pcie_offsets_v6_30 = { .ln_shrd = 0x8000, }; +static const struct qmp_pcie_offsets qmp_pcie_offsets_v8 = { + .serdes = 0x1000, + .pcs = 0x1400, + .tx = 0x0000, + .rx = 0x0200, + .tx2 = 0x0800, + .rx2 = 0x0a00, +}; + static const struct qmp_pcie_offsets qmp_pcie_offsets_v8_50 = { .serdes = 0x8000, .pcs = 0x9000, @@ -4441,6 +4456,22 @@ static const struct qmp_phy_cfg glymur_qmp_gen5x4_pciephy_cfg = { .phy_status = PHYSTATUS_4_20, }; +static const struct qmp_phy_cfg glymur_qmp_gen4x2_pciephy_cfg = { + .lanes = 2, + + .offsets = &qmp_pcie_offsets_v8, + + .reset_list = sdm845_pciephy_reset_l, + .num_resets = ARRAY_SIZE(sdm845_pciephy_reset_l), + .vreg_list = qmp_phy_vreg_l, + .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), + + .regs = pciephy_v8_regs_layout, + + .pwrdn_ctrl = SW_PWRDN | REFCLK_DRV_DSBL, + .phy_status = PHYSTATUS_4_20, +}; + static void qmp_pcie_init_port_b(struct qmp_pcie *qmp, const struct qmp_phy_cfg_tbls *tbls) { const struct qmp_phy_cfg *cfg = qmp->cfg; @@ -5192,6 +5223,9 @@ static int qmp_pcie_probe(struct platform_device *pdev) static const struct of_device_id qmp_pcie_of_match_table[] = { { + .compatible = "qcom,glymur-qmp-gen4x2-pcie-phy", + .data = &glymur_qmp_gen4x2_pciephy_cfg, + }, { .compatible = "qcom,glymur-qmp-gen5x4-pcie-phy", .data = &glymur_qmp_gen5x4_pciephy_cfg, }, { From d1d2c38f53e8f67b6a11866d4202561fbed0a988 Mon Sep 17 00:00:00 2001 From: Hangxiang Ma Date: Tue, 28 Oct 2025 22:44:10 -0700 Subject: [PATCH 0161/2333] FROMGIT: dt-bindings: i2c: qcom-cci: Document Kaanapali compatible Add Kaanapali compatible consistent with CAMSS CCI interfaces. Signed-off-by: Hangxiang Ma Reviewed-by: Loic Poulain Reviewed-by: Krzysztof Kozlowski Signed-off-by: Andi Shyti Link: https://lore.kernel.org/r/20251028-add-support-for-camss-on-kaanapali-v4-1-7eb484c89585@oss.qualcomm.com Signed-off-by: Yijie Yang --- Documentation/devicetree/bindings/i2c/qcom,i2c-cci.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/i2c/qcom,i2c-cci.yaml b/Documentation/devicetree/bindings/i2c/qcom,i2c-cci.yaml index ef6af05f7585b..3a03ffffdc57f 100644 --- a/Documentation/devicetree/bindings/i2c/qcom,i2c-cci.yaml +++ b/Documentation/devicetree/bindings/i2c/qcom,i2c-cci.yaml @@ -25,6 +25,7 @@ properties: - items: - enum: + - qcom,kaanapali-cci - qcom,qcm2290-cci - qcom,qcs8300-cci - qcom,sa8775p-cci @@ -129,6 +130,7 @@ allOf: compatible: contains: enum: + - qcom,kaanapali-cci - qcom,qcm2290-cci - qcom,qcs8300-cci then: From 288cbc6d945e9b2648340b16fffc2ba6e9ad9770 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Tue, 28 Oct 2025 13:46:20 +0200 Subject: [PATCH 0162/2333] FROMGIT: media: iris: turn platform caps into constants Make all struct platform_inst_fw_cap instances constant, they are not modified at runtime. Link: https://gitlab.freedesktop.org/linux-media/media-committers/-/commit/e5894eeefdebf5a6d7512cd23efec78071985738 Reviewed-by: Bryan O'Donoghue Reviewed-by: Dikshita Agarwal Reviewed-by: Vikash Garodia Signed-off-by: Dmitry Baryshkov --- drivers/media/platform/qcom/iris/iris_ctrls.c | 2 +- drivers/media/platform/qcom/iris/iris_platform_common.h | 4 ++-- drivers/media/platform/qcom/iris/iris_platform_gen2.c | 4 ++-- drivers/media/platform/qcom/iris/iris_platform_qcs8300.h | 4 ++-- drivers/media/platform/qcom/iris/iris_platform_sm8250.c | 4 ++-- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/media/platform/qcom/iris/iris_ctrls.c b/drivers/media/platform/qcom/iris/iris_ctrls.c index 754a5ad718bc3..9da050aa1f7ce 100644 --- a/drivers/media/platform/qcom/iris/iris_ctrls.c +++ b/drivers/media/platform/qcom/iris/iris_ctrls.c @@ -301,7 +301,7 @@ int iris_ctrls_init(struct iris_inst *inst) void iris_session_init_caps(struct iris_core *core) { - struct platform_inst_fw_cap *caps; + const struct platform_inst_fw_cap *caps; u32 i, num_cap, cap_id; caps = core->iris_platform_data->inst_fw_caps_dec; diff --git a/drivers/media/platform/qcom/iris/iris_platform_common.h b/drivers/media/platform/qcom/iris/iris_platform_common.h index 58d05e0a112ee..17ed86bf78bb3 100644 --- a/drivers/media/platform/qcom/iris/iris_platform_common.h +++ b/drivers/media/platform/qcom/iris/iris_platform_common.h @@ -215,9 +215,9 @@ struct iris_platform_data { const char *fwname; u32 pas_id; struct platform_inst_caps *inst_caps; - struct platform_inst_fw_cap *inst_fw_caps_dec; + const struct platform_inst_fw_cap *inst_fw_caps_dec; u32 inst_fw_caps_dec_size; - struct platform_inst_fw_cap *inst_fw_caps_enc; + const struct platform_inst_fw_cap *inst_fw_caps_enc; u32 inst_fw_caps_enc_size; struct tz_cp_config *tz_cp_config_data; u32 core_arch; diff --git a/drivers/media/platform/qcom/iris/iris_platform_gen2.c b/drivers/media/platform/qcom/iris/iris_platform_gen2.c index 36d69cc73986b..cbf38e13f89e5 100644 --- a/drivers/media/platform/qcom/iris/iris_platform_gen2.c +++ b/drivers/media/platform/qcom/iris/iris_platform_gen2.c @@ -19,7 +19,7 @@ #define VIDEO_ARCH_LX 1 #define BITRATE_MAX 245000000 -static struct platform_inst_fw_cap inst_fw_cap_sm8550_dec[] = { +static const struct platform_inst_fw_cap inst_fw_cap_sm8550_dec[] = { { .cap_id = PROFILE_H264, .min = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, @@ -203,7 +203,7 @@ static struct platform_inst_fw_cap inst_fw_cap_sm8550_dec[] = { }, }; -static struct platform_inst_fw_cap inst_fw_cap_sm8550_enc[] = { +static const struct platform_inst_fw_cap inst_fw_cap_sm8550_enc[] = { { .cap_id = PROFILE_H264, .min = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, diff --git a/drivers/media/platform/qcom/iris/iris_platform_qcs8300.h b/drivers/media/platform/qcom/iris/iris_platform_qcs8300.h index 35ea0efade73c..87517361a1cf4 100644 --- a/drivers/media/platform/qcom/iris/iris_platform_qcs8300.h +++ b/drivers/media/platform/qcom/iris/iris_platform_qcs8300.h @@ -5,7 +5,7 @@ #define BITRATE_MAX 245000000 -static struct platform_inst_fw_cap inst_fw_cap_qcs8300_dec[] = { +static const struct platform_inst_fw_cap inst_fw_cap_qcs8300_dec[] = { { .cap_id = PROFILE_H264, .min = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, @@ -189,7 +189,7 @@ static struct platform_inst_fw_cap inst_fw_cap_qcs8300_dec[] = { }, }; -static struct platform_inst_fw_cap inst_fw_cap_qcs8300_enc[] = { +static const struct platform_inst_fw_cap inst_fw_cap_qcs8300_enc[] = { { .cap_id = PROFILE_H264, .min = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, diff --git a/drivers/media/platform/qcom/iris/iris_platform_sm8250.c b/drivers/media/platform/qcom/iris/iris_platform_sm8250.c index 16486284f8acc..e29cba993fde9 100644 --- a/drivers/media/platform/qcom/iris/iris_platform_sm8250.c +++ b/drivers/media/platform/qcom/iris/iris_platform_sm8250.c @@ -17,7 +17,7 @@ #define BITRATE_PEAK_DEFAULT (BITRATE_DEFAULT * 2) #define BITRATE_STEP 100 -static struct platform_inst_fw_cap inst_fw_cap_sm8250_dec[] = { +static const struct platform_inst_fw_cap inst_fw_cap_sm8250_dec[] = { { .cap_id = PIPE, .min = PIPE_1, @@ -38,7 +38,7 @@ static struct platform_inst_fw_cap inst_fw_cap_sm8250_dec[] = { }, }; -static struct platform_inst_fw_cap inst_fw_cap_sm8250_enc[] = { +static const struct platform_inst_fw_cap inst_fw_cap_sm8250_enc[] = { { .cap_id = STAGE, .min = STAGE_1, From 83b26d8bfc84ebf1b09e939efc49b9abca8a598d Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Tue, 28 Oct 2025 13:46:21 +0200 Subject: [PATCH 0163/2333] FROMGIT: media: iris: turn platform data into constants Make all struct iris_platform_data instances constant, they are not modified at runtime. Link: https://gitlab.freedesktop.org/linux-media/media-committers/-/commit/7a02a8b98419c992faf8ab714cf4df7da99b2c46 Reviewed-by: Bryan O'Donoghue Reviewed-by: Dikshita Agarwal Reviewed-by: Vikash Garodia Signed-off-by: Dmitry Baryshkov --- .../media/platform/qcom/iris/iris_platform_common.h | 10 +++++----- drivers/media/platform/qcom/iris/iris_platform_gen2.c | 8 ++++---- .../media/platform/qcom/iris/iris_platform_sm8250.c | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/media/platform/qcom/iris/iris_platform_common.h b/drivers/media/platform/qcom/iris/iris_platform_common.h index 17ed86bf78bb3..5ffc1874e8c63 100644 --- a/drivers/media/platform/qcom/iris/iris_platform_common.h +++ b/drivers/media/platform/qcom/iris/iris_platform_common.h @@ -41,11 +41,11 @@ enum pipe_type { PIPE_4 = 4, }; -extern struct iris_platform_data qcs8300_data; -extern struct iris_platform_data sm8250_data; -extern struct iris_platform_data sm8550_data; -extern struct iris_platform_data sm8650_data; -extern struct iris_platform_data sm8750_data; +extern const struct iris_platform_data qcs8300_data; +extern const struct iris_platform_data sm8250_data; +extern const struct iris_platform_data sm8550_data; +extern const struct iris_platform_data sm8650_data; +extern const struct iris_platform_data sm8750_data; enum platform_clk_type { IRIS_AXI_CLK, /* AXI0 in case of platforms with multiple AXI clocks */ diff --git a/drivers/media/platform/qcom/iris/iris_platform_gen2.c b/drivers/media/platform/qcom/iris/iris_platform_gen2.c index cbf38e13f89e5..b444e81635562 100644 --- a/drivers/media/platform/qcom/iris/iris_platform_gen2.c +++ b/drivers/media/platform/qcom/iris/iris_platform_gen2.c @@ -737,7 +737,7 @@ static const u32 sm8550_enc_op_int_buf_tbl[] = { BUF_SCRATCH_2, }; -struct iris_platform_data sm8550_data = { +const struct iris_platform_data sm8550_data = { .get_instance = iris_hfi_gen2_get_instance, .init_hfi_command_ops = iris_hfi_gen2_command_ops_init, .init_hfi_response_ops = iris_hfi_gen2_response_ops_init, @@ -827,7 +827,7 @@ struct iris_platform_data sm8550_data = { * - controller_rst_tbl to sm8650_controller_reset_table * - fwname to "qcom/vpu/vpu33_p4.mbn" */ -struct iris_platform_data sm8650_data = { +const struct iris_platform_data sm8650_data = { .get_instance = iris_hfi_gen2_get_instance, .init_hfi_command_ops = iris_hfi_gen2_command_ops_init, .init_hfi_response_ops = iris_hfi_gen2_response_ops_init, @@ -912,7 +912,7 @@ struct iris_platform_data sm8650_data = { .enc_op_int_buf_tbl_size = ARRAY_SIZE(sm8550_enc_op_int_buf_tbl), }; -struct iris_platform_data sm8750_data = { +const struct iris_platform_data sm8750_data = { .get_instance = iris_hfi_gen2_get_instance, .init_hfi_command_ops = iris_hfi_gen2_command_ops_init, .init_hfi_response_ops = iris_hfi_gen2_response_ops_init, @@ -998,7 +998,7 @@ struct iris_platform_data sm8750_data = { * - inst_caps to platform_inst_cap_qcs8300 * - inst_fw_caps to inst_fw_cap_qcs8300 */ -struct iris_platform_data qcs8300_data = { +const struct iris_platform_data qcs8300_data = { .get_instance = iris_hfi_gen2_get_instance, .init_hfi_command_ops = iris_hfi_gen2_command_ops_init, .init_hfi_response_ops = iris_hfi_gen2_response_ops_init, diff --git a/drivers/media/platform/qcom/iris/iris_platform_sm8250.c b/drivers/media/platform/qcom/iris/iris_platform_sm8250.c index e29cba993fde9..66a5bdd24d8a0 100644 --- a/drivers/media/platform/qcom/iris/iris_platform_sm8250.c +++ b/drivers/media/platform/qcom/iris/iris_platform_sm8250.c @@ -314,7 +314,7 @@ static const u32 sm8250_enc_ip_int_buf_tbl[] = { BUF_SCRATCH_2, }; -struct iris_platform_data sm8250_data = { +const struct iris_platform_data sm8250_data = { .get_instance = iris_hfi_gen1_get_instance, .init_hfi_command_ops = &iris_hfi_gen1_command_ops_init, .init_hfi_response_ops = iris_hfi_gen1_response_ops_init, From fc8e962b34767673490d3267bb5d79372cc73b8b Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Tue, 28 Oct 2025 13:46:22 +0200 Subject: [PATCH 0164/2333] FROMGIT: media: iris: stop encoding PIPE value into fw_caps The value of the PIPE property depends on the number of pipes available on the platform and is frequently the only difference between several fw_caps. In order to reduce duplciation, use num_vpp_pipe from the iris_platform_data rather than hardcoding the value into the fw_cap. Link: https://gitlab.freedesktop.org/linux-media/media-committers/-/commit/6c67d1cf18dce081f126a6aeb9f7cbd328805591 Reviewed-by: Konrad Dybcio Reviewed-by: Vikash Garodia Reviewed-by: Dikshita Agarwal Signed-off-by: Dmitry Baryshkov --- drivers/media/platform/qcom/iris/iris_ctrls.c | 16 +++++++++++++--- .../platform/qcom/iris/iris_platform_gen2.c | 4 +--- .../platform/qcom/iris/iris_platform_qcs8300.h | 4 +--- .../platform/qcom/iris/iris_platform_sm8250.c | 4 +--- 4 files changed, 16 insertions(+), 12 deletions(-) diff --git a/drivers/media/platform/qcom/iris/iris_ctrls.c b/drivers/media/platform/qcom/iris/iris_ctrls.c index 9da050aa1f7ce..c0b3a09ad3e3d 100644 --- a/drivers/media/platform/qcom/iris/iris_ctrls.c +++ b/drivers/media/platform/qcom/iris/iris_ctrls.c @@ -313,13 +313,23 @@ void iris_session_init_caps(struct iris_core *core) continue; core->inst_fw_caps_dec[cap_id].cap_id = caps[i].cap_id; - core->inst_fw_caps_dec[cap_id].min = caps[i].min; - core->inst_fw_caps_dec[cap_id].max = caps[i].max; core->inst_fw_caps_dec[cap_id].step_or_mask = caps[i].step_or_mask; - core->inst_fw_caps_dec[cap_id].value = caps[i].value; core->inst_fw_caps_dec[cap_id].flags = caps[i].flags; core->inst_fw_caps_dec[cap_id].hfi_id = caps[i].hfi_id; core->inst_fw_caps_dec[cap_id].set = caps[i].set; + + if (cap_id == PIPE) { + core->inst_fw_caps_dec[cap_id].value = + core->iris_platform_data->num_vpp_pipe; + core->inst_fw_caps_dec[cap_id].min = + core->iris_platform_data->num_vpp_pipe; + core->inst_fw_caps_dec[cap_id].max = + core->iris_platform_data->num_vpp_pipe; + } else { + core->inst_fw_caps_dec[cap_id].min = caps[i].min; + core->inst_fw_caps_dec[cap_id].max = caps[i].max; + core->inst_fw_caps_dec[cap_id].value = caps[i].value; + } } caps = core->iris_platform_data->inst_fw_caps_enc; diff --git a/drivers/media/platform/qcom/iris/iris_platform_gen2.c b/drivers/media/platform/qcom/iris/iris_platform_gen2.c index b444e81635562..fb3fa1665c523 100644 --- a/drivers/media/platform/qcom/iris/iris_platform_gen2.c +++ b/drivers/media/platform/qcom/iris/iris_platform_gen2.c @@ -160,10 +160,8 @@ static const struct platform_inst_fw_cap inst_fw_cap_sm8550_dec[] = { }, { .cap_id = PIPE, - .min = PIPE_1, - .max = PIPE_4, + /* .max, .min and .value are set via platform data */ .step_or_mask = 1, - .value = PIPE_4, .hfi_id = HFI_PROP_PIPE, .set = iris_set_pipe, }, diff --git a/drivers/media/platform/qcom/iris/iris_platform_qcs8300.h b/drivers/media/platform/qcom/iris/iris_platform_qcs8300.h index 87517361a1cf4..7ae50ab22f8c5 100644 --- a/drivers/media/platform/qcom/iris/iris_platform_qcs8300.h +++ b/drivers/media/platform/qcom/iris/iris_platform_qcs8300.h @@ -146,10 +146,8 @@ static const struct platform_inst_fw_cap inst_fw_cap_qcs8300_dec[] = { }, { .cap_id = PIPE, - .min = PIPE_1, - .max = PIPE_2, + /* .max, .min and .value are set via platform data */ .step_or_mask = 1, - .value = PIPE_2, .hfi_id = HFI_PROP_PIPE, .set = iris_set_pipe, }, diff --git a/drivers/media/platform/qcom/iris/iris_platform_sm8250.c b/drivers/media/platform/qcom/iris/iris_platform_sm8250.c index 66a5bdd24d8a0..805179fba0c41 100644 --- a/drivers/media/platform/qcom/iris/iris_platform_sm8250.c +++ b/drivers/media/platform/qcom/iris/iris_platform_sm8250.c @@ -20,10 +20,8 @@ static const struct platform_inst_fw_cap inst_fw_cap_sm8250_dec[] = { { .cap_id = PIPE, - .min = PIPE_1, - .max = PIPE_4, + /* .max, .min and .value are set via platform data */ .step_or_mask = 1, - .value = PIPE_4, .hfi_id = HFI_PROPERTY_PARAM_WORK_ROUTE, .set = iris_set_pipe, }, From cc934834d92b9a94295908e8234660afa239e26c Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Tue, 28 Oct 2025 13:46:23 +0200 Subject: [PATCH 0165/2333] FROMGIT: media: iris: remove duplication between generic gen2 data and qcs8300 Now as we have removed PIPE value from inst_fw_caps_dec there should be no difference between inst_fw_caps of QCS8300 and SM8550+. Drop the QCS8300-specific tables and use generic one instead. The differences between QCS8300 and SM8550 data comes from a non-conflict merge of commit d22037f3fd33 ("media: iris: Set platform capabilities to firmware for encoder video device") (which added .set callbacks), and commit 6bdfa3f947a7 ("media: iris: Add platform-specific capabilities for encoder video device") (which added QCS8300 data, but not the callbacks). Link: https://gitlab.freedesktop.org/linux-media/media-committers/-/commit/69dfada4c9d077fefc968cca8186ce975d874d49 Reviewed-by: Vikash Garodia Reviewed-by: Dikshita Agarwal Signed-off-by: Dmitry Baryshkov --- .../platform/qcom/iris/iris_platform_gen2.c | 9 +- .../qcom/iris/iris_platform_qcs8300.h | 533 +----------------- 2 files changed, 8 insertions(+), 534 deletions(-) diff --git a/drivers/media/platform/qcom/iris/iris_platform_gen2.c b/drivers/media/platform/qcom/iris/iris_platform_gen2.c index fb3fa1665c523..2631b7317e086 100644 --- a/drivers/media/platform/qcom/iris/iris_platform_gen2.c +++ b/drivers/media/platform/qcom/iris/iris_platform_gen2.c @@ -994,7 +994,6 @@ const struct iris_platform_data sm8750_data = { /* * Shares most of SM8550 data except: * - inst_caps to platform_inst_cap_qcs8300 - * - inst_fw_caps to inst_fw_cap_qcs8300 */ const struct iris_platform_data qcs8300_data = { .get_instance = iris_hfi_gen2_get_instance, @@ -1020,10 +1019,10 @@ const struct iris_platform_data qcs8300_data = { .fwname = "qcom/vpu/vpu30_p4_s6.mbn", .pas_id = IRIS_PAS_ID, .inst_caps = &platform_inst_cap_qcs8300, - .inst_fw_caps_dec = inst_fw_cap_qcs8300_dec, - .inst_fw_caps_dec_size = ARRAY_SIZE(inst_fw_cap_qcs8300_dec), - .inst_fw_caps_enc = inst_fw_cap_qcs8300_enc, - .inst_fw_caps_enc_size = ARRAY_SIZE(inst_fw_cap_qcs8300_enc), + .inst_fw_caps_dec = inst_fw_cap_sm8550_dec, + .inst_fw_caps_dec_size = ARRAY_SIZE(inst_fw_cap_sm8550_dec), + .inst_fw_caps_enc = inst_fw_cap_sm8550_enc, + .inst_fw_caps_enc_size = ARRAY_SIZE(inst_fw_cap_sm8550_enc), .tz_cp_config_data = &tz_cp_config_sm8550, .core_arch = VIDEO_ARCH_LX, .hw_response_timeout = HW_RESPONSE_TIMEOUT_VALUE, diff --git a/drivers/media/platform/qcom/iris/iris_platform_qcs8300.h b/drivers/media/platform/qcom/iris/iris_platform_qcs8300.h index 7ae50ab22f8c5..61025f1e965b8 100644 --- a/drivers/media/platform/qcom/iris/iris_platform_qcs8300.h +++ b/drivers/media/platform/qcom/iris/iris_platform_qcs8300.h @@ -3,535 +3,8 @@ * Copyright (c) 2022-2025 Qualcomm Innovation Center, Inc. All rights reserved. */ -#define BITRATE_MAX 245000000 - -static const struct platform_inst_fw_cap inst_fw_cap_qcs8300_dec[] = { - { - .cap_id = PROFILE_H264, - .min = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, - .max = V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH, - .step_or_mask = BIT(V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) | - BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE) | - BIT(V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) | - BIT(V4L2_MPEG_VIDEO_H264_PROFILE_HIGH) | - BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH), - .value = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH, - .hfi_id = HFI_PROP_PROFILE, - .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, - .set = iris_set_u32_enum, - }, - { - .cap_id = PROFILE_HEVC, - .min = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, - .max = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE, - .step_or_mask = BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN) | - BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE), - .value = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, - .hfi_id = HFI_PROP_PROFILE, - .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, - .set = iris_set_u32_enum, - }, - { - .cap_id = PROFILE_VP9, - .min = V4L2_MPEG_VIDEO_VP9_PROFILE_0, - .max = V4L2_MPEG_VIDEO_VP9_PROFILE_2, - .step_or_mask = BIT(V4L2_MPEG_VIDEO_VP9_PROFILE_0) | - BIT(V4L2_MPEG_VIDEO_VP9_PROFILE_2), - .value = V4L2_MPEG_VIDEO_VP9_PROFILE_0, - .hfi_id = HFI_PROP_PROFILE, - .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, - .set = iris_set_u32_enum, - }, - { - .cap_id = LEVEL_H264, - .min = V4L2_MPEG_VIDEO_H264_LEVEL_1_0, - .max = V4L2_MPEG_VIDEO_H264_LEVEL_6_2, - .step_or_mask = BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_0) | - BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1B) | - BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_1) | - BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_2) | - BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_3) | - BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_0) | - BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_1) | - BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_2) | - BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_0) | - BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_1) | - BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_2) | - BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_0) | - BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_1) | - BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_2) | - BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_0) | - BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_1) | - BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_2) | - BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_0) | - BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_1) | - BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_2), - .value = V4L2_MPEG_VIDEO_H264_LEVEL_6_1, - .hfi_id = HFI_PROP_LEVEL, - .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, - .set = iris_set_u32_enum, - }, - { - .cap_id = LEVEL_HEVC, - .min = V4L2_MPEG_VIDEO_HEVC_LEVEL_1, - .max = V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2, - .step_or_mask = BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_1) | - BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2) | - BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1) | - BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3) | - BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1) | - BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4) | - BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1) | - BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5) | - BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1) | - BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2) | - BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6) | - BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1) | - BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2), - .value = V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1, - .hfi_id = HFI_PROP_LEVEL, - .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, - .set = iris_set_u32_enum, - }, - { - .cap_id = LEVEL_VP9, - .min = V4L2_MPEG_VIDEO_VP9_LEVEL_1_0, - .max = V4L2_MPEG_VIDEO_VP9_LEVEL_6_0, - .step_or_mask = BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_1_0) | - BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_1_1) | - BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_2_0) | - BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_2_1) | - BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_3_0) | - BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_3_1) | - BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_4_0) | - BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_4_1) | - BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_5_0) | - BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_5_1) | - BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_5_2) | - BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_6_0), - .value = V4L2_MPEG_VIDEO_VP9_LEVEL_6_0, - .hfi_id = HFI_PROP_LEVEL, - .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, - .set = iris_set_u32_enum, - }, - { - .cap_id = TIER, - .min = V4L2_MPEG_VIDEO_HEVC_TIER_MAIN, - .max = V4L2_MPEG_VIDEO_HEVC_TIER_HIGH, - .step_or_mask = BIT(V4L2_MPEG_VIDEO_HEVC_TIER_MAIN) | - BIT(V4L2_MPEG_VIDEO_HEVC_TIER_HIGH), - .value = V4L2_MPEG_VIDEO_HEVC_TIER_HIGH, - .hfi_id = HFI_PROP_TIER, - .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, - .set = iris_set_u32_enum, - }, - { - .cap_id = INPUT_BUF_HOST_MAX_COUNT, - .min = DEFAULT_MAX_HOST_BUF_COUNT, - .max = DEFAULT_MAX_HOST_BURST_BUF_COUNT, - .step_or_mask = 1, - .value = DEFAULT_MAX_HOST_BUF_COUNT, - .hfi_id = HFI_PROP_BUFFER_HOST_MAX_COUNT, - .flags = CAP_FLAG_INPUT_PORT, - .set = iris_set_u32, - }, - { - .cap_id = STAGE, - .min = STAGE_1, - .max = STAGE_2, - .step_or_mask = 1, - .value = STAGE_2, - .hfi_id = HFI_PROP_STAGE, - .set = iris_set_stage, - }, - { - .cap_id = PIPE, - /* .max, .min and .value are set via platform data */ - .step_or_mask = 1, - .hfi_id = HFI_PROP_PIPE, - .set = iris_set_pipe, - }, - { - .cap_id = POC, - .min = 0, - .max = 2, - .step_or_mask = 1, - .value = 1, - .hfi_id = HFI_PROP_PIC_ORDER_CNT_TYPE, - }, - { - .cap_id = CODED_FRAMES, - .min = CODED_FRAMES_PROGRESSIVE, - .max = CODED_FRAMES_PROGRESSIVE, - .step_or_mask = 0, - .value = CODED_FRAMES_PROGRESSIVE, - .hfi_id = HFI_PROP_CODED_FRAMES, - }, - { - .cap_id = BIT_DEPTH, - .min = BIT_DEPTH_8, - .max = BIT_DEPTH_8, - .step_or_mask = 1, - .value = BIT_DEPTH_8, - .hfi_id = HFI_PROP_LUMA_CHROMA_BIT_DEPTH, - }, - { - .cap_id = RAP_FRAME, - .min = 0, - .max = 1, - .step_or_mask = 1, - .value = 1, - .hfi_id = HFI_PROP_DEC_START_FROM_RAP_FRAME, - .flags = CAP_FLAG_INPUT_PORT, - .set = iris_set_u32, - }, -}; - -static const struct platform_inst_fw_cap inst_fw_cap_qcs8300_enc[] = { - { - .cap_id = PROFILE_H264, - .min = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, - .max = V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH, - .step_or_mask = BIT(V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) | - BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH) | - BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE) | - BIT(V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) | - BIT(V4L2_MPEG_VIDEO_H264_PROFILE_HIGH), - .value = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH, - .hfi_id = HFI_PROP_PROFILE, - .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, - }, - { - .cap_id = PROFILE_HEVC, - .min = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, - .max = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10, - .step_or_mask = BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN) | - BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE) | - BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10), - .value = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, - .hfi_id = HFI_PROP_PROFILE, - .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, - }, - { - .cap_id = LEVEL_H264, - .min = V4L2_MPEG_VIDEO_H264_LEVEL_1_0, - .max = V4L2_MPEG_VIDEO_H264_LEVEL_6_0, - .step_or_mask = BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_0) | - BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1B) | - BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_1) | - BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_2) | - BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_3) | - BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_0) | - BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_1) | - BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_2) | - BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_0) | - BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_1) | - BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_2) | - BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_0) | - BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_1) | - BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_2) | - BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_0) | - BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_1) | - BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_2) | - BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_0), - .value = V4L2_MPEG_VIDEO_H264_LEVEL_5_0, - .hfi_id = HFI_PROP_LEVEL, - .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, - }, - { - .cap_id = LEVEL_HEVC, - .min = V4L2_MPEG_VIDEO_HEVC_LEVEL_1, - .max = V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2, - .step_or_mask = BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_1) | - BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2) | - BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1) | - BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3) | - BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1) | - BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4) | - BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1) | - BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5) | - BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1) | - BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2) | - BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6) | - BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1) | - BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2), - .value = V4L2_MPEG_VIDEO_HEVC_LEVEL_5, - .hfi_id = HFI_PROP_LEVEL, - .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, - }, - { - .cap_id = STAGE, - .min = STAGE_1, - .max = STAGE_2, - .step_or_mask = 1, - .value = STAGE_2, - .hfi_id = HFI_PROP_STAGE, - }, - { - .cap_id = HEADER_MODE, - .min = V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE, - .max = V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME, - .step_or_mask = BIT(V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE) | - BIT(V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME), - .value = V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME, - .hfi_id = HFI_PROP_SEQ_HEADER_MODE, - .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, - }, - { - .cap_id = PREPEND_SPSPPS_TO_IDR, - .min = 0, - .max = 1, - .step_or_mask = 1, - .value = 0, - }, - { - .cap_id = BITRATE, - .min = 1, - .max = BITRATE_MAX, - .step_or_mask = 1, - .value = BITRATE_DEFAULT, - .hfi_id = HFI_PROP_TOTAL_BITRATE, - .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | - CAP_FLAG_DYNAMIC_ALLOWED, - }, - { - .cap_id = BITRATE_PEAK, - .min = 1, - .max = BITRATE_MAX, - .step_or_mask = 1, - .value = BITRATE_DEFAULT, - .hfi_id = HFI_PROP_TOTAL_PEAK_BITRATE, - .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | - CAP_FLAG_DYNAMIC_ALLOWED, - }, - { - .cap_id = BITRATE_MODE, - .min = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, - .max = V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, - .step_or_mask = BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) | - BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_CBR), - .value = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, - .hfi_id = HFI_PROP_RATE_CONTROL, - .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, - }, - { - .cap_id = FRAME_SKIP_MODE, - .min = V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED, - .max = V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT, - .step_or_mask = BIT(V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED) | - BIT(V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_LEVEL_LIMIT) | - BIT(V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT), - .value = V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED, - .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, - }, - { - .cap_id = FRAME_RC_ENABLE, - .min = 0, - .max = 1, - .step_or_mask = 1, - .value = 1, - }, - { - .cap_id = GOP_SIZE, - .min = 0, - .max = INT_MAX, - .step_or_mask = 1, - .value = 2 * DEFAULT_FPS - 1, - .hfi_id = HFI_PROP_MAX_GOP_FRAMES, - .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | - CAP_FLAG_DYNAMIC_ALLOWED, - }, - { - .cap_id = ENTROPY_MODE, - .min = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC, - .max = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC, - .step_or_mask = BIT(V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC) | - BIT(V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC), - .value = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC, - .hfi_id = HFI_PROP_CABAC_SESSION, - .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, - }, - { - .cap_id = MIN_FRAME_QP_H264, - .min = MIN_QP_8BIT, - .max = MAX_QP, - .step_or_mask = 1, - .value = MIN_QP_8BIT, - .hfi_id = HFI_PROP_MIN_QP_PACKED, - .flags = CAP_FLAG_OUTPUT_PORT, - }, - { - .cap_id = MIN_FRAME_QP_HEVC, - .min = MIN_QP_8BIT, - .max = MAX_QP, - .step_or_mask = 1, - .value = MIN_QP_8BIT, - .hfi_id = HFI_PROP_MIN_QP_PACKED, - .flags = CAP_FLAG_OUTPUT_PORT, - }, - { - .cap_id = MAX_FRAME_QP_H264, - .min = MIN_QP_8BIT, - .max = MAX_QP, - .step_or_mask = 1, - .value = MAX_QP, - .hfi_id = HFI_PROP_MAX_QP_PACKED, - .flags = CAP_FLAG_OUTPUT_PORT, - }, - { - .cap_id = MAX_FRAME_QP_HEVC, - .min = MIN_QP_8BIT, - .max = MAX_QP, - .step_or_mask = 1, - .value = MAX_QP, - .hfi_id = HFI_PROP_MAX_QP_PACKED, - .flags = CAP_FLAG_OUTPUT_PORT, - }, - { - .cap_id = I_FRAME_MIN_QP_H264, - .min = MIN_QP_8BIT, - .max = MAX_QP, - .step_or_mask = 1, - .value = MIN_QP_8BIT, - }, - { - .cap_id = I_FRAME_MIN_QP_HEVC, - .min = MIN_QP_8BIT, - .max = MAX_QP, - .step_or_mask = 1, - .value = MIN_QP_8BIT, - }, - { - .cap_id = P_FRAME_MIN_QP_H264, - .min = MIN_QP_8BIT, - .max = MAX_QP, - .step_or_mask = 1, - .value = MIN_QP_8BIT, - }, - { - .cap_id = P_FRAME_MIN_QP_HEVC, - .min = MIN_QP_8BIT, - .max = MAX_QP, - .step_or_mask = 1, - .value = MIN_QP_8BIT, - }, - { - .cap_id = B_FRAME_MIN_QP_H264, - .min = MIN_QP_8BIT, - .max = MAX_QP, - .step_or_mask = 1, - .value = MIN_QP_8BIT, - }, - { - .cap_id = B_FRAME_MIN_QP_HEVC, - .min = MIN_QP_8BIT, - .max = MAX_QP, - .step_or_mask = 1, - .value = MIN_QP_8BIT, - }, - { - .cap_id = I_FRAME_MAX_QP_H264, - .min = MIN_QP_8BIT, - .max = MAX_QP, - .step_or_mask = 1, - .value = MAX_QP, - }, - { - .cap_id = I_FRAME_MAX_QP_HEVC, - .min = MIN_QP_8BIT, - .max = MAX_QP, - .step_or_mask = 1, - .value = MAX_QP, - }, - { - .cap_id = P_FRAME_MAX_QP_H264, - .min = MIN_QP_8BIT, - .max = MAX_QP, - .step_or_mask = 1, - .value = MAX_QP, - }, - { - .cap_id = P_FRAME_MAX_QP_HEVC, - .min = MIN_QP_8BIT, - .max = MAX_QP, - .step_or_mask = 1, - .value = MAX_QP, - }, - { - .cap_id = B_FRAME_MAX_QP_H264, - .min = MIN_QP_8BIT, - .max = MAX_QP, - .step_or_mask = 1, - .value = MAX_QP, - }, - { - .cap_id = B_FRAME_MAX_QP_HEVC, - .min = MIN_QP_8BIT, - .max = MAX_QP, - .step_or_mask = 1, - .value = MAX_QP, - }, - { - .cap_id = I_FRAME_QP_H264, - .min = MIN_QP_8BIT, - .max = MAX_QP, - .step_or_mask = 1, - .value = DEFAULT_QP, - .hfi_id = HFI_PROP_QP_PACKED, - .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | - CAP_FLAG_DYNAMIC_ALLOWED, - }, - { - .cap_id = I_FRAME_QP_HEVC, - .min = MIN_QP_8BIT, - .max = MAX_QP, - .step_or_mask = 1, - .value = DEFAULT_QP, - .hfi_id = HFI_PROP_QP_PACKED, - .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | - CAP_FLAG_DYNAMIC_ALLOWED, - }, - { - .cap_id = P_FRAME_QP_H264, - .min = MIN_QP_8BIT, - .max = MAX_QP, - .step_or_mask = 1, - .value = DEFAULT_QP, - .hfi_id = HFI_PROP_QP_PACKED, - .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | - CAP_FLAG_DYNAMIC_ALLOWED, - }, - { - .cap_id = P_FRAME_QP_HEVC, - .min = MIN_QP_8BIT, - .max = MAX_QP, - .step_or_mask = 1, - .value = DEFAULT_QP, - .hfi_id = HFI_PROP_QP_PACKED, - .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | - CAP_FLAG_DYNAMIC_ALLOWED, - }, - { - .cap_id = B_FRAME_QP_H264, - .min = MIN_QP_8BIT, - .max = MAX_QP, - .step_or_mask = 1, - .value = DEFAULT_QP, - .hfi_id = HFI_PROP_QP_PACKED, - .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | - CAP_FLAG_DYNAMIC_ALLOWED, - }, - { - .cap_id = B_FRAME_QP_HEVC, - .min = MIN_QP_8BIT, - .max = MAX_QP, - .step_or_mask = 1, - .value = DEFAULT_QP, - .hfi_id = HFI_PROP_QP_PACKED, - .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | - CAP_FLAG_DYNAMIC_ALLOWED, - }, -}; +#ifndef __IRIS_PLATFORM_QCS8300_H__ +#define __IRIS_PLATFORM_QCS8300_H__ static struct platform_inst_caps platform_inst_cap_qcs8300 = { .min_frame_width = 96, @@ -546,3 +19,5 @@ static struct platform_inst_caps platform_inst_cap_qcs8300 = { .max_frame_rate = MAXIMUM_FPS, .max_operating_rate = MAXIMUM_FPS, }; + +#endif From d10e1ac896ab7bc16532b42eff25f62f71db160a Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Tue, 28 Oct 2025 13:46:24 +0200 Subject: [PATCH 0166/2333] FROMGIT: media: iris: rename sm8250 platform file to gen1 In preparation to adding more Gen1 platforms, which will share a significant amount of data, rename the SM8250 platform file to iris_platform_gen1.c. Link: https://gitlab.freedesktop.org/linux-media/media-committers/-/commit/3b72f5e206e65d57df99677dc3142be913cc2114 Reviewed-by: Konrad Dybcio Reviewed-by: Dikshita Agarwal Reviewed-by: Vikash Garodia Signed-off-by: Dmitry Baryshkov --- drivers/media/platform/qcom/iris/Makefile | 2 +- .../qcom/iris/{iris_platform_sm8250.c => iris_platform_gen1.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename drivers/media/platform/qcom/iris/{iris_platform_sm8250.c => iris_platform_gen1.c} (100%) diff --git a/drivers/media/platform/qcom/iris/Makefile b/drivers/media/platform/qcom/iris/Makefile index 13270cd6d8998..fad3be044e5fe 100644 --- a/drivers/media/platform/qcom/iris/Makefile +++ b/drivers/media/platform/qcom/iris/Makefile @@ -26,7 +26,7 @@ qcom-iris-objs += iris_buffer.o \ iris_vpu_common.o \ ifeq ($(CONFIG_VIDEO_QCOM_VENUS),) -qcom-iris-objs += iris_platform_sm8250.o +qcom-iris-objs += iris_platform_gen1.o endif obj-$(CONFIG_VIDEO_QCOM_IRIS) += qcom-iris.o diff --git a/drivers/media/platform/qcom/iris/iris_platform_sm8250.c b/drivers/media/platform/qcom/iris/iris_platform_gen1.c similarity index 100% rename from drivers/media/platform/qcom/iris/iris_platform_sm8250.c rename to drivers/media/platform/qcom/iris/iris_platform_gen1.c From 7d67edc1f56799a2efd9b019eadebd18cf235816 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Tue, 28 Oct 2025 13:46:25 +0200 Subject: [PATCH 0167/2333] FROMGIT: media: iris: enable support for SC7280 platform As a part of migrating code from the old Venus driver to the new Iris one, add support for the SC7280 platform. It is very similar to SM8250, but it (currently) uses no reset controls (there is an optional GCC-generated reset, it will be added later) and no AON registers region. Extend the VPU ops to support optional clocks and skip the AON shutdown for this platform. Link: https://gitlab.freedesktop.org/linux-media/media-committers/-/commit/542e3540ddd75f0a46dd365978476bcc1dda5b5a Signed-off-by: Dmitry Baryshkov Reviewed-by: Vikash Garodia Reviewed-by: Dikshita Agarwal --- .../platform/qcom/iris/iris_platform_common.h | 4 ++ .../platform/qcom/iris/iris_platform_gen1.c | 53 +++++++++++++++++++ .../platform/qcom/iris/iris_platform_sc7280.h | 26 +++++++++ drivers/media/platform/qcom/iris/iris_probe.c | 4 ++ .../media/platform/qcom/iris/iris_resources.c | 2 +- drivers/media/platform/qcom/iris/iris_vpu2.c | 6 +++ .../platform/qcom/iris/iris_vpu_common.c | 34 ++++++++---- 7 files changed, 119 insertions(+), 10 deletions(-) create mode 100644 drivers/media/platform/qcom/iris/iris_platform_sc7280.h diff --git a/drivers/media/platform/qcom/iris/iris_platform_common.h b/drivers/media/platform/qcom/iris/iris_platform_common.h index 5ffc1874e8c63..8d8cdb56a3c77 100644 --- a/drivers/media/platform/qcom/iris/iris_platform_common.h +++ b/drivers/media/platform/qcom/iris/iris_platform_common.h @@ -42,6 +42,7 @@ enum pipe_type { }; extern const struct iris_platform_data qcs8300_data; +extern const struct iris_platform_data sc7280_data; extern const struct iris_platform_data sm8250_data; extern const struct iris_platform_data sm8550_data; extern const struct iris_platform_data sm8650_data; @@ -50,7 +51,9 @@ extern const struct iris_platform_data sm8750_data; enum platform_clk_type { IRIS_AXI_CLK, /* AXI0 in case of platforms with multiple AXI clocks */ IRIS_CTRL_CLK, + IRIS_AHB_CLK, IRIS_HW_CLK, + IRIS_HW_AHB_CLK, IRIS_AXI1_CLK, IRIS_CTRL_FREERUN_CLK, IRIS_HW_FREERUN_CLK, @@ -224,6 +227,7 @@ struct iris_platform_data { u32 hw_response_timeout; struct ubwc_config_data *ubwc_config; u32 num_vpp_pipe; + bool no_aon; u32 max_session_count; /* max number of macroblocks per frame supported */ u32 max_core_mbpf; diff --git a/drivers/media/platform/qcom/iris/iris_platform_gen1.c b/drivers/media/platform/qcom/iris/iris_platform_gen1.c index 805179fba0c41..34cbeb8f52e24 100644 --- a/drivers/media/platform/qcom/iris/iris_platform_gen1.c +++ b/drivers/media/platform/qcom/iris/iris_platform_gen1.c @@ -12,6 +12,8 @@ #include "iris_vpu_buffer.h" #include "iris_vpu_common.h" +#include "iris_platform_sc7280.h" + #define BITRATE_MIN 32000 #define BITRATE_MAX 160000000 #define BITRATE_PEAK_DEFAULT (BITRATE_DEFAULT * 2) @@ -362,3 +364,54 @@ const struct iris_platform_data sm8250_data = { .enc_ip_int_buf_tbl = sm8250_enc_ip_int_buf_tbl, .enc_ip_int_buf_tbl_size = ARRAY_SIZE(sm8250_enc_ip_int_buf_tbl), }; + +const struct iris_platform_data sc7280_data = { + .get_instance = iris_hfi_gen1_get_instance, + .init_hfi_command_ops = &iris_hfi_gen1_command_ops_init, + .init_hfi_response_ops = iris_hfi_gen1_response_ops_init, + .get_vpu_buffer_size = iris_vpu_buf_size, + .vpu_ops = &iris_vpu2_ops, + .set_preset_registers = iris_set_sm8250_preset_registers, + .icc_tbl = sm8250_icc_table, + .icc_tbl_size = ARRAY_SIZE(sm8250_icc_table), + .bw_tbl_dec = sc7280_bw_table_dec, + .bw_tbl_dec_size = ARRAY_SIZE(sc7280_bw_table_dec), + .pmdomain_tbl = sm8250_pmdomain_table, + .pmdomain_tbl_size = ARRAY_SIZE(sm8250_pmdomain_table), + .opp_pd_tbl = sc7280_opp_pd_table, + .opp_pd_tbl_size = ARRAY_SIZE(sc7280_opp_pd_table), + .clk_tbl = sc7280_clk_table, + .clk_tbl_size = ARRAY_SIZE(sc7280_clk_table), + /* Upper bound of DMA address range */ + .dma_mask = 0xe0000000 - 1, + .fwname = "qcom/vpu/vpu20_p1.mbn", + .pas_id = IRIS_PAS_ID, + .inst_caps = &platform_inst_cap_sm8250, + .inst_fw_caps_dec = inst_fw_cap_sm8250_dec, + .inst_fw_caps_dec_size = ARRAY_SIZE(inst_fw_cap_sm8250_dec), + .inst_fw_caps_enc = inst_fw_cap_sm8250_enc, + .inst_fw_caps_enc_size = ARRAY_SIZE(inst_fw_cap_sm8250_enc), + .tz_cp_config_data = &tz_cp_config_sm8250, + .hw_response_timeout = HW_RESPONSE_TIMEOUT_VALUE, + .num_vpp_pipe = 1, + .no_aon = true, + .max_session_count = 16, + .max_core_mbpf = 4096 * 2176 / 256 * 2 + 1920 * 1088 / 256, + /* max spec for SC7280 is 4096x2176@60fps */ + .max_core_mbps = 4096 * 2176 / 256 * 60, + .dec_input_config_params_default = + sm8250_vdec_input_config_param_default, + .dec_input_config_params_default_size = + ARRAY_SIZE(sm8250_vdec_input_config_param_default), + .enc_input_config_params = sm8250_venc_input_config_param, + .enc_input_config_params_size = + ARRAY_SIZE(sm8250_venc_input_config_param), + + .dec_ip_int_buf_tbl = sm8250_dec_ip_int_buf_tbl, + .dec_ip_int_buf_tbl_size = ARRAY_SIZE(sm8250_dec_ip_int_buf_tbl), + .dec_op_int_buf_tbl = sm8250_dec_op_int_buf_tbl, + .dec_op_int_buf_tbl_size = ARRAY_SIZE(sm8250_dec_op_int_buf_tbl), + + .enc_ip_int_buf_tbl = sm8250_enc_ip_int_buf_tbl, + .enc_ip_int_buf_tbl_size = ARRAY_SIZE(sm8250_enc_ip_int_buf_tbl), +}; diff --git a/drivers/media/platform/qcom/iris/iris_platform_sc7280.h b/drivers/media/platform/qcom/iris/iris_platform_sc7280.h new file mode 100644 index 0000000000000..f1bef4d4bcfe8 --- /dev/null +++ b/drivers/media/platform/qcom/iris/iris_platform_sc7280.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#ifndef __IRIS_PLATFORM_SC7280_H__ +#define __IRIS_PLATFORM_SC7280_H__ + +static const struct bw_info sc7280_bw_table_dec[] = { + { ((3840 * 2160) / 256) * 60, 1896000, }, + { ((3840 * 2160) / 256) * 30, 968000, }, + { ((1920 * 1080) / 256) * 60, 618000, }, + { ((1920 * 1080) / 256) * 30, 318000, }, +}; + +static const char * const sc7280_opp_pd_table[] = { "cx" }; + +static const struct platform_clk_data sc7280_clk_table[] = { + {IRIS_CTRL_CLK, "core" }, + {IRIS_AXI_CLK, "iface" }, + {IRIS_AHB_CLK, "bus" }, + {IRIS_HW_CLK, "vcodec_core" }, + {IRIS_HW_AHB_CLK, "vcodec_bus" }, +}; + +#endif diff --git a/drivers/media/platform/qcom/iris/iris_probe.c b/drivers/media/platform/qcom/iris/iris_probe.c index 00e99be16e087..9bc9b34c25765 100644 --- a/drivers/media/platform/qcom/iris/iris_probe.c +++ b/drivers/media/platform/qcom/iris/iris_probe.c @@ -357,6 +357,10 @@ static const struct of_device_id iris_dt_match[] = { .data = &qcs8300_data, }, #if (!IS_ENABLED(CONFIG_VIDEO_QCOM_VENUS)) + { + .compatible = "qcom,sc7280-venus", + .data = &sc7280_data, + }, { .compatible = "qcom,sm8250-venus", .data = &sm8250_data, diff --git a/drivers/media/platform/qcom/iris/iris_resources.c b/drivers/media/platform/qcom/iris/iris_resources.c index cf32f268b703c..164490c49c95e 100644 --- a/drivers/media/platform/qcom/iris/iris_resources.c +++ b/drivers/media/platform/qcom/iris/iris_resources.c @@ -112,7 +112,7 @@ int iris_prepare_enable_clock(struct iris_core *core, enum platform_clk_type clk clock = iris_get_clk_by_type(core, clk_type); if (!clock) - return -EINVAL; + return -ENOENT; return clk_prepare_enable(clock); } diff --git a/drivers/media/platform/qcom/iris/iris_vpu2.c b/drivers/media/platform/qcom/iris/iris_vpu2.c index de7d142316d2d..9c103a2e4e4ea 100644 --- a/drivers/media/platform/qcom/iris/iris_vpu2.c +++ b/drivers/media/platform/qcom/iris/iris_vpu2.c @@ -3,9 +3,15 @@ * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ +#include +#include +#include + #include "iris_instance.h" #include "iris_vpu_common.h" +#include "iris_vpu_register_defines.h" + static u64 iris_vpu2_calc_freq(struct iris_inst *inst, size_t data_size) { struct platform_inst_caps *caps = inst->core->iris_platform_data->inst_caps; diff --git a/drivers/media/platform/qcom/iris/iris_vpu_common.c b/drivers/media/platform/qcom/iris/iris_vpu_common.c index bb98950e018fa..515dd55a3377e 100644 --- a/drivers/media/platform/qcom/iris/iris_vpu_common.c +++ b/drivers/media/platform/qcom/iris/iris_vpu_common.c @@ -222,12 +222,14 @@ int iris_vpu_power_off_controller(struct iris_core *core) writel(MSK_SIGNAL_FROM_TENSILICA | MSK_CORE_POWER_ON, core->reg_base + CPU_CS_X2RPMH); - writel(REQ_POWER_DOWN_PREP, core->reg_base + AON_WRAPPER_MVP_NOC_LPI_CONTROL); + if (!core->iris_platform_data->no_aon) { + writel(REQ_POWER_DOWN_PREP, core->reg_base + AON_WRAPPER_MVP_NOC_LPI_CONTROL); - ret = readl_poll_timeout(core->reg_base + AON_WRAPPER_MVP_NOC_LPI_STATUS, - val, val & BIT(0), 200, 2000); - if (ret) - goto disable_power; + ret = readl_poll_timeout(core->reg_base + AON_WRAPPER_MVP_NOC_LPI_STATUS, + val, val & BIT(0), 200, 2000); + if (ret) + goto disable_power; + } writel(REQ_POWER_DOWN_PREP, core->reg_base + WRAPPER_IRIS_CPU_NOC_LPI_CONTROL); @@ -250,6 +252,7 @@ int iris_vpu_power_off_controller(struct iris_core *core) writel(0x0, core->reg_base + WRAPPER_TZ_CTL_AXI_CLOCK_CONFIG); disable_power: + iris_disable_unprepare_clock(core, IRIS_AHB_CLK); iris_disable_unprepare_clock(core, IRIS_CTRL_CLK); iris_disable_unprepare_clock(core, IRIS_AXI_CLK); iris_disable_power_domains(core, core->pmdomain_tbl->pd_devs[IRIS_CTRL_POWER_DOMAIN]); @@ -261,6 +264,7 @@ void iris_vpu_power_off_hw(struct iris_core *core) { dev_pm_genpd_set_hwmode(core->pmdomain_tbl->pd_devs[IRIS_HW_POWER_DOMAIN], false); iris_disable_power_domains(core, core->pmdomain_tbl->pd_devs[IRIS_HW_POWER_DOMAIN]); + iris_disable_unprepare_clock(core, IRIS_HW_AHB_CLK); iris_disable_unprepare_clock(core, IRIS_HW_CLK); } @@ -294,11 +298,17 @@ int iris_vpu_power_on_controller(struct iris_core *core) ret = iris_prepare_enable_clock(core, IRIS_CTRL_CLK); if (ret) - goto err_disable_clock; + goto err_disable_axi_clock; + + ret = iris_prepare_enable_clock(core, IRIS_AHB_CLK); + if (ret && ret != -ENOENT) + goto err_disable_ctrl_clock; return 0; -err_disable_clock: +err_disable_ctrl_clock: + iris_disable_unprepare_clock(core, IRIS_CTRL_CLK); +err_disable_axi_clock: iris_disable_unprepare_clock(core, IRIS_AXI_CLK); err_disable_power: iris_disable_power_domains(core, core->pmdomain_tbl->pd_devs[IRIS_CTRL_POWER_DOMAIN]); @@ -318,13 +328,19 @@ int iris_vpu_power_on_hw(struct iris_core *core) if (ret) goto err_disable_power; + ret = iris_prepare_enable_clock(core, IRIS_HW_AHB_CLK); + if (ret && ret != -ENOENT) + goto err_disable_hw_clock; + ret = dev_pm_genpd_set_hwmode(core->pmdomain_tbl->pd_devs[IRIS_HW_POWER_DOMAIN], true); if (ret) - goto err_disable_clock; + goto err_disable_hw_ahb_clock; return 0; -err_disable_clock: +err_disable_hw_ahb_clock: + iris_disable_unprepare_clock(core, IRIS_HW_AHB_CLK); +err_disable_hw_clock: iris_disable_unprepare_clock(core, IRIS_HW_CLK); err_disable_power: iris_disable_power_domains(core, core->pmdomain_tbl->pd_devs[IRIS_HW_POWER_DOMAIN]); From 898674e251fbcb619f87fe987cac0934b5f531a9 Mon Sep 17 00:00:00 2001 From: Dikshita Agarwal Date: Sun, 2 Nov 2025 09:10:19 +0530 Subject: [PATCH 0168/2333] FROMLIST: media: iris: remove v4l2_m2m_ioctl_{de,en}coder_cmd API usage during STOP handling Currently v4l2_m2m_ioctl_{de,enc}coder_cmd is being invoked during STOP command handling. However, this is not required as the iris driver has its own drain and stop handling mechanism in place. Using the m2m command API in this context leads to incorrect behavior, where the LAST flag is prematurely attached to a capture buffer, when there are no buffers in m2m source queue. But, in this scenario even though the source buffers are returned to client, hardware might still need to process the pending capture buffers. Attaching LAST flag prematurely can result in the capture buffer being removed from the destination queue before the hardware has finished processing it, causing issues when the buffer is eventually returned by the hardware. To prevent this, remove the m2m API usage in stop handling. Link: https://lore.kernel.org/linux-media/20251102-iris-drain-fix-v1-1-7f88d187fb48@oss.qualcomm.com/ Fixes: d09100763bed ("media: iris: add support for drain sequence") Fixes: 75db90ae067d ("media: iris: Add support for drain sequence in encoder video device") Reviewed-by: Vikash Garodia Signed-off-by: Dikshita Agarwal --- drivers/media/platform/qcom/iris/iris_vidc.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/media/platform/qcom/iris/iris_vidc.c b/drivers/media/platform/qcom/iris/iris_vidc.c index d38d0f6961cd5..07682400de690 100644 --- a/drivers/media/platform/qcom/iris/iris_vidc.c +++ b/drivers/media/platform/qcom/iris/iris_vidc.c @@ -572,9 +572,10 @@ static int iris_dec_cmd(struct file *filp, void *fh, mutex_lock(&inst->lock); - ret = v4l2_m2m_ioctl_decoder_cmd(filp, fh, dec); - if (ret) + if (dec->cmd != V4L2_DEC_CMD_STOP && dec->cmd != V4L2_DEC_CMD_START) { + ret = -EINVAL; goto unlock; + } if (inst->state == IRIS_INST_DEINIT) goto unlock; @@ -605,9 +606,10 @@ static int iris_enc_cmd(struct file *filp, void *fh, mutex_lock(&inst->lock); - ret = v4l2_m2m_ioctl_encoder_cmd(filp, fh, enc); - if (ret) + if (enc->cmd != V4L2_ENC_CMD_STOP && enc->cmd != V4L2_ENC_CMD_START) { + ret = -EINVAL; goto unlock; + } if (inst->state == IRIS_INST_DEINIT) goto unlock; From f0661a528baaf9233238151e36329c61b0afc938 Mon Sep 17 00:00:00 2001 From: Wei Deng Date: Thu, 13 Nov 2025 12:10:10 +0530 Subject: [PATCH 0169/2333] FROMLIST: arm64: dts: qcom: qcs8300-ride: Enable Bluetooth support Enable BT on qcs8300-ride by adding a BT device tree node. Since the platform uses the QCA6698 Bluetooth chip. While the QCA6698 shares the same IP core as the WCN6855, it has different RF components and RAM sizes, requiring new firmware files. Use the firmware-name property to specify the NVM and rampatch firmware to load. Link: https://lore.kernel.org/all/20251118140406.1551669-2-wei.deng@oss.qualcomm.com/ Signed-off-by: Wei Deng --- arch/arm64/boot/dts/qcom/qcs8300-ride.dts | 28 +++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/qcs8300-ride.dts b/arch/arm64/boot/dts/qcom/qcs8300-ride.dts index 1d69d79572d56..0509d17a911a7 100644 --- a/arch/arm64/boot/dts/qcom/qcs8300-ride.dts +++ b/arch/arm64/boot/dts/qcom/qcs8300-ride.dts @@ -18,6 +18,7 @@ aliases { serial0 = &uart7; mmc0 = &sdhc_1; + serial1 = &uart2; }; chosen { @@ -83,6 +84,7 @@ vddpcie1p3-supply = <&vreg_conn_pa>; vddpcie1p9-supply = <&vreg_conn_1p8>; + bt-enable-gpios = <&tlmm 55 GPIO_ACTIVE_HIGH>; wlan-enable-gpios = <&tlmm 54 GPIO_ACTIVE_HIGH>; regulators { @@ -544,6 +546,13 @@ }; &tlmm { + bt_en_state: bt-en-state { + pins = "gpio55"; + function = "gpio"; + bias-pull-down; + output-low; + }; + ethernet0_default: ethernet0-default-state { ethernet0_mdc: ethernet0-mdc-pins { pins = "gpio5"; @@ -620,6 +629,25 @@ }; }; +&uart2 { + status = "okay"; + + bluetooth: bluetooth { + compatible = "qcom,wcn6855-bt"; + firmware-name = "QCA6698/hpnv21", "QCA6698/hpbtfw21.tlv"; + max-speed = <3200000>; + + vddrfacmn-supply = <&vreg_pmu_rfa_cmn>; + vddaon-supply = <&vreg_pmu_aon_0p59>; + vddwlcx-supply = <&vreg_pmu_wlcx_0p8>; + vddwlmx-supply = <&vreg_pmu_wlmx_0p85>; + vddbtcmx-supply = <&vreg_pmu_btcmx_0p85>; + vddrfa0p8-supply = <&vreg_pmu_rfa_0p8>; + vddrfa1p2-supply = <&vreg_pmu_rfa_1p2>; + vddrfa1p8-supply = <&vreg_pmu_rfa_1p7>; + }; +}; + &uart7 { status = "okay"; }; From 042aeae28a6050a564ebc9364713487dcd4a2623 Mon Sep 17 00:00:00 2001 From: Dikshita Agarwal Date: Wed, 8 Oct 2025 15:22:25 +0530 Subject: [PATCH 0170/2333] FROMGIT: media: iris: Add support for HFI_PROP_OPB_ENABLE to control split mode Add handling for the HFI_PROP_OPB_ENABLE property, which allows enabling or disabling split mode in the firmware. When HFI_PROP_OPB_ENABLE is set to true, the firmware activates split mode for output picture buffers (OPB). The OPB format is determined by the HFI_PROP_COLOR_FORMAT property, supporting NV12 or QC08C formats. Link: https://lore.kernel.org/linux-media/20251008-video-iris-ubwc-enable-v2-1-478ba2d96427@oss.qualcomm.com/ Reviewed-by: Vikash Garodia Signed-off-by: Dikshita Agarwal --- .../platform/qcom/iris/iris_hfi_gen2_command.c | 15 +++++++++++++++ .../platform/qcom/iris/iris_hfi_gen2_defines.h | 1 + .../media/platform/qcom/iris/iris_platform_gen2.c | 1 + 3 files changed, 17 insertions(+) diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen2_command.c b/drivers/media/platform/qcom/iris/iris_hfi_gen2_command.c index 4ce71a1425083..56ced61de924e 100644 --- a/drivers/media/platform/qcom/iris/iris_hfi_gen2_command.c +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen2_command.c @@ -422,6 +422,20 @@ static int iris_hfi_gen2_set_level(struct iris_inst *inst, u32 plane) sizeof(u32)); } +static int iris_hfi_gen2_set_opb_enable(struct iris_inst *inst, u32 plane) +{ + u32 port = iris_hfi_gen2_get_port(inst, plane); + u32 opb_enable = iris_split_mode_enabled(inst); + + return iris_hfi_gen2_session_set_property(inst, + HFI_PROP_OPB_ENABLE, + HFI_HOST_FLAGS_NONE, + port, + HFI_PAYLOAD_U32, + &opb_enable, + sizeof(u32)); +} + static int iris_hfi_gen2_set_colorformat(struct iris_inst *inst, u32 plane) { u32 port = iris_hfi_gen2_get_port(inst, plane); @@ -527,6 +541,7 @@ static int iris_hfi_gen2_session_set_config_params(struct iris_inst *inst, u32 p {HFI_PROP_SIGNAL_COLOR_INFO, iris_hfi_gen2_set_colorspace }, {HFI_PROP_PROFILE, iris_hfi_gen2_set_profile }, {HFI_PROP_LEVEL, iris_hfi_gen2_set_level }, + {HFI_PROP_OPB_ENABLE, iris_hfi_gen2_set_opb_enable }, {HFI_PROP_COLOR_FORMAT, iris_hfi_gen2_set_colorformat }, {HFI_PROP_LINEAR_STRIDE_SCANLINE, iris_hfi_gen2_set_linear_stride_scanline }, {HFI_PROP_TIER, iris_hfi_gen2_set_tier }, diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen2_defines.h b/drivers/media/platform/qcom/iris/iris_hfi_gen2_defines.h index aa1f795f5626c..1b6a4dbac828f 100644 --- a/drivers/media/platform/qcom/iris/iris_hfi_gen2_defines.h +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen2_defines.h @@ -91,6 +91,7 @@ enum hfi_seq_header_mode { #define HFI_PROP_BUFFER_MARK 0x0300016c #define HFI_PROP_RAW_RESOLUTION 0x03000178 #define HFI_PROP_TOTAL_PEAK_BITRATE 0x0300017C +#define HFI_PROP_OPB_ENABLE 0x03000184 #define HFI_PROP_COMV_BUFFER_COUNT 0x03000193 #define HFI_PROP_END 0x03FFFFFF diff --git a/drivers/media/platform/qcom/iris/iris_platform_gen2.c b/drivers/media/platform/qcom/iris/iris_platform_gen2.c index 2631b7317e086..c1989240c2486 100644 --- a/drivers/media/platform/qcom/iris/iris_platform_gen2.c +++ b/drivers/media/platform/qcom/iris/iris_platform_gen2.c @@ -689,6 +689,7 @@ static const u32 sm8550_venc_input_config_params[] = { }; static const u32 sm8550_vdec_output_config_params[] = { + HFI_PROP_OPB_ENABLE, HFI_PROP_COLOR_FORMAT, HFI_PROP_LINEAR_STRIDE_SCANLINE, }; From 727c4b54dbd7ba8958b70ba169b744def33b5ce8 Mon Sep 17 00:00:00 2001 From: Dikshita Agarwal Date: Wed, 8 Oct 2025 15:22:26 +0530 Subject: [PATCH 0171/2333] FROMGIT: media: iris: Add support for QC08C format for decoder Introduce handling for the QC08C format in the decoder. QC08C format is NV12 with UBWC compression. Update format checks and configuration to enable decoding of QC08C streams. Link: https://lore.kernel.org/linux-media/20251008-video-iris-ubwc-enable-v2-2-478ba2d96427@oss.qualcomm.com/ Reviewed-by: Vikash Garodia Signed-off-by: Dikshita Agarwal --- .../media/platform/qcom/iris/iris_buffer.c | 5 +- .../qcom/iris/iris_hfi_gen1_command.c | 12 ++-- .../qcom/iris/iris_hfi_gen2_command.c | 3 +- .../media/platform/qcom/iris/iris_instance.h | 7 ++- drivers/media/platform/qcom/iris/iris_utils.c | 3 +- drivers/media/platform/qcom/iris/iris_vdec.c | 61 +++++++++++++++---- 6 files changed, 72 insertions(+), 19 deletions(-) diff --git a/drivers/media/platform/qcom/iris/iris_buffer.c b/drivers/media/platform/qcom/iris/iris_buffer.c index c0900038e7def..83dcf49e57ec1 100644 --- a/drivers/media/platform/qcom/iris/iris_buffer.c +++ b/drivers/media/platform/qcom/iris/iris_buffer.c @@ -261,7 +261,10 @@ int iris_get_buffer_size(struct iris_inst *inst, case BUF_INPUT: return iris_dec_bitstream_buffer_size(inst); case BUF_OUTPUT: - return iris_yuv_buffer_size_nv12(inst); + if (inst->fmt_dst->fmt.pix_mp.pixelformat == V4L2_PIX_FMT_QC08C) + return iris_yuv_buffer_size_qc08c(inst); + else + return iris_yuv_buffer_size_nv12(inst); case BUF_DPB: return iris_yuv_buffer_size_qc08c(inst); default: diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen1_command.c b/drivers/media/platform/qcom/iris/iris_hfi_gen1_command.c index e1788c266bb10..e458d3349ce09 100644 --- a/drivers/media/platform/qcom/iris/iris_hfi_gen1_command.c +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen1_command.c @@ -774,20 +774,21 @@ static int iris_hfi_gen1_set_raw_format(struct iris_inst *inst, u32 plane) pixelformat = inst->fmt_dst->fmt.pix_mp.pixelformat; if (iris_split_mode_enabled(inst)) { fmt.buffer_type = HFI_BUFFER_OUTPUT; - fmt.format = pixelformat == V4L2_PIX_FMT_NV12 ? - HFI_COLOR_FORMAT_NV12_UBWC : 0; + fmt.format = HFI_COLOR_FORMAT_NV12_UBWC; ret = hfi_gen1_set_property(inst, ptype, &fmt, sizeof(fmt)); if (ret) return ret; fmt.buffer_type = HFI_BUFFER_OUTPUT2; - fmt.format = pixelformat == V4L2_PIX_FMT_NV12 ? HFI_COLOR_FORMAT_NV12 : 0; + fmt.format = pixelformat == V4L2_PIX_FMT_NV12 ? + HFI_COLOR_FORMAT_NV12 : HFI_COLOR_FORMAT_NV12_UBWC; ret = hfi_gen1_set_property(inst, ptype, &fmt, sizeof(fmt)); } else { fmt.buffer_type = HFI_BUFFER_OUTPUT; - fmt.format = pixelformat == V4L2_PIX_FMT_NV12 ? HFI_COLOR_FORMAT_NV12 : 0; + fmt.format = pixelformat == V4L2_PIX_FMT_NV12 ? + HFI_COLOR_FORMAT_NV12 : HFI_COLOR_FORMAT_NV12_UBWC; ret = hfi_gen1_set_property(inst, ptype, &fmt, sizeof(fmt)); } @@ -806,6 +807,9 @@ static int iris_hfi_gen1_set_format_constraints(struct iris_inst *inst, u32 plan const u32 ptype = HFI_PROPERTY_PARAM_UNCOMPRESSED_PLANE_ACTUAL_CONSTRAINTS_INFO; struct hfi_uncompressed_plane_actual_constraints_info pconstraint; + if (inst->fmt_dst->fmt.pix_mp.pixelformat == V4L2_PIX_FMT_QC08C) + return 0; + pconstraint.buffer_type = HFI_BUFFER_OUTPUT2; pconstraint.num_planes = 2; pconstraint.plane_format[0].stride_multiples = 128; diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen2_command.c b/drivers/media/platform/qcom/iris/iris_hfi_gen2_command.c index 56ced61de924e..5ad202d3fcdc5 100644 --- a/drivers/media/platform/qcom/iris/iris_hfi_gen2_command.c +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen2_command.c @@ -443,7 +443,8 @@ static int iris_hfi_gen2_set_colorformat(struct iris_inst *inst, u32 plane) if (inst->domain == DECODER) { pixelformat = inst->fmt_dst->fmt.pix_mp.pixelformat; - hfi_colorformat = pixelformat == V4L2_PIX_FMT_NV12 ? HFI_COLOR_FMT_NV12 : 0; + hfi_colorformat = pixelformat == V4L2_PIX_FMT_NV12 ? + HFI_COLOR_FMT_NV12 : HFI_COLOR_FMT_NV12_UBWC; } else { pixelformat = inst->fmt_src->fmt.pix_mp.pixelformat; hfi_colorformat = pixelformat == V4L2_PIX_FMT_NV12 ? HFI_COLOR_FMT_NV12 : 0; diff --git a/drivers/media/platform/qcom/iris/iris_instance.h b/drivers/media/platform/qcom/iris/iris_instance.h index 5982d7adefeab..62fbb30691ff9 100644 --- a/drivers/media/platform/qcom/iris/iris_instance.h +++ b/drivers/media/platform/qcom/iris/iris_instance.h @@ -15,12 +15,17 @@ #define DEFAULT_WIDTH 320 #define DEFAULT_HEIGHT 240 -enum iris_fmt_type { +enum iris_fmt_type_out { IRIS_FMT_H264, IRIS_FMT_HEVC, IRIS_FMT_VP9, }; +enum iris_fmt_type_cap { + IRIS_FMT_NV12, + IRIS_FMT_QC08C, +}; + struct iris_fmt { u32 pixfmt; u32 type; diff --git a/drivers/media/platform/qcom/iris/iris_utils.c b/drivers/media/platform/qcom/iris/iris_utils.c index 85c70a62b1fd2..e2f1131de4312 100644 --- a/drivers/media/platform/qcom/iris/iris_utils.c +++ b/drivers/media/platform/qcom/iris/iris_utils.c @@ -34,7 +34,8 @@ int iris_get_mbpf(struct iris_inst *inst) bool iris_split_mode_enabled(struct iris_inst *inst) { - return inst->fmt_dst->fmt.pix_mp.pixelformat == V4L2_PIX_FMT_NV12; + return inst->fmt_dst->fmt.pix_mp.pixelformat == V4L2_PIX_FMT_NV12 || + inst->fmt_dst->fmt.pix_mp.pixelformat == V4L2_PIX_FMT_QC08C; } void iris_helper_buffers_done(struct iris_inst *inst, unsigned int type, diff --git a/drivers/media/platform/qcom/iris/iris_vdec.c b/drivers/media/platform/qcom/iris/iris_vdec.c index ae13c3e1b426b..96844325b24e2 100644 --- a/drivers/media/platform/qcom/iris/iris_vdec.c +++ b/drivers/media/platform/qcom/iris/iris_vdec.c @@ -67,7 +67,7 @@ void iris_vdec_inst_deinit(struct iris_inst *inst) kfree(inst->fmt_src); } -static const struct iris_fmt iris_vdec_formats[] = { +static const struct iris_fmt iris_vdec_formats_out[] = { [IRIS_FMT_H264] = { .pixfmt = V4L2_PIX_FMT_H264, .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, @@ -82,12 +82,35 @@ static const struct iris_fmt iris_vdec_formats[] = { }, }; +static const struct iris_fmt iris_vdec_formats_cap[] = { + [IRIS_FMT_NV12] = { + .pixfmt = V4L2_PIX_FMT_NV12, + .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, + }, + [IRIS_FMT_QC08C] = { + .pixfmt = V4L2_PIX_FMT_QC08C, + .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, + }, +}; + static const struct iris_fmt * find_format(struct iris_inst *inst, u32 pixfmt, u32 type) { - unsigned int size = ARRAY_SIZE(iris_vdec_formats); - const struct iris_fmt *fmt = iris_vdec_formats; + const struct iris_fmt *fmt = NULL; + unsigned int size = 0; unsigned int i; + switch (type) { + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + fmt = iris_vdec_formats_out; + size = ARRAY_SIZE(iris_vdec_formats_out); + break; + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + fmt = iris_vdec_formats_cap; + size = ARRAY_SIZE(iris_vdec_formats_cap); + break; + default: + return NULL; + } for (i = 0; i < size; i++) { if (fmt[i].pixfmt == pixfmt) @@ -103,8 +126,21 @@ find_format(struct iris_inst *inst, u32 pixfmt, u32 type) static const struct iris_fmt * find_format_by_index(struct iris_inst *inst, u32 index, u32 type) { - const struct iris_fmt *fmt = iris_vdec_formats; - unsigned int size = ARRAY_SIZE(iris_vdec_formats); + const struct iris_fmt *fmt = NULL; + unsigned int size = 0; + + switch (type) { + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + fmt = iris_vdec_formats_out; + size = ARRAY_SIZE(iris_vdec_formats_out); + break; + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + fmt = iris_vdec_formats_cap; + size = ARRAY_SIZE(iris_vdec_formats_cap); + break; + default: + return NULL; + } if (index >= size || fmt[index].type != type) return NULL; @@ -126,9 +162,10 @@ int iris_vdec_enum_fmt(struct iris_inst *inst, struct v4l2_fmtdesc *f) f->flags = V4L2_FMT_FLAG_COMPRESSED | V4L2_FMT_FLAG_DYN_RESOLUTION; break; case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - if (f->index) + fmt = find_format_by_index(inst, f->index, f->type); + if (!fmt) return -EINVAL; - f->pixelformat = V4L2_PIX_FMT_NV12; + f->pixelformat = fmt->pixfmt; break; default: return -EINVAL; @@ -157,7 +194,7 @@ int iris_vdec_try_fmt(struct iris_inst *inst, struct v4l2_format *f) } break; case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - if (f->fmt.pix_mp.pixelformat != V4L2_PIX_FMT_NV12) { + if (!fmt) { f_inst = inst->fmt_dst; f->fmt.pix_mp.pixelformat = f_inst->fmt.pix_mp.pixelformat; f->fmt.pix_mp.width = f_inst->fmt.pix_mp.width; @@ -238,10 +275,11 @@ int iris_vdec_s_fmt(struct iris_inst *inst, struct v4l2_format *f) inst->crop.height = f->fmt.pix_mp.height; break; case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + if (!(find_format(inst, f->fmt.pix_mp.pixelformat, f->type))) + return -EINVAL; + fmt = inst->fmt_dst; fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; - if (fmt->fmt.pix_mp.pixelformat != V4L2_PIX_FMT_NV12) - return -EINVAL; fmt->fmt.pix_mp.pixelformat = f->fmt.pix_mp.pixelformat; fmt->fmt.pix_mp.width = ALIGN(f->fmt.pix_mp.width, 128); fmt->fmt.pix_mp.height = ALIGN(f->fmt.pix_mp.height, 32); @@ -268,7 +306,8 @@ int iris_vdec_validate_format(struct iris_inst *inst, u32 pixelformat) { const struct iris_fmt *fmt = NULL; - if (pixelformat != V4L2_PIX_FMT_NV12) { + fmt = find_format(inst, pixelformat, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); + if (!fmt) { fmt = find_format(inst, pixelformat, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); if (!fmt) return -EINVAL; From e7cd57ebf4650d1fc4e4c635545c39cf1074d1a3 Mon Sep 17 00:00:00 2001 From: Dikshita Agarwal Date: Wed, 8 Oct 2025 15:22:27 +0530 Subject: [PATCH 0172/2333] FROMGIT: media: iris: Add support for QC08C format for encoder Introduce handling for the QC08C format in the encoder. QC08C format is NV12 with UBWC compression. Update format checks and configuration to enable encoding to QC08C streams. Link: https://lore.kernel.org/linux-media/20251008-video-iris-ubwc-enable-v2-3-478ba2d96427@oss.qualcomm.com/ Reviewed-by: Vikash Garodia Signed-off-by: Dikshita Agarwal --- .../media/platform/qcom/iris/iris_buffer.c | 12 +++- .../qcom/iris/iris_hfi_gen1_command.c | 3 +- .../qcom/iris/iris_hfi_gen2_command.c | 3 +- drivers/media/platform/qcom/iris/iris_venc.c | 59 +++++++++++++++---- 4 files changed, 63 insertions(+), 14 deletions(-) diff --git a/drivers/media/platform/qcom/iris/iris_buffer.c b/drivers/media/platform/qcom/iris/iris_buffer.c index 83dcf49e57ec1..b89b1ee06cce1 100644 --- a/drivers/media/platform/qcom/iris/iris_buffer.c +++ b/drivers/media/platform/qcom/iris/iris_buffer.c @@ -171,9 +171,14 @@ static u32 iris_yuv_buffer_size_nv12(struct iris_inst *inst) static u32 iris_yuv_buffer_size_qc08c(struct iris_inst *inst) { u32 y_plane, uv_plane, y_stride, uv_stride; - struct v4l2_format *f = inst->fmt_dst; u32 uv_meta_stride, uv_meta_plane; u32 y_meta_stride, y_meta_plane; + struct v4l2_format *f = NULL; + + if (inst->domain == DECODER) + f = inst->fmt_dst; + else + f = inst->fmt_src; y_meta_stride = ALIGN(DIV_ROUND_UP(f->fmt.pix_mp.width, META_STRIDE_ALIGNED >> 1), META_STRIDE_ALIGNED); @@ -273,7 +278,10 @@ int iris_get_buffer_size(struct iris_inst *inst, } else { switch (buffer_type) { case BUF_INPUT: - return iris_yuv_buffer_size_nv12(inst); + if (inst->fmt_src->fmt.pix_mp.pixelformat == V4L2_PIX_FMT_QC08C) + return iris_yuv_buffer_size_qc08c(inst); + else + return iris_yuv_buffer_size_nv12(inst); case BUF_OUTPUT: return iris_enc_bitstream_buffer_size(inst); default: diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen1_command.c b/drivers/media/platform/qcom/iris/iris_hfi_gen1_command.c index e458d3349ce09..52da7ef7bab08 100644 --- a/drivers/media/platform/qcom/iris/iris_hfi_gen1_command.c +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen1_command.c @@ -795,7 +795,8 @@ static int iris_hfi_gen1_set_raw_format(struct iris_inst *inst, u32 plane) } else { pixelformat = inst->fmt_src->fmt.pix_mp.pixelformat; fmt.buffer_type = HFI_BUFFER_INPUT; - fmt.format = pixelformat == V4L2_PIX_FMT_NV12 ? HFI_COLOR_FORMAT_NV12 : 0; + fmt.format = pixelformat == V4L2_PIX_FMT_NV12 ? + HFI_COLOR_FORMAT_NV12 : HFI_COLOR_FORMAT_NV12_UBWC; ret = hfi_gen1_set_property(inst, ptype, &fmt, sizeof(fmt)); } diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen2_command.c b/drivers/media/platform/qcom/iris/iris_hfi_gen2_command.c index 5ad202d3fcdc5..6a772db2ec33f 100644 --- a/drivers/media/platform/qcom/iris/iris_hfi_gen2_command.c +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen2_command.c @@ -447,7 +447,8 @@ static int iris_hfi_gen2_set_colorformat(struct iris_inst *inst, u32 plane) HFI_COLOR_FMT_NV12 : HFI_COLOR_FMT_NV12_UBWC; } else { pixelformat = inst->fmt_src->fmt.pix_mp.pixelformat; - hfi_colorformat = pixelformat == V4L2_PIX_FMT_NV12 ? HFI_COLOR_FMT_NV12 : 0; + hfi_colorformat = pixelformat == V4L2_PIX_FMT_NV12 ? + HFI_COLOR_FMT_NV12 : HFI_COLOR_FMT_NV12_UBWC; } return iris_hfi_gen2_session_set_property(inst, diff --git a/drivers/media/platform/qcom/iris/iris_venc.c b/drivers/media/platform/qcom/iris/iris_venc.c index 099bd5ed4ae02..95e3ceb22d8c3 100644 --- a/drivers/media/platform/qcom/iris/iris_venc.c +++ b/drivers/media/platform/qcom/iris/iris_venc.c @@ -80,7 +80,7 @@ void iris_venc_inst_deinit(struct iris_inst *inst) kfree(inst->fmt_src); } -static const struct iris_fmt iris_venc_formats[] = { +static const struct iris_fmt iris_venc_formats_cap[] = { [IRIS_FMT_H264] = { .pixfmt = V4L2_PIX_FMT_H264, .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, @@ -91,12 +91,35 @@ static const struct iris_fmt iris_venc_formats[] = { }, }; +static const struct iris_fmt iris_venc_formats_out[] = { + [IRIS_FMT_NV12] = { + .pixfmt = V4L2_PIX_FMT_NV12, + .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, + }, + [IRIS_FMT_QC08C] = { + .pixfmt = V4L2_PIX_FMT_QC08C, + .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, + }, +}; + static const struct iris_fmt * find_format(struct iris_inst *inst, u32 pixfmt, u32 type) { - const struct iris_fmt *fmt = iris_venc_formats; - unsigned int size = ARRAY_SIZE(iris_venc_formats); + const struct iris_fmt *fmt = NULL; + unsigned int size = 0; unsigned int i; + switch (type) { + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + fmt = iris_venc_formats_out; + size = ARRAY_SIZE(iris_venc_formats_out); + break; + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + fmt = iris_venc_formats_cap; + size = ARRAY_SIZE(iris_venc_formats_cap); + break; + default: + return NULL; + } for (i = 0; i < size; i++) { if (fmt[i].pixfmt == pixfmt) @@ -112,8 +135,21 @@ find_format(struct iris_inst *inst, u32 pixfmt, u32 type) static const struct iris_fmt * find_format_by_index(struct iris_inst *inst, u32 index, u32 type) { - const struct iris_fmt *fmt = iris_venc_formats; - unsigned int size = ARRAY_SIZE(iris_venc_formats); + const struct iris_fmt *fmt = NULL; + unsigned int size = 0; + + switch (type) { + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + fmt = iris_venc_formats_out; + size = ARRAY_SIZE(iris_venc_formats_out); + break; + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + fmt = iris_venc_formats_cap; + size = ARRAY_SIZE(iris_venc_formats_cap); + break; + default: + return NULL; + } if (index >= size || fmt[index].type != type) return NULL; @@ -127,9 +163,11 @@ int iris_venc_enum_fmt(struct iris_inst *inst, struct v4l2_fmtdesc *f) switch (f->type) { case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - if (f->index) + fmt = find_format_by_index(inst, f->index, f->type); + if (!fmt) return -EINVAL; - f->pixelformat = V4L2_PIX_FMT_NV12; + + f->pixelformat = fmt->pixfmt; break; case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: fmt = find_format_by_index(inst, f->index, f->type); @@ -156,7 +194,7 @@ int iris_venc_try_fmt(struct iris_inst *inst, struct v4l2_format *f) fmt = find_format(inst, pixmp->pixelformat, f->type); switch (f->type) { case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - if (f->fmt.pix_mp.pixelformat != V4L2_PIX_FMT_NV12) { + if (!fmt) { f_inst = inst->fmt_src; f->fmt.pix_mp.width = f_inst->fmt.pix_mp.width; f->fmt.pix_mp.height = f_inst->fmt.pix_mp.height; @@ -221,7 +259,7 @@ static int iris_venc_s_fmt_input(struct iris_inst *inst, struct v4l2_format *f) iris_venc_try_fmt(inst, f); - if (f->fmt.pix_mp.pixelformat != V4L2_PIX_FMT_NV12) + if (!(find_format(inst, f->fmt.pix_mp.pixelformat, f->type))) return -EINVAL; fmt = inst->fmt_src; @@ -289,7 +327,8 @@ int iris_venc_validate_format(struct iris_inst *inst, u32 pixelformat) { const struct iris_fmt *fmt = NULL; - if (pixelformat != V4L2_PIX_FMT_NV12) { + fmt = find_format(inst, pixelformat, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); + if (!fmt) { fmt = find_format(inst, pixelformat, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); if (!fmt) return -EINVAL; From 7f5810fcacaeb01685dd149e10d84b3ed3485a07 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 26 Oct 2025 20:11:38 +0200 Subject: [PATCH 0173/2333] FROMGIT: media: qcom: iris: Constify iris_v4l2_file_ops The iris_v4l2_file_ops structure is never modified. Make it const. Link: https://lore.kernel.org/linux-media/20251026181138.13387-1-laurent.pinchart@ideasonboard.com/ Signed-off-by: Laurent Pinchart Reviewed-by: Dikshita Agarwal Reviewed-by: Abel Vesa --- drivers/media/platform/qcom/iris/iris_vidc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/qcom/iris/iris_vidc.c b/drivers/media/platform/qcom/iris/iris_vidc.c index 07682400de690..0c9c23ef2d180 100644 --- a/drivers/media/platform/qcom/iris/iris_vidc.c +++ b/drivers/media/platform/qcom/iris/iris_vidc.c @@ -632,7 +632,7 @@ static int iris_enc_cmd(struct file *filp, void *fh, return ret; } -static struct v4l2_file_operations iris_v4l2_file_ops = { +static const struct v4l2_file_operations iris_v4l2_file_ops = { .owner = THIS_MODULE, .open = iris_open, .release = iris_close, From 511774aba822fd8e494d7b8ca66d0e7a3b5d427a Mon Sep 17 00:00:00 2001 From: Dikshita Agarwal Date: Wed, 5 Nov 2025 11:17:37 +0530 Subject: [PATCH 0174/2333] FROMGIT: media: iris: Refine internal buffer reconfiguration logic for resolution change Improve the condition used to determine when input internal buffers need to be reconfigured during streamon on the capture port. Previously, the check relied on the INPUT_PAUSE sub-state, which was also being set during seek operations. This led to input buffers being queued multiple times to the firmware, causing session errors due to duplicate buffer submissions. This change introduces a more accurate check using the FIRST_IPSC and DRC sub-states to ensure that input buffer reconfiguration is triggered only during resolution change scenarios, such as streamoff/on on the capture port. This avoids duplicate buffer queuing during seek operations. Link: https://lore.kernel.org/linux-media/20251105-iris-seek-fix-v3-1-279debaba37a@oss.qualcomm.com/ Fixes: c1f8b2cc72ec ("media: iris: handle streamoff/on from client in dynamic resolution change") Cc: stable@vger.kernel.org Reported-by: Val Packett Closes: https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/4700 Reviewed-by: Vikash Garodia Signed-off-by: Dikshita Agarwal --- drivers/media/platform/qcom/iris/iris_common.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/qcom/iris/iris_common.c b/drivers/media/platform/qcom/iris/iris_common.c index 9fc663bdaf3fc..7f1c7fe144f70 100644 --- a/drivers/media/platform/qcom/iris/iris_common.c +++ b/drivers/media/platform/qcom/iris/iris_common.c @@ -91,12 +91,14 @@ int iris_process_streamon_input(struct iris_inst *inst) int iris_process_streamon_output(struct iris_inst *inst) { const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; - bool drain_active = false, drc_active = false; enum iris_inst_sub_state clear_sub_state = 0; + bool drain_active, drc_active, first_ipsc; int ret = 0; iris_scale_power(inst); + first_ipsc = inst->sub_state & IRIS_INST_SUB_FIRST_IPSC; + drain_active = inst->sub_state & IRIS_INST_SUB_DRAIN && inst->sub_state & IRIS_INST_SUB_DRAIN_LAST; @@ -108,7 +110,8 @@ int iris_process_streamon_output(struct iris_inst *inst) else if (drain_active) clear_sub_state = IRIS_INST_SUB_DRAIN | IRIS_INST_SUB_DRAIN_LAST; - if (inst->domain == DECODER && inst->sub_state & IRIS_INST_SUB_INPUT_PAUSE) { + /* Input internal buffer reconfiguration required in case of resolution change */ + if (first_ipsc || drc_active) { ret = iris_alloc_and_queue_input_int_bufs(inst); if (ret) return ret; From 1af1bf9935671af7c556b7e952a9afd2def6a58d Mon Sep 17 00:00:00 2001 From: Wangao Wang Date: Mon, 27 Oct 2025 17:35:59 +0800 Subject: [PATCH 0175/2333] FROMGIT: media: qcom: iris: Add sanity check for stop streaming Add sanity check in iris_vb2_stop_streaming. If inst->state is already IRIS_INST_ERROR, we should skip the stream_off operation because it would still send packets to the firmware. In iris_kill_session, inst->state is set to IRIS_INST_ERROR and session_close is executed, which will kfree(inst_hfi_gen2->packet). If stop_streaming is called afterward, it will cause a crash. Fixes: 11712ce70f8e5 ("media: iris: implement vb2 streaming ops") Link: https://lore.kernel.org/linux-media/20251027-iris_add_sanity_check-v3-1-232ad24d75d3@oss.qualcomm.com/ Reviewed-by: Bryan O'Donoghue Reviewed-by: Dikshita Agarwal Signed-off-by: Wangao Wang Reviewed-by: Vikash Garodia --- drivers/media/platform/qcom/iris/iris_vb2.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/qcom/iris/iris_vb2.c b/drivers/media/platform/qcom/iris/iris_vb2.c index 139b821f7952f..db8768d8a8f61 100644 --- a/drivers/media/platform/qcom/iris/iris_vb2.c +++ b/drivers/media/platform/qcom/iris/iris_vb2.c @@ -231,6 +231,8 @@ void iris_vb2_stop_streaming(struct vb2_queue *q) return; mutex_lock(&inst->lock); + if (inst->state == IRIS_INST_ERROR) + goto exit; if (!V4L2_TYPE_IS_OUTPUT(q->type) && !V4L2_TYPE_IS_CAPTURE(q->type)) @@ -241,10 +243,10 @@ void iris_vb2_stop_streaming(struct vb2_queue *q) goto exit; exit: - iris_helper_buffers_done(inst, q->type, VB2_BUF_STATE_ERROR); - if (ret) + if (ret) { + iris_helper_buffers_done(inst, q->type, VB2_BUF_STATE_ERROR); iris_inst_change_state(inst, IRIS_INST_ERROR); - + } mutex_unlock(&inst->lock); } From d2eda134a196cbefd3c83c04ed37801946b8b29d Mon Sep 17 00:00:00 2001 From: Jingyi Wang Date: Wed, 24 Sep 2025 17:17:18 -0700 Subject: [PATCH 0176/2333] FROMLIST: dt-bindings: arm: qcom: Document Kaanapali SoC and its reference boards Document the Kaanapali SoC binding and the boards which use it. Signed-off-by: Jingyi Wang Signed-off-by: Yijie Yang Link: https://lore.kernel.org/all/20250924-knp-dts-v1-1-3fdbc4b9e1b1@oss.qualcomm.com/ --- Documentation/devicetree/bindings/arm/qcom.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Documentation/devicetree/bindings/arm/qcom.yaml b/Documentation/devicetree/bindings/arm/qcom.yaml index 18b5ed044f9fc..b338dbb642225 100644 --- a/Documentation/devicetree/bindings/arm/qcom.yaml +++ b/Documentation/devicetree/bindings/arm/qcom.yaml @@ -321,6 +321,12 @@ properties: - qcom,ipq9574-ap-al02-c9 - const: qcom,ipq9574 + - items: + - enum: + - qcom,kaanapali-mtp + - qcom,kaanapali-qrd + - const: qcom,kaanapali + - description: Sierra Wireless MangOH Green with WP8548 Module items: - const: swir,mangoh-green-wp8548 From 083da23bf6c9b9311803102b0c5a611972d07abf Mon Sep 17 00:00:00 2001 From: Jingyi Wang Date: Wed, 24 Sep 2025 17:17:19 -0700 Subject: [PATCH 0177/2333] FROMLIST: arm64: dts: qcom: Introduce Kaanapali SoC Kaanapali is Snapdragon SoC from Qualcomm. Features added in this patch: - CPUs with PSCI idle states and cpufreq - Interrupt-controller with PDC wakeup support - Timers, TCSR Clock Controllers - Reserved Shared memory - GCC and RPMHCC - TLMM - Interconnect with CPU BWMONs - QuP with uart - SMMU - RPMHPD - UFS with Inline Crypto Engine - LLCC - Watchdog Written with help from Raviteja Laggyshetty(added interconnect nodes), Taniya Das(added Clock Controllers and cpufreq), Jishnu Prakash (added rpmhpd), Nitin Rawat(added ufs) and Gaurav Kashyap(added ICE). Co-developed-by: Tengfei Fan Signed-off-by: Tengfei Fan Signed-off-by: Jingyi Wang Signed-off-by: Yijie Yang Link: https://lore.kernel.org/all/20250924-knp-dts-v1-2-3fdbc4b9e1b1@oss.qualcomm.com/ --- arch/arm64/boot/dts/qcom/kaanapali.dtsi | 1320 +++++++++++++++++++++++ 1 file changed, 1320 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/kaanapali.dtsi diff --git a/arch/arm64/boot/dts/qcom/kaanapali.dtsi b/arch/arm64/boot/dts/qcom/kaanapali.dtsi new file mode 100644 index 0000000000000..b385b46428834 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/kaanapali.dtsi @@ -0,0 +1,1320 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/ { + interrupt-parent = <&intc>; + + #address-cells = <2>; + #size-cells = <2>; + + cpus { + #address-cells = <2>; + #size-cells = <0>; + + cpu0: cpu@0 { + device_type = "cpu"; + compatible = "qcom,oryon"; + reg = <0x0 0x0>; + enable-method = "psci"; + next-level-cache = <&l2_0>; + power-domains = <&cpu_pd0>; + power-domain-names = "psci"; + clocks = <&pdp_scmi_perf 0>; + + l2_0: l2-cache { + compatible = "cache"; + cache-level = <2>; + cache-unified; + }; + }; + + cpu1: cpu@100 { + device_type = "cpu"; + compatible = "qcom,oryon"; + reg = <0x0 0x100>; + enable-method = "psci"; + next-level-cache = <&l2_0>; + power-domains = <&cpu_pd1>; + power-domain-names = "psci"; + clocks = <&pdp_scmi_perf 0>; + }; + + cpu2: cpu@200 { + device_type = "cpu"; + compatible = "qcom,oryon"; + reg = <0x0 0x200>; + enable-method = "psci"; + next-level-cache = <&l2_0>; + power-domains = <&cpu_pd2>; + power-domain-names = "psci"; + clocks = <&pdp_scmi_perf 0>; + }; + + cpu3: cpu@300 { + device_type = "cpu"; + compatible = "qcom,oryon"; + reg = <0x0 0x300>; + enable-method = "psci"; + next-level-cache = <&l2_0>; + power-domains = <&cpu_pd3>; + power-domain-names = "psci"; + clocks = <&pdp_scmi_perf 0>; + }; + + cpu4: cpu@400 { + device_type = "cpu"; + compatible = "qcom,oryon"; + reg = <0x0 0x400>; + enable-method = "psci"; + next-level-cache = <&l2_0>; + power-domains = <&cpu_pd4>; + power-domain-names = "psci"; + clocks = <&pdp_scmi_perf 0>; + }; + + cpu5: cpu@500 { + device_type = "cpu"; + compatible = "qcom,oryon"; + reg = <0x0 0x500>; + enable-method = "psci"; + next-level-cache = <&l2_0>; + power-domains = <&cpu_pd5>; + power-domain-names = "psci"; + clocks = <&pdp_scmi_perf 0>; + }; + + cpu6: cpu@10000 { + device_type = "cpu"; + compatible = "qcom,oryon"; + reg = <0x0 0x10000>; + enable-method = "psci"; + next-level-cache = <&l2_1>; + power-domains = <&cpu_pd6>; + power-domain-names = "psci"; + clocks = <&pdp_scmi_perf 1>; + + l2_1: l2-cache { + compatible = "cache"; + cache-level = <2>; + cache-unified; + }; + }; + + cpu7: cpu@10100 { + device_type = "cpu"; + compatible = "qcom,oryon"; + reg = <0x0 0x10100>; + enable-method = "psci"; + next-level-cache = <&l2_1>; + power-domains = <&cpu_pd7>; + power-domain-names = "psci"; + clocks = <&pdp_scmi_perf 1>; + }; + + cpu-map { + cluster0 { + core0 { + cpu = <&cpu0>; + }; + + core1 { + cpu = <&cpu1>; + }; + + core2 { + cpu = <&cpu2>; + }; + + core3 { + cpu = <&cpu3>; + }; + + core4 { + cpu = <&cpu4>; + }; + + core5 { + cpu = <&cpu5>; + }; + }; + + cluster1 { + core0 { + cpu = <&cpu6>; + }; + + core1 { + cpu = <&cpu7>; + }; + }; + }; + + idle-states { + entry-method = "psci"; + + cluster0_c4: cpu-sleep-0 { + compatible = "arm,idle-state"; + idle-state-name = "retention"; + arm,psci-suspend-param = <0x00000004>; + entry-latency-us = <93>; + exit-latency-us = <129>; + min-residency-us = <560>; + }; + + cluster1_c4: cpu-sleep-1 { + compatible = "arm,idle-state"; + idle-state-name = "retention"; + arm,psci-suspend-param = <0x00000004>; + entry-latency-us = <172>; + exit-latency-us = <130>; + min-residency-us = <686>; + }; + }; + + domain-idle-states { + cluster_cl5: cluster-sleep-0 { + compatible = "domain-idle-state"; + arm,psci-suspend-param = <0x01000054>; + entry-latency-us = <2150>; + exit-latency-us = <1983>; + min-residency-us = <9144>; + }; + + domain_ss3: domain-sleep-0 { + compatible = "domain-idle-state"; + arm,psci-suspend-param = <0x0200c354>; + entry-latency-us = <2800>; + exit-latency-us = <4400>; + min-residency-us = <10150>; + }; + }; + }; + + firmware { + scm: scm { + compatible = "qcom,scm-kaanapali", "qcom,scm"; + qcom,dload-mode = <&tcsr 0x19000>; + }; + + scmi: scmi { + compatible = "arm,scmi"; + mboxes = <&pdp0_mbox 0>, <&pdp0_mbox 1>; + mbox-names = "tx", "rx"; + shmem = <&pdp_tx>, <&pdp_rx>; + + #address-cells = <1>; + #size-cells = <0>; + + pdp_scmi_perf: protocol@13 { + reg = <0x13>; + #clock-cells = <1>; + }; + }; + }; + + clk_virt: interconnect-0 { + compatible = "qcom,kaanapali-clk-virt"; + #interconnect-cells = <2>; + qcom,bcm-voters = <&apps_bcm_voter>; + }; + + mc_virt: interconnect-1 { + compatible = "qcom,kaanapali-mc-virt"; + #interconnect-cells = <2>; + qcom,bcm-voters = <&apps_bcm_voter>; + }; + + memory@a0000000 { + device_type = "memory"; + /* We expect the bootloader to fill in the size */ + reg = <0x0 0xa0000000 0x0 0x0>; + }; + + pmu { + compatible = "arm,armv8-pmuv3"; + interrupts = ; + }; + + psci { + compatible = "arm,psci-1.0"; + method = "smc"; + + cpu_pd0: power-domain-cpu0 { + #power-domain-cells = <0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&cluster0_c4>; + }; + + cpu_pd1: power-domain-cpu1 { + #power-domain-cells = <0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&cluster0_c4>; + }; + + cpu_pd2: power-domain-cpu2 { + #power-domain-cells = <0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&cluster0_c4>; + }; + + cpu_pd3: power-domain-cpu3 { + #power-domain-cells = <0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&cluster0_c4>; + }; + + cpu_pd4: power-domain-cpu4 { + #power-domain-cells = <0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&cluster0_c4>; + }; + + cpu_pd5: power-domain-cpu5 { + #power-domain-cells = <0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&cluster0_c4>; + }; + + cpu_pd6: power-domain-cpu6 { + #power-domain-cells = <0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&cluster1_c4>; + }; + + cpu_pd7: power-domain-cpu7 { + #power-domain-cells = <0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&cluster1_c4>; + }; + + cluster_pd: power-domain-cluster { + #power-domain-cells = <0>; + domain-idle-states = <&cluster_cl5>; + power-domains = <&system_pd>; + }; + + system_pd: power-domain-system { + #power-domain-cells = <0>; + domain-idle-states = <&domain_ss3>; + }; + }; + + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + pdp_mem: pdp_region@81300000 { + reg = <0x0 0x81300000 0x0 0x100000>; + no-map; + }; + + aop_cmd_db_mem: aop-cmd-db@81c60000 { + compatible = "qcom,cmd-db"; + reg = <0x0 0x81c60000 0x0 0x20000>; + no-map; + }; + + smem_mem: smem@81d00000 { + compatible = "qcom,smem"; + reg = <0x0 0x81d00000 0x0 0x200000>; + hwlocks = <&tcsr_mutex 3>; + no-map; + }; + + pdp_ns_shared_mem: pdp_ns_shared_region@81f00000 { + reg = <0x0 0x81f00000 0x0 0x100000>; + no-map; + }; + + dsm_partition_1_mem: dsm-partition-1@84a00000 { + reg = <0x0 0x84a00000 0x0 0x5500000>; + no-map; + }; + + dsm_partition_2_mem: dsm-partition-2@89f00000 { + reg = <0x0 0x89f00000 0x0 0xa80000>; + no-map; + }; + + mpss_mem: mpss@8aa00000 { + reg = <0x0 0x8aa00000 0x0 0xeb00000>; + no-map; + }; + + q6_mpss_dtb_mem: q6-mpss-dtb@99500000 { + reg = <0x0 0x99500000 0x0 0x80000>; + no-map; + }; + + ipa_fw_mem: ipa-fw@99580000 { + reg = <0x0 0x99580000 0x0 0x10000>; + no-map; + }; + + ipa_gsi_mem: ipa-gsi@99590000 { + reg = <0x0 0x99590000 0x0 0xa000>; + no-map; + }; + + gpu_microcode_mem: gpu-microcode@9959a000 { + reg = <0x0 0x9959a000 0x0 0x2000>; + no-map; + }; + + camera_mem: camera@99600000 { + reg = <0x0 0x99600000 0x0 0x800000>; + no-map; + }; + + camera_2_mem: camera-2@99e00000 { + reg = <0x0 0x99e00000 0x0 0x800000>; + no-map; + }; + + video_mem: video@9a600000 { + reg = <0x0 0x9a600000 0x0 0x800000>; + no-map; + }; + + cvp_mem: cvp@9ae00000 { + reg = <0x0 0x9ae00000 0x0 0x700000>; + no-map; + }; + + cdsp_mem: cdsp@9b500000 { + reg = <0x0 0x9b500000 0x0 0x1900000>; + no-map; + }; + + q6_cdsp_dtb_mem: q6-cdsp-dtb@9ce00000 { + reg = <0x0 0x9ce00000 0x0 0x80000>; + no-map; + }; + + soccp_mem: soccp@a03d0000 { + reg = <0x0 0xa03d0000 0x0 0x500000>; + no-map; + }; + + soccp_dtb_mem: soccp-dtb@a08d0000 { + reg = <0x0 0xa08d0000 0x0 0x40000>; + no-map; + }; + + q6_adsp_dtb_mem: q6-adsp-dtb@a1380000 { + reg = <0x0 0xa1380000 0x0 0x80000>; + no-map; + }; + + adspslpi_mem: adspslpi@a1400000 { + reg = <0x0 0xa1400000 0x0 0x4c00000>; + no-map; + }; + + rmtfs_mem: rmtfs@d7c00000 { + compatible = "qcom,rmtfs-mem"; + reg = <0 0xd7c00000 0 0x400000>; + no-map; + + qcom,client-id = <1>; + qcom,vmid = ; + }; + }; + + soc: soc@0 { + compatible = "simple-bus"; + + #address-cells = <2>; + #size-cells = <2>; + dma-ranges = <0 0 0 0 0x10 0>; + ranges = <0 0 0 0 0x10 0>; + + gcc: clock-controller@100000 { + compatible = "qcom,kaanapali-gcc"; + reg = <0x0 0x00100000 0x0 0x1f4200>; + + clocks = <&bi_tcxo_div2>, + <0>, + <&sleep_clk>, + <0>, + <0>, + <0>, + <0>, + <0>; + + #clock-cells = <1>; + #reset-cells = <1>; + #power-domain-cells = <1>; + }; + + qupv3_1: geniqup@ac0000 { + compatible = "qcom,geni-se-qup"; + reg = <0x0 0x00ac0000 0x0 0x2000>; + + clocks = <&gcc GCC_QUPV3_WRAP_1_M_AXI_CLK>, + <&gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + clock-names = "m-ahb", + "s-ahb"; + + iommus = <&apps_smmu 0xa3 0x0>; + + dma-coherent; + + #address-cells = <2>; + #size-cells = <2>; + ranges; + + uart7: serial@a9c000 { + compatible = "qcom,geni-debug-uart"; + reg = <0x0 0x00a9c000 0x0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP1_S7_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ACTIVE_ONLY + &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ACTIVE_ONLY>; + interconnect-names = "qup-core", + "qup-config"; + + pinctrl-0 = <&qup_uart7_default>; + pinctrl-names = "default"; + + status = "disabled"; + }; + }; + + ipcc: mailbox@1106000 { + compatible = "qcom,kaanapali-ipcc", "qcom,ipcc"; + reg = <0x0 0x01106000 0x0 0x1000>; + + interrupts = ; + interrupt-controller; + #interrupt-cells = <3>; + + #mbox-cells = <2>; + }; + + cnoc_main: interconnect@1500000 { + compatible = "qcom,kaanapali-cnoc-main"; + reg = <0x0 0x01500000 0x0 0x1a080>; + qcom,bcm-voters = <&apps_bcm_voter>; + #interconnect-cells = <2>; + }; + + config_noc: interconnect@1600000 { + compatible = "qcom,kaanapali-cnoc-cfg"; + reg = <0x0 0x01600000 0x0 0x6200>; + qcom,bcm-voters = <&apps_bcm_voter>; + #interconnect-cells = <2>; + }; + + system_noc: interconnect@1680000 { + compatible = "qcom,kaanapali-system-noc"; + reg = <0x0 0x01680000 0x0 0x1f080>; + qcom,bcm-voters = <&apps_bcm_voter>; + #interconnect-cells = <2>; + }; + + pcie_noc: interconnect@16c0000 { + compatible = "qcom,kaanapali-pcie-anoc"; + reg = <0x0 0x016c0000 0x0 0x11400>; + qcom,bcm-voters = <&apps_bcm_voter>; + #interconnect-cells = <2>; + clocks = <&gcc GCC_AGGRE_NOC_PCIE_AXI_CLK>, + <&gcc GCC_CFG_NOC_PCIE_ANOC_AHB_CLK>; + }; + + aggre_noc: interconnect@16e0000 { + compatible = "qcom,kaanapali-aggre-noc"; + reg = <0x0 0x016e0000 0x0 0x42400>; + qcom,bcm-voters = <&apps_bcm_voter>; + #interconnect-cells = <2>; + clocks = <&gcc GCC_AGGRE_UFS_PHY_AXI_CLK>, + <&gcc GCC_AGGRE_USB3_PRIM_AXI_CLK>, + <&rpmhcc RPMH_IPA_CLK>; + }; + + mmss_noc: interconnect@1780000 { + compatible = "qcom,kaanapali-mmss-noc"; + reg = <0x0 0x01780000 0x0 0x5b800>; + qcom,bcm-voters = <&apps_bcm_voter>; + #interconnect-cells = <2>; + }; + + ufs_mem_phy: phy@1d80000 { + compatible = "qcom,kaanapali-qmp-ufs-phy", "qcom,sm8750-qmp-ufs-phy"; + reg = <0x0 0x01d80000 0x0 0x2000>; + + clocks = <&rpmhcc RPMH_CXO_CLK>, + <&gcc GCC_UFS_PHY_PHY_AUX_CLK>, + <&tcsrcc TCSR_UFS_CLKREF_EN>; + + clock-names = "ref", + "ref_aux", + "qref"; + + resets = <&ufs_mem_hc 0>; + reset-names = "ufsphy"; + + power-domains = <&gcc GCC_UFS_MEM_PHY_GDSC>; + + #clock-cells = <1>; + #phy-cells = <0>; + + status = "disabled"; + }; + + ufs_mem_hc: ufs@1d84000 { + compatible = "qcom,kaanapali-ufshc", + "qcom,ufshc", + "jedec,ufs-2.0"; + reg = <0x0 0x01d84000 0x0 0x3000>; + + interrupts = ; + + clocks = <&gcc GCC_UFS_PHY_AXI_CLK>, + <&gcc GCC_AGGRE_UFS_PHY_AXI_CLK>, + <&gcc GCC_UFS_PHY_AHB_CLK>, + <&gcc GCC_UFS_PHY_UNIPRO_CORE_CLK>, + <&rpmhcc RPMH_LN_BB_CLK3>, + <&gcc GCC_UFS_PHY_TX_SYMBOL_0_CLK>, + <&gcc GCC_UFS_PHY_RX_SYMBOL_0_CLK>, + <&gcc GCC_UFS_PHY_RX_SYMBOL_1_CLK>; + clock-names = "core_clk", + "bus_aggr_clk", + "iface_clk", + "core_clk_unipro", + "ref_clk", + "tx_lane0_sync_clk", + "rx_lane0_sync_clk", + "rx_lane1_sync_clk"; + + operating-points-v2 = <&ufs_opp_table>; + + resets = <&gcc GCC_UFS_PHY_BCR>; + reset-names = "rst"; + + interconnects = <&aggre_noc MASTER_UFS_MEM QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ACTIVE_ONLY + &config_noc SLAVE_UFS_MEM_CFG QCOM_ICC_TAG_ACTIVE_ONLY>; + interconnect-names = "ufs-ddr", + "cpu-ufs"; + + power-domains = <&gcc GCC_UFS_PHY_GDSC>; + required-opps = <&rpmhpd_opp_nom>; + + iommus = <&apps_smmu 0x60 0x0>; + dma-coherent; + + lanes-per-direction = <2>; + qcom,ice = <&ice>; + + phys = <&ufs_mem_phy>; + phy-names = "ufsphy"; + + #reset-cells = <1>; + + status = "disabled"; + + ufs_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-75000000 { + opp-hz = /bits/ 64 <75000000>, + /bits/ 64 <0>, + /bits/ 64 <0>, + /bits/ 64 <75000000>, + /bits/ 64 <0>, + /bits/ 64 <0>, + /bits/ 64 <0>, + /bits/ 64 <0>; + required-opps = <&rpmhpd_opp_low_svs_d1>; + }; + + opp-100000000 { + opp-hz = /bits/ 64 <100000000>, + /bits/ 64 <0>, + /bits/ 64 <0>, + /bits/ 64 <100000000>, + /bits/ 64 <0>, + /bits/ 64 <0>, + /bits/ 64 <0>, + /bits/ 64 <0>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + + opp-403000000 { + opp-hz = /bits/ 64 <403000000>, + /bits/ 64 <0>, + /bits/ 64 <0>, + /bits/ 64 <403000000>, + /bits/ 64 <0>, + /bits/ 64 <0>, + /bits/ 64 <0>, + /bits/ 64 <0>; + required-opps = <&rpmhpd_opp_nom>; + }; + }; + }; + + ice: crypto@1d88000 { + compatible = "qcom,kaanapali-inline-crypto-engine", + "qcom,inline-crypto-engine"; + reg = <0x0 0x01d88000 0x0 0x18000>; + + clocks = <&gcc GCC_UFS_PHY_ICE_CORE_CLK>; + }; + + tcsr_mutex: hwlock@1f40000 { + compatible = "qcom,tcsr-mutex"; + reg = <0x0 0x01f40000 0x0 0x20000>; + #hwlock-cells = <1>; + }; + + tcsr: syscon@1fc0000 { + compatible = "qcom,tcsr-kaanapali", "syscon"; + reg = <0x0 0x1fc0000 0x0 0x30000>; + }; + + tcsrcc: clock-controller@1fd5044 { + compatible = "qcom,kaanapali-tcsr", "syscon"; + reg = <0x0 0x01fd5044 0x0 0x1c>; + + clocks = <&rpmhcc RPMH_CXO_CLK>; + + #clock-cells = <1>; + #reset-cells = <1>; + }; + + lpass_lpiaon_noc: interconnect@7400000 { + compatible = "qcom,kaanapali-lpass-lpiaon-noc"; + reg = <0x0 0x07400000 0x0 0x19080>; + qcom,bcm-voters = <&apps_bcm_voter>; + #interconnect-cells = <2>; + }; + + lpass_lpicx_noc: interconnect@7420000 { + compatible = "qcom,kaanapali-lpass-lpicx-noc"; + reg = <0x0 0x07420000 0x0 0x44080>; + qcom,bcm-voters = <&apps_bcm_voter>; + #interconnect-cells = <2>; + }; + + lpass_ag_noc: interconnect@7f40000 { + compatible = "qcom,kaanapali-lpass-ag-noc"; + reg = <0x0 0x07f40000 0x0 0xe080>; + qcom,bcm-voters = <&apps_bcm_voter>; + #interconnect-cells = <2>; + }; + + pdc: interrupt-controller@b220000 { + compatible = "qcom,kaanapali-pdc", "qcom,pdc"; + reg = <0x0 0x0b220000 0x0 0x10000>, + <0x0 0x179600f0 0x0 0xf4>; + + qcom,pdc-ranges = <0 745 38>, + <40 785 11>, + <51 527 4>, + <58 534 2>, + <61 537 20>, + <84 559 14>, + <98 609 32>, + <130 717 12>, + <142 251 5>, + <147 796 16>, + <163 783 2>, + <165 531 2>, + <167 536 1>, + <168 557 2>, + <170 415 1>, + <171 438 1>, + <172 579 1>, + <173 703 1>, + <174 708 1>, + <175 714 1>, + <176 68 1>, + <177 86 1>, + <178 96 1>, + <179 249 1>; + #interrupt-cells = <2>; + interrupt-parent = <&intc>; + interrupt-controller; + }; + + aoss_qmp: power-management@c300000 { + compatible = "qcom,kaanapali-aoss-qmp", "qcom,aoss-qmp"; + reg = <0x0 0x0c300000 0x0 0x400>; + + interrupts-extended = <&ipcc IPCC_MPROC_AOP + IPCC_MPROC_SIGNAL_GLINK_QMP + IRQ_TYPE_EDGE_RISING>; + + mboxes = <&ipcc IPCC_MPROC_AOP + IPCC_MPROC_SIGNAL_GLINK_QMP>; + + #clock-cells = <0>; + }; + + tlmm: pinctrl@f100000 { + compatible = "qcom,kaanapali-tlmm"; + reg = <0x0 0x0f100000 0x0 0x300000>; + interrupts = ; + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&tlmm 0 0 218>; + interrupt-controller; + #interrupt-cells = <2>; + wakeup-parent = <&pdc>; + + qup_uart7_default: qup-uart7-state { + /* TX, RX */ + pins = "gpio62", "gpio63"; + function = "qup1_se7"; + drive-strength = <2>; + bias-disable; + }; + }; + + sram@14680000 { + compatible = "qcom,kaanapali-imem", "syscon", "simple-mfd"; + reg = <0x0 0x14680000 0x0 0x1000>; + ranges = <0 0 0x14680000 0x1000>; + + #address-cells = <1>; + #size-cells = <1>; + + pil-reloc@94c { + compatible = "qcom,pil-reloc-info"; + reg = <0x94c 0xc8>; + }; + }; + + apps_smmu: iommu@15000000 { + compatible = "qcom,kaanapali-smmu-500", "qcom,smmu-500", "arm,mmu-500"; + reg = <0x0 0x15000000 0x0 0x100000>; + + interrupts =, + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + + #iommu-cells = <2>; + #global-interrupts = <1>; + + dma-coherent; + }; + + intc: interrupt-controller@17000000 { + compatible = "arm,gic-v3"; + reg = <0x0 0x17000000 0x0 0x10000>, + <0x0 0x17080000 0x0 0x200000>; + + interrupts = ; + + #interrupt-cells = <3>; + interrupt-controller; + + #redistributor-regions = <1>; + redistributor-stride = <0x0 0x40000>; + + #address-cells = <2>; + #size-cells = <2>; + ranges; + + gic_its: msi-controller@17040000 { + compatible = "arm,gic-v3-its"; + reg = <0x0 0x17040000 0x0 0x20000>; + + msi-controller; + #msi-cells = <1>; + }; + }; + + watchdog@17600000 { + compatible = "qcom,apss-wdt-kaanapali", "qcom,kpss-wdt"; + reg = <0x0 0x17600000 0x0 0x1000>; + clocks = <&sleep_clk>; + interrupts = ; + }; + + pdp0_mbox: mailbox@17610000 { + compatible = "qcom,kaanapali-cpucp-mbox", "qcom,x1e80100-cpucp-mbox"; + reg = <0 0x17610000 0 0x8000>, <0 0x19980000 0 0x8000>; + interrupts = ; + #mbox-cells = <1>; + }; + + timer@17810000 { + compatible = "arm,armv7-timer-mem"; + reg = <0x0 0x17810000 0x0 0x1000>; + + #address-cells = <2>; + #size-cells = <1>; + ranges = <0 0 0 0 0x20000000>; + + frame@17811000 { + reg = <0x0 0x17811000 0x1000>, + <0x0 0x17812000 0x1000>; + frame-number = <0>; + interrupts = , + ; + }; + + frame@17813000 { + reg = <0x0 0x17813000 0x1000>; + frame-number = <1>; + interrupts = ; + status = "disabled"; + }; + + frame@17815000 { + reg = <0x0 0x17815000 0x1000>; + frame-number = <2>; + interrupts = ; + status = "disabled"; + }; + + frame@17817000 { + reg = <0x0 0x17817000 0x1000>; + frame-number = <3>; + interrupts = ; + status = "disabled"; + }; + + frame@17819000 { + reg = <0x0 0x17819000 0x1000>; + frame-number = <4>; + interrupts = ; + status = "disabled"; + }; + + frame@1781b000 { + reg = <0x0 0x1781b000 0x1000>; + frame-number = <5>; + interrupts = ; + status = "disabled"; + }; + + frame@1781d000 { + reg = <0x0 0x1781d000 0x1000>; + frame-number = <6>; + interrupts = ; + status = "disabled"; + }; + }; + + apps_rsc: rsc@18900000 { + compatible = "qcom,rpmh-rsc"; + reg = <0x0 0x18900000 0x0 0x10000>, + <0x0 0x18910000 0x0 0x10000>, + <0x0 0x18920000 0x0 0x10000>; + reg-names = "drv-0", + "drv-1", + "drv-2"; + interrupts = , + , + ; + + power-domains = <&system_pd>; + label = "apps_rsc"; + + qcom,tcs-offset = <0xd00>; + qcom,drv-id = <2>; + qcom,tcs-config = , + , + , + ; + + apps_bcm_voter: bcm-voter { + compatible = "qcom,bcm-voter"; + }; + + rpmhcc: clock-controller { + compatible = "qcom,kaanapali-rpmh-clk"; + #clock-cells = <1>; + clocks = <&xo_board>; + clock-names = "xo"; + }; + + rpmhpd: power-controller { + compatible = "qcom,kaanapali-rpmhpd"; + + operating-points-v2 = <&rpmhpd_opp_table>; + + #power-domain-cells = <1>; + + rpmhpd_opp_table: opp-table { + compatible = "operating-points-v2"; + + rpmhpd_opp_ret: opp-16 { + opp-level = ; + }; + + rpmhpd_opp_low_svs_d3: opp-50 { + opp-level = ; + }; + + rpmhpd_opp_low_svs_d2_1: opp-51 { + opp-level = ; + }; + + rpmhpd_opp_low_svs_d2: opp-52 { + opp-level = ; + }; + + rpmhpd_opp_low_svs_d1_1: opp-54 { + opp-level = ; + }; + + rpmhpd_opp_low_svs_d1: opp-56 { + opp-level = ; + }; + + rpmhpd_opp_low_svs_d0: opp-60 { + opp-level = ; + }; + + rpmhpd_opp_low_svs: opp-64 { + opp-level = ; + }; + + rpmhpd_opp_low_svs_l0: opp-76 { + opp-level = ; + }; + + rpmhpd_opp_low_svs_l1: opp-80 { + opp-level = ; + }; + + rpmhpd_opp_low_svs_l2: opp-96 { + opp-level = ; + }; + + rpmhpd_opp_svs: opp-128 { + opp-level = ; + }; + + rpmhpd_opp_svs_l0: opp-144 { + opp-level = ; + }; + + rpmhpd_opp_svs_l1: opp-192 { + opp-level = ; + }; + + rpmhpd_opp_svs_l2: opp-224 { + opp-level = ; + }; + + rpmhpd_opp_nom: opp-256 { + opp-level = ; + }; + + rpmhpd_opp_nom_l1: opp-320 { + opp-level = ; + }; + + rpmhpd_opp_nom_l2: opp-336 { + opp-level = ; + }; + + rpmhpd_opp_turbo: opp-384 { + opp-level = ; + }; + + rpmhpd_opp_turbo_l0: opp-400 { + opp-level = ; + }; + + rpmhpd_opp_turbo_l1: opp-416 { + opp-level = ; + }; + + rpmhpd_opp_turbo_l2: opp-432 { + opp-level = ; + }; + + rpmhpd_opp_turbo_l3: opp-448 { + opp-level = ; + }; + + rpmhpd_opp_turbo_l4: opp-452 { + opp-level = ; + }; + + rpmhpd_opp_turbo_l5: opp-456 { + opp-level = ; + }; + + rpmhpd_opp_super_turbo_no_cpr: opp-480 { + opp-level = ; + }; + }; + }; + }; + + nsp_noc: interconnect@260c0000 { + compatible = "qcom,kaanapali-nsp-noc"; + reg = <0x0 0x260c0000 0x0 0x21280>; + qcom,bcm-voters = <&apps_bcm_voter>; + #interconnect-cells = <2>; + }; + + /* Cluster 0 */ + pmu@310b3400 { + compatible = "qcom,kaanapali-cpu-bwmon", "qcom,sdm845-bwmon"; + reg = <0x0 0x310b3400 0x0 0x600>; + + interrupts = ; + + interconnects = <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ACTIVE_ONLY + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ACTIVE_ONLY>; + + operating-points-v2 = <&cpu_bwmon_opp_table>; + + cpu_bwmon_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-0 { + opp-peak-kBps = <2188000>; + }; + + opp-1 { + opp-peak-kBps = <5412000>; + }; + + opp-2 { + opp-peak-kBps = <6220000>; + }; + + opp-3 { + opp-peak-kBps = <6832000>; + }; + + opp-4 { + opp-peak-kBps = <8368000>; + }; + + opp-5 { + opp-peak-kBps = <10944000>; + }; + + opp-6 { + opp-peak-kBps = <12748000>; + }; + + opp-7 { + opp-peak-kBps = <14744000>; + }; + + opp-8 { + opp-peak-kBps = <16896000>; + }; + + opp-9 { + opp-peak-kBps = <19120000>; + }; + + opp-10 { + opp-peak-kBps = <21332000>; + }; + }; + }; + + /* Cluster 1 */ + pmu@310b7400 { + compatible = "qcom,kaanapali-cpu-bwmon", "qcom,sdm845-bwmon"; + reg = <0x0 0x310b7400 0x0 0x600>; + + interrupts = ; + + interconnects = <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ACTIVE_ONLY + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ACTIVE_ONLY>; + + operating-points-v2 = <&cpu_bwmon_opp_table>; + }; + + gem_noc: interconnect@31100000 { + compatible = "qcom,kaanapali-gem-noc"; + reg = <0x0 0x31100000 0x0 0x153080>; + qcom,bcm-voters = <&apps_bcm_voter>; + #interconnect-cells = <2>; + }; + + system-cache-controller@31800000 { + compatible = "qcom,kaanapali-llcc"; + reg = <0x0 0x31800000 0x0 0x200000>, + <0x0 0x32800000 0x0 0x200000>, + <0x0 0x31c00000 0x0 0x200000>, + <0x0 0x32c00000 0x0 0x200000>, + <0x0 0x34800000 0x0 0x200000>, + <0x0 0x34c00000 0x0 0x200000>; + reg-names = "llcc0_base", + "llcc1_base", + "llcc2_base", + "llcc3_base", + "llcc_broadcast_base", + "llcc_broadcast_and_base"; + + interrupts = ; + }; + + sram: sram@81f08000 { + compatible = "mmio-sram"; + reg = <0x0 0x81f08000 0x0 0x200>; + + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x0 0x81f08000 0x200>; + + pdp_rx: scp-sram-section@0 { + compatible = "arm,scmi-shmem"; + reg = <0x0 0x80>; + }; + + pdp_tx: scp-sram-section@100 { + compatible = "arm,scmi-shmem"; + reg = <0x100 0x80>; + }; + }; + }; + + timer { + compatible = "arm,armv8-timer"; + + interrupts = , + , + , + ; + }; +}; From 746a2029c703df8d18c3b3209cd1cb635a2abd92 Mon Sep 17 00:00:00 2001 From: Jingyi Wang Date: Wed, 24 Sep 2025 17:17:20 -0700 Subject: [PATCH 0178/2333] FROMLIST: arm64: dts: qcom: kaanapali: Add base MTP board Add initial support for Qualcomm Kaanapali MTP board which enables DSPs, UFS and booting to shell with uart console. Written with help from Jishnu Prakash (added rpmhpd nodes) and Nitin Rawat (added ufs). Signed-off-by: Jingyi Wang Reviewed-by: Konrad Dybcio Signed-off-by: Yijie Yang Link: https://lore.kernel.org/all/20250924-knp-dts-v1-3-3fdbc4b9e1b1@oss.qualcomm.com/ --- arch/arm64/boot/dts/qcom/Makefile | 1 + arch/arm64/boot/dts/qcom/kaanapali-mtp.dts | 704 +++++++++++++++++++++ 2 files changed, 705 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/kaanapali-mtp.dts diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile index 296688f7cb265..1d081b869bf10 100644 --- a/arch/arm64/boot/dts/qcom/Makefile +++ b/arch/arm64/boot/dts/qcom/Makefile @@ -30,6 +30,7 @@ dtb-$(CONFIG_ARCH_QCOM) += ipq9574-rdp433.dtb dtb-$(CONFIG_ARCH_QCOM) += ipq9574-rdp449.dtb dtb-$(CONFIG_ARCH_QCOM) += ipq9574-rdp453.dtb dtb-$(CONFIG_ARCH_QCOM) += ipq9574-rdp454.dtb +dtb-$(CONFIG_ARCH_QCOM) += kaanapali-mtp.dtb dtb-$(CONFIG_ARCH_QCOM) += lemans-evk.dtb lemans-evk-camera-csi1-imx577-dtbs := lemans-evk.dtb lemans-evk-camera-csi1-imx577.dtbo diff --git a/arch/arm64/boot/dts/qcom/kaanapali-mtp.dts b/arch/arm64/boot/dts/qcom/kaanapali-mtp.dts new file mode 100644 index 0000000000000..9cf3158e27124 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/kaanapali-mtp.dts @@ -0,0 +1,704 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +/dts-v1/; + +#include +#include "kaanapali.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Kaanapali MTP"; + compatible = "qcom,kaanapali-mtp", "qcom,kaanapali"; + chassis-type = "handset"; + + aliases { + serial0 = &uart7; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + clocks { + xo_board: xo-board { + compatible = "fixed-clock"; + clock-frequency = <76800000>; + #clock-cells = <0>; + }; + + sleep_clk: sleep-clk { + compatible = "fixed-clock"; + clock-frequency = <32764>; + #clock-cells = <0>; + }; + + bi_tcxo_div2: bi-tcxo-div2-clk { + compatible = "fixed-factor-clock"; + #clock-cells = <0>; + + clocks = <&rpmhcc RPMH_CXO_CLK>; + clock-mult = <1>; + clock-div = <2>; + }; + + bi_tcxo_ao_div2: bi-tcxo-ao-div2-clk { + compatible = "fixed-factor-clock"; + #clock-cells = <0>; + + clocks = <&rpmhcc RPMH_CXO_CLK_A>; + clock-mult = <1>; + clock-div = <2>; + }; + }; +}; + +&apps_rsc { + regulators-0 { + compatible = "qcom,pmh0101-rpmh-regulators"; + + qcom,pmic-id = "B_E0"; + + vreg_bob1: bob1 { + regulator-name = "vreg_bob1"; + regulator-min-microvolt = <3008000>; + regulator-max-microvolt = <4000000>; + regulator-initial-mode = ; + }; + + vreg_bob2: bob2 { + regulator-name = "vreg_bob2"; + regulator-min-microvolt = <2704000>; + regulator-max-microvolt = <3552000>; + regulator-initial-mode = ; + }; + + vreg_l1b_1p8: ldo1 { + regulator-name = "vreg_l1b_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l2b_3p0: ldo2 { + regulator-name = "vreg_l2b_3p0"; + regulator-min-microvolt = <3008000>; + regulator-max-microvolt = <3048000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l4b_1p8: ldo4 { + regulator-name = "vreg_l4b_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l5b_3p1: ldo5 { + regulator-name = "vreg_l5b_3p1"; + regulator-min-microvolt = <3100000>; + regulator-max-microvolt = <3148000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l6b_1p8: ldo6 { + regulator-name = "vreg_l6b_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3008000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l7b_1p8: ldo7 { + regulator-name = "vreg_l7b_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3008000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l8b_1p8: ldo8 { + regulator-name = "vreg_l8b_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3008000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l9b_2p9: ldo9 { + regulator-name = "vreg_l9b_2p9"; + regulator-min-microvolt = <2960000>; + regulator-max-microvolt = <3008000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l10b_1p8: ldo10 { + regulator-name = "vreg_l10b_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l11b_1p0: ldo11 { + regulator-name = "vreg_l11b_1p0"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1292000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l12b_1p8: ldo12 { + regulator-name = "vreg_l12b_1p8"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l13b_3p0: ldo13 { + regulator-name = "vreg_l13b_3p0"; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l14b_3p2: ldo14 { + regulator-name = "vreg_l14b_3p2"; + regulator-min-microvolt = <3200000>; + regulator-max-microvolt = <3200000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l15b_1p8: ldo15 { + regulator-name = "vreg_l15b_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l17b_2p5: ldo17 { + regulator-name = "vreg_l17b_2p5"; + regulator-min-microvolt = <2504000>; + regulator-max-microvolt = <2504000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l18b_1p2: ldo18 { + regulator-name = "vreg_l18b_1p2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + }; + + regulators-1 { + compatible = "qcom,pmh0110-rpmh-regulators"; + + qcom,pmic-id = "D_E0"; + + vreg_s10d_1p0: smps10 { + regulator-name = "vreg_s10d_1p0"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1100000>; + regulator-initial-mode = ; + }; + + vreg_l1d_1p2: ldo1 { + regulator-name = "vreg_l1d_1p2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1256000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l2d_0p9: ldo2 { + regulator-name = "vreg_l2d_0p9"; + regulator-min-microvolt = <912000>; + regulator-max-microvolt = <958000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l3d_0p8: ldo3 { + regulator-name = "vreg_l3d_0p8"; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <880000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l4d_1p2: ldo4 { + regulator-name = "vreg_l4d_1p2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + }; + + regulators-2 { + compatible = "qcom,pmh0110-rpmh-regulators"; + + qcom,pmic-id = "F_E0"; + + vreg_s6f_0p5: smps6 { + regulator-name = "vreg_s6f_0p5"; + regulator-min-microvolt = <300000>; + regulator-max-microvolt = <570000>; + regulator-initial-mode = ; + }; + + vreg_s7f_1p2: smps7 { + regulator-name = "vreg_s7f_1p2"; + regulator-min-microvolt = <1224000>; + regulator-max-microvolt = <1372000>; + regulator-initial-mode = ; + }; + + vreg_s8f_1p8: smps8 { + regulator-name = "vreg_s8f_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2000000>; + regulator-initial-mode = ; + }; + + vreg_l1f_1p2: ldo1 { + regulator-name = "vreg_l1f_1p2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l2f_1p2: ldo2 { + regulator-name = "vreg_l2f_1p2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l3f_0p8: ldo3 { + regulator-name = "vreg_l3f_0p8"; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <936000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l4f_0p8: ldo4 { + regulator-name = "vreg_l4f_0p8"; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <912000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + }; + + regulators-3 { + compatible = "qcom,pmh0110-rpmh-regulators"; + + qcom,pmic-id = "G_E0"; + + vreg_s7g_0p9: smps7 { + regulator-name = "vreg_s7g_0p9"; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <1100000>; + regulator-initial-mode = ; + }; + + vreg_s9g_1p0: smps9 { + regulator-name = "vreg_s9g_1p0"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1100000>; + regulator-initial-mode = ; + }; + + vreg_l1g_1p2: ldo1 { + regulator-name = "vreg_l1g_1p2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l2g_1p8: ldo2 { + regulator-name = "vreg_l2g_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l3g_1p2: ldo3 { + regulator-name = "vreg_l3g_1p2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l4g_0p9: ldo4 { + regulator-name = "vreg_l4g_0p9"; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <920000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + }; + + regulators-4 { + compatible = "qcom,pmh0110-rpmh-regulators"; + + qcom,pmic-id = "I_E0"; + + vreg_s7i_0p9: smps7 { + regulator-name = "vreg_s7i_0p9"; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <972000>; + regulator-initial-mode = ; + }; + + vreg_l2i_1p2: ldo2 { + regulator-name = "vreg_l2i_1p2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l3i_0p8: ldo3 { + regulator-name = "vreg_l3i_0p8"; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <920000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + }; + + regulators-5 { + compatible = "qcom,pmh0104-rpmh-regulators"; + + qcom,pmic-id = "J_E1"; + + vreg_s1j_0p8: smps1 { + regulator-name = "vreg_s1j_0p8"; + regulator-min-microvolt = <400000>; + regulator-max-microvolt = <1000000>; + regulator-initial-mode = ; + }; + + vreg_s2j_0p8: smps2 { + regulator-name = "vreg_s2j_0p8"; + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <1100000>; + regulator-initial-mode = ; + }; + + vreg_s3j_1p2: smps3 { + regulator-name = "vreg_s3j_1p2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1300000>; + regulator-initial-mode = ; + }; + + vreg_s4j_0p7: smps4 { + regulator-name = "vreg_s4j_0p7"; + regulator-min-microvolt = <300000>; + regulator-max-microvolt = <1000000>; + regulator-initial-mode = ; + }; + }; + + regulators-6 { + compatible = "qcom,pmr735d-rpmh-regulators"; + + qcom,pmic-id = "K_E1"; + + vreg_l1k_0p8: ldo1 { + regulator-name = "vreg_l1k_0p8"; + regulator-min-microvolt = <300000>; + regulator-max-microvolt = <1100000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l2k_0p7: ldo2 { + regulator-name = "vreg_l2k_0p7"; + regulator-min-microvolt = <700000>; + regulator-max-microvolt = <1000000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l3k_1p2: ldo3 { + regulator-name = "vreg_l3k_1p2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l4k_1p0: ldo4 { + regulator-name = "vreg_l4k_1p0"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l5k_0p7: ldo5 { + regulator-name = "vreg_l5k_0p7"; + regulator-min-microvolt = <700000>; + regulator-max-microvolt = <1000000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l6k_1p7: ldo6 { + regulator-name = "vreg_l6k_1p7"; + regulator-min-microvolt = <1700000>; + regulator-max-microvolt = <2000000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l7k_0p7: ldo7 { + regulator-name = "vreg_l7k_0p7"; + regulator-min-microvolt = <700000>; + regulator-max-microvolt = <848000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + }; + + regulators-7 { + compatible = "qcom,pm8010-rpmh-regulators"; + + qcom,pmic-id = "M_E1"; + + vreg_l1m_1p0: ldo1 { + regulator-name = "vreg_l1m_1p0"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1100000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l2m_1p0: ldo2 { + regulator-name = "vreg_l2m_1p0"; + regulator-min-microvolt = <1096000>; + regulator-max-microvolt = <1104000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l3m_2p8: ldo3 { + regulator-name = "vreg_l3m_2p8"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2900000>; + regulator-initial-mode = ; + }; + + vreg_l4m_2p2: ldo4 { + regulator-name = "vreg_l4m_2p2"; + regulator-min-microvolt = <2200000>; + regulator-max-microvolt = <2200000>; + regulator-initial-mode = ; + }; + + vreg_l6m_2p8: ldo6 { + regulator-name = "vreg_l6m_2p8"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-initial-mode = ; + }; + + vreg_l7m_2p8: ldo7 { + regulator-name = "vreg_l7m_2p8"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-initial-mode = ; + }; + }; + + regulators-8 { + compatible = "qcom,pm8010-rpmh-regulators"; + + qcom,pmic-id = "N_E1"; + + vreg_l1n_1p1: ldo1 { + regulator-name = "vreg_l1n_1p1"; + regulator-min-microvolt = <1096000>; + regulator-max-microvolt = <1104000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l2n_1p2: ldo2 { + regulator-name = "vreg_l2n_1p2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l3n_1p8: ldo3 { + regulator-name = "vreg_l3n_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + }; + + vreg_l4n_1p8: ldo4 { + regulator-name = "vreg_l4n_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + }; + + vreg_l5n_2p8: ldo5 { + regulator-name = "vreg_l5n_2p8"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-initial-mode = ; + }; + + vreg_l6n_2p8: ldo6 { + regulator-name = "vreg_l6n_2p8"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-initial-mode = ; + }; + + vreg_l7n_3p3: ldo7 { + regulator-name = "vreg_l7n_3p3"; + regulator-min-microvolt = <3304000>; + regulator-max-microvolt = <3304000>; + regulator-initial-mode = ; + }; + }; +}; + +&tlmm { + gpio-reserved-ranges = <36 4>, /* NFC eSE SPI */ + <74 1>, /* eSE */ + <119 2>, /* SoCCP */ + <144 4>; /* CXM UART */ +}; + +&uart7 { + status = "okay"; +}; + +&ufs_mem_hc { + reset-gpios = <&tlmm 217 GPIO_ACTIVE_LOW>; + + vcc-supply = <&vreg_l17b_2p5>; + vcc-max-microamp = <1200000>; + vccq-supply = <&vreg_l4d_1p2>; + vccq-max-microamp = <1200000>; + + status = "okay"; +}; + +&ufs_mem_phy { + vdda-phy-supply = <&vreg_l4g_0p9>; + vdda-pll-supply = <&vreg_l1d_1p2>; + + status = "okay"; +}; From 5741f5ad59b7660cea28ef8801ce067eed4fac76 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 28 Oct 2025 15:24:24 -0700 Subject: [PATCH 0179/2333] FROMGIT: ufs: core: Revert "Make HID attributes visible" Patch "Make HID attributes visible" is needed for older kernel versions (e.g. 6.12) where ufs_get_device_desc() is called from ufshcd_probe_hba(). In these older kernel versions ufshcd_get_device_desc() may be called after the sysfs attributes have been added. In the upstream kernel however ufshcd_get_device_desc() is called before ufs_sysfs_add_nodes(). See also the ufshcd_device_params_init() call from ufshcd_init(). Hence, calling sysfs_update_group() is not necessary. See also commit 69f5eb78d4b0 ("scsi: ufs: core: Move the ufshcd_device_init(hba, true) call") in kernel v6.13. This patch fixes the following kernel warning: sysfs: cannot create duplicate filename '/devices/platform/3c2d0000.ufs/hid' Workqueue: async async_run_entry_fn Call trace: dump_backtrace+0xfc/0x17c show_stack+0x18/0x28 dump_stack_lvl+0x40/0x104 dump_stack+0x18/0x3c sysfs_warn_dup+0x6c/0xc8 internal_create_group+0x1c8/0x504 sysfs_create_groups+0x38/0x9c ufs_sysfs_add_nodes+0x20/0x58 ufshcd_init+0x1114/0x134c ufshcd_pltfrm_init+0x728/0x7d8 ufs_google_probe+0x30/0x84 platform_probe+0xa0/0xe0 really_probe+0x114/0x454 __driver_probe_device+0xa4/0x160 driver_probe_device+0x44/0x23c __device_attach_driver+0x15c/0x1f4 bus_for_each_drv+0x10c/0x168 __device_attach_async_helper+0x80/0xf8 async_run_entry_fn+0x4c/0x17c process_one_work+0x26c/0x65c worker_thread+0x33c/0x498 kthread+0x110/0x134 ret_from_fork+0x10/0x20 ufshcd 3c2d0000.ufs: ufs_sysfs_add_nodes: sysfs groups creation failed (err = -17) Cc: Daniel Lee Cc: Peter Wang Cc: Bjorn Andersson Cc: Neil Armstrong Fixes: bb7663dec67b ("scsi: ufs: sysfs: Make HID attributes visible") Signed-off-by: Bart Van Assche Fixes: bb7663dec67b ("scsi: ufs: sysfs: Make HID attributes visible") Acked-by: Neil Armstrong Reviewed-by: Peter Wang Reviewed-by: Bjorn Andersson Link: https://lore.kernel.org/all/20251111004554.685418171@linuxfoundation.org/ Signed-off-by: Pradeep P V K --- drivers/ufs/core/ufs-sysfs.c | 2 +- drivers/ufs/core/ufs-sysfs.h | 1 - drivers/ufs/core/ufshcd.c | 2 -- 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/ufs/core/ufs-sysfs.c b/drivers/ufs/core/ufs-sysfs.c index c040afc6668e8..0086816b27cd9 100644 --- a/drivers/ufs/core/ufs-sysfs.c +++ b/drivers/ufs/core/ufs-sysfs.c @@ -1949,7 +1949,7 @@ static umode_t ufs_sysfs_hid_is_visible(struct kobject *kobj, return hba->dev_info.hid_sup ? attr->mode : 0; } -const struct attribute_group ufs_sysfs_hid_group = { +static const struct attribute_group ufs_sysfs_hid_group = { .name = "hid", .attrs = ufs_sysfs_hid, .is_visible = ufs_sysfs_hid_is_visible, diff --git a/drivers/ufs/core/ufs-sysfs.h b/drivers/ufs/core/ufs-sysfs.h index 6efb82a082fdd..8d94af3b80771 100644 --- a/drivers/ufs/core/ufs-sysfs.h +++ b/drivers/ufs/core/ufs-sysfs.h @@ -14,6 +14,5 @@ void ufs_sysfs_remove_nodes(struct device *dev); extern const struct attribute_group ufs_sysfs_unit_descriptor_group; extern const struct attribute_group ufs_sysfs_lun_attributes_group; -extern const struct attribute_group ufs_sysfs_hid_group; #endif diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 8339fec975b92..fd480b1a92f7d 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -8497,8 +8497,6 @@ static int ufs_get_device_desc(struct ufs_hba *hba) DEVICE_DESC_PARAM_EXT_UFS_FEATURE_SUP) & UFS_DEV_HID_SUPPORT; - sysfs_update_group(&hba->dev->kobj, &ufs_sysfs_hid_group); - model_index = desc_buf[DEVICE_DESC_PARAM_PRDCT_NAME]; err = ufshcd_read_string_desc(hba, model_index, From 5c5ee78b52dc805efba4fff54608ad87725c802c Mon Sep 17 00:00:00 2001 From: Pradeep P V K Date: Mon, 13 Oct 2025 15:21:40 +0530 Subject: [PATCH 0180/2333] PENDING: arch: arm64: Enable UFS on x1e80100 SoC Enable UFS on x1e80100 SoC. Signed-off-by: Pradeep P V K --- arch/arm64/boot/dts/qcom/x1e80100.dtsi | 101 +++++++++++++++++++++++++ 1 file changed, 101 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/x1e80100.dtsi b/arch/arm64/boot/dts/qcom/x1e80100.dtsi index 51576d9c935de..17b09166f5442 100644 --- a/arch/arm64/boot/dts/qcom/x1e80100.dtsi +++ b/arch/arm64/boot/dts/qcom/x1e80100.dtsi @@ -4675,6 +4675,107 @@ }; }; + ufs_mem_phy: phy@1d80000 { + compatible = "qcom,sm8550-qmp-ufs-phy"; + reg = <0x0 0x1d80000 0x0 0x2000>; + + clocks = <&rpmhcc RPMH_CXO_CLK>, + <&gcc GCC_UFS_PHY_PHY_AUX_CLK>, + <&tcsr TCSR_UFS_PHY_CLKREF_EN>; + + clock-names = "ref", + "ref_aux", + "qref"; + resets = <&ufs_mem_hc 0>; + reset-names = "ufsphy"; + + power-domains = <&gcc GCC_UFS_MEM_PHY_GDSC>; + + #clock-cells = <1>; + #phy-cells = <0>; + + status = "disabled"; + }; + + ufs_mem_hc: ufs@1d84000 { + compatible = "qcom,sm8550-ufshc", "qcom,ufshc", "jedec,ufs-2.0"; + reg = <0x0 0x1d84000 0x0 0x3000>; + + interrupts = ; + + clocks = <&gcc GCC_UFS_PHY_AXI_CLK>, + <&gcc GCC_AGGRE_UFS_PHY_AXI_CLK>, + <&gcc GCC_UFS_PHY_AHB_CLK>, + <&gcc GCC_UFS_PHY_UNIPRO_CORE_CLK>, + <&rpmhcc RPMH_LN_BB_CLK3>, + <&gcc GCC_UFS_PHY_TX_SYMBOL_0_CLK>, + <&gcc GCC_UFS_PHY_RX_SYMBOL_0_CLK>, + <&gcc GCC_UFS_PHY_RX_SYMBOL_1_CLK>; + clock-names = "core_clk", + "bus_aggr_clk", + "iface_clk", + "core_clk_unipro", + "ref_clk", + "tx_lane0_sync_clk", + "rx_lane0_sync_clk", + "rx_lane1_sync_clk"; + + operating-points-v2 = <&ufs_opp_table>; + + resets = <&gcc GCC_UFS_PHY_BCR>; + reset-names = "rst"; + + interconnects = <&aggre1_noc MASTER_UFS_MEM QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ACTIVE_ONLY + &config_noc SLAVE_UFS_MEM_CFG QCOM_ICC_TAG_ACTIVE_ONLY>; + interconnect-names = "ufs-ddr", + "cpu-ufs"; + + power-domains = <&gcc GCC_UFS_PHY_GDSC>; + required-opps = <&rpmhpd_opp_nom>; + + iommus = <&apps_smmu 0x1a0 0>; + dma-coherent; + + lanes-per-direction = <2>; + + phys = <&ufs_mem_phy>; + phy-names = "ufsphy"; + + #reset-cells = <1>; + + status = "disabled"; + + ufs_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-75000000 { + opp-hz = /bits/ 64 <75000000>, + /bits/ 64 <0>, + /bits/ 64 <0>, + /bits/ 64 <75000000>, + /bits/ 64 <0>, + /bits/ 64 <0>, + /bits/ 64 <0>, + /bits/ 64 <0>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + + opp-300000000 { + opp-hz = /bits/ 64 <300000000>, + /bits/ 64 <0>, + /bits/ 64 <0>, + /bits/ 64 <300000000>, + /bits/ 64 <0>, + /bits/ 64 <0>, + /bits/ 64 <0>, + /bits/ 64 <0>; + required-opps = <&rpmhpd_opp_nom>; + }; + }; + }; + usb_2_hsphy: phy@88e0000 { compatible = "qcom,x1e80100-snps-eusb2-phy", "qcom,sm8550-snps-eusb2-phy"; From ba8c93ddc42883a8b91db3e5fd0f19d0c79a9ddb Mon Sep 17 00:00:00 2001 From: Pradeep P V K Date: Tue, 18 Nov 2025 18:43:50 +0530 Subject: [PATCH 0181/2333] PENDING: arch: arm64: Enable UFS on HAMOA-IOT-EVK board Enable UFS for HAMOA-IOT-EVK board. Signed-off-by: Pradeep P V K --- arch/arm64/boot/dts/qcom/hamoa-iot-evk.dts | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/hamoa-iot-evk.dts b/arch/arm64/boot/dts/qcom/hamoa-iot-evk.dts index df8d6e5c1f45e..b6b45627208d6 100644 --- a/arch/arm64/boot/dts/qcom/hamoa-iot-evk.dts +++ b/arch/arm64/boot/dts/qcom/hamoa-iot-evk.dts @@ -1170,6 +1170,24 @@ status = "okay"; }; +&ufs_mem_phy { + vdda-phy-supply = <&vreg_l3i_0p8>; + vdda-pll-supply = <&vreg_l3e_1p2>; + + status = "okay"; +}; + +&ufs_mem_hc { + reset-gpios = <&tlmm 238 GPIO_ACTIVE_LOW>; + + vcc-supply = <&vreg_l17b_2p5>; + vcc-max-microamp = <1300000>; + vccq-supply = <&vreg_l2i_1p2>; + vccq-max-microamp = <1200000>; + + status = "okay"; +}; + &usb_1_ss0_dwc3_hs { remote-endpoint = <&pmic_glink_ss0_hs_in>; }; From 40fa15ea08b01a310aece3e0342e1eb3b41c7f19 Mon Sep 17 00:00:00 2001 From: Taniya Das Date: Wed, 19 Nov 2025 23:23:03 +0530 Subject: [PATCH 0182/2333] FROMLIST: clk: qcom: gcc-x1e80100: Use BRANCH_HALT_DELAY for UFS PHY symbol Switch the halt_check method from BRANCH_HALT to BRANCH_HALT_DELAY for gcc_ufs_phy_rx_symbol_0_clk, gcc_ufs_phy_rx_symbol_1_clk, and gcc_ufs_phy_tx_symbol_0_clk. These clocks are externally sourced and do not require polling for halt status. Fixes: 161b7c401f4b ("clk: qcom: Add Global Clock controller (GCC) driver for X1E80100") Link: https://lore.kernel.org/r/20251119-gcc_ufs_phy_clk_branch_delay-v1-1-292c3e40b8c7@oss.qualcomm.com Signed-off-by: Taniya Das --- drivers/clk/qcom/gcc-x1e80100.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/clk/qcom/gcc-x1e80100.c b/drivers/clk/qcom/gcc-x1e80100.c index 301fc9fc32d8e..cc68f995fd51f 100644 --- a/drivers/clk/qcom/gcc-x1e80100.c +++ b/drivers/clk/qcom/gcc-x1e80100.c @@ -4741,7 +4741,7 @@ static struct clk_branch gcc_ufs_phy_phy_aux_clk = { static struct clk_branch gcc_ufs_phy_rx_symbol_0_clk = { .halt_reg = 0x7702c, - .halt_check = BRANCH_HALT, + .halt_check = BRANCH_HALT_DELAY, .clkr = { .enable_reg = 0x7702c, .enable_mask = BIT(0), @@ -4754,7 +4754,7 @@ static struct clk_branch gcc_ufs_phy_rx_symbol_0_clk = { static struct clk_branch gcc_ufs_phy_rx_symbol_1_clk = { .halt_reg = 0x770cc, - .halt_check = BRANCH_HALT, + .halt_check = BRANCH_HALT_DELAY, .clkr = { .enable_reg = 0x770cc, .enable_mask = BIT(0), @@ -4767,7 +4767,7 @@ static struct clk_branch gcc_ufs_phy_rx_symbol_1_clk = { static struct clk_branch gcc_ufs_phy_tx_symbol_0_clk = { .halt_reg = 0x77028, - .halt_check = BRANCH_HALT, + .halt_check = BRANCH_HALT_DELAY, .clkr = { .enable_reg = 0x77028, .enable_mask = BIT(0), From 1558b66877e83a1625c0f48de433bb39c6f78789 Mon Sep 17 00:00:00 2001 From: Xiangxu Yin Date: Tue, 4 Nov 2025 09:33:25 +0800 Subject: [PATCH 0183/2333] FROMLIST: arm64: dts: qcom: talos: Add DisplayPort and QMP USB3-DP PHY Introduce DisplayPort controller node and associated QMP USB3-DP PHY for SM6150 SoC. Add data-lanes property to the DP endpoint and update clock assignments for proper DP integration. Reviewed-by: Dmitry Baryshkov Reviewed-by: Konrad Dybcio Signed-off-by: Xiangxu Yin Link: https://lore.kernel.org/all/20251104-add-displayport-support-to-qcs615-devicetree-v7-3-e51669170a6f@oss.qualcomm.com/ --- arch/arm64/boot/dts/qcom/talos.dtsi | 115 +++++++++++++++++++++++++++- 1 file changed, 113 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/talos.dtsi b/arch/arm64/boot/dts/qcom/talos.dtsi index 579c5758ff657..eff8f9f78c6f5 100644 --- a/arch/arm64/boot/dts/qcom/talos.dtsi +++ b/arch/arm64/boot/dts/qcom/talos.dtsi @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -3716,6 +3717,7 @@ reg = <0>; dpu_intf0_out: endpoint { + remote-endpoint = <&mdss_dp0_in>; }; }; @@ -3748,6 +3750,89 @@ }; }; + mdss_dp0: displayport-controller@ae90000 { + compatible = "qcom,sm6150-dp", "qcom,sm8150-dp", "qcom,sm8350-dp"; + + reg = <0x0 0x0ae90000 0x0 0x200>, + <0x0 0x0ae90200 0x0 0x200>, + <0x0 0x0ae90400 0x0 0x600>, + <0x0 0x0ae90a00 0x0 0x600>, + <0x0 0x0ae91000 0x0 0x600>; + + interrupt-parent = <&mdss>; + interrupts = <12>; + + clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>, + <&dispcc DISP_CC_MDSS_DP_AUX_CLK>, + <&dispcc DISP_CC_MDSS_DP_LINK_CLK>, + <&dispcc DISP_CC_MDSS_DP_LINK_INTF_CLK>, + <&dispcc DISP_CC_MDSS_DP_PIXEL_CLK>, + <&dispcc DISP_CC_MDSS_DP_PIXEL1_CLK>; + clock-names = "core_iface", + "core_aux", + "ctrl_link", + "ctrl_link_iface", + "stream_pixel", + "stream_1_pixel"; + + assigned-clocks = <&dispcc DISP_CC_MDSS_DP_LINK_CLK_SRC>, + <&dispcc DISP_CC_MDSS_DP_PIXEL_CLK_SRC>, + <&dispcc DISP_CC_MDSS_DP_PIXEL1_CLK_SRC>; + assigned-clock-parents = <&usb_qmpphy_2 QMP_USB43DP_DP_LINK_CLK>, + <&usb_qmpphy_2 QMP_USB43DP_DP_VCO_DIV_CLK>, + <&usb_qmpphy_2 QMP_USB43DP_DP_VCO_DIV_CLK>; + + phys = <&usb_qmpphy_2 QMP_USB43DP_DP_PHY>; + phy-names = "dp"; + + operating-points-v2 = <&dp_opp_table>; + power-domains = <&rpmhpd RPMHPD_CX>; + + #sound-dai-cells = <0>; + + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + mdss_dp0_in: endpoint { + remote-endpoint = <&dpu_intf0_out>; + }; + }; + + port@1 { + reg = <1>; + + mdss_dp0_out: endpoint { + data-lanes = <3 2 0 1>; + }; + }; + }; + + dp_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-160000000 { + opp-hz = /bits/ 64 <160000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + + opp-270000000 { + opp-hz = /bits/ 64 <270000000>; + required-opps = <&rpmhpd_opp_svs>; + }; + + opp-540000000 { + opp-hz = /bits/ 64 <540000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + }; + }; + mdss_dsi0: dsi@ae94000 { compatible = "qcom,sm6150-dsi-ctrl", "qcom,mdss-dsi-ctrl"; reg = <0x0 0x0ae94000 0x0 0x400>; @@ -3843,8 +3928,8 @@ <&mdss_dsi0_phy DSI_BYTE_PLL_CLK>, <&mdss_dsi0_phy DSI_PIXEL_PLL_CLK>, <0>, - <0>, - <0>; + <&usb_qmpphy_2 QMP_USB43DP_DP_LINK_CLK>, + <&usb_qmpphy_2 QMP_USB43DP_DP_VCO_DIV_CLK>; #clock-cells = <1>; #reset-cells = <1>; @@ -4213,6 +4298,32 @@ status = "disabled"; }; + usb_qmpphy_2: phy@88e8000 { + compatible = "qcom,qcs615-qmp-usb3-dp-phy"; + reg = <0x0 0x088e8000 0x0 0x2000>; + + clocks = <&gcc GCC_USB2_SEC_PHY_AUX_CLK>, + <&gcc GCC_USB3_SEC_CLKREF_CLK>, + <&gcc GCC_AHB2PHY_WEST_CLK>, + <&gcc GCC_USB2_SEC_PHY_PIPE_CLK>; + clock-names = "aux", + "ref", + "cfg_ahb", + "pipe"; + + resets = <&gcc GCC_USB3PHY_PHY_SEC_BCR >, + <&gcc GCC_USB3_DP_PHY_SEC_BCR>; + reset-names = "phy_phy", + "dp_phy"; + + #clock-cells = <1>; + #phy-cells = <1>; + + qcom,tcsr-reg = <&tcsr 0xbff0 0xb24c>; + + status = "disabled"; + }; + usb_1: usb@a6f8800 { compatible = "qcom,qcs615-dwc3", "qcom,dwc3"; reg = <0x0 0x0a6f8800 0x0 0x400>; From ac047bf2fb68a45c0708be88eb78482f1b5278f3 Mon Sep 17 00:00:00 2001 From: Xiangxu Yin Date: Tue, 4 Nov 2025 09:33:26 +0800 Subject: [PATCH 0184/2333] FROMLIST: arm64: dts: qcom: qcs615-ride: Enable DisplayPort Add DP connector node and configure MDSS DisplayPort controller for QCS615 Ride platform. Include PHY supply settings to support DP output. Reviewed-by: Konrad Dybcio Signed-off-by: Xiangxu Yin Link: https://lore.kernel.org/all/20251104-add-displayport-support-to-qcs615-devicetree-v7-4-e51669170a6f@oss.qualcomm.com/ --- arch/arm64/boot/dts/qcom/qcs615-ride.dts | 30 ++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/qcs615-ride.dts b/arch/arm64/boot/dts/qcom/qcs615-ride.dts index 54733ce0ba171..d18a6393c4c2d 100644 --- a/arch/arm64/boot/dts/qcom/qcs615-ride.dts +++ b/arch/arm64/boot/dts/qcom/qcs615-ride.dts @@ -39,6 +39,20 @@ }; }; + dp0-connector { + compatible = "dp-connector"; + label = "DP0"; + type = "mini"; + + hpd-gpios = <&io_expander 8 GPIO_ACTIVE_HIGH>; + + port { + dp0_connector_in: endpoint { + remote-endpoint = <&mdss_dp0_out>; + }; + }; + }; + dp-dsi0-connector { compatible = "dp-connector"; label = "DSI0"; @@ -423,6 +437,15 @@ status = "okay"; }; +&mdss_dp0 { + status = "okay"; +}; + +&mdss_dp0_out { + link-frequencies = /bits/ 64 <1620000000 2700000000 5400000000>; + remote-endpoint = <&dp0_connector_in>; +}; + &mdss_dsi0 { vdda-supply = <&vreg_l11a>; status = "okay"; @@ -631,6 +654,13 @@ status = "okay"; }; +&usb_qmpphy_2 { + vdda-phy-supply = <&vreg_l5a>; + vdda-pll-supply = <&vreg_l12a>; + + status = "okay"; +}; + &usb_1 { status = "okay"; }; From aea4f0c77e2524664061c3756cf8cadccec41145 Mon Sep 17 00:00:00 2001 From: Taniya Das Date: Fri, 31 Oct 2025 15:32:25 +0530 Subject: [PATCH 0185/2333] clk: qcom: tcsrcc-glymur: Update register offsets for clock refs Update the register offsets for all the clock ref branches to match the new address mapping in the TCSR subsystem. Fixes: 2c1d6ce4f3da ("clk: qcom: Add TCSR clock driver for Glymur SoC") Reviewed-by: Abel Vesa Tested-by: Jagadeesh Kona Link: https://lore.kernel.org/r/20251031-tcsrcc_glymur-v1-1-0efb031f0ac5@oss.qualcomm.com Signed-off-by: Taniya Das --- drivers/clk/qcom/tcsrcc-glymur.c | 54 ++++++++++++++++---------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/drivers/clk/qcom/tcsrcc-glymur.c b/drivers/clk/qcom/tcsrcc-glymur.c index c1f8b6d10b7fd..215bc2ac548da 100644 --- a/drivers/clk/qcom/tcsrcc-glymur.c +++ b/drivers/clk/qcom/tcsrcc-glymur.c @@ -28,10 +28,10 @@ enum { }; static struct clk_branch tcsr_edp_clkref_en = { - .halt_reg = 0x1c, + .halt_reg = 0x60, .halt_check = BRANCH_HALT_DELAY, .clkr = { - .enable_reg = 0x1c, + .enable_reg = 0x60, .enable_mask = BIT(0), .hw.init = &(const struct clk_init_data) { .name = "tcsr_edp_clkref_en", @@ -45,10 +45,10 @@ static struct clk_branch tcsr_edp_clkref_en = { }; static struct clk_branch tcsr_pcie_1_clkref_en = { - .halt_reg = 0x4, + .halt_reg = 0x48, .halt_check = BRANCH_HALT_DELAY, .clkr = { - .enable_reg = 0x4, + .enable_reg = 0x48, .enable_mask = BIT(0), .hw.init = &(const struct clk_init_data) { .name = "tcsr_pcie_1_clkref_en", @@ -62,10 +62,10 @@ static struct clk_branch tcsr_pcie_1_clkref_en = { }; static struct clk_branch tcsr_pcie_2_clkref_en = { - .halt_reg = 0x8, + .halt_reg = 0x4c, .halt_check = BRANCH_HALT_DELAY, .clkr = { - .enable_reg = 0x8, + .enable_reg = 0x4c, .enable_mask = BIT(0), .hw.init = &(const struct clk_init_data) { .name = "tcsr_pcie_2_clkref_en", @@ -79,10 +79,10 @@ static struct clk_branch tcsr_pcie_2_clkref_en = { }; static struct clk_branch tcsr_pcie_3_clkref_en = { - .halt_reg = 0x10, + .halt_reg = 0x54, .halt_check = BRANCH_HALT_DELAY, .clkr = { - .enable_reg = 0x10, + .enable_reg = 0x54, .enable_mask = BIT(0), .hw.init = &(const struct clk_init_data) { .name = "tcsr_pcie_3_clkref_en", @@ -96,10 +96,10 @@ static struct clk_branch tcsr_pcie_3_clkref_en = { }; static struct clk_branch tcsr_pcie_4_clkref_en = { - .halt_reg = 0x14, + .halt_reg = 0x58, .halt_check = BRANCH_HALT_DELAY, .clkr = { - .enable_reg = 0x14, + .enable_reg = 0x58, .enable_mask = BIT(0), .hw.init = &(const struct clk_init_data) { .name = "tcsr_pcie_4_clkref_en", @@ -113,10 +113,10 @@ static struct clk_branch tcsr_pcie_4_clkref_en = { }; static struct clk_branch tcsr_usb2_1_clkref_en = { - .halt_reg = 0x28, + .halt_reg = 0x6c, .halt_check = BRANCH_HALT_DELAY, .clkr = { - .enable_reg = 0x28, + .enable_reg = 0x6c, .enable_mask = BIT(0), .hw.init = &(const struct clk_init_data) { .name = "tcsr_usb2_1_clkref_en", @@ -130,10 +130,10 @@ static struct clk_branch tcsr_usb2_1_clkref_en = { }; static struct clk_branch tcsr_usb2_2_clkref_en = { - .halt_reg = 0x2c, + .halt_reg = 0x70, .halt_check = BRANCH_HALT_DELAY, .clkr = { - .enable_reg = 0x2c, + .enable_reg = 0x70, .enable_mask = BIT(0), .hw.init = &(const struct clk_init_data) { .name = "tcsr_usb2_2_clkref_en", @@ -147,10 +147,10 @@ static struct clk_branch tcsr_usb2_2_clkref_en = { }; static struct clk_branch tcsr_usb2_3_clkref_en = { - .halt_reg = 0x30, + .halt_reg = 0x74, .halt_check = BRANCH_HALT_DELAY, .clkr = { - .enable_reg = 0x30, + .enable_reg = 0x74, .enable_mask = BIT(0), .hw.init = &(const struct clk_init_data) { .name = "tcsr_usb2_3_clkref_en", @@ -164,10 +164,10 @@ static struct clk_branch tcsr_usb2_3_clkref_en = { }; static struct clk_branch tcsr_usb2_4_clkref_en = { - .halt_reg = 0x44, + .halt_reg = 0x88, .halt_check = BRANCH_HALT_DELAY, .clkr = { - .enable_reg = 0x44, + .enable_reg = 0x88, .enable_mask = BIT(0), .hw.init = &(const struct clk_init_data) { .name = "tcsr_usb2_4_clkref_en", @@ -181,10 +181,10 @@ static struct clk_branch tcsr_usb2_4_clkref_en = { }; static struct clk_branch tcsr_usb3_0_clkref_en = { - .halt_reg = 0x20, + .halt_reg = 0x64, .halt_check = BRANCH_HALT_DELAY, .clkr = { - .enable_reg = 0x20, + .enable_reg = 0x64, .enable_mask = BIT(0), .hw.init = &(const struct clk_init_data) { .name = "tcsr_usb3_0_clkref_en", @@ -198,10 +198,10 @@ static struct clk_branch tcsr_usb3_0_clkref_en = { }; static struct clk_branch tcsr_usb3_1_clkref_en = { - .halt_reg = 0x24, + .halt_reg = 0x68, .halt_check = BRANCH_HALT_DELAY, .clkr = { - .enable_reg = 0x24, + .enable_reg = 0x68, .enable_mask = BIT(0), .hw.init = &(const struct clk_init_data) { .name = "tcsr_usb3_1_clkref_en", @@ -215,10 +215,10 @@ static struct clk_branch tcsr_usb3_1_clkref_en = { }; static struct clk_branch tcsr_usb4_1_clkref_en = { - .halt_reg = 0x0, + .halt_reg = 0x44, .halt_check = BRANCH_HALT_DELAY, .clkr = { - .enable_reg = 0x0, + .enable_reg = 0x44, .enable_mask = BIT(0), .hw.init = &(const struct clk_init_data) { .name = "tcsr_usb4_1_clkref_en", @@ -232,10 +232,10 @@ static struct clk_branch tcsr_usb4_1_clkref_en = { }; static struct clk_branch tcsr_usb4_2_clkref_en = { - .halt_reg = 0x18, + .halt_reg = 0x5c, .halt_check = BRANCH_HALT_DELAY, .clkr = { - .enable_reg = 0x18, + .enable_reg = 0x5c, .enable_mask = BIT(0), .hw.init = &(const struct clk_init_data) { .name = "tcsr_usb4_2_clkref_en", @@ -268,7 +268,7 @@ static const struct regmap_config tcsr_cc_glymur_regmap_config = { .reg_bits = 32, .reg_stride = 4, .val_bits = 32, - .max_register = 0x44, + .max_register = 0x94, .fast_io = true, }; From a6f7092e9a363fd462a5825ff15a82af744793cb Mon Sep 17 00:00:00 2001 From: Kamal Wadhwa Date: Thu, 18 Sep 2025 14:57:01 +0530 Subject: [PATCH 0186/2333] FROMGIT: dt-bindings: rpmh-regulator : Add compatibles for PMH01XX & PMCX0102 Add rpmh-regulator driver compatibles strings for below PMICs: - PMH0101 - PMH0104 - PMH0110 - PMCX0102 Also add the supply name properties for the regulators present on these PMICs. Co-developed-by: Jishnu Prakash Signed-off-by: Jishnu Prakash Signed-off-by: Kamal Wadhwa Link: https://patch.msgid.link/20250918-glymur-rpmh-regulator-driver-v3-1-184c09678be3@oss.qualcomm.com Signed-off-by: Mark Brown Signed-off-by: Yijie Yang --- .../regulator/qcom,rpmh-regulator.yaml | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.yaml b/Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.yaml index 4c5b0629aa3e6..40e57b10ebbeb 100644 --- a/Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.yaml +++ b/Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.yaml @@ -51,8 +51,12 @@ description: | For PM8450, smps1 - smps6, ldo1 - ldo4 For PM8550, smps1 - smps6, ldo1 - ldo17, bob1 - bob2 For PM8998, smps1 - smps13, ldo1 - ldo28, lvs1 - lvs2 + For PMH0101, ldo1 - ldo18, bob1 - bob2 + For PMH0104, smps1 - smps4 + For PMH0110, smps1 - smps10, ldo1 - ldo4 For PMI8998, bob For PMC8380, smps1 - smps8, ldo1 - lodo3 + For PMCX0102, smps1 - smps10, ldo1 - ldo4 For PMR735A, smps1 - smps3, ldo1 - ldo7 For PMR735B, ldo1 - ldo12 For PMX55, smps1 - smps7, ldo1 - ldo16 @@ -85,7 +89,11 @@ properties: - qcom,pmc8180-rpmh-regulators - qcom,pmc8180c-rpmh-regulators - qcom,pmc8380-rpmh-regulators + - qcom,pmcx0102-rpmh-regulators - qcom,pmg1110-rpmh-regulators + - qcom,pmh0101-rpmh-regulators + - qcom,pmh0104-rpmh-regulators + - qcom,pmh0110-rpmh-regulators - qcom,pmi8998-rpmh-regulators - qcom,pmm8155au-rpmh-regulators - qcom,pmm8654au-rpmh-regulators @@ -246,6 +254,7 @@ allOf: compatible: enum: - qcom,pm8005-rpmh-regulators + - qcom,pmh0104-rpmh-regulators then: patternProperties: "^vdd-s[1-4]-supply$": true @@ -422,6 +431,34 @@ allOf: properties: vdd-s1-supply: true + - if: + properties: + compatible: + enum: + - qcom,pmh0101-rpmh-regulators + then: + properties: + vdd-l1-l4-l10-supply: true + vdd-l2-l13-l14-supply: true + vdd-l3-l11-supply: true + vdd-l5-l16-supply: true + vdd-l6-l7-supply: true + vdd-l8-l9-supply: true + patternProperties: + "^vdd-l(1[2578])-supply$": true + "^vdd-bob[1-2]-supply$": true + + - if: + properties: + compatible: + enum: + - qcom,pmcx0102-rpmh-regulators + - qcom,pmh0110-rpmh-regulators + then: + patternProperties: + "^vdd-l[1-4]-supply$": true + "^vdd-s([1-9]|10)-supply$": true + - if: properties: compatible: From 79c18d27199bcf4fa97427234339f96b18a083b2 Mon Sep 17 00:00:00 2001 From: Kamal Wadhwa Date: Thu, 18 Sep 2025 14:57:02 +0530 Subject: [PATCH 0187/2333] FROMGIT: dt-bindings: rpmh-regulator: Update pmic-id DT prop info for new CMD-DB Currently, CMD-DB names for RPMH regulators follow this format: `^(smps|ldo|bob|vs)[a-n][1-9][0-9]?$` Here, the `[a-n]` value is read from the `pmic-id` DT property, which is unique to each PMIC present on the board. Note that in this older CMD-DB name format the SPMI bus on which a particular PMIC regulator exists was not apparent from its CMD-DB name. New targets like Glymur, where we have multiple SPMI buses, overcome this limitation by following a new CMD-DB name format: `^(L|S|B)[1-9][0-9]?[A-N]_E[0-3]$` Here `[A-N]_E[0-3]` part will now be read from the `pmic-id` DT prop and it includes the SPMI bus id `[0-3]` as well. However, the PMIC ID part `[A-N]` of the CMD-DB name is now unique only to the SPMI bus that the PMIC regulator is present on. which means `L1B_E0` and `L1B_E1` are both possible CMD-DB names for two different regulator LDOs present on two different SPMI buses (bus id 0 and 1) on the same board. Note that since the new `pmic-id` DT property is a combo of PMIC ID and SPMI bus ID, so its still unique to each PMIC present on the board. Update the `pmic-id` property pattern information to reflect this change in the driver handling to support this new CMD-DB naming format while maintaining backward compatiblilty with old CMD-DB naming format which is still supported for older/existing targets. Signed-off-by: Kamal Wadhwa Link: https://patch.msgid.link/20250918-glymur-rpmh-regulator-driver-v3-2-184c09678be3@oss.qualcomm.com Signed-off-by: Mark Brown Signed-off-by: Yijie Yang --- .../devicetree/bindings/regulator/qcom,rpmh-regulator.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.yaml b/Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.yaml index 40e57b10ebbeb..40ddc64577e78 100644 --- a/Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.yaml +++ b/Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.yaml @@ -108,7 +108,7 @@ properties: RPMh resource name suffix used for the regulators found on this PMIC. $ref: /schemas/types.yaml#/definitions/string - enum: [a, b, c, d, e, f, g, h, i, j, k, l, m, n] + pattern: "^[a-n]|[A-N]_E[0-3]+$" qcom,always-wait-for-ack: description: | From 71f424fb76e46df5b2a53dd18f54efeb6a6b267e Mon Sep 17 00:00:00 2001 From: Kamal Wadhwa Date: Thu, 18 Sep 2025 14:57:03 +0530 Subject: [PATCH 0188/2333] FROMGIT: regulator: rpmh-regulator: Add support for new resource name format Currently rpmh-regulator resource name inside CMD-DB follows this format: `^(ldo|smp|bob|vs)[a-n][1-9][0-9]?$` (eg - ldob11, smpa2, bobc1 etc) Here `[a-n]` in the resource name signifies the `pmic-id`. However, newer firmware follows a different format that also includes the `bus_id` as well in the resource name. New format: `^(L|S|B)[1-9][0-9]?[A-N]_E[0-3]$` (eg - L11B_E1, S2A_E0, B1C_E0 etc) Here `_E[0-3]` at the end is the `bus_id`, and upper case `[A-N]` is used to denote `pmic-id`, while the regulator `(ldo|smp|bob)` is replaced with their initials in upper case `(L|S|B|VA)`. To handle this properly, do the following: - Remove the `resource_name` member from vreg init data - Add `index` and `regulator_hw_type` new members, which will contain the index number and the regulator hardware type (SMPS/LDO/BOB/VS) which can be combined with the pmic-id read from the devicetree to generate the resource_name. - Choose new resource name format if `pmic-id` contains `_E` in it, else fallback to old format. Reviewed-by: Dmitry Baryshkov Reviewed-by: Konrad Dybcio Signed-off-by: Kamal Wadhwa Link: https://patch.msgid.link/20250918-glymur-rpmh-regulator-driver-v3-3-184c09678be3@oss.qualcomm.com Signed-off-by: Mark Brown Signed-off-by: Yijie Yang --- drivers/regulator/qcom-rpmh-regulator.c | 1135 ++++++++++++----------- 1 file changed, 587 insertions(+), 548 deletions(-) diff --git a/drivers/regulator/qcom-rpmh-regulator.c b/drivers/regulator/qcom-rpmh-regulator.c index 109f0aae09b1d..dfb5bf5b72a1e 100644 --- a/drivers/regulator/qcom-rpmh-regulator.c +++ b/drivers/regulator/qcom-rpmh-regulator.c @@ -32,6 +32,34 @@ enum rpmh_regulator_type { XOB, }; +/** + * enum regulator_hw_type - supported regulator types + * @SMPS: Switch mode power supply. + * @LDO: Linear Dropout regulator. + * @BOB: Buck/Boost type regulator. + * @VS: Simple voltage ON/OFF switch. + * @NUM_REGULATOR_TYPES: Number of regulator types. + */ +enum regulator_hw_type { + SMPS, + LDO, + BOB, + VS, + NUM_REGULATOR_TYPES, +}; + +struct resource_name_formats { + const char *rsc_name_fmt; + const char *rsc_name_fmt1; +}; + +static const struct resource_name_formats vreg_rsc_name_lookup[NUM_REGULATOR_TYPES] = { + [SMPS] = {"S%d%s", "smp%s%d"}, + [LDO] = {"L%d%s", "ldo%s%d"}, + [BOB] = {"B%d%s", "bob%s%d"}, + [VS] = {"VS%d%s", "vs%s%d"}, +}; + #define RPMH_REGULATOR_REG_VRM_VOLTAGE 0x0 #define RPMH_REGULATOR_REG_ENABLE 0x4 #define RPMH_REGULATOR_REG_VRM_MODE 0x8 @@ -64,6 +92,7 @@ enum rpmh_regulator_type { #define PMIC5_BOB_MODE_AUTO 6 #define PMIC5_BOB_MODE_PWM 7 +#define PMIC_ID_LEN 4 /** * struct rpmh_vreg_hw_data - RPMh regulator hardware configurations * @regulator_type: RPMh accelerator type used to manage this @@ -136,17 +165,17 @@ struct rpmh_vreg { * struct rpmh_vreg_init_data - initialization data for an RPMh regulator * @name: Name for the regulator which also corresponds * to the device tree subnode name of the regulator - * @resource_name: RPMh regulator resource name format string. - * This must include exactly one field: '%s' which - * is filled at run-time with the PMIC ID provided - * by device tree property qcom,pmic-id. Example: - * "ldo%s1" for RPMh resource "ldoa1". + * @index: This is the index number of the regulator present + * on the PMIC. + * @vreg_hw_type: Regulator HW type enum, this must be BOB, SMPS, + * LDO, VS, based on the regulator HW type. * @supply_name: Parent supply regulator name * @hw_data: Configuration data for this PMIC regulator type */ struct rpmh_vreg_init_data { const char *name; - const char *resource_name; + enum regulator_hw_type vreg_hw_type; + int index; const char *supply_name; const struct rpmh_vreg_hw_data *hw_data; }; @@ -417,6 +446,7 @@ static int rpmh_regulator_init_vreg(struct rpmh_vreg *vreg, struct device *dev, { struct regulator_config reg_config = {}; char rpmh_resource_name[20] = ""; + const char *rsc_name; const struct rpmh_vreg_init_data *rpmh_data; struct regulator_init_data *init_data; struct regulator_dev *rdev; @@ -433,8 +463,16 @@ static int rpmh_regulator_init_vreg(struct rpmh_vreg *vreg, struct device *dev, return -EINVAL; } - scnprintf(rpmh_resource_name, sizeof(rpmh_resource_name), - rpmh_data->resource_name, pmic_id); + if (strnlen(pmic_id, PMIC_ID_LEN) > 1 && strnstr(pmic_id, "_E", PMIC_ID_LEN)) { + rsc_name = vreg_rsc_name_lookup[rpmh_data->vreg_hw_type].rsc_name_fmt; + scnprintf(rpmh_resource_name, sizeof(rpmh_resource_name), + rsc_name, rpmh_data->index, pmic_id); + + } else { + rsc_name = vreg_rsc_name_lookup[rpmh_data->vreg_hw_type].rsc_name_fmt1; + scnprintf(rpmh_resource_name, sizeof(rpmh_resource_name), + rsc_name, pmic_id, rpmh_data->index); + } vreg->addr = cmd_db_read_addr(rpmh_resource_name); if (!vreg->addr) { @@ -904,671 +942,672 @@ static const struct rpmh_vreg_hw_data pmic5_bob = { .of_map_mode = rpmh_regulator_pmic4_bob_of_map_mode, }; -#define RPMH_VREG(_name, _resource_name, _hw_data, _supply_name) \ +#define RPMH_VREG(_name, _vreg_hw_type, _index, _hw_data, _supply_name) \ { \ .name = _name, \ - .resource_name = _resource_name, \ + .vreg_hw_type = _vreg_hw_type, \ + .index = _index, \ .hw_data = _hw_data, \ .supply_name = _supply_name, \ } static const struct rpmh_vreg_init_data pm8998_vreg_data[] = { - RPMH_VREG("smps1", "smp%s1", &pmic4_ftsmps426, "vdd-s1"), - RPMH_VREG("smps2", "smp%s2", &pmic4_ftsmps426, "vdd-s2"), - RPMH_VREG("smps3", "smp%s3", &pmic4_hfsmps3, "vdd-s3"), - RPMH_VREG("smps4", "smp%s4", &pmic4_hfsmps3, "vdd-s4"), - RPMH_VREG("smps5", "smp%s5", &pmic4_hfsmps3, "vdd-s5"), - RPMH_VREG("smps6", "smp%s6", &pmic4_ftsmps426, "vdd-s6"), - RPMH_VREG("smps7", "smp%s7", &pmic4_ftsmps426, "vdd-s7"), - RPMH_VREG("smps8", "smp%s8", &pmic4_ftsmps426, "vdd-s8"), - RPMH_VREG("smps9", "smp%s9", &pmic4_ftsmps426, "vdd-s9"), - RPMH_VREG("smps10", "smp%s10", &pmic4_ftsmps426, "vdd-s10"), - RPMH_VREG("smps11", "smp%s11", &pmic4_ftsmps426, "vdd-s11"), - RPMH_VREG("smps12", "smp%s12", &pmic4_ftsmps426, "vdd-s12"), - RPMH_VREG("smps13", "smp%s13", &pmic4_ftsmps426, "vdd-s13"), - RPMH_VREG("ldo1", "ldo%s1", &pmic4_nldo, "vdd-l1-l27"), - RPMH_VREG("ldo2", "ldo%s2", &pmic4_nldo, "vdd-l2-l8-l17"), - RPMH_VREG("ldo3", "ldo%s3", &pmic4_nldo, "vdd-l3-l11"), - RPMH_VREG("ldo4", "ldo%s4", &pmic4_nldo, "vdd-l4-l5"), - RPMH_VREG("ldo5", "ldo%s5", &pmic4_nldo, "vdd-l4-l5"), - RPMH_VREG("ldo6", "ldo%s6", &pmic4_pldo, "vdd-l6"), - RPMH_VREG("ldo7", "ldo%s7", &pmic4_pldo_lv, "vdd-l7-l12-l14-l15"), - RPMH_VREG("ldo8", "ldo%s8", &pmic4_nldo, "vdd-l2-l8-l17"), - RPMH_VREG("ldo9", "ldo%s9", &pmic4_pldo, "vdd-l9"), - RPMH_VREG("ldo10", "ldo%s10", &pmic4_pldo, "vdd-l10-l23-l25"), - RPMH_VREG("ldo11", "ldo%s11", &pmic4_nldo, "vdd-l3-l11"), - RPMH_VREG("ldo12", "ldo%s12", &pmic4_pldo_lv, "vdd-l7-l12-l14-l15"), - RPMH_VREG("ldo13", "ldo%s13", &pmic4_pldo, "vdd-l13-l19-l21"), - RPMH_VREG("ldo14", "ldo%s14", &pmic4_pldo_lv, "vdd-l7-l12-l14-l15"), - RPMH_VREG("ldo15", "ldo%s15", &pmic4_pldo_lv, "vdd-l7-l12-l14-l15"), - RPMH_VREG("ldo16", "ldo%s16", &pmic4_pldo, "vdd-l16-l28"), - RPMH_VREG("ldo17", "ldo%s17", &pmic4_nldo, "vdd-l2-l8-l17"), - RPMH_VREG("ldo18", "ldo%s18", &pmic4_pldo, "vdd-l18-l22"), - RPMH_VREG("ldo19", "ldo%s19", &pmic4_pldo, "vdd-l13-l19-l21"), - RPMH_VREG("ldo20", "ldo%s20", &pmic4_pldo, "vdd-l20-l24"), - RPMH_VREG("ldo21", "ldo%s21", &pmic4_pldo, "vdd-l13-l19-l21"), - RPMH_VREG("ldo22", "ldo%s22", &pmic4_pldo, "vdd-l18-l22"), - RPMH_VREG("ldo23", "ldo%s23", &pmic4_pldo, "vdd-l10-l23-l25"), - RPMH_VREG("ldo24", "ldo%s24", &pmic4_pldo, "vdd-l20-l24"), - RPMH_VREG("ldo25", "ldo%s25", &pmic4_pldo, "vdd-l10-l23-l25"), - RPMH_VREG("ldo26", "ldo%s26", &pmic4_nldo, "vdd-l26"), - RPMH_VREG("ldo27", "ldo%s27", &pmic4_nldo, "vdd-l1-l27"), - RPMH_VREG("ldo28", "ldo%s28", &pmic4_pldo, "vdd-l16-l28"), - RPMH_VREG("lvs1", "vs%s1", &pmic4_lvs, "vin-lvs-1-2"), - RPMH_VREG("lvs2", "vs%s2", &pmic4_lvs, "vin-lvs-1-2"), + RPMH_VREG("smps1", SMPS, 1, &pmic4_ftsmps426, "vdd-s1"), + RPMH_VREG("smps2", SMPS, 2, &pmic4_ftsmps426, "vdd-s2"), + RPMH_VREG("smps3", SMPS, 3, &pmic4_hfsmps3, "vdd-s3"), + RPMH_VREG("smps4", SMPS, 4, &pmic4_hfsmps3, "vdd-s4"), + RPMH_VREG("smps5", SMPS, 5, &pmic4_hfsmps3, "vdd-s5"), + RPMH_VREG("smps6", SMPS, 6, &pmic4_ftsmps426, "vdd-s6"), + RPMH_VREG("smps7", SMPS, 7, &pmic4_ftsmps426, "vdd-s7"), + RPMH_VREG("smps8", SMPS, 8, &pmic4_ftsmps426, "vdd-s8"), + RPMH_VREG("smps9", SMPS, 9, &pmic4_ftsmps426, "vdd-s9"), + RPMH_VREG("smps10", SMPS, 10, &pmic4_ftsmps426, "vdd-s10"), + RPMH_VREG("smps11", SMPS, 11, &pmic4_ftsmps426, "vdd-s11"), + RPMH_VREG("smps12", SMPS, 12, &pmic4_ftsmps426, "vdd-s12"), + RPMH_VREG("smps13", SMPS, 13, &pmic4_ftsmps426, "vdd-s13"), + RPMH_VREG("ldo1", LDO, 1, &pmic4_nldo, "vdd-l1-l27"), + RPMH_VREG("ldo2", LDO, 2, &pmic4_nldo, "vdd-l2-l8-l17"), + RPMH_VREG("ldo3", LDO, 3, &pmic4_nldo, "vdd-l3-l11"), + RPMH_VREG("ldo4", LDO, 4, &pmic4_nldo, "vdd-l4-l5"), + RPMH_VREG("ldo5", LDO, 5, &pmic4_nldo, "vdd-l4-l5"), + RPMH_VREG("ldo6", LDO, 6, &pmic4_pldo, "vdd-l6"), + RPMH_VREG("ldo7", LDO, 7, &pmic4_pldo_lv, "vdd-l7-l12-l14-l15"), + RPMH_VREG("ldo8", LDO, 8, &pmic4_nldo, "vdd-l2-l8-l17"), + RPMH_VREG("ldo9", LDO, 9, &pmic4_pldo, "vdd-l9"), + RPMH_VREG("ldo10", LDO, 10, &pmic4_pldo, "vdd-l10-l23-l25"), + RPMH_VREG("ldo11", LDO, 11, &pmic4_nldo, "vdd-l3-l11"), + RPMH_VREG("ldo12", LDO, 12, &pmic4_pldo_lv, "vdd-l7-l12-l14-l15"), + RPMH_VREG("ldo13", LDO, 13, &pmic4_pldo, "vdd-l13-l19-l21"), + RPMH_VREG("ldo14", LDO, 14, &pmic4_pldo_lv, "vdd-l7-l12-l14-l15"), + RPMH_VREG("ldo15", LDO, 15, &pmic4_pldo_lv, "vdd-l7-l12-l14-l15"), + RPMH_VREG("ldo16", LDO, 16, &pmic4_pldo, "vdd-l16-l28"), + RPMH_VREG("ldo17", LDO, 17, &pmic4_nldo, "vdd-l2-l8-l17"), + RPMH_VREG("ldo18", LDO, 18, &pmic4_pldo, "vdd-l18-l22"), + RPMH_VREG("ldo19", LDO, 19, &pmic4_pldo, "vdd-l13-l19-l21"), + RPMH_VREG("ldo20", LDO, 20, &pmic4_pldo, "vdd-l20-l24"), + RPMH_VREG("ldo21", LDO, 21, &pmic4_pldo, "vdd-l13-l19-l21"), + RPMH_VREG("ldo22", LDO, 22, &pmic4_pldo, "vdd-l18-l22"), + RPMH_VREG("ldo23", LDO, 23, &pmic4_pldo, "vdd-l10-l23-l25"), + RPMH_VREG("ldo24", LDO, 24, &pmic4_pldo, "vdd-l20-l24"), + RPMH_VREG("ldo25", LDO, 25, &pmic4_pldo, "vdd-l10-l23-l25"), + RPMH_VREG("ldo26", LDO, 26, &pmic4_nldo, "vdd-l26"), + RPMH_VREG("ldo27", LDO, 27, &pmic4_nldo, "vdd-l1-l27"), + RPMH_VREG("ldo28", LDO, 28, &pmic4_pldo, "vdd-l16-l28"), + RPMH_VREG("lvs1", VS, 1, &pmic4_lvs, "vin-lvs-1-2"), + RPMH_VREG("lvs2", VS, 2, &pmic4_lvs, "vin-lvs-1-2"), {} }; static const struct rpmh_vreg_init_data pmg1110_vreg_data[] = { - RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps510, "vdd-s1"), + RPMH_VREG("smps1", SMPS, 1, &pmic5_ftsmps510, "vdd-s1"), {} }; static const struct rpmh_vreg_init_data pmi8998_vreg_data[] = { - RPMH_VREG("bob", "bob%s1", &pmic4_bob, "vdd-bob"), + RPMH_VREG("bob", BOB, 1, &pmic4_bob, "vdd-bob"), {} }; static const struct rpmh_vreg_init_data pm8005_vreg_data[] = { - RPMH_VREG("smps1", "smp%s1", &pmic4_ftsmps426, "vdd-s1"), - RPMH_VREG("smps2", "smp%s2", &pmic4_ftsmps426, "vdd-s2"), - RPMH_VREG("smps3", "smp%s3", &pmic4_ftsmps426, "vdd-s3"), - RPMH_VREG("smps4", "smp%s4", &pmic4_ftsmps426, "vdd-s4"), + RPMH_VREG("smps1", SMPS, 1, &pmic4_ftsmps426, "vdd-s1"), + RPMH_VREG("smps2", SMPS, 2, &pmic4_ftsmps426, "vdd-s2"), + RPMH_VREG("smps3", SMPS, 3, &pmic4_ftsmps426, "vdd-s3"), + RPMH_VREG("smps4", SMPS, 4, &pmic4_ftsmps426, "vdd-s4"), {} }; static const struct rpmh_vreg_init_data pm8150_vreg_data[] = { - RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps510, "vdd-s1"), - RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps510, "vdd-s2"), - RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps510, "vdd-s3"), - RPMH_VREG("smps4", "smp%s4", &pmic5_hfsmps510, "vdd-s4"), - RPMH_VREG("smps5", "smp%s5", &pmic5_hfsmps510, "vdd-s5"), - RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps510, "vdd-s6"), - RPMH_VREG("smps7", "smp%s7", &pmic5_ftsmps510, "vdd-s7"), - RPMH_VREG("smps8", "smp%s8", &pmic5_ftsmps510, "vdd-s8"), - RPMH_VREG("smps9", "smp%s9", &pmic5_ftsmps510, "vdd-s9"), - RPMH_VREG("smps10", "smp%s10", &pmic5_ftsmps510, "vdd-s10"), - RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo, "vdd-l1-l8-l11"), - RPMH_VREG("ldo2", "ldo%s2", &pmic5_pldo, "vdd-l2-l10"), - RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo, "vdd-l3-l4-l5-l18"), - RPMH_VREG("ldo4", "ldo%s4", &pmic5_nldo, "vdd-l3-l4-l5-l18"), - RPMH_VREG("ldo5", "ldo%s5", &pmic5_nldo, "vdd-l3-l4-l5-l18"), - RPMH_VREG("ldo6", "ldo%s6", &pmic5_nldo, "vdd-l6-l9"), - RPMH_VREG("ldo7", "ldo%s7", &pmic5_pldo, "vdd-l7-l12-l14-l15"), - RPMH_VREG("ldo8", "ldo%s8", &pmic5_nldo, "vdd-l1-l8-l11"), - RPMH_VREG("ldo9", "ldo%s9", &pmic5_nldo, "vdd-l6-l9"), - RPMH_VREG("ldo10", "ldo%s10", &pmic5_pldo, "vdd-l2-l10"), - RPMH_VREG("ldo11", "ldo%s11", &pmic5_nldo, "vdd-l1-l8-l11"), - RPMH_VREG("ldo12", "ldo%s12", &pmic5_pldo_lv, "vdd-l7-l12-l14-l15"), - RPMH_VREG("ldo13", "ldo%s13", &pmic5_pldo, "vdd-l13-l16-l17"), - RPMH_VREG("ldo14", "ldo%s14", &pmic5_pldo_lv, "vdd-l7-l12-l14-l15"), - RPMH_VREG("ldo15", "ldo%s15", &pmic5_pldo_lv, "vdd-l7-l12-l14-l15"), - RPMH_VREG("ldo16", "ldo%s16", &pmic5_pldo, "vdd-l13-l16-l17"), - RPMH_VREG("ldo17", "ldo%s17", &pmic5_pldo, "vdd-l13-l16-l17"), - RPMH_VREG("ldo18", "ldo%s18", &pmic5_nldo, "vdd-l3-l4-l5-l18"), + RPMH_VREG("smps1", SMPS, 1, &pmic5_ftsmps510, "vdd-s1"), + RPMH_VREG("smps2", SMPS, 2, &pmic5_ftsmps510, "vdd-s2"), + RPMH_VREG("smps3", SMPS, 3, &pmic5_ftsmps510, "vdd-s3"), + RPMH_VREG("smps4", SMPS, 4, &pmic5_hfsmps510, "vdd-s4"), + RPMH_VREG("smps5", SMPS, 5, &pmic5_hfsmps510, "vdd-s5"), + RPMH_VREG("smps6", SMPS, 6, &pmic5_ftsmps510, "vdd-s6"), + RPMH_VREG("smps7", SMPS, 7, &pmic5_ftsmps510, "vdd-s7"), + RPMH_VREG("smps8", SMPS, 8, &pmic5_ftsmps510, "vdd-s8"), + RPMH_VREG("smps9", SMPS, 9, &pmic5_ftsmps510, "vdd-s9"), + RPMH_VREG("smps10", SMPS, 10, &pmic5_ftsmps510, "vdd-s10"), + RPMH_VREG("ldo1", LDO, 1, &pmic5_nldo, "vdd-l1-l8-l11"), + RPMH_VREG("ldo2", LDO, 2, &pmic5_pldo, "vdd-l2-l10"), + RPMH_VREG("ldo3", LDO, 3, &pmic5_nldo, "vdd-l3-l4-l5-l18"), + RPMH_VREG("ldo4", LDO, 4, &pmic5_nldo, "vdd-l3-l4-l5-l18"), + RPMH_VREG("ldo5", LDO, 5, &pmic5_nldo, "vdd-l3-l4-l5-l18"), + RPMH_VREG("ldo6", LDO, 6, &pmic5_nldo, "vdd-l6-l9"), + RPMH_VREG("ldo7", LDO, 7, &pmic5_pldo, "vdd-l7-l12-l14-l15"), + RPMH_VREG("ldo8", LDO, 8, &pmic5_nldo, "vdd-l1-l8-l11"), + RPMH_VREG("ldo9", LDO, 9, &pmic5_nldo, "vdd-l6-l9"), + RPMH_VREG("ldo10", LDO, 10, &pmic5_pldo, "vdd-l2-l10"), + RPMH_VREG("ldo11", LDO, 11, &pmic5_nldo, "vdd-l1-l8-l11"), + RPMH_VREG("ldo12", LDO, 12, &pmic5_pldo_lv, "vdd-l7-l12-l14-l15"), + RPMH_VREG("ldo13", LDO, 13, &pmic5_pldo, "vdd-l13-l16-l17"), + RPMH_VREG("ldo14", LDO, 14, &pmic5_pldo_lv, "vdd-l7-l12-l14-l15"), + RPMH_VREG("ldo15", LDO, 15, &pmic5_pldo_lv, "vdd-l7-l12-l14-l15"), + RPMH_VREG("ldo16", LDO, 16, &pmic5_pldo, "vdd-l13-l16-l17"), + RPMH_VREG("ldo17", LDO, 17, &pmic5_pldo, "vdd-l13-l16-l17"), + RPMH_VREG("ldo18", LDO, 18, &pmic5_nldo, "vdd-l3-l4-l5-l18"), {} }; static const struct rpmh_vreg_init_data pm8150l_vreg_data[] = { - RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps510, "vdd-s1"), - RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps510, "vdd-s2"), - RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps510, "vdd-s3"), - RPMH_VREG("smps4", "smp%s4", &pmic5_ftsmps510, "vdd-s4"), - RPMH_VREG("smps5", "smp%s5", &pmic5_ftsmps510, "vdd-s5"), - RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps510, "vdd-s6"), - RPMH_VREG("smps7", "smp%s7", &pmic5_ftsmps510, "vdd-s7"), - RPMH_VREG("smps8", "smp%s8", &pmic5_hfsmps510, "vdd-s8"), - RPMH_VREG("ldo1", "ldo%s1", &pmic5_pldo_lv, "vdd-l1-l8"), - RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo, "vdd-l2-l3"), - RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo, "vdd-l2-l3"), - RPMH_VREG("ldo4", "ldo%s4", &pmic5_pldo, "vdd-l4-l5-l6"), - RPMH_VREG("ldo5", "ldo%s5", &pmic5_pldo, "vdd-l4-l5-l6"), - RPMH_VREG("ldo6", "ldo%s6", &pmic5_pldo, "vdd-l4-l5-l6"), - RPMH_VREG("ldo7", "ldo%s7", &pmic5_pldo, "vdd-l7-l11"), - RPMH_VREG("ldo8", "ldo%s8", &pmic5_pldo_lv, "vdd-l1-l8"), - RPMH_VREG("ldo9", "ldo%s9", &pmic5_pldo, "vdd-l9-l10"), - RPMH_VREG("ldo10", "ldo%s10", &pmic5_pldo, "vdd-l9-l10"), - RPMH_VREG("ldo11", "ldo%s11", &pmic5_pldo, "vdd-l7-l11"), - RPMH_VREG("bob", "bob%s1", &pmic5_bob, "vdd-bob"), + RPMH_VREG("smps1", SMPS, 1, &pmic5_ftsmps510, "vdd-s1"), + RPMH_VREG("smps2", SMPS, 2, &pmic5_ftsmps510, "vdd-s2"), + RPMH_VREG("smps3", SMPS, 3, &pmic5_ftsmps510, "vdd-s3"), + RPMH_VREG("smps4", SMPS, 4, &pmic5_ftsmps510, "vdd-s4"), + RPMH_VREG("smps5", SMPS, 5, &pmic5_ftsmps510, "vdd-s5"), + RPMH_VREG("smps6", SMPS, 6, &pmic5_ftsmps510, "vdd-s6"), + RPMH_VREG("smps7", SMPS, 7, &pmic5_ftsmps510, "vdd-s7"), + RPMH_VREG("smps8", SMPS, 8, &pmic5_hfsmps510, "vdd-s8"), + RPMH_VREG("ldo1", LDO, 1, &pmic5_pldo_lv, "vdd-l1-l8"), + RPMH_VREG("ldo2", LDO, 2, &pmic5_nldo, "vdd-l2-l3"), + RPMH_VREG("ldo3", LDO, 3, &pmic5_nldo, "vdd-l2-l3"), + RPMH_VREG("ldo4", LDO, 4, &pmic5_pldo, "vdd-l4-l5-l6"), + RPMH_VREG("ldo5", LDO, 5, &pmic5_pldo, "vdd-l4-l5-l6"), + RPMH_VREG("ldo6", LDO, 6, &pmic5_pldo, "vdd-l4-l5-l6"), + RPMH_VREG("ldo7", LDO, 7, &pmic5_pldo, "vdd-l7-l11"), + RPMH_VREG("ldo8", LDO, 8, &pmic5_pldo_lv, "vdd-l1-l8"), + RPMH_VREG("ldo9", LDO, 9, &pmic5_pldo, "vdd-l9-l10"), + RPMH_VREG("ldo10", LDO, 10, &pmic5_pldo, "vdd-l9-l10"), + RPMH_VREG("ldo11", LDO, 11, &pmic5_pldo, "vdd-l7-l11"), + RPMH_VREG("bob", BOB, 1, &pmic5_bob, "vdd-bob"), {} }; static const struct rpmh_vreg_init_data pmm8155au_vreg_data[] = { - RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps510, "vdd-s1"), - RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps510, "vdd-s2"), - RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps510, "vdd-s3"), - RPMH_VREG("smps4", "smp%s4", &pmic5_hfsmps510, "vdd-s4"), - RPMH_VREG("smps5", "smp%s5", &pmic5_hfsmps510, "vdd-s5"), - RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps510, "vdd-s6"), - RPMH_VREG("smps7", "smp%s7", &pmic5_ftsmps510, "vdd-s7"), - RPMH_VREG("smps8", "smp%s8", &pmic5_ftsmps510, "vdd-s8"), - RPMH_VREG("smps9", "smp%s9", &pmic5_ftsmps510, "vdd-s9"), - RPMH_VREG("smps10", "smp%s10", &pmic5_ftsmps510, "vdd-s10"), - RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo, "vdd-l1-l8-l11"), - RPMH_VREG("ldo2", "ldo%s2", &pmic5_pldo, "vdd-l2-l10"), - RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo, "vdd-l3-l4-l5-l18"), - RPMH_VREG("ldo4", "ldo%s4", &pmic5_nldo, "vdd-l3-l4-l5-l18"), - RPMH_VREG("ldo5", "ldo%s5", &pmic5_nldo, "vdd-l3-l4-l5-l18"), - RPMH_VREG("ldo6", "ldo%s6", &pmic5_nldo, "vdd-l6-l9"), - RPMH_VREG("ldo7", "ldo%s7", &pmic5_pldo_lv, "vdd-l7-l12-l14-l15"), - RPMH_VREG("ldo8", "ldo%s8", &pmic5_nldo, "vdd-l1-l8-l11"), - RPMH_VREG("ldo9", "ldo%s9", &pmic5_nldo, "vdd-l6-l9"), - RPMH_VREG("ldo10", "ldo%s10", &pmic5_pldo, "vdd-l2-l10"), - RPMH_VREG("ldo11", "ldo%s11", &pmic5_nldo, "vdd-l1-l8-l11"), - RPMH_VREG("ldo12", "ldo%s12", &pmic5_pldo_lv, "vdd-l7-l12-l14-l15"), - RPMH_VREG("ldo13", "ldo%s13", &pmic5_pldo, "vdd-l13-l16-l17"), - RPMH_VREG("ldo14", "ldo%s14", &pmic5_pldo_lv, "vdd-l7-l12-l14-l15"), - RPMH_VREG("ldo15", "ldo%s15", &pmic5_pldo_lv, "vdd-l7-l12-l14-l15"), - RPMH_VREG("ldo16", "ldo%s16", &pmic5_pldo, "vdd-l13-l16-l17"), - RPMH_VREG("ldo17", "ldo%s17", &pmic5_pldo, "vdd-l13-l16-l17"), - RPMH_VREG("ldo18", "ldo%s18", &pmic5_nldo, "vdd-l3-l4-l5-l18"), + RPMH_VREG("smps1", SMPS, 1, &pmic5_ftsmps510, "vdd-s1"), + RPMH_VREG("smps2", SMPS, 2, &pmic5_ftsmps510, "vdd-s2"), + RPMH_VREG("smps3", SMPS, 3, &pmic5_ftsmps510, "vdd-s3"), + RPMH_VREG("smps4", SMPS, 4, &pmic5_hfsmps510, "vdd-s4"), + RPMH_VREG("smps5", SMPS, 5, &pmic5_hfsmps510, "vdd-s5"), + RPMH_VREG("smps6", SMPS, 6, &pmic5_ftsmps510, "vdd-s6"), + RPMH_VREG("smps7", SMPS, 7, &pmic5_ftsmps510, "vdd-s7"), + RPMH_VREG("smps8", SMPS, 8, &pmic5_ftsmps510, "vdd-s8"), + RPMH_VREG("smps9", SMPS, 9, &pmic5_ftsmps510, "vdd-s9"), + RPMH_VREG("smps10", SMPS, 10, &pmic5_ftsmps510, "vdd-s10"), + RPMH_VREG("ldo1", LDO, 1, &pmic5_nldo, "vdd-l1-l8-l11"), + RPMH_VREG("ldo2", LDO, 2, &pmic5_pldo, "vdd-l2-l10"), + RPMH_VREG("ldo3", LDO, 3, &pmic5_nldo, "vdd-l3-l4-l5-l18"), + RPMH_VREG("ldo4", LDO, 4, &pmic5_nldo, "vdd-l3-l4-l5-l18"), + RPMH_VREG("ldo5", LDO, 5, &pmic5_nldo, "vdd-l3-l4-l5-l18"), + RPMH_VREG("ldo6", LDO, 6, &pmic5_nldo, "vdd-l6-l9"), + RPMH_VREG("ldo7", LDO, 7, &pmic5_pldo_lv, "vdd-l7-l12-l14-l15"), + RPMH_VREG("ldo8", LDO, 8, &pmic5_nldo, "vdd-l1-l8-l11"), + RPMH_VREG("ldo9", LDO, 9, &pmic5_nldo, "vdd-l6-l9"), + RPMH_VREG("ldo10", LDO, 10, &pmic5_pldo, "vdd-l2-l10"), + RPMH_VREG("ldo11", LDO, 11, &pmic5_nldo, "vdd-l1-l8-l11"), + RPMH_VREG("ldo12", LDO, 12, &pmic5_pldo_lv, "vdd-l7-l12-l14-l15"), + RPMH_VREG("ldo13", LDO, 13, &pmic5_pldo, "vdd-l13-l16-l17"), + RPMH_VREG("ldo14", LDO, 14, &pmic5_pldo_lv, "vdd-l7-l12-l14-l15"), + RPMH_VREG("ldo15", LDO, 15, &pmic5_pldo_lv, "vdd-l7-l12-l14-l15"), + RPMH_VREG("ldo16", LDO, 16, &pmic5_pldo, "vdd-l13-l16-l17"), + RPMH_VREG("ldo17", LDO, 17, &pmic5_pldo, "vdd-l13-l16-l17"), + RPMH_VREG("ldo18", LDO, 18, &pmic5_nldo, "vdd-l3-l4-l5-l18"), {} }; static const struct rpmh_vreg_init_data pmm8654au_vreg_data[] = { - RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps527, "vdd-s1"), - RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps527, "vdd-s2"), - RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps527, "vdd-s3"), - RPMH_VREG("smps4", "smp%s4", &pmic5_ftsmps527, "vdd-s4"), - RPMH_VREG("smps5", "smp%s5", &pmic5_ftsmps527, "vdd-s5"), - RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps527, "vdd-s6"), - RPMH_VREG("smps7", "smp%s7", &pmic5_ftsmps527, "vdd-s7"), - RPMH_VREG("smps8", "smp%s8", &pmic5_ftsmps527, "vdd-s8"), - RPMH_VREG("smps9", "smp%s9", &pmic5_ftsmps527, "vdd-s9"), - RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo515, "vdd-s9"), - RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo515, "vdd-l2-l3"), - RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo515, "vdd-l2-l3"), - RPMH_VREG("ldo4", "ldo%s4", &pmic5_nldo515, "vdd-s9"), - RPMH_VREG("ldo5", "ldo%s5", &pmic5_nldo515, "vdd-s9"), - RPMH_VREG("ldo6", "ldo%s6", &pmic5_nldo515, "vdd-l6-l7"), - RPMH_VREG("ldo7", "ldo%s7", &pmic5_nldo515, "vdd-l6-l7"), - RPMH_VREG("ldo8", "ldo%s8", &pmic5_pldo515_mv, "vdd-l8-l9"), - RPMH_VREG("ldo9", "ldo%s9", &pmic5_pldo, "vdd-l8-l9"), + RPMH_VREG("smps1", SMPS, 1, &pmic5_ftsmps527, "vdd-s1"), + RPMH_VREG("smps2", SMPS, 2, &pmic5_ftsmps527, "vdd-s2"), + RPMH_VREG("smps3", SMPS, 3, &pmic5_ftsmps527, "vdd-s3"), + RPMH_VREG("smps4", SMPS, 4, &pmic5_ftsmps527, "vdd-s4"), + RPMH_VREG("smps5", SMPS, 5, &pmic5_ftsmps527, "vdd-s5"), + RPMH_VREG("smps6", SMPS, 6, &pmic5_ftsmps527, "vdd-s6"), + RPMH_VREG("smps7", SMPS, 7, &pmic5_ftsmps527, "vdd-s7"), + RPMH_VREG("smps8", SMPS, 8, &pmic5_ftsmps527, "vdd-s8"), + RPMH_VREG("smps9", SMPS, 9, &pmic5_ftsmps527, "vdd-s9"), + RPMH_VREG("ldo1", LDO, 1, &pmic5_nldo515, "vdd-s9"), + RPMH_VREG("ldo2", LDO, 2, &pmic5_nldo515, "vdd-l2-l3"), + RPMH_VREG("ldo3", LDO, 3, &pmic5_nldo515, "vdd-l2-l3"), + RPMH_VREG("ldo4", LDO, 4, &pmic5_nldo515, "vdd-s9"), + RPMH_VREG("ldo5", LDO, 5, &pmic5_nldo515, "vdd-s9"), + RPMH_VREG("ldo6", LDO, 6, &pmic5_nldo515, "vdd-l6-l7"), + RPMH_VREG("ldo7", LDO, 7, &pmic5_nldo515, "vdd-l6-l7"), + RPMH_VREG("ldo8", LDO, 8, &pmic5_pldo515_mv, "vdd-l8-l9"), + RPMH_VREG("ldo9", LDO, 9, &pmic5_pldo, "vdd-l8-l9"), {} }; static const struct rpmh_vreg_init_data pm8350_vreg_data[] = { - RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps510, "vdd-s1"), - RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps510, "vdd-s2"), - RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps510, "vdd-s3"), - RPMH_VREG("smps4", "smp%s4", &pmic5_ftsmps510, "vdd-s4"), - RPMH_VREG("smps5", "smp%s5", &pmic5_ftsmps510, "vdd-s5"), - RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps510, "vdd-s6"), - RPMH_VREG("smps7", "smp%s7", &pmic5_ftsmps510, "vdd-s7"), - RPMH_VREG("smps8", "smp%s8", &pmic5_ftsmps510, "vdd-s8"), - RPMH_VREG("smps9", "smp%s9", &pmic5_ftsmps510, "vdd-s9"), - RPMH_VREG("smps10", "smp%s10", &pmic5_hfsmps510, "vdd-s10"), - RPMH_VREG("smps11", "smp%s11", &pmic5_hfsmps510, "vdd-s11"), - RPMH_VREG("smps12", "smp%s12", &pmic5_hfsmps510, "vdd-s12"), - RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo, "vdd-l1-l4"), - RPMH_VREG("ldo2", "ldo%s2", &pmic5_pldo, "vdd-l2-l7"), - RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo, "vdd-l3-l5"), - RPMH_VREG("ldo4", "ldo%s4", &pmic5_nldo, "vdd-l1-l4"), - RPMH_VREG("ldo5", "ldo%s5", &pmic5_nldo, "vdd-l3-l5"), - RPMH_VREG("ldo6", "ldo%s6", &pmic5_nldo, "vdd-l6-l9-l10"), - RPMH_VREG("ldo7", "ldo%s7", &pmic5_pldo, "vdd-l2-l7"), - RPMH_VREG("ldo8", "ldo%s8", &pmic5_nldo, "vdd-l8"), - RPMH_VREG("ldo9", "ldo%s9", &pmic5_nldo, "vdd-l6-l9-l10"), - RPMH_VREG("ldo10", "ldo%s10", &pmic5_nldo, "vdd-l6-l9-l10"), + RPMH_VREG("smps1", SMPS, 1, &pmic5_ftsmps510, "vdd-s1"), + RPMH_VREG("smps2", SMPS, 2, &pmic5_ftsmps510, "vdd-s2"), + RPMH_VREG("smps3", SMPS, 3, &pmic5_ftsmps510, "vdd-s3"), + RPMH_VREG("smps4", SMPS, 4, &pmic5_ftsmps510, "vdd-s4"), + RPMH_VREG("smps5", SMPS, 5, &pmic5_ftsmps510, "vdd-s5"), + RPMH_VREG("smps6", SMPS, 6, &pmic5_ftsmps510, "vdd-s6"), + RPMH_VREG("smps7", SMPS, 7, &pmic5_ftsmps510, "vdd-s7"), + RPMH_VREG("smps8", SMPS, 8, &pmic5_ftsmps510, "vdd-s8"), + RPMH_VREG("smps9", SMPS, 9, &pmic5_ftsmps510, "vdd-s9"), + RPMH_VREG("smps10", SMPS, 10, &pmic5_hfsmps510, "vdd-s10"), + RPMH_VREG("smps11", SMPS, 11, &pmic5_hfsmps510, "vdd-s11"), + RPMH_VREG("smps12", SMPS, 12, &pmic5_hfsmps510, "vdd-s12"), + RPMH_VREG("ldo1", LDO, 1, &pmic5_nldo, "vdd-l1-l4"), + RPMH_VREG("ldo2", LDO, 2, &pmic5_pldo, "vdd-l2-l7"), + RPMH_VREG("ldo3", LDO, 3, &pmic5_nldo, "vdd-l3-l5"), + RPMH_VREG("ldo4", LDO, 4, &pmic5_nldo, "vdd-l1-l4"), + RPMH_VREG("ldo5", LDO, 5, &pmic5_nldo, "vdd-l3-l5"), + RPMH_VREG("ldo6", LDO, 6, &pmic5_nldo, "vdd-l6-l9-l10"), + RPMH_VREG("ldo7", LDO, 7, &pmic5_pldo, "vdd-l2-l7"), + RPMH_VREG("ldo8", LDO, 8, &pmic5_nldo, "vdd-l8"), + RPMH_VREG("ldo9", LDO, 9, &pmic5_nldo, "vdd-l6-l9-l10"), + RPMH_VREG("ldo10", LDO, 10, &pmic5_nldo, "vdd-l6-l9-l10"), {} }; static const struct rpmh_vreg_init_data pm8350c_vreg_data[] = { - RPMH_VREG("smps1", "smp%s1", &pmic5_hfsmps515, "vdd-s1"), - RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps510, "vdd-s2"), - RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps510, "vdd-s3"), - RPMH_VREG("smps4", "smp%s4", &pmic5_ftsmps510, "vdd-s4"), - RPMH_VREG("smps5", "smp%s5", &pmic5_ftsmps510, "vdd-s5"), - RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps510, "vdd-s6"), - RPMH_VREG("smps7", "smp%s7", &pmic5_ftsmps510, "vdd-s7"), - RPMH_VREG("smps8", "smp%s8", &pmic5_ftsmps510, "vdd-s8"), - RPMH_VREG("smps9", "smp%s9", &pmic5_ftsmps510, "vdd-s9"), - RPMH_VREG("smps10", "smp%s10", &pmic5_ftsmps510, "vdd-s10"), - RPMH_VREG("ldo1", "ldo%s1", &pmic5_pldo_lv, "vdd-l1-l12"), - RPMH_VREG("ldo2", "ldo%s2", &pmic5_pldo_lv, "vdd-l2-l8"), - RPMH_VREG("ldo3", "ldo%s3", &pmic5_pldo, "vdd-l3-l4-l5-l7-l13"), - RPMH_VREG("ldo4", "ldo%s4", &pmic5_pldo, "vdd-l3-l4-l5-l7-l13"), - RPMH_VREG("ldo5", "ldo%s5", &pmic5_pldo, "vdd-l3-l4-l5-l7-l13"), - RPMH_VREG("ldo6", "ldo%s6", &pmic5_pldo, "vdd-l6-l9-l11"), - RPMH_VREG("ldo7", "ldo%s7", &pmic5_pldo, "vdd-l3-l4-l5-l7-l13"), - RPMH_VREG("ldo8", "ldo%s8", &pmic5_pldo_lv, "vdd-l2-l8"), - RPMH_VREG("ldo9", "ldo%s9", &pmic5_pldo, "vdd-l6-l9-l11"), - RPMH_VREG("ldo10", "ldo%s10", &pmic5_nldo, "vdd-l10"), - RPMH_VREG("ldo11", "ldo%s11", &pmic5_pldo, "vdd-l6-l9-l11"), - RPMH_VREG("ldo12", "ldo%s12", &pmic5_pldo_lv, "vdd-l1-l12"), - RPMH_VREG("ldo13", "ldo%s13", &pmic5_pldo, "vdd-l3-l4-l5-l7-l13"), - RPMH_VREG("bob", "bob%s1", &pmic5_bob, "vdd-bob"), + RPMH_VREG("smps1", SMPS, 1, &pmic5_hfsmps515, "vdd-s1"), + RPMH_VREG("smps2", SMPS, 2, &pmic5_ftsmps510, "vdd-s2"), + RPMH_VREG("smps3", SMPS, 3, &pmic5_ftsmps510, "vdd-s3"), + RPMH_VREG("smps4", SMPS, 4, &pmic5_ftsmps510, "vdd-s4"), + RPMH_VREG("smps5", SMPS, 5, &pmic5_ftsmps510, "vdd-s5"), + RPMH_VREG("smps6", SMPS, 6, &pmic5_ftsmps510, "vdd-s6"), + RPMH_VREG("smps7", SMPS, 7, &pmic5_ftsmps510, "vdd-s7"), + RPMH_VREG("smps8", SMPS, 8, &pmic5_ftsmps510, "vdd-s8"), + RPMH_VREG("smps9", SMPS, 9, &pmic5_ftsmps510, "vdd-s9"), + RPMH_VREG("smps10", SMPS, 10, &pmic5_ftsmps510, "vdd-s10"), + RPMH_VREG("ldo1", LDO, 1, &pmic5_pldo_lv, "vdd-l1-l12"), + RPMH_VREG("ldo2", LDO, 2, &pmic5_pldo_lv, "vdd-l2-l8"), + RPMH_VREG("ldo3", LDO, 3, &pmic5_pldo, "vdd-l3-l4-l5-l7-l13"), + RPMH_VREG("ldo4", LDO, 4, &pmic5_pldo, "vdd-l3-l4-l5-l7-l13"), + RPMH_VREG("ldo5", LDO, 5, &pmic5_pldo, "vdd-l3-l4-l5-l7-l13"), + RPMH_VREG("ldo6", LDO, 6, &pmic5_pldo, "vdd-l6-l9-l11"), + RPMH_VREG("ldo7", LDO, 7, &pmic5_pldo, "vdd-l3-l4-l5-l7-l13"), + RPMH_VREG("ldo8", LDO, 8, &pmic5_pldo_lv, "vdd-l2-l8"), + RPMH_VREG("ldo9", LDO, 9, &pmic5_pldo, "vdd-l6-l9-l11"), + RPMH_VREG("ldo10", LDO, 10, &pmic5_nldo, "vdd-l10"), + RPMH_VREG("ldo11", LDO, 11, &pmic5_pldo, "vdd-l6-l9-l11"), + RPMH_VREG("ldo12", LDO, 12, &pmic5_pldo_lv, "vdd-l1-l12"), + RPMH_VREG("ldo13", LDO, 13, &pmic5_pldo, "vdd-l3-l4-l5-l7-l13"), + RPMH_VREG("bob", BOB, 1, &pmic5_bob, "vdd-bob"), {} }; static const struct rpmh_vreg_init_data pm8450_vreg_data[] = { - RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps520, "vdd-s1"), - RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps520, "vdd-s2"), - RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps520, "vdd-s3"), - RPMH_VREG("smps4", "smp%s4", &pmic5_ftsmps520, "vdd-s4"), - RPMH_VREG("smps5", "smp%s5", &pmic5_ftsmps520, "vdd-s5"), - RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps520, "vdd-s6"), - RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo, "vdd-l1"), - RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo, "vdd-l2"), - RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo, "vdd-l3"), - RPMH_VREG("ldo4", "ldo%s4", &pmic5_pldo_lv, "vdd-l4"), + RPMH_VREG("smps1", SMPS, 1, &pmic5_ftsmps520, "vdd-s1"), + RPMH_VREG("smps2", SMPS, 2, &pmic5_ftsmps520, "vdd-s2"), + RPMH_VREG("smps3", SMPS, 3, &pmic5_ftsmps520, "vdd-s3"), + RPMH_VREG("smps4", SMPS, 4, &pmic5_ftsmps520, "vdd-s4"), + RPMH_VREG("smps5", SMPS, 5, &pmic5_ftsmps520, "vdd-s5"), + RPMH_VREG("smps6", SMPS, 6, &pmic5_ftsmps520, "vdd-s6"), + RPMH_VREG("ldo1", LDO, 1, &pmic5_nldo, "vdd-l1"), + RPMH_VREG("ldo2", LDO, 2, &pmic5_nldo, "vdd-l2"), + RPMH_VREG("ldo3", LDO, 3, &pmic5_nldo, "vdd-l3"), + RPMH_VREG("ldo4", LDO, 4, &pmic5_pldo_lv, "vdd-l4"), {} }; static const struct rpmh_vreg_init_data pm8550_vreg_data[] = { - RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo515, "vdd-l1-l4-l10"), - RPMH_VREG("ldo2", "ldo%s2", &pmic5_pldo, "vdd-l2-l13-l14"), - RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo515, "vdd-l3"), - RPMH_VREG("ldo4", "ldo%s4", &pmic5_nldo515, "vdd-l1-l4-l10"), - RPMH_VREG("ldo5", "ldo%s5", &pmic5_pldo, "vdd-l5-l16"), - RPMH_VREG("ldo6", "ldo%s6", &pmic5_pldo, "vdd-l6-l7"), - RPMH_VREG("ldo7", "ldo%s7", &pmic5_pldo, "vdd-l6-l7"), - RPMH_VREG("ldo8", "ldo%s8", &pmic5_pldo, "vdd-l8-l9"), - RPMH_VREG("ldo9", "ldo%s9", &pmic5_pldo, "vdd-l8-l9"), - RPMH_VREG("ldo10", "ldo%s10", &pmic5_nldo515, "vdd-l1-l4-l10"), - RPMH_VREG("ldo11", "ldo%s11", &pmic5_nldo515, "vdd-l11"), - RPMH_VREG("ldo12", "ldo%s12", &pmic5_nldo515, "vdd-l12"), - RPMH_VREG("ldo13", "ldo%s13", &pmic5_pldo, "vdd-l2-l13-l14"), - RPMH_VREG("ldo14", "ldo%s14", &pmic5_pldo, "vdd-l2-l13-l14"), - RPMH_VREG("ldo15", "ldo%s15", &pmic5_nldo515, "vdd-l15"), - RPMH_VREG("ldo16", "ldo%s16", &pmic5_pldo, "vdd-l5-l16"), - RPMH_VREG("ldo17", "ldo%s17", &pmic5_pldo, "vdd-l17"), - RPMH_VREG("bob1", "bob%s1", &pmic5_bob, "vdd-bob1"), - RPMH_VREG("bob2", "bob%s2", &pmic5_bob, "vdd-bob2"), + RPMH_VREG("ldo1", LDO, 1, &pmic5_nldo515, "vdd-l1-l4-l10"), + RPMH_VREG("ldo2", LDO, 2, &pmic5_pldo, "vdd-l2-l13-l14"), + RPMH_VREG("ldo3", LDO, 3, &pmic5_nldo515, "vdd-l3"), + RPMH_VREG("ldo4", LDO, 4, &pmic5_nldo515, "vdd-l1-l4-l10"), + RPMH_VREG("ldo5", LDO, 5, &pmic5_pldo, "vdd-l5-l16"), + RPMH_VREG("ldo6", LDO, 6, &pmic5_pldo, "vdd-l6-l7"), + RPMH_VREG("ldo7", LDO, 7, &pmic5_pldo, "vdd-l6-l7"), + RPMH_VREG("ldo8", LDO, 8, &pmic5_pldo, "vdd-l8-l9"), + RPMH_VREG("ldo9", LDO, 9, &pmic5_pldo, "vdd-l8-l9"), + RPMH_VREG("ldo10", LDO, 10, &pmic5_nldo515, "vdd-l1-l4-l10"), + RPMH_VREG("ldo11", LDO, 11, &pmic5_nldo515, "vdd-l11"), + RPMH_VREG("ldo12", LDO, 12, &pmic5_nldo515, "vdd-l12"), + RPMH_VREG("ldo13", LDO, 13, &pmic5_pldo, "vdd-l2-l13-l14"), + RPMH_VREG("ldo14", LDO, 14, &pmic5_pldo, "vdd-l2-l13-l14"), + RPMH_VREG("ldo15", LDO, 15, &pmic5_nldo515, "vdd-l15"), + RPMH_VREG("ldo16", LDO, 16, &pmic5_pldo, "vdd-l5-l16"), + RPMH_VREG("ldo17", LDO, 17, &pmic5_pldo, "vdd-l17"), + RPMH_VREG("bob1", BOB, 1, &pmic5_bob, "vdd-bob1"), + RPMH_VREG("bob2", BOB, 2, &pmic5_bob, "vdd-bob2"), {} }; static const struct rpmh_vreg_init_data pm8550vs_vreg_data[] = { - RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps525, "vdd-s1"), - RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps525, "vdd-s2"), - RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps525, "vdd-s3"), - RPMH_VREG("smps4", "smp%s4", &pmic5_ftsmps525, "vdd-s4"), - RPMH_VREG("smps5", "smp%s5", &pmic5_ftsmps525, "vdd-s5"), - RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps525, "vdd-s6"), - RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo515, "vdd-l1"), - RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo515, "vdd-l2"), - RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo515, "vdd-l3"), + RPMH_VREG("smps1", SMPS, 1, &pmic5_ftsmps525, "vdd-s1"), + RPMH_VREG("smps2", SMPS, 2, &pmic5_ftsmps525, "vdd-s2"), + RPMH_VREG("smps3", SMPS, 3, &pmic5_ftsmps525, "vdd-s3"), + RPMH_VREG("smps4", SMPS, 4, &pmic5_ftsmps525, "vdd-s4"), + RPMH_VREG("smps5", SMPS, 5, &pmic5_ftsmps525, "vdd-s5"), + RPMH_VREG("smps6", SMPS, 6, &pmic5_ftsmps525, "vdd-s6"), + RPMH_VREG("ldo1", LDO, 1, &pmic5_nldo515, "vdd-l1"), + RPMH_VREG("ldo2", LDO, 2, &pmic5_nldo515, "vdd-l2"), + RPMH_VREG("ldo3", LDO, 3, &pmic5_nldo515, "vdd-l3"), {} }; static const struct rpmh_vreg_init_data pm8550ve_vreg_data[] = { - RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps525, "vdd-s1"), - RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps525, "vdd-s2"), - RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps525, "vdd-s3"), - RPMH_VREG("smps4", "smp%s4", &pmic5_ftsmps525, "vdd-s4"), - RPMH_VREG("smps5", "smp%s5", &pmic5_ftsmps525, "vdd-s5"), - RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps525, "vdd-s6"), - RPMH_VREG("smps7", "smp%s7", &pmic5_ftsmps525, "vdd-s7"), - RPMH_VREG("smps8", "smp%s8", &pmic5_ftsmps525, "vdd-s8"), - RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo515, "vdd-l1"), - RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo515, "vdd-l2"), - RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo515, "vdd-l3"), + RPMH_VREG("smps1", SMPS, 1, &pmic5_ftsmps525, "vdd-s1"), + RPMH_VREG("smps2", SMPS, 2, &pmic5_ftsmps525, "vdd-s2"), + RPMH_VREG("smps3", SMPS, 3, &pmic5_ftsmps525, "vdd-s3"), + RPMH_VREG("smps4", SMPS, 4, &pmic5_ftsmps525, "vdd-s4"), + RPMH_VREG("smps5", SMPS, 5, &pmic5_ftsmps525, "vdd-s5"), + RPMH_VREG("smps6", SMPS, 6, &pmic5_ftsmps525, "vdd-s6"), + RPMH_VREG("smps7", SMPS, 7, &pmic5_ftsmps525, "vdd-s7"), + RPMH_VREG("smps8", SMPS, 8, &pmic5_ftsmps525, "vdd-s8"), + RPMH_VREG("ldo1", LDO, 1, &pmic5_nldo515, "vdd-l1"), + RPMH_VREG("ldo2", LDO, 2, &pmic5_nldo515, "vdd-l2"), + RPMH_VREG("ldo3", LDO, 3, &pmic5_nldo515, "vdd-l3"), {} }; static const struct rpmh_vreg_init_data pmc8380_vreg_data[] = { - RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps525, "vdd-s1"), - RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps525, "vdd-s2"), - RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps525, "vdd-s3"), - RPMH_VREG("smps4", "smp%s4", &pmic5_ftsmps525, "vdd-s4"), - RPMH_VREG("smps5", "smp%s5", &pmic5_ftsmps525, "vdd-s5"), - RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps525, "vdd-s6"), - RPMH_VREG("smps7", "smp%s7", &pmic5_ftsmps525, "vdd-s7"), - RPMH_VREG("smps8", "smp%s8", &pmic5_ftsmps525, "vdd-s8"), - RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo515, "vdd-l1"), - RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo515, "vdd-l2"), - RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo515, "vdd-l3"), + RPMH_VREG("smps1", SMPS, 1, &pmic5_ftsmps525, "vdd-s1"), + RPMH_VREG("smps2", SMPS, 2, &pmic5_ftsmps525, "vdd-s2"), + RPMH_VREG("smps3", SMPS, 3, &pmic5_ftsmps525, "vdd-s3"), + RPMH_VREG("smps4", SMPS, 4, &pmic5_ftsmps525, "vdd-s4"), + RPMH_VREG("smps5", SMPS, 5, &pmic5_ftsmps525, "vdd-s5"), + RPMH_VREG("smps6", SMPS, 6, &pmic5_ftsmps525, "vdd-s6"), + RPMH_VREG("smps7", SMPS, 7, &pmic5_ftsmps525, "vdd-s7"), + RPMH_VREG("smps8", SMPS, 8, &pmic5_ftsmps525, "vdd-s8"), + RPMH_VREG("ldo1", LDO, 1, &pmic5_nldo515, "vdd-l1"), + RPMH_VREG("ldo2", LDO, 2, &pmic5_nldo515, "vdd-l2"), + RPMH_VREG("ldo3", LDO, 3, &pmic5_nldo515, "vdd-l3"), {} }; static const struct rpmh_vreg_init_data pm8009_vreg_data[] = { - RPMH_VREG("smps1", "smp%s1", &pmic5_hfsmps510, "vdd-s1"), - RPMH_VREG("smps2", "smp%s2", &pmic5_hfsmps515, "vdd-s2"), - RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo, "vdd-l1"), - RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo, "vdd-l2"), - RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo, "vdd-l3"), - RPMH_VREG("ldo4", "ldo%s4", &pmic5_nldo, "vdd-l4"), - RPMH_VREG("ldo5", "ldo%s5", &pmic5_pldo, "vdd-l5-l6"), - RPMH_VREG("ldo6", "ldo%s6", &pmic5_pldo, "vdd-l5-l6"), - RPMH_VREG("ldo7", "ldo%s7", &pmic5_pldo_lv, "vdd-l7"), + RPMH_VREG("smps1", SMPS, 1, &pmic5_hfsmps510, "vdd-s1"), + RPMH_VREG("smps2", SMPS, 2, &pmic5_hfsmps515, "vdd-s2"), + RPMH_VREG("ldo1", LDO, 1, &pmic5_nldo, "vdd-l1"), + RPMH_VREG("ldo2", LDO, 2, &pmic5_nldo, "vdd-l2"), + RPMH_VREG("ldo3", LDO, 3, &pmic5_nldo, "vdd-l3"), + RPMH_VREG("ldo4", LDO, 4, &pmic5_nldo, "vdd-l4"), + RPMH_VREG("ldo5", LDO, 5, &pmic5_pldo, "vdd-l5-l6"), + RPMH_VREG("ldo6", LDO, 6, &pmic5_pldo, "vdd-l5-l6"), + RPMH_VREG("ldo7", LDO, 7, &pmic5_pldo_lv, "vdd-l7"), {} }; static const struct rpmh_vreg_init_data pm8009_1_vreg_data[] = { - RPMH_VREG("smps1", "smp%s1", &pmic5_hfsmps510, "vdd-s1"), - RPMH_VREG("smps2", "smp%s2", &pmic5_hfsmps515_1, "vdd-s2"), - RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo, "vdd-l1"), - RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo, "vdd-l2"), - RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo, "vdd-l3"), - RPMH_VREG("ldo4", "ldo%s4", &pmic5_nldo, "vdd-l4"), - RPMH_VREG("ldo5", "ldo%s5", &pmic5_pldo, "vdd-l5-l6"), - RPMH_VREG("ldo6", "ldo%s6", &pmic5_pldo, "vdd-l5-l6"), - RPMH_VREG("ldo7", "ldo%s7", &pmic5_pldo_lv, "vdd-l7"), + RPMH_VREG("smps1", SMPS, 1, &pmic5_hfsmps510, "vdd-s1"), + RPMH_VREG("smps2", SMPS, 2, &pmic5_hfsmps515_1, "vdd-s2"), + RPMH_VREG("ldo1", LDO, 1, &pmic5_nldo, "vdd-l1"), + RPMH_VREG("ldo2", LDO, 2, &pmic5_nldo, "vdd-l2"), + RPMH_VREG("ldo3", LDO, 3, &pmic5_nldo, "vdd-l3"), + RPMH_VREG("ldo4", LDO, 4, &pmic5_nldo, "vdd-l4"), + RPMH_VREG("ldo5", LDO, 5, &pmic5_pldo, "vdd-l5-l6"), + RPMH_VREG("ldo6", LDO, 6, &pmic5_pldo, "vdd-l5-l6"), + RPMH_VREG("ldo7", LDO, 7, &pmic5_pldo_lv, "vdd-l7"), {} }; static const struct rpmh_vreg_init_data pm8010_vreg_data[] = { - RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo502, "vdd-l1-l2"), - RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo502, "vdd-l1-l2"), - RPMH_VREG("ldo3", "ldo%s3", &pmic5_pldo502ln, "vdd-l3-l4"), - RPMH_VREG("ldo4", "ldo%s4", &pmic5_pldo502ln, "vdd-l3-l4"), - RPMH_VREG("ldo5", "ldo%s5", &pmic5_pldo502, "vdd-l5"), - RPMH_VREG("ldo6", "ldo%s6", &pmic5_pldo502ln, "vdd-l6"), - RPMH_VREG("ldo7", "ldo%s7", &pmic5_pldo502, "vdd-l7"), + RPMH_VREG("ldo1", LDO, 1, &pmic5_nldo502, "vdd-l1-l2"), + RPMH_VREG("ldo2", LDO, 2, &pmic5_nldo502, "vdd-l1-l2"), + RPMH_VREG("ldo3", LDO, 3, &pmic5_pldo502ln, "vdd-l3-l4"), + RPMH_VREG("ldo4", LDO, 4, &pmic5_pldo502ln, "vdd-l3-l4"), + RPMH_VREG("ldo5", LDO, 5, &pmic5_pldo502, "vdd-l5"), + RPMH_VREG("ldo6", LDO, 6, &pmic5_pldo502ln, "vdd-l6"), + RPMH_VREG("ldo7", LDO, 7, &pmic5_pldo502, "vdd-l7"), }; static const struct rpmh_vreg_init_data pm6150_vreg_data[] = { - RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps510, "vdd-s1"), - RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps510, "vdd-s2"), - RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps510, "vdd-s3"), - RPMH_VREG("smps4", "smp%s4", &pmic5_hfsmps510, "vdd-s4"), - RPMH_VREG("smps5", "smp%s5", &pmic5_hfsmps510, "vdd-s5"), - RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo, "vdd-l1"), - RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo, "vdd-l2-l3"), - RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo, "vdd-l2-l3"), - RPMH_VREG("ldo4", "ldo%s4", &pmic5_nldo, "vdd-l4-l7-l8"), - RPMH_VREG("ldo5", "ldo%s5", &pmic5_pldo, "vdd-l5-l16-l17-l18-l19"), - RPMH_VREG("ldo6", "ldo%s6", &pmic5_nldo, "vdd-l6"), - RPMH_VREG("ldo7", "ldo%s7", &pmic5_nldo, "vdd-l4-l7-l8"), - RPMH_VREG("ldo8", "ldo%s8", &pmic5_nldo, "vdd-l4-l7-l8"), - RPMH_VREG("ldo9", "ldo%s9", &pmic5_nldo, "vdd-l9"), - RPMH_VREG("ldo10", "ldo%s10", &pmic5_pldo_lv, "vdd-l10-l14-l15"), - RPMH_VREG("ldo11", "ldo%s11", &pmic5_pldo_lv, "vdd-l11-l12-l13"), - RPMH_VREG("ldo12", "ldo%s12", &pmic5_pldo_lv, "vdd-l11-l12-l13"), - RPMH_VREG("ldo13", "ldo%s13", &pmic5_pldo_lv, "vdd-l11-l12-l13"), - RPMH_VREG("ldo14", "ldo%s14", &pmic5_pldo_lv, "vdd-l10-l14-l15"), - RPMH_VREG("ldo15", "ldo%s15", &pmic5_pldo_lv, "vdd-l10-l14-l15"), - RPMH_VREG("ldo16", "ldo%s16", &pmic5_pldo, "vdd-l5-l16-l17-l18-l19"), - RPMH_VREG("ldo17", "ldo%s17", &pmic5_pldo, "vdd-l5-l16-l17-l18-l19"), - RPMH_VREG("ldo18", "ldo%s18", &pmic5_pldo, "vdd-l5-l16-l17-l18-l19"), - RPMH_VREG("ldo19", "ldo%s19", &pmic5_pldo, "vdd-l5-l16-l17-l18-l19"), + RPMH_VREG("smps1", SMPS, 1, &pmic5_ftsmps510, "vdd-s1"), + RPMH_VREG("smps2", SMPS, 2, &pmic5_ftsmps510, "vdd-s2"), + RPMH_VREG("smps3", SMPS, 3, &pmic5_ftsmps510, "vdd-s3"), + RPMH_VREG("smps4", SMPS, 4, &pmic5_hfsmps510, "vdd-s4"), + RPMH_VREG("smps5", SMPS, 5, &pmic5_hfsmps510, "vdd-s5"), + RPMH_VREG("ldo1", LDO, 1, &pmic5_nldo, "vdd-l1"), + RPMH_VREG("ldo2", LDO, 2, &pmic5_nldo, "vdd-l2-l3"), + RPMH_VREG("ldo3", LDO, 3, &pmic5_nldo, "vdd-l2-l3"), + RPMH_VREG("ldo4", LDO, 4, &pmic5_nldo, "vdd-l4-l7-l8"), + RPMH_VREG("ldo5", LDO, 5, &pmic5_pldo, "vdd-l5-l16-l17-l18-l19"), + RPMH_VREG("ldo6", LDO, 6, &pmic5_nldo, "vdd-l6"), + RPMH_VREG("ldo7", LDO, 7, &pmic5_nldo, "vdd-l4-l7-l8"), + RPMH_VREG("ldo8", LDO, 8, &pmic5_nldo, "vdd-l4-l7-l8"), + RPMH_VREG("ldo9", LDO, 9, &pmic5_nldo, "vdd-l9"), + RPMH_VREG("ldo10", LDO, 10, &pmic5_pldo_lv, "vdd-l10-l14-l15"), + RPMH_VREG("ldo11", LDO, 11, &pmic5_pldo_lv, "vdd-l11-l12-l13"), + RPMH_VREG("ldo12", LDO, 12, &pmic5_pldo_lv, "vdd-l11-l12-l13"), + RPMH_VREG("ldo13", LDO, 13, &pmic5_pldo_lv, "vdd-l11-l12-l13"), + RPMH_VREG("ldo14", LDO, 14, &pmic5_pldo_lv, "vdd-l10-l14-l15"), + RPMH_VREG("ldo15", LDO, 15, &pmic5_pldo_lv, "vdd-l10-l14-l15"), + RPMH_VREG("ldo16", LDO, 16, &pmic5_pldo, "vdd-l5-l16-l17-l18-l19"), + RPMH_VREG("ldo17", LDO, 17, &pmic5_pldo, "vdd-l5-l16-l17-l18-l19"), + RPMH_VREG("ldo18", LDO, 18, &pmic5_pldo, "vdd-l5-l16-l17-l18-l19"), + RPMH_VREG("ldo19", LDO, 19, &pmic5_pldo, "vdd-l5-l16-l17-l18-l19"), {} }; static const struct rpmh_vreg_init_data pm6150l_vreg_data[] = { - RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps510, "vdd-s1"), - RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps510, "vdd-s2"), - RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps510, "vdd-s3"), - RPMH_VREG("smps4", "smp%s4", &pmic5_ftsmps510, "vdd-s4"), - RPMH_VREG("smps5", "smp%s5", &pmic5_ftsmps510, "vdd-s5"), - RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps510, "vdd-s6"), - RPMH_VREG("smps7", "smp%s7", &pmic5_ftsmps510, "vdd-s7"), - RPMH_VREG("smps8", "smp%s8", &pmic5_hfsmps510, "vdd-s8"), - RPMH_VREG("ldo1", "ldo%s1", &pmic5_pldo_lv, "vdd-l1-l8"), - RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo, "vdd-l2-l3"), - RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo, "vdd-l2-l3"), - RPMH_VREG("ldo4", "ldo%s4", &pmic5_pldo, "vdd-l4-l5-l6"), - RPMH_VREG("ldo5", "ldo%s5", &pmic5_pldo, "vdd-l4-l5-l6"), - RPMH_VREG("ldo6", "ldo%s6", &pmic5_pldo, "vdd-l4-l5-l6"), - RPMH_VREG("ldo7", "ldo%s7", &pmic5_pldo, "vdd-l7-l11"), - RPMH_VREG("ldo8", "ldo%s8", &pmic5_pldo, "vdd-l1-l8"), - RPMH_VREG("ldo9", "ldo%s9", &pmic5_pldo, "vdd-l9-l10"), - RPMH_VREG("ldo10", "ldo%s10", &pmic5_pldo, "vdd-l9-l10"), - RPMH_VREG("ldo11", "ldo%s11", &pmic5_pldo, "vdd-l7-l11"), - RPMH_VREG("bob", "bob%s1", &pmic5_bob, "vdd-bob"), + RPMH_VREG("smps1", SMPS, 1, &pmic5_ftsmps510, "vdd-s1"), + RPMH_VREG("smps2", SMPS, 2, &pmic5_ftsmps510, "vdd-s2"), + RPMH_VREG("smps3", SMPS, 3, &pmic5_ftsmps510, "vdd-s3"), + RPMH_VREG("smps4", SMPS, 4, &pmic5_ftsmps510, "vdd-s4"), + RPMH_VREG("smps5", SMPS, 5, &pmic5_ftsmps510, "vdd-s5"), + RPMH_VREG("smps6", SMPS, 6, &pmic5_ftsmps510, "vdd-s6"), + RPMH_VREG("smps7", SMPS, 7, &pmic5_ftsmps510, "vdd-s7"), + RPMH_VREG("smps8", SMPS, 8, &pmic5_hfsmps510, "vdd-s8"), + RPMH_VREG("ldo1", LDO, 1, &pmic5_pldo_lv, "vdd-l1-l8"), + RPMH_VREG("ldo2", LDO, 2, &pmic5_nldo, "vdd-l2-l3"), + RPMH_VREG("ldo3", LDO, 3, &pmic5_nldo, "vdd-l2-l3"), + RPMH_VREG("ldo4", LDO, 4, &pmic5_pldo, "vdd-l4-l5-l6"), + RPMH_VREG("ldo5", LDO, 5, &pmic5_pldo, "vdd-l4-l5-l6"), + RPMH_VREG("ldo6", LDO, 6, &pmic5_pldo, "vdd-l4-l5-l6"), + RPMH_VREG("ldo7", LDO, 7, &pmic5_pldo, "vdd-l7-l11"), + RPMH_VREG("ldo8", LDO, 8, &pmic5_pldo, "vdd-l1-l8"), + RPMH_VREG("ldo9", LDO, 9, &pmic5_pldo, "vdd-l9-l10"), + RPMH_VREG("ldo10", LDO, 10, &pmic5_pldo, "vdd-l9-l10"), + RPMH_VREG("ldo11", LDO, 11, &pmic5_pldo, "vdd-l7-l11"), + RPMH_VREG("bob", BOB, 1, &pmic5_bob, "vdd-bob"), {} }; static const struct rpmh_vreg_init_data pm6350_vreg_data[] = { - RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps510, NULL), - RPMH_VREG("smps2", "smp%s2", &pmic5_hfsmps510, NULL), + RPMH_VREG("smps1", SMPS, 1, &pmic5_ftsmps510, NULL), + RPMH_VREG("smps2", SMPS, 2, &pmic5_hfsmps510, NULL), /* smps3 - smps5 not configured */ - RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo, NULL), - RPMH_VREG("ldo2", "ldo%s2", &pmic5_pldo, NULL), - RPMH_VREG("ldo3", "ldo%s3", &pmic5_pldo, NULL), - RPMH_VREG("ldo4", "ldo%s4", &pmic5_nldo, NULL), - RPMH_VREG("ldo5", "ldo%s5", &pmic5_pldo, NULL), - RPMH_VREG("ldo6", "ldo%s6", &pmic5_pldo, NULL), - RPMH_VREG("ldo7", "ldo%s7", &pmic5_pldo, NULL), - RPMH_VREG("ldo8", "ldo%s8", &pmic5_pldo, NULL), - RPMH_VREG("ldo9", "ldo%s9", &pmic5_pldo, NULL), - RPMH_VREG("ldo10", "ldo%s10", &pmic5_pldo, NULL), - RPMH_VREG("ldo11", "ldo%s11", &pmic5_pldo, NULL), - RPMH_VREG("ldo12", "ldo%s12", &pmic5_pldo, NULL), - RPMH_VREG("ldo13", "ldo%s13", &pmic5_nldo, NULL), - RPMH_VREG("ldo14", "ldo%s14", &pmic5_pldo, NULL), - RPMH_VREG("ldo15", "ldo%s15", &pmic5_nldo, NULL), - RPMH_VREG("ldo16", "ldo%s16", &pmic5_nldo, NULL), + RPMH_VREG("ldo1", LDO, 1, &pmic5_nldo, NULL), + RPMH_VREG("ldo2", LDO, 2, &pmic5_pldo, NULL), + RPMH_VREG("ldo3", LDO, 3, &pmic5_pldo, NULL), + RPMH_VREG("ldo4", LDO, 4, &pmic5_nldo, NULL), + RPMH_VREG("ldo5", LDO, 5, &pmic5_pldo, NULL), + RPMH_VREG("ldo6", LDO, 6, &pmic5_pldo, NULL), + RPMH_VREG("ldo7", LDO, 7, &pmic5_pldo, NULL), + RPMH_VREG("ldo8", LDO, 8, &pmic5_pldo, NULL), + RPMH_VREG("ldo9", LDO, 9, &pmic5_pldo, NULL), + RPMH_VREG("ldo10", LDO, 10, &pmic5_pldo, NULL), + RPMH_VREG("ldo11", LDO, 11, &pmic5_pldo, NULL), + RPMH_VREG("ldo12", LDO, 12, &pmic5_pldo, NULL), + RPMH_VREG("ldo13", LDO, 13, &pmic5_nldo, NULL), + RPMH_VREG("ldo14", LDO, 14, &pmic5_pldo, NULL), + RPMH_VREG("ldo15", LDO, 15, &pmic5_nldo, NULL), + RPMH_VREG("ldo16", LDO, 16, &pmic5_nldo, NULL), /* ldo17 not configured */ - RPMH_VREG("ldo18", "ldo%s18", &pmic5_nldo, NULL), - RPMH_VREG("ldo19", "ldo%s19", &pmic5_nldo, NULL), - RPMH_VREG("ldo20", "ldo%s20", &pmic5_nldo, NULL), - RPMH_VREG("ldo21", "ldo%s21", &pmic5_nldo, NULL), - RPMH_VREG("ldo22", "ldo%s22", &pmic5_nldo, NULL), + RPMH_VREG("ldo18", LDO, 18, &pmic5_nldo, NULL), + RPMH_VREG("ldo19", LDO, 19, &pmic5_nldo, NULL), + RPMH_VREG("ldo20", LDO, 20, &pmic5_nldo, NULL), + RPMH_VREG("ldo21", LDO, 21, &pmic5_nldo, NULL), + RPMH_VREG("ldo22", LDO, 22, &pmic5_nldo, NULL), }; static const struct rpmh_vreg_init_data pmx55_vreg_data[] = { - RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps510, "vdd-s1"), - RPMH_VREG("smps2", "smp%s2", &pmic5_hfsmps510, "vdd-s2"), - RPMH_VREG("smps3", "smp%s3", &pmic5_hfsmps510, "vdd-s3"), - RPMH_VREG("smps4", "smp%s4", &pmic5_hfsmps510, "vdd-s4"), - RPMH_VREG("smps5", "smp%s5", &pmic5_hfsmps510, "vdd-s5"), - RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps510, "vdd-s6"), - RPMH_VREG("smps7", "smp%s7", &pmic5_hfsmps510, "vdd-s7"), - RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo, "vdd-l1-l2"), - RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo, "vdd-l1-l2"), - RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo, "vdd-l3-l9"), - RPMH_VREG("ldo4", "ldo%s4", &pmic5_nldo, "vdd-l4-l12"), - RPMH_VREG("ldo5", "ldo%s5", &pmic5_pldo, "vdd-l5-l6"), - RPMH_VREG("ldo6", "ldo%s6", &pmic5_pldo, "vdd-l5-l6"), - RPMH_VREG("ldo7", "ldo%s7", &pmic5_nldo, "vdd-l7-l8"), - RPMH_VREG("ldo8", "ldo%s8", &pmic5_nldo, "vdd-l7-l8"), - RPMH_VREG("ldo9", "ldo%s9", &pmic5_nldo, "vdd-l3-l9"), - RPMH_VREG("ldo10", "ldo%s10", &pmic5_pldo, "vdd-l10-l11-l13"), - RPMH_VREG("ldo11", "ldo%s11", &pmic5_pldo, "vdd-l10-l11-l13"), - RPMH_VREG("ldo12", "ldo%s12", &pmic5_nldo, "vdd-l4-l12"), - RPMH_VREG("ldo13", "ldo%s13", &pmic5_pldo, "vdd-l10-l11-l13"), - RPMH_VREG("ldo14", "ldo%s14", &pmic5_nldo, "vdd-l14"), - RPMH_VREG("ldo15", "ldo%s15", &pmic5_nldo, "vdd-l15"), - RPMH_VREG("ldo16", "ldo%s16", &pmic5_pldo, "vdd-l16"), + RPMH_VREG("smps1", SMPS, 1, &pmic5_ftsmps510, "vdd-s1"), + RPMH_VREG("smps2", SMPS, 2, &pmic5_hfsmps510, "vdd-s2"), + RPMH_VREG("smps3", SMPS, 3, &pmic5_hfsmps510, "vdd-s3"), + RPMH_VREG("smps4", SMPS, 4, &pmic5_hfsmps510, "vdd-s4"), + RPMH_VREG("smps5", SMPS, 5, &pmic5_hfsmps510, "vdd-s5"), + RPMH_VREG("smps6", SMPS, 6, &pmic5_ftsmps510, "vdd-s6"), + RPMH_VREG("smps7", SMPS, 7, &pmic5_hfsmps510, "vdd-s7"), + RPMH_VREG("ldo1", LDO, 1, &pmic5_nldo, "vdd-l1-l2"), + RPMH_VREG("ldo2", LDO, 2, &pmic5_nldo, "vdd-l1-l2"), + RPMH_VREG("ldo3", LDO, 3, &pmic5_nldo, "vdd-l3-l9"), + RPMH_VREG("ldo4", LDO, 4, &pmic5_nldo, "vdd-l4-l12"), + RPMH_VREG("ldo5", LDO, 5, &pmic5_pldo, "vdd-l5-l6"), + RPMH_VREG("ldo6", LDO, 6, &pmic5_pldo, "vdd-l5-l6"), + RPMH_VREG("ldo7", LDO, 7, &pmic5_nldo, "vdd-l7-l8"), + RPMH_VREG("ldo8", LDO, 8, &pmic5_nldo, "vdd-l7-l8"), + RPMH_VREG("ldo9", LDO, 9, &pmic5_nldo, "vdd-l3-l9"), + RPMH_VREG("ldo10", LDO, 10, &pmic5_pldo, "vdd-l10-l11-l13"), + RPMH_VREG("ldo11", LDO, 11, &pmic5_pldo, "vdd-l10-l11-l13"), + RPMH_VREG("ldo12", LDO, 12, &pmic5_nldo, "vdd-l4-l12"), + RPMH_VREG("ldo13", LDO, 13, &pmic5_pldo, "vdd-l10-l11-l13"), + RPMH_VREG("ldo14", LDO, 14, &pmic5_nldo, "vdd-l14"), + RPMH_VREG("ldo15", LDO, 15, &pmic5_nldo, "vdd-l15"), + RPMH_VREG("ldo16", LDO, 16, &pmic5_pldo, "vdd-l16"), {} }; static const struct rpmh_vreg_init_data pmx65_vreg_data[] = { - RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps510, "vdd-s1"), - RPMH_VREG("smps2", "smp%s2", &pmic5_hfsmps510, "vdd-s2"), - RPMH_VREG("smps3", "smp%s3", &pmic5_hfsmps510, "vdd-s3"), - RPMH_VREG("smps4", "smp%s4", &pmic5_hfsmps510, "vdd-s4"), - RPMH_VREG("smps5", "smp%s5", &pmic5_hfsmps510, "vdd-s5"), - RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps510, "vdd-s6"), - RPMH_VREG("smps7", "smp%s7", &pmic5_hfsmps510, "vdd-s7"), - RPMH_VREG("smps8", "smp%s8", &pmic5_hfsmps510, "vdd-s8"), - RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo, "vdd-l1"), - RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo, "vdd-l2-l18"), - RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo, "vdd-l3"), - RPMH_VREG("ldo4", "ldo%s4", &pmic5_nldo, "vdd-l4"), - RPMH_VREG("ldo5", "ldo%s5", &pmic5_pldo, "vdd-l5-l6-l16"), - RPMH_VREG("ldo6", "ldo%s6", &pmic5_pldo, "vdd-l5-l6-l16"), - RPMH_VREG("ldo7", "ldo%s7", &pmic5_nldo, "vdd-l7"), - RPMH_VREG("ldo8", "ldo%s8", &pmic5_nldo, "vdd-l8-l9"), - RPMH_VREG("ldo9", "ldo%s9", &pmic5_nldo, "vdd-l8-l9"), - RPMH_VREG("ldo10", "ldo%s10", &pmic5_pldo, "vdd-l10"), - RPMH_VREG("ldo11", "ldo%s11", &pmic5_pldo, "vdd-l11-l13"), - RPMH_VREG("ldo12", "ldo%s12", &pmic5_nldo, "vdd-l12"), - RPMH_VREG("ldo13", "ldo%s13", &pmic5_pldo, "vdd-l11-l13"), - RPMH_VREG("ldo14", "ldo%s14", &pmic5_nldo, "vdd-l14"), - RPMH_VREG("ldo15", "ldo%s15", &pmic5_nldo, "vdd-l15"), - RPMH_VREG("ldo16", "ldo%s16", &pmic5_pldo, "vdd-l5-l6-l16"), - RPMH_VREG("ldo17", "ldo%s17", &pmic5_nldo, "vdd-l17"), + RPMH_VREG("smps1", SMPS, 1, &pmic5_ftsmps510, "vdd-s1"), + RPMH_VREG("smps2", SMPS, 2, &pmic5_hfsmps510, "vdd-s2"), + RPMH_VREG("smps3", SMPS, 3, &pmic5_hfsmps510, "vdd-s3"), + RPMH_VREG("smps4", SMPS, 4, &pmic5_hfsmps510, "vdd-s4"), + RPMH_VREG("smps5", SMPS, 5, &pmic5_hfsmps510, "vdd-s5"), + RPMH_VREG("smps6", SMPS, 6, &pmic5_ftsmps510, "vdd-s6"), + RPMH_VREG("smps7", SMPS, 7, &pmic5_hfsmps510, "vdd-s7"), + RPMH_VREG("smps8", SMPS, 8, &pmic5_hfsmps510, "vdd-s8"), + RPMH_VREG("ldo1", LDO, 1, &pmic5_nldo, "vdd-l1"), + RPMH_VREG("ldo2", LDO, 2, &pmic5_nldo, "vdd-l2-l18"), + RPMH_VREG("ldo3", LDO, 3, &pmic5_nldo, "vdd-l3"), + RPMH_VREG("ldo4", LDO, 4, &pmic5_nldo, "vdd-l4"), + RPMH_VREG("ldo5", LDO, 5, &pmic5_pldo, "vdd-l5-l6-l16"), + RPMH_VREG("ldo6", LDO, 6, &pmic5_pldo, "vdd-l5-l6-l16"), + RPMH_VREG("ldo7", LDO, 7, &pmic5_nldo, "vdd-l7"), + RPMH_VREG("ldo8", LDO, 8, &pmic5_nldo, "vdd-l8-l9"), + RPMH_VREG("ldo9", LDO, 9, &pmic5_nldo, "vdd-l8-l9"), + RPMH_VREG("ldo10", LDO, 10, &pmic5_pldo, "vdd-l10"), + RPMH_VREG("ldo11", LDO, 11, &pmic5_pldo, "vdd-l11-l13"), + RPMH_VREG("ldo12", LDO, 12, &pmic5_nldo, "vdd-l12"), + RPMH_VREG("ldo13", LDO, 13, &pmic5_pldo, "vdd-l11-l13"), + RPMH_VREG("ldo14", LDO, 14, &pmic5_nldo, "vdd-l14"), + RPMH_VREG("ldo15", LDO, 15, &pmic5_nldo, "vdd-l15"), + RPMH_VREG("ldo16", LDO, 16, &pmic5_pldo, "vdd-l5-l6-l16"), + RPMH_VREG("ldo17", LDO, 17, &pmic5_nldo, "vdd-l17"), /* ldo18 not configured */ - RPMH_VREG("ldo19", "ldo%s19", &pmic5_nldo, "vdd-l19"), - RPMH_VREG("ldo20", "ldo%s20", &pmic5_nldo, "vdd-l20"), - RPMH_VREG("ldo21", "ldo%s21", &pmic5_nldo, "vdd-l21"), + RPMH_VREG("ldo19", LDO, 19, &pmic5_nldo, "vdd-l19"), + RPMH_VREG("ldo20", LDO, 20, &pmic5_nldo, "vdd-l20"), + RPMH_VREG("ldo21", LDO, 21, &pmic5_nldo, "vdd-l21"), {} }; static const struct rpmh_vreg_init_data pmx75_vreg_data[] = { - RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps525, "vdd-s1"), - RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps525, "vdd-s2"), - RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps525, "vdd-s3"), - RPMH_VREG("smps4", "smp%s4", &pmic5_ftsmps525, "vdd-s4"), - RPMH_VREG("smps5", "smp%s5", &pmic5_ftsmps525, "vdd-s5"), - RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps525, "vdd-s6"), - RPMH_VREG("smps7", "smp%s7", &pmic5_ftsmps525, "vdd-s7"), - RPMH_VREG("smps8", "smp%s8", &pmic5_ftsmps525, "vdd-s8"), - RPMH_VREG("smps9", "smp%s9", &pmic5_ftsmps525, "vdd-s9"), - RPMH_VREG("smps10", "smp%s10", &pmic5_ftsmps525, "vdd-s10"), - RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo515, "vdd-l1"), - RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo515, "vdd-l2-18"), - RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo515, "vdd-l3"), - RPMH_VREG("ldo4", "ldo%s4", &pmic5_nldo515, "vdd-l4-l16"), - RPMH_VREG("ldo5", "ldo%s5", &pmic5_pldo_lv, "vdd-l5-l6"), - RPMH_VREG("ldo6", "ldo%s6", &pmic5_pldo_lv, "vdd-l5-l6"), - RPMH_VREG("ldo7", "ldo%s7", &pmic5_nldo515, "vdd-l7"), - RPMH_VREG("ldo8", "ldo%s8", &pmic5_nldo515, "vdd-l8-l9"), - RPMH_VREG("ldo9", "ldo%s9", &pmic5_nldo515, "vdd-l8-l9"), - RPMH_VREG("ldo10", "ldo%s10", &pmic5_pldo, "vdd-l10"), - RPMH_VREG("ldo11", "ldo%s11", &pmic5_pldo, "vdd-l11-l13"), - RPMH_VREG("ldo12", "ldo%s12", &pmic5_nldo515, "vdd-l12"), - RPMH_VREG("ldo13", "ldo%s13", &pmic5_pldo, "vdd-l11-l13"), - RPMH_VREG("ldo14", "ldo%s14", &pmic5_nldo515, "vdd-l14"), - RPMH_VREG("ldo15", "ldo%s15", &pmic5_nldo515, "vdd-l15"), - RPMH_VREG("ldo16", "ldo%s16", &pmic5_nldo515, "vdd-l4-l16"), - RPMH_VREG("ldo17", "ldo%s17", &pmic5_nldo515, "vdd-l17"), + RPMH_VREG("smps1", SMPS, 1, &pmic5_ftsmps525, "vdd-s1"), + RPMH_VREG("smps2", SMPS, 2, &pmic5_ftsmps525, "vdd-s2"), + RPMH_VREG("smps3", SMPS, 3, &pmic5_ftsmps525, "vdd-s3"), + RPMH_VREG("smps4", SMPS, 4, &pmic5_ftsmps525, "vdd-s4"), + RPMH_VREG("smps5", SMPS, 5, &pmic5_ftsmps525, "vdd-s5"), + RPMH_VREG("smps6", SMPS, 6, &pmic5_ftsmps525, "vdd-s6"), + RPMH_VREG("smps7", SMPS, 7, &pmic5_ftsmps525, "vdd-s7"), + RPMH_VREG("smps8", SMPS, 8, &pmic5_ftsmps525, "vdd-s8"), + RPMH_VREG("smps9", SMPS, 9, &pmic5_ftsmps525, "vdd-s9"), + RPMH_VREG("smps10", SMPS, 10, &pmic5_ftsmps525, "vdd-s10"), + RPMH_VREG("ldo1", LDO, 1, &pmic5_nldo515, "vdd-l1"), + RPMH_VREG("ldo2", LDO, 2, &pmic5_nldo515, "vdd-l2-18"), + RPMH_VREG("ldo3", LDO, 3, &pmic5_nldo515, "vdd-l3"), + RPMH_VREG("ldo4", LDO, 4, &pmic5_nldo515, "vdd-l4-l16"), + RPMH_VREG("ldo5", LDO, 5, &pmic5_pldo_lv, "vdd-l5-l6"), + RPMH_VREG("ldo6", LDO, 6, &pmic5_pldo_lv, "vdd-l5-l6"), + RPMH_VREG("ldo7", LDO, 7, &pmic5_nldo515, "vdd-l7"), + RPMH_VREG("ldo8", LDO, 8, &pmic5_nldo515, "vdd-l8-l9"), + RPMH_VREG("ldo9", LDO, 9, &pmic5_nldo515, "vdd-l8-l9"), + RPMH_VREG("ldo10", LDO, 10, &pmic5_pldo, "vdd-l10"), + RPMH_VREG("ldo11", LDO, 11, &pmic5_pldo, "vdd-l11-l13"), + RPMH_VREG("ldo12", LDO, 12, &pmic5_nldo515, "vdd-l12"), + RPMH_VREG("ldo13", LDO, 13, &pmic5_pldo, "vdd-l11-l13"), + RPMH_VREG("ldo14", LDO, 14, &pmic5_nldo515, "vdd-l14"), + RPMH_VREG("ldo15", LDO, 15, &pmic5_nldo515, "vdd-l15"), + RPMH_VREG("ldo16", LDO, 16, &pmic5_nldo515, "vdd-l4-l16"), + RPMH_VREG("ldo17", LDO, 17, &pmic5_nldo515, "vdd-l17"), /* ldo18 not configured */ - RPMH_VREG("ldo19", "ldo%s19", &pmic5_nldo515, "vdd-l19"), - RPMH_VREG("ldo20", "ldo%s20", &pmic5_nldo515, "vdd-l20-l21"), - RPMH_VREG("ldo21", "ldo%s21", &pmic5_nldo515, "vdd-l20-l21"), + RPMH_VREG("ldo19", LDO, 19, &pmic5_nldo515, "vdd-l19"), + RPMH_VREG("ldo20", LDO, 20, &pmic5_nldo515, "vdd-l20-l21"), + RPMH_VREG("ldo21", LDO, 21, &pmic5_nldo515, "vdd-l20-l21"), }; static const struct rpmh_vreg_init_data pm7325_vreg_data[] = { - RPMH_VREG("smps1", "smp%s1", &pmic5_hfsmps510, "vdd-s1"), - RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps520, "vdd-s2"), - RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps520, "vdd-s3"), - RPMH_VREG("smps4", "smp%s4", &pmic5_ftsmps520, "vdd-s4"), - RPMH_VREG("smps5", "smp%s5", &pmic5_ftsmps520, "vdd-s5"), - RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps520, "vdd-s6"), - RPMH_VREG("smps7", "smp%s7", &pmic5_ftsmps520, "vdd-s7"), - RPMH_VREG("smps8", "smp%s8", &pmic5_hfsmps510, "vdd-s8"), - RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo, "vdd-l1-l4-l12-l15"), - RPMH_VREG("ldo2", "ldo%s2", &pmic5_pldo, "vdd-l2-l7"), - RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo, "vdd-l3"), - RPMH_VREG("ldo4", "ldo%s4", &pmic5_nldo, "vdd-l1-l4-l12-l15"), - RPMH_VREG("ldo5", "ldo%s5", &pmic5_nldo, "vdd-l5"), - RPMH_VREG("ldo6", "ldo%s6", &pmic5_nldo, "vdd-l6-l9-l10"), - RPMH_VREG("ldo7", "ldo%s7", &pmic5_pldo, "vdd-l2-l7"), - RPMH_VREG("ldo8", "ldo%s8", &pmic5_nldo, "vdd-l8"), - RPMH_VREG("ldo9", "ldo%s9", &pmic5_nldo, "vdd-l6-l9-l10"), - RPMH_VREG("ldo10", "ldo%s10", &pmic5_nldo, "vdd-l6-l9-l10"), - RPMH_VREG("ldo11", "ldo%s11", &pmic5_pldo_lv, "vdd-l11-l17-l18-l19"), - RPMH_VREG("ldo12", "ldo%s12", &pmic5_nldo, "vdd-l1-l4-l12-l15"), - RPMH_VREG("ldo13", "ldo%s13", &pmic5_nldo, "vdd-l13"), - RPMH_VREG("ldo14", "ldo%s14", &pmic5_nldo, "vdd-l14-l16"), - RPMH_VREG("ldo15", "ldo%s15", &pmic5_nldo, "vdd-l1-l4-l12-l15"), - RPMH_VREG("ldo16", "ldo%s16", &pmic5_nldo, "vdd-l14-l16"), - RPMH_VREG("ldo17", "ldo%s17", &pmic5_pldo_lv, "vdd-l11-l17-l18-l19"), - RPMH_VREG("ldo18", "ldo%s18", &pmic5_pldo_lv, "vdd-l11-l17-l18-l19"), - RPMH_VREG("ldo19", "ldo%s19", &pmic5_pldo_lv, "vdd-l11-l17-l18-l19"), + RPMH_VREG("smps1", SMPS, 1, &pmic5_hfsmps510, "vdd-s1"), + RPMH_VREG("smps2", SMPS, 2, &pmic5_ftsmps520, "vdd-s2"), + RPMH_VREG("smps3", SMPS, 3, &pmic5_ftsmps520, "vdd-s3"), + RPMH_VREG("smps4", SMPS, 4, &pmic5_ftsmps520, "vdd-s4"), + RPMH_VREG("smps5", SMPS, 5, &pmic5_ftsmps520, "vdd-s5"), + RPMH_VREG("smps6", SMPS, 6, &pmic5_ftsmps520, "vdd-s6"), + RPMH_VREG("smps7", SMPS, 7, &pmic5_ftsmps520, "vdd-s7"), + RPMH_VREG("smps8", SMPS, 8, &pmic5_hfsmps510, "vdd-s8"), + RPMH_VREG("ldo1", LDO, 1, &pmic5_nldo, "vdd-l1-l4-l12-l15"), + RPMH_VREG("ldo2", LDO, 2, &pmic5_pldo, "vdd-l2-l7"), + RPMH_VREG("ldo3", LDO, 3, &pmic5_nldo, "vdd-l3"), + RPMH_VREG("ldo4", LDO, 4, &pmic5_nldo, "vdd-l1-l4-l12-l15"), + RPMH_VREG("ldo5", LDO, 5, &pmic5_nldo, "vdd-l5"), + RPMH_VREG("ldo6", LDO, 6, &pmic5_nldo, "vdd-l6-l9-l10"), + RPMH_VREG("ldo7", LDO, 7, &pmic5_pldo, "vdd-l2-l7"), + RPMH_VREG("ldo8", LDO, 8, &pmic5_nldo, "vdd-l8"), + RPMH_VREG("ldo9", LDO, 9, &pmic5_nldo, "vdd-l6-l9-l10"), + RPMH_VREG("ldo10", LDO, 10, &pmic5_nldo, "vdd-l6-l9-l10"), + RPMH_VREG("ldo11", LDO, 11, &pmic5_pldo_lv, "vdd-l11-l17-l18-l19"), + RPMH_VREG("ldo12", LDO, 12, &pmic5_nldo, "vdd-l1-l4-l12-l15"), + RPMH_VREG("ldo13", LDO, 13, &pmic5_nldo, "vdd-l13"), + RPMH_VREG("ldo14", LDO, 14, &pmic5_nldo, "vdd-l14-l16"), + RPMH_VREG("ldo15", LDO, 15, &pmic5_nldo, "vdd-l1-l4-l12-l15"), + RPMH_VREG("ldo16", LDO, 16, &pmic5_nldo, "vdd-l14-l16"), + RPMH_VREG("ldo17", LDO, 17, &pmic5_pldo_lv, "vdd-l11-l17-l18-l19"), + RPMH_VREG("ldo18", LDO, 18, &pmic5_pldo_lv, "vdd-l11-l17-l18-l19"), + RPMH_VREG("ldo19", LDO, 19, &pmic5_pldo_lv, "vdd-l11-l17-l18-l19"), {} }; static const struct rpmh_vreg_init_data pm7550_vreg_data[] = { - RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps525, "vdd-s1"), - RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps525, "vdd-s2"), - RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps525, "vdd-s3"), - RPMH_VREG("smps4", "smp%s4", &pmic5_ftsmps525, "vdd-s4"), - RPMH_VREG("smps5", "smp%s5", &pmic5_ftsmps525, "vdd-s5"), - RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps525, "vdd-s6"), - RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo515, "vdd-l1"), - RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo515, "vdd-l2-l3"), - RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo515, "vdd-l2-l3"), - RPMH_VREG("ldo4", "ldo%s4", &pmic5_nldo515, "vdd-l4-l5"), - RPMH_VREG("ldo5", "ldo%s5", &pmic5_nldo515, "vdd-l4-l5"), - RPMH_VREG("ldo6", "ldo%s6", &pmic5_nldo515, "vdd-l6"), - RPMH_VREG("ldo7", "ldo%s7", &pmic5_nldo515, "vdd-l7"), - RPMH_VREG("ldo8", "ldo%s8", &pmic5_nldo515, "vdd-l8"), - RPMH_VREG("ldo9", "ldo%s9", &pmic5_nldo515, "vdd-l9-l10"), - RPMH_VREG("ldo10", "ldo%s10", &pmic5_nldo515, "vdd-l9-l10"), - RPMH_VREG("ldo11", "ldo%s11", &pmic5_nldo515, "vdd-l11"), - RPMH_VREG("ldo12", "ldo%s12", &pmic5_pldo515_mv, "vdd-l12-l14"), - RPMH_VREG("ldo13", "ldo%s13", &pmic5_pldo515_mv, "vdd-l13-l16"), - RPMH_VREG("ldo14", "ldo%s14", &pmic5_pldo, "vdd-l12-l14"), - RPMH_VREG("ldo15", "ldo%s15", &pmic5_pldo, "vdd-l15-l17-l18-l19-l20-l21-l22-l23"), - RPMH_VREG("ldo16", "ldo%s16", &pmic5_pldo, "vdd-l13-l16"), - RPMH_VREG("ldo17", "ldo%s17", &pmic5_pldo, "vdd-l15-l17-l18-l19-l20-l21-l22-l23"), - RPMH_VREG("ldo18", "ldo%s18", &pmic5_pldo, "vdd-l15-l17-l18-l19-l20-l21-l22-l23"), - RPMH_VREG("ldo19", "ldo%s19", &pmic5_pldo, "vdd-l15-l17-l18-l19-l20-l21-l22-l23"), - RPMH_VREG("ldo20", "ldo%s20", &pmic5_pldo, "vdd-l15-l17-l18-l19-l20-l21-l22-l23"), - RPMH_VREG("ldo21", "ldo%s21", &pmic5_pldo, "vdd-l15-l17-l18-l19-l20-l21-l22-l23"), - RPMH_VREG("ldo22", "ldo%s22", &pmic5_pldo, "vdd-l15-l17-l18-l19-l20-l21-l22-l23"), - RPMH_VREG("ldo23", "ldo%s23", &pmic5_pldo, "vdd-l15-l17-l18-l19-l20-l21-l22-l23"), - RPMH_VREG("bob", "bob%s1", &pmic5_bob, "vdd-bob"), + RPMH_VREG("smps1", SMPS, 1, &pmic5_ftsmps525, "vdd-s1"), + RPMH_VREG("smps2", SMPS, 2, &pmic5_ftsmps525, "vdd-s2"), + RPMH_VREG("smps3", SMPS, 3, &pmic5_ftsmps525, "vdd-s3"), + RPMH_VREG("smps4", SMPS, 4, &pmic5_ftsmps525, "vdd-s4"), + RPMH_VREG("smps5", SMPS, 5, &pmic5_ftsmps525, "vdd-s5"), + RPMH_VREG("smps6", SMPS, 6, &pmic5_ftsmps525, "vdd-s6"), + RPMH_VREG("ldo1", LDO, 1, &pmic5_nldo515, "vdd-l1"), + RPMH_VREG("ldo2", LDO, 2, &pmic5_nldo515, "vdd-l2-l3"), + RPMH_VREG("ldo3", LDO, 3, &pmic5_nldo515, "vdd-l2-l3"), + RPMH_VREG("ldo4", LDO, 4, &pmic5_nldo515, "vdd-l4-l5"), + RPMH_VREG("ldo5", LDO, 5, &pmic5_nldo515, "vdd-l4-l5"), + RPMH_VREG("ldo6", LDO, 6, &pmic5_nldo515, "vdd-l6"), + RPMH_VREG("ldo7", LDO, 7, &pmic5_nldo515, "vdd-l7"), + RPMH_VREG("ldo8", LDO, 8, &pmic5_nldo515, "vdd-l8"), + RPMH_VREG("ldo9", LDO, 9, &pmic5_nldo515, "vdd-l9-l10"), + RPMH_VREG("ldo10", LDO, 10, &pmic5_nldo515, "vdd-l9-l10"), + RPMH_VREG("ldo11", LDO, 11, &pmic5_nldo515, "vdd-l11"), + RPMH_VREG("ldo12", LDO, 12, &pmic5_pldo515_mv, "vdd-l12-l14"), + RPMH_VREG("ldo13", LDO, 13, &pmic5_pldo515_mv, "vdd-l13-l16"), + RPMH_VREG("ldo14", LDO, 14, &pmic5_pldo, "vdd-l12-l14"), + RPMH_VREG("ldo15", LDO, 15, &pmic5_pldo, "vdd-l15-l17-l18-l19-l20-l21-l22-l23"), + RPMH_VREG("ldo16", LDO, 16, &pmic5_pldo, "vdd-l13-l16"), + RPMH_VREG("ldo17", LDO, 17, &pmic5_pldo, "vdd-l15-l17-l18-l19-l20-l21-l22-l23"), + RPMH_VREG("ldo18", LDO, 18, &pmic5_pldo, "vdd-l15-l17-l18-l19-l20-l21-l22-l23"), + RPMH_VREG("ldo19", LDO, 19, &pmic5_pldo, "vdd-l15-l17-l18-l19-l20-l21-l22-l23"), + RPMH_VREG("ldo20", LDO, 20, &pmic5_pldo, "vdd-l15-l17-l18-l19-l20-l21-l22-l23"), + RPMH_VREG("ldo21", LDO, 21, &pmic5_pldo, "vdd-l15-l17-l18-l19-l20-l21-l22-l23"), + RPMH_VREG("ldo22", LDO, 22, &pmic5_pldo, "vdd-l15-l17-l18-l19-l20-l21-l22-l23"), + RPMH_VREG("ldo23", LDO, 23, &pmic5_pldo, "vdd-l15-l17-l18-l19-l20-l21-l22-l23"), + RPMH_VREG("bob", BOB, 1, &pmic5_bob, "vdd-bob"), {} }; static const struct rpmh_vreg_init_data pmr735a_vreg_data[] = { - RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps520, "vdd-s1"), - RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps520, "vdd-s2"), - RPMH_VREG("smps3", "smp%s3", &pmic5_hfsmps515, "vdd-s3"), - RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo, "vdd-l1-l2"), - RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo, "vdd-l1-l2"), - RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo, "vdd-l3"), - RPMH_VREG("ldo4", "ldo%s4", &pmic5_pldo_lv, "vdd-l4"), - RPMH_VREG("ldo5", "ldo%s5", &pmic5_nldo, "vdd-l5-l6"), - RPMH_VREG("ldo6", "ldo%s6", &pmic5_nldo, "vdd-l5-l6"), - RPMH_VREG("ldo7", "ldo%s7", &pmic5_pldo, "vdd-l7-bob"), + RPMH_VREG("smps1", SMPS, 1, &pmic5_ftsmps520, "vdd-s1"), + RPMH_VREG("smps2", SMPS, 2, &pmic5_ftsmps520, "vdd-s2"), + RPMH_VREG("smps3", SMPS, 3, &pmic5_hfsmps515, "vdd-s3"), + RPMH_VREG("ldo1", LDO, 1, &pmic5_nldo, "vdd-l1-l2"), + RPMH_VREG("ldo2", LDO, 2, &pmic5_nldo, "vdd-l1-l2"), + RPMH_VREG("ldo3", LDO, 3, &pmic5_nldo, "vdd-l3"), + RPMH_VREG("ldo4", LDO, 4, &pmic5_pldo_lv, "vdd-l4"), + RPMH_VREG("ldo5", LDO, 5, &pmic5_nldo, "vdd-l5-l6"), + RPMH_VREG("ldo6", LDO, 6, &pmic5_nldo, "vdd-l5-l6"), + RPMH_VREG("ldo7", LDO, 7, &pmic5_pldo, "vdd-l7-bob"), {} }; static const struct rpmh_vreg_init_data pmr735b_vreg_data[] = { - RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo, "vdd-l1-l2"), - RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo, "vdd-l1-l2"), - RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo, "vdd-l3"), - RPMH_VREG("ldo4", "ldo%s4", &pmic5_pldo_lv, "vdd-l4"), - RPMH_VREG("ldo5", "ldo%s5", &pmic5_nldo, "vdd-l5"), - RPMH_VREG("ldo6", "ldo%s6", &pmic5_nldo, "vdd-l6"), - RPMH_VREG("ldo7", "ldo%s7", &pmic5_nldo, "vdd-l7-l8"), - RPMH_VREG("ldo8", "ldo%s8", &pmic5_nldo, "vdd-l7-l8"), - RPMH_VREG("ldo9", "ldo%s9", &pmic5_nldo, "vdd-l9"), - RPMH_VREG("ldo10", "ldo%s10", &pmic5_pldo_lv, "vdd-l10"), - RPMH_VREG("ldo11", "ldo%s11", &pmic5_nldo, "vdd-l11"), - RPMH_VREG("ldo12", "ldo%s12", &pmic5_nldo, "vdd-l12"), + RPMH_VREG("ldo1", LDO, 1, &pmic5_nldo, "vdd-l1-l2"), + RPMH_VREG("ldo2", LDO, 2, &pmic5_nldo, "vdd-l1-l2"), + RPMH_VREG("ldo3", LDO, 3, &pmic5_nldo, "vdd-l3"), + RPMH_VREG("ldo4", LDO, 4, &pmic5_pldo_lv, "vdd-l4"), + RPMH_VREG("ldo5", LDO, 5, &pmic5_nldo, "vdd-l5"), + RPMH_VREG("ldo6", LDO, 6, &pmic5_nldo, "vdd-l6"), + RPMH_VREG("ldo7", LDO, 7, &pmic5_nldo, "vdd-l7-l8"), + RPMH_VREG("ldo8", LDO, 8, &pmic5_nldo, "vdd-l7-l8"), + RPMH_VREG("ldo9", LDO, 9, &pmic5_nldo, "vdd-l9"), + RPMH_VREG("ldo10", LDO, 10, &pmic5_pldo_lv, "vdd-l10"), + RPMH_VREG("ldo11", LDO, 11, &pmic5_nldo, "vdd-l11"), + RPMH_VREG("ldo12", LDO, 12, &pmic5_nldo, "vdd-l12"), {} }; static const struct rpmh_vreg_init_data pm660_vreg_data[] = { - RPMH_VREG("smps1", "smp%s1", &pmic4_ftsmps426, "vdd-s1"), - RPMH_VREG("smps2", "smp%s2", &pmic4_ftsmps426, "vdd-s2"), - RPMH_VREG("smps3", "smp%s3", &pmic4_ftsmps426, "vdd-s3"), - RPMH_VREG("smps4", "smp%s4", &pmic4_hfsmps3, "vdd-s4"), - RPMH_VREG("smps5", "smp%s5", &pmic4_hfsmps3, "vdd-s5"), - RPMH_VREG("smps6", "smp%s6", &pmic4_hfsmps3, "vdd-s6"), - RPMH_VREG("ldo1", "ldo%s1", &pmic4_nldo, "vdd-l1-l6-l7"), - RPMH_VREG("ldo2", "ldo%s2", &pmic4_nldo, "vdd-l2-l3"), - RPMH_VREG("ldo3", "ldo%s3", &pmic4_nldo, "vdd-l2-l3"), + RPMH_VREG("smps1", SMPS, 1, &pmic4_ftsmps426, "vdd-s1"), + RPMH_VREG("smps2", SMPS, 2, &pmic4_ftsmps426, "vdd-s2"), + RPMH_VREG("smps3", SMPS, 3, &pmic4_ftsmps426, "vdd-s3"), + RPMH_VREG("smps4", SMPS, 4, &pmic4_hfsmps3, "vdd-s4"), + RPMH_VREG("smps5", SMPS, 5, &pmic4_hfsmps3, "vdd-s5"), + RPMH_VREG("smps6", SMPS, 6, &pmic4_hfsmps3, "vdd-s6"), + RPMH_VREG("ldo1", LDO, 1, &pmic4_nldo, "vdd-l1-l6-l7"), + RPMH_VREG("ldo2", LDO, 2, &pmic4_nldo, "vdd-l2-l3"), + RPMH_VREG("ldo3", LDO, 3, &pmic4_nldo, "vdd-l2-l3"), /* ldo4 is inaccessible on PM660 */ - RPMH_VREG("ldo5", "ldo%s5", &pmic4_nldo, "vdd-l5"), - RPMH_VREG("ldo6", "ldo%s6", &pmic4_nldo, "vdd-l1-l6-l7"), - RPMH_VREG("ldo7", "ldo%s7", &pmic4_nldo, "vdd-l1-l6-l7"), - RPMH_VREG("ldo8", "ldo%s8", &pmic4_pldo_lv, "vdd-l8-l9-l10-l11-l12-l13-l14"), - RPMH_VREG("ldo9", "ldo%s9", &pmic4_pldo_lv, "vdd-l8-l9-l10-l11-l12-l13-l14"), - RPMH_VREG("ldo10", "ldo%s10", &pmic4_pldo_lv, "vdd-l8-l9-l10-l11-l12-l13-l14"), - RPMH_VREG("ldo11", "ldo%s11", &pmic4_pldo_lv, "vdd-l8-l9-l10-l11-l12-l13-l14"), - RPMH_VREG("ldo12", "ldo%s12", &pmic4_pldo_lv, "vdd-l8-l9-l10-l11-l12-l13-l14"), - RPMH_VREG("ldo13", "ldo%s13", &pmic4_pldo_lv, "vdd-l8-l9-l10-l11-l12-l13-l14"), - RPMH_VREG("ldo14", "ldo%s14", &pmic4_pldo_lv, "vdd-l8-l9-l10-l11-l12-l13-l14"), - RPMH_VREG("ldo15", "ldo%s15", &pmic4_pldo, "vdd-l15-l16-l17-l18-l19"), - RPMH_VREG("ldo16", "ldo%s16", &pmic4_pldo, "vdd-l15-l16-l17-l18-l19"), - RPMH_VREG("ldo17", "ldo%s17", &pmic4_pldo, "vdd-l15-l16-l17-l18-l19"), - RPMH_VREG("ldo18", "ldo%s18", &pmic4_pldo, "vdd-l15-l16-l17-l18-l19"), - RPMH_VREG("ldo19", "ldo%s19", &pmic4_pldo, "vdd-l15-l16-l17-l18-l19"), + RPMH_VREG("ldo5", LDO, 5, &pmic4_nldo, "vdd-l5"), + RPMH_VREG("ldo6", LDO, 6, &pmic4_nldo, "vdd-l1-l6-l7"), + RPMH_VREG("ldo7", LDO, 7, &pmic4_nldo, "vdd-l1-l6-l7"), + RPMH_VREG("ldo8", LDO, 8, &pmic4_pldo_lv, "vdd-l8-l9-l10-l11-l12-l13-l14"), + RPMH_VREG("ldo9", LDO, 9, &pmic4_pldo_lv, "vdd-l8-l9-l10-l11-l12-l13-l14"), + RPMH_VREG("ldo10", LDO, 10, &pmic4_pldo_lv, "vdd-l8-l9-l10-l11-l12-l13-l14"), + RPMH_VREG("ldo11", LDO, 11, &pmic4_pldo_lv, "vdd-l8-l9-l10-l11-l12-l13-l14"), + RPMH_VREG("ldo12", LDO, 12, &pmic4_pldo_lv, "vdd-l8-l9-l10-l11-l12-l13-l14"), + RPMH_VREG("ldo13", LDO, 13, &pmic4_pldo_lv, "vdd-l8-l9-l10-l11-l12-l13-l14"), + RPMH_VREG("ldo14", LDO, 14, &pmic4_pldo_lv, "vdd-l8-l9-l10-l11-l12-l13-l14"), + RPMH_VREG("ldo15", LDO, 15, &pmic4_pldo, "vdd-l15-l16-l17-l18-l19"), + RPMH_VREG("ldo16", LDO, 16, &pmic4_pldo, "vdd-l15-l16-l17-l18-l19"), + RPMH_VREG("ldo17", LDO, 17, &pmic4_pldo, "vdd-l15-l16-l17-l18-l19"), + RPMH_VREG("ldo18", LDO, 18, &pmic4_pldo, "vdd-l15-l16-l17-l18-l19"), + RPMH_VREG("ldo19", LDO, 19, &pmic4_pldo, "vdd-l15-l16-l17-l18-l19"), {} }; static const struct rpmh_vreg_init_data pm660l_vreg_data[] = { - RPMH_VREG("smps1", "smp%s1", &pmic4_ftsmps426, "vdd-s1"), - RPMH_VREG("smps2", "smp%s2", &pmic4_ftsmps426, "vdd-s2"), - RPMH_VREG("smps3", "smp%s3", &pmic4_ftsmps426, "vdd-s3-s4"), - RPMH_VREG("smps5", "smp%s5", &pmic4_ftsmps426, "vdd-s5"), - RPMH_VREG("ldo1", "ldo%s1", &pmic4_nldo, "vdd-l1-l9-l10"), - RPMH_VREG("ldo2", "ldo%s2", &pmic4_pldo, "vdd-l2"), - RPMH_VREG("ldo3", "ldo%s3", &pmic4_pldo, "vdd-l3-l5-l7-l8"), - RPMH_VREG("ldo4", "ldo%s4", &pmic4_pldo, "vdd-l4-l6"), - RPMH_VREG("ldo5", "ldo%s5", &pmic4_pldo, "vdd-l3-l5-l7-l8"), - RPMH_VREG("ldo6", "ldo%s6", &pmic4_pldo, "vdd-l4-l6"), - RPMH_VREG("ldo7", "ldo%s7", &pmic4_pldo, "vdd-l3-l5-l7-l8"), - RPMH_VREG("ldo8", "ldo%s8", &pmic4_pldo, "vdd-l3-l5-l7-l8"), - RPMH_VREG("bob", "bob%s1", &pmic4_bob, "vdd-bob"), + RPMH_VREG("smps1", SMPS, 1, &pmic4_ftsmps426, "vdd-s1"), + RPMH_VREG("smps2", SMPS, 2, &pmic4_ftsmps426, "vdd-s2"), + RPMH_VREG("smps3", SMPS, 3, &pmic4_ftsmps426, "vdd-s3-s4"), + RPMH_VREG("smps5", SMPS, 5, &pmic4_ftsmps426, "vdd-s5"), + RPMH_VREG("ldo1", LDO, 1, &pmic4_nldo, "vdd-l1-l9-l10"), + RPMH_VREG("ldo2", LDO, 2, &pmic4_pldo, "vdd-l2"), + RPMH_VREG("ldo3", LDO, 3, &pmic4_pldo, "vdd-l3-l5-l7-l8"), + RPMH_VREG("ldo4", LDO, 4, &pmic4_pldo, "vdd-l4-l6"), + RPMH_VREG("ldo5", LDO, 5, &pmic4_pldo, "vdd-l3-l5-l7-l8"), + RPMH_VREG("ldo6", LDO, 6, &pmic4_pldo, "vdd-l4-l6"), + RPMH_VREG("ldo7", LDO, 7, &pmic4_pldo, "vdd-l3-l5-l7-l8"), + RPMH_VREG("ldo8", LDO, 8, &pmic4_pldo, "vdd-l3-l5-l7-l8"), + RPMH_VREG("bob", BOB, 1, &pmic4_bob, "vdd-bob"), {} }; From dc1fc4716b79cf36b2d7459de0dfda2b5f3eebba Mon Sep 17 00:00:00 2001 From: Kamal Wadhwa Date: Thu, 18 Sep 2025 14:57:04 +0530 Subject: [PATCH 0189/2333] FROMGIT: regulator: rpmh-regulator: Add RPMH regulator support for Glymur Add support for PMH0101/PMCX0102/PMH0110/PMH0104 PMIC voltage regulators which are present on Glymur boards. Introduce new LDOs & SMPSs under them (PMIC5 subtype 530 for both). For these new LDOs support a new optimum power mode(OPM). In this mode LDO will automatically switch between high power mode (HPM) and low power mode (LPM) based on the real-time LDO load current. Its operation is analogous to SMPS AUTO mode. Reviewed-by: Dmitry Baryshkov Co-developed-by: Jishnu Prakash Signed-off-by: Jishnu Prakash Signed-off-by: Kamal Wadhwa Link: https://patch.msgid.link/20250918-glymur-rpmh-regulator-driver-v3-4-184c09678be3@oss.qualcomm.com Signed-off-by: Mark Brown Signed-off-by: Yijie Yang --- drivers/regulator/qcom-rpmh-regulator.c | 188 +++++++++++++++++++++++- 1 file changed, 187 insertions(+), 1 deletion(-) diff --git a/drivers/regulator/qcom-rpmh-regulator.c b/drivers/regulator/qcom-rpmh-regulator.c index dfb5bf5b72a1e..0a561f1d94523 100644 --- a/drivers/regulator/qcom-rpmh-regulator.c +++ b/drivers/regulator/qcom-rpmh-regulator.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 // Copyright (c) 2018-2021, The Linux Foundation. All rights reserved. -// Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. +// Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. #define pr_fmt(fmt) "%s: " fmt, __func__ @@ -92,6 +92,11 @@ static const struct resource_name_formats vreg_rsc_name_lookup[NUM_REGULATOR_TYP #define PMIC5_BOB_MODE_AUTO 6 #define PMIC5_BOB_MODE_PWM 7 +#define PMIC530_LDO_MODE_RETENTION 3 +#define PMIC530_LDO_MODE_LPM 4 +#define PMIC530_LDO_MODE_OPM 5 +#define PMIC530_LDO_MODE_HPM 7 + #define PMIC_ID_LEN 4 /** * struct rpmh_vreg_hw_data - RPMh regulator hardware configurations @@ -557,6 +562,14 @@ static const int pmic_mode_map_pmic5_ldo_hpm[REGULATOR_MODE_STANDBY + 1] = { [REGULATOR_MODE_FAST] = -EINVAL, }; +static const int pmic_mode_map_pmic530_ldo[REGULATOR_MODE_STANDBY + 1] = { + [REGULATOR_MODE_INVALID] = -EINVAL, + [REGULATOR_MODE_STANDBY] = PMIC530_LDO_MODE_RETENTION, + [REGULATOR_MODE_IDLE] = PMIC530_LDO_MODE_LPM, + [REGULATOR_MODE_NORMAL] = PMIC530_LDO_MODE_OPM, + [REGULATOR_MODE_FAST] = PMIC530_LDO_MODE_HPM, +}; + static unsigned int rpmh_regulator_pmic4_ldo_of_map_mode(unsigned int rpmh_mode) { unsigned int mode; @@ -579,6 +592,30 @@ static unsigned int rpmh_regulator_pmic4_ldo_of_map_mode(unsigned int rpmh_mode) return mode; } +static unsigned int rpmh_regulator_pmic530_ldo_of_map_mode(unsigned int rpmh_mode) +{ + unsigned int mode; + + switch (rpmh_mode) { + case RPMH_REGULATOR_MODE_HPM: + mode = REGULATOR_MODE_FAST; + break; + case RPMH_REGULATOR_MODE_AUTO: + mode = REGULATOR_MODE_NORMAL; + break; + case RPMH_REGULATOR_MODE_LPM: + mode = REGULATOR_MODE_IDLE; + break; + case RPMH_REGULATOR_MODE_RET: + mode = REGULATOR_MODE_STANDBY; + break; + default: + mode = REGULATOR_MODE_INVALID; + break; + } + return mode; +} + static const int pmic_mode_map_pmic4_smps[REGULATOR_MODE_STANDBY + 1] = { [REGULATOR_MODE_INVALID] = -EINVAL, [REGULATOR_MODE_STANDBY] = PMIC4_SMPS_MODE_RETENTION, @@ -942,6 +979,71 @@ static const struct rpmh_vreg_hw_data pmic5_bob = { .of_map_mode = rpmh_regulator_pmic4_bob_of_map_mode, }; +static const struct rpmh_vreg_hw_data pmic5_nldo530 = { + .regulator_type = VRM, + .ops = &rpmh_regulator_vrm_drms_ops, + .voltage_ranges = (struct linear_range[]) { + REGULATOR_LINEAR_RANGE(320000, 0, 210, 8000), + }, + .n_linear_ranges = 1, + .n_voltages = 211, + .hpm_min_load_uA = 30000, + .pmic_mode_map = pmic_mode_map_pmic530_ldo, + .of_map_mode = rpmh_regulator_pmic530_ldo_of_map_mode, +}; + +static const struct rpmh_vreg_hw_data pmic5_pldo530_mvp150 = { + .regulator_type = VRM, + .ops = &rpmh_regulator_vrm_drms_ops, + .voltage_ranges = (struct linear_range[]) { + REGULATOR_LINEAR_RANGE(1504000, 0, 255, 8000), + }, + .n_linear_ranges = 1, + .n_voltages = 256, + .hpm_min_load_uA = 10000, + .pmic_mode_map = pmic_mode_map_pmic530_ldo, + .of_map_mode = rpmh_regulator_pmic530_ldo_of_map_mode, +}; + +static const struct rpmh_vreg_hw_data pmic5_pldo530_mvp300 = { + .regulator_type = VRM, + .ops = &rpmh_regulator_vrm_drms_ops, + .voltage_ranges = (struct linear_range[]) { + REGULATOR_LINEAR_RANGE(1504000, 0, 255, 8000), + }, + .n_linear_ranges = 1, + .n_voltages = 256, + .hpm_min_load_uA = 20000, + .pmic_mode_map = pmic_mode_map_pmic530_ldo, + .of_map_mode = rpmh_regulator_pmic530_ldo_of_map_mode, +}; + +static const struct rpmh_vreg_hw_data pmic5_pldo530_mvp600 = { + .regulator_type = VRM, + .ops = &rpmh_regulator_vrm_drms_ops, + .voltage_ranges = (struct linear_range[]) { + REGULATOR_LINEAR_RANGE(1504000, 0, 255, 8000), + }, + .n_linear_ranges = 1, + .n_voltages = 256, + .hpm_min_load_uA = 40000, + .pmic_mode_map = pmic_mode_map_pmic530_ldo, + .of_map_mode = rpmh_regulator_pmic530_ldo_of_map_mode, +}; + +static const struct rpmh_vreg_hw_data pmic5_ftsmps530 = { + .regulator_type = VRM, + .ops = &rpmh_regulator_vrm_ops, + .voltage_ranges = (struct linear_range[]) { + REGULATOR_LINEAR_RANGE(252000, 0, 305, 4000), + REGULATOR_LINEAR_RANGE(1480000, 306, 464, 8000), + }, + .n_linear_ranges = 2, + .n_voltages = 465, + .pmic_mode_map = pmic_mode_map_pmic5_smps, + .of_map_mode = rpmh_regulator_pmic4_smps_of_map_mode, +}; + #define RPMH_VREG(_name, _vreg_hw_type, _index, _hw_data, _supply_name) \ { \ .name = _name, \ @@ -1376,6 +1478,74 @@ static const struct rpmh_vreg_init_data pm6350_vreg_data[] = { RPMH_VREG("ldo22", LDO, 22, &pmic5_nldo, NULL), }; +static const struct rpmh_vreg_init_data pmcx0102_vreg_data[] = { + RPMH_VREG("smps1", SMPS, 1, &pmic5_ftsmps530, "vdd-s1"), + RPMH_VREG("smps2", SMPS, 2, &pmic5_ftsmps530, "vdd-s2"), + RPMH_VREG("smps3", SMPS, 3, &pmic5_ftsmps530, "vdd-s3"), + RPMH_VREG("smps4", SMPS, 4, &pmic5_ftsmps530, "vdd-s4"), + RPMH_VREG("smps5", SMPS, 5, &pmic5_ftsmps530, "vdd-s5"), + RPMH_VREG("smps6", SMPS, 6, &pmic5_ftsmps530, "vdd-s6"), + RPMH_VREG("smps7", SMPS, 7, &pmic5_ftsmps530, "vdd-s7"), + RPMH_VREG("smps8", SMPS, 8, &pmic5_ftsmps530, "vdd-s8"), + RPMH_VREG("smps9", SMPS, 9, &pmic5_ftsmps530, "vdd-s9"), + RPMH_VREG("smps10", SMPS, 10, &pmic5_ftsmps530, "vdd-s10"), + RPMH_VREG("ldo1", LDO, 1, &pmic5_nldo530, "vdd-l1"), + RPMH_VREG("ldo2", LDO, 2, &pmic5_nldo530, "vdd-l2"), + RPMH_VREG("ldo3", LDO, 3, &pmic5_nldo530, "vdd-l3"), + RPMH_VREG("ldo4", LDO, 4, &pmic5_nldo530, "vdd-l4"), + {} +}; + +static const struct rpmh_vreg_init_data pmh0101_vreg_data[] = { + RPMH_VREG("ldo1", LDO, 1, &pmic5_nldo530, "vdd-l1-l4-l10"), + RPMH_VREG("ldo2", LDO, 2, &pmic5_pldo530_mvp300, "vdd-l2-l13-l14"), + RPMH_VREG("ldo3", LDO, 3, &pmic5_nldo530, "vdd-l3-l11"), + RPMH_VREG("ldo4", LDO, 4, &pmic5_nldo530, "vdd-l1-l4-l10"), + RPMH_VREG("ldo5", LDO, 5, &pmic5_pldo530_mvp150, "vdd-l5-l16"), + RPMH_VREG("ldo6", LDO, 6, &pmic5_pldo530_mvp300, "vdd-l6-l7"), + RPMH_VREG("ldo7", LDO, 7, &pmic5_pldo530_mvp300, "vdd-l6-l7"), + RPMH_VREG("ldo8", LDO, 8, &pmic5_pldo530_mvp150, "vdd-l8-l9"), + RPMH_VREG("ldo9", LDO, 9, &pmic5_pldo515_mv, "vdd-l8-l9"), + RPMH_VREG("ldo10", LDO, 10, &pmic5_nldo530, "vdd-l1-l4-l10"), + RPMH_VREG("ldo11", LDO, 11, &pmic5_nldo530, "vdd-l3-l11"), + RPMH_VREG("ldo12", LDO, 12, &pmic5_nldo530, "vdd-l12"), + RPMH_VREG("ldo13", LDO, 13, &pmic5_pldo530_mvp150, "vdd-l2-l13-l14"), + RPMH_VREG("ldo14", LDO, 14, &pmic5_pldo530_mvp150, "vdd-l2-l13-l14"), + RPMH_VREG("ldo15", LDO, 15, &pmic5_nldo530, "vdd-l15"), + RPMH_VREG("ldo16", LDO, 15, &pmic5_pldo530_mvp600, "vdd-l5-l16"), + RPMH_VREG("ldo17", LDO, 17, &pmic5_pldo515_mv, "vdd-l17"), + RPMH_VREG("ldo18", LDO, 18, &pmic5_nldo530, "vdd-l18"), + RPMH_VREG("bob1", BOB, 1, &pmic5_bob, "vdd-bob1"), + RPMH_VREG("bob2", BOB, 2, &pmic5_bob, "vdd-bob2"), + {} +}; + +static const struct rpmh_vreg_init_data pmh0104_vreg_data[] = { + RPMH_VREG("smps1", SMPS, 1, &pmic5_ftsmps530, "vdd-s1"), + RPMH_VREG("smps2", SMPS, 2, &pmic5_ftsmps530, "vdd-s2"), + RPMH_VREG("smps3", SMPS, 3, &pmic5_ftsmps530, "vdd-s3"), + RPMH_VREG("smps4", SMPS, 4, &pmic5_ftsmps530, "vdd-s4"), + {} +}; + +static const struct rpmh_vreg_init_data pmh0110_vreg_data[] = { + RPMH_VREG("smps1", SMPS, 1, &pmic5_ftsmps530, "vdd-s1"), + RPMH_VREG("smps2", SMPS, 2, &pmic5_ftsmps530, "vdd-s2"), + RPMH_VREG("smps3", SMPS, 3, &pmic5_ftsmps530, "vdd-s3"), + RPMH_VREG("smps4", SMPS, 4, &pmic5_ftsmps530, "vdd-s4"), + RPMH_VREG("smps5", SMPS, 5, &pmic5_ftsmps530, "vdd-s5"), + RPMH_VREG("smps6", SMPS, 6, &pmic5_ftsmps530, "vdd-s6"), + RPMH_VREG("smps7", SMPS, 7, &pmic5_ftsmps530, "vdd-s7"), + RPMH_VREG("smps8", SMPS, 8, &pmic5_ftsmps530, "vdd-s8"), + RPMH_VREG("smps9", SMPS, 9, &pmic5_ftsmps530, "vdd-s9"), + RPMH_VREG("smps10", SMPS, 10, &pmic5_ftsmps530, "vdd-s10"), + RPMH_VREG("ldo1", LDO, 1, &pmic5_nldo530, "vdd-l1"), + RPMH_VREG("ldo2", LDO, 2, &pmic5_nldo530, "vdd-l2"), + RPMH_VREG("ldo3", LDO, 3, &pmic5_nldo530, "vdd-l3"), + RPMH_VREG("ldo4", LDO, 4, &pmic5_nldo530, "vdd-l4"), + {} +}; + static const struct rpmh_vreg_init_data pmx55_vreg_data[] = { RPMH_VREG("smps1", SMPS, 1, &pmic5_ftsmps510, "vdd-s1"), RPMH_VREG("smps2", SMPS, 2, &pmic5_hfsmps510, "vdd-s2"), @@ -1728,6 +1898,22 @@ static const struct of_device_id __maybe_unused rpmh_regulator_match_table[] = { .compatible = "qcom,pmc8380-rpmh-regulators", .data = pmc8380_vreg_data, }, + { + .compatible = "qcom,pmcx0102-rpmh-regulators", + .data = pmcx0102_vreg_data, + }, + { + .compatible = "qcom,pmh0101-rpmh-regulators", + .data = pmh0101_vreg_data, + }, + { + .compatible = "qcom,pmh0104-rpmh-regulators", + .data = pmh0104_vreg_data, + }, + { + .compatible = "qcom,pmh0110-rpmh-regulators", + .data = pmh0110_vreg_data, + }, { .compatible = "qcom,pmm8155au-rpmh-regulators", .data = pmm8155au_vreg_data, From 3931fba21b2961780b482efa047dff5d86b69de7 Mon Sep 17 00:00:00 2001 From: Jishnu Prakash Date: Wed, 24 Sep 2025 16:30:48 -0700 Subject: [PATCH 0190/2333] FROMGIT: regulator: rpmh-regulator: Add RPMH regulator support for PMR735D Add support for PMR735D PMIC voltage regulators which are present on Kaanapali boards. Signed-off-by: Jishnu Prakash Signed-off-by: Jingyi Wang Reviewed-by: Dmitry Baryshkov Reviewed-by: Krzysztof Kozlowski Signed-off-by: Yijie Yang Link: https://lore.kernel.org/all/20250924-knp-regulator-v1-2-d9cde9a98a44@oss.qualcomm.com/ --- drivers/regulator/qcom-rpmh-regulator.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/regulator/qcom-rpmh-regulator.c b/drivers/regulator/qcom-rpmh-regulator.c index 0a561f1d94523..6e4cb2871fca8 100644 --- a/drivers/regulator/qcom-rpmh-regulator.c +++ b/drivers/regulator/qcom-rpmh-regulator.c @@ -1735,6 +1735,17 @@ static const struct rpmh_vreg_init_data pmr735b_vreg_data[] = { {} }; +static const struct rpmh_vreg_init_data pmr735d_vreg_data[] = { + RPMH_VREG("ldo1", LDO, 1, &pmic5_nldo515, "vdd-l1-l2-l5"), + RPMH_VREG("ldo2", LDO, 2, &pmic5_nldo515, "vdd-l1-l2-l5"), + RPMH_VREG("ldo3", LDO, 3, &pmic5_nldo515, "vdd-l3-l4"), + RPMH_VREG("ldo4", LDO, 4, &pmic5_nldo515, "vdd-l3-l4"), + RPMH_VREG("ldo5", LDO, 5, &pmic5_nldo515, "vdd-l1-l2-l5"), + RPMH_VREG("ldo6", LDO, 6, &pmic5_nldo515, "vdd-l6"), + RPMH_VREG("ldo7", LDO, 7, &pmic5_nldo515, "vdd-l7"), + {} +}; + static const struct rpmh_vreg_init_data pm660_vreg_data[] = { RPMH_VREG("smps1", SMPS, 1, &pmic4_ftsmps426, "vdd-s1"), RPMH_VREG("smps2", SMPS, 2, &pmic4_ftsmps426, "vdd-s2"), @@ -1950,6 +1961,10 @@ static const struct of_device_id __maybe_unused rpmh_regulator_match_table[] = { .compatible = "qcom,pmr735b-rpmh-regulators", .data = pmr735b_vreg_data, }, + { + .compatible = "qcom,pmr735d-rpmh-regulators", + .data = pmr735d_vreg_data, + }, { .compatible = "qcom,pm660-rpmh-regulators", .data = pm660_vreg_data, From 81fc8fbf0f0a02a7b2d855aee574b88bd7d59107 Mon Sep 17 00:00:00 2001 From: Jishnu Prakash Date: Wed, 24 Sep 2025 16:30:47 -0700 Subject: [PATCH 0191/2333] FROMGIT: regulator: dt-bindings: qcom,rpmh: Add support for PMR735D Add support for PMR735D PMIC used on Kaanapali boards. Signed-off-by: Jishnu Prakash Signed-off-by: Jingyi Wang Reviewed-by: Krzysztof Kozlowski Signed-off-by: Yijie Yang Link: https://lore.kernel.org/all/20250924-knp-regulator-v1-1-d9cde9a98a44@oss.qualcomm.com/ --- .../bindings/regulator/qcom,rpmh-regulator.yaml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.yaml b/Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.yaml index 40ddc64577e78..4669095039c8c 100644 --- a/Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.yaml +++ b/Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.yaml @@ -59,6 +59,7 @@ description: | For PMCX0102, smps1 - smps10, ldo1 - ldo4 For PMR735A, smps1 - smps3, ldo1 - ldo7 For PMR735B, ldo1 - ldo12 + For PMR735D, ldo1 - ldo7 For PMX55, smps1 - smps7, ldo1 - ldo16 For PMX65, smps1 - smps8, ldo1 - ldo21 For PMX75, smps1 - smps10, ldo1 - ldo21 @@ -99,6 +100,7 @@ properties: - qcom,pmm8654au-rpmh-regulators - qcom,pmr735a-rpmh-regulators - qcom,pmr735b-rpmh-regulators + - qcom,pmr735d-rpmh-regulators - qcom,pmx55-rpmh-regulators - qcom,pmx65-rpmh-regulators - qcom,pmx75-rpmh-regulators @@ -496,6 +498,18 @@ allOf: patternProperties: "^vdd-l([3-6]|9|1[0-2])-supply$": true + - if: + properties: + compatible: + enum: + - qcom,pmr735d-rpmh-regulators + then: + properties: + vdd-l1-l2-l5-supply: true + vdd-l3-l4-supply: true + patternProperties: + "^vdd-l[6-7]-supply$": true + - if: properties: compatible: From 57bca8ef25e98c56f72e52a5cd5b4e4449ccff81 Mon Sep 17 00:00:00 2001 From: Ayushi Makhija Date: Wed, 26 Nov 2025 09:35:10 +0530 Subject: [PATCH 0192/2333] FROMLIST: arm64: dts: qcom: qcs8300: add Display Serial Interface device nodes Add device tree nodes for the DSI0 controller with their corresponding PHY found on Qualcomm QCS8300 SoC. Signed-off-by: Ayushi Makhija Link: https://lore.kernel.org/all/20251125013302.3835909-5-quic_amakhija@quicinc.com/ Reviewed-by: Dmitry Baryshkov Signed-off-by: Arpit Saini --- arch/arm64/boot/dts/qcom/qcs8300.dtsi | 98 ++++++++++++++++++++++++++- 1 file changed, 97 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/qcs8300.dtsi b/arch/arm64/boot/dts/qcom/qcs8300.dtsi index 4781cdbb4efb0..89435fc5908f9 100644 --- a/arch/arm64/boot/dts/qcom/qcs8300.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs8300.dtsi @@ -3,6 +3,7 @@ * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. */ +#include #include #include #include @@ -5443,6 +5444,13 @@ remote-endpoint = <&mdss_dp0_in>; }; }; + + port@1 { + reg = <1>; + dpu_intf1_out: endpoint { + remote-endpoint = <&mdss_dsi0_in>; + }; + }; }; mdp_opp_table: opp-table { @@ -5470,6 +5478,92 @@ }; }; + mdss_dsi0: dsi@ae94000 { + compatible = "qcom,qcs8300-dsi-ctrl", + "qcom,sa8775p-dsi-ctrl", + "qcom,mdss-dsi-ctrl"; + reg = <0x0 0x0ae94000 0x0 0x400>; + reg-names = "dsi_ctrl"; + + interrupt-parent = <&mdss>; + interrupts = <4>; + + clocks = <&dispcc MDSS_DISP_CC_MDSS_BYTE0_CLK>, + <&dispcc MDSS_DISP_CC_MDSS_BYTE0_INTF_CLK>, + <&dispcc MDSS_DISP_CC_MDSS_PCLK0_CLK>, + <&dispcc MDSS_DISP_CC_MDSS_ESC0_CLK>, + <&dispcc MDSS_DISP_CC_MDSS_AHB_CLK>, + <&gcc GCC_DISP_HF_AXI_CLK>; + clock-names = "byte", + "byte_intf", + "pixel", + "core", + "iface", + "bus"; + + assigned-clocks = <&dispcc MDSS_DISP_CC_MDSS_BYTE0_CLK_SRC>, + <&dispcc MDSS_DISP_CC_MDSS_PCLK0_CLK_SRC>; + assigned-clock-parents = <&mdss_dsi0_phy DSI_BYTE_PLL_CLK>, + <&mdss_dsi0_phy DSI_PIXEL_PLL_CLK>; + + phys = <&mdss_dsi0_phy>; + + operating-points-v2 = <&mdss_dsi_opp_table>; + power-domains = <&rpmhpd RPMHPD_MMCX>; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + mdss_dsi0_in: endpoint { + remote-endpoint = <&dpu_intf1_out>; + }; + }; + + port@1 { + reg = <1>; + mdss_dsi0_out: endpoint { + }; + }; + }; + + mdss_dsi_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-358000000 { + opp-hz = /bits/ 64 <358000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + }; + }; + + mdss_dsi0_phy: phy@ae94400 { + compatible = "qcom,qcs8300-dsi-phy-5nm", + "qcom,sa8775p-dsi-phy-5nm"; + reg = <0x0 0x0ae94400 0x0 0x200>, + <0x0 0x0ae94600 0x0 0x280>, + <0x0 0x0ae94900 0x0 0x27c>; + reg-names = "dsi_phy", + "dsi_phy_lane", + "dsi_pll"; + + #clock-cells = <1>; + #phy-cells = <0>; + + clocks = <&dispcc MDSS_DISP_CC_MDSS_AHB_CLK>, + <&rpmhcc RPMH_CXO_CLK>; + clock-names = "iface", "ref"; + + status = "disabled"; + }; + mdss_dp0_phy: phy@aec2a00 { compatible = "qcom,qcs8300-edp-phy", "qcom,sa8775p-edp-phy"; @@ -5597,7 +5691,9 @@ <&mdss_dp0_phy 0>, <&mdss_dp0_phy 1>, <0>, <0>, - <0>, <0>, <0>, <0>; + <&mdss_dsi0_phy DSI_BYTE_PLL_CLK>, + <&mdss_dsi0_phy DSI_PIXEL_PLL_CLK>, + <0>, <0>; power-domains = <&rpmhpd RPMHPD_MMCX>; #clock-cells = <1>; #reset-cells = <1>; From fe788eadc94070720565f046aa247a52ee148c49 Mon Sep 17 00:00:00 2001 From: Ayushi Makhija Date: Wed, 26 Nov 2025 12:19:38 +0530 Subject: [PATCH 0193/2333] FROMLIST: arm64: dts: qcom: qcs8300-ride: add anx7625 DSI to DP bridge node Add anx7625 DSI to DP bridge device node. Signed-off-by: Ayushi Makhija Link: https://lore.kernel.org/all/20251125013302.3835909-6-quic_amakhija@quicinc.com/ Reviewed-by: Dmitry Baryshkov Signed-off-by: Arpit Saini --- arch/arm64/boot/dts/qcom/qcs8300-ride.dts | 170 ++++++++++++++++++++++ 1 file changed, 170 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/qcs8300-ride.dts b/arch/arm64/boot/dts/qcom/qcs8300-ride.dts index 0509d17a911a7..5d41ab6b1e688 100644 --- a/arch/arm64/boot/dts/qcom/qcs8300-ride.dts +++ b/arch/arm64/boot/dts/qcom/qcs8300-ride.dts @@ -37,6 +37,18 @@ }; }; + dp-dsi0-connector { + compatible = "dp-connector"; + label = "DSI0"; + type = "full-size"; + + port { + dp_dsi0_connector_in: endpoint { + remote-endpoint = <&dsi2dp_bridge_out>; + }; + }; + }; + regulator-usb2-vbus { compatible = "regulator-fixed"; regulator-name = "USB2_VBUS"; @@ -47,6 +59,64 @@ regulator-always-on; }; + vreg_12p0: regulator-vreg-12p0 { + compatible = "regulator-fixed"; + regulator-name = "VREG_12P0"; + + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <12000000>; + regulator-max-microvolt = <12000000>; + }; + + vreg_5p0: regulator-vreg-5p0 { + compatible = "regulator-fixed"; + regulator-name = "VREG_5P0"; + + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + + vin-supply = <&vreg_12p0>; + }; + + vreg_1p8: regulator-vreg-1p8 { + compatible = "regulator-fixed"; + regulator-name = "VREG_1P8"; + + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + + vin-supply = <&vreg_5p0>; + }; + + vreg_1p0: regulator-vreg-1p0 { + compatible = "regulator-fixed"; + regulator-name = "VREG_1P0"; + + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1000000>; + + vin-supply = <&vreg_1p8>; + }; + + vreg_3p0: regulator-vreg-3p0 { + compatible = "regulator-fixed"; + regulator-name = "VREG_3P0"; + + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; + + vin-supply = <&vreg_12p0>; + }; + vreg_conn_1p8: vreg-conn-1p8 { compatible = "regulator-fixed"; regulator-name = "vreg_conn_1p8"; @@ -400,6 +470,70 @@ firmware-name = "qcom/qcs8300/a623_zap.mbn"; }; +&i2c8 { + clock-frequency = <400000>; + status = "okay"; + + io_expander: gpio@74 { + compatible = "ti,tca9539"; + reg = <0x74>; + interrupts-extended = <&tlmm 93 IRQ_TYPE_EDGE_BOTH>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + reset-gpios = <&tlmm 66 GPIO_ACTIVE_LOW>; + + pinctrl-0 = <&io_expander_intr_active>, + <&io_expander_reset_active>; + pinctrl-names = "default"; + }; + + i2c-mux@70 { + compatible = "nxp,pca9543"; + reg = <0x70>; + + #address-cells = <1>; + #size-cells = <0>; + + i2c@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + + bridge@58 { + compatible = "analogix,anx7625"; + reg = <0x58>; + interrupts-extended = <&io_expander 2 IRQ_TYPE_EDGE_FALLING>; + enable-gpios = <&io_expander 1 GPIO_ACTIVE_HIGH>; + reset-gpios = <&io_expander 0 GPIO_ACTIVE_HIGH>; + vdd10-supply = <&vreg_1p0>; + vdd18-supply = <&vreg_1p8>; + vdd33-supply = <&vreg_3p0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + dsi2dp_bridge_in: endpoint { + remote-endpoint = <&mdss_dsi0_out>; + }; + }; + + port@1 { + reg = <1>; + dsi2dp_bridge_out: endpoint { + remote-endpoint = <&dp_dsi0_connector_in>; + }; + }; + }; + }; + }; + }; +}; + &pmm8650au_1_gpios { usb2_en: usb2-en-state { pins = "gpio7"; @@ -437,6 +571,23 @@ status = "okay"; }; +&mdss_dsi0 { + vdda-supply = <&vreg_l5a>; + + status = "okay"; +}; + +&mdss_dsi0_phy { + vdds-supply = <&vreg_l4a>; + + status = "okay"; +}; + +&mdss_dsi0_out { + data-lanes = <0 1 2 3>; + remote-endpoint = <&dsi2dp_bridge_in>; +}; + &pcie0 { pinctrl-0 = <&pcie0_default_state>; pinctrl-names = "default"; @@ -505,6 +656,10 @@ status = "okay"; }; +&qupv3_id_1 { + status = "okay"; +}; + &remoteproc_adsp { firmware-name = "qcom/qcs8300/adsp.mbn"; status = "okay"; @@ -575,6 +730,21 @@ bias-disable; }; + io_expander_intr_active: io-expander-intr-active-state { + pins = "gpio93"; + function = "gpio"; + drive-strength = <2>; + bias-disable; + }; + + io_expander_reset_active: io-expander-reset-active-state { + pins = "gpio66"; + function = "gpio"; + drive-strength = <2>; + bias-disable; + output-high; + }; + pcie0_default_state: pcie0-default-state { wake-pins { pins = "gpio0"; From b017ba7f45d9b2a059da09d19d90bed0b3731c23 Mon Sep 17 00:00:00 2001 From: Vishnu Saini Date: Thu, 20 Nov 2025 16:28:05 +0530 Subject: [PATCH 0194/2333] FROMLIST: arm64: dts: qcom: monaco-evk: add lt8713sx bridge for iq8 Monaco-evk has LT8713sx which act as DP to 3 DP output converter. Edp PHY from monaco soc is connected to lt8713sx as input and output of lt8713sx is connected to 3 mini DP ports. Two of these ports are available in mainboard and one port is available on Mezz board. lt8713sx is connected to soc over i2c0 and with reset gpio connected to pin6 or ioexpander5. Enable the edp nodes from monaco and enable lontium lt8713sx bridge node. Co-developed-by: Prahlad Valluru Signed-off-by: Prahlad Valluru Signed-off-by: Vishnu Saini Link: https://lore.kernel.org/all/20251120-lt8713sx-bridge-linux-for-next-v1-1-2246fc5fb490@qti.qualcomm.com/ --- arch/arm64/boot/dts/qcom/monaco-evk.dts | 44 +++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/monaco-evk.dts b/arch/arm64/boot/dts/qcom/monaco-evk.dts index 492b6407651be..8b4b243b7ee2b 100644 --- a/arch/arm64/boot/dts/qcom/monaco-evk.dts +++ b/arch/arm64/boot/dts/qcom/monaco-evk.dts @@ -398,6 +398,20 @@ firmware-name = "qcom/qcs8300/a623_zap.mbn"; }; +&i2c0 { + pinctrl-0 = <&qup_i2c0_default>; + pinctrl-names = "default"; + + status = "okay"; + + lt8713sx: lt8713sx@4f { + /*Display bridge chip, DP1.4/HDMI2.0/DP++ hub*/ + compatible = "lontium,lt8713sx"; + reg = <0x4f>; + reset-gpios = <&expander5 6 GPIO_ACTIVE_HIGH>; + }; +}; + &i2c1 { pinctrl-0 = <&qup_i2c1_default>; pinctrl-names = "default"; @@ -477,6 +491,23 @@ }; }; +&mdss { + status = "okay"; +}; + +&mdss_dp0 { + status = "okay"; +}; + +&mdss_dp0_out { + data-lanes = <0 1 2 3>; + link-frequencies = /bits/ 64 <1620000000 2700000000 5400000000 8100000000>; +}; + +&mdss_dp0_phy { + status = "okay"; +}; + &iris { status = "okay"; }; @@ -571,6 +602,12 @@ }; &tlmm { + dp_hot_plug_det: dp-hot-plug-det-state { + pins = "gpio94"; + function = "edp0_hot"; + bias-disable; + }; + ethernet0_default: ethernet0-default-state { ethernet0_mdc: ethernet0-mdc-pins { pins = "gpio5"; @@ -633,6 +670,13 @@ }; }; + qup_i2c0_default: qup-i2c0-state { + pins = "gpio17", "gpio18"; + function = "qup0_se0"; + drive-strength = <2>; + bias-pull-up; + }; + qup_i2c1_default: qup-i2c1-state { pins = "gpio19", "gpio20"; function = "qup0_se1"; From a137457c44612bb02b7d6da6860144a8d1d40641 Mon Sep 17 00:00:00 2001 From: Mohd Ayaan Anwar Date: Mon, 24 Nov 2025 14:55:17 +0530 Subject: [PATCH 0195/2333] FROMLIST: dt-bindings: phy: describe additional regulator for Qualcomm SGMII PHY Describe the additional vdda-0p9-supply for the Qualcomm SGMII PHY. Link: https://lore.kernel.org/linux-arm-msm/20251124-sgmiieth_serdes_regulator-v1-0-73ae8f9cbe2a@oss.qualcomm.com/T/#m6e1b5b382e22ef6feac3c6e65e546e3729fa0147 Signed-off-by: Mohd Ayaan Anwar --- .../devicetree/bindings/phy/qcom,sa8775p-dwmac-sgmii-phy.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Documentation/devicetree/bindings/phy/qcom,sa8775p-dwmac-sgmii-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,sa8775p-dwmac-sgmii-phy.yaml index 90fc8c039219c..0a1330b9118d6 100644 --- a/Documentation/devicetree/bindings/phy/qcom,sa8775p-dwmac-sgmii-phy.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,sa8775p-dwmac-sgmii-phy.yaml @@ -36,6 +36,10 @@ properties: description: Phandle to a regulator that provides power to the PHY. + vdda-0p9-supply: + description: + Phandle to a 0.9V regulator supply to the PHY. + "#phy-cells": const: 0 From 457322792a0ec94adeaf45ea4c5f6e76a8e8ba50 Mon Sep 17 00:00:00 2001 From: Mohd Ayaan Anwar Date: Mon, 24 Nov 2025 14:55:18 +0530 Subject: [PATCH 0196/2333] FROMLIST: arm64: dts: qcom: lemans-evk: add additional SerDes PHY regulator Add the additional 0.9V regulator for the Qualcomm SerDes PHY. Link: https://lore.kernel.org/linux-arm-msm/20251124-sgmiieth_serdes_regulator-v1-0-73ae8f9cbe2a@oss.qualcomm.com/T/#m10e0f1595cafd4b88e1e6892ee5bbfdf061a02c6 Fixes: 71ee90ed1756 ("arm64: dts: qcom: lemans-evk: Enable 2.5G Ethernet interface") Signed-off-by: Mohd Ayaan Anwar Reviewed-by: Konrad Dybcio --- arch/arm64/boot/dts/qcom/lemans-evk.dts | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/boot/dts/qcom/lemans-evk.dts b/arch/arm64/boot/dts/qcom/lemans-evk.dts index dd50ed58d1b7e..64e3d231d837a 100644 --- a/arch/arm64/boot/dts/qcom/lemans-evk.dts +++ b/arch/arm64/boot/dts/qcom/lemans-evk.dts @@ -776,6 +776,7 @@ &serdes0 { phy-supply = <&vreg_l5a>; + vdda-0p9-supply = <&vreg_l4a>; status = "okay"; }; From ae04b95f30a6b56d2bbbf59fdb94d45e2be7d0f9 Mon Sep 17 00:00:00 2001 From: Mohd Ayaan Anwar Date: Mon, 24 Nov 2025 14:55:19 +0530 Subject: [PATCH 0197/2333] FROMLIST: arm64: dts: qcom: lemans-ride-common: add additional SerDes PHY regulators Add the additional 0.9V regulators for both of the Qualcomm SerDes PHYs. Link: https://lore.kernel.org/linux-arm-msm/20251124-sgmiieth_serdes_regulator-v1-0-73ae8f9cbe2a@oss.qualcomm.com/T/#m835c4e9fa3f2d0460505dafae6d6a66e61cce8c9 Fixes: 5ef26fb8b3ed ("arm64: dts: qcom: sa8775p-ride: enable the SerDes PHY") Signed-off-by: Mohd Ayaan Anwar Reviewed-by: Konrad Dybcio --- arch/arm64/boot/dts/qcom/lemans-ride-common.dtsi | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/lemans-ride-common.dtsi b/arch/arm64/boot/dts/qcom/lemans-ride-common.dtsi index 357008250c7fb..1b8dbd0eba832 100644 --- a/arch/arm64/boot/dts/qcom/lemans-ride-common.dtsi +++ b/arch/arm64/boot/dts/qcom/lemans-ride-common.dtsi @@ -794,11 +794,15 @@ &serdes0 { phy-supply = <&vreg_l5a>; + vdda-0p9-supply = <&vreg_l4a>; + status = "okay"; }; &serdes1 { phy-supply = <&vreg_l5a>; + vdda-0p9-supply = <&vreg_l4a>; + status = "okay"; }; From 06cd79bf0968decdbc0ad69c5b8152091670d3af Mon Sep 17 00:00:00 2001 From: Mohd Ayaan Anwar Date: Mon, 24 Nov 2025 14:55:20 +0530 Subject: [PATCH 0198/2333] FROMLIST: arm64: dts: qcom: monaco-evk: fix the SerDes PHY regulators The Qualcomm SerDes PHY, present on multiple boards, has two regulators providing supplies of 1.2V (L5A) and 0.9V (L4A). Update the node to reflect the same instead of incorrectly voting for only L4A. Link: https://lore.kernel.org/linux-arm-msm/20251124-sgmiieth_serdes_regulator-v1-0-73ae8f9cbe2a@oss.qualcomm.com/T/#mfd6660dda75ab02044330ddba45590acc8913cd0 Fixes: 117d6bc9326b ("arm64: dts: qcom: qcs8300: Add Monaco EVK board") Reviewed-by: Konrad Dybcio Signed-off-by: Mohd Ayaan Anwar --- arch/arm64/boot/dts/qcom/monaco-evk.dts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/monaco-evk.dts b/arch/arm64/boot/dts/qcom/monaco-evk.dts index 8b4b243b7ee2b..4b3e00444c331 100644 --- a/arch/arm64/boot/dts/qcom/monaco-evk.dts +++ b/arch/arm64/boot/dts/qcom/monaco-evk.dts @@ -586,7 +586,8 @@ }; &serdes0 { - phy-supply = <&vreg_l4a>; + phy-supply = <&vreg_l5a>; + vdda-0p9-supply = <&vreg_l4a>; status = "okay"; }; From 42e779e38be5a316d66b55d6e33beb406a8a55c7 Mon Sep 17 00:00:00 2001 From: Mohd Ayaan Anwar Date: Mon, 24 Nov 2025 14:55:21 +0530 Subject: [PATCH 0199/2333] FROMLIST: arm64: dts: qcom: qcs8300-ride: add additional SerDes PHY regulator Add the additional 0.9V regulator for the Qualcomm SerDes PHY. Link: https://lore.kernel.org/linux-arm-msm/20251124-sgmiieth_serdes_regulator-v1-0-73ae8f9cbe2a@oss.qualcomm.com/T/#m7eceec80e85fa4336a6c60bb99c2beaefe4cb18a Fixes: 787cb3b4c434 ("arm64: dts: qcom: qcs8300-ride: enable ethernet0") Reviewed-by: Konrad Dybcio Signed-off-by: Mohd Ayaan Anwar --- arch/arm64/boot/dts/qcom/qcs8300-ride.dts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/qcs8300-ride.dts b/arch/arm64/boot/dts/qcom/qcs8300-ride.dts index 5d41ab6b1e688..858c1bf4831af 100644 --- a/arch/arm64/boot/dts/qcom/qcs8300-ride.dts +++ b/arch/arm64/boot/dts/qcom/qcs8300-ride.dts @@ -677,6 +677,8 @@ &serdes0 { phy-supply = <&vreg_l5a>; + vdda-0p9-supply = <&vreg_l4a>; + status = "okay"; }; From c280d7e86faa86b16d3c1e313e95207503cf3770 Mon Sep 17 00:00:00 2001 From: Mohd Ayaan Anwar Date: Mon, 24 Nov 2025 14:55:22 +0530 Subject: [PATCH 0200/2333] FROMLIST: phy: qcom: sgmii-eth: add second regulator support The Qualcomm SGMII SerDes PHY requires two regulators to function properly. If both of these are not enabled, the following error is observed: [ 77.105651] qcom-dwmac-sgmii-phy 8909000.phy: QSERDES_COM_C_READY_STATUS timed-out [ 77.113447] qcom-ethqos 23040000.ethernet eth0: __stmmac_open: Serdes powerup failed Therefore, add support for handling the additional regulator in the driver. Link: https://lore.kernel.org/linux-arm-msm/20251124-sgmiieth_serdes_regulator-v1-0-73ae8f9cbe2a@oss.qualcomm.com/T/#m44fe996d0f2a26c428b315959cd0623a0271ac3d Fixes: 601d06277007 ("phy: qcom: add the SGMII SerDes PHY driver") Signed-off-by: Mohd Ayaan Anwar --- drivers/phy/qualcomm/phy-qcom-sgmii-eth.c | 24 ++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/drivers/phy/qualcomm/phy-qcom-sgmii-eth.c b/drivers/phy/qualcomm/phy-qcom-sgmii-eth.c index 5b1c82459c126..5044f244762f4 100644 --- a/drivers/phy/qualcomm/phy-qcom-sgmii-eth.c +++ b/drivers/phy/qualcomm/phy-qcom-sgmii-eth.c @@ -10,6 +10,7 @@ #include #include #include +#include #include "phy-qcom-qmp-pcs-sgmii.h" #include "phy-qcom-qmp-qserdes-com-v5.h" @@ -26,6 +27,7 @@ #define QSERDES_COM_C_PLL_LOCKED BIT(1) struct qcom_dwmac_sgmii_phy_data { + struct regulator *vdda_0p9; struct regmap *regmap; struct clk *refclk; int speed; @@ -266,9 +268,23 @@ static int qcom_dwmac_sgmii_phy_calibrate(struct phy *phy) static int qcom_dwmac_sgmii_phy_power_on(struct phy *phy) { + int ret; struct qcom_dwmac_sgmii_phy_data *data = phy_get_drvdata(phy); - return clk_prepare_enable(data->refclk); + ret = regulator_enable(data->vdda_0p9); + if (ret) + goto out_ret; + + ret = clk_prepare_enable(data->refclk); + if (ret) + goto out_reg_disable; + + return 0; + +out_reg_disable: + regulator_disable(data->vdda_0p9); +out_ret: + return ret; } static int qcom_dwmac_sgmii_phy_power_off(struct phy *phy) @@ -283,6 +299,8 @@ static int qcom_dwmac_sgmii_phy_power_off(struct phy *phy) clk_disable_unprepare(data->refclk); + regulator_disable(data->vdda_0p9); + return 0; } @@ -343,6 +361,10 @@ static int qcom_dwmac_sgmii_phy_probe(struct platform_device *pdev) if (IS_ERR(data->refclk)) return PTR_ERR(data->refclk); + data->vdda_0p9 = devm_regulator_get(dev, "vdda-0p9"); + if (IS_ERR(data->vdda_0p9)) + return PTR_ERR(data->vdda_0p9); + provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); if (IS_ERR(provider)) return PTR_ERR(provider); From 75121cdb51475d7f7f25fbd2b3e8c2e14e835145 Mon Sep 17 00:00:00 2001 From: Komal Bajaj Date: Wed, 22 Oct 2025 14:05:57 +0530 Subject: [PATCH 0201/2333] QCLINUX: Revert "arm64: dts: qcom: sm8750-mtp: Add WiFi and Bluetooth" This reverts commit 141714e163bbb7620d538af48fce4024a4f239e1 due to bootup crash observed on the Pakala MTP device. Signed-off-by: Komal Bajaj --- arch/arm64/boot/dts/qcom/sm8750-mtp.dts | 147 +----------------------- 1 file changed, 4 insertions(+), 143 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm8750-mtp.dts b/arch/arm64/boot/dts/qcom/sm8750-mtp.dts index 3bbb53b7c71f3..946ba53fe63a3 100644 --- a/arch/arm64/boot/dts/qcom/sm8750-mtp.dts +++ b/arch/arm64/boot/dts/qcom/sm8750-mtp.dts @@ -201,74 +201,6 @@ regulator-always-on; regulator-boot-on; }; - - /* - * MTPs rev 2.0 (power grid v8) come with two different WiFi chips: - * WCN7850 and WCN786x. - * Device nodes here for the PMU, WiFi and Bluetooth describe the MTP - * variant with WCN7850. - */ - wcn7850-pmu { - compatible = "qcom,wcn7850-pmu"; - - pinctrl-names = "default"; - pinctrl-0 = <&wlan_en>, <&bt_default>; - - wlan-enable-gpios = <&tlmm 16 GPIO_ACTIVE_HIGH>; - bt-enable-gpios = <&pm8550ve_f_gpios 3 GPIO_ACTIVE_HIGH>; - - vdd-supply = <&vreg_s5f_0p85>; - vddio-supply = <&vreg_l3f_1p8>; - vddio1p2-supply = <&vreg_l2f_1p2>; - vddaon-supply = <&vreg_s4d_0p85>; - vdddig-supply = <&vreg_s1d_0p97>; - vddrfa1p2-supply = <&vreg_s7i_1p2>; - vddrfa1p8-supply = <&vreg_s3g_1p8>; - - clocks = <&rpmhcc RPMH_RF_CLK1>; - - regulators { - vreg_pmu_rfa_cmn: ldo0 { - regulator-name = "vreg_pmu_rfa_cmn"; - }; - - vreg_pmu_aon_0p59: ldo1 { - regulator-name = "vreg_pmu_aon_0p59"; - }; - - vreg_pmu_wlcx_0p8: ldo2 { - regulator-name = "vreg_pmu_wlcx_0p8"; - }; - - vreg_pmu_wlmx_0p85: ldo3 { - regulator-name = "vreg_pmu_wlmx_0p85"; - }; - - vreg_pmu_btcmx_0p85: ldo4 { - regulator-name = "vreg_pmu_btcmx_0p85"; - }; - - vreg_pmu_rfa_0p8: ldo5 { - regulator-name = "vreg_pmu_rfa_0p8"; - }; - - vreg_pmu_rfa_1p2: ldo6 { - regulator-name = "vreg_pmu_rfa_1p2"; - }; - - vreg_pmu_rfa_1p8: ldo7 { - regulator-name = "vreg_pmu_rfa_1p8"; - }; - - vreg_pmu_pcie_0p9: ldo8 { - regulator-name = "vreg_pmu_pcie_0p9"; - }; - - vreg_pmu_pcie_1p8: ldo9 { - regulator-name = "vreg_pmu_pcie_1p8"; - }; - }; - }; }; &apps_rsc { @@ -494,7 +426,7 @@ vreg_s4d_0p85: smps4 { regulator-name = "vreg_s4d_0p85"; - regulator-min-microvolt = <852000>; + regulator-min-microvolt = <500000>; regulator-max-microvolt = <1036000>; regulator-initial-mode = ; }; @@ -540,9 +472,9 @@ qcom,pmic-id = "f"; - vreg_s5f_0p85: smps5 { - regulator-name = "vreg_s5f_0p85"; - regulator-min-microvolt = <852000>; + vreg_s5f_0p5: smps5 { + regulator-name = "vreg_s5f_0p5"; + regulator-min-microvolt = <500000>; regulator-max-microvolt = <1000000>; regulator-initial-mode = ; }; @@ -959,40 +891,6 @@ status = "okay"; }; -&pcie0 { - wake-gpios = <&tlmm 104 GPIO_ACTIVE_HIGH>; - perst-gpios = <&tlmm 102 GPIO_ACTIVE_LOW>; - - pinctrl-0 = <&pcie0_default_state>; - pinctrl-names = "default"; - - status = "okay"; -}; - -&pcie0_phy { - vdda-phy-supply = <&vreg_l1f_0p88>; - vdda-pll-supply = <&vreg_l3g_1p2>; - - status = "okay"; -}; - -&pcieport0 { - wifi@0 { - compatible = "pci17cb,1107"; - reg = <0x10000 0x0 0x0 0x0 0x0>; - - vddrfacmn-supply = <&vreg_pmu_rfa_cmn>; - vddaon-supply = <&vreg_pmu_aon_0p59>; - vddwlcx-supply = <&vreg_pmu_wlcx_0p8>; - vddwlmx-supply = <&vreg_pmu_wlmx_0p85>; - vddrfa0p8-supply = <&vreg_pmu_rfa_0p8>; - vddrfa1p2-supply = <&vreg_pmu_rfa_1p2>; - vddrfa1p8-supply = <&vreg_pmu_rfa_1p8>; - vddpcie0p9-supply = <&vreg_pmu_pcie_0p9>; - vddpcie1p8-supply = <&vreg_pmu_pcie_1p8>; - }; -}; - &pmih0108_eusb2_repeater { status = "okay"; @@ -1004,10 +902,6 @@ status = "okay"; }; -&qupv3_2 { - status = "okay"; -}; - &remoteproc_adsp { firmware-name = "qcom/sm8750/adsp.mbn", "qcom/sm8750/adsp_dtb.mbn"; @@ -1141,14 +1035,6 @@ }; &tlmm { - bt_default: bt-default-state { - sw-ctrl-pins { - pins = "gpio18"; - function = "gpio"; - bias-pull-down; - }; - }; - wcd_default: wcd-reset-n-active-state { pins = "gpio101"; function = "gpio"; @@ -1156,31 +1042,6 @@ bias-disable; output-low; }; - - wlan_en: wlan-en-state { - pins = "gpio16"; - function = "gpio"; - drive-strength = <8>; - bias-pull-down; - }; -}; - -&uart14 { - status = "okay"; - - bluetooth { - compatible = "qcom,wcn7850-bt"; - - vddrfacmn-supply = <&vreg_pmu_rfa_cmn>; - vddaon-supply = <&vreg_pmu_aon_0p59>; - vddwlcx-supply = <&vreg_pmu_wlcx_0p8>; - vddwlmx-supply = <&vreg_pmu_wlmx_0p85>; - vddrfa0p8-supply = <&vreg_pmu_rfa_0p8>; - vddrfa1p2-supply = <&vreg_pmu_rfa_1p2>; - vddrfa1p8-supply = <&vreg_pmu_rfa_1p8>; - - max-speed = <3200000>; - }; }; &ufs_mem_phy { From 6c5fc8cee9039b80ca4388d6e04e0490ec3dfa24 Mon Sep 17 00:00:00 2001 From: Vikram Sharma Date: Thu, 23 Oct 2025 12:28:39 +0530 Subject: [PATCH 0202/2333] QCLINUX: firmware: qcom_scm: Add new scm to update Camera QoS Add new SCM call to program secure camera qos settings. For each NIU camera driver can call this scm API which need each NIU's register offsets, value and number of registers offset that need to be programmed. Signed-off-by: Vikram Sharma --- drivers/firmware/qcom/qcom_scm.c | 45 ++++++++++++++++++++++++++ drivers/firmware/qcom/qcom_scm.h | 3 ++ include/linux/firmware/qcom/qcom_scm.h | 11 +++++++ 3 files changed, 59 insertions(+) diff --git a/drivers/firmware/qcom/qcom_scm.c b/drivers/firmware/qcom/qcom_scm.c index e777b7cb9b127..078cb0bee824f 100644 --- a/drivers/firmware/qcom/qcom_scm.c +++ b/drivers/firmware/qcom/qcom_scm.c @@ -2223,6 +2223,51 @@ bool qcom_scm_is_available(void) } EXPORT_SYMBOL_GPL(qcom_scm_is_available); +int qcom_scm_camera_update_camnoc_qos(uint32_t use_case_id, + uint32_t cam_qos_cnt, struct qcom_scm_camera_qos *cam_qos) +{ + int ret; + dma_addr_t payload_phys; + u32 *payload_buf = NULL; + u32 payload_size = 0; + + if ((cam_qos_cnt > QCOM_SCM_CAMERA_MAX_QOS_CNT) || (cam_qos_cnt && !cam_qos)) { + pr_err("Invalid input SmartQoS count: %d\n", cam_qos_cnt); + return -EINVAL; + } + + struct qcom_scm_desc desc = { + .svc = QCOM_SCM_SVC_CAMERA, + .cmd = QCOM_SCM_CAMERA_UPDATE_CAMNOC_QOS, + .owner = ARM_SMCCC_OWNER_SIP, + .args[0] = use_case_id, + .args[2] = payload_size, + .arginfo = QCOM_SCM_ARGS(3, QCOM_SCM_VAL, QCOM_SCM_RW, QCOM_SCM_VAL), + }; + + payload_size = cam_qos_cnt * sizeof(struct qcom_scm_camera_qos); + + /* fill all required qos settings */ + if (use_case_id && payload_size && cam_qos) { + payload_buf = dma_alloc_coherent(__scm->dev, + payload_size, &payload_phys, GFP_KERNEL); + if (!payload_buf) + return -ENOMEM; + + memcpy(payload_buf, cam_qos, payload_size); + desc.args[1] = payload_phys; + desc.args[2] = payload_size; + + } + ret = qcom_scm_call(__scm->dev, &desc, NULL); + + if (payload_buf) + dma_free_coherent(__scm->dev, payload_size, payload_buf, payload_phys); + + return ret; +} +EXPORT_SYMBOL_GPL(qcom_scm_camera_update_camnoc_qos); + static int qcom_scm_assert_valid_wq_ctx(u32 wq_ctx) { /* FW currently only supports a single wq_ctx (zero). diff --git a/drivers/firmware/qcom/qcom_scm.h b/drivers/firmware/qcom/qcom_scm.h index a56c8212cc0c4..48f2cb83228d6 100644 --- a/drivers/firmware/qcom/qcom_scm.h +++ b/drivers/firmware/qcom/qcom_scm.h @@ -173,6 +173,9 @@ int qcom_scm_shm_bridge_enable(struct device *scm_dev); #define QCOM_SCM_INTERRUPTED 1 #define QCOM_SCM_WAITQ_SLEEP 2 +#define QCOM_SCM_SVC_CAMERA 0x18 +#define QCOM_SCM_CAMERA_UPDATE_CAMNOC_QOS 0xA + static inline int qcom_scm_remap_error(int err) { switch (err) { diff --git a/include/linux/firmware/qcom/qcom_scm.h b/include/linux/firmware/qcom/qcom_scm.h index a55ca771286bf..7c177dec917da 100644 --- a/include/linux/firmware/qcom/qcom_scm.h +++ b/include/linux/firmware/qcom/qcom_scm.h @@ -10,10 +10,12 @@ #include #include +#include #define QCOM_SCM_VERSION(major, minor) (((major) << 16) | ((minor) & 0xFF)) #define QCOM_SCM_CPU_PWR_DOWN_L2_ON 0x0 #define QCOM_SCM_CPU_PWR_DOWN_L2_OFF 0x1 +#define QCOM_SCM_CAMERA_MAX_QOS_CNT 2 #define QCOM_SCM_HDCP_MAX_REQ_CNT 5 struct qcom_scm_hdcp_req { @@ -72,6 +74,15 @@ struct qcom_scm_pas_metadata { ssize_t size; }; +struct qcom_scm_camera_qos { + u32 offset; + u32 val; +}; + +int qcom_scm_camera_update_camnoc_qos(uint32_t use_case_id, + uint32_t qos_cnt, struct qcom_scm_camera_qos *scm_buf); + + int qcom_scm_pas_init_image(u32 peripheral, const void *metadata, size_t size, struct qcom_scm_pas_metadata *ctx); void qcom_scm_pas_metadata_release(struct qcom_scm_pas_metadata *ctx); From 841239d0dc8294a4a9bb5f63b3f4c0dbcf21247f Mon Sep 17 00:00:00 2001 From: Jingyi Wang Date: Mon, 22 Sep 2025 20:34:20 -0700 Subject: [PATCH 0203/2333] FROMLIST: dt-bindings: mailbox: qcom-ipcc: Add bindings for physical client ids Physical client IDs instead of virtual client IDs are used for qcom new platforms in the Inter Process Communication Controller (IPCC) driver as virtual physical mapping logic is removed in HW. Add the bindings. Signed-off-by: Jingyi Wang Signed-off-by: Yijie Yang Link: https://lore.kernel.org/all/20250922-ipcc-header-v1-1-f0b12715e118@oss.qualcomm.com/ --- include/dt-bindings/mailbox/qcom-ipcc.h | 48 +++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/include/dt-bindings/mailbox/qcom-ipcc.h b/include/dt-bindings/mailbox/qcom-ipcc.h index fd85a79381b31..dc07ca27db09d 100644 --- a/include/dt-bindings/mailbox/qcom-ipcc.h +++ b/include/dt-bindings/mailbox/qcom-ipcc.h @@ -36,4 +36,52 @@ #define IPCC_CLIENT_GPDSP0 31 #define IPCC_CLIENT_GPDSP1 32 +/* Physical client IDs */ +#define IPCC_MPROC_AOP 0 +#define IPCC_MPROC_TZ 1 +#define IPCC_MPROC_MPSS 2 +#define IPCC_MPROC_LPASS 3 +#define IPCC_MPROC_SDC 4 +#define IPCC_MPROC_CDSP 5 +#define IPCC_MPROC_APSS 6 +#define IPCC_MPROC_SOCCP 13 +#define IPCC_MPROC_DCP 14 +#define IPCC_MPROC_SPSS 15 +#define IPCC_MPROC_TME 16 + +#define IPCC_COMPUTE_L0_CDSP 2 +#define IPCC_COMPUTE_L0_APSS 3 +#define IPCC_COMPUTE_L0_GPU 4 +#define IPCC_COMPUTE_L0_CVP 8 +#define IPCC_COMPUTE_L0_CAM 9 +#define IPCC_COMPUTE_L0_CAM1 10 +#define IPCC_COMPUTE_L0_DCP 11 +#define IPCC_COMPUTE_L0_VPU 12 +#define IPCC_COMPUTE_L0_SOCCP 16 + +#define IPCC_COMPUTE_L1_CDSP 2 +#define IPCC_COMPUTE_L1_APSS 3 +#define IPCC_COMPUTE_L1_GPU 4 +#define IPCC_COMPUTE_L1_CVP 8 +#define IPCC_COMPUTE_L1_CAM 9 +#define IPCC_COMPUTE_L1_CAM1 10 +#define IPCC_COMPUTE_L1_DCP 11 +#define IPCC_COMPUTE_L1_VPU 12 +#define IPCC_COMPUTE_L1_SOCCP 16 + +#define IPCC_PERIPH_CDSP 2 +#define IPCC_PERIPH_APSS 3 +#define IPCC_PERIPH_PCIE0 4 +#define IPCC_PERIPH_PCIE1 5 + +#define IPCC_FENCE_CDSP 2 +#define IPCC_FENCE_APSS 3 +#define IPCC_FENCE_GPU 4 +#define IPCC_FENCE_CVP 8 +#define IPCC_FENCE_CAM 8 +#define IPCC_FENCE_VPU 20 +#define IPCC_FENCE_SOCCP 24 +#define IPCC_FENCE_CAM1 10 +#define IPCC_FENCE_DCP 11 + #endif From 32998bbef522f5cb37374467b732d89442bcfdc6 Mon Sep 17 00:00:00 2001 From: Krishna Chaitanya Chundru Date: Thu, 27 Nov 2025 17:28:29 +0530 Subject: [PATCH 0204/2333] QCLINUX: arch: arm64: qcom: qcs8300-ride: Enable PCIe Qref regulator PCIe phy needs to be voted for QREF regulator, As the base dtsi changes are still pending we haven't posted the actual fix. Till we post actual fix to upstream, use this change as a workaround. Signed-off-by: Krishna Chaitanya Chundru --- arch/arm64/boot/dts/qcom/qcs8300-ride.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/qcs8300-ride.dts b/arch/arm64/boot/dts/qcom/qcs8300-ride.dts index 858c1bf4831af..010209b0eadb9 100644 --- a/arch/arm64/boot/dts/qcom/qcs8300-ride.dts +++ b/arch/arm64/boot/dts/qcom/qcs8300-ride.dts @@ -602,7 +602,7 @@ &pcie0_phy { vdda-phy-supply = <&vreg_l6a>; - vdda-pll-supply = <&vreg_l5a>; + vdda-pll-supply = <&vreg_l4a>; status = "okay"; }; From dc971666d63a5ebf84df3c98f552a50a8c586ed7 Mon Sep 17 00:00:00 2001 From: Chris Lew Date: Mon, 3 Nov 2025 20:59:28 +0530 Subject: [PATCH 0205/2333] FROMLIST: soc: qcom: smp2p: Add irqchip state support A remoteproc booted during earlier boot stages such as UEFI or the bootloader, may need to be attached to without restarting the remoteproc hardware. To do this the remoteproc will need to check the ready and handover states in smp2p without an interrupt notification. Add support for the .irq_get_irqchip_state callback so remoteproc can read the current state of the fatal, ready and handover bits. Link: https://lore.kernel.org/r/20251103152929.2434911-2-deepak.singh@oss.qualcomm.com Signed-off-by: Chris Lew Signed-off-by: Deepak Kumar Singh --- drivers/soc/qcom/smp2p.c | 61 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/drivers/soc/qcom/smp2p.c b/drivers/soc/qcom/smp2p.c index cb515c2340c10..39628df367458 100644 --- a/drivers/soc/qcom/smp2p.c +++ b/drivers/soc/qcom/smp2p.c @@ -48,6 +48,9 @@ #define SMP2P_MAGIC 0x504d5324 #define SMP2P_ALL_FEATURES SMP2P_FEATURE_SSR_ACK +#define ONE 1 +#define TWO 2 + /** * struct smp2p_smem_item - in memory communication structure * @magic: magic number @@ -222,6 +225,42 @@ static void qcom_smp2p_negotiate(struct qcom_smp2p *smp2p) } } +static void qcom_smp2p_start_in(struct qcom_smp2p *smp2p) +{ + unsigned int smem_id = smp2p->smem_items[SMP2P_INBOUND]; + unsigned int pid = smp2p->remote_pid; + char buf[SMP2P_MAX_ENTRY_NAME]; + struct smp2p_smem_item *in; + struct smp2p_entry *entry; + size_t size; + int i; + + in = qcom_smem_get(pid, smem_id, &size); + if (IS_ERR(in)) + return; + + smp2p->in = in; + + /* Check if version is initialized and set to v2. + * Early enumeration of inbound entries is required only + * for early boot processors which have smp2p version 2. + */ + if (in->version != TWO) + return; + + for (i = smp2p->valid_entries; i < in->valid_entries; i++) { + list_for_each_entry(entry, &smp2p->inbound, node) { + memcpy(buf, in->entries[i].name, sizeof(buf)); + if (!strcmp(buf, entry->name)) { + entry->value = &in->entries[i].value; + entry->last_value = readl(entry->value); + break; + } + } + } + smp2p->valid_entries = i; +} + static void qcom_smp2p_notify_in(struct qcom_smp2p *smp2p) { struct smp2p_smem_item *in; @@ -368,12 +407,31 @@ static void smp2p_irq_print_chip(struct irq_data *irqd, struct seq_file *p) seq_printf(p, "%8s", dev_name(entry->smp2p->dev)); } +static int smp2p_irq_get_irqchip_state(struct irq_data *irqd, enum irqchip_irq_state which, + bool *state) +{ + struct smp2p_entry *entry = irq_data_get_irq_chip_data(irqd); + u32 val; + + if (which != IRQCHIP_STATE_LINE_LEVEL) + return -EINVAL; + + if (!entry->value) + return -ENODEV; + + val = readl(entry->value); + *state = !!(val & BIT(irqd_to_hwirq(irqd))); + + return 0; +} + static struct irq_chip smp2p_irq_chip = { .name = "smp2p", .irq_mask = smp2p_mask_irq, .irq_unmask = smp2p_unmask_irq, .irq_set_type = smp2p_set_irq_type, .irq_print_chip = smp2p_irq_print_chip, + .irq_get_irqchip_state = smp2p_irq_get_irqchip_state, }; static int smp2p_irq_map(struct irq_domain *d, @@ -618,6 +676,9 @@ static int qcom_smp2p_probe(struct platform_device *pdev) } } + /* Check inbound entries in the case of early boot processor */ + qcom_smp2p_start_in(smp2p); + /* Kick the outgoing edge after allocating entries */ qcom_smp2p_kick(smp2p); From 2cf103048fa6404ba91ace93c35997fee43b7f7d Mon Sep 17 00:00:00 2001 From: Chris Lew Date: Mon, 3 Nov 2025 20:59:29 +0530 Subject: [PATCH 0206/2333] FROMLIST: soc: qcom: smp2p: Add support for smp2p v2 Some remoteproc need smp2p v2 support, mirror the version written by the remote if the remote supports v2. This is needed if the remote does not have backwards compatibility with v1. And reset entry last value on SSR for smp2p v2. Link: https://lore.kernel.org/r/20251103152929.2434911-3-deepak.singh@oss.qualcomm.com Signed-off-by: Chris Lew Signed-off-by: Deepak Kumar Singh --- drivers/soc/qcom/smp2p.c | 41 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/drivers/soc/qcom/smp2p.c b/drivers/soc/qcom/smp2p.c index 39628df367458..c35ca7535c144 100644 --- a/drivers/soc/qcom/smp2p.c +++ b/drivers/soc/qcom/smp2p.c @@ -36,6 +36,10 @@ * The driver uses the Linux GPIO and interrupt framework to expose a virtual * GPIO for each outbound entry and a virtual interrupt controller for each * inbound entry. + * + * Driver supports two versions: + * V1 - For processor that start after local host + * V2 - For processor that start in early boot sequence */ #define SMP2P_MAX_ENTRY 16 @@ -50,11 +54,12 @@ #define ONE 1 #define TWO 2 +#define MAX_VERSION TWO /** * struct smp2p_smem_item - in memory communication structure * @magic: magic number - * @version: version - must be 1 + * @version: version * @features: features flag - currently unused * @local_pid: processor id of sending end * @remote_pid: processor id of receiving end @@ -183,14 +188,23 @@ static void qcom_smp2p_kick(struct qcom_smp2p *smp2p) static bool qcom_smp2p_check_ssr(struct qcom_smp2p *smp2p) { struct smp2p_smem_item *in = smp2p->in; + struct smp2p_entry *entry; bool restart; if (!smp2p->ssr_ack_enabled) return false; restart = in->flags & BIT(SMP2P_FLAGS_RESTART_DONE_BIT); + restart = restart != smp2p->ssr_ack; + if (restart && in->version > ONE) { + list_for_each_entry(entry, &smp2p->inbound, node) { + if (!entry->value) + continue; + entry->last_value = 0; + } + } - return restart != smp2p->ssr_ack; + return restart; } static void qcom_smp2p_do_ssr_ack(struct qcom_smp2p *smp2p) @@ -225,6 +239,20 @@ static void qcom_smp2p_negotiate(struct qcom_smp2p *smp2p) } } +static int qcom_smp2p_in_version(struct qcom_smp2p *smp2p) +{ + unsigned int smem_id = smp2p->smem_items[SMP2P_INBOUND]; + unsigned int pid = smp2p->remote_pid; + struct smp2p_smem_item *in; + size_t size; + + in = qcom_smem_get(pid, smem_id, &size); + if (IS_ERR(in)) + return 0; + + return in->version; +} + static void qcom_smp2p_start_in(struct qcom_smp2p *smp2p) { unsigned int smem_id = smp2p->smem_items[SMP2P_INBOUND]; @@ -522,6 +550,7 @@ static int qcom_smp2p_alloc_outbound_item(struct qcom_smp2p *smp2p) struct smp2p_smem_item *out; unsigned smem_id = smp2p->smem_items[SMP2P_OUTBOUND]; unsigned pid = smp2p->remote_pid; + u8 in_version; int ret; ret = qcom_smem_alloc(pid, smem_id, sizeof(*out)); @@ -543,12 +572,18 @@ static int qcom_smp2p_alloc_outbound_item(struct qcom_smp2p *smp2p) out->valid_entries = 0; out->features = SMP2P_ALL_FEATURES; + in_version = qcom_smp2p_in_version(smp2p); + if (in_version > MAX_VERSION) { + dev_err(smp2p->dev, "Unsupported smp2p version\n"); + return -EINVAL; + } + /* * Make sure the rest of the header is written before we validate the * item by writing a valid version number. */ wmb(); - out->version = 1; + out->version = (in_version) ? in_version : 1; qcom_smp2p_kick(smp2p); From 6b1b38f795d74447bf85d062c17c7d954ea5ea15 Mon Sep 17 00:00:00 2001 From: Komal Bajaj Date: Thu, 29 May 2025 17:06:00 +0530 Subject: [PATCH 0207/2333] QCLINUX: defconfig: Introduce prune.config fragment Add prune.config fragment to disable support for non-Qualcomm architectures. This helps reduce boot image size and improves kernel build KPIs by trimming unnecessary configuration options. Signed-off-by: Komal Bajaj --- arch/arm64/configs/prune.config | 326 ++++++++++++++++++++++++++++++++ 1 file changed, 326 insertions(+) create mode 100644 arch/arm64/configs/prune.config diff --git a/arch/arm64/configs/prune.config b/arch/arm64/configs/prune.config new file mode 100644 index 0000000000000..54cf8fa1cd0e0 --- /dev/null +++ b/arch/arm64/configs/prune.config @@ -0,0 +1,326 @@ +# CONFIG_ARCH_ACTIONS is not set +# CONFIG_ARCH_AIROHA is not set +# CONFIG_ARCH_SUNXI is not set +# CONFIG_ARCH_ALPINE is not set +# CONFIG_ARCH_APPLE is not set +# CONFIG_ARCH_BCM is not set +# CONFIG_ARCH_BCM2835 is not set +# CONFIG_ARCH_BCM_IPROC is not set +# CONFIG_ARCH_BCMBCA is not set +# CONFIG_ARCH_BRCMSTB is not set +# CONFIG_ARCH_BERLIN is not set +# CONFIG_ARCH_BLAIZE is not set +# CONFIG_ARCH_EXYNOS is not set +# CONFIG_ARCH_SPARX5 is not set +# CONFIG_ARCH_K3 is not set +# CONFIG_ARCH_LG1K is not set +# CONFIG_ARCH_HISI is not set +# CONFIG_ARCH_KEEMBAY is not set +# CONFIG_ARCH_MEDIATEK is not set +# CONFIG_ARCH_MESON is not set +# CONFIG_ARCH_MVEBU is not set +# CONFIG_ARCH_NXP is not set +# CONFIG_ARCH_MA35 is not set +# CONFIG_ARCH_NPCM is not set +# CONFIG_ARCH_REALTEK is not set +# CONFIG_ARCH_RENESAS is not set +# CONFIG_ARCH_ROCKCHIP is not set +# CONFIG_ARCH_SEATTLE is not set +# CONFIG_ARCH_INTEL_SOCFPGA is not set +# CONFIG_ARCH_STM32 is not set +# CONFIG_ARCH_SYNQUACER is not set +# CONFIG_ARCH_TEGRA is not set +# CONFIG_ARCH_TESLA_FSD is not set +# CONFIG_ARCH_SPRD is not set +# CONFIG_ARCH_THUNDER is not set +# CONFIG_ARCH_THUNDER2 is not set +# CONFIG_ARCH_UNIPHIER is not set +# CONFIG_ARCH_VEXPRESS is not set +# CONFIG_ARCH_VISCONTI is not set +# CONFIG_ARCH_XGENE is not set +# CONFIG_ARCH_ZYNQMP is not set +# CONFIG_MOUSE_PS2 is not set +# CONFIG_RODATA_FULL_DEFAULT_ENABLED is not set +# CONFIG_NET_DSA_TAG_OCELOT is not set +# CONFIG_NET_DSA_TAG_OCELOT_8021Q is not set +# CONFIG_BT_HCIBTUSB_MTK is not set +# CONFIG_BT_HCIUART_BCM is not set +# CONFIG_BT_HCIUART_MRVL is not set +# CONFIG_BT_MRVL is not set +# CONFIG_BT_MRVL_SDIO is not set +# CONFIG_PCIE_ALTERA is not set +# CONFIG_PCIE_ALTERA_MSI is not set +# CONFIG_PCI_HOST_THUNDER_PEM is not set +# CONFIG_PCI_HOST_THUNDER_ECAM is not set +# CONFIG_PCI_XGENE is not set +# CONFIG_PCI_MESON is not set +# CONFIG_PCI_HISI is not set +# CONFIG_PCIE_KIRIN is not set +# CONFIG_BRCMSTB_GISB_ARB is not set +# CONFIG_VEXPRESS_CONFIG is not set +# CONFIG_GNSS_MTK_SERIAL is not set +# CONFIG_MTD_CFI_INTELEXT is not set +# CONFIG_MTD_CFI_AMDSTD is not set +# CONFIG_MTD_CFI_STAA is not set +# CONFIG_MTD_NAND_DENALI_DT is not set +# CONFIG_MTD_NAND_BRCMNAND is not set +# CONFIG_MTD_NAND_BRCMNAND_BCMBCA is not set +# CONFIG_MTD_NAND_BRCMNAND_BRCMSTB is not set +# CONFIG_MTD_NAND_BRCMNAND_IPROC is not set +# CONFIG_B53_SRAB_DRIVER is not set +# CONFIG_NET_DSA_BCM_SF2 is not set +# CONFIG_AMD_XGBE is not set +# CONFIG_BCMGENET is not set +# CONFIG_BNX2X is not set +# CONFIG_SYSTEMPORT is not set +# CONFIG_MACB is not set +# CONFIG_THUNDER_NIC_PF is not set +# CONFIG_HIX5HD2_GMAC is not set +# CONFIG_HNS_DSAF is not set +# CONFIG_HNS_ENET is not set +# CONFIG_HNS3 is not set +# CONFIG_HNS3_HCLGE is not set +# CONFIG_HNS3_ENET is not set +# CONFIG_MVMDIO is not set +# CONFIG_SKY2 is not set +# CONFIG_MLX4_EN is not set +# CONFIG_MLX5_CORE is not set +# CONFIG_MLX5_CORE_EN is not set +# CONFIG_R8169 is not set +# CONFIG_SMC91X is not set +# CONFIG_SMSC911X is not set +# CONFIG_BROADCOM_PHY is not set +# CONFIG_BCM54140_PHY is not set +# CONFIG_MICROSEMI_PHY is not set +# CONFIG_REALTEK_PHY is not set +# CONFIG_ROCKCHIP_PHY is not set +# CONFIG_DP83867_PHY is not set +# CONFIG_DP83TD510_PHY is not set +# CONFIG_VITESSE_PHY is not set +# CONFIG_CAN_FLEXCAN is not set +# CONFIG_CAN_MCP251XFD is not set +# CONFIG_BRCMFMAC is not set +# CONFIG_MWIFIEX is not set +# CONFIG_MWIFIEX_SDIO is not set +# CONFIG_MWIFIEX_PCIE is not set +# CONFIG_MT7921E is not set +# CONFIG_WL18XX is not set +# CONFIG_WLCORE_SDIO is not set +# CONFIG_KEYBOARD_CROS_EC is not set +# CONFIG_KEYBOARD_MTK_PMIC is not set +# CONFIG_MOUSE_ELAN_I2C is not set +# CONFIG_TOUCHSCREEN_ATMEL_MXT is not set +# CONFIG_TOUCHSCREEN_GOODIX is not set +# CONFIG_TOUCHSCREEN_ELAN is not set +# CONFIG_TOUCHSCREEN_EDT_FT5X06 is not set +# CONFIG_INPUT_TPS65219_PWRBUTTON is not set +# CONFIG_SERIAL_XILINX_PS_UART is not set +# CONFIG_SERIAL_XILINX_PS_UART_CONSOLE is not set +# CONFIG_SERIAL_FSL_LPUART is not set +# CONFIG_SERIAL_FSL_LPUART_CONSOLE is not set +# CONFIG_SERIAL_FSL_LINFLEXUART is not set +# CONFIG_SERIAL_FSL_LINFLEXUART_CONSOLE is not set +# CONFIG_TCG_TIS_SPI_CR50 is not set +# CONFIG_TCG_TIS_I2C_CR50 is not set +# CONFIG_TCG_TIS_I2C_INFINEON is not set +# CONFIG_I2C_CADENCE is not set +# CONFIG_I2C_DESIGNWARE_PLATFORM is not set +# CONFIG_I2C_RK3X is not set +# CONFIG_I2C_CROS_EC_TUNNEL is not set +# CONFIG_SPI_CADENCE_QUADSPI is not set +# CONFIG_SPI_DESIGNWARE is not set +# CONFIG_SPI_DW_DMA is not set +# CONFIG_SPI_DW_MMIO is not set +# CONFIG_PINCTRL_MAX77620 is not set +# CONFIG_CHARGER_MT6360 is not set +# CONFIG_CHARGER_BQ25890 is not set +# CONFIG_CHARGER_BQ25980 is not set +# CONFIG_SENSORS_JC42 is not set +# CONFIG_SENSORS_LM75 is not set +# CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_INA2XX is not set +# CONFIG_SENSORS_INA3221 is not set +# CONFIG_ARM_SP805_WATCHDOG is not set +# CONFIG_DW_WATCHDOG is not set +# CONFIG_PM8916_WATCHDOG is not set +# CONFIG_MFD_BD9571MWV is not set +# CONFIG_MFD_AXP20X_I2C is not set +# CONFIG_MFD_HI6421_PMIC is not set +# CONFIG_MFD_MAX77620 is not set +# CONFIG_MFD_MT6360 is not set +# CONFIG_MFD_MT6397 is not set +# CONFIG_MFD_RK8XX_I2C is not set +# CONFIG_MFD_RK8XX_SPI is not set +# CONFIG_MFD_SEC_CORE is not set +# CONFIG_MFD_TI_AM335X_TSCADC is not set +# CONFIG_MFD_TPS65219 is not set +# CONFIG_MFD_WM8994 is not set +# CONFIG_MFD_ROHM_BD718XX is not set +# CONFIG_REGULATOR_AXP20X is not set +# CONFIG_REGULATOR_BD718XX is not set +# CONFIG_REGULATOR_BD9571MWV is not set +# CONFIG_REGULATOR_CROS_EC is not set +# CONFIG_REGULATOR_FAN53555 is not set +# CONFIG_REGULATOR_HI6421V530 is not set +# CONFIG_REGULATOR_MAX77620 is not set +# CONFIG_REGULATOR_MAX8973 is not set +# CONFIG_REGULATOR_MP8859 is not set +# CONFIG_REGULATOR_MT6315 is not set +# CONFIG_REGULATOR_MT6357 is not set +# CONFIG_REGULATOR_MT6358 is not set +# CONFIG_REGULATOR_MT6359 is not set +# CONFIG_REGULATOR_MT6360 is not set +# CONFIG_REGULATOR_MT6397 is not set +# CONFIG_REGULATOR_PFUZE100 is not set +# CONFIG_REGULATOR_RK808 is not set +# CONFIG_REGULATOR_S2MPS11 is not set +# CONFIG_REGULATOR_TPS65132 is not set +# CONFIG_REGULATOR_TPS65219 is not set +# CONFIG_REGULATOR_RK808 is not set +# CONFIG_REGULATOR_S2MPS11 is not set +# CONFIG_REGULATOR_TPS65132 is not set +# CONFIG_REGULATOR_TPS65219 is not set +# CONFIG_MEDIA_ANALOG_TV_SUPPORT is not set +# CONFIG_MEDIA_DIGITAL_TV_SUPPORT is not set +# CONFIG_VIDEO_IMX219 is not set +# CONFIG_VIDEO_OV5640 is not set +# CONFIG_VIDEO_OV5645 is not set +# CONFIG_DRM_I2C_NXP_TDA998X is not set +# CONFIG_DRM_MALI_DISPLAY is not set +# CONFIG_DRM_KOMEDA is not set +# CONFIG_DRM_NOUVEAU is not set +# CONFIG_DRM_PANEL_BOE_TV101WUM_NL6 is not set +# CONFIG_DRM_PANEL_MANTIX_MLAF057WE51 is not set +# CONFIG_DRM_PANEL_RAYDIUM_RM67191 is not set +# CONFIG_DRM_PANEL_SITRONIX_ST7703 is not set +# CONFIG_DRM_PANEL_TRULY_NT35597_WQXGA is not set +# CONFIG_DRM_PANEL_VISIONOX_VTDR6130 is not set +# CONFIG_DRM_LONTIUM_LT8912B is not set +# CONFIG_DRM_NWL_MIPI_DSI is not set +# CONFIG_DRM_PARADE_PS8640 is not set +# CONFIG_DRM_SAMSUNG_DSIM is not set +# CONFIG_DRM_SII902X is not set +# CONFIG_DRM_SIMPLE_BRIDGE is not set +# CONFIG_DRM_THINE_THC63LVD1024 is not set +# CONFIG_DRM_TOSHIBA_TC358768 is not set +# CONFIG_DRM_TI_TFP410 is not set +# CONFIG_DRM_TI_SN65DSI83 is not set +# CONFIG_DRM_TI_SN65DSI86 is not set +# CONFIG_DRM_I2C_ADV7511_AUDIO is not set +# CONFIG_DRM_CDNS_MHDP8546 is not set +# CONFIG_DRM_ETNAVIV is not set +# CONFIG_DRM_HISI_HIBMC is not set +# CONFIG_DRM_HISI_KIRIN is not set +# CONFIG_DRM_PL111 is not set +# CONFIG_DRM_LIMA is not set +# CONFIG_DRM_PANFROST is not set +# CONFIG_DRM_TIDSS is not set +# CONFIG_BACKLIGHT_LP855X is not set +# CONFIG_SND_SOC_FSL_ASRC is not set +# CONFIG_SND_SOC_FSL_SAI is not set +# CONFIG_SND_SOC_FSL_AUDMIX is not set +# CONFIG_SND_SOC_FSL_SSI is not set +# CONFIG_SND_SOC_FSL_SPDIF is not set +# CONFIG_SND_SOC_FSL_ESAI is not set +# CONFIG_SND_SOC_FSL_MICFIL is not set +# CONFIG_SND_SOC_FSL_EASRC is not set +# CONFIG_SND_SOC_IMX_AUDMUX is not set +# CONFIG_SND_SOC_AK4613 is not set +# CONFIG_SND_SOC_ES7134 is not set +# CONFIG_SND_SOC_ES7241 is not set +# CONFIG_SND_SOC_ES8316 is not set +# CONFIG_SND_SOC_GTM601 is not set +# CONFIG_SND_SOC_PCM3168A_I2C is not set +# CONFIG_SND_SOC_RT5640 is not set +# CONFIG_SND_SOC_RT5659 is not set +# CONFIG_SND_SOC_TAS2552 is not set +# CONFIG_SND_SOC_TAS571X is not set +# CONFIG_SND_SOC_TLV320AIC31XX is not set +# CONFIG_SND_SOC_TLV320AIC32X4_I2C is not set +# CONFIG_SND_SOC_TLV320AIC3X_I2C is not set +# CONFIG_SND_SOC_TS3A227E is not set +# CONFIG_SND_SOC_WM8524 is not set +# CONFIG_SND_SOC_WM8904 is not set +# CONFIG_SND_SOC_WM8960 is not set +# CONFIG_SND_SOC_WM8962 is not set +# CONFIG_SND_SOC_WM8978 is not set +# CONFIG_SND_SOC_MT6358 is not set +# CONFIG_SND_SOC_NAU8822 is not set +# CONFIG_MMC_SDHCI_OF_ARASAN is not set +# CONFIG_MMC_SDHCI_OF_DWCMSHC is not set +# CONFIG_MMC_SDHCI_CADENCE is not set +# CONFIG_MMC_SDHCI_F_SDH30 is not set +# CONFIG_MMC_DW_EXYNOS is not set +# CONFIG_MMC_DW_HI3798CV200 is not set +# CONFIG_MMC_DW_K3 is not set +# CONFIG_MMC_MTK is not set +# CONFIG_MMC_SDHCI_XENON is not set +# CONFIG_MMC_SDHCI_AM654 is not set +# CONFIG_RTC_DRV_DS1307 is not set +# CONFIG_RTC_DRV_HYM8563 is not set +# CONFIG_RTC_DRV_MAX77686 is not set +# CONFIG_RTC_DRV_RK808 is not set +# CONFIG_RTC_DRV_PCF85063 is not set +# CONFIG_RTC_DRV_PCF85363 is not set +# CONFIG_RTC_DRV_M41T80 is not set +# CONFIG_RTC_DRV_BQ32K is not set +# CONFIG_RTC_DRV_RX8581 is not set +# CONFIG_RTC_DRV_RV3028 is not set +# CONFIG_RTC_DRV_RV8803 is not set +# CONFIG_RTC_DRV_S5M is not set +# CONFIG_RTC_DRV_DS3232 is not set +# CONFIG_RTC_DRV_PCF2127 is not set +# CONFIG_RTC_DRV_CROS_EC is not set +# CONFIG_RTC_DRV_MT6397 is not set +# CONFIG_BCM_SBA_RAID is not set +# CONFIG_FSL_EDMA is not set +# CONFIG_MV_XOR_V2 is not set +# CONFIG_CHROME_PLATFORMS is not set +# CONFIG_CROS_EC is not set +# CONFIG_CROS_EC_I2C is not set +# CONFIG_CROS_EC_RPMSG is not set +# CONFIG_CROS_EC_SPI is not set +# CONFIG_CROS_EC_CHARDEV is not set +# CONFIG_CLK_VEXPRESS_OSC is not set +# CONFIG_COMMON_CLK_RK808 is not set +# CONFIG_COMMON_CLK_CS2000_CP is not set +# CONFIG_COMMON_CLK_S2MPS11 is not set +# CONFIG_COMMON_CLK_XGENE is not set +# CONFIG_COMMON_CLK_RS9_PCIE is not set +# CONFIG_COMMON_CLK_VC5 is not set +# CONFIG_COMMON_CLK_BD718XX is not set +# CONFIG_SOC_TI is not set +# CONFIG_TI_ADS1015 is not set +# CONFIG_TI_AM335X_ADC is not set +# CONFIG_IIO_CROS_EC_SENSORS_CORE is not set +# CONFIG_IIO_CROS_EC_SENSORS is not set +# CONFIG_IIO_ST_LSM6DSX is not set +# CONFIG_IIO_CROS_EC_LIGHT_PROX is not set +# CONFIG_SENSORS_ISL29018 is not set +# CONFIG_VCNL4000 is not set +# CONFIG_IIO_ST_MAGN_3AXIS is not set +# CONFIG_IIO_CROS_EC_BARO is not set +# CONFIG_MPL3115 is not set +# CONFIG_PWM_CROS_EC is not set +# CONFIG_PHY_CADENCE_TORRENT is not set +# CONFIG_PHY_CADENCE_SIERRA is not set +# CONFIG_CRYPTO_DEV_HISI_SEC2 is not set +# CONFIG_CRYPTO_DEV_HISI_ZIP is not set +# CONFIG_CRYPTO_DEV_HISI_HPRE is not set +# CONFIG_CRYPTO_DEV_HISI_TRNG is not set +# CONFIG_CRYPTO_DEV_AMLOGIC_GXL is not set +# CONFIG_DEVMEM is not set +# CONFIG_STRICT_DEVMEM is not set +# CONFIG_ACORN_PARTITION is not set +# CONFIG_AIX_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_CMDLINE_PARTITION is not set +# CONFIG_KARMA_PARTITION is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_SYSV68_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set From 747d265506279815c52df73fcf1c8e2c3f2e3941 Mon Sep 17 00:00:00 2001 From: Komal Bajaj Date: Tue, 23 Sep 2025 14:20:27 +0530 Subject: [PATCH 0208/2333] QCLINUX: defconfig: Define qcom.config and enable DMABUF heaps Introduce `qcom.config`, a Qualcomm-specific kernel configuration fragment that enables features required by Qualcomm SoCs. It includes CONFIGs not acceptable under the community's common defconfig and ensures essential features and subsystems required by Qualcomm platforms are enbaled. This initial version of `qcom.config` enables DMABUF heap support, including the system heap and default CMA heap. These configurations are essential for buffer sharing across subsystems such as camera, display, and DSP on Qualcomm platforms like qcs6490. Signed-off-by: Komal Bajaj --- arch/arm64/configs/qcom.config | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 arch/arm64/configs/qcom.config diff --git a/arch/arm64/configs/qcom.config b/arch/arm64/configs/qcom.config new file mode 100644 index 0000000000000..7458e86bdc06c --- /dev/null +++ b/arch/arm64/configs/qcom.config @@ -0,0 +1,8 @@ +# qcom.config for Qualcomm-specific kernel configuration +# +# $ make ARCH=arm64 defconfig qcom.config +# +# Keep alphabetically sorted +CONFIG_DMABUF_HEAPS=y +CONFIG_DMABUF_HEAPS_CMA=y +CONFIG_DMABUF_HEAPS_SYSTEM=y From 1520aa520822d2d73d10e654a927902914f5bc57 Mon Sep 17 00:00:00 2001 From: Jie Gan Date: Fri, 26 Sep 2025 10:08:11 +0800 Subject: [PATCH 0209/2333] QCLINUX: arch: arm64: configs: Enable coresight components in qcom.config Add Coresight configs to enable Coresight device drivers on mainline. Signed-off-by: Jie Gan --- arch/arm64/configs/qcom.config | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/arm64/configs/qcom.config b/arch/arm64/configs/qcom.config index 7458e86bdc06c..52b94c17169d0 100644 --- a/arch/arm64/configs/qcom.config +++ b/arch/arm64/configs/qcom.config @@ -3,6 +3,12 @@ # $ make ARCH=arm64 defconfig qcom.config # # Keep alphabetically sorted +CONFIG_CORESIGHT_CORESIGHT_TNOC=m +CONFIG_CORESIGHT_CTCU=m +CONFIG_CORESIGHT_DUMMY=m +CONFIG_CORESIGHT_SOURCE_ETM4X=m +CONFIG_CORESIGHT_TGU=m +CONFIG_CORESIGHT_TPDM=m CONFIG_DMABUF_HEAPS=y CONFIG_DMABUF_HEAPS_CMA=y CONFIG_DMABUF_HEAPS_SYSTEM=y From 58de27c17970152a90d1fe9660961ebc91edf279 Mon Sep 17 00:00:00 2001 From: Charan Teja Kalla Date: Tue, 30 Sep 2025 18:27:55 +0530 Subject: [PATCH 0210/2333] QCLINUX: defconfig: enable zram defconfig on qcom.config Enable ZRAM defconfig on qcom.config. This empowers users to use the compressed block devices for usecases, eg: swap device on zram. Tested: make ARCH=arm64 menuconfig defconfig qcom.config, booted with this configuration on QEMU and verified if /dev/zram0 is exist. Signed-off-by: Charan Teja Kalla --- arch/arm64/configs/qcom.config | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/configs/qcom.config b/arch/arm64/configs/qcom.config index 52b94c17169d0..93e642c519059 100644 --- a/arch/arm64/configs/qcom.config +++ b/arch/arm64/configs/qcom.config @@ -12,3 +12,4 @@ CONFIG_CORESIGHT_TPDM=m CONFIG_DMABUF_HEAPS=y CONFIG_DMABUF_HEAPS_CMA=y CONFIG_DMABUF_HEAPS_SYSTEM=y +CONFIG_ZRAM=y From e4c78c4f150b79369a16341b2784cf8aac827db0 Mon Sep 17 00:00:00 2001 From: Komal Bajaj Date: Mon, 6 Oct 2025 16:56:58 +0530 Subject: [PATCH 0211/2333] QCLINUX: defconfig: Enable scheduler and thermal related configs Enabled key configs for thermal management (CPU_IDLE_THERMAL, IDLE_INJECT), scheduler (SCHED_DEBUG, SCHEDSTATS, TRACE_MMIO_ACCESS), and power control (POWERCAP, UCLAMP_TASK). Also enabled KPROBES, PAN emulation and watchdog pretimeout panic governor for improved instrumentation and security. Signed-off-by: Komal Bajaj --- arch/arm64/configs/qcom.config | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/arch/arm64/configs/qcom.config b/arch/arm64/configs/qcom.config index 93e642c519059..9cd2b50f8b367 100644 --- a/arch/arm64/configs/qcom.config +++ b/arch/arm64/configs/qcom.config @@ -3,13 +3,30 @@ # $ make ARCH=arm64 defconfig qcom.config # # Keep alphabetically sorted +CONFIG_ARM64_SW_TTBR0_PAN=y CONFIG_CORESIGHT_CORESIGHT_TNOC=m CONFIG_CORESIGHT_CTCU=m CONFIG_CORESIGHT_DUMMY=m CONFIG_CORESIGHT_SOURCE_ETM4X=m CONFIG_CORESIGHT_TGU=m CONFIG_CORESIGHT_TPDM=m +CONFIG_CPU_IDLE_THERMAL=y +# CONFIG_DEBUG_INFO_REDUCED is not set CONFIG_DMABUF_HEAPS=y CONFIG_DMABUF_HEAPS_CMA=y CONFIG_DMABUF_HEAPS_SYSTEM=y +CONFIG_IDLE_INJECT=y +CONFIG_KPROBES=y +CONFIG_POWERCAP=y +CONFIG_SCHED_DEBUG=y +CONFIG_SCHEDSTATS=y +CONFIG_TRACE_MMIO_ACCESS=y +CONFIG_UCLAMP_TASK_GROUP=y +CONFIG_UCLAMP_TASK=y +# CONFIG_WATCHDOG_PRETIMEOUT_DEFAULT_GOV_NOOP is not set +CONFIG_WATCHDOG_PRETIMEOUT_DEFAULT_GOV_PANIC=y +CONFIG_WATCHDOG_PRETIMEOUT_GOV_NOOP=y +CONFIG_WATCHDOG_PRETIMEOUT_GOV_PANIC=y +CONFIG_WATCHDOG_PRETIMEOUT_GOV_SEL=m +CONFIG_WATCHDOG_PRETIMEOUT_GOV=y CONFIG_ZRAM=y From 30cb0cdb224bad3b7ec4eeb2cfc361656758a57f Mon Sep 17 00:00:00 2001 From: Komal Bajaj Date: Mon, 6 Oct 2025 17:11:01 +0530 Subject: [PATCH 0212/2333] QCLINUX: debug: Enable additional Qualcomm-specific debug configs Enabled various debug-related kernel config options to improve system diagnostics and aid in development and issue analysis. Signed-off-by: Komal Bajaj --- kernel/configs/debug.config | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/kernel/configs/debug.config b/kernel/configs/debug.config index e81327d2cd639..15e6caa8811a0 100644 --- a/kernel/configs/debug.config +++ b/kernel/configs/debug.config @@ -117,3 +117,12 @@ CONFIG_FUNCTION_TRACER=y # CONFIG_DEBUG_PREEMPT=y CONFIG_PREEMPT=y + +# +# Qualcomm Debug Configs +# +CONFIG_CMA_DEBUG=y +CONFIG_DEBUG_LIST=y +CONFIG_DEBUG_PAGEALLOC=y +# CONFIG_FW_LOADER_DEBUG is not set +CONFIG_HARDLOCKUP_DETECTOR=y From e3fcdeafca64d895356639d0376c8edd422e9053 Mon Sep 17 00:00:00 2001 From: Jie Gan Date: Fri, 31 Oct 2025 15:58:40 +0800 Subject: [PATCH 0213/2333] QCLINUX: arch: arm64: configs: Enable stm components in qcom.config Add STM configs to enable STM functions, like stm ftrace and stm heartbeat. Signed-off-by: Jie Gan --- arch/arm64/configs/qcom.config | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/arm64/configs/qcom.config b/arch/arm64/configs/qcom.config index 9cd2b50f8b367..00e740e4e29de 100644 --- a/arch/arm64/configs/qcom.config +++ b/arch/arm64/configs/qcom.config @@ -20,6 +20,11 @@ CONFIG_KPROBES=y CONFIG_POWERCAP=y CONFIG_SCHED_DEBUG=y CONFIG_SCHEDSTATS=y +CONFIG_STM_PROTO_BASIC=m +CONFIG_STM_PROTO_SYS_T=m +CONFIG_STM_SOURCE_CONSOLE=m +CONFIG_STM_SOURCE_FTRACE=m +CONFIG_STM_SOURCE_HEARTBEAT=m CONFIG_TRACE_MMIO_ACCESS=y CONFIG_UCLAMP_TASK_GROUP=y CONFIG_UCLAMP_TASK=y From e5653010642e57bcd3960e2ef25b1506ee09046a Mon Sep 17 00:00:00 2001 From: Jingyi Wang Date: Wed, 24 Sep 2025 17:05:34 -0700 Subject: [PATCH 0214/2333] FROMLIST: arm64: defconfig: enable GCC, interconnect and pinctrl for Kaanapali The serial engine must be properly setup before kernel reash "init", so UART driver and its dependencies needs to be built in. Enable its dependency GCC, interconnect and pinctrl as built-in to boot Kaanapali QRD and MTP board to UART console. Signed-off-by: Jingyi Wang Signed-off-by: Yijie Yang Link: https://lore.kernel.org/all/20250924-knp-config-v1-1-e2cf83b1932e@oss.qualcomm.com/ --- arch/arm64/configs/defconfig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig index 1a48faad2473a..3c85a0c888614 100644 --- a/arch/arm64/configs/defconfig +++ b/arch/arm64/configs/defconfig @@ -622,6 +622,7 @@ CONFIG_PINCTRL_IPQ5424=y CONFIG_PINCTRL_IPQ8074=y CONFIG_PINCTRL_IPQ6018=y CONFIG_PINCTRL_IPQ9574=y +CONFIG_PINCTRL_KAANAPALI=y CONFIG_PINCTRL_MSM8916=y CONFIG_PINCTRL_MSM8953=y CONFIG_PINCTRL_MSM8976=y @@ -1363,6 +1364,7 @@ CONFIG_COMMON_CLK_MT8192_SCP_ADSP=y CONFIG_COMMON_CLK_MT8192_VDECSYS=y CONFIG_COMMON_CLK_MT8192_VENCSYS=y CONFIG_COMMON_CLK_QCOM=y +CONFIG_CLK_KAANAPALI_GCC=y CONFIG_CLK_X1E80100_CAMCC=m CONFIG_CLK_X1E80100_DISPCC=m CONFIG_CLK_X1E80100_GCC=y @@ -1718,6 +1720,7 @@ CONFIG_INTERCONNECT_IMX8MN=m CONFIG_INTERCONNECT_IMX8MQ=m CONFIG_INTERCONNECT_IMX8MP=y CONFIG_INTERCONNECT_QCOM=y +CONFIG_INTERCONNECT_QCOM_KAANAPALI=y CONFIG_INTERCONNECT_QCOM_MSM8916=m CONFIG_INTERCONNECT_QCOM_MSM8996=y CONFIG_INTERCONNECT_QCOM_OSM_L3=m From 895cb9198edfdafe98337d2ff0f8e3846c6fb244 Mon Sep 17 00:00:00 2001 From: Wenjia Zhang Date: Tue, 4 Nov 2025 17:35:07 +0800 Subject: [PATCH 0215/2333] QCLINUX: defconfig: enable Crypto and ICE related configs Enabled key config of Crypto (CONFIG_CRYPTO_USER_API, CONFIG_CRYPTO_USER_API_HASH, CONFIG_CRYPTO_USER_API_SKCIPHER, CONFIG_CRYPTO_USER_API_AEAD). And else for support ICE config. Signed-off-by: Wenjia Zhang --- arch/arm64/configs/qcom.config | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/arch/arm64/configs/qcom.config b/arch/arm64/configs/qcom.config index 00e740e4e29de..68f9420987e84 100644 --- a/arch/arm64/configs/qcom.config +++ b/arch/arm64/configs/qcom.config @@ -35,3 +35,20 @@ CONFIG_WATCHDOG_PRETIMEOUT_GOV_PANIC=y CONFIG_WATCHDOG_PRETIMEOUT_GOV_SEL=m CONFIG_WATCHDOG_PRETIMEOUT_GOV=y CONFIG_ZRAM=y + +# Add config to support Crypto and ICE +CONFIG_SCSI_UFS_QCOM=y +CONFIG_CRYPTO_USER_API=y +CONFIG_CRYPTO_USER_API_HASH=y +CONFIG_CRYPTO_USER_API_SKCIPHER=y +CONFIG_CRYPTO_USER_API_AEAD=y +CONFIG_BLK_INLINE_ENCRYPTION=y +CONFIG_FS_ENCRYPTION=y +CONFIG_FS_ENCRYPTION_INLINE_CRYPT=y +CONFIG_FS_ENCRYPTION_INLINE_CRYPT_FALLBACK=y +CONFIG_FS_ENCRYPTION_HW_WRAPPED_KEYS=y +CONFIG_SCSI_UFS_CRYPTO=y +CONFIG_QCOM_INLINE_CRYPTO_ENGINE=y +CONFIG_CRYPTO_DEV_QCOM_ICE=y +CONFIG_BLK_INLINE_ENCRYPTION_HW_WRAPPED_KEYS=y + From e665d30ca3942f9e325289cb2e00390f6445bcaa Mon Sep 17 00:00:00 2001 From: Gaurav Kohli Date: Wed, 5 Nov 2025 14:26:27 +0530 Subject: [PATCH 0216/2333] QCLINUX: defconfig: enable amc6821 defconfig on qcom.config Enable SENSOR_AMC6821 defconfig to enable fan controller support. Signed-off-by: Gaurav Kohli --- arch/arm64/configs/qcom.config | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/configs/qcom.config b/arch/arm64/configs/qcom.config index 68f9420987e84..ad4bb73a69202 100644 --- a/arch/arm64/configs/qcom.config +++ b/arch/arm64/configs/qcom.config @@ -25,6 +25,7 @@ CONFIG_STM_PROTO_SYS_T=m CONFIG_STM_SOURCE_CONSOLE=m CONFIG_STM_SOURCE_FTRACE=m CONFIG_STM_SOURCE_HEARTBEAT=m +CONFIG_SENSORS_AMC6821=y CONFIG_TRACE_MMIO_ACCESS=y CONFIG_UCLAMP_TASK_GROUP=y CONFIG_UCLAMP_TASK=y From d549d2fa1a4594702a3423d970a576a07d6dc7db Mon Sep 17 00:00:00 2001 From: Mohd Ayaan Anwar Date: Thu, 13 Nov 2025 14:59:19 +0530 Subject: [PATCH 0217/2333] QCLINUX: defconfig: Enable QCA808X ethernet phy config Enable the config for the QCA808X ethernet PHY driver. Ethernet is non functional without this driver on Lemans and Monaco EVK. Signed-off-by: Mohd Ayaan Anwar --- arch/arm64/configs/qcom.config | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/configs/qcom.config b/arch/arm64/configs/qcom.config index ad4bb73a69202..24fba94365ed2 100644 --- a/arch/arm64/configs/qcom.config +++ b/arch/arm64/configs/qcom.config @@ -18,6 +18,7 @@ CONFIG_DMABUF_HEAPS_SYSTEM=y CONFIG_IDLE_INJECT=y CONFIG_KPROBES=y CONFIG_POWERCAP=y +CONFIG_QCA808X_PHY=m CONFIG_SCHED_DEBUG=y CONFIG_SCHEDSTATS=y CONFIG_STM_PROTO_BASIC=m From 69b95482029dc2d02d30f51155e3bf04a5e058bb Mon Sep 17 00:00:00 2001 From: Fange Zhang Date: Wed, 20 Aug 2025 16:53:30 +0800 Subject: [PATCH 0218/2333] FROMLIST: arm64: defconfig: Enable SX150x GPIO expander driver The ANX7625 bridge on the Qualcomm QCS615 Ride reference board is connected to a Semtech SX150x GPIO expander. Enable the SX150x driver to make the display on boards built following this design functional. Signed-off-by: Fange Zhang Link: https://lore.kernel.org/all/20251105-enable-sx150x-gpio-expander-v3-1-2ec8dfde2c9e@oss.qualcomm.com/ Signed-off-by: Yongxing Mou --- arch/arm64/configs/defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig index 3c85a0c888614..dbdf6dba72d30 100644 --- a/arch/arm64/configs/defconfig +++ b/arch/arm64/configs/defconfig @@ -602,6 +602,7 @@ CONFIG_PINCTRL_DA9062=m CONFIG_PINCTRL_MAX77620=y CONFIG_PINCTRL_RK805=m CONFIG_PINCTRL_SINGLE=y +CONFIG_PINCTRL_SX150X=m CONFIG_PINCTRL_OWL=y CONFIG_PINCTRL_S700=y CONFIG_PINCTRL_S900=y From 5be2b983097663d2b7599469596fc7c39a2628cf Mon Sep 17 00:00:00 2001 From: Komal Bajaj Date: Fri, 14 Nov 2025 19:08:45 +0530 Subject: [PATCH 0219/2333] QCLINUX: defconfig: Enable EDAC_QCOM on qcom.config Enable QCOM EDAC driver support for QCOM SoCs. Signed-off-by: Komal Bajaj --- arch/arm64/configs/qcom.config | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/configs/qcom.config b/arch/arm64/configs/qcom.config index 24fba94365ed2..5358c519a2102 100644 --- a/arch/arm64/configs/qcom.config +++ b/arch/arm64/configs/qcom.config @@ -15,6 +15,7 @@ CONFIG_CPU_IDLE_THERMAL=y CONFIG_DMABUF_HEAPS=y CONFIG_DMABUF_HEAPS_CMA=y CONFIG_DMABUF_HEAPS_SYSTEM=y +CONFIG_EDAC_QCOM=m CONFIG_IDLE_INJECT=y CONFIG_KPROBES=y CONFIG_POWERCAP=y From 7c4846c38d965c110cc465e6a3b5969ab3f27b43 Mon Sep 17 00:00:00 2001 From: Yingying Tang Date: Wed, 12 Nov 2025 11:29:07 +0800 Subject: [PATCH 0220/2333] QCLINUX: debug: Enable WLAN related debug configs Enable WLAN related debug configs. Signed-off-by: Yingying Tang --- kernel/configs/debug.config | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/kernel/configs/debug.config b/kernel/configs/debug.config index 15e6caa8811a0..a03143cf3088f 100644 --- a/kernel/configs/debug.config +++ b/kernel/configs/debug.config @@ -121,8 +121,31 @@ CONFIG_PREEMPT=y # # Qualcomm Debug Configs # +CONFIG_ATH11K_COREDUMP=y +CONFIG_ATH11K_DEBUG=y +CONFIG_ATH11K_DEBUGFS=y +CONFIG_ATH11K_TRACING=y +CONFIG_ATH12K_DEBUG=y +CONFIG_ATH12K_DEBUGFS=y +CONFIG_ATH12K_TRACING=y +CONFIG_ATH12K_COREDUMP=y +CONFIG_CFG80211_DEBUGFS=y CONFIG_CMA_DEBUG=y CONFIG_DEBUG_LIST=y CONFIG_DEBUG_PAGEALLOC=y +CONFIG_DYNAMIC_FTRACE_WITH_REGS=y +CONFIG_FTRACE_SYSCALLS=y +CONFIG_FUNCTION_GRAPH_TRACER=y # CONFIG_FW_LOADER_DEBUG is not set CONFIG_HARDLOCKUP_DETECTOR=y +CONFIG_IRQSOFF_TRACER=y +CONFIG_KPROBE_EVENTS=y +CONFIG_MAC80211_DEBUGFS=y +CONFIG_NL80211_TESTMODE=y +CONFIG_PREEMPT_TRACER=y +CONFIG_PREEMPTIRQ_TRACEPOINTS=y +CONFIG_SCHED_TRACER=y +CONFIG_STACK_TRACER=y +CONFIG_TRACEPOINTS=y +CONFIG_TRACING=y +CONFIG_UPROBE_EVENTS=y From 1546d2bf36e6e6f95b6718671664a7c8efd40a84 Mon Sep 17 00:00:00 2001 From: Yingying Tang Date: Wed, 12 Nov 2025 12:01:17 +0800 Subject: [PATCH 0221/2333] QCLINUX: defconfig: Enable ATH reg setting Enable ATH reg setting, then user can change country code by netlink command. Signed-off-by: Yingying Tang --- arch/arm64/configs/qcom.config | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm64/configs/qcom.config b/arch/arm64/configs/qcom.config index 5358c519a2102..f024f6b9a39dd 100644 --- a/arch/arm64/configs/qcom.config +++ b/arch/arm64/configs/qcom.config @@ -4,6 +4,8 @@ # # Keep alphabetically sorted CONFIG_ARM64_SW_TTBR0_PAN=y +CONFIG_ATH_REG_DYNAMIC_USER_REG_HINTS=y +CONFIG_CFG80211_CERTIFICATION_ONUS=y CONFIG_CORESIGHT_CORESIGHT_TNOC=m CONFIG_CORESIGHT_CTCU=m CONFIG_CORESIGHT_DUMMY=m @@ -16,6 +18,7 @@ CONFIG_DMABUF_HEAPS=y CONFIG_DMABUF_HEAPS_CMA=y CONFIG_DMABUF_HEAPS_SYSTEM=y CONFIG_EDAC_QCOM=m +CONFIG_EXPERT=y CONFIG_IDLE_INJECT=y CONFIG_KPROBES=y CONFIG_POWERCAP=y From 796cfaeefdc360775f5a1b62e10c3723fdd11baf Mon Sep 17 00:00:00 2001 From: Wei Deng Date: Wed, 19 Nov 2025 19:55:44 +0530 Subject: [PATCH 0222/2333] QCLINUX: defconfig: Enable BT_RFCOMM, BT_BNEP and UHID Enable as modules the BT_BNEP and BT_RFCOMM drivers which are required for Bluetooth profiles such as PAN and SPP. Without these modules, PAN and SPP functionality will not be available. Enable UHID support to allow HID over GATT operations. Without this, user-space cannot create virtual HID devices, which impacts HID profile usage over Bluetooth. Signed-off-by: Wei Deng --- arch/arm64/configs/qcom.config | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/arm64/configs/qcom.config b/arch/arm64/configs/qcom.config index f024f6b9a39dd..3fb7c7776c892 100644 --- a/arch/arm64/configs/qcom.config +++ b/arch/arm64/configs/qcom.config @@ -5,6 +5,11 @@ # Keep alphabetically sorted CONFIG_ARM64_SW_TTBR0_PAN=y CONFIG_ATH_REG_DYNAMIC_USER_REG_HINTS=y +CONFIG_BT_BNEP=m +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +CONFIG_BT_RFCOMM=m +CONFIG_BT_RFCOMM_TTY=y CONFIG_CFG80211_CERTIFICATION_ONUS=y CONFIG_CORESIGHT_CORESIGHT_TNOC=m CONFIG_CORESIGHT_CTCU=m @@ -34,6 +39,7 @@ CONFIG_SENSORS_AMC6821=y CONFIG_TRACE_MMIO_ACCESS=y CONFIG_UCLAMP_TASK_GROUP=y CONFIG_UCLAMP_TASK=y +CONFIG_UHID=m # CONFIG_WATCHDOG_PRETIMEOUT_DEFAULT_GOV_NOOP is not set CONFIG_WATCHDOG_PRETIMEOUT_DEFAULT_GOV_PANIC=y CONFIG_WATCHDOG_PRETIMEOUT_GOV_NOOP=y From eb3b532d27fe047a7896b080729ccabdf44edcab Mon Sep 17 00:00:00 2001 From: Maulik Shah Date: Fri, 21 Nov 2025 10:01:00 +0530 Subject: [PATCH 0223/2333] QCLINUX: defconfig: Enable various power management configs Enable various PM configs to enable suspend-resume. Signed-off-by: Maulik Shah --- arch/arm64/configs/qcom.config | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/arm64/configs/qcom.config b/arch/arm64/configs/qcom.config index 3fb7c7776c892..8311dc4f933e9 100644 --- a/arch/arm64/configs/qcom.config +++ b/arch/arm64/configs/qcom.config @@ -26,6 +26,13 @@ CONFIG_EDAC_QCOM=m CONFIG_EXPERT=y CONFIG_IDLE_INJECT=y CONFIG_KPROBES=y +CONFIG_PM_SLEEP=y +CONFIG_PM_SLEEP_SMP=y +CONFIG_PM_AUTOSLEEP=y +CONFIG_PM_WAKELOCKS=y +CONFIG_PM_WAKELOCKS_LIMIT=0 +# CONFIG_PM_WAKELOCKS_GC is not set +CONFIG_PM=y CONFIG_POWERCAP=y CONFIG_QCA808X_PHY=m CONFIG_SCHED_DEBUG=y From 12aa9344efb0c7c2df9130236c871823779bc657 Mon Sep 17 00:00:00 2001 From: Maulik Shah Date: Fri, 21 Nov 2025 13:32:46 +0530 Subject: [PATCH 0224/2333] QCLINUX: debug: Enable power management debug configs Enabled various power management debug related kernel config options to improve system diagnostics and aid in development and issue analysis. Signed-off-by: Maulik Shah --- kernel/configs/debug.config | 3 +++ 1 file changed, 3 insertions(+) diff --git a/kernel/configs/debug.config b/kernel/configs/debug.config index a03143cf3088f..6d30537210f98 100644 --- a/kernel/configs/debug.config +++ b/kernel/configs/debug.config @@ -144,6 +144,9 @@ CONFIG_MAC80211_DEBUGFS=y CONFIG_NL80211_TESTMODE=y CONFIG_PREEMPT_TRACER=y CONFIG_PREEMPTIRQ_TRACEPOINTS=y +CONFIG_PM_ADVANCED_DEBUG=y +CONFIG_PM_DEBUG=y +CONFIG_PM_SLEEP_DEBUG=y CONFIG_SCHED_TRACER=y CONFIG_STACK_TRACER=y CONFIG_TRACEPOINTS=y From b566557de8519d64ae0022c235cbbe51c01e7495 Mon Sep 17 00:00:00 2001 From: Vishnu Saini Date: Thu, 20 Nov 2025 16:28:06 +0530 Subject: [PATCH 0225/2333] FROMLIST: defconfig: qcom: Enable lt8713sx bridge driver Lontium LT8713sx DP bridge hub can be found in monaco-evk for converting 1 DP to 3 DP output. Co-developed-by: Prahlad Valluru Signed-off-by: Prahlad Valluru Signed-off-by: Vishnu Saini Link: https://lore.kernel.org/all/20251120-lt8713sx-bridge-linux-for-next-v1-2-2246fc5fb490@qti.qualcomm.com/ --- arch/arm64/configs/defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig index dbdf6dba72d30..e565477a6fb19 100644 --- a/arch/arm64/configs/defconfig +++ b/arch/arm64/configs/defconfig @@ -949,6 +949,7 @@ CONFIG_DRM_PANEL_VISIONOX_VTDR6130=m CONFIG_DRM_DISPLAY_CONNECTOR=m CONFIG_DRM_FSL_LDB=m CONFIG_DRM_ITE_IT6263=m +CONFIG_DRM_LONTIUM_LT8713SX=m CONFIG_DRM_LONTIUM_LT8912B=m CONFIG_DRM_LONTIUM_LT9611=m CONFIG_DRM_LONTIUM_LT9611UXC=m From c48ef386df71e820e80dc187e75ee2f0ec8a92bf Mon Sep 17 00:00:00 2001 From: Komal Bajaj Date: Thu, 27 Nov 2025 15:03:55 +0530 Subject: [PATCH 0226/2333] QCLINUX: Revert "QCLINUX: defconfig: enable Crypto and ICE related configs" Revert commit 68f6c9a13767b281d3859caf834fbdd3c027ee22. Enabling ICE-related configurations causes crashes on the lemans-evk device, so this change is being reverted until the issue is resolved. Signed-off-by: Komal Bajaj --- arch/arm64/configs/qcom.config | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/arch/arm64/configs/qcom.config b/arch/arm64/configs/qcom.config index 8311dc4f933e9..4133da26d73aa 100644 --- a/arch/arm64/configs/qcom.config +++ b/arch/arm64/configs/qcom.config @@ -54,20 +54,3 @@ CONFIG_WATCHDOG_PRETIMEOUT_GOV_PANIC=y CONFIG_WATCHDOG_PRETIMEOUT_GOV_SEL=m CONFIG_WATCHDOG_PRETIMEOUT_GOV=y CONFIG_ZRAM=y - -# Add config to support Crypto and ICE -CONFIG_SCSI_UFS_QCOM=y -CONFIG_CRYPTO_USER_API=y -CONFIG_CRYPTO_USER_API_HASH=y -CONFIG_CRYPTO_USER_API_SKCIPHER=y -CONFIG_CRYPTO_USER_API_AEAD=y -CONFIG_BLK_INLINE_ENCRYPTION=y -CONFIG_FS_ENCRYPTION=y -CONFIG_FS_ENCRYPTION_INLINE_CRYPT=y -CONFIG_FS_ENCRYPTION_INLINE_CRYPT_FALLBACK=y -CONFIG_FS_ENCRYPTION_HW_WRAPPED_KEYS=y -CONFIG_SCSI_UFS_CRYPTO=y -CONFIG_QCOM_INLINE_CRYPTO_ENGINE=y -CONFIG_CRYPTO_DEV_QCOM_ICE=y -CONFIG_BLK_INLINE_ENCRYPTION_HW_WRAPPED_KEYS=y - From bd46231f724bd58ef61544ef2c74f571f0116356 Mon Sep 17 00:00:00 2001 From: Nikhil V Date: Thu, 27 Nov 2025 15:15:16 +0530 Subject: [PATCH 0227/2333] QCLINUX: defconfig: Enable watchdog drivers for VM usecases CrosVM supports vCPU Stall watchdog. QEMU supports I6300 ESB watchdog. Enable corresponding drivers for Guest VM usecases. Signed-off-by: Nikhil V --- arch/arm64/configs/qcom.config | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm64/configs/qcom.config b/arch/arm64/configs/qcom.config index 4133da26d73aa..5fa9e6af25edb 100644 --- a/arch/arm64/configs/qcom.config +++ b/arch/arm64/configs/qcom.config @@ -24,6 +24,7 @@ CONFIG_DMABUF_HEAPS_CMA=y CONFIG_DMABUF_HEAPS_SYSTEM=y CONFIG_EDAC_QCOM=m CONFIG_EXPERT=y +CONFIG_I6300ESB_WDT=y CONFIG_IDLE_INJECT=y CONFIG_KPROBES=y CONFIG_PM_SLEEP=y @@ -47,6 +48,7 @@ CONFIG_TRACE_MMIO_ACCESS=y CONFIG_UCLAMP_TASK_GROUP=y CONFIG_UCLAMP_TASK=y CONFIG_UHID=m +CONFIG_VCPU_STALL_DETECTOR=y # CONFIG_WATCHDOG_PRETIMEOUT_DEFAULT_GOV_NOOP is not set CONFIG_WATCHDOG_PRETIMEOUT_DEFAULT_GOV_PANIC=y CONFIG_WATCHDOG_PRETIMEOUT_GOV_NOOP=y From 54590c0522234f6a8bf449f16388237e55ee01c6 Mon Sep 17 00:00:00 2001 From: Komal Bajaj Date: Fri, 28 Nov 2025 12:38:09 +0530 Subject: [PATCH 0228/2333] QCLINUX: debug.config: Drop heavy debug configs Removed UBSAN, KASAN, kmemleak, lock proving, and function tracing from debug.config to reduce bootup time and prevent probe deferring issues. Signed-off-by: Komal Bajaj --- kernel/configs/debug.config | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/kernel/configs/debug.config b/kernel/configs/debug.config index 6d30537210f98..8da4b25b1f4db 100644 --- a/kernel/configs/debug.config +++ b/kernel/configs/debug.config @@ -33,12 +33,12 @@ CONFIG_SECTION_MISMATCH_WARN_ONLY=y CONFIG_DEBUG_FS=y CONFIG_DEBUG_FS_ALLOW_ALL=y CONFIG_DEBUG_IRQFLAGS=y -CONFIG_UBSAN=y -CONFIG_UBSAN_BOOL=y -CONFIG_UBSAN_BOUNDS=y -CONFIG_UBSAN_ENUM=y -CONFIG_UBSAN_SHIFT=y -CONFIG_UBSAN_UNREACHABLE=y +# CONFIG_UBSAN is not set +# CONFIG_UBSAN_BOOL is not set +# CONFIG_UBSAN_BOUNDS is not set +# CONFIG_UBSAN_ENUM is not set +# CONFIG_UBSAN_SHIFT is not set +# CONFIG_UBSAN_UNREACHABLE is not set # # Networking Debugging # @@ -57,8 +57,8 @@ CONFIG_DEBUG_NET=y # CONFIG_SLUB_STATS is not set CONFIG_PAGE_EXTENSION=y CONFIG_PAGE_OWNER=y -CONFIG_DEBUG_KMEMLEAK=y -CONFIG_DEBUG_KMEMLEAK_AUTO_SCAN=y +# CONFIG_DEBUG_KMEMLEAK is not set +# CONFIG_DEBUG_KMEMLEAK_AUTO_SCAN is not set CONFIG_DEBUG_OBJECTS=y CONFIG_DEBUG_OBJECTS_ENABLE_DEFAULT=1 CONFIG_DEBUG_OBJECTS_FREE=y @@ -73,10 +73,10 @@ CONFIG_DEBUG_VM=y CONFIG_DEBUG_VM_PGFLAGS=y CONFIG_DEBUG_VM_RB=y CONFIG_DEBUG_VM_VMACACHE=y -CONFIG_KASAN=y -CONFIG_KASAN_GENERIC=y -CONFIG_KASAN_INLINE=y -CONFIG_KASAN_VMALLOC=y +# CONFIG_KASAN is not set +# CONFIG_KASAN_GENERIC is not set +# CONFIG_KASAN_INLINE is not set +# CONFIG_KASAN_VMALLOC is not set CONFIG_PTDUMP_DEBUGFS=y CONFIG_SCHED_STACK_END_CHECK=y CONFIG_SLUB_DEBUG_ON=y @@ -94,7 +94,7 @@ CONFIG_SOFTLOCKUP_DETECTOR=y # Lock Debugging (spinlocks, mutexes, etc...) # # CONFIG_PROVE_RAW_LOCK_NESTING is not set -CONFIG_PROVE_LOCKING=y +# CONFIG_PROVE_LOCKING is not set # # Debug kernel data structures # @@ -102,16 +102,16 @@ CONFIG_BUG_ON_DATA_CORRUPTION=y # # RCU Debugging # -CONFIG_RCU_EXPERT=y -CONFIG_PROVE_RCU=y -CONFIG_PROVE_RCU_LIST=y +# CONFIG_RCU_EXPERT is not set +# CONFIG_PROVE_RCU is not set +# CONFIG_PROVE_RCU_LIST is not set # # Tracers # CONFIG_BRANCH_PROFILE_NONE=y CONFIG_DYNAMIC_FTRACE=y CONFIG_FTRACE=y -CONFIG_FUNCTION_TRACER=y +# CONFIG_FUNCTION_TRACER is not set # # Preemption # From 0d55c1620eb1a68601c9835d1139506096717b88 Mon Sep 17 00:00:00 2001 From: Jiaxing Li Date: Tue, 18 Nov 2025 00:16:10 +0800 Subject: [PATCH 0229/2333] QCLINUX: defconfig: Enable Trusted Execution Environment (TEE) driver for Qualcomm TEE (QTEE) We are planning to replace QPTEE with QCOMTEE on all QCOM-released kernel versions. QTEE allows Trusted Applications (TAs) and services to run securely and offers the same functionality as OPTEE. Signed-off-by: Jiaxing Li Link: https://github.com/qualcomm-linux/kernel-topics/pull/121 --- arch/arm64/configs/defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig index e565477a6fb19..ad2046c9dd94a 100644 --- a/arch/arm64/configs/defconfig +++ b/arch/arm64/configs/defconfig @@ -1710,6 +1710,7 @@ CONFIG_OF_FPGA_REGION=m CONFIG_OF_OVERLAY=y CONFIG_TEE=y CONFIG_OPTEE=y +CONFIG_QCOMTEE=y CONFIG_MUX_GPIO=m CONFIG_MUX_MMIO=y CONFIG_SLIMBUS=m From c8bae7ddde56b4e13c8077f46cac975d93efc9bb Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 9 Oct 2025 11:15:08 +0900 Subject: [PATCH 0230/2333] FROMLIST: arm64: defconfig: Enable two Novatek display panels for MTP8750 and Tianma Enable drivers for Novatek NT36672A panel (used on Xiaomi Pocophone F1 Tianma, Qualcomm SDM845 SoC) and Novatek NT37801 panel (used on Qualcomm MTP8750 development board). Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/all/20251009021507.175290-2-krzysztof.kozlowski@linaro.org/ Signed-off-by: Yash Gupta --- arch/arm64/configs/defconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig index ad2046c9dd94a..99380dd2df898 100644 --- a/arch/arm64/configs/defconfig +++ b/arch/arm64/configs/defconfig @@ -939,7 +939,9 @@ CONFIG_DRM_PANEL_HIMAX_HX8279=m CONFIG_DRM_PANEL_ILITEK_ILI9882T=m CONFIG_DRM_PANEL_KHADAS_TS050=m CONFIG_DRM_PANEL_MANTIX_MLAF057WE51=m +CONFIG_DRM_PANEL_NOVATEK_NT36672A=m CONFIG_DRM_PANEL_NOVATEK_NT36672E=m +CONFIG_DRM_PANEL_NOVATEK_NT37801=m CONFIG_DRM_PANEL_RAYDIUM_RM67191=m CONFIG_DRM_PANEL_SAMSUNG_ATNA33XC20=m CONFIG_DRM_PANEL_SITRONIX_ST7703=m From e5012a6b500b2e7096216d917b0237fd184fb3f6 Mon Sep 17 00:00:00 2001 From: Nikhil V Date: Thu, 20 Nov 2025 15:11:23 +0530 Subject: [PATCH 0231/2333] QCLINUX: defconfig: Enable support for vhost-net, vsock Added the required configs to enable host kernel accelerator for virtio net(vhost-net) and virtual socket protocol(vsock). Signed-off-by: Nikhil V --- arch/arm64/configs/qcom.config | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/arm64/configs/qcom.config b/arch/arm64/configs/qcom.config index 5fa9e6af25edb..ecfe6f69a3880 100644 --- a/arch/arm64/configs/qcom.config +++ b/arch/arm64/configs/qcom.config @@ -27,6 +27,8 @@ CONFIG_EXPERT=y CONFIG_I6300ESB_WDT=y CONFIG_IDLE_INJECT=y CONFIG_KPROBES=y +CONFIG_MACVLAN=y +CONFIG_MACVTAP=y CONFIG_PM_SLEEP=y CONFIG_PM_SLEEP_SMP=y CONFIG_PM_AUTOSLEEP=y @@ -49,6 +51,11 @@ CONFIG_UCLAMP_TASK_GROUP=y CONFIG_UCLAMP_TASK=y CONFIG_UHID=m CONFIG_VCPU_STALL_DETECTOR=y +CONFIG_VHOST_NET=y +CONFIG_VHOST_VSOCK=y +CONFIG_VSOCKETS=y +# CONFIG_VSOCKETS_DIAG is not set +# CONFIG_VSOCKETS_LOOPBACK is not set # CONFIG_WATCHDOG_PRETIMEOUT_DEFAULT_GOV_NOOP is not set CONFIG_WATCHDOG_PRETIMEOUT_DEFAULT_GOV_PANIC=y CONFIG_WATCHDOG_PRETIMEOUT_GOV_NOOP=y From fd098a2ec2ab110cb63f2c3eb337690ec91cb867 Mon Sep 17 00:00:00 2001 From: Ravi Hothi Date: Wed, 3 Dec 2025 10:12:17 +0530 Subject: [PATCH 0232/2333] FROMLIST: arm64: defconfig: Enable Sound DMIC driver Enable CONFIG_SND_SOC_DMIC as a module in the arm64 defconfig to support digital microphone functionality on Qualcomm's Monaco and Lemans platforms. Link: https://lore.kernel.org/all/20251203044217.171598-1-ravi.hothi@oss.qualcomm.com/ Signed-off-by: Ravi Hothi --- arch/arm64/configs/defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig index 99380dd2df898..5ada00cf2b3ad 100644 --- a/arch/arm64/configs/defconfig +++ b/arch/arm64/configs/defconfig @@ -1076,6 +1076,7 @@ CONFIG_SND_SOC_J721E_EVM=m CONFIG_SND_SOC_AK4613=m CONFIG_SND_SOC_AK4619=m CONFIG_SND_SOC_DA7213=m +CONFIG_SND_SOC_DMIC=m CONFIG_SND_SOC_ES7134=m CONFIG_SND_SOC_ES7241=m CONFIG_SND_SOC_ES8316=m From d85affe9104cd7c2b6e476ed6d27e4e6d71cc561 Mon Sep 17 00:00:00 2001 From: Pushpendra Singh Date: Wed, 13 Aug 2025 16:50:49 +0530 Subject: [PATCH 0233/2333] FROMLIST: drivers: qcom: icc-bwmon: Change zone1_thres_count to 3 Change zone1_thres_count to 3 from 16 so that driver can reduce bus vote in 3 sample window instead of waiting for 16 windows. Link: https://lore.kernel.org/lkml/d72182bc-f8d4-4314-b2f1-c9242618eb67@quicinc.com/ Signed-off-by: Pushpendra Singh --- drivers/soc/qcom/icc-bwmon.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/soc/qcom/icc-bwmon.c b/drivers/soc/qcom/icc-bwmon.c index 597f9025e4228..e46975da7dba6 100644 --- a/drivers/soc/qcom/icc-bwmon.c +++ b/drivers/soc/qcom/icc-bwmon.c @@ -830,7 +830,7 @@ static const struct icc_bwmon_data msm8998_bwmon_data = { static const struct icc_bwmon_data sdm845_cpu_bwmon_data = { .sample_ms = 4, .count_unit_kb = 64, - .zone1_thres_count = 16, + .zone1_thres_count = 3, .zone3_thres_count = 1, .quirks = BWMON_HAS_GLOBAL_IRQ, .regmap_fields = sdm845_cpu_bwmon_reg_fields, @@ -849,7 +849,7 @@ static const struct icc_bwmon_data sdm845_llcc_bwmon_data = { static const struct icc_bwmon_data sc7280_llcc_bwmon_data = { .sample_ms = 4, .count_unit_kb = 64, - .zone1_thres_count = 16, + .zone1_thres_count = 3, .zone3_thres_count = 1, .quirks = BWMON_NEEDS_FORCE_CLEAR, .regmap_fields = sdm845_llcc_bwmon_reg_fields, From ab6a7e808ca42d9a0d782ebabd752d9e25e20a3e Mon Sep 17 00:00:00 2001 From: Jingyi Wang Date: Wed, 22 Oct 2025 21:57:37 -0700 Subject: [PATCH 0234/2333] FROMGIT: soc: qcom: socinfo: Add SM8850 SoC ID Add SoC ID for Qualcomm SM8850 which represents the Kaanapali platform. Signed-off-by: Jingyi Wang Signed-off-by: Yijie Yang Link: https://lore.kernel.org/linux-arm-msm/20251022-knp-socid-v2-2-d147eadd09ee@oss.qualcomm.com/ --- drivers/soc/qcom/socinfo.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c index 963772f45489d..a2e2e15b840c4 100644 --- a/drivers/soc/qcom/socinfo.c +++ b/drivers/soc/qcom/socinfo.c @@ -461,6 +461,7 @@ static const struct soc_id soc_id[] = { { qcom_board_id(IPQ5424) }, { qcom_board_id(QCM6690) }, { qcom_board_id(QCS6690) }, + { qcom_board_id(SM8850) }, { qcom_board_id(IPQ5404) }, { qcom_board_id(QCS9100) }, { qcom_board_id(QCS8300) }, From 9306ad935c8886e01cfafd2a98b74e05470dc960 Mon Sep 17 00:00:00 2001 From: Jingyi Wang Date: Wed, 22 Oct 2025 21:57:36 -0700 Subject: [PATCH 0235/2333] FROMGIT: dt-bindings: arm: qcom,ids: Add SoC ID for SM8850 Add the ID for the Qualcomm SM8850 SoC which represents the Kaanapali platform. Signed-off-by: Jingyi Wang Reviewed-by: Krzysztof Kozlowski Signed-off-by: Yijie Yang Link: https://lore.kernel.org/linux-arm-msm/20251022-knp-socid-v2-1-d147eadd09ee@oss.qualcomm.com/ --- include/dt-bindings/arm/qcom,ids.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/dt-bindings/arm/qcom,ids.h b/include/dt-bindings/arm/qcom,ids.h index cb8ce53146f0c..19598ed4679e1 100644 --- a/include/dt-bindings/arm/qcom,ids.h +++ b/include/dt-bindings/arm/qcom,ids.h @@ -286,6 +286,7 @@ #define QCOM_ID_IPQ5424 651 #define QCOM_ID_QCM6690 657 #define QCOM_ID_QCS6690 658 +#define QCOM_ID_SM8850 660 #define QCOM_ID_IPQ5404 671 #define QCOM_ID_QCS9100 667 #define QCOM_ID_QCS8300 674 From 3c243dc021dd5a06d8b321b30757f260cb2895d1 Mon Sep 17 00:00:00 2001 From: Jingyi Wang Date: Wed, 24 Sep 2025 16:24:55 -0700 Subject: [PATCH 0236/2333] FROMGIT: soc: qcom: llcc-qcom: Add support for Kaanapali Add system cache table and configs for Kaanapali SoC. Signed-off-by: Jingyi Wang Reviewed-by: Konrad Dybcio Signed-off-by: Yijie Yang Link: https://lore.kernel.org/all/20250924-knp-llcc-v1-2-ae6a016e5138@oss.qualcomm.com/ --- drivers/soc/qcom/llcc-qcom.c | 373 +++++++++++++++++++++++++++++ include/linux/soc/qcom/llcc-qcom.h | 7 + 2 files changed, 380 insertions(+) diff --git a/drivers/soc/qcom/llcc-qcom.c b/drivers/soc/qcom/llcc-qcom.c index 857ead56b37d0..13e1742672945 100644 --- a/drivers/soc/qcom/llcc-qcom.c +++ b/drivers/soc/qcom/llcc-qcom.c @@ -214,6 +214,364 @@ static const struct llcc_slice_config ipq5424_data[] = { }, }; +static const struct llcc_slice_config kaanapali_data[] = { + { + .usecase_id = LLCC_CPUSS, + .slice_id = 1, + .max_cap = 5120, + .priority = 1, + .bonus_ways = 0xffffffff, + .activate_on_init = true, + .write_scid_en = true, + .stale_en = true, + .mru_uncap_en = true, + .vict_prio = true, + }, { + .usecase_id = LLCC_VIDSC0, + .slice_id = 2, + .max_cap = 512, + .priority = 4, + .fixed_size = true, + .bonus_ways = 0xffffffff, + .mru_uncap_en = true, + .vict_prio = true, + }, { + .usecase_id = LLCC_AUDIO, + .slice_id = 35, + .max_cap = 512, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xffffffff, + .mru_uncap_en = true, + .vict_prio = true, + }, { + .usecase_id = LLCC_MDMHPGRW, + .slice_id = 25, + .max_cap = 1024, + .priority = 5, + .bonus_ways = 0xffffffff, + .mru_uncap_en = true, + .vict_prio = true, + }, { + .usecase_id = LLCC_CMPT, + .slice_id = 34, + .max_cap = 4096, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xffffffff, + .mru_uncap_en = true, + .vict_prio = true, + }, { + .usecase_id = LLCC_GPUHTW, + .slice_id = 11, + .max_cap = 512, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xffffffff, + .mru_uncap_en = true, + .vict_prio = true, + }, { + .usecase_id = LLCC_GPU, + .slice_id = 9, + .max_cap = 5632, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xffffffff, + .write_scid_cacheable_en = true, + .mru_uncap_en = true, + .vict_prio = true, + }, { + .usecase_id = LLCC_MMUHWT, + .slice_id = 18, + .max_cap = 768, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xffffffff, + .activate_on_init = true, + .mru_uncap_en = true, + .vict_prio = true, + }, { + .usecase_id = LLCC_DISP, + .slice_id = 16, + .max_cap = 7168, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xffffffff, + .cache_mode = 2, + .stale_en = true, + .mru_uncap_en = true, + .vict_prio = true, + }, { + .usecase_id = LLCC_MDMHPFX, + .slice_id = 24, + .max_cap = 1024, + .priority = 5, + .fixed_size = true, + .bonus_ways = 0xffffffff, + .mru_uncap_en = true, + .vict_prio = true, + }, { + .usecase_id = LLCC_MDMPNG, + .slice_id = 27, + .max_cap = 256, + .priority = 5, + .bonus_ways = 0xfffff, + .mru_uncap_en = true, + .vict_prio = true, + }, { + .usecase_id = LLCC_CVP, + .slice_id = 8, + .max_cap = 800, + .priority = 5, + .fixed_size = true, + .bonus_ways = 0xffffffff, + .mru_uncap_en = true, + .ovcap_en = true, + .vict_prio = true, + .parent_slice_id = 33, + }, { + .usecase_id = LLCC_MODPE, + .slice_id = 29, + .max_cap = 256, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xf0000000, + .mru_uncap_en = true, + .alloc_oneway_en = true, + .vict_prio = true, + }, { + .usecase_id = LLCC_WRCACHE, + .slice_id = 31, + .max_cap = 512, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xffffffff, + .activate_on_init = true, + .mru_uncap_en = true, + .vict_prio = true, + }, { + .usecase_id = LLCC_CVPFW, + .slice_id = 19, + .max_cap = 512, + .priority = 5, + .fixed_size = true, + .bonus_ways = 0xffffffff, + .mru_uncap_en = true, + .vict_prio = true, + .parent_slice_id = 33, + }, { + .usecase_id = LLCC_CPUMTE, + .slice_id = 7, + .max_cap = 256, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xffffffff, + .mru_uncap_en = true, + .vict_prio = true, + }, { + .usecase_id = LLCC_CMPTHCP, + .slice_id = 15, + .max_cap = 256, + .priority = 4, + .fixed_size = true, + .bonus_ways = 0xffffffff, + .mru_uncap_en = true, + .vict_prio = true, + }, { + .usecase_id = LLCC_LCPDARE, + .slice_id = 30, + .max_cap = 128, + .priority = 5, + .fixed_size = true, + .bonus_ways = 0xffffffff, + .activate_on_init = true, + .mru_uncap_en = true, + .alloc_oneway_en = true, + .vict_prio = true, + }, { + .usecase_id = LLCC_AENPU, + .slice_id = 3, + .max_cap = 3072, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xffffffff, + .cache_mode = 2, + .mru_uncap_en = true, + .vict_prio = true, + }, { + .usecase_id = LLCC_ISLAND1, + .slice_id = 12, + .max_cap = 7936, + .priority = 7, + .fixed_size = true, + .bonus_ways = 0x7fffffff, + .mru_uncap_en = true, + .vict_prio = true, + }, { + .usecase_id = LLCC_DISP_WB, + .slice_id = 23, + .max_cap = 512, + .priority = 4, + .fixed_size = true, + .bonus_ways = 0xffffffff, + .mru_uncap_en = true, + .vict_prio = true, + }, { + .usecase_id = LLCC_VIDVSP, + .slice_id = 4, + .max_cap = 256, + .priority = 4, + .fixed_size = true, + .bonus_ways = 0xffffffff, + .mru_uncap_en = true, + .vict_prio = true, + }, { + .usecase_id = LLCC_VIDDEC, + .slice_id = 5, + .max_cap = 512, + .priority = 4, + .fixed_size = true, + .bonus_ways = 0xffffffff, + .cache_mode = 2, + .mru_uncap_en = true, + .ovcap_en = true, + .vict_prio = true, + .parent_slice_id = 33, + }, { + .usecase_id = LLCC_CAMOFE, + .slice_id = 33, + .max_cap = 6144, + .priority = 4, + .fixed_size = true, + .bonus_ways = 0xffffffff, + .stale_en = true, + .mru_uncap_en = true, + .ovcap_en = true, + .vict_prio = true, + .parent_slice_id = 33, + }, { + .usecase_id = LLCC_CAMRTIP, + .slice_id = 13, + .max_cap = 6144, + .priority = 4, + .fixed_size = true, + .bonus_ways = 0xffffffff, + .stale_en = true, + .mru_uncap_en = true, + .ovcap_en = true, + .vict_prio = true, + .parent_slice_id = 33, + }, { + .usecase_id = LLCC_CAMRTRF, + .slice_id = 10, + .max_cap = 3584, + .priority = 3, + .fixed_size = true, + .bonus_ways = 0xffffffff, + .stale_en = true, + .mru_uncap_en = true, + .ovcap_en = true, + .vict_prio = true, + .parent_slice_id = 33, + }, { + .usecase_id = LLCC_CAMSRTRF, + .slice_id = 21, + .max_cap = 6144, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xffffffff, + .stale_en = true, + .mru_uncap_en = true, + .ovcap_en = true, + .vict_prio = true, + .parent_slice_id = 33, + }, { + .usecase_id = LLCC_VIDEO_APV, + .slice_id = 6, + .max_cap = 768, + .priority = 4, + .fixed_size = true, + .bonus_ways = 0xffffffff, + .mru_uncap_en = true, + .vict_prio = true, + }, { + .usecase_id = LLCC_COMPUTE1, + .slice_id = 22, + .max_cap = 4096, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xffffffff, + .mru_uncap_en = true, + .vict_prio = true, + }, { + .usecase_id = LLCC_CPUSS_OPP, + .slice_id = 32, + .max_cap = 0, + .priority = 0, + .fixed_size = true, + .bonus_ways = 0, + .activate_on_init = true, + .write_scid_en = true, + .mru_uncap_en = true, + .vict_prio = true, + }, { + .usecase_id = LLCC_CPUSSMPAM, + .slice_id = 17, + .max_cap = 2048, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xffffffff, + .activate_on_init = true, + .write_scid_en = true, + .stale_en = true, + .mru_uncap_en = true, + .vict_prio = true, + }, { + .usecase_id = LLCC_CAM_IPE_STROV, + .slice_id = 14, + .max_cap = 400, + .priority = 5, + .fixed_size = true, + .bonus_ways = 0xffffffff, + .mru_uncap_en = true, + .ovcap_en = true, + .vict_prio = true, + .parent_slice_id = 33, + }, { + .usecase_id = LLCC_CAM_OFE_STROV, + .slice_id = 20, + .max_cap = 400, + .priority = 5, + .fixed_size = true, + .bonus_ways = 0xffffffff, + .mru_uncap_en = true, + .ovcap_en = true, + .vict_prio = true, + .parent_slice_id = 33, + }, { + .usecase_id = LLCC_CPUSS_HEU, + .slice_id = 28, + .max_cap = 0, + .priority = 0, + .fixed_size = true, + .bonus_ways = 0, + .mru_uncap_en = true, + .ovcap_en = true, + .vict_prio = true, + }, { + .usecase_id = LLCC_MDM_PNG_FIXED, + .slice_id = 26, + .max_cap = 256, + .priority = 5, + .fixed_size = true, + .bonus_ways = 0xff000000, + .activate_on_init = true, + .write_scid_en = true, + .mru_uncap_en = true, + .vict_prio = true, + }, +}; + static const struct llcc_slice_config sa8775p_data[] = { { .usecase_id = LLCC_CPUSS, @@ -3505,6 +3863,15 @@ static const u32 llcc_v6_reg_offset[] = { [LLCC_TRP_WRS_CACHEABLE_EN] = 0x00042088, }; +static const struct qcom_llcc_config kaanapali_cfg[] = { + { + .sct_data = kaanapali_data, + .size = ARRAY_SIZE(kaanapali_data), + .reg_offset = llcc_v6_reg_offset, + .edac_reg_offset = &llcc_v6_edac_reg_offset, + }, +}; + static const struct qcom_llcc_config qcs615_cfg[] = { { .sct_data = qcs615_data, @@ -3731,6 +4098,11 @@ static const struct qcom_llcc_config x1e80100_cfg[] = { }, }; +static const struct qcom_sct_config kaanapali_cfgs = { + .llcc_config = kaanapali_cfg, + .num_config = ARRAY_SIZE(kaanapali_cfg), +}; + static const struct qcom_sct_config qcs615_cfgs = { .llcc_config = qcs615_cfg, .num_config = ARRAY_SIZE(qcs615_cfg), @@ -4570,6 +4942,7 @@ static int qcom_llcc_probe(struct platform_device *pdev) static const struct of_device_id qcom_llcc_of_match[] = { { .compatible = "qcom,ipq5424-llcc", .data = &ipq5424_cfgs}, + { .compatible = "qcom,kaanapali-llcc", .data = &kaanapali_cfgs}, { .compatible = "qcom,qcs615-llcc", .data = &qcs615_cfgs}, { .compatible = "qcom,qcs8300-llcc", .data = &qcs8300_cfgs}, { .compatible = "qcom,qdu1000-llcc", .data = &qdu1000_cfgs}, diff --git a/include/linux/soc/qcom/llcc-qcom.h b/include/linux/soc/qcom/llcc-qcom.h index 7a69210a250c4..0287f9182c4d7 100644 --- a/include/linux/soc/qcom/llcc-qcom.h +++ b/include/linux/soc/qcom/llcc-qcom.h @@ -74,7 +74,14 @@ #define LLCC_CAMSRTIP 73 #define LLCC_CAMRTRF 74 #define LLCC_CAMSRTRF 75 +#define LLCC_VIDEO_APV 83 +#define LLCC_COMPUTE1 87 +#define LLCC_CPUSS_OPP 88 #define LLCC_CPUSSMPAM 89 +#define LLCC_CAM_IPE_STROV 92 +#define LLCC_CAM_OFE_STROV 93 +#define LLCC_CPUSS_HEU 94 +#define LLCC_MDM_PNG_FIXED 100 /** * struct llcc_slice_desc - Cache slice descriptor From 0cfb7f22eb98012037cc688694fe8ad3a361039f Mon Sep 17 00:00:00 2001 From: Jingyi Wang Date: Wed, 24 Sep 2025 16:24:54 -0700 Subject: [PATCH 0237/2333] FROMGIT: dt-bindings: cache: qcom,llcc: Document the Kaanapali LLCC Document the Last Level Cache Controller on Kaanapali platform. Signed-off-by: Jingyi Wang Reviewed-by: Krzysztof Kozlowski Signed-off-by: Yijie Yang Link: https://lore.kernel.org/all/20250924-knp-llcc-v1-1-ae6a016e5138@oss.qualcomm.com/ --- Documentation/devicetree/bindings/cache/qcom,llcc.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/cache/qcom,llcc.yaml b/Documentation/devicetree/bindings/cache/qcom,llcc.yaml index 37e3ebd554874..a620a2ff5c568 100644 --- a/Documentation/devicetree/bindings/cache/qcom,llcc.yaml +++ b/Documentation/devicetree/bindings/cache/qcom,llcc.yaml @@ -21,6 +21,7 @@ properties: compatible: enum: - qcom,ipq5424-llcc + - qcom,kaanapali-llcc - qcom,qcs615-llcc - qcom,qcs8300-llcc - qcom,qdu1000-llcc @@ -272,6 +273,7 @@ allOf: compatible: contains: enum: + - qcom,kaanapali-llcc - qcom,sm8450-llcc - qcom,sm8550-llcc - qcom,sm8650-llcc From c322bbbe1fc52cbf2d9bebea45d71f4592ab9bca Mon Sep 17 00:00:00 2001 From: Jingyi Wang Date: Wed, 24 Sep 2025 16:24:22 -0700 Subject: [PATCH 0238/2333] FROMLIST: dt-bindings: watchdog: Document Qualcomm Kaanapali watchdog Add devicetree binding for watchdog present on Qualcomm Kaanapali SoC. Signed-off-by: Jingyi Wang Reviewed-by: Krzysztof Kozlowski Signed-off-by: Yijie Yang Link: https://lore.kernel.org/all/20250924-knp-watchdog-v1-1-fd8f3fa0ae7e@oss.qualcomm.com/ --- Documentation/devicetree/bindings/watchdog/qcom-wdt.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/watchdog/qcom-wdt.yaml b/Documentation/devicetree/bindings/watchdog/qcom-wdt.yaml index 49e2b807db0bc..54f5311ed016d 100644 --- a/Documentation/devicetree/bindings/watchdog/qcom-wdt.yaml +++ b/Documentation/devicetree/bindings/watchdog/qcom-wdt.yaml @@ -22,6 +22,7 @@ properties: - qcom,apss-wdt-ipq5332 - qcom,apss-wdt-ipq5424 - qcom,apss-wdt-ipq9574 + - qcom,apss-wdt-kaanapali - qcom,apss-wdt-msm8226 - qcom,apss-wdt-msm8974 - qcom,apss-wdt-msm8994 From 5fb0b8f66306e723520f265a978fd49a75b0cd90 Mon Sep 17 00:00:00 2001 From: Amir Vajid Date: Wed, 24 Sep 2025 16:25:27 -0700 Subject: [PATCH 0239/2333] FROMLIST: dt-bindings: interconnect: qcom-bwmon: Document Kaanapali BWMONs Document the Kaanapali BWMONs, which have one instance per cluster of BWMONv4. Signed-off-by: Amir Vajid Signed-off-by: Jingyi Wang Signed-off-by: Yijie Yang Link: https://lore.kernel.org/all/20250924-knp-bwmon-v1-1-56a9cdda7d72@oss.qualcomm.com/ --- .../devicetree/bindings/interconnect/qcom,msm8998-bwmon.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/interconnect/qcom,msm8998-bwmon.yaml b/Documentation/devicetree/bindings/interconnect/qcom,msm8998-bwmon.yaml index 256de140c03dc..0d1a268db921d 100644 --- a/Documentation/devicetree/bindings/interconnect/qcom,msm8998-bwmon.yaml +++ b/Documentation/devicetree/bindings/interconnect/qcom,msm8998-bwmon.yaml @@ -25,6 +25,7 @@ properties: - const: qcom,msm8998-bwmon # BWMON v4 - items: - enum: + - qcom,kaanapali-cpu-bwmon - qcom,qcm2290-cpu-bwmon - qcom,qcs615-cpu-bwmon - qcom,qcs8300-cpu-bwmon From cb6f977467f93218d33de76548188b55974d9a84 Mon Sep 17 00:00:00 2001 From: Jingyi Wang Date: Tue, 21 Oct 2025 23:32:30 -0700 Subject: [PATCH 0240/2333] FROMLIST: dt-bindings: mailbox: qcom: Add CPUCP mailbox controller bindings for Kaanapali Document CPUSS Control Processor (CPUCP) mailbox controller for Qualcomm Kaanapali, which is compatible with X1E80100, use fallback to indicate this. Signed-off-by: Jingyi Wang Acked-by: Rob Herring (Arm) Signed-off-by: Yijie Yang Link: https://lore.kernel.org/all/20251021-knp-cpufreq-v2-1-95391d66c84e@oss.qualcomm.com/ --- Documentation/devicetree/bindings/mailbox/qcom,cpucp-mbox.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/mailbox/qcom,cpucp-mbox.yaml b/Documentation/devicetree/bindings/mailbox/qcom,cpucp-mbox.yaml index 9122c3d2dc30f..9e91247c521a1 100644 --- a/Documentation/devicetree/bindings/mailbox/qcom,cpucp-mbox.yaml +++ b/Documentation/devicetree/bindings/mailbox/qcom,cpucp-mbox.yaml @@ -19,6 +19,7 @@ properties: - items: - enum: - qcom,glymur-cpucp-mbox + - qcom,kaanapali-cpucp-mbox - const: qcom,x1e80100-cpucp-mbox - enum: - qcom,x1e80100-cpucp-mbox From f34933a16889f7672fb936a95dfb6546686cbb0c Mon Sep 17 00:00:00 2001 From: Jingyi Wang Date: Wed, 24 Sep 2025 16:23:56 -0700 Subject: [PATCH 0241/2333] FROMLIST: dt-bindings: mfd: qcom,tcsr: Add compatible for Kaanapali Document the qcom,tcsr-kaanapali compatible, tcsr will provide various control and status functions for their peripherals. Signed-off-by: Jingyi Wang Signed-off-by: Yijie Yang Link: https://lore.kernel.org/all/20250924-knp-mfd-v1-1-6c8a98760e95@oss.qualcomm.com/ --- Documentation/devicetree/bindings/mfd/qcom,tcsr.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/mfd/qcom,tcsr.yaml b/Documentation/devicetree/bindings/mfd/qcom,tcsr.yaml index 14ae3f00ef7e0..ae55b0a70766a 100644 --- a/Documentation/devicetree/bindings/mfd/qcom,tcsr.yaml +++ b/Documentation/devicetree/bindings/mfd/qcom,tcsr.yaml @@ -48,6 +48,7 @@ properties: - qcom,tcsr-ipq8064 - qcom,tcsr-ipq8074 - qcom,tcsr-ipq9574 + - qcom,tcsr-kaanapali - qcom,tcsr-mdm9615 - qcom,tcsr-msm8226 - qcom,tcsr-msm8660 From 5d2d0284e340c1e52bbdcbfe43887c0e89fa7102 Mon Sep 17 00:00:00 2001 From: Jingyi Wang Date: Fri, 31 Oct 2025 00:41:44 -0700 Subject: [PATCH 0242/2333] FROMLIST: dt-bindings: mailbox: qcom: Add IPCC support for Kaanapali and Glymur Platforms Document the Inter-Processor Communication Controller on the Qualcomm Kaanapali and Glymur Platforms, which will be used to route interrupts across various subsystems found on the SoC. Co-developed-by: Sibi Sankar Signed-off-by: Sibi Sankar Signed-off-by: Jingyi Wang Reviewed-by: Krzysztof Kozlowski Signed-off-by: Yijie Yang Link: https://lore.kernel.org/all/20251031-knp-ipcc-v3-1-62ffb4168dff@oss.qualcomm.com/ --- Documentation/devicetree/bindings/mailbox/qcom-ipcc.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/mailbox/qcom-ipcc.yaml b/Documentation/devicetree/bindings/mailbox/qcom-ipcc.yaml index e5c423130db67..7c4d6170491db 100644 --- a/Documentation/devicetree/bindings/mailbox/qcom-ipcc.yaml +++ b/Documentation/devicetree/bindings/mailbox/qcom-ipcc.yaml @@ -24,6 +24,8 @@ properties: compatible: items: - enum: + - qcom,glymur-ipcc + - qcom,kaanapali-ipcc - qcom,milos-ipcc - qcom,qcs8300-ipcc - qcom,qdu1000-ipcc From 7375880d294e9417221bce2dea52335b0b66b6f8 Mon Sep 17 00:00:00 2001 From: Jingyi Wang Date: Fri, 31 Oct 2025 00:41:45 -0700 Subject: [PATCH 0243/2333] FROMLIST: arm64: dts: qcom: Add header file for IPCC physical client IDs on Kaanapali platform On earlier platforms, Inter Process Communication Controller (IPCC) used virtual client IDs and performed virtual-to-physical mapping in hardware, so the IDs defined in dt-bindings/mailbox/qcom-ipcc.h are common across platforms. Physical client IDs instead of virtual client IDs are used for qcom new platforms like Kaanapali, which will be parsed by the devicetree and passed to hardware to use Physical client IDs directly. Since physical client IDs could vary across platforms, add a corresponding header file for the Kaanapali platform. Signed-off-by: Jingyi Wang Reviewed-by: Krzysztof Kozlowski Signed-off-by: Yijie Yang Link: https://lore.kernel.org/all/20251031-knp-ipcc-v3-2-62ffb4168dff@oss.qualcomm.com/ --- arch/arm64/boot/dts/qcom/kaanapali-ipcc.h | 58 +++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/kaanapali-ipcc.h diff --git a/arch/arm64/boot/dts/qcom/kaanapali-ipcc.h b/arch/arm64/boot/dts/qcom/kaanapali-ipcc.h new file mode 100644 index 0000000000000..125375a4aac0a --- /dev/null +++ b/arch/arm64/boot/dts/qcom/kaanapali-ipcc.h @@ -0,0 +1,58 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#ifndef __DTS_KAANAPALI_MAILBOX_IPCC_H +#define __DTS_KAANAPALI_MAILBOX_IPCC_H + +/* Physical client IDs */ +#define IPCC_MPROC_AOP 0 +#define IPCC_MPROC_TZ 1 +#define IPCC_MPROC_MPSS 2 +#define IPCC_MPROC_LPASS 3 +#define IPCC_MPROC_SDC 4 +#define IPCC_MPROC_CDSP 5 +#define IPCC_MPROC_APSS 6 +#define IPCC_MPROC_SOCCP 13 +#define IPCC_MPROC_DCP 14 +#define IPCC_MPROC_SPSS 15 +#define IPCC_MPROC_TME 16 +#define IPCC_MPROC_WPSS 17 + +#define IPCC_COMPUTE_L0_CDSP 2 +#define IPCC_COMPUTE_L0_APSS 3 +#define IPCC_COMPUTE_L0_GPU 4 +#define IPCC_COMPUTE_L0_CVP 8 +#define IPCC_COMPUTE_L0_CAM 9 +#define IPCC_COMPUTE_L0_CAM1 10 +#define IPCC_COMPUTE_L0_DCP 11 +#define IPCC_COMPUTE_L0_VPU 12 +#define IPCC_COMPUTE_L0_SOCCP 16 + +#define IPCC_COMPUTE_L1_CDSP 2 +#define IPCC_COMPUTE_L1_APSS 3 +#define IPCC_COMPUTE_L1_GPU 4 +#define IPCC_COMPUTE_L1_CVP 8 +#define IPCC_COMPUTE_L1_CAM 9 +#define IPCC_COMPUTE_L1_CAM1 10 +#define IPCC_COMPUTE_L1_DCP 11 +#define IPCC_COMPUTE_L1_VPU 12 +#define IPCC_COMPUTE_L1_SOCCP 16 + +#define IPCC_PERIPH_CDSP 2 +#define IPCC_PERIPH_APSS 3 +#define IPCC_PERIPH_PCIE0 4 +#define IPCC_PERIPH_PCIE1 5 + +#define IPCC_FENCE_CDSP 2 +#define IPCC_FENCE_APSS 3 +#define IPCC_FENCE_GPU 4 +#define IPCC_FENCE_CVP 8 +#define IPCC_FENCE_CAM 8 +#define IPCC_FENCE_CAM1 10 +#define IPCC_FENCE_DCP 11 +#define IPCC_FENCE_VPU 20 +#define IPCC_FENCE_SOCCP 24 + +#endif From 2956b5424c71ce724f0b9e1c5d5440f22c5f941d Mon Sep 17 00:00:00 2001 From: Sibi Sankar Date: Fri, 31 Oct 2025 00:41:46 -0700 Subject: [PATCH 0244/2333] FROMLIST: arm64: dts: qcom: Add header file for IPCC physical client IDs on Glymur platform Physical client IDs are used on Glymur Inter Process Communication Controller (IPCC), add a corresponding header file. Signed-off-by: Sibi Sankar Signed-off-by: Jingyi Wang Reviewed-by: Krzysztof Kozlowski Signed-off-by: Yijie Yang Link: https://lore.kernel.org/all/20251031-knp-ipcc-v3-3-62ffb4168dff@oss.qualcomm.com/ --- arch/arm64/boot/dts/qcom/glymur-ipcc.h | 68 ++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/glymur-ipcc.h diff --git a/arch/arm64/boot/dts/qcom/glymur-ipcc.h b/arch/arm64/boot/dts/qcom/glymur-ipcc.h new file mode 100644 index 0000000000000..700cd7114909f --- /dev/null +++ b/arch/arm64/boot/dts/qcom/glymur-ipcc.h @@ -0,0 +1,68 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#ifndef __DTS_GLYMUR_MAILBOX_IPCC_H +#define __DTS_GLYMUR_MAILBOX_IPCC_H + +/* Glymur physical client IDs */ +#define IPCC_MPROC_AOP 0 +#define IPCC_MPROC_TZ 1 +#define IPCC_MPROC_MPSS 2 +#define IPCC_MPROC_LPASS 3 +#define IPCC_MPROC_SLPI 4 +#define IPCC_MPROC_SDC 5 +#define IPCC_MPROC_CDSP 6 +#define IPCC_MPROC_NPU 7 +#define IPCC_MPROC_APSS 8 +#define IPCC_MPROC_GPU 9 +#define IPCC_MPROC_ICP 11 +#define IPCC_MPROC_VPU 12 +#define IPCC_MPROC_PCIE0 13 +#define IPCC_MPROC_PCIE1 14 +#define IPCC_MPROC_PCIE2 15 +#define IPCC_MPROC_SPSS 16 +#define IPCC_MPROC_PCIE3 19 +#define IPCC_MPROC_PCIE4 20 +#define IPCC_MPROC_PCIE5 21 +#define IPCC_MPROC_PCIE6 22 +#define IPCC_MPROC_TME 23 +#define IPCC_MPROC_WPSS 24 +#define IPCC_MPROC_PCIE7 44 +#define IPCC_MPROC_SOCCP 46 + +#define IPCC_COMPUTE_L0_LPASS 0 +#define IPCC_COMPUTE_L0_CDSP 1 +#define IPCC_COMPUTE_L0_APSS 2 +#define IPCC_COMPUTE_L0_GPU 3 +#define IPCC_COMPUTE_L0_CVP 6 +#define IPCC_COMPUTE_L0_ICP 7 +#define IPCC_COMPUTE_L0_VPU 8 +#define IPCC_COMPUTE_L0_DPU 9 +#define IPCC_COMPUTE_L0_SOCCP 11 + +#define IPCC_COMPUTE_L1_LPASS 0 +#define IPCC_COMPUTE_L1_CDSP 1 +#define IPCC_COMPUTE_L1_APSS 2 +#define IPCC_COMPUTE_L1_GPU 3 +#define IPCC_COMPUTE_L1_CVP 6 +#define IPCC_COMPUTE_L1_ICP 7 +#define IPCC_COMPUTE_L1_VPU 8 +#define IPCC_COMPUTE_L1_DPU 9 +#define IPCC_COMPUTE_L1_SOCCP 11 + +#define IPCC_PERIPH_LPASS 0 +#define IPCC_PERIPH_APSS 1 +#define IPCC_PERIPH_PCIE0 2 +#define IPCC_PERIPH_PCIE1 3 +#define IPCC_PERIPH_PCIE2 6 +#define IPCC_PERIPH_PCIE3 7 +#define IPCC_PERIPH_PCIE4 8 +#define IPCC_PERIPH_PCIE5 9 +#define IPCC_PERIPH_PCIE6 10 +#define IPCC_PERIPH_PCIE7 11 +#define IPCC_PERIPH_SOCCP 13 +#define IPCC_PERIPH_WPSS 16 + +#endif From e359c36116bfdaaf098364f2295f97017bdd802c Mon Sep 17 00:00:00 2001 From: Jingyi Wang Date: Wed, 22 Oct 2025 00:28:41 -0700 Subject: [PATCH 0245/2333] FROMLIST: dt-bindings: soc: qcom: Add qcom,kaanapali-imem compatible Document qcom,kaanapali-imem compatible. Reviewed-by: Eugen Hristev Signed-off-by: Jingyi Wang Signed-off-by: Yijie Yang Link: https://lore.kernel.org/all/20251022-knp-soc-binding-v2-1-3cd3f390f3e2@oss.qualcomm.com/ --- Documentation/devicetree/bindings/sram/qcom,imem.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/sram/qcom,imem.yaml b/Documentation/devicetree/bindings/sram/qcom,imem.yaml index 6a627c57ae2fe..1e29a8ff287f3 100644 --- a/Documentation/devicetree/bindings/sram/qcom,imem.yaml +++ b/Documentation/devicetree/bindings/sram/qcom,imem.yaml @@ -19,6 +19,7 @@ properties: - enum: - qcom,apq8064-imem - qcom,ipq5424-imem + - qcom,kaanapali-imem - qcom,msm8226-imem - qcom,msm8974-imem - qcom,msm8976-imem From 7d85636888664c63df73e016e2cfb456dd50d5ba Mon Sep 17 00:00:00 2001 From: Komal Bajaj Date: Mon, 3 Nov 2025 16:53:10 +0530 Subject: [PATCH 0246/2333] FROMGIT: dt-bindings: arm: qcom,ids: Add SoC ID for QCS6490 Add unique ID for Qualcomm QCS6490 SoC. Link: https://lore.kernel.org/r/20251103-qcs6490_soc_id-v1-1-c139dd1e32c8@oss.qualcomm.com Reviewed-by: Dmitry Baryshkov Signed-off-by: Komal Bajaj --- include/dt-bindings/arm/qcom,ids.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/dt-bindings/arm/qcom,ids.h b/include/dt-bindings/arm/qcom,ids.h index 19598ed4679e1..8776844e0eeb3 100644 --- a/include/dt-bindings/arm/qcom,ids.h +++ b/include/dt-bindings/arm/qcom,ids.h @@ -240,6 +240,7 @@ #define QCOM_ID_SC7280 487 #define QCOM_ID_SC7180P 495 #define QCOM_ID_QCM6490 497 +#define QCOM_ID_QCS6490 498 #define QCOM_ID_SM7325P 499 #define QCOM_ID_IPQ5000 503 #define QCOM_ID_IPQ0509 504 From 2baf0be6a28d7b4fb2ab9b60ca83aebafd204149 Mon Sep 17 00:00:00 2001 From: Komal Bajaj Date: Mon, 3 Nov 2025 16:53:11 +0530 Subject: [PATCH 0247/2333] FROMGIT: soc: qcom: socinfo: Add SoC ID for QCS6490 Add SoC ID table entry for Qualcomm QCS6490. Link: https://lore.kernel.org/r/20251103-qcs6490_soc_id-v1-2-c139dd1e32c8@oss.qualcomm.com Signed-off-by: Komal Bajaj --- drivers/soc/qcom/socinfo.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c index a2e2e15b840c4..704235ad9ccf3 100644 --- a/drivers/soc/qcom/socinfo.c +++ b/drivers/soc/qcom/socinfo.c @@ -415,6 +415,7 @@ static const struct soc_id soc_id[] = { { qcom_board_id(SC7280) }, { qcom_board_id(SC7180P) }, { qcom_board_id(QCM6490) }, + { qcom_board_id(QCS6490) }, { qcom_board_id(SM7325P) }, { qcom_board_id(IPQ5000) }, { qcom_board_id(IPQ0509) }, From eb343bedbab847d979ad9d17990663aa8cd662ba Mon Sep 17 00:00:00 2001 From: Jishnu Prakash Date: Wed, 24 Sep 2025 16:43:06 -0700 Subject: [PATCH 0248/2333] FROMLIST: dt-bindings: mfd: qcom,spmi-pmic: Document PMICs present on Kaanapali Document compatibles for the pmh0101, pmh0104, pmh0110 and pmk8850 SPMI PMICs. Signed-off-by: Jishnu Prakash Signed-off-by: Jingyi Wang Signed-off-by: Yijie Yang Link: https://lore.kernel.org/all/20250924-knp-pmic-binding-v1-1-b9cce48b8460@oss.qualcomm.com/ --- Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.yaml b/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.yaml index 078a6886f8b1e..427023cb11c5e 100644 --- a/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.yaml +++ b/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.yaml @@ -78,6 +78,9 @@ properties: - qcom,pmc8380 - qcom,pmd8028 - qcom,pmd9635 + - qcom,pmh0101 + - qcom,pmh0104 + - qcom,pmh0110 - qcom,pmi632 - qcom,pmi8950 - qcom,pmi8962 @@ -87,6 +90,7 @@ properties: - qcom,pmk8002 - qcom,pmk8350 - qcom,pmk8550 + - qcom,pmk8850 - qcom,pmm8155au - qcom,pmm8654au - qcom,pmp8074 From 82cd1cc6b9e3e936b07b49f2ce6bfb216f9ef857 Mon Sep 17 00:00:00 2001 From: Hrishabh Rajput Date: Tue, 18 Nov 2025 10:40:56 +0000 Subject: [PATCH 0249/2333] firmware: qcom: scm: Register gunyah watchdog device To restrict Gunyah watchdog initialization to Qualcomm platforms running under the Gunyah Hypervisor, register the watchdog device in the QCOM SCM driver. When Gunyah is not present or Gunyah emulates MMIO-based watchdog, we expect Qualcomm watchdog or ARM SBSA watchdog device to be present in the devicetree. First, we make sure we're running under the Gunyah Hypervisor. Then we move to check if any of the above mentioned watchdog device nodes are present, if not then we proceed to register the SMC-based Gunyah watchdog device. Link: https://lore.kernel.org/all/20251118-gunyah_watchdog-v8-1-e5de12e2eef5@oss.qualcomm.com/ Reviewed-by: Dmitry Baryshkov Tested-by: Shivendra Pratap Tested-by: Neil Armstrong Signed-off-by: Hrishabh Rajput --- drivers/firmware/qcom/qcom_scm.c | 53 ++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/drivers/firmware/qcom/qcom_scm.c b/drivers/firmware/qcom/qcom_scm.c index e777b7cb9b127..14d0663316e6b 100644 --- a/drivers/firmware/qcom/qcom_scm.c +++ b/drivers/firmware/qcom/qcom_scm.c @@ -2182,6 +2182,56 @@ int qcom_scm_qtee_callback_response(phys_addr_t buf, size_t buf_size, } EXPORT_SYMBOL(qcom_scm_qtee_callback_response); +static void qcom_scm_gunyah_wdt_free(void *data) +{ + struct platform_device *gunyah_wdt_dev = data; + + platform_device_unregister(gunyah_wdt_dev); +} + +static void qcom_scm_gunyah_wdt_init(struct qcom_scm *scm) +{ + struct platform_device *gunyah_wdt_dev; + struct device_node *np; + bool of_wdt_available; + int i; + static const uuid_t gunyah_uuid = UUID_INIT(0xc1d58fcd, 0xa453, 0x5fdb, + 0x92, 0x65, 0xce, 0x36, + 0x67, 0x3d, 0x5f, 0x14); + static const char * const of_wdt_compatible[] = { + "qcom,kpss-wdt", + "arm,sbsa-gwdt", + }; + + /* Bail out if we are not running under Gunyah */ + if (!IS_ENABLED(CONFIG_HAVE_ARM_SMCCC_DISCOVERY) || + !arm_smccc_hypervisor_has_uuid(&gunyah_uuid)) + return; + + /* + * Gunyah emulates either of Qualcomm watchdog or ARM SBSA watchdog on + * newer platforms. Bail out if we find them in the devicetree. + */ + for (i = 0; i < ARRAY_SIZE(of_wdt_compatible); i++) { + np = of_find_compatible_node(NULL, NULL, of_wdt_compatible[i]); + of_wdt_available = of_device_is_available(np); + of_node_put(np); + if (of_wdt_available) + return; + } + + gunyah_wdt_dev = platform_device_register_simple("gunyah-wdt", -1, + NULL, 0); + if (IS_ERR(gunyah_wdt_dev)) { + dev_err(scm->dev, "Failed to register Gunyah watchdog device: %ld\n", + PTR_ERR(gunyah_wdt_dev)); + return; + } + + devm_add_action_or_reset(scm->dev, qcom_scm_gunyah_wdt_free, + gunyah_wdt_dev); +} + static void qcom_scm_qtee_free(void *data) { struct platform_device *qtee_dev = data; @@ -2448,6 +2498,9 @@ static int qcom_scm_probe(struct platform_device *pdev) /* Initialize the QTEE object interface. */ qcom_scm_qtee_init(scm); + /* Initialize the Gunyah watchdog platform device. */ + qcom_scm_gunyah_wdt_init(scm); + return 0; } From 797d5a2c99ee52b6fdbafcd0862e867d151c0539 Mon Sep 17 00:00:00 2001 From: Hrishabh Rajput Date: Tue, 18 Nov 2025 10:40:57 +0000 Subject: [PATCH 0250/2333] watchdog: Add driver for Gunyah Watchdog On Qualcomm SoCs running under the Gunyah hypervisor, access to watchdog through MMIO is not available on all platforms. Depending on the hypervisor configuration, the watchdog is either fully emulated or exposed via ARM's SMC Calling Conventions (SMCCC) through the Vendor Specific Hypervisor Service Calls space. Add driver to support the SMC-based watchdog provided by the Gunyah Hypervisor. Device registration is done in the QCOM SCM driver after checks to restrict the watchdog initialization to Qualcomm devices running under Gunyah. Gunyah watchdog is not a hardware but an SMC-based vendor-specific hypervisor interface provided by the Gunyah hypervisor. The design involving QCOM SCM driver for registering the platform device has been devised to avoid adding non-hardware nodes to devicetree. Link: https://lore.kernel.org/all/20251118-gunyah_watchdog-v8-2-e5de12e2eef5@oss.qualcomm.com/ Tested-by: Shivendra Pratap Tested-by: Neil Armstrong Signed-off-by: Hrishabh Rajput --- MAINTAINERS | 1 + drivers/watchdog/Kconfig | 13 ++ drivers/watchdog/Makefile | 1 + drivers/watchdog/gunyah_wdt.c | 261 ++++++++++++++++++++++++++++++++++ 4 files changed, 276 insertions(+) create mode 100644 drivers/watchdog/gunyah_wdt.c diff --git a/MAINTAINERS b/MAINTAINERS index 46126ce2f968e..dbe09b2502ca6 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3211,6 +3211,7 @@ F: arch/arm64/boot/dts/qcom/ F: drivers/bus/qcom* F: drivers/firmware/qcom/ F: drivers/soc/qcom/ +F: drivers/watchdog/gunyah_wdt.c F: include/dt-bindings/arm/qcom,ids.h F: include/dt-bindings/firmware/qcom,scm.h F: include/dt-bindings/soc/qcom* diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 05008d937e405..bc6db9a1c116b 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -2354,4 +2354,17 @@ config KEEMBAY_WATCHDOG To compile this driver as a module, choose M here: the module will be called keembay_wdt. +config GUNYAH_WATCHDOG + tristate "Qualcomm Gunyah Watchdog" + depends on ARCH_QCOM || COMPILE_TEST + depends on HAVE_ARM_SMCCC + select WATCHDOG_CORE + help + Say Y here to include support for watchdog timer provided by the + Gunyah hypervisor. The driver uses ARM SMC Calling Convention (SMCCC) + to interact with Gunyah Watchdog. + + To compile this driver as a module, choose M here: the + module will be called gunyah_wdt. + endif # WATCHDOG diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index b680e4d3c1bc2..1215efb7816d2 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -102,6 +102,7 @@ obj-$(CONFIG_MSC313E_WATCHDOG) += msc313e_wdt.o obj-$(CONFIG_APPLE_WATCHDOG) += apple_wdt.o obj-$(CONFIG_SUNPLUS_WATCHDOG) += sunplus_wdt.o obj-$(CONFIG_MARVELL_GTI_WDT) += marvell_gti_wdt.o +obj-$(CONFIG_GUNYAH_WATCHDOG) += gunyah_wdt.o # X86 (i386 + ia64 + x86_64) Architecture obj-$(CONFIG_ACQUIRE_WDT) += acquirewdt.o diff --git a/drivers/watchdog/gunyah_wdt.c b/drivers/watchdog/gunyah_wdt.c new file mode 100644 index 0000000000000..49dfef459e847 --- /dev/null +++ b/drivers/watchdog/gunyah_wdt.c @@ -0,0 +1,261 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define GUNYAH_WDT_SMCCC_CALL_VAL(func_id) \ + ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, ARM_SMCCC_SMC_32,\ + ARM_SMCCC_OWNER_VENDOR_HYP, func_id) + +/* SMCCC function IDs for watchdog operations */ +#define GUNYAH_WDT_CONTROL GUNYAH_WDT_SMCCC_CALL_VAL(0x0005) +#define GUNYAH_WDT_STATUS GUNYAH_WDT_SMCCC_CALL_VAL(0x0006) +#define GUNYAH_WDT_PING GUNYAH_WDT_SMCCC_CALL_VAL(0x0007) +#define GUNYAH_WDT_SET_TIME GUNYAH_WDT_SMCCC_CALL_VAL(0x0008) + +/* + * Control values for GUNYAH_WDT_CONTROL. + * Bit 0 is used to enable or disable the watchdog. If this bit is set, + * then the watchdog is enabled and vice versa. + * Bit 1 should always be set to 1 as this bit is reserved in Gunyah and + * it's expected to be 1. + */ +#define WDT_CTRL_ENABLE (BIT(1) | BIT(0)) +#define WDT_CTRL_DISABLE BIT(1) + +enum gunyah_error { + GUNYAH_ERROR_OK = 0, + GUNYAH_ERROR_UNIMPLEMENTED = -1, + GUNYAH_ERROR_ARG_INVAL = 1, +}; + +/** + * gunyah_error_remap() - Remap Gunyah hypervisor errors into a Linux error code + * @gunyah_error: Gunyah hypercall return value + */ +static inline int gunyah_error_remap(enum gunyah_error gunyah_error) +{ + switch (gunyah_error) { + case GUNYAH_ERROR_OK: + return 0; + case GUNYAH_ERROR_UNIMPLEMENTED: + return -EOPNOTSUPP; + default: + return -EINVAL; + } +} + +static int gunyah_wdt_call(unsigned long func_id, unsigned long arg1, + unsigned long arg2) +{ + struct arm_smccc_res res; + + arm_smccc_1_1_smc(func_id, arg1, arg2, &res); + return gunyah_error_remap(res.a0); +} + +static int gunyah_wdt_start(struct watchdog_device *wdd) +{ + unsigned int timeout_ms; + struct device *dev = wdd->parent; + int ret; + + ret = gunyah_wdt_call(GUNYAH_WDT_CONTROL, WDT_CTRL_DISABLE, 0); + if (ret && watchdog_active(wdd)) { + dev_err(dev, "%s: Failed to stop gunyah wdt %d\n", __func__, ret); + return ret; + } + + timeout_ms = wdd->timeout * 1000; + ret = gunyah_wdt_call(GUNYAH_WDT_SET_TIME, timeout_ms, timeout_ms); + if (ret) { + dev_err(dev, "%s: Failed to set timeout for gunyah wdt %d\n", + __func__, ret); + return ret; + } + + ret = gunyah_wdt_call(GUNYAH_WDT_CONTROL, WDT_CTRL_ENABLE, 0); + if (ret) + dev_err(dev, "%s: Failed to start gunyah wdt %d\n", __func__, ret); + + return ret; +} + +static int gunyah_wdt_stop(struct watchdog_device *wdd) +{ + return gunyah_wdt_call(GUNYAH_WDT_CONTROL, WDT_CTRL_DISABLE, 0); +} + +static int gunyah_wdt_ping(struct watchdog_device *wdd) +{ + return gunyah_wdt_call(GUNYAH_WDT_PING, 0, 0); +} + +static int gunyah_wdt_set_timeout(struct watchdog_device *wdd, + unsigned int timeout_sec) +{ + wdd->timeout = timeout_sec; + + if (watchdog_active(wdd)) + return gunyah_wdt_start(wdd); + + return 0; +} + +static int gunyah_wdt_get_time_since_last_ping(void) +{ + struct arm_smccc_res res; + + arm_smccc_1_1_smc(GUNYAH_WDT_STATUS, 0, 0, &res); + if (res.a0) + return gunyah_error_remap(res.a0); + + return res.a2 / 1000; +} + +static unsigned int gunyah_wdt_get_timeleft(struct watchdog_device *wdd) +{ + int seconds_since_last_ping; + + seconds_since_last_ping = gunyah_wdt_get_time_since_last_ping(); + if (seconds_since_last_ping < 0 || + seconds_since_last_ping > wdd->timeout) + return 0; + + return wdd->timeout - seconds_since_last_ping; +} + +static int gunyah_wdt_restart(struct watchdog_device *wdd, + unsigned long action, void *data) +{ + /* Set timeout to 1ms and send a ping */ + gunyah_wdt_call(GUNYAH_WDT_CONTROL, WDT_CTRL_DISABLE, 0); + gunyah_wdt_call(GUNYAH_WDT_SET_TIME, 1, 1); + gunyah_wdt_call(GUNYAH_WDT_CONTROL, WDT_CTRL_ENABLE, 0); + gunyah_wdt_call(GUNYAH_WDT_PING, 0, 0); + + /* Wait to make sure reset occurs */ + mdelay(100); + + return 0; +} + +static const struct watchdog_info gunyah_wdt_info = { + .identity = "Gunyah Watchdog", + .options = WDIOF_SETTIMEOUT + | WDIOF_KEEPALIVEPING + | WDIOF_MAGICCLOSE, +}; + +static const struct watchdog_ops gunyah_wdt_ops = { + .owner = THIS_MODULE, + .start = gunyah_wdt_start, + .stop = gunyah_wdt_stop, + .ping = gunyah_wdt_ping, + .set_timeout = gunyah_wdt_set_timeout, + .get_timeleft = gunyah_wdt_get_timeleft, + .restart = gunyah_wdt_restart +}; + +static int gunyah_wdt_probe(struct platform_device *pdev) +{ + struct watchdog_device *wdd; + struct device *dev = &pdev->dev; + int ret; + + ret = gunyah_wdt_call(GUNYAH_WDT_STATUS, 0, 0); + if (ret == -EOPNOTSUPP) + return -ENODEV; + + if (ret) + return dev_err_probe(dev, ret, "status check failed\n"); + + wdd = devm_kzalloc(dev, sizeof(*wdd), GFP_KERNEL); + if (!wdd) + return -ENOMEM; + + wdd->info = &gunyah_wdt_info; + wdd->ops = &gunyah_wdt_ops; + wdd->parent = dev; + + /* + * Although Gunyah expects 16-bit unsigned int values as timeout values + * in milliseconds, values above 0x8000 are reserved. This limits the + * max timeout value to 32 seconds. + */ + wdd->max_timeout = 32; /* seconds */ + wdd->min_timeout = 1; /* seconds */ + wdd->timeout = wdd->max_timeout; + + gunyah_wdt_stop(wdd); + platform_set_drvdata(pdev, wdd); + watchdog_set_restart_priority(wdd, 0); + + return devm_watchdog_register_device(dev, wdd); +} + +static void gunyah_wdt_remove(struct platform_device *pdev) +{ + struct watchdog_device *wdd = platform_get_drvdata(pdev); + + gunyah_wdt_stop(wdd); +} + +static int gunyah_wdt_suspend(struct device *dev) +{ + struct watchdog_device *wdd = dev_get_drvdata(dev); + + if (watchdog_active(wdd)) + gunyah_wdt_stop(wdd); + + return 0; +} + +static int gunyah_wdt_resume(struct device *dev) +{ + struct watchdog_device *wdd = dev_get_drvdata(dev); + + if (watchdog_active(wdd)) + gunyah_wdt_start(wdd); + + return 0; +} + +static DEFINE_SIMPLE_DEV_PM_OPS(gunyah_wdt_pm_ops, gunyah_wdt_suspend, gunyah_wdt_resume); + +/* + * Gunyah watchdog is a vendor-specific hypervisor interface provided by the + * Gunyah hypervisor. Using QCOM SCM driver to detect Gunyah watchdog SMCCC + * hypervisor service and register platform device when the service is available + * allows this driver to operate independently of the devicetree and avoids + * adding the non-hardware nodes to the devicetree. + */ +static const struct platform_device_id gunyah_wdt_id[] = { + { .name = "gunyah-wdt" }, + {} +}; +MODULE_DEVICE_TABLE(platform, gunyah_wdt_id); + +static struct platform_driver gunyah_wdt_driver = { + .driver = { + .name = "gunyah-wdt", + .pm = pm_sleep_ptr(&gunyah_wdt_pm_ops), + }, + .id_table = gunyah_wdt_id, + .probe = gunyah_wdt_probe, + .remove = gunyah_wdt_remove, +}; + +module_platform_driver(gunyah_wdt_driver); + +MODULE_DESCRIPTION("Gunyah Watchdog Driver"); +MODULE_LICENSE("GPL"); From aa56c495865001bd138f511336954990b328f7c7 Mon Sep 17 00:00:00 2001 From: Shivendra Pratap Date: Thu, 4 Dec 2025 18:20:29 +0530 Subject: [PATCH 0251/2333] QCLINUX: arm64: configs: qcom.config: Enable GUNYAH_WATCHDOG Enable Gunyah watchdog driver for rb3gen2. Signed-off-by: Shivendra Pratap --- arch/arm64/configs/qcom.config | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/configs/qcom.config b/arch/arm64/configs/qcom.config index ecfe6f69a3880..d2fe51d328e50 100644 --- a/arch/arm64/configs/qcom.config +++ b/arch/arm64/configs/qcom.config @@ -24,6 +24,7 @@ CONFIG_DMABUF_HEAPS_CMA=y CONFIG_DMABUF_HEAPS_SYSTEM=y CONFIG_EDAC_QCOM=m CONFIG_EXPERT=y +CONFIG_GUNYAH_WATCHDOG=y CONFIG_I6300ESB_WDT=y CONFIG_IDLE_INJECT=y CONFIG_KPROBES=y From 872fcdb8fee0fce6b5d1e9ab9a1e69cca372057c Mon Sep 17 00:00:00 2001 From: Gaurav Kohli Date: Thu, 4 Dec 2025 09:41:58 +0530 Subject: [PATCH 0252/2333] FROMLIST: arm64: dts: qcom: monaco-evk: Enable AMC6821 fan controller Enable AMC6821 fan controller for monaco-evk platform and configure pwm polarity as inverted. Signed-off-by: Gaurav Kohli Link: https://lore.kernel.org/r/20251204041158.2613340-1-gaurav.kohli@oss.qualcomm.com --- arch/arm64/boot/dts/qcom/monaco-evk.dts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/monaco-evk.dts b/arch/arm64/boot/dts/qcom/monaco-evk.dts index 4b3e00444c331..697a30a9a4755 100644 --- a/arch/arm64/boot/dts/qcom/monaco-evk.dts +++ b/arch/arm64/boot/dts/qcom/monaco-evk.dts @@ -6,6 +6,7 @@ /dts-v1/; #include +#include #include #include @@ -418,6 +419,16 @@ status = "okay"; + fan_controller: fan@18 { + compatible = "ti,amc6821"; + reg = <0x18>; + #pwm-cells = <2>; + + fan { + pwms = <&fan_controller 40000 PWM_POLARITY_INVERTED>; + }; + }; + eeprom0: eeprom@50 { compatible = "atmel,24c256"; reg = <0x50>; From 05581be0dd9ac0c445abad72a32abc9c3ccd5d24 Mon Sep 17 00:00:00 2001 From: Miaoqing Pan Date: Fri, 14 Nov 2025 12:10:22 +0800 Subject: [PATCH 0253/2333] FROMLIST: wifi: ath11k: add usecase firmware handling based on device compatible For M.2 WLAN chips, there is no suitable DTS node to specify the firmware-name property. In addition, assigning firmware for the M.2 PCIe interface causes chips that do not use usecase specific firmware to fail. Therefore, abandoning the approach of specifying firmware in DTS. As an alternative, propose a static lookup table mapping device compatible to firmware names. Currently, only WCN6855 HW2.1 requires this. For details on usecase specific firmware, see: https://lore.kernel.org/all/20250522013444.1301330-3-miaoqing.pan@oss.qualcomm.com/. Tested-on: WCN6855 hw2.1 PCI WLAN.HSP.1.1-04685-QCAHSPSWPL_V1_V2_SILICONZ_IOE-1 Fixes: edbbc647c4f3 ("wifi: ath11k: support usercase-specific firmware overrides") Signed-off-by: Miaoqing Pan Link: https://lore.kernel.org/linux-wireless/20251204071100.970518-2-miaoqing.pan@oss.qualcomm.com/ --- drivers/net/wireless/ath/ath11k/core.c | 37 +++++++++++++++++++++++++- drivers/net/wireless/ath/ath11k/core.h | 7 +++-- 2 files changed, 39 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c index 812686173ac8a..a4a3a65c77526 100644 --- a/drivers/net/wireless/ath/ath11k/core.c +++ b/drivers/net/wireless/ath/ath11k/core.c @@ -1,7 +1,6 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ @@ -997,6 +996,42 @@ static const struct dmi_system_id ath11k_pm_quirk_table[] = { {} }; +static const struct __ath11k_core_usecase_firmware_table { + u32 hw_rev; + const char *compatible; + const char *firmware_name; +} ath11k_core_usecase_firmware_table[] = { + { ATH11K_HW_WCN6855_HW21, "qcom,lemans-evk", "nfa765"}, + { ATH11K_HW_WCN6855_HW21, "qcom,monaco-evk", "nfa765"}, + { ATH11K_HW_WCN6855_HW21, "qcom,hamoa-iot-evk", "nfa765"}, + { /* Sentinel */ } +}; + +const char *ath11k_core_get_usecase_firmware(struct ath11k_base *ab) +{ + struct device_node *root __free(device_node) = of_find_node_by_path("/"); + const struct __ath11k_core_usecase_firmware_table *entry = NULL; + int i, count = of_property_count_strings(root, "compatible"); + const char *compatible = NULL; + + for (i = 0; i < count; i++) { + if (of_property_read_string_index(root, "compatible", i, + &compatible) < 0) + continue; + + entry = ath11k_core_usecase_firmware_table; + while (entry->compatible) { + if (ab->hw_rev == entry->hw_rev && + !strcmp(entry->compatible, compatible)) + return entry->firmware_name; + entry++; + } + } + + return NULL; +} +EXPORT_SYMBOL(ath11k_core_get_usecase_firmware); + void ath11k_fw_stats_pdevs_free(struct list_head *head) { struct ath11k_fw_stats_pdev *i, *tmp; diff --git a/drivers/net/wireless/ath/ath11k/core.h b/drivers/net/wireless/ath/ath11k/core.h index e8780b05ce11e..f8fcd897ebd26 100644 --- a/drivers/net/wireless/ath/ath11k/core.h +++ b/drivers/net/wireless/ath/ath11k/core.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #ifndef ATH11K_CORE_H @@ -1275,6 +1275,7 @@ bool ath11k_core_coldboot_cal_support(struct ath11k_base *ab); const struct firmware *ath11k_core_firmware_request(struct ath11k_base *ab, const char *filename); +const char *ath11k_core_get_usecase_firmware(struct ath11k_base *ab); static inline const char *ath11k_scan_state_str(enum ath11k_scan_state state) { @@ -1325,9 +1326,7 @@ static inline void ath11k_core_create_firmware_path(struct ath11k_base *ab, const char *filename, void *buf, size_t buf_len) { - const char *fw_name = NULL; - - of_property_read_string(ab->dev->of_node, "firmware-name", &fw_name); + const char *fw_name = ath11k_core_get_usecase_firmware(ab); if (fw_name && strncmp(filename, "board", 5)) snprintf(buf, buf_len, "%s/%s/%s/%s", ATH11K_FW_DIR, From 7ed8cea7644a342684c7ca711f6ff7c65708affa Mon Sep 17 00:00:00 2001 From: Mayank Rana Date: Thu, 13 Nov 2025 14:12:30 +0800 Subject: [PATCH 0254/2333] FROMLIST: mhi: host: Add standard elf image download functionality Currently, the FBC image is a non-standard ELF file that contains a single ELF header, followed by segments for SBL, RDDM, and AMSS. Some devices are unable to process this non-standard ELF format and therefore require special handling during image loading. Add standard_elf_image flag to determine whether the device can process the non-standard ELF format. If this flag is set, a standard ELF image must be loaded, meaning the first 512 KB of the FBC image should be skipped when loading the AMSS image over the BHIe interface. Note that this flag does not affect the SBL image download process. Signed-off-by: Mayank Rana Co-developed-by: Qiang Yu Signed-off-by: Qiang Yu Reviewed-by: Baochen Qiang Link: https://lore.kernel.org/mhi/20250603-standard_elf_image_load_support-v2-1-cce97644e99e@oss.qualcomm.com/ Signed-off-by: Miaoqing Pan --- drivers/bus/mhi/host/boot.c | 7 +++++++ include/linux/mhi.h | 4 ++++ 2 files changed, 11 insertions(+) diff --git a/drivers/bus/mhi/host/boot.c b/drivers/bus/mhi/host/boot.c index 205d83ac069f1..64fb7a257d352 100644 --- a/drivers/bus/mhi/host/boot.c +++ b/drivers/bus/mhi/host/boot.c @@ -584,6 +584,13 @@ void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl) * device transitioning into MHI READY state */ if (fw_load_type == MHI_FW_LOAD_FBC) { + dev_dbg(dev, "standard_elf_image:%s\n", + (mhi_cntrl->standard_elf_image ? "True" : "False")); + if (mhi_cntrl->standard_elf_image) { + fw_data += mhi_cntrl->sbl_size; + fw_sz -= mhi_cntrl->sbl_size; + } + ret = mhi_alloc_bhie_table(mhi_cntrl, &mhi_cntrl->fbc_image, fw_sz); if (ret) { release_firmware(firmware); diff --git a/include/linux/mhi.h b/include/linux/mhi.h index dd372b0123a6d..48f2b50038519 100644 --- a/include/linux/mhi.h +++ b/include/linux/mhi.h @@ -360,6 +360,9 @@ struct mhi_controller_config { * @bounce_buf: Use of bounce buffer * @fbc_download: MHI host needs to do complete image transfer (optional) * @wake_set: Device wakeup set flag + * @standard_elf_image: Flag to determine whether the first 512 KB of the FBC + * image need to be skipped when loading AMSS image over + * BHIe interface (optional) * @irq_flags: irq flags passed to request_irq (optional) * @mru: the default MRU for the MHI device * @@ -445,6 +448,7 @@ struct mhi_controller { bool bounce_buf; bool fbc_download; bool wake_set; + bool standard_elf_image; unsigned long irq_flags; u32 mru; }; From 40dd2fcb17263fb2d0d8ce06de9167444f498d6a Mon Sep 17 00:00:00 2001 From: Yongxing Mou Date: Thu, 11 Sep 2025 19:24:01 +0800 Subject: [PATCH 0255/2333] FROMLIST: dt-bindings: display/msm: Document the DPU for QCS8300 Document the DPU for Qualcomm QCS8300 platform. It use the same DPU hardware with SA8775P and reuse it's driver. Link:https://lore.kernel.org/all/20251029-qcs8300_mdss-v13-1-e8c8c4f82da2@oss.qualcomm.com/ Reviewed-by: Krzysztof Kozlowski Signed-off-by: Yongxing Mou --- .../bindings/display/msm/qcom,sm8650-dpu.yaml | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/Documentation/devicetree/bindings/display/msm/qcom,sm8650-dpu.yaml b/Documentation/devicetree/bindings/display/msm/qcom,sm8650-dpu.yaml index 0a46120dd8680..d9b980a897229 100644 --- a/Documentation/devicetree/bindings/display/msm/qcom,sm8650-dpu.yaml +++ b/Documentation/devicetree/bindings/display/msm/qcom,sm8650-dpu.yaml @@ -13,11 +13,16 @@ $ref: /schemas/display/msm/dpu-common.yaml# properties: compatible: - enum: - - qcom,sa8775p-dpu - - qcom,sm8650-dpu - - qcom,sm8750-dpu - - qcom,x1e80100-dpu + oneOf: + - enum: + - qcom,sa8775p-dpu + - qcom,sm8650-dpu + - qcom,sm8750-dpu + - qcom,x1e80100-dpu + - items: + - enum: + - qcom,qcs8300-dpu + - const: qcom,sa8775p-dpu reg: items: From bef0e2da12ae94ed17c65acaa23f60581bc72019 Mon Sep 17 00:00:00 2001 From: Yongxing Mou Date: Thu, 11 Sep 2025 19:24:02 +0800 Subject: [PATCH 0256/2333] FROMLIST: dt-bindings: display/msm: dp-controller: document QCS8300 compatible Add compatible string for the DisplayPort controller found on the Qualcomm QCS8300 SoC. The Qualcomm QCS8300 platform comes with one DisplayPort controller that supports 4 MST streams, similar to the one found on the SA8775P. Link:https://lore.kernel.org/all/20251029-qcs8300_mdss-v13-2-e8c8c4f82da2@oss.qualcomm.com/ Reviewed-by: Krzysztof Kozlowski Signed-off-by: Yongxing Mou --- .../devicetree/bindings/display/msm/dp-controller.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Documentation/devicetree/bindings/display/msm/dp-controller.yaml b/Documentation/devicetree/bindings/display/msm/dp-controller.yaml index aeb4e4f36044a..ea88e1903f26a 100644 --- a/Documentation/devicetree/bindings/display/msm/dp-controller.yaml +++ b/Documentation/devicetree/bindings/display/msm/dp-controller.yaml @@ -31,6 +31,11 @@ properties: - qcom,sm8650-dp - qcom,x1e80100-dp + - items: + - enum: + - qcom,qcs8300-dp + - const: qcom,sa8775p-dp + - items: - enum: - qcom,sm6350-dp From 5b90a60643721534634647cfec8b94b24accdbc5 Mon Sep 17 00:00:00 2001 From: Yongxing Mou Date: Thu, 11 Sep 2025 19:24:03 +0800 Subject: [PATCH 0257/2333] FROMLIST: dt-bindings: display/msm: Document MDSS on QCS8300 Document the MDSS hardware found on the Qualcomm QCS8300 platform. Link:https://lore.kernel.org/all/20251029-qcs8300_mdss-v13-3-e8c8c4f82da2@oss.qualcomm.com/ Reviewed-by: Krzysztof Kozlowski Signed-off-by: Yongxing Mou --- .../display/msm/qcom,qcs8300-mdss.yaml | 286 ++++++++++++++++++ 1 file changed, 286 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/msm/qcom,qcs8300-mdss.yaml diff --git a/Documentation/devicetree/bindings/display/msm/qcom,qcs8300-mdss.yaml b/Documentation/devicetree/bindings/display/msm/qcom,qcs8300-mdss.yaml new file mode 100644 index 0000000000000..e96baaae9ba9e --- /dev/null +++ b/Documentation/devicetree/bindings/display/msm/qcom,qcs8300-mdss.yaml @@ -0,0 +1,286 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/msm/qcom,qcs8300-mdss.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm Technologies, Inc. QCS8300 Display MDSS + +maintainers: + - Yongxing Mou + +description: + QCS8300 MSM Mobile Display Subsystem(MDSS), which encapsulates sub-blocks like + DPU display controller, DP interfaces and EDP etc. + +$ref: /schemas/display/msm/mdss-common.yaml# + +properties: + compatible: + const: qcom,qcs8300-mdss + + clocks: + items: + - description: Display AHB + - description: Display hf AXI + - description: Display core + + iommus: + maxItems: 1 + + interconnects: + maxItems: 3 + + interconnect-names: + maxItems: 3 + +patternProperties: + "^display-controller@[0-9a-f]+$": + type: object + additionalProperties: true + + properties: + compatible: + contains: + const: qcom,qcs8300-dpu + + "^displayport-controller@[0-9a-f]+$": + type: object + additionalProperties: true + + properties: + compatible: + contains: + const: qcom,qcs8300-dp + + "^phy@[0-9a-f]+$": + type: object + additionalProperties: true + properties: + compatible: + contains: + const: qcom,qcs8300-edp-phy + +required: + - compatible + +unevaluatedProperties: false + +examples: + - | + #include + #include + #include + #include + #include + #include + #include + + mdss: display-subsystem@ae00000 { + compatible = "qcom,qcs8300-mdss"; + reg = <0x0ae00000 0x1000>; + reg-names = "mdss"; + + interconnects = <&mmss_noc MASTER_MDP0 QCOM_ICC_TAG_ACTIVE_ONLY + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ACTIVE_ONLY>, + <&mmss_noc MASTER_MDP1 QCOM_ICC_TAG_ACTIVE_ONLY + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ACTIVE_ONLY>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ACTIVE_ONLY + &config_noc SLAVE_DISPLAY_CFG QCOM_ICC_TAG_ACTIVE_ONLY>; + interconnect-names = "mdp0-mem", + "mdp1-mem", + "cpu-cfg"; + + resets = <&dispcc_core_bcr>; + power-domains = <&dispcc_gdsc>; + + clocks = <&dispcc_ahb_clk>, + <&gcc GCC_DISP_HF_AXI_CLK>, + <&dispcc_mdp_clk>; + + interrupts = ; + interrupt-controller; + #interrupt-cells = <1>; + + iommus = <&apps_smmu 0x1000 0x402>; + + #address-cells = <1>; + #size-cells = <1>; + ranges; + + display-controller@ae01000 { + compatible = "qcom,qcs8300-dpu", "qcom,sa8775p-dpu"; + reg = <0x0ae01000 0x8f000>, + <0x0aeb0000 0x2008>; + reg-names = "mdp", "vbif"; + + clocks = <&gcc GCC_DISP_HF_AXI_CLK>, + <&dispcc0 MDSS_DISP_CC_MDSS_AHB_CLK>, + <&dispcc0 MDSS_DISP_CC_MDSS_MDP_LUT_CLK>, + <&dispcc0 MDSS_DISP_CC_MDSS_MDP_CLK>, + <&dispcc0 MDSS_DISP_CC_MDSS_VSYNC_CLK>; + clock-names = "nrt_bus", + "iface", + "lut", + "core", + "vsync"; + + assigned-clocks = <&dispcc0 MDSS_DISP_CC_MDSS_VSYNC_CLK>; + assigned-clock-rates = <19200000>; + operating-points-v2 = <&mdp_opp_table>; + power-domains = <&rpmhpd RPMHPD_MMCX>; + + interrupt-parent = <&mdss>; + interrupts = <0>; + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + + dpu_intf0_out: endpoint { + remote-endpoint = <&mdss_dp0_in>; + }; + }; + }; + + mdp_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-375000000 { + opp-hz = /bits/ 64 <375000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-500000000 { + opp-hz = /bits/ 64 <500000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + + opp-575000000 { + opp-hz = /bits/ 64 <575000000>; + required-opps = <&rpmhpd_opp_turbo>; + }; + + opp-650000000 { + opp-hz = /bits/ 64 <650000000>; + required-opps = <&rpmhpd_opp_turbo_l1>; + }; + }; + }; + + mdss_dp0_phy: phy@aec2a00 { + compatible = "qcom,qcs8300-edp-phy", "qcom,sa8775p-edp-phy"; + + reg = <0x0aec2a00 0x200>, + <0x0aec2200 0xd0>, + <0x0aec2600 0xd0>, + <0x0aec2000 0x1c8>; + + clocks = <&dispcc MDSS_DISP_CC_MDSS_DPTX0_AUX_CLK>, + <&dispcc MDSS_DISP_CC_MDSS_AHB_CLK>; + clock-names = "aux", + "cfg_ahb"; + + #clock-cells = <1>; + #phy-cells = <0>; + + vdda-phy-supply = <&vreg_l1c>; + vdda-pll-supply = <&vreg_l4a>; + }; + + displayport-controller@af54000 { + compatible = "qcom,qcs8300-dp", "qcom,sa8775p-dp"; + + pinctrl-0 = <&dp_hot_plug_det>; + pinctrl-names = "default"; + + reg = <0xaf54000 0x104>, + <0xaf54200 0x0c0>, + <0xaf55000 0x770>, + <0xaf56000 0x09c>, + <0xaf57000 0x09c>, + <0xaf58000 0x09c>, + <0xaf59000 0x09c>, + <0xaf5a000 0x23c>, + <0xaf5b000 0x23c>; + + interrupt-parent = <&mdss>; + interrupts = <12>; + clocks = <&dispcc0 MDSS_DISP_CC_MDSS_AHB_CLK>, + <&dispcc0 MDSS_DISP_CC_MDSS_DPTX0_AUX_CLK>, + <&dispcc0 MDSS_DISP_CC_MDSS_DPTX0_LINK_CLK>, + <&dispcc0 MDSS_DISP_CC_MDSS_DPTX0_LINK_INTF_CLK>, + <&dispcc0 MDSS_DISP_CC_MDSS_DPTX0_PIXEL0_CLK>, + <&dispcc0 MDSS_DISP_CC_MDSS_DPTX0_PIXEL1_CLK>, + <&dispcc0 MDSS_DISP_CC_MDSS_DPTX0_PIXEL2_CLK>, + <&dispcc0 MDSS_DISP_CC_MDSS_DPTX0_PIXEL3_CLK>; + clock-names = "core_iface", + "core_aux", + "ctrl_link", + "ctrl_link_iface", + "stream_pixel", + "stream_1_pixel", + "stream_2_pixel", + "stream_3_pixel"; + assigned-clocks = <&dispcc0 MDSS_DISP_CC_MDSS_DPTX0_LINK_CLK_SRC>, + <&dispcc0 MDSS_DISP_CC_MDSS_DPTX0_PIXEL0_CLK_SRC>, + <&dispcc0 MDSS_DISP_CC_MDSS_DPTX0_PIXEL1_CLK_SRC>, + <&dispcc0 MDSS_DISP_CC_MDSS_DPTX0_PIXEL2_CLK_SRC>, + <&dispcc0 MDSS_DISP_CC_MDSS_DPTX0_PIXEL3_CLK_SRC>; + assigned-clock-parents = <&mdss_dp0_phy 0>, + <&mdss_dp0_phy 1>, + <&mdss_dp0_phy 1>, + <&mdss_dp0_phy 1>; + phys = <&mdss_dp0_phy>; + phy-names = "dp"; + operating-points-v2 = <&dp_opp_table>; + power-domains = <&rpmhpd RPMHPD_MMCX>; + + #sound-dai-cells = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + mdss_dp0_in: endpoint { + remote-endpoint = <&dpu_intf0_out>; + }; + }; + + port@1 { + reg = <1>; + + mdss_dp_out: endpoint { }; + }; + }; + + dp_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-160000000 { + opp-hz = /bits/ 64 <160000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + + opp-270000000 { + opp-hz = /bits/ 64 <270000000>; + required-opps = <&rpmhpd_opp_svs>; + }; + + opp-540000000 { + opp-hz = /bits/ 64 <540000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-810000000 { + opp-hz = /bits/ 64 <810000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + }; + }; + }; +... From bf7d2e9127be221966d222a36aa2fec52eccbfe8 Mon Sep 17 00:00:00 2001 From: Yongxing Mou Date: Thu, 11 Sep 2025 19:24:04 +0800 Subject: [PATCH 0258/2333] FROMLIST: soc: qcom: ubwc: Add QCS8300 UBWC cfg The QCS8300 supports UBWC 4.0 and 4 channels LP5 memory interface. Use the SC8280XP data structure for QCS8300 according to the specification. Link:https://lore.kernel.org/all/20251029-qcs8300_mdss-v13-4-e8c8c4f82da2@oss.qualcomm.com/ Acked-by: Bjorn Andersson Reviewed-by: Dmitry Baryshkov Signed-off-by: Yongxing Mou --- drivers/soc/qcom/ubwc_config.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/soc/qcom/ubwc_config.c b/drivers/soc/qcom/ubwc_config.c index 15d373bff231d..6de0e9d796c18 100644 --- a/drivers/soc/qcom/ubwc_config.c +++ b/drivers/soc/qcom/ubwc_config.c @@ -237,6 +237,7 @@ static const struct of_device_id qcom_ubwc_configs[] __maybe_unused = { { .compatible = "qcom,msm8998", .data = &msm8998_data }, { .compatible = "qcom,qcm2290", .data = &qcm2290_data, }, { .compatible = "qcom,qcm6490", .data = &sc7280_data, }, + { .compatible = "qcom,qcs8300", .data = &sc8280xp_data, }, { .compatible = "qcom,sa8155p", .data = &sm8150_data, }, { .compatible = "qcom,sa8540p", .data = &sc8280xp_data, }, { .compatible = "qcom,sa8775p", .data = &sa8775p_data, }, From cbd3a2f27d07aa3b3946a6d0bcc25fb79f964939 Mon Sep 17 00:00:00 2001 From: Yongxing Mou Date: Thu, 11 Sep 2025 19:24:05 +0800 Subject: [PATCH 0259/2333] FROMLIST: drm/msm: mdss: Add QCS8300 support Add Mobile Display Subsystem (MDSS) support for the QCS8300 platform. Link:https://lore.kernel.org/all/20251029-qcs8300_mdss-v13-5-e8c8c4f82da2@oss.qualcomm.com/ Reviewed-by: Dmitry Baryshkov Signed-off-by: Yongxing Mou --- drivers/gpu/drm/msm/msm_mdss.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/msm/msm_mdss.c b/drivers/gpu/drm/msm/msm_mdss.c index 2d0e3e784c044..db2f0064eb72e 100644 --- a/drivers/gpu/drm/msm/msm_mdss.c +++ b/drivers/gpu/drm/msm/msm_mdss.c @@ -555,6 +555,7 @@ static const struct of_device_id mdss_dt_match[] = { { .compatible = "qcom,mdss", .data = &data_153k6 }, { .compatible = "qcom,msm8998-mdss", .data = &data_76k8 }, { .compatible = "qcom,qcm2290-mdss", .data = &data_76k8 }, + { .compatible = "qcom,qcs8300-mdss", .data = &data_74k }, { .compatible = "qcom,sa8775p-mdss", .data = &data_74k }, { .compatible = "qcom,sar2130p-mdss", .data = &data_74k }, { .compatible = "qcom,sdm670-mdss", .data = &data_76k8 }, From 4e8079510509cddf670a46df7b4883172cb5761d Mon Sep 17 00:00:00 2001 From: Abel Vesa Date: Tue, 25 Nov 2025 17:46:18 +0530 Subject: [PATCH 0260/2333] FROMLIST: dt-bindings: phy: qcom-edp: Add missing clock for X Elite On X Elite platform, the eDP PHY uses one more clock called ref. The current X Elite devices supported upstream work fine without this clock, because the boot firmware leaves this clock enabled. But we should not rely on that. Also, even though this change breaks the ABI, it is needed in order to make the driver disables this clock along with the other ones, for a proper bring-down of the entire PHY. So attach the this ref clock to the PHY. Cc: stable@vger.kernel.org # v6.10 Fixes: 5d5607861350 ("dt-bindings: phy: qcom-edp: Add X1E80100 PHY compatibles") Link:https://lore.kernel.org/all/20251030-phy-qcom-edp-add-missing-refclk-v5-1-fce8c76f855a@linaro.org/ Reviewed-by: Krzysztof Kozlowski Reviewed-by: Bjorn Andersson Signed-off-by: Abel Vesa --- .../devicetree/bindings/phy/qcom,edp-phy.yaml | 28 ++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/phy/qcom,edp-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,edp-phy.yaml index eb97181cbb957..bfc4d75f50ff9 100644 --- a/Documentation/devicetree/bindings/phy/qcom,edp-phy.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,edp-phy.yaml @@ -37,12 +37,15 @@ properties: - description: PLL register block clocks: - maxItems: 2 + minItems: 2 + maxItems: 3 clock-names: + minItems: 2 items: - const: aux - const: cfg_ahb + - const: ref "#clock-cells": const: 1 @@ -64,6 +67,29 @@ required: - "#clock-cells" - "#phy-cells" +allOf: + - if: + properties: + compatible: + enum: + - qcom,x1e80100-dp-phy + then: + properties: + clocks: + minItems: 3 + maxItems: 3 + clock-names: + minItems: 3 + maxItems: 3 + else: + properties: + clocks: + minItems: 2 + maxItems: 2 + clock-names: + minItems: 2 + maxItems: 2 + additionalProperties: false examples: From c46af42be0e91eeac9113b8d48c7b6016f106017 Mon Sep 17 00:00:00 2001 From: Abel Vesa Date: Fri, 10 Oct 2025 16:30:30 +0530 Subject: [PATCH 0261/2333] FROMLIST: phy: qcom: edp: Make the number of clocks flexible On X Elite, the DP PHY needs another clock called ref, while all other platforms do not. The current X Elite devices supported upstream work fine without this clock, because the boot firmware leaves this clock enabled. But we should not rely on that. Also, even though this change breaks the ABI, it is needed in order to make the driver disables this clock along with the other ones, for a proper bring-down of the entire PHY. So in order to handle these clocks on different platforms, make the driver get all the clocks regardless of how many there are provided. Cc: stable@vger.kernel.org # v6.10 Fixes: db83c107dc29 ("phy: qcom: edp: Add v6 specific ops and X1E80100 platform support") Link:https://lore.kernel.org/all/20251030-phy-qcom-edp-add-missing-refclk-v5-2-fce8c76f855a@linaro.org/ Reviewed-by: Dmitry Baryshkov Reviewed-by: Bjorn Andersson Signed-off-by: Abel Vesa --- drivers/phy/qualcomm/phy-qcom-edp.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-edp.c b/drivers/phy/qualcomm/phy-qcom-edp.c index f1b51018683d5..ca9bb9d70e29e 100644 --- a/drivers/phy/qualcomm/phy-qcom-edp.c +++ b/drivers/phy/qualcomm/phy-qcom-edp.c @@ -103,7 +103,9 @@ struct qcom_edp { struct phy_configure_opts_dp dp_opts; - struct clk_bulk_data clks[2]; + struct clk_bulk_data *clks; + int num_clks; + struct regulator_bulk_data supplies[2]; bool is_edp; @@ -218,7 +220,7 @@ static int qcom_edp_phy_init(struct phy *phy) if (ret) return ret; - ret = clk_bulk_prepare_enable(ARRAY_SIZE(edp->clks), edp->clks); + ret = clk_bulk_prepare_enable(edp->num_clks, edp->clks); if (ret) goto out_disable_supplies; @@ -885,7 +887,7 @@ static int qcom_edp_phy_exit(struct phy *phy) { struct qcom_edp *edp = phy_get_drvdata(phy); - clk_bulk_disable_unprepare(ARRAY_SIZE(edp->clks), edp->clks); + clk_bulk_disable_unprepare(edp->num_clks, edp->clks); regulator_bulk_disable(ARRAY_SIZE(edp->supplies), edp->supplies); return 0; @@ -1092,11 +1094,9 @@ static int qcom_edp_phy_probe(struct platform_device *pdev) if (IS_ERR(edp->pll)) return PTR_ERR(edp->pll); - edp->clks[0].id = "aux"; - edp->clks[1].id = "cfg_ahb"; - ret = devm_clk_bulk_get(dev, ARRAY_SIZE(edp->clks), edp->clks); - if (ret) - return ret; + edp->num_clks = devm_clk_bulk_get_all(dev, &edp->clks); + if (edp->num_clks < 0) + return dev_err_probe(dev, edp->num_clks, "failed to parse clocks\n"); edp->supplies[0].supply = "vdda-phy"; edp->supplies[1].supply = "vdda-pll"; From 7de61f2173d694fa55fbe50f195bf768b7a3bb5f Mon Sep 17 00:00:00 2001 From: Ritesh Kumar Date: Fri, 10 Oct 2025 16:50:16 +0530 Subject: [PATCH 0262/2333] FROMLIST: dt-bindings: phy: qcom-edp: Add eDP ref clk for sa8775p When the initial contribution of eDP PHY for sa8775p was done, eDP reference clock voting was missed. It worked fine at that time because the clock was already enabled by the UFS PHY driver. After commit 77d2fa54a945 ("scsi: ufs: qcom : Refactor phy_power_on/off calls"), eDP reference clock started getting turned off, leading to the following PHY power-on failure: phy phy-aec2a00.phy.10: phy poweron failed --> -110 To fix this, explicit voting for the eDP reference clock is required. This patch adds the eDP reference clock for sa8775p eDP PHY and updates the corresponding example node. Link:https://lore.kernel.org/all/20251104114327.27842-2-riteshk@qti.qualcomm.com/ Signed-off-by: Ritesh Kumar --- .../devicetree/bindings/display/msm/qcom,sa8775p-mdss.yaml | 6 ++++-- Documentation/devicetree/bindings/phy/qcom,edp-phy.yaml | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/display/msm/qcom,sa8775p-mdss.yaml b/Documentation/devicetree/bindings/display/msm/qcom,sa8775p-mdss.yaml index e2730a2f25cfb..6c827cf9692b9 100644 --- a/Documentation/devicetree/bindings/display/msm/qcom,sa8775p-mdss.yaml +++ b/Documentation/devicetree/bindings/display/msm/qcom,sa8775p-mdss.yaml @@ -200,9 +200,11 @@ examples: <0x0aec2000 0x1c8>; clocks = <&dispcc0 MDSS_DISP_CC_MDSS_DPTX0_AUX_CLK>, - <&dispcc0 MDSS_DISP_CC_MDSS_AHB_CLK>; + <&dispcc0 MDSS_DISP_CC_MDSS_AHB_CLK>, + <&gcc GCC_EDP_REF_CLKREF_EN>; clock-names = "aux", - "cfg_ahb"; + "cfg_ahb", + "ref"; #clock-cells = <1>; #phy-cells = <0>; diff --git a/Documentation/devicetree/bindings/phy/qcom,edp-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,edp-phy.yaml index bfc4d75f50ff9..ba757b08b9b1b 100644 --- a/Documentation/devicetree/bindings/phy/qcom,edp-phy.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,edp-phy.yaml @@ -72,6 +72,7 @@ allOf: properties: compatible: enum: + - qcom,sa8775p-edp-phy - qcom,x1e80100-dp-phy then: properties: From a0cd32ebed1e8259b1155be9f20c73849ad41639 Mon Sep 17 00:00:00 2001 From: Xiangxu Yin Date: Fri, 26 Sep 2025 15:25:49 +0800 Subject: [PATCH 0263/2333] FROMLIST: drm/msm/dp: move link-specific parsing from dp_panel to dp_link Since max_dp_lanes and max_dp_link_rate are link-specific parameters, move their parsing from dp_panel to dp_link for better separation of concerns. Reviewed-by: Dmitry Baryshkov Signed-off-by: Xiangxu Yin Link: https://lore.kernel.org/all/20250926-add-displayport-support-for-qcs615-platform-v7-13-dc5edaac6c2b@oss.qualcomm.com/ --- drivers/gpu/drm/msm/dp/dp_link.c | 57 ++++++++++++++++++++++ drivers/gpu/drm/msm/dp/dp_link.h | 4 ++ drivers/gpu/drm/msm/dp/dp_panel.c | 78 ++++--------------------------- drivers/gpu/drm/msm/dp/dp_panel.h | 3 -- 4 files changed, 70 insertions(+), 72 deletions(-) diff --git a/drivers/gpu/drm/msm/dp/dp_link.c b/drivers/gpu/drm/msm/dp/dp_link.c index 66e1bbd80db3a..2aeb3ecf76fab 100644 --- a/drivers/gpu/drm/msm/dp/dp_link.c +++ b/drivers/gpu/drm/msm/dp/dp_link.c @@ -6,12 +6,14 @@ #define pr_fmt(fmt) "[drm-dp] %s: " fmt, __func__ #include +#include #include #include "dp_reg.h" #include "dp_link.h" #include "dp_panel.h" +#define DP_LINK_RATE_HBR2 540000 /* kbytes */ #define DP_TEST_REQUEST_MASK 0x7F enum audio_sample_rate { @@ -1210,10 +1212,61 @@ u32 msm_dp_link_get_test_bits_depth(struct msm_dp_link *msm_dp_link, u32 bpp) return tbd; } +static u32 msm_dp_link_link_frequencies(struct device_node *of_node) +{ + struct device_node *endpoint; + u64 frequency = 0; + int cnt; + + endpoint = of_graph_get_endpoint_by_regs(of_node, 1, 0); /* port@1 */ + if (!endpoint) + return 0; + + cnt = of_property_count_u64_elems(endpoint, "link-frequencies"); + + if (cnt > 0) + of_property_read_u64_index(endpoint, "link-frequencies", + cnt - 1, &frequency); + of_node_put(endpoint); + + do_div(frequency, + 10 * /* from symbol rate to link rate */ + 1000); /* kbytes */ + + return frequency; +} + +static int msm_dp_link_parse_dt(struct device *dev, struct msm_dp_link *msm_dp_link) +{ + struct device_node *of_node = dev->of_node; + int cnt; + + /* + * data-lanes is the property of msm_dp_out endpoint + */ + cnt = drm_of_get_data_lanes_count_ep(of_node, 1, 0, 1, DP_MAX_NUM_DP_LANES); + if (cnt < 0) { + /* legacy code, data-lanes is the property of mdss_dp node */ + cnt = drm_of_get_data_lanes_count(of_node, 1, DP_MAX_NUM_DP_LANES); + } + + if (cnt > 0) + msm_dp_link->max_dp_lanes = cnt; + else + msm_dp_link->max_dp_lanes = DP_MAX_NUM_DP_LANES; /* 4 lanes */ + + msm_dp_link->max_dp_link_rate = msm_dp_link_link_frequencies(of_node); + if (!msm_dp_link->max_dp_link_rate) + msm_dp_link->max_dp_link_rate = DP_LINK_RATE_HBR2; + + return 0; +} + struct msm_dp_link *msm_dp_link_get(struct device *dev, struct drm_dp_aux *aux) { struct msm_dp_link_private *link; struct msm_dp_link *msm_dp_link; + int ret; if (!dev || !aux) { DRM_ERROR("invalid input\n"); @@ -1229,5 +1282,9 @@ struct msm_dp_link *msm_dp_link_get(struct device *dev, struct drm_dp_aux *aux) mutex_init(&link->psm_mutex); msm_dp_link = &link->msm_dp_link; + ret = msm_dp_link_parse_dt(dev, msm_dp_link); + if (ret) + return ERR_PTR(ret); + return msm_dp_link; } diff --git a/drivers/gpu/drm/msm/dp/dp_link.h b/drivers/gpu/drm/msm/dp/dp_link.h index ba47c6d19fbfa..0684a962d4ec9 100644 --- a/drivers/gpu/drm/msm/dp/dp_link.h +++ b/drivers/gpu/drm/msm/dp/dp_link.h @@ -12,6 +12,7 @@ #define DS_PORT_STATUS_CHANGED 0x200 #define DP_TEST_BIT_DEPTH_UNKNOWN 0xFFFFFFFF #define DP_LINK_CAP_ENHANCED_FRAMING (1 << 0) +#define DP_MAX_NUM_DP_LANES 4 struct msm_dp_link_info { unsigned char revision; @@ -72,6 +73,9 @@ struct msm_dp_link { struct msm_dp_link_test_audio test_audio; struct msm_dp_link_phy_params phy_params; struct msm_dp_link_info link_params; + + u32 max_dp_lanes; + u32 max_dp_link_rate; }; /** diff --git a/drivers/gpu/drm/msm/dp/dp_panel.c b/drivers/gpu/drm/msm/dp/dp_panel.c index 15b7f6c7146e1..ad5d55bf009db 100644 --- a/drivers/gpu/drm/msm/dp/dp_panel.c +++ b/drivers/gpu/drm/msm/dp/dp_panel.c @@ -16,9 +16,6 @@ #define DP_INTF_CONFIG_DATABUS_WIDEN BIT(4) -#define DP_MAX_NUM_DP_LANES 4 -#define DP_LINK_RATE_HBR2 540000 /* kbytes */ - struct msm_dp_panel_private { struct device *dev; struct drm_device *drm_dev; @@ -91,6 +88,7 @@ static int msm_dp_panel_read_dpcd(struct msm_dp_panel *msm_dp_panel) int rc, max_lttpr_lanes, max_lttpr_rate; struct msm_dp_panel_private *panel; struct msm_dp_link_info *link_info; + struct msm_dp_link *link; u8 *dpcd, major, minor; panel = container_of(msm_dp_panel, struct msm_dp_panel_private, msm_dp_panel); @@ -105,16 +103,20 @@ static int msm_dp_panel_read_dpcd(struct msm_dp_panel *msm_dp_panel) major = (link_info->revision >> 4) & 0x0f; minor = link_info->revision & 0x0f; + link = panel->link; + drm_dbg_dp(panel->drm_dev, "max_lanes=%d max_link_rate=%d\n", + link->max_dp_lanes, link->max_dp_link_rate); + link_info->rate = drm_dp_max_link_rate(dpcd); link_info->num_lanes = drm_dp_max_lane_count(dpcd); /* Limit data lanes from data-lanes of endpoint property of dtsi */ - if (link_info->num_lanes > msm_dp_panel->max_dp_lanes) - link_info->num_lanes = msm_dp_panel->max_dp_lanes; + if (link_info->num_lanes > link->max_dp_lanes) + link_info->num_lanes = link->max_dp_lanes; /* Limit link rate from link-frequencies of endpoint property of dtsi */ - if (link_info->rate > msm_dp_panel->max_dp_link_rate) - link_info->rate = msm_dp_panel->max_dp_link_rate; + if (link_info->rate > link->max_dp_link_rate) + link_info->rate = link->max_dp_link_rate; /* Limit data lanes from LTTPR capabilities, if any */ max_lttpr_lanes = drm_dp_lttpr_max_lane_count(panel->link->lttpr_common_caps); @@ -173,9 +175,6 @@ int msm_dp_panel_read_sink_caps(struct msm_dp_panel *msm_dp_panel, panel = container_of(msm_dp_panel, struct msm_dp_panel_private, msm_dp_panel); - drm_dbg_dp(panel->drm_dev, "max_lanes=%d max_link_rate=%d\n", - msm_dp_panel->max_dp_lanes, msm_dp_panel->max_dp_link_rate); - rc = msm_dp_panel_read_dpcd(msm_dp_panel); if (rc) { DRM_ERROR("read dpcd failed %d\n", rc); @@ -648,60 +647,6 @@ int msm_dp_panel_init_panel_info(struct msm_dp_panel *msm_dp_panel) return 0; } -static u32 msm_dp_panel_link_frequencies(struct device_node *of_node) -{ - struct device_node *endpoint; - u64 frequency = 0; - int cnt; - - endpoint = of_graph_get_endpoint_by_regs(of_node, 1, 0); /* port@1 */ - if (!endpoint) - return 0; - - cnt = of_property_count_u64_elems(endpoint, "link-frequencies"); - - if (cnt > 0) - of_property_read_u64_index(endpoint, "link-frequencies", - cnt - 1, &frequency); - of_node_put(endpoint); - - do_div(frequency, - 10 * /* from symbol rate to link rate */ - 1000); /* kbytes */ - - return frequency; -} - -static int msm_dp_panel_parse_dt(struct msm_dp_panel *msm_dp_panel) -{ - struct msm_dp_panel_private *panel; - struct device_node *of_node; - int cnt; - - panel = container_of(msm_dp_panel, struct msm_dp_panel_private, msm_dp_panel); - of_node = panel->dev->of_node; - - /* - * data-lanes is the property of msm_dp_out endpoint - */ - cnt = drm_of_get_data_lanes_count_ep(of_node, 1, 0, 1, DP_MAX_NUM_DP_LANES); - if (cnt < 0) { - /* legacy code, data-lanes is the property of mdss_dp node */ - cnt = drm_of_get_data_lanes_count(of_node, 1, DP_MAX_NUM_DP_LANES); - } - - if (cnt > 0) - msm_dp_panel->max_dp_lanes = cnt; - else - msm_dp_panel->max_dp_lanes = DP_MAX_NUM_DP_LANES; /* 4 lanes */ - - msm_dp_panel->max_dp_link_rate = msm_dp_panel_link_frequencies(of_node); - if (!msm_dp_panel->max_dp_link_rate) - msm_dp_panel->max_dp_link_rate = DP_LINK_RATE_HBR2; - - return 0; -} - struct msm_dp_panel *msm_dp_panel_get(struct device *dev, struct drm_dp_aux *aux, struct msm_dp_link *link, void __iomem *link_base, @@ -709,7 +654,6 @@ struct msm_dp_panel *msm_dp_panel_get(struct device *dev, struct drm_dp_aux *aux { struct msm_dp_panel_private *panel; struct msm_dp_panel *msm_dp_panel; - int ret; if (!dev || !aux || !link) { DRM_ERROR("invalid input\n"); @@ -729,10 +673,6 @@ struct msm_dp_panel *msm_dp_panel_get(struct device *dev, struct drm_dp_aux *aux msm_dp_panel = &panel->msm_dp_panel; msm_dp_panel->max_bw_code = DP_LINK_BW_8_1; - ret = msm_dp_panel_parse_dt(msm_dp_panel); - if (ret) - return ERR_PTR(ret); - return msm_dp_panel; } diff --git a/drivers/gpu/drm/msm/dp/dp_panel.h b/drivers/gpu/drm/msm/dp/dp_panel.h index d2cf401506dcb..921a296852d4d 100644 --- a/drivers/gpu/drm/msm/dp/dp_panel.h +++ b/drivers/gpu/drm/msm/dp/dp_panel.h @@ -41,9 +41,6 @@ struct msm_dp_panel { bool vsc_sdp_supported; u32 hw_revision; - u32 max_dp_lanes; - u32 max_dp_link_rate; - u32 max_bw_code; }; From 5ef79567d76d2d20342e6dcfe79611ef1d852c46 Mon Sep 17 00:00:00 2001 From: Xiangxu Yin Date: Fri, 26 Sep 2025 15:25:50 +0800 Subject: [PATCH 0264/2333] FROMLIST: drm/msm/dp: Add support for lane mapping configuration QCS615 platform requires non-default logical-to-physical lane mapping due to its unique hardware routing. Unlike the standard mapping sequence <0 1 2 3>, QCS615 uses <3 2 0 1>, which necessitates explicit configuration via the data-lanes property in the device tree. This ensures correct signal routing between the DP controller and PHY. For partial definitions, fill remaining lanes with unused physical lanes in ascending order. Reviewed-by: Dmitry Baryshkov Signed-off-by: Xiangxu Yin Link: https://lore.kernel.org/all/20250926-add-displayport-support-for-qcs615-platform-v7-14-dc5edaac6c2b@oss.qualcomm.com/ --- drivers/gpu/drm/msm/dp/dp_ctrl.c | 10 +++--- drivers/gpu/drm/msm/dp/dp_link.c | 61 ++++++++++++++++++++++++++++++++ drivers/gpu/drm/msm/dp/dp_link.h | 1 + 3 files changed, 67 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c index c42fd2c17a328..cbcc7c2f0ffc4 100644 --- a/drivers/gpu/drm/msm/dp/dp_ctrl.c +++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c @@ -423,13 +423,13 @@ static void msm_dp_ctrl_config_ctrl(struct msm_dp_ctrl_private *ctrl) static void msm_dp_ctrl_lane_mapping(struct msm_dp_ctrl_private *ctrl) { - u32 ln_0 = 0, ln_1 = 1, ln_2 = 2, ln_3 = 3; /* One-to-One mapping */ + u32 *lane_map = ctrl->link->lane_map; u32 ln_mapping; - ln_mapping = ln_0 << LANE0_MAPPING_SHIFT; - ln_mapping |= ln_1 << LANE1_MAPPING_SHIFT; - ln_mapping |= ln_2 << LANE2_MAPPING_SHIFT; - ln_mapping |= ln_3 << LANE3_MAPPING_SHIFT; + ln_mapping = lane_map[0] << LANE0_MAPPING_SHIFT; + ln_mapping |= lane_map[1] << LANE1_MAPPING_SHIFT; + ln_mapping |= lane_map[2] << LANE2_MAPPING_SHIFT; + ln_mapping |= lane_map[3] << LANE3_MAPPING_SHIFT; msm_dp_write_link(ctrl, REG_DP_LOGICAL2PHYSICAL_LANE_MAPPING, ln_mapping); diff --git a/drivers/gpu/drm/msm/dp/dp_link.c b/drivers/gpu/drm/msm/dp/dp_link.c index 2aeb3ecf76fab..2ae78d33fffd7 100644 --- a/drivers/gpu/drm/msm/dp/dp_link.c +++ b/drivers/gpu/drm/msm/dp/dp_link.c @@ -1236,6 +1236,62 @@ static u32 msm_dp_link_link_frequencies(struct device_node *of_node) return frequency; } +/* + * Always populate msm_dp_link->lane_map with 4 lanes. + * - Use DTS "data-lanes" if present; otherwise fall back to default mapping. + * - For partial definitions, fill remaining entries with unused lanes in + * ascending order. + */ +static int msm_dp_link_lane_map(struct device *dev, struct msm_dp_link *msm_dp_link) +{ + struct device_node *of_node = dev->of_node; + struct device_node *endpoint; + int cnt = msm_dp_link->max_dp_lanes; + u32 tmp[DP_MAX_NUM_DP_LANES]; + u32 map[DP_MAX_NUM_DP_LANES] = {0, 1, 2, 3}; /* default 1:1 mapping */ + bool used[DP_MAX_NUM_DP_LANES] = {false}; + int i, ret = -EINVAL; + + endpoint = of_graph_get_endpoint_by_regs(of_node, 1, -1); + if (endpoint) { + ret = of_property_read_u32_array(endpoint, "data-lanes", tmp, cnt); + if (ret) + dev_dbg(dev, "endpoint data-lanes read failed (ret=%d)\n", ret); + } + + if (ret) { + ret = of_property_read_u32_array(of_node, "data-lanes", tmp, cnt); + if (ret) { + dev_info(dev, "data-lanes not defined, set to default\n"); + goto out; + } + } + + for (i = 0; i < cnt; i++) { + if (tmp[i] >= DP_MAX_NUM_DP_LANES) { + dev_err(dev, "data-lanes[%d]=%u out of range\n", i, tmp[i]); + return -EINVAL; + } + used[tmp[i]] = true; + map[i] = tmp[i]; + } + + /* Fill the remaining entries with unused physical lanes (ascending) */ + i = cnt; + for (int j = 0; i < DP_MAX_NUM_DP_LANES && j < DP_MAX_NUM_DP_LANES; j++) { + if (!used[j]) + map[i++] = j; + } + +out: + if (endpoint) + of_node_put(endpoint); + + dev_dbg(dev, "data-lanes count %d <%d %d %d %d>\n", cnt, map[0], map[1], map[2], map[3]); + memcpy(msm_dp_link->lane_map, map, sizeof(map)); + return 0; +} + static int msm_dp_link_parse_dt(struct device *dev, struct msm_dp_link *msm_dp_link) { struct device_node *of_node = dev->of_node; @@ -1255,6 +1311,11 @@ static int msm_dp_link_parse_dt(struct device *dev, struct msm_dp_link *msm_dp_l else msm_dp_link->max_dp_lanes = DP_MAX_NUM_DP_LANES; /* 4 lanes */ + if (msm_dp_link_lane_map(dev, msm_dp_link)) { + dev_err(dev, "failed to parse data-lanes\n"); + return -EINVAL; + } + msm_dp_link->max_dp_link_rate = msm_dp_link_link_frequencies(of_node); if (!msm_dp_link->max_dp_link_rate) msm_dp_link->max_dp_link_rate = DP_LINK_RATE_HBR2; diff --git a/drivers/gpu/drm/msm/dp/dp_link.h b/drivers/gpu/drm/msm/dp/dp_link.h index 0684a962d4ec9..b1eb2de6d2a76 100644 --- a/drivers/gpu/drm/msm/dp/dp_link.h +++ b/drivers/gpu/drm/msm/dp/dp_link.h @@ -74,6 +74,7 @@ struct msm_dp_link { struct msm_dp_link_phy_params phy_params; struct msm_dp_link_info link_params; + u32 lane_map[DP_MAX_NUM_DP_LANES]; u32 max_dp_lanes; u32 max_dp_link_rate; }; From 896addb54156918e398d9078c1291096e3309d6e Mon Sep 17 00:00:00 2001 From: Xiangxu Yin Date: Tue, 16 Sep 2025 20:11:03 +0800 Subject: [PATCH 0265/2333] FROMLIST: dt-bindings: display/msm: dp-controller: Add SM6150 Add DisplayPort controller binding for Qualcomm SM6150 SoC. SM6150 uses the same controller IP as SM8150. Declare 'qcom,sm6150-dp' as a fallback compatible to 'qcom,sm8150-dp' and 'qcom,sm8350-dp' for consistency with existing bindings and to ensure correct matching and future clarity. Signed-off-by: Xiangxu Yin Acked-by: Rob Herring (Arm) Signed-off-by: Yongxing Mou Link: https://lore.kernel.org/all/20250916-add-dp-controller-support-for-sm6150-v3-1-dd60ebbd101e@oss.qualcomm.com/ --- .../devicetree/bindings/display/msm/dp-controller.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Documentation/devicetree/bindings/display/msm/dp-controller.yaml b/Documentation/devicetree/bindings/display/msm/dp-controller.yaml index ea88e1903f26a..d26e51db7b6bb 100644 --- a/Documentation/devicetree/bindings/display/msm/dp-controller.yaml +++ b/Documentation/devicetree/bindings/display/msm/dp-controller.yaml @@ -58,6 +58,12 @@ properties: - qcom,sm8550-dp - const: qcom,sm8350-dp + - items: + - enum: + - qcom,sm6150-dp + - const: qcom,sm8150-dp + - const: qcom,sm8350-dp + - items: - enum: - qcom,sm8750-dp From c09b189b09007c9b9d1699b4dc420d7d8b8e5aed Mon Sep 17 00:00:00 2001 From: Xiangxu Yin Date: Tue, 4 Nov 2025 09:33:23 +0800 Subject: [PATCH 0266/2333] FROMLIST: dt-bindings: display: msm: sm6150-mdss: Add DisplayPort controller SM6150 uses the same DisplayPort controller as SM8150, which is compatible with SM8350. Add SM6150-specific compatible string for the DisplayPort controller. Signed-off-by: Xiangxu Yin Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/all/20251104-add-displayport-support-to-qcs615-devicetree-v7-1-e51669170a6f@oss.qualcomm.com/ --- .../devicetree/bindings/display/msm/qcom,sm6150-mdss.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Documentation/devicetree/bindings/display/msm/qcom,sm6150-mdss.yaml b/Documentation/devicetree/bindings/display/msm/qcom,sm6150-mdss.yaml index 9ac24f99d3ada..98949deed9ae0 100644 --- a/Documentation/devicetree/bindings/display/msm/qcom,sm6150-mdss.yaml +++ b/Documentation/devicetree/bindings/display/msm/qcom,sm6150-mdss.yaml @@ -51,6 +51,14 @@ patternProperties: compatible: const: qcom,sm6150-dpu + "^displayport-controller@[0-9a-f]+$": + type: object + additionalProperties: true + properties: + compatible: + contains: + const: qcom,sm6150-dp + "^dsi@[0-9a-f]+$": type: object additionalProperties: true From 5d29ae2929746e69681b246b1a99f79f40e08ed5 Mon Sep 17 00:00:00 2001 From: Xiangxu Yin Date: Tue, 4 Nov 2025 09:33:24 +0800 Subject: [PATCH 0267/2333] FROMLIST: dt-bindings: display: msm: sm6150-mdss: Fix example indentation and OPP values Improve the binding example by fixing indentation and adding missing blank lines for better readability. Also correct the OPP clock values to match the actual SM6150 DTS configuration. Reviewed-by: Rob Herring (Arm) Signed-off-by: Xiangxu Yin Link: https://lore.kernel.org/all/20251104-add-displayport-support-to-qcs615-devicetree-v7-2-e51669170a6f@oss.qualcomm.com/ --- .../display/msm/qcom,sm6150-mdss.yaml | 32 ++++++++++--------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/Documentation/devicetree/bindings/display/msm/qcom,sm6150-mdss.yaml b/Documentation/devicetree/bindings/display/msm/qcom,sm6150-mdss.yaml index 98949deed9ae0..46e9335f849fe 100644 --- a/Documentation/devicetree/bindings/display/msm/qcom,sm6150-mdss.yaml +++ b/Documentation/devicetree/bindings/display/msm/qcom,sm6150-mdss.yaml @@ -138,35 +138,37 @@ examples: #size-cells = <0>; port@0 { - reg = <0>; - dpu_intf0_out: endpoint { - }; + reg = <0>; + + dpu_intf0_out: endpoint { + }; }; port@1 { - reg = <1>; - dpu_intf1_out: endpoint { - remote-endpoint = <&mdss_dsi0_in>; - }; + reg = <1>; + + dpu_intf1_out: endpoint { + remote-endpoint = <&mdss_dsi0_in>; + }; }; }; mdp_opp_table: opp-table { compatible = "operating-points-v2"; - opp-19200000 { - opp-hz = /bits/ 64 <19200000>; - required-opps = <&rpmhpd_opp_low_svs>; + opp-192000000 { + opp-hz = /bits/ 64 <192000000>; + required-opps = <&rpmhpd_opp_low_svs>; }; - opp-25600000 { - opp-hz = /bits/ 64 <25600000>; - required-opps = <&rpmhpd_opp_svs>; + opp-256000000 { + opp-hz = /bits/ 64 <256000000>; + required-opps = <&rpmhpd_opp_svs>; }; opp-307200000 { - opp-hz = /bits/ 64 <307200000>; - required-opps = <&rpmhpd_opp_nom>; + opp-hz = /bits/ 64 <307200000>; + required-opps = <&rpmhpd_opp_nom>; }; }; }; From ac23ae86887c34f61b4462223d53a6e0cb659576 Mon Sep 17 00:00:00 2001 From: Xin Ji Date: Tue, 18 Nov 2025 15:49:51 +0530 Subject: [PATCH 0268/2333] FROMLIST: drm/bridge: anx7625: Fix EDID block size at drm_edid_alloc() calling Since DRM validates the all of EDID blocks, allocates drm_edid data structure based on the actually block count returned by the sink monitor at drm_edid_alloc() calling. Fixes: 7c585f9a71aa ("drm/bridge: anx7625: use struct drm_edid more") Signed-off-by: Xin Ji Link: https://lore.kernel.org/all/20250808064613.2623732-1-xji@analogixsemi.com/ Signed-off-by: Arpit Saini --- drivers/gpu/drm/bridge/analogix/anx7625.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.c b/drivers/gpu/drm/bridge/analogix/anx7625.c index 6f3fdcb6afdb9..0bb8be08a77cc 100644 --- a/drivers/gpu/drm/bridge/analogix/anx7625.c +++ b/drivers/gpu/drm/bridge/analogix/anx7625.c @@ -1801,7 +1801,7 @@ static const struct drm_edid *anx7625_edid_read(struct anx7625_data *ctx) return NULL; } - ctx->cached_drm_edid = drm_edid_alloc(edid_buf, FOUR_BLOCK_SIZE); + ctx->cached_drm_edid = drm_edid_alloc(edid_buf, edid_num * EDID_LENGTH); kfree(edid_buf); out: From 76bd632b82ba6b8bdf98b49d55ce7f131e5ba71a Mon Sep 17 00:00:00 2001 From: Xiangxu Yin Date: Fri, 26 Sep 2025 15:25:37 +0800 Subject: [PATCH 0269/2333] FROMLIST: dt-bindings: phy: Add QMP USB3+DP PHY for QCS615 Add device tree binding documentation for the Qualcomm QMP USB3+DP PHY on QCS615 Platform. This PHY supports both USB3 and DP functionality over USB-C, with PHY mode switching capability. It does not support combo mode. Reviewed-by: Rob Herring (Arm) Signed-off-by: Xiangxu Yin Link: https://lore.kernel.org/all/20250926-add-displayport-support-for-qcs615-platform-v7-1-dc5edaac6c2b@oss.qualcomm.com/ --- .../phy/qcom,qcs615-qmp-usb3dp-phy.yaml | 111 ++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 Documentation/devicetree/bindings/phy/qcom,qcs615-qmp-usb3dp-phy.yaml diff --git a/Documentation/devicetree/bindings/phy/qcom,qcs615-qmp-usb3dp-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,qcs615-qmp-usb3dp-phy.yaml new file mode 100644 index 0000000000000..efb465c71c1b5 --- /dev/null +++ b/Documentation/devicetree/bindings/phy/qcom,qcs615-qmp-usb3dp-phy.yaml @@ -0,0 +1,111 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/phy/qcom,qcs615-qmp-usb3dp-phy.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm QMP USB3-DP PHY controller (DP, QCS615) + +maintainers: + - Xiangxu Yin + +description: + The QMP PHY controller supports physical layer functionality for both USB3 + and DisplayPort over USB-C. While it enables mode switching between USB3 and + DisplayPort, but does not support combo mode. + +properties: + compatible: + enum: + - qcom,qcs615-qmp-usb3-dp-phy + + reg: + maxItems: 1 + + clocks: + maxItems: 4 + + clock-names: + items: + - const: aux + - const: ref + - const: cfg_ahb + - const: pipe + + resets: + maxItems: 2 + + reset-names: + items: + - const: phy_phy + - const: dp_phy + + vdda-phy-supply: true + + vdda-pll-supply: true + + "#clock-cells": + const: 1 + description: + See include/dt-bindings/phy/phy-qcom-qmp.h + + "#phy-cells": + const: 1 + description: + See include/dt-bindings/phy/phy-qcom-qmp.h + + qcom,tcsr-reg: + $ref: /schemas/types.yaml#/definitions/phandle-array + items: + - items: + - description: phandle to TCSR hardware block + - description: offset of the VLS CLAMP register + - description: offset of the PHY mode register + description: Clamp and PHY mode register present in the TCSR + +required: + - compatible + - reg + - clocks + - clock-names + - resets + - reset-names + - vdda-phy-supply + - vdda-pll-supply + - "#clock-cells" + - "#phy-cells" + - qcom,tcsr-reg + +additionalProperties: false + +examples: + - | + #include + #include + + phy@88e8000 { + compatible = "qcom,qcs615-qmp-usb3-dp-phy"; + reg = <0x88e8000 0x2000>; + + clocks = <&gcc GCC_USB2_SEC_PHY_AUX_CLK>, + <&gcc GCC_USB3_SEC_CLKREF_CLK>, + <&gcc GCC_AHB2PHY_WEST_CLK>, + <&gcc GCC_USB2_SEC_PHY_PIPE_CLK>; + clock-names = "aux", + "ref", + "cfg_ahb", + "pipe"; + + resets = <&gcc GCC_USB3PHY_PHY_SEC_BCR>, + <&gcc GCC_USB3_DP_PHY_SEC_BCR>; + reset-names = "phy_phy", + "dp_phy"; + + vdda-phy-supply = <&vreg_l5a>; + vdda-pll-supply = <&vreg_l12a>; + + #clock-cells = <1>; + #phy-cells = <1>; + + qcom,tcsr-reg = <&tcsr 0xbff0 0xb24c>; + }; From d009dbe479ad898c5c3e8dc3c8629e6cd39c097d Mon Sep 17 00:00:00 2001 From: Xiangxu Yin Date: Thu, 13 Nov 2025 16:00:16 +0800 Subject: [PATCH 0270/2333] FROMLIST: phy: qcom: qmp-usbc: Rename USB-specific ops to prepare for DP support To support following DisplayPort (DP) mode over the Type-C PHY, rename USB-specific functions and ops to clearly separate them from common or DP-related logic. This is a preparatory cleanup to enable USB + DP dual mode. Reviewed-by: Dmitry Baryshkov Signed-off-by: Xiangxu Yin Link: https://lore.kernel.org/all/20250926-add-displayport-support-for-qcs615-platform-v7-2-dc5edaac6c2b@oss.qualcomm.com/ Signed-off-by: Yongxing Mou --- drivers/phy/qualcomm/phy-qcom-qmp-usbc.c | 55 ++++++++++++------------ 1 file changed, 27 insertions(+), 28 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c index 5e7fcb26744a4..62920dd2aed39 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c @@ -342,11 +342,10 @@ struct qmp_usbc { struct mutex phy_mutex; + struct phy *usb_phy; enum phy_mode mode; unsigned int usb_init_count; - struct phy *phy; - struct clk_fixed_rate pipe_clk_fixed; struct typec_switch_dev *sw; @@ -454,7 +453,7 @@ static const struct qmp_phy_cfg sdm660_usb3phy_cfg = { .regs = qmp_v3_usb3phy_regs_layout_qcm2290, }; -static int qmp_usbc_init(struct phy *phy) +static int qmp_usbc_com_init(struct phy *phy) { struct qmp_usbc *qmp = phy_get_drvdata(phy); const struct qmp_phy_cfg *cfg = qmp->cfg; @@ -504,7 +503,7 @@ static int qmp_usbc_init(struct phy *phy) return ret; } -static int qmp_usbc_exit(struct phy *phy) +static int qmp_usbc_com_exit(struct phy *phy) { struct qmp_usbc *qmp = phy_get_drvdata(phy); const struct qmp_phy_cfg *cfg = qmp->cfg; @@ -518,7 +517,7 @@ static int qmp_usbc_exit(struct phy *phy) return 0; } -static int qmp_usbc_power_on(struct phy *phy) +static int qmp_usbc_usb_power_on(struct phy *phy) { struct qmp_usbc *qmp = phy_get_drvdata(phy); const struct qmp_phy_cfg *cfg = qmp->cfg; @@ -566,7 +565,7 @@ static int qmp_usbc_power_on(struct phy *phy) return ret; } -static int qmp_usbc_power_off(struct phy *phy) +static int qmp_usbc_usb_power_off(struct phy *phy) { struct qmp_usbc *qmp = phy_get_drvdata(phy); const struct qmp_phy_cfg *cfg = qmp->cfg; @@ -587,20 +586,20 @@ static int qmp_usbc_power_off(struct phy *phy) return 0; } -static int qmp_usbc_enable(struct phy *phy) +static int qmp_usbc_usb_enable(struct phy *phy) { struct qmp_usbc *qmp = phy_get_drvdata(phy); int ret; mutex_lock(&qmp->phy_mutex); - ret = qmp_usbc_init(phy); + ret = qmp_usbc_com_init(phy); if (ret) goto out_unlock; - ret = qmp_usbc_power_on(phy); + ret = qmp_usbc_usb_power_on(phy); if (ret) { - qmp_usbc_exit(phy); + qmp_usbc_com_exit(phy); goto out_unlock; } @@ -611,19 +610,19 @@ static int qmp_usbc_enable(struct phy *phy) return ret; } -static int qmp_usbc_disable(struct phy *phy) +static int qmp_usbc_usb_disable(struct phy *phy) { struct qmp_usbc *qmp = phy_get_drvdata(phy); int ret; qmp->usb_init_count--; - ret = qmp_usbc_power_off(phy); + ret = qmp_usbc_usb_power_off(phy); if (ret) return ret; - return qmp_usbc_exit(phy); + return qmp_usbc_com_exit(phy); } -static int qmp_usbc_set_mode(struct phy *phy, enum phy_mode mode, int submode) +static int qmp_usbc_usb_set_mode(struct phy *phy, enum phy_mode mode, int submode) { struct qmp_usbc *qmp = phy_get_drvdata(phy); @@ -632,10 +631,10 @@ static int qmp_usbc_set_mode(struct phy *phy, enum phy_mode mode, int submode) return 0; } -static const struct phy_ops qmp_usbc_phy_ops = { - .init = qmp_usbc_enable, - .exit = qmp_usbc_disable, - .set_mode = qmp_usbc_set_mode, +static const struct phy_ops qmp_usbc_usb_phy_ops = { + .init = qmp_usbc_usb_enable, + .exit = qmp_usbc_usb_disable, + .set_mode = qmp_usbc_usb_set_mode, .owner = THIS_MODULE, }; @@ -690,7 +689,7 @@ static int __maybe_unused qmp_usbc_runtime_suspend(struct device *dev) dev_vdbg(dev, "Suspending QMP phy, mode:%d\n", qmp->mode); - if (!qmp->phy->init_count) { + if (!qmp->usb_init_count) { dev_vdbg(dev, "PHY not initialized, bailing out\n"); return 0; } @@ -710,7 +709,7 @@ static int __maybe_unused qmp_usbc_runtime_resume(struct device *dev) dev_vdbg(dev, "Resuming QMP phy, mode:%d\n", qmp->mode); - if (!qmp->phy->init_count) { + if (!qmp->usb_init_count) { dev_vdbg(dev, "PHY not initialized, bailing out\n"); return 0; } @@ -865,11 +864,11 @@ static int qmp_usbc_typec_switch_set(struct typec_switch_dev *sw, qmp->orientation = orientation; if (qmp->usb_init_count) { - qmp_usbc_power_off(qmp->phy); - qmp_usbc_exit(qmp->phy); + qmp_usbc_usb_power_off(qmp->usb_phy); + qmp_usbc_com_exit(qmp->usb_phy); - qmp_usbc_init(qmp->phy); - qmp_usbc_power_on(qmp->phy); + qmp_usbc_com_init(qmp->usb_phy); + qmp_usbc_usb_power_on(qmp->usb_phy); } mutex_unlock(&qmp->phy_mutex); @@ -1097,14 +1096,14 @@ static int qmp_usbc_probe(struct platform_device *pdev) if (ret) goto err_node_put; - qmp->phy = devm_phy_create(dev, np, &qmp_usbc_phy_ops); - if (IS_ERR(qmp->phy)) { - ret = PTR_ERR(qmp->phy); + qmp->usb_phy = devm_phy_create(dev, np, &qmp_usbc_usb_phy_ops); + if (IS_ERR(qmp->usb_phy)) { + ret = PTR_ERR(qmp->usb_phy); dev_err(dev, "failed to create PHY: %d\n", ret); goto err_node_put; } - phy_set_drvdata(qmp->phy, qmp); + phy_set_drvdata(qmp->usb_phy, qmp); of_node_put(np); From bbe8b3ca45d39aca59232c1e30ca8768fa512e7c Mon Sep 17 00:00:00 2001 From: Xiangxu Yin Date: Fri, 26 Sep 2025 15:25:39 +0800 Subject: [PATCH 0271/2333] FROMLIST: phy: qcom: qmp-usbc: Add DP-related fields for USB/DP switchable PHY Extend qmp_usbc_offsets and qmp_phy_cfg with DP-specific fields, including register offsets, init tables, and callback hooks. Also update qmp_usbc struct to track DP-related resources and state. This enables support for USB/DP switchable Type-C PHYs that operate in either mode. Reviewed-by: Dmitry Baryshkov Signed-off-by: Xiangxu Yin Link: https://lore.kernel.org/all/20250926-add-displayport-support-for-qcs615-platform-v7-3-dc5edaac6c2b@oss.qualcomm.com/ --- drivers/phy/qualcomm/phy-qcom-qmp-usbc.c | 54 ++++++++++++++++++++---- 1 file changed, 46 insertions(+), 8 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c index 62920dd2aed39..de28c3464a40e 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c @@ -293,13 +293,18 @@ struct qmp_usbc_offsets { /* for PHYs with >= 2 lanes */ u16 tx2; u16 rx2; + + u16 dp_serdes; + u16 dp_txa; + u16 dp_txb; + u16 dp_dp_phy; }; -/* struct qmp_phy_cfg - per-PHY initialization config */ +struct qmp_usbc; struct qmp_phy_cfg { const struct qmp_usbc_offsets *offsets; - /* Init sequence for PHY blocks - serdes, tx, rx, pcs */ + /* Init sequence for USB PHY blocks - serdes, tx, rx, pcs */ const struct qmp_phy_init_tbl *serdes_tbl; int serdes_tbl_num; const struct qmp_phy_init_tbl *tx_tbl; @@ -309,6 +314,27 @@ struct qmp_phy_cfg { const struct qmp_phy_init_tbl *pcs_tbl; int pcs_tbl_num; + /* Init sequence for DP PHY blocks - serdes, tx, rbr, hbr, hbr2 */ + const struct qmp_phy_init_tbl *dp_serdes_tbl; + int dp_serdes_tbl_num; + const struct qmp_phy_init_tbl *dp_tx_tbl; + int dp_tx_tbl_num; + const struct qmp_phy_init_tbl *serdes_tbl_rbr; + int serdes_tbl_rbr_num; + const struct qmp_phy_init_tbl *serdes_tbl_hbr; + int serdes_tbl_hbr_num; + const struct qmp_phy_init_tbl *serdes_tbl_hbr2; + int serdes_tbl_hbr2_num; + + const u8 (*swing_tbl)[4][4]; + const u8 (*pre_emphasis_tbl)[4][4]; + + /* DP PHY callbacks */ + void (*dp_aux_init)(struct qmp_usbc *qmp); + void (*configure_dp_tx)(struct qmp_usbc *qmp); + int (*configure_dp_phy)(struct qmp_usbc *qmp); + int (*calibrate_dp_phy)(struct qmp_usbc *qmp); + /* regulators to be requested */ const char * const *vreg_list; int num_vregs; @@ -329,24 +355,36 @@ struct qmp_usbc { void __iomem *rx; void __iomem *tx2; void __iomem *rx2; - - struct regmap *tcsr_map; - u32 vls_clamp_reg; + void __iomem *dp_dp_phy; + void __iomem *dp_tx; + void __iomem *dp_tx2; + void __iomem *dp_serdes; struct clk *pipe_clk; + struct clk_fixed_rate pipe_clk_fixed; + + struct clk_hw dp_link_hw; + struct clk_hw dp_pixel_hw; struct clk_bulk_data *clks; int num_clks; int num_resets; struct reset_control_bulk_data *resets; struct regulator_bulk_data *vregs; + struct regmap *tcsr_map; + u32 vls_clamp_reg; + u32 dp_phy_mode_reg; + struct mutex phy_mutex; struct phy *usb_phy; enum phy_mode mode; unsigned int usb_init_count; - struct clk_fixed_rate pipe_clk_fixed; + struct phy *dp_phy; + unsigned int dp_aux_cfg; + struct phy_configure_opts_dp dp_opts; + unsigned int dp_init_count; struct typec_switch_dev *sw; enum typec_orientation orientation; @@ -689,7 +727,7 @@ static int __maybe_unused qmp_usbc_runtime_suspend(struct device *dev) dev_vdbg(dev, "Suspending QMP phy, mode:%d\n", qmp->mode); - if (!qmp->usb_init_count) { + if (!qmp->usb_init_count && !qmp->dp_init_count) { dev_vdbg(dev, "PHY not initialized, bailing out\n"); return 0; } @@ -709,7 +747,7 @@ static int __maybe_unused qmp_usbc_runtime_resume(struct device *dev) dev_vdbg(dev, "Resuming QMP phy, mode:%d\n", qmp->mode); - if (!qmp->usb_init_count) { + if (!qmp->usb_init_count && !qmp->dp_init_count) { dev_vdbg(dev, "PHY not initialized, bailing out\n"); return 0; } From 23b72922abad7d86fe2ec8391ab3b1f1be241e5d Mon Sep 17 00:00:00 2001 From: Xiangxu Yin Date: Fri, 26 Sep 2025 15:25:40 +0800 Subject: [PATCH 0272/2333] FROMLIST: phy: qcom: qmp-usbc: Add regulator init_load support QMP USBC PHY drivers previously did not set init_load_uA for regulators, which could result in incorrect vote levels. This patch introduces regulator definitions with proper init_load_uA values based on each chip's power grid design. QCS615 USB3 PHY was previously reusing qcm2290_usb3phy_cfg, but its regulator requirements differ. A new qcs615_usb3phy_cfg is added to reflect the correct settings. Reviewed-by: Dmitry Baryshkov Signed-off-by: Xiangxu Yin Link: https://lore.kernel.org/all/20250926-add-displayport-support-for-qcs615-platform-v7-4-dc5edaac6c2b@oss.qualcomm.com/ --- drivers/phy/qualcomm/phy-qcom-qmp-usbc.c | 68 ++++++++++++++---------- 1 file changed, 39 insertions(+), 29 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c index de28c3464a40e..3b48c69f9c3cb 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c @@ -336,7 +336,7 @@ struct qmp_phy_cfg { int (*calibrate_dp_phy)(struct qmp_usbc *qmp); /* regulators to be requested */ - const char * const *vreg_list; + const struct regulator_bulk_data *vreg_list; int num_vregs; /* array of registers with different offsets */ @@ -428,9 +428,19 @@ static const char * const usb3phy_reset_l[] = { "phy_phy", "phy", }; -/* list of regulators */ -static const char * const qmp_phy_vreg_l[] = { - "vdda-phy", "vdda-pll", +static const struct regulator_bulk_data qmp_phy_msm8998_vreg_l[] = { + { .supply = "vdda-phy", .init_load_uA = 68600 }, + { .supply = "vdda-pll", .init_load_uA = 14200 }, +}; + +static const struct regulator_bulk_data qmp_phy_sm2290_vreg_l[] = { + { .supply = "vdda-phy", .init_load_uA = 66100 }, + { .supply = "vdda-pll", .init_load_uA = 13300 }, +}; + +static const struct regulator_bulk_data qmp_phy_qcs615_vreg_l[] = { + { .supply = "vdda-phy", .init_load_uA = 50000 }, + { .supply = "vdda-pll", .init_load_uA = 20000 }, }; static const struct qmp_usbc_offsets qmp_usbc_offsets_v3_qcm2290 = { @@ -454,8 +464,8 @@ static const struct qmp_phy_cfg msm8998_usb3phy_cfg = { .rx_tbl_num = ARRAY_SIZE(msm8998_usb3_rx_tbl), .pcs_tbl = msm8998_usb3_pcs_tbl, .pcs_tbl_num = ARRAY_SIZE(msm8998_usb3_pcs_tbl), - .vreg_list = qmp_phy_vreg_l, - .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), + .vreg_list = qmp_phy_msm8998_vreg_l, + .num_vregs = ARRAY_SIZE(qmp_phy_msm8998_vreg_l), .regs = qmp_v3_usb3phy_regs_layout, }; @@ -470,8 +480,8 @@ static const struct qmp_phy_cfg qcm2290_usb3phy_cfg = { .rx_tbl_num = ARRAY_SIZE(qcm2290_usb3_rx_tbl), .pcs_tbl = qcm2290_usb3_pcs_tbl, .pcs_tbl_num = ARRAY_SIZE(qcm2290_usb3_pcs_tbl), - .vreg_list = qmp_phy_vreg_l, - .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), + .vreg_list = qmp_phy_sm2290_vreg_l, + .num_vregs = ARRAY_SIZE(qmp_phy_sm2290_vreg_l), .regs = qmp_v3_usb3phy_regs_layout_qcm2290, }; @@ -486,8 +496,24 @@ static const struct qmp_phy_cfg sdm660_usb3phy_cfg = { .rx_tbl_num = ARRAY_SIZE(sdm660_usb3_rx_tbl), .pcs_tbl = qcm2290_usb3_pcs_tbl, .pcs_tbl_num = ARRAY_SIZE(qcm2290_usb3_pcs_tbl), - .vreg_list = qmp_phy_vreg_l, - .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), + .vreg_list = qmp_phy_msm8998_vreg_l, + .num_vregs = ARRAY_SIZE(qmp_phy_msm8998_vreg_l), + .regs = qmp_v3_usb3phy_regs_layout_qcm2290, +}; + +static const struct qmp_phy_cfg qcs615_usb3phy_cfg = { + .offsets = &qmp_usbc_offsets_v3_qcm2290, + + .serdes_tbl = qcm2290_usb3_serdes_tbl, + .serdes_tbl_num = ARRAY_SIZE(qcm2290_usb3_serdes_tbl), + .tx_tbl = qcm2290_usb3_tx_tbl, + .tx_tbl_num = ARRAY_SIZE(qcm2290_usb3_tx_tbl), + .rx_tbl = qcm2290_usb3_rx_tbl, + .rx_tbl_num = ARRAY_SIZE(qcm2290_usb3_rx_tbl), + .pcs_tbl = qcm2290_usb3_pcs_tbl, + .pcs_tbl_num = ARRAY_SIZE(qcm2290_usb3_pcs_tbl), + .vreg_list = qmp_phy_qcs615_vreg_l, + .num_vregs = ARRAY_SIZE(qmp_phy_qcs615_vreg_l), .regs = qmp_v3_usb3phy_regs_layout_qcm2290, }; @@ -773,23 +799,6 @@ static const struct dev_pm_ops qmp_usbc_pm_ops = { qmp_usbc_runtime_resume, NULL) }; -static int qmp_usbc_vreg_init(struct qmp_usbc *qmp) -{ - const struct qmp_phy_cfg *cfg = qmp->cfg; - struct device *dev = qmp->dev; - int num = cfg->num_vregs; - int i; - - qmp->vregs = devm_kcalloc(dev, num, sizeof(*qmp->vregs), GFP_KERNEL); - if (!qmp->vregs) - return -ENOMEM; - - for (i = 0; i < num; i++) - qmp->vregs[i].supply = cfg->vreg_list[i]; - - return devm_regulator_bulk_get(dev, num, qmp->vregs); -} - static int qmp_usbc_reset_init(struct qmp_usbc *qmp, const char *const *reset_list, int num_resets) @@ -1097,7 +1106,8 @@ static int qmp_usbc_probe(struct platform_device *pdev) mutex_init(&qmp->phy_mutex); - ret = qmp_usbc_vreg_init(qmp); + ret = devm_regulator_bulk_get_const(qmp->dev, qmp->cfg->num_vregs, + qmp->cfg->vreg_list, &qmp->vregs); if (ret) return ret; @@ -1163,7 +1173,7 @@ static const struct of_device_id qmp_usbc_of_match_table[] = { .data = &qcm2290_usb3phy_cfg, }, { .compatible = "qcom,qcs615-qmp-usb3-phy", - .data = &qcm2290_usb3phy_cfg, + .data = &qcs615_usb3phy_cfg, }, { .compatible = "qcom,sdm660-qmp-usb3-phy", .data = &sdm660_usb3phy_cfg, From 7c79865802593e988ac5e7f054d6030a373df808 Mon Sep 17 00:00:00 2001 From: Xiangxu Yin Date: Fri, 26 Sep 2025 15:25:41 +0800 Subject: [PATCH 0273/2333] FROMLIST: phy: qcom: qmp-usbc: Move reset config into PHY cfg The original reset list only works for USB-only PHYs. USB3DP PHYs require different reset names such as "dp_phy", so they need a separate list. Moving reset configuration into qmp_phy_cfg allows per-PHY customization without adding special-case logic in DT parsing. The legacy DT path keeps using the old hardcoded list, while non-legacy paths use cfg->reset_list. Reviewed-by: Dmitry Baryshkov Signed-off-by: Xiangxu Yin Link: https://lore.kernel.org/all/20250926-add-displayport-support-for-qcs615-platform-v7-5-dc5edaac6c2b@oss.qualcomm.com/ --- drivers/phy/qualcomm/phy-qcom-qmp-usbc.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c index 3b48c69f9c3cb..f9e20f43435c0 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c @@ -335,7 +335,8 @@ struct qmp_phy_cfg { int (*configure_dp_phy)(struct qmp_usbc *qmp); int (*calibrate_dp_phy)(struct qmp_usbc *qmp); - /* regulators to be requested */ + const char * const *reset_list; + int num_resets; const struct regulator_bulk_data *vreg_list; int num_vregs; @@ -464,6 +465,8 @@ static const struct qmp_phy_cfg msm8998_usb3phy_cfg = { .rx_tbl_num = ARRAY_SIZE(msm8998_usb3_rx_tbl), .pcs_tbl = msm8998_usb3_pcs_tbl, .pcs_tbl_num = ARRAY_SIZE(msm8998_usb3_pcs_tbl), + .reset_list = usb3phy_reset_l, + .num_resets = ARRAY_SIZE(usb3phy_reset_l), .vreg_list = qmp_phy_msm8998_vreg_l, .num_vregs = ARRAY_SIZE(qmp_phy_msm8998_vreg_l), .regs = qmp_v3_usb3phy_regs_layout, @@ -480,6 +483,8 @@ static const struct qmp_phy_cfg qcm2290_usb3phy_cfg = { .rx_tbl_num = ARRAY_SIZE(qcm2290_usb3_rx_tbl), .pcs_tbl = qcm2290_usb3_pcs_tbl, .pcs_tbl_num = ARRAY_SIZE(qcm2290_usb3_pcs_tbl), + .reset_list = usb3phy_reset_l, + .num_resets = ARRAY_SIZE(usb3phy_reset_l), .vreg_list = qmp_phy_sm2290_vreg_l, .num_vregs = ARRAY_SIZE(qmp_phy_sm2290_vreg_l), .regs = qmp_v3_usb3phy_regs_layout_qcm2290, @@ -496,6 +501,8 @@ static const struct qmp_phy_cfg sdm660_usb3phy_cfg = { .rx_tbl_num = ARRAY_SIZE(sdm660_usb3_rx_tbl), .pcs_tbl = qcm2290_usb3_pcs_tbl, .pcs_tbl_num = ARRAY_SIZE(qcm2290_usb3_pcs_tbl), + .reset_list = usb3phy_reset_l, + .num_resets = ARRAY_SIZE(usb3phy_reset_l), .vreg_list = qmp_phy_msm8998_vreg_l, .num_vregs = ARRAY_SIZE(qmp_phy_msm8998_vreg_l), .regs = qmp_v3_usb3phy_regs_layout_qcm2290, @@ -512,6 +519,8 @@ static const struct qmp_phy_cfg qcs615_usb3phy_cfg = { .rx_tbl_num = ARRAY_SIZE(qcm2290_usb3_rx_tbl), .pcs_tbl = qcm2290_usb3_pcs_tbl, .pcs_tbl_num = ARRAY_SIZE(qcm2290_usb3_pcs_tbl), + .reset_list = usb3phy_reset_l, + .num_resets = ARRAY_SIZE(usb3phy_reset_l), .vreg_list = qmp_phy_qcs615_vreg_l, .num_vregs = ARRAY_SIZE(qmp_phy_qcs615_vreg_l), .regs = qmp_v3_usb3phy_regs_layout_qcm2290, @@ -1051,8 +1060,7 @@ static int qmp_usbc_parse_dt(struct qmp_usbc *qmp) "failed to get pipe clock\n"); } - ret = qmp_usbc_reset_init(qmp, usb3phy_reset_l, - ARRAY_SIZE(usb3phy_reset_l)); + ret = qmp_usbc_reset_init(qmp, cfg->reset_list, cfg->num_resets); if (ret) return ret; From 438a47c6301a221d52d18d52375c64f237856f00 Mon Sep 17 00:00:00 2001 From: Xiangxu Yin Date: Fri, 26 Sep 2025 15:25:42 +0800 Subject: [PATCH 0274/2333] FROMLIST: phy: qcom: qmp-usbc: add DP link and vco_div clocks for DP PHY USB3DP PHY requires link and vco_div clocks when operating in DP mode. Extend qmp_usbc_register_clocks and the clock provider logic to register these clocks along with the existing pipe clock, to support both USB and DP configurations. Reviewed-by: Dmitry Baryshkov Signed-off-by: Xiangxu Yin Link: https://lore.kernel.org/all/20250926-add-displayport-support-for-qcs615-platform-v7-6-dc5edaac6c2b@oss.qualcomm.com/ --- drivers/phy/qualcomm/phy-qcom-qmp-usbc.c | 210 ++++++++++++++++++++++- 1 file changed, 204 insertions(+), 6 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c index f9e20f43435c0..7139f4dab82fd 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c @@ -22,6 +22,7 @@ #include #include #include +#include #include "phy-qcom-qmp-common.h" @@ -851,9 +852,23 @@ static int qmp_usbc_clk_init(struct qmp_usbc *qmp) return devm_clk_bulk_get_optional(dev, num, qmp->clks); } -static void phy_clk_release_provider(void *res) +static struct clk_hw *qmp_usbc_clks_hw_get(struct of_phandle_args *clkspec, void *data) { - of_clk_del_provider(res); + struct qmp_usbc *qmp = data; + + if (clkspec->args_count == 0) + return &qmp->pipe_clk_fixed.hw; + + switch (clkspec->args[0]) { + case QMP_USB43DP_USB3_PIPE_CLK: + return &qmp->pipe_clk_fixed.hw; + case QMP_USB43DP_DP_LINK_CLK: + return &qmp->dp_link_hw; + case QMP_USB43DP_DP_VCO_DIV_CLK: + return &qmp->dp_pixel_hw; + } + + return ERR_PTR(-EINVAL); } /* @@ -878,12 +893,14 @@ static int phy_pipe_clk_register(struct qmp_usbc *qmp, struct device_node *np) { struct clk_fixed_rate *fixed = &qmp->pipe_clk_fixed; struct clk_init_data init = { }; + char name[64]; int ret; ret = of_property_read_string(np, "clock-output-names", &init.name); if (ret) { - dev_err(qmp->dev, "%pOFn: No clock-output-names\n", np); - return ret; + /* Clock name is not mandatory. */ + snprintf(name, sizeof(name), "%s::pipe_clk", dev_name(qmp->dev)); + init.name = name; } init.ops = &clk_fixed_rate_ops; @@ -892,10 +909,184 @@ static int phy_pipe_clk_register(struct qmp_usbc *qmp, struct device_node *np) fixed->fixed_rate = 125000000; fixed->hw.init = &init; - ret = devm_clk_hw_register(qmp->dev, &fixed->hw); + return devm_clk_hw_register(qmp->dev, &fixed->hw); +} + + +/* + * Display Port PLL driver block diagram for branch clocks + * + * +------------------------------+ + * | DP_VCO_CLK | + * | | + * | +-------------------+ | + * | | (DP PLL/VCO) | | + * | +---------+---------+ | + * | v | + * | +----------+-----------+ | + * | | hsclk_divsel_clk_src | | + * | +----------+-----------+ | + * +------------------------------+ + * | + * +---------<---------v------------>----------+ + * | | + * +--------v----------------+ | + * | dp_phy_pll_link_clk | | + * | link_clk | | + * +--------+----------------+ | + * | | + * | | + * v v + * Input to DISPCC block | + * for link clk, crypto clk | + * and interface clock | + * | + * | + * +--------<------------+-----------------+---<---+ + * | | | + * +----v---------+ +--------v-----+ +--------v------+ + * | vco_divided | | vco_divided | | vco_divided | + * | _clk_src | | _clk_src | | _clk_src | + * | | | | | | + * |divsel_six | | divsel_two | | divsel_four | + * +-------+------+ +-----+--------+ +--------+------+ + * | | | + * v---->----------v-------------<------v + * | + * +----------+-----------------+ + * | dp_phy_pll_vco_div_clk | + * +---------+------------------+ + * | + * v + * Input to DISPCC block + * for DP pixel clock + * + */ +static int qmp_dp_pixel_clk_determine_rate(struct clk_hw *hw, struct clk_rate_request *req) +{ + switch (req->rate) { + case 1620000000UL / 2: + case 2700000000UL / 2: + /* 5.4 is same link rate as 2.7GHz, i.e. div 4 */ + return 0; + default: + return -EINVAL; + } +} + +static unsigned long qmp_dp_pixel_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) +{ + const struct qmp_usbc *qmp; + const struct phy_configure_opts_dp *dp_opts; + + qmp = container_of(hw, struct qmp_usbc, dp_pixel_hw); + + dp_opts = &qmp->dp_opts; + + switch (dp_opts->link_rate) { + case 1620: + return 1620000000UL / 2; + case 2700: + return 2700000000UL / 2; + case 5400: + return 5400000000UL / 4; + default: + return 0; + } +} + +static const struct clk_ops qmp_dp_pixel_clk_ops = { + .determine_rate = qmp_dp_pixel_clk_determine_rate, + .recalc_rate = qmp_dp_pixel_clk_recalc_rate, +}; + +static int qmp_dp_link_clk_determine_rate(struct clk_hw *hw, struct clk_rate_request *req) +{ + switch (req->rate) { + case 162000000: + case 270000000: + case 540000000: + return 0; + default: + return -EINVAL; + } +} + +static unsigned long qmp_dp_link_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) +{ + const struct qmp_usbc *qmp; + const struct phy_configure_opts_dp *dp_opts; + + qmp = container_of(hw, struct qmp_usbc, dp_link_hw); + dp_opts = &qmp->dp_opts; + + switch (dp_opts->link_rate) { + case 1620: + case 2700: + case 5400: + return dp_opts->link_rate * 100000; + default: + return 0; + } +} + +static const struct clk_ops qmp_dp_link_clk_ops = { + .determine_rate = qmp_dp_link_clk_determine_rate, + .recalc_rate = qmp_dp_link_clk_recalc_rate, +}; + +static int phy_dp_clks_register(struct qmp_usbc *qmp, struct device_node *np) +{ + struct clk_init_data init = { }; + char name[64]; + int ret; + + snprintf(name, sizeof(name), "%s::link_clk", dev_name(qmp->dev)); + init.ops = &qmp_dp_link_clk_ops; + init.name = name; + qmp->dp_link_hw.init = &init; + ret = devm_clk_hw_register(qmp->dev, &qmp->dp_link_hw); + if (ret < 0) { + dev_err(qmp->dev, "link clk reg fail ret=%d\n", ret); + return ret; + } + + snprintf(name, sizeof(name), "%s::vco_div_clk", dev_name(qmp->dev)); + init.ops = &qmp_dp_pixel_clk_ops; + init.name = name; + qmp->dp_pixel_hw.init = &init; + ret = devm_clk_hw_register(qmp->dev, &qmp->dp_pixel_hw); + if (ret) { + dev_err(qmp->dev, "pxl clk reg fail ret=%d\n", ret); + return ret; + } + + return 0; +} + +static void phy_clk_release_provider(void *res) +{ + of_clk_del_provider(res); +} + +static int qmp_usbc_register_clocks(struct qmp_usbc *qmp, struct device_node *np) +{ + struct clk_fixed_rate *fixed = &qmp->pipe_clk_fixed; + int ret; + + ret = phy_pipe_clk_register(qmp, np); if (ret) return ret; + if (qmp->dp_serdes != 0) { + ret = phy_dp_clks_register(qmp, np); + if (ret) + return ret; + } + + if (np == qmp->dev->of_node) + return devm_of_clk_add_hw_provider(qmp->dev, qmp_usbc_clks_hw_get, qmp); + ret = of_clk_add_hw_provider(np, of_clk_hw_simple_get, &fixed->hw); if (ret) return ret; @@ -1040,6 +1231,13 @@ static int qmp_usbc_parse_dt(struct qmp_usbc *qmp) if (IS_ERR(base)) return PTR_ERR(base); + if (offs->dp_serdes != 0) { + qmp->dp_serdes = base + offs->dp_serdes; + qmp->dp_tx = base + offs->dp_txa; + qmp->dp_tx2 = base + offs->dp_txb; + qmp->dp_dp_phy = base + offs->dp_dp_phy; + } + qmp->serdes = base + offs->serdes; qmp->pcs = base + offs->pcs; if (offs->pcs_misc) @@ -1148,7 +1346,7 @@ static int qmp_usbc_probe(struct platform_device *pdev) */ pm_runtime_forbid(dev); - ret = phy_pipe_clk_register(qmp, np); + ret = qmp_usbc_register_clocks(qmp, np); if (ret) goto err_node_put; From d34cfcedb88bd87f21be1c0275042bb6aaf8b858 Mon Sep 17 00:00:00 2001 From: Xiangxu Yin Date: Fri, 26 Sep 2025 15:25:43 +0800 Subject: [PATCH 0275/2333] FROMLIST: phy: qcom: qmp-usbc: Move USB-only init to usb_power_on The current implementation programs USB-specific registers in qmp_usbc_com_init(), which is shared by both USB and DP modes. This causes unnecessary configuration when the PHY is used for DP. Move USB-only register setup from com_init to qmp_usbc_usb_power_on, so it runs only for USB mode. Reviewed-by: Dmitry Baryshkov Signed-off-by: Xiangxu Yin Link: https://lore.kernel.org/all/20250926-add-displayport-support-for-qcs615-platform-v7-7-dc5edaac6c2b@oss.qualcomm.com/ --- drivers/phy/qualcomm/phy-qcom-qmp-usbc.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c index 7139f4dab82fd..a971bdc3e7677 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c @@ -30,6 +30,8 @@ #include "phy-qcom-qmp-pcs-misc-v3.h" #define PHY_INIT_COMPLETE_TIMEOUT 10000 +#define SW_PORTSELECT_VAL BIT(0) +#define SW_PORTSELECT_MUX BIT(1) /* set of registers with offsets different per-PHY */ enum qphy_reg_layout { @@ -531,8 +533,6 @@ static int qmp_usbc_com_init(struct phy *phy) { struct qmp_usbc *qmp = phy_get_drvdata(phy); const struct qmp_phy_cfg *cfg = qmp->cfg; - void __iomem *pcs = qmp->pcs; - u32 val = 0; int ret; ret = regulator_bulk_enable(cfg->num_vregs, qmp->vregs); @@ -557,16 +557,6 @@ static int qmp_usbc_com_init(struct phy *phy) if (ret) goto err_assert_reset; - qphy_setbits(pcs, cfg->regs[QPHY_PCS_POWER_DOWN_CONTROL], SW_PWRDN); - -#define SW_PORTSELECT_VAL BIT(0) -#define SW_PORTSELECT_MUX BIT(1) - /* Use software based port select and switch on typec orientation */ - val = SW_PORTSELECT_MUX; - if (qmp->orientation == TYPEC_ORIENTATION_REVERSE) - val |= SW_PORTSELECT_VAL; - writel(val, qmp->pcs_misc); - return 0; err_assert_reset: @@ -599,6 +589,14 @@ static int qmp_usbc_usb_power_on(struct phy *phy) unsigned int val; int ret; + qphy_setbits(qmp->pcs, cfg->regs[QPHY_PCS_POWER_DOWN_CONTROL], SW_PWRDN); + + /* Use software based port select and switch on typec orientation */ + val = SW_PORTSELECT_MUX; + if (qmp->orientation == TYPEC_ORIENTATION_REVERSE) + val |= SW_PORTSELECT_VAL; + writel(val, qmp->pcs_misc); + qmp_configure(qmp->dev, qmp->serdes, cfg->serdes_tbl, cfg->serdes_tbl_num); From 214c84c3f4c29ec2e1c816f101d3b77462c8de44 Mon Sep 17 00:00:00 2001 From: Xiangxu Yin Date: Fri, 26 Sep 2025 15:25:44 +0800 Subject: [PATCH 0276/2333] FROMLIST: phy: qcom: qmp-usbc: Add TCSR parsing and PHY mode setting Extend TCSR parsing to read optional dp_phy_mode_reg and add qmp_usbc_set_phy_mode() to switch between USB and DP modes when supported. Reviewed-by: Dmitry Baryshkov Signed-off-by: Xiangxu Yin Link: https://lore.kernel.org/all/20250926-add-displayport-support-for-qcs615-platform-v7-8-dc5edaac6c2b@oss.qualcomm.com/ --- drivers/phy/qualcomm/phy-qcom-qmp-usbc.c | 25 ++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c index a971bdc3e7677..fab6ccc4a5f12 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c @@ -529,6 +529,12 @@ static const struct qmp_phy_cfg qcs615_usb3phy_cfg = { .regs = qmp_v3_usb3phy_regs_layout_qcm2290, }; +static void qmp_usbc_set_phy_mode(struct qmp_usbc *qmp, bool is_dp) +{ + if (qmp->tcsr_map && qmp->dp_phy_mode_reg) + regmap_write(qmp->tcsr_map, qmp->dp_phy_mode_reg, is_dp); +} + static int qmp_usbc_com_init(struct phy *phy) { struct qmp_usbc *qmp = phy_get_drvdata(phy); @@ -669,6 +675,8 @@ static int qmp_usbc_usb_enable(struct phy *phy) if (ret) goto out_unlock; + qmp_usbc_set_phy_mode(qmp, false); + ret = qmp_usbc_usb_power_on(phy); if (ret) { qmp_usbc_com_exit(phy); @@ -1113,6 +1121,7 @@ static int qmp_usbc_typec_switch_set(struct typec_switch_dev *sw, qmp_usbc_com_exit(qmp->usb_phy); qmp_usbc_com_init(qmp->usb_phy); + qmp_usbc_set_phy_mode(qmp, false); qmp_usbc_usb_power_on(qmp->usb_phy); } @@ -1263,15 +1272,16 @@ static int qmp_usbc_parse_dt(struct qmp_usbc *qmp) return 0; } -static int qmp_usbc_parse_vls_clamp(struct qmp_usbc *qmp) +static int qmp_usbc_parse_tcsr(struct qmp_usbc *qmp) { struct of_phandle_args tcsr_args; struct device *dev = qmp->dev; - int ret; + int ret, args_count; - /* for backwards compatibility ignore if there is no property */ - ret = of_parse_phandle_with_fixed_args(dev->of_node, "qcom,tcsr-reg", 1, 0, - &tcsr_args); + args_count = of_property_count_u32_elems(dev->of_node, "qcom,tcsr-reg"); + args_count = args_count - 1; + ret = of_parse_phandle_with_fixed_args(dev->of_node, "qcom,tcsr-reg", + args_count, 0, &tcsr_args); if (ret == -ENOENT) return 0; else if (ret < 0) @@ -1284,6 +1294,9 @@ static int qmp_usbc_parse_vls_clamp(struct qmp_usbc *qmp) qmp->vls_clamp_reg = tcsr_args.args[0]; + if (args_count > 1) + qmp->dp_phy_mode_reg = tcsr_args.args[1]; + return 0; } @@ -1319,7 +1332,7 @@ static int qmp_usbc_probe(struct platform_device *pdev) if (ret) return ret; - ret = qmp_usbc_parse_vls_clamp(qmp); + ret = qmp_usbc_parse_tcsr(qmp); if (ret) return ret; From d49b976eb68c1f18970f5456ee6c9eda8547e6f2 Mon Sep 17 00:00:00 2001 From: Xiangxu Yin Date: Fri, 26 Sep 2025 15:25:45 +0800 Subject: [PATCH 0277/2333] FROMLIST: phy: qcom: qmp-usbc: Add DP PHY ops for USB/DP switchable Type-C PHYs Define qmp_usbc_dp_phy_ops struct to support DP mode on USB/DP switchable PHYs. Reviewed-by: Dmitry Baryshkov Signed-off-by: Xiangxu Yin Link: https://lore.kernel.org/all/20250926-add-displayport-support-for-qcs615-platform-v7-9-dc5edaac6c2b@oss.qualcomm.com/ --- drivers/phy/qualcomm/phy-qcom-qmp-usbc.c | 194 ++++++++++++++++++++++- 1 file changed, 193 insertions(+), 1 deletion(-) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c index fab6ccc4a5f12..3580c19fd62e0 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c @@ -29,6 +29,8 @@ #include "phy-qcom-qmp.h" #include "phy-qcom-qmp-pcs-misc-v3.h" +#include "phy-qcom-qmp-dp-phy.h" + #define PHY_INIT_COMPLETE_TIMEOUT 10000 #define SW_PORTSELECT_VAL BIT(0) #define SW_PORTSELECT_MUX BIT(1) @@ -711,6 +713,159 @@ static int qmp_usbc_usb_set_mode(struct phy *phy, enum phy_mode mode, int submod return 0; } +static int qmp_usbc_dp_enable(struct phy *phy) +{ + struct qmp_usbc *qmp = phy_get_drvdata(phy); + const struct qmp_phy_cfg *cfg = qmp->cfg; + int ret; + + if (qmp->dp_init_count) { + dev_err(qmp->dev, "DP already inited\n"); + return 0; + } + + mutex_lock(&qmp->phy_mutex); + + ret = qmp_usbc_com_init(phy); + if (ret) + goto dp_init_unlock; + + qmp_usbc_set_phy_mode(qmp, true); + + cfg->dp_aux_init(qmp); + + qmp->dp_init_count++; + +dp_init_unlock: + mutex_unlock(&qmp->phy_mutex); + return ret; +} + +static int qmp_usbc_dp_disable(struct phy *phy) +{ + struct qmp_usbc *qmp = phy_get_drvdata(phy); + + mutex_lock(&qmp->phy_mutex); + + qmp_usbc_com_exit(phy); + + qmp->dp_init_count--; + + mutex_unlock(&qmp->phy_mutex); + + return 0; +} + +static int qmp_usbc_dp_configure(struct phy *phy, union phy_configure_opts *opts) +{ + const struct phy_configure_opts_dp *dp_opts = &opts->dp; + struct qmp_usbc *qmp = phy_get_drvdata(phy); + const struct qmp_phy_cfg *cfg = qmp->cfg; + + mutex_lock(&qmp->phy_mutex); + + memcpy(&qmp->dp_opts, dp_opts, sizeof(*dp_opts)); + if (qmp->dp_opts.set_voltages) { + cfg->configure_dp_tx(qmp); + qmp->dp_opts.set_voltages = 0; + } + + mutex_unlock(&qmp->phy_mutex); + + return 0; +} + +static int qmp_usbc_dp_calibrate(struct phy *phy) +{ + struct qmp_usbc *qmp = phy_get_drvdata(phy); + const struct qmp_phy_cfg *cfg = qmp->cfg; + int ret = 0; + + mutex_lock(&qmp->phy_mutex); + + if (cfg->calibrate_dp_phy) { + ret = cfg->calibrate_dp_phy(qmp); + if (ret) { + dev_err(qmp->dev, "dp calibrate err(%d)\n", ret); + mutex_unlock(&qmp->phy_mutex); + return ret; + } + } + + mutex_unlock(&qmp->phy_mutex); + return 0; +} + +static int qmp_usbc_dp_serdes_init(struct qmp_usbc *qmp) +{ + const struct qmp_phy_cfg *cfg = qmp->cfg; + void __iomem *serdes = qmp->dp_serdes; + const struct phy_configure_opts_dp *dp_opts = &qmp->dp_opts; + + qmp_configure(qmp->dev, serdes, cfg->dp_serdes_tbl, + cfg->dp_serdes_tbl_num); + + switch (dp_opts->link_rate) { + case 1620: + qmp_configure(qmp->dev, serdes, cfg->serdes_tbl_rbr, + cfg->serdes_tbl_rbr_num); + break; + case 2700: + qmp_configure(qmp->dev, serdes, cfg->serdes_tbl_hbr, + cfg->serdes_tbl_hbr_num); + break; + case 5400: + qmp_configure(qmp->dev, serdes, cfg->serdes_tbl_hbr2, + cfg->serdes_tbl_hbr2_num); + break; + default: + /* Other link rates aren't supported */ + return -EINVAL; + } + + return 0; +} + +static int qmp_usbc_dp_power_on(struct phy *phy) +{ + struct qmp_usbc *qmp = phy_get_drvdata(phy); + const struct qmp_phy_cfg *cfg = qmp->cfg; + + void __iomem *tx = qmp->dp_tx; + void __iomem *tx2 = qmp->dp_tx2; + + mutex_lock(&qmp->phy_mutex); + + qmp_usbc_dp_serdes_init(qmp); + + qmp_configure_lane(qmp->dev, tx, cfg->dp_tx_tbl, cfg->dp_tx_tbl_num, 1); + qmp_configure_lane(qmp->dev, tx2, cfg->dp_tx_tbl, cfg->dp_tx_tbl_num, 2); + + /* Configure special DP tx tunings */ + cfg->configure_dp_tx(qmp); + + /* Configure link rate, swing, etc. */ + cfg->configure_dp_phy(qmp); + + mutex_unlock(&qmp->phy_mutex); + + return 0; +} + +static int qmp_usbc_dp_power_off(struct phy *phy) +{ + struct qmp_usbc *qmp = phy_get_drvdata(phy); + + mutex_lock(&qmp->phy_mutex); + + /* Assert DP PHY power down */ + writel(DP_PHY_PD_CTL_PSR_PWRDN, qmp->dp_dp_phy + QSERDES_DP_PHY_PD_CTL); + + mutex_unlock(&qmp->phy_mutex); + + return 0; +} + static const struct phy_ops qmp_usbc_usb_phy_ops = { .init = qmp_usbc_usb_enable, .exit = qmp_usbc_usb_disable, @@ -718,6 +873,16 @@ static const struct phy_ops qmp_usbc_usb_phy_ops = { .owner = THIS_MODULE, }; +static const struct phy_ops qmp_usbc_dp_phy_ops = { + .init = qmp_usbc_dp_enable, + .exit = qmp_usbc_dp_disable, + .configure = qmp_usbc_dp_configure, + .calibrate = qmp_usbc_dp_calibrate, + .power_on = qmp_usbc_dp_power_on, + .power_off = qmp_usbc_dp_power_off, + .owner = THIS_MODULE, +}; + static void qmp_usbc_enable_autonomous_mode(struct qmp_usbc *qmp) { const struct qmp_phy_cfg *cfg = qmp->cfg; @@ -1300,6 +1465,23 @@ static int qmp_usbc_parse_tcsr(struct qmp_usbc *qmp) return 0; } +static struct phy *qmp_usbc_phy_xlate(struct device *dev, const struct of_phandle_args *args) +{ + struct qmp_usbc *qmp = dev_get_drvdata(dev); + + if (args->args_count == 0) + return qmp->usb_phy; + + switch (args->args[0]) { + case QMP_USB43DP_USB3_PHY: + return qmp->usb_phy; + case QMP_USB43DP_DP_PHY: + return qmp->dp_phy ?: ERR_PTR(-ENODEV); + } + + return ERR_PTR(-EINVAL); +} + static int qmp_usbc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -1370,9 +1552,19 @@ static int qmp_usbc_probe(struct platform_device *pdev) phy_set_drvdata(qmp->usb_phy, qmp); + if (qmp->dp_serdes != 0) { + qmp->dp_phy = devm_phy_create(dev, np, &qmp_usbc_dp_phy_ops); + if (IS_ERR(qmp->dp_phy)) { + ret = PTR_ERR(qmp->dp_phy); + dev_err(dev, "failed to create PHY: %d\n", ret); + goto err_node_put; + } + phy_set_drvdata(qmp->dp_phy, qmp); + } + of_node_put(np); - phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); + phy_provider = devm_of_phy_provider_register(dev, qmp_usbc_phy_xlate); return PTR_ERR_OR_ZERO(phy_provider); From aa83118cf6341478bd7b1eec94872bc3b53df57d Mon Sep 17 00:00:00 2001 From: Xiangxu Yin Date: Fri, 26 Sep 2025 15:25:46 +0800 Subject: [PATCH 0278/2333] FROMLIST: phy: qcom: qmp-usbc: Add USB/DP exclude handling When both USB and DP PHY modes are enabled simultaneously on the same QMP USBC PHY, it can lead to hardware misconfiguration and undefined behavior. This happens because the PHY resources are not designed to operate in both modes at the same time. To prevent this, introduce a mutual exclusion check between USB and DP PHY modes. Reviewed-by: Dmitry Baryshkov Signed-off-by: Xiangxu Yin Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/all/20250926-add-displayport-support-for-qcs615-platform-v7-10-dc5edaac6c2b@oss.qualcomm.com/ --- drivers/phy/qualcomm/phy-qcom-qmp-usbc.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c index 3580c19fd62e0..d84bf68940043 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c @@ -666,6 +666,19 @@ static int qmp_usbc_usb_power_off(struct phy *phy) return 0; } +static int qmp_usbc_check_phy_status(struct qmp_usbc *qmp, bool is_dp) +{ + if ((is_dp && qmp->usb_init_count) || + (!is_dp && qmp->dp_init_count)) { + dev_err(qmp->dev, + "PHY is configured for %s, can not enable %s\n", + is_dp ? "USB" : "DP", is_dp ? "DP" : "USB"); + return -EBUSY; + } + + return 0; +} + static int qmp_usbc_usb_enable(struct phy *phy) { struct qmp_usbc *qmp = phy_get_drvdata(phy); @@ -673,6 +686,10 @@ static int qmp_usbc_usb_enable(struct phy *phy) mutex_lock(&qmp->phy_mutex); + ret = qmp_usbc_check_phy_status(qmp, false); + if (ret) + goto out_unlock; + ret = qmp_usbc_com_init(phy); if (ret) goto out_unlock; @@ -726,6 +743,10 @@ static int qmp_usbc_dp_enable(struct phy *phy) mutex_lock(&qmp->phy_mutex); + ret = qmp_usbc_check_phy_status(qmp, true); + if (ret) + goto dp_init_unlock; + ret = qmp_usbc_com_init(phy); if (ret) goto dp_init_unlock; From e27d38e37537bd5cdc967e20ad907ae5d89cab17 Mon Sep 17 00:00:00 2001 From: Xiangxu Yin Date: Fri, 26 Sep 2025 15:25:47 +0800 Subject: [PATCH 0279/2333] FROMLIST: phy: qcom: qmp: Add DP v2 PHY register definitions Add dedicated headers for DP v2 PHY, including QSERDES COM and TX/RX register definitions. Reviewed-by: Dmitry Baryshkov Signed-off-by: Xiangxu Yin Link: https://lore.kernel.org/all/20250926-add-displayport-support-for-qcs615-platform-v7-11-dc5edaac6c2b@oss.qualcomm.com/ --- drivers/phy/qualcomm/phy-qcom-qmp-dp-phy-v2.h | 21 ++++ .../qualcomm/phy-qcom-qmp-qserdes-com-v2.h | 106 ++++++++++++++++++ .../qualcomm/phy-qcom-qmp-qserdes-txrx-v2.h | 68 +++++++++++ drivers/phy/qualcomm/phy-qcom-qmp.h | 3 + 4 files changed, 198 insertions(+) create mode 100644 drivers/phy/qualcomm/phy-qcom-qmp-dp-phy-v2.h create mode 100644 drivers/phy/qualcomm/phy-qcom-qmp-qserdes-com-v2.h create mode 100644 drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v2.h diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-dp-phy-v2.h b/drivers/phy/qualcomm/phy-qcom-qmp-dp-phy-v2.h new file mode 100644 index 0000000000000..8b9572d3cdebb --- /dev/null +++ b/drivers/phy/qualcomm/phy-qcom-qmp-dp-phy-v2.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2017, The Linux Foundation. All rights reserved. + */ + +#ifndef QCOM_PHY_QMP_DP_PHY_V2_H_ +#define QCOM_PHY_QMP_DP_PHY_V2_H_ + +// /* Only for QMP V2 PHY - DP PHY registers */ +#define QSERDES_V2_DP_PHY_AUX_INTERRUPT_MASK 0x048 +#define QSERDES_V2_DP_PHY_AUX_INTERRUPT_CLEAR 0x04c +#define QSERDES_V2_DP_PHY_AUX_BIST_CFG 0x050 + +#define QSERDES_V2_DP_PHY_VCO_DIV 0x068 +#define QSERDES_V2_DP_PHY_TX0_TX1_LANE_CTL 0x06c +#define QSERDES_V2_DP_PHY_TX2_TX3_LANE_CTL 0x088 + +#define QSERDES_V2_DP_PHY_SPARE0 0x0ac +#define QSERDES_V2_DP_PHY_STATUS 0x0c0 + +#endif diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-com-v2.h b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-com-v2.h new file mode 100644 index 0000000000000..3ea1884f35dd5 --- /dev/null +++ b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-com-v2.h @@ -0,0 +1,106 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2017, The Linux Foundation. All rights reserved. + */ + +#ifndef QCOM_PHY_QMP_QSERDES_COM_V2_H_ +#define QCOM_PHY_QMP_QSERDES_COM_V2_H_ + +/* Only for QMP V2 PHY - QSERDES COM registers */ +#define QSERDES_V2_COM_ATB_SEL1 0x000 +#define QSERDES_V2_COM_ATB_SEL2 0x004 +#define QSERDES_V2_COM_FREQ_UPDATE 0x008 +#define QSERDES_V2_COM_BG_TIMER 0x00c +#define QSERDES_V2_COM_SSC_EN_CENTER 0x010 +#define QSERDES_V2_COM_SSC_ADJ_PER1 0x014 +#define QSERDES_V2_COM_SSC_ADJ_PER2 0x018 +#define QSERDES_V2_COM_SSC_PER1 0x01c +#define QSERDES_V2_COM_SSC_PER2 0x020 +#define QSERDES_V2_COM_SSC_STEP_SIZE1 0x024 +#define QSERDES_V2_COM_SSC_STEP_SIZE2 0x028 +#define QSERDES_V2_COM_POST_DIV 0x02c +#define QSERDES_V2_COM_POST_DIV_MUX 0x030 +#define QSERDES_V2_COM_BIAS_EN_CLKBUFLR_EN 0x034 +#define QSERDES_V2_COM_CLK_ENABLE1 0x038 +#define QSERDES_V2_COM_SYS_CLK_CTRL 0x03c +#define QSERDES_V2_COM_SYSCLK_BUF_ENABLE 0x040 +#define QSERDES_V2_COM_PLL_EN 0x044 +#define QSERDES_V2_COM_PLL_IVCO 0x048 +#define QSERDES_V2_COM_LOCK_CMP1_MODE0 0x04c +#define QSERDES_V2_COM_LOCK_CMP2_MODE0 0x050 +#define QSERDES_V2_COM_LOCK_CMP3_MODE0 0x054 +#define QSERDES_V2_COM_LOCK_CMP1_MODE1 0x058 +#define QSERDES_V2_COM_LOCK_CMP2_MODE1 0x05c +#define QSERDES_V2_COM_LOCK_CMP3_MODE1 0x060 +#define QSERDES_V2_COM_EP_CLOCK_DETECT_CTR 0x068 +#define QSERDES_V2_COM_SYSCLK_DET_COMP_STATUS 0x06c +#define QSERDES_V2_COM_CLK_EP_DIV 0x074 +#define QSERDES_V2_COM_CP_CTRL_MODE0 0x078 +#define QSERDES_V2_COM_CP_CTRL_MODE1 0x07c +#define QSERDES_V2_COM_PLL_RCTRL_MODE0 0x084 +#define QSERDES_V2_COM_PLL_RCTRL_MODE1 0x088 +#define QSERDES_V2_COM_PLL_CCTRL_MODE0 0x090 +#define QSERDES_V2_COM_PLL_CCTRL_MODE1 0x094 +#define QSERDES_V2_COM_PLL_CNTRL 0x09c +#define QSERDES_V2_COM_BIAS_EN_CTRL_BY_PSM 0x0a8 +#define QSERDES_V2_COM_SYSCLK_EN_SEL 0x0ac +#define QSERDES_V2_COM_CML_SYSCLK_SEL 0x0b0 +#define QSERDES_V2_COM_RESETSM_CNTRL 0x0b4 +#define QSERDES_V2_COM_RESETSM_CNTRL2 0x0b8 +#define QSERDES_V2_COM_LOCK_CMP_EN 0x0c8 +#define QSERDES_V2_COM_LOCK_CMP_CFG 0x0cc +#define QSERDES_V2_COM_DEC_START_MODE0 0x0d0 +#define QSERDES_V2_COM_DEC_START_MODE1 0x0d4 +#define QSERDES_V2_COM_VCOCAL_DEADMAN_CTRL 0x0d8 +#define QSERDES_V2_COM_DIV_FRAC_START1_MODE0 0x0dc +#define QSERDES_V2_COM_DIV_FRAC_START2_MODE0 0x0e0 +#define QSERDES_V2_COM_DIV_FRAC_START3_MODE0 0x0e4 +#define QSERDES_V2_COM_DIV_FRAC_START1_MODE1 0x0e8 +#define QSERDES_V2_COM_DIV_FRAC_START2_MODE1 0x0ec +#define QSERDES_V2_COM_DIV_FRAC_START3_MODE1 0x0f0 +#define QSERDES_V2_COM_VCO_TUNE_MINVAL1 0x0f4 +#define QSERDES_V2_COM_VCO_TUNE_MINVAL2 0x0f8 +#define QSERDES_V2_COM_INTEGLOOP_INITVAL 0x100 +#define QSERDES_V2_COM_INTEGLOOP_EN 0x104 +#define QSERDES_V2_COM_INTEGLOOP_GAIN0_MODE0 0x108 +#define QSERDES_V2_COM_INTEGLOOP_GAIN1_MODE0 0x10c +#define QSERDES_V2_COM_INTEGLOOP_GAIN0_MODE1 0x110 +#define QSERDES_V2_COM_INTEGLOOP_GAIN1_MODE1 0x114 +#define QSERDES_V2_COM_VCO_TUNE_MAXVAL1 0x118 +#define QSERDES_V2_COM_VCO_TUNE_MAXVAL2 0x11c +#define QSERDES_V2_COM_VCO_TUNE_CTRL 0x124 +#define QSERDES_V2_COM_VCO_TUNE_MAP 0x128 +#define QSERDES_V2_COM_VCO_TUNE1_MODE0 0x12c +#define QSERDES_V2_COM_VCO_TUNE2_MODE0 0x130 +#define QSERDES_V2_COM_VCO_TUNE1_MODE1 0x134 +#define QSERDES_V2_COM_VCO_TUNE2_MODE1 0x138 +#define QSERDES_V2_COM_VCO_TUNE_INITVAL1 0x13c +#define QSERDES_V2_COM_VCO_TUNE_INITVAL2 0x140 +#define QSERDES_V2_COM_VCO_TUNE_TIMER1 0x144 +#define QSERDES_V2_COM_VCO_TUNE_TIMER2 0x148 +#define QSERDES_V2_COM_CMN_STATUS 0x15c +#define QSERDES_V2_COM_RESET_SM_STATUS 0x160 +#define QSERDES_V2_COM_RESTRIM_CODE_STATUS 0x164 +#define QSERDES_V2_COM_PLLCAL_CODE1_STATUS 0x168 +#define QSERDES_V2_COM_PLLCAL_CODE2_STATUS 0x16c +#define QSERDES_V2_COM_CLK_SELECT 0x174 +#define QSERDES_V2_COM_HSCLK_SEL 0x178 +#define QSERDES_V2_COM_INTEGLOOP_BINCODE_STATUS 0x17c +#define QSERDES_V2_COM_PLL_ANALOG 0x180 +#define QSERDES_V2_COM_CORECLK_DIV 0x184 +#define QSERDES_V2_COM_SW_RESET 0x188 +#define QSERDES_V2_COM_CORE_CLK_EN 0x18c +#define QSERDES_V2_COM_C_READY_STATUS 0x190 +#define QSERDES_V2_COM_CMN_CONFIG 0x194 +#define QSERDES_V2_COM_CMN_RATE_OVERRIDE 0x198 +#define QSERDES_V2_COM_SVS_MODE_CLK_SEL 0x19c +#define QSERDES_V2_COM_DEBUG_BUS0 0x1a0 +#define QSERDES_V2_COM_DEBUG_BUS1 0x1a4 +#define QSERDES_V2_COM_DEBUG_BUS2 0x1a8 +#define QSERDES_V2_COM_DEBUG_BUS3 0x1ac +#define QSERDES_V2_COM_DEBUG_BUS_SEL 0x1b0 +#define QSERDES_V2_COM_CMN_MISC1 0x1b4 +#define QSERDES_V2_COM_CMN_MISC2 0x1b8 +#define QSERDES_V2_COM_CORECLK_DIV_MODE1 0x1bc + +#endif diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v2.h b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v2.h new file mode 100644 index 0000000000000..34919720b7bc4 --- /dev/null +++ b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v2.h @@ -0,0 +1,68 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2017, The Linux Foundation. All rights reserved. + */ + +#ifndef QCOM_PHY_QMP_QSERDES_TXRX_V2_H_ +#define QCOM_PHY_QMP_QSERDES_TXRX_V2_H_ + +/* Only for QMP V2 PHY - TX registers */ +#define QSERDES_V2_TX_BIST_MODE_LANENO 0x000 +#define QSERDES_V2_TX_CLKBUF_ENABLE 0x008 +#define QSERDES_V2_TX_TX_EMP_POST1_LVL 0x00c +#define QSERDES_V2_TX_TX_DRV_LVL 0x01c +#define QSERDES_V2_TX_RESET_TSYNC_EN 0x024 +#define QSERDES_V2_TX_PRE_STALL_LDO_BOOST_EN 0x028 +#define QSERDES_V2_TX_TX_BAND 0x02c +#define QSERDES_V2_TX_SLEW_CNTL 0x030 +#define QSERDES_V2_TX_INTERFACE_SELECT 0x034 +#define QSERDES_V2_TX_RES_CODE_LANE_TX 0x03c +#define QSERDES_V2_TX_RES_CODE_LANE_RX 0x040 +#define QSERDES_V2_TX_RES_CODE_LANE_OFFSET_TX 0x044 +#define QSERDES_V2_TX_RES_CODE_LANE_OFFSET_RX 0x048 +#define QSERDES_V2_TX_DEBUG_BUS_SEL 0x058 +#define QSERDES_V2_TX_TRANSCEIVER_BIAS_EN 0x05c +#define QSERDES_V2_TX_HIGHZ_DRVR_EN 0x060 +#define QSERDES_V2_TX_TX_POL_INV 0x064 +#define QSERDES_V2_TX_PARRATE_REC_DETECT_IDLE_EN 0x068 +#define QSERDES_V2_TX_LANE_MODE_1 0x08c +#define QSERDES_V2_TX_LANE_MODE_2 0x090 +#define QSERDES_V2_TX_LANE_MODE_3 0x094 +#define QSERDES_V2_TX_RCV_DETECT_LVL_2 0x0a4 +#define QSERDES_V2_TX_TRAN_DRVR_EMP_EN 0x0c0 +#define QSERDES_V2_TX_TX_INTERFACE_MODE 0x0c4 +#define QSERDES_V2_TX_VMODE_CTRL1 0x0f0 + +/* Only for QMP V2 PHY - RX registers */ +#define QSERDES_V2_RX_UCDR_FO_GAIN 0x008 +#define QSERDES_V2_RX_UCDR_SO_GAIN_HALF 0x00c +#define QSERDES_V2_RX_UCDR_SO_GAIN 0x014 +#define QSERDES_V2_RX_UCDR_SVS_SO_GAIN_HALF 0x024 +#define QSERDES_V2_RX_UCDR_SVS_SO_GAIN_QUARTER 0x028 +#define QSERDES_V2_RX_UCDR_SVS_SO_GAIN 0x02c +#define QSERDES_V2_RX_UCDR_FASTLOCK_FO_GAIN 0x030 +#define QSERDES_V2_RX_UCDR_SO_SATURATION_AND_ENABLE 0x034 +#define QSERDES_V2_RX_UCDR_FASTLOCK_COUNT_LOW 0x03c +#define QSERDES_V2_RX_UCDR_FASTLOCK_COUNT_HIGH 0x040 +#define QSERDES_V2_RX_UCDR_PI_CONTROLS 0x044 +#define QSERDES_V2_RX_RX_TERM_BW 0x07c +#define QSERDES_V2_RX_VGA_CAL_CNTRL1 0x0bc +#define QSERDES_V2_RX_VGA_CAL_CNTRL2 0x0c0 +#define QSERDES_V2_RX_RX_EQ_GAIN2_LSB 0x0c8 +#define QSERDES_V2_RX_RX_EQ_GAIN2_MSB 0x0cc +#define QSERDES_V2_RX_RX_EQU_ADAPTOR_CNTRL1 0x0d0 +#define QSERDES_V2_RX_RX_EQU_ADAPTOR_CNTRL2 0x0d4 +#define QSERDES_V2_RX_RX_EQU_ADAPTOR_CNTRL3 0x0d8 +#define QSERDES_V2_RX_RX_EQU_ADAPTOR_CNTRL4 0x0dc +#define QSERDES_V2_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1 0x0f8 +#define QSERDES_V2_RX_RX_OFFSET_ADAPTOR_CNTRL2 0x0fc +#define QSERDES_V2_RX_SIGDET_ENABLES 0x100 +#define QSERDES_V2_RX_SIGDET_CNTRL 0x104 +#define QSERDES_V2_RX_SIGDET_LVL 0x108 +#define QSERDES_V2_RX_SIGDET_DEGLITCH_CNTRL 0x10c +#define QSERDES_V2_RX_RX_BAND 0x110 +#define QSERDES_V2_RX_RX_INTERFACE_MODE 0x11c +#define QSERDES_V2_RX_RX_MODE_00 0x164 +#define QSERDES_V2_RX_RX_MODE_01 0x168 + +#endif diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.h b/drivers/phy/qualcomm/phy-qcom-qmp.h index f58c82b2dd23e..1a9e4cc5aa11d 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp.h +++ b/drivers/phy/qualcomm/phy-qcom-qmp.h @@ -9,6 +9,9 @@ #include "phy-qcom-qmp-qserdes-com.h" #include "phy-qcom-qmp-qserdes-txrx.h" +#include "phy-qcom-qmp-qserdes-com-v2.h" +#include "phy-qcom-qmp-qserdes-txrx-v2.h" + #include "phy-qcom-qmp-qserdes-com-v3.h" #include "phy-qcom-qmp-qserdes-txrx-v3.h" From a2209bb333d40e18875d277f530072b1bb13ea00 Mon Sep 17 00:00:00 2001 From: Xiangxu Yin Date: Fri, 26 Sep 2025 15:25:48 +0800 Subject: [PATCH 0280/2333] FROMLIST: phy: qcom: qmp-usbc: Add QCS615 USB/DP PHY config and DP mode support Add QCS615-specific configuration for USB/DP PHY, including DP init routines, voltage swing tables, and platform data. Add compatible "qcs615-qmp-usb3-dp-phy". Note: SW_PORTSELECT handling for orientation flip is not implemented due to QCS615 fixed-orientation design and non-standard lane mapping. Signed-off-by: Xiangxu Yin Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/all/20250926-add-displayport-support-for-qcs615-platform-v7-12-dc5edaac6c2b@oss.qualcomm.com/ --- drivers/phy/qualcomm/phy-qcom-qmp-usbc.c | 413 +++++++++++++++++++++++ 1 file changed, 413 insertions(+) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c index d84bf68940043..105cc0f4b8ddd 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c @@ -30,6 +30,7 @@ #include "phy-qcom-qmp-pcs-misc-v3.h" #include "phy-qcom-qmp-dp-phy.h" +#include "phy-qcom-qmp-dp-phy-v2.h" #define PHY_INIT_COMPLETE_TIMEOUT 10000 #define SW_PORTSELECT_VAL BIT(0) @@ -289,6 +290,83 @@ static const struct qmp_phy_init_tbl qcm2290_usb3_pcs_tbl[] = { QMP_PHY_INIT_CFG(QPHY_V3_PCS_RX_SIGDET_LVL, 0x88), }; +static const struct qmp_phy_init_tbl qmp_v2_dp_serdes_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_COM_SVS_MODE_CLK_SEL, 0x01), + QMP_PHY_INIT_CFG(QSERDES_COM_SYSCLK_EN_SEL, 0x37), + QMP_PHY_INIT_CFG(QSERDES_COM_CLK_SELECT, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_SYS_CLK_CTRL, 0x06), + QMP_PHY_INIT_CFG(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x3f), + QMP_PHY_INIT_CFG(QSERDES_COM_CLK_ENABLE1, 0x0e), + QMP_PHY_INIT_CFG(QSERDES_COM_BG_CTRL, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_COM_SYSCLK_BUF_ENABLE, 0x06), + QMP_PHY_INIT_CFG(QSERDES_COM_CLK_SELECT, 0x30), + QMP_PHY_INIT_CFG(QSERDES_COM_PLL_IVCO, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_COM_PLL_CCTRL_MODE0, 0x28), + QMP_PHY_INIT_CFG(QSERDES_COM_PLL_RCTRL_MODE0, 0x16), + QMP_PHY_INIT_CFG(QSERDES_COM_CP_CTRL_MODE0, 0x0b), + QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_GAIN0_MODE0, 0x40), + QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_GAIN1_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_MAP, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_BG_TIMER, 0x08), + QMP_PHY_INIT_CFG(QSERDES_COM_CORECLK_DIV, 0x05), + QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_CTRL, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE1_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE2_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_CTRL, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_CORE_CLK_EN, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_COM_CMN_CONFIG, 0x02), +}; + +static const struct qmp_phy_init_tbl qmp_v2_dp_serdes_tbl_rbr[] = { + QMP_PHY_INIT_CFG(QSERDES_COM_HSCLK_SEL, 0x2c), + QMP_PHY_INIT_CFG(QSERDES_COM_DEC_START_MODE0, 0x69), + QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START1_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START2_MODE0, 0x80), + QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START3_MODE0, 0x07), + QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP1_MODE0, 0xbf), + QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP2_MODE0, 0x21), + QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP3_MODE0, 0x00), +}; + +static const struct qmp_phy_init_tbl qmp_v2_dp_serdes_tbl_hbr[] = { + QMP_PHY_INIT_CFG(QSERDES_COM_HSCLK_SEL, 0x24), + QMP_PHY_INIT_CFG(QSERDES_COM_DEC_START_MODE0, 0x69), + QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START1_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START2_MODE0, 0x80), + QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START3_MODE0, 0x07), + QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP1_MODE0, 0x3f), + QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP2_MODE0, 0x38), + QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP3_MODE0, 0x00), +}; + +static const struct qmp_phy_init_tbl qmp_v2_dp_serdes_tbl_hbr2[] = { + QMP_PHY_INIT_CFG(QSERDES_COM_HSCLK_SEL, 0x20), + QMP_PHY_INIT_CFG(QSERDES_COM_DEC_START_MODE0, 0x8c), + QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START1_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START2_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START3_MODE0, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP1_MODE0, 0x7f), + QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP2_MODE0, 0x70), + QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP3_MODE0, 0x00), +}; + +static const struct qmp_phy_init_tbl qmp_v2_dp_tx_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V2_TX_TRANSCEIVER_BIAS_EN, 0x1a), + QMP_PHY_INIT_CFG(QSERDES_V2_TX_VMODE_CTRL1, 0x40), + QMP_PHY_INIT_CFG(QSERDES_V2_TX_PRE_STALL_LDO_BOOST_EN, 0x30), + QMP_PHY_INIT_CFG(QSERDES_V2_TX_INTERFACE_SELECT, 0x3d), + QMP_PHY_INIT_CFG(QSERDES_V2_TX_CLKBUF_ENABLE, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_V2_TX_RESET_TSYNC_EN, 0x03), + QMP_PHY_INIT_CFG(QSERDES_V2_TX_TRAN_DRVR_EMP_EN, 0x03), + QMP_PHY_INIT_CFG(QSERDES_V2_TX_PARRATE_REC_DETECT_IDLE_EN, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_TX_TX_INTERFACE_MODE, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_TX_TX_EMP_POST1_LVL, 0x2b), + QMP_PHY_INIT_CFG(QSERDES_V2_TX_TX_DRV_LVL, 0x2f), + QMP_PHY_INIT_CFG(QSERDES_V2_TX_TX_BAND, 0x4), + QMP_PHY_INIT_CFG(QSERDES_V2_TX_RES_CODE_LANE_OFFSET_TX, 0x12), + QMP_PHY_INIT_CFG(QSERDES_V2_TX_RES_CODE_LANE_OFFSET_RX, 0x12), +}; + struct qmp_usbc_offsets { u16 serdes; u16 pcs; @@ -434,6 +512,10 @@ static const char * const usb3phy_reset_l[] = { "phy_phy", "phy", }; +static const char * const usb3dpphy_reset_l[] = { + "phy_phy", "dp_phy", +}; + static const struct regulator_bulk_data qmp_phy_msm8998_vreg_l[] = { { .supply = "vdda-phy", .init_load_uA = 68600 }, { .supply = "vdda-pll", .init_load_uA = 14200 }, @@ -459,6 +541,34 @@ static const struct qmp_usbc_offsets qmp_usbc_offsets_v3_qcm2290 = { .rx2 = 0x800, }; +static const struct qmp_usbc_offsets qmp_usbc_usb3dp_offsets_qcs615 = { + .serdes = 0x0, + .pcs = 0xc00, + .pcs_misc = 0xa00, + .tx = 0x200, + .rx = 0x400, + .tx2 = 0x600, + .rx2 = 0x800, + .dp_serdes = 0x1c00, + .dp_txa = 0x1400, + .dp_txb = 0x1800, + .dp_dp_phy = 0x1000, +}; + +static const u8 qmp_v2_dp_pre_emphasis_hbr2_rbr[4][4] = { + {0x00, 0x0b, 0x12, 0xff}, + {0x00, 0x0a, 0x12, 0xff}, + {0x00, 0x0c, 0xff, 0xff}, + {0xff, 0xff, 0xff, 0xff} +}; + +static const u8 qmp_v2_dp_voltage_swing_hbr2_rbr[4][4] = { + {0x07, 0x0f, 0x14, 0xff}, + {0x11, 0x1d, 0x1f, 0xff}, + {0x18, 0x1f, 0xff, 0xff}, + {0xff, 0xff, 0xff, 0xff} +}; + static const struct qmp_phy_cfg msm8998_usb3phy_cfg = { .offsets = &qmp_usbc_offsets_v3_qcm2290, @@ -531,6 +641,51 @@ static const struct qmp_phy_cfg qcs615_usb3phy_cfg = { .regs = qmp_v3_usb3phy_regs_layout_qcm2290, }; +static void qmp_v2_dp_aux_init(struct qmp_usbc *qmp); +static void qmp_v2_configure_dp_tx(struct qmp_usbc *qmp); +static int qmp_v2_configure_dp_phy(struct qmp_usbc *qmp); +static int qmp_v2_calibrate_dp_phy(struct qmp_usbc *qmp); + +static const struct qmp_phy_cfg qcs615_usb3dp_phy_cfg = { + .offsets = &qmp_usbc_usb3dp_offsets_qcs615, + + .serdes_tbl = qcm2290_usb3_serdes_tbl, + .serdes_tbl_num = ARRAY_SIZE(qcm2290_usb3_serdes_tbl), + .tx_tbl = qcm2290_usb3_tx_tbl, + .tx_tbl_num = ARRAY_SIZE(qcm2290_usb3_tx_tbl), + .rx_tbl = qcm2290_usb3_rx_tbl, + .rx_tbl_num = ARRAY_SIZE(qcm2290_usb3_rx_tbl), + .pcs_tbl = qcm2290_usb3_pcs_tbl, + .pcs_tbl_num = ARRAY_SIZE(qcm2290_usb3_pcs_tbl), + + .regs = qmp_v3_usb3phy_regs_layout_qcm2290, + + .dp_serdes_tbl = qmp_v2_dp_serdes_tbl, + .dp_serdes_tbl_num = ARRAY_SIZE(qmp_v2_dp_serdes_tbl), + .dp_tx_tbl = qmp_v2_dp_tx_tbl, + .dp_tx_tbl_num = ARRAY_SIZE(qmp_v2_dp_tx_tbl), + + .serdes_tbl_rbr = qmp_v2_dp_serdes_tbl_rbr, + .serdes_tbl_rbr_num = ARRAY_SIZE(qmp_v2_dp_serdes_tbl_rbr), + .serdes_tbl_hbr = qmp_v2_dp_serdes_tbl_hbr, + .serdes_tbl_hbr_num = ARRAY_SIZE(qmp_v2_dp_serdes_tbl_hbr), + .serdes_tbl_hbr2 = qmp_v2_dp_serdes_tbl_hbr2, + .serdes_tbl_hbr2_num = ARRAY_SIZE(qmp_v2_dp_serdes_tbl_hbr2), + + .swing_tbl = &qmp_v2_dp_voltage_swing_hbr2_rbr, + .pre_emphasis_tbl = &qmp_v2_dp_pre_emphasis_hbr2_rbr, + + .dp_aux_init = qmp_v2_dp_aux_init, + .configure_dp_tx = qmp_v2_configure_dp_tx, + .configure_dp_phy = qmp_v2_configure_dp_phy, + .calibrate_dp_phy = qmp_v2_calibrate_dp_phy, + + .reset_list = usb3dpphy_reset_l, + .num_resets = ARRAY_SIZE(usb3dpphy_reset_l), + .vreg_list = qmp_phy_qcs615_vreg_l, + .num_vregs = ARRAY_SIZE(qmp_phy_qcs615_vreg_l), +}; + static void qmp_usbc_set_phy_mode(struct qmp_usbc *qmp, bool is_dp) { if (qmp->tcsr_map && qmp->dp_phy_mode_reg) @@ -589,6 +744,253 @@ static int qmp_usbc_com_exit(struct phy *phy) return 0; } +static void qmp_v2_dp_aux_init(struct qmp_usbc *qmp) +{ + writel(DP_PHY_PD_CTL_AUX_PWRDN | + DP_PHY_PD_CTL_LANE_0_1_PWRDN | DP_PHY_PD_CTL_LANE_2_3_PWRDN | + DP_PHY_PD_CTL_PLL_PWRDN, + qmp->dp_dp_phy + QSERDES_DP_PHY_PD_CTL); + + writel(DP_PHY_PD_CTL_PWRDN | DP_PHY_PD_CTL_AUX_PWRDN | + DP_PHY_PD_CTL_LANE_0_1_PWRDN | DP_PHY_PD_CTL_LANE_2_3_PWRDN | + DP_PHY_PD_CTL_PLL_PWRDN, + qmp->dp_dp_phy + QSERDES_DP_PHY_PD_CTL); + + writel(0x00, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG0); + writel(0x13, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG1); + writel(0x00, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG2); + writel(0x00, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG3); + writel(0x0a, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG4); + writel(0x26, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG5); + writel(0x0a, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG6); + writel(0x03, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG7); + writel(0xbb, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG8); + writel(0x03, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG9); + qmp->dp_aux_cfg = 0; + + writel(PHY_AUX_STOP_ERR_MASK | PHY_AUX_DEC_ERR_MASK | + PHY_AUX_SYNC_ERR_MASK | PHY_AUX_ALIGN_ERR_MASK | + PHY_AUX_REQ_ERR_MASK, + qmp->dp_dp_phy + QSERDES_V2_DP_PHY_AUX_INTERRUPT_MASK); +} + +static int qmp_v2_configure_dp_swing(struct qmp_usbc *qmp) +{ + const struct qmp_phy_cfg *cfg = qmp->cfg; + const struct phy_configure_opts_dp *dp_opts = &qmp->dp_opts; + void __iomem *tx = qmp->dp_tx; + void __iomem *tx2 = qmp->dp_tx2; + unsigned int v_level = 0, p_level = 0; + u8 voltage_swing_cfg, pre_emphasis_cfg; + int i; + + if (dp_opts->lanes > 4) { + dev_err(qmp->dev, "Invalid lane_num(%d)\n", dp_opts->lanes); + return -EINVAL; + } + + for (i = 0; i < dp_opts->lanes; i++) { + v_level = max(v_level, dp_opts->voltage[i]); + p_level = max(p_level, dp_opts->pre[i]); + } + + if (v_level > 4 || p_level > 4) { + dev_err(qmp->dev, "Invalid v(%d) | p(%d) level)\n", + v_level, p_level); + return -EINVAL; + } + + voltage_swing_cfg = (*cfg->swing_tbl)[v_level][p_level]; + pre_emphasis_cfg = (*cfg->pre_emphasis_tbl)[v_level][p_level]; + + voltage_swing_cfg |= DP_PHY_TXn_TX_DRV_LVL_MUX_EN; + pre_emphasis_cfg |= DP_PHY_TXn_TX_EMP_POST1_LVL_MUX_EN; + + if (voltage_swing_cfg == 0xff && pre_emphasis_cfg == 0xff) + return -EINVAL; + + writel(voltage_swing_cfg, tx + QSERDES_V2_TX_TX_DRV_LVL); + writel(pre_emphasis_cfg, tx + QSERDES_V2_TX_TX_EMP_POST1_LVL); + writel(voltage_swing_cfg, tx2 + QSERDES_V2_TX_TX_DRV_LVL); + writel(pre_emphasis_cfg, tx2 + QSERDES_V2_TX_TX_EMP_POST1_LVL); + + return 0; +} + +static void qmp_usbc_configure_dp_mode(struct qmp_usbc *qmp) +{ + bool reverse = (qmp->orientation == TYPEC_ORIENTATION_REVERSE); + u32 val; + + val = DP_PHY_PD_CTL_PWRDN | DP_PHY_PD_CTL_AUX_PWRDN | + DP_PHY_PD_CTL_PLL_PWRDN | DP_PHY_PD_CTL_LANE_0_1_PWRDN | DP_PHY_PD_CTL_LANE_2_3_PWRDN; + + writel(val, qmp->dp_dp_phy + QSERDES_DP_PHY_PD_CTL); + + if (reverse) + writel(0xc9, qmp->dp_dp_phy + QSERDES_DP_PHY_MODE); + else + writel(0xd9, qmp->dp_dp_phy + QSERDES_DP_PHY_MODE); +} + +static int qmp_usbc_configure_dp_clocks(struct qmp_usbc *qmp) +{ + const struct phy_configure_opts_dp *dp_opts = &qmp->dp_opts; + u32 phy_vco_div; + unsigned long pixel_freq; + + switch (dp_opts->link_rate) { + case 1620: + phy_vco_div = 0x1; + pixel_freq = 1620000000UL / 2; + break; + case 2700: + phy_vco_div = 0x1; + pixel_freq = 2700000000UL / 2; + break; + case 5400: + phy_vco_div = 0x2; + pixel_freq = 5400000000UL / 4; + break; + default: + dev_err(qmp->dev, "link rate:%d not supported\n", dp_opts->link_rate); + return -EINVAL; + } + writel(phy_vco_div, qmp->dp_dp_phy + QSERDES_V2_DP_PHY_VCO_DIV); + + clk_set_rate(qmp->dp_link_hw.clk, dp_opts->link_rate * 100000); + clk_set_rate(qmp->dp_pixel_hw.clk, pixel_freq); + + return 0; +} + +static void qmp_v2_configure_dp_tx(struct qmp_usbc *qmp) +{ + const struct phy_configure_opts_dp *dp_opts = &qmp->dp_opts; + void __iomem *tx = qmp->dp_tx; + void __iomem *tx2 = qmp->dp_tx2; + + /* program default setting first */ + writel(0x2a, tx + QSERDES_V2_TX_TX_DRV_LVL); + writel(0x20, tx + QSERDES_V2_TX_TX_EMP_POST1_LVL); + writel(0x2a, tx2 + QSERDES_V2_TX_TX_DRV_LVL); + writel(0x20, tx2 + QSERDES_V2_TX_TX_EMP_POST1_LVL); + + if (dp_opts->link_rate >= 2700) { + writel(0xc4, tx + QSERDES_V2_TX_LANE_MODE_1); + writel(0xc4, tx2 + QSERDES_V2_TX_LANE_MODE_1); + } else { + writel(0xc6, tx + QSERDES_V2_TX_LANE_MODE_1); + writel(0xc6, tx2 + QSERDES_V2_TX_LANE_MODE_1); + } + + qmp_v2_configure_dp_swing(qmp); +} + +static int qmp_v2_configure_dp_phy(struct qmp_usbc *qmp) +{ + u32 status; + int ret; + + qmp_usbc_configure_dp_mode(qmp); + + writel(0x05, qmp->dp_dp_phy + QSERDES_V2_DP_PHY_TX0_TX1_LANE_CTL); + writel(0x05, qmp->dp_dp_phy + QSERDES_V2_DP_PHY_TX2_TX3_LANE_CTL); + + ret = qmp_usbc_configure_dp_clocks(qmp); + if (ret) + return ret; + + writel(0x01, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG); + writel(0x05, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG); + writel(0x01, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG); + writel(0x09, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG); + + writel(0x20, qmp->dp_serdes + QSERDES_COM_RESETSM_CNTRL); + + if (readl_poll_timeout(qmp->dp_serdes + QSERDES_COM_C_READY_STATUS, + status, + ((status & BIT(0)) > 0), + 500, + 10000)) { + dev_err(qmp->dev, "C_READY not ready\n"); + return -ETIMEDOUT; + } + + if (readl_poll_timeout(qmp->dp_serdes + QSERDES_COM_CMN_STATUS, + status, + ((status & BIT(0)) > 0), + 500, + 10000)){ + dev_err(qmp->dev, "FREQ_DONE not ready\n"); + return -ETIMEDOUT; + } + + if (readl_poll_timeout(qmp->dp_serdes + QSERDES_COM_CMN_STATUS, + status, + ((status & BIT(1)) > 0), + 500, + 10000)){ + dev_err(qmp->dev, "PLL_LOCKED not ready\n"); + return -ETIMEDOUT; + } + + writel(0x19, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG); + + if (readl_poll_timeout(qmp->dp_dp_phy + QSERDES_V2_DP_PHY_STATUS, + status, + ((status & BIT(0)) > 0), + 500, + 10000)){ + dev_err(qmp->dev, "TSYNC_DONE not ready\n"); + return -ETIMEDOUT; + } + + if (readl_poll_timeout(qmp->dp_dp_phy + QSERDES_V2_DP_PHY_STATUS, + status, + ((status & BIT(1)) > 0), + 500, + 10000)){ + dev_err(qmp->dev, "PHY_READY not ready\n"); + return -ETIMEDOUT; + } + + writel(0x3f, qmp->dp_tx + QSERDES_V2_TX_TRANSCEIVER_BIAS_EN); + writel(0x10, qmp->dp_tx + QSERDES_V2_TX_HIGHZ_DRVR_EN); + writel(0x0a, qmp->dp_tx + QSERDES_V2_TX_TX_POL_INV); + writel(0x3f, qmp->dp_tx2 + QSERDES_V2_TX_TRANSCEIVER_BIAS_EN); + writel(0x10, qmp->dp_tx2 + QSERDES_V2_TX_HIGHZ_DRVR_EN); + writel(0x0a, qmp->dp_tx2 + QSERDES_V2_TX_TX_POL_INV); + + writel(0x18, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG); + writel(0x19, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG); + + if (readl_poll_timeout(qmp->dp_dp_phy + QSERDES_V2_DP_PHY_STATUS, + status, + ((status & BIT(1)) > 0), + 500, + 10000)){ + dev_err(qmp->dev, "PHY_READY not ready\n"); + return -ETIMEDOUT; + } + + return 0; +} + +static int qmp_v2_calibrate_dp_phy(struct qmp_usbc *qmp) +{ + static const u8 cfg1_settings[] = {0x13, 0x23, 0x1d}; + u8 val; + + qmp->dp_aux_cfg++; + qmp->dp_aux_cfg %= ARRAY_SIZE(cfg1_settings); + val = cfg1_settings[qmp->dp_aux_cfg]; + + writel(val, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG1); + + return 0; +} + static int qmp_usbc_usb_power_on(struct phy *phy) { struct qmp_usbc *qmp = phy_get_drvdata(phy); @@ -855,6 +1257,14 @@ static int qmp_usbc_dp_power_on(struct phy *phy) void __iomem *tx = qmp->dp_tx; void __iomem *tx2 = qmp->dp_tx2; + /* + * FIXME: SW_PORTSELECT handling for DP orientation flip is not implemented. + * Expected: + * - For standard lane mapping: configure SW_PORTSELECT in QSERDES_DP_PHY_CFG_1. + * - For non-standard mapping: pass orientation to dp_ctrl and handle flip + * via logical2physical lane remapping. + */ + mutex_lock(&qmp->phy_mutex); qmp_usbc_dp_serdes_init(qmp); @@ -1601,6 +2011,9 @@ static const struct of_device_id qmp_usbc_of_match_table[] = { }, { .compatible = "qcom,qcm2290-qmp-usb3-phy", .data = &qcm2290_usb3phy_cfg, + }, { + .compatible = "qcom,qcs615-qmp-usb3-dp-phy", + .data = &qcs615_usb3dp_phy_cfg, }, { .compatible = "qcom,qcs615-qmp-usb3-phy", .data = &qcs615_usb3phy_cfg, From 01fac67d34e2e7420d684e080d0a4de944423aba Mon Sep 17 00:00:00 2001 From: Mani Chandana Ballary Kuntumalla Date: Tue, 23 Sep 2025 17:34:02 +0530 Subject: [PATCH 0281/2333] FROMLIST: drm/msm/dp: Update msm_dp_controller IDs for sa8775p The Qualcomm SA8775P platform comes with 2 DisplayPort controllers for each mdss. Update controller id for DPTX0 and DPTX1 of mdss1. Fixes: dcb380d19e58 ("drm/msm/dp: Add DisplayPort controller for SA8775P") Signed-off-by: Mani Chandana Ballary Kuntumalla Link: https://lore.kernel.org/all/20251125105622.1755651-2-quic_mkuntuma@quicinc.com/ --- drivers/gpu/drm/msm/dp/dp_display.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c index d87d47cc7ec3e..f247aad553975 100644 --- a/drivers/gpu/drm/msm/dp/dp_display.c +++ b/drivers/gpu/drm/msm/dp/dp_display.c @@ -133,8 +133,8 @@ struct msm_dp_desc { static const struct msm_dp_desc msm_dp_desc_sa8775p[] = { { .io_start = 0x0af54000, .id = MSM_DP_CONTROLLER_0, .wide_bus_supported = true }, { .io_start = 0x0af5c000, .id = MSM_DP_CONTROLLER_1, .wide_bus_supported = true }, - { .io_start = 0x22154000, .id = MSM_DP_CONTROLLER_2, .wide_bus_supported = true }, - { .io_start = 0x2215c000, .id = MSM_DP_CONTROLLER_3, .wide_bus_supported = true }, + { .io_start = 0x22154000, .id = MSM_DP_CONTROLLER_0, .wide_bus_supported = true }, + { .io_start = 0x2215c000, .id = MSM_DP_CONTROLLER_1, .wide_bus_supported = true }, {} }; From 3409cd81432de9037354777a2390f6f91aaf4206 Mon Sep 17 00:00:00 2001 From: Yuanjie Yang Date: Thu, 23 Oct 2025 16:06:04 +0800 Subject: [PATCH 0282/2333] FROMLIST: drm/panel: Set sufficient voltage for panel nt37801 The NT37801 Sepc V1.0 chapter "5.7.1 Power On Sequence" states VDDI=1.65V~1.95V, so set sufficient voltage for panel nt37801. Signed-off-by: Yongxing Mou Signed-off-by: Yuanjie Yang Link: https://lore.kernel.org/all/20251023080609.1212-2-yuanjie.yang@oss.qualcomm.com/#r Signed-off-by: Yash Gupta --- drivers/gpu/drm/panel/panel-novatek-nt37801.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/gpu/drm/panel/panel-novatek-nt37801.c b/drivers/gpu/drm/panel/panel-novatek-nt37801.c index d6a37d7e0cc63..7eda16e0c1f94 100644 --- a/drivers/gpu/drm/panel/panel-novatek-nt37801.c +++ b/drivers/gpu/drm/panel/panel-novatek-nt37801.c @@ -267,6 +267,11 @@ static int novatek_nt37801_probe(struct mipi_dsi_device *dsi) if (ret < 0) return ret; + ret = regulator_set_voltage(ctx->supplies[0].consumer, + 1650000, 1950000); + if (ret < 0) + return ret; + ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(ctx->reset_gpio)) return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), From ac23e7e5a8e6f12d4fe3d759ed38a5e0bfcff4bc Mon Sep 17 00:00:00 2001 From: Vishnu Saini Date: Tue, 18 Nov 2025 10:07:09 +0530 Subject: [PATCH 0283/2333] FROMLIST: drm/bridge: add support for lontium lt8713sx bridge driver The lt8713sx is a Type-C/DP1.4 to Type-C/DP1.4/HDMI2.0 converter, with three configurable DP1.4/HDMI2.0/DP++ output interfaces and audio output interface. Driver is required for firmware upgrade in the bridge chip. Co-developed-by: Prahlad Valluru Signed-off-by: Prahlad Valluru Signed-off-by: Vishnu Saini Link: https://lore.kernel.org/all/20251118-lt8713sx-bridge-driver-v2-2-25ad49280a11@oss.qualcomm.com/ --- drivers/gpu/drm/bridge/Kconfig | 10 + drivers/gpu/drm/bridge/Makefile | 1 + drivers/gpu/drm/bridge/lontium-lt8713sx.c | 713 ++++++++++++++++++++++ 3 files changed, 724 insertions(+) create mode 100644 drivers/gpu/drm/bridge/lontium-lt8713sx.c diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig index a250afd8d6622..7fef383ed7cb7 100644 --- a/drivers/gpu/drm/bridge/Kconfig +++ b/drivers/gpu/drm/bridge/Kconfig @@ -184,6 +184,16 @@ config DRM_LONTIUM_LT9611UXC HDMI signals Please say Y if you have such hardware. +config DRM_LONTIUM_LT8713SX + tristate "Lontium LT8713SX DP MST bridge" + depends on OF + select REGMAP_I2C + help + Driver for Lontium LT8713SX DP MST bridge + chip firmware upgrade, which converts Type-C/DP1.4 + to 3 configurable Type-C/DP1.4/HDMI2.0 outputs + Please say Y if you have such hardware. + config DRM_ITE_IT66121 tristate "ITE IT66121 HDMI bridge" depends on OF diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile index c7dc03182e592..07eeb13fa4978 100644 --- a/drivers/gpu/drm/bridge/Makefile +++ b/drivers/gpu/drm/bridge/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_DRM_LONTIUM_LT8912B) += lontium-lt8912b.o obj-$(CONFIG_DRM_LONTIUM_LT9211) += lontium-lt9211.o obj-$(CONFIG_DRM_LONTIUM_LT9611) += lontium-lt9611.o obj-$(CONFIG_DRM_LONTIUM_LT9611UXC) += lontium-lt9611uxc.o +obj-$(CONFIG_DRM_LONTIUM_LT8713SX) += lontium-lt8713sx.o obj-$(CONFIG_DRM_LVDS_CODEC) += lvds-codec.o obj-$(CONFIG_DRM_MEGACHIPS_STDPXXXX_GE_B850V3_FW) += megachips-stdpxxxx-ge-b850v3-fw.o obj-$(CONFIG_DRM_MICROCHIP_LVDS_SERIALIZER) += microchip-lvds.o diff --git a/drivers/gpu/drm/bridge/lontium-lt8713sx.c b/drivers/gpu/drm/bridge/lontium-lt8713sx.c new file mode 100644 index 0000000000000..a5aed2474a2e9 --- /dev/null +++ b/drivers/gpu/drm/bridge/lontium-lt8713sx.c @@ -0,0 +1,713 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define FW_FILE "lt8713sx_fw.bin" + +#define LT8713SX_PAGE_SIZE 256 +#define FW_12K_SIZE (12 * 1024) +#define FW_64K_SIZE (64 * 1024) +#define FW_256K_SIZE (256 * 1024) + +struct crc_config { + u8 width; + u32 poly; + u32 crc_init; + u32 xor_out; + bool ref_in; + bool ref_out; +}; + +struct lt8713sx { + struct device *dev; + + struct regmap *regmap; + /* Protects all accesses to registers by stopping the on-chip MCU */ + struct mutex ocm_lock; + + struct gpio_desc *reset_gpio; + struct gpio_desc *enable_gpio; + + struct regulator_bulk_data supplies[2]; + + struct i2c_client *client; + const struct firmware *fw; + + u8 *fw_buffer; + + u32 main_crc_value; + u32 bank_crc_value[17]; + + int bank_num; +}; + +static void lt8713sx_reset(struct lt8713sx *lt8713sx); + +static const struct regmap_range lt8713sx_ranges[] = { + { + .range_min = 0, + .range_max = 0xffff + }, +}; + +static const struct regmap_access_table lt8713sx_table = { + .yes_ranges = lt8713sx_ranges, + .n_yes_ranges = ARRAY_SIZE(lt8713sx_ranges), +}; + +static const struct regmap_config lt8713sx_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .volatile_table = <8713sx_table, + .cache_type = REGCACHE_NONE, +}; + +static void lt8713sx_i2c_enable(struct lt8713sx *lt8713sx) +{ + regmap_write(lt8713sx->regmap, 0xff, 0xe0); + regmap_write(lt8713sx->regmap, 0xee, 0x01); +} + +static void lt8713sx_i2c_disable(struct lt8713sx *lt8713sx) +{ + regmap_write(lt8713sx->regmap, 0xff, 0xe0); + regmap_write(lt8713sx->regmap, 0xee, 0x00); +} + +static unsigned int bits_reverse(u32 in_val, u8 bits) +{ + u32 out_val = 0; + u8 i; + + for (i = 0; i < bits; i++) { + if (in_val & (1 << i)) + out_val |= 1 << (bits - 1 - i); + } + + return out_val; +} + +static unsigned int get_crc(struct crc_config crc_cfg, const u8 *buf, u64 buf_len) +{ + u8 width = crc_cfg.width; + u32 poly = crc_cfg.poly; + u32 crc = crc_cfg.crc_init; + u32 xorout = crc_cfg.xor_out; + bool refin = crc_cfg.ref_in; + bool refout = crc_cfg.ref_out; + u8 n; + u32 bits; + u32 data; + u8 i; + + n = (width < 8) ? 0 : (width - 8); + crc = (width < 8) ? (crc << (8 - width)) : crc; + bits = (width < 8) ? 0x80 : (1 << (width - 1)); + poly = (width < 8) ? (poly << (8 - width)) : poly; + + while (buf_len--) { + data = *(buf++); + if (refin) + data = bits_reverse(data, 8); + crc ^= (data << n); + for (i = 0; i < 8; i++) { + if (crc & bits) + crc = (crc << 1) ^ poly; + else + crc = crc << 1; + } + } + crc = (width < 8) ? (crc >> (8 - width)) : crc; + if (refout) + crc = bits_reverse(crc, width); + crc ^= xorout; + + return (crc & ((2 << (width - 1)) - 1)); +} + +static u32 calculate_64K_crc(const u8 *upgrade_data, u64 len) +{ + struct crc_config crc_cfg = { + .width = 8, + .poly = 0x31, + .crc_init = 0, + .xor_out = 0, + .ref_out = false, + .ref_in = false, + }; + u64 crc_size = FW_64K_SIZE - 1; + u8 default_val = 0xFF; + + crc_cfg.crc_init = get_crc(crc_cfg, upgrade_data, len); + + crc_size -= len; + while (crc_size--) + crc_cfg.crc_init = get_crc(crc_cfg, &default_val, 1); + + return crc_cfg.crc_init; +} + +static u32 calculate_12K_crc(const u8 *upgrade_data, u64 len) +{ + struct crc_config crc_cfg = { + .width = 8, + .poly = 0x31, + .crc_init = 0, + .xor_out = 0, + .ref_out = false, + .ref_in = false, + }; + u64 crc_size = FW_12K_SIZE; + u8 default_val = 0xFF; + + crc_cfg.crc_init = get_crc(crc_cfg, upgrade_data, len); + + crc_size -= len; + while (crc_size--) + crc_cfg.crc_init = get_crc(crc_cfg, &default_val, 1); + + return crc_cfg.crc_init; +} + +static int lt8713sx_prepare_firmware_data(struct lt8713sx *lt8713sx) +{ + int ret = 0; + + ret = request_firmware(<8713sx->fw, FW_FILE, lt8713sx->dev); + if (ret < 0) { + pr_err("request firmware failed\n"); + return ret; + } + + pr_debug("Firmware size: %zu bytes\n", lt8713sx->fw->size); + + if (lt8713sx->fw->size > FW_256K_SIZE - 1) { + pr_err("Firmware size exceeds 256KB limit\n"); + release_firmware(lt8713sx->fw); + return -EINVAL; + } + + lt8713sx->fw_buffer = kzalloc(FW_256K_SIZE, GFP_KERNEL); + if (!lt8713sx->fw_buffer) { + release_firmware(lt8713sx->fw); + return -ENOMEM; + } + + memset(lt8713sx->fw_buffer, 0xFF, FW_256K_SIZE); + + if (lt8713sx->fw->size < FW_64K_SIZE) { + /*TODO: CRC should be calculated with 0xff also */ + memcpy(lt8713sx->fw_buffer, lt8713sx->fw->data, lt8713sx->fw->size); + lt8713sx->fw_buffer[FW_64K_SIZE - 1] = + calculate_64K_crc(lt8713sx->fw->data, lt8713sx->fw->size); + lt8713sx->main_crc_value = lt8713sx->fw_buffer[FW_64K_SIZE - 1]; + pr_debug("Main Firmware Data Crc=0x%02X\n", lt8713sx->main_crc_value); + + } else { + //main firmware + memcpy(lt8713sx->fw_buffer, lt8713sx->fw->data, FW_64K_SIZE - 1); + lt8713sx->fw_buffer[FW_64K_SIZE - 1] = + calculate_64K_crc(lt8713sx->fw_buffer, FW_64K_SIZE - 1); + lt8713sx->main_crc_value = lt8713sx->fw_buffer[FW_64K_SIZE - 1]; + pr_debug("Main Firmware Data Crc=0x%02X\n", lt8713sx->main_crc_value); + + //bank firmware + memcpy(lt8713sx->fw_buffer + FW_64K_SIZE, + lt8713sx->fw->data + FW_64K_SIZE, + lt8713sx->fw->size - FW_64K_SIZE); + + lt8713sx->bank_num = (lt8713sx->fw->size - FW_64K_SIZE + FW_12K_SIZE - 1) / + FW_12K_SIZE; + pr_debug("Bank Number Total is %d.\n", lt8713sx->bank_num); + + for (int i = 0; i < lt8713sx->bank_num; i++) { + lt8713sx->bank_crc_value[i] = + calculate_12K_crc(lt8713sx->fw_buffer + FW_64K_SIZE + + i * FW_12K_SIZE, + FW_12K_SIZE); + pr_debug("Bank number:%d; Firmware Data Crc:0x%02X\n", + i, lt8713sx->bank_crc_value[i]); + } + } + return 0; +} + +static void lt8713sx_config_parameters(struct lt8713sx *lt8713sx) +{ + regmap_write(lt8713sx->regmap, 0xFF, 0xE0); + regmap_write(lt8713sx->regmap, 0xEE, 0x01); + regmap_write(lt8713sx->regmap, 0x5E, 0xC1); + regmap_write(lt8713sx->regmap, 0x58, 0x00); + regmap_write(lt8713sx->regmap, 0x59, 0x50); + regmap_write(lt8713sx->regmap, 0x5A, 0x10); + regmap_write(lt8713sx->regmap, 0x5A, 0x00); + regmap_write(lt8713sx->regmap, 0x58, 0x21); +} + +static void lt8713sx_wren(struct lt8713sx *lt8713sx) +{ + regmap_write(lt8713sx->regmap, 0xff, 0xe1); + regmap_write(lt8713sx->regmap, 0x03, 0xbf); + regmap_write(lt8713sx->regmap, 0x03, 0xff); + regmap_write(lt8713sx->regmap, 0xff, 0xe0); + regmap_write(lt8713sx->regmap, 0x5a, 0x04); + regmap_write(lt8713sx->regmap, 0x5a, 0x00); +} + +static void lt8713sx_wrdi(struct lt8713sx *lt8713sx) +{ + regmap_write(lt8713sx->regmap, 0x5A, 0x08); + regmap_write(lt8713sx->regmap, 0x5A, 0x00); +} + +static void lt8713sx_fifo_reset(struct lt8713sx *lt8713sx) +{ + regmap_write(lt8713sx->regmap, 0xff, 0xe1); + regmap_write(lt8713sx->regmap, 0x03, 0xbf); + regmap_write(lt8713sx->regmap, 0x03, 0xff); +} + +static void lt8713sx_disable_sram_write(struct lt8713sx *lt8713sx) +{ + regmap_write(lt8713sx->regmap, 0xff, 0xe0); + regmap_write(lt8713sx->regmap, 0x55, 0x00); +} + +static void lt8713sx_sram_to_flash(struct lt8713sx *lt8713sx) +{ + regmap_write(lt8713sx->regmap, 0x5a, 0x30); + regmap_write(lt8713sx->regmap, 0x5a, 0x00); +} + +static void lt8713sx_i2c_to_sram(struct lt8713sx *lt8713sx) +{ + regmap_write(lt8713sx->regmap, 0x55, 0x80); + regmap_write(lt8713sx->regmap, 0x5e, 0xc0); + regmap_write(lt8713sx->regmap, 0x58, 0x21); +} + +static u8 lt8713sx_read_flash_status(struct lt8713sx *lt8713sx) +{ + u32 flash_status = 0; + + regmap_write(lt8713sx->regmap, 0xFF, 0xE1);//fifo_rst_n + regmap_write(lt8713sx->regmap, 0x03, 0x3F); + regmap_write(lt8713sx->regmap, 0x03, 0xFF); + + regmap_write(lt8713sx->regmap, 0xFF, 0xE0); + regmap_write(lt8713sx->regmap, 0x5e, 0x40); + regmap_write(lt8713sx->regmap, 0x56, 0x05);//opcode=read status register + regmap_write(lt8713sx->regmap, 0x55, 0x25); + regmap_write(lt8713sx->regmap, 0x55, 0x01); + regmap_write(lt8713sx->regmap, 0x58, 0x21); + + regmap_read(lt8713sx->regmap, 0x5f, &flash_status); + pr_debug("flash_status:%x\n", flash_status); + + return flash_status; +} + +static void lt8713sx_block_erase(struct lt8713sx *lt8713sx) +{ + u32 i = 0; + u8 flash_status = 0; + u8 blocknum = 0x00; + u32 flashaddr = 0x00; + + for (blocknum = 0; blocknum < 8; blocknum++) { + flashaddr = blocknum * 0x008000; + regmap_write(lt8713sx->regmap, 0xFF, 0xE0); + regmap_write(lt8713sx->regmap, 0xEE, 0x01); + regmap_write(lt8713sx->regmap, 0x5A, 0x04); + regmap_write(lt8713sx->regmap, 0x5A, 0x00); + regmap_write(lt8713sx->regmap, 0x5B, flashaddr >> 16);//set flash address[23:16] + regmap_write(lt8713sx->regmap, 0x5C, flashaddr >> 8);//set flash address[15:8] + regmap_write(lt8713sx->regmap, 0x5D, flashaddr);//set flash address[7:0] + regmap_write(lt8713sx->regmap, 0x5A, 0x01); + regmap_write(lt8713sx->regmap, 0x5A, 0x00); + msleep(100); //delay 100ms + i = 0; + while (1) { + flash_status = lt8713sx_read_flash_status(lt8713sx); //wait erase finish + if ((flash_status & 0x01) == 0) + break; + + if (i > 50) + break; + + i++; + msleep(50); //delay 50ms + } + } + pr_debug("erase flash done.\n"); +} + +static void lt8713sx_load_main_fw_to_sram(struct lt8713sx *lt8713sx) +{ + regmap_write(lt8713sx->regmap, 0xff, 0xe0); + regmap_write(lt8713sx->regmap, 0xee, 0x01); + regmap_write(lt8713sx->regmap, 0x68, 0x00); + regmap_write(lt8713sx->regmap, 0x69, 0x00); + regmap_write(lt8713sx->regmap, 0x6a, 0x00); + regmap_write(lt8713sx->regmap, 0x65, 0x00); + regmap_write(lt8713sx->regmap, 0x66, 0xff); + regmap_write(lt8713sx->regmap, 0x67, 0xff); + regmap_write(lt8713sx->regmap, 0x6b, 0x00); + regmap_write(lt8713sx->regmap, 0x6c, 0x00); + regmap_write(lt8713sx->regmap, 0x60, 0x01); + msleep(200); + regmap_write(lt8713sx->regmap, 0x60, 0x00); +} + +static void lt8713sx_load_bank_fw_to_sram(struct lt8713sx *lt8713sx, u64 addr) +{ + regmap_write(lt8713sx->regmap, 0xff, 0xe0); + regmap_write(lt8713sx->regmap, 0xee, 0x01); + regmap_write(lt8713sx->regmap, 0x68, ((addr & 0xFF0000) >> 16)); + regmap_write(lt8713sx->regmap, 0x69, ((addr & 0x00FF00) >> 8)); + regmap_write(lt8713sx->regmap, 0x6a, (addr & 0x0000FF)); + regmap_write(lt8713sx->regmap, 0x65, 0x00); + regmap_write(lt8713sx->regmap, 0x66, 0x30); + regmap_write(lt8713sx->regmap, 0x67, 0x00); + regmap_write(lt8713sx->regmap, 0x6b, 0x00); + regmap_write(lt8713sx->regmap, 0x6c, 0x00); + regmap_write(lt8713sx->regmap, 0x60, 0x01); + msleep(50); + regmap_write(lt8713sx->regmap, 0x60, 0x00); +} + +static int lt8713sx_write_data(struct lt8713sx *lt8713sx, const u8 *data, u64 filesize) +{ + int page = 0, num = 0, i = 0, val; + + page = (filesize % LT8713SX_PAGE_SIZE) ? + ((filesize / LT8713SX_PAGE_SIZE) + 1) : (filesize / LT8713SX_PAGE_SIZE); + + pr_debug("Writing to Sram=%u pages, total size = %llu bytes\n", page, filesize); + + for (num = 0; num < page; num++) { + pr_debug("page[%d]\n", num); + lt8713sx_i2c_to_sram(lt8713sx); + + for (i = 0; i < LT8713SX_PAGE_SIZE; i++) { + if ((num * LT8713SX_PAGE_SIZE + i) < filesize) + val = *(data + (num * LT8713SX_PAGE_SIZE + i)); + else + val = 0xFF; + regmap_write(lt8713sx->regmap, 0x59, val); + } + + lt8713sx_wren(lt8713sx); + lt8713sx_sram_to_flash(lt8713sx); + } + + lt8713sx_wrdi(lt8713sx); + lt8713sx_disable_sram_write(lt8713sx); + + return 0; +} + +static void lt8713sx_main_upgrade_result(struct lt8713sx *lt8713sx) +{ + u32 main_crc_result; + + regmap_write(lt8713sx->regmap, 0xff, 0xe0); + regmap_read(lt8713sx->regmap, 0x23, &main_crc_result); + + pr_debug("Main CRC HW: 0x%02X\n", main_crc_result); + pr_debug("Main CRC FW: 0x%02X\n", lt8713sx->main_crc_value); + + if (main_crc_result == lt8713sx->main_crc_value) + pr_debug("Main Firmware Upgrade Success.\n"); + else + pr_err("Main Firmware Upgrade Failed.\n"); +} + +static void lt8713sx_bank_upgrade_result(struct lt8713sx *lt8713sx, u8 banknum) +{ + u32 bank_crc_result; + + regmap_write(lt8713sx->regmap, 0xff, 0xe0); + + regmap_read(lt8713sx->regmap, 0x23, &bank_crc_result); + + pr_debug("Bank %d CRC Result: 0x%02X\n", banknum, bank_crc_result); + + if (bank_crc_result == lt8713sx->bank_crc_value[banknum]) + pr_debug("Bank %d Firmware Upgrade Success.\n", banknum); + else + pr_err("Bank %d Firmware Upgrade Failed.\n", banknum); +} + +static void lt8713sx_bank_result_check(struct lt8713sx *lt8713sx) +{ + int i; + u64 addr = 0x010000; + + for (i = 0; i < lt8713sx->bank_num; i++) { + lt8713sx_load_bank_fw_to_sram(lt8713sx, addr); + lt8713sx_bank_upgrade_result(lt8713sx, i); + addr += 0x3000; + } +} + +static int lt8713sx_firmware_upgrade(struct lt8713sx *lt8713sx) +{ + int ret; + + lt8713sx_config_parameters(lt8713sx); + + lt8713sx_block_erase(lt8713sx); + + if (lt8713sx->fw->size < FW_64K_SIZE) { + ret = lt8713sx_write_data(lt8713sx, lt8713sx->fw_buffer, FW_64K_SIZE); + if (ret < 0) { + pr_err("Failed to write firmware data: %d\n", ret); + return ret; + } + } else { + ret = lt8713sx_write_data(lt8713sx, lt8713sx->fw_buffer, lt8713sx->fw->size); + if (ret < 0) { + pr_err("Failed to write firmware data: %d\n", ret); + return ret; + } + } + + pr_debug("Write Data done.\n"); + + return 0; +} + +static int lt8713sx_firmware_update(struct lt8713sx *lt8713sx) +{ + int ret = 0; + + mutex_lock(<8713sx->ocm_lock); + lt8713sx_i2c_enable(lt8713sx); + + ret = lt8713sx_prepare_firmware_data(lt8713sx); + if (ret < 0) { + pr_err("Failed to prepare firmware data: %d\n", ret); + goto error; + } + + ret = lt8713sx_firmware_upgrade(lt8713sx); + if (ret < 0) { + pr_err("Upgrade failure.\n"); + goto error; + } else { + /* Validate CRC */ + lt8713sx_load_main_fw_to_sram(lt8713sx); + lt8713sx_main_upgrade_result(lt8713sx); + lt8713sx_wrdi(lt8713sx); + lt8713sx_fifo_reset(lt8713sx); + lt8713sx_bank_result_check(lt8713sx); + lt8713sx_wrdi(lt8713sx); + } + +error: + lt8713sx_i2c_disable(lt8713sx); + if (!ret) + lt8713sx_reset(lt8713sx); + + kfree(lt8713sx->fw_buffer); + lt8713sx->fw_buffer = NULL; + + if (lt8713sx->fw) { + release_firmware(lt8713sx->fw); + lt8713sx->fw = NULL; + } + mutex_unlock(<8713sx->ocm_lock); + + return ret; +} + +static void lt8713sx_reset(struct lt8713sx *lt8713sx) +{ + pr_debug("reset bridge.\n"); + gpiod_set_value_cansleep(lt8713sx->reset_gpio, 1); + msleep(20); + + gpiod_set_value_cansleep(lt8713sx->reset_gpio, 0); + msleep(20); + + gpiod_set_value_cansleep(lt8713sx->reset_gpio, 1); + msleep(20); + pr_debug("reset done.\n"); +} + +static int lt8713sx_regulator_init(struct lt8713sx *lt8713sx) +{ + int ret; + + lt8713sx->supplies[0].supply = "vdd"; + lt8713sx->supplies[1].supply = "vcc"; + + ret = devm_regulator_bulk_get(lt8713sx->dev, 2, lt8713sx->supplies); + if (ret < 0) + return dev_err_probe(lt8713sx->dev, ret, "failed to get regulators\n"); + + ret = regulator_set_load(lt8713sx->supplies[0].consumer, 200000); + if (ret < 0) + return dev_err_probe(lt8713sx->dev, ret, "failed to set regulator load\n"); + + return 0; +} + +static int lt8713sx_regulator_enable(struct lt8713sx *lt8713sx) +{ + int ret; + + ret = regulator_enable(lt8713sx->supplies[0].consumer); + if (ret < 0) + return dev_err_probe(lt8713sx->dev, ret, "failed to enable vdd regulator\n"); + + usleep_range(1000, 10000); + + ret = regulator_enable(lt8713sx->supplies[1].consumer); + if (ret < 0) { + regulator_disable(lt8713sx->supplies[0].consumer); + return dev_err_probe(lt8713sx->dev, ret, "failed to enable vcc regulator\n"); + } + return 0; +} + +static int lt8713sx_gpio_init(struct lt8713sx *lt8713sx) +{ + struct device *dev = lt8713sx->dev; + + lt8713sx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(lt8713sx->reset_gpio)) + return dev_err_probe(dev, PTR_ERR(lt8713sx->reset_gpio), + "failed to acquire reset gpio\n"); + + /* power enable gpio */ + lt8713sx->enable_gpio = devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_HIGH); + if (IS_ERR(lt8713sx->enable_gpio)) + return dev_err_probe(dev, PTR_ERR(lt8713sx->enable_gpio), + "failed to acquire enable gpio\n"); + return 0; +} + +static ssize_t lt8713sx_firmware_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct lt8713sx *lt8713sx = dev_get_drvdata(dev); + int ret; + + ret = lt8713sx_firmware_update(lt8713sx); + if (ret < 0) + return ret; + return len; +} + +static DEVICE_ATTR_WO(lt8713sx_firmware); + +static struct attribute *lt8713sx_attrs[] = { + &dev_attr_lt8713sx_firmware.attr, + NULL, +}; + +static const struct attribute_group lt8713sx_attr_group = { + .attrs = lt8713sx_attrs, +}; + +static const struct attribute_group *lt8713sx_attr_groups[] = { + <8713sx_attr_group, + NULL, +}; + +static int lt8713sx_probe(struct i2c_client *client) +{ + struct lt8713sx *lt8713sx; + struct device *dev = &client->dev; + int ret; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) + return dev_err_probe(dev, -ENODEV, "device doesn't support I2C\n"); + + lt8713sx = devm_kzalloc(dev, sizeof(*lt8713sx), GFP_KERNEL); + if (!lt8713sx) + return dev_err_probe(dev, -ENOMEM, "failed to allocate lt8713sx struct\n"); + + lt8713sx->dev = dev; + lt8713sx->client = client; + i2c_set_clientdata(client, lt8713sx); + + mutex_init(<8713sx->ocm_lock); + + lt8713sx->regmap = devm_regmap_init_i2c(client, <8713sx_regmap_config); + if (IS_ERR(lt8713sx->regmap)) + return dev_err_probe(dev, PTR_ERR(lt8713sx->regmap), "regmap i2c init failed\n"); + + ret = lt8713sx_gpio_init(lt8713sx); + if (ret < 0) + goto err_of_put; + + ret = lt8713sx_regulator_init(lt8713sx); + if (ret < 0) + goto err_of_put; + + ret = lt8713sx_regulator_enable(lt8713sx); + if (ret) + goto err_of_put; + + lt8713sx_reset(lt8713sx); + + return 0; + +err_of_put: + return ret; +} + +static void lt8713sx_remove(struct i2c_client *client) +{ + struct lt8713sx *lt8713sx = i2c_get_clientdata(client); + + mutex_destroy(<8713sx->ocm_lock); + + regulator_bulk_disable(ARRAY_SIZE(lt8713sx->supplies), lt8713sx->supplies); +} + +static struct i2c_device_id lt8713sx_id[] = { + { "lontium,lt8713sx", 0 }, + { /* sentinel */ } +}; + +static const struct of_device_id lt8713sx_match_table[] = { + { .compatible = "lontium,lt8713sx" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, lt8713sx_match_table); + +static struct i2c_driver lt8713sx_driver = { + .driver = { + .name = "lt8713sx", + .of_match_table = lt8713sx_match_table, + .dev_groups = lt8713sx_attr_groups, + }, + .probe = lt8713sx_probe, + .remove = lt8713sx_remove, + .id_table = lt8713sx_id, +}; + +module_i2c_driver(lt8713sx_driver); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("lt8713sx drm bridge driver"); +MODULE_AUTHOR("Tony "); +MODULE_FIRMWARE(FW_FILE); From f562df8e56dedc2e91f268ae1daebc4359bd4e25 Mon Sep 17 00:00:00 2001 From: Vishnu Saini Date: Tue, 18 Nov 2025 10:07:08 +0530 Subject: [PATCH 0284/2333] FROMLIST: dt-bindings: bridge: lt8713sx: Add bindings Add bindings for lt8713sx bridge. Co-developed-by: Prahlad Valluru Signed-off-by: Prahlad Valluru Signed-off-by: Vishnu Saini Link: https://lore.kernel.org/all/20251118-lt8713sx-bridge-driver-v2-1-25ad49280a11@oss.qualcomm.com/ --- .../display/bridge/lontium,lt8713sx.yaml | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/bridge/lontium,lt8713sx.yaml diff --git a/Documentation/devicetree/bindings/display/bridge/lontium,lt8713sx.yaml b/Documentation/devicetree/bindings/display/bridge/lontium,lt8713sx.yaml new file mode 100644 index 0000000000000..3fb7e042c6887 --- /dev/null +++ b/Documentation/devicetree/bindings/display/bridge/lontium,lt8713sx.yaml @@ -0,0 +1,52 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/bridge/lontium,lt8713sx.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Lontium LT8713SX Type-C/DP1.4 to Type-C/DP1.4/HDMI2.0/DP++ bridge-hub + +maintainers: + - Tony + +description: + The Lontium LT8713SX is a Type-C/DP1.4 to Type-C/DP1.4/HDMI2.0 converter + that integrates one DP input and up to three configurable output interfaces + (DP1.4 / HDMI2.0 / DP++), with SST/MST functionality and audio support. + +properties: + compatible: + enum: + - lontium,lt8713sx + + reg: + maxItems: 1 + + vcc-supply: + description: Regulator for 3.3V vcc. + + vdd-supply: + description: Regulator for 1.1V vdd. + + reset-gpios: + description: GPIO connected to active high RESET pin. + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + bridge@4f { + compatible = "lontium,lt8713sx"; + reg = <0x4f>; + reset-gpios = <&tlmm 6 GPIO_ACTIVE_HIGH>; + }; + }; From c803ec8ef6633ce362182cd7cf22677e22ec14bf Mon Sep 17 00:00:00 2001 From: Gopi Botlagunta Date: Fri, 21 Nov 2025 19:12:06 +0530 Subject: [PATCH 0285/2333] FROMLIST: drm/bridge: lt9611uxc: Increase EDID wait time from 500ms to 1000ms EDID interrupt was coming 600-650 ms after HPD interrupt, resulting into EDID read timeout and default resolution of 1024x768 on display. Signed-off-by: Gopi Botlagunta Link: https://lore.kernel.org/all/20251121-hdmibridge-v1-1-14c63890f362@oss.qualcomm.com/ --- drivers/gpu/drm/bridge/lontium-lt9611uxc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/bridge/lontium-lt9611uxc.c b/drivers/gpu/drm/bridge/lontium-lt9611uxc.c index 38fb8776c0f44..6f2b72fba598e 100644 --- a/drivers/gpu/drm/bridge/lontium-lt9611uxc.c +++ b/drivers/gpu/drm/bridge/lontium-lt9611uxc.c @@ -382,7 +382,7 @@ lt9611uxc_bridge_detect(struct drm_bridge *bridge, struct drm_connector *connect static int lt9611uxc_wait_for_edid(struct lt9611uxc *lt9611uxc) { return wait_event_interruptible_timeout(lt9611uxc->wq, lt9611uxc->edid_read, - msecs_to_jiffies(500)); + msecs_to_jiffies(1000)); } static int lt9611uxc_get_edid_block(void *data, u8 *buf, unsigned int block, size_t len) From accd38cae62eb92e26d6a9e1ccc54f8f6a85c468 Mon Sep 17 00:00:00 2001 From: Ayushi Makhija Date: Tue, 25 Nov 2025 07:03:00 +0530 Subject: [PATCH 0286/2333] FROMLIST: dt-bindings: display: msm: document DSI controller and phy on QCS8300 Document DSI controller and phy on QCS8300 platform. Signed-off-by: Ayushi Makhija Link: https://lore.kernel.org/all/20251125013302.3835909-4-quic_amakhija@quicinc.com/ Signed-off-by: Arpit Saini --- .../display/msm/qcom,qcs8300-mdss.yaml | 102 +++++++++++++++++- 1 file changed, 101 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/display/msm/qcom,qcs8300-mdss.yaml b/Documentation/devicetree/bindings/display/msm/qcom,qcs8300-mdss.yaml index e96baaae9ba9e..c41a86203e78a 100644 --- a/Documentation/devicetree/bindings/display/msm/qcom,qcs8300-mdss.yaml +++ b/Documentation/devicetree/bindings/display/msm/qcom,qcs8300-mdss.yaml @@ -53,13 +53,23 @@ patternProperties: contains: const: qcom,qcs8300-dp + "^dsi@[0-9a-f]+$": + type: object + additionalProperties: true + properties: + compatible: + contains: + const: qcom,qcs8300-dsi-ctrl + "^phy@[0-9a-f]+$": type: object additionalProperties: true properties: compatible: contains: - const: qcom,qcs8300-edp-phy + enum: + - qcom,qcs8300-dsi-phy-5nm + - qcom,qcs8300-edp-phy required: - compatible @@ -71,6 +81,7 @@ examples: #include #include #include + #include #include #include #include @@ -142,6 +153,13 @@ examples: remote-endpoint = <&mdss_dp0_in>; }; }; + + port@1 { + reg = <1>; + dpu_intf1_out: endpoint { + remote-endpoint = <&mdss_dsi0_in>; + }; + }; }; mdp_opp_table: opp-table { @@ -169,6 +187,88 @@ examples: }; }; + dsi@ae94000 { + compatible = "qcom,qcs8300-dsi-ctrl", + "qcom,sa8775p-dsi-ctrl", + "qcom,mdss-dsi-ctrl"; + reg = <0x0ae94000 0x400>; + reg-names = "dsi_ctrl"; + + interrupt-parent = <&mdss>; + interrupts = <4>; + + clocks = <&dispcc MDSS_DISP_CC_MDSS_BYTE0_CLK>, + <&dispcc MDSS_DISP_CC_MDSS_BYTE0_INTF_CLK>, + <&dispcc MDSS_DISP_CC_MDSS_PCLK0_CLK>, + <&dispcc MDSS_DISP_CC_MDSS_ESC0_CLK>, + <&dispcc MDSS_DISP_CC_MDSS_AHB_CLK>, + <&gcc GCC_DISP_HF_AXI_CLK>; + clock-names = "byte", + "byte_intf", + "pixel", + "core", + "iface", + "bus"; + assigned-clocks = <&dispcc MDSS_DISP_CC_MDSS_BYTE0_CLK_SRC>, + <&dispcc MDSS_DISP_CC_MDSS_PCLK0_CLK_SRC>; + assigned-clock-parents = <&mdss_dsi0_phy 0>, <&mdss_dsi0_phy 1>; + phys = <&mdss_dsi0_phy>; + + operating-points-v2 = <&dsi0_opp_table>; + power-domains = <&rpmhpd RPMHPD_MMCX>; + + vdda-supply = <&vreg_l5a>; + + #address-cells = <1>; + #size-cells = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + mdss0_dsi0_in: endpoint { + remote-endpoint = <&dpu_intf1_out>; + }; + }; + + port@1 { + reg = <1>; + mdss0_dsi0_out: endpoint { }; + }; + }; + + dsi0_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-358000000 { + opp-hz = /bits/ 64 <358000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + }; + }; + + mdss_dsi0_phy: phy@ae94400 { + compatible = "qcom,qcs8300-dsi-phy-5nm", + "qcom,sa8775p-dsi-phy-5nm"; + reg = <0x0ae94400 0x200>, + <0x0ae94600 0x280>, + <0x0ae94900 0x27c>; + reg-names = "dsi_phy", + "dsi_phy_lane", + "dsi_pll"; + + #clock-cells = <1>; + #phy-cells = <0>; + + clocks = <&dispcc MDSS_DISP_CC_MDSS_AHB_CLK>, + <&rpmhcc RPMH_CXO_CLK>; + clock-names = "iface", "ref"; + + vdds-supply = <&vreg_l4a>; + }; + mdss_dp0_phy: phy@aec2a00 { compatible = "qcom,qcs8300-edp-phy", "qcom,sa8775p-edp-phy"; From ef92bcc58b4736c20d6fb9fcf6d8d263043ff54c Mon Sep 17 00:00:00 2001 From: Ayushi Makhija Date: Tue, 25 Nov 2025 07:02:59 +0530 Subject: [PATCH 0287/2333] FROMLIST: dt-bindings: msm: dsi-controller-main: document the QCS8300 DSI CTRL Document the DSI CTRL on the QCS8300 Platform. Signed-off-by: Ayushi Makhija Link: https://lore.kernel.org/all/20251125013302.3835909-3-quic_amakhija@quicinc.com/ Signed-off-by: Arpit Saini --- .../devicetree/bindings/display/msm/dsi-controller-main.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Documentation/devicetree/bindings/display/msm/dsi-controller-main.yaml b/Documentation/devicetree/bindings/display/msm/dsi-controller-main.yaml index 4400d4cce0722..6276350e582f7 100644 --- a/Documentation/devicetree/bindings/display/msm/dsi-controller-main.yaml +++ b/Documentation/devicetree/bindings/display/msm/dsi-controller-main.yaml @@ -45,6 +45,11 @@ properties: - qcom,sm8650-dsi-ctrl - qcom,sm8750-dsi-ctrl - const: qcom,mdss-dsi-ctrl + - items: + - enum: + - qcom,qcs8300-dsi-ctrl + - const: qcom,sa8775p-dsi-ctrl + - const: qcom,mdss-dsi-ctrl - enum: - qcom,dsi-ctrl-6g-qcm2290 - qcom,mdss-dsi-ctrl # This should always come with an SoC-specific compatible From 18068b2f14963dca59baaf47b0a722893e65d882 Mon Sep 17 00:00:00 2001 From: Ayushi Makhija Date: Tue, 25 Nov 2025 07:02:58 +0530 Subject: [PATCH 0288/2333] FROMLIST: dt-bindings: display: msm-dsi-phy-7nm: document the QCS8300 DSI PHY Document the DSI PHY on the QCS8300 Platform. Signed-off-by: Ayushi Makhija Link: https://lore.kernel.org/all/20251125013302.3835909-2-quic_amakhija@quicinc.com/ Signed-off-by: Arpit Saini --- .../bindings/display/msm/dsi-phy-7nm.yaml | 30 +++++++++++-------- 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/Documentation/devicetree/bindings/display/msm/dsi-phy-7nm.yaml b/Documentation/devicetree/bindings/display/msm/dsi-phy-7nm.yaml index 1ca820a500b72..7a83387502da1 100644 --- a/Documentation/devicetree/bindings/display/msm/dsi-phy-7nm.yaml +++ b/Documentation/devicetree/bindings/display/msm/dsi-phy-7nm.yaml @@ -14,18 +14,24 @@ allOf: properties: compatible: - enum: - - qcom,dsi-phy-7nm - - qcom,dsi-phy-7nm-8150 - - qcom,sa8775p-dsi-phy-5nm - - qcom,sar2130p-dsi-phy-5nm - - qcom,sc7280-dsi-phy-7nm - - qcom,sm6375-dsi-phy-7nm - - qcom,sm8350-dsi-phy-5nm - - qcom,sm8450-dsi-phy-5nm - - qcom,sm8550-dsi-phy-4nm - - qcom,sm8650-dsi-phy-4nm - - qcom,sm8750-dsi-phy-3nm + oneOf: + - items: + - enum: + - qcom,dsi-phy-7nm + - qcom,dsi-phy-7nm-8150 + - qcom,sa8775p-dsi-phy-5nm + - qcom,sar2130p-dsi-phy-5nm + - qcom,sc7280-dsi-phy-7nm + - qcom,sm6375-dsi-phy-7nm + - qcom,sm8350-dsi-phy-5nm + - qcom,sm8450-dsi-phy-5nm + - qcom,sm8550-dsi-phy-4nm + - qcom,sm8650-dsi-phy-4nm + - qcom,sm8750-dsi-phy-3nm + - items: + - enum: + - qcom,qcs8300-dsi-phy-5nm + - const: qcom,sa8775p-dsi-phy-5nm reg: items: From e33ba2df0d3d45883bb883445f4d5ac298f98fa1 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Wed, 14 May 2025 02:30:00 +0300 Subject: [PATCH 0289/2333] FROMLIST: drm/msm/dpu: enable virtual planes by default Turn on the switch and use virtual planes by default, enhancing utilisation of the display pipelines. It is still possible to use legacy implementation by using `msm.dpu_use_virtual_planes=false` kernel boot parameter. Link:https://lore.kernel.org/all/20250514-dpu-enable-virt-planes-v1-1-bf5ba0088007@oss.qualcomm.com/ Signed-off-by: Dmitry Baryshkov Signed-off-by: Mahadevan P --- drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c index 4e5a8ecd31f75..45bf345493164 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c @@ -52,7 +52,7 @@ #define DPU_DEBUGFS_DIR "msm_dpu" #define DPU_DEBUGFS_HWMASKNAME "hw_log_mask" -bool dpu_use_virtual_planes; +bool dpu_use_virtual_planes = true; module_param(dpu_use_virtual_planes, bool, 0); static int dpu_kms_hw_init(struct msm_kms *kms); From 99b91057d27f9b9240d3a2ffd4c8f4858e11379a Mon Sep 17 00:00:00 2001 From: Mahadevan P Date: Mon, 24 Nov 2025 19:57:01 +0530 Subject: [PATCH 0290/2333] FROMLIST: drm/msm/disp/dpu: add merge3d support for sc7280 Add support for the merge3d block on sc7280 which will allow merge of streams coming from two layer mixers routed to single non DSC interface. This change helps to support larger buffer width which exceeds max_linewidth of 2400. Link:https://lore.kernel.org/all/20251124-merge3d-sc7280-v1-1-798d94211626@oss.qualcomm.com/ Fixes: 591e34a091d1 ("drm/msm/disp/dpu1: add support for display for SC7280 target") Signed-off-by: Mahadevan P --- .../gpu/drm/msm/disp/dpu1/catalog/dpu_7_2_sc7280.h | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_2_sc7280.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_2_sc7280.h index 8f978b9c34520..2f8688224f343 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_2_sc7280.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_2_sc7280.h @@ -13,6 +13,7 @@ static const struct dpu_caps sc7280_dpu_caps = { .has_dim_layer = true, .has_idle_pc = true, .max_linewidth = 2400, + .has_3d_merge = true, .pixel_ram_size = DEFAULT_PIXEL_RAM_SIZE, }; @@ -134,17 +135,24 @@ static const struct dpu_pingpong_cfg sc7280_pp[] = { .name = "pingpong_2", .id = PINGPONG_2, .base = 0x6b000, .len = 0, .sblk = &sc7280_pp_sblk, - .merge_3d = 0, + .merge_3d = MERGE_3D_1, .intr_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 10), }, { .name = "pingpong_3", .id = PINGPONG_3, .base = 0x6c000, .len = 0, .sblk = &sc7280_pp_sblk, - .merge_3d = 0, + .merge_3d = MERGE_3D_1, .intr_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 11), }, }; +static const struct dpu_merge_3d_cfg sc7280_merge_3d[] = { + { + .name = "merge_3d_1", .id = MERGE_3D_1, + .base = 0x4f000, .len = 0x8, + }, +}; + /* NOTE: sc7280 only has one DSC hard slice encoder */ static const struct dpu_dsc_cfg sc7280_dsc[] = { { @@ -247,6 +255,8 @@ const struct dpu_mdss_cfg dpu_sc7280_cfg = { .mixer = sc7280_lm, .pingpong_count = ARRAY_SIZE(sc7280_pp), .pingpong = sc7280_pp, + .merge_3d_count = ARRAY_SIZE(sc7280_merge_3d), + .merge_3d = sc7280_merge_3d, .dsc_count = ARRAY_SIZE(sc7280_dsc), .dsc = sc7280_dsc, .wb_count = ARRAY_SIZE(sc7280_wb), From 840e51261ddeb28c475d0bf3968e268611f195f4 Mon Sep 17 00:00:00 2001 From: Nilesh Laad Date: Wed, 26 Nov 2025 17:01:18 +0530 Subject: [PATCH 0291/2333] FROMLIST: drm/bridge: lt9611uxc: extend mode valid checks Currently valid mode checks are only for hdisplay and vdisplay, add htotal and vtotal to filter only specific modes. Link:https://lore.kernel.org/lkml/20251126-lt9611uxc-modes-v2-1-34bf9b351921@oss.qualcomm.com/ Signed-off-by: Nilesh Laad Signed-off-by: Mahadevan P --- drivers/gpu/drm/bridge/lontium-lt9611uxc.c | 36 ++++++++++++---------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/bridge/lontium-lt9611uxc.c b/drivers/gpu/drm/bridge/lontium-lt9611uxc.c index 6f2b72fba598e..d0273a55687de 100644 --- a/drivers/gpu/drm/bridge/lontium-lt9611uxc.c +++ b/drivers/gpu/drm/bridge/lontium-lt9611uxc.c @@ -89,7 +89,9 @@ static const struct regmap_config lt9611uxc_regmap_config = { struct lt9611uxc_mode { u16 hdisplay; + u16 htotal; u16 vdisplay; + u16 vtotal; u8 vrefresh; }; @@ -98,22 +100,22 @@ struct lt9611uxc_mode { * Enumerate them here to check whether the mode is supported. */ static struct lt9611uxc_mode lt9611uxc_modes[] = { - { 1920, 1080, 60 }, - { 1920, 1080, 30 }, - { 1920, 1080, 25 }, - { 1366, 768, 60 }, - { 1360, 768, 60 }, - { 1280, 1024, 60 }, - { 1280, 800, 60 }, - { 1280, 720, 60 }, - { 1280, 720, 50 }, - { 1280, 720, 30 }, - { 1152, 864, 60 }, - { 1024, 768, 60 }, - { 800, 600, 60 }, - { 720, 576, 50 }, - { 720, 480, 60 }, - { 640, 480, 60 }, + { 1920, 2200, 1080, 1125, 60 }, + { 1920, 2200, 1080, 1125, 30 }, + { 1920, 2640, 1080, 1125, 25 }, + { 1366, 1792, 768, 798, 60 }, + { 1360, 1792, 768, 795, 60 }, + { 1280, 1688, 1024, 1066, 60 }, + { 1280, 1680, 800, 831, 60 }, + { 1280, 1650, 720, 750, 60 }, + { 1280, 1980, 720, 750, 50 }, + { 1280, 3300, 720, 750, 30 }, + { 1152, 1600, 864, 900, 60 }, + { 1024, 1344, 768, 806, 60 }, + { 800, 1056, 600, 628, 60 }, + { 720, 864, 576, 625, 50 }, + { 720, 858, 480, 525, 60 }, + { 640, 800, 480, 525, 60 }, }; static struct lt9611uxc *bridge_to_lt9611uxc(struct drm_bridge *bridge) @@ -237,7 +239,9 @@ static struct lt9611uxc_mode *lt9611uxc_find_mode(const struct drm_display_mode for (i = 0; i < ARRAY_SIZE(lt9611uxc_modes); i++) { if (lt9611uxc_modes[i].hdisplay == mode->hdisplay && + lt9611uxc_modes[i].htotal == mode->htotal && lt9611uxc_modes[i].vdisplay == mode->vdisplay && + lt9611uxc_modes[i].vtotal == mode->vtotal && lt9611uxc_modes[i].vrefresh == drm_mode_vrefresh(mode)) { return <9611uxc_modes[i]; } From 378575e046b64e79a992b62453775ecfe63fc36b Mon Sep 17 00:00:00 2001 From: Nilesh Laad Date: Wed, 26 Nov 2025 18:52:37 +0530 Subject: [PATCH 0292/2333] FROMLIST: drm/bridge: lt9611uxc: add support for 4K@30 resolution Add 3840x2160@30 mode in lt9611uxc modes to add support for 4K@30 resolution. Link:https://lore.kernel.org/r/20251126-lt9611uxc-4k30-v2-1-3de0ea58c24e@oss.qualcomm.com Signed-off-by: Nilesh Laad Signed-off-by: Mahadevan P --- drivers/gpu/drm/bridge/lontium-lt9611uxc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/bridge/lontium-lt9611uxc.c b/drivers/gpu/drm/bridge/lontium-lt9611uxc.c index d0273a55687de..d8ab95bb3a612 100644 --- a/drivers/gpu/drm/bridge/lontium-lt9611uxc.c +++ b/drivers/gpu/drm/bridge/lontium-lt9611uxc.c @@ -100,6 +100,7 @@ struct lt9611uxc_mode { * Enumerate them here to check whether the mode is supported. */ static struct lt9611uxc_mode lt9611uxc_modes[] = { + { 3840, 4400, 2160, 2250, 30 }, { 1920, 2200, 1080, 1125, 60 }, { 1920, 2200, 1080, 1125, 30 }, { 1920, 2640, 1080, 1125, 25 }, From 44a5bf0663cff2f58a32907b7a944fa8c120812e Mon Sep 17 00:00:00 2001 From: Manaf Meethalavalappu Pallikunhi Date: Tue, 21 Oct 2025 23:23:59 -0700 Subject: [PATCH 0293/2333] FROMLIST: dt-bindings: thermal: qcom-tsens: document the Kaanapali Temperature Sensor Document the Temperature Sensor (TSENS) on the Kaanapali Platform. Signed-off-by: Manaf Meethalavalappu Pallikunhi Signed-off-by: Jingyi Wang Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20251021-b4-knp-tsens-v2-1-7b662e2e71b4@oss.qualcomm.com --- Documentation/devicetree/bindings/thermal/qcom-tsens.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml b/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml index 78e2f6573b96f..b9f99d1099499 100644 --- a/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml +++ b/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml @@ -50,6 +50,7 @@ properties: items: - enum: - qcom,glymur-tsens + - qcom,kaanapali-tsens - qcom,milos-tsens - qcom,msm8953-tsens - qcom,msm8996-tsens From fed007627e6eb19876bce762d2a6c3ffc3769b9f Mon Sep 17 00:00:00 2001 From: Harshal Dev Date: Thu, 27 Nov 2025 14:37:04 +0530 Subject: [PATCH 0294/2333] FROMLIST: arm64: dts: qcom: x1e80100: Add crypto engine On X Elite, there is a crypto engine IP block similar to ones found on SM8x50 platforms. Describe the crypto engine and its BAM. Signed-off-by: Harshal Dev Link: https://lore.kernel.org/lkml/20251127-crypto_dt_node_x1e80100-v3-1-29722003fe83@oss.qualcomm.com/ --- arch/arm64/boot/dts/qcom/x1e80100.dtsi | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/x1e80100.dtsi b/arch/arm64/boot/dts/qcom/x1e80100.dtsi index ff544ac35cc8c..74c7102820c60 100644 --- a/arch/arm64/boot/dts/qcom/x1e80100.dtsi +++ b/arch/arm64/boot/dts/qcom/x1e80100.dtsi @@ -3033,6 +3033,30 @@ }; }; + cryptobam: dma-controller@1dc4000 { + compatible = "qcom,bam-v1.7.4", "qcom,bam-v1.7.0"; + reg = <0x0 0x01dc4000 0x0 0x28000>; + interrupts = ; + #dma-cells = <1>; + iommus = <&apps_smmu 0x480 0x0000>, + <&apps_smmu 0x481 0x0000>; + qcom,ee = <0>; + qcom,controlled-remotely; + num-channels = <20>; + qcom,num-ees = <4>; + }; + + crypto: crypto@1dfa000 { + compatible = "qcom,x1e80100-qce", "qcom,sm8150-qce", "qcom,qce"; + reg = <0x0 0x01dfa000 0x0 0x6000>; + dmas = <&cryptobam 4>, <&cryptobam 5>; + dma-names = "rx", "tx"; + iommus = <&apps_smmu 0x480 0x0000>, + <&apps_smmu 0x481 0x0000>; + interconnects = <&aggre2_noc MASTER_CRYPTO 0 &mc_virt SLAVE_EBI1 0>; + interconnect-names = "memory"; + }; + cnoc_main: interconnect@1500000 { compatible = "qcom,x1e80100-cnoc-main"; reg = <0 0x01500000 0 0x14400>; From 37d1752ff15d0e43519f2803ab65e069d5af126f Mon Sep 17 00:00:00 2001 From: Mohammad Rafi Shaik Date: Tue, 7 Oct 2025 07:32:25 +0530 Subject: [PATCH 0295/2333] FROMLIST: ASoC: soc-pcm: Fix mute and unmute control for non-dynamic DAI links In setups where the same codec DAI is reused across multiple DAI links, mute controls via `snd_soc_dai_digital_mute()` is skipped for non-dynamic links. The trigger operations are not invoked when `dai_link->dynamic == 0`, and mute controls is currently conditioned only on `snd_soc_dai_mute_is_ctrled_at_trigger()`. This patch ensures that mute and unmute is applied explicitly for non-dynamic links. Link: https://lore.kernel.org/linux-sound/20251007023325.853640-1-mohammad.rafi.shaik@oss.qualcomm.com/ Fixes: f0220575e65a ("ASoC: soc-dai: add flag to mute and unmute stream during trigger") Cc: stable@vger.kernel.org Signed-off-by: Mohammad Rafi Shaik --- sound/soc/soc-pcm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 2c21fd528afd0..4ed829b49bc2d 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -949,7 +949,7 @@ static int __soc_pcm_prepare(struct snd_soc_pcm_runtime *rtd, SND_SOC_DAPM_STREAM_START); for_each_rtd_dais(rtd, i, dai) { - if (!snd_soc_dai_mute_is_ctrled_at_trigger(dai)) + if (!snd_soc_dai_mute_is_ctrled_at_trigger(dai) || !rtd->dai_link->dynamic) snd_soc_dai_digital_mute(dai, 0, substream->stream); } @@ -1007,7 +1007,7 @@ static int soc_pcm_hw_clean(struct snd_soc_pcm_runtime *rtd, soc_pcm_set_dai_params(dai, NULL); if (snd_soc_dai_stream_active(dai, substream->stream) == 1) { - if (!snd_soc_dai_mute_is_ctrled_at_trigger(dai)) + if (!snd_soc_dai_mute_is_ctrled_at_trigger(dai) || !rtd->dai_link->dynamic) snd_soc_dai_digital_mute(dai, 1, substream->stream); } } From 231704f7d6c09ce72f65029c62e684d4883465c9 Mon Sep 17 00:00:00 2001 From: Jishnu Prakash Date: Fri, 24 Oct 2025 15:03:21 +0530 Subject: [PATCH 0296/2333] FROMLIST: dt-bindings: spmi: split out common QCOM SPMI PMIC arbiter properties Split out the common SPMI PMIC arbiter properties for QCOM devices into a separate file so that it can be included as a reference for devices using them. This will be needed for the upcoming PMIC v8 arbiter support patch, as the v8 arbiter also uses these common properties. Signed-off-by: Jishnu Prakash Reviewed-by: Rob Herring (Arm) Link: https://lore.kernel.org/r/20251024-pmic_arb_v8-v3-1-cad8d6a2cbc0@oss.qualcomm.com Signed-off-by: Rakesh Kota --- .../spmi/qcom,spmi-pmic-arb-common.yaml | 35 +++++++++++++++++++ .../bindings/spmi/qcom,spmi-pmic-arb.yaml | 17 +-------- .../spmi/qcom,x1e80100-spmi-pmic-arb.yaml | 21 +++-------- 3 files changed, 40 insertions(+), 33 deletions(-) create mode 100644 Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb-common.yaml diff --git a/Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb-common.yaml b/Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb-common.yaml new file mode 100644 index 0000000000000..8c38ed145e745 --- /dev/null +++ b/Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb-common.yaml @@ -0,0 +1,35 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/spmi/qcom,spmi-pmic-arb-common.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm Technologies, Inc. SPMI Controller (common) + +maintainers: + - David Collins + +description: | + This defines some common properties used to define Qualcomm SPMI controllers + for PMIC arbiter. + +properties: + qcom,ee: + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 5 + description: + indicates the active Execution Environment identifier + + qcom,channel: + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 5 + description: + which of the PMIC Arb provided channels to use for accesses + +required: + - qcom,ee + - qcom,channel + +additionalProperties: true diff --git a/Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb.yaml b/Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb.yaml index 51daf1b847a9b..d0c683dd52841 100644 --- a/Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb.yaml +++ b/Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb.yaml @@ -19,6 +19,7 @@ description: | allOf: - $ref: spmi.yaml + - $ref: qcom,spmi-pmic-arb-common.yaml properties: compatible: @@ -71,20 +72,6 @@ properties: '#size-cells': true - qcom,ee: - $ref: /schemas/types.yaml#/definitions/uint32 - minimum: 0 - maximum: 5 - description: > - indicates the active Execution Environment identifier - - qcom,channel: - $ref: /schemas/types.yaml#/definitions/uint32 - minimum: 0 - maximum: 5 - description: > - which of the PMIC Arb provided channels to use for accesses - qcom,bus-id: $ref: /schemas/types.yaml#/definitions/uint32 minimum: 0 @@ -97,8 +84,6 @@ properties: required: - compatible - reg-names - - qcom,ee - - qcom,channel unevaluatedProperties: false diff --git a/Documentation/devicetree/bindings/spmi/qcom,x1e80100-spmi-pmic-arb.yaml b/Documentation/devicetree/bindings/spmi/qcom,x1e80100-spmi-pmic-arb.yaml index 7c3cc20a80d6c..08369fdd21612 100644 --- a/Documentation/devicetree/bindings/spmi/qcom,x1e80100-spmi-pmic-arb.yaml +++ b/Documentation/devicetree/bindings/spmi/qcom,x1e80100-spmi-pmic-arb.yaml @@ -17,6 +17,9 @@ description: | The PMIC Arbiter can also act as an interrupt controller, providing interrupts to slave devices. +allOf: + - $ref: qcom,spmi-pmic-arb-common.yaml + properties: compatible: oneOf: @@ -45,20 +48,6 @@ properties: '#size-cells': const: 2 - qcom,ee: - $ref: /schemas/types.yaml#/definitions/uint32 - minimum: 0 - maximum: 5 - description: > - indicates the active Execution Environment identifier - - qcom,channel: - $ref: /schemas/types.yaml#/definitions/uint32 - minimum: 0 - maximum: 5 - description: > - which of the PMIC Arb provided channels to use for accesses - patternProperties: "^spmi@[a-f0-9]+$": type: object @@ -96,10 +85,8 @@ patternProperties: required: - compatible - reg-names - - qcom,ee - - qcom,channel -additionalProperties: false +unevaluatedProperties: false examples: - | From 095d317c07b7e4bbe4052a97fce5029fbd19b1f6 Mon Sep 17 00:00:00 2001 From: Jishnu Prakash Date: Fri, 24 Oct 2025 15:03:22 +0530 Subject: [PATCH 0297/2333] FROMLIST: dt-bindings: spmi: add support for glymur-spmi-pmic-arb (arbiter v8) SPMI PMIC Arbiter version 8 builds upon version 7 with support for up to four SPMI buses. To achieve this, the register map was slightly rearranged. Add a new binding file and compatible string for version 8 using the name 'glymur' as the Qualcomm Technologies, Inc. Glymur SoC is the first one to use PMIC arbiter version 8. This specifies the new register ranges needed only for version 8. Also document SPMI PMIC Arbiter for Qualcomm Kaanapali SoC, by adding fallback to Glymur compatible string, as it too has version 8 functionality. Signed-off-by: David Collins Signed-off-by: Pankaj Patil Signed-off-by: Kamal Wadhwa Signed-off-by: Jingyi Wang Signed-off-by: Jishnu Prakash Reviewed-by: Rob Herring (Arm) Link: https://lore.kernel.org/r/20251024-pmic_arb_v8-v3-2-cad8d6a2cbc0@oss.qualcomm.com Signed-off-by: Rakesh Kota --- .../spmi/qcom,glymur-spmi-pmic-arb.yaml | 150 ++++++++++++++++++ 1 file changed, 150 insertions(+) create mode 100644 Documentation/devicetree/bindings/spmi/qcom,glymur-spmi-pmic-arb.yaml diff --git a/Documentation/devicetree/bindings/spmi/qcom,glymur-spmi-pmic-arb.yaml b/Documentation/devicetree/bindings/spmi/qcom,glymur-spmi-pmic-arb.yaml new file mode 100644 index 0000000000000..3b5005b96c6d5 --- /dev/null +++ b/Documentation/devicetree/bindings/spmi/qcom,glymur-spmi-pmic-arb.yaml @@ -0,0 +1,150 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/spmi/qcom,glymur-spmi-pmic-arb.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm Technologies, Inc. Glymur SPMI Controller (PMIC Arbiter v8) + +maintainers: + - David Collins + +description: | + The Glymur SPMI PMIC Arbiter implements HW version 8 and it's an SPMI + controller with wrapping arbitration logic to allow for multiple on-chip + devices to control up to 4 SPMI separate buses. + + The PMIC Arbiter can also act as an interrupt controller, providing interrupts + to slave devices. + +allOf: + - $ref: /schemas/spmi/qcom,spmi-pmic-arb-common.yaml + +properties: + compatible: + oneOf: + - items: + - enum: + - qcom,kaanapali-spmi-pmic-arb + - const: qcom,glymur-spmi-pmic-arb + - enum: + - qcom,glymur-spmi-pmic-arb + + reg: + items: + - description: core registers + - description: tx-channel per virtual slave registers + - description: rx-channel (called observer) per virtual slave registers + - description: channel to PMIC peripheral mapping registers + + reg-names: + items: + - const: core + - const: chnls + - const: obsrvr + - const: chnl_map + + ranges: true + + '#address-cells': + const: 2 + + '#size-cells': + const: 2 + +patternProperties: + "^spmi@[a-f0-9]+$": + type: object + $ref: /schemas/spmi/spmi.yaml + unevaluatedProperties: false + + properties: + reg: + items: + - description: configuration registers + - description: interrupt controller registers + - description: channel owner EE mapping registers + + reg-names: + items: + - const: cnfg + - const: intr + - const: chnl_owner + + interrupts: + maxItems: 1 + + interrupt-names: + const: periph_irq + + interrupt-controller: true + + '#interrupt-cells': + const: 4 + description: | + cell 1: slave ID for the requested interrupt (0-15) + cell 2: peripheral ID for requested interrupt (0-255) + cell 3: the requested peripheral interrupt (0-7) + cell 4: interrupt flags indicating level-sense information, + as defined in dt-bindings/interrupt-controller/irq.h + +required: + - compatible + - reg-names + +unevaluatedProperties: false + +examples: + - | + #include + + soc { + #address-cells = <2>; + #size-cells = <2>; + + arbiter@c400000 { + compatible = "qcom,glymur-spmi-pmic-arb"; + reg = <0x0 0xc400000 0x0 0x3000>, + <0x0 0xc900000 0x0 0x400000>, + <0x0 0xc4c0000 0x0 0x400000>, + <0x0 0xc403000 0x0 0x8000>; + reg-names = "core", "chnls", "obsrvr", "chnl_map"; + + qcom,ee = <0>; + qcom,channel = <0>; + + #address-cells = <2>; + #size-cells = <2>; + ranges; + + spmi@c426000 { + reg = <0x0 0xc426000 0x0 0x4000>, + <0x0 0xc8c0000 0x0 0x10000>, + <0x0 0xc42a000 0x0 0x8000>; + reg-names = "cnfg", "intr", "chnl_owner"; + + interrupts-extended = <&pdc 1 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "periph_irq"; + interrupt-controller; + #interrupt-cells = <4>; + + #address-cells = <2>; + #size-cells = <0>; + }; + + spmi@c437000 { + reg = <0x0 0xc437000 0x0 0x4000>, + <0x0 0xc8d0000 0x0 0x10000>, + <0x0 0xc43b000 0x0 0x8000>; + reg-names = "cnfg", "intr", "chnl_owner"; + + interrupts-extended = <&pdc 3 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "periph_irq"; + interrupt-controller; + #interrupt-cells = <4>; + + #address-cells = <2>; + #size-cells = <0>; + }; + }; + }; From 45eaf11a441951a7b05dc4178fe45752e6177fbc Mon Sep 17 00:00:00 2001 From: David Collins Date: Fri, 24 Oct 2025 15:03:23 +0530 Subject: [PATCH 0298/2333] FROMLIST: spmi: spmi-pmic-arb: add support for PMIC arbiter v8 PMIC arbiter v8 supports up to 4 SPMI buses and up to 8192 PMIC peripherals. Its register map differs from v7 as several fields increased in size. Add support for PMIC arbiter version 8. Signed-off-by: David Collins Signed-off-by: Kamal Wadhwa Signed-off-by: Jishnu Prakash Link: https://lore.kernel.org/r/20251024-pmic_arb_v8-v3-3-cad8d6a2cbc0@oss.qualcomm.com Signed-off-by: Rakesh Kota --- drivers/spmi/spmi-pmic-arb.c | 324 +++++++++++++++++++++++++++++++---- 1 file changed, 294 insertions(+), 30 deletions(-) diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c index 91581974ef84e..612736973e4b0 100644 --- a/drivers/spmi/spmi-pmic-arb.c +++ b/drivers/spmi/spmi-pmic-arb.c @@ -3,6 +3,7 @@ * Copyright (c) 2012-2015, 2017, 2021, The Linux Foundation. All rights reserved. */ #include +#include #include #include #include @@ -25,10 +26,12 @@ #define PMIC_ARB_VERSION_V3_MIN 0x30000000 #define PMIC_ARB_VERSION_V5_MIN 0x50000000 #define PMIC_ARB_VERSION_V7_MIN 0x70000000 +#define PMIC_ARB_VERSION_V8_MIN 0x80000000 #define PMIC_ARB_INT_EN 0x0004 #define PMIC_ARB_FEATURES 0x0004 #define PMIC_ARB_FEATURES_PERIPH_MASK GENMASK(10, 0) +#define PMIC_ARB_FEATURES_V8_PERIPH_MASK GENMASK(12, 0) #define PMIC_ARB_FEATURES1 0x0008 @@ -50,9 +53,10 @@ #define SPMI_MAPPING_BIT_IS_1_RESULT(X) (((X) >> 0) & 0xFF) #define SPMI_MAPPING_TABLE_TREE_DEPTH 16 /* Maximum of 16-bits */ -#define PMIC_ARB_MAX_PPID BIT(12) /* PPID is 12bit */ +#define PMIC_ARB_MAX_PPID BIT(13) #define PMIC_ARB_APID_VALID BIT(15) #define PMIC_ARB_CHAN_IS_IRQ_OWNER(reg) ((reg) & BIT(24)) +#define PMIC_ARB_V8_CHAN_IS_IRQ_OWNER(reg) ((reg) & BIT(31)) #define INVALID_EE 0xFF /* Ownership Table */ @@ -96,30 +100,33 @@ enum pmic_arb_channel { PMIC_ARB_CHANNEL_OBS, }; -#define PMIC_ARB_MAX_BUSES 2 +#define PMIC_ARB_MAX_BUSES 4 +#define PMIC_ARB_MAX_BUSES_V8 4 /* Maximum number of support PMIC peripherals */ #define PMIC_ARB_MAX_PERIPHS 512 #define PMIC_ARB_MAX_PERIPHS_V7 1024 +#define PMIC_ARB_MAX_PERIPHS_V8 8192 #define PMIC_ARB_TIMEOUT_US 1000 #define PMIC_ARB_MAX_TRANS_BYTES (8) #define PMIC_ARB_APID_MASK 0xFF #define PMIC_ARB_PPID_MASK 0xFFF +#define PMIC_ARB_V8_PPID_MASK 0x1FFF /* interrupt enable bit */ #define SPMI_PIC_ACC_ENABLE_BIT BIT(0) #define spec_to_hwirq(slave_id, periph_id, irq_id, apid) \ - ((((slave_id) & 0xF) << 28) | \ - (((periph_id) & 0xFF) << 20) | \ - (((irq_id) & 0x7) << 16) | \ - (((apid) & 0x3FF) << 0)) + (FIELD_PREP(GENMASK(28, 24), (slave_id)) | \ + FIELD_PREP(GENMASK(23, 16), (periph_id)) | \ + FIELD_PREP(GENMASK(15, 13), (irq_id)) | \ + FIELD_PREP(GENMASK(12, 0), (apid))) -#define hwirq_to_sid(hwirq) (((hwirq) >> 28) & 0xF) -#define hwirq_to_per(hwirq) (((hwirq) >> 20) & 0xFF) -#define hwirq_to_irq(hwirq) (((hwirq) >> 16) & 0x7) -#define hwirq_to_apid(hwirq) (((hwirq) >> 0) & 0x3FF) +#define hwirq_to_sid(hwirq) FIELD_GET(GENMASK(28, 24), (hwirq)) +#define hwirq_to_per(hwirq) FIELD_GET(GENMASK(23, 16), (hwirq)) +#define hwirq_to_irq(hwirq) FIELD_GET(GENMASK(15, 13), (hwirq)) +#define hwirq_to_apid(hwirq) FIELD_GET(GENMASK(12, 0), (hwirq)) struct pmic_arb_ver_ops; @@ -138,11 +145,12 @@ struct spmi_pmic_arb; * @domain: irq domain object for PMIC IRQ domain * @intr: address of the SPMI interrupt control registers. * @cnfg: address of the PMIC Arbiter configuration registers. + * @apid_owner: on v8: address of APID owner mapping table registers * @spmic: spmi controller registered for this bus * @lock: lock to synchronize accesses. - * @base_apid: on v7: minimum APID associated with the particular SPMI - * bus instance - * @apid_count: on v5 and v7: number of APIDs associated with the + * @base_apid: on v7 and v8: minimum APID associated with the + * particular SPMI bus instance + * @apid_count: on v5, v7 and v8: number of APIDs associated with the * particular SPMI bus instance * @mapping_table: in-memory copy of PPID -> APID mapping table. * @mapping_table_valid:bitmap containing valid-only periphs @@ -159,6 +167,7 @@ struct spmi_pmic_arb_bus { struct irq_domain *domain; void __iomem *intr; void __iomem *cnfg; + void __iomem *apid_owner; struct spmi_controller *spmic; raw_spinlock_t lock; u16 base_apid; @@ -181,6 +190,7 @@ struct spmi_pmic_arb_bus { * @wr_base: on v1 "core", on v2 "chnls" register base off DT. * @core: core register base for v2 and above only (see above) * @core_size: core register base size + * @apid_map: on v8, APID mapping table register base * @channel: execution environment channel to use for accesses. * @ee: the current Execution Environment * @ver_ops: version dependent operations. @@ -193,6 +203,7 @@ struct spmi_pmic_arb { void __iomem *wr_base; void __iomem *core; resource_size_t core_size; + void __iomem *apid_map; u8 channel; u8 ee; const struct pmic_arb_ver_ops *ver_ops; @@ -206,6 +217,7 @@ struct spmi_pmic_arb { * * @ver_str: version string. * @get_core_resources: initializes the core, observer and channels + * @get_bus_resources: requests per-SPMI bus register resources * @init_apid: finds the apid base and count * @ppid_to_apid: finds the apid for a given ppid. * @non_data_cmd: on v1 issues an spmi non-data command. @@ -227,6 +239,9 @@ struct spmi_pmic_arb { struct pmic_arb_ver_ops { const char *ver_str; int (*get_core_resources)(struct platform_device *pdev, void __iomem *core); + int (*get_bus_resources)(struct platform_device *pdev, + struct device_node *node, + struct spmi_pmic_arb_bus *bus); int (*init_apid)(struct spmi_pmic_arb_bus *bus, int index); int (*ppid_to_apid)(struct spmi_pmic_arb_bus *bus, u16 ppid); /* spmi commands (read_cmd, write_cmd, cmd) functionality */ @@ -656,7 +671,7 @@ static int periph_interrupt(struct spmi_pmic_arb_bus *bus, u16 apid) unsigned int irq; u32 status, id; int handled = 0; - u8 sid = (bus->apid_data[apid].ppid >> 8) & 0xF; + u8 sid = (bus->apid_data[apid].ppid >> 8) & 0x1F; u8 per = bus->apid_data[apid].ppid & 0xFF; status = readl_relaxed(pmic_arb->ver_ops->irq_status(bus, apid)); @@ -686,7 +701,7 @@ static void pmic_arb_chained_irq(struct irq_desc *desc) int last = bus->max_apid; /* * acc_offset will be non-zero for the secondary SPMI bus instance on - * v7 controllers. + * v7 and v8 controllers. */ int acc_offset = bus->base_apid >> 5; u8 ee = pmic_arb->ee; @@ -913,7 +928,7 @@ static int qpnpint_irq_domain_translate(struct irq_domain *d, return -EINVAL; if (fwspec->param_count != 4) return -EINVAL; - if (intspec[0] > 0xF || intspec[1] > 0xFF || intspec[2] > 0x7) + if (intspec[0] > 0x1F || intspec[1] > 0xFF || intspec[2] > 0x7) return -EINVAL; ppid = intspec[0] << 8 | intspec[1]; @@ -1160,6 +1175,24 @@ static int pmic_arb_ppid_to_apid_v2(struct spmi_pmic_arb_bus *bus, u16 ppid) return apid_valid & ~PMIC_ARB_APID_VALID; } +static void pmic_arb_dump_apid_map(struct spmi_pmic_arb_bus *bus) +{ + struct apid_data *apidd; + u16 apid, ppid; + + /* Dump the mapping table for debug purposes. */ + dev_dbg(&bus->spmic->dev, "PPID APID Write-EE IRQ-EE\n"); + for (ppid = 0; ppid < PMIC_ARB_MAX_PPID; ppid++) { + apid = bus->ppid_to_apid[ppid]; + if (apid & PMIC_ARB_APID_VALID) { + apid &= ~PMIC_ARB_APID_VALID; + apidd = &bus->apid_data[apid]; + dev_dbg(&bus->spmic->dev, "%#03X %3u %2u %2u\n", + ppid, apid, apidd->write_ee, apidd->irq_ee); + } + } +} + static int pmic_arb_read_apid_map_v5(struct spmi_pmic_arb_bus *bus) { struct spmi_pmic_arb *pmic_arb = bus->pmic_arb; @@ -1222,17 +1255,7 @@ static int pmic_arb_read_apid_map_v5(struct spmi_pmic_arb_bus *bus) bus->last_apid = i; } - /* Dump the mapping table for debug purposes. */ - dev_dbg(&bus->spmic->dev, "PPID APID Write-EE IRQ-EE\n"); - for (ppid = 0; ppid < PMIC_ARB_MAX_PPID; ppid++) { - apid = bus->ppid_to_apid[ppid]; - if (apid & PMIC_ARB_APID_VALID) { - apid &= ~PMIC_ARB_APID_VALID; - apidd = &bus->apid_data[apid]; - dev_dbg(&bus->spmic->dev, "%#03X %3u %2u %2u\n", - ppid, apid, apidd->write_ee, apidd->irq_ee); - } - } + pmic_arb_dump_apid_map(bus); return 0; } @@ -1346,7 +1369,7 @@ static int pmic_arb_get_core_resources_v7(struct platform_device *pdev, } /* - * Only v7 supports 2 buses. Each bus will get a different apid count, read + * Arbiter v7 supports 2 buses. Each bus will get a different apid count, read * from different registers. */ static int pmic_arb_init_apid_v7(struct spmi_pmic_arb_bus *bus, int index) @@ -1424,6 +1447,185 @@ static int pmic_arb_offset_v7(struct spmi_pmic_arb_bus *bus, u8 sid, u16 addr, return offset; } +static int pmic_arb_get_core_resources_v8(struct platform_device *pdev, + void __iomem *core) +{ + struct spmi_pmic_arb *pmic_arb = platform_get_drvdata(pdev); + + pmic_arb->apid_map = devm_platform_ioremap_resource_byname(pdev, + "chnl_map"); + if (IS_ERR(pmic_arb->apid_map)) + return PTR_ERR(pmic_arb->apid_map); + + pmic_arb->core = core; + + pmic_arb->max_periphs = PMIC_ARB_MAX_PERIPHS_V8; + + return pmic_arb_get_obsrvr_chnls_v2(pdev); +} + +static int pmic_arb_get_bus_resources_v8(struct platform_device *pdev, + struct device_node *node, + struct spmi_pmic_arb_bus *bus) +{ + int index; + + index = of_property_match_string(node, "reg-names", "chnl_owner"); + if (index < 0) { + dev_err(&pdev->dev, "chnl_owner reg region missing\n"); + return -EINVAL; + } + + bus->apid_owner = devm_of_iomap(&pdev->dev, node, index, NULL); + + return PTR_ERR_OR_ZERO(bus->apid_owner); +} + +static int pmic_arb_read_apid_map_v8(struct spmi_pmic_arb_bus *bus) +{ + struct spmi_pmic_arb *pmic_arb = bus->pmic_arb; + struct apid_data *apidd; + struct apid_data *prev_apidd; + u16 i, apid, ppid, apid_max; + bool valid, is_irq_ee; + u32 regval, offset; + + /* + * In order to allow multiple EEs to write to a single PPID in arbiter + * version 8, there can be more than one APID mapped to each PPID. The + * owner field for each of these mappings specifies the EE which is + * allowed to write to the APID. The owner of the last (highest) APID + * which has the IRQ owner bit set for a given PPID will receive + * interrupts from the PPID. + * + * In arbiter version 8, the APID numbering space is divided between + * the SPMI buses according to this mapping: + * APID = 0 to N-1 --> bus 0 + * APID = N to N+M-1 --> bus 1 + * APID = N+M to N+M+P-1 --> bus 2 + * APID = N+M+P to N+M+P+Q-1 --> bus 3 + * where N = number of APIDs supported by bus 0 + * M = number of APIDs supported by bus 1 + * P = number of APIDs supported by bus 2 + * Q = number of APIDs supported by bus 3 + */ + apidd = &bus->apid_data[bus->base_apid]; + apid_max = bus->base_apid + bus->apid_count; + for (i = bus->base_apid; i < apid_max; i++, apidd++) { + offset = pmic_arb->ver_ops->apid_map_offset(i); + regval = readl_relaxed(pmic_arb->apid_map + offset); + if (!regval) + continue; + ppid = regval & PMIC_ARB_V8_PPID_MASK; + is_irq_ee = PMIC_ARB_V8_CHAN_IS_IRQ_OWNER(regval); + + regval = readl_relaxed(pmic_arb->ver_ops->apid_owner(bus, i)); + apidd->write_ee = SPMI_OWNERSHIP_PERIPH2OWNER(regval); + + apidd->irq_ee = is_irq_ee ? apidd->write_ee : INVALID_EE; + + valid = bus->ppid_to_apid[ppid] & PMIC_ARB_APID_VALID; + apid = bus->ppid_to_apid[ppid] & ~PMIC_ARB_APID_VALID; + prev_apidd = &bus->apid_data[apid]; + + if (!valid || apidd->write_ee == pmic_arb->ee) { + /* First PPID mapping or one for this EE */ + bus->ppid_to_apid[ppid] = i | PMIC_ARB_APID_VALID; + } else if (valid && is_irq_ee && + prev_apidd->write_ee == pmic_arb->ee) { + /* + * Duplicate PPID mapping after the one for this EE; + * override the irq owner + */ + prev_apidd->irq_ee = apidd->irq_ee; + } + + apidd->ppid = ppid; + bus->last_apid = i; + } + + pmic_arb_dump_apid_map(bus); + + return 0; +} + +static int pmic_arb_init_apid_v8(struct spmi_pmic_arb_bus *bus, int index) +{ + struct spmi_pmic_arb *pmic_arb = bus->pmic_arb; + int ret, i; + + if (index < 0 || index >= PMIC_ARB_MAX_BUSES_V8) { + dev_err(&bus->spmic->dev, "Unsupported bus index %d detected\n", + index); + return -EINVAL; + } + + bus->base_apid = 0; + bus->apid_count = 0; + for (i = 0; i <= index; i++) { + bus->base_apid += bus->apid_count; + bus->apid_count = readl_relaxed(pmic_arb->core + PMIC_ARB_FEATURES + i * 4) & + PMIC_ARB_FEATURES_V8_PERIPH_MASK; + } + + if (bus->apid_count == 0) { + dev_err(&bus->spmic->dev, "Bus %d not implemented\n", index); + return -EINVAL; + } else if (bus->base_apid + bus->apid_count > pmic_arb->max_periphs) { + dev_err(&bus->spmic->dev, "Unsupported max APID %d detected\n", + bus->base_apid + bus->apid_count); + return -EINVAL; + } + + ret = pmic_arb_init_apid_min_max(bus); + if (ret) + return ret; + + ret = pmic_arb_read_apid_map_v8(bus); + if (ret) { + dev_err(&bus->spmic->dev, "could not read APID->PPID mapping table, rc= %d\n", + ret); + return ret; + } + + return 0; +} + +/* + * v8 offset per ee and per apid for observer channels and per apid for + * read/write channels. + */ +static int pmic_arb_offset_v8(struct spmi_pmic_arb_bus *bus, u8 sid, u16 addr, + enum pmic_arb_channel ch_type) +{ + struct spmi_pmic_arb *pmic_arb = bus->pmic_arb; + u16 apid; + int rc; + u32 offset = 0; + u16 ppid = (sid << 8) | (addr >> 8); + + rc = pmic_arb->ver_ops->ppid_to_apid(bus, ppid); + if (rc < 0) + return rc; + + apid = rc; + switch (ch_type) { + case PMIC_ARB_CHANNEL_OBS: + offset = 0x40000 * pmic_arb->ee + 0x20 * apid; + break; + case PMIC_ARB_CHANNEL_RW: + if (bus->apid_data[apid].write_ee != pmic_arb->ee) { + dev_err(&bus->spmic->dev, "disallowed SPMI write to sid=%u, addr=0x%04X\n", + sid, addr); + return -EPERM; + } + offset = 0x200 * apid; + break; + } + + return offset; +} + static u32 pmic_arb_fmt_cmd_v1(u8 opc, u8 sid, u16 addr, u8 bc) { return (opc << 27) | ((sid & 0xf) << 20) | (addr << 4) | (bc & 0x7); @@ -1490,6 +1692,14 @@ pmic_arb_acc_enable_v7(struct spmi_pmic_arb_bus *bus, u16 n) return pmic_arb->wr_base + 0x100 + 0x1000 * n; } +static void __iomem * +pmic_arb_acc_enable_v8(struct spmi_pmic_arb_bus *bus, u16 n) +{ + struct spmi_pmic_arb *pmic_arb = bus->pmic_arb; + + return pmic_arb->wr_base + 0x100 + 0x200 * n; +} + static void __iomem * pmic_arb_irq_status_v1(struct spmi_pmic_arb_bus *bus, u16 n) { @@ -1516,6 +1726,14 @@ pmic_arb_irq_status_v7(struct spmi_pmic_arb_bus *bus, u16 n) return pmic_arb->wr_base + 0x104 + 0x1000 * n; } +static void __iomem * +pmic_arb_irq_status_v8(struct spmi_pmic_arb_bus *bus, u16 n) +{ + struct spmi_pmic_arb *pmic_arb = bus->pmic_arb; + + return pmic_arb->wr_base + 0x104 + 0x200 * n; +} + static void __iomem * pmic_arb_irq_clear_v1(struct spmi_pmic_arb_bus *bus, u16 n) { @@ -1542,6 +1760,14 @@ pmic_arb_irq_clear_v7(struct spmi_pmic_arb_bus *bus, u16 n) return pmic_arb->wr_base + 0x108 + 0x1000 * n; } +static void __iomem * +pmic_arb_irq_clear_v8(struct spmi_pmic_arb_bus *bus, u16 n) +{ + struct spmi_pmic_arb *pmic_arb = bus->pmic_arb; + + return pmic_arb->wr_base + 0x108 + 0x200 * n; +} + static u32 pmic_arb_apid_map_offset_v2(u16 n) { return 0x800 + 0x4 * n; @@ -1557,6 +1783,12 @@ static u32 pmic_arb_apid_map_offset_v7(u16 n) return 0x2000 + 0x4 * n; } +static u32 pmic_arb_apid_map_offset_v8(u16 n) +{ + /* For v8, offset is from "chnl_map" base register, not "core". */ + return 0x4 * n; +} + static void __iomem * pmic_arb_apid_owner_v2(struct spmi_pmic_arb_bus *bus, u16 n) { @@ -1564,7 +1796,7 @@ pmic_arb_apid_owner_v2(struct spmi_pmic_arb_bus *bus, u16 n) } /* - * For arbiter version 7, APID ownership table registers have independent + * For arbiter version 7 and 8, APID ownership table registers have independent * numbering space for each SPMI bus instance, so each is indexed starting from * 0. */ @@ -1574,6 +1806,12 @@ pmic_arb_apid_owner_v7(struct spmi_pmic_arb_bus *bus, u16 n) return bus->cnfg + 0x4 * (n - bus->base_apid); } +static void __iomem * +pmic_arb_apid_owner_v8(struct spmi_pmic_arb_bus *bus, u16 n) +{ + return bus->apid_owner + 0x4 * (n - bus->base_apid); +} + static const struct pmic_arb_ver_ops pmic_arb_v1 = { .ver_str = "v1", .get_core_resources = pmic_arb_get_core_resources_v1, @@ -1654,6 +1892,23 @@ static const struct pmic_arb_ver_ops pmic_arb_v7 = { .apid_owner = pmic_arb_apid_owner_v7, }; +static const struct pmic_arb_ver_ops pmic_arb_v8 = { + .ver_str = "v8", + .get_core_resources = pmic_arb_get_core_resources_v8, + .get_bus_resources = pmic_arb_get_bus_resources_v8, + .init_apid = pmic_arb_init_apid_v8, + .ppid_to_apid = pmic_arb_ppid_to_apid_v5, + .non_data_cmd = pmic_arb_non_data_cmd_v2, + .offset = pmic_arb_offset_v8, + .fmt_cmd = pmic_arb_fmt_cmd_v2, + .owner_acc_status = pmic_arb_owner_acc_status_v7, + .acc_enable = pmic_arb_acc_enable_v8, + .irq_status = pmic_arb_irq_status_v8, + .irq_clear = pmic_arb_irq_clear_v8, + .apid_map_offset = pmic_arb_apid_map_offset_v8, + .apid_owner = pmic_arb_apid_owner_v8, +}; + static const struct irq_domain_ops pmic_arb_irq_domain_ops = { .activate = qpnpint_irq_domain_activate, .alloc = qpnpint_irq_domain_alloc, @@ -1731,6 +1986,12 @@ static int spmi_pmic_arb_bus_init(struct platform_device *pdev, bus->spmic = ctrl; bus->id = bus_index; + if (pmic_arb->ver_ops->get_bus_resources) { + ret = pmic_arb->ver_ops->get_bus_resources(pdev, node, bus); + if (ret) + return ret; + } + ret = pmic_arb->ver_ops->init_apid(bus, bus_index); if (ret) return ret; @@ -1825,8 +2086,10 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev) pmic_arb->ver_ops = &pmic_arb_v3; else if (hw_ver < PMIC_ARB_VERSION_V7_MIN) pmic_arb->ver_ops = &pmic_arb_v5; - else + else if (hw_ver < PMIC_ARB_VERSION_V8_MIN) pmic_arb->ver_ops = &pmic_arb_v7; + else + pmic_arb->ver_ops = &pmic_arb_v8; err = pmic_arb->ver_ops->get_core_resources(pdev, core); if (err) @@ -1875,6 +2138,7 @@ static void spmi_pmic_arb_remove(struct platform_device *pdev) static const struct of_device_id spmi_pmic_arb_match_table[] = { { .compatible = "qcom,spmi-pmic-arb", }, { .compatible = "qcom,x1e80100-spmi-pmic-arb", }, + { .compatible = "qcom,glymur-spmi-pmic-arb", }, {}, }; MODULE_DEVICE_TABLE(of, spmi_pmic_arb_match_table); From a322705938efa75ae9b95883d630deb756c0ed91 Mon Sep 17 00:00:00 2001 From: Anjelique Melendez Date: Mon, 27 Oct 2025 14:22:49 -0700 Subject: [PATCH 0299/2333] FROMLIST: dt-bindings: soc: qcom: qcom,pmic-glink: Add Kaanapali and Glymur compatibles Document the Kaanapali and Glymur compatibles used to describe the PMIC glink on each platform. Kaanapali will have the same battery supply properties as sm8550 platforms so define qcom,sm8550-pmic-glink as fallback for Kaanapali. Glymur will have the same battery supply properties as x1e80100 platforms so define qcom,x1e80100-pmic-glink as fallback for Glymur. Signed-off-by: Anjelique Melendez Link: https://lore.kernel.org/r/20251027212250.3847537-2-anjelique.melendez@oss.qualcomm.com Signed-off-by: Rakesh Kota --- .../devicetree/bindings/soc/qcom/qcom,pmic-glink.yaml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,pmic-glink.yaml b/Documentation/devicetree/bindings/soc/qcom/qcom,pmic-glink.yaml index 7085bf88afaba..c570221094197 100644 --- a/Documentation/devicetree/bindings/soc/qcom/qcom,pmic-glink.yaml +++ b/Documentation/devicetree/bindings/soc/qcom/qcom,pmic-glink.yaml @@ -37,12 +37,19 @@ properties: - const: qcom,pmic-glink - items: - enum: + - qcom,kaanapali-pmic-glink - qcom,milos-pmic-glink - qcom,sm8650-pmic-glink - qcom,sm8750-pmic-glink - qcom,x1e80100-pmic-glink - const: qcom,sm8550-pmic-glink - const: qcom,pmic-glink + - items: + - enum: + - qcom,glymur-pmic-glink + - const: qcom,x1e80100-pmic-glink + - const: qcom,sm8550-pmic-glink + - const: qcom,pmic-glink '#address-cells': const: 1 From 30e0cc068de7db63565a371ba3c220ea4dc92785 Mon Sep 17 00:00:00 2001 From: Anjelique Melendez Date: Mon, 27 Oct 2025 14:22:50 -0700 Subject: [PATCH 0300/2333] FROMLIST: soc: qcom: pmic_glink: Add charger PDR service path and service name to client data Currently, the charger PD service path and service name are hard coded however these paths are not guaranteed to be the same between PMICs. For example, on Kaanapali and Glymur, Charger FW runs on SOCCP(another subsystem) which does not have any specific charger PDs defined. Define charger PDR service path and service name as client data so that each PMIC generation can properly define these paths. While at it, add the qcom,kaanapali-pmic-glink and qcom,glymur-pmic-glink compatible strings. Signed-off-by: Anjelique Melendez Link: https://lore.kernel.org/r/20251027212250.3847537-3-anjelique.melendez@oss.qualcomm.com Signed-off-by: Rakesh Kota --- drivers/soc/qcom/pmic_glink.c | 66 ++++++++++++++++++++++------------- 1 file changed, 42 insertions(+), 24 deletions(-) diff --git a/drivers/soc/qcom/pmic_glink.c b/drivers/soc/qcom/pmic_glink.c index c0a4be5df9267..aa5ba9a0285e5 100644 --- a/drivers/soc/qcom/pmic_glink.c +++ b/drivers/soc/qcom/pmic_glink.c @@ -23,13 +23,19 @@ enum { PMIC_GLINK_CLIENT_UCSI, }; +struct pmic_glink_data { + unsigned long client_mask; + char *charger_pdr_service_name; + char *charger_pdr_service_path; +}; + struct pmic_glink { struct device *dev; struct pdr_handle *pdr; struct rpmsg_endpoint *ept; - unsigned long client_mask; + const struct pmic_glink_data *data; struct auxiliary_device altmode_aux; struct auxiliary_device ps_aux; @@ -285,7 +291,6 @@ static struct rpmsg_driver pmic_glink_rpmsg_driver = { static int pmic_glink_probe(struct platform_device *pdev) { - const unsigned long *match_data; struct pdr_service *service; struct pmic_glink *pg; int ret; @@ -302,12 +307,10 @@ static int pmic_glink_probe(struct platform_device *pdev) spin_lock_init(&pg->client_lock); mutex_init(&pg->state_lock); - match_data = (unsigned long *)of_device_get_match_data(&pdev->dev); - if (!match_data) + pg->data = of_device_get_match_data(&pdev->dev); + if (!pg->data) return -EINVAL; - pg->client_mask = *match_data; - pg->pdr = pdr_handle_alloc(pmic_glink_pdr_callback, pg); if (IS_ERR(pg->pdr)) { ret = dev_err_probe(&pdev->dev, PTR_ERR(pg->pdr), @@ -315,27 +318,30 @@ static int pmic_glink_probe(struct platform_device *pdev) return ret; } - if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_UCSI)) { + if (pg->data->client_mask & BIT(PMIC_GLINK_CLIENT_UCSI)) { ret = pmic_glink_add_aux_device(pg, &pg->ucsi_aux, "ucsi"); if (ret) goto out_release_pdr_handle; } - if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_ALTMODE)) { + if (pg->data->client_mask & BIT(PMIC_GLINK_CLIENT_ALTMODE)) { ret = pmic_glink_add_aux_device(pg, &pg->altmode_aux, "altmode"); if (ret) goto out_release_ucsi_aux; } - if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_BATT)) { + if (pg->data->client_mask & BIT(PMIC_GLINK_CLIENT_BATT)) { ret = pmic_glink_add_aux_device(pg, &pg->ps_aux, "power-supply"); if (ret) goto out_release_altmode_aux; } - service = pdr_add_lookup(pg->pdr, "tms/servreg", "msm/adsp/charger_pd"); - if (IS_ERR(service)) { - ret = dev_err_probe(&pdev->dev, PTR_ERR(service), - "failed adding pdr lookup for charger_pd\n"); - goto out_release_aux_devices; + if (pg->data->charger_pdr_service_name && pg->data->charger_pdr_service_path) { + service = pdr_add_lookup(pg->pdr, pg->data->charger_pdr_service_name, + pg->data->charger_pdr_service_path); + if (IS_ERR(service)) { + ret = dev_err_probe(&pdev->dev, PTR_ERR(service), + "failed adding pdr lookup for charger_pd\n"); + goto out_release_aux_devices; + } } mutex_lock(&__pmic_glink_lock); @@ -345,13 +351,13 @@ static int pmic_glink_probe(struct platform_device *pdev) return 0; out_release_aux_devices: - if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_BATT)) + if (pg->data->client_mask & BIT(PMIC_GLINK_CLIENT_BATT)) pmic_glink_del_aux_device(pg, &pg->ps_aux); out_release_altmode_aux: - if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_ALTMODE)) + if (pg->data->client_mask & BIT(PMIC_GLINK_CLIENT_ALTMODE)) pmic_glink_del_aux_device(pg, &pg->altmode_aux); out_release_ucsi_aux: - if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_UCSI)) + if (pg->data->client_mask & BIT(PMIC_GLINK_CLIENT_UCSI)) pmic_glink_del_aux_device(pg, &pg->ucsi_aux); out_release_pdr_handle: pdr_handle_release(pg->pdr); @@ -365,23 +371,35 @@ static void pmic_glink_remove(struct platform_device *pdev) pdr_handle_release(pg->pdr); - if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_BATT)) + if (pg->data->client_mask & BIT(PMIC_GLINK_CLIENT_BATT)) pmic_glink_del_aux_device(pg, &pg->ps_aux); - if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_ALTMODE)) + if (pg->data->client_mask & BIT(PMIC_GLINK_CLIENT_ALTMODE)) pmic_glink_del_aux_device(pg, &pg->altmode_aux); - if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_UCSI)) + if (pg->data->client_mask & BIT(PMIC_GLINK_CLIENT_UCSI)) pmic_glink_del_aux_device(pg, &pg->ucsi_aux); guard(mutex)(&__pmic_glink_lock); __pmic_glink = NULL; } -static const unsigned long pmic_glink_sm8450_client_mask = BIT(PMIC_GLINK_CLIENT_BATT) | - BIT(PMIC_GLINK_CLIENT_ALTMODE) | - BIT(PMIC_GLINK_CLIENT_UCSI); +static const struct pmic_glink_data pmic_glink_sm8450_data = { + .client_mask = BIT(PMIC_GLINK_CLIENT_BATT) | + BIT(PMIC_GLINK_CLIENT_ALTMODE) | + BIT(PMIC_GLINK_CLIENT_UCSI), + .charger_pdr_service_name = "tms/servreg", + .charger_pdr_service_path = "msm/adsp/charger_pd", +}; + +static const struct pmic_glink_data pmic_glink_kaanapali_data = { + .client_mask = BIT(PMIC_GLINK_CLIENT_BATT) | + BIT(PMIC_GLINK_CLIENT_ALTMODE) | + BIT(PMIC_GLINK_CLIENT_UCSI), +}; static const struct of_device_id pmic_glink_of_match[] = { - { .compatible = "qcom,pmic-glink", .data = &pmic_glink_sm8450_client_mask }, + { .compatible = "qcom,glymur-pmic-glink", .data = &pmic_glink_kaanapali_data }, + { .compatible = "qcom,kaanapali-pmic-glink", .data = &pmic_glink_kaanapali_data }, + { .compatible = "qcom,pmic-glink", .data = &pmic_glink_sm8450_data }, {} }; MODULE_DEVICE_TABLE(of, pmic_glink_of_match); From 0903ea9aa92cbb5c5094c713b2d7527094d9451b Mon Sep 17 00:00:00 2001 From: Jishnu Prakash Date: Wed, 24 Sep 2025 22:31:02 +0530 Subject: [PATCH 0301/2333] FROMGIT: dt-bindings: pinctrl: qcom,pmic-gpio: Add GPIO bindings for Glymur PMICs Update the Qualcomm Technologies, Inc. PMIC GPIO binding documentation to include compatible strings for PMK8850, PMH0101, PMH0104, PMH0110 and PMCX0102 PMICs. Signed-off-by: Anjelique Melendez Signed-off-by: Jishnu Prakash Signed-off-by: Pankaj Patil Signed-off-by: Kamal Wadhwa Reviewed-by: Bartosz Golaszewski Acked-by: Rob Herring (Arm) Link: https://lore.kernel.org/r/20250924-glymur-pinctrl-driver-v2-1-11bef014a778@oss.qualcomm.com Signed-off-by: Kamal Wadhwa --- .../bindings/pinctrl/qcom,pmic-gpio.yaml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,pmic-gpio.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,pmic-gpio.yaml index 5e6dfcc3fe9b3..8ae4489637f3d 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,pmic-gpio.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,pmic-gpio.yaml @@ -59,7 +59,11 @@ properties: - qcom,pmc8180-gpio - qcom,pmc8180c-gpio - qcom,pmc8380-gpio + - qcom,pmcx0102-gpio - qcom,pmd8028-gpio + - qcom,pmh0101-gpio + - qcom,pmh0104-gpio + - qcom,pmh0110-gpio - qcom,pmi632-gpio - qcom,pmi8950-gpio - qcom,pmi8994-gpio @@ -68,6 +72,7 @@ properties: - qcom,pmiv0104-gpio - qcom,pmk8350-gpio - qcom,pmk8550-gpio + - qcom,pmk8850-gpio - qcom,pmm8155au-gpio - qcom,pmm8654au-gpio - qcom,pmp8074-gpio @@ -191,6 +196,8 @@ allOf: - qcom,pm8950-gpio - qcom,pm8953-gpio - qcom,pmi632-gpio + - qcom,pmh0104-gpio + - qcom,pmk8850-gpio then: properties: gpio-line-names: @@ -303,6 +310,8 @@ allOf: compatible: contains: enum: + - qcom,pmcx0102-gpio + - qcom,pmh0110-gpio - qcom,pmi8998-gpio then: properties: @@ -318,6 +327,7 @@ allOf: compatible: contains: enum: + - qcom,pmh0101-gpio - qcom,pmih0108-gpio then: properties: @@ -481,13 +491,18 @@ $defs: - gpio1-gpio22 for pm8994 - gpio1-gpio26 for pm8998 - gpio1-gpio22 for pma8084 + - gpio1-gpio14 for pmcx0102 - gpio1-gpio4 for pmd8028 + - gpio1-gpio18 for pmh0101 + - gpio1-gpio8 for pmh0104 + - gpio1-gpio14 for pmh0110 - gpio1-gpio8 for pmi632 - gpio1-gpio2 for pmi8950 - gpio1-gpio10 for pmi8994 - gpio1-gpio18 for pmih0108 - gpio1-gpio4 for pmk8350 - gpio1-gpio6 for pmk8550 + - gpio1-gpio8 for pmk8850 - gpio1-gpio10 for pmm8155au - gpio1-gpio12 for pmm8654au - gpio1-gpio12 for pmp8074 (holes on gpio1 and gpio12) From 06f8c0d26ca68aa7411d08e8364325a7557a5bed Mon Sep 17 00:00:00 2001 From: Anjelique Melendez Date: Wed, 24 Sep 2025 22:31:03 +0530 Subject: [PATCH 0302/2333] FROMGIT: pinctrl: qcom: spmi-gpio: Add PMCX0102, PMK8850 & PMH01XX PMICs support Add support for PMCX0102, PMH0101, PMH0104, PMH0110 and PMK8850 PMIC GPIOs with adding appropriate compatible strings. Signed-off-by: Anjelique Melendez Signed-off-by: Jishnu Prakash Signed-off-by: Kamal Wadhwa Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20250924-glymur-pinctrl-driver-v2-2-11bef014a778@oss.qualcomm.com Signed-off-by: Kamal Wadhwa --- drivers/pinctrl/qcom/pinctrl-spmi-gpio.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c index 485b68cc93f8e..c4f7d2d7a0176 100644 --- a/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c +++ b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c @@ -1239,7 +1239,11 @@ static const struct of_device_id pmic_gpio_of_match[] = { { .compatible = "qcom,pm8998-gpio", .data = (void *) 26 }, { .compatible = "qcom,pma8084-gpio", .data = (void *) 22 }, { .compatible = "qcom,pmc8380-gpio", .data = (void *) 10 }, + { .compatible = "qcom,pmcx0102-gpio", .data = (void *)14 }, { .compatible = "qcom,pmd8028-gpio", .data = (void *) 4 }, + { .compatible = "qcom,pmh0101-gpio", .data = (void *)18 }, + { .compatible = "qcom,pmh0104-gpio", .data = (void *)8 }, + { .compatible = "qcom,pmh0110-gpio", .data = (void *)14 }, { .compatible = "qcom,pmi632-gpio", .data = (void *) 8 }, { .compatible = "qcom,pmi8950-gpio", .data = (void *) 2 }, { .compatible = "qcom,pmi8994-gpio", .data = (void *) 10 }, @@ -1248,6 +1252,7 @@ static const struct of_device_id pmic_gpio_of_match[] = { { .compatible = "qcom,pmiv0104-gpio", .data = (void *) 10 }, { .compatible = "qcom,pmk8350-gpio", .data = (void *) 4 }, { .compatible = "qcom,pmk8550-gpio", .data = (void *) 6 }, + { .compatible = "qcom,pmk8850-gpio", .data = (void *)8 }, { .compatible = "qcom,pmm8155au-gpio", .data = (void *) 10 }, { .compatible = "qcom,pmm8654au-gpio", .data = (void *) 12 }, /* pmp8074 has 12 GPIOs with holes on 1 and 12 */ From 62c1622f81ba726b49b2ba43e68e45ed28b3820c Mon Sep 17 00:00:00 2001 From: Subbaraman Narayanamurthy Date: Wed, 24 Sep 2025 22:31:04 +0530 Subject: [PATCH 0303/2333] FROMGIT:pinctrl: qcom: spmi-gpio: add support for {LV_VIN2, MV_VIN3}_CLK subtypes Add support for SPMI PMIC GPIO subtypes GPIO_LV_VIN2_CLK and GPIO_MV_VIN3_CLK. Signed-off-by: Subbaraman Narayanamurthy Signed-off-by: Jishnu Prakash Signed-off-by: Kamal Wadhwa Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20250924-glymur-pinctrl-driver-v2-3-11bef014a778@oss.qualcomm.com Signed-off-by: Kamal Wadhwa --- drivers/pinctrl/qcom/pinctrl-spmi-gpio.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c index c4f7d2d7a0176..83f940fe30b26 100644 --- a/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c +++ b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c @@ -42,6 +42,8 @@ #define PMIC_GPIO_SUBTYPE_GPIO_MV 0x11 #define PMIC_GPIO_SUBTYPE_GPIO_LV_VIN2 0x12 #define PMIC_GPIO_SUBTYPE_GPIO_MV_VIN3 0x13 +#define PMIC_GPIO_SUBTYPE_GPIO_LV_VIN2_CLK 0x14 +#define PMIC_GPIO_SUBTYPE_GPIO_MV_VIN3_CLK 0x15 #define PMIC_MPP_REG_RT_STS 0x10 #define PMIC_MPP_REG_RT_STS_VAL_MASK 0x1 @@ -852,11 +854,13 @@ static int pmic_gpio_populate(struct pmic_gpio_state *state, pad->lv_mv_type = true; break; case PMIC_GPIO_SUBTYPE_GPIO_LV_VIN2: + case PMIC_GPIO_SUBTYPE_GPIO_LV_VIN2_CLK: pad->num_sources = 2; pad->have_buffer = true; pad->lv_mv_type = true; break; case PMIC_GPIO_SUBTYPE_GPIO_MV_VIN3: + case PMIC_GPIO_SUBTYPE_GPIO_MV_VIN3_CLK: pad->num_sources = 3; pad->have_buffer = true; pad->lv_mv_type = true; From 6fc2c3911517bf9bde33e5795251ae465ff2c4d9 Mon Sep 17 00:00:00 2001 From: Gaurav Kohli Date: Mon, 8 Dec 2025 17:15:58 +0530 Subject: [PATCH 0304/2333] FROMLIST: arm64: dts: qcom: monaco: Enable cpufreq cooling devices Add cooling-cells property to the CPU nodes to support cpufreq cooling devices. Signed-off-by: Gaurav Kohli Link: https://lore.kernel.org/r/20251208114558.2343462-1-gaurav.kohli@oss.qualcomm.com --- arch/arm64/boot/dts/qcom/qcs8300.dtsi | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/qcs8300.dtsi b/arch/arm64/boot/dts/qcom/qcs8300.dtsi index 89435fc5908f9..b176ea6529b5c 100644 --- a/arch/arm64/boot/dts/qcom/qcs8300.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs8300.dtsi @@ -56,6 +56,7 @@ power-domain-names = "psci"; capacity-dmips-mhz = <1946>; dynamic-power-coefficient = <472>; + #cooling-cells = <2>; qcom,freq-domain = <&cpufreq_hw 0>; operating-points-v2 = <&cpu0_opp_table>; interconnects = <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ACTIVE_ONLY @@ -80,6 +81,7 @@ power-domains = <&cpu_pd1>; power-domain-names = "psci"; capacity-dmips-mhz = <1946>; + #cooling-cells = <2>; dynamic-power-coefficient = <472>; qcom,freq-domain = <&cpufreq_hw 0>; operating-points-v2 = <&cpu0_opp_table>; @@ -105,6 +107,7 @@ power-domains = <&cpu_pd2>; power-domain-names = "psci"; capacity-dmips-mhz = <1946>; + #cooling-cells = <2>; dynamic-power-coefficient = <507>; qcom,freq-domain = <&cpufreq_hw 2>; operating-points-v2 = <&cpu2_opp_table>; @@ -130,6 +133,7 @@ power-domains = <&cpu_pd3>; power-domain-names = "psci"; capacity-dmips-mhz = <1946>; + #cooling-cells = <2>; dynamic-power-coefficient = <507>; qcom,freq-domain = <&cpufreq_hw 2>; operating-points-v2 = <&cpu2_opp_table>; @@ -155,6 +159,7 @@ power-domains = <&cpu_pd4>; power-domain-names = "psci"; capacity-dmips-mhz = <1024>; + #cooling-cells = <2>; dynamic-power-coefficient = <100>; qcom,freq-domain = <&cpufreq_hw 1>; operating-points-v2 = <&cpu4_opp_table>; @@ -180,6 +185,7 @@ power-domains = <&cpu_pd5>; power-domain-names = "psci"; capacity-dmips-mhz = <1024>; + #cooling-cells = <2>; dynamic-power-coefficient = <100>; qcom,freq-domain = <&cpufreq_hw 1>; operating-points-v2 = <&cpu4_opp_table>; @@ -205,6 +211,7 @@ power-domains = <&cpu_pd6>; power-domain-names = "psci"; capacity-dmips-mhz = <1024>; + #cooling-cells = <2>; dynamic-power-coefficient = <100>; qcom,freq-domain = <&cpufreq_hw 1>; operating-points-v2 = <&cpu4_opp_table>; @@ -230,6 +237,7 @@ power-domains = <&cpu_pd7>; power-domain-names = "psci"; capacity-dmips-mhz = <1024>; + #cooling-cells = <2>; dynamic-power-coefficient = <100>; qcom,freq-domain = <&cpufreq_hw 1>; operating-points-v2 = <&cpu4_opp_table>; From b2866eca5697568294f76b9d665bfc6224f38dcf Mon Sep 17 00:00:00 2001 From: Pankaj Patil Date: Thu, 25 Sep 2025 12:02:10 +0530 Subject: [PATCH 0305/2333] FROMLIST: arm64: defconfig: Enable Glymur configs for boot to shell The serial engine must be properly setup before kernel reaches "init",so UART driver and its dependencies needs to be built in. Enable its dependency clocks,interconnect and pinctrl as built-in to boot Glymur CRD board to UART console with full USB support. Link: https://lore.kernel.org/lkml/20250925-v3_glymur_introduction-v1-2-24b601bbecc0@oss.qualcomm.com/ Signed-off-by: Pankaj Patil Nacked-by: Dmitry Baryshkov Signed-off-by: Sibi Sankar --- arch/arm64/configs/defconfig | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig index 5ada00cf2b3ad..3ecc20978dc1d 100644 --- a/arch/arm64/configs/defconfig +++ b/arch/arm64/configs/defconfig @@ -617,6 +617,7 @@ CONFIG_PINCTRL_IMX8ULP=y CONFIG_PINCTRL_IMX91=y CONFIG_PINCTRL_IMX93=y CONFIG_PINCTRL_MSM=y +CONFIG_PINCTRL_GLYMUR=y CONFIG_PINCTRL_IPQ5018=y CONFIG_PINCTRL_IPQ5332=y CONFIG_PINCTRL_IPQ5424=y @@ -1369,6 +1370,9 @@ CONFIG_COMMON_CLK_MT8192_SCP_ADSP=y CONFIG_COMMON_CLK_MT8192_VDECSYS=y CONFIG_COMMON_CLK_MT8192_VENCSYS=y CONFIG_COMMON_CLK_QCOM=y +CONFIG_CLK_GLYMUR_DISPCC=y +CONFIG_CLK_GLYMUR_GCC=y +CONFIG_CLK_GLYMUR_TCSRCC=y CONFIG_CLK_KAANAPALI_GCC=y CONFIG_CLK_X1E80100_CAMCC=m CONFIG_CLK_X1E80100_DISPCC=m @@ -1648,6 +1652,7 @@ CONFIG_PHY_QCOM_QMP=m CONFIG_PHY_QCOM_QUSB2=m CONFIG_PHY_QCOM_EUSB2_REPEATER=m CONFIG_PHY_QCOM_M31_USB=m +CONFIG_PHY_QCOM_M31_EUSB=m CONFIG_PHY_QCOM_USB_HS=m CONFIG_PHY_QCOM_USB_SNPS_FEMTO_V2=m CONFIG_PHY_QCOM_USB_HS_28NM=m @@ -1726,6 +1731,7 @@ CONFIG_INTERCONNECT_IMX8MN=m CONFIG_INTERCONNECT_IMX8MQ=m CONFIG_INTERCONNECT_IMX8MP=y CONFIG_INTERCONNECT_QCOM=y +CONFIG_INTERCONNECT_QCOM_GLYMUR=y CONFIG_INTERCONNECT_QCOM_KAANAPALI=y CONFIG_INTERCONNECT_QCOM_MSM8916=m CONFIG_INTERCONNECT_QCOM_MSM8996=y From 490091cadcf97dfe02eb16988a6b8538194adb6a Mon Sep 17 00:00:00 2001 From: Jishnu Prakash Date: Wed, 24 Sep 2025 17:17:25 -0700 Subject: [PATCH 0306/2333] FROMLIST: arm64: dts: qcom: Add PMK8850 pmic dtsi Add base DTS file for PMK8850 including PON, GPIO, RTC and SDAM nodes. Link: https://lore.kernel.org/linux-arm-msm/20250924-knp-dts-v1-8-3fdbc4b9e1b1@oss.qualcomm.com/ Signed-off-by: Jishnu Prakash Signed-off-by: Kamal Wadhwa Signed-off-by: Jingyi Wang Reviewed-by: Konrad Dybcio Signed-off-by: Sibi Sankar --- arch/arm64/boot/dts/qcom/pmk8850.dtsi | 66 +++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/pmk8850.dtsi diff --git a/arch/arm64/boot/dts/qcom/pmk8850.dtsi b/arch/arm64/boot/dts/qcom/pmk8850.dtsi new file mode 100644 index 0000000000000..c19a98ca984b2 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/pmk8850.dtsi @@ -0,0 +1,66 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#include +#include +#include +#include + +&spmi_bus0 { + pmic@0 { + compatible = "qcom,pmk8850", "qcom,spmi-pmic"; + reg = <0x0 SPMI_USID>; + #address-cells = <1>; + #size-cells = <0>; + + pmk8850_pon: pon@1300 { + compatible = "qcom,pmk8350-pon"; + reg = <0x1300>, <0x800>; + reg-names = "hlos", "pbs"; + + pon_pwrkey: pwrkey { + compatible = "qcom,pmk8350-pwrkey"; + interrupts = <0x0 0x13 0x7 IRQ_TYPE_EDGE_BOTH>; + linux,code = ; + }; + + pon_resin: resin { + compatible = "qcom,pmk8350-resin"; + interrupts = <0x0 0x13 0x6 IRQ_TYPE_EDGE_BOTH>; + status = "disabled"; + }; + }; + + pmk8850_gpios: gpio@b800 { + compatible = "qcom,pmk8850-gpio", "qcom,spmi-gpio"; + reg = <0xb800>; + gpio-controller; + gpio-ranges = <&pmk8850_gpios 0 0 8>; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + pmk8850_rtc: rtc@6100 { + compatible = "qcom,pmk8350-rtc"; + reg = <0x6100>, <0x6200>; + reg-names = "rtc", "alarm"; + interrupts = <0x0 0x62 0x1 IRQ_TYPE_EDGE_RISING>; + }; + + pmk8850_sdam_2: nvram@7100 { + compatible = "qcom,spmi-sdam"; + reg = <0x7100>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x7100 0x100>; + + reboot_reason: reboot-reason@48 { + reg = <0x48 0x1>; + bits = <1 7>; + }; + }; + }; +}; From ba91a7a0fbdd6817755dce266fd764b5ae86cd99 Mon Sep 17 00:00:00 2001 From: Jishnu Prakash Date: Wed, 24 Sep 2025 17:17:26 -0700 Subject: [PATCH 0307/2333] FROMLIST: arm64: dts: qcom: Add PMH0101 pmic dtsi Add base DTS file for PMH0101 including temp-alarm, GPIO, PWM and flash nodes. Link: https://lore.kernel.org/linux-arm-msm/20250924-knp-dts-v1-9-3fdbc4b9e1b1@oss.qualcomm.com/ Signed-off-by: Jishnu Prakash Signed-off-by: Kamal Wadhwa Signed-off-by: Jingyi Wang Signed-off-by: Sibi Sankar --- arch/arm64/boot/dts/qcom/pmh0101.dtsi | 45 +++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/pmh0101.dtsi diff --git a/arch/arm64/boot/dts/qcom/pmh0101.dtsi b/arch/arm64/boot/dts/qcom/pmh0101.dtsi new file mode 100644 index 0000000000000..831c79305f7a8 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/pmh0101.dtsi @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#include +#include + +&spmi_bus0 { + pmic@1 { + compatible = "qcom,pmh0101", "qcom,spmi-pmic"; + reg = <0x1 SPMI_USID>; + #address-cells = <1>; + #size-cells = <0>; + + pmh0101_temp_alarm: temp-alarm@a00 { + compatible = "qcom,spmi-temp-alarm"; + reg = <0xa00>; + interrupts = <0x1 0xa 0x0 IRQ_TYPE_EDGE_BOTH>; + #thermal-sensor-cells = <0>; + }; + + pmh0101_gpios: gpio@8800 { + compatible = "qcom,pmh0101-gpio", "qcom,spmi-gpio"; + reg = <0x8800>; + gpio-controller; + gpio-ranges = <&pmh0101_gpios 0 0 18>; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + pmh0101_flash: led-controller@ee00 { + compatible = "qcom,pmh0101-flash-led", "qcom,spmi-flash-led"; + reg = <0xee00>; + status = "disabled"; + }; + + pmh0101_pwm: pwm { + compatible = "qcom,pmh0101-pwm", "qcom,pm8350c-pwm"; + #pwm-cells = <2>; + status = "disabled"; + }; + }; +}; From 487823fc52519a6f6c80b4e1b2eb1bf59cd577b8 Mon Sep 17 00:00:00 2001 From: Jishnu Prakash Date: Wed, 24 Sep 2025 17:17:27 -0700 Subject: [PATCH 0308/2333] FROMLIST: arm64: dts: qcom: Add PMH0104 pmic dtsi Add base DTS file for PMH0104 inclduing temp-alarm and GPIO nodes. Link: https://lore.kernel.org/linux-arm-msm/20250924-knp-dts-v1-10-3fdbc4b9e1b1@oss.qualcomm.com/ Signed-off-by: Jishnu Prakash Signed-off-by: Kamal Wadhwa Signed-off-by: Jingyi Wang Signed-off-by: Sibi Sankar --- arch/arm64/boot/dts/qcom/pmh0104.dtsi | 33 +++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/pmh0104.dtsi diff --git a/arch/arm64/boot/dts/qcom/pmh0104.dtsi b/arch/arm64/boot/dts/qcom/pmh0104.dtsi new file mode 100644 index 0000000000000..f5393fdebe957 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/pmh0104.dtsi @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#include +#include + +&spmi_bus1 { + pmh0104_j_e1: pmic@PMH0104_J_E1_SID { + compatible = "qcom,pmh0104", "qcom,spmi-pmic"; + reg = ; + #address-cells = <1>; + #size-cells = <0>; + + pmh0104_j_e1_temp_alarm: temp-alarm@a00 { + compatible = "qcom,spmi-temp-alarm"; + reg = <0xa00>; + interrupts = ; + #thermal-sensor-cells = <0>; + }; + + pmh0104_j_e1_gpios: gpio@8800 { + compatible = "qcom,pmh0104-gpio", "qcom,spmi-gpio"; + reg = <0x8800>; + gpio-controller; + gpio-ranges = <&pmh0104_j_e1_gpios 0 0 8>; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; +}; From 329675c51e800603298d0f93ea5a2c3de2a33479 Mon Sep 17 00:00:00 2001 From: Jishnu Prakash Date: Wed, 24 Sep 2025 17:17:28 -0700 Subject: [PATCH 0309/2333] FROMLIST: arm64: dts: qcom: Add PMH0110 pmic dtsi Add base DTS file for PMH0110 including temp-alarm and GPIO nodes. Link: https://lore.kernel.org/linux-arm-msm/20250924-knp-dts-v1-11-3fdbc4b9e1b1@oss.qualcomm.com/ Signed-off-by: Jishnu Prakash Signed-off-by: Kamal Wadhwa Signed-off-by: Jingyi Wang Signed-off-by: Sibi Sankar --- arch/arm64/boot/dts/qcom/pmh0110.dtsi | 109 ++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/pmh0110.dtsi diff --git a/arch/arm64/boot/dts/qcom/pmh0110.dtsi b/arch/arm64/boot/dts/qcom/pmh0110.dtsi new file mode 100644 index 0000000000000..b99c33cba8860 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/pmh0110.dtsi @@ -0,0 +1,109 @@ +// SPDX-License-Identifier: BSD-3-Clause-Clear +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#include +#include + +&spmi_bus0 { + pmh0110_d_e0: pmic@PMH0110_D_E0_SID { + compatible = "qcom,pmh0110", "qcom,spmi-pmic"; + reg = ; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + + pmh0110_d_e0_temp_alarm: temp-alarm@a00 { + compatible = "qcom,spmi-temp-alarm"; + reg = <0xa00>; + interrupts = ; + #thermal-sensor-cells = <0>; + }; + + pmh0110_d_e0_gpios: gpio@8800 { + compatible = "qcom,pmh0110-gpio", "qcom,spmi-gpio"; + reg = <0x8800>; + gpio-controller; + gpio-ranges = <&pmh0110_d_e0_gpios 0 0 14>; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; + + pmh0110_f_e0: pmic@PMH0110_F_E0_SID { + compatible = "qcom,pmh0110", "qcom,spmi-pmic"; + reg = ; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + + pmh0110_f_e0_temp_alarm: temp-alarm@a00 { + compatible = "qcom,spmi-temp-alarm"; + reg = <0xa00>; + interrupts = ; + #thermal-sensor-cells = <0>; + }; + + pmh0110_f_e0_gpios: gpio@8800 { + compatible = "qcom,pmh0110-gpio", "qcom,spmi-gpio"; + reg = <0x8800>; + gpio-controller; + gpio-ranges = <&pmh0110_f_e0_gpios 0 0 14>; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; + + pmh0110_g_e0: pmic@PMH0110_G_E0_SID { + compatible = "qcom,pmh0110", "qcom,spmi-pmic"; + reg = ; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + + pmh0110_g_e0_temp_alarm: temp-alarm@a00 { + compatible = "qcom,spmi-temp-alarm"; + reg = <0xa00>; + interrupts = ; + #thermal-sensor-cells = <0>; + }; + + pmh0110_g_e0_gpios: gpio@8800 { + compatible = "qcom,pmh0110-gpio", "qcom,spmi-gpio"; + reg = <0x8800>; + gpio-controller; + gpio-ranges = <&pmh0110_g_e0_gpios 0 0 14>; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; + + pmh0110_i_e0: pmic@PMH0110_I_E0_SID { + compatible = "qcom,pmh0110", "qcom,spmi-pmic"; + reg = ; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + + pmh0110_i_e0_temp_alarm: temp-alarm@a00 { + compatible = "qcom,spmi-temp-alarm"; + reg = <0xa00>; + interrupts = ; + #thermal-sensor-cells = <0>; + }; + + pmh0110_i_e0_gpios: gpio@8800 { + compatible = "qcom,pmh0110-gpio", "qcom,spmi-gpio"; + reg = <0x8800>; + gpio-controller; + gpio-ranges = <&pmh0110_i_e0_gpios 0 0 14>; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; +}; From 4c6c1a61db2dd451b84062dbaf5d93498c88c369 Mon Sep 17 00:00:00 2001 From: Pankaj Patil Date: Thu, 25 Sep 2025 12:02:09 +0530 Subject: [PATCH 0310/2333] FROMLIST: dt-bindings: arm: qcom: Document Glymur SoC and board Document Glymur SoC bindings and Compute Reference Device (CRD) board id Link: https://lore.kernel.org/lkml/20250925-v3_glymur_introduction-v1-1-24b601bbecc0@oss.qualcomm.com/ Signed-off-by: Pankaj Patil Signed-off-by: Sibi Sankar --- Documentation/devicetree/bindings/arm/qcom.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Documentation/devicetree/bindings/arm/qcom.yaml b/Documentation/devicetree/bindings/arm/qcom.yaml index 18b5ed044f9fc..b529a8e097a35 100644 --- a/Documentation/devicetree/bindings/arm/qcom.yaml +++ b/Documentation/devicetree/bindings/arm/qcom.yaml @@ -61,6 +61,11 @@ properties: - qcom,apq8084-sbc - const: qcom,apq8084 + - items: + - enum: + - qcom,glymur-crd + - const: qcom,glymur + - items: - enum: - microsoft,dempsey From 219a2f48fcbfb26d4003825bb1e8238cbbc56480 Mon Sep 17 00:00:00 2001 From: Pankaj Patil Date: Thu, 25 Sep 2025 12:02:11 +0530 Subject: [PATCH 0311/2333] FROMLIST: arm64: dts: qcom: Introduce Glymur base dtsi and CRD dts Introduce initial device tree support for Glymur - Qualcomm's next-generation compute SoC and it's associated Compute Reference Device (CRD) platform. The dt describes CPUs, CPU map, GCC and RPMHCC clock controllers, geni UART, interrupt controller, TLMM, reserved memory, interconnects, SMMU, firmware scm, watchdog, apps rsc, RPMHPD, SRAM, PSCI and pmu nodes. Link: https://lore.kernel.org/lkml/20250925-v3_glymur_introduction-v1-3-24b601bbecc0@oss.qualcomm.com/ Signed-off-by: Pankaj Patil Signed-off-by: Sibi Sankar --- arch/arm64/boot/dts/qcom/Makefile | 1 + arch/arm64/boot/dts/qcom/glymur-crd.dts | 25 + arch/arm64/boot/dts/qcom/glymur.dtsi | 1320 +++++++++++++++++++++++ 3 files changed, 1346 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/glymur-crd.dts create mode 100644 arch/arm64/boot/dts/qcom/glymur.dtsi diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile index 296688f7cb265..15f31a7d3ac4a 100644 --- a/arch/arm64/boot/dts/qcom/Makefile +++ b/arch/arm64/boot/dts/qcom/Makefile @@ -13,6 +13,7 @@ dtb-$(CONFIG_ARCH_QCOM) += apq8039-t2.dtb dtb-$(CONFIG_ARCH_QCOM) += apq8094-sony-xperia-kitakami-karin_windy.dtb dtb-$(CONFIG_ARCH_QCOM) += apq8096-db820c.dtb dtb-$(CONFIG_ARCH_QCOM) += apq8096-ifc6640.dtb +dtb-$(CONFIG_ARCH_QCOM) += glymur-crd.dtb dtb-$(CONFIG_ARCH_QCOM) += hamoa-iot-evk.dtb dtb-$(CONFIG_ARCH_QCOM) += ipq5018-rdp432-c2.dtb dtb-$(CONFIG_ARCH_QCOM) += ipq5018-tplink-archer-ax55-v1.dtb diff --git a/arch/arm64/boot/dts/qcom/glymur-crd.dts b/arch/arm64/boot/dts/qcom/glymur-crd.dts new file mode 100644 index 0000000000000..a1714ec849296 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/glymur-crd.dts @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +/dts-v1/; + +#include "glymur.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Glymur CRD"; + compatible = "qcom,glymur-crd", "qcom,glymur"; + + aliases { + serial0 = &uart21; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; +}; + +&tlmm { + gpio-reserved-ranges = <4 4>, <10 2>, <44 4>; /*Security SPI (TPM)*/ +}; diff --git a/arch/arm64/boot/dts/qcom/glymur.dtsi b/arch/arm64/boot/dts/qcom/glymur.dtsi new file mode 100644 index 0000000000000..f1c5a0cb48367 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/glymur.dtsi @@ -0,0 +1,1320 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/ { + interrupt-parent = <&intc>; + #address-cells = <2>; + #size-cells = <2>; + + chosen { }; + + clocks { + xo_board: xo-board { + compatible = "fixed-clock"; + clock-frequency = <38400000>; + #clock-cells = <0>; + }; + + sleep_clk: sleep-clk { + compatible = "fixed-clock"; + clock-frequency = <32000>; + #clock-cells = <0>; + }; + }; + + cpus { + #address-cells = <2>; + #size-cells = <0>; + + cpu0: cpu0@0 { + device_type = "cpu"; + compatible = "qcom,oryon"; + reg = <0x0 0x0>; + enable-method = "psci"; + next-level-cache = <&l2_0>; + + l2_0: l2-cache { + compatible = "cache"; + cache-level = <2>; + cache-unified; + }; + }; + + cpu1: cpu1@100 { + device_type = "cpu"; + compatible = "qcom,oryon"; + reg = <0x0 0x100>; + enable-method = "psci"; + next-level-cache = <&l2_0>; + }; + + cpu2: cpu2@200 { + device_type = "cpu"; + compatible = "qcom,oryon"; + reg = <0x0 0x200>; + enable-method = "psci"; + next-level-cache = <&l2_0>; + }; + + cpu3: cpu3@300 { + device_type = "cpu"; + compatible = "qcom,oryon"; + reg = <0x0 0x300>; + enable-method = "psci"; + next-level-cache = <&l2_0>; + }; + + cpu4: cpu4@400 { + device_type = "cpu"; + compatible = "qcom,oryon"; + reg = <0x0 0x400>; + enable-method = "psci"; + next-level-cache = <&l2_0>; + }; + + cpu5: cpu5@500 { + device_type = "cpu"; + compatible = "qcom,oryon"; + reg = <0x0 0x500>; + enable-method = "psci"; + next-level-cache = <&l2_0>; + }; + + cpu6: cpu6@10000 { + device_type = "cpu"; + compatible = "qcom,oryon"; + reg = <0x0 0x10000>; + enable-method = "psci"; + next-level-cache = <&l2_1>; + + l2_1: l2-cache { + compatible = "cache"; + cache-level = <2>; + cache-unified; + }; + }; + + cpu7: cpu7@10100 { + device_type = "cpu"; + compatible = "qcom,oryon"; + reg = <0x0 0x10100>; + enable-method = "psci"; + next-level-cache = <&l2_1>; + }; + + cpu8: cpu8@10200 { + device_type = "cpu"; + compatible = "qcom,oryon"; + reg = <0x0 0x10200>; + enable-method = "psci"; + next-level-cache = <&l2_1>; + }; + + cpu9: cpu9@10300 { + device_type = "cpu"; + compatible = "qcom,oryon"; + reg = <0x0 0x10300>; + enable-method = "psci"; + next-level-cache = <&l2_1>; + }; + + cpu10: cpu10@10400 { + device_type = "cpu"; + compatible = "qcom,oryon"; + reg = <0x0 0x10400>; + enable-method = "psci"; + next-level-cache = <&l2_1>; + }; + + cpu11: cpu11@10500 { + device_type = "cpu"; + compatible = "qcom,oryon"; + reg = <0x0 0x10500>; + enable-method = "psci"; + next-level-cache = <&l2_1>; + }; + + cpu12: cpu12@20000 { + device_type = "cpu"; + compatible = "qcom,oryon"; + reg = <0x0 0x20000>; + enable-method = "psci"; + next-level-cache = <&l2_2>; + + l2_2: l2-cache { + compatible = "cache"; + cache-level = <2>; + cache-unified; + }; + }; + + cpu13: cpu13@20100 { + device_type = "cpu"; + compatible = "qcom,oryon"; + reg = <0x0 0x20100>; + enable-method = "psci"; + next-level-cache = <&l2_2>; + }; + + cpu14: cpu14@20200 { + device_type = "cpu"; + compatible = "qcom,oryon"; + reg = <0x0 0x20200>; + enable-method = "psci"; + next-level-cache = <&l2_2>; + }; + + cpu15: cpu15@20300 { + device_type = "cpu"; + compatible = "qcom,oryon"; + reg = <0x0 0x20300>; + enable-method = "psci"; + next-level-cache = <&l2_2>; + }; + + cpu16: cpu16@20400 { + device_type = "cpu"; + compatible = "qcom,oryon"; + reg = <0x0 0x20400>; + enable-method = "psci"; + next-level-cache = <&l2_2>; + }; + + cpu17: cpu17@20500 { + device_type = "cpu"; + compatible = "qcom,oryon"; + reg = <0x0 0x20500>; + enable-method = "psci"; + next-level-cache = <&l2_2>; + }; + }; + + cpu-map { + cluster0 { + core0 { + cpu = <&cpu0>; + }; + core1 { + cpu = <&cpu1>; + }; + core2 { + cpu = <&cpu2>; + }; + core3 { + cpu = <&cpu3>; + }; + core4 { + cpu = <&cpu4>; + }; + core5 { + cpu = <&cpu5>; + }; + }; + + cluster1 { + core0 { + cpu = <&cpu6>; + }; + core1 { + cpu = <&cpu7>; + }; + core2 { + cpu = <&cpu8>; + }; + core3 { + cpu = <&cpu9>; + }; + core4 { + cpu = <&cpu10>; + }; + core5 { + cpu = <&cpu11>; + }; + }; + + cluster2 { + core0 { + cpu = <&cpu12>; + }; + core1 { + cpu = <&cpu13>; + }; + core2 { + cpu = <&cpu14>; + }; + core3 { + cpu = <&cpu15>; + }; + core4 { + cpu = <&cpu16>; + }; + core5 { + cpu = <&cpu17>; + }; + }; + }; + + firmware { + scm: scm { + compatible = "qcom,scm-glymur", "qcom,scm"; + qcom,dload-mode = <&tcsr 0x3000>; + interconnects = <&aggre2_noc MASTER_CRYPTO QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + }; + }; + + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + llcc_lpi_mem: llcc-lpi-region@80000000 { + reg = <0x0 0x80000000 0x0 0x600000>; + no-map; + }; + + llcc_lpi_reserved_mem: llcc-lpi-reserved-region@80900000 { + reg = <0x0 0x80900000 0x0 0x500000>; + no-map; + }; + + cpucp_log_mem: cpucp-log-region@80e00000 { + reg = <0x0 0x80e00000 0x0 0x40000>; + no-map; + }; + + cpucp_fw_mem: cpucp-fw-region@80e40000 { + reg = <0x0 0x80e40000 0x0 0x5c0000>; + no-map; + }; + + pdp_mem: pdp-region@81400000 { + reg = <0x0 0x81400000 0x0 0x100000>; + no-map; + }; + + tags_mem: tags-region@81500000 { + reg = <0x0 0x81500000 0x0 0x360000>; + no-map; + }; + + xbl_dtlog_mem: xbl-dtlog-region@81a00000 { + reg = <0x0 0x81a00000 0x0 0x40000>; + no-map; + }; + + xbl_ramdump_mem: xbl-ramdump-region@81a40000 { + reg = <0x0 0x81a40000 0x0 0x1c0000>; + no-map; + }; + + aop_image_mem: aop-image-region@81c00000 { + reg = <0x0 0x81c00000 0x0 0x60000>; + no-map; + }; + + aop_cmd_db_mem: aop-cmd-db-region@81c60000 { + compatible = "qcom,cmd-db"; + reg = <0x0 0x81c60000 0x0 0x20000>; + no-map; + }; + + aop_config_mem: aop-config-region@81c80000 { + reg = <0x0 0x81c80000 0x0 0x20000>; + no-map; + }; + + tme_crash_dump_mem: tme-crash-dump-region@81ca0000 { + reg = <0x0 0x81ca0000 0x0 0x40000>; + no-map; + }; + + tme_log_mem: tme-log-region@81ce0000 { + reg = <0x0 0x81ce0000 0x0 0x10000>; + no-map; + }; + + gpu_prr_mem: gpu-prr-region@81d00000 { + reg = <0x0 0x81d00000 0x0 0x10000>; + no-map; + }; + + tpm_control_mem: tpm-control-region@81d10000 { + reg = <0x0 0x81d10000 0x0 0x10000>; + no-map; + }; + + usb_ucsi_shared_mem: usb-ucsi-shared-region@81d20000 { + reg = <0x0 0x81d20000 0x0 0x10000>; + no-map; + }; + + pld_pep_mem: pld-pep-region@81d30000 { + reg = <0x0 0x81d30000 0x0 0x10000>; + no-map; + }; + + pld_gmu_mem: pld-gmu-region@81d40000 { + reg = <0x0 0x81d40000 0x0 0x10000>; + no-map; + }; + + pld_pdp_mem: pld-pdp-region@81d50000 { + reg = <0x0 0x81d50000 0x0 0x10000>; + no-map; + }; + + secdata_apss_mem: secdata-apss-region@81d60000 { + reg = <0x0 0x81d60000 0x0 0x10000>; + no-map; + }; + + qcskext_mem: qcskext-region@81d70000 { + reg = <0x0 0x81d70000 0x0 0x20000>; + no-map; + }; + + qup_fw_mem: qup-fw-region@81d90000 { + reg = <0x0 0x81d90000 0x0 0x18000>; + no-map; + }; + + softsku_mem: softsku-region@81da8000 { + reg = <0x0 0x81da8000 0x0 0x9000>; + no-map; + }; + + pdp_ns_shared_mem: pdp-ns-shared-region@81e00000 { + reg = <0x0 0x81e00000 0x0 0x200000>; + no-map; + }; + + acpi_ta_smem_mem: acpi-ta-smem-region@82000000 { + reg = <0x0 0x82000000 0x0 0x200000>; + no-map; + }; + + soccp_sdi_mem: soccp-sdi-region@823a0000 { + reg = <0x0 0x823a0000 0x0 0x40000>; + no-map; + }; + + lpm_violatordata_smem_mem: lpm-violatordata-smem-region@823e0000 { + reg = <0x0 0x823e0000 0x0 0x100000>; + no-map; + }; + + tz_stat_mem: tz-stat-region@82700000 { + reg = <0x0 0x82700000 0x0 0x100000>; + no-map; + }; + + no_reclaim_xbl_scratch_buffer2_mem: no-reclaim-xbl-scratch-buffer2-region@82800000 { + reg = <0x0 0x82800000 0x0 0x1c0000>; + no-map; + }; + + reclaimable_xbl_scratch_buffer_mem: reclaimable-xbl-scratch-buffer-region@829c0000 { + reg = <0x0 0x829c0000 0x0 0x1540000>; + no-map; + }; + + no_reclaim_xbl_scratch_buffer1_mem: no-reclaim-xbl-scratch-buffer1-region@83f00000 { + reg = <0x0 0x83f00000 0x0 0x100000>; + no-map; + }; + + ncc_mem: ncc-region@84000000 { + reg = <0x0 0x84000000 0x0 0x400000>; + no-map; + }; + + spu_secure_shared_memory_mem: spu-secure-shared-memory-region@84900000 { + reg = <0x0 0x84900000 0x0 0x100000>; + no-map; + }; + + adsp_rpc_remote_heap_mem: adsp-rpc-remote-heap-region@84a00000 { + reg = <0x0 0x84a00000 0x0 0x900000>; + no-map; + }; + + smmu_pt_mem: smmu-pt-region@85370000 { + reg = <0x0 0x85370000 0x0 0xa20000>; + no-map; + }; + + oobdaretag_mem: oobdaretag-region@86e10000 { + reg = <0x0 0x86e10000 0x0 0x360000>; + no-map; + }; + + oob_secure_mem: oob-secure-region@87170000 { + reg = <0x0 0x87170000 0x0 0xbc0000>; + no-map; + }; + + oobdtbqc_mem: oobdtbqc-region@87d30000 { + reg = <0x0 0x87d30000 0x0 0x20000>; + no-map; + }; + + oobdtboem_mem: oobdtboem-region@87d50000 { + reg = <0x0 0x87d50000 0x0 0x20000>; + no-map; + }; + + oob_nonsecure_mem: oob-nonsecure-region@87e00000 { + reg = <0x0 0x87e00000 0x0 0xc00000>; + no-map; + }; + + spss_region_mem: spss-region-region@88a00000 { + reg = <0x0 0x88a00000 0x0 0x400000>; + no-map; + }; + + soccp_boot_mem: soccp-boot-region@88e00000 { + reg = <0x0 0x88e00000 0x0 0x400000>; + no-map; + }; + + soccp_boot_dtb_mem: soccp-boot-dtb-region@89200000 { + reg = <0x0 0x89200000 0x0 0x20000>; + no-map; + }; + + soccpdtb_mem: soccpdtb-region@892e0000 { + reg = <0x0 0x892e0000 0x0 0x20000>; + no-map; + }; + + soccp_mem: soccp-region@89300000 { + reg = <0x0 0x89300000 0x0 0x400000>; + no-map; + }; + + cvp_mem: cvp-region@89700000 { + reg = <0x0 0x89700000 0x0 0x700000>; + no-map; + }; + + adspslpi_mem: adspslpi-region@89e00000 { + reg = <0x0 0x89e00000 0x0 0x3a00000>; + no-map; + }; + + q6_adsp_dtb_mem: q6-adsp-dtb-region@8d800000 { + reg = <0x0 0x8d800000 0x0 0x80000>; + no-map; + }; + + cdsp_mem: cdsp-region@8d900000 { + reg = <0x0 0x8d900000 0x0 0x4000000>; + no-map; + }; + + q6_cdsp_dtb_mem: q6-cdsp-dtb-region@91900000 { + reg = <0x0 0x91900000 0x0 0x80000>; + no-map; + }; + + gpu_microcode_mem: gpu-microcode-region@919fe000 { + reg = <0x0 0x919fe000 0x0 0x2000>; + no-map; + }; + + camera_mem: camera-region@91a00000 { + reg = <0x0 0x91a00000 0x0 0x800000>; + no-map; + }; + + av1_encoder_mem: av1-encoder-region@92200000 { + reg = <0x0 0x92200000 0x0 0x700000>; + no-map; + }; + + video_mem: video-region@92900000 { + reg = <0x0 0x92900000 0x0 0xc00000>; + no-map; + }; + + reserved_mem: reserved-region@93500000 { + reg = <0x0 0x93500000 0x0 0xa00000>; + no-map; + }; + + oob_cached_heap_standalone_mem: oob-cached-heap-standalone-region@a2000000 { + reg = <0x0 0xa2000000 0x0 0x5000000>; + no-map; + }; + + bert_mem: bert-region@d6f00000 { + reg = <0x0 0xd6f00000 0x0 0x100000>; + no-map; + }; + + hyp_ac_config_mem: hyp-ac-config-region@d7000000 { + reg = <0x0 0xd7000000 0x0 0x19000>; + no-map; + }; + + xbl_sc_mem: xbl-sc-region@d7019000 { + reg = <0x0 0xd7019000 0x0 0x60000>; + no-map; + }; + + xbl_sc_reserved_mem: xbl-sc-reserved-region@d7079000 { + reg = <0x0 0xd7079000 0x0 0x107000>; + no-map; + }; + + qtee_mem: qtee-region@d7180000 { + reg = <0x0 0xd7180000 0x0 0x680000>; + no-map; + }; + + ta_mem: ta-region@d7800000 { + reg = <0x0 0xd7800000 0x0 0x1c00000>; + no-map; + }; + + tags_mem_2: tags-region-2@d9400000 { + reg = <0x0 0xd9400000 0x0 0x9c0000>; + no-map; + }; + + display_buffer_mem: display-buffer-region@f9a20000 { + reg = <0x0 0xf9a20000 0x0 0x2300000>; + no-map; + }; + + oob_nc_mdm_standalone_mode_mem: oob-nc-mdm-standalone-mode-region@fc000000 { + reg = <0x0 0xfc000000 0x0 0x2000000>; + no-map; + }; + + oob_nc_wlan_standalone_mode_mem: oob-nc-wlan-standalone-mode-region@fe000000 { + reg = <0x0 0xfe000000 0x0 0xc00000>; + no-map; + }; + + oob_nc_glink_always_mem: oob-nc-glink-always-region@fec00000 { + reg = <0x0 0xfec00000 0x0 0x180000>; + no-map; + }; + + oob_nc_glink_assisted_mode_mem: oob-nc-glink-assisted-mode-region@fed80000 { + reg = <0x0 0xfed80000 0x0 0x140000>; + no-map; + }; + + oob_nc_mdm_assisted_mode_mem: oob-nc-mdm-assisted-mode-region@feec0000 { + reg = <0x0 0xfeec0000 0x0 0x10000>; + no-map; + }; + + oob_nc_wlan_assisted_mode_mem: oob-nc-wlan-assisted-mode-region@feed0000 { + reg = <0x0 0xfeed0000 0x0 0x10000>; + no-map; + }; + + smem_mem: smem-region@ffe00000 { + compatible = "qcom,smem"; + reg = <0x0 0xffe00000 0x0 0x200000>; + hwlocks = <&tcsr_mutex 3>; + no-map; + }; + + }; + + clk_virt: interconnect-0 { + compatible = "qcom,glymur-clk-virt"; + #interconnect-cells = <2>; + qcom,bcm-voters = <&apps_bcm_voter>; + }; + + mc_virt: interconnect-1 { + compatible = "qcom,glymur-mc-virt"; + #interconnect-cells = <2>; + qcom,bcm-voters = <&apps_bcm_voter>; + }; + + memory { + device_type = "memory"; + /* We expect the bootloader to fill in the size */ + reg = <0 0 0 0>; + }; + + pmu { + compatible = "arm,armv8-pmuv3"; + interrupts = ; + }; + + psci { + compatible = "arm,psci-1.0"; + method = "smc"; + }; + + soc: soc@0 { + #address-cells = <2>; + #size-cells = <2>; + compatible = "simple-bus"; + ranges = <0 0 0 0 0x10 0>; + dma-ranges = <0 0 0 0 0x10 0>; + + gcc: clock-controller@100000 { + compatible = "qcom,glymur-gcc"; + reg = <0 0x100000 0 0x1f9000>; + clocks = <&rpmhcc RPMH_CXO_CLK>, + <&rpmhcc RPMH_CXO_CLK_A>, + <&sleep_clk>, + <0>, + <0>, + <0>, + <0>, + <0>, + <0>, + <0>, + <0>, + <0>, + <0>, + <0>, + <0>, + <0>, + <0>, + <0>, + <0>, + <0>, + <0>; + #clock-cells = <1>; + #reset-cells = <1>; + #power-domain-cells = <1>; + }; + + qupv3_2: geniqup@8c0000 { + compatible = "qcom,geni-se-qup"; + reg = <0x0 0x008c0000 0x0 0x3000>; + clocks = <&gcc GCC_QUPV3_WRAP_2_M_AHB_CLK>, + <&gcc GCC_QUPV3_WRAP_2_S_AHB_CLK>; + clock-names = "m-ahb", + "s-ahb"; + iommus = <&apps_smmu 0xd63 0x0>; + #address-cells = <2>; + #size-cells = <2>; + ranges; + + uart21: serial@894000 { + compatible = "qcom,geni-debug-uart"; + reg = <0x0 0x00894000 0x0 0x4000>; + interrupts = ; + clocks = <&gcc GCC_QUPV3_WRAP2_S5_CLK>; + clock-names = "se"; + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&hsc_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config"; + pinctrl-0 = <&qup_uart21_default>; + pinctrl-names = "default"; + }; + }; + + cnoc_main: interconnect@1500000 { + compatible = "qcom,glymur-cnoc-main"; + reg = <0x0 0x01500000 0x0 0x17080>; + qcom,bcm-voters = <&apps_bcm_voter>; + #interconnect-cells = <2>; + }; + + config_noc: interconnect@1600000 { + compatible = "qcom,glymur-cnoc-cfg"; + reg = <0x0 0x01600000 0x0 0x6600>; + qcom,bcm-voters = <&apps_bcm_voter>; + #interconnect-cells = <2>; + }; + + system_noc: interconnect@1680000 { + compatible = "qcom,glymur-system-noc"; + reg = <0x0 0x01680000 0x0 0x1c080>; + qcom,bcm-voters = <&apps_bcm_voter>; + #interconnect-cells = <2>; + }; + + pcie_west_anoc: interconnect@16c0000 { + compatible = "qcom,glymur-pcie-west-anoc"; + reg = <0x0 0x016c0000 0x0 0xf580>; + qcom,bcm-voters = <&apps_bcm_voter>; + #interconnect-cells = <2>; + clocks = <&gcc GCC_AGGRE_NOC_PCIE_3A_WEST_SF_AXI_CLK>, + <&gcc GCC_AGGRE_NOC_PCIE_3B_WEST_SF_AXI_CLK>, + <&gcc GCC_AGGRE_NOC_PCIE_4_WEST_SF_AXI_CLK>, + <&gcc GCC_AGGRE_NOC_PCIE_6_WEST_SF_AXI_CLK>; + }; + + pcie_east_anoc: interconnect@16d0000 { + compatible = "qcom,glymur-pcie-east-anoc"; + reg = <0x0 0x016d0000 0x0 0xf300>; + qcom,bcm-voters = <&apps_bcm_voter>; + #interconnect-cells = <2>; + clocks = <&gcc GCC_AGGRE_NOC_PCIE_5_EAST_SF_AXI_CLK>; + }; + + aggre1_noc: interconnect@16e0000 { + compatible = "qcom,glymur-aggre1-noc"; + reg = <0x0 0x016e0000 0x0 0x14400>; + qcom,bcm-voters = <&apps_bcm_voter>; + #interconnect-cells = <2>; + }; + + aggre2_noc: interconnect@1720000 { + compatible = "qcom,glymur-aggre2-noc"; + reg = <0x0 0x01720000 0x0 0x14400>; + qcom,bcm-voters = <&apps_bcm_voter>; + #interconnect-cells = <2>; + clocks = <&gcc GCC_AGGRE_USB3_TERT_AXI_CLK>, + <&gcc GCC_AGGRE_USB4_2_AXI_CLK>, + <&gcc GCC_AGGRE_UFS_PHY_AXI_CLK>; + }; + + aggre3_noc: interconnect@1700000 { + compatible = "qcom,glymur-aggre3-noc"; + reg = <0x0 0x01700000 0x0 0x1d400>; + qcom,bcm-voters = <&apps_bcm_voter>; + #interconnect-cells = <2>; + }; + + aggre4_noc: interconnect@1740000 { + compatible = "qcom,glymur-aggre4-noc"; + reg = <0x0 0x01740000 0x0 0x14400>; + qcom,bcm-voters = <&apps_bcm_voter>; + #interconnect-cells = <2>; + clocks = <&gcc GCC_AGGRE_USB3_PRIM_AXI_CLK>, + <&gcc GCC_AGGRE_USB3_SEC_AXI_CLK>, + <&gcc GCC_AGGRE_USB4_0_AXI_CLK>, + <&gcc GCC_AGGRE_USB4_1_AXI_CLK>; + }; + + mmss_noc: interconnect@1780000 { + compatible = "qcom,glymur-mmss-noc"; + reg = <0x0 0x01780000 0x0 0x5b800>; + qcom,bcm-voters = <&apps_bcm_voter>; + #interconnect-cells = <2>; + }; + + pcie_east_slv_noc: interconnect@1900000 { + compatible = "qcom,glymur-pcie-east-slv-noc"; + reg = <0x0 0x01900000 0x0 0xe080>; + qcom,bcm-voters = <&apps_bcm_voter>; + #interconnect-cells = <2>; + }; + + pcie_west_slv_noc: interconnect@1920000 { + compatible = "qcom,glymur-pcie-west-slv-noc"; + reg = <0x0 0x01920000 0x0 0xf180>; + qcom,bcm-voters = <&apps_bcm_voter>; + #interconnect-cells = <2>; + }; + + tcsr_mutex: hwlock@1f40000 { + compatible = "qcom,tcsr-mutex"; + reg = <0x0 0x01f40000 0x0 0x20000>; + + #hwlock-cells = <1>; + }; + + tcsrcc: clock-controller@1fd5044 { + compatible = "qcom,glymur-tcsr"; + reg = <0x0 0x1fd5044 0x0 0x48>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + tcsr: syscon@1fd6000 { + compatible = "syscon"; + reg = <0x0 0x1fd6000 0x0 0x20000>; + }; + + hsc_noc: interconnect@2000000 { + compatible = "qcom,glymur-hscnoc"; + reg = <0x0 0x02000000 0x0 0x93a080>; + qcom,bcm-voters = <&apps_bcm_voter>; + #interconnect-cells = <2>; + }; + + lpass_lpiaon_noc: interconnect@7400000 { + compatible = "qcom,glymur-lpass-lpiaon-noc"; + reg = <0x0 0x07400000 0x0 0x19080>; + qcom,bcm-voters = <&apps_bcm_voter>; + #interconnect-cells = <2>; + }; + + lpass_lpicx_noc: interconnect@7420000 { + compatible = "qcom,glymur-lpass-lpicx-noc"; + reg = <0x0 0x07420000 0x0 0x44080>; + qcom,bcm-voters = <&apps_bcm_voter>; + #interconnect-cells = <2>; + }; + + lpass_ag_noc: interconnect@7e40000 { + compatible = "qcom,glymur-lpass-ag-noc"; + reg = <0x0 0x07e40000 0x0 0xe080>; + qcom,bcm-voters = <&apps_bcm_voter>; + #interconnect-cells = <2>; + }; + + pdc: interrupt-controller@b220000 { + compatible = "qcom,glymur-pdc", "qcom,pdc"; + reg = <0x0 0x0b220000 0x0 0x10000>; + qcom,pdc-ranges = <0 745 51>, + <51 527 47>, + <98 609 32>, + <130 717 12>, + <142 251 5>, + <147 796 16>, + <171 4104 36>; + #interrupt-cells = <2>; + interrupt-parent = <&intc>; + interrupt-controller; + }; + + sram@c30f000 { + compatible = "qcom,rpmh-stats"; + reg = <0x0 0x0c30f000 0x0 0x400>; + }; + + tlmm: pinctrl@f100000 { + compatible = "qcom,glymur-tlmm"; + reg = <0x0 0x0f100000 0x0 0xf00000>; + interrupts = ; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + gpio-ranges = <&tlmm 0 0 249>; + wakeup-parent = <&pdc>; + + qup_uart21_default: qup-uart21-default-state { + tx-pins { + pins = "gpio86"; + function = "qup2_se5"; + drive-strength = <2>; + bias-disable; + }; + + rx-pins { + pins = "gpio87"; + function = "qup2_se5"; + drive-strength = <2>; + bias-disable; + }; + }; + }; + + apps_smmu: iommu@15000000 { + compatible = "qcom,glymur-smmu-500", + "qcom,smmu-500", + "arm,mmu-500"; + reg = <0x0 0x15000000 0x0 0x100000>; + + #iommu-cells = <2>; + #global-interrupts = <1>; + + interrupts = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + + dma-coherent; + }; + + intc: interrupt-controller@17000000 { + compatible = "arm,gic-v3"; + reg = <0x0 0x17000000 0x0 0x10000>, + <0x0 0x17080000 0x0 0x480000>; + + interrupts = ; + + #interrupt-cells = <3>; + interrupt-controller; + + #redistributor-regions = <1>; + redistributor-stride = <0x0 0x40000>; + + #address-cells = <2>; + #size-cells = <2>; + ranges; + + gic_its: gic-its@17040000 { + compatible = "arm,gic-v3-its"; + reg = <0x0 0x17040000 0x0 0x40000>; + + msi-controller; + #msi-cells = <1>; + }; + }; + + watchdog@17600000 { + compatible = "qcom,kpss-wdt"; + reg = <0x0 0x17600000 0x0 0x1000>; + clocks = <&sleep_clk>; + interrupts = ; + }; + + timer@17810000 { + compatible = "arm,armv7-timer-mem"; + reg = <0x0 0x17810000 0x0 0x1000>; + #address-cells = <2>; + #size-cells = <2>; + ranges; + + frame@17811000 { + reg = <0x0 0x17811000 0x0 0x1000>, + <0x0 0x17812000 0x0 0x1000>; + + interrupts = , + ; + + frame-number = <0>; + }; + + frame@17813000 { + reg = <0x0 0x17813000 0x0 0x1000>; + + interrupts = ; + + frame-number = <1>; + + status = "disabled"; + }; + + frame@17815000 { + reg = <0x0 0x17815000 0x0 0x1000>; + + interrupts = ; + + frame-number = <2>; + + status = "disabled"; + }; + + frame@17817000 { + reg = <0x0 0x17817000 0x0 0x1000>; + + interrupts = ; + + frame-number = <3>; + + status = "disabled"; + }; + + frame@17819000 { + reg = <0x0 0x17819000 0x0 0x1000>; + + interrupts = ; + + frame-number = <4>; + + status = "disabled"; + }; + + frame@1781b000 { + reg = <0x0 0x1781b000 0x0 0x1000>; + + interrupts = ; + + frame-number = <5>; + + status = "disabled"; + }; + + frame@1781d000 { + reg = <0x0 0x1781d000 0x0 0x1000>; + + interrupts = ; + + frame-number = <6>; + + status = "disabled"; + }; + }; + + apps_rsc: rsc@18900000 { + compatible = "qcom,rpmh-rsc"; + label = "apps_rsc"; + reg = <0x0 0x18900000 0x0 0x10000>, + <0x0 0x18910000 0x0 0x10000>, + <0x0 0x18920000 0x0 0x10000>; + reg-names = "drv-0", + "drv-1", + "drv-2"; + interrupts = , + , + ; + qcom,tcs-offset = <0xd00>; + qcom,drv-id = <2>; + qcom,tcs-config = , + , + , + ; + + apps_bcm_voter: bcm-voter { + compatible = "qcom,bcm-voter"; + }; + + rpmhcc: clock-controller { + compatible = "qcom,glymur-rpmh-clk"; + + clocks = <&xo_board>; + clock-names = "xo"; + + #clock-cells = <1>; + }; + + rpmhpd: power-controller { + compatible = "qcom,glymur-rpmhpd"; + + operating-points-v2 = <&rpmhpd_opp_table>; + + #power-domain-cells = <1>; + + rpmhpd_opp_table: opp-table { + compatible = "operating-points-v2"; + + rpmhpd_opp_ret: opp-16 { + opp-level = ; + }; + + rpmhpd_opp_min_svs: opp-48 { + opp-level = ; + }; + + rpmhpd_opp_low_svs_d2: opp-52 { + opp-level = ; + }; + + rpmhpd_opp_low_svs_d1: opp-56 { + opp-level = ; + }; + + rpmhpd_opp_low_svs_d0: opp-60 { + opp-level = ; + }; + + rpmhpd_opp_low_svs: opp-64 { + opp-level = ; + }; + + rpmhpd_opp_low_svs_l1: opp-80 { + opp-level = ; + }; + + rpmhpd_opp_svs: opp-128 { + opp-level = ; + }; + + rpmhpd_opp_svs_l0: opp-144 { + opp-level = ; + }; + + rpmhpd_opp_svs_l1: opp-192 { + opp-level = ; + }; + + rpmhpd_opp_nom: opp-256 { + opp-level = ; + }; + + rpmhpd_opp_nom_l1: opp-320 { + opp-level = ; + }; + + rpmhpd_opp_nom_l2: opp-336 { + opp-level = ; + }; + + rpmhpd_opp_turbo: opp-384 { + opp-level = ; + }; + + rpmhpd_opp_turbo_l1: opp-416 { + opp-level = ; + }; + }; + }; + }; + + nsi_noc: interconnect@1d600000 { + compatible = "qcom,glymur-nsinoc"; + reg = <0x0 0x1d600000 0x0 0x14080>; + qcom,bcm-voters = <&apps_bcm_voter>; + #interconnect-cells = <2>; + }; + + oobm_ss_noc: interconnect@1f300000 { + compatible = "qcom,glymur-oobm-ss-noc"; + reg = <0x0 0x1f300000 0x0 0x49a00>; + qcom,bcm-voters = <&apps_bcm_voter>; + #interconnect-cells = <2>; + }; + + nsp_noc: interconnect@320c0000 { + compatible = "qcom,glymur-nsp-noc"; + reg = <0x0 0x320c0000 0x0 0x21280>; + qcom,bcm-voters = <&apps_bcm_voter>; + #interconnect-cells = <2>; + }; + + sram: sram@81e08000 { + compatible = "mmio-sram"; + reg = <0x0 0x81e08600 0x0 0x300>; + + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x0 0x81e08600 0x300>; + + cpu_scp_lpri0: scp-sram-section@0 { + compatible = "arm,scmi-shmem"; + reg = <0x0 0x180>; + }; + + cpu_scp_lpri1: scp-sram-section@180 { + compatible = "arm,scmi-shmem"; + reg = <0x180 0x180>; + }; + }; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupts = , + , + , + ; + }; +}; From e79e88df1c309a91203a203cfd0fd2a9d100943c Mon Sep 17 00:00:00 2001 From: Jyothi Kumar Seerapu Date: Thu, 25 Sep 2025 12:02:12 +0530 Subject: [PATCH 0312/2333] FROMLIST: arm64: dts: qcom: glymur: Add QUPv3 configuration for serial engines Add device tree support for QUPv3 serial engine protocols on Glymur. Glymur has 24 QUP serial engines across 3 QUP wrappers, each with support of GPI DMA engines. Link: https://lore.kernel.org/lkml/20250925-v3_glymur_introduction-v1-4-24b601bbecc0@oss.qualcomm.com/ Signed-off-by: Jyothi Kumar Seerapu Signed-off-by: Pankaj Patil Signed-off-by: Sibi Sankar --- arch/arm64/boot/dts/qcom/glymur-crd.dts | 43 + arch/arm64/boot/dts/qcom/glymur.dtsi | 3041 +++++++++++++++++++++-- 2 files changed, 2936 insertions(+), 148 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/glymur-crd.dts b/arch/arm64/boot/dts/qcom/glymur-crd.dts index a1714ec849296..4561c0b87b017 100644 --- a/arch/arm64/boot/dts/qcom/glymur-crd.dts +++ b/arch/arm64/boot/dts/qcom/glymur-crd.dts @@ -13,6 +13,49 @@ aliases { serial0 = &uart21; + serial1 = &uart14; + i2c0 = &i2c16; + i2c1 = &i2c17; + i2c2 = &i2c18; + i2c3 = &i2c19; + i2c4 = &i2c20; + i2c5 = &i2c22; + i2c6 = &i2c23; + i2c7 = &i2c8; + i2c8 = &i2c9; + i2c9 = &i2c10; + i2c10 = &i2c11; + i2c11 = &i2c12; + i2c12 = &i2c13; + i2c13 = &i2c15; + i2c14 = &i2c0; + i2c15 = &i2c1; + i2c16 = &i2c2; + i2c17 = &i2c3; + i2c18 = &i2c4; + i2c19 = &i2c5; + i2c20 = &i2c6; + spi0 = &spi16; + spi1 = &spi17; + spi2 = &spi18; + spi3 = &spi19; + spi4 = &spi20; + spi5 = &spi22; + spi6 = &spi23; + spi7 = &spi8; + spi8 = &spi9; + spi9 = &spi10; + spi10 = &spi11; + spi11 = &spi12; + spi12 = &spi13; + spi13 = &spi15; + spi14 = &spi0; + spi15 = &spi1; + spi16 = &spi2; + spi17 = &spi3; + spi18 = &spi4; + spi19 = &spi5; + spi20 = &spi6; }; chosen { diff --git a/arch/arm64/boot/dts/qcom/glymur.dtsi b/arch/arm64/boot/dts/qcom/glymur.dtsi index f1c5a0cb48367..8674465b22707 100644 --- a/arch/arm64/boot/dts/qcom/glymur.dtsi +++ b/arch/arm64/boot/dts/qcom/glymur.dtsi @@ -707,6 +707,32 @@ #power-domain-cells = <1>; }; + gpi_dma2: dma-controller@800000 { + compatible = "qcom,glymur-gpi-dma", "qcom,sm6350-gpi-dma"; + reg = <0 0x00800000 0 0x60000>; + interrupts = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + dma-channels = <16>; + dma-channel-mask = <0x3f>; + #dma-cells = <3>; + iommus = <&apps_smmu 0xd76 0x0>; + status = "ok"; + }; + qupv3_2: geniqup@8c0000 { compatible = "qcom,geni-se-qup"; reg = <0x0 0x008c0000 0x0 0x3000>; @@ -718,6 +744,339 @@ #address-cells = <2>; #size-cells = <2>; ranges; + status = "ok"; + + i2c16: i2c@880000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00880000 0 0x4000>; + interrupts = ; + clocks = <&gcc GCC_QUPV3_WRAP2_S0_CLK>; + clock-names = "se"; + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&hsc_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, + <&aggre3_noc MASTER_QUP_2 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + dmas = <&gpi_dma2 0 0 QCOM_GPI_I2C>, + <&gpi_dma2 1 0 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + pinctrl-0 = <&qup_i2c16_data_clk>; + pinctrl-names = "default"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + spi16: spi@880000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00880000 0 0x4000>; + interrupts = ; + clocks = <&gcc GCC_QUPV3_WRAP2_S0_CLK>; + clock-names = "se"; + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&hsc_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, + <&aggre3_noc MASTER_QUP_2 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + dmas = <&gpi_dma2 0 0 QCOM_GPI_SPI>, + <&gpi_dma2 1 0 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + pinctrl-0 = <&qup_spi16_data_clk>, <&qup_spi16_cs>; + pinctrl-names = "default"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c17: i2c@884000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00884000 0 0x4000>; + interrupts = ; + clocks = <&gcc GCC_QUPV3_WRAP2_S1_CLK>; + clock-names = "se"; + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&hsc_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, + <&aggre3_noc MASTER_QUP_2 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + dmas = <&gpi_dma2 0 1 QCOM_GPI_I2C>, + <&gpi_dma2 1 1 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + pinctrl-0 = <&qup_i2c17_data_clk>; + pinctrl-names = "default"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + spi17: spi@884000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00884000 0 0x4000>; + interrupts = ; + clocks = <&gcc GCC_QUPV3_WRAP2_S1_CLK>; + clock-names = "se"; + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&hsc_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, + <&aggre3_noc MASTER_QUP_2 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + dmas = <&gpi_dma2 0 1 QCOM_GPI_SPI>, + <&gpi_dma2 1 1 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + pinctrl-0 = <&qup_spi17_data_clk>, <&qup_spi17_cs>; + pinctrl-names = "default"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c18: i2c@888000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00888000 0 0x4000>; + interrupts = ; + clocks = <&gcc GCC_QUPV3_WRAP2_S2_CLK>; + clock-names = "se"; + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&hsc_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, + <&aggre3_noc MASTER_QUP_2 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + dmas = <&gpi_dma2 0 2 QCOM_GPI_I2C>, + <&gpi_dma2 1 2 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + pinctrl-0 = <&qup_i2c18_data_clk>; + pinctrl-names = "default"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + spi18: spi@888000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00888000 0 0x4000>; + interrupts = ; + clocks = <&gcc GCC_QUPV3_WRAP2_S2_CLK>; + clock-names = "se"; + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&hsc_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, + <&aggre3_noc MASTER_QUP_2 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + dmas = <&gpi_dma2 0 2 QCOM_GPI_SPI>, + <&gpi_dma2 1 2 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + pinctrl-0 = <&qup_spi18_data_clk>, <&qup_spi18_cs>; + pinctrl-names = "default"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c19: i2c@88c000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x0088c000 0 0x4000>; + interrupts = ; + clocks = <&gcc GCC_QUPV3_WRAP2_S3_CLK>; + clock-names = "se"; + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&hsc_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, + <&aggre3_noc MASTER_QUP_2 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + dmas = <&gpi_dma2 0 3 QCOM_GPI_I2C>, + <&gpi_dma2 1 3 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + pinctrl-0 = <&qup_i2c19_data_clk>; + pinctrl-names = "default"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + spi19: spi@88c000 { + compatible = "qcom,geni-spi"; + reg = <0 0x0088c000 0 0x4000>; + interrupts = ; + clocks = <&gcc GCC_QUPV3_WRAP2_S3_CLK>; + clock-names = "se"; + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&hsc_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, + <&aggre3_noc MASTER_QUP_2 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + dmas = <&gpi_dma2 0 3 QCOM_GPI_SPI>, + <&gpi_dma2 1 3 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + pinctrl-0 = <&qup_spi19_data_clk>, <&qup_spi19_cs>; + pinctrl-names = "default"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + uart19: serial@88c000 { + compatible = "qcom,geni-uart"; + reg = <0 0x0088c000 0 0x4000>; + interrupts = ; + clocks = <&gcc GCC_QUPV3_WRAP2_S3_CLK>; + clock-names = "se"; + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&hsc_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, + <&aggre3_noc MASTER_QUP_2 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + pinctrl-0 = <&qup_uart19_default>; + pinctrl-names = "default"; + status = "disabled"; + }; + + i2c20: i2c@890000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00890000 0 0x4000>; + interrupts = ; + clocks = <&gcc GCC_QUPV3_WRAP2_S4_CLK>; + clock-names = "se"; + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&hsc_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, + <&aggre3_noc MASTER_QUP_2 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + dmas = <&gpi_dma2 0 4 QCOM_GPI_I2C>, + <&gpi_dma2 1 4 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + pinctrl-0 = <&qup_i2c20_data_clk>; + pinctrl-names = "default"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + spi20: spi@890000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00890000 0 0x4000>; + interrupts = ; + clocks = <&gcc GCC_QUPV3_WRAP2_S4_CLK>; + clock-names = "se"; + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&hsc_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, + <&aggre3_noc MASTER_QUP_2 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + dmas = <&gpi_dma2 0 4 QCOM_GPI_SPI>, + <&gpi_dma2 1 4 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + pinctrl-0 = <&qup_spi20_data_clk>, <&qup_spi20_cs>; + pinctrl-names = "default"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c21: i2c@894000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00894000 0 0x4000>; + interrupts = ; + clocks = <&gcc GCC_QUPV3_WRAP2_S5_CLK>; + clock-names = "se"; + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&hsc_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, + <&aggre3_noc MASTER_QUP_2 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + dmas = <&gpi_dma2 0 5 QCOM_GPI_I2C>, + <&gpi_dma2 1 5 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + pinctrl-0 = <&qup_i2c21_data_clk>; + pinctrl-names = "default"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + spi21: spi@894000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00894000 0 0x4000>; + interrupts = ; + clocks = <&gcc GCC_QUPV3_WRAP2_S5_CLK>; + clock-names = "se"; + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&hsc_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, + <&aggre3_noc MASTER_QUP_2 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + dmas = <&gpi_dma2 0 5 QCOM_GPI_SPI>, + <&gpi_dma2 1 5 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + pinctrl-0 = <&qup_spi21_data_clk>, <&qup_spi21_cs>; + pinctrl-names = "default"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; uart21: serial@894000 { compatible = "qcom,geni-debug-uart"; @@ -734,181 +1093,2551 @@ pinctrl-0 = <&qup_uart21_default>; pinctrl-names = "default"; }; - }; - cnoc_main: interconnect@1500000 { - compatible = "qcom,glymur-cnoc-main"; - reg = <0x0 0x01500000 0x0 0x17080>; - qcom,bcm-voters = <&apps_bcm_voter>; - #interconnect-cells = <2>; - }; + i2c22: i2c@898000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00898000 0 0x4000>; + interrupts = ; + clocks = <&gcc GCC_QUPV3_WRAP2_S6_CLK>; + clock-names = "se"; + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&hsc_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, + <&aggre3_noc MASTER_QUP_2 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + dmas = <&gpi_dma2 0 6 QCOM_GPI_I2C>, + <&gpi_dma2 1 6 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + pinctrl-0 = <&qup_i2c22_data_clk>; + pinctrl-names = "default"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; - config_noc: interconnect@1600000 { - compatible = "qcom,glymur-cnoc-cfg"; - reg = <0x0 0x01600000 0x0 0x6600>; - qcom,bcm-voters = <&apps_bcm_voter>; - #interconnect-cells = <2>; - }; + spi22: spi@898000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00898000 0 0x4000>; + interrupts = ; + clocks = <&gcc GCC_QUPV3_WRAP2_S6_CLK>; + clock-names = "se"; + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&hsc_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, + <&aggre3_noc MASTER_QUP_2 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + dmas = <&gpi_dma2 0 6 QCOM_GPI_SPI>, + <&gpi_dma2 1 6 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + pinctrl-0 = <&qup_spi22_data_clk>, <&qup_spi22_cs>; + pinctrl-names = "default"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; - system_noc: interconnect@1680000 { - compatible = "qcom,glymur-system-noc"; - reg = <0x0 0x01680000 0x0 0x1c080>; - qcom,bcm-voters = <&apps_bcm_voter>; - #interconnect-cells = <2>; - }; + uart22: serial@898000 { + compatible = "qcom,geni-uart"; + reg = <0 0x00898000 0 0x4000>; + interrupts = ; + clocks = <&gcc GCC_QUPV3_WRAP2_S6_CLK>; + clock-names = "se"; + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&hsc_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config"; + pinctrl-0 = <&qup_uart22_default>; + pinctrl-names = "default"; + status = "disabled"; + }; - pcie_west_anoc: interconnect@16c0000 { - compatible = "qcom,glymur-pcie-west-anoc"; - reg = <0x0 0x016c0000 0x0 0xf580>; - qcom,bcm-voters = <&apps_bcm_voter>; - #interconnect-cells = <2>; - clocks = <&gcc GCC_AGGRE_NOC_PCIE_3A_WEST_SF_AXI_CLK>, - <&gcc GCC_AGGRE_NOC_PCIE_3B_WEST_SF_AXI_CLK>, - <&gcc GCC_AGGRE_NOC_PCIE_4_WEST_SF_AXI_CLK>, - <&gcc GCC_AGGRE_NOC_PCIE_6_WEST_SF_AXI_CLK>; - }; + i2c23: i2c@89c000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x0089c000 0 0x4000>; + interrupts = ; + clocks = <&gcc GCC_QUPV3_WRAP2_S7_CLK>; + clock-names = "se"; + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&hsc_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, + <&aggre3_noc MASTER_QUP_2 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + dmas = <&gpi_dma2 0 7 QCOM_GPI_I2C>, + <&gpi_dma2 1 7 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + pinctrl-0 = <&qup_i2c23_data_clk>; + pinctrl-names = "default"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; - pcie_east_anoc: interconnect@16d0000 { - compatible = "qcom,glymur-pcie-east-anoc"; - reg = <0x0 0x016d0000 0x0 0xf300>; - qcom,bcm-voters = <&apps_bcm_voter>; - #interconnect-cells = <2>; - clocks = <&gcc GCC_AGGRE_NOC_PCIE_5_EAST_SF_AXI_CLK>; + spi23: spi@89c000 { + compatible = "qcom,geni-spi"; + reg = <0 0x0089c000 0 0x4000>; + interrupts = ; + clocks = <&gcc GCC_QUPV3_WRAP2_S7_CLK>; + clock-names = "se"; + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&hsc_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, + <&aggre3_noc MASTER_QUP_2 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + dmas = <&gpi_dma2 0 7 QCOM_GPI_SPI>, + <&gpi_dma2 1 7 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + pinctrl-0 = <&qup_spi23_data_clk>, <&qup_spi23_cs>; + pinctrl-names = "default"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; }; - aggre1_noc: interconnect@16e0000 { - compatible = "qcom,glymur-aggre1-noc"; - reg = <0x0 0x016e0000 0x0 0x14400>; - qcom,bcm-voters = <&apps_bcm_voter>; - #interconnect-cells = <2>; - }; + gpi_dma1: dma-controller@a00000 { + compatible = "qcom,glymur-gpi-dma", "qcom,sm6350-gpi-dma"; + reg = <0 0x00a00000 0 0x60000>; + interrupts = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + dma-channels = <16>; + dma-channel-mask = <0x3f>; + #dma-cells = <3>; + iommus = <&apps_smmu 0xcb6 0x0>; + status = "okay"; + }; + + qupv3_1: geniqup@ac0000 { + compatible = "qcom,geni-se-qup"; + reg = <0 0x00ac0000 0 0x3000>; + clocks = <&gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, + <&gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + clock-names = "m-ahb", + "s-ahb"; + iommus = <&apps_smmu 0xca3 0x0>; + #address-cells = <2>; + #size-cells = <2>; + ranges; + status = "ok"; - aggre2_noc: interconnect@1720000 { - compatible = "qcom,glymur-aggre2-noc"; - reg = <0x0 0x01720000 0x0 0x14400>; - qcom,bcm-voters = <&apps_bcm_voter>; - #interconnect-cells = <2>; - clocks = <&gcc GCC_AGGRE_USB3_TERT_AXI_CLK>, - <&gcc GCC_AGGRE_USB4_2_AXI_CLK>, - <&gcc GCC_AGGRE_UFS_PHY_AXI_CLK>; - }; + i2c8: i2c@a80000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00a80000 0 0x4000>; + interrupts = ; + clocks = <&gcc GCC_QUPV3_WRAP1_S0_CLK>; + clock-names = "se"; + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>, + <&hsc_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, + <&aggre3_noc MASTER_QUP_1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + dmas = <&gpi_dma1 0 0 QCOM_GPI_I2C>, + <&gpi_dma1 1 0 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + pinctrl-0 = <&qup_i2c8_data_clk>; + pinctrl-names = "default"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; - aggre3_noc: interconnect@1700000 { - compatible = "qcom,glymur-aggre3-noc"; - reg = <0x0 0x01700000 0x0 0x1d400>; - qcom,bcm-voters = <&apps_bcm_voter>; - #interconnect-cells = <2>; - }; + spi8: spi@a80000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00a80000 0 0x4000>; + interrupts = ; + clocks = <&gcc GCC_QUPV3_WRAP1_S0_CLK>; + clock-names = "se"; + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>, + <&hsc_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, + <&aggre3_noc MASTER_QUP_1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + dmas = <&gpi_dma1 0 0 QCOM_GPI_SPI>, + <&gpi_dma1 1 0 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + pinctrl-0 = <&qup_spi8_data_clk>, <&qup_spi8_cs>; + pinctrl-names = "default"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; - aggre4_noc: interconnect@1740000 { - compatible = "qcom,glymur-aggre4-noc"; - reg = <0x0 0x01740000 0x0 0x14400>; - qcom,bcm-voters = <&apps_bcm_voter>; - #interconnect-cells = <2>; - clocks = <&gcc GCC_AGGRE_USB3_PRIM_AXI_CLK>, - <&gcc GCC_AGGRE_USB3_SEC_AXI_CLK>, - <&gcc GCC_AGGRE_USB4_0_AXI_CLK>, - <&gcc GCC_AGGRE_USB4_1_AXI_CLK>; - }; + i2c9: i2c@a84000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00a84000 0 0x4000>; + interrupts = ; + clocks = <&gcc GCC_QUPV3_WRAP1_S1_CLK>; + clock-names = "se"; + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>, + <&hsc_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, + <&aggre3_noc MASTER_QUP_1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + dmas = <&gpi_dma1 0 1 QCOM_GPI_I2C>, + <&gpi_dma1 1 1 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + pinctrl-0 = <&qup_i2c9_data_clk>; + pinctrl-names = "default"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; - mmss_noc: interconnect@1780000 { - compatible = "qcom,glymur-mmss-noc"; - reg = <0x0 0x01780000 0x0 0x5b800>; - qcom,bcm-voters = <&apps_bcm_voter>; - #interconnect-cells = <2>; - }; + spi9: spi@a84000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00a84000 0 0x4000>; + interrupts = ; + clocks = <&gcc GCC_QUPV3_WRAP1_S1_CLK>; + clock-names = "se"; + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>, + <&hsc_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, + <&aggre3_noc MASTER_QUP_1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + dmas = <&gpi_dma1 0 1 QCOM_GPI_SPI>, + <&gpi_dma1 1 1 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + pinctrl-0 = <&qup_spi9_data_clk>, <&qup_spi9_cs>; + pinctrl-names = "default"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; - pcie_east_slv_noc: interconnect@1900000 { - compatible = "qcom,glymur-pcie-east-slv-noc"; - reg = <0x0 0x01900000 0x0 0xe080>; + i2c10: i2c@a88000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00a88000 0 0x4000>; + interrupts = ; + clocks = <&gcc GCC_QUPV3_WRAP1_S2_CLK>; + clock-names = "se"; + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>, + <&hsc_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, + <&aggre3_noc MASTER_QUP_1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + dmas = <&gpi_dma1 0 2 QCOM_GPI_I2C>, + <&gpi_dma1 1 2 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + pinctrl-0 = <&qup_i2c10_data_clk>; + pinctrl-names = "default"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + spi10: spi@a88000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00a88000 0 0x4000>; + interrupts = ; + clocks = <&gcc GCC_QUPV3_WRAP1_S2_CLK>; + clock-names = "se"; + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>, + <&hsc_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, + <&aggre3_noc MASTER_QUP_1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + dmas = <&gpi_dma1 0 2 QCOM_GPI_SPI>, + <&gpi_dma1 1 2 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + pinctrl-0 = <&qup_spi10_data_clk>, <&qup_spi10_cs>; + pinctrl-names = "default"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c11: i2c@a8c000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00a8c000 0 0x4000>; + interrupts = ; + clocks = <&gcc GCC_QUPV3_WRAP1_S3_CLK>; + clock-names = "se"; + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>, + <&hsc_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, + <&aggre3_noc MASTER_QUP_1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + dmas = <&gpi_dma1 0 3 QCOM_GPI_I2C>, + <&gpi_dma1 1 3 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + pinctrl-0 = <&qup_i2c11_data_clk>; + pinctrl-names = "default"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + spi11: spi@a8c000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00a8c000 0 0x4000>; + interrupts = ; + clocks = <&gcc GCC_QUPV3_WRAP1_S3_CLK>; + clock-names = "se"; + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>, + <&hsc_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, + <&aggre3_noc MASTER_QUP_1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + dmas = <&gpi_dma1 0 3 QCOM_GPI_SPI>, + <&gpi_dma1 1 3 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + pinctrl-0 = <&qup_spi11_data_clk>, <&qup_spi11_cs>; + pinctrl-names = "default"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c12: i2c@a90000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00a90000 0 0x4000>; + interrupts = ; + clocks = <&gcc GCC_QUPV3_WRAP1_S4_CLK>; + clock-names = "se"; + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>, + <&hsc_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, + <&aggre3_noc MASTER_QUP_1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + dmas = <&gpi_dma1 0 4 QCOM_GPI_I2C>, + <&gpi_dma1 1 4 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + pinctrl-0 = <&qup_i2c12_data_clk>; + pinctrl-names = "default"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + spi12: spi@a90000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00a90000 0 0x4000>; + interrupts = ; + clocks = <&gcc GCC_QUPV3_WRAP1_S4_CLK>; + clock-names = "se"; + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>, + <&hsc_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, + <&aggre3_noc MASTER_QUP_1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + dmas = <&gpi_dma1 0 4 QCOM_GPI_SPI>, + <&gpi_dma1 1 4 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + pinctrl-0 = <&qup_spi12_data_clk>, <&qup_spi12_cs>; + pinctrl-names = "default"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c13: i2c@a94000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00a94000 0 0x4000>; + interrupts = ; + clocks = <&gcc GCC_QUPV3_WRAP1_S5_CLK>; + clock-names = "se"; + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>, + <&hsc_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, + <&aggre3_noc MASTER_QUP_1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + dmas = <&gpi_dma1 0 5 QCOM_GPI_I2C>, + <&gpi_dma1 1 5 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + pinctrl-0 = <&qup_i2c13_data_clk>; + pinctrl-names = "default"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + spi13: spi@a94000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00a94000 0 0x4000>; + interrupts = ; + clocks = <&gcc GCC_QUPV3_WRAP1_S5_CLK>; + clock-names = "se"; + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>, + <&hsc_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, + <&aggre3_noc MASTER_QUP_1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + dmas = <&gpi_dma1 0 5 QCOM_GPI_SPI>, + <&gpi_dma1 1 5 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + pinctrl-0 = <&qup_spi13_data_clk>, <&qup_spi13_cs>; + pinctrl-names = "default"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c14: i2c@a98000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00a98000 0 0x4000>; + interrupts = ; + clocks = <&gcc GCC_QUPV3_WRAP1_S6_CLK>; + clock-names = "se"; + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>, + <&hsc_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, + <&aggre3_noc MASTER_QUP_1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + dmas = <&gpi_dma1 0 6 QCOM_GPI_I2C>, + <&gpi_dma1 1 6 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + pinctrl-0 = <&qup_i2c14_data_clk>; + pinctrl-names = "default"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + spi14: spi@a98000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00a98000 0 0x4000>; + interrupts = ; + clocks = <&gcc GCC_QUPV3_WRAP1_S6_CLK>; + clock-names = "se"; + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>, + <&hsc_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, + <&aggre3_noc MASTER_QUP_1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + dmas = <&gpi_dma1 0 6 QCOM_GPI_SPI>, + <&gpi_dma1 1 6 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + pinctrl-0 = <&qup_spi14_data_clk>, <&qup_spi14_cs>; + pinctrl-names = "default"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + uart14: serial@a98000 { + compatible = "qcom,geni-uart"; + reg = <0 0x00a98000 0 0x4000>; + interrupts = ; + clocks = <&gcc GCC_QUPV3_WRAP1_S6_CLK>; + clock-names = "se"; + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>, + <&hsc_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, + <&aggre3_noc MASTER_QUP_1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + pinctrl-0 = <&qup_uart14_default>; + pinctrl-names = "default"; + status = "disabled"; + }; + + i2c15: i2c@a9c000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00a9c000 0 0x4000>; + interrupts = ; + clocks = <&gcc GCC_QUPV3_WRAP1_S7_CLK>; + clock-names = "se"; + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>, + <&hsc_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, + <&aggre3_noc MASTER_QUP_1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + dmas = <&gpi_dma1 0 7 QCOM_GPI_I2C>, + <&gpi_dma1 1 7 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + pinctrl-0 = <&qup_i2c15_data_clk>; + pinctrl-names = "default"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + spi15: spi@a9c000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00a9c000 0 0x4000>; + interrupts = ; + clocks = <&gcc GCC_QUPV3_WRAP1_S7_CLK>; + clock-names = "se"; + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>, + <&hsc_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, + <&aggre3_noc MASTER_QUP_1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + dmas = <&gpi_dma1 0 7 QCOM_GPI_SPI>, + <&gpi_dma1 1 7 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + pinctrl-0 = <&qup_spi15_data_clk>, <&qup_spi15_cs>; + pinctrl-names = "default"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + }; + + gpi_dma0: dma-controller@b00000 { + compatible = "qcom,glymur-gpi-dma", "qcom,sm6350-gpi-dma"; + reg = <0 0x00b00000 0 0x60000>; + interrupts = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + dma-channels = <16>; + dma-channel-mask = <0x3f>; + #dma-cells = <3>; + iommus = <&apps_smmu 0xd36 0x0>; + status = "ok"; + }; + + qupv3_0: geniqup@bc0000 { + compatible = "qcom,geni-se-qup"; + reg = <0 0x00bc0000 0 0x3000>; + clocks = <&gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + clock-names = "m-ahb", + "s-ahb"; + iommus = <&apps_smmu 0xd23 0x0>; + #address-cells = <2>; + #size-cells = <2>; + ranges; + status = "ok"; + + i2c0: i2c@b80000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00b80000 0 0x4000>; + interrupts = ; + clocks = <&gcc GCC_QUPV3_WRAP0_S0_CLK>; + clock-names = "se"; + interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS>, + <&hsc_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_0 QCOM_ICC_TAG_ALWAYS>, + <&aggre3_noc MASTER_QUP_0 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + dmas = <&gpi_dma0 0 0 QCOM_GPI_I2C>, + <&gpi_dma0 1 0 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + pinctrl-0 = <&qup_i2c0_data_clk>; + pinctrl-names = "default"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + spi0: spi@b80000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00b80000 0 0x4000>; + interrupts = ; + clocks = <&gcc GCC_QUPV3_WRAP0_S0_CLK>; + clock-names = "se"; + interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS>, + <&hsc_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_0 QCOM_ICC_TAG_ALWAYS>, + <&aggre3_noc MASTER_QUP_0 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + dmas = <&gpi_dma0 0 0 QCOM_GPI_SPI>, + <&gpi_dma0 1 0 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + pinctrl-0 = <&qup_spi0_data_clk>, <&qup_spi0_cs>; + pinctrl-names = "default"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c1: i2c@b84000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00b84000 0 0x4000>; + interrupts = ; + clocks = <&gcc GCC_QUPV3_WRAP0_S1_CLK>; + clock-names = "se"; + interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS>, + <&hsc_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_0 QCOM_ICC_TAG_ALWAYS>, + <&aggre3_noc MASTER_QUP_0 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + dmas = <&gpi_dma0 0 1 QCOM_GPI_I2C>, + <&gpi_dma0 1 1 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + pinctrl-0 = <&qup_i2c1_data_clk>; + pinctrl-names = "default"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + spi1: spi@b84000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00b84000 0 0x4000>; + interrupts = ; + clocks = <&gcc GCC_QUPV3_WRAP0_S1_CLK>; + clock-names = "se"; + interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS>, + <&hsc_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_0 QCOM_ICC_TAG_ALWAYS>, + <&aggre3_noc MASTER_QUP_0 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + dmas = <&gpi_dma0 0 1 QCOM_GPI_SPI>, + <&gpi_dma0 1 1 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + pinctrl-0 = <&qup_spi1_data_clk>, <&qup_spi1_cs>; + pinctrl-names = "default"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c2: i2c@b88000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00b88000 0 0x4000>; + interrupts = ; + clocks = <&gcc GCC_QUPV3_WRAP0_S2_CLK>; + clock-names = "se"; + interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS>, + <&hsc_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_0 QCOM_ICC_TAG_ALWAYS>, + <&aggre3_noc MASTER_QUP_0 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + dmas = <&gpi_dma0 0 2 QCOM_GPI_I2C>, + <&gpi_dma0 1 2 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + pinctrl-0 = <&qup_i2c2_data_clk>; + pinctrl-names = "default"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + spi2: spi@b88000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00b88000 0 0x4000>; + interrupts = ; + clocks = <&gcc GCC_QUPV3_WRAP0_S2_CLK>; + clock-names = "se"; + interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS>, + <&hsc_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_0 QCOM_ICC_TAG_ALWAYS>, + <&aggre3_noc MASTER_QUP_0 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + dmas = <&gpi_dma0 0 2 QCOM_GPI_SPI>, + <&gpi_dma0 1 2 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + pinctrl-0 = <&qup_spi2_data_clk>, <&qup_spi2_cs>; + pinctrl-names = "default"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + uart2: serial@b88000 { + compatible = "qcom,geni-uart"; + reg = <0 0x00b88000 0 0x4000>; + interrupts = ; + clocks = <&gcc GCC_QUPV3_WRAP0_S2_CLK>; + clock-names = "se"; + interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS>, + <&hsc_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_0 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config"; + pinctrl-0 = <&qup_uart2_default>; + pinctrl-names = "default"; + status = "disabled"; + }; + + i2c3: i2c@b8c000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00b8c000 0 0x4000>; + interrupts = ; + clocks = <&gcc GCC_QUPV3_WRAP0_S3_CLK>; + clock-names = "se"; + interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS>, + <&hsc_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_0 QCOM_ICC_TAG_ALWAYS>, + <&aggre3_noc MASTER_QUP_0 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + dmas = <&gpi_dma0 0 3 QCOM_GPI_I2C>, + <&gpi_dma0 1 3 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + pinctrl-0 = <&qup_i2c3_data_clk>; + pinctrl-names = "default"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + spi3: spi@b8c000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00b8c000 0 0x4000>; + interrupts = ; + clocks = <&gcc GCC_QUPV3_WRAP0_S3_CLK>; + clock-names = "se"; + interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS>, + <&hsc_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_0 QCOM_ICC_TAG_ALWAYS>, + <&aggre3_noc MASTER_QUP_0 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + dmas = <&gpi_dma0 0 3 QCOM_GPI_SPI>, + <&gpi_dma0 1 3 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + pinctrl-0 = <&qup_spi3_data_clk>, <&qup_spi3_cs>; + pinctrl-names = "default"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c4: i2c@b90000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00b90000 0 0x4000>; + interrupts = ; + clocks = <&gcc GCC_QUPV3_WRAP0_S4_CLK>; + clock-names = "se"; + interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS>, + <&hsc_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_0 QCOM_ICC_TAG_ALWAYS>, + <&aggre3_noc MASTER_QUP_0 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + dmas = <&gpi_dma0 0 4 QCOM_GPI_I2C>, + <&gpi_dma0 1 4 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + pinctrl-0 = <&qup_i2c4_data_clk>; + pinctrl-names = "default"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + spi4: spi@b90000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00b90000 0 0x4000>; + interrupts = ; + clocks = <&gcc GCC_QUPV3_WRAP0_S4_CLK>; + clock-names = "se"; + interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS>, + <&hsc_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_0 QCOM_ICC_TAG_ALWAYS>, + <&aggre3_noc MASTER_QUP_0 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + dmas = <&gpi_dma0 0 4 QCOM_GPI_SPI>, + <&gpi_dma0 1 4 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + pinctrl-0 = <&qup_spi4_data_clk>, <&qup_spi4_cs>; + pinctrl-names = "default"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c5: i2c@b94000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00b94000 0 0x4000>; + interrupts = ; + clocks = <&gcc GCC_QUPV3_WRAP0_S5_CLK>; + clock-names = "se"; + interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS>, + <&hsc_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_0 QCOM_ICC_TAG_ALWAYS>, + <&aggre3_noc MASTER_QUP_0 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + dmas = <&gpi_dma0 0 5 QCOM_GPI_I2C>, + <&gpi_dma0 1 5 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + pinctrl-0 = <&qup_i2c5_data_clk>; + pinctrl-names = "default"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + spi5: spi@b94000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00b94000 0 0x4000>; + interrupts = ; + clocks = <&gcc GCC_QUPV3_WRAP0_S5_CLK>; + clock-names = "se"; + interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS>, + <&hsc_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_0 QCOM_ICC_TAG_ALWAYS>, + <&aggre3_noc MASTER_QUP_0 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + dmas = <&gpi_dma0 0 5 QCOM_GPI_SPI>, + <&gpi_dma0 1 5 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + pinctrl-0 = <&qup_spi5_data_clk>, <&qup_spi5_cs>; + pinctrl-names = "default"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c6: i2c@b98000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00b98000 0 0x4000>; + interrupts = ; + clocks = <&gcc GCC_QUPV3_WRAP0_S6_CLK>; + clock-names = "se"; + interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS>, + <&hsc_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_0 QCOM_ICC_TAG_ALWAYS>, + <&aggre3_noc MASTER_QUP_0 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + dmas = <&gpi_dma0 0 6 QCOM_GPI_I2C>, + <&gpi_dma0 1 6 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + pinctrl-0 = <&qup_i2c6_data_clk>; + pinctrl-names = "default"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + spi6: spi@b98000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00b98000 0 0x4000>; + interrupts = ; + clocks = <&gcc GCC_QUPV3_WRAP0_S6_CLK>; + clock-names = "se"; + interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS>, + <&hsc_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_0 QCOM_ICC_TAG_ALWAYS>, + <&aggre3_noc MASTER_QUP_0 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + dmas = <&gpi_dma0 0 6 QCOM_GPI_SPI>, + <&gpi_dma0 1 6 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + pinctrl-0 = <&qup_spi6_data_clk>, <&qup_spi6_cs>; + pinctrl-names = "default"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c7: i2c@b9c000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00b9c000 0 0x4000>; + interrupts = ; + clocks = <&gcc GCC_QUPV3_WRAP0_S7_CLK>; + clock-names = "se"; + interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS>, + <&hsc_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_0 QCOM_ICC_TAG_ALWAYS>, + <&aggre3_noc MASTER_QUP_0 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + dmas = <&gpi_dma0 0 7 QCOM_GPI_I2C>, + <&gpi_dma0 1 7 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + pinctrl-0 = <&qup_i2c7_data_clk>; + pinctrl-names = "default"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + spi7: spi@b9c000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00b9c000 0 0x4000>; + interrupts = ; + clocks = <&gcc GCC_QUPV3_WRAP0_S7_CLK>; + clock-names = "se"; + interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS>, + <&hsc_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_0 QCOM_ICC_TAG_ALWAYS>, + <&aggre3_noc MASTER_QUP_0 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + dmas = <&gpi_dma0 0 7 QCOM_GPI_SPI>, + <&gpi_dma0 1 7 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + pinctrl-0 = <&qup_spi7_data_clk>, <&qup_spi7_cs>; + pinctrl-names = "default"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + }; + + cnoc_main: interconnect@1500000 { + compatible = "qcom,glymur-cnoc-main"; + reg = <0x0 0x01500000 0x0 0x17080>; + qcom,bcm-voters = <&apps_bcm_voter>; + #interconnect-cells = <2>; + }; + + config_noc: interconnect@1600000 { + compatible = "qcom,glymur-cnoc-cfg"; + reg = <0x0 0x01600000 0x0 0x6600>; + qcom,bcm-voters = <&apps_bcm_voter>; + #interconnect-cells = <2>; + }; + + system_noc: interconnect@1680000 { + compatible = "qcom,glymur-system-noc"; + reg = <0x0 0x01680000 0x0 0x1c080>; + qcom,bcm-voters = <&apps_bcm_voter>; + #interconnect-cells = <2>; + }; + + pcie_west_anoc: interconnect@16c0000 { + compatible = "qcom,glymur-pcie-west-anoc"; + reg = <0x0 0x016c0000 0x0 0xf580>; + qcom,bcm-voters = <&apps_bcm_voter>; + #interconnect-cells = <2>; + clocks = <&gcc GCC_AGGRE_NOC_PCIE_3A_WEST_SF_AXI_CLK>, + <&gcc GCC_AGGRE_NOC_PCIE_3B_WEST_SF_AXI_CLK>, + <&gcc GCC_AGGRE_NOC_PCIE_4_WEST_SF_AXI_CLK>, + <&gcc GCC_AGGRE_NOC_PCIE_6_WEST_SF_AXI_CLK>; + }; + + pcie_east_anoc: interconnect@16d0000 { + compatible = "qcom,glymur-pcie-east-anoc"; + reg = <0x0 0x016d0000 0x0 0xf300>; qcom,bcm-voters = <&apps_bcm_voter>; #interconnect-cells = <2>; + clocks = <&gcc GCC_AGGRE_NOC_PCIE_5_EAST_SF_AXI_CLK>; }; - pcie_west_slv_noc: interconnect@1920000 { - compatible = "qcom,glymur-pcie-west-slv-noc"; - reg = <0x0 0x01920000 0x0 0xf180>; - qcom,bcm-voters = <&apps_bcm_voter>; - #interconnect-cells = <2>; - }; + aggre1_noc: interconnect@16e0000 { + compatible = "qcom,glymur-aggre1-noc"; + reg = <0x0 0x016e0000 0x0 0x14400>; + qcom,bcm-voters = <&apps_bcm_voter>; + #interconnect-cells = <2>; + }; + + aggre2_noc: interconnect@1720000 { + compatible = "qcom,glymur-aggre2-noc"; + reg = <0x0 0x01720000 0x0 0x14400>; + qcom,bcm-voters = <&apps_bcm_voter>; + #interconnect-cells = <2>; + clocks = <&gcc GCC_AGGRE_USB3_TERT_AXI_CLK>, + <&gcc GCC_AGGRE_USB4_2_AXI_CLK>, + <&gcc GCC_AGGRE_UFS_PHY_AXI_CLK>; + }; + + aggre3_noc: interconnect@1700000 { + compatible = "qcom,glymur-aggre3-noc"; + reg = <0x0 0x01700000 0x0 0x1d400>; + qcom,bcm-voters = <&apps_bcm_voter>; + #interconnect-cells = <2>; + }; + + aggre4_noc: interconnect@1740000 { + compatible = "qcom,glymur-aggre4-noc"; + reg = <0x0 0x01740000 0x0 0x14400>; + qcom,bcm-voters = <&apps_bcm_voter>; + #interconnect-cells = <2>; + clocks = <&gcc GCC_AGGRE_USB3_PRIM_AXI_CLK>, + <&gcc GCC_AGGRE_USB3_SEC_AXI_CLK>, + <&gcc GCC_AGGRE_USB4_0_AXI_CLK>, + <&gcc GCC_AGGRE_USB4_1_AXI_CLK>; + }; + + mmss_noc: interconnect@1780000 { + compatible = "qcom,glymur-mmss-noc"; + reg = <0x0 0x01780000 0x0 0x5b800>; + qcom,bcm-voters = <&apps_bcm_voter>; + #interconnect-cells = <2>; + }; + + pcie_east_slv_noc: interconnect@1900000 { + compatible = "qcom,glymur-pcie-east-slv-noc"; + reg = <0x0 0x01900000 0x0 0xe080>; + qcom,bcm-voters = <&apps_bcm_voter>; + #interconnect-cells = <2>; + }; + + pcie_west_slv_noc: interconnect@1920000 { + compatible = "qcom,glymur-pcie-west-slv-noc"; + reg = <0x0 0x01920000 0x0 0xf180>; + qcom,bcm-voters = <&apps_bcm_voter>; + #interconnect-cells = <2>; + }; + + tcsr_mutex: hwlock@1f40000 { + compatible = "qcom,tcsr-mutex"; + reg = <0x0 0x01f40000 0x0 0x20000>; + + #hwlock-cells = <1>; + }; + + tcsrcc: clock-controller@1fd5044 { + compatible = "qcom,glymur-tcsr"; + reg = <0x0 0x1fd5044 0x0 0x48>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + tcsr: syscon@1fd6000 { + compatible = "syscon"; + reg = <0x0 0x1fd6000 0x0 0x20000>; + }; + + hsc_noc: interconnect@2000000 { + compatible = "qcom,glymur-hscnoc"; + reg = <0x0 0x02000000 0x0 0x93a080>; + qcom,bcm-voters = <&apps_bcm_voter>; + #interconnect-cells = <2>; + }; + + lpass_lpiaon_noc: interconnect@7400000 { + compatible = "qcom,glymur-lpass-lpiaon-noc"; + reg = <0x0 0x07400000 0x0 0x19080>; + qcom,bcm-voters = <&apps_bcm_voter>; + #interconnect-cells = <2>; + }; + + lpass_lpicx_noc: interconnect@7420000 { + compatible = "qcom,glymur-lpass-lpicx-noc"; + reg = <0x0 0x07420000 0x0 0x44080>; + qcom,bcm-voters = <&apps_bcm_voter>; + #interconnect-cells = <2>; + }; + + lpass_ag_noc: interconnect@7e40000 { + compatible = "qcom,glymur-lpass-ag-noc"; + reg = <0x0 0x07e40000 0x0 0xe080>; + qcom,bcm-voters = <&apps_bcm_voter>; + #interconnect-cells = <2>; + }; + + pdc: interrupt-controller@b220000 { + compatible = "qcom,glymur-pdc", "qcom,pdc"; + reg = <0x0 0x0b220000 0x0 0x10000>; + qcom,pdc-ranges = <0 745 51>, + <51 527 47>, + <98 609 32>, + <130 717 12>, + <142 251 5>, + <147 796 16>, + <171 4104 36>; + #interrupt-cells = <2>; + interrupt-parent = <&intc>; + interrupt-controller; + }; + + sram@c30f000 { + compatible = "qcom,rpmh-stats"; + reg = <0x0 0x0c30f000 0x0 0x400>; + }; + + tlmm: pinctrl@f100000 { + compatible = "qcom,glymur-tlmm"; + reg = <0x0 0x0f100000 0x0 0xf00000>; + interrupts = ; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + gpio-ranges = <&tlmm 0 0 249>; + wakeup-parent = <&pdc>; + + qup_i2c0_data_clk: qup-i2c0-data-clk-state { + sda_pins { + /* SDA */ + pins = "gpio0"; + function = "qup0_se0"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + + scl-pins { + /* SCL */ + pins = "gpio1"; + function = "qup0_se0"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + }; + + qup_i2c1_data_clk: qup-i2c1-data-clk-state { + sda_pins { + /* SDA */ + pins = "gpio4"; + function = "qup0_se1"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + + scl-pins { + /* SCL */ + pins = "gpio5"; + function = "qup0_se1"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + }; + + qup_i2c2_data_clk: qup-i2c2-data-clk-state { + sda_pins { + /* SDA */ + pins = "gpio8"; + function = "qup0_se2"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + + scl-pins { + /* SCL */ + pins = "gpio9"; + function = "qup0_se2"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + }; + + qup_i2c3_data_clk: qup-i2c3-data-clk-state { + sda_pins { + /* SDA */ + pins = "gpio12"; + function = "qup0_se3"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + + scl-pins { + /* SCL */ + pins = "gpio13"; + function = "qup0_se3"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + }; + + qup_i2c4_data_clk: qup-i2c4-data-clk-state { + sda_pins { + /* SDA */ + pins = "gpio16"; + function = "qup0_se4"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + + scl-pins { + /* SCL */ + pins = "gpio17"; + function = "qup0_se4"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + }; + + qup_i2c5_data_clk: qup-i2c5-data-clk-state { + sda_pins { + /* SDA */ + pins = "gpio20"; + function = "qup0_se5"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + + scl-pins { + /* SCL */ + pins = "gpio21"; + function = "qup0_se5"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + }; + + qup_i2c6_data_clk: qup-i2c6-data-clk-state { + sda_pins { + /* SDA */ + pins = "gpio6"; + function = "qup0_se6"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + + scl-pins { + /* SCL */ + pins = "gpio7"; + function = "qup0_se6"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + }; + + qup_i2c7_data_clk: qup-i2c7-data-clk-state { + sda_pins { + /* SDA */ + pins = "gpio14"; + function = "qup0_se7"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + + scl-pins { + /* SCL */ + pins = "gpio15"; + function = "qup0_se7"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + }; + + qup_i2c8_data_clk: qup-i2c8-data-clk-state { + sda_pins { + /* SDA */ + pins = "gpio32"; + function = "qup1_se0"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + + scl-pins { + /* SCL */ + pins = "gpio33"; + function = "qup1_se0"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + }; + + qup_i2c9_data_clk: qup-i2c9-data-clk-state { + sda_pins { + /* SDA */ + pins = "gpio36"; + function = "qup1_se1"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + + scl-pins { + /* SCL */ + pins = "gpio37"; + function = "qup1_se1"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + }; + + qup_i2c10_data_clk: qup-i2c10-data-clk-state { + sda_pins { + /* SDA */ + pins = "gpio40"; + function = "qup1_se2"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + + scl-pins { + /* SCL */ + pins = "gpio41"; + function = "qup1_se2"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + }; + + qup_i2c11_data_clk: qup-i2c11-data-clk-state { + sda_pins { + /* SDA */ + pins = "gpio44"; + function = "qup1_se3"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + + scl-pins { + /* SCL */ + pins = "gpio45"; + function = "qup1_se3"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + }; + + qup_i2c12_data_clk: qup-i2c12-data-clk-state { + sda_pins { + /* SDA */ + pins = "gpio48"; + function = "qup1_se4"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + + scl-pins { + /* SCL */ + pins = "gpio49"; + function = "qup1_se4"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + }; + + qup_i2c13_data_clk: qup-i2c13-data-clk-state { + sda_pins { + /* SDA */ + pins = "gpio52"; + function = "qup1_se5"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + + scl-pins { + /* SCL */ + pins = "gpio53"; + function = "qup1_se5"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + }; + + qup_i2c14_data_clk: qup-i2c14-data-clk-state { + sda_pins { + /* SDA */ + pins = "gpio56"; + function = "qup1_se6"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + + scl-pins { + /* SCL */ + pins = "gpio57"; + function = "qup1_se6"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + }; + + qup_i2c15_data_clk: qup-i2c15-data-clk-state { + sda_pins { + /* SDA */ + pins = "gpio54"; + function = "qup1_se7"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + + scl-pins { + /* SCL */ + pins = "gpio55"; + function = "qup1_se7"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + }; + + qup_i2c16_data_clk: qup-i2c16-data-clk-state { + sda_pins { + /* SDA */ + pins = "gpio64"; + function = "qup2_se0"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + + scl-pins { + /* SCL */ + pins = "gpio65"; + function = "qup2_se0"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + }; + + qup_i2c17_data_clk: qup-i2c17-data-clk-state { + sda_pins { + /* SDA */ + pins = "gpio68"; + function = "qup2_se1"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + + scl-pins { + /* SCL */ + pins = "gpio69"; + function = "qup2_se1"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + }; + + qup_i2c18_data_clk: qup-i2c18-data-clk-state { + sda_pins { + /* SDA */ + pins = "gpio72"; + function = "qup2_se2"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + + scl-pins { + /* SCL */ + pins = "gpio73"; + function = "qup2_se2"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + }; + + qup_i2c19_data_clk: qup-i2c19-data-clk-state { + sda_pins { + /* SDA */ + pins = "gpio76"; + function = "qup2_se3"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + + scl-pins { + /* SCL */ + pins = "gpio77"; + function = "qup2_se3"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + }; + + qup_i2c20_data_clk: qup-i2c20-data-clk-state { + sda_pins { + /* SDA */ + pins = "gpio80"; + function = "qup2_se4"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + + scl-pins { + /* SCL */ + pins = "gpio81"; + function = "qup2_se4"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + }; + + qup_i2c21_data_clk: qup-i2c21-data-clk-state { + sda_pins { + /* SDA */ + pins = "gpio84"; + function = "qup2_se5"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + + scl-pins { + /* SCL */ + pins = "gpio85"; + function = "qup2_se5"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + }; + + qup_i2c22_data_clk: qup-i2c22-data-clk-state { + sda_pins { + /* SDA */ + pins = "gpio88"; + function = "qup2_se6"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + + scl-pins { + /* SCL */ + pins = "gpio89"; + function = "qup2_se6"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + }; + + qup_i2c23_data_clk: qup-i2c23-data-clk-state { + sda_pins { + /* SDA */ + pins = "gpio80"; + function = "qup2_se7"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + + scl-pins { + /* SCL */ + pins = "gpio81"; + function = "qup2_se7"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + }; + + qup_spi0_cs: qup-spi0-cs-state { + pins = "gpio3"; + function = "qup0_se0"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi0_data_clk: qup-spi0-data-clk-state { + miso-pins { + /* MISO */ + pins = "gpio0"; + function = "qup0_se0"; + drive-strength = <6>; + bias-disable; + }; + + mosi-pins { + /* MOSI */ + pins = "gpio1"; + function = "qup0_se0"; + drive-strength = <6>; + bias-disable; + }; + + clk-pins { + /* CLK */ + pins = "gpio2"; + function = "qup0_se0"; + drive-strength = <6>; + bias-disable; + }; + }; + + qup_spi1_cs: qup-spi1-cs-state { + pins = "gpio7"; + function = "qup0_se1"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi1_data_clk: qup-spi1-data-clk-state { + miso-pins { + /* MISO */ + pins = "gpio4"; + function = "qup0_se1"; + drive-strength = <6>; + bias-disable; + }; + + mosi-pins { + /* MOSI */ + pins = "gpio5"; + function = "qup0_se1"; + drive-strength = <6>; + bias-disable; + }; + + clk-pins { + /* CLK */ + pins = "gpio6"; + function = "qup0_se1"; + drive-strength = <6>; + bias-disable; + }; + }; + + qup_spi2_cs: qup-spi2-cs-state { + pins = "gpio11"; + function = "qup0_se2"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi2_data_clk: qup-spi2-data-clk-state { + miso-pins { + /* MISO */ + pins = "gpio8"; + function = "qup0_se2"; + drive-strength = <6>; + bias-disable; + }; + + mosi-pins { + /* MOSI */ + pins = "gpio9"; + function = "qup0_se2"; + drive-strength = <6>; + bias-disable; + }; + + clk-pins { + /* CLK */ + pins = "gpio10"; + function = "qup0_se2"; + drive-strength = <6>; + bias-disable; + }; + }; + + qup_spi3_cs: qup-spi3-cs-state { + pins = "gpio15"; + function = "qup0_se3"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi3_data_clk: qup-spi3-data-clk-state { + miso-pins { + /* MISO */ + pins = "gpio12"; + function = "qup0_se3"; + drive-strength = <6>; + bias-disable; + }; + + mosi-pins { + /* MOSI */ + pins = "gpio13"; + function = "qup0_se3"; + drive-strength = <6>; + bias-disable; + }; + + clk-pins { + /* CLK */ + pins = "gpio14"; + function = "qup0_se3"; + drive-strength = <6>; + bias-disable; + }; + }; + + qup_spi4_cs: qup-spi4-cs-state { + pins = "gpio19"; + function = "qup0_se4"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi4_data_clk: qup-spi4-data-clk-state { + miso-pins { + /* MISO */ + pins = "gpio16"; + function = "qup0_se4"; + drive-strength = <6>; + bias-disable; + }; + + mosi-pins { + /* MOSI */ + pins = "gpio17"; + function = "qup0_se4"; + drive-strength = <6>; + bias-disable; + }; + + clk-pins { + /* CLK */ + pins = "gpio18"; + function = "qup0_se4"; + drive-strength = <6>; + bias-disable; + }; + }; + + qup_spi5_cs: qup-spi5-cs-state { + pins = "gpio23"; + function = "qup0_se5"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi5_data_clk: qup-spi5-data-clk-state { + miso-pins { + /* MISO */ + pins = "gpio20"; + function = "qup0_se5"; + drive-strength = <6>; + bias-disable; + }; + + mosi-pins { + /* MOSI */ + pins = "gpio21"; + function = "qup0_se5"; + drive-strength = <6>; + bias-disable; + }; + + clk-pins { + /* CLK */ + pins = "gpio22"; + function = "qup0_se5"; + drive-strength = <6>; + bias-disable; + }; + }; + + qup_spi6_cs: qup-spi6-cs-state { + pins = "gpio5"; + function = "qup0_se6"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi6_data_clk: qup-spi6-data-clk-state { + miso-pins { + /* MISO */ + pins = "gpio6"; + function = "qup0_se6"; + drive-strength = <6>; + bias-disable; + }; + + mosi-pins { + /* MOSI */ + pins = "gpio7"; + function = "qup0_se6"; + drive-strength = <6>; + bias-disable; + }; + + clk-pins { + /* CLK */ + pins = "gpio4"; + function = "qup0_se6"; + drive-strength = <6>; + bias-disable; + }; + }; + + qup_spi7_cs: qup-spi7-cs-state { + pins = "gpio13"; + function = "qup0_se7"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi7_data_clk: qup-spi7-data-clk-state { + /* MISO, MOSI, CLK */ + miso-pins { + /* MISO */ + pins = "gpio14"; + function = "qup0_se7"; + drive-strength = <6>; + bias-disable; + }; + + mosi-pins { + /* MOSI */ + pins = "gpio15"; + function = "qup0_se7"; + drive-strength = <6>; + bias-disable; + }; + + clk-pins { + /* CLK */ + pins = "gpio12"; + function = "qup0_se7"; + drive-strength = <6>; + bias-disable; + }; + }; + + qup_spi8_cs: qup-spi8-cs-state { + pins = "gpio35"; + function = "qup1_se0"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi8_data_clk: qup-spi8-data-clk-state { + miso-pins { + /* MISO */ + pins = "gpio32"; + function = "qup1_se0"; + drive-strength = <6>; + bias-disable; + }; + + mosi-pins { + /* MOSI */ + pins = "gpio33"; + function = "qup1_se0"; + drive-strength = <6>; + bias-disable; + }; + + clk-pins { + /* CLK */ + pins = "gpio34"; + function = "qup1_se0"; + drive-strength = <6>; + bias-disable; + }; + }; + + qup_spi9_cs: qup-spi9-cs-state { + pins = "gpio39"; + function = "qup1_se1"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi9_data_clk: qup-spi9-data-clk-state { + miso-pins { + /* MISO */ + pins = "gpio36"; + function = "qup1_se1"; + drive-strength = <6>; + bias-disable; + }; + + mosi-pins { + /* MOSI */ + pins = "gpio37"; + function = "qup1_se1"; + drive-strength = <6>; + bias-disable; + }; + + clk-pins { + /* CLK */ + pins = "gpio38"; + function = "qup1_se1"; + drive-strength = <6>; + bias-disable; + }; + }; + + qup_spi10_cs: qup-spi10-cs-state { + pins = "gpio43"; + function = "qup1_se2"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi10_data_clk: qup-spi10-data-clk-state { + miso-pins { + /* MISO */ + pins = "gpio40"; + function = "qup1_se2"; + drive-strength = <6>; + bias-disable; + }; + + mosi-pins { + /* MOSI */ + pins = "gpio41"; + function = "qup1_se2"; + drive-strength = <6>; + bias-disable; + }; + + clk-pins { + /* CLK */ + pins = "gpio42"; + function = "qup1_se2"; + drive-strength = <6>; + bias-disable; + }; + }; + + qup_spi11_cs: qup-spi11-cs-state { + pins = "gpio47"; + function = "qup1_se3"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi11_data_clk: qup-spi11-data-clk-state { + miso-pins { + /* MISO */ + pins = "gpio44"; + function = "qup1_se3"; + drive-strength = <6>; + bias-disable; + }; + + mosi-pins { + /* MOSI */ + pins = "gpio45"; + function = "qup1_se3"; + drive-strength = <6>; + bias-disable; + }; + + clk-pins { + /* CLK */ + pins = "gpio46"; + function = "qup1_se3"; + drive-strength = <6>; + bias-disable; + }; + }; + + qup_spi12_cs: qup-spi12-cs-state { + pins = "gpio51"; + function = "qup1_se4"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi12_data_clk: qup-spi12-data-clk-state { + miso-pins { + /* MISO */ + pins = "gpio48"; + function = "qup1_se4"; + drive-strength = <6>; + bias-disable; + }; + + mosi-pins { + /* MOSI */ + pins = "gpio49"; + function = "qup1_se4"; + drive-strength = <6>; + bias-disable; + }; + + clk-pins { + /* CLK */ + pins = "gpio50"; + function = "qup1_se4"; + drive-strength = <6>; + bias-disable; + }; + }; + + qup_spi13_cs: qup-spi13-cs-state { + pins = "gpio55"; + function = "qup1_se5"; + drive-strength = <6>; + bias-disable; + }; - tcsr_mutex: hwlock@1f40000 { - compatible = "qcom,tcsr-mutex"; - reg = <0x0 0x01f40000 0x0 0x20000>; + qup_spi13_data_clk: qup-spi13-data-clk-state { + miso-pins { + /* MISO */ + pins = "gpio52"; + function = "qup1_se5"; + drive-strength = <6>; + bias-disable; + }; - #hwlock-cells = <1>; - }; + mosi-pins { + /* MOSI */ + pins = "gpio53"; + function = "qup1_se5"; + drive-strength = <6>; + bias-disable; + }; - tcsrcc: clock-controller@1fd5044 { - compatible = "qcom,glymur-tcsr"; - reg = <0x0 0x1fd5044 0x0 0x48>; - #clock-cells = <1>; - #reset-cells = <1>; - }; + clk-pins { + /* CLK */ + pins = "gpio54"; + function = "qup1_se5"; + drive-strength = <6>; + bias-disable; + }; + }; - tcsr: syscon@1fd6000 { - compatible = "syscon"; - reg = <0x0 0x1fd6000 0x0 0x20000>; - }; + qup_spi14_cs: qup-spi14-cs-state { + pins = "gpio59"; + function = "qup1_se6"; + drive-strength = <6>; + bias-disable; + }; - hsc_noc: interconnect@2000000 { - compatible = "qcom,glymur-hscnoc"; - reg = <0x0 0x02000000 0x0 0x93a080>; - qcom,bcm-voters = <&apps_bcm_voter>; - #interconnect-cells = <2>; - }; + qup_spi14_data_clk: qup-spi14-data-clk-state { + miso-pins { + /* MISO */ + pins = "gpio56"; + function = "qup1_se6"; + drive-strength = <6>; + bias-disable; + }; + mosi-pins { + /* MOSI */ + pins = "gpio57"; + function = "qup1_se6"; + drive-strength = <6>; + bias-disable; + }; - lpass_lpiaon_noc: interconnect@7400000 { - compatible = "qcom,glymur-lpass-lpiaon-noc"; - reg = <0x0 0x07400000 0x0 0x19080>; - qcom,bcm-voters = <&apps_bcm_voter>; - #interconnect-cells = <2>; - }; + clk-pins { + /* CLK */ + pins = "gpio58"; + function = "qup1_se6"; + drive-strength = <6>; + bias-disable; + }; + }; - lpass_lpicx_noc: interconnect@7420000 { - compatible = "qcom,glymur-lpass-lpicx-noc"; - reg = <0x0 0x07420000 0x0 0x44080>; - qcom,bcm-voters = <&apps_bcm_voter>; - #interconnect-cells = <2>; - }; + qup_spi15_cs: qup-spi15-cs-state { + pins = "gpio53"; + function = "qup1_se7"; + drive-strength = <6>; + bias-disable; + }; - lpass_ag_noc: interconnect@7e40000 { - compatible = "qcom,glymur-lpass-ag-noc"; - reg = <0x0 0x07e40000 0x0 0xe080>; - qcom,bcm-voters = <&apps_bcm_voter>; - #interconnect-cells = <2>; - }; + qup_spi15_data_clk: qup-spi15-data-clk-state { + miso-pins { + /* MISO */ + pins = "gpio54"; + function = "qup1_se7"; + drive-strength = <6>; + bias-disable; + }; - pdc: interrupt-controller@b220000 { - compatible = "qcom,glymur-pdc", "qcom,pdc"; - reg = <0x0 0x0b220000 0x0 0x10000>; - qcom,pdc-ranges = <0 745 51>, - <51 527 47>, - <98 609 32>, - <130 717 12>, - <142 251 5>, - <147 796 16>, - <171 4104 36>; - #interrupt-cells = <2>; - interrupt-parent = <&intc>; - interrupt-controller; - }; + mosi-pins { + /* MOSI */ + pins = "gpio55"; + function = "qup1_se7"; + drive-strength = <6>; + bias-disable; + }; - sram@c30f000 { - compatible = "qcom,rpmh-stats"; - reg = <0x0 0x0c30f000 0x0 0x400>; - }; + clk-pins { + /* CLK */ + pins = "gpio52"; + function = "qup1_se7"; + drive-strength = <6>; + bias-disable; + }; + }; - tlmm: pinctrl@f100000 { - compatible = "qcom,glymur-tlmm"; - reg = <0x0 0x0f100000 0x0 0xf00000>; - interrupts = ; - gpio-controller; - #gpio-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; - gpio-ranges = <&tlmm 0 0 249>; - wakeup-parent = <&pdc>; + qup_spi16_cs: qup-spi16-cs-state { + pins = "gpio67"; + function = "qup2_se0"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi16_data_clk: qup-spi16-data-clk-state { + miso-pins { + /* MISO */ + pins = "gpio64"; + function = "qup2_se0"; + drive-strength = <6>; + bias-disable; + }; + + mosi-pins { + /* MOSI */ + pins = "gpio65"; + function = "qup2_se0"; + drive-strength = <6>; + bias-disable; + }; + + clk-pins { + /* CLK */ + pins = "gpio66"; + function = "qup2_se0"; + drive-strength = <6>; + bias-disable; + }; + }; + + qup_spi17_cs: qup-spi17-cs-state { + pins = "gpio71"; + function = "qup2_se1"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi17_data_clk: qup-spi17-data-clk-state { + miso-pins { + /* MISO */ + pins = "gpio68"; + function = "qup2_se1"; + drive-strength = <6>; + bias-disable; + }; + + mosi-pins { + /* MOSI */ + pins = "gpio69"; + function = "qup2_se1"; + drive-strength = <6>; + bias-disable; + }; + + clk-pins { + /* CLK */ + pins = "gpio70"; + function = "qup2_se1"; + drive-strength = <6>; + bias-disable; + }; + }; + + qup_spi18_cs: qup-spi18-cs-state { + pins = "gpio75"; + function = "qup2_se2"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi18_data_clk: qup-spi18-data-clk-state { + miso-pins { + /* MISO */ + pins = "gpio72"; + function = "qup2_se2"; + drive-strength = <6>; + bias-disable; + }; + + mosi-pins { + /* MOSI */ + pins = "gpio73"; + function = "qup2_se2"; + drive-strength = <6>; + bias-disable; + }; + + clk-pins { + /* CLK */ + pins = "gpio74"; + function = "qup2_se2"; + drive-strength = <6>; + bias-disable; + }; + }; + + qup_spi19_cs: qup-spi19-cs-state { + pins = "gpio79"; + function = "qup2_se3"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi19_data_clk: qup-spi19-data-clk-state { + miso-pins { + /* MISO */ + pins = "gpio76"; + function = "qup2_se3"; + drive-strength = <6>; + bias-disable; + }; + + mosi-pins { + /* MOSI */ + pins = "gpio77"; + function = "qup2_se3"; + drive-strength = <6>; + bias-disable; + }; + + clk-pins { + /* CLK */ + pins = "gpio78"; + function = "qup2_se3"; + drive-strength = <6>; + bias-disable; + }; + }; + + qup_spi20_cs: qup-spi20-cs-state { + pins = "gpio83"; + function = "qup2_se4"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi20_data_clk: qup-spi20-data-clk-state { + miso-pins { + /* MISO */ + pins = "gpio80"; + function = "qup2_se4"; + drive-strength = <6>; + bias-disable; + }; + + mosi-pins { + /* MOSI */ + pins = "gpio81"; + function = "qup2_se4"; + drive-strength = <6>; + bias-disable; + }; + + clk-pins { + /* CLK */ + pins = "gpio82"; + function = "qup2_se4"; + drive-strength = <6>; + bias-disable; + }; + }; + + qup_spi21_cs: qup-spi21-cs-state { + pins = "gpio87"; + function = "qup2_se5"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi21_data_clk: qup-spi21-data-clk-state { + miso-pins { + /* MISO */ + pins = "gpio84"; + function = "qup2_se5"; + drive-strength = <6>; + bias-disable; + }; + + mosi-pins { + /* MOSI */ + pins = "gpio85"; + function = "qup2_se5"; + drive-strength = <6>; + bias-disable; + }; + + clk-pins { + /* CLK */ + pins = "gpio86"; + function = "qup2_se5"; + drive-strength = <6>; + bias-disable; + }; + }; + + qup_spi22_cs: qup-spi22-cs-state { + pins = "gpio91"; + function = "qup2_se6"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi22_data_clk: qup-spi22-data-clk-state { + miso-pins { + /* MISO */ + pins = "gpio88"; + function = "qup2_se6"; + drive-strength = <6>; + bias-disable; + }; + + mosi-pins { + /* MOSI */ + pins = "gpio89"; + function = "qup2_se6"; + drive-strength = <6>; + bias-disable; + }; + + clk-pins { + /* CLK */ + pins = "gpio90"; + function = "qup2_se6"; + drive-strength = <6>; + bias-disable; + }; + }; + + qup_spi23_cs: qup-spi23-cs-state { + pins = "gpio83"; + function = "qup2_se7"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi23_data_clk: qup-spi23-data-clk-state { + miso-pins { + /* MISO */ + pins = "gpio80"; + function = "qup2_se7"; + drive-strength = <6>; + bias-disable; + }; + + mosi-pins { + /* MOSI */ + pins = "gpio81"; + function = "qup2_se7"; + drive-strength = <6>; + bias-disable; + }; + + clk-pins { + /* CLK */ + pins = "gpio82"; + function = "qup2_se7"; + drive-strength = <6>; + bias-disable; + }; + }; + + qup_uart2_default: qup-uart2-default-state { + tx-pins { + pins = "gpio10"; + function = "qup0_se2"; + drive-strength = <2>; + bias-disable; + }; + + rx-pins { + pins = "gpio11"; + function = "qup0_se2"; + drive-strength = <2>; + bias-disable; + }; + }; + + qup_uart14_default: qup-uart14-default-state { + cts-pins { + pins = "gpio56"; + function = "qup1_se6"; + drive-strength = <2>; + bias-disable; + }; + + rts-pins { + pins = "gpio57"; + function = "qup1_se6"; + drive-strength = <2>; + bias-disable; + }; + + tx-pins { + pins = "gpio58"; + function = "qup1_se6"; + drive-strength = <2>; + bias-disable; + }; + + rx-pins { + pins = "gpio59"; + function = "qup1_se6"; + drive-strength = <2>; + bias-disable; + }; + }; + + qup_uart19_default: qup-uart19-default-state { + cts-pins { + pins = "gpio76"; + function = "qup2_se3"; + drive-strength = <2>; + bias-disable; + }; + + rts-pins { + pins = "gpio77"; + function = "qup2_se3"; + drive-strength = <2>; + bias-disable; + }; + + tx-pins { + pins = "gpio78"; + function = "qup2_se3"; + drive-strength = <2>; + bias-disable; + }; + + rx-pins { + pins = "gpio79"; + function = "qup2_se3"; + drive-strength = <2>; + bias-disable; + }; + }; qup_uart21_default: qup-uart21-default-state { tx-pins { @@ -925,6 +3654,22 @@ bias-disable; }; }; + + qup_uart22_default: qup-uart22-default-state { + tx-pins { + pins = "gpio90"; + function = "qup2_se6"; + drive-strength = <2>; + bias-disable; + }; + + rx-pins { + pins = "gpio91"; + function = "qup2_se6"; + drive-strength = <2>; + bias-disable; + }; + }; }; apps_smmu: iommu@15000000 { From 47d766092953d6f4ffd19a1ca9996372d6643b8e Mon Sep 17 00:00:00 2001 From: Maulik Shah Date: Thu, 25 Sep 2025 12:02:13 +0530 Subject: [PATCH 0313/2333] FROMLIST: arm64: dts: qcom: glymur: Add cpu idle states Add CPU power domains Link: https://lore.kernel.org/lkml/20250925-v3_glymur_introduction-v1-5-24b601bbecc0@oss.qualcomm.com/ Signed-off-by: Maulik Shah Signed-off-by: Pankaj Patil Signed-off-by: Sibi Sankar --- arch/arm64/boot/dts/qcom/glymur.dtsi | 235 +++++++++++++++++++++++++++ 1 file changed, 235 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/glymur.dtsi b/arch/arm64/boot/dts/qcom/glymur.dtsi index 8674465b22707..66a548400c720 100644 --- a/arch/arm64/boot/dts/qcom/glymur.dtsi +++ b/arch/arm64/boot/dts/qcom/glymur.dtsi @@ -46,6 +46,9 @@ compatible = "qcom,oryon"; reg = <0x0 0x0>; enable-method = "psci"; + power-domains = <&CPU_PD0>; + power-domain-names = "psci"; + cpu-idle-states = <&CLUSTER0_C4>; next-level-cache = <&l2_0>; l2_0: l2-cache { @@ -60,6 +63,9 @@ compatible = "qcom,oryon"; reg = <0x0 0x100>; enable-method = "psci"; + power-domains = <&CPU_PD1>; + power-domain-names = "psci"; + cpu-idle-states = <&CLUSTER0_C4>; next-level-cache = <&l2_0>; }; @@ -68,6 +74,9 @@ compatible = "qcom,oryon"; reg = <0x0 0x200>; enable-method = "psci"; + power-domains = <&CPU_PD2>; + power-domain-names = "psci"; + cpu-idle-states = <&CLUSTER0_C4>; next-level-cache = <&l2_0>; }; @@ -76,6 +85,9 @@ compatible = "qcom,oryon"; reg = <0x0 0x300>; enable-method = "psci"; + power-domains = <&CPU_PD3>; + power-domain-names = "psci"; + cpu-idle-states = <&CLUSTER0_C4>; next-level-cache = <&l2_0>; }; @@ -84,6 +96,9 @@ compatible = "qcom,oryon"; reg = <0x0 0x400>; enable-method = "psci"; + power-domains = <&CPU_PD4>; + power-domain-names = "psci"; + cpu-idle-states = <&CLUSTER0_C4>; next-level-cache = <&l2_0>; }; @@ -92,6 +107,9 @@ compatible = "qcom,oryon"; reg = <0x0 0x500>; enable-method = "psci"; + power-domains = <&CPU_PD5>; + power-domain-names = "psci"; + cpu-idle-states = <&CLUSTER0_C4>; next-level-cache = <&l2_0>; }; @@ -100,6 +118,9 @@ compatible = "qcom,oryon"; reg = <0x0 0x10000>; enable-method = "psci"; + power-domains = <&CPU_PD6>; + power-domain-names = "psci"; + cpu-idle-states = <&CLUSTER1_C4>; next-level-cache = <&l2_1>; l2_1: l2-cache { @@ -114,6 +135,9 @@ compatible = "qcom,oryon"; reg = <0x0 0x10100>; enable-method = "psci"; + power-domains = <&CPU_PD7>; + power-domain-names = "psci"; + cpu-idle-states = <&CLUSTER1_C4>; next-level-cache = <&l2_1>; }; @@ -122,6 +146,9 @@ compatible = "qcom,oryon"; reg = <0x0 0x10200>; enable-method = "psci"; + power-domains = <&CPU_PD8>; + power-domain-names = "psci"; + cpu-idle-states = <&CLUSTER1_C4>; next-level-cache = <&l2_1>; }; @@ -130,6 +157,9 @@ compatible = "qcom,oryon"; reg = <0x0 0x10300>; enable-method = "psci"; + power-domains = <&CPU_PD9>; + power-domain-names = "psci"; + cpu-idle-states = <&CLUSTER1_C4>; next-level-cache = <&l2_1>; }; @@ -138,6 +168,9 @@ compatible = "qcom,oryon"; reg = <0x0 0x10400>; enable-method = "psci"; + power-domains = <&CPU_PD10>; + power-domain-names = "psci"; + cpu-idle-states = <&CLUSTER1_C4>; next-level-cache = <&l2_1>; }; @@ -146,6 +179,9 @@ compatible = "qcom,oryon"; reg = <0x0 0x10500>; enable-method = "psci"; + power-domains = <&CPU_PD11>; + power-domain-names = "psci"; + cpu-idle-states = <&CLUSTER1_C4>; next-level-cache = <&l2_1>; }; @@ -154,6 +190,9 @@ compatible = "qcom,oryon"; reg = <0x0 0x20000>; enable-method = "psci"; + power-domains = <&CPU_PD12>; + power-domain-names = "psci"; + cpu-idle-states = <&CLUSTER2_C4>; next-level-cache = <&l2_2>; l2_2: l2-cache { @@ -168,6 +207,9 @@ compatible = "qcom,oryon"; reg = <0x0 0x20100>; enable-method = "psci"; + power-domains = <&CPU_PD13>; + power-domain-names = "psci"; + cpu-idle-states = <&CLUSTER2_C4>; next-level-cache = <&l2_2>; }; @@ -176,6 +218,9 @@ compatible = "qcom,oryon"; reg = <0x0 0x20200>; enable-method = "psci"; + power-domains = <&CPU_PD14>; + power-domain-names = "psci"; + cpu-idle-states = <&CLUSTER2_C4>; next-level-cache = <&l2_2>; }; @@ -184,6 +229,9 @@ compatible = "qcom,oryon"; reg = <0x0 0x20300>; enable-method = "psci"; + power-domains = <&CPU_PD15>; + power-domain-names = "psci"; + cpu-idle-states = <&CLUSTER2_C4>; next-level-cache = <&l2_2>; }; @@ -192,6 +240,9 @@ compatible = "qcom,oryon"; reg = <0x0 0x20400>; enable-method = "psci"; + power-domains = <&CPU_PD16>; + power-domain-names = "psci"; + cpu-idle-states = <&CLUSTER2_C4>; next-level-cache = <&l2_2>; }; @@ -200,8 +251,78 @@ compatible = "qcom,oryon"; reg = <0x0 0x20500>; enable-method = "psci"; + power-domains = <&CPU_PD17>; + power-domain-names = "psci"; + cpu-idle-states = <&CLUSTER2_C4>; next-level-cache = <&l2_2>; }; + + idle-states { + entry-method = "psci"; + + CLUSTER0_C4: cpu-sleep-0 { + compatible = "arm,idle-state"; + idle-state-name = "ret"; + arm,psci-suspend-param = <0x00000004>; + entry-latency-us = <180>; + exit-latency-us = <320>; + min-residency-us = <1000>; + }; + + CLUSTER1_C4: cpu-sleep-1 { + compatible = "arm,idle-state"; + idle-state-name = "ret"; + arm,psci-suspend-param = <0x00000004>; + entry-latency-us = <180>; + exit-latency-us = <320>; + min-residency-us = <1000>; + }; + + CLUSTER2_C4: cpu-sleep-2 { + compatible = "arm,idle-state"; + idle-state-name = "ret"; + arm,psci-suspend-param = <0x00000004>; + entry-latency-us = <180>; + exit-latency-us = <320>; + min-residency-us = <1000>; + }; + + cluster0_cl5: cluster-sleep-0 { + compatible = "domain-idle-state"; + idle-state-name = "ret"; + arm,psci-suspend-param = <0x01000054>; + entry-latency-us = <2000>; + exit-latency-us = <2000>; + min-residency-us = <9000>; + }; + + cluster1_cl5: cluster-sleep-1 { + compatible = "domain-idle-state"; + idle-state-name = "ret"; + arm,psci-suspend-param = <0x01000054>; + entry-latency-us = <2000>; + exit-latency-us = <2000>; + min-residency-us = <9000>; + }; + + cluster2_cl5: cluster-sleep-2 { + compatible = "domain-idle-state"; + idle-state-name = "ret"; + arm,psci-suspend-param = <0x01000054>; + entry-latency-us = <2000>; + exit-latency-us = <2000>; + min-residency-us = <9000>; + }; + + APSS_OFF: cluster-ss3 { + compatible = "domain-idle-state"; + idle-state-name = "apps-pc"; + entry-latency-us = <2800>; + exit-latency-us = <4400>; + min-residency-us = <10150>; + arm,psci-suspend-param = <0x0200C354>; + }; + }; }; cpu-map { @@ -669,6 +790,119 @@ psci { compatible = "arm,psci-1.0"; method = "smc"; + + CPU_PD0: power-domain-cpu0 { + #power-domain-cells = <0>; + power-domains = <&CLUSTER0_PD>; + }; + + CPU_PD1: power-domain-cpu1 { + #power-domain-cells = <0>; + power-domains = <&CLUSTER0_PD>; + }; + + CPU_PD2: power-domain-cpu2 { + #power-domain-cells = <0>; + power-domains = <&CLUSTER0_PD>; + }; + + CPU_PD3: power-domain-cpu3 { + #power-domain-cells = <0>; + power-domains = <&CLUSTER0_PD>; + }; + + CPU_PD4: power-domain-cpu4 { + #power-domain-cells = <0>; + power-domains = <&CLUSTER0_PD>; + }; + + CPU_PD5: power-domain-cpu5 { + #power-domain-cells = <0>; + power-domains = <&CLUSTER0_PD>; + }; + + CPU_PD6: power-domain-cpu6 { + #power-domain-cells = <0>; + power-domains = <&CLUSTER1_PD>; + }; + + CPU_PD7: power-domain-cpu7 { + #power-domain-cells = <0>; + power-domains = <&CLUSTER1_PD>; + }; + + CPU_PD8: power-domain-cpu8 { + #power-domain-cells = <0>; + power-domains = <&CLUSTER1_PD>; + }; + + CPU_PD9: power-domain-cpu9 { + #power-domain-cells = <0>; + power-domains = <&CLUSTER1_PD>; + }; + + CPU_PD10: power-domain-cpu10 { + #power-domain-cells = <0>; + power-domains = <&CLUSTER1_PD>; + }; + + CPU_PD11: power-domain-cpu11 { + #power-domain-cells = <0>; + power-domains = <&CLUSTER1_PD>; + }; + + CPU_PD12: power-domain-cpu12 { + #power-domain-cells = <0>; + power-domains = <&CLUSTER2_PD>; + }; + + CPU_PD13: power-domain-cpu13 { + #power-domain-cells = <0>; + power-domains = <&CLUSTER2_PD>; + }; + + CPU_PD14: power-domain-cpu14 { + #power-domain-cells = <0>; + power-domains = <&CLUSTER2_PD>; + }; + + CPU_PD15: power-domain-cpu15 { + #power-domain-cells = <0>; + power-domains = <&CLUSTER2_PD>; + }; + + CPU_PD16: power-domain-cpu16 { + #power-domain-cells = <0>; + power-domains = <&CLUSTER2_PD>; + }; + + CPU_PD17: power-domain-cpu17 { + #power-domain-cells = <0>; + power-domains = <&CLUSTER2_PD>; + }; + + CLUSTER0_PD: power-domain-cpu-cluster0 { + #power-domain-cells = <0>; + power-domains = <&CLUSTER3_PD>; + domain-idle-states = <&cluster0_cl5>; + }; + + CLUSTER1_PD: power-domain-cpu-cluster1 { + #power-domain-cells = <0>; + power-domains = <&CLUSTER3_PD>; + domain-idle-states = <&cluster1_cl5>; + }; + + CLUSTER2_PD: power-domain-cpu-cluster2 { + #power-domain-cells = <0>; + power-domains = <&CLUSTER3_PD>; + domain-idle-states = <&cluster2_cl5>; + }; + + CLUSTER3_PD: power-domain-cpu-cluster3 { + #power-domain-cells = <0>; + domain-idle-states = <&APSS_OFF>; + }; }; soc: soc@0 { @@ -3927,6 +4161,7 @@ , , ; + power-domains = <&CLUSTER3_PD>; apps_bcm_voter: bcm-voter { compatible = "qcom,bcm-voter"; From a6b37fe07c0f694e4beaf2f662f14a0a23e6af08 Mon Sep 17 00:00:00 2001 From: Sibi Sankar Date: Thu, 25 Sep 2025 12:02:14 +0530 Subject: [PATCH 0314/2333] FROMLIST: arm64: dts: qcom: glymur: Enable pdp0 mailbox Enable pdp0 mailbox node on Glymur SoCs. Link: https://lore.kernel.org/lkml/20250925-v3_glymur_introduction-v1-6-24b601bbecc0@oss.qualcomm.com/ Signed-off-by: Pankaj Patil Signed-off-by: Sibi Sankar --- arch/arm64/boot/dts/qcom/glymur.dtsi | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/glymur.dtsi b/arch/arm64/boot/dts/qcom/glymur.dtsi index 66a548400c720..ae013c64e096b 100644 --- a/arch/arm64/boot/dts/qcom/glymur.dtsi +++ b/arch/arm64/boot/dts/qcom/glymur.dtsi @@ -4065,6 +4065,14 @@ interrupts = ; }; + pdp0_mbox: mailbox@17610000 { + compatible = "qcom,glymur-cpucp-mbox", "qcom,x1e80100-cpucp-mbox"; + reg = <0 0x17610000 0 0x8000>, <0 0x19980000 0 0x8000>; + interrupts = ; + #mbox-cells = <1>; + qcom,rx-chans = <0x7>; + }; + timer@17810000 { compatible = "arm,armv7-timer-mem"; reg = <0x0 0x17810000 0x0 0x1000>; From f6f25464005e229ebb344a88f9e9577584ac031a Mon Sep 17 00:00:00 2001 From: Taniya Das Date: Thu, 25 Sep 2025 12:02:15 +0530 Subject: [PATCH 0315/2333] FROMLIST: arm64: dts: qcom: glymur: Enable cpu dvfs for CPU scaling Add sram and scmi nodes required to have a functional cpu dvfs on Glymur SoCs. Link: https://lore.kernel.org/lkml/20250925-v3_glymur_introduction-v1-7-24b601bbecc0@oss.qualcomm.com/ Signed-off-by: Taniya Das Signed-off-by: Pankaj Patil Signed-off-by: Sibi Sankar --- arch/arm64/boot/dts/qcom/glymur.dtsi | 87 ++++++++++++++++------------ 1 file changed, 51 insertions(+), 36 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/glymur.dtsi b/arch/arm64/boot/dts/qcom/glymur.dtsi index ae013c64e096b..d924b4778fd37 100644 --- a/arch/arm64/boot/dts/qcom/glymur.dtsi +++ b/arch/arm64/boot/dts/qcom/glymur.dtsi @@ -46,8 +46,8 @@ compatible = "qcom,oryon"; reg = <0x0 0x0>; enable-method = "psci"; - power-domains = <&CPU_PD0>; - power-domain-names = "psci"; + power-domains = <&CPU_PD0>, <&scmi_perf 0>; + power-domain-names = "psci", "perf"; cpu-idle-states = <&CLUSTER0_C4>; next-level-cache = <&l2_0>; @@ -63,8 +63,8 @@ compatible = "qcom,oryon"; reg = <0x0 0x100>; enable-method = "psci"; - power-domains = <&CPU_PD1>; - power-domain-names = "psci"; + power-domains = <&CPU_PD1>, <&scmi_perf 0>; + power-domain-names = "psci", "perf"; cpu-idle-states = <&CLUSTER0_C4>; next-level-cache = <&l2_0>; }; @@ -74,8 +74,8 @@ compatible = "qcom,oryon"; reg = <0x0 0x200>; enable-method = "psci"; - power-domains = <&CPU_PD2>; - power-domain-names = "psci"; + power-domains = <&CPU_PD2>, <&scmi_perf 0>; + power-domain-names = "psci", "perf"; cpu-idle-states = <&CLUSTER0_C4>; next-level-cache = <&l2_0>; }; @@ -85,8 +85,8 @@ compatible = "qcom,oryon"; reg = <0x0 0x300>; enable-method = "psci"; - power-domains = <&CPU_PD3>; - power-domain-names = "psci"; + power-domains = <&CPU_PD3>, <&scmi_perf 0>; + power-domain-names = "psci", "perf"; cpu-idle-states = <&CLUSTER0_C4>; next-level-cache = <&l2_0>; }; @@ -96,8 +96,8 @@ compatible = "qcom,oryon"; reg = <0x0 0x400>; enable-method = "psci"; - power-domains = <&CPU_PD4>; - power-domain-names = "psci"; + power-domains = <&CPU_PD4>, <&scmi_perf 0>; + power-domain-names = "psci", "perf"; cpu-idle-states = <&CLUSTER0_C4>; next-level-cache = <&l2_0>; }; @@ -107,8 +107,8 @@ compatible = "qcom,oryon"; reg = <0x0 0x500>; enable-method = "psci"; - power-domains = <&CPU_PD5>; - power-domain-names = "psci"; + power-domains = <&CPU_PD5>, <&scmi_perf 0>; + power-domain-names = "psci", "perf"; cpu-idle-states = <&CLUSTER0_C4>; next-level-cache = <&l2_0>; }; @@ -118,8 +118,8 @@ compatible = "qcom,oryon"; reg = <0x0 0x10000>; enable-method = "psci"; - power-domains = <&CPU_PD6>; - power-domain-names = "psci"; + power-domains = <&CPU_PD6>, <&scmi_perf 1>; + power-domain-names = "psci", "perf"; cpu-idle-states = <&CLUSTER1_C4>; next-level-cache = <&l2_1>; @@ -135,8 +135,8 @@ compatible = "qcom,oryon"; reg = <0x0 0x10100>; enable-method = "psci"; - power-domains = <&CPU_PD7>; - power-domain-names = "psci"; + power-domains = <&CPU_PD7>, <&scmi_perf 1>; + power-domain-names = "psci", "perf"; cpu-idle-states = <&CLUSTER1_C4>; next-level-cache = <&l2_1>; }; @@ -146,8 +146,8 @@ compatible = "qcom,oryon"; reg = <0x0 0x10200>; enable-method = "psci"; - power-domains = <&CPU_PD8>; - power-domain-names = "psci"; + power-domains = <&CPU_PD8>, <&scmi_perf 1>; + power-domain-names = "psci", "perf"; cpu-idle-states = <&CLUSTER1_C4>; next-level-cache = <&l2_1>; }; @@ -157,8 +157,8 @@ compatible = "qcom,oryon"; reg = <0x0 0x10300>; enable-method = "psci"; - power-domains = <&CPU_PD9>; - power-domain-names = "psci"; + power-domains = <&CPU_PD9>, <&scmi_perf 1>; + power-domain-names = "psci", "perf"; cpu-idle-states = <&CLUSTER1_C4>; next-level-cache = <&l2_1>; }; @@ -168,8 +168,8 @@ compatible = "qcom,oryon"; reg = <0x0 0x10400>; enable-method = "psci"; - power-domains = <&CPU_PD10>; - power-domain-names = "psci"; + power-domains = <&CPU_PD10>, <&scmi_perf 1>; + power-domain-names = "psci", "perf"; cpu-idle-states = <&CLUSTER1_C4>; next-level-cache = <&l2_1>; }; @@ -179,8 +179,8 @@ compatible = "qcom,oryon"; reg = <0x0 0x10500>; enable-method = "psci"; - power-domains = <&CPU_PD11>; - power-domain-names = "psci"; + power-domains = <&CPU_PD11>, <&scmi_perf 1>; + power-domain-names = "psci", "perf"; cpu-idle-states = <&CLUSTER1_C4>; next-level-cache = <&l2_1>; }; @@ -190,8 +190,8 @@ compatible = "qcom,oryon"; reg = <0x0 0x20000>; enable-method = "psci"; - power-domains = <&CPU_PD12>; - power-domain-names = "psci"; + power-domains = <&CPU_PD12>, <&scmi_perf 2>; + power-domain-names = "psci", "perf"; cpu-idle-states = <&CLUSTER2_C4>; next-level-cache = <&l2_2>; @@ -207,8 +207,8 @@ compatible = "qcom,oryon"; reg = <0x0 0x20100>; enable-method = "psci"; - power-domains = <&CPU_PD13>; - power-domain-names = "psci"; + power-domains = <&CPU_PD13>, <&scmi_perf 2>; + power-domain-names = "psci", "perf"; cpu-idle-states = <&CLUSTER2_C4>; next-level-cache = <&l2_2>; }; @@ -218,8 +218,8 @@ compatible = "qcom,oryon"; reg = <0x0 0x20200>; enable-method = "psci"; - power-domains = <&CPU_PD14>; - power-domain-names = "psci"; + power-domains = <&CPU_PD14>, <&scmi_perf 2>; + power-domain-names = "psci", "perf"; cpu-idle-states = <&CLUSTER2_C4>; next-level-cache = <&l2_2>; }; @@ -229,8 +229,8 @@ compatible = "qcom,oryon"; reg = <0x0 0x20300>; enable-method = "psci"; - power-domains = <&CPU_PD15>; - power-domain-names = "psci"; + power-domains = <&CPU_PD15>, <&scmi_perf 2>; + power-domain-names = "psci", "perf"; cpu-idle-states = <&CLUSTER2_C4>; next-level-cache = <&l2_2>; }; @@ -240,8 +240,8 @@ compatible = "qcom,oryon"; reg = <0x0 0x20400>; enable-method = "psci"; - power-domains = <&CPU_PD16>; - power-domain-names = "psci"; + power-domains = <&CPU_PD16>, <&scmi_perf 2>; + power-domain-names = "psci", "perf"; cpu-idle-states = <&CLUSTER2_C4>; next-level-cache = <&l2_2>; }; @@ -251,8 +251,8 @@ compatible = "qcom,oryon"; reg = <0x0 0x20500>; enable-method = "psci"; - power-domains = <&CPU_PD17>; - power-domain-names = "psci"; + power-domains = <&CPU_PD17>, <&scmi_perf 2>; + power-domain-names = "psci", "perf"; cpu-idle-states = <&CLUSTER2_C4>; next-level-cache = <&l2_2>; }; @@ -397,6 +397,21 @@ interconnects = <&aggre2_noc MASTER_CRYPTO QCOM_ICC_TAG_ALWAYS &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; }; + + scmi { + compatible = "arm,scmi"; + mboxes = <&pdp0_mbox 0>, <&pdp0_mbox 1>; + mbox-names = "tx", "rx"; + shmem = <&cpu_scp_lpri1>, <&cpu_scp_lpri0>; + + #address-cells = <1>; + #size-cells = <0>; + + scmi_perf: protocol@13 { + reg = <0x13>; + #power-domain-cells = <1>; + }; + }; }; reserved-memory { From f8ca1859e1e6a8e4accb480a4915931ff2849dc1 Mon Sep 17 00:00:00 2001 From: Kamal Wadhwa Date: Thu, 25 Sep 2025 12:02:17 +0530 Subject: [PATCH 0316/2333] FROMLIST: arm64: dts: qcom: glymur-crd: Add RPMH regulator rails Add RPMH regulator rails for Glymur CRD. Link: https://lore.kernel.org/lkml/20250925-v3_glymur_introduction-v1-9-24b601bbecc0@oss.qualcomm.com/ Signed-off-by: Kamal Wadhwa Signed-off-by: Pankaj Patil Signed-off-by: Sibi Sankar --- arch/arm64/boot/dts/qcom/glymur-crd.dts | 332 ++++++++++++++++++++++++ 1 file changed, 332 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/glymur-crd.dts b/arch/arm64/boot/dts/qcom/glymur-crd.dts index 4561c0b87b017..e89b81dcb4f47 100644 --- a/arch/arm64/boot/dts/qcom/glymur-crd.dts +++ b/arch/arm64/boot/dts/qcom/glymur-crd.dts @@ -6,6 +6,7 @@ /dts-v1/; #include "glymur.dtsi" +#include / { model = "Qualcomm Technologies, Inc. Glymur CRD"; @@ -66,3 +67,334 @@ &tlmm { gpio-reserved-ranges = <4 4>, <10 2>, <44 4>; /*Security SPI (TPM)*/ }; + +&apps_rsc { + + vph_pwr: vph-pwr-regulator { + compatible = "regulator-fixed"; + regulator-name = "vph_pwr"; + regulator-min-microvolt = <3700000>; + regulator-max-microvolt = <3700000>; + }; + + regulators-0 { + compatible = "qcom,pmh0101-rpmh-regulators"; + qcom,pmic-id = "B_E0"; + + vdd-bob1-supply = <&vph_pwr>; + vdd-bob2-supply = <&vph_pwr>; + vdd-l1-l10-l15-supply = <&vreg_s9f_e0_1p9>; + vdd-l2-l7-l8-l9-l16-supply = <&vreg_bob1_e0>; + vdd-l11-l12-l18-supply = <&vreg_s7f_e0_1p32>; + vdd-l17-supply = <&vreg_bob2_e0>; + + vreg_bob1_e0: bob1 { + regulator-name = "vreg_bob1_e0"; + regulator-min-microvolt = <2200000>; + regulator-max-microvolt = <4224000>; + regulator-initial-mode = ; + }; + + vreg_bob2_e0: bob2 { + regulator-name = "vreg_bob2_e0"; + regulator-min-microvolt = <2540000>; + regulator-max-microvolt = <3600000>; + regulator-initial-mode = ; + }; + + vreg_l1b_e0_1p8: ldo1 { + regulator-name = "vreg_l1b_e0_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + }; + + vreg_l2b_e0_2p9: ldo2 { + regulator-name = "vreg_l2b_e0_2p9"; + regulator-min-microvolt = <2900000>; + regulator-max-microvolt = <3300000>; + regulator-initial-mode = ; + }; + + vreg_l7b_e0_2p79: ldo7 { + regulator-name = "vreg_l7b_e0_2p79"; + regulator-min-microvolt = <2790000>; + regulator-max-microvolt = <3300000>; + regulator-initial-mode = ; + }; + + vreg_l8b_e0_1p50: ldo8 { + regulator-name = "vreg_l8b_e0_1p50"; + regulator-min-microvolt = <1504000>; + regulator-max-microvolt = <3544000>; + regulator-initial-mode = ; + }; + + vreg_l9b_e0_2p7: ldo9 { + regulator-name = "vreg_l9b_e0_2p7"; + regulator-min-microvolt = <2700000>; + regulator-max-microvolt = <3300000>; + regulator-initial-mode = ; + }; + + vreg_l10b_e0_1p8: ldo10 { + regulator-name = "vreg_l10b_e0_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + }; + + vreg_l11b_e0_1p2: ldo11 { + regulator-name = "vreg_l11b_e0_1p2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + }; + + vreg_l12b_e0_1p14: ldo12 { + regulator-name = "vreg_l12b_e0_1p14"; + regulator-min-microvolt = <1140000>; + regulator-max-microvolt = <1260000>; + regulator-initial-mode = ; + }; + + vreg_l15b_e0_1p8: ldo15 { + regulator-name = "vreg_l15b_e0_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + }; + + vreg_l17b_e0_2p4: ldo17 { + regulator-name = "vreg_l17b_e0_2p4"; + regulator-min-microvolt = <2400000>; + regulator-max-microvolt = <2700000>; + regulator-initial-mode = ; + }; + + vreg_l18b_e0_1p2: ldo18 { + regulator-name = "vreg_l18b_e0_1p2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + }; + }; + + regulators-1 { + compatible = "qcom,pmcx0102-rpmh-regulators"; + qcom,pmic-id = "C_E0"; + vdd-s1-supply = <&vph_pwr>; + vdd-s8-supply = <&vph_pwr>; + + vreg_s1c_e0_0p3: smps1 { + regulator-name = "vreg_s1c_e0_0p3"; + regulator-min-microvolt = <300000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + }; + + vreg_s8c_e0_0p3: smps8 { + regulator-name = "vreg_s8c_e0_0p3"; + regulator-min-microvolt = <300000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + }; + }; + + regulators-2 { + compatible = "qcom,pmcx0102-rpmh-regulators"; + qcom,pmic-id = "C_E1"; + + vdd-l2-supply = <&vreg_s7f_e0_1p32>; + vdd-l1-l3-l4-supply = <&vreg_s8f_e0_0p95>; + + vreg_l1c_e1_0p82: ldo1 { + regulator-name = "vreg_l1c_e1_0p82"; + regulator-min-microvolt = <825000>; + regulator-max-microvolt = <958000>; + regulator-initial-mode = ; + }; + + vreg_l2c_e1_1p14: ldo2 { + regulator-name = "vreg_l2c_e1_1p14"; + regulator-min-microvolt = <1140000>; + regulator-max-microvolt = <1300000>; + regulator-initial-mode = ; + }; + + vreg_l3c_e1_0p89: ldo3 { + regulator-name = "vreg_l3c_e1_0p89"; + regulator-min-microvolt = <890000>; + regulator-max-microvolt = <980000>; + regulator-initial-mode = ; + }; + + vreg_l4c_e1_0p72: ldo4 { + regulator-name = "vreg_l4c_e1_0p72"; + regulator-min-microvolt = <720000>; + regulator-max-microvolt = <980000>; + regulator-initial-mode = ; + }; + }; + + regulators-3 { + compatible = "qcom,pmh0110-rpmh-regulators"; + qcom,pmic-id = "F_E0"; + vdd-s7-supply = <&vph_pwr>; + vdd-s8-supply = <&vph_pwr>; + vdd-s9-supply = <&vph_pwr>; + vdd-s10-supply = <&vph_pwr>; + vdd-l2-supply = <&vreg_s8f_e0_0p95>; + vdd-l3-supply = <&vreg_s8f_e0_0p95>; + vdd-l4-supply = <&vreg_s8f_e0_0p95>; + + vreg_s7f_e0_1p32: smps7 { + regulator-name = "vreg_s7f_e0_1p32"; + regulator-min-microvolt = <1320000>; + regulator-max-microvolt = <1352000>; + regulator-initial-mode = ; + }; + + vreg_s8f_e0_0p95: smps8 { + regulator-name = "vreg_s8f_e0_0p95"; + regulator-min-microvolt = <952000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + }; + + vreg_s9f_e0_1p9: smps9 { + regulator-name = "vreg_s9f_e0_1p9"; + regulator-min-microvolt = <1900000>; + regulator-max-microvolt = <2000000>; + regulator-initial-mode = ; + }; + + vreg_s10f_e0_0p3: smps10 { + regulator-name = "vreg_s10f_e0_0p3"; + regulator-min-microvolt = <300000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + }; + + vreg_l2f_e0_0p82: ldo2 { + regulator-name = "vreg_l2f_e0_0p82"; + regulator-min-microvolt = <825000>; + regulator-max-microvolt = <980000>; + regulator-initial-mode = ; + }; + + vreg_l3f_e0_0p72: ldo3 { + regulator-name = "vreg_l3f_e0_0p72"; + regulator-min-microvolt = <720000>; + regulator-max-microvolt = <980000>; + regulator-initial-mode = ; + }; + + vreg_l4f_e0_0p3: ldo4 { + regulator-name = "vreg_l4f_e0_0p3"; + regulator-min-microvolt = <300000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + }; + }; + + regulators-4 { + compatible = "qcom,pmh0110-rpmh-regulators"; + qcom,pmic-id = "F_E1"; + vdd-s1-supply = <&vph_pwr>; + vdd-s3-supply = <&vph_pwr>; + vdd-s5-supply = <&vph_pwr>; + vdd-s6-supply = <&vph_pwr>; + vdd-s7-supply = <&vph_pwr>; + vdd-l1-supply = <&vreg_s8f_e0_0p95>; + vdd-l2-supply = <&vreg_s8f_e0_0p95>; + vdd-l4-supply = <&vreg_s8f_e0_0p95>; + + vreg_s1f_e1_0p3: smps1 { + regulator-name = "vreg_s1f_e1_0p3"; + regulator-min-microvolt = <300000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + }; + + vreg_s5f_e1_0p3: smps5 { + regulator-name = "vreg_s5f_e1_0p3"; + regulator-min-microvolt = <300000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + }; + + vreg_s6f_e1_0p3: smps6 { + regulator-name = "vreg_s6f_e1_0p3"; + regulator-min-microvolt = <300000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + }; + + vreg_s7f_e1_0p3: smps7 { + regulator-name = "vreg_s7f_e1_0p3"; + regulator-min-microvolt = <300000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + }; + + vreg_l1f_e1_0p82: ldo1 { + regulator-name = "vreg_l1f_e1_0p82"; + regulator-min-microvolt = <825000>; + regulator-max-microvolt = <950000>; + regulator-initial-mode = ; + }; + + vreg_l2f_e1_0p83: ldo2 { + regulator-name = "vreg_l2f_e1_0p83"; + regulator-min-microvolt = <830000>; + regulator-max-microvolt = <920000>; + regulator-initial-mode = ; + }; + + vreg_l4f_e1_1p08: ldo4 { + regulator-name = "vreg_l4f_e1_1p08"; + regulator-min-microvolt = <1080000>; + regulator-max-microvolt = <1320000>; + regulator-initial-mode = ; + }; + }; + + regulators-5 { + compatible = "qcom,pmh0110-rpmh-regulators"; + qcom,pmic-id = "H_E0"; + + vdd-l1-supply = <&vreg_s8f_e0_0p95>; + vdd-l2-supply = <&vreg_s8f_e0_0p95>; + vdd-l3-supply = <&vreg_s9f_e0_1p9>; + vdd-l4-supply = <&vreg_s7f_e0_1p32>; + + vreg_l1h_e0_0p89: ldo1 { + regulator-name = "vreg_l1h_e0_0p89"; + regulator-min-microvolt = <825000>; + regulator-max-microvolt = <950000>; + regulator-initial-mode = ; + }; + + vreg_l2h_e0_0p72: ldo2 { + regulator-name = "vreg_l2h_e0_0p72"; + regulator-min-microvolt = <830000>; + regulator-max-microvolt = <920000>; + regulator-initial-mode = ; + }; + + vreg_l3h_e0_0p32: ldo3 { + regulator-name = "vreg_l3h_e0_0p32"; + regulator-min-microvolt = <320000>; + regulator-max-microvolt = <2000000>; + regulator-initial-mode = ; + }; + + vreg_l4h_e0_1p2: ldo4 { + regulator-name = "vreg_l4h_e0_1p2"; + regulator-min-microvolt = <1080000>; + regulator-max-microvolt = <1320000>; + regulator-initial-mode = ; + }; + }; +}; From 4a15fb248e1717c3e93bf9309ae25f4f28dd7532 Mon Sep 17 00:00:00 2001 From: Kamal Wadhwa Date: Thu, 25 Sep 2025 12:02:18 +0530 Subject: [PATCH 0317/2333] FROMLIST: arm64: dts: qcom: glymur: Add SPMI PMIC arbiter device Add spmi-pmic-arb device for the SPMI PMIC arbiter found on Glymur. It has three subnodes corresponding to the SPMI0, SPMI1 & SPMI2 bus controllers. Link: https://lore.kernel.org/lkml/20250925-v3_glymur_introduction-v1-10-24b601bbecc0@oss.qualcomm.com/ Signed-off-by: Kamal Wadhwa Signed-off-by: Pankaj Patil Signed-off-by: Sibi Sankar --- arch/arm64/boot/dts/qcom/glymur.dtsi | 62 ++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/glymur.dtsi b/arch/arm64/boot/dts/qcom/glymur.dtsi index d924b4778fd37..fda6301fdadfc 100644 --- a/arch/arm64/boot/dts/qcom/glymur.dtsi +++ b/arch/arm64/boot/dts/qcom/glymur.dtsi @@ -2577,6 +2577,68 @@ reg = <0x0 0x0c30f000 0x0 0x400>; }; + pmic_arbiter: arbiter@c400000 { + compatible = "qcom,glymur-spmi-pmic-arb"; + reg = <0x0 0x0c400000 0x0 0x00003000>, + <0x0 0x0c900000 0x0 0x00400000>, + <0x0 0x0c4c0000 0x0 0x00400000>, + <0x0 0x0c403000 0x0 0x00008000>; + reg-names = "core", + "chnls", + "obsrvr", + "chnl_map"; + #address-cells = <2>; + #size-cells = <2>; + ranges; + qcom,channel = <0>; + qcom,ee = <0>; + + spmi_bus0: spmi@c426000 { + reg = <0x0 0x0c426000 0x0 0x00004000>, + <0x0 0x0c8c0000 0x0 0x00010000>, + <0x0 0x0c42a000 0x0 0x00008000>; + reg-names = "cnfg", + "intr", + "chnl_owner"; + interrupts-extended = <&pdc 1 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "periph_irq"; + interrupt-controller; + #interrupt-cells = <4>; + #address-cells = <2>; + #size-cells = <0>; + }; + + spmi_bus1: spmi@c437000 { + reg = <0x0 0x0c437000 0x0 0x00004000>, + <0x0 0x0c8d0000 0x0 0x00010000>, + <0x0 0x0c43b000 0x0 0x00008000>; + reg-names = "cnfg", + "intr", + "chnl_owner"; + interrupts-extended = <&pdc 3 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "periph_irq"; + interrupt-controller; + #interrupt-cells = <4>; + #address-cells = <2>; + #size-cells = <0>; + }; + + spmi_bus2: spmi@c48000 { + reg = <0x0 0x0c448000 0x0 0x00004000>, + <0x0 0x0c8e0000 0x0 0x00010000>, + <0x0 0x0c44c000 0x0 0x00008000>; + reg-names = "cnfg", + "intr", + "chnl_owner"; + interrupts-extended = <&pdc 72 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "periph_irq"; + interrupt-controller; + #interrupt-cells = <4>; + #address-cells = <2>; + #size-cells = <0>; + }; + }; + tlmm: pinctrl@f100000 { compatible = "qcom,glymur-tlmm"; reg = <0x0 0x0f100000 0x0 0xf00000>; From 26d2f665a8cca17768577990ea107e3cc373043a Mon Sep 17 00:00:00 2001 From: Kamal Wadhwa Date: Thu, 25 Sep 2025 12:02:19 +0530 Subject: [PATCH 0318/2333] FROMLIST: arm64: dts: qcom: Add PMCX0102 pmic dtsi Add base DTS file for PMCX0102 along with temp-alarm and GPIO nodes. Link: https://lore.kernel.org/lkml/20250925-v3_glymur_introduction-v1-11-24b601bbecc0@oss.qualcomm.com/ Signed-off-by: Kamal Wadhwa Signed-off-by: Pankaj Patil Signed-off-by: Sibi Sankar --- arch/arm64/boot/dts/qcom/pmcx0102.dtsi | 179 +++++++++++++++++++++++++ 1 file changed, 179 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/pmcx0102.dtsi diff --git a/arch/arm64/boot/dts/qcom/pmcx0102.dtsi b/arch/arm64/boot/dts/qcom/pmcx0102.dtsi new file mode 100644 index 0000000000000..839738dda6cd5 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/pmcx0102.dtsi @@ -0,0 +1,179 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#include +#include + +&spmi_bus0 { + pmcx0102_c_e0: pmic@2 { + compatible = "qcom,pmcx0102", "qcom,spmi-pmic"; + reg = <0x2 SPMI_USID>; + #address-cells = <1>; + #size-cells = <0>; + + pmcx0102_c_e0_temp_alarm: temp-alarm@a00 { + compatible = "qcom,spmi-temp-alarm"; + reg = <0xa00>; + interrupts = <0x2 0xa 0x0 IRQ_TYPE_EDGE_BOTH>; + #thermal-sensor-cells = <0>; + }; + + pmcx0102_c_e0_gpios: gpio@8800 { + compatible = "qcom,pmcx0102-gpio", "qcom,spmi-gpio"; + reg = <0x8800>; + gpio-controller; + gpio-ranges = <&pmcx0102_c_e0_gpios 0 0 14>; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; + + pmcx0102_d_e0: pmic@3 { + compatible = "qcom,pmcx0102", "qcom,spmi-pmic"; + reg = <0x3 SPMI_USID>; + #address-cells = <1>; + #size-cells = <0>; + + pmcx0102_d_e0_temp_alarm: temp-alarm@a00 { + compatible = "qcom,spmi-temp-alarm"; + reg = <0xa00>; + interrupts = <0x3 0xa 0x0 IRQ_TYPE_EDGE_BOTH>; + #thermal-sensor-cells = <0>; + }; + + pmcx0102_d_e0_gpios: gpio@8800 { + compatible = "qcom,pmcx0102-gpio", "qcom,spmi-gpio"; + reg = <0x8800>; + gpio-controller; + gpio-ranges = <&pmcx0102_d_e0_gpios 0 0 14>; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; + + pmcx0102_e_e0: pmic@4 { + compatible = "qcom,pmcx0102", "qcom,spmi-pmic"; + reg = <0x4 SPMI_USID>; + #address-cells = <1>; + #size-cells = <0>; + + pmcx0102_e_e0_temp_alarm: temp-alarm@a00 { + compatible = "qcom,spmi-temp-alarm"; + reg = <0xa00>; + interrupts = <0x4 0xa 0x0 IRQ_TYPE_EDGE_BOTH>; + #thermal-sensor-cells = <0>; + }; + + pmcx0102_e_e0_gpios: gpio@8800 { + compatible = "qcom,pmcx0102-gpio", "qcom,spmi-gpio"; + reg = <0x8800>; + gpio-controller; + gpio-ranges = <&pmcx0102_e_e0_gpios 0 0 14>; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; + + pmcx0102_g_e0: pmic@5 { + compatible = "qcom,pmcx0102", "qcom,spmi-pmic"; + reg = <0x6 SPMI_USID>; + #address-cells = <1>; + #size-cells = <0>; + + pmcx0102_g_e0_temp_alarm: temp-alarm@a00 { + compatible = "qcom,spmi-temp-alarm"; + reg = <0xa00>; + interrupts = <0x6 0xa 0x0 IRQ_TYPE_EDGE_BOTH>; + #thermal-sensor-cells = <0>; + }; + + pmcx0102_g_e0_gpios: gpio@8800 { + compatible = "qcom,pmcx0102-gpio", "qcom,spmi-gpio"; + reg = <0x8800>; + gpio-controller; + gpio-ranges = <&pmcx0102_g_e0_gpios 0 0 14>; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; +}; + +&spmi_bus1 { + pmcx0102_c_e1: pmic@2 { + compatible = "qcom,pmcx0102", "qcom,spmi-pmic"; + reg = <0x2 SPMI_USID>; + #address-cells = <1>; + #size-cells = <0>; + + pmcx0102_c_e1_temp_alarm: temp-alarm@a00 { + compatible = "qcom,spmi-temp-alarm"; + reg = <0xa00>; + interrupts = <0x2 0xa 0x0 IRQ_TYPE_EDGE_BOTH>; + #thermal-sensor-cells = <0>; + }; + + pmcx0102_c_e1_gpios: gpio@8800 { + compatible = "qcom,pmcx0102-gpio", "qcom,spmi-gpio"; + reg = <0x8800>; + gpio-controller; + gpio-ranges = <&pmcx0102_c_e1_gpios 0 0 14>; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; + + pmcx0102_d_e1: pmic@3 { + compatible = "qcom,pmcx0102", "qcom,spmi-pmic"; + reg = <0x3 SPMI_USID>; + #address-cells = <1>; + #size-cells = <0>; + + pmcx0102_d_e1_temp_alarm: temp-alarm@a00 { + compatible = "qcom,spmi-temp-alarm"; + reg = <0xa00>; + interrupts = <0x3 0xa 0x0 IRQ_TYPE_EDGE_BOTH>; + #thermal-sensor-cells = <0>; + }; + + pmcx0102_d_e1_gpios: gpio@8800 { + compatible = "qcom,pmcx0102-gpio", "qcom,spmi-gpio"; + reg = <0x8800>; + gpio-controller; + gpio-ranges = <&pmcx0102_d_e1_gpios 0 0 14>; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; + + pmcx0102_e_e1: pmic@4 { + compatible = "qcom,pmcx0102", "qcom,spmi-pmic"; + reg = <0x4 SPMI_USID>; + #address-cells = <1>; + #size-cells = <0>; + + pmcx0102_e_e1_temp_alarm: temp-alarm@a00 { + compatible = "qcom,spmi-temp-alarm"; + reg = <0xa00>; + interrupts = <0x4 0xa 0x0 IRQ_TYPE_EDGE_BOTH>; + #thermal-sensor-cells = <0>; + }; + + pmcx0102_e_e1_gpios: gpio@8800 { + compatible = "qcom,pmcx0102-gpio", "qcom,spmi-gpio"; + reg = <0x8800>; + gpio-controller; + gpio-ranges = <&pmcx0102_e_e0_gpios 0 0 14>; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; +}; From 3ab4ba9a1001f03b1449d8638c764a15801e2a38 Mon Sep 17 00:00:00 2001 From: Kamal Wadhwa Date: Thu, 25 Sep 2025 12:02:21 +0530 Subject: [PATCH 0319/2333] FROMLIST: arm64: dts: qcom: Update pmh0104 dtsi for Glymur CRD Update the pmh0104.dtsi to include multiple instances of PMH0104 DT nodes, one for each SID assigned to this PMIC on the spmi_bus0 and spmi_bus1 in Glymur CRD board. Take care to avoid compilation issue with the existing nodes by gaurding each PMH0104 nodes with `#ifdef` for its corresponding SID macro. So that only the nodes which have the their SID macro defined are the only ones picked for compilation. Link: https://lore.kernel.org/lkml/20250925-v3_glymur_introduction-v1-13-24b601bbecc0@oss.qualcomm.com/ Signed-off-by: Kamal Wadhwa Signed-off-by: Pankaj Patil Signed-off-by: Sibi Sankar --- arch/arm64/boot/dts/qcom/pmh0104.dtsi | 84 +++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/pmh0104.dtsi b/arch/arm64/boot/dts/qcom/pmh0104.dtsi index f5393fdebe957..d3ea7486d842e 100644 --- a/arch/arm64/boot/dts/qcom/pmh0104.dtsi +++ b/arch/arm64/boot/dts/qcom/pmh0104.dtsi @@ -6,7 +6,63 @@ #include #include +&spmi_bus0 { +#ifdef PMH0104_I_E0_SID + pmh0104_i_e0: pmic@PMH0104_I_E0_SID { + compatible = "qcom,pmh0104", "qcom,spmi-pmic"; + reg = ; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + + pmh0104_i_e0_temp_alarm: temp-alarm@a00 { + compatible = "qcom,spmi-temp-alarm"; + reg = <0xa00>; + interrupts = ; + #thermal-sensor-cells = <0>; + }; + + pmh0104_i_e0_gpios: gpio@8800 { + compatible = "qcom,pmh0104-gpio", "qcom,spmi-gpio"; + reg = <0x8800>; + gpio-controller; + gpio-ranges = <&pmh0104_i_e0_gpios 0 0 8>; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; +#endif + +#ifdef PMH0104_J_E0_SID + pmh0104_j_e0: pmic@PMH0104_J_E0_SID { + compatible = "qcom,pmh0104", "qcom,spmi-pmic"; + reg = ; + #address-cells = <1>; + #size-cells = <0>; + + pmh0104_j_e0_temp_alarm: temp-alarm@a00 { + compatible = "qcom,spmi-temp-alarm"; + reg = <0xa00>; + interrupts = ; + #thermal-sensor-cells = <0>; + }; + + pmh0104_j_e0_gpios: gpio@8800 { + compatible = "qcom,pmh0104-gpio", "qcom,spmi-gpio"; + reg = <0x8800>; + gpio-controller; + gpio-ranges = <&pmh0104_j_e0_gpios 0 0 8>; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; +#endif +}; + &spmi_bus1 { +#ifdef PMH0104_J_E1_SID pmh0104_j_e1: pmic@PMH0104_J_E1_SID { compatible = "qcom,pmh0104", "qcom,spmi-pmic"; reg = ; @@ -30,4 +86,32 @@ #interrupt-cells = <2>; }; }; +#endif + +#ifdef PMH0104_L_E1_SID + pmh0104_l_e1: pmic@PMH0104_L_E1_SID { + compatible = "qcom,pmh0104", "qcom,spmi-pmic"; + reg = ; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + + pmh0104_l_e1_temp_alarm: temp-alarm@a00 { + compatible = "qcom,spmi-temp-alarm"; + reg = <0xa00>; + interrupts = ; + #thermal-sensor-cells = <0>; + }; + + pmh0104_l_e1_gpios: gpio@8800 { + compatible = "qcom,pmh0104-gpio", "qcom,spmi-gpio"; + reg = <0x8800>; + gpio-controller; + gpio-ranges = <&pmh0104_l_e1_gpios 0 0 8>; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; +#endif }; From db6fbf06cd95ad47b2bcd2fdb3aab325259e2f2f Mon Sep 17 00:00:00 2001 From: Kamal Wadhwa Date: Thu, 25 Sep 2025 12:02:22 +0530 Subject: [PATCH 0320/2333] FROMLIST: arm64: dts: qcom: Update the pmh0110.dtsi for Glymur Add multiple instance of PMH0110 DT node, one for each assigned SID for this PMIC on the spmi_bus0 and spmi_bus1 on the Glymur CRD. Take care to avoid compilation issue with the existing nodes by gaurding each PMH0110 nodes with `#ifdef` for its corresponding SID macro. So that only the nodes which have the their SID macro defined are the only ones picked for compilation. Link: https://lore.kernel.org/lkml/20250925-v3_glymur_introduction-v1-14-24b601bbecc0@oss.qualcomm.com/ Signed-off-by: Kamal Wadhwa Signed-off-by: Pankaj Patil Signed-off-by: Sibi Sankar --- arch/arm64/boot/dts/qcom/pmh0110.dtsi | 66 ++++++++++++++++++++++++++- 1 file changed, 65 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/pmh0110.dtsi b/arch/arm64/boot/dts/qcom/pmh0110.dtsi index b99c33cba8860..4a5c66e5c9fbc 100644 --- a/arch/arm64/boot/dts/qcom/pmh0110.dtsi +++ b/arch/arm64/boot/dts/qcom/pmh0110.dtsi @@ -7,6 +7,8 @@ #include &spmi_bus0 { + +#ifdef PMH0110_D_E0_SID pmh0110_d_e0: pmic@PMH0110_D_E0_SID { compatible = "qcom,pmh0110", "qcom,spmi-pmic"; reg = ; @@ -31,13 +33,14 @@ #interrupt-cells = <2>; }; }; +#endif +#ifdef PMH0110_F_E0_SID pmh0110_f_e0: pmic@PMH0110_F_E0_SID { compatible = "qcom,pmh0110", "qcom,spmi-pmic"; reg = ; #address-cells = <1>; #size-cells = <0>; - status = "disabled"; pmh0110_f_e0_temp_alarm: temp-alarm@a00 { compatible = "qcom,spmi-temp-alarm"; @@ -56,7 +59,9 @@ #interrupt-cells = <2>; }; }; +#endif +#ifdef PMH0110_G_E0_SID pmh0110_g_e0: pmic@PMH0110_G_E0_SID { compatible = "qcom,pmh0110", "qcom,spmi-pmic"; reg = ; @@ -81,7 +86,36 @@ #interrupt-cells = <2>; }; }; +#endif + +#ifdef PMH0110_H_E0_SID + pmh0110_h_e0: pmic@PMH0110_H_E0_SID { + compatible = "qcom,pmh0110", "qcom,spmi-pmic"; + reg = ; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + + pmh0110_h_e0_temp_alarm: temp-alarm@a00 { + compatible = "qcom,spmi-temp-alarm"; + reg = <0xa00>; + interrupts = ; + #thermal-sensor-cells = <0>; + }; + + pmh0110_h_e0_gpios: gpio@8800 { + compatible = "qcom,pmh0110-gpio", "qcom,spmi-gpio"; + reg = <0x8800>; + gpio-controller; + gpio-ranges = <&pmh0110_h_e0_gpios 0 0 14>; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; +#endif +#ifdef PMH0110_I_E0_SID pmh0110_i_e0: pmic@PMH0110_I_E0_SID { compatible = "qcom,pmh0110", "qcom,spmi-pmic"; reg = ; @@ -106,4 +140,34 @@ #interrupt-cells = <2>; }; }; +#endif +}; + +&spmi_bus1 { +#ifdef PMH0110_F_E1_SID + pmh0110_f_e1: pmic@PMH0110_F_E1_SID { + compatible = "qcom,pmh0110", "qcom,spmi-pmic"; + reg = ; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + + pmh0110_f_e1_temp_alarm: temp-alarm@a00 { + compatible = "qcom,spmi-temp-alarm"; + reg = <0xa00>; + interrupts = ; + #thermal-sensor-cells = <0>; + }; + + pmh0110_f_e1_gpios: gpio@8800 { + compatible = "qcom,pmh0110-gpio", "qcom,spmi-gpio"; + reg = <0x8800>; + gpio-controller; + gpio-ranges = <&pmh0110_f_e1_gpios 0 0 14>; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; +#endif }; From 6d49264dc783ab596b82b8b38bde8137ab08c0a2 Mon Sep 17 00:00:00 2001 From: Kamal Wadhwa Date: Thu, 25 Sep 2025 12:02:23 +0530 Subject: [PATCH 0321/2333] FROMLIST: arm64: dts: qcom: glymur: Add PMICs dtsi for CRD Include all the PMICs present on the Glymur board into the glymur CRD DTS file. Link: https://lore.kernel.org/lkml/20250925-v3_glymur_introduction-v1-15-24b601bbecc0@oss.qualcomm.com/ Signed-off-by: Kamal Wadhwa Signed-off-by: Pankaj Patil Signed-off-by: Sibi Sankar --- arch/arm64/boot/dts/qcom/glymur-crd.dts | 1 + arch/arm64/boot/dts/qcom/glymur-pmics.dtsi | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/glymur-pmics.dtsi diff --git a/arch/arm64/boot/dts/qcom/glymur-crd.dts b/arch/arm64/boot/dts/qcom/glymur-crd.dts index e89b81dcb4f47..97f6eedd72223 100644 --- a/arch/arm64/boot/dts/qcom/glymur-crd.dts +++ b/arch/arm64/boot/dts/qcom/glymur-crd.dts @@ -6,6 +6,7 @@ /dts-v1/; #include "glymur.dtsi" +#include "glymur-pmics.dtsi" #include / { diff --git a/arch/arm64/boot/dts/qcom/glymur-pmics.dtsi b/arch/arm64/boot/dts/qcom/glymur-pmics.dtsi new file mode 100644 index 0000000000000..7f9080b2a86ce --- /dev/null +++ b/arch/arm64/boot/dts/qcom/glymur-pmics.dtsi @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#define PMH0110_F_E0 0x5 +#define PMH0110_H_E0 0x7 +#define PMH0104_I_E0 0x8 +#define PMH0104_J_E0 0x9 + +#define PMH0110_F_E1 0x5 +#define PMH0104_L_E1 0xb + +#include "pmk8850.dtsi" /* SPMI0: SID-0*/ +#include "pmh0101.dtsi" /* SPMI0: SID-1*/ +#include "pmcx0102.dtsi" /* SPMI0: SID-2/3/4/6 SPMI1: SID-2/3/4 */ +#include "pmh0110.dtsi" /* SPMI0: SID-5/7 SPMI1: SID-5 */ +#include "pmh0104.dtsi" /* SPMI0: SID-8/9 SPMI1: SID-11 */ From 00b24a7cf88226d2dcaaa2e9a5884289b2649043 Mon Sep 17 00:00:00 2001 From: Kamal Wadhwa Date: Thu, 25 Sep 2025 12:02:24 +0530 Subject: [PATCH 0322/2333] FROMLIST: arm64: boot: dts: glymur-crd: Add Volume down/up keys support Add Volume Down/Up keys for Glymur CRD. Link: https://lore.kernel.org/lkml/20250925-v3_glymur_introduction-v1-16-24b601bbecc0@oss.qualcomm.com/ Signed-off-by: Kamal Wadhwa Signed-off-by: Pankaj Patil Signed-off-by: Sibi Sankar --- arch/arm64/boot/dts/qcom/glymur-crd.dts | 30 +++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/glymur-crd.dts b/arch/arm64/boot/dts/qcom/glymur-crd.dts index 97f6eedd72223..d6003ae515e37 100644 --- a/arch/arm64/boot/dts/qcom/glymur-crd.dts +++ b/arch/arm64/boot/dts/qcom/glymur-crd.dts @@ -63,12 +63,42 @@ chosen { stdout-path = "serial0:115200n8"; }; + + gpio-keys { + compatible = "gpio-keys"; + + pinctrl-0 = <&key_vol_up_default>; + pinctrl-names = "default"; + + key-volume-up { + label = "Volume Up"; + linux,code = ; + gpios = <&pmh0101_gpios 6 GPIO_ACTIVE_LOW>; + debounce-interval = <15>; + linux,can-disable; + wakeup-source; + }; + }; }; &tlmm { gpio-reserved-ranges = <4 4>, <10 2>, <44 4>; /*Security SPI (TPM)*/ }; +&pmh0101_gpios { + key_vol_up_default: key-vol-up-default-state { + pins = "gpio6"; + function = "gpio"; + output-disable; + bias-pull-up; + }; +}; + +&pon_resin { + linux,code = ; + status = "okay"; +}; + &apps_rsc { vph_pwr: vph-pwr-regulator { From 6f2b9eaa8e528dbb9975f05a4a629d3fc89bc342 Mon Sep 17 00:00:00 2001 From: Kamal Wadhwa Date: Thu, 25 Sep 2025 12:02:25 +0530 Subject: [PATCH 0323/2333] FROMLIST: arm64: dts: qcom: glymur-crd: Avoid RTC probe failure On Glymur boards, the RTC alarm interrupts are routed to SOCCP subsystems and are not available to APPS. This can cause the RTC probe failure as the RTC IRQ registration will fail in probe. Fix this issue by adding `no-alarm` property in the RTC DT node. This will skip the RTC alarm irq registration and the RTC probe will return success. Link: https://lore.kernel.org/lkml/20250925-v3_glymur_introduction-v1-17-24b601bbecc0@oss.qualcomm.com/ Signed-off-by: Kamal Wadhwa Signed-off-by: Pankaj Patil Signed-off-by: Sibi Sankar --- arch/arm64/boot/dts/qcom/glymur-crd.dts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/glymur-crd.dts b/arch/arm64/boot/dts/qcom/glymur-crd.dts index d6003ae515e37..b04c0ed284686 100644 --- a/arch/arm64/boot/dts/qcom/glymur-crd.dts +++ b/arch/arm64/boot/dts/qcom/glymur-crd.dts @@ -429,3 +429,7 @@ }; }; }; + +&pmk8850_rtc { + no-alarm; +}; From 3531c9708e72058ee4c0228394bd713e8da8064b Mon Sep 17 00:00:00 2001 From: Prudhvi Yarlagadda Date: Thu, 25 Sep 2025 12:02:27 +0530 Subject: [PATCH 0324/2333] FROMLIST: arm64: dts: qcom: glymur: Add support for PCIe5 Describe PCIe5 controller and PHY. Also add required system resources like regulators, clocks, interrupts and registers configuration for PCIe5. Link: https://lore.kernel.org/lkml/20250925-v3_glymur_introduction-v1-19-24b601bbecc0@oss.qualcomm.com/ Signed-off-by: Prudhvi Yarlagadda Signed-off-by: Qiang Yu Signed-off-by: Pankaj Patil Signed-off-by: Sibi Sankar --- arch/arm64/boot/dts/qcom/glymur.dtsi | 208 ++++++++++++++++++++++++++- 1 file changed, 207 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/glymur.dtsi b/arch/arm64/boot/dts/qcom/glymur.dtsi index fda6301fdadfc..fbdf479f753a9 100644 --- a/arch/arm64/boot/dts/qcom/glymur.dtsi +++ b/arch/arm64/boot/dts/qcom/glymur.dtsi @@ -950,7 +950,7 @@ <0>, <0>, <0>, - <0>; + <&pcie5_phy>; #clock-cells = <1>; #reset-cells = <1>; #power-domain-cells = <1>; @@ -2510,6 +2510,212 @@ #interconnect-cells = <2>; }; + pcie5: pci@1b40000 { + device_type = "pci"; + compatible = "qcom,glymur-pcie", "qcom,pcie-x1e80100"; + reg = <0x0 0x01b40000 0x0 0x3000>, + <0x7 0xa0000000 0x0 0xf20>, + <0x7 0xa0000f40 0x0 0xa8>, + <0x7 0xb0000000 0x0 0x4000>, + <0x7 0xa0100000 0x0 0x100000>, + <0x0 0x01b43000 0x0 0x1000>; + reg-names = "parf", + "dbi", + "elbi", + "atu", + "config", + "mhi"; + #address-cells = <3>; + #size-cells = <2>; + ranges = <0x02000000 0 0x7a000000 0 0x7a000000 0 0x4000000>; + bus-range = <0 0xff>; + + dma-coherent; + + linux,pci-domain = <5>; + num-lanes = <4>; + max-link-speed = <5>; + + operating-points-v2 = <&pcie5_opp_table>; + + msi-map = <0x0 &gic_its 0xd0000 0x10000>; + + interrupts = , + , + , + , + , + , + , + , + ; + interrupt-names = "msi0", + "msi1", + "msi2", + "msi3", + "msi4", + "msi5", + "msi6", + "msi7", + "global"; + + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 0x7>; + interrupt-map = <0 0 0 1 &intc 0 0 0 526 IRQ_TYPE_LEVEL_HIGH>, + <0 0 0 2 &intc 0 0 0 428 IRQ_TYPE_LEVEL_HIGH>, + <0 0 0 3 &intc 0 0 0 429 IRQ_TYPE_LEVEL_HIGH>, + <0 0 0 4 &intc 0 0 0 435 IRQ_TYPE_LEVEL_HIGH>; + + clocks = <&gcc GCC_PCIE_5_AUX_CLK>, + <&gcc GCC_PCIE_5_CFG_AHB_CLK>, + <&gcc GCC_PCIE_5_MSTR_AXI_CLK>, + <&gcc GCC_PCIE_5_SLV_AXI_CLK>, + <&gcc GCC_PCIE_5_SLV_Q2A_AXI_CLK>, + <&gcc GCC_AGGRE_NOC_PCIE_5_EAST_SF_AXI_CLK>; + clock-names = "aux", + "cfg", + "bus_master", + "bus_slave", + "slave_q2a", + "noc_aggr"; + + assigned-clocks = <&gcc GCC_PCIE_5_AUX_CLK>; + assigned-clock-rates = <19200000>; + + interconnects = <&pcie_east_anoc MASTER_PCIE_5 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>, + <&hsc_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &pcie_east_slv_noc SLAVE_PCIE_5 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "pcie-mem", + "cpu-pcie"; + + resets = <&gcc GCC_PCIE_5_BCR>, + <&gcc GCC_PCIE_5_LINK_DOWN_BCR>; + reset-names = "pci", + "link_down"; + + power-domains = <&gcc GCC_PCIE_5_GDSC>; + + eq-presets-8gts = /bits/ 16 <0x5555 0x5555 0x5555 0x5555>; + eq-presets-16gts = /bits/ 8 <0x55 0x55 0x55 0x55>; + eq-presets-32gts = /bits/ 8 <0x55 0x55 0x55 0x55>; + + status = "disabled"; + + pcie5_opp_table: opp-table { + compatible = "operating-points-v2"; + + /* GEN 1 x1 */ + opp-2500000 { + opp-hz = /bits/ 64 <2500000>; + required-opps = <&rpmhpd_opp_low_svs>; + opp-peak-kBps = <250000 1>; + }; + + /* GEN 1 x2 and GEN 2 x1 */ + opp-5000000 { + opp-hz = /bits/ 64 <5000000>; + required-opps = <&rpmhpd_opp_low_svs>; + opp-peak-kBps = <500000 1>; + }; + + /* GEN 1 x4 and GEN 2 x2 */ + opp-10000000 { + opp-hz = /bits/ 64 <10000000>; + required-opps = <&rpmhpd_opp_low_svs>; + opp-peak-kBps = <1000000 1>; + }; + + /* GEN 2 x4 */ + opp-20000000 { + opp-hz = /bits/ 64 <20000000>; + required-opps = <&rpmhpd_opp_low_svs>; + opp-peak-kBps = <2000000 1>; + }; + + /* GEN 3 x1 */ + opp-8000000 { + opp-hz = /bits/ 64 <8000000>; + required-opps = <&rpmhpd_opp_nom>; + opp-peak-kBps = <984500 1>; + }; + + /* GEN 3 x2 and GEN 4 x1 */ + opp-16000000 { + opp-hz = /bits/ 64 <16000000>; + required-opps = <&rpmhpd_opp_nom>; + opp-peak-kBps = <1969000 1>; + }; + + /* GEN 3 x4, GEN 4 x2 and GEN5 x1*/ + opp-32000000 { + opp-hz = /bits/ 64 <32000000>; + required-opps = <&rpmhpd_opp_nom>; + opp-peak-kBps = <3938000 1>; + }; + + /* GEN 4 x4 and GEN 5 x2 */ + opp-64000000 { + opp-hz = /bits/ 64 <64000000>; + required-opps = <&rpmhpd_opp_nom>; + opp-peak-kBps = <7876000 1>; + }; + + /* GEN 5 x4 */ + opp-128000000 { + opp-hz = /bits/ 64 <128000000>; + required-opps = <&rpmhpd_opp_nom>; + opp-peak-kBps = <15753000 1>; + }; + }; + + pcie5port0: pcie@0 { + device_type = "pci"; + reg = <0x0 0x0 0x0 0x0 0x0>; + bus-range = <0x01 0xff>; + + #address-cells = <3>; + #size-cells = <2>; + ranges; + phys = <&pcie5_phy>; + }; + }; + + pcie5_phy: phy@1b50000 { + compatible = "qcom,glymur-qmp-gen5x4-pcie-phy"; + reg = <0x0 0x01b50000 0x0 0x10000>; + + clocks = <&gcc GCC_PCIE_PHY_5_AUX_CLK>, + <&gcc GCC_PCIE_5_CFG_AHB_CLK>, + <&tcsrcc TCSR_PCIE_1_CLKREF_EN>, + <&gcc GCC_PCIE_5_PHY_RCHNG_CLK>, + <&gcc GCC_PCIE_5_PIPE_CLK>, + <&gcc GCC_PCIE_5_PIPE_DIV2_CLK>; + clock-names = "aux", + "cfg_ahb", + "ref", + "rchng", + "pipe", + "pipediv2"; + + resets = <&gcc GCC_PCIE_5_PHY_BCR>, + <&gcc GCC_PCIE_5_NOCSR_COM_PHY_BCR>; + reset-names = "phy", + "phy_nocsr"; + + assigned-clocks = <&gcc GCC_PCIE_5_PHY_RCHNG_CLK>; + assigned-clock-rates = <100000000>; + + power-domains = <&gcc GCC_PCIE_5_PHY_GDSC>; + + #clock-cells = <0>; + clock-output-names = "pcie5_pipe_clk"; + + #phy-cells = <0>; + + status = "disabled"; + }; + tcsr_mutex: hwlock@1f40000 { compatible = "qcom,tcsr-mutex"; reg = <0x0 0x01f40000 0x0 0x20000>; From 6e186f99af366fcd4e9d2e4e5cbf77198470ade9 Mon Sep 17 00:00:00 2001 From: Qiang Yu Date: Thu, 25 Sep 2025 12:02:28 +0530 Subject: [PATCH 0325/2333] FROMLIST: arm64: dts: qcom: glymur-crd: Add power supply and sideband signal for pcie5 Add perst, wake and clkreq sideband signals and required regulators in PCIe5 controller and PHY device tree node. Link: https://lore.kernel.org/lkml/20250925-v3_glymur_introduction-v1-20-24b601bbecc0@oss.qualcomm.com/ Signed-off-by: Qiang Yu Signed-off-by: Pankaj Patil Reviewed-by: Konrad Dybcio Signed-off-by: Sibi Sankar --- arch/arm64/boot/dts/qcom/glymur-crd.dts | 68 +++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/glymur-crd.dts b/arch/arm64/boot/dts/qcom/glymur-crd.dts index b04c0ed284686..a5113b7b85983 100644 --- a/arch/arm64/boot/dts/qcom/glymur-crd.dts +++ b/arch/arm64/boot/dts/qcom/glymur-crd.dts @@ -79,6 +79,20 @@ wakeup-source; }; }; + + vreg_nvme: regulator-nvme { + compatible = "regulator-fixed"; + + regulator-name = "VREG_NVME_3P3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + + gpio = <&pmh0101_gpios 14 GPIO_ACTIVE_HIGH>; + enable-active-high; + + pinctrl-0 = <&nvme_reg_en>; + pinctrl-names = "default"; + }; }; &tlmm { @@ -433,3 +447,57 @@ &pmk8850_rtc { no-alarm; }; + +&pmh0101_gpios { + nvme_reg_en: nvme-reg-en-state { + pins = "gpio14"; + function = "normal"; + bias-disable; + }; +}; + +&tlmm { + pcie5_default: pcie5-default-state { + clkreq-n-pins { + pins = "gpio153"; + function = "pcie5_clk_req_n"; + drive-strength = <2>; + bias-pull-up; + }; + + perst-n-pins { + pins = "gpio152"; + function = "gpio"; + drive-strength = <2>; + bias-disable; + }; + + wake-n-pins { + pins = "gpio154"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; +}; + +&pcie5 { + vddpe-3v3-supply = <&vreg_nvme>; + + pinctrl-0 = <&pcie5_default>; + pinctrl-names = "default"; + + status = "okay"; +}; + +&pcie5_phy { + vdda-phy-supply = <&vreg_l2f_e0_0p82>; + vdda-pll-supply = <&vreg_l4h_e0_1p2>; + + status = "okay"; +}; + +&pcie5port0 { + perst-gpios = <&tlmm 152 GPIO_ACTIVE_LOW>; + wake-gpios = <&tlmm 154 GPIO_ACTIVE_LOW>; +}; From 205830c6534ff4195ec16aa531f6dbcc4fa487e7 Mon Sep 17 00:00:00 2001 From: Prudhvi Yarlagadda Date: Fri, 17 Oct 2025 18:33:40 -0700 Subject: [PATCH 0326/2333] FROMLIST: dt-bindings: PCI: qcom: Document the Glymur PCIe Controller On the Qualcomm Glymur platform the PCIe host is compatible with the DWC controller present on the X1E80100 platform. So document the PCIe controllers found on Glymur and use the X1E80100 compatible string as a fallback in the schema. Link: https://lore.kernel.org/all/20251017-glymur_pcie-v5-3-82d0c4bd402b@oss.qualcomm.com/ Signed-off-by: Prudhvi Yarlagadda Signed-off-by: Wenbin Yao Acked-by: Rob Herring (Arm) Signed-off-by: Qiang Yu --- .../devicetree/bindings/pci/qcom,pcie-x1e80100.yaml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/pci/qcom,pcie-x1e80100.yaml b/Documentation/devicetree/bindings/pci/qcom,pcie-x1e80100.yaml index 61581ffbfb248..59be6c66b39b5 100644 --- a/Documentation/devicetree/bindings/pci/qcom,pcie-x1e80100.yaml +++ b/Documentation/devicetree/bindings/pci/qcom,pcie-x1e80100.yaml @@ -16,7 +16,12 @@ description: properties: compatible: - const: qcom,pcie-x1e80100 + oneOf: + - const: qcom,pcie-x1e80100 + - items: + - enum: + - qcom,glymur-pcie + - const: qcom,pcie-x1e80100 reg: minItems: 6 From 486bcf7a4a94e54abf5fd9e6cc6bf68eea22a5d6 Mon Sep 17 00:00:00 2001 From: Jyothi Kumar Seerapu Date: Wed, 5 Nov 2025 19:00:42 -0800 Subject: [PATCH 0327/2333] FROMLIST: dt-bindings: dma: qcom,gpi: Document GPI DMA engine for Kaanapali and Glymur SoCs Document the GPI DMA engine on the Kaanapali and Glymur platforms. Link: https://lore.kernel.org/lkml/20251105-knp-bus-v2-1-ed3095c7013a@oss.qualcomm.com/ Signed-off-by: Jyothi Kumar Seerapu Signed-off-by: Pankaj Patil Signed-off-by: Jingyi Wang Reviewed-by: Krzysztof Kozlowski Signed-off-by: Sibi Sankar --- Documentation/devicetree/bindings/dma/qcom,gpi.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/dma/qcom,gpi.yaml b/Documentation/devicetree/bindings/dma/qcom,gpi.yaml index bbe4da2a11054..4cd867854a5fd 100644 --- a/Documentation/devicetree/bindings/dma/qcom,gpi.yaml +++ b/Documentation/devicetree/bindings/dma/qcom,gpi.yaml @@ -24,6 +24,8 @@ properties: - qcom,sm6350-gpi-dma - items: - enum: + - qcom,glymur-gpi-dma + - qcom,kaanapali-gpi-dma - qcom,milos-gpi-dma - qcom,qcm2290-gpi-dma - qcom,qcs8300-gpi-dma From a50984a91bb9d551ee48136ee2db90eca0929979 Mon Sep 17 00:00:00 2001 From: Pankaj Patil Date: Thu, 18 Sep 2025 19:47:38 +0530 Subject: [PATCH 0328/2333] FROMLIST: dt-bindings: firmware: qcom,scm: Document Glymur scm Document the SCM compatible for Qualcomm Glymur SoC. Secure Channel Manager(SCM) is used to communicate with secure firmware. Link: https://lore.kernel.org/all/20250918141738.2524269-1-pankaj.patil@oss.qualcomm.com/ Signed-off-by: Pankaj Patil Acked-by: Rob Herring (Arm) Signed-off-by: Sibi Sankar --- Documentation/devicetree/bindings/firmware/qcom,scm.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/firmware/qcom,scm.yaml b/Documentation/devicetree/bindings/firmware/qcom,scm.yaml index 340b754e63226..d66459f1d84e4 100644 --- a/Documentation/devicetree/bindings/firmware/qcom,scm.yaml +++ b/Documentation/devicetree/bindings/firmware/qcom,scm.yaml @@ -23,6 +23,7 @@ properties: - enum: - qcom,scm-apq8064 - qcom,scm-apq8084 + - qcom,scm-glymur - qcom,scm-ipq4019 - qcom,scm-ipq5018 - qcom,scm-ipq5332 From 2c0e8b5326b2281b2c6c63aaf73442ce97d4a168 Mon Sep 17 00:00:00 2001 From: Jishnu Prakash Date: Wed, 24 Sep 2025 16:43:06 -0700 Subject: [PATCH 0329/2333] FROMLIST: dt-bindings: mfd: qcom,spmi-pmic: Document PMICs present on Kaanapali Document compatibles for the pmh0101, pmh0104, pmh0110 and pmk8850 SPMI PMICs. Signed-off-by: Jishnu Prakash Signed-off-by: Jingyi Wang Link: https://lore.kernel.org/all/20250924-knp-pmic-binding-v1-1-b9cce48b8460@oss.qualcomm.com/ Signed-off-by: Jishnu Prakash --- Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.yaml b/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.yaml index 078a6886f8b1e..427023cb11c5e 100644 --- a/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.yaml +++ b/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.yaml @@ -78,6 +78,9 @@ properties: - qcom,pmc8380 - qcom,pmd8028 - qcom,pmd9635 + - qcom,pmh0101 + - qcom,pmh0104 + - qcom,pmh0110 - qcom,pmi632 - qcom,pmi8950 - qcom,pmi8962 @@ -87,6 +90,7 @@ properties: - qcom,pmk8002 - qcom,pmk8350 - qcom,pmk8550 + - qcom,pmk8850 - qcom,pmm8155au - qcom,pmm8654au - qcom,pmp8074 From c7a9ba0683a15b1bf60e2c9d70f2404f9f183181 Mon Sep 17 00:00:00 2001 From: Jishnu Prakash Date: Wed, 24 Sep 2025 16:43:33 -0700 Subject: [PATCH 0330/2333] FROMLIST: dt-bindings: leds: leds-qcom-lpg: Add support for PMH0101 PWM Add support for PMH0101 PWM modules which are compatible with the PM8350c PWM modules. Signed-off-by: Jishnu Prakash Signed-off-by: Jingyi Wang Link: https://lore.kernel.org/all/20250924-knp-pmic-peri-v2-1-32316039db2f@oss.qualcomm.com/ Signed-off-by: Jishnu Prakash --- Documentation/devicetree/bindings/leds/leds-qcom-lpg.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/leds/leds-qcom-lpg.yaml b/Documentation/devicetree/bindings/leds/leds-qcom-lpg.yaml index 841a0229c472a..1278152e8eed1 100644 --- a/Documentation/devicetree/bindings/leds/leds-qcom-lpg.yaml +++ b/Documentation/devicetree/bindings/leds/leds-qcom-lpg.yaml @@ -38,6 +38,7 @@ properties: - items: - enum: - qcom,pm8550-pwm + - qcom,pmh0101-pwm - const: qcom,pm8350c-pwm - items: - enum: From cee8f43df808c9c45c14f796a5c5a21b2d52ca95 Mon Sep 17 00:00:00 2001 From: Jishnu Prakash Date: Wed, 24 Sep 2025 16:43:34 -0700 Subject: [PATCH 0331/2333] FROMLIST: dt-bindings: leds: qcom,spmi-flash-led: Add PMH0101 compatible Document compatible for PMH0101 Torch and Flash LED controller. Signed-off-by: Jishnu Prakash Signed-off-by: Jingyi Wang Link: https://lore.kernel.org/all/20250924-knp-pmic-peri-v2-2-32316039db2f@oss.qualcomm.com/ Signed-off-by: Jishnu Prakash --- Documentation/devicetree/bindings/leds/qcom,spmi-flash-led.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/leds/qcom,spmi-flash-led.yaml b/Documentation/devicetree/bindings/leds/qcom,spmi-flash-led.yaml index bcf0ad4ea57ea..0df3e460a792b 100644 --- a/Documentation/devicetree/bindings/leds/qcom,spmi-flash-led.yaml +++ b/Documentation/devicetree/bindings/leds/qcom,spmi-flash-led.yaml @@ -28,6 +28,7 @@ properties: - qcom,pm8150l-flash-led - qcom,pm8350c-flash-led - qcom,pm8550-flash-led + - qcom,pmh0101-flash-led - qcom,pmi8998-flash-led - const: qcom,spmi-flash-led From 87f0f2039aeb54ad0610c97d6d0e15b022c95936 Mon Sep 17 00:00:00 2001 From: Anjelique Melendez Date: Fri, 19 Sep 2025 10:50:25 -0700 Subject: [PATCH 0332/2333] FROMGIT: soc: qcom: pmic_glink: Add support for SOCCP remoteproc channels System On Chip Control Processor (SOCCP) is a subsystem that can have battery management firmware running on it to support Type-C/PD and battery charging. SOCCP does not have multiple PDs and hence PDR is not supported. So, if the subsystem comes up/down, rpmsg driver would be probed or removed. Use that for notifying clients of pmic_glink for PDR events. Add support for battery management FW running on SOCCP by adding the "PMIC_RTR_SOCCP_APPS" channel name to the rpmsg_match list and updating notify_clients logic. Signed-off-by: Anjelique Melendez Link: https://lore.kernel.org/all/20250919175025.2988948-1-anjelique.melendez@oss.qualcomm.com/ Signed-off-by: Jishnu Prakash --- drivers/soc/qcom/pmic_glink.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/soc/qcom/pmic_glink.c b/drivers/soc/qcom/pmic_glink.c index aa5ba9a0285e5..13bbc9a5181d2 100644 --- a/drivers/soc/qcom/pmic_glink.c +++ b/drivers/soc/qcom/pmic_glink.c @@ -45,6 +45,7 @@ struct pmic_glink { struct mutex state_lock; unsigned int client_state; unsigned int pdr_state; + bool pdr_available; /* serializing clients list updates */ spinlock_t client_lock; @@ -252,9 +253,12 @@ static int pmic_glink_rpmsg_probe(struct rpmsg_device *rpdev) return dev_err_probe(&rpdev->dev, -ENODEV, "no pmic_glink device to attach to\n"); dev_set_drvdata(&rpdev->dev, pg); + pg->pdr_available = rpdev->id.driver_data; guard(mutex)(&pg->state_lock); pg->ept = rpdev->ept; + if (!pg->pdr_available) + pg->pdr_state = SERVREG_SERVICE_STATE_UP; pmic_glink_state_notify_clients(pg); return 0; @@ -271,11 +275,14 @@ static void pmic_glink_rpmsg_remove(struct rpmsg_device *rpdev) guard(mutex)(&pg->state_lock); pg->ept = NULL; + if (!pg->pdr_available) + pg->pdr_state = SERVREG_SERVICE_STATE_DOWN; pmic_glink_state_notify_clients(pg); } static const struct rpmsg_device_id pmic_glink_rpmsg_id_match[] = { - { "PMIC_RTR_ADSP_APPS" }, + {.name = "PMIC_RTR_ADSP_APPS", .driver_data = true }, + {.name = "PMIC_RTR_SOCCP_APPS", .driver_data = false }, {} }; From 97372deb23bc2fe5d89b8b45ac7f4f97544655da Mon Sep 17 00:00:00 2001 From: Anjelique Melendez Date: Tue, 21 Oct 2025 17:45:53 -0700 Subject: [PATCH 0333/2333] FROMLIST: usb: typec: ucsi_glink: Update request/response buffers to be packed Update the ucsi request/response buffers to be packed to ensure there are no "holes" in memory while we read/write these structs. Signed-off-by: Anjelique Melendez Reviewed-by: Heikki Krogerus Link: https://lore.kernel.org/all/20251022004554.1956729-2-anjelique.melendez@oss.qualcomm.com/ Signed-off-by: Jishnu Prakash --- drivers/usb/typec/ucsi/ucsi_glink.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/usb/typec/ucsi/ucsi_glink.c b/drivers/usb/typec/ucsi/ucsi_glink.c index 8af79101a2fc7..1f9f0d942c1ae 100644 --- a/drivers/usb/typec/ucsi/ucsi_glink.c +++ b/drivers/usb/typec/ucsi/ucsi_glink.c @@ -30,24 +30,24 @@ struct ucsi_read_buf_req_msg { struct pmic_glink_hdr hdr; }; -struct ucsi_read_buf_resp_msg { +struct __packed ucsi_read_buf_resp_msg { struct pmic_glink_hdr hdr; u8 buf[UCSI_BUF_SIZE]; u32 ret_code; }; -struct ucsi_write_buf_req_msg { +struct __packed ucsi_write_buf_req_msg { struct pmic_glink_hdr hdr; u8 buf[UCSI_BUF_SIZE]; u32 reserved; }; -struct ucsi_write_buf_resp_msg { +struct __packed ucsi_write_buf_resp_msg { struct pmic_glink_hdr hdr; u32 ret_code; }; -struct ucsi_notify_ind_msg { +struct __packed ucsi_notify_ind_msg { struct pmic_glink_hdr hdr; u32 notification; u32 receiver; From 8fba65f6e2ddebad2e93252a85e30a35fa99733b Mon Sep 17 00:00:00 2001 From: Anjelique Melendez Date: Tue, 21 Oct 2025 17:45:54 -0700 Subject: [PATCH 0334/2333] FROMLIST: usb: typec: ucsi_glink: Increase buffer size to support UCSI v2 UCSI v2 specification has increased the MSG_IN and MSG_OUT size from 16 bytes to 256 bytes each for the message exchange between OPM and PPM This makes the total buffer size increase from 48 bytes to 528 bytes. Update the buffer size to support this increase. Signed-off-by: Anjelique Melendez Reviewed-by: Heikki Krogerus Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/all/20251022004554.1956729-3-anjelique.melendez@oss.qualcomm.com/ Signed-off-by: Jishnu Prakash --- drivers/usb/typec/ucsi/ucsi_glink.c | 80 +++++++++++++++++++++++++---- 1 file changed, 70 insertions(+), 10 deletions(-) diff --git a/drivers/usb/typec/ucsi/ucsi_glink.c b/drivers/usb/typec/ucsi/ucsi_glink.c index 1f9f0d942c1ae..11b3e24e34e2b 100644 --- a/drivers/usb/typec/ucsi/ucsi_glink.c +++ b/drivers/usb/typec/ucsi/ucsi_glink.c @@ -16,10 +16,10 @@ #define PMIC_GLINK_MAX_PORTS 3 -#define UCSI_BUF_SIZE 48 +#define UCSI_BUF_V1_SIZE (UCSI_MESSAGE_OUT + (UCSI_MESSAGE_OUT - UCSI_MESSAGE_IN)) +#define UCSI_BUF_V2_SIZE (UCSIv2_MESSAGE_OUT + (UCSIv2_MESSAGE_OUT - UCSI_MESSAGE_IN)) #define MSG_TYPE_REQ_RESP 1 -#define UCSI_BUF_SIZE 48 #define UC_NOTIFY_RECEIVER_UCSI 0x0 #define UC_UCSI_READ_BUF_REQ 0x11 @@ -32,13 +32,19 @@ struct ucsi_read_buf_req_msg { struct __packed ucsi_read_buf_resp_msg { struct pmic_glink_hdr hdr; - u8 buf[UCSI_BUF_SIZE]; + union { + u8 v2_buf[UCSI_BUF_V2_SIZE]; + u8 v1_buf[UCSI_BUF_V1_SIZE]; + } buf; u32 ret_code; }; struct __packed ucsi_write_buf_req_msg { struct pmic_glink_hdr hdr; - u8 buf[UCSI_BUF_SIZE]; + union { + u8 v2_buf[UCSI_BUF_V2_SIZE]; + u8 v1_buf[UCSI_BUF_V1_SIZE]; + } buf; u32 reserved; }; @@ -72,7 +78,7 @@ struct pmic_glink_ucsi { bool ucsi_registered; bool pd_running; - u8 read_buf[UCSI_BUF_SIZE]; + u8 read_buf[UCSI_BUF_V2_SIZE]; }; static int pmic_glink_ucsi_read(struct ucsi *__ucsi, unsigned int offset, @@ -132,17 +138,35 @@ static int pmic_glink_ucsi_locked_write(struct pmic_glink_ucsi *ucsi, unsigned i const void *val, size_t val_len) { struct ucsi_write_buf_req_msg req = {}; + size_t req_len, buf_len; unsigned long left; int ret; + u8 *buf; req.hdr.owner = PMIC_GLINK_OWNER_USBC; req.hdr.type = MSG_TYPE_REQ_RESP; req.hdr.opcode = UC_UCSI_WRITE_BUF_REQ; - memcpy(&req.buf[offset], val, val_len); + + if (ucsi->ucsi->version >= UCSI_VERSION_2_0) { + buf_len = UCSI_BUF_V2_SIZE; + buf = req.buf.v2_buf; + } else if (ucsi->ucsi->version) { + buf_len = UCSI_BUF_V1_SIZE; + buf = req.buf.v1_buf; + } else { + dev_err(ucsi->dev, "UCSI version unknown\n"); + return -EINVAL; + } + req_len = sizeof(struct pmic_glink_hdr) + buf_len + sizeof(u32); + + if (offset + val_len > buf_len) + return -EINVAL; + + memcpy(&buf[offset], val, val_len); reinit_completion(&ucsi->write_ack); - ret = pmic_glink_send(ucsi->client, &req, sizeof(req)); + ret = pmic_glink_send(ucsi->client, &req, req_len); if (ret < 0) { dev_err(ucsi->dev, "failed to send UCSI write request: %d\n", ret); return ret; @@ -216,12 +240,48 @@ static const struct ucsi_operations pmic_glink_ucsi_ops = { static void pmic_glink_ucsi_read_ack(struct pmic_glink_ucsi *ucsi, const void *data, int len) { - const struct ucsi_read_buf_resp_msg *resp = data; + u32 ret_code, resp_len, buf_len = 0; + u8 *buf; + + if (ucsi->ucsi->version) { + if (ucsi->ucsi->version >= UCSI_VERSION_2_0) { + buf = ((struct ucsi_read_buf_resp_msg *)data)->buf.v2_buf; + buf_len = UCSI_BUF_V2_SIZE; + } else { + buf = ((struct ucsi_read_buf_resp_msg *)data)->buf.v1_buf; + buf_len = UCSI_BUF_V1_SIZE; + } + } else if (!ucsi->ucsi_registered) { + /* + * If UCSI version is not known yet because device is not registered, choose buffer + * size which best fits incoming data + */ + if (len > sizeof(struct pmic_glink_hdr) + UCSI_BUF_V2_SIZE) { + buf = ((struct ucsi_read_buf_resp_msg *)data)->buf.v2_buf; + buf_len = UCSI_BUF_V2_SIZE; + } else { + buf = ((struct ucsi_read_buf_resp_msg *)data)->buf.v1_buf; + buf_len = UCSI_BUF_V1_SIZE; + } + } else { + dev_err(ucsi->dev, "Device has been registered but UCSI version is still unknown\n"); + return; + } - if (resp->ret_code) + resp_len = sizeof(struct pmic_glink_hdr) + buf_len + sizeof(u32); + + if (len > resp_len) + return; + + /* Ensure that buffer_len leaves space for ret_code to be read back from memory */ + if (buf_len > len - sizeof(struct pmic_glink_hdr) - sizeof(u32)) + buf_len = len - sizeof(struct pmic_glink_hdr) - sizeof(u32); + + memcpy(&ret_code, buf + buf_len, sizeof(u32)); + if (ret_code) return; - memcpy(ucsi->read_buf, resp->buf, UCSI_BUF_SIZE); + memcpy(ucsi->read_buf, buf, buf_len); complete(&ucsi->read_ack); } From b1966182caa723b36e0885eb2e5af3b07a62970e Mon Sep 17 00:00:00 2001 From: Mukesh Ojha Date: Fri, 21 Nov 2025 16:31:03 +0530 Subject: [PATCH 0335/2333] FROMLIST: dt-bindings: remoteproc: qcom,pas: Add iommus property On most Qualcomm platforms, the Qualcomm Hypervisor Execution Environment (QHEE) is either used as a standalone hypervisor or co-exists as a module with the Gunyah hypervisor. When QHEE is present, it configures firmware streams for remote processors. If QHEE is not available, the operating system must perform these configurations instead and for that remote processor firmware stream should be presented to the operating system. To support this, add the iommus property as an optional property for PAS-supported devices. Link: https://lore.kernel.org/lkml/20251121-kvm_rproc_v8-v8-1-8e8e9fb0eca0@oss.qualcomm.com/ Acked-by: Rob Herring (Arm) Reviewed-by: Bryan O'Donoghue Signed-off-by: Mukesh Ojha --- .../devicetree/bindings/remoteproc/qcom,pas-common.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml index 63a82e7a8bf88..68c17bf18987c 100644 --- a/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml +++ b/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml @@ -44,6 +44,9 @@ properties: - const: stop-ack - const: shutdown-ack + iommus: + maxItems: 1 + power-domains: minItems: 1 maxItems: 3 From d329c414ca91ace81ee36ac434be8e28075d6a6e Mon Sep 17 00:00:00 2001 From: Mukesh Ojha Date: Fri, 21 Nov 2025 16:31:04 +0530 Subject: [PATCH 0336/2333] FROMLIST: firmware: qcom_scm: Remove redundant piece of code The qcom_scm_pas_metadata_release() function already frees the allocated memory and sets ctx->ptr to NULL. Resetting ctx->phys and ctx->size to zero is unnecessary because the context is expected to be discarded after release. Lets removes redundant assignments. Link: https://lore.kernel.org/lkml/20251121-kvm_rproc_v8-v8-2-8e8e9fb0eca0@oss.qualcomm.com/ Signed-off-by: Mukesh Ojha --- drivers/firmware/qcom/qcom_scm.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/firmware/qcom/qcom_scm.c b/drivers/firmware/qcom/qcom_scm.c index e777b7cb9b127..26969bcd763ce 100644 --- a/drivers/firmware/qcom/qcom_scm.c +++ b/drivers/firmware/qcom/qcom_scm.c @@ -650,8 +650,6 @@ void qcom_scm_pas_metadata_release(struct qcom_scm_pas_metadata *ctx) dma_free_coherent(__scm->dev, ctx->size, ctx->ptr, ctx->phys); ctx->ptr = NULL; - ctx->phys = 0; - ctx->size = 0; } EXPORT_SYMBOL_GPL(qcom_scm_pas_metadata_release); From 43fc6b4fc625dfd2082c1554f951328483eeb655 Mon Sep 17 00:00:00 2001 From: Mukesh Ojha Date: Fri, 21 Nov 2025 16:31:05 +0530 Subject: [PATCH 0337/2333] FROMLIST: firmware: qcom_scm: Rename peripheral as pas_id Peripheral and pas_id refers to unique id for a subsystem and used only when peripheral authentication service from secure world is utilized. Lets rename peripheral to pas_id to reflect closer to its meaning. Link: https://lore.kernel.org/lkml/20251121-kvm_rproc_v8-v8-3-8e8e9fb0eca0@oss.qualcomm.com/ Reviewed-by: Bryan O'Donoghue Reviewed-by: Konrad Dybcio Signed-off-by: Mukesh Ojha --- drivers/firmware/qcom/qcom_scm.c | 30 +++++++++++++------------- include/linux/firmware/qcom/qcom_scm.h | 10 ++++----- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/drivers/firmware/qcom/qcom_scm.c b/drivers/firmware/qcom/qcom_scm.c index 26969bcd763ce..0a0c48fca7cfd 100644 --- a/drivers/firmware/qcom/qcom_scm.c +++ b/drivers/firmware/qcom/qcom_scm.c @@ -562,7 +562,7 @@ static void qcom_scm_set_download_mode(u32 dload_mode) * qcom_scm_pas_init_image() - Initialize peripheral authentication service * state machine for a given peripheral, using the * metadata - * @peripheral: peripheral id + * @pas_id: peripheral authentication service id * @metadata: pointer to memory containing ELF header, program header table * and optional blob of data used for authenticating the metadata * and the rest of the firmware @@ -575,7 +575,7 @@ static void qcom_scm_set_download_mode(u32 dload_mode) * track the metadata allocation, this needs to be released by invoking * qcom_scm_pas_metadata_release() by the caller. */ -int qcom_scm_pas_init_image(u32 peripheral, const void *metadata, size_t size, +int qcom_scm_pas_init_image(u32 pas_id, const void *metadata, size_t size, struct qcom_scm_pas_metadata *ctx) { dma_addr_t mdata_phys; @@ -585,7 +585,7 @@ int qcom_scm_pas_init_image(u32 peripheral, const void *metadata, size_t size, .svc = QCOM_SCM_SVC_PIL, .cmd = QCOM_SCM_PIL_PAS_INIT_IMAGE, .arginfo = QCOM_SCM_ARGS(2, QCOM_SCM_VAL, QCOM_SCM_RW), - .args[0] = peripheral, + .args[0] = pas_id, .owner = ARM_SMCCC_OWNER_SIP, }; struct qcom_scm_res res; @@ -656,20 +656,20 @@ EXPORT_SYMBOL_GPL(qcom_scm_pas_metadata_release); /** * qcom_scm_pas_mem_setup() - Prepare the memory related to a given peripheral * for firmware loading - * @peripheral: peripheral id + * @pas_id: peripheral authentication service id * @addr: start address of memory area to prepare * @size: size of the memory area to prepare * * Returns 0 on success. */ -int qcom_scm_pas_mem_setup(u32 peripheral, phys_addr_t addr, phys_addr_t size) +int qcom_scm_pas_mem_setup(u32 pas_id, phys_addr_t addr, phys_addr_t size) { int ret; struct qcom_scm_desc desc = { .svc = QCOM_SCM_SVC_PIL, .cmd = QCOM_SCM_PIL_PAS_MEM_SETUP, .arginfo = QCOM_SCM_ARGS(3), - .args[0] = peripheral, + .args[0] = pas_id, .args[1] = addr, .args[2] = size, .owner = ARM_SMCCC_OWNER_SIP, @@ -697,18 +697,18 @@ EXPORT_SYMBOL_GPL(qcom_scm_pas_mem_setup); /** * qcom_scm_pas_auth_and_reset() - Authenticate the given peripheral firmware * and reset the remote processor - * @peripheral: peripheral id + * @pas_id: peripheral authentication service id * * Return 0 on success. */ -int qcom_scm_pas_auth_and_reset(u32 peripheral) +int qcom_scm_pas_auth_and_reset(u32 pas_id) { int ret; struct qcom_scm_desc desc = { .svc = QCOM_SCM_SVC_PIL, .cmd = QCOM_SCM_PIL_PAS_AUTH_AND_RESET, .arginfo = QCOM_SCM_ARGS(1), - .args[0] = peripheral, + .args[0] = pas_id, .owner = ARM_SMCCC_OWNER_SIP, }; struct qcom_scm_res res; @@ -733,18 +733,18 @@ EXPORT_SYMBOL_GPL(qcom_scm_pas_auth_and_reset); /** * qcom_scm_pas_shutdown() - Shut down the remote processor - * @peripheral: peripheral id + * @pas_id: peripheral authentication service id * * Returns 0 on success. */ -int qcom_scm_pas_shutdown(u32 peripheral) +int qcom_scm_pas_shutdown(u32 pas_id) { int ret; struct qcom_scm_desc desc = { .svc = QCOM_SCM_SVC_PIL, .cmd = QCOM_SCM_PIL_PAS_SHUTDOWN, .arginfo = QCOM_SCM_ARGS(1), - .args[0] = peripheral, + .args[0] = pas_id, .owner = ARM_SMCCC_OWNER_SIP, }; struct qcom_scm_res res; @@ -770,18 +770,18 @@ EXPORT_SYMBOL_GPL(qcom_scm_pas_shutdown); /** * qcom_scm_pas_supported() - Check if the peripheral authentication service is * available for the given peripherial - * @peripheral: peripheral id + * @pas_id: peripheral authentication service id * * Returns true if PAS is supported for this peripheral, otherwise false. */ -bool qcom_scm_pas_supported(u32 peripheral) +bool qcom_scm_pas_supported(u32 pas_id) { int ret; struct qcom_scm_desc desc = { .svc = QCOM_SCM_SVC_PIL, .cmd = QCOM_SCM_PIL_PAS_IS_SUPPORTED, .arginfo = QCOM_SCM_ARGS(1), - .args[0] = peripheral, + .args[0] = pas_id, .owner = ARM_SMCCC_OWNER_SIP, }; struct qcom_scm_res res; diff --git a/include/linux/firmware/qcom/qcom_scm.h b/include/linux/firmware/qcom/qcom_scm.h index a55ca771286bf..a13f703b16cd4 100644 --- a/include/linux/firmware/qcom/qcom_scm.h +++ b/include/linux/firmware/qcom/qcom_scm.h @@ -72,13 +72,13 @@ struct qcom_scm_pas_metadata { ssize_t size; }; -int qcom_scm_pas_init_image(u32 peripheral, const void *metadata, size_t size, +int qcom_scm_pas_init_image(u32 pas_id, const void *metadata, size_t size, struct qcom_scm_pas_metadata *ctx); void qcom_scm_pas_metadata_release(struct qcom_scm_pas_metadata *ctx); -int qcom_scm_pas_mem_setup(u32 peripheral, phys_addr_t addr, phys_addr_t size); -int qcom_scm_pas_auth_and_reset(u32 peripheral); -int qcom_scm_pas_shutdown(u32 peripheral); -bool qcom_scm_pas_supported(u32 peripheral); +int qcom_scm_pas_mem_setup(u32 pas_id, phys_addr_t addr, phys_addr_t size); +int qcom_scm_pas_auth_and_reset(u32 pas_id); +int qcom_scm_pas_shutdown(u32 pas_id); +bool qcom_scm_pas_supported(u32 pas_id); int qcom_scm_io_readl(phys_addr_t addr, unsigned int *val); int qcom_scm_io_writel(phys_addr_t addr, unsigned int val); From f966b3af0c4c100e9313917535d2f13d4dca95ad Mon Sep 17 00:00:00 2001 From: Mukesh Ojha Date: Fri, 21 Nov 2025 16:31:06 +0530 Subject: [PATCH 0338/2333] FROMLIST: firmware: qcom_scm: Introduce PAS context initialization helper function When the Peripheral Authentication Service (PAS) method runs on a SoC where Linux operates at EL2 (i.e., without the Gunyah hypervisor), the reset sequences are handled by TrustZone. In such cases, Linux must perform additional steps before invoking PAS SMC calls, such as creating a SHM bridge. Therefore, PAS SMC calls require awareness and handling of these additional steps when Linux runs at EL2. To support this, there is a need for a data structure that can be initialized prior to invoking any SMC or MDT functions. This structure allows those functions to determine whether they are operating in the presence or absence of the Gunyah hypervisor and behave accordingly. Currently, remoteproc and non-remoteproc subsystems use different variants of the MDT loader helper API, primarily due to differences in metadata context handling. Remoteproc subsystems retain the metadata context until authentication and reset are completed, while non-remoteproc subsystems (e.g., video, graphics, IPA, etc.) do not retain the metadata context and can free it within the qcom_scm_pas_init() call by passing a NULL context parameter and due to these differences, it is not possible to extend metadata context handling to support remoteproc and non remoteproc subsystem use PAS operations, when Linux operates at EL2. Add PAS context data structure and initialization helper function. Link: https://lore.kernel.org/lkml/20251121-kvm_rproc_v8-v8-4-8e8e9fb0eca0@oss.qualcomm.com/ Signed-off-by: Mukesh Ojha --- drivers/firmware/qcom/qcom_scm.c | 34 ++++++++++++++++++++++++++ include/linux/firmware/qcom/qcom_scm.h | 14 +++++++++++ 2 files changed, 48 insertions(+) diff --git a/drivers/firmware/qcom/qcom_scm.c b/drivers/firmware/qcom/qcom_scm.c index 0a0c48fca7cfd..e9e9d03ea36ad 100644 --- a/drivers/firmware/qcom/qcom_scm.c +++ b/drivers/firmware/qcom/qcom_scm.c @@ -558,6 +558,40 @@ static void qcom_scm_set_download_mode(u32 dload_mode) dev_err(__scm->dev, "failed to set download mode: %d\n", ret); } +/** + * devm_qcom_scm_pas_context_init() - Initialize peripheral authentication service + * context for a given peripheral + * + * PAS context is device-resource managed, so the caller does not need + * to worry about freeing the context memory. + * + * @dev: PAS firmware device + * @pas_id: peripheral authentication service id + * @mem_phys: Subsystem reserve memory start address + * @mem_size: Subsystem reserve memory size + * + * Upon successful, returns the PAS context or ERR_PTR() of the error otherwise. + */ +struct qcom_scm_pas_context *devm_qcom_scm_pas_context_init(struct device *dev, + u32 pas_id, + phys_addr_t mem_phys, + size_t mem_size) +{ + struct qcom_scm_pas_context *ctx; + + ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return ERR_PTR(-ENOMEM); + + ctx->dev = dev; + ctx->pas_id = pas_id; + ctx->mem_phys = mem_phys; + ctx->mem_size = mem_size; + + return ctx; +} +EXPORT_SYMBOL_GPL(devm_qcom_scm_pas_context_init); + /** * qcom_scm_pas_init_image() - Initialize peripheral authentication service * state machine for a given peripheral, using the diff --git a/include/linux/firmware/qcom/qcom_scm.h b/include/linux/firmware/qcom/qcom_scm.h index a13f703b16cd4..4a57fa676513b 100644 --- a/include/linux/firmware/qcom/qcom_scm.h +++ b/include/linux/firmware/qcom/qcom_scm.h @@ -72,6 +72,20 @@ struct qcom_scm_pas_metadata { ssize_t size; }; +struct qcom_scm_pas_context { + struct device *dev; + u32 pas_id; + phys_addr_t mem_phys; + size_t mem_size; + void *ptr; + dma_addr_t phys; + ssize_t size; +}; + +struct qcom_scm_pas_context *devm_qcom_scm_pas_context_init(struct device *dev, + u32 pas_id, + phys_addr_t mem_phys, + size_t mem_size); int qcom_scm_pas_init_image(u32 pas_id, const void *metadata, size_t size, struct qcom_scm_pas_metadata *ctx); void qcom_scm_pas_metadata_release(struct qcom_scm_pas_metadata *ctx); From 81beeeb47330130c98c456e756c7181483dc6dbb Mon Sep 17 00:00:00 2001 From: Mukesh Ojha Date: Fri, 21 Nov 2025 16:31:07 +0530 Subject: [PATCH 0339/2333] FROMLIST: remoteproc: pas: Replace metadata context with PAS context structure As a superset of the existing metadata context, the PAS context structure enables both remoteproc and non-remoteproc subsystems to better support scenarios where the SoC runs with or without the Gunyah hypervisor. To reflect this, relevant SCM and metadata functions are updated to incorporate PAS context awareness and remove metadata context data structure completely. Link: https://lore.kernel.org/lkml/20251121-kvm_rproc_v8-v8-5-8e8e9fb0eca0@oss.qualcomm.com/ Signed-off-by: Mukesh Ojha --- drivers/firmware/qcom/qcom_scm.c | 8 +++--- drivers/remoteproc/qcom_q6v5_pas.c | 38 ++++++++++++++++++-------- drivers/soc/qcom/mdt_loader.c | 4 +-- include/linux/firmware/qcom/qcom_scm.h | 10 ++----- include/linux/soc/qcom/mdt_loader.h | 6 ++-- 5 files changed, 38 insertions(+), 28 deletions(-) diff --git a/drivers/firmware/qcom/qcom_scm.c b/drivers/firmware/qcom/qcom_scm.c index e9e9d03ea36ad..5fa974683ee00 100644 --- a/drivers/firmware/qcom/qcom_scm.c +++ b/drivers/firmware/qcom/qcom_scm.c @@ -601,7 +601,7 @@ EXPORT_SYMBOL_GPL(devm_qcom_scm_pas_context_init); * and optional blob of data used for authenticating the metadata * and the rest of the firmware * @size: size of the metadata - * @ctx: optional metadata context + * @ctx: optional pas context * * Return: 0 on success. * @@ -610,7 +610,7 @@ EXPORT_SYMBOL_GPL(devm_qcom_scm_pas_context_init); * qcom_scm_pas_metadata_release() by the caller. */ int qcom_scm_pas_init_image(u32 pas_id, const void *metadata, size_t size, - struct qcom_scm_pas_metadata *ctx) + struct qcom_scm_pas_context *ctx) { dma_addr_t mdata_phys; void *mdata_buf; @@ -674,9 +674,9 @@ EXPORT_SYMBOL_GPL(qcom_scm_pas_init_image); /** * qcom_scm_pas_metadata_release() - release metadata context - * @ctx: metadata context + * @ctx: pas context */ -void qcom_scm_pas_metadata_release(struct qcom_scm_pas_metadata *ctx) +void qcom_scm_pas_metadata_release(struct qcom_scm_pas_context *ctx) { if (!ctx->ptr) return; diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c index 158bcd6cc85c5..729e7b9bc1831 100644 --- a/drivers/remoteproc/qcom_q6v5_pas.c +++ b/drivers/remoteproc/qcom_q6v5_pas.c @@ -117,8 +117,8 @@ struct qcom_pas { struct qcom_rproc_ssr ssr_subdev; struct qcom_sysmon *sysmon; - struct qcom_scm_pas_metadata pas_metadata; - struct qcom_scm_pas_metadata dtb_pas_metadata; + struct qcom_scm_pas_context *pas_ctx; + struct qcom_scm_pas_context *dtb_pas_ctx; }; static void qcom_pas_segment_dump(struct rproc *rproc, @@ -211,9 +211,9 @@ static int qcom_pas_unprepare(struct rproc *rproc) * auth_and_reset() was successful, but in other cases clean it up * here. */ - qcom_scm_pas_metadata_release(&pas->pas_metadata); + qcom_scm_pas_metadata_release(pas->pas_ctx); if (pas->dtb_pas_id) - qcom_scm_pas_metadata_release(&pas->dtb_pas_metadata); + qcom_scm_pas_metadata_release(pas->dtb_pas_ctx); return 0; } @@ -241,7 +241,7 @@ static int qcom_pas_load(struct rproc *rproc, const struct firmware *fw) ret = qcom_mdt_pas_init(pas->dev, pas->dtb_firmware, pas->dtb_firmware_name, pas->dtb_pas_id, pas->dtb_mem_phys, - &pas->dtb_pas_metadata); + pas->dtb_pas_ctx); if (ret) goto release_dtb_firmware; @@ -255,7 +255,7 @@ static int qcom_pas_load(struct rproc *rproc, const struct firmware *fw) return 0; release_dtb_metadata: - qcom_scm_pas_metadata_release(&pas->dtb_pas_metadata); + qcom_scm_pas_metadata_release(pas->dtb_pas_ctx); release_dtb_firmware: release_firmware(pas->dtb_firmware); @@ -306,7 +306,7 @@ static int qcom_pas_start(struct rproc *rproc) } ret = qcom_mdt_pas_init(pas->dev, pas->firmware, rproc->firmware, pas->pas_id, - pas->mem_phys, &pas->pas_metadata); + pas->mem_phys, pas->pas_ctx); if (ret) goto disable_px_supply; @@ -332,9 +332,9 @@ static int qcom_pas_start(struct rproc *rproc) goto release_pas_metadata; } - qcom_scm_pas_metadata_release(&pas->pas_metadata); + qcom_scm_pas_metadata_release(pas->pas_ctx); if (pas->dtb_pas_id) - qcom_scm_pas_metadata_release(&pas->dtb_pas_metadata); + qcom_scm_pas_metadata_release(pas->dtb_pas_ctx); /* firmware is used to pass reference from qcom_pas_start(), drop it now */ pas->firmware = NULL; @@ -342,9 +342,9 @@ static int qcom_pas_start(struct rproc *rproc) return 0; release_pas_metadata: - qcom_scm_pas_metadata_release(&pas->pas_metadata); + qcom_scm_pas_metadata_release(pas->pas_ctx); if (pas->dtb_pas_id) - qcom_scm_pas_metadata_release(&pas->dtb_pas_metadata); + qcom_scm_pas_metadata_release(pas->dtb_pas_ctx); disable_px_supply: if (pas->px_supply) regulator_disable(pas->px_supply); @@ -779,6 +779,22 @@ static int qcom_pas_probe(struct platform_device *pdev) } qcom_add_ssr_subdev(rproc, &pas->ssr_subdev, desc->ssr_name); + + pas->pas_ctx = devm_qcom_scm_pas_context_init(pas->dev, pas->pas_id, + pas->mem_phys, pas->mem_size); + if (IS_ERR(pas->pas_ctx)) { + ret = PTR_ERR(pas->pas_ctx); + goto remove_ssr_sysmon; + } + + pas->dtb_pas_ctx = devm_qcom_scm_pas_context_init(pas->dev, pas->dtb_pas_id, + pas->dtb_mem_phys, + pas->dtb_mem_size); + if (IS_ERR(pas->dtb_pas_ctx)) { + ret = PTR_ERR(pas->dtb_pas_ctx); + goto remove_ssr_sysmon; + } + ret = rproc_add(rproc); if (ret) goto remove_ssr_sysmon; diff --git a/drivers/soc/qcom/mdt_loader.c b/drivers/soc/qcom/mdt_loader.c index a5c80d4fcc366..fe35038c5342e 100644 --- a/drivers/soc/qcom/mdt_loader.c +++ b/drivers/soc/qcom/mdt_loader.c @@ -234,13 +234,13 @@ EXPORT_SYMBOL_GPL(qcom_mdt_read_metadata); * @fw_name: name of the firmware, for construction of segment file names * @pas_id: PAS identifier * @mem_phys: physical address of allocated memory region - * @ctx: PAS metadata context, to be released by caller + * @ctx: PAS context, ctx->metadata to be released by caller * * Returns 0 on success, negative errno otherwise. */ int qcom_mdt_pas_init(struct device *dev, const struct firmware *fw, const char *fw_name, int pas_id, phys_addr_t mem_phys, - struct qcom_scm_pas_metadata *ctx) + struct qcom_scm_pas_context *ctx) { const struct elf32_phdr *phdrs; const struct elf32_phdr *phdr; diff --git a/include/linux/firmware/qcom/qcom_scm.h b/include/linux/firmware/qcom/qcom_scm.h index 4a57fa676513b..b10b1aeb32c61 100644 --- a/include/linux/firmware/qcom/qcom_scm.h +++ b/include/linux/firmware/qcom/qcom_scm.h @@ -66,12 +66,6 @@ int qcom_scm_set_warm_boot_addr(void *entry); void qcom_scm_cpu_power_down(u32 flags); int qcom_scm_set_remote_state(u32 state, u32 id); -struct qcom_scm_pas_metadata { - void *ptr; - dma_addr_t phys; - ssize_t size; -}; - struct qcom_scm_pas_context { struct device *dev; u32 pas_id; @@ -87,8 +81,8 @@ struct qcom_scm_pas_context *devm_qcom_scm_pas_context_init(struct device *dev, phys_addr_t mem_phys, size_t mem_size); int qcom_scm_pas_init_image(u32 pas_id, const void *metadata, size_t size, - struct qcom_scm_pas_metadata *ctx); -void qcom_scm_pas_metadata_release(struct qcom_scm_pas_metadata *ctx); + struct qcom_scm_pas_context *ctx); +void qcom_scm_pas_metadata_release(struct qcom_scm_pas_context *ctx); int qcom_scm_pas_mem_setup(u32 pas_id, phys_addr_t addr, phys_addr_t size); int qcom_scm_pas_auth_and_reset(u32 pas_id); int qcom_scm_pas_shutdown(u32 pas_id); diff --git a/include/linux/soc/qcom/mdt_loader.h b/include/linux/soc/qcom/mdt_loader.h index 8ea8230579a20..07c2788418166 100644 --- a/include/linux/soc/qcom/mdt_loader.h +++ b/include/linux/soc/qcom/mdt_loader.h @@ -10,14 +10,14 @@ struct device; struct firmware; -struct qcom_scm_pas_metadata; +struct qcom_scm_pas_context; #if IS_ENABLED(CONFIG_QCOM_MDT_LOADER) ssize_t qcom_mdt_get_size(const struct firmware *fw); int qcom_mdt_pas_init(struct device *dev, const struct firmware *fw, const char *fw_name, int pas_id, phys_addr_t mem_phys, - struct qcom_scm_pas_metadata *pas_metadata_ctx); + struct qcom_scm_pas_context *pas_ctx); int qcom_mdt_load(struct device *dev, const struct firmware *fw, const char *fw_name, int pas_id, void *mem_region, phys_addr_t mem_phys, size_t mem_size, @@ -39,7 +39,7 @@ static inline ssize_t qcom_mdt_get_size(const struct firmware *fw) static inline int qcom_mdt_pas_init(struct device *dev, const struct firmware *fw, const char *fw_name, int pas_id, phys_addr_t mem_phys, - struct qcom_scm_pas_metadata *pas_metadata_ctx) + struct qcom_scm_pas_context *pas_ctx) { return -ENODEV; } From f4bf32151398e435fdbadb50f50bb98a83d2def0 Mon Sep 17 00:00:00 2001 From: Mukesh Ojha Date: Fri, 21 Nov 2025 16:31:08 +0530 Subject: [PATCH 0340/2333] FROMLIST: soc: qcom: mdtloader: Add PAS context aware qcom_mdt_pas_load() function Introduce a new PAS context-aware function, qcom_mdt_pas_load(), for remote processor drivers. This function utilizes the PAS context pointer returned from qcom_scm_pas_ctx_init() to perform firmware metadata verification and memory setup via SMC calls. The qcom_mdt_pas_load() and qcom_mdt_load() functions are largely similar, but the former is designed for clients using the PAS context-based data structure. Over time, all users of qcom_mdt_load() can be migrated to use qcom_mdt_pas_load() for consistency and improved abstraction. As the remoteproc PAS driver (qcom_q6v5_pas) has already adopted the PAS context-based approach, update it to use qcom_mdt_pas_load(). Link: https://lore.kernel.org/lkml/20251121-kvm_rproc_v8-v8-6-8e8e9fb0eca0@oss.qualcomm.com/ Reviewed-by: Konrad Dybcio Signed-off-by: Mukesh Ojha --- drivers/remoteproc/qcom_q6v5_pas.c | 24 +++++----------------- drivers/soc/qcom/mdt_loader.c | 31 +++++++++++++++++++++++++++++ include/linux/soc/qcom/mdt_loader.h | 10 ++++++++++ 3 files changed, 46 insertions(+), 19 deletions(-) diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c index 729e7b9bc1831..9feee2cb18835 100644 --- a/drivers/remoteproc/qcom_q6v5_pas.c +++ b/drivers/remoteproc/qcom_q6v5_pas.c @@ -239,15 +239,9 @@ static int qcom_pas_load(struct rproc *rproc, const struct firmware *fw) return ret; } - ret = qcom_mdt_pas_init(pas->dev, pas->dtb_firmware, pas->dtb_firmware_name, - pas->dtb_pas_id, pas->dtb_mem_phys, - pas->dtb_pas_ctx); - if (ret) - goto release_dtb_firmware; - - ret = qcom_mdt_load_no_init(pas->dev, pas->dtb_firmware, pas->dtb_firmware_name, - pas->dtb_mem_region, pas->dtb_mem_phys, - pas->dtb_mem_size, &pas->dtb_mem_reloc); + ret = qcom_mdt_pas_load(pas->dtb_pas_ctx, pas->dtb_firmware, + pas->dtb_firmware_name, pas->dtb_mem_region, + &pas->dtb_mem_reloc); if (ret) goto release_dtb_metadata; } @@ -256,8 +250,6 @@ static int qcom_pas_load(struct rproc *rproc, const struct firmware *fw) release_dtb_metadata: qcom_scm_pas_metadata_release(pas->dtb_pas_ctx); - -release_dtb_firmware: release_firmware(pas->dtb_firmware); return ret; @@ -305,14 +297,8 @@ static int qcom_pas_start(struct rproc *rproc) } } - ret = qcom_mdt_pas_init(pas->dev, pas->firmware, rproc->firmware, pas->pas_id, - pas->mem_phys, pas->pas_ctx); - if (ret) - goto disable_px_supply; - - ret = qcom_mdt_load_no_init(pas->dev, pas->firmware, rproc->firmware, - pas->mem_region, pas->mem_phys, pas->mem_size, - &pas->mem_reloc); + ret = qcom_mdt_pas_load(pas->pas_ctx, pas->firmware, rproc->firmware, + pas->mem_region, &pas->mem_reloc); if (ret) goto release_pas_metadata; diff --git a/drivers/soc/qcom/mdt_loader.c b/drivers/soc/qcom/mdt_loader.c index fe35038c5342e..847941d232f74 100644 --- a/drivers/soc/qcom/mdt_loader.c +++ b/drivers/soc/qcom/mdt_loader.c @@ -486,5 +486,36 @@ int qcom_mdt_load_no_init(struct device *dev, const struct firmware *fw, } EXPORT_SYMBOL_GPL(qcom_mdt_load_no_init); +/** + * qcom_mdt_pas_load - Loads and authenticates the metadata of the firmware + * (typically contained in the .mdt file), followed by loading the actual + * firmware segments (e.g., .bXX files). Authentication of the segments done + * by a separate call. + * + * The PAS context must be initialized using qcom_scm_pas_context_init() + * prior to invoking this function. + * + * @ctx: Pointer to the PAS (Peripheral Authentication Service) context + * @fw: Firmware object representing the .mdt file + * @firmware: Name of the firmware used to construct segment file names + * @mem_region: Memory region allocated for loading the firmware + * @reloc_base: Physical address adjusted after relocation + * + * Return: 0 on success or a negative error code on failure. + */ +int qcom_mdt_pas_load(struct qcom_scm_pas_context *ctx, const struct firmware *fw, + const char *firmware, void *mem_region, phys_addr_t *reloc_base) +{ + int ret; + + ret = qcom_mdt_pas_init(ctx->dev, fw, firmware, ctx->pas_id, ctx->mem_phys, ctx); + if (ret) + return ret; + + return qcom_mdt_load_no_init(ctx->dev, fw, firmware, mem_region, ctx->mem_phys, + ctx->mem_size, reloc_base); +} +EXPORT_SYMBOL_GPL(qcom_mdt_pas_load); + MODULE_DESCRIPTION("Firmware parser for Qualcomm MDT format"); MODULE_LICENSE("GPL v2"); diff --git a/include/linux/soc/qcom/mdt_loader.h b/include/linux/soc/qcom/mdt_loader.h index 07c2788418166..7d57746fbbfa5 100644 --- a/include/linux/soc/qcom/mdt_loader.h +++ b/include/linux/soc/qcom/mdt_loader.h @@ -23,6 +23,9 @@ int qcom_mdt_load(struct device *dev, const struct firmware *fw, phys_addr_t mem_phys, size_t mem_size, phys_addr_t *reloc_base); +int qcom_mdt_pas_load(struct qcom_scm_pas_context *ctx, const struct firmware *fw, + const char *firmware, void *mem_region, phys_addr_t *reloc_base); + int qcom_mdt_load_no_init(struct device *dev, const struct firmware *fw, const char *fw_name, void *mem_region, phys_addr_t mem_phys, size_t mem_size, @@ -52,6 +55,13 @@ static inline int qcom_mdt_load(struct device *dev, const struct firmware *fw, return -ENODEV; } +static inline int qcom_mdt_pas_load(struct qcom_scm_pas_context *ctx, + const struct firmware *fw, const char *firmware, + void *mem_region, phys_addr_t *reloc_base) +{ + return -ENODEV; +} + static inline int qcom_mdt_load_no_init(struct device *dev, const struct firmware *fw, const char *fw_name, void *mem_region, From 55a4474e0a8f9e0c5e6d0336336225b45ed8a707 Mon Sep 17 00:00:00 2001 From: Mukesh Ojha Date: Fri, 21 Nov 2025 16:31:09 +0530 Subject: [PATCH 0341/2333] FROMLIST: soc: qcom: mdtloader: Remove qcom_mdt_pas_init() from exported symbols qcom_mdt_pas_init() was previously used only by the remoteproc driver (drivers/remoteproc/qcom_q6v5_pas.c). Since that driver has now transitioned to using PAS context-based qcom_mdt_pas_load() function, making qcom_mdt_pas_init() obsolete for external use. Removes qcom_mdt_pas_init() from the list of exported symbols and make it static to limit its scope to internal use within mdtloader. Link: https://lore.kernel.org/lkml/20251121-kvm_rproc_v8-v8-7-8e8e9fb0eca0@oss.qualcomm.com/ Reviewed-by: Konrad Dybcio Signed-off-by: Mukesh Ojha --- drivers/soc/qcom/mdt_loader.c | 11 +++++------ include/linux/soc/qcom/mdt_loader.h | 10 ---------- 2 files changed, 5 insertions(+), 16 deletions(-) diff --git a/drivers/soc/qcom/mdt_loader.c b/drivers/soc/qcom/mdt_loader.c index 847941d232f74..1b426a16389b0 100644 --- a/drivers/soc/qcom/mdt_loader.c +++ b/drivers/soc/qcom/mdt_loader.c @@ -238,9 +238,9 @@ EXPORT_SYMBOL_GPL(qcom_mdt_read_metadata); * * Returns 0 on success, negative errno otherwise. */ -int qcom_mdt_pas_init(struct device *dev, const struct firmware *fw, - const char *fw_name, int pas_id, phys_addr_t mem_phys, - struct qcom_scm_pas_context *ctx) +static int __qcom_mdt_pas_init(struct device *dev, const struct firmware *fw, + const char *fw_name, int pas_id, phys_addr_t mem_phys, + struct qcom_scm_pas_context *ctx) { const struct elf32_phdr *phdrs; const struct elf32_phdr *phdr; @@ -302,7 +302,6 @@ int qcom_mdt_pas_init(struct device *dev, const struct firmware *fw, out: return ret; } -EXPORT_SYMBOL_GPL(qcom_mdt_pas_init); static bool qcom_mdt_bins_are_split(const struct firmware *fw) { @@ -456,7 +455,7 @@ int qcom_mdt_load(struct device *dev, const struct firmware *fw, { int ret; - ret = qcom_mdt_pas_init(dev, fw, firmware, pas_id, mem_phys, NULL); + ret = __qcom_mdt_pas_init(dev, fw, firmware, pas_id, mem_phys, NULL); if (ret) return ret; @@ -508,7 +507,7 @@ int qcom_mdt_pas_load(struct qcom_scm_pas_context *ctx, const struct firmware *f { int ret; - ret = qcom_mdt_pas_init(ctx->dev, fw, firmware, ctx->pas_id, ctx->mem_phys, ctx); + ret = __qcom_mdt_pas_init(ctx->dev, fw, firmware, ctx->pas_id, ctx->mem_phys, ctx); if (ret) return ret; diff --git a/include/linux/soc/qcom/mdt_loader.h b/include/linux/soc/qcom/mdt_loader.h index 7d57746fbbfa5..82372e0db0a18 100644 --- a/include/linux/soc/qcom/mdt_loader.h +++ b/include/linux/soc/qcom/mdt_loader.h @@ -15,9 +15,6 @@ struct qcom_scm_pas_context; #if IS_ENABLED(CONFIG_QCOM_MDT_LOADER) ssize_t qcom_mdt_get_size(const struct firmware *fw); -int qcom_mdt_pas_init(struct device *dev, const struct firmware *fw, - const char *fw_name, int pas_id, phys_addr_t mem_phys, - struct qcom_scm_pas_context *pas_ctx); int qcom_mdt_load(struct device *dev, const struct firmware *fw, const char *fw_name, int pas_id, void *mem_region, phys_addr_t mem_phys, size_t mem_size, @@ -40,13 +37,6 @@ static inline ssize_t qcom_mdt_get_size(const struct firmware *fw) return -ENODEV; } -static inline int qcom_mdt_pas_init(struct device *dev, const struct firmware *fw, - const char *fw_name, int pas_id, phys_addr_t mem_phys, - struct qcom_scm_pas_context *pas_ctx) -{ - return -ENODEV; -} - static inline int qcom_mdt_load(struct device *dev, const struct firmware *fw, const char *fw_name, int pas_id, void *mem_region, phys_addr_t mem_phys, From 158f16f07d028da14b026d362a6e10c8e7156731 Mon Sep 17 00:00:00 2001 From: Mukesh Ojha Date: Fri, 21 Nov 2025 16:31:10 +0530 Subject: [PATCH 0342/2333] FROMLIST: firmware: qcom_scm: Add a prep version of auth_and_reset function For memory passed to TrustZone (TZ), it must either be part of a pool registered with TZ or explicitly registered via SHMbridge SMC calls. When Gunyah hypervisor is present, PAS SMC calls from Linux running at EL1 are trapped by Gunyah running @ EL2, which handles SHMbridge creation for both metadata and remoteproc carveout memory before invoking the calls to TZ. On SoCs running with a non-Gunyah-based hypervisor, Linux must take responsibility for creating the SHM bridge before invoking PAS SMC calls. For the auth_and_reset() call, the remoteproc carveout memory must first be registered with TZ via a SHMbridge SMC call and once authentication and reset are complete, the SHMbridge memory can be deregistered. Introduce qcom_scm_pas_prepare_and_auth_reset(), which sets up the SHM bridge over the remoteproc carveout memory when Linux operates at EL2. This behavior is indicated by a new field added to the PAS context data structure. The function then invokes the auth_and_reset SMC call. Link: https://lore.kernel.org/lkml/20251121-kvm_rproc_v8-v8-8-8e8e9fb0eca0@oss.qualcomm.com/ Signed-off-by: Mukesh Ojha --- drivers/firmware/qcom/qcom_scm.c | 48 ++++++++++++++++++++++++++ include/linux/firmware/qcom/qcom_scm.h | 2 ++ 2 files changed, 50 insertions(+) diff --git a/drivers/firmware/qcom/qcom_scm.c b/drivers/firmware/qcom/qcom_scm.c index 5fa974683ee00..fdb736d839dba 100644 --- a/drivers/firmware/qcom/qcom_scm.c +++ b/drivers/firmware/qcom/qcom_scm.c @@ -765,6 +765,54 @@ int qcom_scm_pas_auth_and_reset(u32 pas_id) } EXPORT_SYMBOL_GPL(qcom_scm_pas_auth_and_reset); +/** + * qcom_scm_pas_prepare_and_auth_reset() - Prepare, authenticate, and reset the + * remote processor + * + * @ctx: Context saved during call to qcom_scm_pas_context_init() + * + * This function performs the necessary steps to prepare a PAS subsystem, + * authenticate it using the provided metadata, and initiate a reset sequence. + * + * It should be used when Linux is in control setting up the IOMMU hardware + * for remote subsystem during secure firmware loading processes. The preparation + * step sets up a shmbridge over the firmware memory before TrustZone accesses the + * firmware memory region for authentication. The authentication step verifies + * the integrity and authenticity of the firmware or configuration using secure + * metadata. Finally, the reset step ensures the subsystem starts in a clean and + * sane state. + * + * Return: 0 on success, negative errno on failure. + */ +int qcom_scm_pas_prepare_and_auth_reset(struct qcom_scm_pas_context *ctx) +{ + u64 handle; + int ret; + + if (!ctx->has_iommu) + return qcom_scm_pas_auth_and_reset(ctx->pas_id); + + /* + * When Linux running @ EL1, Gunyah hypervisor running @ EL2 traps the + * auth_and_reset call and create an shmbridge on the remote subsystem + * memory region and then invokes a call to TrustZone to authenticate. + * When Linux runs @ EL2 Linux must create the shmbridge itself and then + * subsequently call TrustZone for authenticate and reset. + */ + ret = qcom_tzmem_shm_bridge_create(ctx->mem_phys, ctx->mem_size, &handle); + if (ret) { + dev_err(__scm->dev, "Failed to create shmbridge for PAS ID (%u): %d\n", + ctx->pas_id, ret); + return ret; + } + + ret = qcom_scm_pas_auth_and_reset(ctx->pas_id); + qcom_tzmem_shm_bridge_delete(handle); + + return ret; +} +EXPORT_SYMBOL_GPL(qcom_scm_pas_prepare_and_auth_reset); + /** * qcom_scm_pas_shutdown() - Shut down the remote processor * @pas_id: peripheral authentication service id diff --git a/include/linux/firmware/qcom/qcom_scm.h b/include/linux/firmware/qcom/qcom_scm.h index b10b1aeb32c61..ccb8b2e422372 100644 --- a/include/linux/firmware/qcom/qcom_scm.h +++ b/include/linux/firmware/qcom/qcom_scm.h @@ -74,6 +74,7 @@ struct qcom_scm_pas_context { void *ptr; dma_addr_t phys; ssize_t size; + bool has_iommu; }; struct qcom_scm_pas_context *devm_qcom_scm_pas_context_init(struct device *dev, @@ -87,6 +88,7 @@ int qcom_scm_pas_mem_setup(u32 pas_id, phys_addr_t addr, phys_addr_t size); int qcom_scm_pas_auth_and_reset(u32 pas_id); int qcom_scm_pas_shutdown(u32 pas_id); bool qcom_scm_pas_supported(u32 pas_id); +int qcom_scm_pas_prepare_and_auth_reset(struct qcom_scm_pas_context *ctx); int qcom_scm_io_readl(phys_addr_t addr, unsigned int *val); int qcom_scm_io_writel(phys_addr_t addr, unsigned int val); From 10bdb189f779aee6be89e9962fe5a18fbcb9ad05 Mon Sep 17 00:00:00 2001 From: Mukesh Ojha Date: Fri, 21 Nov 2025 16:31:11 +0530 Subject: [PATCH 0343/2333] FROMLIST: firmware: qcom_scm: Refactor qcom_scm_pas_init_image() Refactor qcom_scm_pas_init_image() by moving the memory allocation, copy, and free operations to a higher-level function, and isolate the actual SMC call in a separate function. The main intention is to allow flexibility for different allocators and to respect any constraints that the allocator API may impose before invoking the actual SCM function. Link: https://lore.kernel.org/lkml/20251121-kvm_rproc_v8-v8-9-8e8e9fb0eca0@oss.qualcomm.com/ Reviewed-by: Bryan O'Donoghue Reviewed-by: Konrad Dybcio Signed-off-by: Mukesh Ojha --- drivers/firmware/qcom/qcom_scm.c | 58 ++++++++++++++++++-------------- 1 file changed, 33 insertions(+), 25 deletions(-) diff --git a/drivers/firmware/qcom/qcom_scm.c b/drivers/firmware/qcom/qcom_scm.c index fdb736d839dba..90649d9ade970 100644 --- a/drivers/firmware/qcom/qcom_scm.c +++ b/drivers/firmware/qcom/qcom_scm.c @@ -592,6 +592,37 @@ struct qcom_scm_pas_context *devm_qcom_scm_pas_context_init(struct device *dev, } EXPORT_SYMBOL_GPL(devm_qcom_scm_pas_context_init); +static int __qcom_scm_pas_init_image(u32 pas_id, dma_addr_t mdata_phys, + struct qcom_scm_res *res) +{ + struct qcom_scm_desc desc = { + .svc = QCOM_SCM_SVC_PIL, + .cmd = QCOM_SCM_PIL_PAS_INIT_IMAGE, + .arginfo = QCOM_SCM_ARGS(2, QCOM_SCM_VAL, QCOM_SCM_RW), + .args[0] = pas_id, + .owner = ARM_SMCCC_OWNER_SIP, + }; + int ret; + + ret = qcom_scm_clk_enable(); + if (ret) + return ret; + + ret = qcom_scm_bw_enable(); + if (ret) + goto disable_clk; + + desc.args[1] = mdata_phys; + + ret = qcom_scm_call(__scm->dev, &desc, res); + qcom_scm_bw_disable(); + +disable_clk: + qcom_scm_clk_disable(); + + return ret; +} + /** * qcom_scm_pas_init_image() - Initialize peripheral authentication service * state machine for a given peripheral, using the @@ -612,17 +643,10 @@ EXPORT_SYMBOL_GPL(devm_qcom_scm_pas_context_init); int qcom_scm_pas_init_image(u32 pas_id, const void *metadata, size_t size, struct qcom_scm_pas_context *ctx) { + struct qcom_scm_res res; dma_addr_t mdata_phys; void *mdata_buf; int ret; - struct qcom_scm_desc desc = { - .svc = QCOM_SCM_SVC_PIL, - .cmd = QCOM_SCM_PIL_PAS_INIT_IMAGE, - .arginfo = QCOM_SCM_ARGS(2, QCOM_SCM_VAL, QCOM_SCM_RW), - .args[0] = pas_id, - .owner = ARM_SMCCC_OWNER_SIP, - }; - struct qcom_scm_res res; /* * During the scm call memory protection will be enabled for the meta @@ -643,23 +667,7 @@ int qcom_scm_pas_init_image(u32 pas_id, const void *metadata, size_t size, memcpy(mdata_buf, metadata, size); - ret = qcom_scm_clk_enable(); - if (ret) - goto out; - - ret = qcom_scm_bw_enable(); - if (ret) - goto disable_clk; - - desc.args[1] = mdata_phys; - - ret = qcom_scm_call(__scm->dev, &desc, &res); - qcom_scm_bw_disable(); - -disable_clk: - qcom_scm_clk_disable(); - -out: + ret = __qcom_scm_pas_init_image(pas_id, mdata_phys, &res); if (ret < 0 || !ctx) { dma_free_coherent(__scm->dev, size, mdata_buf, mdata_phys); } else if (ctx) { From 81c76282fd6f056f448f42c1ae7423fedebc5897 Mon Sep 17 00:00:00 2001 From: Mukesh Ojha Date: Fri, 21 Nov 2025 16:31:12 +0530 Subject: [PATCH 0344/2333] FROMLIST: firmware: qcom_scm: Add SHM bridge handling for PAS when running without QHEE On SoCs running with a non-Gunyah-based hypervisor, Linux must take responsibility for creating the SHM bridge both for metadata (before calling qcom_scm_pas_init_image()) and for remoteproc memory (before calling qcom_scm_pas_auth_and_reset()). We have taken care the things required for qcom_scm_pas_auth_and_reset(). Lets put these awareness of above conditions into qcom_scm_pas_init_image() and qcom_scm_pas_metadata_release(). Link: https://lore.kernel.org/lkml/20251121-kvm_rproc_v8-v8-10-8e8e9fb0eca0@oss.qualcomm.com/ Reviewed-by: Konrad Dybcio Signed-off-by: Mukesh Ojha --- drivers/firmware/qcom/qcom_scm.c | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/drivers/firmware/qcom/qcom_scm.c b/drivers/firmware/qcom/qcom_scm.c index 90649d9ade970..84498d0d2f0cc 100644 --- a/drivers/firmware/qcom/qcom_scm.c +++ b/drivers/firmware/qcom/qcom_scm.c @@ -623,6 +623,30 @@ static int __qcom_scm_pas_init_image(u32 pas_id, dma_addr_t mdata_phys, return ret; } +static int qcom_scm_pas_prep_and_init_image(struct qcom_scm_pas_context *ctx, + const void *metadata, size_t size) +{ + struct qcom_scm_res res; + phys_addr_t mdata_phys; + void *mdata_buf; + int ret; + + mdata_buf = qcom_tzmem_alloc(__scm->mempool, size, GFP_KERNEL); + if (!mdata_buf) + return -ENOMEM; + + memcpy(mdata_buf, metadata, size); + mdata_phys = qcom_tzmem_to_phys(mdata_buf); + + ret = __qcom_scm_pas_init_image(ctx->pas_id, mdata_phys, &res); + if (ret < 0) + qcom_tzmem_free(mdata_buf); + else + ctx->ptr = mdata_buf; + + return ret ? : res.result[0]; +} + /** * qcom_scm_pas_init_image() - Initialize peripheral authentication service * state machine for a given peripheral, using the @@ -648,6 +672,9 @@ int qcom_scm_pas_init_image(u32 pas_id, const void *metadata, size_t size, void *mdata_buf; int ret; + if (ctx && ctx->has_iommu) + return qcom_scm_pas_prep_and_init_image(ctx, metadata, size); + /* * During the scm call memory protection will be enabled for the meta * data blob, so make sure it's physically contiguous, 4K aligned and @@ -689,7 +716,10 @@ void qcom_scm_pas_metadata_release(struct qcom_scm_pas_context *ctx) if (!ctx->ptr) return; - dma_free_coherent(__scm->dev, ctx->size, ctx->ptr, ctx->phys); + if (ctx->has_iommu) + qcom_tzmem_free(ctx->ptr); + else + dma_free_coherent(__scm->dev, ctx->size, ctx->ptr, ctx->phys); ctx->ptr = NULL; } From 1ec84858aab15f248caf7e6a2a843926c400e554 Mon Sep 17 00:00:00 2001 From: Mukesh Ojha Date: Fri, 21 Nov 2025 16:31:13 +0530 Subject: [PATCH 0345/2333] FROMLIST: firmware: qcom_scm: Add qcom_scm_pas_get_rsc_table() to get resource table Qualcomm remote processor may rely on Static and Dynamic resources for it to be functional. Static resources are fixed like for example, memory-mapped addresses required by the subsystem and dynamic resources, such as shared memory in DDR etc., are determined at runtime during the boot process. For most of the Qualcomm SoCs, when run with Gunyah or older QHEE hypervisor, all the resources whether it is static or dynamic, is managed by the hypervisor. Dynamic resources if it is present for a remote processor will always be coming from secure world via SMC call while static resources may be present in remote processor firmware binary or it may be coming qcom_scm_pas_get_rsc_table() SMC call along with dynamic resources. Some of the remote processor drivers, such as video, GPU, IPA, etc., do not check whether resources are present in their remote processor firmware binary. In such cases, the caller of this function should set input_rt and input_rt_size as NULL and zero respectively. Remoteproc framework has method to check whether firmware binary contain resources or not and they should be pass resource table pointer to input_rt and resource table size to input_rt_size and this will be forwarded to TrustZone for authentication. TrustZone will then append the dynamic resources and return the complete resource table in output_rt More about documentation on resource table format can be found in include/linux/remoteproc.h Link: https://lore.kernel.org/lkml/20251121-kvm_rproc_v8-v8-11-8e8e9fb0eca0@oss.qualcomm.com/ Signed-off-by: Mukesh Ojha --- drivers/firmware/qcom/qcom_scm.c | 158 +++++++++++++++++++++++++ drivers/firmware/qcom/qcom_scm.h | 1 + include/linux/firmware/qcom/qcom_scm.h | 4 + 3 files changed, 163 insertions(+) diff --git a/drivers/firmware/qcom/qcom_scm.c b/drivers/firmware/qcom/qcom_scm.c index 84498d0d2f0cc..c4420b79fb577 100644 --- a/drivers/firmware/qcom/qcom_scm.c +++ b/drivers/firmware/qcom/qcom_scm.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -111,6 +112,10 @@ enum qcom_scm_qseecom_tz_cmd_info { QSEECOM_TZ_CMD_INFO_VERSION = 3, }; +enum qcom_scm_rsctable_resp_type { + RSCTABLE_BUFFER_NOT_SUFFICIENT = 20, +}; + #define QSEECOM_MAX_APP_NAME_SIZE 64 #define SHMBRIDGE_RESULT_NOTSUPP 4 @@ -766,6 +771,159 @@ int qcom_scm_pas_mem_setup(u32 pas_id, phys_addr_t addr, phys_addr_t size) } EXPORT_SYMBOL_GPL(qcom_scm_pas_mem_setup); +static int __qcom_scm_pas_get_rsc_table(u32 pas_id, void *input_rt, size_t input_rt_size, + void **output_rt, size_t *output_rt_size) +{ + struct qcom_scm_desc desc = { + .svc = QCOM_SCM_SVC_PIL, + .cmd = QCOM_SCM_PIL_PAS_GET_RSCTABLE, + .arginfo = QCOM_SCM_ARGS(5, QCOM_SCM_VAL, QCOM_SCM_RO, QCOM_SCM_VAL, + QCOM_SCM_RW, QCOM_SCM_VAL), + .args[0] = pas_id, + .owner = ARM_SMCCC_OWNER_SIP, + }; + void *input_rt_buf, *output_rt_buf; + struct resource_table *rsc; + struct qcom_scm_res res; + int ret; + + ret = qcom_scm_clk_enable(); + if (ret) + return ret; + + ret = qcom_scm_bw_enable(); + if (ret) + goto disable_clk; + + /* + * TrustZone can not accept buffer as NULL value as argument Hence, + * we need to pass a input buffer indicating that subsystem firmware + * does not have resource table by filling resource table structure. + */ + if (!input_rt) + input_rt_size = sizeof(*rsc); + + input_rt_buf = qcom_tzmem_alloc(__scm->mempool, input_rt_size, GFP_KERNEL); + if (!input_rt_buf) { + ret = -ENOMEM; + goto disable_scm_bw; + } + + if (!input_rt) { + rsc = input_rt_buf; + rsc->num = 0; + } else { + memcpy(input_rt_buf, input_rt, input_rt_size); + } + + output_rt_buf = qcom_tzmem_alloc(__scm->mempool, *output_rt_size, GFP_KERNEL); + if (!output_rt_buf) { + ret = -ENOMEM; + goto free_input_rt_buf; + } + + desc.args[1] = qcom_tzmem_to_phys(input_rt_buf); + desc.args[2] = input_rt_size; + desc.args[3] = qcom_tzmem_to_phys(output_rt_buf); + desc.args[4] = *output_rt_size; + + /* + * Whether SMC fail or pass, res.result[2] will hold actual resource table + * size. + * + * if passed 'output_rt_size' buffer size is not sufficient to hold the + * resource table TrustZone sends, response code in res.result[1] as + * RSCTABLE_BUFFER_NOT_SUFFICIENT so that caller can retry this SMC call with + * output_rt buffer with res.result[2] size. + */ + ret = qcom_scm_call(__scm->dev, &desc, &res); + *output_rt_size = res.result[2]; + if (!ret) + memcpy(*output_rt, output_rt_buf, *output_rt_size); + + if (ret && res.result[1] == RSCTABLE_BUFFER_NOT_SUFFICIENT) + ret = -EAGAIN; + + qcom_tzmem_free(output_rt_buf); + +free_input_rt_buf: + qcom_tzmem_free(input_rt_buf); + +disable_scm_bw: + qcom_scm_bw_disable(); + +disable_clk: + qcom_scm_clk_disable(); + + return ret ? : res.result[0]; +} + +/** + * qcom_scm_pas_get_rsc_table() - Retrieve the resource table in passed output buffer + * for a given peripheral. + * + * Qualcomm remote processor may rely on both static and dynamic resources for + * its functionality. Static resources typically refer to memory-mapped addresses + * required by the subsystem and are often embedded within the firmware binary + * and dynamic resources, such as shared memory in DDR etc., are determined at + * runtime during the boot process. + * + * On Qualcomm Technologies devices, it's possible that static resources are not + * embedded in the firmware binary and instead are provided by TrustZone However, + * dynamic resources are always expected to come from TrustZone. This indicates + * that for Qualcomm devices, all resources (static and dynamic) will be provided + * by TrustZone via the SMC call. + * + * If the remote processor firmware binary does contain static resources, they + * should be passed in input_rt. These will be forwarded to TrustZone for + * authentication. TrustZone will then append the dynamic resources and return + * the complete resource table in output_rt. + * + * If the remote processor firmware binary does not include a resource table, + * the caller of this function should set input_rt as NULL and input_rt_size + * as zero respectively. + * + * More about documentation on resource table data structures can be found in + * include/linux/remoteproc.h + * + * @ctx: PAS context + * @pas_id: peripheral authentication service id + * @input_rt: resource table buffer which is present in firmware binary + * @input_rt_size: size of the resource table present in firmware binary + * @output_rt: buffer to which the both static and dynamic resources will + * be returned. + * @output_rt_size: TrustZone expects caller should pass worst case size for + * the output_rt. + * + * Return: 0 on success and nonzero on failure. + * + * Upon successful return, output_rt will have the resource table and output_rt_size + * will have actual resource table size, + */ +int qcom_scm_pas_get_rsc_table(struct qcom_scm_pas_context *ctx, void *input_rt, + size_t input_rt_size, void **output_rt, + size_t *output_rt_size) +{ + unsigned int retry_num = 5; + int ret; + + do { + *output_rt = kzalloc(*output_rt_size, GFP_KERNEL); + if (!*output_rt) + return -ENOMEM; + + ret = __qcom_scm_pas_get_rsc_table(ctx->pas_id, input_rt, + input_rt_size, output_rt, + output_rt_size); + if (ret) + kfree(*output_rt); + + } while (ret == -EAGAIN && --retry_num); + + return ret; +} +EXPORT_SYMBOL_GPL(qcom_scm_pas_get_rsc_table); + /** * qcom_scm_pas_auth_and_reset() - Authenticate the given peripheral firmware * and reset the remote processor diff --git a/drivers/firmware/qcom/qcom_scm.h b/drivers/firmware/qcom/qcom_scm.h index a56c8212cc0c4..50d87c628d78b 100644 --- a/drivers/firmware/qcom/qcom_scm.h +++ b/drivers/firmware/qcom/qcom_scm.h @@ -105,6 +105,7 @@ int qcom_scm_shm_bridge_enable(struct device *scm_dev); #define QCOM_SCM_PIL_PAS_SHUTDOWN 0x06 #define QCOM_SCM_PIL_PAS_IS_SUPPORTED 0x07 #define QCOM_SCM_PIL_PAS_MSS_RESET 0x0a +#define QCOM_SCM_PIL_PAS_GET_RSCTABLE 0x21 #define QCOM_SCM_SVC_IO 0x05 #define QCOM_SCM_IO_READ 0x01 diff --git a/include/linux/firmware/qcom/qcom_scm.h b/include/linux/firmware/qcom/qcom_scm.h index ccb8b2e422372..814d40d64ab04 100644 --- a/include/linux/firmware/qcom/qcom_scm.h +++ b/include/linux/firmware/qcom/qcom_scm.h @@ -88,6 +88,10 @@ int qcom_scm_pas_mem_setup(u32 pas_id, phys_addr_t addr, phys_addr_t size); int qcom_scm_pas_auth_and_reset(u32 pas_id); int qcom_scm_pas_shutdown(u32 pas_id); bool qcom_scm_pas_supported(u32 pas_id); +int qcom_scm_pas_get_rsc_table(struct qcom_scm_pas_context *ctx, void *input_rt, + size_t input_rt_size, void **output_rt, + size_t *output_rt_size); + int qcom_scm_pas_prepare_and_auth_reset(struct qcom_scm_pas_context *ctx); int qcom_scm_io_readl(phys_addr_t addr, unsigned int *val); From a570d5bcf588bb98a374938246707a445617a360 Mon Sep 17 00:00:00 2001 From: Mukesh Ojha Date: Fri, 21 Nov 2025 16:31:14 +0530 Subject: [PATCH 0346/2333] FROMLIST: remoteproc: pas: Extend parse_fw callback to fetch resources via SMC call Qualcomm remote processor may rely on static and dynamic resources for it to be functional. For most of the Qualcomm SoCs, when run with Gunyah or older QHEE hypervisor, all the resources whether it is static or dynamic, is managed by the hypervisor. Dynamic resources if it is present for a remote processor will always be coming from secure world via SMC call while static resources may be present in remote processor firmware binary or it may be coming from SMC call along with dynamic resources. Remoteproc already has method like rproc_elf_load_rsc_table() to check firmware binary has resources or not and if it is not having then we pass NULL and zero as input resource table and its size argument respectively to qcom_scm_pas_get_rsc_table() and while it has resource present then it should pass the present resources to Trustzone(TZ) so that it could authenticate the present resources and append dynamic resource to return in output_rt argument along with authenticated resources. Extend parse_fw callback to include SMC call to get resources from Trustzone and to leverage resource table parsing and mapping and unmapping code from the remoteproc framework. Link: https://lore.kernel.org/lkml/20251121-kvm_rproc_v8-v8-12-8e8e9fb0eca0@oss.qualcomm.com/ Reviewed-by: Konrad Dybcio Signed-off-by: Mukesh Ojha --- drivers/remoteproc/qcom_q6v5_pas.c | 60 +++++++++++++++++++++++++++++- 1 file changed, 58 insertions(+), 2 deletions(-) diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c index 9feee2cb18835..186a90d6c83a8 100644 --- a/drivers/remoteproc/qcom_q6v5_pas.c +++ b/drivers/remoteproc/qcom_q6v5_pas.c @@ -34,6 +34,7 @@ #define QCOM_PAS_DECRYPT_SHUTDOWN_DELAY_MS 100 #define MAX_ASSIGN_COUNT 3 +#define MAX_RSCTABLE_SIZE SZ_16K struct qcom_pas_data { int crash_reason_smem; @@ -413,6 +414,61 @@ static void *qcom_pas_da_to_va(struct rproc *rproc, u64 da, size_t len, bool *is return pas->mem_region + offset; } +static int qcom_pas_parse_firmware(struct rproc *rproc, const struct firmware *fw) +{ + size_t output_rt_size = MAX_RSCTABLE_SIZE; + struct qcom_pas *pas = rproc->priv; + struct resource_table *table = NULL; + void *output_rt; + size_t table_sz; + int ret; + + ret = qcom_register_dump_segments(rproc, fw); + if (ret) { + dev_err(pas->dev, "Error in registering dump segments\n"); + return ret; + } + + if (!rproc->has_iommu) + return 0; + + ret = rproc_elf_load_rsc_table(rproc, fw); + if (ret) + dev_dbg(&rproc->dev, "Failed to load resource table from firmware\n"); + + table = rproc->table_ptr; + table_sz = rproc->table_sz; + + /* + * The resources consumed by Qualcomm remote processors fall into two categories: + * static (such as the memory carveouts for the rproc firmware) and dynamic (like + * shared memory pools). Both are managed by a Qualcomm hypervisor (such as QHEE + * or Gunyah), if one is present. Otherwise, a resource table must be retrieved + * via an SCM call. That table will list all dynamic resources (if any) and possibly + * the static ones. The static resources may also come from a resource table embedded + * in the rproc firmware instead. + * + * Here, we call rproc_elf_load_rsc_table() to check firmware binary has resources + * or not and if it is not having then we pass NULL and zero as input resource + * table pointer and size respectively to the argument of qcom_scm_pas_get_rsc_table() + * and this is even true for Qualcomm remote processor who does follow remoteproc + * framework. + */ + ret = qcom_scm_pas_get_rsc_table(pas->pas_ctx, table, table_sz, &output_rt, + &output_rt_size); + if (ret) { + dev_err(pas->dev, "Error in getting resource table: %d\n", ret); + return ret; + } + + kfree(rproc->cached_table); + rproc->cached_table = output_rt; + rproc->table_ptr = rproc->cached_table; + rproc->table_sz = output_rt_size; + + return ret; +} + static unsigned long qcom_pas_panic(struct rproc *rproc) { struct qcom_pas *pas = rproc->priv; @@ -425,7 +481,7 @@ static const struct rproc_ops qcom_pas_ops = { .start = qcom_pas_start, .stop = qcom_pas_stop, .da_to_va = qcom_pas_da_to_va, - .parse_fw = qcom_register_dump_segments, + .parse_fw = qcom_pas_parse_firmware, .load = qcom_pas_load, .panic = qcom_pas_panic, }; @@ -435,7 +491,7 @@ static const struct rproc_ops qcom_pas_minidump_ops = { .start = qcom_pas_start, .stop = qcom_pas_stop, .da_to_va = qcom_pas_da_to_va, - .parse_fw = qcom_register_dump_segments, + .parse_fw = qcom_pas_parse_firmware, .load = qcom_pas_load, .panic = qcom_pas_panic, .coredump = qcom_pas_minidump, From 464fb78ea02cf616d58464b045264e52c5f756cb Mon Sep 17 00:00:00 2001 From: Mukesh Ojha Date: Fri, 21 Nov 2025 16:31:15 +0530 Subject: [PATCH 0347/2333] FROMLIST: remoteproc: qcom: pas: Enable Secure PAS support with IOMMU managed by Linux Most Qualcomm platforms feature Gunyah hypervisor, which typically handles IOMMU configuration. This includes mapping memory regions and device memory resources for remote processors by intercepting qcom_scm_pas_auth_and_reset() calls. These mappings are later removed during teardown. Additionally, SHM bridge setup is required to enable memory protection for both remoteproc metadata and its memory regions. When the aforementioned hypervisor is absent, the operating system must perform these configurations instead. When Linux runs as the hypervisor (@ EL2) on a SoC, it will have its own device tree overlay file that specifies the firmware stream ID now managed by Linux for a particular remote processor. If the iommus property is specified in the remoteproc device tree node, it indicates that IOMMU configuration must be handled by Linux. In this case, the has_iommu flag is set for the remote processor, which ensures that the resource table, carveouts, and SHM bridge are properly configured before memory is passed to TrustZone for authentication. Otherwise, the has_iommu flag remains unset, which indicates default behavior. Enables Secure PAS support for remote processors when IOMMU configuration is managed by Linux. Link: https://lore.kernel.org/lkml/20251121-kvm_rproc_v8-v8-13-8e8e9fb0eca0@oss.qualcomm.com/ Signed-off-by: Mukesh Ojha --- drivers/remoteproc/qcom_q6v5_pas.c | 48 ++++++++++++++++++++++++++---- 1 file changed, 43 insertions(+), 5 deletions(-) diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c index 186a90d6c83a8..2df3b06f8157f 100644 --- a/drivers/remoteproc/qcom_q6v5_pas.c +++ b/drivers/remoteproc/qcom_q6v5_pas.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -256,6 +257,22 @@ static int qcom_pas_load(struct rproc *rproc, const struct firmware *fw) return ret; } +static void qcom_pas_unmap_carveout(struct rproc *rproc, phys_addr_t mem_phys, size_t size) +{ + if (rproc->has_iommu) + iommu_unmap(rproc->domain, mem_phys, size); +} + +static int qcom_pas_map_carveout(struct rproc *rproc, phys_addr_t mem_phys, size_t size) +{ + int ret = 0; + + if (rproc->has_iommu) + ret = iommu_map(rproc->domain, mem_phys, mem_phys, size, + IOMMU_READ | IOMMU_WRITE, GFP_KERNEL); + return ret; +} + static int qcom_pas_start(struct rproc *rproc) { struct qcom_pas *pas = rproc->priv; @@ -290,11 +307,15 @@ static int qcom_pas_start(struct rproc *rproc) } if (pas->dtb_pas_id) { - ret = qcom_scm_pas_auth_and_reset(pas->dtb_pas_id); + ret = qcom_pas_map_carveout(rproc, pas->dtb_mem_phys, pas->dtb_mem_size); + if (ret) + goto disable_px_supply; + + ret = qcom_scm_pas_prepare_and_auth_reset(pas->dtb_pas_ctx); if (ret) { dev_err(pas->dev, "failed to authenticate dtb image and release reset\n"); - goto disable_px_supply; + goto unmap_dtb_carveout; } } @@ -305,18 +326,22 @@ static int qcom_pas_start(struct rproc *rproc) qcom_pil_info_store(pas->info_name, pas->mem_phys, pas->mem_size); - ret = qcom_scm_pas_auth_and_reset(pas->pas_id); + ret = qcom_pas_map_carveout(rproc, pas->mem_phys, pas->mem_size); + if (ret) + goto release_pas_metadata; + + ret = qcom_scm_pas_prepare_and_auth_reset(pas->pas_ctx); if (ret) { dev_err(pas->dev, "failed to authenticate image and release reset\n"); - goto release_pas_metadata; + goto unmap_carveout; } ret = qcom_q6v5_wait_for_start(&pas->q6v5, msecs_to_jiffies(5000)); if (ret == -ETIMEDOUT) { dev_err(pas->dev, "start timed out\n"); qcom_scm_pas_shutdown(pas->pas_id); - goto release_pas_metadata; + goto unmap_carveout; } qcom_scm_pas_metadata_release(pas->pas_ctx); @@ -328,10 +353,16 @@ static int qcom_pas_start(struct rproc *rproc) return 0; +unmap_carveout: + qcom_pas_unmap_carveout(rproc, pas->mem_phys, pas->mem_size); release_pas_metadata: qcom_scm_pas_metadata_release(pas->pas_ctx); if (pas->dtb_pas_id) qcom_scm_pas_metadata_release(pas->dtb_pas_ctx); + +unmap_dtb_carveout: + if (pas->dtb_pas_id) + qcom_pas_unmap_carveout(rproc, pas->dtb_mem_phys, pas->dtb_mem_size); disable_px_supply: if (pas->px_supply) regulator_disable(pas->px_supply); @@ -387,8 +418,12 @@ static int qcom_pas_stop(struct rproc *rproc) ret = qcom_scm_pas_shutdown(pas->dtb_pas_id); if (ret) dev_err(pas->dev, "failed to shutdown dtb: %d\n", ret); + + qcom_pas_unmap_carveout(rproc, pas->dtb_mem_phys, pas->dtb_mem_size); } + qcom_pas_unmap_carveout(rproc, pas->mem_phys, pas->mem_size); + handover = qcom_q6v5_unprepare(&pas->q6v5); if (handover) qcom_pas_handover(&pas->q6v5); @@ -758,6 +793,7 @@ static int qcom_pas_probe(struct platform_device *pdev) return -ENOMEM; } + rproc->has_iommu = of_property_present(pdev->dev.of_node, "iommus"); rproc->auto_boot = desc->auto_boot; rproc_coredump_set_elf_info(rproc, ELFCLASS32, EM_NONE); @@ -837,6 +873,8 @@ static int qcom_pas_probe(struct platform_device *pdev) goto remove_ssr_sysmon; } + pas->pas_ctx->has_iommu = rproc->has_iommu; + pas->dtb_pas_ctx->has_iommu = rproc->has_iommu; ret = rproc_add(rproc); if (ret) goto remove_ssr_sysmon; From 5cee34b7521a26dfc75c3f43b29f4a18c522bf6f Mon Sep 17 00:00:00 2001 From: Krishna Kurapati Date: Mon, 8 Dec 2025 14:21:52 +0530 Subject: [PATCH 0348/2333] FROMLIST: arm64: dts: qcom: hamoa-iot-evk: Add vbus regulator support for Type-A ports The Multiport controller on Hamoa EVK platform is connected to Two Type-A ports. VBUS for each of these ports are provided by a TPS2559QWDRCTQ1 regulator, controlled from PMIC GPIOs. Add the necessary regulators and GPIO configuration to power these. Link: https://lore.kernel.org/all/20251208085152.2597818-1-krishna.kurapati@oss.qualcomm.com/ Signed-off-by: Krishna Kurapati Signed-off-by: Xin Liu --- arch/arm64/boot/dts/qcom/hamoa-iot-evk.dts | 37 ++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/hamoa-iot-evk.dts b/arch/arm64/boot/dts/qcom/hamoa-iot-evk.dts index c892622d081cd..058362ca36637 100644 --- a/arch/arm64/boot/dts/qcom/hamoa-iot-evk.dts +++ b/arch/arm64/boot/dts/qcom/hamoa-iot-evk.dts @@ -6,6 +6,7 @@ /dts-v1/; #include "hamoa-iot-som.dtsi" +#include / { model = "Qualcomm Technologies, Inc. Hamoa IoT EVK"; @@ -177,6 +178,26 @@ }; }; + regulator-usb3-vbus { + compatible = "regulator-fixed"; + regulator-name = "USB3_VBUS"; + gpio = <&pm8550ve_9_gpios 4 GPIO_ACTIVE_HIGH>; + pinctrl-0 = <&usb3_en>; + pinctrl-names = "default"; + enable-active-high; + regulator-always-on; + }; + + regulator-usb6-vbus { + compatible = "regulator-fixed"; + regulator-name = "USB6_VBUS"; + gpio = <&pm8550ve_9_gpios 5 GPIO_ACTIVE_HIGH>; + pinctrl-0 = <&usb6_en>; + pinctrl-names = "default"; + enable-active-high; + regulator-always-on; + }; + vreg_edp_3p3: regulator-edp-3p3 { compatible = "regulator-fixed"; @@ -956,6 +977,22 @@ input-disable; output-enable; }; + + usb3_en: usb3-en-state { + pins = "gpio4"; + function = "normal"; + qcom,drive-strength = ; + output-enable; + power-source = <0>; + }; + + usb6_en: usb6-en-state { + pins = "gpio5"; + function = "normal"; + qcom,drive-strength = ; + output-enable; + power-source = <0>; + }; }; &pmc8380_3_gpios { From 731b038c653da0d0585f9fdfd9c0d04a9f489f3c Mon Sep 17 00:00:00 2001 From: Yingying Tang Date: Thu, 4 Dec 2025 16:50:01 +0800 Subject: [PATCH 0349/2333] FROMLIST: arm64: dts: qcom: hamoa-iot-evk: Add WLAN node for hamoa iot evk board WLAN card is connected to PCIe4 on hamoa iot evk board. Add WLAN node to support power sequence for this WLAN card. Link: https://lore.kernel.org/all/20251209115924.848165-1-yingying.tang@oss.qualcomm.com Signed-off-by: Yingying Tang --- arch/arm64/boot/dts/qcom/hamoa-iot-evk.dts | 26 +++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/hamoa-iot-evk.dts b/arch/arm64/boot/dts/qcom/hamoa-iot-evk.dts index 058362ca36637..3acec00b9e6df 100644 --- a/arch/arm64/boot/dts/qcom/hamoa-iot-evk.dts +++ b/arch/arm64/boot/dts/qcom/hamoa-iot-evk.dts @@ -623,7 +623,7 @@ bt-enable-gpios = <&tlmm 116 GPIO_ACTIVE_HIGH>; wlan-enable-gpios = <&tlmm 117 GPIO_ACTIVE_HIGH>; - pinctrl-0 = <&wcn_bt_en>; + pinctrl-0 = <&wcn_bt_en>, <&wcn_wlan_en>; pinctrl-names = "default"; regulators { @@ -929,6 +929,23 @@ vpcie3v3aux-supply = <&vreg_pcie_3v3_aux>; }; +&pcie4_port0 { + wifi@0 { + compatible = "pci17cb,1107"; + reg = <0x10000 0x0 0x0 0x0 0x0>; + + vddaon-supply = <&vreg_pmu_aon_0p59>; + vddwlcx-supply = <&vreg_pmu_wlcx_0p8>; + vddwlmx-supply = <&vreg_pmu_wlmx_0p85>; + vddrfacmn-supply = <&vreg_pmu_rfa_cmn>; + vddrfa0p8-supply = <&vreg_pmu_rfa_0p8>; + vddrfa1p2-supply = <&vreg_pmu_rfa_1p2>; + vddrfa1p8-supply = <&vreg_pmu_rfa_1p8>; + vddpcie0p9-supply = <&vreg_pmu_pcie_0p9>; + vddpcie1p8-supply = <&vreg_pmu_pcie_1p8>; + }; +}; + &pcie5 { vddpe-3v3-supply = <&vreg_wwan>; }; @@ -1305,6 +1322,13 @@ bias-disable; }; + wcn_wlan_en: wcn-wlan-en-state { + pins = "gpio117"; + function = "gpio"; + drive-strength = <2>; + bias-disable; + }; + wwan_sw_en: wwan-sw-en-state { pins = "gpio221"; function = "gpio"; From 95c9f03ffd5f1910d9971c8ba3a4f0917462e4bb Mon Sep 17 00:00:00 2001 From: Salendarsingh Gaud Date: Thu, 11 Dec 2025 12:53:17 +0530 Subject: [PATCH 0350/2333] Add qcom-next log files for 20251211 Adding merge log file and topic_SHA1 file Signed-off-by: Salendarsingh Gaud --- qcom-next/merge.log | 421 +++++++++++++++++++++++++++++++++++++++++++ qcom-next/topic_SHA1 | 44 +++++ 2 files changed, 465 insertions(+) create mode 100644 qcom-next/merge.log create mode 100644 qcom-next/topic_SHA1 diff --git a/qcom-next/merge.log b/qcom-next/merge.log new file mode 100644 index 0000000000000..76ae373942bb6 --- /dev/null +++ b/qcom-next/merge.log @@ -0,0 +1,421 @@ +Verified existence of local and remote repos: Success +/local/mnt/workspace/automerge/actions-runner/_work/kernel-automation/kernel-automation/kernel-topics /local/mnt/workspace/automerge/actions-runner/_work/kernel-automation/kernel-automation/kernel-topics +Reuse-Recorded-Resolution: Enabled +Downloaded shared rerere cache +Local tree is clean +Removing old remotes ... +The remote origin https://github.com/qualcomm-linux/kernel-topics.git is no longer tracked. +Delete it [Y/n]? Done, removed 1 old remote(s). +Adding new remotes... +Adding remote baseline https://github.com/qualcomm-linux/kernel.git qcom-next-staging +Updating baseline +Adding remote tech/bsp/clk https://github.com/qualcomm-linux/kernel-topics.git tech/bsp/clk +Updating tech/bsp/clk +Adding remote tech/bsp/interconnect https://github.com/qualcomm-linux/kernel-topics.git tech/bsp/interconnect +Updating tech/bsp/interconnect +Adding remote tech/mem/secure-buffer https://github.com/qualcomm-linux/kernel-topics.git tech/mem/secure-buffer +Updating tech/mem/secure-buffer +Adding remote tech/security/firmware-smc https://github.com/qualcomm-linux/kernel-topics.git tech/security/firmware-smc +Updating tech/security/firmware-smc +Adding remote tech/bsp/soc-infra https://github.com/qualcomm-linux/kernel-topics.git tech/bsp/soc-infra +Updating tech/bsp/soc-infra +Adding remote tech/debug/soc https://github.com/qualcomm-linux/kernel-topics.git tech/debug/soc +Updating tech/debug/soc +Adding remote tech/bsp/pinctrl https://github.com/qualcomm-linux/kernel-topics.git tech/bsp/pinctrl +Updating tech/bsp/pinctrl +Adding remote tech/bsp/remoteproc https://github.com/qualcomm-linux/kernel-topics.git tech/bsp/remoteproc +Updating tech/bsp/remoteproc +Adding remote tech/bus/peripherals https://github.com/qualcomm-linux/kernel-topics.git tech/bus/peripherals +Updating tech/bus/peripherals +Adding remote tech/bus/pci/all https://github.com/qualcomm-linux/kernel-topics.git tech/bus/pci/all +Updating tech/bus/pci/all +Adding remote tech/bus/pci/mhi https://github.com/qualcomm-linux/kernel-topics.git tech/bus/pci/mhi +Updating tech/bus/pci/mhi +Adding remote tech/bus/pci/phy https://github.com/qualcomm-linux/kernel-topics.git tech/bus/pci/phy +Updating tech/bus/pci/phy +Adding remote tech/bus/pci/pwrctl https://github.com/qualcomm-linux/kernel-topics.git tech/bus/pci/pwrctl +Updating tech/bus/pci/pwrctl +Adding remote tech/bus/usb/dwc https://github.com/qualcomm-linux/kernel-topics.git tech/bus/usb/dwc +Updating tech/bus/usb/dwc +Adding remote tech/bus/usb/gadget https://github.com/qualcomm-linux/kernel-topics.git tech/bus/usb/gadget +Updating tech/bus/usb/gadget +Adding remote tech/bus/usb/phy https://github.com/qualcomm-linux/kernel-topics.git tech/bus/usb/phy +Updating tech/bus/usb/phy +Adding remote tech/debug/eud https://github.com/qualcomm-linux/kernel-topics.git tech/debug/eud +Updating tech/debug/eud +Adding remote tech/debug/hwtracing https://github.com/qualcomm-linux/kernel-topics.git tech/debug/hwtracing +Updating tech/debug/hwtracing +Adding remote tech/debug/rdbg https://github.com/qualcomm-linux/kernel-topics.git tech/debug/rdbg +Updating tech/debug/rdbg +Adding remote tech/pmic/backlight https://github.com/qualcomm-linux/kernel-topics.git tech/pmic/backlight +Updating tech/pmic/backlight +Adding remote tech/pmic/mfd https://github.com/qualcomm-linux/kernel-topics.git tech/pmic/mfd +Updating tech/pmic/mfd +Adding remote tech/pmic/misc https://github.com/qualcomm-linux/kernel-topics.git tech/pmic/misc +Updating tech/pmic/misc +Adding remote tech/pmic/regulator https://github.com/qualcomm-linux/kernel-topics.git tech/pmic/regulator +Updating tech/pmic/regulator +Adding remote tech/pmic/supply https://github.com/qualcomm-linux/kernel-topics.git tech/pmic/supply +Updating tech/pmic/supply +Adding remote tech/mem/dma-buf https://github.com/qualcomm-linux/kernel-topics.git tech/mem/dma-buf +Updating tech/mem/dma-buf +Adding remote tech/mem/iommu https://github.com/qualcomm-linux/kernel-topics.git tech/mem/iommu +Updating tech/mem/iommu +Adding remote tech/mm/audio/all https://github.com/qualcomm-linux/kernel-topics.git tech/mm/audio/all +Updating tech/mm/audio/all +Adding remote tech/mm/audio/soundwire https://github.com/qualcomm-linux/kernel-topics.git tech/mm/audio/soundwire +Updating tech/mm/audio/soundwire +Adding remote tech/mm/camss https://github.com/qualcomm-linux/kernel-topics.git tech/mm/camss +Updating tech/mm/camss +Adding remote tech/mm/drm https://github.com/qualcomm-linux/kernel-topics.git tech/mm/drm +Updating tech/mm/drm +Adding remote tech/mm/fastrpc https://github.com/qualcomm-linux/kernel-topics.git tech/mm/fastrpc +Updating tech/mm/fastrpc +Adding remote tech/mm/phy https://github.com/qualcomm-linux/kernel-topics.git tech/mm/phy +Updating tech/mm/phy +Adding remote tech/mm/video https://github.com/qualcomm-linux/kernel-topics.git tech/mm/video +Updating tech/mm/video +Adding remote tech/mm/gpu https://github.com/qualcomm-linux/kernel-topics.git tech/mm/gpu +Updating tech/mm/gpu +Adding remote tech/mproc/rpmsg https://github.com/qualcomm-linux/kernel-topics.git tech/mproc/rpmsg +Updating tech/mproc/rpmsg +Adding remote tech/mproc/qmi https://github.com/qualcomm-linux/kernel-topics.git tech/mproc/qmi +Updating tech/mproc/qmi +Adding remote tech/net/ath https://github.com/qualcomm-linux/kernel-topics.git tech/net/ath +Updating tech/net/ath +Adding remote tech/net/eth https://github.com/qualcomm-linux/kernel-topics.git tech/net/eth +Updating tech/net/eth +Adding remote tech/net/rmnet https://github.com/qualcomm-linux/kernel-topics.git tech/net/rmnet +Updating tech/net/rmnet +Adding remote tech/net/qrtr https://github.com/qualcomm-linux/kernel-topics.git tech/net/qrtr +Updating tech/net/qrtr +Adding remote tech/net/phy https://github.com/qualcomm-linux/kernel-topics.git tech/net/phy +Updating tech/net/phy +Adding remote tech/net/bluetooth https://github.com/qualcomm-linux/kernel-topics.git tech/net/bluetooth +Updating tech/net/bluetooth +Adding remote tech/pm/opp https://github.com/qualcomm-linux/kernel-topics.git tech/pm/opp +Updating tech/pm/opp +Adding remote tech/pm/pmdomain https://github.com/qualcomm-linux/kernel-topics.git tech/pm/pmdomain +Updating tech/pm/pmdomain +Adding remote tech/pm/power https://github.com/qualcomm-linux/kernel-topics.git tech/pm/power +Updating tech/pm/power +Adding remote tech/pm/thermal https://github.com/qualcomm-linux/kernel-topics.git tech/pm/thermal +Updating tech/pm/thermal +Adding remote tech/security/crypto https://github.com/qualcomm-linux/kernel-topics.git tech/security/crypto +Updating tech/security/crypto +Adding remote tech/security/fscrypt https://github.com/qualcomm-linux/kernel-topics.git tech/security/fscrypt +Updating tech/security/fscrypt +Adding remote tech/security/ice https://github.com/qualcomm-linux/kernel-topics.git tech/security/ice +Updating tech/security/ice +Adding remote tech/storage/nvmem https://github.com/qualcomm-linux/kernel-topics.git tech/storage/nvmem +Updating tech/storage/nvmem +Adding remote tech/storage/phy https://github.com/qualcomm-linux/kernel-topics.git tech/storage/phy +Updating tech/storage/phy +Adding remote tech/storage/all https://github.com/qualcomm-linux/kernel-topics.git tech/storage/all +Updating tech/storage/all +Adding remote tech/virt/gunyah https://github.com/qualcomm-linux/kernel-topics.git tech/virt/gunyah +Updating tech/virt/gunyah +Adding remote tech/all/dt/qcs6490 https://github.com/qualcomm-linux/kernel-topics.git tech/all/dt/qcs6490 +Updating tech/all/dt/qcs6490 +Adding remote tech/all/dt/qcs9100 https://github.com/qualcomm-linux/kernel-topics.git tech/all/dt/qcs9100 +Updating tech/all/dt/qcs9100 +Adding remote tech/all/dt/qcs8300 https://github.com/qualcomm-linux/kernel-topics.git tech/all/dt/qcs8300 +Updating tech/all/dt/qcs8300 +Adding remote tech/all/dt/qcs615 https://github.com/qualcomm-linux/kernel-topics.git tech/all/dt/qcs615 +Updating tech/all/dt/qcs615 +Adding remote tech/all/dt/hamoa https://github.com/qualcomm-linux/kernel-topics.git tech/all/dt/hamoa +Updating tech/all/dt/hamoa +Adding remote tech/all/dt/glymur https://github.com/qualcomm-linux/kernel-topics.git tech/all/dt/glymur +Updating tech/all/dt/glymur +Adding remote tech/all/dt/kaanapali https://github.com/qualcomm-linux/kernel-topics.git tech/all/dt/kaanapali +Updating tech/all/dt/kaanapali +Adding remote tech/all/dt/pakala https://github.com/qualcomm-linux/kernel-topics.git tech/all/dt/pakala +Updating tech/all/dt/pakala +Adding remote tech/all/config https://github.com/qualcomm-linux/kernel-topics.git tech/all/config +Updating tech/all/config +Adding remote tech/overlay/dt https://github.com/qualcomm-linux/kernel-topics.git tech/overlay/dt +Updating tech/overlay/dt +Adding remote tech/all/workaround https://github.com/qualcomm-linux/kernel-topics.git tech/all/workaround +Updating tech/all/workaround +Adding remote tech/mproc/all https://github.com/qualcomm-linux/kernel-topics.git tech/mproc/all +Updating tech/mproc/all +Done, added 66 new remote(s). +Updating the remotes ... +Updating tech/bsp/clk +Updating tech/bsp/interconnect +Updating tech/mem/secure-buffer +Updating tech/security/firmware-smc +Updating tech/bsp/soc-infra +Updating tech/debug/soc +Updating tech/bsp/pinctrl +Updating tech/bsp/remoteproc +Updating tech/bus/peripherals +Updating tech/bus/pci/all +Updating tech/bus/pci/mhi +Updating tech/bus/pci/phy +Updating tech/bus/pci/pwrctl +Updating tech/bus/usb/dwc +Updating tech/bus/usb/gadget +Updating tech/bus/usb/phy +Updating tech/debug/eud +Updating tech/debug/hwtracing +Updating tech/debug/rdbg +Updating tech/pmic/backlight +Updating tech/pmic/mfd +Updating tech/pmic/misc +Updating tech/pmic/regulator +Updating tech/pmic/supply +Updating tech/mem/dma-buf +Updating tech/mem/iommu +Updating tech/mm/audio/all +Updating tech/mm/audio/soundwire +Updating tech/mm/camss +Updating tech/mm/drm +Updating tech/mm/fastrpc +Updating tech/mm/phy +Updating tech/mm/video +Updating tech/mm/gpu +Updating tech/mproc/rpmsg +Updating tech/mproc/qmi +Updating tech/net/ath +Updating tech/net/eth +Updating tech/net/rmnet +Updating tech/net/qrtr +Updating tech/net/phy +Updating tech/net/bluetooth +Updating tech/pm/opp +Updating tech/pm/pmdomain +Updating tech/pm/power +Updating tech/pm/thermal +Updating tech/security/crypto +Updating tech/security/fscrypt +Updating tech/security/ice +Updating tech/storage/nvmem +Updating tech/storage/phy +Updating tech/storage/all +Updating tech/virt/gunyah +Updating tech/all/dt/qcs6490 +Updating tech/all/dt/qcs9100 +Updating tech/all/dt/qcs8300 +Updating tech/all/dt/qcs615 +Updating tech/all/dt/hamoa +Updating tech/all/dt/glymur +Updating tech/all/dt/kaanapali +Updating tech/all/dt/pakala +Updating tech/all/config +Updating tech/overlay/dt +Updating tech/all/workaround +Updating tech/mproc/all +Done, updated 0 remote(s). +Updating baseline ... +Fetching baseline +latest tag/id is 7d0a66e4bb9081d75c82ec4957c50034cb0ea449 +Done, updated baseline. +Latest tag is 7d0a66e4bb9081d75c82ec4957c50034cb0ea449 +Create a new integration branch based on 7d0a66e4bb9081d75c82ec4957c50034cb0ea449 +Merging topic branches... +------------------------------------------ + ** Merging topic branch: tech/bsp/clk/tech/bsp/clk +Merge successful : tech/bsp/clk : aea4f0c77e2524664061c3756cf8cadccec41145 : 8 +------------------------------------------ + ** Merging topic branch: tech/bsp/interconnect/tech/bsp/interconnect +Merge successful : tech/bsp/interconnect : 938409e3faa500839cfe2db3a2e3becfd9fb7fc6 : 2 +------------------------------------------ + ** Merging topic branch: tech/mem/secure-buffer/tech/mem/secure-buffer +Nothing to merge: Already up to date. +------------------------------------------ + ** Merging topic branch: tech/security/firmware-smc/tech/security/firmware-smc +Merge successful : tech/security/firmware-smc : a50984a91bb9d551ee48136ee2db90eca0929979 : 2 +------------------------------------------ + ** Merging topic branch: tech/bsp/soc-infra/tech/bsp/soc-infra +Merge successful : tech/bsp/soc-infra : 797d5a2c99ee52b6fdbafcd0862e867d151c0539 : 18 +------------------------------------------ + ** Merging topic branch: tech/debug/soc/tech/debug/soc +Nothing to merge: Already up to date. +------------------------------------------ + ** Merging topic branch: tech/bsp/pinctrl/tech/bsp/pinctrl +Merge successful : tech/bsp/pinctrl : 9a297f4d9e88c69bd9a650364126da4d2dbb658f : 2 +------------------------------------------ + ** Merging topic branch: tech/bsp/remoteproc/tech/bsp/remoteproc +Merge successful : tech/bsp/remoteproc : 464fb78ea02cf616d58464b045264e52c5f756cb : 13 +------------------------------------------ + ** Merging topic branch: tech/bus/peripherals/tech/bus/peripherals +Merge successful : tech/bus/peripherals : 486bcf7a4a94e54abf5fd9e6cc6bf68eea22a5d6 : 1 +------------------------------------------ + ** Merging topic branch: tech/bus/pci/all/tech/bus/pci/all +Merge successful : tech/bus/pci/all : 205830c6534ff4195ec16aa531f6dbcc4fa487e7 : 8 +------------------------------------------ + ** Merging topic branch: tech/bus/pci/mhi/tech/bus/pci/mhi +Nothing to merge: Already up to date. +------------------------------------------ + ** Merging topic branch: tech/bus/pci/phy/tech/bus/pci/phy +Nothing to merge: Already up to date. +------------------------------------------ + ** Merging topic branch: tech/bus/pci/pwrctl/tech/bus/pci/pwrctl +Merge successful : tech/bus/pci/pwrctl : c36944ebc50ed5d40b3c550cbe5792b93c32dc27 : 7 +------------------------------------------ + ** Merging topic branch: tech/bus/usb/dwc/tech/bus/usb/dwc +Merge successful : tech/bus/usb/dwc : c29f570c16249b9ae1472b08a3570f2985fa5532 : 1 +------------------------------------------ + ** Merging topic branch: tech/bus/usb/gadget/tech/bus/usb/gadget +Nothing to merge: Already up to date. +------------------------------------------ + ** Merging topic branch: tech/bus/usb/phy/tech/bus/usb/phy +Nothing to merge: Already up to date. +------------------------------------------ + ** Merging topic branch: tech/debug/eud/tech/debug/eud +Merge successful : tech/debug/eud : eb36d9dbce445b0a2032775a5668ba02dd4b67cb : 1 +------------------------------------------ + ** Merging topic branch: tech/debug/hwtracing/tech/debug/hwtracing +Merge successful : tech/debug/hwtracing : 961640988eb239085e7643c0ec26e627d8389049 : 34 +------------------------------------------ + ** Merging topic branch: tech/debug/rdbg/tech/debug/rdbg +Nothing to merge: Already up to date. +------------------------------------------ + ** Merging topic branch: tech/pmic/backlight/tech/pmic/backlight +Nothing to merge: Already up to date. +------------------------------------------ + ** Merging topic branch: tech/pmic/mfd/tech/pmic/mfd +Nothing to merge: Already up to date. +------------------------------------------ + ** Merging topic branch: tech/pmic/misc/tech/pmic/misc +Merge successful : tech/pmic/misc : 8fba65f6e2ddebad2e93252a85e30a35fa99733b : 14 +------------------------------------------ + ** Merging topic branch: tech/pmic/regulator/tech/pmic/regulator +Merge successful : tech/pmic/regulator : 81fc8fbf0f0a02a7b2d855aee574b88bd7d59107 : 6 +------------------------------------------ + ** Merging topic branch: tech/pmic/supply/tech/pmic/supply +Nothing to merge: Already up to date. +------------------------------------------ + ** Merging topic branch: tech/mem/dma-buf/tech/mem/dma-buf +Nothing to merge: Already up to date. +------------------------------------------ + ** Merging topic branch: tech/mem/iommu/tech/mem/iommu +Merge successful : tech/mem/iommu : fc1b59c1f4305fd3630a4205d2db8f680626ef5c : 1 +------------------------------------------ + ** Merging topic branch: tech/mm/audio/all/tech/mm/audio/all +Merge successful : tech/mm/audio/all : 37d1752ff15d0e43519f2803ab65e069d5af126f : 1 +------------------------------------------ + ** Merging topic branch: tech/mm/audio/soundwire/tech/mm/audio/soundwire +Nothing to merge: Already up to date. +------------------------------------------ + ** Merging topic branch: tech/mm/camss/tech/mm/camss +Merge successful : tech/mm/camss : d1d2c38f53e8f67b6a11866d4202561fbed0a988 : 3 +------------------------------------------ + ** Merging topic branch: tech/mm/drm/tech/mm/drm +Merge successful : tech/mm/drm : 378575e046b64e79a992b62453775ecfe63fc36b : 38 +------------------------------------------ + ** Merging topic branch: tech/mm/fastrpc/tech/mm/fastrpc +Merge successful : tech/mm/fastrpc : dba4eb255febb4cc38d2e340978c58f8f21ff6cc : 3 +------------------------------------------ + ** Merging topic branch: tech/mm/phy/tech/mm/phy +Nothing to merge: Already up to date. +------------------------------------------ + ** Merging topic branch: tech/mm/video/tech/mm/video +Merge successful : tech/mm/video : 1af1bf9935671af7c556b7e952a9afd2def6a58d : 13 +------------------------------------------ + ** Merging topic branch: tech/mm/gpu/tech/mm/gpu +Merge successful : tech/mm/gpu : 66e31064fee4eca6f3afa26a8db511bb160d2647 : 2 +------------------------------------------ + ** Merging topic branch: tech/mproc/rpmsg/tech/mproc/rpmsg +Nothing to merge: Already up to date. +------------------------------------------ + ** Merging topic branch: tech/mproc/qmi/tech/mproc/qmi +Nothing to merge: Already up to date. +------------------------------------------ + ** Merging topic branch: tech/net/ath/tech/net/ath +Merge successful : tech/net/ath : 7ed8cea7644a342684c7ca711f6ff7c65708affa : 2 +------------------------------------------ + ** Merging topic branch: tech/net/eth/tech/net/eth +Merge successful : tech/net/eth : c280d7e86faa86b16d3c1e313e95207503cf3770 : 1 +------------------------------------------ + ** Merging topic branch: tech/net/rmnet/tech/net/rmnet +Nothing to merge: Already up to date. +------------------------------------------ + ** Merging topic branch: tech/net/qrtr/tech/net/qrtr +Nothing to merge: Already up to date. +------------------------------------------ + ** Merging topic branch: tech/net/phy/tech/net/phy +Nothing to merge: Already up to date. +------------------------------------------ + ** Merging topic branch: tech/net/bluetooth/tech/net/bluetooth +Merge successful : tech/net/bluetooth : b5902f2daf61ad3eed61a9fbf3d75ba3748cf53e : 2 +------------------------------------------ + ** Merging topic branch: tech/pm/opp/tech/pm/opp +Nothing to merge: Already up to date. +------------------------------------------ + ** Merging topic branch: tech/pm/pmdomain/tech/pm/pmdomain +Merge successful : tech/pm/pmdomain : c2e58ee4e1ed72c4fe6fb6a48d8d83d4ea2269fc : 3 +------------------------------------------ + ** Merging topic branch: tech/pm/power/tech/pm/power +Merge successful : tech/pm/power : 9fe45cfe84f7873accec2689b312180897cb56d0 : 7 +------------------------------------------ + ** Merging topic branch: tech/pm/thermal/tech/pm/thermal +Merge successful : tech/pm/thermal : 44a5bf0663cff2f58a32907b7a944fa8c120812e : 1 +------------------------------------------ + ** Merging topic branch: tech/security/crypto/tech/security/crypto +Merge successful : tech/security/crypto : 0ff2ae7f2e708a083b489a9a4a34c07bd701aec1 : 11 +------------------------------------------ + ** Merging topic branch: tech/security/fscrypt/tech/security/fscrypt +Nothing to merge: Already up to date. +------------------------------------------ + ** Merging topic branch: tech/security/ice/tech/security/ice +Merge successful : tech/security/ice : e6140349dfc670e22f2507bb8f053be15b353ddd : 3 +------------------------------------------ + ** Merging topic branch: tech/storage/nvmem/tech/storage/nvmem +Nothing to merge: Already up to date. +------------------------------------------ + ** Merging topic branch: tech/storage/phy/tech/storage/phy +Nothing to merge: Already up to date. +------------------------------------------ + ** Merging topic branch: tech/storage/all/tech/storage/all +Merge successful : tech/storage/all : ba8c93ddc42883a8b91db3e5fd0f19d0c79a9ddb : 6 +------------------------------------------ + ** Merging topic branch: tech/virt/gunyah/tech/virt/gunyah +Nothing to merge: Already up to date. +------------------------------------------ + ** Merging topic branch: tech/all/dt/qcs6490/tech/all/dt/qcs6490 +Merge successful : tech/all/dt/qcs6490 : 91a5f259df1c65b4981c51e7d825a26617afbd50 : 7 +------------------------------------------ + ** Merging topic branch: tech/all/dt/qcs9100/tech/all/dt/qcs9100 +Merge successful : tech/all/dt/qcs9100 : ae04b95f30a6b56d2bbbf59fdb94d45e2be7d0f9 : 15 +------------------------------------------ + ** Merging topic branch: tech/all/dt/qcs8300/tech/all/dt/qcs8300 +Merge successful : tech/all/dt/qcs8300 : 6fc2c3911517bf9bde33e5795251ae465ff2c4d9 : 28 +------------------------------------------ + ** Merging topic branch: tech/all/dt/qcs615/tech/all/dt/qcs615 +Merge successful : tech/all/dt/qcs615 : ac047bf2fb68a45c0708be88eb78482f1b5278f3 : 8 +------------------------------------------ + ** Merging topic branch: tech/all/dt/hamoa/tech/all/dt/hamoa +Merge successful : tech/all/dt/hamoa : 731b038c653da0d0585f9fdfd9c0d04a9f489f3c : 10 +------------------------------------------ + ** Merging topic branch: tech/all/dt/glymur/tech/all/dt/glymur +Merge successful : tech/all/dt/glymur : 6e186f99af366fcd4e9d2e4e5cbf77198470ade9 : 20 +------------------------------------------ + ** Merging topic branch: tech/all/dt/kaanapali/tech/all/dt/kaanapali +Merge successful : tech/all/dt/kaanapali : 746a2029c703df8d18c3b3209cd1cb635a2abd92 : 3 +------------------------------------------ + ** Merging topic branch: tech/all/dt/pakala/tech/all/dt/pakala +Merge successful : tech/all/dt/pakala : e0326f1e866dc1c82669249763e1c76fd60f49f0 : 4 +------------------------------------------ + ** Merging topic branch: tech/all/config/tech/all/config +Merge successful : tech/all/config : b2866eca5697568294f76b9d665bfc6224f38dcf : 28 +------------------------------------------ + ** Merging topic branch: tech/overlay/dt/tech/overlay/dt +Merge failed, manual merge +No files need merging +[qcom-next 3342111513a1] Merge remote-tracking branch tech/overlay/dt into qcom-next +Merge successful : tech/overlay/dt : 03e0b7b70b8df2b6b498a1f7ed565c2bc4a0833b : 5 +------------------------------------------ + ** Merging topic branch: tech/all/workaround/tech/all/workaround +Merge failed, manual merge +No files need merging +[qcom-next 67a672b7d930] Merge remote-tracking branch tech/all/workaround into qcom-next +Merge successful : tech/all/workaround : 841239d0dc8294a4a9bb5f63b3f4c0dbcf21247f : 3 +------------------------------------------ + ** Merging topic branch: tech/mproc/all/tech/mproc/all +Merge successful : tech/mproc/all : 2cf103048fa6404ba91ace93c35997fee43b7f7d : 4 +Done, merged 42 topic(s). +[main 53bc5d7] New rr-cache entries from ci-merge + 1 file changed, 219 insertions(+) + create mode 100644 rr-cache/fd62a37d4fe0f74d9caa954b9b888e7f13e93a28/thisimage diff --git a/qcom-next/topic_SHA1 b/qcom-next/topic_SHA1 new file mode 100644 index 0000000000000..a6fe7348f4228 --- /dev/null +++ b/qcom-next/topic_SHA1 @@ -0,0 +1,44 @@ +Name SHA Commits +------------------------------------------------------------------------------------ +tech/bsp/clk aea4f0c77e2524664061c3756cf8cadccec41145 8 +tech/bsp/interconnect 938409e3faa500839cfe2db3a2e3becfd9fb7fc6 2 +tech/security/firmware-smc a50984a91bb9d551ee48136ee2db90eca0929979 2 +tech/bsp/soc-infra 797d5a2c99ee52b6fdbafcd0862e867d151c0539 18 +tech/bsp/pinctrl 9a297f4d9e88c69bd9a650364126da4d2dbb658f 2 +tech/bsp/remoteproc 464fb78ea02cf616d58464b045264e52c5f756cb 13 +tech/bus/peripherals 486bcf7a4a94e54abf5fd9e6cc6bf68eea22a5d6 1 +tech/bus/pci/all 205830c6534ff4195ec16aa531f6dbcc4fa487e7 8 +tech/bus/pci/pwrctl c36944ebc50ed5d40b3c550cbe5792b93c32dc27 7 +tech/bus/usb/dwc c29f570c16249b9ae1472b08a3570f2985fa5532 1 +tech/debug/eud eb36d9dbce445b0a2032775a5668ba02dd4b67cb 1 +tech/debug/hwtracing 961640988eb239085e7643c0ec26e627d8389049 34 +tech/pmic/misc 8fba65f6e2ddebad2e93252a85e30a35fa99733b 14 +tech/pmic/regulator 81fc8fbf0f0a02a7b2d855aee574b88bd7d59107 6 +tech/mem/iommu fc1b59c1f4305fd3630a4205d2db8f680626ef5c 1 +tech/mm/audio/all 37d1752ff15d0e43519f2803ab65e069d5af126f 1 +tech/mm/camss d1d2c38f53e8f67b6a11866d4202561fbed0a988 3 +tech/mm/drm 378575e046b64e79a992b62453775ecfe63fc36b 38 +tech/mm/fastrpc dba4eb255febb4cc38d2e340978c58f8f21ff6cc 3 +tech/mm/video 1af1bf9935671af7c556b7e952a9afd2def6a58d 13 +tech/mm/gpu 66e31064fee4eca6f3afa26a8db511bb160d2647 2 +tech/net/ath 7ed8cea7644a342684c7ca711f6ff7c65708affa 2 +tech/net/eth c280d7e86faa86b16d3c1e313e95207503cf3770 1 +tech/net/bluetooth b5902f2daf61ad3eed61a9fbf3d75ba3748cf53e 2 +tech/pm/pmdomain c2e58ee4e1ed72c4fe6fb6a48d8d83d4ea2269fc 3 +tech/pm/power 9fe45cfe84f7873accec2689b312180897cb56d0 7 +tech/pm/thermal 44a5bf0663cff2f58a32907b7a944fa8c120812e 1 +tech/security/crypto 0ff2ae7f2e708a083b489a9a4a34c07bd701aec1 11 +tech/security/ice e6140349dfc670e22f2507bb8f053be15b353ddd 3 +tech/storage/all ba8c93ddc42883a8b91db3e5fd0f19d0c79a9ddb 6 +tech/all/dt/qcs6490 91a5f259df1c65b4981c51e7d825a26617afbd50 7 +tech/all/dt/qcs9100 ae04b95f30a6b56d2bbbf59fdb94d45e2be7d0f9 15 +tech/all/dt/qcs8300 6fc2c3911517bf9bde33e5795251ae465ff2c4d9 28 +tech/all/dt/qcs615 ac047bf2fb68a45c0708be88eb78482f1b5278f3 8 +tech/all/dt/hamoa 731b038c653da0d0585f9fdfd9c0d04a9f489f3c 10 +tech/all/dt/glymur 6e186f99af366fcd4e9d2e4e5cbf77198470ade9 20 +tech/all/dt/kaanapali 746a2029c703df8d18c3b3209cd1cb635a2abd92 3 +tech/all/dt/pakala e0326f1e866dc1c82669249763e1c76fd60f49f0 4 +tech/all/config b2866eca5697568294f76b9d665bfc6224f38dcf 28 +tech/overlay/dt 03e0b7b70b8df2b6b498a1f7ed565c2bc4a0833b 5 +tech/all/workaround 841239d0dc8294a4a9bb5f63b3f4c0dbcf21247f 3 +tech/mproc/all 2cf103048fa6404ba91ace93c35997fee43b7f7d 4 From a68b06bdc17205d79196044192e436c55b239513 Mon Sep 17 00:00:00 2001 From: Bagas Sanjaya Date: Wed, 22 Oct 2025 10:43:35 +0700 Subject: [PATCH 0351/2333] Documentation: process: Also mention Sasha Levin as stable tree maintainer commit ba2457109d5b47a90fe565b39524f7225fc23e60 upstream. Sasha has also maintaining stable branch in conjunction with Greg since cb5d21946d2a2f ("MAINTAINERS: Add Sasha as a stable branch maintainer"). Mention him in 2.Process.rst. Cc: stable@vger.kernel.org Signed-off-by: Bagas Sanjaya Reviewed-by: Randy Dunlap Acked-by: Greg Kroah-Hartman Signed-off-by: Jonathan Corbet Message-ID: <20251022034336.22839-1-bagasdotme@gmail.com> Signed-off-by: Greg Kroah-Hartman --- Documentation/process/2.Process.rst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Documentation/process/2.Process.rst b/Documentation/process/2.Process.rst index ef3b116492df0..f4fc0da8999d9 100644 --- a/Documentation/process/2.Process.rst +++ b/Documentation/process/2.Process.rst @@ -104,8 +104,10 @@ kernels go out with a handful of known regressions though, hopefully, none of them are serious. Once a stable release is made, its ongoing maintenance is passed off to the -"stable team," currently Greg Kroah-Hartman. The stable team will release -occasional updates to the stable release using the 5.x.y numbering scheme. +"stable team," currently consists of Greg Kroah-Hartman and Sasha Levin. The +stable team will release occasional updates to the stable release using the +5.x.y numbering scheme. + To be considered for an update release, a patch must (1) fix a significant bug, and (2) already be merged into the mainline for the next development kernel. Kernels will typically receive stable updates for a little more From aa1703f3f706ea0867fb1991dcac709c9ec94cfb Mon Sep 17 00:00:00 2001 From: Ye Bin Date: Sat, 25 Oct 2025 15:26:57 +0800 Subject: [PATCH 0352/2333] jbd2: avoid bug_on in jbd2_journal_get_create_access() when file system corrupted commit 986835bf4d11032bba4ab8414d18fce038c61bb4 upstream. There's issue when file system corrupted: ------------[ cut here ]------------ kernel BUG at fs/jbd2/transaction.c:1289! Oops: invalid opcode: 0000 [#1] SMP KASAN PTI CPU: 5 UID: 0 PID: 2031 Comm: mkdir Not tainted 6.18.0-rc1-next RIP: 0010:jbd2_journal_get_create_access+0x3b6/0x4d0 RSP: 0018:ffff888117aafa30 EFLAGS: 00010202 RAX: 0000000000000000 RBX: ffff88811a86b000 RCX: ffffffff89a63534 RDX: 1ffff110200ec602 RSI: 0000000000000004 RDI: ffff888100763010 RBP: ffff888100763000 R08: 0000000000000001 R09: ffff888100763028 R10: 0000000000000003 R11: 0000000000000000 R12: 0000000000000000 R13: ffff88812c432000 R14: ffff88812c608000 R15: ffff888120bfc000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007f91d6970c99 CR3: 00000001159c4000 CR4: 00000000000006f0 Call Trace: __ext4_journal_get_create_access+0x42/0x170 ext4_getblk+0x319/0x6f0 ext4_bread+0x11/0x100 ext4_append+0x1e6/0x4a0 ext4_init_new_dir+0x145/0x1d0 ext4_mkdir+0x326/0x920 vfs_mkdir+0x45c/0x740 do_mkdirat+0x234/0x2f0 __x64_sys_mkdir+0xd6/0x120 do_syscall_64+0x5f/0xfa0 entry_SYSCALL_64_after_hwframe+0x76/0x7e The above issue occurs with us in errors=continue mode when accompanied by storage failures. There have been many inconsistencies in the file system data. In the case of file system data inconsistency, for example, if the block bitmap of a referenced block is not set, it can lead to the situation where a block being committed is allocated and used again. As a result, the following condition will not be satisfied then trigger BUG_ON. Of course, it is entirely possible to construct a problematic image that can trigger this BUG_ON through specific operations. In fact, I have constructed such an image and easily reproduced this issue. Therefore, J_ASSERT() holds true only under ideal conditions, but it may not necessarily be satisfied in exceptional scenarios. Using J_ASSERT() directly in abnormal situations would cause the system to crash, which is clearly not what we want. So here we directly trigger a JBD abort instead of immediately invoking BUG_ON. Fixes: 470decc613ab ("[PATCH] jbd2: initial copy of files from jbd") Signed-off-by: Ye Bin Reviewed-by: Jan Kara Message-ID: <20251025072657.307851-1-yebin@huaweicloud.com> Signed-off-by: Theodore Ts'o Cc: stable@kernel.org Signed-off-by: Greg Kroah-Hartman --- fs/jbd2/transaction.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c index 3e510564de6ee..9ce626ac947e3 100644 --- a/fs/jbd2/transaction.c +++ b/fs/jbd2/transaction.c @@ -1284,14 +1284,23 @@ int jbd2_journal_get_create_access(handle_t *handle, struct buffer_head *bh) * committing transaction's lists, but it HAS to be in Forget state in * that case: the transaction must have deleted the buffer for it to be * reused here. + * In the case of file system data inconsistency, for example, if the + * block bitmap of a referenced block is not set, it can lead to the + * situation where a block being committed is allocated and used again. + * As a result, the following condition will not be satisfied, so here + * we directly trigger a JBD abort instead of immediately invoking + * bugon. */ spin_lock(&jh->b_state_lock); - J_ASSERT_JH(jh, (jh->b_transaction == transaction || - jh->b_transaction == NULL || - (jh->b_transaction == journal->j_committing_transaction && - jh->b_jlist == BJ_Forget))); + if (!(jh->b_transaction == transaction || jh->b_transaction == NULL || + (jh->b_transaction == journal->j_committing_transaction && + jh->b_jlist == BJ_Forget)) || jh->b_next_transaction != NULL) { + err = -EROFS; + spin_unlock(&jh->b_state_lock); + jbd2_journal_abort(journal, err); + goto out; + } - J_ASSERT_JH(jh, jh->b_next_transaction == NULL); J_ASSERT_JH(jh, buffer_locked(jh2bh(jh))); if (jh->b_transaction == NULL) { From 58df743faf21ceb1880f930aa5dd428e2a5e415d Mon Sep 17 00:00:00 2001 From: Deepanshu Kartikey Date: Mon, 20 Oct 2025 11:39:36 +0530 Subject: [PATCH 0353/2333] ext4: refresh inline data size before write operations commit 892e1cf17555735e9d021ab036c36bc7b58b0e3b upstream. The cached ei->i_inline_size can become stale between the initial size check and when ext4_update_inline_data()/ext4_create_inline_data() use it. Although ext4_get_max_inline_size() reads the correct value at the time of the check, concurrent xattr operations can modify i_inline_size before ext4_write_lock_xattr() is acquired. This causes ext4_update_inline_data() and ext4_create_inline_data() to work with stale capacity values, leading to a BUG_ON() crash in ext4_write_inline_data(): kernel BUG at fs/ext4/inline.c:1331! BUG_ON(pos + len > EXT4_I(inode)->i_inline_size); The race window: 1. ext4_get_max_inline_size() reads i_inline_size = 60 (correct) 2. Size check passes for 50-byte write 3. [Another thread adds xattr, i_inline_size changes to 40] 4. ext4_write_lock_xattr() acquires lock 5. ext4_update_inline_data() uses stale i_inline_size = 60 6. Attempts to write 50 bytes but only 40 bytes actually available 7. BUG_ON() triggers Fix this by recalculating i_inline_size via ext4_find_inline_data_nolock() immediately after acquiring xattr_sem. This ensures ext4_update_inline_data() and ext4_create_inline_data() work with current values that are protected from concurrent modifications. This is similar to commit a54c4613dac1 ("ext4: fix race writing to an inline_data file while its xattrs are changing") which fixed i_inline_off staleness. This patch addresses the related i_inline_size staleness issue. Reported-by: syzbot+f3185be57d7e8dda32b8@syzkaller.appspotmail.com Link: https://syzkaller.appspot.com/bug?extid=f3185be57d7e8dda32b8 Cc: stable@kernel.org Signed-off-by: Deepanshu Kartikey Message-ID: <20251020060936.474314-1-kartikey406@gmail.com> Signed-off-by: Theodore Ts'o Signed-off-by: Greg Kroah-Hartman --- fs/ext4/inline.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/fs/ext4/inline.c b/fs/ext4/inline.c index 1b094a4f38663..b48c7dbe76a2b 100644 --- a/fs/ext4/inline.c +++ b/fs/ext4/inline.c @@ -418,7 +418,12 @@ static int ext4_prepare_inline_data(handle_t *handle, struct inode *inode, return -ENOSPC; ext4_write_lock_xattr(inode, &no_expand); - + /* + * ei->i_inline_size may have changed since the initial check + * if other xattrs were added. Recalculate to ensure + * ext4_update_inline_data() validates against current capacity. + */ + (void) ext4_find_inline_data_nolock(inode); if (ei->i_inline_off) ret = ext4_update_inline_data(handle, inode, len); else From 8229c6ca50cea701e25a7ee25f48441b582ec5fa Mon Sep 17 00:00:00 2001 From: Qianchang Zhao Date: Wed, 26 Nov 2025 12:24:18 +0900 Subject: [PATCH 0354/2333] ksmbd: ipc: fix use-after-free in ipc_msg_send_request commit 1fab1fa091f5aa97265648b53ea031deedd26235 upstream. ipc_msg_send_request() waits for a generic netlink reply using an ipc_msg_table_entry on the stack. The generic netlink handler (handle_generic_event()/handle_response()) fills entry->response under ipc_msg_table_lock, but ipc_msg_send_request() used to validate and free entry->response without holding the same lock. Under high concurrency this allows a race where handle_response() is copying data into entry->response while ipc_msg_send_request() has just freed it, leading to a slab-use-after-free reported by KASAN in handle_generic_event(): BUG: KASAN: slab-use-after-free in handle_generic_event+0x3c4/0x5f0 [ksmbd] Write of size 12 at addr ffff888198ee6e20 by task pool/109349 ... Freed by task: kvfree ipc_msg_send_request [ksmbd] ksmbd_rpc_open -> ksmbd_session_rpc_open [ksmbd] Fix by: - Taking ipc_msg_table_lock in ipc_msg_send_request() while validating entry->response, freeing it when invalid, and removing the entry from ipc_msg_table. - Returning the final entry->response pointer to the caller only after the hash entry is removed under the lock. - Returning NULL in the error path, preserving the original API semantics. This makes all accesses to entry->response consistent with handle_response(), which already updates and fills the response buffer under ipc_msg_table_lock, and closes the race that allowed the UAF. Cc: stable@vger.kernel.org Reported-by: Qianchang Zhao Reported-by: Zhitong Liu Signed-off-by: Qianchang Zhao Acked-by: Namjae Jeon Signed-off-by: Steve French Signed-off-by: Greg Kroah-Hartman --- fs/smb/server/transport_ipc.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/fs/smb/server/transport_ipc.c b/fs/smb/server/transport_ipc.c index 2c08cccfa6809..2dbabe2d80055 100644 --- a/fs/smb/server/transport_ipc.c +++ b/fs/smb/server/transport_ipc.c @@ -553,12 +553,16 @@ static void *ipc_msg_send_request(struct ksmbd_ipc_msg *msg, unsigned int handle up_write(&ipc_msg_table_lock); ret = ipc_msg_send(msg); - if (ret) + if (ret) { + down_write(&ipc_msg_table_lock); goto out; + } ret = wait_event_interruptible_timeout(entry.wait, entry.response != NULL, IPC_WAIT_TIMEOUT); + + down_write(&ipc_msg_table_lock); if (entry.response) { ret = ipc_validate_msg(&entry); if (ret) { @@ -567,7 +571,6 @@ static void *ipc_msg_send_request(struct ksmbd_ipc_msg *msg, unsigned int handle } } out: - down_write(&ipc_msg_table_lock); hash_del(&entry.ipc_table_hlist); up_write(&ipc_msg_table_lock); return entry.response; From 396a9270a7b90886be501611b13aa636f2e8c703 Mon Sep 17 00:00:00 2001 From: Alexander Sverdlin Date: Fri, 19 Sep 2025 11:12:38 +0200 Subject: [PATCH 0355/2333] locking/spinlock/debug: Fix data-race in do_raw_write_lock commit c14ecb555c3ee80eeb030a4e46d00e679537f03a upstream. KCSAN reports: BUG: KCSAN: data-race in do_raw_write_lock / do_raw_write_lock write (marked) to 0xffff800009cf504c of 4 bytes by task 1102 on cpu 1: do_raw_write_lock+0x120/0x204 _raw_write_lock_irq do_exit call_usermodehelper_exec_async ret_from_fork read to 0xffff800009cf504c of 4 bytes by task 1103 on cpu 0: do_raw_write_lock+0x88/0x204 _raw_write_lock_irq do_exit call_usermodehelper_exec_async ret_from_fork value changed: 0xffffffff -> 0x00000001 Reported by Kernel Concurrency Sanitizer on: CPU: 0 PID: 1103 Comm: kworker/u4:1 6.1.111 Commit 1a365e822372 ("locking/spinlock/debug: Fix various data races") has adressed most of these races, but seems to be not consistent/not complete. >From do_raw_write_lock() only debug_write_lock_after() part has been converted to WRITE_ONCE(), but not debug_write_lock_before() part. Do it now. Fixes: 1a365e822372 ("locking/spinlock/debug: Fix various data races") Reported-by: Adrian Freihofer Signed-off-by: Alexander Sverdlin Signed-off-by: Boqun Feng Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: Paul E. McKenney Acked-by: Waiman Long Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- kernel/locking/spinlock_debug.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/locking/spinlock_debug.c b/kernel/locking/spinlock_debug.c index 87b03d2e41dbb..2338b3adfb55f 100644 --- a/kernel/locking/spinlock_debug.c +++ b/kernel/locking/spinlock_debug.c @@ -184,8 +184,8 @@ void do_raw_read_unlock(rwlock_t *lock) static inline void debug_write_lock_before(rwlock_t *lock) { RWLOCK_BUG_ON(lock->magic != RWLOCK_MAGIC, lock, "bad magic"); - RWLOCK_BUG_ON(lock->owner == current, lock, "recursion"); - RWLOCK_BUG_ON(lock->owner_cpu == raw_smp_processor_id(), + RWLOCK_BUG_ON(READ_ONCE(lock->owner) == current, lock, "recursion"); + RWLOCK_BUG_ON(READ_ONCE(lock->owner_cpu) == raw_smp_processor_id(), lock, "cpu recursion"); } From e983feaa79de1e46c9087fb9f02fedb0e5397ce6 Mon Sep 17 00:00:00 2001 From: Giovanni Cabiddu Date: Thu, 20 Nov 2025 16:26:09 +0000 Subject: [PATCH 0356/2333] crypto: zstd - fix double-free in per-CPU stream cleanup commit 48bc9da3c97c15f1ea24934bcb3b736acd30163d upstream. The crypto/zstd module has a double-free bug that occurs when multiple tfms are allocated and freed. The issue happens because zstd_streams (per-CPU contexts) are freed in zstd_exit() during every tfm destruction, rather than being managed at the module level. When multiple tfms exist, each tfm exit attempts to free the same shared per-CPU streams, resulting in a double-free. This leads to a stack trace similar to: BUG: Bad page state in process kworker/u16:1 pfn:106fd93 page: refcount:0 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x106fd93 flags: 0x17ffffc0000000(node=0|zone=2|lastcpupid=0x1fffff) page_type: 0xffffffff() raw: 0017ffffc0000000 dead000000000100 dead000000000122 0000000000000000 raw: 0000000000000000 0000000000000000 00000000ffffffff 0000000000000000 page dumped because: nonzero entire_mapcount Modules linked in: ... CPU: 3 UID: 0 PID: 2506 Comm: kworker/u16:1 Kdump: loaded Tainted: G B Hardware name: ... Workqueue: btrfs-delalloc btrfs_work_helper Call Trace: dump_stack_lvl+0x5d/0x80 bad_page+0x71/0xd0 free_unref_page_prepare+0x24e/0x490 free_unref_page+0x60/0x170 crypto_acomp_free_streams+0x5d/0xc0 crypto_acomp_exit_tfm+0x23/0x50 crypto_destroy_tfm+0x60/0xc0 ... Change the lifecycle management of zstd_streams to free the streams only once during module cleanup. Fixes: f5ad93ffb541 ("crypto: zstd - convert to acomp") Cc: stable@vger.kernel.org Signed-off-by: Giovanni Cabiddu Reviewed-by: Suman Kumar Chakraborty Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman --- crypto/zstd.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/crypto/zstd.c b/crypto/zstd.c index ac318d333b684..32a339b74f34c 100644 --- a/crypto/zstd.c +++ b/crypto/zstd.c @@ -75,11 +75,6 @@ static int zstd_init(struct crypto_acomp *acomp_tfm) return ret; } -static void zstd_exit(struct crypto_acomp *acomp_tfm) -{ - crypto_acomp_free_streams(&zstd_streams); -} - static int zstd_compress_one(struct acomp_req *req, struct zstd_ctx *ctx, const void *src, void *dst, unsigned int *dlen) { @@ -297,7 +292,6 @@ static struct acomp_alg zstd_acomp = { .cra_module = THIS_MODULE, }, .init = zstd_init, - .exit = zstd_exit, .compress = zstd_compress, .decompress = zstd_decompress, }; @@ -310,6 +304,7 @@ static int __init zstd_mod_init(void) static void __exit zstd_mod_fini(void) { crypto_unregister_acomp(&zstd_acomp); + crypto_acomp_free_streams(&zstd_streams); } module_init(zstd_mod_init); From 5cad18e527ba8a9ca5463cc170073eeb5a4826f4 Mon Sep 17 00:00:00 2001 From: Alexey Nepomnyashih Date: Tue, 4 Nov 2025 09:33:25 +0000 Subject: [PATCH 0357/2333] ext4: add i_data_sem protection in ext4_destroy_inline_data_nolock() commit 0cd8feea8777f8d9b9a862b89c688b049a5c8475 upstream. Fix a race between inline data destruction and block mapping. The function ext4_destroy_inline_data_nolock() changes the inode data layout by clearing EXT4_INODE_INLINE_DATA and setting EXT4_INODE_EXTENTS. At the same time, another thread may execute ext4_map_blocks(), which tests EXT4_INODE_EXTENTS to decide whether to call ext4_ext_map_blocks() or ext4_ind_map_blocks(). Without i_data_sem protection, ext4_ind_map_blocks() may receive inode with EXT4_INODE_EXTENTS flag and triggering assert. kernel BUG at fs/ext4/indirect.c:546! EXT4-fs (loop2): unmounting filesystem. invalid opcode: 0000 [#1] PREEMPT SMP KASAN NOPTI Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.12.0-1 04/01/2014 RIP: 0010:ext4_ind_map_blocks.cold+0x2b/0x5a fs/ext4/indirect.c:546 Call Trace: ext4_map_blocks+0xb9b/0x16f0 fs/ext4/inode.c:681 _ext4_get_block+0x242/0x590 fs/ext4/inode.c:822 ext4_block_write_begin+0x48b/0x12c0 fs/ext4/inode.c:1124 ext4_write_begin+0x598/0xef0 fs/ext4/inode.c:1255 ext4_da_write_begin+0x21e/0x9c0 fs/ext4/inode.c:3000 generic_perform_write+0x259/0x5d0 mm/filemap.c:3846 ext4_buffered_write_iter+0x15b/0x470 fs/ext4/file.c:285 ext4_file_write_iter+0x8e0/0x17f0 fs/ext4/file.c:679 call_write_iter include/linux/fs.h:2271 [inline] do_iter_readv_writev+0x212/0x3c0 fs/read_write.c:735 do_iter_write+0x186/0x710 fs/read_write.c:861 vfs_iter_write+0x70/0xa0 fs/read_write.c:902 iter_file_splice_write+0x73b/0xc90 fs/splice.c:685 do_splice_from fs/splice.c:763 [inline] direct_splice_actor+0x10f/0x170 fs/splice.c:950 splice_direct_to_actor+0x33a/0xa10 fs/splice.c:896 do_splice_direct+0x1a9/0x280 fs/splice.c:1002 do_sendfile+0xb13/0x12c0 fs/read_write.c:1255 __do_sys_sendfile64 fs/read_write.c:1323 [inline] __se_sys_sendfile64 fs/read_write.c:1309 [inline] __x64_sys_sendfile64+0x1cf/0x210 fs/read_write.c:1309 do_syscall_x64 arch/x86/entry/common.c:51 [inline] do_syscall_64+0x35/0x80 arch/x86/entry/common.c:81 entry_SYSCALL_64_after_hwframe+0x6e/0xd8 Fixes: c755e251357a ("ext4: fix deadlock between inline_data and ext4_expand_extra_isize_ea()") Cc: stable@vger.kernel.org # v4.11+ Signed-off-by: Alexey Nepomnyashih Message-ID: <20251104093326.697381-1-sdl@nppct.ru> Signed-off-by: Theodore Ts'o Signed-off-by: Greg Kroah-Hartman --- fs/ext4/inline.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/fs/ext4/inline.c b/fs/ext4/inline.c index b48c7dbe76a2b..1f6bc05593df1 100644 --- a/fs/ext4/inline.c +++ b/fs/ext4/inline.c @@ -451,9 +451,13 @@ static int ext4_destroy_inline_data_nolock(handle_t *handle, if (!ei->i_inline_off) return 0; + down_write(&ei->i_data_sem); + error = ext4_get_inode_loc(inode, &is.iloc); - if (error) + if (error) { + up_write(&ei->i_data_sem); return error; + } error = ext4_xattr_ibody_find(inode, &i, &is); if (error) @@ -492,6 +496,7 @@ static int ext4_destroy_inline_data_nolock(handle_t *handle, brelse(is.iloc.bh); if (error == -ENODATA) error = 0; + up_write(&ei->i_data_sem); return error; } From 3428831264096d32f830a7fcfc7885dd263e511a Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Tue, 11 Nov 2025 14:23:32 +0000 Subject: [PATCH 0358/2333] rust_binder: fix race condition on death_list commit 3e0ae02ba831da2b707905f4e602e43f8507b8cc upstream. Rust Binder contains the following unsafe operation: // SAFETY: A `NodeDeath` is never inserted into the death list // of any node other than its owner, so it is either in this // death list or in no death list. unsafe { node_inner.death_list.remove(self) }; This operation is unsafe because when touching the prev/next pointers of a list element, we have to ensure that no other thread is also touching them in parallel. If the node is present in the list that `remove` is called on, then that is fine because we have exclusive access to that list. If the node is not in any list, then it's also ok. But if it's present in a different list that may be accessed in parallel, then that may be a data race on the prev/next pointers. And unfortunately that is exactly what is happening here. In Node::release, we: 1. Take the lock. 2. Move all items to a local list on the stack. 3. Drop the lock. 4. Iterate the local list on the stack. Combined with threads using the unsafe remove method on the original list, this leads to memory corruption of the prev/next pointers. This leads to crashes like this one: Unable to handle kernel paging request at virtual address 000bb9841bcac70e Mem abort info: ESR = 0x0000000096000044 EC = 0x25: DABT (current EL), IL = 32 bits SET = 0, FnV = 0 EA = 0, S1PTW = 0 FSC = 0x04: level 0 translation fault Data abort info: ISV = 0, ISS = 0x00000044, ISS2 = 0x00000000 CM = 0, WnR = 1, TnD = 0, TagAccess = 0 GCS = 0, Overlay = 0, DirtyBit = 0, Xs = 0 [000bb9841bcac70e] address between user and kernel address ranges Internal error: Oops: 0000000096000044 [#1] PREEMPT SMP google-cdd 538c004.gcdd: context saved(CPU:1) item - log_kevents is disabled Modules linked in: ... rust_binder CPU: 1 UID: 0 PID: 2092 Comm: kworker/1:178 Tainted: G S W OE 6.12.52-android16-5-g98debd5df505-4k #1 f94a6367396c5488d635708e43ee0c888d230b0b Tainted: [S]=CPU_OUT_OF_SPEC, [W]=WARN, [O]=OOT_MODULE, [E]=UNSIGNED_MODULE Hardware name: MUSTANG PVT 1.0 based on LGA (DT) Workqueue: events _RNvXs6_NtCsdfZWD8DztAw_6kernel9workqueueINtNtNtB7_4sync3arc3ArcNtNtCs8QPsHWIn21X_16rust_binder_main7process7ProcessEINtB5_15WorkItemPointerKy0_E3runB13_ [rust_binder] pstate: 23400005 (nzCv daif +PAN -UAO +TCO +DIT -SSBS BTYPE=--) pc : _RNvXs3_NtCs8QPsHWIn21X_16rust_binder_main7processNtB5_7ProcessNtNtCsdfZWD8DztAw_6kernel9workqueue8WorkItem3run+0x450/0x11f8 [rust_binder] lr : _RNvXs3_NtCs8QPsHWIn21X_16rust_binder_main7processNtB5_7ProcessNtNtCsdfZWD8DztAw_6kernel9workqueue8WorkItem3run+0x464/0x11f8 [rust_binder] sp : ffffffc09b433ac0 x29: ffffffc09b433d30 x28: ffffff8821690000 x27: ffffffd40cbaa448 x26: ffffff8821690000 x25: 00000000ffffffff x24: ffffff88d0376578 x23: 0000000000000001 x22: ffffffc09b433c78 x21: ffffff88e8f9bf40 x20: ffffff88e8f9bf40 x19: ffffff882692b000 x18: ffffffd40f10bf00 x17: 00000000c006287d x16: 00000000c006287d x15: 00000000000003b0 x14: 0000000000000100 x13: 000000201cb79ae0 x12: fffffffffffffff0 x11: 0000000000000000 x10: 0000000000000001 x9 : 0000000000000000 x8 : b80bb9841bcac706 x7 : 0000000000000001 x6 : fffffffebee63f30 x5 : 0000000000000000 x4 : 0000000000000001 x3 : 0000000000000000 x2 : 0000000000004c31 x1 : ffffff88216900c0 x0 : ffffff88e8f9bf00 Call trace: _RNvXs3_NtCs8QPsHWIn21X_16rust_binder_main7processNtB5_7ProcessNtNtCsdfZWD8DztAw_6kernel9workqueue8WorkItem3run+0x450/0x11f8 [rust_binder bbc172b53665bbc815363b22e97e3f7e3fe971fc] process_scheduled_works+0x1c4/0x45c worker_thread+0x32c/0x3e8 kthread+0x11c/0x1c8 ret_from_fork+0x10/0x20 Code: 94218d85 b4000155 a94026a8 d10102a0 (f9000509) ---[ end trace 0000000000000000 ]--- Thus, modify Node::release to pop items directly off the original list. Cc: stable@vger.kernel.org Fixes: eafedbc7c050 ("rust_binder: add Rust Binder driver") Signed-off-by: Alice Ryhl Acked-by: Miguel Ojeda Link: https://patch.msgid.link/20251111-binder-fix-list-remove-v1-1-8ed14a0da63d@google.com Signed-off-by: Greg Kroah-Hartman Signed-off-by: Greg Kroah-Hartman --- drivers/android/binder/node.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/android/binder/node.rs b/drivers/android/binder/node.rs index 08d362deaf61e..c26d113ede966 100644 --- a/drivers/android/binder/node.rs +++ b/drivers/android/binder/node.rs @@ -541,10 +541,10 @@ impl Node { guard = self.owner.inner.lock(); } - let death_list = core::mem::take(&mut self.inner.access_mut(&mut guard).death_list); - drop(guard); - for death in death_list { + while let Some(death) = self.inner.access_mut(&mut guard).death_list.pop_front() { + drop(guard); death.into_arc().set_dead(); + guard = self.owner.inner.lock(); } } From 877adccfacb32687b90714a27cfb09f444fdfa16 Mon Sep 17 00:00:00 2001 From: Nikita Zhandarovich Date: Thu, 23 Oct 2025 17:14:56 +0300 Subject: [PATCH 0359/2333] comedi: pcl818: fix null-ptr-deref in pcl818_ai_cancel() commit a51f025b5038abd3d22eed2ede4cd46793d89565 upstream. Syzbot identified an issue [1] in pcl818_ai_cancel(), which stems from the fact that in case of early device detach via pcl818_detach(), subdevice dev->read_subdev may not have initialized its pointer to &struct comedi_async as intended. Thus, any such dereferencing of &s->async->cmd will lead to general protection fault and kernel crash. Mitigate this problem by removing a call to pcl818_ai_cancel() from pcl818_detach() altogether. This way, if the subdevice setups its support for async commands, everything async-related will be handled via subdevice's own ->cancel() function in comedi_device_detach_locked() even before pcl818_detach(). If no support for asynchronous commands is provided, there is no need to cancel anything either. [1] Syzbot crash: Oops: general protection fault, probably for non-canonical address 0xdffffc0000000005: 0000 [#1] SMP KASAN PTI KASAN: null-ptr-deref in range [0x0000000000000028-0x000000000000002f] CPU: 1 UID: 0 PID: 6050 Comm: syz.0.18 Not tainted syzkaller #0 PREEMPT(full) Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 08/18/2025 RIP: 0010:pcl818_ai_cancel+0x69/0x3f0 drivers/comedi/drivers/pcl818.c:762 ... Call Trace: pcl818_detach+0x66/0xd0 drivers/comedi/drivers/pcl818.c:1115 comedi_device_detach_locked+0x178/0x750 drivers/comedi/drivers.c:207 do_devconfig_ioctl drivers/comedi/comedi_fops.c:848 [inline] comedi_unlocked_ioctl+0xcde/0x1020 drivers/comedi/comedi_fops.c:2178 vfs_ioctl fs/ioctl.c:51 [inline] __do_sys_ioctl fs/ioctl.c:597 [inline] ... Reported-by: syzbot+fce5d9d5bd067d6fbe9b@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=fce5d9d5bd067d6fbe9b Fixes: 00aba6e7b565 ("staging: comedi: pcl818: remove 'neverending_ai' from private data") Cc: stable Signed-off-by: Nikita Zhandarovich Reviewed-by: Ian Abbott Link: https://patch.msgid.link/20251023141457.398685-1-n.zhandarovich@fintech.ru Signed-off-by: Greg Kroah-Hartman Signed-off-by: Greg Kroah-Hartman --- drivers/comedi/drivers/pcl818.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/comedi/drivers/pcl818.c b/drivers/comedi/drivers/pcl818.c index 4127adcfb2295..06fe06396f23a 100644 --- a/drivers/comedi/drivers/pcl818.c +++ b/drivers/comedi/drivers/pcl818.c @@ -1111,10 +1111,9 @@ static void pcl818_detach(struct comedi_device *dev) { struct pcl818_private *devpriv = dev->private; - if (devpriv) { - pcl818_ai_cancel(dev, dev->read_subdev); + if (devpriv) pcl818_reset(dev); - } + pcl818_free_dma(dev); comedi_legacy_detach(dev); } From 53903ac9ca1abffa27327e85075ec496fa55ccf3 Mon Sep 17 00:00:00 2001 From: Omar Sandoval Date: Tue, 4 Nov 2025 09:55:26 -0800 Subject: [PATCH 0360/2333] KVM: SVM: Don't skip unrelated instruction if INT3/INTO is replaced commit 4da3768e1820cf15cced390242d8789aed34f54d upstream. When re-injecting a soft interrupt from an INT3, INT0, or (select) INTn instruction, discard the exception and retry the instruction if the code stream is changed (e.g. by a different vCPU) between when the CPU executes the instruction and when KVM decodes the instruction to get the next RIP. As effectively predicted by commit 6ef88d6e36c2 ("KVM: SVM: Re-inject INT3/INTO instead of retrying the instruction"), failure to verify that the correct INTn instruction was decoded can effectively clobber guest state due to decoding the wrong instruction and thus specifying the wrong next RIP. The bug most often manifests as "Oops: int3" panics on static branch checks in Linux guests. Enabling or disabling a static branch in Linux uses the kernel's "text poke" code patching mechanism. To modify code while other CPUs may be executing that code, Linux (temporarily) replaces the first byte of the original instruction with an int3 (opcode 0xcc), then patches in the new code stream except for the first byte, and finally replaces the int3 with the first byte of the new code stream. If a CPU hits the int3, i.e. executes the code while it's being modified, then the guest kernel must look up the RIP to determine how to handle the #BP, e.g. by emulating the new instruction. If the RIP is incorrect, then this lookup fails and the guest kernel panics. The bug reproduces almost instantly by hacking the guest kernel to repeatedly check a static branch[1] while running a drgn script[2] on the host to constantly swap out the memory containing the guest's TSS. [1]: https://gist.github.com/osandov/44d17c51c28c0ac998ea0334edf90b5a [2]: https://gist.github.com/osandov/10e45e45afa29b11e0c7209247afc00b Fixes: 6ef88d6e36c2 ("KVM: SVM: Re-inject INT3/INTO instead of retrying the instruction") Cc: stable@vger.kernel.org Co-developed-by: Sean Christopherson Signed-off-by: Omar Sandoval Link: https://patch.msgid.link/1cc6dcdf36e3add7ee7c8d90ad58414eeb6c3d34.1762278762.git.osandov@fb.com Signed-off-by: Sean Christopherson Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/kvm_host.h | 9 +++++++++ arch/x86/kvm/svm/svm.c | 24 +++++++++++++----------- arch/x86/kvm/x86.c | 21 +++++++++++++++++++++ 3 files changed, 43 insertions(+), 11 deletions(-) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 48598d017d6f3..974d64bf0a4d2 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -2143,6 +2143,11 @@ u64 vcpu_tsc_khz(struct kvm_vcpu *vcpu); * the gfn, i.e. retrying the instruction will hit a * !PRESENT fault, which results in a new shadow page * and sends KVM back to square one. + * + * EMULTYPE_SKIP_SOFT_INT - Set in combination with EMULTYPE_SKIP to only skip + * an instruction if it could generate a given software + * interrupt, which must be encoded via + * EMULTYPE_SET_SOFT_INT_VECTOR(). */ #define EMULTYPE_NO_DECODE (1 << 0) #define EMULTYPE_TRAP_UD (1 << 1) @@ -2153,6 +2158,10 @@ u64 vcpu_tsc_khz(struct kvm_vcpu *vcpu); #define EMULTYPE_PF (1 << 6) #define EMULTYPE_COMPLETE_USER_EXIT (1 << 7) #define EMULTYPE_WRITE_PF_TO_SP (1 << 8) +#define EMULTYPE_SKIP_SOFT_INT (1 << 9) + +#define EMULTYPE_SET_SOFT_INT_VECTOR(v) ((u32)((v) & 0xff) << 16) +#define EMULTYPE_GET_SOFT_INT_VECTOR(e) (((e) >> 16) & 0xff) static inline bool kvm_can_emulate_event_vectoring(int emul_type) { diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index 9d29b2e7e855d..f2fa69dd5cc72 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -272,6 +272,7 @@ static void svm_set_interrupt_shadow(struct kvm_vcpu *vcpu, int mask) } static int __svm_skip_emulated_instruction(struct kvm_vcpu *vcpu, + int emul_type, bool commit_side_effects) { struct vcpu_svm *svm = to_svm(vcpu); @@ -293,7 +294,7 @@ static int __svm_skip_emulated_instruction(struct kvm_vcpu *vcpu, if (unlikely(!commit_side_effects)) old_rflags = svm->vmcb->save.rflags; - if (!kvm_emulate_instruction(vcpu, EMULTYPE_SKIP)) + if (!kvm_emulate_instruction(vcpu, emul_type)) return 0; if (unlikely(!commit_side_effects)) @@ -311,11 +312,13 @@ static int __svm_skip_emulated_instruction(struct kvm_vcpu *vcpu, static int svm_skip_emulated_instruction(struct kvm_vcpu *vcpu) { - return __svm_skip_emulated_instruction(vcpu, true); + return __svm_skip_emulated_instruction(vcpu, EMULTYPE_SKIP, true); } -static int svm_update_soft_interrupt_rip(struct kvm_vcpu *vcpu) +static int svm_update_soft_interrupt_rip(struct kvm_vcpu *vcpu, u8 vector) { + const int emul_type = EMULTYPE_SKIP | EMULTYPE_SKIP_SOFT_INT | + EMULTYPE_SET_SOFT_INT_VECTOR(vector); unsigned long rip, old_rip = kvm_rip_read(vcpu); struct vcpu_svm *svm = to_svm(vcpu); @@ -331,7 +334,7 @@ static int svm_update_soft_interrupt_rip(struct kvm_vcpu *vcpu) * in use, the skip must not commit any side effects such as clearing * the interrupt shadow or RFLAGS.RF. */ - if (!__svm_skip_emulated_instruction(vcpu, !nrips)) + if (!__svm_skip_emulated_instruction(vcpu, emul_type, !nrips)) return -EIO; rip = kvm_rip_read(vcpu); @@ -367,7 +370,7 @@ static void svm_inject_exception(struct kvm_vcpu *vcpu) kvm_deliver_exception_payload(vcpu, ex); if (kvm_exception_is_soft(ex->vector) && - svm_update_soft_interrupt_rip(vcpu)) + svm_update_soft_interrupt_rip(vcpu, ex->vector)) return; svm->vmcb->control.event_inj = ex->vector @@ -3633,11 +3636,12 @@ static bool svm_set_vnmi_pending(struct kvm_vcpu *vcpu) static void svm_inject_irq(struct kvm_vcpu *vcpu, bool reinjected) { + struct kvm_queued_interrupt *intr = &vcpu->arch.interrupt; struct vcpu_svm *svm = to_svm(vcpu); u32 type; - if (vcpu->arch.interrupt.soft) { - if (svm_update_soft_interrupt_rip(vcpu)) + if (intr->soft) { + if (svm_update_soft_interrupt_rip(vcpu, intr->nr)) return; type = SVM_EVTINJ_TYPE_SOFT; @@ -3645,12 +3649,10 @@ static void svm_inject_irq(struct kvm_vcpu *vcpu, bool reinjected) type = SVM_EVTINJ_TYPE_INTR; } - trace_kvm_inj_virq(vcpu->arch.interrupt.nr, - vcpu->arch.interrupt.soft, reinjected); + trace_kvm_inj_virq(intr->nr, intr->soft, reinjected); ++vcpu->stat.irq_injections; - svm->vmcb->control.event_inj = vcpu->arch.interrupt.nr | - SVM_EVTINJ_VALID | type; + svm->vmcb->control.event_inj = intr->nr | SVM_EVTINJ_VALID | type; } void svm_complete_interrupt_delivery(struct kvm_vcpu *vcpu, int delivery_mode, diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index c9c2aa6f4705e..e6f2e34ec97d1 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -9337,6 +9337,23 @@ static bool is_vmware_backdoor_opcode(struct x86_emulate_ctxt *ctxt) return false; } +static bool is_soft_int_instruction(struct x86_emulate_ctxt *ctxt, + int emulation_type) +{ + u8 vector = EMULTYPE_GET_SOFT_INT_VECTOR(emulation_type); + + switch (ctxt->b) { + case 0xcc: + return vector == BP_VECTOR; + case 0xcd: + return vector == ctxt->src.val; + case 0xce: + return vector == OF_VECTOR; + default: + return false; + } +} + /* * Decode an instruction for emulation. The caller is responsible for handling * code breakpoints. Note, manually detecting code breakpoints is unnecessary @@ -9447,6 +9464,10 @@ int x86_emulate_instruction(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa, * injecting single-step #DBs. */ if (emulation_type & EMULTYPE_SKIP) { + if (emulation_type & EMULTYPE_SKIP_SOFT_INT && + !is_soft_int_instruction(ctxt, emulation_type)) + return 0; + if (ctxt->mode != X86EMUL_MODE_PROT64) ctxt->eip = (u32)ctxt->_eip; else From 99115ab00c1fcded6cae2403cea72ee09734d9c6 Mon Sep 17 00:00:00 2001 From: Slark Xiao Date: Tue, 18 Nov 2025 14:45:28 +0800 Subject: [PATCH 0361/2333] USB: serial: option: add Foxconn T99W760 commit 7970b4969c4c99bcdaf105f9f39c6d2021f6d244 upstream. T99W760 is designed based on Qualcomm SDX35 (5G redcap) chip. There are three serial ports to be enumerated: Modem, NMEA and Diag. test evidence as below: T: Bus=03 Lev=01 Prnt=01 Port=03 Cnt=01 Dev#= 4 Spd=5000 MxCh= 0 D: Ver= 3.20 Cls=ef(misc ) Sub=02 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=0489 ProdID=e123 Rev=05.15 S: Manufacturer=QCOM S: Product=SDXBAAGHA-IDP _SN:39A8D3E4 S: SerialNumber=39a8d3e4 C: #Ifs= 6 Cfg#= 1 Atr=a0 MxPwr=896mA I: If#= 0 Alt= 0 #EPs= 1 Cls=02(commc) Sub=0e Prot=00 Driver=cdc_mbim E: Ad=82(I) Atr=03(Int.) MxPS= 64 Ivl=32ms I: If#= 1 Alt= 1 #EPs= 2 Cls=0a(data ) Sub=00 Prot=02 Driver=cdc_mbim E: Ad=01(O) Atr=02(Bulk) MxPS=1024 Ivl=0ms E: Ad=81(I) Atr=02(Bulk) MxPS=1024 Ivl=0ms I: If#= 2 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=40 Driver=option E: Ad=02(O) Atr=02(Bulk) MxPS=1024 Ivl=0ms E: Ad=83(I) Atr=02(Bulk) MxPS=1024 Ivl=0ms E: Ad=84(I) Atr=03(Int.) MxPS= 10 Ivl=32ms I: If#= 3 Alt= 0 #EPs= 1 Cls=ff(vend.) Sub=ff Prot=ff Driver=(none) E: Ad=85(I) Atr=03(Int.) MxPS= 64 Ivl=32ms I: If#= 4 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=40 Driver=option E: Ad=03(O) Atr=02(Bulk) MxPS=1024 Ivl=0ms E: Ad=86(I) Atr=02(Bulk) MxPS=1024 Ivl=0ms E: Ad=87(I) Atr=03(Int.) MxPS= 10 Ivl=32ms I: If#= 5 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=30 Driver=option E: Ad=04(O) Atr=02(Bulk) MxPS=1024 Ivl=0ms E: Ad=88(I) Atr=02(Bulk) MxPS=1024 Ivl=0ms 0&1: MBIM, 2:Modem, 3:GNSS(non-serial port), 4: NMEA, 5:Diag Signed-off-by: Slark Xiao Cc: stable@vger.kernel.org Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index e9400727ad36e..d13226f9b811f 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -2376,6 +2376,8 @@ static const struct usb_device_id option_ids[] = { .driver_info = RSVD(3) }, { USB_DEVICE_INTERFACE_CLASS(0x0489, 0xe0f0, 0xff), /* Foxconn T99W373 MBIM */ .driver_info = RSVD(3) }, + { USB_DEVICE_INTERFACE_CLASS(0x0489, 0xe123, 0xff), /* Foxconn T99W760 MBIM */ + .driver_info = RSVD(3) }, { USB_DEVICE_INTERFACE_CLASS(0x0489, 0xe145, 0xff), /* Foxconn T99W651 RNDIS */ .driver_info = RSVD(5) | RSVD(6) }, { USB_DEVICE_INTERFACE_CLASS(0x0489, 0xe15f, 0xff), /* Foxconn T99W709 */ From 1425cc83a839a4c2f25c3272efa56461ff563065 Mon Sep 17 00:00:00 2001 From: Fabio Porcedda Date: Wed, 26 Nov 2025 15:26:39 +0100 Subject: [PATCH 0362/2333] USB: serial: option: add Telit Cinterion FE910C04 new compositions commit c908039a29aa70870871f4848125b3d743f929bf upstream. Add the following Telit Cinterion new compositions: 0x10c1: RNDIS + tty (AT/NMEA) + tty (AT) + tty (diag) T: Bus=01 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 2 Spd=480 MxCh= 0 D: Ver= 2.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS=64 #Cfgs= 1 P: Vendor=1bc7 ProdID=10c1 Rev=05.15 S: Manufacturer=Telit Cinterion S: Product=FE910 S: SerialNumber=f71b8b32 C: #Ifs= 5 Cfg#= 1 Atr=e0 MxPwr=500mA I: If#= 0 Alt= 0 #EPs= 1 Cls=ef(misc ) Sub=04 Prot=01 Driver=rndis_host E: Ad=82(I) Atr=03(Int.) MxPS= 8 Ivl=32ms I: If#= 1 Alt= 0 #EPs= 2 Cls=0a(data ) Sub=00 Prot=00 Driver=rndis_host E: Ad=01(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=81(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms I: If#= 2 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=60 Driver=option E: Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=83(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=84(I) Atr=03(Int.) MxPS= 10 Ivl=32ms I: If#= 3 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=40 Driver=option E: Ad=03(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=85(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=86(I) Atr=03(Int.) MxPS= 10 Ivl=32ms I: If#= 4 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=30 Driver=option E: Ad=04(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=87(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms 0x10c2: MBIM + tty (AT/NMEA) + tty (AT) + tty (diag) T: Bus=01 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 8 Spd=480 MxCh= 0 D: Ver= 2.00 Cls=ef(misc ) Sub=02 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=1bc7 ProdID=10c2 Rev=05.15 S: Manufacturer=Telit Cinterion S: Product=FE910 S: SerialNumber=f71b8b32 C: #Ifs= 5 Cfg#= 1 Atr=e0 MxPwr=500mA I: If#= 0 Alt= 0 #EPs= 1 Cls=02(commc) Sub=0e Prot=00 Driver=cdc_mbim E: Ad=82(I) Atr=03(Int.) MxPS= 64 Ivl=32ms I: If#= 1 Alt= 1 #EPs= 2 Cls=0a(data ) Sub=00 Prot=02 Driver=cdc_mbim E: Ad=01(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=81(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms I: If#= 2 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=60 Driver=option E: Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=83(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=84(I) Atr=03(Int.) MxPS= 10 Ivl=32ms I: If#= 3 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=40 Driver=option E: Ad=03(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=85(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=86(I) Atr=03(Int.) MxPS= 10 Ivl=32ms I: If#= 4 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=30 Driver=option E: Ad=04(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=87(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms 0x10c3: ECM + tty (AT/NMEA) + tty (AT) + tty (diag) T: Bus=01 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 9 Spd=480 MxCh= 0 D: Ver= 2.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS=64 #Cfgs= 1 P: Vendor=1bc7 ProdID=10c3 Rev=05.15 S: Manufacturer=Telit Cinterion S: Product=FE910 S: SerialNumber=f71b8b32 C: #Ifs= 5 Cfg#= 1 Atr=e0 MxPwr=500mA I: If#= 0 Alt= 0 #EPs= 1 Cls=02(commc) Sub=06 Prot=00 Driver=cdc_ether E: Ad=82(I) Atr=03(Int.) MxPS= 16 Ivl=32ms I: If#= 1 Alt= 1 #EPs= 2 Cls=0a(data ) Sub=00 Prot=00 Driver=cdc_ether E: Ad=01(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=81(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms I: If#= 2 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=60 Driver=option E: Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=83(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=84(I) Atr=03(Int.) MxPS= 10 Ivl=32ms I: If#= 3 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=40 Driver=option E: Ad=03(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=85(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=86(I) Atr=03(Int.) MxPS= 10 Ivl=32ms I: If#= 4 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=30 Driver=option E: Ad=04(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=87(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms 0x10c5: RNDIS + tty (AT) + tty (AT) + tty (diag) T: Bus=01 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 10 Spd=480 MxCh= 0 D: Ver= 2.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS=64 #Cfgs= 1 P: Vendor=1bc7 ProdID=10c5 Rev=05.15 S: Manufacturer=Telit Cinterion S: Product=FE910 S: SerialNumber=f71b8b32 C: #Ifs= 5 Cfg#= 1 Atr=e0 MxPwr=500mA I: If#= 0 Alt= 0 #EPs= 1 Cls=ef(misc ) Sub=04 Prot=01 Driver=rndis_host E: Ad=82(I) Atr=03(Int.) MxPS= 8 Ivl=32ms I: If#= 1 Alt= 0 #EPs= 2 Cls=0a(data ) Sub=00 Prot=00 Driver=rndis_host E: Ad=01(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=81(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms I: If#= 2 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=40 Driver=option E: Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=83(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=84(I) Atr=03(Int.) MxPS= 10 Ivl=32ms I: If#= 3 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=40 Driver=option E: Ad=03(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=85(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=86(I) Atr=03(Int.) MxPS= 10 Ivl=32ms I: If#= 4 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=30 Driver=option E: Ad=04(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=87(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms 0x10c6: MBIM + tty (AT) + tty (AT) + tty (diag) T: Bus=01 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 11 Spd=480 MxCh= 0 D: Ver= 2.00 Cls=ef(misc ) Sub=02 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=1bc7 ProdID=10c6 Rev=05.15 S: Manufacturer=Telit Cinterion S: Product=FE910 S: SerialNumber=f71b8b32 C: #Ifs= 5 Cfg#= 1 Atr=e0 MxPwr=500mA I: If#= 0 Alt= 0 #EPs= 1 Cls=02(commc) Sub=0e Prot=00 Driver=cdc_mbim E: Ad=82(I) Atr=03(Int.) MxPS= 64 Ivl=32ms I: If#= 1 Alt= 1 #EPs= 2 Cls=0a(data ) Sub=00 Prot=02 Driver=cdc_mbim E: Ad=01(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=81(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms I: If#= 2 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=40 Driver=option E: Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=83(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=84(I) Atr=03(Int.) MxPS= 10 Ivl=32ms I: If#= 3 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=40 Driver=option E: Ad=03(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=85(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=86(I) Atr=03(Int.) MxPS= 10 Ivl=32ms I: If#= 4 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=30 Driver=option E: Ad=04(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=87(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms 0x10c9: MBIM + tty (AT) + tty (diag) + DPL (Data Packet Logging) + adb T: Bus=01 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 13 Spd=480 MxCh= 0 D: Ver= 2.00 Cls=ef(misc ) Sub=02 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=1bc7 ProdID=10c9 Rev=05.15 S: Manufacturer=Telit Cinterion S: Product=FE910 S: SerialNumber=f71b8b32 C: #Ifs= 6 Cfg#= 1 Atr=e0 MxPwr=500mA I: If#= 0 Alt= 0 #EPs= 1 Cls=02(commc) Sub=0e Prot=00 Driver=cdc_mbim E: Ad=82(I) Atr=03(Int.) MxPS= 64 Ivl=32ms I: If#= 1 Alt= 1 #EPs= 2 Cls=0a(data ) Sub=00 Prot=02 Driver=cdc_mbim E: Ad=01(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=81(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms I: If#= 2 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=40 Driver=option E: Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=83(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=84(I) Atr=03(Int.) MxPS= 10 Ivl=32ms I: If#= 3 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=30 Driver=option E: Ad=03(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=85(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms I: If#= 4 Alt= 0 #EPs= 1 Cls=ff(vend.) Sub=ff Prot=80 Driver=(none) E: Ad=86(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms I: If#= 5 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=42 Prot=01 Driver=usbfs E: Ad=04(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=87(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms 0x10cb: RNDIS + tty (AT) + tty (diag) + DPL (Data Packet Logging) + adb T: Bus=01 Lev=01 Prnt=01 Port=09 Cnt=01 Dev#= 9 Spd=480 MxCh= 0 D: Ver= 2.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS=64 #Cfgs= 1 P: Vendor=1bc7 ProdID=10cb Rev=05.15 S: Manufacturer=Telit Cinterion S: Product=FE910 S: SerialNumber=f71b8b32 C: #Ifs= 6 Cfg#= 1 Atr=e0 MxPwr=500mA I: If#= 0 Alt= 0 #EPs= 1 Cls=ef(misc ) Sub=04 Prot=01 Driver=rndis_host E: Ad=82(I) Atr=03(Int.) MxPS= 8 Ivl=32ms I: If#= 1 Alt= 0 #EPs= 2 Cls=0a(data ) Sub=00 Prot=00 Driver=rndis_host E: Ad=01(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=81(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms I: If#= 2 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=40 Driver=option E: Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=83(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=84(I) Atr=03(Int.) MxPS= 10 Ivl=32ms I: If#= 3 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=30 Driver=option E: Ad=03(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=85(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms I: If#= 4 Alt= 0 #EPs= 1 Cls=ff(vend.) Sub=ff Prot=80 Driver=(none) E: Ad=86(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms I: If#= 5 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=42 Prot=01 Driver=(none) E: Ad=04(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=87(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms Cc: stable@vger.kernel.org Signed-off-by: Fabio Porcedda Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index d13226f9b811f..09f1876811b0d 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -1433,10 +1433,24 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x10b3, 0xff, 0xff, 0x60) }, { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x10c0, 0xff), /* Telit FE910C04 (rmnet) */ .driver_info = RSVD(0) | NCTRL(3) }, + { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x10c1, 0xff), /* Telit FE910C04 (RNDIS) */ + .driver_info = NCTRL(4) }, + { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x10c2, 0xff), /* Telit FE910C04 (MBIM) */ + .driver_info = NCTRL(4) }, + { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x10c3, 0xff), /* Telit FE910C04 (ECM) */ + .driver_info = NCTRL(4) }, { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x10c4, 0xff), /* Telit FE910C04 (rmnet) */ .driver_info = RSVD(0) | NCTRL(3) }, + { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x10c5, 0xff), /* Telit FE910C04 (RNDIS) */ + .driver_info = NCTRL(4) }, + { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x10c6, 0xff), /* Telit FE910C04 (MBIM) */ + .driver_info = NCTRL(4) }, { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x10c8, 0xff), /* Telit FE910C04 (rmnet) */ .driver_info = RSVD(0) | NCTRL(2) | RSVD(3) | RSVD(4) }, + { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x10c9, 0xff), /* Telit FE910C04 (MBIM) */ + .driver_info = NCTRL(3) | RSVD(4) | RSVD(5) }, + { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x10cb, 0xff), /* Telit FE910C04 (RNDIS) */ + .driver_info = NCTRL(3) | RSVD(4) | RSVD(5) }, { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x10d0, 0xff, 0xff, 0x30), /* Telit FN990B (rmnet) */ .driver_info = NCTRL(5) }, { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x10d0, 0xff, 0xff, 0x40) }, From a0538d99153f3f688649d09b4d637902846b585e Mon Sep 17 00:00:00 2001 From: Fabio Porcedda Date: Wed, 26 Nov 2025 15:26:40 +0100 Subject: [PATCH 0363/2333] USB: serial: option: move Telit 0x10c7 composition in the right place commit 072f2c49572547f4b0776fe2da6b8f61e4b34699 upstream. Move Telit 0x10c7 composition right after 0x10c6 composition and before 0x10c8 composition. Signed-off-by: Fabio Porcedda Cc: stable@vger.kernel.org Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 09f1876811b0d..4c0e5a3ab557b 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -1445,6 +1445,9 @@ static const struct usb_device_id option_ids[] = { .driver_info = NCTRL(4) }, { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x10c6, 0xff), /* Telit FE910C04 (MBIM) */ .driver_info = NCTRL(4) }, + { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x10c7, 0xff, 0xff, 0x30), /* Telit FE910C04 (ECM) */ + .driver_info = NCTRL(4) }, + { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x10c7, 0xff, 0xff, 0x40) }, { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x10c8, 0xff), /* Telit FE910C04 (rmnet) */ .driver_info = RSVD(0) | NCTRL(2) | RSVD(3) | RSVD(4) }, { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x10c9, 0xff), /* Telit FE910C04 (MBIM) */ @@ -1455,9 +1458,6 @@ static const struct usb_device_id option_ids[] = { .driver_info = NCTRL(5) }, { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x10d0, 0xff, 0xff, 0x40) }, { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x10d0, 0xff, 0xff, 0x60) }, - { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x10c7, 0xff, 0xff, 0x30), /* Telit FE910C04 (ECM) */ - .driver_info = NCTRL(4) }, - { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x10c7, 0xff, 0xff, 0x40) }, { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x10d1, 0xff, 0xff, 0x30), /* Telit FN990B (MBIM) */ .driver_info = NCTRL(6) }, { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x10d1, 0xff, 0xff, 0x40) }, From 64934857c8847ade8d1e061faf1128a929d1ab17 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 10 Nov 2025 12:12:05 +0100 Subject: [PATCH 0364/2333] USB: serial: ftdi_sio: match on interface number for jtag commit 4e31a5d0a9ee672f708fc993c1d5520643f769fd upstream. Some FTDI devices have the first port reserved for JTAG and have been using a dedicated quirk to prevent binding to it. As can be inferred directly or indirectly from the commit messages, almost all of these devices are dual port devices which means that the more recently added macro for matching on interface number can be used instead (and some such devices do so already). This avoids probing interfaces that will never be bound and cleans up the match table somewhat. Note that the JTAG quirk is kept for quad port devices, which would otherwise require three match entries. Cc: stable@vger.kernel.org Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 72 ++++++++++++----------------------- 1 file changed, 24 insertions(+), 48 deletions(-) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index b37fa31f56943..9993a5123344e 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -628,10 +628,8 @@ static const struct usb_device_id id_table_combined[] = { { USB_DEVICE(FTDI_VID, FTDI_IBS_PEDO_PID) }, { USB_DEVICE(FTDI_VID, FTDI_IBS_PROD_PID) }, { USB_DEVICE(FTDI_VID, FTDI_TAVIR_STK500_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_TIAO_UMPA_PID), - .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, - { USB_DEVICE(FTDI_VID, FTDI_NT_ORIONLXM_PID), - .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, + { USB_DEVICE_INTERFACE_NUMBER(FTDI_VID, FTDI_TIAO_UMPA_PID, 1) }, + { USB_DEVICE_INTERFACE_NUMBER(FTDI_VID, FTDI_NT_ORIONLXM_PID, 1) }, { USB_DEVICE(FTDI_VID, FTDI_NT_ORIONLX_PLUS_PID) }, { USB_DEVICE(FTDI_VID, FTDI_NT_ORION_IO_PID) }, { USB_DEVICE(FTDI_VID, FTDI_NT_ORIONMX_PID) }, @@ -842,24 +840,17 @@ static const struct usb_device_id id_table_combined[] = { { USB_DEVICE(FTDI_VID, FTDI_ELSTER_UNICOM_PID) }, { USB_DEVICE(FTDI_VID, FTDI_PROPOX_JTAGCABLEII_PID) }, { USB_DEVICE(FTDI_VID, FTDI_PROPOX_ISPCABLEIII_PID) }, - { USB_DEVICE(FTDI_VID, CYBER_CORTEX_AV_PID), - .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, + { USB_DEVICE_INTERFACE_NUMBER(FTDI_VID, CYBER_CORTEX_AV_PID, 1) }, { USB_DEVICE_INTERFACE_NUMBER(OLIMEX_VID, OLIMEX_ARM_USB_OCD_PID, 1) }, { USB_DEVICE_INTERFACE_NUMBER(OLIMEX_VID, OLIMEX_ARM_USB_OCD_H_PID, 1) }, { USB_DEVICE_INTERFACE_NUMBER(OLIMEX_VID, OLIMEX_ARM_USB_TINY_PID, 1) }, { USB_DEVICE_INTERFACE_NUMBER(OLIMEX_VID, OLIMEX_ARM_USB_TINY_H_PID, 1) }, - { USB_DEVICE(FIC_VID, FIC_NEO1973_DEBUG_PID), - .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, - { USB_DEVICE(FTDI_VID, FTDI_OOCDLINK_PID), - .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, - { USB_DEVICE(FTDI_VID, LMI_LM3S_DEVEL_BOARD_PID), - .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, - { USB_DEVICE(FTDI_VID, LMI_LM3S_EVAL_BOARD_PID), - .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, - { USB_DEVICE(FTDI_VID, LMI_LM3S_ICDI_BOARD_PID), - .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, - { USB_DEVICE(FTDI_VID, FTDI_TURTELIZER_PID), - .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, + { USB_DEVICE_INTERFACE_NUMBER(FIC_VID, FIC_NEO1973_DEBUG_PID, 1) }, + { USB_DEVICE_INTERFACE_NUMBER(FTDI_VID, FTDI_OOCDLINK_PID, 1) }, + { USB_DEVICE_INTERFACE_NUMBER(FTDI_VID, LMI_LM3S_DEVEL_BOARD_PID, 1) }, + { USB_DEVICE_INTERFACE_NUMBER(FTDI_VID, LMI_LM3S_EVAL_BOARD_PID, 1) }, + { USB_DEVICE_INTERFACE_NUMBER(FTDI_VID, LMI_LM3S_ICDI_BOARD_PID, 1) }, + { USB_DEVICE_INTERFACE_NUMBER(FTDI_VID, FTDI_TURTELIZER_PID, 1) }, { USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID_USB60F) }, { USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID_SCU18) }, { USB_DEVICE(FTDI_VID, FTDI_REU_TINY_PID) }, @@ -901,17 +892,14 @@ static const struct usb_device_id id_table_combined[] = { { USB_DEVICE(ATMEL_VID, STK541_PID) }, { USB_DEVICE(DE_VID, STB_PID) }, { USB_DEVICE(DE_VID, WHT_PID) }, - { USB_DEVICE(ADI_VID, ADI_GNICE_PID), - .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, - { USB_DEVICE(ADI_VID, ADI_GNICEPLUS_PID), - .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, + { USB_DEVICE_INTERFACE_NUMBER(ADI_VID, ADI_GNICE_PID, 1) }, + { USB_DEVICE_INTERFACE_NUMBER(ADI_VID, ADI_GNICEPLUS_PID, 1) }, { USB_DEVICE_AND_INTERFACE_INFO(MICROCHIP_VID, MICROCHIP_USB_BOARD_PID, USB_CLASS_VENDOR_SPEC, USB_SUBCLASS_VENDOR_SPEC, 0x00) }, { USB_DEVICE_INTERFACE_NUMBER(ACTEL_VID, MICROSEMI_ARROW_SF2PLUS_BOARD_PID, 2) }, { USB_DEVICE(JETI_VID, JETI_SPC1201_PID) }, - { USB_DEVICE(MARVELL_VID, MARVELL_SHEEVAPLUG_PID), - .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, + { USB_DEVICE_INTERFACE_NUMBER(MARVELL_VID, MARVELL_SHEEVAPLUG_PID, 1) }, { USB_DEVICE(LARSENBRUSGAARD_VID, LB_ALTITRACK_PID) }, { USB_DEVICE(GN_OTOMETRICS_VID, AURICAL_USB_PID) }, { USB_DEVICE(FTDI_VID, PI_C865_PID) }, @@ -934,10 +922,8 @@ static const struct usb_device_id id_table_combined[] = { { USB_DEVICE(PI_VID, PI_1016_PID) }, { USB_DEVICE(KONDO_VID, KONDO_USB_SERIAL_PID) }, { USB_DEVICE(BAYER_VID, BAYER_CONTOUR_CABLE_PID) }, - { USB_DEVICE(FTDI_VID, MARVELL_OPENRD_PID), - .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, - { USB_DEVICE(FTDI_VID, TI_XDS100V2_PID), - .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, + { USB_DEVICE_INTERFACE_NUMBER(FTDI_VID, MARVELL_OPENRD_PID, 1) }, + { USB_DEVICE_INTERFACE_NUMBER(FTDI_VID, TI_XDS100V2_PID, 1) }, { USB_DEVICE(FTDI_VID, HAMEG_HO820_PID) }, { USB_DEVICE(FTDI_VID, HAMEG_HO720_PID) }, { USB_DEVICE(FTDI_VID, HAMEG_HO730_PID) }, @@ -946,18 +932,14 @@ static const struct usb_device_id id_table_combined[] = { { USB_DEVICE(FTDI_VID, MJSG_SR_RADIO_PID) }, { USB_DEVICE(FTDI_VID, MJSG_HD_RADIO_PID) }, { USB_DEVICE(FTDI_VID, MJSG_XM_RADIO_PID) }, - { USB_DEVICE(FTDI_VID, XVERVE_SIGNALYZER_ST_PID), - .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, - { USB_DEVICE(FTDI_VID, XVERVE_SIGNALYZER_SLITE_PID), - .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, - { USB_DEVICE(FTDI_VID, XVERVE_SIGNALYZER_SH2_PID), - .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, + { USB_DEVICE_INTERFACE_NUMBER(FTDI_VID, XVERVE_SIGNALYZER_ST_PID, 1) }, + { USB_DEVICE_INTERFACE_NUMBER(FTDI_VID, XVERVE_SIGNALYZER_SLITE_PID, 1) }, + { USB_DEVICE_INTERFACE_NUMBER(FTDI_VID, XVERVE_SIGNALYZER_SH2_PID, 1) }, { USB_DEVICE(FTDI_VID, XVERVE_SIGNALYZER_SH4_PID), .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, { USB_DEVICE(FTDI_VID, SEGWAY_RMP200_PID) }, { USB_DEVICE(FTDI_VID, ACCESIO_COM4SM_PID) }, - { USB_DEVICE(IONICS_VID, IONICS_PLUGCOMPUTER_PID), - .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, + { USB_DEVICE_INTERFACE_NUMBER(IONICS_VID, IONICS_PLUGCOMPUTER_PID, 1) }, { USB_DEVICE(FTDI_VID, FTDI_CHAMSYS_24_MASTER_WING_PID) }, { USB_DEVICE(FTDI_VID, FTDI_CHAMSYS_PC_WING_PID) }, { USB_DEVICE(FTDI_VID, FTDI_CHAMSYS_USB_DMX_PID) }, @@ -972,15 +954,12 @@ static const struct usb_device_id id_table_combined[] = { { USB_DEVICE(FTDI_VID, FTDI_CINTERION_MC55I_PID) }, { USB_DEVICE(FTDI_VID, FTDI_FHE_PID) }, { USB_DEVICE(FTDI_VID, FTDI_DOTEC_PID) }, - { USB_DEVICE(QIHARDWARE_VID, MILKYMISTONE_JTAGSERIAL_PID), - .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, - { USB_DEVICE(ST_VID, ST_STMCLT_2232_PID), - .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, + { USB_DEVICE_INTERFACE_NUMBER(QIHARDWARE_VID, MILKYMISTONE_JTAGSERIAL_PID, 1) }, + { USB_DEVICE_INTERFACE_NUMBER(ST_VID, ST_STMCLT_2232_PID, 1) }, { USB_DEVICE(ST_VID, ST_STMCLT_4232_PID), .driver_info = (kernel_ulong_t)&ftdi_stmclite_quirk }, { USB_DEVICE(FTDI_VID, FTDI_RF_R106) }, - { USB_DEVICE(FTDI_VID, FTDI_DISTORTEC_JTAG_LOCK_PICK_PID), - .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, + { USB_DEVICE_INTERFACE_NUMBER(FTDI_VID, FTDI_DISTORTEC_JTAG_LOCK_PICK_PID, 1) }, { USB_DEVICE(FTDI_VID, FTDI_LUMEL_PD12_PID) }, /* Crucible Devices */ { USB_DEVICE(FTDI_VID, FTDI_CT_COMET_PID) }, @@ -1055,8 +1034,7 @@ static const struct usb_device_id id_table_combined[] = { { USB_DEVICE(ICPDAS_VID, ICPDAS_I7561U_PID) }, { USB_DEVICE(ICPDAS_VID, ICPDAS_I7563U_PID) }, { USB_DEVICE(WICED_VID, WICED_USB20706V2_PID) }, - { USB_DEVICE(TI_VID, TI_CC3200_LAUNCHPAD_PID), - .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, + { USB_DEVICE_INTERFACE_NUMBER(TI_VID, TI_CC3200_LAUNCHPAD_PID, 1) }, { USB_DEVICE(CYPRESS_VID, CYPRESS_WICED_BT_USB_PID) }, { USB_DEVICE(CYPRESS_VID, CYPRESS_WICED_WL_USB_PID) }, { USB_DEVICE(AIRBUS_DS_VID, AIRBUS_DS_P8GR) }, @@ -1076,10 +1054,8 @@ static const struct usb_device_id id_table_combined[] = { { USB_DEVICE(UBLOX_VID, UBLOX_C099F9P_ODIN_PID) }, { USB_DEVICE_INTERFACE_NUMBER(UBLOX_VID, UBLOX_EVK_M101_PID, 2) }, /* FreeCalypso USB adapters */ - { USB_DEVICE(FTDI_VID, FTDI_FALCONIA_JTAG_BUF_PID), - .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, - { USB_DEVICE(FTDI_VID, FTDI_FALCONIA_JTAG_UNBUF_PID), - .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, + { USB_DEVICE_INTERFACE_NUMBER(FTDI_VID, FTDI_FALCONIA_JTAG_BUF_PID, 1) }, + { USB_DEVICE_INTERFACE_NUMBER(FTDI_VID, FTDI_FALCONIA_JTAG_UNBUF_PID, 1) }, /* GMC devices */ { USB_DEVICE(GMC_VID, GMC_Z216C_PID) }, /* Altera USB Blaster 3 */ From 48e5794baf58c5ad789fd3301991eaa60417a6f0 Mon Sep 17 00:00:00 2001 From: Magne Bruno Date: Mon, 10 Nov 2025 17:24:56 +0100 Subject: [PATCH 0365/2333] serial: add support of CPCI cards commit 0e5a99e0e5f50353b86939ff6e424800d769c818 upstream. Addi-Data GmbH is manufacturing multi-serial ports cards supporting CompactPCI (known as CPCI). Those cards are identified with different DeviceIds. Those cards integrating standard UARTs work the same way as PCI/PCIe models already supported in the serial driver. Signed-off-by: Magne Bruno Link: https://patch.msgid.link/20251110162456.341029-1-magne.bruno@addi-data.com Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_pci.c | 37 ++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index 152f914c599dc..12e8ceffab65f 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -95,6 +95,11 @@ #define PCI_DEVICE_ID_MOXA_CP138E_A 0x1381 #define PCI_DEVICE_ID_MOXA_CP168EL_A 0x1683 +#define PCI_DEVICE_ID_ADDIDATA_CPCI7500 0x7003 +#define PCI_DEVICE_ID_ADDIDATA_CPCI7500_NG 0x7024 +#define PCI_DEVICE_ID_ADDIDATA_CPCI7420_NG 0x7025 +#define PCI_DEVICE_ID_ADDIDATA_CPCI7300_NG 0x7026 + /* Unknown vendors/cards - this should not be in linux/pci_ids.h */ #define PCI_SUBDEVICE_ID_UNKNOWN_0x1584 0x1584 #define PCI_SUBDEVICE_ID_UNKNOWN_0x1588 0x1588 @@ -5996,6 +6001,38 @@ static const struct pci_device_id serial_pci_tbl[] = { 0, pbn_ADDIDATA_PCIe_8_3906250 }, + { PCI_VENDOR_ID_ADDIDATA, + PCI_DEVICE_ID_ADDIDATA_CPCI7500, + PCI_ANY_ID, + PCI_ANY_ID, + 0, + 0, + pbn_b0_4_115200 }, + + { PCI_VENDOR_ID_ADDIDATA, + PCI_DEVICE_ID_ADDIDATA_CPCI7500_NG, + PCI_ANY_ID, + PCI_ANY_ID, + 0, + 0, + pbn_b0_4_115200 }, + + { PCI_VENDOR_ID_ADDIDATA, + PCI_DEVICE_ID_ADDIDATA_CPCI7420_NG, + PCI_ANY_ID, + PCI_ANY_ID, + 0, + 0, + pbn_b0_2_115200 }, + + { PCI_VENDOR_ID_ADDIDATA, + PCI_DEVICE_ID_ADDIDATA_CPCI7300_NG, + PCI_ANY_ID, + PCI_ANY_ID, + 0, + 0, + pbn_b0_1_115200 }, + { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9835, PCI_VENDOR_ID_IBM, 0x0299, 0, 0, pbn_b0_bt_2_115200 }, From a136ffb888bbb4b2a1e0f284dbc40d5cc399eb17 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Fri, 14 Nov 2025 10:13:46 +0000 Subject: [PATCH 0366/2333] dt-bindings: serial: rsci: Drop "uart-has-rtscts: false" commit a6cdfd69ad38997108b862f9aafc547891506701 upstream. Drop "uart-has-rtscts: false" from binding as the IP supports hardware flow control on all SoCs. Cc: stable@kernel.org Fixes: 25422e8f46c1 ("dt-bindings: serial: Add compatible for Renesas RZ/T2H SoC in sci") Acked-by: Conor Dooley Reviewed-by: Geert Uytterhoeven Signed-off-by: Biju Das Link: https://patch.msgid.link/20251114101350.106699-2-biju.das.jz@bp.renesas.com Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/serial/renesas,rsci.yaml | 2 -- 1 file changed, 2 deletions(-) diff --git a/Documentation/devicetree/bindings/serial/renesas,rsci.yaml b/Documentation/devicetree/bindings/serial/renesas,rsci.yaml index f50d8e02f4764..6b1f827a335b3 100644 --- a/Documentation/devicetree/bindings/serial/renesas,rsci.yaml +++ b/Documentation/devicetree/bindings/serial/renesas,rsci.yaml @@ -54,8 +54,6 @@ properties: power-domains: maxItems: 1 - uart-has-rtscts: false - required: - compatible - reg From a1210a4023aaef57cbaf66066c78b3eefbc68731 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Fri, 14 Nov 2025 10:13:47 +0000 Subject: [PATCH 0367/2333] serial: sh-sci: Fix deadlock during RSCI FIFO overrun error commit 75a9f4c54770f062f4b3813a83667452b326dda3 upstream. On RSCI IP, a deadlock occurs during a FIFO overrun error, as it uses a different register to clear the FIFO overrun error status. Cc: stable@kernel.org Fixes: 0666e3fe95ab ("serial: sh-sci: Add support for RZ/T2H SCI") Signed-off-by: Biju Das Reviewed-by: Geert Uytterhoeven Link: https://patch.msgid.link/20251114101350.106699-3-biju.das.jz@bp.renesas.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sh-sci.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 62bb62b82cbe5..1db4af6fe5909 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -1024,8 +1024,16 @@ static int sci_handle_fifo_overrun(struct uart_port *port) status = s->ops->read_reg(port, s->params->overrun_reg); if (status & s->params->overrun_mask) { - status &= ~s->params->overrun_mask; - s->ops->write_reg(port, s->params->overrun_reg, status); + if (s->type == SCI_PORT_RSCI) { + /* + * All of the CFCLR_*C clearing bits match the corresponding + * CSR_*status bits. So, reuse the overrun mask for clearing. + */ + s->ops->clear_SCxSR(port, s->params->overrun_mask); + } else { + status &= ~s->params->overrun_mask; + s->ops->write_reg(port, s->params->overrun_reg, status); + } port->icount.overrun++; From 1888f286b7afeeb7a66eb30f46c9053ac8c0b25d Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 22 Oct 2025 17:26:33 +0200 Subject: [PATCH 0368/2333] USB: serial: belkin_sa: fix TIOCMBIS and TIOCMBIC commit b6e0b3016187446ddef9edac03cd9d544ac63f11 upstream. Asserting or deasserting a modem control line using TIOCMBIS or TIOCMBIC should not deassert any lines that are not in the mask. Fix this long-standing regression dating back to 2003 when the tiocmset() callback was introduced. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Cc: stable@vger.kernel.org Reviewed-by: Greg Kroah-Hartman Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/belkin_sa.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c index 44f5b58beec92..aa6b4c4ad5ecb 100644 --- a/drivers/usb/serial/belkin_sa.c +++ b/drivers/usb/serial/belkin_sa.c @@ -435,7 +435,7 @@ static int belkin_sa_tiocmset(struct tty_struct *tty, struct belkin_sa_private *priv = usb_get_serial_port_data(port); unsigned long control_state; unsigned long flags; - int retval; + int retval = 0; int rts = 0; int dtr = 0; @@ -452,26 +452,32 @@ static int belkin_sa_tiocmset(struct tty_struct *tty, } if (clear & TIOCM_RTS) { control_state &= ~TIOCM_RTS; - rts = 0; + rts = 1; } if (clear & TIOCM_DTR) { control_state &= ~TIOCM_DTR; - dtr = 0; + dtr = 1; } priv->control_state = control_state; spin_unlock_irqrestore(&priv->lock, flags); - retval = BSA_USB_CMD(BELKIN_SA_SET_RTS_REQUEST, rts); - if (retval < 0) { - dev_err(&port->dev, "Set RTS error %d\n", retval); - goto exit; + if (rts) { + retval = BSA_USB_CMD(BELKIN_SA_SET_RTS_REQUEST, + !!(control_state & TIOCM_RTS)); + if (retval < 0) { + dev_err(&port->dev, "Set RTS error %d\n", retval); + goto exit; + } } - retval = BSA_USB_CMD(BELKIN_SA_SET_DTR_REQUEST, dtr); - if (retval < 0) { - dev_err(&port->dev, "Set DTR error %d\n", retval); - goto exit; + if (dtr) { + retval = BSA_USB_CMD(BELKIN_SA_SET_DTR_REQUEST, + !!(control_state & TIOCM_DTR)); + if (retval < 0) { + dev_err(&port->dev, "Set DTR error %d\n", retval); + goto exit; + } } exit: return retval; From e7edecc410886b75e9dd2b29391e1be4a6423f0a Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 22 Oct 2025 17:26:34 +0200 Subject: [PATCH 0369/2333] USB: serial: kobil_sct: fix TIOCMBIS and TIOCMBIC commit d432df758f92c4c28aac409bc807fd1716167577 upstream. Asserting or deasserting a modem control line using TIOCMBIS or TIOCMBIC should not deassert any lines that are not in the mask. Fix this long-standing issue dating back to 2003 when the support for these ioctls was added with the introduction of the tiocmset() callback. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Cc: stable@vger.kernel.org Reviewed-by: Greg Kroah-Hartman Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/kobil_sct.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c index 464433be20344..96ea571c436a7 100644 --- a/drivers/usb/serial/kobil_sct.c +++ b/drivers/usb/serial/kobil_sct.c @@ -418,7 +418,7 @@ static int kobil_tiocmset(struct tty_struct *tty, struct usb_serial_port *port = tty->driver_data; struct device *dev = &port->dev; struct kobil_private *priv; - int result; + int result = 0; int dtr = 0; int rts = 0; @@ -435,12 +435,12 @@ static int kobil_tiocmset(struct tty_struct *tty, if (set & TIOCM_DTR) dtr = 1; if (clear & TIOCM_RTS) - rts = 0; + rts = 1; if (clear & TIOCM_DTR) - dtr = 0; + dtr = 1; - if (priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID) { - if (dtr != 0) + if (dtr && priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID) { + if (set & TIOCM_DTR) dev_dbg(dev, "%s - Setting DTR\n", __func__); else dev_dbg(dev, "%s - Clearing DTR\n", __func__); @@ -448,13 +448,13 @@ static int kobil_tiocmset(struct tty_struct *tty, usb_sndctrlpipe(port->serial->dev, 0), SUSBCRequest_SetStatusLinesOrQueues, USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT, - ((dtr != 0) ? SUSBCR_SSL_SETDTR : SUSBCR_SSL_CLRDTR), + ((set & TIOCM_DTR) ? SUSBCR_SSL_SETDTR : SUSBCR_SSL_CLRDTR), 0, NULL, 0, KOBIL_TIMEOUT); - } else { - if (rts != 0) + } else if (rts) { + if (set & TIOCM_RTS) dev_dbg(dev, "%s - Setting RTS\n", __func__); else dev_dbg(dev, "%s - Clearing RTS\n", __func__); @@ -462,7 +462,7 @@ static int kobil_tiocmset(struct tty_struct *tty, usb_sndctrlpipe(port->serial->dev, 0), SUSBCRequest_SetStatusLinesOrQueues, USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT, - ((rts != 0) ? SUSBCR_SSL_SETRTS : SUSBCR_SSL_CLRRTS), + ((set & TIOCM_RTS) ? SUSBCR_SSL_SETRTS : SUSBCR_SSL_CLRRTS), 0, NULL, 0, From ce1d0f5c7b428007973c3d7f97329a5349d9fe33 Mon Sep 17 00:00:00 2001 From: Gopi Krishna Menon Date: Mon, 13 Oct 2025 16:27:20 +0700 Subject: [PATCH 0370/2333] Documentation/rtla: rename common_xxx.rst files to common_xxx.txt commit 96b546c241b11a97ba1247580208c554458e7866 upstream. Sphinx reports htmldocs errors: Documentation/tools/rtla/common_options.rst:58: ERROR: Undefined substitution referenced: "threshold". Documentation/tools/rtla/common_options.rst:88: ERROR: Undefined substitution referenced: "tool". Documentation/tools/rtla/common_options.rst:88: ERROR: Undefined substitution referenced: "thresharg". Documentation/tools/rtla/common_options.rst:88: ERROR: Undefined substitution referenced: "tracer". Documentation/tools/rtla/common_options.rst:92: ERROR: Undefined substitution referenced: "tracer". Documentation/tools/rtla/common_options.rst:98: ERROR: Undefined substitution referenced: "actionsperf". Documentation/tools/rtla/common_options.rst:113: ERROR: Undefined substitution referenced: "tool". common_*.rst files are snippets that are intended to be included by rtla docs (rtla*.rst). common_options.rst in particular contains substitutions which depend on other common_* includes, so building it independently as reST source results in above errors. Rename all common_*.rst files to common_*.txt to prevent Sphinx from building these snippets as standalone reST source and update all include references accordingly. Link: https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html#substitutions Suggested-by: Tomas Glozar Suggested-by: Bagas Sanjaya Signed-off-by: Gopi Krishna Menon Reviewed-by: Tomas Glozar Fixes: 05b7e10687c6 ("tools/rtla: Add remaining support for osnoise actions") Reviewed-by: Bagas Sanjaya Link: https://lore.kernel.org/r/20251008184522.13201-1-krishnagopi487@gmail.com [Bagas: massage commit message and apply trailers] Signed-off-by: Bagas Sanjaya Reviewed-by: Randy Dunlap Tested-by: Randy Dunlap Signed-off-by: Jonathan Corbet Message-ID: <20251013092719.30780-2-bagasdotme@gmail.com> Signed-off-by: Bagas Sanjaya Signed-off-by: Greg Kroah-Hartman --- .../{common_appendix.rst => common_appendix.txt} | 0 ...mmon_hist_options.rst => common_hist_options.txt} | 0 .../rtla/{common_options.rst => common_options.txt} | 0 ...escription.rst => common_osnoise_description.txt} | 0 ...snoise_options.rst => common_osnoise_options.txt} | 0 ...common_timerlat_aa.rst => common_timerlat_aa.txt} | 0 ...scription.rst => common_timerlat_description.txt} | 0 ...erlat_options.rst => common_timerlat_options.txt} | 0 ...common_top_options.rst => common_top_options.txt} | 0 Documentation/tools/rtla/rtla-hwnoise.rst | 8 ++++---- Documentation/tools/rtla/rtla-osnoise-hist.rst | 10 +++++----- Documentation/tools/rtla/rtla-osnoise-top.rst | 10 +++++----- Documentation/tools/rtla/rtla-osnoise.rst | 4 ++-- Documentation/tools/rtla/rtla-timerlat-hist.rst | 12 ++++++------ Documentation/tools/rtla/rtla-timerlat-top.rst | 12 ++++++------ Documentation/tools/rtla/rtla-timerlat.rst | 4 ++-- Documentation/tools/rtla/rtla.rst | 2 +- 17 files changed, 31 insertions(+), 31 deletions(-) rename Documentation/tools/rtla/{common_appendix.rst => common_appendix.txt} (100%) rename Documentation/tools/rtla/{common_hist_options.rst => common_hist_options.txt} (100%) rename Documentation/tools/rtla/{common_options.rst => common_options.txt} (100%) rename Documentation/tools/rtla/{common_osnoise_description.rst => common_osnoise_description.txt} (100%) rename Documentation/tools/rtla/{common_osnoise_options.rst => common_osnoise_options.txt} (100%) rename Documentation/tools/rtla/{common_timerlat_aa.rst => common_timerlat_aa.txt} (100%) rename Documentation/tools/rtla/{common_timerlat_description.rst => common_timerlat_description.txt} (100%) rename Documentation/tools/rtla/{common_timerlat_options.rst => common_timerlat_options.txt} (100%) rename Documentation/tools/rtla/{common_top_options.rst => common_top_options.txt} (100%) diff --git a/Documentation/tools/rtla/common_appendix.rst b/Documentation/tools/rtla/common_appendix.txt similarity index 100% rename from Documentation/tools/rtla/common_appendix.rst rename to Documentation/tools/rtla/common_appendix.txt diff --git a/Documentation/tools/rtla/common_hist_options.rst b/Documentation/tools/rtla/common_hist_options.txt similarity index 100% rename from Documentation/tools/rtla/common_hist_options.rst rename to Documentation/tools/rtla/common_hist_options.txt diff --git a/Documentation/tools/rtla/common_options.rst b/Documentation/tools/rtla/common_options.txt similarity index 100% rename from Documentation/tools/rtla/common_options.rst rename to Documentation/tools/rtla/common_options.txt diff --git a/Documentation/tools/rtla/common_osnoise_description.rst b/Documentation/tools/rtla/common_osnoise_description.txt similarity index 100% rename from Documentation/tools/rtla/common_osnoise_description.rst rename to Documentation/tools/rtla/common_osnoise_description.txt diff --git a/Documentation/tools/rtla/common_osnoise_options.rst b/Documentation/tools/rtla/common_osnoise_options.txt similarity index 100% rename from Documentation/tools/rtla/common_osnoise_options.rst rename to Documentation/tools/rtla/common_osnoise_options.txt diff --git a/Documentation/tools/rtla/common_timerlat_aa.rst b/Documentation/tools/rtla/common_timerlat_aa.txt similarity index 100% rename from Documentation/tools/rtla/common_timerlat_aa.rst rename to Documentation/tools/rtla/common_timerlat_aa.txt diff --git a/Documentation/tools/rtla/common_timerlat_description.rst b/Documentation/tools/rtla/common_timerlat_description.txt similarity index 100% rename from Documentation/tools/rtla/common_timerlat_description.rst rename to Documentation/tools/rtla/common_timerlat_description.txt diff --git a/Documentation/tools/rtla/common_timerlat_options.rst b/Documentation/tools/rtla/common_timerlat_options.txt similarity index 100% rename from Documentation/tools/rtla/common_timerlat_options.rst rename to Documentation/tools/rtla/common_timerlat_options.txt diff --git a/Documentation/tools/rtla/common_top_options.rst b/Documentation/tools/rtla/common_top_options.txt similarity index 100% rename from Documentation/tools/rtla/common_top_options.rst rename to Documentation/tools/rtla/common_top_options.txt diff --git a/Documentation/tools/rtla/rtla-hwnoise.rst b/Documentation/tools/rtla/rtla-hwnoise.rst index 3a7163c02ac8e..26512b15fe7ba 100644 --- a/Documentation/tools/rtla/rtla-hwnoise.rst +++ b/Documentation/tools/rtla/rtla-hwnoise.rst @@ -29,11 +29,11 @@ collection of the tracer output. OPTIONS ======= -.. include:: common_osnoise_options.rst +.. include:: common_osnoise_options.txt -.. include:: common_top_options.rst +.. include:: common_top_options.txt -.. include:: common_options.rst +.. include:: common_options.txt EXAMPLE ======= @@ -106,4 +106,4 @@ AUTHOR ====== Written by Daniel Bristot de Oliveira -.. include:: common_appendix.rst +.. include:: common_appendix.txt diff --git a/Documentation/tools/rtla/rtla-osnoise-hist.rst b/Documentation/tools/rtla/rtla-osnoise-hist.rst index 1fc60ef261067..007521c865d97 100644 --- a/Documentation/tools/rtla/rtla-osnoise-hist.rst +++ b/Documentation/tools/rtla/rtla-osnoise-hist.rst @@ -15,7 +15,7 @@ SYNOPSIS DESCRIPTION =========== -.. include:: common_osnoise_description.rst +.. include:: common_osnoise_description.txt The **rtla osnoise hist** tool collects all **osnoise:sample_threshold** occurrence in a histogram, displaying the results in a user-friendly way. @@ -24,11 +24,11 @@ collection of the tracer output. OPTIONS ======= -.. include:: common_osnoise_options.rst +.. include:: common_osnoise_options.txt -.. include:: common_hist_options.rst +.. include:: common_hist_options.txt -.. include:: common_options.rst +.. include:: common_options.txt EXAMPLE ======= @@ -65,4 +65,4 @@ AUTHOR ====== Written by Daniel Bristot de Oliveira -.. include:: common_appendix.rst +.. include:: common_appendix.txt diff --git a/Documentation/tools/rtla/rtla-osnoise-top.rst b/Documentation/tools/rtla/rtla-osnoise-top.rst index b1cbd7bcd4aed..6ccadae389457 100644 --- a/Documentation/tools/rtla/rtla-osnoise-top.rst +++ b/Documentation/tools/rtla/rtla-osnoise-top.rst @@ -15,7 +15,7 @@ SYNOPSIS DESCRIPTION =========== -.. include:: common_osnoise_description.rst +.. include:: common_osnoise_description.txt **rtla osnoise top** collects the periodic summary from the *osnoise* tracer, including the counters of the occurrence of the interference source, @@ -26,11 +26,11 @@ collection of the tracer output. OPTIONS ======= -.. include:: common_osnoise_options.rst +.. include:: common_osnoise_options.txt -.. include:: common_top_options.rst +.. include:: common_top_options.txt -.. include:: common_options.rst +.. include:: common_options.txt EXAMPLE ======= @@ -60,4 +60,4 @@ AUTHOR ====== Written by Daniel Bristot de Oliveira -.. include:: common_appendix.rst +.. include:: common_appendix.txt diff --git a/Documentation/tools/rtla/rtla-osnoise.rst b/Documentation/tools/rtla/rtla-osnoise.rst index c129b206ce348..540d2bf6c1524 100644 --- a/Documentation/tools/rtla/rtla-osnoise.rst +++ b/Documentation/tools/rtla/rtla-osnoise.rst @@ -14,7 +14,7 @@ SYNOPSIS DESCRIPTION =========== -.. include:: common_osnoise_description.rst +.. include:: common_osnoise_description.txt The *osnoise* tracer outputs information in two ways. It periodically prints a summary of the noise of the operating system, including the counters of @@ -56,4 +56,4 @@ AUTHOR ====== Written by Daniel Bristot de Oliveira -.. include:: common_appendix.rst +.. include:: common_appendix.txt diff --git a/Documentation/tools/rtla/rtla-timerlat-hist.rst b/Documentation/tools/rtla/rtla-timerlat-hist.rst index 4923a362129bb..f56fe546411bd 100644 --- a/Documentation/tools/rtla/rtla-timerlat-hist.rst +++ b/Documentation/tools/rtla/rtla-timerlat-hist.rst @@ -16,7 +16,7 @@ SYNOPSIS DESCRIPTION =========== -.. include:: common_timerlat_description.rst +.. include:: common_timerlat_description.txt The **rtla timerlat hist** displays a histogram of each tracer event occurrence. This tool uses the periodic information, and the @@ -25,13 +25,13 @@ occurrence. This tool uses the periodic information, and the OPTIONS ======= -.. include:: common_timerlat_options.rst +.. include:: common_timerlat_options.txt -.. include:: common_hist_options.rst +.. include:: common_hist_options.txt -.. include:: common_options.rst +.. include:: common_options.txt -.. include:: common_timerlat_aa.rst +.. include:: common_timerlat_aa.txt EXAMPLE ======= @@ -110,4 +110,4 @@ AUTHOR ====== Written by Daniel Bristot de Oliveira -.. include:: common_appendix.rst +.. include:: common_appendix.txt diff --git a/Documentation/tools/rtla/rtla-timerlat-top.rst b/Documentation/tools/rtla/rtla-timerlat-top.rst index 50968cdd2095a..7dbe625d0c424 100644 --- a/Documentation/tools/rtla/rtla-timerlat-top.rst +++ b/Documentation/tools/rtla/rtla-timerlat-top.rst @@ -16,7 +16,7 @@ SYNOPSIS DESCRIPTION =========== -.. include:: common_timerlat_description.rst +.. include:: common_timerlat_description.txt The **rtla timerlat top** displays a summary of the periodic output from the *timerlat* tracer. It also provides information for each @@ -26,13 +26,13 @@ seem with the option **-T**. OPTIONS ======= -.. include:: common_timerlat_options.rst +.. include:: common_timerlat_options.txt -.. include:: common_top_options.rst +.. include:: common_top_options.txt -.. include:: common_options.rst +.. include:: common_options.txt -.. include:: common_timerlat_aa.rst +.. include:: common_timerlat_aa.txt **--aa-only** *us* @@ -133,4 +133,4 @@ AUTHOR ------ Written by Daniel Bristot de Oliveira -.. include:: common_appendix.rst +.. include:: common_appendix.txt diff --git a/Documentation/tools/rtla/rtla-timerlat.rst b/Documentation/tools/rtla/rtla-timerlat.rst index 20e2d259467fd..ce9f57e038c37 100644 --- a/Documentation/tools/rtla/rtla-timerlat.rst +++ b/Documentation/tools/rtla/rtla-timerlat.rst @@ -14,7 +14,7 @@ SYNOPSIS DESCRIPTION =========== -.. include:: common_timerlat_description.rst +.. include:: common_timerlat_description.txt The **rtla timerlat top** mode displays a summary of the periodic output from the *timerlat* tracer. The **rtla timerlat hist** mode displays @@ -51,4 +51,4 @@ AUTHOR ====== Written by Daniel Bristot de Oliveira -.. include:: common_appendix.rst +.. include:: common_appendix.txt diff --git a/Documentation/tools/rtla/rtla.rst b/Documentation/tools/rtla/rtla.rst index fc0d233efcd5d..2a5fb7004ad44 100644 --- a/Documentation/tools/rtla/rtla.rst +++ b/Documentation/tools/rtla/rtla.rst @@ -45,4 +45,4 @@ AUTHOR ====== Daniel Bristot de Oliveira -.. include:: common_appendix.rst +.. include:: common_appendix.txt From f75b9d2c9f5b53cc3acacef62326417cd97e5e39 Mon Sep 17 00:00:00 2001 From: Zenm Chen Date: Mon, 29 Sep 2025 11:57:18 +0800 Subject: [PATCH 0371/2333] wifi: rtl8xxxu: Add USB ID 2001:3328 for D-Link AN3U rev. A1 commit 3f9553f65d0b77b724565bbe42c4daa3fab57d5c upstream. Add USB ID 2001:3328 for D-Link AN3U rev. A1 which is a RTL8192FU-based Wi-Fi adapter. Compile tested only. Cc: stable@vger.kernel.org # 6.6.x Signed-off-by: Zenm Chen Reviewed-by: Ping-Ke Shih Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250929035719.6172-1-zenmchen@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/realtek/rtl8xxxu/core.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/wireless/realtek/rtl8xxxu/core.c b/drivers/net/wireless/realtek/rtl8xxxu/core.c index 3ded5952729fc..be39463bd6c46 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/core.c @@ -8136,6 +8136,9 @@ static const struct usb_device_id dev_table[] = { /* TP-Link TL-WN823N V2 */ {USB_DEVICE_AND_INTERFACE_INFO(0x2357, 0x0135, 0xff, 0xff, 0xff), .driver_info = (unsigned long)&rtl8192fu_fops}, +/* D-Link AN3U rev. A1 */ +{USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x3328, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8192fu_fops}, #ifdef CONFIG_RTL8XXXU_UNTESTED /* Still supported by rtlwifi */ {USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x8176, 0xff, 0xff, 0xff), From 401b10a72f5a69ecdb5f57d554ab9e04a19268f1 Mon Sep 17 00:00:00 2001 From: Zenm Chen Date: Mon, 29 Sep 2025 11:57:19 +0800 Subject: [PATCH 0372/2333] wifi: rtw88: Add USB ID 2001:3329 for D-Link AC13U rev. A1 commit b377dcd9a286a6f81922ae442cd1c743bc4a2b35 upstream. Add USB ID 2001:3329 for D-Link AC13U rev. A1 which is a RTL8812CU-based Wi-Fi adapter. Compile tested only. Cc: stable@vger.kernel.org # 6.6.x Signed-off-by: Zenm Chen Acked-by: Ping-Ke Shih Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250929035719.6172-2-zenmchen@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/realtek/rtw88/rtw8822cu.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822cu.c b/drivers/net/wireless/realtek/rtw88/rtw8822cu.c index 324fd5c8bfd44..755f76840b121 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8822cu.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8822cu.c @@ -21,6 +21,8 @@ static const struct usb_device_id rtw_8822cu_id_table[] = { .driver_info = (kernel_ulong_t)&(rtw8822c_hw_spec) }, { USB_DEVICE_AND_INTERFACE_INFO(0x13b1, 0x0043, 0xff, 0xff, 0xff), .driver_info = (kernel_ulong_t)&(rtw8822c_hw_spec) }, /* Alpha - Alpha */ + { USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x3329, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&(rtw8822c_hw_spec) }, /* D-Link AC13U rev. A1 */ {}, }; MODULE_DEVICE_TABLE(usb, rtw_8822cu_id_table); From 4e6a40977495118373ce0e5d6b3ba4fe7d16ba17 Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Tue, 7 Oct 2025 11:15:20 +0000 Subject: [PATCH 0373/2333] iio: adc: ad4080: fix chip identification MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit b66cddc8be7278fd14650ff9182f3794397f8b31 upstream. Fix AD4080 chip identification by using the correct 16-bit product ID (0x0050) instead of GENMASK(2, 0). Update the chip reading logic to use regmap_bulk_read to read both PRODUCT_ID_L and PRODUCT_ID_H registers and combine them into a 16-bit value. The original implementation was incorrectly reading only 3 bits, which would not correctly identify the AD4080 chip. Fixes: 6b31ba1811b6 ("iio: adc: ad4080: add driver support") Signed-off-by: Antoniu Miclaus Reviewed-by: Nuno Sá Cc: Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman --- drivers/iio/adc/ad4080.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/iio/adc/ad4080.c b/drivers/iio/adc/ad4080.c index 6e61787ed3213..e15310fcd21a3 100644 --- a/drivers/iio/adc/ad4080.c +++ b/drivers/iio/adc/ad4080.c @@ -125,7 +125,7 @@ /* Miscellaneous Definitions */ #define AD4080_SPI_READ BIT(7) -#define AD4080_CHIP_ID GENMASK(2, 0) +#define AD4080_CHIP_ID 0x0050 #define AD4080_LVDS_CNV_CLK_CNT_MAX 7 @@ -445,7 +445,8 @@ static int ad4080_setup(struct iio_dev *indio_dev) { struct ad4080_state *st = iio_priv(indio_dev); struct device *dev = regmap_get_device(st->regmap); - unsigned int id; + __le16 id_le; + u16 id; int ret; ret = regmap_write(st->regmap, AD4080_REG_INTERFACE_CONFIG_A, @@ -458,10 +459,12 @@ static int ad4080_setup(struct iio_dev *indio_dev) if (ret) return ret; - ret = regmap_read(st->regmap, AD4080_REG_CHIP_TYPE, &id); + ret = regmap_bulk_read(st->regmap, AD4080_REG_PRODUCT_ID_L, &id_le, + sizeof(id_le)); if (ret) return ret; + id = le16_to_cpu(id_le); if (id != AD4080_CHIP_ID) dev_info(dev, "Unrecognized CHIP_ID 0x%X\n", id); From 888f7e2847bcb9df8257e656e1e837828942c53b Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Thu, 23 Oct 2025 13:31:41 +0100 Subject: [PATCH 0374/2333] comedi: c6xdigio: Fix invalid PNP driver unregistration commit 72262330f7b3ad2130e800cecf02adcce3c32c77 upstream. The Comedi low-level driver "c6xdigio" seems to be for a parallel port connected device. When the Comedi core calls the driver's Comedi "attach" handler `c6xdigio_attach()` to configure a Comedi to use this driver, it tries to enable the parallel port PNP resources by registering a PNP driver with `pnp_register_driver()`, but ignores the return value. (The `struct pnp_driver` it uses has only the `name` and `id_table` members filled in.) The driver's Comedi "detach" handler `c6xdigio_detach()` unconditionally unregisters the PNP driver with `pnp_unregister_driver()`. It is possible for `c6xdigio_attach()` to return an error before it calls `pnp_register_driver()` and it is possible for the call to `pnp_register_driver()` to return an error (that is ignored). In both cases, the driver should not be calling `pnp_unregister_driver()` as it does in `c6xdigio_detach()`. (Note that `c6xdigio_detach()` will be called by the Comedi core if `c6xdigio_attach()` returns an error, or if the Comedi core decides to detach the Comedi device from the driver for some other reason.) The unconditional call to `pnp_unregister_driver()` without a previous successful call to `pnp_register_driver()` will cause `driver_unregister()` to issue a warning "Unexpected driver unregister!". This was detected by Syzbot [1]. Also, the PNP driver registration and unregistration should be done at module init and exit time, respectively, not when attaching or detaching Comedi devices to the driver. (There might be more than one Comedi device being attached to the driver, although that is unlikely.) Change the driver to do the PNP driver registration at module init time, and the unregistration at module exit time. Since `c6xdigio_detach()` now only calls `comedi_legacy_detach()`, remove the function and change the Comedi driver "detach" handler to `comedi_legacy_detach`. ------------------------------------------- [1] Syzbot sample crash report: Unexpected driver unregister! WARNING: CPU: 0 PID: 5970 at drivers/base/driver.c:273 driver_unregister drivers/base/driver.c:273 [inline] WARNING: CPU: 0 PID: 5970 at drivers/base/driver.c:273 driver_unregister+0x90/0xb0 drivers/base/driver.c:270 Modules linked in: CPU: 0 UID: 0 PID: 5970 Comm: syz.0.17 Not tainted syzkaller #0 PREEMPT(full) Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 10/02/2025 RIP: 0010:driver_unregister drivers/base/driver.c:273 [inline] RIP: 0010:driver_unregister+0x90/0xb0 drivers/base/driver.c:270 Code: 48 89 ef e8 c2 e6 82 fc 48 89 df e8 3a 93 ff ff 5b 5d e9 c3 6d d9 fb e8 be 6d d9 fb 90 48 c7 c7 e0 f8 1f 8c e8 51 a2 97 fb 90 <0f> 0b 90 90 5b 5d e9 a5 6d d9 fb e8 e0 f4 41 fc eb 94 e8 d9 f4 41 RSP: 0018:ffffc9000373f9a0 EFLAGS: 00010282 RAX: 0000000000000000 RBX: ffffffff8ff24720 RCX: ffffffff817b6ee8 RDX: ffff88807c932480 RSI: ffffffff817b6ef5 RDI: 0000000000000001 RBP: 0000000000000000 R08: 0000000000000001 R09: 0000000000000000 R10: 0000000000000001 R11: 0000000000000001 R12: ffffffff8ff24660 R13: dffffc0000000000 R14: 0000000000000000 R15: ffff88814cca0000 FS: 000055556dab1500(0000) GS:ffff8881249d9000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 000055f77f285cd0 CR3: 000000007d871000 CR4: 00000000003526f0 Call Trace: comedi_device_detach_locked+0x12f/0xa50 drivers/comedi/drivers.c:207 comedi_device_detach+0x67/0xb0 drivers/comedi/drivers.c:215 comedi_device_attach+0x43d/0x900 drivers/comedi/drivers.c:1011 do_devconfig_ioctl+0x1b1/0x710 drivers/comedi/comedi_fops.c:872 comedi_unlocked_ioctl+0x165d/0x2f00 drivers/comedi/comedi_fops.c:2178 vfs_ioctl fs/ioctl.c:51 [inline] __do_sys_ioctl fs/ioctl.c:597 [inline] __se_sys_ioctl fs/ioctl.c:583 [inline] __x64_sys_ioctl+0x18e/0x210 fs/ioctl.c:583 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] do_syscall_64+0xcd/0xfa0 arch/x86/entry/syscall_64.c:94 entry_SYSCALL_64_after_hwframe+0x77/0x7f RIP: 0033:0x7fc05798eec9 Code: ff ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 40 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 a8 ff ff ff f7 d8 64 89 01 48 RSP: 002b:00007ffcf8184238 EFLAGS: 00000246 ORIG_RAX: 0000000000000010 RAX: ffffffffffffffda RBX: 00007fc057be5fa0 RCX: 00007fc05798eec9 RDX: 0000200000000080 RSI: 0000000040946400 RDI: 0000000000000003 RBP: 00007fc057a11f91 R08: 0000000000000000 R09: 0000000000000000 R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000 R13: 00007fc057be5fa0 R14: 00007fc057be5fa0 R15: 0000000000000003 ------------------------------------------- Reported-by: syzbot+6616bba359cec7a1def1@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=6616bba359cec7a1def1 Fixes: 2c89e159cd2f ("Staging: comedi: add c6xdigio driver") Cc: stable Signed-off-by: Ian Abbott Link: https://patch.msgid.link/20251023123141.6537-1-abbotti@mev.co.uk Signed-off-by: Greg Kroah-Hartman --- drivers/comedi/drivers/c6xdigio.c | 46 +++++++++++++++++++++++-------- 1 file changed, 35 insertions(+), 11 deletions(-) diff --git a/drivers/comedi/drivers/c6xdigio.c b/drivers/comedi/drivers/c6xdigio.c index 14b90d1c64dc1..8a38d97d463b2 100644 --- a/drivers/comedi/drivers/c6xdigio.c +++ b/drivers/comedi/drivers/c6xdigio.c @@ -249,9 +249,6 @@ static int c6xdigio_attach(struct comedi_device *dev, if (ret) return ret; - /* Make sure that PnP ports get activated */ - pnp_register_driver(&c6xdigio_pnp_driver); - s = &dev->subdevices[0]; /* pwm output subdevice */ s->type = COMEDI_SUBD_PWM; @@ -278,19 +275,46 @@ static int c6xdigio_attach(struct comedi_device *dev, return 0; } -static void c6xdigio_detach(struct comedi_device *dev) -{ - comedi_legacy_detach(dev); - pnp_unregister_driver(&c6xdigio_pnp_driver); -} - static struct comedi_driver c6xdigio_driver = { .driver_name = "c6xdigio", .module = THIS_MODULE, .attach = c6xdigio_attach, - .detach = c6xdigio_detach, + .detach = comedi_legacy_detach, }; -module_comedi_driver(c6xdigio_driver); + +static bool c6xdigio_pnp_registered = false; + +static int __init c6xdigio_module_init(void) +{ + int ret; + + ret = comedi_driver_register(&c6xdigio_driver); + if (ret) + return ret; + + if (IS_ENABLED(CONFIG_PNP)) { + /* Try to activate the PnP ports */ + ret = pnp_register_driver(&c6xdigio_pnp_driver); + if (ret) { + pr_warn("failed to register pnp driver - err %d\n", + ret); + ret = 0; /* ignore the error. */ + } else { + c6xdigio_pnp_registered = true; + } + } + + return 0; +} +module_init(c6xdigio_module_init); + +static void __exit c6xdigio_module_exit(void) +{ + if (c6xdigio_pnp_registered) + pnp_unregister_driver(&c6xdigio_pnp_driver); + comedi_driver_unregister(&c6xdigio_driver); +} +module_exit(c6xdigio_module_exit); MODULE_AUTHOR("Comedi https://www.comedi.org"); MODULE_DESCRIPTION("Comedi driver for the C6x_DIGIO DSP daughter card"); From 543f4c380c2e1f35e60528df7cb54705cda7fee3 Mon Sep 17 00:00:00 2001 From: Nikita Zhandarovich Date: Thu, 23 Oct 2025 16:22:04 +0300 Subject: [PATCH 0375/2333] comedi: multiq3: sanitize config options in multiq3_attach() commit f24c6e3a39fa355dabfb684c9ca82db579534e72 upstream. Syzbot identified an issue [1] in multiq3_attach() that induces a task timeout due to open() or COMEDI_DEVCONFIG ioctl operations, specifically, in the case of multiq3 driver. This problem arose when syzkaller managed to craft weird configuration options used to specify the number of channels in encoder subdevice. If a particularly great number is passed to s->n_chan in multiq3_attach() via it->options[2], then multiple calls to multiq3_encoder_reset() at the end of driver-specific attach() method will be running for minutes, thus blocking tasks and affected devices as well. While this issue is most likely not too dangerous for real-life devices, it still makes sense to sanitize configuration inputs. Enable a sensible limit on the number of encoder chips (4 chips max, each with 2 channels) to stop this behaviour from manifesting. [1] Syzbot crash: INFO: task syz.2.19:6067 blocked for more than 143 seconds. ... Call Trace: context_switch kernel/sched/core.c:5254 [inline] __schedule+0x17c4/0x4d60 kernel/sched/core.c:6862 __schedule_loop kernel/sched/core.c:6944 [inline] schedule+0x165/0x360 kernel/sched/core.c:6959 schedule_preempt_disabled+0x13/0x30 kernel/sched/core.c:7016 __mutex_lock_common kernel/locking/mutex.c:676 [inline] __mutex_lock+0x7e6/0x1350 kernel/locking/mutex.c:760 comedi_open+0xc0/0x590 drivers/comedi/comedi_fops.c:2868 chrdev_open+0x4cc/0x5e0 fs/char_dev.c:414 do_dentry_open+0x953/0x13f0 fs/open.c:965 vfs_open+0x3b/0x340 fs/open.c:1097 ... Reported-by: syzbot+7811bb68a317954a0347@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=7811bb68a317954a0347 Fixes: 77e01cdbad51 ("Staging: comedi: add multiq3 driver") Cc: stable Signed-off-by: Nikita Zhandarovich Reviewed-by: Ian Abbott Link: https://patch.msgid.link/20251023132205.395753-1-n.zhandarovich@fintech.ru Signed-off-by: Greg Kroah-Hartman --- drivers/comedi/drivers/multiq3.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/comedi/drivers/multiq3.c b/drivers/comedi/drivers/multiq3.c index 07ff5383da997..ac369e9a262d7 100644 --- a/drivers/comedi/drivers/multiq3.c +++ b/drivers/comedi/drivers/multiq3.c @@ -67,6 +67,11 @@ #define MULTIQ3_TRSFRCNTR_OL 0x10 /* xfer CNTR to OL (x and y) */ #define MULTIQ3_EFLAG_RESET 0x06 /* reset E bit of flag reg */ +/* + * Limit on the number of optional encoder channels + */ +#define MULTIQ3_MAX_ENC_CHANS 8 + static void multiq3_set_ctrl(struct comedi_device *dev, unsigned int bits) { /* @@ -312,6 +317,10 @@ static int multiq3_attach(struct comedi_device *dev, s->insn_read = multiq3_encoder_insn_read; s->insn_config = multiq3_encoder_insn_config; + /* sanity check for number of encoder channels */ + if (s->n_chan > MULTIQ3_MAX_ENC_CHANS) + s->n_chan = MULTIQ3_MAX_ENC_CHANS; + for (i = 0; i < s->n_chan; i++) multiq3_encoder_reset(dev, i); From aac80e912de306815297a3b74f0426873ffa7dc3 Mon Sep 17 00:00:00 2001 From: Nikita Zhandarovich Date: Thu, 23 Oct 2025 16:22:32 +0300 Subject: [PATCH 0376/2333] comedi: check device's attached status in compat ioctls commit 0de7d9cd07a2671fa6089173bccc0b2afe6b93ee upstream. Syzbot identified an issue [1] that crashes kernel, seemingly due to unexistent callback dev->get_valid_routes(). By all means, this should not occur as said callback must always be set to get_zero_valid_routes() in __comedi_device_postconfig(). As the crash seems to appear exclusively in i386 kernels, at least, judging from [1] reports, the blame lies with compat versions of standard IOCTL handlers. Several of them are modified and do not use comedi_unlocked_ioctl(). While functionality of these ioctls essentially copy their original versions, they do not have required sanity check for device's attached status. This, in turn, leads to a possibility of calling select IOCTLs on a device that has not been properly setup, even via COMEDI_DEVCONFIG. Doing so on unconfigured devices means that several crucial steps are missed, for instance, specifying dev->get_valid_routes() callback. Fix this somewhat crudely by ensuring device's attached status before performing any ioctls, improving logic consistency between modern and compat functions. [1] Syzbot report: BUG: kernel NULL pointer dereference, address: 0000000000000000 ... CR2: ffffffffffffffd6 CR3: 000000006c717000 CR4: 0000000000352ef0 Call Trace: get_valid_routes drivers/comedi/comedi_fops.c:1322 [inline] parse_insn+0x78c/0x1970 drivers/comedi/comedi_fops.c:1401 do_insnlist_ioctl+0x272/0x700 drivers/comedi/comedi_fops.c:1594 compat_insnlist drivers/comedi/comedi_fops.c:3208 [inline] comedi_compat_ioctl+0x810/0x990 drivers/comedi/comedi_fops.c:3273 __do_compat_sys_ioctl fs/ioctl.c:695 [inline] __se_compat_sys_ioctl fs/ioctl.c:638 [inline] __ia32_compat_sys_ioctl+0x242/0x370 fs/ioctl.c:638 do_syscall_32_irqs_on arch/x86/entry/syscall_32.c:83 [inline] ... Reported-by: syzbot+ab8008c24e84adee93ff@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=ab8008c24e84adee93ff Fixes: 3fbfd2223a27 ("comedi: get rid of compat_alloc_user_space() mess in COMEDI_CHANINFO compat") Cc: stable Reviewed-by: Ian Abbott Signed-off-by: Nikita Zhandarovich Link: https://patch.msgid.link/20251023132234.395794-1-n.zhandarovich@fintech.ru Signed-off-by: Greg Kroah-Hartman --- drivers/comedi/comedi_fops.c | 42 ++++++++++++++++++++++++++++++------ 1 file changed, 36 insertions(+), 6 deletions(-) diff --git a/drivers/comedi/comedi_fops.c b/drivers/comedi/comedi_fops.c index 7e2f2b1a1c362..b2e62e04afd99 100644 --- a/drivers/comedi/comedi_fops.c +++ b/drivers/comedi/comedi_fops.c @@ -3023,7 +3023,12 @@ static int compat_chaninfo(struct file *file, unsigned long arg) chaninfo.rangelist = compat_ptr(chaninfo32.rangelist); mutex_lock(&dev->mutex); - err = do_chaninfo_ioctl(dev, &chaninfo); + if (!dev->attached) { + dev_dbg(dev->class_dev, "no driver attached\n"); + err = -ENODEV; + } else { + err = do_chaninfo_ioctl(dev, &chaninfo); + } mutex_unlock(&dev->mutex); return err; } @@ -3044,7 +3049,12 @@ static int compat_rangeinfo(struct file *file, unsigned long arg) rangeinfo.range_ptr = compat_ptr(rangeinfo32.range_ptr); mutex_lock(&dev->mutex); - err = do_rangeinfo_ioctl(dev, &rangeinfo); + if (!dev->attached) { + dev_dbg(dev->class_dev, "no driver attached\n"); + err = -ENODEV; + } else { + err = do_rangeinfo_ioctl(dev, &rangeinfo); + } mutex_unlock(&dev->mutex); return err; } @@ -3120,7 +3130,12 @@ static int compat_cmd(struct file *file, unsigned long arg) return rc; mutex_lock(&dev->mutex); - rc = do_cmd_ioctl(dev, &cmd, ©, file); + if (!dev->attached) { + dev_dbg(dev->class_dev, "no driver attached\n"); + rc = -ENODEV; + } else { + rc = do_cmd_ioctl(dev, &cmd, ©, file); + } mutex_unlock(&dev->mutex); if (copy) { /* Special case: copy cmd back to user. */ @@ -3145,7 +3160,12 @@ static int compat_cmdtest(struct file *file, unsigned long arg) return rc; mutex_lock(&dev->mutex); - rc = do_cmdtest_ioctl(dev, &cmd, ©, file); + if (!dev->attached) { + dev_dbg(dev->class_dev, "no driver attached\n"); + rc = -ENODEV; + } else { + rc = do_cmdtest_ioctl(dev, &cmd, ©, file); + } mutex_unlock(&dev->mutex); if (copy) { err = put_compat_cmd(compat_ptr(arg), &cmd); @@ -3205,7 +3225,12 @@ static int compat_insnlist(struct file *file, unsigned long arg) } mutex_lock(&dev->mutex); - rc = do_insnlist_ioctl(dev, insns, insnlist32.n_insns, file); + if (!dev->attached) { + dev_dbg(dev->class_dev, "no driver attached\n"); + rc = -ENODEV; + } else { + rc = do_insnlist_ioctl(dev, insns, insnlist32.n_insns, file); + } mutex_unlock(&dev->mutex); kfree(insns); return rc; @@ -3224,7 +3249,12 @@ static int compat_insn(struct file *file, unsigned long arg) return rc; mutex_lock(&dev->mutex); - rc = do_insn_ioctl(dev, &insn, file); + if (!dev->attached) { + dev_dbg(dev->class_dev, "no driver attached\n"); + rc = -ENODEV; + } else { + rc = do_insn_ioctl(dev, &insn, file); + } mutex_unlock(&dev->mutex); return rc; } From c0d93d69e1472ba75b78898979b90a98ba2a2501 Mon Sep 17 00:00:00 2001 From: Navaneeth K Date: Thu, 20 Nov 2025 16:23:52 +0000 Subject: [PATCH 0377/2333] staging: rtl8723bs: fix out-of-bounds read in rtw_get_ie() parser commit 154828bf9559b9c8421fc2f0d7f7f76b3683aaed upstream. The Information Element (IE) parser rtw_get_ie() trusted the length byte of each IE without validating that the IE body (len bytes after the 2-byte header) fits inside the remaining frame buffer. A malformed frame can advertise an IE length larger than the available data, causing the parser to increment its pointer beyond the buffer end. This results in out-of-bounds reads or, depending on the pattern, an infinite loop. Fix by validating that (offset + 2 + len) does not exceed the limit before accepting the IE or advancing to the next element. This prevents OOB reads and ensures the parser terminates safely on malformed frames. Signed-off-by: Navaneeth K Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8723bs/core/rtw_ieee80211.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/staging/rtl8723bs/core/rtw_ieee80211.c b/drivers/staging/rtl8723bs/core/rtw_ieee80211.c index 53d4c113b19c8..df35c616e71ff 100644 --- a/drivers/staging/rtl8723bs/core/rtw_ieee80211.c +++ b/drivers/staging/rtl8723bs/core/rtw_ieee80211.c @@ -140,22 +140,24 @@ u8 *rtw_get_ie(u8 *pbuf, signed int index, signed int *len, signed int limit) signed int tmp, i; u8 *p; - if (limit < 1) + if (limit < 2) return NULL; p = pbuf; i = 0; *len = 0; - while (1) { + while (i + 2 <= limit) { + tmp = *(p + 1); + if (i + 2 + tmp > limit) + break; + if (*p == index) { - *len = *(p + 1); + *len = tmp; return p; } - tmp = *(p + 1); + p += (tmp + 2); i += (tmp + 2); - if (i >= limit) - break; } return NULL; } From e841d8ea722315b781c4fc5bf4f7670fbca88875 Mon Sep 17 00:00:00 2001 From: Navaneeth K Date: Thu, 20 Nov 2025 16:33:08 +0000 Subject: [PATCH 0378/2333] staging: rtl8723bs: fix stack buffer overflow in OnAssocReq IE parsing commit 6ef0e1c10455927867cac8f0ed6b49f328f8cf95 upstream. The Supported Rates IE length from an incoming Association Request frame was used directly as the memcpy() length when copying into a fixed-size 16-byte stack buffer (supportRate). A malicious station can advertise an IE length larger than 16 bytes, causing a stack buffer overflow. Clamp ie_len to the buffer size before copying the Supported Rates IE, and correct the bounds check when merging Extended Supported Rates to prevent a second potential overflow. This prevents kernel stack corruption triggered by malformed association requests. Signed-off-by: Navaneeth K Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8723bs/core/rtw_mlme_ext.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c b/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c index a897c433d2b06..fd7fa9278a780 100644 --- a/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c +++ b/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c @@ -1042,6 +1042,9 @@ unsigned int OnAssocReq(struct adapter *padapter, union recv_frame *precv_frame) status = WLAN_STATUS_CHALLENGE_FAIL; goto OnAssocReqFail; } else { + if (ie_len > sizeof(supportRate)) + ie_len = sizeof(supportRate); + memcpy(supportRate, p+2, ie_len); supportRateNum = ie_len; @@ -1049,7 +1052,7 @@ unsigned int OnAssocReq(struct adapter *padapter, union recv_frame *precv_frame) pkt_len - WLAN_HDR_A3_LEN - ie_offset); if (p) { - if (supportRateNum <= sizeof(supportRate)) { + if (supportRateNum + ie_len <= sizeof(supportRate)) { memcpy(supportRate+supportRateNum, p+2, ie_len); supportRateNum += ie_len; } From bf323db1d883c209880bd92f3b12503e3531c3fc Mon Sep 17 00:00:00 2001 From: Navaneeth K Date: Thu, 20 Nov 2025 16:35:20 +0000 Subject: [PATCH 0379/2333] staging: rtl8723bs: fix out-of-bounds read in OnBeacon ESR IE parsing commit 502ddcc405b69fa92e0add6c1714d654504f6fd7 upstream. The Extended Supported Rates (ESR) IE handling in OnBeacon accessed *(p + 1 + ielen) and *(p + 2 + ielen) without verifying that these offsets lie within the received frame buffer. A malformed beacon with an ESR IE positioned at the end of the buffer could cause an out-of-bounds read, potentially triggering a kernel panic. Add a boundary check to ensure that the ESR IE body and the subsequent bytes are within the limits of the frame before attempting to access them. This prevents OOB reads caused by malformed beacon frames. Signed-off-by: Navaneeth K Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8723bs/core/rtw_mlme_ext.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c b/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c index fd7fa9278a780..72eb48d554a35 100644 --- a/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c +++ b/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c @@ -588,9 +588,11 @@ unsigned int OnBeacon(struct adapter *padapter, union recv_frame *precv_frame) p = rtw_get_ie(pframe + sizeof(struct ieee80211_hdr_3addr) + _BEACON_IE_OFFSET_, WLAN_EID_EXT_SUPP_RATES, &ielen, precv_frame->u.hdr.len - sizeof(struct ieee80211_hdr_3addr) - _BEACON_IE_OFFSET_); if (p && ielen > 0) { - if ((*(p + 1 + ielen) == 0x2D) && (*(p + 2 + ielen) != 0x2D)) - /* Invalid value 0x2D is detected in Extended Supported Rates (ESR) IE. Try to fix the IE length to avoid failed Beacon parsing. */ - *(p + 1) = ielen - 1; + if (p + 2 + ielen < pframe + len) { + if ((*(p + 1 + ielen) == 0x2D) && (*(p + 2 + ielen) != 0x2D)) + /* Invalid value 0x2D is detected in Extended Supported Rates (ESR) IE. Try to fix the IE length to avoid failed Beacon parsing. */ + *(p + 1) = ielen - 1; + } } if (pmlmeext->sitesurvey_res.state == SCAN_PROCESS) { From 25442251cbda7590d87d8203a8dc1ddf2c93de61 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 12 Dec 2025 18:42:47 +0100 Subject: [PATCH 0380/2333] Linux 6.18.1 Link: https://lore.kernel.org/r/20251210072944.363788552@linuxfoundation.org Tested-by: Brett A C Sheffield Tested-by: Takeshi Ogasawara Tested-by: Jeffrin Jose T Tested-by: Salvatore Bonaccorso Tested-By: Achill Gilgenast = Tested-by: Peter Schneider Tested-by: Florian Fainelli Tested-by: Hardik Garg Tested-by: Dileep Malepu Tested-by: Ronald Warsow Tested-by: Ron Economos Tested-by: Linux Kernel Functional Testing Tested-by: Mark Brown Tested-by: Jon Hunter Signed-off-by: Greg Kroah-Hartman --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index a082a1d7c7d9b..23cc6c39819b1 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 VERSION = 6 PATCHLEVEL = 18 -SUBLEVEL = 0 +SUBLEVEL = 1 EXTRAVERSION = NAME = Baby Opossum Posse From 2ff36ad6e42502cb4c5c263d0e0b7d1bfd890f14 Mon Sep 17 00:00:00 2001 From: Gaurav Kohli Date: Mon, 15 Dec 2025 12:37:54 +0530 Subject: [PATCH 0381/2333] QCLINUX: defconfig: enable EMC2305 defconfig on qcom.config Enable SENSOR_EMC2305 defconfig to enable fan controller support. Signed-off-by: Gaurav Kohli --- arch/arm64/configs/qcom.config | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/configs/qcom.config b/arch/arm64/configs/qcom.config index d2fe51d328e50..5f0766325552b 100644 --- a/arch/arm64/configs/qcom.config +++ b/arch/arm64/configs/qcom.config @@ -47,6 +47,7 @@ CONFIG_STM_SOURCE_CONSOLE=m CONFIG_STM_SOURCE_FTRACE=m CONFIG_STM_SOURCE_HEARTBEAT=m CONFIG_SENSORS_AMC6821=y +CONFIG_SENSORS_EMC2305=y CONFIG_TRACE_MMIO_ACCESS=y CONFIG_UCLAMP_TASK_GROUP=y CONFIG_UCLAMP_TASK=y From cf036137162c1f227e8e488d3a60b99894853593 Mon Sep 17 00:00:00 2001 From: Konstantin Andreev Date: Mon, 16 Jun 2025 04:07:29 +0300 Subject: [PATCH 0382/2333] smack: fix bug: SMACK64TRANSMUTE set on non-directory [ Upstream commit 195da3ff244deff119c3f5244b464b2236ea1725 ] When a new file system object is created and the conditions for label transmutation are met, the SMACK64TRANSMUTE extended attribute is set on the object regardless of its type: file, pipe, socket, symlink, or directory. However, SMACK64TRANSMUTE may only be set on directories. This bug is a combined effect of the commits [1] and [2] which both transfer functionality from smack_d_instantiate() to smack_inode_init_security(), but only in part. Commit [1] set blank SMACK64TRANSMUTE on improper object types. Commit [2] set "TRUE" SMACK64TRANSMUTE on improper object types. [1] 2023-06-10, Fixes: baed456a6a2f ("smack: Set the SMACK64TRANSMUTE xattr in smack_inode_init_security()") Link: https://lore.kernel.org/linux-security-module/20230610075738.3273764-3-roberto.sassu@huaweicloud.com/ [2] 2023-11-16, Fixes: e63d86b8b764 ("smack: Initialize the in-memory inode in smack_inode_init_security()") Link: https://lore.kernel.org/linux-security-module/20231116090125.187209-5-roberto.sassu@huaweicloud.com/ Signed-off-by: Konstantin Andreev Signed-off-by: Casey Schaufler Signed-off-by: Sasha Levin --- security/smack/smack_lsm.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index af986587841d8..39a4caeb6bc8e 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -1015,18 +1015,20 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir, if (tsp->smk_task != tsp->smk_transmuted) isp = issp->smk_inode = dsp; - issp->smk_flags |= SMK_INODE_TRANSMUTE; - xattr_transmute = lsm_get_xattr_slot(xattrs, - xattr_count); - if (xattr_transmute) { - xattr_transmute->value = kmemdup(TRANS_TRUE, - TRANS_TRUE_SIZE, - GFP_NOFS); - if (!xattr_transmute->value) - return -ENOMEM; - - xattr_transmute->value_len = TRANS_TRUE_SIZE; - xattr_transmute->name = XATTR_SMACK_TRANSMUTE; + if (S_ISDIR(inode->i_mode)) { + issp->smk_flags |= SMK_INODE_TRANSMUTE; + xattr_transmute = lsm_get_xattr_slot(xattrs, + xattr_count); + if (xattr_transmute) { + xattr_transmute->value = kmemdup(TRANS_TRUE, + TRANS_TRUE_SIZE, + GFP_NOFS); + if (!xattr_transmute->value) + return -ENOMEM; + + xattr_transmute->value_len = TRANS_TRUE_SIZE; + xattr_transmute->name = XATTR_SMACK_TRANSMUTE; + } } } From 06025d5e707f760992946f17af403831d5a6347c Mon Sep 17 00:00:00 2001 From: Konstantin Andreev Date: Mon, 16 Jun 2025 04:07:28 +0300 Subject: [PATCH 0383/2333] smack: deduplicate "does access rule request transmutation" [ Upstream commit 635a01da8385fc00a144ec24684100bd1aa9db11 ] Signed-off-by: Konstantin Andreev Signed-off-by: Casey Schaufler Stable-dep-of: 78fc6a94be25 ("smack: fix bug: invalid label of unix socket file") Signed-off-by: Sasha Levin --- security/smack/smack_lsm.c | 57 +++++++++++++++++++++----------------- 1 file changed, 32 insertions(+), 25 deletions(-) diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 39a4caeb6bc8e..a005f5afb8e0d 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -962,6 +962,24 @@ static int smack_inode_alloc_security(struct inode *inode) return 0; } +/** + * smk_rule_transmutes - does access rule for (subject,object) contain 't'? + * @subject: a pointer to the subject's Smack label entry + * @object: a pointer to the object's Smack label entry + */ +static bool +smk_rule_transmutes(struct smack_known *subject, + const struct smack_known *object) +{ + int may; + + rcu_read_lock(); + may = smk_access_entry(subject->smk_known, object->smk_known, + &subject->smk_rules); + rcu_read_unlock(); + return (may > 0) && (may & MAY_TRANSMUTE); +} + /** * smack_inode_init_security - copy out the smack from an inode * @inode: the newly created inode @@ -977,23 +995,19 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir, struct xattr *xattrs, int *xattr_count) { struct task_smack *tsp = smack_cred(current_cred()); - struct inode_smack *issp = smack_inode(inode); - struct smack_known *skp = smk_of_task(tsp); - struct smack_known *isp = smk_of_inode(inode); + struct inode_smack * const issp = smack_inode(inode); struct smack_known *dsp = smk_of_inode(dir); struct xattr *xattr = lsm_get_xattr_slot(xattrs, xattr_count); - int may; + bool trans_cred; + bool trans_rule; /* * If equal, transmuting already occurred in * smack_dentry_create_files_as(). No need to check again. */ - if (tsp->smk_task != tsp->smk_transmuted) { - rcu_read_lock(); - may = smk_access_entry(skp->smk_known, dsp->smk_known, - &skp->smk_rules); - rcu_read_unlock(); - } + trans_cred = (tsp->smk_task == tsp->smk_transmuted); + if (!trans_cred) + trans_rule = smk_rule_transmutes(smk_of_task(tsp), dsp); /* * In addition to having smk_task equal to smk_transmuted, @@ -1001,9 +1015,7 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir, * requests transmutation then by all means transmute. * Mark the inode as changed. */ - if ((tsp->smk_task == tsp->smk_transmuted) || - (may > 0 && ((may & MAY_TRANSMUTE) != 0) && - smk_inode_transmutable(dir))) { + if (trans_cred || (trans_rule && smk_inode_transmutable(dir))) { struct xattr *xattr_transmute; /* @@ -1012,8 +1024,8 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir, * inode label was already set correctly in * smack_inode_alloc_security(). */ - if (tsp->smk_task != tsp->smk_transmuted) - isp = issp->smk_inode = dsp; + if (!trans_cred) + issp->smk_inode = dsp; if (S_ISDIR(inode->i_mode)) { issp->smk_flags |= SMK_INODE_TRANSMUTE; @@ -1035,11 +1047,13 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir, issp->smk_flags |= SMK_INODE_INSTANT; if (xattr) { - xattr->value = kstrdup(isp->smk_known, GFP_NOFS); + const char *inode_label = issp->smk_inode->smk_known; + + xattr->value = kstrdup(inode_label, GFP_NOFS); if (!xattr->value) return -ENOMEM; - xattr->value_len = strlen(isp->smk_known); + xattr->value_len = strlen(inode_label); xattr->name = XATTR_SMACK_SUFFIX; } @@ -4917,7 +4931,6 @@ static int smack_dentry_create_files_as(struct dentry *dentry, int mode, struct task_smack *otsp = smack_cred(old); struct task_smack *ntsp = smack_cred(new); struct inode_smack *isp; - int may; /* * Use the process credential unless all of @@ -4931,18 +4944,12 @@ static int smack_dentry_create_files_as(struct dentry *dentry, int mode, isp = smack_inode(d_inode(dentry->d_parent)); if (isp->smk_flags & SMK_INODE_TRANSMUTE) { - rcu_read_lock(); - may = smk_access_entry(otsp->smk_task->smk_known, - isp->smk_inode->smk_known, - &otsp->smk_task->smk_rules); - rcu_read_unlock(); - /* * If the directory is transmuting and the rule * providing access is transmuting use the containing * directory label instead of the process label. */ - if (may > 0 && (may & MAY_TRANSMUTE)) { + if (smk_rule_transmutes(otsp->smk_task, isp->smk_inode)) { ntsp->smk_task = isp->smk_inode; ntsp->smk_transmuted = ntsp->smk_task; } From 3c4f1ca5bd912d08d33415bf537f99adeb1a9708 Mon Sep 17 00:00:00 2001 From: Konstantin Andreev Date: Mon, 16 Jun 2025 04:07:30 +0300 Subject: [PATCH 0384/2333] smack: deduplicate xattr setting in smack_inode_init_security() [ Upstream commit 8e5d9f916a9678e2dcbed2289b87efd453e4e052 ] Signed-off-by: Konstantin Andreev Signed-off-by: Casey Schaufler Stable-dep-of: 78fc6a94be25 ("smack: fix bug: invalid label of unix socket file") Signed-off-by: Sasha Levin --- security/smack/smack_lsm.c | 56 ++++++++++++++++++++------------------ 1 file changed, 29 insertions(+), 27 deletions(-) diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index a005f5afb8e0d..9eefb5cfccba5 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -980,6 +980,24 @@ smk_rule_transmutes(struct smack_known *subject, return (may > 0) && (may & MAY_TRANSMUTE); } +static int +xattr_dupval(struct xattr *xattrs, int *xattr_count, + const char *name, const void *value, unsigned int vallen) +{ + struct xattr * const xattr = lsm_get_xattr_slot(xattrs, xattr_count); + + if (!xattr) + return 0; + + xattr->value = kmemdup(value, vallen, GFP_NOFS); + if (!xattr->value) + return -ENOMEM; + + xattr->value_len = vallen; + xattr->name = name; + return 0; +} + /** * smack_inode_init_security - copy out the smack from an inode * @inode: the newly created inode @@ -997,7 +1015,6 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir, struct task_smack *tsp = smack_cred(current_cred()); struct inode_smack * const issp = smack_inode(inode); struct smack_known *dsp = smk_of_inode(dir); - struct xattr *xattr = lsm_get_xattr_slot(xattrs, xattr_count); bool trans_cred; bool trans_rule; @@ -1016,8 +1033,6 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir, * Mark the inode as changed. */ if (trans_cred || (trans_rule && smk_inode_transmutable(dir))) { - struct xattr *xattr_transmute; - /* * The caller of smack_dentry_create_files_as() * should have overridden the current cred, so the @@ -1029,35 +1044,22 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir, if (S_ISDIR(inode->i_mode)) { issp->smk_flags |= SMK_INODE_TRANSMUTE; - xattr_transmute = lsm_get_xattr_slot(xattrs, - xattr_count); - if (xattr_transmute) { - xattr_transmute->value = kmemdup(TRANS_TRUE, - TRANS_TRUE_SIZE, - GFP_NOFS); - if (!xattr_transmute->value) - return -ENOMEM; - - xattr_transmute->value_len = TRANS_TRUE_SIZE; - xattr_transmute->name = XATTR_SMACK_TRANSMUTE; - } + + if (xattr_dupval(xattrs, xattr_count, + XATTR_SMACK_TRANSMUTE, + TRANS_TRUE, + TRANS_TRUE_SIZE + )) + return -ENOMEM; } } issp->smk_flags |= SMK_INODE_INSTANT; - if (xattr) { - const char *inode_label = issp->smk_inode->smk_known; - - xattr->value = kstrdup(inode_label, GFP_NOFS); - if (!xattr->value) - return -ENOMEM; - - xattr->value_len = strlen(inode_label); - xattr->name = XATTR_SMACK_SUFFIX; - } - - return 0; + return xattr_dupval(xattrs, xattr_count, + XATTR_SMACK_SUFFIX, + issp->smk_inode->smk_known, + strlen(issp->smk_inode->smk_known)); } /** From f1dbb370eca563582f90744618e6eaa95335fde6 Mon Sep 17 00:00:00 2001 From: Konstantin Andreev Date: Mon, 16 Jun 2025 04:07:31 +0300 Subject: [PATCH 0385/2333] smack: always "instantiate" inode in smack_inode_init_security() [ Upstream commit 69204f6cdb90f56b7ca27966d1080841108fc5de ] If memory allocation for the SMACK64TRANSMUTE xattr value fails in smack_inode_init_security(), the SMK_INODE_INSTANT flag is not set in (struct inode_smack *issp)->smk_flags, leaving the inode as not "instantiated". It does not matter if fs frees the inode after failed smack_inode_init_security() call, but there is no guarantee for this. To be safe, mark the inode as "instantiated", even if allocation of xattr values fails. Signed-off-by: Konstantin Andreev Signed-off-by: Casey Schaufler Stable-dep-of: 78fc6a94be25 ("smack: fix bug: invalid label of unix socket file") Signed-off-by: Sasha Levin --- security/smack/smack_lsm.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 9eefb5cfccba5..db2a9aa9f1a05 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -1015,6 +1015,8 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir, struct task_smack *tsp = smack_cred(current_cred()); struct inode_smack * const issp = smack_inode(inode); struct smack_known *dsp = smk_of_inode(dir); + int rc = 0; + int transflag = 0; bool trans_cred; bool trans_rule; @@ -1043,18 +1045,20 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir, issp->smk_inode = dsp; if (S_ISDIR(inode->i_mode)) { - issp->smk_flags |= SMK_INODE_TRANSMUTE; + transflag = SMK_INODE_TRANSMUTE; if (xattr_dupval(xattrs, xattr_count, XATTR_SMACK_TRANSMUTE, TRANS_TRUE, TRANS_TRUE_SIZE )) - return -ENOMEM; + rc = -ENOMEM; } } - issp->smk_flags |= SMK_INODE_INSTANT; + issp->smk_flags |= (SMK_INODE_INSTANT | transflag); + if (rc) + return rc; return xattr_dupval(xattrs, xattr_count, XATTR_SMACK_SUFFIX, From 70c5be42f691fb6b46084bdf42e191cab0e9dde7 Mon Sep 17 00:00:00 2001 From: Konstantin Andreev Date: Mon, 16 Jun 2025 04:07:32 +0300 Subject: [PATCH 0386/2333] smack: fix bug: invalid label of unix socket file [ Upstream commit 78fc6a94be252b27bb73e4926eed70b5e302a8e0 ] According to [1], the label of a UNIX domain socket (UDS) file (i.e., the filesystem object representing the socket) is not supposed to participate in Smack security. To achieve this, [1] labels UDS files with "*" in smack_d_instantiate(). Before [2], smack_d_instantiate() was responsible for initializing Smack security for all inodes, except ones under /proc [2] imposed the sole responsibility for initializing inode security for newly created filesystem objects on smack_inode_init_security(). However, smack_inode_init_security() lacks some logic present in smack_d_instantiate(). In particular, it does not label UDS files with "*". This patch adds the missing labeling of UDS files with "*" to smack_inode_init_security(). Labeling UDS files with "*" in smack_d_instantiate() still works for stale UDS files that already exist on disk. Stale UDS files are useless, but I keep labeling them for consistency and maybe to make easier for user to delete them. Compared to [1], this version introduces the following improvements: * UDS file label is held inside inode only and not saved to xattrs. * relabeling UDS files (setxattr, removexattr, etc.) is blocked. [1] 2010-11-24 Casey Schaufler commit b4e0d5f0791b ("Smack: UDS revision") [2] 2023-11-16 roberto.sassu Fixes: e63d86b8b764 ("smack: Initialize the in-memory inode in smack_inode_init_security()") Link: https://lore.kernel.org/linux-security-module/20231116090125.187209-5-roberto.sassu@huaweicloud.com/ Signed-off-by: Konstantin Andreev Signed-off-by: Casey Schaufler Signed-off-by: Sasha Levin --- Documentation/admin-guide/LSM/Smack.rst | 5 +++ security/smack/smack_lsm.c | 58 +++++++++++++++++++------ 2 files changed, 49 insertions(+), 14 deletions(-) diff --git a/Documentation/admin-guide/LSM/Smack.rst b/Documentation/admin-guide/LSM/Smack.rst index 6d44f4fdbf59f..1b554b5bf98e6 100644 --- a/Documentation/admin-guide/LSM/Smack.rst +++ b/Documentation/admin-guide/LSM/Smack.rst @@ -696,6 +696,11 @@ sockets. A privileged program may set this to match the label of another task with which it hopes to communicate. +UNIX domain socket (UDS) with a BSD address functions both as a file in a +filesystem and as a socket. As a file, it carries the SMACK64 attribute. This +attribute is not involved in Smack security enforcement and is immutably +assigned the label "*". + Smack Netlabel Exceptions ~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index db2a9aa9f1a05..d16453801a79e 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -1020,6 +1020,16 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir, bool trans_cred; bool trans_rule; + /* + * UNIX domain sockets use lower level socket data. Let + * UDS inode have fixed * label to keep smack_inode_permission() calm + * when called from unix_find_bsd() + */ + if (S_ISSOCK(inode->i_mode)) { + /* forced label, no need to save to xattrs */ + issp->smk_inode = &smack_known_star; + goto instant_inode; + } /* * If equal, transmuting already occurred in * smack_dentry_create_files_as(). No need to check again. @@ -1056,14 +1066,16 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir, } } - issp->smk_flags |= (SMK_INODE_INSTANT | transflag); - if (rc) - return rc; - - return xattr_dupval(xattrs, xattr_count, + if (rc == 0) + if (xattr_dupval(xattrs, xattr_count, XATTR_SMACK_SUFFIX, issp->smk_inode->smk_known, - strlen(issp->smk_inode->smk_known)); + strlen(issp->smk_inode->smk_known) + )) + rc = -ENOMEM; +instant_inode: + issp->smk_flags |= (SMK_INODE_INSTANT | transflag); + return rc; } /** @@ -1337,13 +1349,23 @@ static int smack_inode_setxattr(struct mnt_idmap *idmap, int check_import = 0; int check_star = 0; int rc = 0; + umode_t const i_mode = d_backing_inode(dentry)->i_mode; /* * Check label validity here so import won't fail in post_setxattr */ - if (strcmp(name, XATTR_NAME_SMACK) == 0 || - strcmp(name, XATTR_NAME_SMACKIPIN) == 0 || - strcmp(name, XATTR_NAME_SMACKIPOUT) == 0) { + if (strcmp(name, XATTR_NAME_SMACK) == 0) { + /* + * UDS inode has fixed label + */ + if (S_ISSOCK(i_mode)) { + rc = -EINVAL; + } else { + check_priv = 1; + check_import = 1; + } + } else if (strcmp(name, XATTR_NAME_SMACKIPIN) == 0 || + strcmp(name, XATTR_NAME_SMACKIPOUT) == 0) { check_priv = 1; check_import = 1; } else if (strcmp(name, XATTR_NAME_SMACKEXEC) == 0 || @@ -1353,7 +1375,7 @@ static int smack_inode_setxattr(struct mnt_idmap *idmap, check_star = 1; } else if (strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0) { check_priv = 1; - if (!S_ISDIR(d_backing_inode(dentry)->i_mode) || + if (!S_ISDIR(i_mode) || size != TRANS_TRUE_SIZE || strncmp(value, TRANS_TRUE, TRANS_TRUE_SIZE) != 0) rc = -EINVAL; @@ -1484,12 +1506,15 @@ static int smack_inode_removexattr(struct mnt_idmap *idmap, * Don't do anything special for these. * XATTR_NAME_SMACKIPIN * XATTR_NAME_SMACKIPOUT + * XATTR_NAME_SMACK if S_ISSOCK (UDS inode has fixed label) */ if (strcmp(name, XATTR_NAME_SMACK) == 0) { - struct super_block *sbp = dentry->d_sb; - struct superblock_smack *sbsp = smack_superblock(sbp); + if (!S_ISSOCK(d_backing_inode(dentry)->i_mode)) { + struct super_block *sbp = dentry->d_sb; + struct superblock_smack *sbsp = smack_superblock(sbp); - isp->smk_inode = sbsp->smk_default; + isp->smk_inode = sbsp->smk_default; + } } else if (strcmp(name, XATTR_NAME_SMACKEXEC) == 0) isp->smk_task = NULL; else if (strcmp(name, XATTR_NAME_SMACKMMAP) == 0) @@ -3607,7 +3632,7 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode) */ /* - * UNIX domain sockets use lower level socket data. + * UDS inode has fixed label (*) */ if (S_ISSOCK(inode->i_mode)) { final = &smack_known_star; @@ -4872,6 +4897,11 @@ static int smack_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid) static int smack_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen) { + /* + * UDS inode has fixed label. Ignore nfs label. + */ + if (S_ISSOCK(inode->i_mode)) + return 0; return smack_inode_setsecurity(inode, XATTR_SMACK_SUFFIX, ctx, ctxlen, 0); } From 60e8d49989410a7ade60f5dadfcd979c117d05c0 Mon Sep 17 00:00:00 2001 From: Konstantin Andreev Date: Tue, 17 Jun 2025 00:32:16 +0300 Subject: [PATCH 0387/2333] smack: fix bug: unprivileged task can create labels [ Upstream commit c147e13ea7fe9f118f8c9ba5e96cbd644b00d6b3 ] If an unprivileged task is allowed to relabel itself (/smack/relabel-self is not empty), it can freely create new labels by writing their names into own /proc/PID/attr/smack/current This occurs because do_setattr() imports the provided label in advance, before checking "relabel-self" list. This change ensures that the "relabel-self" list is checked before importing the label. Fixes: 38416e53936e ("Smack: limited capability for changing process label") Signed-off-by: Konstantin Andreev Signed-off-by: Casey Schaufler Signed-off-by: Sasha Levin --- security/smack/smack_lsm.c | 41 +++++++++++++++++++++++++------------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index d16453801a79e..07dbc4cd303a7 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -3778,8 +3778,8 @@ static int do_setattr(u64 attr, void *value, size_t size) struct task_smack *tsp = smack_cred(current_cred()); struct cred *new; struct smack_known *skp; - struct smack_known_list_elem *sklep; - int rc; + char *labelstr; + int rc = 0; if (!smack_privileged(CAP_MAC_ADMIN) && list_empty(&tsp->smk_relabel)) return -EPERM; @@ -3790,28 +3790,41 @@ static int do_setattr(u64 attr, void *value, size_t size) if (attr != LSM_ATTR_CURRENT) return -EOPNOTSUPP; - skp = smk_import_entry(value, size); - if (IS_ERR(skp)) - return PTR_ERR(skp); + labelstr = smk_parse_smack(value, size); + if (IS_ERR(labelstr)) + return PTR_ERR(labelstr); /* * No process is ever allowed the web ("@") label * and the star ("*") label. */ - if (skp == &smack_known_web || skp == &smack_known_star) - return -EINVAL; + if (labelstr[1] == '\0' /* '@', '*' */) { + const char c = labelstr[0]; + + if (c == *smack_known_web.smk_known || + c == *smack_known_star.smk_known) { + rc = -EPERM; + goto free_labelstr; + } + } if (!smack_privileged(CAP_MAC_ADMIN)) { - rc = -EPERM; + const struct smack_known_list_elem *sklep; list_for_each_entry(sklep, &tsp->smk_relabel, list) - if (sklep->smk_label == skp) { - rc = 0; - break; - } - if (rc) - return rc; + if (strcmp(sklep->smk_label->smk_known, labelstr) == 0) + goto free_labelstr; + rc = -EPERM; } +free_labelstr: + kfree(labelstr); + if (rc) + return -EPERM; + + skp = smk_import_entry(value, size); + if (IS_ERR(skp)) + return PTR_ERR(skp); + new = prepare_creds(); if (new == NULL) return -ENOMEM; From cf008f5bd3d5db210d1edd244e7cd1d879cb1a5e Mon Sep 17 00:00:00 2001 From: Konstantin Andreev Date: Tue, 17 Jun 2025 00:32:17 +0300 Subject: [PATCH 0388/2333] smack: fix bug: setting task label silently ignores input garbage [ Upstream commit 674e2b24791cbe8fd5dc8a0aed4cb4404fcd2028 ] This command: # echo foo/bar >/proc/$$/attr/smack/current gives the task a label 'foo' w/o indication that label does not match input. Setting the label with lsm_set_self_attr() syscall behaves identically. This occures because: 1) smk_parse_smack() is used to convert input to a label 2) smk_parse_smack() takes only that part from the beginning of the input that looks like a label. 3) `/' is prohibited in labels, so only "foo" is taken. (2) is by design, because smk_parse_smack() is used for parsing strings which are more than just a label. Silent failure is not a good thing, and there are two indicators that this was not done intentionally: (size >= SMK_LONGLABEL) ~> invalid clause at the beginning of the do_setattr() and the "Returns the length of the smack label" claim in the do_setattr() description. So I fixed this by adding one tiny check: the taken label length == input length. Since input length is now strictly controlled, I changed the two ways of setting label smack_setselfattr(): lsm_set_self_attr() syscall smack_setprocattr(): > /proc/.../current to accommodate the divergence in what they understand by "input length": smack_setselfattr counts mandatory \0 into input length, smack_setprocattr does not. smack_setprocattr allows various trailers after label Related changes: * fixed description for smk_parse_smack * allow unprivileged tasks validate label syntax. * extract smk_parse_label_len() from smk_parse_smack() so parsing may be done w/o string allocation. * extract smk_import_valid_label() from smk_import_entry() to avoid repeated parsing. * smk_parse_smack(): scan null-terminated strings for no more than SMK_LONGLABEL(256) characters * smack_setselfattr(): require struct lsm_ctx . flags == 0 to reserve them for future. Fixes: e114e473771c ("Smack: Simplified Mandatory Access Control Kernel") Signed-off-by: Konstantin Andreev Signed-off-by: Casey Schaufler Signed-off-by: Sasha Levin --- Documentation/admin-guide/LSM/Smack.rst | 11 ++- security/smack/smack.h | 3 + security/smack/smack_access.c | 93 ++++++++++++++----- security/smack/smack_lsm.c | 115 +++++++++++++++--------- 4 files changed, 156 insertions(+), 66 deletions(-) diff --git a/Documentation/admin-guide/LSM/Smack.rst b/Documentation/admin-guide/LSM/Smack.rst index 1b554b5bf98e6..c5ed775f2d107 100644 --- a/Documentation/admin-guide/LSM/Smack.rst +++ b/Documentation/admin-guide/LSM/Smack.rst @@ -601,10 +601,15 @@ specification. Task Attribute ~~~~~~~~~~~~~~ -The Smack label of a process can be read from /proc//attr/current. A -process can read its own Smack label from /proc/self/attr/current. A +The Smack label of a process can be read from ``/proc//attr/current``. A +process can read its own Smack label from ``/proc/self/attr/current``. A privileged process can change its own Smack label by writing to -/proc/self/attr/current but not the label of another process. +``/proc/self/attr/current`` but not the label of another process. + +Format of writing is : only the label or the label followed by one of the +3 trailers: ``\n`` (by common agreement for ``/proc/...`` interfaces), +``\0`` (because some applications incorrectly include it), +``\n\0`` (because we think some applications may incorrectly include it). File Attribute ~~~~~~~~~~~~~~ diff --git a/security/smack/smack.h b/security/smack/smack.h index bf6a6ed3946ce..759343a6bbaeb 100644 --- a/security/smack/smack.h +++ b/security/smack/smack.h @@ -286,9 +286,12 @@ int smk_tskacc(struct task_smack *, struct smack_known *, int smk_curacc(struct smack_known *, u32, struct smk_audit_info *); int smack_str_from_perm(char *string, int access); struct smack_known *smack_from_secid(const u32); +int smk_parse_label_len(const char *string, int len); char *smk_parse_smack(const char *string, int len); int smk_netlbl_mls(int, char *, struct netlbl_lsm_secattr *, int); struct smack_known *smk_import_entry(const char *, int); +struct smack_known *smk_import_valid_label(const char *label, int label_len, + gfp_t gfp); void smk_insert_entry(struct smack_known *skp); struct smack_known *smk_find_entry(const char *); bool smack_privileged(int cap); diff --git a/security/smack/smack_access.c b/security/smack/smack_access.c index 2e4a0cb22782b..a289cb6672bd4 100644 --- a/security/smack/smack_access.c +++ b/security/smack/smack_access.c @@ -443,19 +443,19 @@ struct smack_known *smk_find_entry(const char *string) } /** - * smk_parse_smack - parse smack label from a text string - * @string: a text string that might contain a Smack label - * @len: the maximum size, or zero if it is NULL terminated. + * smk_parse_label_len - calculate the length of the starting segment + * in the string that constitutes a valid smack label + * @string: a text string that might contain a Smack label at the beginning + * @len: the maximum size to look into, may be zero if string is null-terminated * - * Returns a pointer to the clean label or an error code. + * Returns the length of the segment (0 < L < SMK_LONGLABEL) or an error code. */ -char *smk_parse_smack(const char *string, int len) +int smk_parse_label_len(const char *string, int len) { - char *smack; int i; - if (len <= 0) - len = strlen(string) + 1; + if (len <= 0 || len > SMK_LONGLABEL) + len = SMK_LONGLABEL; /* * Reserve a leading '-' as an indicator that @@ -463,7 +463,7 @@ char *smk_parse_smack(const char *string, int len) * including /smack/cipso and /smack/cipso2 */ if (string[0] == '-') - return ERR_PTR(-EINVAL); + return -EINVAL; for (i = 0; i < len; i++) if (string[i] > '~' || string[i] <= ' ' || string[i] == '/' || @@ -471,6 +471,25 @@ char *smk_parse_smack(const char *string, int len) break; if (i == 0 || i >= SMK_LONGLABEL) + return -EINVAL; + + return i; +} + +/** + * smk_parse_smack - copy the starting segment in the string + * that constitutes a valid smack label + * @string: a text string that might contain a Smack label at the beginning + * @len: the maximum size to look into, may be zero if string is null-terminated + * + * Returns a pointer to the copy of the label or an error code. + */ +char *smk_parse_smack(const char *string, int len) +{ + char *smack; + int i = smk_parse_label_len(string, len); + + if (i < 0) return ERR_PTR(-EINVAL); smack = kstrndup(string, i, GFP_NOFS); @@ -554,31 +573,25 @@ int smack_populate_secattr(struct smack_known *skp) } /** - * smk_import_entry - import a label, return the list entry - * @string: a text string that might be a Smack label - * @len: the maximum size, or zero if it is NULL terminated. + * smk_import_valid_allocated_label - import a label, return the list entry + * @smack: a text string that is a valid Smack label and may be kfree()ed. + * It is consumed: either becomes a part of the entry or kfree'ed. * - * Returns a pointer to the entry in the label list that - * matches the passed string, adding it if necessary, - * or an error code. + * Returns: see description of smk_import_entry() */ -struct smack_known *smk_import_entry(const char *string, int len) +static struct smack_known * +smk_import_allocated_label(char *smack, gfp_t gfp) { struct smack_known *skp; - char *smack; int rc; - smack = smk_parse_smack(string, len); - if (IS_ERR(smack)) - return ERR_CAST(smack); - mutex_lock(&smack_known_lock); skp = smk_find_entry(smack); if (skp != NULL) goto freeout; - skp = kzalloc(sizeof(*skp), GFP_NOFS); + skp = kzalloc(sizeof(*skp), gfp); if (skp == NULL) { skp = ERR_PTR(-ENOMEM); goto freeout; @@ -608,6 +621,42 @@ struct smack_known *smk_import_entry(const char *string, int len) return skp; } +/** + * smk_import_entry - import a label, return the list entry + * @string: a text string that might contain a Smack label at the beginning + * @len: the maximum size to look into, may be zero if string is null-terminated + * + * Returns a pointer to the entry in the label list that + * matches the passed string, adding it if necessary, + * or an error code. + */ +struct smack_known *smk_import_entry(const char *string, int len) +{ + char *smack = smk_parse_smack(string, len); + + if (IS_ERR(smack)) + return ERR_CAST(smack); + + return smk_import_allocated_label(smack, GFP_NOFS); +} + +/** + * smk_import_valid_label - import a label, return the list entry + * @label a text string that is a valid Smack label, not null-terminated + * + * Returns: see description of smk_import_entry() + */ +struct smack_known * +smk_import_valid_label(const char *label, int label_len, gfp_t gfp) +{ + char *smack = kstrndup(label, label_len, gfp); + + if (!smack) + return ERR_PTR(-ENOMEM); + + return smk_import_allocated_label(smack, gfp); +} + /** * smack_from_secid - find the Smack label associated with a secid * @secid: an integer that might be associated with a Smack label diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 07dbc4cd303a7..7fd8a60b8be90 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -3710,7 +3710,7 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode) * @attr: which attribute to fetch * @ctx: buffer to receive the result * @size: available size in, actual size out - * @flags: unused + * @flags: reserved, currently zero * * Fill the passed user space @ctx with the details of the requested * attribute. @@ -3771,57 +3771,52 @@ static int smack_getprocattr(struct task_struct *p, const char *name, char **val * Sets the Smack value of the task. Only setting self * is permitted and only with privilege * - * Returns the length of the smack label or an error code + * Returns zero on success or an error code */ -static int do_setattr(u64 attr, void *value, size_t size) +static int do_setattr(unsigned int attr, void *value, size_t size) { struct task_smack *tsp = smack_cred(current_cred()); struct cred *new; struct smack_known *skp; - char *labelstr; - int rc = 0; - - if (!smack_privileged(CAP_MAC_ADMIN) && list_empty(&tsp->smk_relabel)) - return -EPERM; + int label_len; + /* + * let unprivileged user validate input, check permissions later + */ if (value == NULL || size == 0 || size >= SMK_LONGLABEL) return -EINVAL; - if (attr != LSM_ATTR_CURRENT) - return -EOPNOTSUPP; - - labelstr = smk_parse_smack(value, size); - if (IS_ERR(labelstr)) - return PTR_ERR(labelstr); + label_len = smk_parse_label_len(value, size); + if (label_len < 0 || label_len != size) + return -EINVAL; /* * No process is ever allowed the web ("@") label * and the star ("*") label. */ - if (labelstr[1] == '\0' /* '@', '*' */) { - const char c = labelstr[0]; + if (label_len == 1 /* '@', '*' */) { + const char c = *(const char *)value; if (c == *smack_known_web.smk_known || - c == *smack_known_star.smk_known) { - rc = -EPERM; - goto free_labelstr; - } + c == *smack_known_star.smk_known) + return -EPERM; } if (!smack_privileged(CAP_MAC_ADMIN)) { const struct smack_known_list_elem *sklep; - list_for_each_entry(sklep, &tsp->smk_relabel, list) - if (strcmp(sklep->smk_label->smk_known, labelstr) == 0) - goto free_labelstr; - rc = -EPERM; - } + list_for_each_entry(sklep, &tsp->smk_relabel, list) { + const char *cp = sklep->smk_label->smk_known; -free_labelstr: - kfree(labelstr); - if (rc) + if (strlen(cp) == label_len && + strncmp(cp, value, label_len) == 0) + goto in_relabel; + } return -EPERM; +in_relabel: + ; + } - skp = smk_import_entry(value, size); + skp = smk_import_valid_label(value, label_len, GFP_KERNEL); if (IS_ERR(skp)) return PTR_ERR(skp); @@ -3837,7 +3832,7 @@ static int do_setattr(u64 attr, void *value, size_t size) smk_destroy_label_list(&tsp->smk_relabel); commit_creds(new); - return size; + return 0; } /** @@ -3845,7 +3840,7 @@ static int do_setattr(u64 attr, void *value, size_t size) * @attr: which attribute to set * @ctx: buffer containing the data * @size: size of @ctx - * @flags: unused + * @flags: reserved, must be zero * * Fill the passed user space @ctx with the details of the requested * attribute. @@ -3855,12 +3850,26 @@ static int do_setattr(u64 attr, void *value, size_t size) static int smack_setselfattr(unsigned int attr, struct lsm_ctx *ctx, u32 size, u32 flags) { - int rc; + if (attr != LSM_ATTR_CURRENT) + return -EOPNOTSUPP; - rc = do_setattr(attr, ctx->ctx, ctx->ctx_len); - if (rc > 0) - return 0; - return rc; + if (ctx->flags) + return -EINVAL; + /* + * string must have \0 terminator, included in ctx->ctx + * (see description of struct lsm_ctx) + */ + if (ctx->ctx_len == 0) + return -EINVAL; + + if (ctx->ctx[ctx->ctx_len - 1] != '\0') + return -EINVAL; + /* + * other do_setattr() caller, smack_setprocattr(), + * does not count \0 into size, so + * decreasing length by 1 to accommodate the divergence. + */ + return do_setattr(attr, ctx->ctx, ctx->ctx_len - 1); } /** @@ -3872,15 +3881,39 @@ static int smack_setselfattr(unsigned int attr, struct lsm_ctx *ctx, * Sets the Smack value of the task. Only setting self * is permitted and only with privilege * - * Returns the length of the smack label or an error code + * Returns the size of the input value or an error code */ static int smack_setprocattr(const char *name, void *value, size_t size) { - int attr = lsm_name_to_attr(name); + size_t realsize = size; + unsigned int attr = lsm_name_to_attr(name); - if (attr != LSM_ATTR_UNDEF) - return do_setattr(attr, value, size); - return -EINVAL; + switch (attr) { + case LSM_ATTR_UNDEF: return -EINVAL; + default: return -EOPNOTSUPP; + case LSM_ATTR_CURRENT: + ; + } + + /* + * The value for the "current" attribute is the label + * followed by one of the 4 trailers: none, \0, \n, \n\0 + * + * I.e. following inputs are accepted as 3-characters long label "foo": + * + * "foo" (3 characters) + * "foo\0" (4 characters) + * "foo\n" (4 characters) + * "foo\n\0" (5 characters) + */ + + if (realsize && (((const char *)value)[realsize - 1] == '\0')) + --realsize; + + if (realsize && (((const char *)value)[realsize - 1] == '\n')) + --realsize; + + return do_setattr(attr, value, realsize) ? : size; } /** From 79197c6007f2afbfd7bcf5b9b80ccabf8483d774 Mon Sep 17 00:00:00 2001 From: Mainak Sen Date: Mon, 7 Jul 2025 18:17:39 +0900 Subject: [PATCH 0389/2333] gpu: host1x: Fix race in syncpt alloc/free [ Upstream commit c7d393267c497502fa737607f435f05dfe6e3d9b ] Fix race condition between host1x_syncpt_alloc() and host1x_syncpt_put() by using kref_put_mutex() instead of kref_put() + manual mutex locking. This ensures no thread can acquire the syncpt_mutex after the refcount drops to zero but before syncpt_release acquires it. This prevents races where syncpoints could be allocated while still being cleaned up from a previous release. Remove explicit mutex locking in syncpt_release as kref_put_mutex() handles this atomically. Signed-off-by: Mainak Sen Fixes: f5ba33fb9690 ("gpu: host1x: Reserve VBLANK syncpoints at initialization") Signed-off-by: Mikko Perttunen Signed-off-by: Thierry Reding Link: https://lore.kernel.org/r/20250707-host1x-syncpt-race-fix-v1-1-28b0776e70bc@nvidia.com Signed-off-by: Sasha Levin --- drivers/gpu/host1x/syncpt.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/gpu/host1x/syncpt.c b/drivers/gpu/host1x/syncpt.c index f63d14a57a1d9..acc7d82e0585e 100644 --- a/drivers/gpu/host1x/syncpt.c +++ b/drivers/gpu/host1x/syncpt.c @@ -345,8 +345,6 @@ static void syncpt_release(struct kref *ref) sp->locked = false; - mutex_lock(&sp->host->syncpt_mutex); - host1x_syncpt_base_free(sp->base); kfree(sp->name); sp->base = NULL; @@ -369,7 +367,7 @@ void host1x_syncpt_put(struct host1x_syncpt *sp) if (!sp) return; - kref_put(&sp->ref, syncpt_release); + kref_put_mutex(&sp->ref, syncpt_release, &sp->host->syncpt_mutex); } EXPORT_SYMBOL(host1x_syncpt_put); From 359653edd5374fbba28f93043554dcc494aee85f Mon Sep 17 00:00:00 2001 From: Lizhi Hou Date: Tue, 9 Sep 2025 08:45:31 -0700 Subject: [PATCH 0390/2333] accel/amdxdna: Fix an integer overflow in aie2_query_ctx_status_array() [ Upstream commit 9e16c8bf9aebf629344cfd4cd5e3dc7d8c3f7d82 ] The unpublished smatch static checker reported a warning. drivers/accel/amdxdna/aie2_pci.c:904 aie2_query_ctx_status_array() warn: potential user controlled sizeof overflow 'args->num_element * args->element_size' '1-u32max(user) * 1-u32max(user)' Even this will not cause a real issue, it is better to put a reasonable limitation for element_size and num_element. Add condition to make sure the input element_size <= 4K and num_element <= 1K. Reported-by: Dan Carpenter Closes: https://lore.kernel.org/dri-devel/aL56ZCLyl3tLQM1e@stanley.mountain/ Fixes: 2f509fe6a42c ("accel/amdxdna: Add ioctl DRM_IOCTL_AMDXDNA_GET_ARRAY") Reviewed-by: Maciej Falkowski Signed-off-by: Lizhi Hou Link: https://lore.kernel.org/r/20250909154531.3469979-1-lizhi.hou@amd.com Signed-off-by: Sasha Levin --- drivers/accel/amdxdna/aie2_pci.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/accel/amdxdna/aie2_pci.c b/drivers/accel/amdxdna/aie2_pci.c index 87c425e3d2b99..6e39c769bb6d8 100644 --- a/drivers/accel/amdxdna/aie2_pci.c +++ b/drivers/accel/amdxdna/aie2_pci.c @@ -898,6 +898,12 @@ static int aie2_query_ctx_status_array(struct amdxdna_client *client, drm_WARN_ON(&xdna->ddev, !mutex_is_locked(&xdna->dev_lock)); + if (args->element_size > SZ_4K || args->num_element > SZ_1K) { + XDNA_DBG(xdna, "Invalid element size %d or number of element %d", + args->element_size, args->num_element); + return -EINVAL; + } + array_args.element_size = min(args->element_size, sizeof(struct amdxdna_drm_hwctx_entry)); array_args.buffer = args->buffer; From 3bb9d125972c748a07eb65bd4e9396b06fd73e2b Mon Sep 17 00:00:00 2001 From: Lizhi Hou Date: Tue, 16 Sep 2025 10:48:42 -0700 Subject: [PATCH 0391/2333] accel/amdxdna: Call dma_buf_vmap_unlocked() for imported object [ Upstream commit 457f4393d02fdb612a93912fb09cef70e6e545c9 ] In amdxdna_gem_obj_vmap(), calling dma_buf_vmap() triggers a kernel warning if LOCKDEP is enabled. So for imported object, use dma_buf_vmap_unlocked(). Then, use drm_gem_vmap() for other objects. The similar change applies to vunmap code. Fixes: bd72d4acda10 ("accel/amdxdna: Support user space allocated buffer") Reviewed-by: Maciej Falkowski Signed-off-by: Lizhi Hou Link: https://lore.kernel.org/r/20250916174842.234709-1-lizhi.hou@amd.com Signed-off-by: Sasha Levin --- drivers/accel/amdxdna/amdxdna_gem.c | 47 ++++++++++++----------------- 1 file changed, 20 insertions(+), 27 deletions(-) diff --git a/drivers/accel/amdxdna/amdxdna_gem.c b/drivers/accel/amdxdna/amdxdna_gem.c index d407a36eb4126..7f91863c3f24c 100644 --- a/drivers/accel/amdxdna/amdxdna_gem.c +++ b/drivers/accel/amdxdna/amdxdna_gem.c @@ -392,35 +392,33 @@ static const struct dma_buf_ops amdxdna_dmabuf_ops = { .vunmap = drm_gem_dmabuf_vunmap, }; -static int amdxdna_gem_obj_vmap(struct drm_gem_object *obj, struct iosys_map *map) +static int amdxdna_gem_obj_vmap(struct amdxdna_gem_obj *abo, void **vaddr) { - struct amdxdna_gem_obj *abo = to_xdna_obj(obj); - - iosys_map_clear(map); - - dma_resv_assert_held(obj->resv); + struct iosys_map map = IOSYS_MAP_INIT_VADDR(NULL); + int ret; if (is_import_bo(abo)) - dma_buf_vmap(abo->dma_buf, map); + ret = dma_buf_vmap_unlocked(abo->dma_buf, &map); else - drm_gem_shmem_object_vmap(obj, map); - - if (!map->vaddr) - return -ENOMEM; + ret = drm_gem_vmap(to_gobj(abo), &map); - return 0; + *vaddr = map.vaddr; + return ret; } -static void amdxdna_gem_obj_vunmap(struct drm_gem_object *obj, struct iosys_map *map) +static void amdxdna_gem_obj_vunmap(struct amdxdna_gem_obj *abo) { - struct amdxdna_gem_obj *abo = to_xdna_obj(obj); + struct iosys_map map; + + if (!abo->mem.kva) + return; - dma_resv_assert_held(obj->resv); + iosys_map_set_vaddr(&map, abo->mem.kva); if (is_import_bo(abo)) - dma_buf_vunmap(abo->dma_buf, map); + dma_buf_vunmap_unlocked(abo->dma_buf, &map); else - drm_gem_shmem_object_vunmap(obj, map); + drm_gem_vunmap(to_gobj(abo), &map); } static struct dma_buf *amdxdna_gem_prime_export(struct drm_gem_object *gobj, int flags) @@ -455,7 +453,6 @@ static void amdxdna_gem_obj_free(struct drm_gem_object *gobj) { struct amdxdna_dev *xdna = to_xdna_dev(gobj->dev); struct amdxdna_gem_obj *abo = to_xdna_obj(gobj); - struct iosys_map map = IOSYS_MAP_INIT_VADDR(abo->mem.kva); XDNA_DBG(xdna, "BO type %d xdna_addr 0x%llx", abo->type, abo->mem.dev_addr); @@ -468,7 +465,7 @@ static void amdxdna_gem_obj_free(struct drm_gem_object *gobj) if (abo->type == AMDXDNA_BO_DEV_HEAP) drm_mm_takedown(&abo->mm); - drm_gem_vunmap(gobj, &map); + amdxdna_gem_obj_vunmap(abo); mutex_destroy(&abo->lock); if (is_import_bo(abo)) { @@ -489,8 +486,8 @@ static const struct drm_gem_object_funcs amdxdna_gem_shmem_funcs = { .pin = drm_gem_shmem_object_pin, .unpin = drm_gem_shmem_object_unpin, .get_sg_table = drm_gem_shmem_object_get_sg_table, - .vmap = amdxdna_gem_obj_vmap, - .vunmap = amdxdna_gem_obj_vunmap, + .vmap = drm_gem_shmem_object_vmap, + .vunmap = drm_gem_shmem_object_vunmap, .mmap = amdxdna_gem_obj_mmap, .vm_ops = &drm_gem_shmem_vm_ops, .export = amdxdna_gem_prime_export, @@ -663,7 +660,6 @@ amdxdna_drm_create_dev_heap(struct drm_device *dev, struct drm_file *filp) { struct amdxdna_client *client = filp->driver_priv; - struct iosys_map map = IOSYS_MAP_INIT_VADDR(NULL); struct amdxdna_dev *xdna = to_xdna_dev(dev); struct amdxdna_gem_obj *abo; int ret; @@ -692,12 +688,11 @@ amdxdna_drm_create_dev_heap(struct drm_device *dev, abo->mem.dev_addr = client->xdna->dev_info->dev_mem_base; drm_mm_init(&abo->mm, abo->mem.dev_addr, abo->mem.size); - ret = drm_gem_vmap(to_gobj(abo), &map); + ret = amdxdna_gem_obj_vmap(abo, &abo->mem.kva); if (ret) { XDNA_ERR(xdna, "Vmap heap bo failed, ret %d", ret); goto release_obj; } - abo->mem.kva = map.vaddr; client->dev_heap = abo; drm_gem_object_get(to_gobj(abo)); @@ -748,7 +743,6 @@ amdxdna_drm_create_cmd_bo(struct drm_device *dev, struct amdxdna_drm_create_bo *args, struct drm_file *filp) { - struct iosys_map map = IOSYS_MAP_INIT_VADDR(NULL); struct amdxdna_dev *xdna = to_xdna_dev(dev); struct amdxdna_gem_obj *abo; int ret; @@ -770,12 +764,11 @@ amdxdna_drm_create_cmd_bo(struct drm_device *dev, abo->type = AMDXDNA_BO_CMD; abo->client = filp->driver_priv; - ret = drm_gem_vmap(to_gobj(abo), &map); + ret = amdxdna_gem_obj_vmap(abo, &abo->mem.kva); if (ret) { XDNA_ERR(xdna, "Vmap cmd bo failed, ret %d", ret); goto release_obj; } - abo->mem.kva = map.vaddr; return abo; From 270f4eb14e0fb8c212ce57c11466da45e0a9c262 Mon Sep 17 00:00:00 2001 From: Karol Wachowski Date: Tue, 16 Sep 2025 10:48:09 +0200 Subject: [PATCH 0392/2333] accel/ivpu: Ensure rpm_runtime_put in case of engine reset/resume fail [ Upstream commit 9f6c63285737b141ca25a619add80a96111b8b96 ] Previously, aborting work could return early after engine reset or resume failure, skipping the necessary runtime_put cleanup leaving the device with incorrect reference count breaking runtime power management state. Replace early returns with goto statements to ensure runtime_put is always executed. Fixes: a47e36dc5d90 ("accel/ivpu: Trigger device recovery on engine reset/resume failure") Reviewed-by: Lizhi Hou Signed-off-by: Karol Wachowski Link: https://lore.kernel.org/r/20250916084809.850073-1-karol.wachowski@linux.intel.com Signed-off-by: Sasha Levin --- drivers/accel/ivpu/ivpu_job.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/accel/ivpu/ivpu_job.c b/drivers/accel/ivpu/ivpu_job.c index 060f1fc031d34..dbefa43c74e28 100644 --- a/drivers/accel/ivpu/ivpu_job.c +++ b/drivers/accel/ivpu/ivpu_job.c @@ -1012,7 +1012,7 @@ void ivpu_context_abort_work_fn(struct work_struct *work) if (vdev->fw->sched_mode == VPU_SCHEDULING_MODE_HW) if (ivpu_jsm_reset_engine(vdev, 0)) - return; + goto runtime_put; mutex_lock(&vdev->context_list_lock); xa_for_each(&vdev->context_xa, ctx_id, file_priv) { @@ -1036,7 +1036,7 @@ void ivpu_context_abort_work_fn(struct work_struct *work) goto runtime_put; if (ivpu_jsm_hws_resume_engine(vdev, 0)) - return; + goto runtime_put; /* * In hardware scheduling mode NPU already has stopped processing jobs * and won't send us any further notifications, thus we have to free job related resources From 28540b8f226b5f2fe5158c0ae2bc1e159b7965a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guido=20G=C3=BCnther?= Date: Wed, 10 Sep 2025 18:39:56 +0200 Subject: [PATCH 0393/2333] drm/panel: visionox-rm69299: Fix clock frequency for SHIFT6mq MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit d298062312724606855294503acebc7ee55ffbca ] Make the clock frequency match what the sdm845 downstream kernel uses. Otherwise the panel stays black. Fixes: 783334f366b18 ("drm/panel: visionox-rm69299: support the variant found in the SHIFT6mq") Signed-off-by: Guido Günther Reviewed-by: Neil Armstrong Reviewed-by: Dmitry Baryshkov Signed-off-by: Neil Armstrong Link: https://lore.kernel.org/r/20250910-shift6mq-panel-v3-1-a7729911afb9@sigxcpu.org Signed-off-by: Sasha Levin --- drivers/gpu/drm/panel/panel-visionox-rm69299.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/panel/panel-visionox-rm69299.c b/drivers/gpu/drm/panel/panel-visionox-rm69299.c index 909c280eab1fb..5491d601681cf 100644 --- a/drivers/gpu/drm/panel/panel-visionox-rm69299.c +++ b/drivers/gpu/drm/panel/panel-visionox-rm69299.c @@ -247,7 +247,7 @@ static const struct drm_display_mode visionox_rm69299_1080x2248_60hz = { }; static const struct drm_display_mode visionox_rm69299_1080x2160_60hz = { - .clock = 158695, + .clock = (2160 + 8 + 4 + 4) * (1080 + 26 + 2 + 36) * 60 / 1000, .hdisplay = 1080, .hsync_start = 1080 + 26, .hsync_end = 1080 + 26 + 2, From f94792340ecc6b8762777da034e2644b469e707a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guido=20G=C3=BCnther?= Date: Wed, 10 Sep 2025 18:39:57 +0200 Subject: [PATCH 0394/2333] drm/panel: visionox-rm69299: Don't clear all mode flags MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 39144b611e9cd4f5814f4098c891b545dd70c536 ] Don't clear all mode flags. We only want to maek sure we use HS mode during unprepare. Fixes: c7f66d32dd431 ("drm/panel: add support for rm69299 visionox panel") Reviewed-by: Neil Armstrong Signed-off-by: Guido Günther Reviewed-by: Dmitry Baryshkov Signed-off-by: Neil Armstrong Link: https://lore.kernel.org/r/20250910-shift6mq-panel-v3-2-a7729911afb9@sigxcpu.org Signed-off-by: Sasha Levin --- drivers/gpu/drm/panel/panel-visionox-rm69299.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/panel/panel-visionox-rm69299.c b/drivers/gpu/drm/panel/panel-visionox-rm69299.c index 5491d601681cf..66c30db3b73a7 100644 --- a/drivers/gpu/drm/panel/panel-visionox-rm69299.c +++ b/drivers/gpu/drm/panel/panel-visionox-rm69299.c @@ -192,7 +192,7 @@ static int visionox_rm69299_unprepare(struct drm_panel *panel) struct visionox_rm69299 *ctx = panel_to_ctx(panel); struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi }; - ctx->dsi->mode_flags = 0; + ctx->dsi->mode_flags &= ~MIPI_DSI_MODE_LPM; mipi_dsi_dcs_set_display_off_multi(&dsi_ctx); From 94c56e7f63c2d952ca64a2c9a0a1ef0f8c71cf9b Mon Sep 17 00:00:00 2001 From: Jacek Lawrynowicz Date: Thu, 25 Sep 2025 16:50:59 +0200 Subject: [PATCH 0395/2333] accel/ivpu: Rework bind/unbind of imported buffers [ Upstream commit e0c0891cd63bf8338c25c423e28a5a93aed3d74c ] Ensure that imported buffers are properly mapped and unmapped in the same way as regular buffers to properly handle buffers during device's bind and unbind operations to prevent resource leaks and inconsistent buffer states. Imported buffers are now dma_mapped before submission and dma_unmapped in ivpu_bo_unbind(), guaranteeing they are unmapped when the device is unbound. Add also imported buffers to vdev->bo_list for consistent unmapping on device unbind. The bo->ctx_id is set in open() so imported buffers have a valid context ID. Debug logs have been updated to match the new code structure. The function ivpu_bo_pin() has been renamed to ivpu_bo_bind() to better reflect its purpose, and unbind tests have been refactored for improved coverage and clarity. Signed-off-by: Jacek Lawrynowicz Signed-off-by: Maciej Falkowski Reviewed-by: Karol Wachowski Signed-off-by: Karol Wachowski Link: https://lore.kernel.org/r/20250925145059.1446243-1-maciej.falkowski@linux.intel.com Stable-dep-of: 8b694b405a84 ("accel/ivpu: Fix page fault in ivpu_bo_unbind_all_bos_from_context()") Signed-off-by: Sasha Levin --- drivers/accel/ivpu/ivpu_gem.c | 90 ++++++++++++++++++++++------------- drivers/accel/ivpu/ivpu_gem.h | 2 +- drivers/accel/ivpu/ivpu_job.c | 2 +- 3 files changed, 60 insertions(+), 34 deletions(-) diff --git a/drivers/accel/ivpu/ivpu_gem.c b/drivers/accel/ivpu/ivpu_gem.c index 59cfcf3eaded9..dc6d0d15cda9c 100644 --- a/drivers/accel/ivpu/ivpu_gem.c +++ b/drivers/accel/ivpu/ivpu_gem.c @@ -27,8 +27,8 @@ static const struct drm_gem_object_funcs ivpu_gem_funcs; static inline void ivpu_dbg_bo(struct ivpu_device *vdev, struct ivpu_bo *bo, const char *action) { ivpu_dbg(vdev, BO, - "%6s: bo %8p vpu_addr %9llx size %8zu ctx %d has_pages %d dma_mapped %d mmu_mapped %d wc %d imported %d\n", - action, bo, bo->vpu_addr, ivpu_bo_size(bo), bo->ctx_id, + "%6s: bo %8p size %9zu ctx %d vpu_addr %9llx pages %d sgt %d mmu_mapped %d wc %d imported %d\n", + action, bo, ivpu_bo_size(bo), bo->ctx_id, bo->vpu_addr, (bool)bo->base.pages, (bool)bo->base.sgt, bo->mmu_mapped, bo->base.map_wc, (bool)drm_gem_is_imported(&bo->base.base)); } @@ -43,22 +43,46 @@ static inline void ivpu_bo_unlock(struct ivpu_bo *bo) dma_resv_unlock(bo->base.base.resv); } +static struct sg_table *ivpu_bo_map_attachment(struct ivpu_device *vdev, struct ivpu_bo *bo) +{ + struct sg_table *sgt = bo->base.sgt; + + drm_WARN_ON(&vdev->drm, !bo->base.base.import_attach); + + ivpu_bo_lock(bo); + + if (!sgt) { + sgt = dma_buf_map_attachment(bo->base.base.import_attach, DMA_BIDIRECTIONAL); + if (IS_ERR(sgt)) + ivpu_err(vdev, "Failed to map BO in IOMMU: %ld\n", PTR_ERR(sgt)); + else + bo->base.sgt = sgt; + } + + ivpu_bo_unlock(bo); + + return sgt; +} + /* - * ivpu_bo_pin() - pin the backing physical pages and map them to VPU. + * ivpu_bo_bind() - pin the backing physical pages and map them to VPU. * * This function pins physical memory pages, then maps the physical pages * to IOMMU address space and finally updates the VPU MMU page tables * to allow the VPU to translate VPU address to IOMMU address. */ -int __must_check ivpu_bo_pin(struct ivpu_bo *bo) +int __must_check ivpu_bo_bind(struct ivpu_bo *bo) { struct ivpu_device *vdev = ivpu_bo_to_vdev(bo); struct sg_table *sgt; int ret = 0; - ivpu_dbg_bo(vdev, bo, "pin"); + ivpu_dbg_bo(vdev, bo, "bind"); - sgt = drm_gem_shmem_get_pages_sgt(&bo->base); + if (bo->base.base.import_attach) + sgt = ivpu_bo_map_attachment(vdev, bo); + else + sgt = drm_gem_shmem_get_pages_sgt(&bo->base); if (IS_ERR(sgt)) { ret = PTR_ERR(sgt); ivpu_err(vdev, "Failed to map BO in IOMMU: %d\n", ret); @@ -99,7 +123,9 @@ ivpu_bo_alloc_vpu_addr(struct ivpu_bo *bo, struct ivpu_mmu_context *ctx, ret = ivpu_mmu_context_insert_node(ctx, range, ivpu_bo_size(bo), &bo->mm_node); if (!ret) { bo->ctx = ctx; + bo->ctx_id = ctx->id; bo->vpu_addr = bo->mm_node.start; + ivpu_dbg_bo(vdev, bo, "vaddr"); } else { ivpu_err(vdev, "Failed to add BO to context %u: %d\n", ctx->id, ret); } @@ -115,7 +141,7 @@ static void ivpu_bo_unbind_locked(struct ivpu_bo *bo) { struct ivpu_device *vdev = ivpu_bo_to_vdev(bo); - lockdep_assert(dma_resv_held(bo->base.base.resv) || !kref_read(&bo->base.base.refcount)); + dma_resv_assert_held(bo->base.base.resv); if (bo->mmu_mapped) { drm_WARN_ON(&vdev->drm, !bo->ctx); @@ -134,9 +160,14 @@ static void ivpu_bo_unbind_locked(struct ivpu_bo *bo) return; if (bo->base.sgt) { - dma_unmap_sgtable(vdev->drm.dev, bo->base.sgt, DMA_BIDIRECTIONAL, 0); - sg_free_table(bo->base.sgt); - kfree(bo->base.sgt); + if (bo->base.base.import_attach) { + dma_buf_unmap_attachment(bo->base.base.import_attach, + bo->base.sgt, DMA_BIDIRECTIONAL); + } else { + dma_unmap_sgtable(vdev->drm.dev, bo->base.sgt, DMA_BIDIRECTIONAL, 0); + sg_free_table(bo->base.sgt); + kfree(bo->base.sgt); + } bo->base.sgt = NULL; } } @@ -162,6 +193,7 @@ void ivpu_bo_unbind_all_bos_from_context(struct ivpu_device *vdev, struct ivpu_m struct drm_gem_object *ivpu_gem_create_object(struct drm_device *dev, size_t size) { + struct ivpu_device *vdev = to_ivpu_device(dev); struct ivpu_bo *bo; if (size == 0 || !PAGE_ALIGNED(size)) @@ -176,6 +208,11 @@ struct drm_gem_object *ivpu_gem_create_object(struct drm_device *dev, size_t siz INIT_LIST_HEAD(&bo->bo_list_node); + mutex_lock(&vdev->bo_list_lock); + list_add_tail(&bo->bo_list_node, &vdev->bo_list); + mutex_unlock(&vdev->bo_list_lock); + + ivpu_dbg(vdev, BO, " alloc: bo %8p size %9zu\n", bo, size); return &bo->base.base; } @@ -184,7 +221,6 @@ struct drm_gem_object *ivpu_gem_prime_import(struct drm_device *dev, { struct device *attach_dev = dev->dev; struct dma_buf_attachment *attach; - struct sg_table *sgt; struct drm_gem_object *obj; int ret; @@ -194,16 +230,10 @@ struct drm_gem_object *ivpu_gem_prime_import(struct drm_device *dev, get_dma_buf(dma_buf); - sgt = dma_buf_map_attachment_unlocked(attach, DMA_BIDIRECTIONAL); - if (IS_ERR(sgt)) { - ret = PTR_ERR(sgt); - goto fail_detach; - } - - obj = drm_gem_shmem_prime_import_sg_table(dev, attach, sgt); + obj = drm_gem_shmem_prime_import_sg_table(dev, attach, NULL); if (IS_ERR(obj)) { ret = PTR_ERR(obj); - goto fail_unmap; + goto fail_detach; } obj->import_attach = attach; @@ -211,8 +241,6 @@ struct drm_gem_object *ivpu_gem_prime_import(struct drm_device *dev, return obj; -fail_unmap: - dma_buf_unmap_attachment_unlocked(attach, sgt, DMA_BIDIRECTIONAL); fail_detach: dma_buf_detach(dma_buf, attach); dma_buf_put(dma_buf); @@ -220,7 +248,7 @@ struct drm_gem_object *ivpu_gem_prime_import(struct drm_device *dev, return ERR_PTR(ret); } -static struct ivpu_bo *ivpu_bo_alloc(struct ivpu_device *vdev, u64 size, u32 flags, u32 ctx_id) +static struct ivpu_bo *ivpu_bo_alloc(struct ivpu_device *vdev, u64 size, u32 flags) { struct drm_gem_shmem_object *shmem; struct ivpu_bo *bo; @@ -238,16 +266,9 @@ static struct ivpu_bo *ivpu_bo_alloc(struct ivpu_device *vdev, u64 size, u32 fla return ERR_CAST(shmem); bo = to_ivpu_bo(&shmem->base); - bo->ctx_id = ctx_id; bo->base.map_wc = flags & DRM_IVPU_BO_WC; bo->flags = flags; - mutex_lock(&vdev->bo_list_lock); - list_add_tail(&bo->bo_list_node, &vdev->bo_list); - mutex_unlock(&vdev->bo_list_lock); - - ivpu_dbg_bo(vdev, bo, "alloc"); - return bo; } @@ -281,6 +302,8 @@ static void ivpu_gem_bo_free(struct drm_gem_object *obj) ivpu_dbg_bo(vdev, bo, "free"); + drm_WARN_ON(&vdev->drm, list_empty(&bo->bo_list_node)); + mutex_lock(&vdev->bo_list_lock); list_del(&bo->bo_list_node); mutex_unlock(&vdev->bo_list_lock); @@ -290,7 +313,10 @@ static void ivpu_gem_bo_free(struct drm_gem_object *obj) drm_WARN_ON(&vdev->drm, ivpu_bo_size(bo) == 0); drm_WARN_ON(&vdev->drm, bo->base.vaddr); + ivpu_bo_lock(bo); ivpu_bo_unbind_locked(bo); + ivpu_bo_unlock(bo); + drm_WARN_ON(&vdev->drm, bo->mmu_mapped); drm_WARN_ON(&vdev->drm, bo->ctx); @@ -326,7 +352,7 @@ int ivpu_bo_create_ioctl(struct drm_device *dev, void *data, struct drm_file *fi if (size == 0) return -EINVAL; - bo = ivpu_bo_alloc(vdev, size, args->flags, file_priv->ctx.id); + bo = ivpu_bo_alloc(vdev, size, args->flags); if (IS_ERR(bo)) { ivpu_err(vdev, "Failed to allocate BO: %pe (ctx %u size %llu flags 0x%x)", bo, file_priv->ctx.id, args->size, args->flags); @@ -360,7 +386,7 @@ ivpu_bo_create(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx, drm_WARN_ON(&vdev->drm, !PAGE_ALIGNED(range->end)); drm_WARN_ON(&vdev->drm, !PAGE_ALIGNED(size)); - bo = ivpu_bo_alloc(vdev, size, flags, IVPU_GLOBAL_CONTEXT_MMU_SSID); + bo = ivpu_bo_alloc(vdev, size, flags); if (IS_ERR(bo)) { ivpu_err(vdev, "Failed to allocate BO: %pe (vpu_addr 0x%llx size %llu flags 0x%x)", bo, range->start, size, flags); @@ -371,7 +397,7 @@ ivpu_bo_create(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx, if (ret) goto err_put; - ret = ivpu_bo_pin(bo); + ret = ivpu_bo_bind(bo); if (ret) goto err_put; diff --git a/drivers/accel/ivpu/ivpu_gem.h b/drivers/accel/ivpu/ivpu_gem.h index aa8ff14f7aae1..ade0d127453ff 100644 --- a/drivers/accel/ivpu/ivpu_gem.h +++ b/drivers/accel/ivpu/ivpu_gem.h @@ -24,7 +24,7 @@ struct ivpu_bo { bool mmu_mapped; }; -int ivpu_bo_pin(struct ivpu_bo *bo); +int ivpu_bo_bind(struct ivpu_bo *bo); void ivpu_bo_unbind_all_bos_from_context(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx); struct drm_gem_object *ivpu_gem_create_object(struct drm_device *dev, size_t size); diff --git a/drivers/accel/ivpu/ivpu_job.c b/drivers/accel/ivpu/ivpu_job.c index dbefa43c74e28..1e4caf5726474 100644 --- a/drivers/accel/ivpu/ivpu_job.c +++ b/drivers/accel/ivpu/ivpu_job.c @@ -732,7 +732,7 @@ ivpu_job_prepare_bos_for_submit(struct drm_file *file, struct ivpu_job *job, u32 job->bos[i] = to_ivpu_bo(obj); - ret = ivpu_bo_pin(job->bos[i]); + ret = ivpu_bo_bind(job->bos[i]); if (ret) return ret; } From c9ef5ccd8bd9bcf598b6d3f77e7eb4dde7149aec Mon Sep 17 00:00:00 2001 From: Jacek Lawrynowicz Date: Thu, 25 Sep 2025 16:51:14 +0200 Subject: [PATCH 0396/2333] accel/ivpu: Fix page fault in ivpu_bo_unbind_all_bos_from_context() [ Upstream commit 8b694b405a84696f1d964f6da7cf9721e68c4714 ] Don't add BO to the vdev->bo_list in ivpu_gem_create_object(). When failure happens inside drm_gem_shmem_create(), the BO is not fully created and ivpu_gem_bo_free() callback will not be called causing a deleted BO to be left on the list. Fixes: 8d88e4cdce4f ("accel/ivpu: Use GEM shmem helper for all buffers") Signed-off-by: Jacek Lawrynowicz Signed-off-by: Maciej Falkowski Reviewed-by: Karol Wachowski Signed-off-by: Karol Wachowski Link: https://lore.kernel.org/r/20250925145114.1446283-1-maciej.falkowski@linux.intel.com Signed-off-by: Sasha Levin --- drivers/accel/ivpu/ivpu_gem.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/drivers/accel/ivpu/ivpu_gem.c b/drivers/accel/ivpu/ivpu_gem.c index dc6d0d15cda9c..171e809575ad6 100644 --- a/drivers/accel/ivpu/ivpu_gem.c +++ b/drivers/accel/ivpu/ivpu_gem.c @@ -193,7 +193,6 @@ void ivpu_bo_unbind_all_bos_from_context(struct ivpu_device *vdev, struct ivpu_m struct drm_gem_object *ivpu_gem_create_object(struct drm_device *dev, size_t size) { - struct ivpu_device *vdev = to_ivpu_device(dev); struct ivpu_bo *bo; if (size == 0 || !PAGE_ALIGNED(size)) @@ -208,20 +207,17 @@ struct drm_gem_object *ivpu_gem_create_object(struct drm_device *dev, size_t siz INIT_LIST_HEAD(&bo->bo_list_node); - mutex_lock(&vdev->bo_list_lock); - list_add_tail(&bo->bo_list_node, &vdev->bo_list); - mutex_unlock(&vdev->bo_list_lock); - - ivpu_dbg(vdev, BO, " alloc: bo %8p size %9zu\n", bo, size); return &bo->base.base; } struct drm_gem_object *ivpu_gem_prime_import(struct drm_device *dev, struct dma_buf *dma_buf) { + struct ivpu_device *vdev = to_ivpu_device(dev); struct device *attach_dev = dev->dev; struct dma_buf_attachment *attach; struct drm_gem_object *obj; + struct ivpu_bo *bo; int ret; attach = dma_buf_attach(dma_buf, attach_dev); @@ -239,6 +235,14 @@ struct drm_gem_object *ivpu_gem_prime_import(struct drm_device *dev, obj->import_attach = attach; obj->resv = dma_buf->resv; + bo = to_ivpu_bo(obj); + + mutex_lock(&vdev->bo_list_lock); + list_add_tail(&bo->bo_list_node, &vdev->bo_list); + mutex_unlock(&vdev->bo_list_lock); + + ivpu_dbg(vdev, BO, "import: bo %8p size %9zu\n", bo, ivpu_bo_size(bo)); + return obj; fail_detach: @@ -269,6 +273,12 @@ static struct ivpu_bo *ivpu_bo_alloc(struct ivpu_device *vdev, u64 size, u32 fla bo->base.map_wc = flags & DRM_IVPU_BO_WC; bo->flags = flags; + mutex_lock(&vdev->bo_list_lock); + list_add_tail(&bo->bo_list_node, &vdev->bo_list); + mutex_unlock(&vdev->bo_list_lock); + + ivpu_dbg(vdev, BO, " alloc: bo %8p size %9llu\n", bo, size); + return bo; } From ec6ca941783a96c2b4217b5d511c2f675e0f8b44 Mon Sep 17 00:00:00 2001 From: Karol Wachowski Date: Wed, 1 Oct 2025 12:43:22 +0200 Subject: [PATCH 0397/2333] accel/ivpu: Fix DCT active percent format [ Upstream commit aa1c2b073ad23847dd2e7bdc7d30009f34ed7f59 ] The pcode MAILBOX STATUS register PARAM2 field expects DCT active percent in U1.7 value format. Convert percentage value to this format before writing to the register. Fixes: a19bffb10c46 ("accel/ivpu: Implement DCT handling") Reviewed-by: Lizhi Hou Signed-off-by: Karol Wachowski Link: https://lore.kernel.org/r/20251001104322.1249896-1-karol.wachowski@linux.intel.com Signed-off-by: Sasha Levin --- drivers/accel/ivpu/ivpu_hw_btrs.c | 2 +- drivers/accel/ivpu/ivpu_hw_btrs.h | 2 +- drivers/accel/ivpu/ivpu_pm.c | 9 +++++++-- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/accel/ivpu/ivpu_hw_btrs.c b/drivers/accel/ivpu/ivpu_hw_btrs.c index afdb3b2aa72a7..aa33f562d29c1 100644 --- a/drivers/accel/ivpu/ivpu_hw_btrs.c +++ b/drivers/accel/ivpu/ivpu_hw_btrs.c @@ -752,7 +752,7 @@ int ivpu_hw_btrs_dct_get_request(struct ivpu_device *vdev, bool *enable) } } -void ivpu_hw_btrs_dct_set_status(struct ivpu_device *vdev, bool enable, u32 active_percent) +void ivpu_hw_btrs_dct_set_status(struct ivpu_device *vdev, bool enable, u8 active_percent) { u32 val = 0; u32 cmd = enable ? DCT_ENABLE : DCT_DISABLE; diff --git a/drivers/accel/ivpu/ivpu_hw_btrs.h b/drivers/accel/ivpu/ivpu_hw_btrs.h index 032c384ac3d4d..c4c10e22f30f3 100644 --- a/drivers/accel/ivpu/ivpu_hw_btrs.h +++ b/drivers/accel/ivpu/ivpu_hw_btrs.h @@ -36,7 +36,7 @@ u32 ivpu_hw_btrs_dpu_freq_get(struct ivpu_device *vdev); bool ivpu_hw_btrs_irq_handler_mtl(struct ivpu_device *vdev, int irq); bool ivpu_hw_btrs_irq_handler_lnl(struct ivpu_device *vdev, int irq); int ivpu_hw_btrs_dct_get_request(struct ivpu_device *vdev, bool *enable); -void ivpu_hw_btrs_dct_set_status(struct ivpu_device *vdev, bool enable, u32 active_percent); +void ivpu_hw_btrs_dct_set_status(struct ivpu_device *vdev, bool enable, u8 active_percent); u32 ivpu_hw_btrs_telemetry_offset_get(struct ivpu_device *vdev); u32 ivpu_hw_btrs_telemetry_size_get(struct ivpu_device *vdev); u32 ivpu_hw_btrs_telemetry_enable_get(struct ivpu_device *vdev); diff --git a/drivers/accel/ivpu/ivpu_pm.c b/drivers/accel/ivpu/ivpu_pm.c index 475ddc94f1cfe..457ccf09df545 100644 --- a/drivers/accel/ivpu/ivpu_pm.c +++ b/drivers/accel/ivpu/ivpu_pm.c @@ -502,6 +502,11 @@ void ivpu_pm_irq_dct_work_fn(struct work_struct *work) else ret = ivpu_pm_dct_disable(vdev); - if (!ret) - ivpu_hw_btrs_dct_set_status(vdev, enable, vdev->pm->dct_active_percent); + if (!ret) { + /* Convert percent to U1.7 format */ + u8 val = DIV_ROUND_CLOSEST(vdev->pm->dct_active_percent * 128, 100); + + ivpu_hw_btrs_dct_set_status(vdev, enable, val); + } + } From 1f0ca9d3e7c38a39f1f12377c24decf0bba46e54 Mon Sep 17 00:00:00 2001 From: Janusz Krzysztofik Date: Fri, 26 Sep 2025 17:26:27 +0200 Subject: [PATCH 0398/2333] drm/vgem-fence: Fix potential deadlock on release MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 78b4d6463e9e69e5103f98b367f8984ad12cdc6f ] A timer that expires a vgem fence automatically in 10 seconds is now released with timer_delete_sync() from fence->ops.release() called on last dma_fence_put(). In some scenarios, it can run in IRQ context, which is not safe unless TIMER_IRQSAFE is used. One potentially risky scenario was demonstrated in Intel DRM CI trybot, BAT run on machine bat-adlp-6, while working on new IGT subtests syncobj_timeline@stress-* as user space replacements of some problematic test cases of a dma-fence-chain selftest [1]. [117.004338] ================================ [117.004340] WARNING: inconsistent lock state [117.004342] 6.17.0-rc7-CI_DRM_17270-g7644974e648c+ #1 Tainted: G S U [117.004346] -------------------------------- [117.004347] inconsistent {HARDIRQ-ON-W} -> {IN-HARDIRQ-W} usage. [117.004349] swapper/0/0 [HC1[1]:SC1[1]:HE0:SE0] takes: [117.004352] ffff888138f86aa8 ((&fence->timer)){?.-.}-{0:0}, at: __timer_delete_sync+0x4b/0x190 [117.004361] {HARDIRQ-ON-W} state was registered at: [117.004363] lock_acquire+0xc4/0x2e0 [117.004366] call_timer_fn+0x80/0x2a0 [117.004368] __run_timers+0x231/0x310 [117.004370] run_timer_softirq+0x76/0xe0 [117.004372] handle_softirqs+0xd4/0x4d0 [117.004375] __irq_exit_rcu+0x13f/0x160 [117.004377] irq_exit_rcu+0xe/0x20 [117.004379] sysvec_apic_timer_interrupt+0xa0/0xc0 [117.004382] asm_sysvec_apic_timer_interrupt+0x1b/0x20 [117.004385] cpuidle_enter_state+0x12b/0x8a0 [117.004388] cpuidle_enter+0x2e/0x50 [117.004393] call_cpuidle+0x22/0x60 [117.004395] do_idle+0x1fd/0x260 [117.004398] cpu_startup_entry+0x29/0x30 [117.004401] start_secondary+0x12d/0x160 [117.004404] common_startup_64+0x13e/0x141 [117.004407] irq event stamp: 2282669 [117.004409] hardirqs last enabled at (2282668): [] _raw_spin_unlock_irqrestore+0x51/0x80 [117.004414] hardirqs last disabled at (2282669): [] sysvec_irq_work+0x11/0xc0 [117.004419] softirqs last enabled at (2254702): [] __do_softirq+0x10/0x18 [117.004423] softirqs last disabled at (2254725): [] __irq_exit_rcu+0x13f/0x160 [117.004426] other info that might help us debug this: [117.004429] Possible unsafe locking scenario: [117.004432] CPU0 [117.004433] ---- [117.004434] lock((&fence->timer)); [117.004436] [117.004438] lock((&fence->timer)); [117.004440] *** DEADLOCK *** [117.004443] 1 lock held by swapper/0/0: [117.004445] #0: ffffc90000003d50 ((&fence->timer)){?.-.}-{0:0}, at: call_timer_fn+0x7a/0x2a0 [117.004450] stack backtrace: [117.004453] CPU: 0 UID: 0 PID: 0 Comm: swapper/0 Tainted: G S U 6.17.0-rc7-CI_DRM_17270-g7644974e648c+ #1 PREEMPT(voluntary) [117.004455] Tainted: [S]=CPU_OUT_OF_SPEC, [U]=USER [117.004455] Hardware name: Intel Corporation Alder Lake Client Platform/AlderLake-P DDR4 RVP, BIOS RPLPFWI1.R00.4035.A00.2301200723 01/20/2023 [117.004456] Call Trace: [117.004456] [117.004457] dump_stack_lvl+0x91/0xf0 [117.004460] dump_stack+0x10/0x20 [117.004461] print_usage_bug.part.0+0x260/0x360 [117.004463] mark_lock+0x76e/0x9c0 [117.004465] ? register_lock_class+0x48/0x4a0 [117.004467] __lock_acquire+0xbc3/0x2860 [117.004469] lock_acquire+0xc4/0x2e0 [117.004470] ? __timer_delete_sync+0x4b/0x190 [117.004472] ? __timer_delete_sync+0x4b/0x190 [117.004473] __timer_delete_sync+0x68/0x190 [117.004474] ? __timer_delete_sync+0x4b/0x190 [117.004475] timer_delete_sync+0x10/0x20 [117.004476] vgem_fence_release+0x19/0x30 [vgem] [117.004478] dma_fence_release+0xc1/0x3b0 [117.004480] ? dma_fence_release+0xa1/0x3b0 [117.004481] dma_fence_chain_release+0xe7/0x130 [117.004483] dma_fence_release+0xc1/0x3b0 [117.004484] ? _raw_spin_unlock_irqrestore+0x27/0x80 [117.004485] dma_fence_chain_irq_work+0x59/0x80 [117.004487] irq_work_single+0x75/0xa0 [117.004490] irq_work_run_list+0x33/0x60 [117.004491] irq_work_run+0x18/0x40 [117.004493] __sysvec_irq_work+0x35/0x170 [117.004494] sysvec_irq_work+0x47/0xc0 [117.004496] asm_sysvec_irq_work+0x1b/0x20 [117.004497] RIP: 0010:_raw_spin_unlock_irqrestore+0x57/0x80 [117.004499] Code: 00 75 1c 65 ff 0d d9 34 68 01 74 20 5b 41 5c 5d 31 c0 31 d2 31 c9 31 f6 31 ff c3 cc cc cc cc e8 7f 9d d3 fe fb 0f 1f 44 00 00 d7 0f 1f 44 00 00 5b 41 5c 5d 31 c0 31 d2 31 c9 31 f6 31 ff c3 [117.004499] RSP: 0018:ffffc90000003cf0 EFLAGS: 00000246 [117.004500] RAX: 0000000000000000 RBX: ffff888155e94c40 RCX: 0000000000000000 [117.004501] RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000000 [117.004502] RBP: ffffc90000003d00 R08: 0000000000000000 R09: 0000000000000000 [117.004502] R10: 0000000000000000 R11: 0000000000000000 R12: 0000000000000246 [117.004502] R13: 0000000000000001 R14: 0000000000000246 R15: ffff888155e94c80 [117.004506] dma_fence_signal+0x49/0xb0 [117.004507] ? __pfx_vgem_fence_timeout+0x10/0x10 [vgem] [117.004508] vgem_fence_timeout+0x12/0x20 [vgem] [117.004509] call_timer_fn+0xa1/0x2a0 [117.004512] ? __pfx_vgem_fence_timeout+0x10/0x10 [vgem] [117.004513] __run_timers+0x231/0x310 [117.004514] ? tmigr_handle_remote+0x2ac/0x560 [117.004517] timer_expire_remote+0x46/0x70 [117.004518] tmigr_handle_remote+0x433/0x560 [117.004520] ? __run_timers+0x239/0x310 [117.004521] ? run_timer_softirq+0x21/0xe0 [117.004522] ? lock_release+0xce/0x2a0 [117.004524] run_timer_softirq+0xcf/0xe0 [117.004525] handle_softirqs+0xd4/0x4d0 [117.004526] __irq_exit_rcu+0x13f/0x160 [117.004527] irq_exit_rcu+0xe/0x20 [117.004528] sysvec_apic_timer_interrupt+0xa0/0xc0 [117.004529] [117.004529] [117.004529] asm_sysvec_apic_timer_interrupt+0x1b/0x20 [117.004530] RIP: 0010:cpuidle_enter_state+0x12b/0x8a0 [117.004532] Code: 48 0f a3 05 97 ce 0e 01 0f 82 2e 03 00 00 31 ff e8 8a 41 bd fe 80 7d d0 00 0f 85 11 03 00 00 e8 8b 06 d5 fe fb 0f 1f 44 00 00 <45> 85 f6 0f 88 67 02 00 00 4d 63 ee 49 83 fd 0a 0f 83 34 06 00 00 [117.004532] RSP: 0018:ffffffff83403d88 EFLAGS: 00000246 [117.004533] RAX: 0000000000000000 RBX: ffff88888f046440 RCX: 0000000000000000 [117.004533] RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000000 [117.004534] RBP: ffffffff83403dd8 R08: 0000000000000000 R09: 0000000000000000 [117.004534] R10: 0000000000000000 R11: 0000000000000000 R12: ffffffff837cbe80 [117.004534] R13: 0000000000000004 R14: 0000000000000004 R15: 0000001ad1df466b [117.004537] ? cpuidle_enter_state+0x125/0x8a0 [117.004538] ? sched_clock_noinstr+0x9/0x10 [117.004540] cpuidle_enter+0x2e/0x50 [117.004542] call_cpuidle+0x22/0x60 [117.004542] do_idle+0x1fd/0x260 [117.004544] cpu_startup_entry+0x29/0x30 [117.004546] rest_init+0x104/0x200 [117.004548] start_kernel+0x93d/0xbd0 [117.004550] ? load_ucode_intel_bsp+0x2a/0x90 [117.004551] ? sme_unmap_bootdata+0x14/0x80 [117.004554] x86_64_start_reservations+0x18/0x30 [117.004555] x86_64_start_kernel+0xfd/0x150 [117.004556] ? soft_restart_cpu+0x14/0x14 [117.004558] common_startup_64+0x13e/0x141 [117.004560] [117.004565] ------------[ cut here ]------------ [117.004692] WARNING: CPU: 0 PID: 0 at kernel/time/timer.c:1610 __timer_delete_sync+0x126/0x190 [117.004697] Modules linked in: vgem snd_hda_codec_intelhdmi snd_hda_codec_hdmi i915 prime_numbers ttm drm_buddy drm_display_helper cec rc_core i2c_algo_bit hid_sensor_custom hid_sensor_hub hid_generic intel_ishtp_hid hid intel_uncore_frequency intel_uncore_frequency_common x86_pkg_temp_thermal intel_powerclamp cmdlinepart ee1004 r8153_ecm spi_nor coretemp cdc_ether mei_pxp mei_hdcp usbnet mtd intel_rapl_msr wmi_bmof kvm_intel snd_hda_intel snd_intel_dspcfg processor_thermal_device_pci kvm snd_hda_codec processor_thermal_device irqbypass processor_thermal_wt_hint polyval_clmulni platform_temperature_control snd_hda_core ghash_clmulni_intel processor_thermal_rfim spi_pxa2xx_platform snd_hwdep aesni_intel processor_thermal_rapl dw_dmac snd_pcm dw_dmac_core intel_rapl_common r8152 rapl mii intel_cstate spi_pxa2xx_core i2c_i801 processor_thermal_wt_req snd_timer i2c_mux mei_me intel_ish_ipc processor_thermal_power_floor e1000e snd i2c_smbus spi_intel_pci processor_thermal_mbox mei soundcore intel_ishtp thunderbolt idma64 [117.004733] spi_intel int340x_thermal_zone igen6_edac binfmt_misc intel_skl_int3472_tps68470 intel_pmc_core tps68470_regulator video clk_tps68470 pmt_telemetry pmt_discovery nls_iso8859_1 pmt_class intel_pmc_ssram_telemetry intel_skl_int3472_discrete int3400_thermal intel_hid intel_skl_int3472_common acpi_thermal_rel intel_vsec wmi pinctrl_tigerlake acpi_tad sparse_keymap acpi_pad dm_multipath msr nvme_fabrics fuse efi_pstore nfnetlink autofs4 [117.004782] CPU: 0 UID: 0 PID: 0 Comm: swapper/0 Tainted: G S U 6.17.0-rc7-CI_DRM_17270-g7644974e648c+ #1 PREEMPT(voluntary) [117.004787] Tainted: [S]=CPU_OUT_OF_SPEC, [U]=USER [117.004789] Hardware name: Intel Corporation Alder Lake Client Platform/AlderLake-P DDR4 RVP, BIOS RPLPFWI1.R00.4035.A00.2301200723 01/20/2023 [117.004793] RIP: 0010:__timer_delete_sync+0x126/0x190 [117.004795] Code: 31 c0 45 31 c9 c3 cc cc cc cc 48 8b 75 d0 45 84 f6 74 63 49 c7 45 18 00 00 00 00 48 89 c7 e8 51 46 39 01 f3 90 e9 66 ff ff ff <0f> 0b e9 5f ff ff ff e8 ee e4 0c 00 49 8d 5d 28 45 31 c9 31 c9 4c [117.004801] RSP: 0018:ffffc90000003a40 EFLAGS: 00010046 [117.004804] RAX: ffffffff815093fb RBX: ffff888138f86aa8 RCX: 0000000000000000 [117.004807] RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000000 [117.004809] RBP: ffffc90000003a70 R08: 0000000000000000 R09: 0000000000000000 [117.004812] R10: 0000000000000000 R11: 0000000000000000 R12: ffffffff815093fb [117.004814] R13: ffff888138f86a80 R14: 0000000000000000 R15: 0000000000000000 [117.004817] FS: 0000000000000000(0000) GS:ffff88890b0f7000(0000) knlGS:0000000000000000 [117.004820] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [117.004823] CR2: 00005db8131eb7f0 CR3: 0000000003448000 CR4: 0000000000f52ef0 [117.004826] PKRU: 55555554 [117.004827] Call Trace: [117.004829] [117.004831] timer_delete_sync+0x10/0x20 [117.004833] vgem_fence_release+0x19/0x30 [vgem] [117.004836] dma_fence_release+0xc1/0x3b0 [117.004838] ? dma_fence_release+0xa1/0x3b0 [117.004841] dma_fence_chain_release+0xe7/0x130 [117.004844] dma_fence_release+0xc1/0x3b0 [117.004847] ? _raw_spin_unlock_irqrestore+0x27/0x80 [117.004850] dma_fence_chain_irq_work+0x59/0x80 [117.004853] irq_work_single+0x75/0xa0 [117.004857] irq_work_run_list+0x33/0x60 [117.004860] irq_work_run+0x18/0x40 [117.004863] __sysvec_irq_work+0x35/0x170 [117.004865] sysvec_irq_work+0x47/0xc0 [117.004868] asm_sysvec_irq_work+0x1b/0x20 [117.004871] RIP: 0010:_raw_spin_unlock_irqrestore+0x57/0x80 [117.004874] Code: 00 75 1c 65 ff 0d d9 34 68 01 74 20 5b 41 5c 5d 31 c0 31 d2 31 c9 31 f6 31 ff c3 cc cc cc cc e8 7f 9d d3 fe fb 0f 1f 44 00 00 d7 0f 1f 44 00 00 5b 41 5c 5d 31 c0 31 d2 31 c9 31 f6 31 ff c3 [117.004879] RSP: 0018:ffffc90000003cf0 EFLAGS: 00000246 [117.004882] RAX: 0000000000000000 RBX: ffff888155e94c40 RCX: 0000000000000000 [117.004884] RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000000 [117.004887] RBP: ffffc90000003d00 R08: 0000000000000000 R09: 0000000000000000 [117.004890] R10: 0000000000000000 R11: 0000000000000000 R12: 0000000000000246 [117.004892] R13: 0000000000000001 R14: 0000000000000246 R15: ffff888155e94c80 [117.004897] dma_fence_signal+0x49/0xb0 [117.004899] ? __pfx_vgem_fence_timeout+0x10/0x10 [vgem] [117.004902] vgem_fence_timeout+0x12/0x20 [vgem] [117.004904] call_timer_fn+0xa1/0x2a0 [117.004908] ? __pfx_vgem_fence_timeout+0x10/0x10 [vgem] [117.004910] __run_timers+0x231/0x310 [117.004913] ? tmigr_handle_remote+0x2ac/0x560 [117.004917] timer_expire_remote+0x46/0x70 [117.004919] tmigr_handle_remote+0x433/0x560 [117.004923] ? __run_timers+0x239/0x310 [117.004925] ? run_timer_softirq+0x21/0xe0 [117.004928] ? lock_release+0xce/0x2a0 [117.004931] run_timer_softirq+0xcf/0xe0 [117.004933] handle_softirqs+0xd4/0x4d0 [117.004936] __irq_exit_rcu+0x13f/0x160 [117.004938] irq_exit_rcu+0xe/0x20 [117.004940] sysvec_apic_timer_interrupt+0xa0/0xc0 [117.004943] [117.004944] [117.004946] asm_sysvec_apic_timer_interrupt+0x1b/0x20 [117.004949] RIP: 0010:cpuidle_enter_state+0x12b/0x8a0 [117.004953] Code: 48 0f a3 05 97 ce 0e 01 0f 82 2e 03 00 00 31 ff e8 8a 41 bd fe 80 7d d0 00 0f 85 11 03 00 00 e8 8b 06 d5 fe fb 0f 1f 44 00 00 <45> 85 f6 0f 88 67 02 00 00 4d 63 ee 49 83 fd 0a 0f 83 34 06 00 00 [117.004961] RSP: 0018:ffffffff83403d88 EFLAGS: 00000246 [117.004963] RAX: 0000000000000000 RBX: ffff88888f046440 RCX: 0000000000000000 [117.004966] RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000000 [117.004968] RBP: ffffffff83403dd8 R08: 0000000000000000 R09: 0000000000000000 [117.004971] R10: 0000000000000000 R11: 0000000000000000 R12: ffffffff837cbe80 [117.004974] R13: 0000000000000004 R14: 0000000000000004 R15: 0000001ad1df466b [117.004978] ? cpuidle_enter_state+0x125/0x8a0 [117.004981] ? sched_clock_noinstr+0x9/0x10 [117.004985] cpuidle_enter+0x2e/0x50 [117.004989] call_cpuidle+0x22/0x60 [117.004991] do_idle+0x1fd/0x260 [117.005001] cpu_startup_entry+0x29/0x30 [117.005004] rest_init+0x104/0x200 [117.005008] start_kernel+0x93d/0xbd0 [117.005011] ? load_ucode_intel_bsp+0x2a/0x90 [117.005014] ? sme_unmap_bootdata+0x14/0x80 [117.005017] x86_64_start_reservations+0x18/0x30 [117.005020] x86_64_start_kernel+0xfd/0x150 [117.005023] ? soft_restart_cpu+0x14/0x14 [117.005026] common_startup_64+0x13e/0x141 [117.005030] [117.005032] irq event stamp: 2282669 [117.005034] hardirqs last enabled at (2282668): [] _raw_spin_unlock_irqrestore+0x51/0x80 [117.005038] hardirqs last disabled at (2282669): [] sysvec_irq_work+0x11/0xc0 [117.005043] softirqs last enabled at (2254702): [] __do_softirq+0x10/0x18 [117.005047] softirqs last disabled at (2254725): [] __irq_exit_rcu+0x13f/0x160 [117.005051] ---[ end trace 0000000000000000 ]--- Make the timer IRQ safe. [1] https://patchwork.freedesktop.org/series/154987/#rev2 Fixes: 4077798484459 ("drm/vgem: Attach sw fences to exported vGEM dma-buf (ioctl)") Signed-off-by: Janusz Krzysztofik Reviewed-by: Christian König Link: https://lore.kernel.org/r/20250926152628.2165080-2-janusz.krzysztofik@linux.intel.com Signed-off-by: Maarten Lankhorst Signed-off-by: Sasha Levin --- drivers/gpu/drm/vgem/vgem_fence.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/vgem/vgem_fence.c b/drivers/gpu/drm/vgem/vgem_fence.c index fd76730fd38c0..07db319c3d7f9 100644 --- a/drivers/gpu/drm/vgem/vgem_fence.c +++ b/drivers/gpu/drm/vgem/vgem_fence.c @@ -79,7 +79,7 @@ static struct dma_fence *vgem_fence_create(struct vgem_file *vfile, dma_fence_init(&fence->base, &vgem_fence_ops, &fence->lock, dma_fence_context_alloc(1), 1); - timer_setup(&fence->timer, vgem_fence_timeout, 0); + timer_setup(&fence->timer, vgem_fence_timeout, TIMER_IRQSAFE); /* We force the fence to expire within 10s to prevent driver hangs */ mod_timer(&fence->timer, jiffies + VGEM_FENCE_TIMEOUT); From 20798610f0e2c91a8deccda8c3b597269af72557 Mon Sep 17 00:00:00 2001 From: Siddharth Chintamaneni Date: Wed, 1 Oct 2025 17:27:02 +0000 Subject: [PATCH 0399/2333] bpf: Cleanup unused func args in rqspinlock implementation [ Upstream commit 56b4d162392dda2365fbc1f482184a24b489d07d ] cleanup unused function args in check_deadlock* functions. Fixes: 31158ad02ddb ("rqspinlock: Add deadlock detection and recovery") Signed-off-by: Siddharth Chintamaneni Reviewed-by: Eduard Zingerman Acked-by: Kumar Kartikeya Dwivedi Link: https://lore.kernel.org/r/20251001172702.122838-1-sidchintamaneni@gmail.com Signed-off-by: Alexei Starovoitov Signed-off-by: Sasha Levin --- kernel/bpf/rqspinlock.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/kernel/bpf/rqspinlock.c b/kernel/bpf/rqspinlock.c index a00561b1d3e51..21be48108e962 100644 --- a/kernel/bpf/rqspinlock.c +++ b/kernel/bpf/rqspinlock.c @@ -89,15 +89,14 @@ struct rqspinlock_timeout { DEFINE_PER_CPU_ALIGNED(struct rqspinlock_held, rqspinlock_held_locks); EXPORT_SYMBOL_GPL(rqspinlock_held_locks); -static bool is_lock_released(rqspinlock_t *lock, u32 mask, struct rqspinlock_timeout *ts) +static bool is_lock_released(rqspinlock_t *lock, u32 mask) { if (!(atomic_read_acquire(&lock->val) & (mask))) return true; return false; } -static noinline int check_deadlock_AA(rqspinlock_t *lock, u32 mask, - struct rqspinlock_timeout *ts) +static noinline int check_deadlock_AA(rqspinlock_t *lock) { struct rqspinlock_held *rqh = this_cpu_ptr(&rqspinlock_held_locks); int cnt = min(RES_NR_HELD, rqh->cnt); @@ -118,8 +117,7 @@ static noinline int check_deadlock_AA(rqspinlock_t *lock, u32 mask, * more locks, which reduce to ABBA). This is not exhaustive, and we rely on * timeouts as the final line of defense. */ -static noinline int check_deadlock_ABBA(rqspinlock_t *lock, u32 mask, - struct rqspinlock_timeout *ts) +static noinline int check_deadlock_ABBA(rqspinlock_t *lock, u32 mask) { struct rqspinlock_held *rqh = this_cpu_ptr(&rqspinlock_held_locks); int rqh_cnt = min(RES_NR_HELD, rqh->cnt); @@ -142,7 +140,7 @@ static noinline int check_deadlock_ABBA(rqspinlock_t *lock, u32 mask, * Let's ensure to break out of this loop if the lock is available for * us to potentially acquire. */ - if (is_lock_released(lock, mask, ts)) + if (is_lock_released(lock, mask)) return 0; /* @@ -198,15 +196,14 @@ static noinline int check_deadlock_ABBA(rqspinlock_t *lock, u32 mask, return 0; } -static noinline int check_deadlock(rqspinlock_t *lock, u32 mask, - struct rqspinlock_timeout *ts) +static noinline int check_deadlock(rqspinlock_t *lock, u32 mask) { int ret; - ret = check_deadlock_AA(lock, mask, ts); + ret = check_deadlock_AA(lock); if (ret) return ret; - ret = check_deadlock_ABBA(lock, mask, ts); + ret = check_deadlock_ABBA(lock, mask); if (ret) return ret; @@ -234,7 +231,7 @@ static noinline int check_timeout(rqspinlock_t *lock, u32 mask, */ if (prev + NSEC_PER_MSEC < time) { ts->cur = time; - return check_deadlock(lock, mask, ts); + return check_deadlock(lock, mask); } return 0; From d8edc163ccf59547ccdcbb09ede8f4a1afbac582 Mon Sep 17 00:00:00 2001 From: Kumar Kartikeya Dwivedi Date: Tue, 7 Oct 2025 22:03:47 +0000 Subject: [PATCH 0400/2333] bpf: Fix sleepable context for async callbacks [ Upstream commit 469d638d1520a9332cd0d034690e75e845610a51 ] Fix the BPF verifier to correctly determine the sleepable context of async callbacks based on the async primitive type rather than the arming program's context. The bug is in in_sleepable() which uses OR logic to check if the current execution context is sleepable. When a sleepable program arms a timer callback, the callback's state correctly has in_sleepable=false, but in_sleepable() would still return true due to env->prog->sleepable being true. This incorrectly allows sleepable helpers like bpf_copy_from_user() inside timer callbacks when armed from sleepable programs, even though timer callbacks always execute in non-sleepable context. Fix in_sleepable() to rely solely on env->cur_state->in_sleepable, and initialize state->in_sleepable to env->prog->sleepable in do_check_common() for the main program entry. This ensures the sleepable context is properly tracked per verification state rather than being overridden by the program's sleepability. The env->cur_state NULL check in in_sleepable() was only needed for do_misc_fixups() which runs after verification when env->cur_state is set to NULL. Update do_misc_fixups() to use env->prog->sleepable directly for the storage_get_function check, and remove the redundant NULL check from in_sleepable(). Introduce is_async_cb_sleepable() helper to explicitly determine async callback sleepability based on the primitive type: - bpf_timer callbacks are never sleepable - bpf_wq and bpf_task_work callbacks are always sleepable Add verifier_bug() check to catch unhandled async callback types, ensuring future additions cannot be silently mishandled. Move the is_task_work_add_kfunc() forward declaration to the top alongside other callback-related helpers. We update push_async_cb() to adjust to the new changes. At the same time, while simplifying in_sleepable(), we notice a problem in do_misc_fixups. Fix storage_get helpers to use GFP_ATOMIC when called from non-sleepable contexts within sleepable programs, such as bpf_timer callbacks. Currently, the check in do_misc_fixups assumes that env->prog->sleepable, previously in_sleepable(env) which only resolved to this check before last commit, holds across the program's execution, but that is not true. Instead, the func_atomic bit must be set whenever we see the function being called in an atomic context. Previously, this is being done when the helper is invoked in atomic contexts in sleepable programs, we can simply just set the value to true without doing an in_sleepable() check. We must also do a standalone in_sleepable() check to handle cases where the async callback itself is armed from a sleepable program, but is itself non-sleepable (e.g., timer callback) and invokes such a helper, thus needing the func_atomic bit to be true for the said call. Adjust do_misc_fixups() to drop any checks regarding sleepable nature of the program, and just depend on the func_atomic bit to decide which GFP flag to pass. Fixes: 81f1d7a583fa ("bpf: wq: add bpf_wq_set_callback_impl") Fixes: b00fa38a9c1c ("bpf: Enable non-atomic allocations in local storage") Acked-by: Eduard Zingerman Signed-off-by: Kumar Kartikeya Dwivedi Link: https://lore.kernel.org/r/20251007220349.3852807-2-memxor@gmail.com Signed-off-by: Alexei Starovoitov Signed-off-by: Sasha Levin --- kernel/bpf/verifier.c | 41 ++++++++++++++++++++++++++++++----------- 1 file changed, 30 insertions(+), 11 deletions(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index fbe4bb91c564a..460107b0449fe 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -515,6 +515,7 @@ static bool is_callback_calling_kfunc(u32 btf_id); static bool is_bpf_throw_kfunc(struct bpf_insn *insn); static bool is_bpf_wq_set_callback_impl_kfunc(u32 btf_id); +static bool is_task_work_add_kfunc(u32 func_id); static bool is_sync_callback_calling_function(enum bpf_func_id func_id) { @@ -547,6 +548,21 @@ static bool is_async_callback_calling_insn(struct bpf_insn *insn) (bpf_pseudo_kfunc_call(insn) && is_async_callback_calling_kfunc(insn->imm)); } +static bool is_async_cb_sleepable(struct bpf_verifier_env *env, struct bpf_insn *insn) +{ + /* bpf_timer callbacks are never sleepable. */ + if (bpf_helper_call(insn) && insn->imm == BPF_FUNC_timer_set_callback) + return false; + + /* bpf_wq and bpf_task_work callbacks are always sleepable. */ + if (bpf_pseudo_kfunc_call(insn) && insn->off == 0 && + (is_bpf_wq_set_callback_impl_kfunc(insn->imm) || is_task_work_add_kfunc(insn->imm))) + return true; + + verifier_bug(env, "unhandled async callback in is_async_cb_sleepable"); + return false; +} + static bool is_may_goto_insn(struct bpf_insn *insn) { return insn->code == (BPF_JMP | BPF_JCOND) && insn->src_reg == BPF_MAY_GOTO; @@ -5826,8 +5842,7 @@ static int map_kptr_match_type(struct bpf_verifier_env *env, static bool in_sleepable(struct bpf_verifier_env *env) { - return env->prog->sleepable || - (env->cur_state && env->cur_state->in_sleepable); + return env->cur_state->in_sleepable; } /* The non-sleepable programs and sleepable programs with explicit bpf_rcu_read_lock() @@ -10368,8 +10383,6 @@ typedef int (*set_callee_state_fn)(struct bpf_verifier_env *env, struct bpf_func_state *callee, int insn_idx); -static bool is_task_work_add_kfunc(u32 func_id); - static int set_callee_state(struct bpf_verifier_env *env, struct bpf_func_state *caller, struct bpf_func_state *callee, int insn_idx); @@ -10588,8 +10601,7 @@ static int push_callback_call(struct bpf_verifier_env *env, struct bpf_insn *ins env->subprog_info[subprog].is_async_cb = true; async_cb = push_async_cb(env, env->subprog_info[subprog].start, insn_idx, subprog, - is_bpf_wq_set_callback_impl_kfunc(insn->imm) || - is_task_work_add_kfunc(insn->imm)); + is_async_cb_sleepable(env, insn)); if (!async_cb) return -EFAULT; callee = async_cb->frame[0]; @@ -11428,7 +11440,7 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn return -EINVAL; } - if (in_sleepable(env) && is_storage_get_function(func_id)) + if (is_storage_get_function(func_id)) env->insn_aux_data[insn_idx].storage_get_func_atomic = true; } @@ -11439,7 +11451,7 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn return -EINVAL; } - if (in_sleepable(env) && is_storage_get_function(func_id)) + if (is_storage_get_function(func_id)) env->insn_aux_data[insn_idx].storage_get_func_atomic = true; } @@ -11450,10 +11462,17 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn return -EINVAL; } - if (in_sleepable(env) && is_storage_get_function(func_id)) + if (is_storage_get_function(func_id)) env->insn_aux_data[insn_idx].storage_get_func_atomic = true; } + /* + * Non-sleepable contexts in sleepable programs (e.g., timer callbacks) + * are atomic and must use GFP_ATOMIC for storage_get helpers. + */ + if (!in_sleepable(env) && is_storage_get_function(func_id)) + env->insn_aux_data[insn_idx].storage_get_func_atomic = true; + meta.func_id = func_id; /* check args */ for (i = 0; i < MAX_BPF_FUNC_REG_ARGS; i++) { @@ -22485,8 +22504,7 @@ static int do_misc_fixups(struct bpf_verifier_env *env) } if (is_storage_get_function(insn->imm)) { - if (!in_sleepable(env) || - env->insn_aux_data[i + delta].storage_get_func_atomic) + if (env->insn_aux_data[i + delta].storage_get_func_atomic) insn_buf[0] = BPF_MOV64_IMM(BPF_REG_5, (__force __s32)GFP_ATOMIC); else insn_buf[0] = BPF_MOV64_IMM(BPF_REG_5, (__force __s32)GFP_KERNEL); @@ -23156,6 +23174,7 @@ static int do_check_common(struct bpf_verifier_env *env, int subprog) state->curframe = 0; state->speculative = false; state->branches = 1; + state->in_sleepable = env->prog->sleepable; state->frame[0] = kzalloc(sizeof(struct bpf_func_state), GFP_KERNEL_ACCOUNT); if (!state->frame[0]) { kfree(state); From 19e359b18ae346d444f882eeb30733fed8f04484 Mon Sep 17 00:00:00 2001 From: Mykyta Yatsenko Date: Fri, 10 Oct 2025 17:46:04 +0100 Subject: [PATCH 0401/2333] bpf: Fix handling maps with no BTF and non-constant offsets for the bpf_wq [ Upstream commit 5f8d41172931a92339c5cce81a3142065fa56e45 ] Fix handling maps with no BTF and non-constant offsets for the bpf_wq. This de-duplicates logic with other internal structs (task_work, timer), keeps error reporting consistent, and makes future changes to the layout handling centralized. Fixes: d940c9b94d7e ("bpf: add support for KF_ARG_PTR_TO_WORKQUEUE") Signed-off-by: Mykyta Yatsenko Acked-by: Andrii Nakryiko Acked-by: Eduard Zingerman Link: https://lore.kernel.org/r/20251010164606.147298-1-mykyta.yatsenko5@gmail.com Signed-off-by: Alexei Starovoitov Signed-off-by: Sasha Levin --- kernel/bpf/verifier.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 460107b0449fe..52c01c011c6fb 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -8479,6 +8479,9 @@ static int check_map_field_pointer(struct bpf_verifier_env *env, u32 regno, case BPF_TASK_WORK: field_off = map->record->task_work_off; break; + case BPF_WORKQUEUE: + field_off = map->record->wq_off; + break; default: verifier_bug(env, "unsupported BTF field type: %s\n", struct_name); return -EINVAL; @@ -8520,13 +8523,17 @@ static int process_wq_func(struct bpf_verifier_env *env, int regno, { struct bpf_reg_state *regs = cur_regs(env), *reg = ®s[regno]; struct bpf_map *map = reg->map_ptr; - u64 val = reg->var_off.value; + int err; - if (map->record->wq_off != val + reg->off) { - verbose(env, "off %lld doesn't point to 'struct bpf_wq' that is at %d\n", - val + reg->off, map->record->wq_off); - return -EINVAL; + err = check_map_field_pointer(env, regno, BPF_WORKQUEUE); + if (err) + return err; + + if (meta->map.ptr) { + verifier_bug(env, "Two map pointers in a bpf_wq helper"); + return -EFAULT; } + meta->map.uid = reg->map_uid; meta->map.ptr = map; return 0; From e506f976c9143ed5920456f3847b102a581edbae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Fri, 26 Sep 2025 16:26:58 +0200 Subject: [PATCH 0402/2333] tools/nolibc: handle NULL wstatus argument to waitpid() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 812f223fe9be03dc22abb85240b6f075135d2386 ] wstatus is allowed to be NULL. Avoid a segmentation fault in this case. Fixes: 0c89abf5ab3f ("tools/nolibc: implement waitpid() in terms of waitid()") Signed-off-by: Thomas Weißschuh Acked-by: Willy Tarreau Signed-off-by: Thomas Weißschuh Signed-off-by: Sasha Levin --- tools/include/nolibc/sys/wait.h | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/tools/include/nolibc/sys/wait.h b/tools/include/nolibc/sys/wait.h index 4e66e1f7a03e4..9d9319ba92cbd 100644 --- a/tools/include/nolibc/sys/wait.h +++ b/tools/include/nolibc/sys/wait.h @@ -65,23 +65,29 @@ pid_t waitpid(pid_t pid, int *status, int options) switch (info.si_code) { case 0: - *status = 0; + if (status) + *status = 0; break; case CLD_EXITED: - *status = (info.si_status & 0xff) << 8; + if (status) + *status = (info.si_status & 0xff) << 8; break; case CLD_KILLED: - *status = info.si_status & 0x7f; + if (status) + *status = info.si_status & 0x7f; break; case CLD_DUMPED: - *status = (info.si_status & 0x7f) | 0x80; + if (status) + *status = (info.si_status & 0x7f) | 0x80; break; case CLD_STOPPED: case CLD_TRAPPED: - *status = (info.si_status << 8) + 0x7f; + if (status) + *status = (info.si_status << 8) + 0x7f; break; case CLD_CONTINUED: - *status = 0xffff; + if (status) + *status = 0xffff; break; default: return -1; From caceff35c24ad8daad32cc96294d65a4c5bb1b8d Mon Sep 17 00:00:00 2001 From: Seungjin Bae Date: Sun, 28 Sep 2025 14:56:11 -0400 Subject: [PATCH 0403/2333] USB: Fix descriptor count when handling invalid MBIM extended descriptor [ Upstream commit 5570ad1423ee60f6e972dadb63fb2e5f90a54cbe ] In cdc_parse_cdc_header(), the check for the USB_CDC_MBIM_EXTENDED_TYPE descriptor was using 'break' upon detecting an invalid length. This was incorrect because 'break' only exits the switch statement, causing the code to fall through to cnt++, thus incorrectly incrementing the count of parsed descriptors for a descriptor that was actually invalid and being discarded. This patch changes 'break' to 'goto next_desc;' to ensure that the logic skips the counter increment and correctly proceeds to the next descriptor in the buffer. This maintains an accurate count of only the successfully parsed descriptors. Fixes: e4c6fb7794982 ("usbnet: move the CDC parser into USB core") Signed-off-by: Seungjin Bae Link: https://lore.kernel.org/r/20250928185611.764589-1-eeodqql09@gmail.com Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin --- drivers/usb/core/message.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index d2b2787be4092..6138468c67c47 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -2431,7 +2431,7 @@ int cdc_parse_cdc_header(struct usb_cdc_parsed_header *hdr, break; case USB_CDC_MBIM_EXTENDED_TYPE: if (elength < sizeof(struct usb_cdc_mbim_extended_desc)) - break; + goto next_desc; hdr->usb_cdc_mbim_extended_desc = (struct usb_cdc_mbim_extended_desc *)buffer; break; From b5b479a13b90a1684f54835e61617d9e1f2f312d Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 9 Oct 2025 06:29:11 -0700 Subject: [PATCH 0404/2333] perf bpf_counter: Fix opening of "any"(-1) CPU events [ Upstream commit 2a67955de13624ec17d1c2504d2c9eeb37933b77 ] The bperf BPF counter code doesn't handle "any"(-1) CPU events, always wanting to aggregate a count against a CPU, which avoids the need for atomics so let's not change that. Force evsels used for BPF counters to require a CPU when not in system-wide mode so that the "any"(-1) value isn't used during map propagation and evsel's CPU map matches that of the PMU. Fixes: b91917c0c6fa ("perf bpf_counter: Fix handling of cpumap fixing hybrid") Signed-off-by: Ian Rogers Signed-off-by: Namhyung Kim Signed-off-by: Sasha Levin --- tools/perf/builtin-stat.c | 13 +++++++++++++ tools/perf/util/bpf_counter.c | 7 ++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 7006f848f87a6..f1c9d6c94fc50 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -2540,6 +2540,7 @@ int cmd_stat(int argc, const char **argv) unsigned int interval, timeout; const char * const stat_subcommands[] = { "record", "report" }; char errbuf[BUFSIZ]; + struct evsel *counter; setlocale(LC_ALL, ""); @@ -2797,6 +2798,18 @@ int cmd_stat(int argc, const char **argv) evlist__warn_user_requested_cpus(evsel_list, target.cpu_list); + evlist__for_each_entry(evsel_list, counter) { + /* + * Setup BPF counters to require CPUs as any(-1) isn't + * supported. evlist__create_maps below will propagate this + * information to the evsels. Note, evsel__is_bperf isn't yet + * set up, and this change must happen early, so directly use + * the bpf_counter variable and target information. + */ + if ((counter->bpf_counter || target.use_bpf) && !target__has_cpu(&target)) + counter->core.requires_cpu = true; + } + if (evlist__create_maps(evsel_list, &target) < 0) { if (target__has_task(&target)) { pr_err("Problems finding threads of monitor\n"); diff --git a/tools/perf/util/bpf_counter.c b/tools/perf/util/bpf_counter.c index ca5d01b9017db..a5882b5822057 100644 --- a/tools/perf/util/bpf_counter.c +++ b/tools/perf/util/bpf_counter.c @@ -460,6 +460,7 @@ static int bperf_reload_leader_program(struct evsel *evsel, int attr_map_fd, struct bperf_leader_bpf *skel = bperf_leader_bpf__open(); int link_fd, diff_map_fd, err; struct bpf_link *link = NULL; + struct perf_thread_map *threads; if (!skel) { pr_err("Failed to open leader skeleton\n"); @@ -495,7 +496,11 @@ static int bperf_reload_leader_program(struct evsel *evsel, int attr_map_fd, * following evsel__open_per_cpu call */ evsel->leader_skel = skel; - evsel__open(evsel, evsel->core.cpus, evsel->core.threads); + assert(!perf_cpu_map__has_any_cpu_or_is_empty(evsel->core.cpus)); + /* Always open system wide. */ + threads = thread_map__new_by_tid(-1); + evsel__open(evsel, evsel->core.cpus, threads); + perf_thread_map__put(threads); out: bperf_leader_bpf__destroy(skel); From 0c1e8e2c6e0687647321bf2194c102ecead26b48 Mon Sep 17 00:00:00 2001 From: Abel Vesa Date: Fri, 19 Sep 2025 15:17:11 +0300 Subject: [PATCH 0405/2333] pinctrl: qcom: glymur: Drop unnecessary platform data from match table [ Upstream commit 37e7b536061a33c8f27030e3ffc5a717a6c319e3 ] The platform specific configuration is already passed on to the generic msm probe. So it's useless to exist in the match table next to the compatible. So drop it from match table. Fixes: 87ebcd8baebf ("pinctrl: qcom: Add glymur pinctrl driver") Signed-off-by: Abel Vesa Reviewed-by: Dmitry Baryshkov Signed-off-by: Linus Walleij Signed-off-by: Sasha Levin --- drivers/pinctrl/qcom/pinctrl-glymur.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pinctrl/qcom/pinctrl-glymur.c b/drivers/pinctrl/qcom/pinctrl-glymur.c index 9913f98e95311..9781e7fcb3a11 100644 --- a/drivers/pinctrl/qcom/pinctrl-glymur.c +++ b/drivers/pinctrl/qcom/pinctrl-glymur.c @@ -1743,7 +1743,7 @@ static const struct msm_pinctrl_soc_data glymur_tlmm = { }; static const struct of_device_id glymur_tlmm_of_match[] = { - { .compatible = "qcom,glymur-tlmm", .data = &glymur_tlmm }, + { .compatible = "qcom,glymur-tlmm", }, { } }; From e558173196b0e9d4fbff8832c4debad3d5bad6ad Mon Sep 17 00:00:00 2001 From: Abel Vesa Date: Fri, 19 Sep 2025 15:17:12 +0300 Subject: [PATCH 0406/2333] pinctrl: qcom: glymur: Fix the gpio and egpio pin functions [ Upstream commit e73fda2dcb0bad6650e654556c5242b773707257 ] Mark the gpio/egpio as GPIO specific pin functions, othewise the pin muxing generic framework will complain about the gpio being already requested by a different owner. Fixes: 87ebcd8baebf ("pinctrl: qcom: Add glymur pinctrl driver") Signed-off-by: Abel Vesa Reviewed-by: Bartosz Golaszewski Reviewed-by: Dmitry Baryshkov Signed-off-by: Linus Walleij Signed-off-by: Sasha Levin --- drivers/pinctrl/qcom/pinctrl-glymur.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/pinctrl/qcom/pinctrl-glymur.c b/drivers/pinctrl/qcom/pinctrl-glymur.c index 9781e7fcb3a11..335005084b6bc 100644 --- a/drivers/pinctrl/qcom/pinctrl-glymur.c +++ b/drivers/pinctrl/qcom/pinctrl-glymur.c @@ -1316,7 +1316,7 @@ static const char *const wcn_sw_ctrl_groups[] = { }; static const struct pinfunction glymur_functions[] = { - MSM_PIN_FUNCTION(gpio), + MSM_GPIO_PIN_FUNCTION(gpio), MSM_PIN_FUNCTION(resout_gpio_n), MSM_PIN_FUNCTION(aoss_cti), MSM_PIN_FUNCTION(asc_cci), @@ -1342,7 +1342,7 @@ static const struct pinfunction glymur_functions[] = { MSM_PIN_FUNCTION(edp0_hot), MSM_PIN_FUNCTION(edp0_lcd), MSM_PIN_FUNCTION(edp1_lcd), - MSM_PIN_FUNCTION(egpio), + MSM_GPIO_PIN_FUNCTION(egpio), MSM_PIN_FUNCTION(eusb_ac_en), MSM_PIN_FUNCTION(gcc_gp1), MSM_PIN_FUNCTION(gcc_gp2), From d07b4af12015cc136f2795bb88ef4d7b869aa9d1 Mon Sep 17 00:00:00 2001 From: Roberto Sassu Date: Wed, 8 Oct 2025 13:35:03 +0200 Subject: [PATCH 0407/2333] ima: Attach CREDS_CHECK IMA hook to bprm_creds_from_file LSM hook [ Upstream commit 8f3fc4f3f8aa6e99266c69cc78bdaa58379e65fc ] Since commit 56305aa9b6fa ("exec: Compute file based creds only once"), the credentials to be applied to the process after execution are not calculated anymore for each step of finding intermediate interpreters (including the final binary), but only after the final binary to be executed without interpreter has been found. In particular, that means that the bprm_check_security LSM hook will not see the updated cred->e[ug]id for the intermediate and for the final binary to be executed, since the function doing this task has been moved from prepare_binprm(), which calls the bprm_check_security hook, to bprm_creds_from_file(). This breaks the IMA expectation for the CREDS_CHECK hook, introduced with commit d906c10d8a31 ("IMA: Support using new creds in appraisal policy"), which expects to evaluate "the credentials that will be committed when the new process is started". This is clearly not the case for the CREDS_CHECK IMA hook, which is attached to bprm_check_security. This issue does not affect systems which load a policy with the BPRM_CHECK hook with no other criteria, as is the case with the built-in "tcb" and/or "appraise_tcb" IMA policies. The "tcb" built-in policy measures all executions regardless of the new credentials, and the "appraise_tcb" policy is written in terms of the file owner, rather than IMA hooks. However, it does affect systems without a BPRM_CHECK policy rule or with a BPRM_CHECK policy rule that does not include what CREDS_CHECK evaluates. As an extreme example, taking a standalone rule like: measure func=CREDS_CHECK euid=0 This will not measure for example sudo (because CREDS_CHECK still sees the bprm->cred->euid set to the regular user UID), but only the subsequent commands after the euid was applied to the children. Make set[ug]id programs measured/appraised again by splitting ima_bprm_check() in two separate hook implementations (CREDS_CHECK now being implemented by ima_creds_check()), and by attaching CREDS_CHECK to the bprm_creds_from_file LSM hook. The limitation of this approach is that CREDS_CHECK will not be invoked anymore for the intermediate interpreters, like it was before, but only for the final binary. This limitation can be removed only by reverting commit 56305aa9b6fa ("exec: Compute file based creds only once"). Link: https://github.com/linux-integrity/linux/issues/3 Fixes: 56305aa9b6fa ("exec: Compute file based creds only once") Cc: Serge E. Hallyn Cc: Matthew Garrett Cc: Eric W. Biederman Cc: Jann Horn Cc: Christian Brauner Cc: Kees Cook Signed-off-by: Roberto Sassu Signed-off-by: Mimi Zohar Signed-off-by: Sasha Levin --- security/integrity/ima/ima_main.c | 42 ++++++++++++++++++++++++------- 1 file changed, 33 insertions(+), 9 deletions(-) diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index cdd225f65a629..ebaebccfbe9ab 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c @@ -573,18 +573,41 @@ static int ima_file_mprotect(struct vm_area_struct *vma, unsigned long reqprot, */ static int ima_bprm_check(struct linux_binprm *bprm) { - int ret; struct lsm_prop prop; security_current_getlsmprop_subj(&prop); - ret = process_measurement(bprm->file, current_cred(), - &prop, NULL, 0, MAY_EXEC, BPRM_CHECK); - if (ret) - return ret; - - security_cred_getlsmprop(bprm->cred, &prop); - return process_measurement(bprm->file, bprm->cred, &prop, NULL, 0, - MAY_EXEC, CREDS_CHECK); + return process_measurement(bprm->file, current_cred(), + &prop, NULL, 0, MAY_EXEC, BPRM_CHECK); +} + +/** + * ima_creds_check - based on policy, collect/store measurement. + * @bprm: contains the linux_binprm structure + * @file: contains the file descriptor of the binary being executed + * + * The OS protects against an executable file, already open for write, + * from being executed in deny_write_access() and an executable file, + * already open for execute, from being modified in get_write_access(). + * So we can be certain that what we verify and measure here is actually + * what is being executed. + * + * The difference from ima_bprm_check() is that ima_creds_check() is invoked + * only after determining the final binary to be executed without interpreter, + * and not when searching for intermediate binaries. The reason is that since + * commit 56305aa9b6fab ("exec: Compute file based creds only once"), the + * credentials to be applied to the process are calculated only at that stage + * (bprm_creds_from_file security hook instead of bprm_check_security). + * + * On success return 0. On integrity appraisal error, assuming the file + * is in policy and IMA-appraisal is in enforcing mode, return -EACCES. + */ +static int ima_creds_check(struct linux_binprm *bprm, const struct file *file) +{ + struct lsm_prop prop; + + security_current_getlsmprop_subj(&prop); + return process_measurement((struct file *)file, bprm->cred, &prop, NULL, + 0, MAY_EXEC, CREDS_CHECK); } /** @@ -1242,6 +1265,7 @@ static int __init init_ima(void) static struct security_hook_list ima_hooks[] __ro_after_init = { LSM_HOOK_INIT(bprm_check_security, ima_bprm_check), LSM_HOOK_INIT(bprm_creds_for_exec, ima_bprm_creds_for_exec), + LSM_HOOK_INIT(bprm_creds_from_file, ima_creds_check), LSM_HOOK_INIT(file_post_open, ima_file_check), LSM_HOOK_INIT(inode_post_create_tmpfile, ima_post_create_tmpfile), LSM_HOOK_INIT(file_release, ima_file_free), From 1d49bdea86e3f84c9eef15d296ad2eec333d8295 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Sun, 21 Sep 2025 12:15:52 +0100 Subject: [PATCH 0408/2333] pinctrl: renesas: rzg2l: Fix PMC restore [ Upstream commit cea950101108b7bfffe26ec4007b8e263a4b56a8 ] PMC restore needs unlocking the register using the PWPR register. Fixes: ede014cd1ea6422d ("pinctrl: renesas: rzg2l: Add function pointer for PMC register write") Signed-off-by: Biju Das Reviewed-by: Geert Uytterhoeven Link: https://patch.msgid.link/20250921111557.103069-2-biju.das.jz@bp.renesas.com Signed-off-by: Geert Uytterhoeven Signed-off-by: Sasha Levin --- drivers/pinctrl/renesas/pinctrl-rzg2l.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/pinctrl/renesas/pinctrl-rzg2l.c b/drivers/pinctrl/renesas/pinctrl-rzg2l.c index f524af6f586f4..94cb77949f595 100644 --- a/drivers/pinctrl/renesas/pinctrl-rzg2l.c +++ b/drivers/pinctrl/renesas/pinctrl-rzg2l.c @@ -2993,7 +2993,11 @@ static void rzg2l_pinctrl_pm_setup_regs(struct rzg2l_pinctrl *pctrl, bool suspen * Now cache the registers or set them in the order suggested by * HW manual (section "Operation for GPIO Function"). */ - RZG2L_PCTRL_REG_ACCESS8(suspend, pctrl->base + PMC(off), cache->pmc[port]); + if (suspend) + RZG2L_PCTRL_REG_ACCESS8(suspend, pctrl->base + PMC(off), cache->pmc[port]); + else + pctrl->data->pmc_writeb(pctrl, cache->pmc[port], PMC(off)); + if (has_iolh) { RZG2L_PCTRL_REG_ACCESS32(suspend, pctrl->base + IOLH(off), cache->iolh[0][port]); From f57b5f2ad106a9f7ab5fa4e03bb8fe978d3f31ec Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Thu, 18 Sep 2025 05:04:43 +0200 Subject: [PATCH 0409/2333] clk: renesas: cpg-mssr: Add missing 1ms delay into reset toggle callback [ Upstream commit 62abfd7bedc2b3d86d4209a4146f9d2b5ae21fab ] R-Car V4H Reference Manual R19UH0186EJ0130 Rev.1.30 Apr. 21, 2025 page 583 Figure 9.3.1(a) Software Reset flow (A) as well as flow (B) / (C) indicate after reset has been asserted by writing a matching reset bit into register SRCR, it is mandatory to wait 1ms. This 1ms delay is documented on R-Car V4H and V4M, it is currently unclear whether S4 is affected as well. This patch does apply the extra delay on R-Car S4 as well. Fix the reset driver to respect the additional delay when toggling resets. Drivers which use separate reset_control_(de)assert() must assure matching delay in their driver code. Fixes: 0ab55cf18341 ("clk: renesas: cpg-mssr: Add support for R-Car V4H") Signed-off-by: Marek Vasut Reviewed-by: Geert Uytterhoeven Link: https://patch.msgid.link/20250918030552.331389-1-marek.vasut+renesas@mailbox.org Signed-off-by: Geert Uytterhoeven Signed-off-by: Sasha Levin --- drivers/clk/renesas/renesas-cpg-mssr.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/clk/renesas/renesas-cpg-mssr.c b/drivers/clk/renesas/renesas-cpg-mssr.c index de1cf7ba45b78..7063d896249ea 100644 --- a/drivers/clk/renesas/renesas-cpg-mssr.c +++ b/drivers/clk/renesas/renesas-cpg-mssr.c @@ -689,8 +689,15 @@ static int cpg_mssr_reset(struct reset_controller_dev *rcdev, /* Reset module */ writel(bitmask, priv->pub.base0 + priv->reset_regs[reg]); - /* Wait for at least one cycle of the RCLK clock (@ ca. 32 kHz) */ - udelay(35); + /* + * On R-Car Gen4, delay after SRCR has been written is 1ms. + * On older SoCs, delay after SRCR has been written is 35us + * (one cycle of the RCLK clock @ ca. 32 kHz). + */ + if (priv->reg_layout == CLK_REG_LAYOUT_RCAR_GEN4) + usleep_range(1000, 2000); + else + usleep_range(35, 1000); /* Release module from reset state */ writel(bitmask, priv->pub.base0 + priv->reset_clear_regs[reg]); From b1c7a8145137c093e67a36cca42e7e11a25e4c23 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Mon, 22 Sep 2025 18:20:38 +0200 Subject: [PATCH 0410/2333] clk: renesas: cpg-mssr: Read back reset registers to assure values latched [ Upstream commit b91401af6c00ffab003698bfabd4c166df30748b ] On R-Car V4H, the PCIEC controller DBI read would generate an SError in case the controller reset is released by writing SRSTCLR register first, and immediately afterward reading some PCIEC controller DBI register. The issue triggers in rcar_gen4_pcie_additional_common_init() on dw_pcie_readl_dbi(dw, PCIE_PORT_LANE_SKEW), which on V4H is the first read after reset_control_deassert(dw->core_rsts[DW_PCIE_PWR_RST].rstc). The reset controller which contains the SRSTCLR register and the PCIEC controller which contains the DBI register share the same root access bus, but the bus then splits into separate segments before reaching each IP. Even if the SRSTCLR write access was posted on the bus before the DBI read access, it seems the DBI read access may reach the PCIEC controller before the SRSTCLR write completed, and trigger the SError. Mitigate the issue by adding a dummy SRSTCLR read, which assures the SRSTCLR write completes fully and is latched into the reset controller, before the PCIEC DBI read access can occur. Fixes: 0ab55cf18341 ("clk: renesas: cpg-mssr: Add support for R-Car V4H") Reviewed-by: Wolfram Sang Tested-by: Geert Uytterhoeven Signed-off-by: Marek Vasut Reviewed-by: Geert Uytterhoeven Link: https://patch.msgid.link/20250922162113.113223-1-marek.vasut+renesas@mailbox.org Signed-off-by: Geert Uytterhoeven Signed-off-by: Sasha Levin --- drivers/clk/renesas/renesas-cpg-mssr.c | 46 ++++++++++++-------------- 1 file changed, 21 insertions(+), 25 deletions(-) diff --git a/drivers/clk/renesas/renesas-cpg-mssr.c b/drivers/clk/renesas/renesas-cpg-mssr.c index 7063d896249ea..a0a68ec0490f7 100644 --- a/drivers/clk/renesas/renesas-cpg-mssr.c +++ b/drivers/clk/renesas/renesas-cpg-mssr.c @@ -676,18 +676,32 @@ static int __init cpg_mssr_add_clk_domain(struct device *dev, #define rcdev_to_priv(x) container_of(x, struct cpg_mssr_priv, rcdev) -static int cpg_mssr_reset(struct reset_controller_dev *rcdev, - unsigned long id) +static int cpg_mssr_reset_operate(struct reset_controller_dev *rcdev, + const char *func, bool set, unsigned long id) { struct cpg_mssr_priv *priv = rcdev_to_priv(rcdev); unsigned int reg = id / 32; unsigned int bit = id % 32; + const u16 off = set ? priv->reset_regs[reg] : priv->reset_clear_regs[reg]; u32 bitmask = BIT(bit); - dev_dbg(priv->dev, "reset %u%02u\n", reg, bit); + if (func) + dev_dbg(priv->dev, "%s %u%02u\n", func, reg, bit); + + writel(bitmask, priv->pub.base0 + off); + readl(priv->pub.base0 + off); + barrier_data(priv->pub.base0 + off); + + return 0; +} + +static int cpg_mssr_reset(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct cpg_mssr_priv *priv = rcdev_to_priv(rcdev); /* Reset module */ - writel(bitmask, priv->pub.base0 + priv->reset_regs[reg]); + cpg_mssr_reset_operate(rcdev, "reset", true, id); /* * On R-Car Gen4, delay after SRCR has been written is 1ms. @@ -700,36 +714,18 @@ static int cpg_mssr_reset(struct reset_controller_dev *rcdev, usleep_range(35, 1000); /* Release module from reset state */ - writel(bitmask, priv->pub.base0 + priv->reset_clear_regs[reg]); - - return 0; + return cpg_mssr_reset_operate(rcdev, NULL, false, id); } static int cpg_mssr_assert(struct reset_controller_dev *rcdev, unsigned long id) { - struct cpg_mssr_priv *priv = rcdev_to_priv(rcdev); - unsigned int reg = id / 32; - unsigned int bit = id % 32; - u32 bitmask = BIT(bit); - - dev_dbg(priv->dev, "assert %u%02u\n", reg, bit); - - writel(bitmask, priv->pub.base0 + priv->reset_regs[reg]); - return 0; + return cpg_mssr_reset_operate(rcdev, "assert", true, id); } static int cpg_mssr_deassert(struct reset_controller_dev *rcdev, unsigned long id) { - struct cpg_mssr_priv *priv = rcdev_to_priv(rcdev); - unsigned int reg = id / 32; - unsigned int bit = id % 32; - u32 bitmask = BIT(bit); - - dev_dbg(priv->dev, "deassert %u%02u\n", reg, bit); - - writel(bitmask, priv->pub.base0 + priv->reset_clear_regs[reg]); - return 0; + return cpg_mssr_reset_operate(rcdev, "deassert", false, id); } static int cpg_mssr_status(struct reset_controller_dev *rcdev, From ac35eed93429cdfe8b5ad71d167b8dd33bdcaeee Mon Sep 17 00:00:00 2001 From: Cyrille Pitchen Date: Mon, 14 Oct 2024 15:19:42 +0530 Subject: [PATCH 0411/2333] drm: atmel-hlcdc: fix atmel_xlcdc_plane_setup_scaler() [ Upstream commit a312acdcec57b3955fbf1f3057c13a6d38e4aa2a ] On SoCs, like the SAM9X75, which embed the XLCDC ip, the registers that configure the unified scaling engine were not filled with proper values. Indeed, for YCbCr formats, the VXSCFACT bitfield of the HEOCFG25 register and the HXSCFACT bitfield of the HEOCFG27 register were incorrect. For 4:2:0 formats, both vertical and horizontal factors for chroma chanels should be divided by 2 from the factors for the luma channel. Hence: HEOCFG24.VXSYFACT = VFACTOR HEOCFG25.VSXCFACT = VFACTOR / 2 HEOCFG26.HXSYFACT = HFACTOR HEOCFG27.HXSCFACT = HFACTOR / 2 However, for 4:2:2 formats, only the horizontal factor for chroma chanels should be divided by 2 from the factor for the luma channel; the vertical factor is the same for all the luma and chroma channels. Hence: HEOCFG24.VXSYFACT = VFACTOR HEOCFG25.VXSCFACT = VFACTOR HEOCFG26.HXSYFACT = HFACTOR HEOCFG27.HXSCFACT = HFACTOR / 2 Fixes: d498771b0b83 ("drm: atmel_hlcdc: Add support for XLCDC using IP specific driver ops") Signed-off-by: Cyrille Pitchen Reviewed-by: Dmitry Baryshkov Acked-by: Nicolas Ferre Link: https://lore.kernel.org/r/20241014094942.325211-1-manikandan.m@microchip.com Signed-off-by: Manikandan Muralidharan Signed-off-by: Sasha Levin --- .../gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c | 27 ++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c index 4a7ba0918eca1..3787db014501e 100644 --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c @@ -365,13 +365,34 @@ void atmel_xlcdc_plane_setup_scaler(struct atmel_hlcdc_plane *plane, xfactor); /* - * With YCbCr 4:2:2 and YCbYcr 4:2:0 window resampling, configuration - * register LCDC_HEOCFG25.VXSCFACT and LCDC_HEOCFG27.HXSCFACT is half + * With YCbCr 4:2:0 window resampling, configuration register + * LCDC_HEOCFG25.VXSCFACT and LCDC_HEOCFG27.HXSCFACT values are half * the value of yfactor and xfactor. + * + * On the other hand, with YCbCr 4:2:2 window resampling, only the + * configuration register LCDC_HEOCFG27.HXSCFACT value is half the value + * of the xfactor; the value of LCDC_HEOCFG25.VXSCFACT is yfactor (no + * division by 2). */ - if (state->base.fb->format->format == DRM_FORMAT_YUV420) { + switch (state->base.fb->format->format) { + /* YCbCr 4:2:2 */ + case DRM_FORMAT_YUYV: + case DRM_FORMAT_UYVY: + case DRM_FORMAT_YVYU: + case DRM_FORMAT_VYUY: + case DRM_FORMAT_YUV422: + case DRM_FORMAT_NV61: + xfactor /= 2; + break; + + /* YCbCr 4:2:0 */ + case DRM_FORMAT_YUV420: + case DRM_FORMAT_NV21: yfactor /= 2; xfactor /= 2; + break; + default: + break; } atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.scaler_config + 2, From 4e02cff54ba0a45db8d1a9d472cfcb321bfb017b Mon Sep 17 00:00:00 2001 From: Mavroudis Chatzilazaridis Date: Thu, 2 Oct 2025 19:30:58 +0000 Subject: [PATCH 0412/2333] HID: logitech-hidpp: Do not assume FAP in hidpp_send_message_sync() [ Upstream commit aba7963544d47d82cdf36602a6678a093af0299d ] Currently, hidpp_send_message_sync() retries sending the message when the device returns a busy error code, specifically HIDPP20_ERROR_BUSY, which has a different meaning under RAP. This ends up being a problem because this function is used for both FAP and RAP messages. This issue is not noticeable on older receivers with unreachable devices since they return HIDPP_ERROR_RESOURCE_ERROR (0x09), which is not equal to HIDPP20_ERROR_BUSY (0x08). However, newer receivers return HIDPP_ERROR_UNKNOWN_DEVICE (0x08) which happens to equal to HIDPP20_ERROR_BUSY, causing unnecessary retries when the device is not actually busy. This is resolved by checking if the error response is FAP or RAP and picking the respective ERROR_BUSY code. Fixes: 60165ab774cb ("HID: logitech-hidpp: rework one more time the retries attempts") Signed-off-by: Mavroudis Chatzilazaridis Tested-by: Stuart Hayhurst Signed-off-by: Jiri Kosina Signed-off-by: Sasha Levin --- drivers/hid/hid-logitech-hidpp.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c index 5e763de4b94fd..a88f2e5f791c6 100644 --- a/drivers/hid/hid-logitech-hidpp.c +++ b/drivers/hid/hid-logitech-hidpp.c @@ -352,10 +352,15 @@ static int hidpp_send_message_sync(struct hidpp_device *hidpp, do { ret = __do_hidpp_send_message_sync(hidpp, message, response); - if (ret != HIDPP20_ERROR_BUSY) + if (response->report_id == REPORT_ID_HIDPP_SHORT && + ret != HIDPP_ERROR_BUSY) + break; + if ((response->report_id == REPORT_ID_HIDPP_LONG || + response->report_id == REPORT_ID_HIDPP_VERY_LONG) && + ret != HIDPP20_ERROR_BUSY) break; - dbg_hid("%s:got busy hidpp 2.0 error %02X, retrying\n", __func__, ret); + dbg_hid("%s:got busy hidpp error %02X, retrying\n", __func__, ret); } while (--max_retries); mutex_unlock(&hidpp->send_mutex); From 80b75beb1619a0015553057ab517a019c9721d83 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Fri, 26 Sep 2025 20:33:15 +0800 Subject: [PATCH 0413/2333] remoteproc: imx_rproc: Fix runtime PM cleanup and improve remove path [ Upstream commit 80405a34e1f8975cdb2d7d8679bca7f768861035 ] Proper cleanup should be done when rproc_add() fails by invoking both pm_runtime_disable() and pm_runtime_put_noidle() to avoid leaving the device in an inconsistent power state. Fix it by adding pm_runtime_put_noidle() and pm_runtime_disable() in the error path. Also Update the remove() callback to use pm_runtime_put_noidle() instead of pm_runtime_put(), to clearly indicate that only need to restore the usage count. Fixes: a876a3aacc43 ("remoteproc: imx_rproc: detect and attach to pre-booted remote cores") Cc: Ulf Hansson Cc: Hiago De Franco Suggested-by: Ulf Hansson Signed-off-by: Peng Fan Reviewed-by: Ulf Hansson Link: https://lore.kernel.org/r/20250926-imx_rproc_v3-v3-1-4c0ec279cc5f@nxp.com Signed-off-by: Mathieu Poirier Signed-off-by: Sasha Levin --- drivers/remoteproc/imx_rproc.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c index bb25221a4a898..8424e6ea5569b 100644 --- a/drivers/remoteproc/imx_rproc.c +++ b/drivers/remoteproc/imx_rproc.c @@ -1136,11 +1136,16 @@ static int imx_rproc_probe(struct platform_device *pdev) ret = rproc_add(rproc); if (ret) { dev_err(dev, "rproc_add failed\n"); - goto err_put_clk; + goto err_put_pm; } return 0; +err_put_pm: + if (dcfg->method == IMX_RPROC_SCU_API) { + pm_runtime_disable(dev); + pm_runtime_put_noidle(dev); + } err_put_clk: clk_disable_unprepare(priv->clk); err_put_scu: @@ -1160,7 +1165,7 @@ static void imx_rproc_remove(struct platform_device *pdev) if (priv->dcfg->method == IMX_RPROC_SCU_API) { pm_runtime_disable(priv->dev); - pm_runtime_put(priv->dev); + pm_runtime_put_noidle(priv->dev); } clk_disable_unprepare(priv->clk); rproc_del(rproc); From bee781b8c03ed5db1a8c0f471afa991138fe5f5c Mon Sep 17 00:00:00 2001 From: Dylan Hatch Date: Tue, 23 Sep 2025 00:49:41 +0000 Subject: [PATCH 0414/2333] objtool: Fix standalone --hacks=jump_label [ Upstream commit be8374a5ba7cbab6b97df94b4ffe0b92f5c8a6d2 ] The objtool command line 'objtool --hacks=jump_label foo.o' on its own should be expected to rewrite jump labels to NOPs. This means the add_special_section_alts() code path needs to run when only this option is provided. This is mainly relevant in certain debugging situations, but could potentially also fix kernel builds in which objtool is run with --hacks=jump_label but without --orc, --stackval, --uaccess, or --hacks=noinstr. Fixes: de6fbcedf5ab ("objtool: Read special sections with alts only when specific options are selected") Signed-off-by: Dylan Hatch Signed-off-by: Josh Poimboeuf Signed-off-by: Sasha Levin --- tools/objtool/check.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/objtool/check.c b/tools/objtool/check.c index 9004fbc067693..6059a546fb759 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -2564,7 +2564,8 @@ static int decode_sections(struct objtool_file *file) * Must be before add_jump_destinations(), which depends on 'func' * being set for alternatives, to enable proper sibling call detection. */ - if (opts.stackval || opts.orc || opts.uaccess || opts.noinstr) { + if (opts.stackval || opts.orc || opts.uaccess || opts.noinstr || + opts.hack_jump_label) { ret = add_special_section_alts(file); if (ret) return ret; From 157d7d16f81714eb278927e210c4c164031ffa92 Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Wed, 17 Sep 2025 09:03:27 -0700 Subject: [PATCH 0415/2333] objtool: Fix weak symbol detection [ Upstream commit 72567c630d32bc31f671977f78228c80937ed80e ] find_symbol_hole_containing() fails to find a symbol hole (aka stripped weak symbol) if its section has no symbols before the hole. This breaks weak symbol detection if -ffunction-sections is enabled. Fix that by allowing the interval tree to contain section symbols, which are always at offset zero for a given section. Fixes a bunch of (-ffunction-sections) warnings like: vmlinux.o: warning: objtool: .text.__x64_sys_io_setup+0x10: unreachable instruction Fixes: 4adb23686795 ("objtool: Ignore extra-symbol code") Acked-by: Petr Mladek Tested-by: Joe Lawrence Signed-off-by: Josh Poimboeuf Signed-off-by: Sasha Levin --- tools/objtool/elf.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c index ca5d77db692a2..9cb51fcde7986 100644 --- a/tools/objtool/elf.c +++ b/tools/objtool/elf.c @@ -108,7 +108,7 @@ struct symbol_hole { }; /* - * Find !section symbol where @offset is after it. + * Find the last symbol before @offset. */ static int symbol_hole_by_offset(const void *key, const struct rb_node *node) { @@ -119,8 +119,7 @@ static int symbol_hole_by_offset(const void *key, const struct rb_node *node) return -1; if (sh->key >= s->offset + s->len) { - if (s->type != STT_SECTION) - sh->sym = s; + sh->sym = s; return 1; } @@ -412,7 +411,8 @@ static void elf_add_symbol(struct elf *elf, struct symbol *sym) sym->len = sym->sym.st_size; __sym_for_each(iter, &sym->sec->symbol_tree, sym->offset, sym->offset) { - if (iter->offset == sym->offset && iter->type == sym->type) + if (iter->offset == sym->offset && iter->type == sym->type && + iter->len == sym->len) iter->alias = sym; } From fe14b92fb97c38ab40216165bab5fa3cd9cbd386 Mon Sep 17 00:00:00 2001 From: "Wludzik, Jozef" Date: Tue, 14 Oct 2025 09:17:25 +0200 Subject: [PATCH 0416/2333] accel/ivpu: Fix race condition when mapping dmabuf [ Upstream commit 63c7870fab67b2ab2bfe75e8b46f3c37b88c47a8 ] Fix a race that can occur when multiple jobs submit the same dmabuf. This could cause the sg_table to be mapped twice, leading to undefined behavior. Fixes: e0c0891cd63b ("accel/ivpu: Rework bind/unbind of imported buffers") Signed-off-by: Wludzik, Jozef Reviewed-by: Jeff Hugo Signed-off-by: Karol Wachowski Link: https://lore.kernel.org/r/20251014071725.3047287-1-karol.wachowski@linux.intel.com Signed-off-by: Sasha Levin --- drivers/accel/ivpu/ivpu_gem.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/accel/ivpu/ivpu_gem.c b/drivers/accel/ivpu/ivpu_gem.c index 171e809575ad6..1fca969df19dc 100644 --- a/drivers/accel/ivpu/ivpu_gem.c +++ b/drivers/accel/ivpu/ivpu_gem.c @@ -45,12 +45,13 @@ static inline void ivpu_bo_unlock(struct ivpu_bo *bo) static struct sg_table *ivpu_bo_map_attachment(struct ivpu_device *vdev, struct ivpu_bo *bo) { - struct sg_table *sgt = bo->base.sgt; + struct sg_table *sgt; drm_WARN_ON(&vdev->drm, !bo->base.base.import_attach); ivpu_bo_lock(bo); + sgt = bo->base.sgt; if (!sgt) { sgt = dma_buf_map_attachment(bo->base.base.import_attach, DMA_BIDIRECTIONAL); if (IS_ERR(sgt)) From 27858e7883778919a79c2b5633a22e422f834ee0 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Sun, 5 Oct 2025 11:24:04 -0700 Subject: [PATCH 0417/2333] perf parse-events: Fix legacy cache events if event is duplicated in a PMU [ Upstream commit b7b76f607a15f16031001687e733046b5f6f5d86 ] The term list when adding an event to a PMU is expected to have the event name for the alias lookup. Also, set found_supported so that -EINVAL isn't returned. Fixes: 62593394f66a ("perf parse-events: Legacy cache names on all PMUs and lower priority") Tested-by: Thomas Richter Signed-off-by: Ian Rogers Tested-by: James Clark Signed-off-by: Namhyung Kim Signed-off-by: Sasha Levin --- tools/perf/util/parse-events.c | 28 +++++++++++++++++++++++++++- tools/perf/util/parse-events.h | 3 ++- tools/perf/util/parse-events.y | 2 +- 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index da73d686f6b93..90a765016f64f 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -475,8 +475,10 @@ static int parse_events_add_pmu(struct parse_events_state *parse_state, int parse_events_add_cache(struct list_head *list, int *idx, const char *name, struct parse_events_state *parse_state, - struct parse_events_terms *parsed_terms) + struct parse_events_terms *parsed_terms, + void *loc_) { + YYLTYPE *loc = loc_; struct perf_pmu *pmu = NULL; bool found_supported = false; const char *config_name = get_config_name(parsed_terms); @@ -497,12 +499,36 @@ int parse_events_add_cache(struct list_head *list, int *idx, const char *name, * The PMU has the event so add as not a legacy cache * event. */ + struct parse_events_terms temp_terms; + struct parse_events_term *term; + char *config = strdup(name); + + if (!config) + goto out_err; + + parse_events_terms__init(&temp_terms); + if (!parsed_terms) + parsed_terms = &temp_terms; + + if (parse_events_term__num(&term, + PARSE_EVENTS__TERM_TYPE_USER, + config, /*num=*/1, /*novalue=*/true, + loc, /*loc_val=*/NULL) < 0) { + zfree(&config); + goto out_err; + } + list_add(&term->list, &parsed_terms->terms); + ret = parse_events_add_pmu(parse_state, list, pmu, parsed_terms, first_wildcard_match, /*alternate_hw_config=*/PERF_COUNT_HW_MAX); + list_del_init(&term->list); + parse_events_term__delete(term); + parse_events_terms__exit(&temp_terms); if (ret) goto out_err; + found_supported = true; if (first_wildcard_match == NULL) first_wildcard_match = container_of(list->prev, struct evsel, core.node); diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index 8f8c8e7fbcf18..8af19dec6a17d 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h @@ -237,7 +237,8 @@ int parse_events_add_numeric(struct parse_events_state *parse_state, bool wildcard); int parse_events_add_cache(struct list_head *list, int *idx, const char *name, struct parse_events_state *parse_state, - struct parse_events_terms *parsed_terms); + struct parse_events_terms *parsed_terms, + void *loc); int parse_events__decode_legacy_cache(const char *name, int pmu_type, __u64 *config); int parse_events_add_breakpoint(struct parse_events_state *parse_state, struct list_head *list, diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y index a2361c0040d75..ced26c549c33a 100644 --- a/tools/perf/util/parse-events.y +++ b/tools/perf/util/parse-events.y @@ -353,7 +353,7 @@ PE_LEGACY_CACHE opt_event_config if (!list) YYNOMEM; - err = parse_events_add_cache(list, &parse_state->idx, $1, parse_state, $2); + err = parse_events_add_cache(list, &parse_state->idx, $1, parse_state, $2, &@1); parse_events_terms__delete($2); free($1); From 5248b34df18c2d60fa9f0f5f2101ae00bb8cf0bf Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Fri, 26 Sep 2025 15:05:52 +0200 Subject: [PATCH 0418/2333] gpu: nova-core: gsp: remove useless conversion [ Upstream commit 87990025b87283f1b8c50d4d75379ca6d86d2211 ] Because nova-core depends on CONFIG_64BIT and a raw DmaAddress is always a u64, we can remove the now actually useless conversion. Signed-off-by: Danilo Krummrich Reviewed-by: John Hubbard [acourbot@nvidia.com: reword commit as suggested by John.] Signed-off-by: Alexandre Courbot Message-ID: <20250926130623.61316-1-dakr@kernel.org> Stable-dep-of: f7a33a67c50c ("gpu: nova-core: gsp: do not unwrap() SGEntry") Signed-off-by: Sasha Levin --- drivers/gpu/nova-core/firmware/gsp.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/nova-core/firmware/gsp.rs b/drivers/gpu/nova-core/firmware/gsp.rs index 9b70095434c61..ca785860e1c82 100644 --- a/drivers/gpu/nova-core/firmware/gsp.rs +++ b/drivers/gpu/nova-core/firmware/gsp.rs @@ -202,8 +202,7 @@ impl GspFirmware { let mut level0_data = kvec![0u8; GSP_PAGE_SIZE]?; // Fill level 1 page entry. - #[allow(clippy::useless_conversion)] - let level1_entry = u64::from(level1.iter().next().unwrap().dma_address()); + let level1_entry = level1.iter().next().unwrap().dma_address(); let dst = &mut level0_data[..size_of_val(&level1_entry)]; dst.copy_from_slice(&level1_entry.to_le_bytes()); From 72f8a15524f315ba5594d35511b2926a8a42fb46 Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Fri, 26 Sep 2025 15:05:53 +0200 Subject: [PATCH 0419/2333] gpu: nova-core: gsp: do not unwrap() SGEntry [ Upstream commit f7a33a67c50c92589b046e69b9075b7d28d31f87 ] Don't use unwrap() to extract an Option, instead handle the error condition gracefully. Fixes: a841614e607c ("gpu: nova-core: firmware: process and prepare the GSP firmware") Signed-off-by: Danilo Krummrich Reviewed-by: John Hubbard Signed-off-by: Alexandre Courbot Message-ID: <20250926130623.61316-2-dakr@kernel.org> Signed-off-by: Sasha Levin --- drivers/gpu/nova-core/firmware/gsp.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/nova-core/firmware/gsp.rs b/drivers/gpu/nova-core/firmware/gsp.rs index ca785860e1c82..6b0761460a57d 100644 --- a/drivers/gpu/nova-core/firmware/gsp.rs +++ b/drivers/gpu/nova-core/firmware/gsp.rs @@ -202,9 +202,10 @@ impl GspFirmware { let mut level0_data = kvec![0u8; GSP_PAGE_SIZE]?; // Fill level 1 page entry. - let level1_entry = level1.iter().next().unwrap().dma_address(); - let dst = &mut level0_data[..size_of_val(&level1_entry)]; - dst.copy_from_slice(&level1_entry.to_le_bytes()); + let level1_entry = level1.iter().next().ok_or(EINVAL)?; + let level1_entry_addr = level1_entry.dma_address(); + let dst = &mut level0_data[..size_of_val(&level1_entry_addr)]; + dst.copy_from_slice(&level1_entry_addr.to_le_bytes()); // Turn the level0 page table into a [`DmaObject`]. DmaObject::from_data(dev, &level0_data)? From b1497ea246396962156b63d5c568a16d6e32de0b Mon Sep 17 00:00:00 2001 From: Kang Yang Date: Tue, 14 Oct 2025 19:07:57 +0800 Subject: [PATCH 0420/2333] wifi: ath10k: move recovery check logic into a new work MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit f35a07a4842a88801d9182b1a76d178bfa616978 ] Currently, ath10k has a recovery check logic. It will wait for the last recovery to finish by wait_for_completion_timeout(); But in SDIO scenarios, the recovery function may be invoked from interrupt context, where long blocking waits are undesirable and can lead to system instability. Additionally, Linux’s ordered workqueue processes one task at a time. If a previous recovery is still queued or executing, new triggers are ignored. This prevents accurate tracking of consecutive failures and delays transition to the WEDGED state. To address this, move the recovery check logic into a different workqueue. Tested-on: QCA6174 hw3.2 PCI WLAN.RM.4.4.1-00288-QCARMSWPZ-1 Tested-on: QCA6174 hw3.2 SDIO WLAN.RMH.4.4.1-00189 Fixes: c256a94d1b1b ("wifi: ath10k: shutdown driver when hardware is unreliable") Signed-off-by: Kang Yang Reviewed-by: Baochen Qiang Link: https://patch.msgid.link/20251014110757.155-1-kang.yang@oss.qualcomm.com Signed-off-by: Jeff Johnson Signed-off-by: Sasha Levin --- drivers/net/wireless/ath/ath10k/core.c | 20 +++++++++----------- drivers/net/wireless/ath/ath10k/core.h | 2 +- drivers/net/wireless/ath/ath10k/mac.c | 2 +- 3 files changed, 11 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 6f78f1752cd6f..9ae3595fb6986 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -3,7 +3,6 @@ * Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ @@ -2493,8 +2492,9 @@ static int ath10k_init_hw_params(struct ath10k *ar) return 0; } -static bool ath10k_core_needs_recovery(struct ath10k *ar) +static void ath10k_core_recovery_check_work(struct work_struct *work) { + struct ath10k *ar = container_of(work, struct ath10k, recovery_check_work); long time_left; /* Sometimes the recovery will fail and then the next all recovery fail, @@ -2504,7 +2504,7 @@ static bool ath10k_core_needs_recovery(struct ath10k *ar) ath10k_err(ar, "consecutive fail %d times, will shutdown driver!", atomic_read(&ar->fail_cont_count)); ar->state = ATH10K_STATE_WEDGED; - return false; + return; } ath10k_dbg(ar, ATH10K_DBG_BOOT, "total recovery count: %d", ++ar->recovery_count); @@ -2518,27 +2518,24 @@ static bool ath10k_core_needs_recovery(struct ath10k *ar) ATH10K_RECOVERY_TIMEOUT_HZ); if (time_left) { ath10k_warn(ar, "previous recovery succeeded, skip this!\n"); - return false; + return; } /* Record the continuous recovery fail count when recovery failed. */ atomic_inc(&ar->fail_cont_count); /* Avoid having multiple recoveries at the same time. */ - return false; + return; } atomic_inc(&ar->pending_recovery); - - return true; + queue_work(ar->workqueue, &ar->restart_work); } void ath10k_core_start_recovery(struct ath10k *ar) { - if (!ath10k_core_needs_recovery(ar)) - return; - - queue_work(ar->workqueue, &ar->restart_work); + /* Use workqueue_aux to avoid blocking recovery tracking */ + queue_work(ar->workqueue_aux, &ar->recovery_check_work); } EXPORT_SYMBOL(ath10k_core_start_recovery); @@ -3734,6 +3731,7 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev, INIT_WORK(&ar->register_work, ath10k_core_register_work); INIT_WORK(&ar->restart_work, ath10k_core_restart); + INIT_WORK(&ar->recovery_check_work, ath10k_core_recovery_check_work); INIT_WORK(&ar->set_coverage_class_work, ath10k_core_set_coverage_class_work); diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 8c72ed386edb7..859176fcb5a29 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -3,7 +3,6 @@ * Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ @@ -1208,6 +1207,7 @@ struct ath10k { struct work_struct register_work; struct work_struct restart_work; + struct work_struct recovery_check_work; struct work_struct bundle_tx_work; struct work_struct tx_complete_work; diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 154ac7a709824..da6f7957a0ae7 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -3,7 +3,6 @@ * Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ @@ -5428,6 +5427,7 @@ static void ath10k_stop(struct ieee80211_hw *hw, bool suspend) cancel_work_sync(&ar->set_coverage_class_work); cancel_delayed_work_sync(&ar->scan.timeout); cancel_work_sync(&ar->restart_work); + cancel_work_sync(&ar->recovery_check_work); } static int ath10k_config_ps(struct ath10k *ar) From 99fc0689a58802498e9a1a245b43634ba20b856f Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Tue, 14 Oct 2025 10:30:20 +0800 Subject: [PATCH 0421/2333] wifi: ath11k: restore register window after global reset [ Upstream commit 596b911644cc19ecba0dbc9c92849fb59390e29a ] Hardware target implements an address space larger than that PCI BAR can map. In order to be able to access the whole target address space, the BAR space is split into 4 segments, of which the last 3, called windows, can be dynamically mapped to the desired area. This is achieved by updating window register with appropriate window value. Currently each time when accessing a register that beyond ATH11K_PCI_WINDOW_START, host calculates the window value and caches it after window update, this way next time when accessing a register falling in the same window, host knows that the window is already good hence no additional update needed. However this mechanism breaks after global reset is triggered in ath11k_pci_soc_global_reset(), because with global reset hardware resets window register hence the window is not properly mapped any more. Current host does nothing about this, as a result a subsequent register access may not work as expected if it falls in a window same as before. Although there is no obvious issue seen now, better to fix it to avoid future problem. The fix is done by restoring the window register after global reset. Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.30 Fixes: d5c65159f289 ("ath11k: driver for Qualcomm IEEE 802.11ax devices") Signed-off-by: Baochen Qiang Reviewed-by: Vasanthakumar Thiagarajan Link: https://patch.msgid.link/20251014-ath11k-reset-window-cache-v1-1-b85271b111dd@oss.qualcomm.com Signed-off-by: Jeff Johnson Signed-off-by: Sasha Levin --- drivers/net/wireless/ath/ath11k/pci.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath11k/pci.c b/drivers/net/wireless/ath/ath11k/pci.c index d8655badd96d0..7114eca8810db 100644 --- a/drivers/net/wireless/ath/ath11k/pci.c +++ b/drivers/net/wireless/ath/ath11k/pci.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include @@ -177,6 +177,19 @@ static inline void ath11k_pci_select_static_window(struct ath11k_pci *ab_pci) ab_pci->ab->mem + ATH11K_PCI_WINDOW_REG_ADDRESS); } +static void ath11k_pci_restore_window(struct ath11k_base *ab) +{ + struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); + + spin_lock_bh(&ab_pci->window_lock); + + iowrite32(ATH11K_PCI_WINDOW_ENABLE_BIT | ab_pci->register_window, + ab->mem + ATH11K_PCI_WINDOW_REG_ADDRESS); + ioread32(ab->mem + ATH11K_PCI_WINDOW_REG_ADDRESS); + + spin_unlock_bh(&ab_pci->window_lock); +} + static void ath11k_pci_soc_global_reset(struct ath11k_base *ab) { u32 val, delay; @@ -201,6 +214,11 @@ static void ath11k_pci_soc_global_reset(struct ath11k_base *ab) val = ath11k_pcic_read32(ab, PCIE_SOC_GLOBAL_RESET); if (val == 0xffffffff) ath11k_warn(ab, "link down error during global reset\n"); + + /* Restore window register as its content is cleared during + * hardware global reset, such that it aligns with host cache. + */ + ath11k_pci_restore_window(ab); } static void ath11k_pci_clear_dbg_registers(struct ath11k_base *ab) From ab0554f51e5f2b9506e8a09e8accd02f00056729 Mon Sep 17 00:00:00 2001 From: Sarika Sharma Date: Tue, 30 Sep 2025 14:45:50 +0530 Subject: [PATCH 0422/2333] wifi: ath12k: Fix MSDU buffer types handling in RX error path [ Upstream commit 36f9edbb9d0fc36c865c74f3c1ad8e1261ad3981 ] Currently, packets received on the REO exception ring from unassociated peers are of MSDU buffer type, while the driver expects link descriptor type packets. These packets are not parsed further due to a return check on packet type in ath12k_hal_desc_reo_parse_err(), but the associated skb is not freed. This may lead to kernel crashes and buffer leaks. Hence to fix, update the RX error handler to explicitly drop MSDU buffer type packets received on the REO exception ring. This prevents further processing of invalid packets and ensures stability in the RX error handling path. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.4.1-00199-QCAHKSWPL_SILICONZ-1 Fixes: d889913205cf ("wifi: ath12k: driver for Qualcomm Wi-Fi 7 devices") Signed-off-by: Sarika Sharma Reviewed-by: Baochen Qiang Reviewed-by: Vasanthakumar Thiagarajan Link: https://patch.msgid.link/20250930091551.3305312-2-sarika.sharma@oss.qualcomm.com Signed-off-by: Jeff Johnson Signed-off-by: Sasha Levin --- drivers/net/wireless/ath/ath12k/dp_rx.c | 70 ++++++++++++++++++++++-- drivers/net/wireless/ath/ath12k/hal_rx.c | 10 +--- 2 files changed, 66 insertions(+), 14 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c index 5e5c14a70316d..99d29eda26cf1 100644 --- a/drivers/net/wireless/ath/ath12k/dp_rx.c +++ b/drivers/net/wireless/ath/ath12k/dp_rx.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include @@ -3781,6 +3781,48 @@ ath12k_dp_process_rx_err_buf(struct ath12k *ar, struct hal_reo_dest_ring *desc, return 0; } +static int ath12k_dp_h_msdu_buffer_type(struct ath12k_base *ab, + struct list_head *list, + struct hal_reo_dest_ring *desc) +{ + struct ath12k_rx_desc_info *desc_info; + struct ath12k_skb_rxcb *rxcb; + struct sk_buff *msdu; + u64 desc_va; + + desc_va = (u64)le32_to_cpu(desc->buf_va_hi) << 32 | + le32_to_cpu(desc->buf_va_lo); + desc_info = (struct ath12k_rx_desc_info *)(uintptr_t)desc_va; + if (!desc_info) { + u32 cookie; + + cookie = le32_get_bits(desc->buf_addr_info.info1, + BUFFER_ADDR_INFO1_SW_COOKIE); + desc_info = ath12k_dp_get_rx_desc(ab, cookie); + if (!desc_info) { + ath12k_warn(ab, "Invalid cookie in manual descriptor retrieval: 0x%x\n", + cookie); + return -EINVAL; + } + } + + if (desc_info->magic != ATH12K_DP_RX_DESC_MAGIC) { + ath12k_warn(ab, "rx exception, magic check failed with value: %u\n", + desc_info->magic); + return -EINVAL; + } + + msdu = desc_info->skb; + desc_info->skb = NULL; + list_add_tail(&desc_info->list, list); + rxcb = ATH12K_SKB_RXCB(msdu); + dma_unmap_single(ab->dev, rxcb->paddr, msdu->len + skb_tailroom(msdu), + DMA_FROM_DEVICE); + dev_kfree_skb_any(msdu); + + return 0; +} + int ath12k_dp_rx_process_err(struct ath12k_base *ab, struct napi_struct *napi, int budget) { @@ -3825,6 +3867,26 @@ int ath12k_dp_rx_process_err(struct ath12k_base *ab, struct napi_struct *napi, drop = false; ab->device_stats.err_ring_pkts++; + hw_link_id = le32_get_bits(reo_desc->info0, + HAL_REO_DEST_RING_INFO0_SRC_LINK_ID); + device_id = hw_links[hw_link_id].device_id; + partner_ab = ath12k_ag_to_ab(ag, device_id); + + /* Below case is added to handle data packet from un-associated clients. + * As it is expected that AST lookup will fail for + * un-associated station's data packets. + */ + if (le32_get_bits(reo_desc->info0, HAL_REO_DEST_RING_INFO0_BUFFER_TYPE) == + HAL_REO_DEST_RING_BUFFER_TYPE_MSDU) { + if (!ath12k_dp_h_msdu_buffer_type(partner_ab, + &rx_desc_used_list[device_id], + reo_desc)) { + num_buffs_reaped[device_id]++; + tot_n_bufs_reaped++; + } + goto next_desc; + } + ret = ath12k_hal_desc_reo_parse_err(ab, reo_desc, &paddr, &desc_bank); if (ret) { @@ -3833,11 +3895,6 @@ int ath12k_dp_rx_process_err(struct ath12k_base *ab, struct napi_struct *napi, continue; } - hw_link_id = le32_get_bits(reo_desc->info0, - HAL_REO_DEST_RING_INFO0_SRC_LINK_ID); - device_id = hw_links[hw_link_id].device_id; - partner_ab = ath12k_ag_to_ab(ag, device_id); - pdev_id = ath12k_hw_mac_id_to_pdev_id(partner_ab->hw_params, hw_links[hw_link_id].pdev_idx); ar = partner_ab->pdevs[pdev_id].ar; @@ -3886,6 +3943,7 @@ int ath12k_dp_rx_process_err(struct ath12k_base *ab, struct napi_struct *napi, } } +next_desc: if (tot_n_bufs_reaped >= quota) { tot_n_bufs_reaped = quota; goto exit; diff --git a/drivers/net/wireless/ath/ath12k/hal_rx.c b/drivers/net/wireless/ath/ath12k/hal_rx.c index 669096278fdd4..c4443ca05cd65 100644 --- a/drivers/net/wireless/ath/ath12k/hal_rx.c +++ b/drivers/net/wireless/ath/ath12k/hal_rx.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include "debug.h" @@ -323,7 +323,7 @@ int ath12k_hal_desc_reo_parse_err(struct ath12k_base *ab, { enum hal_reo_dest_ring_push_reason push_reason; enum hal_reo_dest_ring_error_code err_code; - u32 cookie, val; + u32 cookie; push_reason = le32_get_bits(desc->info0, HAL_REO_DEST_RING_INFO0_PUSH_REASON); @@ -338,12 +338,6 @@ int ath12k_hal_desc_reo_parse_err(struct ath12k_base *ab, return -EINVAL; } - val = le32_get_bits(desc->info0, HAL_REO_DEST_RING_INFO0_BUFFER_TYPE); - if (val != HAL_REO_DEST_RING_BUFFER_TYPE_LINK_DESC) { - ath12k_warn(ab, "expected buffer type link_desc"); - return -EINVAL; - } - ath12k_hal_rx_reo_ent_paddr_get(ab, &desc->buf_addr_info, paddr, &cookie); *desc_bank = u32_get_bits(cookie, DP_LINK_DESC_BANK_MASK); From d911fa97dab3ba026a8b96bb7f833d007b7fc4e1 Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Thu, 9 Oct 2025 14:16:55 -0700 Subject: [PATCH 0423/2333] wifi: ath12k: fix VHT MCS assignment [ Upstream commit 8c21b32c2cc82224c7fc1a9f67318f3b1199744b ] While associating, firmware needs the peer's receive capability to calculate its own VHT transmit MCS. Currently, the host sends this information via mcs->rx_mcs_set field, but firmware actually reads it from mcs->tx_mcs_set field. This mismatch is incorrect. This issue has not caused failures so far because most peers advertise identical TX and RX capabilities. Fix this by assigning the value to tx_mcs_set as expected. Additionally, the rate control mask is intended to limit our transmit MCS, so it should also apply to the peer's receive capability. Update the logic accordingly. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Fixes: d889913205cf ("wifi: ath12k: driver for Qualcomm Wi-Fi 7 devices") Signed-off-by: Baochen Qiang Signed-off-by: Pradeep Kumar Chitrapu Reviewed-by: Vasanthakumar Thiagarajan Reviewed-by: Baochen Qiang Link: https://patch.msgid.link/20251009211656.2386085-2-quic_pradeepc@quicinc.com Signed-off-by: Jeff Johnson Signed-off-by: Sasha Levin --- drivers/net/wireless/ath/ath12k/mac.c | 7 +++---- drivers/net/wireless/ath/ath12k/wmi.c | 13 ++++++++----- drivers/net/wireless/ath/ath12k/wmi.h | 2 ++ 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index db351c9220181..4e6d136433202 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -2249,7 +2249,6 @@ static void ath12k_peer_assoc_h_vht(struct ath12k *ar, struct cfg80211_chan_def def; enum nl80211_band band; u16 *vht_mcs_mask; - u16 tx_mcs_map; u8 ampdu_factor; u8 max_nss, vht_mcs; int i, vht_nss, nss_idx; @@ -2340,10 +2339,10 @@ static void ath12k_peer_assoc_h_vht(struct ath12k *ar, arg->peer_nss = min(link_sta->rx_nss, max_nss); arg->rx_max_rate = __le16_to_cpu(vht_cap->vht_mcs.rx_highest); arg->rx_mcs_set = __le16_to_cpu(vht_cap->vht_mcs.rx_mcs_map); - arg->tx_max_rate = __le16_to_cpu(vht_cap->vht_mcs.tx_highest); + arg->rx_mcs_set = ath12k_peer_assoc_h_vht_limit(arg->rx_mcs_set, vht_mcs_mask); - tx_mcs_map = __le16_to_cpu(vht_cap->vht_mcs.tx_mcs_map); - arg->tx_mcs_set = ath12k_peer_assoc_h_vht_limit(tx_mcs_map, vht_mcs_mask); + arg->tx_max_rate = __le16_to_cpu(vht_cap->vht_mcs.tx_highest); + arg->tx_mcs_set = __le16_to_cpu(vht_cap->vht_mcs.tx_mcs_map); /* In QCN9274 platform, VHT MCS rate 10 and 11 is enabled by default. * VHT MCS rate 10 and 11 is not supported in 11ac standard. diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index ff6b3d4ea8208..e76275bd6916f 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include #include @@ -2367,10 +2367,13 @@ int ath12k_wmi_send_peer_assoc_cmd(struct ath12k *ar, cmd->peer_bw_rxnss_override |= cpu_to_le32(arg->peer_bw_rxnss_override); if (arg->vht_capable) { - mcs->rx_max_rate = cpu_to_le32(arg->rx_max_rate); - mcs->rx_mcs_set = cpu_to_le32(arg->rx_mcs_set); - mcs->tx_max_rate = cpu_to_le32(arg->tx_max_rate); - mcs->tx_mcs_set = cpu_to_le32(arg->tx_mcs_set); + /* Firmware interprets mcs->tx_mcs_set field as peer's + * RX capability + */ + mcs->rx_max_rate = cpu_to_le32(arg->tx_max_rate); + mcs->rx_mcs_set = cpu_to_le32(arg->tx_mcs_set); + mcs->tx_max_rate = cpu_to_le32(arg->rx_max_rate); + mcs->tx_mcs_set = cpu_to_le32(arg->rx_mcs_set); } /* HE Rates */ diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h index a8c3190e8ad95..6d9c645e3d5d0 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.h +++ b/drivers/net/wireless/ath/ath12k/wmi.h @@ -4218,8 +4218,10 @@ struct wmi_unit_test_cmd { struct ath12k_wmi_vht_rate_set_params { __le32 tlv_header; __le32 rx_max_rate; + /* MCS at which the peer can transmit */ __le32 rx_mcs_set; __le32 tx_max_rate; + /* MCS at which the peer can receive */ __le32 tx_mcs_set; __le32 tx_max_mcs_nss; } __packed; From ca2a33cee1ef8bc6fb16fbb4e065fadaddea977c Mon Sep 17 00:00:00 2001 From: Pradeep Kumar Chitrapu Date: Thu, 9 Oct 2025 14:16:56 -0700 Subject: [PATCH 0424/2333] wifi: ath12k: fix TX and RX MCS rate configurations in HE mode [ Upstream commit 9c5f229b1312a31aff762b2111f6751e4e3722fe ] Currently, the TX and RX MCS rate configurations per peer are reversed when sent to the firmware. As a result, RX MCS rates are configured for TX, and vice versa. This commit rectifies the configuration to match what the firmware expects. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Fixes: d889913205cf ("wifi: ath12k: driver for Qualcomm Wi-Fi 7 devices") Signed-off-by: Pradeep Kumar Chitrapu Reviewed-by: Vasanthakumar Thiagarajan Reviewed-by: Baochen Qiang Link: https://patch.msgid.link/20251009211656.2386085-3-quic_pradeepc@quicinc.com Signed-off-by: Jeff Johnson Signed-off-by: Sasha Levin --- drivers/net/wireless/ath/ath12k/mac.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 4e6d136433202..0cec6c47fca29 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -2624,9 +2624,10 @@ static void ath12k_peer_assoc_h_he(struct ath12k *ar, switch (link_sta->bandwidth) { case IEEE80211_STA_RX_BW_160: v = le16_to_cpu(he_cap->he_mcs_nss_supp.rx_mcs_160); + v = ath12k_peer_assoc_h_he_limit(v, he_mcs_mask); arg->peer_he_rx_mcs_set[WMI_HECAP_TXRX_MCS_NSS_IDX_160] = v; - v = ath12k_peer_assoc_h_he_limit(v, he_mcs_mask); + v = le16_to_cpu(he_cap->he_mcs_nss_supp.tx_mcs_160); arg->peer_he_tx_mcs_set[WMI_HECAP_TXRX_MCS_NSS_IDX_160] = v; arg->peer_he_mcs_count++; @@ -2636,10 +2637,10 @@ static void ath12k_peer_assoc_h_he(struct ath12k *ar, default: v = le16_to_cpu(he_cap->he_mcs_nss_supp.rx_mcs_80); + v = ath12k_peer_assoc_h_he_limit(v, he_mcs_mask); arg->peer_he_rx_mcs_set[WMI_HECAP_TXRX_MCS_NSS_IDX_80] = v; v = le16_to_cpu(he_cap->he_mcs_nss_supp.tx_mcs_80); - v = ath12k_peer_assoc_h_he_limit(v, he_mcs_mask); arg->peer_he_tx_mcs_set[WMI_HECAP_TXRX_MCS_NSS_IDX_80] = v; arg->peer_he_mcs_count++; From 01f1097166380de2a745cb9a03d0752a341102cc Mon Sep 17 00:00:00 2001 From: Fernand Sieber Date: Thu, 18 Sep 2025 17:05:28 +0200 Subject: [PATCH 0425/2333] sched/fair: Forfeit vruntime on yield [ Upstream commit 79104becf42baeeb4a3f2b106f954b9fc7c10a3c ] If a task yields, the scheduler may decide to pick it again. The task in turn may decide to yield immediately or shortly after, leading to a tight loop of yields. If there's another runnable task as this point, the deadline will be increased by the slice at each loop. This can cause the deadline to runaway pretty quickly, and subsequent elevated run delays later on as the task doesn't get picked again. The reason the scheduler can pick the same task again and again despite its deadline increasing is because it may be the only eligible task at that point. Fix this by making the task forfeiting its remaining vruntime and pushing the deadline one slice ahead. This implements yield behavior more authentically. We limit the forfeiting to eligible tasks. This is because core scheduling prefers running ineligible tasks rather than force idling. As such, without the condition, we can end up on a yield loop which makes the vruntime increase rapidly, leading to anomalous run delays later down the line. Fixes: 147f3efaa24182 ("sched/fair: Implement an EEVDF-like scheduling policy") Signed-off-by: Fernand Sieber Signed-off-by: Peter Zijlstra (Intel) Link: https://lore.kernel.org/r/20250401123622.584018-1-sieberf@amazon.com Link: https://lore.kernel.org/r/20250911095113.203439-1-sieberf@amazon.com Link: https://lore.kernel.org/r/20250916140228.452231-1-sieberf@amazon.com Signed-off-by: Sasha Levin --- kernel/sched/fair.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 5b752324270b0..2a4a1c6e25da0 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -9014,7 +9014,19 @@ static void yield_task_fair(struct rq *rq) */ rq_clock_skip_update(rq); - se->deadline += calc_delta_fair(se->slice, se); + /* + * Forfeit the remaining vruntime, only if the entity is eligible. This + * condition is necessary because in core scheduling we prefer to run + * ineligible tasks rather than force idling. If this happens we may + * end up in a loop where the core scheduler picks the yielding task, + * which yields immediately again; without the condition the vruntime + * ends up quickly running away. + */ + if (entity_eligible(cfs_rq, se)) { + se->vruntime = se->deadline; + se->deadline += calc_delta_fair(se->slice, se); + update_min_vruntime(cfs_rq); + } } static bool yield_to_task_fair(struct rq *rq, struct task_struct *p) From 2f525dea50f2db43821616e2634d3770520841f2 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 13 Oct 2025 11:46:01 +0200 Subject: [PATCH 0426/2333] irqchip/bcm2712-mip: Fix OF node reference imbalance [ Upstream commit 0435bcc4e5858c632c1b6d5afa637580d9779890 ] The init callback must not decrement the reference count of the provided irqchip OF node. This should not cause any trouble currently, but if the driver ever starts probe deferring it could lead to warnings about reference underflow and saturation. Fixes: 32c6c054661a ("irqchip: Add Broadcom BCM2712 MSI-X interrupt controller") Signed-off-by: Johan Hovold Signed-off-by: Thomas Gleixner Reviewed-by: Florian Fainelli Signed-off-by: Sasha Levin --- drivers/irqchip/irq-bcm2712-mip.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/irqchip/irq-bcm2712-mip.c b/drivers/irqchip/irq-bcm2712-mip.c index 9bd7bc0bf6d59..256c2d59f717d 100644 --- a/drivers/irqchip/irq-bcm2712-mip.c +++ b/drivers/irqchip/irq-bcm2712-mip.c @@ -239,7 +239,6 @@ static int __init mip_of_msi_init(struct device_node *node, struct device_node * int ret; pdev = of_find_device_by_node(node); - of_node_put(node); if (!pdev) return -EPROBE_DEFER; From e74c71452437fa9d0b79710f4f2c24a118b9d4e9 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 13 Oct 2025 11:46:02 +0200 Subject: [PATCH 0427/2333] irqchip/bcm2712-mip: Fix section mismatch [ Upstream commit a8452d1d59d46066051e676d5daa472cd08cb304 ] Platform drivers can be probed after their init sections have been discarded so the irqchip init callback must not live in init. Fixes: 32c6c054661a ("irqchip: Add Broadcom BCM2712 MSI-X interrupt controller") Signed-off-by: Johan Hovold Signed-off-by: Thomas Gleixner Reviewed-by: Florian Fainelli Signed-off-by: Sasha Levin --- drivers/irqchip/irq-bcm2712-mip.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/irqchip/irq-bcm2712-mip.c b/drivers/irqchip/irq-bcm2712-mip.c index 256c2d59f717d..8466646e5a2da 100644 --- a/drivers/irqchip/irq-bcm2712-mip.c +++ b/drivers/irqchip/irq-bcm2712-mip.c @@ -232,7 +232,7 @@ static int mip_parse_dt(struct mip_priv *mip, struct device_node *np) return ret; } -static int __init mip_of_msi_init(struct device_node *node, struct device_node *parent) +static int mip_of_msi_init(struct device_node *node, struct device_node *parent) { struct platform_device *pdev; struct mip_priv *mip; From 2f36222dbc040967f5493e049526dbf9c3f92194 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 13 Oct 2025 11:46:03 +0200 Subject: [PATCH 0428/2333] irqchip/irq-bcm7038-l1: Fix section mismatch [ Upstream commit e9db5332caaf4789ae3bafe72f61ad8e6e0c2d81 ] Platform drivers can be probed after their init sections have been discarded so the irqchip init callback must not live in init. Fixes: c057c799e379 ("irqchip/irq-bcm7038-l1: Switch to IRQCHIP_PLATFORM_DRIVER") Signed-off-by: Johan Hovold Signed-off-by: Thomas Gleixner Reviewed-by: Florian Fainelli Signed-off-by: Sasha Levin --- drivers/irqchip/irq-bcm7038-l1.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/irqchip/irq-bcm7038-l1.c b/drivers/irqchip/irq-bcm7038-l1.c index 04fac0cc857fd..eda33bd5d080c 100644 --- a/drivers/irqchip/irq-bcm7038-l1.c +++ b/drivers/irqchip/irq-bcm7038-l1.c @@ -219,9 +219,8 @@ static int bcm7038_l1_set_affinity(struct irq_data *d, } #endif -static int __init bcm7038_l1_init_one(struct device_node *dn, - unsigned int idx, - struct bcm7038_l1_chip *intc) +static int bcm7038_l1_init_one(struct device_node *dn, unsigned int idx, + struct bcm7038_l1_chip *intc) { struct resource res; resource_size_t sz; @@ -395,8 +394,7 @@ static const struct irq_domain_ops bcm7038_l1_domain_ops = { .map = bcm7038_l1_map, }; -static int __init bcm7038_l1_of_init(struct device_node *dn, - struct device_node *parent) +static int bcm7038_l1_of_init(struct device_node *dn, struct device_node *parent) { struct bcm7038_l1_chip *intc; int idx, ret; From 6769909e3ed8d21811996755ad920e03c2579186 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 13 Oct 2025 11:46:04 +0200 Subject: [PATCH 0429/2333] irqchip/irq-bcm7120-l2: Fix section mismatch [ Upstream commit bfc0c5beab1fde843677923cf008f41d583c980a ] Platform drivers can be probed after their init sections have been discarded so the irqchip init callbacks must not live in init. Fixes: 3ac268d5ed22 ("irqchip/irq-bcm7120-l2: Switch to IRQCHIP_PLATFORM_DRIVER") Signed-off-by: Johan Hovold Signed-off-by: Thomas Gleixner Reviewed-by: Florian Fainelli Signed-off-by: Sasha Levin --- drivers/irqchip/irq-bcm7120-l2.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/drivers/irqchip/irq-bcm7120-l2.c b/drivers/irqchip/irq-bcm7120-l2.c index ff22c31044018..b6c85560c42ea 100644 --- a/drivers/irqchip/irq-bcm7120-l2.c +++ b/drivers/irqchip/irq-bcm7120-l2.c @@ -143,8 +143,7 @@ static int bcm7120_l2_intc_init_one(struct device_node *dn, return 0; } -static int __init bcm7120_l2_intc_iomap_7120(struct device_node *dn, - struct bcm7120_l2_intc_data *data) +static int bcm7120_l2_intc_iomap_7120(struct device_node *dn, struct bcm7120_l2_intc_data *data) { int ret; @@ -177,8 +176,7 @@ static int __init bcm7120_l2_intc_iomap_7120(struct device_node *dn, return 0; } -static int __init bcm7120_l2_intc_iomap_3380(struct device_node *dn, - struct bcm7120_l2_intc_data *data) +static int bcm7120_l2_intc_iomap_3380(struct device_node *dn, struct bcm7120_l2_intc_data *data) { unsigned int gc_idx; @@ -208,10 +206,9 @@ static int __init bcm7120_l2_intc_iomap_3380(struct device_node *dn, return 0; } -static int __init bcm7120_l2_intc_probe(struct device_node *dn, - struct device_node *parent, +static int bcm7120_l2_intc_probe(struct device_node *dn, struct device_node *parent, int (*iomap_regs_fn)(struct device_node *, - struct bcm7120_l2_intc_data *), + struct bcm7120_l2_intc_data *), const char *intc_name) { unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN; @@ -339,15 +336,13 @@ static int __init bcm7120_l2_intc_probe(struct device_node *dn, return ret; } -static int __init bcm7120_l2_intc_probe_7120(struct device_node *dn, - struct device_node *parent) +static int bcm7120_l2_intc_probe_7120(struct device_node *dn, struct device_node *parent) { return bcm7120_l2_intc_probe(dn, parent, bcm7120_l2_intc_iomap_7120, "BCM7120 L2"); } -static int __init bcm7120_l2_intc_probe_3380(struct device_node *dn, - struct device_node *parent) +static int bcm7120_l2_intc_probe_3380(struct device_node *dn, struct device_node *parent) { return bcm7120_l2_intc_probe(dn, parent, bcm7120_l2_intc_iomap_3380, "BCM3380 L2"); From 99e8c4978410032c64fe94d8ead6bc89ee2c0c8a Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 13 Oct 2025 11:46:05 +0200 Subject: [PATCH 0430/2333] irqchip/irq-brcmstb-l2: Fix section mismatch [ Upstream commit bbe1775924478e95372c2f896064ab6446000713 ] Platform drivers can be probed after their init sections have been discarded so the irqchip init callbacks must not live in init. Fixes: 51d9db5c8fbb ("irqchip/irq-brcmstb-l2: Switch to IRQCHIP_PLATFORM_DRIVER") Signed-off-by: Johan Hovold Signed-off-by: Thomas Gleixner Reviewed-by: Florian Fainelli Signed-off-by: Sasha Levin --- drivers/irqchip/irq-brcmstb-l2.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/irqchip/irq-brcmstb-l2.c b/drivers/irqchip/irq-brcmstb-l2.c index 1bec5b2cd3f0e..53e67c6c01f7a 100644 --- a/drivers/irqchip/irq-brcmstb-l2.c +++ b/drivers/irqchip/irq-brcmstb-l2.c @@ -138,10 +138,8 @@ static void brcmstb_l2_intc_resume(struct irq_data *d) irq_reg_writel(gc, ~b->saved_mask, ct->regs.enable); } -static int __init brcmstb_l2_intc_of_init(struct device_node *np, - struct device_node *parent, - const struct brcmstb_intc_init_params - *init_params) +static int brcmstb_l2_intc_of_init(struct device_node *np, struct device_node *parent, + const struct brcmstb_intc_init_params *init_params) { unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN; unsigned int set = 0; @@ -257,14 +255,12 @@ static int __init brcmstb_l2_intc_of_init(struct device_node *np, return ret; } -static int __init brcmstb_l2_edge_intc_of_init(struct device_node *np, - struct device_node *parent) +static int brcmstb_l2_edge_intc_of_init(struct device_node *np, struct device_node *parent) { return brcmstb_l2_intc_of_init(np, parent, &l2_edge_intc_init); } -static int __init brcmstb_l2_lvl_intc_of_init(struct device_node *np, - struct device_node *parent) +static int brcmstb_l2_lvl_intc_of_init(struct device_node *np, struct device_node *parent) { return brcmstb_l2_intc_of_init(np, parent, &l2_lvl_intc_init); } From 60597d44de5fe532614fbfa23dc57a0177c838ab Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 13 Oct 2025 11:46:06 +0200 Subject: [PATCH 0431/2333] irqchip/imx-mu-msi: Fix section mismatch [ Upstream commit 64acfd8e680ff8992c101fe19aadb112ce551072 ] Platform drivers can be probed after their init sections have been discarded so the irqchip init callbacks must not live in init. Fixes: 70afdab904d2 ("irqchip: Add IMX MU MSI controller driver") Signed-off-by: Johan Hovold Signed-off-by: Thomas Gleixner Signed-off-by: Sasha Levin --- drivers/irqchip/irq-imx-mu-msi.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/drivers/irqchip/irq-imx-mu-msi.c b/drivers/irqchip/irq-imx-mu-msi.c index d2a4e8a61a42b..41df168aa7da2 100644 --- a/drivers/irqchip/irq-imx-mu-msi.c +++ b/drivers/irqchip/irq-imx-mu-msi.c @@ -296,9 +296,8 @@ static const struct imx_mu_dcfg imx_mu_cfg_imx8ulp = { }, }; -static int __init imx_mu_of_init(struct device_node *dn, - struct device_node *parent, - const struct imx_mu_dcfg *cfg) +static int imx_mu_of_init(struct device_node *dn, struct device_node *parent, + const struct imx_mu_dcfg *cfg) { struct platform_device *pdev = of_find_device_by_node(dn); struct device_link *pd_link_a; @@ -416,20 +415,17 @@ static const struct dev_pm_ops imx_mu_pm_ops = { imx_mu_runtime_resume, NULL) }; -static int __init imx_mu_imx7ulp_of_init(struct device_node *dn, - struct device_node *parent) +static int imx_mu_imx7ulp_of_init(struct device_node *dn, struct device_node *parent) { return imx_mu_of_init(dn, parent, &imx_mu_cfg_imx7ulp); } -static int __init imx_mu_imx6sx_of_init(struct device_node *dn, - struct device_node *parent) +static int imx_mu_imx6sx_of_init(struct device_node *dn, struct device_node *parent) { return imx_mu_of_init(dn, parent, &imx_mu_cfg_imx6sx); } -static int __init imx_mu_imx8ulp_of_init(struct device_node *dn, - struct device_node *parent) +static int imx_mu_imx8ulp_of_init(struct device_node *dn, struct device_node *parent) { return imx_mu_of_init(dn, parent, &imx_mu_cfg_imx8ulp); } From 3f1ac747652fe2ce067d243f5410e21b4b425326 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 13 Oct 2025 11:46:07 +0200 Subject: [PATCH 0432/2333] irqchip/renesas-rzg2l: Fix section mismatch [ Upstream commit 5b338fbb2b5b21d61a9eaba14dcf43108de30258 ] Platform drivers can be probed after their init sections have been discarded so the irqchip init callbacks must not live in init. Fixes: d011c022efe27579 ("irqchip/renesas-rzg2l: Add support for RZ/Five SoC") Signed-off-by: Johan Hovold Signed-off-by: Thomas Gleixner Reviewed-by: Geert Uytterhoeven Signed-off-by: Sasha Levin --- drivers/irqchip/irq-renesas-rzg2l.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/irqchip/irq-renesas-rzg2l.c b/drivers/irqchip/irq-renesas-rzg2l.c index 2a54adeb4cc71..12b6eb1503016 100644 --- a/drivers/irqchip/irq-renesas-rzg2l.c +++ b/drivers/irqchip/irq-renesas-rzg2l.c @@ -597,14 +597,12 @@ static int rzg2l_irqc_common_init(struct device_node *node, struct device_node * return 0; } -static int __init rzg2l_irqc_init(struct device_node *node, - struct device_node *parent) +static int rzg2l_irqc_init(struct device_node *node, struct device_node *parent) { return rzg2l_irqc_common_init(node, parent, &rzg2l_irqc_chip); } -static int __init rzfive_irqc_init(struct device_node *node, - struct device_node *parent) +static int rzfive_irqc_init(struct device_node *node, struct device_node *parent) { return rzg2l_irqc_common_init(node, parent, &rzfive_irqc_chip); } From d4caa2df1f0812fe6c7eb8029ee3d62b7978e578 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 13 Oct 2025 11:46:08 +0200 Subject: [PATCH 0433/2333] irqchip/starfive-jh8100: Fix section mismatch [ Upstream commit f798bdb9aa81c425184f92e3d0b44d3b53d10da7 ] Platform drivers can be probed after their init sections have been discarded so the irqchip init callback must not live in init. Fixes: e4e535036173 ("irqchip: Add StarFive external interrupt controller") Signed-off-by: Johan Hovold Signed-off-by: Thomas Gleixner Reviewed-by: Changhuang Liang Signed-off-by: Sasha Levin --- drivers/irqchip/irq-starfive-jh8100-intc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/irqchip/irq-starfive-jh8100-intc.c b/drivers/irqchip/irq-starfive-jh8100-intc.c index 2460798ec158b..117f2c651ebd0 100644 --- a/drivers/irqchip/irq-starfive-jh8100-intc.c +++ b/drivers/irqchip/irq-starfive-jh8100-intc.c @@ -114,8 +114,7 @@ static void starfive_intc_irq_handler(struct irq_desc *desc) chained_irq_exit(chip, desc); } -static int __init starfive_intc_init(struct device_node *intc, - struct device_node *parent) +static int starfive_intc_init(struct device_node *intc, struct device_node *parent) { struct starfive_irq_chip *irqc; struct reset_control *rst; From defdeae616070373e406fc6f69d343a0ecba15a0 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 13 Oct 2025 11:46:09 +0200 Subject: [PATCH 0434/2333] irqchip/qcom-irq-combiner: Fix section mismatch [ Upstream commit 9b685058ca936752285c5520d351b828312ac965 ] Platform drivers can be probed after their init sections have been discarded so the probe callback must not live in init. Fixes: f20cc9b00c7b ("irqchip/qcom: Add IRQ combiner driver") Signed-off-by: Johan Hovold Signed-off-by: Thomas Gleixner Signed-off-by: Sasha Levin --- drivers/irqchip/qcom-irq-combiner.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/irqchip/qcom-irq-combiner.c b/drivers/irqchip/qcom-irq-combiner.c index 18e696dc7f4d6..9308088773be7 100644 --- a/drivers/irqchip/qcom-irq-combiner.c +++ b/drivers/irqchip/qcom-irq-combiner.c @@ -222,7 +222,7 @@ static int get_registers(struct platform_device *pdev, struct combiner *comb) return 0; } -static int __init combiner_probe(struct platform_device *pdev) +static int combiner_probe(struct platform_device *pdev) { struct combiner *combiner; int nregs; From d2e28c3ed2e2a3d0072f9e21c27680e3a82d0d74 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 13 Oct 2025 11:46:10 +0200 Subject: [PATCH 0435/2333] irqchip: Drop leftover brackets [ Upstream commit 3540d99c03a88d4ebf65026f1f1926d3af658fb1 ] Drop some unnecessary brackets in platform_irqchip_probe() mistakenly left by commit 9322d1915f9d ("irqchip: Plug a OF node reference leak in platform_irqchip_probe()"). Signed-off-by: Johan Hovold Signed-off-by: Thomas Gleixner Reviewed-by: Geert Uytterhoeven Stable-dep-of: 1e3e330c0707 ("irqchip: Pass platform device to platform drivers") Signed-off-by: Sasha Levin --- drivers/irqchip/irqchip.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/irqchip/irqchip.c b/drivers/irqchip/irqchip.c index 0ee7b6b71f5fa..652d20d2b07f1 100644 --- a/drivers/irqchip/irqchip.c +++ b/drivers/irqchip/irqchip.c @@ -38,9 +38,8 @@ int platform_irqchip_probe(struct platform_device *pdev) struct device_node *par_np __free(device_node) = of_irq_find_parent(np); of_irq_init_cb_t irq_init_cb = of_device_get_match_data(&pdev->dev); - if (!irq_init_cb) { + if (!irq_init_cb) return -EINVAL; - } if (par_np == np) par_np = NULL; @@ -53,9 +52,8 @@ int platform_irqchip_probe(struct platform_device *pdev) * interrupt controller. The actual initialization callback of this * interrupt controller can check for specific domains as necessary. */ - if (par_np && !irq_find_matching_host(par_np, DOMAIN_BUS_ANY)) { + if (par_np && !irq_find_matching_host(par_np, DOMAIN_BUS_ANY)) return -EPROBE_DEFER; - } return irq_init_cb(np, par_np); } From 58c47ba6f329f1597f077640c84c290a2adb1119 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 13 Oct 2025 11:46:11 +0200 Subject: [PATCH 0436/2333] irqchip: Pass platform device to platform drivers [ Upstream commit 1e3e330c07076a0582385bbea029c9cc918fa30d ] The IRQCHIP_PLATFORM_DRIVER macros can be used to convert OF irqchip drivers to platform drivers but currently reuse the OF init callback prototype that only takes OF nodes as arguments. This forces drivers to do reverse lookups of their struct devices during probe if they need them for things like dev_printk() and device managed resources. Half of the drivers doing reverse lookups also currently fail to release the additional reference taken during the lookup, while other drivers have had the reference leak plugged in various ways (e.g. using non-intuitive cleanup constructs which still confuse static checkers). Switch to using a probe callback that takes a platform device as its first argument to simplify drivers and plug the remaining (mostly benign) reference leaks. Fixes: 32c6c054661a ("irqchip: Add Broadcom BCM2712 MSI-X interrupt controller") Fixes: 70afdab904d2 ("irqchip: Add IMX MU MSI controller driver") Fixes: a6199bb514d8 ("irqchip: Add Qualcomm MPM controller driver") Signed-off-by: Johan Hovold Signed-off-by: Thomas Gleixner Reviewed-by: Florian Fainelli Reviewed-by: Changhuang Liang Signed-off-by: Sasha Levin --- drivers/irqchip/irq-bcm2712-mip.c | 10 ++----- drivers/irqchip/irq-bcm7038-l1.c | 5 ++-- drivers/irqchip/irq-bcm7120-l2.c | 20 ++++--------- drivers/irqchip/irq-brcmstb-l2.c | 21 ++++++------- drivers/irqchip/irq-imx-mu-msi.c | 24 +++++++-------- drivers/irqchip/irq-mchp-eic.c | 5 ++-- drivers/irqchip/irq-meson-gpio.c | 5 ++-- drivers/irqchip/irq-qcom-mpm.c | 6 ++-- drivers/irqchip/irq-renesas-rzg2l.c | 35 +++++++--------------- drivers/irqchip/irq-renesas-rzv2h.c | 32 ++++++-------------- drivers/irqchip/irq-starfive-jh8100-intc.c | 5 ++-- drivers/irqchip/irqchip.c | 6 ++-- drivers/irqchip/qcom-pdc.c | 5 ++-- include/linux/irqchip.h | 8 ++++- 14 files changed, 78 insertions(+), 109 deletions(-) diff --git a/drivers/irqchip/irq-bcm2712-mip.c b/drivers/irqchip/irq-bcm2712-mip.c index 8466646e5a2da..4761974ad650a 100644 --- a/drivers/irqchip/irq-bcm2712-mip.c +++ b/drivers/irqchip/irq-bcm2712-mip.c @@ -232,16 +232,12 @@ static int mip_parse_dt(struct mip_priv *mip, struct device_node *np) return ret; } -static int mip_of_msi_init(struct device_node *node, struct device_node *parent) +static int mip_msi_probe(struct platform_device *pdev, struct device_node *parent) { - struct platform_device *pdev; + struct device_node *node = pdev->dev.of_node; struct mip_priv *mip; int ret; - pdev = of_find_device_by_node(node); - if (!pdev) - return -EPROBE_DEFER; - mip = kzalloc(sizeof(*mip), GFP_KERNEL); if (!mip) return -ENOMEM; @@ -284,7 +280,7 @@ static int mip_of_msi_init(struct device_node *node, struct device_node *parent) } IRQCHIP_PLATFORM_DRIVER_BEGIN(mip_msi) -IRQCHIP_MATCH("brcm,bcm2712-mip", mip_of_msi_init) +IRQCHIP_MATCH("brcm,bcm2712-mip", mip_msi_probe) IRQCHIP_PLATFORM_DRIVER_END(mip_msi) MODULE_DESCRIPTION("Broadcom BCM2712 MSI-X interrupt controller"); MODULE_AUTHOR("Phil Elwell "); diff --git a/drivers/irqchip/irq-bcm7038-l1.c b/drivers/irqchip/irq-bcm7038-l1.c index eda33bd5d080c..821b288587cab 100644 --- a/drivers/irqchip/irq-bcm7038-l1.c +++ b/drivers/irqchip/irq-bcm7038-l1.c @@ -394,8 +394,9 @@ static const struct irq_domain_ops bcm7038_l1_domain_ops = { .map = bcm7038_l1_map, }; -static int bcm7038_l1_of_init(struct device_node *dn, struct device_node *parent) +static int bcm7038_l1_probe(struct platform_device *pdev, struct device_node *parent) { + struct device_node *dn = pdev->dev.of_node; struct bcm7038_l1_chip *intc; int idx, ret; @@ -453,7 +454,7 @@ static int bcm7038_l1_of_init(struct device_node *dn, struct device_node *parent } IRQCHIP_PLATFORM_DRIVER_BEGIN(bcm7038_l1) -IRQCHIP_MATCH("brcm,bcm7038-l1-intc", bcm7038_l1_of_init) +IRQCHIP_MATCH("brcm,bcm7038-l1-intc", bcm7038_l1_probe) IRQCHIP_PLATFORM_DRIVER_END(bcm7038_l1) MODULE_DESCRIPTION("Broadcom STB 7038-style L1/L2 interrupt controller"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/irqchip/irq-bcm7120-l2.c b/drivers/irqchip/irq-bcm7120-l2.c index b6c85560c42ea..518c9d4366a55 100644 --- a/drivers/irqchip/irq-bcm7120-l2.c +++ b/drivers/irqchip/irq-bcm7120-l2.c @@ -206,14 +206,14 @@ static int bcm7120_l2_intc_iomap_3380(struct device_node *dn, struct bcm7120_l2_ return 0; } -static int bcm7120_l2_intc_probe(struct device_node *dn, struct device_node *parent, +static int bcm7120_l2_intc_probe(struct platform_device *pdev, struct device_node *parent, int (*iomap_regs_fn)(struct device_node *, struct bcm7120_l2_intc_data *), const char *intc_name) { unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN; + struct device_node *dn = pdev->dev.of_node; struct bcm7120_l2_intc_data *data; - struct platform_device *pdev; struct irq_chip_generic *gc; struct irq_chip_type *ct; int ret = 0; @@ -224,14 +224,7 @@ static int bcm7120_l2_intc_probe(struct device_node *dn, struct device_node *par if (!data) return -ENOMEM; - pdev = of_find_device_by_node(dn); - if (!pdev) { - ret = -ENODEV; - goto out_free_data; - } - data->num_parent_irqs = platform_irq_count(pdev); - put_device(&pdev->dev); if (data->num_parent_irqs <= 0) { pr_err("invalid number of parent interrupts\n"); ret = -ENOMEM; @@ -331,20 +324,19 @@ static int bcm7120_l2_intc_probe(struct device_node *dn, struct device_node *par if (data->map_base[idx]) iounmap(data->map_base[idx]); } -out_free_data: kfree(data); return ret; } -static int bcm7120_l2_intc_probe_7120(struct device_node *dn, struct device_node *parent) +static int bcm7120_l2_intc_probe_7120(struct platform_device *pdev, struct device_node *parent) { - return bcm7120_l2_intc_probe(dn, parent, bcm7120_l2_intc_iomap_7120, + return bcm7120_l2_intc_probe(pdev, parent, bcm7120_l2_intc_iomap_7120, "BCM7120 L2"); } -static int bcm7120_l2_intc_probe_3380(struct device_node *dn, struct device_node *parent) +static int bcm7120_l2_intc_probe_3380(struct platform_device *pdev, struct device_node *parent) { - return bcm7120_l2_intc_probe(dn, parent, bcm7120_l2_intc_iomap_3380, + return bcm7120_l2_intc_probe(pdev, parent, bcm7120_l2_intc_iomap_3380, "BCM3380 L2"); } diff --git a/drivers/irqchip/irq-brcmstb-l2.c b/drivers/irqchip/irq-brcmstb-l2.c index 53e67c6c01f7a..bb7078d6524f9 100644 --- a/drivers/irqchip/irq-brcmstb-l2.c +++ b/drivers/irqchip/irq-brcmstb-l2.c @@ -138,11 +138,12 @@ static void brcmstb_l2_intc_resume(struct irq_data *d) irq_reg_writel(gc, ~b->saved_mask, ct->regs.enable); } -static int brcmstb_l2_intc_of_init(struct device_node *np, struct device_node *parent, - const struct brcmstb_intc_init_params *init_params) +static int brcmstb_l2_intc_probe(struct platform_device *pdev, struct device_node *parent, + const struct brcmstb_intc_init_params *init_params) { unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN; unsigned int set = 0; + struct device_node *np = pdev->dev.of_node; struct brcmstb_l2_intc_data *data; struct irq_chip_type *ct; int ret; @@ -255,21 +256,21 @@ static int brcmstb_l2_intc_of_init(struct device_node *np, struct device_node *p return ret; } -static int brcmstb_l2_edge_intc_of_init(struct device_node *np, struct device_node *parent) +static int brcmstb_l2_edge_intc_probe(struct platform_device *pdev, struct device_node *parent) { - return brcmstb_l2_intc_of_init(np, parent, &l2_edge_intc_init); + return brcmstb_l2_intc_probe(pdev, parent, &l2_edge_intc_init); } -static int brcmstb_l2_lvl_intc_of_init(struct device_node *np, struct device_node *parent) +static int brcmstb_l2_lvl_intc_probe(struct platform_device *pdev, struct device_node *parent) { - return brcmstb_l2_intc_of_init(np, parent, &l2_lvl_intc_init); + return brcmstb_l2_intc_probe(pdev, parent, &l2_lvl_intc_init); } IRQCHIP_PLATFORM_DRIVER_BEGIN(brcmstb_l2) -IRQCHIP_MATCH("brcm,l2-intc", brcmstb_l2_edge_intc_of_init) -IRQCHIP_MATCH("brcm,hif-spi-l2-intc", brcmstb_l2_edge_intc_of_init) -IRQCHIP_MATCH("brcm,upg-aux-aon-l2-intc", brcmstb_l2_edge_intc_of_init) -IRQCHIP_MATCH("brcm,bcm7271-l2-intc", brcmstb_l2_lvl_intc_of_init) +IRQCHIP_MATCH("brcm,l2-intc", brcmstb_l2_edge_intc_probe) +IRQCHIP_MATCH("brcm,hif-spi-l2-intc", brcmstb_l2_edge_intc_probe) +IRQCHIP_MATCH("brcm,upg-aux-aon-l2-intc", brcmstb_l2_edge_intc_probe) +IRQCHIP_MATCH("brcm,bcm7271-l2-intc", brcmstb_l2_lvl_intc_probe) IRQCHIP_PLATFORM_DRIVER_END(brcmstb_l2) MODULE_DESCRIPTION("Broadcom STB generic L2 interrupt controller"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/irqchip/irq-imx-mu-msi.c b/drivers/irqchip/irq-imx-mu-msi.c index 41df168aa7da2..c598f2f52fc6f 100644 --- a/drivers/irqchip/irq-imx-mu-msi.c +++ b/drivers/irqchip/irq-imx-mu-msi.c @@ -296,10 +296,9 @@ static const struct imx_mu_dcfg imx_mu_cfg_imx8ulp = { }, }; -static int imx_mu_of_init(struct device_node *dn, struct device_node *parent, - const struct imx_mu_dcfg *cfg) +static int imx_mu_probe(struct platform_device *pdev, struct device_node *parent, + const struct imx_mu_dcfg *cfg) { - struct platform_device *pdev = of_find_device_by_node(dn); struct device_link *pd_link_a; struct device_link *pd_link_b; struct imx_mu_msi *msi_data; @@ -415,28 +414,27 @@ static const struct dev_pm_ops imx_mu_pm_ops = { imx_mu_runtime_resume, NULL) }; -static int imx_mu_imx7ulp_of_init(struct device_node *dn, struct device_node *parent) +static int imx_mu_imx7ulp_probe(struct platform_device *pdev, struct device_node *parent) { - return imx_mu_of_init(dn, parent, &imx_mu_cfg_imx7ulp); + return imx_mu_probe(pdev, parent, &imx_mu_cfg_imx7ulp); } -static int imx_mu_imx6sx_of_init(struct device_node *dn, struct device_node *parent) +static int imx_mu_imx6sx_probe(struct platform_device *pdev, struct device_node *parent) { - return imx_mu_of_init(dn, parent, &imx_mu_cfg_imx6sx); + return imx_mu_probe(pdev, parent, &imx_mu_cfg_imx6sx); } -static int imx_mu_imx8ulp_of_init(struct device_node *dn, struct device_node *parent) +static int imx_mu_imx8ulp_probe(struct platform_device *pdev, struct device_node *parent) { - return imx_mu_of_init(dn, parent, &imx_mu_cfg_imx8ulp); + return imx_mu_probe(pdev, parent, &imx_mu_cfg_imx8ulp); } IRQCHIP_PLATFORM_DRIVER_BEGIN(imx_mu_msi) -IRQCHIP_MATCH("fsl,imx7ulp-mu-msi", imx_mu_imx7ulp_of_init) -IRQCHIP_MATCH("fsl,imx6sx-mu-msi", imx_mu_imx6sx_of_init) -IRQCHIP_MATCH("fsl,imx8ulp-mu-msi", imx_mu_imx8ulp_of_init) +IRQCHIP_MATCH("fsl,imx7ulp-mu-msi", imx_mu_imx7ulp_probe) +IRQCHIP_MATCH("fsl,imx6sx-mu-msi", imx_mu_imx6sx_probe) +IRQCHIP_MATCH("fsl,imx8ulp-mu-msi", imx_mu_imx8ulp_probe) IRQCHIP_PLATFORM_DRIVER_END(imx_mu_msi, .pm = &imx_mu_pm_ops) - MODULE_AUTHOR("Frank Li "); MODULE_DESCRIPTION("Freescale MU MSI controller driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/irqchip/irq-mchp-eic.c b/drivers/irqchip/irq-mchp-eic.c index 516a3a0e359cc..b513a899c0853 100644 --- a/drivers/irqchip/irq-mchp-eic.c +++ b/drivers/irqchip/irq-mchp-eic.c @@ -199,8 +199,9 @@ static const struct irq_domain_ops mchp_eic_domain_ops = { .free = irq_domain_free_irqs_common, }; -static int mchp_eic_init(struct device_node *node, struct device_node *parent) +static int mchp_eic_probe(struct platform_device *pdev, struct device_node *parent) { + struct device_node *node = pdev->dev.of_node; struct irq_domain *parent_domain = NULL; int ret, i; @@ -273,7 +274,7 @@ static int mchp_eic_init(struct device_node *node, struct device_node *parent) } IRQCHIP_PLATFORM_DRIVER_BEGIN(mchp_eic) -IRQCHIP_MATCH("microchip,sama7g5-eic", mchp_eic_init) +IRQCHIP_MATCH("microchip,sama7g5-eic", mchp_eic_probe) IRQCHIP_PLATFORM_DRIVER_END(mchp_eic) MODULE_DESCRIPTION("Microchip External Interrupt Controller"); diff --git a/drivers/irqchip/irq-meson-gpio.c b/drivers/irqchip/irq-meson-gpio.c index 7d177626d64ba..09ebf1d9c21b0 100644 --- a/drivers/irqchip/irq-meson-gpio.c +++ b/drivers/irqchip/irq-meson-gpio.c @@ -572,8 +572,9 @@ static int meson_gpio_irq_parse_dt(struct device_node *node, struct meson_gpio_i return 0; } -static int meson_gpio_irq_of_init(struct device_node *node, struct device_node *parent) +static int meson_gpio_irq_probe(struct platform_device *pdev, struct device_node *parent) { + struct device_node *node = pdev->dev.of_node; struct irq_domain *domain, *parent_domain; struct meson_gpio_irq_controller *ctl; int ret; @@ -630,7 +631,7 @@ static int meson_gpio_irq_of_init(struct device_node *node, struct device_node * } IRQCHIP_PLATFORM_DRIVER_BEGIN(meson_gpio_intc) -IRQCHIP_MATCH("amlogic,meson-gpio-intc", meson_gpio_irq_of_init) +IRQCHIP_MATCH("amlogic,meson-gpio-intc", meson_gpio_irq_probe) IRQCHIP_PLATFORM_DRIVER_END(meson_gpio_intc) MODULE_AUTHOR("Jerome Brunet "); diff --git a/drivers/irqchip/irq-qcom-mpm.c b/drivers/irqchip/irq-qcom-mpm.c index 8d569f7c5a7aa..83f31ea657b74 100644 --- a/drivers/irqchip/irq-qcom-mpm.c +++ b/drivers/irqchip/irq-qcom-mpm.c @@ -320,9 +320,9 @@ static bool gic_hwirq_is_mapped(struct mpm_gic_map *maps, int cnt, u32 hwirq) return false; } -static int qcom_mpm_init(struct device_node *np, struct device_node *parent) +static int qcom_mpm_probe(struct platform_device *pdev, struct device_node *parent) { - struct platform_device *pdev = of_find_device_by_node(np); + struct device_node *np = pdev->dev.of_node; struct device *dev = &pdev->dev; struct irq_domain *parent_domain; struct generic_pm_domain *genpd; @@ -478,7 +478,7 @@ static int qcom_mpm_init(struct device_node *np, struct device_node *parent) } IRQCHIP_PLATFORM_DRIVER_BEGIN(qcom_mpm) -IRQCHIP_MATCH("qcom,mpm", qcom_mpm_init) +IRQCHIP_MATCH("qcom,mpm", qcom_mpm_probe) IRQCHIP_PLATFORM_DRIVER_END(qcom_mpm) MODULE_DESCRIPTION("Qualcomm Technologies, Inc. MSM Power Manager"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/irqchip/irq-renesas-rzg2l.c b/drivers/irqchip/irq-renesas-rzg2l.c index 12b6eb1503016..1bf19deb02c4e 100644 --- a/drivers/irqchip/irq-renesas-rzg2l.c +++ b/drivers/irqchip/irq-renesas-rzg2l.c @@ -8,7 +8,6 @@ */ #include -#include #include #include #include @@ -528,18 +527,15 @@ static int rzg2l_irqc_parse_interrupts(struct rzg2l_irqc_priv *priv, return 0; } -static int rzg2l_irqc_common_init(struct device_node *node, struct device_node *parent, - const struct irq_chip *irq_chip) +static int rzg2l_irqc_common_probe(struct platform_device *pdev, struct device_node *parent, + const struct irq_chip *irq_chip) { - struct platform_device *pdev = of_find_device_by_node(node); - struct device *dev __free(put_device) = pdev ? &pdev->dev : NULL; struct irq_domain *irq_domain, *parent_domain; + struct device_node *node = pdev->dev.of_node; + struct device *dev = &pdev->dev; struct reset_control *resetn; int ret; - if (!pdev) - return -ENODEV; - parent_domain = irq_find_host(parent); if (!parent_domain) return dev_err_probe(dev, -ENODEV, "cannot find parent domain\n"); @@ -583,33 +579,22 @@ static int rzg2l_irqc_common_init(struct device_node *node, struct device_node * register_syscore_ops(&rzg2l_irqc_syscore_ops); - /* - * Prevent the cleanup function from invoking put_device by assigning - * NULL to dev. - * - * make coccicheck will complain about missing put_device calls, but - * those are false positives, as dev will be automatically "put" via - * __free_put_device on the failing path. - * On the successful path we don't actually want to "put" dev. - */ - dev = NULL; - return 0; } -static int rzg2l_irqc_init(struct device_node *node, struct device_node *parent) +static int rzg2l_irqc_probe(struct platform_device *pdev, struct device_node *parent) { - return rzg2l_irqc_common_init(node, parent, &rzg2l_irqc_chip); + return rzg2l_irqc_common_probe(pdev, parent, &rzg2l_irqc_chip); } -static int rzfive_irqc_init(struct device_node *node, struct device_node *parent) +static int rzfive_irqc_probe(struct platform_device *pdev, struct device_node *parent) { - return rzg2l_irqc_common_init(node, parent, &rzfive_irqc_chip); + return rzg2l_irqc_common_probe(pdev, parent, &rzfive_irqc_chip); } IRQCHIP_PLATFORM_DRIVER_BEGIN(rzg2l_irqc) -IRQCHIP_MATCH("renesas,rzg2l-irqc", rzg2l_irqc_init) -IRQCHIP_MATCH("renesas,r9a07g043f-irqc", rzfive_irqc_init) +IRQCHIP_MATCH("renesas,rzg2l-irqc", rzg2l_irqc_probe) +IRQCHIP_MATCH("renesas,r9a07g043f-irqc", rzfive_irqc_probe) IRQCHIP_PLATFORM_DRIVER_END(rzg2l_irqc) MODULE_AUTHOR("Lad Prabhakar "); MODULE_DESCRIPTION("Renesas RZ/G2L IRQC Driver"); diff --git a/drivers/irqchip/irq-renesas-rzv2h.c b/drivers/irqchip/irq-renesas-rzv2h.c index 9018d9c3911e3..899a423b5da8f 100644 --- a/drivers/irqchip/irq-renesas-rzv2h.c +++ b/drivers/irqchip/irq-renesas-rzv2h.c @@ -490,29 +490,15 @@ static int rzv2h_icu_parse_interrupts(struct rzv2h_icu_priv *priv, struct device return 0; } -static void rzv2h_icu_put_device(void *data) -{ - put_device(data); -} - -static int rzv2h_icu_init_common(struct device_node *node, struct device_node *parent, - const struct rzv2h_hw_info *hw_info) +static int rzv2h_icu_probe_common(struct platform_device *pdev, struct device_node *parent, + const struct rzv2h_hw_info *hw_info) { struct irq_domain *irq_domain, *parent_domain; + struct device_node *node = pdev->dev.of_node; struct rzv2h_icu_priv *rzv2h_icu_data; - struct platform_device *pdev; struct reset_control *resetn; int ret; - pdev = of_find_device_by_node(node); - if (!pdev) - return -ENODEV; - - ret = devm_add_action_or_reset(&pdev->dev, rzv2h_icu_put_device, - &pdev->dev); - if (ret < 0) - return ret; - parent_domain = irq_find_host(parent); if (!parent_domain) { dev_err(&pdev->dev, "cannot find parent domain\n"); @@ -618,19 +604,19 @@ static const struct rzv2h_hw_info rzv2h_hw_params = { .field_width = 8, }; -static int rzg3e_icu_init(struct device_node *node, struct device_node *parent) +static int rzg3e_icu_probe(struct platform_device *pdev, struct device_node *parent) { - return rzv2h_icu_init_common(node, parent, &rzg3e_hw_params); + return rzv2h_icu_probe_common(pdev, parent, &rzg3e_hw_params); } -static int rzv2h_icu_init(struct device_node *node, struct device_node *parent) +static int rzv2h_icu_probe(struct platform_device *pdev, struct device_node *parent) { - return rzv2h_icu_init_common(node, parent, &rzv2h_hw_params); + return rzv2h_icu_probe_common(pdev, parent, &rzv2h_hw_params); } IRQCHIP_PLATFORM_DRIVER_BEGIN(rzv2h_icu) -IRQCHIP_MATCH("renesas,r9a09g047-icu", rzg3e_icu_init) -IRQCHIP_MATCH("renesas,r9a09g057-icu", rzv2h_icu_init) +IRQCHIP_MATCH("renesas,r9a09g047-icu", rzg3e_icu_probe) +IRQCHIP_MATCH("renesas,r9a09g057-icu", rzv2h_icu_probe) IRQCHIP_PLATFORM_DRIVER_END(rzv2h_icu) MODULE_AUTHOR("Fabrizio Castro "); MODULE_DESCRIPTION("Renesas RZ/V2H(P) ICU Driver"); diff --git a/drivers/irqchip/irq-starfive-jh8100-intc.c b/drivers/irqchip/irq-starfive-jh8100-intc.c index 117f2c651ebd0..705361b4ebe07 100644 --- a/drivers/irqchip/irq-starfive-jh8100-intc.c +++ b/drivers/irqchip/irq-starfive-jh8100-intc.c @@ -114,8 +114,9 @@ static void starfive_intc_irq_handler(struct irq_desc *desc) chained_irq_exit(chip, desc); } -static int starfive_intc_init(struct device_node *intc, struct device_node *parent) +static int starfive_intc_probe(struct platform_device *pdev, struct device_node *parent) { + struct device_node *intc = pdev->dev.of_node; struct starfive_irq_chip *irqc; struct reset_control *rst; struct clk *clk; @@ -198,7 +199,7 @@ static int starfive_intc_init(struct device_node *intc, struct device_node *pare } IRQCHIP_PLATFORM_DRIVER_BEGIN(starfive_intc) -IRQCHIP_MATCH("starfive,jh8100-intc", starfive_intc_init) +IRQCHIP_MATCH("starfive,jh8100-intc", starfive_intc_probe) IRQCHIP_PLATFORM_DRIVER_END(starfive_intc) MODULE_DESCRIPTION("StarFive JH8100 External Interrupt Controller"); diff --git a/drivers/irqchip/irqchip.c b/drivers/irqchip/irqchip.c index 652d20d2b07f1..689c8e4489019 100644 --- a/drivers/irqchip/irqchip.c +++ b/drivers/irqchip/irqchip.c @@ -36,9 +36,9 @@ int platform_irqchip_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; struct device_node *par_np __free(device_node) = of_irq_find_parent(np); - of_irq_init_cb_t irq_init_cb = of_device_get_match_data(&pdev->dev); + platform_irq_probe_t irq_probe = of_device_get_match_data(&pdev->dev); - if (!irq_init_cb) + if (!irq_probe) return -EINVAL; if (par_np == np) @@ -55,6 +55,6 @@ int platform_irqchip_probe(struct platform_device *pdev) if (par_np && !irq_find_matching_host(par_np, DOMAIN_BUS_ANY)) return -EPROBE_DEFER; - return irq_init_cb(np, par_np); + return irq_probe(pdev, par_np); } EXPORT_SYMBOL_GPL(platform_irqchip_probe); diff --git a/drivers/irqchip/qcom-pdc.c b/drivers/irqchip/qcom-pdc.c index 52d77546aacb9..518f7f0f3dab5 100644 --- a/drivers/irqchip/qcom-pdc.c +++ b/drivers/irqchip/qcom-pdc.c @@ -350,9 +350,10 @@ static int pdc_setup_pin_mapping(struct device_node *np) #define QCOM_PDC_SIZE 0x30000 -static int qcom_pdc_init(struct device_node *node, struct device_node *parent) +static int qcom_pdc_probe(struct platform_device *pdev, struct device_node *parent) { struct irq_domain *parent_domain, *pdc_domain; + struct device_node *node = pdev->dev.of_node; resource_size_t res_size; struct resource res; int ret; @@ -428,7 +429,7 @@ static int qcom_pdc_init(struct device_node *node, struct device_node *parent) } IRQCHIP_PLATFORM_DRIVER_BEGIN(qcom_pdc) -IRQCHIP_MATCH("qcom,pdc", qcom_pdc_init) +IRQCHIP_MATCH("qcom,pdc", qcom_pdc_probe) IRQCHIP_PLATFORM_DRIVER_END(qcom_pdc) MODULE_DESCRIPTION("Qualcomm Technologies, Inc. Power Domain Controller"); MODULE_LICENSE("GPL v2"); diff --git a/include/linux/irqchip.h b/include/linux/irqchip.h index d5e6024cb2a8c..bc4ddacd6ddc1 100644 --- a/include/linux/irqchip.h +++ b/include/linux/irqchip.h @@ -17,12 +17,18 @@ #include #include +typedef int (*platform_irq_probe_t)(struct platform_device *, struct device_node *); + /* Undefined on purpose */ extern of_irq_init_cb_t typecheck_irq_init_cb; +extern platform_irq_probe_t typecheck_irq_probe; #define typecheck_irq_init_cb(fn) \ (__typecheck(typecheck_irq_init_cb, &fn) ? fn : fn) +#define typecheck_irq_probe(fn) \ + (__typecheck(typecheck_irq_probe, &fn) ? fn : fn) + /* * This macro must be used by the different irqchip drivers to declare * the association between their DT compatible string and their @@ -42,7 +48,7 @@ extern int platform_irqchip_probe(struct platform_device *pdev); static const struct of_device_id drv_name##_irqchip_match_table[] = { #define IRQCHIP_MATCH(compat, fn) { .compatible = compat, \ - .data = typecheck_irq_init_cb(fn), }, + .data = typecheck_irq_probe(fn), }, #define IRQCHIP_PLATFORM_DRIVER_END(drv_name, ...) \ From 841b3868a64f6f3fd06bf7797ba149eb53c2ee45 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Wed, 24 Sep 2025 18:20:17 +0800 Subject: [PATCH 0437/2333] crypto: authenc - Correctly pass EINPROGRESS back up to the caller [ Upstream commit 96feb73def02d175850daa0e7c2c90c876681b5c ] When authenc is invoked with MAY_BACKLOG, it needs to pass EINPROGRESS notifications back up to the caller when the underlying algorithm returns EBUSY synchronously. However, if the EBUSY comes from the second part of an authenc call, i.e., it is asynchronous, both the EBUSY and the subsequent EINPROGRESS notification must not be passed to the caller. Implement this by passing a mask to the function that starts the second half of authenc and using it to determine whether EBUSY and EINPROGRESS should be passed to the caller. This was a deficiency in the original implementation of authenc because it was not expected to be used with MAY_BACKLOG. Reported-by: Ingo Franzki Reported-by: Mikulas Patocka Fixes: 180ce7e81030 ("crypto: authenc - Add EINPROGRESS check") Signed-off-by: Herbert Xu Signed-off-by: Sasha Levin --- crypto/authenc.c | 75 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 50 insertions(+), 25 deletions(-) diff --git a/crypto/authenc.c b/crypto/authenc.c index a723769c87779..ac679ce2cb953 100644 --- a/crypto/authenc.c +++ b/crypto/authenc.c @@ -37,7 +37,7 @@ struct authenc_request_ctx { static void authenc_request_complete(struct aead_request *req, int err) { - if (err != -EINPROGRESS) + if (err != -EINPROGRESS && err != -EBUSY) aead_request_complete(req, err); } @@ -107,27 +107,42 @@ static int crypto_authenc_setkey(struct crypto_aead *authenc, const u8 *key, return err; } -static void authenc_geniv_ahash_done(void *data, int err) +static void authenc_geniv_ahash_finish(struct aead_request *req) { - struct aead_request *req = data; struct crypto_aead *authenc = crypto_aead_reqtfm(req); struct aead_instance *inst = aead_alg_instance(authenc); struct authenc_instance_ctx *ictx = aead_instance_ctx(inst); struct authenc_request_ctx *areq_ctx = aead_request_ctx(req); struct ahash_request *ahreq = (void *)(areq_ctx->tail + ictx->reqoff); - if (err) - goto out; - scatterwalk_map_and_copy(ahreq->result, req->dst, req->assoclen + req->cryptlen, crypto_aead_authsize(authenc), 1); +} -out: +static void authenc_geniv_ahash_done(void *data, int err) +{ + struct aead_request *req = data; + + if (!err) + authenc_geniv_ahash_finish(req); aead_request_complete(req, err); } -static int crypto_authenc_genicv(struct aead_request *req, unsigned int flags) +/* + * Used when the ahash request was invoked in the async callback context + * of the previous skcipher request. Eat any EINPROGRESS notifications. + */ +static void authenc_geniv_ahash_done2(void *data, int err) +{ + struct aead_request *req = data; + + if (!err) + authenc_geniv_ahash_finish(req); + authenc_request_complete(req, err); +} + +static int crypto_authenc_genicv(struct aead_request *req, unsigned int mask) { struct crypto_aead *authenc = crypto_aead_reqtfm(req); struct aead_instance *inst = aead_alg_instance(authenc); @@ -136,6 +151,7 @@ static int crypto_authenc_genicv(struct aead_request *req, unsigned int flags) struct crypto_ahash *auth = ctx->auth; struct authenc_request_ctx *areq_ctx = aead_request_ctx(req); struct ahash_request *ahreq = (void *)(areq_ctx->tail + ictx->reqoff); + unsigned int flags = aead_request_flags(req) & ~mask; u8 *hash = areq_ctx->tail; int err; @@ -143,7 +159,8 @@ static int crypto_authenc_genicv(struct aead_request *req, unsigned int flags) ahash_request_set_crypt(ahreq, req->dst, hash, req->assoclen + req->cryptlen); ahash_request_set_callback(ahreq, flags, - authenc_geniv_ahash_done, req); + mask ? authenc_geniv_ahash_done2 : + authenc_geniv_ahash_done, req); err = crypto_ahash_digest(ahreq); if (err) @@ -159,12 +176,11 @@ static void crypto_authenc_encrypt_done(void *data, int err) { struct aead_request *areq = data; - if (err) - goto out; - - err = crypto_authenc_genicv(areq, 0); - -out: + if (err) { + aead_request_complete(areq, err); + return; + } + err = crypto_authenc_genicv(areq, CRYPTO_TFM_REQ_MAY_SLEEP); authenc_request_complete(areq, err); } @@ -199,11 +215,18 @@ static int crypto_authenc_encrypt(struct aead_request *req) if (err) return err; - return crypto_authenc_genicv(req, aead_request_flags(req)); + return crypto_authenc_genicv(req, 0); +} + +static void authenc_decrypt_tail_done(void *data, int err) +{ + struct aead_request *req = data; + + authenc_request_complete(req, err); } static int crypto_authenc_decrypt_tail(struct aead_request *req, - unsigned int flags) + unsigned int mask) { struct crypto_aead *authenc = crypto_aead_reqtfm(req); struct aead_instance *inst = aead_alg_instance(authenc); @@ -214,6 +237,7 @@ static int crypto_authenc_decrypt_tail(struct aead_request *req, struct skcipher_request *skreq = (void *)(areq_ctx->tail + ictx->reqoff); unsigned int authsize = crypto_aead_authsize(authenc); + unsigned int flags = aead_request_flags(req) & ~mask; u8 *ihash = ahreq->result + authsize; struct scatterlist *src, *dst; @@ -230,7 +254,9 @@ static int crypto_authenc_decrypt_tail(struct aead_request *req, skcipher_request_set_tfm(skreq, ctx->enc); skcipher_request_set_callback(skreq, flags, - req->base.complete, req->base.data); + mask ? authenc_decrypt_tail_done : + req->base.complete, + mask ? req : req->base.data); skcipher_request_set_crypt(skreq, src, dst, req->cryptlen - authsize, req->iv); @@ -241,12 +267,11 @@ static void authenc_verify_ahash_done(void *data, int err) { struct aead_request *req = data; - if (err) - goto out; - - err = crypto_authenc_decrypt_tail(req, 0); - -out: + if (err) { + aead_request_complete(req, err); + return; + } + err = crypto_authenc_decrypt_tail(req, CRYPTO_TFM_REQ_MAY_SLEEP); authenc_request_complete(req, err); } @@ -273,7 +298,7 @@ static int crypto_authenc_decrypt(struct aead_request *req) if (err) return err; - return crypto_authenc_decrypt_tail(req, aead_request_flags(req)); + return crypto_authenc_decrypt_tail(req, 0); } static int crypto_authenc_init_tfm(struct crypto_aead *tfm) From 81ffe9a265df3e41534726b852ab08792e3d374d Mon Sep 17 00:00:00 2001 From: Raphael Pinsonneault-Thibeault Date: Sun, 12 Oct 2025 16:16:34 -0400 Subject: [PATCH 0438/2333] ntfs3: fix uninit memory after failed mi_read in mi_format_new MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 73e6b9dacf72a1e7a4265eacca46f8f33e0997d6 ] Fix a KMSAN un-init bug found by syzkaller. ntfs_get_bh() expects a buffer from sb_getblk(), that buffer may not be uptodate. We do not bring the buffer uptodate before setting it as uptodate. If the buffer were to not be uptodate, it could mean adding a buffer with un-init data to the mi record. Attempting to load that record will trigger KMSAN. Avoid this by setting the buffer as uptodate, if it’s not already, by overwriting it. Reported-by: syzbot+7a2ba6b7b66340cff225@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=7a2ba6b7b66340cff225 Tested-by: syzbot+7a2ba6b7b66340cff225@syzkaller.appspotmail.com Fixes: 4342306f0f0d5 ("fs/ntfs3: Add file operations and implementation") Signed-off-by: Raphael Pinsonneault-Thibeault Signed-off-by: Konstantin Komarov Signed-off-by: Sasha Levin --- fs/ntfs3/fsntfs.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/fs/ntfs3/fsntfs.c b/fs/ntfs3/fsntfs.c index c7a2f191254da..5ae910e9ecbda 100644 --- a/fs/ntfs3/fsntfs.c +++ b/fs/ntfs3/fsntfs.c @@ -1349,7 +1349,14 @@ int ntfs_get_bh(struct ntfs_sb_info *sbi, const struct runs_tree *run, u64 vbo, } if (buffer_locked(bh)) __wait_on_buffer(bh); - set_buffer_uptodate(bh); + + lock_buffer(bh); + if (!buffer_uptodate(bh)) + { + memset(bh->b_data, 0, blocksize); + set_buffer_uptodate(bh); + } + unlock_buffer(bh); } else { bh = ntfs_bread(sb, block); if (!bh) { From b40a4eb4a0543d49686a6e693745009dac3b86a9 Mon Sep 17 00:00:00 2001 From: Sidharth Seela Date: Tue, 23 Sep 2025 12:10:16 +0530 Subject: [PATCH 0439/2333] ntfs3: Fix uninit buffer allocated by __getname() [ Upstream commit 9948dcb2f7b5a1bf8e8710eafaf6016e00be3ad6 ] Fix uninit errors caused after buffer allocation given to 'de'; by initializing the buffer with zeroes. The fix was found by using KMSAN. Reported-by: syzbot+332bd4e9d148f11a87dc@syzkaller.appspotmail.com Fixes: 78ab59fee07f2 ("fs/ntfs3: Rework file operations") Signed-off-by: Sidharth Seela Signed-off-by: Konstantin Komarov Signed-off-by: Sasha Levin --- fs/ntfs3/inode.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/ntfs3/inode.c b/fs/ntfs3/inode.c index 3959f23c487a2..3a0676871bade 100644 --- a/fs/ntfs3/inode.c +++ b/fs/ntfs3/inode.c @@ -1722,6 +1722,7 @@ int ntfs_link_inode(struct inode *inode, struct dentry *dentry) de = __getname(); if (!de) return -ENOMEM; + memset(de, 0, PATH_MAX); /* Mark rw ntfs as dirty. It will be cleared at umount. */ ntfs_set_state(sbi, NTFS_DIRTY_DIRTY); From fdbf4423bb81168fc670c5e99f2e7523bd68b095 Mon Sep 17 00:00:00 2001 From: Kathiravan Thirumoorthy Date: Tue, 14 Oct 2025 10:25:01 +0530 Subject: [PATCH 0440/2333] arm64: dts: qcom: ipq5424: correct the TF-A reserved memory to 512K [ Upstream commit 28803705b552a0a711fa849490f14dca2bc5296e ] Correct the reserved memory size for TF-A to 512K, as it was mistakenly marked as 500K. Update the reserved memory node accordingly. Fixes: 8517204c982b ("arm64: dts: qcom: ipq5424: Add reserved memory for TF-A") Signed-off-by: Kathiravan Thirumoorthy Link: https://lore.kernel.org/r/20251014-tfa-reserved-mem-v1-1-48c82033c8a7@oss.qualcomm.com Signed-off-by: Bjorn Andersson Signed-off-by: Sasha Levin --- arch/arm64/boot/dts/qcom/ipq5424.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/ipq5424.dtsi b/arch/arm64/boot/dts/qcom/ipq5424.dtsi index ef2b52f3597d9..227d5ce297515 100644 --- a/arch/arm64/boot/dts/qcom/ipq5424.dtsi +++ b/arch/arm64/boot/dts/qcom/ipq5424.dtsi @@ -213,7 +213,7 @@ }; tfa@8a832000 { - reg = <0x0 0x8a832000 0x0 0x7d000>; + reg = <0x0 0x8a832000 0x0 0x80000>; no-map; status = "disabled"; }; From d98d38c7f8ca522684919ba049069e8052677fc3 Mon Sep 17 00:00:00 2001 From: Francesco Lavra Date: Fri, 17 Oct 2025 18:42:54 +0200 Subject: [PATCH 0441/2333] iio: imu: st_lsm6dsx: Fix measurement unit for odr struct member [ Upstream commit c6d702f2b77194b62fb2098c63bb7f2a87da142d ] The `odr` field in struct st_lsm6dsx_sensor contains a data rate value expressed in mHz, not in Hz. Fixes: f8710f0357bc3 ("iio: imu: st_lsm6dsx: express odr in mHZ") Signed-off-by: Francesco Lavra Acked-by: Lorenzo Bianconi Signed-off-by: Jonathan Cameron Signed-off-by: Sasha Levin --- drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h index 381b016fa5243..56244d49ab2fc 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h @@ -383,7 +383,7 @@ enum st_lsm6dsx_fifo_mode { * @id: Sensor identifier. * @hw: Pointer to instance of struct st_lsm6dsx_hw. * @gain: Configured sensor sensitivity. - * @odr: Output data rate of the sensor [Hz]. + * @odr: Output data rate of the sensor [mHz]. * @samples_to_discard: Number of samples to discard for filters settling time. * @watermark: Sensor watermark level. * @decimator: Sensor decimation factor. From b346cdd95f7ac367f66dcb7e591eed51961357e5 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Fri, 17 Oct 2025 12:13:23 -0700 Subject: [PATCH 0442/2333] firmware: qcom: tzmem: fix qcom_tzmem_policy kernel-doc [ Upstream commit edd548dc64a699d71ea4f537f815044e763d01e1 ] Fix kernel-doc warnings by using correct kernel-doc syntax and formatting to prevent warnings: Warning: include/linux/firmware/qcom/qcom_tzmem.h:25 Enum value 'QCOM_TZMEM_POLICY_STATIC' not described in enum 'qcom_tzmem_policy' Warning: ../include/linux/firmware/qcom/qcom_tzmem.h:25 Enum value 'QCOM_TZMEM_POLICY_MULTIPLIER' not described in enum 'qcom_tzmem_policy' Warning: ../include/linux/firmware/qcom/qcom_tzmem.h:25 Enum value 'QCOM_TZMEM_POLICY_ON_DEMAND' not described in enum 'qcom_tzmem_policy' Fixes: 84f5a7b67b61 ("firmware: qcom: add a dedicated TrustZone buffer allocator") Signed-off-by: Randy Dunlap Link: https://lore.kernel.org/r/20251017191323.1820167-1-rdunlap@infradead.org Signed-off-by: Bjorn Andersson Signed-off-by: Sasha Levin --- include/linux/firmware/qcom/qcom_tzmem.h | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/include/linux/firmware/qcom/qcom_tzmem.h b/include/linux/firmware/qcom/qcom_tzmem.h index 48ac0e5454c7f..23173e0c3dddd 100644 --- a/include/linux/firmware/qcom/qcom_tzmem.h +++ b/include/linux/firmware/qcom/qcom_tzmem.h @@ -17,11 +17,20 @@ struct qcom_tzmem_pool; * enum qcom_tzmem_policy - Policy for pool growth. */ enum qcom_tzmem_policy { - /**< Static pool, never grow above initial size. */ + /** + * @QCOM_TZMEM_POLICY_STATIC: Static pool, + * never grow above initial size. + */ QCOM_TZMEM_POLICY_STATIC = 1, - /**< When out of memory, add increment * current size of memory. */ + /** + * @QCOM_TZMEM_POLICY_MULTIPLIER: When out of memory, + * add increment * current size of memory. + */ QCOM_TZMEM_POLICY_MULTIPLIER, - /**< When out of memory add as much as is needed until max_size. */ + /** + * @QCOM_TZMEM_POLICY_ON_DEMAND: When out of memory + * add as much as is needed until max_size. + */ QCOM_TZMEM_POLICY_ON_DEMAND, }; From 67c42f3ec0bdff098c804b9132ad204c2804829c Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Fri, 17 Oct 2025 16:03:57 -0700 Subject: [PATCH 0443/2333] perf parse-events: Make X modifier more respectful of groups [ Upstream commit 800201997a509c298e74696da3586d82b1a2b6f4 ] Events with an X modifier were reordered within a group, for example slots was made the leader in: ``` $ perf record -e '{cpu/mem-stores/ppu,cpu/slots/uX}' -- sleep 1 ``` Fix by making `dont_regroup` evsels always use their index for sorting. Make the cur_leader, when fixing the groups, be that of `dont_regroup` evsel so that the `dont_regroup` evsel doesn't become a leader. On a tigerlake this patch corrects this and meets expectations in: ``` $ perf stat -e '{cpu/mem-stores/,cpu/slots/uX}' -a -- sleep 0.1 Performance counter stats for 'system wide': 83,458,652 cpu/mem-stores/ 2,720,854,880 cpu/slots/uX 0.103780587 seconds time elapsed $ perf stat -e 'slots,slots:X' -a -- sleep 0.1 Performance counter stats for 'system wide': 732,042,247 slots (48.96%) 643,288,155 slots:X (51.04%) 0.102731018 seconds time elapsed ``` Closes: https://lore.kernel.org/lkml/18f20d38-070c-4e17-bc90-cf7102e1e53d@linux.intel.com/ Fixes: 035c17893082 ("perf parse-events: Add 'X' modifier to exclude an event from being regrouped") Signed-off-by: Ian Rogers Signed-off-by: Namhyung Kim Signed-off-by: Sasha Levin --- tools/perf/util/parse-events.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 90a765016f64f..cd9315d3ca117 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -2121,14 +2121,18 @@ static int evlist__cmp(void *_fg_idx, const struct list_head *l, const struct li * event's index is used. An index may be forced for events that * must be in the same group, namely Intel topdown events. */ - if (*force_grouped_idx != -1 && arch_evsel__must_be_in_group(lhs)) { + if (lhs->dont_regroup) { + lhs_sort_idx = lhs_core->idx; + } else if (*force_grouped_idx != -1 && arch_evsel__must_be_in_group(lhs)) { lhs_sort_idx = *force_grouped_idx; } else { bool lhs_has_group = lhs_core->leader != lhs_core || lhs_core->nr_members > 1; lhs_sort_idx = lhs_has_group ? lhs_core->leader->idx : lhs_core->idx; } - if (*force_grouped_idx != -1 && arch_evsel__must_be_in_group(rhs)) { + if (rhs->dont_regroup) { + rhs_sort_idx = rhs_core->idx; + } else if (*force_grouped_idx != -1 && arch_evsel__must_be_in_group(rhs)) { rhs_sort_idx = *force_grouped_idx; } else { bool rhs_has_group = rhs_core->leader != rhs_core || rhs_core->nr_members > 1; @@ -2226,10 +2230,10 @@ static int parse_events__sort_events_and_fix_groups(struct list_head *list) */ idx = 0; list_for_each_entry(pos, list, core.node) { - const struct evsel *pos_leader = evsel__leader(pos); + struct evsel *pos_leader = evsel__leader(pos); const char *pos_pmu_name = pos->group_pmu_name; const char *cur_leader_pmu_name; - bool pos_force_grouped = force_grouped_idx != -1 && + bool pos_force_grouped = force_grouped_idx != -1 && !pos->dont_regroup && arch_evsel__must_be_in_group(pos); /* Reset index and nr_members. */ @@ -2243,8 +2247,8 @@ static int parse_events__sort_events_and_fix_groups(struct list_head *list) * groups can't span PMUs. */ if (!cur_leader || pos->dont_regroup) { - cur_leader = pos; - cur_leaders_grp = &pos->core; + cur_leader = pos->dont_regroup ? pos_leader : pos; + cur_leaders_grp = &cur_leader->core; if (pos_force_grouped) force_grouped_leader = pos; } From 12b413f5460c393d1151a37f591140693eca0f84 Mon Sep 17 00:00:00 2001 From: T Pratham Date: Wed, 8 Oct 2025 15:03:14 +0530 Subject: [PATCH 0444/2333] crypto: aead - Fix reqsize handling [ Upstream commit 9b04d8f00569573796dd05397f5779135593eb24 ] Commit afddce13ce81d ("crypto: api - Add reqsize to crypto_alg") introduced cra_reqsize field in crypto_alg struct to replace type specific reqsize fields. It looks like this was introduced specifically for ahash and acomp from the commit description as subsequent commits add necessary changes in these alg frameworks. However, this is being recommended for use in all crypto algs instead of setting reqsize using crypto_*_set_reqsize(). Using cra_reqsize in aead algorithms, hence, causes memory corruptions and crashes as the underlying functions in the algorithm framework have not been updated to set the reqsize properly from cra_reqsize. [1] Add proper set_reqsize calls in the aead init function to properly initialize reqsize for these algorithms in the framework. [1]: https://gist.github.com/Pratham-T/24247446f1faf4b7843e4014d5089f6b Fixes: afddce13ce81d ("crypto: api - Add reqsize to crypto_alg") Signed-off-by: T Pratham Signed-off-by: Herbert Xu Signed-off-by: Sasha Levin --- crypto/aead.c | 1 + 1 file changed, 1 insertion(+) diff --git a/crypto/aead.c b/crypto/aead.c index 5d14b775036ee..51ab3af691af2 100644 --- a/crypto/aead.c +++ b/crypto/aead.c @@ -120,6 +120,7 @@ static int crypto_aead_init_tfm(struct crypto_tfm *tfm) struct aead_alg *alg = crypto_aead_alg(aead); crypto_aead_set_flags(aead, CRYPTO_TFM_NEED_KEY); + crypto_aead_set_reqsize(aead, crypto_tfm_alg_reqsize(tfm)); aead->authsize = alg->maxauthsize; From a43afb170963876684ac895c4ea1bdb2f2bbf978 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Mon, 29 Sep 2025 20:13:22 +0200 Subject: [PATCH 0445/2333] PCI: sg2042: Fix a reference count issue in sg2042_pcie_remove() [ Upstream commit 932ec9dff6da40382ee63049a11a6ff047bdc259 ] devm_pm_runtime_enable() is used in the probe, so pm_runtime_disable() should not be called explicitly in the remove function. Fixes: 1c72774df028 ("PCI: sg2042: Add Sophgo SG2042 PCIe driver") Signed-off-by: Christophe JAILLET Signed-off-by: Manivannan Sadhasivam Tested-by: Chen Wang # on Pioneerbox. Acked-by: Chen Wang Link: https://patch.msgid.link/242eca0ff6601de7966a53706e9950fbcb10aac8.1759169586.git.christophe.jaillet@wanadoo.fr Signed-off-by: Sasha Levin --- drivers/pci/controller/cadence/pcie-sg2042.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/pci/controller/cadence/pcie-sg2042.c b/drivers/pci/controller/cadence/pcie-sg2042.c index a077b28d48949..0c50c74d03eeb 100644 --- a/drivers/pci/controller/cadence/pcie-sg2042.c +++ b/drivers/pci/controller/cadence/pcie-sg2042.c @@ -74,15 +74,12 @@ static int sg2042_pcie_probe(struct platform_device *pdev) static void sg2042_pcie_remove(struct platform_device *pdev) { struct cdns_pcie *pcie = platform_get_drvdata(pdev); - struct device *dev = &pdev->dev; struct cdns_pcie_rc *rc; rc = container_of(pcie, struct cdns_pcie_rc, pcie); cdns_pcie_host_disable(rc); cdns_pcie_disable_phy(pcie); - - pm_runtime_disable(dev); } static int sg2042_pcie_suspend_noirq(struct device *dev) From 95b122036d7a454f879954977ac0783f5c2dec13 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 13 Oct 2025 12:28:02 -0700 Subject: [PATCH 0446/2333] block/mq-deadline: Introduce dd_start_request() [ Upstream commit 93a358af59c6e8ab00b57cfdb1c437516a4948ca ] Prepare for adding a second caller of this function. No functionality has been changed. Cc: Damien Le Moal Cc: Yu Kuai Cc: chengkaitao Signed-off-by: Bart Van Assche Reviewed-by: Damien Le Moal Signed-off-by: Jens Axboe Stable-dep-of: d60055cf5270 ("block/mq-deadline: Switch back to a single dispatch list") Signed-off-by: Sasha Levin --- block/mq-deadline.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/block/mq-deadline.c b/block/mq-deadline.c index 3e741d33142d3..647a45f6d9352 100644 --- a/block/mq-deadline.c +++ b/block/mq-deadline.c @@ -306,6 +306,19 @@ static bool started_after(struct deadline_data *dd, struct request *rq, return time_after(start_time, latest_start); } +static struct request *dd_start_request(struct deadline_data *dd, + enum dd_data_dir data_dir, + struct request *rq) +{ + u8 ioprio_class = dd_rq_ioclass(rq); + enum dd_prio prio = ioprio_class_to_prio[ioprio_class]; + + dd->per_prio[prio].latest_pos[data_dir] = blk_rq_pos(rq); + dd->per_prio[prio].stats.dispatched++; + rq->rq_flags |= RQF_STARTED; + return rq; +} + /* * deadline_dispatch_requests selects the best request according to * read/write expire, fifo_batch, etc and with a start time <= @latest_start. @@ -316,8 +329,6 @@ static struct request *__dd_dispatch_request(struct deadline_data *dd, { struct request *rq, *next_rq; enum dd_data_dir data_dir; - enum dd_prio prio; - u8 ioprio_class; lockdep_assert_held(&dd->lock); @@ -411,12 +422,7 @@ static struct request *__dd_dispatch_request(struct deadline_data *dd, dd->batching++; deadline_move_request(dd, per_prio, rq); done: - ioprio_class = dd_rq_ioclass(rq); - prio = ioprio_class_to_prio[ioprio_class]; - dd->per_prio[prio].latest_pos[data_dir] = blk_rq_pos(rq); - dd->per_prio[prio].stats.dispatched++; - rq->rq_flags |= RQF_STARTED; - return rq; + return dd_start_request(dd, data_dir, rq); } /* From 204f13654142c91a6f01096ae7196a68eb3f32e9 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 13 Oct 2025 12:28:03 -0700 Subject: [PATCH 0447/2333] block/mq-deadline: Switch back to a single dispatch list [ Upstream commit d60055cf52703a705b86fb25b9b7931ec7ee399c ] Commit c807ab520fc3 ("block/mq-deadline: Add I/O priority support") modified the behavior of request flag BLK_MQ_INSERT_AT_HEAD from dispatching a request before other requests into dispatching a request before other requests with the same I/O priority. This is not correct since BLK_MQ_INSERT_AT_HEAD is used when requeuing requests and also when a flush request is inserted. Both types of requests should be dispatched as soon as possible. Hence, make the mq-deadline I/O scheduler again ignore the I/O priority for BLK_MQ_INSERT_AT_HEAD requests. Cc: Damien Le Moal Cc: Yu Kuai Reported-by: chengkaitao Closes: https://lore.kernel.org/linux-block/20251009155253.14611-1-pilgrimtao@gmail.com/ Fixes: c807ab520fc3 ("block/mq-deadline: Add I/O priority support") Signed-off-by: Bart Van Assche Reviewed-by: Damien Le Moalv Signed-off-by: Jens Axboe Signed-off-by: Sasha Levin --- block/mq-deadline.c | 107 +++++++++++++++++++------------------------- 1 file changed, 47 insertions(+), 60 deletions(-) diff --git a/block/mq-deadline.c b/block/mq-deadline.c index 647a45f6d9352..3e3719093aec7 100644 --- a/block/mq-deadline.c +++ b/block/mq-deadline.c @@ -71,7 +71,6 @@ struct io_stats_per_prio { * present on both sort_list[] and fifo_list[]. */ struct dd_per_prio { - struct list_head dispatch; struct rb_root sort_list[DD_DIR_COUNT]; struct list_head fifo_list[DD_DIR_COUNT]; /* Position of the most recently dispatched request. */ @@ -84,6 +83,7 @@ struct deadline_data { * run time data */ + struct list_head dispatch; struct dd_per_prio per_prio[DD_PRIO_COUNT]; /* Data direction of latest dispatched request. */ @@ -332,16 +332,6 @@ static struct request *__dd_dispatch_request(struct deadline_data *dd, lockdep_assert_held(&dd->lock); - if (!list_empty(&per_prio->dispatch)) { - rq = list_first_entry(&per_prio->dispatch, struct request, - queuelist); - if (started_after(dd, rq, latest_start)) - return NULL; - list_del_init(&rq->queuelist); - data_dir = rq_data_dir(rq); - goto done; - } - /* * batches are currently reads XOR writes */ @@ -421,7 +411,6 @@ static struct request *__dd_dispatch_request(struct deadline_data *dd, */ dd->batching++; deadline_move_request(dd, per_prio, rq); -done: return dd_start_request(dd, data_dir, rq); } @@ -469,6 +458,14 @@ static struct request *dd_dispatch_request(struct blk_mq_hw_ctx *hctx) enum dd_prio prio; spin_lock(&dd->lock); + + if (!list_empty(&dd->dispatch)) { + rq = list_first_entry(&dd->dispatch, struct request, queuelist); + list_del_init(&rq->queuelist); + dd_start_request(dd, rq_data_dir(rq), rq); + goto unlock; + } + rq = dd_dispatch_prio_aged_requests(dd, now); if (rq) goto unlock; @@ -557,10 +554,10 @@ static int dd_init_sched(struct request_queue *q, struct elevator_queue *eq) eq->elevator_data = dd; + INIT_LIST_HEAD(&dd->dispatch); for (prio = 0; prio <= DD_PRIO_MAX; prio++) { struct dd_per_prio *per_prio = &dd->per_prio[prio]; - INIT_LIST_HEAD(&per_prio->dispatch); INIT_LIST_HEAD(&per_prio->fifo_list[DD_READ]); INIT_LIST_HEAD(&per_prio->fifo_list[DD_WRITE]); per_prio->sort_list[DD_READ] = RB_ROOT; @@ -664,7 +661,7 @@ static void dd_insert_request(struct blk_mq_hw_ctx *hctx, struct request *rq, trace_block_rq_insert(rq); if (flags & BLK_MQ_INSERT_AT_HEAD) { - list_add(&rq->queuelist, &per_prio->dispatch); + list_add(&rq->queuelist, &dd->dispatch); rq->fifo_time = jiffies; } else { deadline_add_rq_rb(per_prio, rq); @@ -731,8 +728,7 @@ static void dd_finish_request(struct request *rq) static bool dd_has_work_for_prio(struct dd_per_prio *per_prio) { - return !list_empty_careful(&per_prio->dispatch) || - !list_empty_careful(&per_prio->fifo_list[DD_READ]) || + return !list_empty_careful(&per_prio->fifo_list[DD_READ]) || !list_empty_careful(&per_prio->fifo_list[DD_WRITE]); } @@ -741,6 +737,9 @@ static bool dd_has_work(struct blk_mq_hw_ctx *hctx) struct deadline_data *dd = hctx->queue->elevator->elevator_data; enum dd_prio prio; + if (!list_empty_careful(&dd->dispatch)) + return true; + for (prio = 0; prio <= DD_PRIO_MAX; prio++) if (dd_has_work_for_prio(&dd->per_prio[prio])) return true; @@ -949,49 +948,39 @@ static int dd_owned_by_driver_show(void *data, struct seq_file *m) return 0; } -#define DEADLINE_DISPATCH_ATTR(prio) \ -static void *deadline_dispatch##prio##_start(struct seq_file *m, \ - loff_t *pos) \ - __acquires(&dd->lock) \ -{ \ - struct request_queue *q = m->private; \ - struct deadline_data *dd = q->elevator->elevator_data; \ - struct dd_per_prio *per_prio = &dd->per_prio[prio]; \ - \ - spin_lock(&dd->lock); \ - return seq_list_start(&per_prio->dispatch, *pos); \ -} \ - \ -static void *deadline_dispatch##prio##_next(struct seq_file *m, \ - void *v, loff_t *pos) \ -{ \ - struct request_queue *q = m->private; \ - struct deadline_data *dd = q->elevator->elevator_data; \ - struct dd_per_prio *per_prio = &dd->per_prio[prio]; \ - \ - return seq_list_next(v, &per_prio->dispatch, pos); \ -} \ - \ -static void deadline_dispatch##prio##_stop(struct seq_file *m, void *v) \ - __releases(&dd->lock) \ -{ \ - struct request_queue *q = m->private; \ - struct deadline_data *dd = q->elevator->elevator_data; \ - \ - spin_unlock(&dd->lock); \ -} \ - \ -static const struct seq_operations deadline_dispatch##prio##_seq_ops = { \ - .start = deadline_dispatch##prio##_start, \ - .next = deadline_dispatch##prio##_next, \ - .stop = deadline_dispatch##prio##_stop, \ - .show = blk_mq_debugfs_rq_show, \ +static void *deadline_dispatch_start(struct seq_file *m, loff_t *pos) + __acquires(&dd->lock) +{ + struct request_queue *q = m->private; + struct deadline_data *dd = q->elevator->elevator_data; + + spin_lock(&dd->lock); + return seq_list_start(&dd->dispatch, *pos); } -DEADLINE_DISPATCH_ATTR(0); -DEADLINE_DISPATCH_ATTR(1); -DEADLINE_DISPATCH_ATTR(2); -#undef DEADLINE_DISPATCH_ATTR +static void *deadline_dispatch_next(struct seq_file *m, void *v, loff_t *pos) +{ + struct request_queue *q = m->private; + struct deadline_data *dd = q->elevator->elevator_data; + + return seq_list_next(v, &dd->dispatch, pos); +} + +static void deadline_dispatch_stop(struct seq_file *m, void *v) + __releases(&dd->lock) +{ + struct request_queue *q = m->private; + struct deadline_data *dd = q->elevator->elevator_data; + + spin_unlock(&dd->lock); +} + +static const struct seq_operations deadline_dispatch_seq_ops = { + .start = deadline_dispatch_start, + .next = deadline_dispatch_next, + .stop = deadline_dispatch_stop, + .show = blk_mq_debugfs_rq_show, +}; #define DEADLINE_QUEUE_DDIR_ATTRS(name) \ {#name "_fifo_list", 0400, \ @@ -1014,9 +1003,7 @@ static const struct blk_mq_debugfs_attr deadline_queue_debugfs_attrs[] = { {"batching", 0400, deadline_batching_show}, {"starved", 0400, deadline_starved_show}, {"async_depth", 0400, dd_async_depth_show}, - {"dispatch0", 0400, .seq_ops = &deadline_dispatch0_seq_ops}, - {"dispatch1", 0400, .seq_ops = &deadline_dispatch1_seq_ops}, - {"dispatch2", 0400, .seq_ops = &deadline_dispatch2_seq_ops}, + {"dispatch", 0400, .seq_ops = &deadline_dispatch_seq_ops}, {"owned_by_driver", 0400, dd_owned_by_driver_show}, {"queued", 0400, dd_queued_show}, {}, From fbea4c63b5385588cb44ab21f91e55e33c719a54 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Mon, 20 Oct 2025 09:54:41 +0200 Subject: [PATCH 0448/2333] bpf: Do not let BPF test infra emit invalid GSO types to stack [ Upstream commit 04a899573fb87273a656f178b5f920c505f68875 ] Yinhao et al. reported that their fuzzer tool was able to trigger a skb_warn_bad_offload() from netif_skb_features() -> gso_features_check(). When a BPF program - triggered via BPF test infra - pushes the packet to the loopback device via bpf_clone_redirect() then mentioned offload warning can be seen. GSO-related features are then rightfully disabled. We get into this situation due to convert___skb_to_skb() setting gso_segs and gso_size but not gso_type. Technically, it makes sense that this warning triggers since the GSO properties are malformed due to the gso_type. Potentially, the gso_type could be marked non-trustworthy through setting it at least to SKB_GSO_DODGY without any other specific assumptions, but that also feels wrong given we should not go further into the GSO engine in the first place. The checks were added in 121d57af308d ("gso: validate gso_type in GSO handlers") because there were malicious (syzbot) senders that combine a protocol with a non-matching gso_type. If we would want to drop such packets, gso_features_check() currently only returns feature flags via netif_skb_features(), so one location for potentially dropping such skbs could be validate_xmit_unreadable_skb(), but then otoh it would be an additional check in the fast-path for a very corner case. Given bpf_clone_redirect() is the only place where BPF test infra could emit such packets, lets reject them right there. Fixes: 850a88cc4096 ("bpf: Expose __sk_buff wire_len/gso_segs to BPF_PROG_TEST_RUN") Fixes: cf62089b0edd ("bpf: Add gso_size to __sk_buff") Reported-by: Yinhao Hu Reported-by: Kaiyan Mei Reported-by: Dongliang Mu Signed-off-by: Daniel Borkmann Signed-off-by: Martin KaFai Lau Link: https://patch.msgid.link/20251020075441.127980-1-daniel@iogearbox.net Signed-off-by: Sasha Levin --- net/bpf/test_run.c | 5 +++++ net/core/filter.c | 7 +++++++ 2 files changed, 12 insertions(+) diff --git a/net/bpf/test_run.c b/net/bpf/test_run.c index 8b7d0b90fea76..55a79337ac51f 100644 --- a/net/bpf/test_run.c +++ b/net/bpf/test_run.c @@ -939,6 +939,11 @@ static int convert___skb_to_skb(struct sk_buff *skb, struct __sk_buff *__skb) if (__skb->gso_segs > GSO_MAX_SEGS) return -EINVAL; + + /* Currently GSO type is zero/unset. If this gets extended with + * a small list of accepted GSO types in future, the filter for + * an unset GSO type in bpf_clone_redirect() can be lifted. + */ skb_shinfo(skb)->gso_segs = __skb->gso_segs; skb_shinfo(skb)->gso_size = __skb->gso_size; skb_shinfo(skb)->hwtstamps.hwtstamp = __skb->hwtstamp; diff --git a/net/core/filter.c b/net/core/filter.c index fa06c5a08e22f..1efec0d70d783 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -2458,6 +2458,13 @@ BPF_CALL_3(bpf_clone_redirect, struct sk_buff *, skb, u32, ifindex, u64, flags) if (unlikely(flags & (~(BPF_F_INGRESS) | BPF_F_REDIRECT_INTERNAL))) return -EINVAL; + /* BPF test infra's convert___skb_to_skb() can create type-less + * GSO packets. gso_features_check() will detect this as a bad + * offload. However, lets not leak them out in the first place. + */ + if (unlikely(skb_is_gso(skb) && !skb_shinfo(skb)->gso_type)) + return -EBADMSG; + dev = dev_get_by_index_rcu(dev_net(skb->dev), ifindex); if (unlikely(!dev)) return -EINVAL; From a45df9009fa81b7881865be0c16e87d428cbe630 Mon Sep 17 00:00:00 2001 From: Tim Harvey Date: Thu, 18 Sep 2025 08:44:45 -0700 Subject: [PATCH 0449/2333] arm64: dts: freescale: imx8mp-venice-gw7905-2x: remove duplicate usdhc1 props [ Upstream commit 8b7e58ab4a02601a0e86e9f9701d4612038d8b29 ] Remove the un-intended duplicate properties from usdhc1. Fixes: 0d5b288c2110e ("arm64: dts: freescale: Add imx8mp-venice-gw7905-2x") Signed-off-by: Tim Harvey Reviewed-by: Peng Fan Signed-off-by: Shawn Guo Signed-off-by: Sasha Levin --- arch/arm64/boot/dts/freescale/imx8mp-venice-gw702x.dtsi | 3 --- 1 file changed, 3 deletions(-) diff --git a/arch/arm64/boot/dts/freescale/imx8mp-venice-gw702x.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-venice-gw702x.dtsi index cbf0c9a740faa..303995a8adce8 100644 --- a/arch/arm64/boot/dts/freescale/imx8mp-venice-gw702x.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mp-venice-gw702x.dtsi @@ -423,9 +423,6 @@ bus-width = <4>; non-removable; status = "okay"; - bus-width = <4>; - non-removable; - status = "okay"; }; /* eMMC */ From 152044f4b08d282f41bd5a16d68644c2fded5a57 Mon Sep 17 00:00:00 2001 From: Tim Harvey Date: Thu, 18 Sep 2025 08:44:49 -0700 Subject: [PATCH 0450/2333] arm64: dts: imx8mm-venice-gw72xx: remove unused sdhc1 pinctrl [ Upstream commit d949b8d12d6e8fa119bca10d3157cd42e810f6f7 ] The SDHC1 interface is not used on the imx8mm-venice-gw72xx. Remove the unused pinctrl_usdhc1 iomux node. Fixes: 6f30b27c5ef5 ("arm64: dts: imx8mm: Add Gateworks i.MX 8M Mini Development Kits") Signed-off-by: Tim Harvey Reviewed-by: Peng Fan Signed-off-by: Shawn Guo Signed-off-by: Sasha Levin --- .../boot/dts/freescale/imx8mm-venice-gw72xx.dtsi | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw72xx.dtsi b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw72xx.dtsi index 752caa38eb03b..266038fbbef97 100644 --- a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw72xx.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw72xx.dtsi @@ -351,17 +351,6 @@ >; }; - pinctrl_usdhc1: usdhc1grp { - fsl,pins = < - MX8MM_IOMUXC_SD1_CLK_USDHC1_CLK 0x190 - MX8MM_IOMUXC_SD1_CMD_USDHC1_CMD 0x1d0 - MX8MM_IOMUXC_SD1_DATA0_USDHC1_DATA0 0x1d0 - MX8MM_IOMUXC_SD1_DATA1_USDHC1_DATA1 0x1d0 - MX8MM_IOMUXC_SD1_DATA2_USDHC1_DATA2 0x1d0 - MX8MM_IOMUXC_SD1_DATA3_USDHC1_DATA3 0x1d0 - >; - }; - pinctrl_usdhc2: usdhc2grp { fsl,pins = < MX8MM_IOMUXC_SD2_CLK_USDHC2_CLK 0x190 From 7e13775ed0b78f49c879fd003a51a0299ee7330e Mon Sep 17 00:00:00 2001 From: Tim Harvey Date: Thu, 18 Sep 2025 08:44:50 -0700 Subject: [PATCH 0451/2333] arm64: dts: imx8mp-venice-gw702x: remove off-board uart [ Upstream commit effe98060f70eb96e142f656e750d6af275ceac3 ] UART1 and UART3 go to a connector for use on a baseboard and as such are defined in the baseboard device-trees. Remove them from the gw702x SOM device-tree. Fixes: 0d5b288c2110 ("arm64: dts: freescale: Add imx8mp-venice-gw7905-2x") Signed-off-by: Tim Harvey Reviewed-by: Peng Fan Signed-off-by: Shawn Guo Signed-off-by: Sasha Levin --- .../dts/freescale/imx8mp-venice-gw702x.dtsi | 28 ------------------- 1 file changed, 28 deletions(-) diff --git a/arch/arm64/boot/dts/freescale/imx8mp-venice-gw702x.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-venice-gw702x.dtsi index 303995a8adce8..086ee4510cd83 100644 --- a/arch/arm64/boot/dts/freescale/imx8mp-venice-gw702x.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mp-venice-gw702x.dtsi @@ -395,13 +395,6 @@ status = "okay"; }; -/* off-board header */ -&uart1 { - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_uart1>; - status = "okay"; -}; - /* console */ &uart2 { pinctrl-names = "default"; @@ -409,13 +402,6 @@ status = "okay"; }; -/* off-board header */ -&uart3 { - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_uart3>; - status = "okay"; -}; - /* off-board */ &usdhc1 { pinctrl-names = "default"; @@ -520,13 +506,6 @@ >; }; - pinctrl_uart1: uart1grp { - fsl,pins = < - MX8MP_IOMUXC_UART1_RXD__UART1_DCE_RX 0x140 - MX8MP_IOMUXC_UART1_TXD__UART1_DCE_TX 0x140 - >; - }; - pinctrl_uart2: uart2grp { fsl,pins = < MX8MP_IOMUXC_UART2_RXD__UART2_DCE_RX 0x140 @@ -534,13 +513,6 @@ >; }; - pinctrl_uart3: uart3grp { - fsl,pins = < - MX8MP_IOMUXC_UART3_RXD__UART3_DCE_RX 0x140 - MX8MP_IOMUXC_UART3_TXD__UART3_DCE_TX 0x140 - >; - }; - pinctrl_usdhc1: usdhc1grp { fsl,pins = < MX8MP_IOMUXC_SD1_CLK__USDHC1_CLK 0x190 From a482d003391615f8c2d6a0f740086e1558c88614 Mon Sep 17 00:00:00 2001 From: Tim Harvey Date: Thu, 18 Sep 2025 08:44:51 -0700 Subject: [PATCH 0452/2333] arm64: dts: imx8mp-venice-gw702x: remove off-board sdhc1 [ Upstream commit 9db04b310ef99b546e4240c55842e81b06b78579 ] SDHC1 on the GW702x SOM routes to a connector for use on a baseboard and as such are defined in the baseboard device-trees. Remove it from the gw702x SOM device-tree. Fixes: 0d5b288c2110 ("arm64: dts: freescale: Add imx8mp-venice-gw7905-2x") Signed-off-by: Tim Harvey Reviewed-by: Peng Fan Signed-off-by: Shawn Guo Signed-off-by: Sasha Levin --- .../dts/freescale/imx8mp-venice-gw702x.dtsi | 20 ------------------- .../dts/freescale/imx8mp-venice-gw72xx.dtsi | 11 ---------- 2 files changed, 31 deletions(-) diff --git a/arch/arm64/boot/dts/freescale/imx8mp-venice-gw702x.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-venice-gw702x.dtsi index 086ee4510cd83..fb159199b39de 100644 --- a/arch/arm64/boot/dts/freescale/imx8mp-venice-gw702x.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mp-venice-gw702x.dtsi @@ -402,15 +402,6 @@ status = "okay"; }; -/* off-board */ -&usdhc1 { - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_usdhc1>; - bus-width = <4>; - non-removable; - status = "okay"; -}; - /* eMMC */ &usdhc3 { pinctrl-names = "default", "state_100mhz", "state_200mhz"; @@ -513,17 +504,6 @@ >; }; - pinctrl_usdhc1: usdhc1grp { - fsl,pins = < - MX8MP_IOMUXC_SD1_CLK__USDHC1_CLK 0x190 - MX8MP_IOMUXC_SD1_CMD__USDHC1_CMD 0x1d0 - MX8MP_IOMUXC_SD1_DATA0__USDHC1_DATA0 0x1d0 - MX8MP_IOMUXC_SD1_DATA1__USDHC1_DATA1 0x1d0 - MX8MP_IOMUXC_SD1_DATA2__USDHC1_DATA2 0x1d0 - MX8MP_IOMUXC_SD1_DATA3__USDHC1_DATA3 0x1d0 - >; - }; - pinctrl_usdhc3: usdhc3grp { fsl,pins = < MX8MP_IOMUXC_NAND_WE_B__USDHC3_CLK 0x190 diff --git a/arch/arm64/boot/dts/freescale/imx8mp-venice-gw72xx.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-venice-gw72xx.dtsi index cf747ec6fa16e..76020ef89bf3e 100644 --- a/arch/arm64/boot/dts/freescale/imx8mp-venice-gw72xx.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mp-venice-gw72xx.dtsi @@ -365,17 +365,6 @@ >; }; - pinctrl_usdhc1: usdhc1grp { - fsl,pins = < - MX8MP_IOMUXC_SD1_CLK__USDHC1_CLK 0x190 - MX8MP_IOMUXC_SD1_CMD__USDHC1_CMD 0x1d0 - MX8MP_IOMUXC_SD1_DATA0__USDHC1_DATA0 0x1d0 - MX8MP_IOMUXC_SD1_DATA1__USDHC1_DATA1 0x1d0 - MX8MP_IOMUXC_SD1_DATA2__USDHC1_DATA2 0x1d0 - MX8MP_IOMUXC_SD1_DATA3__USDHC1_DATA3 0x1d0 - >; - }; - pinctrl_usdhc2: usdhc2grp { fsl,pins = < MX8MP_IOMUXC_SD2_CLK__USDHC2_CLK 0x190 From 7ba92dd7206b147966f2d076eff8867b8b685f0d Mon Sep 17 00:00:00 2001 From: Joy Zou Date: Fri, 19 Sep 2025 10:27:04 +0800 Subject: [PATCH 0453/2333] arm64: dts: imx95-15x15-evk: add fan-supply property for pwm-fan [ Upstream commit 93b2fac5cdaf0d501d04c9a4b0e5024632a6af7c ] Add fan-supply regulator to pwm-fan node to specify power source. Fixes: e3e8b199aff8 ("arm64: dts: imx95: Add imx95-15x15-evk support") Signed-off-by: Joy Zou Reviewed-by: Frank Li Signed-off-by: Shawn Guo Signed-off-by: Sasha Levin --- arch/arm64/boot/dts/freescale/imx95-15x15-evk.dts | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/boot/dts/freescale/imx95-15x15-evk.dts b/arch/arm64/boot/dts/freescale/imx95-15x15-evk.dts index 148243470dd4a..0953c25ef5576 100644 --- a/arch/arm64/boot/dts/freescale/imx95-15x15-evk.dts +++ b/arch/arm64/boot/dts/freescale/imx95-15x15-evk.dts @@ -61,6 +61,7 @@ fan0: pwm-fan { compatible = "pwm-fan"; + fan-supply = <®_vcc_12v>; #cooling-cells = <2>; cooling-levels = <64 128 192 255>; pwms = <&tpm6 0 4000000 PWM_POLARITY_INVERTED>; From 9d231ef85d9a9f7aa86b3f4830b274b7e2fe4283 Mon Sep 17 00:00:00 2001 From: Tianyou Li Date: Mon, 20 Oct 2025 15:30:05 +0800 Subject: [PATCH 0454/2333] perf annotate: Check return value of evsel__get_arch() properly [ Upstream commit f1204e5846d22fb2fffbd1164eeb19535f306797 ] Check the error code of evsel__get_arch() in the symbol__annotate(). Previously it checked non-zero value but after the refactoring it does only for negative values. Fixes: 0669729eb0afb0cf ("perf annotate: Factor out evsel__get_arch()") Suggested-by: James Clark Acked-by: Namhyung Kim Signed-off-by: Tianyou Li Signed-off-by: Namhyung Kim Signed-off-by: Sasha Levin --- tools/perf/util/annotate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index a2e34f149a074..1d6900033b3a0 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -1021,7 +1021,7 @@ int symbol__annotate(struct map_symbol *ms, struct evsel *evsel, int err, nr; err = evsel__get_arch(evsel, &arch); - if (err < 0) + if (err) return err; if (parch) From 1321c33a8fc5eaa3fb6a54ad31e06614bedcc1e3 Mon Sep 17 00:00:00 2001 From: Peter Griffin Date: Mon, 13 Oct 2025 21:51:33 +0100 Subject: [PATCH 0455/2333] arm64: dts: exynos: gs101: fix clock module unit reg sizes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit ddb2a16804d005a96e8b5ffc0925e2f5bff65767 ] The memory map lists each clock module unit as having a size of 0x10000. Additionally there are some undocumented registers in this region that need to be used for automatic clock gating mode. Some of those registers also need to be saved/restored on suspend & resume. Fixes: 86124c76683e ("arm64: dts: exynos: gs101: enable cmu-hsi2 clock controller") Fixes: 4982a4a2092e ("arm64: dts: exynos: gs101: enable cmu-hsi0 clock controller") Fixes: 7d66d98b5bf3 ("arm64: dts: exynos: gs101: enable cmu-peric1 clock controller") Fixes: e62c706f3aa0 ("arm64: dts: exynos: gs101: enable cmu-peric0 clock controller") Fixes: ea89fdf24fd9 ("arm64: dts: exynos: google: Add initial Google gs101 SoC support") Signed-off-by: Peter Griffin Reviewed-by: André Draszik Link: https://patch.msgid.link/20251013-automatic-clocks-v1-4-72851ee00300@linaro.org Signed-off-by: Krzysztof Kozlowski Signed-off-by: Sasha Levin --- arch/arm64/boot/dts/exynos/google/gs101.dtsi | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/arch/arm64/boot/dts/exynos/google/gs101.dtsi b/arch/arm64/boot/dts/exynos/google/gs101.dtsi index 31c99526470d0..6335e0a8136be 100644 --- a/arch/arm64/boot/dts/exynos/google/gs101.dtsi +++ b/arch/arm64/boot/dts/exynos/google/gs101.dtsi @@ -288,7 +288,7 @@ cmu_misc: clock-controller@10010000 { compatible = "google,gs101-cmu-misc"; - reg = <0x10010000 0x8000>; + reg = <0x10010000 0x10000>; #clock-cells = <1>; clocks = <&cmu_top CLK_DOUT_CMU_MISC_BUS>, <&cmu_top CLK_DOUT_CMU_MISC_SSS>; @@ -365,7 +365,7 @@ cmu_peric0: clock-controller@10800000 { compatible = "google,gs101-cmu-peric0"; - reg = <0x10800000 0x4000>; + reg = <0x10800000 0x10000>; #clock-cells = <1>; clocks = <&ext_24_5m>, <&cmu_top CLK_DOUT_CMU_PERIC0_BUS>, @@ -911,7 +911,7 @@ cmu_peric1: clock-controller@10c00000 { compatible = "google,gs101-cmu-peric1"; - reg = <0x10c00000 0x4000>; + reg = <0x10c00000 0x10000>; #clock-cells = <1>; clocks = <&ext_24_5m>, <&cmu_top CLK_DOUT_CMU_PERIC1_BUS>, @@ -1265,7 +1265,7 @@ cmu_hsi0: clock-controller@11000000 { compatible = "google,gs101-cmu-hsi0"; - reg = <0x11000000 0x4000>; + reg = <0x11000000 0x10000>; #clock-cells = <1>; clocks = <&ext_24_5m>, @@ -1332,7 +1332,7 @@ cmu_hsi2: clock-controller@14400000 { compatible = "google,gs101-cmu-hsi2"; - reg = <0x14400000 0x4000>; + reg = <0x14400000 0x10000>; #clock-cells = <1>; clocks = <&ext_24_5m>, <&cmu_top CLK_DOUT_CMU_HSI2_BUS>, @@ -1395,7 +1395,7 @@ cmu_apm: clock-controller@17400000 { compatible = "google,gs101-cmu-apm"; - reg = <0x17400000 0x8000>; + reg = <0x17400000 0x10000>; #clock-cells = <1>; clocks = <&ext_24_5m>; @@ -1497,7 +1497,7 @@ cmu_top: clock-controller@1e080000 { compatible = "google,gs101-cmu-top"; - reg = <0x1e080000 0x8000>; + reg = <0x1e080000 0x10000>; #clock-cells = <1>; clocks = <&ext_24_5m>; From 4b9404cc439d41d394acedf4f6def3b786c6ef86 Mon Sep 17 00:00:00 2001 From: Peter Griffin Date: Mon, 13 Oct 2025 21:51:34 +0100 Subject: [PATCH 0456/2333] arm64: dts: exynos: gs101: fix sysreg_apm reg property MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 4348c22a4f15dbef1314f1a353d7f053b24e9ace ] Both the start address and size are incorrect for the apm_sysreg DT node. Update to match the TRM (rather than how it was defined downstream). Fixes: ea89fdf24fd9 ("arm64: dts: exynos: google: Add initial Google gs101 SoC support") Signed-off-by: Peter Griffin Reviewed-by: André Draszik Link: https://patch.msgid.link/20251013-automatic-clocks-v1-5-72851ee00300@linaro.org Signed-off-by: Krzysztof Kozlowski Signed-off-by: Sasha Levin --- arch/arm64/boot/dts/exynos/google/gs101.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/exynos/google/gs101.dtsi b/arch/arm64/boot/dts/exynos/google/gs101.dtsi index 6335e0a8136be..c01ff4e1b0d5d 100644 --- a/arch/arm64/boot/dts/exynos/google/gs101.dtsi +++ b/arch/arm64/boot/dts/exynos/google/gs101.dtsi @@ -1402,9 +1402,9 @@ clock-names = "oscclk"; }; - sysreg_apm: syscon@174204e0 { + sysreg_apm: syscon@17420000 { compatible = "google,gs101-apm-sysreg", "syscon"; - reg = <0x174204e0 0x1000>; + reg = <0x17420000 0x10000>; }; pmu_system_controller: system-controller@17460000 { From 712102126091c8aa8bc79afbadc2024e54dde67d Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 3 Oct 2025 10:35:34 +0200 Subject: [PATCH 0457/2333] PCI: rcar-gen2: Drop ARM dependency from PCI_RCAR_GEN2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit d312742f686582e6457070bcfd24bee8acfdf213 ] Since the reliance on ARM-specific struct pci_sys_data was removed, this driver can be compile-tested on other architectures. While at it, make the help text a bit more generic, as some members of the R-Car Gen2 family have a different number of internal PCI controllers. Fixes: 4a957563fe0231e0 ("PCI: rcar-gen2: Convert to use modern host bridge probe functions") Suggested-by: Ilpo Jarvinen Signed-off-by: Geert Uytterhoeven Signed-off-by: Manivannan Sadhasivam [bhelgaas: add rcar-gen2 to subject] Signed-off-by: Bjorn Helgaas Reviewed-by: Ilpo Järvinen Link: https://patch.msgid.link/00f75d6732eacce93f04ffaeedc415d2db714cd6.1759480426.git.geert+renesas@glider.be Signed-off-by: Sasha Levin --- drivers/pci/controller/Kconfig | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/pci/controller/Kconfig b/drivers/pci/controller/Kconfig index 41748d083b933..0452151a7bccc 100644 --- a/drivers/pci/controller/Kconfig +++ b/drivers/pci/controller/Kconfig @@ -259,12 +259,11 @@ config PCIE_RCAR_EP config PCI_RCAR_GEN2 bool "Renesas R-Car Gen2 Internal PCI controller" - depends on ARCH_RENESAS || COMPILE_TEST - depends on ARM + depends on (ARCH_RENESAS && ARM) || COMPILE_TEST help Say Y here if you want internal PCI support on R-Car Gen2 SoC. - There are 3 internal PCI controllers available with a single - built-in EHCI/OHCI host controller present on each one. + Each internal PCI controller contains a single built-in EHCI/OHCI + host controller. config PCIE_ROCKCHIP bool From 78bf5afa25d6a8838e61f99b45c150db10ff91a6 Mon Sep 17 00:00:00 2001 From: Li Qiang Date: Wed, 15 Oct 2025 14:40:20 +0800 Subject: [PATCH 0458/2333] uio: uio_fsl_elbc_gpcm:: Add null pointer check to uio_fsl_elbc_gpcm_probe [ Upstream commit d48fb15e6ad142e0577428a8c5028136e10c7b3d ] devm_kasprintf() returns a pointer to dynamically allocated memory which can be NULL upon failure. Fixes: d57801c45f53e ("uio: uio_fsl_elbc_gpcm: use device-managed allocators") Signed-off-by: Li Qiang Link: https://patch.msgid.link/20251015064020.56589-1-liqiang01@kylinos.cn Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin --- drivers/uio/uio_fsl_elbc_gpcm.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/uio/uio_fsl_elbc_gpcm.c b/drivers/uio/uio_fsl_elbc_gpcm.c index 81454c3e2484c..338dd2aaabc87 100644 --- a/drivers/uio/uio_fsl_elbc_gpcm.c +++ b/drivers/uio/uio_fsl_elbc_gpcm.c @@ -384,6 +384,11 @@ static int uio_fsl_elbc_gpcm_probe(struct platform_device *pdev) /* set all UIO data */ info->mem[0].name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%pOFn", node); + if (!info->mem[0].name) { + ret = -ENODEV; + goto out_err3; + } + info->mem[0].addr = res.start; info->mem[0].size = resource_size(&res); info->mem[0].memtype = UIO_MEM_PHYS; @@ -423,6 +428,8 @@ static int uio_fsl_elbc_gpcm_probe(struct platform_device *pdev) out_err2: if (priv->shutdown) priv->shutdown(info, true); + +out_err3: iounmap(info->mem[0].internal_addr); return ret; } From 9ff72116e6c86545b60da5c1eb5344858c3daadd Mon Sep 17 00:00:00 2001 From: Sherry Sun Date: Thu, 2 Oct 2025 12:52:58 +0800 Subject: [PATCH 0459/2333] tty: serial: imx: Only configure the wake register when device is set as wakeup source [ Upstream commit d55f3d2375ceeb08330d30f1e08196993c0b6583 ] Currently, the i.MX UART driver enables wake-related registers for all UART devices by default. However, this is unnecessary for devices that are not configured as wakeup sources. To address this, add a device_may_wakeup() check before configuring the UART wake-related registers. Fixes: db1a9b55004c ("tty: serial: imx: Allow UART to be a source for wakeup") Signed-off-by: Sherry Sun Reviewed-by: Frank Li Link: https://patch.msgid.link/20251002045259.2725461-2-sherry.sun@nxp.com Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin --- drivers/tty/serial/imx.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index 500dfc009d03e..90e2ea1e8afe5 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -2697,8 +2697,22 @@ static void imx_uart_save_context(struct imx_port *sport) /* called with irq off */ static void imx_uart_enable_wakeup(struct imx_port *sport, bool on) { + struct tty_port *port = &sport->port.state->port; + struct device *tty_dev; + bool may_wake = false; u32 ucr3; + scoped_guard(tty_port_tty, port) { + struct tty_struct *tty = scoped_tty(); + + tty_dev = tty->dev; + may_wake = tty_dev && device_may_wakeup(tty_dev); + } + + /* only configure the wake register when device set as wakeup source */ + if (!may_wake) + return; + uart_port_lock_irq(&sport->port); ucr3 = imx_uart_readl(sport, UCR3); From 69671a253ffe065eae90c637f5b8145626357b68 Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy Date: Wed, 22 Oct 2025 02:44:45 +0300 Subject: [PATCH 0460/2333] clk: qcom: camcc-sm8550: Specify Titan GDSC power domain as a parent to other [ Upstream commit d8f1121ebf4036884fc9ab1968f606523dd1c1fe ] When a consumer turns on/off a power domain dependent on another power domain in hardware, the parent power domain shall be turned on/off by the power domain provider as well, and to get it the power domain hardware hierarchy shall be described in the CAMCC driver. Establish the power domain hierarchy with a Titan GDSC set as a parent of all other GDSC power domains provided by the SM8550 camera clock controller to enforce a correct sequence of enabling and disabling power domains by the consumers, this fixes the CAMCC as a supplier of power domains to CAMSS IP and its driver. Fixes: ccc4e6a061a2 ("clk: qcom: camcc-sm8550: Add camera clock controller driver for SM8550") Reviewed-by: Konrad Dybcio Reviewed-by: Imran Shaik Reviewed-by: Bryan O'Donoghue Signed-off-by: Vladimir Zapolskiy Link: https://lore.kernel.org/r/20251021234450.2271279-2-vladimir.zapolskiy@linaro.org Signed-off-by: Bjorn Andersson Signed-off-by: Sasha Levin --- drivers/clk/qcom/camcc-sm8550.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/clk/qcom/camcc-sm8550.c b/drivers/clk/qcom/camcc-sm8550.c index 63aed9e4c362d..b8ece8a57a8a9 100644 --- a/drivers/clk/qcom/camcc-sm8550.c +++ b/drivers/clk/qcom/camcc-sm8550.c @@ -3204,6 +3204,8 @@ static struct clk_branch cam_cc_sfe_1_fast_ahb_clk = { }, }; +static struct gdsc cam_cc_titan_top_gdsc; + static struct gdsc cam_cc_bps_gdsc = { .gdscr = 0x10004, .en_rest_wait_val = 0x2, @@ -3213,6 +3215,7 @@ static struct gdsc cam_cc_bps_gdsc = { .name = "cam_cc_bps_gdsc", }, .pwrsts = PWRSTS_OFF_ON, + .parent = &cam_cc_titan_top_gdsc.pd, .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, }; @@ -3225,6 +3228,7 @@ static struct gdsc cam_cc_ife_0_gdsc = { .name = "cam_cc_ife_0_gdsc", }, .pwrsts = PWRSTS_OFF_ON, + .parent = &cam_cc_titan_top_gdsc.pd, .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, }; @@ -3237,6 +3241,7 @@ static struct gdsc cam_cc_ife_1_gdsc = { .name = "cam_cc_ife_1_gdsc", }, .pwrsts = PWRSTS_OFF_ON, + .parent = &cam_cc_titan_top_gdsc.pd, .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, }; @@ -3249,6 +3254,7 @@ static struct gdsc cam_cc_ife_2_gdsc = { .name = "cam_cc_ife_2_gdsc", }, .pwrsts = PWRSTS_OFF_ON, + .parent = &cam_cc_titan_top_gdsc.pd, .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, }; @@ -3261,6 +3267,7 @@ static struct gdsc cam_cc_ipe_0_gdsc = { .name = "cam_cc_ipe_0_gdsc", }, .pwrsts = PWRSTS_OFF_ON, + .parent = &cam_cc_titan_top_gdsc.pd, .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, }; @@ -3273,6 +3280,7 @@ static struct gdsc cam_cc_sbi_gdsc = { .name = "cam_cc_sbi_gdsc", }, .pwrsts = PWRSTS_OFF_ON, + .parent = &cam_cc_titan_top_gdsc.pd, .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, }; @@ -3285,6 +3293,7 @@ static struct gdsc cam_cc_sfe_0_gdsc = { .name = "cam_cc_sfe_0_gdsc", }, .pwrsts = PWRSTS_OFF_ON, + .parent = &cam_cc_titan_top_gdsc.pd, .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, }; @@ -3297,6 +3306,7 @@ static struct gdsc cam_cc_sfe_1_gdsc = { .name = "cam_cc_sfe_1_gdsc", }, .pwrsts = PWRSTS_OFF_ON, + .parent = &cam_cc_titan_top_gdsc.pd, .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, }; From 27fa51ddddb363a3b87f91c5e192cd5f0550de3f Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy Date: Wed, 22 Oct 2025 02:44:46 +0300 Subject: [PATCH 0461/2333] clk: qcom: camcc-sm6350: Specify Titan GDSC power domain as a parent to other [ Upstream commit a76ce61d7225934b0a52c8172a8cd944002a8c6f ] When a consumer turns on/off a power domain dependent on another power domain in hardware, the parent power domain shall be turned on/off by the power domain provider as well, and to get it the power domain hardware hierarchy shall be described in the CAMCC driver. Establish the power domain hierarchy with a Titan GDSC set as a parent of all other GDSC power domains provided by the SM6350 camera clock controller to enforce a correct sequence of enabling and disabling power domains by the consumers, this fixes the CAMCC as a supplier of power domains to CAMSS IP and its driver. Fixes: 80f5451d9a7c ("clk: qcom: Add camera clock controller driver for SM6350") Reviewed-by: Konrad Dybcio Reviewed-by: Imran Shaik Reviewed-by: Bryan O'Donoghue Signed-off-by: Vladimir Zapolskiy Link: https://lore.kernel.org/r/20251021234450.2271279-3-vladimir.zapolskiy@linaro.org Signed-off-by: Bjorn Andersson Signed-off-by: Sasha Levin --- drivers/clk/qcom/camcc-sm6350.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/clk/qcom/camcc-sm6350.c b/drivers/clk/qcom/camcc-sm6350.c index 8aac97d29ce3f..6c272f7b07219 100644 --- a/drivers/clk/qcom/camcc-sm6350.c +++ b/drivers/clk/qcom/camcc-sm6350.c @@ -1693,6 +1693,8 @@ static struct clk_branch camcc_sys_tmr_clk = { }, }; +static struct gdsc titan_top_gdsc; + static struct gdsc bps_gdsc = { .gdscr = 0x6004, .en_rest_wait_val = 0x2, @@ -1702,6 +1704,7 @@ static struct gdsc bps_gdsc = { .name = "bps_gdsc", }, .pwrsts = PWRSTS_OFF_ON, + .parent = &titan_top_gdsc.pd, .flags = VOTABLE, }; @@ -1714,6 +1717,7 @@ static struct gdsc ipe_0_gdsc = { .name = "ipe_0_gdsc", }, .pwrsts = PWRSTS_OFF_ON, + .parent = &titan_top_gdsc.pd, .flags = VOTABLE, }; @@ -1726,6 +1730,7 @@ static struct gdsc ife_0_gdsc = { .name = "ife_0_gdsc", }, .pwrsts = PWRSTS_OFF_ON, + .parent = &titan_top_gdsc.pd, }; static struct gdsc ife_1_gdsc = { @@ -1737,6 +1742,7 @@ static struct gdsc ife_1_gdsc = { .name = "ife_1_gdsc", }, .pwrsts = PWRSTS_OFF_ON, + .parent = &titan_top_gdsc.pd, }; static struct gdsc ife_2_gdsc = { @@ -1748,6 +1754,7 @@ static struct gdsc ife_2_gdsc = { .name = "ife_2_gdsc", }, .pwrsts = PWRSTS_OFF_ON, + .parent = &titan_top_gdsc.pd, }; static struct gdsc titan_top_gdsc = { From 6d9ed274d8da1a4532da4eb43b7340f4265ed54a Mon Sep 17 00:00:00 2001 From: Taniya Das Date: Wed, 24 Sep 2025 00:08:30 +0530 Subject: [PATCH 0462/2333] clk: qcom: gcc-sm8750: Add a new frequency for sdcc2 clock [ Upstream commit 393f7834cd2b1eaf4a9eff2701e706e73e660dd7 ] The SD card support requires a 37.5MHz clock; add it to the frequency list for the storage SW driver to be able to request for the frequency. Fixes: 3267c774f3ff ("clk: qcom: Add support for GCC on SM8750") Signed-off-by: Taniya Das Reviewed-by: Imran Shaik Link: https://lore.kernel.org/r/20250924-sm8750_gcc_sdcc2_frequency-v1-1-541fd321125f@oss.qualcomm.com Signed-off-by: Bjorn Andersson Signed-off-by: Sasha Levin --- drivers/clk/qcom/gcc-sm8750.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/qcom/gcc-sm8750.c b/drivers/clk/qcom/gcc-sm8750.c index 8092dd6b37b56..def86b71a3da5 100644 --- a/drivers/clk/qcom/gcc-sm8750.c +++ b/drivers/clk/qcom/gcc-sm8750.c @@ -1012,6 +1012,7 @@ static struct clk_rcg2 gcc_qupv3_wrap2_s7_clk_src = { static const struct freq_tbl ftbl_gcc_sdcc2_apps_clk_src[] = { F(400000, P_BI_TCXO, 12, 1, 4), F(25000000, P_GCC_GPLL0_OUT_EVEN, 12, 0, 0), + F(37500000, P_GCC_GPLL0_OUT_EVEN, 8, 0, 0), F(50000000, P_GCC_GPLL0_OUT_EVEN, 6, 0, 0), F(100000000, P_GCC_GPLL0_OUT_EVEN, 3, 0, 0), F(202000000, P_GCC_GPLL9_OUT_MAIN, 4, 0, 0), From 25dddde6564299f433d1a1acc680cb77fc452de4 Mon Sep 17 00:00:00 2001 From: Taniya Das Date: Thu, 25 Sep 2025 15:49:00 +0530 Subject: [PATCH 0463/2333] clk: qcom: gcc-glymur: Update the halt check flags for pipe clocks [ Upstream commit 18da820eb632fbd99167f3fc6650a30db714ddfd ] The pipe clocks for PCIE and USB are externally sourced and they should not be polled by the clock driver. Update the halt_check flags to 'SKIP' to disable polling for these clocks. This helps avoid the clock status stuck at 'off' warnings, which are benign, since all consumers of the PHYs must initialize a given instance before performing any operations. Fixes: efe504300a17 ("clk: qcom: gcc: Add support for Global Clock Controller") Reviewed-by: Konrad Dybcio Signed-off-by: Taniya Das Reviewed-by: Imran Shaik Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20250925-glymur_gcc_usb_fixes-v2-1-ee4619571efe@oss.qualcomm.com Signed-off-by: Bjorn Andersson Signed-off-by: Sasha Levin --- drivers/clk/qcom/gcc-glymur.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/clk/qcom/gcc-glymur.c b/drivers/clk/qcom/gcc-glymur.c index 62059120f9720..d938e7dc5b66e 100644 --- a/drivers/clk/qcom/gcc-glymur.c +++ b/drivers/clk/qcom/gcc-glymur.c @@ -6760,7 +6760,7 @@ static struct clk_branch gcc_usb3_prim_phy_com_aux_clk = { static struct clk_branch gcc_usb3_prim_phy_pipe_clk = { .halt_reg = 0x3f088, - .halt_check = BRANCH_HALT_DELAY, + .halt_check = BRANCH_HALT_SKIP, .hwcg_reg = 0x3f088, .hwcg_bit = 1, .clkr = { @@ -6816,7 +6816,7 @@ static struct clk_branch gcc_usb3_sec_phy_com_aux_clk = { static struct clk_branch gcc_usb3_sec_phy_pipe_clk = { .halt_reg = 0xe2078, - .halt_check = BRANCH_HALT_VOTED, + .halt_check = BRANCH_HALT_SKIP, .hwcg_reg = 0xe2078, .hwcg_bit = 1, .clkr = { @@ -6872,7 +6872,7 @@ static struct clk_branch gcc_usb3_tert_phy_com_aux_clk = { static struct clk_branch gcc_usb3_tert_phy_pipe_clk = { .halt_reg = 0xe1078, - .halt_check = BRANCH_HALT_VOTED, + .halt_check = BRANCH_HALT_SKIP, .hwcg_reg = 0xe1078, .hwcg_bit = 1, .clkr = { @@ -6961,7 +6961,7 @@ static struct clk_branch gcc_usb4_0_master_clk = { static struct clk_branch gcc_usb4_0_phy_p2rr2p_pipe_clk = { .halt_reg = 0x2b0f4, - .halt_check = BRANCH_HALT, + .halt_check = BRANCH_HALT_SKIP, .clkr = { .enable_reg = 0x2b0f4, .enable_mask = BIT(0), @@ -6979,7 +6979,7 @@ static struct clk_branch gcc_usb4_0_phy_p2rr2p_pipe_clk = { static struct clk_branch gcc_usb4_0_phy_pcie_pipe_clk = { .halt_reg = 0x2b04c, - .halt_check = BRANCH_HALT_VOTED, + .halt_check = BRANCH_HALT_SKIP, .clkr = { .enable_reg = 0x62010, .enable_mask = BIT(11), @@ -7033,7 +7033,7 @@ static struct clk_branch gcc_usb4_0_phy_rx1_clk = { static struct clk_branch gcc_usb4_0_phy_usb_pipe_clk = { .halt_reg = 0x2b0bc, - .halt_check = BRANCH_HALT_VOTED, + .halt_check = BRANCH_HALT_SKIP, .hwcg_reg = 0x2b0bc, .hwcg_bit = 1, .clkr = { @@ -7196,7 +7196,7 @@ static struct clk_branch gcc_usb4_1_master_clk = { static struct clk_branch gcc_usb4_1_phy_p2rr2p_pipe_clk = { .halt_reg = 0x2d118, - .halt_check = BRANCH_HALT, + .halt_check = BRANCH_HALT_SKIP, .clkr = { .enable_reg = 0x2d118, .enable_mask = BIT(0), @@ -7214,7 +7214,7 @@ static struct clk_branch gcc_usb4_1_phy_p2rr2p_pipe_clk = { static struct clk_branch gcc_usb4_1_phy_pcie_pipe_clk = { .halt_reg = 0x2d04c, - .halt_check = BRANCH_HALT_VOTED, + .halt_check = BRANCH_HALT_SKIP, .clkr = { .enable_reg = 0x62010, .enable_mask = BIT(12), @@ -7268,7 +7268,7 @@ static struct clk_branch gcc_usb4_1_phy_rx1_clk = { static struct clk_branch gcc_usb4_1_phy_usb_pipe_clk = { .halt_reg = 0x2d0e0, - .halt_check = BRANCH_HALT_VOTED, + .halt_check = BRANCH_HALT_SKIP, .hwcg_reg = 0x2d0e0, .hwcg_bit = 1, .clkr = { @@ -7431,7 +7431,7 @@ static struct clk_branch gcc_usb4_2_master_clk = { static struct clk_branch gcc_usb4_2_phy_p2rr2p_pipe_clk = { .halt_reg = 0xe00f8, - .halt_check = BRANCH_HALT, + .halt_check = BRANCH_HALT_SKIP, .clkr = { .enable_reg = 0xe00f8, .enable_mask = BIT(0), @@ -7449,7 +7449,7 @@ static struct clk_branch gcc_usb4_2_phy_p2rr2p_pipe_clk = { static struct clk_branch gcc_usb4_2_phy_pcie_pipe_clk = { .halt_reg = 0xe004c, - .halt_check = BRANCH_HALT_VOTED, + .halt_check = BRANCH_HALT_SKIP, .clkr = { .enable_reg = 0x62010, .enable_mask = BIT(13), @@ -7503,7 +7503,7 @@ static struct clk_branch gcc_usb4_2_phy_rx1_clk = { static struct clk_branch gcc_usb4_2_phy_usb_pipe_clk = { .halt_reg = 0xe00c0, - .halt_check = BRANCH_HALT_VOTED, + .halt_check = BRANCH_HALT_SKIP, .hwcg_reg = 0xe00c0, .hwcg_bit = 1, .clkr = { From b2427d5693c37a19c80a66db0dda9cba7dcb23a4 Mon Sep 17 00:00:00 2001 From: Luo Jie Date: Tue, 14 Oct 2025 22:35:26 +0800 Subject: [PATCH 0464/2333] clk: qcom: gcc-ipq5424: Correct the icc_first_node_id [ Upstream commit 464ce94531f5a62ce29081a9d3c70eb4d525f443 ] Update to use the expected icc_first_node_id for registering the icc clocks, ensuring correct association of clocks with interconnect nodes. Fixes: 170f3d2c065e ("clk: qcom: ipq5424: Use icc-clk for enabling NoC related clocks") Reviewed-by: Konrad Dybcio Signed-off-by: Luo Jie Link: https://lore.kernel.org/r/20251014-qcom_ipq5424_nsscc-v7-1-081f4956be02@quicinc.com Signed-off-by: Bjorn Andersson Signed-off-by: Sasha Levin --- drivers/clk/qcom/gcc-ipq5424.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/clk/qcom/gcc-ipq5424.c b/drivers/clk/qcom/gcc-ipq5424.c index 3d42f3d85c7a9..71afa1b86b723 100644 --- a/drivers/clk/qcom/gcc-ipq5424.c +++ b/drivers/clk/qcom/gcc-ipq5424.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2018,2020 The Linux Foundation. All rights reserved. - * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include @@ -3284,6 +3284,7 @@ static const struct qcom_cc_desc gcc_ipq5424_desc = { .num_clk_hws = ARRAY_SIZE(gcc_ipq5424_hws), .icc_hws = icc_ipq5424_hws, .num_icc_hws = ARRAY_SIZE(icc_ipq5424_hws), + .icc_first_node_id = IPQ_APPS_ID, }; static int gcc_ipq5424_probe(struct platform_device *pdev) From 680df1f60e027ca06f380b297e25666988f70ae7 Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Tue, 21 Oct 2025 20:08:54 +0200 Subject: [PATCH 0465/2333] clk: qcom: camcc-sm6350: Fix PLL config of PLL2 [ Upstream commit ab0e13141d679fdffdd3463a272c5c1b10be1794 ] The 'Agera' PLLs (with clk_agera_pll_configure) do not take some of the parameters that are provided in the vendor driver. Instead the upstream configuration should provide the final user_ctl value that is written to the USER_CTL register. Fix the config so that the PLL is configured correctly, and fixes CAMCC_MCLK* being stuck off. Fixes: 80f5451d9a7c ("clk: qcom: Add camera clock controller driver for SM6350") Suggested-by: Taniya Das Signed-off-by: Luca Weiss Reviewed-by: Abel Vesa Reviewed-by: Taniya Das Link: https://lore.kernel.org/r/20251021-agera-pll-fixups-v1-1-8c1d8aff4afc@fairphone.com Signed-off-by: Bjorn Andersson Signed-off-by: Sasha Levin --- drivers/clk/qcom/camcc-sm6350.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/clk/qcom/camcc-sm6350.c b/drivers/clk/qcom/camcc-sm6350.c index 6c272f7b07219..7df12c1311c68 100644 --- a/drivers/clk/qcom/camcc-sm6350.c +++ b/drivers/clk/qcom/camcc-sm6350.c @@ -145,15 +145,11 @@ static struct clk_alpha_pll_postdiv camcc_pll1_out_even = { static const struct alpha_pll_config camcc_pll2_config = { .l = 0x64, .alpha = 0x0, - .post_div_val = 0x3 << 8, - .post_div_mask = 0x3 << 8, - .aux_output_mask = BIT(1), - .main_output_mask = BIT(0), - .early_output_mask = BIT(3), .config_ctl_val = 0x20000800, .config_ctl_hi_val = 0x400003d2, .test_ctl_val = 0x04000400, .test_ctl_hi_val = 0x00004000, + .user_ctl_val = 0x0000030b, }; static struct clk_alpha_pll camcc_pll2 = { From 37b8870d96d4daa639f19b7aba5d85e96f3ff16b Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Tue, 21 Oct 2025 20:08:55 +0200 Subject: [PATCH 0466/2333] clk: qcom: camcc-sm7150: Fix PLL config of PLL2 [ Upstream commit 415aad75c7e5cdb72e0672dc1159be1a99535ecd ] The 'Agera' PLLs (with clk_agera_pll_configure) do not take some of the parameters that are provided in the vendor driver. Instead the upstream configuration should provide the final user_ctl value that is written to the USER_CTL register. Fix the config so that the PLL is configured correctly. Fixes: 9f0532da4226 ("clk: qcom: Add Camera Clock Controller driver for SM7150") Suggested-by: Taniya Das Signed-off-by: Luca Weiss Reviewed-by: Abel Vesa Reviewed-by: Taniya Das Link: https://lore.kernel.org/r/20251021-agera-pll-fixups-v1-2-8c1d8aff4afc@fairphone.com Signed-off-by: Bjorn Andersson Signed-off-by: Sasha Levin --- drivers/clk/qcom/camcc-sm7150.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/clk/qcom/camcc-sm7150.c b/drivers/clk/qcom/camcc-sm7150.c index 4a3baf5d8e858..590548cac45bf 100644 --- a/drivers/clk/qcom/camcc-sm7150.c +++ b/drivers/clk/qcom/camcc-sm7150.c @@ -139,13 +139,9 @@ static struct clk_fixed_factor camcc_pll1_out_even = { /* 1920MHz configuration */ static const struct alpha_pll_config camcc_pll2_config = { .l = 0x64, - .post_div_val = 0x3 << 8, - .post_div_mask = 0x3 << 8, - .early_output_mask = BIT(3), - .aux_output_mask = BIT(1), - .main_output_mask = BIT(0), .config_ctl_hi_val = 0x400003d6, .config_ctl_val = 0x20000954, + .user_ctl_val = 0x0000030b, }; static struct clk_alpha_pll camcc_pll2 = { From 599b5f3f4224a53c7622e7ddf12cfaa8ee78aa35 Mon Sep 17 00:00:00 2001 From: Haotian Zhang Date: Tue, 21 Oct 2025 00:02:15 +0800 Subject: [PATCH 0467/2333] soc: qcom: gsbi: fix double disable caused by devm [ Upstream commit 2286e18e3937c69cc103308a8c1d4898d8a7b04f ] In the commit referenced by the Fixes tag, devm_clk_get_enabled() was introduced to replace devm_clk_get() and clk_prepare_enable(). While the clk_disable_unprepare() call in the error path was correctly removed, the one in the remove function was overlooked, leading to a double disable issue. Remove the redundant clk_disable_unprepare() call from gsbi_remove() to fix this issue. Since all resources are now managed by devres and will be automatically released, the remove function serves no purpose and can be deleted entirely. Fixes: 489d7a8cc286 ("soc: qcom: use devm_clk_get_enabled() in gsbi_probe()") Signed-off-by: Haotian Zhang Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/stable/20251020160215.523-1-vulab%40iscas.ac.cn Link: https://lore.kernel.org/r/20251020160215.523-1-vulab@iscas.ac.cn Signed-off-by: Bjorn Andersson Signed-off-by: Sasha Levin --- drivers/soc/qcom/qcom_gsbi.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/soc/qcom/qcom_gsbi.c b/drivers/soc/qcom/qcom_gsbi.c index 8f1158e0c6313..a25d1de592f06 100644 --- a/drivers/soc/qcom/qcom_gsbi.c +++ b/drivers/soc/qcom/qcom_gsbi.c @@ -212,13 +212,6 @@ static int gsbi_probe(struct platform_device *pdev) return of_platform_populate(node, NULL, NULL, &pdev->dev); } -static void gsbi_remove(struct platform_device *pdev) -{ - struct gsbi_info *gsbi = platform_get_drvdata(pdev); - - clk_disable_unprepare(gsbi->hclk); -} - static const struct of_device_id gsbi_dt_match[] = { { .compatible = "qcom,gsbi-v1.0.0", }, { }, @@ -232,7 +225,6 @@ static struct platform_driver gsbi_driver = { .of_match_table = gsbi_dt_match, }, .probe = gsbi_probe, - .remove = gsbi_remove, }; module_platform_driver(gsbi_driver); From b7090a5c153105b9fd221a5a81459ee8cd5babd6 Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Mon, 13 Oct 2025 13:40:10 +0200 Subject: [PATCH 0468/2333] crypto: asymmetric_keys - prevent overflow in asymmetric_key_generate_id [ Upstream commit df0845cf447ae1556c3440b8b155de0926cbaa56 ] Use check_add_overflow() to guard against potential integer overflows when adding the binary blob lengths and the size of an asymmetric_key_id structure and return ERR_PTR(-EOVERFLOW) accordingly. This prevents a possible buffer overflow when copying data from potentially malicious X.509 certificate fields that can be arbitrarily large, such as ASN.1 INTEGER serial numbers, issuer names, etc. Fixes: 7901c1a8effb ("KEYS: Implement binary asymmetric key ID handling") Signed-off-by: Thorsten Blum Reviewed-by: Lukas Wunner Signed-off-by: Herbert Xu Signed-off-by: Sasha Levin --- crypto/asymmetric_keys/asymmetric_type.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/crypto/asymmetric_keys/asymmetric_type.c b/crypto/asymmetric_keys/asymmetric_type.c index ba2d9d1ea235a..348966ea2175c 100644 --- a/crypto/asymmetric_keys/asymmetric_type.c +++ b/crypto/asymmetric_keys/asymmetric_type.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -141,12 +142,17 @@ struct asymmetric_key_id *asymmetric_key_generate_id(const void *val_1, size_t len_2) { struct asymmetric_key_id *kid; - - kid = kmalloc(sizeof(struct asymmetric_key_id) + len_1 + len_2, - GFP_KERNEL); + size_t kid_sz; + size_t len; + + if (check_add_overflow(len_1, len_2, &len)) + return ERR_PTR(-EOVERFLOW); + if (check_add_overflow(sizeof(struct asymmetric_key_id), len, &kid_sz)) + return ERR_PTR(-EOVERFLOW); + kid = kmalloc(kid_sz, GFP_KERNEL); if (!kid) return ERR_PTR(-ENOMEM); - kid->len = len_1 + len_2; + kid->len = len; memcpy(kid->data, val_1, len_1); memcpy(kid->data + len_1, val_2, len_2); return kid; From 5c75e55e43e8699ee1189ee568a5157753d097c1 Mon Sep 17 00:00:00 2001 From: nieweiqiang Date: Sat, 18 Oct 2025 19:27:39 +0800 Subject: [PATCH 0469/2333] crypto: hisilicon/qm - restore original qos values [ Upstream commit e7066160f5b4187ad9869b712fa7a35d3d5be6b9 ] When the new qos valus setting fails, restore to the original qos values. Fixes: 72b010dc33b9 ("crypto: hisilicon/qm - supports writing QoS int the host") Signed-off-by: nieweiqiang Signed-off-by: Chenghai Huang Signed-off-by: Herbert Xu Signed-off-by: Sasha Levin --- drivers/crypto/hisilicon/qm.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/crypto/hisilicon/qm.c b/drivers/crypto/hisilicon/qm.c index 3b391a1466353..0968304c0cb51 100644 --- a/drivers/crypto/hisilicon/qm.c +++ b/drivers/crypto/hisilicon/qm.c @@ -3678,6 +3678,7 @@ static void qm_clear_vft_config(struct hisi_qm *qm) static int qm_func_shaper_enable(struct hisi_qm *qm, u32 fun_index, u32 qos) { struct device *dev = &qm->pdev->dev; + struct qm_shaper_factor t_factor; u32 ir = qos * QM_QOS_RATE; int ret, total_vfs, i; @@ -3685,6 +3686,7 @@ static int qm_func_shaper_enable(struct hisi_qm *qm, u32 fun_index, u32 qos) if (fun_index > total_vfs) return -EINVAL; + memcpy(&t_factor, &qm->factor[fun_index], sizeof(t_factor)); qm->factor[fun_index].func_qos = qos; ret = qm_get_shaper_para(ir, &qm->factor[fun_index]); @@ -3698,11 +3700,21 @@ static int qm_func_shaper_enable(struct hisi_qm *qm, u32 fun_index, u32 qos) ret = qm_set_vft_common(qm, SHAPER_VFT, fun_index, i, 1); if (ret) { dev_err(dev, "type: %d, failed to set shaper vft!\n", i); - return -EINVAL; + goto back_func_qos; } } return 0; + +back_func_qos: + memcpy(&qm->factor[fun_index], &t_factor, sizeof(t_factor)); + for (i--; i >= ALG_TYPE_0; i--) { + ret = qm_set_vft_common(qm, SHAPER_VFT, fun_index, i, 1); + if (ret) + dev_err(dev, "failed to restore shaper vft during rollback!\n"); + } + + return -EINVAL; } static u32 qm_get_shaper_vft_qos(struct hisi_qm *qm, u32 fun_index) From 18d4706956b73895ea75131b827a76c24775348c Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Fri, 17 Oct 2025 09:48:59 +0800 Subject: [PATCH 0470/2333] wifi: ath11k: fix VHT MCS assignment [ Upstream commit 47d0cd6bccb4604192633cc8d29511e85d811fc0 ] While associating, firmware needs to know peer's receive capability to calculate its own VHT transmit MCS, currently host sends this information to firmware via mcs->rx_mcs_set field, this is wrong as firmware actually takes it from mcs->tx_mcs_set field. Till now there is no failure seen due to this, most likely because almost all peers are advertising the same capability for both transmit and receive. Swap the assignment to fix it. Besides, rate control mask is meant to limit our own transmit MCS, hence need to go via mcs->tx_mcs_set field. With the aforementioned swapping done, change is needed as well to apply it to the peer's receive capability rather than transmit capability. Tested-on: WCN6855 hw2.1 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.41 Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.4.1-00199-QCAHKSWPL_SILICONZ-1 Fixes: d5c65159f289 ("ath11k: driver for Qualcomm IEEE 802.11ax devices") Signed-off-by: Baochen Qiang Reviewed-by: Vasanthakumar Thiagarajan Link: https://patch.msgid.link/20251017-ath11k-mcs-assignment-v1-1-da40825c1783@oss.qualcomm.com Signed-off-by: Jeff Johnson Signed-off-by: Sasha Levin --- drivers/net/wireless/ath/ath11k/mac.c | 4 ++-- drivers/net/wireless/ath/ath11k/wmi.c | 13 ++++++++----- drivers/net/wireless/ath/ath11k/wmi.h | 2 ++ 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index 0e41b5a91d66d..49c639d73d58d 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -2235,9 +2235,9 @@ static void ath11k_peer_assoc_h_vht(struct ath11k *ar, arg->peer_nss = min(sta->deflink.rx_nss, max_nss); arg->rx_max_rate = __le16_to_cpu(vht_cap->vht_mcs.rx_highest); arg->rx_mcs_set = __le16_to_cpu(vht_cap->vht_mcs.rx_mcs_map); + arg->rx_mcs_set = ath11k_peer_assoc_h_vht_limit(arg->rx_mcs_set, vht_mcs_mask); arg->tx_max_rate = __le16_to_cpu(vht_cap->vht_mcs.tx_highest); - arg->tx_mcs_set = ath11k_peer_assoc_h_vht_limit( - __le16_to_cpu(vht_cap->vht_mcs.tx_mcs_map), vht_mcs_mask); + arg->tx_mcs_set = __le16_to_cpu(vht_cap->vht_mcs.tx_mcs_map); /* In IPQ8074 platform, VHT mcs rate 10 and 11 is enabled by default. * VHT mcs rate 10 and 11 is not supported in 11ac standard. diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c index e3b444333deed..649839d243293 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.c +++ b/drivers/net/wireless/ath/ath11k/wmi.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include #include @@ -2061,10 +2061,13 @@ int ath11k_wmi_send_peer_assoc_cmd(struct ath11k *ar, cmd->peer_bw_rxnss_override |= param->peer_bw_rxnss_override; if (param->vht_capable) { - mcs->rx_max_rate = param->rx_max_rate; - mcs->rx_mcs_set = param->rx_mcs_set; - mcs->tx_max_rate = param->tx_max_rate; - mcs->tx_mcs_set = param->tx_mcs_set; + /* firmware interprets mcs->tx_mcs_set field as peer's + * RX capability + */ + mcs->tx_max_rate = param->rx_max_rate; + mcs->tx_mcs_set = param->rx_mcs_set; + mcs->rx_max_rate = param->tx_max_rate; + mcs->rx_mcs_set = param->tx_mcs_set; } /* HE Rates */ diff --git a/drivers/net/wireless/ath/ath11k/wmi.h b/drivers/net/wireless/ath/ath11k/wmi.h index 9fcffaa2f383c..6e9354297e71d 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.h +++ b/drivers/net/wireless/ath/ath11k/wmi.h @@ -4133,8 +4133,10 @@ struct wmi_rate_set { struct wmi_vht_rate_set { u32 tlv_header; u32 rx_max_rate; + /* MCS at which the peer can transmit */ u32 rx_mcs_set; u32 tx_max_rate; + /* MCS at which the peer can receive */ u32 tx_mcs_set; u32 tx_max_mcs_nss; } __packed; From 6b1a0da75932353f66e710976ca85a7131f647ff Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Fri, 17 Oct 2025 09:49:00 +0800 Subject: [PATCH 0471/2333] wifi: ath11k: fix peer HE MCS assignment [ Upstream commit 4a013ca2d490c73c40588d62712ffaa432046a04 ] In ath11k_wmi_send_peer_assoc_cmd(), peer's transmit MCS is sent to firmware as receive MCS while peer's receive MCS sent as transmit MCS, which goes against firmwire's definition. While connecting to a misbehaved AP that advertises 0xffff (meaning not supported) for 160 MHz transmit MCS map, firmware crashes due to 0xffff is assigned to he_mcs->rx_mcs_set field. Ext Tag: HE Capabilities [...] Supported HE-MCS and NSS Set [...] Rx and Tx MCS Maps 160 MHz [...] Tx HE-MCS Map 160 MHz: 0xffff Swap the assignment to fix this issue. As the HE rate control mask is meant to limit our own transmit MCS, it needs to go via he_mcs->rx_mcs_set field. With the aforementioned swapping done, change is needed as well to apply it to the peer's receive MCS. Tested-on: WCN6855 hw2.1 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.41 Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.4.1-00199-QCAHKSWPL_SILICONZ-1 Fixes: 61fe43e7216d ("ath11k: add support for setting fixed HE rate/gi/ltf") Signed-off-by: Baochen Qiang Reviewed-by: Vasanthakumar Thiagarajan Link: https://patch.msgid.link/20251017-ath11k-mcs-assignment-v1-2-da40825c1783@oss.qualcomm.com Signed-off-by: Jeff Johnson Signed-off-by: Sasha Levin --- drivers/net/wireless/ath/ath11k/mac.c | 4 ++-- drivers/net/wireless/ath/ath11k/wmi.c | 7 +++++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index 49c639d73d58d..f142c17aa9aa7 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -2522,10 +2522,10 @@ static void ath11k_peer_assoc_h_he(struct ath11k *ar, he_tx_mcs = v; } v = le16_to_cpu(he_cap->he_mcs_nss_supp.rx_mcs_160); + v = ath11k_peer_assoc_h_he_limit(v, he_mcs_mask); arg->peer_he_rx_mcs_set[WMI_HECAP_TXRX_MCS_NSS_IDX_160] = v; v = le16_to_cpu(he_cap->he_mcs_nss_supp.tx_mcs_160); - v = ath11k_peer_assoc_h_he_limit(v, he_mcs_mask); arg->peer_he_tx_mcs_set[WMI_HECAP_TXRX_MCS_NSS_IDX_160] = v; arg->peer_he_mcs_count++; @@ -2535,10 +2535,10 @@ static void ath11k_peer_assoc_h_he(struct ath11k *ar, default: v = le16_to_cpu(he_cap->he_mcs_nss_supp.rx_mcs_80); + v = ath11k_peer_assoc_h_he_limit(v, he_mcs_mask); arg->peer_he_rx_mcs_set[WMI_HECAP_TXRX_MCS_NSS_IDX_80] = v; v = le16_to_cpu(he_cap->he_mcs_nss_supp.tx_mcs_80); - v = ath11k_peer_assoc_h_he_limit(v, he_mcs_mask); arg->peer_he_tx_mcs_set[WMI_HECAP_TXRX_MCS_NSS_IDX_80] = v; arg->peer_he_mcs_count++; diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c index 649839d243293..110035dae8a61 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.c +++ b/drivers/net/wireless/ath/ath11k/wmi.c @@ -2091,8 +2091,11 @@ int ath11k_wmi_send_peer_assoc_cmd(struct ath11k *ar, FIELD_PREP(WMI_TLV_LEN, sizeof(*he_mcs) - TLV_HDR_SIZE); - he_mcs->rx_mcs_set = param->peer_he_tx_mcs_set[i]; - he_mcs->tx_mcs_set = param->peer_he_rx_mcs_set[i]; + /* firmware interprets mcs->rx_mcs_set field as peer's + * RX capability + */ + he_mcs->rx_mcs_set = param->peer_he_rx_mcs_set[i]; + he_mcs->tx_mcs_set = param->peer_he_tx_mcs_set[i]; ptr += sizeof(*he_mcs); } From 1acc6fc225a9cf872425be5d6ffde6ea5d42bb4f Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Mon, 20 Oct 2025 16:17:54 +0200 Subject: [PATCH 0472/2333] s390/smp: Fix fallback CPU detection [ Upstream commit 07a75d08cfa1b883a6e1256666e5f0617ee99231 ] In case SCLP CPU detection does not work a fallback mechanism using SIGP is in place. Since a cleanup this does not work correctly anymore: new CPUs are only considered if their type matches the boot CPU. Before the cleanup the information if a CPU type should be considered was also part of a structure generated by the fallback mechanism and indicated that a CPU type should not be considered when adding CPUs. Since the rework a global SCLP state is used instead. If the global SCLP state indicates that the CPU type should be considered and the fallback mechanism is used, there may be a mismatch with CPU types if CPUs are added. This can lead to a system with only a single CPU even tough there are many more CPUs. Address this by simply copying the boot cpu type into the generated data structure from the fallback mechanism. Reported-by: Alexander Egorenkov Fixes: d08d94306e90 ("s390/smp: cleanup core vs. cpu in the SCLP interface") Reviewed-by: Mete Durlu Signed-off-by: Heiko Carstens Signed-off-by: Sasha Levin --- arch/s390/kernel/smp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index da84c0dc6b7e0..70df4ca5d4436 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c @@ -697,6 +697,7 @@ static void __ref smp_get_core_info(struct sclp_core_info *info, int early) continue; info->core[info->configured].core_id = address >> smp_cpu_mt_shift; + info->core[info->configured].type = boot_core_type; info->configured++; } info->combined = info->configured; From 27c62aeef710d443dd24e16bb9d05013db737f37 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 14 Oct 2025 13:00:58 -0700 Subject: [PATCH 0473/2333] scsi: ufs: core: Move the ufshcd_enable_intr() declaration [ Upstream commit b30006b5bec1dcba207bc42e7f7cd96a568acc27 ] ufshcd_enable_intr() is not exported and hence should not be declared in include/ufs/ufshcd.h. Fixes: 253757797973 ("scsi: ufs: core: Change MCQ interrupt enable flow") Signed-off-by: Bart Van Assche Reviewed-by: Peter Wang Link: https://patch.msgid.link/20251014200118.3390839-7-bvanassche@acm.org Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin --- drivers/ufs/core/ufshcd-priv.h | 2 ++ include/ufs/ufshcd.h | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/ufs/core/ufshcd-priv.h b/drivers/ufs/core/ufshcd-priv.h index d0a2c963a27d3..1f0d38aa37f92 100644 --- a/drivers/ufs/core/ufshcd-priv.h +++ b/drivers/ufs/core/ufshcd-priv.h @@ -6,6 +6,8 @@ #include #include +void ufshcd_enable_intr(struct ufs_hba *hba, u32 intrs); + static inline bool ufshcd_is_user_access_allowed(struct ufs_hba *hba) { return !hba->shutting_down; diff --git a/include/ufs/ufshcd.h b/include/ufs/ufshcd.h index 0f95576bf1f6c..d949db3a46759 100644 --- a/include/ufs/ufshcd.h +++ b/include/ufs/ufshcd.h @@ -1302,7 +1302,6 @@ static inline void ufshcd_rmwl(struct ufs_hba *hba, u32 mask, u32 val, u32 reg) void ufshcd_enable_irq(struct ufs_hba *hba); void ufshcd_disable_irq(struct ufs_hba *hba); -void ufshcd_enable_intr(struct ufs_hba *hba, u32 intrs); int ufshcd_alloc_host(struct device *, struct ufs_hba **); int ufshcd_hba_enable(struct ufs_hba *hba); int ufshcd_init(struct ufs_hba *, void __iomem *, unsigned int); From 0f984f5f8126378423c2f346a15ecf9f216c2983 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Fri, 24 Oct 2025 12:24:33 +0200 Subject: [PATCH 0474/2333] s390/ap: Don't leak debug feature files if AP instructions are not available [ Upstream commit 020d5dc57874e58d3ebae398f3fe258f029e3d06 ] If no AP instructions are available the AP bus module leaks registered debug feature files. Change function call order to fix this. Fixes: cccd85bfb7bf ("s390/zcrypt: Rework debug feature invocations.") Reviewed-by: Harald Freudenberger Signed-off-by: Heiko Carstens Signed-off-by: Sasha Levin --- drivers/s390/crypto/ap_bus.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index 65f1a127cc3f6..dfd5d0f61a70d 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -2484,15 +2484,15 @@ static int __init ap_module_init(void) { int rc; - rc = ap_debug_init(); - if (rc) - return rc; - if (!ap_instructions_available()) { pr_warn("The hardware system does not support AP instructions\n"); return -ENODEV; } + rc = ap_debug_init(); + if (rc) + return rc; + /* init ap_queue hashtable */ hash_init(ap_queues); From 04d808a6efb58f0a2fe040301d7ebe736c259d6b Mon Sep 17 00:00:00 2001 From: Len Brown Date: Mon, 20 Oct 2025 18:41:38 -0300 Subject: [PATCH 0475/2333] tools/power turbostat: Regression fix Uncore MHz printed in hex [ Upstream commit 92664f2e6ab2228a3330734fc72dabeaf8a49ee1 ] A patch to allow specifying FORMAT_AVERAGE to added counters... broke the internally added counter for Cluster Uncore MHz -- printing it in HEX. Fixes: dcd1c379b0f1 ("tools/power turbostat: add format "average" for external attributes") Reported-by: Andrej Tkalcec Signed-off-by: Len Brown Signed-off-by: Sasha Levin --- tools/power/x86/turbostat/turbostat.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c index f2512d78bcbd8..1b5ca2f4e92ff 100644 --- a/tools/power/x86/turbostat/turbostat.c +++ b/tools/power/x86/turbostat/turbostat.c @@ -3285,13 +3285,13 @@ int format_counters(PER_THREAD_PARAMS) /* Added counters */ for (i = 0, mp = sys.tp; mp; i++, mp = mp->next) { - if (mp->format == FORMAT_RAW || mp->format == FORMAT_AVERAGE) { + if (mp->format == FORMAT_RAW) { if (mp->width == 32) outp += sprintf(outp, "%s0x%08x", (printed++ ? delim : ""), (unsigned int)t->counter[i]); else outp += sprintf(outp, "%s0x%016llx", (printed++ ? delim : ""), t->counter[i]); - } else if (mp->format == FORMAT_DELTA) { + } else if (mp->format == FORMAT_DELTA || mp->format == FORMAT_AVERAGE) { if ((mp->type == COUNTER_ITEMS) && sums_need_wide_columns) outp += sprintf(outp, "%s%8lld", (printed++ ? delim : ""), t->counter[i]); else @@ -3382,13 +3382,13 @@ int format_counters(PER_THREAD_PARAMS) outp += sprintf(outp, "%s%lld", (printed++ ? delim : ""), c->core_throt_cnt); for (i = 0, mp = sys.cp; mp; i++, mp = mp->next) { - if (mp->format == FORMAT_RAW || mp->format == FORMAT_AVERAGE) { + if (mp->format == FORMAT_RAW) { if (mp->width == 32) outp += sprintf(outp, "%s0x%08x", (printed++ ? delim : ""), (unsigned int)c->counter[i]); else outp += sprintf(outp, "%s0x%016llx", (printed++ ? delim : ""), c->counter[i]); - } else if (mp->format == FORMAT_DELTA) { + } else if (mp->format == FORMAT_DELTA || mp->format == FORMAT_AVERAGE) { if ((mp->type == COUNTER_ITEMS) && sums_need_wide_columns) outp += sprintf(outp, "%s%8lld", (printed++ ? delim : ""), c->counter[i]); else @@ -3581,7 +3581,7 @@ int format_counters(PER_THREAD_PARAMS) outp += sprintf(outp, "%s%d", (printed++ ? delim : ""), p->uncore_mhz); for (i = 0, mp = sys.pp; mp; i++, mp = mp->next) { - if (mp->format == FORMAT_RAW || mp->format == FORMAT_AVERAGE) { + if (mp->format == FORMAT_RAW) { if (mp->width == 32) outp += sprintf(outp, "%s0x%08x", (printed++ ? delim : ""), (unsigned int)p->counter[i]); @@ -3758,7 +3758,7 @@ int delta_package(struct pkg_data *new, struct pkg_data *old) new->rapl_dram_perf_status.raw_value - old->rapl_dram_perf_status.raw_value; for (i = 0, mp = sys.pp; mp; i++, mp = mp->next) { - if (mp->format == FORMAT_RAW || mp->format == FORMAT_AVERAGE) + if (mp->format == FORMAT_RAW) old->counter[i] = new->counter[i]; else if (mp->format == FORMAT_AVERAGE) old->counter[i] = new->counter[i]; From d0a5b5d56438b372cf601b50087e4330165524f2 Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Fri, 17 Oct 2025 10:36:36 +0800 Subject: [PATCH 0476/2333] wifi: ath12k: restore register window after global reset [ Upstream commit a41281f6518e485220d180a6031d302a736fc463 ] Hardware target implements an address space larger than that PCI BAR can map. In order to be able to access the whole target address space, the BAR space is split into 4 segments, of which the last 3, called windows, can be dynamically mapped to the desired area. This is achieved by updating WINDOW_REG_ADDRESS register with appropriate window value. Currently each time when accessing a register that beyond WINDOW_START, host calculates the window value and caches it after window update, this way next time when accessing a register falling in the same window, host knows that the window is already good hence no additional update needed. However this mechanism breaks after global reset is triggered in ath12k_pci_soc_global_reset(), because with global reset hardware resets WINDOW_REG_ADDRESS register hence the window is not properly mapped any more. Current host does nothing about this, as a result a subsequent register access may not work as expected if it falls in a window same as before. Although there is no obvious issue seen now, better to fix it to avoid future problem. The fix is done by restoring the window register after global reset. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.1.c5-00284.1-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Fixes: d889913205cf ("wifi: ath12k: driver for Qualcomm Wi-Fi 7 devices") Signed-off-by: Baochen Qiang Reviewed-by: Vasanthakumar Thiagarajan Link: https://patch.msgid.link/20251017-ath12k-reset-window-cache-v1-1-29e0e751deed@oss.qualcomm.com Signed-off-by: Jeff Johnson Signed-off-by: Sasha Levin --- drivers/net/wireless/ath/ath12k/pci.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath12k/pci.c b/drivers/net/wireless/ath/ath12k/pci.c index c729d5526c753..60b8f7361b7f6 100644 --- a/drivers/net/wireless/ath/ath12k/pci.c +++ b/drivers/net/wireless/ath/ath12k/pci.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2019-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include @@ -218,6 +218,19 @@ static inline bool ath12k_pci_is_offset_within_mhi_region(u32 offset) return (offset >= PCI_MHIREGLEN_REG && offset <= PCI_MHI_REGION_END); } +static void ath12k_pci_restore_window(struct ath12k_base *ab) +{ + struct ath12k_pci *ab_pci = ath12k_pci_priv(ab); + + spin_lock_bh(&ab_pci->window_lock); + + iowrite32(WINDOW_ENABLE_BIT | ab_pci->register_window, + ab->mem + WINDOW_REG_ADDRESS); + ioread32(ab->mem + WINDOW_REG_ADDRESS); + + spin_unlock_bh(&ab_pci->window_lock); +} + static void ath12k_pci_soc_global_reset(struct ath12k_base *ab) { u32 val, delay; @@ -242,6 +255,11 @@ static void ath12k_pci_soc_global_reset(struct ath12k_base *ab) val = ath12k_pci_read32(ab, PCIE_SOC_GLOBAL_RESET); if (val == 0xffffffff) ath12k_warn(ab, "link down error during global reset\n"); + + /* Restore window register as its content is cleared during + * hardware global reset, such that it aligns with host cache. + */ + ath12k_pci_restore_window(ab); } static void ath12k_pci_clear_dbg_registers(struct ath12k_base *ab) From 62e122809aed1aaeb61b67dc8d00648a4a230bdf Mon Sep 17 00:00:00 2001 From: Lizhi Hou Date: Fri, 24 Oct 2025 09:55:03 -0700 Subject: [PATCH 0477/2333] accel/amdxdna: Fix uninitialized return value [ Upstream commit 81233d5419cf20e4f5ef505882951616888a2ef9 ] In aie2_get_hwctx_status() and aie2_query_ctx_status_array(), the functions could return an uninitialized value in some cases. Update them to always return 0. The amount of valid results is indicated by the returned buffer_size, element_size, and num_element fields. Fixes: 2f509fe6a42c ("accel/amdxdna: Add ioctl DRM_IOCTL_AMDXDNA_GET_ARRAY") Reviewed-by: Mario Limonciello (AMD) Signed-off-by: Lizhi Hou Link: https://patch.msgid.link/20251024165503.1548131-1-lizhi.hou@amd.com Signed-off-by: Sasha Levin --- drivers/accel/amdxdna/aie2_pci.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/accel/amdxdna/aie2_pci.c b/drivers/accel/amdxdna/aie2_pci.c index 6e39c769bb6d8..43f725e1a2d76 100644 --- a/drivers/accel/amdxdna/aie2_pci.c +++ b/drivers/accel/amdxdna/aie2_pci.c @@ -845,7 +845,7 @@ static int aie2_get_hwctx_status(struct amdxdna_client *client, } args->buffer_size -= (u32)(array_args.buffer - args->buffer); - return ret; + return 0; } static int aie2_get_info(struct amdxdna_client *client, struct amdxdna_drm_get_info *args) @@ -920,7 +920,7 @@ static int aie2_query_ctx_status_array(struct amdxdna_client *client, args->num_element = (u32)((array_args.buffer - args->buffer) / args->element_size); - return ret; + return 0; } static int aie2_get_array(struct amdxdna_client *client, From fa66269056680f61289f46da813e63dd439ccdb7 Mon Sep 17 00:00:00 2001 From: Przemek Kitszel Date: Fri, 12 Sep 2025 15:06:20 +0200 Subject: [PATCH 0478/2333] ice: move service task start out of ice_init_pf() [ Upstream commit 806c4f32a80627f8977fda53520afc41491d162f ] Move service task start out of ice_init_pf(). Do analogous with deinit. Service task is needed up to the very end of driver removal, later commit of the series will move it later on execution timeline. Signed-off-by: Przemek Kitszel Tested-by: Rinitha S (A Contingent worker at Intel) Signed-off-by: Tony Nguyen Stable-dep-of: 1390b8b3d2be ("ice: remove duplicate call to ice_deinit_hw() on error paths") Signed-off-by: Sasha Levin --- drivers/net/ethernet/intel/ice/ice.h | 1 + drivers/net/ethernet/intel/ice/ice_main.c | 18 +++++++++++------- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h index 22b8323ff0d0e..0e58a58c23eb3 100644 --- a/drivers/net/ethernet/intel/ice/ice.h +++ b/drivers/net/ethernet/intel/ice/ice.h @@ -1029,6 +1029,7 @@ int ice_open(struct net_device *netdev); int ice_open_internal(struct net_device *netdev); int ice_stop(struct net_device *netdev); void ice_service_task_schedule(struct ice_pf *pf); +void ice_start_service_task(struct ice_pf *pf); int ice_load(struct ice_pf *pf); void ice_unload(struct ice_pf *pf); void ice_adv_lnk_speed_maps_init(void); diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index 86f5859e88ef5..41c2f0d52ce0d 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -3951,7 +3951,6 @@ u16 ice_get_avail_rxq_count(struct ice_pf *pf) */ static void ice_deinit_pf(struct ice_pf *pf) { - ice_service_task_stop(pf); mutex_destroy(&pf->lag_mutex); mutex_destroy(&pf->adev_mutex); mutex_destroy(&pf->sw_mutex); @@ -4030,6 +4029,14 @@ static void ice_set_pf_caps(struct ice_pf *pf) pf->max_pf_rxqs = func_caps->common_cap.num_rxq; } +void ice_start_service_task(struct ice_pf *pf) +{ + timer_setup(&pf->serv_tmr, ice_service_timer, 0); + pf->serv_tmr_period = HZ; + INIT_WORK(&pf->serv_task, ice_service_task); + clear_bit(ICE_SERVICE_SCHED, pf->state); +} + /** * ice_init_pf - Initialize general software structures (struct ice_pf) * @pf: board private structure to initialize @@ -4049,12 +4056,6 @@ static int ice_init_pf(struct ice_pf *pf) init_waitqueue_head(&pf->reset_wait_queue); - /* setup service timer and periodic service task */ - timer_setup(&pf->serv_tmr, ice_service_timer, 0); - pf->serv_tmr_period = HZ; - INIT_WORK(&pf->serv_task, ice_service_task); - clear_bit(ICE_SERVICE_SCHED, pf->state); - mutex_init(&pf->avail_q_mutex); pf->avail_txqs = bitmap_zalloc(pf->max_pf_txqs, GFP_KERNEL); if (!pf->avail_txqs) @@ -4745,6 +4746,7 @@ int ice_init_dev(struct ice_pf *pf) ice_set_safe_mode_caps(hw); } + ice_start_service_task(pf); err = ice_init_pf(pf); if (err) { dev_err(dev, "ice_init_pf failed: %d\n", err); @@ -4791,6 +4793,7 @@ int ice_init_dev(struct ice_pf *pf) ice_clear_interrupt_scheme(pf); unroll_pf_init: ice_deinit_pf(pf); + ice_service_task_stop(pf); return err; } @@ -4799,6 +4802,7 @@ void ice_deinit_dev(struct ice_pf *pf) ice_free_irq_msix_misc(pf); ice_deinit_pf(pf); ice_deinit_hw(&pf->hw); + ice_service_task_stop(pf); /* Service task is already stopped, so call reset directly. */ ice_reset(&pf->hw, ICE_RESET_PFR); From 0380ea173bf93f0ad33afc3f992ca4e8091cf9fd Mon Sep 17 00:00:00 2001 From: Przemek Kitszel Date: Fri, 12 Sep 2025 15:06:21 +0200 Subject: [PATCH 0479/2333] ice: move ice_init_interrupt_scheme() prior ice_init_pf() [ Upstream commit 2fe18288fce6b421f1dc585bcb9dd3afa32d3ad9 ] Move ice_init_interrupt_scheme() prior ice_init_pf(). To enable the move ice_set_pf_caps() was moved out from ice_init_pf() to the caller (ice_init_dev()), and placed prior to the irq scheme init. The move makes deinit order of ice_deinit_dev() and failure-path of ice_init_pf() match (at least in terms of not calling ice_clear_interrupt_scheme() and ice_deinit_pf() in opposite ways). The new order aligns with findings made by Jakub Buchocki in the commit 24b454bc354a ("ice: Fix ice module unload"). Signed-off-by: Przemek Kitszel Reviewed-by: Aleksandr Loktionov Tested-by: Rinitha S (A Contingent worker at Intel) Signed-off-by: Tony Nguyen Stable-dep-of: 1390b8b3d2be ("ice: remove duplicate call to ice_deinit_hw() on error paths") Signed-off-by: Sasha Levin --- drivers/net/ethernet/intel/ice/ice_main.c | 25 ++++++++++------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index 41c2f0d52ce0d..13db83fb383e6 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -4043,8 +4043,6 @@ void ice_start_service_task(struct ice_pf *pf) */ static int ice_init_pf(struct ice_pf *pf) { - ice_set_pf_caps(pf); - mutex_init(&pf->sw_mutex); mutex_init(&pf->tc_mutex); mutex_init(&pf->adev_mutex); @@ -4746,11 +4744,18 @@ int ice_init_dev(struct ice_pf *pf) ice_set_safe_mode_caps(hw); } + ice_set_pf_caps(pf); + err = ice_init_interrupt_scheme(pf); + if (err) { + dev_err(dev, "ice_init_interrupt_scheme failed: %d\n", err); + return -EIO; + } + ice_start_service_task(pf); err = ice_init_pf(pf); if (err) { dev_err(dev, "ice_init_pf failed: %d\n", err); - return err; + goto unroll_irq_scheme_init; } pf->hw.udp_tunnel_nic.set_port = ice_udp_tunnel_set_port; @@ -4768,14 +4773,6 @@ int ice_init_dev(struct ice_pf *pf) pf->hw.udp_tunnel_nic.tables[1].tunnel_types = UDP_TUNNEL_TYPE_GENEVE; } - - err = ice_init_interrupt_scheme(pf); - if (err) { - dev_err(dev, "ice_init_interrupt_scheme failed: %d\n", err); - err = -EIO; - goto unroll_pf_init; - } - /* In case of MSIX we are going to setup the misc vector right here * to handle admin queue events etc. In case of legacy and MSI * the misc functionality and queue processing is combined in @@ -4784,16 +4781,16 @@ int ice_init_dev(struct ice_pf *pf) err = ice_req_irq_msix_misc(pf); if (err) { dev_err(dev, "setup of misc vector failed: %d\n", err); - goto unroll_irq_scheme_init; + goto unroll_pf_init; } return 0; -unroll_irq_scheme_init: - ice_clear_interrupt_scheme(pf); unroll_pf_init: ice_deinit_pf(pf); +unroll_irq_scheme_init: ice_service_task_stop(pf); + ice_clear_interrupt_scheme(pf); return err; } From 46d0b034b15d4b75c346293560468edf8a28796e Mon Sep 17 00:00:00 2001 From: Przemek Kitszel Date: Fri, 12 Sep 2025 15:06:22 +0200 Subject: [PATCH 0480/2333] ice: ice_init_pf: destroy mutexes and xarrays on memory alloc failure [ Upstream commit 71430451f81bd6550e46d89b69103a111fc42982 ] Unroll actions of ice_init_pf() when it fails. ice_deinit_pf() happens to be perfect to call here. Signed-off-by: Przemek Kitszel Reviewed-by: Aleksandr Loktionov Tested-by: Rinitha S (A Contingent worker at Intel) Signed-off-by: Tony Nguyen Stable-dep-of: 1390b8b3d2be ("ice: remove duplicate call to ice_deinit_hw() on error paths") Signed-off-by: Sasha Levin --- drivers/net/ethernet/intel/ice/ice_main.c | 31 +++++++++-------------- 1 file changed, 12 insertions(+), 19 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index 13db83fb383e6..80349aed1f9d6 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -3951,6 +3951,8 @@ u16 ice_get_avail_rxq_count(struct ice_pf *pf) */ static void ice_deinit_pf(struct ice_pf *pf) { + /* note that we unroll also on ice_init_pf() failure here */ + mutex_destroy(&pf->lag_mutex); mutex_destroy(&pf->adev_mutex); mutex_destroy(&pf->sw_mutex); @@ -4055,25 +4057,6 @@ static int ice_init_pf(struct ice_pf *pf) init_waitqueue_head(&pf->reset_wait_queue); mutex_init(&pf->avail_q_mutex); - pf->avail_txqs = bitmap_zalloc(pf->max_pf_txqs, GFP_KERNEL); - if (!pf->avail_txqs) - return -ENOMEM; - - pf->avail_rxqs = bitmap_zalloc(pf->max_pf_rxqs, GFP_KERNEL); - if (!pf->avail_rxqs) { - bitmap_free(pf->avail_txqs); - pf->avail_txqs = NULL; - return -ENOMEM; - } - - pf->txtime_txqs = bitmap_zalloc(pf->max_pf_txqs, GFP_KERNEL); - if (!pf->txtime_txqs) { - bitmap_free(pf->avail_txqs); - pf->avail_txqs = NULL; - bitmap_free(pf->avail_rxqs); - pf->avail_rxqs = NULL; - return -ENOMEM; - } mutex_init(&pf->vfs.table_lock); hash_init(pf->vfs.table); @@ -4086,7 +4069,17 @@ static int ice_init_pf(struct ice_pf *pf) xa_init(&pf->dyn_ports); xa_init(&pf->sf_nums); + pf->avail_txqs = bitmap_zalloc(pf->max_pf_txqs, GFP_KERNEL); + pf->avail_rxqs = bitmap_zalloc(pf->max_pf_rxqs, GFP_KERNEL); + pf->txtime_txqs = bitmap_zalloc(pf->max_pf_txqs, GFP_KERNEL); + if (!pf->avail_txqs || !pf->avail_rxqs || !pf->txtime_txqs) + goto undo_init; + return 0; +undo_init: + /* deinit handles half-initialized pf just fine */ + ice_deinit_pf(pf); + return -ENOMEM; } /** From 6a7d04909a959d8a3d0b54cd69cae76313d7ed1c Mon Sep 17 00:00:00 2001 From: Przemek Kitszel Date: Fri, 12 Sep 2025 15:06:23 +0200 Subject: [PATCH 0481/2333] ice: move udp_tunnel_nic and misc IRQ setup into ice_init_pf() [ Upstream commit e3bf1cdde7471bab7fc20dd1a37c2cdb82d3f76b ] Move udp_tunnel_nic setup and ice_req_irq_msix_misc() call into ice_init_pf(), remove some redundancy in the former while moving. Move ice_free_irq_msix_misc() call into ice_deinit_pf(), to mimic the above in terms of needed cleanup. Guard it via emptiness check, to keep the allowance of half-initialized pf being cleaned up. Signed-off-by: Przemek Kitszel Reviewed-by: Aleksandr Loktionov Tested-by: Rinitha S (A Contingent worker at Intel) Signed-off-by: Tony Nguyen Stable-dep-of: 1390b8b3d2be ("ice: remove duplicate call to ice_deinit_hw() on error paths") Signed-off-by: Sasha Levin --- drivers/net/ethernet/intel/ice/ice_main.c | 58 +++++++++++------------ 1 file changed, 28 insertions(+), 30 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index 80349aed1f9d6..6773b918daffc 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -3978,6 +3978,9 @@ static void ice_deinit_pf(struct ice_pf *pf) if (pf->ptp.clock) ptp_clock_unregister(pf->ptp.clock); + if (!xa_empty(&pf->irq_tracker.entries)) + ice_free_irq_msix_misc(pf); + xa_destroy(&pf->dyn_ports); xa_destroy(&pf->sf_nums); } @@ -4045,6 +4048,11 @@ void ice_start_service_task(struct ice_pf *pf) */ static int ice_init_pf(struct ice_pf *pf) { + struct udp_tunnel_nic_info *udp_tunnel_nic = &pf->hw.udp_tunnel_nic; + struct device *dev = ice_pf_to_dev(pf); + struct ice_hw *hw = &pf->hw; + int err = -ENOMEM; + mutex_init(&pf->sw_mutex); mutex_init(&pf->tc_mutex); mutex_init(&pf->adev_mutex); @@ -4075,11 +4083,30 @@ static int ice_init_pf(struct ice_pf *pf) if (!pf->avail_txqs || !pf->avail_rxqs || !pf->txtime_txqs) goto undo_init; + udp_tunnel_nic->set_port = ice_udp_tunnel_set_port; + udp_tunnel_nic->unset_port = ice_udp_tunnel_unset_port; + udp_tunnel_nic->shared = &hw->udp_tunnel_shared; + udp_tunnel_nic->tables[0].n_entries = hw->tnl.valid_count[TNL_VXLAN]; + udp_tunnel_nic->tables[0].tunnel_types = UDP_TUNNEL_TYPE_VXLAN; + udp_tunnel_nic->tables[1].n_entries = hw->tnl.valid_count[TNL_GENEVE]; + udp_tunnel_nic->tables[1].tunnel_types = UDP_TUNNEL_TYPE_GENEVE; + + /* In case of MSIX we are going to setup the misc vector right here + * to handle admin queue events etc. In case of legacy and MSI + * the misc functionality and queue processing is combined in + * the same vector and that gets setup at open. + */ + err = ice_req_irq_msix_misc(pf); + if (err) { + dev_err(dev, "setup of misc vector failed: %d\n", err); + goto undo_init; + } + return 0; undo_init: /* deinit handles half-initialized pf just fine */ ice_deinit_pf(pf); - return -ENOMEM; + return err; } /** @@ -4751,36 +4778,8 @@ int ice_init_dev(struct ice_pf *pf) goto unroll_irq_scheme_init; } - pf->hw.udp_tunnel_nic.set_port = ice_udp_tunnel_set_port; - pf->hw.udp_tunnel_nic.unset_port = ice_udp_tunnel_unset_port; - pf->hw.udp_tunnel_nic.shared = &pf->hw.udp_tunnel_shared; - if (pf->hw.tnl.valid_count[TNL_VXLAN]) { - pf->hw.udp_tunnel_nic.tables[0].n_entries = - pf->hw.tnl.valid_count[TNL_VXLAN]; - pf->hw.udp_tunnel_nic.tables[0].tunnel_types = - UDP_TUNNEL_TYPE_VXLAN; - } - if (pf->hw.tnl.valid_count[TNL_GENEVE]) { - pf->hw.udp_tunnel_nic.tables[1].n_entries = - pf->hw.tnl.valid_count[TNL_GENEVE]; - pf->hw.udp_tunnel_nic.tables[1].tunnel_types = - UDP_TUNNEL_TYPE_GENEVE; - } - /* In case of MSIX we are going to setup the misc vector right here - * to handle admin queue events etc. In case of legacy and MSI - * the misc functionality and queue processing is combined in - * the same vector and that gets setup at open. - */ - err = ice_req_irq_msix_misc(pf); - if (err) { - dev_err(dev, "setup of misc vector failed: %d\n", err); - goto unroll_pf_init; - } - return 0; -unroll_pf_init: - ice_deinit_pf(pf); unroll_irq_scheme_init: ice_service_task_stop(pf); ice_clear_interrupt_scheme(pf); @@ -4789,7 +4788,6 @@ int ice_init_dev(struct ice_pf *pf) void ice_deinit_dev(struct ice_pf *pf) { - ice_free_irq_msix_misc(pf); ice_deinit_pf(pf); ice_deinit_hw(&pf->hw); ice_service_task_stop(pf); From 8cea2a81db58e1288d3d4347109f1b04a989a125 Mon Sep 17 00:00:00 2001 From: Przemek Kitszel Date: Fri, 12 Sep 2025 15:06:24 +0200 Subject: [PATCH 0482/2333] ice: move ice_init_pf() out of ice_init_dev() [ Upstream commit ef825bdb4605742c4efc03f67d930e80c42f33cb ] Move ice_init_pf() out of ice_init_dev(). Do the same for deinit counterpart. Signed-off-by: Przemek Kitszel Reviewed-by: Aleksandr Loktionov Tested-by: Rinitha S (A Contingent worker at Intel) Signed-off-by: Tony Nguyen Stable-dep-of: 1390b8b3d2be ("ice: remove duplicate call to ice_deinit_hw() on error paths") Signed-off-by: Sasha Levin --- .../net/ethernet/intel/ice/devlink/devlink.c | 16 ++++++++-- drivers/net/ethernet/intel/ice/ice.h | 2 ++ drivers/net/ethernet/intel/ice/ice_main.c | 32 +++++++++---------- 3 files changed, 31 insertions(+), 19 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/devlink/devlink.c b/drivers/net/ethernet/intel/ice/devlink/devlink.c index fb2de521731ae..c354a03c950cd 100644 --- a/drivers/net/ethernet/intel/ice/devlink/devlink.c +++ b/drivers/net/ethernet/intel/ice/devlink/devlink.c @@ -459,6 +459,7 @@ static void ice_devlink_reinit_down(struct ice_pf *pf) rtnl_lock(); ice_vsi_decfg(ice_get_main_vsi(pf)); rtnl_unlock(); + ice_deinit_pf(pf); ice_deinit_dev(pf); } @@ -1231,11 +1232,12 @@ static void ice_set_min_max_msix(struct ice_pf *pf) static int ice_devlink_reinit_up(struct ice_pf *pf) { struct ice_vsi *vsi = ice_get_main_vsi(pf); + struct device *dev = ice_pf_to_dev(pf); int err; err = ice_init_hw(&pf->hw); if (err) { - dev_err(ice_pf_to_dev(pf), "ice_init_hw failed: %d\n", err); + dev_err(dev, "ice_init_hw failed: %d\n", err); return err; } @@ -1246,13 +1248,19 @@ static int ice_devlink_reinit_up(struct ice_pf *pf) if (err) goto unroll_hw_init; + err = ice_init_pf(pf); + if (err) { + dev_err(dev, "ice_init_pf failed: %d\n", err); + goto unroll_dev_init; + } + vsi->flags = ICE_VSI_FLAG_INIT; rtnl_lock(); err = ice_vsi_cfg(vsi); rtnl_unlock(); if (err) - goto err_vsi_cfg; + goto unroll_pf_init; /* No need to take devl_lock, it's already taken by devlink API */ err = ice_load(pf); @@ -1265,7 +1273,9 @@ static int ice_devlink_reinit_up(struct ice_pf *pf) rtnl_lock(); ice_vsi_decfg(vsi); rtnl_unlock(); -err_vsi_cfg: +unroll_pf_init: + ice_deinit_pf(pf); +unroll_dev_init: ice_deinit_dev(pf); unroll_hw_init: ice_deinit_hw(&pf->hw); diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h index 0e58a58c23eb3..9a1abd4573372 100644 --- a/drivers/net/ethernet/intel/ice/ice.h +++ b/drivers/net/ethernet/intel/ice/ice.h @@ -1035,6 +1035,8 @@ void ice_unload(struct ice_pf *pf); void ice_adv_lnk_speed_maps_init(void); int ice_init_dev(struct ice_pf *pf); void ice_deinit_dev(struct ice_pf *pf); +int ice_init_pf(struct ice_pf *pf); +void ice_deinit_pf(struct ice_pf *pf); int ice_change_mtu(struct net_device *netdev, int new_mtu); void ice_tx_timeout(struct net_device *netdev, unsigned int txqueue); int ice_xdp(struct net_device *dev, struct netdev_bpf *xdp); diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index 6773b918daffc..6b3d941f419b3 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -3949,7 +3949,7 @@ u16 ice_get_avail_rxq_count(struct ice_pf *pf) * ice_deinit_pf - Unrolls initialziations done by ice_init_pf * @pf: board private structure to initialize */ -static void ice_deinit_pf(struct ice_pf *pf) +void ice_deinit_pf(struct ice_pf *pf) { /* note that we unroll also on ice_init_pf() failure here */ @@ -4045,8 +4045,9 @@ void ice_start_service_task(struct ice_pf *pf) /** * ice_init_pf - Initialize general software structures (struct ice_pf) * @pf: board private structure to initialize + * Return: 0 on success, negative errno otherwise. */ -static int ice_init_pf(struct ice_pf *pf) +int ice_init_pf(struct ice_pf *pf) { struct udp_tunnel_nic_info *udp_tunnel_nic = &pf->hw.udp_tunnel_nic; struct device *dev = ice_pf_to_dev(pf); @@ -4772,23 +4773,12 @@ int ice_init_dev(struct ice_pf *pf) } ice_start_service_task(pf); - err = ice_init_pf(pf); - if (err) { - dev_err(dev, "ice_init_pf failed: %d\n", err); - goto unroll_irq_scheme_init; - } return 0; - -unroll_irq_scheme_init: - ice_service_task_stop(pf); - ice_clear_interrupt_scheme(pf); - return err; } void ice_deinit_dev(struct ice_pf *pf) { - ice_deinit_pf(pf); ice_deinit_hw(&pf->hw); ice_service_task_stop(pf); @@ -5030,21 +5020,28 @@ static void ice_deinit_devlink(struct ice_pf *pf) static int ice_init(struct ice_pf *pf) { + struct device *dev = ice_pf_to_dev(pf); int err; err = ice_init_dev(pf); if (err) return err; + err = ice_init_pf(pf); + if (err) { + dev_err(dev, "ice_init_pf failed: %d\n", err); + goto unroll_dev_init; + } + if (pf->hw.mac_type == ICE_MAC_E830) { err = pci_enable_ptm(pf->pdev, NULL); if (err) - dev_dbg(ice_pf_to_dev(pf), "PCIe PTM not supported by PCIe bus/controller\n"); + dev_dbg(dev, "PCIe PTM not supported by PCIe bus/controller\n"); } err = ice_alloc_vsis(pf); if (err) - goto err_alloc_vsis; + goto unroll_pf_init; err = ice_init_pf_sw(pf); if (err) @@ -5081,7 +5078,9 @@ static int ice_init(struct ice_pf *pf) ice_deinit_pf_sw(pf); err_init_pf_sw: ice_dealloc_vsis(pf); -err_alloc_vsis: +unroll_pf_init: + ice_deinit_pf(pf); +unroll_dev_init: ice_deinit_dev(pf); return err; } @@ -5093,6 +5092,7 @@ static void ice_deinit(struct ice_pf *pf) ice_deinit_pf_sw(pf); ice_dealloc_vsis(pf); + ice_deinit_pf(pf); ice_deinit_dev(pf); } From 3cef143aba0462d284ce18b004581cd26e6067ae Mon Sep 17 00:00:00 2001 From: Przemek Kitszel Date: Fri, 12 Sep 2025 15:06:25 +0200 Subject: [PATCH 0483/2333] ice: extract ice_init_dev() from ice_init() [ Upstream commit c2fb9398f73d41cb2b5da74ff505578525ee3fd8 ] Extract ice_init_dev() from ice_init(), to allow service task and IRQ scheme teardown to be put after clearing SW constructs in the subsequent commit. Signed-off-by: Przemek Kitszel Reviewed-by: Aleksandr Loktionov Tested-by: Rinitha S (A Contingent worker at Intel) Signed-off-by: Tony Nguyen Stable-dep-of: 1390b8b3d2be ("ice: remove duplicate call to ice_deinit_hw() on error paths") Signed-off-by: Sasha Levin --- drivers/net/ethernet/intel/ice/ice_main.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index 6b3d941f419b3..a12dcc733e041 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -5023,14 +5023,10 @@ static int ice_init(struct ice_pf *pf) struct device *dev = ice_pf_to_dev(pf); int err; - err = ice_init_dev(pf); - if (err) - return err; - err = ice_init_pf(pf); if (err) { dev_err(dev, "ice_init_pf failed: %d\n", err); - goto unroll_dev_init; + return err; } if (pf->hw.mac_type == ICE_MAC_E830) { @@ -5080,8 +5076,6 @@ static int ice_init(struct ice_pf *pf) ice_dealloc_vsis(pf); unroll_pf_init: ice_deinit_pf(pf); -unroll_dev_init: - ice_deinit_dev(pf); return err; } @@ -5093,7 +5087,6 @@ static void ice_deinit(struct ice_pf *pf) ice_deinit_pf_sw(pf); ice_dealloc_vsis(pf); ice_deinit_pf(pf); - ice_deinit_dev(pf); } /** @@ -5323,10 +5316,14 @@ ice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent) } pf->adapter = adapter; - err = ice_init(pf); + err = ice_init_dev(pf); if (err) goto unroll_adapter; + err = ice_init(pf); + if (err) + goto unroll_dev_init; + devl_lock(priv_to_devlink(pf)); err = ice_load(pf); if (err) @@ -5344,6 +5341,8 @@ ice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent) unroll_init: devl_unlock(priv_to_devlink(pf)); ice_deinit(pf); +unroll_dev_init: + ice_deinit_dev(pf); unroll_adapter: ice_adapter_put(pdev); unroll_hw_init: @@ -5457,6 +5456,7 @@ static void ice_remove(struct pci_dev *pdev) devl_unlock(priv_to_devlink(pf)); ice_deinit(pf); + ice_deinit_dev(pf); ice_vsi_release_all(pf); ice_setup_mc_magic_wake(pf); From ac4d0d4c469c84b81068608afb6a53d61c2a12d2 Mon Sep 17 00:00:00 2001 From: Przemek Kitszel Date: Fri, 12 Sep 2025 15:06:26 +0200 Subject: [PATCH 0484/2333] ice: move ice_deinit_dev() to the end of deinit paths [ Upstream commit 8a37f9e2ff40f4a4fa8def22febefe4daf58e573 ] ice_deinit_dev() takes care of turning off adminq processing, which is much needed during driver teardown (remove, reset, error path). Move it to the very end where applicable. For example, ice_deinit_hw() called after adminq deinit slows rmmod on my two-card setup by about 60 seconds. ice_init_dev() and ice_deinit_dev() scopes were reduced by previous commits of the series, with a final touch of extracting ice_init_dev_hw() out now (there is no deinit counterpart). Note that removed ice_service_task_stop() call from ice_remove() is placed in the ice_deinit_dev() (and stopping twice makes no sense). Signed-off-by: Przemek Kitszel Reviewed-by: Aleksandr Loktionov Tested-by: Rinitha S (A Contingent worker at Intel) Signed-off-by: Tony Nguyen Stable-dep-of: 1390b8b3d2be ("ice: remove duplicate call to ice_deinit_hw() on error paths") Signed-off-by: Sasha Levin --- .../net/ethernet/intel/ice/devlink/devlink.c | 5 +++- drivers/net/ethernet/intel/ice/ice.h | 1 + drivers/net/ethernet/intel/ice/ice_common.c | 3 +++ drivers/net/ethernet/intel/ice/ice_main.c | 23 ++++++++++++------- 4 files changed, 23 insertions(+), 9 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/devlink/devlink.c b/drivers/net/ethernet/intel/ice/devlink/devlink.c index c354a03c950cd..938914abbe066 100644 --- a/drivers/net/ethernet/intel/ice/devlink/devlink.c +++ b/drivers/net/ethernet/intel/ice/devlink/devlink.c @@ -1233,6 +1233,7 @@ static int ice_devlink_reinit_up(struct ice_pf *pf) { struct ice_vsi *vsi = ice_get_main_vsi(pf); struct device *dev = ice_pf_to_dev(pf); + bool need_dev_deinit = false; int err; err = ice_init_hw(&pf->hw); @@ -1276,9 +1277,11 @@ static int ice_devlink_reinit_up(struct ice_pf *pf) unroll_pf_init: ice_deinit_pf(pf); unroll_dev_init: - ice_deinit_dev(pf); + need_dev_deinit = true; unroll_hw_init: ice_deinit_hw(&pf->hw); + if (need_dev_deinit) + ice_deinit_dev(pf); return err; } diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h index 9a1abd4573372..9ee596773f34e 100644 --- a/drivers/net/ethernet/intel/ice/ice.h +++ b/drivers/net/ethernet/intel/ice/ice.h @@ -1033,6 +1033,7 @@ void ice_start_service_task(struct ice_pf *pf); int ice_load(struct ice_pf *pf); void ice_unload(struct ice_pf *pf); void ice_adv_lnk_speed_maps_init(void); +void ice_init_dev_hw(struct ice_pf *pf); int ice_init_dev(struct ice_pf *pf); void ice_deinit_dev(struct ice_pf *pf); int ice_init_pf(struct ice_pf *pf); diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c index 2532b6f82e971..6edeb06b4dce2 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.c +++ b/drivers/net/ethernet/intel/ice/ice_common.c @@ -1161,6 +1161,9 @@ int ice_init_hw(struct ice_hw *hw) status = ice_init_hw_tbls(hw); if (status) goto err_unroll_fltr_mgmt_struct; + + ice_init_dev_hw(hw->back); + mutex_init(&hw->tnl_lock); ice_init_chk_recipe_reuse_support(hw); diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index a12dcc733e041..f1ebdb7dbdc73 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -4742,9 +4742,8 @@ static void ice_decfg_netdev(struct ice_vsi *vsi) vsi->netdev = NULL; } -int ice_init_dev(struct ice_pf *pf) +void ice_init_dev_hw(struct ice_pf *pf) { - struct device *dev = ice_pf_to_dev(pf); struct ice_hw *hw = &pf->hw; int err; @@ -4764,6 +4763,12 @@ int ice_init_dev(struct ice_pf *pf) */ ice_set_safe_mode_caps(hw); } +} + +int ice_init_dev(struct ice_pf *pf) +{ + struct device *dev = ice_pf_to_dev(pf); + int err; ice_set_pf_caps(pf); err = ice_init_interrupt_scheme(pf); @@ -5220,6 +5225,7 @@ static int ice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent) { struct device *dev = &pdev->dev; + bool need_dev_deinit = false; struct ice_adapter *adapter; struct ice_pf *pf; struct ice_hw *hw; @@ -5342,11 +5348,13 @@ ice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent) devl_unlock(priv_to_devlink(pf)); ice_deinit(pf); unroll_dev_init: - ice_deinit_dev(pf); + need_dev_deinit = true; unroll_adapter: ice_adapter_put(pdev); unroll_hw_init: ice_deinit_hw(hw); + if (need_dev_deinit) + ice_deinit_dev(pf); return err; } @@ -5441,10 +5449,6 @@ static void ice_remove(struct pci_dev *pdev) ice_hwmon_exit(pf); - ice_service_task_stop(pf); - ice_aq_cancel_waiting_tasks(pf); - set_bit(ICE_DOWN, pf->state); - if (!ice_is_safe_mode(pf)) ice_remove_arfs(pf); @@ -5456,13 +5460,16 @@ static void ice_remove(struct pci_dev *pdev) devl_unlock(priv_to_devlink(pf)); ice_deinit(pf); - ice_deinit_dev(pf); ice_vsi_release_all(pf); ice_setup_mc_magic_wake(pf); ice_set_wake(pf); ice_adapter_put(pdev); + + ice_deinit_dev(pf); + ice_aq_cancel_waiting_tasks(pf); + set_bit(ICE_DOWN, pf->state); } /** From c91eee346089e4d287d5a111719e57cac605275e Mon Sep 17 00:00:00 2001 From: Przemek Kitszel Date: Fri, 12 Sep 2025 15:06:27 +0200 Subject: [PATCH 0485/2333] ice: remove duplicate call to ice_deinit_hw() on error paths [ Upstream commit 1390b8b3d2bef9bfbb852fc735430798bfca36e7 ] Current unwinding code on error paths of ice_devlink_reinit_up() and ice_probe() have manual call to ice_deinit_hw() (which is good, as there is also manual call to ice_hw_init() there), which is then duplicated (and was prior current series) in ice_deinit_dev(). Fix the above by removing ice_deinit_hw() from ice_deinit_dev(). Add a (now missing) call in ice_remove(). Reported-by: Jacob Keller Link: https://lore.kernel.org/intel-wired-lan/20250717-jk-ddp-safe-mode-issue-v1-1-e113b2baed79@intel.com/ Fixes: 4d3f59bfa2cd ("ice: split ice_init_hw() out from ice_init_dev()") Signed-off-by: Przemek Kitszel Reviewed-by: Aleksandr Loktionov Tested-by: Rinitha S (A Contingent worker at Intel) Signed-off-by: Tony Nguyen Signed-off-by: Sasha Levin --- drivers/net/ethernet/intel/ice/ice_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index f1ebdb7dbdc73..b0f8a96c13b47 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -4784,7 +4784,6 @@ int ice_init_dev(struct ice_pf *pf) void ice_deinit_dev(struct ice_pf *pf) { - ice_deinit_hw(&pf->hw); ice_service_task_stop(pf); /* Service task is already stopped, so call reset directly. */ @@ -5466,6 +5465,7 @@ static void ice_remove(struct pci_dev *pdev) ice_set_wake(pf); ice_adapter_put(pdev); + ice_deinit_hw(&pf->hw); ice_deinit_dev(pf); ice_aq_cancel_waiting_tasks(pf); From 2f902d08e1f313190c05566f72a2baace73b501a Mon Sep 17 00:00:00 2001 From: Thomas Richard Date: Mon, 20 Oct 2025 17:36:25 +0200 Subject: [PATCH 0486/2333] leds: upboard: Fix module alias [ Upstream commit c06a017439110debd335b6864bc2d69835624235 ] The module alias does not match the cell name defined in the MFD driver, preventing automatic loading when the driver is built as a module. So fix the module alias to ensure proper module auto-loading. Fixes: 0ef2929a0181 ("leds: Add AAEON UP board LED driver") Signed-off-by: Thomas Richard Reviewed-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20251020-leds-upboard-fix-module-alias-v2-1-84ac5c3a1a81@bootlin.com Signed-off-by: Lee Jones Signed-off-by: Sasha Levin --- drivers/leds/leds-upboard.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/leds/leds-upboard.c b/drivers/leds/leds-upboard.c index b350eb294280f..12989b2f19530 100644 --- a/drivers/leds/leds-upboard.c +++ b/drivers/leds/leds-upboard.c @@ -123,4 +123,4 @@ MODULE_AUTHOR("Gary Wang "); MODULE_AUTHOR("Thomas Richard "); MODULE_DESCRIPTION("UP Board LED driver"); MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:upboard-led"); +MODULE_ALIAS("platform:upboard-leds"); From b8b3bdfb10765e71712f27a6ed093a22b252f645 Mon Sep 17 00:00:00 2001 From: Bhanu Seshu Kumar Valluri Date: Tue, 14 Oct 2025 08:11:09 +0530 Subject: [PATCH 0487/2333] PCI: endpoint: pci-epf-test: Fix sleeping function being called from atomic context [ Upstream commit 25423cda145f9ed6ee4a72d9f2603ac2a4685e74 ] When Root Complex (RC) triggers a Doorbell interrupt to Endpoint (EP), it triggers the below warning in the EP: BUG: sleeping function called from invalid context at kernel/locking/mutex.c:271 Call trace: __might_resched+0x130/0x158 __might_sleep+0x70/0x88 mutex_lock+0x2c/0x80 pci_epc_get_msi+0x78/0xd8 pci_epf_test_raise_irq.isra.0+0x74/0x138 pci_epf_test_doorbell_handler+0x34/0x50 The BUG arises because the EP's pci_epf_test_doorbell_handler() which is running in the hard IRQ context is making an indirect call to pci_epc_get_msi(), which uses mutex inside. To fix the issue, convert the hard IRQ handler to a threaded IRQ handler to allow it to call functions that can sleep during bottom half execution. Also, register the threaded IRQ handler with IRQF_ONESHOT to keep the interrupt line disabled until the threaded IRQ handler completes execution. Fixes: eff0c286aa91 ("PCI: endpoint: pci-epf-test: Add doorbell test support") Signed-off-by: Bhanu Seshu Kumar Valluri [mani: reworded description a bit] Signed-off-by: Manivannan Sadhasivam Reviewed-by: Niklas Cassel Reviewed-by: Frank Li Link: https://patch.msgid.link/20251014024109.42287-1-bhanuseshukumar@gmail.com Signed-off-by: Sasha Levin --- drivers/pci/endpoint/functions/pci-epf-test.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/pci/endpoint/functions/pci-epf-test.c b/drivers/pci/endpoint/functions/pci-epf-test.c index 31617772ad516..b05e8db575c35 100644 --- a/drivers/pci/endpoint/functions/pci-epf-test.c +++ b/drivers/pci/endpoint/functions/pci-epf-test.c @@ -730,8 +730,9 @@ static void pci_epf_test_enable_doorbell(struct pci_epf_test *epf_test, if (bar < BAR_0) goto err_doorbell_cleanup; - ret = request_irq(epf->db_msg[0].virq, pci_epf_test_doorbell_handler, 0, - "pci-ep-test-doorbell", epf_test); + ret = request_threaded_irq(epf->db_msg[0].virq, NULL, + pci_epf_test_doorbell_handler, IRQF_ONESHOT, + "pci-ep-test-doorbell", epf_test); if (ret) { dev_err(&epf->dev, "Failed to request doorbell IRQ: %d\n", From 01caee81ca7b76aa4d813e3ba3b87d1e92c50b38 Mon Sep 17 00:00:00 2001 From: Randolph Sapp Date: Fri, 19 Sep 2025 14:33:42 -0500 Subject: [PATCH 0488/2333] arm64: dts: ti: k3-am62p: Fix memory ranges for GPU [ Upstream commit 76546090b1726118cd6fb3db7159fc2a3fdda8a0 ] Update the memory region listed in the k3-am62p.dtsi for the BXS-4-64 GPU to match the Main Memory Map described in the TRM [1]. [1] https://www.ti.com/lit/ug/spruj83b/spruj83b.pdf Fixes: 29075cc09f43 ("arm64: dts: ti: Introduce AM62P5 family of SoCs") Signed-off-by: Randolph Sapp Reviewed-by: Michael Walle Link: https://patch.msgid.link/20250919193341.707660-2-rs@ti.com Signed-off-by: Vignesh Raghavendra Signed-off-by: Sasha Levin --- arch/arm64/boot/dts/ti/k3-am62p.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/ti/k3-am62p.dtsi b/arch/arm64/boot/dts/ti/k3-am62p.dtsi index 75a15c368c11b..dd24c40c7965d 100644 --- a/arch/arm64/boot/dts/ti/k3-am62p.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am62p.dtsi @@ -59,7 +59,7 @@ <0x00 0x01000000 0x00 0x01000000 0x00 0x01b28400>, /* First peripheral window */ <0x00 0x08000000 0x00 0x08000000 0x00 0x00200000>, /* Main CPSW */ <0x00 0x0e000000 0x00 0x0e000000 0x00 0x01d20000>, /* Second peripheral window */ - <0x00 0x0fd00000 0x00 0x0fd00000 0x00 0x00020000>, /* GPU */ + <0x00 0x0fd80000 0x00 0x0fd80000 0x00 0x00080000>, /* GPU */ <0x00 0x20000000 0x00 0x20000000 0x00 0x0a008000>, /* Third peripheral window */ <0x00 0x30040000 0x00 0x30040000 0x00 0x00080000>, /* PRUSS-M */ <0x00 0x30101000 0x00 0x30101000 0x00 0x00010100>, /* CSI window */ From a705920161fb36dd6b3e1a8fd0586afdb1bf2283 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Fri, 17 Oct 2025 09:56:24 +0800 Subject: [PATCH 0489/2333] firmware: imx: scu-irq: fix OF node leak in [ Upstream commit ee67247843a2b62d1473cfa4df300e69b5190ccf ] imx_scu_enable_general_irq_channel() calls of_parse_phandle_with_args(), but does not release the OF node reference. Add a of_node_put() call to release the reference. Fixes: 851826c7566e ("firmware: imx: enable imx scu general irq function") Reviewed-by: Frank Li Signed-off-by: Peng Fan Signed-off-by: Shawn Guo Signed-off-by: Sasha Levin --- drivers/firmware/imx/imx-scu-irq.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/firmware/imx/imx-scu-irq.c b/drivers/firmware/imx/imx-scu-irq.c index 6125cccc9ba79..f2b902e95b738 100644 --- a/drivers/firmware/imx/imx-scu-irq.c +++ b/drivers/firmware/imx/imx-scu-irq.c @@ -226,8 +226,10 @@ int imx_scu_enable_general_irq_channel(struct device *dev) INIT_WORK(&imx_sc_irq_work, imx_scu_irq_work_handler); if (!of_parse_phandle_with_args(dev->of_node, "mboxes", - "#mbox-cells", 0, &spec)) + "#mbox-cells", 0, &spec)) { i = of_alias_get_id(spec.np, "mu"); + of_node_put(spec.np); + } /* use mu1 as general mu irq channel if failed */ if (i < 0) From ca3630751d7f83f29c2a5429836b8e5bc7c1d5e3 Mon Sep 17 00:00:00 2001 From: Krishna Kurapati Date: Sun, 19 Oct 2025 17:26:30 +0530 Subject: [PATCH 0490/2333] arm64: dts: qcom: x1e80100: Fix compile warnings for USB HS controller [ Upstream commit 0dab10c38282e6ef87ef88efb99d4106cce7ed33 ] With W=1, the following error comes up: Warning (graph_child_address): /soc@0/usb@a2f8800/usb@a200000/ports: graph node has single child node 'port@0', #address-cells/#size-cells are not necessary This could be since the controller is only HS capable and only one port node is added. Fixes: 4af46b7bd66f ("arm64: dts: qcom: x1e80100: Add USB nodes") Signed-off-by: Krishna Kurapati Reviewed-by: Konrad Dybcio Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20251019115630.2222720-1-krishna.kurapati@oss.qualcomm.com Signed-off-by: Bjorn Andersson Signed-off-by: Sasha Levin --- arch/arm64/boot/dts/qcom/x1e80100.dtsi | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/x1e80100.dtsi b/arch/arm64/boot/dts/qcom/x1e80100.dtsi index 51576d9c935de..6beef835c33ad 100644 --- a/arch/arm64/boot/dts/qcom/x1e80100.dtsi +++ b/arch/arm64/boot/dts/qcom/x1e80100.dtsi @@ -4939,15 +4939,8 @@ dma-coherent; - ports { - #address-cells = <1>; - #size-cells = <0>; - - port@0 { - reg = <0>; - - usb_2_dwc3_hs: endpoint { - }; + port { + usb_2_dwc3_hs: endpoint { }; }; }; From 7ecbc8f8b2da66116976816fc8c9f43366422b29 Mon Sep 17 00:00:00 2001 From: Krishna Kurapati Date: Fri, 24 Oct 2025 16:20:18 +0530 Subject: [PATCH 0491/2333] arm64: dts: qcom: x1e80100: Add missing quirk for HS only USB controller [ Upstream commit 6b3e8a5d6c88609d9ce93789524f818cca0aa485 ] The PIPE clock is provided by the USB3 PHY, which is predictably not connected to the HS-only controller. Add "qcom,select-utmi-as-pipe-clk" quirk to HS only USB controller to disable pipe clock requirement. Fixes: 4af46b7bd66f ("arm64: dts: qcom: x1e80100: Add USB nodes") Signed-off-by: Krishna Kurapati Reviewed-by: Abel Vesa Link: https://lore.kernel.org/r/20251024105019.2220832-2-krishna.kurapati@oss.qualcomm.com Signed-off-by: Bjorn Andersson Signed-off-by: Sasha Levin --- arch/arm64/boot/dts/qcom/x1e80100.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/boot/dts/qcom/x1e80100.dtsi b/arch/arm64/boot/dts/qcom/x1e80100.dtsi index 6beef835c33ad..662ad694cd914 100644 --- a/arch/arm64/boot/dts/qcom/x1e80100.dtsi +++ b/arch/arm64/boot/dts/qcom/x1e80100.dtsi @@ -4922,6 +4922,7 @@ interconnect-names = "usb-ddr", "apps-usb"; + qcom,select-utmi-as-pipe-clk; wakeup-source; status = "disabled"; From b5cc20b665cfe1650633e593696138e262acb0c8 Mon Sep 17 00:00:00 2001 From: Krishna Kurapati Date: Fri, 24 Oct 2025 16:20:19 +0530 Subject: [PATCH 0492/2333] arm64: dts: qcom: lemans: Add missing quirk for HS only USB controller [ Upstream commit 0903296efd0b4e17c8d556ce8c33347147301870 ] The PIPE clock is provided by the USB3 PHY, which is predictably not connected to the HS-only controller. Add "qcom,select-utmi-as-pipe-clk" quirk to HS only USB controller to disable pipe clock requirement. Fixes: de1001525c1a ("arm64: dts: qcom: sa8775p: add USB nodes") Signed-off-by: Krishna Kurapati Reviewed-by: Abel Vesa Link: https://lore.kernel.org/r/20251024105019.2220832-3-krishna.kurapati@oss.qualcomm.com Signed-off-by: Bjorn Andersson Signed-off-by: Sasha Levin --- arch/arm64/boot/dts/qcom/lemans.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/boot/dts/qcom/lemans.dtsi b/arch/arm64/boot/dts/qcom/lemans.dtsi index cf685cb186edc..c2d2200d845b3 100644 --- a/arch/arm64/boot/dts/qcom/lemans.dtsi +++ b/arch/arm64/boot/dts/qcom/lemans.dtsi @@ -4106,6 +4106,7 @@ <&gem_noc MASTER_APPSS_PROC 0 &config_noc SLAVE_USB2 0>; interconnect-names = "usb-ddr", "apps-usb"; + qcom,select-utmi-as-pipe-clk; wakeup-source; iommus = <&apps_smmu 0x020 0x0>; From 6044e4081959519faaf3b91495bee97ff2c57795 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Mon, 27 Oct 2025 11:24:57 +0100 Subject: [PATCH 0493/2333] tools/nolibc: x86: fix section mismatch caused by asm "mem*" functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 2602949b22330f1275138e2b5aea5d49126b9757 ] I recently got occasional build failures at -Os or -Oz that would always involve waitpid(), where the assembler would complain about this: init.s: Error: .size expression for waitpid.constprop.0 does not evaluate to a constant And without -fno-asynchronous-unwind-tables it could also spit such errors: init.s:836: Error: CFI instruction used without previous .cfi_startproc init.s:838: Error: .cfi_endproc without corresponding .cfi_startproc init.s: Error: open CFI at the end of file; missing .cfi_endproc directive A trimmed down reproducer is as simple as this: int main(int argc, char **argv) { int ret, status; if (argc == 0) ret = waitpid(-1, &status, 0); else ret = waitpid(-1, &status, 0); return status; } It produces the following asm code on x86_64: .text .section .text.nolibc_memmove_memcpy .weak memmove .weak memcpy memmove: memcpy: movq %rdx, %rcx (...) retq .section .text.nolibc_memset .weak memset memset: xchgl %eax, %esi movq %rdx, %rcx pushq %rdi rep stosb popq %rax retq .type waitpid.constprop.0.isra.0, @function waitpid.constprop.0.isra.0: subq $8, %rsp (...) jmp *.L5(,%rax,8) .section .rodata .align 8 .align 4 .L5: .quad .L10 (...) .quad .L4 .text .L10: (...) .cfi_def_cfa_offset 8 ret .cfi_endproc .LFE273: .size waitpid.constprop.0.isra.0, .-waitpid.constprop.0.isra.0 It's a bit dense, but here's the explanation: the compiler has emitted a ".text" statement because it knows it's working in the .text section. Then, our hand-written asm code for the mem* functions forced the section to .text.something without the compiler knowing about it, so it thinks the code is still being emitted for .text. As such, without any .section statement, the waitpid.constprop.0.isra.0 label is in fact placed in the previously created section, here .text.nolibc_memset. The waitpid() function involves a switch/case statement that can be turned to a jump table, which is what the compiler does with the .rodata section, and after that it restores .text, which is no longer the previous .text.nolibc_memset section. Then the CFI statements cross a section, so does the .size calculation, which explains the error. While a first approach consisting in placing an explicit ".text" at the end of these functions was verified to work, it's still unreliable as it depends on what the compiler remembers having emitted previously. A better approach is to replace the ".section" with ".pushsection", and place a ".popsection" at the end, so that these code blocks are agnostic to where they're placed relative to other blocks. Fixes: 553845eebd60 ("tools/nolibc: x86-64: Use `rep movsb` for `memcpy()` and `memmove()`") Fixes: 12108aa8c1a1 ("tools/nolibc: x86-64: Use `rep stosb` for `memset()`") Signed-off-by: Willy Tarreau Signed-off-by: Thomas Weißschuh Signed-off-by: Sasha Levin --- tools/include/nolibc/arch-x86.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tools/include/nolibc/arch-x86.h b/tools/include/nolibc/arch-x86.h index d3efc0c3b8adc..c8b0c3e624a51 100644 --- a/tools/include/nolibc/arch-x86.h +++ b/tools/include/nolibc/arch-x86.h @@ -351,7 +351,7 @@ void *memcpy(void *dst, const void *src, size_t len); void *memset(void *dst, int c, size_t len); __asm__ ( -".section .text.nolibc_memmove_memcpy\n" +".pushsection .text.nolibc_memmove_memcpy\n" ".weak memmove\n" ".weak memcpy\n" "memmove:\n" @@ -371,8 +371,9 @@ __asm__ ( "rep movsb\n\t" "cld\n\t" "retq\n" +".popsection\n" -".section .text.nolibc_memset\n" +".pushsection .text.nolibc_memset\n" ".weak memset\n" "memset:\n" "xchgl %eax, %esi\n\t" @@ -381,6 +382,7 @@ __asm__ ( "rep stosb\n\t" "popq %rax\n\t" "retq\n" +".popsection\n" ); #endif /* !defined(__x86_64__) */ From ff24f6314f1cfc82a9304681ba915b90ab14902e Mon Sep 17 00:00:00 2001 From: Dzmitry Sankouski Date: Fri, 26 Sep 2025 20:13:26 +0300 Subject: [PATCH 0494/2333] arm64: dts: qcom: sdm845-starqltechn: remove (address|size)-cells [ Upstream commit 4133486382364f60ea7e4f2c9070555689d9606e ] Drop the unused address/size-cells properties to silence the DT checker warning: pmic@66 (maxim,max77705): '#address-cells', '#size-cells' do not match any of the regexes: '^pinctrl-[0-9]+$' Fixes: 7a88a931d095 ("arm64: dts: qcom: sdm845-starqltechn: add max77705 PMIC") Reviewed-by: Konrad Dybcio Signed-off-by: Dzmitry Sankouski Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20250926-starqltechn-correct_max77705_nodes-v5-1-c6ab35165534@gmail.com Signed-off-by: Bjorn Andersson Signed-off-by: Sasha Levin --- arch/arm64/boot/dts/qcom/sdm845-samsung-starqltechn.dts | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm845-samsung-starqltechn.dts b/arch/arm64/boot/dts/qcom/sdm845-samsung-starqltechn.dts index 75a53f0bbebd0..45c7aa0f602d8 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-samsung-starqltechn.dts +++ b/arch/arm64/boot/dts/qcom/sdm845-samsung-starqltechn.dts @@ -606,8 +606,6 @@ interrupts = <11 IRQ_TYPE_LEVEL_LOW>; pinctrl-0 = <&pmic_int_default>; pinctrl-names = "default"; - #address-cells = <1>; - #size-cells = <0>; leds { compatible = "maxim,max77705-rgb"; From f4e3cbc96b8632888c970478b59c8a6b6f056ff8 Mon Sep 17 00:00:00 2001 From: Dzmitry Sankouski Date: Fri, 26 Sep 2025 20:13:27 +0300 Subject: [PATCH 0495/2333] arm64: dts: qcom: sdm845-starqltechn: fix max77705 interrupts [ Upstream commit 4372b15d89e253e40816f0bde100890cddd25a81 ] Since max77705 has a register, which indicates interrupt source, it acts as an interrupt controller. Direct MAX77705's subdevices to use the IC's internal interrupt controller, instead of listening to every interrupt fired by the chip towards the host device. Fixes: 7a88a931d095 ("arm64: dts: qcom: sdm845-starqltechn: add max77705 PMIC") Reviewed-by: Dmitry Baryshkov Signed-off-by: Dzmitry Sankouski Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20250926-starqltechn-correct_max77705_nodes-v5-2-c6ab35165534@gmail.com Signed-off-by: Bjorn Andersson Signed-off-by: Sasha Levin --- .../boot/dts/qcom/sdm845-samsung-starqltechn.dts | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm845-samsung-starqltechn.dts b/arch/arm64/boot/dts/qcom/sdm845-samsung-starqltechn.dts index 45c7aa0f602d8..215e1491f3e9a 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-samsung-starqltechn.dts +++ b/arch/arm64/boot/dts/qcom/sdm845-samsung-starqltechn.dts @@ -599,11 +599,13 @@ &i2c14 { status = "okay"; - pmic@66 { + max77705: pmic@66 { compatible = "maxim,max77705"; reg = <0x66>; + #interrupt-cells = <1>; interrupt-parent = <&pm8998_gpios>; interrupts = <11 IRQ_TYPE_LEVEL_LOW>; + interrupt-controller; pinctrl-0 = <&pmic_int_default>; pinctrl-names = "default"; @@ -644,8 +646,8 @@ reg = <0x69>; compatible = "maxim,max77705-charger"; monitored-battery = <&battery>; - interrupt-parent = <&pm8998_gpios>; - interrupts = <11 IRQ_TYPE_LEVEL_LOW>; + interrupt-parent = <&max77705>; + interrupts = <0>; }; fuel-gauge@36 { @@ -653,8 +655,8 @@ compatible = "maxim,max77705-battery"; power-supplies = <&max77705_charger>; maxim,rsns-microohm = <5000>; - interrupt-parent = <&pm8998_gpios>; - interrupts = <11 IRQ_TYPE_LEVEL_LOW>; + interrupt-parent = <&max77705>; + interrupts = <2>; }; }; From 63f8119b2ca14ed1e0b4bab598bef0811866f705 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Sat, 27 Sep 2025 13:20:28 +0200 Subject: [PATCH 0496/2333] arm64: dts: qcom: sdm845-oneplus: Correct gpio used for slider [ Upstream commit d7ec7d34237498fab7a6afed8da4b7139b0e387c ] The previous GPIO numbers were wrong. Update them to the correct ones and fix the label. Fixes: 288ef8a42612 ("arm64: dts: sdm845: add oneplus6/6t devices") Signed-off-by: Gergo Koteles Signed-off-by: David Heidelberg Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20250927-slider-correct-v1-1-fb8cc7fdcedf@ixit.cz Signed-off-by: Bjorn Andersson Signed-off-by: Sasha Levin --- arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi b/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi index dcfffb271fcf3..51a9a276399ac 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi @@ -803,8 +803,8 @@ bias-disable; }; - tri_state_key_default: tri-state-key-default-state { - pins = "gpio40", "gpio42", "gpio26"; + alert_slider_default: alert-slider-default-state { + pins = "gpio126", "gpio52", "gpio24"; function = "gpio"; drive-strength = <2>; bias-disable; From d9360ce07ea1274ce2af59f1eca2c858809bd3d6 Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Tue, 30 Sep 2025 15:57:01 +0200 Subject: [PATCH 0497/2333] arm64: dts: qcom: qcm6490-fairphone-fp5: Add supplies to simple-fb node [ Upstream commit 3d4142cac46b4dde4e60908c509c4cf107067114 ] Add the OLED power supplies to the simple-framebuffer node, so that the regulators don't get turned off while the simple-fb is being used. Fixes: c365a026155c ("arm64: dts: qcom: qcm6490-fairphone-fp5: Enable display") Signed-off-by: Luca Weiss Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20250930-sc7280-dts-misc-v1-1-5a45923ef705@fairphone.com Signed-off-by: Bjorn Andersson Signed-off-by: Sasha Levin --- arch/arm64/boot/dts/qcom/qcm6490-fairphone-fp5.dts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/qcm6490-fairphone-fp5.dts b/arch/arm64/boot/dts/qcom/qcm6490-fairphone-fp5.dts index 519e458e1a890..36d5750584831 100644 --- a/arch/arm64/boot/dts/qcom/qcm6490-fairphone-fp5.dts +++ b/arch/arm64/boot/dts/qcom/qcm6490-fairphone-fp5.dts @@ -47,6 +47,8 @@ stride = <(1224 * 4)>; format = "a8r8g8b8"; clocks = <&gcc GCC_DISP_HF_AXI_CLK>; + vci-supply = <&vreg_oled_vci>; + dvdd-supply = <&vreg_oled_dvdd>; }; }; From 436017ec6beebc72550a621977be77f890221194 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Tue, 7 Oct 2025 20:53:44 +0200 Subject: [PATCH 0498/2333] arm64: dts: qcom: sm8650: set ufs as dma coherent [ Upstream commit c2703c90161b45bca5b65f362adbae02ed71fcc1 ] The UFS device is ovbiously dma coherent like the other IOMMU devices like usb, mmc, ... let's fix this by adding the flag. To be sure an extensive test has been performed to be sure it's safe, as downstream uses this flag for UFS as well. As an experiment, I checked how the dma-coherent could impact the UFS bandwidth, and it happens the max bandwidth on cached write is slighly highter (up to 10%) while using less cpu time since cache sync/flush is skipped. Fixes: 10e024671295 ("arm64: dts: qcom: sm8650: add interconnect dependent device nodes") Signed-off-by: Neil Armstrong Reviewed-by: Krzysztof Kozlowski Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20251007-topic-sm8650-upstream-ufs-dma-coherent-v1-1-f3cfeaee04ce@linaro.org Signed-off-by: Bjorn Andersson Signed-off-by: Sasha Levin --- arch/arm64/boot/dts/qcom/sm8650.dtsi | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm8650.dtsi b/arch/arm64/boot/dts/qcom/sm8650.dtsi index ebf1971b1bfbe..3b03c13539386 100644 --- a/arch/arm64/boot/dts/qcom/sm8650.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8650.dtsi @@ -3988,6 +3988,8 @@ iommus = <&apps_smmu 0x60 0>; + dma-coherent; + lanes-per-direction = <2>; qcom,ice = <&ice>; From d30ffee3c9f8c98dd27b80becc0cf2035c28247b Mon Sep 17 00:00:00 2001 From: Krishna Chaitanya Chundru Date: Wed, 8 Oct 2025 10:08:55 +0530 Subject: [PATCH 0499/2333] arm64: dts: qcom: sm8750-mtp: move PCIe GPIOs to pcieport0 node [ Upstream commit cc8056a16472d186140d1a66ed5648cee41f4379 ] Relocate the wake-gpios and perst-gpios properties from the pcie0 controller node to the pcieport0 node. These GPIOs are associated with the PCIe root port and should reside under the pcieport0 node. Also rename perst-gpios to reset-gpios to match the expected property name in the PCIe port node. Fixes: 141714e163bb ("arm64: dts: qcom: sm8750-mtp: Add WiFi and Bluetooth") Signed-off-by: Krishna Chaitanya Chundru Reviewed-by: Krzysztof Kozlowski Tested-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20251008-sm8750-v1-1-daeadfcae980@oss.qualcomm.com Signed-off-by: Bjorn Andersson Signed-off-by: Sasha Levin --- arch/arm64/boot/dts/qcom/sm8750-mtp.dts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm8750-mtp.dts b/arch/arm64/boot/dts/qcom/sm8750-mtp.dts index 3bbb53b7c71f3..45b5f75815670 100644 --- a/arch/arm64/boot/dts/qcom/sm8750-mtp.dts +++ b/arch/arm64/boot/dts/qcom/sm8750-mtp.dts @@ -960,9 +960,6 @@ }; &pcie0 { - wake-gpios = <&tlmm 104 GPIO_ACTIVE_HIGH>; - perst-gpios = <&tlmm 102 GPIO_ACTIVE_LOW>; - pinctrl-0 = <&pcie0_default_state>; pinctrl-names = "default"; @@ -977,6 +974,9 @@ }; &pcieport0 { + wake-gpios = <&tlmm 104 GPIO_ACTIVE_HIGH>; + reset-gpios = <&tlmm 102 GPIO_ACTIVE_LOW>; + wifi@0 { compatible = "pci17cb,1107"; reg = <0x10000 0x0 0x0 0x0 0x0>; From f8d49ad15f580b0638fb62dac5a333e068c47eb9 Mon Sep 17 00:00:00 2001 From: Alexander Martinz Date: Thu, 9 Oct 2025 11:06:33 +0200 Subject: [PATCH 0500/2333] arm64: dts: qcom: qcm6490-shift-otter: Add missing reserved-memory [ Upstream commit f404fdcb50021fdad6bc734d69468cc777901a80 ] It seems we also need to reserve a region of 81 MiB called "removed_mem" otherwise we can easily hit memory errors with higher RAM usage. Fixes: 249666e34c24 ("arm64: dts: qcom: add QCM6490 SHIFTphone 8") Signed-off-by: Alexander Martinz Reviewed-by: Konrad Dybcio Signed-off-by: Luca Weiss Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20251009-otter-further-bringup-v2-3-5bb2f4a02cea@fairphone.com Signed-off-by: Bjorn Andersson Signed-off-by: Sasha Levin --- arch/arm64/boot/dts/qcom/qcm6490-shift-otter.dts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/qcm6490-shift-otter.dts b/arch/arm64/boot/dts/qcom/qcm6490-shift-otter.dts index eb8efba1b9dda..cc99925798873 100644 --- a/arch/arm64/boot/dts/qcom/qcm6490-shift-otter.dts +++ b/arch/arm64/boot/dts/qcom/qcm6490-shift-otter.dts @@ -118,6 +118,11 @@ no-map; }; + removed_mem: removed@c0000000 { + reg = <0x0 0xc0000000 0x0 0x5100000>; + no-map; + }; + rmtfs_mem: rmtfs@f8500000 { compatible = "qcom,rmtfs-mem"; reg = <0x0 0xf8500000 0x0 0x600000>; From e4badd5c24f75637a05b386010262e7076433f8b Mon Sep 17 00:00:00 2001 From: Val Packett Date: Sun, 12 Oct 2025 19:40:08 -0300 Subject: [PATCH 0501/2333] arm64: dts: qcom: x1-dell-thena: Add missing pinctrl for eDP HPD [ Upstream commit 1bdfe3edd4c862f97ac65b60da1db999981fc52a ] The commit a41d23142d87 ("arm64: dts: qcom: x1e80100-dell-xps13-9345: Add missing pinctrl for eDP HPD") has applied this change to a very similar machine, so apply it here too. This allows us not to rely on the boot firmware to set up the pinctrl for the eDP HPD line of the internal display. Fixes: e7733b42111c ("arm64: dts: qcom: Add support for Dell Inspiron 7441 / Latitude 7455") Reviewed-by: Bryan O'Donoghue Signed-off-by: Val Packett Link: https://lore.kernel.org/r/20251012224706.14311-1-val@packett.cool Signed-off-by: Bjorn Andersson Signed-off-by: Sasha Levin --- arch/arm64/boot/dts/qcom/x1-dell-thena.dtsi | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/x1-dell-thena.dtsi b/arch/arm64/boot/dts/qcom/x1-dell-thena.dtsi index cc64558ed5e6f..9df66295660c3 100644 --- a/arch/arm64/boot/dts/qcom/x1-dell-thena.dtsi +++ b/arch/arm64/boot/dts/qcom/x1-dell-thena.dtsi @@ -1039,6 +1039,9 @@ &mdss_dp3 { /delete-property/ #sound-dai-cells; + pinctrl-0 = <&edp0_hpd_default>; + pinctrl-names = "default"; + status = "okay"; aux-bus { From a2d1270ee7eff05fee743b264be52c9d9dc37b08 Mon Sep 17 00:00:00 2001 From: Val Packett Date: Sun, 12 Oct 2025 19:48:07 -0300 Subject: [PATCH 0502/2333] arm64: dts: qcom: x1-dell-thena: remove dp data-lanes [ Upstream commit 147d5eefab8f0e17e9951fb5e0c4c77bada34558 ] The commit 458de584248a ("arm64: dts: qcom: x1e80100: move dp0/1/2 data-lanes to SoC dtsi") has landed before this file was added, so the data-lanes lines here remained. Remove them to enable 4-lane DP on the X1E Dell Inspiron/Latitude. Fixes: e7733b42111c ("arm64: dts: qcom: Add support for Dell Inspiron 7441 / Latitude 7455") Reviewed-by: Bryan O'Donoghue Signed-off-by: Val Packett Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20251012224909.14988-1-val@packett.cool Signed-off-by: Bjorn Andersson Signed-off-by: Sasha Levin --- arch/arm64/boot/dts/qcom/x1-dell-thena.dtsi | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/x1-dell-thena.dtsi b/arch/arm64/boot/dts/qcom/x1-dell-thena.dtsi index 9df66295660c3..847b678f040c0 100644 --- a/arch/arm64/boot/dts/qcom/x1-dell-thena.dtsi +++ b/arch/arm64/boot/dts/qcom/x1-dell-thena.dtsi @@ -1023,7 +1023,6 @@ }; &mdss_dp0_out { - data-lanes = <0 1>; link-frequencies = /bits/ 64 <1620000000 2700000000 5400000000 8100000000>; }; @@ -1032,7 +1031,6 @@ }; &mdss_dp1_out { - data-lanes = <0 1>; link-frequencies = /bits/ 64 <1620000000 2700000000 5400000000 8100000000>; }; From 20d56cf50da21d6eda835df433ba3525c187d880 Mon Sep 17 00:00:00 2001 From: Pengyu Luo Date: Mon, 13 Oct 2025 19:55:05 +0800 Subject: [PATCH 0503/2333] arm64: dts: qcom: sc8280xp: Fix shifted GPI DMA channels [ Upstream commit fb48d3f3abba9a7bca2814fa2e9db8ac5b9e16b9 ] The GPI DMA channels in sc8280xp.dtsi are wrong. Let's fix it. Origianl patch was rebased to the linux-next and formated to a new patch again later, then it got the GPI DMA channels in the new patch shifted. Fixes: 71b12166a2be ("arm64: dts: qcom: sc8280xp: Describe GPI DMA controller nodes") Signed-off-by: Pengyu Luo Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20251013115506.103649-1-mitltlatltl@gmail.com Signed-off-by: Bjorn Andersson Signed-off-by: Sasha Levin --- arch/arm64/boot/dts/qcom/sc8280xp.dtsi | 170 ++++++++++++------------- 1 file changed, 85 insertions(+), 85 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sc8280xp.dtsi b/arch/arm64/boot/dts/qcom/sc8280xp.dtsi index 279e5e6beae20..963ce2362a52e 100644 --- a/arch/arm64/boot/dts/qcom/sc8280xp.dtsi +++ b/arch/arm64/boot/dts/qcom/sc8280xp.dtsi @@ -967,8 +967,8 @@ <&aggre1_noc MASTER_QUP_2 0 &mc_virt SLAVE_EBI1 0>; interconnect-names = "qup-core", "qup-config", "qup-memory"; - dmas = <&gpi_dma2 0 6 QCOM_GPI_SPI>, - <&gpi_dma2 1 6 QCOM_GPI_SPI>; + dmas = <&gpi_dma2 0 0 QCOM_GPI_I2C>, + <&gpi_dma2 1 0 QCOM_GPI_I2C>; dma-names = "tx", "rx"; @@ -989,8 +989,8 @@ <&aggre1_noc MASTER_QUP_2 0 &mc_virt SLAVE_EBI1 0>; interconnect-names = "qup-core", "qup-config", "qup-memory"; - dmas = <&gpi_dma2 0 0 QCOM_GPI_I2C>, - <&gpi_dma2 1 0 QCOM_GPI_I2C>; + dmas = <&gpi_dma2 0 0 QCOM_GPI_SPI>, + <&gpi_dma2 1 0 QCOM_GPI_SPI>; dma-names = "tx", "rx"; @@ -1011,8 +1011,8 @@ <&aggre1_noc MASTER_QUP_2 0 &mc_virt SLAVE_EBI1 0>; interconnect-names = "qup-core", "qup-config", "qup-memory"; - dmas = <&gpi_dma2 0 0 QCOM_GPI_SPI>, - <&gpi_dma2 1 0 QCOM_GPI_SPI>; + dmas = <&gpi_dma2 0 1 QCOM_GPI_I2C>, + <&gpi_dma2 1 1 QCOM_GPI_I2C>; dma-names = "tx", "rx"; @@ -1033,8 +1033,8 @@ <&aggre1_noc MASTER_QUP_2 0 &mc_virt SLAVE_EBI1 0>; interconnect-names = "qup-core", "qup-config", "qup-memory"; - dmas = <&gpi_dma2 0 1 QCOM_GPI_I2C>, - <&gpi_dma2 1 1 QCOM_GPI_I2C>; + dmas = <&gpi_dma2 0 1 QCOM_GPI_SPI>, + <&gpi_dma2 1 1 QCOM_GPI_SPI>; dma-names = "tx", "rx"; @@ -1069,8 +1069,8 @@ <&aggre1_noc MASTER_QUP_2 0 &mc_virt SLAVE_EBI1 0>; interconnect-names = "qup-core", "qup-config", "qup-memory"; - dmas = <&gpi_dma2 0 1 QCOM_GPI_SPI>, - <&gpi_dma2 1 1 QCOM_GPI_SPI>; + dmas = <&gpi_dma2 0 2 QCOM_GPI_I2C>, + <&gpi_dma2 1 2 QCOM_GPI_I2C>; dma-names = "tx", "rx"; @@ -1091,8 +1091,8 @@ <&aggre1_noc MASTER_QUP_2 0 &mc_virt SLAVE_EBI1 0>; interconnect-names = "qup-core", "qup-config", "qup-memory"; - dmas = <&gpi_dma2 0 2 QCOM_GPI_I2C>, - <&gpi_dma2 1 2 QCOM_GPI_I2C>; + dmas = <&gpi_dma2 0 2 QCOM_GPI_SPI>, + <&gpi_dma2 1 2 QCOM_GPI_SPI>; dma-names = "tx", "rx"; @@ -1131,8 +1131,8 @@ <&aggre1_noc MASTER_QUP_2 0 &mc_virt SLAVE_EBI1 0>; interconnect-names = "qup-core", "qup-config", "qup-memory"; - dmas = <&gpi_dma2 0 2 QCOM_GPI_SPI>, - <&gpi_dma2 1 2 QCOM_GPI_SPI>; + dmas = <&gpi_dma2 0 3 QCOM_GPI_I2C>, + <&gpi_dma2 1 3 QCOM_GPI_I2C>; dma-names = "tx", "rx"; @@ -1153,8 +1153,8 @@ <&aggre1_noc MASTER_QUP_2 0 &mc_virt SLAVE_EBI1 0>; interconnect-names = "qup-core", "qup-config", "qup-memory"; - dmas = <&gpi_dma2 0 3 QCOM_GPI_I2C>, - <&gpi_dma2 1 3 QCOM_GPI_I2C>; + dmas = <&gpi_dma2 0 3 QCOM_GPI_SPI>, + <&gpi_dma2 1 3 QCOM_GPI_SPI>; dma-names = "tx", "rx"; @@ -1175,8 +1175,8 @@ <&aggre1_noc MASTER_QUP_2 0 &mc_virt SLAVE_EBI1 0>; interconnect-names = "qup-core", "qup-config", "qup-memory"; - dmas = <&gpi_dma2 0 3 QCOM_GPI_SPI>, - <&gpi_dma2 1 3 QCOM_GPI_SPI>; + dmas = <&gpi_dma2 0 4 QCOM_GPI_I2C>, + <&gpi_dma2 1 4 QCOM_GPI_I2C>; dma-names = "tx", "rx"; @@ -1197,8 +1197,8 @@ <&aggre1_noc MASTER_QUP_2 0 &mc_virt SLAVE_EBI1 0>; interconnect-names = "qup-core", "qup-config", "qup-memory"; - dmas = <&gpi_dma2 0 4 QCOM_GPI_I2C>, - <&gpi_dma2 1 4 QCOM_GPI_I2C>; + dmas = <&gpi_dma2 0 4 QCOM_GPI_SPI>, + <&gpi_dma2 1 4 QCOM_GPI_SPI>; dma-names = "tx", "rx"; @@ -1241,8 +1241,8 @@ <&aggre1_noc MASTER_QUP_2 0 &mc_virt SLAVE_EBI1 0>; interconnect-names = "qup-core", "qup-config", "qup-memory"; - dmas = <&gpi_dma2 0 4 QCOM_GPI_SPI>, - <&gpi_dma2 1 4 QCOM_GPI_SPI>; + dmas = <&gpi_dma2 0 5 QCOM_GPI_SPI>, + <&gpi_dma2 1 5 QCOM_GPI_SPI>; dma-names = "tx", "rx"; @@ -1285,8 +1285,8 @@ <&aggre1_noc MASTER_QUP_2 0 &mc_virt SLAVE_EBI1 0>; interconnect-names = "qup-core", "qup-config", "qup-memory"; - dmas = <&gpi_dma2 0 5 QCOM_GPI_SPI>, - <&gpi_dma2 1 5 QCOM_GPI_SPI>; + dmas = <&gpi_dma2 0 6 QCOM_GPI_SPI>, + <&gpi_dma2 1 6 QCOM_GPI_SPI>; dma-names = "tx", "rx"; @@ -1338,7 +1338,7 @@ }; }; - gpi_dma0: dma-controller@900000 { + gpi_dma0: dma-controller@900000 { compatible = "qcom,sc8280xp-gpi-dma", "qcom,sm6350-gpi-dma"; reg = <0 0x00900000 0 0x60000>; @@ -1393,8 +1393,8 @@ <&aggre1_noc MASTER_QUP_0 0 &mc_virt SLAVE_EBI1 0>; interconnect-names = "qup-core", "qup-config", "qup-memory"; - dmas = <&gpi_dma0 0 7 QCOM_GPI_I2C>, - <&gpi_dma0 1 7 QCOM_GPI_I2C>; + dmas = <&gpi_dma0 0 0 QCOM_GPI_I2C>, + <&gpi_dma0 1 0 QCOM_GPI_I2C>; dma-names = "tx", "rx"; @@ -1415,8 +1415,8 @@ <&aggre1_noc MASTER_QUP_0 0 &mc_virt SLAVE_EBI1 0>; interconnect-names = "qup-core", "qup-config", "qup-memory"; - dmas = <&gpi_dma0 0 0 QCOM_GPI_I2C>, - <&gpi_dma0 1 0 QCOM_GPI_I2C>; + dmas = <&gpi_dma0 0 0 QCOM_GPI_SPI>, + <&gpi_dma0 1 0 QCOM_GPI_SPI>; dma-names = "tx", "rx"; @@ -1437,8 +1437,8 @@ <&aggre1_noc MASTER_QUP_0 0 &mc_virt SLAVE_EBI1 0>; interconnect-names = "qup-core", "qup-config", "qup-memory"; - dmas = <&gpi_dma0 0 0 QCOM_GPI_SPI>, - <&gpi_dma0 1 0 QCOM_GPI_SPI>; + dmas = <&gpi_dma0 0 1 QCOM_GPI_I2C>, + <&gpi_dma0 1 1 QCOM_GPI_I2C>; dma-names = "tx", "rx"; @@ -1459,8 +1459,8 @@ <&aggre1_noc MASTER_QUP_0 0 &mc_virt SLAVE_EBI1 0>; interconnect-names = "qup-core", "qup-config", "qup-memory"; - dmas = <&gpi_dma0 0 1 QCOM_GPI_I2C>, - <&gpi_dma0 1 1 QCOM_GPI_I2C>; + dmas = <&gpi_dma0 0 1 QCOM_GPI_SPI>, + <&gpi_dma0 1 1 QCOM_GPI_SPI>; dma-names = "tx", "rx"; @@ -1481,8 +1481,8 @@ <&aggre1_noc MASTER_QUP_0 0 &mc_virt SLAVE_EBI1 0>; interconnect-names = "qup-core", "qup-config", "qup-memory"; - dmas = <&gpi_dma0 0 1 QCOM_GPI_SPI>, - <&gpi_dma0 1 1 QCOM_GPI_SPI>; + dmas = <&gpi_dma0 0 2 QCOM_GPI_I2C>, + <&gpi_dma0 1 2 QCOM_GPI_I2C>; dma-names = "tx", "rx"; @@ -1503,8 +1503,8 @@ <&aggre1_noc MASTER_QUP_0 0 &mc_virt SLAVE_EBI1 0>; interconnect-names = "qup-core", "qup-config", "qup-memory"; - dmas = <&gpi_dma0 0 2 QCOM_GPI_I2C>, - <&gpi_dma0 1 2 QCOM_GPI_I2C>; + dmas = <&gpi_dma0 0 2 QCOM_GPI_SPI>, + <&gpi_dma0 1 2 QCOM_GPI_SPI>; dma-names = "tx", "rx"; @@ -1539,8 +1539,8 @@ <&aggre1_noc MASTER_QUP_0 0 &mc_virt SLAVE_EBI1 0>; interconnect-names = "qup-core", "qup-config", "qup-memory"; - dmas = <&gpi_dma0 0 2 QCOM_GPI_SPI>, - <&gpi_dma0 1 2 QCOM_GPI_SPI>; + dmas = <&gpi_dma0 0 3 QCOM_GPI_I2C>, + <&gpi_dma0 1 3 QCOM_GPI_I2C>; dma-names = "tx", "rx"; @@ -1561,8 +1561,8 @@ <&aggre1_noc MASTER_QUP_0 0 &mc_virt SLAVE_EBI1 0>; interconnect-names = "qup-core", "qup-config", "qup-memory"; - dmas = <&gpi_dma0 0 3 QCOM_GPI_I2C>, - <&gpi_dma0 1 3 QCOM_GPI_I2C>; + dmas = <&gpi_dma0 0 3 QCOM_GPI_SPI>, + <&gpi_dma0 1 3 QCOM_GPI_SPI>; dma-names = "tx", "rx"; @@ -1583,8 +1583,8 @@ <&aggre1_noc MASTER_QUP_0 0 &mc_virt SLAVE_EBI1 0>; interconnect-names = "qup-core", "qup-config", "qup-memory"; - dmas = <&gpi_dma0 0 3 QCOM_GPI_SPI>, - <&gpi_dma0 1 3 QCOM_GPI_SPI>; + dmas = <&gpi_dma0 0 4 QCOM_GPI_I2C>, + <&gpi_dma0 1 4 QCOM_GPI_I2C>; dma-names = "tx", "rx"; @@ -1605,8 +1605,8 @@ <&aggre1_noc MASTER_QUP_0 0 &mc_virt SLAVE_EBI1 0>; interconnect-names = "qup-core", "qup-config", "qup-memory"; - dmas = <&gpi_dma0 0 4 QCOM_GPI_I2C>, - <&gpi_dma0 1 4 QCOM_GPI_I2C>; + dmas = <&gpi_dma0 0 4 QCOM_GPI_SPI>, + <&gpi_dma0 1 4 QCOM_GPI_SPI>; dma-names = "tx", "rx"; @@ -1627,8 +1627,8 @@ <&aggre1_noc MASTER_QUP_0 0 &mc_virt SLAVE_EBI1 0>; interconnect-names = "qup-core", "qup-config", "qup-memory"; - dmas = <&gpi_dma0 0 4 QCOM_GPI_SPI>, - <&gpi_dma0 1 4 QCOM_GPI_SPI>; + dmas = <&gpi_dma0 0 5 QCOM_GPI_I2C>, + <&gpi_dma0 1 5 QCOM_GPI_I2C>; dma-names = "tx", "rx"; @@ -1649,8 +1649,8 @@ <&aggre1_noc MASTER_QUP_0 0 &mc_virt SLAVE_EBI1 0>; interconnect-names = "qup-core", "qup-config", "qup-memory"; - dmas = <&gpi_dma0 0 5 QCOM_GPI_I2C>, - <&gpi_dma0 1 5 QCOM_GPI_I2C>; + dmas = <&gpi_dma0 0 5 QCOM_GPI_SPI>, + <&gpi_dma0 1 5 QCOM_GPI_SPI>; dma-names = "tx", "rx"; @@ -1671,8 +1671,8 @@ <&aggre1_noc MASTER_QUP_0 0 &mc_virt SLAVE_EBI1 0>; interconnect-names = "qup-core", "qup-config", "qup-memory"; - dmas = <&gpi_dma0 0 5 QCOM_GPI_SPI>, - <&gpi_dma0 1 5 QCOM_GPI_SPI>; + dmas = <&gpi_dma0 0 6 QCOM_GPI_I2C>, + <&gpi_dma0 1 6 QCOM_GPI_I2C>; dma-names = "tx", "rx"; @@ -1693,8 +1693,8 @@ <&aggre1_noc MASTER_QUP_0 0 &mc_virt SLAVE_EBI1 0>; interconnect-names = "qup-core", "qup-config", "qup-memory"; - dmas = <&gpi_dma0 0 6 QCOM_GPI_I2C>, - <&gpi_dma0 1 6 QCOM_GPI_I2C>; + dmas = <&gpi_dma0 0 6 QCOM_GPI_SPI>, + <&gpi_dma0 1 6 QCOM_GPI_SPI>; dma-names = "tx", "rx"; @@ -1715,8 +1715,8 @@ <&aggre1_noc MASTER_QUP_0 0 &mc_virt SLAVE_EBI1 0>; interconnect-names = "qup-core", "qup-config", "qup-memory"; - dmas = <&gpi_dma0 0 6 QCOM_GPI_SPI>, - <&gpi_dma0 1 6 QCOM_GPI_SPI>; + dmas = <&gpi_dma0 0 7 QCOM_GPI_I2C>, + <&gpi_dma0 1 7 QCOM_GPI_I2C>; dma-names = "tx", "rx"; @@ -1800,8 +1800,8 @@ <&aggre1_noc MASTER_QUP_1 0 &mc_virt SLAVE_EBI1 0>; interconnect-names = "qup-core", "qup-config", "qup-memory"; - dmas = <&gpi_dma1 0 7 QCOM_GPI_I2C>, - <&gpi_dma1 1 7 QCOM_GPI_I2C>; + dmas = <&gpi_dma1 0 0 QCOM_GPI_I2C>, + <&gpi_dma1 1 0 QCOM_GPI_I2C>; dma-names = "tx", "rx"; @@ -1822,8 +1822,8 @@ <&aggre1_noc MASTER_QUP_1 0 &mc_virt SLAVE_EBI1 0>; interconnect-names = "qup-core", "qup-config", "qup-memory"; - dmas = <&gpi_dma1 0 0 QCOM_GPI_I2C>, - <&gpi_dma1 1 0 QCOM_GPI_I2C>; + dmas = <&gpi_dma1 0 0 QCOM_GPI_SPI>, + <&gpi_dma1 1 0 QCOM_GPI_SPI>; dma-names = "tx", "rx"; @@ -1844,8 +1844,8 @@ <&aggre1_noc MASTER_QUP_1 0 &mc_virt SLAVE_EBI1 0>; interconnect-names = "qup-core", "qup-config", "qup-memory"; - dmas = <&gpi_dma1 0 0 QCOM_GPI_SPI>, - <&gpi_dma1 1 0 QCOM_GPI_SPI>; + dmas = <&gpi_dma1 0 1 QCOM_GPI_I2C>, + <&gpi_dma1 1 1 QCOM_GPI_I2C>; dma-names = "tx", "rx"; @@ -1866,8 +1866,8 @@ <&aggre1_noc MASTER_QUP_1 0 &mc_virt SLAVE_EBI1 0>; interconnect-names = "qup-core", "qup-config", "qup-memory"; - dmas = <&gpi_dma1 0 1 QCOM_GPI_I2C>, - <&gpi_dma1 1 1 QCOM_GPI_I2C>; + dmas = <&gpi_dma1 0 1 QCOM_GPI_SPI>, + <&gpi_dma1 1 1 QCOM_GPI_SPI>; dma-names = "tx", "rx"; @@ -1888,8 +1888,8 @@ <&aggre1_noc MASTER_QUP_1 0 &mc_virt SLAVE_EBI1 0>; interconnect-names = "qup-core", "qup-config", "qup-memory"; - dmas = <&gpi_dma1 0 1 QCOM_GPI_SPI>, - <&gpi_dma1 1 1 QCOM_GPI_SPI>; + dmas = <&gpi_dma1 0 2 QCOM_GPI_I2C>, + <&gpi_dma1 1 2 QCOM_GPI_I2C>; dma-names = "tx", "rx"; @@ -1910,8 +1910,8 @@ <&aggre1_noc MASTER_QUP_1 0 &mc_virt SLAVE_EBI1 0>; interconnect-names = "qup-core", "qup-config", "qup-memory"; - dmas = <&gpi_dma1 0 2 QCOM_GPI_I2C>, - <&gpi_dma1 1 2 QCOM_GPI_I2C>; + dmas = <&gpi_dma1 0 2 QCOM_GPI_SPI>, + <&gpi_dma1 1 2 QCOM_GPI_SPI>; dma-names = "tx", "rx"; @@ -1932,8 +1932,8 @@ <&aggre1_noc MASTER_QUP_1 0 &mc_virt SLAVE_EBI1 0>; interconnect-names = "qup-core", "qup-config", "qup-memory"; - dmas = <&gpi_dma1 0 2 QCOM_GPI_SPI>, - <&gpi_dma1 1 2 QCOM_GPI_SPI>; + dmas = <&gpi_dma1 0 3 QCOM_GPI_I2C>, + <&gpi_dma1 1 3 QCOM_GPI_I2C>; dma-names = "tx", "rx"; @@ -1954,8 +1954,8 @@ <&aggre1_noc MASTER_QUP_1 0 &mc_virt SLAVE_EBI1 0>; interconnect-names = "qup-core", "qup-config", "qup-memory"; - dmas = <&gpi_dma1 0 3 QCOM_GPI_I2C>, - <&gpi_dma1 1 3 QCOM_GPI_I2C>; + dmas = <&gpi_dma1 0 3 QCOM_GPI_SPI>, + <&gpi_dma1 1 3 QCOM_GPI_SPI>; dma-names = "tx", "rx"; @@ -1976,8 +1976,8 @@ <&aggre1_noc MASTER_QUP_1 0 &mc_virt SLAVE_EBI1 0>; interconnect-names = "qup-core", "qup-config", "qup-memory"; - dmas = <&gpi_dma1 0 3 QCOM_GPI_SPI>, - <&gpi_dma1 1 3 QCOM_GPI_SPI>; + dmas = <&gpi_dma1 0 4 QCOM_GPI_I2C>, + <&gpi_dma1 1 4 QCOM_GPI_I2C>; dma-names = "tx", "rx"; @@ -1998,8 +1998,8 @@ <&aggre1_noc MASTER_QUP_1 0 &mc_virt SLAVE_EBI1 0>; interconnect-names = "qup-core", "qup-config", "qup-memory"; - dmas = <&gpi_dma1 0 4 QCOM_GPI_I2C>, - <&gpi_dma1 1 4 QCOM_GPI_I2C>; + dmas = <&gpi_dma1 0 4 QCOM_GPI_SPI>, + <&gpi_dma1 1 4 QCOM_GPI_SPI>; dma-names = "tx", "rx"; @@ -2020,8 +2020,8 @@ <&aggre1_noc MASTER_QUP_1 0 &mc_virt SLAVE_EBI1 0>; interconnect-names = "qup-core", "qup-config", "qup-memory"; - dmas = <&gpi_dma1 0 4 QCOM_GPI_SPI>, - <&gpi_dma1 1 4 QCOM_GPI_SPI>; + dmas = <&gpi_dma1 0 5 QCOM_GPI_I2C>, + <&gpi_dma1 1 5 QCOM_GPI_I2C>; dma-names = "tx", "rx"; @@ -2042,8 +2042,8 @@ <&aggre1_noc MASTER_QUP_1 0 &mc_virt SLAVE_EBI1 0>; interconnect-names = "qup-core", "qup-config", "qup-memory"; - dmas = <&gpi_dma1 0 5 QCOM_GPI_I2C>, - <&gpi_dma1 1 5 QCOM_GPI_I2C>; + dmas = <&gpi_dma1 0 5 QCOM_GPI_SPI>, + <&gpi_dma1 1 5 QCOM_GPI_SPI>; dma-names = "tx", "rx"; @@ -2064,8 +2064,8 @@ <&aggre1_noc MASTER_QUP_1 0 &mc_virt SLAVE_EBI1 0>; interconnect-names = "qup-core", "qup-config", "qup-memory"; - dmas = <&gpi_dma1 0 5 QCOM_GPI_SPI>, - <&gpi_dma1 1 5 QCOM_GPI_SPI>; + dmas = <&gpi_dma1 0 6 QCOM_GPI_I2C>, + <&gpi_dma1 1 6 QCOM_GPI_I2C>; dma-names = "tx", "rx"; @@ -2086,8 +2086,8 @@ <&aggre1_noc MASTER_QUP_1 0 &mc_virt SLAVE_EBI1 0>; interconnect-names = "qup-core", "qup-config", "qup-memory"; - dmas = <&gpi_dma1 0 6 QCOM_GPI_I2C>, - <&gpi_dma1 1 6 QCOM_GPI_I2C>; + dmas = <&gpi_dma1 0 6 QCOM_GPI_SPI>, + <&gpi_dma1 1 6 QCOM_GPI_SPI>; dma-names = "tx", "rx"; @@ -2108,8 +2108,8 @@ <&aggre1_noc MASTER_QUP_1 0 &mc_virt SLAVE_EBI1 0>; interconnect-names = "qup-core", "qup-config", "qup-memory"; - dmas = <&gpi_dma1 0 6 QCOM_GPI_SPI>, - <&gpi_dma1 1 6 QCOM_GPI_SPI>; + dmas = <&gpi_dma1 0 7 QCOM_GPI_I2C>, + <&gpi_dma1 1 7 QCOM_GPI_I2C>; dma-names = "tx", "rx"; From 21c7d04fa88dcec046ceabdbea4700d41a018f98 Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Wed, 15 Oct 2025 18:32:16 +0200 Subject: [PATCH 0504/2333] arm64: dts: qcom: sdm845-starqltechn: Fix i2c-gpio node name [ Upstream commit 6030fa06360b8b8d898b66ac156adaaf990b83cb ] Fix the following DT checker warning: $nodename:0: 'i2c21' does not match '^i2c(@.+|-[a-z0-9]+)?$' Fixes: 3a4600448bef ("arm64: dts: qcom: sdm845-starqltechn: add display PMIC") Signed-off-by: Konrad Dybcio Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20251015-topic-starltechn_i2c_gpio-v1-1-6d303184ee87@oss.qualcomm.com Signed-off-by: Bjorn Andersson Signed-off-by: Sasha Levin --- arch/arm64/boot/dts/qcom/sdm845-samsung-starqltechn.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sdm845-samsung-starqltechn.dts b/arch/arm64/boot/dts/qcom/sdm845-samsung-starqltechn.dts index 215e1491f3e9a..493c69e991746 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-samsung-starqltechn.dts +++ b/arch/arm64/boot/dts/qcom/sdm845-samsung-starqltechn.dts @@ -158,7 +158,7 @@ }; }; - i2c21 { + i2c-21 { compatible = "i2c-gpio"; sda-gpios = <&tlmm 127 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; scl-gpios = <&tlmm 128 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; From bd55d00190673cbf609528fe3d4f8dc221a5226e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eric=20Gon=C3=A7alves?= Date: Thu, 16 Oct 2025 16:21:29 -0400 Subject: [PATCH 0505/2333] arm64: dts: qcom: sm8250-samsung-common: correct reserved pins MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 42e56b53a1919dbbd78e140a9f8223f8136ac360 ] The S20 series has additional reserved pins for the fingerprint sensor, GPIO 20-23. Correct it by adding them into gpio-reserved-ranges. Fixes: 6657fe9e9f23 ("arm64: dts: qcom: add initial support for Samsung Galaxy S20 FE") Signed-off-by: Eric Gonçalves Reviewed-by: Dmitry Baryshkov Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20251016202129.226449-1-ghatto404@gmail.com Signed-off-by: Bjorn Andersson Signed-off-by: Sasha Levin --- arch/arm64/boot/dts/qcom/sm8250-samsung-common.dtsi | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sm8250-samsung-common.dtsi b/arch/arm64/boot/dts/qcom/sm8250-samsung-common.dtsi index cf3d917addd82..ef7ea4f72bf99 100644 --- a/arch/arm64/boot/dts/qcom/sm8250-samsung-common.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8250-samsung-common.dtsi @@ -159,7 +159,8 @@ }; &tlmm { - gpio-reserved-ranges = <40 4>; /* I2C (Unused) */ + gpio-reserved-ranges = <20 4>, /* SPI (fingerprint scanner) */ + <40 4>; /* Unused */ }; &usb_1 { From cc12e90519c287c43de32dfbd6122fae5213bef7 Mon Sep 17 00:00:00 2001 From: Michal Suchanek Date: Wed, 22 Oct 2025 12:38:35 +0200 Subject: [PATCH 0506/2333] perf hwmon_pmu: Fix uninitialized variable warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 2fee899c068c159e486e62623afe9e2a4975bd79 ] The line_len is only set on success. Check the return value instead. util/hwmon_pmu.c: In function ‘perf_pmus__read_hwmon_pmus’: util/hwmon_pmu.c:742:20: warning: ‘line_len’ may be used uninitialized [-Wmaybe-uninitialized] 742 | if (line_len > 0 && line[line_len - 1] == '\n') | ^ util/hwmon_pmu.c:719:24: note: ‘line_len’ was declared here 719 | size_t line_len; Fixes: 53cc0b351ec9 ("perf hwmon_pmu: Add a tool PMU exposing events from hwmon in sysfs") Signed-off-by: Michal Suchanek Signed-off-by: Namhyung Kim Signed-off-by: Sasha Levin --- tools/perf/util/hwmon_pmu.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tools/perf/util/hwmon_pmu.c b/tools/perf/util/hwmon_pmu.c index 416dfea9ffff6..5c27256a220a5 100644 --- a/tools/perf/util/hwmon_pmu.c +++ b/tools/perf/util/hwmon_pmu.c @@ -742,8 +742,7 @@ int perf_pmus__read_hwmon_pmus(struct list_head *pmus) continue; } io__init(&io, name_fd, buf2, sizeof(buf2)); - io__getline(&io, &line, &line_len); - if (line_len > 0 && line[line_len - 1] == '\n') + if (io__getline(&io, &line, &line_len) > 0 && line[line_len - 1] == '\n') line[line_len - 1] = '\0'; hwmon_pmu__new(pmus, buf, class_hwmon_ent->d_name, line); close(name_fd); From 2cf1278e942b2d202f2d4ceeab70a810ebc4da0a Mon Sep 17 00:00:00 2001 From: Horatiu Vultur Date: Thu, 23 Oct 2025 21:13:50 +0200 Subject: [PATCH 0507/2333] phy: mscc: Fix PTP for VSC8574 and VSC8572 [ Upstream commit ea5df88aeca112aac69e6c32e3dd1433a113b0c9 ] The PTP initialization is two-step. First part are the function vsc8584_ptp_probe_once() and vsc8584_ptp_probe() at probe time which initialize the locks, queues, creates the PTP device. The second part is the function vsc8584_ptp_init() at config_init() time which initialize PTP in the HW. For VSC8574 and VSC8572, the PTP initialization is incomplete. It is missing the first part but it makes the second part. Meaning that the ptp_clock_register() is never called. There is no crash without the first part when enabling PTP but this is unexpected because some PHys have PTP functionality exposed by the driver and some don't even though they share the same PTP clock PTP. Fixes: 774626fa440e ("net: phy: mscc: Add PTP support for 2 more VSC PHYs") Reviewed-by: Maxime Chevallier Signed-off-by: Horatiu Vultur Link: https://patch.msgid.link/20251023191350.190940-3-horatiu.vultur@microchip.com Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- drivers/net/phy/mscc/mscc_main.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/phy/mscc/mscc_main.c b/drivers/net/phy/mscc/mscc_main.c index ef0ef1570d392..48d43f60b8ff8 100644 --- a/drivers/net/phy/mscc/mscc_main.c +++ b/drivers/net/phy/mscc/mscc_main.c @@ -2625,7 +2625,7 @@ static struct phy_driver vsc85xx_driver[] = { .suspend = &genphy_suspend, .resume = &genphy_resume, .remove = &vsc85xx_remove, - .probe = &vsc8574_probe, + .probe = &vsc8584_probe, .set_wol = &vsc85xx_wol_set, .get_wol = &vsc85xx_wol_get, .get_tunable = &vsc85xx_get_tunable, @@ -2648,12 +2648,12 @@ static struct phy_driver vsc85xx_driver[] = { .config_aneg = &vsc85xx_config_aneg, .aneg_done = &genphy_aneg_done, .read_status = &vsc85xx_read_status, - .handle_interrupt = vsc85xx_handle_interrupt, + .handle_interrupt = vsc8584_handle_interrupt, .config_intr = &vsc85xx_config_intr, .suspend = &genphy_suspend, .resume = &genphy_resume, .remove = &vsc85xx_remove, - .probe = &vsc8574_probe, + .probe = &vsc8584_probe, .set_wol = &vsc85xx_wol_set, .get_wol = &vsc85xx_wol_get, .get_tunable = &vsc85xx_get_tunable, From 7a26bcbe469c043780f1027bc10d1369ad1fc0b2 Mon Sep 17 00:00:00 2001 From: Kuniyuki Iwashima Date: Thu, 23 Oct 2025 23:16:50 +0000 Subject: [PATCH 0508/2333] sctp: Defer SCTP_DBG_OBJCNT_DEC() to sctp_destroy_sock(). [ Upstream commit 622e8838a29845316668ec2e7648428878df7f9a ] SCTP_DBG_OBJCNT_INC() is called only when sctp_init_sock() returns 0 after successfully allocating sctp_sk(sk)->ep. OTOH, SCTP_DBG_OBJCNT_DEC() is called in sctp_close(). The code seems to expect that the socket is always exposed to userspace once SCTP_DBG_OBJCNT_INC() is incremented, but there is a path where the assumption is not true. In sctp_accept(), sctp_sock_migrate() could fail after sctp_init_sock(). Then, sk_common_release() does not call inet_release() nor sctp_close(). Instead, it calls sk->sk_prot->destroy(). Let's move SCTP_DBG_OBJCNT_DEC() from sctp_close() to sctp_destroy_sock(). Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Signed-off-by: Kuniyuki Iwashima Acked-by: Xin Long Link: https://patch.msgid.link/20251023231751.4168390-2-kuniyu@google.com Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- net/sctp/socket.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/net/sctp/socket.c b/net/sctp/socket.c index ed8293a342402..d190e75e46454 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -1553,8 +1553,6 @@ static void sctp_close(struct sock *sk, long timeout) spin_unlock_bh(&net->sctp.addr_wq_lock); sock_put(sk); - - SCTP_DBG_OBJCNT_DEC(sock); } /* Handle EPIPE error. */ @@ -5109,9 +5107,12 @@ static void sctp_destroy_sock(struct sock *sk) sp->do_auto_asconf = 0; list_del(&sp->auto_asconf_list); } + sctp_endpoint_free(sp->ep); + sk_sockets_allocated_dec(sk); sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1); + SCTP_DBG_OBJCNT_DEC(sock); } static void sctp_destruct_sock(struct sock *sk) From a10b6eb5c5e59d74360829c7a8ac249a0a7f8160 Mon Sep 17 00:00:00 2001 From: Loic Poulain Date: Thu, 18 Sep 2025 17:54:56 +0200 Subject: [PATCH 0509/2333] arm64: dts: qcom: qcm2290: Fix camss register prop ordering [ Upstream commit 67445dc8a8060309eeb7aebbc41fa0e58302fc09 ] The qcm2290 CAMSS node has been applied from the V4 series, but a later version changed the order of the register property, fix it to prevent dtb check error. Fixes: 2b3aef30dd9d ("arm64: dts: qcom: qcm2290: Add CAMSS node") Signed-off-by: Loic Poulain Link: https://lore.kernel.org/r/20250918155456.1158691-1-loic.poulain@oss.qualcomm.com Signed-off-by: Bjorn Andersson Signed-off-by: Sasha Levin --- arch/arm64/boot/dts/qcom/qcm2290.dtsi | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/qcm2290.dtsi b/arch/arm64/boot/dts/qcom/qcm2290.dtsi index 08141b41de246..3b0ba590ee825 100644 --- a/arch/arm64/boot/dts/qcom/qcm2290.dtsi +++ b/arch/arm64/boot/dts/qcom/qcm2290.dtsi @@ -1685,25 +1685,25 @@ }; }; - camss: camss@5c6e000 { + camss: camss@5c11000 { compatible = "qcom,qcm2290-camss"; - reg = <0x0 0x5c6e000 0x0 0x1000>, + reg = <0x0 0x5c11000 0x0 0x1000>, + <0x0 0x5c6e000 0x0 0x1000>, <0x0 0x5c75000 0x0 0x1000>, <0x0 0x5c52000 0x0 0x1000>, <0x0 0x5c53000 0x0 0x1000>, <0x0 0x5c66000 0x0 0x400>, <0x0 0x5c68000 0x0 0x400>, - <0x0 0x5c11000 0x0 0x1000>, <0x0 0x5c6f000 0x0 0x4000>, <0x0 0x5c76000 0x0 0x4000>; - reg-names = "csid0", + reg-names = "top", + "csid0", "csid1", "csiphy0", "csiphy1", "csitpg0", "csitpg1", - "top", "vfe0", "vfe1"; From bc4c14a3863cc0e03698caec9a0cdabd779776ee Mon Sep 17 00:00:00 2001 From: Zhu Yanjun Date: Mon, 27 Oct 2025 14:52:03 -0700 Subject: [PATCH 0510/2333] RDMA/rxe: Fix null deref on srq->rq.queue after resize failure [ Upstream commit 503a5e4690ae14c18570141bc0dcf7501a8419b0 ] A NULL pointer dereference can occur in rxe_srq_chk_attr() when ibv_modify_srq() is invoked twice in succession under certain error conditions. The first call may fail in rxe_queue_resize(), which leads rxe_srq_from_attr() to set srq->rq.queue = NULL. The second call then triggers a crash (null deref) when accessing srq->rq.queue->buf->index_mask. Call Trace: rxe_modify_srq+0x170/0x480 [rdma_rxe] ? __pfx_rxe_modify_srq+0x10/0x10 [rdma_rxe] ? uverbs_try_lock_object+0x4f/0xa0 [ib_uverbs] ? rdma_lookup_get_uobject+0x1f0/0x380 [ib_uverbs] ib_uverbs_modify_srq+0x204/0x290 [ib_uverbs] ? __pfx_ib_uverbs_modify_srq+0x10/0x10 [ib_uverbs] ? tryinc_node_nr_active+0xe6/0x150 ? uverbs_fill_udata+0xed/0x4f0 [ib_uverbs] ib_uverbs_handler_UVERBS_METHOD_INVOKE_WRITE+0x2c0/0x470 [ib_uverbs] ? __pfx_ib_uverbs_handler_UVERBS_METHOD_INVOKE_WRITE+0x10/0x10 [ib_uverbs] ? uverbs_fill_udata+0xed/0x4f0 [ib_uverbs] ib_uverbs_run_method+0x55a/0x6e0 [ib_uverbs] ? __pfx_ib_uverbs_handler_UVERBS_METHOD_INVOKE_WRITE+0x10/0x10 [ib_uverbs] ib_uverbs_cmd_verbs+0x54d/0x800 [ib_uverbs] ? __pfx_ib_uverbs_cmd_verbs+0x10/0x10 [ib_uverbs] ? __pfx___raw_spin_lock_irqsave+0x10/0x10 ? __pfx_do_vfs_ioctl+0x10/0x10 ? ioctl_has_perm.constprop.0.isra.0+0x2c7/0x4c0 ? __pfx_ioctl_has_perm.constprop.0.isra.0+0x10/0x10 ib_uverbs_ioctl+0x13e/0x220 [ib_uverbs] ? __pfx_ib_uverbs_ioctl+0x10/0x10 [ib_uverbs] __x64_sys_ioctl+0x138/0x1c0 do_syscall_64+0x82/0x250 ? fdget_pos+0x58/0x4c0 ? ksys_write+0xf3/0x1c0 ? __pfx_ksys_write+0x10/0x10 ? do_syscall_64+0xc8/0x250 ? __pfx_vm_mmap_pgoff+0x10/0x10 ? fget+0x173/0x230 ? fput+0x2a/0x80 ? ksys_mmap_pgoff+0x224/0x4c0 ? do_syscall_64+0xc8/0x250 ? do_user_addr_fault+0x37b/0xfe0 ? clear_bhb_loop+0x50/0xa0 ? clear_bhb_loop+0x50/0xa0 ? clear_bhb_loop+0x50/0xa0 entry_SYSCALL_64_after_hwframe+0x76/0x7e Fixes: 8700e3e7c485 ("Soft RoCE driver") Tested-by: Liu Yi Signed-off-by: Zhu Yanjun Link: https://patch.msgid.link/20251027215203.1321-1-yanjun.zhu@linux.dev Signed-off-by: Leon Romanovsky Signed-off-by: Sasha Levin --- drivers/infiniband/sw/rxe/rxe_srq.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/infiniband/sw/rxe/rxe_srq.c b/drivers/infiniband/sw/rxe/rxe_srq.c index 3661cb627d28a..2a234f26ac104 100644 --- a/drivers/infiniband/sw/rxe/rxe_srq.c +++ b/drivers/infiniband/sw/rxe/rxe_srq.c @@ -171,7 +171,7 @@ int rxe_srq_from_attr(struct rxe_dev *rxe, struct rxe_srq *srq, udata, mi, &srq->rq.producer_lock, &srq->rq.consumer_lock); if (err) - goto err_free; + return err; srq->rq.max_wr = attr->max_wr; } @@ -180,11 +180,6 @@ int rxe_srq_from_attr(struct rxe_dev *rxe, struct rxe_srq *srq, srq->limit = attr->srq_limit; return 0; - -err_free: - rxe_queue_cleanup(q); - srq->rq.queue = NULL; - return err; } void rxe_srq_cleanup(struct rxe_pool_elem *elem) From 479a71edb7b36eeaafbe8333a901124e2fe92c27 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 29 Sep 2025 11:36:02 +0200 Subject: [PATCH 0511/2333] ARM: dts: renesas: gose: Remove superfluous port property [ Upstream commit 00df14f34615630f92f97c9d6790bd9d25c4242d ] 'bus-width' is defined for the corresponding vin input port already. No need to declare it in the output port again. Fixes: arch/arm/boot/dts/renesas/r8a7793-gose.dtb: composite-in@20 (adi,adv7180cp): ports:port@3:endpoint: Unevaluated properties are not allowed ('bus-width' was unexpected) from schema $id: http://devicetree.org/schemas/media/i2c/adi,adv7180.yaml# Signed-off-by: Wolfram Sang Reviewed-by: Geert Uytterhoeven Link: https://patch.msgid.link/20250929093616.17679-2-wsa+renesas@sang-engineering.com Signed-off-by: Geert Uytterhoeven Signed-off-by: Sasha Levin --- arch/arm/boot/dts/renesas/r8a7793-gose.dts | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm/boot/dts/renesas/r8a7793-gose.dts b/arch/arm/boot/dts/renesas/r8a7793-gose.dts index 45b267ec26794..5c6928c941aca 100644 --- a/arch/arm/boot/dts/renesas/r8a7793-gose.dts +++ b/arch/arm/boot/dts/renesas/r8a7793-gose.dts @@ -373,7 +373,6 @@ port@3 { reg = <3>; adv7180_out: endpoint { - bus-width = <8>; remote-endpoint = <&vin1ep>; }; }; From ee3ff9742a44d9ec040d7aef9ff505d76e095ffd Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 7 Oct 2025 12:46:25 +0200 Subject: [PATCH 0512/2333] ARM: dts: renesas: r9a06g032-rzn1d400-db: Drop invalid #cells properties [ Upstream commit ca7fffb6e92a7c93604ea2bae0e1c89b20750937 ] The 'ethernet-ports' node in the SoC DTSI handles them already. Fixes: arch/arm/boot/dts/renesas/r9a06g032-rzn1d400-db.dtb: switch@44050000 (renesas,r9a06g032-a5psw): Unevaluated properties are not allowed ('#address-cells', '#size-cells' were unexpected) from schema $id: http://devicetree.org/schemas/net/dsa/renesas,rzn1-a5psw.yaml# Fixes: 5b6d7c3c5861ad4a ("ARM: dts: r9a06g032-rzn1d400-db: Add switch description") Signed-off-by: Wolfram Sang Reviewed-by: Geert Uytterhoeven Link: https://patch.msgid.link/20251007104624.19786-2-wsa+renesas@sang-engineering.com Signed-off-by: Geert Uytterhoeven Signed-off-by: Sasha Levin --- arch/arm/boot/dts/renesas/r9a06g032-rzn1d400-db.dts | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/arm/boot/dts/renesas/r9a06g032-rzn1d400-db.dts b/arch/arm/boot/dts/renesas/r9a06g032-rzn1d400-db.dts index 3258b2e274346..4a72aa7663f25 100644 --- a/arch/arm/boot/dts/renesas/r9a06g032-rzn1d400-db.dts +++ b/arch/arm/boot/dts/renesas/r9a06g032-rzn1d400-db.dts @@ -308,8 +308,6 @@ &switch { status = "okay"; - #address-cells = <1>; - #size-cells = <0>; pinctrl-names = "default"; pinctrl-0 = <&pins_eth3>, <&pins_eth4>, <&pins_mdio1>; From 77ac34b838e2093d498e6dc9f5944038ba83c06d Mon Sep 17 00:00:00 2001 From: Prike Liang Date: Mon, 29 Sep 2025 13:52:13 +0800 Subject: [PATCH 0513/2333] drm/amdgpu: add userq object va track helpers [ Upstream commit 5cfa33fabf01f2cc0af6b1feed6e65cb81806a37 ] Add the userq object virtual address list_add() helpers for tracking the userq obj va address usage. Signed-off-by: Prike Liang Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher Stable-dep-of: a0559012a18a ("drm/amdgpu/userq: fix SDMA and compute validation") Signed-off-by: Sasha Levin --- drivers/gpu/drm/amd/amdgpu/amdgpu_object.h | 1 + drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c | 44 ++++++++++++++++------ drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h | 12 ++++-- drivers/gpu/drm/amd/amdgpu/mes_userqueue.c | 16 ++++---- 4 files changed, 52 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h index 656b8a931dae8..52c2d1731aabf 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h @@ -96,6 +96,7 @@ struct amdgpu_bo_va { * if non-zero, cannot unmap from GPU because user queues may still access it */ unsigned int queue_refcount; + atomic_t userq_va_mapped; }; struct amdgpu_bo { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c index 1add21160d218..79c7fa0a9ff7b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c @@ -44,10 +44,29 @@ u32 amdgpu_userq_get_supported_ip_mask(struct amdgpu_device *adev) return userq_ip_mask; } -int amdgpu_userq_input_va_validate(struct amdgpu_vm *vm, u64 addr, - u64 expected_size) +static int amdgpu_userq_buffer_va_list_add(struct amdgpu_usermode_queue *queue, + struct amdgpu_bo_va_mapping *va_map, u64 addr) +{ + struct amdgpu_userq_va_cursor *va_cursor; + struct userq_va_list; + + va_cursor = kzalloc(sizeof(*va_cursor), GFP_KERNEL); + if (!va_cursor) + return -ENOMEM; + + INIT_LIST_HEAD(&va_cursor->list); + va_cursor->gpu_addr = addr; + atomic_set(&va_map->bo_va->userq_va_mapped, 1); + list_add(&va_cursor->list, &queue->userq_va_list); + + return 0; +} + +int amdgpu_userq_input_va_validate(struct amdgpu_usermode_queue *queue, + u64 addr, u64 expected_size) { struct amdgpu_bo_va_mapping *va_map; + struct amdgpu_vm *vm = queue->vm; u64 user_addr; u64 size; int r = 0; @@ -67,6 +86,7 @@ int amdgpu_userq_input_va_validate(struct amdgpu_vm *vm, u64 addr, /* Only validate the userq whether resident in the VM mapping range */ if (user_addr >= va_map->start && va_map->last - user_addr + 1 >= size) { + amdgpu_userq_buffer_va_list_add(queue, va_map, user_addr); amdgpu_bo_unreserve(vm->root.bo); return 0; } @@ -185,6 +205,7 @@ amdgpu_userq_cleanup(struct amdgpu_userq_mgr *uq_mgr, uq_funcs->mqd_destroy(uq_mgr, queue); amdgpu_userq_fence_driver_free(queue); idr_remove(&uq_mgr->userq_idr, queue_id); + list_del(&queue->userq_va_list); kfree(queue); } @@ -505,14 +526,7 @@ amdgpu_userq_create(struct drm_file *filp, union drm_amdgpu_userq *args) goto unlock; } - /* Validate the userq virtual address.*/ - if (amdgpu_userq_input_va_validate(&fpriv->vm, args->in.queue_va, args->in.queue_size) || - amdgpu_userq_input_va_validate(&fpriv->vm, args->in.rptr_va, AMDGPU_GPU_PAGE_SIZE) || - amdgpu_userq_input_va_validate(&fpriv->vm, args->in.wptr_va, AMDGPU_GPU_PAGE_SIZE)) { - r = -EINVAL; - kfree(queue); - goto unlock; - } + INIT_LIST_HEAD(&queue->userq_va_list); queue->doorbell_handle = args->in.doorbell_handle; queue->queue_type = args->in.ip_type; queue->vm = &fpriv->vm; @@ -523,6 +537,15 @@ amdgpu_userq_create(struct drm_file *filp, union drm_amdgpu_userq *args) db_info.db_obj = &queue->db_obj; db_info.doorbell_offset = args->in.doorbell_offset; + /* Validate the userq virtual address.*/ + if (amdgpu_userq_input_va_validate(queue, args->in.queue_va, args->in.queue_size) || + amdgpu_userq_input_va_validate(queue, args->in.rptr_va, AMDGPU_GPU_PAGE_SIZE) || + amdgpu_userq_input_va_validate(queue, args->in.wptr_va, AMDGPU_GPU_PAGE_SIZE)) { + r = -EINVAL; + kfree(queue); + goto unlock; + } + /* Convert relative doorbell offset into absolute doorbell index */ index = amdgpu_userq_get_doorbell_index(uq_mgr, &db_info, filp); if (index == (uint64_t)-EINVAL) { @@ -548,7 +571,6 @@ amdgpu_userq_create(struct drm_file *filp, union drm_amdgpu_userq *args) goto unlock; } - qid = idr_alloc(&uq_mgr->userq_idr, queue, 1, AMDGPU_MAX_USERQ_COUNT, GFP_KERNEL); if (qid < 0) { drm_file_err(uq_mgr->file, "Failed to allocate a queue id\n"); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h index c027dd9166727..dbc13a807ca82 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h @@ -47,6 +47,11 @@ struct amdgpu_userq_obj { struct amdgpu_bo *obj; }; +struct amdgpu_userq_va_cursor { + u64 gpu_addr; + struct list_head list; +}; + struct amdgpu_usermode_queue { int queue_type; enum amdgpu_userq_state state; @@ -66,6 +71,8 @@ struct amdgpu_usermode_queue { u32 xcp_id; int priority; struct dentry *debugfs_queue; + + struct list_head userq_va_list; }; struct amdgpu_userq_funcs { @@ -136,7 +143,6 @@ int amdgpu_userq_stop_sched_for_enforce_isolation(struct amdgpu_device *adev, u32 idx); int amdgpu_userq_start_sched_for_enforce_isolation(struct amdgpu_device *adev, u32 idx); - -int amdgpu_userq_input_va_validate(struct amdgpu_vm *vm, u64 addr, - u64 expected_size); +int amdgpu_userq_input_va_validate(struct amdgpu_usermode_queue *queue, + u64 addr, u64 expected_size); #endif diff --git a/drivers/gpu/drm/amd/amdgpu/mes_userqueue.c b/drivers/gpu/drm/amd/amdgpu/mes_userqueue.c index 1cd9eaeef38f9..5c63480dda9c4 100644 --- a/drivers/gpu/drm/amd/amdgpu/mes_userqueue.c +++ b/drivers/gpu/drm/amd/amdgpu/mes_userqueue.c @@ -298,8 +298,9 @@ static int mes_userq_mqd_create(struct amdgpu_userq_mgr *uq_mgr, goto free_mqd; } - if (amdgpu_userq_input_va_validate(queue->vm, compute_mqd->eop_va, - max_t(u32, PAGE_SIZE, AMDGPU_GPU_PAGE_SIZE))) + r = amdgpu_userq_input_va_validate(queue, compute_mqd->eop_va, + max_t(u32, PAGE_SIZE, AMDGPU_GPU_PAGE_SIZE)); + if (r) goto free_mqd; userq_props->eop_gpu_addr = compute_mqd->eop_va; @@ -330,8 +331,9 @@ static int mes_userq_mqd_create(struct amdgpu_userq_mgr *uq_mgr, userq_props->tmz_queue = mqd_user->flags & AMDGPU_USERQ_CREATE_FLAGS_QUEUE_SECURE; - if (amdgpu_userq_input_va_validate(queue->vm, mqd_gfx_v11->shadow_va, - shadow_info.shadow_size)) + r = amdgpu_userq_input_va_validate(queue, mqd_gfx_v11->shadow_va, + shadow_info.shadow_size); + if (r) goto free_mqd; kfree(mqd_gfx_v11); @@ -350,9 +352,9 @@ static int mes_userq_mqd_create(struct amdgpu_userq_mgr *uq_mgr, r = -ENOMEM; goto free_mqd; } - - if (amdgpu_userq_input_va_validate(queue->vm, mqd_sdma_v11->csa_va, - shadow_info.csa_size)) + r = amdgpu_userq_input_va_validate(queue, mqd_sdma_v11->csa_va, + shadow_info.csa_size); + if (r) goto free_mqd; userq_props->csa_addr = mqd_sdma_v11->csa_va; From 3e3cb76251769af696907e83a2101676eaac0044 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 10 Oct 2025 15:21:02 -0400 Subject: [PATCH 0514/2333] drm/amdgpu/userq: fix SDMA and compute validation [ Upstream commit a0559012a18a5a6ad87516e982892765a403b8ab ] The CSA and EOP buffers have different alignement requirements. Hardcode them for now as a bug fix. A proper query will be added in a subsequent patch. v2: verify gfx shadow helper callback (Prike) Fixes: 9e46b8bb0539 ("drm/amdgpu: validate userq buffer virtual address and size") Reviewed-by: Prike Liang Signed-off-by: Alex Deucher Signed-off-by: Sasha Levin --- drivers/gpu/drm/amd/amdgpu/mes_userqueue.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/mes_userqueue.c b/drivers/gpu/drm/amd/amdgpu/mes_userqueue.c index 5c63480dda9c4..f5aa83ff57f35 100644 --- a/drivers/gpu/drm/amd/amdgpu/mes_userqueue.c +++ b/drivers/gpu/drm/amd/amdgpu/mes_userqueue.c @@ -254,7 +254,6 @@ static int mes_userq_mqd_create(struct amdgpu_userq_mgr *uq_mgr, struct amdgpu_mqd *mqd_hw_default = &adev->mqds[queue->queue_type]; struct drm_amdgpu_userq_in *mqd_user = args_in; struct amdgpu_mqd_prop *userq_props; - struct amdgpu_gfx_shadow_info shadow_info; int r; /* Structure to initialize MQD for userqueue using generic MQD init function */ @@ -280,8 +279,6 @@ static int mes_userq_mqd_create(struct amdgpu_userq_mgr *uq_mgr, userq_props->doorbell_index = queue->doorbell_index; userq_props->fence_address = queue->fence_drv->gpu_addr; - if (adev->gfx.funcs->get_gfx_shadow_info) - adev->gfx.funcs->get_gfx_shadow_info(adev, &shadow_info, true); if (queue->queue_type == AMDGPU_HW_IP_COMPUTE) { struct drm_amdgpu_userq_mqd_compute_gfx11 *compute_mqd; @@ -299,7 +296,7 @@ static int mes_userq_mqd_create(struct amdgpu_userq_mgr *uq_mgr, } r = amdgpu_userq_input_va_validate(queue, compute_mqd->eop_va, - max_t(u32, PAGE_SIZE, AMDGPU_GPU_PAGE_SIZE)); + 2048); if (r) goto free_mqd; @@ -312,6 +309,14 @@ static int mes_userq_mqd_create(struct amdgpu_userq_mgr *uq_mgr, kfree(compute_mqd); } else if (queue->queue_type == AMDGPU_HW_IP_GFX) { struct drm_amdgpu_userq_mqd_gfx11 *mqd_gfx_v11; + struct amdgpu_gfx_shadow_info shadow_info; + + if (adev->gfx.funcs->get_gfx_shadow_info) { + adev->gfx.funcs->get_gfx_shadow_info(adev, &shadow_info, true); + } else { + r = -EINVAL; + goto free_mqd; + } if (mqd_user->mqd_size != sizeof(*mqd_gfx_v11) || !mqd_user->mqd) { DRM_ERROR("Invalid GFX MQD\n"); @@ -335,6 +340,10 @@ static int mes_userq_mqd_create(struct amdgpu_userq_mgr *uq_mgr, shadow_info.shadow_size); if (r) goto free_mqd; + r = amdgpu_userq_input_va_validate(queue, mqd_gfx_v11->csa_va, + shadow_info.csa_size); + if (r) + goto free_mqd; kfree(mqd_gfx_v11); } else if (queue->queue_type == AMDGPU_HW_IP_DMA) { @@ -353,7 +362,7 @@ static int mes_userq_mqd_create(struct amdgpu_userq_mgr *uq_mgr, goto free_mqd; } r = amdgpu_userq_input_va_validate(queue, mqd_sdma_v11->csa_va, - shadow_info.csa_size); + 32); if (r) goto free_mqd; From 1564c04afa92c2c7af79891d5596642384b34999 Mon Sep 17 00:00:00 2001 From: Li Qiang Date: Fri, 17 Oct 2025 12:11:28 +0800 Subject: [PATCH 0515/2333] wifi: iwlwifi: mld: add null check for kzalloc() in iwl_mld_send_proto_offload() [ Upstream commit 3df28496673bd8009f1cd3a85a63650c96e369f4 ] Add a missing NULL pointer check after kzalloc() in iwl_mld_send_proto_offload(). Without this check, a failed allocation could lead to a NULL dereference. Fixes: d1e879ec600f9 ("wifi: iwlwifi: add iwlmld sub-driver") Signed-off-by: Li Qiang Link: https://patch.msgid.link/20251017041128.1379715-1-liqiang01@kylinos.cn Signed-off-by: Miri Korenblit Signed-off-by: Sasha Levin --- drivers/net/wireless/intel/iwlwifi/mld/d3.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/wireless/intel/iwlwifi/mld/d3.c b/drivers/net/wireless/intel/iwlwifi/mld/d3.c index 1d4282a21f09e..dd85be94433cc 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/d3.c @@ -1794,6 +1794,10 @@ iwl_mld_send_proto_offload(struct iwl_mld *mld, u32 enabled = 0; cmd = kzalloc(hcmd.len[0], GFP_KERNEL); + if (!cmd) { + IWL_DEBUG_WOWLAN(mld, "Failed to allocate proto offload cmd\n"); + return -ENOMEM; + } #if IS_ENABLED(CONFIG_IPV6) struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif); From af76d442a543f596fd78a13f7369a20831fa1c76 Mon Sep 17 00:00:00 2001 From: Aryan Srivastava Date: Fri, 24 Oct 2025 13:19:41 +1300 Subject: [PATCH 0516/2333] Revert "mtd: rawnand: marvell: fix layouts" [ Upstream commit fbd72cb463fdea3a0c900dd5d6e813cdebc3a73c ] This reverts commit e6a30d0c48a1e8a68f1cc413bee65302ab03ddfb. This change resulted in the 8bit ECC layouts having the incorrect amount of read/write chunks, the last spare bytes chunk would always be missed. Fixes: e6a30d0c48a1 ("mtd: rawnand: marvell: fix layouts") Signed-off-by: Aryan Srivastava Signed-off-by: Miquel Raynal Signed-off-by: Sasha Levin --- drivers/mtd/nand/raw/marvell_nand.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/mtd/nand/raw/marvell_nand.c b/drivers/mtd/nand/raw/marvell_nand.c index 303b3016a070b..38b7eb5b992c8 100644 --- a/drivers/mtd/nand/raw/marvell_nand.c +++ b/drivers/mtd/nand/raw/marvell_nand.c @@ -290,13 +290,16 @@ static const struct marvell_hw_ecc_layout marvell_nfc_layouts[] = { MARVELL_LAYOUT( 2048, 512, 4, 1, 1, 2048, 32, 30, 0, 0, 0), MARVELL_LAYOUT( 2048, 512, 8, 2, 1, 1024, 0, 30,1024,32, 30), MARVELL_LAYOUT( 2048, 512, 8, 2, 1, 1024, 0, 30,1024,64, 30), - MARVELL_LAYOUT( 2048, 512, 16, 4, 4, 512, 0, 30, 0, 32, 30), + MARVELL_LAYOUT( 2048, 512, 12, 3, 2, 704, 0, 30,640, 0, 30), + MARVELL_LAYOUT( 2048, 512, 16, 5, 4, 512, 0, 30, 0, 32, 30), MARVELL_LAYOUT( 4096, 512, 4, 2, 2, 2048, 32, 30, 0, 0, 0), - MARVELL_LAYOUT( 4096, 512, 8, 4, 4, 1024, 0, 30, 0, 64, 30), - MARVELL_LAYOUT( 4096, 512, 16, 8, 8, 512, 0, 30, 0, 32, 30), + MARVELL_LAYOUT( 4096, 512, 8, 5, 4, 1024, 0, 30, 0, 64, 30), + MARVELL_LAYOUT( 4096, 512, 12, 6, 5, 704, 0, 30,576, 32, 30), + MARVELL_LAYOUT( 4096, 512, 16, 9, 8, 512, 0, 30, 0, 32, 30), MARVELL_LAYOUT( 8192, 512, 4, 4, 4, 2048, 0, 30, 0, 0, 0), - MARVELL_LAYOUT( 8192, 512, 8, 8, 8, 1024, 0, 30, 0, 160, 30), - MARVELL_LAYOUT( 8192, 512, 16, 16, 16, 512, 0, 30, 0, 32, 30), + MARVELL_LAYOUT( 8192, 512, 8, 9, 8, 1024, 0, 30, 0, 160, 30), + MARVELL_LAYOUT( 8192, 512, 12, 12, 11, 704, 0, 30,448, 64, 30), + MARVELL_LAYOUT( 8192, 512, 16, 17, 16, 512, 0, 30, 0, 32, 30), }; /** From 34de3867bdfdf5bee1e9b27efa91a0aab2e5d11e Mon Sep 17 00:00:00 2001 From: Aryan Srivastava Date: Fri, 24 Oct 2025 13:19:42 +1300 Subject: [PATCH 0517/2333] mtd: nand: relax ECC parameter validation check [ Upstream commit 050553c683f21eebd7d1020df9b2ec852e2a9e4e ] Due to the custom handling and layouts of certain nand controllers this validity check will always fail for certain layouts. The check inherently depends on even chunk sizing and this is not always the case. Modify the check to only print a warning, instead of failing to init the attached NAND. This allows various 8 bit and 12 ECC strength layouts to be used. Fixes: 68c18dae6888 ("mtd: rawnand: marvell: add missing layouts") Signed-off-by: Aryan Srivastava Signed-off-by: Miquel Raynal Signed-off-by: Sasha Levin --- drivers/mtd/nand/raw/nand_base.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c index c7d9501f646b3..ad6d66309597b 100644 --- a/drivers/mtd/nand/raw/nand_base.c +++ b/drivers/mtd/nand/raw/nand_base.c @@ -6338,11 +6338,14 @@ static int nand_scan_tail(struct nand_chip *chip) ecc->steps = mtd->writesize / ecc->size; if (!base->ecc.ctx.nsteps) base->ecc.ctx.nsteps = ecc->steps; - if (ecc->steps * ecc->size != mtd->writesize) { - WARN(1, "Invalid ECC parameters\n"); - ret = -EINVAL; - goto err_nand_manuf_cleanup; - } + + /* + * Validity check: Warn if ECC parameters are not compatible with page size. + * Due to the custom handling of ECC blocks in certain controllers the check + * may result in an expected failure. + */ + if (ecc->steps * ecc->size != mtd->writesize) + pr_warn("ECC parameters may be invalid in reference to underlying NAND chip\n"); if (!ecc->total) { ecc->total = ecc->steps * ecc->bytes; From 8f4e27e870960cdc102e3e9ad89517f3c42ab8ae Mon Sep 17 00:00:00 2001 From: Haotian Zhang Date: Tue, 28 Oct 2025 17:47:47 +0800 Subject: [PATCH 0518/2333] mtd: rawnand: lpc32xx_slc: fix GPIO descriptor leak on probe error and remove [ Upstream commit cdf44f1add4ec9ee80569d5a43e6e9bba0d74c7a ] The driver calls gpiod_get_optional() in the probe function but never calls gpiod_put() in the remove function or in the probe error path. This leads to a GPIO descriptor resource leak. The lpc32xx_mlc.c driver in the same directory handles this correctly by calling gpiod_put() on both paths. Add gpiod_put() in the remove function and in the probe error path to fix the resource leak. Fixes: 6b923db2867c ("mtd: rawnand: lpc32xx_slc: switch to using gpiod API") Signed-off-by: Haotian Zhang Signed-off-by: Miquel Raynal Signed-off-by: Sasha Levin --- drivers/mtd/nand/raw/lpc32xx_slc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/mtd/nand/raw/lpc32xx_slc.c b/drivers/mtd/nand/raw/lpc32xx_slc.c index b54d76547ffb2..fea3705a21386 100644 --- a/drivers/mtd/nand/raw/lpc32xx_slc.c +++ b/drivers/mtd/nand/raw/lpc32xx_slc.c @@ -937,6 +937,7 @@ static int lpc32xx_nand_probe(struct platform_device *pdev) dma_release_channel(host->dma_chan); enable_wp: lpc32xx_wp_enable(host); + gpiod_put(host->wp_gpio); return res; } @@ -962,6 +963,7 @@ static void lpc32xx_nand_remove(struct platform_device *pdev) writel(tmp, SLC_CTRL(host->io_base)); lpc32xx_wp_enable(host); + gpiod_put(host->wp_gpio); } static int lpc32xx_nand_resume(struct platform_device *pdev) From 8fc78e468f9e4dfaa278a84d0b349e2f773aa19b Mon Sep 17 00:00:00 2001 From: Arnaud Lecomte Date: Sat, 25 Oct 2025 19:28:58 +0000 Subject: [PATCH 0519/2333] bpf: Refactor stack map trace depth calculation into helper function [ Upstream commit e17d62fedd10ae56e2426858bd0757da544dbc73 ] Extract the duplicated maximum allowed depth computation for stack traces stored in BPF stacks from bpf_get_stackid() and __bpf_get_stack() into a dedicated stack_map_calculate_max_depth() helper function. This unifies the logic for: - The max depth computation - Enforcing the sysctl_perf_event_max_stack limit No functional changes for existing code paths. Signed-off-by: Arnaud Lecomte Signed-off-by: Andrii Nakryiko Acked-by: Yonghong Song Acked-by: Song Liu Link: https://lore.kernel.org/bpf/20251025192858.31424-1-contact@arnaud-lcm.com Stable-dep-of: 23f852daa4ba ("bpf: Fix stackmap overflow check in __bpf_get_stackid()") Signed-off-by: Sasha Levin --- kernel/bpf/stackmap.c | 47 +++++++++++++++++++++++++++++-------------- 1 file changed, 32 insertions(+), 15 deletions(-) diff --git a/kernel/bpf/stackmap.c b/kernel/bpf/stackmap.c index 4d53cdd1374cf..5e9ad050333c2 100644 --- a/kernel/bpf/stackmap.c +++ b/kernel/bpf/stackmap.c @@ -42,6 +42,28 @@ static inline int stack_map_data_size(struct bpf_map *map) sizeof(struct bpf_stack_build_id) : sizeof(u64); } +/** + * stack_map_calculate_max_depth - Calculate maximum allowed stack trace depth + * @size: Size of the buffer/map value in bytes + * @elem_size: Size of each stack trace element + * @flags: BPF stack trace flags (BPF_F_USER_STACK, BPF_F_USER_BUILD_ID, ...) + * + * Return: Maximum number of stack trace entries that can be safely stored + */ +static u32 stack_map_calculate_max_depth(u32 size, u32 elem_size, u64 flags) +{ + u32 skip = flags & BPF_F_SKIP_FIELD_MASK; + u32 max_depth; + u32 curr_sysctl_max_stack = READ_ONCE(sysctl_perf_event_max_stack); + + max_depth = size / elem_size; + max_depth += skip; + if (max_depth > curr_sysctl_max_stack) + return curr_sysctl_max_stack; + + return max_depth; +} + static int prealloc_elems_and_freelist(struct bpf_stack_map *smap) { u64 elem_size = sizeof(struct stack_map_bucket) + @@ -300,20 +322,17 @@ static long __bpf_get_stackid(struct bpf_map *map, BPF_CALL_3(bpf_get_stackid, struct pt_regs *, regs, struct bpf_map *, map, u64, flags) { - u32 max_depth = map->value_size / stack_map_data_size(map); - u32 skip = flags & BPF_F_SKIP_FIELD_MASK; + u32 elem_size = stack_map_data_size(map); bool user = flags & BPF_F_USER_STACK; struct perf_callchain_entry *trace; bool kernel = !user; + u32 max_depth; if (unlikely(flags & ~(BPF_F_SKIP_FIELD_MASK | BPF_F_USER_STACK | BPF_F_FAST_STACK_CMP | BPF_F_REUSE_STACKID))) return -EINVAL; - max_depth += skip; - if (max_depth > sysctl_perf_event_max_stack) - max_depth = sysctl_perf_event_max_stack; - + max_depth = stack_map_calculate_max_depth(map->value_size, elem_size, flags); trace = get_perf_callchain(regs, kernel, user, max_depth, false, false); @@ -406,7 +425,7 @@ static long __bpf_get_stack(struct pt_regs *regs, struct task_struct *task, struct perf_callchain_entry *trace_in, void *buf, u32 size, u64 flags, bool may_fault) { - u32 trace_nr, copy_len, elem_size, num_elem, max_depth; + u32 trace_nr, copy_len, elem_size, max_depth; bool user_build_id = flags & BPF_F_USER_BUILD_ID; bool crosstask = task && task != current; u32 skip = flags & BPF_F_SKIP_FIELD_MASK; @@ -438,21 +457,20 @@ static long __bpf_get_stack(struct pt_regs *regs, struct task_struct *task, goto clear; } - num_elem = size / elem_size; - max_depth = num_elem + skip; - if (sysctl_perf_event_max_stack < max_depth) - max_depth = sysctl_perf_event_max_stack; + max_depth = stack_map_calculate_max_depth(size, elem_size, flags); if (may_fault) rcu_read_lock(); /* need RCU for perf's callchain below */ - if (trace_in) + if (trace_in) { trace = trace_in; - else if (kernel && task) + trace->nr = min_t(u32, trace->nr, max_depth); + } else if (kernel && task) { trace = get_callchain_entry_for_task(task, max_depth); - else + } else { trace = get_perf_callchain(regs, kernel, user, max_depth, crosstask, false); + } if (unlikely(!trace) || trace->nr < skip) { if (may_fault) @@ -461,7 +479,6 @@ static long __bpf_get_stack(struct pt_regs *regs, struct task_struct *task, } trace_nr = trace->nr - skip; - trace_nr = (trace_nr <= num_elem) ? trace_nr : num_elem; copy_len = trace_nr * elem_size; ips = trace->ip + skip; From 4669a8db976c8cbd5427fe9945f12c5fa5168ff3 Mon Sep 17 00:00:00 2001 From: Arnaud Lecomte Date: Sat, 25 Oct 2025 19:29:41 +0000 Subject: [PATCH 0520/2333] bpf: Fix stackmap overflow check in __bpf_get_stackid() [ Upstream commit 23f852daa4bab4d579110e034e4d513f7d490846 ] Syzkaller reported a KASAN slab-out-of-bounds write in __bpf_get_stackid() when copying stack trace data. The issue occurs when the perf trace contains more stack entries than the stack map bucket can hold, leading to an out-of-bounds write in the bucket's data array. Fixes: ee2a098851bf ("bpf: Adjust BPF stack helper functions to accommodate skip > 0") Reported-by: syzbot+c9b724fbb41cf2538b7b@syzkaller.appspotmail.com Signed-off-by: Arnaud Lecomte Signed-off-by: Andrii Nakryiko Acked-by: Yonghong Song Acked-by: Song Liu Link: https://lore.kernel.org/bpf/20251025192941.1500-1-contact@arnaud-lcm.com Closes: https://syzkaller.appspot.com/bug?extid=c9b724fbb41cf2538b7b Signed-off-by: Sasha Levin --- kernel/bpf/stackmap.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/kernel/bpf/stackmap.c b/kernel/bpf/stackmap.c index 5e9ad050333c2..2365541c81dd1 100644 --- a/kernel/bpf/stackmap.c +++ b/kernel/bpf/stackmap.c @@ -251,8 +251,8 @@ static long __bpf_get_stackid(struct bpf_map *map, { struct bpf_stack_map *smap = container_of(map, struct bpf_stack_map, map); struct stack_map_bucket *bucket, *new_bucket, *old_bucket; + u32 hash, id, trace_nr, trace_len, i, max_depth; u32 skip = flags & BPF_F_SKIP_FIELD_MASK; - u32 hash, id, trace_nr, trace_len, i; bool user = flags & BPF_F_USER_STACK; u64 *ips; bool hash_matches; @@ -261,7 +261,8 @@ static long __bpf_get_stackid(struct bpf_map *map, /* skipping more than usable stack trace */ return -EFAULT; - trace_nr = trace->nr - skip; + max_depth = stack_map_calculate_max_depth(map->value_size, stack_map_data_size(map), flags); + trace_nr = min_t(u32, trace->nr - skip, max_depth - skip); trace_len = trace_nr * sizeof(u64); ips = trace->ip + skip; hash = jhash2((u32 *)ips, trace_len / sizeof(u32), 0); @@ -390,15 +391,11 @@ BPF_CALL_3(bpf_get_stackid_pe, struct bpf_perf_event_data_kern *, ctx, return -EFAULT; nr_kernel = count_kernel_ip(trace); + __u64 nr = trace->nr; /* save original */ if (kernel) { - __u64 nr = trace->nr; - trace->nr = nr_kernel; ret = __bpf_get_stackid(map, trace, flags); - - /* restore nr */ - trace->nr = nr; } else { /* user */ u64 skip = flags & BPF_F_SKIP_FIELD_MASK; @@ -409,6 +406,10 @@ BPF_CALL_3(bpf_get_stackid_pe, struct bpf_perf_event_data_kern *, ctx, flags = (flags & ~BPF_F_SKIP_FIELD_MASK) | skip; ret = __bpf_get_stackid(map, trace, flags); } + + /* restore nr */ + trace->nr = nr; + return ret; } From 75446d62696c9cf486074e49844922e1de732381 Mon Sep 17 00:00:00 2001 From: Zhang Rui Date: Thu, 23 Oct 2025 15:37:52 -0700 Subject: [PATCH 0521/2333] perf/x86/intel/cstate: Remove PC3 support from LunarLake [ Upstream commit 4ba45f041abe60337fdeeb68553b9ee1217d544e ] LunarLake doesn't support Package C3. Remove the PC3 residency counter support from LunarLake. Fixes: 26579860fbd5 ("perf/x86/intel/cstate: Add Lunarlake support") Signed-off-by: Zhang Rui Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: Kan Liang Reviewed-by: Dapeng Mi Link: https://patch.msgid.link/20251023223754.1743928-3-zide.chen@intel.com Signed-off-by: Sasha Levin --- arch/x86/events/intel/cstate.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/x86/events/intel/cstate.c b/arch/x86/events/intel/cstate.c index ec753e39b0077..6f5286a99e0c3 100644 --- a/arch/x86/events/intel/cstate.c +++ b/arch/x86/events/intel/cstate.c @@ -70,7 +70,7 @@ * perf code: 0x01 * Available model: NHM,WSM,SNB,IVB,HSW,BDW,SKL,KNL, * GLM,CNL,KBL,CML,ICL,TGL,TNT,RKL, - * ADL,RPL,MTL,ARL,LNL + * ADL,RPL,MTL,ARL * Scope: Package (physical package) * MSR_PKG_C6_RESIDENCY: Package C6 Residency Counter. * perf code: 0x02 @@ -522,7 +522,6 @@ static const struct cstate_model lnl_cstates __initconst = { BIT(PERF_CSTATE_CORE_C7_RES), .pkg_events = BIT(PERF_CSTATE_PKG_C2_RES) | - BIT(PERF_CSTATE_PKG_C3_RES) | BIT(PERF_CSTATE_PKG_C6_RES) | BIT(PERF_CSTATE_PKG_C10_RES), }; From 5b56a123422330e826184b5b78fb94cefc45c8a4 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Mon, 22 Sep 2025 15:47:00 +0200 Subject: [PATCH 0522/2333] task_work: Fix NMI race condition [ Upstream commit ef1ea98c8fffe227e5319215d84a53fa2a4bcebc ] __schedule() // disable irqs task_work_add(current, work, TWA_NMI_CURRENT); // current = next; // enable irqs task_work_set_notify_irq() test_and_set_tsk_thread_flag(current, TIF_NOTIFY_RESUME); // wrong task! // original task skips task work on its next return to user (or exit!) Fixes: 466e4d801cd4 ("task_work: Add TWA_NMI_CURRENT as an additional notify mode.") Reported-by: Josh Poimboeuf Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: Steven Rostedt (Google) Link: https://patch.msgid.link/20250924080118.425949403@infradead.org Signed-off-by: Sasha Levin --- kernel/task_work.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/kernel/task_work.c b/kernel/task_work.c index d1efec571a4a4..0f7519f8e7c93 100644 --- a/kernel/task_work.c +++ b/kernel/task_work.c @@ -9,7 +9,12 @@ static struct callback_head work_exited; /* all we need is ->next == NULL */ #ifdef CONFIG_IRQ_WORK static void task_work_set_notify_irq(struct irq_work *entry) { - test_and_set_tsk_thread_flag(current, TIF_NOTIFY_RESUME); + /* + * no-op IPI + * + * TWA_NMI_CURRENT will already have set the TIF flag, all + * this interrupt does it tickle the return-to-user path. + */ } static DEFINE_PER_CPU(struct irq_work, irq_work_NMI_resume) = IRQ_WORK_INIT_HARD(task_work_set_notify_irq); @@ -86,6 +91,7 @@ int task_work_add(struct task_struct *task, struct callback_head *work, break; #ifdef CONFIG_IRQ_WORK case TWA_NMI_CURRENT: + set_tsk_thread_flag(current, TIF_NOTIFY_RESUME); irq_work_queue(this_cpu_ptr(&irq_work_NMI_resume)); break; #endif From 390a08dd68e647606afddd7187643ff8b043daf8 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Wed, 29 Oct 2025 00:28:11 +0100 Subject: [PATCH 0523/2333] drm/rcar-du: dsi: Fix missing parameter in RXSETR_...EN macros [ Upstream commit 42bbf82b73bda18bbc3e158cb6fda040bb586feb ] The RXSETR_CRCEN(n) and RXSETR_ECCEN(n) macros both take parameter (n), add the missing macro parameter. Neither of those macros is used by the driver, so for now the bug is harmless. Fixes: 685e8dae19df ("drm/rcar-du: dsi: Implement DSI command support") Reviewed-by: Laurent Pinchart Reviewed-by: Tomi Valkeinen Signed-off-by: Marek Vasut Reported-by: Laurent Pinchart Link: https://patch.msgid.link/20251028232959.109936-2-marek.vasut+renesas@mailbox.org Signed-off-by: Tomi Valkeinen Signed-off-by: Sasha Levin --- drivers/gpu/drm/renesas/rcar-du/rcar_mipi_dsi_regs.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/renesas/rcar-du/rcar_mipi_dsi_regs.h b/drivers/gpu/drm/renesas/rcar-du/rcar_mipi_dsi_regs.h index 76521276e2af8..dd871e17dcf53 100644 --- a/drivers/gpu/drm/renesas/rcar-du/rcar_mipi_dsi_regs.h +++ b/drivers/gpu/drm/renesas/rcar-du/rcar_mipi_dsi_regs.h @@ -50,8 +50,8 @@ #define TXCMPPD3R 0x16c #define RXSETR 0x200 -#define RXSETR_CRCEN (((n) & 0xf) << 24) -#define RXSETR_ECCEN (((n) & 0xf) << 16) +#define RXSETR_CRCEN(n) (((n) & 0xf) << 24) +#define RXSETR_ECCEN(n) (((n) & 0xf) << 16) #define RXPSETR 0x210 #define RXPSETR_LPPDACC (1 << 0) #define RXPSR 0x220 From d53bfb48f6d01d8af988a01549cce52b9a5719ae Mon Sep 17 00:00:00 2001 From: Tengda Wu Date: Thu, 23 Oct 2025 09:06:32 +0000 Subject: [PATCH 0524/2333] x86/dumpstack: Prevent KASAN false positive warnings in __show_regs() [ Upstream commit ced37e9ceae50e4cb6cd058963bd315ec9afa651 ] When triggering a stack dump via sysrq (echo t > /proc/sysrq-trigger), KASAN may report false-positive out-of-bounds access: BUG: KASAN: out-of-bounds in __show_regs+0x4b/0x340 Call Trace: dump_stack_lvl print_address_description.constprop.0 print_report __show_regs show_trace_log_lvl sched_show_task show_state_filter sysrq_handle_showstate __handle_sysrq write_sysrq_trigger proc_reg_write vfs_write ksys_write do_syscall_64 entry_SYSCALL_64_after_hwframe The issue occurs as follows: Task A (walk other tasks' stacks) Task B (running) 1. echo t > /proc/sysrq-trigger show_trace_log_lvl regs = unwind_get_entry_regs() show_regs_if_on_stack(regs) 2. The stack value pointed by `regs` keeps changing, and so are the tags in its KASAN shadow region. __show_regs(regs) regs->ax, regs->bx, ... 3. hit KASAN redzones, OOB When task A walks task B's stack without suspending it, the continuous changes in task B's stack (and corresponding KASAN shadow tags) may cause task A to hit KASAN redzones when accessing obsolete values on the stack, resulting in false positive reports. Simply stopping the task before unwinding is not a viable fix, as it would alter the state intended to inspect. This is especially true for diagnosing misbehaving tasks (e.g., in a hard lockup), where stopping might fail or hide the root cause by changing the call stack. Therefore, fix this by disabling KASAN checks during asynchronous stack unwinding, which is identified when the unwinding task does not match the current task (task != current). [ bp: Align arguments on function's opening brace. ] Fixes: 3b3fa11bc700 ("x86/dumpstack: Print any pt_regs found on the stack") Signed-off-by: Tengda Wu Signed-off-by: Borislav Petkov (AMD) Reviewed-by: Andrey Ryabinin Acked-by: Josh Poimboeuf Link: https://patch.msgid.link/all/20251023090632.269121-1-wutengda@huaweicloud.com Signed-off-by: Sasha Levin --- arch/x86/kernel/dumpstack.c | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/arch/x86/kernel/dumpstack.c b/arch/x86/kernel/dumpstack.c index 71ee20102a8af..b10684dedc589 100644 --- a/arch/x86/kernel/dumpstack.c +++ b/arch/x86/kernel/dumpstack.c @@ -181,8 +181,8 @@ static void show_regs_if_on_stack(struct stack_info *info, struct pt_regs *regs, * in false positive reports. Disable instrumentation to avoid those. */ __no_kmsan_checks -static void show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs, - unsigned long *stack, const char *log_lvl) +static void __show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs, + unsigned long *stack, const char *log_lvl) { struct unwind_state state; struct stack_info stack_info = {0}; @@ -303,6 +303,25 @@ static void show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs, } } +static void show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs, + unsigned long *stack, const char *log_lvl) +{ + /* + * Disable KASAN to avoid false positives during walking another + * task's stacks, as values on these stacks may change concurrently + * with task execution. + */ + bool disable_kasan = task && task != current; + + if (disable_kasan) + kasan_disable_current(); + + __show_trace_log_lvl(task, regs, stack, log_lvl); + + if (disable_kasan) + kasan_enable_current(); +} + void show_stack(struct task_struct *task, unsigned long *sp, const char *loglvl) { From 22da82674af6f6f625202b1e89a7781d82db7809 Mon Sep 17 00:00:00 2001 From: Maciej Falkowski Date: Mon, 27 Oct 2025 16:09:32 +0100 Subject: [PATCH 0525/2333] accel/ivpu: Remove skip of dma unmap for imported buffers [ Upstream commit c063c1bbee67391f12956d2ffdd5da00eb87ff79 ] Rework of imported buffers introduced in the commit e0c0891cd63b ("accel/ivpu: Rework bind/unbind of imported buffers") switched the logic of imported buffers by dma mapping/unmapping them just as the regular buffers. The commit didn't include removal of skipping dma unmap of imported buffers which results in them being mapped without unmapping. Fixes: e0c0891cd63b ("accel/ivpu: Rework bind/unbind of imported buffers") Reviewed-by: Jeff Hugo Reviewed-by: Karol Wachowski Signed-off-by: Maciej Falkowski Link: https://patch.msgid.link/20251027150933.2384538-1-maciej.falkowski@linux.intel.com Signed-off-by: Sasha Levin --- drivers/accel/ivpu/ivpu_gem.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/accel/ivpu/ivpu_gem.c b/drivers/accel/ivpu/ivpu_gem.c index 1fca969df19dc..a38e41f9c7123 100644 --- a/drivers/accel/ivpu/ivpu_gem.c +++ b/drivers/accel/ivpu/ivpu_gem.c @@ -157,9 +157,6 @@ static void ivpu_bo_unbind_locked(struct ivpu_bo *bo) bo->ctx = NULL; } - if (drm_gem_is_imported(&bo->base.base)) - return; - if (bo->base.sgt) { if (bo->base.base.import_attach) { dma_buf_unmap_attachment(bo->base.base.import_attach, From 35eb1ae22c79d24f35cbe401c59738081fce2f23 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Wed, 24 Sep 2025 16:20:50 +0200 Subject: [PATCH 0526/2333] tools/nolibc/stdio: let perror work when NOLIBC_IGNORE_ERRNO is set MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit c485ca3aff2442adea4c08ceb5183e671ebed22a ] There is no errno variable when NOLIBC_IGNORE_ERRNO is defined. As such, simply print the message with "unknown error" rather than the integer value of errno. Fixes: acab7bcdb1bc ("tools/nolibc/stdio: add perror() to report the errno value") Signed-off-by: Benjamin Berg Signed-off-by: Thomas Weißschuh Signed-off-by: Sasha Levin --- tools/include/nolibc/stdio.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tools/include/nolibc/stdio.h b/tools/include/nolibc/stdio.h index 7630234408c58..724d05ce69624 100644 --- a/tools/include/nolibc/stdio.h +++ b/tools/include/nolibc/stdio.h @@ -600,7 +600,11 @@ int sscanf(const char *str, const char *format, ...) static __attribute__((unused)) void perror(const char *msg) { +#ifdef NOLIBC_IGNORE_ERRNO + fprintf(stderr, "%s%sunknown error\n", (msg && *msg) ? msg : "", (msg && *msg) ? ": " : ""); +#else fprintf(stderr, "%s%serrno=%d\n", (msg && *msg) ? msg : "", (msg && *msg) ? ": " : "", errno); +#endif } static __attribute__((unused)) From aa857ba3ef527cc16ac53ce9e851a55dda97a6a5 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Wed, 24 Sep 2025 16:20:51 +0200 Subject: [PATCH 0527/2333] tools/nolibc/dirent: avoid errno in readdir_r MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 4ada5679f18dbbe92d87c37a842c3368e6ab5e4a ] Using errno is not possible when NOLIBC_IGNORE_ERRNO is set. Use sys_lseek instead of lseek as that avoids using errno. Fixes: 665fa8dea90d ("tools/nolibc: add support for directory access") Signed-off-by: Benjamin Berg Signed-off-by: Thomas Weißschuh Signed-off-by: Sasha Levin --- tools/include/nolibc/dirent.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/include/nolibc/dirent.h b/tools/include/nolibc/dirent.h index 758b95c48e7a4..61a122a60327d 100644 --- a/tools/include/nolibc/dirent.h +++ b/tools/include/nolibc/dirent.h @@ -86,9 +86,9 @@ int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result) * readdir() can only return one entry at a time. * Make sure the non-returned ones are not skipped. */ - ret = lseek(fd, ldir->d_off, SEEK_SET); - if (ret == -1) - return errno; + ret = sys_lseek(fd, ldir->d_off, SEEK_SET); + if (ret < 0) + return -ret; entry->d_ino = ldir->d_ino; /* the destination should always be big enough */ From 4e45bd3f95fa703199b7b8e975c11318a4d818e5 Mon Sep 17 00:00:00 2001 From: Taniya Das Date: Wed, 29 Oct 2025 15:07:54 +0530 Subject: [PATCH 0528/2333] clk: qcom: gcc-qcs615: Update the SDCC clock to use shared_floor_ops [ Upstream commit 0820c9373369c83de5202871d02682d583a91a9c ] Fix "gcc_sdcc2_apps_clk_src: rcg didn't update its configuration" during boot. This happens due to the floor_ops tries to update the rcg configuration even if the clock is not enabled. The shared_floor_ops ensures that the RCG is safely parked and the new parent configuration is cached in the parked_cfg when the clock is off. Ensure to use the ops for the other SDCC clock instances as well. Fixes: 39d6dcf67fe9 ("clk: qcom: gcc: Add support for QCS615 GCC clocks") Reviewed-by: Abel Vesa Signed-off-by: Taniya Das Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20251029-sdcc_rcg2_shared_ops-v3-1-ecf47d9601d1@oss.qualcomm.com Signed-off-by: Bjorn Andersson Signed-off-by: Sasha Levin --- drivers/clk/qcom/gcc-qcs615.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/clk/qcom/gcc-qcs615.c b/drivers/clk/qcom/gcc-qcs615.c index 9695446bc2a3c..5b3b8dd4f114b 100644 --- a/drivers/clk/qcom/gcc-qcs615.c +++ b/drivers/clk/qcom/gcc-qcs615.c @@ -784,7 +784,7 @@ static struct clk_rcg2 gcc_sdcc1_apps_clk_src = { .name = "gcc_sdcc1_apps_clk_src", .parent_data = gcc_parent_data_1, .num_parents = ARRAY_SIZE(gcc_parent_data_1), - .ops = &clk_rcg2_floor_ops, + .ops = &clk_rcg2_shared_floor_ops, }, }; @@ -806,7 +806,7 @@ static struct clk_rcg2 gcc_sdcc1_ice_core_clk_src = { .name = "gcc_sdcc1_ice_core_clk_src", .parent_data = gcc_parent_data_0, .num_parents = ARRAY_SIZE(gcc_parent_data_0), - .ops = &clk_rcg2_floor_ops, + .ops = &clk_rcg2_shared_floor_ops, }, }; @@ -830,7 +830,7 @@ static struct clk_rcg2 gcc_sdcc2_apps_clk_src = { .name = "gcc_sdcc2_apps_clk_src", .parent_data = gcc_parent_data_8, .num_parents = ARRAY_SIZE(gcc_parent_data_8), - .ops = &clk_rcg2_floor_ops, + .ops = &clk_rcg2_shared_floor_ops, }, }; From 921eed200c8f6675e91daa5df6a64fcf62faebc6 Mon Sep 17 00:00:00 2001 From: Haotian Zhang Date: Wed, 29 Oct 2025 10:27:33 +0800 Subject: [PATCH 0529/2333] soc: qcom: smem: fix hwspinlock resource leak in probe error paths [ Upstream commit dc5db35073a19f6d3c30bea367b551c1a784ef8f ] The hwspinlock acquired via hwspin_lock_request_specific() is not released on several error paths. This results in resource leakage when probe fails. Switch to devm_hwspin_lock_request_specific() to automatically handle cleanup on probe failure. Remove the manual hwspin_lock_free() in qcom_smem_remove() as devm handles it automatically. Fixes: 20bb6c9de1b7 ("soc: qcom: smem: map only partitions used by local HOST") Signed-off-by: Haotian Zhang Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20251029022733.255-1-vulab@iscas.ac.cn Signed-off-by: Bjorn Andersson Signed-off-by: Sasha Levin --- drivers/soc/qcom/smem.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/soc/qcom/smem.c b/drivers/soc/qcom/smem.c index c4c45f15dca4f..f1d1b5aa5e4db 100644 --- a/drivers/soc/qcom/smem.c +++ b/drivers/soc/qcom/smem.c @@ -1190,7 +1190,7 @@ static int qcom_smem_probe(struct platform_device *pdev) return dev_err_probe(&pdev->dev, hwlock_id, "failed to retrieve hwlock\n"); - smem->hwlock = hwspin_lock_request_specific(hwlock_id); + smem->hwlock = devm_hwspin_lock_request_specific(&pdev->dev, hwlock_id); if (!smem->hwlock) return -ENXIO; @@ -1243,7 +1243,6 @@ static void qcom_smem_remove(struct platform_device *pdev) { platform_device_unregister(__smem->socinfo); - hwspin_lock_free(__smem->hwlock); __smem = NULL; } From 3dc8f5c1956bfa259fd3e378864f474bda762978 Mon Sep 17 00:00:00 2001 From: Haotian Zhang Date: Wed, 29 Oct 2025 09:42:52 +0800 Subject: [PATCH 0530/2333] pinctrl: stm32: fix hwspinlock resource leak in probe function [ Upstream commit 002679f79ed605e543fbace465557317cd307c9a ] In stm32_pctl_probe(), hwspin_lock_request_specific() is called to request a hwspinlock, but the acquired lock is not freed on multiple error paths after this call. This causes resource leakage when the function fails to initialize properly. Use devm_hwspin_lock_request_specific() instead of hwspin_lock_request_specific() to automatically manage the hwspinlock resource lifecycle. Fixes: 97cfb6cd34f2 ("pinctrl: stm32: protect configuration registers with a hwspinlock") Signed-off-by: Haotian Zhang Reviewed-by: Antonio Borneo Signed-off-by: Linus Walleij Signed-off-by: Sasha Levin --- drivers/pinctrl/stm32/pinctrl-stm32.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pinctrl/stm32/pinctrl-stm32.c b/drivers/pinctrl/stm32/pinctrl-stm32.c index 3ebb468de830d..e73feb8ac90d1 100644 --- a/drivers/pinctrl/stm32/pinctrl-stm32.c +++ b/drivers/pinctrl/stm32/pinctrl-stm32.c @@ -1671,7 +1671,7 @@ int stm32_pctl_probe(struct platform_device *pdev) if (hwlock_id == -EPROBE_DEFER) return hwlock_id; } else { - pctl->hwlock = hwspin_lock_request_specific(hwlock_id); + pctl->hwlock = devm_hwspin_lock_request_specific(dev, hwlock_id); } spin_lock_init(&pctl->irqmux_lock); From 48efc0303ac98707e4d8d6308972d18be73f45ff Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Tue, 28 Oct 2025 12:00:53 +0100 Subject: [PATCH 0531/2333] drm: nova: select NOVA_CORE [ Upstream commit 97ad568cd6a58804129ba071f3258b5c4782fb0d ] The nova-drm driver does not provide any value without nova-core being selected as well, hence select NOVA_CORE. Fixes: cdeaeb9dd762 ("drm: nova-drm: add initial driver skeleton") Reviewed-by: Alexandre Courbot Reviewed-by: John Hubbard Link: https://patch.msgid.link/20251028110058.340320-2-dakr@kernel.org Signed-off-by: Danilo Krummrich Signed-off-by: Sasha Levin --- drivers/gpu/drm/nova/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/nova/Kconfig b/drivers/gpu/drm/nova/Kconfig index cca6a3fea879b..bd1df08791911 100644 --- a/drivers/gpu/drm/nova/Kconfig +++ b/drivers/gpu/drm/nova/Kconfig @@ -4,6 +4,7 @@ config DRM_NOVA depends on PCI depends on RUST select AUXILIARY_BUS + select NOVA_CORE default n help Choose this if you want to build the Nova DRM driver for Nvidia From d71333ffdd3707d84cfb95acfaf8ba892adc066b Mon Sep 17 00:00:00 2001 From: Tomasz Rusinowicz Date: Wed, 29 Oct 2025 08:14:51 +0100 Subject: [PATCH 0532/2333] accel/ivpu: Fix race condition when unbinding BOs [ Upstream commit 00812636df370bedf4e44a0c81b86ea96bca8628 ] Fix 'Memory manager not clean during takedown' warning that occurs when ivpu_gem_bo_free() removes the BO from the BOs list before it gets unmapped. Then file_priv_unbind() triggers a warning in drm_mm_takedown() during context teardown. Protect the unmapping sequence with bo_list_lock to ensure the BO is always fully unmapped when removed from the list. This ensures the BO is either fully unmapped at context teardown time or present on the list and unmapped by file_priv_unbind(). Fixes: 48aea7f2a2ef ("accel/ivpu: Fix locking in ivpu_bo_remove_all_bos_from_context()") Signed-off-by: Tomasz Rusinowicz Reviewed-by: Jeff Hugo Signed-off-by: Karol Wachowski Link: https://patch.msgid.link/20251029071451.184243-1-karol.wachowski@linux.intel.com Signed-off-by: Sasha Levin --- drivers/accel/ivpu/ivpu_gem.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/accel/ivpu/ivpu_gem.c b/drivers/accel/ivpu/ivpu_gem.c index a38e41f9c7123..fda0a18e6d639 100644 --- a/drivers/accel/ivpu/ivpu_gem.c +++ b/drivers/accel/ivpu/ivpu_gem.c @@ -314,7 +314,6 @@ static void ivpu_gem_bo_free(struct drm_gem_object *obj) mutex_lock(&vdev->bo_list_lock); list_del(&bo->bo_list_node); - mutex_unlock(&vdev->bo_list_lock); drm_WARN_ON(&vdev->drm, !drm_gem_is_imported(&bo->base.base) && !dma_resv_test_signaled(obj->resv, DMA_RESV_USAGE_READ)); @@ -325,6 +324,8 @@ static void ivpu_gem_bo_free(struct drm_gem_object *obj) ivpu_bo_unbind_locked(bo); ivpu_bo_unlock(bo); + mutex_unlock(&vdev->bo_list_lock); + drm_WARN_ON(&vdev->drm, bo->mmu_mapped); drm_WARN_ON(&vdev->drm, bo->ctx); From eab1b59664ee29852587a967517ce680b29ad501 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Tue, 28 Oct 2025 09:45:48 +0100 Subject: [PATCH 0533/2333] pidfs: add missing PIDFD_INFO_SIZE_VER1 [ Upstream commit 4061c43a99772c66c378cfacaa71550ab3b35909 ] We grew struct pidfd_info not too long ago. Link: https://patch.msgid.link/20251028-work-coredump-signal-v1-3-ca449b7b7aa0@kernel.org Fixes: 1d8db6fd698d ("pidfs, coredump: add PIDFD_INFO_COREDUMP") Reviewed-by: Alexander Mikhalitsyn Reviewed-by: Oleg Nesterov Signed-off-by: Christian Brauner Signed-off-by: Sasha Levin --- include/uapi/linux/pidfd.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/uapi/linux/pidfd.h b/include/uapi/linux/pidfd.h index 957db425d459a..6ccbabd9a68d8 100644 --- a/include/uapi/linux/pidfd.h +++ b/include/uapi/linux/pidfd.h @@ -28,6 +28,7 @@ #define PIDFD_INFO_COREDUMP (1UL << 4) /* Only returned if requested. */ #define PIDFD_INFO_SIZE_VER0 64 /* sizeof first published struct */ +#define PIDFD_INFO_SIZE_VER1 72 /* sizeof second published struct */ /* * Values for @coredump_mask in pidfd_info. From ae7a542dbab5bc5af5aa9789d27e15d3791e357f Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Tue, 28 Oct 2025 09:45:49 +0100 Subject: [PATCH 0534/2333] pidfs: add missing BUILD_BUG_ON() assert on struct pidfd_info [ Upstream commit d8fc51d8fa3b9894713e7eebcf574bee488fa3e1 ] Validate that the size of struct pidfd_info is correctly updated. Link: https://patch.msgid.link/20251028-work-coredump-signal-v1-4-ca449b7b7aa0@kernel.org Fixes: 1d8db6fd698d ("pidfs, coredump: add PIDFD_INFO_COREDUMP") Reviewed-by: Alexander Mikhalitsyn Reviewed-by: Oleg Nesterov Signed-off-by: Christian Brauner Signed-off-by: Sasha Levin --- fs/pidfs.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/pidfs.c b/fs/pidfs.c index 0ef5b47d796a2..f4d7dac1b4494 100644 --- a/fs/pidfs.c +++ b/fs/pidfs.c @@ -306,6 +306,8 @@ static long pidfd_info(struct file *file, unsigned int cmd, unsigned long arg) const struct cred *c; __u64 mask; + BUILD_BUG_ON(sizeof(struct pidfd_info) != PIDFD_INFO_SIZE_VER1); + if (!uinfo) return -EINVAL; if (usize < PIDFD_INFO_SIZE_VER0) From 670b969647302b16fa88a179b1950714da18f2c5 Mon Sep 17 00:00:00 2001 From: Aniket Limaye Date: Wed, 22 Oct 2025 17:56:33 +0530 Subject: [PATCH 0535/2333] arm64: dts: ti: k3-j784s4: Fix I2C pinmux pull configuration [ Upstream commit 671c852fc53d1b6f5eccdb03c1889a484c9d1996 ] The I2C pins for some of the instances on J784S4/J742S2/AM69 are configured as PIN_INPUT_PULLUP while these pins are open-drain type and do not support internal pull-ups [0][1][2]. The pullup configuration bits in the corresponding padconfig registers are reserved and any writes to them have no effect and readback checks on those bits fail. Update the pinmux settings to use PIN_INPUT instead of PIN_INPUT_PULLUP to reflect the correct hardware behaviour. [0]: https://www.ti.com/lit/gpn/tda4ah-q1 (J784S4 Datasheet: Table 5-1. Pin Attributes) [1]: https://www.ti.com/lit/gpn/tda4ape-q1 (J742S2 Datasheet: Table 5-1. Pin Attributes) [2]: https://www.ti.com/lit/gpn/am69a (AM69 Datasheet: Table 5-1. Pin Attributes) Fixes: e20a06aca5c9 ("arm64: dts: ti: Add support for J784S4 EVM board") Fixes: 635fb18ba008 ("arch: arm64: dts: Add support for AM69 Starter Kit") Fixes: 0ec1a48d99dd ("arm64: dts: ti: k3-am69-sk: Add pinmux for RPi Header") Signed-off-by: Aniket Limaye Reviewed-by: Udit Kumar Link: https://patch.msgid.link/20251022122638.234367-1-a-limaye@ti.com Signed-off-by: Vignesh Raghavendra Signed-off-by: Sasha Levin --- arch/arm64/boot/dts/ti/k3-am69-sk.dts | 8 ++++---- arch/arm64/boot/dts/ti/k3-j784s4-j742s2-evm-common.dtsi | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/arm64/boot/dts/ti/k3-am69-sk.dts b/arch/arm64/boot/dts/ti/k3-am69-sk.dts index 5896e57b5b9ed..0e2d12cb051da 100644 --- a/arch/arm64/boot/dts/ti/k3-am69-sk.dts +++ b/arch/arm64/boot/dts/ti/k3-am69-sk.dts @@ -236,8 +236,8 @@ main_i2c0_pins_default: main-i2c0-default-pins { pinctrl-single,pins = < - J784S4_IOPAD(0x0e0, PIN_INPUT_PULLUP, 0) /* (AN36) I2C0_SCL */ - J784S4_IOPAD(0x0e4, PIN_INPUT_PULLUP, 0) /* (AP37) I2C0_SDA */ + J784S4_IOPAD(0x0e0, PIN_INPUT, 0) /* (AN36) I2C0_SCL */ + J784S4_IOPAD(0x0e4, PIN_INPUT, 0) /* (AP37) I2C0_SDA */ >; }; @@ -416,8 +416,8 @@ mcu_i2c0_pins_default: mcu-i2c0-default-pins { pinctrl-single,pins = < - J784S4_WKUP_IOPAD(0x0a0, PIN_INPUT_PULLUP, 0) /* (M35) MCU_I2C0_SCL */ - J784S4_WKUP_IOPAD(0x0a4, PIN_INPUT_PULLUP, 0) /* (G34) MCU_I2C0_SDA */ + J784S4_WKUP_IOPAD(0x0a0, PIN_INPUT, 0) /* (M35) MCU_I2C0_SCL */ + J784S4_WKUP_IOPAD(0x0a4, PIN_INPUT, 0) /* (G34) MCU_I2C0_SDA */ >; }; diff --git a/arch/arm64/boot/dts/ti/k3-j784s4-j742s2-evm-common.dtsi b/arch/arm64/boot/dts/ti/k3-j784s4-j742s2-evm-common.dtsi index 419c1a70e028d..2834f0a8bbee0 100644 --- a/arch/arm64/boot/dts/ti/k3-j784s4-j742s2-evm-common.dtsi +++ b/arch/arm64/boot/dts/ti/k3-j784s4-j742s2-evm-common.dtsi @@ -270,8 +270,8 @@ main_i2c0_pins_default: main-i2c0-default-pins { pinctrl-single,pins = < - J784S4_IOPAD(0x0e0, PIN_INPUT_PULLUP, 0) /* (AN36) I2C0_SCL */ - J784S4_IOPAD(0x0e4, PIN_INPUT_PULLUP, 0) /* (AP37) I2C0_SDA */ + J784S4_IOPAD(0x0e0, PIN_INPUT, 0) /* (AN36) I2C0_SCL */ + J784S4_IOPAD(0x0e4, PIN_INPUT, 0) /* (AP37) I2C0_SDA */ >; }; From c704ccb558eef6704cccc2b4f8f22e09ae0ebe6f Mon Sep 17 00:00:00 2001 From: Frank Li Date: Thu, 16 Oct 2025 10:38:13 -0400 Subject: [PATCH 0536/2333] i3c: fix refcount inconsistency in i3c_master_register [ Upstream commit 9d4f219807d5ac11fb1d596e4ddb09336b040067 ] In `i3c_master_register`, a possible refcount inconsistency has been identified, causing possible resource leak. Function `of_node_get` increases the refcount of `parent->of_node`. If function `i3c_bus_init` fails, the function returns immediately without a corresponding decrease, resulting in an inconsistent refcounter. Move call i3c_bus_init() after device_initialize() to let callback i3c_masterdev_release() release of_node. Reported-by: Shuhao Fu Closes: https://lore.kernel.org/linux-i3c/aO2tjp_FsV_WohPG@osx.local/T/#m2c05a982beeb14e7bf039c1d8db856734bf234c7 Fixes: 3a379bbcea0a ("i3c: Add core I3C infrastructure") Signed-off-by: Frank Li Link: https://patch.msgid.link/20251016143814.2551256-1-Frank.Li@nxp.com Signed-off-by: Alexandre Belloni Signed-off-by: Sasha Levin --- drivers/i3c/master.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c index d946db75df706..66513a27e6e77 100644 --- a/drivers/i3c/master.c +++ b/drivers/i3c/master.c @@ -2883,10 +2883,6 @@ int i3c_master_register(struct i3c_master_controller *master, INIT_LIST_HEAD(&master->boardinfo.i2c); INIT_LIST_HEAD(&master->boardinfo.i3c); - ret = i3c_bus_init(i3cbus, master->dev.of_node); - if (ret) - return ret; - device_initialize(&master->dev); dev_set_name(&master->dev, "i3c-%d", i3cbus->id); @@ -2894,6 +2890,10 @@ int i3c_master_register(struct i3c_master_controller *master, master->dev.coherent_dma_mask = parent->coherent_dma_mask; master->dev.dma_parms = parent->dma_parms; + ret = i3c_bus_init(i3cbus, master->dev.of_node); + if (ret) + goto err_put_dev; + ret = of_populate_i3c_bus(master); if (ret) goto err_put_dev; From 8ddff9989f06aa9a30fa8b76f3154149f76b42fd Mon Sep 17 00:00:00 2001 From: Stanley Chu Date: Mon, 27 Oct 2025 11:47:15 +0800 Subject: [PATCH 0537/2333] i3c: master: svc: Prevent incomplete IBI transaction [ Upstream commit 3a36273e5a07dda0ccec193800f3b78c3c0380af ] If no free IBI slot is available, svc_i3c_master_handle_ibi returns immediately. This causes the STOP condition to be missed because the EmitStop request is sent when the transfer is not complete. To resolve this, svc_i3c_master_handle_ibi must wait for the transfer to complete before returning. Fixes: dd3c52846d59 ("i3c: master: svc: Add Silvaco I3C master driver") Signed-off-by: Stanley Chu Reviewed-by: Frank Li Reviewed-by: Miquel Raynal Link: https://patch.msgid.link/20251027034715.708243-1-yschu@nuvoton.com Signed-off-by: Alexandre Belloni Signed-off-by: Sasha Levin --- drivers/i3c/master/svc-i3c-master.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/drivers/i3c/master/svc-i3c-master.c b/drivers/i3c/master/svc-i3c-master.c index 9641e66a4e5f2..e70a64f2a32fa 100644 --- a/drivers/i3c/master/svc-i3c-master.c +++ b/drivers/i3c/master/svc-i3c-master.c @@ -406,21 +406,27 @@ static int svc_i3c_master_handle_ibi(struct svc_i3c_master *master, int ret, val; u8 *buf; - slot = i3c_generic_ibi_get_free_slot(data->ibi_pool); - if (!slot) - return -ENOSPC; - - slot->len = 0; - buf = slot->data; - + /* + * Wait for transfer to complete before returning. Otherwise, the EmitStop + * request might be sent when the transfer is not complete. + */ ret = readl_relaxed_poll_timeout(master->regs + SVC_I3C_MSTATUS, val, SVC_I3C_MSTATUS_COMPLETE(val), 0, 1000); if (ret) { dev_err(master->dev, "Timeout when polling for COMPLETE\n"); - i3c_generic_ibi_recycle_slot(data->ibi_pool, slot); return ret; } + slot = i3c_generic_ibi_get_free_slot(data->ibi_pool); + if (!slot) { + dev_dbg(master->dev, "No free ibi slot, drop the data\n"); + writel(SVC_I3C_MDATACTRL_FLUSHRB, master->regs + SVC_I3C_MDATACTRL); + return -ENOSPC; + } + + slot->len = 0; + buf = slot->data; + while (SVC_I3C_MSTATUS_RXPEND(readl(master->regs + SVC_I3C_MSTATUS)) && slot->len < SVC_I3C_FIFO_SIZE) { mdatactrl = readl(master->regs + SVC_I3C_MDATACTRL); From cbd5021199db356c6dc1928d48e3fb132dbbc9bb Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 10 Jun 2025 11:27:08 +0200 Subject: [PATCH 0538/2333] random: use offstack cpumask when necessary [ Upstream commit 5d49f1a5bd358d24e5f88b23b46da833de1dbec8 ] The entropy generation function keeps a local cpu mask on the stack, which can trigger warnings in configurations with a large number of CPUs: drivers/char/random.c:1292:20: error: stack frame size (1288) exceeds limit (1280) in 'try_to_generate_entropy' [-Werror,-Wframe-larger-than] Use the cpumask interface to dynamically allocate it in those configurations. Fixes: 1c21fe00eda7 ("random: spread out jitter callback to different CPUs") Signed-off-by: Arnd Bergmann Signed-off-by: Jason A. Donenfeld Signed-off-by: Sasha Levin --- drivers/char/random.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/drivers/char/random.c b/drivers/char/random.c index b8b24b6ed3fe4..4ba5f0c4c8b24 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -1296,6 +1296,7 @@ static void __cold try_to_generate_entropy(void) struct entropy_timer_state *stack = PTR_ALIGN((void *)stack_bytes, SMP_CACHE_BYTES); unsigned int i, num_different = 0; unsigned long last = random_get_entropy(); + cpumask_var_t timer_cpus; int cpu = -1; for (i = 0; i < NUM_TRIAL_SAMPLES - 1; ++i) { @@ -1310,13 +1311,15 @@ static void __cold try_to_generate_entropy(void) atomic_set(&stack->samples, 0); timer_setup_on_stack(&stack->timer, entropy_timer, 0); + if (!alloc_cpumask_var(&timer_cpus, GFP_KERNEL)) + goto out; + while (!crng_ready() && !signal_pending(current)) { /* * Check !timer_pending() and then ensure that any previous callback has finished * executing by checking timer_delete_sync_try(), before queueing the next one. */ if (!timer_pending(&stack->timer) && timer_delete_sync_try(&stack->timer) >= 0) { - struct cpumask timer_cpus; unsigned int num_cpus; /* @@ -1326,19 +1329,19 @@ static void __cold try_to_generate_entropy(void) preempt_disable(); /* Only schedule callbacks on timer CPUs that are online. */ - cpumask_and(&timer_cpus, housekeeping_cpumask(HK_TYPE_TIMER), cpu_online_mask); - num_cpus = cpumask_weight(&timer_cpus); + cpumask_and(timer_cpus, housekeeping_cpumask(HK_TYPE_TIMER), cpu_online_mask); + num_cpus = cpumask_weight(timer_cpus); /* In very bizarre case of misconfiguration, fallback to all online. */ if (unlikely(num_cpus == 0)) { - timer_cpus = *cpu_online_mask; - num_cpus = cpumask_weight(&timer_cpus); + *timer_cpus = *cpu_online_mask; + num_cpus = cpumask_weight(timer_cpus); } /* Basic CPU round-robin, which avoids the current CPU. */ do { - cpu = cpumask_next(cpu, &timer_cpus); + cpu = cpumask_next(cpu, timer_cpus); if (cpu >= nr_cpu_ids) - cpu = cpumask_first(&timer_cpus); + cpu = cpumask_first(timer_cpus); } while (cpu == smp_processor_id() && num_cpus > 1); /* Expiring the timer at `jiffies` means it's the next tick. */ @@ -1354,6 +1357,8 @@ static void __cold try_to_generate_entropy(void) } mix_pool_bytes(&stack->entropy, sizeof(stack->entropy)); + free_cpumask_var(timer_cpus); +out: timer_delete_sync(&stack->timer); timer_destroy_on_stack(&stack->timer); } From d0bb3db7b2959581270b77669faca67441a8f3af Mon Sep 17 00:00:00 2001 From: Abdun Nihaal Date: Tue, 28 Oct 2025 22:34:55 +0530 Subject: [PATCH 0539/2333] wifi: ath12k: fix potential memory leak in ath12k_wow_arp_ns_offload() [ Upstream commit be5febd51c478bc8e24ad3480435f2754a403b14 ] When the call to ath12k_wmi_arp_ns_offload() fails, the temporary memory allocation for offload is not freed before returning. Fix that by freeing offload in the error path. Fixes: 1666108c74c4 ("wifi: ath12k: support ARP and NS offload") Signed-off-by: Abdun Nihaal Reviewed-by: Baochen Qiang Link: https://patch.msgid.link/20251028170457.134608-1-nihaal@cse.iitm.ac.in Signed-off-by: Jeff Johnson Signed-off-by: Sasha Levin --- drivers/net/wireless/ath/ath12k/wow.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/ath/ath12k/wow.c b/drivers/net/wireless/ath/ath12k/wow.c index dce9bd0bcaefb..e8481626f1940 100644 --- a/drivers/net/wireless/ath/ath12k/wow.c +++ b/drivers/net/wireless/ath/ath12k/wow.c @@ -758,6 +758,7 @@ static int ath12k_wow_arp_ns_offload(struct ath12k *ar, bool enable) if (ret) { ath12k_warn(ar->ab, "failed to set arp ns offload vdev %i: enable %d, ret %d\n", arvif->vdev_id, enable, ret); + kfree(offload); return ret; } } From 36faecac7a2c238d46008f2c8f088d0eba674252 Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Wed, 29 Oct 2025 10:07:14 +0800 Subject: [PATCH 0540/2333] wifi: ath12k: fix reusing m3 memory [ Upstream commit 00575bb44b2c2aa53d0a768de2b80c9c1af0174d ] During firmware recovery or suspend/resume, m3 memory could be reused if the size of the new m3 binary is equal to or less than that of the existing memory. There will be issues for the latter case, since m3_mem->size will be updated with a smaller value and this value is eventually used in the free path, where the original total size should be used instead. To fix it, add a new member in m3_mem_region structure to track the original memory size and use it in free path. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.1.c5-00302-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.115823.3 Fixes: 05090ae82f44 ("wifi: ath12k: check M3 buffer size as well whey trying to reuse it") Signed-off-by: Baochen Qiang Reviewed-by: Vasanthakumar Thiagarajan Link: https://patch.msgid.link/20251029-ath12k-fix-m3-reuse-v1-1-69225bacfc5d@oss.qualcomm.com Signed-off-by: Jeff Johnson Signed-off-by: Sasha Levin --- drivers/net/wireless/ath/ath12k/qmi.c | 11 +++++++---- drivers/net/wireless/ath/ath12k/qmi.h | 5 ++++- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/qmi.c b/drivers/net/wireless/ath/ath12k/qmi.c index 36325e62aa242..8de9aee2498ec 100644 --- a/drivers/net/wireless/ath/ath12k/qmi.c +++ b/drivers/net/wireless/ath/ath12k/qmi.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include @@ -3114,9 +3114,10 @@ static void ath12k_qmi_m3_free(struct ath12k_base *ab) if (!m3_mem->vaddr) return; - dma_free_coherent(ab->dev, m3_mem->size, + dma_free_coherent(ab->dev, m3_mem->total_size, m3_mem->vaddr, m3_mem->paddr); m3_mem->vaddr = NULL; + m3_mem->total_size = 0; m3_mem->size = 0; } @@ -3152,7 +3153,7 @@ static int ath12k_qmi_m3_load(struct ath12k_base *ab) /* In recovery/resume cases, M3 buffer is not freed, try to reuse that */ if (m3_mem->vaddr) { - if (m3_mem->size >= m3_len) + if (m3_mem->total_size >= m3_len) goto skip_m3_alloc; /* Old buffer is too small, free and reallocate */ @@ -3164,11 +3165,13 @@ static int ath12k_qmi_m3_load(struct ath12k_base *ab) GFP_KERNEL); if (!m3_mem->vaddr) { ath12k_err(ab, "failed to allocate memory for M3 with size %zu\n", - fw->size); + m3_len); ret = -ENOMEM; goto out; } + m3_mem->total_size = m3_len; + skip_m3_alloc: memcpy(m3_mem->vaddr, m3_data, m3_len); m3_mem->size = m3_len; diff --git a/drivers/net/wireless/ath/ath12k/qmi.h b/drivers/net/wireless/ath/ath12k/qmi.h index 4767d9a2e309e..7a88268aa1e9e 100644 --- a/drivers/net/wireless/ath/ath12k/qmi.h +++ b/drivers/net/wireless/ath/ath12k/qmi.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #ifndef ATH12K_QMI_H @@ -120,6 +120,9 @@ struct target_info { }; struct m3_mem_region { + /* total memory allocated */ + u32 total_size; + /* actual memory being used */ u32 size; dma_addr_t paddr; void *vaddr; From 4f93750fa58861abee4318115ef0023c8d3ba0c0 Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Thu, 30 Oct 2025 10:08:43 +0800 Subject: [PATCH 0541/2333] wifi: ath12k: fix error handling in creating hardware group [ Upstream commit 088a099690e4c0d291db505013317ab5dd58b4d5 ] In ath12k_core_init() when ath12k_core_hw_group_create() fails, ath12k_core_hw_group_destroy() is called where for each device below path would get executed ath12k_core_soc_destroy() ath12k_qmi_deinit_service() qmi_handle_release() This results in kernel crash in case one of the device fails at qmi_handle_init() when creating hardware group: ath12k_pci 0000:10:00.0: failed to initialize qmi handle ath12k_pci 0000:10:00.0: failed to initialize qmi :-517 ath12k_pci 0000:10:00.0: failed to create soc core: -517 ath12k_pci 0000:10:00.0: unable to create hw group BUG: unable to handle page fault for address: ffffffffffffffb7 RIP: 0010:qmi_handle_release Call Trace: ath12k_qmi_deinit_service ath12k_core_hw_group_destroy ath12k_core_init ath12k_pci_probe The detailed reason is, when qmi_handle_init() fails for a device ab->qmi.handle is not correctly initialized. Then ath12k_core_hw_group_create() returns failure, since error handing is done for all device, eventually qmi_handle_release() is called for the issue device and finally kernel crashes due to the uninitialized ab->qmi.handle. Fix this by moving error handling to ath12k_core_hw_group_create(), this way the issue device can be skipped. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.1.c5-00284.1-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Fixes: 6f245ea0ec6c ("wifi: ath12k: introduce device group abstraction") Link: https://lore.kernel.org/ath12k/fabc97122016d1a66a53ddedd965d134@posteo.net Reported-by: a-development Closes: https://bugzilla.kernel.org/show_bug.cgi?id=220518 Tested-by: a-development Signed-off-by: Baochen Qiang Reviewed-by: Vasanthakumar Thiagarajan Link: https://patch.msgid.link/20251030-fix-hw-group-create-err-handling-v1-1-0659e4d15fb9@oss.qualcomm.com Signed-off-by: Jeff Johnson Signed-off-by: Sasha Levin --- drivers/net/wireless/ath/ath12k/core.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c index 5d494c5cdc0da..a2137b363c2fe 100644 --- a/drivers/net/wireless/ath/ath12k/core.c +++ b/drivers/net/wireless/ath/ath12k/core.c @@ -2106,14 +2106,27 @@ static int ath12k_core_hw_group_create(struct ath12k_hw_group *ag) ret = ath12k_core_soc_create(ab); if (ret) { mutex_unlock(&ab->core_lock); - ath12k_err(ab, "failed to create soc core: %d\n", ret); - return ret; + ath12k_err(ab, "failed to create soc %d core: %d\n", i, ret); + goto destroy; } mutex_unlock(&ab->core_lock); } return 0; + +destroy: + for (i--; i >= 0; i--) { + ab = ag->ab[i]; + if (!ab) + continue; + + mutex_lock(&ab->core_lock); + ath12k_core_soc_destroy(ab); + mutex_unlock(&ab->core_lock); + } + + return ret; } void ath12k_core_hw_group_set_mlo_capable(struct ath12k_hw_group *ag) @@ -2188,7 +2201,7 @@ int ath12k_core_init(struct ath12k_base *ab) if (ret) { mutex_unlock(&ag->mutex); ath12k_warn(ab, "unable to create hw group\n"); - goto err_destroy_hw_group; + goto err_unassign_hw_group; } } @@ -2196,8 +2209,7 @@ int ath12k_core_init(struct ath12k_base *ab) return 0; -err_destroy_hw_group: - ath12k_core_hw_group_destroy(ab->ag); +err_unassign_hw_group: ath12k_core_hw_group_unassign(ab); err_unregister_notifier: ath12k_core_panic_notifier_unregister(ab); From 41b6231291750e2caa9550cf2728e04fed255bda Mon Sep 17 00:00:00 2001 From: Rameshkumar Sundaram Date: Sun, 26 Oct 2025 23:52:53 +0530 Subject: [PATCH 0542/2333] wifi: ath12k: enforce vdev limit in ath12k_mac_vdev_create() [ Upstream commit 448bf7b51426bcca54b5ac1ddd1045a36c9d1dea ] Currently, vdev limit check is performed only in ath12k_mac_assign_vif_to_vdev(). If the host has already created maximum number of vdevs for the radio (ar) and a scan request arrives for the same radio, ath12k_mac_initiate_hw_scan() attempts to create a vdev without checking the limit, causing firmware asserts. Centralize the vdev limit guard by moving the check into ath12k_mac_vdev_create() so that all callers obey the limit. While doing this, update the condition from `num_created_vdevs > (TARGET_NUM_VDEVS(ab) - 1)` to `num_created_vdevs >= TARGET_NUM_VDEVS(ab)` for clarity and to eliminate unnecessary arithmetic. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.4.1-00199-QCAHKSWPL_SILICONZ-1 Fixes: 0d6e6736ed9f ("wifi: ath12k: scan statemachine changes for single wiphy") Fixes: 4938ba733ee2 ("wifi: ath12k: modify remain on channel for single wiphy") Signed-off-by: Rameshkumar Sundaram Reviewed-by: Vasanthakumar Thiagarajan Link: https://patch.msgid.link/20251026182254.1399650-2-rameshkumar.sundaram@oss.qualcomm.com Signed-off-by: Jeff Johnson Signed-off-by: Sasha Levin --- drivers/net/wireless/ath/ath12k/mac.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 0cec6c47fca29..8f139505019c4 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -9687,6 +9687,12 @@ int ath12k_mac_vdev_create(struct ath12k *ar, struct ath12k_link_vif *arvif) if (vif->type == NL80211_IFTYPE_MONITOR && ar->monitor_vdev_created) return -EINVAL; + if (ar->num_created_vdevs >= TARGET_NUM_VDEVS(ab)) { + ath12k_warn(ab, "failed to create vdev, reached max vdev limit %d\n", + TARGET_NUM_VDEVS(ab)); + return -ENOSPC; + } + link_id = arvif->link_id; if (link_id < IEEE80211_MLD_MAX_NUM_LINKS) { @@ -10046,12 +10052,6 @@ static struct ath12k *ath12k_mac_assign_vif_to_vdev(struct ieee80211_hw *hw, if (arvif->is_created) goto flush; - if (ar->num_created_vdevs > (TARGET_NUM_VDEVS(ab) - 1)) { - ath12k_warn(ab, "failed to create vdev, reached max vdev limit %d\n", - TARGET_NUM_VDEVS(ab)); - goto unlock; - } - ret = ath12k_mac_vdev_create(ar, arvif); if (ret) { ath12k_warn(ab, "failed to create vdev %pM ret %d", vif->addr, ret); From e442e820e95389931be507c9d6c174e9ce4c6167 Mon Sep 17 00:00:00 2001 From: Rameshkumar Sundaram Date: Sun, 26 Oct 2025 23:52:54 +0530 Subject: [PATCH 0543/2333] wifi: ath12k: unassign arvif on scan vdev create failure [ Upstream commit e70515039d44be61b6a73aafb401d141b0034d12 ] During scan and remain-on-channel requests, a scan link vif (arvif) is assigned and a temporary vdev is created. If vdev creation fails, the assigned arvif is left attached until the virtual interface is removed, leaving a stale link in ahvif. Fix this by freeing the stale arvif and resetting the corresponding link in ahvif by calling ath12k_mac_unassign_link_vif() when vdev creation fails. While at it, propagate the actual error code from ath12k_mac_vdev_create() instead of returning -EINVAL in ath12k_mac_initiate_hw_scan(). Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.4.1-00199-QCAHKSWPL_SILICONZ-1 Fixes: 477cabfdb776 ("wifi: ath12k: modify link arvif creation and removal for MLO") Signed-off-by: Rameshkumar Sundaram Reviewed-by: Vasanthakumar Thiagarajan Link: https://patch.msgid.link/20251026182254.1399650-3-rameshkumar.sundaram@oss.qualcomm.com Signed-off-by: Jeff Johnson Signed-off-by: Sasha Levin --- drivers/net/wireless/ath/ath12k/mac.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 8f139505019c4..095b49a39683c 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -5059,7 +5059,8 @@ static int ath12k_mac_initiate_hw_scan(struct ieee80211_hw *hw, ret = ath12k_mac_vdev_create(ar, arvif); if (ret) { ath12k_warn(ar->ab, "unable to create scan vdev %d\n", ret); - return -EINVAL; + ath12k_mac_unassign_link_vif(arvif); + return ret; } } @@ -12895,6 +12896,7 @@ static int ath12k_mac_op_remain_on_channel(struct ieee80211_hw *hw, if (ret) { ath12k_warn(ar->ab, "unable to create scan vdev for roc: %d\n", ret); + ath12k_mac_unassign_link_vif(arvif); return ret; } } From 3fcb47f405e9f6d15c6b1d1cb3c4358d5b34d871 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Thu, 2 Oct 2025 11:53:00 +0300 Subject: [PATCH 0544/2333] interconnect: qcom: msm8996: add missing link to SLAVE_USB_HS [ Upstream commit 8cf9b43f6b4d90e19a9341edefdd46842d4adb55 ] >From the initial submission the interconnect driver missed the link from SNOC_PNOC to the USB 2 configuration space. Add missing link in order to let the platform configure and utilize this path. Fixes: 7add937f5222 ("interconnect: qcom: Add MSM8996 interconnect provider driver") Signed-off-by: Dmitry Baryshkov Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20251002-fix-msm8996-icc-v1-1-a36a05d1f869@oss.qualcomm.com Signed-off-by: Georgi Djakov Signed-off-by: Sasha Levin --- drivers/interconnect/qcom/msm8996.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/interconnect/qcom/msm8996.c b/drivers/interconnect/qcom/msm8996.c index b73566c9b21f9..84cfafb22aa17 100644 --- a/drivers/interconnect/qcom/msm8996.c +++ b/drivers/interconnect/qcom/msm8996.c @@ -552,6 +552,7 @@ static struct qcom_icc_node mas_venus_vmem = { static const u16 mas_snoc_pnoc_links[] = { MSM8996_SLAVE_BLSP_1, MSM8996_SLAVE_BLSP_2, + MSM8996_SLAVE_USB_HS, MSM8996_SLAVE_SDCC_1, MSM8996_SLAVE_SDCC_2, MSM8996_SLAVE_SDCC_4, From 30f32fa4d2331896ae05ac75dfc06aaa007a35d6 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Thu, 2 Oct 2025 11:53:01 +0300 Subject: [PATCH 0545/2333] arm64: dts: qcom: msm8996: add interconnect paths to USB2 controller [ Upstream commit 242f7558e7bf54cb63c06506f7b0630dd67d45a4 ] Add the missing interconnects to the USB2 host. The Fixes tag points to the commit which broke probing of the USB host on that platform. Fixes: 130733a10079 ("interconnect: qcom: msm8996: Promote to core_initcall") Signed-off-by: Dmitry Baryshkov Reviewed-by: Konrad Dybcio Acked-by: Bjorn Andersson Link: https://lore.kernel.org/r/20251002-fix-msm8996-icc-v1-2-a36a05d1f869@oss.qualcomm.com Signed-off-by: Georgi Djakov Signed-off-by: Sasha Levin --- arch/arm64/boot/dts/qcom/msm8996.dtsi | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/msm8996.dtsi b/arch/arm64/boot/dts/qcom/msm8996.dtsi index c75b522f6eba6..33608b1d7d060 100644 --- a/arch/arm64/boot/dts/qcom/msm8996.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8996.dtsi @@ -3496,6 +3496,9 @@ <&gcc GCC_USB20_MASTER_CLK>; assigned-clock-rates = <19200000>, <60000000>; + interconnects = <&pnoc MASTER_USB_HS &bimc SLAVE_EBI_CH0>, + <&bimc MASTER_AMPSS_M0 &pnoc SLAVE_USB_HS>; + interconnect-names = "usb-ddr", "apps-usb"; power-domains = <&gcc USB30_GDSC>; qcom,select-utmi-as-pipe-clk; status = "disabled"; From 14700e6b28f3e21fe9fe2f506b6d4e45c289f37f Mon Sep 17 00:00:00 2001 From: Lizhi Hou Date: Wed, 29 Oct 2025 12:34:23 -0700 Subject: [PATCH 0546/2333] accel/amdxdna: Fix incorrect command state for timed out job [ Upstream commit 6fb7f298883246e21f60f971065adcb789ae6eba ] When a command times out, mark it as ERT_CMD_STATE_TIMEOUT. Any other commands that are canceled due to this timeout should be marked as ERT_CMD_STATE_ABORT. Fixes: aac243092b70 ("accel/amdxdna: Add command execution") Reviewed-by: Mario Limonciello (AMD) Signed-off-by: Lizhi Hou Link: https://patch.msgid.link/20251029193423.2430463-1-lizhi.hou@amd.com Signed-off-by: Sasha Levin --- drivers/accel/amdxdna/aie2_ctx.c | 15 +++++++++++++-- drivers/accel/amdxdna/amdxdna_ctx.h | 1 + 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/drivers/accel/amdxdna/aie2_ctx.c b/drivers/accel/amdxdna/aie2_ctx.c index e9f9b1fa5dc1b..c9f712f0ec00c 100644 --- a/drivers/accel/amdxdna/aie2_ctx.c +++ b/drivers/accel/amdxdna/aie2_ctx.c @@ -204,10 +204,13 @@ aie2_sched_resp_handler(void *handle, void __iomem *data, size_t size) cmd_abo = job->cmd_bo; - if (unlikely(!data)) + if (unlikely(job->job_timeout)) { + amdxdna_cmd_set_state(cmd_abo, ERT_CMD_STATE_TIMEOUT); + ret = -EINVAL; goto out; + } - if (unlikely(size != sizeof(u32))) { + if (unlikely(!data) || unlikely(size != sizeof(u32))) { amdxdna_cmd_set_state(cmd_abo, ERT_CMD_STATE_ABORT); ret = -EINVAL; goto out; @@ -260,6 +263,13 @@ aie2_sched_cmdlist_resp_handler(void *handle, void __iomem *data, size_t size) int ret = 0; cmd_abo = job->cmd_bo; + + if (unlikely(job->job_timeout)) { + amdxdna_cmd_set_state(cmd_abo, ERT_CMD_STATE_TIMEOUT); + ret = -EINVAL; + goto out; + } + if (unlikely(!data) || unlikely(size != sizeof(u32) * 3)) { amdxdna_cmd_set_state(cmd_abo, ERT_CMD_STATE_ABORT); ret = -EINVAL; @@ -362,6 +372,7 @@ aie2_sched_job_timedout(struct drm_sched_job *sched_job) xdna = hwctx->client->xdna; trace_xdna_job(sched_job, hwctx->name, "job timedout", job->seq); + job->job_timeout = true; mutex_lock(&xdna->dev_lock); aie2_hwctx_stop(xdna, hwctx, sched_job); diff --git a/drivers/accel/amdxdna/amdxdna_ctx.h b/drivers/accel/amdxdna/amdxdna_ctx.h index 7cd7a55936f09..8c1d181df6e79 100644 --- a/drivers/accel/amdxdna/amdxdna_ctx.h +++ b/drivers/accel/amdxdna/amdxdna_ctx.h @@ -105,6 +105,7 @@ struct amdxdna_sched_job { /* user can wait on this fence */ struct dma_fence *out_fence; bool job_done; + bool job_timeout; u64 seq; struct amdxdna_gem_obj *cmd_bo; size_t bo_cnt; From 18fe7b456f99c478a1d7cc3fd66ec2eacfeb8f66 Mon Sep 17 00:00:00 2001 From: Kuan-Wei Chiu Date: Fri, 10 Oct 2025 23:14:47 +0800 Subject: [PATCH 0547/2333] interconnect: debugfs: Fix incorrect error handling for NULL path [ Upstream commit 6bfe104fd0f94d0248af22c256ce725ee087157b ] The icc_commit_set() function, used by the debugfs interface, checks the validity of the global cur_path pointer using IS_ERR_OR_NULL(). However, in the specific case where cur_path is NULL, while IS_ERR_OR_NULL(NULL) correctly evaluates to true, the subsequent call to PTR_ERR(NULL) returns 0. This causes the function to return a success code (0) instead of an error, misleading the user into believing their bandwidth request was successfully committed when, in fact, no operation was performed. Fix this by adding an explicit check to return -EINVAL if cur_path is NULL. This prevents silent failures and ensures that an invalid operational sequence is immediately and clearly reported as an error. Fixes: 770c69f037c1 ("interconnect: Add debugfs test client") Signed-off-by: Kuan-Wei Chiu Link: https://lore.kernel.org/r/20251010151447.2289779-1-visitorckw@gmail.com Signed-off-by: Georgi Djakov Signed-off-by: Sasha Levin --- drivers/interconnect/debugfs-client.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/interconnect/debugfs-client.c b/drivers/interconnect/debugfs-client.c index bc3fd8a7b9eb4..778deeb4a7e8a 100644 --- a/drivers/interconnect/debugfs-client.c +++ b/drivers/interconnect/debugfs-client.c @@ -117,7 +117,12 @@ static int icc_commit_set(void *data, u64 val) mutex_lock(&debugfs_lock); - if (IS_ERR_OR_NULL(cur_path)) { + if (!cur_path) { + ret = -EINVAL; + goto out; + } + + if (IS_ERR(cur_path)) { ret = PTR_ERR(cur_path); goto out; } From e620258d7d5ee5b9fe35e6e4932b6b73aae385cf Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Mon, 27 Oct 2025 19:45:53 +0100 Subject: [PATCH 0548/2333] arm64: dts: renesas: sparrow-hawk: Fix full-size DP connector node name and labels MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 9d22a34a016313137b9e534a918f1f9aa790aa69 ] The DisplayPort connector on Retronix R-Car V4H Sparrow Hawk board is a full-size DisplayPort connector. Fix the copy-paste error and update the DT node name and labels accordingly. No functional change. Fixes: a719915e76f2 ("arm64: dts: renesas: r8a779g3: Add Retronix R-Car V4H Sparrow Hawk board support") Signed-off-by: Marek Vasut Reviewed-by: Niklas Söderlund Reviewed-by: Geert Uytterhoeven Link: https://patch.msgid.link/20251027184604.34550-1-marek.vasut+renesas@mailbox.org Signed-off-by: Geert Uytterhoeven Signed-off-by: Sasha Levin --- arch/arm64/boot/dts/renesas/r8a779g3-sparrow-hawk.dts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm64/boot/dts/renesas/r8a779g3-sparrow-hawk.dts b/arch/arm64/boot/dts/renesas/r8a779g3-sparrow-hawk.dts index 1da8e476b2193..ff07d984cbf29 100644 --- a/arch/arm64/boot/dts/renesas/r8a779g3-sparrow-hawk.dts +++ b/arch/arm64/boot/dts/renesas/r8a779g3-sparrow-hawk.dts @@ -119,13 +119,13 @@ }; /* Page 27 / DSI to Display */ - mini-dp-con { + dp-con { compatible = "dp-connector"; label = "CN6"; type = "full-size"; port { - mini_dp_con_in: endpoint { + dp_con_in: endpoint { remote-endpoint = <&sn65dsi86_out>; }; }; @@ -407,7 +407,7 @@ port@1 { reg = <1>; sn65dsi86_out: endpoint { - remote-endpoint = <&mini_dp_con_in>; + remote-endpoint = <&dp_con_in>; }; }; }; From d41ba8c6f667c76fb9592748d5e0c7224183d6c1 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Wed, 29 Oct 2025 13:20:19 +0100 Subject: [PATCH 0549/2333] cgroup: add cgroup namespace to tree after owner is set [ Upstream commit 768b1565d9d1e1eebf7567f477f7f46c05a98a4d ] Otherwise we trip VFS_WARN_ON_ONC() in __ns_tree_add_raw(). Link: https://patch.msgid.link/20251029-work-namespace-nstree-listns-v4-6-2e6f823ebdc0@kernel.org Fixes: 7c6059398533 ("cgroup: support ns lookup") Tested-by: syzbot@syzkaller.appspotmail.com Reviewed-by: Jeff Layton Signed-off-by: Christian Brauner Signed-off-by: Sasha Levin --- kernel/cgroup/namespace.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/cgroup/namespace.c b/kernel/cgroup/namespace.c index fdbe57578e688..db9617556dd70 100644 --- a/kernel/cgroup/namespace.c +++ b/kernel/cgroup/namespace.c @@ -30,7 +30,6 @@ static struct cgroup_namespace *alloc_cgroup_ns(void) ret = ns_common_init(new_ns); if (ret) return ERR_PTR(ret); - ns_tree_add(new_ns); return no_free_ptr(new_ns); } @@ -86,6 +85,7 @@ struct cgroup_namespace *copy_cgroup_ns(u64 flags, new_ns->ucounts = ucounts; new_ns->root_cset = cset; + ns_tree_add(new_ns); return new_ns; } From 76103ac4b4b9fe3b7e85fc614dc16011ed70f734 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 29 Oct 2025 16:00:28 +0100 Subject: [PATCH 0550/2333] drm/imagination: Fix reference to devm_platform_get_and_ioremap_resource() [ Upstream commit f1aa93005d0d6fb3293ca9c3eb08d1d1557117bf ] The call to devm_platform_ioremap_resource() was replaced by a call to devm_platform_get_and_ioremap_resource(), but the comment referring to the function's possible returned error codes was not updated. Fixes: 927f3e0253c11276 ("drm/imagination: Implement MIPS firmware processor and MMU support") Signed-off-by: Geert Uytterhoeven Reviewed-by: Matt Coster Link: https://patch.msgid.link/2266514318480d17f52c7e5e67578dae6827914e.1761745586.git.geert+renesas@glider.be Signed-off-by: Matt Coster Signed-off-by: Sasha Levin --- drivers/gpu/drm/imagination/pvr_device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/imagination/pvr_device.c b/drivers/gpu/drm/imagination/pvr_device.c index 294b6019b4155..78d6b8a0a4506 100644 --- a/drivers/gpu/drm/imagination/pvr_device.c +++ b/drivers/gpu/drm/imagination/pvr_device.c @@ -48,7 +48,7 @@ * * Return: * * 0 on success, or - * * Any error returned by devm_platform_ioremap_resource(). + * * Any error returned by devm_platform_get_and_ioremap_resource(). */ static int pvr_device_reg_init(struct pvr_device *pvr_dev) From 8d88ab9f20884dfc15b4af7611b7719d31d059a6 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Wed, 29 Oct 2025 21:01:39 -0700 Subject: [PATCH 0551/2333] perf lock contention: Load kernel map before lookup [ Upstream commit 553d18c98a896094b99a01765b9698b204183d49 ] On some machines, it caused troubles when it tried to find kernel symbols. I think it's because kernel modules and kallsyms are messed up during load and split. Basically we want to make sure the kernel map is loaded and the code has it in the lock_contention_read(). But recently we added more lookups in the lock_contention_prepare() which is called before _read(). Also the kernel map (kallsyms) may not be the first one in the group like on ARM. Let's use machine__kernel_map() rather than just loading the first map. Reviewed-by: Ian Rogers Fixes: 688d2e8de231c54e ("perf lock contention: Add -l/--lock-addr option") Signed-off-by: Namhyung Kim Signed-off-by: Sasha Levin --- tools/perf/util/bpf_lock_contention.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/perf/util/bpf_lock_contention.c b/tools/perf/util/bpf_lock_contention.c index 60b81d586323f..7b5671f13c535 100644 --- a/tools/perf/util/bpf_lock_contention.c +++ b/tools/perf/util/bpf_lock_contention.c @@ -184,6 +184,9 @@ int lock_contention_prepare(struct lock_contention *con) struct evlist *evlist = con->evlist; struct target *target = con->target; + /* make sure it loads the kernel map before lookup */ + map__load(machine__kernel_map(con->machine)); + skel = lock_contention_bpf__open(); if (!skel) { pr_err("Failed to open lock-contention BPF skeleton\n"); @@ -749,9 +752,6 @@ int lock_contention_read(struct lock_contention *con) bpf_prog_test_run_opts(prog_fd, &opts); } - /* make sure it loads the kernel map */ - maps__load_first(machine->kmaps); - prev_key = NULL; while (!bpf_map_get_next_key(fd, prev_key, &key)) { s64 ls_key; From d733e1e6ed7196086e13933ffcd2ff9bcf954169 Mon Sep 17 00:00:00 2001 From: Shuai Xue Date: Thu, 23 Oct 2025 09:50:43 +0800 Subject: [PATCH 0552/2333] perf record: skip synthesize event when open evsel failed [ Upstream commit 163e5f2b96632b7fb2eaa965562aca0dbdf9f996 ] When using perf record with the `--overwrite` option, a segmentation fault occurs if an event fails to open. For example: perf record -e cycles-ct -F 1000 -a --overwrite Error: cycles-ct:H: PMU Hardware doesn't support sampling/overflow-interrupts. Try 'perf stat' perf: Segmentation fault #0 0x6466b6 in dump_stack debug.c:366 #1 0x646729 in sighandler_dump_stack debug.c:378 #2 0x453fd1 in sigsegv_handler builtin-record.c:722 #3 0x7f8454e65090 in __restore_rt libc-2.32.so[54090] #4 0x6c5671 in __perf_event__synthesize_id_index synthetic-events.c:1862 #5 0x6c5ac0 in perf_event__synthesize_id_index synthetic-events.c:1943 #6 0x458090 in record__synthesize builtin-record.c:2075 #7 0x45a85a in __cmd_record builtin-record.c:2888 #8 0x45deb6 in cmd_record builtin-record.c:4374 #9 0x4e5e33 in run_builtin perf.c:349 #10 0x4e60bf in handle_internal_command perf.c:401 #11 0x4e6215 in run_argv perf.c:448 #12 0x4e653a in main perf.c:555 #13 0x7f8454e4fa72 in __libc_start_main libc-2.32.so[3ea72] #14 0x43a3ee in _start ??:0 The --overwrite option implies --tail-synthesize, which collects non-sample events reflecting the system status when recording finishes. However, when evsel opening fails (e.g., unsupported event 'cycles-ct'), session->evlist is not initialized and remains NULL. The code unconditionally calls record__synthesize() in the error path, which iterates through the NULL evlist pointer and causes a segfault. To fix it, move the record__synthesize() call inside the error check block, so it's only called when there was no error during recording, ensuring that evlist is properly initialized. Fixes: 4ea648aec019 ("perf record: Add --tail-synthesize option") Signed-off-by: Shuai Xue Signed-off-by: Namhyung Kim Signed-off-by: Sasha Levin --- tools/perf/builtin-record.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index d76f01956e33b..b1fb87016d5aa 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -2883,11 +2883,11 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) rec->bytes_written += off_cpu_write(rec->session); record__read_lost_samples(rec); - record__synthesize(rec, true); /* this will be recalculated during process_buildids() */ rec->samples = 0; if (!err) { + record__synthesize(rec, true); if (!rec->timestamp_filename) { record__finish_output(rec); } else { From d7eaed82c21ea760acb16ded5924896b95cce767 Mon Sep 17 00:00:00 2001 From: Taniya Das Date: Fri, 31 Oct 2025 15:32:25 +0530 Subject: [PATCH 0553/2333] clk: qcom: tcsrcc-glymur: Update register offsets for clock refs [ Upstream commit a4aa1ceb89f5c0d27a55671d88699cf5eae7331b ] Update the register offsets for all the clock ref branches to match the new address mapping in the TCSR subsystem. Fixes: 2c1d6ce4f3da ("clk: qcom: Add TCSR clock driver for Glymur SoC") Signed-off-by: Taniya Das Reviewed-by: Abel Vesa Tested-by: Jagadeesh Kona Link: https://lore.kernel.org/r/20251031-tcsrcc_glymur-v1-1-0efb031f0ac5@oss.qualcomm.com Signed-off-by: Bjorn Andersson Signed-off-by: Sasha Levin --- drivers/clk/qcom/tcsrcc-glymur.c | 54 ++++++++++++++++---------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/drivers/clk/qcom/tcsrcc-glymur.c b/drivers/clk/qcom/tcsrcc-glymur.c index c1f8b6d10b7fd..215bc2ac548da 100644 --- a/drivers/clk/qcom/tcsrcc-glymur.c +++ b/drivers/clk/qcom/tcsrcc-glymur.c @@ -28,10 +28,10 @@ enum { }; static struct clk_branch tcsr_edp_clkref_en = { - .halt_reg = 0x1c, + .halt_reg = 0x60, .halt_check = BRANCH_HALT_DELAY, .clkr = { - .enable_reg = 0x1c, + .enable_reg = 0x60, .enable_mask = BIT(0), .hw.init = &(const struct clk_init_data) { .name = "tcsr_edp_clkref_en", @@ -45,10 +45,10 @@ static struct clk_branch tcsr_edp_clkref_en = { }; static struct clk_branch tcsr_pcie_1_clkref_en = { - .halt_reg = 0x4, + .halt_reg = 0x48, .halt_check = BRANCH_HALT_DELAY, .clkr = { - .enable_reg = 0x4, + .enable_reg = 0x48, .enable_mask = BIT(0), .hw.init = &(const struct clk_init_data) { .name = "tcsr_pcie_1_clkref_en", @@ -62,10 +62,10 @@ static struct clk_branch tcsr_pcie_1_clkref_en = { }; static struct clk_branch tcsr_pcie_2_clkref_en = { - .halt_reg = 0x8, + .halt_reg = 0x4c, .halt_check = BRANCH_HALT_DELAY, .clkr = { - .enable_reg = 0x8, + .enable_reg = 0x4c, .enable_mask = BIT(0), .hw.init = &(const struct clk_init_data) { .name = "tcsr_pcie_2_clkref_en", @@ -79,10 +79,10 @@ static struct clk_branch tcsr_pcie_2_clkref_en = { }; static struct clk_branch tcsr_pcie_3_clkref_en = { - .halt_reg = 0x10, + .halt_reg = 0x54, .halt_check = BRANCH_HALT_DELAY, .clkr = { - .enable_reg = 0x10, + .enable_reg = 0x54, .enable_mask = BIT(0), .hw.init = &(const struct clk_init_data) { .name = "tcsr_pcie_3_clkref_en", @@ -96,10 +96,10 @@ static struct clk_branch tcsr_pcie_3_clkref_en = { }; static struct clk_branch tcsr_pcie_4_clkref_en = { - .halt_reg = 0x14, + .halt_reg = 0x58, .halt_check = BRANCH_HALT_DELAY, .clkr = { - .enable_reg = 0x14, + .enable_reg = 0x58, .enable_mask = BIT(0), .hw.init = &(const struct clk_init_data) { .name = "tcsr_pcie_4_clkref_en", @@ -113,10 +113,10 @@ static struct clk_branch tcsr_pcie_4_clkref_en = { }; static struct clk_branch tcsr_usb2_1_clkref_en = { - .halt_reg = 0x28, + .halt_reg = 0x6c, .halt_check = BRANCH_HALT_DELAY, .clkr = { - .enable_reg = 0x28, + .enable_reg = 0x6c, .enable_mask = BIT(0), .hw.init = &(const struct clk_init_data) { .name = "tcsr_usb2_1_clkref_en", @@ -130,10 +130,10 @@ static struct clk_branch tcsr_usb2_1_clkref_en = { }; static struct clk_branch tcsr_usb2_2_clkref_en = { - .halt_reg = 0x2c, + .halt_reg = 0x70, .halt_check = BRANCH_HALT_DELAY, .clkr = { - .enable_reg = 0x2c, + .enable_reg = 0x70, .enable_mask = BIT(0), .hw.init = &(const struct clk_init_data) { .name = "tcsr_usb2_2_clkref_en", @@ -147,10 +147,10 @@ static struct clk_branch tcsr_usb2_2_clkref_en = { }; static struct clk_branch tcsr_usb2_3_clkref_en = { - .halt_reg = 0x30, + .halt_reg = 0x74, .halt_check = BRANCH_HALT_DELAY, .clkr = { - .enable_reg = 0x30, + .enable_reg = 0x74, .enable_mask = BIT(0), .hw.init = &(const struct clk_init_data) { .name = "tcsr_usb2_3_clkref_en", @@ -164,10 +164,10 @@ static struct clk_branch tcsr_usb2_3_clkref_en = { }; static struct clk_branch tcsr_usb2_4_clkref_en = { - .halt_reg = 0x44, + .halt_reg = 0x88, .halt_check = BRANCH_HALT_DELAY, .clkr = { - .enable_reg = 0x44, + .enable_reg = 0x88, .enable_mask = BIT(0), .hw.init = &(const struct clk_init_data) { .name = "tcsr_usb2_4_clkref_en", @@ -181,10 +181,10 @@ static struct clk_branch tcsr_usb2_4_clkref_en = { }; static struct clk_branch tcsr_usb3_0_clkref_en = { - .halt_reg = 0x20, + .halt_reg = 0x64, .halt_check = BRANCH_HALT_DELAY, .clkr = { - .enable_reg = 0x20, + .enable_reg = 0x64, .enable_mask = BIT(0), .hw.init = &(const struct clk_init_data) { .name = "tcsr_usb3_0_clkref_en", @@ -198,10 +198,10 @@ static struct clk_branch tcsr_usb3_0_clkref_en = { }; static struct clk_branch tcsr_usb3_1_clkref_en = { - .halt_reg = 0x24, + .halt_reg = 0x68, .halt_check = BRANCH_HALT_DELAY, .clkr = { - .enable_reg = 0x24, + .enable_reg = 0x68, .enable_mask = BIT(0), .hw.init = &(const struct clk_init_data) { .name = "tcsr_usb3_1_clkref_en", @@ -215,10 +215,10 @@ static struct clk_branch tcsr_usb3_1_clkref_en = { }; static struct clk_branch tcsr_usb4_1_clkref_en = { - .halt_reg = 0x0, + .halt_reg = 0x44, .halt_check = BRANCH_HALT_DELAY, .clkr = { - .enable_reg = 0x0, + .enable_reg = 0x44, .enable_mask = BIT(0), .hw.init = &(const struct clk_init_data) { .name = "tcsr_usb4_1_clkref_en", @@ -232,10 +232,10 @@ static struct clk_branch tcsr_usb4_1_clkref_en = { }; static struct clk_branch tcsr_usb4_2_clkref_en = { - .halt_reg = 0x18, + .halt_reg = 0x5c, .halt_check = BRANCH_HALT_DELAY, .clkr = { - .enable_reg = 0x18, + .enable_reg = 0x5c, .enable_mask = BIT(0), .hw.init = &(const struct clk_init_data) { .name = "tcsr_usb4_2_clkref_en", @@ -268,7 +268,7 @@ static const struct regmap_config tcsr_cc_glymur_regmap_config = { .reg_bits = 32, .reg_stride = 4, .val_bits = 32, - .max_register = 0x44, + .max_register = 0x94, .fast_io = true, }; From e21665bac15c642c2cd48a283a06de8c51e689fb Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Fri, 24 Oct 2025 15:25:31 +0200 Subject: [PATCH 0554/2333] timers/migration: Convert "while" loops to use "for" [ Upstream commit 6c181b5667eea3e6564d334443536a5974190e15 ] Both the "do while" and "while" loops in tmigr_setup_groups() eventually mimic the behaviour of "for" loops. Simplify accordingly. Signed-off-by: Frederic Weisbecker Signed-off-by: Thomas Gleixner Link: https://patch.msgid.link/20251024132536.39841-2-frederic@kernel.org Stable-dep-of: 5eb579dfd46b ("timers/migration: Fix imbalanced NUMA trees") Signed-off-by: Sasha Levin --- kernel/time/timer_migration.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/kernel/time/timer_migration.c b/kernel/time/timer_migration.c index c0c54dc5314c3..1e371f1fdc86c 100644 --- a/kernel/time/timer_migration.c +++ b/kernel/time/timer_migration.c @@ -1642,22 +1642,23 @@ static void tmigr_connect_child_parent(struct tmigr_group *child, static int tmigr_setup_groups(unsigned int cpu, unsigned int node) { struct tmigr_group *group, *child, **stack; - int top = 0, err = 0, i = 0; + int i, top = 0, err = 0; struct list_head *lvllist; stack = kcalloc(tmigr_hierarchy_levels, sizeof(*stack), GFP_KERNEL); if (!stack) return -ENOMEM; - do { + for (i = 0; i < tmigr_hierarchy_levels; i++) { group = tmigr_get_group(cpu, node, i); if (IS_ERR(group)) { err = PTR_ERR(group); + i--; break; } top = i; - stack[i++] = group; + stack[i] = group; /* * When booting only less CPUs of a system than CPUs are @@ -1667,16 +1668,18 @@ static int tmigr_setup_groups(unsigned int cpu, unsigned int node) * be different from tmigr_hierarchy_levels, contains only a * single group. */ - if (group->parent || list_is_singular(&tmigr_level_list[i - 1])) + if (group->parent || list_is_singular(&tmigr_level_list[i])) break; + } - } while (i < tmigr_hierarchy_levels); - - /* Assert single root */ - WARN_ON_ONCE(!err && !group->parent && !list_is_singular(&tmigr_level_list[top])); + /* Assert single root without parent */ + if (WARN_ON_ONCE(i >= tmigr_hierarchy_levels)) + return -EINVAL; + if (WARN_ON_ONCE(!err && !group->parent && !list_is_singular(&tmigr_level_list[top]))) + return -EINVAL; - while (i > 0) { - group = stack[--i]; + for (; i >= 0; i--) { + group = stack[i]; if (err < 0) { list_del(&group->list); From cc25b81fe0eadde8d24431f810dbb64f5be981ae Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Fri, 24 Oct 2025 15:25:32 +0200 Subject: [PATCH 0555/2333] timers/migration: Remove locking on group connection [ Upstream commit fa9620355d4192200f15cb3d97c6eb9c02442249 ] Initializing the tmc's group, the group's number of children and the group's parent can all be done without locking because: 1) Reading the group's parent and its group mask is done locklessly. 2) The connections prepared for a given CPU hierarchy are visible to the target CPU once online, thanks to the CPU hotplug enforced memory ordering. 3) In case of a newly created upper level, the new root and its connections and initialization are made visible by the CPU which made the connections. When that CPUs goes idle in the future, the new link is published by tmigr_inactive_up() through the atomic RmW on ->migr_state. 4) If CPUs were still walking up the active hierarchy, they could observe the new root earlier. In this case the ordering is enforced by an early initialization of the group mask and by barriers that maintain address dependency as explained in: b729cc1ec21a ("timers/migration: Fix another race between hotplug and idle entry/exit") de3ced72a792 ("timers/migration: Enforce group initialization visibility to tree walkers") 5) Timers are propagated by a chain of group locking from the bottom to the top. And while doing so, the tree also propagates groups links and initialization. Therefore remote expiration, which also relies on group locking, will observe those links and initialization while holding the root lock before walking the tree remotely and update remote timers. This is especially important for migrators in the active hierarchy that may observe the new root early. Therefore the locking is unnecessary at initialization. If anything, it just brings confusion. Remove it. Signed-off-by: Frederic Weisbecker Signed-off-by: Thomas Gleixner Link: https://patch.msgid.link/20251024132536.39841-3-frederic@kernel.org Stable-dep-of: 5eb579dfd46b ("timers/migration: Fix imbalanced NUMA trees") Signed-off-by: Sasha Levin --- kernel/time/timer_migration.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/kernel/time/timer_migration.c b/kernel/time/timer_migration.c index 1e371f1fdc86c..5f8aef94ca0f7 100644 --- a/kernel/time/timer_migration.c +++ b/kernel/time/timer_migration.c @@ -1573,9 +1573,6 @@ static void tmigr_connect_child_parent(struct tmigr_group *child, { struct tmigr_walk data; - raw_spin_lock_irq(&child->lock); - raw_spin_lock_nested(&parent->lock, SINGLE_DEPTH_NESTING); - if (activate) { /* * @child is the old top and @parent the new one. In this @@ -1596,9 +1593,6 @@ static void tmigr_connect_child_parent(struct tmigr_group *child, */ smp_store_release(&child->parent, parent); - raw_spin_unlock(&parent->lock); - raw_spin_unlock_irq(&child->lock); - trace_tmigr_connect_child_parent(child); if (!activate) @@ -1695,13 +1689,9 @@ static int tmigr_setup_groups(unsigned int cpu, unsigned int node) if (i == 0) { struct tmigr_cpu *tmc = per_cpu_ptr(&tmigr_cpu, cpu); - raw_spin_lock_irq(&group->lock); - tmc->tmgroup = group; tmc->groupmask = BIT(group->num_children++); - raw_spin_unlock_irq(&group->lock); - trace_tmigr_connect_cpu_parent(tmc); /* There are no children that need to be connected */ From d4b3a4c2aa7b042e61303f1342ba7113783dbd09 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Fri, 24 Oct 2025 15:25:33 +0200 Subject: [PATCH 0556/2333] timers/migration: Fix imbalanced NUMA trees [ Upstream commit 5eb579dfd46b4949117ecb0f1ba2f12d3dc9a6f2 ] When a CPU from a new node boots, the old root may happen to be connected to the new root even if their node mismatch, as depicted in the following scenario: 1) CPU 0 boots and creates the first group for node 0. [GRP0:0] node 0 | CPU 0 2) CPU 1 from node 1 boots and creates a new top that corresponds to node 1, but it also connects the old root from node 0 to the new root from node 1 by mistake. [GRP1:0] node 1 / \ / \ [GRP0:0] [GRP0:1] node 0 node 1 | | CPU 0 CPU 1 3) This eventually leads to an imbalanced tree where some node 0 CPUs migrate node 1 timers (and vice versa) way before reaching the crossnode groups, resulting in more frequent remote memory accesses than expected. [GRP2:0] NUMA_NO_NODE / \ [GRP1:0] [GRP1:1] node 1 node 0 / \ | / \ [...] [GRP0:0] [GRP0:1] node 0 node 1 | | CPU 0... CPU 1... A balanced tree should only contain groups having children that belong to the same node: [GRP2:0] NUMA_NO_NODE / \ [GRP1:0] [GRP1:0] node 0 node 1 / \ / \ / \ / \ [GRP0:0] [...] [...] [GRP0:1] node 0 node 1 | | CPU 0... CPU 1... In order to fix this, the hierarchy must be unfolded up to the crossnode level as soon as a node mismatch is detected. For example the stage 2 above should lead to this layout: [GRP2:0] NUMA_NO_NODE / \ [GRP1:0] [GRP1:1] node 0 node 1 / \ / \ [GRP0:0] [GRP0:1] node 0 node 1 | | CPU 0 CPU 1 This means that not only GRP1:0 must be created but also GRP1:1 and GRP2:0 in order to prepare a balanced tree for next CPUs to boot. Fixes: 7ee988770326 ("timers: Implement the hierarchical pull model") Signed-off-by: Frederic Weisbecker Signed-off-by: Thomas Gleixner Link: https://patch.msgid.link/20251024132536.39841-4-frederic@kernel.org Signed-off-by: Sasha Levin --- kernel/time/timer_migration.c | 231 +++++++++++++++++++--------------- 1 file changed, 127 insertions(+), 104 deletions(-) diff --git a/kernel/time/timer_migration.c b/kernel/time/timer_migration.c index 5f8aef94ca0f7..49635a2b7ee28 100644 --- a/kernel/time/timer_migration.c +++ b/kernel/time/timer_migration.c @@ -420,6 +420,8 @@ static struct list_head *tmigr_level_list __read_mostly; static unsigned int tmigr_hierarchy_levels __read_mostly; static unsigned int tmigr_crossnode_level __read_mostly; +static struct tmigr_group *tmigr_root; + static DEFINE_PER_CPU(struct tmigr_cpu, tmigr_cpu); #define TMIGR_NONE 0xFF @@ -522,11 +524,9 @@ struct tmigr_walk { typedef bool (*up_f)(struct tmigr_group *, struct tmigr_group *, struct tmigr_walk *); -static void __walk_groups(up_f up, struct tmigr_walk *data, - struct tmigr_cpu *tmc) +static void __walk_groups_from(up_f up, struct tmigr_walk *data, + struct tmigr_group *child, struct tmigr_group *group) { - struct tmigr_group *child = NULL, *group = tmc->tmgroup; - do { WARN_ON_ONCE(group->level >= tmigr_hierarchy_levels); @@ -544,6 +544,12 @@ static void __walk_groups(up_f up, struct tmigr_walk *data, } while (group); } +static void __walk_groups(up_f up, struct tmigr_walk *data, + struct tmigr_cpu *tmc) +{ + __walk_groups_from(up, data, NULL, tmc->tmgroup); +} + static void walk_groups(up_f up, struct tmigr_walk *data, struct tmigr_cpu *tmc) { lockdep_assert_held(&tmc->lock); @@ -1498,21 +1504,6 @@ static void tmigr_init_group(struct tmigr_group *group, unsigned int lvl, s.seq = 0; atomic_set(&group->migr_state, s.state); - /* - * If this is a new top-level, prepare its groupmask in advance. - * This avoids accidents where yet another new top-level is - * created in the future and made visible before the current groupmask. - */ - if (list_empty(&tmigr_level_list[lvl])) { - group->groupmask = BIT(0); - /* - * The previous top level has prepared its groupmask already, - * simply account it as the first child. - */ - if (lvl > 0) - group->num_children = 1; - } - timerqueue_init_head(&group->events); timerqueue_init(&group->groupevt.nextevt); group->groupevt.nextevt.expires = KTIME_MAX; @@ -1567,22 +1558,51 @@ static struct tmigr_group *tmigr_get_group(unsigned int cpu, int node, return group; } +static bool tmigr_init_root(struct tmigr_group *group, bool activate) +{ + if (!group->parent && group != tmigr_root) { + /* + * This is the new top-level, prepare its groupmask in advance + * to avoid accidents where yet another new top-level is + * created in the future and made visible before this groupmask. + */ + group->groupmask = BIT(0); + WARN_ON_ONCE(activate); + + return true; + } + + return false; + +} + static void tmigr_connect_child_parent(struct tmigr_group *child, struct tmigr_group *parent, bool activate) { - struct tmigr_walk data; + if (tmigr_init_root(parent, activate)) { + /* + * The previous top level had prepared its groupmask already, + * simply account it in advance as the first child. If some groups + * have been created between the old and new root due to node + * mismatch, the new root's child will be intialized accordingly. + */ + parent->num_children = 1; + } - if (activate) { + /* Connecting old root to new root ? */ + if (!parent->parent && activate) { /* - * @child is the old top and @parent the new one. In this - * case groupmask is pre-initialized and @child already - * accounted, along with its new sibling corresponding to the - * CPU going up. + * @child is the old top, or in case of node mismatch, some + * intermediate group between the old top and the new one in + * @parent. In this case the @child must be pre-accounted above + * as the first child. Its new inactive sibling corresponding + * to the CPU going up has been accounted as the second child. */ - WARN_ON_ONCE(child->groupmask != BIT(0) || parent->num_children != 2); + WARN_ON_ONCE(parent->num_children != 2); + child->groupmask = BIT(0); } else { - /* Adding @child for the CPU going up to @parent. */ + /* Common case adding @child for the CPU going up to @parent. */ child->groupmask = BIT(parent->num_children++); } @@ -1594,56 +1614,28 @@ static void tmigr_connect_child_parent(struct tmigr_group *child, smp_store_release(&child->parent, parent); trace_tmigr_connect_child_parent(child); - - if (!activate) - return; - - /* - * To prevent inconsistent states, active children need to be active in - * the new parent as well. Inactive children are already marked inactive - * in the parent group: - * - * * When new groups were created by tmigr_setup_groups() starting from - * the lowest level (and not higher then one level below the current - * top level), then they are not active. They will be set active when - * the new online CPU comes active. - * - * * But if a new group above the current top level is required, it is - * mandatory to propagate the active state of the already existing - * child to the new parent. So tmigr_connect_child_parent() is - * executed with the formerly top level group (child) and the newly - * created group (parent). - * - * * It is ensured that the child is active, as this setup path is - * executed in hotplug prepare callback. This is exectued by an - * already connected and !idle CPU. Even if all other CPUs go idle, - * the CPU executing the setup will be responsible up to current top - * level group. And the next time it goes inactive, it will release - * the new childmask and parent to subsequent walkers through this - * @child. Therefore propagate active state unconditionally. - */ - data.childmask = child->groupmask; - - /* - * There is only one new level per time (which is protected by - * tmigr_mutex). When connecting the child and the parent and set the - * child active when the parent is inactive, the parent needs to be the - * uppermost level. Otherwise there went something wrong! - */ - WARN_ON(!tmigr_active_up(parent, child, &data) && parent->parent); } -static int tmigr_setup_groups(unsigned int cpu, unsigned int node) +static int tmigr_setup_groups(unsigned int cpu, unsigned int node, + struct tmigr_group *start, bool activate) { struct tmigr_group *group, *child, **stack; - int i, top = 0, err = 0; - struct list_head *lvllist; + int i, top = 0, err = 0, start_lvl = 0; + bool root_mismatch = false; stack = kcalloc(tmigr_hierarchy_levels, sizeof(*stack), GFP_KERNEL); if (!stack) return -ENOMEM; - for (i = 0; i < tmigr_hierarchy_levels; i++) { + if (start) { + stack[start->level] = start; + start_lvl = start->level + 1; + } + + if (tmigr_root) + root_mismatch = tmigr_root->numa_node != node; + + for (i = start_lvl; i < tmigr_hierarchy_levels; i++) { group = tmigr_get_group(cpu, node, i); if (IS_ERR(group)) { err = PTR_ERR(group); @@ -1656,23 +1648,25 @@ static int tmigr_setup_groups(unsigned int cpu, unsigned int node) /* * When booting only less CPUs of a system than CPUs are - * available, not all calculated hierarchy levels are required. + * available, not all calculated hierarchy levels are required, + * unless a node mismatch is detected. * * The loop is aborted as soon as the highest level, which might * be different from tmigr_hierarchy_levels, contains only a - * single group. + * single group, unless the nodes mismatch below tmigr_crossnode_level */ - if (group->parent || list_is_singular(&tmigr_level_list[i])) + if (group->parent) + break; + if ((!root_mismatch || i >= tmigr_crossnode_level) && + list_is_singular(&tmigr_level_list[i])) break; } /* Assert single root without parent */ if (WARN_ON_ONCE(i >= tmigr_hierarchy_levels)) return -EINVAL; - if (WARN_ON_ONCE(!err && !group->parent && !list_is_singular(&tmigr_level_list[top]))) - return -EINVAL; - for (; i >= 0; i--) { + for (; i >= start_lvl; i--) { group = stack[i]; if (err < 0) { @@ -1692,48 +1686,63 @@ static int tmigr_setup_groups(unsigned int cpu, unsigned int node) tmc->tmgroup = group; tmc->groupmask = BIT(group->num_children++); + tmigr_init_root(group, activate); + trace_tmigr_connect_cpu_parent(tmc); /* There are no children that need to be connected */ continue; } else { child = stack[i - 1]; - /* Will be activated at online time */ - tmigr_connect_child_parent(child, group, false); + tmigr_connect_child_parent(child, group, activate); } + } - /* check if uppermost level was newly created */ - if (top != i) - continue; - - WARN_ON_ONCE(top == 0); + if (err < 0) + goto out; - lvllist = &tmigr_level_list[top]; + if (activate) { + struct tmigr_walk data; /* - * Newly created root level should have accounted the upcoming - * CPU's child group and pre-accounted the old root. + * To prevent inconsistent states, active children need to be active in + * the new parent as well. Inactive children are already marked inactive + * in the parent group: + * + * * When new groups were created by tmigr_setup_groups() starting from + * the lowest level, then they are not active. They will be set active + * when the new online CPU comes active. + * + * * But if new groups above the current top level are required, it is + * mandatory to propagate the active state of the already existing + * child to the new parents. So tmigr_active_up() activates the + * new parents while walking up from the old root to the new. + * + * * It is ensured that @start is active, as this setup path is + * executed in hotplug prepare callback. This is executed by an + * already connected and !idle CPU. Even if all other CPUs go idle, + * the CPU executing the setup will be responsible up to current top + * level group. And the next time it goes inactive, it will release + * the new childmask and parent to subsequent walkers through this + * @child. Therefore propagate active state unconditionally. */ - if (group->num_children == 2 && list_is_singular(lvllist)) { - /* - * The target CPU must never do the prepare work, except - * on early boot when the boot CPU is the target. Otherwise - * it may spuriously activate the old top level group inside - * the new one (nevertheless whether old top level group is - * active or not) and/or release an uninitialized childmask. - */ - WARN_ON_ONCE(cpu == raw_smp_processor_id()); - - lvllist = &tmigr_level_list[top - 1]; - list_for_each_entry(child, lvllist, list) { - if (child->parent) - continue; + WARN_ON_ONCE(!start->parent); + data.childmask = start->groupmask; + __walk_groups_from(tmigr_active_up, &data, start, start->parent); + } - tmigr_connect_child_parent(child, group, true); - } + /* Root update */ + if (list_is_singular(&tmigr_level_list[top])) { + group = list_first_entry(&tmigr_level_list[top], + typeof(*group), list); + WARN_ON_ONCE(group->parent); + if (tmigr_root) { + /* Old root should be the same or below */ + WARN_ON_ONCE(tmigr_root->level > top); } + tmigr_root = group; } - +out: kfree(stack); return err; @@ -1741,12 +1750,26 @@ static int tmigr_setup_groups(unsigned int cpu, unsigned int node) static int tmigr_add_cpu(unsigned int cpu) { + struct tmigr_group *old_root = tmigr_root; int node = cpu_to_node(cpu); int ret; - mutex_lock(&tmigr_mutex); - ret = tmigr_setup_groups(cpu, node); - mutex_unlock(&tmigr_mutex); + guard(mutex)(&tmigr_mutex); + + ret = tmigr_setup_groups(cpu, node, NULL, false); + + /* Root has changed? Connect the old one to the new */ + if (ret >= 0 && old_root && old_root != tmigr_root) { + /* + * The target CPU must never do the prepare work, except + * on early boot when the boot CPU is the target. Otherwise + * it may spuriously activate the old top level group inside + * the new one (nevertheless whether old top level group is + * active or not) and/or release an uninitialized childmask. + */ + WARN_ON_ONCE(cpu == raw_smp_processor_id()); + ret = tmigr_setup_groups(-1, old_root->numa_node, old_root, true); + } return ret; } From 8c473255e5ee235e91bc5a41bbf60431a16a2db6 Mon Sep 17 00:00:00 2001 From: Haotian Zhang Date: Mon, 29 Sep 2025 19:32:34 +0800 Subject: [PATCH 0557/2333] power: supply: rt5033_charger: Fix device node reference leaks [ Upstream commit 6cdc4d488c2f3a61174bfba4e8cc4ac92c219258 ] The device node pointers `np_conn` and `np_edev`, obtained from of_parse_phandle() and of_get_parent() respectively, are not released. This results in a reference count leak. Add of_node_put() calls after the last use of these device nodes to properly release their references and fix the leaks. Fixes: 8242336dc8a8 ("power: supply: rt5033_charger: Add cable detection and USB OTG supply") Signed-off-by: Haotian Zhang Link: https://patch.msgid.link/20250929113234.1726-1-vulab@iscas.ac.cn Signed-off-by: Sebastian Reichel Signed-off-by: Sasha Levin --- drivers/power/supply/rt5033_charger.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/power/supply/rt5033_charger.c b/drivers/power/supply/rt5033_charger.c index 2fdc584397075..de724f23e453b 100644 --- a/drivers/power/supply/rt5033_charger.c +++ b/drivers/power/supply/rt5033_charger.c @@ -701,6 +701,8 @@ static int rt5033_charger_probe(struct platform_device *pdev) np_conn = of_parse_phandle(pdev->dev.of_node, "richtek,usb-connector", 0); np_edev = of_get_parent(np_conn); charger->edev = extcon_find_edev_by_node(np_edev); + of_node_put(np_edev); + of_node_put(np_conn); if (IS_ERR(charger->edev)) { dev_warn(charger->dev, "no extcon device found in device-tree\n"); goto out; From 97ec116a7e57439081fa7567c618b39d833a7625 Mon Sep 17 00:00:00 2001 From: Ivan Abramov Date: Wed, 8 Oct 2025 15:07:11 +0300 Subject: [PATCH 0558/2333] power: supply: cw2015: Check devm_delayed_work_autocancel() return code [ Upstream commit 92ec7e7b86ec0aff9cd7db64d9dce50a0ea7c542 ] Since devm_delayed_work_autocancel() may fail, add return code check and exit cw_bat_probe() on error. Found by Linux Verification Center (linuxtesting.org) with SVACE. Fixes: 0cb172a4918e ("power: supply: cw2015: Use device managed API to simplify the code") Signed-off-by: Ivan Abramov Link: https://patch.msgid.link/20251008120711.556021-1-i.abramov@mt-integration.ru Signed-off-by: Sebastian Reichel Signed-off-by: Sasha Levin --- drivers/power/supply/cw2015_battery.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/power/supply/cw2015_battery.c b/drivers/power/supply/cw2015_battery.c index 2263d5d3448fd..0806abea2372f 100644 --- a/drivers/power/supply/cw2015_battery.c +++ b/drivers/power/supply/cw2015_battery.c @@ -699,7 +699,13 @@ static int cw_bat_probe(struct i2c_client *client) if (!cw_bat->battery_workqueue) return -ENOMEM; - devm_delayed_work_autocancel(&client->dev, &cw_bat->battery_delay_work, cw_bat_work); + ret = devm_delayed_work_autocancel(&client->dev, &cw_bat->battery_delay_work, cw_bat_work); + if (ret) { + dev_err_probe(&client->dev, ret, + "Failed to register delayed work\n"); + return ret; + } + queue_delayed_work(cw_bat->battery_workqueue, &cw_bat->battery_delay_work, msecs_to_jiffies(10)); return 0; From 1cea1ca5e8d4a6e03eda1bb2747c850103a8cd57 Mon Sep 17 00:00:00 2001 From: Ivan Abramov Date: Wed, 8 Oct 2025 16:36:47 +0300 Subject: [PATCH 0559/2333] power: supply: max17040: Check iio_read_channel_processed() return code [ Upstream commit 2c68ac48c52ad146523f32b01d70009622bf81aa ] Since iio_read_channel_processed() may fail, return its exit code on error. Found by Linux Verification Center (linuxtesting.org) with SVACE. Fixes: 814755c48f8b ("power: max17040: get thermal data from adc if available") Signed-off-by: Ivan Abramov Link: https://patch.msgid.link/20251008133648.559286-1-i.abramov@mt-integration.ru Signed-off-by: Sebastian Reichel Signed-off-by: Sasha Levin --- drivers/power/supply/max17040_battery.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/power/supply/max17040_battery.c b/drivers/power/supply/max17040_battery.c index c1640bc6accd2..48453508688a4 100644 --- a/drivers/power/supply/max17040_battery.c +++ b/drivers/power/supply/max17040_battery.c @@ -388,6 +388,7 @@ static int max17040_get_property(struct power_supply *psy, union power_supply_propval *val) { struct max17040_chip *chip = power_supply_get_drvdata(psy); + int ret; switch (psp) { case POWER_SUPPLY_PROP_ONLINE: @@ -410,7 +411,10 @@ static int max17040_get_property(struct power_supply *psy, if (!chip->channel_temp) return -ENODATA; - iio_read_channel_processed(chip->channel_temp, &val->intval); + ret = iio_read_channel_processed(chip->channel_temp, &val->intval); + if (ret) + return ret; + val->intval /= 100; /* Convert from milli- to deci-degree */ break; From 52d3f2076122ad2d0ea11b32e3f45ae05df4180e Mon Sep 17 00:00:00 2001 From: Ivan Abramov Date: Thu, 9 Oct 2025 17:47:24 +0300 Subject: [PATCH 0560/2333] power: supply: rt9467: Return error on failure in rt9467_set_value_from_ranges() [ Upstream commit 8b27fe2d8d2380118c343629175385ff587e2fe4 ] The return value of rt9467_set_value_from_ranges() when setting AICL VTH is not checked, even though it may fail. Log error and return from rt9467_run_aicl() on fail. Found by Linux Verification Center (linuxtesting.org) with SVACE. Fixes: 6f7f70e3a8dd ("power: supply: rt9467: Add Richtek RT9467 charger driver") Signed-off-by: Ivan Abramov Link: https://patch.msgid.link/20251009144725.562278-1-i.abramov@mt-integration.ru Signed-off-by: Sebastian Reichel Signed-off-by: Sasha Levin --- drivers/power/supply/rt9467-charger.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/power/supply/rt9467-charger.c b/drivers/power/supply/rt9467-charger.c index fe773dd8b404f..b4917514bd701 100644 --- a/drivers/power/supply/rt9467-charger.c +++ b/drivers/power/supply/rt9467-charger.c @@ -588,6 +588,10 @@ static int rt9467_run_aicl(struct rt9467_chg_data *data) aicl_vth = mivr_vth + RT9467_AICLVTH_GAP_uV; ret = rt9467_set_value_from_ranges(data, F_AICL_VTH, RT9467_RANGE_AICL_VTH, aicl_vth); + if (ret) { + dev_err(data->dev, "Failed to set AICL VTH\n"); + return ret; + } /* Trigger AICL function */ ret = regmap_field_write(data->rm_field[F_AICL_MEAS], 1); From a77929363637c5625ee58d5eafa3736cb69126b5 Mon Sep 17 00:00:00 2001 From: Murad Masimov Date: Thu, 9 Oct 2025 17:53:08 +0300 Subject: [PATCH 0561/2333] power: supply: rt9467: Prevent using uninitialized local variable in rt9467_set_value_from_ranges() [ Upstream commit 15aca30cc6c69806054b896a2ccf7577239cb878 ] There is a typo in rt9467_set_value_from_ranges() that can cause leaving local variable sel with an undefined value which is then used in regmap_field_write(). Found by Linux Verification Center (linuxtesting.org) with SVACE. Fixes: 6f7f70e3a8dd ("power: supply: rt9467: Add Richtek RT9467 charger driver") Signed-off-by: Murad Masimov Link: https://patch.msgid.link/20251009145308.1830893-1-m.masimov@mt-integration.ru Signed-off-by: Sebastian Reichel Signed-off-by: Sasha Levin --- drivers/power/supply/rt9467-charger.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/power/supply/rt9467-charger.c b/drivers/power/supply/rt9467-charger.c index b4917514bd701..44c26fb37a775 100644 --- a/drivers/power/supply/rt9467-charger.c +++ b/drivers/power/supply/rt9467-charger.c @@ -376,7 +376,7 @@ static int rt9467_set_value_from_ranges(struct rt9467_chg_data *data, if (rsel == RT9467_RANGE_VMIVR) { ret = linear_range_get_selector_high(range, value, &sel, &found); if (ret) - value = range->max_sel; + sel = range->max_sel; } else { linear_range_get_selector_within(range, value, &sel); } From eade8ea73b91a2fc03c0dfb89ec3c829938fffce Mon Sep 17 00:00:00 2001 From: Ivan Abramov Date: Thu, 9 Oct 2025 20:05:52 +0300 Subject: [PATCH 0562/2333] power: supply: wm831x: Check wm831x_set_bits() return value [ Upstream commit ea14bae6df18942bccb467fcf5ff33ca677b8253 ] Since wm831x_set_bits() may return error, log failure and exit from wm831x_usb_limit_change() in such case. Found by Linux Verification Center (linuxtesting.org) with SVACE. Fixes: 626b6cd5f52e ("power: wm831x_power: Support USB charger current limit management") Signed-off-by: Ivan Abramov Link: https://patch.msgid.link/20251009170553.566561-1-i.abramov@mt-integration.ru Signed-off-by: Sebastian Reichel Signed-off-by: Sasha Levin --- drivers/power/supply/wm831x_power.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/power/supply/wm831x_power.c b/drivers/power/supply/wm831x_power.c index 6acdba7885ca5..78fa0573ef25c 100644 --- a/drivers/power/supply/wm831x_power.c +++ b/drivers/power/supply/wm831x_power.c @@ -144,6 +144,7 @@ static int wm831x_usb_limit_change(struct notifier_block *nb, struct wm831x_power, usb_notify); unsigned int i, best; + int ret; /* Find the highest supported limit */ best = 0; @@ -156,8 +157,13 @@ static int wm831x_usb_limit_change(struct notifier_block *nb, dev_dbg(wm831x_power->wm831x->dev, "Limiting USB current to %umA", wm831x_usb_limits[best]); - wm831x_set_bits(wm831x_power->wm831x, WM831X_POWER_STATE, - WM831X_USB_ILIM_MASK, best); + ret = wm831x_set_bits(wm831x_power->wm831x, WM831X_POWER_STATE, + WM831X_USB_ILIM_MASK, best); + if (ret < 0) { + dev_err(wm831x_power->wm831x->dev, + "Failed to set USB current limit: %d\n", ret); + return ret; + } return 0; } From 2614ebcf2bca48e5f2b4ca1835870db4d1e65a0b Mon Sep 17 00:00:00 2001 From: Val Packett Date: Sun, 12 Oct 2025 20:32:18 -0300 Subject: [PATCH 0563/2333] power: supply: qcom_battmgr: clamp charge control thresholds [ Upstream commit 8809980fdc8a86070667032fa4005ee83f1c62f3 ] The sysfs API documentation says that drivers "round written values to the nearest supported value" for charge_control_end_threshold. Let's do this for both thresholds, as userspace (e.g. upower) generally does not expect these writes to fail at all. Fixes: cc3e883a0625 ("power: supply: qcom_battmgr: Add charge control support") Signed-off-by: Val Packett Link: https://patch.msgid.link/20251012233333.19144-3-val@packett.cool Signed-off-by: Sebastian Reichel Signed-off-by: Sasha Levin --- drivers/power/supply/qcom_battmgr.c | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/drivers/power/supply/qcom_battmgr.c b/drivers/power/supply/qcom_battmgr.c index 3c2837ef34617..c8028606bba00 100644 --- a/drivers/power/supply/qcom_battmgr.c +++ b/drivers/power/supply/qcom_battmgr.c @@ -678,12 +678,7 @@ static int qcom_battmgr_set_charge_start_threshold(struct qcom_battmgr *battmgr, u32 target_soc, delta_soc; int ret; - if (start_soc < CHARGE_CTRL_START_THR_MIN || - start_soc > CHARGE_CTRL_START_THR_MAX) { - dev_err(battmgr->dev, "charge control start threshold exceed range: [%u - %u]\n", - CHARGE_CTRL_START_THR_MIN, CHARGE_CTRL_START_THR_MAX); - return -EINVAL; - } + start_soc = clamp(start_soc, CHARGE_CTRL_START_THR_MIN, CHARGE_CTRL_START_THR_MAX); /* * If the new start threshold is larger than the old end threshold, @@ -716,12 +711,7 @@ static int qcom_battmgr_set_charge_end_threshold(struct qcom_battmgr *battmgr, i u32 delta_soc = CHARGE_CTRL_DELTA_SOC; int ret; - if (end_soc < CHARGE_CTRL_END_THR_MIN || - end_soc > CHARGE_CTRL_END_THR_MAX) { - dev_err(battmgr->dev, "charge control end threshold exceed range: [%u - %u]\n", - CHARGE_CTRL_END_THR_MIN, CHARGE_CTRL_END_THR_MAX); - return -EINVAL; - } + end_soc = clamp(end_soc, CHARGE_CTRL_END_THR_MIN, CHARGE_CTRL_END_THR_MAX); if (battmgr->info.charge_ctrl_start && end_soc > battmgr->info.charge_ctrl_start) delta_soc = end_soc - battmgr->info.charge_ctrl_start; From 69675b2d60416cbcc8de89e350124d0d33f8cae7 Mon Sep 17 00:00:00 2001 From: Val Packett Date: Sun, 12 Oct 2025 20:32:19 -0300 Subject: [PATCH 0564/2333] power: supply: qcom_battmgr: support disabling charge control [ Upstream commit 446fcf494691da4e685923e5fad02b163955fc0e ] Existing userspace (in particular, upower) disables charge control by setting the start threshold to 0 and the stop threshold to 100. Handle that by actually setting the enable bit to 0 when a start threshold of 0 was requested. Fixes: cc3e883a0625 ("power: supply: qcom_battmgr: Add charge control support") Signed-off-by: Val Packett Link: https://patch.msgid.link/20251012233333.19144-4-val@packett.cool Signed-off-by: Sebastian Reichel Signed-off-by: Sasha Levin --- drivers/power/supply/qcom_battmgr.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/power/supply/qcom_battmgr.c b/drivers/power/supply/qcom_battmgr.c index c8028606bba00..e6f01e0122e1c 100644 --- a/drivers/power/supply/qcom_battmgr.c +++ b/drivers/power/supply/qcom_battmgr.c @@ -257,6 +257,7 @@ struct qcom_battmgr_info { unsigned int capacity_warning; unsigned int cycle_count; unsigned int charge_count; + bool charge_ctrl_enable; unsigned int charge_ctrl_start; unsigned int charge_ctrl_end; char model_number[BATTMGR_STRING_LEN]; @@ -659,13 +660,13 @@ static int qcom_battmgr_bat_get_property(struct power_supply *psy, } static int qcom_battmgr_set_charge_control(struct qcom_battmgr *battmgr, - u32 target_soc, u32 delta_soc) + bool enable, u32 target_soc, u32 delta_soc) { struct qcom_battmgr_charge_ctrl_request request = { .hdr.owner = cpu_to_le32(PMIC_GLINK_OWNER_BATTMGR), .hdr.type = cpu_to_le32(PMIC_GLINK_REQ_RESP), .hdr.opcode = cpu_to_le32(BATTMGR_CHG_CTRL_LIMIT_EN), - .enable = cpu_to_le32(1), + .enable = cpu_to_le32(enable), .target_soc = cpu_to_le32(target_soc), .delta_soc = cpu_to_le32(delta_soc), }; @@ -677,6 +678,7 @@ static int qcom_battmgr_set_charge_start_threshold(struct qcom_battmgr *battmgr, { u32 target_soc, delta_soc; int ret; + bool enable = start_soc != 0; start_soc = clamp(start_soc, CHARGE_CTRL_START_THR_MIN, CHARGE_CTRL_START_THR_MAX); @@ -696,9 +698,10 @@ static int qcom_battmgr_set_charge_start_threshold(struct qcom_battmgr *battmgr, } mutex_lock(&battmgr->lock); - ret = qcom_battmgr_set_charge_control(battmgr, target_soc, delta_soc); + ret = qcom_battmgr_set_charge_control(battmgr, enable, target_soc, delta_soc); mutex_unlock(&battmgr->lock); if (!ret) { + battmgr->info.charge_ctrl_enable = enable; battmgr->info.charge_ctrl_start = start_soc; battmgr->info.charge_ctrl_end = target_soc; } @@ -710,6 +713,7 @@ static int qcom_battmgr_set_charge_end_threshold(struct qcom_battmgr *battmgr, i { u32 delta_soc = CHARGE_CTRL_DELTA_SOC; int ret; + bool enable = battmgr->info.charge_ctrl_enable; end_soc = clamp(end_soc, CHARGE_CTRL_END_THR_MIN, CHARGE_CTRL_END_THR_MAX); @@ -717,7 +721,7 @@ static int qcom_battmgr_set_charge_end_threshold(struct qcom_battmgr *battmgr, i delta_soc = end_soc - battmgr->info.charge_ctrl_start; mutex_lock(&battmgr->lock); - ret = qcom_battmgr_set_charge_control(battmgr, end_soc, delta_soc); + ret = qcom_battmgr_set_charge_control(battmgr, enable, end_soc, delta_soc); mutex_unlock(&battmgr->lock); if (!ret) { battmgr->info.charge_ctrl_start = end_soc - delta_soc; From fb8f2b55a101c3c71440b417e61825ffb614ba71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ahelenia=20Ziemia=C5=84ska?= Date: Fri, 17 Oct 2025 00:05:18 +0200 Subject: [PATCH 0565/2333] power: supply: apm_power: only unset own apm_get_power_status MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit bd44ea12919ac4e83c9f3997240fe58266aa8799 ] Mirroring drivers/macintosh/apm_emu.c, this means that modprobe apm_power && modprobe $anotherdriver && modprobe -r apm_power leaves $anotherdriver's apm_get_power_status instead of deleting it. Fixes: 3788ec932bfd ("[BATTERY] APM emulation driver for class batteries") Signed-off-by: Ahelenia Ziemiańska Link: https://patch.msgid.link/xczpgox57hxbunkcbdl5fxhc4gnsajsipldfidi7355afezk64@tarta.nabijaczleweli.xyz Signed-off-by: Sebastian Reichel Signed-off-by: Sasha Levin --- drivers/power/supply/apm_power.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/power/supply/apm_power.c b/drivers/power/supply/apm_power.c index 9236e00785786..9933cdc5c387a 100644 --- a/drivers/power/supply/apm_power.c +++ b/drivers/power/supply/apm_power.c @@ -364,7 +364,8 @@ static int __init apm_battery_init(void) static void __exit apm_battery_exit(void) { - apm_get_power_status = NULL; + if (apm_get_power_status == apm_battery_apm_get_power_status) + apm_get_power_status = NULL; } module_init(apm_battery_init); From e4a462b4e9961284a4f6e1f427c70f1b3f523d75 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 27 Oct 2025 11:46:38 -0700 Subject: [PATCH 0566/2333] scsi: target: Do not write NUL characters into ASCII configfs output [ Upstream commit c03b55f235e283cae49c88b9602fd11096b92eba ] NUL characters are not allowed in ASCII configfs output. Hence this patch. Fixes: c66ac9db8d4a ("[SCSI] target: Add LIO target core v4.0.0-rc6") Signed-off-by: Bart Van Assche Link: https://patch.msgid.link/20251027184639.3501254-2-bvanassche@acm.org Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin --- drivers/target/target_core_configfs.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index b19acd662726d..1bd28482e7cb3 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c @@ -2772,7 +2772,6 @@ static ssize_t target_lu_gp_members_show(struct config_item *item, char *page) cur_len = snprintf(buf, LU_GROUP_NAME_BUF, "%s/%s\n", config_item_name(&hba->hba_group.cg_item), config_item_name(&dev->dev_group.cg_item)); - cur_len++; /* Extra byte for NULL terminator */ if ((cur_len + len) > PAGE_SIZE || cur_len > LU_GROUP_NAME_BUF) { pr_warn("Ran out of lu_gp_show_attr" From 8d11a6c811a5f58cb13af7b6417177b834df8edc Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Wed, 17 Sep 2025 17:12:53 -0500 Subject: [PATCH 0567/2333] scsi: target: Fix LUN/device R/W and total command stats [ Upstream commit 95aa2041c654161d1b5c1eca5379d67d91ef1cf2 ] In commit 9cf2317b795d ("scsi: target: Move I/O path stats to per CPU") I saw we sometimes use %u and also misread the spec. As a result I thought all the stats were supposed to be 32-bit only. However, for the majority of cases we support currently, the spec specifies u64 bit stats. This patch converts the stats changed in the commit above to u64. Fixes: 9cf2317b795d ("scsi: target: Move I/O path stats to per CPU") Signed-off-by: Mike Christie Reviewed-by: Dmitry Bogdanov Link: https://patch.msgid.link/20250917221338.14813-2-michael.christie@oracle.com Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin --- drivers/target/target_core_stat.c | 24 ++++++++++++------------ include/target/target_core_base.h | 12 ++++++------ 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/drivers/target/target_core_stat.c b/drivers/target/target_core_stat.c index 6bdf2d8bd6942..4fdc307ea38bc 100644 --- a/drivers/target/target_core_stat.c +++ b/drivers/target/target_core_stat.c @@ -282,7 +282,7 @@ static ssize_t target_stat_lu_num_cmds_show(struct config_item *item, struct se_device *dev = to_stat_lu_dev(item); struct se_dev_io_stats *stats; unsigned int cpu; - u32 cmds = 0; + u64 cmds = 0; for_each_possible_cpu(cpu) { stats = per_cpu_ptr(dev->stats, cpu); @@ -290,7 +290,7 @@ static ssize_t target_stat_lu_num_cmds_show(struct config_item *item, } /* scsiLuNumCommands */ - return snprintf(page, PAGE_SIZE, "%u\n", cmds); + return snprintf(page, PAGE_SIZE, "%llu\n", cmds); } static ssize_t target_stat_lu_read_mbytes_show(struct config_item *item, @@ -299,7 +299,7 @@ static ssize_t target_stat_lu_read_mbytes_show(struct config_item *item, struct se_device *dev = to_stat_lu_dev(item); struct se_dev_io_stats *stats; unsigned int cpu; - u32 bytes = 0; + u64 bytes = 0; for_each_possible_cpu(cpu) { stats = per_cpu_ptr(dev->stats, cpu); @@ -307,7 +307,7 @@ static ssize_t target_stat_lu_read_mbytes_show(struct config_item *item, } /* scsiLuReadMegaBytes */ - return snprintf(page, PAGE_SIZE, "%u\n", bytes >> 20); + return snprintf(page, PAGE_SIZE, "%llu\n", bytes >> 20); } static ssize_t target_stat_lu_write_mbytes_show(struct config_item *item, @@ -316,7 +316,7 @@ static ssize_t target_stat_lu_write_mbytes_show(struct config_item *item, struct se_device *dev = to_stat_lu_dev(item); struct se_dev_io_stats *stats; unsigned int cpu; - u32 bytes = 0; + u64 bytes = 0; for_each_possible_cpu(cpu) { stats = per_cpu_ptr(dev->stats, cpu); @@ -324,7 +324,7 @@ static ssize_t target_stat_lu_write_mbytes_show(struct config_item *item, } /* scsiLuWrittenMegaBytes */ - return snprintf(page, PAGE_SIZE, "%u\n", bytes >> 20); + return snprintf(page, PAGE_SIZE, "%llu\n", bytes >> 20); } static ssize_t target_stat_lu_resets_show(struct config_item *item, char *page) @@ -1044,7 +1044,7 @@ static ssize_t target_stat_auth_num_cmds_show(struct config_item *item, struct se_dev_entry *deve; unsigned int cpu; ssize_t ret; - u32 cmds = 0; + u64 cmds = 0; rcu_read_lock(); deve = target_nacl_find_deve(nacl, lacl->mapped_lun); @@ -1059,7 +1059,7 @@ static ssize_t target_stat_auth_num_cmds_show(struct config_item *item, } /* scsiAuthIntrOutCommands */ - ret = snprintf(page, PAGE_SIZE, "%u\n", cmds); + ret = snprintf(page, PAGE_SIZE, "%llu\n", cmds); rcu_read_unlock(); return ret; } @@ -1073,7 +1073,7 @@ static ssize_t target_stat_auth_read_mbytes_show(struct config_item *item, struct se_dev_entry *deve; unsigned int cpu; ssize_t ret; - u32 bytes = 0; + u64 bytes = 0; rcu_read_lock(); deve = target_nacl_find_deve(nacl, lacl->mapped_lun); @@ -1088,7 +1088,7 @@ static ssize_t target_stat_auth_read_mbytes_show(struct config_item *item, } /* scsiAuthIntrReadMegaBytes */ - ret = snprintf(page, PAGE_SIZE, "%u\n", bytes >> 20); + ret = snprintf(page, PAGE_SIZE, "%llu\n", bytes >> 20); rcu_read_unlock(); return ret; } @@ -1102,7 +1102,7 @@ static ssize_t target_stat_auth_write_mbytes_show(struct config_item *item, struct se_dev_entry *deve; unsigned int cpu; ssize_t ret; - u32 bytes = 0; + u64 bytes = 0; rcu_read_lock(); deve = target_nacl_find_deve(nacl, lacl->mapped_lun); @@ -1117,7 +1117,7 @@ static ssize_t target_stat_auth_write_mbytes_show(struct config_item *item, } /* scsiAuthIntrWrittenMegaBytes */ - ret = snprintf(page, PAGE_SIZE, "%u\n", bytes >> 20); + ret = snprintf(page, PAGE_SIZE, "%llu\n", bytes >> 20); rcu_read_unlock(); return ret; } diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index c4d9116904aa0..27e1f9d5f0c6c 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -671,9 +671,9 @@ struct se_lun_acl { }; struct se_dev_entry_io_stats { - u32 total_cmds; - u32 read_bytes; - u32 write_bytes; + u64 total_cmds; + u64 read_bytes; + u64 write_bytes; }; struct se_dev_entry { @@ -806,9 +806,9 @@ struct se_device_queue { }; struct se_dev_io_stats { - u32 total_cmds; - u32 read_bytes; - u32 write_bytes; + u64 total_cmds; + u64 read_bytes; + u64 write_bytes; }; struct se_device { From 1254303ef82c84466a38a81238a81987ebfe00e5 Mon Sep 17 00:00:00 2001 From: Tingmao Wang Date: Sun, 2 Nov 2025 23:56:30 +0000 Subject: [PATCH 0568/2333] fs/9p: Don't open remote file with APPEND mode when writeback cache is used [ Upstream commit a63dd8fd137933551bfd9aeeeaa942f04c7aad65 ] When page cache is used, writebacks are done on a page granularity, and it is expected that the underlying filesystem (such as v9fs) should respect the write position. However, currently v9fs will passthrough O_APPEND to the server even on cached mode. This causes data corruption if a sync or fstat gets between two writes to the same file. This patch removes the APPEND flag from the open request we send to the server when writeback caching is involved. I believe keeping server-side APPEND is probably fine for uncached mode (even if two fds are opened, one without O_APPEND and one with it, this should still be fine since they would use separate fid for the writes). Signed-off-by: Tingmao Wang Fixes: 4eb3117888a9 ("fs/9p: Rework cache modes and add new options to Documentation") Message-ID: <20251102235631.8724-1-m@maowtm.org> Signed-off-by: Dominique Martinet Signed-off-by: Sasha Levin --- fs/9p/vfs_file.c | 11 ++++++++--- fs/9p/vfs_inode.c | 3 +-- fs/9p/vfs_inode_dotl.c | 2 +- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c index eb0b083da269b..d1db03093d4c3 100644 --- a/fs/9p/vfs_file.c +++ b/fs/9p/vfs_file.c @@ -43,14 +43,18 @@ int v9fs_file_open(struct inode *inode, struct file *file) struct v9fs_session_info *v9ses; struct p9_fid *fid; int omode; + int o_append; p9_debug(P9_DEBUG_VFS, "inode: %p file: %p\n", inode, file); v9ses = v9fs_inode2v9ses(inode); - if (v9fs_proto_dotl(v9ses)) + if (v9fs_proto_dotl(v9ses)) { omode = v9fs_open_to_dotl_flags(file->f_flags); - else + o_append = P9_DOTL_APPEND; + } else { omode = v9fs_uflags2omode(file->f_flags, v9fs_proto_dotu(v9ses)); + o_append = P9_OAPPEND; + } fid = file->private_data; if (!fid) { fid = v9fs_fid_clone(file_dentry(file)); @@ -58,9 +62,10 @@ int v9fs_file_open(struct inode *inode, struct file *file) return PTR_ERR(fid); if ((v9ses->cache & CACHE_WRITEBACK) && (omode & P9_OWRITE)) { - int writeback_omode = (omode & ~P9_OWRITE) | P9_ORDWR; + int writeback_omode = (omode & ~(P9_OWRITE | o_append)) | P9_ORDWR; p9_debug(P9_DEBUG_CACHE, "write-only file with writeback enabled, try opening O_RDWR\n"); + err = p9_client_open(fid, writeback_omode); if (err < 0) { p9_debug(P9_DEBUG_CACHE, "could not open O_RDWR, disabling caches\n"); diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index d0c77ec31b1dd..0f3189a0a516a 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c @@ -786,7 +786,7 @@ v9fs_vfs_atomic_open(struct inode *dir, struct dentry *dentry, p9_omode = v9fs_uflags2omode(flags, v9fs_proto_dotu(v9ses)); if ((v9ses->cache & CACHE_WRITEBACK) && (p9_omode & P9_OWRITE)) { - p9_omode = (p9_omode & ~P9_OWRITE) | P9_ORDWR; + p9_omode = (p9_omode & ~(P9_OWRITE | P9_OAPPEND)) | P9_ORDWR; p9_debug(P9_DEBUG_CACHE, "write-only file with writeback enabled, creating w/ O_RDWR\n"); } @@ -1393,4 +1393,3 @@ static const struct inode_operations v9fs_symlink_inode_operations = { .getattr = v9fs_vfs_getattr, .setattr = v9fs_vfs_setattr, }; - diff --git a/fs/9p/vfs_inode_dotl.c b/fs/9p/vfs_inode_dotl.c index be297e3354688..6312b3590f743 100644 --- a/fs/9p/vfs_inode_dotl.c +++ b/fs/9p/vfs_inode_dotl.c @@ -282,7 +282,7 @@ v9fs_vfs_atomic_open_dotl(struct inode *dir, struct dentry *dentry, } if ((v9ses->cache & CACHE_WRITEBACK) && (p9_omode & P9_OWRITE)) { - p9_omode = (p9_omode & ~P9_OWRITE) | P9_ORDWR; + p9_omode = (p9_omode & ~(P9_OWRITE | P9_DOTL_APPEND)) | P9_ORDWR; p9_debug(P9_DEBUG_CACHE, "write-only file with writeback enabled, creating w/ O_RDWR\n"); } From 1292bd488a816a797c839765ce79f8cb2ef28ea0 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Fri, 31 Oct 2025 17:03:17 +0100 Subject: [PATCH 0569/2333] drm/panthor: Handle errors returned by drm_sched_entity_init() [ Upstream commit bb7939e332c64c4ef33974a0eae4f3841acfa8eb ] In practice it's not going to fail because we're passing the current sanity checks done by drm_sched_entity_init(), and that's the only reason it would return an error, but better safe than sorry. Fixes: de8548813824 ("drm/panthor: Add the scheduler logical block") Reviewed-by: Liviu Dudau Signed-off-by: Boris Brezillon Link: https://patch.msgid.link/20251031160318.832427-1-boris.brezillon@collabora.com Signed-off-by: Liviu Dudau Signed-off-by: Sasha Levin --- drivers/gpu/drm/panthor/panthor_sched.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/panthor/panthor_sched.c b/drivers/gpu/drm/panthor/panthor_sched.c index 3d1f57e3990f4..85ef9a7acc147 100644 --- a/drivers/gpu/drm/panthor/panthor_sched.c +++ b/drivers/gpu/drm/panthor/panthor_sched.c @@ -3403,6 +3403,8 @@ group_create_queue(struct panthor_group *group, drm_sched = &queue->scheduler; ret = drm_sched_entity_init(&queue->entity, 0, &drm_sched, 1, NULL); + if (ret) + goto err_free_queue; return queue; From 1ec19ea882841ff9de37d94c7db908af6a3ba325 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Fri, 31 Oct 2025 17:03:18 +0100 Subject: [PATCH 0570/2333] drm/panthor: Fix group_free_queue() for partially initialized queues MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 94a6d20feadbbe24e8a7b1c56394789ea5358fcc ] group_free_queue() can be called on a partially initialized queue object if something fails in group_create_queue(). Make sure we don't call drm_sched_entity_destroy() on an entity that hasn't been initialized. Fixes: 7d9c3442b02a ("drm/panthor: Defer scheduler entitiy destruction to queue release") Reviewed-by: Adrián Larumbe Reviewed-by: Liviu Dudau Signed-off-by: Boris Brezillon Link: https://patch.msgid.link/20251031160318.832427-2-boris.brezillon@collabora.com Signed-off-by: Liviu Dudau Signed-off-by: Sasha Levin --- drivers/gpu/drm/panthor/panthor_sched.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/panthor/panthor_sched.c b/drivers/gpu/drm/panthor/panthor_sched.c index 85ef9a7acc147..a39f0fb370dc6 100644 --- a/drivers/gpu/drm/panthor/panthor_sched.c +++ b/drivers/gpu/drm/panthor/panthor_sched.c @@ -895,7 +895,8 @@ static void group_free_queue(struct panthor_group *group, struct panthor_queue * if (IS_ERR_OR_NULL(queue)) return; - drm_sched_entity_destroy(&queue->entity); + if (queue->entity.fence_context) + drm_sched_entity_destroy(&queue->entity); if (queue->scheduler.ops) drm_sched_fini(&queue->scheduler); From 6c1da9ae2c123a9ffda5375e64cc81f9ed3cc04a Mon Sep 17 00:00:00 2001 From: Ketil Johnsen Date: Mon, 27 Oct 2025 15:02:15 +0100 Subject: [PATCH 0571/2333] drm/panthor: Fix UAF race between device unplug and FW event processing [ Upstream commit 7051f6ba968fa69918d72cc26de4d6cf7ea05b90 ] The function panthor_fw_unplug() will free the FW memory sections. The problem is that there could still be pending FW events which are yet not handled at this point. process_fw_events_work() can in this case try to access said freed memory. Simply call disable_work_sync() to both drain and prevent future invocation of process_fw_events_work(). Signed-off-by: Ketil Johnsen Fixes: de85488138247 ("drm/panthor: Add the scheduler logical block") Reviewed-by: Liviu Dudau Link: https://patch.msgid.link/20251027140217.121274-1-ketil.johnsen@arm.com Signed-off-by: Liviu Dudau Signed-off-by: Sasha Levin --- drivers/gpu/drm/panthor/panthor_sched.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/panthor/panthor_sched.c b/drivers/gpu/drm/panthor/panthor_sched.c index a39f0fb370dc6..0279e19aadae9 100644 --- a/drivers/gpu/drm/panthor/panthor_sched.c +++ b/drivers/gpu/drm/panthor/panthor_sched.c @@ -3859,6 +3859,7 @@ void panthor_sched_unplug(struct panthor_device *ptdev) struct panthor_scheduler *sched = ptdev->scheduler; cancel_delayed_work_sync(&sched->tick_work); + disable_work_sync(&sched->fw_events_work); mutex_lock(&sched->lock); if (sched->pm.has_ref) { From 05bfa79dec11c96397b9087dca4a661f48cc29e3 Mon Sep 17 00:00:00 2001 From: Ketil Johnsen Date: Wed, 22 Oct 2025 12:32:41 +0200 Subject: [PATCH 0572/2333] drm/panthor: Fix race with suspend during unplug [ Upstream commit 08be57e6e8aa20ea5a6dd2552e38ac168d6a9b11 ] There is a race between panthor_device_unplug() and panthor_device_suspend() which can lead to IRQ handlers running on a powered down GPU. This is how it can happen: - unplug routine calls drm_dev_unplug() - panthor_device_suspend() can now execute, and will skip a lot of important work because the device is currently marked as unplugged. - IRQs will remain active in this case and IRQ handlers can therefore try to access a powered down GPU. The fix is simply to take the PM ref in panthor_device_unplug() a little bit earlier, before drm_dev_unplug(). Signed-off-by: Ketil Johnsen Fixes: 5fe909cae118a ("drm/panthor: Add the device logical block") Reviewed-by: Boris Brezillon Reviewed-by: Liviu Dudau Reviewed-by: Steven Price Link: https://patch.msgid.link/20251022103242.1083311-1-ketil.johnsen@arm.com Signed-off-by: Liviu Dudau Signed-off-by: Sasha Levin --- drivers/gpu/drm/panthor/panthor_device.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/panthor/panthor_device.c b/drivers/gpu/drm/panthor/panthor_device.c index 81df49880bd87..962a10e00848e 100644 --- a/drivers/gpu/drm/panthor/panthor_device.c +++ b/drivers/gpu/drm/panthor/panthor_device.c @@ -83,6 +83,8 @@ void panthor_device_unplug(struct panthor_device *ptdev) return; } + drm_WARN_ON(&ptdev->base, pm_runtime_get_sync(ptdev->base.dev) < 0); + /* Call drm_dev_unplug() so any access to HW blocks happening after * that point get rejected. */ @@ -93,8 +95,6 @@ void panthor_device_unplug(struct panthor_device *ptdev) */ mutex_unlock(&ptdev->unplug.lock); - drm_WARN_ON(&ptdev->base, pm_runtime_get_sync(ptdev->base.dev) < 0); - /* Now, try to cleanly shutdown the GPU before the device resources * get reclaimed. */ From 0612704b6f6ddf2ae223019c52148c5ac76cf70e Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Fri, 31 Oct 2025 16:48:15 +0100 Subject: [PATCH 0573/2333] drm/panthor: Fix UAF on kernel BO VA nodes [ Upstream commit 98dd5143447af0ee33551776d8b2560c35d0bc4a ] If the MMU is down, panthor_vm_unmap_range() might return an error. We expect the page table to be updated still, and if the MMU is blocked, the rest of the GPU should be blocked too, so no risk of accessing physical memory returned to the system (which the current code doesn't cover for anyway). Proceed with the rest of the cleanup instead of bailing out and leaving the va_node inserted in the drm_mm, which leads to UAF when other adjacent nodes are removed from the drm_mm tree. Reported-by: Lars-Ivar Hesselberg Simonsen Closes: https://gitlab.freedesktop.org/panfrost/linux/-/issues/57 Fixes: 8a1cc07578bf ("drm/panthor: Add GEM logical block") Signed-off-by: Boris Brezillon Reviewed-by: Liviu Dudau Link: https://patch.msgid.link/20251031154818.821054-2-boris.brezillon@collabora.com Signed-off-by: Liviu Dudau Signed-off-by: Sasha Levin --- drivers/gpu/drm/panthor/panthor_gem.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/panthor/panthor_gem.c b/drivers/gpu/drm/panthor/panthor_gem.c index 3f43686f01958..14ed09d700f2f 100644 --- a/drivers/gpu/drm/panthor/panthor_gem.c +++ b/drivers/gpu/drm/panthor/panthor_gem.c @@ -86,7 +86,6 @@ static void panthor_gem_free_object(struct drm_gem_object *obj) void panthor_kernel_bo_destroy(struct panthor_kernel_bo *bo) { struct panthor_vm *vm; - int ret; if (IS_ERR_OR_NULL(bo)) return; @@ -94,18 +93,11 @@ void panthor_kernel_bo_destroy(struct panthor_kernel_bo *bo) vm = bo->vm; panthor_kernel_bo_vunmap(bo); - if (drm_WARN_ON(bo->obj->dev, - to_panthor_bo(bo->obj)->exclusive_vm_root_gem != panthor_vm_root_gem(vm))) - goto out_free_bo; - - ret = panthor_vm_unmap_range(vm, bo->va_node.start, bo->va_node.size); - if (ret) - goto out_free_bo; - + drm_WARN_ON(bo->obj->dev, + to_panthor_bo(bo->obj)->exclusive_vm_root_gem != panthor_vm_root_gem(vm)); + panthor_vm_unmap_range(vm, bo->va_node.start, bo->va_node.size); panthor_vm_free_va(vm, &bo->va_node); drm_gem_object_put(bo->obj); - -out_free_bo: panthor_vm_put(vm); kfree(bo); } From 6a6f1e983edc7229499e8f7d0ba19e497d6fdadc Mon Sep 17 00:00:00 2001 From: "Thomas Richard (TI.com)" Date: Fri, 31 Oct 2025 13:44:56 +0100 Subject: [PATCH 0574/2333] firmware: ti_sci: Set IO Isolation only if the firmware is capable [ Upstream commit 999e9bc953e321651d69556fdd5dfd178f96f128 ] Prevent calling ti_sci_cmd_set_io_isolation() on firmware that does not support the IO_ISOLATION capability. Add the MSG_FLAG_CAPS_IO_ISOLATION capability flag and check it before attempting to set IO isolation during suspend/resume operations. Without this check, systems with older firmware may experience undefined behavior or errors when entering/exiting suspend states. Fixes: ec24643bdd62 ("firmware: ti_sci: Add system suspend and resume call") Signed-off-by: Thomas Richard (TI.com) Reviewed-by: Kevin Hilman Link: https://patch.msgid.link/20251031-ti-sci-io-isolation-v2-1-60d826b65949@bootlin.com Signed-off-by: Nishanth Menon Signed-off-by: Sasha Levin --- drivers/firmware/ti_sci.c | 21 +++++++++++++-------- drivers/firmware/ti_sci.h | 2 ++ 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/drivers/firmware/ti_sci.c b/drivers/firmware/ti_sci.c index 49fd2ae01055d..8d96a3c12b36a 100644 --- a/drivers/firmware/ti_sci.c +++ b/drivers/firmware/ti_sci.c @@ -3751,9 +3751,11 @@ static int __maybe_unused ti_sci_suspend_noirq(struct device *dev) struct ti_sci_info *info = dev_get_drvdata(dev); int ret = 0; - ret = ti_sci_cmd_set_io_isolation(&info->handle, TISCI_MSG_VALUE_IO_ENABLE); - if (ret) - return ret; + if (info->fw_caps & MSG_FLAG_CAPS_IO_ISOLATION) { + ret = ti_sci_cmd_set_io_isolation(&info->handle, TISCI_MSG_VALUE_IO_ENABLE); + if (ret) + return ret; + } return 0; } @@ -3767,9 +3769,11 @@ static int __maybe_unused ti_sci_resume_noirq(struct device *dev) u8 pin; u8 mode; - ret = ti_sci_cmd_set_io_isolation(&info->handle, TISCI_MSG_VALUE_IO_DISABLE); - if (ret) - return ret; + if (info->fw_caps & MSG_FLAG_CAPS_IO_ISOLATION) { + ret = ti_sci_cmd_set_io_isolation(&info->handle, TISCI_MSG_VALUE_IO_DISABLE); + if (ret) + return ret; + } ret = ti_sci_msg_cmd_lpm_wake_reason(&info->handle, &source, &time, &pin, &mode); /* Do not fail to resume on error as the wake reason is not critical */ @@ -3928,11 +3932,12 @@ static int ti_sci_probe(struct platform_device *pdev) } ti_sci_msg_cmd_query_fw_caps(&info->handle, &info->fw_caps); - dev_dbg(dev, "Detected firmware capabilities: %s%s%s%s\n", + dev_dbg(dev, "Detected firmware capabilities: %s%s%s%s%s\n", info->fw_caps & MSG_FLAG_CAPS_GENERIC ? "Generic" : "", info->fw_caps & MSG_FLAG_CAPS_LPM_PARTIAL_IO ? " Partial-IO" : "", info->fw_caps & MSG_FLAG_CAPS_LPM_DM_MANAGED ? " DM-Managed" : "", - info->fw_caps & MSG_FLAG_CAPS_LPM_ABORT ? " LPM-Abort" : "" + info->fw_caps & MSG_FLAG_CAPS_LPM_ABORT ? " LPM-Abort" : "", + info->fw_caps & MSG_FLAG_CAPS_IO_ISOLATION ? " IO-Isolation" : "" ); ti_sci_setup_ops(info); diff --git a/drivers/firmware/ti_sci.h b/drivers/firmware/ti_sci.h index 701c416b2e78f..7559cde17b6cc 100644 --- a/drivers/firmware/ti_sci.h +++ b/drivers/firmware/ti_sci.h @@ -149,6 +149,7 @@ struct ti_sci_msg_req_reboot { * MSG_FLAG_CAPS_LPM_PARTIAL_IO: Partial IO in LPM * MSG_FLAG_CAPS_LPM_DM_MANAGED: LPM can be managed by DM * MSG_FLAG_CAPS_LPM_ABORT: Abort entry to LPM + * MSG_FLAG_CAPS_IO_ISOLATION: IO Isolation support * * Response to a generic message with message type TI_SCI_MSG_QUERY_FW_CAPS * providing currently available SOC/firmware capabilities. SoC that don't @@ -160,6 +161,7 @@ struct ti_sci_msg_resp_query_fw_caps { #define MSG_FLAG_CAPS_LPM_PARTIAL_IO TI_SCI_MSG_FLAG(4) #define MSG_FLAG_CAPS_LPM_DM_MANAGED TI_SCI_MSG_FLAG(5) #define MSG_FLAG_CAPS_LPM_ABORT TI_SCI_MSG_FLAG(9) +#define MSG_FLAG_CAPS_IO_ISOLATION TI_SCI_MSG_FLAG(7) #define MSG_MASK_CAPS_LPM GENMASK_ULL(4, 1) u64 fw_caps; } __packed; From ad804f43873aa290dbe7463454359b256b414e49 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Mon, 3 Nov 2025 16:10:10 +0100 Subject: [PATCH 0575/2333] ns: add NS_COMMON_INIT() [ Upstream commit d915fe20e5cba4bd50e41e792a32dcddc7490e25 ] Add an initializer that can be used for the ns common initialization for static namespace such as most init namespaces. Suggested-by: Thomas Gleixner Link: https://patch.msgid.link/87ecqhy2y5.ffs@tglx Signed-off-by: Christian Brauner Stable-dep-of: 3dd50c58664e ("ns: initialize ns_list_node for initial namespaces") Signed-off-by: Sasha Levin --- include/linux/ns_common.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/include/linux/ns_common.h b/include/linux/ns_common.h index f5b68b8abb543..3a72c3f81eca4 100644 --- a/include/linux/ns_common.h +++ b/include/linux/ns_common.h @@ -119,6 +119,16 @@ void __ns_common_free(struct ns_common *ns); struct user_namespace *: CLONE_NEWUSER, \ struct uts_namespace *: CLONE_NEWUTS) +#define NS_COMMON_INIT(nsname, refs) \ +{ \ + .ns_type = ns_common_type(&nsname), \ + .ns_id = 0, \ + .inum = ns_init_inum(&nsname), \ + .ops = to_ns_operations(&nsname), \ + .stashed = NULL, \ + .__ns_ref = REFCOUNT_INIT(refs), \ +} + #define ns_common_init(__ns) \ __ns_common_init(to_ns_common(__ns), \ ns_common_type(__ns), \ From e31c902d785411eb4a246fba2e8a32aa59d33ce2 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Wed, 29 Oct 2025 13:20:21 +0100 Subject: [PATCH 0576/2333] ns: initialize ns_list_node for initial namespaces [ Upstream commit 3dd50c58664e2684bd610a57bf3ab713cbb0ea91 ] Make sure that the list is always initialized for initial namespaces. Link: https://patch.msgid.link/20251029-work-namespace-nstree-listns-v4-8-2e6f823ebdc0@kernel.org Fixes: 885fc8ac0a4d ("nstree: make iterator generic") Tested-by: syzbot@syzkaller.appspotmail.com Reviewed-by: Jeff Layton Signed-off-by: Christian Brauner Signed-off-by: Sasha Levin --- include/linux/ns_common.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/ns_common.h b/include/linux/ns_common.h index 3a72c3f81eca4..71a5e28344d11 100644 --- a/include/linux/ns_common.h +++ b/include/linux/ns_common.h @@ -127,6 +127,7 @@ void __ns_common_free(struct ns_common *ns); .ops = to_ns_operations(&nsname), \ .stashed = NULL, \ .__ns_ref = REFCOUNT_INIT(refs), \ + .ns_list_node = LIST_HEAD_INIT(nsname.ns.ns_list_node), \ } #define ns_common_init(__ns) \ From 0ec4aaf5f3f559716a6559f3d6d9616e9470bed6 Mon Sep 17 00:00:00 2001 From: Songtang Liu Date: Thu, 30 Oct 2025 22:55:25 -0700 Subject: [PATCH 0577/2333] iommu/amd: Fix potential out-of-bounds read in iommu_mmio_show [ Upstream commit a0c7005333f9a968abb058b1d77bbcd7fb7fd1e7 ] In iommu_mmio_write(), it validates the user-provided offset with the check: `iommu->dbg_mmio_offset > iommu->mmio_phys_end - 4`. This assumes a 4-byte access. However, the corresponding show handler, iommu_mmio_show(), uses readq() to perform an 8-byte (64-bit) read. If a user provides an offset equal to `mmio_phys_end - 4`, the check passes, and will lead to a 4-byte out-of-bounds read. Fix this by adjusting the boundary check to use sizeof(u64), which corresponds to the size of the readq() operation. Fixes: 7a4ee419e8c1 ("iommu/amd: Add debugfs support to dump IOMMU MMIO registers") Signed-off-by: Songtang Liu Reviewed-by: Dheeraj Kumar Srivastava Tested-by: Dheeraj Kumar Srivastava Signed-off-by: Joerg Roedel Signed-off-by: Sasha Levin --- drivers/iommu/amd/debugfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iommu/amd/debugfs.c b/drivers/iommu/amd/debugfs.c index 10fa217a71199..20b04996441d6 100644 --- a/drivers/iommu/amd/debugfs.c +++ b/drivers/iommu/amd/debugfs.c @@ -37,7 +37,7 @@ static ssize_t iommu_mmio_write(struct file *filp, const char __user *ubuf, if (ret) return ret; - if (iommu->dbg_mmio_offset > iommu->mmio_phys_end - 4) { + if (iommu->dbg_mmio_offset > iommu->mmio_phys_end - sizeof(u64)) { iommu->dbg_mmio_offset = -1; return -EINVAL; } From 83143f9df885f793f8f20236cf569d6f1b7b8b81 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Mon, 3 Nov 2025 00:12:40 +0100 Subject: [PATCH 0578/2333] cleanup: fix scoped_class() [ Upstream commit 4e97bae1b412cd6ed8053b3d8a242122952985cc ] This is a class, not a guard so why on earth is it checking for guard pointers or conditional lock acquisition? None of it makes any sense at all. I'm not sure what happened back then. Maybe I had a brief psychedelic period that I completely forgot about and spaced out into a zone where that initial macro implementation made any sense at all. Link: https://patch.msgid.link/20251103-work-creds-init_cred-v1-1-cb3ec8711a6a@kernel.org Fixes: 5c21c5f22d07 ("cleanup: add a scoped version of CLASS()") Reviewed-by: Jens Axboe Signed-off-by: Christian Brauner Signed-off-by: Sasha Levin --- include/linux/cleanup.h | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/include/linux/cleanup.h b/include/linux/cleanup.h index 2573585b7f068..19c7e475d3a4d 100644 --- a/include/linux/cleanup.h +++ b/include/linux/cleanup.h @@ -290,15 +290,16 @@ static inline class_##_name##_t class_##_name##ext##_constructor(_init_args) \ class_##_name##_t var __cleanup(class_##_name##_destructor) = \ class_##_name##_constructor -#define scoped_class(_name, var, args) \ - for (CLASS(_name, var)(args); \ - __guard_ptr(_name)(&var) || !__is_cond_ptr(_name); \ - ({ goto _label; })) \ - if (0) { \ -_label: \ - break; \ +#define __scoped_class(_name, var, _label, args...) \ + for (CLASS(_name, var)(args); ; ({ goto _label; })) \ + if (0) { \ +_label: \ + break; \ } else +#define scoped_class(_name, var, args...) \ + __scoped_class(_name, var, __UNIQUE_ID(label), args) + /* * DEFINE_GUARD(name, type, lock, unlock): * trivial wrapper around DEFINE_CLASS() above specifically From 01bbf25c767219b14c3235bfa85906b8d2cb8fbc Mon Sep 17 00:00:00 2001 From: Vishwaroop A Date: Tue, 28 Oct 2025 15:57:01 +0000 Subject: [PATCH 0579/2333] spi: tegra210-quad: Fix timeout handling [ Upstream commit b4e002d8a7cee3b1d70efad0e222567f92a73000 ] When the CPU that the QSPI interrupt handler runs on (typically CPU 0) is excessively busy, it can lead to rare cases of the IRQ thread not running before the transfer timeout is reached. While handling the timeouts, any pending transfers are cleaned up and the message that they correspond to is marked as failed, which leaves the curr_xfer field pointing at stale memory. To avoid this, clear curr_xfer to NULL upon timeout and check for this condition when the IRQ thread is finally run. While at it, also make sure to clear interrupts on failure so that new interrupts can be run. A better, more involved, fix would move the interrupt clearing into a hard IRQ handler. Ideally we would also want to signal that the IRQ thread no longer needs to be run after the timeout is hit to avoid the extra check for a valid transfer. Fixes: 921fc1838fb0 ("spi: tegra210-quad: Add support for Tegra210 QSPI controller") Signed-off-by: Thierry Reding Signed-off-by: Vishwaroop A Link: https://patch.msgid.link/20251028155703.4151791-2-va@nvidia.com Signed-off-by: Mark Brown Signed-off-by: Sasha Levin --- drivers/spi/spi-tegra210-quad.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi-tegra210-quad.c b/drivers/spi/spi-tegra210-quad.c index 3be7499db21ec..d9ca3d7b082f2 100644 --- a/drivers/spi/spi-tegra210-quad.c +++ b/drivers/spi/spi-tegra210-quad.c @@ -1024,8 +1024,10 @@ static void tegra_qspi_handle_error(struct tegra_qspi *tqspi) dev_err(tqspi->dev, "error in transfer, fifo status 0x%08x\n", tqspi->status_reg); tegra_qspi_dump_regs(tqspi); tegra_qspi_flush_fifos(tqspi, true); - if (device_reset(tqspi->dev) < 0) + if (device_reset(tqspi->dev) < 0) { dev_warn_once(tqspi->dev, "device reset failed\n"); + tegra_qspi_mask_clear_irq(tqspi); + } } static void tegra_qspi_transfer_end(struct spi_device *spi) @@ -1176,9 +1178,11 @@ static int tegra_qspi_combined_seq_xfer(struct tegra_qspi *tqspi, } /* Reset controller if timeout happens */ - if (device_reset(tqspi->dev) < 0) + if (device_reset(tqspi->dev) < 0) { dev_warn_once(tqspi->dev, "device reset failed\n"); + tegra_qspi_mask_clear_irq(tqspi); + } ret = -EIO; goto exit; } @@ -1200,11 +1204,13 @@ static int tegra_qspi_combined_seq_xfer(struct tegra_qspi *tqspi, tegra_qspi_transfer_end(spi); spi_transfer_delay_exec(xfer); } + tqspi->curr_xfer = NULL; transfer_phase++; } ret = 0; exit: + tqspi->curr_xfer = NULL; msg->status = ret; return ret; @@ -1290,6 +1296,8 @@ static int tegra_qspi_non_combined_seq_xfer(struct tegra_qspi *tqspi, msg->actual_length += xfer->len + dummy_bytes; complete_xfer: + tqspi->curr_xfer = NULL; + if (ret < 0) { tegra_qspi_transfer_end(spi); spi_transfer_delay_exec(xfer); @@ -1395,6 +1403,7 @@ static irqreturn_t handle_cpu_based_xfer(struct tegra_qspi *tqspi) tegra_qspi_calculate_curr_xfer_param(tqspi, t); tegra_qspi_start_cpu_based_transfer(tqspi, t); exit: + tqspi->curr_xfer = NULL; spin_unlock_irqrestore(&tqspi->lock, flags); return IRQ_HANDLED; } @@ -1480,6 +1489,15 @@ static irqreturn_t tegra_qspi_isr_thread(int irq, void *context_data) { struct tegra_qspi *tqspi = context_data; + /* + * Occasionally the IRQ thread takes a long time to wake up (usually + * when the CPU that it's running on is excessively busy) and we have + * already reached the timeout before and cleaned up the timed out + * transfer. Avoid any processing in that case and bail out early. + */ + if (!tqspi->curr_xfer) + return IRQ_NONE; + tqspi->status_reg = tegra_qspi_readl(tqspi, QSPI_FIFO_STATUS); if (tqspi->cur_direction & DATA_DIR_TX) From b454e6282cbfefd2e6f592c7a73131b36cb7fb96 Mon Sep 17 00:00:00 2001 From: Alan Maguire Date: Tue, 4 Nov 2025 20:33:08 +0000 Subject: [PATCH 0580/2333] libbpf: Fix parsing of multi-split BTF [ Upstream commit 4f596acc260e691a2e348f64230392f3472feea3 ] When creating multi-split BTF we correctly set the start string offset to be the size of the base string section plus the base BTF start string offset; the latter is needed for multi-split BTF since the offset is non-zero there. Unfortunately the BTF parsing case needed that logic and it was missed. Fixes: 4e29128a9ace ("libbpf/btf: Fix string handling to support multi-split BTF") Signed-off-by: Alan Maguire Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/20251104203309.318429-2-alan.maguire@oracle.com Signed-off-by: Sasha Levin --- tools/lib/bpf/btf.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/lib/bpf/btf.c b/tools/lib/bpf/btf.c index 18907f0fcf9f0..9f141395c074e 100644 --- a/tools/lib/bpf/btf.c +++ b/tools/lib/bpf/btf.c @@ -1061,7 +1061,7 @@ static struct btf *btf_new(const void *data, __u32 size, struct btf *base_btf, b if (base_btf) { btf->base_btf = base_btf; btf->start_id = btf__type_cnt(base_btf); - btf->start_str_off = base_btf->hdr->str_len; + btf->start_str_off = base_btf->hdr->str_len + base_btf->start_str_off; } if (is_mmap) { @@ -5818,7 +5818,7 @@ void btf_set_base_btf(struct btf *btf, const struct btf *base_btf) { btf->base_btf = (struct btf *)base_btf; btf->start_id = btf__type_cnt(base_btf); - btf->start_str_off = base_btf->hdr->str_len; + btf->start_str_off = base_btf->hdr->str_len + base_btf->start_str_off; } int btf__relocate(struct btf *btf, const struct btf *base_btf) From 29e886ee371b674220a7557dd0070c73dab73c0b Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 2 Oct 2025 11:53:05 +0200 Subject: [PATCH 0581/2333] ARM: dts: am33xx: Add missing serial console speed [ Upstream commit 9c95fc710b0d05f797db9e26d56524efa74f8978 ] Without a serial console speed specified in chosen/stdout-path in the DTB, the serial console uses the default speed of the serial driver, unless explicitly overridden in a legacy console= kernel command-line parameter. After dropping "ti,omap3-uart" from the list of compatible values in DT, AM33xx serial ports can no longer be used with the legacy OMAP serial driver, but only with the OMAP-flavored 8250 serial driver (which is mutually-exclusive with the former). However, replacing CONFIG_SERIAL_OMAP=y by CONFIG_SERIAL_8250_OMAP=y (with/without enabling CONFIG_SERIAL_8250_OMAP_TTYO_FIXUP) may not be sufficient to restore serial console functionality: the legacy OMAP serial driver defaults to 115200 bps, while the 8250 serial driver defaults to 9600 bps, causing no visible output on the serial console when no appropriate console= kernel command-line parameter is specified. Fix this for all AM33xx boards by adding ":115200n8" to chosen/stdout-path. This requires replacing the "&uartN" reference by the corresponding "serialN" DT alias. Fixes: ca8be8fc2c306efb ("ARM: dts: am33xx-l4: fix UART compatible") Fixes: 077e1cde78c3f904 ("ARM: omap2plus_defconfig: Enable 8250_OMAP") Closes: https://lore.kernel.org/CAMuHMdUb7Jb2=GqK3=Rn+Gv5G9KogcQieqDvjDCkJA4zyX4VcA@mail.gmail.com Signed-off-by: Geert Uytterhoeven Reviewed-by: Matti Vaittinen Tested-by: Matti Vaittinen Reviewed-by: Bruno Thomsen Link: https://lore.kernel.org/r/63cef5c3643d359e8ec13366ca79377f12dd73b1.1759398641.git.geert+renesas@glider.be Signed-off-by: Kevin Hilman Signed-off-by: Sasha Levin --- arch/arm/boot/dts/ti/omap/am335x-bone-common.dtsi | 2 +- arch/arm/boot/dts/ti/omap/am335x-boneblue.dts | 2 +- arch/arm/boot/dts/ti/omap/am335x-chiliboard.dts | 2 +- arch/arm/boot/dts/ti/omap/am335x-evm.dts | 2 +- arch/arm/boot/dts/ti/omap/am335x-evmsk.dts | 2 +- arch/arm/boot/dts/ti/omap/am335x-guardian.dts | 2 +- arch/arm/boot/dts/ti/omap/am335x-icev2.dts | 2 +- arch/arm/boot/dts/ti/omap/am335x-myirtech-myd.dts | 2 +- arch/arm/boot/dts/ti/omap/am335x-osd3358-sm-red.dts | 2 +- arch/arm/boot/dts/ti/omap/am335x-pdu001.dts | 2 +- arch/arm/boot/dts/ti/omap/am335x-pocketbeagle.dts | 2 +- arch/arm/boot/dts/ti/omap/am335x-sl50.dts | 2 +- 12 files changed, 12 insertions(+), 12 deletions(-) diff --git a/arch/arm/boot/dts/ti/omap/am335x-bone-common.dtsi b/arch/arm/boot/dts/ti/omap/am335x-bone-common.dtsi index ad1e60a9b6fde..b75dabfa56ae7 100644 --- a/arch/arm/boot/dts/ti/omap/am335x-bone-common.dtsi +++ b/arch/arm/boot/dts/ti/omap/am335x-bone-common.dtsi @@ -16,7 +16,7 @@ }; chosen { - stdout-path = &uart0; + stdout-path = "serial0:115200n8"; }; leds { diff --git a/arch/arm/boot/dts/ti/omap/am335x-boneblue.dts b/arch/arm/boot/dts/ti/omap/am335x-boneblue.dts index f579df4c2c540..d430f0bef1653 100644 --- a/arch/arm/boot/dts/ti/omap/am335x-boneblue.dts +++ b/arch/arm/boot/dts/ti/omap/am335x-boneblue.dts @@ -13,7 +13,7 @@ compatible = "ti,am335x-bone-blue", "ti,am33xx"; chosen { - stdout-path = &uart0; + stdout-path = "serial0:115200n8"; }; leds { diff --git a/arch/arm/boot/dts/ti/omap/am335x-chiliboard.dts b/arch/arm/boot/dts/ti/omap/am335x-chiliboard.dts index 648e97fe1dfd5..ae5bc58984972 100644 --- a/arch/arm/boot/dts/ti/omap/am335x-chiliboard.dts +++ b/arch/arm/boot/dts/ti/omap/am335x-chiliboard.dts @@ -12,7 +12,7 @@ "ti,am33xx"; chosen { - stdout-path = &uart0; + stdout-path = "serial0:115200n8"; }; leds { diff --git a/arch/arm/boot/dts/ti/omap/am335x-evm.dts b/arch/arm/boot/dts/ti/omap/am335x-evm.dts index 20222f82f21bf..856fa1191ed24 100644 --- a/arch/arm/boot/dts/ti/omap/am335x-evm.dts +++ b/arch/arm/boot/dts/ti/omap/am335x-evm.dts @@ -23,7 +23,7 @@ }; chosen { - stdout-path = &uart0; + stdout-path = "serial0:115200n8"; }; vbat: fixedregulator0 { diff --git a/arch/arm/boot/dts/ti/omap/am335x-evmsk.dts b/arch/arm/boot/dts/ti/omap/am335x-evmsk.dts index eba888dcd60e7..d8baccdf8bc46 100644 --- a/arch/arm/boot/dts/ti/omap/am335x-evmsk.dts +++ b/arch/arm/boot/dts/ti/omap/am335x-evmsk.dts @@ -30,7 +30,7 @@ }; chosen { - stdout-path = &uart0; + stdout-path = "serial0:115200n8"; }; vbat: fixedregulator0 { diff --git a/arch/arm/boot/dts/ti/omap/am335x-guardian.dts b/arch/arm/boot/dts/ti/omap/am335x-guardian.dts index 4b070e634b281..6ce3a2d029eed 100644 --- a/arch/arm/boot/dts/ti/omap/am335x-guardian.dts +++ b/arch/arm/boot/dts/ti/omap/am335x-guardian.dts @@ -14,7 +14,7 @@ compatible = "bosch,am335x-guardian", "ti,am33xx"; chosen { - stdout-path = &uart0; + stdout-path = "serial0:115200n8"; tick-timer = &timer2; }; diff --git a/arch/arm/boot/dts/ti/omap/am335x-icev2.dts b/arch/arm/boot/dts/ti/omap/am335x-icev2.dts index 6f0f4fba043b9..ba488bba6925d 100644 --- a/arch/arm/boot/dts/ti/omap/am335x-icev2.dts +++ b/arch/arm/boot/dts/ti/omap/am335x-icev2.dts @@ -22,7 +22,7 @@ }; chosen { - stdout-path = &uart3; + stdout-path = "serial3:115200n8"; }; vbat: fixedregulator0 { diff --git a/arch/arm/boot/dts/ti/omap/am335x-myirtech-myd.dts b/arch/arm/boot/dts/ti/omap/am335x-myirtech-myd.dts index 06a352f98b220..476a6bdaf43f3 100644 --- a/arch/arm/boot/dts/ti/omap/am335x-myirtech-myd.dts +++ b/arch/arm/boot/dts/ti/omap/am335x-myirtech-myd.dts @@ -15,7 +15,7 @@ compatible = "myir,myd-am335x", "myir,myc-am335x", "ti,am33xx"; chosen { - stdout-path = &uart0; + stdout-path = "serial0:115200n8"; }; clk12m: clk12m { diff --git a/arch/arm/boot/dts/ti/omap/am335x-osd3358-sm-red.dts b/arch/arm/boot/dts/ti/omap/am335x-osd3358-sm-red.dts index d28d397288476..23caaaabf3513 100644 --- a/arch/arm/boot/dts/ti/omap/am335x-osd3358-sm-red.dts +++ b/arch/arm/boot/dts/ti/omap/am335x-osd3358-sm-red.dts @@ -147,7 +147,7 @@ }; chosen { - stdout-path = &uart0; + stdout-path = "serial0:115200n8"; }; leds { diff --git a/arch/arm/boot/dts/ti/omap/am335x-pdu001.dts b/arch/arm/boot/dts/ti/omap/am335x-pdu001.dts index c9ccb9de21ad7..9f611debc2090 100644 --- a/arch/arm/boot/dts/ti/omap/am335x-pdu001.dts +++ b/arch/arm/boot/dts/ti/omap/am335x-pdu001.dts @@ -21,7 +21,7 @@ compatible = "ti,am33xx"; chosen { - stdout-path = &uart3; + stdout-path = "serial3:115200n8"; }; cpus { diff --git a/arch/arm/boot/dts/ti/omap/am335x-pocketbeagle.dts b/arch/arm/boot/dts/ti/omap/am335x-pocketbeagle.dts index 78ce860e59b3d..24d9f90fad01f 100644 --- a/arch/arm/boot/dts/ti/omap/am335x-pocketbeagle.dts +++ b/arch/arm/boot/dts/ti/omap/am335x-pocketbeagle.dts @@ -15,7 +15,7 @@ compatible = "ti,am335x-pocketbeagle", "ti,am335x-bone", "ti,am33xx"; chosen { - stdout-path = &uart0; + stdout-path = "serial0:115200n8"; }; leds { diff --git a/arch/arm/boot/dts/ti/omap/am335x-sl50.dts b/arch/arm/boot/dts/ti/omap/am335x-sl50.dts index f3524e5ee43e2..1dc4e344efd63 100644 --- a/arch/arm/boot/dts/ti/omap/am335x-sl50.dts +++ b/arch/arm/boot/dts/ti/omap/am335x-sl50.dts @@ -25,7 +25,7 @@ }; chosen { - stdout-path = &uart0; + stdout-path = "serial0:115200n8"; }; leds { From 97f035128363a8240d229f767914ee7200f3452d Mon Sep 17 00:00:00 2001 From: Yegor Yefremov Date: Tue, 7 Oct 2025 12:38:51 +0200 Subject: [PATCH 0582/2333] ARM: dts: am335x-netcom-plus-2xx: add missing GPIO labels [ Upstream commit d0c4b1723c419a18cb434903c7754954ecb51d35 ] Fixes: 8e9d75fd2ec2 ("ARM: dts: am335x-netcom: add GPIO names for NetCom Plus 2-port devices") Signed-off-by: Yegor Yefremov Link: https://lore.kernel.org/r/20251007103851.3765678-1-yegorslists@googlemail.com Signed-off-by: Kevin Hilman Signed-off-by: Sasha Levin --- arch/arm/boot/dts/ti/omap/am335x-netcom-plus-2xx.dts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/arm/boot/dts/ti/omap/am335x-netcom-plus-2xx.dts b/arch/arm/boot/dts/ti/omap/am335x-netcom-plus-2xx.dts index f66d57bb685ee..f0519ab301416 100644 --- a/arch/arm/boot/dts/ti/omap/am335x-netcom-plus-2xx.dts +++ b/arch/arm/boot/dts/ti/omap/am335x-netcom-plus-2xx.dts @@ -222,10 +222,10 @@ "ModeA1", "ModeA2", "ModeA3", - "NC", - "NC", - "NC", - "NC", + "ModeB0", + "ModeB1", + "ModeB2", + "ModeB3", "NC", "NC", "NC", From ecd2c6686f49371ac3398e57743bec1aa2b6130b Mon Sep 17 00:00:00 2001 From: Jihed Chaibi Date: Sun, 14 Sep 2025 21:25:15 +0200 Subject: [PATCH 0583/2333] ARM: dts: omap3: beagle-xm: Correct obsolete TWL4030 power compatible [ Upstream commit f7f3bc18300a230e0f1bfb17fc8889435c1e47f5 ] The "ti,twl4030-power-beagleboard-xm" compatible string is obsolete and is not supported by any in-kernel driver. Currently, the kernel falls back to the second entry, "ti,twl4030-power-idle-osc-off", to bind a driver to this node. Make this fallback explicit by removing the obsolete board-specific compatible. This preserves the existing functionality while making the DTS compliant with the new, stricter 'ti,twl.yaml' binding. Fixes: 9188883fd66e9 ("ARM: dts: Enable twl4030 off-idle configuration for selected omaps") Signed-off-by: Jihed Chaibi Link: https://lore.kernel.org/r/20250914192516.164629-3-jihed.chaibi.dev@gmail.com Signed-off-by: Kevin Hilman Signed-off-by: Sasha Levin --- arch/arm/boot/dts/ti/omap/omap3-beagle-xm.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/ti/omap/omap3-beagle-xm.dts b/arch/arm/boot/dts/ti/omap/omap3-beagle-xm.dts index 08ee0f8ea68fd..71b39a923d37c 100644 --- a/arch/arm/boot/dts/ti/omap/omap3-beagle-xm.dts +++ b/arch/arm/boot/dts/ti/omap/omap3-beagle-xm.dts @@ -291,7 +291,7 @@ }; twl_power: power { - compatible = "ti,twl4030-power-beagleboard-xm", "ti,twl4030-power-idle-osc-off"; + compatible = "ti,twl4030-power-idle-osc-off"; ti,use_poweroff; }; }; From a1b7235ba4388eacf90ec6cbc1c7697bf77bf44a Mon Sep 17 00:00:00 2001 From: Jihed Chaibi Date: Sun, 14 Sep 2025 21:25:16 +0200 Subject: [PATCH 0584/2333] ARM: dts: omap3: n900: Correct obsolete TWL4030 power compatible [ Upstream commit 3862123e9b56663c7a3e4a308e6e65bffe44f646 ] The "ti,twl4030-power-n900" compatible string is obsolete and is not supported by any in-kernel driver. Currently, the kernel falls back to the second entry, "ti,twl4030-power-idle-osc-off", to bind a driver to this node. Make this fallback explicit by removing the obsolete board-specific compatible. This preserves the existing functionality while making the DTS compliant with the new, stricter 'ti,twl.yaml' binding. Fixes: daebabd578647 ("mfd: twl4030-power: Fix PM idle pin configuration to not conflict with regulators") Signed-off-by: Jihed Chaibi Link: https://lore.kernel.org/r/20250914192516.164629-4-jihed.chaibi.dev@gmail.com Signed-off-by: Kevin Hilman Signed-off-by: Sasha Levin --- arch/arm/boot/dts/ti/omap/omap3-n900.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/ti/omap/omap3-n900.dts b/arch/arm/boot/dts/ti/omap/omap3-n900.dts index c50ca572d1b9b..7db73d9bed9e4 100644 --- a/arch/arm/boot/dts/ti/omap/omap3-n900.dts +++ b/arch/arm/boot/dts/ti/omap/omap3-n900.dts @@ -508,7 +508,7 @@ }; twl_power: power { - compatible = "ti,twl4030-power-n900", "ti,twl4030-power-idle-osc-off"; + compatible = "ti,twl4030-power-idle-osc-off"; ti,use_poweroff; }; }; From 040ce00735c17b4c30c18c8f36805ba952a447e2 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Wed, 5 Nov 2025 11:00:14 +0100 Subject: [PATCH 0585/2333] entry,unwind/deferred: Fix unwind_reset_info() placement [ Upstream commit cf76553aaa363620f58a6b6409bf544f4bcfa8de ] Stephen reported that on KASAN builds he's seeing: vmlinux.o: warning: objtool: user_exc_vmm_communication+0x15a: call to __kasan_check_read() leaves .noinstr.text section vmlinux.o: warning: objtool: exc_debug_user+0x182: call to __kasan_check_read() leaves .noinstr.text section vmlinux.o: warning: objtool: exc_int3+0x123: call to __kasan_check_read() leaves .noinstr.text section vmlinux.o: warning: objtool: noist_exc_machine_check+0x17a: call to __kasan_check_read() leaves .noinstr.text section vmlinux.o: warning: objtool: fred_exc_machine_check+0x17e: call to __kasan_check_read() leaves .noinstr.text section This turns out to be atomic ops from unwind_reset_info() that have explicit instrumentation. Place unwind_reset_info() in the preceding instrumentation_begin() section. Fixes: c6439bfaabf2 ("Merge tag 'trace-deferred-unwind-v6.17' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace") Reported-by: Stephen Rothwell Reported-by: Ingo Molnar Signed-off-by: Peter Zijlstra (Intel) Link: https://patch.msgid.link/20251105100014.GY4068168@noisy.programming.kicks-ass.net Signed-off-by: Sasha Levin --- include/linux/irq-entry-common.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/irq-entry-common.h b/include/linux/irq-entry-common.h index d643c7c87822e..ba1ed42f8a1c2 100644 --- a/include/linux/irq-entry-common.h +++ b/include/linux/irq-entry-common.h @@ -253,11 +253,11 @@ static __always_inline void exit_to_user_mode_prepare(struct pt_regs *regs) static __always_inline void exit_to_user_mode(void) { instrumentation_begin(); + unwind_reset_info(); trace_hardirqs_on_prepare(); lockdep_hardirqs_on_prepare(); instrumentation_end(); - unwind_reset_info(); user_enter_irqoff(); arch_exit_to_user_mode(); lockdep_hardirqs_on(CALLER_ADDR0); From 414c982faffa39f234af1ec889785d4c5733d615 Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Thu, 9 Oct 2025 16:22:54 +0200 Subject: [PATCH 0586/2333] arm64: tegra: Add pinctrl definitions for pcie-ep nodes [ Upstream commit 21ef26d0e71f053e809926d45b86b0afbc3686bb ] When the PCIe controller is running in endpoint mode, the controller initialization is triggered by a PERST# (PCIe reset) GPIO deassertion. The driver has configured an IRQ to trigger when the PERST# GPIO changes state. Without the pinctrl definition, we do not get an IRQ when PERST# is deasserted, so the PCIe controller never gets initialized. Add the missing definitions, so that the controller actually gets initialized. Fixes: ec142c44b026 ("arm64: tegra: Add P2U and PCIe controller nodes to Tegra234 DT") Fixes: 0580286d0d22 ("arm64: tegra: Add Tegra234 PCIe C4 EP definition") Signed-off-by: Niklas Cassel Reviewed-by: Manikanta Maddireddy [treding@nvidia.com: add blank lines to separate blocks] Signed-off-by: Thierry Reding Signed-off-by: Sasha Levin --- arch/arm64/boot/dts/nvidia/tegra234.dtsi | 61 ++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/arch/arm64/boot/dts/nvidia/tegra234.dtsi b/arch/arm64/boot/dts/nvidia/tegra234.dtsi index df034dbb82853..5657045c53d90 100644 --- a/arch/arm64/boot/dts/nvidia/tegra234.dtsi +++ b/arch/arm64/boot/dts/nvidia/tegra234.dtsi @@ -9,6 +9,7 @@ #include #include #include +#include / { compatible = "nvidia,tegra234"; @@ -127,6 +128,56 @@ pinmux: pinmux@2430000 { compatible = "nvidia,tegra234-pinmux"; reg = <0x0 0x2430000 0x0 0x19100>; + + pex_rst_c4_in_state: pinmux-pex-rst-c4-in { + pex_rst { + nvidia,pins = "pex_l4_rst_n_pl1"; + nvidia,function = "rsvd1"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + }; + + pex_rst_c5_in_state: pinmux-pex-rst-c5-in { + pex_rst { + nvidia,pins = "pex_l5_rst_n_paf1"; + nvidia,function = "rsvd1"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + }; + + pex_rst_c6_in_state: pinmux-pex-rst-c6-in { + pex_rst { + nvidia,pins = "pex_l6_rst_n_paf3"; + nvidia,function = "rsvd1"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + }; + + pex_rst_c7_in_state: pinmux-pex-rst-c7-in { + pex_rst { + nvidia,pins = "pex_l7_rst_n_pag1"; + nvidia,function = "rsvd1"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + }; + + pex_rst_c10_in_state: pinmux-pex-rst-c10-in { + pex_rst { + nvidia,pins = "pex_l10_rst_n_pag7"; + nvidia,function = "rsvd1"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + }; }; gpcdma: dma-controller@2600000 { @@ -4630,6 +4681,8 @@ <&bpmp TEGRA234_RESET_PEX2_CORE_10>; reset-names = "apb", "core"; + pinctrl-names = "default"; + pinctrl-0 = <&pex_rst_c10_in_state>; interrupts = ; /* controller interrupt */ interrupt-names = "intr"; @@ -4881,6 +4934,8 @@ <&bpmp TEGRA234_RESET_PEX0_CORE_4>; reset-names = "apb", "core"; + pinctrl-names = "default"; + pinctrl-0 = <&pex_rst_c4_in_state>; interrupts = ; /* controller interrupt */ interrupt-names = "intr"; nvidia,bpmp = <&bpmp 4>; @@ -5023,6 +5078,8 @@ <&bpmp TEGRA234_RESET_PEX1_CORE_5>; reset-names = "apb", "core"; + pinctrl-names = "default"; + pinctrl-0 = <&pex_rst_c5_in_state>; interrupts = ; /* controller interrupt */ interrupt-names = "intr"; @@ -5115,6 +5172,8 @@ <&bpmp TEGRA234_RESET_PEX1_CORE_6>; reset-names = "apb", "core"; + pinctrl-names = "default"; + pinctrl-0 = <&pex_rst_c6_in_state>; interrupts = ; /* controller interrupt */ interrupt-names = "intr"; @@ -5207,6 +5266,8 @@ <&bpmp TEGRA234_RESET_PEX2_CORE_7>; reset-names = "apb", "core"; + pinctrl-names = "default"; + pinctrl-0 = <&pex_rst_c7_in_state>; interrupts = ; /* controller interrupt */ interrupt-names = "intr"; From cda077a19f5c8d6ec61e5b97deca203d95e3a422 Mon Sep 17 00:00:00 2001 From: Xiaoqi Zhuang Date: Tue, 21 Oct 2025 16:45:25 +0800 Subject: [PATCH 0587/2333] coresight: ETR: Fix ETR buffer use-after-free issue [ Upstream commit 35501ac3c7d40a7bb9568c2f89d6b56beaf9bed3 ] When ETR is enabled as CS_MODE_SYSFS, if the buffer size is changed and enabled again, currently sysfs_buf will point to the newly allocated memory(buf_new) and free the old memory(buf_old). But the etr_buf that is being used by the ETR remains pointed to buf_old, not updated to buf_new. In this case, it will result in a memory use-after-free issue. Fix this by checking ETR's mode before updating and releasing buf_old, if the mode is CS_MODE_SYSFS, then skip updating and releasing it. Fixes: bd2767ec3df2 ("coresight: Fix run time warnings while reusing ETR buffer") Signed-off-by: Xiaoqi Zhuang Signed-off-by: Suzuki K Poulose Tested-by: Leo Yan Link: https://lore.kernel.org/r/20251021-fix_etr_issue-v3-1-99a2d066fee2@oss.qualcomm.com Signed-off-by: Sasha Levin --- drivers/hwtracing/coresight/coresight-tmc-etr.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c index b07fcdb3fe1a8..800be06598c1b 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c @@ -1250,6 +1250,13 @@ static struct etr_buf *tmc_etr_get_sysfs_buffer(struct coresight_device *csdev) * with the lock released. */ raw_spin_lock_irqsave(&drvdata->spinlock, flags); + + /* + * If the ETR is already enabled, continue with the existing buffer. + */ + if (coresight_get_mode(csdev) == CS_MODE_SYSFS) + goto out; + sysfs_buf = READ_ONCE(drvdata->sysfs_buf); if (!sysfs_buf || (sysfs_buf->size != drvdata->size)) { raw_spin_unlock_irqrestore(&drvdata->spinlock, flags); From ac3cd83b02c75289a855eb37b79d30430f562e5f Mon Sep 17 00:00:00 2001 From: Usama Arif Date: Mon, 3 Nov 2025 14:09:22 +0000 Subject: [PATCH 0588/2333] x86/boot: Fix page table access in 5-level to 4-level paging transition [ Upstream commit eb2266312507d7b757859e2227aa5c4ba6280ebe ] When transitioning from 5-level to 4-level paging, the existing code incorrectly accesses page table entries by directly dereferencing CR3 and applying PAGE_MASK. This approach has several issues: - __native_read_cr3() returns the raw CR3 register value, which on x86_64 includes not just the physical address but also flags. Bits above the physical address width of the system i.e. above __PHYSICAL_MASK_SHIFT) are also not masked. - The PGD entry is masked by PAGE_SIZE which doesn't take into account the higher bits such as _PAGE_BIT_NOPTISHADOW. Replace this with proper accessor functions: - native_read_cr3_pa(): Uses CR3_ADDR_MASK to additionally mask metadata out of CR3 (like SME or LAM bits). All remaining bits are real address bits or reserved and must be 0. - mask pgd value with PTE_PFN_MASK instead of PAGE_MASK, accounting for flags above bit 51 (_PAGE_BIT_NOPTISHADOW in particular). Bits below 51, but above the max physical address are reserved and must be 0. Fixes: e9d0e6330eb8 ("x86/boot/compressed/64: Prepare new top-level page table for trampoline") Reported-by: Michael van der Westhuizen Reported-by: Tobias Fleig Co-developed-by: Kiryl Shutsemau Signed-off-by: Kiryl Shutsemau Signed-off-by: Usama Arif Signed-off-by: Borislav Petkov (AMD) Reviewed-by: Ard Biesheuvel Acked-by: Dave Hansen Link: https://lore.kernel.org/r/a482fd68-ce54-472d-8df1-33d6ac9f6bb5@intel.com Signed-off-by: Sasha Levin --- arch/x86/boot/compressed/pgtable_64.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/arch/x86/boot/compressed/pgtable_64.c b/arch/x86/boot/compressed/pgtable_64.c index bdd26050dff77..0e89e197e1126 100644 --- a/arch/x86/boot/compressed/pgtable_64.c +++ b/arch/x86/boot/compressed/pgtable_64.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include "../string.h" #include "efi.h" @@ -168,9 +169,10 @@ asmlinkage void configure_5level_paging(struct boot_params *bp, void *pgtable) * For 4- to 5-level paging transition, set up current CR3 as * the first and the only entry in a new top-level page table. */ - *trampoline_32bit = __native_read_cr3() | _PAGE_TABLE_NOENC; + *trampoline_32bit = native_read_cr3_pa() | _PAGE_TABLE_NOENC; } else { - unsigned long src; + u64 *new_cr3; + pgd_t *pgdp; /* * For 5- to 4-level paging transition, copy page table pointed @@ -180,8 +182,9 @@ asmlinkage void configure_5level_paging(struct boot_params *bp, void *pgtable) * We cannot just point to the page table from trampoline as it * may be above 4G. */ - src = *(unsigned long *)__native_read_cr3() & PAGE_MASK; - memcpy(trampoline_32bit, (void *)src, PAGE_SIZE); + pgdp = (pgd_t *)native_read_cr3_pa(); + new_cr3 = (u64 *)(native_pgd_val(pgdp[0]) & PTE_PFN_MASK); + memcpy(trampoline_32bit, new_cr3, PAGE_SIZE); } toggle_la57(trampoline_32bit); From a89d6e83f0e814bda39d073dc361457dd51ae3c3 Mon Sep 17 00:00:00 2001 From: Usama Arif Date: Mon, 3 Nov 2025 14:09:23 +0000 Subject: [PATCH 0589/2333] efi/libstub: Fix page table access in 5-level to 4-level paging transition [ Upstream commit 84361123413efc84b06f3441c6c827b95d902732 ] When transitioning from 5-level to 4-level paging, the existing code incorrectly accesses page table entries by directly dereferencing CR3 and applying PAGE_MASK. This approach has several issues: - __native_read_cr3() returns the raw CR3 register value, which on x86_64 includes not just the physical address but also flags Bits above the physical address width of the system (i.e. above __PHYSICAL_MASK_SHIFT) are also not masked. - The pgd value is masked by PAGE_SIZE which doesn't take into account the higher bits such as _PAGE_BIT_NOPTISHADOW. Replace this with proper accessor functions: - native_read_cr3_pa(): Uses CR3_ADDR_MASK to additionally mask metadata out of CR3 (like SME or LAM bits). All remaining bits are real address bits or reserved and must be 0. - mask pgd value with PTE_PFN_MASK instead of PAGE_MASK, accounting for flags above bit 51 (_PAGE_BIT_NOPTISHADOW in particular). Bits below 51, but above the max physical address are reserved and must be 0. Fixes: cb1c9e02b0c1 ("x86/efistub: Perform 4/5 level paging switch from the stub") Reported-by: Michael van der Westhuizen Reported-by: Tobias Fleig Co-developed-by: Kiryl Shutsemau Signed-off-by: Kiryl Shutsemau Signed-off-by: Usama Arif Signed-off-by: Borislav Petkov (AMD) Reviewed-by: Ard Biesheuvel Link: https://patch.msgid.link/20251103141002.2280812-3-usamaarif642@gmail.com Signed-off-by: Sasha Levin --- drivers/firmware/efi/libstub/x86-5lvl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/firmware/efi/libstub/x86-5lvl.c b/drivers/firmware/efi/libstub/x86-5lvl.c index f1c5fb45d5f7c..c00d0ae7ed5d5 100644 --- a/drivers/firmware/efi/libstub/x86-5lvl.c +++ b/drivers/firmware/efi/libstub/x86-5lvl.c @@ -66,7 +66,7 @@ void efi_5level_switch(void) bool have_la57 = native_read_cr4() & X86_CR4_LA57; bool need_toggle = want_la57 ^ have_la57; u64 *pgt = (void *)la57_toggle + PAGE_SIZE; - u64 *cr3 = (u64 *)__native_read_cr3(); + pgd_t *cr3 = (pgd_t *)native_read_cr3_pa(); u64 *new_cr3; if (!la57_toggle || !need_toggle) @@ -82,7 +82,7 @@ void efi_5level_switch(void) new_cr3[0] = (u64)cr3 | _PAGE_TABLE_NOENC; } else { /* take the new root table pointer from the current entry #0 */ - new_cr3 = (u64 *)(cr3[0] & PAGE_MASK); + new_cr3 = (u64 *)(native_pgd_val(cr3[0]) & PTE_PFN_MASK); /* copy the new root table if it is not 32-bit addressable */ if ((u64)new_cr3 > U32_MAX) From 9253f39bcf9af402a16ef6edd8bd502513bbef14 Mon Sep 17 00:00:00 2001 From: Wang Liang Date: Wed, 5 Nov 2025 12:19:56 -0800 Subject: [PATCH 0590/2333] locktorture: Fix memory leak in param_set_cpumask() [ Upstream commit e52b43883d084a9af263c573f2a1bd1ca5088389 ] With CONFIG_CPUMASK_OFFSTACK=y, the 'bind_writers' buffer is allocated via alloc_cpumask_var() in param_set_cpumask(). But it is not freed, when setting the module parameter multiple times by sysfs interface or removing module. Below kmemleak trace is seen for this issue: unreferenced object 0xffff888100aabff8 (size 8): comm "bash", pid 323, jiffies 4295059233 hex dump (first 8 bytes): 07 00 00 00 00 00 00 00 ........ backtrace (crc ac50919): __kmalloc_node_noprof+0x2e5/0x420 alloc_cpumask_var_node+0x1f/0x30 param_set_cpumask+0x26/0xb0 [locktorture] param_attr_store+0x93/0x100 module_attr_store+0x1b/0x30 kernfs_fop_write_iter+0x114/0x1b0 vfs_write+0x300/0x410 ksys_write+0x60/0xd0 do_syscall_64+0xa4/0x260 entry_SYSCALL_64_after_hwframe+0x77/0x7f This issue can be reproduced by: insmod locktorture.ko bind_writers=1 rmmod locktorture or: insmod locktorture.ko bind_writers=1 echo 2 > /sys/module/locktorture/parameters/bind_writers Considering that setting the module parameter 'bind_writers' or 'bind_readers' by sysfs interface has no real effect, set the parameter permissions to 0444. To fix the memory leak when removing module, free 'bind_writers' and 'bind_readers' memory in lock_torture_cleanup(). Fixes: 73e341242483 ("locktorture: Add readers_bind and writers_bind module parameters") Suggested-by: Zhang Changzhong Signed-off-by: Wang Liang Signed-off-by: Paul E. McKenney Signed-off-by: Frederic Weisbecker Signed-off-by: Sasha Levin --- kernel/locking/locktorture.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/kernel/locking/locktorture.c b/kernel/locking/locktorture.c index ce0362f0a8719..6567e5eeacc0e 100644 --- a/kernel/locking/locktorture.c +++ b/kernel/locking/locktorture.c @@ -103,8 +103,8 @@ static const struct kernel_param_ops lt_bind_ops = { .get = param_get_cpumask, }; -module_param_cb(bind_readers, <_bind_ops, &bind_readers, 0644); -module_param_cb(bind_writers, <_bind_ops, &bind_writers, 0644); +module_param_cb(bind_readers, <_bind_ops, &bind_readers, 0444); +module_param_cb(bind_writers, <_bind_ops, &bind_writers, 0444); long torture_sched_setaffinity(pid_t pid, const struct cpumask *in_mask, bool dowarn); @@ -1211,6 +1211,10 @@ static void lock_torture_cleanup(void) cxt.cur_ops->exit(); cxt.init_called = false; } + + free_cpumask_var(bind_readers); + free_cpumask_var(bind_writers); + torture_cleanup_end(); } From bcf44fe565bf1bf098fecd338a625db3180ec531 Mon Sep 17 00:00:00 2001 From: Fedor Pchelkin Date: Tue, 4 Nov 2025 16:57:08 +0300 Subject: [PATCH 0591/2333] wifi: rtw89: usb: use common error path for skbs in rtw89_usb_rx_handler() [ Upstream commit 28a45575289f3292aa9cb7bacae18ba3ee7a6adf ] Allow adding rx_skb to rx_free_queue for later reuse on the common error handling path, otherwise free it. Found by Linux Verification Center (linuxtesting.org). Fixes: 2135c28be6a8 ("wifi: rtw89: Add usb.{c,h}") Acked-by: Ping-Ke Shih Signed-off-by: Fedor Pchelkin Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20251104135720.321110-2-pchelkin@ispras.ru Signed-off-by: Sasha Levin --- drivers/net/wireless/realtek/rtw89/usb.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/usb.c b/drivers/net/wireless/realtek/rtw89/usb.c index 6cf89aee252ed..e8e064cf7e0ad 100644 --- a/drivers/net/wireless/realtek/rtw89/usb.c +++ b/drivers/net/wireless/realtek/rtw89/usb.c @@ -410,8 +410,7 @@ static void rtw89_usb_rx_handler(struct work_struct *work) if (skb_queue_len(&rtwusb->rx_queue) >= RTW89_USB_MAX_RXQ_LEN) { rtw89_warn(rtwdev, "rx_queue overflow\n"); - dev_kfree_skb_any(rx_skb); - continue; + goto free_or_reuse; } memset(&desc_info, 0, sizeof(desc_info)); @@ -422,7 +421,7 @@ static void rtw89_usb_rx_handler(struct work_struct *work) rtw89_debug(rtwdev, RTW89_DBG_HCI, "failed to allocate RX skb of size %u\n", desc_info.pkt_size); - continue; + goto free_or_reuse; } pkt_offset = desc_info.offset + desc_info.rxd_len; @@ -432,6 +431,7 @@ static void rtw89_usb_rx_handler(struct work_struct *work) rtw89_core_rx(rtwdev, &desc_info, skb); +free_or_reuse: if (skb_queue_len(&rtwusb->rx_free_queue) >= RTW89_USB_RX_SKB_NUM) dev_kfree_skb_any(rx_skb); else From 87cc6fe79c3e5a4760c396fb715dc8b137ffe149 Mon Sep 17 00:00:00 2001 From: Fedor Pchelkin Date: Tue, 4 Nov 2025 16:57:09 +0300 Subject: [PATCH 0592/2333] wifi: rtw89: usb: fix leak in rtw89_usb_write_port() [ Upstream commit 7543818e97d5d54b3b2f75f1c4dedee298d7d914 ] When there is an attempt to write data and RTW89_FLAG_UNPLUGGED is set, this means device is disconnected and no urb is submitted. Return appropriate error code to the caller to properly free the allocated resources. Found by Linux Verification Center (linuxtesting.org). Fixes: 2135c28be6a8 ("wifi: rtw89: Add usb.{c,h}") Acked-by: Ping-Ke Shih Signed-off-by: Fedor Pchelkin Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20251104135720.321110-3-pchelkin@ispras.ru Signed-off-by: Sasha Levin --- drivers/net/wireless/realtek/rtw89/usb.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/usb.c b/drivers/net/wireless/realtek/rtw89/usb.c index e8e064cf7e0ad..512a46dd9d06a 100644 --- a/drivers/net/wireless/realtek/rtw89/usb.c +++ b/drivers/net/wireless/realtek/rtw89/usb.c @@ -256,7 +256,7 @@ static int rtw89_usb_write_port(struct rtw89_dev *rtwdev, u8 ch_dma, int ret; if (test_bit(RTW89_FLAG_UNPLUGGED, rtwdev->flags)) - return 0; + return -ENODEV; urb = usb_alloc_urb(0, GFP_ATOMIC); if (!urb) @@ -305,8 +305,9 @@ static void rtw89_usb_ops_tx_kick_off(struct rtw89_dev *rtwdev, u8 txch) ret = rtw89_usb_write_port(rtwdev, txch, skb->data, skb->len, txcb); if (ret) { - rtw89_err(rtwdev, "write port txch %d failed: %d\n", - txch, ret); + if (ret != -ENODEV) + rtw89_err(rtwdev, "write port txch %d failed: %d\n", + txch, ret); skb_dequeue(&txcb->tx_ack_queue); kfree(txcb); From 9922a95abfc1b13d49cd07343fa5268cabee3bf1 Mon Sep 17 00:00:00 2001 From: Haotian Zhang Date: Fri, 10 Oct 2025 09:17:36 +0800 Subject: [PATCH 0593/2333] mfd: da9055: Fix missing regmap_del_irq_chip() in error path [ Upstream commit 1b58acfd067ca16116b9234cd6b2d30cc8ab7502 ] When da9055_device_init() fails after regmap_add_irq_chip() succeeds but mfd_add_devices() fails, the error handling path only calls mfd_remove_devices() but forgets to call regmap_del_irq_chip(). This results in a resource leak. Fix this by adding regmap_del_irq_chip() to the error path so that resources are released properly. Fixes: 2896434cf272 ("mfd: DA9055 core driver") Signed-off-by: Haotian Zhang Link: https://patch.msgid.link/20251010011737.1078-1-vulab@iscas.ac.cn Signed-off-by: Lee Jones Signed-off-by: Sasha Levin --- drivers/mfd/da9055-core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mfd/da9055-core.c b/drivers/mfd/da9055-core.c index 1f727ef60d638..8c989b74f924e 100644 --- a/drivers/mfd/da9055-core.c +++ b/drivers/mfd/da9055-core.c @@ -388,6 +388,7 @@ int da9055_device_init(struct da9055 *da9055) err: mfd_remove_devices(da9055->dev); + regmap_del_irq_chip(da9055->chip_irq, da9055->irq_data); return ret; } From c7ca777c58795d0940891ae3577f629c85311d61 Mon Sep 17 00:00:00 2001 From: Manish Dharanenthiran Date: Fri, 31 Oct 2025 08:37:46 +0530 Subject: [PATCH 0594/2333] wifi: ath12k: Fix timeout error during beacon stats retrieval [ Upstream commit 2977567b244f056d86658160659f06cd6c78ba3d ] Currently, for beacon_stats, ath12k_mac_get_fw_stats() is called for each started BSS on the specified hardware. ath12k_mac_get_fw_stats() will wait for the fw_stats_done completion after fetching the requested data from firmware. For the beacon_stats, fw_stats_done completion will be set only when stats are received for all BSSes. However, for other stats like vdev_stats or pdev_stats, there is one request to the firmware for all enabled BSSes. Since beacon_stats is fetched individually for all BSSes enabled in that pdev, waiting for the completion event results in a timeout error when multiple BSSes are enabled. Avoid this by completing the fw_stats_done immediately after updating the requested BSS's beacon stats in the list. Subsequently, this list will be used to display the beacon stats for all enabled BSSes in the requested pdev. Additionally, remove 'num_bcn_recvd' from the ath12k_fw_stats struct as it is no longer needed. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.4.1-00199-QCAHKSWPL_SILICONZ-1 Fixes: 9fe4669ae919 ("wifi: ath12k: Request beacon stats from firmware") Signed-off-by: Manish Dharanenthiran Reviewed-by: Vasanthakumar Thiagarajan Reviewed-by: Baochen Qiang Link: https://patch.msgid.link/20251031-beacon_stats-v1-2-f52fce7b03ac@qti.qualcomm.com Signed-off-by: Jeff Johnson Signed-off-by: Sasha Levin --- drivers/net/wireless/ath/ath12k/core.c | 2 -- drivers/net/wireless/ath/ath12k/core.h | 1 - drivers/net/wireless/ath/ath12k/wmi.c | 10 +--------- 3 files changed, 1 insertion(+), 12 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c index a2137b363c2fe..cc352eef19399 100644 --- a/drivers/net/wireless/ath/ath12k/core.c +++ b/drivers/net/wireless/ath/ath12k/core.c @@ -1,7 +1,6 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ @@ -1250,7 +1249,6 @@ void ath12k_fw_stats_reset(struct ath12k *ar) spin_lock_bh(&ar->data_lock); ath12k_fw_stats_free(&ar->fw_stats); ar->fw_stats.num_vdev_recvd = 0; - ar->fw_stats.num_bcn_recvd = 0; spin_unlock_bh(&ar->data_lock); } diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index 3d1956966a485..d7688b383f62c 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -644,7 +644,6 @@ struct ath12k_fw_stats { struct list_head vdevs; struct list_head bcn; u32 num_vdev_recvd; - u32 num_bcn_recvd; }; struct ath12k_dbg_htt_stats { diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index e76275bd6916f..e647b842a6a1c 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -8418,18 +8418,10 @@ static void ath12k_wmi_fw_stats_process(struct ath12k *ar, ath12k_warn(ab, "empty beacon stats"); return; } - /* Mark end until we reached the count of all started VDEVs - * within the PDEV - */ - if (ar->num_started_vdevs) - is_end = ((++ar->fw_stats.num_bcn_recvd) == - ar->num_started_vdevs); list_splice_tail_init(&stats->bcn, &ar->fw_stats.bcn); - - if (is_end) - complete(&ar->fw_stats_done); + complete(&ar->fw_stats_done); } } From c94c069c0b120af7b698542d0d10597b618aa395 Mon Sep 17 00:00:00 2001 From: Zhang Yi Date: Mon, 13 Oct 2025 09:51:17 +0800 Subject: [PATCH 0595/2333] ext4: correct the checking of quota files before moving extents [ Upstream commit a2e5a3cea4b18f6e2575acc444a5e8cce1fc8260 ] The move extent operation should return -EOPNOTSUPP if any of the inodes is a quota inode, rather than requiring both to be quota inodes. Fixes: 02749a4c2082 ("ext4: add ext4_is_quota_file()") Signed-off-by: Zhang Yi Reviewed-by: Jan Kara Message-ID: <20251013015128.499308-2-yi.zhang@huaweicloud.com> Signed-off-by: Theodore Ts'o Signed-off-by: Sasha Levin --- fs/ext4/move_extent.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/ext4/move_extent.c b/fs/ext4/move_extent.c index 4b091c21908fd..0f4b7c89edd39 100644 --- a/fs/ext4/move_extent.c +++ b/fs/ext4/move_extent.c @@ -485,7 +485,7 @@ mext_check_arguments(struct inode *orig_inode, return -ETXTBSY; } - if (ext4_is_quota_file(orig_inode) && ext4_is_quota_file(donor_inode)) { + if (ext4_is_quota_file(orig_inode) || ext4_is_quota_file(donor_inode)) { ext4_debug("ext4 move extent: The argument files should not be quota files [ino:orig %lu, donor %lu]\n", orig_inode->i_ino, donor_inode->i_ino); return -EOPNOTSUPP; From ba2726d43d3b33c36a75707086c15c35afcbb82e Mon Sep 17 00:00:00 2001 From: Lizhi Hou Date: Wed, 5 Nov 2025 11:41:40 -0800 Subject: [PATCH 0596/2333] accel/amdxdna: Fix dma_fence leak when job is canceled [ Upstream commit dea9f84776b96a703f504631ebe9fea07bd2c181 ] Currently, dma_fence_put(job->fence) is called in job notification callback. However, if a job is canceled, the notification callback is never invoked, leading to a memory leak. Move dma_fence_put(job->fence) to the job cleanup function to ensure the fence is always released. Fixes: aac243092b70 ("accel/amdxdna: Add command execution") Reviewed-by: Mario Limonciello (AMD) Signed-off-by: Lizhi Hou Link: https://patch.msgid.link/20251105194140.1004314-1-lizhi.hou@amd.com Signed-off-by: Sasha Levin --- drivers/accel/amdxdna/aie2_ctx.c | 1 - drivers/accel/amdxdna/amdxdna_ctx.c | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/accel/amdxdna/aie2_ctx.c b/drivers/accel/amdxdna/aie2_ctx.c index c9f712f0ec00c..2e479a8d86c31 100644 --- a/drivers/accel/amdxdna/aie2_ctx.c +++ b/drivers/accel/amdxdna/aie2_ctx.c @@ -189,7 +189,6 @@ aie2_sched_notify(struct amdxdna_sched_job *job) up(&job->hwctx->priv->job_sem); job->job_done = true; - dma_fence_put(fence); mmput_async(job->mm); aie2_job_put(job); } diff --git a/drivers/accel/amdxdna/amdxdna_ctx.c b/drivers/accel/amdxdna/amdxdna_ctx.c index 4bfe4ef20550f..856fb25086f12 100644 --- a/drivers/accel/amdxdna/amdxdna_ctx.c +++ b/drivers/accel/amdxdna/amdxdna_ctx.c @@ -389,6 +389,7 @@ void amdxdna_sched_job_cleanup(struct amdxdna_sched_job *job) trace_amdxdna_debug_point(job->hwctx->name, job->seq, "job release"); amdxdna_arg_bos_put(job); amdxdna_gem_put_obj(job->cmd_bo); + dma_fence_put(job->fence); } int amdxdna_cmd_submit(struct amdxdna_client *client, From 40a1e0142096dd7dd6cb5373841222b528698588 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 3 Oct 2025 12:30:43 +0300 Subject: [PATCH 0597/2333] hfs: fix potential use after free in hfs_correct_next_unused_CNID() [ Upstream commit c105e76bb17cf4b55fe89c6ad4f6a0e3972b5b08 ] This code calls hfs_bnode_put(node) which drops the refcount and then dreferences "node" on the next line. It's only safe to use "node" when we're holding a reference so flip these two lines around. Fixes: a06ec283e125 ("hfs: add logic of correcting a next unused CNID") Signed-off-by: Dan Carpenter Reviewed-by: Viacheslav Dubeyko Signed-off-by: Viacheslav Dubeyko Link: https://lore.kernel.org/r/aN-Xw8KnbSnuIcLk@stanley.mountain Signed-off-by: Viacheslav Dubeyko Signed-off-by: Sasha Levin --- fs/hfs/catalog.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/hfs/catalog.c b/fs/hfs/catalog.c index caebabb6642f1..b80ba40e38776 100644 --- a/fs/hfs/catalog.c +++ b/fs/hfs/catalog.c @@ -322,9 +322,9 @@ int hfs_correct_next_unused_CNID(struct super_block *sb, u32 cnid) } } + node_id = node->prev; hfs_bnode_put(node); - node_id = node->prev; } while (node_id >= leaf_head); return -ENOENT; From b9422f46d9c54d0b67ea650ae083f766e6e58e9f Mon Sep 17 00:00:00 2001 From: FUKAUMI Naoki Date: Tue, 4 Nov 2025 08:52:27 +0000 Subject: [PATCH 0598/2333] arm64: dts: rockchip: Fix USB Type-C host mode for Radxa ROCK 5B+/5T [ Upstream commit fbf90d1b697faf61bb8b3ed72be6a8ebeb09de3d ] The Radxa ROCK 5B+/5T USB Type-C port supports Dual Role Data and should also act as a host. However, currently, when acting as a host, only self-powered devices work. Since the ROCK 5B+ supports Dual Role Power, set the power-role property to "dual" and the try-power-role property to "sink". (along with related properties) The ROCK 5T should only support the "source" power-role. This allows the port to act as a host, supply power to the port, and allow bus-powered devices to work. Note that on the ROCK 5T, with this patch applied, it has been observed that some bus-powered devices do not work correctly. Also, it has been observed that after connecting a device (and the data-role switches to host), connecting a host device does not switch the data-role back to the device role. These issues should be addressed separately. Note that there is a separate known issue where USB 3.0 SuperSpeed devices do not work when oriented in reverse. This issue should also be addressed separately. (USB 2.0/1.1 devices work in both orientations) Fixes: 67b2c15d8fb3c ("arm64: dts: rockchip: add USB-C support for ROCK 5B/5B+/5T") Signed-off-by: FUKAUMI Naoki Link: https://patch.msgid.link/20251104085227.820-1-naoki@radxa.com Signed-off-by: Heiko Stuebner Signed-off-by: Sasha Levin --- arch/arm64/boot/dts/rockchip/rk3588-rock-5b-5bp-5t.dtsi | 4 ++-- arch/arm64/boot/dts/rockchip/rk3588-rock-5b-plus.dts | 5 +++++ arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dts | 4 ++++ arch/arm64/boot/dts/rockchip/rk3588-rock-5t.dts | 4 ++++ 4 files changed, 15 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/rockchip/rk3588-rock-5b-5bp-5t.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-rock-5b-5bp-5t.dtsi index 3bbe78810ec6f..7aac77dfc5f16 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-rock-5b-5bp-5t.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588-rock-5b-5bp-5t.dtsi @@ -331,12 +331,12 @@ data-role = "dual"; /* fusb302 supports PD Rev 2.0 Ver 1.2 */ pd-revision = /bits/ 8 <0x2 0x0 0x1 0x2>; - power-role = "sink"; - try-power-role = "sink"; op-sink-microwatt = <1000000>; sink-pdos = , ; + source-pdos = + ; altmodes { displayport { diff --git a/arch/arm64/boot/dts/rockchip/rk3588-rock-5b-plus.dts b/arch/arm64/boot/dts/rockchip/rk3588-rock-5b-plus.dts index 5e984a44120e4..07a840d9b3859 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-rock-5b-plus.dts +++ b/arch/arm64/boot/dts/rockchip/rk3588-rock-5b-plus.dts @@ -110,6 +110,11 @@ }; }; +&usb_con { + power-role = "dual"; + try-power-role = "sink"; +}; + &usbdp_phy0 { pinctrl-names = "default"; pinctrl-0 = <&usbc_sbu_dc>; diff --git a/arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dts b/arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dts index 8ef01010d985b..da13dafcbc823 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dts +++ b/arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dts @@ -49,6 +49,10 @@ }; }; +&usb_con { + power-role = "sink"; +}; + &usbdp_phy0 { pinctrl-names = "default"; pinctrl-0 = <&usbc_sbu_dc>; diff --git a/arch/arm64/boot/dts/rockchip/rk3588-rock-5t.dts b/arch/arm64/boot/dts/rockchip/rk3588-rock-5t.dts index c1763835f53d4..0dd90c744380b 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-rock-5t.dts +++ b/arch/arm64/boot/dts/rockchip/rk3588-rock-5t.dts @@ -130,6 +130,10 @@ }; }; +&usb_con { + power-role = "source"; +}; + &usbdp_phy0 { pinctrl-names = "default"; pinctrl-0 = <&usbc_sbu_dc>; From e2a1f510e5990d0cc507ffc3d15f981b753ff7df Mon Sep 17 00:00:00 2001 From: Pavel Begunkov Date: Thu, 6 Nov 2025 12:58:19 +0000 Subject: [PATCH 0599/2333] io_uring: use WRITE_ONCE for user shared memory [ Upstream commit 93e197e524b14d185d011813b72773a1a49d932d ] IORING_SETUP_NO_MMAP rings remain user accessible even before the ctx setup is finalised, so use WRITE_ONCE consistently when initialising rings. Fixes: 03d89a2de25bb ("io_uring: support for user allocated memory for rings/sqes") Signed-off-by: Pavel Begunkov Signed-off-by: Jens Axboe Signed-off-by: Sasha Levin --- io_uring/io_uring.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/io_uring/io_uring.c b/io_uring/io_uring.c index 02339b74ba8d4..765abec2571f0 100644 --- a/io_uring/io_uring.c +++ b/io_uring/io_uring.c @@ -3623,10 +3623,6 @@ static __cold int io_allocate_scq_urings(struct io_ring_ctx *ctx, if (!(ctx->flags & IORING_SETUP_NO_SQARRAY)) ctx->sq_array = (u32 *)((char *)rings + sq_array_offset); - rings->sq_ring_mask = p->sq_entries - 1; - rings->cq_ring_mask = p->cq_entries - 1; - rings->sq_ring_entries = p->sq_entries; - rings->cq_ring_entries = p->cq_entries; if (p->flags & IORING_SETUP_SQE128) size = array_size(2 * sizeof(struct io_uring_sqe), p->sq_entries); @@ -3649,6 +3645,12 @@ static __cold int io_allocate_scq_urings(struct io_ring_ctx *ctx, return ret; } ctx->sq_sqes = io_region_get_ptr(&ctx->sq_region); + + memset(rings, 0, sizeof(*rings)); + WRITE_ONCE(rings->sq_ring_mask, ctx->sq_entries - 1); + WRITE_ONCE(rings->cq_ring_mask, ctx->cq_entries - 1); + WRITE_ONCE(rings->sq_ring_entries, ctx->sq_entries); + WRITE_ONCE(rings->cq_ring_entries, ctx->cq_entries); return 0; } From 6b089028bff1f2ff9e0c62b8f1faca1a620e5d6e Mon Sep 17 00:00:00 2001 From: Dapeng Mi Date: Wed, 29 Oct 2025 18:21:26 +0800 Subject: [PATCH 0600/2333] perf/x86: Fix NULL event access and potential PEBS record loss [ Upstream commit 7e772a93eb61cb6265bdd1c5bde17d0f2718b452 ] When intel_pmu_drain_pebs_icl() is called to drain PEBS records, the perf_event_overflow() could be called to process the last PEBS record. While perf_event_overflow() could trigger the interrupt throttle and stop all events of the group, like what the below call-chain shows. perf_event_overflow() -> __perf_event_overflow() ->__perf_event_account_interrupt() -> perf_event_throttle_group() -> perf_event_throttle() -> event->pmu->stop() -> x86_pmu_stop() The side effect of stopping the events is that all corresponding event pointers in cpuc->events[] array are cleared to NULL. Assume there are two PEBS events (event a and event b) in a group. When intel_pmu_drain_pebs_icl() calls perf_event_overflow() to process the last PEBS record of PEBS event a, interrupt throttle is triggered and all pointers of event a and event b are cleared to NULL. Then intel_pmu_drain_pebs_icl() tries to process the last PEBS record of event b and encounters NULL pointer access. To avoid this issue, move cpuc->events[] clearing from x86_pmu_stop() to x86_pmu_del(). It's safe since cpuc->active_mask or cpuc->pebs_enabled is always checked before access the event pointer from cpuc->events[]. Closes: https://lore.kernel.org/oe-lkp/202507042103.a15d2923-lkp@intel.com Fixes: 9734e25fbf5a ("perf: Fix the throttle logic for a group") Reported-by: kernel test robot Suggested-by: Peter Zijlstra Signed-off-by: Dapeng Mi Signed-off-by: Peter Zijlstra (Intel) Link: https://patch.msgid.link/20251029102136.61364-3-dapeng1.mi@linux.intel.com Signed-off-by: Sasha Levin --- arch/x86/events/core.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c index fa6c47b509897..dd9ff120ad437 100644 --- a/arch/x86/events/core.c +++ b/arch/x86/events/core.c @@ -1344,6 +1344,7 @@ static void x86_pmu_enable(struct pmu *pmu) hwc->state |= PERF_HES_ARCH; x86_pmu_stop(event, PERF_EF_UPDATE); + cpuc->events[hwc->idx] = NULL; } /* @@ -1365,6 +1366,7 @@ static void x86_pmu_enable(struct pmu *pmu) * if cpuc->enabled = 0, then no wrmsr as * per x86_pmu_enable_event() */ + cpuc->events[hwc->idx] = event; x86_pmu_start(event, PERF_EF_RELOAD); } cpuc->n_added = 0; @@ -1531,7 +1533,6 @@ static void x86_pmu_start(struct perf_event *event, int flags) event->hw.state = 0; - cpuc->events[idx] = event; __set_bit(idx, cpuc->active_mask); static_call(x86_pmu_enable)(event); perf_event_update_userpage(event); @@ -1610,7 +1611,6 @@ void x86_pmu_stop(struct perf_event *event, int flags) if (test_bit(hwc->idx, cpuc->active_mask)) { static_call(x86_pmu_disable)(event); __clear_bit(hwc->idx, cpuc->active_mask); - cpuc->events[hwc->idx] = NULL; WARN_ON_ONCE(hwc->state & PERF_HES_STOPPED); hwc->state |= PERF_HES_STOPPED; } @@ -1648,6 +1648,7 @@ static void x86_pmu_del(struct perf_event *event, int flags) * Not a TXN, therefore cleanup properly. */ x86_pmu_stop(event, PERF_EF_UPDATE); + cpuc->events[event->hw.idx] = NULL; for (i = 0; i < cpuc->n_events; i++) { if (event == cpuc->event_list[i]) From 16d8e53a8f78f24f20b12feed26e7e1b1d056bb0 Mon Sep 17 00:00:00 2001 From: Dapeng Mi Date: Wed, 29 Oct 2025 18:21:28 +0800 Subject: [PATCH 0601/2333] perf/x86/intel: Correct large PEBS flag check [ Upstream commit 5e4e355ae7cdeb0fef5dbe908866e1f895abfacc ] current large PEBS flag check only checks if sample_regs_user contains unsupported GPRs but doesn't check if sample_regs_intr contains unsupported GPRs. Of course, currently PEBS HW supports to sample all perf supported GPRs, the missed check doesn't cause real issue. But it won't be true any more after the subsequent patches support to sample SSP register. SSP sampling is not supported by adaptive PEBS HW and it would be supported until arch-PEBS HW. So correct this issue. Fixes: a47ba4d77e12 ("perf/x86: Enable free running PEBS for REGS_USER/INTR") Signed-off-by: Dapeng Mi Signed-off-by: Peter Zijlstra (Intel) Link: https://patch.msgid.link/20251029102136.61364-5-dapeng1.mi@linux.intel.com Signed-off-by: Sasha Levin --- arch/x86/events/intel/core.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c index fe65be0b9d9c4..9b824ed6fc1de 100644 --- a/arch/x86/events/intel/core.c +++ b/arch/x86/events/intel/core.c @@ -4029,7 +4029,9 @@ static unsigned long intel_pmu_large_pebs_flags(struct perf_event *event) if (!event->attr.exclude_kernel) flags &= ~PERF_SAMPLE_REGS_USER; if (event->attr.sample_regs_user & ~PEBS_GP_REGS) - flags &= ~(PERF_SAMPLE_REGS_USER | PERF_SAMPLE_REGS_INTR); + flags &= ~PERF_SAMPLE_REGS_USER; + if (event->attr.sample_regs_intr & ~PEBS_GP_REGS) + flags &= ~PERF_SAMPLE_REGS_INTR; return flags; } From 10be1301ae69df4db775b269cdf56dbb9d3d588b Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Fri, 7 Nov 2025 18:10:08 +0100 Subject: [PATCH 0602/2333] regulator: core: disable supply if enabling main regulator fails [ Upstream commit fb1ebb10468da414d57153ddebaab29c38ef1a78 ] For 'always-on' and 'boot-on' regulators, the set_machine_constraints() may enable supply before enabling the main regulator, however if the latter fails, the function returns with an error but the supply remains enabled. When this happens, the regulator_register() function continues on the error path where it puts the supply regulator. Since enabling the supply is not balanced with a disable call, a warning similar to the following gets issued from _regulator_put(): [ 1.603889] WARNING: CPU: 2 PID: 44 at _regulator_put+0x8c/0xa0 [ 1.603908] Modules linked in: [ 1.603926] CPU: 2 UID: 0 PID: 44 Comm: kworker/u16:3 Not tainted 6.18.0-rc4 #0 NONE [ 1.603938] Hardware name: Qualcomm Technologies, Inc. IPQ9574/AP-AL02-C7 (DT) [ 1.603945] Workqueue: async async_run_entry_fn [ 1.603958] pstate: 60400005 (nZCv daif +PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 1.603967] pc : _regulator_put+0x8c/0xa0 [ 1.603976] lr : _regulator_put+0x7c/0xa0 ... [ 1.604140] Call trace: [ 1.604145] _regulator_put+0x8c/0xa0 (P) [ 1.604156] regulator_register+0x2ec/0xbf0 [ 1.604166] devm_regulator_register+0x60/0xb0 [ 1.604178] rpm_reg_probe+0x120/0x208 [ 1.604187] platform_probe+0x64/0xa8 ... In order to avoid this, change the set_machine_constraints() function to disable the supply if enabling the main regulator fails. Fixes: 05f224ca6693 ("regulator: core: Clean enabling always-on regulators + their supplies") Signed-off-by: Gabor Juhos Link: https://patch.msgid.link/20251107-regulator-disable-supply-v1-1-c95f0536f1b5@gmail.com Signed-off-by: Mark Brown Signed-off-by: Sasha Levin --- drivers/regulator/core.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index dd7b10e768c06..fc93612f4ec0c 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -1618,6 +1618,8 @@ static int set_machine_constraints(struct regulator_dev *rdev) * and we have control then make sure it is enabled. */ if (rdev->constraints->always_on || rdev->constraints->boot_on) { + bool supply_enabled = false; + /* If we want to enable this regulator, make sure that we know * the supplying regulator. */ @@ -1637,11 +1639,14 @@ static int set_machine_constraints(struct regulator_dev *rdev) rdev->supply = NULL; return ret; } + supply_enabled = true; } ret = _regulator_do_enable(rdev); if (ret < 0 && ret != -EINVAL) { rdev_err(rdev, "failed to enable: %pe\n", ERR_PTR(ret)); + if (supply_enabled) + regulator_disable(rdev->supply); return ret; } From 59392f424f8442a4533abc1515e79ae5dc3b89a4 Mon Sep 17 00:00:00 2001 From: Xiao Ni Date: Sun, 28 Sep 2025 09:24:24 +0800 Subject: [PATCH 0603/2333] md: delete mddev kobj before deleting gendisk kobj [ Upstream commit cc394b94dc40b661efc9895665abf03640ffff2d ] In sync del gendisk path, it deletes gendisk first and the directory /sys/block/md is removed. Then it releases mddev kobj in a delayed work. If we enable debug log in sysfs_remove_group, we can see the debug log 'sysfs group bitmap not found for kobject md'. It's the reason that the parent kobj has been deleted, so it can't find parent directory. In creating path, it allocs gendisk first, then adds mddev kobj. So it should delete mddev kobj before deleting gendisk. Before commit 9e59d609763f ("md: call del_gendisk in control path"), it releases mddev kobj first. If the kobj hasn't been deleted, it does clean job and deletes the kobj. Then it calls del_gendisk and releases gendisk kobj. So it doesn't need to call kobject_del to delete mddev kobj. After this patch, in sync del gendisk path, the sequence changes. So it needs to call kobject_del to delete mddev kobj. After this patch, the sequence is: 1. kobject del mddev kobj 2. del_gendisk deletes gendisk kobj 3. mddev_delayed_delete releases mddev kobj 4. md_kobj_release releases gendisk kobj Link: https://lore.kernel.org/linux-raid/20250928012424.61370-1-xni@redhat.com Fixes: 9e59d609763f ("md: call del_gendisk in control path") Signed-off-by: Xiao Ni Reviewed-by: Li Nan Signed-off-by: Yu Kuai Signed-off-by: Sasha Levin --- drivers/md/md.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/md/md.c b/drivers/md/md.c index 41c476b40c7a3..8128c8839a082 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -941,8 +941,10 @@ void mddev_unlock(struct mddev *mddev) * do_md_stop. dm raid only uses md_stop to stop. So dm raid * doesn't need to check MD_DELETED when getting reconfig lock */ - if (test_bit(MD_DELETED, &mddev->flags)) + if (test_bit(MD_DELETED, &mddev->flags)) { + kobject_del(&mddev->kobj); del_gendisk(mddev->gendisk); + } } } EXPORT_SYMBOL_GPL(mddev_unlock); From f98b191f78124405294481dea85f8a22a3eb0a59 Mon Sep 17 00:00:00 2001 From: Yun Zhou Date: Wed, 15 Oct 2025 16:32:27 +0800 Subject: [PATCH 0604/2333] md: fix rcu protection in md_wakeup_thread [ Upstream commit 0dc76205549b4c25705e54345f211b9f66e018a0 ] We attempted to use RCU to protect the pointer 'thread', but directly passed the value when calling md_wakeup_thread(). This means that the RCU pointer has been acquired before rcu_read_lock(), which renders rcu_read_lock() ineffective and could lead to a use-after-free. Link: https://lore.kernel.org/linux-raid/20251015083227.1079009-1-yun.zhou@windriver.com Fixes: 446931543982 ("md: protect md_thread with rcu") Signed-off-by: Yun Zhou Reviewed-by: Li Nan Reviewed-by: Yu Kuai Signed-off-by: Yu Kuai Signed-off-by: Sasha Levin --- drivers/md/md.c | 14 ++++++-------- drivers/md/md.h | 8 +++++++- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/drivers/md/md.c b/drivers/md/md.c index 8128c8839a082..6062e0deb6160 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -99,7 +99,7 @@ static int remove_and_add_spares(struct mddev *mddev, struct md_rdev *this); static void mddev_detach(struct mddev *mddev); static void export_rdev(struct md_rdev *rdev, struct mddev *mddev); -static void md_wakeup_thread_directly(struct md_thread __rcu *thread); +static void md_wakeup_thread_directly(struct md_thread __rcu **thread); /* * Default number of read corrections we'll attempt on an rdev @@ -5136,7 +5136,7 @@ static void stop_sync_thread(struct mddev *mddev, bool locked) * Thread might be blocked waiting for metadata update which will now * never happen */ - md_wakeup_thread_directly(mddev->sync_thread); + md_wakeup_thread_directly(&mddev->sync_thread); if (work_pending(&mddev->sync_work)) flush_work(&mddev->sync_work); @@ -8375,22 +8375,21 @@ static int md_thread(void *arg) return 0; } -static void md_wakeup_thread_directly(struct md_thread __rcu *thread) +static void md_wakeup_thread_directly(struct md_thread __rcu **thread) { struct md_thread *t; rcu_read_lock(); - t = rcu_dereference(thread); + t = rcu_dereference(*thread); if (t) wake_up_process(t->tsk); rcu_read_unlock(); } -void md_wakeup_thread(struct md_thread __rcu *thread) +void __md_wakeup_thread(struct md_thread __rcu *thread) { struct md_thread *t; - rcu_read_lock(); t = rcu_dereference(thread); if (t) { pr_debug("md: waking up MD thread %s.\n", t->tsk->comm); @@ -8398,9 +8397,8 @@ void md_wakeup_thread(struct md_thread __rcu *thread) if (wq_has_sleeper(&t->wqueue)) wake_up(&t->wqueue); } - rcu_read_unlock(); } -EXPORT_SYMBOL(md_wakeup_thread); +EXPORT_SYMBOL(__md_wakeup_thread); struct md_thread *md_register_thread(void (*run) (struct md_thread *), struct mddev *mddev, const char *name) diff --git a/drivers/md/md.h b/drivers/md/md.h index 1979c2d4fe89e..5d5f780b84477 100644 --- a/drivers/md/md.h +++ b/drivers/md/md.h @@ -882,6 +882,12 @@ struct md_io_clone { #define THREAD_WAKEUP 0 +#define md_wakeup_thread(thread) do { \ + rcu_read_lock(); \ + __md_wakeup_thread(thread); \ + rcu_read_unlock(); \ +} while (0) + static inline void safe_put_page(struct page *p) { if (p) put_page(p); @@ -895,7 +901,7 @@ extern struct md_thread *md_register_thread( struct mddev *mddev, const char *name); extern void md_unregister_thread(struct mddev *mddev, struct md_thread __rcu **threadp); -extern void md_wakeup_thread(struct md_thread __rcu *thread); +extern void __md_wakeup_thread(struct md_thread __rcu *thread); extern void md_check_recovery(struct mddev *mddev); extern void md_reap_sync_thread(struct mddev *mddev); extern enum sync_action md_sync_action(struct mddev *mddev); From f0fae1debeb9102398ddf2ef69b4f5d395afafed Mon Sep 17 00:00:00 2001 From: Xiao Ni Date: Wed, 29 Oct 2025 14:34:19 +0800 Subject: [PATCH 0605/2333] md: avoid repeated calls to del_gendisk [ Upstream commit 90e3bb44c0a86e245d8e5c6520206fa113acb1ee ] There is a uaf problem which is found by case 23rdev-lifetime: Oops: general protection fault, probably for non-canonical address 0xdead000000000122 RIP: 0010:bdi_unregister+0x4b/0x170 Call Trace: __del_gendisk+0x356/0x3e0 mddev_unlock+0x351/0x360 rdev_attr_store+0x217/0x280 kernfs_fop_write_iter+0x14a/0x210 vfs_write+0x29e/0x550 ksys_write+0x74/0xf0 do_syscall_64+0xbb/0x380 entry_SYSCALL_64_after_hwframe+0x77/0x7f RIP: 0033:0x7ff5250a177e The sequence is: 1. rdev remove path gets reconfig_mutex 2. rdev remove path release reconfig_mutex in mddev_unlock 3. md stop calls do_md_stop and sets MD_DELETED 4. rdev remove path calls del_gendisk because MD_DELETED is set 5. md stop path release reconfig_mutex and calls del_gendisk again So there is a race condition we should resolve. This patch adds a flag MD_DO_DELETE to avoid the race condition. Link: https://lore.kernel.org/linux-raid/20251029063419.21700-1-xni@redhat.com Fixes: 9e59d609763f ("md: call del_gendisk in control path") Signed-off-by: Xiao Ni Suggested-by: Yu Kuai Reviewed-by: Li Nan Signed-off-by: Yu Kuai Signed-off-by: Sasha Levin --- drivers/md/md.c | 3 ++- drivers/md/md.h | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/md/md.c b/drivers/md/md.c index 6062e0deb6160..5d40beaecc9c7 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -941,7 +941,8 @@ void mddev_unlock(struct mddev *mddev) * do_md_stop. dm raid only uses md_stop to stop. So dm raid * doesn't need to check MD_DELETED when getting reconfig lock */ - if (test_bit(MD_DELETED, &mddev->flags)) { + if (test_bit(MD_DELETED, &mddev->flags) && + !test_and_set_bit(MD_DO_DELETE, &mddev->flags)) { kobject_del(&mddev->kobj); del_gendisk(mddev->gendisk); } diff --git a/drivers/md/md.h b/drivers/md/md.h index 5d5f780b84477..fd6e001c1d38f 100644 --- a/drivers/md/md.h +++ b/drivers/md/md.h @@ -354,6 +354,7 @@ enum mddev_flags { MD_HAS_MULTIPLE_PPLS, MD_NOT_READY, MD_BROKEN, + MD_DO_DELETE, MD_DELETED, }; From 742012f6bf29553fdc460bf646a58df3a7b43d01 Mon Sep 17 00:00:00 2001 From: Zheng Qixing Date: Sat, 8 Nov 2025 15:02:02 +0800 Subject: [PATCH 0606/2333] nbd: defer config put in recv_work [ Upstream commit 9517b82d8d422d426a988b213fdd45c6b417b86d ] There is one uaf issue in recv_work when running NBD_CLEAR_SOCK and NBD_CMD_RECONFIGURE: nbd_genl_connect // conf_ref=2 (connect and recv_work A) nbd_open // conf_ref=3 recv_work A done // conf_ref=2 NBD_CLEAR_SOCK // conf_ref=1 nbd_genl_reconfigure // conf_ref=2 (trigger recv_work B) close nbd // conf_ref=1 recv_work B config_put // conf_ref=0 atomic_dec(&config->recv_threads); -> UAF Or only running NBD_CLEAR_SOCK: nbd_genl_connect // conf_ref=2 nbd_open // conf_ref=3 NBD_CLEAR_SOCK // conf_ref=2 close nbd nbd_release config_put // conf_ref=1 recv_work config_put // conf_ref=0 atomic_dec(&config->recv_threads); -> UAF Commit 87aac3a80af5 ("nbd: call nbd_config_put() before notifying the waiter") moved nbd_config_put() to run before waking up the waiter in recv_work, in order to ensure that nbd_start_device_ioctl() would not be woken up while nbd->task_recv was still uncleared. However, in nbd_start_device_ioctl(), after being woken up it explicitly calls flush_workqueue() to make sure all current works are finished. Therefore, there is no need to move the config put ahead of the wakeup. Move nbd_config_put() to the end of recv_work, so that the reference is held for the whole lifetime of the worker thread. This makes sure the config cannot be freed while recv_work is still running, even if clear + reconfigure interleave. In addition, we don't need to worry about recv_work dropping the last nbd_put (which causes deadlock): path A (netlink with NBD_CFLAG_DESTROY_ON_DISCONNECT): connect // nbd_refs=1 (trigger recv_work) open nbd // nbd_refs=2 NBD_CLEAR_SOCK close nbd nbd_release nbd_disconnect_and_put flush_workqueue // recv_work done nbd_config_put nbd_put // nbd_refs=1 nbd_put // nbd_refs=0 queue_work path B (netlink without NBD_CFLAG_DESTROY_ON_DISCONNECT): connect // nbd_refs=2 (trigger recv_work) open nbd // nbd_refs=3 NBD_CLEAR_SOCK // conf_refs=2 close nbd nbd_release nbd_config_put // conf_refs=1 nbd_put // nbd_refs=2 recv_work done // conf_refs=0, nbd_refs=1 rmmod // nbd_refs=0 Reported-by: syzbot+56fbf4c7ddf65e95c7cc@syzkaller.appspotmail.com Closes: https://lore.kernel.org/all/6907edce.a70a0220.37351b.0014.GAE@google.com/T/ Fixes: 87aac3a80af5 ("nbd: make the config put is called before the notifying the waiter") Depends-on: e2daec488c57 ("nbd: Fix hungtask when nbd_config_put") Signed-off-by: Zheng Qixing Signed-off-by: Jens Axboe Signed-off-by: Sasha Levin --- drivers/block/nbd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index a853c65ac65df..215fc18115b78 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -1024,9 +1024,9 @@ static void recv_work(struct work_struct *work) nbd_mark_nsock_dead(nbd, nsock, 1); mutex_unlock(&nsock->tx_lock); - nbd_config_put(nbd); atomic_dec(&config->recv_threads); wake_up(&config->recv_wq); + nbd_config_put(nbd); kfree(args); } From f7c6c26a99779e4657ea83361b4042435de96d39 Mon Sep 17 00:00:00 2001 From: Haotian Zhang Date: Tue, 4 Nov 2025 17:48:47 +0800 Subject: [PATCH 0607/2333] scsi: stex: Fix reboot_notifier leak in probe error path [ Upstream commit 20da637eb545b04753e20c675cfe97b04c7b600b ] In stex_probe(), register_reboot_notifier() is called at the beginning, but if any subsequent initialization step fails, the function returns without unregistering the notifier, resulting in a resource leak. Add unregister_reboot_notifier() in the out_disable error path to ensure proper cleanup on all failure paths. Fixes: 61b745fa63db ("scsi: stex: Add S6 support") Signed-off-by: Haotian Zhang Link: https://patch.msgid.link/20251104094847.270-1-vulab@iscas.ac.cn Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin --- drivers/scsi/stex.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/stex.c b/drivers/scsi/stex.c index d8ad02c293205..e02f28e5a104e 100644 --- a/drivers/scsi/stex.c +++ b/drivers/scsi/stex.c @@ -1844,6 +1844,7 @@ static int stex_probe(struct pci_dev *pdev, const struct pci_device_id *id) out_scsi_host_put: scsi_host_put(host); out_disable: + unregister_reboot_notifier(&stex_notifier); pci_disable_device(pdev); return err; From 1a5c5a2f88e839af5320216a02ffb075b668596a Mon Sep 17 00:00:00 2001 From: Mike McGowen Date: Thu, 6 Nov 2025 10:38:20 -0600 Subject: [PATCH 0608/2333] scsi: smartpqi: Fix device resources accessed after device removal [ Upstream commit b518e86d1a70a88f6592a7c396cf1b93493d1aab ] Correct possible race conditions during device removal. Previously, a scheduled work item to reset a LUN could still execute after the device was removed, leading to use-after-free and other resource access issues. This race condition occurs because the abort handler may schedule a LUN reset concurrently with device removal via sdev_destroy(), leading to use-after-free and improper access to freed resources. - Check in the device reset handler if the device is still present in the controller's SCSI device list before running; if not, the reset is skipped. - Cancel any pending TMF work that has not started in sdev_destroy(). - Ensure device freeing in sdev_destroy() is done while holding the LUN reset mutex to avoid races with ongoing resets. Fixes: 2d80f4054f7f ("scsi: smartpqi: Update deleting a LUN via sysfs") Reviewed-by: Scott Teel Reviewed-by: Scott Benesh Signed-off-by: Mike McGowen Signed-off-by: Don Brace Link: https://patch.msgid.link/20251106163823.786828-3-don.brace@microchip.com Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin --- drivers/scsi/smartpqi/smartpqi_init.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/drivers/scsi/smartpqi/smartpqi_init.c b/drivers/scsi/smartpqi/smartpqi_init.c index 03c97e60d36f6..fdc856845a05d 100644 --- a/drivers/scsi/smartpqi/smartpqi_init.c +++ b/drivers/scsi/smartpqi/smartpqi_init.c @@ -6410,10 +6410,22 @@ static int pqi_device_reset(struct pqi_ctrl_info *ctrl_info, struct pqi_scsi_dev static int pqi_device_reset_handler(struct pqi_ctrl_info *ctrl_info, struct pqi_scsi_dev *device, u8 lun, struct scsi_cmnd *scmd, u8 scsi_opcode) { + unsigned long flags; int rc; mutex_lock(&ctrl_info->lun_reset_mutex); + spin_lock_irqsave(&ctrl_info->scsi_device_list_lock, flags); + if (pqi_find_scsi_dev(ctrl_info, device->bus, device->target, device->lun) == NULL) { + dev_warn(&ctrl_info->pci_dev->dev, + "skipping reset of scsi %d:%d:%d:%u, device has been removed\n", + ctrl_info->scsi_host->host_no, device->bus, device->target, device->lun); + spin_unlock_irqrestore(&ctrl_info->scsi_device_list_lock, flags); + mutex_unlock(&ctrl_info->lun_reset_mutex); + return 0; + } + spin_unlock_irqrestore(&ctrl_info->scsi_device_list_lock, flags); + dev_err(&ctrl_info->pci_dev->dev, "resetting scsi %d:%d:%d:%u SCSI cmd at %p due to cmd opcode 0x%02x\n", ctrl_info->scsi_host->host_no, device->bus, device->target, lun, scmd, scsi_opcode); @@ -6594,7 +6606,9 @@ static void pqi_sdev_destroy(struct scsi_device *sdev) { struct pqi_ctrl_info *ctrl_info; struct pqi_scsi_dev *device; + struct pqi_tmf_work *tmf_work; int mutex_acquired; + unsigned int lun; unsigned long flags; ctrl_info = shost_to_hba(sdev->host); @@ -6621,8 +6635,13 @@ static void pqi_sdev_destroy(struct scsi_device *sdev) mutex_unlock(&ctrl_info->scan_mutex); + for (lun = 0, tmf_work = device->tmf_work; lun < PQI_MAX_LUNS_PER_DEVICE; lun++, tmf_work++) + cancel_work_sync(&tmf_work->work_struct); + + mutex_lock(&ctrl_info->lun_reset_mutex); pqi_dev_info(ctrl_info, "removed", device); pqi_free_device(device); + mutex_unlock(&ctrl_info->lun_reset_mutex); } static int pqi_getpciinfo_ioctl(struct pqi_ctrl_info *ctrl_info, void __user *arg) From e463548fd80e779efea1cb2d3049b8a7231e6925 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 29 Oct 2025 10:34:42 +0100 Subject: [PATCH 0609/2333] staging: most: remove broken i2c driver [ Upstream commit 495df2da6944477d282d5cc0c13174d06e25b310 ] The MOST I2C driver has been completely broken for five years without anyone noticing so remove the driver from staging. Specifically, commit 723de0f9171e ("staging: most: remove device from interface structure") started requiring drivers to set the interface device pointer before registration, but the I2C driver was never updated which results in a NULL pointer dereference if anyone ever tries to probe it. Fixes: 723de0f9171e ("staging: most: remove device from interface structure") Cc: Christian Gromm Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20251029093442.29256-1-johan@kernel.org Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin --- drivers/staging/most/Kconfig | 2 - drivers/staging/most/Makefile | 1 - drivers/staging/most/i2c/Kconfig | 13 -- drivers/staging/most/i2c/Makefile | 4 - drivers/staging/most/i2c/i2c.c | 374 ------------------------------ 5 files changed, 394 deletions(-) delete mode 100644 drivers/staging/most/i2c/Kconfig delete mode 100644 drivers/staging/most/i2c/Makefile delete mode 100644 drivers/staging/most/i2c/i2c.c diff --git a/drivers/staging/most/Kconfig b/drivers/staging/most/Kconfig index 6f420cbcdcfff..e89658df6f124 100644 --- a/drivers/staging/most/Kconfig +++ b/drivers/staging/most/Kconfig @@ -24,6 +24,4 @@ source "drivers/staging/most/video/Kconfig" source "drivers/staging/most/dim2/Kconfig" -source "drivers/staging/most/i2c/Kconfig" - endif diff --git a/drivers/staging/most/Makefile b/drivers/staging/most/Makefile index 8b3fc5a7af514..e45084df7803a 100644 --- a/drivers/staging/most/Makefile +++ b/drivers/staging/most/Makefile @@ -3,4 +3,3 @@ obj-$(CONFIG_MOST_NET) += net/ obj-$(CONFIG_MOST_VIDEO) += video/ obj-$(CONFIG_MOST_DIM2) += dim2/ -obj-$(CONFIG_MOST_I2C) += i2c/ diff --git a/drivers/staging/most/i2c/Kconfig b/drivers/staging/most/i2c/Kconfig deleted file mode 100644 index ff64283cbad18..0000000000000 --- a/drivers/staging/most/i2c/Kconfig +++ /dev/null @@ -1,13 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# -# MOST I2C configuration -# - -config MOST_I2C - tristate "I2C" - depends on I2C - help - Say Y here if you want to connect via I2C to network transceiver. - - To compile this driver as a module, choose M here: the - module will be called most_i2c. diff --git a/drivers/staging/most/i2c/Makefile b/drivers/staging/most/i2c/Makefile deleted file mode 100644 index 71099dd0f85b9..0000000000000 --- a/drivers/staging/most/i2c/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -obj-$(CONFIG_MOST_I2C) += most_i2c.o - -most_i2c-objs := i2c.o diff --git a/drivers/staging/most/i2c/i2c.c b/drivers/staging/most/i2c/i2c.c deleted file mode 100644 index 184b2dd11fc34..0000000000000 --- a/drivers/staging/most/i2c/i2c.c +++ /dev/null @@ -1,374 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * i2c.c - Hardware Dependent Module for I2C Interface - * - * Copyright (C) 2013-2015, Microchip Technology Germany II GmbH & Co. KG - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include -#include - -enum { CH_RX, CH_TX, NUM_CHANNELS }; - -#define MAX_BUFFERS_CONTROL 32 -#define MAX_BUF_SIZE_CONTROL 256 - -/** - * list_first_mbo - get the first mbo from a list - * @ptr: the list head to take the mbo from. - */ -#define list_first_mbo(ptr) \ - list_first_entry(ptr, struct mbo, list) - -static unsigned int polling_rate; -module_param(polling_rate, uint, 0644); -MODULE_PARM_DESC(polling_rate, "Polling rate [Hz]. Default = 0 (use IRQ)"); - -struct hdm_i2c { - struct most_interface most_iface; - struct most_channel_capability capabilities[NUM_CHANNELS]; - struct i2c_client *client; - struct rx { - struct delayed_work dwork; - struct list_head list; - bool int_disabled; - unsigned int delay; - } rx; - char name[64]; -}; - -static inline struct hdm_i2c *to_hdm(struct most_interface *iface) -{ - return container_of(iface, struct hdm_i2c, most_iface); -} - -static irqreturn_t most_irq_handler(int, void *); -static void pending_rx_work(struct work_struct *); - -/** - * configure_channel - called from MOST core to configure a channel - * @most_iface: interface the channel belongs to - * @ch_idx: channel to be configured - * @channel_config: structure that holds the configuration information - * - * Return 0 on success, negative on failure. - * - * Receives configuration information from MOST core and initialize the - * corresponding channel. - */ -static int configure_channel(struct most_interface *most_iface, - int ch_idx, - struct most_channel_config *channel_config) -{ - int ret; - struct hdm_i2c *dev = to_hdm(most_iface); - unsigned int delay, pr; - - BUG_ON(ch_idx < 0 || ch_idx >= NUM_CHANNELS); - - if (channel_config->data_type != MOST_CH_CONTROL) { - pr_err("bad data type for channel %d\n", ch_idx); - return -EPERM; - } - - if (channel_config->direction != dev->capabilities[ch_idx].direction) { - pr_err("bad direction for channel %d\n", ch_idx); - return -EPERM; - } - - if (channel_config->direction == MOST_CH_RX) { - if (!polling_rate) { - if (dev->client->irq <= 0) { - pr_err("bad irq: %d\n", dev->client->irq); - return -ENOENT; - } - dev->rx.int_disabled = false; - ret = request_irq(dev->client->irq, most_irq_handler, 0, - dev->client->name, dev); - if (ret) { - pr_err("request_irq(%d) failed: %d\n", - dev->client->irq, ret); - return ret; - } - } else { - delay = msecs_to_jiffies(MSEC_PER_SEC / polling_rate); - dev->rx.delay = delay ? delay : 1; - pr = MSEC_PER_SEC / jiffies_to_msecs(dev->rx.delay); - pr_info("polling rate is %u Hz\n", pr); - } - } - - return 0; -} - -/** - * enqueue - called from MOST core to enqueue a buffer for data transfer - * @most_iface: intended interface - * @ch_idx: ID of the channel the buffer is intended for - * @mbo: pointer to the buffer object - * - * Return 0 on success, negative on failure. - * - * Transmit the data over I2C if it is a "write" request or push the buffer into - * list if it is an "read" request - */ -static int enqueue(struct most_interface *most_iface, - int ch_idx, struct mbo *mbo) -{ - struct hdm_i2c *dev = to_hdm(most_iface); - int ret; - - BUG_ON(ch_idx < 0 || ch_idx >= NUM_CHANNELS); - - if (ch_idx == CH_RX) { - /* RX */ - if (!polling_rate) - disable_irq(dev->client->irq); - cancel_delayed_work_sync(&dev->rx.dwork); - list_add_tail(&mbo->list, &dev->rx.list); - if (dev->rx.int_disabled || polling_rate) - pending_rx_work(&dev->rx.dwork.work); - if (!polling_rate) - enable_irq(dev->client->irq); - } else { - /* TX */ - ret = i2c_master_send(dev->client, mbo->virt_address, - mbo->buffer_length); - if (ret <= 0) { - mbo->processed_length = 0; - mbo->status = MBO_E_INVAL; - } else { - mbo->processed_length = mbo->buffer_length; - mbo->status = MBO_SUCCESS; - } - mbo->complete(mbo); - } - - return 0; -} - -/** - * poison_channel - called from MOST core to poison buffers of a channel - * @most_iface: pointer to the interface the channel to be poisoned belongs to - * @ch_idx: corresponding channel ID - * - * Return 0 on success, negative on failure. - * - * If channel direction is RX, complete the buffers in list with - * status MBO_E_CLOSE - */ -static int poison_channel(struct most_interface *most_iface, - int ch_idx) -{ - struct hdm_i2c *dev = to_hdm(most_iface); - struct mbo *mbo; - - BUG_ON(ch_idx < 0 || ch_idx >= NUM_CHANNELS); - - if (ch_idx == CH_RX) { - if (!polling_rate) - free_irq(dev->client->irq, dev); - cancel_delayed_work_sync(&dev->rx.dwork); - - while (!list_empty(&dev->rx.list)) { - mbo = list_first_mbo(&dev->rx.list); - list_del(&mbo->list); - - mbo->processed_length = 0; - mbo->status = MBO_E_CLOSE; - mbo->complete(mbo); - } - } - - return 0; -} - -static void do_rx_work(struct hdm_i2c *dev) -{ - struct mbo *mbo; - unsigned char msg[MAX_BUF_SIZE_CONTROL]; - int ret; - u16 pml, data_size; - - /* Read PML (2 bytes) */ - ret = i2c_master_recv(dev->client, msg, 2); - if (ret <= 0) { - pr_err("Failed to receive PML\n"); - return; - } - - pml = (msg[0] << 8) | msg[1]; - if (!pml) - return; - - data_size = pml + 2; - - /* Read the whole message, including PML */ - ret = i2c_master_recv(dev->client, msg, data_size); - if (ret <= 0) { - pr_err("Failed to receive a Port Message\n"); - return; - } - - mbo = list_first_mbo(&dev->rx.list); - list_del(&mbo->list); - - mbo->processed_length = min(data_size, mbo->buffer_length); - memcpy(mbo->virt_address, msg, mbo->processed_length); - mbo->status = MBO_SUCCESS; - mbo->complete(mbo); -} - -/** - * pending_rx_work - Read pending messages through I2C - * @work: definition of this work item - * - * Invoked by the Interrupt Service Routine, most_irq_handler() - */ -static void pending_rx_work(struct work_struct *work) -{ - struct hdm_i2c *dev = container_of(work, struct hdm_i2c, rx.dwork.work); - - if (list_empty(&dev->rx.list)) - return; - - do_rx_work(dev); - - if (polling_rate) { - schedule_delayed_work(&dev->rx.dwork, dev->rx.delay); - } else { - dev->rx.int_disabled = false; - enable_irq(dev->client->irq); - } -} - -/* - * most_irq_handler - Interrupt Service Routine - * @irq: irq number - * @_dev: private data - * - * Schedules a delayed work - * - * By default the interrupt line behavior is Active Low. Once an interrupt is - * generated by the device, until driver clears the interrupt (by reading - * the PMP message), device keeps the interrupt line in low state. Since i2c - * read is done in work queue, the interrupt line must be disabled temporarily - * to avoid ISR being called repeatedly. Re-enable the interrupt in workqueue, - * after reading the message. - * - * Note: If we use the interrupt line in Falling edge mode, there is a - * possibility to miss interrupts when ISR is getting executed. - * - */ -static irqreturn_t most_irq_handler(int irq, void *_dev) -{ - struct hdm_i2c *dev = _dev; - - disable_irq_nosync(irq); - dev->rx.int_disabled = true; - schedule_delayed_work(&dev->rx.dwork, 0); - - return IRQ_HANDLED; -} - -/* - * i2c_probe - i2c probe handler - * @client: i2c client device structure - * @id: i2c client device id - * - * Return 0 on success, negative on failure. - * - * Register the i2c client device as a MOST interface - */ -static int i2c_probe(struct i2c_client *client) -{ - struct hdm_i2c *dev; - int ret, i; - - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) - return -ENOMEM; - - /* ID format: i2c--
*/ - snprintf(dev->name, sizeof(dev->name), "i2c-%d-%04x", - client->adapter->nr, client->addr); - - for (i = 0; i < NUM_CHANNELS; i++) { - dev->capabilities[i].data_type = MOST_CH_CONTROL; - dev->capabilities[i].num_buffers_packet = MAX_BUFFERS_CONTROL; - dev->capabilities[i].buffer_size_packet = MAX_BUF_SIZE_CONTROL; - } - dev->capabilities[CH_RX].direction = MOST_CH_RX; - dev->capabilities[CH_RX].name_suffix = "rx"; - dev->capabilities[CH_TX].direction = MOST_CH_TX; - dev->capabilities[CH_TX].name_suffix = "tx"; - - dev->most_iface.interface = ITYPE_I2C; - dev->most_iface.description = dev->name; - dev->most_iface.num_channels = NUM_CHANNELS; - dev->most_iface.channel_vector = dev->capabilities; - dev->most_iface.configure = configure_channel; - dev->most_iface.enqueue = enqueue; - dev->most_iface.poison_channel = poison_channel; - - INIT_LIST_HEAD(&dev->rx.list); - - INIT_DELAYED_WORK(&dev->rx.dwork, pending_rx_work); - - dev->client = client; - i2c_set_clientdata(client, dev); - - ret = most_register_interface(&dev->most_iface); - if (ret) { - pr_err("Failed to register i2c as a MOST interface\n"); - kfree(dev); - return ret; - } - - return 0; -} - -/* - * i2c_remove - i2c remove handler - * @client: i2c client device structure - * - * Return 0 on success. - * - * Unregister the i2c client device as a MOST interface - */ -static void i2c_remove(struct i2c_client *client) -{ - struct hdm_i2c *dev = i2c_get_clientdata(client); - - most_deregister_interface(&dev->most_iface); - kfree(dev); -} - -static const struct i2c_device_id i2c_id[] = { - { "most_i2c" }, - { } /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE(i2c, i2c_id); - -static struct i2c_driver i2c_driver = { - .driver = { - .name = "hdm_i2c", - }, - .probe = i2c_probe, - .remove = i2c_remove, - .id_table = i2c_id, -}; - -module_i2c_driver(i2c_driver); - -MODULE_AUTHOR("Andrey Shvetsov "); -MODULE_DESCRIPTION("I2C Hardware Dependent Module"); -MODULE_LICENSE("GPL"); From 986d67f2d72aa4ec7a31bd922f98346745f6ea49 Mon Sep 17 00:00:00 2001 From: Rodrigo Gobbi Date: Sun, 2 Nov 2025 19:30:18 -0300 Subject: [PATCH 0610/2333] iio: imu: bmi270: fix dev_err_probe error msg [ Upstream commit 02f86101e430cce9a99a044b483c4ed5b91bb3b8 ] The bmi270 can be connected to I2C or a SPI interface. If it is a SPI, during probe, if devm_regmap_init() fails, it should print the "spi" term rather "i2c". Fixes: 92cc50a00574 ("iio: imu: bmi270: Add spi driver for bmi270 imu") Signed-off-by: Rodrigo Gobbi Reviewed-by: Andy Shevchenko Signed-off-by: Jonathan Cameron Signed-off-by: Sasha Levin --- drivers/iio/imu/bmi270/bmi270_spi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/imu/bmi270/bmi270_spi.c b/drivers/iio/imu/bmi270/bmi270_spi.c index 19dd7734f9d07..80c9fa1d685ab 100644 --- a/drivers/iio/imu/bmi270/bmi270_spi.c +++ b/drivers/iio/imu/bmi270/bmi270_spi.c @@ -60,7 +60,7 @@ static int bmi270_spi_probe(struct spi_device *spi) &bmi270_spi_regmap_config); if (IS_ERR(regmap)) return dev_err_probe(dev, PTR_ERR(regmap), - "Failed to init i2c regmap"); + "Failed to init spi regmap\n"); return bmi270_core_probe(dev, regmap, chip_info); } From 83f23bf28e1b27f35569ff3456961233248b304c Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Sat, 1 Nov 2025 09:59:40 +0530 Subject: [PATCH 0611/2333] dt-bindings: PCI: amlogic: Fix the register name of the DBI region [ Upstream commit 4813dea9e272ba0a57c50b8d51d440dd8e3ccdd7 ] Binding incorrectly specifies the 'DBI' region as 'ELBI'. DBI is a must have region for DWC controllers as it has the Root Port and controller specific registers, while ELBI has optional registers. Hence, fix the binding. Though this is an ABI break, this change is needed to accurately describe the PCI memory map. Fixes: 7cd210391101 ("dt-bindings: PCI: meson: add DT bindings for Amlogic Meson PCIe controller") Signed-off-by: Manivannan Sadhasivam Signed-off-by: Manivannan Sadhasivam Link: https://patch.msgid.link/20251101-pci-meson-fix-v1-1-c50dcc56ed6a@oss.qualcomm.com Signed-off-by: Sasha Levin --- Documentation/devicetree/bindings/pci/amlogic,axg-pcie.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/pci/amlogic,axg-pcie.yaml b/Documentation/devicetree/bindings/pci/amlogic,axg-pcie.yaml index 79a21ba0f9fd6..c8258ef403283 100644 --- a/Documentation/devicetree/bindings/pci/amlogic,axg-pcie.yaml +++ b/Documentation/devicetree/bindings/pci/amlogic,axg-pcie.yaml @@ -36,13 +36,13 @@ properties: reg: items: - - description: External local bus interface registers + - description: Data Bus Interface registers - description: Meson designed configuration registers - description: PCIe configuration space reg-names: items: - - const: elbi + - const: dbi - const: cfg - const: config @@ -113,7 +113,7 @@ examples: pcie: pcie@f9800000 { compatible = "amlogic,axg-pcie", "snps,dw-pcie"; reg = <0xf9800000 0x400000>, <0xff646000 0x2000>, <0xf9f00000 0x100000>; - reg-names = "elbi", "cfg", "config"; + reg-names = "dbi", "cfg", "config"; interrupts = ; clocks = <&pclk>, <&clk_port>, <&clk_phy>; clock-names = "pclk", "port", "general"; From 8ccdf3a6cde161ea349d63ec9e5bb4208e190098 Mon Sep 17 00:00:00 2001 From: Ma Ke Date: Mon, 10 Nov 2025 08:51:58 +0800 Subject: [PATCH 0612/2333] RDMA/rtrs: server: Fix error handling in get_or_create_srv [ Upstream commit a338d6e849ab31f32c08b4fcac11c0c72afbb150 ] After device_initialize() is called, use put_device() to release the device according to kernel device management rules. While direct kfree() work in this case, using put_device() is more correct. Found by code review. Fixes: 9cb837480424 ("RDMA/rtrs: server: main functionality") Signed-off-by: Ma Ke Link: https://patch.msgid.link/20251110005158.13394-1-make24@iscas.ac.cn Acked-by: Jack Wang Signed-off-by: Leon Romanovsky Signed-off-by: Sasha Levin --- drivers/infiniband/ulp/rtrs/rtrs-srv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/infiniband/ulp/rtrs/rtrs-srv.c b/drivers/infiniband/ulp/rtrs/rtrs-srv.c index ef4abdea3c2d2..9ecc6343455d6 100644 --- a/drivers/infiniband/ulp/rtrs/rtrs-srv.c +++ b/drivers/infiniband/ulp/rtrs/rtrs-srv.c @@ -1450,7 +1450,7 @@ static struct rtrs_srv_sess *get_or_create_srv(struct rtrs_srv_ctx *ctx, kfree(srv->chunks); err_free_srv: - kfree(srv); + put_device(&srv->dev); return ERR_PTR(-ENOMEM); } From 131097fe8b7d0ddcf8fa29b02ae032b5e1bd20e5 Mon Sep 17 00:00:00 2001 From: Jihed Chaibi Date: Tue, 16 Sep 2025 00:46:11 +0200 Subject: [PATCH 0613/2333] ARM: dts: stm32: stm32mp157c-phycore: Fix STMPE811 touchscreen node properties [ Upstream commit e40b061cd379f4897e705d17cf1b4572ad0f3963 ] Move st,adc-freq, st,mod-12b, st,ref-sel, and st,sample-time properties from the touchscreen subnode to the parent touch@44 node. These properties are defined in the st,stmpe.yaml schema for the parent node, not the touchscreen subnode, resolving the validation error about unevaluated properties. Fixes: 27538a18a4fcc ("ARM: dts: stm32: add STM32MP1-based Phytec SoM") Signed-off-by: Jihed Chaibi Link: https://lore.kernel.org/r/20250915224611.169980-1-jihed.chaibi.dev@gmail.com Signed-off-by: Alexandre Torgue Signed-off-by: Sasha Levin --- .../boot/dts/st/stm32mp157c-phycore-stm32mp15-som.dtsi | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/arm/boot/dts/st/stm32mp157c-phycore-stm32mp15-som.dtsi b/arch/arm/boot/dts/st/stm32mp157c-phycore-stm32mp15-som.dtsi index bf0c32027baf7..370b2afbf15bf 100644 --- a/arch/arm/boot/dts/st/stm32mp157c-phycore-stm32mp15-som.dtsi +++ b/arch/arm/boot/dts/st/stm32mp157c-phycore-stm32mp15-som.dtsi @@ -185,13 +185,13 @@ interrupt-parent = <&gpioi>; vio-supply = <&v3v3>; vcc-supply = <&v3v3>; + st,sample-time = <4>; + st,mod-12b = <1>; + st,ref-sel = <0>; + st,adc-freq = <1>; touchscreen { compatible = "st,stmpe-ts"; - st,sample-time = <4>; - st,mod-12b = <1>; - st,ref-sel = <0>; - st,adc-freq = <1>; st,ave-ctrl = <1>; st,touch-det-delay = <2>; st,settling = <2>; From d0c9effd82f2c19b92acd07d357fac5f392d549a Mon Sep 17 00:00:00 2001 From: Carl Worth Date: Thu, 25 Sep 2025 18:42:31 +0800 Subject: [PATCH 0614/2333] coresight: tmc: add the handle of the event to the path [ Upstream commit aaa5abcc9d44d2c8484f779ab46d242d774cabcb ] The handle is essential for retrieving the AUX_EVENT of each CPU and is required in perf mode. It has been added to the coresight_path so that dependent devices can access it from the path when needed. The existing bug can be reproduced with: perf record -e cs_etm//k -C 0-9 dd if=/dev/zero of=/dev/null Showing an oops as follows: Unable to handle kernel paging request at virtual address 000f6e84934ed19e Call trace: tmc_etr_get_buffer+0x30/0x80 [coresight_tmc] (P) catu_enable_hw+0xbc/0x3d0 [coresight_catu] catu_enable+0x70/0xe0 [coresight_catu] coresight_enable_path+0xb0/0x258 [coresight] Fixes: 080ee83cc361 ("Coresight: Change functions to accept the coresight_path") Signed-off-by: Carl Worth Reviewed-by: Leo Yan Co-developed-by: Jie Gan Signed-off-by: Jie Gan Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20250925-fix_helper_data-v2-1-edd8a07c1646@oss.qualcomm.com Signed-off-by: Sasha Levin --- drivers/hwtracing/coresight/coresight-etm-perf.c | 1 + drivers/hwtracing/coresight/coresight-tmc-etr.c | 3 ++- include/linux/coresight.h | 10 ++++++---- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.c b/drivers/hwtracing/coresight/coresight-etm-perf.c index f677c08233ba1..5c256af6e54af 100644 --- a/drivers/hwtracing/coresight/coresight-etm-perf.c +++ b/drivers/hwtracing/coresight/coresight-etm-perf.c @@ -520,6 +520,7 @@ static void etm_event_start(struct perf_event *event, int flags) goto out; path = etm_event_cpu_path(event_data, cpu); + path->handle = handle; /* We need a sink, no need to continue without one */ sink = coresight_get_sink(path); if (WARN_ON_ONCE(!sink)) diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c index 800be06598c1b..60b0e0a6da057 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c @@ -1334,7 +1334,8 @@ static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev) struct etr_buf *tmc_etr_get_buffer(struct coresight_device *csdev, enum cs_mode mode, void *data) { - struct perf_output_handle *handle = data; + struct coresight_path *path = data; + struct perf_output_handle *handle = path->handle; struct etr_perf_buffer *etr_perf; switch (mode) { diff --git a/include/linux/coresight.h b/include/linux/coresight.h index 6de59ce8ef8ca..2626105e37191 100644 --- a/include/linux/coresight.h +++ b/include/linux/coresight.h @@ -332,12 +332,14 @@ static struct coresight_dev_list (var) = { \ /** * struct coresight_path - data needed by enable/disable path - * @path_list: path from source to sink. - * @trace_id: trace_id of the whole path. + * @path_list: path from source to sink. + * @trace_id: trace_id of the whole path. + * @handle: handle of the aux_event. */ struct coresight_path { - struct list_head path_list; - u8 trace_id; + struct list_head path_list; + u8 trace_id; + struct perf_output_handle *handle; }; enum cs_mode { From ab5e8ebeee1caa4fcf8be7d8d62c0a7165469076 Mon Sep 17 00:00:00 2001 From: Edward Adam Davis Date: Tue, 16 Sep 2025 13:50:13 +0800 Subject: [PATCH 0615/2333] ntfs3: init run lock for extend inode [ Upstream commit be99c62ac7e7af514e4b13f83c891a3cccefaa48 ] After setting the inode mode of $Extend to a regular file, executing the truncate system call will enter the do_truncate() routine, causing the run_lock uninitialized error reported by syzbot. Prior to patch 4e8011ffec79, if the inode mode of $Extend was not set to a regular file, the do_truncate() routine would not be entered. Add the run_lock initialization when loading $Extend. syzbot reported: INFO: trying to register non-static key. Call Trace: dump_stack_lvl+0x189/0x250 lib/dump_stack.c:120 assign_lock_key+0x133/0x150 kernel/locking/lockdep.c:984 register_lock_class+0x105/0x320 kernel/locking/lockdep.c:1299 __lock_acquire+0x99/0xd20 kernel/locking/lockdep.c:5112 lock_acquire+0x120/0x360 kernel/locking/lockdep.c:5868 down_write+0x96/0x1f0 kernel/locking/rwsem.c:1590 ntfs_set_size+0x140/0x200 fs/ntfs3/inode.c:860 ntfs_extend+0x1d9/0x970 fs/ntfs3/file.c:387 ntfs_setattr+0x2e8/0xbe0 fs/ntfs3/file.c:808 Fixes: 4e8011ffec79 ("ntfs3: pretend $Extend records as regular files") Reported-by: syzbot+bdeb22a4b9a09ab9aa45@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=bdeb22a4b9a09ab9aa45 Tested-by: syzbot+bdeb22a4b9a09ab9aa45@syzkaller.appspotmail.com Signed-off-by: Edward Adam Davis Signed-off-by: Konstantin Komarov Signed-off-by: Sasha Levin --- fs/ntfs3/inode.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/ntfs3/inode.c b/fs/ntfs3/inode.c index 3a0676871bade..05004f8880ce6 100644 --- a/fs/ntfs3/inode.c +++ b/fs/ntfs3/inode.c @@ -472,6 +472,7 @@ static struct inode *ntfs_read_mft(struct inode *inode, /* Records in $Extend are not a files or general directories. */ inode->i_op = &ntfs_file_inode_operations; mode = S_IFREG; + init_rwsem(&ni->file.run_lock); } else { err = -EINVAL; goto out; From ee8b0b284ccff4035f74367db721922f7a053ad8 Mon Sep 17 00:00:00 2001 From: Akash Goel Date: Tue, 21 Oct 2025 09:10:42 +0100 Subject: [PATCH 0616/2333] drm/panthor: Fix potential memleak of vma structure [ Upstream commit 4492d54d59872bb72e119ff9f77969ab4d8a0e6b ] This commit addresses a memleak issue of panthor_vma (or drm_gpuva) structure in Panthor driver, that can happen if the GPU page table update operation to map the pages fail. The issue is very unlikely to occur in practice. v2: Add panthor_vm_op_ctx_return_vma() helper (Boris) v3: Add WARN_ON_ONCE (Boris) Fixes: 647810ec2476 ("drm/panthor: Add the MMU/VM logical block") Signed-off-by: Akash Goel Reviewed-by: Boris Brezillon Reviewed-by: Steven Price Signed-off-by: Steven Price Link: https://patch.msgid.link/20251021081042.1377406-1-akash.goel@arm.com Signed-off-by: Sasha Levin --- drivers/gpu/drm/panthor/panthor_mmu.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/panthor/panthor_mmu.c b/drivers/gpu/drm/panthor/panthor_mmu.c index 7870e7dbaa5d4..15961629872e1 100644 --- a/drivers/gpu/drm/panthor/panthor_mmu.c +++ b/drivers/gpu/drm/panthor/panthor_mmu.c @@ -1146,6 +1146,20 @@ static void panthor_vm_cleanup_op_ctx(struct panthor_vm_op_ctx *op_ctx, } } +static void +panthor_vm_op_ctx_return_vma(struct panthor_vm_op_ctx *op_ctx, + struct panthor_vma *vma) +{ + for (u32 i = 0; i < ARRAY_SIZE(op_ctx->preallocated_vmas); i++) { + if (!op_ctx->preallocated_vmas[i]) { + op_ctx->preallocated_vmas[i] = vma; + return; + } + } + + WARN_ON_ONCE(1); +} + static struct panthor_vma * panthor_vm_op_ctx_get_vma(struct panthor_vm_op_ctx *op_ctx) { @@ -2085,8 +2099,10 @@ static int panthor_gpuva_sm_step_map(struct drm_gpuva_op *op, void *priv) ret = panthor_vm_map_pages(vm, op->map.va.addr, flags_to_prot(vma->flags), op_ctx->map.sgt, op->map.gem.offset, op->map.va.range); - if (ret) + if (ret) { + panthor_vm_op_ctx_return_vma(op_ctx, vma); return ret; + } /* Ref owned by the mapping now, clear the obj field so we don't release the * pinning/obj ref behind GPUVA's back. From cd2898f0fd8efa34874affdd87f99b06e9bff03e Mon Sep 17 00:00:00 2001 From: Bean Huo Date: Sat, 8 Nov 2025 00:05:17 +0100 Subject: [PATCH 0617/2333] scsi: ufs: core: fix incorrect buffer duplication in ufshcd_read_string_desc() [ Upstream commit d794b499f948801f54d67ddbc34a6eac5a6d150a ] The function ufshcd_read_string_desc() was duplicating memory starting from the beginning of struct uc_string_id, which included the length and type fields. As a result, the allocated buffer contained unwanted metadata in addition to the string itself. The correct behavior is to duplicate only the Unicode character array in the structure. Update the code so that only the actual string content is copied into the new buffer. Fixes: 5f57704dbcfe ("scsi: ufs: Use kmemdup in ufshcd_read_string_desc()") Reviewed-by: Avri Altman Reviewed-by: Bart Van Assche Signed-off-by: Bean Huo Link: https://patch.msgid.link/20251107230518.4060231-3-beanhuo@iokpp.de Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin --- drivers/ufs/core/ufshcd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index d6a060a724618..12f5a7a973128 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -3837,7 +3837,7 @@ int ufshcd_read_string_desc(struct ufs_hba *hba, u8 desc_index, str[ret++] = '\0'; } else { - str = kmemdup(uc_str, uc_str->len, GFP_KERNEL); + str = kmemdup(uc_str->uc, uc_str->len, GFP_KERNEL); if (!str) { ret = -ENOMEM; goto out; From a66e5f556bd7aac4fb8c2bd3f0feb8b21215e580 Mon Sep 17 00:00:00 2001 From: Li Nan Date: Mon, 3 Nov 2025 20:57:53 +0800 Subject: [PATCH 0618/2333] md: delete md_redundancy_group when array is becoming inactive [ Upstream commit 0ce112d9171ad766d4c6716951e73f91a0bfc184 ] 'md_redundancy_group' are created in md_run() and deleted in del_gendisk(), but these are not paired. Writing inactive/active to sysfs array_state can trigger md_run() multiple times without del_gendisk(), leading to duplicate creation as below: sysfs: cannot create duplicate filename '/devices/virtual/block/md0/md/sync_action' Call Trace: dump_stack_lvl+0x9f/0x120 dump_stack+0x14/0x20 sysfs_warn_dup+0x96/0xc0 sysfs_add_file_mode_ns+0x19c/0x1b0 internal_create_group+0x213/0x830 sysfs_create_group+0x17/0x20 md_run+0x856/0xe60 ? __x64_sys_openat+0x23/0x30 do_md_run+0x26/0x1d0 array_state_store+0x559/0x760 md_attr_store+0xc9/0x1e0 sysfs_kf_write+0x6f/0xa0 kernfs_fop_write_iter+0x141/0x2a0 vfs_write+0x1fc/0x5a0 ksys_write+0x79/0x180 __x64_sys_write+0x1d/0x30 x64_sys_call+0x2818/0x2880 do_syscall_64+0xa9/0x580 entry_SYSCALL_64_after_hwframe+0x4b/0x53 md: cannot register extra attributes for md0 Creation of it depends on 'pers', its lifecycle cannot be aligned with gendisk. So fix this issue by triggering 'md_redundancy_group' deletion when the array is becoming inactive. Link: https://lore.kernel.org/linux-raid/20251103125757.1405796-2-linan666@huaweicloud.com Fixes: 790abe4d77af ("md: remove/add redundancy group only in level change") Signed-off-by: Li Nan Reviewed-by: Xiao Ni Signed-off-by: Yu Kuai Signed-off-by: Sasha Levin --- drivers/md/md.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/md/md.c b/drivers/md/md.c index 5d40beaecc9c7..7b21eb1dbc533 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -6872,6 +6872,10 @@ static int do_md_stop(struct mddev *mddev, int mode) if (!md_is_rdwr(mddev)) set_disk_ro(disk, 0); + if (mode == 2 && mddev->pers->sync_request && + mddev->to_remove == NULL) + mddev->to_remove = &md_redundancy_group; + __md_stop_writes(mddev); __md_stop(mddev); From 9d37fe37dfa0833a8768740f0575e0ffd793cb4a Mon Sep 17 00:00:00 2001 From: Li Nan Date: Mon, 3 Nov 2025 20:57:54 +0800 Subject: [PATCH 0619/2333] md: init bioset in mddev_init [ Upstream commit 381a3ce1c0ffed647c9b913e142b099c7e9d5afc ] IO operations may be needed before md_run(), such as updating metadata after writing sysfs. Without bioset, this triggers a NULL pointer dereference as below: BUG: kernel NULL pointer dereference, address: 0000000000000020 Call Trace: md_update_sb+0x658/0xe00 new_level_store+0xc5/0x120 md_attr_store+0xc9/0x1e0 sysfs_kf_write+0x6f/0xa0 kernfs_fop_write_iter+0x141/0x2a0 vfs_write+0x1fc/0x5a0 ksys_write+0x79/0x180 __x64_sys_write+0x1d/0x30 x64_sys_call+0x2818/0x2880 do_syscall_64+0xa9/0x580 entry_SYSCALL_64_after_hwframe+0x4b/0x53 Reproducer ``` mdadm -CR /dev/md0 -l1 -n2 /dev/sd[cd] echo inactive > /sys/block/md0/md/array_state echo 10 > /sys/block/md0/md/new_level ``` mddev_init() can only be called once per mddev, no need to test if bioset has been initialized anymore. Link: https://lore.kernel.org/linux-raid/20251103125757.1405796-3-linan666@huaweicloud.com Fixes: d981ed841930 ("md: Add new_level sysfs interface") Signed-off-by: Li Nan Reviewed-by: Xiao Ni Signed-off-by: Yu Kuai Signed-off-by: Sasha Levin --- drivers/md/md.c | 69 +++++++++++++++++++++++-------------------------- 1 file changed, 33 insertions(+), 36 deletions(-) diff --git a/drivers/md/md.c b/drivers/md/md.c index 7b21eb1dbc533..cef5b2954ac5a 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -730,6 +730,8 @@ static void mddev_clear_bitmap_ops(struct mddev *mddev) int mddev_init(struct mddev *mddev) { + int err = 0; + if (!IS_ENABLED(CONFIG_MD_BITMAP)) mddev->bitmap_id = ID_BITMAP_NONE; else @@ -741,10 +743,23 @@ int mddev_init(struct mddev *mddev) if (percpu_ref_init(&mddev->writes_pending, no_op, PERCPU_REF_ALLOW_REINIT, GFP_KERNEL)) { - percpu_ref_exit(&mddev->active_io); - return -ENOMEM; + err = -ENOMEM; + goto exit_acitve_io; } + err = bioset_init(&mddev->bio_set, BIO_POOL_SIZE, 0, BIOSET_NEED_BVECS); + if (err) + goto exit_writes_pending; + + err = bioset_init(&mddev->sync_set, BIO_POOL_SIZE, 0, BIOSET_NEED_BVECS); + if (err) + goto exit_bio_set; + + err = bioset_init(&mddev->io_clone_set, BIO_POOL_SIZE, + offsetof(struct md_io_clone, bio_clone), 0); + if (err) + goto exit_sync_set; + /* We want to start with the refcount at zero */ percpu_ref_put(&mddev->writes_pending); @@ -773,11 +788,24 @@ int mddev_init(struct mddev *mddev) INIT_WORK(&mddev->del_work, mddev_delayed_delete); return 0; + +exit_sync_set: + bioset_exit(&mddev->sync_set); +exit_bio_set: + bioset_exit(&mddev->bio_set); +exit_writes_pending: + percpu_ref_exit(&mddev->writes_pending); +exit_acitve_io: + percpu_ref_exit(&mddev->active_io); + return err; } EXPORT_SYMBOL_GPL(mddev_init); void mddev_destroy(struct mddev *mddev) { + bioset_exit(&mddev->bio_set); + bioset_exit(&mddev->sync_set); + bioset_exit(&mddev->io_clone_set); percpu_ref_exit(&mddev->active_io); percpu_ref_exit(&mddev->writes_pending); } @@ -6387,29 +6415,9 @@ int md_run(struct mddev *mddev) nowait = nowait && bdev_nowait(rdev->bdev); } - if (!bioset_initialized(&mddev->bio_set)) { - err = bioset_init(&mddev->bio_set, BIO_POOL_SIZE, 0, BIOSET_NEED_BVECS); - if (err) - return err; - } - if (!bioset_initialized(&mddev->sync_set)) { - err = bioset_init(&mddev->sync_set, BIO_POOL_SIZE, 0, BIOSET_NEED_BVECS); - if (err) - goto exit_bio_set; - } - - if (!bioset_initialized(&mddev->io_clone_set)) { - err = bioset_init(&mddev->io_clone_set, BIO_POOL_SIZE, - offsetof(struct md_io_clone, bio_clone), 0); - if (err) - goto exit_sync_set; - } - pers = get_pers(mddev->level, mddev->clevel); - if (!pers) { - err = -EINVAL; - goto abort; - } + if (!pers) + return -EINVAL; if (mddev->level != pers->head.id) { mddev->level = pers->head.id; mddev->new_level = pers->head.id; @@ -6420,8 +6428,7 @@ int md_run(struct mddev *mddev) pers->start_reshape == NULL) { /* This personality cannot handle reshaping... */ put_pers(pers); - err = -EINVAL; - goto abort; + return -EINVAL; } if (pers->sync_request) { @@ -6548,12 +6555,6 @@ int md_run(struct mddev *mddev) mddev->private = NULL; put_pers(pers); md_bitmap_destroy(mddev); -abort: - bioset_exit(&mddev->io_clone_set); -exit_sync_set: - bioset_exit(&mddev->sync_set); -exit_bio_set: - bioset_exit(&mddev->bio_set); return err; } EXPORT_SYMBOL_GPL(md_run); @@ -6778,10 +6779,6 @@ static void __md_stop(struct mddev *mddev) mddev->private = NULL; put_pers(pers); clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery); - - bioset_exit(&mddev->bio_set); - bioset_exit(&mddev->sync_set); - bioset_exit(&mddev->io_clone_set); } void md_stop(struct mddev *mddev) From 990016bd5d02ad465706b1446acb2692e8e6c762 Mon Sep 17 00:00:00 2001 From: "Gautham R. Shenoy" Date: Fri, 7 Nov 2025 13:11:45 +0530 Subject: [PATCH 0620/2333] cpufreq/amd-pstate: Call cppc_set_auto_sel() only for online CPUs [ Upstream commit bb31fef0d03ed17d587b40e3458786be408fb9df ] amd_pstate_change_mode_without_dvr_change() calls cppc_set_auto_sel() for all the present CPUs. However, this callpath eventually calls cppc_set_reg_val() which accesses the per-cpu cpc_desc_ptr object. This object is initialized only for online CPUs via acpi_soft_cpu_online() --> __acpi_processor_start() --> acpi_cppc_processor_probe(). Hence, restrict calling cppc_set_auto_sel() to only the online CPUs. Fixes: 3ca7bc818d8c ("cpufreq: amd-pstate: Add guided mode control support via sysfs") Suggested-by: Mario Limonciello (AMD) (kernel.org) Signed-off-by: Gautham R. Shenoy Signed-off-by: Mario Limonciello (AMD) Signed-off-by: Sasha Levin --- drivers/cpufreq/amd-pstate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/cpufreq/amd-pstate.c b/drivers/cpufreq/amd-pstate.c index b44f0f7a5ba1c..602e4fa81d6c5 100644 --- a/drivers/cpufreq/amd-pstate.c +++ b/drivers/cpufreq/amd-pstate.c @@ -1282,7 +1282,7 @@ static int amd_pstate_change_mode_without_dvr_change(int mode) if (cpu_feature_enabled(X86_FEATURE_CPPC) || cppc_state == AMD_PSTATE_ACTIVE) return 0; - for_each_present_cpu(cpu) { + for_each_online_cpu(cpu) { cppc_set_auto_sel(cpu, (cppc_state == AMD_PSTATE_PASSIVE) ? 0 : 1); } From f834bd9fb83ee396944a4458c9f8d1ea3ed8a027 Mon Sep 17 00:00:00 2001 From: Sourabh Jain Date: Wed, 5 Nov 2025 09:09:41 +0530 Subject: [PATCH 0621/2333] powerpc/kdump: Fix size calculation for hot-removed memory ranges [ Upstream commit 7afe2383eff05f76f4ce2cfda658b7889c89f101 ] The elfcorehdr segment in the kdump image stores information about the memory regions (called crash memory ranges) that the kdump kernel must capture. When a memory hot-remove event occurs, the kernel regenerates the elfcorehdr for the currently loaded kdump image to remove the hot-removed memory from the crash memory ranges. Call chain: remove_mem_range() update_crash_elfcorehdr() arch_crash_handle_hotplug_event() crash_handle_hotplug_event() While removing the hot-removed memory from the crash memory ranges in remove_mem_range(), if the removed memory lies within an existing crash range, that range is split into two. During this split, the size of the second range was being calculated incorrectly. This leads to dump capture failure with makedumpfile with below error: $ makedumpfile -l -d 31 /proc/vmcore /tmp/vmcore readpage_elf: Attempt to read non-existent page at 0xbbdab0000. readmem: type_addr: 0, addr:c000000bbdab7f00, size:16 validate_mem_section: Can't read mem_section array. readpage_elf: Attempt to read non-existent page at 0xbbdab0000. readmem: type_addr: 0, addr:c000000bbdab7f00, size:8 get_mm_sparsemem: Can't get the address of mem_section. The updated crash memory range in PT_LOAD entry is holding incorrect data (checkout FileSiz and MemSiz): readelf -a /proc/vmcore Type Offset VirtAddr PhysAddr FileSiz MemSiz Flags Align LOAD 0x0000000b013d0000 0xc000000b80000000 0x0000000b80000000 0xffffffffc0000000 0xffffffffc0000000 RWE 0x0 Update the size calculation for the new crash memory range to fix this issue. Note: This problem will not occur if the kdump kernel is loaded or reloaded after a memory hot-remove operation. Fixes: 849599b702ef ("powerpc/crash: add crash memory hotplug support") Reported-by: Shirisha G Signed-off-by: Sourabh Jain Signed-off-by: Madhavan Srinivasan Link: https://patch.msgid.link/20251105033941.1752287-1-sourabhjain@linux.ibm.com Signed-off-by: Sasha Levin --- arch/powerpc/kexec/ranges.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/kexec/ranges.c b/arch/powerpc/kexec/ranges.c index 3702b0bdab141..426bdca4667e7 100644 --- a/arch/powerpc/kexec/ranges.c +++ b/arch/powerpc/kexec/ranges.c @@ -697,8 +697,8 @@ int remove_mem_range(struct crash_mem **mem_ranges, u64 base, u64 size) * two half. */ else { + size = mem_rngs->ranges[i].end - end + 1; mem_rngs->ranges[i].end = base - 1; - size = mem_rngs->ranges[i].end - end; ret = add_mem_range(mem_ranges, end + 1, size); } } From 74e9f302f31fb5f94ba62ba8d781cbb45818692d Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Fri, 12 Sep 2025 10:37:34 +0200 Subject: [PATCH 0622/2333] powerpc/32: Fix unpaired stwcx. on interrupt exit [ Upstream commit 10e1c77c3636d815db802ceef588522c2d2d947c ] Commit b96bae3ae2cb ("powerpc/32: Replace ASM exception exit by C exception exit from ppc64") erroneouly copied to powerpc/32 the logic from powerpc/64 based on feature CPU_FTR_STCX_CHECKS_ADDRESS which is always 0 on powerpc/32. Re-instate the logic implemented by commit b64f87c16f3c ("[POWERPC] Avoid unpaired stwcx. on some processors") which is based on CPU_FTR_NEED_PAIRED_STWCX feature. Fixes: b96bae3ae2cb ("powerpc/32: Replace ASM exception exit by C exception exit from ppc64") Signed-off-by: Christophe Leroy Signed-off-by: Madhavan Srinivasan Link: https://patch.msgid.link/6040b5dbcf5cdaa1cd919fcf0790f12974ea6e5a.1757666244.git.christophe.leroy@csgroup.eu Signed-off-by: Sasha Levin --- arch/powerpc/kernel/entry_32.S | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/arch/powerpc/kernel/entry_32.S b/arch/powerpc/kernel/entry_32.S index f4a8c98772491..1beb578c64114 100644 --- a/arch/powerpc/kernel/entry_32.S +++ b/arch/powerpc/kernel/entry_32.S @@ -263,10 +263,9 @@ interrupt_return: mtspr SPRN_SRR1,r12 BEGIN_FTR_SECTION + lwarx r0,0,r1 +END_FTR_SECTION_IFSET(CPU_FTR_NEED_PAIRED_STWCX) stwcx. r0,0,r1 /* to clear the reservation */ -FTR_SECTION_ELSE - lwarx r0,0,r1 -ALT_FTR_SECTION_END_IFCLR(CPU_FTR_STCX_CHECKS_ADDRESS) lwz r3,_CCR(r1) lwz r4,_LINK(r1) @@ -306,10 +305,9 @@ ALT_FTR_SECTION_END_IFCLR(CPU_FTR_STCX_CHECKS_ADDRESS) mtspr SPRN_SRR1,r12 BEGIN_FTR_SECTION + lwarx r0,0,r1 +END_FTR_SECTION_IFSET(CPU_FTR_NEED_PAIRED_STWCX) stwcx. r0,0,r1 /* to clear the reservation */ -FTR_SECTION_ELSE - lwarx r0,0,r1 -ALT_FTR_SECTION_END_IFCLR(CPU_FTR_STCX_CHECKS_ADDRESS) lwz r3,_LINK(r1) lwz r4,_CTR(r1) From 48a7d427eb65922b3f17fbe00e2bbc7cb9eac381 Mon Sep 17 00:00:00 2001 From: Long Li Date: Tue, 19 Aug 2025 17:10:35 +0800 Subject: [PATCH 0623/2333] macintosh/mac_hid: fix race condition in mac_hid_toggle_emumouse [ Upstream commit 1e4b207ffe54cf33a4b7a2912c4110f89c73bf3f ] The following warning appears when running syzkaller, and this issue also exists in the mainline code. ------------[ cut here ]------------ list_add double add: new=ffffffffa57eee28, prev=ffffffffa57eee28, next=ffffffffa5e63100. WARNING: CPU: 0 PID: 1491 at lib/list_debug.c:35 __list_add_valid_or_report+0xf7/0x130 Modules linked in: CPU: 0 PID: 1491 Comm: syz.1.28 Not tainted 6.6.0+ #3 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.16.0-0-gd239552ce722-prebuilt.qemu.org 04/01/2014 RIP: 0010:__list_add_valid_or_report+0xf7/0x130 RSP: 0018:ff1100010dfb7b78 EFLAGS: 00010282 RAX: 0000000000000000 RBX: ffffffffa57eee18 RCX: ffffffff97fc9817 RDX: 0000000000040000 RSI: ffa0000002383000 RDI: 0000000000000001 RBP: ffffffffa57eee28 R08: 0000000000000001 R09: ffe21c0021bf6f2c R10: 0000000000000001 R11: 6464615f7473696c R12: ffffffffa5e63100 R13: ffffffffa57eee28 R14: ffffffffa57eee28 R15: ff1100010dfb7d48 FS: 00007fb14398b640(0000) GS:ff11000119600000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000000 CR3: 000000010d096005 CR4: 0000000000773ef0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 PKRU: 80000000 Call Trace: input_register_handler+0xb3/0x210 mac_hid_start_emulation+0x1c5/0x290 mac_hid_toggle_emumouse+0x20a/0x240 proc_sys_call_handler+0x4c2/0x6e0 new_sync_write+0x1b1/0x2d0 vfs_write+0x709/0x950 ksys_write+0x12a/0x250 do_syscall_64+0x5a/0x110 entry_SYSCALL_64_after_hwframe+0x78/0xe2 The WARNING occurs when two processes concurrently write to the mac-hid emulation sysctl, causing a race condition in mac_hid_toggle_emumouse(). Both processes read old_val=0, then both try to register the input handler, leading to a double list_add of the same handler. CPU0 CPU1 ------------------------- ------------------------- vfs_write() //write 1 vfs_write() //write 1 proc_sys_write() proc_sys_write() mac_hid_toggle_emumouse() mac_hid_toggle_emumouse() old_val = *valp // old_val=0 old_val = *valp // old_val=0 mutex_lock_killable() proc_dointvec() // *valp=1 mac_hid_start_emulation() input_register_handler() mutex_unlock() mutex_lock_killable() proc_dointvec() mac_hid_start_emulation() input_register_handler() //Trigger Warning mutex_unlock() Fix this by moving the old_val read inside the mutex lock region. Fixes: 99b089c3c38a ("Input: Mac button emulation - implement as an input filter") Signed-off-by: Long Li Signed-off-by: Madhavan Srinivasan Link: https://patch.msgid.link/20250819091035.2263329-1-leo.lilong@huaweicloud.com Signed-off-by: Sasha Levin --- drivers/macintosh/mac_hid.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/macintosh/mac_hid.c b/drivers/macintosh/mac_hid.c index 369d72f59b3c1..06fd910b3fd1a 100644 --- a/drivers/macintosh/mac_hid.c +++ b/drivers/macintosh/mac_hid.c @@ -187,13 +187,14 @@ static int mac_hid_toggle_emumouse(const struct ctl_table *table, int write, void *buffer, size_t *lenp, loff_t *ppos) { int *valp = table->data; - int old_val = *valp; + int old_val; int rc; rc = mutex_lock_killable(&mac_hid_emumouse_mutex); if (rc) return rc; + old_val = *valp; rc = proc_dointvec(table, write, buffer, lenp, ppos); if (rc == 0 && write && *valp != old_val) { From 51b823d7723f11b444607268a67502064898047c Mon Sep 17 00:00:00 2001 From: Abdun Nihaal Date: Mon, 10 Nov 2025 23:23:15 +0530 Subject: [PATCH 0624/2333] wifi: cw1200: Fix potential memory leak in cw1200_bh_rx_helper() [ Upstream commit 5e88e864118c20e63a1571d0ff0a152e5d684959 ] In one of the error paths, the memory allocated for skb_rx is not freed. Fix that by freeing it before returning. Fixes: a910e4a94f69 ("cw1200: add driver for the ST-E CW1100 & CW1200 WLAN chipsets") Signed-off-by: Abdun Nihaal Link: https://patch.msgid.link/20251110175316.106591-1-nihaal@cse.iitm.ac.in Signed-off-by: Johannes Berg Signed-off-by: Sasha Levin --- drivers/net/wireless/st/cw1200/bh.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/st/cw1200/bh.c b/drivers/net/wireless/st/cw1200/bh.c index 3b4ded2ac801c..37232ee220375 100644 --- a/drivers/net/wireless/st/cw1200/bh.c +++ b/drivers/net/wireless/st/cw1200/bh.c @@ -317,10 +317,12 @@ static int cw1200_bh_rx_helper(struct cw1200_common *priv, if (wsm_id & 0x0400) { int rc = wsm_release_tx_buffer(priv, 1); - if (WARN_ON(rc < 0)) + if (WARN_ON(rc < 0)) { + dev_kfree_skb(skb_rx); return rc; - else if (rc > 0) + } else if (rc > 0) { *tx = 1; + } } /* cw1200_wsm_rx takes care on SKB livetime */ From c9e805f6a35d1dd189a9345595a5c20e87611942 Mon Sep 17 00:00:00 2001 From: Zheng Qixing Date: Mon, 10 Nov 2025 20:49:20 +0800 Subject: [PATCH 0625/2333] nbd: defer config unlock in nbd_genl_connect [ Upstream commit 1649714b930f9ea6233ce0810ba885999da3b5d4 ] There is one use-after-free warning when running NBD_CMD_CONNECT and NBD_CLEAR_SOCK: nbd_genl_connect nbd_alloc_and_init_config // config_refs=1 nbd_start_device // config_refs=2 set NBD_RT_HAS_CONFIG_REF open nbd // config_refs=3 recv_work done // config_refs=2 NBD_CLEAR_SOCK // config_refs=1 close nbd // config_refs=0 refcount_inc -> uaf ------------[ cut here ]------------ refcount_t: addition on 0; use-after-free. WARNING: CPU: 24 PID: 1014 at lib/refcount.c:25 refcount_warn_saturate+0x12e/0x290 nbd_genl_connect+0x16d0/0x1ab0 genl_family_rcv_msg_doit+0x1f3/0x310 genl_rcv_msg+0x44a/0x790 The issue can be easily reproduced by adding a small delay before refcount_inc(&nbd->config_refs) in nbd_genl_connect(): mutex_unlock(&nbd->config_lock); if (!ret) { set_bit(NBD_RT_HAS_CONFIG_REF, &config->runtime_flags); + printk("before sleep\n"); + mdelay(5 * 1000); + printk("after sleep\n"); refcount_inc(&nbd->config_refs); nbd_connect_reply(info, nbd->index); } Fixes: e46c7287b1c2 ("nbd: add a basic netlink interface") Signed-off-by: Zheng Qixing Reviewed-by: Yu Kuai Signed-off-by: Jens Axboe Signed-off-by: Sasha Levin --- drivers/block/nbd.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index 215fc18115b78..a05ff68e58d06 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -2241,12 +2241,13 @@ static int nbd_genl_connect(struct sk_buff *skb, struct genl_info *info) ret = nbd_start_device(nbd); out: - mutex_unlock(&nbd->config_lock); if (!ret) { set_bit(NBD_RT_HAS_CONFIG_REF, &config->runtime_flags); refcount_inc(&nbd->config_refs); nbd_connect_reply(info, nbd->index); } + mutex_unlock(&nbd->config_lock); + nbd_config_put(nbd); if (put_dev) nbd_put(nbd); From de11c3e5908be46b9e87580b4aae3325c28e4520 Mon Sep 17 00:00:00 2001 From: David Wei Date: Fri, 31 Oct 2025 19:24:48 -0700 Subject: [PATCH 0626/2333] net: export netdev_get_by_index_lock() [ Upstream commit c07a491c1b735e0c27454ea5c27a446d43401b1e ] Need to call netdev_get_by_index_lock() from io_uring/zcrx.c, but it is currently private to net. Export the function in linux/netdevice.h. Signed-off-by: David Wei Acked-by: Jakub Kicinski Signed-off-by: Jens Axboe Stable-dep-of: b6c5f9454ef3 ("io_uring/zcrx: call netdev_queue_get_dma_dev() under instance lock") Signed-off-by: Sasha Levin --- include/linux/netdevice.h | 1 + net/core/dev.h | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index d1a687444b275..77c46a2823eca 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -3401,6 +3401,7 @@ struct net_device *dev_get_by_index(struct net *net, int ifindex); struct net_device *__dev_get_by_index(struct net *net, int ifindex); struct net_device *netdev_get_by_index(struct net *net, int ifindex, netdevice_tracker *tracker, gfp_t gfp); +struct net_device *netdev_get_by_index_lock(struct net *net, int ifindex); struct net_device *netdev_get_by_name(struct net *net, const char *name, netdevice_tracker *tracker, gfp_t gfp); struct net_device *netdev_get_by_flags_rcu(struct net *net, netdevice_tracker *tracker, diff --git a/net/core/dev.h b/net/core/dev.h index 900880e8b5b4b..df8a90fe89f8f 100644 --- a/net/core/dev.h +++ b/net/core/dev.h @@ -29,7 +29,6 @@ struct napi_struct * netdev_napi_by_id_lock(struct net *net, unsigned int napi_id); struct net_device *dev_get_by_napi_id(unsigned int napi_id); -struct net_device *netdev_get_by_index_lock(struct net *net, int ifindex); struct net_device *__netdev_put_lock(struct net_device *dev, struct net *net); struct net_device * netdev_xa_find_lock(struct net *net, struct net_device *dev, From 4717e7860649b846fab1b458e3339cac0eb4894e Mon Sep 17 00:00:00 2001 From: David Wei Date: Fri, 31 Oct 2025 19:24:49 -0700 Subject: [PATCH 0627/2333] io_uring/zcrx: call netdev_queue_get_dma_dev() under instance lock [ Upstream commit b6c5f9454ef34fd2753ba7843ef4d9a295c43eee ] netdev ops must be called under instance lock or rtnl_lock, but io_register_zcrx_ifq() isn't doing this for netdev_queue_get_dma_dev(). Fix this by taking the instance lock using netdev_get_by_index_lock(). Extended the instance lock section to include attaching a memory provider. Could not move io_zcrx_create_area() outside, since the dmabuf codepath IORING_ZCRX_AREA_DMABUF requires ifq->dev. Fixes: 59b8b32ac8d4 ("io_uring/zcrx: add support for custom DMA devices") Signed-off-by: David Wei Reviewed-by: Pavel Begunkov Reviewed-by: Jakub Kicinski Signed-off-by: Jens Axboe Signed-off-by: Sasha Levin --- io_uring/zcrx.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/io_uring/zcrx.c b/io_uring/zcrx.c index b1b723222cdb8..875ad40cf6591 100644 --- a/io_uring/zcrx.c +++ b/io_uring/zcrx.c @@ -599,29 +599,30 @@ int io_register_zcrx_ifq(struct io_ring_ctx *ctx, if (ret) goto err; - ifq->netdev = netdev_get_by_index(current->nsproxy->net_ns, reg.if_idx, - &ifq->netdev_tracker, GFP_KERNEL); + ifq->netdev = netdev_get_by_index_lock(current->nsproxy->net_ns, reg.if_idx); if (!ifq->netdev) { ret = -ENODEV; goto err; } + netdev_hold(ifq->netdev, &ifq->netdev_tracker, GFP_KERNEL); ifq->dev = netdev_queue_get_dma_dev(ifq->netdev, reg.if_rxq); if (!ifq->dev) { ret = -EOPNOTSUPP; - goto err; + goto netdev_put_unlock; } get_device(ifq->dev); ret = io_zcrx_create_area(ifq, &area); if (ret) - goto err; + goto netdev_put_unlock; mp_param.mp_ops = &io_uring_pp_zc_ops; mp_param.mp_priv = ifq; - ret = net_mp_open_rxq(ifq->netdev, reg.if_rxq, &mp_param); + ret = __net_mp_open_rxq(ifq->netdev, reg.if_rxq, &mp_param, NULL); if (ret) - goto err; + goto netdev_put_unlock; + netdev_unlock(ifq->netdev); ifq->if_rxq = reg.if_rxq; reg.zcrx_id = id; @@ -640,6 +641,9 @@ int io_register_zcrx_ifq(struct io_ring_ctx *ctx, goto err; } return 0; +netdev_put_unlock: + netdev_put(ifq->netdev, &ifq->netdev_tracker); + netdev_unlock(ifq->netdev); err: scoped_guard(mutex, &ctx->mmap_lock) xa_erase(&ctx->zcrx_ctxs, id); From 192e8ce302f14ac66259231dd10cede19858d742 Mon Sep 17 00:00:00 2001 From: Bartlomiej Kubik Date: Wed, 5 Nov 2025 22:18:08 +0100 Subject: [PATCH 0628/2333] fs/ntfs3: Initialize allocated memory before use [ Upstream commit a8a3ca23bbd9d849308a7921a049330dc6c91398 ] KMSAN reports: Multiple uninitialized values detected: - KMSAN: uninit-value in ntfs_read_hdr (3) - KMSAN: uninit-value in bcmp (3) Memory is allocated by __getname(), which is a wrapper for kmem_cache_alloc(). This memory is used before being properly cleared. Change kmem_cache_alloc() to kmem_cache_zalloc() to properly allocate and clear memory before use. Fixes: 82cae269cfa9 ("fs/ntfs3: Add initialization of super block") Fixes: 78ab59fee07f ("fs/ntfs3: Rework file operations") Tested-by: syzbot+332bd4e9d148f11a87dc@syzkaller.appspotmail.com Reported-by: syzbot+332bd4e9d148f11a87dc@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=332bd4e9d148f11a87dc Fixes: 82cae269cfa9 ("fs/ntfs3: Add initialization of super block") Fixes: 78ab59fee07f ("fs/ntfs3: Rework file operations") Tested-by: syzbot+0399100e525dd9696764@syzkaller.appspotmail.com Reported-by: syzbot+0399100e525dd9696764@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=0399100e525dd9696764 Reviewed-by: Khalid Aziz Signed-off-by: Bartlomiej Kubik Signed-off-by: Konstantin Komarov Signed-off-by: Sasha Levin --- fs/ntfs3/inode.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/fs/ntfs3/inode.c b/fs/ntfs3/inode.c index 05004f8880ce6..164fd63dff40d 100644 --- a/fs/ntfs3/inode.c +++ b/fs/ntfs3/inode.c @@ -1279,7 +1279,7 @@ int ntfs_create_inode(struct mnt_idmap *idmap, struct inode *dir, fa |= FILE_ATTRIBUTE_READONLY; /* Allocate PATH_MAX bytes. */ - new_de = __getname(); + new_de = kmem_cache_zalloc(names_cachep, GFP_KERNEL); if (!new_de) { err = -ENOMEM; goto out1; @@ -1720,10 +1720,9 @@ int ntfs_link_inode(struct inode *inode, struct dentry *dentry) struct NTFS_DE *de; /* Allocate PATH_MAX bytes. */ - de = __getname(); + de = kmem_cache_zalloc(names_cachep, GFP_KERNEL); if (!de) return -ENOMEM; - memset(de, 0, PATH_MAX); /* Mark rw ntfs as dirty. It will be cleared at umount. */ ntfs_set_state(sbi, NTFS_DIRTY_DIRTY); @@ -1759,7 +1758,7 @@ int ntfs_unlink_inode(struct inode *dir, const struct dentry *dentry) return -EINVAL; /* Allocate PATH_MAX bytes. */ - de = __getname(); + de = kmem_cache_zalloc(names_cachep, GFP_KERNEL); if (!de) return -ENOMEM; From 4305e94270fab6cdba356e446b816acaa854526f Mon Sep 17 00:00:00 2001 From: Leo Yan Date: Tue, 11 Nov 2025 18:58:35 +0000 Subject: [PATCH 0629/2333] coresight: Change device mode to atomic type [ Upstream commit 693d1eaca940f277af24c74873ef2313816ff444 ] The device mode is defined as local type. This type cannot promise SMP-safe access. Change to atomic type and impose relax ordering, which ensures the SMP-safe synchronisation and the ordering between the mode setting and relevant operations. Fixes: 22fd532eaa0c ("coresight: etm3x: adding operation mode for etm_enable()") Reviewed-by: Mike Leach Tested-by: James Clark Signed-off-by: Leo Yan Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20251111-arm_coresight_power_management_fix-v6-1-f55553b6c8b3@arm.com Signed-off-by: Sasha Levin --- include/linux/coresight.h | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/include/linux/coresight.h b/include/linux/coresight.h index 2626105e37191..fafc9ec13f9f4 100644 --- a/include/linux/coresight.h +++ b/include/linux/coresight.h @@ -251,15 +251,11 @@ struct coresight_trace_id_map { * by @coresight_ops. * @access: Device i/o access abstraction for this device. * @dev: The device entity associated to this component. - * @mode: This tracer's mode, i.e sysFS, Perf or disabled. This is - * actually an 'enum cs_mode', but is stored in an atomic type. - * This is always accessed through local_read() and local_set(), - * but wherever it's done from within the Coresight device's lock, - * a non-atomic read would also work. This is the main point of - * synchronisation between code happening inside the sysfs mode's - * coresight_mutex and outside when running in Perf mode. A compare - * and exchange swap is done to atomically claim one mode or the - * other. + * @mode: The device mode, i.e sysFS, Perf or disabled. This is actually + * an 'enum cs_mode' but stored in an atomic type. Access is always + * through atomic APIs, ensuring SMP-safe synchronisation between + * racing from sysFS and Perf mode. A compare-and-exchange + * operation is done to atomically claim one mode or the other. * @refcnt: keep track of what is in use. Only access this outside of the * device's spinlock when the coresight_mutex held and mode == * CS_MODE_SYSFS. Otherwise it must be accessed from inside the @@ -288,7 +284,7 @@ struct coresight_device { const struct coresight_ops *ops; struct csdev_access access; struct device dev; - local_t mode; + atomic_t mode; int refcnt; bool orphan; /* sink specific fields */ @@ -623,13 +619,14 @@ static inline bool coresight_is_percpu_sink(struct coresight_device *csdev) static inline bool coresight_take_mode(struct coresight_device *csdev, enum cs_mode new_mode) { - return local_cmpxchg(&csdev->mode, CS_MODE_DISABLED, new_mode) == - CS_MODE_DISABLED; + int curr = CS_MODE_DISABLED; + + return atomic_try_cmpxchg_acquire(&csdev->mode, &curr, new_mode); } static inline enum cs_mode coresight_get_mode(struct coresight_device *csdev) { - return local_read(&csdev->mode); + return atomic_read_acquire(&csdev->mode); } static inline void coresight_set_mode(struct coresight_device *csdev, @@ -645,7 +642,7 @@ static inline void coresight_set_mode(struct coresight_device *csdev, WARN(new_mode != CS_MODE_DISABLED && current_mode != CS_MODE_DISABLED && current_mode != new_mode, "Device already in use\n"); - local_set(&csdev->mode, new_mode); + atomic_set_release(&csdev->mode, new_mode); } struct coresight_device *coresight_register(struct coresight_desc *desc); From e45178e98848feaf1fddfa1b70d31ecc6ec9ea61 Mon Sep 17 00:00:00 2001 From: Leo Yan Date: Tue, 11 Nov 2025 18:58:36 +0000 Subject: [PATCH 0630/2333] coresight: etm4x: Always set tracer's device mode on target CPU [ Upstream commit 28eee2158575aea8fee7807adb9248ceaf9196f1 ] When enabling a tracer via SysFS interface, the device mode may be set by any CPU - not necessarily the target CPU. This can lead to race condition in SMP, and may result in incorrect mode values being read. Consider the following example, where CPU0 attempts to enable the tracer on CPU1 (the target CPU): CPU0 CPU1 etm4_enable() ` coresight_take_mode(SYSFS) ` etm4_enable_sysfs() ` smp_call_function_single() ----> etm4_enable_hw_smp_call() / / CPU idle: / etm4_cpu_save() / ` coresight_get_mode() Failed to enable h/w / ^^^ ` coresight_set_mode(DISABLED) <-' Read the intermediate SYSFS mode In this case, CPU0 initiates the operation by taking the SYSFS mode to avoid conflicts with the Perf mode. It then sends an IPI to CPU1 to configure the tracer registers. If any error occurs during this process, CPU0 rolls back by setting the mode to DISABLED. However, if CPU1 enters an idle state during this time, it might read the intermediate SYSFS mode. As a result, the CPU PM flow could wrongly save and restore tracer context that is actually disabled. To resolve the issue, this commit moves the device mode setting logic on the target CPU. This ensures that the device mode is only modified by the target CPU, eliminating race condition between mode writes and reads across CPUs. An additional change introduces the etm4_disable_sysfs_smp_call() function for SMP calls, which disables the tracer and explicitly set the mode to DISABLED during SysFS operations. Rename etm4_disable_hw_smp_call() to etm4_disable_sysfs_smp_call() for naming consistency. The flow is updated with this change: CPU0 CPU1 etm4_enable() ` etm4_enable_sysfs() ` smp_call_function_single() ----> etm4_enable_hw_smp_call() ` coresight_take_mode(SYSFS) Failed, set back to DISABLED ` coresight_set_mode(DISABLED) CPU idle: etm4_cpu_save() ` coresight_get_mode() ^^^ Read out the DISABLED mode Fixes: c38a9ec2b2c1 ("coresight: etm4x: moving etm_drvdata::enable to atomic field") Reviewed-by: Yeoreum Yun Reviewed-by: mike Leach Tested-by: James Clark Signed-off-by: Leo Yan Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20251111-arm_coresight_power_management_fix-v6-2-f55553b6c8b3@arm.com Signed-off-by: Sasha Levin --- .../coresight/coresight-etm4x-core.c | 60 ++++++++++++------- 1 file changed, 38 insertions(+), 22 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c index 020f070bf17dc..1324b40d54210 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x-core.c +++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c @@ -589,13 +589,26 @@ static int etm4_enable_hw(struct etmv4_drvdata *drvdata) return rc; } -static void etm4_enable_hw_smp_call(void *info) +static void etm4_enable_sysfs_smp_call(void *info) { struct etm4_enable_arg *arg = info; + struct coresight_device *csdev; if (WARN_ON(!arg)) return; + + csdev = arg->drvdata->csdev; + if (!coresight_take_mode(csdev, CS_MODE_SYSFS)) { + /* Someone is already using the tracer */ + arg->rc = -EBUSY; + return; + } + arg->rc = etm4_enable_hw(arg->drvdata); + + /* The tracer didn't start */ + if (arg->rc) + coresight_set_mode(csdev, CS_MODE_DISABLED); } /* @@ -808,13 +821,14 @@ static int etm4_enable_perf(struct coresight_device *csdev, struct perf_event *event, struct coresight_path *path) { - int ret = 0; struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); + int ret; - if (WARN_ON_ONCE(drvdata->cpu != smp_processor_id())) { - ret = -EINVAL; - goto out; - } + if (WARN_ON_ONCE(drvdata->cpu != smp_processor_id())) + return -EINVAL; + + if (!coresight_take_mode(csdev, CS_MODE_PERF)) + return -EBUSY; /* Configure the tracer based on the session's specifics */ ret = etm4_parse_event_config(csdev, event); @@ -830,6 +844,9 @@ static int etm4_enable_perf(struct coresight_device *csdev, ret = etm4_enable_hw(drvdata); out: + /* Failed to start tracer; roll back to DISABLED mode */ + if (ret) + coresight_set_mode(csdev, CS_MODE_DISABLED); return ret; } @@ -861,7 +878,7 @@ static int etm4_enable_sysfs(struct coresight_device *csdev, struct coresight_pa */ arg.drvdata = drvdata; ret = smp_call_function_single(drvdata->cpu, - etm4_enable_hw_smp_call, &arg, 1); + etm4_enable_sysfs_smp_call, &arg, 1); if (!ret) ret = arg.rc; if (!ret) @@ -882,11 +899,6 @@ static int etm4_enable(struct coresight_device *csdev, struct perf_event *event, { int ret; - if (!coresight_take_mode(csdev, mode)) { - /* Someone is already using the tracer */ - return -EBUSY; - } - switch (mode) { case CS_MODE_SYSFS: ret = etm4_enable_sysfs(csdev, path); @@ -898,10 +910,6 @@ static int etm4_enable(struct coresight_device *csdev, struct perf_event *event, ret = -EINVAL; } - /* The tracer didn't start */ - if (ret) - coresight_set_mode(csdev, CS_MODE_DISABLED); - return ret; } @@ -953,10 +961,9 @@ static void etm4_disable_trace_unit(struct etmv4_drvdata *drvdata) isb(); } -static void etm4_disable_hw(void *info) +static void etm4_disable_hw(struct etmv4_drvdata *drvdata) { u32 control; - struct etmv4_drvdata *drvdata = info; struct etmv4_config *config = &drvdata->config; struct coresight_device *csdev = drvdata->csdev; struct csdev_access *csa = &csdev->access; @@ -993,6 +1000,15 @@ static void etm4_disable_hw(void *info) "cpu: %d disable smp call done\n", drvdata->cpu); } +static void etm4_disable_sysfs_smp_call(void *info) +{ + struct etmv4_drvdata *drvdata = info; + + etm4_disable_hw(drvdata); + + coresight_set_mode(drvdata->csdev, CS_MODE_DISABLED); +} + static int etm4_disable_perf(struct coresight_device *csdev, struct perf_event *event) { @@ -1022,6 +1038,8 @@ static int etm4_disable_perf(struct coresight_device *csdev, /* TRCVICTLR::SSSTATUS, bit[9] */ filters->ssstatus = (control & BIT(9)); + coresight_set_mode(drvdata->csdev, CS_MODE_DISABLED); + /* * perf will release trace ids when _free_aux() is * called at the end of the session. @@ -1047,7 +1065,8 @@ static void etm4_disable_sysfs(struct coresight_device *csdev) * Executing etm4_disable_hw on the cpu whose ETM is being disabled * ensures that register writes occur when cpu is powered. */ - smp_call_function_single(drvdata->cpu, etm4_disable_hw, drvdata, 1); + smp_call_function_single(drvdata->cpu, etm4_disable_sysfs_smp_call, + drvdata, 1); raw_spin_unlock(&drvdata->spinlock); @@ -1087,9 +1106,6 @@ static void etm4_disable(struct coresight_device *csdev, etm4_disable_perf(csdev, event); break; } - - if (mode) - coresight_set_mode(csdev, CS_MODE_DISABLED); } static int etm4_resume_perf(struct coresight_device *csdev) From 9698a89977fb885499b853ff16efecb14528d60d Mon Sep 17 00:00:00 2001 From: Leo Yan Date: Tue, 11 Nov 2025 18:58:37 +0000 Subject: [PATCH 0631/2333] coresight: etm3x: Always set tracer's device mode on target CPU [ Upstream commit ab3fde32afe6a77e5cc60f868e44e6e09424752b ] The ETMv3 driver shares the same issue as ETMv4 regarding race conditions when accessing the device mode. This commit applies the same fix: ensuring that the device mode is modified only by the target CPU to eliminate race conditions across CPUs. Fixes: 22fd532eaa0c ("coresight: etm3x: adding operation mode for etm_enable()") Reviewed-by: Mike Leach Tested-by: James Clark Signed-off-by: Leo Yan Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20251111-arm_coresight_power_management_fix-v6-3-f55553b6c8b3@arm.com Signed-off-by: Sasha Levin --- .../coresight/coresight-etm3x-core.c | 59 +++++++++++++------ 1 file changed, 40 insertions(+), 19 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-etm3x-core.c b/drivers/hwtracing/coresight/coresight-etm3x-core.c index 45630a1cd32fb..a5e809589d3e3 100644 --- a/drivers/hwtracing/coresight/coresight-etm3x-core.c +++ b/drivers/hwtracing/coresight/coresight-etm3x-core.c @@ -439,13 +439,26 @@ struct etm_enable_arg { int rc; }; -static void etm_enable_hw_smp_call(void *info) +static void etm_enable_sysfs_smp_call(void *info) { struct etm_enable_arg *arg = info; + struct coresight_device *csdev; if (WARN_ON(!arg)) return; + + csdev = arg->drvdata->csdev; + if (!coresight_take_mode(csdev, CS_MODE_SYSFS)) { + /* Someone is already using the tracer */ + arg->rc = -EBUSY; + return; + } + arg->rc = etm_enable_hw(arg->drvdata); + + /* The tracer didn't start */ + if (arg->rc) + coresight_set_mode(csdev, CS_MODE_DISABLED); } static int etm_cpu_id(struct coresight_device *csdev) @@ -465,16 +478,26 @@ static int etm_enable_perf(struct coresight_device *csdev, struct coresight_path *path) { struct etm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); + int ret; if (WARN_ON_ONCE(drvdata->cpu != smp_processor_id())) return -EINVAL; + if (!coresight_take_mode(csdev, CS_MODE_PERF)) + return -EBUSY; + /* Configure the tracer based on the session's specifics */ etm_parse_event_config(drvdata, event); drvdata->traceid = path->trace_id; /* And enable it */ - return etm_enable_hw(drvdata); + ret = etm_enable_hw(drvdata); + + /* Failed to start tracer; roll back to DISABLED mode */ + if (ret) + coresight_set_mode(csdev, CS_MODE_DISABLED); + + return ret; } static int etm_enable_sysfs(struct coresight_device *csdev, struct coresight_path *path) @@ -494,7 +517,7 @@ static int etm_enable_sysfs(struct coresight_device *csdev, struct coresight_pat if (cpu_online(drvdata->cpu)) { arg.drvdata = drvdata; ret = smp_call_function_single(drvdata->cpu, - etm_enable_hw_smp_call, &arg, 1); + etm_enable_sysfs_smp_call, &arg, 1); if (!ret) ret = arg.rc; if (!ret) @@ -517,12 +540,6 @@ static int etm_enable(struct coresight_device *csdev, struct perf_event *event, enum cs_mode mode, struct coresight_path *path) { int ret; - struct etm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); - - if (!coresight_take_mode(csdev, mode)) { - /* Someone is already using the tracer */ - return -EBUSY; - } switch (mode) { case CS_MODE_SYSFS: @@ -535,17 +552,12 @@ static int etm_enable(struct coresight_device *csdev, struct perf_event *event, ret = -EINVAL; } - /* The tracer didn't start */ - if (ret) - coresight_set_mode(drvdata->csdev, CS_MODE_DISABLED); - return ret; } -static void etm_disable_hw(void *info) +static void etm_disable_hw(struct etm_drvdata *drvdata) { int i; - struct etm_drvdata *drvdata = info; struct etm_config *config = &drvdata->config; struct coresight_device *csdev = drvdata->csdev; @@ -567,6 +579,15 @@ static void etm_disable_hw(void *info) "cpu: %d disable smp call done\n", drvdata->cpu); } +static void etm_disable_sysfs_smp_call(void *info) +{ + struct etm_drvdata *drvdata = info; + + etm_disable_hw(drvdata); + + coresight_set_mode(drvdata->csdev, CS_MODE_DISABLED); +} + static void etm_disable_perf(struct coresight_device *csdev) { struct etm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); @@ -588,6 +609,8 @@ static void etm_disable_perf(struct coresight_device *csdev) CS_LOCK(drvdata->csa.base); + coresight_set_mode(drvdata->csdev, CS_MODE_DISABLED); + /* * perf will release trace ids when _free_aux() * is called at the end of the session @@ -612,7 +635,8 @@ static void etm_disable_sysfs(struct coresight_device *csdev) * Executing etm_disable_hw on the cpu whose ETM is being disabled * ensures that register writes occur when cpu is powered. */ - smp_call_function_single(drvdata->cpu, etm_disable_hw, drvdata, 1); + smp_call_function_single(drvdata->cpu, etm_disable_sysfs_smp_call, + drvdata, 1); spin_unlock(&drvdata->spinlock); cpus_read_unlock(); @@ -652,9 +676,6 @@ static void etm_disable(struct coresight_device *csdev, WARN_ON_ONCE(mode); return; } - - if (mode) - coresight_set_mode(csdev, CS_MODE_DISABLED); } static const struct coresight_ops_source etm_source_ops = { From 352faa1d6387bf88b309252b9369803ac3365636 Mon Sep 17 00:00:00 2001 From: Leo Yan Date: Tue, 11 Nov 2025 18:58:38 +0000 Subject: [PATCH 0632/2333] coresight: etm4x: Correct polling IDLE bit [ Upstream commit 4dc4e22f9536341255f5de6047977a80ff47eaef ] Since commit 4ff6039ffb79 ("coresight-etm4x: add isb() before reading the TRCSTATR"), the code has incorrectly been polling the PMSTABLE bit instead of the IDLE bit. This commit corrects the typo. Fixes: 4ff6039ffb79 ("coresight-etm4x: add isb() before reading the TRCSTATR") Reviewed-by: Yeoreum Yun Reviewed-by: Mike Leach Tested-by: James Clark Signed-off-by: Leo Yan Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20251111-arm_coresight_power_management_fix-v6-4-f55553b6c8b3@arm.com Signed-off-by: Sasha Levin --- drivers/hwtracing/coresight/coresight-etm4x-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c index 1324b40d54210..c562f82985192 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x-core.c +++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c @@ -1924,7 +1924,7 @@ static int __etm4_cpu_save(struct etmv4_drvdata *drvdata) state->trcpdcr = etm4x_read32(csa, TRCPDCR); /* wait for TRCSTATR.IDLE to go up */ - if (etm4x_wait_status(csa, TRCSTATR_PMSTABLE_BIT, 1)) { + if (etm4x_wait_status(csa, TRCSTATR_IDLE_BIT, 1)) { dev_err(etm_dev, "timeout while waiting for Idle Trace Status\n"); etm4_os_unlock(drvdata); From 2daa7706a0004d33734cb5ba56c5b3e095c8cfbe Mon Sep 17 00:00:00 2001 From: Leo Yan Date: Tue, 11 Nov 2025 18:58:39 +0000 Subject: [PATCH 0633/2333] coresight: etm4x: Add context synchronization before enabling trace [ Upstream commit 64eb04ae545294e105ad91714dc3167a0b660731 ] According to the software usage PKLXF in Arm ARM (ARM DDI 0487 L.a), a Context synchronization event is required before enabling the trace unit. An ISB is added to meet this requirement, particularly for guarding the operations in the flow: etm4x_allow_trace() `> kvm_tracing_set_el1_configuration() `> write_sysreg_s(trfcr_while_in_guest, SYS_TRFCR_EL12) Improved the barrier comments to provide more accurate information. Fixes: 1ab3bb9df5e3 ("coresight: etm4x: Add necessary synchronization for sysreg access") Reviewed-by: Mike Leach Reviewed-by: Yeoreun Yun Tested-by: James Clark Signed-off-by: Leo Yan Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20251111-arm_coresight_power_management_fix-v6-5-f55553b6c8b3@arm.com Signed-off-by: Sasha Levin --- .../coresight/coresight-etm4x-core.c | 27 ++++++++++++++++--- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c index c562f82985192..5e707d082537a 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x-core.c +++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c @@ -446,10 +446,24 @@ static int etm4_enable_trace_unit(struct etmv4_drvdata *drvdata) etm4x_relaxed_write32(csa, TRCRSR_TA, TRCRSR); etm4x_allow_trace(drvdata); + + /* + * According to software usage PKLXF in Arm ARM (ARM DDI 0487 L.a), + * execute a Context synchronization event to guarantee the trace unit + * will observe the new values of the System registers. + */ + if (!csa->io_mem) + isb(); + /* Enable the trace unit */ etm4x_relaxed_write32(csa, 1, TRCPRGCTLR); - /* Synchronize the register updates for sysreg access */ + /* + * As recommended by section 4.3.7 ("Synchronization when using system + * instructions to progrom the trace unit") of ARM IHI 0064H.b, the + * self-hosted trace analyzer must perform a Context synchronization + * event between writing to the TRCPRGCTLR and reading the TRCSTATR. + */ if (!csa->io_mem) isb(); @@ -931,11 +945,16 @@ static void etm4_disable_trace_unit(struct etmv4_drvdata *drvdata) */ etm4x_prohibit_trace(drvdata); /* - * Make sure everything completes before disabling, as recommended - * by section 7.3.77 ("TRCVICTLR, ViewInst Main Control Register, - * SSTATUS") of ARM IHI 0064D + * Prevent being speculative at the point of disabling the trace unit, + * as recommended by section 7.3.77 ("TRCVICTLR, ViewInst Main Control + * Register, SSTATUS") of ARM IHI 0064D */ dsb(sy); + /* + * According to software usage VKHHY in Arm ARM (ARM DDI 0487 L.a), + * execute a Context synchronization event to guarantee no new + * program-flow trace is generated. + */ isb(); /* Trace synchronization barrier, is a nop if not supported */ tsb_csync(); From e485e76864b61670cd30884db98f8706b65d8248 Mon Sep 17 00:00:00 2001 From: Leo Yan Date: Tue, 11 Nov 2025 18:58:40 +0000 Subject: [PATCH 0634/2333] coresight: etm4x: Properly control filter in CPU idle with FEAT_TRF [ Upstream commit 1fdc2cd347a7bc58acacb6144404ee892cea6c2e ] If a CPU supports FEAT_TRF, as described in the section K5.5 "Context switching", Arm ARM (ARM DDI 0487 L.a), it defines a flow to prohibit program-flow trace, execute a TSB CSYNC instruction for flushing, followed by clearing TRCPRGCTLR.EN bit. To restore the state, the reverse sequence is required. This differs from the procedure described in the section 3.4.1 "The procedure when powering down the PE" of ARM IHI0064H.b, which involves the OS Lock to prevent external debugger accesses and implicitly disables trace. To be compatible with different ETM versions, explicitly control trace unit using etm4_disable_trace_unit() and etm4_enable_trace_unit() during CPU idle to comply with FEAT_TRF. As a result, the save states for TRFCR_ELx and trcprgctlr are redundant, remove them. Fixes: f188b5e76aae ("coresight: etm4x: Save/restore state across CPU low power states") Reviewed-by: Mike Leach Tested-by: James Clark Reviewed-by: Yeoreum Yun Signed-off-by: Leo Yan Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20251111-arm_coresight_power_management_fix-v6-6-f55553b6c8b3@arm.com Signed-off-by: Sasha Levin --- drivers/hwtracing/coresight/coresight-etm4x-core.c | 14 +++++++------- drivers/hwtracing/coresight/coresight-etm4x.h | 3 --- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c index 5e707d082537a..fdda924a2c711 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x-core.c +++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c @@ -1858,9 +1858,11 @@ static int __etm4_cpu_save(struct etmv4_drvdata *drvdata) goto out; } + if (!drvdata->paused) + etm4_disable_trace_unit(drvdata); + state = drvdata->save_state; - state->trcprgctlr = etm4x_read32(csa, TRCPRGCTLR); if (drvdata->nr_pe) state->trcprocselr = etm4x_read32(csa, TRCPROCSELR); state->trcconfigr = etm4x_read32(csa, TRCCONFIGR); @@ -1970,9 +1972,6 @@ static int etm4_cpu_save(struct etmv4_drvdata *drvdata) { int ret = 0; - /* Save the TRFCR irrespective of whether the ETM is ON */ - if (drvdata->trfcr) - drvdata->save_trfcr = read_trfcr(); /* * Save and restore the ETM Trace registers only if * the ETM is active. @@ -1994,7 +1993,6 @@ static void __etm4_cpu_restore(struct etmv4_drvdata *drvdata) etm4_cs_unlock(drvdata, csa); etm4x_relaxed_write32(csa, state->trcclaimset, TRCCLAIMSET); - etm4x_relaxed_write32(csa, state->trcprgctlr, TRCPRGCTLR); if (drvdata->nr_pe) etm4x_relaxed_write32(csa, state->trcprocselr, TRCPROCSELR); etm4x_relaxed_write32(csa, state->trcconfigr, TRCCONFIGR); @@ -2079,13 +2077,15 @@ static void __etm4_cpu_restore(struct etmv4_drvdata *drvdata) /* Unlock the OS lock to re-enable trace and external debug access */ etm4_os_unlock(drvdata); + + if (!drvdata->paused) + etm4_enable_trace_unit(drvdata); + etm4_cs_lock(drvdata, csa); } static void etm4_cpu_restore(struct etmv4_drvdata *drvdata) { - if (drvdata->trfcr) - write_trfcr(drvdata->save_trfcr); if (drvdata->state_needs_restore) __etm4_cpu_restore(drvdata); } diff --git a/drivers/hwtracing/coresight/coresight-etm4x.h b/drivers/hwtracing/coresight/coresight-etm4x.h index 13ec9ecef46f5..b8796b4271025 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x.h +++ b/drivers/hwtracing/coresight/coresight-etm4x.h @@ -866,7 +866,6 @@ struct etmv4_config { * struct etm4_save_state - state to be preserved when ETM is without power */ struct etmv4_save_state { - u32 trcprgctlr; u32 trcprocselr; u32 trcconfigr; u32 trcauxctlr; @@ -980,7 +979,6 @@ struct etmv4_save_state { * at runtime, due to the additional setting of TRFCR_CX when * in EL2. Otherwise, 0. * @config: structure holding configuration parameters. - * @save_trfcr: Saved TRFCR_EL1 register during a CPU PM event. * @save_state: State to be preserved across power loss * @state_needs_restore: True when there is context to restore after PM exit * @skip_power_up: Indicates if an implementation can skip powering up @@ -1037,7 +1035,6 @@ struct etmv4_drvdata { bool lpoverride; u64 trfcr; struct etmv4_config config; - u64 save_trfcr; struct etmv4_save_state *save_state; bool state_needs_restore; bool skip_power_up; From b2abcb89865b4fae66cb7a6c5f063fa4af0071f4 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Mon, 10 Nov 2025 23:59:44 -0800 Subject: [PATCH 0635/2333] perf tools: Fix missing feature check for inherit + SAMPLE_READ [ Upstream commit 367377f45c0b568882567f797b7b18b263505be7 ] It should also have PERF_SAMPLE_TID to enable inherit and PERF_SAMPLE_READ on recent kernels. Not having _TID makes the feature check wrongly detect the inherit and _READ support. It was reported that the following command failed due to the error in the missing feature check on Intel SPR machines. $ perf record -e '{cpu/mem-loads-aux/S,cpu/mem-loads,ldlat=3/PS}' -- ls Error: Failure to open event 'cpu/mem-loads,ldlat=3/PS' on PMU 'cpu' which will be removed. Invalid event (cpu/mem-loads,ldlat=3/PS) in per-thread mode, enable system wide with '-a'. Reviewed-by: Ian Rogers Fixes: 3b193a57baf15c468 ("perf tools: Detect missing kernel features properly") Reported-and-tested-by: Chen, Zide Closes: https://lore.kernel.org/lkml/20251022220802.1335131-1-zide.chen@intel.com/ Signed-off-by: Namhyung Kim Signed-off-by: Sasha Levin --- tools/perf/util/evsel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 56ebefd075f2e..9df9818e37013 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -2473,7 +2473,7 @@ static bool evsel__detect_missing_features(struct evsel *evsel, struct perf_cpu /* Please add new feature detection here. */ attr.inherit = true; - attr.sample_type = PERF_SAMPLE_READ; + attr.sample_type = PERF_SAMPLE_READ | PERF_SAMPLE_TID; if (has_attr_feature(&attr, /*flags=*/0)) goto found; perf_missing_features.inherit_sample_read = true; From b1d4bb43691c9e04bc479e76ed03f623e7a4d392 Mon Sep 17 00:00:00 2001 From: Jayesh Choudhary Date: Tue, 4 Nov 2025 20:44:21 +0530 Subject: [PATCH 0636/2333] drm/tidss: Remove max_pclk_khz and min_pclk_khz from tidss display features [ Upstream commit 527e132573dfa793818a536b18eec49598a6f6f5 ] The TIDSS hardware does not have independent maximum or minimum pixel clock limits for each video port. Instead, these limits are determined by the SoC's clock architecture. Previously, this constraint was modeled using the 'max_pclk_khz' and 'min_pclk_khz' fields in 'dispc_features', but this approach is static and does not account for the dynamic behavior of PLLs. This patch removes the 'max_pclk_khz' and 'min_pclk_khz' fields from 'dispc_features'. The correct way to check if a requested mode's pixel clock is supported is by using 'clk_round_rate()' in the 'mode_valid()' hook. If the best frequency match for the mode clock falls within the supported tolerance, it is approved. TIDSS supports a 5% pixel clock tolerance, which is now reflected in the validation logic. This change allows existing DSS-compatible drivers to be reused across SoCs that only differ in their pixel clock characteristics. The validation uses 'clk_round_rate()' for each mode, which may introduce additional delay (about 3.5 ms for 30 modes), but this is generally negligible. Users desiring faster validation may bypass these calls selectively, for example, checking only the highest resolution mode, as shown here[1]. [1]: https://lore.kernel.org/all/20250704094851.182131-3-j-choudhary@ti.com/ Tested-by: Michael Walle Reviewed-by: Devarsh Thakkar Reviewed-by: Tomi Valkeinen Signed-off-by: Jayesh Choudhary Signed-off-by: Swamil Jain Link: https://patch.msgid.link/20251104151422.307162-2-s-jain1@ti.com [Tomi: dropped 'inline' from check_pixel_clock] Signed-off-by: Tomi Valkeinen Stable-dep-of: 86db652fc22f ("drm/tidss: Move OLDI mode validation to OLDI bridge mode_valid hook") Signed-off-by: Sasha Levin --- drivers/gpu/drm/tidss/tidss_dispc.c | 86 +++++++++++------------------ drivers/gpu/drm/tidss/tidss_dispc.h | 3 - 2 files changed, 31 insertions(+), 58 deletions(-) diff --git a/drivers/gpu/drm/tidss/tidss_dispc.c b/drivers/gpu/drm/tidss/tidss_dispc.c index 7c8c15a5c39b3..55259b8e87510 100644 --- a/drivers/gpu/drm/tidss/tidss_dispc.c +++ b/drivers/gpu/drm/tidss/tidss_dispc.c @@ -57,12 +57,6 @@ static const u16 tidss_k2g_common_regs[DISPC_COMMON_REG_TABLE_LEN] = { }; const struct dispc_features dispc_k2g_feats = { - .min_pclk_khz = 4375, - - .max_pclk_khz = { - [DISPC_VP_DPI] = 150000, - }, - /* * XXX According TRM the RGB input buffer width up to 2560 should * work on 3 taps, but in practice it only works up to 1280. @@ -145,11 +139,6 @@ static const u16 tidss_am65x_common_regs[DISPC_COMMON_REG_TABLE_LEN] = { }; const struct dispc_features dispc_am65x_feats = { - .max_pclk_khz = { - [DISPC_VP_DPI] = 165000, - [DISPC_VP_OLDI_AM65X] = 165000, - }, - .scaling = { .in_width_max_5tap_rgb = 1280, .in_width_max_3tap_rgb = 2560, @@ -245,11 +234,6 @@ static const u16 tidss_j721e_common_regs[DISPC_COMMON_REG_TABLE_LEN] = { }; const struct dispc_features dispc_j721e_feats = { - .max_pclk_khz = { - [DISPC_VP_DPI] = 170000, - [DISPC_VP_INTERNAL] = 600000, - }, - .scaling = { .in_width_max_5tap_rgb = 2048, .in_width_max_3tap_rgb = 4096, @@ -316,11 +300,6 @@ const struct dispc_features dispc_j721e_feats = { }; const struct dispc_features dispc_am625_feats = { - .max_pclk_khz = { - [DISPC_VP_DPI] = 165000, - [DISPC_VP_INTERNAL] = 170000, - }, - .scaling = { .in_width_max_5tap_rgb = 1280, .in_width_max_3tap_rgb = 2560, @@ -377,15 +356,6 @@ const struct dispc_features dispc_am625_feats = { }; const struct dispc_features dispc_am62a7_feats = { - /* - * if the code reaches dispc_mode_valid with VP1, - * it should return MODE_BAD. - */ - .max_pclk_khz = { - [DISPC_VP_TIED_OFF] = 0, - [DISPC_VP_DPI] = 165000, - }, - .scaling = { .in_width_max_5tap_rgb = 1280, .in_width_max_3tap_rgb = 2560, @@ -442,10 +412,6 @@ const struct dispc_features dispc_am62a7_feats = { }; const struct dispc_features dispc_am62l_feats = { - .max_pclk_khz = { - [DISPC_VP_DPI] = 165000, - }, - .subrev = DISPC_AM62L, .common = "common", @@ -1331,33 +1297,54 @@ static void dispc_vp_set_default_color(struct dispc_device *dispc, DISPC_OVR_DEFAULT_COLOR2, (v >> 32) & 0xffff); } +/* + * Calculate the percentage difference between the requested pixel clock rate + * and the effective rate resulting from calculating the clock divider value. + */ +unsigned int dispc_pclk_diff(unsigned long rate, unsigned long real_rate) +{ + int r = rate / 100, rr = real_rate / 100; + + return (unsigned int)(abs(((rr - r) * 100) / r)); +} + +static int check_pixel_clock(struct dispc_device *dispc, u32 hw_videoport, + unsigned long clock) +{ + unsigned long round_clock; + + round_clock = clk_round_rate(dispc->vp_clk[hw_videoport], clock); + /* + * To keep the check consistent with dispc_vp_set_clk_rate(), we + * use the same 5% check here. + */ + if (dispc_pclk_diff(clock, round_clock) > 5) + return -EINVAL; + + return 0; +} + enum drm_mode_status dispc_vp_mode_valid(struct dispc_device *dispc, u32 hw_videoport, const struct drm_display_mode *mode) { u32 hsw, hfp, hbp, vsw, vfp, vbp; enum dispc_vp_bus_type bus_type; - int max_pclk; bus_type = dispc->feat->vp_bus_type[hw_videoport]; - max_pclk = dispc->feat->max_pclk_khz[bus_type]; - - if (WARN_ON(max_pclk == 0)) + if (WARN_ON(bus_type == DISPC_VP_TIED_OFF)) return MODE_BAD; - if (mode->clock < dispc->feat->min_pclk_khz) - return MODE_CLOCK_LOW; - - if (mode->clock > max_pclk) - return MODE_CLOCK_HIGH; - if (mode->hdisplay > 4096) return MODE_BAD; if (mode->vdisplay > 4096) return MODE_BAD; + if (check_pixel_clock(dispc, hw_videoport, mode->clock * 1000)) + return MODE_CLOCK_RANGE; + /* TODO: add interlace support */ if (mode->flags & DRM_MODE_FLAG_INTERLACE) return MODE_NO_INTERLACE; @@ -1421,17 +1408,6 @@ void dispc_vp_disable_clk(struct dispc_device *dispc, u32 hw_videoport) clk_disable_unprepare(dispc->vp_clk[hw_videoport]); } -/* - * Calculate the percentage difference between the requested pixel clock rate - * and the effective rate resulting from calculating the clock divider value. - */ -unsigned int dispc_pclk_diff(unsigned long rate, unsigned long real_rate) -{ - int r = rate / 100, rr = real_rate / 100; - - return (unsigned int)(abs(((rr - r) * 100) / r)); -} - int dispc_vp_set_clk_rate(struct dispc_device *dispc, u32 hw_videoport, unsigned long rate) { diff --git a/drivers/gpu/drm/tidss/tidss_dispc.h b/drivers/gpu/drm/tidss/tidss_dispc.h index 60c1b400eb893..42279312dcc1b 100644 --- a/drivers/gpu/drm/tidss/tidss_dispc.h +++ b/drivers/gpu/drm/tidss/tidss_dispc.h @@ -77,9 +77,6 @@ enum dispc_dss_subrevision { }; struct dispc_features { - int min_pclk_khz; - int max_pclk_khz[DISPC_VP_MAX_BUS_TYPE]; - struct dispc_features_scaling scaling; enum dispc_dss_subrevision subrev; From 4dd34a24b68eb3e985e223525ab747ed17d031af Mon Sep 17 00:00:00 2001 From: Jayesh Choudhary Date: Tue, 4 Nov 2025 20:44:22 +0530 Subject: [PATCH 0637/2333] drm/tidss: Move OLDI mode validation to OLDI bridge mode_valid hook [ Upstream commit 86db652fc22f5674ffe3b1f7c91c397c69d26d94 ] After integrating OLDI support[0], it is necessary to identify which VP instances use OLDI, since the OLDI driver owns the video port clock (as a serial clock). Clock operations on these VPs must be delegated to the OLDI driver, not handled by the TIDSS driver. This issue also emerged in upstream discussions when DSI-related clock management was attempted in the TIDSS driver[1]. To address this, add an 'is_ext_vp_clk' array to the 'tidss_device' structure, marking a VP as 'true' during 'tidss_oldi_init()' and as 'false' during 'tidss_oldi_deinit()'. TIDSS then uses 'is_ext_vp_clk' to skip clock validation checks in 'dispc_vp_mode_valid()' for VPs under OLDI control. Since OLDI uses the DSS VP clock directly as a serial interface and manages its own rate, mode validation should be implemented in the OLDI bridge's 'mode_valid' hook. This patch adds that logic, ensuring proper delegation and avoiding spurious clock handling in the TIDSS driver. [0]: https://lore.kernel.org/all/20250528122544.817829-1-aradhya.bhatia@linux.dev/ [1]: https://lore.kernel.org/all/DA6TT575Z82D.3MPK8HG5GRL8U@kernel.org/ Fixes: 7246e0929945 ("drm/tidss: Add OLDI bridge support") Tested-by: Michael Walle Reviewed-by: Devarsh Thakkar Reviewed-by: Tomi Valkeinen Signed-off-by: Jayesh Choudhary Signed-off-by: Swamil Jain Link: https://patch.msgid.link/20251104151422.307162-3-s-jain1@ti.com Signed-off-by: Tomi Valkeinen Link: https://patch.msgid.link/ffd5ebe03391b3c01e616c0c844a4b8ddecede36.1762513240.git.jani.nikula@intel.com Signed-off-by: Sasha Levin --- drivers/gpu/drm/tidss/tidss_dispc.c | 7 +++++++ drivers/gpu/drm/tidss/tidss_drv.h | 2 ++ drivers/gpu/drm/tidss/tidss_oldi.c | 22 ++++++++++++++++++++++ 3 files changed, 31 insertions(+) diff --git a/drivers/gpu/drm/tidss/tidss_dispc.c b/drivers/gpu/drm/tidss/tidss_dispc.c index 55259b8e87510..6bf1171d0bc2d 100644 --- a/drivers/gpu/drm/tidss/tidss_dispc.c +++ b/drivers/gpu/drm/tidss/tidss_dispc.c @@ -1313,6 +1313,13 @@ static int check_pixel_clock(struct dispc_device *dispc, u32 hw_videoport, { unsigned long round_clock; + /* + * For VP's with external clocking, clock operations must be + * delegated to respective driver, so we skip the check here. + */ + if (dispc->tidss->is_ext_vp_clk[hw_videoport]) + return 0; + round_clock = clk_round_rate(dispc->vp_clk[hw_videoport], clock); /* * To keep the check consistent with dispc_vp_set_clk_rate(), we diff --git a/drivers/gpu/drm/tidss/tidss_drv.h b/drivers/gpu/drm/tidss/tidss_drv.h index 84454a4855d11..e1c1f41d8b4be 100644 --- a/drivers/gpu/drm/tidss/tidss_drv.h +++ b/drivers/gpu/drm/tidss/tidss_drv.h @@ -24,6 +24,8 @@ struct tidss_device { const struct dispc_features *feat; struct dispc_device *dispc; + bool is_ext_vp_clk[TIDSS_MAX_PORTS]; + unsigned int num_crtcs; struct drm_crtc *crtcs[TIDSS_MAX_PORTS]; diff --git a/drivers/gpu/drm/tidss/tidss_oldi.c b/drivers/gpu/drm/tidss/tidss_oldi.c index 7688251beba28..17c535bfa0576 100644 --- a/drivers/gpu/drm/tidss/tidss_oldi.c +++ b/drivers/gpu/drm/tidss/tidss_oldi.c @@ -309,6 +309,25 @@ static u32 *tidss_oldi_atomic_get_input_bus_fmts(struct drm_bridge *bridge, return input_fmts; } +static enum drm_mode_status +tidss_oldi_mode_valid(struct drm_bridge *bridge, + const struct drm_display_info *info, + const struct drm_display_mode *mode) +{ + struct tidss_oldi *oldi = drm_bridge_to_tidss_oldi(bridge); + unsigned long round_clock; + + round_clock = clk_round_rate(oldi->serial, mode->clock * 7 * 1000); + /* + * To keep the check consistent with dispc_vp_set_clk_rate(), + * we use the same 5% check here. + */ + if (dispc_pclk_diff(mode->clock * 7 * 1000, round_clock) > 5) + return -EINVAL; + + return 0; +} + static const struct drm_bridge_funcs tidss_oldi_bridge_funcs = { .attach = tidss_oldi_bridge_attach, .atomic_pre_enable = tidss_oldi_atomic_pre_enable, @@ -317,6 +336,7 @@ static const struct drm_bridge_funcs tidss_oldi_bridge_funcs = { .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, .atomic_reset = drm_atomic_helper_bridge_reset, + .mode_valid = tidss_oldi_mode_valid, }; static int get_oldi_mode(struct device_node *oldi_tx, int *companion_instance) @@ -430,6 +450,7 @@ void tidss_oldi_deinit(struct tidss_device *tidss) for (int i = 0; i < tidss->num_oldis; i++) { if (tidss->oldis[i]) { drm_bridge_remove(&tidss->oldis[i]->bridge); + tidss->is_ext_vp_clk[tidss->oldis[i]->parent_vp] = false; tidss->oldis[i] = NULL; } } @@ -580,6 +601,7 @@ int tidss_oldi_init(struct tidss_device *tidss) oldi->bridge.timings = &default_tidss_oldi_timings; tidss->oldis[tidss->num_oldis++] = oldi; + tidss->is_ext_vp_clk[oldi->parent_vp] = true; oldi->tidss = tidss; drm_bridge_add(&oldi->bridge); From 0dcbf7d6e9015447dfed6b3616ecef163e5e0fd8 Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Tue, 28 Oct 2025 16:51:23 +0000 Subject: [PATCH 0638/2333] clk: renesas: r9a09g077: Propagate rate changes to parent clocks [ Upstream commit 145dfd70b9c70e5bc03494a7ce8fa3748ac01af3 ] Add the CLK_SET_RATE_PARENT flag to divider clock registration so that rate changes can propagate to parent clocks when needed. This allows the CPG divider clocks to request rate adjustments from their parent, ensuring correct frequency scaling and improved flexibility in clock rate selection. Fixes: 065fe720eec6e ("clk: renesas: Add support for R9A09G077 SoC") Signed-off-by: Lad Prabhakar Reviewed-by: Geert Uytterhoeven Link: https://patch.msgid.link/20251028165127.991351-2-prabhakar.mahadev-lad.rj@bp.renesas.com Signed-off-by: Geert Uytterhoeven Signed-off-by: Sasha Levin --- drivers/clk/renesas/r9a09g077-cpg.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/clk/renesas/r9a09g077-cpg.c b/drivers/clk/renesas/r9a09g077-cpg.c index af3ef6d58c87c..d12975418a568 100644 --- a/drivers/clk/renesas/r9a09g077-cpg.c +++ b/drivers/clk/renesas/r9a09g077-cpg.c @@ -217,7 +217,7 @@ r9a09g077_cpg_div_clk_register(struct device *dev, if (core->dtable) clk_hw = clk_hw_register_divider_table(dev, core->name, - parent_name, 0, + parent_name, CLK_SET_RATE_PARENT, addr, GET_SHIFT(core->conf), GET_WIDTH(core->conf), @@ -226,7 +226,7 @@ r9a09g077_cpg_div_clk_register(struct device *dev, &pub->rmw_lock); else clk_hw = clk_hw_register_divider(dev, core->name, - parent_name, 0, + parent_name, CLK_SET_RATE_PARENT, addr, GET_SHIFT(core->conf), GET_WIDTH(core->conf), From 8cacdb0f0bca048bcffd1b8c48a3daa40dcae3a6 Mon Sep 17 00:00:00 2001 From: Haotian Zhang Date: Thu, 30 Oct 2025 14:16:03 +0800 Subject: [PATCH 0639/2333] clk: renesas: r9a06g032: Fix memory leak in error path [ Upstream commit f8def051bbcf8677f64701e9699bf6d11e2780cd ] The current code uses of_iomap() to map registers but never calls iounmap() on any error path after the mapping. This causes a memory leak when probe fails after successful ioremap, for example when of_clk_add_provider() or r9a06g032_add_clk_domain() fails. Replace of_iomap() with devm_of_iomap() to automatically unmap the region on probe failure. Update the error check accordingly to use IS_ERR() and PTR_ERR() since devm_of_iomap() returns ERR_PTR on error. Fixes: 4c3d88526eba ("clk: renesas: Renesas R9A06G032 clock driver") Signed-off-by: Haotian Zhang Reviewed-by: Geert Uytterhoeven Link: https://patch.msgid.link/20251030061603.1954-1-vulab@iscas.ac.cn Signed-off-by: Geert Uytterhoeven Signed-off-by: Sasha Levin --- drivers/clk/renesas/r9a06g032-clocks.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/clk/renesas/r9a06g032-clocks.c b/drivers/clk/renesas/r9a06g032-clocks.c index dcda19318b2a9..0f5c91b5dfa99 100644 --- a/drivers/clk/renesas/r9a06g032-clocks.c +++ b/drivers/clk/renesas/r9a06g032-clocks.c @@ -1333,9 +1333,9 @@ static int __init r9a06g032_clocks_probe(struct platform_device *pdev) if (IS_ERR(mclk)) return PTR_ERR(mclk); - clocks->reg = of_iomap(np, 0); - if (WARN_ON(!clocks->reg)) - return -ENOMEM; + clocks->reg = devm_of_iomap(dev, np, 0, NULL); + if (IS_ERR(clocks->reg)) + return PTR_ERR(clocks->reg); r9a06g032_init_h2mode(clocks); From e0a7eab9165a6a0dcaf1306c3f1aa6a151e4aa95 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 10 Nov 2025 14:21:18 +0100 Subject: [PATCH 0640/2333] lib/vsprintf: Check pointer before dereferencing in time_and_date() [ Upstream commit 372a12bd5df0199aa234eaf8ef31ed7ecd61d40f ] The pointer may be invalid when gets to the printf(). In particular the time_and_date() dereferencing it in some cases without checking. Move the check from rtc_str() to time_and_date() to cover all cases. Fixes: 7daac5b2fdf8 ("lib/vsprintf: Print time64_t in human readable format") Signed-off-by: Andy Shevchenko Reviewed-by: Petr Mladek Link: https://patch.msgid.link/20251110132118.4113976-1-andriy.shevchenko@linux.intel.com Signed-off-by: Petr Mladek Signed-off-by: Sasha Levin --- lib/vsprintf.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/vsprintf.c b/lib/vsprintf.c index eb0cb11d0d126..a356965c1d734 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -1928,9 +1928,6 @@ char *rtc_str(char *buf, char *end, const struct rtc_time *tm, bool found = true; int count = 2; - if (check_pointer(&buf, end, tm, spec)) - return buf; - switch (fmt[count]) { case 'd': have_t = false; @@ -1996,6 +1993,9 @@ static noinline_for_stack char *time_and_date(char *buf, char *end, void *ptr, struct printf_spec spec, const char *fmt) { + if (check_pointer(&buf, end, ptr, spec)) + return buf; + switch (fmt[1]) { case 'R': return rtc_str(buf, end, (const struct rtc_time *)ptr, spec, fmt); From e5c52c320577cd405b251943ef77842dc6f303bf Mon Sep 17 00:00:00 2001 From: Dmitry Antipov Date: Thu, 9 Oct 2025 13:23:49 +0300 Subject: [PATCH 0641/2333] ocfs2: relax BUG() to ocfs2_error() in __ocfs2_move_extent() [ Upstream commit 8a7d58845fae061c62b50bc5eeb9bae4a1dedc3d ] In '__ocfs2_move_extent()', relax 'BUG()' to 'ocfs2_error()' just to avoid crashing the whole kernel due to a filesystem corruption. Fixes: 8f603e567aa7 ("Ocfs2/move_extents: move a range of extent.") Link: https://lkml.kernel.org/r/20251009102349.181126-2-dmantipov@yandex.ru Signed-off-by: Dmitry Antipov Closes: https://syzkaller.appspot.com/bug?extid=727d161855d11d81e411 Reported-by: syzbot+727d161855d11d81e411@syzkaller.appspotmail.com Reviewed-by: Joseph Qi Cc: Mark Fasheh Cc: Joel Becker Cc: Junxiao Bi Cc: Changwei Ge Cc: Jun Piao Signed-off-by: Andrew Morton Signed-off-by: Sasha Levin --- fs/ocfs2/move_extents.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/fs/ocfs2/move_extents.c b/fs/ocfs2/move_extents.c index 10923bf7c8b84..26e150c5f25eb 100644 --- a/fs/ocfs2/move_extents.c +++ b/fs/ocfs2/move_extents.c @@ -98,7 +98,13 @@ static int __ocfs2_move_extent(handle_t *handle, rec = &el->l_recs[index]; - BUG_ON(ext_flags != rec->e_flags); + if (ext_flags != rec->e_flags) { + ret = ocfs2_error(inode->i_sb, + "Inode %llu has corrupted extent %d with flags 0x%x at cpos %u\n", + (unsigned long long)ino, index, rec->e_flags, cpos); + goto out; + } + /* * after moving/defraging to new location, the extent is not going * to be refcounted anymore. From d7ea2b4d0b703207bf09c9a912530b2edfb67bf7 Mon Sep 17 00:00:00 2001 From: Joseph Qi Date: Sat, 25 Oct 2025 20:32:17 +0800 Subject: [PATCH 0642/2333] ocfs2: use correct endian in ocfs2_dinode_has_extents [ Upstream commit c9dff86eb78a4b6b02b1e407993c946ccaf9bfb4 ] Fields in ocfs2_dinode is little endian, covert to host endian when checking those contents. Link: https://lkml.kernel.org/r/20251025123218.3997866-1-joseph.qi@linux.alibaba.com Fixes: fdbb6cd96ed5 ("ocfs2: correct l_next_free_rec in online check") Signed-off-by: Joseph Qi Reviewed-by: Heming Zhao Cc: Mark Fasheh Cc: Joel Becker Cc: Junxiao Bi Cc: Changwei Ge Cc: Jun Piao Signed-off-by: Andrew Morton Signed-off-by: Sasha Levin --- fs/ocfs2/inode.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c index fcc89856ab95b..0a0a96054bfec 100644 --- a/fs/ocfs2/inode.c +++ b/fs/ocfs2/inode.c @@ -201,13 +201,15 @@ struct inode *ocfs2_iget(struct ocfs2_super *osb, u64 blkno, unsigned flags, static int ocfs2_dinode_has_extents(struct ocfs2_dinode *di) { /* inodes flagged with other stuff in id2 */ - if (di->i_flags & (OCFS2_SUPER_BLOCK_FL | OCFS2_LOCAL_ALLOC_FL | - OCFS2_CHAIN_FL | OCFS2_DEALLOC_FL)) + if (le32_to_cpu(di->i_flags) & + (OCFS2_SUPER_BLOCK_FL | OCFS2_LOCAL_ALLOC_FL | OCFS2_CHAIN_FL | + OCFS2_DEALLOC_FL)) return 0; /* i_flags doesn't indicate when id2 is a fast symlink */ - if (S_ISLNK(di->i_mode) && di->i_size && di->i_clusters == 0) + if (S_ISLNK(le16_to_cpu(di->i_mode)) && le64_to_cpu(di->i_size) && + !le32_to_cpu(di->i_clusters)) return 0; - if (di->i_dyn_features & OCFS2_INLINE_DATA_FL) + if (le16_to_cpu(di->i_dyn_features) & OCFS2_INLINE_DATA_FL) return 0; return 1; From b47b1e1889c8bb33282160e7e17c8474cee0d6d2 Mon Sep 17 00:00:00 2001 From: Haotian Zhang Date: Tue, 11 Nov 2025 15:50:00 +0800 Subject: [PATCH 0643/2333] ACPI: property: Fix fwnode refcount leak in acpi_fwnode_graph_parse_endpoint() [ Upstream commit 593ee49222a0d751062fd9a5e4a963ade4ec028a ] acpi_fwnode_graph_parse_endpoint() calls fwnode_get_parent() to obtain the parent fwnode but returns without calling fwnode_handle_put() on it. This potentially leads to a fwnode refcount leak and prevents the parent node from being released properly. Call fwnode_handle_put() on the parent fwnode before returning to prevent the leak from occurring. Fixes: 3b27d00e7b6d ("device property: Move fwnode graph ops to firmware specific locations") Signed-off-by: Haotian Zhang Reviewed-by: Sakari Ailus [ rjw: Changelog edits ] Link: https://patch.msgid.link/20251111075000.1828-1-vulab@iscas.ac.cn Signed-off-by: Rafael J. Wysocki Signed-off-by: Sasha Levin --- drivers/acpi/property.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c index 43d5e457814e1..b12057baaae7b 100644 --- a/drivers/acpi/property.c +++ b/drivers/acpi/property.c @@ -1714,6 +1714,7 @@ static int acpi_fwnode_graph_parse_endpoint(const struct fwnode_handle *fwnode, if (fwnode_property_read_u32(fwnode, "reg", &endpoint->id)) fwnode_property_read_u32(fwnode, "endpoint", &endpoint->id); + fwnode_handle_put(port_fwnode); return 0; } From 5c1fb3fd05da3d55b8cbc42d7d660b313cbdc936 Mon Sep 17 00:00:00 2001 From: Tony Battersby Date: Mon, 10 Nov 2025 11:07:37 -0500 Subject: [PATCH 0644/2333] scsi: qla2xxx: Clear cmds after chip reset [ Upstream commit d46c69a087aa3d1513f7a78f871b80251ea0c1ae ] Commit aefed3e5548f ("scsi: qla2xxx: target: Fix offline port handling and host reset handling") caused two problems: 1. Commands sent to FW, after chip reset got stuck and never freed as FW is not going to respond to them anymore. 2. BUG_ON(cmd->sg_mapped) in qlt_free_cmd(). Commit 26f9ce53817a ("scsi: qla2xxx: Fix missed DMA unmap for aborted commands") attempted to fix this, but introduced another bug under different circumstances when two different CPUs were racing to call qlt_unmap_sg() at the same time: BUG_ON(!valid_dma_direction(dir)) in dma_unmap_sg_attrs(). So revert "scsi: qla2xxx: Fix missed DMA unmap for aborted commands" and partially revert "scsi: qla2xxx: target: Fix offline port handling and host reset handling" at __qla2x00_abort_all_cmds. Fixes: aefed3e5548f ("scsi: qla2xxx: target: Fix offline port handling and host reset handling") Fixes: 26f9ce53817a ("scsi: qla2xxx: Fix missed DMA unmap for aborted commands") Co-developed-by: Dmitry Bogdanov Signed-off-by: Dmitry Bogdanov Signed-off-by: Tony Battersby Link: https://patch.msgid.link/0e7e5d26-e7a0-42d1-8235-40eeb27f3e98@cybernetics.com Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin --- drivers/scsi/qla2xxx/qla_os.c | 20 ++++++++++++++++++-- drivers/scsi/qla2xxx/qla_target.c | 5 +---- drivers/scsi/qla2xxx/qla_target.h | 1 + 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 5ffd945866527..70a579cf9c3fd 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -1881,10 +1881,26 @@ __qla2x00_abort_all_cmds(struct qla_qpair *qp, int res) continue; } cmd = (struct qla_tgt_cmd *)sp; - cmd->aborted = 1; + + if (cmd->sg_mapped) + qlt_unmap_sg(vha, cmd); + + if (cmd->state == QLA_TGT_STATE_NEED_DATA) { + cmd->aborted = 1; + cmd->write_data_transferred = 0; + cmd->state = QLA_TGT_STATE_DATA_IN; + ha->tgt.tgt_ops->handle_data(cmd); + } else { + ha->tgt.tgt_ops->free_cmd(cmd); + } break; case TYPE_TGT_TMCMD: - /* Skip task management functions. */ + /* + * Currently, only ABTS response gets on the + * outstanding_cmds[] + */ + ha->tgt.tgt_ops->free_mcmd( + (struct qla_tgt_mgmt_cmd *) sp); break; default: break; diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c index 1e81582085e38..4c6aff59fe3fb 100644 --- a/drivers/scsi/qla2xxx/qla_target.c +++ b/drivers/scsi/qla2xxx/qla_target.c @@ -2443,7 +2443,7 @@ static int qlt_pci_map_calc_cnt(struct qla_tgt_prm *prm) return -1; } -static void qlt_unmap_sg(struct scsi_qla_host *vha, struct qla_tgt_cmd *cmd) +void qlt_unmap_sg(struct scsi_qla_host *vha, struct qla_tgt_cmd *cmd) { struct qla_hw_data *ha; struct qla_qpair *qpair; @@ -3773,9 +3773,6 @@ int qlt_abort_cmd(struct qla_tgt_cmd *cmd) spin_lock_irqsave(&cmd->cmd_lock, flags); if (cmd->aborted) { - if (cmd->sg_mapped) - qlt_unmap_sg(vha, cmd); - spin_unlock_irqrestore(&cmd->cmd_lock, flags); /* * It's normal to see 2 calls in this path: diff --git a/drivers/scsi/qla2xxx/qla_target.h b/drivers/scsi/qla2xxx/qla_target.h index 15a59c125c532..c483966d0a847 100644 --- a/drivers/scsi/qla2xxx/qla_target.h +++ b/drivers/scsi/qla2xxx/qla_target.h @@ -1058,6 +1058,7 @@ extern int qlt_abort_cmd(struct qla_tgt_cmd *); extern void qlt_xmit_tm_rsp(struct qla_tgt_mgmt_cmd *); extern void qlt_free_mcmd(struct qla_tgt_mgmt_cmd *); extern void qlt_free_cmd(struct qla_tgt_cmd *cmd); +extern void qlt_unmap_sg(struct scsi_qla_host *vha, struct qla_tgt_cmd *cmd); extern void qlt_async_event(uint16_t, struct scsi_qla_host *, uint16_t *); extern void qlt_enable_vha(struct scsi_qla_host *); extern void qlt_vport_create(struct scsi_qla_host *, struct qla_hw_data *); From 54a7e83112742d75c19226665a729113f16165ae Mon Sep 17 00:00:00 2001 From: Haotian Zhang Date: Wed, 29 Oct 2025 11:25:55 +0800 Subject: [PATCH 0645/2333] scsi: sim710: Fix resource leak by adding missing ioport_unmap() calls [ Upstream commit acd194d9b5bac419e04968ffa44351afabb50bac ] The driver calls ioport_map() to map I/O ports in sim710_probe_common() but never calls ioport_unmap() to release the mapping. This causes resource leaks in both the error path when request_irq() fails and in the normal device removal path via sim710_device_remove(). Add ioport_unmap() calls in the out_release error path and in sim710_device_remove(). Fixes: 56fece20086e ("[PATCH] finally fix 53c700 to use the generic iomem infrastructure") Signed-off-by: Haotian Zhang Link: https://patch.msgid.link/20251029032555.1476-1-vulab@iscas.ac.cn Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin --- drivers/scsi/sim710.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/scsi/sim710.c b/drivers/scsi/sim710.c index e519df68d603d..70c75ab1453a1 100644 --- a/drivers/scsi/sim710.c +++ b/drivers/scsi/sim710.c @@ -133,6 +133,7 @@ static int sim710_probe_common(struct device *dev, unsigned long base_addr, out_put_host: scsi_host_put(host); out_release: + ioport_unmap(hostdata->base); release_region(base_addr, 64); out_free: kfree(hostdata); @@ -148,6 +149,7 @@ static int sim710_device_remove(struct device *dev) scsi_remove_host(host); NCR_700_release(host); + ioport_unmap(hostdata->base); kfree(hostdata); free_irq(host->irq, host); release_region(host->base, 64); From 659dd9c8cd59d09481c3be17607171285c63dfee Mon Sep 17 00:00:00 2001 From: Haotian Zhang Date: Fri, 31 Oct 2025 10:16:20 +0800 Subject: [PATCH 0646/2333] leds: netxbig: Fix GPIO descriptor leak in error paths [ Upstream commit 03865dd8af52eb16c38062df2ed30a91b604780e ] The function netxbig_gpio_ext_get() acquires GPIO descriptors but fails to release them when errors occur mid-way through initialization. The cleanup callback registered by devm_add_action_or_reset() only runs on success, leaving acquired GPIOs leaked on error paths. Add goto-based error handling to release all acquired GPIOs before returning errors. Fixes: 9af512e81964 ("leds: netxbig: Convert to use GPIO descriptors") Suggested-by: Markus Elfring Signed-off-by: Haotian Zhang Link: https://patch.msgid.link/20251031021620.781-1-vulab@iscas.ac.cn Signed-off-by: Lee Jones Signed-off-by: Sasha Levin --- drivers/leds/leds-netxbig.c | 36 ++++++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/drivers/leds/leds-netxbig.c b/drivers/leds/leds-netxbig.c index e95287416ef87..99df46f2d9f52 100644 --- a/drivers/leds/leds-netxbig.c +++ b/drivers/leds/leds-netxbig.c @@ -364,6 +364,9 @@ static int netxbig_gpio_ext_get(struct device *dev, if (!addr) return -ENOMEM; + gpio_ext->addr = addr; + gpio_ext->num_addr = 0; + /* * We cannot use devm_ managed resources with these GPIO descriptors * since they are associated with the "GPIO extension device" which @@ -375,45 +378,58 @@ static int netxbig_gpio_ext_get(struct device *dev, gpiod = gpiod_get_index(gpio_ext_dev, "addr", i, GPIOD_OUT_LOW); if (IS_ERR(gpiod)) - return PTR_ERR(gpiod); + goto err_set_code; gpiod_set_consumer_name(gpiod, "GPIO extension addr"); addr[i] = gpiod; + gpio_ext->num_addr++; } - gpio_ext->addr = addr; - gpio_ext->num_addr = num_addr; ret = gpiod_count(gpio_ext_dev, "data"); if (ret < 0) { dev_err(dev, "Failed to count GPIOs in DT property data-gpios\n"); - return ret; + goto err_free_addr; } num_data = ret; data = devm_kcalloc(dev, num_data, sizeof(*data), GFP_KERNEL); - if (!data) - return -ENOMEM; + if (!data) { + ret = -ENOMEM; + goto err_free_addr; + } + + gpio_ext->data = data; + gpio_ext->num_data = 0; for (i = 0; i < num_data; i++) { gpiod = gpiod_get_index(gpio_ext_dev, "data", i, GPIOD_OUT_LOW); if (IS_ERR(gpiod)) - return PTR_ERR(gpiod); + goto err_free_data; gpiod_set_consumer_name(gpiod, "GPIO extension data"); data[i] = gpiod; + gpio_ext->num_data++; } - gpio_ext->data = data; - gpio_ext->num_data = num_data; gpiod = gpiod_get(gpio_ext_dev, "enable", GPIOD_OUT_LOW); if (IS_ERR(gpiod)) { dev_err(dev, "Failed to get GPIO from DT property enable-gpio\n"); - return PTR_ERR(gpiod); + goto err_free_data; } gpiod_set_consumer_name(gpiod, "GPIO extension enable"); gpio_ext->enable = gpiod; return devm_add_action_or_reset(dev, netxbig_gpio_ext_remove, gpio_ext); + +err_free_data: + for (i = 0; i < gpio_ext->num_data; i++) + gpiod_put(gpio_ext->data[i]); +err_set_code: + ret = PTR_ERR(gpiod); +err_free_addr: + for (i = 0; i < gpio_ext->num_addr; i++) + gpiod_put(gpio_ext->addr[i]); + return ret; } static int netxbig_leds_get_of_pdata(struct device *dev, From 8e2121a40c39e26e8ba8cffbe30a00f607379b65 Mon Sep 17 00:00:00 2001 From: Chaitanya S Prakash Date: Fri, 17 Oct 2025 10:44:36 +0530 Subject: [PATCH 0647/2333] arm64/mm: Allow __create_pgd_mapping() to propagate pgtable_alloc() errors [ Upstream commit bfc184cb1ba7226b21ab26f0b220581895c5ac9e ] arch_add_memory() is used to hotplug memory into a system but as a part of its implementation it calls __create_pgd_mapping(), which uses pgtable_alloc() in order to build intermediate page tables. As this path was initally only used during early boot pgtable_alloc() is designed to BUG_ON() on failure. However, in the event that memory hotplug is attempted when the system's memory is extremely tight and the allocation were to fail, it would lead to panicking the system, which is not desirable. Hence update __create_pgd_mapping and all it's callers to be non void and propagate -ENOMEM on allocation failure to allow system to fail gracefully. But during early boot if there is an allocation failure, we want the system to panic, hence create a wrapper around __create_pgd_mapping() called early_create_pgd_mapping() which is designed to panic, if ret is non zero value. All the init calls are updated to use this wrapper rather than the modified __create_pgd_mapping() to restore functionality. Fixes: 4ab215061554 ("arm64: Add memory hotplug support") Reviewed-by: Dev Jain Reviewed-by: Ryan Roberts Reviewed-by: Kevin Brodsky Signed-off-by: Chaitanya S Prakash Signed-off-by: Linu Cherian Reviewed-by: Anshuman Khandual Signed-off-by: Catalin Marinas Signed-off-by: Sasha Levin --- arch/arm64/mm/mmu.c | 214 ++++++++++++++++++++++++++++---------------- 1 file changed, 136 insertions(+), 78 deletions(-) diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c index 2ba01dc8ef822..aeb6fb25a951a 100644 --- a/arch/arm64/mm/mmu.c +++ b/arch/arm64/mm/mmu.c @@ -49,6 +49,8 @@ #define NO_CONT_MAPPINGS BIT(1) #define NO_EXEC_MAPPINGS BIT(2) /* assumes FEAT_HPDS is not used */ +#define INVALID_PHYS_ADDR (-1ULL) + DEFINE_STATIC_KEY_FALSE(arm64_ptdump_lock_key); u64 kimage_voffset __ro_after_init; @@ -194,11 +196,11 @@ static void init_pte(pte_t *ptep, unsigned long addr, unsigned long end, } while (ptep++, addr += PAGE_SIZE, addr != end); } -static void alloc_init_cont_pte(pmd_t *pmdp, unsigned long addr, - unsigned long end, phys_addr_t phys, - pgprot_t prot, - phys_addr_t (*pgtable_alloc)(enum pgtable_type), - int flags) +static int alloc_init_cont_pte(pmd_t *pmdp, unsigned long addr, + unsigned long end, phys_addr_t phys, + pgprot_t prot, + phys_addr_t (*pgtable_alloc)(enum pgtable_type), + int flags) { unsigned long next; pmd_t pmd = READ_ONCE(*pmdp); @@ -213,6 +215,8 @@ static void alloc_init_cont_pte(pmd_t *pmdp, unsigned long addr, pmdval |= PMD_TABLE_PXN; BUG_ON(!pgtable_alloc); pte_phys = pgtable_alloc(TABLE_PTE); + if (pte_phys == INVALID_PHYS_ADDR) + return -ENOMEM; ptep = pte_set_fixmap(pte_phys); init_clear_pgtable(ptep); ptep += pte_index(addr); @@ -244,11 +248,13 @@ static void alloc_init_cont_pte(pmd_t *pmdp, unsigned long addr, * walker. */ pte_clear_fixmap(); + + return 0; } -static void init_pmd(pmd_t *pmdp, unsigned long addr, unsigned long end, - phys_addr_t phys, pgprot_t prot, - phys_addr_t (*pgtable_alloc)(enum pgtable_type), int flags) +static int init_pmd(pmd_t *pmdp, unsigned long addr, unsigned long end, + phys_addr_t phys, pgprot_t prot, + phys_addr_t (*pgtable_alloc)(enum pgtable_type), int flags) { unsigned long next; @@ -269,22 +275,29 @@ static void init_pmd(pmd_t *pmdp, unsigned long addr, unsigned long end, BUG_ON(!pgattr_change_is_safe(pmd_val(old_pmd), READ_ONCE(pmd_val(*pmdp)))); } else { - alloc_init_cont_pte(pmdp, addr, next, phys, prot, - pgtable_alloc, flags); + int ret; + + ret = alloc_init_cont_pte(pmdp, addr, next, phys, prot, + pgtable_alloc, flags); + if (ret) + return ret; BUG_ON(pmd_val(old_pmd) != 0 && pmd_val(old_pmd) != READ_ONCE(pmd_val(*pmdp))); } phys += next - addr; } while (pmdp++, addr = next, addr != end); + + return 0; } -static void alloc_init_cont_pmd(pud_t *pudp, unsigned long addr, - unsigned long end, phys_addr_t phys, - pgprot_t prot, - phys_addr_t (*pgtable_alloc)(enum pgtable_type), - int flags) +static int alloc_init_cont_pmd(pud_t *pudp, unsigned long addr, + unsigned long end, phys_addr_t phys, + pgprot_t prot, + phys_addr_t (*pgtable_alloc)(enum pgtable_type), + int flags) { + int ret; unsigned long next; pud_t pud = READ_ONCE(*pudp); pmd_t *pmdp; @@ -301,6 +314,8 @@ static void alloc_init_cont_pmd(pud_t *pudp, unsigned long addr, pudval |= PUD_TABLE_PXN; BUG_ON(!pgtable_alloc); pmd_phys = pgtable_alloc(TABLE_PMD); + if (pmd_phys == INVALID_PHYS_ADDR) + return -ENOMEM; pmdp = pmd_set_fixmap(pmd_phys); init_clear_pgtable(pmdp); pmdp += pmd_index(addr); @@ -320,20 +335,26 @@ static void alloc_init_cont_pmd(pud_t *pudp, unsigned long addr, (flags & NO_CONT_MAPPINGS) == 0) __prot = __pgprot(pgprot_val(prot) | PTE_CONT); - init_pmd(pmdp, addr, next, phys, __prot, pgtable_alloc, flags); + ret = init_pmd(pmdp, addr, next, phys, __prot, pgtable_alloc, flags); + if (ret) + goto out; pmdp += pmd_index(next) - pmd_index(addr); phys += next - addr; } while (addr = next, addr != end); +out: pmd_clear_fixmap(); + + return ret; } -static void alloc_init_pud(p4d_t *p4dp, unsigned long addr, unsigned long end, - phys_addr_t phys, pgprot_t prot, - phys_addr_t (*pgtable_alloc)(enum pgtable_type), - int flags) +static int alloc_init_pud(p4d_t *p4dp, unsigned long addr, unsigned long end, + phys_addr_t phys, pgprot_t prot, + phys_addr_t (*pgtable_alloc)(enum pgtable_type), + int flags) { + int ret = 0; unsigned long next; p4d_t p4d = READ_ONCE(*p4dp); pud_t *pudp; @@ -346,6 +367,8 @@ static void alloc_init_pud(p4d_t *p4dp, unsigned long addr, unsigned long end, p4dval |= P4D_TABLE_PXN; BUG_ON(!pgtable_alloc); pud_phys = pgtable_alloc(TABLE_PUD); + if (pud_phys == INVALID_PHYS_ADDR) + return -ENOMEM; pudp = pud_set_fixmap(pud_phys); init_clear_pgtable(pudp); pudp += pud_index(addr); @@ -375,8 +398,10 @@ static void alloc_init_pud(p4d_t *p4dp, unsigned long addr, unsigned long end, BUG_ON(!pgattr_change_is_safe(pud_val(old_pud), READ_ONCE(pud_val(*pudp)))); } else { - alloc_init_cont_pmd(pudp, addr, next, phys, prot, - pgtable_alloc, flags); + ret = alloc_init_cont_pmd(pudp, addr, next, phys, prot, + pgtable_alloc, flags); + if (ret) + goto out; BUG_ON(pud_val(old_pud) != 0 && pud_val(old_pud) != READ_ONCE(pud_val(*pudp))); @@ -384,14 +409,18 @@ static void alloc_init_pud(p4d_t *p4dp, unsigned long addr, unsigned long end, phys += next - addr; } while (pudp++, addr = next, addr != end); +out: pud_clear_fixmap(); + + return ret; } -static void alloc_init_p4d(pgd_t *pgdp, unsigned long addr, unsigned long end, - phys_addr_t phys, pgprot_t prot, - phys_addr_t (*pgtable_alloc)(enum pgtable_type), - int flags) +static int alloc_init_p4d(pgd_t *pgdp, unsigned long addr, unsigned long end, + phys_addr_t phys, pgprot_t prot, + phys_addr_t (*pgtable_alloc)(enum pgtable_type), + int flags) { + int ret; unsigned long next; pgd_t pgd = READ_ONCE(*pgdp); p4d_t *p4dp; @@ -404,6 +433,8 @@ static void alloc_init_p4d(pgd_t *pgdp, unsigned long addr, unsigned long end, pgdval |= PGD_TABLE_PXN; BUG_ON(!pgtable_alloc); p4d_phys = pgtable_alloc(TABLE_P4D); + if (p4d_phys == INVALID_PHYS_ADDR) + return -ENOMEM; p4dp = p4d_set_fixmap(p4d_phys); init_clear_pgtable(p4dp); p4dp += p4d_index(addr); @@ -418,8 +449,10 @@ static void alloc_init_p4d(pgd_t *pgdp, unsigned long addr, unsigned long end, next = p4d_addr_end(addr, end); - alloc_init_pud(p4dp, addr, next, phys, prot, - pgtable_alloc, flags); + ret = alloc_init_pud(p4dp, addr, next, phys, prot, + pgtable_alloc, flags); + if (ret) + goto out; BUG_ON(p4d_val(old_p4d) != 0 && p4d_val(old_p4d) != READ_ONCE(p4d_val(*p4dp))); @@ -427,15 +460,19 @@ static void alloc_init_p4d(pgd_t *pgdp, unsigned long addr, unsigned long end, phys += next - addr; } while (p4dp++, addr = next, addr != end); +out: p4d_clear_fixmap(); + + return ret; } -static void __create_pgd_mapping_locked(pgd_t *pgdir, phys_addr_t phys, - unsigned long virt, phys_addr_t size, - pgprot_t prot, - phys_addr_t (*pgtable_alloc)(enum pgtable_type), - int flags) +static int __create_pgd_mapping_locked(pgd_t *pgdir, phys_addr_t phys, + unsigned long virt, phys_addr_t size, + pgprot_t prot, + phys_addr_t (*pgtable_alloc)(enum pgtable_type), + int flags) { + int ret; unsigned long addr, end, next; pgd_t *pgdp = pgd_offset_pgd(pgdir, virt); @@ -444,7 +481,7 @@ static void __create_pgd_mapping_locked(pgd_t *pgdir, phys_addr_t phys, * within a page, we cannot map the region as the caller expects. */ if (WARN_ON((phys ^ virt) & ~PAGE_MASK)) - return; + return -EINVAL; phys &= PAGE_MASK; addr = virt & PAGE_MASK; @@ -452,25 +489,45 @@ static void __create_pgd_mapping_locked(pgd_t *pgdir, phys_addr_t phys, do { next = pgd_addr_end(addr, end); - alloc_init_p4d(pgdp, addr, next, phys, prot, pgtable_alloc, - flags); + ret = alloc_init_p4d(pgdp, addr, next, phys, prot, pgtable_alloc, + flags); + if (ret) + return ret; phys += next - addr; } while (pgdp++, addr = next, addr != end); + + return 0; } -static void __create_pgd_mapping(pgd_t *pgdir, phys_addr_t phys, - unsigned long virt, phys_addr_t size, - pgprot_t prot, - phys_addr_t (*pgtable_alloc)(enum pgtable_type), - int flags) +static int __create_pgd_mapping(pgd_t *pgdir, phys_addr_t phys, + unsigned long virt, phys_addr_t size, + pgprot_t prot, + phys_addr_t (*pgtable_alloc)(enum pgtable_type), + int flags) { + int ret; + mutex_lock(&fixmap_lock); - __create_pgd_mapping_locked(pgdir, phys, virt, size, prot, - pgtable_alloc, flags); + ret = __create_pgd_mapping_locked(pgdir, phys, virt, size, prot, + pgtable_alloc, flags); mutex_unlock(&fixmap_lock); + + return ret; } -#define INVALID_PHYS_ADDR (-1ULL) +static void early_create_pgd_mapping(pgd_t *pgdir, phys_addr_t phys, + unsigned long virt, phys_addr_t size, + pgprot_t prot, + phys_addr_t (*pgtable_alloc)(enum pgtable_type), + int flags) +{ + int ret; + + ret = __create_pgd_mapping(pgdir, phys, virt, size, prot, pgtable_alloc, + flags); + if (ret) + panic("Failed to create page tables\n"); +} static phys_addr_t __pgd_pgtable_alloc(struct mm_struct *mm, gfp_t gfp, enum pgtable_type pgtable_type) @@ -511,21 +568,13 @@ try_pgd_pgtable_alloc_init_mm(enum pgtable_type pgtable_type, gfp_t gfp) static phys_addr_t __maybe_unused pgd_pgtable_alloc_init_mm(enum pgtable_type pgtable_type) { - phys_addr_t pa; - - pa = __pgd_pgtable_alloc(&init_mm, GFP_PGTABLE_KERNEL, pgtable_type); - BUG_ON(pa == INVALID_PHYS_ADDR); - return pa; + return __pgd_pgtable_alloc(&init_mm, GFP_PGTABLE_KERNEL, pgtable_type); } static phys_addr_t pgd_pgtable_alloc_special_mm(enum pgtable_type pgtable_type) { - phys_addr_t pa; - - pa = __pgd_pgtable_alloc(NULL, GFP_PGTABLE_KERNEL, pgtable_type); - BUG_ON(pa == INVALID_PHYS_ADDR); - return pa; + return __pgd_pgtable_alloc(NULL, GFP_PGTABLE_KERNEL, pgtable_type); } static void split_contpte(pte_t *ptep) @@ -935,8 +984,8 @@ void __init create_mapping_noalloc(phys_addr_t phys, unsigned long virt, &phys, virt); return; } - __create_pgd_mapping(init_mm.pgd, phys, virt, size, prot, NULL, - NO_CONT_MAPPINGS); + early_create_pgd_mapping(init_mm.pgd, phys, virt, size, prot, NULL, + NO_CONT_MAPPINGS); } void __init create_pgd_mapping(struct mm_struct *mm, phys_addr_t phys, @@ -950,8 +999,8 @@ void __init create_pgd_mapping(struct mm_struct *mm, phys_addr_t phys, if (page_mappings_only) flags = NO_BLOCK_MAPPINGS | NO_CONT_MAPPINGS; - __create_pgd_mapping(mm->pgd, phys, virt, size, prot, - pgd_pgtable_alloc_special_mm, flags); + early_create_pgd_mapping(mm->pgd, phys, virt, size, prot, + pgd_pgtable_alloc_special_mm, flags); } static void update_mapping_prot(phys_addr_t phys, unsigned long virt, @@ -963,8 +1012,8 @@ static void update_mapping_prot(phys_addr_t phys, unsigned long virt, return; } - __create_pgd_mapping(init_mm.pgd, phys, virt, size, prot, NULL, - NO_CONT_MAPPINGS); + early_create_pgd_mapping(init_mm.pgd, phys, virt, size, prot, NULL, + NO_CONT_MAPPINGS); /* flush the TLBs after updating live kernel mappings */ flush_tlb_kernel_range(virt, virt + size); @@ -973,8 +1022,8 @@ static void update_mapping_prot(phys_addr_t phys, unsigned long virt, static void __init __map_memblock(pgd_t *pgdp, phys_addr_t start, phys_addr_t end, pgprot_t prot, int flags) { - __create_pgd_mapping(pgdp, start, __phys_to_virt(start), end - start, - prot, early_pgtable_alloc, flags); + early_create_pgd_mapping(pgdp, start, __phys_to_virt(start), end - start, + prot, early_pgtable_alloc, flags); } void __init mark_linear_text_alias_ro(void) @@ -1207,6 +1256,8 @@ static int __init __kpti_install_ng_mappings(void *__unused) remap_fn = (void *)__pa_symbol(idmap_kpti_install_ng_mappings); if (!cpu) { + int ret; + alloc = __get_free_pages(GFP_ATOMIC | __GFP_ZERO, order); kpti_ng_temp_pgd = (pgd_t *)(alloc + (levels - 1) * PAGE_SIZE); kpti_ng_temp_alloc = kpti_ng_temp_pgd_pa = __pa(kpti_ng_temp_pgd); @@ -1227,9 +1278,11 @@ static int __init __kpti_install_ng_mappings(void *__unused) // covers the PTE[] page itself, the remaining entries are free // to be used as a ad-hoc fixmap. // - __create_pgd_mapping_locked(kpti_ng_temp_pgd, __pa(alloc), - KPTI_NG_TEMP_VA, PAGE_SIZE, PAGE_KERNEL, - kpti_ng_pgd_alloc, 0); + ret = __create_pgd_mapping_locked(kpti_ng_temp_pgd, __pa(alloc), + KPTI_NG_TEMP_VA, PAGE_SIZE, PAGE_KERNEL, + kpti_ng_pgd_alloc, 0); + if (ret) + panic("Failed to create page tables\n"); } cpu_install_idmap(); @@ -1282,9 +1335,9 @@ static int __init map_entry_trampoline(void) /* Map only the text into the trampoline page table */ memset(tramp_pg_dir, 0, PGD_SIZE); - __create_pgd_mapping(tramp_pg_dir, pa_start, TRAMP_VALIAS, - entry_tramp_text_size(), prot, - pgd_pgtable_alloc_init_mm, NO_BLOCK_MAPPINGS); + early_create_pgd_mapping(tramp_pg_dir, pa_start, TRAMP_VALIAS, + entry_tramp_text_size(), prot, + pgd_pgtable_alloc_init_mm, NO_BLOCK_MAPPINGS); /* Map both the text and data into the kernel page table */ for (i = 0; i < DIV_ROUND_UP(entry_tramp_text_size(), PAGE_SIZE); i++) @@ -1926,23 +1979,28 @@ int arch_add_memory(int nid, u64 start, u64 size, if (force_pte_mapping()) flags |= NO_BLOCK_MAPPINGS | NO_CONT_MAPPINGS; - __create_pgd_mapping(swapper_pg_dir, start, __phys_to_virt(start), - size, params->pgprot, pgd_pgtable_alloc_init_mm, - flags); + ret = __create_pgd_mapping(swapper_pg_dir, start, __phys_to_virt(start), + size, params->pgprot, pgd_pgtable_alloc_init_mm, + flags); + if (ret) + goto err; memblock_clear_nomap(start, size); ret = __add_pages(nid, start >> PAGE_SHIFT, size >> PAGE_SHIFT, params); if (ret) - __remove_pgd_mapping(swapper_pg_dir, - __phys_to_virt(start), size); - else { - /* Address of hotplugged memory can be smaller */ - max_pfn = max(max_pfn, PFN_UP(start + size)); - max_low_pfn = max_pfn; - } + goto err; + + /* Address of hotplugged memory can be smaller */ + max_pfn = max(max_pfn, PFN_UP(start + size)); + max_low_pfn = max_pfn; + + return 0; +err: + __remove_pgd_mapping(swapper_pg_dir, + __phys_to_virt(start), size); return ret; } From 677b91705b351951bb50edee9cdd868757d39b09 Mon Sep 17 00:00:00 2001 From: Lizhi Hou Date: Fri, 7 Nov 2025 10:11:15 -0800 Subject: [PATCH 0648/2333] accel/amdxdna: Clear mailbox interrupt register during channel creation [ Upstream commit 6ff9385c07aa311f01f87307e6256231be7d8675 ] The mailbox interrupt register is not always cleared when a mailbox channel is created. This can leave stale interrupt states from previous operations. Fix this by explicitly clearing the interrupt register in the mailbox channel creation function. Fixes: b87f920b9344 ("accel/amdxdna: Support hardware mailbox") Reviewed-by: Maciej Falkowski Signed-off-by: Lizhi Hou Link: https://patch.msgid.link/20251107181115.1293158-1-lizhi.hou@amd.com Signed-off-by: Sasha Levin --- drivers/accel/amdxdna/amdxdna_mailbox.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/accel/amdxdna/amdxdna_mailbox.c b/drivers/accel/amdxdna/amdxdna_mailbox.c index da1ac89bb78f1..6634a4d5717ff 100644 --- a/drivers/accel/amdxdna/amdxdna_mailbox.c +++ b/drivers/accel/amdxdna/amdxdna_mailbox.c @@ -513,6 +513,7 @@ xdna_mailbox_create_channel(struct mailbox *mb, } mb_chann->bad_state = false; + mailbox_reg_write(mb_chann, mb_chann->iohub_int_addr, 0); MB_DBG(mb_chann, "Mailbox channel created (irq: %d)", mb_chann->msix_irq); return mb_chann; From 2f13baf62bbd1b38e82b04f062c86e75ee1155a6 Mon Sep 17 00:00:00 2001 From: Lizhi Hou Date: Fri, 7 Nov 2025 10:10:50 -0800 Subject: [PATCH 0649/2333] accel/amdxdna: Fix deadlock between context destroy and job timeout [ Upstream commit ca2583412306ceda9304a7c4302fd9efbf43e963 ] Hardware context destroy function holds dev_lock while waiting for all jobs to complete. The timeout job also needs to acquire dev_lock, this leads to a deadlock. Fix the issue by temporarily releasing dev_lock before waiting for all jobs to finish, and reacquiring it afterward. Fixes: 4fd6ca90fc7f ("accel/amdxdna: Refactor hardware context destroy routine") Reviewed-by: Maciej Falkowski Signed-off-by: Lizhi Hou Link: https://patch.msgid.link/20251107181050.1293125-1-lizhi.hou@amd.com Signed-off-by: Sasha Levin --- drivers/accel/amdxdna/aie2_ctx.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/accel/amdxdna/aie2_ctx.c b/drivers/accel/amdxdna/aie2_ctx.c index 2e479a8d86c31..75246c481fa50 100644 --- a/drivers/accel/amdxdna/aie2_ctx.c +++ b/drivers/accel/amdxdna/aie2_ctx.c @@ -681,17 +681,19 @@ void aie2_hwctx_fini(struct amdxdna_hwctx *hwctx) ndev->hwctx_num--; XDNA_DBG(xdna, "%s sequence number %lld", hwctx->name, hwctx->priv->seq); - drm_sched_entity_destroy(&hwctx->priv->entity); - aie2_hwctx_wait_for_idle(hwctx); /* Request fw to destroy hwctx and cancel the rest pending requests */ aie2_release_resource(hwctx); + mutex_unlock(&xdna->dev_lock); + drm_sched_entity_destroy(&hwctx->priv->entity); + /* Wait for all submitted jobs to be completed or canceled */ wait_event(hwctx->priv->job_free_wq, atomic64_read(&hwctx->job_submit_cnt) == atomic64_read(&hwctx->job_free_cnt)); + mutex_lock(&xdna->dev_lock); drm_sched_fini(&hwctx->priv->sched); aie2_ctx_syncobj_destroy(hwctx); From 4a03d69cece145e4fb527464be29c3806aa3221e Mon Sep 17 00:00:00 2001 From: Leon Hwang Date: Wed, 5 Nov 2025 23:14:06 +0800 Subject: [PATCH 0650/2333] bpf: Free special fields when update [lru_,]percpu_hash maps [ Upstream commit 6af6e49a76c9af7d42eb923703e7648cb2bf401a ] As [lru_,]percpu_hash maps support BPF_KPTR_{REF,PERCPU}, missing calls to 'bpf_obj_free_fields()' in 'pcpu_copy_value()' could cause the memory referenced by BPF_KPTR_{REF,PERCPU} fields to be held until the map gets freed. Fix this by calling 'bpf_obj_free_fields()' after 'copy_map_value[,_long]()' in 'pcpu_copy_value()'. Fixes: 65334e64a493 ("bpf: Support kptrs in percpu hashmap and percpu LRU hashmap") Signed-off-by: Leon Hwang Acked-by: Yonghong Song Link: https://lore.kernel.org/r/20251105151407.12723-2-leon.hwang@linux.dev Signed-off-by: Alexei Starovoitov Signed-off-by: Sasha Levin --- kernel/bpf/hashtab.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/kernel/bpf/hashtab.c b/kernel/bpf/hashtab.c index c2fcd0cd51e51..e7721f0776c72 100644 --- a/kernel/bpf/hashtab.c +++ b/kernel/bpf/hashtab.c @@ -947,15 +947,21 @@ static void free_htab_elem(struct bpf_htab *htab, struct htab_elem *l) static void pcpu_copy_value(struct bpf_htab *htab, void __percpu *pptr, void *value, bool onallcpus) { + void *ptr; + if (!onallcpus) { /* copy true value_size bytes */ - copy_map_value(&htab->map, this_cpu_ptr(pptr), value); + ptr = this_cpu_ptr(pptr); + copy_map_value(&htab->map, ptr, value); + bpf_obj_free_fields(htab->map.record, ptr); } else { u32 size = round_up(htab->map.value_size, 8); int off = 0, cpu; for_each_possible_cpu(cpu) { - copy_map_value_long(&htab->map, per_cpu_ptr(pptr, cpu), value + off); + ptr = per_cpu_ptr(pptr, cpu); + copy_map_value_long(&htab->map, ptr, value + off); + bpf_obj_free_fields(htab->map.record, ptr); off += size; } } From 59a8b59c5a49ea1827be080d5726436949f0cceb Mon Sep 17 00:00:00 2001 From: Siddharth Vadapalli Date: Wed, 29 Oct 2025 13:34:51 +0530 Subject: [PATCH 0651/2333] PCI: keystone: Exit ks_pcie_probe() for invalid mode [ Upstream commit 95d9c3f0e4546eaec0977f3b387549a8463cd49f ] Commit under Fixes introduced support for PCIe EP mode on AM654x platforms. When the mode happens to be either "DW_PCIE_RC_TYPE" or "DW_PCIE_EP_TYPE", the PCIe Controller is configured accordingly. However, when the mode is neither of them, an error message is displayed, but the driver probe succeeds. Since this "invalid" mode is not associated with a functional PCIe Controller, the probe should fail. Fix the behavior by exiting "ks_pcie_probe()" with the return value of "-EINVAL" in addition to displaying the existing error message when the mode is invalid. Fixes: 23284ad677a9 ("PCI: keystone: Add support for PCIe EP in AM654x Platforms") Signed-off-by: Siddharth Vadapalli Signed-off-by: Manivannan Sadhasivam Signed-off-by: Bjorn Helgaas Link: https://patch.msgid.link/20251029080547.1253757-4-s-vadapalli@ti.com Signed-off-by: Sasha Levin --- drivers/pci/controller/dwc/pci-keystone.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index eb00aa3807220..25b8193ffbcf1 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c @@ -1337,6 +1337,8 @@ static int ks_pcie_probe(struct platform_device *pdev) break; default: dev_err(dev, "INVALID device type %d\n", mode); + ret = -EINVAL; + goto err_get_sync; } ks_pcie_enable_error_irq(ks_pcie); From 58f2087a7ccd1bcc37439cfef67ced0c09d9322b Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Wed, 5 Nov 2025 09:05:25 +0200 Subject: [PATCH 0652/2333] soc: renesas: r9a09g056-sys: Populate max_register [ Upstream commit 4ff787433ba6d564b00334b4bfd6350f5b6f4bb3 ] Populate max_register to avoid external aborts. Fixes: 2da2740fb9c8 ("soc: renesas: rz-sysc: Add syscon/regmap support") Signed-off-by: Claudiu Beznea Reviewed-by: Geert Uytterhoeven Link: https://patch.msgid.link/20251105070526.264445-2-claudiu.beznea.uj@bp.renesas.com Signed-off-by: Geert Uytterhoeven Signed-off-by: Sasha Levin --- drivers/soc/renesas/r9a09g056-sys.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/soc/renesas/r9a09g056-sys.c b/drivers/soc/renesas/r9a09g056-sys.c index 3ad1422eba36e..16b4e433c3373 100644 --- a/drivers/soc/renesas/r9a09g056-sys.c +++ b/drivers/soc/renesas/r9a09g056-sys.c @@ -72,4 +72,5 @@ static const struct rz_sysc_soc_id_init_data rzv2n_sys_soc_id_init_data __initco const struct rz_sysc_init_data rzv2n_sys_init_data = { .soc_id_init_data = &rzv2n_sys_soc_id_init_data, + .max_register = 0x170c, }; From ee6dda36b499def7c2158310dc3608fa3dd6bf2e Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Wed, 5 Nov 2025 09:05:26 +0200 Subject: [PATCH 0653/2333] soc: renesas: rz-sysc: Populate readable_reg/writeable_reg in regmap config [ Upstream commit c432180a7d95081353a96fd6d5bd75b0fc8a27c3 ] Not all system controller registers are accessible from Linux. Accessing such registers generates synchronous external abort. Populate the readable_reg and writeable_reg members of the regmap config to inform the regmap core which registers can be accessed. The list will need to be updated whenever new system controller functionality is exported through regmap. Fixes: 2da2740fb9c8 ("soc: renesas: rz-sysc: Add syscon/regmap support") Signed-off-by: Claudiu Beznea Reviewed-by: Geert Uytterhoeven Link: https://patch.msgid.link/20251105070526.264445-3-claudiu.beznea.uj@bp.renesas.com Signed-off-by: Geert Uytterhoeven Signed-off-by: Sasha Levin --- drivers/soc/renesas/r9a08g045-sysc.c | 69 ++++++++++++++++++ drivers/soc/renesas/r9a09g047-sys.c | 79 +++++++++++++++++++++ drivers/soc/renesas/r9a09g056-sys.c | 68 ++++++++++++++++++ drivers/soc/renesas/r9a09g057-sys.c | 101 +++++++++++++++++++++++++++ drivers/soc/renesas/rz-sysc.c | 2 + drivers/soc/renesas/rz-sysc.h | 4 ++ 6 files changed, 323 insertions(+) diff --git a/drivers/soc/renesas/r9a08g045-sysc.c b/drivers/soc/renesas/r9a08g045-sysc.c index 0504d4e687616..03d653d5cde55 100644 --- a/drivers/soc/renesas/r9a08g045-sysc.c +++ b/drivers/soc/renesas/r9a08g045-sysc.c @@ -6,10 +6,29 @@ */ #include +#include #include #include "rz-sysc.h" +#define SYS_XSPI_MAP_STAADD_CS0 0x348 +#define SYS_XSPI_MAP_ENDADD_CS0 0x34c +#define SYS_XSPI_MAP_STAADD_CS1 0x350 +#define SYS_XSPI_MAP_ENDADD_CS1 0x354 +#define SYS_GETH0_CFG 0x380 +#define SYS_GETH1_CFG 0x390 +#define SYS_PCIE_CFG 0x3a0 +#define SYS_PCIE_MON 0x3a4 +#define SYS_PCIE_ERR_MON 0x3ac +#define SYS_PCIE_PHY 0x3b4 +#define SYS_I2C0_CFG 0x400 +#define SYS_I2C1_CFG 0x410 +#define SYS_I2C2_CFG 0x420 +#define SYS_I2C3_CFG 0x430 +#define SYS_I3C_CFG 0x440 +#define SYS_USB_PWRRDY 0xd70 +#define SYS_PCIE_RST_RSM_B 0xd74 + static const struct rz_sysc_soc_id_init_data rzg3s_sysc_soc_id_init_data __initconst = { .family = "RZ/G3S", .id = 0x85e0447, @@ -18,7 +37,57 @@ static const struct rz_sysc_soc_id_init_data rzg3s_sysc_soc_id_init_data __initc .specific_id_mask = GENMASK(27, 0), }; +static bool rzg3s_regmap_readable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case SYS_XSPI_MAP_STAADD_CS0: + case SYS_XSPI_MAP_ENDADD_CS0: + case SYS_XSPI_MAP_STAADD_CS1: + case SYS_XSPI_MAP_ENDADD_CS1: + case SYS_GETH0_CFG: + case SYS_GETH1_CFG: + case SYS_PCIE_CFG: + case SYS_PCIE_MON: + case SYS_PCIE_ERR_MON: + case SYS_PCIE_PHY: + case SYS_I2C0_CFG: + case SYS_I2C1_CFG: + case SYS_I2C2_CFG: + case SYS_I2C3_CFG: + case SYS_I3C_CFG: + case SYS_USB_PWRRDY: + case SYS_PCIE_RST_RSM_B: + return true; + default: + return false; + } +} + +static bool rzg3s_regmap_writeable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case SYS_XSPI_MAP_STAADD_CS0: + case SYS_XSPI_MAP_ENDADD_CS0: + case SYS_XSPI_MAP_STAADD_CS1: + case SYS_XSPI_MAP_ENDADD_CS1: + case SYS_PCIE_CFG: + case SYS_PCIE_PHY: + case SYS_I2C0_CFG: + case SYS_I2C1_CFG: + case SYS_I2C2_CFG: + case SYS_I2C3_CFG: + case SYS_I3C_CFG: + case SYS_USB_PWRRDY: + case SYS_PCIE_RST_RSM_B: + return true; + default: + return false; + } +} + const struct rz_sysc_init_data rzg3s_sysc_init_data __initconst = { .soc_id_init_data = &rzg3s_sysc_soc_id_init_data, + .readable_reg = rzg3s_regmap_readable_reg, + .writeable_reg = rzg3s_regmap_writeable_reg, .max_register = 0xe20, }; diff --git a/drivers/soc/renesas/r9a09g047-sys.c b/drivers/soc/renesas/r9a09g047-sys.c index 2e8426c030504..e413b0eff9bfd 100644 --- a/drivers/soc/renesas/r9a09g047-sys.c +++ b/drivers/soc/renesas/r9a09g047-sys.c @@ -29,6 +29,27 @@ #define SYS_LSI_PRR_CA55_DIS BIT(8) #define SYS_LSI_PRR_NPU_DIS BIT(1) +#define SYS_LSI_OTPTSU1TRMVAL0 0x330 +#define SYS_LSI_OTPTSU1TRMVAL1 0x334 +#define SYS_SPI_STAADDCS0 0x900 +#define SYS_SPI_ENDADDCS0 0x904 +#define SYS_SPI_STAADDCS1 0x908 +#define SYS_SPI_ENDADDCS1 0x90c +#define SYS_VSP_CLK 0xe00 +#define SYS_GBETH0_CFG 0xf00 +#define SYS_GBETH1_CFG 0xf04 +#define SYS_PCIE_INTX_CH0 0x1000 +#define SYS_PCIE_MSI1_CH0 0x1004 +#define SYS_PCIE_MSI2_CH0 0x1008 +#define SYS_PCIE_MSI3_CH0 0x100c +#define SYS_PCIE_MSI4_CH0 0x1010 +#define SYS_PCIE_MSI5_CH0 0x1014 +#define SYS_PCIE_PME_CH0 0x1018 +#define SYS_PCIE_ACK_CH0 0x101c +#define SYS_PCIE_MISC_CH0 0x1020 +#define SYS_PCIE_MODE_CH0 0x1024 +#define SYS_ADC_CFG 0x1600 + static void rzg3e_sys_print_id(struct device *dev, void __iomem *sysc_base, struct soc_device_attribute *soc_dev_attr) @@ -62,7 +83,65 @@ static const struct rz_sysc_soc_id_init_data rzg3e_sys_soc_id_init_data __initco .print_id = rzg3e_sys_print_id, }; +static bool rzg3e_regmap_readable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case SYS_LSI_OTPTSU1TRMVAL0: + case SYS_LSI_OTPTSU1TRMVAL1: + case SYS_SPI_STAADDCS0: + case SYS_SPI_ENDADDCS0: + case SYS_SPI_STAADDCS1: + case SYS_SPI_ENDADDCS1: + case SYS_VSP_CLK: + case SYS_GBETH0_CFG: + case SYS_GBETH1_CFG: + case SYS_PCIE_INTX_CH0: + case SYS_PCIE_MSI1_CH0: + case SYS_PCIE_MSI2_CH0: + case SYS_PCIE_MSI3_CH0: + case SYS_PCIE_MSI4_CH0: + case SYS_PCIE_MSI5_CH0: + case SYS_PCIE_PME_CH0: + case SYS_PCIE_ACK_CH0: + case SYS_PCIE_MISC_CH0: + case SYS_PCIE_MODE_CH0: + case SYS_ADC_CFG: + return true; + default: + return false; + } +} + +static bool rzg3e_regmap_writeable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case SYS_SPI_STAADDCS0: + case SYS_SPI_ENDADDCS0: + case SYS_SPI_STAADDCS1: + case SYS_SPI_ENDADDCS1: + case SYS_VSP_CLK: + case SYS_GBETH0_CFG: + case SYS_GBETH1_CFG: + case SYS_PCIE_INTX_CH0: + case SYS_PCIE_MSI1_CH0: + case SYS_PCIE_MSI2_CH0: + case SYS_PCIE_MSI3_CH0: + case SYS_PCIE_MSI4_CH0: + case SYS_PCIE_MSI5_CH0: + case SYS_PCIE_PME_CH0: + case SYS_PCIE_ACK_CH0: + case SYS_PCIE_MISC_CH0: + case SYS_PCIE_MODE_CH0: + case SYS_ADC_CFG: + return true; + default: + return false; + } +} + const struct rz_sysc_init_data rzg3e_sys_init_data = { .soc_id_init_data = &rzg3e_sys_soc_id_init_data, + .readable_reg = rzg3e_regmap_readable_reg, + .writeable_reg = rzg3e_regmap_writeable_reg, .max_register = 0x170c, }; diff --git a/drivers/soc/renesas/r9a09g056-sys.c b/drivers/soc/renesas/r9a09g056-sys.c index 16b4e433c3373..42f5eff291fd1 100644 --- a/drivers/soc/renesas/r9a09g056-sys.c +++ b/drivers/soc/renesas/r9a09g056-sys.c @@ -34,6 +34,24 @@ #define SYS_RZV2N_FEATURE_C55 BIT(1) #define SYS_RZV2N_FEATURE_SEC BIT(2) +#define SYS_LSI_OTPTSU0TRMVAL0 0x320 +#define SYS_LSI_OTPTSU0TRMVAL1 0x324 +#define SYS_LSI_OTPTSU1TRMVAL0 0x330 +#define SYS_LSI_OTPTSU1TRMVAL1 0x334 +#define SYS_GBETH0_CFG 0xf00 +#define SYS_GBETH1_CFG 0xf04 +#define SYS_PCIE_INTX_CH0 0x1000 +#define SYS_PCIE_MSI1_CH0 0x1004 +#define SYS_PCIE_MSI2_CH0 0x1008 +#define SYS_PCIE_MSI3_CH0 0x100c +#define SYS_PCIE_MSI4_CH0 0x1010 +#define SYS_PCIE_MSI5_CH0 0x1014 +#define SYS_PCIE_PME_CH0 0x1018 +#define SYS_PCIE_ACK_CH0 0x101c +#define SYS_PCIE_MISC_CH0 0x1020 +#define SYS_PCIE_MODE_CH0 0x1024 +#define SYS_ADC_CFG 0x1600 + static void rzv2n_sys_print_id(struct device *dev, void __iomem *sysc_base, struct soc_device_attribute *soc_dev_attr) @@ -70,7 +88,57 @@ static const struct rz_sysc_soc_id_init_data rzv2n_sys_soc_id_init_data __initco .print_id = rzv2n_sys_print_id, }; +static bool rzv2n_regmap_readable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case SYS_LSI_OTPTSU0TRMVAL0: + case SYS_LSI_OTPTSU0TRMVAL1: + case SYS_LSI_OTPTSU1TRMVAL0: + case SYS_LSI_OTPTSU1TRMVAL1: + case SYS_GBETH0_CFG: + case SYS_GBETH1_CFG: + case SYS_PCIE_INTX_CH0: + case SYS_PCIE_MSI1_CH0: + case SYS_PCIE_MSI2_CH0: + case SYS_PCIE_MSI3_CH0: + case SYS_PCIE_MSI4_CH0: + case SYS_PCIE_MSI5_CH0: + case SYS_PCIE_PME_CH0: + case SYS_PCIE_ACK_CH0: + case SYS_PCIE_MISC_CH0: + case SYS_PCIE_MODE_CH0: + case SYS_ADC_CFG: + return true; + default: + return false; + } +} + +static bool rzv2n_regmap_writeable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case SYS_GBETH0_CFG: + case SYS_GBETH1_CFG: + case SYS_PCIE_INTX_CH0: + case SYS_PCIE_MSI1_CH0: + case SYS_PCIE_MSI2_CH0: + case SYS_PCIE_MSI3_CH0: + case SYS_PCIE_MSI4_CH0: + case SYS_PCIE_MSI5_CH0: + case SYS_PCIE_PME_CH0: + case SYS_PCIE_ACK_CH0: + case SYS_PCIE_MISC_CH0: + case SYS_PCIE_MODE_CH0: + case SYS_ADC_CFG: + return true; + default: + return false; + } +} + const struct rz_sysc_init_data rzv2n_sys_init_data = { .soc_id_init_data = &rzv2n_sys_soc_id_init_data, + .readable_reg = rzv2n_regmap_readable_reg, + .writeable_reg = rzv2n_regmap_writeable_reg, .max_register = 0x170c, }; diff --git a/drivers/soc/renesas/r9a09g057-sys.c b/drivers/soc/renesas/r9a09g057-sys.c index e3390e7c7fe51..827c718ac7c54 100644 --- a/drivers/soc/renesas/r9a09g057-sys.c +++ b/drivers/soc/renesas/r9a09g057-sys.c @@ -29,6 +29,35 @@ #define SYS_LSI_PRR_GPU_DIS BIT(0) #define SYS_LSI_PRR_ISP_DIS BIT(4) +#define SYS_LSI_OTPTSU0TRMVAL0 0x320 +#define SYS_LSI_OTPTSU0TRMVAL1 0x324 +#define SYS_LSI_OTPTSU1TRMVAL0 0x330 +#define SYS_LSI_OTPTSU1TRMVAL1 0x334 +#define SYS_GBETH0_CFG 0xf00 +#define SYS_GBETH1_CFG 0xf04 +#define SYS_PCIE_INTX_CH0 0x1000 +#define SYS_PCIE_MSI1_CH0 0x1004 +#define SYS_PCIE_MSI2_CH0 0x1008 +#define SYS_PCIE_MSI3_CH0 0x100c +#define SYS_PCIE_MSI4_CH0 0x1010 +#define SYS_PCIE_MSI5_CH0 0x1014 +#define SYS_PCIE_PME_CH0 0x1018 +#define SYS_PCIE_ACK_CH0 0x101c +#define SYS_PCIE_MISC_CH0 0x1020 +#define SYS_PCIE_MODE_CH0 0x1024 +#define SYS_PCIE_INTX_CH1 0x1030 +#define SYS_PCIE_MSI1_CH1 0x1034 +#define SYS_PCIE_MSI2_CH1 0x1038 +#define SYS_PCIE_MSI3_CH1 0x103c +#define SYS_PCIE_MSI4_CH1 0x1040 +#define SYS_PCIE_MSI5_CH1 0x1044 +#define SYS_PCIE_PME_CH1 0x1048 +#define SYS_PCIE_ACK_CH1 0x104c +#define SYS_PCIE_MISC_CH1 0x1050 +#define SYS_PCIE_MODE_CH1 0x1054 +#define SYS_PCIE_MODE 0x1060 +#define SYS_ADC_CFG 0x1600 + static void rzv2h_sys_print_id(struct device *dev, void __iomem *sysc_base, struct soc_device_attribute *soc_dev_attr) @@ -62,7 +91,79 @@ static const struct rz_sysc_soc_id_init_data rzv2h_sys_soc_id_init_data __initco .print_id = rzv2h_sys_print_id, }; +static bool rzv2h_regmap_readable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case SYS_LSI_OTPTSU0TRMVAL0: + case SYS_LSI_OTPTSU0TRMVAL1: + case SYS_LSI_OTPTSU1TRMVAL0: + case SYS_LSI_OTPTSU1TRMVAL1: + case SYS_GBETH0_CFG: + case SYS_GBETH1_CFG: + case SYS_PCIE_INTX_CH0: + case SYS_PCIE_MSI1_CH0: + case SYS_PCIE_MSI2_CH0: + case SYS_PCIE_MSI3_CH0: + case SYS_PCIE_MSI4_CH0: + case SYS_PCIE_MSI5_CH0: + case SYS_PCIE_PME_CH0: + case SYS_PCIE_ACK_CH0: + case SYS_PCIE_MISC_CH0: + case SYS_PCIE_MODE_CH0: + case SYS_PCIE_INTX_CH1: + case SYS_PCIE_MSI1_CH1: + case SYS_PCIE_MSI2_CH1: + case SYS_PCIE_MSI3_CH1: + case SYS_PCIE_MSI4_CH1: + case SYS_PCIE_MSI5_CH1: + case SYS_PCIE_PME_CH1: + case SYS_PCIE_ACK_CH1: + case SYS_PCIE_MISC_CH1: + case SYS_PCIE_MODE_CH1: + case SYS_PCIE_MODE: + case SYS_ADC_CFG: + return true; + default: + return false; + } +} + +static bool rzv2h_regmap_writeable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case SYS_GBETH0_CFG: + case SYS_GBETH1_CFG: + case SYS_PCIE_INTX_CH0: + case SYS_PCIE_MSI1_CH0: + case SYS_PCIE_MSI2_CH0: + case SYS_PCIE_MSI3_CH0: + case SYS_PCIE_MSI4_CH0: + case SYS_PCIE_MSI5_CH0: + case SYS_PCIE_PME_CH0: + case SYS_PCIE_ACK_CH0: + case SYS_PCIE_MISC_CH0: + case SYS_PCIE_MODE_CH0: + case SYS_PCIE_INTX_CH1: + case SYS_PCIE_MSI1_CH1: + case SYS_PCIE_MSI2_CH1: + case SYS_PCIE_MSI3_CH1: + case SYS_PCIE_MSI4_CH1: + case SYS_PCIE_MSI5_CH1: + case SYS_PCIE_PME_CH1: + case SYS_PCIE_ACK_CH1: + case SYS_PCIE_MISC_CH1: + case SYS_PCIE_MODE_CH1: + case SYS_PCIE_MODE: + case SYS_ADC_CFG: + return true; + default: + return false; + } +} + const struct rz_sysc_init_data rzv2h_sys_init_data = { .soc_id_init_data = &rzv2h_sys_soc_id_init_data, + .readable_reg = rzv2h_regmap_readable_reg, + .writeable_reg = rzv2h_regmap_writeable_reg, .max_register = 0x170c, }; diff --git a/drivers/soc/renesas/rz-sysc.c b/drivers/soc/renesas/rz-sysc.c index 9f79e299e6f41..19c1e666279b7 100644 --- a/drivers/soc/renesas/rz-sysc.c +++ b/drivers/soc/renesas/rz-sysc.c @@ -140,6 +140,8 @@ static int rz_sysc_probe(struct platform_device *pdev) regmap_cfg->val_bits = 32; regmap_cfg->fast_io = true; regmap_cfg->max_register = data->max_register; + regmap_cfg->readable_reg = data->readable_reg; + regmap_cfg->writeable_reg = data->writeable_reg; regmap = devm_regmap_init_mmio(dev, sysc->base, regmap_cfg); if (IS_ERR(regmap)) diff --git a/drivers/soc/renesas/rz-sysc.h b/drivers/soc/renesas/rz-sysc.h index 8eec355d5d562..88929bf21cb11 100644 --- a/drivers/soc/renesas/rz-sysc.h +++ b/drivers/soc/renesas/rz-sysc.h @@ -34,10 +34,14 @@ struct rz_sysc_soc_id_init_data { /** * struct rz_sysc_init_data - RZ SYSC initialization data * @soc_id_init_data: RZ SYSC SoC ID initialization data + * @writeable_reg: Regmap writeable register check function + * @readable_reg: Regmap readable register check function * @max_register: Maximum SYSC register offset to be used by the regmap config */ struct rz_sysc_init_data { const struct rz_sysc_soc_id_init_data *soc_id_init_data; + bool (*writeable_reg)(struct device *dev, unsigned int reg); + bool (*readable_reg)(struct device *dev, unsigned int reg); u32 max_register; }; From 3eeb44415063095da9a8c131dd34b9b86f46c55c Mon Sep 17 00:00:00 2001 From: FUKAUMI Naoki Date: Wed, 12 Nov 2025 03:51:29 +0000 Subject: [PATCH 0654/2333] arm64: dts: rockchip: Move the EEPROM to correct I2C bus on Radxa ROCK 5A [ Upstream commit 92e6e0b0e595afdda6296c760551ad3ffe9d5231 ] The BL24C16 EEPROM chip found on Radxa ROCK 5A is connected to the i2c0 bus, [1] so move the eeprom node from the i2c2 bus to the i2c0 bus. [1] Link: https://dl.radxa.com/rock5/5a/docs/hw/radxa_rock5a_V1.1_sch.pdf p.19 Fixes: 89c880808cff8 ("arm64: dts: rockchip: add I2C EEPROM to rock-5a") Signed-off-by: FUKAUMI Naoki Link: https://patch.msgid.link/20251112035133.28753-2-naoki@radxa.com Signed-off-by: Heiko Stuebner Signed-off-by: Sasha Levin --- arch/arm64/boot/dts/rockchip/rk3588s-rock-5a.dts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/arm64/boot/dts/rockchip/rk3588s-rock-5a.dts b/arch/arm64/boot/dts/rockchip/rk3588s-rock-5a.dts index 19a08f7794e67..428c6f0232a34 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588s-rock-5a.dts +++ b/arch/arm64/boot/dts/rockchip/rk3588s-rock-5a.dts @@ -228,6 +228,12 @@ regulator-off-in-suspend; }; }; + + eeprom: eeprom@50 { + compatible = "belling,bl24c16a", "atmel,24c16"; + reg = <0x50>; + pagesize = <16>; + }; }; &i2c2 { @@ -249,12 +255,6 @@ regulator-off-in-suspend; }; }; - - eeprom: eeprom@50 { - compatible = "belling,bl24c16a", "atmel,24c16"; - reg = <0x50>; - pagesize = <16>; - }; }; &i2c3 { From 63d98a936f0f4b723596ae023ba180f495e7b43a Mon Sep 17 00:00:00 2001 From: FUKAUMI Naoki Date: Wed, 12 Nov 2025 03:51:30 +0000 Subject: [PATCH 0655/2333] arm64: dts: rockchip: Add eeprom vcc-supply for Radxa ROCK 5A [ Upstream commit 3069ff1930aa71e125874c780ffaa6caeda5800a ] The VCC supply for the BL24C16 EEPROM chip found on Radxa ROCK 5A is vcc_3v3_pmu, which is routed to vcc_3v3_s3 via a zero-ohm resistor. [1] Describe this supply. [1] https://dl.radxa.com/rock5/5a/docs/hw/radxa_rock5a_V1.1_sch.pdf p.4, p.19 Fixes: 89c880808cff8 ("arm64: dts: rockchip: add I2C EEPROM to rock-5a") Signed-off-by: FUKAUMI Naoki Link: https://patch.msgid.link/20251112035133.28753-3-naoki@radxa.com Signed-off-by: Heiko Stuebner Signed-off-by: Sasha Levin --- arch/arm64/boot/dts/rockchip/rk3588s-rock-5a.dts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/rockchip/rk3588s-rock-5a.dts b/arch/arm64/boot/dts/rockchip/rk3588s-rock-5a.dts index 428c6f0232a34..041a0fff22ccb 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588s-rock-5a.dts +++ b/arch/arm64/boot/dts/rockchip/rk3588s-rock-5a.dts @@ -233,6 +233,7 @@ compatible = "belling,bl24c16a", "atmel,24c16"; reg = <0x50>; pagesize = <16>; + vcc-supply = <&vcc_3v3_pmu>; }; }; @@ -600,7 +601,7 @@ }; }; - vcc_3v3_s3: dcdc-reg8 { + vcc_3v3_pmu: vcc_3v3_s3: dcdc-reg8 { regulator-name = "vcc_3v3_s3"; regulator-always-on; regulator-boot-on; From 42a2a70a12e42d96d6cd8778705208bd77e4994e Mon Sep 17 00:00:00 2001 From: FUKAUMI Naoki Date: Wed, 12 Nov 2025 03:51:31 +0000 Subject: [PATCH 0656/2333] arm64: dts: rockchip: Add eeprom vcc-supply for Radxa ROCK 3C [ Upstream commit 260316d35cf8f8606c5ed7a349cc92e1e71d8150 ] The VCC supply for the BL24C16 EEPROM chip found on Radxa ROCK 3C is vcca1v8_pmu. [1] Describe this supply. [1] https://dl.radxa.com/rock3/docs/hw/3c/v1400/radxa_rock_3c_v1400_schematic.pdf p.13 Fixes: ee219017ddb50 ("arm64: dts: rockchip: Add Radxa ROCK 3C") Signed-off-by: FUKAUMI Naoki Link: https://patch.msgid.link/20251112035133.28753-4-naoki@radxa.com Signed-off-by: Heiko Stuebner Signed-off-by: Sasha Levin --- arch/arm64/boot/dts/rockchip/rk3566-rock-3c.dts | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/boot/dts/rockchip/rk3566-rock-3c.dts b/arch/arm64/boot/dts/rockchip/rk3566-rock-3c.dts index 6224d72813e59..80ac40555e023 100644 --- a/arch/arm64/boot/dts/rockchip/rk3566-rock-3c.dts +++ b/arch/arm64/boot/dts/rockchip/rk3566-rock-3c.dts @@ -466,6 +466,7 @@ compatible = "belling,bl24c16a", "atmel,24c16"; reg = <0x50>; pagesize = <16>; + vcc-supply = <&vcca1v8_pmu>; }; }; From 94a9c0c42cce51a53af36585328b44fb72a34f2d Mon Sep 17 00:00:00 2001 From: Zilin Guan Date: Sun, 9 Nov 2025 14:56:48 +0000 Subject: [PATCH 0657/2333] crypto: iaa - Fix incorrect return value in save_iaa_wq() [ Upstream commit 76ce17f6f7f78ab79b9741388bdb4dafa985b4e9 ] The save_iaa_wq() function unconditionally returns 0, even when an error is encountered. This prevents the error code from being propagated to the caller. Fix this by returning the 'ret' variable, which holds the actual status of the operations within the function. Fixes: ea7a5cbb43696 ("crypto: iaa - Add Intel IAA Compression Accelerator crypto driver core") Signed-off-by: Zilin Guan Signed-off-by: Herbert Xu Signed-off-by: Sasha Levin --- drivers/crypto/intel/iaa/iaa_crypto_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/crypto/intel/iaa/iaa_crypto_main.c b/drivers/crypto/intel/iaa/iaa_crypto_main.c index 23f585219fb4b..d0058757b0000 100644 --- a/drivers/crypto/intel/iaa/iaa_crypto_main.c +++ b/drivers/crypto/intel/iaa/iaa_crypto_main.c @@ -805,7 +805,7 @@ static int save_iaa_wq(struct idxd_wq *wq) if (!cpus_per_iaa) cpus_per_iaa = 1; out: - return 0; + return ret; } static void remove_iaa_wq(struct idxd_wq *wq) From 13dcd6308cb8f67134ee5d5d762b2a66363c695b Mon Sep 17 00:00:00 2001 From: Aleksei Nikiforov Date: Fri, 7 Nov 2025 16:59:16 +0100 Subject: [PATCH 0658/2333] s390/fpu: Fix false-positive kmsan report in fpu_vstl() [ Upstream commit 14e4e4175b64dd9216b522f6ece8af6997d063b2 ] A false-positive kmsan report is detected when running ping command. An inline assembly instruction 'vstl' can write varied amount of bytes depending on value of 'index' argument. If 'index' > 0, 'vstl' writes at least 2 bytes. clang generates kmsan write helper call depending on inline assembly constraints. Constraints are evaluated compile-time, but value of 'index' argument is known only at runtime. clang currently generates call to __msan_instrument_asm_store with 1 byte as size. Manually call kmsan function to indicate correct amount of bytes written and fix false-positive report. This change fixes following kmsan reports: [ 36.563119] ===================================================== [ 36.563594] BUG: KMSAN: uninit-value in virtqueue_add+0x35c6/0x7c70 [ 36.563852] virtqueue_add+0x35c6/0x7c70 [ 36.564016] virtqueue_add_outbuf+0xa0/0xb0 [ 36.564266] start_xmit+0x288c/0x4a20 [ 36.564460] dev_hard_start_xmit+0x302/0x900 [ 36.564649] sch_direct_xmit+0x340/0xea0 [ 36.564894] __dev_queue_xmit+0x2e94/0x59b0 [ 36.565058] neigh_resolve_output+0x936/0xb40 [ 36.565278] __neigh_update+0x2f66/0x3a60 [ 36.565499] neigh_update+0x52/0x60 [ 36.565683] arp_process+0x1588/0x2de0 [ 36.565916] NF_HOOK+0x1da/0x240 [ 36.566087] arp_rcv+0x3e4/0x6e0 [ 36.566306] __netif_receive_skb_list_core+0x1374/0x15a0 [ 36.566527] netif_receive_skb_list_internal+0x1116/0x17d0 [ 36.566710] napi_complete_done+0x376/0x740 [ 36.566918] virtnet_poll+0x1bae/0x2910 [ 36.567130] __napi_poll+0xf4/0x830 [ 36.567294] net_rx_action+0x97c/0x1ed0 [ 36.567556] handle_softirqs+0x306/0xe10 [ 36.567731] irq_exit_rcu+0x14c/0x2e0 [ 36.567910] do_io_irq+0xd4/0x120 [ 36.568139] io_int_handler+0xc2/0xe8 [ 36.568299] arch_cpu_idle+0xb0/0xc0 [ 36.568540] arch_cpu_idle+0x76/0xc0 [ 36.568726] default_idle_call+0x40/0x70 [ 36.568953] do_idle+0x1d6/0x390 [ 36.569486] cpu_startup_entry+0x9a/0xb0 [ 36.569745] rest_init+0x1ea/0x290 [ 36.570029] start_kernel+0x95e/0xb90 [ 36.570348] startup_continue+0x2e/0x40 [ 36.570703] [ 36.570798] Uninit was created at: [ 36.571002] kmem_cache_alloc_node_noprof+0x9e8/0x10e0 [ 36.571261] kmalloc_reserve+0x12a/0x470 [ 36.571553] __alloc_skb+0x310/0x860 [ 36.571844] __ip_append_data+0x483e/0x6a30 [ 36.572170] ip_append_data+0x11c/0x1e0 [ 36.572477] raw_sendmsg+0x1c8c/0x2180 [ 36.572818] inet_sendmsg+0xe6/0x190 [ 36.573142] __sys_sendto+0x55e/0x8e0 [ 36.573392] __s390x_sys_socketcall+0x19ae/0x2ba0 [ 36.573571] __do_syscall+0x12e/0x240 [ 36.573823] system_call+0x6e/0x90 [ 36.573976] [ 36.574017] Byte 35 of 98 is uninitialized [ 36.574082] Memory access of size 98 starts at 0000000007aa0012 [ 36.574218] [ 36.574325] CPU: 0 UID: 0 PID: 0 Comm: swapper/0 Tainted: G B N 6.17.0-dirty #16 NONE [ 36.574541] Tainted: [B]=BAD_PAGE, [N]=TEST [ 36.574617] Hardware name: IBM 3931 A01 703 (KVM/Linux) [ 36.574755] ===================================================== [ 63.532541] ===================================================== [ 63.533639] BUG: KMSAN: uninit-value in virtqueue_add+0x35c6/0x7c70 [ 63.533989] virtqueue_add+0x35c6/0x7c70 [ 63.534940] virtqueue_add_outbuf+0xa0/0xb0 [ 63.535861] start_xmit+0x288c/0x4a20 [ 63.536708] dev_hard_start_xmit+0x302/0x900 [ 63.537020] sch_direct_xmit+0x340/0xea0 [ 63.537997] __dev_queue_xmit+0x2e94/0x59b0 [ 63.538819] neigh_resolve_output+0x936/0xb40 [ 63.539793] ip_finish_output2+0x1ee2/0x2200 [ 63.540784] __ip_finish_output+0x272/0x7a0 [ 63.541765] ip_finish_output+0x4e/0x5e0 [ 63.542791] ip_output+0x166/0x410 [ 63.543771] ip_push_pending_frames+0x1a2/0x470 [ 63.544753] raw_sendmsg+0x1f06/0x2180 [ 63.545033] inet_sendmsg+0xe6/0x190 [ 63.546006] __sys_sendto+0x55e/0x8e0 [ 63.546859] __s390x_sys_socketcall+0x19ae/0x2ba0 [ 63.547730] __do_syscall+0x12e/0x240 [ 63.548019] system_call+0x6e/0x90 [ 63.548989] [ 63.549779] Uninit was created at: [ 63.550691] kmem_cache_alloc_node_noprof+0x9e8/0x10e0 [ 63.550975] kmalloc_reserve+0x12a/0x470 [ 63.551969] __alloc_skb+0x310/0x860 [ 63.552949] __ip_append_data+0x483e/0x6a30 [ 63.553902] ip_append_data+0x11c/0x1e0 [ 63.554912] raw_sendmsg+0x1c8c/0x2180 [ 63.556719] inet_sendmsg+0xe6/0x190 [ 63.557534] __sys_sendto+0x55e/0x8e0 [ 63.557875] __s390x_sys_socketcall+0x19ae/0x2ba0 [ 63.558869] __do_syscall+0x12e/0x240 [ 63.559832] system_call+0x6e/0x90 [ 63.560780] [ 63.560972] Byte 35 of 98 is uninitialized [ 63.561741] Memory access of size 98 starts at 0000000005704312 [ 63.561950] [ 63.562824] CPU: 3 UID: 0 PID: 192 Comm: ping Tainted: G B N 6.17.0-dirty #16 NONE [ 63.563868] Tainted: [B]=BAD_PAGE, [N]=TEST [ 63.564751] Hardware name: IBM 3931 A01 703 (KVM/Linux) [ 63.564986] ===================================================== Fixes: dcd3e1de9d17 ("s390/checksum: provide csum_partial_copy_nocheck()") Signed-off-by: Aleksei Nikiforov Signed-off-by: Heiko Carstens Signed-off-by: Sasha Levin --- arch/s390/include/asm/fpu-insn.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/s390/include/asm/fpu-insn.h b/arch/s390/include/asm/fpu-insn.h index e99f8bca8e08c..96727f3bd0dce 100644 --- a/arch/s390/include/asm/fpu-insn.h +++ b/arch/s390/include/asm/fpu-insn.h @@ -12,6 +12,7 @@ #ifndef __ASSEMBLER__ #include +#include #include asm(".include \"asm/fpu-insn-asm.h\"\n"); @@ -393,6 +394,7 @@ static __always_inline void fpu_vstl(u8 v1, u32 index, const void *vxr) : [vxr] "=Q" (*(u8 *)vxr) : [index] "d" (index), [v1] "I" (v1) : "memory"); + kmsan_unpoison_memory(vxr, size); } #else /* CONFIG_CC_HAS_ASM_AOR_FORMAT_FLAGS */ @@ -409,6 +411,7 @@ static __always_inline void fpu_vstl(u8 v1, u32 index, const void *vxr) : [vxr] "=R" (*(u8 *)vxr) : [index] "d" (index), [v1] "I" (v1) : "memory", "1"); + kmsan_unpoison_memory(vxr, size); } #endif /* CONFIG_CC_HAS_ASM_AOR_FORMAT_FLAGS */ From a2fb63bc252a8c580cae4d1430bafdc779ab1239 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 26 Sep 2025 18:57:03 +0200 Subject: [PATCH 0659/2333] pwm: Simplify printf to emit chip->npwm in $debugfs/pwm MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 3cf8e55894b51c14f8500cae5e68ed48b1b0f3fd ] Instead of caring to correctly pluralize "PWM device(s)" using (chip->npwm != 1) ? "s" : "" or str_plural(chip->npwm) just simplify the format to not need a plural-s. Signed-off-by: Uwe Kleine-König Link: https://patch.msgid.link/20250926165702.321514-2-u.kleine-koenig@baylibre.com Signed-off-by: Uwe Kleine-König Stable-dep-of: 5f7ff902e7f3 ("pwm: Use %u to printf unsigned int pwm_chip::npwm and pwm_chip::id") Signed-off-by: Sasha Levin --- drivers/pwm/core.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c index ea2ccf42e8144..5b75f4a084967 100644 --- a/drivers/pwm/core.c +++ b/drivers/pwm/core.c @@ -2696,11 +2696,10 @@ static int pwm_seq_show(struct seq_file *s, void *v) { struct pwm_chip *chip = v; - seq_printf(s, "%s%d: %s/%s, %d PWM device%s\n", + seq_printf(s, "%s%d: %s/%s, npwm: %d\n", (char *)s->private, chip->id, pwmchip_parent(chip)->bus ? pwmchip_parent(chip)->bus->name : "no-bus", - dev_name(pwmchip_parent(chip)), chip->npwm, - (chip->npwm != 1) ? "s" : ""); + dev_name(pwmchip_parent(chip)), chip->npwm); pwm_dbg_show(chip, s); From 036bae52e5c1055d225fb2be19d4fedea4192c6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 6 Oct 2025 15:35:26 +0200 Subject: [PATCH 0660/2333] pwm: Use %u to printf unsigned int pwm_chip::npwm and pwm_chip::id MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 5f7ff902e7f324c10f2b64c5ba2e5e2d0bc4e07e ] %u is the right conversion specifier to emit an unsigned int value. Fixes: 62099abf67a2 ("pwm: Add debugfs interface") Fixes: 0360a4873372 ("pwm: Mention PWM chip ID in /sys/kernel/debug/pwm") Signed-off-by: Uwe Kleine-König Link: https://patch.msgid.link/20251006133525.2457171-2-u.kleine-koenig@baylibre.com Signed-off-by: Uwe Kleine-König Signed-off-by: Sasha Levin --- drivers/pwm/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c index 5b75f4a084967..7dd1cf2ba4025 100644 --- a/drivers/pwm/core.c +++ b/drivers/pwm/core.c @@ -2696,7 +2696,7 @@ static int pwm_seq_show(struct seq_file *s, void *v) { struct pwm_chip *chip = v; - seq_printf(s, "%s%d: %s/%s, npwm: %d\n", + seq_printf(s, "%s%u: %s/%s, npwm: %u\n", (char *)s->private, chip->id, pwmchip_parent(chip)->bus ? pwmchip_parent(chip)->bus->name : "no-bus", dev_name(pwmchip_parent(chip)), chip->npwm); From 41ba9d25d965e52f45ffbb9e3a988d638256efbd Mon Sep 17 00:00:00 2001 From: Praveen Talari Date: Mon, 10 Nov 2025 15:40:40 +0530 Subject: [PATCH 0661/2333] arm64: dts: qcom: qrb2210-rb1: Fix UART3 wakeup IRQ storm [ Upstream commit 9c92d36b0b1ea8b2a19dbe0416434f3491dbfaaf ] For BT use cases, pins are configured with pull-up state in sleep state to avoid noise. If IRQ type is configured as level high and the GPIO line is also in a high state, it causes continuous interrupt assertions leading to an IRQ storm when wakeup irq enables at system suspend/runtime suspend. Switching to edge-triggered interrupt (IRQ_TYPE_EDGE_FALLING) resolves this by only triggering on state transitions (high-to-low) rather than maintaining sensitivity to the static level state, effectively preventing the continuous interrupt condition and eliminating the wakeup IRQ storm. Fixes: 9380e0a1d449 ("arm64: dts: qcom: qrb2210-rb1: add Bluetooth support") Signed-off-by: Praveen Talari Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20251110101043.2108414-2-praveen.talari@oss.qualcomm.com Signed-off-by: Bjorn Andersson Signed-off-by: Sasha Levin --- arch/arm64/boot/dts/qcom/qrb2210-rb1.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/qrb2210-rb1.dts b/arch/arm64/boot/dts/qcom/qrb2210-rb1.dts index 67ba508e92ba1..3eedfb2cf4799 100644 --- a/arch/arm64/boot/dts/qcom/qrb2210-rb1.dts +++ b/arch/arm64/boot/dts/qcom/qrb2210-rb1.dts @@ -649,7 +649,7 @@ &uart3 { /delete-property/ interrupts; interrupts-extended = <&intc GIC_SPI 330 IRQ_TYPE_LEVEL_HIGH>, - <&tlmm 11 IRQ_TYPE_LEVEL_HIGH>; + <&tlmm 11 IRQ_TYPE_EDGE_FALLING>; pinctrl-0 = <&uart3_default>; pinctrl-1 = <&uart3_sleep>; pinctrl-names = "default", "sleep"; From 7102ea1e816ac2a694d91b33233ddd63ae582b42 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Mon, 27 Oct 2025 15:35:17 +0200 Subject: [PATCH 0662/2333] drm/msm/dpu: drop dpu_hw_dsc_destroy() prototype [ Upstream commit d9792823d18ff9895eaf5769a29a54804f24bc25 ] The commit a106ed98af68 ("drm/msm/dpu: use devres-managed allocation for HW blocks") dropped all dpu_hw_foo_destroy() functions, but the prototype for dpu_hw_dsc_destroy() was omitted. Drop it now to clean up the header. Fixes: a106ed98af68 ("drm/msm/dpu: use devres-managed allocation for HW blocks") Signed-off-by: Dmitry Baryshkov Reviewed-by: Konrad Dybcio Reviewed-by: Jessica Zhang Patchwork: https://patchwork.freedesktop.org/patch/683697/ Link: https://lore.kernel.org/r/20251027-dpu-drop-dsc-destroy-v1-1-968128de4bf6@oss.qualcomm.com Signed-off-by: Sasha Levin --- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h index b7013c9822d23..cc7cc6f6f7cda 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h @@ -71,12 +71,6 @@ struct dpu_hw_dsc *dpu_hw_dsc_init_1_2(struct drm_device *dev, const struct dpu_dsc_cfg *cfg, void __iomem *addr); -/** - * dpu_hw_dsc_destroy - destroys dsc driver context - * @dsc: Pointer to dsc driver context returned by dpu_hw_dsc_init - */ -void dpu_hw_dsc_destroy(struct dpu_hw_dsc *dsc); - static inline struct dpu_hw_dsc *to_dpu_hw_dsc(struct dpu_hw_blk *hw) { return container_of(hw, struct dpu_hw_dsc, base); From 9c58e23af95102948dc69d77cd4ef423269d7b06 Mon Sep 17 00:00:00 2001 From: Rene Rebe Date: Fri, 14 Nov 2025 15:30:33 +0100 Subject: [PATCH 0663/2333] ps3disk: use memcpy_{from,to}_bvec index MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 79bd8c9814a273fa7ba43399e1c07adec3fc95db ] With 6e0a48552b8c (ps3disk: use memcpy_{from,to}_bvec) converting ps3disk to new bvec helpers, incrementing the offset was accidently lost, corrupting consecutive buffers. Restore index for non-corrupted data transfers. Fixes: 6e0a48552b8c (ps3disk: use memcpy_{from,to}_bvec) Signed-off-by: René Rebe Reviewed-by: Christoph Hellwig Signed-off-by: Jens Axboe Signed-off-by: Sasha Levin --- drivers/block/ps3disk.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/block/ps3disk.c b/drivers/block/ps3disk.c index dc9e4a14b8854..8892f218a8147 100644 --- a/drivers/block/ps3disk.c +++ b/drivers/block/ps3disk.c @@ -85,10 +85,14 @@ static void ps3disk_scatter_gather(struct ps3_storage_device *dev, struct bio_vec bvec; rq_for_each_segment(bvec, req, iter) { + dev_dbg(&dev->sbd.core, "%s:%u: %u sectors from %llu\n", + __func__, __LINE__, bio_sectors(iter.bio), + iter.bio->bi_iter.bi_sector); if (gather) memcpy_from_bvec(dev->bounce_buf + offset, &bvec); else memcpy_to_bvec(&bvec, dev->bounce_buf + offset); + offset += bvec.bv_len; } } From 020ecb16e57889a7ab507c0a115f42be577782b3 Mon Sep 17 00:00:00 2001 From: Aaron Kling Date: Tue, 23 Sep 2025 11:58:05 -0500 Subject: [PATCH 0664/2333] soc/tegra: fuse: speedo-tegra210: Update speedo IDs [ Upstream commit ce27c9c2129679551c4e5fe71c1c5d42fff399c2 ] Existing code only sets CPU and GPU speedo IDs 0 and 1. The CPU DVFS code supports 11 IDs and nouveau supports 5. This aligns with what the downstream vendor kernel supports. Align SKUs with the downstream list. The Tegra210 CVB tables were added in the first referenced fixes commit. Since then, all Tegra210 SoCs have tried to scale to 1.9 GHz, when the supported devkits are only supposed to scale to 1.5 or 1.7 GHZ. Overclocking should not be the default state. Fixes: 2b2dbc2f94e5 ("clk: tegra: dfll: add CVB tables for Tegra210") Fixes: 579db6e5d9b8 ("arm64: tegra: Enable DFLL support on Jetson Nano") Signed-off-by: Aaron Kling Signed-off-by: Thierry Reding Signed-off-by: Sasha Levin --- drivers/soc/tegra/fuse/speedo-tegra210.c | 62 ++++++++++++++++-------- 1 file changed, 43 insertions(+), 19 deletions(-) diff --git a/drivers/soc/tegra/fuse/speedo-tegra210.c b/drivers/soc/tegra/fuse/speedo-tegra210.c index 695d0b7f9a8ab..a8cc363297723 100644 --- a/drivers/soc/tegra/fuse/speedo-tegra210.c +++ b/drivers/soc/tegra/fuse/speedo-tegra210.c @@ -65,27 +65,51 @@ static void __init rev_sku_to_speedo_ids(struct tegra_sku_info *sku_info, sku_info->gpu_speedo_id = 0; *threshold = THRESHOLD_INDEX_0; - switch (sku) { - case 0x00: /* Engineering SKU */ - case 0x01: /* Engineering SKU */ - case 0x07: - case 0x17: - case 0x27: - if (speedo_rev >= 2) + if (sku_info->revision >= TEGRA_REVISION_A02) { + switch (sku) { + case 0x00: /* Engineering SKU */ + case 0x01: /* Engineering SKU */ + case 0x13: + sku_info->cpu_speedo_id = 5; + sku_info->gpu_speedo_id = 2; + break; + + case 0x07: + case 0x17: + case 0x1F: + sku_info->cpu_speedo_id = 7; + sku_info->gpu_speedo_id = 2; + break; + + case 0x27: + sku_info->cpu_speedo_id = 1; + sku_info->gpu_speedo_id = 2; + break; + + case 0x83: + sku_info->cpu_speedo_id = 3; + sku_info->gpu_speedo_id = 3; + break; + + case 0x87: + sku_info->cpu_speedo_id = 2; sku_info->gpu_speedo_id = 1; - break; - - case 0x13: - if (speedo_rev >= 2) - sku_info->gpu_speedo_id = 1; - - sku_info->cpu_speedo_id = 1; - break; - - default: + break; + + case 0x8F: + sku_info->cpu_speedo_id = 9; + sku_info->gpu_speedo_id = 2; + break; + + default: + pr_err("Tegra210: unknown revision 2 or newer SKU %#04x\n", sku); + /* Using the default for the error case */ + break; + } + } else if (sku == 0x00 || sku == 0x01 || sku == 0x07 || sku == 0x13 || sku == 0x17) { + sku_info->gpu_speedo_id = 1; + } else { pr_err("Tegra210: unknown SKU %#04x\n", sku); - /* Using the default for the error case */ - break; } } From 07cfb9c3f6d01a904329fd797d9a4b938b04b784 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Thu, 13 Nov 2025 18:26:18 +0200 Subject: [PATCH 0665/2333] PCI: Prevent resource tree corruption when BAR resize fails MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 91c4c89db41499eea1b29c56655f79c3bae66e93 ] pbus_reassign_bridge_resources() saves bridge windows into the saved list before attempting to adjust resource assignments to perform a BAR resize operation. If resource adjustments cannot be completed fully, rollback is attempted by restoring the resource from the saved list. The rollback, however, does not check whether the resources it restores were assigned by the partial resize attempt. If restore changes addresses of the resource, it can result in corrupting the resource tree. An example of a corrupted resource tree with overlapping addresses: 6200000000000-6203fbfffffff : pciex@620c3c0000000 6200000000000-6203fbff0ffff : PCI Bus 0030:01 6200020000000-62000207fffff : 0030:01:00.0 6200000000000-6203fbff0ffff : PCI Bus 0030:02 A resource that are assigned into the resource tree must remain unchanged. Thus, release such a resource before attempting to restore and claim it back. For simplicity, always do the release and claim back for the resource even in the cases where it is restored to the same address range. Note: this fix may "break" some cases where devices "worked" because the resource tree corruption allowed address space double counting to fit more resource than what can now be assigned without double counting. The upcoming changes to BAR resizing should address those scenarios (to the extent possible). Fixes: 8bb705e3e79d ("PCI: Add pci_resize_resource() for resizing BARs") Reported-by: Simon Richter Link: https://lore.kernel.org/linux-pci/67840a16-99b4-4d8c-9b5c-4721ab0970a2@hogyros.de/ Reported-by: Alex Bennée Link: https://lore.kernel.org/linux-pci/874irqop6b.fsf@draig.linaro.org/ Signed-off-by: Ilpo Järvinen Signed-off-by: Bjorn Helgaas Tested-by: Alex Bennée # AVA, AMD GPU Link: https://patch.msgid.link/20251113162628.5946-2-ilpo.jarvinen@linux.intel.com Signed-off-by: Sasha Levin --- drivers/pci/setup-bus.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index 3645f392a9fd3..5ba878f15db35 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -2504,6 +2504,11 @@ int pbus_reassign_bridge_resources(struct pci_bus *bus, struct resource *res) bridge = dev_res->dev; i = pci_resource_num(bridge, res); + if (res->parent) { + release_child_resources(res); + pci_release_resource(bridge, i); + } + restore_dev_resource(dev_res); pci_claim_resource(bridge, i); From 6394fc65d7bc3de439e6947d321b1d0917f8bda0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Fri, 14 Nov 2025 14:43:56 +0100 Subject: [PATCH 0666/2333] kbuild: don't enable CC_CAN_LINK if the dummy program generates warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit d81d9d389b9b73acd68f300c8889c7fa1acd4977 ] It is possible that the kernel toolchain generates warnings when used together with the system toolchain. This happens for example when the older kernel toolchain does not handle new versions of sframe debug information. While these warnings where ignored during the evaluation of CC_CAN_LINK, together with CONFIG_WERROR the actual userprog build will later fail. Example warning: .../x86_64-linux/13.2.0/../../../../x86_64-linux/bin/ld: error in /lib/../lib64/crt1.o(.sframe); no .sframe will be created collect2: error: ld returned 1 exit status Make sure that the very simple example program does not generate warnings already to avoid breaking the userprog compilations. Fixes: ec4a3992bc0b ("kbuild: respect CONFIG_WERROR for linker and assembler") Fixes: 3f0ff4cc6ffb ("kbuild: respect CONFIG_WERROR for userprogs") Signed-off-by: Thomas Weißschuh Reviewed-by: Nicolas Schier Reviewed-by: Nathan Chancellor Link: https://patch.msgid.link/20251114-kbuild-userprogs-bits-v3-1-4dee0d74d439@linutronix.de Signed-off-by: Nicolas Schier Signed-off-by: Sasha Levin --- scripts/cc-can-link.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/cc-can-link.sh b/scripts/cc-can-link.sh index 6efcead319898..e67fd8d7b6841 100755 --- a/scripts/cc-can-link.sh +++ b/scripts/cc-can-link.sh @@ -1,7 +1,7 @@ #!/bin/sh # SPDX-License-Identifier: GPL-2.0 -cat << "END" | $@ -x c - -o /dev/null >/dev/null 2>&1 +cat << "END" | $@ -Werror -Wl,--fatal-warnings -x c - -o /dev/null >/dev/null 2>&1 #include int main(void) { From 4a9b0581757a97ed70805bd01b3c254890020be6 Mon Sep 17 00:00:00 2001 From: Sahil Chandna Date: Fri, 14 Nov 2025 12:19:22 +0530 Subject: [PATCH 0667/2333] bpf: Prevent nesting overflow in bpf_try_get_buffers [ Upstream commit c1da3df7191f1b4df9256bcd30d78f78201e1d17 ] bpf_try_get_buffers() returns one of multiple per-CPU buffers based on a per-CPU nesting counter. This mechanism expects that buffers are not endlessly acquired before being returned. migrate_disable() ensures that a task remains on the same CPU, but it does not prevent the task from being preempted by another task on that CPU. Without disabled preemption, a task may be preempted while holding a buffer, allowing another task to run on same CPU and acquire an additional buffer. Several such preemptions can cause the per-CPU nest counter to exceed MAX_BPRINTF_NEST_LEVEL and trigger the warning in bpf_try_get_buffers(). Adding preempt_disable()/preempt_enable() around buffer acquisition and release prevents this task preemption and preserves the intended bounded nesting behavior. Reported-by: syzbot+b0cff308140f79a9c4cb@syzkaller.appspotmail.com Closes: https://lore.kernel.org/all/68f6a4c8.050a0220.1be48.0011.GAE@google.com/ Fixes: 4223bf833c849 ("bpf: Remove preempt_disable in bpf_try_get_buffers") Suggested-by: Yonghong Song Reviewed-by: Sebastian Andrzej Siewior Signed-off-by: Sahil Chandna Link: https://lore.kernel.org/r/20251114064922.11650-1-chandna.sahil@gmail.com Signed-off-by: Alexei Starovoitov Signed-off-by: Sasha Levin --- kernel/bpf/helpers.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c index e4007fea49091..81ef159ef89bd 100644 --- a/kernel/bpf/helpers.c +++ b/kernel/bpf/helpers.c @@ -777,9 +777,11 @@ int bpf_try_get_buffers(struct bpf_bprintf_buffers **bufs) { int nest_level; + preempt_disable(); nest_level = this_cpu_inc_return(bpf_bprintf_nest_level); if (WARN_ON_ONCE(nest_level > MAX_BPRINTF_NEST_LEVEL)) { this_cpu_dec(bpf_bprintf_nest_level); + preempt_enable(); return -EBUSY; } *bufs = this_cpu_ptr(&bpf_bprintf_bufs[nest_level - 1]); @@ -792,6 +794,7 @@ void bpf_put_buffers(void) if (WARN_ON_ONCE(this_cpu_read(bpf_bprintf_nest_level) == 0)) return; this_cpu_dec(bpf_bprintf_nest_level); + preempt_enable(); } void bpf_bprintf_cleanup(struct bpf_bprintf_data *data) From 7547576c6209f510550ddcd342b6c52c85e1a612 Mon Sep 17 00:00:00 2001 From: Menglong Dong Date: Mon, 10 Nov 2025 20:07:05 +0800 Subject: [PATCH 0668/2333] bpf: Handle return value of ftrace_set_filter_ip in register_fentry [ Upstream commit fea3f5e83c5cd80a76d97343023a2f2e6bd862bf ] The error that returned by ftrace_set_filter_ip() in register_fentry() is not handled properly. Just fix it. Fixes: 00963a2e75a8 ("bpf: Support bpf_trampoline on functions with IPMODIFY (e.g. livepatch)") Signed-off-by: Menglong Dong Acked-by: Song Liu Link: https://lore.kernel.org/r/20251110120705.1553694-1-dongml2@chinatelecom.cn Signed-off-by: Alexei Starovoitov Signed-off-by: Sasha Levin --- kernel/bpf/trampoline.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/kernel/bpf/trampoline.c b/kernel/bpf/trampoline.c index f2cb0b0970933..04104397c432e 100644 --- a/kernel/bpf/trampoline.c +++ b/kernel/bpf/trampoline.c @@ -220,7 +220,9 @@ static int register_fentry(struct bpf_trampoline *tr, void *new_addr) } if (tr->func.ftrace_managed) { - ftrace_set_filter_ip(tr->fops, (unsigned long)ip, 0, 1); + ret = ftrace_set_filter_ip(tr->fops, (unsigned long)ip, 0, 1); + if (ret) + return ret; ret = register_ftrace_direct(tr->fops, (long)new_addr); } else { ret = bpf_arch_text_poke(ip, BPF_MOD_CALL, NULL, new_addr); From 59bad3c98cad39585f19de742c3390c44679b9c2 Mon Sep 17 00:00:00 2001 From: Alexei Starovoitov Date: Thu, 13 Nov 2025 09:11:53 -0800 Subject: [PATCH 0669/2333] selftests/bpf: Fix failure paths in send_signal test [ Upstream commit c13339039891dbdfa6c1972f0483bd07f610b776 ] When test_send_signal_kern__open_and_load() fails parent closes the pipe which cases ASSERT_EQ(read(pipe_p2c...)) to fail, but child continues and enters infinite loop, while parent is stuck in wait(NULL). Other error paths have similar issue, so kill the child before waiting on it. The bug was discovered while compiling all of selftests with -O1 instead of -O2 which caused progs/test_send_signal_kern.c to fail to load. Fixes: ab8b7f0cb358 ("tools/bpf: Add self tests for bpf_send_signal_thread()") Signed-off-by: Alexei Starovoitov Signed-off-by: Andrii Nakryiko Acked-by: Eduard Zingerman Link: https://lore.kernel.org/bpf/20251113171153.2583-1-alexei.starovoitov@gmail.com Signed-off-by: Sasha Levin --- tools/testing/selftests/bpf/prog_tests/send_signal.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tools/testing/selftests/bpf/prog_tests/send_signal.c b/tools/testing/selftests/bpf/prog_tests/send_signal.c index 1702aa592c2c2..7ac4d5a488aa5 100644 --- a/tools/testing/selftests/bpf/prog_tests/send_signal.c +++ b/tools/testing/selftests/bpf/prog_tests/send_signal.c @@ -206,6 +206,11 @@ static void test_send_signal_common(struct perf_event_attr *attr, skel_open_load_failure: close(pipe_c2p[0]); close(pipe_p2c[1]); + /* + * Child is either about to exit cleanly or stuck in case of errors. + * Nudge it to exit. + */ + kill(pid, SIGKILL); wait(NULL); } From 942268e2726ac7f16e3ec49dbfbbbe7cf5af9da5 Mon Sep 17 00:00:00 2001 From: Martin KaFai Lau Date: Wed, 12 Nov 2025 15:23:30 -0800 Subject: [PATCH 0670/2333] bpf: Check skb->transport_header is set in bpf_skb_check_mtu [ Upstream commit d946f3c98328171fa50ddb908593cf833587f725 ] The bpf_skb_check_mtu helper needs to use skb->transport_header when the BPF_MTU_CHK_SEGS flag is used: bpf_skb_check_mtu(skb, ifindex, &mtu_len, 0, BPF_MTU_CHK_SEGS) The transport_header is not always set. There is a WARN_ON_ONCE report when CONFIG_DEBUG_NET is enabled + skb->gso_size is set + bpf_prog_test_run is used: WARNING: CPU: 1 PID: 2216 at ./include/linux/skbuff.h:3071 skb_gso_validate_network_len bpf_skb_check_mtu bpf_prog_3920e25740a41171_tc_chk_segs_flag # A test in the next patch bpf_test_run bpf_prog_test_run_skb For a normal ingress skb (not test_run), skb_reset_transport_header is performed but there is plan to avoid setting it as described in commit 2170a1f09148 ("net: no longer reset transport_header in __netif_receive_skb_core()"). This patch fixes the bpf helper by checking skb_transport_header_was_set(). The check is done just before skb->transport_header is used, to avoid breaking the existing bpf prog. The WARN_ON_ONCE is limited to bpf_prog_test_run, so targeting bpf-next. Fixes: 34b2021cc616 ("bpf: Add BPF-helper for MTU checking") Cc: Jesper Dangaard Brouer Reported-by: Kaiyan Mei Reported-by: Yinhao Hu Signed-off-by: Martin KaFai Lau Link: https://lore.kernel.org/r/20251112232331.1566074-1-martin.lau@linux.dev Signed-off-by: Alexei Starovoitov Signed-off-by: Sasha Levin --- net/core/filter.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/net/core/filter.c b/net/core/filter.c index 1efec0d70d783..df6ce85e48dcd 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -6429,9 +6429,12 @@ BPF_CALL_5(bpf_skb_check_mtu, struct sk_buff *, skb, */ if (skb_is_gso(skb)) { ret = BPF_MTU_CHK_RET_SUCCESS; - if (flags & BPF_MTU_CHK_SEGS && - !skb_gso_validate_network_len(skb, mtu)) - ret = BPF_MTU_CHK_RET_SEGS_TOOBIG; + if (flags & BPF_MTU_CHK_SEGS) { + if (!skb_transport_header_was_set(skb)) + return -EINVAL; + if (!skb_gso_validate_network_len(skb, mtu)) + ret = BPF_MTU_CHK_RET_SEGS_TOOBIG; + } } out: *mtu_len = mtu; From 38080597380815897a8db07d682f739cf9738ad1 Mon Sep 17 00:00:00 2001 From: Nuno Das Neves Date: Fri, 17 Oct 2025 11:58:17 -0700 Subject: [PATCH 0671/2333] mshv: Fix deposit memory in MSHV_ROOT_HVCALL [ Upstream commit 4cc1aa469cd6b714adc958547a4866247bfd60a9 ] When the MSHV_ROOT_HVCALL ioctl is executing a hypercall, and gets HV_STATUS_INSUFFICIENT_MEMORY, it deposits memory and then returns -EAGAIN to userspace. The expectation is that the VMM will retry. However, some VMM code in the wild doesn't do this and simply fails. Rather than force the VMM to retry, change the ioctl to deposit memory on demand and immediately retry the hypercall as is done with all the other hypercall helper functions. In addition to making the ioctl easier to use, removing the need for multiple syscalls improves performance. There is a complication: unlike the other hypercall helper functions, in MSHV_ROOT_HVCALL the input is opaque to the kernel. This is problematic for rep hypercalls, because the next part of the input list can't be copied on each loop after depositing pages (this was the original reason for returning -EAGAIN in this case). Introduce hv_do_rep_hypercall_ex(), which adds a 'rep_start' parameter. This solves the issue, allowing the deposit loop in MSHV_ROOT_HVCALL to restart a rep hypercall after depositing pages partway through. Fixes: 621191d709b1 ("Drivers: hv: Introduce mshv_root module to expose /dev/mshv to VMMs") Signed-off-by: Nuno Das Neves Reviewed-by: Michael Kelley Signed-off-by: Wei Liu Signed-off-by: Sasha Levin --- drivers/hv/mshv_root_main.c | 58 ++++++++++++++++++---------------- include/asm-generic/mshyperv.h | 17 ++++++++-- 2 files changed, 44 insertions(+), 31 deletions(-) diff --git a/drivers/hv/mshv_root_main.c b/drivers/hv/mshv_root_main.c index e3b2bd417c464..5156b8b0a39f4 100644 --- a/drivers/hv/mshv_root_main.c +++ b/drivers/hv/mshv_root_main.c @@ -159,6 +159,7 @@ static int mshv_ioctl_passthru_hvcall(struct mshv_partition *partition, unsigned int pages_order; void *input_pg = NULL; void *output_pg = NULL; + u16 reps_completed; if (copy_from_user(&args, user_args, sizeof(args))) return -EFAULT; @@ -210,41 +211,42 @@ static int mshv_ioctl_passthru_hvcall(struct mshv_partition *partition, */ *(u64 *)input_pg = partition->pt_id; - if (args.reps) - status = hv_do_rep_hypercall(args.code, args.reps, 0, - input_pg, output_pg); - else - status = hv_do_hypercall(args.code, input_pg, output_pg); - - if (hv_result(status) == HV_STATUS_CALL_PENDING) { - if (is_async) { - mshv_async_hvcall_handler(partition, &status); - } else { /* Paranoia check. This shouldn't happen! */ - ret = -EBADFD; - goto free_pages_out; + reps_completed = 0; + do { + if (args.reps) { + status = hv_do_rep_hypercall_ex(args.code, args.reps, + 0, reps_completed, + input_pg, output_pg); + reps_completed = hv_repcomp(status); + } else { + status = hv_do_hypercall(args.code, input_pg, output_pg); } - } - if (hv_result(status) == HV_STATUS_INSUFFICIENT_MEMORY) { - ret = hv_call_deposit_pages(NUMA_NO_NODE, partition->pt_id, 1); - if (!ret) - ret = -EAGAIN; - } else if (!hv_result_success(status)) { - ret = hv_result_to_errno(status); - } + if (hv_result(status) == HV_STATUS_CALL_PENDING) { + if (is_async) { + mshv_async_hvcall_handler(partition, &status); + } else { /* Paranoia check. This shouldn't happen! */ + ret = -EBADFD; + goto free_pages_out; + } + } + + if (hv_result_success(status)) + break; + + if (hv_result(status) != HV_STATUS_INSUFFICIENT_MEMORY) + ret = hv_result_to_errno(status); + else + ret = hv_call_deposit_pages(NUMA_NO_NODE, + partition->pt_id, 1); + } while (!ret); - /* - * Always return the status and output data regardless of result. - * The VMM may need it to determine how to proceed. E.g. the status may - * contain the number of reps completed if a rep hypercall partially - * succeeded. - */ args.status = hv_result(status); - args.reps = args.reps ? hv_repcomp(status) : 0; + args.reps = reps_completed; if (copy_to_user(user_args, &args, sizeof(args))) ret = -EFAULT; - if (output_pg && + if (!ret && output_pg && copy_to_user((void __user *)args.out_ptr, output_pg, args.out_sz)) ret = -EFAULT; diff --git a/include/asm-generic/mshyperv.h b/include/asm-generic/mshyperv.h index 64ba6bc807d98..b89c7e3a20474 100644 --- a/include/asm-generic/mshyperv.h +++ b/include/asm-generic/mshyperv.h @@ -124,10 +124,12 @@ static inline unsigned int hv_repcomp(u64 status) /* * Rep hypercalls. Callers of this functions are supposed to ensure that - * rep_count and varhead_size comply with Hyper-V hypercall definition. + * rep_count, varhead_size, and rep_start comply with Hyper-V hypercall + * definition. */ -static inline u64 hv_do_rep_hypercall(u16 code, u16 rep_count, u16 varhead_size, - void *input, void *output) +static inline u64 hv_do_rep_hypercall_ex(u16 code, u16 rep_count, + u16 varhead_size, u16 rep_start, + void *input, void *output) { u64 control = code; u64 status; @@ -135,6 +137,7 @@ static inline u64 hv_do_rep_hypercall(u16 code, u16 rep_count, u16 varhead_size, control |= (u64)varhead_size << HV_HYPERCALL_VARHEAD_OFFSET; control |= (u64)rep_count << HV_HYPERCALL_REP_COMP_OFFSET; + control |= (u64)rep_start << HV_HYPERCALL_REP_START_OFFSET; do { status = hv_do_hypercall(control, input, output); @@ -152,6 +155,14 @@ static inline u64 hv_do_rep_hypercall(u16 code, u16 rep_count, u16 varhead_size, return status; } +/* For the typical case where rep_start is 0 */ +static inline u64 hv_do_rep_hypercall(u16 code, u16 rep_count, u16 varhead_size, + void *input, void *output) +{ + return hv_do_rep_hypercall_ex(code, rep_count, varhead_size, 0, + input, output); +} + /* Generate the guest OS identifier as described in the Hyper-V TLFS */ static inline u64 hv_generate_guest_id(u64 kernel_version) { From ab3e7a78d83a61d335458cfe2e4d17eba69ae73d Mon Sep 17 00:00:00 2001 From: Nuno Das Neves Date: Thu, 6 Nov 2025 14:13:30 -0800 Subject: [PATCH 0672/2333] mshv: Fix create memory region overlap check [ Upstream commit ba9eb9b86d232854e983203dc2fb1ba18e316681 ] The current check is incorrect; it only checks if the beginning or end of a region is within an existing region. This doesn't account for userspace specifying a region that begins before and ends after an existing region. Change the logic to a range intersection check against gfns and uaddrs for each region. Remove mshv_partition_region_by_uaddr() as it is no longer used. Fixes: 621191d709b1 ("Drivers: hv: Introduce mshv_root module to expose /dev/mshv to VMMs") Reported-by: Michael Kelley Closes: https://lore.kernel.org/linux-hyperv/SN6PR02MB41575BE0406D3AB22E1D7DB5D4C2A@SN6PR02MB4157.namprd02.prod.outlook.com/ Signed-off-by: Nuno Das Neves Reviewed-by: Michael Kelley Signed-off-by: Wei Liu Signed-off-by: Sasha Levin --- drivers/hv/mshv_root_main.c | 31 +++++++++++-------------------- 1 file changed, 11 insertions(+), 20 deletions(-) diff --git a/drivers/hv/mshv_root_main.c b/drivers/hv/mshv_root_main.c index 5156b8b0a39f4..4e04bef544379 100644 --- a/drivers/hv/mshv_root_main.c +++ b/drivers/hv/mshv_root_main.c @@ -1174,21 +1174,6 @@ mshv_partition_region_by_gfn(struct mshv_partition *partition, u64 gfn) return NULL; } -static struct mshv_mem_region * -mshv_partition_region_by_uaddr(struct mshv_partition *partition, u64 uaddr) -{ - struct mshv_mem_region *region; - - hlist_for_each_entry(region, &partition->pt_mem_regions, hnode) { - if (uaddr >= region->start_uaddr && - uaddr < region->start_uaddr + - (region->nr_pages << HV_HYP_PAGE_SHIFT)) - return region; - } - - return NULL; -} - /* * NB: caller checks and makes sure mem->size is page aligned * Returns: 0 with regionpp updated on success, or -errno @@ -1198,15 +1183,21 @@ static int mshv_partition_create_region(struct mshv_partition *partition, struct mshv_mem_region **regionpp, bool is_mmio) { - struct mshv_mem_region *region; + struct mshv_mem_region *region, *rg; u64 nr_pages = HVPFN_DOWN(mem->size); /* Reject overlapping regions */ - if (mshv_partition_region_by_gfn(partition, mem->guest_pfn) || - mshv_partition_region_by_gfn(partition, mem->guest_pfn + nr_pages - 1) || - mshv_partition_region_by_uaddr(partition, mem->userspace_addr) || - mshv_partition_region_by_uaddr(partition, mem->userspace_addr + mem->size - 1)) + hlist_for_each_entry(rg, &partition->pt_mem_regions, hnode) { + u64 rg_size = rg->nr_pages << HV_HYP_PAGE_SHIFT; + + if ((mem->guest_pfn + nr_pages <= rg->start_gfn || + rg->start_gfn + rg->nr_pages <= mem->guest_pfn) && + (mem->userspace_addr + mem->size <= rg->start_uaddr || + rg->start_uaddr + rg_size <= mem->userspace_addr)) + continue; + return -EEXIST; + } region = vzalloc(sizeof(*region) + sizeof(struct page *) * nr_pages); if (!region) From e2b25922e5664ce2406b7ec0aa3a89c8406d1b4b Mon Sep 17 00:00:00 2001 From: Haotian Zhang Date: Thu, 13 Nov 2025 10:30:32 +0800 Subject: [PATCH 0673/2333] watchdog: wdat_wdt: Fix ACPI table leak in probe function [ Upstream commit 25c0b472eab8379683d4eef681185c104bed8ffd ] wdat_wdt_probe() calls acpi_get_table() to obtain the WDAT ACPI table but never calls acpi_put_table() on any paths. This causes a permanent ACPI table memory leak. Add a single cleanup path which calls acpi_put_table() to ensure the ACPI table is always released. Fixes: 058dfc767008 ("ACPI / watchdog: Add support for WDAT hardware watchdog") Suggested-by: Guenter Roeck Signed-off-by: Haotian Zhang Reviewed-by: Guenter Roeck Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck Signed-off-by: Sasha Levin --- drivers/watchdog/wdat_wdt.c | 64 +++++++++++++++++++++++++------------ 1 file changed, 43 insertions(+), 21 deletions(-) diff --git a/drivers/watchdog/wdat_wdt.c b/drivers/watchdog/wdat_wdt.c index 650fdc7996e1c..dd3c2d69c9df1 100644 --- a/drivers/watchdog/wdat_wdt.c +++ b/drivers/watchdog/wdat_wdt.c @@ -326,19 +326,27 @@ static int wdat_wdt_probe(struct platform_device *pdev) return -ENODEV; wdat = devm_kzalloc(dev, sizeof(*wdat), GFP_KERNEL); - if (!wdat) - return -ENOMEM; + if (!wdat) { + ret = -ENOMEM; + goto out_put_table; + } regs = devm_kcalloc(dev, pdev->num_resources, sizeof(*regs), GFP_KERNEL); - if (!regs) - return -ENOMEM; + if (!regs) { + ret = -ENOMEM; + goto out_put_table; + } /* WDAT specification wants to have >= 1ms period */ - if (tbl->timer_period < 1) - return -EINVAL; - if (tbl->min_count > tbl->max_count) - return -EINVAL; + if (tbl->timer_period < 1) { + ret = -EINVAL; + goto out_put_table; + } + if (tbl->min_count > tbl->max_count) { + ret = -EINVAL; + goto out_put_table; + } wdat->period = tbl->timer_period; wdat->wdd.min_timeout = DIV_ROUND_UP(wdat->period * tbl->min_count, 1000); @@ -355,15 +363,20 @@ static int wdat_wdt_probe(struct platform_device *pdev) res = &pdev->resource[i]; if (resource_type(res) == IORESOURCE_MEM) { reg = devm_ioremap_resource(dev, res); - if (IS_ERR(reg)) - return PTR_ERR(reg); + if (IS_ERR(reg)) { + ret = PTR_ERR(reg); + goto out_put_table; + } } else if (resource_type(res) == IORESOURCE_IO) { reg = devm_ioport_map(dev, res->start, 1); - if (!reg) - return -ENOMEM; + if (!reg) { + ret = -ENOMEM; + goto out_put_table; + } } else { dev_err(dev, "Unsupported resource\n"); - return -EINVAL; + ret = -EINVAL; + goto out_put_table; } regs[i] = reg; @@ -385,8 +398,10 @@ static int wdat_wdt_probe(struct platform_device *pdev) } instr = devm_kzalloc(dev, sizeof(*instr), GFP_KERNEL); - if (!instr) - return -ENOMEM; + if (!instr) { + ret = -ENOMEM; + goto out_put_table; + } INIT_LIST_HEAD(&instr->node); instr->entry = entries[i]; @@ -417,7 +432,8 @@ static int wdat_wdt_probe(struct platform_device *pdev) if (!instr->reg) { dev_err(dev, "I/O resource not found\n"); - return -EINVAL; + ret = -EINVAL; + goto out_put_table; } instructions = wdat->instructions[action]; @@ -425,8 +441,10 @@ static int wdat_wdt_probe(struct platform_device *pdev) instructions = devm_kzalloc(dev, sizeof(*instructions), GFP_KERNEL); - if (!instructions) - return -ENOMEM; + if (!instructions) { + ret = -ENOMEM; + goto out_put_table; + } INIT_LIST_HEAD(instructions); wdat->instructions[action] = instructions; @@ -443,7 +461,7 @@ static int wdat_wdt_probe(struct platform_device *pdev) ret = wdat_wdt_enable_reboot(wdat); if (ret) - return ret; + goto out_put_table; platform_set_drvdata(pdev, wdat); @@ -460,12 +478,16 @@ static int wdat_wdt_probe(struct platform_device *pdev) ret = wdat_wdt_set_timeout(&wdat->wdd, timeout); if (ret) - return ret; + goto out_put_table; watchdog_set_nowayout(&wdat->wdd, nowayout); watchdog_stop_on_reboot(&wdat->wdd); watchdog_stop_on_unregister(&wdat->wdd); - return devm_watchdog_register_device(dev, &wdat->wdd); + ret = devm_watchdog_register_device(dev, &wdat->wdd); + +out_put_table: + acpi_put_table((struct acpi_table_header *)tbl); + return ret; } static int wdat_wdt_suspend_noirq(struct device *dev) From 4d9bebb2e9b6ddcca359e8701e09ae8f4cfdf9ae Mon Sep 17 00:00:00 2001 From: Haotian Zhang Date: Wed, 5 Nov 2025 16:42:20 +0800 Subject: [PATCH 0674/2333] watchdog: starfive: Fix resource leak in probe error path [ Upstream commit 5bcc5786a0cfa9249ccbe539833040a6285d0de3 ] If pm_runtime_put_sync() fails after watchdog_register_device() succeeds, the probe function jumps to err_exit without unregistering the watchdog device. This leaves the watchdog registered in the subsystem while the driver fails to load, resulting in a resource leak. Add a new error label err_unregister_wdt to properly unregister the watchdog device. Fixes: 8bc22a2f1bf0 ("watchdog: starfive: Check pm_runtime_enabled() before decrementing usage counter") Signed-off-by: Haotian Zhang Reviewed-by: Wim Van Sebroeck Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck Signed-off-by: Sasha Levin --- drivers/watchdog/starfive-wdt.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/watchdog/starfive-wdt.c b/drivers/watchdog/starfive-wdt.c index 355918d62f63d..ed71d3960a0f2 100644 --- a/drivers/watchdog/starfive-wdt.c +++ b/drivers/watchdog/starfive-wdt.c @@ -500,12 +500,14 @@ static int starfive_wdt_probe(struct platform_device *pdev) if (pm_runtime_enabled(&pdev->dev)) { ret = pm_runtime_put_sync(&pdev->dev); if (ret) - goto err_exit; + goto err_unregister_wdt; } } return 0; +err_unregister_wdt: + watchdog_unregister_device(&wdt->wdd); err_exit: starfive_wdt_disable_clock(wdt); pm_runtime_disable(&pdev->dev); From 97d817c1145036f451cae939e71297f9fa9348da Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 12 Nov 2025 15:55:08 +0100 Subject: [PATCH 0675/2333] iio: core: add missing mutex_destroy in iio_dev_release() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit f5d203467a31798191365efeb16cd619d2c8f23a ] Add missing mutex_destroy() call in iio_dev_release() to properly clean up the mutex initialized in iio_device_alloc(). Ensure proper resource cleanup and follows kernel practices. Found by code review. While at it, create a lockdep key before mutex initialisation. This will help with converting it to the better API in the future. Fixes: 847ec80bbaa7 ("Staging: IIO: core support for device registration and management") Fixes: ac917a81117c ("staging:iio:core set the iio_dev.info pointer to null on unregister under lock.") Signed-off-by: Andy Shevchenko Reviewed-by: Nuno Sá Signed-off-by: Jonathan Cameron Signed-off-by: Sasha Levin --- drivers/iio/industrialio-core.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index 88c3d585a1bd0..93d6e5b101cf1 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -1654,6 +1654,9 @@ static void iio_dev_release(struct device *device) iio_device_detach_buffers(indio_dev); + mutex_destroy(&iio_dev_opaque->info_exist_lock); + mutex_destroy(&iio_dev_opaque->mlock); + lockdep_unregister_key(&iio_dev_opaque->mlock_key); ida_free(&iio_ida, iio_dev_opaque->id); @@ -1698,8 +1701,7 @@ struct iio_dev *iio_device_alloc(struct device *parent, int sizeof_priv) indio_dev->dev.type = &iio_device_type; indio_dev->dev.bus = &iio_bus_type; device_initialize(&indio_dev->dev); - mutex_init(&iio_dev_opaque->mlock); - mutex_init(&iio_dev_opaque->info_exist_lock); + INIT_LIST_HEAD(&iio_dev_opaque->channel_attr_list); iio_dev_opaque->id = ida_alloc(&iio_ida, GFP_KERNEL); @@ -1722,6 +1724,9 @@ struct iio_dev *iio_device_alloc(struct device *parent, int sizeof_priv) lockdep_register_key(&iio_dev_opaque->mlock_key); lockdep_set_class(&iio_dev_opaque->mlock, &iio_dev_opaque->mlock_key); + mutex_init(&iio_dev_opaque->mlock); + mutex_init(&iio_dev_opaque->info_exist_lock); + return indio_dev; } EXPORT_SYMBOL(iio_device_alloc); From e1cc8886b628c4ce2dedef4b41383bb2e3fef16f Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 12 Nov 2025 15:55:09 +0100 Subject: [PATCH 0676/2333] iio: core: Clean up device correctly on iio_device_alloc() failure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit b0e6871415b25f5e84a79621834e3d0c9d4627a6 ] Once we called device_initialize() we have to call put_device() on it. Refactor the code to make it in the right order. Fixes: fe6f45f6ba22 ("iio: core: check return value when calling dev_set_name()") Fixes: 847ec80bbaa7 ("Staging: IIO: core support for device registration and management") Signed-off-by: Andy Shevchenko Reviewed-by: Nuno Sá Signed-off-by: Jonathan Cameron Signed-off-by: Sasha Levin --- drivers/iio/industrialio-core.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index 93d6e5b101cf1..5d2f35cf18bc3 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -1697,11 +1697,6 @@ struct iio_dev *iio_device_alloc(struct device *parent, int sizeof_priv) ACCESS_PRIVATE(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; - indio_dev->dev.bus = &iio_bus_type; - device_initialize(&indio_dev->dev); - INIT_LIST_HEAD(&iio_dev_opaque->channel_attr_list); iio_dev_opaque->id = ida_alloc(&iio_ida, GFP_KERNEL); @@ -1727,6 +1722,11 @@ struct iio_dev *iio_device_alloc(struct device *parent, int sizeof_priv) mutex_init(&iio_dev_opaque->mlock); mutex_init(&iio_dev_opaque->info_exist_lock); + indio_dev->dev.parent = parent; + indio_dev->dev.type = &iio_device_type; + indio_dev->dev.bus = &iio_bus_type; + device_initialize(&indio_dev->dev); + return indio_dev; } EXPORT_SYMBOL(iio_device_alloc); From 30db8309b703a80b0e6afca1d0797635c96c5a87 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 26 Oct 2025 02:38:43 -0400 Subject: [PATCH 0677/2333] fuse_ctl_add_conn(): fix nlink breakage in case of early failure [ Upstream commit c460192aae197df1b4db1dca493c35ad529f1b64 ] fuse_ctl_remove_conn() used to decrement the link count of root manually; that got subsumed by simple_recursive_removal(), but in case when subdirectory creation has failed the latter won't get called. Just move the modification of parent's link count into fuse_ctl_add_dentry() to keep the things simple. Allows to get rid of the nlink argument as well... Fixes: fcaac5b42768 "fuse_ctl: use simple_recursive_removal()" Acked-by: Miklos Szeredi Signed-off-by: Al Viro Signed-off-by: Sasha Levin --- fs/fuse/control.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/fs/fuse/control.c b/fs/fuse/control.c index bb407705603c2..5247df896c5d0 100644 --- a/fs/fuse/control.c +++ b/fs/fuse/control.c @@ -205,8 +205,7 @@ static const struct file_operations fuse_conn_congestion_threshold_ops = { static struct dentry *fuse_ctl_add_dentry(struct dentry *parent, struct fuse_conn *fc, - const char *name, - int mode, int nlink, + const char *name, int mode, const struct inode_operations *iop, const struct file_operations *fop) { @@ -232,7 +231,10 @@ static struct dentry *fuse_ctl_add_dentry(struct dentry *parent, if (iop) inode->i_op = iop; inode->i_fop = fop; - set_nlink(inode, nlink); + if (S_ISDIR(mode)) { + inc_nlink(d_inode(parent)); + inc_nlink(inode); + } inode->i_private = fc; d_add(dentry, inode); @@ -252,22 +254,21 @@ int fuse_ctl_add_conn(struct fuse_conn *fc) return 0; parent = fuse_control_sb->s_root; - inc_nlink(d_inode(parent)); sprintf(name, "%u", fc->dev); - parent = fuse_ctl_add_dentry(parent, fc, name, S_IFDIR | 0500, 2, + parent = fuse_ctl_add_dentry(parent, fc, name, S_IFDIR | 0500, &simple_dir_inode_operations, &simple_dir_operations); if (!parent) goto err; - if (!fuse_ctl_add_dentry(parent, fc, "waiting", S_IFREG | 0400, 1, + if (!fuse_ctl_add_dentry(parent, fc, "waiting", S_IFREG | 0400, NULL, &fuse_ctl_waiting_ops) || - !fuse_ctl_add_dentry(parent, fc, "abort", S_IFREG | 0200, 1, + !fuse_ctl_add_dentry(parent, fc, "abort", S_IFREG | 0200, NULL, &fuse_ctl_abort_ops) || !fuse_ctl_add_dentry(parent, fc, "max_background", S_IFREG | 0600, - 1, NULL, &fuse_conn_max_background_ops) || + NULL, &fuse_conn_max_background_ops) || !fuse_ctl_add_dentry(parent, fc, "congestion_threshold", - S_IFREG | 0600, 1, NULL, + S_IFREG | 0600, NULL, &fuse_conn_congestion_threshold_ops)) goto err; From bc2b1bbc0329900b97034b6ad3728111fb4f4f01 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 25 Oct 2025 18:13:48 -0400 Subject: [PATCH 0678/2333] tracefs: fix a leak in eventfs_create_events_dir() [ Upstream commit 798a401660a151633cb171738a72a8f1efb9b0b4 ] If we have LOCKDOWN_TRACEFS, the function bails out - *after* having locked the parent directory and without bothering to undo that. Just check it before tracefs_start_creating()... Fixes: e24709454c45 "tracefs/eventfs: Add missing lockdown checks" Acked-by: Steven Rostedt (Google) Signed-off-by: Al Viro Signed-off-by: Sasha Levin --- fs/tracefs/event_inode.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/tracefs/event_inode.c b/fs/tracefs/event_inode.c index 8705c77a9e75a..93c231601c8e2 100644 --- a/fs/tracefs/event_inode.c +++ b/fs/tracefs/event_inode.c @@ -757,7 +757,7 @@ struct eventfs_inode *eventfs_create_events_dir(const char *name, struct dentry const struct eventfs_entry *entries, int size, void *data) { - struct dentry *dentry = tracefs_start_creating(name, parent); + struct dentry *dentry; struct eventfs_root_inode *rei; struct eventfs_inode *ei; struct tracefs_inode *ti; @@ -768,6 +768,7 @@ struct eventfs_inode *eventfs_create_events_dir(const char *name, struct dentry if (security_locked_down(LOCKDOWN_TRACEFS)) return NULL; + dentry = tracefs_start_creating(name, parent); if (IS_ERR(dentry)) return ERR_CAST(dentry); From f677cd77319bcb0b03db4c9a2417db5054c44221 Mon Sep 17 00:00:00 2001 From: Sergey Bashirov Date: Fri, 3 Oct 2025 12:11:03 +0300 Subject: [PATCH 0679/2333] NFSD/blocklayout: Fix minlength check in proc_layoutget [ Upstream commit 3524b021b0ec620a76c89aee78e9d4b4130fb711 ] The extent returned by the file system may have a smaller offset than the segment offset requested by the client. In this case, the minimum segment length must be checked against the requested range. Otherwise, the client may not be able to continue the read/write operation. Fixes: 8650b8a05850 ("nfsd: pNFS block layout driver") Signed-off-by: Sergey Bashirov Reviewed-by: Christoph Hellwig Signed-off-by: Chuck Lever Signed-off-by: Sasha Levin --- fs/nfsd/blocklayout.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fs/nfsd/blocklayout.c b/fs/nfsd/blocklayout.c index fde5539cf6a69..425648565ab2d 100644 --- a/fs/nfsd/blocklayout.c +++ b/fs/nfsd/blocklayout.c @@ -23,6 +23,7 @@ nfsd4_block_proc_layoutget(struct svc_rqst *rqstp, struct inode *inode, { struct nfsd4_layout_seg *seg = &args->lg_seg; struct super_block *sb = inode->i_sb; + u64 length; u32 block_size = i_blocksize(inode); struct pnfs_block_extent *bex; struct iomap iomap; @@ -56,7 +57,8 @@ nfsd4_block_proc_layoutget(struct svc_rqst *rqstp, struct inode *inode, goto out_error; } - if (iomap.length < args->lg_minlength) { + length = iomap.offset + iomap.length - seg->offset; + if (length < args->lg_minlength) { dprintk("pnfsd: extent smaller than minlength\n"); goto out_layoutunavailable; } From 8f1db86ea95c1a4521cf744d9e86a46cc8e9c553 Mon Sep 17 00:00:00 2001 From: Markus Niebel Date: Thu, 30 Oct 2025 13:49:08 +0100 Subject: [PATCH 0680/2333] arm64: dts: imx95-tqma9596sa: fix TPM5 pinctrl node name [ Upstream commit 046cb64923e8c05a8fb656baffcd8c3fc67fb688 ] tpm4grp will be overwritten. Fix node name Fixes: 91d1ff322c47 ("arm64: dt: imx95: Add TQMa95xxSA") Signed-off-by: Markus Niebel Signed-off-by: Alexander Stein Signed-off-by: Shawn Guo Signed-off-by: Sasha Levin --- arch/arm64/boot/dts/freescale/imx95-tqma9596sa.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/freescale/imx95-tqma9596sa.dtsi b/arch/arm64/boot/dts/freescale/imx95-tqma9596sa.dtsi index 180124cc5bce1..c3bb61ea67961 100644 --- a/arch/arm64/boot/dts/freescale/imx95-tqma9596sa.dtsi +++ b/arch/arm64/boot/dts/freescale/imx95-tqma9596sa.dtsi @@ -617,7 +617,7 @@ fsl,pins = ; }; - pinctrl_tpm5: tpm4grp { + pinctrl_tpm5: tpm5grp { fsl,pins = ; }; From e5e0f94996f0c522de94b652ffacf65a6c681e8a Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Thu, 30 Oct 2025 13:49:09 +0100 Subject: [PATCH 0681/2333] arm64: dts: imx95-tqma9596sa: reduce maximum FlexSPI frequency to 66MHz [ Upstream commit 461be3802562b2d41250b40868310579a32f32c1 ] 66 MHz is the maximum FlexPI clock frequency in normal/overdrive mode when RXCLKSRC = 0 (Default) Fixes: 91d1ff322c47 ("arm64: dt: imx95: Add TQMa95xxSA") Signed-off-by: Alexander Stein Signed-off-by: Shawn Guo Signed-off-by: Sasha Levin --- arch/arm64/boot/dts/freescale/imx95-tqma9596sa.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/freescale/imx95-tqma9596sa.dtsi b/arch/arm64/boot/dts/freescale/imx95-tqma9596sa.dtsi index c3bb61ea67961..16c40d11d3b5d 100644 --- a/arch/arm64/boot/dts/freescale/imx95-tqma9596sa.dtsi +++ b/arch/arm64/boot/dts/freescale/imx95-tqma9596sa.dtsi @@ -115,7 +115,7 @@ flash0: flash@0 { compatible = "jedec,spi-nor"; reg = <0>; - spi-max-frequency = <80000000>; + spi-max-frequency = <66000000>; spi-tx-bus-width = <4>; spi-rx-bus-width = <4>; vcc-supply = <®_1v8>; From d36f07b8e59054fe6d35b7c6eaa623d6004c8449 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Fri, 14 Nov 2025 15:54:32 -0800 Subject: [PATCH 0682/2333] block/blk-throttle: Fix throttle slice time for SSDs [ Upstream commit f76581f9f1d29e32e120b0242974ba266e79de58 ] Commit d61fcfa4bb18 ("blk-throttle: choose a small throtl_slice for SSD") introduced device type specific throttle slices if BLK_DEV_THROTTLING_LOW was enabled. Commit bf20ab538c81 ("blk-throttle: remove CONFIG_BLK_DEV_THROTTLING_LOW") removed support for BLK_DEV_THROTTLING_LOW, but left the device type specific throttle slices in place. This effectively changed throttling behavior on systems with SSD which now use a different and non-configurable slice time compared to non-SSD devices. Practical impact is that throughput tests with low configured throttle values (65536 bps) experience less than expected throughput on SSDs, presumably due to rounding errors associated with the small throttle slice time used for those devices. The same tests pass when setting the throttle values to 65536 * 4 = 262144 bps. The original code sets the throttle slice time to DFL_THROTL_SLICE_HD if CONFIG_BLK_DEV_THROTTLING_LOW is disabled. Restore that code to fix the problem. With that, DFL_THROTL_SLICE_SSD is no longer necessary. Revert to the original code and re-introduce DFL_THROTL_SLICE to replace both DFL_THROTL_SLICE_HD and DFL_THROTL_SLICE_SSD. This effectively reverts commit d61fcfa4bb18 ("blk-throttle: choose a small throtl_slice for SSD"). While at it, also remove MAX_THROTL_SLICE since it is not used anymore. Fixes: bf20ab538c81 ("blk-throttle: remove CONFIG_BLK_DEV_THROTTLING_LOW") Cc: Yu Kuai Cc: Tejun Heo Signed-off-by: Guenter Roeck Signed-off-by: Khazhismel Kumykov Reviewed-by: Yu Kuai Signed-off-by: Jens Axboe Signed-off-by: Sasha Levin --- block/blk-throttle.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/block/blk-throttle.c b/block/blk-throttle.c index 2c5b64b1a724a..c19d052a8f2f1 100644 --- a/block/blk-throttle.c +++ b/block/blk-throttle.c @@ -22,9 +22,7 @@ #define THROTL_QUANTUM 32 /* Throttling is performed over a slice and after that slice is renewed */ -#define DFL_THROTL_SLICE_HD (HZ / 10) -#define DFL_THROTL_SLICE_SSD (HZ / 50) -#define MAX_THROTL_SLICE (HZ) +#define DFL_THROTL_SLICE (HZ / 10) /* A workqueue to queue throttle related work */ static struct workqueue_struct *kthrotld_workqueue; @@ -1341,10 +1339,7 @@ static int blk_throtl_init(struct gendisk *disk) goto out; } - if (blk_queue_nonrot(q)) - td->throtl_slice = DFL_THROTL_SLICE_SSD; - else - td->throtl_slice = DFL_THROTL_SLICE_HD; + td->throtl_slice = DFL_THROTL_SLICE; td->track_bio_latency = !queue_is_mq(q); if (!td->track_bio_latency) blk_stat_enable_accounting(q); From 0bc9149da210df7e9a191dde246b89d9ad23be8a Mon Sep 17 00:00:00 2001 From: Huiwen He Date: Thu, 13 Nov 2025 01:04:11 +0800 Subject: [PATCH 0683/2333] drm/msm: Fix NULL pointer dereference in crashstate_get_vm_logs() [ Upstream commit 3099e0247e3217e1b39c1c61766e06ec3d13835f ] crashstate_get_vm_logs() did not check the return value of kmalloc_array(). In low-memory situations, kmalloc_array() may return NULL, leading to a NULL pointer dereference when the function later accesses state->vm_logs. Fix this by checking the return value of kmalloc_array() and setting state->nr_vm_logs to 0 if allocation fails. Fixes: 9edc52967cc7 ("drm/msm: Add VM logging for VM_BIND updates") Signed-off-by: Huiwen He Patchwork: https://patchwork.freedesktop.org/patch/687555/ Signed-off-by: Rob Clark Signed-off-by: Sasha Levin --- drivers/gpu/drm/msm/msm_gpu.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c index 17759abc46d7d..e23f70fbc8cb2 100644 --- a/drivers/gpu/drm/msm/msm_gpu.c +++ b/drivers/gpu/drm/msm/msm_gpu.c @@ -348,6 +348,10 @@ static void crashstate_get_vm_logs(struct msm_gpu_state *state, struct msm_gem_v state->vm_logs = kmalloc_array( state->nr_vm_logs, sizeof(vm->log[0]), GFP_KERNEL); + if (!state->vm_logs) { + state->nr_vm_logs = 0; + } + for (int i = 0; i < state->nr_vm_logs; i++) { int idx = (i + first) & vm_log_mask; From 966fcbb8c80318aa581e97da32056ffbab6138fe Mon Sep 17 00:00:00 2001 From: Huiwen He Date: Thu, 13 Nov 2025 01:19:47 +0800 Subject: [PATCH 0684/2333] drm/msm: fix missing NULL check after kcalloc in crashstate_get_bos() [ Upstream commit 3065e6a4d3594b42dae6176b3e2c0c3563cf94b8 ] The crashstate_get_bos() function allocates memory for `state->bos` using kcalloc(), but the vmbind path does not check for allocation failure before dereferencing it in the following drm_gpuvm_for_each_va() loop. This could lead to a NULL pointer dereference if memory allocation fails. Fix this by wrapping the drm_gpuvm_for_each_va() loop with a NULL check on state->bos, similar to the safety check in the non-vmbind path. Fixes: af9aa6f316b3d ("drm/msm: Crashdump support for sparse") Signed-off-by: Huiwen He Patchwork: https://patchwork.freedesktop.org/patch/687556/ Signed-off-by: Rob Clark Signed-off-by: Sasha Levin --- drivers/gpu/drm/msm/msm_gpu.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c index e23f70fbc8cb2..dd0605fe1243d 100644 --- a/drivers/gpu/drm/msm/msm_gpu.c +++ b/drivers/gpu/drm/msm/msm_gpu.c @@ -287,16 +287,17 @@ static void crashstate_get_bos(struct msm_gpu_state *state, struct msm_gem_submi state->bos = kcalloc(cnt, sizeof(struct msm_gpu_state_bo), GFP_KERNEL); - drm_gpuvm_for_each_va (vma, submit->vm) { - bool dump = rd_full || (vma->flags & MSM_VMA_DUMP); + if (state->bos) + drm_gpuvm_for_each_va(vma, submit->vm) { + bool dump = rd_full || (vma->flags & MSM_VMA_DUMP); - /* Skip MAP_NULL/PRR VMAs: */ - if (!vma->gem.obj) - continue; + /* Skip MAP_NULL/PRR VMAs: */ + if (!vma->gem.obj) + continue; - msm_gpu_crashstate_get_bo(state, vma->gem.obj, vma->va.addr, - dump, vma->gem.offset, vma->va.range); - } + msm_gpu_crashstate_get_bo(state, vma->gem.obj, vma->va.addr, + dump, vma->gem.offset, vma->va.range); + } drm_exec_fini(&exec); } else { From 7b1e3cb2070e2dc0bef3718fb483e1fdef587fab Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Thu, 13 Nov 2025 22:40:50 +0200 Subject: [PATCH 0685/2333] drm/msm/a2xx: stop over-complaining about the legacy firmware [ Upstream commit a3a22373fce576560757f5616eb48dbf85891d9c ] If the rootfs have a legacy A200 firmware, currently the driver will complain each time the hw is reinited (which can happen a lot). E.g. with GL testsuite the hw is reinited after each test, spamming the console. Make sure that the message is printed only once: when we detect the firmware that doesn't support protection. Fixes: 302295070d3c ("drm/msm/a2xx: support loading legacy (iMX) firmware") Signed-off-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/688098/ Signed-off-by: Rob Clark Signed-off-by: Sasha Levin --- drivers/gpu/drm/msm/adreno/a2xx_gpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/adreno/a2xx_gpu.c b/drivers/gpu/drm/msm/adreno/a2xx_gpu.c index ec38db45d8a36..963c0f669ee50 100644 --- a/drivers/gpu/drm/msm/adreno/a2xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a2xx_gpu.c @@ -234,7 +234,7 @@ static int a2xx_hw_init(struct msm_gpu *gpu) * word (0x20xxxx for A200, 0x220xxx for A220, 0x225xxx for A225). * Older firmware files, which lack protection support, have 0 instead. */ - if (ptr[1] == 0) { + if (ptr[1] == 0 && !a2xx_gpu->protection_disabled) { dev_warn(gpu->dev->dev, "Legacy firmware detected, disabling protection support\n"); a2xx_gpu->protection_disabled = true; From 0e82816b68968ae3011386cdb60da0305842ee04 Mon Sep 17 00:00:00 2001 From: Christian Bruel Date: Fri, 14 Nov 2025 08:45:52 +0100 Subject: [PATCH 0686/2333] PCI: stm32: Fix LTSSM EP race with start link [ Upstream commit fa81d6099007728cae39c6f937d83903bbddab5e ] If the host has deasserted PERST# and started link training before the link is started on EP side, enabling LTSSM before the endpoint registers are initialized in the perst_irq handler results in probing incorrect values. Thus, wait for the PERST# level-triggered interrupt to start link training at the end of initialization and cleanup the stm32_pcie_[start stop]_link functions. Fixes: 151f3d29baf4 ("PCI: stm32-ep: Add PCIe Endpoint support for STM32MP25") Signed-off-by: Christian Bruel [mani: added fixes tag] Signed-off-by: Manivannan Sadhasivam [bhelgaas: wrap line] Signed-off-by: Bjorn Helgaas Link: https://patch.msgid.link/20251114-perst_ep-v1-1-e7976317a890@foss.st.com Signed-off-by: Sasha Levin --- drivers/pci/controller/dwc/pcie-stm32-ep.c | 39 +++++----------------- 1 file changed, 8 insertions(+), 31 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-stm32-ep.c b/drivers/pci/controller/dwc/pcie-stm32-ep.c index 3400c7cd2d88a..faa6433a784f3 100644 --- a/drivers/pci/controller/dwc/pcie-stm32-ep.c +++ b/drivers/pci/controller/dwc/pcie-stm32-ep.c @@ -37,36 +37,9 @@ static void stm32_pcie_ep_init(struct dw_pcie_ep *ep) dw_pcie_ep_reset_bar(pci, bar); } -static int stm32_pcie_enable_link(struct dw_pcie *pci) -{ - struct stm32_pcie *stm32_pcie = to_stm32_pcie(pci); - - regmap_update_bits(stm32_pcie->regmap, SYSCFG_PCIECR, - STM32MP25_PCIECR_LTSSM_EN, - STM32MP25_PCIECR_LTSSM_EN); - - return dw_pcie_wait_for_link(pci); -} - -static void stm32_pcie_disable_link(struct dw_pcie *pci) -{ - struct stm32_pcie *stm32_pcie = to_stm32_pcie(pci); - - regmap_update_bits(stm32_pcie->regmap, SYSCFG_PCIECR, STM32MP25_PCIECR_LTSSM_EN, 0); -} - static int stm32_pcie_start_link(struct dw_pcie *pci) { struct stm32_pcie *stm32_pcie = to_stm32_pcie(pci); - int ret; - - dev_dbg(pci->dev, "Enable link\n"); - - ret = stm32_pcie_enable_link(pci); - if (ret) { - dev_err(pci->dev, "PCIe cannot establish link: %d\n", ret); - return ret; - } enable_irq(stm32_pcie->perst_irq); @@ -77,11 +50,7 @@ static void stm32_pcie_stop_link(struct dw_pcie *pci) { struct stm32_pcie *stm32_pcie = to_stm32_pcie(pci); - dev_dbg(pci->dev, "Disable link\n"); - disable_irq(stm32_pcie->perst_irq); - - stm32_pcie_disable_link(pci); } static int stm32_pcie_raise_irq(struct dw_pcie_ep *ep, u8 func_no, @@ -152,6 +121,9 @@ static void stm32_pcie_perst_assert(struct dw_pcie *pci) dev_dbg(dev, "PERST asserted by host\n"); + regmap_update_bits(stm32_pcie->regmap, SYSCFG_PCIECR, + STM32MP25_PCIECR_LTSSM_EN, 0); + pci_epc_deinit_notify(ep->epc); stm32_pcie_disable_resources(stm32_pcie); @@ -192,6 +164,11 @@ static void stm32_pcie_perst_deassert(struct dw_pcie *pci) pci_epc_init_notify(ep->epc); + /* Enable link training */ + regmap_update_bits(stm32_pcie->regmap, SYSCFG_PCIECR, + STM32MP25_PCIECR_LTSSM_EN, + STM32MP25_PCIECR_LTSSM_EN); + return; err_disable_resources: From 9ea941e8bba68f9cefd4ed18663a3a8c85e836e1 Mon Sep 17 00:00:00 2001 From: Christian Bruel Date: Fri, 14 Nov 2025 09:08:05 +0100 Subject: [PATCH 0687/2333] PCI: stm32: Fix EP page_size alignment [ Upstream commit ff529a9307a03ec03ed9751da053b57149300053 ] pci_epc_mem_alloc_addr() allocates a CPU address from the ATU window phys base and a page number. Set the ep->page_size so the resulting CPU address is correctly aligned with the ATU required alignment. Fixes: 151f3d29baf4 ("PCI: stm32-ep: Add PCIe Endpoint support for STM32MP25") Signed-off-by: Christian Bruel [mani: added fixes tag] Signed-off-by: Manivannan Sadhasivam Signed-off-by: Bjorn Helgaas Link: https://patch.msgid.link/20251114-atu_align_ep-v1-1-88da5366fa04@foss.st.com Signed-off-by: Sasha Levin --- drivers/pci/controller/dwc/pcie-stm32-ep.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/pci/controller/dwc/pcie-stm32-ep.c b/drivers/pci/controller/dwc/pcie-stm32-ep.c index faa6433a784f3..7d48038d576d9 100644 --- a/drivers/pci/controller/dwc/pcie-stm32-ep.c +++ b/drivers/pci/controller/dwc/pcie-stm32-ep.c @@ -214,6 +214,8 @@ static int stm32_add_pcie_ep(struct stm32_pcie *stm32_pcie, ep->ops = &stm32_pcie_ep_ops; + ep->page_size = stm32_pcie_epc_features.align; + ret = dw_pcie_ep_init(ep); if (ret) { dev_err(dev, "Failed to initialize ep: %d\n", ret); From c9d1c4152e6d32fa74034464854bee262a60bc43 Mon Sep 17 00:00:00 2001 From: Abdun Nihaal Date: Fri, 14 Nov 2025 15:15:26 +0530 Subject: [PATCH 0688/2333] wifi: rtl818x: Fix potential memory leaks in rtl8180_init_rx_ring() [ Upstream commit 9b5b9c042b30befc5b37e4539ace95af70843473 ] In rtl8180_init_rx_ring(), memory is allocated for skb packets and DMA allocations in a loop. When an allocation fails, the previously successful allocations are not freed on exit. Fix that by jumping to err_free_rings label on error, which calls rtl8180_free_rx_ring() to free the allocations. Remove the free of rx_ring in rtl8180_init_rx_ring() error path, and set the freed priv->rx_buf entry to null, to avoid double free. Fixes: f653211197f3 ("Add rtl8180 wireless driver") Signed-off-by: Abdun Nihaal Reviewed-by: Ping-Ke Shih Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20251114094527.79842-1-nihaal@cse.iitm.ac.in Signed-off-by: Sasha Levin --- drivers/net/wireless/realtek/rtl818x/rtl8180/dev.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/realtek/rtl818x/rtl8180/dev.c b/drivers/net/wireless/realtek/rtl818x/rtl8180/dev.c index 2905baea62390..070c0431c4821 100644 --- a/drivers/net/wireless/realtek/rtl818x/rtl8180/dev.c +++ b/drivers/net/wireless/realtek/rtl818x/rtl8180/dev.c @@ -1023,9 +1023,6 @@ static int rtl8180_init_rx_ring(struct ieee80211_hw *dev) dma_addr_t *mapping; entry = priv->rx_ring + priv->rx_ring_sz*i; if (!skb) { - dma_free_coherent(&priv->pdev->dev, - priv->rx_ring_sz * 32, - priv->rx_ring, priv->rx_ring_dma); wiphy_err(dev->wiphy, "Cannot allocate RX skb\n"); return -ENOMEM; } @@ -1037,9 +1034,7 @@ static int rtl8180_init_rx_ring(struct ieee80211_hw *dev) if (dma_mapping_error(&priv->pdev->dev, *mapping)) { kfree_skb(skb); - dma_free_coherent(&priv->pdev->dev, - priv->rx_ring_sz * 32, - priv->rx_ring, priv->rx_ring_dma); + priv->rx_buf[i] = NULL; wiphy_err(dev->wiphy, "Cannot map DMA for RX skb\n"); return -ENOMEM; } @@ -1130,7 +1125,7 @@ static int rtl8180_start(struct ieee80211_hw *dev) ret = rtl8180_init_rx_ring(dev); if (ret) - return ret; + goto err_free_rings; for (i = 0; i < (dev->queues + 1); i++) if ((ret = rtl8180_init_tx_ring(dev, i, 16))) From d2b57ba171648096b77c493d4e142e1b6f26e546 Mon Sep 17 00:00:00 2001 From: Inochi Amaoto Date: Fri, 14 Nov 2025 08:38:04 +0800 Subject: [PATCH 0689/2333] net: phy: Add helper for fixing RGMII PHY mode based on internal mac delay [ Upstream commit 24afd7827efb7c69adfc41835390470e3eec4740 ] The "phy-mode" property of devicetree indicates whether the PCB has delay now, which means the mac needs to modify the PHY mode based on whether there is an internal delay in the mac. This modification is similar for many ethernet drivers. To simplify code, define the helper phy_fix_phy_mode_for_mac_delays(speed, mac_txid, mac_rxid) to fix PHY mode based on whether mac adds internal delay. Suggested-by: Russell King (Oracle) Signed-off-by: Inochi Amaoto Reviewed-by: Maxime Chevallier Reviewed-by: Simon Horman Link: https://patch.msgid.link/20251114003805.494387-3-inochiama@gmail.com Signed-off-by: Jakub Kicinski Stable-dep-of: db37c6e510de ("net: stmmac: dwmac-sophgo: Add phy interface filter") Signed-off-by: Sasha Levin --- drivers/net/phy/phy-core.c | 43 ++++++++++++++++++++++++++++++++++++++ include/linux/phy.h | 3 +++ 2 files changed, 46 insertions(+) diff --git a/drivers/net/phy/phy-core.c b/drivers/net/phy/phy-core.c index 605ca20ae192d..0c63e6ba2cb0c 100644 --- a/drivers/net/phy/phy-core.c +++ b/drivers/net/phy/phy-core.c @@ -101,6 +101,49 @@ const char *phy_rate_matching_to_str(int rate_matching) } EXPORT_SYMBOL_GPL(phy_rate_matching_to_str); +/** + * phy_fix_phy_mode_for_mac_delays - Convenience function for fixing PHY + * mode based on whether mac adds internal delay + * + * @interface: The current interface mode of the port + * @mac_txid: True if the mac adds internal tx delay + * @mac_rxid: True if the mac adds internal rx delay + * + * Return: fixed PHY mode, or PHY_INTERFACE_MODE_NA if the interface can + * not apply the internal delay + */ +phy_interface_t phy_fix_phy_mode_for_mac_delays(phy_interface_t interface, + bool mac_txid, bool mac_rxid) +{ + if (!phy_interface_mode_is_rgmii(interface)) + return interface; + + if (mac_txid && mac_rxid) { + if (interface == PHY_INTERFACE_MODE_RGMII_ID) + return PHY_INTERFACE_MODE_RGMII; + return PHY_INTERFACE_MODE_NA; + } + + if (mac_txid) { + if (interface == PHY_INTERFACE_MODE_RGMII_ID) + return PHY_INTERFACE_MODE_RGMII_RXID; + if (interface == PHY_INTERFACE_MODE_RGMII_TXID) + return PHY_INTERFACE_MODE_RGMII; + return PHY_INTERFACE_MODE_NA; + } + + if (mac_rxid) { + if (interface == PHY_INTERFACE_MODE_RGMII_ID) + return PHY_INTERFACE_MODE_RGMII_TXID; + if (interface == PHY_INTERFACE_MODE_RGMII_RXID) + return PHY_INTERFACE_MODE_RGMII; + return PHY_INTERFACE_MODE_NA; + } + + return interface; +} +EXPORT_SYMBOL_GPL(phy_fix_phy_mode_for_mac_delays); + /** * phy_interface_num_ports - Return the number of links that can be carried by * a given MAC-PHY physical link. Returns 0 if this is diff --git a/include/linux/phy.h b/include/linux/phy.h index 3c7634482356e..0bc00a4cceb24 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -1813,6 +1813,9 @@ static inline bool phy_is_pseudo_fixed_link(struct phy_device *phydev) return phydev->is_pseudo_fixed_link; } +phy_interface_t phy_fix_phy_mode_for_mac_delays(phy_interface_t interface, + bool mac_txid, bool mac_rxid); + int phy_save_page(struct phy_device *phydev); int phy_select_page(struct phy_device *phydev, int page); int phy_restore_page(struct phy_device *phydev, int oldpage, int ret); From 26815698b6fbdf97f74f0bed9747543adc7bbbf5 Mon Sep 17 00:00:00 2001 From: Inochi Amaoto Date: Fri, 14 Nov 2025 08:38:05 +0800 Subject: [PATCH 0690/2333] net: stmmac: dwmac-sophgo: Add phy interface filter [ Upstream commit db37c6e510deabc9b0ee27c08f1c5aaa19f2e8ef ] As the SG2042 has an internal rx delay, the delay should be removed when initializing the mac, otherwise the phy will be misconfigurated. Fixes: 543009e2d4cd ("net: stmmac: dwmac-sophgo: Add support for Sophgo SG2042 SoC") Signed-off-by: Inochi Amaoto Tested-by: Han Gao Reviewed-by: Andrew Lunn Reviewed-by: Simon Horman Link: https://patch.msgid.link/20251114003805.494387-4-inochiama@gmail.com Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- .../ethernet/stmicro/stmmac/dwmac-sophgo.c | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sophgo.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sophgo.c index 3b7947a7a7ba7..fcdda2401968b 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sophgo.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sophgo.c @@ -7,11 +7,16 @@ #include #include +#include #include #include #include "stmmac_platform.h" +struct sophgo_dwmac_data { + bool has_internal_rx_delay; +}; + static int sophgo_sg2044_dwmac_init(struct platform_device *pdev, struct plat_stmmacenet_data *plat_dat, struct stmmac_resources *stmmac_res) @@ -32,6 +37,7 @@ static int sophgo_sg2044_dwmac_init(struct platform_device *pdev, static int sophgo_dwmac_probe(struct platform_device *pdev) { struct plat_stmmacenet_data *plat_dat; + const struct sophgo_dwmac_data *data; struct stmmac_resources stmmac_res; struct device *dev = &pdev->dev; int ret; @@ -50,11 +56,23 @@ static int sophgo_dwmac_probe(struct platform_device *pdev) if (ret) return ret; + data = device_get_match_data(&pdev->dev); + if (data && data->has_internal_rx_delay) { + plat_dat->phy_interface = phy_fix_phy_mode_for_mac_delays(plat_dat->phy_interface, + false, true); + if (plat_dat->phy_interface == PHY_INTERFACE_MODE_NA) + return -EINVAL; + } + return stmmac_dvr_probe(dev, plat_dat, &stmmac_res); } +static const struct sophgo_dwmac_data sg2042_dwmac_data = { + .has_internal_rx_delay = true, +}; + static const struct of_device_id sophgo_dwmac_match[] = { - { .compatible = "sophgo,sg2042-dwmac" }, + { .compatible = "sophgo,sg2042-dwmac", .data = &sg2042_dwmac_data }, { .compatible = "sophgo,sg2044-dwmac" }, { /* sentinel */ } }; From 2579c356ccd35d06238b176e4b460978186d804b Mon Sep 17 00:00:00 2001 From: Pu Lehui Date: Sat, 15 Nov 2025 10:23:43 +0000 Subject: [PATCH 0691/2333] bpf: Fix invalid prog->stats access when update_effective_progs fails [ Upstream commit 7dc211c1159d991db609bdf4b0fb9033c04adcbc ] Syzkaller triggers an invalid memory access issue following fault injection in update_effective_progs. The issue can be described as follows: __cgroup_bpf_detach update_effective_progs compute_effective_progs bpf_prog_array_alloc <-- fault inject purge_effective_progs /* change to dummy_bpf_prog */ array->items[index] = &dummy_bpf_prog.prog ---softirq start--- __do_softirq ... __cgroup_bpf_run_filter_skb __bpf_prog_run_save_cb bpf_prog_run stats = this_cpu_ptr(prog->stats) /* invalid memory access */ flags = u64_stats_update_begin_irqsave(&stats->syncp) ---softirq end--- static_branch_dec(&cgroup_bpf_enabled_key[atype]) The reason is that fault injection caused update_effective_progs to fail and then changed the original prog into dummy_bpf_prog.prog in purge_effective_progs. Then a softirq came, and accessing the members of dummy_bpf_prog.prog in the softirq triggers invalid mem access. To fix it, skip updating stats when stats is NULL. Fixes: 492ecee892c2 ("bpf: enable program stats") Signed-off-by: Pu Lehui Link: https://lore.kernel.org/r/20251115102343.2200727-1-pulehui@huaweicloud.com Signed-off-by: Alexei Starovoitov Signed-off-by: Sasha Levin --- include/linux/filter.h | 12 +++++++----- kernel/bpf/syscall.c | 3 +++ 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/include/linux/filter.h b/include/linux/filter.h index 973233b82dc1f..569de3b14279a 100644 --- a/include/linux/filter.h +++ b/include/linux/filter.h @@ -712,11 +712,13 @@ static __always_inline u32 __bpf_prog_run(const struct bpf_prog *prog, ret = dfunc(ctx, prog->insnsi, prog->bpf_func); duration = sched_clock() - start; - stats = this_cpu_ptr(prog->stats); - flags = u64_stats_update_begin_irqsave(&stats->syncp); - u64_stats_inc(&stats->cnt); - u64_stats_add(&stats->nsecs, duration); - u64_stats_update_end_irqrestore(&stats->syncp, flags); + if (likely(prog->stats)) { + stats = this_cpu_ptr(prog->stats); + flags = u64_stats_update_begin_irqsave(&stats->syncp); + u64_stats_inc(&stats->cnt); + u64_stats_add(&stats->nsecs, duration); + u64_stats_update_end_irqrestore(&stats->syncp, flags); + } } else { ret = dfunc(ctx, prog->insnsi, prog->bpf_func); } diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index 8a129746bd6cc..15f9afdbfc275 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -2462,6 +2462,9 @@ void notrace bpf_prog_inc_misses_counter(struct bpf_prog *prog) struct bpf_prog_stats *stats; unsigned int flags; + if (unlikely(!prog->stats)) + return; + stats = this_cpu_ptr(prog->stats); flags = u64_stats_update_begin_irqsave(&stats->syncp); u64_stats_inc(&stats->misses); From 1fcbf18558c5df09ffb4d75c811471055edbcb62 Mon Sep 17 00:00:00 2001 From: "Ritesh Harjani (IBM)" Date: Thu, 30 Oct 2025 20:27:27 +0530 Subject: [PATCH 0692/2333] powerpc/64s/hash: Restrict stress_hpt_struct memblock region to within RMA limit [ Upstream commit 17b45ccf09882e0c808ad2cf62acdc90ad968746 ] When HV=0 & IR/DR=0, the Hash MMU is said to be in Virtual Real Addressing Mode during early boot. During this, we should ensure that memory region allocations for stress_hpt_struct should happen from within RMA region as otherwise the boot might get stuck while doing memset of this region. History behind why do we have RMA region limitation is better explained in these 2 patches [1] & [2]. This patch ensures that memset to stress_hpt_struct during early boot does not cross ppc64_rma_size boundary. [1]: https://lore.kernel.org/all/20190710052018.14628-1-sjitindarsingh@gmail.com/ [2]: https://lore.kernel.org/all/87wp54usvj.fsf@linux.vnet.ibm.com/ Fixes: 6b34a099faa12 ("powerpc/64s/hash: add stress_hpt kernel boot option to increase hash faults") Signed-off-by: Ritesh Harjani (IBM) Signed-off-by: Madhavan Srinivasan Link: https://patch.msgid.link/ada1173933ea7617a994d6ee3e54ced8797339fc.1761834163.git.ritesh.list@gmail.com Signed-off-by: Sasha Levin --- arch/powerpc/mm/book3s64/hash_utils.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/arch/powerpc/mm/book3s64/hash_utils.c b/arch/powerpc/mm/book3s64/hash_utils.c index 3aee3af614af8..c99be1286d517 100644 --- a/arch/powerpc/mm/book3s64/hash_utils.c +++ b/arch/powerpc/mm/book3s64/hash_utils.c @@ -1302,11 +1302,14 @@ static void __init htab_initialize(void) unsigned long table; unsigned long pteg_count; unsigned long prot; - phys_addr_t base = 0, size = 0, end; + phys_addr_t base = 0, size = 0, end, limit = MEMBLOCK_ALLOC_ANYWHERE; u64 i; DBG(" -> htab_initialize()\n"); + if (firmware_has_feature(FW_FEATURE_LPAR)) + limit = ppc64_rma_size; + if (mmu_has_feature(MMU_FTR_1T_SEGMENT)) { mmu_kernel_ssize = MMU_SEGSIZE_1T; mmu_highuser_ssize = MMU_SEGSIZE_1T; @@ -1322,7 +1325,7 @@ static void __init htab_initialize(void) // Too early to use nr_cpu_ids, so use NR_CPUS tmp = memblock_phys_alloc_range(sizeof(struct stress_hpt_struct) * NR_CPUS, __alignof__(struct stress_hpt_struct), - 0, MEMBLOCK_ALLOC_ANYWHERE); + MEMBLOCK_LOW_LIMIT, limit); memset((void *)tmp, 0xff, sizeof(struct stress_hpt_struct) * NR_CPUS); stress_hpt_struct = __va(tmp); @@ -1356,11 +1359,10 @@ static void __init htab_initialize(void) mmu_hash_ops.hpte_clear_all(); #endif } else { - unsigned long limit = MEMBLOCK_ALLOC_ANYWHERE; table = memblock_phys_alloc_range(htab_size_bytes, htab_size_bytes, - 0, limit); + MEMBLOCK_LOW_LIMIT, limit); if (!table) panic("ERROR: Failed to allocate %pa bytes below %pa\n", &htab_size_bytes, &limit); From 6b405443b6ab2c1f4c2d10574ac66f4e00827ed9 Mon Sep 17 00:00:00 2001 From: "Ritesh Harjani (IBM)" Date: Thu, 30 Oct 2025 20:27:28 +0530 Subject: [PATCH 0693/2333] powerpc/64s/ptdump: Fix kernel_hash_pagetable dump for ISA v3.00 HPTE format [ Upstream commit eae40a6da63faa9fb63ff61f8fa2b3b57da78a84 ] HPTE format was changed since Power9 (ISA 3.0) onwards. While dumping kernel hash page tables, nothing gets printed on powernv P9+. This patch utilizes the helpers added in the patch tagged as fixes, to convert new format to old format and dump the hptes. This fix is only needed for native_find() (powernv), since pseries continues to work fine with the old format. Fixes: 6b243fcfb5f1e ("powerpc/64: Simplify adaptation to new ISA v3.00 HPTE format") Signed-off-by: Ritesh Harjani (IBM) Signed-off-by: Madhavan Srinivasan Link: https://patch.msgid.link/4c2bb9e5b3cfbc0dd80b61b67cdd3ccfc632684c.1761834163.git.ritesh.list@gmail.com Signed-off-by: Sasha Levin --- arch/powerpc/mm/ptdump/hashpagetable.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/powerpc/mm/ptdump/hashpagetable.c b/arch/powerpc/mm/ptdump/hashpagetable.c index a6baa6166d940..671d0dc00c6d0 100644 --- a/arch/powerpc/mm/ptdump/hashpagetable.c +++ b/arch/powerpc/mm/ptdump/hashpagetable.c @@ -216,6 +216,8 @@ static int native_find(unsigned long ea, int psize, bool primary, u64 *v, u64 vpn = hpt_vpn(ea, vsid, ssize); hash = hpt_hash(vpn, shift, ssize); want_v = hpte_encode_avpn(vpn, psize, ssize); + if (cpu_has_feature(CPU_FTR_ARCH_300)) + want_v = hpte_old_to_new_v(want_v); /* to check in the secondary hash table, we invert the hash */ if (!primary) @@ -229,6 +231,10 @@ static int native_find(unsigned long ea, int psize, bool primary, u64 *v, u64 /* HPTE matches */ *v = be64_to_cpu(hptep->v); *r = be64_to_cpu(hptep->r); + if (cpu_has_feature(CPU_FTR_ARCH_300)) { + *v = hpte_new_to_old_v(*v, *r); + *r = hpte_new_to_old_r(*r); + } return 0; } ++hpte_group; From 11e221124be0324e872d2fdf3d73e18a886214a4 Mon Sep 17 00:00:00 2001 From: Ovidiu Panait Date: Thu, 13 Nov 2025 11:27:20 +0000 Subject: [PATCH 0694/2333] net: stmmac: Fix VLAN 0 deletion in vlan_del_hw_rx_fltr() [ Upstream commit d9db25723677c3741a0cf3643f7f7429fc983921 ] When the "rx-vlan-filter" feature is enabled on a network device, the 8021q module automatically adds a VLAN 0 hardware filter when the device is brought administratively up. For stmmac, this causes vlan_add_hw_rx_fltr() to create a new entry for VID 0 in the mac_device_info->vlan_filter array, in the following format: VLAN_TAG_DATA_ETV | VLAN_TAG_DATA_VEN | vid Here, VLAN_TAG_DATA_VEN indicates that the hardware filter is enabled for that VID. However, on the delete path, vlan_del_hw_rx_fltr() searches the vlan_filter array by VID only, without verifying whether a VLAN entry is enabled. As a result, when the 8021q module attempts to remove VLAN 0, the function may mistakenly match a zero-initialized slot rather than the actual VLAN 0 entry, causing incorrect deletions and leaving stale entries in the hardware table. Fix this by verifying that the VLAN entry's enable bit (VLAN_TAG_DATA_VEN) is set before matching and deleting by VID. This ensures only active VLAN entries are removed and avoids leaving stale entries in the VLAN filter table, particularly for VLAN ID 0. Fixes: ed64639bc1e08 ("net: stmmac: Add support for VLAN Rx filtering") Signed-off-by: Ovidiu Panait Reviewed-by: Maxime Chevallier Link: https://patch.msgid.link/20251113112721.70500-2-ovidiu.panait.rb@renesas.com Signed-off-by: Paolo Abeni Signed-off-by: Sasha Levin --- drivers/net/ethernet/stmicro/stmmac/stmmac_vlan.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_vlan.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_vlan.c index ff02a79c00d4f..b18404dd5a8be 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_vlan.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_vlan.c @@ -122,7 +122,8 @@ static int vlan_del_hw_rx_fltr(struct net_device *dev, /* Extended Rx VLAN Filter Enable */ for (i = 0; i < hw->num_vlan; i++) { - if ((hw->vlan_filter[i] & VLAN_TAG_DATA_VID) == vid) { + if ((hw->vlan_filter[i] & VLAN_TAG_DATA_VEN) && + ((hw->vlan_filter[i] & VLAN_TAG_DATA_VID) == vid)) { ret = vlan_write_filter(dev, hw, i, 0); if (!ret) From 169361f0e0bca86883974441f981bb5296250415 Mon Sep 17 00:00:00 2001 From: Edward Adam Davis Date: Tue, 11 Nov 2025 19:13:56 +0800 Subject: [PATCH 0695/2333] fs/ntfs3: out1 also needs to put mi [ Upstream commit 4d78d1173a653acdaf7500a32b8dc530ca4ad075 ] After ntfs_look_free_mft() executes successfully, all subsequent code that fails to execute must put mi. Fixes: 4342306f0f0d ("fs/ntfs3: Add file operations and implementation") Signed-off-by: Edward Adam Davis Signed-off-by: Konstantin Komarov Signed-off-by: Sasha Levin --- fs/ntfs3/frecord.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/ntfs3/frecord.c b/fs/ntfs3/frecord.c index 8f9fe1d7a6908..a557e3ec0d4c4 100644 --- a/fs/ntfs3/frecord.c +++ b/fs/ntfs3/frecord.c @@ -1015,9 +1015,9 @@ static int ni_ins_attr_ext(struct ntfs_inode *ni, struct ATTR_LIST_ENTRY *le, out2: ni_remove_mi(ni, mi); - mi_put(mi); out1: + mi_put(mi); ntfs_mark_rec_free(sbi, rno, is_mft); out: From 4a3a5c2e93c71dcbe6ba00b87549365eb85130b6 Mon Sep 17 00:00:00 2001 From: Edward Adam Davis Date: Tue, 11 Nov 2025 19:05:42 +0800 Subject: [PATCH 0696/2333] fs/ntfs3: Prevent memory leaks in add sub record [ Upstream commit ccc4e86d1c24260c18ae94541198c3711c140da6 ] If a rb node with the same ino already exists in the rb tree, the newly alloced mft_inode in ni_add_subrecord() will not have its memory cleaned up, which leads to the memory leak issue reported by syzbot. The best option to avoid this issue is to put the newly alloced mft node when a rb node with the same ino already exists in the rb tree and return the rb node found in the rb tree to the parent layer. syzbot reported: BUG: memory leak unreferenced object 0xffff888110bef280 (size 128): backtrace (crc 126a088f): ni_add_subrecord+0x31/0x180 fs/ntfs3/frecord.c:317 ntfs_look_free_mft+0xf0/0x790 fs/ntfs3/fsntfs.c:715 BUG: memory leak unreferenced object 0xffff888109093400 (size 1024): backtrace (crc 7197c55e): mi_init+0x2b/0x50 fs/ntfs3/record.c:105 mi_format_new+0x40/0x220 fs/ntfs3/record.c:422 Fixes: 4342306f0f0d ("fs/ntfs3: Add file operations and implementation") Reported-by: syzbot+3932ccb896e06f7414c9@syzkaller.appspotmail.com Signed-off-by: Edward Adam Davis Signed-off-by: Konstantin Komarov Signed-off-by: Sasha Levin --- fs/ntfs3/frecord.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/fs/ntfs3/frecord.c b/fs/ntfs3/frecord.c index a557e3ec0d4c4..e5a005d216f31 100644 --- a/fs/ntfs3/frecord.c +++ b/fs/ntfs3/frecord.c @@ -325,8 +325,10 @@ bool ni_add_subrecord(struct ntfs_inode *ni, CLST rno, struct mft_inode **mi) mi_get_ref(&ni->mi, &m->mrec->parent_ref); - ni_add_mi(ni, m); - *mi = m; + *mi = ni_ins_mi(ni, &ni->mi_tree, m->rno, &m->node); + if (*mi != m) + mi_put(m); + return true; } From 295ba29e49f63f9d9b72b160ac466ffb174f7cb8 Mon Sep 17 00:00:00 2001 From: Jay Liu Date: Sun, 21 Sep 2025 13:53:05 +0800 Subject: [PATCH 0697/2333] drm/mediatek: Fix CCORR mtk_ctm_s31_32_to_s1_n function issue [ Upstream commit 20ac36b71c53b8c36c6903b5ca87c75226700a97 ] if matrixbit is 11, The range of color matrix is from 0 to (BIT(12) - 1). Values from 0 to (BIT(11) - 1) represent positive numbers, values from BIT(11) to (BIT(12) - 1) represent negative numbers. For example, -1 need converted to 8191. so convert S31.32 to HW Q2.11 format by drm_color_ctm_s31_32_to_qm_n, and set int_bits to 2. Fixes: 738ed4156fba ("drm/mediatek: Add matrix_bits private data for ccorr") Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Jay Liu Link: https://patchwork.kernel.org/project/dri-devel/patch/20250921055416.25588-2-jay.liu@mediatek.com/ Signed-off-by: Chun-Kuang Hu Signed-off-by: Sasha Levin --- drivers/gpu/drm/mediatek/mtk_disp_ccorr.c | 23 +---------------------- 1 file changed, 1 insertion(+), 22 deletions(-) diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ccorr.c b/drivers/gpu/drm/mediatek/mtk_disp_ccorr.c index 10d60d2c2a568..6d7bf4afa78d3 100644 --- a/drivers/gpu/drm/mediatek/mtk_disp_ccorr.c +++ b/drivers/gpu/drm/mediatek/mtk_disp_ccorr.c @@ -80,27 +80,6 @@ void mtk_ccorr_stop(struct device *dev) writel_relaxed(0x0, ccorr->regs + DISP_CCORR_EN); } -/* Converts a DRM S31.32 value to the HW S1.n format. */ -static u16 mtk_ctm_s31_32_to_s1_n(u64 in, u32 n) -{ - u16 r; - - /* Sign bit. */ - r = in & BIT_ULL(63) ? BIT(n + 1) : 0; - - if ((in & GENMASK_ULL(62, 33)) > 0) { - /* identity value 0x100000000 -> 0x400(mt8183), */ - /* identity value 0x100000000 -> 0x800(mt8192), */ - /* if bigger this, set it to max 0x7ff. */ - r |= GENMASK(n, 0); - } else { - /* take the n+1 most important bits. */ - r |= (in >> (32 - n)) & GENMASK(n, 0); - } - - return r; -} - void mtk_ccorr_ctm_set(struct device *dev, struct drm_crtc_state *state) { struct mtk_disp_ccorr *ccorr = dev_get_drvdata(dev); @@ -119,7 +98,7 @@ void mtk_ccorr_ctm_set(struct device *dev, struct drm_crtc_state *state) input = ctm->matrix; for (i = 0; i < ARRAY_SIZE(coeffs); i++) - coeffs[i] = mtk_ctm_s31_32_to_s1_n(input[i], matrix_bits); + coeffs[i] = drm_color_ctm_s31_32_to_qm_n(input[i], 2, matrix_bits); mtk_ddp_write(cmdq_pkt, coeffs[0] << 16 | coeffs[1], &ccorr->cmdq_reg, ccorr->regs, DISP_CCORR_COEF_0); From 45ca97e4ec9bbf6bfba498e9156ed643e54eea39 Mon Sep 17 00:00:00 2001 From: Akhil P Oommen Date: Tue, 18 Nov 2025 14:20:29 +0530 Subject: [PATCH 0698/2333] drm/msm/a6xx: Flush LRZ cache before PT switch [ Upstream commit 180349b8407f3b268b2ceac0e590b8199e043081 ] As per the recommendation, A7x and newer GPUs should flush the LRZ cache before switching the pagetable. Update a6xx_set_pagetable() to do this. While we are at it, sync both BV and BR before issuing a CP_RESET_CONTEXT_STATE command, to match the downstream sequence. Fixes: af66706accdf ("drm/msm/a6xx: Add skeleton A7xx support") Reviewed-by: Konrad Dybcio Signed-off-by: Akhil P Oommen Patchwork: https://patchwork.freedesktop.org/patch/688995/ Message-ID: <20251118-kaana-gpu-support-v4-2-86eeb8e93fb6@oss.qualcomm.com> Signed-off-by: Rob Clark Signed-off-by: Sasha Levin --- drivers/gpu/drm/msm/adreno/a6xx_gpu.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c index b8f8ae940b55f..6f7ed07670b12 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c @@ -224,7 +224,7 @@ static void a6xx_set_pagetable(struct a6xx_gpu *a6xx_gpu, OUT_RING(ring, submit->seqno - 1); OUT_PKT7(ring, CP_THREAD_CONTROL, 1); - OUT_RING(ring, CP_SET_THREAD_BOTH); + OUT_RING(ring, CP_THREAD_CONTROL_0_SYNC_THREADS | CP_SET_THREAD_BOTH); /* Reset state used to synchronize BR and BV */ OUT_PKT7(ring, CP_RESET_CONTEXT_STATE, 1); @@ -235,7 +235,13 @@ static void a6xx_set_pagetable(struct a6xx_gpu *a6xx_gpu, CP_RESET_CONTEXT_STATE_0_RESET_GLOBAL_LOCAL_TS); OUT_PKT7(ring, CP_THREAD_CONTROL, 1); - OUT_RING(ring, CP_SET_THREAD_BR); + OUT_RING(ring, CP_THREAD_CONTROL_0_SYNC_THREADS | CP_SET_THREAD_BOTH); + + OUT_PKT7(ring, CP_EVENT_WRITE, 1); + OUT_RING(ring, LRZ_FLUSH); + + OUT_PKT7(ring, CP_THREAD_CONTROL, 1); + OUT_RING(ring, CP_THREAD_CONTROL_0_SYNC_THREADS | CP_SET_THREAD_BR); } if (!sysprof) { From e24720c823389017de8b58c4279ef321d14a04bc Mon Sep 17 00:00:00 2001 From: Akhil P Oommen Date: Tue, 18 Nov 2025 14:20:30 +0530 Subject: [PATCH 0699/2333] drm/msm/a6xx: Fix the gemnoc workaround [ Upstream commit ff7a6de043fce21ea5891311746b16121b385c59 ] Correct the register offset and enable this workaround for all A7x and newer GPUs to match the recommendation. Also, downstream does this w/a after moving the fence to allow mode. So do the same. Fixes: dbfbb376b50c ("drm/msm/a6xx: Add A621 support") Reviewed-by: Konrad Dybcio Signed-off-by: Akhil P Oommen Patchwork: https://patchwork.freedesktop.org/patch/688997/ Message-ID: <20251118-kaana-gpu-support-v4-3-86eeb8e93fb6@oss.qualcomm.com> Signed-off-by: Rob Clark Signed-off-by: Sasha Levin --- drivers/gpu/drm/msm/adreno/a6xx_gmu.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c index 4e6dc16e4a4c4..605bb55de8d52 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c @@ -485,8 +485,9 @@ static void a6xx_gemnoc_workaround(struct a6xx_gmu *gmu) * in the power down sequence not being fully executed. That in turn can * prevent CX_GDSC from collapsing. Assert Qactive to avoid this. */ - if (adreno_is_a621(adreno_gpu) || adreno_is_7c3(adreno_gpu)) - gmu_write(gmu, REG_A6XX_GMU_AO_AHB_FENCE_CTRL, BIT(0)); + if (adreno_is_a7xx(adreno_gpu) || (adreno_is_a621(adreno_gpu) || + adreno_is_7c3(adreno_gpu))) + gmu_write(gmu, REG_A6XX_GPU_GMU_CX_GMU_CX_FALNEXT_INTF, BIT(0)); } /* Let the GMU know that we are about to go into slumber */ @@ -522,10 +523,9 @@ static int a6xx_gmu_notify_slumber(struct a6xx_gmu *gmu) } out: - a6xx_gemnoc_workaround(gmu); - /* Put fence into allow mode */ gmu_write(gmu, REG_A6XX_GMU_AO_AHB_FENCE_CTRL, 0); + a6xx_gemnoc_workaround(gmu); return ret; } From d8995c4d86ac692dcc766531ee7c9b8c56ecf5a0 Mon Sep 17 00:00:00 2001 From: Akhil P Oommen Date: Tue, 18 Nov 2025 14:20:39 +0530 Subject: [PATCH 0700/2333] drm/msm/a6xx: Improve MX rail fallback in RPMH vote init [ Upstream commit ca04ce7a2f22652fdf6489fa7e02e7d2c08698f4 ] Current logic assumes that the voltage corners in both MxG and MxA are always same. This is not true for recent targets. So, rework the rpmh init sequence to probe and calculate the votes with the respective rails, ie, GX rails should use MxG as secondary rail and Cx rail should use MxA as the secondary rail. Fixes: d6225e0cd096 ("drm/msm/adreno: Add support for X185 GPU") Reviewed-by: Konrad Dybcio Signed-off-by: Akhil P Oommen Patchwork: https://patchwork.freedesktop.org/patch/689014/ Message-ID: <20251118-kaana-gpu-support-v4-12-86eeb8e93fb6@oss.qualcomm.com> Signed-off-by: Rob Clark Signed-off-by: Sasha Levin --- drivers/gpu/drm/msm/adreno/a6xx_gmu.c | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c index 605bb55de8d52..21a3f9b0ab4c2 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c @@ -1492,13 +1492,14 @@ static unsigned int a6xx_gmu_get_arc_level(struct device *dev, } static int a6xx_gmu_rpmh_arc_votes_init(struct device *dev, u32 *votes, - unsigned long *freqs, int freqs_count, const char *id) + unsigned long *freqs, int freqs_count, + const char *pri_id, const char *sec_id) { int i, j; const u16 *pri, *sec; size_t pri_count, sec_count; - pri = cmd_db_read_aux_data(id, &pri_count); + pri = cmd_db_read_aux_data(pri_id, &pri_count); if (IS_ERR(pri)) return PTR_ERR(pri); /* @@ -1509,13 +1510,7 @@ static int a6xx_gmu_rpmh_arc_votes_init(struct device *dev, u32 *votes, if (!pri_count) return -EINVAL; - /* - * Some targets have a separate gfx mxc rail. So try to read that first and then fall back - * to regular mx rail if it is missing - */ - sec = cmd_db_read_aux_data("gmxc.lvl", &sec_count); - if (IS_ERR(sec) && sec != ERR_PTR(-EPROBE_DEFER)) - sec = cmd_db_read_aux_data("mx.lvl", &sec_count); + sec = cmd_db_read_aux_data(sec_id, &sec_count); if (IS_ERR(sec)) return PTR_ERR(sec); @@ -1583,15 +1578,24 @@ static int a6xx_gmu_rpmh_votes_init(struct a6xx_gmu *gmu) struct adreno_gpu *adreno_gpu = &a6xx_gpu->base; const struct a6xx_info *info = adreno_gpu->info->a6xx; struct msm_gpu *gpu = &adreno_gpu->base; + const char *sec_id; + const u16 *gmxc; int ret; + gmxc = cmd_db_read_aux_data("gmxc.lvl", NULL); + if (gmxc == ERR_PTR(-EPROBE_DEFER)) + return -EPROBE_DEFER; + + /* If GMxC is present, prefer that as secondary rail for GX votes */ + sec_id = IS_ERR_OR_NULL(gmxc) ? "mx.lvl" : "gmxc.lvl"; + /* Build the GX votes */ ret = a6xx_gmu_rpmh_arc_votes_init(&gpu->pdev->dev, gmu->gx_arc_votes, - gmu->gpu_freqs, gmu->nr_gpu_freqs, "gfx.lvl"); + gmu->gpu_freqs, gmu->nr_gpu_freqs, "gfx.lvl", sec_id); /* Build the CX votes */ ret |= a6xx_gmu_rpmh_arc_votes_init(gmu->dev, gmu->cx_arc_votes, - gmu->gmu_freqs, gmu->nr_gmu_freqs, "cx.lvl"); + gmu->gmu_freqs, gmu->nr_gmu_freqs, "cx.lvl", "mx.lvl"); /* Build the interconnect votes */ if (info->bcms && gmu->nr_gpu_bws > 1) From 77d179867bcc1f8f48bcfc5cdbcf40ba3ab86ead Mon Sep 17 00:00:00 2001 From: Longbin Li Date: Mon, 17 Nov 2025 17:05:39 +0800 Subject: [PATCH 0701/2333] spi: sophgo: Fix incorrect use of bus width value macros [ Upstream commit d9813cd23d5a7b254cc1b1c1ea042634d8da62e6 ] The previous code initialized the 'reg' value with specific bus-width values (BUS_WIDTH_2_BIT and BUS_WIDTH_4_BIT), which introduces ambiguity. Replace them with BUS_WIDTH_MASK to express the intention clearly. Fixes: de16c322eefb ("spi: sophgo: add SG2044 SPI NOR controller driver") Signed-off-by: Longbin Li Link: https://patch.msgid.link/20251117090559.78288-1-looong.bin@gmail.com Signed-off-by: Mark Brown Signed-off-by: Sasha Levin --- drivers/spi/spi-sg2044-nor.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi-sg2044-nor.c b/drivers/spi/spi-sg2044-nor.c index af48b1fcda930..37f1cfe10be46 100644 --- a/drivers/spi/spi-sg2044-nor.c +++ b/drivers/spi/spi-sg2044-nor.c @@ -42,6 +42,7 @@ #define SPIFMC_TRAN_CSR_TRAN_MODE_RX BIT(0) #define SPIFMC_TRAN_CSR_TRAN_MODE_TX BIT(1) #define SPIFMC_TRAN_CSR_FAST_MODE BIT(3) +#define SPIFMC_TRAN_CSR_BUS_WIDTH_MASK GENMASK(5, 4) #define SPIFMC_TRAN_CSR_BUS_WIDTH_1_BIT (0x00 << 4) #define SPIFMC_TRAN_CSR_BUS_WIDTH_2_BIT (0x01 << 4) #define SPIFMC_TRAN_CSR_BUS_WIDTH_4_BIT (0x02 << 4) @@ -122,8 +123,7 @@ static u32 sg2044_spifmc_init_reg(struct sg2044_spifmc *spifmc) reg = readl(spifmc->io_base + SPIFMC_TRAN_CSR); reg &= ~(SPIFMC_TRAN_CSR_TRAN_MODE_MASK | SPIFMC_TRAN_CSR_FAST_MODE | - SPIFMC_TRAN_CSR_BUS_WIDTH_2_BIT | - SPIFMC_TRAN_CSR_BUS_WIDTH_4_BIT | + SPIFMC_TRAN_CSR_BUS_WIDTH_MASK | SPIFMC_TRAN_CSR_DMA_EN | SPIFMC_TRAN_CSR_ADDR_BYTES_MASK | SPIFMC_TRAN_CSR_WITH_CMD | From 3e5b25da0b4109a3e063759735e6ec4236ea5a05 Mon Sep 17 00:00:00 2001 From: Fernando Fernandez Mancera Date: Sat, 15 Nov 2025 10:59:38 +0100 Subject: [PATCH 0702/2333] ipv6: clear RA flags when adding a static route [ Upstream commit f72514b3c5698e4b900b25345e09f9ed33123de6 ] When an IPv6 Router Advertisement (RA) is received for a prefix, the kernel creates the corresponding on-link route with flags RTF_ADDRCONF and RTF_PREFIX_RT configured and RTF_EXPIRES if lifetime is set. If later a user configures a static IPv6 address on the same prefix the kernel clears the RTF_EXPIRES flag but it doesn't clear the RTF_ADDRCONF and RTF_PREFIX_RT. When the next RA for that prefix is received, the kernel sees the route as RA-learned and wrongly configures back the lifetime. This is problematic because if the route expires, the static address won't have the corresponding on-link route. This fix clears the RTF_ADDRCONF and RTF_PREFIX_RT flags preventing that the lifetime is configured when the next RA arrives. If the static address is deleted, the route becomes RA-learned again. Fixes: 14ef37b6d00e ("ipv6: fix route lookup in addrconf_prefix_rcv()") Reported-by: Garri Djavadyan Closes: https://lore.kernel.org/netdev/ba807d39aca5b4dcf395cc11dca61a130a52cfd3.camel@gmail.com/ Signed-off-by: Fernando Fernandez Mancera Reviewed-by: David Ahern Link: https://patch.msgid.link/20251115095939.6967-1-fmancera@suse.de Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- net/ipv6/ip6_fib.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index 02c16909f6182..2111af022d946 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c @@ -1138,6 +1138,10 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct fib6_info *rt, fib6_set_expires(iter, rt->expires); fib6_add_gc_list(iter); } + if (!(rt->fib6_flags & (RTF_ADDRCONF | RTF_PREFIX_RT))) { + iter->fib6_flags &= ~RTF_ADDRCONF; + iter->fib6_flags &= ~RTF_PREFIX_RT; + } if (rt->fib6_pmtu) fib6_metric_set(iter, RTAX_MTU, From 1ade1edef373e87ba8d4e5dfe07fe420e77474a4 Mon Sep 17 00:00:00 2001 From: Leo Yan Date: Wed, 12 Nov 2025 18:24:27 +0000 Subject: [PATCH 0703/2333] perf arm_spe: Fix memset subclass in operation [ Upstream commit 33e1fffea492b7158a168914dc0da6aedf78d08e ] The operation subclass is extracted from bits [7..1] of the payload. Since bit [0] is not parsed, there is no chance to match the memset type (0x25). As a result, the memset payload is never parsed successfully. Instead of extracting a unified bit field, change to extract the specific bits for each operation subclass. Fixes: 34fb60400e32 ("perf arm-spe: Add raw decoding for SPEv1.3 MTE and MOPS load/store") Signed-off-by: Leo Yan Reviewed-by: Ian Rogers Reviewed-by: James Clark Signed-off-by: Namhyung Kim Signed-off-by: Sasha Levin --- .../arm-spe-decoder/arm-spe-pkt-decoder.c | 25 ++++++------------- .../arm-spe-decoder/arm-spe-pkt-decoder.h | 15 ++++++----- 2 files changed, 14 insertions(+), 26 deletions(-) diff --git a/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c b/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c index 80561630253dd..1a1ffe50ee73a 100644 --- a/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c +++ b/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c @@ -371,31 +371,20 @@ static int arm_spe_pkt_desc_op_type(const struct arm_spe_pkt *packet, arm_spe_pkt_out_string(&err, &buf, &buf_len, " AR"); } - switch (SPE_OP_PKT_LDST_SUBCLASS_GET(payload)) { - case SPE_OP_PKT_LDST_SUBCLASS_SIMD_FP: + if (SPE_OP_PKT_LDST_SUBCLASS_SIMD_FP(payload)) arm_spe_pkt_out_string(&err, &buf, &buf_len, " SIMD-FP"); - break; - case SPE_OP_PKT_LDST_SUBCLASS_GP_REG: + else if (SPE_OP_PKT_LDST_SUBCLASS_GP_REG(payload)) arm_spe_pkt_out_string(&err, &buf, &buf_len, " GP-REG"); - break; - case SPE_OP_PKT_LDST_SUBCLASS_UNSPEC_REG: + else if (SPE_OP_PKT_LDST_SUBCLASS_UNSPEC_REG(payload)) arm_spe_pkt_out_string(&err, &buf, &buf_len, " UNSPEC-REG"); - break; - case SPE_OP_PKT_LDST_SUBCLASS_NV_SYSREG: + else if (SPE_OP_PKT_LDST_SUBCLASS_NV_SYSREG(payload)) arm_spe_pkt_out_string(&err, &buf, &buf_len, " NV-SYSREG"); - break; - case SPE_OP_PKT_LDST_SUBCLASS_MTE_TAG: + else if (SPE_OP_PKT_LDST_SUBCLASS_MTE_TAG(payload)) arm_spe_pkt_out_string(&err, &buf, &buf_len, " MTE-TAG"); - break; - case SPE_OP_PKT_LDST_SUBCLASS_MEMCPY: + else if (SPE_OP_PKT_LDST_SUBCLASS_MEMCPY(payload)) arm_spe_pkt_out_string(&err, &buf, &buf_len, " MEMCPY"); - break; - case SPE_OP_PKT_LDST_SUBCLASS_MEMSET: + else if (SPE_OP_PKT_LDST_SUBCLASS_MEMSET(payload)) arm_spe_pkt_out_string(&err, &buf, &buf_len, " MEMSET"); - break; - default: - break; - } if (SPE_OP_PKT_IS_LDST_SVE(payload)) { /* SVE effective vector length */ diff --git a/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.h b/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.h index d00c2481712dc..75e355fe3438c 100644 --- a/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.h +++ b/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.h @@ -125,14 +125,13 @@ enum arm_spe_events { #define SPE_OP_PKT_IS_OTHER_SVE_OP(v) (((v) & (BIT(7) | BIT(3) | BIT(0))) == 0x8) -#define SPE_OP_PKT_LDST_SUBCLASS_GET(v) ((v) & GENMASK_ULL(7, 1)) -#define SPE_OP_PKT_LDST_SUBCLASS_GP_REG 0x0 -#define SPE_OP_PKT_LDST_SUBCLASS_SIMD_FP 0x4 -#define SPE_OP_PKT_LDST_SUBCLASS_UNSPEC_REG 0x10 -#define SPE_OP_PKT_LDST_SUBCLASS_NV_SYSREG 0x30 -#define SPE_OP_PKT_LDST_SUBCLASS_MTE_TAG 0x14 -#define SPE_OP_PKT_LDST_SUBCLASS_MEMCPY 0x20 -#define SPE_OP_PKT_LDST_SUBCLASS_MEMSET 0x25 +#define SPE_OP_PKT_LDST_SUBCLASS_GP_REG(v) (((v) & GENMASK_ULL(7, 1)) == 0x0) +#define SPE_OP_PKT_LDST_SUBCLASS_SIMD_FP(v) (((v) & GENMASK_ULL(7, 1)) == 0x4) +#define SPE_OP_PKT_LDST_SUBCLASS_UNSPEC_REG(v) (((v) & GENMASK_ULL(7, 1)) == 0x10) +#define SPE_OP_PKT_LDST_SUBCLASS_NV_SYSREG(v) (((v) & GENMASK_ULL(7, 1)) == 0x30) +#define SPE_OP_PKT_LDST_SUBCLASS_MTE_TAG(v) (((v) & GENMASK_ULL(7, 1)) == 0x14) +#define SPE_OP_PKT_LDST_SUBCLASS_MEMCPY(v) (((v) & GENMASK_ULL(7, 1)) == 0x20) +#define SPE_OP_PKT_LDST_SUBCLASS_MEMSET(v) (((v) & GENMASK_ULL(7, 0)) == 0x25) #define SPE_OP_PKT_IS_LDST_ATOMIC(v) (((v) & (GENMASK_ULL(7, 5) | BIT(1))) == 0x2) From f4b45dc5eeb3d5ae3b80566692a27256ba707140 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 18 Nov 2025 18:43:02 +0100 Subject: [PATCH 0704/2333] pwm: bcm2835: Make sure the channel is enabled after pwm_request() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit cda323dbda76600bf9761970d58517648f0de67d ] The .free callback cleared among others the enable bit PWENx in the control register. When the PWM is requested later again this bit isn't restored but the core assumes the PWM is enabled and thus skips a request to configure the same state as before. To fix that don't touch the hardware configuration in .free(). For symmetry also drop .request() and configure the mode completely in .apply(). Fixes: e5a06dc5ac1f ("pwm: Add BCM2835 PWM driver") Signed-off-by: Uwe Kleine-König Reviewed-by: Florian Fainelli Link: https://patch.msgid.link/20251118174303.1761577-2-u.kleine-koenig@baylibre.com Signed-off-by: Uwe Kleine-König Signed-off-by: Sasha Levin --- drivers/pwm/pwm-bcm2835.c | 28 +++------------------------- 1 file changed, 3 insertions(+), 25 deletions(-) diff --git a/drivers/pwm/pwm-bcm2835.c b/drivers/pwm/pwm-bcm2835.c index 578e95e0296c6..532903da521fd 100644 --- a/drivers/pwm/pwm-bcm2835.c +++ b/drivers/pwm/pwm-bcm2835.c @@ -34,29 +34,6 @@ static inline struct bcm2835_pwm *to_bcm2835_pwm(struct pwm_chip *chip) return pwmchip_get_drvdata(chip); } -static int bcm2835_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm) -{ - struct bcm2835_pwm *pc = to_bcm2835_pwm(chip); - u32 value; - - value = readl(pc->base + PWM_CONTROL); - value &= ~(PWM_CONTROL_MASK << PWM_CONTROL_SHIFT(pwm->hwpwm)); - value |= (PWM_MODE << PWM_CONTROL_SHIFT(pwm->hwpwm)); - writel(value, pc->base + PWM_CONTROL); - - return 0; -} - -static void bcm2835_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm) -{ - struct bcm2835_pwm *pc = to_bcm2835_pwm(chip); - u32 value; - - value = readl(pc->base + PWM_CONTROL); - value &= ~(PWM_CONTROL_MASK << PWM_CONTROL_SHIFT(pwm->hwpwm)); - writel(value, pc->base + PWM_CONTROL); -} - static int bcm2835_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, const struct pwm_state *state) { @@ -102,6 +79,9 @@ static int bcm2835_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, /* set polarity */ val = readl(pc->base + PWM_CONTROL); + val &= ~(PWM_CONTROL_MASK << PWM_CONTROL_SHIFT(pwm->hwpwm)); + val |= PWM_MODE << PWM_CONTROL_SHIFT(pwm->hwpwm); + if (state->polarity == PWM_POLARITY_NORMAL) val &= ~(PWM_POLARITY << PWM_CONTROL_SHIFT(pwm->hwpwm)); else @@ -119,8 +99,6 @@ static int bcm2835_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, } static const struct pwm_ops bcm2835_pwm_ops = { - .request = bcm2835_pwm_request, - .free = bcm2835_pwm_free, .apply = bcm2835_pwm_apply, }; From 638779b175216840e321319bd371ff89fdcd5e56 Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Thu, 13 Nov 2025 12:52:55 +0800 Subject: [PATCH 0705/2333] scsi: ufs: rockchip: Reset controller on PRE_CHANGE of hce enable notify [ Upstream commit b0ee72db9132bd19b1b80152b35e0cf6a6cbd9f2 ] This fixes the dme-reset failed when doing recovery. Because device reset is not enough, we could occasionally see the error below: ufshcd-rockchip 2a2d0000.ufs: uic cmd 0x14 with arg3 0x0 completion timeout ufshcd-rockchip 2a2d0000.ufs: dme-reset: error code -110 ufshcd-rockchip 2a2d0000.ufs: DME_RESET failed ufshcd-rockchip 2a2d0000.ufs: ufshcd_host_reset_and_restore: Host init failed -110 Fix this by resetting the controller on PRE_CHANGE stage of hce enable notify. Fixes: d3cbe455d6eb ("scsi: ufs: rockchip: Initial support for UFS") Signed-off-by: Shawn Lin Link: https://patch.msgid.link/1763009575-237552-1-git-send-email-shawn.lin@rock-chips.com Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin --- drivers/ufs/host/ufs-rockchip.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/drivers/ufs/host/ufs-rockchip.c b/drivers/ufs/host/ufs-rockchip.c index 8754085dd0ccf..8cecb28cdce41 100644 --- a/drivers/ufs/host/ufs-rockchip.c +++ b/drivers/ufs/host/ufs-rockchip.c @@ -20,9 +20,17 @@ #include "ufshcd-pltfrm.h" #include "ufs-rockchip.h" +static void ufs_rockchip_controller_reset(struct ufs_rockchip_host *host) +{ + reset_control_assert(host->rst); + udelay(1); + reset_control_deassert(host->rst); +} + static int ufs_rockchip_hce_enable_notify(struct ufs_hba *hba, enum ufs_notify_change_status status) { + struct ufs_rockchip_host *host = ufshcd_get_variant(hba); int err = 0; if (status == POST_CHANGE) { @@ -37,6 +45,9 @@ static int ufs_rockchip_hce_enable_notify(struct ufs_hba *hba, return ufshcd_vops_phy_initialization(hba); } + /* PRE_CHANGE */ + ufs_rockchip_controller_reset(host); + return 0; } @@ -156,9 +167,7 @@ static int ufs_rockchip_common_init(struct ufs_hba *hba) return dev_err_probe(dev, PTR_ERR(host->rst), "failed to get reset control\n"); - reset_control_assert(host->rst); - udelay(1); - reset_control_deassert(host->rst); + ufs_rockchip_controller_reset(host); host->ref_out_clk = devm_clk_get_enabled(dev, "ref_out"); if (IS_ERR(host->ref_out_clk)) @@ -282,9 +291,7 @@ static int ufs_rockchip_runtime_resume(struct device *dev) return err; } - reset_control_assert(host->rst); - udelay(1); - reset_control_deassert(host->rst); + ufs_rockchip_controller_reset(host); return ufshcd_runtime_resume(dev); } From 5fa1c8226b4532ad7011d295d3ab4ad45df105ae Mon Sep 17 00:00:00 2001 From: Zilin Guan Date: Thu, 13 Nov 2025 15:12:46 +0000 Subject: [PATCH 0706/2333] scsi: qla2xxx: Fix improper freeing of purex item [ Upstream commit 78b1a242fe612a755f2158fd206ee6bb577d18ca ] In qla2xxx_process_purls_iocb(), an item is allocated via qla27xx_copy_multiple_pkt(), which internally calls qla24xx_alloc_purex_item(). The qla24xx_alloc_purex_item() function may return a pre-allocated item from a per-adapter pool for small allocations, instead of dynamically allocating memory with kzalloc(). An error handling path in qla2xxx_process_purls_iocb() incorrectly uses kfree() to release the item. If the item was from the pre-allocated pool, calling kfree() on it is a bug that can lead to memory corruption. Fix this by using the correct deallocation function, qla24xx_free_purex_item(), which properly handles both dynamically allocated and pre-allocated items. Fixes: 875386b98857 ("scsi: qla2xxx: Add Unsolicited LS Request and Response Support for NVMe") Signed-off-by: Zilin Guan Reviewed-by: Himanshu Madhani Link: https://patch.msgid.link/20251113151246.762510-1-zilin@seu.edu.cn Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin --- drivers/scsi/qla2xxx/qla_nvme.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/qla2xxx/qla_nvme.c b/drivers/scsi/qla2xxx/qla_nvme.c index 316594aa40cc5..42eb65a62f1f3 100644 --- a/drivers/scsi/qla2xxx/qla_nvme.c +++ b/drivers/scsi/qla2xxx/qla_nvme.c @@ -1292,7 +1292,7 @@ void qla2xxx_process_purls_iocb(void **pkt, struct rsp_que **rsp) a.reason = FCNVME_RJT_RC_LOGIC; a.explanation = FCNVME_RJT_EXP_NONE; xmt_reject = true; - kfree(item); + qla24xx_free_purex_item(item); goto out; } From 6fccca4dbebc99655e0101949af05d74c5b67d63 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Tue, 18 Nov 2025 01:40:28 +0200 Subject: [PATCH 0707/2333] net: phy: realtek: create rtl8211f_config_rgmii_delay() [ Upstream commit 8e982441ba601d982dd0739972115d85ae01d99b ] The control flow in rtl8211f_config_init() has some pitfalls which were probably unintended. Specifically it has an early return: switch (phydev->interface) { ... default: /* the rest of the modes imply leaving delay as is. */ return 0; } which exits the entire config_init() function. This means it also skips doing things such as disabling CLKOUT or disabling PHY-mode EEE. For the RTL8211FS, which uses PHY_INTERFACE_MODE_SGMII, this might be a problem. However, I don't know that it is, so there is no Fixes: tag. The issue was observed through code inspection. Signed-off-by: Vladimir Oltean Reviewed-by: Andrew Lunn Link: https://patch.msgid.link/20251117234033.345679-2-vladimir.oltean@nxp.com Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- drivers/net/phy/realtek/realtek_main.c | 65 +++++++++++++++----------- 1 file changed, 39 insertions(+), 26 deletions(-) diff --git a/drivers/net/phy/realtek/realtek_main.c b/drivers/net/phy/realtek/realtek_main.c index 16a347084293e..b26f4d1c6bbfa 100644 --- a/drivers/net/phy/realtek/realtek_main.c +++ b/drivers/net/phy/realtek/realtek_main.c @@ -560,22 +560,11 @@ static int rtl8211c_config_init(struct phy_device *phydev) CTL1000_ENABLE_MASTER | CTL1000_AS_MASTER); } -static int rtl8211f_config_init(struct phy_device *phydev) +static int rtl8211f_config_rgmii_delay(struct phy_device *phydev) { - struct rtl821x_priv *priv = phydev->priv; - struct device *dev = &phydev->mdio.dev; u16 val_txdly, val_rxdly; int ret; - ret = phy_modify_paged_changed(phydev, RTL8211F_PHYCR_PAGE, RTL8211F_PHYCR1, - RTL8211F_ALDPS_PLL_OFF | RTL8211F_ALDPS_ENABLE | RTL8211F_ALDPS_XTAL_OFF, - priv->phycr1); - if (ret < 0) { - dev_err(dev, "aldps mode configuration failed: %pe\n", - ERR_PTR(ret)); - return ret; - } - switch (phydev->interface) { case PHY_INTERFACE_MODE_RGMII: val_txdly = 0; @@ -605,34 +594,58 @@ static int rtl8211f_config_init(struct phy_device *phydev) RTL8211F_TXCR, RTL8211F_TX_DELAY, val_txdly); if (ret < 0) { - dev_err(dev, "Failed to update the TX delay register\n"); + phydev_err(phydev, "Failed to update the TX delay register: %pe\n", + ERR_PTR(ret)); return ret; } else if (ret) { - dev_dbg(dev, - "%s 2ns TX delay (and changing the value from pin-strapping RXD1 or the bootloader)\n", - str_enable_disable(val_txdly)); + phydev_dbg(phydev, + "%s 2ns TX delay (and changing the value from pin-strapping RXD1 or the bootloader)\n", + str_enable_disable(val_txdly)); } else { - dev_dbg(dev, - "2ns TX delay was already %s (by pin-strapping RXD1 or bootloader configuration)\n", - str_enabled_disabled(val_txdly)); + phydev_dbg(phydev, + "2ns TX delay was already %s (by pin-strapping RXD1 or bootloader configuration)\n", + str_enabled_disabled(val_txdly)); } ret = phy_modify_paged_changed(phydev, RTL8211F_RGMII_PAGE, RTL8211F_RXCR, RTL8211F_RX_DELAY, val_rxdly); if (ret < 0) { - dev_err(dev, "Failed to update the RX delay register\n"); + phydev_err(phydev, "Failed to update the RX delay register: %pe\n", + ERR_PTR(ret)); return ret; } else if (ret) { - dev_dbg(dev, - "%s 2ns RX delay (and changing the value from pin-strapping RXD0 or the bootloader)\n", - str_enable_disable(val_rxdly)); + phydev_dbg(phydev, + "%s 2ns RX delay (and changing the value from pin-strapping RXD0 or the bootloader)\n", + str_enable_disable(val_rxdly)); } else { - dev_dbg(dev, - "2ns RX delay was already %s (by pin-strapping RXD0 or bootloader configuration)\n", - str_enabled_disabled(val_rxdly)); + phydev_dbg(phydev, + "2ns RX delay was already %s (by pin-strapping RXD0 or bootloader configuration)\n", + str_enabled_disabled(val_rxdly)); } + return 0; +} + +static int rtl8211f_config_init(struct phy_device *phydev) +{ + struct rtl821x_priv *priv = phydev->priv; + struct device *dev = &phydev->mdio.dev; + int ret; + + ret = phy_modify_paged_changed(phydev, RTL8211F_PHYCR_PAGE, RTL8211F_PHYCR1, + RTL8211F_ALDPS_PLL_OFF | RTL8211F_ALDPS_ENABLE | RTL8211F_ALDPS_XTAL_OFF, + priv->phycr1); + if (ret < 0) { + dev_err(dev, "aldps mode configuration failed: %pe\n", + ERR_PTR(ret)); + return ret; + } + + ret = rtl8211f_config_rgmii_delay(phydev); + if (ret) + return ret; + if (!priv->has_phycr2) return 0; From 3cf1f23648496703707f5049807b856df2696688 Mon Sep 17 00:00:00 2001 From: "Vineeth Pillai (Google)" Date: Wed, 19 Nov 2025 13:16:12 +0800 Subject: [PATCH 0708/2333] iommu/vt-d: Set INTEL_IOMMU_FLOPPY_WA depend on BLK_DEV_FD [ Upstream commit cb3db5a39e2a6b6396df1780d39a250f649d2e3a ] INTEL_IOMMU_FLOPPY_WA workaround was introduced to create direct mappings for first 16MB for floppy devices as the floppy drivers were not using dma apis. We need not do this direct map if floppy driver is not enabled. INTEL_IOMMU_FLOPPY_WA is generally not a good idea. Iommu will be mapping pages in this address range while kernel would also be allocating from this range(mostly on memory stress). A misbehaving device using this domain will have access to the pages that the kernel might be actively using. We noticed this while running a test that was trying to figure out if any pages used by kernel is in iommu page tables. This patch reduces the scope of the above issue by disabling the workaround when floppy driver is not enabled. But we would still need to fix the floppy driver to use dma apis so that we need not do direct map without reserving the pages. Or the other option is to reserve this memory range in firmware so that kernel will not use the pages. Fixes: d850c2ee5fe2 ("iommu/vt-d: Expose ISA direct mapping region via iommu_get_resv_regions") Fixes: 49a0429e53f2 ("Intel IOMMU: Iommu floppy workaround") Signed-off-by: Vineeth Pillai (Google) Link: https://lore.kernel.org/r/20251002161625.1155133-1-vineeth@bitbyteword.org Signed-off-by: Lu Baolu Signed-off-by: Joerg Roedel Signed-off-by: Sasha Levin --- drivers/iommu/intel/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iommu/intel/Kconfig b/drivers/iommu/intel/Kconfig index f2f538c706503..17a91f881b2e9 100644 --- a/drivers/iommu/intel/Kconfig +++ b/drivers/iommu/intel/Kconfig @@ -66,7 +66,7 @@ config INTEL_IOMMU_DEFAULT_ON config INTEL_IOMMU_FLOPPY_WA def_bool y - depends on X86 + depends on X86 && BLK_DEV_FD help Floppy disk drivers are known to bypass DMA API calls thereby failing to work when IOMMU is enabled. This From 055e892aac1414bd3a17d435361722e2a6b4b2db Mon Sep 17 00:00:00 2001 From: Aashish Sharma Date: Wed, 19 Nov 2025 13:16:13 +0800 Subject: [PATCH 0709/2333] iommu/vt-d: Fix unused invalidation hint in qi_desc_iotlb [ Upstream commit 6b38a108eeb3936b21643191db535a35dd7c890b ] Invalidation hint (ih) in the function 'qi_desc_iotlb' is initialized to zero and never used. It is embedded in the 0th bit of the 'addr' parameter. Get the correct 'ih' value from there. Fixes: f701c9f36bcb ("iommu/vt-d: Factor out invalidation descriptor composition") Signed-off-by: Aashish Sharma Link: https://lore.kernel.org/r/20251009010903.1323979-1-aashish@aashishsharma.net Signed-off-by: Lu Baolu Signed-off-by: Joerg Roedel Signed-off-by: Sasha Levin --- drivers/iommu/intel/iommu.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iommu/intel/iommu.h b/drivers/iommu/intel/iommu.h index 3056583d7f56b..dcc5466d35f93 100644 --- a/drivers/iommu/intel/iommu.h +++ b/drivers/iommu/intel/iommu.h @@ -1097,7 +1097,7 @@ static inline void qi_desc_iotlb(struct intel_iommu *iommu, u16 did, u64 addr, struct qi_desc *desc) { u8 dw = 0, dr = 0; - int ih = 0; + int ih = addr & 1; if (cap_write_drain(iommu->cap)) dw = 1; From a6fb8785b1796c42728cf7498cb045772efd7af6 Mon Sep 17 00:00:00 2001 From: Chien Wong Date: Thu, 13 Nov 2025 22:05:07 +0800 Subject: [PATCH 0710/2333] wifi: mac80211: fix CMAC functions not handling errors [ Upstream commit 353cda30d30e5dc7cacf8de5d2546724708ae3bb ] The called hash functions could fail thus we should check return values. Fixes: 26717828b75d ("mac80211: aes-cmac: switch to shash CMAC driver") Signed-off-by: Chien Wong Link: https://patch.msgid.link/20251113140511.48658-2-m@xv97.com Signed-off-by: Johannes Berg Signed-off-by: Sasha Levin --- net/mac80211/aes_cmac.c | 63 +++++++++++++++++++++++++++++------------ net/mac80211/aes_cmac.h | 8 +++--- net/mac80211/wpa.c | 20 +++++++------ 3 files changed, 61 insertions(+), 30 deletions(-) diff --git a/net/mac80211/aes_cmac.c b/net/mac80211/aes_cmac.c index 48c04f89de20a..65989c7dfc680 100644 --- a/net/mac80211/aes_cmac.c +++ b/net/mac80211/aes_cmac.c @@ -22,50 +22,77 @@ static const u8 zero[CMAC_TLEN_256]; -void ieee80211_aes_cmac(struct crypto_shash *tfm, const u8 *aad, - const u8 *data, size_t data_len, u8 *mic) +int ieee80211_aes_cmac(struct crypto_shash *tfm, const u8 *aad, + const u8 *data, size_t data_len, u8 *mic) { + int err; SHASH_DESC_ON_STACK(desc, tfm); u8 out[AES_BLOCK_SIZE]; const __le16 *fc; desc->tfm = tfm; - crypto_shash_init(desc); - crypto_shash_update(desc, aad, AAD_LEN); + err = crypto_shash_init(desc); + if (err) + return err; + err = crypto_shash_update(desc, aad, AAD_LEN); + if (err) + return err; fc = (const __le16 *)aad; if (ieee80211_is_beacon(*fc)) { /* mask Timestamp field to zero */ - crypto_shash_update(desc, zero, 8); - crypto_shash_update(desc, data + 8, data_len - 8 - CMAC_TLEN); + err = crypto_shash_update(desc, zero, 8); + if (err) + return err; + err = crypto_shash_update(desc, data + 8, + data_len - 8 - CMAC_TLEN); + if (err) + return err; } else { - crypto_shash_update(desc, data, data_len - CMAC_TLEN); + err = crypto_shash_update(desc, data, + data_len - CMAC_TLEN); + if (err) + return err; } - crypto_shash_finup(desc, zero, CMAC_TLEN, out); - + err = crypto_shash_finup(desc, zero, CMAC_TLEN, out); + if (err) + return err; memcpy(mic, out, CMAC_TLEN); + + return 0; } -void ieee80211_aes_cmac_256(struct crypto_shash *tfm, const u8 *aad, - const u8 *data, size_t data_len, u8 *mic) +int ieee80211_aes_cmac_256(struct crypto_shash *tfm, const u8 *aad, + const u8 *data, size_t data_len, u8 *mic) { + int err; SHASH_DESC_ON_STACK(desc, tfm); const __le16 *fc; desc->tfm = tfm; - crypto_shash_init(desc); - crypto_shash_update(desc, aad, AAD_LEN); + err = crypto_shash_init(desc); + if (err) + return err; + err = crypto_shash_update(desc, aad, AAD_LEN); + if (err) + return err; fc = (const __le16 *)aad; if (ieee80211_is_beacon(*fc)) { /* mask Timestamp field to zero */ - crypto_shash_update(desc, zero, 8); - crypto_shash_update(desc, data + 8, - data_len - 8 - CMAC_TLEN_256); + err = crypto_shash_update(desc, zero, 8); + if (err) + return err; + err = crypto_shash_update(desc, data + 8, + data_len - 8 - CMAC_TLEN_256); + if (err) + return err; } else { - crypto_shash_update(desc, data, data_len - CMAC_TLEN_256); + err = crypto_shash_update(desc, data, data_len - CMAC_TLEN_256); + if (err) + return err; } - crypto_shash_finup(desc, zero, CMAC_TLEN_256, mic); + return crypto_shash_finup(desc, zero, CMAC_TLEN_256, mic); } struct crypto_shash *ieee80211_aes_cmac_key_setup(const u8 key[], diff --git a/net/mac80211/aes_cmac.h b/net/mac80211/aes_cmac.h index 76817446fb838..f74150542142a 100644 --- a/net/mac80211/aes_cmac.h +++ b/net/mac80211/aes_cmac.h @@ -11,10 +11,10 @@ struct crypto_shash *ieee80211_aes_cmac_key_setup(const u8 key[], size_t key_len); -void ieee80211_aes_cmac(struct crypto_shash *tfm, const u8 *aad, - const u8 *data, size_t data_len, u8 *mic); -void ieee80211_aes_cmac_256(struct crypto_shash *tfm, const u8 *aad, - const u8 *data, size_t data_len, u8 *mic); +int ieee80211_aes_cmac(struct crypto_shash *tfm, const u8 *aad, + const u8 *data, size_t data_len, u8 *mic); +int ieee80211_aes_cmac_256(struct crypto_shash *tfm, const u8 *aad, + const u8 *data, size_t data_len, u8 *mic); void ieee80211_aes_cmac_key_free(struct crypto_shash *tfm); #endif /* AES_CMAC_H */ diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index 40d5d9e484791..bb0fa505cdcae 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c @@ -869,8 +869,9 @@ ieee80211_crypto_aes_cmac_encrypt(struct ieee80211_tx_data *tx) /* * MIC = AES-128-CMAC(IGTK, AAD || Management Frame Body || MMIE, 64) */ - ieee80211_aes_cmac(key->u.aes_cmac.tfm, aad, - skb->data + 24, skb->len - 24, mmie->mic); + if (ieee80211_aes_cmac(key->u.aes_cmac.tfm, aad, + skb->data + 24, skb->len - 24, mmie->mic)) + return TX_DROP; return TX_CONTINUE; } @@ -916,8 +917,9 @@ ieee80211_crypto_aes_cmac_256_encrypt(struct ieee80211_tx_data *tx) /* MIC = AES-256-CMAC(IGTK, AAD || Management Frame Body || MMIE, 128) */ - ieee80211_aes_cmac_256(key->u.aes_cmac.tfm, aad, - skb->data + 24, skb->len - 24, mmie->mic); + if (ieee80211_aes_cmac_256(key->u.aes_cmac.tfm, aad, + skb->data + 24, skb->len - 24, mmie->mic)) + return TX_DROP; return TX_CONTINUE; } @@ -956,8 +958,9 @@ ieee80211_crypto_aes_cmac_decrypt(struct ieee80211_rx_data *rx) if (!(status->flag & RX_FLAG_DECRYPTED)) { /* hardware didn't decrypt/verify MIC */ bip_aad(skb, aad); - ieee80211_aes_cmac(key->u.aes_cmac.tfm, aad, - skb->data + 24, skb->len - 24, mic); + if (ieee80211_aes_cmac(key->u.aes_cmac.tfm, aad, + skb->data + 24, skb->len - 24, mic)) + return RX_DROP_U_DECRYPT_FAIL; if (crypto_memneq(mic, mmie->mic, sizeof(mmie->mic))) { key->u.aes_cmac.icverrors++; return RX_DROP_U_MIC_FAIL; @@ -1006,8 +1009,9 @@ ieee80211_crypto_aes_cmac_256_decrypt(struct ieee80211_rx_data *rx) if (!(status->flag & RX_FLAG_DECRYPTED)) { /* hardware didn't decrypt/verify MIC */ bip_aad(skb, aad); - ieee80211_aes_cmac_256(key->u.aes_cmac.tfm, aad, - skb->data + 24, skb->len - 24, mic); + if (ieee80211_aes_cmac_256(key->u.aes_cmac.tfm, aad, + skb->data + 24, skb->len - 24, mic)) + return RX_DROP_U_DECRYPT_FAIL; if (crypto_memneq(mic, mmie->mic, sizeof(mmie->mic))) { key->u.aes_cmac.icverrors++; return RX_DROP_U_MIC_FAIL; From efdb8e298907639746a283eefd699e4bfd94c100 Mon Sep 17 00:00:00 2001 From: Costa Shulyupin Date: Thu, 2 Oct 2025 20:08:45 +0300 Subject: [PATCH 0711/2333] tools/rtla: Fix unassigned nr_cpus [ Upstream commit b4275b23010df719ec6508ddbc84951dcd24adce ] In recently introduced timerlat_free(), the variable 'nr_cpus' is not assigned. Assign it with sysconf(_SC_NPROCESSORS_CONF) as done elsewhere. Remove the culprit: -Wno-maybe-uninitialized. The rest of the code is clean. Signed-off-by: Costa Shulyupin Reviewed-by: Tomas Glozar Fixes: 2f3172f9dd58 ("tools/rtla: Consolidate code between osnoise/timerlat and hist/top") Link: https://lore.kernel.org/r/20251002170846.437888-1-costa.shul@redhat.com Signed-off-by: Tomas Glozar Signed-off-by: Sasha Levin --- tools/tracing/rtla/Makefile.rtla | 2 +- tools/tracing/rtla/src/timerlat.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/tools/tracing/rtla/Makefile.rtla b/tools/tracing/rtla/Makefile.rtla index 08c1b40883d3a..1743d91829d46 100644 --- a/tools/tracing/rtla/Makefile.rtla +++ b/tools/tracing/rtla/Makefile.rtla @@ -18,7 +18,7 @@ export CC AR STRIP PKG_CONFIG LD_SO_CONF_PATH LDCONFIG FOPTS := -flto=auto -ffat-lto-objects -fexceptions -fstack-protector-strong \ -fasynchronous-unwind-tables -fstack-clash-protection WOPTS := -O -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 \ - -Wp,-D_GLIBCXX_ASSERTIONS -Wno-maybe-uninitialized + -Wp,-D_GLIBCXX_ASSERTIONS ifeq ($(CC),clang) FOPTS := $(filter-out -flto=auto -ffat-lto-objects, $(FOPTS)) diff --git a/tools/tracing/rtla/src/timerlat.c b/tools/tracing/rtla/src/timerlat.c index b692128741279..11ad447a8dd78 100644 --- a/tools/tracing/rtla/src/timerlat.c +++ b/tools/tracing/rtla/src/timerlat.c @@ -215,7 +215,8 @@ void timerlat_analyze(struct osnoise_tool *tool, bool stopped) void timerlat_free(struct osnoise_tool *tool) { struct timerlat_params *params = to_timerlat_params(tool->params); - int nr_cpus, i; + int nr_cpus = sysconf(_SC_NPROCESSORS_CONF); + int i; timerlat_aa_destroy(); if (dma_latency_fd >= 0) From f75dc8cb4117067ed2bec2b27a61ccbc4ab65f33 Mon Sep 17 00:00:00 2001 From: Tomas Glozar Date: Tue, 7 Oct 2025 11:53:39 +0200 Subject: [PATCH 0712/2333] tools/rtla: Fix --on-threshold always triggering [ Upstream commit 417bd0d502f90a2e785e7299dae4f248b5ac0292 ] Commit 8d933d5c89e8 ("rtla/timerlat: Add continue action") moved the code performing on-threshold actions (enabled through --on-threshold option) to inside the RTLA main loop. The condition in the loop does not check whether the threshold was actually exceeded or if stop tracing was requested by the user through SIGINT or duration. This leads to a bug where on-threshold actions are always performed, even when the threshold was not hit. (BPF mode is not affected, since it uses a different condition in the while loop.) Add a condition that checks for !stop_tracing before executing the actions. Also, fix incorrect brackets in hist_main_loop to match the semantics of top_main_loop. Fixes: 8d933d5c89e8 ("rtla/timerlat: Add continue action") Fixes: 2f3172f9dd58 ("tools/rtla: Consolidate code between osnoise/timerlat and hist/top") Reviewed-by: Crystal Wood Reviewed-by: Wander Lairson Costa Link: https://lore.kernel.org/r/20251007095341.186923-1-tglozar@redhat.com Signed-off-by: Tomas Glozar Signed-off-by: Sasha Levin --- tools/tracing/rtla/src/common.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/tools/tracing/rtla/src/common.c b/tools/tracing/rtla/src/common.c index 2e6e3dac1897f..b197037fc58b3 100644 --- a/tools/tracing/rtla/src/common.c +++ b/tools/tracing/rtla/src/common.c @@ -268,6 +268,10 @@ int top_main_loop(struct osnoise_tool *tool) tool->ops->print_stats(tool); if (osnoise_trace_is_off(tool, record)) { + if (stop_tracing) + /* stop tracing requested, do not perform actions */ + return 0; + actions_perform(¶ms->threshold_actions); if (!params->threshold_actions.continue_flag) @@ -315,20 +319,22 @@ int hist_main_loop(struct osnoise_tool *tool) } if (osnoise_trace_is_off(tool, tool->record)) { + if (stop_tracing) + /* stop tracing requested, do not perform actions */ + break; + actions_perform(¶ms->threshold_actions); - if (!params->threshold_actions.continue_flag) { + if (!params->threshold_actions.continue_flag) /* continue flag not set, break */ break; - /* continue action reached, re-enable tracing */ - if (tool->record) - trace_instance_start(&tool->record->trace); - if (tool->aa) - trace_instance_start(&tool->aa->trace); - trace_instance_start(&tool->trace); - } - break; + /* continue action reached, re-enable tracing */ + if (tool->record) + trace_instance_start(&tool->record->trace); + if (tool->aa) + trace_instance_start(&tool->aa->trace); + trace_instance_start(&tool->trace); } /* is there still any user-threads ? */ From f620f2a12012a5bc9fa8c2688fdfd98fdae751ff Mon Sep 17 00:00:00 2001 From: Haotian Zhang Date: Tue, 18 Nov 2025 20:15:00 +0800 Subject: [PATCH 0713/2333] mfd: mt6397-irq: Fix missing irq_domain_remove() in error path [ Upstream commit b4b1bd1f330fdd13706382be6c90ce9f58cee3f5 ] If devm_request_threaded_irq() fails after irq_domain_create_linear() succeeds in mt6397_irq_init(), the function returns without removing the created IRQ domain, leading to a resource leak. Call irq_domain_remove() in the error path after a successful irq_domain_create_linear() to properly release the IRQ domain. Fixes: a4872e80ce7d ("mfd: mt6397: Extract IRQ related code from core driver") Signed-off-by: Haotian Zhang Link: https://patch.msgid.link/20251118121500.605-1-vulab@iscas.ac.cn Signed-off-by: Lee Jones Signed-off-by: Sasha Levin --- drivers/mfd/mt6397-irq.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mfd/mt6397-irq.c b/drivers/mfd/mt6397-irq.c index 0e463026c5a91..5d2e5459f7444 100644 --- a/drivers/mfd/mt6397-irq.c +++ b/drivers/mfd/mt6397-irq.c @@ -229,6 +229,7 @@ int mt6397_irq_init(struct mt6397_chip *chip) if (ret) { dev_err(chip->dev, "failed to register irq=%d; err: %d\n", chip->irq, ret); + irq_domain_remove(chip->irq_domain); return ret; } From d0482ca91d76b337fd485a2437edabc530b3630f Mon Sep 17 00:00:00 2001 From: Haotian Zhang Date: Tue, 18 Nov 2025 20:14:27 +0800 Subject: [PATCH 0714/2333] mfd: mt6358-irq: Fix missing irq_domain_remove() in error path [ Upstream commit 384bd58bf7095e4c4c8fcdbcede316ef342c630c ] If devm_request_threaded_irq() fails after irq_domain_add_linear() succeeds in mt6358_irq_init(), the function returns without removing the created IRQ domain, leading to a resource leak. Call irq_domain_remove() in the error path after a successful irq_domain_add_linear() to properly release the IRQ domain. Fixes: 2b91c28f2abd ("mfd: Add support for the MediaTek MT6358 PMIC") Signed-off-by: Haotian Zhang Link: https://patch.msgid.link/20251118121427.583-1-vulab@iscas.ac.cn Signed-off-by: Lee Jones Signed-off-by: Sasha Levin --- drivers/mfd/mt6358-irq.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mfd/mt6358-irq.c b/drivers/mfd/mt6358-irq.c index f467b00d23660..74cf208430440 100644 --- a/drivers/mfd/mt6358-irq.c +++ b/drivers/mfd/mt6358-irq.c @@ -285,6 +285,7 @@ int mt6358_irq_init(struct mt6397_chip *chip) if (ret) { dev_err(chip->dev, "Failed to register IRQ=%d, ret=%d\n", chip->irq, ret); + irq_domain_remove(chip->irq_domain); return ret; } From 7045d5970e16393c1ad3fd1b27c433b6c22c6dee Mon Sep 17 00:00:00 2001 From: Yuntao Wang Date: Sat, 15 Nov 2025 21:47:46 +0800 Subject: [PATCH 0715/2333] of/fdt: Consolidate duplicate code into helper functions [ Upstream commit 8278cb72c60399f6dc6300c409879fb4c7291513 ] Currently, there are many pieces of nearly identical code scattered across different places. Consolidate the duplicate code into helper functions to improve maintainability and reduce the likelihood of errors. Signed-off-by: Yuntao Wang Link: https://patch.msgid.link/20251115134753.179931-2-yuntao.wang@linux.dev Signed-off-by: Rob Herring (Arm) Stable-dep-of: bec5f6092bc1 ("of/fdt: Fix the len check in early_init_dt_check_for_elfcorehdr()") Signed-off-by: Sasha Levin --- drivers/of/fdt.c | 41 +++++++++++++++++++++++++++++++++++++++++ include/linux/of_fdt.h | 9 +++++++++ 2 files changed, 50 insertions(+) diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index 0edd639898a63..0c18bdefbbeea 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -625,6 +625,47 @@ const void *__init of_get_flat_dt_prop(unsigned long node, const char *name, return fdt_getprop(initial_boot_params, node, name, size); } +const __be32 *__init of_flat_dt_get_addr_size_prop(unsigned long node, + const char *name, + int *entries) +{ + const __be32 *prop; + int len, elen = (dt_root_addr_cells + dt_root_size_cells) * sizeof(__be32); + + prop = of_get_flat_dt_prop(node, name, &len); + if (!prop || len % elen) { + *entries = 0; + return NULL; + } + + *entries = len / elen; + return prop; +} + +bool __init of_flat_dt_get_addr_size(unsigned long node, const char *name, + u64 *addr, u64 *size) +{ + const __be32 *prop; + int entries; + + prop = of_flat_dt_get_addr_size_prop(node, name, &entries); + if (!prop || entries != 1) + return false; + + of_flat_dt_read_addr_size(prop, 0, addr, size); + return true; +} + +void __init of_flat_dt_read_addr_size(const __be32 *prop, int entry_index, + u64 *addr, u64 *size) +{ + int entry_cells = dt_root_addr_cells + dt_root_size_cells; + prop += entry_cells * entry_index; + + *addr = dt_mem_next_cell(dt_root_addr_cells, &prop); + *size = dt_mem_next_cell(dt_root_size_cells, &prop); +} + /** * of_fdt_is_compatible - Return true if given node from the given blob has * compat in its compatible list diff --git a/include/linux/of_fdt.h b/include/linux/of_fdt.h index b8d6c0c208760..51dadbaa3d63a 100644 --- a/include/linux/of_fdt.h +++ b/include/linux/of_fdt.h @@ -55,6 +55,15 @@ extern int of_get_flat_dt_subnode_by_name(unsigned long node, const char *uname); extern const void *of_get_flat_dt_prop(unsigned long node, const char *name, int *size); + +extern const __be32 *of_flat_dt_get_addr_size_prop(unsigned long node, + const char *name, + int *entries); +extern bool of_flat_dt_get_addr_size(unsigned long node, const char *name, + u64 *addr, u64 *size); +extern void of_flat_dt_read_addr_size(const __be32 *prop, int entry_index, + u64 *addr, u64 *size); + extern int of_flat_dt_is_compatible(unsigned long node, const char *name); extern unsigned long of_get_flat_dt_root(void); extern uint32_t of_get_flat_dt_phandle(unsigned long node); From f326efdcab7f826ccd3a0a54cd737b7320444f10 Mon Sep 17 00:00:00 2001 From: Yuntao Wang Date: Sat, 15 Nov 2025 21:47:47 +0800 Subject: [PATCH 0716/2333] of/fdt: Fix the len check in early_init_dt_check_for_elfcorehdr() [ Upstream commit bec5f6092bc1328895992ff02b862ba34b45a0b7 ] The len value is in bytes, while `dt_root_addr_cells + dt_root_size_cells` is in cells (4 bytes per cell). Comparing them directly is incorrect. Use a helper function to simplify the code and address this issue. Fixes: f7e7ce93aac1 ("of: fdt: Add generic support for handling elf core headers property") Fixes: e62aaeac426ab1dd ("arm64: kdump: provide /proc/vmcore file") Signed-off-by: Yuntao Wang Link: https://patch.msgid.link/20251115134753.179931-3-yuntao.wang@linux.dev Signed-off-by: Rob Herring (Arm) Signed-off-by: Sasha Levin --- drivers/of/fdt.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index 0c18bdefbbeea..b45f60dccd7cf 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -853,21 +853,15 @@ static void __init early_init_dt_check_for_initrd(unsigned long node) */ static void __init early_init_dt_check_for_elfcorehdr(unsigned long node) { - const __be32 *prop; - int len; - if (!IS_ENABLED(CONFIG_CRASH_DUMP)) return; pr_debug("Looking for elfcorehdr property... "); - prop = of_get_flat_dt_prop(node, "linux,elfcorehdr", &len); - if (!prop || (len < (dt_root_addr_cells + dt_root_size_cells))) + if (!of_flat_dt_get_addr_size(node, "linux,elfcorehdr", + &elfcorehdr_addr, &elfcorehdr_size)) return; - elfcorehdr_addr = dt_mem_next_cell(dt_root_addr_cells, &prop); - elfcorehdr_size = dt_mem_next_cell(dt_root_size_cells, &prop); - pr_debug("elfcorehdr_start=0x%llx elfcorehdr_size=0x%llx\n", elfcorehdr_addr, elfcorehdr_size); } From 38c8c945c2c2b404e7203b36023d2aa0a888c617 Mon Sep 17 00:00:00 2001 From: Yuntao Wang Date: Sat, 15 Nov 2025 21:47:48 +0800 Subject: [PATCH 0717/2333] of/fdt: Fix the len check in early_init_dt_check_for_usable_mem_range() [ Upstream commit 463942de13cd30fad5dba709f708483eab7efc2c ] The len value is in bytes, while `dt_root_addr_cells + dt_root_size_cells` is in cells (4 bytes per cell). Modulo calculation between them is incorrect, the units must be converted first. Use helper functions to simplify the code and fix this issue. Fixes: fb319e77a0e7 ("of: fdt: Add memory for devices by DT property "linux,usable-memory-range"") Fixes: 2af2b50acf9b9c38 ("of: fdt: Add generic support for handling usable memory range property") Fixes: 8f579b1c4e347b23 ("arm64: limit memory regions based on DT property, usable-memory-range") Signed-off-by: Yuntao Wang Link: https://patch.msgid.link/20251115134753.179931-4-yuntao.wang@linux.dev Signed-off-by: Rob Herring (Arm) Signed-off-by: Sasha Levin --- drivers/of/fdt.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index b45f60dccd7cf..ea37ba694bcd7 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -884,8 +884,9 @@ static unsigned long chosen_node_offset = -FDT_ERR_NOTFOUND; void __init early_init_dt_check_for_usable_mem_range(void) { struct memblock_region rgn[MAX_USABLE_RANGES] = {0}; - const __be32 *prop, *endp; + const __be32 *prop; int len, i; + u64 base, size; unsigned long node = chosen_node_offset; if ((long)node < 0) @@ -893,14 +894,17 @@ void __init early_init_dt_check_for_usable_mem_range(void) pr_debug("Looking for usable-memory-range property... "); - prop = of_get_flat_dt_prop(node, "linux,usable-memory-range", &len); - if (!prop || (len % (dt_root_addr_cells + dt_root_size_cells))) + prop = of_flat_dt_get_addr_size_prop(node, "linux,usable-memory-range", + &len); + if (!prop) return; - endp = prop + (len / sizeof(__be32)); - for (i = 0; i < MAX_USABLE_RANGES && prop < endp; i++) { - rgn[i].base = dt_mem_next_cell(dt_root_addr_cells, &prop); - rgn[i].size = dt_mem_next_cell(dt_root_size_cells, &prop); + len = min(len, MAX_USABLE_RANGES); + + for (i = 0; i < len; i++) { + of_flat_dt_read_addr_size(prop, i, &base, &size); + rgn[i].base = base; + rgn[i].size = size; pr_debug("cap_mem_regions[%d]: base=%pa, size=%pa\n", i, &rgn[i].base, &rgn[i].size); From 0d8e2c04a2ec53d93cc327e12975f611e5df314b Mon Sep 17 00:00:00 2001 From: Yuntao Wang Date: Sat, 15 Nov 2025 21:47:49 +0800 Subject: [PATCH 0718/2333] of/fdt: Fix incorrect use of dt_root_addr_cells in early_init_dt_check_kho() [ Upstream commit c85da64ce2c36bba469f6feede9ca768f0361741 ] When reading the fdt_size value, the argument passed to dt_mem_next_cell() is dt_root_addr_cells, but it should be dt_root_size_cells. The same issue occurs when reading the scratch_size value. Use a helper function to simplify the code and fix these issues. Fixes: 274cdcb1c004 ("arm64: add KHO support") Signed-off-by: Yuntao Wang Link: https://patch.msgid.link/20251115134753.179931-5-yuntao.wang@linux.dev Signed-off-by: Rob Herring (Arm) Signed-off-by: Sasha Levin --- drivers/of/fdt.c | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index ea37ba694bcd7..fdaee4906836f 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -922,26 +922,18 @@ static void __init early_init_dt_check_kho(void) { unsigned long node = chosen_node_offset; u64 fdt_start, fdt_size, scratch_start, scratch_size; - const __be32 *p; - int l; if (!IS_ENABLED(CONFIG_KEXEC_HANDOVER) || (long)node < 0) return; - p = of_get_flat_dt_prop(node, "linux,kho-fdt", &l); - if (l != (dt_root_addr_cells + dt_root_size_cells) * sizeof(__be32)) + if (!of_flat_dt_get_addr_size(node, "linux,kho-fdt", + &fdt_start, &fdt_size)) return; - fdt_start = dt_mem_next_cell(dt_root_addr_cells, &p); - fdt_size = dt_mem_next_cell(dt_root_addr_cells, &p); - - p = of_get_flat_dt_prop(node, "linux,kho-scratch", &l); - if (l != (dt_root_addr_cells + dt_root_size_cells) * sizeof(__be32)) + if (!of_flat_dt_get_addr_size(node, "linux,kho-scratch", + &scratch_start, &scratch_size)) return; - scratch_start = dt_mem_next_cell(dt_root_addr_cells, &p); - scratch_size = dt_mem_next_cell(dt_root_addr_cells, &p); - kho_populate(fdt_start, fdt_size, scratch_start, scratch_size); } From ae5f4c7397d0b7627df176dc2f9ac45dfa4e5d86 Mon Sep 17 00:00:00 2001 From: Fenglin Wu Date: Wed, 19 Nov 2025 14:06:43 +0800 Subject: [PATCH 0719/2333] leds: rgb: leds-qcom-lpg: Don't enable TRILED when configuring PWM [ Upstream commit 072cd5f458d76b9e15d89ebdaea8b5cb1312eeef ] The PWM signal from the LPG channel can be routed to PMIC GPIOs with proper GPIO configuration, and it is not necessary to enable the TRILED channel in that case. This also applies to the LPG channels that mapped to TRILED channels. Additionally, enabling the TRILED channel unnecessarily would cause a voltage increase in its power supply. Hence remove it. Fixes: 24e2d05d1b68 ("leds: Add driver for Qualcomm LPG") Signed-off-by: Fenglin Wu Reviewed-by: Bjorn Andersson Link: https://patch.msgid.link/20251119-lpg_triled_fix-v3-2-84b6dbdc774a@oss.qualcomm.com Signed-off-by: Lee Jones Signed-off-by: Sasha Levin --- drivers/leds/rgb/leds-qcom-lpg.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/leds/rgb/leds-qcom-lpg.c b/drivers/leds/rgb/leds-qcom-lpg.c index 4f2a178e3d265..e197f548cddb0 100644 --- a/drivers/leds/rgb/leds-qcom-lpg.c +++ b/drivers/leds/rgb/leds-qcom-lpg.c @@ -2,7 +2,7 @@ /* * Copyright (c) 2017-2022 Linaro Ltd * Copyright (c) 2010-2012, The Linux Foundation. All rights reserved. - * Copyright (c) 2023-2024, Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include #include @@ -1247,8 +1247,6 @@ static int lpg_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, lpg_apply(chan); - triled_set(lpg, chan->triled_mask, chan->enabled ? chan->triled_mask : 0); - out_unlock: mutex_unlock(&lpg->lock); From 97525d3a7f8b66e5eddd27ab2509aca177103704 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Thu, 23 Oct 2025 16:58:05 +0300 Subject: [PATCH 0720/2333] phy: renesas: rcar-gen3-usb2: Fix an error handling path in rcar_gen3_phy_usb2_probe() [ Upstream commit 662bb179d3381c7c069e44bb177396bcaee31cc8 ] If an error occurs after the reset_control_deassert(), reset_control_assert() must be called, as already done in the remove function. Use devm_add_action_or_reset() to add the missing call and simplify the .remove() function accordingly. While at it, drop struct rcar_gen3_chan::rstc as it is not used aymore. [claudiu.beznea: removed "struct reset_control *rstc = data;" from rcar_gen3_reset_assert(), dropped struct rcar_gen3_chan::rstc] Fixes: 4eae16375357 ("phy: renesas: rcar-gen3-usb2: Add support to initialize the bus") Signed-off-by: Christophe JAILLET Reviewed-by: Biju Das Reviewed-by: Geert Uytterhoeven Tested-by: Wolfram Sang Signed-off-by: Claudiu Beznea Link: https://patch.msgid.link/20251023135810.1688415-3-claudiu.beznea.uj@bp.renesas.com Signed-off-by: Vinod Koul Signed-off-by: Sasha Levin --- drivers/phy/renesas/phy-rcar-gen3-usb2.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/drivers/phy/renesas/phy-rcar-gen3-usb2.c b/drivers/phy/renesas/phy-rcar-gen3-usb2.c index 3f6b480e10922..a38ead7c8055d 100644 --- a/drivers/phy/renesas/phy-rcar-gen3-usb2.c +++ b/drivers/phy/renesas/phy-rcar-gen3-usb2.c @@ -134,7 +134,6 @@ struct rcar_gen3_chan { struct extcon_dev *extcon; struct rcar_gen3_phy rphys[NUM_OF_PHYS]; struct regulator *vbus; - struct reset_control *rstc; struct work_struct work; spinlock_t lock; /* protects access to hardware and driver data structure. */ enum usb_dr_mode dr_mode; @@ -771,21 +770,31 @@ static enum usb_dr_mode rcar_gen3_get_dr_mode(struct device_node *np) return candidate; } +static void rcar_gen3_reset_assert(void *data) +{ + reset_control_assert(data); +} + static int rcar_gen3_phy_usb2_init_bus(struct rcar_gen3_chan *channel) { struct device *dev = channel->dev; + struct reset_control *rstc; int ret; u32 val; - channel->rstc = devm_reset_control_array_get_shared(dev); - if (IS_ERR(channel->rstc)) - return PTR_ERR(channel->rstc); + rstc = devm_reset_control_array_get_shared(dev); + if (IS_ERR(rstc)) + return PTR_ERR(rstc); ret = pm_runtime_resume_and_get(dev); if (ret) return ret; - ret = reset_control_deassert(channel->rstc); + ret = reset_control_deassert(rstc); + if (ret) + goto rpm_put; + + ret = devm_add_action_or_reset(dev, rcar_gen3_reset_assert, rstc); if (ret) goto rpm_put; @@ -924,7 +933,6 @@ static void rcar_gen3_phy_usb2_remove(struct platform_device *pdev) if (channel->is_otg_channel) device_remove_file(&pdev->dev, &dev_attr_role); - reset_control_assert(channel->rstc); pm_runtime_disable(&pdev->dev); }; From c6dda44381eded529d8366fcf3a32730c6dffe45 Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Tue, 18 Nov 2025 17:52:05 +0800 Subject: [PATCH 0721/2333] phy: rockchip: naneng-combphy: Fix PCIe L1ss support RK3528 [ Upstream commit a2a18e5da64f8da306fa97c397b4c739ea776f37 ] When PCIe link enters L1 PM substates, the PHY will turn off its PLL for power-saving. However, it turns off the PLL too fast which leads the PHY to be broken. According to the PHY document, we need to delay PLL turnoff time. Fixes: bbcca4fac873 ("phy: rockchip: naneng-combphy: Add RK3528 support") Signed-off-by: Shawn Lin Reviewed-by: Neil Armstrong Link: https://patch.msgid.link/1763459526-35004-1-git-send-email-shawn.lin@rock-chips.com Signed-off-by: Vinod Koul Signed-off-by: Sasha Levin --- drivers/phy/rockchip/phy-rockchip-naneng-combphy.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c b/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c index a3ef19807b9ef..e303bec8a996f 100644 --- a/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c +++ b/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c @@ -21,6 +21,9 @@ #define REF_CLOCK_100MHz (100 * HZ_PER_MHZ) /* RK3528 COMBO PHY REG */ +#define RK3528_PHYREG5 0x14 +#define RK3528_PHYREG5_GATE_TX_PCK_SEL BIT(3) +#define RK3528_PHYREG5_GATE_TX_PCK_DLY_PLL_OFF BIT(3) #define RK3528_PHYREG6 0x18 #define RK3528_PHYREG6_PLL_KVCO GENMASK(12, 10) #define RK3528_PHYREG6_PLL_KVCO_VALUE 0x2 @@ -504,6 +507,10 @@ static int rk3528_combphy_cfg(struct rockchip_combphy_priv *priv) case REF_CLOCK_100MHz: rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_clk_100m, true); if (priv->type == PHY_TYPE_PCIE) { + /* Gate_tx_pck_sel length select for L1ss support */ + rockchip_combphy_updatel(priv, RK3528_PHYREG5_GATE_TX_PCK_SEL, + RK3528_PHYREG5_GATE_TX_PCK_DLY_PLL_OFF, RK3528_PHYREG5); + /* PLL KVCO tuning fine */ val = FIELD_PREP(RK3528_PHYREG6_PLL_KVCO, RK3528_PHYREG6_PLL_KVCO_VALUE); rockchip_combphy_updatel(priv, RK3528_PHYREG6_PLL_KVCO, val, From b36ba24f7d6d8bc669456742f01103629c139629 Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Tue, 18 Nov 2025 17:52:06 +0800 Subject: [PATCH 0722/2333] phy: rockchip: naneng-combphy: Fix PCIe L1ss support RK3562 [ Upstream commit be866e68966d20bcc4a73708093d577176f99c0c ] When PCIe link enters L1 PM substates, the PHY will turn off its PLL for power-saving. However, it turns off the PLL too fast which leads the PHY to be broken. According to the PHY document, we need to delay PLL turnoff time. Fixes: f13bff25161b ("phy: rockchip-naneng-combo: Support rk3562") Signed-off-by: Shawn Lin Reviewed-by: Neil Armstrong Link: https://patch.msgid.link/1763459526-35004-2-git-send-email-shawn.lin@rock-chips.com Signed-off-by: Vinod Koul Signed-off-by: Sasha Levin --- drivers/phy/rockchip/phy-rockchip-naneng-combphy.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c b/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c index e303bec8a996f..7f8fc8e6d4890 100644 --- a/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c +++ b/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c @@ -106,6 +106,10 @@ #define RK3568_PHYREG18 0x44 #define RK3568_PHYREG18_PLL_LOOP 0x32 +#define RK3568_PHYREG30 0x74 +#define RK3568_PHYREG30_GATE_TX_PCK_SEL BIT(7) +#define RK3568_PHYREG30_GATE_TX_PCK_DLY_PLL_OFF BIT(7) + #define RK3568_PHYREG32 0x7C #define RK3568_PHYREG32_SSC_MASK GENMASK(7, 4) #define RK3568_PHYREG32_SSC_DIR_MASK GENMASK(5, 4) @@ -664,6 +668,10 @@ static int rk3562_combphy_cfg(struct rockchip_combphy_priv *priv) case REF_CLOCK_100MHz: rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_clk_100m, true); if (priv->type == PHY_TYPE_PCIE) { + /* Gate_tx_pck_sel length select for L1ss support */ + rockchip_combphy_updatel(priv, RK3568_PHYREG30_GATE_TX_PCK_SEL, + RK3568_PHYREG30_GATE_TX_PCK_DLY_PLL_OFF, + RK3568_PHYREG30); /* PLL KVCO tuning fine */ val = FIELD_PREP(RK3568_PHYREG33_PLL_KVCO_MASK, RK3568_PHYREG33_PLL_KVCO_VALUE); From a614c316a8c29ba35da15dad77155a972a04499e Mon Sep 17 00:00:00 2001 From: Xiaolei Wang Date: Thu, 25 Sep 2025 09:38:06 +0800 Subject: [PATCH 0723/2333] phy: freescale: Initialize priv->lock [ Upstream commit 95e5905698983df94069e185f9eb3c67c7cf75d5 ] Initialize priv->lock to fix the following warning. WARNING: CPU: 0 PID: 12 at kernel/locking/mutex.c:577 __mutex_lock+0x70c/0x8b8 Modules linked in: Hardware name: Freescale i.MX8QM MEK (DT) Call trace: __mutex_lock+0x70c/0x8b8 (P) mutex_lock_nested+0x24/0x30 imx_hsio_power_on+0x4c/0x764 phy_power_on+0x7c/0x12c imx_pcie_host_init+0x1d0/0x4d4 dw_pcie_host_init+0x188/0x4b0 imx_pcie_probe+0x324/0x6f4 platform_probe+0x5c/0x98 really_probe+0xbc/0x29c __driver_probe_device+0x78/0x12c driver_probe_device+0xd8/0x160 __device_attach_driver+0xb8/0x138 bus_for_each_drv+0x84/0xe4 __device_attach_async_helper+0xb8/0xdc async_run_entry_fn+0x34/0xe0 process_one_work+0x220/0x694 worker_thread+0x1c0/0x36c kthread+0x14c/0x224 Fixes: 82c56b6dd24f ("phy: freescale: imx8qm-hsio: Add i.MX8QM HSIO PHY driver support") Signed-off-by: Xiaolei Wang Reviewed-by: Frank Li Reviewed-by: Neil Armstrong Link: https://patch.msgid.link/20250925013806.569658-1-xiaolei.wang@windriver.com Signed-off-by: Vinod Koul Signed-off-by: Sasha Levin --- drivers/phy/freescale/phy-fsl-imx8qm-hsio.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/phy/freescale/phy-fsl-imx8qm-hsio.c b/drivers/phy/freescale/phy-fsl-imx8qm-hsio.c index 5dca93cd325c8..977d21d753a59 100644 --- a/drivers/phy/freescale/phy-fsl-imx8qm-hsio.c +++ b/drivers/phy/freescale/phy-fsl-imx8qm-hsio.c @@ -533,7 +533,7 @@ static struct phy *imx_hsio_xlate(struct device *dev, static int imx_hsio_probe(struct platform_device *pdev) { - int i; + int i, ret; void __iomem *off; struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; @@ -545,6 +545,9 @@ static int imx_hsio_probe(struct platform_device *pdev) return -ENOMEM; priv->dev = &pdev->dev; priv->drvdata = of_device_get_match_data(dev); + ret = devm_mutex_init(dev, &priv->lock); + if (ret) + return ret; /* Get HSIO configuration mode */ if (of_property_read_string(np, "fsl,hsio-cfg", &priv->hsio_cfg)) From 26efe0db47e5c07a5e6db10391422b71d1272c8e Mon Sep 17 00:00:00 2001 From: Cristian Ciocaltea Date: Tue, 28 Oct 2025 10:00:54 +0200 Subject: [PATCH 0724/2333] phy: rockchip: samsung-hdptx: Fix reported clock rate in high bpc mode [ Upstream commit 72126e9623e1696ea83c77ef6d0306a6263bdd6b ] When making use of the clock provider functionality, the output clock does normally match the TMDS character rate, which is what the PHY PLL gets configured to. However, this is only applicable for default color depth of 8 bpc. For higher depths, the output clock is further divided by the hardware according to the formula: output_clock_rate = tmds_char_rate * 8 / bpc Since the existence of the clock divider wasn't taken into account when support for high bpc has been introduced, make the necessary adjustments to report the correct clock rate. Fixes: 9d0ec51d7c22 ("phy: rockchip: samsung-hdptx: Add high color depth management") Reported-by: Andy Yan Signed-off-by: Cristian Ciocaltea Reviewed-by: Neil Armstrong Link: https://patch.msgid.link/20251028-phy-hdptx-fixes-v1-1-ecc642a59d94@collabora.com Signed-off-by: Vinod Koul Signed-off-by: Sasha Levin --- drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c index 01bbf668e05ef..aee03e8655f66 100644 --- a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c +++ b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c @@ -1037,7 +1037,8 @@ static int rk_hdptx_ropll_tmds_cmn_config(struct rk_hdptx_phy *hdptx) ret = rk_hdptx_post_enable_pll(hdptx); if (!ret) - hdptx->hw_rate = hdptx->hdmi_cfg.tmds_char_rate; + hdptx->hw_rate = DIV_ROUND_CLOSEST_ULL(hdptx->hdmi_cfg.tmds_char_rate * 8, + hdptx->hdmi_cfg.bpc); return ret; } @@ -1895,19 +1896,20 @@ static long rk_hdptx_phy_clk_round_rate(struct clk_hw *hw, unsigned long rate, * hence ensure rk_hdptx_phy_clk_set_rate() won't be invoked with * a different rate argument. */ - return hdptx->hdmi_cfg.tmds_char_rate; + return DIV_ROUND_CLOSEST_ULL(hdptx->hdmi_cfg.tmds_char_rate * 8, hdptx->hdmi_cfg.bpc); } static int rk_hdptx_phy_clk_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) { struct rk_hdptx_phy *hdptx = to_rk_hdptx_phy(hw); + unsigned long long tmds_rate = DIV_ROUND_CLOSEST_ULL(rate * hdptx->hdmi_cfg.bpc, 8); /* Revert any unlikely TMDS char rate change since round_rate() */ - if (hdptx->hdmi_cfg.tmds_char_rate != rate) { - dev_warn(hdptx->dev, "Reverting unexpected rate change from %lu to %llu\n", - rate, hdptx->hdmi_cfg.tmds_char_rate); - hdptx->hdmi_cfg.tmds_char_rate = rate; + if (hdptx->hdmi_cfg.tmds_char_rate != tmds_rate) { + dev_warn(hdptx->dev, "Reverting unexpected rate change from %llu to %llu\n", + tmds_rate, hdptx->hdmi_cfg.tmds_char_rate); + hdptx->hdmi_cfg.tmds_char_rate = tmds_rate; } /* From 348c9b3d47a65081f47d74b49569ef28c903ac98 Mon Sep 17 00:00:00 2001 From: Cristian Ciocaltea Date: Tue, 28 Oct 2025 10:00:55 +0200 Subject: [PATCH 0725/2333] phy: rockchip: samsung-hdptx: Reduce ROPLL loop bandwidth [ Upstream commit 8daaced9f5eeb4a2c8ca08b0a8286b6a498a8387 ] Due to its relatively low frequency, a noise stemming from the 24MHz PLL reference clock may traverse the low-pass loop filter of ROPLL, which could potentially generate some HDMI flash artifacts. Reduce ROPLL loop bandwidth in an attempt to mitigate the problem. Fixes: 553be2830c5f ("phy: rockchip: Add Samsung HDMI/eDP Combo PHY driver") Co-developed-by: Algea Cao Signed-off-by: Algea Cao Signed-off-by: Cristian Ciocaltea Reviewed-by: Neil Armstrong Link: https://patch.msgid.link/20251028-phy-hdptx-fixes-v1-2-ecc642a59d94@collabora.com Signed-off-by: Vinod Koul Signed-off-by: Sasha Levin --- drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c index aee03e8655f66..8ba9b53c2309b 100644 --- a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c +++ b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c @@ -500,9 +500,7 @@ static const struct reg_sequence rk_hdtpx_common_cmn_init_seq[] = { REG_SEQ0(CMN_REG(0043), 0x00), REG_SEQ0(CMN_REG(0044), 0x46), REG_SEQ0(CMN_REG(0045), 0x24), - REG_SEQ0(CMN_REG(0046), 0xff), REG_SEQ0(CMN_REG(0047), 0x00), - REG_SEQ0(CMN_REG(0048), 0x44), REG_SEQ0(CMN_REG(0049), 0xfa), REG_SEQ0(CMN_REG(004a), 0x08), REG_SEQ0(CMN_REG(004b), 0x00), @@ -575,6 +573,8 @@ static const struct reg_sequence rk_hdtpx_tmds_cmn_init_seq[] = { REG_SEQ0(CMN_REG(0034), 0x00), REG_SEQ0(CMN_REG(003d), 0x40), REG_SEQ0(CMN_REG(0042), 0x78), + REG_SEQ0(CMN_REG(0046), 0xdd), + REG_SEQ0(CMN_REG(0048), 0x11), REG_SEQ0(CMN_REG(004e), 0x34), REG_SEQ0(CMN_REG(005c), 0x25), REG_SEQ0(CMN_REG(005e), 0x4f), From fd6835c98ea6669d7422d40b96a3710fa9157629 Mon Sep 17 00:00:00 2001 From: Cristian Ciocaltea Date: Tue, 28 Oct 2025 10:00:56 +0200 Subject: [PATCH 0726/2333] phy: rockchip: samsung-hdptx: Prevent Inter-Pair Skew from exceeding the limits [ Upstream commit 51023cf6cc5db3423dea6620746d9087e336e024 ] Fixup PHY deskew FIFO to prevent the phase of D2 lane going ahead of other lanes. It's worth noting this might only happen when dealing with HDMI 2.0 rates. Fixes: 553be2830c5f ("phy: rockchip: Add Samsung HDMI/eDP Combo PHY driver") Co-developed-by: Algea Cao Signed-off-by: Algea Cao Signed-off-by: Cristian Ciocaltea Reviewed-by: Neil Armstrong Link: https://patch.msgid.link/20251028-phy-hdptx-fixes-v1-3-ecc642a59d94@collabora.com Signed-off-by: Vinod Koul Signed-off-by: Sasha Levin --- drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c index 8ba9b53c2309b..29de2f7bdae8a 100644 --- a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c +++ b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c @@ -668,13 +668,9 @@ static const struct reg_sequence rk_hdtpx_common_lane_init_seq[] = { static const struct reg_sequence rk_hdtpx_tmds_lane_init_seq[] = { REG_SEQ0(LANE_REG(0312), 0x00), - REG_SEQ0(LANE_REG(031e), 0x00), REG_SEQ0(LANE_REG(0412), 0x00), - REG_SEQ0(LANE_REG(041e), 0x00), REG_SEQ0(LANE_REG(0512), 0x00), - REG_SEQ0(LANE_REG(051e), 0x00), REG_SEQ0(LANE_REG(0612), 0x00), - REG_SEQ0(LANE_REG(061e), 0x08), REG_SEQ0(LANE_REG(0303), 0x2f), REG_SEQ0(LANE_REG(0403), 0x2f), REG_SEQ0(LANE_REG(0503), 0x2f), @@ -687,6 +683,11 @@ static const struct reg_sequence rk_hdtpx_tmds_lane_init_seq[] = { REG_SEQ0(LANE_REG(0406), 0x1c), REG_SEQ0(LANE_REG(0506), 0x1c), REG_SEQ0(LANE_REG(0606), 0x1c), + /* Keep Inter-Pair Skew in the limits */ + REG_SEQ0(LANE_REG(031e), 0x02), + REG_SEQ0(LANE_REG(041e), 0x02), + REG_SEQ0(LANE_REG(051e), 0x02), + REG_SEQ0(LANE_REG(061e), 0x0a), }; static struct tx_drv_ctrl tx_drv_ctrl_rbr[4][4] = { From 340a73d8b6647a8e2404247cd0207337beb945c0 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Thu, 20 Nov 2025 15:30:11 +0000 Subject: [PATCH 0727/2333] ASoC: SDCA: Fix missing dash in HIDE DisCo property [ Upstream commit 3508311f2e1c872b645f13c6fd52840418089d41 ] The property name is "mipi-sdca-RxUMP-ownership-transition-max-delay", with a dash between max and delay. Add the missing dash. Fixes: 13ef21dffe76 ("ASoC: SDCA: add support for HIDE entity properties and HID descriptor/report") Tested-by: Bard Liao Reviewed-by: Maciej Strozek Reviewed-by: Peter Ujfalusi Tested-by: Richard Fitzgerald Signed-off-by: Charles Keepax Link: https://patch.msgid.link/20251120153023.2105663-3-ckeepax@opensource.cirrus.com Reviewed-by: Vinod Koul Signed-off-by: Mark Brown Signed-off-by: Sasha Levin --- sound/soc/sdca/sdca_functions.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sdca/sdca_functions.c b/sound/soc/sdca/sdca_functions.c index 0ccb6775f4de3..19b12564f822e 100644 --- a/sound/soc/sdca/sdca_functions.c +++ b/sound/soc/sdca/sdca_functions.c @@ -1263,7 +1263,7 @@ find_sdca_entity_hide(struct device *dev, struct fwnode_handle *function_node, unsigned char *report_desc = NULL; ret = fwnode_property_read_u32(entity_node, - "mipi-sdca-RxUMP-ownership-transition-maxdelay", &delay); + "mipi-sdca-RxUMP-ownership-transition-max-delay", &delay); if (!ret) hide->max_delay = delay; From 59bea0e26b8cf54b3db89e0ef0de2c90696fd5a3 Mon Sep 17 00:00:00 2001 From: Matt Bobrowski Date: Tue, 18 Nov 2025 07:37:34 +0000 Subject: [PATCH 0728/2333] selftests/bpf: Use ASSERT_STRNEQ to factor in long slab cache names [ Upstream commit d088da904223e8f5e19c6d156cf372d5baec1a7c ] subtest_kmem_cache_iter_check_slabinfo() fundamentally compares slab cache names parsed out from /proc/slabinfo against those stored within struct kmem_cache_result. The current problem is that the slab cache name within struct kmem_cache_result is stored within a bounded fixed-length array (sized to SLAB_NAME_MAX(32)), whereas the name parsed out from /proc/slabinfo is not. Meaning, using ASSERT_STREQ() can certainly lead to test failures, particularly when dealing with slab cache names that are longer than SLAB_NAME_MAX(32) bytes. Notably, kmem_cache_create() allows callers to create slab caches with somewhat arbitrarily sized names via its __name identifier argument, so exceeding the SLAB_NAME_MAX(32) limit that is in place now can certainly happen. Make subtest_kmem_cache_iter_check_slabinfo() more reliable by only checking up to sizeof(struct kmem_cache_result.name) - 1 using ASSERT_STRNEQ(). Fixes: a496d0cdc84d ("selftests/bpf: Add a test for kmem_cache_iter") Signed-off-by: Matt Bobrowski Signed-off-by: Martin KaFai Lau Acked-by: Song Liu Link: https://patch.msgid.link/20251118073734.4188710-1-mattbobrowski@google.com Signed-off-by: Sasha Levin --- tools/testing/selftests/bpf/prog_tests/kmem_cache_iter.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/bpf/prog_tests/kmem_cache_iter.c b/tools/testing/selftests/bpf/prog_tests/kmem_cache_iter.c index 1de14b111931a..6e35e13c20220 100644 --- a/tools/testing/selftests/bpf/prog_tests/kmem_cache_iter.c +++ b/tools/testing/selftests/bpf/prog_tests/kmem_cache_iter.c @@ -57,7 +57,8 @@ static void subtest_kmem_cache_iter_check_slabinfo(struct kmem_cache_iter *skel) if (!ASSERT_OK(ret, "kmem_cache_lookup")) break; - ASSERT_STREQ(r.name, name, "kmem_cache_name"); + ASSERT_STRNEQ(r.name, name, sizeof(r.name) - 1, + "kmem_cache_name"); ASSERT_EQ(r.obj_size, objsize, "kmem_cache_objsize"); seen++; From 872b3ffc5107b7486364efd9e213b8ed866d4179 Mon Sep 17 00:00:00 2001 From: Alexander Dahl Date: Wed, 19 Nov 2025 13:47:36 +0100 Subject: [PATCH 0729/2333] net: phy: adin1100: Fix software power-down ready condition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit bccaf1fe08f2c9f96f6bc38391d41e67f6bf38e3 ] Value CRSM_SFT_PD written to Software Power-Down Control Register (CRSM_SFT_PD_CNTRL) is 0x01 and therefor different to value CRSM_SFT_PD_RDY (0x02) read from System Status Register (CRSM_STAT) for confirmation powerdown has been reached. The condition could have only worked when disabling powerdown (both 0x00), but never when enabling it (0x01 != 0x02). Result is a timeout, like so: $ ifdown eth0 macb f802c000.ethernet eth0: Link is Down ADIN1100 f802c000.ethernet-ffffffff:01: adin_set_powerdown_mode failed: -110 ADIN1100 f802c000.ethernet-ffffffff:01: adin_set_powerdown_mode failed: -110 Fixes: 7eaf9132996a ("net: phy: adin1100: Add initial support for ADIN1100 industrial PHY") Signed-off-by: Alexander Dahl Reviewed-by: Russell King (Oracle) Acked-by: Nuno Sá Link: https://patch.msgid.link/20251119124737.280939-2-ada@thorsis.com Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- drivers/net/phy/adin1100.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/phy/adin1100.c b/drivers/net/phy/adin1100.c index bd7a47a903aca..10b796c2daee7 100644 --- a/drivers/net/phy/adin1100.c +++ b/drivers/net/phy/adin1100.c @@ -201,7 +201,7 @@ static int adin_set_powerdown_mode(struct phy_device *phydev, bool en) return ret; return phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1, ADIN_CRSM_STAT, ret, - (ret & ADIN_CRSM_SFT_PD_RDY) == val, + !!(ret & ADIN_CRSM_SFT_PD_RDY) == en, 1000, 30000, true); } From 04c79e05e13ce3cff44c4c4af8e8aa25e5086484 Mon Sep 17 00:00:00 2001 From: Chen Ridong Date: Fri, 14 Nov 2025 02:08:47 +0000 Subject: [PATCH 0730/2333] cpuset: Treat cpusets in attaching as populated [ Upstream commit b1bcaed1e39a9e0dfbe324a15d2ca4253deda316 ] Currently, the check for whether a partition is populated does not account for tasks in the cpuset of attaching. This is a corner case that can leave a task stuck in a partition with no effective CPUs. The race condition occurs as follows: cpu0 cpu1 //cpuset A with cpu N migrate task p to A cpuset_can_attach // with effective cpus // check ok // cpuset_mutex is not held // clear cpuset.cpus.exclusive // making effective cpus empty update_exclusive_cpumask // tasks_nocpu_error check ok // empty effective cpus, partition valid cpuset_attach ... // task p stays in A, with non-effective cpus. To fix this issue, this patch introduces cs_is_populated, which considers tasks in the attaching cpuset. This new helper is used in validate_change and partition_is_populated. Fixes: e2d59900d936 ("cgroup/cpuset: Allow no-task partition to have empty cpuset.cpus.effective") Signed-off-by: Chen Ridong Reviewed-by: Waiman Long Signed-off-by: Tejun Heo Signed-off-by: Sasha Levin --- kernel/cgroup/cpuset.c | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c index 52468d2c178a3..4dcd633fd6df5 100644 --- a/kernel/cgroup/cpuset.c +++ b/kernel/cgroup/cpuset.c @@ -352,6 +352,15 @@ static inline bool is_in_v2_mode(void) (cpuset_cgrp_subsys.root->flags & CGRP_ROOT_CPUSET_V2_MODE); } +static inline bool cpuset_is_populated(struct cpuset *cs) +{ + lockdep_assert_held(&cpuset_mutex); + + /* Cpusets in the process of attaching should be considered as populated */ + return cgroup_is_populated(cs->css.cgroup) || + cs->attach_in_progress; +} + /** * partition_is_populated - check if partition has tasks * @cs: partition root to be checked @@ -364,21 +373,31 @@ static inline bool is_in_v2_mode(void) static inline bool partition_is_populated(struct cpuset *cs, struct cpuset *excluded_child) { - struct cgroup_subsys_state *css; - struct cpuset *child; + struct cpuset *cp; + struct cgroup_subsys_state *pos_css; - if (cs->css.cgroup->nr_populated_csets) + /* + * We cannot call cs_is_populated(cs) directly, as + * nr_populated_domain_children may include populated + * csets from descendants that are partitions. + */ + if (cs->css.cgroup->nr_populated_csets || + cs->attach_in_progress) return true; if (!excluded_child && !cs->nr_subparts) return cgroup_is_populated(cs->css.cgroup); rcu_read_lock(); - cpuset_for_each_child(child, css, cs) { - if (child == excluded_child) + cpuset_for_each_descendant_pre(cp, pos_css, cs) { + if (cp == cs || cp == excluded_child) continue; - if (is_partition_valid(child)) + + if (is_partition_valid(cp)) { + pos_css = css_rightmost_descendant(pos_css); continue; - if (cgroup_is_populated(child->css.cgroup)) { + } + + if (cpuset_is_populated(cp)) { rcu_read_unlock(); return true; } @@ -663,7 +682,7 @@ static int validate_change(struct cpuset *cur, struct cpuset *trial) * be changed to have empty cpus_allowed or mems_allowed. */ ret = -ENOSPC; - if ((cgroup_is_populated(cur->css.cgroup) || cur->attach_in_progress)) { + if (cpuset_is_populated(cur)) { if (!cpumask_empty(cur->cpus_allowed) && cpumask_empty(trial->cpus_allowed)) goto out; From ee5b0b28c9938b1cc88f23842aedef86e617e18b Mon Sep 17 00:00:00 2001 From: Charles Mirabile Date: Mon, 17 Nov 2025 14:03:29 -0500 Subject: [PATCH 0731/2333] clk: spacemit: Set clk_hw_onecell_data::num before using flex array [ Upstream commit 23b2d2fb136959fd0a8e309c70be83d9b8841c7e ] When booting with KASAN enabled the following splat is encountered during probe of the k1 clock driver: UBSAN: array-index-out-of-bounds in drivers/clk/spacemit/ccu-k1.c:1044:16 index 0 is out of range for type 'clk_hw *[*]' CPU: 0 UID: 0 PID: 1 Comm: swapper/0 Not tainted 6.18.0-rc5+ #1 PREEMPT(lazy) Hardware name: Unknown Unknown Product/Unknown Product, BIOS 2022.10spacemit 10/01/2022 Call Trace: [] dump_backtrace+0x28/0x38 [] show_stack+0x3a/0x50 [] dump_stack_lvl+0x5a/0x80 [] dump_stack+0x18/0x20 [] ubsan_epilogue+0x10/0x48 [] __ubsan_handle_out_of_bounds+0xa6/0xa8 [] k1_ccu_probe+0x37e/0x420 [] platform_probe+0x56/0x98 [] really_probe+0x9e/0x350 [] __driver_probe_device+0x80/0x138 [] driver_probe_device+0x3a/0xd0 [] __driver_attach+0xac/0x1b8 [] bus_for_each_dev+0x6c/0xc8 [] driver_attach+0x26/0x38 [] bus_add_driver+0x13e/0x268 [] driver_register+0x52/0x100 [] __platform_driver_register+0x28/0x38 [] k1_ccu_driver_init+0x22/0x38 [] do_one_initcall+0x62/0x2a0 [] do_initcalls+0x170/0x1a8 [] kernel_init_freeable+0x16a/0x1e0 [] kernel_init+0x2c/0x180 [] ret_from_fork_kernel+0x16/0x1d8 [] ret_from_fork_kernel_asm+0x16/0x18 ---[ end trace ]--- This is bogus and is simply a result of KASAN consulting the `.num` member of the struct for bounds information (as it should due to `__counted_by`) and finding 0 set by kzalloc() because it has not been initialized before the loop that fills in the array. The easy fix is to just move the line that sets `num` to before the loop that fills the array so that KASAN has the information it needs to accurately conclude that the access is valid. Fixes: 1b72c59db0add ("clk: spacemit: Add clock support for SpacemiT K1 SoC") Tested-by: Yanko Kaneti Signed-off-by: Charles Mirabile Reviewed-by: Alex Elder Reviewed-by: Troy Mitchell Reviewed-by: Yixun Lan Signed-off-by: Stephen Boyd Signed-off-by: Sasha Levin --- drivers/clk/spacemit/ccu-k1.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/clk/spacemit/ccu-k1.c b/drivers/clk/spacemit/ccu-k1.c index f5a9fe6ba1859..4761bc1e3b6e6 100644 --- a/drivers/clk/spacemit/ccu-k1.c +++ b/drivers/clk/spacemit/ccu-k1.c @@ -1018,6 +1018,8 @@ static int spacemit_ccu_register(struct device *dev, if (!clk_data) return -ENOMEM; + clk_data->num = data->num; + for (i = 0; i < data->num; i++) { struct clk_hw *hw = data->hws[i]; struct ccu_common *common; @@ -1044,8 +1046,6 @@ static int spacemit_ccu_register(struct device *dev, clk_data->hws[i] = hw; } - clk_data->num = data->num; - ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, clk_data); if (ret) dev_err(dev, "failed to add clock hardware provider (%d)\n", ret); From 5ebf0fe7eaef9f6173a4c6ea77c5353e21645d15 Mon Sep 17 00:00:00 2001 From: Seungjin Bae Date: Mon, 17 Nov 2025 20:32:59 -0500 Subject: [PATCH 0732/2333] wifi: rtl818x: rtl8187: Fix potential buffer underflow in rtl8187_rx_cb() [ Upstream commit b647d2574e4583c2e3b0ab35568f60c88e910840 ] The rtl8187_rx_cb() calculates the rx descriptor header address by subtracting its size from the skb tail pointer. However, it does not validate if the received packet (skb->len from urb->actual_length) is large enough to contain this header. If a truncated packet is received, this will lead to a buffer underflow, reading memory before the start of the skb data area, and causing a kernel panic. Add length checks for both rtl8187 and rtl8187b descriptor headers before attempting to access them, dropping the packet cleanly if the check fails. Fixes: 6f7853f3cbe4 ("rtl8187: change rtl8187_dev.c to support RTL8187B (part 2)") Signed-off-by: Seungjin Bae Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20251118013258.1789949-2-eeodqql09@gmail.com Signed-off-by: Sasha Levin --- .../wireless/realtek/rtl818x/rtl8187/dev.c | 27 +++++++++++++------ 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c b/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c index 0c5c66401daa6..7aa2da0cd63cc 100644 --- a/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c +++ b/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c @@ -338,14 +338,16 @@ static void rtl8187_rx_cb(struct urb *urb) spin_unlock_irqrestore(&priv->rx_queue.lock, f); skb_put(skb, urb->actual_length); - if (unlikely(urb->status)) { - dev_kfree_skb_irq(skb); - return; - } + if (unlikely(urb->status)) + goto free_skb; if (!priv->is_rtl8187b) { - struct rtl8187_rx_hdr *hdr = - (typeof(hdr))(skb_tail_pointer(skb) - sizeof(*hdr)); + struct rtl8187_rx_hdr *hdr; + + if (skb->len < sizeof(struct rtl8187_rx_hdr)) + goto free_skb; + + hdr = (typeof(hdr))(skb_tail_pointer(skb) - sizeof(*hdr)); flags = le32_to_cpu(hdr->flags); /* As with the RTL8187B below, the AGC is used to calculate * signal strength. In this case, the scaling @@ -355,8 +357,12 @@ static void rtl8187_rx_cb(struct urb *urb) rx_status.antenna = (hdr->signal >> 7) & 1; rx_status.mactime = le64_to_cpu(hdr->mac_time); } else { - struct rtl8187b_rx_hdr *hdr = - (typeof(hdr))(skb_tail_pointer(skb) - sizeof(*hdr)); + struct rtl8187b_rx_hdr *hdr; + + if (skb->len < sizeof(struct rtl8187b_rx_hdr)) + goto free_skb; + + hdr = (typeof(hdr))(skb_tail_pointer(skb) - sizeof(*hdr)); /* The Realtek datasheet for the RTL8187B shows that the RX * header contains the following quantities: signal quality, * RSSI, AGC, the received power in dB, and the measured SNR. @@ -409,6 +415,11 @@ static void rtl8187_rx_cb(struct urb *urb) skb_unlink(skb, &priv->rx_queue); dev_kfree_skb_irq(skb); } + return; + +free_skb: + dev_kfree_skb_irq(skb); + return; } static int rtl8187_init_urbs(struct ieee80211_hw *dev) From 22b5096abc9824fb84f0bfe084f5be9f7ea5f2d9 Mon Sep 17 00:00:00 2001 From: Jason Tian Date: Thu, 14 Aug 2025 09:52:52 -0700 Subject: [PATCH 0733/2333] RAS: Report all ARM processor CPER information to userspace [ Upstream commit 05954511b73e748d0370549ad9dd9cd95297d97a ] The ARM processor CPER record was added in UEFI v2.6 and remained unchanged up to v2.10. Yet, the original arm_event trace code added by e9279e83ad1f ("trace, ras: add ARM processor error trace event") is incomplete, as it only traces some fields of UAPI 2.6 table N.16, not exporting any information from tables N.17 to N.29 of the record. This is not enough for the user to be able to figure out what has exactly happened or to take appropriate action. According to the UEFI v2.9 specification chapter N2.4.4, the ARM processor error section includes: - several (ERR_INFO_NUM) ARM processor error information structures (Tables N.17 to N.20); - several (CONTEXT_INFO_NUM) ARM processor context information structures (Tables N.21 to N.29); - several vendor specific error information structures. The size is given by Section Length minus the size of the other fields. In addition, it also exports two fields that are parsed by the GHES driver when firmware reports it, e.g.: - error severity - CPU logical index Report all of these information to userspace via a the ARM tracepoint so that userspace can properly record the error and take decisions related to CPU core isolation according to error severity and other info. The updated ARM trace event now contains the following fields: ====================================== ============================= UEFI field on table N.16 ARM Processor trace fields ====================================== ============================= Validation handled when filling data for affinity MPIDR and running state. ERR_INFO_NUM pei_len CONTEXT_INFO_NUM ctx_len Section Length indirectly reported by pei_len, ctx_len and oem_len Error affinity level affinity MPIDR_EL1 mpidr MIDR_EL1 midr Running State running_state PSCI State psci_state Processor Error Information Structure pei_err - count at pei_len Processor Context ctx_err- count at ctx_len Vendor Specific Error Info oem - count at oem_len ====================================== ============================= It should be noted that decoding of tables N.17 to N.29, if needed, will be handled in userspace. That gives more flexibility, as there won't be any need to flood the kernel with micro-architecture specific error decoding. Also, decoding the other fields require a complex logic, and should be done for each of the several values inside the record field. So, let userspace daemons like rasdaemon decode them, parsing such tables and having vendor-specific micro-architecture-specific decoders. [mchehab: modified description, solved merge conflicts and fixed coding style] Signed-off-by: Jason Tian Co-developed-by: Shengwei Luo Signed-off-by: Shengwei Luo Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Daniel Ferguson # rebased Reviewed-by: Jonathan Cameron Tested-by: Shiju Jose Acked-by: Borislav Petkov (AMD) Fixes: e9279e83ad1f ("trace, ras: add ARM processor error trace event") Link: https://uefi.org/specs/UEFI/2.10/Apx_N_Common_Platform_Error_Record.html#arm-processor-error-section Signed-off-by: Ard Biesheuvel Signed-off-by: Sasha Levin --- drivers/acpi/apei/ghes.c | 11 ++++----- drivers/ras/ras.c | 40 ++++++++++++++++++++++++++++++-- include/linux/ras.h | 16 ++++++++++--- include/ras/ras_event.h | 49 ++++++++++++++++++++++++++++++++++++---- 4 files changed, 99 insertions(+), 17 deletions(-) diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c index 97ee19f2cae06..7d2466b515046 100644 --- a/drivers/acpi/apei/ghes.c +++ b/drivers/acpi/apei/ghes.c @@ -552,7 +552,7 @@ static bool ghes_handle_memory_failure(struct acpi_hest_generic_data *gdata, } static bool ghes_handle_arm_hw_error(struct acpi_hest_generic_data *gdata, - int sev, bool sync) + int sev, bool sync) { struct cper_sec_proc_arm *err = acpi_hest_get_payload(gdata); int flags = sync ? MF_ACTION_REQUIRED : 0; @@ -560,9 +560,8 @@ static bool ghes_handle_arm_hw_error(struct acpi_hest_generic_data *gdata, int sec_sev, i; char *p; - log_arm_hw_error(err); - sec_sev = ghes_severity(gdata->error_severity); + log_arm_hw_error(err, sec_sev); if (sev != GHES_SEV_RECOVERABLE || sec_sev != GHES_SEV_RECOVERABLE) return false; @@ -895,11 +894,9 @@ static void ghes_do_proc(struct ghes *ghes, arch_apei_report_mem_error(sev, mem_err); queued = ghes_handle_memory_failure(gdata, sev, sync); - } - else if (guid_equal(sec_type, &CPER_SEC_PCIE)) { + } else if (guid_equal(sec_type, &CPER_SEC_PCIE)) { ghes_handle_aer(gdata); - } - else if (guid_equal(sec_type, &CPER_SEC_PROC_ARM)) { + } else if (guid_equal(sec_type, &CPER_SEC_PROC_ARM)) { queued = ghes_handle_arm_hw_error(gdata, sev, sync); } else if (guid_equal(sec_type, &CPER_SEC_CXL_PROT_ERR)) { struct cxl_cper_sec_prot_err *prot_err = acpi_hest_get_payload(gdata); diff --git a/drivers/ras/ras.c b/drivers/ras/ras.c index ac0e132ccc3eb..2a5b5a9fdcb36 100644 --- a/drivers/ras/ras.c +++ b/drivers/ras/ras.c @@ -53,9 +53,45 @@ void log_non_standard_event(const guid_t *sec_type, const guid_t *fru_id, } EXPORT_SYMBOL_GPL(log_non_standard_event); -void log_arm_hw_error(struct cper_sec_proc_arm *err) +void log_arm_hw_error(struct cper_sec_proc_arm *err, const u8 sev) { - trace_arm_event(err); + struct cper_arm_err_info *err_info; + struct cper_arm_ctx_info *ctx_info; + u8 *ven_err_data; + u32 ctx_len = 0; + int n, sz, cpu; + s32 vsei_len; + u32 pei_len; + u8 *pei_err, *ctx_err; + + pei_len = sizeof(struct cper_arm_err_info) * err->err_info_num; + pei_err = (u8 *)(err + 1); + + err_info = (struct cper_arm_err_info *)(err + 1); + ctx_info = (struct cper_arm_ctx_info *)(err_info + err->err_info_num); + ctx_err = (u8 *)ctx_info; + + for (n = 0; n < err->context_info_num; n++) { + sz = sizeof(struct cper_arm_ctx_info) + ctx_info->size; + ctx_info = (struct cper_arm_ctx_info *)((long)ctx_info + sz); + ctx_len += sz; + } + + vsei_len = err->section_length - (sizeof(struct cper_sec_proc_arm) + pei_len + ctx_len); + if (vsei_len < 0) { + pr_warn(FW_BUG "section length: %d\n", err->section_length); + pr_warn(FW_BUG "section length is too small\n"); + pr_warn(FW_BUG "firmware-generated error record is incorrect\n"); + vsei_len = 0; + } + ven_err_data = (u8 *)ctx_info; + + cpu = GET_LOGICAL_INDEX(err->mpidr); + if (cpu < 0) + cpu = -1; + + trace_arm_event(err, pei_err, pei_len, ctx_err, ctx_len, + ven_err_data, (u32)vsei_len, sev, cpu); } static int __init ras_init(void) diff --git a/include/linux/ras.h b/include/linux/ras.h index a64182bc72ad3..468941bfe855f 100644 --- a/include/linux/ras.h +++ b/include/linux/ras.h @@ -24,8 +24,7 @@ int __init parse_cec_param(char *str); void log_non_standard_event(const guid_t *sec_type, const guid_t *fru_id, const char *fru_text, const u8 sev, const u8 *err, const u32 len); -void log_arm_hw_error(struct cper_sec_proc_arm *err); - +void log_arm_hw_error(struct cper_sec_proc_arm *err, const u8 sev); #else static inline void log_non_standard_event(const guid_t *sec_type, @@ -33,7 +32,7 @@ log_non_standard_event(const guid_t *sec_type, const u8 sev, const u8 *err, const u32 len) { return; } static inline void -log_arm_hw_error(struct cper_sec_proc_arm *err) { return; } +log_arm_hw_error(struct cper_sec_proc_arm *err, const u8 sev) { return; } #endif struct atl_err { @@ -53,4 +52,15 @@ static inline unsigned long amd_convert_umc_mca_addr_to_sys_addr(struct atl_err *err) { return -EINVAL; } #endif /* CONFIG_AMD_ATL */ +#if defined(CONFIG_ARM) || defined(CONFIG_ARM64) +#include +/* + * Include ARM-specific SMP header which provides a function mapping mpidr to + * CPU logical index. + */ +#define GET_LOGICAL_INDEX(mpidr) get_logical_index(mpidr & MPIDR_HWID_BITMASK) +#else +#define GET_LOGICAL_INDEX(mpidr) -EINVAL +#endif /* CONFIG_ARM || CONFIG_ARM64 */ + #endif /* __RAS_H__ */ diff --git a/include/ras/ras_event.h b/include/ras/ras_event.h index c8cd0f00c8454..c9f0b1018bcce 100644 --- a/include/ras/ras_event.h +++ b/include/ras/ras_event.h @@ -168,11 +168,25 @@ TRACE_EVENT(mc_event, * This event is generated when hardware detects an ARM processor error * has occurred. UEFI 2.6 spec section N.2.4.4. */ +#define APEIL "ARM Processor Err Info data len" +#define APEID "ARM Processor Err Info raw data" +#define APECIL "ARM Processor Err Context Info data len" +#define APECID "ARM Processor Err Context Info raw data" +#define VSEIL "Vendor Specific Err Info data len" +#define VSEID "Vendor Specific Err Info raw data" TRACE_EVENT(arm_event, - TP_PROTO(const struct cper_sec_proc_arm *proc), + TP_PROTO(const struct cper_sec_proc_arm *proc, + const u8 *pei_err, + const u32 pei_len, + const u8 *ctx_err, + const u32 ctx_len, + const u8 *oem, + const u32 oem_len, + u8 sev, + int cpu), - TP_ARGS(proc), + TP_ARGS(proc, pei_err, pei_len, ctx_err, ctx_len, oem, oem_len, sev, cpu), TP_STRUCT__entry( __field(u64, mpidr) @@ -180,6 +194,14 @@ TRACE_EVENT(arm_event, __field(u32, running_state) __field(u32, psci_state) __field(u8, affinity) + __field(u32, pei_len) + __dynamic_array(u8, pei_buf, pei_len) + __field(u32, ctx_len) + __dynamic_array(u8, ctx_buf, ctx_len) + __field(u32, oem_len) + __dynamic_array(u8, oem_buf, oem_len) + __field(u8, sev) + __field(int, cpu) ), TP_fast_assign( @@ -199,12 +221,29 @@ TRACE_EVENT(arm_event, __entry->running_state = ~0; __entry->psci_state = ~0; } + __entry->pei_len = pei_len; + memcpy(__get_dynamic_array(pei_buf), pei_err, pei_len); + __entry->ctx_len = ctx_len; + memcpy(__get_dynamic_array(ctx_buf), ctx_err, ctx_len); + __entry->oem_len = oem_len; + memcpy(__get_dynamic_array(oem_buf), oem, oem_len); + __entry->sev = sev; + __entry->cpu = cpu; ), - TP_printk("affinity level: %d; MPIDR: %016llx; MIDR: %016llx; " - "running state: %d; PSCI state: %d", + TP_printk("cpu: %d; error: %d; affinity level: %d; MPIDR: %016llx; MIDR: %016llx; " + "running state: %d; PSCI state: %d; " + "%s: %d; %s: %s; %s: %d; %s: %s; %s: %d; %s: %s", + __entry->cpu, + __entry->sev, __entry->affinity, __entry->mpidr, __entry->midr, - __entry->running_state, __entry->psci_state) + __entry->running_state, __entry->psci_state, + APEIL, __entry->pei_len, APEID, + __print_hex(__get_dynamic_array(pei_buf), __entry->pei_len), + APECIL, __entry->ctx_len, APECID, + __print_hex(__get_dynamic_array(ctx_buf), __entry->ctx_len), + VSEIL, __entry->oem_len, VSEID, + __print_hex(__get_dynamic_array(oem_buf), __entry->oem_len)) ); /* From 89f6fb920e2cf5f4632263c684d4f8c1199c5b9e Mon Sep 17 00:00:00 2001 From: Tomas Glozar Date: Tue, 7 Oct 2025 11:53:40 +0200 Subject: [PATCH 0734/2333] rtla/tests: Extend action tests to 5s [ Upstream commit d649e9f04cb0224817dac8190461ef1674e32b37 ] In non-BPF mode, it takes up to 1 second for RTLA to notice that tracing has been stopped. That means that action tests cannot have a 1 second duration, as the SIGALRM will be racing with the threshold overflow. Previously, non-BPF mode actions were buggy and always executed the action, even when stopping on duration or SIGINT, preventing this issue from manifesting. Now that this has been fixed, the tests have become flaky, and this has to be adjusted. Fixes: 4e26f84abfbb ("rtla/tests: Add tests for actions") Fixes: 05b7e10687c6 ("tools/rtla: Add remaining support for osnoise actions") Reviewed-by: Wander Lairson Costa Link: https://lore.kernel.org/r/20251007095341.186923-2-tglozar@redhat.com Signed-off-by: Tomas Glozar Signed-off-by: Sasha Levin --- tools/tracing/rtla/tests/osnoise.t | 4 ++-- tools/tracing/rtla/tests/timerlat.t | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/tracing/rtla/tests/osnoise.t b/tools/tracing/rtla/tests/osnoise.t index e3c89d45a6bb0..08196443fef16 100644 --- a/tools/tracing/rtla/tests/osnoise.t +++ b/tools/tracing/rtla/tests/osnoise.t @@ -39,9 +39,9 @@ check "hist stop at failed action" \ check "top stop at failed action" \ "timerlat top -T 2 --on-threshold shell,command='echo -n abc; false' --on-threshold shell,command='echo -n defgh'" 2 "^abc" "defgh" check "hist with continue" \ - "osnoise hist -S 2 -d 1s --on-threshold shell,command='echo TestOutput' --on-threshold continue" 0 "^TestOutput$" + "osnoise hist -S 2 -d 5s --on-threshold shell,command='echo TestOutput' --on-threshold continue" 0 "^TestOutput$" check "top with continue" \ - "osnoise top -q -S 2 -d 1s --on-threshold shell,command='echo TestOutput' --on-threshold continue" 0 "^TestOutput$" + "osnoise top -q -S 2 -d 5s --on-threshold shell,command='echo TestOutput' --on-threshold continue" 0 "^TestOutput$" check "hist with trace output at end" \ "osnoise hist -d 1s --on-end trace" 0 "^ Saving trace to osnoise_trace.txt$" check "top with trace output at end" \ diff --git a/tools/tracing/rtla/tests/timerlat.t b/tools/tracing/rtla/tests/timerlat.t index b5d1e7260a9be..b550a6ae24456 100644 --- a/tools/tracing/rtla/tests/timerlat.t +++ b/tools/tracing/rtla/tests/timerlat.t @@ -60,9 +60,9 @@ check "hist stop at failed action" \ check "top stop at failed action" \ "timerlat top -T 2 --on-threshold shell,command='echo -n 1; false' --on-threshold shell,command='echo -n 2'" 2 "^1ALL" check "hist with continue" \ - "timerlat hist -T 2 -d 1s --on-threshold shell,command='echo TestOutput' --on-threshold continue" 0 "^TestOutput$" + "timerlat hist -T 2 -d 5s --on-threshold shell,command='echo TestOutput' --on-threshold continue" 0 "^TestOutput$" check "top with continue" \ - "timerlat top -q -T 2 -d 1s --on-threshold shell,command='echo TestOutput' --on-threshold continue" 0 "^TestOutput$" + "timerlat top -q -T 2 -d 5s --on-threshold shell,command='echo TestOutput' --on-threshold continue" 0 "^TestOutput$" check "hist with trace output at end" \ "timerlat hist -d 1s --on-end trace" 0 "^ Saving trace to timerlat_trace.txt$" check "top with trace output at end" \ From 93409bddc50bde57848854986c4f14e60f363df8 Mon Sep 17 00:00:00 2001 From: Tomas Glozar Date: Tue, 7 Oct 2025 11:53:41 +0200 Subject: [PATCH 0735/2333] rtla/tests: Fix osnoise test calling timerlat [ Upstream commit 34c170ae5c3036ef879567a37409a2859e327342 ] osnoise test "top stop at failed action" is calling timerlat instead of osnoise by mistake. Fix it so that it calls the correct RTLA subcommand. Fixes: 05b7e10687c6 ("tools/rtla: Add remaining support for osnoise actions") Reviewed-by: Wander Lairson Costa Link: https://lore.kernel.org/r/20251007095341.186923-3-tglozar@redhat.com Signed-off-by: Tomas Glozar Signed-off-by: Sasha Levin --- tools/tracing/rtla/tests/osnoise.t | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/tracing/rtla/tests/osnoise.t b/tools/tracing/rtla/tests/osnoise.t index 08196443fef16..3963346089207 100644 --- a/tools/tracing/rtla/tests/osnoise.t +++ b/tools/tracing/rtla/tests/osnoise.t @@ -37,7 +37,7 @@ check "multiple actions" \ check "hist stop at failed action" \ "osnoise hist -S 2 --on-threshold shell,command='echo -n 1; false' --on-threshold shell,command='echo -n 2'" 2 "^1# RTLA osnoise histogram$" check "top stop at failed action" \ - "timerlat top -T 2 --on-threshold shell,command='echo -n abc; false' --on-threshold shell,command='echo -n defgh'" 2 "^abc" "defgh" + "osnoise top -S 2 --on-threshold shell,command='echo -n abc; false' --on-threshold shell,command='echo -n defgh'" 2 "^abc" "defgh" check "hist with continue" \ "osnoise hist -S 2 -d 5s --on-threshold shell,command='echo TestOutput' --on-threshold continue" 0 "^TestOutput$" check "top with continue" \ From 97ee9b4f32c8a594f3d26a53baf03c3de9580361 Mon Sep 17 00:00:00 2001 From: Ivan Pravdin Date: Mon, 3 Nov 2025 11:19:08 -0500 Subject: [PATCH 0736/2333] rtla: Fix -a overriding -t argument [ Upstream commit ddb6e42494e5c48c17e64f29b7674b9add486a19 ] When running rtla as `rtla -t custom_file.txt -a 100` -a options override trace output filename specified by -t option. Running the command above will create _trace.txt file instead of custom_file.txt. Fix this by making sure that -a option does not override trace output filename even if it's passed after trace output filename is specified. Fixes: 173a3b014827 ("rtla/timerlat: Add the automatic trace option") Signed-off-by: Ivan Pravdin Reviewed-by: Tomas Glozar Link: https://lore.kernel.org/r/b6ae60424050b2c1c8709e18759adead6012b971.1762186418.git.ipravdin.official@gmail.com [ use capital letter in subject, as required by tracing subsystem ] Signed-off-by: Tomas Glozar Signed-off-by: Sasha Levin --- tools/tracing/rtla/src/osnoise_hist.c | 3 ++- tools/tracing/rtla/src/osnoise_top.c | 3 ++- tools/tracing/rtla/src/timerlat_hist.c | 3 ++- tools/tracing/rtla/src/timerlat_top.c | 3 ++- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/tools/tracing/rtla/src/osnoise_hist.c b/tools/tracing/rtla/src/osnoise_hist.c index dffb6d0a98d7d..d22feb4d6cc9d 100644 --- a/tools/tracing/rtla/src/osnoise_hist.c +++ b/tools/tracing/rtla/src/osnoise_hist.c @@ -557,7 +557,8 @@ static struct common_params params->threshold = 1; /* set trace */ - trace_output = "osnoise_trace.txt"; + if (!trace_output) + trace_output = "osnoise_trace.txt"; break; case 'b': diff --git a/tools/tracing/rtla/src/osnoise_top.c b/tools/tracing/rtla/src/osnoise_top.c index 95418f7ecc961..a8d31030c4122 100644 --- a/tools/tracing/rtla/src/osnoise_top.c +++ b/tools/tracing/rtla/src/osnoise_top.c @@ -397,7 +397,8 @@ struct common_params *osnoise_top_parse_args(int argc, char **argv) params->threshold = 1; /* set trace */ - trace_output = "osnoise_trace.txt"; + if (!trace_output) + trace_output = "osnoise_trace.txt"; break; case 'c': diff --git a/tools/tracing/rtla/src/timerlat_hist.c b/tools/tracing/rtla/src/timerlat_hist.c index 606c1688057b2..3d56df3d5fa0d 100644 --- a/tools/tracing/rtla/src/timerlat_hist.c +++ b/tools/tracing/rtla/src/timerlat_hist.c @@ -878,7 +878,8 @@ static struct common_params params->print_stack = auto_thresh; /* set trace */ - trace_output = "timerlat_trace.txt"; + if (!trace_output) + trace_output = "timerlat_trace.txt"; break; case 'c': diff --git a/tools/tracing/rtla/src/timerlat_top.c b/tools/tracing/rtla/src/timerlat_top.c index fc479a0dcb597..6cc9a3607c665 100644 --- a/tools/tracing/rtla/src/timerlat_top.c +++ b/tools/tracing/rtla/src/timerlat_top.c @@ -628,7 +628,8 @@ static struct common_params params->print_stack = auto_thresh; /* set trace */ - trace_output = "timerlat_trace.txt"; + if (!trace_output) + trace_output = "timerlat_trace.txt"; break; case '5': From 32952c4f4d1b2deb30dce72ba109da808a9018e1 Mon Sep 17 00:00:00 2001 From: Zhao Yipeng Date: Thu, 20 Nov 2025 15:18:05 +0800 Subject: [PATCH 0737/2333] ima: Handle error code returned by ima_filter_rule_match() [ Upstream commit 738c9738e690f5cea24a3ad6fd2d9a323cf614f6 ] In ima_match_rules(), if ima_filter_rule_match() returns -ENOENT due to the rule being NULL, the function incorrectly skips the 'if (!rc)' check and sets 'result = true'. The LSM rule is considered a match, causing extra files to be measured by IMA. This issue can be reproduced in the following scenario: After unloading the SELinux policy module via 'semodule -d', if an IMA measurement is triggered before ima_lsm_rules is updated, in ima_match_rules(), the first call to ima_filter_rule_match() returns -ESTALE. This causes the code to enter the 'if (rc == -ESTALE && !rule_reinitialized)' block, perform ima_lsm_copy_rule() and retry. In ima_lsm_copy_rule(), since the SELinux module has been removed, the rule becomes NULL, and the second call to ima_filter_rule_match() returns -ENOENT. This bypasses the 'if (!rc)' check and results in a false match. Call trace: selinux_audit_rule_match+0x310/0x3b8 security_audit_rule_match+0x60/0xa0 ima_match_rules+0x2e4/0x4a0 ima_match_policy+0x9c/0x1e8 ima_get_action+0x48/0x60 process_measurement+0xf8/0xa98 ima_bprm_check+0x98/0xd8 security_bprm_check+0x5c/0x78 search_binary_handler+0x6c/0x318 exec_binprm+0x58/0x1b8 bprm_execve+0xb8/0x130 do_execveat_common.isra.0+0x1a8/0x258 __arm64_sys_execve+0x48/0x68 invoke_syscall+0x50/0x128 el0_svc_common.constprop.0+0xc8/0xf0 do_el0_svc+0x24/0x38 el0_svc+0x44/0x200 el0t_64_sync_handler+0x100/0x130 el0t_64_sync+0x3c8/0x3d0 Fix this by changing 'if (!rc)' to 'if (rc <= 0)' to ensure that error codes like -ENOENT do not bypass the check and accidentally result in a successful match. Fixes: 4af4662fa4a9d ("integrity: IMA policy") Signed-off-by: Zhao Yipeng Reviewed-by: Roberto Sassu Signed-off-by: Mimi Zohar Signed-off-by: Sasha Levin --- security/integrity/ima/ima_policy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index 128fab8979308..db6d55af5a80b 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c @@ -674,7 +674,7 @@ static bool ima_match_rules(struct ima_rule_entry *rule, goto retry; } } - if (!rc) { + if (rc <= 0) { result = false; goto out; } From 3681b60224e895c2c23da32506f365ef80301f78 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Thu, 30 Oct 2025 10:39:06 +0100 Subject: [PATCH 0738/2333] usb: chaoskey: fix locking for O_NONBLOCK [ Upstream commit a2fa8a12e6bc9d89c0505b8dd7ae38ec173d25de ] A failure to take a lock with O_NONBLOCK needs to result in -EAGAIN. Change it. Fixes: 66e3e591891da ("usb: Add driver for Altus Metrum ChaosKey device (v2)") Signed-off-by: Oliver Neukum Link: https://patch.msgid.link/20251030093918.2248104-1-oneukum@suse.com Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin --- drivers/usb/misc/chaoskey.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/drivers/usb/misc/chaoskey.c b/drivers/usb/misc/chaoskey.c index 225863321dc47..45cff32656c6e 100644 --- a/drivers/usb/misc/chaoskey.c +++ b/drivers/usb/misc/chaoskey.c @@ -444,9 +444,19 @@ static ssize_t chaoskey_read(struct file *file, goto bail; mutex_unlock(&dev->rng_lock); - result = mutex_lock_interruptible(&dev->lock); - if (result) - goto bail; + if (file->f_flags & O_NONBLOCK) { + result = mutex_trylock(&dev->lock); + if (result == 0) { + result = -EAGAIN; + goto bail; + } else { + result = 0; + } + } else { + result = mutex_lock_interruptible(&dev->lock); + if (result) + goto bail; + } if (dev->valid == dev->used) { result = _chaoskey_fill(dev); if (result < 0) { From cc0d2b85447cfe3c520d5cfe02d62d5e43c46b37 Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Tue, 4 Nov 2025 08:25:02 +0800 Subject: [PATCH 0739/2333] usb: dwc2: fix hang during shutdown if set as peripheral [ Upstream commit b6ebcfdcac40a27953f052e4269ce75a18825ffc ] dwc2 on most platforms needs phy controller, clock and power supply. All of them must be enabled/activated to properly operate. If dwc2 is configured as peripheral mode, then all the above three hardware resources are disabled at the end of the probe: /* Gadget code manages lowlevel hw on its own */ if (hsotg->dr_mode == USB_DR_MODE_PERIPHERAL) dwc2_lowlevel_hw_disable(hsotg); But dwc2_driver_shutdown() tries to disable the interrupts on HW IP level. This would result in hang during shutdown if dwc2 is configured as peripheral mode. Fix this hang by only disable and sync irq when lowlevel hw is enabled. Fixes: 4fdf228cdf69 ("usb: dwc2: Fix shutdown callback in platform") Signed-off-by: Jisheng Zhang Link: https://patch.msgid.link/20251104002503.17158-2-jszhang@kernel.org Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin --- drivers/usb/dwc2/platform.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c index 3f83ecc9fc236..b07bdf16326a4 100644 --- a/drivers/usb/dwc2/platform.c +++ b/drivers/usb/dwc2/platform.c @@ -369,11 +369,11 @@ static void dwc2_driver_shutdown(struct platform_device *dev) { struct dwc2_hsotg *hsotg = platform_get_drvdata(dev); - dwc2_disable_global_interrupts(hsotg); - synchronize_irq(hsotg->irq); - - if (hsotg->ll_hw_enabled) + if (hsotg->ll_hw_enabled) { + dwc2_disable_global_interrupts(hsotg); + synchronize_irq(hsotg->irq); dwc2_lowlevel_hw_disable(hsotg); + } } /** From dda165e3be9d5a65bb8a75f34abe02d1c37dbeec Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Tue, 4 Nov 2025 08:25:03 +0800 Subject: [PATCH 0740/2333] usb: dwc2: fix hang during suspend if set as peripheral [ Upstream commit 2b94b054ac4974ad2f89f7f7461840c851933adb ] dwc2 on most platforms needs phy controller, clock and power supply. All of them must be enabled/activated to properly operate. If dwc2 is configured as peripheral mode, then all the above three hardware resources are disabled at the end of the probe: /* Gadget code manages lowlevel hw on its own */ if (hsotg->dr_mode == USB_DR_MODE_PERIPHERAL) dwc2_lowlevel_hw_disable(hsotg); But the dwc2_suspend() tries to read the dwc2's reg to check whether is_device_mode or not, this would result in hang during suspend if dwc2 is configured as peripheral mode. Fix this hang by bypassing suspend/resume if lowlevel hw isn't enabled. Fixes: 09a75e857790 ("usb: dwc2: refactor common low-level hw code to platform.c") Signed-off-by: Jisheng Zhang Link: https://patch.msgid.link/20251104002503.17158-3-jszhang@kernel.org Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin --- drivers/usb/dwc2/platform.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c index b07bdf16326a4..ef0d730770347 100644 --- a/drivers/usb/dwc2/platform.c +++ b/drivers/usb/dwc2/platform.c @@ -649,9 +649,13 @@ static int dwc2_driver_probe(struct platform_device *dev) static int __maybe_unused dwc2_suspend(struct device *dev) { struct dwc2_hsotg *dwc2 = dev_get_drvdata(dev); - bool is_device_mode = dwc2_is_device_mode(dwc2); + bool is_device_mode; int ret = 0; + if (!dwc2->ll_hw_enabled) + return 0; + + is_device_mode = dwc2_is_device_mode(dwc2); if (is_device_mode) dwc2_hsotg_suspend(dwc2); @@ -728,6 +732,9 @@ static int __maybe_unused dwc2_resume(struct device *dev) struct dwc2_hsotg *dwc2 = dev_get_drvdata(dev); int ret = 0; + if (!dwc2->ll_hw_enabled) + return 0; + if (dwc2->phy_off_for_suspend && dwc2->ll_hw_enabled) { ret = __dwc2_lowlevel_hw_enable(dwc2); if (ret) From 442f55d47d584e89f7c94223dfa8ec3dcfa017f9 Mon Sep 17 00:00:00 2001 From: Gopi Krishna Menon Date: Tue, 28 Oct 2025 22:26:57 +0530 Subject: [PATCH 0741/2333] usb: raw-gadget: cap raw_io transfer length to KMALLOC_MAX_SIZE [ Upstream commit a5160af78be7fcf3ade6caab0a14e349560c96d7 ] The previous commit removed the PAGE_SIZE limit on transfer length of raw_io buffer in order to avoid any problems with emulating USB devices whose full configuration descriptor exceeds PAGE_SIZE in length. However this also removes the upperbound on user supplied length, allowing very large values to be passed to the allocator. syzbot on fuzzing the transfer length with very large value (1.81GB) results in kmalloc() to fall back to the page allocator, which triggers a kernel warning as the page allocator cannot handle allocations more than MAX_PAGE_ORDER/KMALLOC_MAX_SIZE. Since there is no limit imposed on the size of buffer for both control and non control transfers, cap the raw_io transfer length to KMALLOC_MAX_SIZE and return -EINVAL for larger transfer length to prevent any warnings from the page allocator. Fixes: 37b9dd0d114a ("usb: raw-gadget: do not limit transfer length") Tested-by: syzbot+d8fd35fa6177afa8c92b@syzkaller.appspotmail.com Reported-by: syzbot+d8fd35fa6177afa8c92b@syzkaller.appspotmail.com Closes: https://lore.kernel.org/all/68fc07a0.a70a0220.3bf6c6.01ab.GAE@google.com/ Signed-off-by: Gopi Krishna Menon Reviewed-by: Andrey Konovalov Link: https://patch.msgid.link/20251028165659.50962-1-krishnagopi487@gmail.com Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin --- drivers/usb/gadget/legacy/raw_gadget.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/usb/gadget/legacy/raw_gadget.c b/drivers/usb/gadget/legacy/raw_gadget.c index b71680c58de6c..46f343ba48b3d 100644 --- a/drivers/usb/gadget/legacy/raw_gadget.c +++ b/drivers/usb/gadget/legacy/raw_gadget.c @@ -40,6 +40,7 @@ MODULE_LICENSE("GPL"); static DEFINE_IDA(driver_id_numbers); #define DRIVER_DRIVER_NAME_LENGTH_MAX 32 +#define USB_RAW_IO_LENGTH_MAX KMALLOC_MAX_SIZE #define RAW_EVENT_QUEUE_SIZE 16 @@ -667,6 +668,8 @@ static void *raw_alloc_io_data(struct usb_raw_ep_io *io, void __user *ptr, return ERR_PTR(-EINVAL); if (!usb_raw_io_flags_valid(io->flags)) return ERR_PTR(-EINVAL); + if (io->length > USB_RAW_IO_LENGTH_MAX) + return ERR_PTR(-EINVAL); if (get_from_user) data = memdup_user(ptr + sizeof(*io), io->length); else { From 93787117dcf19e6b9febbb389062d1fcf8c90cdd Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 21 Nov 2025 16:35:24 +0300 Subject: [PATCH 0742/2333] regulator: pca9450: Fix error code in probe() [ Upstream commit 670500b41e543c5cb09eb9f7f0e4e26c5b5fdf7e ] Return "PTR_ERR(pca9450->sd_vsel_gpio)" instead of "ret". The "ret" variable is success at this point. Fixes: 3ce6f4f943dd ("regulator: pca9450: Fix control register for LDO5") Signed-off-by: Dan Carpenter Link: https://patch.msgid.link/aSBqnPoBrsNB1Ale@stanley.mountain Signed-off-by: Mark Brown Signed-off-by: Sasha Levin --- drivers/regulator/pca9450-regulator.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/regulator/pca9450-regulator.c b/drivers/regulator/pca9450-regulator.c index 4be270f4d6c35..91b96dbab328b 100644 --- a/drivers/regulator/pca9450-regulator.c +++ b/drivers/regulator/pca9450-regulator.c @@ -1251,10 +1251,9 @@ static int pca9450_i2c_probe(struct i2c_client *i2c) * to this signal (if SION bit is set in IOMUX). */ pca9450->sd_vsel_gpio = gpiod_get_optional(&ldo5->dev, "sd-vsel", GPIOD_IN); - if (IS_ERR(pca9450->sd_vsel_gpio)) { - dev_err(&i2c->dev, "Failed to get SD_VSEL GPIO\n"); - return ret; - } + if (IS_ERR(pca9450->sd_vsel_gpio)) + return dev_err_probe(&i2c->dev, PTR_ERR(pca9450->sd_vsel_gpio), + "Failed to get SD_VSEL GPIO\n"); pca9450->sd_vsel_fixed_low = of_property_read_bool(ldo5->dev.of_node, "nxp,sd-vsel-fixed-low"); From 833e49fa2dd4c58333862060f08e7947ab6a19e6 Mon Sep 17 00:00:00 2001 From: Matt Bobrowski Date: Thu, 20 Nov 2025 14:20:59 +0000 Subject: [PATCH 0743/2333] selftests/bpf: skip test_perf_branches_hw() on unsupported platforms [ Upstream commit 27746aaf1b20172f0859546c4a3e82eca459f680 ] Gracefully skip the test_perf_branches_hw subtest on platforms that do not support LBR or require specialized perf event attributes to enable branch sampling. For example, AMD's Milan (Zen 3) supports BRS rather than traditional LBR. This requires specific configurations (attr.type = PERF_TYPE_RAW, attr.config = RETIRED_TAKEN_BRANCH_INSTRUCTIONS) that differ from the generic setup used within this test. Notably, it also probably doesn't hold much value to special case perf event configurations for selected micro architectures. Fixes: 67306f84ca78c ("selftests/bpf: Add bpf_read_branch_records() selftest") Signed-off-by: Matt Bobrowski Acked-by: Song Liu Link: https://lore.kernel.org/r/20251120142059.2836181-1-mattbobrowski@google.com Signed-off-by: Alexei Starovoitov Signed-off-by: Sasha Levin --- tools/testing/selftests/bpf/prog_tests/perf_branches.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/perf_branches.c b/tools/testing/selftests/bpf/prog_tests/perf_branches.c index bc24f83339d64..06c7986131d96 100644 --- a/tools/testing/selftests/bpf/prog_tests/perf_branches.c +++ b/tools/testing/selftests/bpf/prog_tests/perf_branches.c @@ -116,11 +116,11 @@ static void test_perf_branches_hw(void) pfd = syscall(__NR_perf_event_open, &attr, -1, 0, -1, PERF_FLAG_FD_CLOEXEC); /* - * Some setups don't support branch records (virtual machines, !x86), - * so skip test in this case. + * Some setups don't support LBR (virtual machines, !x86, AMD Milan Zen + * 3 which only supports BRS), so skip test in this case. */ if (pfd < 0) { - if (errno == ENOENT || errno == EOPNOTSUPP) { + if (errno == ENOENT || errno == EOPNOTSUPP || errno == EINVAL) { printf("%s:SKIP:no PERF_SAMPLE_BRANCH_STACK\n", __func__); test__skip(); From a8cf555fd77383574c4dcff7a2625fbcbd149362 Mon Sep 17 00:00:00 2001 From: Matt Bobrowski Date: Wed, 19 Nov 2025 14:35:40 +0000 Subject: [PATCH 0744/2333] selftests/bpf: Improve reliability of test_perf_branches_no_hw() [ Upstream commit ae24fc8a16b0481ea8c5acbc66453c49ec0431c4 ] Currently, test_perf_branches_no_hw() relies on the busy loop within test_perf_branches_common() being slow enough to allow at least one perf event sample tick to occur before starting to tear down the backing perf event BPF program. With a relatively small fixed iteration count of 1,000,000, this is not guaranteed on modern fast CPUs, resulting in the test run to subsequently fail with the following: bpf_testmod.ko is already unloaded. Loading bpf_testmod.ko... Successfully loaded bpf_testmod.ko. test_perf_branches_common:PASS:test_perf_branches_load 0 nsec test_perf_branches_common:PASS:attach_perf_event 0 nsec test_perf_branches_common:PASS:set_affinity 0 nsec check_good_sample:PASS:output not valid 0 nsec check_good_sample:PASS:read_branches_size 0 nsec check_good_sample:PASS:read_branches_stack 0 nsec check_good_sample:PASS:read_branches_stack 0 nsec check_good_sample:PASS:read_branches_global 0 nsec check_good_sample:PASS:read_branches_global 0 nsec check_good_sample:PASS:read_branches_size 0 nsec test_perf_branches_no_hw:PASS:perf_event_open 0 nsec test_perf_branches_common:PASS:test_perf_branches_load 0 nsec test_perf_branches_common:PASS:attach_perf_event 0 nsec test_perf_branches_common:PASS:set_affinity 0 nsec check_bad_sample:FAIL:output not valid no valid sample from prog Summary: 0/1 PASSED, 0 SKIPPED, 1 FAILED Successfully unloaded bpf_testmod.ko. On a modern CPU (i.e. one with a 3.5 GHz clock rate), executing 1 million increments of a volatile integer can take significantly less than 1 millisecond. If the spin loop and detachment of the perf event BPF program elapses before the first 1 ms sampling interval elapses, the perf event will never end up firing. Fix this by bumping the loop iteration counter a little within test_perf_branches_common(), along with ensuring adding another loop termination condition which is directly influenced by the backing perf event BPF program executing. Notably, a concious decision was made to not adjust the sample_freq value as that is just not a reliable way to go about fixing the problem. It effectively still leaves the race window open. Fixes: 67306f84ca78c ("selftests/bpf: Add bpf_read_branch_records() selftest") Signed-off-by: Matt Bobrowski Reviewed-by: Jiri Olsa Link: https://lore.kernel.org/r/20251119143540.2911424-1-mattbobrowski@google.com Signed-off-by: Alexei Starovoitov Signed-off-by: Sasha Levin --- .../selftests/bpf/prog_tests/perf_branches.c | 16 ++++++++++++++-- .../selftests/bpf/progs/test_perf_branches.c | 3 +++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/perf_branches.c b/tools/testing/selftests/bpf/prog_tests/perf_branches.c index 06c7986131d96..0a7ef770c487c 100644 --- a/tools/testing/selftests/bpf/prog_tests/perf_branches.c +++ b/tools/testing/selftests/bpf/prog_tests/perf_branches.c @@ -15,6 +15,10 @@ static void check_good_sample(struct test_perf_branches *skel) int pbe_size = sizeof(struct perf_branch_entry); int duration = 0; + if (CHECK(!skel->bss->run_cnt, "invalid run_cnt", + "checked sample validity before prog run")) + return; + if (CHECK(!skel->bss->valid, "output not valid", "no valid sample from prog")) return; @@ -45,6 +49,10 @@ static void check_bad_sample(struct test_perf_branches *skel) int written_stack = skel->bss->written_stack_out; int duration = 0; + if (CHECK(!skel->bss->run_cnt, "invalid run_cnt", + "checked sample validity before prog run")) + return; + if (CHECK(!skel->bss->valid, "output not valid", "no valid sample from prog")) return; @@ -83,8 +91,12 @@ static void test_perf_branches_common(int perf_fd, err = pthread_setaffinity_np(pthread_self(), sizeof(cpu_set), &cpu_set); if (CHECK(err, "set_affinity", "cpu #0, err %d\n", err)) goto out_destroy; - /* spin the loop for a while (random high number) */ - for (i = 0; i < 1000000; ++i) + + /* Spin the loop for a while by using a high iteration count, and by + * checking whether the specific run count marker has been explicitly + * incremented at least once by the backing perf_event BPF program. + */ + for (i = 0; i < 100000000 && !*(volatile int *)&skel->bss->run_cnt; ++i) ++j; test_perf_branches__detach(skel); diff --git a/tools/testing/selftests/bpf/progs/test_perf_branches.c b/tools/testing/selftests/bpf/progs/test_perf_branches.c index a1ccc831c882f..05ac9410cd68c 100644 --- a/tools/testing/selftests/bpf/progs/test_perf_branches.c +++ b/tools/testing/selftests/bpf/progs/test_perf_branches.c @@ -8,6 +8,7 @@ #include int valid = 0; +int run_cnt = 0; int required_size_out = 0; int written_stack_out = 0; int written_global_out = 0; @@ -24,6 +25,8 @@ int perf_branches(void *ctx) __u64 entries[4 * 3] = {0}; int required_size, written_stack, written_global; + ++run_cnt; + /* write to stack */ written_stack = bpf_read_branch_records(ctx, entries, sizeof(entries), 0); /* ignore spurious events */ From 982ef82af9980eb9e058320b9f9ce673d941c612 Mon Sep 17 00:00:00 2001 From: Xing Guo Date: Fri, 21 Nov 2025 14:14:58 +0800 Subject: [PATCH 0745/2333] selftests/bpf: Update test_tag to use sha256 [ Upstream commit b7f7d76d6e354a5acc711da37cb2829ccf40558f ] commit 603b44162325 ("bpf: Update the bpf_prog_calc_tag to use SHA256") changed digest of prog_tag to SHA256 but forgot to update tests correspondingly. Fix it. Fixes: 603b44162325 ("bpf: Update the bpf_prog_calc_tag to use SHA256") Signed-off-by: Xing Guo Link: https://lore.kernel.org/r/20251121061458.3145167-1-higuoxing@gmail.com Signed-off-by: Alexei Starovoitov Signed-off-by: Sasha Levin --- tools/testing/selftests/bpf/test_tag.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/bpf/test_tag.c b/tools/testing/selftests/bpf/test_tag.c index 5546b05a04866..f1300047c1e0a 100644 --- a/tools/testing/selftests/bpf/test_tag.c +++ b/tools/testing/selftests/bpf/test_tag.c @@ -116,7 +116,7 @@ static void tag_from_alg(int insns, uint8_t *tag, uint32_t len) static const struct sockaddr_alg alg = { .salg_family = AF_ALG, .salg_type = "hash", - .salg_name = "sha1", + .salg_name = "sha256", }; int fd_base, fd_alg, ret; ssize_t size; From a6c22c91b6284e4713c0cf5b20ab3c9c71b77ae8 Mon Sep 17 00:00:00 2001 From: Martin Teichmann Date: Wed, 19 Nov 2025 17:03:52 +0100 Subject: [PATCH 0746/2333] bpf: properly verify tail call behavior [ Upstream commit e3245f8990431950d20631c72236d4e8cb2dcde8 ] A successful ebpf tail call does not return to the caller, but to the caller-of-the-caller, often just finishing the ebpf program altogether. Any restrictions that the verifier needs to take into account - notably the fact that the tail call might have modified packet pointers - are to be checked on the caller-of-the-caller. Checking it on the caller made the verifier refuse perfectly fine programs that would use the packet pointers after a tail call, which is no problem as this code is only executed if the tail call was unsuccessful, i.e. nothing happened. This patch simulates the behavior of a tail call in the verifier. A conditional jump to the code after the tail call is added for the case of an unsucessful tail call, and a return to the caller is simulated for a successful tail call. For the successful case we assume that the tail call returns an int, as tail calls are currently only allowed in functions that return and int. We always assume that the tail call modified the packet pointers, as we do not know what the tail call did. For the unsuccessful case we know nothing happened, so we do not need to add new constraints. This approach also allows to check other problems that may occur with tail calls, namely we are now able to check that precision is properly propagated into subprograms using tail calls, as well as checking the live slots in such a subprogram. Fixes: 1a4607ffba35 ("bpf: consider that tail calls invalidate packet pointers") Link: https://lore.kernel.org/bpf/20251029105828.1488347-1-martin.teichmann@xfel.eu/ Signed-off-by: Martin Teichmann Acked-by: Eduard Zingerman Link: https://lore.kernel.org/r/20251119160355.1160932-2-martin.teichmann@xfel.eu Signed-off-by: Alexei Starovoitov Signed-off-by: Sasha Levin --- kernel/bpf/verifier.c | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 52c01c011c6fb..89560e455ce7b 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -4408,6 +4408,11 @@ static int backtrack_insn(struct bpf_verifier_env *env, int idx, int subseq_idx, bt_reg_mask(bt)); return -EFAULT; } + if (insn->src_reg == BPF_REG_0 && insn->imm == BPF_FUNC_tail_call + && subseq_idx - idx != 1) { + if (bt_subprog_enter(bt)) + return -EFAULT; + } } else if (opcode == BPF_EXIT) { bool r0_precise; @@ -10995,6 +11000,10 @@ static int prepare_func_exit(struct bpf_verifier_env *env, int *insn_idx) bool in_callback_fn; int err; + err = bpf_update_live_stack(env); + if (err) + return err; + callee = state->frame[state->curframe]; r0 = &callee->regs[BPF_REG_0]; if (r0->type == PTR_TO_STACK) { @@ -11912,6 +11921,25 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn env->prog->call_get_func_ip = true; } + if (func_id == BPF_FUNC_tail_call) { + if (env->cur_state->curframe) { + struct bpf_verifier_state *branch; + + mark_reg_scratched(env, BPF_REG_0); + branch = push_stack(env, env->insn_idx + 1, env->insn_idx, false); + if (IS_ERR(branch)) + return PTR_ERR(branch); + clear_all_pkt_pointers(env); + mark_reg_unknown(env, regs, BPF_REG_0); + err = prepare_func_exit(env, &env->insn_idx); + if (err) + return err; + env->insn_idx--; + } else { + changes_data = false; + } + } + if (changes_data) clear_all_pkt_pointers(env); return 0; @@ -19810,9 +19838,6 @@ static int process_bpf_exit_full(struct bpf_verifier_env *env, return PROCESS_BPF_EXIT; if (env->cur_state->curframe) { - err = bpf_update_live_stack(env); - if (err) - return err; /* exit from nested function */ err = prepare_func_exit(env, &env->insn_idx); if (err) From 9b3f71cf02e04cfaa482155e3078707fe7f8aef4 Mon Sep 17 00:00:00 2001 From: Haotian Zhang Date: Mon, 10 Nov 2025 14:54:38 +0800 Subject: [PATCH 0747/2333] crypto: starfive - Correctly handle return of sg_nents_for_len [ Upstream commit e9eb52037a529fbb307c290e9951a62dd728b03d ] The return value of sg_nents_for_len was assigned to an unsigned long in starfive_hash_digest, causing negative error codes to be converted to large positive integers. Add error checking for sg_nents_for_len and return immediately on failure to prevent potential buffer overflows. Fixes: 7883d1b28a2b ("crypto: starfive - Add hash and HMAC support") Signed-off-by: Haotian Zhang Signed-off-by: Herbert Xu Signed-off-by: Sasha Levin --- drivers/crypto/starfive/jh7110-hash.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/crypto/starfive/jh7110-hash.c b/drivers/crypto/starfive/jh7110-hash.c index e6839c7bfb73a..54b7af4a7aee8 100644 --- a/drivers/crypto/starfive/jh7110-hash.c +++ b/drivers/crypto/starfive/jh7110-hash.c @@ -325,6 +325,7 @@ static int starfive_hash_digest(struct ahash_request *req) struct starfive_cryp_ctx *ctx = crypto_ahash_ctx(tfm); struct starfive_cryp_request_ctx *rctx = ahash_request_ctx(req); struct starfive_cryp_dev *cryp = ctx->cryp; + int sg_len; memset(rctx, 0, sizeof(struct starfive_cryp_request_ctx)); @@ -333,7 +334,10 @@ static int starfive_hash_digest(struct ahash_request *req) rctx->in_sg = req->src; rctx->blksize = crypto_tfm_alg_blocksize(crypto_ahash_tfm(tfm)); rctx->digsize = crypto_ahash_digestsize(tfm); - rctx->in_sg_len = sg_nents_for_len(rctx->in_sg, rctx->total); + sg_len = sg_nents_for_len(rctx->in_sg, rctx->total); + if (sg_len < 0) + return sg_len; + rctx->in_sg_len = sg_len; ctx->rctx = rctx; return crypto_transfer_hash_request_to_engine(cryp->engine, req); From 2873d804b4f342c92bd0ff1a151d19e72650430b Mon Sep 17 00:00:00 2001 From: Haotian Zhang Date: Mon, 10 Nov 2025 15:20:41 +0800 Subject: [PATCH 0748/2333] crypto: ccree - Correctly handle return of sg_nents_for_len [ Upstream commit 8700ce07c5c6bf27afa7b59a8d9cf58d783a7d5c ] Fix error handling in cc_map_hash_request_update where sg_nents_for_len return value was assigned to u32, converting negative errors to large positive values before passing to sg_copy_to_buffer. Check sg_nents_for_len return value and propagate errors before assigning to areq_ctx->in_nents. Fixes: b7ec8530687a ("crypto: ccree - use std api when possible") Signed-off-by: Haotian Zhang Signed-off-by: Herbert Xu Signed-off-by: Sasha Levin --- drivers/crypto/ccree/cc_buffer_mgr.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/crypto/ccree/cc_buffer_mgr.c b/drivers/crypto/ccree/cc_buffer_mgr.c index 3963bb91321fc..dc7e0cd51c259 100644 --- a/drivers/crypto/ccree/cc_buffer_mgr.c +++ b/drivers/crypto/ccree/cc_buffer_mgr.c @@ -1235,6 +1235,7 @@ int cc_map_hash_request_update(struct cc_drvdata *drvdata, void *ctx, int rc = 0; u32 dummy = 0; u32 mapped_nents = 0; + int sg_nents; dev_dbg(dev, " update params : curr_buff=%p curr_buff_cnt=0x%X nbytes=0x%X src=%p curr_index=%u\n", curr_buff, *curr_buff_cnt, nbytes, src, areq_ctx->buff_index); @@ -1248,7 +1249,10 @@ int cc_map_hash_request_update(struct cc_drvdata *drvdata, void *ctx, if (total_in_len < block_size) { dev_dbg(dev, " less than one block: curr_buff=%p *curr_buff_cnt=0x%X copy_to=%p\n", curr_buff, *curr_buff_cnt, &curr_buff[*curr_buff_cnt]); - areq_ctx->in_nents = sg_nents_for_len(src, nbytes); + sg_nents = sg_nents_for_len(src, nbytes); + if (sg_nents < 0) + return sg_nents; + areq_ctx->in_nents = sg_nents; sg_copy_to_buffer(src, areq_ctx->in_nents, &curr_buff[*curr_buff_cnt], nbytes); *curr_buff_cnt += nbytes; From 469b0b8ce08818f3e4f01d2fa8d0dadeab501e1f Mon Sep 17 00:00:00 2001 From: Pengjie Zhang Date: Mon, 15 Sep 2025 14:21:35 +0800 Subject: [PATCH 0749/2333] PM / devfreq: hisi: Fix potential UAF in OPP handling [ Upstream commit 26dd44a40096468396b6438985d8e44e0743f64c ] Ensure all required data is acquired before calling dev_pm_opp_put(opp) to maintain correct resource acquisition and release order. Fixes: 7da2fdaaa1e6 ("PM / devfreq: Add HiSilicon uncore frequency scaling driver") Signed-off-by: Pengjie Zhang Reviewed-by: Jie Zhan Acked-by: Chanwoo Choi Signed-off-by: Chanwoo Choi Link: https://patchwork.kernel.org/project/linux-pm/patch/20250915062135.748653-1-zhangpengjie2@huawei.com/ Signed-off-by: Sasha Levin --- drivers/devfreq/hisi_uncore_freq.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/devfreq/hisi_uncore_freq.c b/drivers/devfreq/hisi_uncore_freq.c index 96d1815059e32..c1ed70fa0a400 100644 --- a/drivers/devfreq/hisi_uncore_freq.c +++ b/drivers/devfreq/hisi_uncore_freq.c @@ -265,10 +265,11 @@ static int hisi_uncore_target(struct device *dev, unsigned long *freq, dev_err(dev, "Failed to get opp for freq %lu hz\n", *freq); return PTR_ERR(opp); } - dev_pm_opp_put(opp); data = (u32)(dev_pm_opp_get_freq(opp) / HZ_PER_MHZ); + dev_pm_opp_put(opp); + return hisi_uncore_cmd_send(uncore, HUCF_PCC_CMD_SET_FREQ, &data); } From 1fa7e6e78bd6ce61c00d749532639b9b4e20795b Mon Sep 17 00:00:00 2001 From: Fangyu Yu Date: Fri, 21 Nov 2025 21:35:43 +0800 Subject: [PATCH 0750/2333] RISC-V: KVM: Fix guest page fault within HLV* instructions [ Upstream commit 974555d6e417974e63444266e495a06d06c23af5 ] When executing HLV* instructions at the HS mode, a guest page fault may occur when a g-stage page table migration between triggering the virtual instruction exception and executing the HLV* instruction. This may be a corner case, and one simpler way to handle this is to re-execute the instruction where the virtual instruction exception occurred, and the guest page fault will be automatically handled. Fixes: b91f0e4cb8a3 ("RISC-V: KVM: Factor-out instruction emulation into separate sources") Signed-off-by: Fangyu Yu Reviewed-by: Anup Patel Link: https://lore.kernel.org/r/20251121133543.46822-1-fangyu.yu@linux.alibaba.com Signed-off-by: Anup Patel Signed-off-by: Sasha Levin --- arch/riscv/kvm/vcpu_insn.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/arch/riscv/kvm/vcpu_insn.c b/arch/riscv/kvm/vcpu_insn.c index de1f96ea62251..4d89b94128aea 100644 --- a/arch/riscv/kvm/vcpu_insn.c +++ b/arch/riscv/kvm/vcpu_insn.c @@ -298,6 +298,22 @@ static int system_opcode_insn(struct kvm_vcpu *vcpu, struct kvm_run *run, return (rc <= 0) ? rc : 1; } +static bool is_load_guest_page_fault(unsigned long scause) +{ + /** + * If a g-stage page fault occurs, the direct approach + * is to let the g-stage page fault handler handle it + * naturally, however, calling the g-stage page fault + * handler here seems rather strange. + * Considering this is a corner case, we can directly + * return to the guest and re-execute the same PC, this + * will trigger a g-stage page fault again and then the + * regular g-stage page fault handler will populate + * g-stage page table. + */ + return (scause == EXC_LOAD_GUEST_PAGE_FAULT); +} + /** * kvm_riscv_vcpu_virtual_insn -- Handle virtual instruction trap * @@ -323,6 +339,8 @@ int kvm_riscv_vcpu_virtual_insn(struct kvm_vcpu *vcpu, struct kvm_run *run, ct->sepc, &utrap); if (utrap.scause) { + if (is_load_guest_page_fault(utrap.scause)) + return 1; utrap.sepc = ct->sepc; kvm_riscv_vcpu_trap_redirect(vcpu, &utrap); return 1; @@ -378,6 +396,8 @@ int kvm_riscv_vcpu_mmio_load(struct kvm_vcpu *vcpu, struct kvm_run *run, insn = kvm_riscv_vcpu_unpriv_read(vcpu, true, ct->sepc, &utrap); if (utrap.scause) { + if (is_load_guest_page_fault(utrap.scause)) + return 1; /* Redirect trap if we failed to read instruction */ utrap.sepc = ct->sepc; kvm_riscv_vcpu_trap_redirect(vcpu, &utrap); @@ -504,6 +524,8 @@ int kvm_riscv_vcpu_mmio_store(struct kvm_vcpu *vcpu, struct kvm_run *run, insn = kvm_riscv_vcpu_unpriv_read(vcpu, true, ct->sepc, &utrap); if (utrap.scause) { + if (is_load_guest_page_fault(utrap.scause)) + return 1; /* Redirect trap if we failed to read instruction */ utrap.sepc = ct->sepc; kvm_riscv_vcpu_trap_redirect(vcpu, &utrap); From 46198ad004297e003b5e35a90aa841ecdb668bef Mon Sep 17 00:00:00 2001 From: Gao Xiang Date: Mon, 17 Nov 2025 19:57:29 +0800 Subject: [PATCH 0751/2333] erofs: correct FSDAX detection [ Upstream commit ebe4f3f6eb0c10f87c58e52a8912694c14fdeda6 ] The detection of the primary device is skipped incorrectly if the multiple or flattened feature is enabled. It also fixes the FSDAX misdetection for non-block extra blobs. Fixes: c6993c4cb918 ("erofs: Fallback to normal access if DAX is not supported on extra device") Reported-and-tested-by: syzbot+31b8fb02cb8a25bd5e78@syzkaller.appspotmail.com Closes: https://lore.kernel.org/r/691af9f6.a70a0220.3124cb.0097.GAE@google.com Cc: Yuezhang Mo Reviewed-by: Chao Yu Signed-off-by: Gao Xiang Signed-off-by: Sasha Levin --- fs/erofs/super.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/fs/erofs/super.c b/fs/erofs/super.c index f3f8d8c066e4e..cd8ff98c29384 100644 --- a/fs/erofs/super.c +++ b/fs/erofs/super.c @@ -174,15 +174,15 @@ static int erofs_init_device(struct erofs_buf *buf, struct super_block *sb, if (!erofs_is_fileio_mode(sbi)) { dif->dax_dev = fs_dax_get_by_bdev(file_bdev(file), &dif->dax_part_off, NULL, NULL); - if (!dif->dax_dev && test_opt(&sbi->opt, DAX_ALWAYS)) { - erofs_info(sb, "DAX unsupported by %s. Turning off DAX.", - dif->path); - clear_opt(&sbi->opt, DAX_ALWAYS); - } } else if (!S_ISREG(file_inode(file)->i_mode)) { fput(file); return -EINVAL; } + if (!dif->dax_dev && test_opt(&sbi->opt, DAX_ALWAYS)) { + erofs_info(sb, "DAX unsupported by %s. Turning off DAX.", + dif->path); + clear_opt(&sbi->opt, DAX_ALWAYS); + } dif->file = file; } @@ -215,13 +215,13 @@ static int erofs_scan_devices(struct super_block *sb, ondisk_extradevs, sbi->devs->extra_devices); return -EINVAL; } - if (!ondisk_extradevs) { - if (test_opt(&sbi->opt, DAX_ALWAYS) && !sbi->dif0.dax_dev) { - erofs_info(sb, "DAX unsupported by block device. Turning off DAX."); - clear_opt(&sbi->opt, DAX_ALWAYS); - } - return 0; + + if (test_opt(&sbi->opt, DAX_ALWAYS) && !sbi->dif0.dax_dev) { + erofs_info(sb, "DAX unsupported by block device. Turning off DAX."); + clear_opt(&sbi->opt, DAX_ALWAYS); } + if (!ondisk_extradevs) + return 0; if (!sbi->devs->extra_devices && !erofs_is_fscache_mode(sb)) sbi->devs->flatdev = true; From 620472e6b303c4dbcc7ecf1aba1cda4f3523e4a4 Mon Sep 17 00:00:00 2001 From: Gao Xiang Date: Sat, 22 Nov 2025 14:23:32 +0800 Subject: [PATCH 0752/2333] erofs: limit the level of fs stacking for file-backed mounts [ Upstream commit d53cd891f0e4311889349fff3a784dc552f814b9 ] Otherwise, it could cause potential kernel stack overflow (e.g., EROFS mounting itself). Reviewed-by: Sheng Yong Fixes: fb176750266a ("erofs: add file-backed mount support") Reviewed-by: Chao Yu Reviewed-by: Hongbo Li Signed-off-by: Gao Xiang Signed-off-by: Sasha Levin --- fs/erofs/super.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/fs/erofs/super.c b/fs/erofs/super.c index cd8ff98c29384..937a215f626c1 100644 --- a/fs/erofs/super.c +++ b/fs/erofs/super.c @@ -639,6 +639,22 @@ static int erofs_fc_fill_super(struct super_block *sb, struct fs_context *fc) sbi->blkszbits = PAGE_SHIFT; if (!sb->s_bdev) { + /* + * (File-backed mounts) EROFS claims it's safe to nest other + * fs contexts (including its own) due to self-controlled RO + * accesses/contexts and no side-effect changes that need to + * context save & restore so it can reuse the current thread + * context. However, it still needs to bump `s_stack_depth` to + * avoid kernel stack overflow from nested filesystems. + */ + if (erofs_is_fileio_mode(sbi)) { + sb->s_stack_depth = + file_inode(sbi->dif0.file)->i_sb->s_stack_depth + 1; + if (sb->s_stack_depth > FILESYSTEM_MAX_STACK_DEPTH) { + erofs_err(sb, "maximum fs stacking depth exceeded"); + return -ENOTBLK; + } + } sb->s_blocksize = PAGE_SIZE; sb->s_blocksize_bits = PAGE_SHIFT; From 32fdf021f6c90af7fb78597a8ef158abd2a99c62 Mon Sep 17 00:00:00 2001 From: Selvin Xavier Date: Wed, 19 Nov 2025 23:36:54 -0800 Subject: [PATCH 0753/2333] RDMA/bnxt_re: Fix the inline size for GenP7 devices [ Upstream commit 6afe40ff484a1155b71158b911c65299496e35c3 ] Inline size supported by the device is based on the number of SGEs supported by the adapter. Change the inline size calculation based on that. Fixes: de1d364c3815 ("RDMA/bnxt_re: Add support for Variable WQE in Genp7 adapters") Reviewed-by: Kashyap Desai Signed-off-by: Kalesh AP Signed-off-by: Selvin Xavier Link: https://patch.msgid.link/1763624215-10382-1-git-send-email-selvin.xavier@broadcom.com Signed-off-by: Leon Romanovsky Signed-off-by: Sasha Levin --- drivers/infiniband/hw/bnxt_re/qplib_sp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/bnxt_re/qplib_sp.c b/drivers/infiniband/hw/bnxt_re/qplib_sp.c index 9ef581ed785c8..a9afac2cbb7cf 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_sp.c +++ b/drivers/infiniband/hw/bnxt_re/qplib_sp.c @@ -162,7 +162,7 @@ int bnxt_qplib_get_dev_attr(struct bnxt_qplib_rcfw *rcfw) attr->max_srq_wqes = le32_to_cpu(sb->max_srq_wr) - 1; attr->max_srq_sges = sb->max_srq_sge; attr->max_pkey = 1; - attr->max_inline_data = le32_to_cpu(sb->max_inline_data); + attr->max_inline_data = attr->max_qp_sges * sizeof(struct sq_sge); if (!bnxt_qplib_is_chip_gen_p7(rcfw->res->cctx)) attr->l2_db_size = (sb->l2_db_space_size + 1) * (0x01 << RCFW_DBR_BASE_PAGE_SHIFT); From ce649d74650a9fd7890c2450a58c091103e5790d Mon Sep 17 00:00:00 2001 From: Selvin Xavier Date: Wed, 19 Nov 2025 23:36:55 -0800 Subject: [PATCH 0754/2333] RDMA/bnxt_re: Pass correct flag for dma mr creation [ Upstream commit a26c4c7cdb50247b8486f1caa1ea8ab5e5c37edf ] DMA MR doesn't use the unified MR model. So the lkey passed on to the reg_mr command to FW should contain the correct lkey. Driver is incorrectly over writing the lkey with pdid and firmware commands fails due to this. Avoid passing the wrong key for cases where the unified MR registration is not used. Fixes: f786eebbbefa ("RDMA/bnxt_re: Avoid an extra hwrm per MR creation") Signed-off-by: Kalesh AP Signed-off-by: Selvin Xavier Link: https://patch.msgid.link/1763624215-10382-2-git-send-email-selvin.xavier@broadcom.com Signed-off-by: Leon Romanovsky Signed-off-by: Sasha Levin --- drivers/infiniband/hw/bnxt_re/ib_verbs.c | 8 +++++--- drivers/infiniband/hw/bnxt_re/qplib_sp.c | 6 +++--- drivers/infiniband/hw/bnxt_re/qplib_sp.h | 2 +- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.c b/drivers/infiniband/hw/bnxt_re/ib_verbs.c index 84ce3fce2826b..f19b55c13d580 100644 --- a/drivers/infiniband/hw/bnxt_re/ib_verbs.c +++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.c @@ -601,7 +601,8 @@ static int bnxt_re_create_fence_mr(struct bnxt_re_pd *pd) mr->qplib_mr.va = (u64)(unsigned long)fence->va; mr->qplib_mr.total_size = BNXT_RE_FENCE_BYTES; rc = bnxt_qplib_reg_mr(&rdev->qplib_res, &mr->qplib_mr, NULL, - BNXT_RE_FENCE_PBL_SIZE, PAGE_SIZE); + BNXT_RE_FENCE_PBL_SIZE, PAGE_SIZE, + _is_alloc_mr_unified(rdev->dev_attr->dev_cap_flags)); if (rc) { ibdev_err(&rdev->ibdev, "Failed to register fence-MR\n"); goto fail; @@ -4027,7 +4028,7 @@ struct ib_mr *bnxt_re_get_dma_mr(struct ib_pd *ib_pd, int mr_access_flags) mr->qplib_mr.hwq.level = PBL_LVL_MAX; mr->qplib_mr.total_size = -1; /* Infinte length */ rc = bnxt_qplib_reg_mr(&rdev->qplib_res, &mr->qplib_mr, NULL, 0, - PAGE_SIZE); + PAGE_SIZE, false); if (rc) goto fail_mr; @@ -4257,7 +4258,8 @@ static struct ib_mr *__bnxt_re_user_reg_mr(struct ib_pd *ib_pd, u64 length, u64 umem_pgs = ib_umem_num_dma_blocks(umem, page_size); rc = bnxt_qplib_reg_mr(&rdev->qplib_res, &mr->qplib_mr, umem, - umem_pgs, page_size); + umem_pgs, page_size, + _is_alloc_mr_unified(rdev->dev_attr->dev_cap_flags)); if (rc) { ibdev_err(&rdev->ibdev, "Failed to register user MR - rc = %d\n", rc); rc = -EIO; diff --git a/drivers/infiniband/hw/bnxt_re/qplib_sp.c b/drivers/infiniband/hw/bnxt_re/qplib_sp.c index a9afac2cbb7cf..408a34df26672 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_sp.c +++ b/drivers/infiniband/hw/bnxt_re/qplib_sp.c @@ -578,7 +578,7 @@ int bnxt_qplib_dereg_mrw(struct bnxt_qplib_res *res, struct bnxt_qplib_mrw *mrw, } int bnxt_qplib_reg_mr(struct bnxt_qplib_res *res, struct bnxt_qplib_mrw *mr, - struct ib_umem *umem, int num_pbls, u32 buf_pg_size) + struct ib_umem *umem, int num_pbls, u32 buf_pg_size, bool unified_mr) { struct bnxt_qplib_rcfw *rcfw = res->rcfw; struct bnxt_qplib_hwq_attr hwq_attr = {}; @@ -640,7 +640,7 @@ int bnxt_qplib_reg_mr(struct bnxt_qplib_res *res, struct bnxt_qplib_mrw *mr, req.access = (mr->access_flags & BNXT_QPLIB_MR_ACCESS_MASK); req.va = cpu_to_le64(mr->va); req.key = cpu_to_le32(mr->lkey); - if (_is_alloc_mr_unified(res->dattr->dev_cap_flags)) + if (unified_mr) req.key = cpu_to_le32(mr->pd->id); req.flags = cpu_to_le16(mr->flags); req.mr_size = cpu_to_le64(mr->total_size); @@ -651,7 +651,7 @@ int bnxt_qplib_reg_mr(struct bnxt_qplib_res *res, struct bnxt_qplib_mrw *mr, if (rc) goto fail; - if (_is_alloc_mr_unified(res->dattr->dev_cap_flags)) { + if (unified_mr) { mr->lkey = le32_to_cpu(resp.xid); mr->rkey = mr->lkey; } diff --git a/drivers/infiniband/hw/bnxt_re/qplib_sp.h b/drivers/infiniband/hw/bnxt_re/qplib_sp.h index 147b5d9c03138..5a45c55c6464c 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_sp.h +++ b/drivers/infiniband/hw/bnxt_re/qplib_sp.h @@ -341,7 +341,7 @@ int bnxt_qplib_alloc_mrw(struct bnxt_qplib_res *res, int bnxt_qplib_dereg_mrw(struct bnxt_qplib_res *res, struct bnxt_qplib_mrw *mrw, bool block); int bnxt_qplib_reg_mr(struct bnxt_qplib_res *res, struct bnxt_qplib_mrw *mr, - struct ib_umem *umem, int num_pbls, u32 buf_pg_size); + struct ib_umem *umem, int num_pbls, u32 buf_pg_size, bool unified_mr); int bnxt_qplib_free_mrw(struct bnxt_qplib_res *res, struct bnxt_qplib_mrw *mr); int bnxt_qplib_alloc_fast_reg_mr(struct bnxt_qplib_res *res, struct bnxt_qplib_mrw *mr, int max); From aa9dc3d80dd588c94f1abe9b9fa50576f2dd0ff6 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Fri, 21 Nov 2025 13:36:03 +0800 Subject: [PATCH 0755/2333] crypto: ahash - Fix crypto_ahash_import with partial block data [ Upstream commit b0356b75f42fde15d4be268c5891f2cee6eb65bf ] Restore the partial block buffer in crypto_ahash_import by copying it. Check whether the partial block buffer exceeds the maximum size and return -EOVERFLOW if it does. Zero the partial block buffer in crypto_ahash_import_core. Reported-by: T Pratham Tested-by: T Pratham Fixes: 9d7a0ab1c753 ("crypto: ahash - Handle partial blocks in API") Signed-off-by: Herbert Xu Signed-off-by: Sasha Levin --- crypto/ahash.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/crypto/ahash.c b/crypto/ahash.c index dfb4f5476428f..819b484a1a003 100644 --- a/crypto/ahash.c +++ b/crypto/ahash.c @@ -661,6 +661,12 @@ int crypto_ahash_import_core(struct ahash_request *req, const void *in) in); if (crypto_ahash_get_flags(tfm) & CRYPTO_TFM_NEED_KEY) return -ENOKEY; + if (crypto_ahash_block_only(tfm)) { + unsigned int reqsize = crypto_ahash_reqsize(tfm); + u8 *buf = ahash_request_ctx(req); + + buf[reqsize - 1] = 0; + } return crypto_ahash_alg(tfm)->import_core(req, in); } EXPORT_SYMBOL_GPL(crypto_ahash_import_core); @@ -674,10 +680,14 @@ int crypto_ahash_import(struct ahash_request *req, const void *in) if (crypto_ahash_get_flags(tfm) & CRYPTO_TFM_NEED_KEY) return -ENOKEY; if (crypto_ahash_block_only(tfm)) { + unsigned int plen = crypto_ahash_blocksize(tfm) + 1; unsigned int reqsize = crypto_ahash_reqsize(tfm); + unsigned int ss = crypto_ahash_statesize(tfm); u8 *buf = ahash_request_ctx(req); - buf[reqsize - 1] = 0; + memcpy(buf + reqsize - plen, in + ss - plen, plen); + if (buf[reqsize - 1] >= plen) + return -EOVERFLOW; } return crypto_ahash_alg(tfm)->import(req, in); } From fd9c3a1c963f4bb92435df4fd538d917023aed86 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Fri, 21 Nov 2025 13:54:20 +0800 Subject: [PATCH 0756/2333] crypto: ahash - Zero positive err value in ahash_update_finish [ Upstream commit ebbdf6466b30e3b37f3b360826efd21f0633fb9e ] The partial block length returned by a block-only driver should not be passed up to the caller since ahash itself deals with the partial block data. Set err to zero in ahash_update_finish if it was positive. Reported-by: T Pratham Tested-by: T Pratham Fixes: 9d7a0ab1c753 ("crypto: ahash - Handle partial blocks in API") Signed-off-by: Herbert Xu Signed-off-by: Sasha Levin --- crypto/ahash.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/crypto/ahash.c b/crypto/ahash.c index 819b484a1a003..66492ae75fcfb 100644 --- a/crypto/ahash.c +++ b/crypto/ahash.c @@ -423,7 +423,11 @@ static int ahash_update_finish(struct ahash_request *req, int err) req->nbytes += nonzero - blen; - blen = err < 0 ? 0 : err + nonzero; + blen = 0; + if (err >= 0) { + blen = err + nonzero; + err = 0; + } if (ahash_request_isvirt(req)) memcpy(buf, req->svirt + req->nbytes - blen, blen); else From 23ca40088490b535f473273b7e522c364cb1f471 Mon Sep 17 00:00:00 2001 From: Baojun Xu Date: Mon, 24 Nov 2025 11:15:42 +0800 Subject: [PATCH 0757/2333] ASoC: tas2781: Correct the wrong chip ID for reset variable check [ Upstream commit 34b78ddd78428e66a7f08f71763258723eae2306 ] The new variable of reset was added for TAS58XX on TAS5825 first. And TAS5802/5815... was added later, so this reset variable check should be changed to lowest chip of TAS58XX. Fixes: 53a3c6e22283 ("ASoC: tas2781: Support more newly-released amplifiers tas58xx in the driver") Signed-off-by: Baojun Xu Link: https://patch.msgid.link/20251124031542.2793-1-baojun.xu@ti.com Signed-off-by: Mark Brown Signed-off-by: Sasha Levin --- sound/soc/codecs/tas2781-comlib-i2c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/tas2781-comlib-i2c.c b/sound/soc/codecs/tas2781-comlib-i2c.c index b3fd7350143bd..e24d56a14cfda 100644 --- a/sound/soc/codecs/tas2781-comlib-i2c.c +++ b/sound/soc/codecs/tas2781-comlib-i2c.c @@ -320,7 +320,7 @@ void tasdevice_reset(struct tasdevice_priv *tas_dev) for (i = 0; i < tas_dev->ndev; i++) { ret = tasdevice_dev_write(tas_dev, i, TASDEVICE_REG_SWRESET, - tas_dev->chip_id >= TAS5825 ? + tas_dev->chip_id >= TAS5802 ? TAS5825_REG_SWRESET_RESET : TASDEVICE_REG_SWRESET_RESET); if (ret < 0) From 791520a8e54e2a3ed3c4ad09c764be865deaaf01 Mon Sep 17 00:00:00 2001 From: Shenghao Ding Date: Sat, 22 Nov 2025 07:44:27 +0800 Subject: [PATCH 0758/2333] ASoC: tas2781: correct the wrong period [ Upstream commit 950167a99dfd27eeaf177092908c598a31c79a7e ] A wrong preiod at the end of the sentence was reported by one of my customers. Their thorough code review is greatly appreciated. Fixes: 49e2e353fb0d ("ASoC: tas2781: Add Calibration Kcontrols for Chromebook") Signed-off-by: Shenghao Ding Link: https://patch.msgid.link/20251121234427.402-1-shenghao-ding@ti.com Signed-off-by: Mark Brown Signed-off-by: Sasha Levin --- sound/soc/codecs/tas2781-i2c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/tas2781-i2c.c b/sound/soc/codecs/tas2781-i2c.c index 8f37aa00e62ee..a3b4d2c3b4789 100644 --- a/sound/soc/codecs/tas2781-i2c.c +++ b/sound/soc/codecs/tas2781-i2c.c @@ -1391,7 +1391,7 @@ static int tasdevice_create_cali_ctrls(struct tasdevice_priv *priv) /* * Alloc kcontrol via devm_kzalloc(), which don't manually - * free the kcontrol。 + * free the kcontrol. */ cali_ctrls = devm_kcalloc(priv->dev, nctrls, sizeof(cali_ctrls[0]), GFP_KERNEL); From b8f34c1c5c4f5130c20e3253c95ba1d844d402b9 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 29 Sep 2025 13:17:23 +0200 Subject: [PATCH 0759/2333] wifi: mt76: mt7996: fix null pointer deref in mt7996_conf_tx() [ Upstream commit 79277f8ad15ec5f255ed0e1427c7a8a3e94e7f52 ] If a link does not have an assigned channel yet, mt7996_vif_link returns NULL. We still need to store the updated queue settings in that case, and apply them later. Move the location of the queue params to within struct mt7996_vif_link. Fixes: c0df2f0caa8d ("wifi: mt76: mt7996: prepare mt7996_mcu_set_tx for MLO support") Acked-by: Lorenzo Bianconi Link: https://patch.msgid.link/20250929111723.52486-1-nbd@nbd.name Signed-off-by: Felix Fietkau Signed-off-by: Sasha Levin --- drivers/net/wireless/mediatek/mt76/mt7996/main.c | 6 +++--- drivers/net/wireless/mediatek/mt76/mt7996/mcu.c | 5 ++++- drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h | 7 ++++++- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c index 581314368c5ba..b53ca702591c6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c @@ -665,8 +665,8 @@ mt7996_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, unsigned int link_id, u16 queue, const struct ieee80211_tx_queue_params *params) { - struct mt7996_dev *dev = mt7996_hw_dev(hw); - struct mt7996_vif_link *mlink = mt7996_vif_link(dev, vif, link_id); + struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; + struct mt7996_vif_link_info *link_info = &mvif->link_info[link_id]; static const u8 mq_to_aci[] = { [IEEE80211_AC_VO] = 3, [IEEE80211_AC_VI] = 2, @@ -675,7 +675,7 @@ mt7996_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, }; /* firmware uses access class index */ - mlink->queue_params[mq_to_aci[queue]] = *params; + link_info->queue_params[mq_to_aci[queue]] = *params; /* no need to update right away, we'll get BSS_CHANGED_QOS */ return 0; diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c index 0347ee0c2dd75..afa6a43bd51e5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c @@ -3414,6 +3414,9 @@ int mt7996_mcu_set_tx(struct mt7996_dev *dev, struct ieee80211_vif *vif, #define WMM_PARAM_SET (WMM_AIFS_SET | WMM_CW_MIN_SET | \ WMM_CW_MAX_SET | WMM_TXOP_SET) struct mt7996_vif_link *link = mt7996_vif_conf_link(dev, vif, link_conf); + struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; + unsigned int link_id = link_conf->link_id; + struct mt7996_vif_link_info *link_info = &mvif->link_info[link_id]; struct { u8 bss_idx; u8 __rsv[3]; @@ -3431,7 +3434,7 @@ int mt7996_mcu_set_tx(struct mt7996_dev *dev, struct ieee80211_vif *vif, skb_put_data(skb, &hdr, sizeof(hdr)); for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { - struct ieee80211_tx_queue_params *q = &link->queue_params[ac]; + struct ieee80211_tx_queue_params *q = &link_info->queue_params[ac]; struct edca *e; struct tlv *tlv; diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h index 8ec2acdb33193..718e4d4ad85f2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h @@ -253,16 +253,21 @@ struct mt7996_vif_link { struct mt7996_sta_link msta_link; struct mt7996_phy *phy; - struct ieee80211_tx_queue_params queue_params[IEEE80211_NUM_ACS]; struct cfg80211_bitrate_mask bitrate_mask; u8 mld_idx; }; +struct mt7996_vif_link_info { + struct ieee80211_tx_queue_params queue_params[IEEE80211_NUM_ACS]; +}; + struct mt7996_vif { struct mt7996_vif_link deflink; /* must be first */ struct mt76_vif_data mt76; + struct mt7996_vif_link_info link_info[IEEE80211_MLD_MAX_NUM_LINKS]; + u8 mld_group_idx; u8 mld_remap_idx; }; From cbeca0b7ea207028036fa365ca7441c7720891c2 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Wed, 24 Sep 2025 15:51:39 +0200 Subject: [PATCH 0760/2333] wifi: mt76: mt7996: Remove unnecessary link_id checks in mt7996_tx [ Upstream commit 084922069ceac4d594c06b76a80352139fd15f4d ] Remove unnecessary link_id checks in mt7996_tx routine since if the link identifier provided by mac80211 is unspecified the value will be overwritten at the beginning on the function. Fixes: f940c9b7aef6 ("wifi: mt76: mt7996: Set proper link destination address in mt7996_tx()") Signed-off-by: Lorenzo Bianconi Link: https://patch.msgid.link/20250924-mt76_tx_unnecessary-check-v1-1-e595930a5662@kernel.org Signed-off-by: Felix Fietkau Signed-off-by: Sasha Levin --- drivers/net/wireless/mediatek/mt76/mt7996/main.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c index b53ca702591c6..2b52d057287a1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c @@ -1339,12 +1339,10 @@ static void mt7996_tx(struct ieee80211_hw *hw, } if (mvif) { - struct mt76_vif_link *mlink = &mvif->deflink.mt76; + struct mt76_vif_link *mlink; - if (link_id < IEEE80211_LINK_UNSPECIFIED) - mlink = rcu_dereference(mvif->mt76.link[link_id]); - - if (mlink->wcid) + mlink = rcu_dereference(mvif->mt76.link[link_id]); + if (mlink && mlink->wcid) wcid = mlink->wcid; if (mvif->mt76.roc_phy && @@ -1352,7 +1350,7 @@ static void mt7996_tx(struct ieee80211_hw *hw, mphy = mvif->mt76.roc_phy; if (mphy->roc_link) wcid = mphy->roc_link->wcid; - } else { + } else if (mlink) { mphy = mt76_vif_link_phy(mlink); } } @@ -1362,7 +1360,7 @@ static void mt7996_tx(struct ieee80211_hw *hw, goto unlock; } - if (msta && link_id < IEEE80211_LINK_UNSPECIFIED) { + if (msta) { struct mt7996_sta_link *msta_link; msta_link = rcu_dereference(msta->link[link_id]); From d582d0e988d696698c94edf097062bb987ae592c Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Wed, 8 Oct 2025 12:41:48 +0200 Subject: [PATCH 0761/2333] wifi: mt76: wed: use proper wed reference in mt76 wed driver callabacks [ Upstream commit 385aab8fccd7a8746b9f1a17f3c1e38498a14bc7 ] MT7996 driver can use both wed and wed_hif2 devices to offload traffic from/to the wireless NIC. In the current codebase we assume to always use the primary wed device in wed callbacks resulting in the following crash if the hw runs wed_hif2 (e.g. 6GHz link). [ 297.455876] Unable to handle kernel read from unreadable memory at virtual address 000000000000080a [ 297.464928] Mem abort info: [ 297.467722] ESR = 0x0000000096000005 [ 297.471461] EC = 0x25: DABT (current EL), IL = 32 bits [ 297.476766] SET = 0, FnV = 0 [ 297.479809] EA = 0, S1PTW = 0 [ 297.482940] FSC = 0x05: level 1 translation fault [ 297.487809] Data abort info: [ 297.490679] ISV = 0, ISS = 0x00000005, ISS2 = 0x00000000 [ 297.496156] CM = 0, WnR = 0, TnD = 0, TagAccess = 0 [ 297.501196] GCS = 0, Overlay = 0, DirtyBit = 0, Xs = 0 [ 297.506500] user pgtable: 4k pages, 39-bit VAs, pgdp=0000000107480000 [ 297.512927] [000000000000080a] pgd=08000001097fb003, p4d=08000001097fb003, pud=08000001097fb003, pmd=0000000000000000 [ 297.523532] Internal error: Oops: 0000000096000005 [#1] SMP [ 297.715393] CPU: 2 UID: 0 PID: 45 Comm: kworker/u16:2 Tainted: G O 6.12.50 #0 [ 297.723908] Tainted: [O]=OOT_MODULE [ 297.727384] Hardware name: Banana Pi BPI-R4 (2x SFP+) (DT) [ 297.732857] Workqueue: nf_ft_offload_del nf_flow_rule_route_ipv6 [nf_flow_table] [ 297.740254] pstate: 60400005 (nZCv daif +PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 297.747205] pc : mt76_wed_offload_disable+0x64/0xa0 [mt76] [ 297.752688] lr : mtk_wed_flow_remove+0x58/0x80 [ 297.757126] sp : ffffffc080fe3ae0 [ 297.760430] x29: ffffffc080fe3ae0 x28: ffffffc080fe3be0 x27: 00000000deadbef7 [ 297.767557] x26: ffffff80c5ebca00 x25: 0000000000000001 x24: ffffff80c85f4c00 [ 297.774683] x23: ffffff80c1875b78 x22: ffffffc080d42cd0 x21: ffffffc080660018 [ 297.781809] x20: ffffff80c6a076d0 x19: ffffff80c6a043c8 x18: 0000000000000000 [ 297.788935] x17: 0000000000000000 x16: 0000000000000001 x15: 0000000000000000 [ 297.796060] x14: 0000000000000019 x13: ffffff80c0ad8ec0 x12: 00000000fa83b2da [ 297.803185] x11: ffffff80c02700c0 x10: ffffff80c0ad8ec0 x9 : ffffff81fef96200 [ 297.810311] x8 : ffffff80c02700c0 x7 : ffffff80c02700d0 x6 : 0000000000000002 [ 297.817435] x5 : 0000000000000400 x4 : 0000000000000000 x3 : 0000000000000000 [ 297.824561] x2 : 0000000000000001 x1 : 0000000000000800 x0 : ffffff80c6a063c8 [ 297.831686] Call trace: [ 297.834123] mt76_wed_offload_disable+0x64/0xa0 [mt76] [ 297.839254] mtk_wed_flow_remove+0x58/0x80 [ 297.843342] mtk_flow_offload_cmd+0x434/0x574 [ 297.847689] mtk_wed_setup_tc_block_cb+0x30/0x40 [ 297.852295] nf_flow_offload_ipv6_hook+0x7f4/0x964 [nf_flow_table] [ 297.858466] nf_flow_rule_route_ipv6+0x438/0x4a4 [nf_flow_table] [ 297.864463] process_one_work+0x174/0x300 [ 297.868465] worker_thread+0x278/0x430 [ 297.872204] kthread+0xd8/0xdc [ 297.875251] ret_from_fork+0x10/0x20 [ 297.878820] Code: 928b5ae0 8b000273 91400a60 f943fa61 (79401421) [ 297.884901] ---[ end trace 0000000000000000 ]--- Fix the issue detecting the proper wed reference to use running wed callabacks. Fixes: 83eafc9251d6 ("wifi: mt76: mt7996: add wed tx support") Tested-by: Daniel Pawlik Tested-by: Matteo Croce Signed-off-by: Lorenzo Bianconi Link: https://patch.msgid.link/20251008-wed-fixes-v1-1-8f7678583385@kernel.org Signed-off-by: Felix Fietkau Signed-off-by: Sasha Levin --- drivers/net/wireless/mediatek/mt76/mt76.h | 9 +++++++++ drivers/net/wireless/mediatek/mt76/mt7996/mmio.c | 1 + drivers/net/wireless/mediatek/mt76/wed.c | 10 +++++----- include/linux/soc/mediatek/mtk_wed.h | 1 + 4 files changed, 16 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index e0d50b58cd012..7753afa3d883d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -1252,6 +1252,15 @@ static inline int mt76_wed_dma_setup(struct mt76_dev *dev, struct mt76_queue *q, #define mt76_dereference(p, dev) \ rcu_dereference_protected(p, lockdep_is_held(&(dev)->mutex)) +static inline struct mt76_dev *mt76_wed_to_dev(struct mtk_wed_device *wed) +{ +#ifdef CONFIG_NET_MEDIATEK_SOC_WED + if (wed->wlan.hif2) + return container_of(wed, struct mt76_dev, mmio.wed_hif2); +#endif /* CONFIG_NET_MEDIATEK_SOC_WED */ + return container_of(wed, struct mt76_dev, mmio.wed); +} + static inline struct mt76_wcid * __mt76_wcid_ptr(struct mt76_dev *dev, u16 idx) { diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c index d14b626ee5115..80db102ed809c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c @@ -595,6 +595,7 @@ int mt7996_mmio_wed_init(struct mt7996_dev *dev, void *pdev_ptr, wed->wlan.nbuf = MT7996_HW_TOKEN_SIZE; wed->wlan.token_start = MT7996_TOKEN_SIZE - wed->wlan.nbuf; + wed->wlan.hif2 = hif2; wed->wlan.amsdu_max_subframes = 8; wed->wlan.amsdu_max_len = 1536; diff --git a/drivers/net/wireless/mediatek/mt76/wed.c b/drivers/net/wireless/mediatek/mt76/wed.c index 907a8e43e72ad..fbd7e59c73aaf 100644 --- a/drivers/net/wireless/mediatek/mt76/wed.c +++ b/drivers/net/wireless/mediatek/mt76/wed.c @@ -8,7 +8,7 @@ void mt76_wed_release_rx_buf(struct mtk_wed_device *wed) { - struct mt76_dev *dev = container_of(wed, struct mt76_dev, mmio.wed); + struct mt76_dev *dev = mt76_wed_to_dev(wed); int i; for (i = 0; i < dev->rx_token_size; i++) { @@ -31,8 +31,8 @@ EXPORT_SYMBOL_GPL(mt76_wed_release_rx_buf); #ifdef CONFIG_NET_MEDIATEK_SOC_WED u32 mt76_wed_init_rx_buf(struct mtk_wed_device *wed, int size) { - struct mt76_dev *dev = container_of(wed, struct mt76_dev, mmio.wed); struct mtk_wed_bm_desc *desc = wed->rx_buf_ring.desc; + struct mt76_dev *dev = mt76_wed_to_dev(wed); struct mt76_queue *q = &dev->q_rx[MT_RXQ_MAIN]; struct mt76_txwi_cache *t = NULL; int i; @@ -80,7 +80,7 @@ EXPORT_SYMBOL_GPL(mt76_wed_init_rx_buf); int mt76_wed_offload_enable(struct mtk_wed_device *wed) { - struct mt76_dev *dev = container_of(wed, struct mt76_dev, mmio.wed); + struct mt76_dev *dev = mt76_wed_to_dev(wed); spin_lock_bh(&dev->token_lock); dev->token_size = wed->wlan.token_start; @@ -164,7 +164,7 @@ EXPORT_SYMBOL_GPL(mt76_wed_dma_setup); void mt76_wed_offload_disable(struct mtk_wed_device *wed) { - struct mt76_dev *dev = container_of(wed, struct mt76_dev, mmio.wed); + struct mt76_dev *dev = mt76_wed_to_dev(wed); spin_lock_bh(&dev->token_lock); dev->token_size = dev->drv->token_size; @@ -174,7 +174,7 @@ EXPORT_SYMBOL_GPL(mt76_wed_offload_disable); void mt76_wed_reset_complete(struct mtk_wed_device *wed) { - struct mt76_dev *dev = container_of(wed, struct mt76_dev, mmio.wed); + struct mt76_dev *dev = mt76_wed_to_dev(wed); complete(&dev->mmio.wed_reset_complete); } diff --git a/include/linux/soc/mediatek/mtk_wed.h b/include/linux/soc/mediatek/mtk_wed.h index c4ff6bab176db..3fa93bd650044 100644 --- a/include/linux/soc/mediatek/mtk_wed.h +++ b/include/linux/soc/mediatek/mtk_wed.h @@ -154,6 +154,7 @@ struct mtk_wed_device { bool wcid_512; bool hw_rro; bool msi; + bool hif2; u16 token_start; unsigned int nbuf; From d2d11298dfc3eb35872fea9226e294fac445e55a Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 14 Oct 2025 15:28:53 +0200 Subject: [PATCH 0762/2333] wifi: mt76: mt7996: Remove useless check in mt7996_msdu_page_get_from_cache() [ Upstream commit 2157e49892c5eae210b8fa6ee8672bd9d0ffa4b5 ] Get rid of useless null-pointer check in mt7996_msdu_page_get_from_cache since we have already verfied the list is not empty. Fixes: b1e58e137b616 ("wifi: mt76: mt7996: Introduce RRO MSDU callbacks") Reported-by: kernel test robot Closes: https://lore.kernel.org/r/202510100155.MS0IXhzm-lkp@intel.com/ Signed-off-by: Lorenzo Bianconi Link: https://patch.msgid.link/20251014-mt7996_msdu_page_get_from_cache-remove-null-ptr-check-v1-1-fbeb7881e192@kernel.org Signed-off-by: Felix Fietkau Signed-off-by: Sasha Levin --- drivers/net/wireless/mediatek/mt76/mt7996/mac.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c index 9501def3e0e3e..284f2eea71e5b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c @@ -1681,8 +1681,7 @@ mt7996_msdu_page_get_from_cache(struct mt7996_dev *dev) if (!list_empty(&dev->wed_rro.page_cache)) { p = list_first_entry(&dev->wed_rro.page_cache, struct mt7996_msdu_page, list); - if (p) - list_del(&p->list); + list_del(&p->list); } spin_unlock(&dev->wed_rro.lock); From 2cde732373a734c1d68f38e83344a49f5f4a2f54 Mon Sep 17 00:00:00 2001 From: Fedor Pchelkin Date: Mon, 27 Oct 2025 14:18:39 +0300 Subject: [PATCH 0763/2333] Revert "wifi: mt76: mt792x: improve monitor interface handling" [ Upstream commit cdb2941a516cf06929293604e2e0f4c1d6f3541e ] This reverts commit 55e95ce469d0c61041bae48b2ebb7fcbf6d1ba7f. mt792x drivers don't seem to support multi-radio devices yet. At least they don't mess with `struct wiphy_radio` at the moment. Packet capturing on monitor interface doesn't work after the blamed patch: tcpdump -i wls6mon -n -vvv Revert the NO_VIRTUAL_MONITOR feature for now to resolve the issue. Found by Linux Verification Center (linuxtesting.org). Fixes: 55e95ce469d0 ("wifi: mt76: mt792x: improve monitor interface handling") Signed-off-by: Fedor Pchelkin Link: https://patch.msgid.link/20251027111843.38975-1-pchelkin@ispras.ru Signed-off-by: Felix Fietkau Signed-off-by: Sasha Levin --- drivers/net/wireless/mediatek/mt76/mt792x_core.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_core.c b/drivers/net/wireless/mediatek/mt76/mt792x_core.c index c0e56541a9547..9cad572c34a38 100644 --- a/drivers/net/wireless/mediatek/mt76/mt792x_core.c +++ b/drivers/net/wireless/mediatek/mt76/mt792x_core.c @@ -688,7 +688,6 @@ int mt792x_init_wiphy(struct ieee80211_hw *hw) ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS); ieee80211_hw_set(hw, SUPPORTS_VHT_EXT_NSS_BW); ieee80211_hw_set(hw, CONNECTION_MONITOR); - ieee80211_hw_set(hw, NO_VIRTUAL_MONITOR); ieee80211_hw_set(hw, SUPPORTS_MULTI_BSSID); ieee80211_hw_set(hw, SUPPORTS_ONLY_HE_MULTI_BSSID); From 74bb080717a3dc9f26cfc4874c69181910f54042 Mon Sep 17 00:00:00 2001 From: StanleyYP Wang Date: Thu, 6 Nov 2025 14:41:52 +0800 Subject: [PATCH 0764/2333] wifi: mt76: mt7996: fix max nss value when getting rx chainmask [ Upstream commit 361b59b6be7c33c43b619d5cada394efc0f3b398 ] Since wiphy->available_antennas_tx now accumulates the chainmask of all the radios of a wiphy, use phy->orig_antenna_mask to get the original max nss for comparison. Fixes: 69d54ce7491d ("wifi: mt76: mt7996: switch to single multi-radio wiphy") Signed-off-by: StanleyYP Wang Signed-off-by: Shayne Chen Link: https://patch.msgid.link/20251106064203.1000505-1-shayne.chen@mediatek.com Signed-off-by: Felix Fietkau Signed-off-by: Sasha Levin --- drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h index 718e4d4ad85f2..1727e73a99ce6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h @@ -786,7 +786,7 @@ void mt7996_memcpy_fromio(struct mt7996_dev *dev, void *buf, u32 offset, static inline u16 mt7996_rx_chainmask(struct mt7996_phy *phy) { - int max_nss = hweight8(phy->mt76->hw->wiphy->available_antennas_tx); + int max_nss = hweight16(phy->orig_antenna_mask); int cur_nss = hweight8(phy->mt76->antenna_mask); u16 tx_chainmask = phy->mt76->chainmask; From 95bb36f8d6b30829c4aaacddcbe3213e96acd04c Mon Sep 17 00:00:00 2001 From: Howard Hsu Date: Thu, 6 Nov 2025 14:41:54 +0800 Subject: [PATCH 0765/2333] wifi: mt76: mt7996: fix implicit beamforming support for mt7992 [ Upstream commit 5d86765828b47444908a8689f2625872e8dac48f ] Fix the ibf_timeout field for mt7996, mt7992 and mt7990 chipsets. For the mt7992, this value shall be set as 0xff, while the others shall be set as 0x18. Fixes: ad4c9a8a9803 ("wifi: mt76: mt7996: add implicit beamforming support for mt7992") Signed-off-by: Howard Hsu Signed-off-by: Shayne Chen Link: https://patch.msgid.link/20251106064203.1000505-3-shayne.chen@mediatek.com Signed-off-by: Felix Fietkau Signed-off-by: Sasha Levin --- drivers/net/wireless/mediatek/mt76/mt7996/mcu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c index afa6a43bd51e5..9af3c48707ab7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c @@ -1822,8 +1822,8 @@ mt7996_mcu_sta_bfer_tlv(struct mt7996_dev *dev, struct sk_buff *skb, bf->ibf_nrow = tx_ant; if (link_sta->eht_cap.has_eht || link_sta->he_cap.has_he) - bf->ibf_timeout = is_mt7996(&dev->mt76) ? MT7996_IBF_TIMEOUT : - MT7992_IBF_TIMEOUT; + bf->ibf_timeout = is_mt7992(&dev->mt76) ? MT7992_IBF_TIMEOUT : + MT7996_IBF_TIMEOUT; else if (!ebf && link_sta->bandwidth <= IEEE80211_STA_RX_BW_40 && !bf->ncol) bf->ibf_timeout = MT7996_IBF_TIMEOUT_LEGACY; else From ee94375d06b5db5f7f4943ddc9f2f763eaf7a978 Mon Sep 17 00:00:00 2001 From: Shayne Chen Date: Thu, 6 Nov 2025 14:41:56 +0800 Subject: [PATCH 0766/2333] wifi: mt76: mt7996: fix several fields in mt7996_mcu_bss_basic_tlv() [ Upstream commit bb705a606734e1ce0ff17a4f368a896757ba686d ] Fix several fields in mt7996_mcu_bss_basic_tlv() that were not obtained from the correct link. Without this patch, the MLD station interface does not function properly. Fixes: 34a41bfbcb71 ("wifi: mt76: mt7996: prepare mt7996_mcu_add_dev/bss_info for MLO support") Signed-off-by: Shayne Chen Acked-by: Lorenzo Bianconi Link: https://patch.msgid.link/20251106064203.1000505-5-shayne.chen@mediatek.com Signed-off-by: Felix Fietkau Signed-off-by: Sasha Levin --- .../net/wireless/mediatek/mt76/mt7996/mcu.c | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c index 9af3c48707ab7..21be88e76c655 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c @@ -1034,7 +1034,6 @@ mt7996_mcu_bss_basic_tlv(struct sk_buff *skb, struct mt76_connac_bss_basic_tlv *bss; u32 type = CONNECTION_INFRA_AP; u16 sta_wlan_idx = wlan_idx; - struct ieee80211_sta *sta; struct tlv *tlv; int idx; @@ -1045,14 +1044,18 @@ mt7996_mcu_bss_basic_tlv(struct sk_buff *skb, break; case NL80211_IFTYPE_STATION: if (enable) { + struct ieee80211_sta *sta; + rcu_read_lock(); - sta = ieee80211_find_sta(vif, vif->bss_conf.bssid); - /* TODO: enable BSS_INFO_UAPSD & BSS_INFO_PM */ + sta = ieee80211_find_sta(vif, link_conf->bssid); if (sta) { - struct mt76_wcid *wcid; + struct mt7996_sta *msta = (void *)sta->drv_priv; + struct mt7996_sta_link *msta_link; + int link_id = link_conf->link_id; - wcid = (struct mt76_wcid *)sta->drv_priv; - sta_wlan_idx = wcid->idx; + msta_link = rcu_dereference(msta->link[link_id]); + if (msta_link) + sta_wlan_idx = msta_link->wcid.idx; } rcu_read_unlock(); } @@ -1069,8 +1072,6 @@ mt7996_mcu_bss_basic_tlv(struct sk_buff *skb, tlv = mt7996_mcu_add_uni_tlv(skb, UNI_BSS_INFO_BASIC, sizeof(*bss)); bss = (struct mt76_connac_bss_basic_tlv *)tlv; - bss->bcn_interval = cpu_to_le16(link_conf->beacon_int); - bss->dtim_period = link_conf->dtim_period; bss->bmc_tx_wlan_idx = cpu_to_le16(wlan_idx); bss->sta_idx = cpu_to_le16(sta_wlan_idx); bss->conn_type = cpu_to_le32(type); @@ -1090,10 +1091,10 @@ mt7996_mcu_bss_basic_tlv(struct sk_buff *skb, memcpy(bss->bssid, link_conf->bssid, ETH_ALEN); bss->bcn_interval = cpu_to_le16(link_conf->beacon_int); - bss->dtim_period = vif->bss_conf.dtim_period; + bss->dtim_period = link_conf->dtim_period; bss->phymode = mt76_connac_get_phy_mode(phy, vif, chandef->chan->band, NULL); - bss->phymode_ext = mt76_connac_get_phy_mode_ext(phy, &vif->bss_conf, + bss->phymode_ext = mt76_connac_get_phy_mode_ext(phy, link_conf, chandef->chan->band); return 0; From d64e6f27260eef3df49c5c3950494b6e9d36caad Mon Sep 17 00:00:00 2001 From: Shayne Chen Date: Thu, 6 Nov 2025 14:41:57 +0800 Subject: [PATCH 0767/2333] wifi: mt76: mt7996: fix teardown command for an MLD peer [ Upstream commit e077071e7ac48d5453072f615d51629891c5b90d ] For an MLD peer, we only need to call the teardown command when removing the last link, and there's no need to call mt7996_mcu_add_sta() for the earlier links. Fixes: c1d6dd5d03eb ("wifi: mt76: mt7996: Add mt7996_mcu_teardown_mld_sta rouine") Signed-off-by: Shayne Chen Acked-by: Lorenzo Bianconi Link: https://patch.msgid.link/20251106064203.1000505-6-shayne.chen@mediatek.com Signed-off-by: Felix Fietkau Signed-off-by: Sasha Levin --- drivers/net/wireless/mediatek/mt76/mt7996/main.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c index 2b52d057287a1..aa46ea707b406 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c @@ -1206,13 +1206,13 @@ mt7996_mac_sta_event(struct mt7996_dev *dev, struct ieee80211_vif *vif, mt7996_mac_twt_teardown_flow(dev, link, msta_link, i); - if (sta->mlo && links == BIT(link_id)) /* last link */ - mt7996_mcu_teardown_mld_sta(dev, link, - msta_link); - else + if (!sta->mlo) mt7996_mcu_add_sta(dev, link_conf, link_sta, link, msta_link, CONN_STATE_DISCONNECT, false); + else if (sta->mlo && links == BIT(link_id)) /* last link */ + mt7996_mcu_teardown_mld_sta(dev, link, + msta_link); msta_link->wcid.sta_disabled = 1; msta_link->wcid.sta = 0; links = links & ~BIT(link_id); From e5c42efeb162c56e25f53c51ec31ee54691667f2 Mon Sep 17 00:00:00 2001 From: Shayne Chen Date: Thu, 6 Nov 2025 14:41:58 +0800 Subject: [PATCH 0768/2333] wifi: mt76: mt7996: set link_valid field when initializing wcid [ Upstream commit 7eaea3a8ba1e9bb58f87e3030f6ce18537e57e1f ] This ensures the upper layer uses the correct link ID during packet processing. Fixes: dd82a9e02c05 ("wifi: mt76: mt7996: Rely on mt7996_sta_link in sta_add/sta_remove callbacks") Signed-off-by: Shayne Chen Acked-by: Lorenzo Bianconi Link: https://patch.msgid.link/20251106064203.1000505-7-shayne.chen@mediatek.com Signed-off-by: Felix Fietkau Signed-off-by: Sasha Levin --- drivers/net/wireless/mediatek/mt76/mt7996/main.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c index aa46ea707b406..4e73854589558 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c @@ -343,6 +343,7 @@ int mt7996_vif_link_add(struct mt76_phy *mphy, struct ieee80211_vif *vif, INIT_LIST_HEAD(&msta_link->rc_list); msta_link->wcid.idx = idx; msta_link->wcid.link_id = link_conf->link_id; + msta_link->wcid.link_valid = ieee80211_vif_is_mld(vif); msta_link->wcid.tx_info |= MT_WCID_TX_INFO_SET; mt76_wcid_init(&msta_link->wcid, band_idx); @@ -984,6 +985,7 @@ mt7996_mac_sta_init_link(struct mt7996_dev *dev, msta_link->wcid.sta = 1; msta_link->wcid.idx = idx; msta_link->wcid.link_id = link_id; + msta_link->wcid.link_valid = !!sta->valid_links; msta_link->wcid.def_wcid = &msta->deflink.wcid; ewma_avg_signal_init(&msta_link->avg_ack_signal); From 9a43ed9ab800a9935eac8b0d264ea8d659a47db0 Mon Sep 17 00:00:00 2001 From: Shayne Chen Date: Thu, 6 Nov 2025 14:42:00 +0800 Subject: [PATCH 0769/2333] wifi: mt76: mt7996: fix MLD group index assignment [ Upstream commit 4fb3b4e7d1ca5453c6167816230370afc15f26bf ] Fix extender mode and MBSS issues caused by incorrect assignment of the MLD group and remap indices. Fixes: ed01c310eca9 ("wifi: mt76: mt7996: Fix mt7996_mcu_bss_mld_tlv routine") Signed-off-by: Shayne Chen Acked-by: Lorenzo Bianconi Link: https://patch.msgid.link/20251106064203.1000505-9-shayne.chen@mediatek.com Signed-off-by: Felix Fietkau Signed-off-by: Sasha Levin --- .../net/wireless/mediatek/mt76/mt7996/main.c | 58 +++++++++++++------ 1 file changed, 40 insertions(+), 18 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c index 4e73854589558..dc0fcf5cb7fb1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c @@ -90,9 +90,11 @@ static void mt7996_stop(struct ieee80211_hw *hw, bool suspend) { } -static inline int get_free_idx(u32 mask, u8 start, u8 end) +static inline int get_free_idx(u64 mask, u8 start, u8 end) { - return ffs(~mask & GENMASK(end, start)); + if (~mask & GENMASK_ULL(end, start)) + return __ffs64(~mask & GENMASK_ULL(end, start)) + 1; + return 0; } static int get_omac_idx(enum nl80211_iftype type, u64 mask) @@ -308,12 +310,6 @@ int mt7996_vif_link_add(struct mt76_phy *mphy, struct ieee80211_vif *vif, if (idx < 0) return -ENOSPC; - if (!dev->mld_idx_mask) { /* first link in the group */ - mvif->mld_group_idx = get_own_mld_idx(dev->mld_idx_mask, true); - mvif->mld_remap_idx = get_free_idx(dev->mld_remap_idx_mask, - 0, 15); - } - mld_idx = get_own_mld_idx(dev->mld_idx_mask, false); if (mld_idx < 0) return -ENOSPC; @@ -331,10 +327,6 @@ int mt7996_vif_link_add(struct mt76_phy *mphy, struct ieee80211_vif *vif, return ret; dev->mt76.vif_mask |= BIT_ULL(mlink->idx); - if (!dev->mld_idx_mask) { - dev->mld_idx_mask |= BIT_ULL(mvif->mld_group_idx); - dev->mld_remap_idx_mask |= BIT_ULL(mvif->mld_remap_idx); - } dev->mld_idx_mask |= BIT_ULL(link->mld_idx); phy->omac_mask |= BIT_ULL(mlink->omac_idx); @@ -424,11 +416,6 @@ void mt7996_vif_link_remove(struct mt76_phy *mphy, struct ieee80211_vif *vif, dev->mt76.vif_mask &= ~BIT_ULL(mlink->idx); dev->mld_idx_mask &= ~BIT_ULL(link->mld_idx); phy->omac_mask &= ~BIT_ULL(mlink->omac_idx); - if (!(dev->mld_idx_mask & ~BIT_ULL(mvif->mld_group_idx))) { - /* last link */ - dev->mld_idx_mask &= ~BIT_ULL(mvif->mld_group_idx); - dev->mld_remap_idx_mask &= ~BIT_ULL(mvif->mld_remap_idx); - } spin_lock_bh(&dev->mt76.sta_poll_lock); if (!list_empty(&msta_link->wcid.poll_list)) @@ -2217,7 +2204,42 @@ mt7996_change_vif_links(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 old_links, u16 new_links, struct ieee80211_bss_conf *old[IEEE80211_MLD_MAX_NUM_LINKS]) { - return 0; + struct mt7996_dev *dev = mt7996_hw_dev(hw); + struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; + int ret = 0; + + mutex_lock(&dev->mt76.mutex); + + if (!old_links) { + int idx; + + idx = get_own_mld_idx(dev->mld_idx_mask, true); + if (idx < 0) { + ret = -ENOSPC; + goto out; + } + mvif->mld_group_idx = idx; + dev->mld_idx_mask |= BIT_ULL(mvif->mld_group_idx); + + idx = get_free_idx(dev->mld_remap_idx_mask, 0, 15) - 1; + if (idx < 0) { + ret = -ENOSPC; + goto out; + } + mvif->mld_remap_idx = idx; + dev->mld_remap_idx_mask |= BIT_ULL(mvif->mld_remap_idx); + } + + if (new_links) + goto out; + + dev->mld_idx_mask &= ~BIT_ULL(mvif->mld_group_idx); + dev->mld_remap_idx_mask &= ~BIT_ULL(mvif->mld_remap_idx); + +out: + mutex_unlock(&dev->mt76.mutex); + + return ret; } static void From 7d6cd8f51ad8a632fdcf12fbdc93b93a27aa6ddf Mon Sep 17 00:00:00 2001 From: Shayne Chen Date: Thu, 6 Nov 2025 14:42:01 +0800 Subject: [PATCH 0770/2333] wifi: mt76: mt7996: fix MLO set key and group key issues [ Upstream commit e11be918d91e7d33ac4bad41dbe666a9abf1cfaa ] This patch fixes the following key issues: - Pass correct link BSS to mt7996_mcu_add_key(), and use HW beacon protection mode for mt7990 chipset - Do not do group key deletion for GTK and IGTK due to FW design, the delete key command will delete all group keys of a link BSS - For deleting BIGTK, FW adds a new flow, but the "sec->add" field should be filled with "SET_KEY". Note that if BIGTK is not deleted, it will cause beacon decryption issue when switching from an AP interface to a station interface Fixes: 0c45d52276fd ("wifi: mt76: mt7996: fix setting beacon protection keys") Co-developed-by: Allen Ye Signed-off-by: Allen Ye Co-developed-by: Peter Chiu Signed-off-by: Peter Chiu Signed-off-by: Shayne Chen Link: https://patch.msgid.link/20251106064203.1000505-10-shayne.chen@mediatek.com Signed-off-by: Felix Fietkau Signed-off-by: Sasha Levin --- .../net/wireless/mediatek/mt76/mt7996/mac.c | 7 +++- .../net/wireless/mediatek/mt76/mt7996/main.c | 5 +-- .../net/wireless/mediatek/mt76/mt7996/mcu.c | 35 +++++++++++++------ .../wireless/mediatek/mt76/mt7996/mt7996.h | 2 +- 4 files changed, 34 insertions(+), 15 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c index 284f2eea71e5b..fe31db5440a84 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c @@ -794,6 +794,7 @@ mt7996_mac_write_txwi_80211(struct mt7996_dev *dev, __le32 *txwi, u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK; __le16 fc = hdr->frame_control, sc = hdr->seq_ctrl; u16 seqno = le16_to_cpu(sc); + bool hw_bigtk = false; u8 fc_type, fc_stype; u32 val; @@ -819,7 +820,11 @@ mt7996_mac_write_txwi_80211(struct mt7996_dev *dev, __le32 *txwi, info->flags & IEEE80211_TX_CTL_USE_MINRATE) val |= MT_TXD1_FIXED_RATE; - if (key && multicast && ieee80211_is_robust_mgmt_frame(skb)) { + if (is_mt7990(&dev->mt76) && ieee80211_is_beacon(fc) && + (wcid->hw_key_idx2 == 6 || wcid->hw_key_idx2 == 7)) + hw_bigtk = true; + + if ((key && multicast && ieee80211_is_robust_mgmt_frame(skb)) || hw_bigtk) { val |= MT_TXD1_BIP; txwi[3] &= ~cpu_to_le32(MT_TXD3_PROTECT_FRAME); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c index dc0fcf5cb7fb1..beb455185f904 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c @@ -249,12 +249,13 @@ mt7996_set_hw_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, else if (idx == *wcid_keyidx) *wcid_keyidx = -1; - if (cmd != SET_KEY && sta) + /* only do remove key for BIGTK */ + if (cmd != SET_KEY && !is_bigtk) return 0; mt76_wcid_key_setup(&dev->mt76, &msta_link->wcid, key); - err = mt7996_mcu_add_key(&dev->mt76, vif, key, + err = mt7996_mcu_add_key(&dev->mt76, link, key, MCU_WMWA_UNI_CMD(STA_REC_UPDATE), &msta_link->wcid, cmd); diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c index 21be88e76c655..5bde9959bbb99 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c @@ -2527,7 +2527,7 @@ int mt7996_mcu_teardown_mld_sta(struct mt7996_dev *dev, } static int -mt7996_mcu_sta_key_tlv(struct mt76_wcid *wcid, +mt7996_mcu_sta_key_tlv(struct mt76_dev *dev, struct mt76_wcid *wcid, struct sk_buff *skb, struct ieee80211_key_conf *key, enum set_key_cmd cmd) @@ -2539,7 +2539,10 @@ mt7996_mcu_sta_key_tlv(struct mt76_wcid *wcid, tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_KEY_V2, sizeof(*sec)); sec = (struct sta_rec_sec_uni *)tlv; - sec->add = 0; + /* due to connac3 FW design, we only do remove key for BIGTK; even for + * removal, the field should be filled with SET_KEY + */ + sec->add = SET_KEY; sec->n_cipher = 1; sec_key = &sec->key[0]; sec_key->wlan_idx = cpu_to_le16(wcid->idx); @@ -2579,29 +2582,33 @@ mt7996_mcu_sta_key_tlv(struct mt76_wcid *wcid, case WLAN_CIPHER_SUITE_BIP_GMAC_256: sec_key->cipher_id = MCU_CIPHER_BCN_PROT_GMAC_256; break; + case WLAN_CIPHER_SUITE_BIP_CMAC_256: + if (!is_mt7990(dev)) + return -EOPNOTSUPP; + sec_key->cipher_id = MCU_CIPHER_BCN_PROT_CMAC_256; + break; default: return -EOPNOTSUPP; } - sec_key->bcn_mode = BP_SW_MODE; + sec_key->bcn_mode = is_mt7990(dev) ? BP_HW_MODE : BP_SW_MODE; return 0; } -int mt7996_mcu_add_key(struct mt76_dev *dev, struct ieee80211_vif *vif, +int mt7996_mcu_add_key(struct mt76_dev *dev, struct mt7996_vif_link *link, struct ieee80211_key_conf *key, int mcu_cmd, struct mt76_wcid *wcid, enum set_key_cmd cmd) { - struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv; struct sk_buff *skb; int ret; - skb = __mt76_connac_mcu_alloc_sta_req(dev, mvif, wcid, - MT7996_STA_UPDATE_MAX_SIZE); + skb = __mt76_connac_mcu_alloc_sta_req(dev, (struct mt76_vif_link *)link, + wcid, MT7996_STA_UPDATE_MAX_SIZE); if (IS_ERR(skb)) return PTR_ERR(skb); - ret = mt7996_mcu_sta_key_tlv(wcid, skb, key, cmd); + ret = mt7996_mcu_sta_key_tlv(dev, wcid, skb, key, cmd); if (ret) { dev_kfree_skb(skb); return ret; @@ -2721,12 +2728,18 @@ mt7996_mcu_beacon_mbss(struct sk_buff *rskb, struct sk_buff *skb, static void mt7996_mcu_beacon_cont(struct mt7996_dev *dev, struct ieee80211_bss_conf *link_conf, + struct mt7996_vif_link *link, struct sk_buff *rskb, struct sk_buff *skb, struct bss_bcn_content_tlv *bcn, struct ieee80211_mutable_offsets *offs) { - struct mt76_wcid *wcid = &dev->mt76.global_wcid; - u8 *buf; + u8 *buf, keyidx = link->msta_link.wcid.hw_key_idx2; + struct mt76_wcid *wcid; + + if (is_mt7990(&dev->mt76) && (keyidx == 6 || keyidx == 7)) + wcid = &link->msta_link.wcid; + else + wcid = &dev->mt76.global_wcid; bcn->pkt_len = cpu_to_le16(MT_TXD_SIZE + skb->len); bcn->tim_ie_pos = cpu_to_le16(offs->tim_offset); @@ -2801,7 +2814,7 @@ int mt7996_mcu_add_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif, info = IEEE80211_SKB_CB(skb); info->hw_queue |= FIELD_PREP(MT_TX_HW_QUEUE_PHY, mlink->band_idx); - mt7996_mcu_beacon_cont(dev, link_conf, rskb, skb, bcn, &offs); + mt7996_mcu_beacon_cont(dev, link_conf, link, rskb, skb, bcn, &offs); if (link_conf->bssid_indicator) mt7996_mcu_beacon_mbss(rskb, skb, bcn, &offs); mt7996_mcu_beacon_cntdwn(rskb, skb, &offs, link_conf->csa_active); diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h index 1727e73a99ce6..b942928c79e28 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h @@ -848,7 +848,7 @@ void mt7996_update_channel(struct mt76_phy *mphy); int mt7996_init_debugfs(struct mt7996_dev *dev); void mt7996_debugfs_rx_fw_monitor(struct mt7996_dev *dev, const void *data, int len); bool mt7996_debugfs_rx_log(struct mt7996_dev *dev, const void *data, int len); -int mt7996_mcu_add_key(struct mt76_dev *dev, struct ieee80211_vif *vif, +int mt7996_mcu_add_key(struct mt76_dev *dev, struct mt7996_vif_link *link, struct ieee80211_key_conf *key, int mcu_cmd, struct mt76_wcid *wcid, enum set_key_cmd cmd); int mt7996_mcu_bcn_prot_enable(struct mt7996_dev *dev, From 1a4b481a21ae3a84b3862963091698d299d8e63c Mon Sep 17 00:00:00 2001 From: Shayne Chen Date: Thu, 6 Nov 2025 14:42:02 +0800 Subject: [PATCH 0771/2333] wifi: mt76: mt7996: fix using wrong phy to start in mt7996_mac_restart() [ Upstream commit f1e9f369ae42ee433836b24467e645192d046a51 ] Pass the correct mt7996_phy to mt7996_run(). Fixes: 0a5df0ec47f7 ("wifi: mt76: mt7996: remove redundant per-phy mac80211 calls during restart") Signed-off-by: Shayne Chen Acked-by: Lorenzo Bianconi Link: https://patch.msgid.link/20251106064203.1000505-11-shayne.chen@mediatek.com Signed-off-by: Felix Fietkau Signed-off-by: Sasha Levin --- drivers/net/wireless/mediatek/mt76/mt7996/mac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c index fe31db5440a84..b06728a98a691 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c @@ -2341,7 +2341,7 @@ mt7996_mac_restart(struct mt7996_dev *dev) if (!test_bit(MT76_STATE_RUNNING, &phy->mt76->state)) continue; - ret = mt7996_run(&dev->phy); + ret = mt7996_run(phy); if (ret) goto out; } From b4b789d24319e9068bcb785f2ef6f8d487e2188b Mon Sep 17 00:00:00 2001 From: Shayne Chen Date: Thu, 6 Nov 2025 14:42:03 +0800 Subject: [PATCH 0772/2333] wifi: mt76: mt7996: fix EMI rings for RRO [ Upstream commit a4031fec9d0d230224a7edcefa3368c06c317148 ] The RRO EMI rings only need to be allocated when WED is not active. This patch fixes command timeout issue for the setting of WED off and RRO on. Fixes: 3a29164425e9 ("wifi: mt76: mt7996: Add SW path for HW-RRO v3.1") Co-developed-by: Rex Lu Signed-off-by: Rex Lu Signed-off-by: Shayne Chen Acked-by: Lorenzo Bianconi Link: https://patch.msgid.link/20251106064203.1000505-12-shayne.chen@mediatek.com Signed-off-by: Felix Fietkau Signed-off-by: Sasha Levin --- .../net/wireless/mediatek/mt76/mt7996/dma.c | 15 +++++++++------ .../net/wireless/mediatek/mt76/mt7996/init.c | 19 ++++++++++++++++--- 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/dma.c b/drivers/net/wireless/mediatek/mt76/mt7996/dma.c index 659015f93d323..7ed2f21b0e6db 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/dma.c @@ -512,12 +512,15 @@ int mt7996_dma_rro_init(struct mt7996_dev *dev) if (ret) return ret; - /* We need to set cpu idx pointer before resetting the EMI - * queues. - */ - mdev->q_rx[MT_RXQ_RRO_RXDMAD_C].emi_cpu_idx = - &dev->wed_rro.emi_rings_cpu.ptr->ring[0].idx; - mt76_queue_reset(dev, &mdev->q_rx[MT_RXQ_RRO_RXDMAD_C], true); + if (!mtk_wed_device_active(&mdev->mmio.wed)) { + /* We need to set cpu idx pointer before resetting the + * EMI queues. + */ + mdev->q_rx[MT_RXQ_RRO_RXDMAD_C].emi_cpu_idx = + &dev->wed_rro.emi_rings_cpu.ptr->ring[0].idx; + mt76_queue_reset(dev, &mdev->q_rx[MT_RXQ_RRO_RXDMAD_C], + true); + } goto start_hw_rro; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/init.c b/drivers/net/wireless/mediatek/mt76/mt7996/init.c index 5e95a36b42d16..b136b9a669769 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/init.c @@ -959,9 +959,10 @@ static int mt7996_wed_rro_init(struct mt7996_dev *dev) MT7996_RRO_MSDU_PG_SIZE_PER_CR); } - if (dev->mt76.hwrro_mode == MT76_HWRRO_V3_1) { + if (!mtk_wed_device_active(&dev->mt76.mmio.wed) && + dev->mt76.hwrro_mode == MT76_HWRRO_V3_1) { ptr = dmam_alloc_coherent(dev->mt76.dma_dev, - sizeof(dev->wed_rro.emi_rings_cpu.ptr), + sizeof(*dev->wed_rro.emi_rings_cpu.ptr), &dev->wed_rro.emi_rings_cpu.phy_addr, GFP_KERNEL); if (!ptr) @@ -970,7 +971,7 @@ static int mt7996_wed_rro_init(struct mt7996_dev *dev) dev->wed_rro.emi_rings_cpu.ptr = ptr; ptr = dmam_alloc_coherent(dev->mt76.dma_dev, - sizeof(dev->wed_rro.emi_rings_dma.ptr), + sizeof(*dev->wed_rro.emi_rings_dma.ptr), &dev->wed_rro.emi_rings_dma.phy_addr, GFP_KERNEL); if (!ptr) @@ -1036,6 +1037,18 @@ static void mt7996_wed_rro_free(struct mt7996_dev *dev) dev->wed_rro.msdu_pg[i].phy_addr); } + if (dev->wed_rro.emi_rings_cpu.ptr) + dmam_free_coherent(dev->mt76.dma_dev, + sizeof(*dev->wed_rro.emi_rings_cpu.ptr), + dev->wed_rro.emi_rings_cpu.ptr, + dev->wed_rro.emi_rings_cpu.phy_addr); + + if (dev->wed_rro.emi_rings_dma.ptr) + dmam_free_coherent(dev->mt76.dma_dev, + sizeof(*dev->wed_rro.emi_rings_dma.ptr), + dev->wed_rro.emi_rings_dma.ptr, + dev->wed_rro.emi_rings_dma.phy_addr); + if (!dev->wed_rro.session.ptr) return; From 46f0648e261c3775194bed3eb764d37e95429a90 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 14 Nov 2025 14:16:21 +0100 Subject: [PATCH 0773/2333] wifi: mt76: mt7996: grab mt76 mutex in mt7996_mac_sta_event() [ Upstream commit 5a4bcba26e9fbea87507a81ad891e70bb525014f ] Grab mt76 mutex in mt7996_mac_sta_event routine in order to rely on mt76_dereference() utility macro. Fixes: ecd72f9695e7e ("wifi: mt76: mt7996: Support MLO in mt7996_mac_sta_event()") Signed-off-by: Lorenzo Bianconi Tested-by: Ben Greear Link: https://patch.msgid.link/20251114-mt76-fix-missing-mtx-v1-1-259ebf11f654@kernel.org Signed-off-by: Felix Fietkau Signed-off-by: Sasha Levin --- drivers/net/wireless/mediatek/mt76/mt7996/main.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c index beb455185f904..ead56ce4c0362 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c @@ -1150,12 +1150,15 @@ mt7996_mac_sta_event(struct mt7996_dev *dev, struct ieee80211_vif *vif, unsigned long links = sta->valid_links; struct ieee80211_link_sta *link_sta; unsigned int link_id; + int err = 0; + + mutex_lock(&dev->mt76.mutex); for_each_sta_active_link(vif, sta, link_sta, link_id) { struct ieee80211_bss_conf *link_conf; struct mt7996_sta_link *msta_link; struct mt7996_vif_link *link; - int i, err; + int i; link_conf = link_conf_dereference_protected(vif, link_id); if (!link_conf) @@ -1175,12 +1178,12 @@ mt7996_mac_sta_event(struct mt7996_dev *dev, struct ieee80211_vif *vif, link, msta_link, CONN_STATE_CONNECT, true); if (err) - return err; + goto unlock; err = mt7996_mcu_add_rate_ctrl(dev, msta_link->sta, vif, link_id, false); if (err) - return err; + goto unlock; msta_link->wcid.tx_info |= MT_WCID_TX_INFO_SET; break; @@ -1189,7 +1192,7 @@ mt7996_mac_sta_event(struct mt7996_dev *dev, struct ieee80211_vif *vif, link, msta_link, CONN_STATE_PORT_SECURE, false); if (err) - return err; + goto unlock; break; case MT76_STA_EVENT_DISASSOC: for (i = 0; i < ARRAY_SIZE(msta_link->twt.flow); i++) @@ -1209,8 +1212,10 @@ mt7996_mac_sta_event(struct mt7996_dev *dev, struct ieee80211_vif *vif, break; } } +unlock: + mutex_unlock(&dev->mt76.mutex); - return 0; + return err; } static void From 70656b45467ce09b9938e9b2e06442c853ba9e63 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 14 Nov 2025 14:16:23 +0100 Subject: [PATCH 0774/2333] wifi: mt76: Move mt76_abort_scan out of mt76_reset_device() [ Upstream commit 6aaaaeacf18b2dc2b0f78f241800e0ea680938c7 ] Move mt76_abort_scan routine out of mt76_reset_device() in order to avoid a possible deadlock since mt76_reset_device routine is running with mt76 mutex help and mt76_abort_scan_complete() can grab mt76 mutex in some cases. Fixes: b36d55610215a ("wifi: mt76: abort scan/roc on hw restart") Signed-off-by: Lorenzo Bianconi Tested-by: Ben Greear Link: https://patch.msgid.link/20251114-mt76-fix-missing-mtx-v1-3-259ebf11f654@kernel.org Signed-off-by: Felix Fietkau Signed-off-by: Sasha Levin --- drivers/net/wireless/mediatek/mt76/mac80211.c | 2 -- drivers/net/wireless/mediatek/mt76/mt7915/mac.c | 2 ++ drivers/net/wireless/mediatek/mt76/mt7996/mac.c | 2 ++ 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index 5ceaf78c9ea06..5e75861bf6f99 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -847,8 +847,6 @@ void mt76_reset_device(struct mt76_dev *dev) } rcu_read_unlock(); - mt76_abort_scan(dev); - INIT_LIST_HEAD(&dev->wcid_list); INIT_LIST_HEAD(&dev->sta_poll_list); dev->vif_mask = 0; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c index 1c0d310146d63..5caf818e82834 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c @@ -1451,6 +1451,8 @@ mt7915_mac_full_reset(struct mt7915_dev *dev) if (ext_phy) cancel_delayed_work_sync(&ext_phy->mac_work); + mt76_abort_scan(&dev->mt76); + mutex_lock(&dev->mt76.mutex); for (i = 0; i < 10; i++) { if (!mt7915_mac_restart(dev)) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c index b06728a98a691..cfad46a532bb7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c @@ -2424,6 +2424,8 @@ mt7996_mac_full_reset(struct mt7996_dev *dev) mt7996_for_each_phy(dev, phy) cancel_delayed_work_sync(&phy->mt76->mac_work); + mt76_abort_scan(&dev->mt76); + mutex_lock(&dev->mt76.mutex); for (i = 0; i < 10; i++) { if (!mt7996_mac_restart(dev)) From c319967690d4257c6ed76bea1c928a6f6498facc Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 14 Nov 2025 14:16:24 +0100 Subject: [PATCH 0775/2333] wifi: mt76: mt7996: skip deflink accounting for offchannel links [ Upstream commit 4fe823b9ee0317b04ddc6d9e00fea892498aa0f2 ] Do not take into account offchannel links for deflink accounting. Fixes: a3316d2fc669f ("wifi: mt76: mt7996: set vif default link_id adding/removing vif links") Signed-off-by: Lorenzo Bianconi Tested-by: Ben Greear Link: https://patch.msgid.link/20251114-mt76-fix-missing-mtx-v1-4-259ebf11f654@kernel.org Signed-off-by: Felix Fietkau Signed-off-by: Sasha Levin --- drivers/net/wireless/mediatek/mt76/mt7996/main.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c index ead56ce4c0362..5ff7ab596f88c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c @@ -370,7 +370,8 @@ int mt7996_vif_link_add(struct mt76_phy *mphy, struct ieee80211_vif *vif, ieee80211_iter_keys(mphy->hw, vif, mt7996_key_iter, &it); - if (mvif->mt76.deflink_id == IEEE80211_LINK_UNSPECIFIED) + if (!mlink->wcid->offchannel && + mvif->mt76.deflink_id == IEEE80211_LINK_UNSPECIFIED) mvif->mt76.deflink_id = link_conf->link_id; return 0; @@ -401,7 +402,8 @@ void mt7996_vif_link_remove(struct mt76_phy *mphy, struct ieee80211_vif *vif, rcu_assign_pointer(dev->mt76.wcid[idx], NULL); - if (mvif->mt76.deflink_id == link_conf->link_id) { + if (!mlink->wcid->offchannel && + mvif->mt76.deflink_id == link_conf->link_id) { struct ieee80211_bss_conf *iter; unsigned int link_id; From abdedd46dc58c1bc3428c8eb430026591cd9f74b Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sat, 15 Nov 2025 11:41:00 +0100 Subject: [PATCH 0776/2333] wifi: mt76: mt7996: skip ieee80211_iter_keys() on scanning link remove [ Upstream commit 2a432a6d0066d4ce05a2d0eec1da9e061eb70c49 ] mt7996_vif_link_remove routine is executed by mt76_scan_complete() without holding the wiphy mutex triggering the following lockdep warning. WARNING: CPU: 0 PID: 72 at net/mac80211/key.c:1029 ieee80211_iter_keys+0xe4/0x1a0 [mac80211] CPU: 0 UID: 0 PID: 72 Comm: kworker/u32:2 Tainted: G S 6.18.0-rc5+ #27 PREEMPT(full) Tainted: [S]=CPU_OUT_OF_SPEC Hardware name: Default string Default string/SKYBAY, BIOS 5.12 02/15/2023 Workqueue: phy3 mt76_scan_work [mt76] RIP: 0010:ieee80211_iter_keys+0xe4/0x1a0 [mac80211] Code: 4c 48 83 c4 10 5b 5d 41 5c 41 5d 41 5e 41 5f c3 48 8b 47 48 be ff ff ff ff 48 8d 78 68 e8 b4 eb 1e e1 85 c0 0f 85 49 ff ff ff 4c 8b ab 90 1a 00 00 48 8d 83 90 RSP: 0018:ffffc900002f7cb0 EFLAGS: 00010246 RAX: 0000000000000000 RBX: ffff888127e00ee0 RCX: 0000000000000000 RDX: 0000000000000000 RSI: ffff888127e00788 RDI: ffff88811132b5c8 RBP: ffffffffa0ddf400 R08: 0000000000000001 R09: 000000009dcc1dac R10: 0000000000000001 R11: ffff88811132b5a0 R12: ffffc900002f7d00 R13: ffff8882581e6a80 R14: ffff888127e0afc8 R15: ffff888158832038 FS: 0000000000000000(0000) GS:ffff8884da486000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000030a0fd90 CR3: 0000000002c52004 CR4: 00000000003706f0 Call Trace: ? lock_acquire+0xc2/0x2c0 mt7996_vif_link_remove+0x64/0x2b0 [mt7996e] mt76_put_vif_phy_link+0x41/0x50 [mt76] mt76_scan_complete+0x77/0x100 [mt76] mt76_scan_work+0x2eb/0x3f0 [mt76] ? process_one_work+0x1e5/0x6d0 process_one_work+0x221/0x6d0 worker_thread+0x19a/0x340 ? rescuer_thread+0x450/0x450 kthread+0x108/0x220 ? kthreads_online_cpu+0x110/0x110 ret_from_fork+0x1c6/0x220 ? kthreads_online_cpu+0x110/0x110 ret_from_fork_asm+0x11/0x20 irq event stamp: 45471 hardirqs last enabled at (45477): [] __up_console_sem+0x5e/0x70 hardirqs last disabled at (45482): [] __up_console_sem+0x43/0x70 softirqs last enabled at (44500): [] napi_pp_put_page+0xac/0xd0 softirqs last disabled at (44498): [] page_pool_put_unrefed_netmem+0x290/0x3d0 ---[ end trace 0000000000000000 ]--- Fix the issue skipping ieee80211_iter_keys() for scanning links in mt7996_vif_link_remove routine since we have not uploaded any hw keys for these links. Fixes: 04414d7bba78 ("wifi: mt76: mt7996: delete vif keys when requested") Signed-off-by: Lorenzo Bianconi Tested-by: Ben Greear Link: https://patch.msgid.link/20251115-mt7996-key-iter-link-remove-fix-v1-1-4f3f4e1eaa78@kernel.org Signed-off-by: Felix Fietkau Signed-off-by: Sasha Levin --- drivers/net/wireless/mediatek/mt76/mt7996/main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c index 5ff7ab596f88c..2ad52ae2c5f55 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c @@ -392,7 +392,8 @@ void mt7996_vif_link_remove(struct mt76_phy *mphy, struct ieee80211_vif *vif, }; int idx = msta_link->wcid.idx; - ieee80211_iter_keys(mphy->hw, vif, mt7996_key_iter, &it); + if (!mlink->wcid->offchannel) + ieee80211_iter_keys(mphy->hw, vif, mt7996_key_iter, &it); mt7996_mcu_add_sta(dev, link_conf, NULL, link, NULL, CONN_STATE_DISCONNECT, false); From f4c57afff3b096e7237c51b9a55f52fd311e3348 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 18 Nov 2025 10:30:26 +0100 Subject: [PATCH 0777/2333] wifi: mt76: mt7996: Add missing locking in mt7996_mac_sta_rc_work() [ Upstream commit 7545551631fa63101f97974f49ac0b564814f703 ] Grab the mt76 mutex running mt7996_mac_sta_rc_work() since it is required by mt7996_mcu_add_rate_ctrl routine. Fixes: 28d519d0d493a ("wifi: mt76: Move RCU section in mt7996_mcu_add_rate_ctrl_fixed()") Signed-off-by: Lorenzo Bianconi Link: https://patch.msgid.link/20251118-mt7996-rc-work-missing-mtx-v1-1-0739c493a6cb@kernel.org Signed-off-by: Felix Fietkau Signed-off-by: Sasha Levin --- drivers/net/wireless/mediatek/mt76/mt7996/mac.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c index cfad46a532bb7..502136691a69e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c @@ -2860,6 +2860,8 @@ void mt7996_mac_sta_rc_work(struct work_struct *work) LIST_HEAD(list); u32 changed; + mutex_lock(&dev->mt76.mutex); + spin_lock_bh(&dev->mt76.sta_poll_lock); list_splice_init(&dev->sta_rc_list, &list); @@ -2892,6 +2894,8 @@ void mt7996_mac_sta_rc_work(struct work_struct *work) } spin_unlock_bh(&dev->mt76.sta_poll_lock); + + mutex_unlock(&dev->mt76.mutex); } void mt7996_mac_work(struct work_struct *work) From 4d42aba0ee49c0aa015c50c4f2a07cf8fa1c3a49 Mon Sep 17 00:00:00 2001 From: Zilin Guan Date: Thu, 13 Nov 2025 06:24:15 +0000 Subject: [PATCH 0778/2333] mt76: mt7615: Fix memory leak in mt7615_mcu_wtbl_sta_add() [ Upstream commit 53d1548612670aa8b5d89745116cc33d9d172863 ] In mt7615_mcu_wtbl_sta_add(), an skb sskb is allocated. If the subsequent call to mt76_connac_mcu_alloc_wtbl_req() fails, the function returns an error without freeing sskb, leading to a memory leak. Fix this by calling dev_kfree_skb() on sskb in the error handling path to ensure it is properly released. Fixes: 99c457d902cf9 ("mt76: mt7615: move mt7615_mcu_set_bmc to mt7615_mcu_ops") Signed-off-by: Zilin Guan Acked-by: Lorenzo Bianconi Link: https://patch.msgid.link/20251113062415.103611-1-zilin@seu.edu.cn Signed-off-by: Felix Fietkau Signed-off-by: Sasha Levin --- drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index 4064e193d4dec..08ee2e861c4e2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -874,8 +874,10 @@ mt7615_mcu_wtbl_sta_add(struct mt7615_phy *phy, struct ieee80211_vif *vif, wtbl_hdr = mt76_connac_mcu_alloc_wtbl_req(&dev->mt76, &msta->wcid, WTBL_RESET_AND_SET, NULL, &wskb); - if (IS_ERR(wtbl_hdr)) + if (IS_ERR(wtbl_hdr)) { + dev_kfree_skb(sskb); return PTR_ERR(wtbl_hdr); + } if (enable) { mt76_connac_mcu_wtbl_generic_tlv(&dev->mt76, wskb, vif, sta, From 1bdf06f25a497bfb764e53dafb74de2a4b6e330b Mon Sep 17 00:00:00 2001 From: Dinh Nguyen Date: Fri, 14 Nov 2025 12:58:13 -0600 Subject: [PATCH 0779/2333] firmware: stratix10-svc: fix make htmldocs warning for stratix10_svc [ Upstream commit 377441d53a2df61b105e823b335010cd4f1a6e56 ] Fix this warning that was generated from "make htmldocs": WARNING: drivers/firmware/stratix10-svc.c:58 struct member 'intel_svc_fcs' not described in 'stratix10_svc' Fixes: e6281c26674e ("firmware: stratix10-svc: Add support for FCS") Reported-by: Stephen Rothwell Closes: https://lore.kernel.org/linux-next/20251106145941.37920e97@canb.auug.org.au/ Signed-off-by: Dinh Nguyen Link: https://patch.msgid.link/20251114185815.358423-1-dinguyen@kernel.org Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin --- drivers/firmware/stratix10-svc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/firmware/stratix10-svc.c b/drivers/firmware/stratix10-svc.c index 00f58e27f6de5..deee0e7be34bd 100644 --- a/drivers/firmware/stratix10-svc.c +++ b/drivers/firmware/stratix10-svc.c @@ -52,6 +52,7 @@ struct stratix10_svc_chan; /** * struct stratix10_svc - svc private data * @stratix10_svc_rsu: pointer to stratix10 RSU device + * @intel_svc_fcs: pointer to the FCS device */ struct stratix10_svc { struct platform_device *stratix10_svc_rsu; From 56296da5e6bf558cd8b91108a356cbd7cd35adbf Mon Sep 17 00:00:00 2001 From: Jianglei Nie Date: Wed, 12 Nov 2025 20:22:07 +0100 Subject: [PATCH 0780/2333] staging: fbtft: core: fix potential memory leak in fbtft_probe_common() [ Upstream commit 47d3949a9b04cbcb0e10abae30c2b53e98706e11 ] fbtft_probe_common() allocates a memory chunk for "info" with fbtft_framebuffer_alloc(). When "display->buswidth == 0" is true, the function returns without releasing the "info", which will lead to a memory leak. Fix it by calling fbtft_framebuffer_release() when "display->buswidth == 0" is true. Fixes: c296d5f9957c ("staging: fbtft: core support") Signed-off-by: Jianglei Nie Signed-off-by: Andy Shevchenko Acked-by: Abdun Nihaal Link: https://patch.msgid.link/20251112192235.2088654-1-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin --- drivers/staging/fbtft/fbtft-core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/staging/fbtft/fbtft-core.c b/drivers/staging/fbtft/fbtft-core.c index 9e7b84071174c..8a5ccc8ae0a18 100644 --- a/drivers/staging/fbtft/fbtft-core.c +++ b/drivers/staging/fbtft/fbtft-core.c @@ -1171,8 +1171,8 @@ int fbtft_probe_common(struct fbtft_display *display, par->pdev = pdev; if (display->buswidth == 0) { - dev_err(dev, "buswidth is not set\n"); - return -EINVAL; + ret = dev_err_probe(dev, -EINVAL, "buswidth is not set\n"); + goto out_release; } /* write register functions */ From 3d12cc5d13f6dc98b128e5c666417b6e2df6406a Mon Sep 17 00:00:00 2001 From: Ryan Huang Date: Fri, 7 Nov 2025 11:09:17 -0800 Subject: [PATCH 0781/2333] iommu/arm-smmu-v3: Fix error check in arm_smmu_alloc_cd_tables [ Upstream commit 5941f0e0c1e0be03ebc15b461f64208f5250d3d9 ] In arm_smmu_alloc_cd_tables(), the error check following the dma_alloc_coherent() for cd_table->l2.l1tab incorrectly tests cd_table->l2.l2ptrs. This means an allocation failure for l1tab goes undetected, causing the function to return 0 (success) erroneously. Correct the check to test cd_table->l2.l1tab. Fixes: e3b1be2e73db ("iommu/arm-smmu-v3: Reorganize struct arm_smmu_ctx_desc_cfg") Signed-off-by: Daniel Mentz Signed-off-by: Ryan Huang Reviewed-by: Nicolin Chen Reviewed-by: Pranjal Shrivastava Reviewed-by: Jason Gunthorpe Signed-off-by: Will Deacon Signed-off-by: Sasha Levin --- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c index 2a8b46b948f05..9780f40ba3e65 100644 --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c @@ -1464,7 +1464,7 @@ static int arm_smmu_alloc_cd_tables(struct arm_smmu_master *master) cd_table->l2.l1tab = dma_alloc_coherent(smmu->dev, l1size, &cd_table->cdtab_dma, GFP_KERNEL); - if (!cd_table->l2.l2ptrs) { + if (!cd_table->l2.l1tab) { ret = -ENOMEM; goto err_free_l2ptrs; } From 489a8f559fafe6a72f44aeff81de44259d5d37fe Mon Sep 17 00:00:00 2001 From: Alan Maguire Date: Thu, 20 Nov 2025 08:47:53 +0000 Subject: [PATCH 0782/2333] bpftool: Allow bpftool to build with openssl < 3 [ Upstream commit 90ae54b4c7eca42d5ce006dd0a8cb0b5bfbf80d0 ] ERR_get_error_all()[1] is a openssl v3 API, so to make code compatible with openssl v1 utilize ERR_get_err_line_data instead. Since openssl is already a build requirement for the kernel (minimum requirement openssl 1.0.0), this will allow bpftool to compile where opensslv3 is not available. Signing-related BPF selftests pass with openssl v1. [1] https://docs.openssl.org/3.4/man3/ERR_get_error/ Fixes: 40863f4d6ef2 ("bpftool: Add support for signing BPF programs") Signed-off-by: Alan Maguire Acked-by: Song Liu Acked-by: Quentin Monnet Link: https://lore.kernel.org/r/20251120084754.640405-2-alan.maguire@oracle.com Signed-off-by: Alexei Starovoitov Signed-off-by: Sasha Levin --- tools/bpf/bpftool/sign.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tools/bpf/bpftool/sign.c b/tools/bpf/bpftool/sign.c index b34f74d210e9c..f9b742f4bb104 100644 --- a/tools/bpf/bpftool/sign.c +++ b/tools/bpf/bpftool/sign.c @@ -28,6 +28,12 @@ #define OPEN_SSL_ERR_BUF_LEN 256 +/* Use deprecated in 3.0 ERR_get_error_line_data for openssl < 3 */ +#if !defined(OPENSSL_VERSION_MAJOR) || (OPENSSL_VERSION_MAJOR < 3) +#define ERR_get_error_all(file, line, func, data, flags) \ + ERR_get_error_line_data(file, line, data, flags) +#endif + static void display_openssl_errors(int l) { char buf[OPEN_SSL_ERR_BUF_LEN]; From 3b796d3f16c108fb287f7eb5f4eb66c8770898e7 Mon Sep 17 00:00:00 2001 From: Alan Maguire Date: Thu, 20 Nov 2025 08:47:54 +0000 Subject: [PATCH 0783/2333] selftests/bpf: Allow selftests to build with older xxd [ Upstream commit ad93ba02678eda5fc8e259cf4b52997e6fa570cf ] Currently selftests require xxd with the "-n " option which allows the user to specify a name not derived from the input object path. Instead of relying on this newer feature, older xxd can be used if we link our desired name ("test_progs_verification_cert") to the input object. Many distros ship xxd in vim-common package and do not have the latest xxd with -n support. Fixes: b720903e2b14d ("selftests/bpf: Enable signature verification for some lskel tests") Signed-off-by: Alan Maguire Link: https://lore.kernel.org/r/20251120084754.640405-3-alan.maguire@oracle.com Signed-off-by: Alexei Starovoitov Signed-off-by: Sasha Levin --- tools/testing/selftests/bpf/.gitignore | 1 + tools/testing/selftests/bpf/Makefile | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/bpf/.gitignore b/tools/testing/selftests/bpf/.gitignore index be1ee7ba7ce03..ca557e5668fd8 100644 --- a/tools/testing/selftests/bpf/.gitignore +++ b/tools/testing/selftests/bpf/.gitignore @@ -23,6 +23,7 @@ test_tcpnotify_user test_libbpf xdping test_cpp +test_progs_verification_cert *.d *.subskel.h *.skel.h diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile index f00587d4ede68..e59b2bbf8d920 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile @@ -721,7 +721,8 @@ $(VERIFICATION_CERT) $(PRIVATE_KEY): $(VERIFY_SIG_SETUP) $(Q)$(VERIFY_SIG_SETUP) genkey $(BUILD_DIR) $(VERIFY_SIG_HDR): $(VERIFICATION_CERT) - $(Q)xxd -i -n test_progs_verification_cert $< > $@ + $(Q)ln -fs $< test_progs_verification_cert && \ + xxd -i test_progs_verification_cert > $@ # Define test_progs test runner. TRUNNER_TESTS_DIR := prog_tests @@ -893,7 +894,8 @@ EXTRA_CLEAN := $(SCRATCH_DIR) $(HOST_SCRATCH_DIR) \ $(addprefix $(OUTPUT)/,*.o *.d *.skel.h *.lskel.h *.subskel.h \ no_alu32 cpuv4 bpf_gcc \ liburandom_read.so) \ - $(OUTPUT)/FEATURE-DUMP.selftests + $(OUTPUT)/FEATURE-DUMP.selftests \ + test_progs_verification_cert .PHONY: docs docs-clean From 364685c4c2d9c9f4408d95451bcf42fdeebc3ebb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miquel=20Sabat=C3=A9=20Sol=C3=A0?= Date: Wed, 1 Oct 2025 20:05:03 +0200 Subject: [PATCH 0784/2333] btrfs: fix double free of qgroup record after failure to add delayed ref head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 725e46298876a2cc1f1c3fb22ba69d29102c3ddf ] In the previous code it was possible to incur into a double kfree() scenario when calling add_delayed_ref_head(). This could happen if the record was reported to already exist in the btrfs_qgroup_trace_extent_nolock() call, but then there was an error later on add_delayed_ref_head(). In this case, since add_delayed_ref_head() returned an error, the caller went to free the record. Since add_delayed_ref_head() couldn't set this kfree'd pointer to NULL, then kfree() would have acted on a non-NULL 'record' object which was pointing to memory already freed by the callee. The problem comes from the fact that the responsibility to kfree the object is on both the caller and the callee at the same time. Hence, the fix for this is to shift the ownership of the 'qrecord' object out of the add_delayed_ref_head(). That is, we will never attempt to kfree() the given object inside of this function, and will expect the caller to act on the 'qrecord' object on its own. The only exception where the 'qrecord' object cannot be kfree'd is if it was inserted into the tracing logic, for which we already have the 'qrecord_inserted_ret' boolean to account for this. Hence, the caller has to kfree the object only if add_delayed_ref_head() reports not to have inserted it on the tracing logic. As a side-effect of the above, we must guarantee that 'qrecord_inserted_ret' is properly initialized at the start of the function, not at the end, and then set when an actual insert happens. This way we avoid 'qrecord_inserted_ret' having an invalid value on an early exit. The documentation from the add_delayed_ref_head() has also been updated to reflect on the exact ownership of the 'qrecord' object. Fixes: 6ef8fbce0104 ("btrfs: fix missing error handling when adding delayed ref with qgroups enabled") Reviewed-by: Filipe Manana Signed-off-by: Miquel Sabaté Solà Signed-off-by: Filipe Manana Signed-off-by: David Sterba Signed-off-by: Sasha Levin --- fs/btrfs/delayed-ref.c | 43 ++++++++++++++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/fs/btrfs/delayed-ref.c b/fs/btrfs/delayed-ref.c index 481802efaa143..f8fc26272f76c 100644 --- a/fs/btrfs/delayed-ref.c +++ b/fs/btrfs/delayed-ref.c @@ -798,9 +798,13 @@ static void init_delayed_ref_head(struct btrfs_delayed_ref_head *head_ref, } /* - * helper function to actually insert a head node into the rbtree. - * this does all the dirty work in terms of maintaining the correct - * overall modification count. + * Helper function to actually insert a head node into the xarray. This does all + * the dirty work in terms of maintaining the correct overall modification + * count. + * + * The caller is responsible for calling kfree() on @qrecord. More specifically, + * if this function reports that it did not insert it as noted in + * @qrecord_inserted_ret, then it's safe to call kfree() on it. * * Returns an error pointer in case of an error. */ @@ -814,7 +818,14 @@ add_delayed_ref_head(struct btrfs_trans_handle *trans, struct btrfs_delayed_ref_head *existing; struct btrfs_delayed_ref_root *delayed_refs; const unsigned long index = (head_ref->bytenr >> fs_info->sectorsize_bits); - bool qrecord_inserted = false; + + /* + * If 'qrecord_inserted_ret' is provided, then the first thing we need + * to do is to initialize it to false just in case we have an exit + * before trying to insert the record. + */ + if (qrecord_inserted_ret) + *qrecord_inserted_ret = false; delayed_refs = &trans->transaction->delayed_refs; lockdep_assert_held(&delayed_refs->lock); @@ -833,6 +844,12 @@ add_delayed_ref_head(struct btrfs_trans_handle *trans, /* Record qgroup extent info if provided */ if (qrecord) { + /* + * Setting 'qrecord' but not 'qrecord_inserted_ret' will likely + * result in a memory leakage. + */ + ASSERT(qrecord_inserted_ret != NULL); + int ret; ret = btrfs_qgroup_trace_extent_nolock(fs_info, delayed_refs, qrecord, @@ -840,12 +857,10 @@ add_delayed_ref_head(struct btrfs_trans_handle *trans, if (ret) { /* Clean up if insertion fails or item exists. */ xa_release(&delayed_refs->dirty_extents, index); - /* Caller responsible for freeing qrecord on error. */ if (ret < 0) return ERR_PTR(ret); - kfree(qrecord); - } else { - qrecord_inserted = true; + } else if (qrecord_inserted_ret) { + *qrecord_inserted_ret = true; } } @@ -888,8 +903,6 @@ add_delayed_ref_head(struct btrfs_trans_handle *trans, delayed_refs->num_heads++; delayed_refs->num_heads_ready++; } - if (qrecord_inserted_ret) - *qrecord_inserted_ret = qrecord_inserted; return head_ref; } @@ -1049,6 +1062,14 @@ static int add_delayed_ref(struct btrfs_trans_handle *trans, xa_release(&delayed_refs->head_refs, index); spin_unlock(&delayed_refs->lock); ret = PTR_ERR(new_head_ref); + + /* + * It's only safe to call kfree() on 'qrecord' if + * add_delayed_ref_head() has _not_ inserted it for + * tracing. Otherwise we need to handle this here. + */ + if (!qrecord_reserved || qrecord_inserted) + goto free_head_ref; goto free_record; } head_ref = new_head_ref; @@ -1071,6 +1092,8 @@ static int add_delayed_ref(struct btrfs_trans_handle *trans, if (qrecord_inserted) return btrfs_qgroup_trace_extent_post(trans, record, generic_ref->bytenr); + + kfree(record); return 0; free_record: From 742b90eaf394f0018352c0e10dc89763b2dd5267 Mon Sep 17 00:00:00 2001 From: Boris Burkov Date: Wed, 1 Oct 2025 17:20:22 -0700 Subject: [PATCH 0785/2333] btrfs: fix racy bitfield write in btrfs_clear_space_info_full() [ Upstream commit 38e818718c5e04961eea0fa8feff3f100ce40408 ] From the memory-barriers.txt document regarding memory barrier ordering guarantees: (*) These guarantees do not apply to bitfields, because compilers often generate code to modify these using non-atomic read-modify-write sequences. Do not attempt to use bitfields to synchronize parallel algorithms. (*) Even in cases where bitfields are protected by locks, all fields in a given bitfield must be protected by one lock. If two fields in a given bitfield are protected by different locks, the compiler's non-atomic read-modify-write sequences can cause an update to one field to corrupt the value of an adjacent field. btrfs_space_info has a bitfield sharing an underlying word consisting of the fields full, chunk_alloc, and flush: struct btrfs_space_info { struct btrfs_fs_info * fs_info; /* 0 8 */ struct btrfs_space_info * parent; /* 8 8 */ ... int clamp; /* 172 4 */ unsigned int full:1; /* 176: 0 4 */ unsigned int chunk_alloc:1; /* 176: 1 4 */ unsigned int flush:1; /* 176: 2 4 */ ... Therefore, to be safe from parallel read-modify-writes losing a write to one of the bitfield members protected by a lock, all writes to all the bitfields must use the lock. They almost universally do, except for btrfs_clear_space_info_full() which iterates over the space_infos and writes out found->full = 0 without a lock. Imagine that we have one thread completing a transaction in which we finished deleting a block_group and are thus calling btrfs_clear_space_info_full() while simultaneously the data reclaim ticket infrastructure is running do_async_reclaim_data_space(): T1 T2 btrfs_commit_transaction btrfs_clear_space_info_full data_sinfo->full = 0 READ: full:0, chunk_alloc:0, flush:1 do_async_reclaim_data_space(data_sinfo) spin_lock(&space_info->lock); if(list_empty(tickets)) space_info->flush = 0; READ: full: 0, chunk_alloc:0, flush:1 MOD/WRITE: full: 0, chunk_alloc:0, flush:0 spin_unlock(&space_info->lock); return; MOD/WRITE: full:0, chunk_alloc:0, flush:1 and now data_sinfo->flush is 1 but the reclaim worker has exited. This breaks the invariant that flush is 0 iff there is no work queued or running. Once this invariant is violated, future allocations that go into __reserve_bytes() will add tickets to space_info->tickets but will see space_info->flush is set to 1 and not queue the work. After this, they will block forever on the resulting ticket, as it is now impossible to kick the worker again. I also confirmed by looking at the assembly of the affected kernel that it is doing RMW operations. For example, to set the flush (3rd) bit to 0, the assembly is: andb $0xfb,0x60(%rbx) and similarly for setting the full (1st) bit to 0: andb $0xfe,-0x20(%rax) So I think this is really a bug on practical systems. I have observed a number of systems in this exact state, but am currently unable to reproduce it. Rather than leaving this footgun lying around for the future, take advantage of the fact that there is room in the struct anyway, and that it is already quite large and simply change the three bitfield members to bools. This avoids writes to space_info->full having any effect on writes to space_info->flush, regardless of locking. Fixes: 957780eb2788 ("Btrfs: introduce ticketed enospc infrastructure") Reviewed-by: Qu Wenruo Signed-off-by: Boris Burkov Reviewed-by: David Sterba Signed-off-by: David Sterba Signed-off-by: Sasha Levin --- fs/btrfs/block-group.c | 6 +++--- fs/btrfs/space-info.c | 22 +++++++++++----------- fs/btrfs/space-info.h | 6 +++--- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/fs/btrfs/block-group.c b/fs/btrfs/block-group.c index 5322ef2ae015e..8bf501fbcc0be 100644 --- a/fs/btrfs/block-group.c +++ b/fs/btrfs/block-group.c @@ -4215,7 +4215,7 @@ int btrfs_chunk_alloc(struct btrfs_trans_handle *trans, mutex_unlock(&fs_info->chunk_mutex); } else { /* Proceed with allocation */ - space_info->chunk_alloc = 1; + space_info->chunk_alloc = true; wait_for_alloc = false; spin_unlock(&space_info->lock); } @@ -4264,7 +4264,7 @@ int btrfs_chunk_alloc(struct btrfs_trans_handle *trans, spin_lock(&space_info->lock); if (ret < 0) { if (ret == -ENOSPC) - space_info->full = 1; + space_info->full = true; else goto out; } else { @@ -4274,7 +4274,7 @@ int btrfs_chunk_alloc(struct btrfs_trans_handle *trans, space_info->force_alloc = CHUNK_ALLOC_NO_FORCE; out: - space_info->chunk_alloc = 0; + space_info->chunk_alloc = false; spin_unlock(&space_info->lock); mutex_unlock(&fs_info->chunk_mutex); diff --git a/fs/btrfs/space-info.c b/fs/btrfs/space-info.c index 97452fb5d29b0..85c466c85910a 100644 --- a/fs/btrfs/space-info.c +++ b/fs/btrfs/space-info.c @@ -192,7 +192,7 @@ void btrfs_clear_space_info_full(struct btrfs_fs_info *info) struct btrfs_space_info *found; list_for_each_entry(found, head, list) - found->full = 0; + found->full = false; } /* @@ -372,7 +372,7 @@ void btrfs_add_bg_to_space_info(struct btrfs_fs_info *info, space_info->bytes_readonly += block_group->bytes_super; btrfs_space_info_update_bytes_zone_unusable(space_info, block_group->zone_unusable); if (block_group->length > 0) - space_info->full = 0; + space_info->full = false; btrfs_try_granting_tickets(info, space_info); spin_unlock(&space_info->lock); @@ -1146,7 +1146,7 @@ static void do_async_reclaim_metadata_space(struct btrfs_space_info *space_info) spin_lock(&space_info->lock); to_reclaim = btrfs_calc_reclaim_metadata_size(fs_info, space_info); if (!to_reclaim) { - space_info->flush = 0; + space_info->flush = false; spin_unlock(&space_info->lock); return; } @@ -1158,7 +1158,7 @@ static void do_async_reclaim_metadata_space(struct btrfs_space_info *space_info) flush_space(fs_info, space_info, to_reclaim, flush_state, false); spin_lock(&space_info->lock); if (list_empty(&space_info->tickets)) { - space_info->flush = 0; + space_info->flush = false; spin_unlock(&space_info->lock); return; } @@ -1201,7 +1201,7 @@ static void do_async_reclaim_metadata_space(struct btrfs_space_info *space_info) flush_state = FLUSH_DELAYED_ITEMS_NR; commit_cycles--; } else { - space_info->flush = 0; + space_info->flush = false; } } else { flush_state = FLUSH_DELAYED_ITEMS_NR; @@ -1383,7 +1383,7 @@ static void do_async_reclaim_data_space(struct btrfs_space_info *space_info) spin_lock(&space_info->lock); if (list_empty(&space_info->tickets)) { - space_info->flush = 0; + space_info->flush = false; spin_unlock(&space_info->lock); return; } @@ -1394,7 +1394,7 @@ static void do_async_reclaim_data_space(struct btrfs_space_info *space_info) flush_space(fs_info, space_info, U64_MAX, ALLOC_CHUNK_FORCE, false); spin_lock(&space_info->lock); if (list_empty(&space_info->tickets)) { - space_info->flush = 0; + space_info->flush = false; spin_unlock(&space_info->lock); return; } @@ -1411,7 +1411,7 @@ static void do_async_reclaim_data_space(struct btrfs_space_info *space_info) data_flush_states[flush_state], false); spin_lock(&space_info->lock); if (list_empty(&space_info->tickets)) { - space_info->flush = 0; + space_info->flush = false; spin_unlock(&space_info->lock); return; } @@ -1428,7 +1428,7 @@ static void do_async_reclaim_data_space(struct btrfs_space_info *space_info) if (maybe_fail_all_tickets(fs_info, space_info)) flush_state = 0; else - space_info->flush = 0; + space_info->flush = false; } else { flush_state = 0; } @@ -1444,7 +1444,7 @@ static void do_async_reclaim_data_space(struct btrfs_space_info *space_info) aborted_fs: maybe_fail_all_tickets(fs_info, space_info); - space_info->flush = 0; + space_info->flush = false; spin_unlock(&space_info->lock); } @@ -1825,7 +1825,7 @@ static int __reserve_bytes(struct btrfs_fs_info *fs_info, */ maybe_clamp_preempt(fs_info, space_info); - space_info->flush = 1; + space_info->flush = true; trace_btrfs_trigger_flush(fs_info, space_info->flags, orig_bytes, flush, diff --git a/fs/btrfs/space-info.h b/fs/btrfs/space-info.h index 679f22efb4073..a846f63585c95 100644 --- a/fs/btrfs/space-info.h +++ b/fs/btrfs/space-info.h @@ -142,11 +142,11 @@ struct btrfs_space_info { flushing. The value is >> clamp, so turns out to be a 2^clamp divisor. */ - unsigned int full:1; /* indicates that we cannot allocate any more + bool full; /* indicates that we cannot allocate any more chunks for this space */ - unsigned int chunk_alloc:1; /* set if we are allocating a chunk */ + bool chunk_alloc; /* set if we are allocating a chunk */ - unsigned int flush:1; /* set if we are trying to make space */ + bool flush; /* set if we are trying to make space */ unsigned int force_alloc; /* set if we need to force a chunk alloc for this space */ From d65f49f772cf51ea0fedacf96ae2b906876ea73c Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Wed, 5 Nov 2025 20:28:12 +1030 Subject: [PATCH 0786/2333] btrfs: make sure extent and csum paths are always released in scrub_raid56_parity_stripe() [ Upstream commit d435c513652e6a90a13c881986a2cc6420c99cab ] Unlike queue_scrub_stripe() which uses the global sctx->extent_path and sctx->csum_path which are always released at the end of scrub_stripe(), scrub_raid56_parity_stripe() uses local extent_path and csum_path, as that function is going to handle the full stripe, whose bytenr may be smaller than the bytenr in the global sctx paths. However the cleanup of local extent/csum paths is only happening after we have successfully submitted an rbio. There are several error routes that we didn't release those two paths: - scrub_find_fill_first_stripe() errored out at csum tree search In that case extent_path is still valid, and that function itself will not release the extent_path passed in. And the function returns directly without releasing both paths. - The full stripe is empty - Some blocks failed to be recovered - btrfs_map_block() failed - raid56_parity_alloc_scrub_rbio() failed The function returns directly without releasing both paths. Fix it by covering btrfs_release_path() calls inside the out: tag. This is just a hot fix, in the long run we will go scoped based auto freeing for both local paths. Fixes: 1dc4888e725d ("btrfs: scrub: avoid unnecessary extent tree search preparing stripes") Fixes: 3c771c194402 ("btrfs: scrub: avoid unnecessary csum tree search preparing stripes") Signed-off-by: Qu Wenruo Reviewed-by: David Sterba Signed-off-by: David Sterba Signed-off-by: Sasha Levin --- fs/btrfs/scrub.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index ba20d9286a340..65361af302343 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c @@ -2230,9 +2230,9 @@ static int scrub_raid56_parity_stripe(struct scrub_ctx *sctx, bio_put(bio); btrfs_bio_counter_dec(fs_info); +out: btrfs_release_path(&extent_path); btrfs_release_path(&csum_path); -out: return ret; } From f5190da518bed09b1f82dec89cdf931a177243f3 Mon Sep 17 00:00:00 2001 From: Filipe Manana Date: Thu, 13 Nov 2025 12:52:45 +0000 Subject: [PATCH 0787/2333] btrfs: fix leaf leak in an error path in btrfs_del_items() [ Upstream commit e7dd1182fcedee7c6097c9f49eba8de94a4364e3 ] If the call to btrfs_del_leaf() fails we return without decrementing the extra ref we took on the leaf, therefore leaking it. Fix this by ensuring we drop the ref count before returning the error. Fixes: 751a27615dda ("btrfs: do not BUG_ON() on tree mod log failures at btrfs_del_ptr()") Reviewed-by: Qu Wenruo Signed-off-by: Filipe Manana Reviewed-by: David Sterba Signed-off-by: David Sterba Signed-off-by: Sasha Levin --- fs/btrfs/ctree.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index 561658aca018b..6e053caa6e101 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c @@ -4566,9 +4566,9 @@ int btrfs_del_items(struct btrfs_trans_handle *trans, struct btrfs_root *root, if (btrfs_header_nritems(leaf) == 0) { path->slots[1] = slot; ret = btrfs_del_leaf(trans, root, path, leaf); + free_extent_buffer(leaf); if (ret < 0) return ret; - free_extent_buffer(leaf); ret = 0; } else { /* if we're still in the path, make sure From 644ddd0d96d1d95d28d41566863348539c280610 Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Fri, 14 Nov 2025 20:09:00 +0800 Subject: [PATCH 0788/2333] PCI: dwc: Fix wrong PORT_LOGIC_LTSSM_STATE_MASK definition [ Upstream commit bcc9a4a0bca3aee4303fa4a20302e57b24ac8f68 ] As per DesignWare Cores PCI Express Controller Databook, section 5.50, SII: Debug Signals, cxpl_debug_info[63:0]: [5:0] smlh_ltssm_state: LTSSM current state. Encoding is same as the dedicated smlh_ltssm_state output. The mask should be 6 bits, from 0 to 5. Hence, fix the mask definition. Fixes: 23fe5bd4be90 ("PCI: keystone: Cleanup ks_pcie_link_up()") Signed-off-by: Shawn Lin [mani: reworded description] Signed-off-by: Manivannan Sadhasivam Signed-off-by: Bjorn Helgaas Link: https://patch.msgid.link/1763122140-203068-1-git-send-email-shawn.lin@rock-chips.com Signed-off-by: Sasha Levin --- drivers/pci/controller/dwc/pcie-designware.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index e995f692a1ecd..24bfa5231923a 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -97,7 +97,7 @@ #define PORT_LANE_SKEW_INSERT_MASK GENMASK(23, 0) #define PCIE_PORT_DEBUG0 0x728 -#define PORT_LOGIC_LTSSM_STATE_MASK 0x1f +#define PORT_LOGIC_LTSSM_STATE_MASK 0x3f #define PORT_LOGIC_LTSSM_STATE_L0 0x11 #define PCIE_PORT_DEBUG1 0x72C #define PCIE_PORT_DEBUG1_LINK_UP BIT(4) From 60ac9e5820b9e6337acab7ad2155297e322f7e0f Mon Sep 17 00:00:00 2001 From: Timur Tabi Date: Thu, 13 Nov 2025 17:03:22 -0600 Subject: [PATCH 0789/2333] drm/nouveau: restrict the flush page to a 32-bit address [ Upstream commit 04d98b3452331fa53ec3b698b66273af6ef73288 ] The flush page DMA address is stored in a special register that is not associated with the GPU's standard DMA range. For example, on Turing, the GPU's MMU can handle 47-bit addresses, but the flush page address register is limited to 40 bits. At the point during device initialization when the flush page is allocated, the DMA mask is still at its default of 32 bits. So even though it's unlikely that the flush page could exist above a 40-bit address, the dma_map_page() call could fail, e.g. if IOMMU is disabled and the address is above 32 bits. The simplest way to achieve all constraints is to allocate the page in the DMA32 zone. Since the flush page is literally just a page, this is an acceptable limitation. The alternative is to temporarily set the DMA mask to 40 (or 52 for Hopper and later) bits, but that could have unforseen side effects. In situations where the flush page is allocated above 32 bits and IOMMU is disabled, you will get an error like this: nouveau 0000:65:00.0: DMA addr 0x0000000107c56000+4096 overflow (mask ffffffff, bus limit 0). Fixes: 5728d064190e ("drm/nouveau/fb: handle sysmem flush page from common code") Signed-off-by: Timur Tabi Reviewed-by: Lyude Paul Signed-off-by: Lyude Paul Link: https://patch.msgid.link/20251113230323.1271726-1-ttabi@nvidia.com Signed-off-by: Sasha Levin --- drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c index 8a286a9349ac6..7ce1b65e2c1c2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c @@ -279,7 +279,7 @@ nvkm_fb_ctor(const struct nvkm_fb_func *func, struct nvkm_device *device, mutex_init(&fb->tags.mutex); if (func->sysmem.flush_page_init) { - fb->sysmem.flush_page = alloc_page(GFP_KERNEL | __GFP_ZERO); + fb->sysmem.flush_page = alloc_page(GFP_KERNEL | GFP_DMA32 | __GFP_ZERO); if (!fb->sysmem.flush_page) return -ENOMEM; From f8a794ea740ddbd110d323121d50fc9cb1b36c5b Mon Sep 17 00:00:00 2001 From: David Gow Date: Sat, 22 Nov 2025 16:32:12 +0800 Subject: [PATCH 0790/2333] um: Don't rename vmap to kernel_vmap [ Upstream commit a74b6c0e53a6df8e8a096b50c06c4f872906368a ] In order to work around the existence of a vmap symbol in libpcap, the UML makefile unconditionally redefines vmap to kernel_vmap. However, this not only affects the actual vmap symbol, but also anything else named vmap, including a number of struct members in DRM. This would not be too much of a problem, since all uses are also updated, except we now have Rust DRM bindings, which expect the corresponding Rust structs to have 'vmap' names. Since the redefinition applies in bindgen, but not to Rust code, we end up with errors such as: error[E0560]: struct `drm_gem_object_funcs` has no fields named `vmap` --> rust/kernel/drm/gem/mod.rs:210:9 Since libpcap support was removed in commit 12b8e7e69aa7 ("um: Remove obsolete pcap driver"), remove the, now unnecessary, define as well. We also take this opportunity to update the comment. Signed-off-by: David Gow Acked-by: Miguel Ojeda Link: https://patch.msgid.link/20251122083213.3996586-1-davidgow@google.com Fixes: 12b8e7e69aa7 ("um: Remove obsolete pcap driver") [adjust commmit message a bit] Signed-off-by: Johannes Berg Signed-off-by: Sasha Levin --- arch/um/Makefile | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/arch/um/Makefile b/arch/um/Makefile index 7be0143b5ba35..721b652ffb658 100644 --- a/arch/um/Makefile +++ b/arch/um/Makefile @@ -46,19 +46,17 @@ ARCH_INCLUDE := -I$(srctree)/$(SHARED_HEADERS) ARCH_INCLUDE += -I$(srctree)/$(HOST_DIR)/um/shared KBUILD_CPPFLAGS += -I$(srctree)/$(HOST_DIR)/um -# -Dvmap=kernel_vmap prevents anything from referencing the libpcap.o symbol so -# named - it's a common symbol in libpcap, so we get a binary which crashes. -# -# Same things for in6addr_loopback and mktime - found in libc. For these two we -# only get link-time error, luckily. +# -Dstrrchr=kernel_strrchr (as well as the various in6addr symbols) prevents +# anything from referencing +# libc symbols with the same name, which can cause a linker error. # # -Dlongjmp=kernel_longjmp prevents anything from referencing the libpthread.a # embedded copy of longjmp, same thing for setjmp. # -# These apply to USER_CFLAGS to. +# These apply to USER_CFLAGS too. KBUILD_CFLAGS += $(CFLAGS) $(CFLAGS-y) -D__arch_um__ \ - $(ARCH_INCLUDE) $(MODE_INCLUDE) -Dvmap=kernel_vmap \ + $(ARCH_INCLUDE) $(MODE_INCLUDE) \ -Dlongjmp=kernel_longjmp -Dsetjmp=kernel_setjmp \ -Din6addr_loopback=kernel_in6addr_loopback \ -Din6addr_any=kernel_in6addr_any -Dstrrchr=kernel_strrchr \ From 74c0c1af04ee6982b47237b1c12cff63ffb14460 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 13 Nov 2025 18:06:27 +0100 Subject: [PATCH 0791/2333] iomap: always run error completions in user context [ Upstream commit ddb4873286e03e193c5a3bebb5fc6fa820e9ee3a ] At least zonefs expects error completions to be able to sleep. Because error completions aren't performance critical, just defer them to workqueue context unconditionally. Fixes: 8dcc1a9d90c1 ("fs: New zonefs file system") Signed-off-by: Christoph Hellwig Link: https://patch.msgid.link/20251113170633.1453259-3-hch@lst.de Reviewed-by: Jan Kara Reviewed-by: Chaitanya Kulkarni Signed-off-by: Christian Brauner Signed-off-by: Sasha Levin --- fs/iomap/direct-io.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/fs/iomap/direct-io.c b/fs/iomap/direct-io.c index 5d5d63efbd576..143160042552b 100644 --- a/fs/iomap/direct-io.c +++ b/fs/iomap/direct-io.c @@ -179,7 +179,18 @@ static void iomap_dio_done(struct iomap_dio *dio) WRITE_ONCE(dio->submit.waiter, NULL); blk_wake_io_task(waiter); - } else if (dio->flags & IOMAP_DIO_INLINE_COMP) { + return; + } + + /* + * Always run error completions in user context. These are not + * performance critical and some code relies on taking sleeping locks + * for error handling. + */ + if (dio->error) + dio->flags &= ~IOMAP_DIO_INLINE_COMP; + + if (dio->flags & IOMAP_DIO_INLINE_COMP) { WRITE_ONCE(iocb->private, NULL); iomap_dio_complete_work(&dio->aio.work); } else if (dio->flags & IOMAP_DIO_CALLER_COMP) { From c67775cf0da2407f113c1229e350758f4dca0f51 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 24 Nov 2025 15:00:13 +0100 Subject: [PATCH 0792/2333] iomap: allocate s_dio_done_wq for async reads as well [ Upstream commit 7fd8720dff2d9c70cf5a1a13b7513af01952ec02 ] Since commit 222f2c7c6d14 ("iomap: always run error completions in user context"), read error completions are deferred to s_dio_done_wq. This means the workqueue also needs to be allocated for async reads. Fixes: 222f2c7c6d14 ("iomap: always run error completions in user context") Reported-by: syzbot+a2b9a4ed0d61b1efb3f5@syzkaller.appspotmail.com Signed-off-by: Christoph Hellwig Link: https://patch.msgid.link/20251124140013.902853-1-hch@lst.de Tested-by: syzbot+a2b9a4ed0d61b1efb3f5@syzkaller.appspotmail.com Reviewed-by: Dave Chinner Reviewed-by: Darrick J. Wong Signed-off-by: Christian Brauner Signed-off-by: Sasha Levin --- fs/iomap/direct-io.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/fs/iomap/direct-io.c b/fs/iomap/direct-io.c index 143160042552b..6317e4cd42517 100644 --- a/fs/iomap/direct-io.c +++ b/fs/iomap/direct-io.c @@ -728,12 +728,12 @@ __iomap_dio_rw(struct kiocb *iocb, struct iov_iter *iter, } goto out_free_dio; } + } - if (!wait_for_completion && !inode->i_sb->s_dio_done_wq) { - ret = sb_init_dio_done_wq(inode->i_sb); - if (ret < 0) - goto out_free_dio; - } + if (!wait_for_completion && !inode->i_sb->s_dio_done_wq) { + ret = sb_init_dio_done_wq(inode->i_sb); + if (ret < 0) + goto out_free_dio; } inode_dio_begin(inode); From ad26a7ef04882d26dfb365335baacfbd8be97f21 Mon Sep 17 00:00:00 2001 From: Ria Thomas Date: Mon, 24 Nov 2025 18:26:37 +0530 Subject: [PATCH 0793/2333] wifi: ieee80211: correct FILS status codes [ Upstream commit 24d4da5c2565313c2ad3c43449937a9351a64407 ] The FILS status codes are set to 108/109, but the IEEE 802.11-2020 spec defines them as 112/113. Update the enum so it matches the specification and keeps the kernel consistent with standard values. Fixes: a3caf7440ded ("cfg80211: Add support for FILS shared key authentication offload") Signed-off-by: Ria Thomas Reviewed-by: Jeff Johnson Link: https://patch.msgid.link/20251124125637.3936154-1-ria.thomas@morsemicro.com Signed-off-by: Johannes Berg Signed-off-by: Sasha Levin --- include/linux/ieee80211.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index ddff9102f6332..1f4679092e69d 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -3594,8 +3594,8 @@ enum ieee80211_statuscode { WLAN_STATUS_DENIED_WITH_SUGGESTED_BAND_AND_CHANNEL = 99, WLAN_STATUS_DENIED_DUE_TO_SPECTRUM_MANAGEMENT = 103, /* 802.11ai */ - WLAN_STATUS_FILS_AUTHENTICATION_FAILURE = 108, - WLAN_STATUS_UNKNOWN_AUTHENTICATION_SERVER = 109, + WLAN_STATUS_FILS_AUTHENTICATION_FAILURE = 112, + WLAN_STATUS_UNKNOWN_AUTHENTICATION_SERVER = 113, WLAN_STATUS_SAE_HASH_TO_ELEMENT = 126, WLAN_STATUS_SAE_PK = 127, WLAN_STATUS_DENIED_TID_TO_LINK_MAPPING = 133, From 08c9dc6b0f2c68e5e7c374ac4499e321e435d46c Mon Sep 17 00:00:00 2001 From: Luca Ceresoli Date: Mon, 19 May 2025 22:19:11 +0200 Subject: [PATCH 0794/2333] backlight: led-bl: Add devlink to supplier LEDs [ Upstream commit 9341d6698f4cfdfc374fb6944158d111ebe16a9d ] LED Backlight is a consumer of one or multiple LED class devices, but devlink is currently unable to create correct supplier-producer links when the supplier is a class device. It creates instead a link where the supplier is the parent of the expected device. One consequence is that removal order is not correctly enforced. Issues happen for example with the following sections in a device tree overlay: // An LED driver chip pca9632@62 { compatible = "nxp,pca9632"; reg = <0x62>; // ... addon_led_pwm: led-pwm@3 { reg = <3>; label = "addon:led:pwm"; }; }; backlight-addon { compatible = "led-backlight"; leds = <&addon_led_pwm>; brightness-levels = <255>; default-brightness-level = <255>; }; In this example, the devlink should be created between the backlight-addon (consumer) and the pca9632@62 (supplier). Instead it is created between the backlight-addon (consumer) and the parent of the pca9632@62, which is typically the I2C bus adapter. On removal of the above overlay, the LED driver can be removed before the backlight device, resulting in: Unable to handle kernel NULL pointer dereference at virtual address 0000000000000010 ... Call trace: led_put+0xe0/0x140 devm_led_release+0x6c/0x98 Another way to reproduce the bug without any device tree overlays is unbinding the LED class device (pca9632@62) before unbinding the consumer (backlight-addon): echo 11-0062 >/sys/bus/i2c/drivers/leds-pca963x/unbind echo ...backlight-dock >/sys/bus/platform/drivers/led-backlight/unbind Fix by adding a devlink between the consuming led-backlight device and the supplying LED device, as other drivers and subsystems do as well. Fixes: ae232e45acf9 ("backlight: add led-backlight driver") Signed-off-by: Luca Ceresoli Reviewed-by: Daniel Thompson (RISCstar) Reviewed-by: Herve Codina Tested-by: Alexander Sverdlin Link: https://patch.msgid.link/20250519-led-backlight-add-devlink-to-supplier-class-device-v6-1-845224aeb2ce@bootlin.com Signed-off-by: Lee Jones Signed-off-by: Sasha Levin --- drivers/video/backlight/led_bl.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/video/backlight/led_bl.c b/drivers/video/backlight/led_bl.c index efc5e380669ae..f7ab9b3607313 100644 --- a/drivers/video/backlight/led_bl.c +++ b/drivers/video/backlight/led_bl.c @@ -210,6 +210,19 @@ static int led_bl_probe(struct platform_device *pdev) return PTR_ERR(priv->bl_dev); } + for (i = 0; i < priv->nb_leds; i++) { + struct device_link *link; + + link = device_link_add(&pdev->dev, priv->leds[i]->dev->parent, + DL_FLAG_AUTOREMOVE_CONSUMER); + if (!link) { + dev_err(&pdev->dev, "Failed to add devlink (consumer %s, supplier %s)\n", + dev_name(&pdev->dev), dev_name(priv->leds[i]->dev->parent)); + backlight_device_unregister(priv->bl_dev); + return -EINVAL; + } + } + for (i = 0; i < priv->nb_leds; i++) { mutex_lock(&priv->leds[i]->led_access); led_sysfs_disable(priv->leds[i]); From 57c6cea2073c4561487967476bd9c05a4d4e49e7 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Mon, 10 Nov 2025 22:09:16 -0800 Subject: [PATCH 0795/2333] backlight: lp855x: Fix lp855x.h kernel-doc warnings [ Upstream commit 2d45db63260c6ae3cf007361e04a1c41bd265084 ] Add a missing struct short description and a missing leading " *" to lp855x.h to avoid kernel-doc warnings: Warning: include/linux/platform_data/lp855x.h:126 missing initial short description on line: * struct lp855x_platform_data Warning: include/linux/platform_data/lp855x.h:131 bad line: Only valid when mode is PWM_BASED. Fixes: 7be865ab8634 ("backlight: new backlight driver for LP855x devices") Signed-off-by: Randy Dunlap Reviewed-by: Daniel Thompson (RISCstar) Link: https://patch.msgid.link/20251111060916.1995920-1-rdunlap@infradead.org Signed-off-by: Lee Jones Signed-off-by: Sasha Levin --- include/linux/platform_data/lp855x.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/linux/platform_data/lp855x.h b/include/linux/platform_data/lp855x.h index ab222dd05bbc2..3b4a891acefe9 100644 --- a/include/linux/platform_data/lp855x.h +++ b/include/linux/platform_data/lp855x.h @@ -124,12 +124,12 @@ struct lp855x_rom_data { }; /** - * struct lp855x_platform_data + * struct lp855x_platform_data - lp855 platform-specific data * @name : Backlight driver name. If it is not defined, default name is set. * @device_control : value of DEVICE CONTROL register * @initial_brightness : initial value of backlight brightness * @period_ns : platform specific pwm period value. unit is nano. - Only valid when mode is PWM_BASED. + * Only valid when mode is PWM_BASED. * @size_program : total size of lp855x_rom_data * @rom_data : list of new eeprom/eprom registers */ From cefb67ea27f95715a1e33e0e9ca0488f6495e051 Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Thu, 21 Aug 2025 10:33:53 +0200 Subject: [PATCH 0796/2333] iommu/arm-smmu-qcom: Enable use of all SMR groups when running bare-metal [ Upstream commit 5583a55e074b33ccd88ac0542fd7cd656a7e2c8c ] Some platforms (e.g. SC8280XP and X1E) support more than 128 stream matching groups. This is more than what is defined as maximum by the ARM SMMU architecture specification. Commit 122611347326 ("iommu/arm-smmu-qcom: Limit the SMR groups to 128") disabled use of the additional groups because they don't exhibit the same behavior as the architecture supported ones. It seems like this is just another quirk of the hypervisor: When running bare-metal without the hypervisor, the additional groups appear to behave just like all others. The boot firmware uses some of the additional groups, so ignoring them in this situation leads to stream match conflicts whenever we allocate a new SMR group for the same SID. The workaround exists primarily because the bypass quirk detection fails when using a S2CR register from the additional matching groups, so let's perform the test with the last reliable S2CR (127) and then limit the number of SMR groups only if we detect that we are running below the hypervisor (because of the bypass quirk). Fixes: 122611347326 ("iommu/arm-smmu-qcom: Limit the SMR groups to 128") Signed-off-by: Stephan Gerhold Signed-off-by: Will Deacon Signed-off-by: Sasha Levin --- drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c | 27 ++++++++++++++-------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c index 57c097e876130..c939d0856b719 100644 --- a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c +++ b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c @@ -431,17 +431,19 @@ static int qcom_smmu_cfg_probe(struct arm_smmu_device *smmu) /* * Some platforms support more than the Arm SMMU architected maximum of - * 128 stream matching groups. For unknown reasons, the additional - * groups don't exhibit the same behavior as the architected registers, - * so limit the groups to 128 until the behavior is fixed for the other - * groups. + * 128 stream matching groups. The additional registers appear to have + * the same behavior as the architected registers in the hardware. + * However, on some firmware versions, the hypervisor does not + * correctly trap and emulate accesses to the additional registers, + * resulting in unexpected behavior. + * + * If there are more than 128 groups, use the last reliable group to + * detect if we need to apply the bypass quirk. */ - if (smmu->num_mapping_groups > 128) { - dev_notice(smmu->dev, "\tLimiting the stream matching groups to 128\n"); - smmu->num_mapping_groups = 128; - } - - last_s2cr = ARM_SMMU_GR0_S2CR(smmu->num_mapping_groups - 1); + if (smmu->num_mapping_groups > 128) + last_s2cr = ARM_SMMU_GR0_S2CR(127); + else + last_s2cr = ARM_SMMU_GR0_S2CR(smmu->num_mapping_groups - 1); /* * With some firmware versions writes to S2CR of type FAULT are @@ -464,6 +466,11 @@ static int qcom_smmu_cfg_probe(struct arm_smmu_device *smmu) reg = FIELD_PREP(ARM_SMMU_CBAR_TYPE, CBAR_TYPE_S1_TRANS_S2_BYPASS); arm_smmu_gr1_write(smmu, ARM_SMMU_GR1_CBAR(qsmmu->bypass_cbndx), reg); + + if (smmu->num_mapping_groups > 128) { + dev_notice(smmu->dev, "\tLimiting the stream matching groups to 128\n"); + smmu->num_mapping_groups = 128; + } } for (i = 0; i < smmu->num_mapping_groups; i++) { From 118894098d4e139afbaa397090ead292196d1ccb Mon Sep 17 00:00:00 2001 From: Krzysztof Czurylo Date: Mon, 24 Nov 2025 20:53:42 -0600 Subject: [PATCH 0797/2333] RDMA/irdma: Fix data race in irdma_sc_ccq_arm [ Upstream commit a521928164433de44fed5aaf5f49aeb3f1fb96f5 ] Adds a lock around irdma_sc_ccq_arm body to prevent inter-thread data race. Fixes data race in irdma_sc_ccq_arm() reported by KCSAN: BUG: KCSAN: data-race in irdma_sc_ccq_arm [irdma] / irdma_sc_ccq_arm [irdma] read to 0xffff9d51b4034220 of 8 bytes by task 255 on cpu 11: irdma_sc_ccq_arm+0x36/0xd0 [irdma] irdma_cqp_ce_handler+0x300/0x310 [irdma] cqp_compl_worker+0x2a/0x40 [irdma] process_one_work+0x402/0x7e0 worker_thread+0xb3/0x6d0 kthread+0x178/0x1a0 ret_from_fork+0x2c/0x50 write to 0xffff9d51b4034220 of 8 bytes by task 89 on cpu 3: irdma_sc_ccq_arm+0x7e/0xd0 [irdma] irdma_cqp_ce_handler+0x300/0x310 [irdma] irdma_wait_event+0xd4/0x3e0 [irdma] irdma_handle_cqp_op+0xa5/0x220 [irdma] irdma_hw_flush_wqes+0xb1/0x300 [irdma] irdma_flush_wqes+0x22e/0x3a0 [irdma] irdma_cm_disconn_true+0x4c7/0x5d0 [irdma] irdma_disconnect_worker+0x35/0x50 [irdma] process_one_work+0x402/0x7e0 worker_thread+0xb3/0x6d0 kthread+0x178/0x1a0 ret_from_fork+0x2c/0x50 value changed: 0x0000000000024000 -> 0x0000000000034000 Fixes: 3f49d6842569 ("RDMA/irdma: Implement HW Admin Queue OPs") Signed-off-by: Krzysztof Czurylo Signed-off-by: Tatyana Nikolova Link: https://patch.msgid.link/20251125025350.180-2-tatyana.e.nikolova@intel.com Signed-off-by: Leon Romanovsky Signed-off-by: Sasha Levin --- drivers/infiniband/hw/irdma/ctrl.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/infiniband/hw/irdma/ctrl.c b/drivers/infiniband/hw/irdma/ctrl.c index 4ef1c29032f77..991ce4890bfb2 100644 --- a/drivers/infiniband/hw/irdma/ctrl.c +++ b/drivers/infiniband/hw/irdma/ctrl.c @@ -3950,11 +3950,13 @@ int irdma_sc_cqp_destroy(struct irdma_sc_cqp *cqp) */ void irdma_sc_ccq_arm(struct irdma_sc_cq *ccq) { + unsigned long flags; u64 temp_val; u16 sw_cq_sel; u8 arm_next_se; u8 arm_seq_num; + spin_lock_irqsave(&ccq->dev->cqp_lock, flags); get_64bit_val(ccq->cq_uk.shadow_area, 32, &temp_val); sw_cq_sel = (u16)FIELD_GET(IRDMA_CQ_DBSA_SW_CQ_SELECT, temp_val); arm_next_se = (u8)FIELD_GET(IRDMA_CQ_DBSA_ARM_NEXT_SE, temp_val); @@ -3965,6 +3967,7 @@ void irdma_sc_ccq_arm(struct irdma_sc_cq *ccq) FIELD_PREP(IRDMA_CQ_DBSA_ARM_NEXT_SE, arm_next_se) | FIELD_PREP(IRDMA_CQ_DBSA_ARM_NEXT, 1); set_64bit_val(ccq->cq_uk.shadow_area, 32, temp_val); + spin_unlock_irqrestore(&ccq->dev->cqp_lock, flags); dma_wmb(); /* make sure shadow area is updated before arming */ From 4b8abcc87373c97c92512b86bd49bc8048e0a301 Mon Sep 17 00:00:00 2001 From: Krzysztof Czurylo Date: Mon, 24 Nov 2025 20:53:43 -0600 Subject: [PATCH 0798/2333] RDMA/irdma: Fix data race in irdma_free_pble [ Upstream commit 81f44409fb4f027d1e6d54edbeba5156ad94b214 ] Protects pble_rsrc counters with mutex to prevent data race. Fixes the following data race in irdma_free_pble reported by KCSAN: BUG: KCSAN: data-race in irdma_free_pble [irdma] / irdma_free_pble [irdma] write to 0xffff91430baa0078 of 8 bytes by task 16956 on cpu 5: irdma_free_pble+0x3b/0xb0 [irdma] irdma_dereg_mr+0x108/0x110 [irdma] ib_dereg_mr_user+0x74/0x160 [ib_core] uverbs_free_mr+0x26/0x30 [ib_uverbs] destroy_hw_idr_uobject+0x4a/0x90 [ib_uverbs] uverbs_destroy_uobject+0x7b/0x330 [ib_uverbs] uobj_destroy+0x61/0xb0 [ib_uverbs] ib_uverbs_run_method+0x1f2/0x380 [ib_uverbs] ib_uverbs_cmd_verbs+0x365/0x440 [ib_uverbs] ib_uverbs_ioctl+0x111/0x190 [ib_uverbs] __x64_sys_ioctl+0xc9/0x100 do_syscall_64+0x44/0xa0 entry_SYSCALL_64_after_hwframe+0x6e/0xd8 read to 0xffff91430baa0078 of 8 bytes by task 16953 on cpu 2: irdma_free_pble+0x23/0xb0 [irdma] irdma_dereg_mr+0x108/0x110 [irdma] ib_dereg_mr_user+0x74/0x160 [ib_core] uverbs_free_mr+0x26/0x30 [ib_uverbs] destroy_hw_idr_uobject+0x4a/0x90 [ib_uverbs] uverbs_destroy_uobject+0x7b/0x330 [ib_uverbs] uobj_destroy+0x61/0xb0 [ib_uverbs] ib_uverbs_run_method+0x1f2/0x380 [ib_uverbs] ib_uverbs_cmd_verbs+0x365/0x440 [ib_uverbs] ib_uverbs_ioctl+0x111/0x190 [ib_uverbs] __x64_sys_ioctl+0xc9/0x100 do_syscall_64+0x44/0xa0 entry_SYSCALL_64_after_hwframe+0x6e/0xd8 value changed: 0x0000000000005a62 -> 0x0000000000005a68 Fixes: e8c4dbc2fcac ("RDMA/irdma: Add PBLE resource manager") Signed-off-by: Krzysztof Czurylo Signed-off-by: Tatyana Nikolova Link: https://patch.msgid.link/20251125025350.180-3-tatyana.e.nikolova@intel.com Signed-off-by: Leon Romanovsky Signed-off-by: Sasha Levin --- drivers/infiniband/hw/irdma/pble.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/hw/irdma/pble.c b/drivers/infiniband/hw/irdma/pble.c index fa6325adaedec..28dfad7f940c2 100644 --- a/drivers/infiniband/hw/irdma/pble.c +++ b/drivers/infiniband/hw/irdma/pble.c @@ -506,12 +506,14 @@ int irdma_get_pble(struct irdma_hmc_pble_rsrc *pble_rsrc, void irdma_free_pble(struct irdma_hmc_pble_rsrc *pble_rsrc, struct irdma_pble_alloc *palloc) { - pble_rsrc->freedpbles += palloc->total_cnt; - if (palloc->level == PBLE_LEVEL_2) free_lvl2(pble_rsrc, palloc); else irdma_prm_return_pbles(&pble_rsrc->pinfo, &palloc->level1.chunkinfo); + + mutex_lock(&pble_rsrc->pble_mutex_lock); + pble_rsrc->freedpbles += palloc->total_cnt; pble_rsrc->stats_alloc_freed++; + mutex_unlock(&pble_rsrc->pble_mutex_lock); } From e0331f477c1925b1eaf5c7c385ff14f8efc86aad Mon Sep 17 00:00:00 2001 From: Tatyana Nikolova Date: Mon, 24 Nov 2025 20:53:44 -0600 Subject: [PATCH 0799/2333] RDMA/irdma: Add a missing kfree of struct irdma_pci_f for GEN2 [ Upstream commit 9e13d880ebae5da9b39ef2ed83a89737e927173f ] During a refactor of the irdma GEN2 code, the kfree of the irdma_pci_f struct in icrdma_remove(), which was originally introduced upstream as part of commit 80f2ab46c2ee ("irdma: free iwdev->rf after removing MSI-X") was accidentally removed. Fixes: 0c2b80cac96e ("RDMA/irdma: Refactor GEN2 auxiliary driver") Signed-off-by: Krzysztof Czurylo Signed-off-by: Tatyana Nikolova Link: https://patch.msgid.link/20251125025350.180-4-tatyana.e.nikolova@intel.com Signed-off-by: Leon Romanovsky Signed-off-by: Sasha Levin --- drivers/infiniband/hw/irdma/icrdma_if.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/infiniband/hw/irdma/icrdma_if.c b/drivers/infiniband/hw/irdma/icrdma_if.c index 27b191f61caf4..5d3fd118e4f81 100644 --- a/drivers/infiniband/hw/irdma/icrdma_if.c +++ b/drivers/infiniband/hw/irdma/icrdma_if.c @@ -320,6 +320,8 @@ static void icrdma_remove(struct auxiliary_device *aux_dev) irdma_ib_unregister_device(iwdev); icrdma_deinit_interrupts(iwdev->rf, cdev_info); + kfree(iwdev->rf); + pr_debug("INIT: Gen[%d] func[%d] device remove success\n", rdma_ver, PCI_FUNC(cdev_info->pdev->devfn)); } From b0258b9ecbc0a46fa6d4bdd2b9c3b546ca13c84f Mon Sep 17 00:00:00 2001 From: Krzysztof Czurylo Date: Mon, 24 Nov 2025 20:53:45 -0600 Subject: [PATCH 0800/2333] RDMA/irdma: Fix SIGBUS in AEQ destroy [ Upstream commit 5eff1ecce30143c3f8924d91770d81d44bd5abe5 ] Removes write to IRDMA_PFINT_AEQCTL register prior to destroying AEQ, as this register does not exist in GEN3+ hardware and this kind of IRQ configuration is no longer required. Fixes: b800e82feba7 ("RDMA/irdma: Add GEN3 support for AEQ and CEQ") Signed-off-by: Krzysztof Czurylo Signed-off-by: Tatyana Nikolova Link: https://patch.msgid.link/20251125025350.180-5-tatyana.e.nikolova@intel.com Signed-off-by: Leon Romanovsky Signed-off-by: Sasha Levin --- drivers/infiniband/hw/irdma/ctrl.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/irdma/ctrl.c b/drivers/infiniband/hw/irdma/ctrl.c index 991ce4890bfb2..cb970c9090ee0 100644 --- a/drivers/infiniband/hw/irdma/ctrl.c +++ b/drivers/infiniband/hw/irdma/ctrl.c @@ -4734,7 +4734,8 @@ static int irdma_sc_aeq_destroy(struct irdma_sc_aeq *aeq, u64 scratch, u64 hdr; dev = aeq->dev; - if (dev->privileged) + + if (dev->hw_attrs.uk_attrs.hw_rev <= IRDMA_GEN_2) writel(0, dev->hw_regs[IRDMA_PFINT_AEQCTL]); cqp = dev->cqp; From 4b71f69c49141d6b13d05559cbac66f36aa6d644 Mon Sep 17 00:00:00 2001 From: Anil Samal Date: Mon, 24 Nov 2025 20:53:46 -0600 Subject: [PATCH 0801/2333] RDMA/irdma: Add missing mutex destroy [ Upstream commit 35bd787babd1f5a42641d0b1513edbed5d4e1624 ] Add missing destroy of ah_tbl_lock and vchnl_mutex. Fixes: d5edd33364a5 ("RDMA/irdma: RDMA/irdma: Add GEN3 core driver support") Signed-off-by: Anil Samal Signed-off-by: Krzysztof Czurylo Signed-off-by: Tatyana Nikolova Link: https://patch.msgid.link/20251125025350.180-6-tatyana.e.nikolova@intel.com Signed-off-by: Leon Romanovsky Signed-off-by: Sasha Levin --- drivers/infiniband/hw/irdma/icrdma_if.c | 4 +++- drivers/infiniband/hw/irdma/ig3rdma_if.c | 4 ++++ drivers/infiniband/hw/irdma/verbs.c | 4 +++- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/hw/irdma/icrdma_if.c b/drivers/infiniband/hw/irdma/icrdma_if.c index 5d3fd118e4f81..b49fd9cf24765 100644 --- a/drivers/infiniband/hw/irdma/icrdma_if.c +++ b/drivers/infiniband/hw/irdma/icrdma_if.c @@ -302,7 +302,8 @@ static int icrdma_probe(struct auxiliary_device *aux_dev, const struct auxiliary err_ctrl_init: icrdma_deinit_interrupts(rf, cdev_info); err_init_interrupts: - kfree(iwdev->rf); + mutex_destroy(&rf->ah_tbl_lock); + kfree(rf); ib_dealloc_device(&iwdev->ibdev); return err; @@ -319,6 +320,7 @@ static void icrdma_remove(struct auxiliary_device *aux_dev) ice_rdma_update_vsi_filter(cdev_info, iwdev->vsi_num, false); irdma_ib_unregister_device(iwdev); icrdma_deinit_interrupts(iwdev->rf, cdev_info); + mutex_destroy(&iwdev->rf->ah_tbl_lock); kfree(iwdev->rf); diff --git a/drivers/infiniband/hw/irdma/ig3rdma_if.c b/drivers/infiniband/hw/irdma/ig3rdma_if.c index 1bb42eb298ba6..e1d6670d9396e 100644 --- a/drivers/infiniband/hw/irdma/ig3rdma_if.c +++ b/drivers/infiniband/hw/irdma/ig3rdma_if.c @@ -55,6 +55,7 @@ static int ig3rdma_vchnl_init(struct irdma_pci_f *rf, ret = irdma_sc_vchnl_init(&rf->sc_dev, &virt_info); if (ret) { destroy_workqueue(rf->vchnl_wq); + mutex_destroy(&rf->sc_dev.vchnl_mutex); return ret; } @@ -124,7 +125,9 @@ static void ig3rdma_decfg_rf(struct irdma_pci_f *rf) { struct irdma_hw *hw = &rf->hw; + mutex_destroy(&rf->ah_tbl_lock); destroy_workqueue(rf->vchnl_wq); + mutex_destroy(&rf->sc_dev.vchnl_mutex); kfree(hw->io_regs); iounmap(hw->rdma_reg.addr); } @@ -149,6 +152,7 @@ static int ig3rdma_cfg_rf(struct irdma_pci_f *rf, err = ig3rdma_cfg_regions(&rf->hw, cdev_info); if (err) { destroy_workqueue(rf->vchnl_wq); + mutex_destroy(&rf->sc_dev.vchnl_mutex); return err; } diff --git a/drivers/infiniband/hw/irdma/verbs.c b/drivers/infiniband/hw/irdma/verbs.c index c883c9ea5a831..c884f2ce282f9 100644 --- a/drivers/infiniband/hw/irdma/verbs.c +++ b/drivers/infiniband/hw/irdma/verbs.c @@ -5500,7 +5500,9 @@ void irdma_ib_dealloc_device(struct ib_device *ibdev) irdma_rt_deinit_hw(iwdev); if (!iwdev->is_vport) { irdma_ctrl_deinit_hw(iwdev->rf); - if (iwdev->rf->vchnl_wq) + if (iwdev->rf->vchnl_wq) { destroy_workqueue(iwdev->rf->vchnl_wq); + mutex_destroy(&iwdev->rf->sc_dev.vchnl_mutex); + } } } From aac0552d66c2cc9fae23d5821ea75f54df94ac49 Mon Sep 17 00:00:00 2001 From: Jacob Moroni Date: Mon, 24 Nov 2025 20:53:47 -0600 Subject: [PATCH 0802/2333] RDMA/irdma: Do not directly rely on IB_PD_UNSAFE_GLOBAL_RKEY [ Upstream commit 71d3bdae5eab21cf8991a6f3cd914caa31d5a51f ] The HW disables bounds checking for MRs with a length of zero, so the driver will only allow a zero length MR if the "all_memory" flag is set, and this flag is only set if IB_PD_UNSAFE_GLOBAL_RKEY is set for the PD. This means that the "get_dma_mr" method will currently fail unless the IB_PD_UNSAFE_GLOBAL_RKEY flag is set. This has not been an issue because the "get_dma_mr" method is only ever invoked if the device does not support the local DMA key or if IB_PD_UNSAFE_GLOBAL_RKEY is set, and so far, all IRDMA HW supports the local DMA lkey. However, some new HW does not support the local DMA lkey, so the "get_dma_mr" method needs to work without IB_PD_UNSAFE_GLOBAL_RKEY being set. To support HW that does not allow the local DMA lkey, the logic has been changed to pass an explicit flag to indicate when a dma_mr is being created so that the zero length will be allowed. Also, the "all_memory" flag has been forced to false for normal MR allocation since these MRs are never supposed to provide global unsafe rkey semantics anyway; only the MR created with "get_dma_mr" should support this. Fixes: bb6d73d9add6 ("RDMA/irdma: Prevent zero-length STAG registration") Signed-off-by: Jacob Moroni Signed-off-by: Tatyana Nikolova Link: https://patch.msgid.link/20251125025350.180-7-tatyana.e.nikolova@intel.com Signed-off-by: Leon Romanovsky Signed-off-by: Sasha Levin --- drivers/infiniband/hw/irdma/cm.c | 2 +- drivers/infiniband/hw/irdma/main.h | 2 +- drivers/infiniband/hw/irdma/verbs.c | 15 ++++++++------- drivers/infiniband/hw/irdma/verbs.h | 3 ++- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/drivers/infiniband/hw/irdma/cm.c b/drivers/infiniband/hw/irdma/cm.c index c6a0a661d6e7e..f4f4f92ba63ac 100644 --- a/drivers/infiniband/hw/irdma/cm.c +++ b/drivers/infiniband/hw/irdma/cm.c @@ -3710,7 +3710,7 @@ int irdma_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) iwpd = iwqp->iwpd; tagged_offset = (uintptr_t)iwqp->ietf_mem.va; ibmr = irdma_reg_phys_mr(&iwpd->ibpd, iwqp->ietf_mem.pa, buf_len, - IB_ACCESS_LOCAL_WRITE, &tagged_offset); + IB_ACCESS_LOCAL_WRITE, &tagged_offset, false); if (IS_ERR(ibmr)) { ret = -ENOMEM; goto error; diff --git a/drivers/infiniband/hw/irdma/main.h b/drivers/infiniband/hw/irdma/main.h index 886b30da188ae..65ce4924dbfa6 100644 --- a/drivers/infiniband/hw/irdma/main.h +++ b/drivers/infiniband/hw/irdma/main.h @@ -556,7 +556,7 @@ void irdma_copy_ip_htonl(__be32 *dst, u32 *src); u16 irdma_get_vlan_ipv4(u32 *addr); void irdma_get_vlan_mac_ipv6(u32 *addr, u16 *vlan_id, u8 *mac); struct ib_mr *irdma_reg_phys_mr(struct ib_pd *ib_pd, u64 addr, u64 size, - int acc, u64 *iova_start); + int acc, u64 *iova_start, bool dma_mr); int irdma_upload_qp_context(struct irdma_qp *iwqp, bool freeze, bool raw); void irdma_cqp_ce_handler(struct irdma_pci_f *rf, struct irdma_sc_cq *cq); int irdma_ah_cqp_op(struct irdma_pci_f *rf, struct irdma_sc_ah *sc_ah, u8 cmd, diff --git a/drivers/infiniband/hw/irdma/verbs.c b/drivers/infiniband/hw/irdma/verbs.c index c884f2ce282f9..8c44c3fcf9731 100644 --- a/drivers/infiniband/hw/irdma/verbs.c +++ b/drivers/infiniband/hw/irdma/verbs.c @@ -3108,7 +3108,6 @@ static int irdma_hw_alloc_stag(struct irdma_device *iwdev, info->stag_idx = iwmr->stag >> IRDMA_CQPSQ_STAG_IDX_S; info->pd_id = iwpd->sc_pd.pd_id; info->total_len = iwmr->len; - info->all_memory = pd->flags & IB_PD_UNSAFE_GLOBAL_RKEY; info->remote_access = true; cqp_info->cqp_cmd = IRDMA_OP_ALLOC_STAG; cqp_info->post_sq = 1; @@ -3119,7 +3118,7 @@ static int irdma_hw_alloc_stag(struct irdma_device *iwdev, if (status) return status; - iwmr->is_hwreg = 1; + iwmr->is_hwreg = true; return 0; } @@ -3263,7 +3262,7 @@ static int irdma_hwreg_mr(struct irdma_device *iwdev, struct irdma_mr *iwmr, if (iwdev->rf->sc_dev.hw_attrs.uk_attrs.feature_flags & IRDMA_FEATURE_ATOMIC_OPS) stag_info->remote_atomics_en = (access & IB_ACCESS_REMOTE_ATOMIC) ? 1 : 0; stag_info->pd_id = iwpd->sc_pd.pd_id; - stag_info->all_memory = pd->flags & IB_PD_UNSAFE_GLOBAL_RKEY; + stag_info->all_memory = iwmr->dma_mr; if (stag_info->access_rights & IRDMA_ACCESS_FLAGS_ZERO_BASED) stag_info->addr_type = IRDMA_ADDR_TYPE_ZERO_BASED; else @@ -3290,7 +3289,7 @@ static int irdma_hwreg_mr(struct irdma_device *iwdev, struct irdma_mr *iwmr, irdma_put_cqp_request(&iwdev->rf->cqp, cqp_request); if (!ret) - iwmr->is_hwreg = 1; + iwmr->is_hwreg = true; return ret; } @@ -3663,7 +3662,7 @@ static int irdma_hwdereg_mr(struct ib_mr *ib_mr) if (status) return status; - iwmr->is_hwreg = 0; + iwmr->is_hwreg = false; return 0; } @@ -3786,9 +3785,10 @@ static struct ib_mr *irdma_rereg_user_mr(struct ib_mr *ib_mr, int flags, * @size: size of memory to register * @access: Access rights * @iova_start: start of virtual address for physical buffers + * @dma_mr: Flag indicating whether this region is a PD DMA MR */ struct ib_mr *irdma_reg_phys_mr(struct ib_pd *pd, u64 addr, u64 size, int access, - u64 *iova_start) + u64 *iova_start, bool dma_mr) { struct irdma_device *iwdev = to_iwdev(pd->device); struct irdma_pbl *iwpbl; @@ -3805,6 +3805,7 @@ struct ib_mr *irdma_reg_phys_mr(struct ib_pd *pd, u64 addr, u64 size, int access iwpbl = &iwmr->iwpbl; iwpbl->iwmr = iwmr; iwmr->type = IRDMA_MEMREG_TYPE_MEM; + iwmr->dma_mr = dma_mr; iwpbl->user_base = *iova_start; stag = irdma_create_stag(iwdev); if (!stag) { @@ -3843,7 +3844,7 @@ static struct ib_mr *irdma_get_dma_mr(struct ib_pd *pd, int acc) { u64 kva = 0; - return irdma_reg_phys_mr(pd, 0, 0, acc, &kva); + return irdma_reg_phys_mr(pd, 0, 0, acc, &kva, true); } /** diff --git a/drivers/infiniband/hw/irdma/verbs.h b/drivers/infiniband/hw/irdma/verbs.h index ac8b387018350..aabbb3442098b 100644 --- a/drivers/infiniband/hw/irdma/verbs.h +++ b/drivers/infiniband/hw/irdma/verbs.h @@ -111,7 +111,8 @@ struct irdma_mr { }; struct ib_umem *region; int access; - u8 is_hwreg; + bool is_hwreg:1; + bool dma_mr:1; u16 type; u32 page_cnt; u64 page_size; From 951870eee2dc0eb11c6e62fc3fb8e43ec59654c3 Mon Sep 17 00:00:00 2001 From: Jacob Moroni Date: Mon, 24 Nov 2025 20:53:48 -0600 Subject: [PATCH 0803/2333] RDMA/irdma: Do not set IBK_LOCAL_DMA_LKEY for GEN3+ [ Upstream commit eef3ad030b08c0f100cb18de7f604442a1adb8c7 ] The GEN3 hardware does not appear to support IBK_LOCAL_DMA_LKEY. Attempts to use it will result in an AE. Fixes: eb31dfc2b41a ("RDMA/irdma: Restrict Memory Window and CQE Timestamping to GEN3") Signed-off-by: Jacob Moroni Signed-off-by: Tatyana Nikolova Link: https://patch.msgid.link/20251125025350.180-8-tatyana.e.nikolova@intel.com Signed-off-by: Leon Romanovsky Signed-off-by: Sasha Levin --- drivers/infiniband/hw/irdma/verbs.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/irdma/verbs.c b/drivers/infiniband/hw/irdma/verbs.c index 8c44c3fcf9731..afccd9f08b8a5 100644 --- a/drivers/infiniband/hw/irdma/verbs.c +++ b/drivers/infiniband/hw/irdma/verbs.c @@ -27,7 +27,8 @@ static int irdma_query_device(struct ib_device *ibdev, irdma_fw_minor_ver(&rf->sc_dev); props->device_cap_flags = IB_DEVICE_MEM_WINDOW | IB_DEVICE_MEM_MGT_EXTENSIONS; - props->kernel_cap_flags = IBK_LOCAL_DMA_LKEY; + if (hw_attrs->uk_attrs.hw_rev < IRDMA_GEN_3) + props->kernel_cap_flags = IBK_LOCAL_DMA_LKEY; props->vendor_id = pcidev->vendor; props->vendor_part_id = pcidev->device; From 63f755a2ef55c041a9763a94500a7e66b13f838e Mon Sep 17 00:00:00 2001 From: Jacob Moroni Date: Mon, 24 Nov 2025 20:53:49 -0600 Subject: [PATCH 0804/2333] RDMA/irdma: Remove doorbell elision logic [ Upstream commit 62356fccb195f83d2ceafc787c5ba87ebbe5edfe ] In some cases, this logic can result in doorbell writes being skipped when they should not have been (at least on GEN3 HW), so remove it. This also means that the mb() can be safely downgraded to dma_wmb(). Fixes: 551c46edc769 ("RDMA/irdma: Add user/kernel shared libraries") Signed-off-by: Jacob Moroni Signed-off-by: Tatyana Nikolova Link: https://patch.msgid.link/20251125025350.180-9-tatyana.e.nikolova@intel.com Signed-off-by: Leon Romanovsky Signed-off-by: Sasha Levin --- drivers/infiniband/hw/irdma/puda.c | 1 - drivers/infiniband/hw/irdma/uk.c | 31 ++---------------------------- drivers/infiniband/hw/irdma/user.h | 1 - 3 files changed, 2 insertions(+), 31 deletions(-) diff --git a/drivers/infiniband/hw/irdma/puda.c b/drivers/infiniband/hw/irdma/puda.c index 694e5a9ed15d0..9cd14a50f1a93 100644 --- a/drivers/infiniband/hw/irdma/puda.c +++ b/drivers/infiniband/hw/irdma/puda.c @@ -685,7 +685,6 @@ static int irdma_puda_qp_create(struct irdma_puda_rsrc *rsrc) ukqp->rq_size = rsrc->rq_size; IRDMA_RING_INIT(ukqp->sq_ring, ukqp->sq_size); - IRDMA_RING_INIT(ukqp->initial_ring, ukqp->sq_size); IRDMA_RING_INIT(ukqp->rq_ring, ukqp->rq_size); ukqp->wqe_alloc_db = qp->pd->dev->wqe_alloc_db; diff --git a/drivers/infiniband/hw/irdma/uk.c b/drivers/infiniband/hw/irdma/uk.c index ce1ae10c30fca..d5568584ad5e3 100644 --- a/drivers/infiniband/hw/irdma/uk.c +++ b/drivers/infiniband/hw/irdma/uk.c @@ -114,33 +114,8 @@ void irdma_clr_wqes(struct irdma_qp_uk *qp, u32 qp_wqe_idx) */ void irdma_uk_qp_post_wr(struct irdma_qp_uk *qp) { - u64 temp; - u32 hw_sq_tail; - u32 sw_sq_head; - - /* valid bit is written and loads completed before reading shadow */ - mb(); - - /* read the doorbell shadow area */ - get_64bit_val(qp->shadow_area, 0, &temp); - - hw_sq_tail = (u32)FIELD_GET(IRDMA_QP_DBSA_HW_SQ_TAIL, temp); - sw_sq_head = IRDMA_RING_CURRENT_HEAD(qp->sq_ring); - if (sw_sq_head != qp->initial_ring.head) { - if (sw_sq_head != hw_sq_tail) { - if (sw_sq_head > qp->initial_ring.head) { - if (hw_sq_tail >= qp->initial_ring.head && - hw_sq_tail < sw_sq_head) - writel(qp->qp_id, qp->wqe_alloc_db); - } else { - if (hw_sq_tail >= qp->initial_ring.head || - hw_sq_tail < sw_sq_head) - writel(qp->qp_id, qp->wqe_alloc_db); - } - } - } - - qp->initial_ring.head = qp->sq_ring.head; + dma_wmb(); + writel(qp->qp_id, qp->wqe_alloc_db); } /** @@ -1574,7 +1549,6 @@ static void irdma_setup_connection_wqes(struct irdma_qp_uk *qp, qp->conn_wqes = move_cnt; IRDMA_RING_MOVE_HEAD_BY_COUNT_NOCHECK(qp->sq_ring, move_cnt); IRDMA_RING_MOVE_TAIL_BY_COUNT(qp->sq_ring, move_cnt); - IRDMA_RING_MOVE_HEAD_BY_COUNT_NOCHECK(qp->initial_ring, move_cnt); } /** @@ -1719,7 +1693,6 @@ int irdma_uk_qp_init(struct irdma_qp_uk *qp, struct irdma_qp_uk_init_info *info) qp->max_sq_frag_cnt = info->max_sq_frag_cnt; sq_ring_size = qp->sq_size << info->sq_shift; IRDMA_RING_INIT(qp->sq_ring, sq_ring_size); - IRDMA_RING_INIT(qp->initial_ring, sq_ring_size); if (info->first_sq_wq) { irdma_setup_connection_wqes(qp, info); qp->swqe_polarity = 1; diff --git a/drivers/infiniband/hw/irdma/user.h b/drivers/infiniband/hw/irdma/user.h index ab57f689827a0..aeebf768174ab 100644 --- a/drivers/infiniband/hw/irdma/user.h +++ b/drivers/infiniband/hw/irdma/user.h @@ -456,7 +456,6 @@ struct irdma_srq_uk { struct irdma_uk_attrs *uk_attrs; __le64 *shadow_area; struct irdma_ring srq_ring; - struct irdma_ring initial_ring; u32 srq_id; u32 srq_size; u32 max_srq_frag_cnt; From 73573f7e52842dfb1c205a6617afe5ae49335ea0 Mon Sep 17 00:00:00 2001 From: Jijun Wang Date: Mon, 24 Nov 2025 20:53:50 -0600 Subject: [PATCH 0805/2333] RDMA/irdma: Fix SRQ shadow area address initialization [ Upstream commit 01dad9ca37c60d08f71e2ef639875ae895deede6 ] Fix SRQ shadow area address initialization. Fixes: 563e1feb5f6e ("RDMA/irdma: Add SRQ support") Signed-off-by: Jijun Wang Signed-off-by: Jay Bhat Link: https://patch.msgid.link/20251125025350.180-10-tatyana.e.nikolova@intel.com Signed-off-by: Leon Romanovsky Signed-off-by: Sasha Levin --- drivers/infiniband/hw/irdma/verbs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/irdma/verbs.c b/drivers/infiniband/hw/irdma/verbs.c index afccd9f08b8a5..b8655504da290 100644 --- a/drivers/infiniband/hw/irdma/verbs.c +++ b/drivers/infiniband/hw/irdma/verbs.c @@ -2307,8 +2307,8 @@ static int irdma_setup_kmode_srq(struct irdma_device *iwdev, ukinfo->srq_size = depth >> shift; ukinfo->shadow_area = mem->va + ring_size; - info->shadow_area_pa = info->srq_pa + ring_size; info->srq_pa = mem->pa; + info->shadow_area_pa = info->srq_pa + ring_size; return 0; } From 46cd9849e5207e92b2f1d429a4688d4954c5918b Mon Sep 17 00:00:00 2001 From: Guillaume La Roque Date: Sun, 23 Nov 2025 18:14:10 +0100 Subject: [PATCH 0806/2333] arm64: dts: amlogic: meson-g12b: Fix L2 cache reference for S922X CPUs [ Upstream commit a7ab6f946683e065fa22db1cc2f2748d4584178a ] The original addition of cache information for the Amlogic S922X SoC used the wrong next-level cache node for CPU cores 100 and 101, incorrectly referencing `l2_cache_l`. These cores actually belong to the big cluster and should reference `l2_cache_b`. Update the device tree accordingly. Fixes: e7f85e6c155a ("arm64: dts: amlogic: Add cache information to the Amlogic S922X SoC") Signed-off-by: Guillaume La Roque Reviewed-by: Neil Armstrong Link: https://patch.msgid.link/20251123-fixkhadas-v1-1-045348f0a4c2@baylibre.com Signed-off-by: Neil Armstrong Signed-off-by: Sasha Levin --- arch/arm64/boot/dts/amlogic/meson-g12b.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/amlogic/meson-g12b.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12b.dtsi index f04efa8282561..23358d94844c9 100644 --- a/arch/arm64/boot/dts/amlogic/meson-g12b.dtsi +++ b/arch/arm64/boot/dts/amlogic/meson-g12b.dtsi @@ -87,7 +87,7 @@ i-cache-line-size = <32>; i-cache-size = <0x8000>; i-cache-sets = <32>; - next-level-cache = <&l2_cache_l>; + next-level-cache = <&l2_cache_b>; #cooling-cells = <2>; }; @@ -103,7 +103,7 @@ i-cache-line-size = <32>; i-cache-size = <0x8000>; i-cache-sets = <32>; - next-level-cache = <&l2_cache_l>; + next-level-cache = <&l2_cache_b>; #cooling-cells = <2>; }; From 0a3d0e94866352c9ecd75a50e361773ec06099f8 Mon Sep 17 00:00:00 2001 From: Akash Goel Date: Thu, 20 Nov 2025 17:21:18 +0000 Subject: [PATCH 0807/2333] drm/panthor: Avoid adding of kernel BOs to extobj list [ Upstream commit ce04ec03a9c2c4f3e60e26f21311b25d5a478208 ] The kernel BOs unnecessarily got added to the external objects list of drm_gpuvm, when mapping to GPU, which would have resulted in few extra CPU cycles being spent at the time of job submission as drm_exec_until_all_locked() loop iterates over all external objects. Kernel BOs are private to a VM and so they share the dma_resv object of the dummy GEM object created for a VM. Use of DRM_EXEC_IGNORE_DUPLICATES flag ensured the recursive locking of the dummy GEM object was ignored. Also no extra space got allocated to add fences to the dma_resv object of dummy GEM object. So no other impact apart from few extra CPU cycles. This commit sets the pointer to dma_resv object of GEM object of kernel BOs before they are mapped to GPU, to prevent them from being added to external objects list. v2: Add R-bs and fixes tags Fixes: 8a1cc07578bf ("drm/panthor: Add GEM logical block") Signed-off-by: Akash Goel Reviewed-by: Boris Brezillon Reviewed-by: Steven Price Link: https://patch.msgid.link/20251120172118.2741724-1-akash.goel@arm.com Signed-off-by: Boris Brezillon Signed-off-by: Sasha Levin --- drivers/gpu/drm/panthor/panthor_gem.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/panthor/panthor_gem.c b/drivers/gpu/drm/panthor/panthor_gem.c index 14ed09d700f2f..43471babff86c 100644 --- a/drivers/gpu/drm/panthor/panthor_gem.c +++ b/drivers/gpu/drm/panthor/panthor_gem.c @@ -144,6 +144,9 @@ panthor_kernel_bo_create(struct panthor_device *ptdev, struct panthor_vm *vm, bo = to_panthor_bo(&obj->base); kbo->obj = &obj->base; bo->flags = bo_flags; + bo->exclusive_vm_root_gem = panthor_vm_root_gem(vm); + drm_gem_object_get(bo->exclusive_vm_root_gem); + bo->base.base.resv = bo->exclusive_vm_root_gem->resv; if (vm == panthor_fw_vm(ptdev)) debug_flags |= PANTHOR_DEBUGFS_GEM_USAGE_FLAG_FW_MAPPED; @@ -167,9 +170,6 @@ panthor_kernel_bo_create(struct panthor_device *ptdev, struct panthor_vm *vm, goto err_free_va; kbo->vm = panthor_vm_get(vm); - bo->exclusive_vm_root_gem = panthor_vm_root_gem(vm); - drm_gem_object_get(bo->exclusive_vm_root_gem); - bo->base.base.resv = bo->exclusive_vm_root_gem->resv; return kbo; err_free_va: From cbc8d54c7313be21f82c252bda35e2ba36c3b4b4 Mon Sep 17 00:00:00 2001 From: Haotian Zhang Date: Thu, 30 Oct 2025 17:07:10 +0800 Subject: [PATCH 0808/2333] clocksource/drivers/ralink: Fix resource leaks in init error path [ Upstream commit 2ba8e2aae1324704565a7d4d66f199d056c9e3c6 ] The ralink_systick_init() function does not release all acquired resources on its error paths. If irq_of_parse_and_map() or a subsequent call fails, the previously created I/O memory mapping and IRQ mapping are leaked. Add goto-based error handling labels to ensure that all allocated resources are correctly freed. Fixes: 1f2acc5a8a0a ("MIPS: ralink: Add support for systick timer found on newer ralink SoC") Signed-off-by: Haotian Zhang Signed-off-by: Daniel Lezcano Link: https://patch.msgid.link/20251030090710.1603-1-vulab@iscas.ac.cn Signed-off-by: Sasha Levin --- drivers/clocksource/timer-ralink.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/clocksource/timer-ralink.c b/drivers/clocksource/timer-ralink.c index 6ecdb4228f763..68434d9ed9107 100644 --- a/drivers/clocksource/timer-ralink.c +++ b/drivers/clocksource/timer-ralink.c @@ -130,14 +130,15 @@ static int __init ralink_systick_init(struct device_node *np) systick.dev.irq = irq_of_parse_and_map(np, 0); if (!systick.dev.irq) { pr_err("%pOFn: request_irq failed", np); - return -EINVAL; + ret = -EINVAL; + goto err_iounmap; } ret = clocksource_mmio_init(systick.membase + SYSTICK_COUNT, np->name, SYSTICK_FREQ, 301, 16, clocksource_mmio_readl_up); if (ret) - return ret; + goto err_free_irq; clockevents_register_device(&systick.dev); @@ -145,6 +146,12 @@ static int __init ralink_systick_init(struct device_node *np) np, systick.dev.mult, systick.dev.shift); return 0; + +err_free_irq: + irq_dispose_mapping(systick.dev.irq); +err_iounmap: + iounmap(systick.membase); + return ret; } TIMER_OF_DECLARE(systick, "ralink,cevt-systick", ralink_systick_init); From 9876d55a04457317eede51d2bb43d0148790895d Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Fri, 17 Oct 2025 07:50:39 +0200 Subject: [PATCH 0809/2333] clocksource/drivers/stm: Fix double deregistration on probe failure [ Upstream commit 6b38a8b31e2c5c2c3fd5f9848850788c190f216d ] The purpose of the devm_add_action_or_reset() helper is to call the action function in case adding an action ever fails so drop the clock source deregistration from the error path to avoid deregistering twice. Fixes: cec32ac75827 ("clocksource/drivers/nxp-timer: Add the System Timer Module for the s32gx platforms") Signed-off-by: Johan Hovold Signed-off-by: Daniel Lezcano Cc: Daniel Lezcano Link: https://patch.msgid.link/20251017055039.7307-1-johan@kernel.org Signed-off-by: Sasha Levin --- drivers/clocksource/timer-nxp-stm.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/clocksource/timer-nxp-stm.c b/drivers/clocksource/timer-nxp-stm.c index bbc40623728fa..16d52167e949b 100644 --- a/drivers/clocksource/timer-nxp-stm.c +++ b/drivers/clocksource/timer-nxp-stm.c @@ -208,10 +208,8 @@ static int __init nxp_stm_clocksource_init(struct device *dev, struct stm_timer return ret; ret = devm_add_action_or_reset(dev, devm_clocksource_unregister, stm_timer); - if (ret) { - clocksource_unregister(&stm_timer->cs); + if (ret) return ret; - } stm_sched_clock = stm_timer; From 364752785f7dfa2d1455c3e56fccb1cf08c3b0d8 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 11 Nov 2025 16:32:24 +0100 Subject: [PATCH 0810/2333] clocksource/drivers/arm_arch_timer_mmio: Prevent driver unbind [ Upstream commit 6aa10f0e2ef9eba1955be6a9d0a8eaecf6bdb7ae ] Clockevents cannot be deregistered so suppress the bind attributes to prevent the driver from being unbound and releasing the underlying resources after registration. Fixes: 4891f01527bb ("clocksource/drivers/arm_arch_timer: Add standalone MMIO driver") Signed-off-by: Johan Hovold Signed-off-by: Daniel Lezcano Acked-by: Marc Zyngier Link: https://patch.msgid.link/20251111153226.579-2-johan@kernel.org Signed-off-by: Sasha Levin --- drivers/clocksource/arm_arch_timer_mmio.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/clocksource/arm_arch_timer_mmio.c b/drivers/clocksource/arm_arch_timer_mmio.c index ebe1987d651eb..d10362692fdd3 100644 --- a/drivers/clocksource/arm_arch_timer_mmio.c +++ b/drivers/clocksource/arm_arch_timer_mmio.c @@ -426,6 +426,7 @@ static struct platform_driver arch_timer_mmio_drv = { .driver = { .name = "arch-timer-mmio", .of_match_table = arch_timer_mmio_of_table, + .suppress_bind_attrs = true, }, .probe = arch_timer_mmio_probe, }; @@ -434,6 +435,7 @@ builtin_platform_driver(arch_timer_mmio_drv); static struct platform_driver arch_timer_mmio_acpi_drv = { .driver = { .name = "gtdt-arm-mmio-timer", + .suppress_bind_attrs = true, }, .probe = arch_timer_mmio_probe, }; From 7da0b7f66a203a3e7707cb79d0308a43d7b67f2f Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 11 Nov 2025 16:32:25 +0100 Subject: [PATCH 0811/2333] clocksource/drivers/nxp-pit: Prevent driver unbind [ Upstream commit e25f964cf414dafa6bee5c9c2c0b1d1fb041dc92 ] The driver does not support unbinding (e.g. as clockevents cannot be deregistered) so suppress the bind attributes to prevent the driver from being unbound and rebound after registration (and disabling the timer when reprobing fails). Even if the driver can currently only be built-in, also switch to builtin_platform_driver() to prevent it from being unloaded should modular builds ever be enabled. Fixes: bee33f22d7c3 ("clocksource/drivers/nxp-pit: Add NXP Automotive s32g2 / s32g3 support") Signed-off-by: Johan Hovold Signed-off-by: Daniel Lezcano Link: https://patch.msgid.link/20251111153226.579-3-johan@kernel.org Signed-off-by: Sasha Levin --- drivers/clocksource/timer-nxp-pit.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/clocksource/timer-nxp-pit.c b/drivers/clocksource/timer-nxp-pit.c index 2d0a3554b6bf7..d1740f18f7180 100644 --- a/drivers/clocksource/timer-nxp-pit.c +++ b/drivers/clocksource/timer-nxp-pit.c @@ -374,9 +374,10 @@ static struct platform_driver nxp_pit_driver = { .driver = { .name = "nxp-pit", .of_match_table = pit_timer_of_match, + .suppress_bind_attrs = true, }, .probe = pit_timer_probe, }; -module_platform_driver(nxp_pit_driver); +builtin_platform_driver(nxp_pit_driver); TIMER_OF_DECLARE(vf610, "fsl,vf610-pit", pit_timer_init); From 755927ae17691c29bb5c8568e0e96a7ee58a14e9 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Fri, 17 Oct 2025 07:49:43 +0200 Subject: [PATCH 0812/2333] clocksource/drivers/nxp-stm: Fix section mismatches [ Upstream commit b452d2c97eeccbf9c7ac5b3d2d9e80bf6d8a23db ] Platform drivers can be probed after their init sections have been discarded (e.g. on probe deferral or manual rebind through sysfs) so the probe function must not live in init. Device managed resource actions similarly cannot be discarded. The "_probe" suffix of the driver structure name prevents modpost from warning about this so replace it to catch any similar future issues. Fixes: cec32ac75827 ("clocksource/drivers/nxp-timer: Add the System Timer Module for the s32gx platforms") Signed-off-by: Johan Hovold Signed-off-by: Daniel Lezcano Cc: stable@vger.kernel.org # 6.16 Cc: Daniel Lezcano Link: https://patch.msgid.link/20251017054943.7195-1-johan@kernel.org Stable-dep-of: 6a2416892e89 ("clocksource/drivers/nxp-stm: Prevent driver unbind") Signed-off-by: Sasha Levin --- drivers/clocksource/timer-nxp-stm.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/clocksource/timer-nxp-stm.c b/drivers/clocksource/timer-nxp-stm.c index 16d52167e949b..c320d764b12e2 100644 --- a/drivers/clocksource/timer-nxp-stm.c +++ b/drivers/clocksource/timer-nxp-stm.c @@ -177,15 +177,15 @@ static void nxp_stm_clocksource_resume(struct clocksource *cs) nxp_stm_clocksource_enable(cs); } -static void __init devm_clocksource_unregister(void *data) +static void devm_clocksource_unregister(void *data) { struct stm_timer *stm_timer = data; clocksource_unregister(&stm_timer->cs); } -static int __init nxp_stm_clocksource_init(struct device *dev, struct stm_timer *stm_timer, - const char *name, void __iomem *base, struct clk *clk) +static int nxp_stm_clocksource_init(struct device *dev, struct stm_timer *stm_timer, + const char *name, void __iomem *base, struct clk *clk) { int ret; @@ -296,9 +296,9 @@ static void nxp_stm_clockevent_resume(struct clock_event_device *ced) nxp_stm_module_get(stm_timer); } -static int __init nxp_stm_clockevent_per_cpu_init(struct device *dev, struct stm_timer *stm_timer, - const char *name, void __iomem *base, int irq, - struct clk *clk, int cpu) +static int nxp_stm_clockevent_per_cpu_init(struct device *dev, struct stm_timer *stm_timer, + const char *name, void __iomem *base, int irq, + struct clk *clk, int cpu) { stm_timer->base = base; stm_timer->rate = clk_get_rate(clk); @@ -386,7 +386,7 @@ static irqreturn_t nxp_stm_module_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -static int __init nxp_stm_timer_probe(struct platform_device *pdev) +static int nxp_stm_timer_probe(struct platform_device *pdev) { struct stm_timer *stm_timer; struct device *dev = &pdev->dev; @@ -482,14 +482,14 @@ static const struct of_device_id nxp_stm_of_match[] = { }; MODULE_DEVICE_TABLE(of, nxp_stm_of_match); -static struct platform_driver nxp_stm_probe = { +static struct platform_driver nxp_stm_driver = { .probe = nxp_stm_timer_probe, .driver = { .name = "nxp-stm", .of_match_table = nxp_stm_of_match, }, }; -module_platform_driver(nxp_stm_probe); +module_platform_driver(nxp_stm_driver); MODULE_DESCRIPTION("NXP System Timer Module driver"); MODULE_LICENSE("GPL"); From 110337fa5f06b7259035d70418eefa65ffdd3a94 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 11 Nov 2025 16:32:26 +0100 Subject: [PATCH 0813/2333] clocksource/drivers/nxp-stm: Prevent driver unbind [ Upstream commit 6a2416892e8942f5e2bfe9b85c0164f410a53a2d ] Clockevents cannot be deregistered so suppress the bind attributes to prevent the driver from being unbound and releasing the underlying resources after registration. Even if the driver can currently only be built-in, also switch to builtin_platform_driver() to prevent it from being unloaded should modular builds ever be enabled. Fixes: cec32ac75827 ("clocksource/drivers/nxp-timer: Add the System Timer Module for the s32gx platforms") Signed-off-by: Johan Hovold Signed-off-by: Daniel Lezcano Link: https://patch.msgid.link/20251111153226.579-4-johan@kernel.org Signed-off-by: Sasha Levin --- drivers/clocksource/timer-nxp-stm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/clocksource/timer-nxp-stm.c b/drivers/clocksource/timer-nxp-stm.c index c320d764b12e2..1ab907233f481 100644 --- a/drivers/clocksource/timer-nxp-stm.c +++ b/drivers/clocksource/timer-nxp-stm.c @@ -487,9 +487,10 @@ static struct platform_driver nxp_stm_driver = { .driver = { .name = "nxp-stm", .of_match_table = nxp_stm_of_match, + .suppress_bind_attrs = true, }, }; -module_platform_driver(nxp_stm_driver); +builtin_platform_driver(nxp_stm_driver); MODULE_DESCRIPTION("NXP System Timer Module driver"); MODULE_LICENSE("GPL"); From 4876a36bc639deff734915bd8b53b76acaf2a6c9 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 26 Nov 2025 10:16:34 +0100 Subject: [PATCH 0814/2333] ASoC: nau8325: use simple i2c probe function [ Upstream commit b4d072c98e47c562834f2a050ca98a1c709ef4f9 ] The i2c probe functions here don't use the id information provided in their second argument, so the single-parameter i2c probe function ("probe_new") can be used instead. This avoids scanning the identifier tables during probes. Signed-off-by: Jaroslav Kysela Link: https://patch.msgid.link/20251126091759.2490019-2-perex@perex.cz Signed-off-by: Mark Brown Stable-dep-of: cd41d3420ef6 ("ASoC: nau8325: add missing build config") Signed-off-by: Sasha Levin --- sound/soc/codecs/nau8325.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/soc/codecs/nau8325.c b/sound/soc/codecs/nau8325.c index 2266f320a8f22..5b3115b0a7e58 100644 --- a/sound/soc/codecs/nau8325.c +++ b/sound/soc/codecs/nau8325.c @@ -829,8 +829,7 @@ static int nau8325_read_device_properties(struct device *dev, return 0; } -static int nau8325_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int nau8325_i2c_probe(struct i2c_client *i2c) { struct device *dev = &i2c->dev; struct nau8325 *nau8325 = dev_get_platdata(dev); From 1123b37d894768b256a36273f9a397e1e23397a6 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 3 Dec 2025 15:06:12 +0100 Subject: [PATCH 0815/2333] ASoC: codecs: nau8325: Silence uninitialized variables warnings commit 2c7e5e17c05f1d5e10e63e1baff2b362cd08dcd6 upstream. clang W=1 builds warn: nau8325.c:430:13: error: variable 'n2_max' is uninitialized when used here [-Werror,-Wuninitialized] which are false positive, because the variables will be always initialized when used (guarded by mclk_max!=0 check). However initializing them upfront makes the code more obvious and easier, plus it silences the warning. Signed-off-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20251203140611.87191-2-krzysztof.kozlowski@oss.qualcomm.com Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/codecs/nau8325.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/nau8325.c b/sound/soc/codecs/nau8325.c index 5b3115b0a7e58..d396160213f5d 100644 --- a/sound/soc/codecs/nau8325.c +++ b/sound/soc/codecs/nau8325.c @@ -386,7 +386,8 @@ static int nau8325_clksrc_choose(struct nau8325 *nau8325, const struct nau8325_srate_attr **srate_table, int *n1_sel, int *mult_sel, int *n2_sel) { - int i, j, mclk, mclk_max, ratio, ratio_sel, n2_max; + int i, j, mclk, ratio; + int mclk_max = 0, ratio_sel = 0, n2_max = 0; if (!nau8325->mclk || !nau8325->fs) goto proc_err; @@ -408,7 +409,6 @@ static int nau8325_clksrc_choose(struct nau8325 *nau8325, } /* Get MCLK_SRC through 1/N, Multiplier, and then 1/N2. */ - mclk_max = 0; for (i = 0; i < ARRAY_SIZE(mclk_n1_div); i++) { for (j = 0; j < ARRAY_SIZE(mclk_n3_mult); j++) { mclk = nau8325->mclk << mclk_n3_mult[j].param; From 79bc3bdf36bc29037cb4a5fe0cd8e4d93101ef7f Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 26 Nov 2025 10:16:35 +0100 Subject: [PATCH 0816/2333] ASoC: nau8325: add missing build config [ Upstream commit cd41d3420ef658b2ca902d7677536ec8e25b610a ] This configuration was missing from the initial commit. Found by Jiri Benc Fixes: c0a3873b9938 ("ASoC: nau8325: new driver") Cc: Seven Lee Signed-off-by: Jaroslav Kysela Link: https://patch.msgid.link/20251126091759.2490019-3-perex@perex.cz Signed-off-by: Mark Brown Signed-off-by: Sasha Levin --- sound/soc/codecs/Kconfig | 5 +++++ sound/soc/codecs/Makefile | 2 ++ 2 files changed, 7 insertions(+) diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 160c07699a8b7..91ac99bc3edb2 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -170,6 +170,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_MT6359 imply SND_SOC_MT6660 imply SND_SOC_NAU8315 + imply SND_SOC_NAU8325 imply SND_SOC_NAU8540 imply SND_SOC_NAU8810 imply SND_SOC_NAU8821 @@ -2715,6 +2716,10 @@ config SND_SOC_MT6660 config SND_SOC_NAU8315 tristate "Nuvoton Technology Corporation NAU8315 CODEC" +config SND_SOC_NAU8325 + tristate "Nuvoton Technology Corporation NAU8325 CODEC" + depends on I2C + config SND_SOC_NAU8540 tristate "Nuvoton Technology Corporation NAU85L40 CODEC" depends on I2C diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index bd95a7c911d5c..da4077463278e 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -192,6 +192,7 @@ snd-soc-mt6359-y := mt6359.o snd-soc-mt6359-accdet-y := mt6359-accdet.o snd-soc-mt6660-y := mt6660.o snd-soc-nau8315-y := nau8315.o +snd-soc-nau8325-y := nau8325.o snd-soc-nau8540-y := nau8540.o snd-soc-nau8810-y := nau8810.o snd-soc-nau8821-y := nau8821.o @@ -618,6 +619,7 @@ obj-$(CONFIG_SND_SOC_MT6359) += snd-soc-mt6359.o obj-$(CONFIG_SND_SOC_MT6359_ACCDET) += mt6359-accdet.o obj-$(CONFIG_SND_SOC_MT6660) += snd-soc-mt6660.o obj-$(CONFIG_SND_SOC_NAU8315) += snd-soc-nau8315.o +obj-$(CONFIG_SND_SOC_NAU8325) += snd-soc-nau8325.o obj-$(CONFIG_SND_SOC_NAU8540) += snd-soc-nau8540.o obj-$(CONFIG_SND_SOC_NAU8810) += snd-soc-nau8810.o obj-$(CONFIG_SND_SOC_NAU8821) += snd-soc-nau8821.o From 49e7347f4644d031306d56cb4d51e467cbdcbc69 Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Thu, 13 Nov 2025 12:05:37 +0000 Subject: [PATCH 0817/2333] gfs2: Prevent recursive memory reclaim [ Upstream commit 2c5f4a53476e3cab70adc77b38942c066bd2c17c ] Function new_inode() returns a new inode with inode->i_mapping->gfp_mask set to GFP_HIGHUSER_MOVABLE. This value includes the __GFP_FS flag, so allocations in that address space can recurse into filesystem memory reclaim. We don't want that to happen because it can consume a significant amount of stack memory. Worse than that is that it can also deadlock: for example, in several places, gfs2_unstuff_dinode() is called inside filesystem transactions. This calls filemap_grab_folio(), which can allocate a new folio, which can trigger memory reclaim. If memory reclaim recurses into the filesystem and starts another transaction, a deadlock will ensue. To fix these kinds of problems, prevent memory reclaim from recursing into filesystem code by making sure that the gfp_mask of inode address spaces doesn't include __GFP_FS. The "meta" and resource group address spaces were already using GFP_NOFS as their gfp_mask (which doesn't include __GFP_FS). The default value of GFP_HIGHUSER_MOVABLE is less restrictive than GFP_NOFS, though. To avoid being overly limiting, use the default value and only knock off the __GFP_FS flag. I'm not sure if this will actually make a difference, but it also shouldn't hurt. This patch is loosely based on commit ad22c7a043c2 ("xfs: prevent stack overflows from page cache allocation"). Fixes xfstest generic/273. Fixes: dc0b9435238c ("gfs: Don't use GFP_NOFS in gfs2_unstuff_dinode") Reviewed-by: Andrew Price Signed-off-by: Andreas Gruenbacher Signed-off-by: Sasha Levin --- fs/gfs2/glock.c | 5 ++++- fs/gfs2/inode.c | 15 +++++++++++++++ fs/gfs2/inode.h | 1 + fs/gfs2/ops_fstype.c | 2 +- 4 files changed, 21 insertions(+), 2 deletions(-) diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index b677c0e6b9ab3..9f2eb7e385695 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -1211,10 +1211,13 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number, mapping = gfs2_glock2aspace(gl); if (mapping) { + gfp_t gfp_mask; + mapping->a_ops = &gfs2_meta_aops; mapping->host = sdp->sd_inode; mapping->flags = 0; - mapping_set_gfp_mask(mapping, GFP_NOFS); + gfp_mask = mapping_gfp_mask(sdp->sd_inode->i_mapping); + mapping_set_gfp_mask(mapping, gfp_mask); mapping->i_private_data = NULL; mapping->writeback_index = 0; } diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 8a7ed80d9f2d6..d7e35a05c1610 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -89,6 +89,19 @@ static int iget_set(struct inode *inode, void *opaque) return 0; } +void gfs2_setup_inode(struct inode *inode) +{ + gfp_t gfp_mask; + + /* + * Ensure all page cache allocations are done from GFP_NOFS context to + * prevent direct reclaim recursion back into the filesystem and blowing + * stacks or deadlocking. + */ + gfp_mask = mapping_gfp_mask(inode->i_mapping); + mapping_set_gfp_mask(inode->i_mapping, gfp_mask & ~__GFP_FS); +} + /** * gfs2_inode_lookup - Lookup an inode * @sb: The super block @@ -132,6 +145,7 @@ struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned int type, struct gfs2_glock *io_gl; int extra_flags = 0; + gfs2_setup_inode(inode); error = gfs2_glock_get(sdp, no_addr, &gfs2_inode_glops, CREATE, &ip->i_gl); if (unlikely(error)) @@ -752,6 +766,7 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry, error = -ENOMEM; if (!inode) goto fail_gunlock; + gfs2_setup_inode(inode); ip = GFS2_I(inode); error = posix_acl_create(dir, &mode, &default_acl, &acl); diff --git a/fs/gfs2/inode.h b/fs/gfs2/inode.h index e43f08eb26e72..2fcd96dd13613 100644 --- a/fs/gfs2/inode.h +++ b/fs/gfs2/inode.h @@ -86,6 +86,7 @@ static inline int gfs2_check_internal_file_size(struct inode *inode, return -EIO; } +void gfs2_setup_inode(struct inode *inode); struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned type, u64 no_addr, u64 no_formal_ino, unsigned int blktype); diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index aa15183f9a168..1a2db8053da04 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -1183,7 +1183,7 @@ static int gfs2_fill_super(struct super_block *sb, struct fs_context *fc) mapping = gfs2_aspace(sdp); mapping->a_ops = &gfs2_rgrp_aops; - mapping_set_gfp_mask(mapping, GFP_NOFS); + gfs2_setup_inode(sdp->sd_inode); error = init_names(sdp, silent); if (error) From ee0fa63171ba80f228141e2ba6743006f9e49437 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Wed, 26 Nov 2025 14:45:09 +0800 Subject: [PATCH 0818/2333] ASoC: fsl_xcvr: clear the channel status control memory [ Upstream commit 73b97d46dde64fa184d47865d4a532d818c3a007 ] memset_io() writes memory byte by byte with __raw_writeb() on the arm platform if the size is word. but XCVR data RAM memory can't be accessed with byte address, so with memset_io() the channel status control memory is not really cleared, use writel_relaxed() instead. Fixes: 28564486866f ("ASoC: fsl_xcvr: Add XCVR ASoC CPU DAI driver") Signed-off-by: Shengjiu Wang Link: https://patch.msgid.link/20251126064509.1900974-1-shengjiu.wang@nxp.com Signed-off-by: Mark Brown Signed-off-by: Sasha Levin --- sound/soc/fsl/fsl_xcvr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/fsl/fsl_xcvr.c b/sound/soc/fsl/fsl_xcvr.c index 5d804860f7d8c..58db4906a01d5 100644 --- a/sound/soc/fsl/fsl_xcvr.c +++ b/sound/soc/fsl/fsl_xcvr.c @@ -1421,7 +1421,7 @@ static irqreturn_t irq0_isr(int irq, void *devid) bitrev32(val); } /* clear CS control register */ - memset_io(reg_ctrl, 0, sizeof(val)); + writel_relaxed(0, reg_ctrl); } } else { regmap_read(xcvr->regmap, FSL_XCVR_RX_CS_DATA_0, From c9083b2fce6b3bddceba7c4166ce3013f2941e0e Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Thu, 6 Nov 2025 11:40:54 +0900 Subject: [PATCH 0819/2333] firmware_loader: make RUST_FW_LOADER_ABSTRACTIONS select FW_LOADER [ Upstream commit 9906efa545d1d2cf25a614eeb219d3f8d5a302cd ] The use of firmware_loader is an implementation detail of drivers rather than a dependency. FW_LOADER is typically selected rather than depended on; the Rust abstractions should do the same thing. Fixes: de6582833db0 ("rust: add firmware abstractions") Signed-off-by: Alexandre Courbot Link: https://patch.msgid.link/20251106-b4-select-rust-fw-v3-1-771172257755@nvidia.com Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin --- drivers/base/firmware_loader/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/base/firmware_loader/Kconfig b/drivers/base/firmware_loader/Kconfig index 752b9a9bea038..15eff8a4b5053 100644 --- a/drivers/base/firmware_loader/Kconfig +++ b/drivers/base/firmware_loader/Kconfig @@ -38,7 +38,7 @@ config FW_LOADER_DEBUG config RUST_FW_LOADER_ABSTRACTIONS bool "Rust Firmware Loader abstractions" depends on RUST - depends on FW_LOADER=y + select FW_LOADER help This enables the Rust abstractions for the firmware loader API. From 2f62a4e395883ec5a25b6c5a832373459e22f7f3 Mon Sep 17 00:00:00 2001 From: Haotian Zhang Date: Fri, 21 Nov 2025 14:40:27 +0800 Subject: [PATCH 0820/2333] greybus: gb-beagleplay: Fix timeout handling in bootloader functions [ Upstream commit e6df0f649cff08da7a2feb6d963b39076ca129f9 ] wait_for_completion_timeout() returns the remaining jiffies (at least 1) on success or 0 on timeout, but never negative error codes. The current code incorrectly checks for negative values, causing timeouts to be ignored and treated as success. Check for a zero return value to correctly identify and handle timeout events. Fixes: 0cf7befa3ea2 ("greybus: gb-beagleplay: Add firmware upload API") Signed-off-by: Haotian Zhang Link: https://patch.msgid.link/20251121064027.571-1-vulab@iscas.ac.cn Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin --- drivers/greybus/gb-beagleplay.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/greybus/gb-beagleplay.c b/drivers/greybus/gb-beagleplay.c index 9610f878da1b6..87186f891a6ac 100644 --- a/drivers/greybus/gb-beagleplay.c +++ b/drivers/greybus/gb-beagleplay.c @@ -644,8 +644,8 @@ static int cc1352_bootloader_wait_for_ack(struct gb_beagleplay *bg) ret = wait_for_completion_timeout( &bg->fwl_ack_com, msecs_to_jiffies(CC1352_BOOTLOADER_TIMEOUT)); - if (ret < 0) - return dev_err_probe(&bg->sd->dev, ret, + if (!ret) + return dev_err_probe(&bg->sd->dev, -ETIMEDOUT, "Failed to acquire ack semaphore"); switch (READ_ONCE(bg->fwl_ack)) { @@ -683,8 +683,8 @@ static int cc1352_bootloader_get_status(struct gb_beagleplay *bg) ret = wait_for_completion_timeout( &bg->fwl_cmd_response_com, msecs_to_jiffies(CC1352_BOOTLOADER_TIMEOUT)); - if (ret < 0) - return dev_err_probe(&bg->sd->dev, ret, + if (!ret) + return dev_err_probe(&bg->sd->dev, -ETIMEDOUT, "Failed to acquire last status semaphore"); switch (READ_ONCE(bg->fwl_cmd_response)) { @@ -768,8 +768,8 @@ static int cc1352_bootloader_crc32(struct gb_beagleplay *bg, u32 *crc32) ret = wait_for_completion_timeout( &bg->fwl_cmd_response_com, msecs_to_jiffies(CC1352_BOOTLOADER_TIMEOUT)); - if (ret < 0) - return dev_err_probe(&bg->sd->dev, ret, + if (!ret) + return dev_err_probe(&bg->sd->dev, -ETIMEDOUT, "Failed to acquire last status semaphore"); *crc32 = READ_ONCE(bg->fwl_cmd_response); From eda80f733fbd5744ce6c1b3b9e9b2daf705dcf0f Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 20 Nov 2025 07:47:22 +0100 Subject: [PATCH 0821/2333] fs: refactor file timestamp update logic [ Upstream commit 3cd9a42f1b5e34d3972237cbf8541af60844cbd4 ] Currently the two high-level APIs use two helper functions to implement almost all of the logic. Refactor the two helpers and the common logic into a new file_update_time_flags routine that gets the iocb flags or 0 in case of file_update_time passed so that the entire logic is contained in a single function and can be easily understood and modified. Signed-off-by: Christoph Hellwig Link: https://patch.msgid.link/20251120064859.2911749-2-hch@lst.de Reviewed-by: Chaitanya Kulkarni Reviewed-by: Jeff Layton Reviewed-by: Jan Kara Signed-off-by: Christian Brauner Stable-dep-of: 7f30e7a42371 ("fs: lift the FMODE_NOCMTIME check into file_update_time_flags") Signed-off-by: Sasha Levin --- fs/inode.c | 54 +++++++++++++++++------------------------------------- 1 file changed, 17 insertions(+), 37 deletions(-) diff --git a/fs/inode.c b/fs/inode.c index cff1d3af0d577..540f4a28c202d 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -2322,10 +2322,12 @@ struct timespec64 current_time(struct inode *inode) } EXPORT_SYMBOL(current_time); -static int inode_needs_update_time(struct inode *inode) +static int file_update_time_flags(struct file *file, unsigned int flags) { + struct inode *inode = file_inode(file); struct timespec64 now, ts; - int sync_it = 0; + int sync_mode = 0; + int ret = 0; /* First try to exhaust all avenues to not sync */ if (IS_NOCMTIME(inode)) @@ -2335,29 +2337,23 @@ static int inode_needs_update_time(struct inode *inode) ts = inode_get_mtime(inode); if (!timespec64_equal(&ts, &now)) - sync_it |= S_MTIME; - + sync_mode |= S_MTIME; ts = inode_get_ctime(inode); if (!timespec64_equal(&ts, &now)) - sync_it |= S_CTIME; - + sync_mode |= S_CTIME; if (IS_I_VERSION(inode) && inode_iversion_need_inc(inode)) - sync_it |= S_VERSION; + sync_mode |= S_VERSION; - return sync_it; -} - -static int __file_update_time(struct file *file, int sync_mode) -{ - int ret = 0; - struct inode *inode = file_inode(file); + if (!sync_mode) + return 0; - /* try to update time settings */ - if (!mnt_get_write_access_file(file)) { - ret = inode_update_time(inode, sync_mode); - mnt_put_write_access_file(file); - } + if (flags & IOCB_NOWAIT) + return -EAGAIN; + if (mnt_get_write_access_file(file)) + return 0; + ret = inode_update_time(inode, sync_mode); + mnt_put_write_access_file(file); return ret; } @@ -2377,14 +2373,7 @@ static int __file_update_time(struct file *file, int sync_mode) */ int file_update_time(struct file *file) { - int ret; - struct inode *inode = file_inode(file); - - ret = inode_needs_update_time(inode); - if (ret <= 0) - return ret; - - return __file_update_time(file, ret); + return file_update_time_flags(file, 0); } EXPORT_SYMBOL(file_update_time); @@ -2406,7 +2395,6 @@ EXPORT_SYMBOL(file_update_time); static int file_modified_flags(struct file *file, int flags) { int ret; - struct inode *inode = file_inode(file); /* * Clear the security bits if the process is not being run by root. @@ -2415,17 +2403,9 @@ static int file_modified_flags(struct file *file, int flags) ret = file_remove_privs_flags(file, flags); if (ret) return ret; - if (unlikely(file->f_mode & FMODE_NOCMTIME)) return 0; - - ret = inode_needs_update_time(inode); - if (ret <= 0) - return ret; - if (flags & IOCB_NOWAIT) - return -EAGAIN; - - return __file_update_time(file, ret); + return file_update_time_flags(file, flags); } /** From e901d77f8994362a249714804d47560a92dff911 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 20 Nov 2025 07:47:23 +0100 Subject: [PATCH 0822/2333] fs: lift the FMODE_NOCMTIME check into file_update_time_flags [ Upstream commit 7f30e7a42371af4bba53f9a875a0d320cead9f4b ] FMODE_NOCMTIME used to be just a hack for the legacy XFS handle-based "invisible I/O", but commit e5e9b24ab8fa ("nfsd: freeze c/mtime updates with outstanding WRITE_ATTRS delegation") started using it from generic callers. I'm not sure other file systems are actually read for this in general, so the above commit should get a closer look, but for it to make any sense, file_update_time needs to respect the flag. Lift the check from file_modified_flags to file_update_time so that users of file_update_time inherit the behavior and so that all the checks are done in one place. Fixes: e5e9b24ab8fa ("nfsd: freeze c/mtime updates with outstanding WRITE_ATTRS delegation") Signed-off-by: Christoph Hellwig Link: https://patch.msgid.link/20251120064859.2911749-3-hch@lst.de Reviewed-by: Chaitanya Kulkarni Reviewed-by: Jeff Layton Reviewed-by: Jan Kara Signed-off-by: Christian Brauner Signed-off-by: Sasha Levin --- fs/inode.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/inode.c b/fs/inode.c index 540f4a28c202d..2c55ec49b0239 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -2332,6 +2332,8 @@ static int file_update_time_flags(struct file *file, unsigned int flags) /* First try to exhaust all avenues to not sync */ if (IS_NOCMTIME(inode)) return 0; + if (unlikely(file->f_mode & FMODE_NOCMTIME)) + return 0; now = current_time(inode); @@ -2403,8 +2405,6 @@ static int file_modified_flags(struct file *file, int flags) ret = file_remove_privs_flags(file, flags); if (ret) return ret; - if (unlikely(file->f_mode & FMODE_NOCMTIME)) - return 0; return file_update_time_flags(file, flags); } From 2f4f72e580b5c90a4171a2055afcdd9676c68248 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 8 Nov 2025 08:14:04 +0100 Subject: [PATCH 0823/2333] misc: rp1: Fix an error handling path in rp1_probe() [ Upstream commit 43cd4b634ef90c4e2ff75eaeb361786fa04c8874 ] When DT is used to get the reference of 'rp1_node', it should be released when not needed anymore, otherwise it is leaking. In such a case, add the missing of_node_put() call at the end of the probe, as already done in the error handling path. Fixes: 49d63971f963 ("misc: rp1: RaspberryPi RP1 misc driver") Signed-off-by: Christophe JAILLET Reviewed-by: Andrea della Porta Link: https://patch.msgid.link/9bc1206de787fa86384f3e5ba0a8027947bc00ff.1762585959.git.christophe.jaillet@wanadoo.fr Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin --- drivers/misc/rp1/rp1_pci.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/misc/rp1/rp1_pci.c b/drivers/misc/rp1/rp1_pci.c index 803832006ec87..a342bcc6164bb 100644 --- a/drivers/misc/rp1/rp1_pci.c +++ b/drivers/misc/rp1/rp1_pci.c @@ -289,6 +289,9 @@ static int rp1_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto err_unload_overlay; } + if (skip_ovl) + of_node_put(rp1_node); + return 0; err_unload_overlay: From 843bdaf0bfdd43b85b48f75845d5999c6e8a24ea Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 31 Oct 2025 16:02:25 +0300 Subject: [PATCH 0824/2333] drm/amd/display: Fix logical vs bitwise bug in get_embedded_panel_info_v2_1() [ Upstream commit 1a79482699b4d1e43948d14f0c7193dc1dcad858 ] The .H_SYNC_POLARITY and .V_SYNC_POLARITY variables are 1 bit bitfields of a u32. The ATOM_HSYNC_POLARITY define is 0x2 and the ATOM_VSYNC_POLARITY is 0x4. When we do a bitwise negate of 0, 2, or 4 then the last bit is always 1 so this code always sets .H_SYNC_POLARITY and .V_SYNC_POLARITY to true. This code is instead intended to check if the ATOM_HSYNC_POLARITY or ATOM_VSYNC_POLARITY flags are set and reverse the result. In other words, it's supposed to be a logical negate instead of a bitwise negate. Fixes: ae79c310b1a6 ("drm/amd/display: Add DCE12 bios parser support") Signed-off-by: Dan Carpenter Reviewed-by: Alex Hung Signed-off-by: Alex Deucher Signed-off-by: Sasha Levin --- drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c b/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c index 04eb647acc4e1..550a9f1d03f82 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c +++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c @@ -1480,10 +1480,10 @@ static enum bp_result get_embedded_panel_info_v2_1( /* not provided by VBIOS */ info->lcd_timing.misc_info.HORIZONTAL_CUT_OFF = 0; - info->lcd_timing.misc_info.H_SYNC_POLARITY = ~(uint32_t) (lvds->lcd_timing.miscinfo - & ATOM_HSYNC_POLARITY); - info->lcd_timing.misc_info.V_SYNC_POLARITY = ~(uint32_t) (lvds->lcd_timing.miscinfo - & ATOM_VSYNC_POLARITY); + info->lcd_timing.misc_info.H_SYNC_POLARITY = !(lvds->lcd_timing.miscinfo & + ATOM_HSYNC_POLARITY); + info->lcd_timing.misc_info.V_SYNC_POLARITY = !(lvds->lcd_timing.miscinfo & + ATOM_VSYNC_POLARITY); /* not provided by VBIOS */ info->lcd_timing.misc_info.VERTICAL_CUT_OFF = 0; From 627a55ec0039a9e1aef71614016e8b2cc74a3917 Mon Sep 17 00:00:00 2001 From: Eric Huang Date: Wed, 19 Nov 2025 15:07:10 -0500 Subject: [PATCH 0825/2333] drm/amdkfd: assign AID to uuid in topology for SPX mode [ Upstream commit 089702632f1dd38fadc9af13816485d6aa518dbb ] XCD id is assigned to uuid, which causes some performance drop in SPX mode, assigning AID back will resolve the issue. Fixes: 3a75edf93aae ("drm/amdkfd: set uuid for each partition in topology") Signed-off-by: Eric Huang Reviewed-by: Harish Kasiviswanathan Signed-off-by: Alex Deucher Signed-off-by: Sasha Levin --- drivers/gpu/drm/amd/amdkfd/kfd_topology.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c index 5c98746eb72df..811636af14eaa 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c @@ -530,7 +530,9 @@ static ssize_t node_show(struct kobject *kobj, struct attribute *attr, sysfs_show_32bit_prop(buffer, offs, "sdma_fw_version", dev->gpu->kfd->sdma_fw_version); sysfs_show_64bit_prop(buffer, offs, "unique_id", - dev->gpu->xcp ? + dev->gpu->xcp && + (dev->gpu->xcp->xcp_mgr->mode != + AMDGPU_SPX_PARTITION_MODE) ? dev->gpu->xcp->unique_id : dev->gpu->adev->unique_id); sysfs_show_32bit_prop(buffer, offs, "num_xcc", From 17fc4443ee121b3703cb0a13710b296c68b674ca Mon Sep 17 00:00:00 2001 From: Haotian Zhang Date: Thu, 27 Nov 2025 00:26:02 +0800 Subject: [PATCH 0826/2333] hwmon: sy7636a: Fix regulator_enable resource leak on error path [ Upstream commit 2f88425ef590b7fcc2324334b342e048edc144a9 ] In sy7636a_sensor_probe(), regulator_enable() is called but if devm_hwmon_device_register_with_info() fails, the function returns without calling regulator_disable(), leaving the regulator enabled and leaking the reference count. Switch to devm_regulator_get_enable() to automatically manage the regulator resource. Fixes: de34a4053250 ("hwmon: sy7636a: Add temperature driver for sy7636a") Suggested-by: Guenter Roeck Signed-off-by: Haotian Zhang Link: https://lore.kernel.org/r/20251126162602.2086-1-vulab@iscas.ac.cn Signed-off-by: Guenter Roeck Signed-off-by: Sasha Levin --- drivers/hwmon/sy7636a-hwmon.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/hwmon/sy7636a-hwmon.c b/drivers/hwmon/sy7636a-hwmon.c index a12fc0ce70e76..d51daaf63d632 100644 --- a/drivers/hwmon/sy7636a-hwmon.c +++ b/drivers/hwmon/sy7636a-hwmon.c @@ -66,18 +66,13 @@ static const struct hwmon_chip_info sy7636a_chip_info = { static int sy7636a_sensor_probe(struct platform_device *pdev) { struct regmap *regmap = dev_get_regmap(pdev->dev.parent, NULL); - struct regulator *regulator; struct device *hwmon_dev; int err; if (!regmap) return -EPROBE_DEFER; - regulator = devm_regulator_get(&pdev->dev, "vcom"); - if (IS_ERR(regulator)) - return PTR_ERR(regulator); - - err = regulator_enable(regulator); + err = devm_regulator_get_enable(&pdev->dev, "vcom"); if (err) return err; From 7639d398316643e385ec27b4a49fa625f08a278b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Rebe?= Date: Wed, 26 Nov 2025 16:55:13 +0100 Subject: [PATCH 0827/2333] ACPI: processor_core: fix map_x2apic_id for amd-pstate on am4 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 17e7972979e147cc51d4a165e6b6b0f93273ca68 ] On all AMD AM4 systems I have seen, e.g ASUS X470-i, Pro WS X570 Ace and equivalent Gigabyte, amd-pstate does not initialize when the x2apic is enabled in the BIOS. Kernel debug messages include: [ 0.315438] acpi LNXCPU:00: Failed to get CPU physical ID. [ 0.354756] ACPI CPPC: No CPC descriptor for CPU:0 [ 0.714951] amd_pstate: the _CPC object is not present in SBIOS or ACPI disabled I tracked this down to map_x2apic_id() checking device_declaration passed in via the type argument of acpi_get_phys_id() via map_madt_entry() while map_lapic_id() does not. It appears these BIOSes use Processor statements for declaring the CPUs in the ACPI namespace instead of processor device objects (which should have been used). CPU declarations via Processor statements were deprecated in ACPI 6.0 that was released 10 years ago. They should not be used any more in any contemporary platform firmware. I tried to contact Asus support multiple times, but never received a reply nor did any BIOS update ever change this. Fix amd-pstate w/ x2apic on am4 by allowing map_x2apic_id() to work with CPUs declared via Processor statements for IDs less than 255, which is consistent with ACPI 5.0 that still allowed Processor statements to be used for declaring CPUs. Fixes: 7237d3de78ff ("x86, ACPI: add support for x2apic ACPI extensions") Signed-off-by: René Rebe [ rjw: Changelog edits ] Link: https://patch.msgid.link/20251126.165513.1373131139292726554.rene@exactco.de Signed-off-by: Rafael J. Wysocki Signed-off-by: Sasha Levin --- drivers/acpi/processor_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index 9b6b71a2ffb54..a4498357bd165 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c @@ -54,7 +54,7 @@ static int map_x2apic_id(struct acpi_subtable_header *entry, if (!(apic->lapic_flags & ACPI_MADT_ENABLED)) return -ENODEV; - if (device_declaration && (apic->uid == acpi_id)) { + if (apic->uid == acpi_id && (device_declaration || acpi_id < 255)) { *apic_id = apic->local_apic_id; return 0; } From 4e2a8fb1ce6ce2483da25d056fd61cc25bdbaf2b Mon Sep 17 00:00:00 2001 From: Kevin Brodsky Date: Wed, 26 Nov 2025 12:48:35 +0000 Subject: [PATCH 0828/2333] ublk: prevent invalid access with DEBUG [ Upstream commit c6a45ee7607de3a350008630f4369b1b5ac80884 ] ublk_ch_uring_cmd_local() may jump to the out label before initialising the io pointer. This will cause trouble if DEBUG is defined, because the pr_devel() call dereferences io. Clang reports: drivers/block/ublk_drv.c:2403:6: error: variable 'io' is used uninitialized whenever 'if' condition is true [-Werror,-Wsometimes-uninitialized] 2403 | if (tag >= ub->dev_info.queue_depth) | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ drivers/block/ublk_drv.c:2492:32: note: uninitialized use occurs here 2492 | __func__, cmd_op, tag, ret, io->flags); | Fix this by initialising io to NULL and checking it before dereferencing it. Signed-off-by: Kevin Brodsky Fixes: 71f28f3136af ("ublk_drv: add io_uring based userspace block driver") Reviewed-by: Caleb Sander Mateos Signed-off-by: Jens Axboe Signed-off-by: Sasha Levin --- drivers/block/ublk_drv.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c index 0c74a41a67530..359564c40cb50 100644 --- a/drivers/block/ublk_drv.c +++ b/drivers/block/ublk_drv.c @@ -2367,7 +2367,7 @@ static int ublk_ch_uring_cmd_local(struct io_uring_cmd *cmd, u16 buf_idx = UBLK_INVALID_BUF_IDX; struct ublk_device *ub = cmd->file->private_data; struct ublk_queue *ubq; - struct ublk_io *io; + struct ublk_io *io = NULL; u32 cmd_op = cmd->cmd_op; u16 q_id = READ_ONCE(ub_src->q_id); u16 tag = READ_ONCE(ub_src->tag); @@ -2488,7 +2488,7 @@ static int ublk_ch_uring_cmd_local(struct io_uring_cmd *cmd, out: pr_devel("%s: complete: cmd op %d, tag %d ret %x io_flags %x\n", - __func__, cmd_op, tag, ret, io->flags); + __func__, cmd_op, tag, ret, io ? io->flags : 0); return ret; } From c1b149b698e29cf576744773fd18b4662cc4c47c Mon Sep 17 00:00:00 2001 From: Matthieu Buffet Date: Mon, 27 Oct 2025 02:14:40 +0100 Subject: [PATCH 0829/2333] selftests/landlock: Fix makefile header list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit e61462232a58bddd818fa6a913a9a2e76fd3634f ] Make all headers part of make's dependencies computations. Otherwise, updating audit.h, common.h, scoped_base_variants.h, scoped_common.h, scoped_multiple_domain_variants.h, or wrappers.h, re-running make and running selftests could lead to testing stale headers. Fixes: 6a500b22971c ("selftests/landlock: Add tests for audit flags and domain IDs") Fixes: fefcf0f7cf47 ("selftests/landlock: Test abstract UNIX socket scoping") Fixes: 5147779d5e1b ("selftests/landlock: Add wrappers.h") Signed-off-by: Matthieu Buffet Link: https://lore.kernel.org/r/20251027011440.1838514-1-matthieu@buffet.re Signed-off-by: Mickaël Salaün Signed-off-by: Sasha Levin --- tools/testing/selftests/landlock/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/landlock/Makefile b/tools/testing/selftests/landlock/Makefile index a3f449914bf93..044b83bde16eb 100644 --- a/tools/testing/selftests/landlock/Makefile +++ b/tools/testing/selftests/landlock/Makefile @@ -4,7 +4,7 @@ CFLAGS += -Wall -O2 $(KHDR_INCLUDES) -LOCAL_HDRS += common.h +LOCAL_HDRS += $(wildcard *.h) src_test := $(wildcard *_test.c) From f0022551745d72fc0e7bc8601234d690dee2178d Mon Sep 17 00:00:00 2001 From: Edward Adam Davis Date: Sun, 16 Nov 2025 22:58:13 +0800 Subject: [PATCH 0830/2333] bpf: Fix exclusive map memory leak [ Upstream commit 688b745401ab16e2e1a3b504863f0a45fd345638 ] When excl_prog_hash is 0 and excl_prog_hash_size is non-zero, the map also needs to be freed. Otherwise, the map memory will not be reclaimed, just like the memory leak problem reported by syzbot [1]. syzbot reported: BUG: memory leak backtrace (crc 7b9fb9b4): map_create+0x322/0x11e0 kernel/bpf/syscall.c:1512 __sys_bpf+0x3556/0x3610 kernel/bpf/syscall.c:6131 Fixes: baefdbdf6812 ("bpf: Implement exclusive map creation") Reported-by: syzbot+cf08c551fecea9fd1320@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=cf08c551fecea9fd1320 Tested-by: syzbot+cf08c551fecea9fd1320@syzkaller.appspotmail.com Signed-off-by: Edward Adam Davis Acked-by: Yonghong Song Link: https://lore.kernel.org/r/tencent_3F226F882CE56DCC94ACE90EED1ECCFC780A@qq.com Signed-off-by: Alexei Starovoitov Signed-off-by: Sasha Levin --- kernel/bpf/syscall.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index 15f9afdbfc275..df219e7259099 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -1585,7 +1585,8 @@ static int map_create(union bpf_attr *attr, bpfptr_t uattr) goto free_map; } } else if (attr->excl_prog_hash_size) { - return -EINVAL; + err = -EINVAL; + goto free_map; } err = security_bpf_map_create(map, attr, token, uattr.is_kernel); From a537ffa7f44b5dcaa8a8f64c9bdeafc016b8a69c Mon Sep 17 00:00:00 2001 From: Yongjian Sun Date: Thu, 6 Nov 2025 14:06:14 +0800 Subject: [PATCH 0831/2333] ext4: improve integrity checking in __mb_check_buddy by enhancing order-0 validation [ Upstream commit d9ee3ff810f1cc0e253c9f2b17b668b973cb0e06 ] When the MB_CHECK_ASSERT macro is enabled, we found that the current validation logic in __mb_check_buddy has a gap in detecting certain invalid buddy states, particularly related to order-0 (bitmap) bits. The original logic consists of three steps: 1. Validates higher-order buddies: if a higher-order bit is set, at most one of the two corresponding lower-order bits may be free; if a higher-order bit is clear, both lower-order bits must be allocated (and their bitmap bits must be 0). 2. For any set bit in order-0, ensures all corresponding higher-order bits are not free. 3. Verifies that all preallocated blocks (pa) in the group have pa_pstart within bounds and their bitmap bits marked as allocated. However, this approach fails to properly validate cases where order-0 bits are incorrectly cleared (0), allowing some invalid configurations to pass: corrupt integral order 3 1 1 order 2 1 1 1 1 order 1 1 1 1 1 1 1 1 1 order 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 Here we get two adjacent free blocks at order-0 with inconsistent higher-order state, and the right one shows the correct scenario. The root cause is insufficient validation of order-0 zero bits. To fix this and improve completeness without significant performance cost, we refine the logic: 1. Maintain the top-down higher-order validation, but we no longer check the cases where the higher-order bit is 0, as this case will be covered in step 2. 2. Enhance order-0 checking by examining pairs of bits: - If either bit in a pair is set (1), all corresponding higher-order bits must not be free. - If both bits are clear (0), then exactly one of the corresponding higher-order bits must be free 3. Keep the preallocation (pa) validation unchanged. This change closes the validation gap, ensuring illegal buddy states involving order-0 are correctly detected, while removing redundant checks and maintaining efficiency. Fixes: c9de560ded61f ("ext4: Add multi block allocator for ext4") Suggested-by: Jan Kara Signed-off-by: Yongjian Sun Reviewed-by: Baokun Li Reviewed-by: Jan Kara Message-ID: <20251106060614.631382-3-sunyongjian@huaweicloud.com> Signed-off-by: Theodore Ts'o Signed-off-by: Sasha Levin --- fs/ext4/mballoc.c | 49 +++++++++++++++++++++++++++++++---------------- 1 file changed, 32 insertions(+), 17 deletions(-) diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c index 9087183602e44..c56b51e1162eb 100644 --- a/fs/ext4/mballoc.c +++ b/fs/ext4/mballoc.c @@ -682,6 +682,24 @@ do { \ } \ } while (0) +/* + * Perform buddy integrity check with the following steps: + * + * 1. Top-down validation (from highest order down to order 1, excluding order-0 bitmap): + * For each pair of adjacent orders, if a higher-order bit is set (indicating a free block), + * at most one of the two corresponding lower-order bits may be clear (free). + * + * 2. Order-0 (bitmap) validation, performed on bit pairs: + * - If either bit in a pair is set (1, allocated), then all corresponding higher-order bits + * must not be free (0). + * - If both bits in a pair are clear (0, free), then exactly one of the corresponding + * higher-order bits must be free (0). + * + * 3. Preallocation (pa) list validation: + * For each preallocated block (pa) in the group: + * - Verify that pa_pstart falls within the bounds of this block group. + * - Ensure the corresponding bit(s) in the order-0 bitmap are marked as allocated (1). + */ static void __mb_check_buddy(struct ext4_buddy *e4b, char *file, const char *function, int line) { @@ -723,15 +741,6 @@ static void __mb_check_buddy(struct ext4_buddy *e4b, char *file, continue; } - /* both bits in buddy2 must be 1 */ - MB_CHECK_ASSERT(mb_test_bit(i << 1, buddy2)); - MB_CHECK_ASSERT(mb_test_bit((i << 1) + 1, buddy2)); - - for (j = 0; j < (1 << order); j++) { - k = (i * (1 << order)) + j; - MB_CHECK_ASSERT( - !mb_test_bit(k, e4b->bd_bitmap)); - } count++; } MB_CHECK_ASSERT(e4b->bd_info->bb_counters[order] == count); @@ -747,15 +756,21 @@ static void __mb_check_buddy(struct ext4_buddy *e4b, char *file, fragments++; fstart = i; } - continue; + } else { + fstart = -1; } - fstart = -1; - /* check used bits only */ - for (j = 0; j < e4b->bd_blkbits + 1; j++) { - buddy2 = mb_find_buddy(e4b, j, &max2); - k = i >> j; - MB_CHECK_ASSERT(k < max2); - MB_CHECK_ASSERT(mb_test_bit(k, buddy2)); + if (!(i & 1)) { + int in_use, zero_bit_count = 0; + + in_use = mb_test_bit(i, buddy) || mb_test_bit(i + 1, buddy); + for (j = 1; j < e4b->bd_blkbits + 2; j++) { + buddy2 = mb_find_buddy(e4b, j, &max2); + k = i >> j; + MB_CHECK_ASSERT(k < max2); + if (!mb_test_bit(k, buddy2)) + zero_bit_count++; + } + MB_CHECK_ASSERT(zero_bit_count == !in_use); } } MB_CHECK_ASSERT(!EXT4_MB_GRP_NEED_INIT(e4b->bd_info)); From 2a3f91ef20ec4bebdae49f945905e97f68705636 Mon Sep 17 00:00:00 2001 From: Willem de Bruijn Date: Tue, 25 Nov 2025 18:35:05 -0500 Subject: [PATCH 0832/2333] selftests/net: packetdrill: pass send_omit_free to MSG_ZEROCOPY tests [ Upstream commit c01a6e5b2e4f21d31cf725b9f3803cb0280b1b8d ] The --send_omit_free flag is needed for TCP zero copy tests, to ensure that packetdrill doesn't free the send() buffer after the send() call. Fixes: 1e42f73fd3c2 ("selftests/net: packetdrill: import tcp/zerocopy") Closes: https://lore.kernel.org/netdev/20251124071831.4cbbf412@kernel.org/ Suggested-by: Neal Cardwell Signed-off-by: Willem de Bruijn Link: https://patch.msgid.link/20251125234029.1320984-1-willemdebruijn.kernel@gmail.com Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- .../net/packetdrill/tcp_syscall_bad_arg_sendmsg-empty-iov.pkt | 4 ++++ .../testing/selftests/net/packetdrill/tcp_zerocopy_basic.pkt | 2 ++ .../testing/selftests/net/packetdrill/tcp_zerocopy_batch.pkt | 2 ++ .../testing/selftests/net/packetdrill/tcp_zerocopy_client.pkt | 2 ++ .../testing/selftests/net/packetdrill/tcp_zerocopy_closed.pkt | 2 ++ .../selftests/net/packetdrill/tcp_zerocopy_epoll_edge.pkt | 3 +++ .../net/packetdrill/tcp_zerocopy_epoll_exclusive.pkt | 3 +++ .../selftests/net/packetdrill/tcp_zerocopy_epoll_oneshot.pkt | 3 +++ .../net/packetdrill/tcp_zerocopy_fastopen-client.pkt | 2 ++ .../net/packetdrill/tcp_zerocopy_fastopen-server.pkt | 2 ++ .../selftests/net/packetdrill/tcp_zerocopy_maxfrags.pkt | 2 ++ .../testing/selftests/net/packetdrill/tcp_zerocopy_small.pkt | 2 ++ 12 files changed, 29 insertions(+) diff --git a/tools/testing/selftests/net/packetdrill/tcp_syscall_bad_arg_sendmsg-empty-iov.pkt b/tools/testing/selftests/net/packetdrill/tcp_syscall_bad_arg_sendmsg-empty-iov.pkt index b2b2cdf27e20f..454441e7ecff6 100644 --- a/tools/testing/selftests/net/packetdrill/tcp_syscall_bad_arg_sendmsg-empty-iov.pkt +++ b/tools/testing/selftests/net/packetdrill/tcp_syscall_bad_arg_sendmsg-empty-iov.pkt @@ -1,6 +1,10 @@ // SPDX-License-Identifier: GPL-2.0 // Test that we correctly skip zero-length IOVs. + +--send_omit_free // do not reuse send buffers with zerocopy + `./defaults.sh` + 0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 +0 setsockopt(3, SOL_SOCKET, SO_ZEROCOPY, [1], 4) = 0 +0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 diff --git a/tools/testing/selftests/net/packetdrill/tcp_zerocopy_basic.pkt b/tools/testing/selftests/net/packetdrill/tcp_zerocopy_basic.pkt index a82c8899d36bf..0a0700afdaa38 100644 --- a/tools/testing/selftests/net/packetdrill/tcp_zerocopy_basic.pkt +++ b/tools/testing/selftests/net/packetdrill/tcp_zerocopy_basic.pkt @@ -4,6 +4,8 @@ // send a packet with MSG_ZEROCOPY and receive the notification ID // repeat and verify IDs are consecutive +--send_omit_free // do not reuse send buffers with zerocopy + `./defaults.sh` 0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 diff --git a/tools/testing/selftests/net/packetdrill/tcp_zerocopy_batch.pkt b/tools/testing/selftests/net/packetdrill/tcp_zerocopy_batch.pkt index c01915e7f4a15..df91675d2991c 100644 --- a/tools/testing/selftests/net/packetdrill/tcp_zerocopy_batch.pkt +++ b/tools/testing/selftests/net/packetdrill/tcp_zerocopy_batch.pkt @@ -3,6 +3,8 @@ // // send multiple packets, then read one range of all notifications. +--send_omit_free // do not reuse send buffers with zerocopy + `./defaults.sh` 0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 diff --git a/tools/testing/selftests/net/packetdrill/tcp_zerocopy_client.pkt b/tools/testing/selftests/net/packetdrill/tcp_zerocopy_client.pkt index 6509882932e91..2963cfcb14dfd 100644 --- a/tools/testing/selftests/net/packetdrill/tcp_zerocopy_client.pkt +++ b/tools/testing/selftests/net/packetdrill/tcp_zerocopy_client.pkt @@ -1,6 +1,8 @@ // SPDX-License-Identifier: GPL-2.0 // Minimal client-side zerocopy test +--send_omit_free // do not reuse send buffers with zerocopy + `./defaults.sh` 0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 4 diff --git a/tools/testing/selftests/net/packetdrill/tcp_zerocopy_closed.pkt b/tools/testing/selftests/net/packetdrill/tcp_zerocopy_closed.pkt index 2cd78755cb2ac..ea0c2fa73c2d6 100644 --- a/tools/testing/selftests/net/packetdrill/tcp_zerocopy_closed.pkt +++ b/tools/testing/selftests/net/packetdrill/tcp_zerocopy_closed.pkt @@ -7,6 +7,8 @@ // First send on a closed socket and wait for (absent) notification. // Then connect and send and verify that notification nr. is zero. +--send_omit_free // do not reuse send buffers with zerocopy + `./defaults.sh` 0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 4 diff --git a/tools/testing/selftests/net/packetdrill/tcp_zerocopy_epoll_edge.pkt b/tools/testing/selftests/net/packetdrill/tcp_zerocopy_epoll_edge.pkt index 7671c20e01cf6..4df978a9b82e7 100644 --- a/tools/testing/selftests/net/packetdrill/tcp_zerocopy_epoll_edge.pkt +++ b/tools/testing/selftests/net/packetdrill/tcp_zerocopy_epoll_edge.pkt @@ -7,6 +7,9 @@ // fire two sends with MSG_ZEROCOPY and receive the acks. confirm that EPOLLERR // is correctly fired only once, when EPOLLET is set. send another packet with // MSG_ZEROCOPY. confirm that EPOLLERR is correctly fired again only once. + +--send_omit_free // do not reuse send buffers with zerocopy + `./defaults.sh` 0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 diff --git a/tools/testing/selftests/net/packetdrill/tcp_zerocopy_epoll_exclusive.pkt b/tools/testing/selftests/net/packetdrill/tcp_zerocopy_epoll_exclusive.pkt index fadc480fdb7fe..36b6edc4858c4 100644 --- a/tools/testing/selftests/net/packetdrill/tcp_zerocopy_epoll_exclusive.pkt +++ b/tools/testing/selftests/net/packetdrill/tcp_zerocopy_epoll_exclusive.pkt @@ -8,6 +8,9 @@ // fire two sends with MSG_ZEROCOPY and receive the acks. confirm that EPOLLERR // is correctly fired only once, when EPOLLET is set. send another packet with // MSG_ZEROCOPY. confirm that EPOLLERR is correctly fired again only once. + +--send_omit_free // do not reuse send buffers with zerocopy + `./defaults.sh` 0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 diff --git a/tools/testing/selftests/net/packetdrill/tcp_zerocopy_epoll_oneshot.pkt b/tools/testing/selftests/net/packetdrill/tcp_zerocopy_epoll_oneshot.pkt index 5bfa0d1d2f4a3..1bea6f3b4558d 100644 --- a/tools/testing/selftests/net/packetdrill/tcp_zerocopy_epoll_oneshot.pkt +++ b/tools/testing/selftests/net/packetdrill/tcp_zerocopy_epoll_oneshot.pkt @@ -8,6 +8,9 @@ // is correctly fired only once, when EPOLLONESHOT is set. send another packet // with MSG_ZEROCOPY. confirm that EPOLLERR is not fired. Rearm the FD and // confirm that EPOLLERR is correctly set. + +--send_omit_free // do not reuse send buffers with zerocopy + `./defaults.sh` 0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 diff --git a/tools/testing/selftests/net/packetdrill/tcp_zerocopy_fastopen-client.pkt b/tools/testing/selftests/net/packetdrill/tcp_zerocopy_fastopen-client.pkt index 4a73bbf469610..e27c21ff5d18d 100644 --- a/tools/testing/selftests/net/packetdrill/tcp_zerocopy_fastopen-client.pkt +++ b/tools/testing/selftests/net/packetdrill/tcp_zerocopy_fastopen-client.pkt @@ -8,6 +8,8 @@ // one will have no data in the initial send. On return 0 the // zerocopy notification counter is not incremented. Verify this too. +--send_omit_free // do not reuse send buffers with zerocopy + `./defaults.sh` // Send a FastOpen request, no cookie yet so no data in SYN diff --git a/tools/testing/selftests/net/packetdrill/tcp_zerocopy_fastopen-server.pkt b/tools/testing/selftests/net/packetdrill/tcp_zerocopy_fastopen-server.pkt index 36086c5877ce7..b1fa77c77dfa7 100644 --- a/tools/testing/selftests/net/packetdrill/tcp_zerocopy_fastopen-server.pkt +++ b/tools/testing/selftests/net/packetdrill/tcp_zerocopy_fastopen-server.pkt @@ -4,6 +4,8 @@ // send data with MSG_FASTOPEN | MSG_ZEROCOPY and verify that the // kernel returns the notification ID. +--send_omit_free // do not reuse send buffers with zerocopy + `./defaults.sh ./set_sysctls.py /proc/sys/net/ipv4/tcp_fastopen=0x207` diff --git a/tools/testing/selftests/net/packetdrill/tcp_zerocopy_maxfrags.pkt b/tools/testing/selftests/net/packetdrill/tcp_zerocopy_maxfrags.pkt index 672f817faca0d..2f5317d0a9fab 100644 --- a/tools/testing/selftests/net/packetdrill/tcp_zerocopy_maxfrags.pkt +++ b/tools/testing/selftests/net/packetdrill/tcp_zerocopy_maxfrags.pkt @@ -7,6 +7,8 @@ // because each iovec element becomes a frag // 3) the PSH bit is set on an skb when it runs out of fragments +--send_omit_free // do not reuse send buffers with zerocopy + `./defaults.sh` 0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 diff --git a/tools/testing/selftests/net/packetdrill/tcp_zerocopy_small.pkt b/tools/testing/selftests/net/packetdrill/tcp_zerocopy_small.pkt index a9a1ac0aea4f4..9d5272c6b2079 100644 --- a/tools/testing/selftests/net/packetdrill/tcp_zerocopy_small.pkt +++ b/tools/testing/selftests/net/packetdrill/tcp_zerocopy_small.pkt @@ -4,6 +4,8 @@ // verify that SO_EE_CODE_ZEROCOPY_COPIED is set on zerocopy // packets of all sizes, including the smallest payload, 1B. +--send_omit_free // do not reuse send buffers with zerocopy + `./defaults.sh` 0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 From 1b70f280c39ede03b8027ead55df76d2ad4784e0 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Thu, 23 Oct 2025 09:04:14 -0700 Subject: [PATCH 0833/2333] of: Skip devicetree kunit tests when RISCV+ACPI doesn't populate root node [ Upstream commit 546dbb0223102813ffb5bbcb9443a47c3183f195 ] Starting with commit 69a8b62a7aa1 ("riscv: acpi: avoid errors caused by probing DT devices when ACPI is used"), riscv images no longer populate devicetree if ACPI is enabled. This causes unit tests to fail which require the root node to be set. # Subtest: of_dtb # module: of_test 1..2 # of_dtb_root_node_found_by_path: EXPECTATION FAILED at drivers/of/of_test.c:21 Expected np is not null, but is # of_dtb_root_node_found_by_path: pass:0 fail:1 skip:0 total:1 not ok 1 of_dtb_root_node_found_by_path # of_dtb_root_node_populates_of_root: EXPECTATION FAILED at drivers/of/of_test.c:31 Expected of_root is not null, but is # of_dtb_root_node_populates_of_root: pass:0 fail:1 skip:0 total:1 not ok 2 of_dtb_root_node_populates_of_root Skip those tests for RISCV if the root node is not populated. Fixes: 69a8b62a7aa1 ("riscv: acpi: avoid errors caused by probing DT devices when ACPI is used") Cc: Han Gao Cc: Paul Walmsley Signed-off-by: Guenter Roeck Reviewed-by: Paul Walmsley # arch/riscv Link: https://patch.msgid.link/20251023160415.705294-1-linux@roeck-us.net Signed-off-by: Rob Herring (Arm) Signed-off-by: Sasha Levin --- drivers/of/of_kunit_helpers.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/of/of_kunit_helpers.c b/drivers/of/of_kunit_helpers.c index 7b3ed5a382aaa..f6ed1af8b62aa 100644 --- a/drivers/of/of_kunit_helpers.c +++ b/drivers/of/of_kunit_helpers.c @@ -18,8 +18,9 @@ */ void of_root_kunit_skip(struct kunit *test) { - if (IS_ENABLED(CONFIG_ARM64) && IS_ENABLED(CONFIG_ACPI) && !of_root) - kunit_skip(test, "arm64+acpi doesn't populate a root node"); + if ((IS_ENABLED(CONFIG_ARM64) || IS_ENABLED(CONFIG_RISCV)) && + IS_ENABLED(CONFIG_ACPI) && !of_root) + kunit_skip(test, "arm64/riscv+acpi doesn't populate a root node"); } EXPORT_SYMBOL_GPL(of_root_kunit_skip); From 3c30975c9abaa8058716fedfc8828a6f2bd3a201 Mon Sep 17 00:00:00 2001 From: Alok Tiwari Date: Wed, 1 Oct 2025 12:16:50 -0700 Subject: [PATCH 0834/2333] virtio_vdpa: fix misleading return in void function [ Upstream commit e40b6abe0b1247d43bc61942aa7534fca7209e44 ] virtio_vdpa_set_status() is declared as returning void, but it used "return vdpa_set_status()" Since vdpa_set_status() also returns void, the return statement is unnecessary and misleading. Remove it. Fixes: c043b4a8cf3b ("virtio: introduce a vDPA based transport") Signed-off-by: Alok Tiwari Message-Id: <20251001191653.1713923-1-alok.a.tiwari@oracle.com> Signed-off-by: Michael S. Tsirkin Acked-by: Jason Wang Signed-off-by: Sasha Levin --- drivers/virtio/virtio_vdpa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/virtio/virtio_vdpa.c b/drivers/virtio/virtio_vdpa.c index f9a29045eca0d..0a801f67b5996 100644 --- a/drivers/virtio/virtio_vdpa.c +++ b/drivers/virtio/virtio_vdpa.c @@ -80,7 +80,7 @@ static void virtio_vdpa_set_status(struct virtio_device *vdev, u8 status) { struct vdpa_device *vdpa = vd_get_vdpa(vdev); - return vdpa_set_status(vdpa, status); + vdpa_set_status(vdpa, status); } static void virtio_vdpa_reset(struct virtio_device *vdev) From a8d39a172781b7f9e5ae440dea97865499d0375c Mon Sep 17 00:00:00 2001 From: Kriish Sharma Date: Mon, 10 Nov 2025 20:29:20 +0000 Subject: [PATCH 0835/2333] virtio: fix kernel-doc for mapping/free_coherent functions [ Upstream commit f8113000855a8cc2c6d8e19b97a390f1c082285d ] Documentation build reported: WARNING: ./drivers/virtio/virtio_ring.c:3174 function parameter 'vaddr' not described in 'virtqueue_map_free_coherent' WARNING: ./drivers/virtio/virtio_ring.c:3308 expecting prototype for virtqueue_mapping_error(). Prototype was for virtqueue_map_mapping_error() instead The kernel-doc block for virtqueue_map_free_coherent() omitted the @vaddr parameter, and the kernel-doc header for virtqueue_map_mapping_error() used the wrong function name (virtqueue_mapping_error) instead of the actual function name. This change updates: - the function name in the comment to virtqueue_map_mapping_error() - adds the missing @vaddr description in the comment for virtqueue_map_free_coherent() Fixes: b41cb3bcf67f ("virtio: rename dma helpers") Signed-off-by: Kriish Sharma Reviewed-by: Chaitanya Kulkarni Signed-off-by: Michael S. Tsirkin Message-Id: <20251110202920.2250244-1-kriish.sharma2006@gmail.com> Signed-off-by: Sasha Levin --- drivers/virtio/virtio_ring.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c index 7b6205253b46b..ddab689596717 100644 --- a/drivers/virtio/virtio_ring.c +++ b/drivers/virtio/virtio_ring.c @@ -3166,6 +3166,7 @@ EXPORT_SYMBOL_GPL(virtqueue_map_alloc_coherent); * @vdev: the virtio device we are talking to * @map: metadata for performing mapping * @size: the size of the buffer + * @vaddr: the virtual address that needs to be freed * @map_handle: the mapped address that needs to be freed * */ @@ -3190,7 +3191,7 @@ EXPORT_SYMBOL_GPL(virtqueue_map_free_coherent); * @dir: mapping direction * @attrs: mapping attributes * - * Returns mapped address. Caller should check that by virtqueue_mapping_error(). + * Returns mapped address. Caller should check that by virtqueue_map_mapping_error(). */ dma_addr_t virtqueue_map_page_attrs(const struct virtqueue *_vq, struct page *page, @@ -3249,7 +3250,7 @@ EXPORT_SYMBOL_GPL(virtqueue_unmap_page_attrs); * The caller calls this to do dma mapping in advance. The DMA address can be * passed to this _vq when it is in pre-mapped mode. * - * return mapped address. Caller should check that by virtqueue_mapping_error(). + * return mapped address. Caller should check that by virtqueue_map_mapping_error(). */ dma_addr_t virtqueue_map_single_attrs(const struct virtqueue *_vq, void *ptr, size_t size, @@ -3299,7 +3300,7 @@ void virtqueue_unmap_single_attrs(const struct virtqueue *_vq, EXPORT_SYMBOL_GPL(virtqueue_unmap_single_attrs); /** - * virtqueue_mapping_error - check dma address + * virtqueue_map_mapping_error - check dma address * @_vq: the struct virtqueue we're talking about. * @addr: DMA address * From 201ca193b4928dba9da0d10b1c356b7f9172249e Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Thu, 13 Nov 2025 04:34:31 -0500 Subject: [PATCH 0836/2333] virtio: fix typo in virtio_device_ready() comment [ Upstream commit 361173f95ae4b726ebbbf0bd594274f5576c4abc ] "coherenct" -> "coherent" Fixes: 8b4ec69d7e09 ("virtio: harden vring IRQ") Message-Id: Acked-by: Jason Wang Signed-off-by: Michael S. Tsirkin Signed-off-by: Sasha Levin --- include/linux/virtio_config.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/virtio_config.h b/include/linux/virtio_config.h index 16001e9f9b391..1ea5baa62141f 100644 --- a/include/linux/virtio_config.h +++ b/include/linux/virtio_config.h @@ -362,7 +362,7 @@ void virtio_device_ready(struct virtio_device *dev) * specific set_status() method. * * A well behaved device will only notify a virtqueue after - * DRIVER_OK, this means the device should "see" the coherenct + * DRIVER_OK, this means the device should "see" the coherent * memory write that set vq->broken as false which is done by * the driver when it sees DRIVER_OK, then the following * driver's vring_interrupt() will see vq->broken as false so From e3e6c543e6952e28cd218e15678f6a2a03e833eb Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Thu, 13 Nov 2025 04:34:34 -0500 Subject: [PATCH 0837/2333] virtio: fix whitespace in virtio_config_ops [ Upstream commit 7831791e77a1cd29528d4dc336ce14466aef5ba6 ] The finalize_features documentation uses a tab between words. Use space instead. Fixes: d16c0cd27331 ("docs: driver-api: virtio: virtio on Linux") Message-Id: <39d7685c82848dc6a876d175e33a1407f6ab3fc1.1763026134.git.mst@redhat.com> Acked-by: Jason Wang Signed-off-by: Michael S. Tsirkin Signed-off-by: Sasha Levin --- include/linux/virtio_config.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/virtio_config.h b/include/linux/virtio_config.h index 1ea5baa62141f..dbc7eff1f101f 100644 --- a/include/linux/virtio_config.h +++ b/include/linux/virtio_config.h @@ -86,7 +86,7 @@ struct virtqueue_info { * vdev: the virtio_device * This sends the driver feature bits to the device: it can change * the dev->feature bits if it wants. - * Note that despite the name this can be called any number of + * Note that despite the name this can be called any number of * times. * Returns 0 on success or error status * @bus_name: return the bus name associated with the device (optional) From 6c5dfc6f33deeb9e8a397d3b10b8da8c6b6f5731 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Thu, 13 Nov 2025 04:34:36 -0500 Subject: [PATCH 0838/2333] virtio: fix grammar in virtio_queue_info docs [ Upstream commit 63598fba55ab9d384818fed48dc04006cecf7be4 ] Fix grammar in the description of @ctx Fixes: c502eb85c34e ("virtio: introduce virtio_queue_info struct and find_vqs_info() config op") Message-Id: Acked-by: Jason Wang Signed-off-by: Michael S. Tsirkin Signed-off-by: Sasha Levin --- include/linux/virtio_config.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/virtio_config.h b/include/linux/virtio_config.h index dbc7eff1f101f..78cf4119f5674 100644 --- a/include/linux/virtio_config.h +++ b/include/linux/virtio_config.h @@ -24,7 +24,7 @@ typedef void vq_callback_t(struct virtqueue *); * a virtqueue unused by the driver. * @callback: A callback to invoke on a used buffer notification. * NULL for a virtqueue that does not need a callback. - * @ctx: A flag to indicate to maintain an extra context per virtqueue. + * @ctx: whether to maintain an extra context per virtqueue. */ struct virtqueue_info { const char *name; From ed4dade6223d590e2d3b52a1b35f8e930738e165 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Thu, 13 Nov 2025 04:34:38 -0500 Subject: [PATCH 0839/2333] virtio: fix grammar in virtio_map_ops docs [ Upstream commit c15f42e09178d2849744ccf064200f5e7f71e688 ] Fix grammar issues in the virtio_map_ops docs: - missing article before "transport" - "implements" -> "implement" to match subject Fixes: bee8c7c24b73 ("virtio: introduce map ops in virtio core") Message-Id: <3f7bcae5a984f14b72e67e82572b110acb06fa7e.1763026134.git.mst@redhat.com> Acked-by: Jason Wang Signed-off-by: Michael S. Tsirkin Signed-off-by: Sasha Levin --- include/linux/virtio_config.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/linux/virtio_config.h b/include/linux/virtio_config.h index 78cf4119f5674..6660132258d40 100644 --- a/include/linux/virtio_config.h +++ b/include/linux/virtio_config.h @@ -141,8 +141,8 @@ struct virtio_config_ops { /** * struct virtio_map_ops - operations for mapping buffer for a virtio device - * Note: For transport that has its own mapping logic it must - * implements all of the operations + * Note: For a transport that has its own mapping logic it must + * implement all of the operations * @map_page: map a buffer to the device * map: metadata for performing mapping * page: the page that will be mapped by the device From 5fdd8443c0a4c4f03cfdbdb9255a43c5a1cb280d Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Thu, 13 Nov 2025 04:34:41 -0500 Subject: [PATCH 0840/2333] virtio: standardize Returns documentation style [ Upstream commit 5e88a5a97d113619b674ebfdd1d2065f2edd10eb ] Remove colons after "Returns" in virtio_map_ops function documentation - both to avoid triggering an htmldoc warning and for consistency with virtio_config_ops. This affects map_page, alloc, need_sync, and max_mapping_size. Fixes: bee8c7c24b73 ("virtio: introduce map ops in virtio core") Message-Id: Acked-by: Jason Wang Signed-off-by: Michael S. Tsirkin Signed-off-by: Sasha Levin --- include/linux/virtio_config.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/linux/virtio_config.h b/include/linux/virtio_config.h index 6660132258d40..e231147ff92db 100644 --- a/include/linux/virtio_config.h +++ b/include/linux/virtio_config.h @@ -150,7 +150,7 @@ struct virtio_config_ops { * size: the buffer size * dir: mapping direction * attrs: mapping attributes - * Returns: the mapped address + * Returns the mapped address * @unmap_page: unmap a buffer from the device * map: device specific mapping map * map_handle: the mapped address @@ -172,7 +172,7 @@ struct virtio_config_ops { * size: the size of the buffer * map_handle: the mapping address to sync * gfp: allocation flag (GFP_XXX) - * Returns: virtual address of the allocated buffer + * Returns virtual address of the allocated buffer * @free: free a coherent buffer mapping * map: metadata for performing mapping * size: the size of the buffer @@ -182,13 +182,13 @@ struct virtio_config_ops { * @need_sync: if the buffer needs synchronization * map: metadata for performing mapping * map_handle: the mapped address - * Returns: whether the buffer needs synchronization + * Returns whether the buffer needs synchronization * @mapping_error: if the mapping address is error * map: metadata for performing mapping * map_handle: the mapped address * @max_mapping_size: get the maximum buffer size that can be mapped * map: metadata for performing mapping - * Returns: the maximum buffer size that can be mapped + * Returns the maximum buffer size that can be mapped */ struct virtio_map_ops { dma_addr_t (*map_page)(union virtio_map map, struct page *page, From 99ae54bbb4751ec1ab8599151bf4871d845982fc Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Thu, 13 Nov 2025 04:34:43 -0500 Subject: [PATCH 0841/2333] virtio: fix virtqueue_set_affinity() docs [ Upstream commit 43236d8bbafff94b423afecc4a692dd90602d426 ] Rewrite the comment for better grammar and clarity. Fixes: 75a0a52be3c2 ("virtio: introduce an API to set affinity for a virtqueue") Message-Id: Acked-by: Jason Wang Signed-off-by: Michael S. Tsirkin Signed-off-by: Sasha Levin --- include/linux/virtio_config.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/virtio_config.h b/include/linux/virtio_config.h index e231147ff92db..1a019a1f168d5 100644 --- a/include/linux/virtio_config.h +++ b/include/linux/virtio_config.h @@ -384,7 +384,7 @@ const char *virtio_bus_name(struct virtio_device *vdev) * @vq: the virtqueue * @cpu_mask: the cpu mask * - * Pay attention the function are best-effort: the affinity hint may not be set + * Note that this function is best-effort: the affinity hint may not be set * due to config support, irq type and sharing. * */ From d94497989a9ce95f71b5e1108de07c75112e8f71 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Thu, 13 Nov 2025 04:34:49 -0500 Subject: [PATCH 0842/2333] virtio: fix map ops comment [ Upstream commit deb55fc994e3dc38f139c0147c15fc2a9db27086 ] @free will free the map handle not sync it. Fix the doc to match. Fixes: bee8c7c24b73 ("virtio: introduce map ops in virtio core") Message-Id: Acked-by: Jason Wang Signed-off-by: Michael S. Tsirkin Signed-off-by: Sasha Levin --- include/linux/virtio_config.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/virtio_config.h b/include/linux/virtio_config.h index 1a019a1f168d5..a1af2676bbe6a 100644 --- a/include/linux/virtio_config.h +++ b/include/linux/virtio_config.h @@ -177,7 +177,7 @@ struct virtio_config_ops { * map: metadata for performing mapping * size: the size of the buffer * vaddr: virtual address of the buffer - * map_handle: the mapping address to sync + * map_handle: the mapping address that needs to be freed * attrs: unmapping attributes * @need_sync: if the buffer needs synchronization * map: metadata for performing mapping From ba8a48b7be20f3818d4942b9611983a117f042b6 Mon Sep 17 00:00:00 2001 From: Alok Tiwari Date: Mon, 29 Sep 2025 06:42:53 -0700 Subject: [PATCH 0843/2333] vdpa/mlx5: Fix incorrect error code reporting in query_virtqueues [ Upstream commit f0ea2e91093ac979d07ebd033e0f45869b1d2608 ] When query_virtqueues() fails, the error log prints the variable err instead of cmd->err. Since err may still be zero at this point, the log message can misleadingly report a success value 0 even though the command actually failed. Even worse, once err is set to the first failure, subsequent logs print that same stale value. This makes the error reporting appear one step behind the actual failing queue index, which is confusing and misleading. Fix the log to report cmd->err, which reflects the real failure code returned by the firmware. Fixes: 1fcdf43ea69e ("vdpa/mlx5: Use async API for vq query command") Signed-off-by: Alok Tiwari Acked-by: Jason Wang Reviewed-by: Dragos Tatulea Signed-off-by: Michael S. Tsirkin Message-Id: <20250929134258.80956-1-alok.a.tiwari@oracle.com> Signed-off-by: Sasha Levin --- drivers/vdpa/mlx5/net/mlx5_vnet.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/vdpa/mlx5/net/mlx5_vnet.c b/drivers/vdpa/mlx5/net/mlx5_vnet.c index a7936bd1aabe1..ddaa1366704bb 100644 --- a/drivers/vdpa/mlx5/net/mlx5_vnet.c +++ b/drivers/vdpa/mlx5/net/mlx5_vnet.c @@ -1256,7 +1256,7 @@ static int query_virtqueues(struct mlx5_vdpa_net *ndev, int vq_idx = start_vq + i; if (cmd->err) { - mlx5_vdpa_err(mvdev, "query vq %d failed, err: %d\n", vq_idx, err); + mlx5_vdpa_err(mvdev, "query vq %d failed, err: %d\n", vq_idx, cmd->err); if (!err) err = cmd->err; continue; From 09853ba0977f678561d93286d40e1ad62c80447b Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Sat, 1 Nov 2025 14:43:58 -0500 Subject: [PATCH 0844/2333] vhost: Fix kthread worker cgroup failure handling [ Upstream commit f3f64c2eaffbc3169bbe1e5d1e897e6dacc839d1 ] If we fail to attach to a cgroup we are leaking the id. This adds a new goto to free the id. Fixes: 7d9896e9f6d0 ("vhost: Reintroduce kthread API and add mode selection") Signed-off-by: Mike Christie Acked-by: Jason Wang Reviewed-by: Chaitanya Kulkarni Signed-off-by: Michael S. Tsirkin Message-Id: <20251101194358.13605-1-michael.christie@oracle.com> Signed-off-by: Sasha Levin --- drivers/vhost/vhost.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index a78226b37739d..bccdc9eab267a 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -804,11 +804,13 @@ static int vhost_kthread_worker_create(struct vhost_worker *worker, ret = vhost_attach_task_to_cgroups(worker); if (ret) - goto stop_worker; + goto free_id; worker->id = id; return 0; +free_id: + xa_erase(&dev->worker_xa, id); stop_worker: vhost_kthread_do_stop(worker); return ret; From ce46f6a8d62449c6cd0710756717c0c233014b13 Mon Sep 17 00:00:00 2001 From: Alok Tiwari Date: Sat, 18 Oct 2025 10:46:46 -0700 Subject: [PATCH 0845/2333] vdpa/pds: use %pe for ERR_PTR() in event handler registration [ Upstream commit 731ca4a4cc52fd5c5ae309edcfd2d7e54ece3321 ] Use %pe instead of %ps when printing ERR_PTR() values. %ps is intended for string pointers, while %pe correctly prints symbolic error names for error pointers returned via ERR_PTR(). This shows the returned error value more clearly. Fixes: 67f27b8b3a34 ("pds_vdpa: subscribe to the pds_core events") Signed-off-by: Alok Tiwari Reviewed-by: Brett Creeley Signed-off-by: Michael S. Tsirkin Message-Id: <20251018174705.1511982-1-alok.a.tiwari@oracle.com> Signed-off-by: Sasha Levin --- drivers/vdpa/pds/vdpa_dev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/vdpa/pds/vdpa_dev.c b/drivers/vdpa/pds/vdpa_dev.c index 36f61cc96e211..43426bd971acc 100644 --- a/drivers/vdpa/pds/vdpa_dev.c +++ b/drivers/vdpa/pds/vdpa_dev.c @@ -51,7 +51,7 @@ static int pds_vdpa_register_event_handler(struct pds_vdpa_device *pdsv) err = pdsc_register_notify(nb); if (err) { nb->notifier_call = NULL; - dev_err(dev, "failed to register pds event handler: %ps\n", + dev_err(dev, "failed to register pds event handler: %pe\n", ERR_PTR(err)); return -EINVAL; } From 9223cdb994d9327ebce47a5749a763fb820bd2c1 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Tue, 21 Oct 2025 10:56:57 -0400 Subject: [PATCH 0846/2333] virtio: clean up features qword/dword terms [ Upstream commit 9513f25056b22100ddffe24898c587873b0d022c ] virtio pci uses word to mean "16 bits". mmio uses it to mean "32 bits". To avoid confusion, let's avoid the term in core virtio altogether. Just say U64 to mean "64 bit". Fixes: e7d4c1c5a546 ("virtio: introduce extended features") Cc: Paolo Abeni Acked-by: Jason Wang Message-ID: Signed-off-by: Michael S. Tsirkin Signed-off-by: Sasha Levin --- drivers/vhost/net.c | 12 +++++------ drivers/virtio/virtio.c | 12 +++++------ drivers/virtio/virtio_debug.c | 10 ++++----- drivers/virtio/virtio_pci_modern_dev.c | 6 +++--- include/linux/virtio.h | 2 +- include/linux/virtio_config.h | 2 +- include/linux/virtio_features.h | 29 +++++++++++++------------- include/linux/virtio_pci_modern.h | 8 +++---- 8 files changed, 41 insertions(+), 40 deletions(-) diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c index 8f7f50acb6d63..1e77c0482b849 100644 --- a/drivers/vhost/net.c +++ b/drivers/vhost/net.c @@ -69,7 +69,7 @@ MODULE_PARM_DESC(experimental_zcopytx, "Enable Zero Copy TX;" #define VHOST_DMA_IS_DONE(len) ((__force u32)(len) >= (__force u32)VHOST_DMA_DONE_LEN) -static const u64 vhost_net_features[VIRTIO_FEATURES_DWORDS] = { +static const u64 vhost_net_features[VIRTIO_FEATURES_U64S] = { VHOST_FEATURES | (1ULL << VHOST_NET_F_VIRTIO_NET_HDR) | (1ULL << VIRTIO_NET_F_MRG_RXBUF) | @@ -1731,7 +1731,7 @@ static long vhost_net_set_owner(struct vhost_net *n) static long vhost_net_ioctl(struct file *f, unsigned int ioctl, unsigned long arg) { - u64 all_features[VIRTIO_FEATURES_DWORDS]; + u64 all_features[VIRTIO_FEATURES_U64S]; struct vhost_net *n = f->private_data; void __user *argp = (void __user *)arg; u64 __user *featurep = argp; @@ -1763,7 +1763,7 @@ static long vhost_net_ioctl(struct file *f, unsigned int ioctl, /* Copy the net features, up to the user-provided buffer size */ argp += sizeof(u64); - copied = min(count, VIRTIO_FEATURES_DWORDS); + copied = min(count, (u64)VIRTIO_FEATURES_U64S); if (copy_to_user(argp, vhost_net_features, copied * sizeof(u64))) return -EFAULT; @@ -1778,13 +1778,13 @@ static long vhost_net_ioctl(struct file *f, unsigned int ioctl, virtio_features_zero(all_features); argp += sizeof(u64); - copied = min(count, VIRTIO_FEATURES_DWORDS); + copied = min(count, (u64)VIRTIO_FEATURES_U64S); if (copy_from_user(all_features, argp, copied * sizeof(u64))) return -EFAULT; /* * Any feature specified by user-space above - * VIRTIO_FEATURES_MAX is not supported by definition. + * VIRTIO_FEATURES_BITS is not supported by definition. */ for (i = copied; i < count; ++i) { if (copy_from_user(&features, featurep + 1 + i, @@ -1794,7 +1794,7 @@ static long vhost_net_ioctl(struct file *f, unsigned int ioctl, return -EOPNOTSUPP; } - for (i = 0; i < VIRTIO_FEATURES_DWORDS; i++) + for (i = 0; i < VIRTIO_FEATURES_U64S; i++) if (all_features[i] & ~vhost_net_features[i]) return -EOPNOTSUPP; diff --git a/drivers/virtio/virtio.c b/drivers/virtio/virtio.c index a09eb4d62f82d..5bdc6b82b30b4 100644 --- a/drivers/virtio/virtio.c +++ b/drivers/virtio/virtio.c @@ -53,7 +53,7 @@ static ssize_t features_show(struct device *_d, /* We actually represent this as a bitstring, as it could be * arbitrary length in future. */ - for (i = 0; i < VIRTIO_FEATURES_MAX; i++) + for (i = 0; i < VIRTIO_FEATURES_BITS; i++) len += sysfs_emit_at(buf, len, "%c", __virtio_test_bit(dev, i) ? '1' : '0'); len += sysfs_emit_at(buf, len, "\n"); @@ -272,8 +272,8 @@ static int virtio_dev_probe(struct device *_d) int err, i; struct virtio_device *dev = dev_to_virtio(_d); struct virtio_driver *drv = drv_to_virtio(dev->dev.driver); - u64 device_features[VIRTIO_FEATURES_DWORDS]; - u64 driver_features[VIRTIO_FEATURES_DWORDS]; + u64 device_features[VIRTIO_FEATURES_U64S]; + u64 driver_features[VIRTIO_FEATURES_U64S]; u64 driver_features_legacy; /* We have a driver! */ @@ -286,7 +286,7 @@ static int virtio_dev_probe(struct device *_d) virtio_features_zero(driver_features); for (i = 0; i < drv->feature_table_size; i++) { unsigned int f = drv->feature_table[i]; - if (!WARN_ON_ONCE(f >= VIRTIO_FEATURES_MAX)) + if (!WARN_ON_ONCE(f >= VIRTIO_FEATURES_BITS)) virtio_features_set_bit(driver_features, f); } @@ -303,7 +303,7 @@ static int virtio_dev_probe(struct device *_d) } if (virtio_features_test_bit(device_features, VIRTIO_F_VERSION_1)) { - for (i = 0; i < VIRTIO_FEATURES_DWORDS; ++i) + for (i = 0; i < VIRTIO_FEATURES_U64S; ++i) dev->features_array[i] = driver_features[i] & device_features[i]; } else { @@ -325,7 +325,7 @@ static int virtio_dev_probe(struct device *_d) goto err; if (drv->validate) { - u64 features[VIRTIO_FEATURES_DWORDS]; + u64 features[VIRTIO_FEATURES_U64S]; virtio_features_copy(features, dev->features_array); err = drv->validate(dev); diff --git a/drivers/virtio/virtio_debug.c b/drivers/virtio/virtio_debug.c index d58713ddf2e58..ccf1955a1183a 100644 --- a/drivers/virtio/virtio_debug.c +++ b/drivers/virtio/virtio_debug.c @@ -8,12 +8,12 @@ static struct dentry *virtio_debugfs_dir; static int virtio_debug_device_features_show(struct seq_file *s, void *data) { - u64 device_features[VIRTIO_FEATURES_DWORDS]; + u64 device_features[VIRTIO_FEATURES_U64S]; struct virtio_device *dev = s->private; unsigned int i; virtio_get_features(dev, device_features); - for (i = 0; i < VIRTIO_FEATURES_MAX; i++) { + for (i = 0; i < VIRTIO_FEATURES_BITS; i++) { if (virtio_features_test_bit(device_features, i)) seq_printf(s, "%u\n", i); } @@ -26,7 +26,7 @@ static int virtio_debug_filter_features_show(struct seq_file *s, void *data) struct virtio_device *dev = s->private; unsigned int i; - for (i = 0; i < VIRTIO_FEATURES_MAX; i++) { + for (i = 0; i < VIRTIO_FEATURES_BITS; i++) { if (virtio_features_test_bit(dev->debugfs_filter_features, i)) seq_printf(s, "%u\n", i); } @@ -50,7 +50,7 @@ static int virtio_debug_filter_feature_add(void *data, u64 val) { struct virtio_device *dev = data; - if (val >= VIRTIO_FEATURES_MAX) + if (val >= VIRTIO_FEATURES_BITS) return -EINVAL; virtio_features_set_bit(dev->debugfs_filter_features, val); @@ -64,7 +64,7 @@ static int virtio_debug_filter_feature_del(void *data, u64 val) { struct virtio_device *dev = data; - if (val >= VIRTIO_FEATURES_MAX) + if (val >= VIRTIO_FEATURES_BITS) return -EINVAL; virtio_features_clear_bit(dev->debugfs_filter_features, val); diff --git a/drivers/virtio/virtio_pci_modern_dev.c b/drivers/virtio/virtio_pci_modern_dev.c index 9e503b7a58d81..413a8c3534638 100644 --- a/drivers/virtio/virtio_pci_modern_dev.c +++ b/drivers/virtio/virtio_pci_modern_dev.c @@ -401,7 +401,7 @@ void vp_modern_get_extended_features(struct virtio_pci_modern_device *mdev, int i; virtio_features_zero(features); - for (i = 0; i < VIRTIO_FEATURES_WORDS; i++) { + for (i = 0; i < VIRTIO_FEATURES_BITS / 32; i++) { u64 cur; vp_iowrite32(i, &cfg->device_feature_select); @@ -427,7 +427,7 @@ vp_modern_get_driver_extended_features(struct virtio_pci_modern_device *mdev, int i; virtio_features_zero(features); - for (i = 0; i < VIRTIO_FEATURES_WORDS; i++) { + for (i = 0; i < VIRTIO_FEATURES_BITS / 32; i++) { u64 cur; vp_iowrite32(i, &cfg->guest_feature_select); @@ -448,7 +448,7 @@ void vp_modern_set_extended_features(struct virtio_pci_modern_device *mdev, struct virtio_pci_common_cfg __iomem *cfg = mdev->common; int i; - for (i = 0; i < VIRTIO_FEATURES_WORDS; i++) { + for (i = 0; i < VIRTIO_FEATURES_BITS / 32; i++) { u32 cur = features[i >> 1] >> (32 * (i & 1)); vp_iowrite32(i, &cfg->guest_feature_select); diff --git a/include/linux/virtio.h b/include/linux/virtio.h index 96c66126c0741..132a474e59140 100644 --- a/include/linux/virtio.h +++ b/include/linux/virtio.h @@ -177,7 +177,7 @@ struct virtio_device { union virtio_map vmap; #ifdef CONFIG_VIRTIO_DEBUG struct dentry *debugfs_dir; - u64 debugfs_filter_features[VIRTIO_FEATURES_DWORDS]; + u64 debugfs_filter_features[VIRTIO_FEATURES_U64S]; #endif }; diff --git a/include/linux/virtio_config.h b/include/linux/virtio_config.h index a1af2676bbe6a..69f84ea85d71a 100644 --- a/include/linux/virtio_config.h +++ b/include/linux/virtio_config.h @@ -80,7 +80,7 @@ struct virtqueue_info { * Returns the first 64 feature bits. * @get_extended_features: * vdev: the virtio_device - * Returns the first VIRTIO_FEATURES_MAX feature bits (all we currently + * Returns the first VIRTIO_FEATURES_BITS feature bits (all we currently * need). * @finalize_features: confirm what device features we'll be using. * vdev: the virtio_device diff --git a/include/linux/virtio_features.h b/include/linux/virtio_features.h index f748f2f87de8d..ea2ad8717882e 100644 --- a/include/linux/virtio_features.h +++ b/include/linux/virtio_features.h @@ -4,15 +4,16 @@ #include -#define VIRTIO_FEATURES_DWORDS 2 -#define VIRTIO_FEATURES_MAX (VIRTIO_FEATURES_DWORDS * 64) -#define VIRTIO_FEATURES_WORDS (VIRTIO_FEATURES_DWORDS * 2) +#define VIRTIO_FEATURES_U64S 2 +#define VIRTIO_FEATURES_BITS (VIRTIO_FEATURES_U64S * 64) + #define VIRTIO_BIT(b) BIT_ULL((b) & 0x3f) -#define VIRTIO_DWORD(b) ((b) >> 6) +#define VIRTIO_U64(b) ((b) >> 6) + #define VIRTIO_DECLARE_FEATURES(name) \ union { \ u64 name; \ - u64 name##_array[VIRTIO_FEATURES_DWORDS];\ + u64 name##_array[VIRTIO_FEATURES_U64S];\ } static inline bool virtio_features_chk_bit(unsigned int bit) @@ -22,9 +23,9 @@ static inline bool virtio_features_chk_bit(unsigned int bit) * Don't care returning the correct value: the build * will fail before any bad features access */ - BUILD_BUG_ON(bit >= VIRTIO_FEATURES_MAX); + BUILD_BUG_ON(bit >= VIRTIO_FEATURES_BITS); } else { - if (WARN_ON_ONCE(bit >= VIRTIO_FEATURES_MAX)) + if (WARN_ON_ONCE(bit >= VIRTIO_FEATURES_BITS)) return false; } return true; @@ -34,26 +35,26 @@ static inline bool virtio_features_test_bit(const u64 *features, unsigned int bit) { return virtio_features_chk_bit(bit) && - !!(features[VIRTIO_DWORD(bit)] & VIRTIO_BIT(bit)); + !!(features[VIRTIO_U64(bit)] & VIRTIO_BIT(bit)); } static inline void virtio_features_set_bit(u64 *features, unsigned int bit) { if (virtio_features_chk_bit(bit)) - features[VIRTIO_DWORD(bit)] |= VIRTIO_BIT(bit); + features[VIRTIO_U64(bit)] |= VIRTIO_BIT(bit); } static inline void virtio_features_clear_bit(u64 *features, unsigned int bit) { if (virtio_features_chk_bit(bit)) - features[VIRTIO_DWORD(bit)] &= ~VIRTIO_BIT(bit); + features[VIRTIO_U64(bit)] &= ~VIRTIO_BIT(bit); } static inline void virtio_features_zero(u64 *features) { - memset(features, 0, sizeof(features[0]) * VIRTIO_FEATURES_DWORDS); + memset(features, 0, sizeof(features[0]) * VIRTIO_FEATURES_U64S); } static inline void virtio_features_from_u64(u64 *features, u64 from) @@ -66,7 +67,7 @@ static inline bool virtio_features_equal(const u64 *f1, const u64 *f2) { int i; - for (i = 0; i < VIRTIO_FEATURES_DWORDS; ++i) + for (i = 0; i < VIRTIO_FEATURES_U64S; ++i) if (f1[i] != f2[i]) return false; return true; @@ -74,14 +75,14 @@ static inline bool virtio_features_equal(const u64 *f1, const u64 *f2) static inline void virtio_features_copy(u64 *to, const u64 *from) { - memcpy(to, from, sizeof(to[0]) * VIRTIO_FEATURES_DWORDS); + memcpy(to, from, sizeof(to[0]) * VIRTIO_FEATURES_U64S); } static inline void virtio_features_andnot(u64 *to, const u64 *f1, const u64 *f2) { int i; - for (i = 0; i < VIRTIO_FEATURES_DWORDS; i++) + for (i = 0; i < VIRTIO_FEATURES_U64S; i++) to[i] = f1[i] & ~f2[i]; } diff --git a/include/linux/virtio_pci_modern.h b/include/linux/virtio_pci_modern.h index 48bc12d1045bd..9a3f2fc53bd65 100644 --- a/include/linux/virtio_pci_modern.h +++ b/include/linux/virtio_pci_modern.h @@ -107,7 +107,7 @@ void vp_modern_set_extended_features(struct virtio_pci_modern_device *mdev, static inline u64 vp_modern_get_features(struct virtio_pci_modern_device *mdev) { - u64 features_array[VIRTIO_FEATURES_DWORDS]; + u64 features_array[VIRTIO_FEATURES_U64S]; vp_modern_get_extended_features(mdev, features_array); return features_array[0]; @@ -116,11 +116,11 @@ vp_modern_get_features(struct virtio_pci_modern_device *mdev) static inline u64 vp_modern_get_driver_features(struct virtio_pci_modern_device *mdev) { - u64 features_array[VIRTIO_FEATURES_DWORDS]; + u64 features_array[VIRTIO_FEATURES_U64S]; int i; vp_modern_get_driver_extended_features(mdev, features_array); - for (i = 1; i < VIRTIO_FEATURES_DWORDS; ++i) + for (i = 1; i < VIRTIO_FEATURES_U64S; ++i) WARN_ON_ONCE(features_array[i]); return features_array[0]; } @@ -128,7 +128,7 @@ vp_modern_get_driver_features(struct virtio_pci_modern_device *mdev) static inline void vp_modern_set_features(struct virtio_pci_modern_device *mdev, u64 features) { - u64 features_array[VIRTIO_FEATURES_DWORDS]; + u64 features_array[VIRTIO_FEATURES_U64S]; virtio_features_from_u64(features_array, features); vp_modern_set_extended_features(mdev, features_array); From a2f79598c6c1fd9b3a9544623c98e62194e2dd64 Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Wed, 26 Nov 2025 10:55:20 +0100 Subject: [PATCH 0847/2333] ASoC: Intel: catpt: Fix error path in hw_params() [ Upstream commit 86a5b621be658fc8fe594ca6db317d64de30cce1 ] Do not leave any resources hanging on the DSP side if applying user settings fails. Fixes: 768a3a3b327d ("ASoC: Intel: catpt: Optimize applying user settings") Signed-off-by: Cezary Rojewski Reviewed-by: Andy Shevchenko Link: https://patch.msgid.link/20251126095523.3925364-4-cezary.rojewski@intel.com Signed-off-by: Mark Brown Signed-off-by: Sasha Levin --- sound/soc/intel/catpt/pcm.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sound/soc/intel/catpt/pcm.c b/sound/soc/intel/catpt/pcm.c index bf734c69c4e09..eb03cecdee281 100644 --- a/sound/soc/intel/catpt/pcm.c +++ b/sound/soc/intel/catpt/pcm.c @@ -417,8 +417,10 @@ static int catpt_dai_hw_params(struct snd_pcm_substream *substream, return CATPT_IPC_ERROR(ret); ret = catpt_dai_apply_usettings(dai, stream); - if (ret) + if (ret) { + catpt_ipc_free_stream(cdev, stream->info.stream_hw_id); return ret; + } stream->allocated = true; return 0; From 749c2b72a2baebf023cbcdffc4c1bc50c4e6442a Mon Sep 17 00:00:00 2001 From: Mikhail Kshevetskiy Date: Wed, 26 Nov 2025 02:40:45 +0300 Subject: [PATCH 0848/2333] spi: airoha-snfi: en7523: workaround flash damaging if UART_TXD was short to GND [ Upstream commit 061795b345aff371df8f71d54ae7c7dc8ae630d0 ] Airoha EN7523 specific bug -------------------------- We found that some serial console may pull TX line to GROUND during board boot time. Airoha uses TX line as one of its bootstrap pins. On the EN7523 SoC this may lead to booting in RESERVED boot mode. It was found that some flashes operates incorrectly in RESERVED mode. Micron and Skyhigh flashes are definitely affected by the issue, Winbond flashes are not affected. Details: -------- DMA reading of odd pages on affected flashes operates incorrectly. Page reading offset (start of the page) on hardware level is replaced by 0x10. Thus results in incorrect data reading. As result OS loading becomes impossible. Usage of UBI make things even worse. On attaching, UBI will detects corruptions (because of wrong reading of odd pages) and will try to recover. For recovering UBI will erase and write 'damaged' blocks with a valid information. This will destroy all UBI data. Non-DMA reading is OK. This patch detects booting in reserved mode, turn off DMA and print big fat warning. It's worth noting that the boot configuration is preserved across reboots. Therefore, to boot normally, you should do the following: - disconnect the serial console from the board, - power cycle the board. Fixes: a403997c12019 ("spi: airoha: add SPI-NAND Flash controller driver") Signed-off-by: Mikhail Kshevetskiy Reviewed-by: AngeloGioacchino Del Regno Reviewed-by: Andy Shevchenko Link: https://patch.msgid.link/20251125234047.1101985-2-mikhail.kshevetskiy@iopsys.eu Signed-off-by: Mark Brown Signed-off-by: Sasha Levin --- drivers/spi/spi-airoha-snfi.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi-airoha-snfi.c b/drivers/spi/spi-airoha-snfi.c index b78163eaed61d..20b5d469d519a 100644 --- a/drivers/spi/spi-airoha-snfi.c +++ b/drivers/spi/spi-airoha-snfi.c @@ -1030,6 +1030,11 @@ static const struct spi_controller_mem_ops airoha_snand_mem_ops = { .dirmap_write = airoha_snand_dirmap_write, }; +static const struct spi_controller_mem_ops airoha_snand_nodma_mem_ops = { + .supports_op = airoha_snand_supports_op, + .exec_op = airoha_snand_exec_op, +}; + static int airoha_snand_setup(struct spi_device *spi) { struct airoha_snand_ctrl *as_ctrl; @@ -1104,7 +1109,9 @@ static int airoha_snand_probe(struct platform_device *pdev) struct airoha_snand_ctrl *as_ctrl; struct device *dev = &pdev->dev; struct spi_controller *ctrl; + bool dma_enable = true; void __iomem *base; + u32 sfc_strap; int err; ctrl = devm_spi_alloc_host(dev, sizeof(*as_ctrl)); @@ -1139,12 +1146,28 @@ static int airoha_snand_probe(struct platform_device *pdev) return dev_err_probe(dev, PTR_ERR(as_ctrl->spi_clk), "unable to get spi clk\n"); + if (device_is_compatible(dev, "airoha,en7523-snand")) { + err = regmap_read(as_ctrl->regmap_ctrl, + REG_SPI_CTRL_SFC_STRAP, &sfc_strap); + if (err) + return err; + + if (!(sfc_strap & 0x04)) { + dma_enable = false; + dev_warn(dev, "Detected booting in RESERVED mode (UART_TXD was short to GND).\n"); + dev_warn(dev, "This mode is known for incorrect DMA reading of some flashes.\n"); + dev_warn(dev, "Much slower PIO mode will be used to prevent flash data damage.\n"); + dev_warn(dev, "Unplug UART cable and power cycle board to get full performance.\n"); + } + } + err = dma_set_mask(as_ctrl->dev, DMA_BIT_MASK(32)); if (err) return err; ctrl->num_chipselect = 2; - ctrl->mem_ops = &airoha_snand_mem_ops; + ctrl->mem_ops = dma_enable ? &airoha_snand_mem_ops + : &airoha_snand_nodma_mem_ops; ctrl->bits_per_word_mask = SPI_BPW_MASK(8); ctrl->mode_bits = SPI_RX_DUAL; ctrl->setup = airoha_snand_setup; From 1f11f4e8b7f78527c3a99cc8c2059a3e116438ef Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Wed, 26 Nov 2025 12:00:38 +0100 Subject: [PATCH 0849/2333] soc: samsung: exynos-pmu: Fix structure initialization [ Upstream commit 2224ea67c75d0a0b9eaf803d0dfdab8d0c601c35 ] Commit 78b72897a5c8 ("soc: samsung: exynos-pmu: Enable CPU Idle for gs101") added system wide suspend/resume callbacks to Exynos PMU driver, but some items used by these callbacks are initialized only on GS101-compatible boards. Move that initialization to exynos_pmu_probe() to avoid potential lockdep warnings like below observed during system suspend/resume cycle: INFO: trying to register non-static key. The code is fine but needs lockdep annotation, or maybe you didn't initialize this object before use? turning off the locking correctness validator. CPU: 0 UID: 0 PID: 2134 Comm: rtcwake Not tainted 6.18.0-rc7-next-20251126-00039-g1d656a1af243 #11794 PREEMPT Hardware name: Samsung Exynos (Flattened Device Tree) Call trace: unwind_backtrace from show_stack+0x10/0x14 show_stack from dump_stack_lvl+0x68/0x88 dump_stack_lvl from register_lock_class+0x970/0x988 register_lock_class from __lock_acquire+0xc8/0x29ec __lock_acquire from lock_acquire+0x134/0x39c lock_acquire from _raw_spin_lock+0x38/0x48 _raw_spin_lock from exynos_cpupm_suspend_noirq+0x18/0x34 exynos_cpupm_suspend_noirq from dpm_run_callback+0x98/0x2b8 dpm_run_callback from device_suspend_noirq+0x8c/0x310 Fixes: 78b72897a5c8 ("soc: samsung: exynos-pmu: Enable CPU Idle for gs101") Signed-off-by: Marek Szyprowski Link: https://patch.msgid.link/20251126110038.3326768-1-m.szyprowski@samsung.com [krzk: include calltrace into commit msg] Signed-off-by: Krzysztof Kozlowski Signed-off-by: Sasha Levin --- drivers/soc/samsung/exynos-pmu.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/soc/samsung/exynos-pmu.c b/drivers/soc/samsung/exynos-pmu.c index 22c50ca2aa79b..df5b1f299a260 100644 --- a/drivers/soc/samsung/exynos-pmu.c +++ b/drivers/soc/samsung/exynos-pmu.c @@ -585,10 +585,6 @@ static int setup_cpuhp_and_cpuidle(struct device *dev) if (!pmu_context->in_cpuhp) return -ENOMEM; - raw_spin_lock_init(&pmu_context->cpupm_lock); - pmu_context->sys_inreboot = false; - pmu_context->sys_insuspend = false; - /* set PMU to power on */ for_each_online_cpu(cpu) gs101_cpuhp_pmu_online(cpu); @@ -657,6 +653,9 @@ static int exynos_pmu_probe(struct platform_device *pdev) pmu_context->pmureg = regmap; pmu_context->dev = dev; + raw_spin_lock_init(&pmu_context->cpupm_lock); + pmu_context->sys_inreboot = false; + pmu_context->sys_insuspend = false; if (pmu_context->pmu_data && pmu_context->pmu_data->pmu_cpuhp) { ret = setup_cpuhp_and_cpuidle(dev); From 104a6ed7a4c0301cb75423b79b1f628e029a0713 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Wed, 26 Nov 2025 11:26:15 +0100 Subject: [PATCH 0850/2333] ARM: dts: samsung: universal_c210: turn off SDIO WLAN chip during system suspend [ Upstream commit 97aee67e2406ea381408915e606c5f86448f3949 ] Commit 8c3170628a9c ("wifi: brcmfmac: keep power during suspend if board requires it") changed default behavior of the BRCMFMAC driver, which now keeps SDIO card powered during system suspend to enable optional support for WOWL. This feature is not supported by the legacy Exynos4 based boards and leads to WLAN disfunction after system suspend/resume cycle. Fix this by annotating SDIO host used by WLAN chip with 'cap-power-off-card' property, which should have been there from the beginning. Fixes: f1b0ffaa686f ("ARM: dts: exynos: Enable WLAN support for the UniversalC210 board") Signed-off-by: Marek Szyprowski Link: https://patch.msgid.link/20251126102618.3103517-2-m.szyprowski@samsung.com Signed-off-by: Krzysztof Kozlowski Signed-off-by: Sasha Levin --- arch/arm/boot/dts/samsung/exynos4210-universal_c210.dts | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/boot/dts/samsung/exynos4210-universal_c210.dts b/arch/arm/boot/dts/samsung/exynos4210-universal_c210.dts index bdc30f8cf748f..91490693432b6 100644 --- a/arch/arm/boot/dts/samsung/exynos4210-universal_c210.dts +++ b/arch/arm/boot/dts/samsung/exynos4210-universal_c210.dts @@ -610,6 +610,7 @@ #size-cells = <0>; non-removable; + cap-power-off-card; bus-width = <4>; mmc-pwrseq = <&wlan_pwrseq>; vmmc-supply = <&ldo5_reg>; From ad3e7ec8e21e6087269db9c71b7fd42301f05821 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Wed, 26 Nov 2025 11:26:16 +0100 Subject: [PATCH 0851/2333] ARM: dts: samsung: exynos4210-i9100: turn off SDIO WLAN chip during system suspend [ Upstream commit 863d69923bdb6f414d0a3f504f1dfaeacbc00b09 ] Commit 8c3170628a9c ("wifi: brcmfmac: keep power during suspend if board requires it") changed default behavior of the BRCMFMAC driver, which now keeps SDIO card powered during system suspend to enable optional support for WOWL. This feature is not supported by the legacy Exynos4 based boards and leads to WLAN disfunction after system suspend/resume cycle. Fix this by annotating SDIO host used by WLAN chip with 'cap-power-off-card' property, which should have been there from the beginning. Fixes: 8620cc2f99b7 ("ARM: dts: exynos: Add devicetree file for the Galaxy S2") Signed-off-by: Marek Szyprowski Link: https://patch.msgid.link/20251126102618.3103517-3-m.szyprowski@samsung.com Signed-off-by: Krzysztof Kozlowski Signed-off-by: Sasha Levin --- arch/arm/boot/dts/samsung/exynos4210-i9100.dts | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/boot/dts/samsung/exynos4210-i9100.dts b/arch/arm/boot/dts/samsung/exynos4210-i9100.dts index df229fb8a16be..8a635bee59fa9 100644 --- a/arch/arm/boot/dts/samsung/exynos4210-i9100.dts +++ b/arch/arm/boot/dts/samsung/exynos4210-i9100.dts @@ -853,6 +853,7 @@ #size-cells = <0>; non-removable; + cap-power-off-card; bus-width = <4>; mmc-pwrseq = <&wlan_pwrseq>; vmmc-supply = <&vtf_reg>; From b4eb208dee57dc51d3a7002334b3dfb23cf2ce16 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Wed, 26 Nov 2025 11:26:17 +0100 Subject: [PATCH 0852/2333] ARM: dts: samsung: exynos4210-trats: turn off SDIO WLAN chip during system suspend [ Upstream commit 97cc9c346b2c9cde075b9420fc172137d2427711 ] Commit 8c3170628a9c ("wifi: brcmfmac: keep power during suspend if board requires it") changed default behavior of the BRCMFMAC driver, which now keeps SDIO card powered during system suspend to enable optional support for WOWL. This feature is not supported by the legacy Exynos4 based boards and leads to WLAN disfunction after system suspend/resume cycle. Fix this by annotating SDIO host used by WLAN chip with 'cap-power-off-card' property, which should have been there from the beginning. Fixes: a19f6efc01df ("ARM: dts: exynos: Enable WLAN support for the Trats board") Signed-off-by: Marek Szyprowski Link: https://patch.msgid.link/20251126102618.3103517-4-m.szyprowski@samsung.com Signed-off-by: Krzysztof Kozlowski Signed-off-by: Sasha Levin --- arch/arm/boot/dts/samsung/exynos4210-trats.dts | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/boot/dts/samsung/exynos4210-trats.dts b/arch/arm/boot/dts/samsung/exynos4210-trats.dts index 95e0e01b6ff6b..6bd902cb8f4ad 100644 --- a/arch/arm/boot/dts/samsung/exynos4210-trats.dts +++ b/arch/arm/boot/dts/samsung/exynos4210-trats.dts @@ -518,6 +518,7 @@ #size-cells = <0>; non-removable; + cap-power-off-card; bus-width = <4>; mmc-pwrseq = <&wlan_pwrseq>; vmmc-supply = <&tflash_reg>; From ed3cc640b4f1662e7b4a8941bead6779f2d48cb3 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Wed, 26 Nov 2025 11:26:18 +0100 Subject: [PATCH 0853/2333] ARM: dts: samsung: exynos4412-midas: turn off SDIO WLAN chip during system suspend [ Upstream commit 2ff147fdfa99b8cbb8c2833e685fde7c42580ae6 ] Commit 8c3170628a9c ("wifi: brcmfmac: keep power during suspend if board requires it") changed default behavior of the BRCMFMAC driver, which now keeps SDIO card powered during system suspend to enable optional support for WOWL. This feature is not supported by the legacy Exynos4 based boards and leads to WLAN disfunction after system suspend/resume cycle. Fix this by annotating SDIO host used by WLAN chip with 'cap-power-off-card' property, which should have been there from the beginning. Fixes: f77cbb9a3e5d ("ARM: dts: exynos: Add bcm4334 device node to Trats2") Signed-off-by: Marek Szyprowski Link: https://patch.msgid.link/20251126102618.3103517-5-m.szyprowski@samsung.com Signed-off-by: Krzysztof Kozlowski Signed-off-by: Sasha Levin --- arch/arm/boot/dts/samsung/exynos4412-midas.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/boot/dts/samsung/exynos4412-midas.dtsi b/arch/arm/boot/dts/samsung/exynos4412-midas.dtsi index 05ddddb565ee3..48245b1665a69 100644 --- a/arch/arm/boot/dts/samsung/exynos4412-midas.dtsi +++ b/arch/arm/boot/dts/samsung/exynos4412-midas.dtsi @@ -1440,6 +1440,7 @@ #address-cells = <1>; #size-cells = <0>; non-removable; + cap-power-off-card; bus-width = <4>; mmc-pwrseq = <&wlan_pwrseq>; From 64099b5c0aeb70bc7cd5556eb7f59c5b4a5010bf Mon Sep 17 00:00:00 2001 From: sparkhuang Date: Thu, 27 Nov 2025 10:57:16 +0800 Subject: [PATCH 0854/2333] regulator: core: Protect regulator_supply_alias_list with regulator_list_mutex [ Upstream commit 0cc15a10c3b4ab14cd71b779fd5c9ca0cb2bc30d ] regulator_supply_alias_list was accessed without any locking in regulator_supply_alias(), regulator_register_supply_alias(), and regulator_unregister_supply_alias(). Concurrent registration, unregistration and lookups can race, leading to: 1 use-after-free if an alias entry is removed while being read, 2 duplicate entries when two threads register the same alias, 3 inconsistent alias mappings observed by consumers. Protect all traversals, insertions and deletions on regulator_supply_alias_list with the existing regulator_list_mutex. Fixes: a06ccd9c3785f ("regulator: core: Add ability to create a lookup alias for supply") Signed-off-by: sparkhuang Reviewed-by: Charles Keepax Link: https://patch.msgid.link/20251127025716.5440-1-huangshaobo3@xiaomi.com Signed-off-by: Mark Brown Signed-off-by: Sasha Levin --- drivers/regulator/core.c | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index fc93612f4ec0c..b38b087eccfd7 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -1947,6 +1947,7 @@ static void regulator_supply_alias(struct device **dev, const char **supply) { struct regulator_supply_alias *map; + mutex_lock(®ulator_list_mutex); map = regulator_find_supply_alias(*dev, *supply); if (map) { dev_dbg(*dev, "Mapping supply %s to %s,%s\n", @@ -1955,6 +1956,7 @@ static void regulator_supply_alias(struct device **dev, const char **supply) *dev = map->alias_dev; *supply = map->alias_supply; } + mutex_unlock(®ulator_list_mutex); } static int regulator_match(struct device *dev, const void *data) @@ -2497,22 +2499,26 @@ int regulator_register_supply_alias(struct device *dev, const char *id, const char *alias_id) { struct regulator_supply_alias *map; + struct regulator_supply_alias *new_map; - map = regulator_find_supply_alias(dev, id); - if (map) - return -EEXIST; - - map = kzalloc(sizeof(struct regulator_supply_alias), GFP_KERNEL); - if (!map) + new_map = kzalloc(sizeof(struct regulator_supply_alias), GFP_KERNEL); + if (!new_map) return -ENOMEM; - map->src_dev = dev; - map->src_supply = id; - map->alias_dev = alias_dev; - map->alias_supply = alias_id; - - list_add(&map->list, ®ulator_supply_alias_list); + mutex_lock(®ulator_list_mutex); + map = regulator_find_supply_alias(dev, id); + if (map) { + mutex_unlock(®ulator_list_mutex); + kfree(new_map); + return -EEXIST; + } + new_map->src_dev = dev; + new_map->src_supply = id; + new_map->alias_dev = alias_dev; + new_map->alias_supply = alias_id; + list_add(&new_map->list, ®ulator_supply_alias_list); + mutex_unlock(®ulator_list_mutex); pr_info("Adding alias for supply %s,%s -> %s,%s\n", id, dev_name(dev), alias_id, dev_name(alias_dev)); @@ -2532,11 +2538,13 @@ void regulator_unregister_supply_alias(struct device *dev, const char *id) { struct regulator_supply_alias *map; + mutex_lock(®ulator_list_mutex); map = regulator_find_supply_alias(dev, id); if (map) { list_del(&map->list); kfree(map); } + mutex_unlock(®ulator_list_mutex); } EXPORT_SYMBOL_GPL(regulator_unregister_supply_alias); From f2888bfb900332d5a06f9387a4af537da652d2ab Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Thu, 27 Nov 2025 18:00:42 +0800 Subject: [PATCH 0855/2333] arm64: dts: mediatek: mt8195: Fix address range for JPEG decoder core 1 [ Upstream commit ce48af13e6381772cc27676be63a6d9176c14a49 ] The base address of JPEG decoder core 1 should start at 0x10000, and have a size of 0x10000, i.e. it is right after core 0. Instead the core has the same base address as core 0, and with a crazy large size. This looks like a mixup of address and size cells when the ranges were converted. This causes the kernel to fail to register the second core due to sysfs name conflicts: sysfs: cannot create duplicate filename '/devices/platform/soc/soc:jpeg-decoder@1a040000/1a040000.jpgdec' Fix up the address range. Fixes: a9eac43d039f ("arm64: dts: mediatek: mt8195: Fix ranges for jpeg enc/decoder nodes") Signed-off-by: Chen-Yu Tsai Acked-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20251127100044.612825-1-wenst@chromium.org Signed-off-by: Arnd Bergmann Signed-off-by: Sasha Levin --- arch/arm64/boot/dts/mediatek/mt8195.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/mediatek/mt8195.dtsi b/arch/arm64/boot/dts/mediatek/mt8195.dtsi index ec452d6570314..c7adafaa83288 100644 --- a/arch/arm64/boot/dts/mediatek/mt8195.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt8195.dtsi @@ -3067,7 +3067,7 @@ jpgdec@0,10000 { compatible = "mediatek,mt8195-jpgdec-hw"; - reg = <0 0 0x10000 0x10000>;/* JPGDEC_C1 */ + reg = <0 0x10000 0 0x10000>;/* JPGDEC_C1 */ iommus = <&iommu_vdo M4U_PORT_L19_JPGDEC_WDMA0>, <&iommu_vdo M4U_PORT_L19_JPGDEC_BSDMA0>, <&iommu_vdo M4U_PORT_L19_JPGDEC_WDMA1>, From 3c0493f81dfac8138f5a9a8c23a97671526b78ce Mon Sep 17 00:00:00 2001 From: Ilias Stamatis Date: Mon, 24 Nov 2025 16:53:49 +0000 Subject: [PATCH 0856/2333] Reinstate "resource: avoid unnecessary lookups in find_next_iomem_res()" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 6fb3acdebf65a72df0a95f9fd2c901ff2bc9a3a2 ] Commit 97523a4edb7b ("kernel/resource: remove first_lvl / siblings_only logic") removed an optimization introduced by commit 756398750e11 ("resource: avoid unnecessary lookups in find_next_iomem_res()"). That was not called out in the message of the first commit explicitly so it's not entirely clear whether removing the optimization happened inadvertently or not. As the original commit message of the optimization explains there is no point considering the children of a subtree in find_next_iomem_res() if the top level range does not match. Reinstating the optimization results in performance improvements in systems where /proc/iomem is ~5k lines long. Calling mmap() on /dev/mem in such platforms takes 700-1500μs without the optimisation and 10-50μs with the optimisation. Note that even though commit 97523a4edb7b removed the 'sibling_only' parameter from next_resource(), newer kernels have basically reinstated it under the name 'skip_children'. Link: https://lore.kernel.org/all/20251124165349.3377826-1-ilstam@amazon.com/T/#u Fixes: 97523a4edb7b ("kernel/resource: remove first_lvl / siblings_only logic") Signed-off-by: Ilias Stamatis Acked-by: David Hildenbrand (Red Hat) Cc: Andriy Shevchenko Cc: Baoquan He Cc: "Huang, Ying" Cc: Nadav Amit Signed-off-by: Andrew Morton Signed-off-by: Sasha Levin --- kernel/resource.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/kernel/resource.c b/kernel/resource.c index b9fa2a4ce089c..e4e9bac12e6e1 100644 --- a/kernel/resource.c +++ b/kernel/resource.c @@ -341,6 +341,8 @@ static int find_next_iomem_res(resource_size_t start, resource_size_t end, unsigned long flags, unsigned long desc, struct resource *res) { + /* Skip children until we find a top level range that matches */ + bool skip_children = true; struct resource *p; if (!res) @@ -351,7 +353,7 @@ static int find_next_iomem_res(resource_size_t start, resource_size_t end, read_lock(&resource_lock); - for_each_resource(&iomem_resource, p, false) { + for_each_resource(&iomem_resource, p, skip_children) { /* If we passed the resource we are looking for, stop */ if (p->start > end) { p = NULL; @@ -362,6 +364,12 @@ static int find_next_iomem_res(resource_size_t start, resource_size_t end, if (p->end < start) continue; + /* + * We found a top level range that matches what we are looking + * for. Time to start checking children too. + */ + skip_children = false; + /* Found a match, break */ if (is_type_match(p, flags, desc)) break; From 87a453f31c636de84420fcce68659abd37d269fd Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 27 Nov 2025 23:26:22 +0000 Subject: [PATCH 0857/2333] netfilter: flowtable: check for maximum number of encapsulations in bridge vlan [ Upstream commit 634f3853cc98d73bdec8918010ee29b06981583e ] Add a sanity check to skip path discovery if the maximum number of encapsulation is reached. While at it, check for underflow too. Fixes: 26267bf9bb57 ("netfilter: flowtable: bridge vlan hardware offload and switchdev") Signed-off-by: Pablo Neira Ayuso Signed-off-by: Sasha Levin --- net/netfilter/nft_flow_offload.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/net/netfilter/nft_flow_offload.c b/net/netfilter/nft_flow_offload.c index 14dd1c0698c3c..e95e5f59a3d6a 100644 --- a/net/netfilter/nft_flow_offload.c +++ b/net/netfilter/nft_flow_offload.c @@ -141,12 +141,19 @@ static void nft_dev_path_info(const struct net_device_path_stack *stack, info->ingress_vlans |= BIT(info->num_encaps - 1); break; case DEV_PATH_BR_VLAN_TAG: + if (info->num_encaps >= NF_FLOW_TABLE_ENCAP_MAX) { + info->indev = NULL; + break; + } info->encap[info->num_encaps].id = path->bridge.vlan_id; info->encap[info->num_encaps].proto = path->bridge.vlan_proto; info->num_encaps++; break; case DEV_PATH_BR_VLAN_UNTAG: - info->num_encaps--; + if (WARN_ON_ONCE(info->num_encaps-- == 0)) { + info->indev = NULL; + break; + } break; case DEV_PATH_BR_VLAN_KEEP: break; From f6904ed15ed1a188543057e3cb0d02daa80edfc9 Mon Sep 17 00:00:00 2001 From: Fernando Fernandez Mancera Date: Fri, 21 Nov 2025 01:14:30 +0100 Subject: [PATCH 0858/2333] netfilter: nf_conncount: rework API to use sk_buff directly [ Upstream commit be102eb6a0e7c03db00e50540622f4e43b2d2844 ] When using nf_conncount infrastructure for non-confirmed connections a duplicated track is possible due to an optimization introduced since commit d265929930e2 ("netfilter: nf_conncount: reduce unnecessary GC"). In order to fix this introduce a new conncount API that receives directly an sk_buff struct. It fetches the tuple and zone and the corresponding ct from it. It comes with both existing conncount variants nf_conncount_count_skb() and nf_conncount_add_skb(). In addition remove the old API and adjust all the users to use the new one. This way, for each sk_buff struct it is possible to check if there is a ct present and already confirmed. If so, skip the add operation. Fixes: d265929930e2 ("netfilter: nf_conncount: reduce unnecessary GC") Signed-off-by: Fernando Fernandez Mancera Signed-off-by: Pablo Neira Ayuso Signed-off-by: Sasha Levin --- include/net/netfilter/nf_conntrack_count.h | 17 +- net/netfilter/nf_conncount.c | 177 ++++++++++++++------- net/netfilter/nft_connlimit.c | 21 +-- net/netfilter/xt_connlimit.c | 14 +- net/openvswitch/conntrack.c | 16 +- 5 files changed, 142 insertions(+), 103 deletions(-) diff --git a/include/net/netfilter/nf_conntrack_count.h b/include/net/netfilter/nf_conntrack_count.h index 1b58b5b91ff6a..52a06de41aa0f 100644 --- a/include/net/netfilter/nf_conntrack_count.h +++ b/include/net/netfilter/nf_conntrack_count.h @@ -18,15 +18,14 @@ struct nf_conncount_list { struct nf_conncount_data *nf_conncount_init(struct net *net, unsigned int keylen); void nf_conncount_destroy(struct net *net, struct nf_conncount_data *data); -unsigned int nf_conncount_count(struct net *net, - struct nf_conncount_data *data, - const u32 *key, - const struct nf_conntrack_tuple *tuple, - const struct nf_conntrack_zone *zone); - -int nf_conncount_add(struct net *net, struct nf_conncount_list *list, - const struct nf_conntrack_tuple *tuple, - const struct nf_conntrack_zone *zone); +unsigned int nf_conncount_count_skb(struct net *net, + const struct sk_buff *skb, + u16 l3num, + struct nf_conncount_data *data, + const u32 *key); + +int nf_conncount_add_skb(struct net *net, const struct sk_buff *skb, + u16 l3num, struct nf_conncount_list *list); void nf_conncount_list_init(struct nf_conncount_list *list); diff --git a/net/netfilter/nf_conncount.c b/net/netfilter/nf_conncount.c index 913ede2f57f9a..0ffc5ff78a714 100644 --- a/net/netfilter/nf_conncount.c +++ b/net/netfilter/nf_conncount.c @@ -122,15 +122,65 @@ find_or_evict(struct net *net, struct nf_conncount_list *list, return ERR_PTR(-EAGAIN); } +static bool get_ct_or_tuple_from_skb(struct net *net, + const struct sk_buff *skb, + u16 l3num, + struct nf_conn **ct, + struct nf_conntrack_tuple *tuple, + const struct nf_conntrack_zone **zone, + bool *refcounted) +{ + const struct nf_conntrack_tuple_hash *h; + enum ip_conntrack_info ctinfo; + struct nf_conn *found_ct; + + found_ct = nf_ct_get(skb, &ctinfo); + if (found_ct && !nf_ct_is_template(found_ct)) { + *tuple = found_ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple; + *zone = nf_ct_zone(found_ct); + *ct = found_ct; + return true; + } + + if (!nf_ct_get_tuplepr(skb, skb_network_offset(skb), l3num, net, tuple)) + return false; + + if (found_ct) + *zone = nf_ct_zone(found_ct); + + h = nf_conntrack_find_get(net, *zone, tuple); + if (!h) + return true; + + found_ct = nf_ct_tuplehash_to_ctrack(h); + *refcounted = true; + *ct = found_ct; + + return true; +} + static int __nf_conncount_add(struct net *net, - struct nf_conncount_list *list, - const struct nf_conntrack_tuple *tuple, - const struct nf_conntrack_zone *zone) + const struct sk_buff *skb, + u16 l3num, + struct nf_conncount_list *list) { + const struct nf_conntrack_zone *zone = &nf_ct_zone_dflt; const struct nf_conntrack_tuple_hash *found; struct nf_conncount_tuple *conn, *conn_n; + struct nf_conntrack_tuple tuple; + struct nf_conn *ct = NULL; struct nf_conn *found_ct; unsigned int collect = 0; + bool refcounted = false; + + if (!get_ct_or_tuple_from_skb(net, skb, l3num, &ct, &tuple, &zone, &refcounted)) + return -ENOENT; + + if (ct && nf_ct_is_confirmed(ct)) { + if (refcounted) + nf_ct_put(ct); + return 0; + } if ((u32)jiffies == list->last_gc) goto add_new_node; @@ -144,10 +194,10 @@ static int __nf_conncount_add(struct net *net, if (IS_ERR(found)) { /* Not found, but might be about to be confirmed */ if (PTR_ERR(found) == -EAGAIN) { - if (nf_ct_tuple_equal(&conn->tuple, tuple) && + if (nf_ct_tuple_equal(&conn->tuple, &tuple) && nf_ct_zone_id(&conn->zone, conn->zone.dir) == nf_ct_zone_id(zone, zone->dir)) - return 0; /* already exists */ + goto out_put; /* already exists */ } else { collect++; } @@ -156,7 +206,7 @@ static int __nf_conncount_add(struct net *net, found_ct = nf_ct_tuplehash_to_ctrack(found); - if (nf_ct_tuple_equal(&conn->tuple, tuple) && + if (nf_ct_tuple_equal(&conn->tuple, &tuple) && nf_ct_zone_equal(found_ct, zone, zone->dir)) { /* * We should not see tuples twice unless someone hooks @@ -165,7 +215,7 @@ static int __nf_conncount_add(struct net *net, * Attempt to avoid a re-add in this case. */ nf_ct_put(found_ct); - return 0; + goto out_put; } else if (already_closed(found_ct)) { /* * we do not care about connections which are @@ -188,31 +238,35 @@ static int __nf_conncount_add(struct net *net, if (conn == NULL) return -ENOMEM; - conn->tuple = *tuple; + conn->tuple = tuple; conn->zone = *zone; conn->cpu = raw_smp_processor_id(); conn->jiffies32 = (u32)jiffies; list_add_tail(&conn->node, &list->head); list->count++; list->last_gc = (u32)jiffies; + +out_put: + if (refcounted) + nf_ct_put(ct); return 0; } -int nf_conncount_add(struct net *net, - struct nf_conncount_list *list, - const struct nf_conntrack_tuple *tuple, - const struct nf_conntrack_zone *zone) +int nf_conncount_add_skb(struct net *net, + const struct sk_buff *skb, + u16 l3num, + struct nf_conncount_list *list) { int ret; /* check the saved connections */ spin_lock_bh(&list->list_lock); - ret = __nf_conncount_add(net, list, tuple, zone); + ret = __nf_conncount_add(net, skb, l3num, list); spin_unlock_bh(&list->list_lock); return ret; } -EXPORT_SYMBOL_GPL(nf_conncount_add); +EXPORT_SYMBOL_GPL(nf_conncount_add_skb); void nf_conncount_list_init(struct nf_conncount_list *list) { @@ -309,19 +363,22 @@ static void schedule_gc_worker(struct nf_conncount_data *data, int tree) static unsigned int insert_tree(struct net *net, + const struct sk_buff *skb, + u16 l3num, struct nf_conncount_data *data, struct rb_root *root, unsigned int hash, - const u32 *key, - const struct nf_conntrack_tuple *tuple, - const struct nf_conntrack_zone *zone) + const u32 *key) { struct nf_conncount_rb *gc_nodes[CONNCOUNT_GC_MAX_NODES]; + const struct nf_conntrack_zone *zone = &nf_ct_zone_dflt; + bool do_gc = true, refcounted = false; + unsigned int count = 0, gc_count = 0; struct rb_node **rbnode, *parent; - struct nf_conncount_rb *rbconn; + struct nf_conntrack_tuple tuple; struct nf_conncount_tuple *conn; - unsigned int count = 0, gc_count = 0; - bool do_gc = true; + struct nf_conncount_rb *rbconn; + struct nf_conn *ct = NULL; spin_lock_bh(&nf_conncount_locks[hash]); restart: @@ -340,7 +397,7 @@ insert_tree(struct net *net, } else { int ret; - ret = nf_conncount_add(net, &rbconn->list, tuple, zone); + ret = nf_conncount_add_skb(net, skb, l3num, &rbconn->list); if (ret) count = 0; /* hotdrop */ else @@ -364,30 +421,35 @@ insert_tree(struct net *net, goto restart; } - /* expected case: match, insert new node */ - rbconn = kmem_cache_alloc(conncount_rb_cachep, GFP_ATOMIC); - if (rbconn == NULL) - goto out_unlock; + if (get_ct_or_tuple_from_skb(net, skb, l3num, &ct, &tuple, &zone, &refcounted)) { + /* expected case: match, insert new node */ + rbconn = kmem_cache_alloc(conncount_rb_cachep, GFP_ATOMIC); + if (rbconn == NULL) + goto out_unlock; - conn = kmem_cache_alloc(conncount_conn_cachep, GFP_ATOMIC); - if (conn == NULL) { - kmem_cache_free(conncount_rb_cachep, rbconn); - goto out_unlock; - } + conn = kmem_cache_alloc(conncount_conn_cachep, GFP_ATOMIC); + if (conn == NULL) { + kmem_cache_free(conncount_rb_cachep, rbconn); + goto out_unlock; + } - conn->tuple = *tuple; - conn->zone = *zone; - conn->cpu = raw_smp_processor_id(); - conn->jiffies32 = (u32)jiffies; - memcpy(rbconn->key, key, sizeof(u32) * data->keylen); + conn->tuple = tuple; + conn->zone = *zone; + conn->cpu = raw_smp_processor_id(); + conn->jiffies32 = (u32)jiffies; + memcpy(rbconn->key, key, sizeof(u32) * data->keylen); + + nf_conncount_list_init(&rbconn->list); + list_add(&conn->node, &rbconn->list.head); + count = 1; + rbconn->list.count = count; - nf_conncount_list_init(&rbconn->list); - list_add(&conn->node, &rbconn->list.head); - count = 1; - rbconn->list.count = count; + rb_link_node_rcu(&rbconn->node, parent, rbnode); + rb_insert_color(&rbconn->node, root); - rb_link_node_rcu(&rbconn->node, parent, rbnode); - rb_insert_color(&rbconn->node, root); + if (refcounted) + nf_ct_put(ct); + } out_unlock: spin_unlock_bh(&nf_conncount_locks[hash]); return count; @@ -395,10 +457,10 @@ insert_tree(struct net *net, static unsigned int count_tree(struct net *net, + const struct sk_buff *skb, + u16 l3num, struct nf_conncount_data *data, - const u32 *key, - const struct nf_conntrack_tuple *tuple, - const struct nf_conntrack_zone *zone) + const u32 *key) { struct rb_root *root; struct rb_node *parent; @@ -422,7 +484,7 @@ count_tree(struct net *net, } else { int ret; - if (!tuple) { + if (!skb) { nf_conncount_gc_list(net, &rbconn->list); return rbconn->list.count; } @@ -437,7 +499,7 @@ count_tree(struct net *net, } /* same source network -> be counted! */ - ret = __nf_conncount_add(net, &rbconn->list, tuple, zone); + ret = __nf_conncount_add(net, skb, l3num, &rbconn->list); spin_unlock_bh(&rbconn->list.list_lock); if (ret) return 0; /* hotdrop */ @@ -446,10 +508,10 @@ count_tree(struct net *net, } } - if (!tuple) + if (!skb) return 0; - return insert_tree(net, data, root, hash, key, tuple, zone); + return insert_tree(net, skb, l3num, data, root, hash, key); } static void tree_gc_worker(struct work_struct *work) @@ -511,18 +573,19 @@ static void tree_gc_worker(struct work_struct *work) } /* Count and return number of conntrack entries in 'net' with particular 'key'. - * If 'tuple' is not null, insert it into the accounting data structure. - * Call with RCU read lock. + * If 'skb' is not null, insert the corresponding tuple into the accounting + * data structure. Call with RCU read lock. */ -unsigned int nf_conncount_count(struct net *net, - struct nf_conncount_data *data, - const u32 *key, - const struct nf_conntrack_tuple *tuple, - const struct nf_conntrack_zone *zone) +unsigned int nf_conncount_count_skb(struct net *net, + const struct sk_buff *skb, + u16 l3num, + struct nf_conncount_data *data, + const u32 *key) { - return count_tree(net, data, key, tuple, zone); + return count_tree(net, skb, l3num, data, key); + } -EXPORT_SYMBOL_GPL(nf_conncount_count); +EXPORT_SYMBOL_GPL(nf_conncount_count_skb); struct nf_conncount_data *nf_conncount_init(struct net *net, unsigned int keylen) { diff --git a/net/netfilter/nft_connlimit.c b/net/netfilter/nft_connlimit.c index fc35a11cdca20..5df7134131d29 100644 --- a/net/netfilter/nft_connlimit.c +++ b/net/netfilter/nft_connlimit.c @@ -24,26 +24,11 @@ static inline void nft_connlimit_do_eval(struct nft_connlimit *priv, const struct nft_pktinfo *pkt, const struct nft_set_ext *ext) { - const struct nf_conntrack_zone *zone = &nf_ct_zone_dflt; - const struct nf_conntrack_tuple *tuple_ptr; - struct nf_conntrack_tuple tuple; - enum ip_conntrack_info ctinfo; - const struct nf_conn *ct; unsigned int count; + int err; - tuple_ptr = &tuple; - - ct = nf_ct_get(pkt->skb, &ctinfo); - if (ct != NULL) { - tuple_ptr = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple; - zone = nf_ct_zone(ct); - } else if (!nf_ct_get_tuplepr(pkt->skb, skb_network_offset(pkt->skb), - nft_pf(pkt), nft_net(pkt), &tuple)) { - regs->verdict.code = NF_DROP; - return; - } - - if (nf_conncount_add(nft_net(pkt), priv->list, tuple_ptr, zone)) { + err = nf_conncount_add_skb(nft_net(pkt), pkt->skb, nft_pf(pkt), priv->list); + if (err) { regs->verdict.code = NF_DROP; return; } diff --git a/net/netfilter/xt_connlimit.c b/net/netfilter/xt_connlimit.c index 0189f8b6b0bd1..848287ab79cfb 100644 --- a/net/netfilter/xt_connlimit.c +++ b/net/netfilter/xt_connlimit.c @@ -31,8 +31,6 @@ connlimit_mt(const struct sk_buff *skb, struct xt_action_param *par) { struct net *net = xt_net(par); const struct xt_connlimit_info *info = par->matchinfo; - struct nf_conntrack_tuple tuple; - const struct nf_conntrack_tuple *tuple_ptr = &tuple; const struct nf_conntrack_zone *zone = &nf_ct_zone_dflt; enum ip_conntrack_info ctinfo; const struct nf_conn *ct; @@ -40,13 +38,8 @@ connlimit_mt(const struct sk_buff *skb, struct xt_action_param *par) u32 key[5]; ct = nf_ct_get(skb, &ctinfo); - if (ct != NULL) { - tuple_ptr = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple; + if (ct) zone = nf_ct_zone(ct); - } else if (!nf_ct_get_tuplepr(skb, skb_network_offset(skb), - xt_family(par), net, &tuple)) { - goto hotdrop; - } if (xt_family(par) == NFPROTO_IPV6) { const struct ipv6hdr *iph = ipv6_hdr(skb); @@ -69,10 +62,9 @@ connlimit_mt(const struct sk_buff *skb, struct xt_action_param *par) key[1] = zone->id; } - connections = nf_conncount_count(net, info->data, key, tuple_ptr, - zone); + connections = nf_conncount_count_skb(net, skb, xt_family(par), info->data, key); if (connections == 0) - /* kmalloc failed, drop it entirely */ + /* kmalloc failed or tuple couldn't be found, drop it entirely */ goto hotdrop; return (connections > info->limit) ^ !!(info->flags & XT_CONNLIMIT_INVERT); diff --git a/net/openvswitch/conntrack.c b/net/openvswitch/conntrack.c index e573e92213029..a0811e1fba656 100644 --- a/net/openvswitch/conntrack.c +++ b/net/openvswitch/conntrack.c @@ -928,8 +928,8 @@ static u32 ct_limit_get(const struct ovs_ct_limit_info *info, u16 zone) } static int ovs_ct_check_limit(struct net *net, - const struct ovs_conntrack_info *info, - const struct nf_conntrack_tuple *tuple) + const struct sk_buff *skb, + const struct ovs_conntrack_info *info) { struct ovs_net *ovs_net = net_generic(net, ovs_net_id); const struct ovs_ct_limit_info *ct_limit_info = ovs_net->ct_limit_info; @@ -942,8 +942,9 @@ static int ovs_ct_check_limit(struct net *net, if (per_zone_limit == OVS_CT_LIMIT_UNLIMITED) return 0; - connections = nf_conncount_count(net, ct_limit_info->data, - &conncount_key, tuple, &info->zone); + connections = nf_conncount_count_skb(net, skb, info->family, + ct_limit_info->data, + &conncount_key); if (connections > per_zone_limit) return -ENOMEM; @@ -972,8 +973,7 @@ static int ovs_ct_commit(struct net *net, struct sw_flow_key *key, #if IS_ENABLED(CONFIG_NETFILTER_CONNCOUNT) if (static_branch_unlikely(&ovs_ct_limit_enabled)) { if (!nf_ct_is_confirmed(ct)) { - err = ovs_ct_check_limit(net, info, - &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); + err = ovs_ct_check_limit(net, skb, info); if (err) { net_warn_ratelimited("openvswitch: zone: %u " "exceeds conntrack limit\n", @@ -1770,8 +1770,8 @@ static int __ovs_ct_limit_get_zone_limit(struct net *net, zone_limit.limit = limit; nf_ct_zone_init(&ct_zone, zone_id, NF_CT_DEFAULT_ZONE_DIR, 0); - zone_limit.count = nf_conncount_count(net, data, &conncount_key, NULL, - &ct_zone); + zone_limit.count = nf_conncount_count_skb(net, NULL, 0, data, + &conncount_key); return nla_put_nohdr(reply, sizeof(zone_limit), &zone_limit); } From 77ea3d8ac3d3d59b5ac9ad639e4ba107c0f2ff1e Mon Sep 17 00:00:00 2001 From: Fernando Fernandez Mancera Date: Fri, 21 Nov 2025 01:14:32 +0100 Subject: [PATCH 0859/2333] netfilter: nft_connlimit: update the count if add was skipped [ Upstream commit 69894e5b4c5e28cda5f32af33d4a92b7a4b93b0e ] Connlimit expression can be used for all kind of packets and not only for packets with connection state new. See this ruleset as example: table ip filter { chain input { type filter hook input priority filter; policy accept; tcp dport 22 ct count over 4 counter } } Currently, if the connection count goes over the limit the counter will count the packets. When a connection is closed, the connection count won't decrement as it should because it is only updated for new connections due to an optimization on __nf_conncount_add() that prevents updating the list if the connection is duplicated. To solve this problem, check whether the connection was skipped and if so, update the list. Adjust count_tree() too so the same fix is applied for xt_connlimit. Fixes: 976afca1ceba ("netfilter: nf_conncount: Early exit in nf_conncount_lookup() and cleanup") Closes: https://lore.kernel.org/netfilter/trinity-85c72a88-d762-46c3-be97-36f10e5d9796-1761173693813@3c-app-mailcom-bs12/ Signed-off-by: Fernando Fernandez Mancera Signed-off-by: Pablo Neira Ayuso Signed-off-by: Sasha Levin --- net/netfilter/nf_conncount.c | 12 ++++++++---- net/netfilter/nft_connlimit.c | 13 +++++++++++-- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/net/netfilter/nf_conncount.c b/net/netfilter/nf_conncount.c index 0ffc5ff78a714..b84cfb5616df4 100644 --- a/net/netfilter/nf_conncount.c +++ b/net/netfilter/nf_conncount.c @@ -179,7 +179,7 @@ static int __nf_conncount_add(struct net *net, if (ct && nf_ct_is_confirmed(ct)) { if (refcounted) nf_ct_put(ct); - return 0; + return -EEXIST; } if ((u32)jiffies == list->last_gc) @@ -398,7 +398,7 @@ insert_tree(struct net *net, int ret; ret = nf_conncount_add_skb(net, skb, l3num, &rbconn->list); - if (ret) + if (ret && ret != -EEXIST) count = 0; /* hotdrop */ else count = rbconn->list.count; @@ -501,10 +501,14 @@ count_tree(struct net *net, /* same source network -> be counted! */ ret = __nf_conncount_add(net, skb, l3num, &rbconn->list); spin_unlock_bh(&rbconn->list.list_lock); - if (ret) + if (ret && ret != -EEXIST) { return 0; /* hotdrop */ - else + } else { + /* -EEXIST means add was skipped, update the list */ + if (ret == -EEXIST) + nf_conncount_gc_list(net, &rbconn->list); return rbconn->list.count; + } } } diff --git a/net/netfilter/nft_connlimit.c b/net/netfilter/nft_connlimit.c index 5df7134131d29..d4964087bbc5e 100644 --- a/net/netfilter/nft_connlimit.c +++ b/net/netfilter/nft_connlimit.c @@ -29,8 +29,17 @@ static inline void nft_connlimit_do_eval(struct nft_connlimit *priv, err = nf_conncount_add_skb(nft_net(pkt), pkt->skb, nft_pf(pkt), priv->list); if (err) { - regs->verdict.code = NF_DROP; - return; + if (err == -EEXIST) { + /* Call gc to update the list count if any connection has + * been closed already. This is useful for softlimit + * connections like limiting bandwidth based on a number + * of open connections. + */ + nf_conncount_gc_list(nft_net(pkt), priv->list); + } else { + regs->verdict.code = NF_DROP; + return; + } } count = READ_ONCE(priv->list->count); From 6d080f810ffd6b8e002ce5bee8b9c551ca2535c2 Mon Sep 17 00:00:00 2001 From: Michal Schmidt Date: Wed, 26 Nov 2025 10:48:49 +0100 Subject: [PATCH 0860/2333] iavf: Implement settime64 with -EOPNOTSUPP [ Upstream commit 1e43ebcd5152b3e681a334cc6542fb21770c3a2e ] ptp_clock_settime() assumes every ptp_clock has implemented settime64(). Stub it with -EOPNOTSUPP to prevent a NULL dereference. The fix is similar to commit 329d050bbe63 ("gve: Implement settime64 with -EOPNOTSUPP"). Fixes: d734223b2f0d ("iavf: add initial framework for registering PTP clock") Signed-off-by: Michal Schmidt Reviewed-by: Aleksandr Loktionov Reviewed-by: Tim Hostetler Link: https://patch.msgid.link/20251126094850.2842557-1-mschmidt@redhat.com Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- drivers/net/ethernet/intel/iavf/iavf_ptp.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/net/ethernet/intel/iavf/iavf_ptp.c b/drivers/net/ethernet/intel/iavf/iavf_ptp.c index b4d5eda2e84fc..9cbd8c1540318 100644 --- a/drivers/net/ethernet/intel/iavf/iavf_ptp.c +++ b/drivers/net/ethernet/intel/iavf/iavf_ptp.c @@ -252,6 +252,12 @@ static int iavf_ptp_gettimex64(struct ptp_clock_info *info, return iavf_read_phc_indirect(adapter, ts, sts); } +static int iavf_ptp_settime64(struct ptp_clock_info *info, + const struct timespec64 *ts) +{ + return -EOPNOTSUPP; +} + /** * iavf_ptp_cache_phc_time - Cache PHC time for performing timestamp extension * @adapter: private adapter structure @@ -320,6 +326,7 @@ static int iavf_ptp_register_clock(struct iavf_adapter *adapter) KBUILD_MODNAME, dev_name(dev)); ptp_info->owner = THIS_MODULE; ptp_info->gettimex64 = iavf_ptp_gettimex64; + ptp_info->settime64 = iavf_ptp_settime64; ptp_info->do_aux_work = iavf_ptp_do_aux_work; clock = ptp_clock_register(ptp_info, dev); From 4ac26aafdc8c7271414e2e7c0b2cb266a26591bc Mon Sep 17 00:00:00 2001 From: Antoine Tenart Date: Wed, 26 Nov 2025 11:26:25 +0100 Subject: [PATCH 0861/2333] net: vxlan: prevent NULL deref in vxlan_xmit_one [ Upstream commit 1f73a56f986005f0bc64ed23873930e2ee4f5911 ] Neither sock4 nor sock6 pointers are guaranteed to be non-NULL in vxlan_xmit_one, e.g. if the iface is brought down. This can lead to the following NULL dereference: BUG: kernel NULL pointer dereference, address: 0000000000000010 Oops: Oops: 0000 [#1] SMP NOPTI RIP: 0010:vxlan_xmit_one+0xbb3/0x1580 Call Trace: vxlan_xmit+0x429/0x610 dev_hard_start_xmit+0x55/0xa0 __dev_queue_xmit+0x6d0/0x7f0 ip_finish_output2+0x24b/0x590 ip_output+0x63/0x110 Mentioned commits changed the code path in vxlan_xmit_one and as a side effect the sock4/6 pointer validity checks in vxlan(6)_get_route were lost. Fix this by adding back checks. Since both commits being fixed were released in the same version (v6.7) and are strongly related, bundle the fixes in a single commit. Reported-by: Liang Li Fixes: 6f19b2c136d9 ("vxlan: use generic function for tunnel IPv4 route lookup") Fixes: 2aceb896ee18 ("vxlan: use generic function for tunnel IPv6 route lookup") Cc: Beniamino Galvani Signed-off-by: Antoine Tenart Reviewed-by: Ido Schimmel Tested-by: Ido Schimmel Link: https://patch.msgid.link/20251126102627.74223-1-atenart@kernel.org Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- drivers/net/vxlan/vxlan_core.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c index a5c55e7e4d795..e957aa12a8a44 100644 --- a/drivers/net/vxlan/vxlan_core.c +++ b/drivers/net/vxlan/vxlan_core.c @@ -2349,7 +2349,7 @@ void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, int addr_family; __u8 tos, ttl; int ifindex; - int err; + int err = 0; u32 flags = vxlan->cfg.flags; bool use_cache; bool udp_sum = false; @@ -2454,12 +2454,18 @@ void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, rcu_read_lock(); if (addr_family == AF_INET) { - struct vxlan_sock *sock4 = rcu_dereference(vxlan->vn4_sock); + struct vxlan_sock *sock4; u16 ipcb_flags = 0; struct rtable *rt; __be16 df = 0; __be32 saddr; + sock4 = rcu_dereference(vxlan->vn4_sock); + if (unlikely(!sock4)) { + reason = SKB_DROP_REASON_DEV_READY; + goto tx_error; + } + if (!ifindex) ifindex = sock4->sock->sk->sk_bound_dev_if; @@ -2534,10 +2540,16 @@ void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, ipcb_flags); #if IS_ENABLED(CONFIG_IPV6) } else { - struct vxlan_sock *sock6 = rcu_dereference(vxlan->vn6_sock); + struct vxlan_sock *sock6; struct in6_addr saddr; u16 ip6cb_flags = 0; + sock6 = rcu_dereference(vxlan->vn6_sock); + if (unlikely(!sock6)) { + reason = SKB_DROP_REASON_DEV_READY; + goto tx_error; + } + if (!ifindex) ifindex = sock6->sock->sk->sk_bound_dev_if; From 3a11d8ae00c9e4cda68f331fafd3a79549fea626 Mon Sep 17 00:00:00 2001 From: Alexey Kodanev Date: Wed, 26 Nov 2025 10:43:27 +0000 Subject: [PATCH 0862/2333] net: stmmac: fix rx limit check in stmmac_rx_zc() [ Upstream commit 8048168df56e225c94e50b04cb7b0514135d7a1c ] The extra "count >= limit" check in stmmac_rx_zc() is redundant and has no effect because the value of "count" doesn't change after the while condition at this point. However, it can change after "read_again:" label: while (count < limit) { ... if (count >= limit) break; read_again: ... /* XSK pool expects RX frame 1:1 mapped to XSK buffer */ if (likely(status & rx_not_ls)) { xsk_buff_free(buf->xdp); buf->xdp = NULL; dirty++; count++; goto read_again; } ... This patch addresses the same issue previously resolved in stmmac_rx() by commit fa02de9e7588 ("net: stmmac: fix rx budget limit check"). The fix is the same: move the check after the label to ensure that it bounds the goto loop. Fixes: bba2556efad6 ("net: stmmac: Enable RX via AF_XDP zero-copy") Signed-off-by: Alexey Kodanev Reviewed-by: Russell King (Oracle) Link: https://patch.msgid.link/20251126104327.175590-1-aleksei.kodanev@bell-sw.com Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 7b90ecd3a55e6..86e912471dead 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -5258,10 +5258,10 @@ static int stmmac_rx_zc(struct stmmac_priv *priv, int limit, u32 queue) len = 0; } +read_again: if (count >= limit) break; -read_again: buf1_len = 0; entry = next_entry; buf = &rx_q->buf_pool[entry]; From 44309fda9c60d792cdd4da96d35c4af0895dfbe7 Mon Sep 17 00:00:00 2001 From: Haotian Zhang Date: Mon, 24 Nov 2025 00:35:51 +0800 Subject: [PATCH 0863/2333] mtd: rawnand: renesas: Handle devm_pm_runtime_enable() errors [ Upstream commit a3623e1ae1ed6be4d49b2ccb9996a9d2b65c1828 ] devm_pm_runtime_enable() can fail due to memory allocation failures. The current code ignores its return value and proceeds with pm_runtime_resume_and_get(), which may operate on incorrectly initialized runtime PM state. Check the return value of devm_pm_runtime_enable() and return the error code if it fails. Fixes: 6a2277a0ebe7 ("mtd: rawnand: renesas: Use runtime PM instead of the raw clock API") Signed-off-by: Haotian Zhang Reviewed-by: Geert Uytterhoeven Signed-off-by: Miquel Raynal Signed-off-by: Sasha Levin --- drivers/mtd/nand/raw/renesas-nand-controller.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/nand/raw/renesas-nand-controller.c b/drivers/mtd/nand/raw/renesas-nand-controller.c index ac8c1b80d7be9..201dd62b99905 100644 --- a/drivers/mtd/nand/raw/renesas-nand-controller.c +++ b/drivers/mtd/nand/raw/renesas-nand-controller.c @@ -1336,7 +1336,10 @@ static int rnandc_probe(struct platform_device *pdev) if (IS_ERR(rnandc->regs)) return PTR_ERR(rnandc->regs); - devm_pm_runtime_enable(&pdev->dev); + ret = devm_pm_runtime_enable(&pdev->dev); + if (ret) + return ret; + ret = pm_runtime_resume_and_get(&pdev->dev); if (ret < 0) return ret; From 81841da1f30f66a850cc8796d99ba330aad9d696 Mon Sep 17 00:00:00 2001 From: Tianchu Chen Date: Fri, 28 Nov 2025 16:06:30 +0800 Subject: [PATCH 0864/2333] spi: ch341: fix out-of-bounds memory access in ch341_transfer_one [ Upstream commit 545d1287e40a55242f6ab68bcc1ba3b74088b1bc ] Discovered by Atuin - Automated Vulnerability Discovery Engine. The 'len' variable is calculated as 'min(32, trans->len + 1)', which includes the 1-byte command header. When copying data from 'trans->tx_buf' to 'ch341->tx_buf + 1', using 'len' as the length is incorrect because: 1. It causes an out-of-bounds read from 'trans->tx_buf' (which has size 'trans->len', i.e., 'len - 1' in this context). 2. It can cause an out-of-bounds write to 'ch341->tx_buf' if 'len' is CH341_PACKET_LENGTH (32). Writing 32 bytes to ch341->tx_buf + 1 overflows the buffer. Fix this by copying 'len - 1' bytes. Fixes: 8846739f52af ("spi: add ch341a usb2spi driver") Signed-off-by: Tianchu Chen Link: https://patch.msgid.link/20251128160630.0f922c45ec6084a46fb57099@linux.dev Signed-off-by: Mark Brown Signed-off-by: Sasha Levin --- drivers/spi/spi-ch341.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-ch341.c b/drivers/spi/spi-ch341.c index 46bc208f2d050..79d2f9ab4ef03 100644 --- a/drivers/spi/spi-ch341.c +++ b/drivers/spi/spi-ch341.c @@ -78,7 +78,7 @@ static int ch341_transfer_one(struct spi_controller *host, ch341->tx_buf[0] = CH341A_CMD_SPI_STREAM; - memcpy(ch341->tx_buf + 1, trans->tx_buf, len); + memcpy(ch341->tx_buf + 1, trans->tx_buf, len - 1); ret = usb_bulk_msg(ch341->udev, ch341->write_pipe, ch341->tx_buf, len, NULL, CH341_DEFAULT_TIMEOUT); From 3e2fc1e57a5361633a4bf4222640c6bfe41ff8ea Mon Sep 17 00:00:00 2001 From: Dev Jain Date: Wed, 12 Nov 2025 11:57:15 +0530 Subject: [PATCH 0865/2333] arm64/pageattr: Propagate return value from __change_memory_common [ Upstream commit e5efd56fa157d2e7d789949d1d64eccbac18a897 ] The rodata=on security measure requires that any code path which does vmalloc -> set_memory_ro/set_memory_rox must protect the linear map alias too. Therefore, if such a call fails, we must abort set_memory_* and caller must take appropriate action; currently we are suppressing the error, and there is a real chance of such an error arising post commit a166563e7ec3 ("arm64: mm: support large block mapping when rodata=full"). Therefore, propagate any error to the caller. Fixes: a166563e7ec3 ("arm64: mm: support large block mapping when rodata=full") Signed-off-by: Dev Jain Reviewed-by: Ryan Roberts Signed-off-by: Catalin Marinas Signed-off-by: Sasha Levin --- arch/arm64/mm/pageattr.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/arch/arm64/mm/pageattr.c b/arch/arm64/mm/pageattr.c index 5135f2d66958d..b4ea86cd3a719 100644 --- a/arch/arm64/mm/pageattr.c +++ b/arch/arm64/mm/pageattr.c @@ -148,6 +148,7 @@ static int change_memory_common(unsigned long addr, int numpages, unsigned long size = PAGE_SIZE * numpages; unsigned long end = start + size; struct vm_struct *area; + int ret; int i; if (!PAGE_ALIGNED(addr)) { @@ -185,8 +186,10 @@ static int change_memory_common(unsigned long addr, int numpages, if (rodata_full && (pgprot_val(set_mask) == PTE_RDONLY || pgprot_val(clear_mask) == PTE_RDONLY)) { for (i = 0; i < area->nr_pages; i++) { - __change_memory_common((u64)page_address(area->pages[i]), + ret = __change_memory_common((u64)page_address(area->pages[i]), PAGE_SIZE, set_mask, clear_mask); + if (ret) + return ret; } } From addbb8ddb443f68ccb97e5889c7931033de909c6 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Mon, 24 Nov 2025 15:36:22 -0700 Subject: [PATCH 0866/2333] vfio/pci: Use RCU for error/request triggers to avoid circular locking [ Upstream commit 98693e0897f754e3f51ce6626ed5f785f625ba2b ] Thanks to a device generating an ACS violation during bus reset, lockdep reported the following circular locking issue: CPU0: SET_IRQS (MSI/X): holds igate, acquires memory_lock CPU1: HOT_RESET: holds memory_lock, acquires pci_bus_sem CPU2: AER: holds pci_bus_sem, acquires igate This results in a potential 3-way deadlock. Remove the pci_bus_sem->igate leg of the triangle by using RCU to peek at the eventfd rather than locking it with igate. Fixes: 3be3a074cf5b ("vfio-pci: Don't use device_lock around AER interrupt setup") Signed-off-by: Alex Williamson Reviewed-by: Jason Gunthorpe Link: https://lore.kernel.org/r/20251124223623.2770706-1-alex@shazbot.org Signed-off-by: Alex Williamson Signed-off-by: Sasha Levin --- drivers/vfio/pci/vfio_pci_core.c | 68 ++++++++++++++++++++++--------- drivers/vfio/pci/vfio_pci_intrs.c | 52 ++++++++++++++--------- drivers/vfio/pci/vfio_pci_priv.h | 4 ++ include/linux/vfio_pci_core.h | 10 ++++- 4 files changed, 93 insertions(+), 41 deletions(-) diff --git a/drivers/vfio/pci/vfio_pci_core.c b/drivers/vfio/pci/vfio_pci_core.c index 7dcf5439dedc9..5efe7535f41ed 100644 --- a/drivers/vfio/pci/vfio_pci_core.c +++ b/drivers/vfio/pci/vfio_pci_core.c @@ -41,6 +41,40 @@ static bool nointxmask; static bool disable_vga; static bool disable_idle_d3; +static void vfio_pci_eventfd_rcu_free(struct rcu_head *rcu) +{ + struct vfio_pci_eventfd *eventfd = + container_of(rcu, struct vfio_pci_eventfd, rcu); + + eventfd_ctx_put(eventfd->ctx); + kfree(eventfd); +} + +int vfio_pci_eventfd_replace_locked(struct vfio_pci_core_device *vdev, + struct vfio_pci_eventfd __rcu **peventfd, + struct eventfd_ctx *ctx) +{ + struct vfio_pci_eventfd *new = NULL; + struct vfio_pci_eventfd *old; + + lockdep_assert_held(&vdev->igate); + + if (ctx) { + new = kzalloc(sizeof(*new), GFP_KERNEL_ACCOUNT); + if (!new) + return -ENOMEM; + + new->ctx = ctx; + } + + old = rcu_replace_pointer(*peventfd, new, + lockdep_is_held(&vdev->igate)); + if (old) + call_rcu(&old->rcu, vfio_pci_eventfd_rcu_free); + + return 0; +} + /* List of PF's that vfio_pci_core_sriov_configure() has been called on */ static DEFINE_MUTEX(vfio_pci_sriov_pfs_mutex); static LIST_HEAD(vfio_pci_sriov_pfs); @@ -696,14 +730,8 @@ void vfio_pci_core_close_device(struct vfio_device *core_vdev) vfio_pci_core_disable(vdev); mutex_lock(&vdev->igate); - if (vdev->err_trigger) { - eventfd_ctx_put(vdev->err_trigger); - vdev->err_trigger = NULL; - } - if (vdev->req_trigger) { - eventfd_ctx_put(vdev->req_trigger); - vdev->req_trigger = NULL; - } + vfio_pci_eventfd_replace_locked(vdev, &vdev->err_trigger, NULL); + vfio_pci_eventfd_replace_locked(vdev, &vdev->req_trigger, NULL); mutex_unlock(&vdev->igate); } EXPORT_SYMBOL_GPL(vfio_pci_core_close_device); @@ -1800,21 +1828,21 @@ void vfio_pci_core_request(struct vfio_device *core_vdev, unsigned int count) struct vfio_pci_core_device *vdev = container_of(core_vdev, struct vfio_pci_core_device, vdev); struct pci_dev *pdev = vdev->pdev; + struct vfio_pci_eventfd *eventfd; - mutex_lock(&vdev->igate); - - if (vdev->req_trigger) { + rcu_read_lock(); + eventfd = rcu_dereference(vdev->req_trigger); + if (eventfd) { if (!(count % 10)) pci_notice_ratelimited(pdev, "Relaying device request to user (#%u)\n", count); - eventfd_signal(vdev->req_trigger); + eventfd_signal(eventfd->ctx); } else if (count == 0) { pci_warn(pdev, "No device request channel registered, blocked until released by user\n"); } - - mutex_unlock(&vdev->igate); + rcu_read_unlock(); } EXPORT_SYMBOL_GPL(vfio_pci_core_request); @@ -2227,13 +2255,13 @@ pci_ers_result_t vfio_pci_core_aer_err_detected(struct pci_dev *pdev, pci_channel_state_t state) { struct vfio_pci_core_device *vdev = dev_get_drvdata(&pdev->dev); + struct vfio_pci_eventfd *eventfd; - mutex_lock(&vdev->igate); - - if (vdev->err_trigger) - eventfd_signal(vdev->err_trigger); - - mutex_unlock(&vdev->igate); + rcu_read_lock(); + eventfd = rcu_dereference(vdev->err_trigger); + if (eventfd) + eventfd_signal(eventfd->ctx); + rcu_read_unlock(); return PCI_ERS_RESULT_CAN_RECOVER; } diff --git a/drivers/vfio/pci/vfio_pci_intrs.c b/drivers/vfio/pci/vfio_pci_intrs.c index 30d3e921cb0de..c76e753b3cecd 100644 --- a/drivers/vfio/pci/vfio_pci_intrs.c +++ b/drivers/vfio/pci/vfio_pci_intrs.c @@ -731,21 +731,27 @@ static int vfio_pci_set_msi_trigger(struct vfio_pci_core_device *vdev, return 0; } -static int vfio_pci_set_ctx_trigger_single(struct eventfd_ctx **ctx, +static int vfio_pci_set_ctx_trigger_single(struct vfio_pci_core_device *vdev, + struct vfio_pci_eventfd __rcu **peventfd, unsigned int count, uint32_t flags, void *data) { /* DATA_NONE/DATA_BOOL enables loopback testing */ if (flags & VFIO_IRQ_SET_DATA_NONE) { - if (*ctx) { - if (count) { - eventfd_signal(*ctx); - } else { - eventfd_ctx_put(*ctx); - *ctx = NULL; - } + struct vfio_pci_eventfd *eventfd; + + eventfd = rcu_dereference_protected(*peventfd, + lockdep_is_held(&vdev->igate)); + + if (!eventfd) + return -EINVAL; + + if (count) { + eventfd_signal(eventfd->ctx); return 0; } + + return vfio_pci_eventfd_replace_locked(vdev, peventfd, NULL); } else if (flags & VFIO_IRQ_SET_DATA_BOOL) { uint8_t trigger; @@ -753,8 +759,15 @@ static int vfio_pci_set_ctx_trigger_single(struct eventfd_ctx **ctx, return -EINVAL; trigger = *(uint8_t *)data; - if (trigger && *ctx) - eventfd_signal(*ctx); + + if (trigger) { + struct vfio_pci_eventfd *eventfd = + rcu_dereference_protected(*peventfd, + lockdep_is_held(&vdev->igate)); + + if (eventfd) + eventfd_signal(eventfd->ctx); + } return 0; } else if (flags & VFIO_IRQ_SET_DATA_EVENTFD) { @@ -765,22 +778,23 @@ static int vfio_pci_set_ctx_trigger_single(struct eventfd_ctx **ctx, fd = *(int32_t *)data; if (fd == -1) { - if (*ctx) - eventfd_ctx_put(*ctx); - *ctx = NULL; + return vfio_pci_eventfd_replace_locked(vdev, + peventfd, NULL); } else if (fd >= 0) { struct eventfd_ctx *efdctx; + int ret; efdctx = eventfd_ctx_fdget(fd); if (IS_ERR(efdctx)) return PTR_ERR(efdctx); - if (*ctx) - eventfd_ctx_put(*ctx); + ret = vfio_pci_eventfd_replace_locked(vdev, + peventfd, efdctx); + if (ret) + eventfd_ctx_put(efdctx); - *ctx = efdctx; + return ret; } - return 0; } return -EINVAL; @@ -793,7 +807,7 @@ static int vfio_pci_set_err_trigger(struct vfio_pci_core_device *vdev, if (index != VFIO_PCI_ERR_IRQ_INDEX || start != 0 || count > 1) return -EINVAL; - return vfio_pci_set_ctx_trigger_single(&vdev->err_trigger, + return vfio_pci_set_ctx_trigger_single(vdev, &vdev->err_trigger, count, flags, data); } @@ -804,7 +818,7 @@ static int vfio_pci_set_req_trigger(struct vfio_pci_core_device *vdev, if (index != VFIO_PCI_REQ_IRQ_INDEX || start != 0 || count > 1) return -EINVAL; - return vfio_pci_set_ctx_trigger_single(&vdev->req_trigger, + return vfio_pci_set_ctx_trigger_single(vdev, &vdev->req_trigger, count, flags, data); } diff --git a/drivers/vfio/pci/vfio_pci_priv.h b/drivers/vfio/pci/vfio_pci_priv.h index a9972eacb2936..97d992c063229 100644 --- a/drivers/vfio/pci/vfio_pci_priv.h +++ b/drivers/vfio/pci/vfio_pci_priv.h @@ -26,6 +26,10 @@ struct vfio_pci_ioeventfd { bool vfio_pci_intx_mask(struct vfio_pci_core_device *vdev); void vfio_pci_intx_unmask(struct vfio_pci_core_device *vdev); +int vfio_pci_eventfd_replace_locked(struct vfio_pci_core_device *vdev, + struct vfio_pci_eventfd __rcu **peventfd, + struct eventfd_ctx *ctx); + int vfio_pci_set_irqs_ioctl(struct vfio_pci_core_device *vdev, uint32_t flags, unsigned index, unsigned start, unsigned count, void *data); diff --git a/include/linux/vfio_pci_core.h b/include/linux/vfio_pci_core.h index f541044e42a2a..f5c93787f8e0b 100644 --- a/include/linux/vfio_pci_core.h +++ b/include/linux/vfio_pci_core.h @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -27,6 +28,11 @@ struct vfio_pci_core_device; struct vfio_pci_region; +struct vfio_pci_eventfd { + struct eventfd_ctx *ctx; + struct rcu_head rcu; +}; + struct vfio_pci_regops { ssize_t (*rw)(struct vfio_pci_core_device *vdev, char __user *buf, size_t count, loff_t *ppos, bool iswrite); @@ -83,8 +89,8 @@ struct vfio_pci_core_device { struct pci_saved_state *pci_saved_state; struct pci_saved_state *pm_save; int ioeventfds_nr; - struct eventfd_ctx *err_trigger; - struct eventfd_ctx *req_trigger; + struct vfio_pci_eventfd __rcu *err_trigger; + struct vfio_pci_eventfd __rcu *req_trigger; struct eventfd_ctx *pm_wake_eventfd_ctx; struct list_head dummy_resources_list; struct mutex ioeventfds_lock; From cadb28f8b3fd6908e3051e86158c65c3a8e1c907 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Sala=C3=BCn?= Date: Fri, 28 Nov 2025 18:21:56 +0100 Subject: [PATCH 0867/2333] landlock: Fix handling of disconnected directories MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 49c9e09d961025b22e61ef9ad56aa1c21b6ce2f1 ] Disconnected files or directories can appear when they are visible and opened from a bind mount, but have been renamed or moved from the source of the bind mount in a way that makes them inaccessible from the mount point (i.e. out of scope). Previously, access rights tied to files or directories opened through a disconnected directory were collected by walking the related hierarchy down to the root of the filesystem, without taking into account the mount point because it couldn't be found. This could lead to inconsistent access results, potential access right widening, and hard-to-debug renames, especially since such paths cannot be printed. For a sandboxed task to create a disconnected directory, it needs to have write access (i.e. FS_MAKE_REG, FS_REMOVE_FILE, and FS_REFER) to the underlying source of the bind mount, and read access to the related mount point. Because a sandboxed task cannot acquire more access rights than those defined by its Landlock domain, this could lead to inconsistent access rights due to missing permissions that should be inherited from the mount point hierarchy, while inheriting permissions from the filesystem hierarchy hidden by this mount point instead. Landlock now handles files and directories opened from disconnected directories by taking into account the filesystem hierarchy when the mount point is not found in the hierarchy walk, and also always taking into account the mount point from which these disconnected directories were opened. This ensures that a rename is not allowed if it would widen access rights [1]. The rationale is that, even if disconnected hierarchies might not be visible or accessible to a sandboxed task, relying on the collected access rights from them improves the guarantee that access rights will not be widened during a rename because of the access right comparison between the source and the destination (see LANDLOCK_ACCESS_FS_REFER). It may look like this would grant more access on disconnected files and directories, but the security policies are always enforced for all the evaluated hierarchies. This new behavior should be less surprising to users and safer from an access control perspective. Remove a wrong WARN_ON_ONCE() canary in collect_domain_accesses() and fix the related comment. Because opened files have their access rights stored in the related file security properties, there is no impact for disconnected or unlinked files. Cc: Christian Brauner Cc: Günther Noack Cc: Song Liu Reported-by: Tingmao Wang Closes: https://lore.kernel.org/r/027d5190-b37a-40a8-84e9-4ccbc352bcdf@maowtm.org Closes: https://lore.kernel.org/r/09b24128f86973a6022e6aa8338945fcfb9a33e4.1749925391.git.m@maowtm.org Fixes: b91c3e4ea756 ("landlock: Add support for file reparenting with LANDLOCK_ACCESS_FS_REFER") Fixes: cb2c7d1a1776 ("landlock: Support filesystem access-control") Link: https://lore.kernel.org/r/b0f46246-f2c5-42ca-93ce-0d629702a987@maowtm.org [1] Reviewed-by: Tingmao Wang Link: https://lore.kernel.org/r/20251128172200.760753-2-mic@digikod.net Signed-off-by: Mickaël Salaün Signed-off-by: Sasha Levin --- security/landlock/errata/abi-1.h | 16 +++++++++++++ security/landlock/fs.c | 40 ++++++++++++++++++++++---------- 2 files changed, 44 insertions(+), 12 deletions(-) create mode 100644 security/landlock/errata/abi-1.h diff --git a/security/landlock/errata/abi-1.h b/security/landlock/errata/abi-1.h new file mode 100644 index 0000000000000..e8a2bff2e5b6a --- /dev/null +++ b/security/landlock/errata/abi-1.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +/** + * DOC: erratum_3 + * + * Erratum 3: Disconnected directory handling + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This fix addresses an issue with disconnected directories that occur when a + * directory is moved outside the scope of a bind mount. The change ensures + * that evaluated access rights include both those from the disconnected file + * hierarchy down to its filesystem root and those from the related mount point + * hierarchy. This prevents access right widening through rename or link + * actions. + */ +LANDLOCK_ERRATUM(3) diff --git a/security/landlock/fs.c b/security/landlock/fs.c index d9c12b993fa7d..a2ed0e76938aa 100644 --- a/security/landlock/fs.c +++ b/security/landlock/fs.c @@ -909,21 +909,31 @@ static bool is_access_to_paths_allowed( break; } } + if (unlikely(IS_ROOT(walker_path.dentry))) { - /* - * Stops at disconnected root directories. Only allows - * access to internal filesystems (e.g. nsfs, which is - * reachable through /proc//ns/). - */ - if (walker_path.mnt->mnt_flags & MNT_INTERNAL) { + if (likely(walker_path.mnt->mnt_flags & MNT_INTERNAL)) { + /* + * Stops and allows access when reaching disconnected root + * directories that are part of internal filesystems (e.g. nsfs, + * which is reachable through /proc//ns/). + */ allowed_parent1 = true; allowed_parent2 = true; + break; } - break; + + /* + * We reached a disconnected root directory from a bind mount. + * Let's continue the walk with the mount point we missed. + */ + dput(walker_path.dentry); + walker_path.dentry = walker_path.mnt->mnt_root; + dget(walker_path.dentry); + } else { + parent_dentry = dget_parent(walker_path.dentry); + dput(walker_path.dentry); + walker_path.dentry = parent_dentry; } - parent_dentry = dget_parent(walker_path.dentry); - dput(walker_path.dentry); - walker_path.dentry = parent_dentry; } path_put(&walker_path); @@ -1021,6 +1031,9 @@ static access_mask_t maybe_remove(const struct dentry *const dentry) * file. While walking from @dir to @mnt_root, we record all the domain's * allowed accesses in @layer_masks_dom. * + * Because of disconnected directories, this walk may not reach @mnt_dir. In + * this case, the walk will continue to @mnt_dir after this call. + * * This is similar to is_access_to_paths_allowed() but much simpler because it * only handles walking on the same mount point and only checks one set of * accesses. @@ -1062,8 +1075,11 @@ static bool collect_domain_accesses( break; } - /* We should not reach a root other than @mnt_root. */ - if (dir == mnt_root || WARN_ON_ONCE(IS_ROOT(dir))) + /* + * Stops at the mount point or the filesystem root for a disconnected + * directory. + */ + if (dir == mnt_root || unlikely(IS_ROOT(dir))) break; parent_dentry = dget_parent(dir); From f61d6d4e1508c94d3d35428fb6229453d6926e8e Mon Sep 17 00:00:00 2001 From: Robert Marko Date: Thu, 27 Nov 2025 12:44:35 +0100 Subject: [PATCH 0868/2333] net: phy: aquantia: check for NVMEM deferral [ Upstream commit a6c121a2432eee2c4ebceb1483ccd4a50a52983d ] Currently, if NVMEM provider is probed later than Aquantia, loading the firmware will fail with -EINVAL. To fix this, simply check for -EPROBE_DEFER when NVMEM is attempted and return it. Fixes: e93984ebc1c8 ("net: phy: aquantia: add firmware load support") Signed-off-by: Robert Marko Reviewed-by: Russell King (Oracle) Link: https://patch.msgid.link/20251127114514.460924-1-robimarko@gmail.com Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- drivers/net/phy/aquantia/aquantia_firmware.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/phy/aquantia/aquantia_firmware.c b/drivers/net/phy/aquantia/aquantia_firmware.c index bbbcc9736b00e..569256152689f 100644 --- a/drivers/net/phy/aquantia/aquantia_firmware.c +++ b/drivers/net/phy/aquantia/aquantia_firmware.c @@ -369,7 +369,7 @@ int aqr_firmware_load(struct phy_device *phydev) * assume that, and load a new image. */ ret = aqr_firmware_load_nvmem(phydev); - if (!ret) + if (ret == -EPROBE_DEFER || !ret) return ret; ret = aqr_firmware_load_fs(phydev); From 4cc8dd1aafacbd256a67feceff9b2daad5a95cc7 Mon Sep 17 00:00:00 2001 From: Hangbin Liu Date: Thu, 27 Nov 2025 14:33:10 +0000 Subject: [PATCH 0869/2333] selftests: bonding: add delay before each xvlan_over_bond connectivity check [ Upstream commit 2c28ee720ad14f58eb88a97ec3efe7c5c315ea5d ] Jakub reported increased flakiness in bond_macvlan_ipvlan.sh on regular kernel, while the tests consistently pass on a debug kernel. This suggests a timing-sensitive issue. To mitigate this, introduce a short sleep before each xvlan_over_bond connectivity check. The delay helps ensure neighbor and route cache have fully converged before verifying connectivity. The sleep interval is kept minimal since check_connection() is invoked nearly 100 times during the test. Fixes: 246af950b940 ("selftests: bonding: add macvlan over bond testing") Reported-by: Jakub Kicinski Closes: https://lore.kernel.org/netdev/20251114082014.750edfad@kernel.org Signed-off-by: Hangbin Liu Link: https://patch.msgid.link/20251127143310.47740-1-liuhangbin@gmail.com Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- .../testing/selftests/drivers/net/bonding/bond_macvlan_ipvlan.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/testing/selftests/drivers/net/bonding/bond_macvlan_ipvlan.sh b/tools/testing/selftests/drivers/net/bonding/bond_macvlan_ipvlan.sh index c4711272fe45d..559f300f965aa 100755 --- a/tools/testing/selftests/drivers/net/bonding/bond_macvlan_ipvlan.sh +++ b/tools/testing/selftests/drivers/net/bonding/bond_macvlan_ipvlan.sh @@ -30,6 +30,7 @@ check_connection() local message=${3} RET=0 + sleep 0.25 ip netns exec ${ns} ping ${target} -c 4 -i 0.1 &>/dev/null check_err $? "ping failed" log_test "${bond_mode}/${xvlan_type}_${xvlan_mode}: ${message}" From 760bc6ceda8e2c273c0e2018ad2595967c3dd308 Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Thu, 27 Nov 2025 07:30:15 -0800 Subject: [PATCH 0870/2333] net: netpoll: initialize work queue before error checks [ Upstream commit e5235eb6cfe02a51256013a78f7b28779a7740d5 ] Prevent a kernel warning when netconsole setup fails on devices with IFF_DISABLE_NETPOLL flag. The warning (at kernel/workqueue.c:4242 in __flush_work) occurs because the cleanup path tries to cancel an uninitialized work queue. When __netpoll_setup() encounters a device with IFF_DISABLE_NETPOLL, it fails early and calls skb_pool_flush() for cleanup. This function calls cancel_work_sync(&np->refill_wq), but refill_wq hasn't been initialized yet, triggering the warning. Move INIT_WORK() to the beginning of __netpoll_setup(), ensuring the work queue is properly initialized before any potential failure points. This allows the cleanup path to safely cancel the work queue regardless of where the setup fails. Fixes: 248f6571fd4c5 ("netpoll: Optimize skb refilling on critical path") Signed-off-by: Breno Leitao Link: https://patch.msgid.link/20251127-netpoll_fix_init_work-v1-1-65c07806d736@debian.org Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- net/core/netpoll.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/core/netpoll.c b/net/core/netpoll.c index 331764845e8fa..09f72f10813cc 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c @@ -554,6 +554,7 @@ int __netpoll_setup(struct netpoll *np, struct net_device *ndev) int err; skb_queue_head_init(&np->skb_pool); + INIT_WORK(&np->refill_wq, refill_skbs_work_handler); if (ndev->priv_flags & IFF_DISABLE_NETPOLL) { np_err(np, "%s doesn't support polling, aborting\n", @@ -591,7 +592,6 @@ int __netpoll_setup(struct netpoll *np, struct net_device *ndev) /* fill up the skb queue */ refill_skbs(np); - INIT_WORK(&np->refill_wq, refill_skbs_work_handler); /* last thing to do is link it to the net device structure */ rcu_assign_pointer(ndev->npinfo, npinfo); From 03ee076352cf625d7785fc43fce9caf806e7c665 Mon Sep 17 00:00:00 2001 From: Ivan Stepchenko Date: Fri, 21 Nov 2025 14:54:46 +0300 Subject: [PATCH 0871/2333] mtd: lpddr_cmds: fix signed shifts in lpddr_cmds [ Upstream commit c909fec69f84b39e63876c69b9df2c178c6b76ba ] There are several places where a value of type 'int' is shifted by lpddr->chipshift. lpddr->chipshift is derived from QINFO geometry and might reach 31 when QINFO reports a 2 GiB size - the maximum supported by LPDDR(1) compliant chips. This may cause unexpected sign-extensions when casting the integer value to the type of 'unsigned long'. Use '1UL << lpddr->chipshift' and cast 'j' to unsigned long before shifting so the computation is performed at the destination width. Found by Linux Verification Center (linuxtesting.org) with SVACE. Fixes: c68264711ca6 ("[MTD] LPDDR Command set driver") Signed-off-by: Ivan Stepchenko Signed-off-by: Miquel Raynal Signed-off-by: Sasha Levin --- drivers/mtd/lpddr/lpddr_cmds.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/mtd/lpddr/lpddr_cmds.c b/drivers/mtd/lpddr/lpddr_cmds.c index 290fd0119e984..cd37d58abacb7 100644 --- a/drivers/mtd/lpddr/lpddr_cmds.c +++ b/drivers/mtd/lpddr/lpddr_cmds.c @@ -79,7 +79,7 @@ struct mtd_info *lpddr_cmdset(struct map_info *map) mutex_init(&shared[i].lock); for (j = 0; j < lpddr->qinfo->HWPartsNum; j++) { *chip = lpddr->chips[i]; - chip->start += j << lpddr->chipshift; + chip->start += (unsigned long)j << lpddr->chipshift; chip->oldstate = chip->state = FL_READY; chip->priv = &shared[i]; /* those should be reset too since @@ -559,7 +559,7 @@ static int lpddr_point(struct mtd_info *mtd, loff_t adr, size_t len, break; if ((len + ofs - 1) >> lpddr->chipshift) - thislen = (1<chipshift) - ofs; + thislen = (1UL << lpddr->chipshift) - ofs; else thislen = len; /* get the chip */ @@ -575,7 +575,7 @@ static int lpddr_point(struct mtd_info *mtd, loff_t adr, size_t len, len -= thislen; ofs = 0; - last_end += 1 << lpddr->chipshift; + last_end += 1UL << lpddr->chipshift; chipnum++; chip = &lpddr->chips[chipnum]; } @@ -601,7 +601,7 @@ static int lpddr_unpoint (struct mtd_info *mtd, loff_t adr, size_t len) break; if ((len + ofs - 1) >> lpddr->chipshift) - thislen = (1<chipshift) - ofs; + thislen = (1UL << lpddr->chipshift) - ofs; else thislen = len; From 43b6c312b8ff013258e21c2b4eca4887171ebbc3 Mon Sep 17 00:00:00 2001 From: Kumar Kartikeya Dwivedi Date: Fri, 28 Nov 2025 23:27:57 +0000 Subject: [PATCH 0872/2333] rqspinlock: Enclose lock/unlock within lock entry acquisitions [ Upstream commit beb7021a6003d9c6a463fffca0d6311efb8e0e66 ] Ritesh reported that timeouts occurred frequently for rqspinlock despite reentrancy on the same lock on the same CPU in [0]. This patch closes one of the races leading to this behavior, and reduces the frequency of timeouts. We currently have a tiny window between the fast-path cmpxchg and the grabbing of the lock entry where an NMI could land, attempt the same lock that was just acquired, and end up timing out. This is not ideal. Instead, move the lock entry acquisition from the fast path to before the cmpxchg, and remove the grabbing of the lock entry in the slow path, assuming it was already taken by the fast path. The TAS fallback is invoked directly without being preceded by the typical fast path, therefore we must continue to grab the deadlock detection entry in that case. Case on lock leading to missed AA: cmpxchg lock A ... rqspinlock acquisition of A ... timeout grab_held_lock_entry(A) There is a similar case when unlocking the lock. If the NMI lands between the WRITE_ONCE and smp_store_release, it is possible that we end up in a situation where the NMI fails to diagnose the AA condition, leading to a timeout. Case on unlock leading to missed AA: WRITE_ONCE(rqh->locks[rqh->cnt - 1], NULL) ... rqspinlock acquisition of A ... timeout smp_store_release(A->locked, 0) The patch changes the order on unlock to smp_store_release() succeeded by WRITE_ONCE() of NULL. This avoids the missed AA detection described above, but may lead to a false positive if the NMI lands between these two statements, which is acceptable (and preferred over a timeout). The original intention of the reverse order on unlock was to prevent the following possible misdiagnosis of an ABBA scenario: grab entry A lock A grab entry B lock B unlock B smp_store_release(B->locked, 0) grab entry B lock B grab entry A lock A ! WRITE_ONCE(rqh->locks[rqh->cnt - 1], NULL) If the store release were is after the WRITE_ONCE, the other CPU would not observe B in the table of the CPU unlocking the lock B. However, since the threads are obviously participating in an ABBA deadlock, it is no longer appealing to use the order above since it may lead to a 250 ms timeout due to missed AA detection. [0]: https://lore.kernel.org/bpf/CAH6OuBTjG+N=+GGwcpOUbeDN563oz4iVcU3rbse68egp9wj9_A@mail.gmail.com Fixes: 0d80e7f951be ("rqspinlock: Choose trylock fallback for NMI waiters") Reported-by: Ritesh Oedayrajsingh Varma Signed-off-by: Kumar Kartikeya Dwivedi Link: https://lore.kernel.org/r/20251128232802.1031906-2-memxor@gmail.com Signed-off-by: Alexei Starovoitov Signed-off-by: Sasha Levin --- include/asm-generic/rqspinlock.h | 60 +++++++++++++++++--------------- kernel/bpf/rqspinlock.c | 15 ++++---- 2 files changed, 38 insertions(+), 37 deletions(-) diff --git a/include/asm-generic/rqspinlock.h b/include/asm-generic/rqspinlock.h index 6d4244d643df3..0f2dcbbfee2f0 100644 --- a/include/asm-generic/rqspinlock.h +++ b/include/asm-generic/rqspinlock.h @@ -129,8 +129,8 @@ static __always_inline void release_held_lock_entry(void) * for lock B * release_held_lock_entry * - * try_cmpxchg_acquire for lock A * grab_held_lock_entry + * try_cmpxchg_acquire for lock A * * Lack of any ordering means reordering may occur such that dec, inc * are done before entry is overwritten. This permits a remote lock @@ -139,13 +139,8 @@ static __always_inline void release_held_lock_entry(void) * CPU holds a lock it is attempting to acquire, leading to false ABBA * diagnosis). * - * In case of unlock, we will always do a release on the lock word after - * releasing the entry, ensuring that other CPUs cannot hold the lock - * (and make conclusions about deadlocks) until the entry has been - * cleared on the local CPU, preventing any anomalies. Reordering is - * still possible there, but a remote CPU cannot observe a lock in our - * table which it is already holding, since visibility entails our - * release store for the said lock has not retired. + * The case of unlock is treated differently due to NMI reentrancy, see + * comments in res_spin_unlock. * * In theory we don't have a problem if the dec and WRITE_ONCE above get * reordered with each other, we either notice an empty NULL entry on @@ -175,10 +170,22 @@ static __always_inline int res_spin_lock(rqspinlock_t *lock) { int val = 0; - if (likely(atomic_try_cmpxchg_acquire(&lock->val, &val, _Q_LOCKED_VAL))) { - grab_held_lock_entry(lock); + /* + * Grab the deadlock detection entry before doing the cmpxchg, so that + * reentrancy due to NMIs between the succeeding cmpxchg and creation of + * held lock entry can correctly detect an acquisition attempt in the + * interrupted context. + * + * cmpxchg lock A + * + * res_spin_lock(A) --> missed AA, leads to timeout + * + * grab_held_lock_entry(A) + */ + grab_held_lock_entry(lock); + + if (likely(atomic_try_cmpxchg_acquire(&lock->val, &val, _Q_LOCKED_VAL))) return 0; - } return resilient_queued_spin_lock_slowpath(lock, val); } @@ -192,28 +199,25 @@ static __always_inline void res_spin_unlock(rqspinlock_t *lock) { struct rqspinlock_held *rqh = this_cpu_ptr(&rqspinlock_held_locks); - if (unlikely(rqh->cnt > RES_NR_HELD)) - goto unlock; - WRITE_ONCE(rqh->locks[rqh->cnt - 1], NULL); -unlock: /* - * Release barrier, ensures correct ordering. See release_held_lock_entry - * for details. Perform release store instead of queued_spin_unlock, - * since we use this function for test-and-set fallback as well. When we - * have CONFIG_QUEUED_SPINLOCKS=n, we clear the full 4-byte lockword. + * Release barrier, ensures correct ordering. Perform release store + * instead of queued_spin_unlock, since we use this function for the TAS + * fallback as well. When we have CONFIG_QUEUED_SPINLOCKS=n, we clear + * the full 4-byte lockword. * - * Like release_held_lock_entry, we can do the release before the dec. - * We simply care about not seeing the 'lock' in our table from a remote - * CPU once the lock has been released, which doesn't rely on the dec. + * Perform the smp_store_release before clearing the lock entry so that + * NMIs landing in the unlock path can correctly detect AA issues. The + * opposite order shown below may lead to missed AA checks: * - * Unlike smp_wmb(), release is not a two way fence, hence it is - * possible for a inc to move up and reorder with our clearing of the - * entry. This isn't a problem however, as for a misdiagnosis of ABBA, - * the remote CPU needs to hold this lock, which won't be released until - * the store below is done, which would ensure the entry is overwritten - * to NULL, etc. + * WRITE_ONCE(rqh->locks[rqh->cnt - 1], NULL) + * + * res_spin_lock(A) --> missed AA, leads to timeout + * + * smp_store_release(A->locked, 0) */ smp_store_release(&lock->locked, 0); + if (likely(rqh->cnt <= RES_NR_HELD)) + WRITE_ONCE(rqh->locks[rqh->cnt - 1], NULL); this_cpu_dec(rqspinlock_held_locks.cnt); } diff --git a/kernel/bpf/rqspinlock.c b/kernel/bpf/rqspinlock.c index 21be48108e962..f4c534fa4e87b 100644 --- a/kernel/bpf/rqspinlock.c +++ b/kernel/bpf/rqspinlock.c @@ -275,6 +275,10 @@ int __lockfunc resilient_tas_spin_lock(rqspinlock_t *lock) int val, ret = 0; RES_INIT_TIMEOUT(ts); + /* + * The fast path is not invoked for the TAS fallback, so we must grab + * the deadlock detection entry here. + */ grab_held_lock_entry(lock); /* @@ -397,10 +401,7 @@ int __lockfunc resilient_queued_spin_lock_slowpath(rqspinlock_t *lock, u32 val) goto queue; } - /* - * Grab an entry in the held locks array, to enable deadlock detection. - */ - grab_held_lock_entry(lock); + /* Deadlock detection entry already held after failing fast path. */ /* * We're pending, wait for the owner to go away. @@ -448,11 +449,7 @@ int __lockfunc resilient_queued_spin_lock_slowpath(rqspinlock_t *lock, u32 val) */ queue: lockevent_inc(lock_slowpath); - /* - * Grab deadlock detection entry for the queue path. - */ - grab_held_lock_entry(lock); - + /* Deadlock detection entry already held after failing fast path. */ node = this_cpu_ptr(&rqnodes[0].mcs); idx = node->count++; tail = encode_tail(smp_processor_id(), idx); From 14980281ebff84f6b6ec9262ba6951c73031680c Mon Sep 17 00:00:00 2001 From: Kumar Kartikeya Dwivedi Date: Fri, 28 Nov 2025 23:27:59 +0000 Subject: [PATCH 0873/2333] rqspinlock: Use trylock fallback when per-CPU rqnode is busy [ Upstream commit 81d5a6a438595e46be191d602e5c2d6d73992fdc ] In addition to deferring to the trylock fallback in NMIs, only do so when an rqspinlock waiter is queued on the current CPU. This is detected by noticing a non-zero node index. This allows NMI waiters to join the waiter queue if it isn't interrupting an existing rqspinlock waiter, and increase the chances of fairly obtaining the lock, performing deadlock detection as the head, and not being starved while attempting the trylock. The trylock path in particular is unlikely to succeed under contention, as it relies on the lock word becoming 0, which indicates no contention. This means that the most likely result for NMIs attempting a trylock is a timeout under contention if they don't hit an AA or ABBA case. The core problem being addressed through the fixed commit was removing the dependency edge between an NMI queue waiter and the queue waiter it is interrupting. Whenever a circular dependency forms, and with no way to break it (as non-head waiters don't poll for deadlocks or timeouts), we would enter into a deadlock. A trylock either breaks such an edge by probing for deadlocks, and finally terminating the waiting loop using a timeout. By excluding queueing on CPUs where the node index is non-zero for NMIs, this sort of dependency is broken. The CPU enters the trylock path for those cases, and falls back to deadlock checks and timeouts. However, in other case where it doesn't interrupt the CPU in the slow path while its queued on the lock, it can join the queue as a normal waiter, and avoid trylock associated starvation and subsequent timeouts. There are a few remaining cases here that matter: the NMI can still preempt the owner in its critical section, and if it queues as a non-head waiter, it can end up impeding the progress of the owner. While this won't deadlock, since the head waiter will eventually signal the NMI waiter to either stop (due to a timeout), it can still lead to long timeouts. These gaps will be addressed in subsequent commits. Note that while the node count detection approach is less conservative than simply deferring NMIs to trylock, it is going to return errors where attempts to lock B in NMI happen while waiters for lock A are in a lower context on the same CPU. However, this only occurs when the lower context is queued in the slow path, and the NMI attempt can proceed without failure in all other cases. To continue to prevent AA deadlocks (or ABBA in a similar NMI interrupting lower context pattern), we'd need a more fleshed out algorithm to unlink NMI waiters after they queue and detect such cases. However, all that complexity isn't appealing yet to reduce the failure rate in the small window inside the slow path. It is important to note that reentrancy in the slow path can also happen through trace_contention_{begin,end}, but in those cases, unlike an NMI, the forward progress of the head waiter (or the predecessor in general) is not being blocked. Fixes: 0d80e7f951be ("rqspinlock: Choose trylock fallback for NMI waiters") Reported-by: Ritesh Oedayrajsingh Varma Suggested-by: Alexei Starovoitov Signed-off-by: Kumar Kartikeya Dwivedi Link: https://lore.kernel.org/r/20251128232802.1031906-4-memxor@gmail.com Signed-off-by: Alexei Starovoitov Signed-off-by: Sasha Levin --- kernel/bpf/rqspinlock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/bpf/rqspinlock.c b/kernel/bpf/rqspinlock.c index f4c534fa4e87b..3faf9cbd6c753 100644 --- a/kernel/bpf/rqspinlock.c +++ b/kernel/bpf/rqspinlock.c @@ -465,7 +465,7 @@ int __lockfunc resilient_queued_spin_lock_slowpath(rqspinlock_t *lock, u32 val) * any MCS node. This is not the most elegant solution, but is * simple enough. */ - if (unlikely(idx >= _Q_MAX_NODES || in_nmi())) { + if (unlikely(idx >= _Q_MAX_NODES || (in_nmi() && idx > 0))) { lockevent_inc(lock_no_node); RES_RESET_TIMEOUT(ts, RES_DEF_TIMEOUT); while (!queued_spin_trylock(lock)) { From de4a27113099a8916bc715c322fb23965bdfe4d2 Mon Sep 17 00:00:00 2001 From: Alexandru Gagniuc Date: Fri, 28 Nov 2025 19:32:05 -0600 Subject: [PATCH 0874/2333] remoteproc: qcom_q6v5_wcss: fix parsing of qcom,halt-regs [ Upstream commit 7e81fa8d809ed1e67ae9ecd52d20a20c2c65d877 ] The "qcom,halt-regs" consists of a phandle reference followed by the three offsets within syscon for halt registers. Thus, we need to request 4 integers from of_property_read_variable_u32_array(), with the halt_reg ofsets at indexes 1, 2, and 3. Offset 0 is the phandle. With MAX_HALT_REG at 3, of_property_read_variable_u32_array() returns -EOVERFLOW, causing .probe() to fail. Increase MAX_HALT_REG to 4, and update the indexes accordingly. Fixes: 0af65b9b915e ("remoteproc: qcom: wcss: Add non pas wcss Q6 support for QCS404") Signed-off-by: Alexandru Gagniuc Link: https://lore.kernel.org/r/20251129013207.3981517-1-mr.nuke.me@gmail.com Signed-off-by: Bjorn Andersson Signed-off-by: Sasha Levin --- drivers/remoteproc/qcom_q6v5_wcss.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/remoteproc/qcom_q6v5_wcss.c b/drivers/remoteproc/qcom_q6v5_wcss.c index 07c88623f5978..23ec87827d4f8 100644 --- a/drivers/remoteproc/qcom_q6v5_wcss.c +++ b/drivers/remoteproc/qcom_q6v5_wcss.c @@ -85,7 +85,7 @@ #define TCSR_WCSS_CLK_MASK 0x1F #define TCSR_WCSS_CLK_ENABLE 0x14 -#define MAX_HALT_REG 3 +#define MAX_HALT_REG 4 enum { WCSS_IPQ8074, WCSS_QCS404, @@ -864,9 +864,9 @@ static int q6v5_wcss_init_mmio(struct q6v5_wcss *wcss, return -EINVAL; } - wcss->halt_q6 = halt_reg[0]; - wcss->halt_wcss = halt_reg[1]; - wcss->halt_nc = halt_reg[2]; + wcss->halt_q6 = halt_reg[1]; + wcss->halt_wcss = halt_reg[2]; + wcss->halt_nc = halt_reg[3]; return 0; } From 61e684ef4c2bc157c50bde5f2e842cacc26761ba Mon Sep 17 00:00:00 2001 From: Yu Kuai Date: Mon, 17 Nov 2025 16:55:57 +0800 Subject: [PATCH 0875/2333] md/raid5: fix IO hang when array is broken with IO inflight [ Upstream commit a913d1f6a7f607c110aeef8b58c8988f47a4b24e ] Following test can cause IO hang: mdadm -CvR /dev/md0 -l10 -n4 /dev/sd[abcd] --assume-clean --chunk=64K --bitmap=none sleep 5 echo 1 > /sys/block/sda/device/delete echo 1 > /sys/block/sdb/device/delete echo 1 > /sys/block/sdc/device/delete echo 1 > /sys/block/sdd/device/delete dd if=/dev/md0 of=/dev/null bs=8k count=1 iflag=direct Root cause: 1) all disks removed, however all rdevs in the array is still in sync, IO will be issued normally. 2) IO failure from sda, and set badblocks failed, sda will be faulty and MD_SB_CHANGING_PENDING will be set. 3) error recovery try to recover this IO from other disks, IO will be issued to sdb, sdc, and sdd. 4) IO failure from sdb, and set badblocks failed again, now array is broken and will become read-only. 5) IO failure from sdc and sdd, however, stripe can't be handled anymore because MD_SB_CHANGING_PENDING is set: handle_stripe handle_stripe if (test_bit MD_SB_CHANGING_PENDING) set_bit STRIPE_HANDLE goto finish // skip handling failed stripe release_stripe if (test_bit STRIPE_HANDLE) list_add_tail conf->hand_list 6) later raid5d can't handle failed stripe as well: raid5d md_check_recovery md_update_sb if (!md_is_rdwr()) // can't clear pending bit return if (test_bit MD_SB_CHANGING_PENDING) break; // can't handle failed stripe Since MD_SB_CHANGING_PENDING can never be cleared for read-only array, fix this problem by skip this checking for read-only array. Link: https://lore.kernel.org/linux-raid/20251117085557.770572-3-yukuai@fnnas.com Fixes: d87f064f5874 ("md: never update metadata when array is read-only.") Signed-off-by: Yu Kuai Reviewed-by: Li Nan Signed-off-by: Sasha Levin --- drivers/md/raid5.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 24b32a0c95b40..8b5f8a12d4179 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -4956,7 +4956,8 @@ static void handle_stripe(struct stripe_head *sh) goto finish; if (s.handle_bad_blocks || - test_bit(MD_SB_CHANGE_PENDING, &conf->mddev->sb_flags)) { + (md_is_rdwr(conf->mddev) && + test_bit(MD_SB_CHANGE_PENDING, &conf->mddev->sb_flags))) { set_bit(STRIPE_HANDLE, &sh->state); goto finish; } @@ -6768,7 +6769,8 @@ static void raid5d(struct md_thread *thread) int batch_size, released; unsigned int offset; - if (test_bit(MD_SB_CHANGE_PENDING, &mddev->sb_flags)) + if (md_is_rdwr(mddev) && + test_bit(MD_SB_CHANGE_PENDING, &mddev->sb_flags)) break; released = release_stripe_list(conf, conf->temp_inactive_list); From 36c6c788173e72a26c61ed07a36541ad71e32639 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 27 Nov 2025 14:53:25 +0100 Subject: [PATCH 0876/2333] clk: keystone: fix compile testing [ Upstream commit b276445e98fe28609688fb85b89a81b803910e63 ] Some keystone clock drivers can be selected when COMPILE_TEST is enabled but since commit b745c0794e2f ("clk: keystone: Add sci-clk driver support") they are never actually built. Enable compile testing by allowing the build system to process the keystone drivers. Fixes: b745c0794e2f ("clk: keystone: Add sci-clk driver support") Signed-off-by: Johan Hovold Signed-off-by: Stephen Boyd Signed-off-by: Sasha Levin --- drivers/clk/Makefile | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index b74a1767ca278..61ec08404442b 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -125,8 +125,7 @@ obj-$(CONFIG_ARCH_HISI) += hisilicon/ obj-y += imgtec/ obj-y += imx/ obj-y += ingenic/ -obj-$(CONFIG_ARCH_K3) += keystone/ -obj-$(CONFIG_ARCH_KEYSTONE) += keystone/ +obj-y += keystone/ obj-y += mediatek/ obj-$(CONFIG_ARCH_MESON) += meson/ obj-y += microchip/ From c9ae2463c529d750c8977a3304354cadd5f5df58 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 25 Nov 2025 09:55:54 +0100 Subject: [PATCH 0877/2333] smb: smbdirect: introduce SMBDIRECT_DEBUG_ERR_PTR() helper [ Upstream commit 1f3fd108c5c5a9885c6c276a2489c49b60a6b90d ] This can be used like this: int err = somefunc(); pr_warn("err=%1pe\n", SMBDIRECT_DEBUG_ERR_PTR(err)); This will be used in the following fixes in order to be prepared to identify real world problems more easily. Cc: Steve French Cc: Tom Talpey Cc: Long Li Cc: Namjae Jeon Cc: Paulo Alcantara Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Acked-by: Namjae Jeon Signed-off-by: Steve French Stable-dep-of: 425c32750b48 ("smb: server: relax WARN_ON_ONCE(SMBDIRECT_SOCKET_*) checks in recv_done() and smb_direct_cm_handler()") Signed-off-by: Sasha Levin --- fs/smb/common/smbdirect/smbdirect_socket.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/fs/smb/common/smbdirect/smbdirect_socket.h b/fs/smb/common/smbdirect/smbdirect_socket.h index ee5a90d691c89..611986827a5e2 100644 --- a/fs/smb/common/smbdirect/smbdirect_socket.h +++ b/fs/smb/common/smbdirect/smbdirect_socket.h @@ -74,6 +74,19 @@ const char *smbdirect_socket_status_string(enum smbdirect_socket_status status) return ""; } +/* + * This can be used with %1pe to print errors as strings or '0' + * And it avoids warnings like: warn: passing zero to 'ERR_PTR' + * from smatch -p=kernel --pedantic + */ +static __always_inline +const void * __must_check SMBDIRECT_DEBUG_ERR_PTR(long error) +{ + if (error == 0) + return NULL; + return ERR_PTR(error); +} + enum smbdirect_keepalive_status { SMBDIRECT_KEEPALIVE_NONE, SMBDIRECT_KEEPALIVE_PENDING, From 7d077222555e2dd8e06870950c513510c57d1b10 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 25 Nov 2025 09:55:55 +0100 Subject: [PATCH 0878/2333] smb: smbdirect: introduce SMBDIRECT_CHECK_STATUS_{WARN,DISCONNECT}() [ Upstream commit 1adb2dab9727c5beaaf253f67bf4fc2c54ae70e7 ] These will be used in various places in order to assert the current status mostly during the connect and negotiation phase. It will replace the WARN_ON_ONCE(sc->status != ...) calls, which are very useless in order to identify the problem that happened. As a start client and server will need to define their own __SMBDIRECT_SOCKET_DISCONNECT(__sc) macro in order to use SMBDIRECT_CHECK_STATUS_DISCONNECT(). Cc: Steve French Cc: Tom Talpey Cc: Long Li Cc: Namjae Jeon Cc: Paulo Alcantara Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Acked-by: Namjae Jeon Signed-off-by: Steve French Stable-dep-of: 425c32750b48 ("smb: server: relax WARN_ON_ONCE(SMBDIRECT_SOCKET_*) checks in recv_done() and smb_direct_cm_handler()") Signed-off-by: Sasha Levin --- fs/smb/common/smbdirect/smbdirect_socket.h | 38 ++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/fs/smb/common/smbdirect/smbdirect_socket.h b/fs/smb/common/smbdirect/smbdirect_socket.h index 611986827a5e2..384b19177e1c3 100644 --- a/fs/smb/common/smbdirect/smbdirect_socket.h +++ b/fs/smb/common/smbdirect/smbdirect_socket.h @@ -394,6 +394,44 @@ static __always_inline void smbdirect_socket_init(struct smbdirect_socket *sc) init_waitqueue_head(&sc->mr_io.cleanup.wait_queue); } +#define __SMBDIRECT_CHECK_STATUS_FAILED(__sc, __expected_status, __error_cmd, __unexpected_cmd) ({ \ + bool __failed = false; \ + if (unlikely((__sc)->first_error)) { \ + __failed = true; \ + __error_cmd \ + } else if (unlikely((__sc)->status != (__expected_status))) { \ + __failed = true; \ + __unexpected_cmd \ + } \ + __failed; \ +}) + +#define __SMBDIRECT_CHECK_STATUS_WARN(__sc, __expected_status, __unexpected_cmd) \ + __SMBDIRECT_CHECK_STATUS_FAILED(__sc, __expected_status, \ + , \ + { \ + const struct sockaddr_storage *__src = NULL; \ + const struct sockaddr_storage *__dst = NULL; \ + if ((__sc)->rdma.cm_id) { \ + __src = &(__sc)->rdma.cm_id->route.addr.src_addr; \ + __dst = &(__sc)->rdma.cm_id->route.addr.dst_addr; \ + } \ + WARN_ONCE(1, \ + "expected[%s] != %s first_error=%1pe local=%pISpsfc remote=%pISpsfc\n", \ + smbdirect_socket_status_string(__expected_status), \ + smbdirect_socket_status_string((__sc)->status), \ + SMBDIRECT_DEBUG_ERR_PTR((__sc)->first_error), \ + __src, __dst); \ + __unexpected_cmd \ + }) + +#define SMBDIRECT_CHECK_STATUS_WARN(__sc, __expected_status) \ + __SMBDIRECT_CHECK_STATUS_WARN(__sc, __expected_status, /* nothing */) + +#define SMBDIRECT_CHECK_STATUS_DISCONNECT(__sc, __expected_status) \ + __SMBDIRECT_CHECK_STATUS_WARN(__sc, __expected_status, \ + __SMBDIRECT_SOCKET_DISCONNECT(__sc);) + struct smbdirect_send_io { struct smbdirect_socket *socket; struct ib_cqe cqe; From 7c4f55905cfbebdde377b7582a682775c43e2ac3 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 25 Nov 2025 15:21:53 +0100 Subject: [PATCH 0879/2333] smb: server: relax WARN_ON_ONCE(SMBDIRECT_SOCKET_*) checks in recv_done() and smb_direct_cm_handler() [ Upstream commit 425c32750b48956a6e156b6a4609d281ee471359 ] Namjae reported the following: I have a simple file copy test with windows 11 client, and get the following error message. [ 894.140312] ------------[ cut here ]------------ [ 894.140316] WARNING: CPU: 1 PID: 116 at fs/smb/server/transport_rdma.c:642 recv_done+0x308/0x360 [ksmbd] [ 894.140335] Modules linked in: ksmbd cmac nls_utf8 nls_ucs2_utils libarc4 nls_iso8859_1 snd_hda_codec_intelhdmi snd_hda_codec_hdmi snd_hda_codec_alc882 snd_hda_codec_realtek_lib snd_hda_codec_generic rpcrdma intel_rapl_msr rdma_ucm intel_rapl_common snd_hda_intel ib_iser snd_hda_codec intel_uncore_frequency intel_uncore_frequency_common snd_hda_core intel_tcc_cooling x86_pkg_temp_thermal intel_powerclamp snd_intel_dspcfg libiscsi snd_intel_sdw_acpi coretemp scsi_transport_iscsi snd_hwdep kvm_intel i915 snd_pcm ib_umad rdma_cm snd_seq_midi ib_ipoib kvm snd_seq_midi_event iw_cm snd_rawmidi ghash_clmulni_intel ib_cm aesni_intel snd_seq mei_hdcp drm_buddy rapl snd_seq_device eeepc_wmi asus_wmi snd_timer intel_cstate ttm snd drm_client_lib drm_display_helper sparse_keymap soundcore platform_profile mxm_wmi wmi_bmof joydev mei_me cec acpi_pad mei rc_core drm_kms_helper input_leds i2c_algo_bit mac_hid sch_fq_codel msr parport_pc ppdev lp nfsd parport auth_rpcgss binfmt_misc nfs_acl lockd grace drm sunrpc ramoops efi_pstore [ 894.140414] reed_solomon pstore_blk pstore_zone autofs4 btrfs blake2b_generic xor raid6_pq mlx5_ib ib_uverbs ib_core hid_generic uas usbhid hid r8169 i2c_i801 usb_storage i2c_mux i2c_smbus mlx5_core realtek ahci mlxfw psample libahci video wmi [last unloaded: ksmbd] [ 894.140442] CPU: 1 UID: 0 PID: 116 Comm: kworker/1:1H Tainted: G W 6.18.0-rc5+ #1 PREEMPT(voluntary) [ 894.140447] Tainted: [W]=WARN [ 894.140448] Hardware name: System manufacturer System Product Name/H110M-K, BIOS 3601 12/12/2017 [ 894.140450] Workqueue: ib-comp-wq ib_cq_poll_work [ib_core] [ 894.140476] RIP: 0010:recv_done+0x308/0x360 [ksmbd] [ 894.140487] Code: 2e f2 ff ff 5b 41 5c 41 5d 41 5e 41 5f 5d c3 cc cc cc cc 41 8b 55 10 49 8b 75 08 b9 02 00 00 00 e8 ed f4 f2 c3 e9 59 fd ff ff <0f> 0b e9 02 ff ff ff 49 8b 74 24 28 49 8d 94 24 c8 00 00 00 bf 00 [ 894.140490] RSP: 0018:ffffa47ec03f3d78 EFLAGS: 00010293 [ 894.140492] RAX: 0000000000000001 RBX: ffff8eb84c818000 RCX: 000000010002ba00 [ 894.140494] RDX: 0000000037600001 RSI: 0000000000000083 RDI: ffff8eb92ec9ee40 [ 894.140496] RBP: ffffa47ec03f3da0 R08: 0000000000000000 R09: 0000000000000010 [ 894.140498] R10: ffff8eb801705680 R11: fefefefefefefeff R12: ffff8eb7454b8810 [ 894.140499] R13: ffff8eb746deb988 R14: ffff8eb746deb980 R15: ffff8eb84c818000 [ 894.140501] FS: 0000000000000000(0000) GS:ffff8eb9a7355000(0000) knlGS:0000000000000000 [ 894.140503] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 894.140505] CR2: 00002d9401d60018 CR3: 0000000010a40006 CR4: 00000000003726f0 [ 894.140507] Call Trace: [ 894.140509] [ 894.140512] __ib_process_cq+0x8e/0x190 [ib_core] [ 894.140530] ib_cq_poll_work+0x2f/0x90 [ib_core] [ 894.140545] process_scheduled_works+0xd4/0x430 [ 894.140554] worker_thread+0x12a/0x270 [ 894.140558] kthread+0x10d/0x250 [ 894.140564] ? __pfx_worker_thread+0x10/0x10 [ 894.140567] ? __pfx_kthread+0x10/0x10 [ 894.140571] ret_from_fork+0x11a/0x160 [ 894.140574] ? __pfx_kthread+0x10/0x10 [ 894.140577] ret_from_fork_asm+0x1a/0x30 [ 894.140584] [ 894.140585] ---[ end trace 0000000000000000 ]--- [ 894.154363] ------------[ cut here ]------------ [ 894.154367] WARNING: CPU: 3 PID: 5543 at fs/smb/server/transport_rdma.c:1728 smb_direct_cm_handler+0x121/0x130 [ksmbd] [ 894.154384] Modules linked in: ksmbd cmac nls_utf8 nls_ucs2_utils libarc4 nls_iso8859_1 snd_hda_codec_intelhdmi snd_hda_codec_hdmi snd_hda_codec_alc882 snd_hda_codec_realtek_lib snd_hda_codec_generic rpcrdma intel_rapl_msr rdma_ucm intel_rapl_common snd_hda_intel ib_iser snd_hda_codec intel_uncore_frequency intel_uncore_frequency_common snd_hda_core intel_tcc_cooling x86_pkg_temp_thermal intel_powerclamp snd_intel_dspcfg libiscsi snd_intel_sdw_acpi coretemp scsi_transport_iscsi snd_hwdep kvm_intel i915 snd_pcm ib_umad rdma_cm snd_seq_midi ib_ipoib kvm snd_seq_midi_event iw_cm snd_rawmidi ghash_clmulni_intel ib_cm aesni_intel snd_seq mei_hdcp drm_buddy rapl snd_seq_device eeepc_wmi asus_wmi snd_timer intel_cstate ttm snd drm_client_lib drm_display_helper sparse_keymap soundcore platform_profile mxm_wmi wmi_bmof joydev mei_me cec acpi_pad mei rc_core drm_kms_helper input_leds i2c_algo_bit mac_hid sch_fq_codel msr parport_pc ppdev lp nfsd parport auth_rpcgss binfmt_misc nfs_acl lockd grace drm sunrpc ramoops efi_pstore [ 894.154456] reed_solomon pstore_blk pstore_zone autofs4 btrfs blake2b_generic xor raid6_pq mlx5_ib ib_uverbs ib_core hid_generic uas usbhid hid r8169 i2c_i801 usb_storage i2c_mux i2c_smbus mlx5_core realtek ahci mlxfw psample libahci video wmi [last unloaded: ksmbd] [ 894.154483] CPU: 3 UID: 0 PID: 5543 Comm: kworker/3:6 Tainted: G W 6.18.0-rc5+ #1 PREEMPT(voluntary) [ 894.154487] Tainted: [W]=WARN [ 894.154488] Hardware name: System manufacturer System Product Name/H110M-K, BIOS 3601 12/12/2017 [ 894.154490] Workqueue: ib_cm cm_work_handler [ib_cm] [ 894.154499] RIP: 0010:smb_direct_cm_handler+0x121/0x130 [ksmbd] [ 894.154507] Code: e7 e8 13 b1 ef ff 44 89 e1 4c 89 ee 48 c7 c7 80 d7 59 c1 48 89 c2 e8 2e 4d ef c3 31 c0 5b 41 5c 41 5d 41 5e 5d c3 cc cc cc cc <0f> 0b eb a5 66 66 2e 0f 1f 84 00 00 00 00 00 90 90 90 90 90 90 90 [ 894.154510] RSP: 0018:ffffa47ec1b27c00 EFLAGS: 00010206 [ 894.154512] RAX: ffffffffc1304e00 RBX: ffff8eb89ae50880 RCX: 0000000000000000 [ 894.154514] RDX: ffff8eb730960000 RSI: ffffa47ec1b27c60 RDI: ffff8eb7454b9400 [ 894.154515] RBP: ffffa47ec1b27c20 R08: 0000000000000002 R09: ffff8eb730b8c18b [ 894.154517] R10: 0000000000000001 R11: 0000000000000001 R12: 0000000000000009 [ 894.154518] R13: ffff8eb7454b9400 R14: ffff8eb7454b8810 R15: ffff8eb815c43000 [ 894.154520] FS: 0000000000000000(0000) GS:ffff8eb9a7455000(0000) knlGS:0000000000000000 [ 894.154522] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 894.154523] CR2: 00007fe1310e99d0 CR3: 0000000010a40005 CR4: 00000000003726f0 [ 894.154525] Call Trace: [ 894.154527] [ 894.154530] cma_cm_event_handler+0x27/0xd0 [rdma_cm] [ 894.154541] cma_ib_handler+0x99/0x2e0 [rdma_cm] [ 894.154551] cm_process_work+0x28/0xf0 [ib_cm] [ 894.154557] cm_queue_work_unlock+0x41/0xf0 [ib_cm] [ 894.154563] cm_work_handler+0x2eb/0x25b0 [ib_cm] [ 894.154568] ? pwq_activate_first_inactive+0x52/0x70 [ 894.154572] ? pwq_dec_nr_in_flight+0x244/0x330 [ 894.154575] process_scheduled_works+0xd4/0x430 [ 894.154579] worker_thread+0x12a/0x270 [ 894.154581] kthread+0x10d/0x250 [ 894.154585] ? __pfx_worker_thread+0x10/0x10 [ 894.154587] ? __pfx_kthread+0x10/0x10 [ 894.154590] ret_from_fork+0x11a/0x160 [ 894.154593] ? __pfx_kthread+0x10/0x10 [ 894.154596] ret_from_fork_asm+0x1a/0x30 [ 894.154602] [ 894.154603] ---[ end trace 0000000000000000 ]--- [ 894.154931] ksmbd: smb_direct: disconnected [ 894.157278] ksmbd: smb_direct: disconnected I guess sc->first_error is already set and sc->status is thus unexpected, so this should avoid the WARN[_ON]_ONCE() if sc->first_error is already set and have a usable error path. While there set sc->first_error as soon as possible. v1 of this patch revealed the real problem with this message: [ 309.560973] expected[NEGOTIATE_NEEDED] != RDMA_CONNECT_RUNNING first_error=0 local=192.168.0.200:445 remote=192.168.0.100:60445 [ 309.561034] WARNING: CPU: 2 PID: 78 at transport_rdma.c:643 recv_done+0x2fa/0x3d0 [ksmbd] Some drivers (at least mlx5_ib) might post a recv completion before RDMA_CM_EVENT_ESTABLISHED, so we need to adjust our expectation in that case. Fixes: e2d5e516c663 ("smb: server: only turn into SMBDIRECT_SOCKET_CONNECTED when negotiation is done") Cc: Steve French Cc: Tom Talpey Cc: Long Li Cc: Namjae Jeon Cc: Paulo Alcantara Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Acked-by: Namjae Jeon Signed-off-by: Steve French Signed-off-by: Sasha Levin --- fs/smb/server/transport_rdma.c | 40 +++++++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c index e2be9a4961546..4e7ab8d9314f6 100644 --- a/fs/smb/server/transport_rdma.c +++ b/fs/smb/server/transport_rdma.c @@ -19,6 +19,8 @@ #include #include +#define __SMBDIRECT_SOCKET_DISCONNECT(__sc) smb_direct_disconnect_rdma_connection(__sc) + #include "glob.h" #include "connection.h" #include "smb_common.h" @@ -231,6 +233,9 @@ static void smb_direct_disconnect_rdma_work(struct work_struct *work) struct smbdirect_socket *sc = container_of(work, struct smbdirect_socket, disconnect_work); + if (sc->first_error == 0) + sc->first_error = -ECONNABORTED; + /* * make sure this and other work is not queued again * but here we don't block and avoid @@ -241,9 +246,6 @@ static void smb_direct_disconnect_rdma_work(struct work_struct *work) disable_delayed_work(&sc->idle.timer_work); disable_work(&sc->idle.immediate_work); - if (sc->first_error == 0) - sc->first_error = -ECONNABORTED; - switch (sc->status) { case SMBDIRECT_SOCKET_NEGOTIATE_NEEDED: case SMBDIRECT_SOCKET_NEGOTIATE_RUNNING: @@ -287,6 +289,9 @@ static void smb_direct_disconnect_rdma_work(struct work_struct *work) static void smb_direct_disconnect_rdma_connection(struct smbdirect_socket *sc) { + if (sc->first_error == 0) + sc->first_error = -ECONNABORTED; + /* * make sure other work (than disconnect_work) is * not queued again but here we don't block and avoid @@ -296,9 +301,6 @@ smb_direct_disconnect_rdma_connection(struct smbdirect_socket *sc) disable_work(&sc->idle.immediate_work); disable_delayed_work(&sc->idle.timer_work); - if (sc->first_error == 0) - sc->first_error = -ECONNABORTED; - switch (sc->status) { case SMBDIRECT_SOCKET_RESOLVE_ADDR_FAILED: case SMBDIRECT_SOCKET_RESOLVE_ROUTE_FAILED: @@ -639,7 +641,18 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) return; } sc->recv_io.reassembly.full_packet_received = true; - WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_NEGOTIATE_NEEDED); + /* + * Some drivers (at least mlx5_ib) might post a + * recv completion before RDMA_CM_EVENT_ESTABLISHED, + * we need to adjust our expectation in that case. + */ + if (!sc->first_error && sc->status == SMBDIRECT_SOCKET_RDMA_CONNECT_RUNNING) + sc->status = SMBDIRECT_SOCKET_NEGOTIATE_NEEDED; + if (SMBDIRECT_CHECK_STATUS_WARN(sc, SMBDIRECT_SOCKET_NEGOTIATE_NEEDED)) { + put_recvmsg(sc, recvmsg); + smb_direct_disconnect_rdma_connection(sc); + return; + } sc->status = SMBDIRECT_SOCKET_NEGOTIATE_RUNNING; enqueue_reassembly(sc, recvmsg, 0); wake_up(&sc->status_wait); @@ -1725,7 +1738,18 @@ static int smb_direct_cm_handler(struct rdma_cm_id *cm_id, switch (event->event) { case RDMA_CM_EVENT_ESTABLISHED: { - WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_RDMA_CONNECT_RUNNING); + /* + * Some drivers (at least mlx5_ib) might post a + * recv completion before RDMA_CM_EVENT_ESTABLISHED, + * we need to adjust our expectation in that case. + * + * As we already started the negotiation, we just + * ignore RDMA_CM_EVENT_ESTABLISHED here. + */ + if (!sc->first_error && sc->status > SMBDIRECT_SOCKET_RDMA_CONNECT_RUNNING) + break; + if (SMBDIRECT_CHECK_STATUS_DISCONNECT(sc, SMBDIRECT_SOCKET_RDMA_CONNECT_RUNNING)) + break; sc->status = SMBDIRECT_SOCKET_NEGOTIATE_NEEDED; wake_up(&sc->status_wait); break; From 0a1254e59754f1564cc20b6d903a688cd0bd7eaa Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 25 Nov 2025 15:21:54 +0100 Subject: [PATCH 0880/2333] smb: client: relax WARN_ON_ONCE(SMBDIRECT_SOCKET_*) checks in recv_done() and smbd_conn_upcall() [ Upstream commit dc10cf1368af8cb816dcaa2502ba7d44fff20612 ] sc->first_error might already be set and sc->status is thus unexpected, so this should avoid the WARN[_ON]_ONCE() if sc->first_error is already set and have a usable error path. While there set sc->first_error as soon as possible. This is done based on a problem seen in similar places on the server. And there it was already very useful in order to find the problem when we have a meaningful WARN_ONCE() that prints details about the connection. This is much more useful: [ 309.560973] expected[NEGOTIATE_NEEDED] != RDMA_CONNECT_RUNNING first_error=0 local=192.168.0.200:445 remote=192.168.0.100:60445 [ 309.561034] WARNING: CPU: 2 PID: 78 at transport_rdma.c:643 recv_done+0x2fa/0x3d0 [ksmbd] than what we had before (only): [ 894.140316] WARNING: CPU: 1 PID: 116 at fs/smb/server/transport_rdma.c:642 recv_done+0x308/0x360 [ksmbd] Fixes: 58dfba8a2d4e ("smb: client/smbdirect: replace SMBDIRECT_SOCKET_CONNECTING with more detailed states") Cc: Steve French Cc: Tom Talpey Cc: Long Li Cc: Namjae Jeon Cc: Paulo Alcantara Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Acked-by: Namjae Jeon Signed-off-by: Steve French Signed-off-by: Sasha Levin --- fs/smb/client/smbdirect.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c index c6c428c2e08dd..788a0670c4a8d 100644 --- a/fs/smb/client/smbdirect.c +++ b/fs/smb/client/smbdirect.c @@ -7,6 +7,7 @@ #include #include #include +#define __SMBDIRECT_SOCKET_DISCONNECT(__sc) smbd_disconnect_rdma_connection(__sc) #include "../common/smbdirect/smbdirect_pdu.h" #include "smbdirect.h" #include "cifs_debug.h" @@ -186,6 +187,9 @@ static void smbd_disconnect_rdma_work(struct work_struct *work) struct smbdirect_socket *sc = container_of(work, struct smbdirect_socket, disconnect_work); + if (sc->first_error == 0) + sc->first_error = -ECONNABORTED; + /* * make sure this and other work is not queued again * but here we don't block and avoid @@ -197,9 +201,6 @@ static void smbd_disconnect_rdma_work(struct work_struct *work) disable_work(&sc->idle.immediate_work); disable_delayed_work(&sc->idle.timer_work); - if (sc->first_error == 0) - sc->first_error = -ECONNABORTED; - switch (sc->status) { case SMBDIRECT_SOCKET_NEGOTIATE_NEEDED: case SMBDIRECT_SOCKET_NEGOTIATE_RUNNING: @@ -242,6 +243,9 @@ static void smbd_disconnect_rdma_work(struct work_struct *work) static void smbd_disconnect_rdma_connection(struct smbdirect_socket *sc) { + if (sc->first_error == 0) + sc->first_error = -ECONNABORTED; + /* * make sure other work (than disconnect_work) is * not queued again but here we don't block and avoid @@ -252,9 +256,6 @@ static void smbd_disconnect_rdma_connection(struct smbdirect_socket *sc) disable_work(&sc->idle.immediate_work); disable_delayed_work(&sc->idle.timer_work); - if (sc->first_error == 0) - sc->first_error = -ECONNABORTED; - switch (sc->status) { case SMBDIRECT_SOCKET_RESOLVE_ADDR_FAILED: case SMBDIRECT_SOCKET_RESOLVE_ROUTE_FAILED: @@ -322,27 +323,27 @@ static int smbd_conn_upcall( switch (event->event) { case RDMA_CM_EVENT_ADDR_RESOLVED: - WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_RESOLVE_ADDR_RUNNING); + if (SMBDIRECT_CHECK_STATUS_DISCONNECT(sc, SMBDIRECT_SOCKET_RESOLVE_ADDR_RUNNING)) + break; sc->status = SMBDIRECT_SOCKET_RESOLVE_ROUTE_NEEDED; wake_up(&sc->status_wait); break; case RDMA_CM_EVENT_ROUTE_RESOLVED: - WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_RESOLVE_ROUTE_RUNNING); + if (SMBDIRECT_CHECK_STATUS_DISCONNECT(sc, SMBDIRECT_SOCKET_RESOLVE_ROUTE_RUNNING)) + break; sc->status = SMBDIRECT_SOCKET_RDMA_CONNECT_NEEDED; wake_up(&sc->status_wait); break; case RDMA_CM_EVENT_ADDR_ERROR: log_rdma_event(ERR, "connecting failed event=%s\n", event_name); - WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_RESOLVE_ADDR_RUNNING); sc->status = SMBDIRECT_SOCKET_RESOLVE_ADDR_FAILED; smbd_disconnect_rdma_work(&sc->disconnect_work); break; case RDMA_CM_EVENT_ROUTE_ERROR: log_rdma_event(ERR, "connecting failed event=%s\n", event_name); - WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_RESOLVE_ROUTE_RUNNING); sc->status = SMBDIRECT_SOCKET_RESOLVE_ROUTE_FAILED; smbd_disconnect_rdma_work(&sc->disconnect_work); break; @@ -428,7 +429,8 @@ static int smbd_conn_upcall( min_t(u8, sp->responder_resources, peer_responder_resources); - WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_RDMA_CONNECT_RUNNING); + if (SMBDIRECT_CHECK_STATUS_DISCONNECT(sc, SMBDIRECT_SOCKET_RDMA_CONNECT_RUNNING)) + break; sc->status = SMBDIRECT_SOCKET_NEGOTIATE_NEEDED; wake_up(&sc->status_wait); break; @@ -437,7 +439,6 @@ static int smbd_conn_upcall( case RDMA_CM_EVENT_UNREACHABLE: case RDMA_CM_EVENT_REJECTED: log_rdma_event(ERR, "connecting failed event=%s\n", event_name); - WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_RDMA_CONNECT_RUNNING); sc->status = SMBDIRECT_SOCKET_RDMA_CONNECT_FAILED; smbd_disconnect_rdma_work(&sc->disconnect_work); break; @@ -699,7 +700,8 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) negotiate_done = process_negotiation_response(response, wc->byte_len); put_receive_buffer(sc, response); - WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_NEGOTIATE_RUNNING); + if (SMBDIRECT_CHECK_STATUS_WARN(sc, SMBDIRECT_SOCKET_NEGOTIATE_RUNNING)) + negotiate_done = false; if (!negotiate_done) { sc->status = SMBDIRECT_SOCKET_NEGOTIATE_FAILED; smbd_disconnect_rdma_connection(sc); From 210226ce6ca6c14f0c673dd73ec46390f0ec082f Mon Sep 17 00:00:00 2001 From: "Christophe Leroy (CS GROUP)" Date: Sat, 29 Nov 2025 10:56:02 +0100 Subject: [PATCH 0881/2333] um: Disable KASAN_INLINE when STATIC_LINK is selected [ Upstream commit a3209bb94b36351f11e0d9e72ac44e5dd777a069 ] um doesn't support KASAN_INLINE together with STATIC_LINK. Instead of failing the build, disable KASAN_INLINE when STATIC_LINK is selected. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202511290451.x9GZVJ1l-lkp@intel.com/ Fixes: 1e338f4d99e6 ("kasan: introduce ARCH_DEFER_KASAN and unify static key across modes") Signed-off-by: Christophe Leroy (CS GROUP) Link: https://patch.msgid.link/2620ab0bbba640b6237c50b9c0dca1c7d1142f5d.1764410067.git.chleroy@kernel.org Signed-off-by: Johannes Berg Signed-off-by: Sasha Levin --- arch/um/Kconfig | 1 + arch/um/include/asm/kasan.h | 4 ---- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/arch/um/Kconfig b/arch/um/Kconfig index 49781bee79058..93ed850d508ed 100644 --- a/arch/um/Kconfig +++ b/arch/um/Kconfig @@ -5,6 +5,7 @@ menu "UML-specific options" config UML bool default y + select ARCH_DISABLE_KASAN_INLINE if STATIC_LINK select ARCH_NEEDS_DEFER_KASAN if STATIC_LINK select ARCH_WANTS_DYNAMIC_TASK_STRUCT select ARCH_HAS_CACHE_LINE_SIZE diff --git a/arch/um/include/asm/kasan.h b/arch/um/include/asm/kasan.h index b54a4e937fd12..81bcdc0f962e6 100644 --- a/arch/um/include/asm/kasan.h +++ b/arch/um/include/asm/kasan.h @@ -24,10 +24,6 @@ #ifdef CONFIG_KASAN void kasan_init(void); - -#if defined(CONFIG_STATIC_LINK) && defined(CONFIG_KASAN_INLINE) -#error UML does not work in KASAN_INLINE mode with STATIC_LINK enabled! -#endif #else static inline void kasan_init(void) { } #endif /* CONFIG_KASAN */ From c25b004020809fb71aa712d55eb19b853c327e98 Mon Sep 17 00:00:00 2001 From: Jonas Gorski Date: Fri, 28 Nov 2025 09:06:19 +0100 Subject: [PATCH 0882/2333] net: dsa: b53: fix VLAN_ID_IDX write size for BCM5325/65 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 6f268e275c74dae0536e0b61982a8db25bcf4f16 ] Since BCM5325 and BCM5365 only support up to 256 VLANs, the VLAN_ID_IDX register is only 8 bit wide, not 16 bit, so use an appropriate accessor. Fixes: c45655386e53 ("net: dsa: b53: add support for FDB operations on 5325/5365") Reviewed-by: Florian Fainelli Tested-by: Álvaro Fernández Rojas Signed-off-by: Jonas Gorski Link: https://patch.msgid.link/20251128080625.27181-2-jonas.gorski@gmail.com Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- drivers/net/dsa/b53/b53_common.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c index eb767edc4c135..a09ed32dccc07 100644 --- a/drivers/net/dsa/b53/b53_common.c +++ b/drivers/net/dsa/b53/b53_common.c @@ -1924,8 +1924,12 @@ static int b53_arl_op(struct b53_device *dev, int op, int port, /* Perform a read for the given MAC and VID */ b53_write48(dev, B53_ARLIO_PAGE, B53_MAC_ADDR_IDX, mac); - if (!is5325m(dev)) - b53_write16(dev, B53_ARLIO_PAGE, B53_VLAN_ID_IDX, vid); + if (!is5325m(dev)) { + if (is5325(dev) || is5365(dev)) + b53_write8(dev, B53_ARLIO_PAGE, B53_VLAN_ID_IDX, vid); + else + b53_write16(dev, B53_ARLIO_PAGE, B53_VLAN_ID_IDX, vid); + } /* Issue a read operation for this MAC */ ret = b53_arl_rw_op(dev, 1); From 6f2311c6cb9f16b8fa50f4c2d5bef22d1a54f4aa Mon Sep 17 00:00:00 2001 From: Jonas Gorski Date: Fri, 28 Nov 2025 09:06:20 +0100 Subject: [PATCH 0883/2333] net: dsa: b53: fix extracting VID from entry for BCM5325/65 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 9316012dd01952f75e37035360138ccc786ef727 ] BCM5325/65's Entry register uses the highest three bits for VALID/STATIC/AGE, so shifting by 53 only will add these to b53_arl_entry::vid. So make sure to mask the vid value as well, to not get invalid VIDs. Fixes: c45655386e53 ("net: dsa: b53: add support for FDB operations on 5325/5365") Reviewed-by: Florian Fainelli Tested-by: Álvaro Fernández Rojas Signed-off-by: Jonas Gorski Link: https://patch.msgid.link/20251128080625.27181-3-jonas.gorski@gmail.com Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- drivers/net/dsa/b53/b53_priv.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/dsa/b53/b53_priv.h b/drivers/net/dsa/b53/b53_priv.h index 458775f951643..2f44b3b6a0d9f 100644 --- a/drivers/net/dsa/b53/b53_priv.h +++ b/drivers/net/dsa/b53/b53_priv.h @@ -338,7 +338,7 @@ static inline void b53_arl_to_entry_25(struct b53_arl_entry *ent, ent->is_age = !!(mac_vid & ARLTBL_AGE_25); ent->is_static = !!(mac_vid & ARLTBL_STATIC_25); u64_to_ether_addr(mac_vid, ent->mac); - ent->vid = mac_vid >> ARLTBL_VID_S_65; + ent->vid = (mac_vid >> ARLTBL_VID_S_65) & ARLTBL_VID_MASK_25; } static inline void b53_arl_from_entry(u64 *mac_vid, u32 *fwd_entry, From 397fdaf790ceb3cfa2b3b11bbfc384a5526b6d9d Mon Sep 17 00:00:00 2001 From: Jonas Gorski Date: Fri, 7 Nov 2025 09:07:42 +0100 Subject: [PATCH 0884/2333] net: dsa: b53: b53_arl_read{,25}(): use the entry for comparision [ Upstream commit a6e4fd38bf2f2e2363b61c27f4e6c49b14e4bb07 ] Align the b53_arl_read{,25}() functions by consistently using the parsed arl entry instead of parsing the raw registers again. Signed-off-by: Jonas Gorski Reviewed-by: Florian Fainelli Link: https://patch.msgid.link/20251107080749.26936-2-jonas.gorski@gmail.com Signed-off-by: Jakub Kicinski Stable-dep-of: 8e46aacea426 ("net: dsa: b53: use same ARL search result offset for BCM5325/65") Signed-off-by: Sasha Levin --- drivers/net/dsa/b53/b53_common.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c index a09ed32dccc07..4d8de90fb4ab8 100644 --- a/drivers/net/dsa/b53/b53_common.c +++ b/drivers/net/dsa/b53/b53_common.c @@ -1830,7 +1830,7 @@ static int b53_arl_rw_op(struct b53_device *dev, unsigned int op) return b53_arl_op_wait(dev); } -static int b53_arl_read(struct b53_device *dev, u64 mac, +static int b53_arl_read(struct b53_device *dev, const u8 *mac, u16 vid, struct b53_arl_entry *ent, u8 *idx) { DECLARE_BITMAP(free_bins, B53_ARLTBL_MAX_BIN_ENTRIES); @@ -1854,14 +1854,13 @@ static int b53_arl_read(struct b53_device *dev, u64 mac, B53_ARLTBL_DATA_ENTRY(i), &fwd_entry); b53_arl_to_entry(ent, mac_vid, fwd_entry); - if (!(fwd_entry & ARLTBL_VALID)) { + if (!ent->is_valid) { set_bit(i, free_bins); continue; } - if ((mac_vid & ARLTBL_MAC_MASK) != mac) + if (!ether_addr_equal(ent->mac, mac)) continue; - if (dev->vlan_enabled && - ((mac_vid >> ARLTBL_VID_S) & ARLTBL_VID_MASK) != vid) + if (dev->vlan_enabled && ent->vid != vid) continue; *idx = i; return 0; @@ -1871,7 +1870,7 @@ static int b53_arl_read(struct b53_device *dev, u64 mac, return *idx >= dev->num_arl_bins ? -ENOSPC : -ENOENT; } -static int b53_arl_read_25(struct b53_device *dev, u64 mac, +static int b53_arl_read_25(struct b53_device *dev, const u8 *mac, u16 vid, struct b53_arl_entry *ent, u8 *idx) { DECLARE_BITMAP(free_bins, B53_ARLTBL_MAX_BIN_ENTRIES); @@ -1893,14 +1892,13 @@ static int b53_arl_read_25(struct b53_device *dev, u64 mac, b53_arl_to_entry_25(ent, mac_vid); - if (!(mac_vid & ARLTBL_VALID_25)) { + if (!ent->is_valid) { set_bit(i, free_bins); continue; } - if ((mac_vid & ARLTBL_MAC_MASK) != mac) + if (!ether_addr_equal(ent->mac, mac)) continue; - if (dev->vlan_enabled && - ((mac_vid >> ARLTBL_VID_S_65) & ARLTBL_VID_MASK_25) != vid) + if (dev->vlan_enabled && ent->vid != vid) continue; *idx = i; return 0; @@ -1937,9 +1935,9 @@ static int b53_arl_op(struct b53_device *dev, int op, int port, return ret; if (is5325(dev) || is5365(dev)) - ret = b53_arl_read_25(dev, mac, vid, &ent, &idx); + ret = b53_arl_read_25(dev, addr, vid, &ent, &idx); else - ret = b53_arl_read(dev, mac, vid, &ent, &idx); + ret = b53_arl_read(dev, addr, vid, &ent, &idx); /* If this is a read, just finish now */ if (op) From ed2f26bf281bfd061d3b64bd6c23846839fee08a Mon Sep 17 00:00:00 2001 From: Jonas Gorski Date: Fri, 7 Nov 2025 09:07:43 +0100 Subject: [PATCH 0885/2333] net: dsa: b53: move reading ARL entries into their own function [ Upstream commit 4a291fe7226736a465ddb3fa93c21fcef7162ec7 ] Instead of duplicating the whole code iterating over all bins for BCM5325, factor out reading and parsing the entry into its own functions, and name it the modern one after the first chip with that ARL format, (BCM53)95. Signed-off-by: Jonas Gorski Reviewed-by: Florian Fainelli Link: https://patch.msgid.link/20251107080749.26936-3-jonas.gorski@gmail.com Signed-off-by: Jakub Kicinski Stable-dep-of: 8e46aacea426 ("net: dsa: b53: use same ARL search result offset for BCM5325/65") Signed-off-by: Sasha Levin --- drivers/net/dsa/b53/b53_common.c | 69 +++++++++++--------------------- 1 file changed, 23 insertions(+), 46 deletions(-) diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c index 4d8de90fb4ab8..41dcd2d03230d 100644 --- a/drivers/net/dsa/b53/b53_common.c +++ b/drivers/net/dsa/b53/b53_common.c @@ -1830,48 +1830,30 @@ static int b53_arl_rw_op(struct b53_device *dev, unsigned int op) return b53_arl_op_wait(dev); } -static int b53_arl_read(struct b53_device *dev, const u8 *mac, - u16 vid, struct b53_arl_entry *ent, u8 *idx) +static void b53_arl_read_entry_25(struct b53_device *dev, + struct b53_arl_entry *ent, u8 idx) { - DECLARE_BITMAP(free_bins, B53_ARLTBL_MAX_BIN_ENTRIES); - unsigned int i; - int ret; - - ret = b53_arl_op_wait(dev); - if (ret) - return ret; - - bitmap_zero(free_bins, dev->num_arl_bins); - - /* Read the bins */ - for (i = 0; i < dev->num_arl_bins; i++) { - u64 mac_vid; - u32 fwd_entry; + u64 mac_vid; - b53_read64(dev, B53_ARLIO_PAGE, - B53_ARLTBL_MAC_VID_ENTRY(i), &mac_vid); - b53_read32(dev, B53_ARLIO_PAGE, - B53_ARLTBL_DATA_ENTRY(i), &fwd_entry); - b53_arl_to_entry(ent, mac_vid, fwd_entry); + b53_read64(dev, B53_ARLIO_PAGE, B53_ARLTBL_MAC_VID_ENTRY(idx), + &mac_vid); + b53_arl_to_entry_25(ent, mac_vid); +} - if (!ent->is_valid) { - set_bit(i, free_bins); - continue; - } - if (!ether_addr_equal(ent->mac, mac)) - continue; - if (dev->vlan_enabled && ent->vid != vid) - continue; - *idx = i; - return 0; - } +static void b53_arl_read_entry_95(struct b53_device *dev, + struct b53_arl_entry *ent, u8 idx) +{ + u32 fwd_entry; + u64 mac_vid; - *idx = find_first_bit(free_bins, dev->num_arl_bins); - return *idx >= dev->num_arl_bins ? -ENOSPC : -ENOENT; + b53_read64(dev, B53_ARLIO_PAGE, B53_ARLTBL_MAC_VID_ENTRY(idx), + &mac_vid); + b53_read32(dev, B53_ARLIO_PAGE, B53_ARLTBL_DATA_ENTRY(idx), &fwd_entry); + b53_arl_to_entry(ent, mac_vid, fwd_entry); } -static int b53_arl_read_25(struct b53_device *dev, const u8 *mac, - u16 vid, struct b53_arl_entry *ent, u8 *idx) +static int b53_arl_read(struct b53_device *dev, const u8 *mac, + u16 vid, struct b53_arl_entry *ent, u8 *idx) { DECLARE_BITMAP(free_bins, B53_ARLTBL_MAX_BIN_ENTRIES); unsigned int i; @@ -1885,12 +1867,10 @@ static int b53_arl_read_25(struct b53_device *dev, const u8 *mac, /* Read the bins */ for (i = 0; i < dev->num_arl_bins; i++) { - u64 mac_vid; - - b53_read64(dev, B53_ARLIO_PAGE, - B53_ARLTBL_MAC_VID_ENTRY(i), &mac_vid); - - b53_arl_to_entry_25(ent, mac_vid); + if (is5325(dev) || is5365(dev)) + b53_arl_read_entry_25(dev, ent, i); + else + b53_arl_read_entry_95(dev, ent, i); if (!ent->is_valid) { set_bit(i, free_bins); @@ -1934,10 +1914,7 @@ static int b53_arl_op(struct b53_device *dev, int op, int port, if (ret) return ret; - if (is5325(dev) || is5365(dev)) - ret = b53_arl_read_25(dev, addr, vid, &ent, &idx); - else - ret = b53_arl_read(dev, addr, vid, &ent, &idx); + ret = b53_arl_read(dev, addr, vid, &ent, &idx); /* If this is a read, just finish now */ if (op) From 5e86ebfb43069d572c6f742aa60a8cb80a2f1b83 Mon Sep 17 00:00:00 2001 From: Jonas Gorski Date: Fri, 7 Nov 2025 09:07:44 +0100 Subject: [PATCH 0886/2333] net: dsa: b53: move writing ARL entries into their own functions [ Upstream commit bf6e9d2ae1dbafee53ec4ccd126595172e1e5278 ] Move writing ARL entries into individual functions for each format. Signed-off-by: Jonas Gorski Reviewed-by: Florian Fainelli Link: https://patch.msgid.link/20251107080749.26936-4-jonas.gorski@gmail.com Signed-off-by: Jakub Kicinski Stable-dep-of: 8e46aacea426 ("net: dsa: b53: use same ARL search result offset for BCM5325/65") Signed-off-by: Sasha Levin --- drivers/net/dsa/b53/b53_common.c | 38 ++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c index 41dcd2d03230d..4c418e0531f73 100644 --- a/drivers/net/dsa/b53/b53_common.c +++ b/drivers/net/dsa/b53/b53_common.c @@ -1840,6 +1840,16 @@ static void b53_arl_read_entry_25(struct b53_device *dev, b53_arl_to_entry_25(ent, mac_vid); } +static void b53_arl_write_entry_25(struct b53_device *dev, + const struct b53_arl_entry *ent, u8 idx) +{ + u64 mac_vid; + + b53_arl_from_entry_25(&mac_vid, ent); + b53_write64(dev, B53_ARLIO_PAGE, B53_ARLTBL_MAC_VID_ENTRY(idx), + mac_vid); +} + static void b53_arl_read_entry_95(struct b53_device *dev, struct b53_arl_entry *ent, u8 idx) { @@ -1852,6 +1862,19 @@ static void b53_arl_read_entry_95(struct b53_device *dev, b53_arl_to_entry(ent, mac_vid, fwd_entry); } +static void b53_arl_write_entry_95(struct b53_device *dev, + const struct b53_arl_entry *ent, u8 idx) +{ + u32 fwd_entry; + u64 mac_vid; + + b53_arl_from_entry(&mac_vid, &fwd_entry, ent); + b53_write64(dev, B53_ARLIO_PAGE, B53_ARLTBL_MAC_VID_ENTRY(idx), + mac_vid); + b53_write32(dev, B53_ARLIO_PAGE, B53_ARLTBL_DATA_ENTRY(idx), + fwd_entry); +} + static int b53_arl_read(struct b53_device *dev, const u8 *mac, u16 vid, struct b53_arl_entry *ent, u8 *idx) { @@ -1892,9 +1915,8 @@ static int b53_arl_op(struct b53_device *dev, int op, int port, const unsigned char *addr, u16 vid, bool is_valid) { struct b53_arl_entry ent; - u32 fwd_entry; - u64 mac, mac_vid = 0; u8 idx = 0; + u64 mac; int ret; /* Convert the array into a 64-bit MAC */ @@ -1931,7 +1953,6 @@ static int b53_arl_op(struct b53_device *dev, int op, int port, /* We could not find a matching MAC, so reset to a new entry */ dev_dbg(dev->dev, "{%pM,%.4d} not found, using idx: %d\n", addr, vid, idx); - fwd_entry = 0; break; default: dev_dbg(dev->dev, "{%pM,%.4d} found, using idx: %d\n", @@ -1959,16 +1980,9 @@ static int b53_arl_op(struct b53_device *dev, int op, int port, ent.is_age = false; memcpy(ent.mac, addr, ETH_ALEN); if (is5325(dev) || is5365(dev)) - b53_arl_from_entry_25(&mac_vid, &ent); + b53_arl_write_entry_25(dev, &ent, idx); else - b53_arl_from_entry(&mac_vid, &fwd_entry, &ent); - - b53_write64(dev, B53_ARLIO_PAGE, - B53_ARLTBL_MAC_VID_ENTRY(idx), mac_vid); - - if (!is5325(dev) && !is5365(dev)) - b53_write32(dev, B53_ARLIO_PAGE, - B53_ARLTBL_DATA_ENTRY(idx), fwd_entry); + b53_arl_write_entry_95(dev, &ent, idx); return b53_arl_rw_op(dev, 0); } From f3affeb3c7d0fcb1ab577590a5a7ce7a36ddad43 Mon Sep 17 00:00:00 2001 From: Jonas Gorski Date: Fri, 7 Nov 2025 09:07:45 +0100 Subject: [PATCH 0887/2333] net: dsa: b53: provide accessors for accessing ARL_SRCH_CTL [ Upstream commit 1716be6db04af53bac9b869f01156a460595cf41 ] In order to more easily support more formats, move accessing ARL_SRCH_CTL into helper functions to contain the differences. Signed-off-by: Jonas Gorski Reviewed-by: Florian Fainelli Link: https://patch.msgid.link/20251107080749.26936-5-jonas.gorski@gmail.com Signed-off-by: Jakub Kicinski Stable-dep-of: 8e46aacea426 ("net: dsa: b53: use same ARL search result offset for BCM5325/65") Signed-off-by: Sasha Levin --- drivers/net/dsa/b53/b53_common.c | 37 +++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c index 4c418e0531f73..38e6fa05042ca 100644 --- a/drivers/net/dsa/b53/b53_common.c +++ b/drivers/net/dsa/b53/b53_common.c @@ -2017,18 +2017,37 @@ int b53_fdb_del(struct dsa_switch *ds, int port, } EXPORT_SYMBOL(b53_fdb_del); -static int b53_arl_search_wait(struct b53_device *dev) +static void b53_read_arl_srch_ctl(struct b53_device *dev, u8 *val) { - unsigned int timeout = 1000; - u8 reg, offset; + u8 offset; + + if (is5325(dev) || is5365(dev)) + offset = B53_ARL_SRCH_CTL_25; + else + offset = B53_ARL_SRCH_CTL; + + b53_read8(dev, B53_ARLIO_PAGE, offset, val); +} + +static void b53_write_arl_srch_ctl(struct b53_device *dev, u8 val) +{ + u8 offset; if (is5325(dev) || is5365(dev)) offset = B53_ARL_SRCH_CTL_25; else offset = B53_ARL_SRCH_CTL; + b53_write8(dev, B53_ARLIO_PAGE, offset, val); +} + +static int b53_arl_search_wait(struct b53_device *dev) +{ + unsigned int timeout = 1000; + u8 reg; + do { - b53_read8(dev, B53_ARLIO_PAGE, offset, ®); + b53_read_arl_srch_ctl(dev, ®); if (!(reg & ARL_SRCH_STDN)) return -ENOENT; @@ -2083,23 +2102,15 @@ int b53_fdb_dump(struct dsa_switch *ds, int port, unsigned int count = 0, results_per_hit = 1; struct b53_device *priv = ds->priv; struct b53_arl_entry results[2]; - u8 offset; int ret; - u8 reg; if (priv->num_arl_bins > 2) results_per_hit = 2; mutex_lock(&priv->arl_mutex); - if (is5325(priv) || is5365(priv)) - offset = B53_ARL_SRCH_CTL_25; - else - offset = B53_ARL_SRCH_CTL; - /* Start search operation */ - reg = ARL_SRCH_STDN; - b53_write8(priv, B53_ARLIO_PAGE, offset, reg); + b53_write_arl_srch_ctl(priv, ARL_SRCH_STDN); do { ret = b53_arl_search_wait(priv); From e0c63c85e00773c9102c092f92ac75f71b6856c8 Mon Sep 17 00:00:00 2001 From: Jonas Gorski Date: Fri, 7 Nov 2025 09:07:46 +0100 Subject: [PATCH 0888/2333] net: dsa: b53: split reading search entry into their own functions [ Upstream commit e0c476f325a8c9b961a3d446c24d3c8ecae7d186 ] Split reading search entries into a function for each format. Signed-off-by: Jonas Gorski Reviewed-by: Florian Fainelli Link: https://patch.msgid.link/20251107080749.26936-6-jonas.gorski@gmail.com Signed-off-by: Jakub Kicinski Stable-dep-of: 8e46aacea426 ("net: dsa: b53: use same ARL search result offset for BCM5325/65") Signed-off-by: Sasha Levin --- drivers/net/dsa/b53/b53_common.c | 56 ++++++++++++++++++++++---------- 1 file changed, 38 insertions(+), 18 deletions(-) diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c index 38e6fa05042ca..190eb11644917 100644 --- a/drivers/net/dsa/b53/b53_common.c +++ b/drivers/net/dsa/b53/b53_common.c @@ -2060,28 +2060,48 @@ static int b53_arl_search_wait(struct b53_device *dev) return -ETIMEDOUT; } -static void b53_arl_search_rd(struct b53_device *dev, u8 idx, - struct b53_arl_entry *ent) +static void b53_arl_search_read_25(struct b53_device *dev, u8 idx, + struct b53_arl_entry *ent) { u64 mac_vid; - if (is5325(dev)) { - b53_read64(dev, B53_ARLIO_PAGE, B53_ARL_SRCH_RSTL_0_MACVID_25, - &mac_vid); - b53_arl_to_entry_25(ent, mac_vid); - } else if (is5365(dev)) { - b53_read64(dev, B53_ARLIO_PAGE, B53_ARL_SRCH_RSTL_0_MACVID_65, - &mac_vid); - b53_arl_to_entry_25(ent, mac_vid); - } else { - u32 fwd_entry; + b53_read64(dev, B53_ARLIO_PAGE, B53_ARL_SRCH_RSTL_0_MACVID_25, + &mac_vid); + b53_arl_to_entry_25(ent, mac_vid); +} - b53_read64(dev, B53_ARLIO_PAGE, B53_ARL_SRCH_RSTL_MACVID(idx), - &mac_vid); - b53_read32(dev, B53_ARLIO_PAGE, B53_ARL_SRCH_RSTL(idx), - &fwd_entry); - b53_arl_to_entry(ent, mac_vid, fwd_entry); - } +static void b53_arl_search_read_65(struct b53_device *dev, u8 idx, + struct b53_arl_entry *ent) +{ + u64 mac_vid; + + b53_read64(dev, B53_ARLIO_PAGE, B53_ARL_SRCH_RSTL_0_MACVID_65, + &mac_vid); + b53_arl_to_entry_25(ent, mac_vid); +} + +static void b53_arl_search_read_95(struct b53_device *dev, u8 idx, + struct b53_arl_entry *ent) +{ + u32 fwd_entry; + u64 mac_vid; + + b53_read64(dev, B53_ARLIO_PAGE, B53_ARL_SRCH_RSTL_MACVID(idx), + &mac_vid); + b53_read32(dev, B53_ARLIO_PAGE, B53_ARL_SRCH_RSTL(idx), + &fwd_entry); + b53_arl_to_entry(ent, mac_vid, fwd_entry); +} + +static void b53_arl_search_rd(struct b53_device *dev, u8 idx, + struct b53_arl_entry *ent) +{ + if (is5325(dev)) + b53_arl_search_read_25(dev, idx, ent); + else if (is5365(dev)) + b53_arl_search_read_65(dev, idx, ent); + else + b53_arl_search_read_95(dev, idx, ent); } static int b53_fdb_copy(int port, const struct b53_arl_entry *ent, From 4e8f43e63878e45c7efcc508236ae782d32f2e8a Mon Sep 17 00:00:00 2001 From: Jonas Gorski Date: Fri, 7 Nov 2025 09:07:47 +0100 Subject: [PATCH 0889/2333] net: dsa: b53: move ARL entry functions into ops struct [ Upstream commit a7e73339ad46ade76d29fb6cc7d7854222608c26 ] Now that the differences in ARL entry formats are neatly contained into functions per chip family, wrap them into an ops struct and add wrapper functions to access them. Signed-off-by: Jonas Gorski Reviewed-by: Florian Fainelli Link: https://patch.msgid.link/20251107080749.26936-7-jonas.gorski@gmail.com Signed-off-by: Jakub Kicinski Stable-dep-of: 8e46aacea426 ("net: dsa: b53: use same ARL search result offset for BCM5325/65") Signed-off-by: Sasha Levin --- drivers/net/dsa/b53/b53_common.c | 67 ++++++++++++++++++++++---------- drivers/net/dsa/b53/b53_priv.h | 30 ++++++++++++++ 2 files changed, 76 insertions(+), 21 deletions(-) diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c index 190eb11644917..50ed9b7157197 100644 --- a/drivers/net/dsa/b53/b53_common.c +++ b/drivers/net/dsa/b53/b53_common.c @@ -1890,10 +1890,7 @@ static int b53_arl_read(struct b53_device *dev, const u8 *mac, /* Read the bins */ for (i = 0; i < dev->num_arl_bins; i++) { - if (is5325(dev) || is5365(dev)) - b53_arl_read_entry_25(dev, ent, i); - else - b53_arl_read_entry_95(dev, ent, i); + b53_arl_read_entry(dev, ent, i); if (!ent->is_valid) { set_bit(i, free_bins); @@ -1979,10 +1976,7 @@ static int b53_arl_op(struct b53_device *dev, int op, int port, ent.is_static = true; ent.is_age = false; memcpy(ent.mac, addr, ETH_ALEN); - if (is5325(dev) || is5365(dev)) - b53_arl_write_entry_25(dev, &ent, idx); - else - b53_arl_write_entry_95(dev, &ent, idx); + b53_arl_write_entry(dev, &ent, idx); return b53_arl_rw_op(dev, 0); } @@ -2093,17 +2087,6 @@ static void b53_arl_search_read_95(struct b53_device *dev, u8 idx, b53_arl_to_entry(ent, mac_vid, fwd_entry); } -static void b53_arl_search_rd(struct b53_device *dev, u8 idx, - struct b53_arl_entry *ent) -{ - if (is5325(dev)) - b53_arl_search_read_25(dev, idx, ent); - else if (is5365(dev)) - b53_arl_search_read_65(dev, idx, ent); - else - b53_arl_search_read_95(dev, idx, ent); -} - static int b53_fdb_copy(int port, const struct b53_arl_entry *ent, dsa_fdb_dump_cb_t *cb, void *data) { @@ -2137,13 +2120,13 @@ int b53_fdb_dump(struct dsa_switch *ds, int port, if (ret) break; - b53_arl_search_rd(priv, 0, &results[0]); + b53_arl_search_read(priv, 0, &results[0]); ret = b53_fdb_copy(port, &results[0], cb, data); if (ret) break; if (results_per_hit == 2) { - b53_arl_search_rd(priv, 1, &results[1]); + b53_arl_search_read(priv, 1, &results[1]); ret = b53_fdb_copy(port, &results[1], cb, data); if (ret) break; @@ -2669,6 +2652,24 @@ static const struct dsa_switch_ops b53_switch_ops = { .port_change_mtu = b53_change_mtu, }; +static const struct b53_arl_ops b53_arl_ops_25 = { + .arl_read_entry = b53_arl_read_entry_25, + .arl_write_entry = b53_arl_write_entry_25, + .arl_search_read = b53_arl_search_read_25, +}; + +static const struct b53_arl_ops b53_arl_ops_65 = { + .arl_read_entry = b53_arl_read_entry_25, + .arl_write_entry = b53_arl_write_entry_25, + .arl_search_read = b53_arl_search_read_65, +}; + +static const struct b53_arl_ops b53_arl_ops_95 = { + .arl_read_entry = b53_arl_read_entry_95, + .arl_write_entry = b53_arl_write_entry_95, + .arl_search_read = b53_arl_search_read_95, +}; + struct b53_chip_data { u32 chip_id; const char *dev_name; @@ -2682,6 +2683,7 @@ struct b53_chip_data { u8 duplex_reg; u8 jumbo_pm_reg; u8 jumbo_size_reg; + const struct b53_arl_ops *arl_ops; }; #define B53_VTA_REGS \ @@ -2701,6 +2703,7 @@ static const struct b53_chip_data b53_switch_chips[] = { .arl_buckets = 1024, .imp_port = 5, .duplex_reg = B53_DUPLEX_STAT_FE, + .arl_ops = &b53_arl_ops_25, }, { .chip_id = BCM5365_DEVICE_ID, @@ -2711,6 +2714,7 @@ static const struct b53_chip_data b53_switch_chips[] = { .arl_buckets = 1024, .imp_port = 5, .duplex_reg = B53_DUPLEX_STAT_FE, + .arl_ops = &b53_arl_ops_65, }, { .chip_id = BCM5389_DEVICE_ID, @@ -2724,6 +2728,7 @@ static const struct b53_chip_data b53_switch_chips[] = { .duplex_reg = B53_DUPLEX_STAT_GE, .jumbo_pm_reg = B53_JUMBO_PORT_MASK, .jumbo_size_reg = B53_JUMBO_MAX_SIZE, + .arl_ops = &b53_arl_ops_95, }, { .chip_id = BCM5395_DEVICE_ID, @@ -2737,6 +2742,7 @@ static const struct b53_chip_data b53_switch_chips[] = { .duplex_reg = B53_DUPLEX_STAT_GE, .jumbo_pm_reg = B53_JUMBO_PORT_MASK, .jumbo_size_reg = B53_JUMBO_MAX_SIZE, + .arl_ops = &b53_arl_ops_95, }, { .chip_id = BCM5397_DEVICE_ID, @@ -2750,6 +2756,7 @@ static const struct b53_chip_data b53_switch_chips[] = { .duplex_reg = B53_DUPLEX_STAT_GE, .jumbo_pm_reg = B53_JUMBO_PORT_MASK, .jumbo_size_reg = B53_JUMBO_MAX_SIZE, + .arl_ops = &b53_arl_ops_95, }, { .chip_id = BCM5398_DEVICE_ID, @@ -2763,6 +2770,7 @@ static const struct b53_chip_data b53_switch_chips[] = { .duplex_reg = B53_DUPLEX_STAT_GE, .jumbo_pm_reg = B53_JUMBO_PORT_MASK, .jumbo_size_reg = B53_JUMBO_MAX_SIZE, + .arl_ops = &b53_arl_ops_95, }, { .chip_id = BCM53101_DEVICE_ID, @@ -2776,6 +2784,7 @@ static const struct b53_chip_data b53_switch_chips[] = { .duplex_reg = B53_DUPLEX_STAT_GE, .jumbo_pm_reg = B53_JUMBO_PORT_MASK, .jumbo_size_reg = B53_JUMBO_MAX_SIZE, + .arl_ops = &b53_arl_ops_95, }, { .chip_id = BCM53115_DEVICE_ID, @@ -2789,6 +2798,7 @@ static const struct b53_chip_data b53_switch_chips[] = { .duplex_reg = B53_DUPLEX_STAT_GE, .jumbo_pm_reg = B53_JUMBO_PORT_MASK, .jumbo_size_reg = B53_JUMBO_MAX_SIZE, + .arl_ops = &b53_arl_ops_95, }, { .chip_id = BCM53125_DEVICE_ID, @@ -2802,6 +2812,7 @@ static const struct b53_chip_data b53_switch_chips[] = { .duplex_reg = B53_DUPLEX_STAT_GE, .jumbo_pm_reg = B53_JUMBO_PORT_MASK, .jumbo_size_reg = B53_JUMBO_MAX_SIZE, + .arl_ops = &b53_arl_ops_95, }, { .chip_id = BCM53128_DEVICE_ID, @@ -2815,6 +2826,7 @@ static const struct b53_chip_data b53_switch_chips[] = { .duplex_reg = B53_DUPLEX_STAT_GE, .jumbo_pm_reg = B53_JUMBO_PORT_MASK, .jumbo_size_reg = B53_JUMBO_MAX_SIZE, + .arl_ops = &b53_arl_ops_95, }, { .chip_id = BCM63XX_DEVICE_ID, @@ -2828,6 +2840,7 @@ static const struct b53_chip_data b53_switch_chips[] = { .duplex_reg = B53_DUPLEX_STAT_63XX, .jumbo_pm_reg = B53_JUMBO_PORT_MASK_63XX, .jumbo_size_reg = B53_JUMBO_MAX_SIZE_63XX, + .arl_ops = &b53_arl_ops_95, }, { .chip_id = BCM53010_DEVICE_ID, @@ -2841,6 +2854,7 @@ static const struct b53_chip_data b53_switch_chips[] = { .duplex_reg = B53_DUPLEX_STAT_GE, .jumbo_pm_reg = B53_JUMBO_PORT_MASK, .jumbo_size_reg = B53_JUMBO_MAX_SIZE, + .arl_ops = &b53_arl_ops_95, }, { .chip_id = BCM53011_DEVICE_ID, @@ -2854,6 +2868,7 @@ static const struct b53_chip_data b53_switch_chips[] = { .duplex_reg = B53_DUPLEX_STAT_GE, .jumbo_pm_reg = B53_JUMBO_PORT_MASK, .jumbo_size_reg = B53_JUMBO_MAX_SIZE, + .arl_ops = &b53_arl_ops_95, }, { .chip_id = BCM53012_DEVICE_ID, @@ -2867,6 +2882,7 @@ static const struct b53_chip_data b53_switch_chips[] = { .duplex_reg = B53_DUPLEX_STAT_GE, .jumbo_pm_reg = B53_JUMBO_PORT_MASK, .jumbo_size_reg = B53_JUMBO_MAX_SIZE, + .arl_ops = &b53_arl_ops_95, }, { .chip_id = BCM53018_DEVICE_ID, @@ -2880,6 +2896,7 @@ static const struct b53_chip_data b53_switch_chips[] = { .duplex_reg = B53_DUPLEX_STAT_GE, .jumbo_pm_reg = B53_JUMBO_PORT_MASK, .jumbo_size_reg = B53_JUMBO_MAX_SIZE, + .arl_ops = &b53_arl_ops_95, }, { .chip_id = BCM53019_DEVICE_ID, @@ -2893,6 +2910,7 @@ static const struct b53_chip_data b53_switch_chips[] = { .duplex_reg = B53_DUPLEX_STAT_GE, .jumbo_pm_reg = B53_JUMBO_PORT_MASK, .jumbo_size_reg = B53_JUMBO_MAX_SIZE, + .arl_ops = &b53_arl_ops_95, }, { .chip_id = BCM58XX_DEVICE_ID, @@ -2906,6 +2924,7 @@ static const struct b53_chip_data b53_switch_chips[] = { .duplex_reg = B53_DUPLEX_STAT_GE, .jumbo_pm_reg = B53_JUMBO_PORT_MASK, .jumbo_size_reg = B53_JUMBO_MAX_SIZE, + .arl_ops = &b53_arl_ops_95, }, { .chip_id = BCM583XX_DEVICE_ID, @@ -2919,6 +2938,7 @@ static const struct b53_chip_data b53_switch_chips[] = { .duplex_reg = B53_DUPLEX_STAT_GE, .jumbo_pm_reg = B53_JUMBO_PORT_MASK, .jumbo_size_reg = B53_JUMBO_MAX_SIZE, + .arl_ops = &b53_arl_ops_95, }, /* Starfighter 2 */ { @@ -2933,6 +2953,7 @@ static const struct b53_chip_data b53_switch_chips[] = { .duplex_reg = B53_DUPLEX_STAT_GE, .jumbo_pm_reg = B53_JUMBO_PORT_MASK, .jumbo_size_reg = B53_JUMBO_MAX_SIZE, + .arl_ops = &b53_arl_ops_95, }, { .chip_id = BCM7445_DEVICE_ID, @@ -2946,6 +2967,7 @@ static const struct b53_chip_data b53_switch_chips[] = { .duplex_reg = B53_DUPLEX_STAT_GE, .jumbo_pm_reg = B53_JUMBO_PORT_MASK, .jumbo_size_reg = B53_JUMBO_MAX_SIZE, + .arl_ops = &b53_arl_ops_95, }, { .chip_id = BCM7278_DEVICE_ID, @@ -2959,6 +2981,7 @@ static const struct b53_chip_data b53_switch_chips[] = { .duplex_reg = B53_DUPLEX_STAT_GE, .jumbo_pm_reg = B53_JUMBO_PORT_MASK, .jumbo_size_reg = B53_JUMBO_MAX_SIZE, + .arl_ops = &b53_arl_ops_95, }, { .chip_id = BCM53134_DEVICE_ID, @@ -2973,6 +2996,7 @@ static const struct b53_chip_data b53_switch_chips[] = { .duplex_reg = B53_DUPLEX_STAT_GE, .jumbo_pm_reg = B53_JUMBO_PORT_MASK, .jumbo_size_reg = B53_JUMBO_MAX_SIZE, + .arl_ops = &b53_arl_ops_95, }, }; @@ -3001,6 +3025,7 @@ static int b53_switch_init(struct b53_device *dev) dev->num_vlans = chip->vlans; dev->num_arl_bins = chip->arl_bins; dev->num_arl_buckets = chip->arl_buckets; + dev->arl_ops = chip->arl_ops; break; } } diff --git a/drivers/net/dsa/b53/b53_priv.h b/drivers/net/dsa/b53/b53_priv.h index 2f44b3b6a0d9f..c6e2d5e41c758 100644 --- a/drivers/net/dsa/b53/b53_priv.h +++ b/drivers/net/dsa/b53/b53_priv.h @@ -58,6 +58,17 @@ struct b53_io_ops { bool link_up); }; +struct b53_arl_entry; + +struct b53_arl_ops { + void (*arl_read_entry)(struct b53_device *dev, + struct b53_arl_entry *ent, u8 idx); + void (*arl_write_entry)(struct b53_device *dev, + const struct b53_arl_entry *ent, u8 idx); + void (*arl_search_read)(struct b53_device *dev, u8 idx, + struct b53_arl_entry *ent); +}; + #define B53_INVALID_LANE 0xff enum { @@ -127,6 +138,7 @@ struct b53_device { struct mutex stats_mutex; struct mutex arl_mutex; const struct b53_io_ops *ops; + const struct b53_arl_ops *arl_ops; /* chip specific data */ u32 chip_id; @@ -371,6 +383,24 @@ static inline void b53_arl_from_entry_25(u64 *mac_vid, *mac_vid |= ARLTBL_AGE_25; } +static inline void b53_arl_read_entry(struct b53_device *dev, + struct b53_arl_entry *ent, u8 idx) +{ + dev->arl_ops->arl_read_entry(dev, ent, idx); +} + +static inline void b53_arl_write_entry(struct b53_device *dev, + const struct b53_arl_entry *ent, u8 idx) +{ + dev->arl_ops->arl_write_entry(dev, ent, idx); +} + +static inline void b53_arl_search_read(struct b53_device *dev, u8 idx, + struct b53_arl_entry *ent) +{ + dev->arl_ops->arl_search_read(dev, idx, ent); +} + #ifdef CONFIG_BCM47XX #include From c15c2c2b72acd25b249a10295088b52ceb8c5e3e Mon Sep 17 00:00:00 2001 From: Jonas Gorski Date: Fri, 7 Nov 2025 09:07:48 +0100 Subject: [PATCH 0890/2333] net: dsa: b53: add support for 5389/5397/5398 ARL entry format [ Upstream commit 300f78e8b6b7be17c2c78afeded75be68acb1aa7 ] BCM5389, BCM5397 and BCM5398 use a different ARL entry format with just a 16 bit fwdentry register, as well as different search control and data offsets. So add appropriate ops for them and switch those chips to use them. Signed-off-by: Jonas Gorski Reviewed-by: Florian Fainelli Link: https://patch.msgid.link/20251107080749.26936-8-jonas.gorski@gmail.com Signed-off-by: Jakub Kicinski Stable-dep-of: 8e46aacea426 ("net: dsa: b53: use same ARL search result offset for BCM5325/65") Signed-off-by: Sasha Levin --- drivers/net/dsa/b53/b53_common.c | 53 ++++++++++++++++++++++++++++++-- drivers/net/dsa/b53/b53_priv.h | 26 ++++++++++++++++ drivers/net/dsa/b53/b53_regs.h | 13 ++++++++ 3 files changed, 89 insertions(+), 3 deletions(-) diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c index 50ed9b7157197..dedbd53412871 100644 --- a/drivers/net/dsa/b53/b53_common.c +++ b/drivers/net/dsa/b53/b53_common.c @@ -1850,6 +1850,31 @@ static void b53_arl_write_entry_25(struct b53_device *dev, mac_vid); } +static void b53_arl_read_entry_89(struct b53_device *dev, + struct b53_arl_entry *ent, u8 idx) +{ + u64 mac_vid; + u16 fwd_entry; + + b53_read64(dev, B53_ARLIO_PAGE, B53_ARLTBL_MAC_VID_ENTRY(idx), + &mac_vid); + b53_read16(dev, B53_ARLIO_PAGE, B53_ARLTBL_DATA_ENTRY(idx), &fwd_entry); + b53_arl_to_entry_89(ent, mac_vid, fwd_entry); +} + +static void b53_arl_write_entry_89(struct b53_device *dev, + const struct b53_arl_entry *ent, u8 idx) +{ + u32 fwd_entry; + u64 mac_vid; + + b53_arl_from_entry_89(&mac_vid, &fwd_entry, ent); + b53_write64(dev, B53_ARLIO_PAGE, + B53_ARLTBL_MAC_VID_ENTRY(idx), mac_vid); + b53_write16(dev, B53_ARLIO_PAGE, + B53_ARLTBL_DATA_ENTRY(idx), fwd_entry); +} + static void b53_arl_read_entry_95(struct b53_device *dev, struct b53_arl_entry *ent, u8 idx) { @@ -2017,6 +2042,8 @@ static void b53_read_arl_srch_ctl(struct b53_device *dev, u8 *val) if (is5325(dev) || is5365(dev)) offset = B53_ARL_SRCH_CTL_25; + else if (dev->chip_id == BCM5389_DEVICE_ID || is5397_98(dev)) + offset = B53_ARL_SRCH_CTL_89; else offset = B53_ARL_SRCH_CTL; @@ -2029,6 +2056,8 @@ static void b53_write_arl_srch_ctl(struct b53_device *dev, u8 val) if (is5325(dev) || is5365(dev)) offset = B53_ARL_SRCH_CTL_25; + else if (dev->chip_id == BCM5389_DEVICE_ID || is5397_98(dev)) + offset = B53_ARL_SRCH_CTL_89; else offset = B53_ARL_SRCH_CTL; @@ -2074,6 +2103,18 @@ static void b53_arl_search_read_65(struct b53_device *dev, u8 idx, b53_arl_to_entry_25(ent, mac_vid); } +static void b53_arl_search_read_89(struct b53_device *dev, u8 idx, + struct b53_arl_entry *ent) +{ + u16 fwd_entry; + u64 mac_vid; + + b53_read64(dev, B53_ARLIO_PAGE, B53_ARL_SRCH_RSLT_MACVID_89, + &mac_vid); + b53_read16(dev, B53_ARLIO_PAGE, B53_ARL_SRCH_RSLT_89, &fwd_entry); + b53_arl_to_entry_89(ent, mac_vid, fwd_entry); +} + static void b53_arl_search_read_95(struct b53_device *dev, u8 idx, struct b53_arl_entry *ent) { @@ -2664,6 +2705,12 @@ static const struct b53_arl_ops b53_arl_ops_65 = { .arl_search_read = b53_arl_search_read_65, }; +static const struct b53_arl_ops b53_arl_ops_89 = { + .arl_read_entry = b53_arl_read_entry_89, + .arl_write_entry = b53_arl_write_entry_89, + .arl_search_read = b53_arl_search_read_89, +}; + static const struct b53_arl_ops b53_arl_ops_95 = { .arl_read_entry = b53_arl_read_entry_95, .arl_write_entry = b53_arl_write_entry_95, @@ -2728,7 +2775,7 @@ static const struct b53_chip_data b53_switch_chips[] = { .duplex_reg = B53_DUPLEX_STAT_GE, .jumbo_pm_reg = B53_JUMBO_PORT_MASK, .jumbo_size_reg = B53_JUMBO_MAX_SIZE, - .arl_ops = &b53_arl_ops_95, + .arl_ops = &b53_arl_ops_89, }, { .chip_id = BCM5395_DEVICE_ID, @@ -2756,7 +2803,7 @@ static const struct b53_chip_data b53_switch_chips[] = { .duplex_reg = B53_DUPLEX_STAT_GE, .jumbo_pm_reg = B53_JUMBO_PORT_MASK, .jumbo_size_reg = B53_JUMBO_MAX_SIZE, - .arl_ops = &b53_arl_ops_95, + .arl_ops = &b53_arl_ops_89, }, { .chip_id = BCM5398_DEVICE_ID, @@ -2770,7 +2817,7 @@ static const struct b53_chip_data b53_switch_chips[] = { .duplex_reg = B53_DUPLEX_STAT_GE, .jumbo_pm_reg = B53_JUMBO_PORT_MASK, .jumbo_size_reg = B53_JUMBO_MAX_SIZE, - .arl_ops = &b53_arl_ops_95, + .arl_ops = &b53_arl_ops_89, }, { .chip_id = BCM53101_DEVICE_ID, diff --git a/drivers/net/dsa/b53/b53_priv.h b/drivers/net/dsa/b53/b53_priv.h index c6e2d5e41c758..127ce7f6b16ba 100644 --- a/drivers/net/dsa/b53/b53_priv.h +++ b/drivers/net/dsa/b53/b53_priv.h @@ -353,6 +353,18 @@ static inline void b53_arl_to_entry_25(struct b53_arl_entry *ent, ent->vid = (mac_vid >> ARLTBL_VID_S_65) & ARLTBL_VID_MASK_25; } +static inline void b53_arl_to_entry_89(struct b53_arl_entry *ent, + u64 mac_vid, u16 fwd_entry) +{ + memset(ent, 0, sizeof(*ent)); + ent->port = fwd_entry & ARLTBL_DATA_PORT_ID_MASK_89; + ent->is_valid = !!(fwd_entry & ARLTBL_VALID_89); + ent->is_age = !!(fwd_entry & ARLTBL_AGE_89); + ent->is_static = !!(fwd_entry & ARLTBL_STATIC_89); + u64_to_ether_addr(mac_vid, ent->mac); + ent->vid = mac_vid >> ARLTBL_VID_S; +} + static inline void b53_arl_from_entry(u64 *mac_vid, u32 *fwd_entry, const struct b53_arl_entry *ent) { @@ -383,6 +395,20 @@ static inline void b53_arl_from_entry_25(u64 *mac_vid, *mac_vid |= ARLTBL_AGE_25; } +static inline void b53_arl_from_entry_89(u64 *mac_vid, u32 *fwd_entry, + const struct b53_arl_entry *ent) +{ + *mac_vid = ether_addr_to_u64(ent->mac); + *mac_vid |= (u64)(ent->vid & ARLTBL_VID_MASK) << ARLTBL_VID_S; + *fwd_entry = ent->port & ARLTBL_DATA_PORT_ID_MASK_89; + if (ent->is_valid) + *fwd_entry |= ARLTBL_VALID_89; + if (ent->is_static) + *fwd_entry |= ARLTBL_STATIC_89; + if (ent->is_age) + *fwd_entry |= ARLTBL_AGE_89; +} + static inline void b53_arl_read_entry(struct b53_device *dev, struct b53_arl_entry *ent, u8 idx) { diff --git a/drivers/net/dsa/b53/b53_regs.h b/drivers/net/dsa/b53/b53_regs.h index 8ce1ce72e9385..d9026cf865549 100644 --- a/drivers/net/dsa/b53/b53_regs.h +++ b/drivers/net/dsa/b53/b53_regs.h @@ -342,12 +342,20 @@ #define ARLTBL_STATIC BIT(15) #define ARLTBL_VALID BIT(16) +/* BCM5389 ARL Table Data Entry N Register format (16 bit) */ +#define ARLTBL_DATA_PORT_ID_MASK_89 GENMASK(8, 0) +#define ARLTBL_TC_MASK_89 GENMASK(12, 10) +#define ARLTBL_AGE_89 BIT(13) +#define ARLTBL_STATIC_89 BIT(14) +#define ARLTBL_VALID_89 BIT(15) + /* Maximum number of bin entries in the ARL for all switches */ #define B53_ARLTBL_MAX_BIN_ENTRIES 4 /* ARL Search Control Register (8 bit) */ #define B53_ARL_SRCH_CTL 0x50 #define B53_ARL_SRCH_CTL_25 0x20 +#define B53_ARL_SRCH_CTL_89 0x30 #define ARL_SRCH_VLID BIT(0) #define ARL_SRCH_STDN BIT(7) @@ -355,10 +363,12 @@ #define B53_ARL_SRCH_ADDR 0x51 #define B53_ARL_SRCH_ADDR_25 0x22 #define B53_ARL_SRCH_ADDR_65 0x24 +#define B53_ARL_SRCH_ADDR_89 0x31 #define ARL_ADDR_MASK GENMASK(14, 0) /* ARL Search MAC/VID Result (64 bit) */ #define B53_ARL_SRCH_RSTL_0_MACVID 0x60 +#define B53_ARL_SRCH_RSLT_MACVID_89 0x33 /* Single register search result on 5325 */ #define B53_ARL_SRCH_RSTL_0_MACVID_25 0x24 @@ -368,6 +378,9 @@ /* ARL Search Data Result (32 bit) */ #define B53_ARL_SRCH_RSTL_0 0x68 +/* BCM5389 ARL Search Data Result (16 bit) */ +#define B53_ARL_SRCH_RSLT_89 0x3b + #define B53_ARL_SRCH_RSTL_MACVID(x) (B53_ARL_SRCH_RSTL_0_MACVID + ((x) * 0x10)) #define B53_ARL_SRCH_RSTL(x) (B53_ARL_SRCH_RSTL_0 + ((x) * 0x10)) From e23860a4bf1e675f36eb706adc6ce8dc2365b075 Mon Sep 17 00:00:00 2001 From: Jonas Gorski Date: Fri, 28 Nov 2025 09:06:21 +0100 Subject: [PATCH 0891/2333] net: dsa: b53: use same ARL search result offset for BCM5325/65 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 8e46aacea4264bcb8d4265fb07577afff58ae78d ] BCM5365's search result is at the same offset as BCM5325's search result, and they (mostly) share the same format, so switch BCM5365 to BCM5325's arl ops. Fixes: c45655386e53 ("net: dsa: b53: add support for FDB operations on 5325/5365") Reviewed-by: Florian Fainelli Tested-by: Álvaro Fernández Rojas Signed-off-by: Jonas Gorski Link: https://patch.msgid.link/20251128080625.27181-4-jonas.gorski@gmail.com Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- drivers/net/dsa/b53/b53_common.c | 18 +----------------- drivers/net/dsa/b53/b53_regs.h | 4 +--- 2 files changed, 2 insertions(+), 20 deletions(-) diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c index dedbd53412871..68e9162087ab4 100644 --- a/drivers/net/dsa/b53/b53_common.c +++ b/drivers/net/dsa/b53/b53_common.c @@ -2093,16 +2093,6 @@ static void b53_arl_search_read_25(struct b53_device *dev, u8 idx, b53_arl_to_entry_25(ent, mac_vid); } -static void b53_arl_search_read_65(struct b53_device *dev, u8 idx, - struct b53_arl_entry *ent) -{ - u64 mac_vid; - - b53_read64(dev, B53_ARLIO_PAGE, B53_ARL_SRCH_RSTL_0_MACVID_65, - &mac_vid); - b53_arl_to_entry_25(ent, mac_vid); -} - static void b53_arl_search_read_89(struct b53_device *dev, u8 idx, struct b53_arl_entry *ent) { @@ -2699,12 +2689,6 @@ static const struct b53_arl_ops b53_arl_ops_25 = { .arl_search_read = b53_arl_search_read_25, }; -static const struct b53_arl_ops b53_arl_ops_65 = { - .arl_read_entry = b53_arl_read_entry_25, - .arl_write_entry = b53_arl_write_entry_25, - .arl_search_read = b53_arl_search_read_65, -}; - static const struct b53_arl_ops b53_arl_ops_89 = { .arl_read_entry = b53_arl_read_entry_89, .arl_write_entry = b53_arl_write_entry_89, @@ -2761,7 +2745,7 @@ static const struct b53_chip_data b53_switch_chips[] = { .arl_buckets = 1024, .imp_port = 5, .duplex_reg = B53_DUPLEX_STAT_FE, - .arl_ops = &b53_arl_ops_65, + .arl_ops = &b53_arl_ops_25, }, { .chip_id = BCM5389_DEVICE_ID, diff --git a/drivers/net/dsa/b53/b53_regs.h b/drivers/net/dsa/b53/b53_regs.h index d9026cf865549..f2a3696d122fa 100644 --- a/drivers/net/dsa/b53/b53_regs.h +++ b/drivers/net/dsa/b53/b53_regs.h @@ -370,10 +370,8 @@ #define B53_ARL_SRCH_RSTL_0_MACVID 0x60 #define B53_ARL_SRCH_RSLT_MACVID_89 0x33 -/* Single register search result on 5325 */ +/* Single register search result on 5325/5365 */ #define B53_ARL_SRCH_RSTL_0_MACVID_25 0x24 -/* Single register search result on 5365 */ -#define B53_ARL_SRCH_RSTL_0_MACVID_65 0x30 /* ARL Search Data Result (32 bit) */ #define B53_ARL_SRCH_RSTL_0 0x68 From e5a6a2475901d66bcf06778e4c091c4ca927ae62 Mon Sep 17 00:00:00 2001 From: Jonas Gorski Date: Fri, 28 Nov 2025 09:06:22 +0100 Subject: [PATCH 0892/2333] net: dsa: b53: fix CPU port unicast ARL entries for BCM5325/65 [ Upstream commit 85132103f700b1340fc17df8a981509d17bf4872 ] On BCM5325 and BCM5365, unicast ARL entries use 8 as the value for the CPU port, so we need to translate it to/from 5 as used for the CPU port at most other places. Fixes: c45655386e53 ("net: dsa: b53: add support for FDB operations on 5325/5365") Signed-off-by: Jonas Gorski Reviewed-by: Florian Fainelli Link: https://patch.msgid.link/20251128080625.27181-5-jonas.gorski@gmail.com Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- drivers/net/dsa/b53/b53_priv.h | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/net/dsa/b53/b53_priv.h b/drivers/net/dsa/b53/b53_priv.h index 127ce7f6b16ba..80e7dd6169b47 100644 --- a/drivers/net/dsa/b53/b53_priv.h +++ b/drivers/net/dsa/b53/b53_priv.h @@ -344,12 +344,14 @@ static inline void b53_arl_to_entry_25(struct b53_arl_entry *ent, u64 mac_vid) { memset(ent, 0, sizeof(*ent)); - ent->port = (mac_vid >> ARLTBL_DATA_PORT_ID_S_25) & - ARLTBL_DATA_PORT_ID_MASK_25; ent->is_valid = !!(mac_vid & ARLTBL_VALID_25); ent->is_age = !!(mac_vid & ARLTBL_AGE_25); ent->is_static = !!(mac_vid & ARLTBL_STATIC_25); u64_to_ether_addr(mac_vid, ent->mac); + ent->port = (mac_vid >> ARLTBL_DATA_PORT_ID_S_25) & + ARLTBL_DATA_PORT_ID_MASK_25; + if (is_unicast_ether_addr(ent->mac) && ent->port == B53_CPU_PORT) + ent->port = B53_CPU_PORT_25; ent->vid = (mac_vid >> ARLTBL_VID_S_65) & ARLTBL_VID_MASK_25; } @@ -383,8 +385,11 @@ static inline void b53_arl_from_entry_25(u64 *mac_vid, const struct b53_arl_entry *ent) { *mac_vid = ether_addr_to_u64(ent->mac); - *mac_vid |= (u64)(ent->port & ARLTBL_DATA_PORT_ID_MASK_25) << - ARLTBL_DATA_PORT_ID_S_25; + if (is_unicast_ether_addr(ent->mac) && ent->port == B53_CPU_PORT_25) + *mac_vid |= (u64)B53_CPU_PORT << ARLTBL_DATA_PORT_ID_S_25; + else + *mac_vid |= (u64)(ent->port & ARLTBL_DATA_PORT_ID_MASK_25) << + ARLTBL_DATA_PORT_ID_S_25; *mac_vid |= (u64)(ent->vid & ARLTBL_VID_MASK_25) << ARLTBL_VID_S_65; if (ent->is_valid) From 8e881dfd5255f7a435e3c31c6123fed35154451a Mon Sep 17 00:00:00 2001 From: Jonas Gorski Date: Fri, 7 Nov 2025 09:07:49 +0100 Subject: [PATCH 0893/2333] net: dsa: b53: add support for bcm63xx ARL entry format [ Upstream commit 2b3013ac03028a2364d8779719bb6bfbc0212435 ] The ARL registers of BCM63XX embedded switches are somewhat unique. The normal ARL table access registers have the same format as BCM5389, but the ARL search registers differ: * SRCH_CTL is at the same offset of BCM5389, but 16 bits wide. It does not have more fields, just needs to be accessed by a 16 bit read. * SRCH_RSLT_MACVID and SRCH_RSLT are aligned to 32 bit, and have shifted offsets. * SRCH_RSLT has a different format than the normal ARL data entry register. * There is only one set of ENTRY_N registers, implying a 1 bin layout. So add appropriate ops for bcm63xx and let it use it. Signed-off-by: Jonas Gorski Reviewed-by: Florian Fainelli Link: https://patch.msgid.link/20251107080749.26936-9-jonas.gorski@gmail.com Signed-off-by: Jakub Kicinski Stable-dep-of: 3b08863469aa ("net: dsa: b53: fix BCM5325/65 ARL entry multicast port masks") Signed-off-by: Sasha Levin --- drivers/net/dsa/b53/b53_common.c | 44 +++++++++++++++++++++++++++----- drivers/net/dsa/b53/b53_priv.h | 15 +++++++++++ drivers/net/dsa/b53/b53_regs.h | 9 +++++++ 3 files changed, 61 insertions(+), 7 deletions(-) diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c index 68e9162087ab4..db1ed8c9c536e 100644 --- a/drivers/net/dsa/b53/b53_common.c +++ b/drivers/net/dsa/b53/b53_common.c @@ -2042,12 +2042,20 @@ static void b53_read_arl_srch_ctl(struct b53_device *dev, u8 *val) if (is5325(dev) || is5365(dev)) offset = B53_ARL_SRCH_CTL_25; - else if (dev->chip_id == BCM5389_DEVICE_ID || is5397_98(dev)) + else if (dev->chip_id == BCM5389_DEVICE_ID || is5397_98(dev) || + is63xx(dev)) offset = B53_ARL_SRCH_CTL_89; else offset = B53_ARL_SRCH_CTL; - b53_read8(dev, B53_ARLIO_PAGE, offset, val); + if (is63xx(dev)) { + u16 val16; + + b53_read16(dev, B53_ARLIO_PAGE, offset, &val16); + *val = val16 & 0xff; + } else { + b53_read8(dev, B53_ARLIO_PAGE, offset, val); + } } static void b53_write_arl_srch_ctl(struct b53_device *dev, u8 val) @@ -2056,12 +2064,16 @@ static void b53_write_arl_srch_ctl(struct b53_device *dev, u8 val) if (is5325(dev) || is5365(dev)) offset = B53_ARL_SRCH_CTL_25; - else if (dev->chip_id == BCM5389_DEVICE_ID || is5397_98(dev)) + else if (dev->chip_id == BCM5389_DEVICE_ID || is5397_98(dev) || + is63xx(dev)) offset = B53_ARL_SRCH_CTL_89; else offset = B53_ARL_SRCH_CTL; - b53_write8(dev, B53_ARLIO_PAGE, offset, val); + if (is63xx(dev)) + b53_write16(dev, B53_ARLIO_PAGE, offset, val); + else + b53_write8(dev, B53_ARLIO_PAGE, offset, val); } static int b53_arl_search_wait(struct b53_device *dev) @@ -2105,6 +2117,18 @@ static void b53_arl_search_read_89(struct b53_device *dev, u8 idx, b53_arl_to_entry_89(ent, mac_vid, fwd_entry); } +static void b53_arl_search_read_63xx(struct b53_device *dev, u8 idx, + struct b53_arl_entry *ent) +{ + u16 fwd_entry; + u64 mac_vid; + + b53_read64(dev, B53_ARLIO_PAGE, B53_ARL_SRCH_RSLT_MACVID_63XX, + &mac_vid); + b53_read16(dev, B53_ARLIO_PAGE, B53_ARL_SRCH_RSLT_63XX, &fwd_entry); + b53_arl_search_to_entry_63xx(ent, mac_vid, fwd_entry); +} + static void b53_arl_search_read_95(struct b53_device *dev, u8 idx, struct b53_arl_entry *ent) { @@ -2695,6 +2719,12 @@ static const struct b53_arl_ops b53_arl_ops_89 = { .arl_search_read = b53_arl_search_read_89, }; +static const struct b53_arl_ops b53_arl_ops_63xx = { + .arl_read_entry = b53_arl_read_entry_89, + .arl_write_entry = b53_arl_write_entry_89, + .arl_search_read = b53_arl_search_read_63xx, +}; + static const struct b53_arl_ops b53_arl_ops_95 = { .arl_read_entry = b53_arl_read_entry_95, .arl_write_entry = b53_arl_write_entry_95, @@ -2864,14 +2894,14 @@ static const struct b53_chip_data b53_switch_chips[] = { .dev_name = "BCM63xx", .vlans = 4096, .enabled_ports = 0, /* pdata must provide them */ - .arl_bins = 4, - .arl_buckets = 1024, + .arl_bins = 1, + .arl_buckets = 4096, .imp_port = 8, .vta_regs = B53_VTA_REGS_63XX, .duplex_reg = B53_DUPLEX_STAT_63XX, .jumbo_pm_reg = B53_JUMBO_PORT_MASK_63XX, .jumbo_size_reg = B53_JUMBO_MAX_SIZE_63XX, - .arl_ops = &b53_arl_ops_95, + .arl_ops = &b53_arl_ops_63xx, }, { .chip_id = BCM53010_DEVICE_ID, diff --git a/drivers/net/dsa/b53/b53_priv.h b/drivers/net/dsa/b53/b53_priv.h index 80e7dd6169b47..ae2c615c088ed 100644 --- a/drivers/net/dsa/b53/b53_priv.h +++ b/drivers/net/dsa/b53/b53_priv.h @@ -414,6 +414,21 @@ static inline void b53_arl_from_entry_89(u64 *mac_vid, u32 *fwd_entry, *fwd_entry |= ARLTBL_AGE_89; } +static inline void b53_arl_search_to_entry_63xx(struct b53_arl_entry *ent, + u64 mac_vid, u16 fwd_entry) +{ + memset(ent, 0, sizeof(*ent)); + u64_to_ether_addr(mac_vid, ent->mac); + ent->vid = mac_vid >> ARLTBL_VID_S; + + ent->port = fwd_entry & ARL_SRST_PORT_ID_MASK_63XX; + ent->port >>= 1; + + ent->is_age = !!(fwd_entry & ARL_SRST_AGE_63XX); + ent->is_static = !!(fwd_entry & ARL_SRST_STATIC_63XX); + ent->is_valid = 1; +} + static inline void b53_arl_read_entry(struct b53_device *dev, struct b53_arl_entry *ent, u8 idx) { diff --git a/drivers/net/dsa/b53/b53_regs.h b/drivers/net/dsa/b53/b53_regs.h index f2a3696d122fa..fcedd5fb00337 100644 --- a/drivers/net/dsa/b53/b53_regs.h +++ b/drivers/net/dsa/b53/b53_regs.h @@ -364,11 +364,13 @@ #define B53_ARL_SRCH_ADDR_25 0x22 #define B53_ARL_SRCH_ADDR_65 0x24 #define B53_ARL_SRCH_ADDR_89 0x31 +#define B53_ARL_SRCH_ADDR_63XX 0x32 #define ARL_ADDR_MASK GENMASK(14, 0) /* ARL Search MAC/VID Result (64 bit) */ #define B53_ARL_SRCH_RSTL_0_MACVID 0x60 #define B53_ARL_SRCH_RSLT_MACVID_89 0x33 +#define B53_ARL_SRCH_RSLT_MACVID_63XX 0x34 /* Single register search result on 5325/5365 */ #define B53_ARL_SRCH_RSTL_0_MACVID_25 0x24 @@ -382,6 +384,13 @@ #define B53_ARL_SRCH_RSTL_MACVID(x) (B53_ARL_SRCH_RSTL_0_MACVID + ((x) * 0x10)) #define B53_ARL_SRCH_RSTL(x) (B53_ARL_SRCH_RSTL_0 + ((x) * 0x10)) +/* 63XX ARL Search Data Result (16 bit) */ +#define B53_ARL_SRCH_RSLT_63XX 0x3c +#define ARL_SRST_PORT_ID_MASK_63XX GENMASK(9, 1) +#define ARL_SRST_TC_MASK_63XX GENMASK(13, 11) +#define ARL_SRST_AGE_63XX BIT(14) +#define ARL_SRST_STATIC_63XX BIT(15) + /************************************************************************* * IEEE 802.1X Registers *************************************************************************/ From 0d0116335eba7f83fd756d2e301fbc0f64152961 Mon Sep 17 00:00:00 2001 From: Jonas Gorski Date: Fri, 28 Nov 2025 09:06:23 +0100 Subject: [PATCH 0894/2333] net: dsa: b53: fix BCM5325/65 ARL entry multicast port masks [ Upstream commit 3b08863469aa6028ac7c3120966f4e2f6051cf6b ] We currently use the mask 0xf for writing and reading b53_entry::port, but this is only correct for unicast ARL entries. Multicast ARL entries use a bitmask, and 0xf is not enough space for ports > 3, which includes the CPU port. So extend the mask accordingly to also fit port 4 (bit 4) and MII (bit 5). According to the datasheet the multicast port mask is [60:48], making it 12 bit wide, but bits 60-55 are reserved anyway, and collide with the priority field at [60:59], so I am not sure if this is valid. Therefore leave it at the actual used range, [53:48]. The ARL search result register differs a bit, and there the mask is only [52:48], so only spanning the user ports. The MII port bit is contained in the Search Result Extension register. So create a separate search result parse function that properly handles this. Fixes: c45655386e53 ("net: dsa: b53: add support for FDB operations on 5325/5365") Reviewed-by: Florian Fainelli Signed-off-by: Jonas Gorski Link: https://patch.msgid.link/20251128080625.27181-6-jonas.gorski@gmail.com Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- drivers/net/dsa/b53/b53_common.c | 4 +++- drivers/net/dsa/b53/b53_priv.h | 25 +++++++++++++++++++++---- drivers/net/dsa/b53/b53_regs.h | 8 +++++++- 3 files changed, 31 insertions(+), 6 deletions(-) diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c index db1ed8c9c536e..5544e8e9c6446 100644 --- a/drivers/net/dsa/b53/b53_common.c +++ b/drivers/net/dsa/b53/b53_common.c @@ -2099,10 +2099,12 @@ static void b53_arl_search_read_25(struct b53_device *dev, u8 idx, struct b53_arl_entry *ent) { u64 mac_vid; + u8 ext; + b53_read8(dev, B53_ARLIO_PAGE, B53_ARL_SRCH_RSLT_EXT_25, &ext); b53_read64(dev, B53_ARLIO_PAGE, B53_ARL_SRCH_RSTL_0_MACVID_25, &mac_vid); - b53_arl_to_entry_25(ent, mac_vid); + b53_arl_search_to_entry_25(ent, mac_vid, ext); } static void b53_arl_search_read_89(struct b53_device *dev, u8 idx, diff --git a/drivers/net/dsa/b53/b53_priv.h b/drivers/net/dsa/b53/b53_priv.h index ae2c615c088ed..f4afbfcc345e6 100644 --- a/drivers/net/dsa/b53/b53_priv.h +++ b/drivers/net/dsa/b53/b53_priv.h @@ -348,8 +348,8 @@ static inline void b53_arl_to_entry_25(struct b53_arl_entry *ent, ent->is_age = !!(mac_vid & ARLTBL_AGE_25); ent->is_static = !!(mac_vid & ARLTBL_STATIC_25); u64_to_ether_addr(mac_vid, ent->mac); - ent->port = (mac_vid >> ARLTBL_DATA_PORT_ID_S_25) & - ARLTBL_DATA_PORT_ID_MASK_25; + ent->port = (mac_vid & ARLTBL_DATA_PORT_ID_MASK_25) >> + ARLTBL_DATA_PORT_ID_S_25; if (is_unicast_ether_addr(ent->mac) && ent->port == B53_CPU_PORT) ent->port = B53_CPU_PORT_25; ent->vid = (mac_vid >> ARLTBL_VID_S_65) & ARLTBL_VID_MASK_25; @@ -388,8 +388,8 @@ static inline void b53_arl_from_entry_25(u64 *mac_vid, if (is_unicast_ether_addr(ent->mac) && ent->port == B53_CPU_PORT_25) *mac_vid |= (u64)B53_CPU_PORT << ARLTBL_DATA_PORT_ID_S_25; else - *mac_vid |= (u64)(ent->port & ARLTBL_DATA_PORT_ID_MASK_25) << - ARLTBL_DATA_PORT_ID_S_25; + *mac_vid |= ((u64)ent->port << ARLTBL_DATA_PORT_ID_S_25) & + ARLTBL_DATA_PORT_ID_MASK_25; *mac_vid |= (u64)(ent->vid & ARLTBL_VID_MASK_25) << ARLTBL_VID_S_65; if (ent->is_valid) @@ -414,6 +414,23 @@ static inline void b53_arl_from_entry_89(u64 *mac_vid, u32 *fwd_entry, *fwd_entry |= ARLTBL_AGE_89; } +static inline void b53_arl_search_to_entry_25(struct b53_arl_entry *ent, + u64 mac_vid, u8 ext) +{ + memset(ent, 0, sizeof(*ent)); + ent->is_valid = !!(mac_vid & ARLTBL_VALID_25); + ent->is_age = !!(mac_vid & ARLTBL_AGE_25); + ent->is_static = !!(mac_vid & ARLTBL_STATIC_25); + u64_to_ether_addr(mac_vid, ent->mac); + ent->vid = (mac_vid >> ARLTBL_VID_S_65) & ARLTBL_VID_MASK_25; + ent->port = (mac_vid & ARL_SRCH_RSLT_PORT_ID_MASK_25) >> + ARL_SRCH_RSLT_PORT_ID_S_25; + if (is_multicast_ether_addr(ent->mac) && (ext & ARL_SRCH_RSLT_EXT_MC_MII)) + ent->port |= BIT(B53_CPU_PORT_25); + else if (!is_multicast_ether_addr(ent->mac) && ent->port == B53_CPU_PORT) + ent->port = B53_CPU_PORT_25; +} + static inline void b53_arl_search_to_entry_63xx(struct b53_arl_entry *ent, u64 mac_vid, u16 fwd_entry) { diff --git a/drivers/net/dsa/b53/b53_regs.h b/drivers/net/dsa/b53/b53_regs.h index fcedd5fb00337..e0379e70900b7 100644 --- a/drivers/net/dsa/b53/b53_regs.h +++ b/drivers/net/dsa/b53/b53_regs.h @@ -328,7 +328,7 @@ #define ARLTBL_VID_MASK_25 0xff #define ARLTBL_VID_MASK 0xfff #define ARLTBL_DATA_PORT_ID_S_25 48 -#define ARLTBL_DATA_PORT_ID_MASK_25 0xf +#define ARLTBL_DATA_PORT_ID_MASK_25 GENMASK_ULL(53, 48) #define ARLTBL_VID_S_65 53 #define ARLTBL_AGE_25 BIT_ULL(61) #define ARLTBL_STATIC_25 BIT_ULL(62) @@ -374,6 +374,12 @@ /* Single register search result on 5325/5365 */ #define B53_ARL_SRCH_RSTL_0_MACVID_25 0x24 +#define ARL_SRCH_RSLT_PORT_ID_S_25 48 +#define ARL_SRCH_RSLT_PORT_ID_MASK_25 GENMASK_ULL(52, 48) + +/* BCM5325/5365 Search result extend register (8 bit) */ +#define B53_ARL_SRCH_RSLT_EXT_25 0x2c +#define ARL_SRCH_RSLT_EXT_MC_MII BIT(2) /* ARL Search Data Result (32 bit) */ #define B53_ARL_SRCH_RSTL_0 0x68 From b07e2f191d88d3007d53495b82fbd2d23e8273c4 Mon Sep 17 00:00:00 2001 From: Jonas Gorski Date: Fri, 28 Nov 2025 09:06:24 +0100 Subject: [PATCH 0895/2333] net: dsa: b53: fix BCM5325/65 ARL entry VIDs [ Upstream commit d39514e6a2d14f57830d649e2bf03b49612c2f73 ] BCM5325/65's ARL entry registers do not contain the VID, only the search result register does. ARL entries have a separate VID entry register for the index into the VLAN table. So make ARL entry accessors use the VID entry registers instead, and move the VLAN ID field definition to the search register definition. Fixes: c45655386e53 ("net: dsa: b53: add support for FDB operations on 5325/5365") Signed-off-by: Jonas Gorski Reviewed-by: Florian Fainelli Link: https://patch.msgid.link/20251128080625.27181-7-jonas.gorski@gmail.com Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- drivers/net/dsa/b53/b53_common.c | 9 +++++++-- drivers/net/dsa/b53/b53_priv.h | 12 ++++++------ drivers/net/dsa/b53/b53_regs.h | 7 +++++-- 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c index 5544e8e9c6446..62cafced758e7 100644 --- a/drivers/net/dsa/b53/b53_common.c +++ b/drivers/net/dsa/b53/b53_common.c @@ -1833,19 +1833,24 @@ static int b53_arl_rw_op(struct b53_device *dev, unsigned int op) static void b53_arl_read_entry_25(struct b53_device *dev, struct b53_arl_entry *ent, u8 idx) { + u8 vid_entry; u64 mac_vid; + b53_read8(dev, B53_ARLIO_PAGE, B53_ARLTBL_VID_ENTRY_25(idx), + &vid_entry); b53_read64(dev, B53_ARLIO_PAGE, B53_ARLTBL_MAC_VID_ENTRY(idx), &mac_vid); - b53_arl_to_entry_25(ent, mac_vid); + b53_arl_to_entry_25(ent, mac_vid, vid_entry); } static void b53_arl_write_entry_25(struct b53_device *dev, const struct b53_arl_entry *ent, u8 idx) { + u8 vid_entry; u64 mac_vid; - b53_arl_from_entry_25(&mac_vid, ent); + b53_arl_from_entry_25(&mac_vid, &vid_entry, ent); + b53_write8(dev, B53_ARLIO_PAGE, B53_ARLTBL_VID_ENTRY_25(idx), vid_entry); b53_write64(dev, B53_ARLIO_PAGE, B53_ARLTBL_MAC_VID_ENTRY(idx), mac_vid); } diff --git a/drivers/net/dsa/b53/b53_priv.h b/drivers/net/dsa/b53/b53_priv.h index f4afbfcc345e6..bd6849e5bb939 100644 --- a/drivers/net/dsa/b53/b53_priv.h +++ b/drivers/net/dsa/b53/b53_priv.h @@ -341,7 +341,7 @@ static inline void b53_arl_to_entry(struct b53_arl_entry *ent, } static inline void b53_arl_to_entry_25(struct b53_arl_entry *ent, - u64 mac_vid) + u64 mac_vid, u8 vid_entry) { memset(ent, 0, sizeof(*ent)); ent->is_valid = !!(mac_vid & ARLTBL_VALID_25); @@ -352,7 +352,7 @@ static inline void b53_arl_to_entry_25(struct b53_arl_entry *ent, ARLTBL_DATA_PORT_ID_S_25; if (is_unicast_ether_addr(ent->mac) && ent->port == B53_CPU_PORT) ent->port = B53_CPU_PORT_25; - ent->vid = (mac_vid >> ARLTBL_VID_S_65) & ARLTBL_VID_MASK_25; + ent->vid = vid_entry; } static inline void b53_arl_to_entry_89(struct b53_arl_entry *ent, @@ -381,7 +381,7 @@ static inline void b53_arl_from_entry(u64 *mac_vid, u32 *fwd_entry, *fwd_entry |= ARLTBL_AGE; } -static inline void b53_arl_from_entry_25(u64 *mac_vid, +static inline void b53_arl_from_entry_25(u64 *mac_vid, u8 *vid_entry, const struct b53_arl_entry *ent) { *mac_vid = ether_addr_to_u64(ent->mac); @@ -390,14 +390,13 @@ static inline void b53_arl_from_entry_25(u64 *mac_vid, else *mac_vid |= ((u64)ent->port << ARLTBL_DATA_PORT_ID_S_25) & ARLTBL_DATA_PORT_ID_MASK_25; - *mac_vid |= (u64)(ent->vid & ARLTBL_VID_MASK_25) << - ARLTBL_VID_S_65; if (ent->is_valid) *mac_vid |= ARLTBL_VALID_25; if (ent->is_static) *mac_vid |= ARLTBL_STATIC_25; if (ent->is_age) *mac_vid |= ARLTBL_AGE_25; + *vid_entry = ent->vid; } static inline void b53_arl_from_entry_89(u64 *mac_vid, u32 *fwd_entry, @@ -422,7 +421,8 @@ static inline void b53_arl_search_to_entry_25(struct b53_arl_entry *ent, ent->is_age = !!(mac_vid & ARLTBL_AGE_25); ent->is_static = !!(mac_vid & ARLTBL_STATIC_25); u64_to_ether_addr(mac_vid, ent->mac); - ent->vid = (mac_vid >> ARLTBL_VID_S_65) & ARLTBL_VID_MASK_25; + ent->vid = (mac_vid & ARL_SRCH_RSLT_VID_MASK_25) >> + ARL_SRCH_RSLT_VID_S_25; ent->port = (mac_vid & ARL_SRCH_RSLT_PORT_ID_MASK_25) >> ARL_SRCH_RSLT_PORT_ID_S_25; if (is_multicast_ether_addr(ent->mac) && (ext & ARL_SRCH_RSLT_EXT_MC_MII)) diff --git a/drivers/net/dsa/b53/b53_regs.h b/drivers/net/dsa/b53/b53_regs.h index e0379e70900b7..b6fe7d207a2c1 100644 --- a/drivers/net/dsa/b53/b53_regs.h +++ b/drivers/net/dsa/b53/b53_regs.h @@ -325,11 +325,9 @@ #define B53_ARLTBL_MAC_VID_ENTRY(n) ((0x10 * (n)) + 0x10) #define ARLTBL_MAC_MASK 0xffffffffffffULL #define ARLTBL_VID_S 48 -#define ARLTBL_VID_MASK_25 0xff #define ARLTBL_VID_MASK 0xfff #define ARLTBL_DATA_PORT_ID_S_25 48 #define ARLTBL_DATA_PORT_ID_MASK_25 GENMASK_ULL(53, 48) -#define ARLTBL_VID_S_65 53 #define ARLTBL_AGE_25 BIT_ULL(61) #define ARLTBL_STATIC_25 BIT_ULL(62) #define ARLTBL_VALID_25 BIT_ULL(63) @@ -349,6 +347,9 @@ #define ARLTBL_STATIC_89 BIT(14) #define ARLTBL_VALID_89 BIT(15) +/* BCM5325/BCM565 ARL Table VID Entry N Registers (8 bit) */ +#define B53_ARLTBL_VID_ENTRY_25(n) ((0x2 * (n)) + 0x30) + /* Maximum number of bin entries in the ARL for all switches */ #define B53_ARLTBL_MAX_BIN_ENTRIES 4 @@ -376,6 +377,8 @@ #define B53_ARL_SRCH_RSTL_0_MACVID_25 0x24 #define ARL_SRCH_RSLT_PORT_ID_S_25 48 #define ARL_SRCH_RSLT_PORT_ID_MASK_25 GENMASK_ULL(52, 48) +#define ARL_SRCH_RSLT_VID_S_25 53 +#define ARL_SRCH_RSLT_VID_MASK_25 GENMASK_ULL(60, 53) /* BCM5325/5365 Search result extend register (8 bit) */ #define B53_ARL_SRCH_RSLT_EXT_25 0x2c From 4a7f375f625d466c8305585f9201abda90006174 Mon Sep 17 00:00:00 2001 From: Xiaoliang Yang Date: Sun, 30 Nov 2025 15:16:44 +0200 Subject: [PATCH 0896/2333] net: hsr: create an API to get hsr port type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit a0244e76213980f3b9bb5d40b0b6705fcf24230d ] Since the introduction of HSR_PT_INTERLINK in commit 5055cccfc2d1 ("net: hsr: Provide RedBox support (HSR-SAN)"), we see that different port types require different settings for hardware offload, which was not the case before when we only had HSR_PT_SLAVE_A and HSR_PT_SLAVE_B. But there is currently no way to know which port is which type, so create the hsr_get_port_type() API function and export it. When hsr_get_port_type() is called from the device driver, the port can must be found in the HSR port list. An important use case is for this function to work from offloading drivers' NETDEV_CHANGEUPPER handler, which is triggered by hsr_portdev_setup() -> netdev_master_upper_dev_link(). Therefore, we need to move the addition of the hsr_port to the HSR port list prior to calling hsr_portdev_setup(). This makes the error restoration path also more similar to hsr_del_port(), where kfree_rcu(port) is already used. Cc: Sebastian Andrzej Siewior Cc: Lukasz Majewski Signed-off-by: Xiaoliang Yang Signed-off-by: Vladimir Oltean Reviewed-by: Łukasz Majewski Link: https://patch.msgid.link/20251130131657.65080-3-vladimir.oltean@nxp.com Signed-off-by: Jakub Kicinski Stable-dep-of: 30296ac76426 ("net: dsa: xrs700x: reject unsupported HSR configurations") Signed-off-by: Sasha Levin --- include/linux/if_hsr.h | 9 +++++++++ net/hsr/hsr_device.c | 20 ++++++++++++++++++++ net/hsr/hsr_slave.c | 7 ++++--- 3 files changed, 33 insertions(+), 3 deletions(-) diff --git a/include/linux/if_hsr.h b/include/linux/if_hsr.h index d7941fd880329..f4cf2dd36d193 100644 --- a/include/linux/if_hsr.h +++ b/include/linux/if_hsr.h @@ -43,6 +43,8 @@ extern bool is_hsr_master(struct net_device *dev); extern int hsr_get_version(struct net_device *dev, enum hsr_version *ver); struct net_device *hsr_get_port_ndev(struct net_device *ndev, enum hsr_port_type pt); +int hsr_get_port_type(struct net_device *hsr_dev, struct net_device *dev, + enum hsr_port_type *type); #else static inline bool is_hsr_master(struct net_device *dev) { @@ -59,6 +61,13 @@ static inline struct net_device *hsr_get_port_ndev(struct net_device *ndev, { return ERR_PTR(-EINVAL); } + +static inline int hsr_get_port_type(struct net_device *hsr_dev, + struct net_device *dev, + enum hsr_port_type *type) +{ + return -EINVAL; +} #endif /* CONFIG_HSR */ #endif /*_LINUX_IF_HSR_H_*/ diff --git a/net/hsr/hsr_device.c b/net/hsr/hsr_device.c index 492cbc78ab75a..d1bfc49b5f017 100644 --- a/net/hsr/hsr_device.c +++ b/net/hsr/hsr_device.c @@ -690,6 +690,26 @@ struct net_device *hsr_get_port_ndev(struct net_device *ndev, } EXPORT_SYMBOL(hsr_get_port_ndev); +int hsr_get_port_type(struct net_device *hsr_dev, struct net_device *dev, + enum hsr_port_type *type) +{ + struct hsr_priv *hsr = netdev_priv(hsr_dev); + struct hsr_port *port; + + rcu_read_lock(); + hsr_for_each_port(hsr, port) { + if (port->dev == dev) { + *type = port->type; + rcu_read_unlock(); + return 0; + } + } + rcu_read_unlock(); + + return -EINVAL; +} +EXPORT_SYMBOL(hsr_get_port_type); + /* Default multicast address for HSR Supervision frames */ static const unsigned char def_multicast_addr[ETH_ALEN] __aligned(2) = { 0x01, 0x15, 0x4e, 0x00, 0x01, 0x00 diff --git a/net/hsr/hsr_slave.c b/net/hsr/hsr_slave.c index 8177ac6c2d26d..afe06ba00ea44 100644 --- a/net/hsr/hsr_slave.c +++ b/net/hsr/hsr_slave.c @@ -207,14 +207,14 @@ int hsr_add_port(struct hsr_priv *hsr, struct net_device *dev, port->type = type; ether_addr_copy(port->original_macaddress, dev->dev_addr); + list_add_tail_rcu(&port->port_list, &hsr->ports); + if (type != HSR_PT_MASTER) { res = hsr_portdev_setup(hsr, dev, port, extack); if (res) goto fail_dev_setup; } - list_add_tail_rcu(&port->port_list, &hsr->ports); - master = hsr_port_get_hsr(hsr, HSR_PT_MASTER); netdev_update_features(master->dev); dev_set_mtu(master->dev, hsr_get_max_mtu(hsr)); @@ -222,7 +222,8 @@ int hsr_add_port(struct hsr_priv *hsr, struct net_device *dev, return 0; fail_dev_setup: - kfree(port); + list_del_rcu(&port->port_list); + kfree_rcu(port, rcu); return res; } From 1ce413fd4d0459a6e42a6efbeba634c1072bc00f Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Sun, 30 Nov 2025 15:16:46 +0200 Subject: [PATCH 0897/2333] net: dsa: xrs700x: reject unsupported HSR configurations [ Upstream commit 30296ac7642652428396222e720718f2661e9425 ] As discussed here: https://lore.kernel.org/netdev/20240620090210.drop6jwh7e5qw556@skbuf/ the fact is that the xrs700x.c driver only supports offloading HSR_PT_SLAVE_A and HSR_PT_SLAVE_B (which were the only port types at the time the offload was written, _for this driver_). Up until now, the API did not explicitly tell offloading drivers what port has what role. So xrs700x can get confused and think that it can support a configuration which it actually can't. There was a table in the attached link which gave an example: $ ip link add name hsr0 type hsr slave1 swp0 slave2 swp1 \ interlink swp2 supervision 45 version 1 HSR_PT_SLAVE_A HSR_PT_SLAVE_B HSR_PT_INTERLINK ---------------------------------------------------------------- user space 0 1 2 requests ---------------------------------------------------------------- XRS700X driver 1 2 - understands The switch would act as if the ring ports were swp1 and swp2. Now that we have explicit hsr_get_port_type() API, let's use that to work around the unintended semantical changes of the offloading API brought by the introduction of interlink ports in HSR. Fixes: 5055cccfc2d1 ("net: hsr: Provide RedBox support (HSR-SAN)") Cc: Lukasz Majewski Signed-off-by: Vladimir Oltean Reviewed-by: George McCollister Link: https://patch.msgid.link/20251130131657.65080-5-vladimir.oltean@nxp.com Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- drivers/net/dsa/xrs700x/xrs700x.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/net/dsa/xrs700x/xrs700x.c b/drivers/net/dsa/xrs700x/xrs700x.c index 4dbcc49a9e526..0a05f4156ef4d 100644 --- a/drivers/net/dsa/xrs700x/xrs700x.c +++ b/drivers/net/dsa/xrs700x/xrs700x.c @@ -566,6 +566,7 @@ static int xrs700x_hsr_join(struct dsa_switch *ds, int port, struct xrs700x *priv = ds->priv; struct net_device *user; int ret, i, hsr_pair[2]; + enum hsr_port_type type; enum hsr_version ver; bool fwd = false; @@ -589,6 +590,16 @@ static int xrs700x_hsr_join(struct dsa_switch *ds, int port, return -EOPNOTSUPP; } + ret = hsr_get_port_type(hsr, dsa_to_port(ds, port)->user, &type); + if (ret) + return ret; + + if (type != HSR_PT_SLAVE_A && type != HSR_PT_SLAVE_B) { + NL_SET_ERR_MSG_MOD(extack, + "Only HSR slave ports can be offloaded"); + return -EOPNOTSUPP; + } + dsa_hsr_foreach_port(dp, ds, hsr) { if (dp->index != port) { partner = dp; From 3ed6c458530a547ed0c9ea0b02b19bab620be88b Mon Sep 17 00:00:00 2001 From: Xiang Mei Date: Thu, 27 Nov 2025 17:14:14 -0700 Subject: [PATCH 0898/2333] net/sched: sch_cake: Fix incorrect qlen reduction in cake_drop MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 9fefc78f7f02d71810776fdeb119a05a946a27cc ] In cake_drop(), qdisc_tree_reduce_backlog() is used to update the qlen and backlog of the qdisc hierarchy. Its caller, cake_enqueue(), assumes that the parent qdisc will enqueue the current packet. However, this assumption breaks when cake_enqueue() returns NET_XMIT_CN: the parent qdisc stops enqueuing current packet, leaving the tree qlen/backlog accounting inconsistent. This mismatch can lead to a NULL dereference (e.g., when the parent Qdisc is qfq_qdisc). This patch computes the qlen/backlog delta in a more robust way by observing the difference before and after the series of cake_drop() calls, and then compensates the qdisc tree accounting if cake_enqueue() returns NET_XMIT_CN. To ensure correct compensation when ACK thinning is enabled, a new variable is introduced to keep qlen unchanged. Fixes: 15de71d06a40 ("net/sched: Make cake_enqueue return NET_XMIT_CN when past buffer_limit") Signed-off-by: Xiang Mei Reviewed-by: Toke Høiland-Jørgensen Link: https://patch.msgid.link/20251128001415.377823-1-xmei5@asu.edu Signed-off-by: Paolo Abeni Signed-off-by: Sasha Levin --- net/sched/sch_cake.c | 58 ++++++++++++++++++++++++-------------------- 1 file changed, 32 insertions(+), 26 deletions(-) diff --git a/net/sched/sch_cake.c b/net/sched/sch_cake.c index 32bacfc314c26..d325a90cde9ee 100644 --- a/net/sched/sch_cake.c +++ b/net/sched/sch_cake.c @@ -1597,7 +1597,6 @@ static unsigned int cake_drop(struct Qdisc *sch, struct sk_buff **to_free) qdisc_drop_reason(skb, sch, to_free, SKB_DROP_REASON_QDISC_OVERLIMIT); sch->q.qlen--; - qdisc_tree_reduce_backlog(sch, 1, len); cake_heapify(q, 0); @@ -1743,14 +1742,14 @@ static void cake_reconfigure(struct Qdisc *sch); static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch, struct sk_buff **to_free) { + u32 idx, tin, prev_qlen, prev_backlog, drop_id; struct cake_sched_data *q = qdisc_priv(sch); - int len = qdisc_pkt_len(skb); - int ret; + int len = qdisc_pkt_len(skb), ret; struct sk_buff *ack = NULL; ktime_t now = ktime_get(); struct cake_tin_data *b; struct cake_flow *flow; - u32 idx, tin; + bool same_flow = false; /* choose flow to insert into */ idx = cake_classify(sch, &b, skb, q->flow_mode, &ret); @@ -1823,6 +1822,8 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch, consume_skb(skb); } else { /* not splitting */ + int ack_pkt_len = 0; + cobalt_set_enqueue_time(skb, now); get_cobalt_cb(skb)->adjusted_len = cake_overhead(q, skb); flow_queue_add(flow, skb); @@ -1833,13 +1834,13 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch, if (ack) { b->ack_drops++; sch->qstats.drops++; - b->bytes += qdisc_pkt_len(ack); - len -= qdisc_pkt_len(ack); + ack_pkt_len = qdisc_pkt_len(ack); + b->bytes += ack_pkt_len; q->buffer_used += skb->truesize - ack->truesize; if (q->rate_flags & CAKE_FLAG_INGRESS) cake_advance_shaper(q, b, ack, now, true); - qdisc_tree_reduce_backlog(sch, 1, qdisc_pkt_len(ack)); + qdisc_tree_reduce_backlog(sch, 1, ack_pkt_len); consume_skb(ack); } else { sch->q.qlen++; @@ -1848,11 +1849,11 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch, /* stats */ b->packets++; - b->bytes += len; - b->backlogs[idx] += len; - b->tin_backlog += len; - sch->qstats.backlog += len; - q->avg_window_bytes += len; + b->bytes += len - ack_pkt_len; + b->backlogs[idx] += len - ack_pkt_len; + b->tin_backlog += len - ack_pkt_len; + sch->qstats.backlog += len - ack_pkt_len; + q->avg_window_bytes += len - ack_pkt_len; } if (q->overflow_timeout) @@ -1927,24 +1928,29 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch, if (q->buffer_used > q->buffer_max_used) q->buffer_max_used = q->buffer_used; - if (q->buffer_used > q->buffer_limit) { - bool same_flow = false; - u32 dropped = 0; - u32 drop_id; + if (q->buffer_used <= q->buffer_limit) + return NET_XMIT_SUCCESS; - while (q->buffer_used > q->buffer_limit) { - dropped++; - drop_id = cake_drop(sch, to_free); + prev_qlen = sch->q.qlen; + prev_backlog = sch->qstats.backlog; - if ((drop_id >> 16) == tin && - (drop_id & 0xFFFF) == idx) - same_flow = true; - } - b->drop_overlimit += dropped; + while (q->buffer_used > q->buffer_limit) { + drop_id = cake_drop(sch, to_free); + if ((drop_id >> 16) == tin && + (drop_id & 0xFFFF) == idx) + same_flow = true; + } + + prev_qlen -= sch->q.qlen; + prev_backlog -= sch->qstats.backlog; + b->drop_overlimit += prev_qlen; - if (same_flow) - return NET_XMIT_CN; + if (same_flow) { + qdisc_tree_reduce_backlog(sch, prev_qlen - 1, + prev_backlog - len); + return NET_XMIT_CN; } + qdisc_tree_reduce_backlog(sch, prev_qlen, prev_backlog); return NET_XMIT_SUCCESS; } From bd4da8f59dbbccee0841479e23481bc3f3f2e696 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 25 Nov 2025 00:07:46 -0800 Subject: [PATCH 0899/2333] perf jitdump: Add sym/str-tables to build-ID generation [ Upstream commit 25d498e636d1f8d138d65246cfb5b1fc3069ca56 ] It was reported that python backtrace with JIT dump was broken after the change to built-in SHA-1 implementation. It seems python generates the same JIT code for each function. They will become separate DSOs but the contents are the same. Only difference is in the symbol name. But this caused a problem that every JIT'ed DSOs will have the same build-ID which makes perf confused. And it resulted in no python symbols (from JIT) in the output. Looking back at the original code before the conversion, it used the load_addr as well as the code section to distinguish each DSO. But it'd be better to use contents of symtab and strtab instead as it aligns with some linker behaviors. This patch adds a buffer to save all the contents in a single place for SHA-1 calculation. Probably we need to add sha1_update() or similar to update the existing hash value with different contents and use it here. But it's out of scope for this change and I'd like something that can be backported to the stable trees easily. Reviewed-by: Ian Rogers Cc: Eric Biggers Cc: Pablo Galindo Cc: Fangrui Song Link: https://github.com/python/cpython/issues/139544 Fixes: e3f612c1d8f3945b ("perf genelf: Remove libcrypto dependency and use built-in sha1()") Signed-off-by: Namhyung Kim Signed-off-by: Sasha Levin --- tools/perf/util/genelf.c | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/tools/perf/util/genelf.c b/tools/perf/util/genelf.c index 591548b10e34e..a1cd5196f4ec8 100644 --- a/tools/perf/util/genelf.c +++ b/tools/perf/util/genelf.c @@ -173,6 +173,8 @@ jit_write_elf(int fd, uint64_t load_addr __maybe_unused, const char *sym, Elf_Shdr *shdr; uint64_t eh_frame_base_offset; char *strsym = NULL; + void *build_id_data = NULL, *tmp; + int build_id_data_len; int symlen; int retval = -1; @@ -251,6 +253,14 @@ jit_write_elf(int fd, uint64_t load_addr __maybe_unused, const char *sym, shdr->sh_flags = SHF_EXECINSTR | SHF_ALLOC; shdr->sh_entsize = 0; + build_id_data = malloc(csize); + if (build_id_data == NULL) { + warnx("cannot allocate build-id data"); + goto error; + } + memcpy(build_id_data, code, csize); + build_id_data_len = csize; + /* * Setup .eh_frame_hdr and .eh_frame */ @@ -334,6 +344,15 @@ jit_write_elf(int fd, uint64_t load_addr __maybe_unused, const char *sym, shdr->sh_entsize = sizeof(Elf_Sym); shdr->sh_link = unwinding ? 6 : 4; /* index of .strtab section */ + tmp = realloc(build_id_data, build_id_data_len + sizeof(symtab)); + if (tmp == NULL) { + warnx("cannot allocate build-id data"); + goto error; + } + memcpy(tmp + build_id_data_len, symtab, sizeof(symtab)); + build_id_data = tmp; + build_id_data_len += sizeof(symtab); + /* * setup symbols string table * 2 = 1 for 0 in 1st entry, 1 for the 0 at end of symbol for 2nd entry @@ -376,6 +395,15 @@ jit_write_elf(int fd, uint64_t load_addr __maybe_unused, const char *sym, shdr->sh_flags = 0; shdr->sh_entsize = 0; + tmp = realloc(build_id_data, build_id_data_len + symlen); + if (tmp == NULL) { + warnx("cannot allocate build-id data"); + goto error; + } + memcpy(tmp + build_id_data_len, strsym, symlen); + build_id_data = tmp; + build_id_data_len += symlen; + /* * setup build-id section */ @@ -394,7 +422,7 @@ jit_write_elf(int fd, uint64_t load_addr __maybe_unused, const char *sym, /* * build-id generation */ - sha1(code, csize, bnote.build_id); + sha1(build_id_data, build_id_data_len, bnote.build_id); bnote.desc.namesz = sizeof(bnote.name); /* must include 0 termination */ bnote.desc.descsz = sizeof(bnote.build_id); bnote.desc.type = NT_GNU_BUILD_ID; @@ -439,7 +467,7 @@ jit_write_elf(int fd, uint64_t load_addr __maybe_unused, const char *sym, (void)elf_end(e); free(strsym); - + free(build_id_data); return retval; } From d009ff8959d28d2a33aeb96a5f7e7161c421d78f Mon Sep 17 00:00:00 2001 From: Shuhao Fu Date: Tue, 21 Oct 2025 16:42:28 +0800 Subject: [PATCH 0900/2333] exfat: fix refcount leak in exfat_find [ Upstream commit 9aee8de970f18c2aaaa348e3de86c38e2d956c1d ] Fix refcount leaks in `exfat_find` related to `exfat_get_dentry_set`. Function `exfat_get_dentry_set` would increase the reference counter of `es->bh` on success. Therefore, `exfat_put_dentry_set` must be called after `exfat_get_dentry_set` to ensure refcount consistency. This patch relocate two checks to avoid possible leaks. Fixes: 82ebecdc74ff ("exfat: fix improper check of dentry.stream.valid_size") Fixes: 13940cef9549 ("exfat: add a check for invalid data size") Signed-off-by: Shuhao Fu Reviewed-by: Yuezhang Mo Signed-off-by: Namjae Jeon Signed-off-by: Sasha Levin --- fs/exfat/namei.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/fs/exfat/namei.c b/fs/exfat/namei.c index 745dce29ddb53..dfe957493d49e 100644 --- a/fs/exfat/namei.c +++ b/fs/exfat/namei.c @@ -645,16 +645,6 @@ static int exfat_find(struct inode *dir, const struct qstr *qname, info->valid_size = le64_to_cpu(ep2->dentry.stream.valid_size); info->size = le64_to_cpu(ep2->dentry.stream.size); - if (info->valid_size < 0) { - exfat_fs_error(sb, "data valid size is invalid(%lld)", info->valid_size); - return -EIO; - } - - if (unlikely(EXFAT_B_TO_CLU_ROUND_UP(info->size, sbi) > sbi->used_clusters)) { - exfat_fs_error(sb, "data size is invalid(%lld)", info->size); - return -EIO; - } - info->start_clu = le32_to_cpu(ep2->dentry.stream.start_clu); if (!is_valid_cluster(sbi, info->start_clu) && info->size) { exfat_warn(sb, "start_clu is invalid cluster(0x%x)", @@ -692,6 +682,16 @@ static int exfat_find(struct inode *dir, const struct qstr *qname, 0); exfat_put_dentry_set(&es, false); + if (info->valid_size < 0) { + exfat_fs_error(sb, "data valid size is invalid(%lld)", info->valid_size); + return -EIO; + } + + if (unlikely(EXFAT_B_TO_CLU_ROUND_UP(info->size, sbi) > sbi->used_clusters)) { + exfat_fs_error(sb, "data size is invalid(%lld)", info->size); + return -EIO; + } + if (ei->start_clu == EXFAT_FREE_CLUSTER) { exfat_fs_error(sb, "non-zero size file starts with zero cluster (size : %llu, p_dir : %u, entry : 0x%08x)", From 88fc3dd6e631b3e2975f898c6c2b6bc6f7058b44 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Tue, 18 Nov 2025 11:10:26 +0900 Subject: [PATCH 0901/2333] exfat: fix divide-by-zero in exfat_allocate_bitmap [ Upstream commit d70a5804c563b5e34825353ba9927509df709651 ] The variable max_ra_count can be 0 in exfat_allocate_bitmap(), which causes a divide-by-zero error in the subsequent modulo operation (i % max_ra_count), leading to a system crash. When max_ra_count is 0, it means that readahead is not used. This patch load the bitmap without readahead. Fixes: 9fd688678dd8 ("exfat: optimize allocation bitmap loading time") Reported-by: Jiaming Zhang Signed-off-by: Namjae Jeon Signed-off-by: Sasha Levin --- fs/exfat/balloc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/exfat/balloc.c b/fs/exfat/balloc.c index 2d2d510f2372c..0b6466b3490a0 100644 --- a/fs/exfat/balloc.c +++ b/fs/exfat/balloc.c @@ -106,7 +106,7 @@ static int exfat_allocate_bitmap(struct super_block *sb, (PAGE_SHIFT - sb->s_blocksize_bits); for (i = 0; i < sbi->map_sectors; i++) { /* Trigger the next readahead in advance. */ - if (0 == (i % max_ra_count)) { + if (max_ra_count && 0 == (i % max_ra_count)) { blk_start_plug(&plug); for (j = i; j < min(max_ra_count, sbi->map_sectors - i) + i; j++) sb_breadahead(sb, sector + j); From 30f874b8a92ff71a275846d38f2e39a44ae0e4a8 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 2 Dec 2025 15:57:14 -0800 Subject: [PATCH 0902/2333] perf tools: Mark split kallsyms DSOs as loaded [ Upstream commit 7da4d60db33cccd8f4c445ab20bba71531435ee5 ] The maps__split_kallsyms() will split symbols to module DSOs if it comes from a module. It also handled some unusual kernel symbols after modules by creating new kernel maps like "[kernel].0". But they are pseudo DSOs to have those unexpected symbols. They should not be considered as unloaded kernel DSOs. Otherwise the dso__load() for them will end up calling dso__load_kallsyms() and then maps__split_kallsyms() again and again. Reviewed-by: Ian Rogers Fixes: 2e538c4a1847291cf ("perf tools: Improve kernel/modules symbol lookup") Signed-off-by: Namhyung Kim Signed-off-by: Sasha Levin --- tools/perf/util/symbol.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 948d3e8ad782b..aed65b1abe669 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -976,6 +976,7 @@ static int maps__split_kallsyms(struct maps *kmaps, struct dso *dso, u64 delta, return -1; dso__set_kernel(ndso, dso__kernel(dso)); + dso__set_loaded(ndso); curr_map = map__new2(pos->start, ndso); if (curr_map == NULL) { From 501a16c1ddb23beb27fa31a98c8054e34f9ea4b9 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 2 Dec 2025 15:57:15 -0800 Subject: [PATCH 0903/2333] perf tools: Fix split kallsyms DSO counting [ Upstream commit ad0b9c4865b98dc37f4d606d26b1c19808796805 ] It's counted twice as it's increased after calling maps__insert(). I guess we want to increase it only after it's added properly. Reviewed-by: Ian Rogers Fixes: 2e538c4a1847291cf ("perf tools: Improve kernel/modules symbol lookup") Signed-off-by: Namhyung Kim Signed-off-by: Sasha Levin --- tools/perf/util/symbol.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index aed65b1abe669..f6c268c588a56 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -964,11 +964,11 @@ static int maps__split_kallsyms(struct maps *kmaps, struct dso *dso, u64 delta, if (dso__kernel(dso) == DSO_SPACE__KERNEL_GUEST) snprintf(dso_name, sizeof(dso_name), "[guest.kernel].%d", - kernel_range++); + kernel_range); else snprintf(dso_name, sizeof(dso_name), "[kernel].%d", - kernel_range++); + kernel_range); ndso = dso__new(dso_name); map__zput(curr_map); From badf751a785d624f2ab326f7d00d11a5a78842dc Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Sat, 22 Nov 2025 00:19:13 -0800 Subject: [PATCH 0904/2333] perf kvm: Fix debug assertion [ Upstream commit 27e711257902475097dea3f79cbdf241fe37ec00 ] There are 2 slots left for kvm_add_default_arch_event, fix the assertion so that debug builds don't fail the assert and to agree with the comment. Fixes: 45ff39f6e70aa55d0 ("perf tools kvm: Fix the potential out of range memory access issue") Signed-off-by: Ian Rogers Signed-off-by: Namhyung Kim Signed-off-by: Sasha Levin --- tools/perf/builtin-kvm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c index f0f285763f190..c61369d54dd9d 100644 --- a/tools/perf/builtin-kvm.c +++ b/tools/perf/builtin-kvm.c @@ -2014,7 +2014,7 @@ static int __cmd_record(const char *file_name, int argc, const char **argv) for (j = 1; j < argc; j++, i++) rec_argv[i] = STRDUP_FAIL_EXIT(argv[j]); - BUG_ON(i != rec_argc); + BUG_ON(i + 2 != rec_argc); ret = kvm_add_default_arch_event(&i, rec_argv); if (ret) From 654841dd211b006803a5f8a4005f03010e0fdbdc Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Sat, 22 Nov 2025 00:19:18 -0800 Subject: [PATCH 0905/2333] perf hist: In init, ensure mem_info is put on error paths [ Upstream commit f60efb4454b24cc944ff3eac164bb9dce9169f71 ] Rather than exit the internal map_symbols directly, put the mem-info that does this and also lowers the reference count on the mem-info itself otherwise the mem-info is being leaked. Fixes: 56e144fe98260a0f ("perf mem_info: Add and use map_symbol__exit and addr_map_symbol__exit") Signed-off-by: Ian Rogers Reviewed-by: Arnaldo Carvalho de Melo Signed-off-by: Namhyung Kim Signed-off-by: Sasha Levin --- tools/perf/util/hist.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 64ff427040c34..ef4b569f7df46 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -608,10 +608,8 @@ static int hist_entry__init(struct hist_entry *he, map_symbol__exit(&he->branch_info->to.ms); zfree(&he->branch_info); } - if (he->mem_info) { - map_symbol__exit(&mem_info__iaddr(he->mem_info)->ms); - map_symbol__exit(&mem_info__daddr(he->mem_info)->ms); - } + if (he->mem_info) + mem_info__zput(he->mem_info); err: map_symbol__exit(&he->ms); zfree(&he->stat_acc); From b9ceff1ca3ef9a3f7438e0825b6095da3905fc4c Mon Sep 17 00:00:00 2001 From: Haotian Zhang Date: Wed, 3 Dec 2025 14:13:47 +0800 Subject: [PATCH 0906/2333] pinctrl: single: Fix incorrect type for error return variable [ Upstream commit 61d1bb53547d42c6bdaec9da4496beb3a1a05264 ] pcs_pinconf_get() and pcs_pinconf_set() declare ret as unsigned int, but assign it the return values of pcs_get_function() that may return negative error codes. This causes negative error codes to be converted to large positive values. Change ret from unsigned int to int in both functions. Fixes: 9dddb4df90d1 ("pinctrl: single: support generic pinconf") Signed-off-by: Haotian Zhang Signed-off-by: Linus Walleij Signed-off-by: Sasha Levin --- drivers/pinctrl/pinctrl-single.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c index 6d580aa282ec9..998f23d6c3179 100644 --- a/drivers/pinctrl/pinctrl-single.c +++ b/drivers/pinctrl/pinctrl-single.c @@ -485,7 +485,8 @@ static int pcs_pinconf_get(struct pinctrl_dev *pctldev, struct pcs_device *pcs = pinctrl_dev_get_drvdata(pctldev); struct pcs_function *func; enum pin_config_param param; - unsigned offset = 0, data = 0, i, j, ret; + unsigned offset = 0, data = 0, i, j; + int ret; ret = pcs_get_function(pctldev, pin, &func); if (ret) @@ -549,9 +550,9 @@ static int pcs_pinconf_set(struct pinctrl_dev *pctldev, { struct pcs_device *pcs = pinctrl_dev_get_drvdata(pctldev); struct pcs_function *func; - unsigned offset = 0, shift = 0, i, data, ret; + unsigned offset = 0, shift = 0, i, data; u32 arg; - int j; + int j, ret; enum pin_config_param param; ret = pcs_get_function(pctldev, pin, &func); From 850f134a4c81954f95f0eafe49e80fece82b11ba Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Wed, 3 Dec 2025 13:47:00 -0800 Subject: [PATCH 0907/2333] perf stat: Allow no events to open if this is a "--null" run [ Upstream commit 6744c0b182c1f371135bc3f4e62b96ad884c9f89 ] It is intended that a "--null" run doesn't open any events. Fixes: 2cc7aa995ce9 ("perf stat: Refactor retry/skip/fatal error handling") Tested-by: Ingo Molnar Signed-off-by: Ian Rogers Tested-by: Thomas Richter Signed-off-by: Namhyung Kim Signed-off-by: Sasha Levin --- tools/perf/builtin-stat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index f1c9d6c94fc50..b6533dcf5465b 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -856,7 +856,7 @@ static int __run_perf_stat(int argc, const char **argv, int run_idx) goto err_out; } } - if (!has_supported_counters) { + if (!has_supported_counters && !stat_config.null_run) { evsel__open_strerror(evlist__first(evsel_list), &target, open_err, msg, sizeof(msg)); ui__error("No supported events found.\n%s\n", msg); From 15a6572117f09674216377e05dc923c8283241f3 Mon Sep 17 00:00:00 2001 From: Abdun Nihaal Date: Wed, 3 Dec 2025 09:25:44 +0530 Subject: [PATCH 0908/2333] fbdev: ssd1307fb: fix potential page leak in ssd1307fb_probe() [ Upstream commit 164312662ae9764b83b84d97afb25c42eb2be473 ] The page allocated for vmem using __get_free_pages() is not freed on the error paths after it. Fix that by adding a corresponding __free_pages() call to the error path. Fixes: facd94bc458a ("fbdev: ssd1307fb: Allocate page aligned video memory.") Signed-off-by: Abdun Nihaal Signed-off-by: Helge Deller Signed-off-by: Sasha Levin --- drivers/video/fbdev/ssd1307fb.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/video/fbdev/ssd1307fb.c b/drivers/video/fbdev/ssd1307fb.c index aa6cc0a8151ac..83dd31fa1fab5 100644 --- a/drivers/video/fbdev/ssd1307fb.c +++ b/drivers/video/fbdev/ssd1307fb.c @@ -680,7 +680,7 @@ static int ssd1307fb_probe(struct i2c_client *client) if (!ssd1307fb_defio) { dev_err(dev, "Couldn't allocate deferred io.\n"); ret = -ENOMEM; - goto fb_alloc_error; + goto fb_defio_error; } ssd1307fb_defio->delay = HZ / refreshrate; @@ -757,6 +757,8 @@ static int ssd1307fb_probe(struct i2c_client *client) regulator_disable(par->vbat_reg); reset_oled_error: fb_deferred_io_cleanup(info); +fb_defio_error: + __free_pages(vmem, get_order(vmem_size)); fb_alloc_error: framebuffer_release(info); return ret; From fe9a3154bb5b020f0fe9ddb661560f37ebaff5da Mon Sep 17 00:00:00 2001 From: Eric Sandeen Date: Tue, 2 Dec 2025 16:30:53 -0600 Subject: [PATCH 0909/2333] 9p: fix cache/debug options printing in v9fs_show_options [ Upstream commit f0445613314f474c1a0ec6fa8a5cd153a618f1b6 ] commit 4eb3117888a92 changed the cache= option to accept either string shortcuts or bitfield values. It also changed /proc/mounts to emit the option as the hexadecimal numeric value rather than the shortcut string. However, by printing "cache=%x" without the leading 0x, shortcuts such as "cache=loose" will emit "cache=f" and 'f' is not a string that is parseable by kstrtoint(), so remounting may fail if a remount with "cache=f" is attempted. debug=%x has had the same problem since options have been displayed in c4fac9100456 ("9p: Implement show_options") Fix these by adding the 0x prefix to the hexadecimal value shown in /proc/mounts. Fixes: 4eb3117888a92 ("fs/9p: Rework cache modes and add new options to Documentation") Signed-off-by: Eric Sandeen Message-ID: <54b93378-dcf1-4b04-922d-c8b4393da299@redhat.com> [Dominique: use %#x at Al Viro's suggestion, also handle debug] Tested-by: Remi Pommarel Signed-off-by: Dominique Martinet Signed-off-by: Sasha Levin --- fs/9p/v9fs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c index a020a8f00a1ac..bde3ffb0e319a 100644 --- a/fs/9p/v9fs.c +++ b/fs/9p/v9fs.c @@ -101,7 +101,7 @@ int v9fs_show_options(struct seq_file *m, struct dentry *root) struct v9fs_session_info *v9ses = root->d_sb->s_fs_info; if (v9ses->debug) - seq_printf(m, ",debug=%x", v9ses->debug); + seq_printf(m, ",debug=%#x", v9ses->debug); if (!uid_eq(v9ses->dfltuid, V9FS_DEFUID)) seq_printf(m, ",dfltuid=%u", from_kuid_munged(&init_user_ns, v9ses->dfltuid)); @@ -117,7 +117,7 @@ int v9fs_show_options(struct seq_file *m, struct dentry *root) if (v9ses->nodev) seq_puts(m, ",nodevmap"); if (v9ses->cache) - seq_printf(m, ",cache=%x", v9ses->cache); + seq_printf(m, ",cache=%#x", v9ses->cache); #ifdef CONFIG_9P_FSCACHE if (v9ses->cachetag && (v9ses->cache & CACHE_FSCACHE)) seq_printf(m, ",cachetag=%s", v9ses->cachetag); From 8061d3b7bb917812c697f25495cb015d3a6c42e8 Mon Sep 17 00:00:00 2001 From: xupengbo Date: Wed, 27 Aug 2025 10:22:07 +0800 Subject: [PATCH 0910/2333] sched/fair: Fix unfairness caused by stalled tg_load_avg_contrib when the last task migrates out [ Upstream commit ca125231dd29fc0678dd3622e9cdea80a51dffe4 ] When a task is migrated out, there is a probability that the tg->load_avg value will become abnormal. The reason is as follows: 1. Due to the 1ms update period limitation in update_tg_load_avg(), there is a possibility that the reduced load_avg is not updated to tg->load_avg when a task migrates out. 2. Even though __update_blocked_fair() traverses the leaf_cfs_rq_list and calls update_tg_load_avg() for cfs_rqs that are not fully decayed, the key function cfs_rq_is_decayed() does not check whether cfs->tg_load_avg_contrib is null. Consequently, in some cases, __update_blocked_fair() removes cfs_rqs whose avg.load_avg has not been updated to tg->load_avg. Add a check of cfs_rq->tg_load_avg_contrib in cfs_rq_is_decayed(), which fixes the case (2.) mentioned above. Fixes: 1528c661c24b ("sched/fair: Ratelimit update to tg->load_avg") Signed-off-by: xupengbo Signed-off-by: Peter Zijlstra (Intel) Signed-off-by: Ingo Molnar Reviewed-by: Aaron Lu Reviewed-by: Vincent Guittot Tested-by: Aaron Lu Link: https://patch.msgid.link/20250827022208.14487-1-xupengbo@oppo.com Signed-off-by: Sasha Levin --- kernel/sched/fair.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 2a4a1c6e25da0..71d3f4125b0e7 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -4059,6 +4059,9 @@ static inline bool cfs_rq_is_decayed(struct cfs_rq *cfs_rq) if (child_cfs_rq_on_list(cfs_rq)) return false; + if (cfs_rq->tg_load_avg_contrib) + return false; + return true; } From 41a59772b5007e9f1fd4a11e8509cee3d5c8e6e4 Mon Sep 17 00:00:00 2001 From: John Stultz Date: Fri, 5 Dec 2025 01:27:09 +0000 Subject: [PATCH 0911/2333] sched/core: Fix psi_dequeue() for Proxy Execution [ Upstream commit c2ae8b0df2d1bb7a063f9e356e4e9a06cd4afe11 ] Currently, if the sleep flag is set, psi_dequeue() doesn't change any of the psi_flags. This is because psi_task_switch() will clear TSK_ONCPU as well as other potential flags (TSK_RUNNING), and the assumption is that a voluntary sleep always consists of a task being dequeued followed shortly there after with a psi_sched_switch() call. Proxy Execution changes this expectation, as mutex-blocked tasks that would normally sleep stay on the runqueue. But in the case where the mutex-owning task goes to sleep, or the owner is on a remote cpu, we will then deactivate the blocked task shortly after. In that situation, the mutex-blocked task will have had its TSK_ONCPU cleared when it was switched off the cpu, but it will stay TSK_RUNNING. Then if we later dequeue it (as currently done if we hit a case find_proxy_task() can't yet handle, such as the case of the owner being on another rq or a sleeping owner) psi_dequeue() won't change any state (leaving it TSK_RUNNING), as it incorrectly expects a psi_task_switch() call to immediately follow. Later on when the task get woken/re-enqueued, and psi_flags are set for TSK_RUNNING, we hit an error as the task is already TSK_RUNNING: psi: inconsistent task state! task=188:kworker/28:0 cpu=28 psi_flags=4 clear=0 set=4 To resolve this, extend the logic in psi_dequeue() so that if the sleep flag is set, we also check if psi_flags have TSK_ONCPU set (meaning the psi_task_switch is imminent) before we do the shortcut return. If TSK_ONCPU is not set, that means we've already switched away, and this psi_dequeue call needs to clear the flags. Fixes: be41bde4c3a8 ("sched: Add an initial sketch of the find_proxy_task() function") Reported-by: K Prateek Nayak Signed-off-by: John Stultz Signed-off-by: Ingo Molnar Tested-by: K Prateek Nayak Tested-by: Haiyue Wang Acked-by: Johannes Weiner Link: https://patch.msgid.link/20251205012721.756394-1-jstultz@google.com Closes: https://lore.kernel.org/lkml/20251117185550.365156-1-kprateek.nayak@amd.com/ Signed-off-by: Sasha Levin --- kernel/sched/stats.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/kernel/sched/stats.h b/kernel/sched/stats.h index 26f3fd4d34cea..73bd6bca4d310 100644 --- a/kernel/sched/stats.h +++ b/kernel/sched/stats.h @@ -180,8 +180,13 @@ static inline void psi_dequeue(struct task_struct *p, int flags) * avoid walking all ancestors twice, psi_task_switch() handles * TSK_RUNNING and TSK_IOWAIT for us when it moves TSK_ONCPU. * Do nothing here. + * + * In the SCHED_PROXY_EXECUTION case we may do sleeping + * dequeues that are not followed by a task switch, so check + * TSK_ONCPU is set to ensure the task switch is imminent. + * Otherwise clear the flags as usual. */ - if (flags & DEQUEUE_SLEEP) + if ((flags & DEQUEUE_SLEEP) && (p->psi_flags & TSK_ONCPU)) return; /* From 52eb1c76c0dcd586bf0a8fa6e0a6e6b23881f4a2 Mon Sep 17 00:00:00 2001 From: Xi Pardee Date: Tue, 14 Oct 2025 14:45:29 -0700 Subject: [PATCH 0912/2333] platform/x86:intel/pmc: Update Arrow Lake telemetry GUID MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 644ab3bc98ee386f178d5209ae8170b3fac591aa ] Update ARL_PMT_DMU_GUID value. Arrow Lake PMT DMU GUID has been updated after it was add to the driver. This updates ensures that the die C6 value is available in the debug filesystem. Bugzilla Link: https://bugzilla.kernel.org/show_bug.cgi?id=220421 Fixes: 83f168a1a437 ("platform/x86/intel/pmc: Add Arrow Lake S support to intel_pmc_core driver") Tested-by: Mark Pearson Signed-off-by: Xi Pardee Link: https://patch.msgid.link/20251014214548.629023-2-xi.pardee@linux.intel.com Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen Signed-off-by: Sasha Levin --- drivers/platform/x86/intel/pmc/core.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/x86/intel/pmc/core.h b/drivers/platform/x86/intel/pmc/core.h index f4dadb696a314..d6818bd34768e 100644 --- a/drivers/platform/x86/intel/pmc/core.h +++ b/drivers/platform/x86/intel/pmc/core.h @@ -282,7 +282,7 @@ enum ppfear_regs { /* Die C6 from PUNIT telemetry */ #define MTL_PMT_DMU_DIE_C6_OFFSET 15 #define MTL_PMT_DMU_GUID 0x1A067102 -#define ARL_PMT_DMU_GUID 0x1A06A000 +#define ARL_PMT_DMU_GUID 0x1A06A102 #define LNL_PMC_MMIO_REG_LEN 0x2708 #define LNL_PMC_LTR_OSSE 0x1B88 From b18d3c3ce852372cd612901488436315aca6d02e Mon Sep 17 00:00:00 2001 From: Daeho Jeong Date: Fri, 3 Oct 2025 15:43:08 -0700 Subject: [PATCH 0913/2333] f2fs: maintain one time GC mode is enabled during whole zoned GC cycle [ Upstream commit e462fc48ceb8224811c3224650afed05cb7f0872 ] The current version missed setting one time GC for normal zoned GC cycle. So, valid threshold control is not working. Need to fix it to prevent excessive GC for zoned devices. Fixes: e791d00bd06c ("f2fs: add valid block ratio not to do excessive GC for one time GC") Signed-off-by: Daeho Jeong Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim Signed-off-by: Sasha Levin --- fs/f2fs/gc.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c index a7708cf80c04e..8abf521530ff3 100644 --- a/fs/f2fs/gc.c +++ b/fs/f2fs/gc.c @@ -38,13 +38,14 @@ static int gc_thread_func(void *data) struct f2fs_gc_control gc_control = { .victim_segno = NULL_SEGNO, .should_migrate_blocks = false, - .err_gc_skipped = false }; + .err_gc_skipped = false, + .one_time = false }; wait_ms = gc_th->min_sleep_time; set_freezable(); do { - bool sync_mode, foreground = false; + bool sync_mode, foreground = false, gc_boost = false; wait_event_freezable_timeout(*wq, kthread_should_stop() || @@ -52,8 +53,12 @@ static int gc_thread_func(void *data) gc_th->gc_wake, msecs_to_jiffies(wait_ms)); - if (test_opt(sbi, GC_MERGE) && waitqueue_active(fggc_wq)) + if (test_opt(sbi, GC_MERGE) && waitqueue_active(fggc_wq)) { foreground = true; + gc_control.one_time = false; + } else if (f2fs_sb_has_blkzoned(sbi)) { + gc_control.one_time = true; + } /* give it a try one time */ if (gc_th->gc_wake) @@ -81,8 +86,6 @@ static int gc_thread_func(void *data) continue; } - gc_control.one_time = false; - /* * [GC triggering condition] * 0. GC is not conducted currently. @@ -132,7 +135,7 @@ static int gc_thread_func(void *data) if (need_to_boost_gc(sbi)) { decrease_sleep_time(gc_th, &wait_ms); if (f2fs_sb_has_blkzoned(sbi)) - gc_control.one_time = true; + gc_boost = true; } else { increase_sleep_time(gc_th, &wait_ms); } @@ -141,7 +144,7 @@ static int gc_thread_func(void *data) FOREGROUND : BACKGROUND); sync_mode = (F2FS_OPTION(sbi).bggc_mode == BGGC_MODE_SYNC) || - (gc_control.one_time && gc_th->boost_gc_greedy); + (gc_boost && gc_th->boost_gc_greedy); /* foreground GC was been triggered via f2fs_balance_fs() */ if (foreground && !f2fs_sb_has_blkzoned(sbi)) From 2e1c79299036614ac32b251d145fad5391f4bcab Mon Sep 17 00:00:00 2001 From: Haotian Zhang Date: Tue, 21 Oct 2025 18:35:59 +0800 Subject: [PATCH 0914/2333] rtc: amlogic-a4: fix double free caused by devm [ Upstream commit 384150d7a5b60c1086790a8ee07b0629f906cca2 ] The clock obtained via devm_clk_get_enabled() is automatically managed by devres and will be disabled and freed on driver detach. Manually calling clk_disable_unprepare() in error path and remove function causes double free. Remove the redundant clk_disable_unprepare() calls from the probe error path and aml_rtc_remove(), allowing the devm framework to automatically manage the clock lifecycle. Fixes: c89ac9182ee2 ("rtc: support for the Amlogic on-chip RTC") Signed-off-by: Haotian Zhang Reviewed-by: Xianwei Zhao Link: https://patch.msgid.link/20251021103559.1903-1-vulab@iscas.ac.cn Signed-off-by: Alexandre Belloni Signed-off-by: Sasha Levin --- drivers/rtc/rtc-amlogic-a4.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/rtc/rtc-amlogic-a4.c b/drivers/rtc/rtc-amlogic-a4.c index 1928b29c10454..a993d35e1d6b0 100644 --- a/drivers/rtc/rtc-amlogic-a4.c +++ b/drivers/rtc/rtc-amlogic-a4.c @@ -390,7 +390,6 @@ static int aml_rtc_probe(struct platform_device *pdev) return 0; err_clk: - clk_disable_unprepare(rtc->sys_clk); device_init_wakeup(dev, false); return ret; @@ -423,9 +422,6 @@ static SIMPLE_DEV_PM_OPS(aml_rtc_pm_ops, static void aml_rtc_remove(struct platform_device *pdev) { - struct aml_rtc_data *rtc = dev_get_drvdata(&pdev->dev); - - clk_disable_unprepare(rtc->sys_clk); device_init_wakeup(&pdev->dev, false); } From 530f1ba287937726ff220de9c82566e74e35dcae Mon Sep 17 00:00:00 2001 From: Abel Vesa Date: Tue, 11 Nov 2025 08:43:51 +0200 Subject: [PATCH 0915/2333] kbuild: install-extmod-build: Properly fix CC expansion when ccache is used [ Upstream commit 4ab2ee307983548b29ddaab0ecaef82d526cf4c9 ] Currently, when cross-compiling and ccache is used, the expanding of CC turns out to be without any quotes, leading to the following error: make[4]: *** No rule to make target 'aarch64-linux-gnu-gcc'. Stop. make[3]: *** [Makefile:2164: run-command] Error 2 And it makes sense, because after expansion it ends up like this: make run-command KBUILD_RUN_COMMAND=+$(MAKE) \ HOSTCC=ccache aarch64-linux-gnu-gcc VPATH= srcroot=. $(build)= ... So add another set of double quotes to surround whatever CC expands to to make sure the aarch64-linux-gnu-gcc isn't expanded to something that looks like an entirely separate target. Fixes: 140332b6ed72 ("kbuild: fix linux-headers package build when $(CC) cannot link userspace") Signed-off-by: Abel Vesa Reviewed-by: Nicolas Schier Link: https://patch.msgid.link/20251111-kbuild-install-extmod-build-fix-cc-expand-third-try-v2-1-15ba1b37e71a@linaro.org Signed-off-by: Nathan Chancellor Signed-off-by: Sasha Levin --- scripts/package/install-extmod-build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/package/install-extmod-build b/scripts/package/install-extmod-build index 054fdf45cc37a..2576cf7902dbb 100755 --- a/scripts/package/install-extmod-build +++ b/scripts/package/install-extmod-build @@ -63,7 +63,7 @@ if [ "${CC}" != "${HOSTCC}" ]; then # Clear VPATH and srcroot because the source files reside in the output # directory. # shellcheck disable=SC2016 # $(MAKE) and $(build) will be expanded by Make - "${MAKE}" run-command KBUILD_RUN_COMMAND='+$(MAKE) HOSTCC='"${CC}"' VPATH= srcroot=. $(build)='"$(realpath --relative-to=. "${destdir}")"/scripts + "${MAKE}" run-command KBUILD_RUN_COMMAND='+$(MAKE) HOSTCC="'"${CC}"'" VPATH= srcroot=. $(build)='"$(realpath --relative-to=. "${destdir}")"/scripts rm -f "${destdir}/scripts/Kbuild" fi From f0f456c327f5728ca632746cdfae0bf4f6bc5188 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 17 Nov 2025 15:28:17 -0500 Subject: [PATCH 0916/2333] NFS: Avoid changing nlink when file removes and attribute updates race [ Upstream commit bd4928ec799b31c492eb63f9f4a0c1e0bb4bb3f7 ] If a file removal races with another operation that updates its attributes, then skip the change to nlink, and just mark the attributes as being stale. Reported-by: Aiden Lambert Fixes: 59a707b0d42e ("NFS: Ensure we revalidate the inode correctly after remove or rename") Signed-off-by: Trond Myklebust Signed-off-by: Sasha Levin --- fs/nfs/dir.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index ea9f6ca8f30fa..d557b0443e8b0 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -1894,13 +1894,15 @@ static int nfs_dentry_delete(const struct dentry *dentry) } /* Ensure that we revalidate inode->i_nlink */ -static void nfs_drop_nlink(struct inode *inode) +static void nfs_drop_nlink(struct inode *inode, unsigned long gencount) { + struct nfs_inode *nfsi = NFS_I(inode); + spin_lock(&inode->i_lock); /* drop the inode if we're reasonably sure this is the last link */ - if (inode->i_nlink > 0) + if (inode->i_nlink > 0 && gencount == nfsi->attr_gencount) drop_nlink(inode); - NFS_I(inode)->attr_gencount = nfs_inc_attr_generation_counter(); + nfsi->attr_gencount = nfs_inc_attr_generation_counter(); nfs_set_cache_invalid( inode, NFS_INO_INVALID_CHANGE | NFS_INO_INVALID_CTIME | NFS_INO_INVALID_NLINK); @@ -1914,8 +1916,9 @@ static void nfs_drop_nlink(struct inode *inode) static void nfs_dentry_iput(struct dentry *dentry, struct inode *inode) { if (dentry->d_flags & DCACHE_NFSFS_RENAMED) { + unsigned long gencount = READ_ONCE(NFS_I(inode)->attr_gencount); nfs_complete_unlink(dentry, inode); - nfs_drop_nlink(inode); + nfs_drop_nlink(inode, gencount); } iput(inode); } @@ -2507,9 +2510,11 @@ static int nfs_safe_remove(struct dentry *dentry) trace_nfs_remove_enter(dir, dentry); if (inode != NULL) { + unsigned long gencount = READ_ONCE(NFS_I(inode)->attr_gencount); + error = NFS_PROTO(dir)->remove(dir, dentry); if (error == 0) - nfs_drop_nlink(inode); + nfs_drop_nlink(inode, gencount); } else error = NFS_PROTO(dir)->remove(dir, dentry); if (error == -ENOENT) @@ -2709,6 +2714,7 @@ int nfs_rename(struct mnt_idmap *idmap, struct inode *old_dir, { struct inode *old_inode = d_inode(old_dentry); struct inode *new_inode = d_inode(new_dentry); + unsigned long new_gencount = 0; struct dentry *dentry = NULL; struct rpc_task *task; bool must_unblock = false; @@ -2761,6 +2767,7 @@ int nfs_rename(struct mnt_idmap *idmap, struct inode *old_dir, } else { block_revalidate(new_dentry); must_unblock = true; + new_gencount = NFS_I(new_inode)->attr_gencount; spin_unlock(&new_dentry->d_lock); } @@ -2800,7 +2807,7 @@ int nfs_rename(struct mnt_idmap *idmap, struct inode *old_dir, new_dir, new_dentry, error); if (!error) { if (new_inode != NULL) - nfs_drop_nlink(new_inode); + nfs_drop_nlink(new_inode, new_gencount); /* * The d_move() should be here instead of in an async RPC completion * handler because we need the proper locks to move the dentry. If From 4836f912acc702d6e70eab3f1d796895906a540d Mon Sep 17 00:00:00 2001 From: Armin Wolf Date: Tue, 11 Nov 2025 14:11:22 +0100 Subject: [PATCH 0917/2333] fs/nls: Fix utf16 to utf8 conversion MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 25524b6190295577e4918c689644451365e6466d ] Currently the function responsible for converting between utf16 and utf8 strings will ignore any characters that cannot be converted. This however also includes multi-byte characters that do not fit into the provided string buffer. This can cause problems if such a multi-byte character is followed by a single-byte character. In such a case the multi-byte character might be ignored when the provided string buffer is too small, but the single-byte character might fit and is thus still copied into the resulting string. Fix this by stop filling the provided string buffer once a character does not fit. In order to be able to do this extend utf32_to_utf8() to return useful errno codes instead of -1. Fixes: 74675a58507e ("NLS: update handling of Unicode") Signed-off-by: Armin Wolf Link: https://patch.msgid.link/20251111131125.3379-2-W_Armin@gmx.de Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen Signed-off-by: Sasha Levin --- fs/nls/nls_base.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/fs/nls/nls_base.c b/fs/nls/nls_base.c index 18d597e49a194..d434c4463a8f7 100644 --- a/fs/nls/nls_base.c +++ b/fs/nls/nls_base.c @@ -94,7 +94,7 @@ int utf32_to_utf8(unicode_t u, u8 *s, int maxout) l = u; if (l > UNICODE_MAX || (l & SURROGATE_MASK) == SURROGATE_PAIR) - return -1; + return -EILSEQ; nc = 0; for (t = utf8_table; t->cmask && maxout; t++, maxout--) { @@ -110,7 +110,7 @@ int utf32_to_utf8(unicode_t u, u8 *s, int maxout) return nc; } } - return -1; + return -EOVERFLOW; } EXPORT_SYMBOL(utf32_to_utf8); @@ -217,8 +217,16 @@ int utf16s_to_utf8s(const wchar_t *pwcs, int inlen, enum utf16_endian endian, inlen--; } size = utf32_to_utf8(u, op, maxout); - if (size == -1) { - /* Ignore character and move on */ + if (size < 0) { + if (size == -EILSEQ) { + /* Ignore character and move on */ + continue; + } + /* + * Stop filling the buffer with data once a character + * does not fit anymore. + */ + break; } else { op += size; maxout -= size; From 32b7ba23b4df7f0d58cdc0d19485e8786242b591 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 19 Nov 2025 08:36:16 -0500 Subject: [PATCH 0918/2333] NFS: Initialise verifiers for visible dentries in readdir and lookup [ Upstream commit 9bd545539b233725a3416801f7c374bff0327d6e ] Ensure that the verifiers are initialised before calling d_splice_alias() in both nfs_prime_dcache() and nfs_lookup(). Reported-by: Michael Stoler Fixes: a1147b8281bd ("NFS: Fix up directory verifier races") Signed-off-by: Trond Myklebust Signed-off-by: Sasha Levin --- fs/nfs/dir.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index d557b0443e8b0..2eead7e85be5b 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -789,16 +789,17 @@ void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry, goto out; } + nfs_set_verifier(dentry, dir_verifier); inode = nfs_fhget(dentry->d_sb, entry->fh, entry->fattr); alias = d_splice_alias(inode, dentry); d_lookup_done(dentry); if (alias) { if (IS_ERR(alias)) goto out; + nfs_set_verifier(alias, dir_verifier); dput(dentry); dentry = alias; } - nfs_set_verifier(dentry, dir_verifier); trace_nfs_readdir_lookup(d_inode(parent), dentry, 0); out: dput(dentry); @@ -1994,13 +1995,14 @@ struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, unsigned in nfs_lookup_advise_force_readdirplus(dir, flags); no_entry: + nfs_set_verifier(dentry, dir_verifier); res = d_splice_alias(inode, dentry); if (res != NULL) { if (IS_ERR(res)) goto out; + nfs_set_verifier(res, dir_verifier); dentry = res; } - nfs_set_verifier(dentry, dir_verifier); out: trace_nfs_lookup_exit(dir, dentry, flags, PTR_ERR_OR_ZERO(res)); nfs_free_fattr(fattr); From 97b93a595be0e68880123ea2c4df39865b62c768 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 19 Nov 2025 08:39:50 -0500 Subject: [PATCH 0919/2333] NFS: Initialise verifiers for visible dentries in nfs_atomic_open() [ Upstream commit 518c32a1bc4f8df1a8442ee8cdfea3e2fcff20a0 ] Ensure that the verifiers are initialised before calling d_splice_alias() in nfs_atomic_open(). Reported-by: Michael Stoler Fixes: 809fd143de88 ("NFSv4: Ensure nfs_atomic_open set the dentry verifier on ENOENT") Signed-off-by: Trond Myklebust Signed-off-by: Sasha Levin --- fs/nfs/dir.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 2eead7e85be5b..3b8250ee01412 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -2144,12 +2144,12 @@ int nfs_atomic_open(struct inode *dir, struct dentry *dentry, d_drop(dentry); switch (err) { case -ENOENT: - d_splice_alias(NULL, dentry); if (nfs_server_capable(dir, NFS_CAP_CASE_INSENSITIVE)) dir_verifier = inode_peek_iversion_raw(dir); else dir_verifier = nfs_save_change_attribute(dir); nfs_set_verifier(dentry, dir_verifier); + d_splice_alias(NULL, dentry); break; case -EISDIR: case -ENOTDIR: From a7d914e1f9b4e487648f6d24900899a11ad6867b Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 19 Nov 2025 08:43:21 -0500 Subject: [PATCH 0920/2333] NFS: Initialise verifiers for visible dentries in _nfs4_open_and_get_state [ Upstream commit 0f900f11002ff52391fc2aa4a75e59f26ed1c242 ] Ensure that the verifiers are initialised before calling d_splice_alias() in _nfs4_open_and_get_state(). Reported-by: Michael Stoler Fixes: cf5b4059ba71 ("NFSv4: Fix races between open and dentry revalidation") Signed-off-by: Trond Myklebust Signed-off-by: Sasha Levin --- fs/nfs/nfs4proc.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 93c6ce04332b8..6f4e14fb7b9b8 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -3174,18 +3174,6 @@ static int _nfs4_open_and_get_state(struct nfs4_opendata *opendata, if (opendata->o_res.rflags & NFS4_OPEN_RESULT_PRESERVE_UNLINKED) set_bit(NFS_INO_PRESERVE_UNLINKED, &NFS_I(state->inode)->flags); - dentry = opendata->dentry; - if (d_really_is_negative(dentry)) { - struct dentry *alias; - d_drop(dentry); - alias = d_splice_alias(igrab(state->inode), dentry); - /* d_splice_alias() can't fail here - it's a non-directory */ - if (alias) { - dput(ctx->dentry); - ctx->dentry = dentry = alias; - } - } - switch(opendata->o_arg.claim) { default: break; @@ -3196,7 +3184,20 @@ static int _nfs4_open_and_get_state(struct nfs4_opendata *opendata, break; if (opendata->o_res.delegation.type != 0) dir_verifier = nfs_save_change_attribute(dir); - nfs_set_verifier(dentry, dir_verifier); + } + + dentry = opendata->dentry; + nfs_set_verifier(dentry, dir_verifier); + if (d_really_is_negative(dentry)) { + struct dentry *alias; + d_drop(dentry); + alias = d_splice_alias(igrab(state->inode), dentry); + /* d_splice_alias() can't fail here - it's a non-directory */ + if (alias) { + dput(ctx->dentry); + nfs_set_verifier(alias, dir_verifier); + ctx->dentry = dentry = alias; + } } /* Parse layoutget results before we check for access */ From 38694f9aae00459ab443a7dc8b3949a6b33b560a Mon Sep 17 00:00:00 2001 From: Jonathan Curley Date: Wed, 12 Nov 2025 18:02:42 +0000 Subject: [PATCH 0921/2333] NFSv4/pNFS: Clear NFS_INO_LAYOUTCOMMIT in pnfs_mark_layout_stateid_invalid [ Upstream commit e0f8058f2cb56de0b7572f51cd563ca5debce746 ] Fixes a crash when layout is null during this call stack: write_inode -> nfs4_write_inode -> pnfs_layoutcommit_inode pnfs_set_layoutcommit relies on the lseg refcount to keep the layout around. Need to clear NFS_INO_LAYOUTCOMMIT otherwise we might attempt to reference a null layout. Fixes: fe1cf9469d7bc ("pNFS: Clear all layout segment state in pnfs_mark_layout_stateid_invalid") Signed-off-by: Jonathan Curley Signed-off-by: Trond Myklebust Signed-off-by: Sasha Levin --- fs/nfs/pnfs.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index a3135b5af7eec..7ce2e840217cf 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c @@ -464,6 +464,7 @@ pnfs_mark_layout_stateid_invalid(struct pnfs_layout_hdr *lo, struct pnfs_layout_segment *lseg, *next; set_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags); + clear_bit(NFS_INO_LAYOUTCOMMIT, &NFS_I(lo->plh_inode)->flags); list_for_each_entry_safe(lseg, next, &lo->plh_segs, pls_list) pnfs_clear_lseg_state(lseg, lseg_list); pnfs_clear_layoutreturn_info(lo); From c646ebff3fa571e7ea974235286fb9ed3edc260c Mon Sep 17 00:00:00 2001 From: Akash Goel Date: Thu, 27 Nov 2025 16:49:12 +0000 Subject: [PATCH 0922/2333] drm/panthor: Prevent potential UAF in group creation [ Upstream commit eec7e23d848d2194dd8791fcd0f4a54d4378eecd ] This commit prevents the possibility of a use after free issue in the GROUP_CREATE ioctl function, which arose as pointer to the group is accessed in that ioctl function after storing it in the Xarray. A malicious userspace can second guess the handle of a group and try to call GROUP_DESTROY ioctl from another thread around the same time as GROUP_CREATE ioctl. To prevent the use after free exploit, this commit uses a mark on an entry of group pool Xarray which is added just before returning from the GROUP_CREATE ioctl function. The mark is checked for all ioctls that specify the group handle and so userspace won't be abe to delete a group that isn't marked yet. v2: Add R-bs and fixes tags Fixes: de85488138247 ("drm/panthor: Add the scheduler logical block") Co-developed-by: Boris Brezillon Signed-off-by: Boris Brezillon Signed-off-by: Akash Goel Reviewed-by: Boris Brezillon Reviewed-by: Steven Price Reviewed-by: Chia-I Wu Link: https://patch.msgid.link/20251127164912.3788155-1-akash.goel@arm.com Signed-off-by: Sasha Levin --- drivers/gpu/drm/panthor/panthor_sched.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/panthor/panthor_sched.c b/drivers/gpu/drm/panthor/panthor_sched.c index 0279e19aadae9..881a07ffbabc8 100644 --- a/drivers/gpu/drm/panthor/panthor_sched.c +++ b/drivers/gpu/drm/panthor/panthor_sched.c @@ -772,6 +772,12 @@ struct panthor_job_profiling_data { */ #define MAX_GROUPS_PER_POOL 128 +/* + * Mark added on an entry of group pool Xarray to identify if the group has + * been fully initialized and can be accessed elsewhere in the driver code. + */ +#define GROUP_REGISTERED XA_MARK_1 + /** * struct panthor_group_pool - Group pool * @@ -2900,7 +2906,7 @@ void panthor_fdinfo_gather_group_samples(struct panthor_file *pfile) return; xa_lock(&gpool->xa); - xa_for_each(&gpool->xa, i, group) { + xa_for_each_marked(&gpool->xa, i, group, GROUP_REGISTERED) { guard(spinlock)(&group->fdinfo.lock); pfile->stats.cycles += group->fdinfo.data.cycles; pfile->stats.time += group->fdinfo.data.time; @@ -3575,6 +3581,8 @@ int panthor_group_create(struct panthor_file *pfile, group_init_task_info(group); + xa_set_mark(&gpool->xa, gid, GROUP_REGISTERED); + return gid; err_put_group: @@ -3589,6 +3597,9 @@ int panthor_group_destroy(struct panthor_file *pfile, u32 group_handle) struct panthor_scheduler *sched = ptdev->scheduler; struct panthor_group *group; + if (!xa_get_mark(&gpool->xa, group_handle, GROUP_REGISTERED)) + return -EINVAL; + group = xa_erase(&gpool->xa, group_handle); if (!group) return -EINVAL; @@ -3614,12 +3625,12 @@ int panthor_group_destroy(struct panthor_file *pfile, u32 group_handle) } static struct panthor_group *group_from_handle(struct panthor_group_pool *pool, - u32 group_handle) + unsigned long group_handle) { struct panthor_group *group; xa_lock(&pool->xa); - group = group_get(xa_load(&pool->xa, group_handle)); + group = group_get(xa_find(&pool->xa, &group_handle, group_handle, GROUP_REGISTERED)); xa_unlock(&pool->xa); return group; @@ -3706,7 +3717,7 @@ panthor_fdinfo_gather_group_mem_info(struct panthor_file *pfile, return; xa_lock(&gpool->xa); - xa_for_each(&gpool->xa, i, group) { + xa_for_each_marked(&gpool->xa, i, group, GROUP_REGISTERED) { stats->resident += group->fdinfo.kbo_sizes; if (group->csg_id >= 0) stats->active += group->fdinfo.kbo_sizes; From 699e32e42faf9b7948a19c84c1dc52b52f04aac5 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Fri, 28 Nov 2025 13:39:07 -0500 Subject: [PATCH 0923/2333] Revert "nfs: ignore SB_RDONLY when remounting nfs" [ Upstream commit 400fa37afbb11a601c204b72af0f0e5bc2db695c ] This reverts commit 80c4de6ab44c14e910117a02f2f8241ffc6ec54a. Silently ignoring the "ro" and "rw" mount options causes user confusion, and regressions. Reported-by: Alkis Georgopoulos Cc: Li Lingfeng Fixes: 80c4de6ab44c ("nfs: ignore SB_RDONLY when remounting nfs") Signed-off-by: Trond Myklebust Signed-off-by: Sasha Levin --- fs/nfs/super.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 72dee6f3050e6..527000f5d150c 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -1051,16 +1051,6 @@ int nfs_reconfigure(struct fs_context *fc) sync_filesystem(sb); - /* - * The SB_RDONLY flag has been removed from the superblock during - * mounts to prevent interference between different filesystems. - * Similarly, it is also necessary to ignore the SB_RDONLY flag - * during reconfiguration; otherwise, it may also result in the - * creation of redundant superblocks when mounting a directory with - * different rw and ro flags multiple times. - */ - fc->sb_flags_mask &= ~SB_RDONLY; - /* * Userspace mount programs that send binary options generally send * them populated with default values. We have no way to know which From 10d58baf7d0e0f6add673d24d83c665d7b62c0c9 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Fri, 28 Nov 2025 13:39:38 -0500 Subject: [PATCH 0924/2333] Revert "nfs: clear SB_RDONLY before getting superblock" [ Upstream commit d216b698d44e33417ad4cc796cb04ccddbb8c0ee ] This reverts commit 8cd9b785943c57a136536250da80ba1eb6f8eb18. Silently ignoring the "ro" and "rw" mount options causes user confusion, and regressions. Reported-by: Alkis Georgopoulos Cc: Li Lingfeng Fixes: 8cd9b785943c ("nfs: clear SB_RDONLY before getting superblock") Signed-off-by: Trond Myklebust Signed-off-by: Sasha Levin --- fs/nfs/super.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 527000f5d150c..9b9464e70a7f0 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -1308,17 +1308,8 @@ int nfs_get_tree_common(struct fs_context *fc) if (IS_ERR(server)) return PTR_ERR(server); - /* - * When NFS_MOUNT_UNSHARED is not set, NFS forces the sharing of a - * superblock among each filesystem that mounts sub-directories - * belonging to a single exported root path. - * To prevent interference between different filesystems, the - * SB_RDONLY flag should be removed from the superblock. - */ if (server->flags & NFS_MOUNT_UNSHARED) compare_super = NULL; - else - fc->sb_flags &= ~SB_RDONLY; /* -o noac implies -o sync */ if (server->flags & NFS_MOUNT_NOAC) From c30cb13edcbff4145fe1bbb5898126717fe07f6a Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Fri, 28 Nov 2025 13:39:45 -0500 Subject: [PATCH 0925/2333] Revert "nfs: ignore SB_RDONLY when mounting nfs" [ Upstream commit d4a26d34f1946142f9d32e540490e4926ae9a46b ] This reverts commit 52cb7f8f177878b4f22397b9c4d2c8f743766be3. Silently ignoring the "ro" and "rw" mount options causes user confusion, and regressions. Reported-by: Alkis Georgopoulos Cc: Li Lingfeng Fixes: 52cb7f8f1778 ("nfs: ignore SB_RDONLY when mounting nfs") Signed-off-by: Trond Myklebust Signed-off-by: Sasha Levin --- fs/nfs/internal.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index 2ecd38e1d17a8..ffd382aa31ac0 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h @@ -13,7 +13,7 @@ #include #include -#define NFS_SB_MASK (SB_NOSUID|SB_NODEV|SB_NOEXEC|SB_SYNCHRONOUS) +#define NFS_SB_MASK (SB_RDONLY|SB_NOSUID|SB_NODEV|SB_NOEXEC|SB_SYNCHRONOUS) extern const struct export_operations nfs_export_ops; From df9b003a2ecacc7218486fbb31fe008c93097d5f Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Fri, 28 Nov 2025 14:22:44 -0500 Subject: [PATCH 0926/2333] NFS: Automounted filesystems should inherit ro,noexec,nodev,sync flags [ Upstream commit 8675c69816e4276b979ff475ee5fac4688f80125 ] When a filesystem is being automounted, it needs to preserve the user-set superblock mount options, such as the "ro" flag. Reported-by: Li Lingfeng Link: https://lore.kernel.org/all/20240604112636.236517-3-lilingfeng@huaweicloud.com/ Fixes: f2aedb713c28 ("NFS: Add fs_context support.") Signed-off-by: Trond Myklebust Signed-off-by: Sasha Levin --- fs/nfs/namespace.c | 6 ++++++ fs/nfs/super.c | 4 ---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c index 5a4d193da1a98..dca055676c4f3 100644 --- a/fs/nfs/namespace.c +++ b/fs/nfs/namespace.c @@ -149,6 +149,7 @@ struct vfsmount *nfs_d_automount(struct path *path) struct vfsmount *mnt = ERR_PTR(-ENOMEM); struct nfs_server *server = NFS_SB(path->dentry->d_sb); struct nfs_client *client = server->nfs_client; + unsigned long s_flags = path->dentry->d_sb->s_flags; int timeout = READ_ONCE(nfs_mountpoint_expiry_timeout); int ret; @@ -174,6 +175,11 @@ struct vfsmount *nfs_d_automount(struct path *path) fc->net_ns = get_net(client->cl_net); } + /* Inherit the flags covered by NFS_SB_MASK */ + fc->sb_flags_mask |= NFS_SB_MASK; + fc->sb_flags &= ~NFS_SB_MASK; + fc->sb_flags |= s_flags & NFS_SB_MASK; + /* for submounts we want the same server; referrals will reassign */ memcpy(&ctx->nfs_server._address, &client->cl_addr, client->cl_addrlen); ctx->nfs_server.addrlen = client->cl_addrlen; diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 9b9464e70a7f0..66413133b43e3 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -1315,10 +1315,6 @@ int nfs_get_tree_common(struct fs_context *fc) if (server->flags & NFS_MOUNT_NOAC) fc->sb_flags |= SB_SYNCHRONOUS; - if (ctx->clone_data.sb) - if (ctx->clone_data.sb->s_flags & SB_SYNCHRONOUS) - fc->sb_flags |= SB_SYNCHRONOUS; - /* Get a superblock - note that we may end up sharing one that already exists */ fc->s_fs_info = server; s = sget_fc(fc, compare_super, nfs_set_super); From 6d335d8a26bf79092d2fd3486546ec8a466470fd Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Fri, 28 Nov 2025 16:06:41 -0500 Subject: [PATCH 0927/2333] NFS: Fix inheritance of the block sizes when automounting [ Upstream commit 2b092175f5e301cdaa935093edfef2be9defb6df ] Only inherit the block sizes that were actually specified as mount parameters for the parent mount. Fixes: 62a55d088cd8 ("NFS: Additional refactoring for fs_context conversion") Signed-off-by: Trond Myklebust Signed-off-by: Sasha Levin --- fs/nfs/client.c | 21 +++++++++++++++++---- fs/nfs/internal.h | 1 - fs/nfs/namespace.c | 5 ++++- fs/nfs/nfs4client.c | 18 ++++++++++++++---- fs/nfs/super.c | 10 +++------- include/linux/nfs_fs_sb.h | 5 +++++ 6 files changed, 43 insertions(+), 17 deletions(-) diff --git a/fs/nfs/client.c b/fs/nfs/client.c index 54699299d5b16..2aaea9c98c2cd 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c @@ -784,10 +784,18 @@ static int nfs_init_server(struct nfs_server *server, server->fattr_valid = NFS_ATTR_FATTR_V4; } - if (ctx->rsize) + if (ctx->bsize) { + server->bsize = ctx->bsize; + server->automount_inherit |= NFS_AUTOMOUNT_INHERIT_BSIZE; + } + if (ctx->rsize) { server->rsize = nfs_io_size(ctx->rsize, clp->cl_proto); - if (ctx->wsize) + server->automount_inherit |= NFS_AUTOMOUNT_INHERIT_RSIZE; + } + if (ctx->wsize) { server->wsize = nfs_io_size(ctx->wsize, clp->cl_proto); + server->automount_inherit |= NFS_AUTOMOUNT_INHERIT_WSIZE; + } server->acregmin = ctx->acregmin * HZ; server->acregmax = ctx->acregmax * HZ; @@ -977,8 +985,13 @@ EXPORT_SYMBOL_GPL(nfs_probe_server); void nfs_server_copy_userdata(struct nfs_server *target, struct nfs_server *source) { target->flags = source->flags; - target->rsize = source->rsize; - target->wsize = source->wsize; + target->automount_inherit = source->automount_inherit; + if (source->automount_inherit & NFS_AUTOMOUNT_INHERIT_BSIZE) + target->bsize = source->bsize; + if (source->automount_inherit & NFS_AUTOMOUNT_INHERIT_RSIZE) + target->rsize = source->rsize; + if (source->automount_inherit & NFS_AUTOMOUNT_INHERIT_WSIZE) + target->wsize = source->wsize; target->acregmin = source->acregmin; target->acregmax = source->acregmax; target->acdirmin = source->acdirmin; diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index ffd382aa31ac0..2e596244799f3 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h @@ -152,7 +152,6 @@ struct nfs_fs_context { struct super_block *sb; struct dentry *dentry; struct nfs_fattr *fattr; - unsigned int inherited_bsize; } clone_data; }; diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c index dca055676c4f3..9e4d94f41fc67 100644 --- a/fs/nfs/namespace.c +++ b/fs/nfs/namespace.c @@ -190,6 +190,10 @@ struct vfsmount *nfs_d_automount(struct path *path) ctx->nfs_mod = client->cl_nfs_mod; get_nfs_version(ctx->nfs_mod); + /* Inherit block sizes if they were specified as mount parameters */ + if (server->automount_inherit & NFS_AUTOMOUNT_INHERIT_BSIZE) + ctx->bsize = server->bsize; + ret = client->rpc_ops->submount(fc, server); if (ret < 0) { mnt = ERR_PTR(ret); @@ -289,7 +293,6 @@ int nfs_do_submount(struct fs_context *fc) return -ENOMEM; ctx->internal = true; - ctx->clone_data.inherited_bsize = ctx->clone_data.sb->s_blocksize_bits; p = nfs_devname(dentry, buffer, 4096); if (IS_ERR(p)) { diff --git a/fs/nfs/nfs4client.c b/fs/nfs/nfs4client.c index 3a4baed993c96..4ff0e9dd1145e 100644 --- a/fs/nfs/nfs4client.c +++ b/fs/nfs/nfs4client.c @@ -1174,10 +1174,20 @@ static int nfs4_init_server(struct nfs_server *server, struct fs_context *fc) if (error < 0) return error; - if (ctx->rsize) - server->rsize = nfs_io_size(ctx->rsize, server->nfs_client->cl_proto); - if (ctx->wsize) - server->wsize = nfs_io_size(ctx->wsize, server->nfs_client->cl_proto); + if (ctx->bsize) { + server->bsize = ctx->bsize; + server->automount_inherit |= NFS_AUTOMOUNT_INHERIT_BSIZE; + } + if (ctx->rsize) { + server->rsize = + nfs_io_size(ctx->rsize, server->nfs_client->cl_proto); + server->automount_inherit |= NFS_AUTOMOUNT_INHERIT_RSIZE; + } + if (ctx->wsize) { + server->wsize = + nfs_io_size(ctx->wsize, server->nfs_client->cl_proto); + server->automount_inherit |= NFS_AUTOMOUNT_INHERIT_WSIZE; + } server->acregmin = ctx->acregmin * HZ; server->acregmax = ctx->acregmax * HZ; diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 66413133b43e3..57d372db03b93 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -1091,8 +1091,9 @@ static void nfs_fill_super(struct super_block *sb, struct nfs_fs_context *ctx) sb->s_blocksize = 0; sb->s_xattr = server->nfs_client->cl_nfs_mod->xattr; sb->s_op = server->nfs_client->cl_nfs_mod->sops; - if (ctx->bsize) - sb->s_blocksize = nfs_block_size(ctx->bsize, &sb->s_blocksize_bits); + if (server->bsize) + sb->s_blocksize = + nfs_block_size(server->bsize, &sb->s_blocksize_bits); switch (server->nfs_client->rpc_ops->version) { case 2: @@ -1338,13 +1339,8 @@ int nfs_get_tree_common(struct fs_context *fc) } if (!s->s_root) { - unsigned bsize = ctx->clone_data.inherited_bsize; /* initial superblock/root creation */ nfs_fill_super(s, ctx); - if (bsize) { - s->s_blocksize_bits = bsize; - s->s_blocksize = 1U << bsize; - } error = nfs_get_cache_cookie(s, ctx); if (error < 0) goto error_splat_super; diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h index d30c0245031c0..30ac384e011a4 100644 --- a/include/linux/nfs_fs_sb.h +++ b/include/linux/nfs_fs_sb.h @@ -172,6 +172,11 @@ struct nfs_server { #define NFS_MOUNT_FORCE_RDIRPLUS 0x20000000 #define NFS_MOUNT_NETUNREACH_FATAL 0x40000000 + unsigned int automount_inherit; /* Properties inherited by automount */ +#define NFS_AUTOMOUNT_INHERIT_BSIZE 0x0001 +#define NFS_AUTOMOUNT_INHERIT_RSIZE 0x0002 +#define NFS_AUTOMOUNT_INHERIT_WSIZE 0x0004 + unsigned int caps; /* server capabilities */ __u64 fattr_valid; /* Valid attributes */ unsigned int rsize; /* read size */ From c3430e94a0a235928253d9d06fde7d2dd7300d64 Mon Sep 17 00:00:00 2001 From: Armin Wolf Date: Sat, 29 Nov 2025 12:15:35 +0100 Subject: [PATCH 0928/2333] fs/nls: Fix inconsistency between utf8_to_utf32() and utf32_to_utf8() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit c36f9d7b2869a003a2f7d6ff2c6bac9e62fd7d68 ] After commit 25524b619029 ("fs/nls: Fix utf16 to utf8 conversion"), the return values of utf8_to_utf32() and utf32_to_utf8() are inconsistent when encountering an error: utf8_to_utf32() returns -1, while utf32_to_utf8() returns errno codes. Fix this inconsistency by modifying utf8_to_utf32() to return errno codes as well. Fixes: 25524b619029 ("fs/nls: Fix utf16 to utf8 conversion") Suggested-by: Andy Shevchenko Reviewed-by: Andy Shevchenko Signed-off-by: Armin Wolf Link: https://patch.msgid.link/20251129111535.8984-1-W_Armin@gmx.de Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen Signed-off-by: Sasha Levin --- fs/nls/nls_base.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/fs/nls/nls_base.c b/fs/nls/nls_base.c index d434c4463a8f7..a5c3a9f1b8dc5 100644 --- a/fs/nls/nls_base.c +++ b/fs/nls/nls_base.c @@ -67,19 +67,22 @@ int utf8_to_utf32(const u8 *s, int inlen, unicode_t *pu) l &= t->lmask; if (l < t->lval || l > UNICODE_MAX || (l & SURROGATE_MASK) == SURROGATE_PAIR) - return -1; + return -EILSEQ; + *pu = (unicode_t) l; return nc; } if (inlen <= nc) - return -1; + return -EOVERFLOW; + s++; c = (*s ^ 0x80) & 0xFF; if (c & 0xC0) - return -1; + return -EILSEQ; + l = (l << 6) | c; } - return -1; + return -EILSEQ; } EXPORT_SYMBOL(utf8_to_utf32); From 2606e7e090fe19237cf8604e3445e1c4cf657c88 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Sat, 29 Nov 2025 11:13:08 +0100 Subject: [PATCH 0929/2333] platform/x86: asus-wmi: use brightness_set_blocking() for kbd led MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit ccb61a328321ba3f8567e350664c9ca7a42b6c70 ] kbd_led_set() can sleep, and so may not be used as the brightness_set() callback. Otherwise using this led with a trigger leads to system hangs accompanied by: BUG: scheduling while atomic: acpi_fakekeyd/2588/0x00000003 CPU: 4 UID: 0 PID: 2588 Comm: acpi_fakekeyd Not tainted 6.17.9+deb14-amd64 #1 PREEMPT(lazy) Debian 6.17.9-1 Hardware name: ASUSTeK COMPUTER INC. ASUS EXPERTBOOK B9403CVAR/B9403CVAR, BIOS B9403CVAR.311 12/24/2024 Call Trace: [...] schedule_timeout+0xbd/0x100 __down_common+0x175/0x290 down_timeout+0x67/0x70 acpi_os_wait_semaphore+0x57/0x90 [...] asus_wmi_evaluate_method3+0x87/0x190 [asus_wmi] led_trigger_event+0x3f/0x60 [...] Fixes: 9fe44fc98ce4 ("platform/x86: asus-wmi: Simplify the keyboard brightness updating process") Signed-off-by: Anton Khirnov Reviewed-by: Andy Shevchenko Reviewed-by: Denis Benato Link: https://patch.msgid.link/20251129101307.18085-3-anton@khirnov.net Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen Signed-off-by: Sasha Levin --- drivers/platform/x86/asus-wmi.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index e72a2b5d158e9..8e3300f5c2943 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -1619,14 +1619,14 @@ static void do_kbd_led_set(struct led_classdev *led_cdev, int value) kbd_led_update(asus); } -static void kbd_led_set(struct led_classdev *led_cdev, - enum led_brightness value) +static int kbd_led_set(struct led_classdev *led_cdev, enum led_brightness value) { /* Prevent disabling keyboard backlight on module unregister */ if (led_cdev->flags & LED_UNREGISTERING) - return; + return 0; do_kbd_led_set(led_cdev, value); + return 0; } static void kbd_led_set_by_kbd(struct asus_wmi *asus, enum led_brightness value) @@ -1802,7 +1802,7 @@ static int asus_wmi_led_init(struct asus_wmi *asus) asus->kbd_led_wk = led_val; asus->kbd_led.name = "asus::kbd_backlight"; asus->kbd_led.flags = LED_BRIGHT_HW_CHANGED; - asus->kbd_led.brightness_set = kbd_led_set; + asus->kbd_led.brightness_set_blocking = kbd_led_set; asus->kbd_led.brightness_get = kbd_led_get; asus->kbd_led.max_brightness = 3; From 488ef9dd5c094a96d506a502aa467b983484c4b5 Mon Sep 17 00:00:00 2001 From: Haotian Zhang Date: Tue, 2 Dec 2025 18:16:42 +0800 Subject: [PATCH 0930/2333] ASoC: bcm: bcm63xx-pcm-whistler: Check return value of of_dma_configure() [ Upstream commit 0ebbd45c33d0049ebf5a22c1434567f0c420b333 ] bcm63xx_soc_pcm_new() does not check the return value of of_dma_configure(), which may fail with -EPROBE_DEFER or other errors, allowing PCM setup to continue with incomplete DMA configuration. Add error checking for of_dma_configure() and return on failure. Fixes: 88eb404ccc3e ("ASoC: brcm: Add DSL/PON SoC audio driver") Signed-off-by: Haotian Zhang Link: https://patch.msgid.link/20251202101642.492-1-vulab@iscas.ac.cn Signed-off-by: Mark Brown Signed-off-by: Sasha Levin --- sound/soc/bcm/bcm63xx-pcm-whistler.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sound/soc/bcm/bcm63xx-pcm-whistler.c b/sound/soc/bcm/bcm63xx-pcm-whistler.c index e3a4fcc63a56d..efeb06ddabeb3 100644 --- a/sound/soc/bcm/bcm63xx-pcm-whistler.c +++ b/sound/soc/bcm/bcm63xx-pcm-whistler.c @@ -358,7 +358,9 @@ static int bcm63xx_soc_pcm_new(struct snd_soc_component *component, i2s_priv = dev_get_drvdata(snd_soc_rtd_to_cpu(rtd, 0)->dev); - of_dma_configure(pcm->card->dev, pcm->card->dev->of_node, 1); + ret = of_dma_configure(pcm->card->dev, pcm->card->dev->of_node, 1); + if (ret) + return ret; ret = dma_coerce_mask_and_coherent(pcm->card->dev, DMA_BIT_MASK(32)); if (ret) From a52d027b4d6bc818b17f2523be2c2464b9db79be Mon Sep 17 00:00:00 2001 From: Hemalatha Pinnamreddy Date: Wed, 3 Dec 2025 12:16:48 +0530 Subject: [PATCH 0931/2333] ASoC: amd: acp: Audio is not resuming after s0ix [ Upstream commit 3ee257aba1d56c3f0f1028669a8ad0f1a477f05b ] Audio fails to resume after system exits suspend mode due to accessing incorrect ring buffer address during resume. This patch resolves issue by selecting correct address based on the ACP version. Fixes: f6f7d25b11033 ("ASoC: amd: acp: Add pte configuration for ACP7.0 platform") Signed-off-by: Hemalatha Pinnamreddy Signed-off-by: Raghavendra Prasad Mallela Reviewed-by: Mario Limonciello (AMD) Link: https://patch.msgid.link/20251203064650.2554625-1-raghavendraprasad.mallela@amd.com Signed-off-by: Mark Brown Signed-off-by: Sasha Levin --- sound/soc/amd/acp/acp-legacy-common.c | 30 +++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/sound/soc/amd/acp/acp-legacy-common.c b/sound/soc/amd/acp/acp-legacy-common.c index 3078f459e0050..4e477c48d4bdd 100644 --- a/sound/soc/amd/acp/acp-legacy-common.c +++ b/sound/soc/amd/acp/acp-legacy-common.c @@ -219,7 +219,10 @@ static int set_acp_i2s_dma_fifo(struct snd_pcm_substream *substream, SP_PB_FIFO_ADDR_OFFSET; reg_fifo_addr = ACP_I2S_TX_FIFOADDR(chip); reg_fifo_size = ACP_I2S_TX_FIFOSIZE(chip); - phy_addr = I2S_SP_TX_MEM_WINDOW_START + stream->reg_offset; + if (chip->acp_rev >= ACP70_PCI_ID) + phy_addr = ACP7x_I2S_SP_TX_MEM_WINDOW_START; + else + phy_addr = I2S_SP_TX_MEM_WINDOW_START + stream->reg_offset; writel(phy_addr, chip->base + ACP_I2S_TX_RINGBUFADDR(chip)); } else { reg_dma_size = ACP_I2S_RX_DMA_SIZE(chip); @@ -227,7 +230,10 @@ static int set_acp_i2s_dma_fifo(struct snd_pcm_substream *substream, SP_CAPT_FIFO_ADDR_OFFSET; reg_fifo_addr = ACP_I2S_RX_FIFOADDR(chip); reg_fifo_size = ACP_I2S_RX_FIFOSIZE(chip); - phy_addr = I2S_SP_RX_MEM_WINDOW_START + stream->reg_offset; + if (chip->acp_rev >= ACP70_PCI_ID) + phy_addr = ACP7x_I2S_SP_RX_MEM_WINDOW_START; + else + phy_addr = I2S_SP_RX_MEM_WINDOW_START + stream->reg_offset; writel(phy_addr, chip->base + ACP_I2S_RX_RINGBUFADDR(chip)); } break; @@ -238,7 +244,10 @@ static int set_acp_i2s_dma_fifo(struct snd_pcm_substream *substream, BT_PB_FIFO_ADDR_OFFSET; reg_fifo_addr = ACP_BT_TX_FIFOADDR(chip); reg_fifo_size = ACP_BT_TX_FIFOSIZE(chip); - phy_addr = I2S_BT_TX_MEM_WINDOW_START + stream->reg_offset; + if (chip->acp_rev >= ACP70_PCI_ID) + phy_addr = ACP7x_I2S_BT_TX_MEM_WINDOW_START; + else + phy_addr = I2S_BT_TX_MEM_WINDOW_START + stream->reg_offset; writel(phy_addr, chip->base + ACP_BT_TX_RINGBUFADDR(chip)); } else { reg_dma_size = ACP_BT_RX_DMA_SIZE(chip); @@ -246,7 +255,10 @@ static int set_acp_i2s_dma_fifo(struct snd_pcm_substream *substream, BT_CAPT_FIFO_ADDR_OFFSET; reg_fifo_addr = ACP_BT_RX_FIFOADDR(chip); reg_fifo_size = ACP_BT_RX_FIFOSIZE(chip); - phy_addr = I2S_BT_TX_MEM_WINDOW_START + stream->reg_offset; + if (chip->acp_rev >= ACP70_PCI_ID) + phy_addr = ACP7x_I2S_BT_RX_MEM_WINDOW_START; + else + phy_addr = I2S_BT_RX_MEM_WINDOW_START + stream->reg_offset; writel(phy_addr, chip->base + ACP_BT_RX_RINGBUFADDR(chip)); } break; @@ -257,7 +269,10 @@ static int set_acp_i2s_dma_fifo(struct snd_pcm_substream *substream, HS_PB_FIFO_ADDR_OFFSET; reg_fifo_addr = ACP_HS_TX_FIFOADDR; reg_fifo_size = ACP_HS_TX_FIFOSIZE; - phy_addr = I2S_HS_TX_MEM_WINDOW_START + stream->reg_offset; + if (chip->acp_rev >= ACP70_PCI_ID) + phy_addr = ACP7x_I2S_HS_TX_MEM_WINDOW_START; + else + phy_addr = I2S_HS_TX_MEM_WINDOW_START + stream->reg_offset; writel(phy_addr, chip->base + ACP_HS_TX_RINGBUFADDR); } else { reg_dma_size = ACP_HS_RX_DMA_SIZE; @@ -265,7 +280,10 @@ static int set_acp_i2s_dma_fifo(struct snd_pcm_substream *substream, HS_CAPT_FIFO_ADDR_OFFSET; reg_fifo_addr = ACP_HS_RX_FIFOADDR; reg_fifo_size = ACP_HS_RX_FIFOSIZE; - phy_addr = I2S_HS_RX_MEM_WINDOW_START + stream->reg_offset; + if (chip->acp_rev >= ACP70_PCI_ID) + phy_addr = ACP7x_I2S_HS_RX_MEM_WINDOW_START; + else + phy_addr = I2S_HS_RX_MEM_WINDOW_START + stream->reg_offset; writel(phy_addr, chip->base + ACP_HS_RX_RINGBUFADDR); } break; From a15353ac167fad88af1e03781b869d51c5f54860 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Wed, 3 Dec 2025 18:05:28 +0800 Subject: [PATCH 0932/2333] ASoC: ak4458: Disable regulator when error happens [ Upstream commit ae585fabb9713a43e358cf606451386757225c95 ] Disable regulator in runtime resume when error happens to balance the reference count of regulator. Fixes: 7e3096e8f823 ("ASoC: ak4458: Add regulator support") Signed-off-by: Shengjiu Wang Link: https://patch.msgid.link/20251203100529.3841203-2-shengjiu.wang@nxp.com Signed-off-by: Mark Brown Signed-off-by: Sasha Levin --- sound/soc/codecs/ak4458.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/ak4458.c b/sound/soc/codecs/ak4458.c index 57cf601d3df35..a6c04dd3de3ed 100644 --- a/sound/soc/codecs/ak4458.c +++ b/sound/soc/codecs/ak4458.c @@ -671,7 +671,15 @@ static int ak4458_runtime_resume(struct device *dev) regcache_cache_only(ak4458->regmap, false); regcache_mark_dirty(ak4458->regmap); - return regcache_sync(ak4458->regmap); + ret = regcache_sync(ak4458->regmap); + if (ret) + goto err; + + return 0; +err: + regcache_cache_only(ak4458->regmap, true); + regulator_bulk_disable(ARRAY_SIZE(ak4458->supplies), ak4458->supplies); + return ret; } static const struct snd_soc_component_driver soc_codec_dev_ak4458 = { From 9a3192f81819da52f3f67b42955da873382dff57 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Wed, 3 Dec 2025 18:05:29 +0800 Subject: [PATCH 0933/2333] ASoC: ak5558: Disable regulator when error happens [ Upstream commit 1f8f726a2a29c28f65b30880335a1610c5e63594 ] Disable regulator in runtime resume when error happens to balance the reference count of regulator. Fixes: 2ff6d5a108c6 ("ASoC: ak5558: Add regulator support") Signed-off-by: Shengjiu Wang Link: https://patch.msgid.link/20251203100529.3841203-3-shengjiu.wang@nxp.com Signed-off-by: Mark Brown Signed-off-by: Sasha Levin --- sound/soc/codecs/ak5558.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/ak5558.c b/sound/soc/codecs/ak5558.c index 683f3e472f500..73684fc5beb1a 100644 --- a/sound/soc/codecs/ak5558.c +++ b/sound/soc/codecs/ak5558.c @@ -372,7 +372,15 @@ static int ak5558_runtime_resume(struct device *dev) regcache_cache_only(ak5558->regmap, false); regcache_mark_dirty(ak5558->regmap); - return regcache_sync(ak5558->regmap); + ret = regcache_sync(ak5558->regmap); + if (ret) + goto err; + + return 0; +err: + regcache_cache_only(ak5558->regmap, true); + regulator_bulk_disable(ARRAY_SIZE(ak5558->supplies), ak5558->supplies); + return ret; } static const struct dev_pm_ops ak5558_pm = { From 6acd144fa8b115d4e7078e3882ac30151d01219a Mon Sep 17 00:00:00 2001 From: Daeho Jeong Date: Tue, 11 Nov 2025 09:52:46 -0800 Subject: [PATCH 0934/2333] f2fs: revert summary entry count from 2048 to 512 in 16kb block support [ Upstream commit 7ee8bc3942f20964ad730871b885688ea3a2961a ] The recent increase in the number of Segment Summary Area (SSA) entries from 512 to 2048 was an unintentional change in logic of 16kb block support. This commit corrects the issue. To better utilize the space available from the erroneous 2048-entry calculation, we are implementing a solution to share the currently unused SSA space with neighboring segments. This enhances overall SSA utilization without impacting the established 8MB segment size. Fixes: d7e9a9037de2 ("f2fs: Support Block Size == Page Size") Signed-off-by: Daeho Jeong Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim Signed-off-by: Sasha Levin --- fs/f2fs/f2fs.h | 2 + fs/f2fs/gc.c | 117 +++++++++++++++++++++++----------------- fs/f2fs/recovery.c | 2 +- fs/f2fs/segment.c | 38 +++++++++---- fs/f2fs/segment.h | 8 ++- fs/f2fs/super.c | 14 +++++ fs/f2fs/sysfs.c | 7 +++ include/linux/f2fs_fs.h | 5 +- 8 files changed, 130 insertions(+), 63 deletions(-) diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 5b4e9548a231f..5149f351f03d2 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -245,6 +245,7 @@ struct f2fs_mount_info { #define F2FS_FEATURE_COMPRESSION 0x00002000 #define F2FS_FEATURE_RO 0x00004000 #define F2FS_FEATURE_DEVICE_ALIAS 0x00008000 +#define F2FS_FEATURE_PACKED_SSA 0x00010000 #define __F2FS_HAS_FEATURE(raw_super, mask) \ ((raw_super->feature & cpu_to_le32(mask)) != 0) @@ -4710,6 +4711,7 @@ F2FS_FEATURE_FUNCS(casefold, CASEFOLD); F2FS_FEATURE_FUNCS(compression, COMPRESSION); F2FS_FEATURE_FUNCS(readonly, RO); F2FS_FEATURE_FUNCS(device_alias, DEVICE_ALIAS); +F2FS_FEATURE_FUNCS(packed_ssa, PACKED_SSA); #ifdef CONFIG_BLK_DEV_ZONED static inline bool f2fs_zone_is_seq(struct f2fs_sb_info *sbi, int devi, diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c index 8abf521530ff3..af2f4d28462c0 100644 --- a/fs/f2fs/gc.c +++ b/fs/f2fs/gc.c @@ -1732,7 +1732,7 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi, unsigned char type = IS_DATASEG(get_seg_entry(sbi, segno)->type) ? SUM_TYPE_DATA : SUM_TYPE_NODE; unsigned char data_type = (type == SUM_TYPE_DATA) ? DATA : NODE; - int submitted = 0; + int submitted = 0, sum_blk_cnt; if (__is_large_section(sbi)) { sec_end_segno = rounddown(end_segno, SEGS_PER_SEC(sbi)); @@ -1766,22 +1766,28 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi, sanity_check_seg_type(sbi, get_seg_entry(sbi, segno)->type); + segno = rounddown(segno, SUMS_PER_BLOCK); + sum_blk_cnt = DIV_ROUND_UP(end_segno - segno, SUMS_PER_BLOCK); /* readahead multi ssa blocks those have contiguous address */ if (__is_large_section(sbi)) f2fs_ra_meta_pages(sbi, GET_SUM_BLOCK(sbi, segno), - end_segno - segno, META_SSA, true); + sum_blk_cnt, META_SSA, true); /* reference all summary page */ while (segno < end_segno) { - struct folio *sum_folio = f2fs_get_sum_folio(sbi, segno++); + struct folio *sum_folio = f2fs_get_sum_folio(sbi, segno); + + segno += SUMS_PER_BLOCK; if (IS_ERR(sum_folio)) { int err = PTR_ERR(sum_folio); - end_segno = segno - 1; - for (segno = start_segno; segno < end_segno; segno++) { + end_segno = segno - SUMS_PER_BLOCK; + segno = rounddown(start_segno, SUMS_PER_BLOCK); + while (segno < end_segno) { sum_folio = filemap_get_folio(META_MAPPING(sbi), GET_SUM_BLOCK(sbi, segno)); folio_put_refs(sum_folio, 2); + segno += SUMS_PER_BLOCK; } return err; } @@ -1790,68 +1796,83 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi, blk_start_plug(&plug); - for (segno = start_segno; segno < end_segno; segno++) { - struct f2fs_summary_block *sum; + segno = start_segno; + while (segno < end_segno) { + unsigned int cur_segno; /* find segment summary of victim */ struct folio *sum_folio = filemap_get_folio(META_MAPPING(sbi), GET_SUM_BLOCK(sbi, segno)); + unsigned int block_end_segno = rounddown(segno, SUMS_PER_BLOCK) + + SUMS_PER_BLOCK; + + if (block_end_segno > end_segno) + block_end_segno = end_segno; if (is_cursec(sbi, GET_SEC_FROM_SEG(sbi, segno))) { f2fs_err(sbi, "%s: segment %u is used by log", __func__, segno); f2fs_bug_on(sbi, 1); - goto skip; + goto next_block; } - if (get_valid_blocks(sbi, segno, false) == 0) - goto freed; - if (gc_type == BG_GC && __is_large_section(sbi) && - migrated >= sbi->migration_granularity) - goto skip; if (!folio_test_uptodate(sum_folio) || unlikely(f2fs_cp_error(sbi))) - goto skip; + goto next_block; - sum = folio_address(sum_folio); - if (type != GET_SUM_TYPE((&sum->footer))) { - f2fs_err(sbi, "Inconsistent segment (%u) type [%d, %d] in SIT and SSA", - segno, type, GET_SUM_TYPE((&sum->footer))); - f2fs_stop_checkpoint(sbi, false, - STOP_CP_REASON_CORRUPTED_SUMMARY); - goto skip; - } + for (cur_segno = segno; cur_segno < block_end_segno; + cur_segno++) { + struct f2fs_summary_block *sum; - /* - * this is to avoid deadlock: - * - lock_page(sum_page) - f2fs_replace_block - * - check_valid_map() - down_write(sentry_lock) - * - down_read(sentry_lock) - change_curseg() - * - lock_page(sum_page) - */ - if (type == SUM_TYPE_NODE) - submitted += gc_node_segment(sbi, sum->entries, segno, - gc_type); - else - submitted += gc_data_segment(sbi, sum->entries, gc_list, - segno, gc_type, - force_migrate); + if (get_valid_blocks(sbi, cur_segno, false) == 0) + goto freed; + if (gc_type == BG_GC && __is_large_section(sbi) && + migrated >= sbi->migration_granularity) + continue; - stat_inc_gc_seg_count(sbi, data_type, gc_type); - sbi->gc_reclaimed_segs[sbi->gc_mode]++; - migrated++; + sum = SUM_BLK_PAGE_ADDR(sum_folio, cur_segno); + if (type != GET_SUM_TYPE((&sum->footer))) { + f2fs_err(sbi, "Inconsistent segment (%u) type " + "[%d, %d] in SSA and SIT", + cur_segno, type, + GET_SUM_TYPE((&sum->footer))); + f2fs_stop_checkpoint(sbi, false, + STOP_CP_REASON_CORRUPTED_SUMMARY); + continue; + } -freed: - if (gc_type == FG_GC && - get_valid_blocks(sbi, segno, false) == 0) - seg_freed++; + /* + * this is to avoid deadlock: + * - lock_page(sum_page) - f2fs_replace_block + * - check_valid_map() - down_write(sentry_lock) + * - down_read(sentry_lock) - change_curseg() + * - lock_page(sum_page) + */ + if (type == SUM_TYPE_NODE) + submitted += gc_node_segment(sbi, sum->entries, + cur_segno, gc_type); + else + submitted += gc_data_segment(sbi, sum->entries, + gc_list, cur_segno, + gc_type, force_migrate); - if (__is_large_section(sbi)) - sbi->next_victim_seg[gc_type] = - (segno + 1 < sec_end_segno) ? - segno + 1 : NULL_SEGNO; -skip: + stat_inc_gc_seg_count(sbi, data_type, gc_type); + sbi->gc_reclaimed_segs[sbi->gc_mode]++; + migrated++; + +freed: + if (gc_type == FG_GC && + get_valid_blocks(sbi, cur_segno, false) == 0) + seg_freed++; + + if (__is_large_section(sbi)) + sbi->next_victim_seg[gc_type] = + (cur_segno + 1 < sec_end_segno) ? + cur_segno + 1 : NULL_SEGNO; + } +next_block: folio_put_refs(sum_folio, 2); + segno = block_end_segno; } if (submitted) diff --git a/fs/f2fs/recovery.c b/fs/f2fs/recovery.c index 215e442db72c8..af72309b9bfc6 100644 --- a/fs/f2fs/recovery.c +++ b/fs/f2fs/recovery.c @@ -519,7 +519,7 @@ static int check_index_in_prev_nodes(struct f2fs_sb_info *sbi, sum_folio = f2fs_get_sum_folio(sbi, segno); if (IS_ERR(sum_folio)) return PTR_ERR(sum_folio); - sum_node = folio_address(sum_folio); + sum_node = SUM_BLK_PAGE_ADDR(sum_folio, segno); sum = sum_node->entries[blkoff]; f2fs_folio_put(sum_folio, true); got_it: diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index b45eace879d74..ac84559dc2693 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -2712,7 +2712,15 @@ struct folio *f2fs_get_sum_folio(struct f2fs_sb_info *sbi, unsigned int segno) void f2fs_update_meta_page(struct f2fs_sb_info *sbi, void *src, block_t blk_addr) { - struct folio *folio = f2fs_grab_meta_folio(sbi, blk_addr); + struct folio *folio; + + if (SUMS_PER_BLOCK == 1) + folio = f2fs_grab_meta_folio(sbi, blk_addr); + else + folio = f2fs_get_meta_folio_retry(sbi, blk_addr); + + if (IS_ERR(folio)) + return; memcpy(folio_address(folio), src, PAGE_SIZE); folio_mark_dirty(folio); @@ -2720,9 +2728,21 @@ void f2fs_update_meta_page(struct f2fs_sb_info *sbi, } static void write_sum_page(struct f2fs_sb_info *sbi, - struct f2fs_summary_block *sum_blk, block_t blk_addr) + struct f2fs_summary_block *sum_blk, unsigned int segno) { - f2fs_update_meta_page(sbi, (void *)sum_blk, blk_addr); + struct folio *folio; + + if (SUMS_PER_BLOCK == 1) + return f2fs_update_meta_page(sbi, (void *)sum_blk, + GET_SUM_BLOCK(sbi, segno)); + + folio = f2fs_get_sum_folio(sbi, segno); + if (IS_ERR(folio)) + return; + + memcpy(SUM_BLK_PAGE_ADDR(folio, segno), sum_blk, sizeof(*sum_blk)); + folio_mark_dirty(folio); + f2fs_folio_put(folio, true); } static void write_current_sum_page(struct f2fs_sb_info *sbi, @@ -2987,7 +3007,7 @@ static int new_curseg(struct f2fs_sb_info *sbi, int type, bool new_sec) int ret; if (curseg->inited) - write_sum_page(sbi, curseg->sum_blk, GET_SUM_BLOCK(sbi, segno)); + write_sum_page(sbi, curseg->sum_blk, segno); segno = __get_next_segno(sbi, type); ret = get_new_segment(sbi, &segno, new_sec, pinning); @@ -3046,7 +3066,7 @@ static int change_curseg(struct f2fs_sb_info *sbi, int type) struct folio *sum_folio; if (curseg->inited) - write_sum_page(sbi, curseg->sum_blk, GET_SUM_BLOCK(sbi, curseg->segno)); + write_sum_page(sbi, curseg->sum_blk, curseg->segno); __set_test_and_inuse(sbi, new_segno); @@ -3065,7 +3085,7 @@ static int change_curseg(struct f2fs_sb_info *sbi, int type) memset(curseg->sum_blk, 0, SUM_ENTRY_SIZE); return PTR_ERR(sum_folio); } - sum_node = folio_address(sum_folio); + sum_node = SUM_BLK_PAGE_ADDR(sum_folio, new_segno); memcpy(curseg->sum_blk, sum_node, SUM_ENTRY_SIZE); f2fs_folio_put(sum_folio, true); return 0; @@ -3154,8 +3174,7 @@ static void __f2fs_save_inmem_curseg(struct f2fs_sb_info *sbi, int type) goto out; if (get_valid_blocks(sbi, curseg->segno, false)) { - write_sum_page(sbi, curseg->sum_blk, - GET_SUM_BLOCK(sbi, curseg->segno)); + write_sum_page(sbi, curseg->sum_blk, curseg->segno); } else { mutex_lock(&DIRTY_I(sbi)->seglist_lock); __set_test_and_free(sbi, curseg->segno, true); @@ -3833,8 +3852,7 @@ int f2fs_allocate_data_block(struct f2fs_sb_info *sbi, struct folio *folio, 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)); + write_sum_page(sbi, curseg->sum_blk, curseg->segno); reset_curseg_fields(curseg); goto skip_new_segment; } diff --git a/fs/f2fs/segment.h b/fs/f2fs/segment.h index 1ce2c8abaf488..e883f14c228f2 100644 --- a/fs/f2fs/segment.h +++ b/fs/f2fs/segment.h @@ -85,8 +85,12 @@ static inline void sanity_check_seg_type(struct f2fs_sb_info *sbi, #define GET_ZONE_FROM_SEG(sbi, segno) \ GET_ZONE_FROM_SEC(sbi, GET_SEC_FROM_SEG(sbi, segno)) -#define GET_SUM_BLOCK(sbi, segno) \ - ((sbi)->sm_info->ssa_blkaddr + (segno)) +#define SUMS_PER_BLOCK (F2FS_BLKSIZE / F2FS_SUM_BLKSIZE) +#define GET_SUM_BLOCK(sbi, segno) \ + (SM_I(sbi)->ssa_blkaddr + (segno / SUMS_PER_BLOCK)) +#define GET_SUM_BLKOFF(segno) (segno % SUMS_PER_BLOCK) +#define SUM_BLK_PAGE_ADDR(folio, segno) \ + (folio_address(folio) + GET_SUM_BLKOFF(segno) * F2FS_SUM_BLKSIZE) #define GET_SUM_TYPE(footer) ((footer)->entry_type) #define SET_SUM_TYPE(footer, type) ((footer)->entry_type = (type)) diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index db7afb8064115..9085b4a511a48 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -4051,6 +4051,20 @@ static int sanity_check_raw_super(struct f2fs_sb_info *sbi, if (sanity_check_area_boundary(sbi, folio, index)) return -EFSCORRUPTED; + /* + * Check for legacy summary layout on 16KB+ block devices. + * Modern f2fs-tools packs multiple 4KB summary areas into one block, + * whereas legacy versions used one block per summary, leading + * to a much larger SSA. + */ + if (SUMS_PER_BLOCK > 1 && + !(__F2FS_HAS_FEATURE(raw_super, F2FS_FEATURE_PACKED_SSA))) { + f2fs_info(sbi, "Error: Device formatted with a legacy version. " + "Please reformat with a tool supporting the packed ssa " + "feature for block sizes larger than 4kb."); + return -EOPNOTSUPP; + } + return 0; } diff --git a/fs/f2fs/sysfs.c b/fs/f2fs/sysfs.c index 6d2a4fba68a29..5685b454bfd12 100644 --- a/fs/f2fs/sysfs.c +++ b/fs/f2fs/sysfs.c @@ -235,6 +235,9 @@ static ssize_t features_show(struct f2fs_attr *a, if (f2fs_sb_has_compression(sbi)) len += sysfs_emit_at(buf, len, "%s%s", len ? ", " : "", "compression"); + if (f2fs_sb_has_packed_ssa(sbi)) + len += sysfs_emit_at(buf, len, "%s%s", + len ? ", " : "", "packed_ssa"); len += sysfs_emit_at(buf, len, "%s%s", len ? ", " : "", "pin_file"); len += sysfs_emit_at(buf, len, "\n"); @@ -1296,6 +1299,7 @@ F2FS_FEATURE_RO_ATTR(pin_file); #ifdef CONFIG_UNICODE F2FS_FEATURE_RO_ATTR(linear_lookup); #endif +F2FS_FEATURE_RO_ATTR(packed_ssa); #define ATTR_LIST(name) (&f2fs_attr_##name.attr) static struct attribute *f2fs_attrs[] = { @@ -1455,6 +1459,7 @@ static struct attribute *f2fs_feat_attrs[] = { #ifdef CONFIG_UNICODE BASE_ATTR_LIST(linear_lookup), #endif + BASE_ATTR_LIST(packed_ssa), NULL, }; ATTRIBUTE_GROUPS(f2fs_feat); @@ -1490,6 +1495,7 @@ F2FS_SB_FEATURE_RO_ATTR(casefold, CASEFOLD); F2FS_SB_FEATURE_RO_ATTR(compression, COMPRESSION); F2FS_SB_FEATURE_RO_ATTR(readonly, RO); F2FS_SB_FEATURE_RO_ATTR(device_alias, DEVICE_ALIAS); +F2FS_SB_FEATURE_RO_ATTR(packed_ssa, PACKED_SSA); static struct attribute *f2fs_sb_feat_attrs[] = { ATTR_LIST(sb_encryption), @@ -1507,6 +1513,7 @@ static struct attribute *f2fs_sb_feat_attrs[] = { ATTR_LIST(sb_compression), ATTR_LIST(sb_readonly), ATTR_LIST(sb_device_alias), + ATTR_LIST(sb_packed_ssa), NULL, }; ATTRIBUTE_GROUPS(f2fs_sb_feat); diff --git a/include/linux/f2fs_fs.h b/include/linux/f2fs_fs.h index 6afb4a13b81d6..a7880787cad36 100644 --- a/include/linux/f2fs_fs.h +++ b/include/linux/f2fs_fs.h @@ -17,6 +17,7 @@ #define F2FS_LOG_SECTORS_PER_BLOCK (PAGE_SHIFT - 9) /* log number for sector/blk */ #define F2FS_BLKSIZE PAGE_SIZE /* support only block == page */ #define F2FS_BLKSIZE_BITS PAGE_SHIFT /* bits for F2FS_BLKSIZE */ +#define F2FS_SUM_BLKSIZE 4096 /* only support 4096 byte sum block */ #define F2FS_MAX_EXTENSION 64 /* # of extension entries */ #define F2FS_EXTENSION_LEN 8 /* max size of extension */ @@ -441,7 +442,7 @@ struct f2fs_sit_block { * from node's page's beginning to get a data block address. * ex) data_blkaddr = (block_t)(nodepage_start_address + ofs_in_node) */ -#define ENTRIES_IN_SUM (F2FS_BLKSIZE / 8) +#define ENTRIES_IN_SUM (F2FS_SUM_BLKSIZE / 8) #define SUMMARY_SIZE (7) /* sizeof(struct f2fs_summary) */ #define SUM_FOOTER_SIZE (5) /* sizeof(struct summary_footer) */ #define SUM_ENTRY_SIZE (SUMMARY_SIZE * ENTRIES_IN_SUM) @@ -467,7 +468,7 @@ struct summary_footer { __le32 check_sum; /* summary checksum */ } __packed; -#define SUM_JOURNAL_SIZE (F2FS_BLKSIZE - SUM_FOOTER_SIZE -\ +#define SUM_JOURNAL_SIZE (F2FS_SUM_BLKSIZE - SUM_FOOTER_SIZE -\ SUM_ENTRY_SIZE) #define NAT_JOURNAL_ENTRIES ((SUM_JOURNAL_SIZE - 2) /\ sizeof(struct nat_journal_entry)) From 7b91877113945d4c300ff329b66aa566f72d0874 Mon Sep 17 00:00:00 2001 From: Cong Zhang Date: Wed, 3 Dec 2025 11:34:21 +0800 Subject: [PATCH 0935/2333] blk-mq: Abort suspend when wakeup events are pending [ Upstream commit c196bf43d706592d8801a7513603765080e495fb ] During system suspend, wakeup capable IRQs for block device can be delayed, which can cause blk_mq_hctx_notify_offline() to hang indefinitely while waiting for pending request to complete. Skip the request waiting loop and abort suspend when wakeup events are pending to prevent the deadlock. Fixes: bf0beec0607d ("blk-mq: drain I/O when all CPUs in a hctx are offline") Signed-off-by: Cong Zhang Signed-off-by: Jens Axboe Signed-off-by: Sasha Levin --- block/blk-mq.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/block/blk-mq.c b/block/blk-mq.c index d626d32f6e576..33a0062f9e56d 100644 --- a/block/blk-mq.c +++ b/block/blk-mq.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -3707,6 +3708,7 @@ static int blk_mq_hctx_notify_offline(unsigned int cpu, struct hlist_node *node) { struct blk_mq_hw_ctx *hctx = hlist_entry_safe(node, struct blk_mq_hw_ctx, cpuhp_online); + int ret = 0; if (blk_mq_hctx_has_online_cpu(hctx, cpu)) return 0; @@ -3727,12 +3729,24 @@ static int blk_mq_hctx_notify_offline(unsigned int cpu, struct hlist_node *node) * frozen and there are no requests. */ if (percpu_ref_tryget(&hctx->queue->q_usage_counter)) { - while (blk_mq_hctx_has_requests(hctx)) + while (blk_mq_hctx_has_requests(hctx)) { + /* + * The wakeup capable IRQ handler of block device is + * not called during suspend. Skip the loop by checking + * pm_wakeup_pending to prevent the deadlock and improve + * suspend latency. + */ + if (pm_wakeup_pending()) { + clear_bit(BLK_MQ_S_INACTIVE, &hctx->state); + ret = -EBUSY; + break; + } msleep(5); + } percpu_ref_put(&hctx->queue->q_usage_counter); } - return 0; + return ret; } /* From 0accacccba1943a32986b95225607f1994b0d26d Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 4 Dec 2025 10:45:45 +0100 Subject: [PATCH 0936/2333] drm/panel: novatek-nt35560: avoid on-stack device structure [ Upstream commit 1a7a7b80a22448dff55e1ad69a4681fd8b760b85 ] A cleanup patch apparently by accident used a local device structure instead of a pointer to one in the nt35560_read_id() function, causing a warning about stack usage: drivers/gpu/drm/panel/panel-novatek-nt35560.c: In function 'nt35560_read_id': drivers/gpu/drm/panel/panel-novatek-nt35560.c:249:1: error: the frame size of 1296 bytes is larger than 1280 bytes [-Werror=frame-larger-than=] Change this to a pointer as was liley intended here. Fixes: 5fbc0dbb92d6 ("drm/panel: novatek-nt35560: Clean up driver") Signed-off-by: Arnd Bergmann Reviewed-by: Douglas Anderson Signed-off-by: Douglas Anderson Link: https://patch.msgid.link/20251204094550.1030506-1-arnd@kernel.org Signed-off-by: Sasha Levin --- drivers/gpu/drm/panel/panel-novatek-nt35560.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/panel/panel-novatek-nt35560.c b/drivers/gpu/drm/panel/panel-novatek-nt35560.c index 561e6643dcbb6..6e5173f98a226 100644 --- a/drivers/gpu/drm/panel/panel-novatek-nt35560.c +++ b/drivers/gpu/drm/panel/panel-novatek-nt35560.c @@ -213,7 +213,7 @@ static const struct backlight_properties nt35560_bl_props = { static void nt35560_read_id(struct mipi_dsi_multi_context *dsi_ctx) { - struct device dev = dsi_ctx->dsi->dev; + struct device *dev = &dsi_ctx->dsi->dev; u8 vendor, version, panel; u16 val; @@ -225,7 +225,7 @@ static void nt35560_read_id(struct mipi_dsi_multi_context *dsi_ctx) return; if (vendor == 0x00) { - dev_err(&dev, "device vendor ID is zero\n"); + dev_err(dev, "device vendor ID is zero\n"); dsi_ctx->accum_err = -ENODEV; return; } @@ -236,12 +236,12 @@ static void nt35560_read_id(struct mipi_dsi_multi_context *dsi_ctx) case DISPLAY_SONY_ACX424AKP_ID2: case DISPLAY_SONY_ACX424AKP_ID3: case DISPLAY_SONY_ACX424AKP_ID4: - dev_info(&dev, + dev_info(dev, "MTP vendor: %02x, version: %02x, panel: %02x\n", vendor, version, panel); break; default: - dev_info(&dev, + dev_info(dev, "unknown vendor: %02x, version: %02x, panel: %02x\n", vendor, version, panel); break; From 2864db01b3e54ae441b15bfb65f342e69e51140b Mon Sep 17 00:00:00 2001 From: shechenglong Date: Wed, 3 Dec 2025 23:17:49 +0800 Subject: [PATCH 0937/2333] block: fix comment for op_is_zone_mgmt() to include RESET_ALL [ Upstream commit 8a32282175c964eb15638e8dfe199fc13c060f67 ] REQ_OP_ZONE_RESET_ALL is a zone management request, and op_is_zone_mgmt() has returned true for it. Update the comment to remove the misleading exception note so the documentation matches the implementation. Fixes: 12a1c9353c47 ("block: fix op_is_zone_mgmt() to handle REQ_OP_ZONE_RESET_ALL") Signed-off-by: shechenglong Reviewed-by: Damien Le Moal Reviewed-by: Johannes Thumshirn Signed-off-by: Jens Axboe Signed-off-by: Sasha Levin --- include/linux/blk_types.h | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h index 44c30183ecc34..4e2e3aed32f5f 100644 --- a/include/linux/blk_types.h +++ b/include/linux/blk_types.h @@ -469,10 +469,7 @@ static inline bool op_is_discard(blk_opf_t op) } /* - * Check if a bio or request operation is a zone management operation, with - * the exception of REQ_OP_ZONE_RESET_ALL which is treated as a special case - * due to its different handling in the block layer and device response in - * case of command failure. + * Check if a bio or request operation is a zone management operation. */ static inline bool op_is_zone_mgmt(enum req_op op) { From 7193407bc4457212fa38ec3aff9c640e63a8dbef Mon Sep 17 00:00:00 2001 From: Shaurya Rane Date: Thu, 4 Dec 2025 23:42:59 +0530 Subject: [PATCH 0938/2333] block: fix memory leak in __blkdev_issue_zero_pages [ Upstream commit f7e3f852a42d7cd8f1af2c330d9d153e30c8adcf ] Move the fatal signal check before bio_alloc() to prevent a memory leak when BLKDEV_ZERO_KILLABLE is set and a fatal signal is pending. Previously, the bio was allocated before checking for a fatal signal. If a signal was pending, the code would break out of the loop without freeing or chaining the just-allocated bio, causing a memory leak. This matches the pattern already used in __blkdev_issue_write_zeroes() where the signal check precedes the allocation. Fixes: bf86bcdb4012 ("blk-lib: check for kill signal in ioctl BLKZEROOUT") Reported-by: syzbot+527a7e48a3d3d315d862@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=527a7e48a3d3d315d862 Signed-off-by: Shaurya Rane Reviewed-by: Keith Busch Tested-by: syzbot+527a7e48a3d3d315d862@syzkaller.appspotmail.com Signed-off-by: Jens Axboe Signed-off-by: Sasha Levin --- block/blk-lib.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/block/blk-lib.c b/block/blk-lib.c index 3030a772d3aa0..352e3c0f8a7d7 100644 --- a/block/blk-lib.c +++ b/block/blk-lib.c @@ -202,13 +202,13 @@ static void __blkdev_issue_zero_pages(struct block_device *bdev, unsigned int nr_vecs = __blkdev_sectors_to_bio_pages(nr_sects); struct bio *bio; - bio = bio_alloc(bdev, nr_vecs, REQ_OP_WRITE, gfp_mask); - bio->bi_iter.bi_sector = sector; - if ((flags & BLKDEV_ZERO_KILLABLE) && fatal_signal_pending(current)) break; + bio = bio_alloc(bdev, nr_vecs, REQ_OP_WRITE, gfp_mask); + bio->bi_iter.bi_sector = sector; + do { unsigned int len; From 6a960b58df612dec4ca8a85c53019b2bfb70f061 Mon Sep 17 00:00:00 2001 From: Israel Rukshin Date: Sun, 23 Nov 2025 16:46:48 +0200 Subject: [PATCH 0939/2333] nvme-auth: use kvfree() for memory allocated with kvcalloc() [ Upstream commit bb9f4cca7c031de6f0e85f7ba24abf0172829f85 ] Memory allocated by kvcalloc() may come from vmalloc or kmalloc, so use kvfree() instead of kfree() for proper deallocation. Fixes: aa36d711e945 ("nvme-auth: convert dhchap_auth_list to an array") Signed-off-by: Israel Rukshin Reviewed-by: Max Gurtovoy Reviewed-by: Christoph Hellwig Signed-off-by: Keith Busch Signed-off-by: Sasha Levin --- drivers/nvme/host/auth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/nvme/host/auth.c b/drivers/nvme/host/auth.c index a01178caf15bb..8f3ccb317e4de 100644 --- a/drivers/nvme/host/auth.c +++ b/drivers/nvme/host/auth.c @@ -1122,7 +1122,7 @@ void nvme_auth_free(struct nvme_ctrl *ctrl) if (ctrl->dhchap_ctxs) { for (i = 0; i < ctrl_max_dhchaps(ctrl); i++) nvme_auth_free_dhchap(&ctrl->dhchap_ctxs[i]); - kfree(ctrl->dhchap_ctxs); + kvfree(ctrl->dhchap_ctxs); } if (ctrl->host_key) { nvme_auth_free_key(ctrl->host_key); From 0e777da54152fabd626828356f37505344c0ebb2 Mon Sep 17 00:00:00 2001 From: Caleb Sander Mateos Date: Thu, 4 Dec 2025 15:43:31 -0700 Subject: [PATCH 0940/2333] io_uring/kbuf: use READ_ONCE() for userspace-mapped memory [ Upstream commit 78385c7299f7514697d196b3233a91bd5e485591 ] The struct io_uring_buf elements in a buffer ring are in a memory region accessible from userspace. A malicious/buggy userspace program could therefore write to them at any time, so they should be accessed with READ_ONCE() in the kernel. Commit 98b6fa62c84f ("io_uring/kbuf: always use READ_ONCE() to read ring provided buffer lengths") already switched the reads of the len field to READ_ONCE(). Do the same for bid and addr. Signed-off-by: Caleb Sander Mateos Fixes: c7fb19428d67 ("io_uring: add support for ring mapped supplied buffers") Cc: Joanne Koong Signed-off-by: Jens Axboe Signed-off-by: Sasha Levin --- io_uring/kbuf.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/io_uring/kbuf.c b/io_uring/kbuf.c index a727e020fe036..d974381d93ff7 100644 --- a/io_uring/kbuf.c +++ b/io_uring/kbuf.c @@ -44,7 +44,7 @@ static bool io_kbuf_inc_commit(struct io_buffer_list *bl, int len) buf_len -= this_len; /* Stop looping for invalid buffer length of 0 */ if (buf_len || !this_len) { - buf->addr += this_len; + buf->addr = READ_ONCE(buf->addr) + this_len; buf->len = buf_len; return false; } @@ -198,9 +198,9 @@ static struct io_br_sel io_ring_buffer_select(struct io_kiocb *req, size_t *len, if (*len == 0 || *len > buf_len) *len = buf_len; req->flags |= REQ_F_BUFFER_RING | REQ_F_BUFFERS_COMMIT; - req->buf_index = buf->bid; + req->buf_index = READ_ONCE(buf->bid); sel.buf_list = bl; - sel.addr = u64_to_user_ptr(buf->addr); + sel.addr = u64_to_user_ptr(READ_ONCE(buf->addr)); if (io_should_commit(req, issue_flags)) { io_kbuf_commit(req, sel.buf_list, *len, 1); @@ -280,7 +280,7 @@ static int io_ring_buffers_peek(struct io_kiocb *req, struct buf_sel_arg *arg, if (!arg->max_len) arg->max_len = INT_MAX; - req->buf_index = buf->bid; + req->buf_index = READ_ONCE(buf->bid); do { u32 len = READ_ONCE(buf->len); @@ -295,7 +295,7 @@ static int io_ring_buffers_peek(struct io_kiocb *req, struct buf_sel_arg *arg, } } - iov->iov_base = u64_to_user_ptr(buf->addr); + iov->iov_base = u64_to_user_ptr(READ_ONCE(buf->addr)); iov->iov_len = len; iov++; From bc6761c022558aa3f3eea012a28dd9624abfffac Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 3 Dec 2025 20:35:23 +0300 Subject: [PATCH 0941/2333] drm/plane: Fix IS_ERR() vs NULL check in drm_plane_create_hotspot_properties() [ Upstream commit 479acb9db3199cdb70e5478a6f633b5f20c7d8df ] The drm_property_create_signed_range() function doesn't return error pointers it returns NULL on error. Fix the error checking to match. Fixes: 8f7179a1027d ("drm/atomic: Add support for mouse hotspots") Signed-off-by: Dan Carpenter Reviewed-by: Javier Martinez Canillas Reviewed-by: Zack Rusin Link: https://patch.msgid.link/aTB023cfcIPkCsFS@stanley.mountain Signed-off-by: Maxime Ripard Signed-off-by: Sasha Levin --- drivers/gpu/drm/drm_plane.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c index a30493ed97157..4cadea997129d 100644 --- a/drivers/gpu/drm/drm_plane.c +++ b/drivers/gpu/drm/drm_plane.c @@ -338,14 +338,14 @@ static int drm_plane_create_hotspot_properties(struct drm_plane *plane) prop_x = drm_property_create_signed_range(plane->dev, 0, "HOTSPOT_X", INT_MIN, INT_MAX); - if (IS_ERR(prop_x)) - return PTR_ERR(prop_x); + if (!prop_x) + return -ENOMEM; prop_y = drm_property_create_signed_range(plane->dev, 0, "HOTSPOT_Y", INT_MIN, INT_MAX); - if (IS_ERR(prop_y)) { + if (!prop_y) { drm_property_destroy(plane->dev, prop_x); - return PTR_ERR(prop_y); + return -ENOMEM; } drm_object_attach_property(&plane->base, prop_x, 0); From 8fee481ee6c0d1e3ca64d0cabaa2653533d34a23 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 4 Dec 2025 19:39:34 +0000 Subject: [PATCH 0942/2333] regulator: fixed: Rely on the core freeing the enable GPIO [ Upstream commit 79a45ddcdbba330f5139c7c7ff7042d69cf147b2 ] In order to simplify ownership rules for enable GPIOs supplied by drivers regulator_register() always takes ownership of them, even if it ends up failing for some other reason. We therefore should not free the GPIO if registration fails but just let the core worry about things. Fixes: 636f4618b1cd (regulator: fixed: fix GPIO descriptor leak on register failure) Reported-by: Diederik de Haas Closes: https://lore.kernel.org/r/DEPEYUF5BRGY.UKFBWRRE8HNP@cknow-tech.com Tested-by: Diederik de Haas Signed-off-by: Mark Brown Link: https://patch.msgid.link/20251204-regulator-fixed-fix-gpiod-leak-v1-1-48efea5b82c2@kernel.org Signed-off-by: Mark Brown Signed-off-by: Sasha Levin --- drivers/regulator/fixed.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/drivers/regulator/fixed.c b/drivers/regulator/fixed.c index a2d16e9abfb58..254c0a8a45559 100644 --- a/drivers/regulator/fixed.c +++ b/drivers/regulator/fixed.c @@ -330,13 +330,10 @@ static int reg_fixed_voltage_probe(struct platform_device *pdev) drvdata->dev = devm_regulator_register(&pdev->dev, &drvdata->desc, &cfg); - if (IS_ERR(drvdata->dev)) { - ret = dev_err_probe(&pdev->dev, PTR_ERR(drvdata->dev), - "Failed to register regulator: %ld\n", - PTR_ERR(drvdata->dev)); - gpiod_put(cfg.ena_gpiod); - return ret; - } + if (IS_ERR(drvdata->dev)) + return dev_err_probe(&pdev->dev, PTR_ERR(drvdata->dev), + "Failed to register regulator: %ld\n", + PTR_ERR(drvdata->dev)); platform_set_drvdata(pdev, drvdata); From cdda0d06f8650e33255f79839f188bbece44117c Mon Sep 17 00:00:00 2001 From: Junrui Luo Date: Wed, 3 Dec 2025 12:27:03 +0800 Subject: [PATCH 0943/2333] ALSA: firewire-motu: fix buffer overflow in hwdep read for DSP events [ Upstream commit 210d77cca3d0494ed30a5c628b20c1d95fa04fb1 ] The DSP event handling code in hwdep_read() could write more bytes to the user buffer than requested, when a user provides a buffer smaller than the event header size (8 bytes). Fix by using min_t() to clamp the copy size, This ensures we never copy more than the user requested. Reported-by: Yuhao Jiang Reported-by: Junrui Luo Fixes: 634ec0b2906e ("ALSA: firewire-motu: notify event for parameter change in register DSP model") Signed-off-by: Junrui Luo Link: https://patch.msgid.link/SYBPR01MB78810656377E79E58350D951AFD9A@SYBPR01MB7881.ausprd01.prod.outlook.com Signed-off-by: Takashi Iwai Signed-off-by: Sasha Levin --- sound/firewire/motu/motu-hwdep.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sound/firewire/motu/motu-hwdep.c b/sound/firewire/motu/motu-hwdep.c index 981c19430cb0f..6675b23aad69e 100644 --- a/sound/firewire/motu/motu-hwdep.c +++ b/sound/firewire/motu/motu-hwdep.c @@ -83,10 +83,11 @@ static long hwdep_read(struct snd_hwdep *hwdep, char __user *buf, long count, event.motu_register_dsp_change.type = SNDRV_FIREWIRE_EVENT_MOTU_REGISTER_DSP_CHANGE; event.motu_register_dsp_change.count = (consumed - sizeof(event.motu_register_dsp_change)) / 4; - if (copy_to_user(buf, &event, sizeof(event.motu_register_dsp_change))) + if (copy_to_user(buf, &event, + min_t(long, count, sizeof(event.motu_register_dsp_change)))) return -EFAULT; - count = consumed; + count = min_t(long, count, consumed); } else { spin_unlock_irq(&motu->lock); From 731e1beb10c4e43b8dc70462814792049f8aa329 Mon Sep 17 00:00:00 2001 From: Madhur Kumar Date: Thu, 4 Dec 2025 17:38:22 +0530 Subject: [PATCH 0944/2333] drm/nouveau: refactor deprecated strcpy [ Upstream commit 2bdc2c0e12fac56e41ec05fb771ead986ea6dac0 ] strcpy() has been deprecated because it performs no bounds checking on the destination buffer, which can lead to buffer overflows. Use the safer strscpy() instead. Signed-off-by: Madhur Kumar Reviewed-by: Lyude Paul Fixes: 15a996bbb697 ("drm/nouveau: assign fence_chan->name correctly") Signed-off-by: Lyude Paul Link: https://patch.msgid.link/20251204120822.17502-1-madhurkumar004@gmail.com Signed-off-by: Sasha Levin --- drivers/gpu/drm/nouveau/nouveau_fence.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c index 869d4335c0f45..4a193b7d6d9e4 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fence.c +++ b/drivers/gpu/drm/nouveau/nouveau_fence.c @@ -183,11 +183,11 @@ nouveau_fence_context_new(struct nouveau_channel *chan, struct nouveau_fence_cha fctx->context = drm->runl[chan->runlist].context_base + chan->chid; if (chan == drm->cechan) - strcpy(fctx->name, "copy engine channel"); + strscpy(fctx->name, "copy engine channel"); else if (chan == drm->channel) - strcpy(fctx->name, "generic kernel channel"); + strscpy(fctx->name, "generic kernel channel"); else - strcpy(fctx->name, cli->name); + strscpy(fctx->name, cli->name); kref_init(&fctx->fence_ref); if (!priv->uevent) From ec8ccaa4d33e8b05f34de8f5139720e59b0ffc46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Rebe?= Date: Tue, 2 Dec 2025 16:49:52 +0100 Subject: [PATCH 0945/2333] drm/nouveau: fix circular dep oops from vendored i2c encoder MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit d84e47edf156a953ed340ba6a202dcd3ea39ba0a ] Since commit a73583107af9 ("drm/nouveau: vendor in drm_encoder_slave API") nouveau appears to be broken for all dispnv04 GPUs (before NV50). Depending on the kernel version, either having no display output and hanging in kernel for a long time, or even oopsing in the cleanup path like: Hardware name: PowerMac11,2 PPC970MP 0x440101 PowerMac ... nouveau 0000:0a:00.0: drm: 0x14C5: Parsing digital output script table BUG: Unable to handle kernel data access on read at 0x00041520 Faulting instruction address: 0xc0003d0001be0844 Oops: Kernel access of bad area, sig: 11 [#1] BE PAGE_SIZE=4K MMU=Hash SMP NR_CPUS=8 NUMA PowerMac Modules linked in: windfarm_cpufreq_clamp windfarm_smu_sensors windfarm_smu_controls windfarm_pm112 snd_aoa_codec_onyx snd_aoa_fabric_layout snd_aoa windfarm_pid jo apple_mfi_fastcharge rndis_host cdc_ether usbnet mii snd_aoa_i2sbus snd_aoa_soundbus snd_pcm snd_timer snd soundcore rack_meter windfarm_smu_sat windfarm_max6690_s m75_sensor windfarm_core gpu_sched drm_gpuvm drm_exec drm_client_lib drm_ttm_helper ttm drm_display_helper drm_kms_helper drm drm_panel_orientation_quirks syscopyar _sys_fops i2c_algo_bit backlight uio_pdrv_genirq uio uninorth_agp agpgart zram dm_mod dax ipv6 nfsv4 dns_resolver nfs lockd grace sunrpc offb cfbfillrect cfbimgblt ont input_leds sr_mod cdrom sd_mod uas ata_generic hid_apple hid_generic usbhid hid usb_storage pata_macio sata_svw libata firewire_ohci scsi_mod firewire_core ohci ehci_pci ehci_hcd tg3 ohci_hcd libphy usbcore usb_common nls_base led_class CPU: 0 UID: 0 PID: 245 Comm: (udev-worker) Not tainted 6.14.0-09584-g7d06015d936c #7 PREEMPTLAZY Hardware name: PowerMac11,2 PPC970MP 0x440101 PowerMac NIP: c0003d0001be0844 LR: c0003d0001be0830 CTR: 0000000000000000 REGS: c0000000053f70e0 TRAP: 0300 Not tainted (6.14.0-09584-g7d06015d936c) MSR: 9000000000009032 CR: 24222220 XER: 00000000 DAR: 0000000000041520 DSISR: 40000000 IRQMASK: 0 \x0aGPR00: c0003d0001be0830 c0000000053f7380 c0003d0000911900 c000000007bc6800 \x0aGPR04: 0000000000000000 0000000000000000 c000000007bc6e70 0000000000000001 \x0aGPR08: 01f3040000000000 0000000000041520 0000000000000000 c0003d0000813958 \x0aGPR12: c000000000071a48 c000000000e28000 0000000000000020 0000000000000000 \x0aGPR16: 0000000000000000 0000000000f52630 0000000000000000 0000000000000000 \x0aGPR20: 0000000000000000 0000000000000000 0000000000000001 c0003d0000928528 \x0aGPR24: c0003d0000928598 0000000000000000 c000000007025480 c000000007025480 \x0aGPR28: c0000000010b4000 0000000000000000 c000000007bc1800 c000000007bc6800 NIP [c0003d0001be0844] nv_crtc_destroy+0x44/0xd4 [nouveau] LR [c0003d0001be0830] nv_crtc_destroy+0x30/0xd4 [nouveau] Call Trace: [c0000000053f7380] [c0003d0001be0830] nv_crtc_destroy+0x30/0xd4 [nouveau] (unreliable) [c0000000053f73c0] [c0003d00007f7bf4] drm_mode_config_cleanup+0x27c/0x30c [drm] [c0000000053f7490] [c0003d0001bdea50] nouveau_display_create+0x1cc/0x550 [nouveau] [c0000000053f7500] [c0003d0001bcc29c] nouveau_drm_device_init+0x1c8/0x844 [nouveau] [c0000000053f75e0] [c0003d0001bcc9ec] nouveau_drm_probe+0xd4/0x1e0 [nouveau] [c0000000053f7670] [c000000000557d24] local_pci_probe+0x50/0xa8 [c0000000053f76f0] [c000000000557fa8] pci_device_probe+0x22c/0x240 [c0000000053f7760] [c0000000005fff3c] really_probe+0x188/0x31c [c0000000053f77e0] [c000000000600204] __driver_probe_device+0x134/0x13c [c0000000053f7860] [c0000000006002c0] driver_probe_device+0x3c/0xb4 [c0000000053f78a0] [c000000000600534] __driver_attach+0x118/0x128 [c0000000053f78e0] [c0000000005fe038] bus_for_each_dev+0xa8/0xf4 [c0000000053f7950] [c0000000005ff460] driver_attach+0x2c/0x40 [c0000000053f7970] [c0000000005fea68] bus_add_driver+0x130/0x278 [c0000000053f7a00] [c00000000060117c] driver_register+0x9c/0x1a0 [c0000000053f7a80] [c00000000055623c] __pci_register_driver+0x5c/0x70 [c0000000053f7aa0] [c0003d0001c058a0] nouveau_drm_init+0x254/0x278 [nouveau] [c0000000053f7b10] [c00000000000e9bc] do_one_initcall+0x84/0x268 [c0000000053f7bf0] [c0000000001a0ba0] do_init_module+0x70/0x2d8 [c0000000053f7c70] [c0000000001a42bc] init_module_from_file+0xb4/0x108 [c0000000053f7d50] [c0000000001a4504] sys_finit_module+0x1ac/0x478 [c0000000053f7e10] [c000000000023230] system_call_exception+0x1a4/0x20c [c0000000053f7e50] [c00000000000c554] system_call_common+0xf4/0x258 --- interrupt: c00 at 0xfd5f988 NIP: 000000000fd5f988 LR: 000000000ff9b148 CTR: 0000000000000000 REGS: c0000000053f7e80 TRAP: 0c00 Not tainted (6.14.0-09584-g7d06015d936c) MSR: 100000000000d032 CR: 28222244 XER: 00000000 IRQMASK: 0 \x0aGPR00: 0000000000000161 00000000ffcdc2d0 00000000405db160 0000000000000020 \x0aGPR04: 000000000ffa2c9c 0000000000000000 000000000000001f 0000000000000045 \x0aGPR08: 0000000011a13770 0000000000000000 0000000000000000 0000000000000000 \x0aGPR12: 0000000000000000 0000000010249d8c 0000000000000020 0000000000000000 \x0aGPR16: 0000000000000000 0000000000f52630 0000000000000000 0000000000000000 \x0aGPR20: 0000000000000000 0000000000000000 0000000000000000 0000000011a11a70 \x0aGPR24: 0000000011a13580 0000000011a11950 0000000011a11a70 0000000000020000 \x0aGPR28: 000000000ffa2c9c 0000000000000000 000000000ffafc40 0000000011a11a70 NIP [000000000fd5f988] 0xfd5f988 LR [000000000ff9b148] 0xff9b148 --- interrupt: c00 Code: f821ffc1 418200ac e93f0000 e9290038 e9291468 eba90000 48026c0d e8410018 e93f06aa 3d290001 392982a4 79291f24 <7fdd482a> 2c3e0000 41820030 7fc3f378 ---[ end trace 0000000000000000 ]--- This is caused by the i2c encoder modules vendored into nouveau/ now depending on the equally vendored nouveau_i2c_encoder_destroy function. Trying to auto-load this modules hangs on nouveau initialization until timeout, and nouveau continues without i2c video encoders. Fix by avoiding nouveau dependency by __always_inlining that helper functions into those i2c video encoder modules. Fixes: a73583107af9 ("drm/nouveau: vendor in drm_encoder_slave API") Signed-off-by: René Rebe Reviewed-by: Lyude Paul [Lyude: fixed commit reference in description] Signed-off-by: Lyude Paul Link: https://patch.msgid.link/20251202.164952.2216481867721531616.rene@exactco.de Signed-off-by: Sasha Levin --- .../nouveau/dispnv04/nouveau_i2c_encoder.c | 20 ------------------- .../include/dispnv04/i2c/encoder_i2c.h | 19 +++++++++++++++++- 2 files changed, 18 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/nouveau/dispnv04/nouveau_i2c_encoder.c b/drivers/gpu/drm/nouveau/dispnv04/nouveau_i2c_encoder.c index e2bf99c433366..a60209097a20a 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/nouveau_i2c_encoder.c +++ b/drivers/gpu/drm/nouveau/dispnv04/nouveau_i2c_encoder.c @@ -94,26 +94,6 @@ int nouveau_i2c_encoder_init(struct drm_device *dev, return err; } -/** - * nouveau_i2c_encoder_destroy - Unregister the I2C device backing an encoder - * @drm_encoder: Encoder to be unregistered. - * - * This should be called from the @destroy method of an I2C slave - * encoder driver once I2C access is no longer needed. - */ -void nouveau_i2c_encoder_destroy(struct drm_encoder *drm_encoder) -{ - struct nouveau_i2c_encoder *encoder = to_encoder_i2c(drm_encoder); - struct i2c_client *client = nouveau_i2c_encoder_get_client(drm_encoder); - struct module *module = client->dev.driver->owner; - - i2c_unregister_device(client); - encoder->i2c_client = NULL; - - module_put(module); -} -EXPORT_SYMBOL(nouveau_i2c_encoder_destroy); - /* * Wrapper fxns which can be plugged in to drm_encoder_helper_funcs: */ diff --git a/drivers/gpu/drm/nouveau/include/dispnv04/i2c/encoder_i2c.h b/drivers/gpu/drm/nouveau/include/dispnv04/i2c/encoder_i2c.h index 31334aa90781b..869820701a56e 100644 --- a/drivers/gpu/drm/nouveau/include/dispnv04/i2c/encoder_i2c.h +++ b/drivers/gpu/drm/nouveau/include/dispnv04/i2c/encoder_i2c.h @@ -202,7 +202,24 @@ static inline struct i2c_client *nouveau_i2c_encoder_get_client(struct drm_encod return to_encoder_i2c(encoder)->i2c_client; } -void nouveau_i2c_encoder_destroy(struct drm_encoder *encoder); +/** + * nouveau_i2c_encoder_destroy - Unregister the I2C device backing an encoder + * @drm_encoder: Encoder to be unregistered. + * + * This should be called from the @destroy method of an I2C slave + * encoder driver once I2C access is no longer needed. + */ +static __always_inline void nouveau_i2c_encoder_destroy(struct drm_encoder *drm_encoder) +{ + struct nouveau_i2c_encoder *encoder = to_encoder_i2c(drm_encoder); + struct i2c_client *client = nouveau_i2c_encoder_get_client(drm_encoder); + struct module *module = client->dev.driver->owner; + + i2c_unregister_device(client); + encoder->i2c_client = NULL; + + module_put(module); +} /* * Wrapper fxns which can be plugged in to drm_encoder_helper_funcs: From c61af12157ef9fe480ab84b4923e8ca3d8f86a62 Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 2 Dec 2025 16:24:53 +0000 Subject: [PATCH 0946/2333] cifs: Fix handling of a beyond-EOF DIO/unbuffered read over SMB1 [ Upstream commit 9d85ac939d52e93d80efb01a299c6f0bedb30487 ] If a DIO read or an unbuffered read request extends beyond the EOF, the server will return a short read and a status code indicating that EOF was hit, which gets translated to -ENODATA. Note that the client does not cap the request at i_size, but asks for the amount requested in case there's a race on the server with a third party. Now, on the client side, the request will get split into multiple subrequests if rsize is smaller than the full request size. A subrequest that starts before or at the EOF and returns short data up to the EOF will be correctly handled, with the NETFS_SREQ_HIT_EOF flag being set, indicating to netfslib that we can't read more. If a subrequest, however, starts after the EOF and not at it, HIT_EOF will not be flagged, its error will be set to -ENODATA and it will be abandoned. This will cause the request as a whole to fail with -ENODATA. Fix this by setting NETFS_SREQ_HIT_EOF on any subrequest that lies beyond the EOF marker. This can be reproduced by mounting with "cache=none,sign,vers=1.0" and doing a read of a file that's significantly bigger than the size of the file (e.g. attempting to read 64KiB from a 16KiB file). Fixes: a68c74865f51 ("cifs: Fix SMB1 readv/writev callback in the same way as SMB2/3") Signed-off-by: David Howells Reviewed-by: Paulo Alcantara (Red Hat) cc: Shyam Prasad N cc: linux-cifs@vger.kernel.org cc: netfs@lists.linux.dev cc: linux-fsdevel@vger.kernel.org Signed-off-by: Steve French Signed-off-by: Sasha Levin --- fs/smb/client/cifssmb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/smb/client/cifssmb.c b/fs/smb/client/cifssmb.c index dcc50a2bfa4b2..bfc9b1ea76fac 100644 --- a/fs/smb/client/cifssmb.c +++ b/fs/smb/client/cifssmb.c @@ -1374,7 +1374,7 @@ cifs_readv_callback(struct mid_q_entry *mid) } else { size_t trans = rdata->subreq.transferred + rdata->got_bytes; if (trans < rdata->subreq.len && - rdata->subreq.start + trans == ictx->remote_i_size) { + rdata->subreq.start + trans >= ictx->remote_i_size) { rdata->result = 0; __set_bit(NETFS_SREQ_HIT_EOF, &rdata->subreq.flags); } else if (rdata->got_bytes > 0) { From 5dfdc0ba05441f17947682b11bfceeca45d451d6 Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 3 Dec 2025 21:55:27 +0000 Subject: [PATCH 0947/2333] cifs: Fix handling of a beyond-EOF DIO/unbuffered read over SMB2 [ Upstream commit 4ae4dde6f34a4124c65468ae4fa1f915fb40f900 ] If a DIO read or an unbuffered read request extends beyond the EOF, the server will return a short read and a status code indicating that EOF was hit, which gets translated to -ENODATA. Note that the client does not cap the request at i_size, but asks for the amount requested in case there's a race on the server with a third party. Now, on the client side, the request will get split into multiple subrequests if rsize is smaller than the full request size. A subrequest that starts before or at the EOF and returns short data up to the EOF will be correctly handled, with the NETFS_SREQ_HIT_EOF flag being set, indicating to netfslib that we can't read more. If a subrequest, however, starts after the EOF and not at it, HIT_EOF will not be flagged, its error will be set to -ENODATA and it will be abandoned. This will cause the request as a whole to fail with -ENODATA. Fix this by setting NETFS_SREQ_HIT_EOF on any subrequest that lies beyond the EOF marker. Fixes: 1da29f2c39b6 ("netfs, cifs: Fix handling of short DIO read") Signed-off-by: David Howells Reviewed-by: Paulo Alcantara (Red Hat) cc: Shyam Prasad N cc: linux-cifs@vger.kernel.org cc: netfs@lists.linux.dev cc: linux-fsdevel@vger.kernel.org Signed-off-by: Steve French Signed-off-by: Sasha Levin --- fs/smb/client/smb2pdu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c index 8b4a4573e9c37..e661d40213eab 100644 --- a/fs/smb/client/smb2pdu.c +++ b/fs/smb/client/smb2pdu.c @@ -4629,7 +4629,7 @@ smb2_readv_callback(struct mid_q_entry *mid) } else { size_t trans = rdata->subreq.transferred + rdata->got_bytes; if (trans < rdata->subreq.len && - rdata->subreq.start + trans == ictx->remote_i_size) { + rdata->subreq.start + trans >= ictx->remote_i_size) { __set_bit(NETFS_SREQ_HIT_EOF, &rdata->subreq.flags); rdata->result = 0; } From 1959d1265e24131265a7976648d0431c658ff4a5 Mon Sep 17 00:00:00 2001 From: Mike Snitzer Date: Wed, 26 Nov 2025 01:01:26 -0500 Subject: [PATCH 0948/2333] nfs/localio: remove alignment size checking in nfs_is_local_dio_possible [ Upstream commit f50d0328d02fe38ba196a73c143e5d87e341d4f7 ] This check to ensure dio_offset_align isn't larger than PAGE_SIZE is no longer relevant (older iterations of NFS Direct was allocating misaligned head and tail pages but no longer does, so this check isn't needed). Fixes: c817248fc831 ("nfs/localio: add proper O_DIRECT support for READ and WRITE") Signed-off-by: Mike Snitzer Signed-off-by: Trond Myklebust Signed-off-by: Sasha Levin --- fs/nfs/localio.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/fs/nfs/localio.c b/fs/nfs/localio.c index 656976b4f42ce..512d9c5ff608a 100644 --- a/fs/nfs/localio.c +++ b/fs/nfs/localio.c @@ -339,8 +339,6 @@ nfs_is_local_dio_possible(struct nfs_local_kiocb *iocb, int rw, if (unlikely(!nf_dio_mem_align || !nf_dio_offset_align)) return false; - if (unlikely(nf_dio_offset_align > PAGE_SIZE)) - return false; if (unlikely(len < nf_dio_offset_align)) return false; From 829adc469a18a1893c93b23f2155efbee363a0df Mon Sep 17 00:00:00 2001 From: Mike Snitzer Date: Wed, 26 Nov 2025 01:01:27 -0500 Subject: [PATCH 0949/2333] nfs/localio: remove 61 byte hole from needless ____cacheline_aligned [ Upstream commit 0b873de2c02f9cc655bef6bee0eb9e404126ed6c ] struct nfs_local_kiocb used ____cacheline_aligned on its iters[] array and as the structure evolved it caused a 61 byte hole to form. Fix this by removing ____cacheline_aligned and reordering iters[] before iter_is_dio_aligned[]. Fixes: 6a218b9c3183 ("nfs/localio: do not issue misaligned DIO out-of-order") Signed-off-by: Mike Snitzer Signed-off-by: Trond Myklebust Signed-off-by: Sasha Levin --- fs/nfs/localio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/nfs/localio.c b/fs/nfs/localio.c index 512d9c5ff608a..b98bb292fef0c 100644 --- a/fs/nfs/localio.c +++ b/fs/nfs/localio.c @@ -43,8 +43,8 @@ struct nfs_local_kiocb { size_t end_len; short int end_iter_index; atomic_t n_iters; + struct iov_iter iters[NFSLOCAL_MAX_IOS]; bool iter_is_dio_aligned[NFSLOCAL_MAX_IOS]; - struct iov_iter iters[NFSLOCAL_MAX_IOS] ____cacheline_aligned; /* End mostly DIO-specific members */ }; From f81f7e1344c43945c75129d740f434110b4f1f1e Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 5 Dec 2025 10:54:09 +0100 Subject: [PATCH 0950/2333] gpio: tb10x: fix OF_GPIO dependency [ Upstream commit dd44d4d0c55a4ecf5eabf7856f96ed47e0684780 ] Selecting OF_GPIO is generally not allowed, it always gets enabled when both GPIOLIB and OF are turned on. The tb10x driver now warns about this after it was enabled for compile-testing: WARNING: unmet direct dependencies detected for OF_GPIO Depends on [n]: GPIOLIB [=y] && OF [=n] && HAS_IOMEM [=y] Selected by [y]: - GPIO_TB10X [=y] && GPIOLIB [=y] && HAS_IOMEM [=y] && (ARC_PLAT_TB10X || COMPILE_TEST [=y]) OF_GPIO is not required for compile-testing and is already enabled when the driver is usable, so just drop the 'select' line. Fixes: 682fbb18e14c ("gpio: tb10x: allow building the module with COMPILE_TEST=y") Signed-off-by: Arnd Bergmann Link: https://lore.kernel.org/r/20251205095429.1291866-1-arnd@kernel.org Signed-off-by: Bartosz Golaszewski Signed-off-by: Sasha Levin --- drivers/gpio/Kconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 7ee3afbc2b05d..e053524c5e35f 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -738,7 +738,6 @@ config GPIO_TB10X depends on ARC_PLAT_TB10X || COMPILE_TEST select GPIO_GENERIC select GENERIC_IRQ_CHIP - select OF_GPIO config GPIO_TEGRA tristate "NVIDIA Tegra GPIO support" From 581a9f4c1cd859c968159d6e3a4e2c93b0faadef Mon Sep 17 00:00:00 2001 From: Kathara Sasikumar Date: Fri, 5 Dec 2025 21:58:35 +0000 Subject: [PATCH 0951/2333] docs: hwmon: fix link to g762 devicetree binding [ Upstream commit 08bfcf4ff9d39228150a757803fc02dffce84ab0 ] The devicetree binding for g762 was converted to YAML to match vendor prefix conventions. Update the reference accordingly. Signed-off-by: Kathara Sasikumar Link: https://lore.kernel.org/r/20251205215835.783273-1-katharasasikumar007@gmail.com Fixes: 3d8e25372417 ("dt-bindings: hwmon: g762: Convert to yaml schema") Signed-off-by: Guenter Roeck Signed-off-by: Sasha Levin --- Documentation/hwmon/g762.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/hwmon/g762.rst b/Documentation/hwmon/g762.rst index 0371b3365c48c..f224552a2d3cc 100644 --- a/Documentation/hwmon/g762.rst +++ b/Documentation/hwmon/g762.rst @@ -17,7 +17,7 @@ done via a userland daemon like fancontrol. Note that those entries do not provide ways to setup the specific hardware characteristics of the system (reference clock, pulses per fan revolution, ...); Those can be modified via devicetree bindings -documented in Documentation/devicetree/bindings/hwmon/g762.txt or +documented in Documentation/devicetree/bindings/hwmon/gmt,g762.yaml or using a specific platform_data structure in board initialization file (see include/linux/platform_data/g762.h). From bfef208916d724bb39554cba99679ef3ebcb1ac5 Mon Sep 17 00:00:00 2001 From: Troy Mitchell Date: Thu, 13 Nov 2025 21:21:50 +0800 Subject: [PATCH 0952/2333] i2c: spacemit: fix detect issue MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 25faa5364638b86ec0d0edb4486daa9d40a0be8f ] This commit addresses two issues causing i2c detect to fail. The identified issues are: 1. Incorrect error handling for BED (Bus Error No ACK/NAK): Before this commit, Both ALD (Arbitration Loss Detected) and BED returned -EAGAIN. 2. Missing interrupt status clear after initialization in xfer(): On the K1 SoC, simply fixing the first issue changed the error from -EAGAIN to -ETIMEOUT. Through tracing, it was determined that this is likely due to MSD (Master Stop Detected) latency issues. That means the MSD bit in the ISR may still be set on the next transfer. As a result, the controller won't work — we can see from the scope that it doesn't issue any signal. (This only occurs during rapid consecutive I2C transfers. That explains why the issue only shows up with i2cdetect.) With these two fixes, i2c device detection now functions correctly on the K1 SoC. Fixes: 5ea558473fa31 ("i2c: spacemit: add support for SpacemiT K1 SoC") Tested-by: Aurelien Jarno Signed-off-by: Troy Mitchell Reviewed-by: Aurelien Jarno Tested-by: Michael Opdenacker Signed-off-by: Andi Shyti Link: https://lore.kernel.org/r/20251113-fix-k1-detect-failure-v2-1-b02a9a74f65a@linux.spacemit.com Signed-off-by: Sasha Levin --- drivers/i2c/busses/i2c-k1.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/drivers/i2c/busses/i2c-k1.c b/drivers/i2c/busses/i2c-k1.c index 6b918770e612e..d42c03ef5db59 100644 --- a/drivers/i2c/busses/i2c-k1.c +++ b/drivers/i2c/busses/i2c-k1.c @@ -158,11 +158,16 @@ static int spacemit_i2c_handle_err(struct spacemit_i2c_dev *i2c) { dev_dbg(i2c->dev, "i2c error status: 0x%08x\n", i2c->status); - if (i2c->status & (SPACEMIT_SR_BED | SPACEMIT_SR_ALD)) { + /* Arbitration Loss Detected */ + if (i2c->status & SPACEMIT_SR_ALD) { spacemit_i2c_reset(i2c); return -EAGAIN; } + /* Bus Error No ACK/NAK */ + if (i2c->status & SPACEMIT_SR_BED) + spacemit_i2c_reset(i2c); + return i2c->status & SPACEMIT_SR_ACKNAK ? -ENXIO : -EIO; } @@ -224,6 +229,12 @@ static void spacemit_i2c_check_bus_release(struct spacemit_i2c_dev *i2c) } } +static inline void +spacemit_i2c_clear_int_status(struct spacemit_i2c_dev *i2c, u32 mask) +{ + writel(mask & SPACEMIT_I2C_INT_STATUS_MASK, i2c->base + SPACEMIT_ISR); +} + static void spacemit_i2c_init(struct spacemit_i2c_dev *i2c) { u32 val; @@ -267,12 +278,8 @@ static void spacemit_i2c_init(struct spacemit_i2c_dev *i2c) val = readl(i2c->base + SPACEMIT_IRCR); val |= SPACEMIT_RCR_SDA_GLITCH_NOFIX; writel(val, i2c->base + SPACEMIT_IRCR); -} -static inline void -spacemit_i2c_clear_int_status(struct spacemit_i2c_dev *i2c, u32 mask) -{ - writel(mask & SPACEMIT_I2C_INT_STATUS_MASK, i2c->base + SPACEMIT_ISR); + spacemit_i2c_clear_int_status(i2c, SPACEMIT_I2C_INT_STATUS_MASK); } static void spacemit_i2c_start(struct spacemit_i2c_dev *i2c) From d8fae0475d95858833efe7d7e59bebe6da972032 Mon Sep 17 00:00:00 2001 From: Dave Kleikamp Date: Tue, 2 Dec 2025 09:28:10 -0600 Subject: [PATCH 0953/2333] dma/pool: eliminate alloc_pages warning in atomic_pool_expand [ Upstream commit 463d439becb81383f3a5a5d840800131f265a09c ] atomic_pool_expand iteratively tries the allocation while decrementing the page order. There is no need to issue a warning if an attempted allocation fails. Signed-off-by: Dave Kleikamp Reviewed-by: Robin Murphy Fixes: d7e673ec2c8e ("dma-pool: Only allocate from CMA when in same memory zone") [mszyprow: fixed typo] Signed-off-by: Marek Szyprowski Link: https://lore.kernel.org/r/20251202152810.142370-1-dave.kleikamp@oracle.com Signed-off-by: Sasha Levin --- kernel/dma/pool.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/dma/pool.c b/kernel/dma/pool.c index ee45dee33d491..26392badc36b0 100644 --- a/kernel/dma/pool.c +++ b/kernel/dma/pool.c @@ -93,7 +93,7 @@ static int atomic_pool_expand(struct gen_pool *pool, size_t pool_size, page = dma_alloc_from_contiguous(NULL, 1 << order, order, false); if (!page) - page = alloc_pages(gfp, order); + page = alloc_pages(gfp | __GFP_NOWARN, order); } while (!page && order-- > 0); if (!page) goto out; From 4058530b4294273ac298f955ea83c60b49927a55 Mon Sep 17 00:00:00 2001 From: Andres J Rosa Date: Wed, 3 Dec 2025 10:25:01 -0600 Subject: [PATCH 0954/2333] ALSA: uapi: Fix typo in asound.h comment [ Upstream commit 9a97857db0c5655b8932f86b5d18bb959079b0ee ] Fix 'level-shit' to 'level-shift' in struct snd_cea_861_aud_if comment. Fixes: 7ba1c40b536e ("ALSA: Add definitions for CEA-861 Audio InfoFrames") Signed-off-by: Andres J Rosa Link: https://patch.msgid.link/20251203162509.1822-1-andyrosa@gmail.com Signed-off-by: Takashi Iwai Signed-off-by: Sasha Levin --- include/uapi/sound/asound.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/uapi/sound/asound.h b/include/uapi/sound/asound.h index 5a049eeaeccea..d3ce75ba938a8 100644 --- a/include/uapi/sound/asound.h +++ b/include/uapi/sound/asound.h @@ -60,7 +60,7 @@ struct snd_cea_861_aud_if { unsigned char db2_sf_ss; /* sample frequency and size */ unsigned char db3; /* not used, all zeros */ unsigned char db4_ca; /* channel allocation code */ - unsigned char db5_dminh_lsv; /* downmix inhibit & level-shit values */ + unsigned char db5_dminh_lsv; /* downmix inhibit & level-shift values */ }; /**************************************************************************** From 0c1239fb5c425d281264d3b6afa7335f47681ac8 Mon Sep 17 00:00:00 2001 From: Xiaogang Chen Date: Mon, 1 Dec 2025 14:12:29 -0600 Subject: [PATCH 0955/2333] drm/amdkfd: Use huge page size to check split svm range alignment [ Upstream commit bf2084a7b1d75d093b6a79df4c10142d49fbaa0e ] When split svm ranges that have been mapped using huge page should use huge page size(2MB) to check split range alignment, not prange->granularity that means migration granularity. Fixes: 7ef6b2d4b7e5 ("drm/amdkfd: remap unaligned svm ranges that have split") Signed-off-by: Xiaogang Chen Reviewed-by: Philip Yang Signed-off-by: Alex Deucher (cherry picked from commit 448ee45353ef9fb1a34f5f26eb3f48923c6f0898) Signed-off-by: Sasha Levin --- drivers/gpu/drm/amd/amdkfd/kfd_svm.c | 46 +++++++++++++++++++--------- 1 file changed, 32 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c index 74a1d3e1d52be..49dd0a81114e4 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c @@ -1144,30 +1144,48 @@ static int svm_range_split_tail(struct svm_range *prange, uint64_t new_last, struct list_head *insert_list, struct list_head *remap_list) { + unsigned long last_align_down = ALIGN_DOWN(prange->last, 512); + unsigned long start_align = ALIGN(prange->start, 512); + bool huge_page_mapping = last_align_down > start_align; struct svm_range *tail = NULL; - int r = svm_range_split(prange, prange->start, new_last, &tail); + int r; - if (!r) { - list_add(&tail->list, insert_list); - if (!IS_ALIGNED(new_last + 1, 1UL << prange->granularity)) - list_add(&tail->update_list, remap_list); - } - return r; + r = svm_range_split(prange, prange->start, new_last, &tail); + + if (r) + return r; + + list_add(&tail->list, insert_list); + + if (huge_page_mapping && tail->start > start_align && + tail->start < last_align_down && (!IS_ALIGNED(tail->start, 512))) + list_add(&tail->update_list, remap_list); + + return 0; } static int svm_range_split_head(struct svm_range *prange, uint64_t new_start, struct list_head *insert_list, struct list_head *remap_list) { + unsigned long last_align_down = ALIGN_DOWN(prange->last, 512); + unsigned long start_align = ALIGN(prange->start, 512); + bool huge_page_mapping = last_align_down > start_align; struct svm_range *head = NULL; - int r = svm_range_split(prange, new_start, prange->last, &head); + int r; - if (!r) { - list_add(&head->list, insert_list); - if (!IS_ALIGNED(new_start, 1UL << prange->granularity)) - list_add(&head->update_list, remap_list); - } - return r; + r = svm_range_split(prange, new_start, prange->last, &head); + + if (r) + return r; + + list_add(&head->list, insert_list); + + if (huge_page_mapping && head->last + 1 > start_align && + head->last + 1 < last_align_down && (!IS_ALIGNED(head->last, 512))) + list_add(&head->update_list, remap_list); + + return 0; } static void From f67ae28e9ac348fb47c9b54f06bbb31fd3578f3e Mon Sep 17 00:00:00 2001 From: Haotian Zhang Date: Wed, 26 Nov 2025 16:06:25 +0800 Subject: [PATCH 0956/2333] rtc: gamecube: Check the return value of ioremap() [ Upstream commit d1220e47e4bd2be8b84bc158f4dea44f2f88b226 ] The function ioremap() in gamecube_rtc_read_offset_from_sram() can fail and return NULL, which is dereferenced without checking, leading to a NULL pointer dereference. Add a check for the return value of ioremap() and return -ENOMEM on failure. Fixes: 86559400b3ef ("rtc: gamecube: Add a RTC driver for the GameCube, Wii and Wii U") Signed-off-by: Haotian Zhang Reviewed-by: Link Mauve Link: https://patch.msgid.link/20251126080625.1752-1-vulab@iscas.ac.cn Signed-off-by: Alexandre Belloni Signed-off-by: Sasha Levin --- drivers/rtc/rtc-gamecube.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/rtc/rtc-gamecube.c b/drivers/rtc/rtc-gamecube.c index c828bc8e05b9c..045d5d45ab4b0 100644 --- a/drivers/rtc/rtc-gamecube.c +++ b/drivers/rtc/rtc-gamecube.c @@ -242,6 +242,10 @@ static int gamecube_rtc_read_offset_from_sram(struct priv *d) } hw_srnprot = ioremap(res.start, resource_size(&res)); + if (!hw_srnprot) { + pr_err("failed to ioremap hw_srnprot\n"); + return -ENOMEM; + } old = ioread32be(hw_srnprot); /* TODO: figure out why we use this magic constant. I obtained it by From 4a7915a26d19e053828e0645c991770f271b2c89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nuno=20S=C3=A1?= Date: Fri, 28 Nov 2025 16:36:38 +0000 Subject: [PATCH 0957/2333] rtc: max31335: Fix ignored return value in set_alarm MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit f07640f9fb8df2158199da1da1f8282948385a84 ] Return the result from regmap_update_bits() instead of ignoring it and always returning 0. Fixes: dedaf03b99d6 ("rtc: max31335: add driver support") Signed-off-by: Nuno Sá Link: https://patch.msgid.link/20251128-max31335-handler-error-v1-1-6b6f7f78dbda@analog.com Signed-off-by: Alexandre Belloni Signed-off-by: Sasha Levin --- drivers/rtc/rtc-max31335.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/rtc/rtc-max31335.c b/drivers/rtc/rtc-max31335.c index dfb5bad3a3691..23b7bf16b4cd5 100644 --- a/drivers/rtc/rtc-max31335.c +++ b/drivers/rtc/rtc-max31335.c @@ -391,10 +391,8 @@ static int max31335_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) if (ret) return ret; - ret = regmap_update_bits(max31335->regmap, max31335->chip->int_status_reg, - MAX31335_STATUS1_A1F, 0); - - return 0; + return regmap_update_bits(max31335->regmap, max31335->chip->int_status_reg, + MAX31335_STATUS1_A1F, 0); } static int max31335_alarm_irq_enable(struct device *dev, unsigned int enabled) From d48f75972d39537b837f569134e6fd1f05fcc27c Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Sat, 6 Dec 2025 14:38:48 +0100 Subject: [PATCH 0958/2333] regulator: spacemit: Align input supply name with the DT binding [ Upstream commit 99f0c3a654c4a762aca4fadc8d9f8636b36d570a ] The Device Tree binding schema for the SpacemiT P1 PMIC defines the main input supply property as "vin-supply", but the driver defines the supply name for BUCK and ALDO regulators as "vcc". This causes the regulator core to lookup for a non-existent "vcc-supply". Rename the supply from "vcc" to "vin", to match the DT binding and ensure that the regulators input supplies are correctly resolved. After this change, the regulators supply hierarchy is correctly reported: $ cat /sys/kernel/debug/regulator/regulator_summary regulator use open bypass opmode voltage current min max --------------------------------------------------------------------------------------- regulator-dummy 1 0 0 unknown 0mV 0mA 0mV 0mV dc_in_12v 2 1 0 unknown 12000mV 0mA 12000mV 12000mV vcc_4v 7 10 0 unknown 4000mV 0mA 4000mV 4000mV buck1 1 0 0 unknown 1050mV 0mA 500mV 3425mV buck2 1 0 0 unknown 900mV 0mA 500mV 3425mV buck3 1 0 0 unknown 1800mV 0mA 500mV 1800mV buck4 1 0 0 unknown 3300mV 0mA 500mV 3300mV buck5 3 7 0 unknown 2100mV 0mA 500mV 3425mV dldo1 0 0 0 unknown 1200mV 0mA 500mV 3125mV dldo2 0 0 0 unknown 500mV 0mA 500mV 3125mV dldo3 0 0 0 unknown 500mV 0mA 500mV 3125mV dldo4 1 0 0 unknown 1800mV 0mA 500mV 3125mV dldo5 0 0 0 unknown 500mV 0mA 500mV 3125mV dldo6 1 0 0 unknown 1800mV 0mA 500mV 3125mV dldo7 0 0 0 unknown 500mV 0mA 500mV 3125mV buck6 1 0 0 unknown 1100mV 0mA 500mV 3425mV aldo1 0 0 0 unknown 1800mV 0mA 500mV 3125mV aldo2 0 0 0 unknown 500mV 0mA 500mV 3125mV aldo3 0 0 0 unknown 500mV 0mA 500mV 3125mV aldo4 0 0 0 unknown 500mV 0mA 500mV 3125mV Fixes: 8b84d712ad84 ("regulator: spacemit: support SpacemiT P1 regulators") Signed-off-by: Javier Martinez Canillas Link: https://patch.msgid.link/20251206133852.1739475-1-javierm@redhat.com Signed-off-by: Mark Brown Signed-off-by: Sasha Levin --- drivers/regulator/spacemit-p1.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/regulator/spacemit-p1.c b/drivers/regulator/spacemit-p1.c index d437e6738ea1e..2bf9137e12b1d 100644 --- a/drivers/regulator/spacemit-p1.c +++ b/drivers/regulator/spacemit-p1.c @@ -87,10 +87,10 @@ static const struct linear_range p1_ldo_ranges[] = { } #define P1_BUCK_DESC(_n) \ - P1_REG_DESC(BUCK, buck, _n, "vcc", 0x47, BUCK_MASK, 254, p1_buck_ranges) + P1_REG_DESC(BUCK, buck, _n, "vin", 0x47, BUCK_MASK, 254, p1_buck_ranges) #define P1_ALDO_DESC(_n) \ - P1_REG_DESC(ALDO, aldo, _n, "vcc", 0x5b, LDO_MASK, 117, p1_ldo_ranges) + P1_REG_DESC(ALDO, aldo, _n, "vin", 0x5b, LDO_MASK, 117, p1_ldo_ranges) #define P1_DLDO_DESC(_n) \ P1_REG_DESC(DLDO, dldo, _n, "buck5", 0x67, LDO_MASK, 117, p1_ldo_ranges) From 8f9e51cf2a2a43d0cd72d3dc0b5ccea3f639c187 Mon Sep 17 00:00:00 2001 From: Junrui Luo Date: Tue, 9 Dec 2025 13:16:41 +0800 Subject: [PATCH 0959/2333] ALSA: firewire-motu: add bounds check in put_user loop for DSP events [ Upstream commit 298e753880b6ea99ac30df34959a7a03b0878eed ] In the DSP event handling code, a put_user() loop copies event data. When the user buffer size is not aligned to 4 bytes, it could overwrite beyond the buffer boundary. Fix by adding a bounds check before put_user(). Suggested-by: Takashi Iwai Fixes: 634ec0b2906e ("ALSA: firewire-motu: notify event for parameter change in register DSP model") Signed-off-by: Junrui Luo Link: https://patch.msgid.link/SYBPR01MB788112C72AF8A1C8C448B4B8AFA3A@SYBPR01MB7881.ausprd01.prod.outlook.com Signed-off-by: Takashi Iwai Signed-off-by: Sasha Levin --- sound/firewire/motu/motu-hwdep.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/firewire/motu/motu-hwdep.c b/sound/firewire/motu/motu-hwdep.c index 6675b23aad69e..89dc436a06529 100644 --- a/sound/firewire/motu/motu-hwdep.c +++ b/sound/firewire/motu/motu-hwdep.c @@ -75,7 +75,7 @@ static long hwdep_read(struct snd_hwdep *hwdep, char __user *buf, long count, while (consumed < count && snd_motu_register_dsp_message_parser_copy_event(motu, &ev)) { ptr = (u32 __user *)(buf + consumed); - if (put_user(ev, ptr)) + if (consumed + sizeof(ev) > count || put_user(ev, ptr)) return -EFAULT; consumed += sizeof(ev); } From fb074e5c4f3eacda00b920a7192f12aa8fdbddad Mon Sep 17 00:00:00 2001 From: Liyuan Pang Date: Tue, 9 Dec 2025 03:19:45 +0100 Subject: [PATCH 0960/2333] ARM: 9464/1: fix input-only operand modification in load_unaligned_zeropad() [ Upstream commit edb924a7211c9aa7a4a415e03caee4d875e46b8e ] In the inline assembly inside load_unaligned_zeropad(), the "addr" is constrained as input-only operand. The compiler assumes that on exit from the asm statement these operands contain the same values as they had before executing the statement, but when kernel page fault happened, the assembly fixup code "bic %2 %2, #0x3" modify the value of "addr", which may lead to an unexpected behavior. Use a temporary variable "tmp" to handle it, instead of modifying the input-only operand, just like what arm64's load_unaligned_zeropad() does. Fixes: b9a50f74905a ("ARM: 7450/1: dcache: select DCACHE_WORD_ACCESS for little-endian ARMv6+ CPUs") Co-developed-by: Xie Yuanbin Signed-off-by: Xie Yuanbin Signed-off-by: Liyuan Pang Signed-off-by: Russell King (Oracle) Signed-off-by: Sasha Levin --- arch/arm/include/asm/word-at-a-time.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/arm/include/asm/word-at-a-time.h b/arch/arm/include/asm/word-at-a-time.h index f9a3897b06e7f..5023f98d8293d 100644 --- a/arch/arm/include/asm/word-at-a-time.h +++ b/arch/arm/include/asm/word-at-a-time.h @@ -67,7 +67,7 @@ static inline unsigned long find_zero(unsigned long mask) */ static inline unsigned long load_unaligned_zeropad(const void *addr) { - unsigned long ret, offset; + unsigned long ret, tmp; /* Load word from unaligned pointer addr */ asm( @@ -75,9 +75,9 @@ static inline unsigned long load_unaligned_zeropad(const void *addr) "2:\n" " .pushsection .text.fixup,\"ax\"\n" " .align 2\n" - "3: and %1, %2, #0x3\n" - " bic %2, %2, #0x3\n" - " ldr %0, [%2]\n" + "3: bic %1, %2, #0x3\n" + " ldr %0, [%1]\n" + " and %1, %2, #0x3\n" " lsl %1, %1, #0x3\n" #ifndef __ARMEB__ " lsr %0, %0, %1\n" @@ -90,7 +90,7 @@ static inline unsigned long load_unaligned_zeropad(const void *addr) " .align 3\n" " .long 1b, 3b\n" " .popsection" - : "=&r" (ret), "=&r" (offset) + : "=&r" (ret), "=&r" (tmp) : "r" (addr), "Qo" (*(unsigned long *)addr)); return ret; From c287d34592cca02a91ad60449d88e5c713e9f57b Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 18 Sep 2025 11:40:51 +0300 Subject: [PATCH 0961/2333] drm/xe/fbdev: use the same 64-byte stride alignment as i915 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 4a36b339a14ae6f2a366125e3d64f0c165193293 ] For reasons unknown, xe uses XE_PAGE_SIZE alignment for stride. Presumably it's just a confusion between stride alignment and bo allocation size alignment. Switch to 64 byte alignment to, uh, align with i915. This will also be helpful in deduplicating and unifying the xe and i915 framebuffer allocation. Link: https://lore.kernel.org/r/aLqsC87Ol_zCXOkN@intel.com Suggested-by: Ville Syrjälä Reviewed-by: Ville Syrjälä Link: https://lore.kernel.org/r/7f4972104de8b179d5724ae83892ee294d3f3fd3.1758184771.git.jani.nikula@intel.com Signed-off-by: Jani Nikula Stable-dep-of: 460b31720369 ("drm/i915/fbdev: Hold runtime PM ref during fbdev BO creation") Signed-off-by: Sasha Levin --- drivers/gpu/drm/xe/display/intel_fbdev_fb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/xe/display/intel_fbdev_fb.c b/drivers/gpu/drm/xe/display/intel_fbdev_fb.c index 8ea9a472113c4..bce4cb16f6820 100644 --- a/drivers/gpu/drm/xe/display/intel_fbdev_fb.c +++ b/drivers/gpu/drm/xe/display/intel_fbdev_fb.c @@ -33,7 +33,7 @@ struct intel_framebuffer *intel_fbdev_fb_alloc(struct drm_fb_helper *helper, mode_cmd.height = sizes->surface_height; mode_cmd.pitches[0] = ALIGN(mode_cmd.width * - DIV_ROUND_UP(sizes->surface_bpp, 8), XE_PAGE_SIZE); + DIV_ROUND_UP(sizes->surface_bpp, 8), 64); mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp, sizes->surface_depth); From bc600ef08326915039e61432501ea290940b0a57 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 18 Sep 2025 11:40:52 +0300 Subject: [PATCH 0962/2333] drm/i915/fbdev: make intel_framebuffer_create() error return handling explicit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 6979d2c80c2a5b1f04157c4d6eb038bb32861cfa ] It's sketchy to pass error pointers via to_intel_framebuffer(). It probably works as long as struct intel_framebuffer embeds struct drm_framebuffer at offset 0, but be explicit about it. Reviewed-by: Ville Syrjälä Link: https://lore.kernel.org/r/17631db227d527d6c67f5d6b67adec1ff8dc6f8d.1758184771.git.jani.nikula@intel.com Signed-off-by: Jani Nikula Stable-dep-of: 460b31720369 ("drm/i915/fbdev: Hold runtime PM ref during fbdev BO creation") Signed-off-by: Sasha Levin --- drivers/gpu/drm/i915/display/intel_fbdev_fb.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_fbdev_fb.c b/drivers/gpu/drm/i915/display/intel_fbdev_fb.c index 210aee9ae88b8..b9dfd00a7d05b 100644 --- a/drivers/gpu/drm/i915/display/intel_fbdev_fb.c +++ b/drivers/gpu/drm/i915/display/intel_fbdev_fb.c @@ -67,9 +67,16 @@ struct intel_framebuffer *intel_fbdev_fb_alloc(struct drm_fb_helper *helper, mode_cmd.pixel_format, mode_cmd.modifier[0]), &mode_cmd); + if (IS_ERR(fb)) { + i915_gem_object_put(obj); + goto err; + } + i915_gem_object_put(obj); return to_intel_framebuffer(fb); +err: + return ERR_CAST(fb); } int intel_fbdev_fb_fill_info(struct intel_display *display, struct fb_info *info, From 6f36ae55d245f4f88ca5d27218f252fd03104d2b Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 18 Sep 2025 11:40:53 +0300 Subject: [PATCH 0963/2333] drm/{i915, xe}/fbdev: pass struct drm_device to intel_fbdev_fb_alloc() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 9e5cf822a207ee8c9856024c047abaccb4d185e5 ] The function doesn't actually need struct drm_fb_helper for anything, just pass struct drm_device. Reviewed-by: Ville Syrjälä Link: https://lore.kernel.org/r/16360584f80cdc5ee35fd94cfd92fd3955588dfd.1758184771.git.jani.nikula@intel.com Signed-off-by: Jani Nikula Stable-dep-of: 460b31720369 ("drm/i915/fbdev: Hold runtime PM ref during fbdev BO creation") Signed-off-by: Sasha Levin --- drivers/gpu/drm/i915/display/intel_fbdev.c | 2 +- drivers/gpu/drm/i915/display/intel_fbdev_fb.c | 10 +++++----- drivers/gpu/drm/i915/display/intel_fbdev_fb.h | 4 ++-- drivers/gpu/drm/xe/display/intel_fbdev_fb.c | 7 +++---- 4 files changed, 11 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_fbdev.c b/drivers/gpu/drm/i915/display/intel_fbdev.c index 7c4709d58aa34..46c6de5f60888 100644 --- a/drivers/gpu/drm/i915/display/intel_fbdev.c +++ b/drivers/gpu/drm/i915/display/intel_fbdev.c @@ -237,7 +237,7 @@ int intel_fbdev_driver_fbdev_probe(struct drm_fb_helper *helper, if (!fb || drm_WARN_ON(display->drm, !intel_fb_bo(&fb->base))) { drm_dbg_kms(display->drm, "no BIOS fb, allocating a new one\n"); - fb = intel_fbdev_fb_alloc(helper, sizes); + fb = intel_fbdev_fb_alloc(display->drm, sizes); if (IS_ERR(fb)) return PTR_ERR(fb); } else { diff --git a/drivers/gpu/drm/i915/display/intel_fbdev_fb.c b/drivers/gpu/drm/i915/display/intel_fbdev_fb.c index b9dfd00a7d05b..4de13d1a4c7a7 100644 --- a/drivers/gpu/drm/i915/display/intel_fbdev_fb.c +++ b/drivers/gpu/drm/i915/display/intel_fbdev_fb.c @@ -13,11 +13,11 @@ #include "intel_fb.h" #include "intel_fbdev_fb.h" -struct intel_framebuffer *intel_fbdev_fb_alloc(struct drm_fb_helper *helper, +struct intel_framebuffer *intel_fbdev_fb_alloc(struct drm_device *drm, struct drm_fb_helper_surface_size *sizes) { - struct intel_display *display = to_intel_display(helper->dev); - struct drm_i915_private *dev_priv = to_i915(display->drm); + struct intel_display *display = to_intel_display(drm); + struct drm_i915_private *dev_priv = to_i915(drm); struct drm_framebuffer *fb; struct drm_mode_fb_cmd2 mode_cmd = {}; struct drm_i915_gem_object *obj; @@ -58,12 +58,12 @@ struct intel_framebuffer *intel_fbdev_fb_alloc(struct drm_fb_helper *helper, } if (IS_ERR(obj)) { - drm_err(display->drm, "failed to allocate framebuffer (%pe)\n", obj); + drm_err(drm, "failed to allocate framebuffer (%pe)\n", obj); return ERR_PTR(-ENOMEM); } fb = intel_framebuffer_create(intel_bo_to_drm_bo(obj), - drm_get_format_info(display->drm, + drm_get_format_info(drm, mode_cmd.pixel_format, mode_cmd.modifier[0]), &mode_cmd); diff --git a/drivers/gpu/drm/i915/display/intel_fbdev_fb.h b/drivers/gpu/drm/i915/display/intel_fbdev_fb.h index cb79572727150..668ae355f5e5b 100644 --- a/drivers/gpu/drm/i915/display/intel_fbdev_fb.h +++ b/drivers/gpu/drm/i915/display/intel_fbdev_fb.h @@ -6,14 +6,14 @@ #ifndef __INTEL_FBDEV_FB_H__ #define __INTEL_FBDEV_FB_H__ -struct drm_fb_helper; +struct drm_device; struct drm_fb_helper_surface_size; struct drm_gem_object; struct fb_info; struct i915_vma; struct intel_display; -struct intel_framebuffer *intel_fbdev_fb_alloc(struct drm_fb_helper *helper, +struct intel_framebuffer *intel_fbdev_fb_alloc(struct drm_device *drm, struct drm_fb_helper_surface_size *sizes); int intel_fbdev_fb_fill_info(struct intel_display *display, struct fb_info *info, struct drm_gem_object *obj, struct i915_vma *vma); diff --git a/drivers/gpu/drm/xe/display/intel_fbdev_fb.c b/drivers/gpu/drm/xe/display/intel_fbdev_fb.c index bce4cb16f6820..5c0874bfa6ab1 100644 --- a/drivers/gpu/drm/xe/display/intel_fbdev_fb.c +++ b/drivers/gpu/drm/xe/display/intel_fbdev_fb.c @@ -15,12 +15,11 @@ #include -struct intel_framebuffer *intel_fbdev_fb_alloc(struct drm_fb_helper *helper, +struct intel_framebuffer *intel_fbdev_fb_alloc(struct drm_device *drm, struct drm_fb_helper_surface_size *sizes) { struct drm_framebuffer *fb; - struct drm_device *dev = helper->dev; - struct xe_device *xe = to_xe_device(dev); + struct xe_device *xe = to_xe_device(drm); struct drm_mode_fb_cmd2 mode_cmd = {}; struct xe_bo *obj; int size; @@ -67,7 +66,7 @@ struct intel_framebuffer *intel_fbdev_fb_alloc(struct drm_fb_helper *helper, } fb = intel_framebuffer_create(&obj->ttm.base, - drm_get_format_info(dev, + drm_get_format_info(drm, mode_cmd.pixel_format, mode_cmd.modifier[0]), &mode_cmd); From cabc9d26c06fec51a21702c20759a816755de131 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 18 Sep 2025 11:40:54 +0300 Subject: [PATCH 0964/2333] drm/{i915, xe}/fbdev: deduplicate struct drm_mode_fb_cmd2 init MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit f9ff39f940f5ddd1d4ffcff602de7206aa1ff05d ] Pull struct drm_mode_fb_cmd2 initialization out of the driver dependent code into shared display code. v2: Rebase on xe stride alignment change Reviewed-by: Ville Syrjälä Link: https://lore.kernel.org/r/e922e47bfd39f9c5777f869ff23c23309ebbb380.1758184771.git.jani.nikula@intel.com Signed-off-by: Jani Nikula Stable-dep-of: 460b31720369 ("drm/i915/fbdev: Hold runtime PM ref during fbdev BO creation") Signed-off-by: Sasha Levin --- drivers/gpu/drm/i915/display/intel_fbdev.c | 32 ++++++++++++++++++- drivers/gpu/drm/i915/display/intel_fbdev_fb.c | 25 ++++----------- drivers/gpu/drm/i915/display/intel_fbdev_fb.h | 4 +-- drivers/gpu/drm/xe/display/intel_fbdev_fb.c | 25 ++++----------- 4 files changed, 45 insertions(+), 41 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_fbdev.c b/drivers/gpu/drm/i915/display/intel_fbdev.c index 46c6de5f60888..e46c08762b847 100644 --- a/drivers/gpu/drm/i915/display/intel_fbdev.c +++ b/drivers/gpu/drm/i915/display/intel_fbdev.c @@ -207,6 +207,35 @@ static const struct drm_fb_helper_funcs intel_fb_helper_funcs = { .fb_set_suspend = intelfb_set_suspend, }; +static void intel_fbdev_fill_mode_cmd(struct drm_fb_helper_surface_size *sizes, + struct drm_mode_fb_cmd2 *mode_cmd) +{ + /* we don't do packed 24bpp */ + if (sizes->surface_bpp == 24) + sizes->surface_bpp = 32; + + mode_cmd->width = sizes->surface_width; + mode_cmd->height = sizes->surface_height; + + mode_cmd->pitches[0] = ALIGN(mode_cmd->width * DIV_ROUND_UP(sizes->surface_bpp, 8), 64); + mode_cmd->pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp, + sizes->surface_depth); +} + +static struct intel_framebuffer * +__intel_fbdev_fb_alloc(struct intel_display *display, + struct drm_fb_helper_surface_size *sizes) +{ + struct drm_mode_fb_cmd2 mode_cmd = {}; + struct intel_framebuffer *fb; + + intel_fbdev_fill_mode_cmd(sizes, &mode_cmd); + + fb = intel_fbdev_fb_alloc(display->drm, &mode_cmd); + + return fb; +} + int intel_fbdev_driver_fbdev_probe(struct drm_fb_helper *helper, struct drm_fb_helper_surface_size *sizes) { @@ -237,7 +266,8 @@ int intel_fbdev_driver_fbdev_probe(struct drm_fb_helper *helper, if (!fb || drm_WARN_ON(display->drm, !intel_fb_bo(&fb->base))) { drm_dbg_kms(display->drm, "no BIOS fb, allocating a new one\n"); - fb = intel_fbdev_fb_alloc(display->drm, sizes); + + fb = __intel_fbdev_fb_alloc(display, sizes); if (IS_ERR(fb)) return PTR_ERR(fb); } else { diff --git a/drivers/gpu/drm/i915/display/intel_fbdev_fb.c b/drivers/gpu/drm/i915/display/intel_fbdev_fb.c index 4de13d1a4c7a7..685612e6afc53 100644 --- a/drivers/gpu/drm/i915/display/intel_fbdev_fb.c +++ b/drivers/gpu/drm/i915/display/intel_fbdev_fb.c @@ -3,7 +3,7 @@ * Copyright © 2023 Intel Corporation */ -#include +#include #include "gem/i915_gem_lmem.h" @@ -14,28 +14,15 @@ #include "intel_fbdev_fb.h" struct intel_framebuffer *intel_fbdev_fb_alloc(struct drm_device *drm, - struct drm_fb_helper_surface_size *sizes) + struct drm_mode_fb_cmd2 *mode_cmd) { struct intel_display *display = to_intel_display(drm); struct drm_i915_private *dev_priv = to_i915(drm); struct drm_framebuffer *fb; - struct drm_mode_fb_cmd2 mode_cmd = {}; struct drm_i915_gem_object *obj; int size; - /* we don't do packed 24bpp */ - if (sizes->surface_bpp == 24) - sizes->surface_bpp = 32; - - mode_cmd.width = sizes->surface_width; - mode_cmd.height = sizes->surface_height; - - mode_cmd.pitches[0] = ALIGN(mode_cmd.width * - DIV_ROUND_UP(sizes->surface_bpp, 8), 64); - mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp, - sizes->surface_depth); - - size = mode_cmd.pitches[0] * mode_cmd.height; + size = mode_cmd->pitches[0] * mode_cmd->height; size = PAGE_ALIGN(size); obj = ERR_PTR(-ENODEV); @@ -64,9 +51,9 @@ struct intel_framebuffer *intel_fbdev_fb_alloc(struct drm_device *drm, fb = intel_framebuffer_create(intel_bo_to_drm_bo(obj), drm_get_format_info(drm, - mode_cmd.pixel_format, - mode_cmd.modifier[0]), - &mode_cmd); + mode_cmd->pixel_format, + mode_cmd->modifier[0]), + mode_cmd); if (IS_ERR(fb)) { i915_gem_object_put(obj); goto err; diff --git a/drivers/gpu/drm/i915/display/intel_fbdev_fb.h b/drivers/gpu/drm/i915/display/intel_fbdev_fb.h index 668ae355f5e5b..83454ffbf79cd 100644 --- a/drivers/gpu/drm/i915/display/intel_fbdev_fb.h +++ b/drivers/gpu/drm/i915/display/intel_fbdev_fb.h @@ -7,14 +7,14 @@ #define __INTEL_FBDEV_FB_H__ struct drm_device; -struct drm_fb_helper_surface_size; struct drm_gem_object; +struct drm_mode_fb_cmd2; struct fb_info; struct i915_vma; struct intel_display; struct intel_framebuffer *intel_fbdev_fb_alloc(struct drm_device *drm, - struct drm_fb_helper_surface_size *sizes); + struct drm_mode_fb_cmd2 *mode_cmd); int intel_fbdev_fb_fill_info(struct intel_display *display, struct fb_info *info, struct drm_gem_object *obj, struct i915_vma *vma); diff --git a/drivers/gpu/drm/xe/display/intel_fbdev_fb.c b/drivers/gpu/drm/xe/display/intel_fbdev_fb.c index 5c0874bfa6ab1..8eaf1cc7fdf93 100644 --- a/drivers/gpu/drm/xe/display/intel_fbdev_fb.c +++ b/drivers/gpu/drm/xe/display/intel_fbdev_fb.c @@ -3,7 +3,7 @@ * Copyright © 2023 Intel Corporation */ -#include +#include #include "intel_display_core.h" #include "intel_display_types.h" @@ -16,27 +16,14 @@ #include struct intel_framebuffer *intel_fbdev_fb_alloc(struct drm_device *drm, - struct drm_fb_helper_surface_size *sizes) + struct drm_mode_fb_cmd2 *mode_cmd) { struct drm_framebuffer *fb; struct xe_device *xe = to_xe_device(drm); - struct drm_mode_fb_cmd2 mode_cmd = {}; struct xe_bo *obj; int size; - /* we don't do packed 24bpp */ - if (sizes->surface_bpp == 24) - sizes->surface_bpp = 32; - - mode_cmd.width = sizes->surface_width; - mode_cmd.height = sizes->surface_height; - - mode_cmd.pitches[0] = ALIGN(mode_cmd.width * - DIV_ROUND_UP(sizes->surface_bpp, 8), 64); - mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp, - sizes->surface_depth); - - size = mode_cmd.pitches[0] * mode_cmd.height; + size = mode_cmd->pitches[0] * mode_cmd->height; size = PAGE_ALIGN(size); obj = ERR_PTR(-ENODEV); @@ -67,9 +54,9 @@ struct intel_framebuffer *intel_fbdev_fb_alloc(struct drm_device *drm, fb = intel_framebuffer_create(&obj->ttm.base, drm_get_format_info(drm, - mode_cmd.pixel_format, - mode_cmd.modifier[0]), - &mode_cmd); + mode_cmd->pixel_format, + mode_cmd->modifier[0]), + mode_cmd); if (IS_ERR(fb)) { xe_bo_unpin_map_no_vm(obj); goto err; From 97ee36e58a8cf608cc762b65aec27fd729857181 Mon Sep 17 00:00:00 2001 From: Dibin Moolakadan Subrahmanian Date: Tue, 11 Nov 2025 19:24:03 +0530 Subject: [PATCH 0965/2333] drm/i915/fbdev: Hold runtime PM ref during fbdev BO creation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 460b31720369fc77c23301708641cfa1bf2fcb8f ] During fbdev probe, the xe driver allocates and pins a framebuffer BO (via xe_bo_create_pin_map_novm() → xe_ggtt_insert_bo()). Without a runtime PM reference, xe_pm_runtime_get_noresume() warns about missing outer PM protection as below: xe 0000:03:00.0: [drm] Missing outer runtime PM protection Acquire a runtime PM reference before framebuffer allocation to ensure xe_ggtt_insert_bo() executes under active runtime PM context. Changes in v2: - Update commit message to add Fixes tag (Jani Nikula) Closes: https://gitlab.freedesktop.org/drm/xe/kernel/-/issues/6350 Fixes: 44e694958b95 ("drm/xe/display: Implement display support") Cc: Jani Nikula Signed-off-by: Dibin Moolakadan Subrahmanian Reviewed-by: Jouni Högander Signed-off-by: Ankit Nautiyal Link: https://patch.msgid.link/20251111135403.3415947-1-dibin.moolakadan.subrahmanian@intel.com (cherry picked from commit 37fc7b7b3ab0e3bb900657199cd3770a4fda03fb) Signed-off-by: Jani Nikula Signed-off-by: Sasha Levin --- drivers/gpu/drm/i915/display/intel_fbdev.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_fbdev.c b/drivers/gpu/drm/i915/display/intel_fbdev.c index e46c08762b847..7daf72b69bae4 100644 --- a/drivers/gpu/drm/i915/display/intel_fbdev.c +++ b/drivers/gpu/drm/i915/display/intel_fbdev.c @@ -263,13 +263,18 @@ int intel_fbdev_driver_fbdev_probe(struct drm_fb_helper *helper, drm_framebuffer_put(&fb->base); fb = NULL; } + + wakeref = intel_display_rpm_get(display); + if (!fb || drm_WARN_ON(display->drm, !intel_fb_bo(&fb->base))) { drm_dbg_kms(display->drm, "no BIOS fb, allocating a new one\n"); fb = __intel_fbdev_fb_alloc(display, sizes); - if (IS_ERR(fb)) - return PTR_ERR(fb); + if (IS_ERR(fb)) { + ret = PTR_ERR(fb); + goto out_unlock; + } } else { drm_dbg_kms(display->drm, "re-using BIOS fb\n"); prealloc = true; @@ -277,8 +282,6 @@ int intel_fbdev_driver_fbdev_probe(struct drm_fb_helper *helper, sizes->fb_height = fb->base.height; } - wakeref = intel_display_rpm_get(display); - /* Pin the GGTT vma for our access via info->screen_base. * This also validates that any existing fb inherited from the * BIOS is suitable for own access. From ef0cd7b694928573f6569e61c14f5f059253162e Mon Sep 17 00:00:00 2001 From: Mohamed Khalfella Date: Fri, 5 Dec 2025 13:17:02 -0800 Subject: [PATCH 0966/2333] block: Use RCU in blk_mq_[un]quiesce_tagset() instead of set->tag_list_lock [ Upstream commit 59e25ef2b413c72da6686d431e7759302cfccafa ] blk_mq_{add,del}_queue_tag_set() functions add and remove queues from tagset, the functions make sure that tagset and queues are marked as shared when two or more queues are attached to the same tagset. Initially a tagset starts as unshared and when the number of added queues reaches two, blk_mq_add_queue_tag_set() marks it as shared along with all the queues attached to it. When the number of attached queues drops to 1 blk_mq_del_queue_tag_set() need to mark both the tagset and the remaining queues as unshared. Both functions need to freeze current queues in tagset before setting on unsetting BLK_MQ_F_TAG_QUEUE_SHARED flag. While doing so, both functions hold set->tag_list_lock mutex, which makes sense as we do not want queues to be added or deleted in the process. This used to work fine until commit 98d81f0df70c ("nvme: use blk_mq_[un]quiesce_tagset") made the nvme driver quiesce tagset instead of quiscing individual queues. blk_mq_quiesce_tagset() does the job and quiesce the queues in set->tag_list while holding set->tag_list_lock also. This results in deadlock between two threads with these stacktraces: __schedule+0x47c/0xbb0 ? timerqueue_add+0x66/0xb0 schedule+0x1c/0xa0 schedule_preempt_disabled+0xa/0x10 __mutex_lock.constprop.0+0x271/0x600 blk_mq_quiesce_tagset+0x25/0xc0 nvme_dev_disable+0x9c/0x250 nvme_timeout+0x1fc/0x520 blk_mq_handle_expired+0x5c/0x90 bt_iter+0x7e/0x90 blk_mq_queue_tag_busy_iter+0x27e/0x550 ? __blk_mq_complete_request_remote+0x10/0x10 ? __blk_mq_complete_request_remote+0x10/0x10 ? __call_rcu_common.constprop.0+0x1c0/0x210 blk_mq_timeout_work+0x12d/0x170 process_one_work+0x12e/0x2d0 worker_thread+0x288/0x3a0 ? rescuer_thread+0x480/0x480 kthread+0xb8/0xe0 ? kthread_park+0x80/0x80 ret_from_fork+0x2d/0x50 ? kthread_park+0x80/0x80 ret_from_fork_asm+0x11/0x20 __schedule+0x47c/0xbb0 ? xas_find+0x161/0x1a0 schedule+0x1c/0xa0 blk_mq_freeze_queue_wait+0x3d/0x70 ? destroy_sched_domains_rcu+0x30/0x30 blk_mq_update_tag_set_shared+0x44/0x80 blk_mq_exit_queue+0x141/0x150 del_gendisk+0x25a/0x2d0 nvme_ns_remove+0xc9/0x170 nvme_remove_namespaces+0xc7/0x100 nvme_remove+0x62/0x150 pci_device_remove+0x23/0x60 device_release_driver_internal+0x159/0x200 unbind_store+0x99/0xa0 kernfs_fop_write_iter+0x112/0x1e0 vfs_write+0x2b1/0x3d0 ksys_write+0x4e/0xb0 do_syscall_64+0x5b/0x160 entry_SYSCALL_64_after_hwframe+0x4b/0x53 The top stacktrace is showing nvme_timeout() called to handle nvme command timeout. timeout handler is trying to disable the controller and as a first step, it needs to blk_mq_quiesce_tagset() to tell blk-mq not to call queue callback handlers. The thread is stuck waiting for set->tag_list_lock as it tries to walk the queues in set->tag_list. The lock is held by the second thread in the bottom stack which is waiting for one of queues to be frozen. The queue usage counter will drop to zero after nvme_timeout() finishes, and this will not happen because the thread will wait for this mutex forever. Given that [un]quiescing queue is an operation that does not need to sleep, update blk_mq_[un]quiesce_tagset() to use RCU instead of taking set->tag_list_lock, update blk_mq_{add,del}_queue_tag_set() to use RCU safe list operations. Also, delete INIT_LIST_HEAD(&q->tag_set_list) in blk_mq_del_queue_tag_set() because we can not re-initialize it while the list is being traversed under RCU. The deleted queue will not be added/deleted to/from a tagset and it will be freed in blk_free_queue() after the end of RCU grace period. Signed-off-by: Mohamed Khalfella Fixes: 98d81f0df70c ("nvme: use blk_mq_[un]quiesce_tagset") Reviewed-by: Ming Lei Reviewed-by: Bart Van Assche Signed-off-by: Jens Axboe Signed-off-by: Sasha Levin --- block/blk-mq.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/block/blk-mq.c b/block/blk-mq.c index 33a0062f9e56d..f901aeba85522 100644 --- a/block/blk-mq.c +++ b/block/blk-mq.c @@ -336,12 +336,12 @@ void blk_mq_quiesce_tagset(struct blk_mq_tag_set *set) { struct request_queue *q; - mutex_lock(&set->tag_list_lock); - list_for_each_entry(q, &set->tag_list, tag_set_list) { + rcu_read_lock(); + list_for_each_entry_rcu(q, &set->tag_list, tag_set_list) { if (!blk_queue_skip_tagset_quiesce(q)) blk_mq_quiesce_queue_nowait(q); } - mutex_unlock(&set->tag_list_lock); + rcu_read_unlock(); blk_mq_wait_quiesce_done(set); } @@ -351,12 +351,12 @@ void blk_mq_unquiesce_tagset(struct blk_mq_tag_set *set) { struct request_queue *q; - mutex_lock(&set->tag_list_lock); - list_for_each_entry(q, &set->tag_list, tag_set_list) { + rcu_read_lock(); + list_for_each_entry_rcu(q, &set->tag_list, tag_set_list) { if (!blk_queue_skip_tagset_quiesce(q)) blk_mq_unquiesce_queue(q); } - mutex_unlock(&set->tag_list_lock); + rcu_read_unlock(); } EXPORT_SYMBOL_GPL(blk_mq_unquiesce_tagset); @@ -4308,7 +4308,7 @@ static void blk_mq_del_queue_tag_set(struct request_queue *q) struct blk_mq_tag_set *set = q->tag_set; mutex_lock(&set->tag_list_lock); - list_del(&q->tag_set_list); + list_del_rcu(&q->tag_set_list); if (list_is_singular(&set->tag_list)) { /* just transitioned to unshared */ set->flags &= ~BLK_MQ_F_TAG_QUEUE_SHARED; @@ -4316,7 +4316,6 @@ static void blk_mq_del_queue_tag_set(struct request_queue *q) blk_mq_update_tag_set_shared(set, false); } mutex_unlock(&set->tag_list_lock); - INIT_LIST_HEAD(&q->tag_set_list); } static void blk_mq_add_queue_tag_set(struct blk_mq_tag_set *set, @@ -4335,7 +4334,7 @@ static void blk_mq_add_queue_tag_set(struct blk_mq_tag_set *set, } if (set->flags & BLK_MQ_F_TAG_QUEUE_SHARED) queue_set_hctx_shared(q, true); - list_add_tail(&q->tag_set_list, &set->tag_list); + list_add_tail_rcu(&q->tag_set_list, &set->tag_list); mutex_unlock(&set->tag_list_lock); } From f80cf70de9121ea689e88a67c51e68fe2821ae29 Mon Sep 17 00:00:00 2001 From: Hemalatha Pinnamreddy Date: Wed, 3 Dec 2025 17:31:34 +0530 Subject: [PATCH 0967/2333] ASoC: amd: acp: update tdm channels for specific DAI [ Upstream commit f34836a8ddf9216ff919927cddb705022bf30aab ] TDM channel updates were applied to all DAIs, causing configurations to overwrite for unrelated streams. The logic is modified to update channels only for targeted DAI. This prevents corruption of other DAI settings and resolves audio issues observed during system suspend and resume cycles. Fixes: 12229b7e50cf ("ASoC: amd: acp: Add TDM support for acp i2s stream") Signed-off-by: Hemalatha Pinnamreddy Signed-off-by: Raghavendra Prasad Mallela Link: https://patch.msgid.link/20251203120136.2591395-1-raghavendraprasad.mallela@amd.com Signed-off-by: Mark Brown Signed-off-by: Sasha Levin --- sound/soc/amd/acp/acp-i2s.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/amd/acp/acp-i2s.c b/sound/soc/amd/acp/acp-i2s.c index 4ba0a66981ea9..283a674c7e2c3 100644 --- a/sound/soc/amd/acp/acp-i2s.c +++ b/sound/soc/amd/acp/acp-i2s.c @@ -157,6 +157,8 @@ static int acp_i2s_set_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask, u32 rx_mas spin_lock_irq(&chip->acp_lock); list_for_each_entry(stream, &chip->stream_list, list) { + if (dai->id != stream->dai_id) + continue; switch (chip->acp_rev) { case ACP_RN_PCI_ID: case ACP_RMB_PCI_ID: From 992710902de453ecd7c1a54352fcf3243ef5d855 Mon Sep 17 00:00:00 2001 From: Alexey Simakov Date: Tue, 2 Dec 2025 20:18:38 +0300 Subject: [PATCH 0968/2333] dm-raid: fix possible NULL dereference with undefined raid type [ Upstream commit 2f6cfd6d7cb165a7af8877b838a9f6aab4159324 ] rs->raid_type is assigned from get_raid_type_by_ll(), which may return NULL. This NULL value could be dereferenced later in the condition 'if (!(rs_is_raid10(rs) && rt_is_raid0(rs->raid_type)))'. Add a fail-fast check to return early with an error if raid_type is NULL, similar to other uses of this function. Found by Linux Verification Center (linuxtesting.org) with Svace. Fixes: 33e53f06850f ("dm raid: introduce extended superblock and new raid types to support takeover/reshaping") Signed-off-by: Alexey Simakov Signed-off-by: Mikulas Patocka Signed-off-by: Sasha Levin --- drivers/md/dm-raid.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/md/dm-raid.c b/drivers/md/dm-raid.c index c6f7129e43d34..4bacdc499984b 100644 --- a/drivers/md/dm-raid.c +++ b/drivers/md/dm-raid.c @@ -2287,6 +2287,8 @@ static int super_init_validation(struct raid_set *rs, struct md_rdev *rdev) mddev->reshape_position = le64_to_cpu(sb->reshape_position); rs->raid_type = get_raid_type_by_ll(mddev->level, mddev->layout); + if (!rs->raid_type) + return -EINVAL; } } else { From ea98ced74f5034e0056ff551a03de485b2ca16b2 Mon Sep 17 00:00:00 2001 From: Haotian Zhang Date: Mon, 1 Dec 2025 15:41:03 +0800 Subject: [PATCH 0969/2333] dm log-writes: Add missing set_freezable() for freezable kthread [ Upstream commit ab08f9c8b363297cafaf45475b08f78bf19b88ef ] The log_writes_kthread() calls try_to_freeze() but lacks set_freezable(), rendering the freeze attempt ineffective since kernel threads are non-freezable by default. This prevents proper thread suspension during system suspend/hibernate. Add set_freezable() to explicitly mark the thread as freezable. Fixes: 0e9cebe72459 ("dm: add log writes target") Signed-off-by: Haotian Zhang Reviewed-by: Benjamin Marzinski Signed-off-by: Mikulas Patocka Signed-off-by: Sasha Levin --- drivers/md/dm-log-writes.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/md/dm-log-writes.c b/drivers/md/dm-log-writes.c index 7bb7174f8f4f8..f0c84e7a5daa6 100644 --- a/drivers/md/dm-log-writes.c +++ b/drivers/md/dm-log-writes.c @@ -432,6 +432,7 @@ static int log_writes_kthread(void *arg) struct log_writes_c *lc = arg; sector_t sector = 0; + set_freezable(); while (!kthread_should_stop()) { bool super = false; bool logging_enabled; From 9e434426cc23ad5e2aad649327b59aea00294b13 Mon Sep 17 00:00:00 2001 From: Duoming Zhou Date: Tue, 28 Oct 2025 18:01:49 +0800 Subject: [PATCH 0970/2333] scsi: imm: Fix use-after-free bug caused by unfinished delayed work [ Upstream commit ab58153ec64fa3fc9aea09ca09dc9322e0b54a7c ] The delayed work item 'imm_tq' is initialized in imm_attach() and scheduled via imm_queuecommand() for processing SCSI commands. When the IMM parallel port SCSI host adapter is detached through imm_detach(), the imm_struct device instance is deallocated. However, the delayed work might still be pending or executing when imm_detach() is called, leading to use-after-free bugs when the work function imm_interrupt() accesses the already freed imm_struct memory. The race condition can occur as follows: CPU 0(detach thread) | CPU 1 | imm_queuecommand() | imm_queuecommand_lck() imm_detach() | schedule_delayed_work() kfree(dev) //FREE | imm_interrupt() | dev = container_of(...) //USE dev-> //USE Add disable_delayed_work_sync() in imm_detach() to guarantee proper cancellation of the delayed work item before imm_struct is deallocated. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Signed-off-by: Duoming Zhou Link: https://patch.msgid.link/20251028100149.40721-1-duoming@zju.edu.cn Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin --- drivers/scsi/imm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/imm.c b/drivers/scsi/imm.c index 5c602c0577989..45b0e33293a59 100644 --- a/drivers/scsi/imm.c +++ b/drivers/scsi/imm.c @@ -1260,6 +1260,7 @@ static void imm_detach(struct parport *pb) imm_struct *dev; list_for_each_entry(dev, &imm_hosts, list) { if (dev->dev->port == pb) { + disable_delayed_work_sync(&dev->imm_tq); list_del_init(&dev->list); scsi_remove_host(dev->host); scsi_host_put(dev->host); From 35287d31e0834c7be21146ba4560d15da8a450f3 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Thu, 4 Dec 2025 07:04:52 -1000 Subject: [PATCH 0971/2333] scsi: ufs: core: Fix an error handler crash [ Upstream commit 14be351e5cd07349377010e457a58fac99201832 ] The UFS error handler may be activated before SCSI scanning has started and hence before hba->ufs_device_wlun has been set. Check the hba->ufs_device_wlun pointer before using it. Cc: Peter Wang Cc: Nitin Rawat Fixes: e23ef4f22db3 ("scsi: ufs: core: Fix error handler host_sem issue") Fixes: f966e02ae521 ("scsi: ufs: core: Fix runtime suspend error deadlock") Signed-off-by: Bart Van Assche Reviewed-by: Peter Wang Reviewed-by: Nitin Rawat Tested-by: Nitin Rawat #SM8750 Link: https://patch.msgid.link/20251204170457.994851-1-bvanassche@acm.org Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin --- drivers/ufs/core/ufshcd.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 12f5a7a973128..a921a9098a291 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -6670,19 +6670,22 @@ static void ufshcd_err_handler(struct work_struct *work) hba->saved_uic_err, hba->force_reset, ufshcd_is_link_broken(hba) ? "; link is broken" : ""); - /* - * Use ufshcd_rpm_get_noresume() here to safely perform link recovery - * even if an error occurs during runtime suspend or runtime resume. - * This avoids potential deadlocks that could happen if we tried to - * resume the device while a PM operation is already in progress. - */ - ufshcd_rpm_get_noresume(hba); - if (hba->pm_op_in_progress) { - ufshcd_link_recovery(hba); + if (hba->ufs_device_wlun) { + /* + * Use ufshcd_rpm_get_noresume() here to safely perform link + * recovery even if an error occurs during runtime suspend or + * runtime resume. This avoids potential deadlocks that could + * happen if we tried to resume the device while a PM operation + * is already in progress. + */ + ufshcd_rpm_get_noresume(hba); + if (hba->pm_op_in_progress) { + ufshcd_link_recovery(hba); + ufshcd_rpm_put(hba); + return; + } ufshcd_rpm_put(hba); - return; } - ufshcd_rpm_put(hba); down(&hba->host_sem); spin_lock_irqsave(hba->host->host_lock, flags); From da07fa8730596596f0156900337444806c52ef45 Mon Sep 17 00:00:00 2001 From: Thaumy Cheng Date: Tue, 9 Dec 2025 12:16:00 +0800 Subject: [PATCH 0972/2333] perf/core: Fix missing read event generation on task exit [ Upstream commit c418d8b4d7a43a86b82ee39cb52ece3034383530 ] For events with inherit_stat enabled, a "read" event will be generated to collect per task event counts on task exit. The call chain is as follows: do_exit -> perf_event_exit_task -> perf_event_exit_task_context -> perf_event_exit_event -> perf_remove_from_context -> perf_child_detach -> sync_child_event -> perf_event_read_event However, the child event context detaches the task too early in perf_event_exit_task_context, which causes sync_child_event to never generate the read event in this case, since child_event->ctx->task is always set to TASK_TOMBSTONE. Fix that by moving context lock section backward to ensure ctx->task is not set to TASK_TOMBSTONE before generating the read event. Because perf_event_free_task calls perf_event_exit_task_context with exit = false to tear down all child events from the context, and the task never lived, accessing the task PID can lead to a use-after-free. To fix that, let sync_child_event read task from argument and move the call to the only place it should be triggered to avoid the effect of setting ctx->task to TASK_TOMESTONE, and add a task parameter to perf_event_exit_event to trigger the sync_child_event properly when needed. This bug can be reproduced by running "perf record -s" and attaching to any program that generates perf events in its child tasks. If we check the result with "perf report -T", the last line of the report will leave an empty table like "# PID TID", which is expected to contain the per-task event counts by design. Fixes: ef54c1a476ae ("perf: Rework perf_event_exit_event()") Signed-off-by: Thaumy Cheng Signed-off-by: Ingo Molnar Acked-by: Peter Zijlstra Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Arnaldo Carvalho de Melo Cc: Ian Rogers Cc: James Clark Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: linux-perf-users@vger.kernel.org Link: https://patch.msgid.link/20251209041600.963586-1-thaumy.love@gmail.com Signed-off-by: Sasha Levin --- kernel/events/core.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/kernel/events/core.c b/kernel/events/core.c index 2c35acc2722b0..413b88a4e00fb 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -2316,8 +2316,6 @@ static void perf_group_detach(struct perf_event *event) perf_event__header_size(leader); } -static void sync_child_event(struct perf_event *child_event); - static void perf_child_detach(struct perf_event *event) { struct perf_event *parent_event = event->parent; @@ -2336,7 +2334,6 @@ static void perf_child_detach(struct perf_event *event) lockdep_assert_held(&parent_event->child_mutex); */ - sync_child_event(event); list_del_init(&event->child_list); } @@ -4587,6 +4584,7 @@ static void perf_event_enable_on_exec(struct perf_event_context *ctx) static void perf_remove_from_owner(struct perf_event *event); static void perf_event_exit_event(struct perf_event *event, struct perf_event_context *ctx, + struct task_struct *task, bool revoke); /* @@ -4614,7 +4612,7 @@ static void perf_event_remove_on_exec(struct perf_event_context *ctx) modified = true; - perf_event_exit_event(event, ctx, false); + perf_event_exit_event(event, ctx, ctx->task, false); } raw_spin_lock_irqsave(&ctx->lock, flags); @@ -12447,7 +12445,7 @@ static void __pmu_detach_event(struct pmu *pmu, struct perf_event *event, /* * De-schedule the event and mark it REVOKED. */ - perf_event_exit_event(event, ctx, true); + perf_event_exit_event(event, ctx, ctx->task, true); /* * All _free_event() bits that rely on event->pmu: @@ -14004,14 +14002,13 @@ void perf_pmu_migrate_context(struct pmu *pmu, int src_cpu, int dst_cpu) } EXPORT_SYMBOL_GPL(perf_pmu_migrate_context); -static void sync_child_event(struct perf_event *child_event) +static void sync_child_event(struct perf_event *child_event, + struct task_struct *task) { struct perf_event *parent_event = child_event->parent; u64 child_val; if (child_event->attr.inherit_stat) { - struct task_struct *task = child_event->ctx->task; - if (task && task != TASK_TOMBSTONE) perf_event_read_event(child_event, task); } @@ -14030,7 +14027,9 @@ static void sync_child_event(struct perf_event *child_event) static void perf_event_exit_event(struct perf_event *event, - struct perf_event_context *ctx, bool revoke) + struct perf_event_context *ctx, + struct task_struct *task, + bool revoke) { struct perf_event *parent_event = event->parent; unsigned long detach_flags = DETACH_EXIT; @@ -14053,6 +14052,9 @@ perf_event_exit_event(struct perf_event *event, mutex_lock(&parent_event->child_mutex); /* PERF_ATTACH_ITRACE might be set concurrently */ attach_state = READ_ONCE(event->attach_state); + + if (attach_state & PERF_ATTACH_CHILD) + sync_child_event(event, task); } if (revoke) @@ -14144,7 +14146,7 @@ static void perf_event_exit_task_context(struct task_struct *task, bool exit) perf_event_task(task, ctx, 0); list_for_each_entry_safe(child_event, next, &ctx->event_list, event_entry) - perf_event_exit_event(child_event, ctx, false); + perf_event_exit_event(child_event, ctx, exit ? task : NULL, false); mutex_unlock(&ctx->mutex); From efd65e2e2fd96f7aaa5cb07d79bbbfcfc80aa552 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 9 Dec 2025 09:54:16 +0300 Subject: [PATCH 0973/2333] irqchip/mchp-eic: Fix error code in mchp_eic_domain_alloc() [ Upstream commit 7dbc0d40d8347bd9de55c904f59ea44bcc8dedb7 ] If irq_domain_translate_twocell() sets "hwirq" to >= MCHP_EIC_NIRQ (2) then it results in an out of bounds access. The code checks for invalid values, but doesn't set the error code. Return -EINVAL in that case, instead of returning success. Fixes: 00fa3461c86d ("irqchip/mchp-eic: Add support for the Microchip EIC") Signed-off-by: Dan Carpenter Signed-off-by: Thomas Gleixner Reviewed-by: Claudiu Beznea Link: https://patch.msgid.link/aTfHmOz6IBpTIPU5@stanley.mountain Signed-off-by: Sasha Levin --- drivers/irqchip/irq-mchp-eic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/irqchip/irq-mchp-eic.c b/drivers/irqchip/irq-mchp-eic.c index b513a899c0853..979bb86929f8e 100644 --- a/drivers/irqchip/irq-mchp-eic.c +++ b/drivers/irqchip/irq-mchp-eic.c @@ -166,7 +166,7 @@ static int mchp_eic_domain_alloc(struct irq_domain *domain, unsigned int virq, ret = irq_domain_translate_twocell(domain, fwspec, &hwirq, &type); if (ret || hwirq >= MCHP_EIC_NIRQ) - return ret; + return ret ?: -EINVAL; switch (type) { case IRQ_TYPE_EDGE_RISING: From d0fab03390ae1b2f56f9592bc79442d5ecac0dd2 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Thu, 27 Nov 2025 15:47:23 +0100 Subject: [PATCH 0974/2333] cpu: Make atomic hotplug callbacks run with interrupts disabled on UP [ Upstream commit c94291914b200e10c72cef23c8e4c67eb4fdbcd9 ] On SMP systems the CPU hotplug callbacks in the "starting" range are invoked while the CPU is brought up and interrupts are still disabled. Callbacks which are added later are invoked via the hotplug-thread on the target CPU and interrupts are explicitly disabled. In the UP case callbacks which are added later are invoked directly without the thread indirection. This is in principle okay since there is just one CPU but those callbacks are invoked with interrupt disabled code. That's incorrect as those callbacks assume interrupt disabled context. Disable interrupts before invoking the callbacks on UP if the state is atomic and interrupts are expected to be disabled. The "save" part is required because this is also invoked early in the boot process while interrupts are disabled and must not be enabled prematurely. Fixes: 06ddd17521bf1 ("sched/smp: Always define is_percpu_thread() and scheduler_ipi()") Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Thomas Gleixner Link: https://patch.msgid.link/20251127144723.ev9DuXXR@linutronix.de Signed-off-by: Sasha Levin --- kernel/cpu.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/kernel/cpu.c b/kernel/cpu.c index db9f6c539b28c..15000c7abc659 100644 --- a/kernel/cpu.c +++ b/kernel/cpu.c @@ -249,6 +249,14 @@ static int cpuhp_invoke_callback(unsigned int cpu, enum cpuhp_state state, return ret; } +/* + * The former STARTING/DYING states, ran with IRQs disabled and must not fail. + */ +static bool cpuhp_is_atomic_state(enum cpuhp_state state) +{ + return CPUHP_AP_IDLE_DEAD <= state && state < CPUHP_AP_ONLINE; +} + #ifdef CONFIG_SMP static bool cpuhp_is_ap_state(enum cpuhp_state state) { @@ -271,14 +279,6 @@ static inline void complete_ap_thread(struct cpuhp_cpu_state *st, bool bringup) complete(done); } -/* - * The former STARTING/DYING states, ran with IRQs disabled and must not fail. - */ -static bool cpuhp_is_atomic_state(enum cpuhp_state state) -{ - return CPUHP_AP_IDLE_DEAD <= state && state < CPUHP_AP_ONLINE; -} - /* Synchronization state management */ enum cpuhp_sync_state { SYNC_STATE_DEAD, @@ -2364,7 +2364,14 @@ static int cpuhp_issue_call(int cpu, enum cpuhp_state state, bool bringup, else ret = cpuhp_invoke_callback(cpu, state, bringup, node, NULL); #else - ret = cpuhp_invoke_callback(cpu, state, bringup, node, NULL); + if (cpuhp_is_atomic_state(state)) { + guard(irqsave)(); + ret = cpuhp_invoke_callback(cpu, state, bringup, node, NULL); + /* STARTING/DYING must not fail! */ + WARN_ON_ONCE(ret); + } else { + ret = cpuhp_invoke_callback(cpu, state, bringup, node, NULL); + } #endif BUG_ON(ret && !bringup); return ret; From f2091f479f5bd27e9b425d251e869f2a7580b1fa Mon Sep 17 00:00:00 2001 From: Dmitry Antipov Date: Fri, 5 Dec 2025 09:51:59 +0300 Subject: [PATCH 0975/2333] ocfs2: fix memory leak in ocfs2_merge_rec_left() [ Upstream commit 2214ec4bf89d0fd27717322d3983a2f3b469c7f3 ] In 'ocfs2_merge_rec_left()', do not reset 'left_path' to NULL after move, thus allowing 'ocfs2_free_path()' to free it before return. Link: https://lkml.kernel.org/r/20251205065159.392749-1-dmantipov@yandex.ru Fixes: 677b975282e4 ("ocfs2: Add support for cross extent block") Signed-off-by: Dmitry Antipov Reported-by: syzbot+cfc7cab3bb6eaa7c4de2@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=cfc7cab3bb6eaa7c4de2 Reviewed-by: Heming Zhao Acked-by: Joseph Qi Cc: Mark Fasheh Cc: Joel Becker Cc: Junxiao Bi Cc: Changwei Ge Cc: Jun Piao Signed-off-by: Andrew Morton Signed-off-by: Sasha Levin --- fs/ocfs2/alloc.c | 1 - 1 file changed, 1 deletion(-) diff --git a/fs/ocfs2/alloc.c b/fs/ocfs2/alloc.c index 162711cc5b201..a0ced11e0c24a 100644 --- a/fs/ocfs2/alloc.c +++ b/fs/ocfs2/alloc.c @@ -3654,7 +3654,6 @@ static int ocfs2_merge_rec_left(struct ocfs2_path *right_path, * So we use the new rightmost path. */ ocfs2_mv_path(right_path, left_path); - left_path = NULL; } else ocfs2_complete_edge_insert(handle, left_path, right_path, subtree_index); From 67d5a5e20259414b5ad6ba8bdf1aff8e80ca9c49 Mon Sep 17 00:00:00 2001 From: Evan Li Date: Fri, 12 Dec 2025 16:49:43 +0800 Subject: [PATCH 0976/2333] perf/x86/intel: Fix NULL event dereference crash in handle_pmi_common() [ Upstream commit 9415f749d34b926b9e4853da1462f4d941f89a0d ] handle_pmi_common() may observe an active bit set in cpuc->active_mask while the corresponding cpuc->events[] entry has already been cleared, which leads to a NULL pointer dereference. This can happen when interrupt throttling stops all events in a group while PEBS processing is still in progress. perf_event_overflow() can trigger perf_event_throttle_group(), which stops the group and clears the cpuc->events[] entry, but the active bit may still be set when handle_pmi_common() iterates over the events. The following recent fix: 7e772a93eb61 ("perf/x86: Fix NULL event access and potential PEBS record loss") moved the cpuc->events[] clearing from x86_pmu_stop() to x86_pmu_del() and relied on cpuc->active_mask/pebs_enabled checks. However, handle_pmi_common() can still encounter a NULL cpuc->events[] entry despite the active bit being set. Add an explicit NULL check on the event pointer before using it, to cover this legitimate scenario and avoid the NULL dereference crash. Fixes: 7e772a93eb61 ("perf/x86: Fix NULL event access and potential PEBS record loss") Reported-by: kitta Co-developed-by: kitta Signed-off-by: Evan Li Signed-off-by: Ingo Molnar Link: https://patch.msgid.link/20251212084943.2124787-1-evan.li@linux.alibaba.com Closes: https://bugzilla.kernel.org/show_bug.cgi?id=220855 Signed-off-by: Sasha Levin --- arch/x86/events/intel/core.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c index 9b824ed6fc1de..32d551f2646a7 100644 --- a/arch/x86/events/intel/core.c +++ b/arch/x86/events/intel/core.c @@ -3249,6 +3249,9 @@ static int handle_pmi_common(struct pt_regs *regs, u64 status) if (!test_bit(bit, cpuc->active_mask)) continue; + /* Event may have already been cleared: */ + if (!event) + continue; /* * There may be unprocessed PEBS records in the PEBS buffer, From a980fec3d5eba63a9b40f2ae3a7807ffc447cd6a Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 14 Aug 2025 09:52:54 -0700 Subject: [PATCH 0977/2333] efi/cper: Add a new helper function to print bitmasks [ Upstream commit a976d790f49499ccaa0f991788ad8ebf92e7fd5c ] Add a helper function to print a string with names associated to each bit field. A typical example is: const char * const bits[] = { "bit 3 name", "bit 4 name", "bit 5 name", }; char str[120]; unsigned int bitmask = BIT(3) | BIT(5); #define MASK GENMASK(5,3) cper_bits_to_str(str, sizeof(str), FIELD_GET(MASK, bitmask), bits, ARRAY_SIZE(bits)); The above code fills string "str" with "bit 3 name|bit 5 name". Reviewed-by: Jonathan Cameron Signed-off-by: Mauro Carvalho Chehab Acked-by: Borislav Petkov (AMD) Signed-off-by: Ard Biesheuvel Signed-off-by: Sasha Levin --- drivers/firmware/efi/cper.c | 60 +++++++++++++++++++++++++++++++++++++ include/linux/cper.h | 2 ++ 2 files changed, 62 insertions(+) diff --git a/drivers/firmware/efi/cper.c b/drivers/firmware/efi/cper.c index 928409199a1a4..79ba688a64f8d 100644 --- a/drivers/firmware/efi/cper.c +++ b/drivers/firmware/efi/cper.c @@ -12,6 +12,7 @@ * Specification version 2.4. */ +#include #include #include #include @@ -106,6 +107,65 @@ void cper_print_bits(const char *pfx, unsigned int bits, printk("%s\n", buf); } +/** + * cper_bits_to_str - return a string for set bits + * @buf: buffer to store the output string + * @buf_size: size of the output string buffer + * @bits: bit mask + * @strs: string array, indexed by bit position + * @strs_size: size of the string array: @strs + * + * Add to @buf the bitmask in hexadecimal. Then, for each set bit in @bits, + * add the corresponding string describing the bit in @strs to @buf. + * + * A typical example is:: + * + * const char * const bits[] = { + * "bit 3 name", + * "bit 4 name", + * "bit 5 name", + * }; + * char str[120]; + * unsigned int bitmask = BIT(3) | BIT(5); + * #define MASK GENMASK(5,3) + * + * cper_bits_to_str(str, sizeof(str), FIELD_GET(MASK, bitmask), + * bits, ARRAY_SIZE(bits)); + * + * The above code fills the string ``str`` with ``bit 3 name|bit 5 name``. + * + * Return: number of bytes stored or an error code if lower than zero. + */ +int cper_bits_to_str(char *buf, int buf_size, unsigned long bits, + const char * const strs[], unsigned int strs_size) +{ + int len = buf_size; + char *str = buf; + int i, size; + + *buf = '\0'; + + for_each_set_bit(i, &bits, strs_size) { + if (!(bits & BIT_ULL(i))) + continue; + + if (*buf && len > 0) { + *str = '|'; + len--; + str++; + } + + size = strscpy(str, strs[i], len); + if (size < 0) + return size; + + len -= size; + str += size; + } + return len - buf_size; +} +EXPORT_SYMBOL_GPL(cper_bits_to_str); + static const char * const proc_type_strs[] = { "IA32/X64", "IA64", diff --git a/include/linux/cper.h b/include/linux/cper.h index 0ed60a91eca9d..58f40477c824e 100644 --- a/include/linux/cper.h +++ b/include/linux/cper.h @@ -588,6 +588,8 @@ const char *cper_mem_err_type_str(unsigned int); const char *cper_mem_err_status_str(u64 status); void cper_print_bits(const char *prefix, unsigned int bits, const char * const strs[], unsigned int strs_size); +int cper_bits_to_str(char *buf, int buf_size, unsigned long bits, + const char * const strs[], unsigned int strs_size); void cper_mem_err_pack(const struct cper_sec_mem_err *, struct cper_mem_err_compact *); const char *cper_mem_err_unpack(struct trace_seq *, From 742082e59fcc7361e98686f76055115c29702521 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 14 Aug 2025 09:52:53 -0700 Subject: [PATCH 0978/2333] efi/cper: Adjust infopfx size to accept an extra space MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 8ad2c72e21efb3dc76c5b14089fa7984cdd87898 ] Compiling with W=1 with werror enabled produces an error: drivers/firmware/efi/cper-arm.c: In function ‘cper_print_proc_arm’: drivers/firmware/efi/cper-arm.c:298:64: error: ‘snprintf’ output may be truncated before the last format character [-Werror=format-truncation=] 298 | snprintf(infopfx, sizeof(infopfx), "%s ", newpfx); | ^ drivers/firmware/efi/cper-arm.c:298:25: note: ‘snprintf’ output between 2 and 65 bytes into a destination of size 64 298 | snprintf(infopfx, sizeof(infopfx), "%s ", newpfx); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ As the logic there adds an space at the end of infopx buffer. Add an extra space to avoid such warning. Signed-off-by: Mauro Carvalho Chehab Reviewed-by: Jonathan Cameron Acked-by: Borislav Petkov (AMD) Signed-off-by: Ard Biesheuvel Signed-off-by: Sasha Levin --- drivers/firmware/efi/cper-arm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/firmware/efi/cper-arm.c b/drivers/firmware/efi/cper-arm.c index f0a63d09d3c49..6ff781e47147c 100644 --- a/drivers/firmware/efi/cper-arm.c +++ b/drivers/firmware/efi/cper-arm.c @@ -240,7 +240,7 @@ void cper_print_proc_arm(const char *pfx, int i, len, max_ctx_type; struct cper_arm_err_info *err_info; struct cper_arm_ctx_info *ctx_info; - char newpfx[64], infopfx[64]; + char newpfx[64], infopfx[ARRAY_SIZE(newpfx) + 1]; printk("%sMIDR: 0x%016llx\n", pfx, proc->midr); From 1f2f0ff3cacb12fad1c9829b2f31cac9095c696b Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 14 Aug 2025 09:52:55 -0700 Subject: [PATCH 0979/2333] efi/cper: align ARM CPER type with UEFI 2.9A/2.10 specs [ Upstream commit 96b010536ee020e716d28d9b359a4bcd18800aeb ] Up to UEFI spec 2.9, the type byte of CPER struct for ARM processor was defined simply as: Type at byte offset 4: - Cache error - TLB Error - Bus Error - Micro-architectural Error All other values are reserved Yet, there was no information about how this would be encoded. Spec 2.9A errata corrected it by defining: - Bit 1 - Cache Error - Bit 2 - TLB Error - Bit 3 - Bus Error - Bit 4 - Micro-architectural Error All other values are reserved That actually aligns with the values already defined on older versions at N.2.4.1. Generic Processor Error Section. Spec 2.10 also preserve the same encoding as 2.9A. Adjust CPER and GHES handling code for both generic and ARM processors to properly handle UEFI 2.9A and 2.10 encoding. Link: https://uefi.org/specs/UEFI/2.10/Apx_N_Common_Platform_Error_Record.html#arm-processor-error-information Signed-off-by: Mauro Carvalho Chehab Reviewed-by: Jonathan Cameron Acked-by: Borislav Petkov (AMD) Signed-off-by: Ard Biesheuvel Signed-off-by: Sasha Levin --- drivers/acpi/apei/ghes.c | 16 +++++++---- drivers/firmware/efi/cper-arm.c | 50 ++++++++++++++++----------------- include/linux/cper.h | 10 +++---- 3 files changed, 39 insertions(+), 37 deletions(-) diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c index 7d2466b515046..56107aa002744 100644 --- a/drivers/acpi/apei/ghes.c +++ b/drivers/acpi/apei/ghes.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -556,6 +557,7 @@ static bool ghes_handle_arm_hw_error(struct acpi_hest_generic_data *gdata, { struct cper_sec_proc_arm *err = acpi_hest_get_payload(gdata); int flags = sync ? MF_ACTION_REQUIRED : 0; + char error_type[120]; bool queued = false; int sec_sev, i; char *p; @@ -568,9 +570,8 @@ static bool ghes_handle_arm_hw_error(struct acpi_hest_generic_data *gdata, p = (char *)(err + 1); for (i = 0; i < err->err_info_num; i++) { struct cper_arm_err_info *err_info = (struct cper_arm_err_info *)p; - bool is_cache = (err_info->type == CPER_ARM_CACHE_ERROR); + bool is_cache = err_info->type & CPER_ARM_CACHE_ERROR; bool has_pa = (err_info->validation_bits & CPER_ARM_INFO_VALID_PHYSICAL_ADDR); - const char *error_type = "unknown error"; /* * The field (err_info->error_info & BIT(26)) is fixed to set to @@ -584,12 +585,15 @@ static bool ghes_handle_arm_hw_error(struct acpi_hest_generic_data *gdata, continue; } - if (err_info->type < ARRAY_SIZE(cper_proc_error_type_strs)) - error_type = cper_proc_error_type_strs[err_info->type]; + cper_bits_to_str(error_type, sizeof(error_type), + FIELD_GET(CPER_ARM_ERR_TYPE_MASK, err_info->type), + cper_proc_error_type_strs, + ARRAY_SIZE(cper_proc_error_type_strs)); pr_warn_ratelimited(FW_WARN GHES_PFX - "Unhandled processor error type: %s\n", - error_type); + "Unhandled processor error type 0x%02x: %s%s\n", + err_info->type, error_type, + (err_info->type & ~CPER_ARM_ERR_TYPE_MASK) ? " with reserved bit(s)" : ""); p += err_info->length; } diff --git a/drivers/firmware/efi/cper-arm.c b/drivers/firmware/efi/cper-arm.c index 6ff781e47147c..76542a53e2027 100644 --- a/drivers/firmware/efi/cper-arm.c +++ b/drivers/firmware/efi/cper-arm.c @@ -93,15 +93,11 @@ static void cper_print_arm_err_info(const char *pfx, u32 type, bool proc_context_corrupt, corrected, precise_pc, restartable_pc; bool time_out, access_mode; - /* If the type is unknown, bail. */ - if (type > CPER_ARM_MAX_TYPE) - return; - /* * Vendor type errors have error information values that are vendor * specific. */ - if (type == CPER_ARM_VENDOR_ERROR) + if (type & CPER_ARM_VENDOR_ERROR) return; if (error_info & CPER_ARM_ERR_VALID_TRANSACTION_TYPE) { @@ -116,43 +112,38 @@ static void cper_print_arm_err_info(const char *pfx, u32 type, if (error_info & CPER_ARM_ERR_VALID_OPERATION_TYPE) { op_type = ((error_info >> CPER_ARM_ERR_OPERATION_SHIFT) & CPER_ARM_ERR_OPERATION_MASK); - switch (type) { - case CPER_ARM_CACHE_ERROR: + if (type & CPER_ARM_CACHE_ERROR) { if (op_type < ARRAY_SIZE(arm_cache_err_op_strs)) { - printk("%soperation type: %s\n", pfx, + printk("%scache error, operation type: %s\n", pfx, arm_cache_err_op_strs[op_type]); } - break; - case CPER_ARM_TLB_ERROR: + } + if (type & CPER_ARM_TLB_ERROR) { if (op_type < ARRAY_SIZE(arm_tlb_err_op_strs)) { - printk("%soperation type: %s\n", pfx, + printk("%sTLB error, operation type: %s\n", pfx, arm_tlb_err_op_strs[op_type]); } - break; - case CPER_ARM_BUS_ERROR: + } + if (type & CPER_ARM_BUS_ERROR) { if (op_type < ARRAY_SIZE(arm_bus_err_op_strs)) { - printk("%soperation type: %s\n", pfx, + printk("%sbus error, operation type: %s\n", pfx, arm_bus_err_op_strs[op_type]); } - break; } } if (error_info & CPER_ARM_ERR_VALID_LEVEL) { level = ((error_info >> CPER_ARM_ERR_LEVEL_SHIFT) & CPER_ARM_ERR_LEVEL_MASK); - switch (type) { - case CPER_ARM_CACHE_ERROR: + if (type & CPER_ARM_CACHE_ERROR) printk("%scache level: %d\n", pfx, level); - break; - case CPER_ARM_TLB_ERROR: + + if (type & CPER_ARM_TLB_ERROR) printk("%sTLB level: %d\n", pfx, level); - break; - case CPER_ARM_BUS_ERROR: + + if (type & CPER_ARM_BUS_ERROR) printk("%saffinity level at which the bus error occurred: %d\n", pfx, level); - break; - } } if (error_info & CPER_ARM_ERR_VALID_PROC_CONTEXT_CORRUPT) { @@ -241,6 +232,7 @@ void cper_print_proc_arm(const char *pfx, struct cper_arm_err_info *err_info; struct cper_arm_ctx_info *ctx_info; char newpfx[64], infopfx[ARRAY_SIZE(newpfx) + 1]; + char error_type[120]; printk("%sMIDR: 0x%016llx\n", pfx, proc->midr); @@ -289,9 +281,15 @@ void cper_print_proc_arm(const char *pfx, newpfx); } - printk("%serror_type: %d, %s\n", newpfx, err_info->type, - err_info->type < ARRAY_SIZE(cper_proc_error_type_strs) ? - cper_proc_error_type_strs[err_info->type] : "unknown"); + cper_bits_to_str(error_type, sizeof(error_type), + FIELD_GET(CPER_ARM_ERR_TYPE_MASK, err_info->type), + cper_proc_error_type_strs, + ARRAY_SIZE(cper_proc_error_type_strs)); + + printk("%serror_type: 0x%02x: %s%s\n", newpfx, err_info->type, + error_type, + (err_info->type & ~CPER_ARM_ERR_TYPE_MASK) ? " with reserved bit(s)" : ""); + if (err_info->validation_bits & CPER_ARM_INFO_VALID_ERR_INFO) { printk("%serror_info: 0x%016llx\n", newpfx, err_info->error_info); diff --git a/include/linux/cper.h b/include/linux/cper.h index 58f40477c824e..5b1236d8c65bb 100644 --- a/include/linux/cper.h +++ b/include/linux/cper.h @@ -297,11 +297,11 @@ enum { #define CPER_ARM_INFO_FLAGS_PROPAGATED BIT(2) #define CPER_ARM_INFO_FLAGS_OVERFLOW BIT(3) -#define CPER_ARM_CACHE_ERROR 0 -#define CPER_ARM_TLB_ERROR 1 -#define CPER_ARM_BUS_ERROR 2 -#define CPER_ARM_VENDOR_ERROR 3 -#define CPER_ARM_MAX_TYPE CPER_ARM_VENDOR_ERROR +#define CPER_ARM_ERR_TYPE_MASK GENMASK(4,1) +#define CPER_ARM_CACHE_ERROR BIT(1) +#define CPER_ARM_TLB_ERROR BIT(2) +#define CPER_ARM_BUS_ERROR BIT(3) +#define CPER_ARM_VENDOR_ERROR BIT(4) #define CPER_ARM_ERR_VALID_TRANSACTION_TYPE BIT(0) #define CPER_ARM_ERR_VALID_OPERATION_TYPE BIT(1) From 93193a1a007750c864dfbbac732e31c7cc086872 Mon Sep 17 00:00:00 2001 From: Haotien Hsu Date: Thu, 27 Nov 2025 11:35:40 +0800 Subject: [PATCH 0980/2333] usb: gadget: tegra-xudc: Always reinitialize data toggle when clear halt commit 2585973c7f9ee31d21e5848c996fab2521fd383d upstream. The driver previously skipped handling ClearFeature(ENDPOINT_HALT) when the endpoint was already not halted. This prevented the controller from resetting the data sequence number and reinitializing the endpoint state. According to USB 3.2 specification Rev. 1.1, section 9.4.5, ClearFeature(ENDPOINT_HALT) must always reset the data sequence and set the stream state machine to Disabled, regardless of whether the endpoint was halted. Remove the early return so that ClearFeature(ENDPOINT_HALT) always resets the endpoint sequence state as required by the specification. Fixes: 49db427232fe ("usb: gadget: Add UDC driver for tegra XUSB device mode controller") Cc: stable Signed-off-by: Haotien Hsu Signed-off-by: Wayne Chang Link: https://patch.msgid.link/20251127033540.2287517-1-waynec@nvidia.com Signed-off-by: Greg Kroah-Hartman Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/udc/tegra-xudc.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/usb/gadget/udc/tegra-xudc.c b/drivers/usb/gadget/udc/tegra-xudc.c index 0c38fc37b6e66..9d2007f448c04 100644 --- a/drivers/usb/gadget/udc/tegra-xudc.c +++ b/drivers/usb/gadget/udc/tegra-xudc.c @@ -1558,12 +1558,6 @@ static int __tegra_xudc_ep_set_halt(struct tegra_xudc_ep *ep, bool halt) return -ENOTSUPP; } - if (!!(xudc_readl(xudc, EP_HALT) & BIT(ep->index)) == halt) { - dev_dbg(xudc->dev, "EP %u already %s\n", ep->index, - halt ? "halted" : "not halted"); - return 0; - } - if (halt) { ep_halt(xudc, ep->index); } else { From a902fc01813a412f60e4b27caa10803f7deb7369 Mon Sep 17 00:00:00 2001 From: Duoming Zhou Date: Tue, 25 Nov 2025 18:36:26 +0800 Subject: [PATCH 0981/2333] usb: typec: ucsi: fix probe failure in gaokun_ucsi_probe() commit 6b120ef99fbcba9e413783561f8cc160719db589 upstream. The gaokun_ucsi_probe() uses ucsi_create() to allocate a UCSI instance. The ucsi_create() validates whether ops->poll_cci is defined, and if not, it directly returns -EINVAL. However, the gaokun_ucsi_ops structure does not define the poll_cci, causing ucsi_create() always fail with -EINVAL. This issue can be observed in the kernel log with the following error: ucsi_huawei_gaokun.ucsi huawei_gaokun_ec.ucsi.0: probe with driver ucsi_huawei_gaokun.ucsi failed with error -22 Fix the issue by adding the missing poll_cci callback to gaokun_ucsi_ops. Fixes: 00327d7f2c8c ("usb: typec: ucsi: add Huawei Matebook E Go ucsi driver") Cc: stable Signed-off-by: Duoming Zhou Reviewed-by: Heikki Krogerus Reviewed-by: Pengyu Luo Link: https://patch.msgid.link/4d077d6439d728be68646bb8c8678436a3a0885e.1764065838.git.duoming@zju.edu.cn Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/ucsi/ucsi_huawei_gaokun.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/typec/ucsi/ucsi_huawei_gaokun.c b/drivers/usb/typec/ucsi/ucsi_huawei_gaokun.c index 7b5222081bbb5..8401ab414bd92 100644 --- a/drivers/usb/typec/ucsi/ucsi_huawei_gaokun.c +++ b/drivers/usb/typec/ucsi/ucsi_huawei_gaokun.c @@ -196,6 +196,7 @@ static void gaokun_ucsi_connector_status(struct ucsi_connector *con) const struct ucsi_operations gaokun_ucsi_ops = { .read_version = gaokun_ucsi_read_version, .read_cci = gaokun_ucsi_read_cci, + .poll_cci = gaokun_ucsi_read_cci, .read_message_in = gaokun_ucsi_read_message_in, .sync_control = ucsi_sync_control_common, .async_control = gaokun_ucsi_async_control, From 6507f1810d3c8f758ee173b56a7d626256671819 Mon Sep 17 00:00:00 2001 From: Diogo Ivo Date: Fri, 21 Nov 2025 18:16:36 +0000 Subject: [PATCH 0982/2333] usb: phy: Initialize struct usb_phy list_head commit c69ff68b097b0f53333114f1b2c3dc128f389596 upstream. As part of the registration of a new 'struct usb_phy' with the USB PHY core via either usb_add_phy(struct usb_phy *x, ...) or usb_add_phy_dev(struct usb_phy *x) these functions call list_add_tail(&x->head, phy_list) in order for the new instance x to be stored in phy_list, a static list kept internally by the core. After 7d21114dc6a2 ("usb: phy: Introduce one extcon device into usb phy") when executing either of the registration functions above it is possible that usb_add_extcon() fails, leading to either function returning before the call to list_add_tail(), leaving x->head uninitialized. Then, when a driver tries to undo the failed registration by calling usb_remove_phy(struct usb_phy *x) there will be an unconditional call to list_del(&x->head) acting on an uninitialized variable, and thus a possible NULL pointer dereference. Fix this by initializing x->head before usb_add_extcon() has a chance to fail. Note that this was not needed before 7d21114dc6a2 since list_add_phy() was executed unconditionally and it guaranteed that x->head was initialized. Fixes: 7d21114dc6a2 ("usb: phy: Introduce one extcon device into usb phy") Cc: stable Signed-off-by: Diogo Ivo Link: https://patch.msgid.link/20251121-diogo-smaug_typec-v2-1-5c37c1169d57@tecnico.ulisboa.pt Signed-off-by: Greg Kroah-Hartman --- drivers/usb/phy/phy.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/usb/phy/phy.c b/drivers/usb/phy/phy.c index e1435bc596622..5a9b9353f343d 100644 --- a/drivers/usb/phy/phy.c +++ b/drivers/usb/phy/phy.c @@ -646,6 +646,8 @@ int usb_add_phy(struct usb_phy *x, enum usb_phy_type type) return -EINVAL; } + INIT_LIST_HEAD(&x->head); + usb_charger_init(x); ret = usb_add_extcon(x); if (ret) @@ -696,6 +698,8 @@ int usb_add_phy_dev(struct usb_phy *x) return -EINVAL; } + INIT_LIST_HEAD(&x->head); + usb_charger_init(x); ret = usb_add_extcon(x); if (ret) From a880ef71a1c8da266b88491213c37893e2126489 Mon Sep 17 00:00:00 2001 From: Duoming Zhou Date: Tue, 25 Nov 2025 18:36:27 +0800 Subject: [PATCH 0983/2333] usb: typec: ucsi: fix use-after-free caused by uec->work commit 2b7a0f47aaf2439d517ba0a6b29c66a535302154 upstream. The delayed work uec->work is scheduled in gaokun_ucsi_probe() but never properly canceled in gaokun_ucsi_remove(). This creates use-after-free scenarios where the ucsi and gaokun_ucsi structure are freed after ucsi_destroy() completes execution, while the gaokun_ucsi_register_worker() might be either currently executing or still pending in the work queue. The already-freed gaokun_ucsi or ucsi structure may then be accessed. Furthermore, the race window is 3 seconds, which is sufficiently long to make this bug easily reproducible. The following is the trace captured by KASAN: ================================================================== BUG: KASAN: slab-use-after-free in __run_timers+0x5ec/0x630 Write of size 8 at addr ffff00000ec28cc8 by task swapper/0/0 ... Call trace: show_stack+0x18/0x24 (C) dump_stack_lvl+0x78/0x90 print_report+0x114/0x580 kasan_report+0xa4/0xf0 __asan_report_store8_noabort+0x20/0x2c __run_timers+0x5ec/0x630 run_timer_softirq+0xe8/0x1cc handle_softirqs+0x294/0x720 __do_softirq+0x14/0x20 ____do_softirq+0x10/0x1c call_on_irq_stack+0x30/0x48 do_softirq_own_stack+0x1c/0x28 __irq_exit_rcu+0x27c/0x364 irq_exit_rcu+0x10/0x1c el1_interrupt+0x40/0x60 el1h_64_irq_handler+0x18/0x24 el1h_64_irq+0x6c/0x70 arch_local_irq_enable+0x4/0x8 (P) do_idle+0x334/0x458 cpu_startup_entry+0x60/0x70 rest_init+0x158/0x174 start_kernel+0x2f8/0x394 __primary_switched+0x8c/0x94 Allocated by task 72 on cpu 0 at 27.510341s: kasan_save_stack+0x2c/0x54 kasan_save_track+0x24/0x5c kasan_save_alloc_info+0x40/0x54 __kasan_kmalloc+0xa0/0xb8 __kmalloc_node_track_caller_noprof+0x1c0/0x588 devm_kmalloc+0x7c/0x1c8 gaokun_ucsi_probe+0xa0/0x840 auxiliary_bus_probe+0x94/0xf8 really_probe+0x17c/0x5b8 __driver_probe_device+0x158/0x2c4 driver_probe_device+0x10c/0x264 __device_attach_driver+0x168/0x2d0 bus_for_each_drv+0x100/0x188 __device_attach+0x174/0x368 device_initial_probe+0x14/0x20 bus_probe_device+0x120/0x150 device_add+0xb3c/0x10fc __auxiliary_device_add+0x88/0x130 ... Freed by task 73 on cpu 1 at 28.910627s: kasan_save_stack+0x2c/0x54 kasan_save_track+0x24/0x5c __kasan_save_free_info+0x4c/0x74 __kasan_slab_free+0x60/0x8c kfree+0xd4/0x410 devres_release_all+0x140/0x1f0 device_unbind_cleanup+0x20/0x190 device_release_driver_internal+0x344/0x460 device_release_driver+0x18/0x24 bus_remove_device+0x198/0x274 device_del+0x310/0xa84 ... The buggy address belongs to the object at ffff00000ec28c00 which belongs to the cache kmalloc-512 of size 512 The buggy address is located 200 bytes inside of freed 512-byte region The buggy address belongs to the physical page: page: refcount:0 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x4ec28 head: order:2 mapcount:0 entire_mapcount:0 nr_pages_mapped:0 pincount:0 flags: 0x3fffe0000000040(head|node=0|zone=0|lastcpupid=0x1ffff) page_type: f5(slab) raw: 03fffe0000000040 ffff000008801c80 dead000000000122 0000000000000000 raw: 0000000000000000 0000000080100010 00000000f5000000 0000000000000000 head: 03fffe0000000040 ffff000008801c80 dead000000000122 0000000000000000 head: 0000000000000000 0000000080100010 00000000f5000000 0000000000000000 head: 03fffe0000000002 fffffdffc03b0a01 00000000ffffffff 00000000ffffffff head: ffffffffffffffff 0000000000000000 00000000ffffffff 0000000000000004 page dumped because: kasan: bad access detected Memory state around the buggy address: ffff00000ec28b80: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc ffff00000ec28c00: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb >ffff00000ec28c80: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb ^ ffff00000ec28d00: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb ffff00000ec28d80: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb ================================================================== Add disable_delayed_work_sync() in gaokun_ucsi_remove() to ensure that uec->work is properly canceled and prevented from executing after the ucsi and gaokun_ucsi structure have been deallocated. Fixes: 00327d7f2c8c ("usb: typec: ucsi: add Huawei Matebook E Go ucsi driver") Cc: stable Signed-off-by: Duoming Zhou Reviewed-by: Heikki Krogerus Link: https://patch.msgid.link/cc31e12ef9ffbf86676585b02233165fd33f0d8e.1764065838.git.duoming@zju.edu.cn Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/ucsi/ucsi_huawei_gaokun.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/typec/ucsi/ucsi_huawei_gaokun.c b/drivers/usb/typec/ucsi/ucsi_huawei_gaokun.c index 8401ab414bd92..c5965656babad 100644 --- a/drivers/usb/typec/ucsi/ucsi_huawei_gaokun.c +++ b/drivers/usb/typec/ucsi/ucsi_huawei_gaokun.c @@ -503,6 +503,7 @@ static void gaokun_ucsi_remove(struct auxiliary_device *adev) { struct gaokun_ucsi *uec = auxiliary_get_drvdata(adev); + disable_delayed_work_sync(&uec->work); gaokun_ec_unregister_notify(uec->ec, &uec->nb); ucsi_unregister(uec->ucsi); ucsi_destroy(uec->ucsi); From d6d0caff738fafc20eb242433685b398f9158314 Mon Sep 17 00:00:00 2001 From: Sven Peter Date: Wed, 15 Oct 2025 15:40:42 +0000 Subject: [PATCH 0984/2333] usb: dwc3: dwc3_power_off_all_roothub_ports: Use ioremap_np when required commit 5ed9cc71432a8adf3c42223c935f714aac29901b upstream. On Apple Silicon machines we can't use ioremap() / Device-nGnRE to map most regions but must use ioremap_np() / Device-nGnRnE whenever IORESOURCE_MEM_NONPOSTED is set. Make sure this is also done inside dwc3_power_off_all_roothub_ports to prevent SErrors. Fixes: 2d2a3349521d ("usb: dwc3: Add workaround for host mode VBUS glitch when boot") Cc: stable@kernel.org Acked-by: Thinh Nguyen Reviewed-by: Neal Gompa Signed-off-by: Sven Peter Link: https://patch.msgid.link/20251015-b4-aplpe-dwc3-v2-2-cbd65a2d511a@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/host.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c index 1c513bf8002ec..e77fd86d09cf0 100644 --- a/drivers/usb/dwc3/host.c +++ b/drivers/usb/dwc3/host.c @@ -37,7 +37,10 @@ static void dwc3_power_off_all_roothub_ports(struct dwc3 *dwc) /* xhci regs are not mapped yet, do it temporarily here */ if (dwc->xhci_resources[0].start) { - xhci_regs = ioremap(dwc->xhci_resources[0].start, DWC3_XHCI_REGS_END); + if (dwc->xhci_resources[0].flags & IORESOURCE_MEM_NONPOSTED) + xhci_regs = ioremap_np(dwc->xhci_resources[0].start, DWC3_XHCI_REGS_END); + else + xhci_regs = ioremap(dwc->xhci_resources[0].start, DWC3_XHCI_REGS_END); if (!xhci_regs) { dev_err(dwc->dev, "Failed to ioremap xhci_regs\n"); return; From 1e1b3207a53e50d5a66289fffc1f7d52cd9c50f9 Mon Sep 17 00:00:00 2001 From: Junrui Luo Date: Fri, 28 Nov 2025 12:06:31 +0800 Subject: [PATCH 0985/2333] ALSA: dice: fix buffer overflow in detect_stream_formats() commit 324f3e03e8a85931ce0880654e3c3eb38b0f0bba upstream. The function detect_stream_formats() reads the stream_count value directly from a FireWire device without validating it. This can lead to out-of-bounds writes when a malicious device provides a stream_count value greater than MAX_STREAMS. Fix by applying the same validation to both TX and RX stream counts in detect_stream_formats(). Reported-by: Yuhao Jiang Reported-by: Junrui Luo Fixes: 58579c056c1c ("ALSA: dice: use extended protocol to detect available stream formats") Cc: stable@vger.kernel.org Reviewed-by: Takashi Sakamoto Signed-off-by: Junrui Luo Link: https://patch.msgid.link/SYBPR01MB7881B043FC68B4C0DA40B73DAFDCA@SYBPR01MB7881.ausprd01.prod.outlook.com Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/firewire/dice/dice-extension.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/firewire/dice/dice-extension.c b/sound/firewire/dice/dice-extension.c index 02f4a8318e38e..48bfb3ad93ce5 100644 --- a/sound/firewire/dice/dice-extension.c +++ b/sound/firewire/dice/dice-extension.c @@ -116,7 +116,7 @@ static int detect_stream_formats(struct snd_dice *dice, u64 section_addr) break; base_offset += EXT_APP_STREAM_ENTRIES; - stream_count = be32_to_cpu(reg[0]); + stream_count = min_t(unsigned int, be32_to_cpu(reg[0]), MAX_STREAMS); err = read_stream_entries(dice, section_addr, base_offset, stream_count, mode, dice->tx_pcm_chs, @@ -125,7 +125,7 @@ static int detect_stream_formats(struct snd_dice *dice, u64 section_addr) break; base_offset += stream_count * EXT_APP_STREAM_ENTRY_SIZE; - stream_count = be32_to_cpu(reg[1]); + stream_count = min_t(unsigned int, be32_to_cpu(reg[1]), MAX_STREAMS); err = read_stream_entries(dice, section_addr, base_offset, stream_count, mode, dice->rx_pcm_chs, From acacb5b7109acb83b6154b4654acdbec6aa5f54f Mon Sep 17 00:00:00 2001 From: Antheas Kapenekakis Date: Sun, 26 Oct 2025 20:16:35 +0100 Subject: [PATCH 0986/2333] ALSA: hda/realtek: Add match for ASUS Xbox Ally projects commit 18a4895370a79a3efb4a53ccd1efffef6c5b634e upstream. Bind the realtek codec to TAS2781 I2C audio amps on ASUS Xbox Ally projects. While these projects work without a quirk, adding it increases the output volume significantly. Cc: stable@vger.kernel.org # 6.17 Signed-off-by: Antheas Kapenekakis Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20251026191635.2447593-2-lkml@antheas.dev Signed-off-by: Greg Kroah-Hartman --- sound/hda/codecs/realtek/alc269.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/hda/codecs/realtek/alc269.c b/sound/hda/codecs/realtek/alc269.c index b45fcc9a3785e..a6d494dab5b6d 100644 --- a/sound/hda/codecs/realtek/alc269.c +++ b/sound/hda/codecs/realtek/alc269.c @@ -6736,6 +6736,8 @@ static const struct hda_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1043, 0x12f0, "ASUS X541UV", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1043, 0x1313, "Asus K42JZ", ALC269VB_FIXUP_ASUS_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1043, 0x1314, "ASUS GA605K", ALC285_FIXUP_ASUS_GA605K_HEADSET_MIC), + SND_PCI_QUIRK(0x1043, 0x1384, "ASUS RC73XA", ALC287_FIXUP_TXNW2781_I2C), + SND_PCI_QUIRK(0x1043, 0x1394, "ASUS RC73YA", ALC287_FIXUP_TXNW2781_I2C), SND_PCI_QUIRK(0x1043, 0x13b0, "ASUS Z550SA", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1043, 0x1427, "Asus Zenbook UX31E", ALC269VB_FIXUP_ASUS_ZENBOOK), SND_PCI_QUIRK(0x1043, 0x1433, "ASUS GX650PY/PZ/PV/PU/PYV/PZV/PIV/PVV", ALC285_FIXUP_ASUS_I2C_HEADSET_MIC), From 3646c928bb77c28bd79f8e1893d32db49230b657 Mon Sep 17 00:00:00 2001 From: Antheas Kapenekakis Date: Sun, 26 Oct 2025 20:16:34 +0100 Subject: [PATCH 0987/2333] ALSA: hda/tas2781: fix speaker id retrieval for multiple probes commit 945865a0ddf3e3950aea32e23e10d815ee9b21bc upstream. Currently, on ASUS projects, the TAS2781 codec attaches the speaker GPIO to the first tasdevice_priv instance using devm. This causes tas2781_read_acpi to fail on subsequent probes since the GPIO is already managed by the first device. This causes a failure on Xbox Ally X, because it has two amplifiers, and prevents us from quirking both the Xbox Ally and Xbox Ally X in the realtek codec driver. It is unnecessary to attach the GPIO to a device as it is static. Therefore, instead of attaching it and then reading it when loading the firmware, read its value directly in tas2781_read_acpi and store it in the private data structure. Then, make reading the value non-fatal so that ASUS projects that miss a speaker pin can still work, perhaps using fallback firmware. Fixes: 4e7035a75da9 ("ALSA: hda/tas2781: Add speaker id check for ASUS projects") Cc: stable@vger.kernel.org # 6.17 Signed-off-by: Antheas Kapenekakis Reviewed-by: Baojun Xu Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20251026191635.2447593-1-lkml@antheas.dev Signed-off-by: Greg Kroah-Hartman --- include/sound/tas2781.h | 2 +- .../hda/codecs/side-codecs/tas2781_hda_i2c.c | 44 +++++++++++-------- 2 files changed, 26 insertions(+), 20 deletions(-) diff --git a/include/sound/tas2781.h b/include/sound/tas2781.h index 0fbcdb15c74b5..29d15ba65f04d 100644 --- a/include/sound/tas2781.h +++ b/include/sound/tas2781.h @@ -197,7 +197,6 @@ struct tasdevice_priv { struct acoustic_data acou_data; #endif struct tasdevice_fw *fmw; - struct gpio_desc *speaker_id; struct gpio_desc *reset; struct mutex codec_lock; struct regmap *regmap; @@ -215,6 +214,7 @@ struct tasdevice_priv { unsigned int magic_num; unsigned int chip_id; unsigned int sysclk; + int speaker_id; int irq; int cur_prog; diff --git a/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c b/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c index 0357401a60234..c8619995b1d78 100644 --- a/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c +++ b/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c @@ -87,6 +87,7 @@ static const struct acpi_gpio_mapping tas2781_speaker_id_gpios[] = { static int tas2781_read_acpi(struct tasdevice_priv *p, const char *hid) { + struct gpio_desc *speaker_id; struct acpi_device *adev; struct device *physdev; LIST_HEAD(resources); @@ -119,19 +120,31 @@ static int tas2781_read_acpi(struct tasdevice_priv *p, const char *hid) /* Speaker id was needed for ASUS projects. */ ret = kstrtou32(sub, 16, &subid); if (!ret && upper_16_bits(subid) == PCI_VENDOR_ID_ASUSTEK) { - ret = devm_acpi_dev_add_driver_gpios(p->dev, - tas2781_speaker_id_gpios); - if (ret < 0) + ret = acpi_dev_add_driver_gpios(adev, tas2781_speaker_id_gpios); + if (ret < 0) { dev_err(p->dev, "Failed to add driver gpio %d.\n", ret); - p->speaker_id = devm_gpiod_get(p->dev, "speakerid", GPIOD_IN); - if (IS_ERR(p->speaker_id)) { - dev_err(p->dev, "Failed to get Speaker id.\n"); - ret = PTR_ERR(p->speaker_id); - goto err; + p->speaker_id = -1; + goto end_2563; + } + + speaker_id = fwnode_gpiod_get_index(acpi_fwnode_handle(adev), + "speakerid", 0, GPIOD_IN, NULL); + if (!IS_ERR(speaker_id)) { + p->speaker_id = gpiod_get_value_cansleep(speaker_id); + dev_dbg(p->dev, "Got speaker id gpio from ACPI: %d.\n", + p->speaker_id); + gpiod_put(speaker_id); + } else { + p->speaker_id = -1; + ret = PTR_ERR(speaker_id); + dev_err(p->dev, "Get speaker id gpio failed %d.\n", + ret); } + + acpi_dev_remove_driver_gpios(adev); } else { - p->speaker_id = NULL; + p->speaker_id = -1; } end_2563: @@ -432,23 +445,16 @@ static void tasdevice_dspfw_init(void *context) struct tas2781_hda *tas_hda = dev_get_drvdata(tas_priv->dev); struct tas2781_hda_i2c_priv *hda_priv = tas_hda->hda_priv; struct hda_codec *codec = tas_priv->codec; - int ret, spk_id; + int ret; tasdevice_dsp_remove(tas_priv); tas_priv->fw_state = TASDEVICE_DSP_FW_PENDING; - if (tas_priv->speaker_id != NULL) { - // Speaker id need to be checked for ASUS only. - spk_id = gpiod_get_value(tas_priv->speaker_id); - if (spk_id < 0) { - // Speaker id is not valid, use default. - dev_dbg(tas_priv->dev, "Wrong spk_id = %d\n", spk_id); - spk_id = 0; - } + if (tas_priv->speaker_id >= 0) { snprintf(tas_priv->coef_binaryname, sizeof(tas_priv->coef_binaryname), "TAS2XXX%04X%d.bin", lower_16_bits(codec->core.subsystem_id), - spk_id); + tas_priv->speaker_id); } else { snprintf(tas_priv->coef_binaryname, sizeof(tas_priv->coef_binaryname), From 343fa9800cf9870ec681e21f0a6f2157b74ae520 Mon Sep 17 00:00:00 2001 From: Denis Arefev Date: Tue, 2 Dec 2025 13:13:36 +0300 Subject: [PATCH 0988/2333] ALSA: hda: cs35l41: Fix NULL pointer dereference in cs35l41_hda_read_acpi() commit c34b04cc6178f33c08331568c7fd25c5b9a39f66 upstream. The acpi_get_first_physical_node() function can return NULL, in which case the get_device() function also returns NULL, but this value is then dereferenced without checking,so add a check to prevent a crash. Found by Linux Verification Center (linuxtesting.org) with SVACE. Fixes: 7b2f3eb492da ("ALSA: hda: cs35l41: Add support for CS35L41 in HDA systems") Cc: stable@vger.kernel.org Signed-off-by: Denis Arefev Reviewed-by: Richard Fitzgerald Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20251202101338.11437-1-arefev@swemel.ru Signed-off-by: Greg Kroah-Hartman --- sound/hda/codecs/side-codecs/cs35l41_hda.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/hda/codecs/side-codecs/cs35l41_hda.c b/sound/hda/codecs/side-codecs/cs35l41_hda.c index c0f2a3ff77a1b..21e00055c0c44 100644 --- a/sound/hda/codecs/side-codecs/cs35l41_hda.c +++ b/sound/hda/codecs/side-codecs/cs35l41_hda.c @@ -1901,6 +1901,8 @@ static int cs35l41_hda_read_acpi(struct cs35l41_hda *cs35l41, const char *hid, i cs35l41->dacpi = adev; physdev = get_device(acpi_get_first_physical_node(adev)); + if (!physdev) + return -ENODEV; sub = acpi_get_subsystem_id(ACPI_HANDLE(physdev)); if (IS_ERR(sub)) From 590bd2a7acba27fda5e4e9d623780f977c0e1e14 Mon Sep 17 00:00:00 2001 From: Junrui Luo Date: Thu, 6 Nov 2025 10:24:57 +0800 Subject: [PATCH 0989/2333] ALSA: wavefront: Clear substream pointers on close commit e11c5c13ce0ab2325d38fe63500be1dd88b81e38 upstream. Clear substream pointers in close functions to avoid leaving dangling pointers, helping to improve code safety and prevents potential issues. Reported-by: Yuhao Jiang Reported-by: Junrui Luo Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Cc: stable@vger.kernel.org Signed-off-by: Junrui Luo Link: https://patch.msgid.link/SYBPR01MB7881DF762CAB45EE42F6D812AFC2A@SYBPR01MB7881.ausprd01.prod.outlook.com Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/isa/wavefront/wavefront_midi.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/isa/wavefront/wavefront_midi.c b/sound/isa/wavefront/wavefront_midi.c index 1250ecba659a0..69d87c4cafaed 100644 --- a/sound/isa/wavefront/wavefront_midi.c +++ b/sound/isa/wavefront/wavefront_midi.c @@ -278,6 +278,7 @@ static int snd_wavefront_midi_input_close(struct snd_rawmidi_substream *substrea return -EIO; guard(spinlock_irqsave)(&midi->open); + midi->substream_input[mpu] = NULL; midi->mode[mpu] &= ~MPU401_MODE_INPUT; return 0; @@ -300,6 +301,7 @@ static int snd_wavefront_midi_output_close(struct snd_rawmidi_substream *substre return -EIO; guard(spinlock_irqsave)(&midi->open); + midi->substream_output[mpu] = NULL; midi->mode[mpu] &= ~MPU401_MODE_OUTPUT; return 0; } From 1823e08f76c68b9e1d26f6d5ef831b96f61a62a0 Mon Sep 17 00:00:00 2001 From: Junrui Luo Date: Thu, 6 Nov 2025 10:49:46 +0800 Subject: [PATCH 0990/2333] ALSA: wavefront: Fix integer overflow in sample size validation commit 0c4a13ba88594fd4a27292853e736c6b4349823d upstream. The wavefront_send_sample() function has an integer overflow issue when validating sample size. The header->size field is u32 but gets cast to int for comparison with dev->freemem Fix by using unsigned comparison to avoid integer overflow. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Cc: stable@vger.kernel.org Signed-off-by: Junrui Luo Link: https://patch.msgid.link/SYBPR01MB7881B47789D1B060CE8BF4C3AFC2A@SYBPR01MB7881.ausprd01.prod.outlook.com Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/isa/wavefront/wavefront_synth.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/isa/wavefront/wavefront_synth.c b/sound/isa/wavefront/wavefront_synth.c index cd5c177943aa0..0d78533e1cfd6 100644 --- a/sound/isa/wavefront/wavefront_synth.c +++ b/sound/isa/wavefront/wavefront_synth.c @@ -950,9 +950,9 @@ wavefront_send_sample (snd_wavefront_t *dev, if (header->size) { dev->freemem = wavefront_freemem (dev); - if (dev->freemem < (int)header->size) { + if (dev->freemem < 0 || dev->freemem < header->size) { dev_err(dev->card->dev, - "insufficient memory to load %d byte sample.\n", + "insufficient memory to load %u byte sample.\n", header->size); return -ENOMEM; } From 78d82960b939df64cf7d26ca5ed34eb87f44c9e5 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 18 Dec 2025 14:03:43 +0100 Subject: [PATCH 0991/2333] Linux 6.18.2 Link: https://lore.kernel.org/r/20251216111401.280873349@linuxfoundation.org Tested-by: Ronald Warsow Tested-by: Brett A C Sheffield Tested-by: Achill Gilgenast = Tested-by: Dileep Malepu dileep.debian@gmail.com Tested-by: Salvatore Bonaccorso Tested-by: Florian Fainelli Tested-by: Ron Economos Tested-by: Jeffrin Jose T Tested-by: Takeshi Ogasawara Tested-by: Justin M. Forbes Tested-by: Jon Hunter Tested-by: Peter Schneider Tested-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 23cc6c39819b1..c2b5cfd2fce01 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 VERSION = 6 PATCHLEVEL = 18 -SUBLEVEL = 1 +SUBLEVEL = 2 EXTRAVERSION = NAME = Baby Opossum Posse From e7a4d4537890c7a83c97a57acd0c90ce6b8b42e0 Mon Sep 17 00:00:00 2001 From: Gaurav Kohli Date: Mon, 15 Dec 2025 10:24:51 +0530 Subject: [PATCH 0992/2333] FROMLIST: arm64: dts: qcom: lemans: Enable cpufreq cooling devices Add cooling-cells property to the CPU nodes to support cpufreq cooling devices. Signed-off-by: Gaurav Kohli Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20251215045451.3150894-1-gaurav.kohli@oss.qualcomm.com --- arch/arm64/boot/dts/qcom/lemans.dtsi | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/lemans.dtsi b/arch/arm64/boot/dts/qcom/lemans.dtsi index 8b77e2a5ef01f..fc9ebf7d2cf0b 100644 --- a/arch/arm64/boot/dts/qcom/lemans.dtsi +++ b/arch/arm64/boot/dts/qcom/lemans.dtsi @@ -55,6 +55,7 @@ qcom,freq-domain = <&cpufreq_hw 0>; next-level-cache = <&l2_0>; capacity-dmips-mhz = <1024>; + #cooling-cells = <2>; dynamic-power-coefficient = <100>; operating-points-v2 = <&cpu0_opp_table>; interconnects = <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ACTIVE_ONLY @@ -84,6 +85,7 @@ qcom,freq-domain = <&cpufreq_hw 0>; next-level-cache = <&l2_1>; capacity-dmips-mhz = <1024>; + #cooling-cells = <2>; dynamic-power-coefficient = <100>; operating-points-v2 = <&cpu0_opp_table>; interconnects = <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ACTIVE_ONLY @@ -108,6 +110,7 @@ qcom,freq-domain = <&cpufreq_hw 0>; next-level-cache = <&l2_2>; capacity-dmips-mhz = <1024>; + #cooling-cells = <2>; dynamic-power-coefficient = <100>; operating-points-v2 = <&cpu0_opp_table>; interconnects = <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ACTIVE_ONLY @@ -132,6 +135,7 @@ qcom,freq-domain = <&cpufreq_hw 0>; next-level-cache = <&l2_3>; capacity-dmips-mhz = <1024>; + #cooling-cells = <2>; dynamic-power-coefficient = <100>; operating-points-v2 = <&cpu0_opp_table>; interconnects = <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ACTIVE_ONLY @@ -156,6 +160,7 @@ qcom,freq-domain = <&cpufreq_hw 1>; next-level-cache = <&l2_4>; capacity-dmips-mhz = <1024>; + #cooling-cells = <2>; dynamic-power-coefficient = <100>; operating-points-v2 = <&cpu4_opp_table>; interconnects = <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ACTIVE_ONLY @@ -186,6 +191,7 @@ qcom,freq-domain = <&cpufreq_hw 1>; next-level-cache = <&l2_5>; capacity-dmips-mhz = <1024>; + #cooling-cells = <2>; dynamic-power-coefficient = <100>; operating-points-v2 = <&cpu4_opp_table>; interconnects = <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ACTIVE_ONLY @@ -210,6 +216,7 @@ qcom,freq-domain = <&cpufreq_hw 1>; next-level-cache = <&l2_6>; capacity-dmips-mhz = <1024>; + #cooling-cells = <2>; dynamic-power-coefficient = <100>; operating-points-v2 = <&cpu4_opp_table>; interconnects = <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ACTIVE_ONLY @@ -234,6 +241,7 @@ qcom,freq-domain = <&cpufreq_hw 1>; next-level-cache = <&l2_7>; capacity-dmips-mhz = <1024>; + #cooling-cells = <2>; dynamic-power-coefficient = <100>; operating-points-v2 = <&cpu4_opp_table>; interconnects = <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ACTIVE_ONLY From eefd169fd74fc700a01322efa03a39f968c1ffb1 Mon Sep 17 00:00:00 2001 From: Akhil P Oommen Date: Tue, 18 Nov 2025 14:20:37 +0530 Subject: [PATCH 0993/2333] FROMGIT: drm/msm/a6xx: Rebase GMU register offsets GMU registers are always at a fixed offset from the GPU base address, a consistency maintained at least within a given architecture generation. In A8x family, the base address of the GMU has changed, but the offsets of the gmu registers remain largely the same. To enable reuse of the gmu code for A8x chipsets, update the gmu register offsets to be relative to the GPU's base address instead of GMU's. Signed-off-by: Akhil P Oommen Patchwork: https://patchwork.freedesktop.org/patch/689010/ Message-ID: <20251118-kaana-gpu-support-v4-10-86eeb8e93fb6@oss.qualcomm.com> Signed-off-by: Rob Clark Link: https://lore.kernel.org/r/20251118-kaana-gpu-support-v4-10-86eeb8e93fb6@oss.qualcomm.com --- drivers/gpu/drm/msm/adreno/a6xx_gmu.c | 100 ++++--- drivers/gpu/drm/msm/adreno/a6xx_gmu.h | 20 +- drivers/gpu/drm/msm/adreno/a6xx_gpu_state.h | 56 ++-- .../gpu/drm/msm/registers/adreno/a6xx_gmu.xml | 248 +++++++++--------- 4 files changed, 221 insertions(+), 203 deletions(-) diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c index d9ffe9e93ad9d..55ea8efdf57ae 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c @@ -596,22 +596,19 @@ static inline void pdc_write(void __iomem *ptr, u32 offset, u32 value) writel(value, ptr + (offset << 2)); } -static void __iomem *a6xx_gmu_get_mmio(struct platform_device *pdev, - const char *name); - static void a6xx_gmu_rpmh_init(struct a6xx_gmu *gmu) { struct a6xx_gpu *a6xx_gpu = container_of(gmu, struct a6xx_gpu, gmu); struct adreno_gpu *adreno_gpu = &a6xx_gpu->base; struct platform_device *pdev = to_platform_device(gmu->dev); - void __iomem *pdcptr = a6xx_gmu_get_mmio(pdev, "gmu_pdc"); + void __iomem *pdcptr = devm_platform_ioremap_resource_byname(pdev, "gmu_pdc"); u32 seqmem0_drv0_reg = REG_A6XX_RSCC_SEQ_MEM_0_DRV0; void __iomem *seqptr = NULL; uint32_t pdc_address_offset; bool pdc_in_aop = false; if (IS_ERR(pdcptr)) - goto err; + return; if (adreno_is_a650_family(adreno_gpu) || adreno_is_a7xx(adreno_gpu)) @@ -624,9 +621,9 @@ static void a6xx_gmu_rpmh_init(struct a6xx_gmu *gmu) pdc_address_offset = 0x30080; if (!pdc_in_aop) { - seqptr = a6xx_gmu_get_mmio(pdev, "gmu_pdc_seq"); + seqptr = devm_platform_ioremap_resource_byname(pdev, "gmu_pdc_seq"); if (IS_ERR(seqptr)) - goto err; + return; } /* Disable SDE clock gating */ @@ -716,12 +713,6 @@ static void a6xx_gmu_rpmh_init(struct a6xx_gmu *gmu) /* ensure no writes happen before the uCode is fully written */ wmb(); - -err: - if (!IS_ERR_OR_NULL(pdcptr)) - iounmap(pdcptr); - if (!IS_ERR_OR_NULL(seqptr)) - iounmap(seqptr); } /* @@ -1807,27 +1798,6 @@ static int a6xx_gmu_clocks_probe(struct a6xx_gmu *gmu) return 0; } -static void __iomem *a6xx_gmu_get_mmio(struct platform_device *pdev, - const char *name) -{ - void __iomem *ret; - struct resource *res = platform_get_resource_byname(pdev, - IORESOURCE_MEM, name); - - if (!res) { - DRM_DEV_ERROR(&pdev->dev, "Unable to find the %s registers\n", name); - return ERR_PTR(-EINVAL); - } - - ret = ioremap(res->start, resource_size(res)); - if (!ret) { - DRM_DEV_ERROR(&pdev->dev, "Unable to map the %s registers\n", name); - return ERR_PTR(-EINVAL); - } - - return ret; -} - static int a6xx_gmu_get_irq(struct a6xx_gmu *gmu, struct platform_device *pdev, const char *name, irq_handler_t handler) { @@ -1878,7 +1848,6 @@ void a6xx_gmu_remove(struct a6xx_gpu *a6xx_gpu) { struct adreno_gpu *adreno_gpu = &a6xx_gpu->base; struct a6xx_gmu *gmu = &a6xx_gpu->gmu; - struct platform_device *pdev = to_platform_device(gmu->dev); mutex_lock(&gmu->lock); if (!gmu->initialized) { @@ -1907,8 +1876,6 @@ void a6xx_gmu_remove(struct a6xx_gpu *a6xx_gpu) qmp_put(gmu->qmp); iounmap(gmu->mmio); - if (platform_get_resource_byname(pdev, IORESOURCE_MEM, "rscc")) - iounmap(gmu->rscc); gmu->mmio = NULL; gmu->rscc = NULL; @@ -1935,10 +1902,38 @@ static int cxpd_notifier_cb(struct notifier_block *nb, return 0; } +static void __iomem *a6xx_gmu_get_mmio(struct platform_device *pdev, + const char *name, resource_size_t *start) +{ + void __iomem *ret; + struct resource *res = platform_get_resource_byname(pdev, + IORESOURCE_MEM, name); + + if (!res) { + DRM_DEV_ERROR(&pdev->dev, "Unable to find the %s registers\n", name); + return ERR_PTR(-EINVAL); + } + + ret = ioremap(res->start, resource_size(res)); + if (!ret) { + DRM_DEV_ERROR(&pdev->dev, "Unable to map the %s registers\n", name); + return ERR_PTR(-EINVAL); + } + + if (start) + *start = res->start; + + return ret; +} + int a6xx_gmu_wrapper_init(struct a6xx_gpu *a6xx_gpu, struct device_node *node) { struct platform_device *pdev = of_find_device_by_node(node); + struct adreno_gpu *adreno_gpu = &a6xx_gpu->base; + struct msm_gpu *gpu = &adreno_gpu->base; struct a6xx_gmu *gmu = &a6xx_gpu->gmu; + resource_size_t start; + struct resource *res; int ret; if (!pdev) @@ -1963,12 +1958,21 @@ int a6xx_gmu_wrapper_init(struct a6xx_gpu *a6xx_gpu, struct device_node *node) gmu->nr_clocks = ret; /* Map the GMU registers */ - gmu->mmio = a6xx_gmu_get_mmio(pdev, "gmu"); + gmu->mmio = a6xx_gmu_get_mmio(pdev, "gmu", &start); if (IS_ERR(gmu->mmio)) { ret = PTR_ERR(gmu->mmio); goto err_mmio; } + res = platform_get_resource_byname(gpu->pdev, IORESOURCE_MEM, "kgsl_3d0_reg_memory"); + if (!res) { + ret = -EINVAL; + goto err_mmio; + } + + /* Identify gmu base offset from gpu base address */ + gmu->mmio_offset = (u32)(start - res->start); + gmu->cxpd = dev_pm_domain_attach_by_name(gmu->dev, "cx"); if (IS_ERR(gmu->cxpd)) { ret = PTR_ERR(gmu->cxpd); @@ -2010,10 +2014,13 @@ int a6xx_gmu_wrapper_init(struct a6xx_gpu *a6xx_gpu, struct device_node *node) int a6xx_gmu_init(struct a6xx_gpu *a6xx_gpu, struct device_node *node) { + struct platform_device *pdev = of_find_device_by_node(node); struct adreno_gpu *adreno_gpu = &a6xx_gpu->base; + struct msm_gpu *gpu = &adreno_gpu->base; struct a6xx_gmu *gmu = &a6xx_gpu->gmu; - struct platform_device *pdev = of_find_device_by_node(node); struct device_link *link; + resource_size_t start; + struct resource *res; int ret; if (!pdev) @@ -2108,15 +2115,24 @@ int a6xx_gmu_init(struct a6xx_gpu *a6xx_gpu, struct device_node *node) goto err_memory; /* Map the GMU registers */ - gmu->mmio = a6xx_gmu_get_mmio(pdev, "gmu"); + gmu->mmio = a6xx_gmu_get_mmio(pdev, "gmu", &start); if (IS_ERR(gmu->mmio)) { ret = PTR_ERR(gmu->mmio); goto err_memory; } + res = platform_get_resource_byname(gpu->pdev, IORESOURCE_MEM, "kgsl_3d0_reg_memory"); + if (!res) { + ret = -EINVAL; + goto err_mmio; + } + + /* Identify gmu base offset from gpu base address */ + gmu->mmio_offset = (u32)(start - res->start); + if (adreno_is_a650_family(adreno_gpu) || adreno_is_a7xx(adreno_gpu)) { - gmu->rscc = a6xx_gmu_get_mmio(pdev, "rscc"); + gmu->rscc = devm_platform_ioremap_resource_byname(pdev, "rscc"); if (IS_ERR(gmu->rscc)) { ret = -ENODEV; goto err_mmio; @@ -2194,8 +2210,6 @@ int a6xx_gmu_init(struct a6xx_gpu *a6xx_gpu, struct device_node *node) err_mmio: iounmap(gmu->mmio); - if (platform_get_resource_byname(pdev, IORESOURCE_MEM, "rscc")) - iounmap(gmu->rscc); free_irq(gmu->gmu_irq, gmu); free_irq(gmu->hfi_irq, gmu); diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.h b/drivers/gpu/drm/msm/adreno/a6xx_gmu.h index 06cfc294016f5..55b1c78daa8b5 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.h +++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.h @@ -68,6 +68,7 @@ struct a6xx_gmu { struct drm_gpuvm *vm; void __iomem *mmio; + u32 mmio_offset; void __iomem *rscc; int hfi_irq; @@ -130,20 +131,23 @@ struct a6xx_gmu { unsigned long status; }; +#define GMU_BYTE_OFFSET(gmu, offset) (((offset) << 2) - (gmu)->mmio_offset) + static inline u32 gmu_read(struct a6xx_gmu *gmu, u32 offset) { - return readl(gmu->mmio + (offset << 2)); + /* The 'offset' is based on GPU's start address. Adjust it */ + return readl(gmu->mmio + GMU_BYTE_OFFSET(gmu, offset)); } static inline void gmu_write(struct a6xx_gmu *gmu, u32 offset, u32 value) { - writel(value, gmu->mmio + (offset << 2)); + writel(value, gmu->mmio + GMU_BYTE_OFFSET(gmu, offset)); } static inline void gmu_write_bulk(struct a6xx_gmu *gmu, u32 offset, const u32 *data, u32 size) { - memcpy_toio(gmu->mmio + (offset << 2), data, size); + memcpy_toio(gmu->mmio + GMU_BYTE_OFFSET(gmu, offset), data, size); wmb(); } @@ -160,17 +164,17 @@ static inline u64 gmu_read64(struct a6xx_gmu *gmu, u32 lo, u32 hi) { u64 val; - val = (u64) readl(gmu->mmio + (lo << 2)); - val |= ((u64) readl(gmu->mmio + (hi << 2)) << 32); + val = gmu_read(gmu, lo); + val |= ((u64) gmu_read(gmu, hi) << 32); return val; } #define gmu_poll_timeout(gmu, addr, val, cond, interval, timeout) \ - readl_poll_timeout((gmu)->mmio + ((addr) << 2), val, cond, \ - interval, timeout) + readl_poll_timeout((gmu)->mmio + (GMU_BYTE_OFFSET(gmu, addr)), val, \ + cond, interval, timeout) #define gmu_poll_timeout_atomic(gmu, addr, val, cond, interval, timeout) \ - readl_poll_timeout_atomic((gmu)->mmio + ((addr) << 2), val, cond, \ + readl_poll_timeout_atomic((gmu)->mmio + (GMU_BYTE_OFFSET(gmu, addr)), val, cond, \ interval, timeout) static inline u32 gmu_read_rscc(struct a6xx_gmu *gmu, u32 offset) diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.h b/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.h index 1c18499b60bb9..4753b71837f33 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.h +++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.h @@ -343,48 +343,48 @@ static const struct a6xx_registers a6xx_gbif_reglist = static const u32 a6xx_gmu_gx_registers[] = { /* GMU GX */ - 0x0000, 0x0000, 0x0010, 0x0013, 0x0016, 0x0016, 0x0018, 0x001b, - 0x001e, 0x001e, 0x0020, 0x0023, 0x0026, 0x0026, 0x0028, 0x002b, - 0x002e, 0x002e, 0x0030, 0x0033, 0x0036, 0x0036, 0x0038, 0x003b, - 0x003e, 0x003e, 0x0040, 0x0043, 0x0046, 0x0046, 0x0080, 0x0084, - 0x0100, 0x012b, 0x0140, 0x0140, + 0x1a800, 0x1a800, 0x1a810, 0x1a813, 0x1a816, 0x1a816, 0x1a818, 0x1a81b, + 0x1a81e, 0x1a81e, 0x1a820, 0x1a823, 0x1a826, 0x1a826, 0x1a828, 0x1a82b, + 0x1a82e, 0x1a82e, 0x1a830, 0x1a833, 0x1a836, 0x1a836, 0x1a838, 0x1a83b, + 0x1a83e, 0x1a83e, 0x1a840, 0x1a843, 0x1a846, 0x1a846, 0x1a880, 0x1a884, + 0x1a900, 0x1a92b, 0x1a940, 0x1a940, }; static const u32 a6xx_gmu_cx_registers[] = { /* GMU CX */ - 0x4c00, 0x4c07, 0x4c10, 0x4c12, 0x4d00, 0x4d00, 0x4d07, 0x4d0a, - 0x5000, 0x5004, 0x5007, 0x5008, 0x500b, 0x500c, 0x500f, 0x501c, - 0x5024, 0x502a, 0x502d, 0x5030, 0x5040, 0x5053, 0x5087, 0x5089, - 0x50a0, 0x50a2, 0x50a4, 0x50af, 0x50c0, 0x50c3, 0x50d0, 0x50d0, - 0x50e4, 0x50e4, 0x50e8, 0x50ec, 0x5100, 0x5103, 0x5140, 0x5140, - 0x5142, 0x5144, 0x514c, 0x514d, 0x514f, 0x5151, 0x5154, 0x5154, - 0x5157, 0x5158, 0x515d, 0x515d, 0x5162, 0x5162, 0x5164, 0x5165, - 0x5180, 0x5186, 0x5190, 0x519e, 0x51c0, 0x51c0, 0x51c5, 0x51cc, - 0x51e0, 0x51e2, 0x51f0, 0x51f0, 0x5200, 0x5201, + 0x1f400, 0x1f407, 0x1f410, 0x1f412, 0x1f500, 0x1f500, 0x1f507, 0x1f50a, + 0x1f800, 0x1f804, 0x1f807, 0x1f808, 0x1f80b, 0x1f80c, 0x1f80f, 0x1f81c, + 0x1f824, 0x1f82a, 0x1f82d, 0x1f830, 0x1f840, 0x1f853, 0x1f887, 0x1f889, + 0x1f8a0, 0x1f8a2, 0x1f8a4, 0x1f8af, 0x1f8c0, 0x1f8c3, 0x1f8d0, 0x1f8d0, + 0x1f8e4, 0x1f8e4, 0x1f8e8, 0x1f8ec, 0x1f900, 0x1f903, 0x1f940, 0x1f940, + 0x1f942, 0x1f944, 0x1f94c, 0x1f94d, 0x1f94f, 0x1f951, 0x1f954, 0x1f954, + 0x1f957, 0x1f958, 0x1f95d, 0x1f95d, 0x1f962, 0x1f962, 0x1f964, 0x1f965, + 0x1f980, 0x1f986, 0x1f990, 0x1f99e, 0x1f9c0, 0x1f9c0, 0x1f9c5, 0x1f9cc, + 0x1f9e0, 0x1f9e2, 0x1f9f0, 0x1f9f0, 0x1fa00, 0x1fa01, /* GMU AO */ - 0x9300, 0x9316, 0x9400, 0x9400, + 0x23b00, 0x23b16, 0x23c00, 0x23c00, }; static const u32 a6xx_gmu_gpucc_registers[] = { /* GPU CC */ - 0x9800, 0x9812, 0x9840, 0x9852, 0x9c00, 0x9c04, 0x9c07, 0x9c0b, - 0x9c15, 0x9c1c, 0x9c1e, 0x9c2d, 0x9c3c, 0x9c3d, 0x9c3f, 0x9c40, - 0x9c42, 0x9c49, 0x9c58, 0x9c5a, 0x9d40, 0x9d5e, 0xa000, 0xa002, - 0xa400, 0xa402, 0xac00, 0xac02, 0xb000, 0xb002, 0xb400, 0xb402, - 0xb800, 0xb802, + 0x24000, 0x24012, 0x24040, 0x24052, 0x24400, 0x24404, 0x24407, 0x2440b, + 0x24415, 0x2441c, 0x2441e, 0x2442d, 0x2443c, 0x2443d, 0x2443f, 0x24440, + 0x24442, 0x24449, 0x24458, 0x2445a, 0x24540, 0x2455e, 0x24800, 0x24802, + 0x24c00, 0x24c02, 0x25400, 0x25402, 0x25800, 0x25802, 0x25c00, 0x25c02, + 0x26000, 0x26002, /* GPU CC ACD */ - 0xbc00, 0xbc16, 0xbc20, 0xbc27, + 0x26400, 0x26416, 0x26420, 0x26427, }; static const u32 a621_gmu_gpucc_registers[] = { /* GPU CC */ - 0x9800, 0x980e, 0x9c00, 0x9c0e, 0xb000, 0xb004, 0xb400, 0xb404, - 0xb800, 0xb804, 0xbc00, 0xbc05, 0xbc14, 0xbc1d, 0xbc2a, 0xbc30, - 0xbc32, 0xbc32, 0xbc41, 0xbc55, 0xbc66, 0xbc68, 0xbc78, 0xbc7a, - 0xbc89, 0xbc8a, 0xbc9c, 0xbc9e, 0xbca0, 0xbca3, 0xbcb3, 0xbcb5, - 0xbcc5, 0xbcc7, 0xbcd6, 0xbcd8, 0xbce8, 0xbce9, 0xbcf9, 0xbcfc, - 0xbd0b, 0xbd0c, 0xbd1c, 0xbd1e, 0xbd40, 0xbd70, 0xbe00, 0xbe16, - 0xbe20, 0xbe2d, + 0x24000, 0x2400e, 0x24400, 0x2440e, 0x25800, 0x25804, 0x25c00, 0x25c04, + 0x26000, 0x26004, 0x26400, 0x26405, 0x26414, 0x2641d, 0x2642a, 0x26430, + 0x26432, 0x26432, 0x26441, 0x26455, 0x26466, 0x26468, 0x26478, 0x2647a, + 0x26489, 0x2648a, 0x2649c, 0x2649e, 0x264a0, 0x264a3, 0x264b3, 0x264b5, + 0x264c5, 0x264c7, 0x264d6, 0x264d8, 0x264e8, 0x264e9, 0x264f9, 0x264fc, + 0x2650b, 0x2650c, 0x2651c, 0x2651e, 0x26540, 0x26570, 0x26600, 0x26616, + 0x26620, 0x2662d, }; static const u32 a6xx_gmu_cx_rscc_registers[] = { diff --git a/drivers/gpu/drm/msm/registers/adreno/a6xx_gmu.xml b/drivers/gpu/drm/msm/registers/adreno/a6xx_gmu.xml index b15a242d974d6..09b8a0b9c0de7 100644 --- a/drivers/gpu/drm/msm/registers/adreno/a6xx_gmu.xml +++ b/drivers/gpu/drm/msm/registers/adreno/a6xx_gmu.xml @@ -40,56 +40,56 @@ xsi:schemaLocation="https://gitlab.freedesktop.org/freedreno/ rules-fd.xsd"> - - - - - - - - - - - - - + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + @@ -99,15 +99,15 @@ xsi:schemaLocation="https://gitlab.freedesktop.org/freedreno/ rules-fd.xsd"> - + - + - + @@ -119,71 +119,71 @@ xsi:schemaLocation="https://gitlab.freedesktop.org/freedreno/ rules-fd.xsd"> - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -191,27 +191,27 @@ xsi:schemaLocation="https://gitlab.freedesktop.org/freedreno/ rules-fd.xsd"> - - - - - + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + From 8ec9fcf3f3c8e2cee5455f0b1ab0c58ef4f66151 Mon Sep 17 00:00:00 2001 From: Akhil P Oommen Date: Thu, 4 Dec 2025 18:51:53 +0530 Subject: [PATCH 0994/2333] FROMLIST: drm/msm/a6xx: Retrieve gmu core range by index Some GPUs like A612 doesn't use a named register range resource. This is because the reg-name property is discouraged when there is just a single resource. To address this, retrieve the 'gmu' register range by its index. It is always guaranteed to be at index 0. Signed-off-by: Akhil P Oommen Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20251204-qcs615-spin-2-v4-1-f5a00c5b663f@oss.qualcomm.com --- drivers/gpu/drm/msm/adreno/a6xx_gmu.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c index 55ea8efdf57ae..ed9fbd9b4ccc5 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c @@ -1902,21 +1902,19 @@ static int cxpd_notifier_cb(struct notifier_block *nb, return 0; } -static void __iomem *a6xx_gmu_get_mmio(struct platform_device *pdev, - const char *name, resource_size_t *start) +static void __iomem *a6xx_gmu_get_mmio(struct platform_device *pdev, resource_size_t *start) { + struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); void __iomem *ret; - struct resource *res = platform_get_resource_byname(pdev, - IORESOURCE_MEM, name); if (!res) { - DRM_DEV_ERROR(&pdev->dev, "Unable to find the %s registers\n", name); + DRM_DEV_ERROR(&pdev->dev, "Unable to find the gmu core registers\n"); return ERR_PTR(-EINVAL); } ret = ioremap(res->start, resource_size(res)); if (!ret) { - DRM_DEV_ERROR(&pdev->dev, "Unable to map the %s registers\n", name); + DRM_DEV_ERROR(&pdev->dev, "Unable to map the gmu core registers\n"); return ERR_PTR(-EINVAL); } @@ -1958,7 +1956,7 @@ int a6xx_gmu_wrapper_init(struct a6xx_gpu *a6xx_gpu, struct device_node *node) gmu->nr_clocks = ret; /* Map the GMU registers */ - gmu->mmio = a6xx_gmu_get_mmio(pdev, "gmu", &start); + gmu->mmio = a6xx_gmu_get_mmio(pdev, &start); if (IS_ERR(gmu->mmio)) { ret = PTR_ERR(gmu->mmio); goto err_mmio; @@ -2115,7 +2113,7 @@ int a6xx_gmu_init(struct a6xx_gpu *a6xx_gpu, struct device_node *node) goto err_memory; /* Map the GMU registers */ - gmu->mmio = a6xx_gmu_get_mmio(pdev, "gmu", &start); + gmu->mmio = a6xx_gmu_get_mmio(pdev, &start); if (IS_ERR(gmu->mmio)) { ret = PTR_ERR(gmu->mmio); goto err_memory; From b701fc8247c0ab465261cc56c5b39b72a7d40f90 Mon Sep 17 00:00:00 2001 From: Akhil P Oommen Date: Thu, 4 Dec 2025 18:51:54 +0530 Subject: [PATCH 0995/2333] FROMLIST: dt-bindings: display/msm: gpu: Simplify conditional schema logic JSON Schema conditionals can become complex and error-prone when combined with regex patterns. To improve readability and maintainability, replace nested if-else blocks with a flattened structure using explicit enums. Signed-off-by: Akhil P Oommen Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20251204-qcs615-spin-2-v4-2-f5a00c5b663f@oss.qualcomm.com --- .../devicetree/bindings/display/msm/gpu.yaml | 56 ++++++++++++------- 1 file changed, 36 insertions(+), 20 deletions(-) diff --git a/Documentation/devicetree/bindings/display/msm/gpu.yaml b/Documentation/devicetree/bindings/display/msm/gpu.yaml index 3696b083e3530..1a71afdbbbe0e 100644 --- a/Documentation/devicetree/bindings/display/msm/gpu.yaml +++ b/Documentation/devicetree/bindings/display/msm/gpu.yaml @@ -388,26 +388,42 @@ allOf: required: - clocks - clock-names - else: - if: - properties: - compatible: - contains: - oneOf: - - pattern: '^qcom,adreno-[67][0-9][0-9]\.[0-9]+$' - - pattern: '^qcom,adreno-[0-9a-f]{8}$' - - then: # Starting with A6xx, the clocks are usually defined in the GMU node - properties: - clocks: false - clock-names: false - - reg-names: - minItems: 1 - items: - - const: kgsl_3d0_reg_memory - - const: cx_mem - - const: cx_dbgc + + - if: + properties: + compatible: + contains: + enum: + - qcom,adreno-615.0 + - qcom,adreno-618.0 + - qcom,adreno-619.0 + - qcom,adreno-621.0 + - qcom,adreno-623.0 + - qcom,adreno-630.2 + - qcom,adreno-635.0 + - qcom,adreno-640.1 + - qcom,adreno-650.2 + - qcom,adreno-660.1 + - qcom,adreno-663.0 + - qcom,adreno-680.1 + - qcom,adreno-690.0 + - qcom,adreno-730.1 + - qcom,adreno-43030c00 + - qcom,adreno-43050a01 + - qcom,adreno-43050c01 + - qcom,adreno-43051401 + + then: # Starting with A6xx, the clocks are usually defined in the GMU node + properties: + clocks: false + clock-names: false + + reg-names: + minItems: 1 + items: + - const: kgsl_3d0_reg_memory + - const: cx_mem + - const: cx_dbgc examples: - | From ebc2e74421a2a446638a26225cba66e9306fbab7 Mon Sep 17 00:00:00 2001 From: Akhil P Oommen Date: Thu, 4 Dec 2025 18:51:55 +0530 Subject: [PATCH 0996/2333] FROMLIST: dt-bindings: display/msm: gpu: Document A612 GPU A612 GPU has a new IP called RGMU (Reduced Graphics Management Unit) which replaces GMU. But it doesn't do clock or voltage scaling. So we need the gpu core clock in the GPU node along with the power domain to do clock and voltage scaling from the kernel. Update the bindings to describe this GPU. Signed-off-by: Akhil P Oommen Link: https://lore.kernel.org/r/20251204-qcs615-spin-2-v4-3-f5a00c5b663f@oss.qualcomm.com --- .../devicetree/bindings/display/msm/gpu.yaml | 30 +++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/display/msm/gpu.yaml b/Documentation/devicetree/bindings/display/msm/gpu.yaml index 1a71afdbbbe0e..52294cfad7410 100644 --- a/Documentation/devicetree/bindings/display/msm/gpu.yaml +++ b/Documentation/devicetree/bindings/display/msm/gpu.yaml @@ -45,11 +45,11 @@ properties: - const: amd,imageon clocks: - minItems: 2 + minItems: 1 maxItems: 7 clock-names: - minItems: 2 + minItems: 1 maxItems: 7 reg: @@ -389,6 +389,32 @@ allOf: - clocks - clock-names + - if: + properties: + compatible: + contains: + const: qcom,adreno-612.0 + then: + properties: + clocks: + items: + - description: GPU Core clock + + clock-names: + items: + - const: core + + reg-names: + minItems: 1 + items: + - const: kgsl_3d0_reg_memory + - const: cx_mem + - const: cx_dbgc + + required: + - clocks + - clock-names + - if: properties: compatible: From 9c3df11ac5df3f7dfa1399388fdecd970940b136 Mon Sep 17 00:00:00 2001 From: Jie Zhang Date: Thu, 4 Dec 2025 18:51:56 +0530 Subject: [PATCH 0997/2333] FROMLIST: dt-bindings: display/msm/rgmu: Document A612 RGMU RGMU a.k.a Reduced Graphics Management Unit is a small state machine with the sole purpose of providing IFPC (Inter Frame Power Collapse) support. Compared to GMU, it doesn't manage GPU clock, voltage scaling, bw voting or any other functionalities. All it does is detect an idle GPU and toggle the GDSC switch. As it doesn't access DDR space, it doesn't require iommu. So far, only Adreno 612 GPU has an RGMU core. Document it in qcom,adreno-rgmu.yaml. Signed-off-by: Jie Zhang Signed-off-by: Akhil P Oommen Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20251204-qcs615-spin-2-v4-4-f5a00c5b663f@oss.qualcomm.com --- .../display/msm/qcom,adreno-rgmu.yaml | 126 ++++++++++++++++++ MAINTAINERS | 1 + 2 files changed, 127 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/msm/qcom,adreno-rgmu.yaml diff --git a/Documentation/devicetree/bindings/display/msm/qcom,adreno-rgmu.yaml b/Documentation/devicetree/bindings/display/msm/qcom,adreno-rgmu.yaml new file mode 100644 index 0000000000000..bacc5b32e6d7b --- /dev/null +++ b/Documentation/devicetree/bindings/display/msm/qcom,adreno-rgmu.yaml @@ -0,0 +1,126 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +%YAML 1.2 +--- + +$id: http://devicetree.org/schemas/display/msm/qcom,adreno-rgmu.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: RGMU attached to certain Adreno GPUs + +maintainers: + - Rob Clark + +description: + RGMU (Reduced Graphics Management Unit) IP is present in some GPUs that + belong to Adreno A6xx family. It is a small state machine that helps to + toggle the GX GDSC (connected to CX rail) to implement IFPC feature and save + power. + +properties: + compatible: + items: + - const: qcom,adreno-rgmu-612.0 + - const: qcom,adreno-rgmu + + reg: + items: + - description: Core RGMU registers + + clocks: + items: + - description: GMU clock + - description: GPU CX clock + - description: GPU AXI clock + - description: GPU MEMNOC clock + - description: GPU SMMU vote clock + + clock-names: + items: + - const: gmu + - const: cxo + - const: axi + - const: memnoc + - const: smmu_vote + + power-domains: + items: + - description: CX GDSC power domain + - description: GX GDSC power domain + + power-domain-names: + items: + - const: cx + - const: gx + + interrupts: + items: + - description: GMU OOB interrupt + - description: GMU interrupt + + interrupt-names: + items: + - const: oob + - const: gmu + + operating-points-v2: true + opp-table: + type: object + +required: + - compatible + - reg + - clocks + - clock-names + - power-domains + - power-domain-names + - interrupts + - interrupt-names + - operating-points-v2 + +additionalProperties: false + +examples: + - | + #include + #include + #include + #include + + gmu@506a000 { + compatible = "qcom,adreno-rgmu-612.0", "qcom,adreno-rgmu"; + + reg = <0x05000000 0x90000>; + + clocks = <&gpucc GPU_CC_CX_GMU_CLK>, + <&gpucc GPU_CC_CXO_CLK>, + <&gcc GCC_DDRSS_GPU_AXI_CLK>, + <&gcc GCC_GPU_MEMNOC_GFX_CLK>, + <&gpucc GPU_CC_HLOS1_VOTE_GPU_SMMU_CLK>; + clock-names = "gmu", + "cxo", + "axi", + "memnoc", + "smmu_vote"; + + power-domains = <&gpucc CX_GDSC>, + <&gpucc GX_GDSC>; + power-domain-names = "cx", + "gx"; + + interrupts = , + ; + interrupt-names = "oob", + "gmu"; + + operating-points-v2 = <&gmu_opp_table>; + + gmu_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-200000000 { + opp-hz = /bits/ 64 <200000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + }; + }; diff --git a/MAINTAINERS b/MAINTAINERS index bfd5ce9b30049..f8f919b53a3cc 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7884,6 +7884,7 @@ S: Maintained B: https://gitlab.freedesktop.org/drm/msm/-/issues T: git https://gitlab.freedesktop.org/drm/msm.git F: Documentation/devicetree/bindings/display/msm/gpu.yaml +F: Documentation/devicetree/bindings/display/msm/qcom,adreno-rgmu.yaml F: Documentation/devicetree/bindings/opp/opp-v2-qcom-adreno.yaml F: drivers/gpu/drm/msm/adreno/ F: drivers/gpu/drm/msm/msm_gpu.* From 5f825a2145c3d9f274b1e1c70e2698dcaf5db7d3 Mon Sep 17 00:00:00 2001 From: Qingqing Zhou Date: Thu, 4 Dec 2025 18:51:57 +0530 Subject: [PATCH 0998/2333] FROMLIST: arm64: dts: qcom: talos: add the GPU SMMU node Add the Adreno GPU SMMU node for Talos chipset. Signed-off-by: Qingqing Zhou Signed-off-by: Jie Zhang Signed-off-by: Akhil P Oommen Reviewed-by: Dmitry Baryshkov Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20251204-qcs615-spin-2-v4-5-f5a00c5b663f@oss.qualcomm.com --- arch/arm64/boot/dts/qcom/talos.dtsi | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/talos.dtsi b/arch/arm64/boot/dts/qcom/talos.dtsi index eff8f9f78c6f5..d3a253296fa5e 100644 --- a/arch/arm64/boot/dts/qcom/talos.dtsi +++ b/arch/arm64/boot/dts/qcom/talos.dtsi @@ -1701,6 +1701,31 @@ #power-domain-cells = <1>; }; + adreno_smmu: iommu@50a0000 { + compatible = "qcom,qcs615-smmu-500", "qcom,adreno-smmu", + "qcom,smmu-500", "arm,mmu-500"; + reg = <0x0 0x050a0000 0x0 0x40000>; + #iommu-cells = <2>; + #global-interrupts = <1>; + interrupts = , + , + , + , + , + , + , + , + ; + clocks = <&gcc GCC_GPU_MEMNOC_GFX_CLK>, + <&gpucc GPU_CC_HLOS1_VOTE_GPU_SMMU_CLK>, + <&gcc GCC_GPU_SNOC_DVM_GFX_CLK>; + clock-names = "mem", + "hlos", + "iface"; + power-domains = <&gpucc CX_GDSC>; + dma-coherent; + }; + stm@6002000 { compatible = "arm,coresight-stm", "arm,primecell"; reg = <0x0 0x06002000 0x0 0x1000>, From 22b9fb659a19c90272ec715af9e0444324d79907 Mon Sep 17 00:00:00 2001 From: Jie Zhang Date: Thu, 4 Dec 2025 18:51:58 +0530 Subject: [PATCH 0999/2333] FROMLIST: arm64: dts: qcom: talos: Add gpu and rgmu nodes Add gpu and rgmu nodes for Talos chipset. Signed-off-by: Jie Zhang Signed-off-by: Akhil P Oommen Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20251204-qcs615-spin-2-v4-6-f5a00c5b663f@oss.qualcomm.com --- arch/arm64/boot/dts/qcom/talos.dtsi | 110 ++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/talos.dtsi b/arch/arm64/boot/dts/qcom/talos.dtsi index d3a253296fa5e..e8d7476894b01 100644 --- a/arch/arm64/boot/dts/qcom/talos.dtsi +++ b/arch/arm64/boot/dts/qcom/talos.dtsi @@ -509,6 +509,11 @@ reg = <0x0 0x95900000 0x0 0x1e00000>; no-map; }; + + pil_gpu_mem: pil-gpu@97715000 { + reg = <0x0 0x97715000 0x0 0x2000>; + no-map; + }; }; soc: soc@0 { @@ -1688,6 +1693,111 @@ }; }; + gpu: gpu@5000000 { + compatible = "qcom,adreno-612.0", "qcom,adreno"; + reg = <0x0 0x05000000 0x0 0x40000>, + <0x0 0x0509e000 0x0 0x1000>, + <0x0 0x05061000 0x0 0x800>; + reg-names = "kgsl_3d0_reg_memory", + "cx_mem", + "cx_dbgc"; + + clocks = <&gpucc GPU_CC_GX_GFX3D_CLK>; + clock-names = "core"; + + interrupts = ; + + interconnects = <&gem_noc MASTER_GFX3D QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "gfx-mem"; + + iommus = <&adreno_smmu 0x0 0x401>; + + operating-points-v2 = <&gpu_opp_table>; + power-domains = <&rpmhpd RPMHPD_CX>; + + qcom,gmu = <&gmu>; + + #cooling-cells = <2>; + + status = "disabled"; + + gpu_zap_shader: zap-shader { + memory-region = <&pil_gpu_mem>; + }; + + gpu_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-845000000 { + opp-hz = /bits/ 64 <845000000>; + required-opps = <&rpmhpd_opp_turbo>; + opp-peak-kBps = <7050000>; + }; + + opp-745000000 { + opp-hz = /bits/ 64 <745000000>; + required-opps = <&rpmhpd_opp_nom_l1>; + opp-peak-kBps = <6075000>; + }; + + opp-650000000 { + opp-hz = /bits/ 64 <650000000>; + required-opps = <&rpmhpd_opp_nom>; + opp-peak-kBps = <5287500>; + }; + + opp-500000000 { + opp-hz = /bits/ 64 <500000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + opp-peak-kBps = <3975000>; + }; + + opp-435000000 { + opp-hz = /bits/ 64 <435000000>; + required-opps = <&rpmhpd_opp_svs>; + opp-peak-kBps = <3000000>; + }; + }; + }; + + gmu: gmu@506a000 { + compatible = "qcom,adreno-rgmu-612.0", "qcom,adreno-rgmu"; + reg = <0x0 0x0506a000 0x0 0x34000>; + + clocks = <&gpucc GPU_CC_CX_GMU_CLK>, + <&gpucc GPU_CC_CXO_CLK>, + <&gcc GCC_DDRSS_GPU_AXI_CLK>, + <&gcc GCC_GPU_MEMNOC_GFX_CLK>, + <&gpucc GPU_CC_HLOS1_VOTE_GPU_SMMU_CLK>; + clock-names = "gmu", + "cxo", + "axi", + "memnoc", + "smmu_vote"; + + power-domains = <&gpucc CX_GDSC>, + <&gpucc GX_GDSC>; + power-domain-names = "cx", + "gx"; + + interrupts = , + ; + interrupt-names = "oob", + "gmu"; + + operating-points-v2 = <&gmu_opp_table>; + + gmu_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-200000000 { + opp-hz = /bits/ 64 <200000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + }; + }; + gpucc: clock-controller@5090000 { compatible = "qcom,qcs615-gpucc"; reg = <0 0x05090000 0 0x9000>; From 419c9ab1690cf1655d88268b9a6e5ce04fcb1e63 Mon Sep 17 00:00:00 2001 From: Gaurav Kohli Date: Thu, 4 Dec 2025 18:51:59 +0530 Subject: [PATCH 1000/2333] FROMLIST: arm64: dts: qcom: talos: Add GPU cooling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Unlike the CPU, the GPU does not throttle its speed automatically when it reaches high temperatures. Set up GPU cooling by throttling the GPU speed when it reaches 105°C. Signed-off-by: Gaurav Kohli Signed-off-by: Akhil P Oommen Link: https://lore.kernel.org/r/20251204-qcs615-spin-2-v4-7-f5a00c5b663f@oss.qualcomm.com --- arch/arm64/boot/dts/qcom/talos.dtsi | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/talos.dtsi b/arch/arm64/boot/dts/qcom/talos.dtsi index e8d7476894b01..d312d9eb278c5 100644 --- a/arch/arm64/boot/dts/qcom/talos.dtsi +++ b/arch/arm64/boot/dts/qcom/talos.dtsi @@ -18,6 +18,7 @@ #include #include #include +#include / { interrupt-parent = <&intc>; @@ -4806,12 +4807,25 @@ thermal-sensors = <&tsens0 9>; trips { + gpu_alert0: trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + gpu-critical { temperature = <115000>; hysteresis = <1000>; type = "critical"; }; }; + + cooling-maps { + map0 { + trip = <&gpu_alert0>; + cooling-device = <&gpu THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + }; }; q6-hvx-thermal { From fd40a59c5dd8a09bff57513fce3259b68f92bae5 Mon Sep 17 00:00:00 2001 From: Jie Zhang Date: Thu, 4 Dec 2025 18:52:00 +0530 Subject: [PATCH 1001/2333] FROMLIST: arm64: dts: qcom: qcs615-ride: Enable Adreno 612 GPU Enable GPU for qcs615-ride platform and provide path for zap shader. Signed-off-by: Jie Zhang Signed-off-by: Akhil P Oommen Reviewed-by: Konrad Dybcio Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20251204-qcs615-spin-2-v4-8-f5a00c5b663f@oss.qualcomm.com --- arch/arm64/boot/dts/qcom/qcs615-ride.dts | 8 ++++++++ arch/arm64/boot/dts/qcom/talos.dtsi | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/qcs615-ride.dts b/arch/arm64/boot/dts/qcom/qcs615-ride.dts index d18a6393c4c2d..189e2e3da8612 100644 --- a/arch/arm64/boot/dts/qcom/qcs615-ride.dts +++ b/arch/arm64/boot/dts/qcom/qcs615-ride.dts @@ -372,6 +372,14 @@ }; }; +&gpu { + status = "okay"; +}; + +&gpu_zap_shader { + firmware-name = "qcom/qcs615/a612_zap.mbn"; +}; + &i2c2 { clock-frequency = <400000>; status = "okay"; diff --git a/arch/arm64/boot/dts/qcom/talos.dtsi b/arch/arm64/boot/dts/qcom/talos.dtsi index d312d9eb278c5..64776e96c2404 100644 --- a/arch/arm64/boot/dts/qcom/talos.dtsi +++ b/arch/arm64/boot/dts/qcom/talos.dtsi @@ -1764,7 +1764,7 @@ gmu: gmu@506a000 { compatible = "qcom,adreno-rgmu-612.0", "qcom,adreno-rgmu"; - reg = <0x0 0x0506a000 0x0 0x34000>; + reg = <0x0 0x0506d000 0x0 0x2c000>; clocks = <&gpucc GPU_CC_CX_GMU_CLK>, <&gpucc GPU_CC_CXO_CLK>, From 2f3e81803f9846e8a56e43df89a6eb482dbe94b3 Mon Sep 17 00:00:00 2001 From: Raghavender Reddy Bujala Date: Tue, 23 Dec 2025 18:49:59 +0530 Subject: [PATCH 1002/2333] QCLINUX: arm64: configs: qcom.config: Enable UINPUT Enable UINPUT, which is required for BT AVRC profile to register the events and All passthrough commands of AVRCP will be listed in this event under /dev/input/ Signed-off-by: Raghavender Reddy Bujala --- arch/arm64/configs/qcom.config | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/configs/qcom.config b/arch/arm64/configs/qcom.config index d2fe51d328e50..7dc21568d5cf5 100644 --- a/arch/arm64/configs/qcom.config +++ b/arch/arm64/configs/qcom.config @@ -27,6 +27,7 @@ CONFIG_EXPERT=y CONFIG_GUNYAH_WATCHDOG=y CONFIG_I6300ESB_WDT=y CONFIG_IDLE_INJECT=y +CONFIG_INPUT_UINPUT=y CONFIG_KPROBES=y CONFIG_MACVLAN=y CONFIG_MACVTAP=y From d7fab2fe7aaa65a1417b668d43729783a3987f71 Mon Sep 17 00:00:00 2001 From: Manaf Meethalavalappu Pallikunhi Date: Mon, 15 Dec 2025 16:29:34 +0530 Subject: [PATCH 1003/2333] FROMLIST: arm64: dts: qcom: qcs6490-rb3gen2: Adjust tsens thermal zone configuration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The QCS6490 rb3gen2 board uses the same Qualcomm QCM6490 platform but has a different thermal junction temperature specification due to package-level differences. Update passive/hot trip thresholds to 105°C and critical trip thresholds to 115°C for various subsystem TSENS sensors. Disable CPU cooling maps for CPU TSENS since CPU thermal mitigation is handled automatically in hardware on this board. Signed-off-by: Manaf Meethalavalappu Pallikunhi Link: https://lore.kernel.org/r/20251215105934.2428987-1-manaf.pallikunhi@oss.qualcomm.com --- arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts | 334 +++++++++++++++++++ 1 file changed, 334 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts b/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts index c146161e4bb41..b66bbdc561d05 100644 --- a/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts +++ b/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts @@ -1256,6 +1256,340 @@ }; }; +&thermal_zones { + cpu0-thermal { + trips { + /delete-node/ trip-point0; + /delete-node/ trip-point1; + + cpu-crit { + temperature = <115000>; + }; + }; + + /delete-node/ cooling-maps; + }; + + cpu1-thermal { + trips { + /delete-node/ trip-point0; + /delete-node/ trip-point1; + + cpu-crit { + temperature = <115000>; + }; + }; + + /delete-node/ cooling-maps; + }; + + cpu2-thermal { + trips { + /delete-node/ trip-point0; + /delete-node/ trip-point1; + + cpu-crit { + temperature = <115000>; + }; + }; + + /delete-node/ cooling-maps; + }; + + cpu3-thermal { + trips { + /delete-node/ trip-point0; + /delete-node/ trip-point1; + + cpu-crit { + temperature = <115000>; + }; + }; + + /delete-node/ cooling-maps; + }; + + cpu4-thermal { + trips { + /delete-node/ trip-point0; + /delete-node/ trip-point1; + + cpu-crit { + temperature = <115000>; + }; + }; + + /delete-node/ cooling-maps; + }; + + cpu5-thermal { + trips { + /delete-node/ trip-point0; + /delete-node/ trip-point1; + + cpu-crit { + temperature = <115000>; + }; + }; + + /delete-node/ cooling-maps; + }; + + cpu6-thermal { + trips { + /delete-node/ trip-point0; + /delete-node/ trip-point1; + + cpu-crit { + temperature = <115000>; + }; + }; + + /delete-node/ cooling-maps; + }; + + cpu7-thermal { + trips { + /delete-node/ trip-point0; + /delete-node/ trip-point1; + + cpu-crit { + temperature = <115000>; + }; + }; + + /delete-node/ cooling-maps; + }; + + cpu8-thermal { + trips { + /delete-node/ trip-point0; + /delete-node/ trip-point1; + + cpu-crit { + temperature = <115000>; + }; + }; + + /delete-node/ cooling-maps; + }; + + cpu9-thermal { + trips { + /delete-node/ trip-point0; + /delete-node/ trip-point1; + + cpu-crit { + temperature = <115000>; + }; + }; + + /delete-node/ cooling-maps; + }; + + cpu10-thermal { + trips { + /delete-node/ trip-point0; + /delete-node/ trip-point1; + + cpu-crit { + temperature = <115000>; + }; + }; + + /delete-node/ cooling-maps; + }; + + cpu11-thermal { + trips { + /delete-node/ trip-point0; + /delete-node/ trip-point1; + + cpu-crit { + temperature = <115000>; + }; + }; + + /delete-node/ cooling-maps; + }; + + aoss0-thermal { + trips { + trip-point0 { + temperature = <105000>; + }; + + aoss0-crit { + temperature = <115000>; + }; + }; + }; + + aoss1-thermal { + trips { + trip-point0 { + temperature = <105000>; + }; + + aoss1-crit { + temperature = <115000>; + }; + }; + }; + + cpuss0-thermal { + trips { + /delete-node/ trip-point0; + + cluster0-crit { + temperature = <115000>; + }; + }; + }; + + cpuss1-thermal { + trips { + /delete-node/ trip-point0; + + cluster0-crit { + temperature = <115000>; + }; + }; + }; + + gpuss0-thermal { + trips { + trip-point0 { + temperature = <105000>; + }; + + gpuss0-crit { + temperature = <115000>; + }; + }; + }; + + gpuss1-thermal { + trips { + trip-point0 { + temperature = <105000>; + }; + + gpuss1-crit { + temperature = <115000>; + }; + }; + }; + + nspss0-thermal { + trips { + trip-point0 { + temperature = <105000>; + }; + + nspss0-crit { + temperature = <115000>; + }; + }; + }; + + nspss1-thermal { + trips { + trip-point0 { + temperature = <105000>; + }; + + nspss1-crit { + temperature = <115000>; + }; + }; + }; + + video-thermal { + trips { + trip-point0 { + temperature = <105000>; + }; + + video-crit { + temperature = <115000>; + }; + }; + }; + + ddr-thermal { + trips { + trip-point0 { + temperature = <105000>; + }; + + ddr-crit { + temperature = <115000>; + }; + }; + }; + + mdmss0-thermal { + trips { + trip-point0 { + temperature = <105000>; + }; + + mdmss0-crit { + temperature = <115000>; + }; + }; + }; + + mdmss1-thermal { + trips { + trip-point0 { + temperature = <105000>; + }; + + mdmss1-crit { + temperature = <115000>; + }; + }; + }; + + mdmss2-thermal { + trips { + trip-point0 { + temperature = <105000>; + }; + + mdmss2-crit { + temperature = <115000>; + }; + }; + }; + + mdmss3-thermal { + trips { + trip-point0 { + temperature = <105000>; + }; + + mdmss3-crit { + temperature = <115000>; + }; + }; + }; + + camera0-thermal { + trips { + trip-point0 { + temperature = <105000>; + }; + + camera0-crit { + temperature = <115000>; + }; + }; + }; +}; + &tlmm { gpio-reserved-ranges = <32 2>, /* ADSP */ <48 4>; /* NFC */ From 815abd1709666f2807ee2651a814c883120c04ba Mon Sep 17 00:00:00 2001 From: Filipe Manana Date: Wed, 3 Dec 2025 17:02:00 +0000 Subject: [PATCH 1004/2333] btrfs: do not skip logging new dentries when logging a new name [ Upstream commit 5630f7557de61264ccb4f031d4734a1a97eaed16 ] When we are logging a directory and the log context indicates that we are logging a new name for some other file (that is or was inside that directory), we skip logging the inodes for new dentries in the directory. This is ok most of the time, but if after the rename or link operation that triggered the logging of that directory, we have an explicit fsync of that directory without the directory inode being evicted and reloaded, we end up never logging the inodes for the new dentries that we found during the new name logging, as the next directory fsync will only process dentries that were added after the last time we logged the directory (we are doing an incremental directory logging). So make sure we always log new dentries for a directory even if we are in a context of logging a new name. We started skipping logging inodes for new dentries as of commit c48792c6ee7a ("btrfs: do not log new dentries when logging that a new name exists") and it was fine back then, because when logging a directory we always iterated over all the directory entries (for leaves changed in the current transaction) so a subsequent fsync would always log anything that was previously skipped while logging a directory when logging a new name (with btrfs_log_new_name()). But later support for incrementally logging a directory was added in commit dc2872247ec0 ("btrfs: keep track of the last logged keys when logging a directory"), to avoid checking all dir items every time we log a directory, so the check to skip dentry logging added in the first commit should have been removed when the incremental support for logging a directory was added. A test case for fstests will follow soon. Reported-by: Vyacheslav Kovalevsky Link: https://lore.kernel.org/linux-btrfs/84c4e713-85d6-42b9-8dcf-0722ed26cb05@gmail.com/ Fixes: dc2872247ec0 ("btrfs: keep track of the last logged keys when logging a directory") Reviewed-by: Boris Burkov Signed-off-by: Filipe Manana Signed-off-by: David Sterba Signed-off-by: Sasha Levin --- fs/btrfs/tree-log.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 30f3c3b849c14..f55d886debe2f 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -5872,14 +5872,6 @@ static int log_new_dir_dentries(struct btrfs_trans_handle *trans, struct btrfs_inode *curr_inode = start_inode; int ret = 0; - /* - * If we are logging a new name, as part of a link or rename operation, - * don't bother logging new dentries, as we just want to log the names - * of an inode and that any new parents exist. - */ - if (ctx->logging_new_name) - return 0; - path = btrfs_alloc_path(); if (!path) return -ENOMEM; From f79a80c7fc06df8e4b2b0918608f035136a43fa3 Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Tue, 25 Nov 2025 18:49:56 +1030 Subject: [PATCH 1005/2333] btrfs: fix a potential path leak in print_data_reloc_error() [ Upstream commit 313ef70a9f0f637a09d9ef45222f5bdcf30a354b ] Inside print_data_reloc_error(), if extent_from_logical() failed we return immediately. However there are the following cases where extent_from_logical() can return error but still holds a path: - btrfs_search_slot() returned 0 - No backref item found in extent tree - No flags_ret provided This is not possible in this call site though. So for the above two cases, we can return without releasing the path, causing extent buffer leaks. Fixes: b9a9a85059cd ("btrfs: output affected files when relocation fails") Signed-off-by: Qu Wenruo Reviewed-by: David Sterba Signed-off-by: David Sterba Signed-off-by: Sasha Levin --- fs/btrfs/inode.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 6282911e536f0..51401d586a7b6 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -256,6 +256,7 @@ static void print_data_reloc_error(const struct btrfs_inode *inode, u64 file_off if (ret < 0) { btrfs_err_rl(fs_info, "failed to lookup extent item for logical %llu: %d", logical, ret); + btrfs_release_path(&path); return; } eb = path.nodes[0]; From 75fffc9fef36e98a667b390ccaad8a774dd3360c Mon Sep 17 00:00:00 2001 From: Ondrej Mosnacek Date: Thu, 4 Dec 2025 13:59:16 +0100 Subject: [PATCH 1006/2333] bpf, arm64: Do not audit capability check in do_jit() [ Upstream commit 189e5deb944a6f9c7992355d60bffd8ec2e54a9c ] Analogically to the x86 commit 881a9c9cb785 ("bpf: Do not audit capability check in do_jit()"), change the capable() call to ns_capable_noaudit() in order to avoid spurious SELinux denials in audit log. The commit log from that commit applies here as well: """ The failure of this check only results in a security mitigation being applied, slightly affecting performance of the compiled BPF program. It doesn't result in a failed syscall, an thus auditing a failed LSM permission check for it is unwanted. For example with SELinux, it causes a denial to be reported for confined processes running as root, which tends to be flagged as a problem to be fixed in the policy. Yet dontauditing or allowing CAP_SYS_ADMIN to the domain may not be desirable, as it would allow/silence also other checks - either going against the principle of least privilege or making debugging potentially harder. Fix it by changing it from capable() to ns_capable_noaudit(), which instructs the LSMs to not audit the resulting denials. """ Fixes: f300769ead03 ("arm64: bpf: Only mitigate cBPF programs loaded by unprivileged users") Signed-off-by: Ondrej Mosnacek Link: https://lore.kernel.org/r/20251204125916.441021-1-omosnace@redhat.com Signed-off-by: Alexei Starovoitov Signed-off-by: Sasha Levin --- arch/arm64/net/bpf_jit_comp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/net/bpf_jit_comp.c b/arch/arm64/net/bpf_jit_comp.c index 0c9a50a1e73e7..0dfefeedfe56c 100644 --- a/arch/arm64/net/bpf_jit_comp.c +++ b/arch/arm64/net/bpf_jit_comp.c @@ -1004,7 +1004,7 @@ static void __maybe_unused build_bhb_mitigation(struct jit_ctx *ctx) arm64_get_spectre_v2_state() == SPECTRE_VULNERABLE) return; - if (capable(CAP_SYS_ADMIN)) + if (ns_capable_noaudit(&init_user_ns, CAP_SYS_ADMIN)) return; if (supports_clearbhb(SCOPE_SYSTEM)) { From b7a2957ace3de743ff1bcf1295e662576b1a02ec Mon Sep 17 00:00:00 2001 From: "T.J. Mercier" Date: Wed, 3 Dec 2025 16:03:47 -0800 Subject: [PATCH 1007/2333] bpf: Fix truncated dmabuf iterator reads [ Upstream commit 234483565dbb2b264fdd165927c89fbf3ecf4733 ] If there is a large number (hundreds) of dmabufs allocated, the text output generated from dmabuf_iter_seq_show can exceed common user buffer sizes (e.g. PAGE_SIZE) necessitating multiple start/stop cycles to iterate through all dmabufs. However the dmabuf iterator currently returns NULL in dmabuf_iter_seq_start for all non-zero pos values, which results in the truncation of the output before all dmabufs are handled. After dma_buf_iter_begin / dma_buf_iter_next, the refcount of the buffer is elevated so that the BPF iterator program can run without holding any locks. When a stop occurs, instead of immediately dropping the reference on the buffer, stash a pointer to the buffer in seq->priv until either start is called or the iterator is released. This also enables the resumption of iteration without first walking through the list of dmabufs based on the pos value. Fixes: 76ea95534995 ("bpf: Add dmabuf iterator") Signed-off-by: T.J. Mercier Link: https://lore.kernel.org/r/20251204000348.1413593-1-tjmercier@google.com Signed-off-by: Alexei Starovoitov Signed-off-by: Sasha Levin --- kernel/bpf/dmabuf_iter.c | 56 +++++++++++++++++++++++++++++++++++----- 1 file changed, 49 insertions(+), 7 deletions(-) diff --git a/kernel/bpf/dmabuf_iter.c b/kernel/bpf/dmabuf_iter.c index 4dd7ef7c145ca..cd500248abd95 100644 --- a/kernel/bpf/dmabuf_iter.c +++ b/kernel/bpf/dmabuf_iter.c @@ -6,10 +6,33 @@ #include #include +struct dmabuf_iter_priv { + /* + * If this pointer is non-NULL, the buffer's refcount is elevated to + * prevent destruction between stop/start. If reading is not resumed and + * start is never called again, then dmabuf_iter_seq_fini drops the + * reference when the iterator is released. + */ + struct dma_buf *dmabuf; +}; + static void *dmabuf_iter_seq_start(struct seq_file *seq, loff_t *pos) { - if (*pos) - return NULL; + struct dmabuf_iter_priv *p = seq->private; + + if (*pos) { + struct dma_buf *dmabuf = p->dmabuf; + + if (!dmabuf) + return NULL; + + /* + * Always resume from where we stopped, regardless of the value + * of pos. + */ + p->dmabuf = NULL; + return dmabuf; + } return dma_buf_iter_begin(); } @@ -54,8 +77,11 @@ static void dmabuf_iter_seq_stop(struct seq_file *seq, void *v) { struct dma_buf *dmabuf = v; - if (dmabuf) - dma_buf_put(dmabuf); + if (dmabuf) { + struct dmabuf_iter_priv *p = seq->private; + + p->dmabuf = dmabuf; + } } static const struct seq_operations dmabuf_iter_seq_ops = { @@ -71,11 +97,27 @@ static void bpf_iter_dmabuf_show_fdinfo(const struct bpf_iter_aux_info *aux, seq_puts(seq, "dmabuf iter\n"); } +static int dmabuf_iter_seq_init(void *priv, struct bpf_iter_aux_info *aux) +{ + struct dmabuf_iter_priv *p = (struct dmabuf_iter_priv *)priv; + + p->dmabuf = NULL; + return 0; +} + +static void dmabuf_iter_seq_fini(void *priv) +{ + struct dmabuf_iter_priv *p = (struct dmabuf_iter_priv *)priv; + + if (p->dmabuf) + dma_buf_put(p->dmabuf); +} + static const struct bpf_iter_seq_info dmabuf_iter_seq_info = { .seq_ops = &dmabuf_iter_seq_ops, - .init_seq_private = NULL, - .fini_seq_private = NULL, - .seq_priv_size = 0, + .init_seq_private = dmabuf_iter_seq_init, + .fini_seq_private = dmabuf_iter_seq_fini, + .seq_priv_size = sizeof(struct dmabuf_iter_priv), }; static struct bpf_iter_reg bpf_dmabuf_reg_info = { From d0e177e176e7d1e90c55b17c519c2aa954a4db1e Mon Sep 17 00:00:00 2001 From: Shuran Liu Date: Sat, 6 Dec 2025 22:12:09 +0800 Subject: [PATCH 1008/2333] bpf: Fix verifier assumptions of bpf_d_path's output buffer [ Upstream commit ac44dcc788b950606793e8f9690c30925f59df02 ] Commit 37cce22dbd51 ("bpf: verifier: Refactor helper access type tracking") started distinguishing read vs write accesses performed by helpers. The second argument of bpf_d_path() is a pointer to a buffer that the helper fills with the resulting path. However, its prototype currently uses ARG_PTR_TO_MEM without MEM_WRITE. Before 37cce22dbd51, helper accesses were conservatively treated as potential writes, so this mismatch did not cause issues. Since that commit, the verifier may incorrectly assume that the buffer contents are unchanged across the helper call and base its optimizations on this wrong assumption. This can lead to misbehaviour in BPF programs that read back the buffer, such as prefix comparisons on the returned path. Fix this by marking the second argument of bpf_d_path() as ARG_PTR_TO_MEM | MEM_WRITE so that the verifier correctly models the write to the caller-provided buffer. Fixes: 37cce22dbd51 ("bpf: verifier: Refactor helper access type tracking") Co-developed-by: Zesen Liu Signed-off-by: Zesen Liu Co-developed-by: Peili Gao Signed-off-by: Peili Gao Co-developed-by: Haoran Ni Signed-off-by: Haoran Ni Signed-off-by: Shuran Liu Reviewed-by: Matt Bobrowski Link: https://lore.kernel.org/r/20251206141210.3148-2-electronlsr@gmail.com Signed-off-by: Alexei Starovoitov Signed-off-by: Sasha Levin --- kernel/trace/bpf_trace.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c index 4f87c16d915a0..49e0bdaa7a1bf 100644 --- a/kernel/trace/bpf_trace.c +++ b/kernel/trace/bpf_trace.c @@ -965,7 +965,7 @@ static const struct bpf_func_proto bpf_d_path_proto = { .ret_type = RET_INTEGER, .arg1_type = ARG_PTR_TO_BTF_ID, .arg1_btf_id = &bpf_d_path_btf_ids[0], - .arg2_type = ARG_PTR_TO_MEM, + .arg2_type = ARG_PTR_TO_MEM | MEM_WRITE, .arg3_type = ARG_CONST_SIZE_OR_ZERO, .allowed = bpf_d_path_allowed, }; From 6564f76a9efe7af2244140199faf8f8a18eccfbc Mon Sep 17 00:00:00 2001 From: Deepanshu Kartikey Date: Wed, 10 Dec 2025 18:58:07 +0530 Subject: [PATCH 1009/2333] btrfs: fix memory leak of fs_devices in degraded seed device path [ Upstream commit b57f2ddd28737db6ff0e9da8467f0ab9d707e997 ] In open_seed_devices(), when find_fsid() fails and we're in DEGRADED mode, a new fs_devices is allocated via alloc_fs_devices() but is never added to the seed_list before returning. This contrasts with the normal path where fs_devices is properly added via list_add(). If any error occurs later in read_one_dev() or btrfs_read_chunk_tree(), the cleanup code iterates seed_list to free seed devices, but this orphaned fs_devices is never found and never freed, causing a memory leak. Any devices allocated via add_missing_dev() and attached to this fs_devices are also leaked. Fix this by adding the newly allocated fs_devices to seed_list in the degraded path, consistent with the normal path. Fixes: 5f37583569442 ("Btrfs: move the missing device to its own fs device list") Reported-by: syzbot+eadd98df8bceb15d7fed@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=eadd98df8bceb15d7fed Tested-by: syzbot+eadd98df8bceb15d7fed@syzkaller.appspotmail.com Reviewed-by: Qu Wenruo Signed-off-by: Deepanshu Kartikey Reviewed-by: David Sterba Signed-off-by: David Sterba Signed-off-by: Sasha Levin --- fs/btrfs/volumes.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 2bec544d8ba30..48e717c105c35 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -7178,6 +7178,7 @@ static struct btrfs_fs_devices *open_seed_devices(struct btrfs_fs_info *fs_info, fs_devices->seeding = true; fs_devices->opened = 1; + list_add(&fs_devices->seed_list, &fs_info->fs_devices->seed_list); return fs_devices; } From 6fd59082b6266a2392fd005009b97f6bcf9912f5 Mon Sep 17 00:00:00 2001 From: Filipe Manana Date: Thu, 11 Dec 2025 11:51:19 +0000 Subject: [PATCH 1010/2333] btrfs: fix changeset leak on mmap write after failure to reserve metadata [ Upstream commit 37343524f000d2a64359867d7024a73233d3b438 ] If the call to btrfs_delalloc_reserve_metadata() fails we jump to the 'out_noreserve' label and there we never free the extent_changeset allocated by the previous call to btrfs_check_data_free_space() (if qgroups are enabled). Fix this by calling extent_changeset_free() under the 'out_noreserve' label. Fixes: 6599716de2d6 ("btrfs: fix -ENOSPC mmap write failure on NOCOW files/extents") Reported-by: syzbot+2f8aa76e6acc9fce6638@syzkaller.appspotmail.com Link: https://lore.kernel.org/linux-btrfs/693a635a.a70a0220.33cd7b.0029.GAE@google.com/ Reviewed-by: Qu Wenruo Signed-off-by: Filipe Manana Reviewed-by: David Sterba Signed-off-by: David Sterba Signed-off-by: Sasha Levin --- fs/btrfs/file.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index fa82def46e395..0fee45d35a5f8 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -2018,13 +2018,14 @@ static vm_fault_t btrfs_page_mkwrite(struct vm_fault *vmf) else btrfs_delalloc_release_space(inode, data_reserved, page_start, reserved_space, true); - extent_changeset_free(data_reserved); out_noreserve: if (only_release_metadata) btrfs_check_nocow_unlock(inode); sb_end_pagefault(inode->vfs_inode.i_sb); + extent_changeset_free(data_reserved); + if (ret < 0) return vmf_error(ret); From 4642686699a46718d7f2fb5acd1e9d866a9d9cca Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 13 Dec 2025 17:50:23 -0500 Subject: [PATCH 1011/2333] shmem: fix recovery on rename failures [ Upstream commit e1b4c6a58304fd490124cc2b454d80edc786665c ] maple_tree insertions can fail if we are seriously short on memory; simple_offset_rename() does not recover well if it runs into that. The same goes for simple_offset_rename_exchange(). Moreover, shmem_whiteout() expects that if it succeeds, the caller will progress to d_move(), i.e. that shmem_rename2() won't fail past the successful call of shmem_whiteout(). Not hard to fix, fortunately - mtree_store() can't fail if the index we are trying to store into is already present in the tree as a singleton. For simple_offset_rename_exchange() that's enough - we just need to be careful about the order of operations. For simple_offset_rename() solution is to preinsert the target into the tree for new_dir; the rest can be done without any potentially failing operations. That preinsertion has to be done in shmem_rename2() rather than in simple_offset_rename() itself - otherwise we'd need to deal with the possibility of failure after successful shmem_whiteout(). Fixes: a2e459555c5f ("shmem: stable directory offsets") Reviewed-by: Christian Brauner Reviewed-by: Chuck Lever Signed-off-by: Al Viro Signed-off-by: Sasha Levin --- fs/libfs.c | 50 +++++++++++++++++++--------------------------- include/linux/fs.h | 2 +- mm/shmem.c | 18 ++++++++++++----- 3 files changed, 35 insertions(+), 35 deletions(-) diff --git a/fs/libfs.c b/fs/libfs.c index ce8c496a6940a..6be233c787fd8 100644 --- a/fs/libfs.c +++ b/fs/libfs.c @@ -346,22 +346,22 @@ void simple_offset_remove(struct offset_ctx *octx, struct dentry *dentry) * User space expects the directory offset value of the replaced * (new) directory entry to be unchanged after a rename. * - * Returns zero on success, a negative errno value on failure. + * Caller must have grabbed a slot for new_dentry in the maple_tree + * associated with new_dir, even if dentry is negative. */ -int simple_offset_rename(struct inode *old_dir, struct dentry *old_dentry, - struct inode *new_dir, struct dentry *new_dentry) +void simple_offset_rename(struct inode *old_dir, struct dentry *old_dentry, + struct inode *new_dir, struct dentry *new_dentry) { struct offset_ctx *old_ctx = old_dir->i_op->get_offset_ctx(old_dir); struct offset_ctx *new_ctx = new_dir->i_op->get_offset_ctx(new_dir); long new_offset = dentry2offset(new_dentry); - simple_offset_remove(old_ctx, old_dentry); + if (WARN_ON(!new_offset)) + return; - if (new_offset) { - offset_set(new_dentry, 0); - return simple_offset_replace(new_ctx, old_dentry, new_offset); - } - return simple_offset_add(new_ctx, old_dentry); + simple_offset_remove(old_ctx, old_dentry); + offset_set(new_dentry, 0); + WARN_ON(simple_offset_replace(new_ctx, old_dentry, new_offset)); } /** @@ -388,31 +388,23 @@ int simple_offset_rename_exchange(struct inode *old_dir, long new_index = dentry2offset(new_dentry); int ret; - simple_offset_remove(old_ctx, old_dentry); - simple_offset_remove(new_ctx, new_dentry); + if (WARN_ON(!old_index || !new_index)) + return -EINVAL; - ret = simple_offset_replace(new_ctx, old_dentry, new_index); - if (ret) - goto out_restore; + ret = mtree_store(&new_ctx->mt, new_index, old_dentry, GFP_KERNEL); + if (WARN_ON(ret)) + return ret; - ret = simple_offset_replace(old_ctx, new_dentry, old_index); - if (ret) { - simple_offset_remove(new_ctx, old_dentry); - goto out_restore; + ret = mtree_store(&old_ctx->mt, old_index, new_dentry, GFP_KERNEL); + if (WARN_ON(ret)) { + mtree_store(&new_ctx->mt, new_index, new_dentry, GFP_KERNEL); + return ret; } - ret = simple_rename_exchange(old_dir, old_dentry, new_dir, new_dentry); - if (ret) { - simple_offset_remove(new_ctx, old_dentry); - simple_offset_remove(old_ctx, new_dentry); - goto out_restore; - } + offset_set(old_dentry, new_index); + offset_set(new_dentry, old_index); + simple_rename_exchange(old_dir, old_dentry, new_dir, new_dentry); return 0; - -out_restore: - (void)simple_offset_replace(old_ctx, old_dentry, old_index); - (void)simple_offset_replace(new_ctx, new_dentry, new_index); - return ret; } /** diff --git a/include/linux/fs.h b/include/linux/fs.h index dd3b57cfadeeb..9b2230fb2332f 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -3676,7 +3676,7 @@ struct offset_ctx { void simple_offset_init(struct offset_ctx *octx); int simple_offset_add(struct offset_ctx *octx, struct dentry *dentry); void simple_offset_remove(struct offset_ctx *octx, struct dentry *dentry); -int simple_offset_rename(struct inode *old_dir, struct dentry *old_dentry, +void simple_offset_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry); int simple_offset_rename_exchange(struct inode *old_dir, struct dentry *old_dentry, diff --git a/mm/shmem.c b/mm/shmem.c index 5a3f0f754dc0c..d09ccb2ba21e9 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -4039,6 +4039,7 @@ static int shmem_rename2(struct mnt_idmap *idmap, { struct inode *inode = d_inode(old_dentry); int they_are_dirs = S_ISDIR(inode->i_mode); + bool had_offset = false; int error; if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE | RENAME_WHITEOUT)) @@ -4051,16 +4052,23 @@ static int shmem_rename2(struct mnt_idmap *idmap, if (!simple_empty(new_dentry)) return -ENOTEMPTY; + error = simple_offset_add(shmem_get_offset_ctx(new_dir), new_dentry); + if (error == -EBUSY) + had_offset = true; + else if (unlikely(error)) + return error; + if (flags & RENAME_WHITEOUT) { error = shmem_whiteout(idmap, old_dir, old_dentry); - if (error) + if (error) { + if (!had_offset) + simple_offset_remove(shmem_get_offset_ctx(new_dir), + new_dentry); return error; + } } - error = simple_offset_rename(old_dir, old_dentry, new_dir, new_dentry); - if (error) - return error; - + simple_offset_rename(old_dir, old_dentry, new_dir, new_dentry); if (d_really_is_positive(new_dentry)) { (void) shmem_unlink(new_dir, new_dentry); if (they_are_dirs) { From 142194fb21afe964d2d194cab1fc357cbf87e899 Mon Sep 17 00:00:00 2001 From: Joanne Koong Date: Mon, 22 Sep 2025 11:00:42 -0700 Subject: [PATCH 1012/2333] iomap: adjust read range correctly for non-block-aligned positions [ Upstream commit 7aa6bc3e8766990824f66ca76c19596ce10daf3e ] iomap_adjust_read_range() assumes that the position and length passed in are block-aligned. This is not always the case however, as shown in the syzbot generated case for erofs. This causes too many bytes to be skipped for uptodate blocks, which results in returning the incorrect position and length to read in. If all the blocks are uptodate, this underflows length and returns a position beyond the folio. Fix the calculation to also take into account the block offset when calculating how many bytes can be skipped for uptodate blocks. Signed-off-by: Joanne Koong Tested-by: syzbot@syzkaller.appspotmail.com Reviewed-by: Brian Foster Reviewed-by: Christoph Hellwig Signed-off-by: Christian Brauner Signed-off-by: Sasha Levin --- fs/iomap/buffered-io.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/fs/iomap/buffered-io.c b/fs/iomap/buffered-io.c index 8b847a1e27f13..1c95a0a7b302d 100644 --- a/fs/iomap/buffered-io.c +++ b/fs/iomap/buffered-io.c @@ -240,17 +240,24 @@ static void iomap_adjust_read_range(struct inode *inode, struct folio *folio, * to avoid reading in already uptodate ranges. */ if (ifs) { - unsigned int i; + unsigned int i, blocks_skipped; /* move forward for each leading block marked uptodate */ - for (i = first; i <= last; i++) { + for (i = first; i <= last; i++) if (!ifs_block_is_uptodate(ifs, i)) break; - *pos += block_size; - poff += block_size; - plen -= block_size; - first++; + + blocks_skipped = i - first; + if (blocks_skipped) { + unsigned long block_offset = *pos & (block_size - 1); + unsigned bytes_skipped = + (blocks_skipped << block_bits) - block_offset; + + *pos += bytes_skipped; + poff += bytes_skipped; + plen -= bytes_skipped; } + first = i; /* truncate len if we find any trailing uptodate block(s) */ while (++i <= last) { From bfa4924cbc5204cac3e8fa02048d94be1eb50062 Mon Sep 17 00:00:00 2001 From: Joanne Koong Date: Tue, 11 Nov 2025 11:36:51 -0800 Subject: [PATCH 1013/2333] iomap: account for unaligned end offsets when truncating read range [ Upstream commit 9d875e0eef8ec15b6b1da0cb9a0f8ed13efee89e ] The end position to start truncating from may be at an offset into a block, which under the current logic would result in overtruncation. Adjust the calculation to account for unaligned end offsets. Signed-off-by: Joanne Koong Link: https://patch.msgid.link/20251111193658.3495942-3-joannelkoong@gmail.com Reviewed-by: Christoph Hellwig Reviewed-by: Darrick J. Wong Signed-off-by: Christian Brauner Signed-off-by: Sasha Levin --- fs/iomap/buffered-io.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/fs/iomap/buffered-io.c b/fs/iomap/buffered-io.c index 1c95a0a7b302d..c0fa6acf19375 100644 --- a/fs/iomap/buffered-io.c +++ b/fs/iomap/buffered-io.c @@ -217,6 +217,22 @@ static void ifs_free(struct folio *folio) kfree(ifs); } +/* + * Calculate how many bytes to truncate based off the number of blocks to + * truncate and the end position to start truncating from. + */ +static size_t iomap_bytes_to_truncate(loff_t end_pos, unsigned block_bits, + unsigned blocks_truncated) +{ + unsigned block_size = 1 << block_bits; + unsigned block_offset = end_pos & (block_size - 1); + + if (!block_offset) + return blocks_truncated << block_bits; + + return ((blocks_truncated - 1) << block_bits) + block_offset; +} + /* * Calculate the range inside the folio that we actually need to read. */ @@ -262,7 +278,8 @@ static void iomap_adjust_read_range(struct inode *inode, struct folio *folio, /* truncate len if we find any trailing uptodate block(s) */ while (++i <= last) { if (ifs_block_is_uptodate(ifs, i)) { - plen -= (last - i + 1) * block_size; + plen -= iomap_bytes_to_truncate(*pos + plen, + block_bits, last - i + 1); last = i - 1; break; } @@ -278,7 +295,8 @@ static void iomap_adjust_read_range(struct inode *inode, struct folio *folio, unsigned end = offset_in_folio(folio, isize - 1) >> block_bits; if (first <= end && last > end) - plen -= (last - end) * block_size; + plen -= iomap_bytes_to_truncate(*pos + plen, block_bits, + last - end); } *offp = poff; From ec73412f61d3d36af5ae97df453871fef839628f Mon Sep 17 00:00:00 2001 From: Pankaj Raghav Date: Sun, 21 Sep 2025 12:03:58 +0200 Subject: [PATCH 1014/2333] scripts/faddr2line: Fix "Argument list too long" error [ Upstream commit ff5c0466486ba8d07ab2700380e8fd6d5344b4e9 ] The run_readelf() function reads the entire output of readelf into a single shell variable. For large object files with extensive debug information, the size of this variable can exceed the system's command-line argument length limit. When this variable is subsequently passed to sed via `echo "${out}"`, it triggers an "Argument list too long" error, causing the script to fail. Fix this by redirecting the output of readelf to a temporary file instead of a variable. The sed commands are then modified to read from this file, avoiding the argument length limitation entirely. Signed-off-by: Pankaj Raghav Signed-off-by: Josh Poimboeuf Signed-off-by: Sasha Levin --- scripts/faddr2line | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/scripts/faddr2line b/scripts/faddr2line index 1fa6beef9f978..477b6d2aa3179 100755 --- a/scripts/faddr2line +++ b/scripts/faddr2line @@ -107,14 +107,19 @@ find_dir_prefix() { run_readelf() { local objfile=$1 - local out=$(${READELF} --file-header --section-headers --symbols --wide $objfile) + local tmpfile + tmpfile=$(mktemp) + + ${READELF} --file-header --section-headers --symbols --wide "$objfile" > "$tmpfile" # This assumes that readelf first prints the file header, then the section headers, then the symbols. # Note: It seems that GNU readelf does not prefix section headers with the "There are X section headers" # line when multiple options are given, so let's also match with the "Section Headers:" line. - ELF_FILEHEADER=$(echo "${out}" | sed -n '/There are [0-9]* section headers, starting at offset\|Section Headers:/q;p') - ELF_SECHEADERS=$(echo "${out}" | sed -n '/There are [0-9]* section headers, starting at offset\|Section Headers:/,$p' | sed -n '/Symbol table .* contains [0-9]* entries:/q;p') - ELF_SYMS=$(echo "${out}" | sed -n '/Symbol table .* contains [0-9]* entries:/,$p') + ELF_FILEHEADER=$(sed -n '/There are [0-9]* section headers, starting at offset\|Section Headers:/q;p' "$tmpfile") + ELF_SECHEADERS=$(sed -n '/There are [0-9]* section headers, starting at offset\|Section Headers:/,$p' "$tmpfile" | sed -n '/Symbol table .* contains [0-9]* entries:/q;p') + ELF_SYMS=$(sed -n '/Symbol table .* contains [0-9]* entries:/,$p' "$tmpfile") + + rm -f -- "$tmpfile" } check_vmlinux() { From 43c2e5c2acaae50e99d1c20a5a46e367c442fb3b Mon Sep 17 00:00:00 2001 From: George Kennedy Date: Tue, 8 Oct 2024 08:00:53 -0500 Subject: [PATCH 1015/2333] perf/x86/amd: Check event before enable to avoid GPF [ Upstream commit 866cf36bfee4fba6a492d2dcc5133f857e3446b0 ] On AMD machines cpuc->events[idx] can become NULL in a subtle race condition with NMI->throttle->x86_pmu_stop(). Check event for NULL in amd_pmu_enable_all() before enable to avoid a GPF. This appears to be an AMD only issue. Syzkaller reported a GPF in amd_pmu_enable_all. INFO: NMI handler (perf_event_nmi_handler) took too long to run: 13.143 msecs Oops: general protection fault, probably for non-canonical address 0xdffffc0000000034: 0000 PREEMPT SMP KASAN NOPTI KASAN: null-ptr-deref in range [0x00000000000001a0-0x00000000000001a7] CPU: 0 UID: 0 PID: 328415 Comm: repro_36674776 Not tainted 6.12.0-rc1-syzk RIP: 0010:x86_pmu_enable_event (arch/x86/events/perf_event.h:1195 arch/x86/events/core.c:1430) RSP: 0018:ffff888118009d60 EFLAGS: 00010012 RAX: dffffc0000000000 RBX: 0000000000000000 RCX: 0000000000000000 RDX: 0000000000000034 RSI: 0000000000000000 RDI: 00000000000001a0 RBP: 0000000000000001 R08: 0000000000000000 R09: 0000000000000000 R10: 0000000000000000 R11: 0000000000000000 R12: 0000000000000002 R13: ffff88811802a440 R14: ffff88811802a240 R15: ffff8881132d8601 FS: 00007f097dfaa700(0000) GS:ffff888118000000(0000) GS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00000000200001c0 CR3: 0000000103d56000 CR4: 00000000000006f0 Call Trace: amd_pmu_enable_all (arch/x86/events/amd/core.c:760 (discriminator 2)) x86_pmu_enable (arch/x86/events/core.c:1360) event_sched_out (kernel/events/core.c:1191 kernel/events/core.c:1186 kernel/events/core.c:2346) __perf_remove_from_context (kernel/events/core.c:2435) event_function (kernel/events/core.c:259) remote_function (kernel/events/core.c:92 (discriminator 1) kernel/events/core.c:72 (discriminator 1)) __flush_smp_call_function_queue (./arch/x86/include/asm/jump_label.h:27 ./include/linux/jump_label.h:207 ./include/trace/events/csd.h:64 kernel/smp.c:135 kernel/smp.c:540) __sysvec_call_function_single (./arch/x86/include/asm/jump_label.h:27 ./include/linux/jump_label.h:207 ./arch/x86/include/asm/trace/irq_vectors.h:99 arch/x86/kernel/smp.c:272) sysvec_call_function_single (arch/x86/kernel/smp.c:266 (discriminator 47) arch/x86/kernel/smp.c:266 (discriminator 47)) Reported-by: syzkaller Signed-off-by: George Kennedy Signed-off-by: Peter Zijlstra (Intel) Signed-off-by: Sasha Levin --- arch/x86/events/amd/core.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/arch/x86/events/amd/core.c b/arch/x86/events/amd/core.c index b20661b8621d1..8868f5f5379ba 100644 --- a/arch/x86/events/amd/core.c +++ b/arch/x86/events/amd/core.c @@ -763,7 +763,12 @@ static void amd_pmu_enable_all(int added) if (!test_bit(idx, cpuc->active_mask)) continue; - amd_pmu_enable_event(cpuc->events[idx]); + /* + * FIXME: cpuc->events[idx] can become NULL in a subtle race + * condition with NMI->throttle->x86_pmu_stop(). + */ + if (cpuc->events[idx]) + amd_pmu_enable_event(cpuc->events[idx]); } } From 3ed049fbfb4d75b4e0b8ab54c934f485129d5dc8 Mon Sep 17 00:00:00 2001 From: Doug Berger Date: Thu, 14 Aug 2025 18:22:36 -0700 Subject: [PATCH 1016/2333] sched/deadline: only set free_cpus for online runqueues [ Upstream commit 382748c05e58a9f1935f5a653c352422375566ea ] Commit 16b269436b72 ("sched/deadline: Modify cpudl::free_cpus to reflect rd->online") introduced the cpudl_set/clear_freecpu functions to allow the cpu_dl::free_cpus mask to be manipulated by the deadline scheduler class rq_on/offline callbacks so the mask would also reflect this state. Commit 9659e1eeee28 ("sched/deadline: Remove cpu_active_mask from cpudl_find()") removed the check of the cpu_active_mask to save some processing on the premise that the cpudl::free_cpus mask already reflected the runqueue online state. Unfortunately, there are cases where it is possible for the cpudl_clear function to set the free_cpus bit for a CPU when the deadline runqueue is offline. When this occurs while a CPU is connected to the default root domain the flag may retain the bad state after the CPU has been unplugged. Later, a different CPU that is transitioning through the default root domain may push a deadline task to the powered down CPU when cpudl_find sees its free_cpus bit is set. If this happens the task will not have the opportunity to run. One example is outlined here: https://lore.kernel.org/lkml/20250110233010.2339521-1-opendmb@gmail.com Another occurs when the last deadline task is migrated from a CPU that has an offlined runqueue. The dequeue_task member of the deadline scheduler class will eventually call cpudl_clear and set the free_cpus bit for the CPU. This commit modifies the cpudl_clear function to be aware of the online state of the deadline runqueue so that the free_cpus mask can be updated appropriately. It is no longer necessary to manage the mask outside of the cpudl_set/clear functions so the cpudl_set/clear_freecpu functions are removed. In addition, since the free_cpus mask is now only updated under the cpudl lock the code was changed to use the non-atomic __cpumask functions. Signed-off-by: Doug Berger Signed-off-by: Peter Zijlstra (Intel) Signed-off-by: Sasha Levin --- kernel/sched/cpudeadline.c | 34 +++++++++------------------------- kernel/sched/cpudeadline.h | 4 +--- kernel/sched/deadline.c | 8 ++++---- 3 files changed, 14 insertions(+), 32 deletions(-) diff --git a/kernel/sched/cpudeadline.c b/kernel/sched/cpudeadline.c index cdd740b3f7743..37b572cc8aca2 100644 --- a/kernel/sched/cpudeadline.c +++ b/kernel/sched/cpudeadline.c @@ -166,12 +166,13 @@ int cpudl_find(struct cpudl *cp, struct task_struct *p, * cpudl_clear - remove a CPU from the cpudl max-heap * @cp: the cpudl max-heap context * @cpu: the target CPU + * @online: the online state of the deadline runqueue * * Notes: assumes cpu_rq(cpu)->lock is locked * * Returns: (void) */ -void cpudl_clear(struct cpudl *cp, int cpu) +void cpudl_clear(struct cpudl *cp, int cpu, bool online) { int old_idx, new_cpu; unsigned long flags; @@ -184,7 +185,7 @@ void cpudl_clear(struct cpudl *cp, int cpu) if (old_idx == IDX_INVALID) { /* * Nothing to remove if old_idx was invalid. - * This could happen if a rq_offline_dl is + * This could happen if rq_online_dl or rq_offline_dl is * called for a CPU without -dl tasks running. */ } else { @@ -195,9 +196,12 @@ void cpudl_clear(struct cpudl *cp, int cpu) cp->elements[new_cpu].idx = old_idx; cp->elements[cpu].idx = IDX_INVALID; cpudl_heapify(cp, old_idx); - - cpumask_set_cpu(cpu, cp->free_cpus); } + if (likely(online)) + __cpumask_set_cpu(cpu, cp->free_cpus); + else + __cpumask_clear_cpu(cpu, cp->free_cpus); + raw_spin_unlock_irqrestore(&cp->lock, flags); } @@ -228,7 +232,7 @@ void cpudl_set(struct cpudl *cp, int cpu, u64 dl) cp->elements[new_idx].cpu = cpu; cp->elements[cpu].idx = new_idx; cpudl_heapify_up(cp, new_idx); - cpumask_clear_cpu(cpu, cp->free_cpus); + __cpumask_clear_cpu(cpu, cp->free_cpus); } else { cp->elements[old_idx].dl = dl; cpudl_heapify(cp, old_idx); @@ -237,26 +241,6 @@ void cpudl_set(struct cpudl *cp, int cpu, u64 dl) raw_spin_unlock_irqrestore(&cp->lock, flags); } -/* - * cpudl_set_freecpu - Set the cpudl.free_cpus - * @cp: the cpudl max-heap context - * @cpu: rd attached CPU - */ -void cpudl_set_freecpu(struct cpudl *cp, int cpu) -{ - cpumask_set_cpu(cpu, cp->free_cpus); -} - -/* - * cpudl_clear_freecpu - Clear the cpudl.free_cpus - * @cp: the cpudl max-heap context - * @cpu: rd attached CPU - */ -void cpudl_clear_freecpu(struct cpudl *cp, int cpu) -{ - cpumask_clear_cpu(cpu, cp->free_cpus); -} - /* * cpudl_init - initialize the cpudl structure * @cp: the cpudl max-heap context diff --git a/kernel/sched/cpudeadline.h b/kernel/sched/cpudeadline.h index 11c0f1faa7e11..d7699468eedd5 100644 --- a/kernel/sched/cpudeadline.h +++ b/kernel/sched/cpudeadline.h @@ -19,8 +19,6 @@ struct cpudl { int cpudl_find(struct cpudl *cp, struct task_struct *p, struct cpumask *later_mask); void cpudl_set(struct cpudl *cp, int cpu, u64 dl); -void cpudl_clear(struct cpudl *cp, int cpu); +void cpudl_clear(struct cpudl *cp, int cpu, bool online); int cpudl_init(struct cpudl *cp); -void cpudl_set_freecpu(struct cpudl *cp, int cpu); -void cpudl_clear_freecpu(struct cpudl *cp, int cpu); void cpudl_cleanup(struct cpudl *cp); diff --git a/kernel/sched/deadline.c b/kernel/sched/deadline.c index 7b7671060bf9e..19b1a8b81c76c 100644 --- a/kernel/sched/deadline.c +++ b/kernel/sched/deadline.c @@ -1811,7 +1811,7 @@ static void dec_dl_deadline(struct dl_rq *dl_rq, u64 deadline) if (!dl_rq->dl_nr_running) { dl_rq->earliest_dl.curr = 0; dl_rq->earliest_dl.next = 0; - cpudl_clear(&rq->rd->cpudl, rq->cpu); + cpudl_clear(&rq->rd->cpudl, rq->cpu, rq->online); cpupri_set(&rq->rd->cpupri, rq->cpu, rq->rt.highest_prio.curr); } else { struct rb_node *leftmost = rb_first_cached(&dl_rq->root); @@ -2883,9 +2883,10 @@ static void rq_online_dl(struct rq *rq) if (rq->dl.overloaded) dl_set_overload(rq); - cpudl_set_freecpu(&rq->rd->cpudl, rq->cpu); if (rq->dl.dl_nr_running > 0) cpudl_set(&rq->rd->cpudl, rq->cpu, rq->dl.earliest_dl.curr); + else + cpudl_clear(&rq->rd->cpudl, rq->cpu, true); } /* Assumes rq->lock is held */ @@ -2894,8 +2895,7 @@ static void rq_offline_dl(struct rq *rq) if (rq->dl.overloaded) dl_clear_overload(rq); - cpudl_clear(&rq->rd->cpudl, rq->cpu); - cpudl_clear_freecpu(&rq->rd->cpudl, rq->cpu); + cpudl_clear(&rq->rd->cpudl, rq->cpu, false); } void __init init_sched_dl_class(void) From aab3236ff1da534d2886798caeaaec5fa1f7fe96 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Fri, 7 Nov 2025 17:01:20 +0100 Subject: [PATCH 1017/2333] sched/fair: Revert max_newidle_lb_cost bump [ Upstream commit d206fbad9328ddb68ebabd7cf7413392acd38081 ] Many people reported regressions on their database workloads due to: 155213a2aed4 ("sched/fair: Bump sd->max_newidle_lb_cost when newidle balance fails") For instance Adam Li reported a 6% regression on SpecJBB. Conversely this will regress schbench again; on my machine from 2.22 Mrps/s down to 2.04 Mrps/s. Reported-by: Joseph Salisbury Reported-by: Adam Li Reported-by: Dietmar Eggemann Reported-by: Hazem Mohamed Abuelfotoh Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: Dietmar Eggemann Tested-by: Dietmar Eggemann Tested-by: Chris Mason Link: https://lkml.kernel.org/r/20250626144017.1510594-2-clm@fb.com Link: https://lkml.kernel.org/r/006c9df2-b691-47f1-82e6-e233c3f91faf@oracle.com Link: https://patch.msgid.link/20251107161739.406147760@infradead.org Signed-off-by: Sasha Levin --- kernel/sched/fair.c | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 71d3f4125b0e7..967ca52fb2311 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -12174,14 +12174,8 @@ static inline bool update_newidle_cost(struct sched_domain *sd, u64 cost) /* * Track max cost of a domain to make sure to not delay the * next wakeup on the CPU. - * - * sched_balance_newidle() bumps the cost whenever newidle - * balance fails, and we don't want things to grow out of - * control. Use the sysctl_sched_migration_cost as the upper - * limit, plus a litle extra to avoid off by ones. */ - sd->max_newidle_lb_cost = - min(cost, sysctl_sched_migration_cost + 200); + sd->max_newidle_lb_cost = cost; sd->last_decay_max_lb_cost = jiffies; } else if (time_after(jiffies, sd->last_decay_max_lb_cost + HZ)) { /* @@ -12873,17 +12867,10 @@ static int sched_balance_newidle(struct rq *this_rq, struct rq_flags *rf) t1 = sched_clock_cpu(this_cpu); domain_cost = t1 - t0; + update_newidle_cost(sd, domain_cost); + curr_cost += domain_cost; t0 = t1; - - /* - * Failing newidle means it is not effective; - * bump the cost so we end up doing less of it. - */ - if (!pulled_task) - domain_cost = (3 * sd->max_newidle_lb_cost) / 2; - - update_newidle_cost(sd, domain_cost); } /* From bb4c2f559e576dbabdb5413e92b692d36d9f5703 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Fri, 31 Oct 2025 12:04:24 +0100 Subject: [PATCH 1018/2333] x86/ptrace: Always inline trivial accessors [ Upstream commit 1fe4002cf7f23d70c79bda429ca2a9423ebcfdfa ] A KASAN build bloats these single load/store helpers such that it fails to inline them: vmlinux.o: error: objtool: irqentry_exit+0x5e8: call to instruction_pointer_set() with UACCESS enabled Make sure the compiler isn't allowed to do stupid. Signed-off-by: Peter Zijlstra (Intel) Signed-off-by: Ingo Molnar Link: https://patch.msgid.link/20251031105435.GU4068168@noisy.programming.kicks-ass.net Signed-off-by: Sasha Levin --- arch/x86/include/asm/ptrace.h | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/arch/x86/include/asm/ptrace.h b/arch/x86/include/asm/ptrace.h index 50f75467f73d0..b5dec859bc75a 100644 --- a/arch/x86/include/asm/ptrace.h +++ b/arch/x86/include/asm/ptrace.h @@ -187,12 +187,12 @@ convert_ip_to_linear(struct task_struct *child, struct pt_regs *regs); extern void send_sigtrap(struct pt_regs *regs, int error_code, int si_code); -static inline unsigned long regs_return_value(struct pt_regs *regs) +static __always_inline unsigned long regs_return_value(struct pt_regs *regs) { return regs->ax; } -static inline void regs_set_return_value(struct pt_regs *regs, unsigned long rc) +static __always_inline void regs_set_return_value(struct pt_regs *regs, unsigned long rc) { regs->ax = rc; } @@ -277,34 +277,34 @@ static __always_inline bool ip_within_syscall_gap(struct pt_regs *regs) } #endif -static inline unsigned long kernel_stack_pointer(struct pt_regs *regs) +static __always_inline unsigned long kernel_stack_pointer(struct pt_regs *regs) { return regs->sp; } -static inline unsigned long instruction_pointer(struct pt_regs *regs) +static __always_inline unsigned long instruction_pointer(struct pt_regs *regs) { return regs->ip; } -static inline void instruction_pointer_set(struct pt_regs *regs, - unsigned long val) +static __always_inline +void instruction_pointer_set(struct pt_regs *regs, unsigned long val) { regs->ip = val; } -static inline unsigned long frame_pointer(struct pt_regs *regs) +static __always_inline unsigned long frame_pointer(struct pt_regs *regs) { return regs->bp; } -static inline unsigned long user_stack_pointer(struct pt_regs *regs) +static __always_inline unsigned long user_stack_pointer(struct pt_regs *regs) { return regs->sp; } -static inline void user_stack_pointer_set(struct pt_regs *regs, - unsigned long val) +static __always_inline +void user_stack_pointer_set(struct pt_regs *regs, unsigned long val) { regs->sp = val; } From f91dad0a3b381244183ffbea4cec5a7a69d6f41e Mon Sep 17 00:00:00 2001 From: Cryolitia PukNgae Date: Tue, 25 Nov 2025 16:14:38 +0800 Subject: [PATCH 1019/2333] ACPICA: Avoid walking the Namespace if start_node is NULL [ Upstream commit 9d6c58dae8f6590c746ac5d0012ffe14a77539f0 ] Although commit 0c9992315e73 ("ACPICA: Avoid walking the ACPI Namespace if it is not there") fixed the situation when both start_node and acpi_gbl_root_node are NULL, the Linux kernel mainline now still crashed on Honor Magicbook 14 Pro [1]. That happens due to the access to the member of parent_node in acpi_ns_get_next_node(). The NULL pointer dereference will always happen, no matter whether or not the start_node is equal to ACPI_ROOT_OBJECT, so move the check of start_node being NULL out of the if block. Unfortunately, all the attempts to contact Honor have failed, they refused to provide any technical support for Linux. The bad DSDT table's dump could be found on GitHub [2]. DMI: HONOR FMB-P/FMB-P-PCB, BIOS 1.13 05/08/2025 Link: https://github.com/acpica/acpica/commit/1c1b57b9eba4554cb132ee658dd942c0210ed20d Link: https://gist.github.com/Cryolitia/a860ffc97437dcd2cd988371d5b73ed7 [1] Link: https://github.com/denis-bb/honor-fmb-p-dsdt [2] Signed-off-by: Cryolitia PukNgae Reviewed-by: WangYuli [ rjw: Subject adjustment, changelog edits ] Link: https://patch.msgid.link/20251125-acpica-v1-1-99e63b1b25f8@linux.dev Signed-off-by: Rafael J. Wysocki Signed-off-by: Sasha Levin --- drivers/acpi/acpica/nswalk.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/acpi/acpica/nswalk.c b/drivers/acpi/acpica/nswalk.c index a2ac06a26e921..5670ff5a43cd4 100644 --- a/drivers/acpi/acpica/nswalk.c +++ b/drivers/acpi/acpica/nswalk.c @@ -169,9 +169,12 @@ acpi_ns_walk_namespace(acpi_object_type type, if (start_node == ACPI_ROOT_OBJECT) { start_node = acpi_gbl_root_node; - if (!start_node) { - return_ACPI_STATUS(AE_NO_NAMESPACE); - } + } + + /* Avoid walking the namespace if the StartNode is NULL */ + + if (!start_node) { + return_ACPI_STATUS(AE_NO_NAMESPACE); } /* Null child means "get first node" */ From 29014a19d4176067b88aecc25a483fc525e1ef97 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 1 Oct 2025 13:43:19 +0300 Subject: [PATCH 1020/2333] ACPI: property: Use ACPI functions in acpi_graph_get_next_endpoint() only [ Upstream commit 5d010473cdeaabf6a2d3a9e2aed2186c1b73c213 ] Calling fwnode_get_next_child_node() in ACPI implementation of the fwnode property API is somewhat problematic as the latter is used in the impelementation of the former. Instead of using fwnode_get_next_child_node() in acpi_graph_get_next_endpoint(), call acpi_get_next_subnode() directly instead. Signed-off-by: Sakari Ailus Reviewed-by: Laurent Pinchart Reviewed-by: Jonathan Cameron Link: https://patch.msgid.link/20251001104320.1272752-3-sakari.ailus@linux.intel.com Signed-off-by: Rafael J. Wysocki Signed-off-by: Sasha Levin --- drivers/acpi/property.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c index b12057baaae7b..19737f9e1e16f 100644 --- a/drivers/acpi/property.c +++ b/drivers/acpi/property.c @@ -1472,7 +1472,7 @@ static struct fwnode_handle *acpi_graph_get_next_endpoint( if (!prev) { do { - port = fwnode_get_next_child_node(fwnode, port); + port = acpi_get_next_subnode(fwnode, port); /* * The names of the port nodes begin with "port@" * followed by the number of the port node and they also @@ -1490,13 +1490,13 @@ static struct fwnode_handle *acpi_graph_get_next_endpoint( if (!port) return NULL; - endpoint = fwnode_get_next_child_node(port, prev); + endpoint = acpi_get_next_subnode(port, prev); while (!endpoint) { - port = fwnode_get_next_child_node(fwnode, port); + port = acpi_get_next_subnode(fwnode, port); if (!port) break; if (is_acpi_graph_node(port, "port")) - endpoint = fwnode_get_next_child_node(port, NULL); + endpoint = acpi_get_next_subnode(port, NULL); } /* From 3d9ecabe2953d3827d9bf9198b48d2db573a8259 Mon Sep 17 00:00:00 2001 From: Hal Feng Date: Thu, 16 Oct 2025 16:00:48 +0800 Subject: [PATCH 1021/2333] cpufreq: dt-platdev: Add JH7110S SOC to the allowlist [ Upstream commit 6e7970cab51d01b8f7c56f120486c571c22e1b80 ] Add the compatible strings for supporting the generic cpufreq driver on the StarFive JH7110S SoC. Signed-off-by: Hal Feng Reviewed-by: Heinrich Schuchardt Signed-off-by: Viresh Kumar Signed-off-by: Sasha Levin --- drivers/cpufreq/cpufreq-dt-platdev.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/cpufreq/cpufreq-dt-platdev.c b/drivers/cpufreq/cpufreq-dt-platdev.c index cd1816a12bb99..dc11b62399ad5 100644 --- a/drivers/cpufreq/cpufreq-dt-platdev.c +++ b/drivers/cpufreq/cpufreq-dt-platdev.c @@ -87,6 +87,7 @@ static const struct of_device_id allowlist[] __initconst = { { .compatible = "st-ericsson,u9540", }, { .compatible = "starfive,jh7110", }, + { .compatible = "starfive,jh7110s", }, { .compatible = "ti,omap2", }, { .compatible = "ti,omap4", }, From f916f071e41c637ea73aa0ea6f4551eedbd81ec9 Mon Sep 17 00:00:00 2001 From: Armin Wolf Date: Wed, 8 Oct 2025 01:41:45 +0200 Subject: [PATCH 1022/2333] ACPI: fan: Workaround for 64-bit firmware bug [ Upstream commit 2e00f7a4bb0ac25ec7477b55fe482da39fb4dce8 ] Some firmware implementations use the "Ones" ASL opcode to produce an integer with all bits set in order to indicate missing speed or power readings. This however only works when using 32-bit integers, as the ACPI spec requires a 32-bit integer (0xFFFFFFFF) to be returned for missing speed/power readings. With 64-bit integers the "Ones" opcode produces a 64-bit integer with all bits set, violating the ACPI spec regarding the placeholder value for missing readings. Work around such buggy firmware implementation by also checking for 64-bit integers with all bits set when reading _FST. Signed-off-by: Armin Wolf [ rjw: Typo fix in the changelog ] Link: https://patch.msgid.link/20251007234149.2769-3-W_Armin@gmx.de Signed-off-by: Rafael J. Wysocki Signed-off-by: Sasha Levin --- drivers/acpi/fan.h | 33 +++++++++++++++++++++++++++++++++ drivers/acpi/fan_hwmon.c | 10 +++------- 2 files changed, 36 insertions(+), 7 deletions(-) diff --git a/drivers/acpi/fan.h b/drivers/acpi/fan.h index bedbab0e8e4e9..0d73433c38892 100644 --- a/drivers/acpi/fan.h +++ b/drivers/acpi/fan.h @@ -11,6 +11,7 @@ #define _ACPI_FAN_H_ #include +#include #define ACPI_FAN_DEVICE_IDS \ {"INT3404", }, /* Fan */ \ @@ -60,6 +61,38 @@ struct acpi_fan { struct device_attribute fine_grain_control; }; +/** + * acpi_fan_speed_valid - Check if fan speed value is valid + * @speeed: Speed value returned by the ACPI firmware + * + * Check if the fan speed value returned by the ACPI firmware is valid. This function is + * necessary as ACPI firmware implementations can return 0xFFFFFFFF to signal that the + * ACPI fan does not support speed reporting. Additionally, some buggy ACPI firmware + * implementations return a value larger than the 32-bit integer value defined by + * the ACPI specification when using placeholder values. Such invalid values are also + * detected by this function. + * + * Returns: True if the fan speed value is valid, false otherwise. + */ +static inline bool acpi_fan_speed_valid(u64 speed) +{ + return speed < U32_MAX; +} + +/** + * acpi_fan_power_valid - Check if fan power value is valid + * @power: Power value returned by the ACPI firmware + * + * Check if the fan power value returned by the ACPI firmware is valid. + * See acpi_fan_speed_valid() for details. + * + * Returns: True if the fan power value is valid, false otherwise. + */ +static inline bool acpi_fan_power_valid(u64 power) +{ + return power < U32_MAX; +} + int acpi_fan_get_fst(acpi_handle handle, struct acpi_fan_fst *fst); int acpi_fan_create_attributes(struct acpi_device *device); void acpi_fan_delete_attributes(struct acpi_device *device); diff --git a/drivers/acpi/fan_hwmon.c b/drivers/acpi/fan_hwmon.c index 4b2c2007f2d7f..47a02ef5a6067 100644 --- a/drivers/acpi/fan_hwmon.c +++ b/drivers/acpi/fan_hwmon.c @@ -15,10 +15,6 @@ #include "fan.h" -/* Returned when the ACPI fan does not support speed reporting */ -#define FAN_SPEED_UNAVAILABLE U32_MAX -#define FAN_POWER_UNAVAILABLE U32_MAX - static struct acpi_fan_fps *acpi_fan_get_current_fps(struct acpi_fan *fan, u64 control) { unsigned int i; @@ -77,7 +73,7 @@ static umode_t acpi_fan_hwmon_is_visible(const void *drvdata, enum hwmon_sensor_ * when the associated attribute should not be created. */ for (i = 0; i < fan->fps_count; i++) { - if (fan->fps[i].power != FAN_POWER_UNAVAILABLE) + if (acpi_fan_power_valid(fan->fps[i].power)) return 0444; } @@ -106,7 +102,7 @@ static int acpi_fan_hwmon_read(struct device *dev, enum hwmon_sensor_types type, case hwmon_fan: switch (attr) { case hwmon_fan_input: - if (fst.speed == FAN_SPEED_UNAVAILABLE) + if (!acpi_fan_speed_valid(fst.speed)) return -ENODEV; if (fst.speed > LONG_MAX) @@ -134,7 +130,7 @@ static int acpi_fan_hwmon_read(struct device *dev, enum hwmon_sensor_types type, if (!fps) return -EIO; - if (fps->power == FAN_POWER_UNAVAILABLE) + if (!acpi_fan_power_valid(fps->power)) return -ENODEV; if (fps->power > LONG_MAX / MICROWATT_PER_MILLIWATT) From e486de4c945d32e6205aa9b0404880956d01bb83 Mon Sep 17 00:00:00 2001 From: Shuhao Fu Date: Mon, 6 Oct 2025 03:31:17 +0800 Subject: [PATCH 1023/2333] cpufreq: s5pv210: fix refcount leak [ Upstream commit 2de5cb96060a1664880d65b120e59485a73588a8 ] In function `s5pv210_cpu_init`, a possible refcount inconsistency has been identified, causing a resource leak. Why it is a bug: 1. For every clk_get, there should be a matching clk_put on every successive error handling path. 2. After calling `clk_get(dmc1_clk)`, variable `dmc1_clk` will not be freed even if any error happens. How it is fixed: For every failed path, an extra goto label is added to ensure `dmc1_clk` will be freed regardlessly. Signed-off-by: Shuhao Fu Signed-off-by: Viresh Kumar Signed-off-by: Sasha Levin --- drivers/cpufreq/s5pv210-cpufreq.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/cpufreq/s5pv210-cpufreq.c b/drivers/cpufreq/s5pv210-cpufreq.c index 4215621deb3fe..ba8a1c96427a1 100644 --- a/drivers/cpufreq/s5pv210-cpufreq.c +++ b/drivers/cpufreq/s5pv210-cpufreq.c @@ -518,7 +518,7 @@ static int s5pv210_cpu_init(struct cpufreq_policy *policy) if (policy->cpu != 0) { ret = -EINVAL; - goto out_dmc1; + goto out; } /* @@ -530,7 +530,7 @@ static int s5pv210_cpu_init(struct cpufreq_policy *policy) if ((mem_type != LPDDR) && (mem_type != LPDDR2)) { pr_err("CPUFreq doesn't support this memory type\n"); ret = -EINVAL; - goto out_dmc1; + goto out; } /* Find current refresh counter and frequency each DMC */ @@ -544,6 +544,8 @@ static int s5pv210_cpu_init(struct cpufreq_policy *policy) cpufreq_generic_init(policy, s5pv210_freq_table, 40000); return 0; +out: + clk_put(dmc1_clk); out_dmc1: clk_put(dmc0_clk); out_dmc0: From 63859f6da00d6f6b7ed5b64453d9ff7f9b8d24c7 Mon Sep 17 00:00:00 2001 From: Aboorva Devarajan Date: Mon, 6 Oct 2025 07:09:54 +0530 Subject: [PATCH 1024/2333] cpuidle: menu: Use residency threshold in polling state override decisions [ Upstream commit 07d815701274d156ad8c7c088a52e01642156fb8 ] On virtualized PowerPC (pseries) systems, where only one polling state (Snooze) and one deep state (CEDE) are available, selecting CEDE when the predicted idle duration is less than the target residency of CEDE state can hurt performance. In such cases, the entry/exit overhead of CEDE outweighs the power savings, leading to unnecessary state transitions and higher latency. Menu governor currently contains a special-case rule that prioritizes the first non-polling state over polling, even when its target residency is much longer than the predicted idle duration. On PowerPC/pseries, where the gap between the polling state (Snooze) and the first non-polling state (CEDE) is large, this behavior causes performance regressions. Refine that special case by adding an extra requirement: the first non-polling state can only be chosen if its target residency is below the defined RESIDENCY_THRESHOLD_NS. If this condition is not satisfied, polling is allowed instead, avoiding suboptimal non-polling state entries. This change is limited to the single special-case rule for the first non-polling state. The general non-polling state selection logic in the menu governor remains unchanged. Performance improvement observed with pgbench on PowerPC (pseries) system: +---------------------------+------------+------------+------------+ | Metric | Baseline | Patched | Change (%) | +---------------------------+------------+------------+------------+ | Transactions/sec (TPS) | 495,210 | 536,982 | +8.45% | | Avg latency (ms) | 0.163 | 0.150 | -7.98% | +---------------------------+------------+------------+------------+ CPUIdle state usage: +--------------+--------------+-------------+ | Metric | Baseline | Patched | +--------------+--------------+-------------+ | Total usage | 12,735,820 | 13,918,442 | | Above usage | 11,401,520 | 1,598,210 | | Below usage | 20,145 | 702,395 | +--------------+--------------+-------------+ Above/Total and Below/Total usage percentages: +------------------------+-----------+---------+ | Metric | Baseline | Patched | +------------------------+-----------+---------+ | Above % (Above/Total) | 89.56% | 11.49% | | Below % (Below/Total) | 0.16% | 5.05% | | Total cpuidle miss (%) | 89.72% | 16.54% | +------------------------+-----------+---------+ The results indicate that restricting CEDE selection to cases where its residency matches the predicted idle time reduces mispredictions, lowers unnecessary state transitions, and improves overall throughput. Reviewed-by: Christian Loehle Signed-off-by: Aboorva Devarajan [ rjw: Changelog edits, rebase ] Link: https://patch.msgid.link/20251006013954.17972-1-aboorvad@linux.ibm.com Signed-off-by: Rafael J. Wysocki Signed-off-by: Sasha Levin --- drivers/cpuidle/governors/menu.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c index 23239b0c04f95..64d6f7a1c7766 100644 --- a/drivers/cpuidle/governors/menu.c +++ b/drivers/cpuidle/governors/menu.c @@ -317,12 +317,13 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, } /* - * Use a physical idle state, not busy polling, unless a timer - * is going to trigger soon enough or the exit latency of the - * idle state in question is greater than the predicted idle - * duration. + * Use a physical idle state instead of busy polling so long as + * its target residency is below the residency threshold, its + * exit latency is not greater than the predicted idle duration, + * and the next timer doesn't expire soon. */ if ((drv->states[idx].flags & CPUIDLE_FLAG_POLLING) && + s->target_residency_ns < RESIDENCY_THRESHOLD_NS && s->target_residency_ns <= data->next_timer_ns && s->exit_latency_ns <= predicted_ns) { predicted_ns = s->target_residency_ns; From 3ef4a51315a92fb88f7541516af1b19aa0305712 Mon Sep 17 00:00:00 2001 From: Yu Peng Date: Thu, 30 Oct 2025 20:37:57 +0800 Subject: [PATCH 1025/2333] x86/microcode: Mark early_parse_cmdline() as __init [ Upstream commit ca8313fd83399ea1d18e695c2ae9b259985c9e1f ] Fix section mismatch warning reported by modpost: .text:early_parse_cmdline() -> .init.data:boot_command_line The function early_parse_cmdline() is only called during init and accesses init data, so mark it __init to match its usage. [ bp: This happens only when the toolchain fails to inline the function and I haven't been able to reproduce it with any toolchain I'm using. Patch is obviously correct regardless. ] Signed-off-by: Yu Peng Signed-off-by: Borislav Petkov (AMD) Link: https://patch.msgid.link/all/20251030123757.1410904-1-pengyu@kylinos.cn Signed-off-by: Sasha Levin --- arch/x86/kernel/cpu/microcode/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kernel/cpu/microcode/core.c b/arch/x86/kernel/cpu/microcode/core.c index f75c140906d00..539edd6d6dc8c 100644 --- a/arch/x86/kernel/cpu/microcode/core.c +++ b/arch/x86/kernel/cpu/microcode/core.c @@ -136,7 +136,7 @@ bool __init microcode_loader_disabled(void) return dis_ucode_ldr; } -static void early_parse_cmdline(void) +static void __init early_parse_cmdline(void) { char cmd_buf[64] = {}; char *s, *p = cmd_buf; From ab665eb9997198408b915724df6954156260bfd3 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 18 Sep 2025 13:54:55 +0200 Subject: [PATCH 1026/2333] scripts: kdoc_parser.py: warn about Python version only once [ Upstream commit ade9b9576e2f000fb2ef0ac3bcd26e1167fd813b ] When running kernel-doc over multiple documents, it emits one error message per file with is not what we want: $ python3.6 scripts/kernel-doc.py . --none ... Warning: ./include/trace/events/swiotlb.h:0 Python 3.7 or later is required for correct results Warning: ./include/trace/events/iommu.h:0 Python 3.7 or later is required for correct results Warning: ./include/trace/events/sock.h:0 Python 3.7 or later is required for correct results ... Change the logic to warn it only once at the library: $ python3.6 scripts/kernel-doc.py . --none Warning: Python 3.7 or later is required for correct results Warning: ./include/cxl/features.h:0 Python 3.7 or later is required for correct results When running from command line, it warns twice, but that sounds ok. Signed-off-by: Mauro Carvalho Chehab Message-ID: <68e54cf8b1201d1f683aad9bc710a99421910356.1758196090.git.mchehab+huawei@kernel.org> Signed-off-by: Jonathan Corbet Signed-off-by: Sasha Levin --- scripts/lib/kdoc/kdoc_parser.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/scripts/lib/kdoc/kdoc_parser.py b/scripts/lib/kdoc/kdoc_parser.py index 2376f180b1fa9..89d920e0b65ca 100644 --- a/scripts/lib/kdoc/kdoc_parser.py +++ b/scripts/lib/kdoc/kdoc_parser.py @@ -350,6 +350,7 @@ def dump_section(self, start_new=True): self.section = SECTION_DEFAULT self._contents = [] +python_warning = False class KernelDoc: """ @@ -383,9 +384,13 @@ def __init__(self, config, fname): # We need Python 3.7 for its "dicts remember the insertion # order" guarantee # - if sys.version_info.major == 3 and sys.version_info.minor < 7: + global python_warning + if (not python_warning and + sys.version_info.major == 3 and sys.version_info.minor < 7): + self.emit_msg(0, 'Python 3.7 or later is required for correct results') + python_warning = True def emit_msg(self, ln, msg, warning=True): """Emit a message""" From c9266cafb2772d7ff3adae699b86b2e12d6d4d5f Mon Sep 17 00:00:00 2001 From: Song Liu Date: Mon, 13 Oct 2025 10:30:19 -0700 Subject: [PATCH 1027/2333] livepatch: Match old_sympos 0 and 1 in klp_find_func() [ Upstream commit 139560e8b973402140cafeb68c656c1374bd4c20 ] When there is only one function of the same name, old_sympos of 0 and 1 are logically identical. Match them in klp_find_func(). This is to avoid a corner case with different toolchain behavior. In this specific issue, two versions of kpatch-build were used to build livepatch for the same kernel. One assigns old_sympos == 0 for unique local functions, the other assigns old_sympos == 1 for unique local functions. Both versions work fine by themselves. (PS: This behavior change was introduced in a downstream version of kpatch-build. This change does not exist in upstream kpatch-build.) However, during livepatch upgrade (with the replace flag set) from a patch built with one version of kpatch-build to the same fix built with the other version of kpatch-build, livepatching fails with errors like: [ 14.218706] sysfs: cannot create duplicate filename 'xxx/somefunc,1' ... [ 14.219466] Call Trace: [ 14.219468] [ 14.219469] dump_stack_lvl+0x47/0x60 [ 14.219474] sysfs_warn_dup.cold+0x17/0x27 [ 14.219476] sysfs_create_dir_ns+0x95/0xb0 [ 14.219479] kobject_add_internal+0x9e/0x260 [ 14.219483] kobject_add+0x68/0x80 [ 14.219485] ? kstrdup+0x3c/0xa0 [ 14.219486] klp_enable_patch+0x320/0x830 [ 14.219488] patch_init+0x443/0x1000 [ccc_0_6] [ 14.219491] ? 0xffffffffa05eb000 [ 14.219492] do_one_initcall+0x2e/0x190 [ 14.219494] do_init_module+0x67/0x270 [ 14.219496] init_module_from_file+0x75/0xa0 [ 14.219499] idempotent_init_module+0x15a/0x240 [ 14.219501] __x64_sys_finit_module+0x61/0xc0 [ 14.219503] do_syscall_64+0x5b/0x160 [ 14.219505] entry_SYSCALL_64_after_hwframe+0x4b/0x53 [ 14.219507] RIP: 0033:0x7f545a4bd96d ... [ 14.219516] kobject: kobject_add_internal failed for somefunc,1 with -EEXIST, don't try to register things with the same name ... This happens because klp_find_func() thinks somefunc with old_sympos==0 is not the same as somefunc with old_sympos==1, and klp_add_object_nops adds another xxx/func,1 to the list of functions to patch. Signed-off-by: Song Liu Acked-by: Josh Poimboeuf [pmladek@suse.com: Fixed some typos.] Reviewed-by: Petr Mladek Tested-by: Petr Mladek Signed-off-by: Petr Mladek Signed-off-by: Sasha Levin --- kernel/livepatch/core.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c index 0e73fac55f8eb..4e7a5cbc40a91 100644 --- a/kernel/livepatch/core.c +++ b/kernel/livepatch/core.c @@ -88,8 +88,14 @@ static struct klp_func *klp_find_func(struct klp_object *obj, struct klp_func *func; klp_for_each_func(obj, func) { + /* + * Besides identical old_sympos, also consider old_sympos + * of 0 and 1 are identical. + */ if ((strcmp(old_func->old_name, func->old_name) == 0) && - (old_func->old_sympos == func->old_sympos)) { + ((old_func->old_sympos == func->old_sympos) || + (old_func->old_sympos == 0 && func->old_sympos == 1) || + (old_func->old_sympos == 1 && func->old_sympos == 0))) { return func; } } From 1c553c454f540e1f312a5d47280612fd50d52091 Mon Sep 17 00:00:00 2001 From: "Mario Limonciello (AMD)" Date: Wed, 29 Oct 2025 11:15:01 -0500 Subject: [PATCH 1028/2333] crypto: ccp - Add support for PCI device 0x115A [ Upstream commit 9fc6290117259a8dbf8247cb54559df62fd1550f ] PCI device 0x115A is similar to pspv5, except it doesn't have platform access mailbox support. Signed-off-by: Mario Limonciello (AMD) Acked-by: Tom Lendacky Signed-off-by: Herbert Xu Signed-off-by: Sasha Levin --- drivers/crypto/ccp/sp-pci.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/drivers/crypto/ccp/sp-pci.c b/drivers/crypto/ccp/sp-pci.c index e7bb803912a6d..8891ceee1d7d0 100644 --- a/drivers/crypto/ccp/sp-pci.c +++ b/drivers/crypto/ccp/sp-pci.c @@ -459,6 +459,17 @@ static const struct psp_vdata pspv6 = { .intsts_reg = 0x10514, /* P2CMSG_INTSTS */ }; +static const struct psp_vdata pspv7 = { + .tee = &teev2, + .cmdresp_reg = 0x10944, /* C2PMSG_17 */ + .cmdbuff_addr_lo_reg = 0x10948, /* C2PMSG_18 */ + .cmdbuff_addr_hi_reg = 0x1094c, /* C2PMSG_19 */ + .bootloader_info_reg = 0x109ec, /* C2PMSG_59 */ + .feature_reg = 0x109fc, /* C2PMSG_63 */ + .inten_reg = 0x10510, /* P2CMSG_INTEN */ + .intsts_reg = 0x10514, /* P2CMSG_INTSTS */ +}; + #endif static const struct sp_dev_vdata dev_vdata[] = { @@ -525,6 +536,13 @@ static const struct sp_dev_vdata dev_vdata[] = { .psp_vdata = &pspv6, #endif }, + { /* 9 */ + .bar = 2, +#ifdef CONFIG_CRYPTO_DEV_SP_PSP + .psp_vdata = &pspv7, +#endif + }, + }; static const struct pci_device_id sp_pci_table[] = { { PCI_VDEVICE(AMD, 0x1537), (kernel_ulong_t)&dev_vdata[0] }, @@ -539,6 +557,7 @@ static const struct pci_device_id sp_pci_table[] = { { PCI_VDEVICE(AMD, 0x17E0), (kernel_ulong_t)&dev_vdata[7] }, { PCI_VDEVICE(AMD, 0x156E), (kernel_ulong_t)&dev_vdata[8] }, { PCI_VDEVICE(AMD, 0x17D8), (kernel_ulong_t)&dev_vdata[8] }, + { PCI_VDEVICE(AMD, 0x115A), (kernel_ulong_t)&dev_vdata[9] }, /* Last entry must be zero */ { 0, } }; From 5859a556db4b3ba93bcef21c5d448467a9bc6b53 Mon Sep 17 00:00:00 2001 From: Konstantin Komarov Date: Mon, 1 Sep 2025 11:48:48 +0300 Subject: [PATCH 1029/2333] fs/ntfs3: Support timestamps prior to epoch [ Upstream commit 5180138604323895b5c291eca6aa7c20be494ade ] Before it used an unsigned 64-bit type, which prevented proper handling of timestamps earlier than 1970-01-01. Switch to a signed 64-bit type to support pre-epoch timestamps. The issue was caught by xfstests. Signed-off-by: Konstantin Komarov Signed-off-by: Sasha Levin --- fs/ntfs3/ntfs_fs.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/fs/ntfs3/ntfs_fs.h b/fs/ntfs3/ntfs_fs.h index 630128716ea73..2649fbe16669d 100644 --- a/fs/ntfs3/ntfs_fs.h +++ b/fs/ntfs3/ntfs_fs.h @@ -979,11 +979,12 @@ static inline __le64 kernel2nt(const struct timespec64 *ts) */ static inline void nt2kernel(const __le64 tm, struct timespec64 *ts) { - u64 t = le64_to_cpu(tm) - _100ns2seconds * SecondsToStartOf1970; + s32 t32; + /* use signed 64 bit to support timestamps prior to epoch. xfstest 258. */ + s64 t = le64_to_cpu(tm) - _100ns2seconds * SecondsToStartOf1970; - // WARNING: do_div changes its first argument(!) - ts->tv_nsec = do_div(t, _100ns2seconds) * 100; - ts->tv_sec = t; + ts->tv_sec = div_s64_rem(t, _100ns2seconds, &t32); + ts->tv_nsec = t32 * 100; } static inline struct ntfs_sb_info *ntfs_sb(struct super_block *sb) From f44e3d622d74e3e77cd672046e7afae6f337d73c Mon Sep 17 00:00:00 2001 From: Mikhail Malyshev Date: Wed, 15 Oct 2025 16:34:52 +0000 Subject: [PATCH 1030/2333] kbuild: Use objtree for module signing key path [ Upstream commit af61da281f52aba0c5b090bafb3a31c5739850ff ] When building out-of-tree modules with CONFIG_MODULE_SIG_FORCE=y, module signing fails because the private key path uses $(srctree) while the public key path uses $(objtree). Since signing keys are generated in the build directory during kernel compilation, both paths should use $(objtree) for consistency. This causes SSL errors like: SSL error:02001002:system library:fopen:No such file or directory sign-file: /kernel-src/certs/signing_key.pem The issue occurs because: - sig-key uses: $(srctree)/certs/signing_key.pem (source tree) - cmd_sign uses: $(objtree)/certs/signing_key.x509 (build tree) But both keys are generated in $(objtree) during the build. This complements commit 25ff08aa43e37 ("kbuild: Fix signing issue for external modules") which fixed the scripts path and public key path, but missed the private key path inconsistency. Fixes out-of-tree module signing for configurations with separate source and build directories (e.g., O=/kernel-out). Signed-off-by: Mikhail Malyshev Reviewed-by: Nathan Chancellor Tested-by: Nicolas Schier Link: https://patch.msgid.link/20251015163452.3754286-1-mike.malyshev@gmail.com Signed-off-by: Nicolas Schier Signed-off-by: Sasha Levin --- scripts/Makefile.modinst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/Makefile.modinst b/scripts/Makefile.modinst index 1628198f3e830..9ba45e5b32b18 100644 --- a/scripts/Makefile.modinst +++ b/scripts/Makefile.modinst @@ -100,7 +100,7 @@ endif # Don't stop modules_install even if we can't sign external modules. # ifeq ($(filter pkcs11:%, $(CONFIG_MODULE_SIG_KEY)),) -sig-key := $(if $(wildcard $(CONFIG_MODULE_SIG_KEY)),,$(srctree)/)$(CONFIG_MODULE_SIG_KEY) +sig-key := $(if $(wildcard $(CONFIG_MODULE_SIG_KEY)),,$(objtree)/)$(CONFIG_MODULE_SIG_KEY) else sig-key := $(CONFIG_MODULE_SIG_KEY) endif From b3c151fe8f543f1a0b8b5df16ce5d97afa5ec85a Mon Sep 17 00:00:00 2001 From: Pedro Demarchi Gomes Date: Fri, 3 Oct 2025 12:38:50 -0300 Subject: [PATCH 1031/2333] ntfs: set dummy blocksize to read boot_block when mounting [ Upstream commit d1693a7d5a38acf6424235a6070bcf5b186a360d ] When mounting, sb->s_blocksize is used to read the boot_block without being defined or validated. Set a dummy blocksize before attempting to read the boot_block. The issue can be triggered with the following syz reproducer: mkdirat(0xffffffffffffff9c, &(0x7f0000000080)='./file1\x00', 0x0) r4 = openat$nullb(0xffffffffffffff9c, &(0x7f0000000040), 0x121403, 0x0) ioctl$FS_IOC_SETFLAGS(r4, 0x40081271, &(0x7f0000000980)=0x4000) mount(&(0x7f0000000140)=@nullb, &(0x7f0000000040)='./cgroup\x00', &(0x7f0000000000)='ntfs3\x00', 0x2208004, 0x0) syz_clone(0x88200200, 0x0, 0x0, 0x0, 0x0, 0x0) Here, the ioctl sets the bdev block size to 16384. During mount, get_tree_bdev_flags() calls sb_set_blocksize(sb, block_size(bdev)), but since block_size(bdev) > PAGE_SIZE, sb_set_blocksize() leaves sb->s_blocksize at zero. Later, ntfs_init_from_boot() attempts to read the boot_block while sb->s_blocksize is still zero, which triggers the bug. Reported-by: syzbot+f4f84b57a01d6b8364ad@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=f4f84b57a01d6b8364ad Signed-off-by: Pedro Demarchi Gomes [almaz.alexandrovich@paragon-software.com: changed comment style, added return value handling] Signed-off-by: Konstantin Komarov Signed-off-by: Sasha Levin --- fs/ntfs3/super.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/fs/ntfs3/super.c b/fs/ntfs3/super.c index ddff94c091b8c..e6c0908e27c29 100644 --- a/fs/ntfs3/super.c +++ b/fs/ntfs3/super.c @@ -933,6 +933,11 @@ static int ntfs_init_from_boot(struct super_block *sb, u32 sector_size, sbi->volume.blocks = dev_size >> PAGE_SHIFT; + /* Set dummy blocksize to read boot_block. */ + if (!sb_min_blocksize(sb, PAGE_SIZE)) { + return -EINVAL; + } + read_boot: bh = ntfs_bread(sb, boot_block); if (!bh) From 772e0a8809f17c3fffec98ab6422fe2bb13dace2 Mon Sep 17 00:00:00 2001 From: Viacheslav Dubeyko Date: Fri, 31 Oct 2025 17:12:30 -0700 Subject: [PATCH 1032/2333] hfsplus: fix volume corruption issue for generic/070 [ Upstream commit ed490f36f439b877393c12a2113601e4145a5a56 ] The xfstests' test-case generic/070 leaves HFS+ volume in corrupted state: sudo ./check generic/070 FSTYP -- hfsplus PLATFORM -- Linux/x86_64 hfsplus-testing-0001 6.17.0-rc1+ #4 SMP PREEMPT_DYNAMIC Wed Oct 1 15:02:44 PDT 2025 MKFS_OPTIONS -- /dev/loop51 MOUNT_OPTIONS -- /dev/loop51 /mnt/scratch generic/070 _check_generic_filesystem: filesystem on /dev/loop50 is inconsistent (see xfstests-dev/results//generic/070.full for details) Ran: generic/070 Failures: generic/070 Failed 1 of 1 tests sudo fsck.hfsplus -d /dev/loop50 ** /dev/loop50 Using cacheBlockSize=32K cacheTotalBlock=1024 cacheSize=32768K. Executing fsck_hfs (version 540.1-Linux). ** Checking non-journaled HFS Plus Volume. The volume name is test ** Checking extents overflow file. Unused node is not erased (node = 1) ** Checking catalog file. ** Checking multi-linked files. ** Checking catalog hierarchy. ** Checking extended attributes file. ** Checking volume bitmap. ** Checking volume information. Verify Status: VIStat = 0x0000, ABTStat = 0x0000 EBTStat = 0x0004 CBTStat = 0x0000 CatStat = 0x00000000 ** Repairing volume. ** Rechecking volume. ** Checking non-journaled HFS Plus Volume. The volume name is test ** Checking extents overflow file. ** Checking catalog file. ** Checking multi-linked files. ** Checking catalog hierarchy. ** Checking extended attributes file. ** Checking volume bitmap. ** Checking volume information. ** The volume test was repaired successfully. It is possible to see that fsck.hfsplus detected not erased and unused node for the case of extents overflow file. The HFS+ logic has special method that defines if the node should be erased: bool hfs_bnode_need_zeroout(struct hfs_btree *tree) { struct super_block *sb = tree->inode->i_sb; struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb); const u32 volume_attr = be32_to_cpu(sbi->s_vhdr->attributes); return tree->cnid == HFSPLUS_CAT_CNID && volume_attr & HFSPLUS_VOL_UNUSED_NODE_FIX; } However, it is possible to see that this method works only for the case of catalog file. But debugging of the issue has shown that HFSPLUS_VOL_UNUSED_NODE_FIX attribute has been requested for the extents overflow file too: catalog file kernel: hfsplus: node 4, num_recs 0, flags 0x10 kernel: hfsplus: tree->cnid 4, volume_attr 0x80000800 extents overflow file kernel: hfsplus: node 1, num_recs 0, flags 0x10 kernel: hfsplus: tree->cnid 3, volume_attr 0x80000800 This patch modifies the hfs_bnode_need_zeroout() by checking only volume_attr but not the b-tree ID because node zeroing can be requested for all HFS+ b-tree types. sudo ./check generic/070 FSTYP -- hfsplus PLATFORM -- Linux/x86_64 hfsplus-testing-0001 6.18.0-rc3+ #79 SMP PREEMPT_DYNAMIC Fri Oct 31 16:07:42 PDT 2025 MKFS_OPTIONS -- /dev/loop51 MOUNT_OPTIONS -- /dev/loop51 /mnt/scratch generic/070 33s ... 34s Ran: generic/070 Passed all 1 tests Signed-off-by: Viacheslav Dubeyko cc: John Paul Adrian Glaubitz cc: Yangtao Li cc: linux-fsdevel@vger.kernel.org Link: https://lore.kernel.org/r/20251101001229.247432-1-slava@dubeyko.com Signed-off-by: Viacheslav Dubeyko Signed-off-by: Sasha Levin --- fs/hfsplus/bnode.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/fs/hfsplus/bnode.c b/fs/hfsplus/bnode.c index 63e652ad1e0de..edf7e27e1e375 100644 --- a/fs/hfsplus/bnode.c +++ b/fs/hfsplus/bnode.c @@ -704,6 +704,5 @@ bool hfs_bnode_need_zeroout(struct hfs_btree *tree) struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb); const u32 volume_attr = be32_to_cpu(sbi->s_vhdr->attributes); - return tree->cnid == HFSPLUS_CAT_CNID && - volume_attr & HFSPLUS_VOL_UNUSED_NODE_FIX; + return volume_attr & HFSPLUS_VOL_UNUSED_NODE_FIX; } From 5882e7c8cdbb5e254a69628b780acff89c78071e Mon Sep 17 00:00:00 2001 From: Yang Chenzhi Date: Fri, 29 Aug 2025 17:39:12 +0800 Subject: [PATCH 1033/2333] hfsplus: fix missing hfs_bnode_get() in __hfs_bnode_create [ Upstream commit 152af114287851583cf7e0abc10129941f19466a ] When sync() and link() are called concurrently, both threads may enter hfs_bnode_find() without finding the node in the hash table and proceed to create it. Thread A: hfsplus_write_inode() -> hfsplus_write_system_inode() -> hfs_btree_write() -> hfs_bnode_find(tree, 0) -> __hfs_bnode_create(tree, 0) Thread B: hfsplus_create_cat() -> hfs_brec_insert() -> hfs_bnode_split() -> hfs_bmap_alloc() -> hfs_bnode_find(tree, 0) -> __hfs_bnode_create(tree, 0) In this case, thread A creates the bnode, sets refcnt=1, and hashes it. Thread B also tries to create the same bnode, notices it has already been inserted, drops its own instance, and uses the hashed one without getting the node. ``` node2 = hfs_bnode_findhash(tree, cnid); if (!node2) { <- Thread A hash = hfs_bnode_hash(cnid); node->next_hash = tree->node_hash[hash]; tree->node_hash[hash] = node; tree->node_hash_cnt++; } else { <- Thread B spin_unlock(&tree->hash_lock); kfree(node); wait_event(node2->lock_wq, !test_bit(HFS_BNODE_NEW, &node2->flags)); return node2; } ``` However, hfs_bnode_find() requires each call to take a reference. Here both threads end up setting refcnt=1. When they later put the node, this triggers: BUG_ON(!atomic_read(&node->refcnt)) In this scenario, Thread B in fact finds the node in the hash table rather than creating a new one, and thus must take a reference. Fix this by calling hfs_bnode_get() when reusing a bnode newly created by another thread to ensure the refcount is updated correctly. A similar bug was fixed in HFS long ago in commit a9dc087fd3c4 ("fix missing hfs_bnode_get() in __hfs_bnode_create") but the same issue remained in HFS+ until now. Reported-by: syzbot+005d2a9ecd9fbf525f6a@syzkaller.appspotmail.com Signed-off-by: Yang Chenzhi Signed-off-by: Viacheslav Dubeyko Link: https://lore.kernel.org/r/20250829093912.611853-1-yang.chenzhi@vivo.com Signed-off-by: Viacheslav Dubeyko Signed-off-by: Sasha Levin --- fs/hfsplus/bnode.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/hfsplus/bnode.c b/fs/hfsplus/bnode.c index edf7e27e1e375..482a6c5faa197 100644 --- a/fs/hfsplus/bnode.c +++ b/fs/hfsplus/bnode.c @@ -481,6 +481,7 @@ static struct hfs_bnode *__hfs_bnode_create(struct hfs_btree *tree, u32 cnid) tree->node_hash[hash] = node; tree->node_hash_cnt++; } else { + hfs_bnode_get(node2); spin_unlock(&tree->hash_lock); kfree(node); wait_event(node2->lock_wq, From 91f114bffa36ce56d0e1f60a0a44fc09baaefc79 Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Sat, 15 Nov 2025 18:18:54 +0900 Subject: [PATCH 1034/2333] hfsplus: Verify inode mode when loading from disk [ Upstream commit 005d4b0d33f6b4a23d382b7930f7a96b95b01f39 ] syzbot is reporting that S_IFMT bits of inode->i_mode can become bogus when the S_IFMT bits of the 16bits "mode" field loaded from disk are corrupted. According to [1], the permissions field was treated as reserved in Mac OS 8 and 9. According to [2], the reserved field was explicitly initialized with 0, and that field must remain 0 as long as reserved. Therefore, when the "mode" field is not 0 (i.e. no longer reserved), the file must be S_IFDIR if dir == 1, and the file must be one of S_IFREG/S_IFLNK/S_IFCHR/ S_IFBLK/S_IFIFO/S_IFSOCK if dir == 0. Reported-by: syzbot Closes: https://syzkaller.appspot.com/bug?extid=895c23f6917da440ed0d Link: https://developer.apple.com/library/archive/technotes/tn/tn1150.html#HFSPlusPermissions [1] Link: https://developer.apple.com/library/archive/technotes/tn/tn1150.html#ReservedAndPadFields [2] Signed-off-by: Tetsuo Handa Reviewed-by: Viacheslav Dubeyko Signed-off-by: Viacheslav Dubeyko Link: https://lore.kernel.org/r/04ded9f9-73fb-496c-bfa5-89c4f5d1d7bb@I-love.SAKURA.ne.jp Signed-off-by: Viacheslav Dubeyko Signed-off-by: Sasha Levin --- fs/hfsplus/inode.c | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c index b51a411ecd237..e290e417ed3a7 100644 --- a/fs/hfsplus/inode.c +++ b/fs/hfsplus/inode.c @@ -180,13 +180,29 @@ const struct dentry_operations hfsplus_dentry_operations = { .d_compare = hfsplus_compare_dentry, }; -static void hfsplus_get_perms(struct inode *inode, - struct hfsplus_perm *perms, int dir) +static int hfsplus_get_perms(struct inode *inode, + struct hfsplus_perm *perms, int dir) { struct hfsplus_sb_info *sbi = HFSPLUS_SB(inode->i_sb); u16 mode; mode = be16_to_cpu(perms->mode); + if (dir) { + if (mode && !S_ISDIR(mode)) + goto bad_type; + } else if (mode) { + switch (mode & S_IFMT) { + case S_IFREG: + case S_IFLNK: + case S_IFCHR: + case S_IFBLK: + case S_IFIFO: + case S_IFSOCK: + break; + default: + goto bad_type; + } + } i_uid_write(inode, be32_to_cpu(perms->owner)); if ((test_bit(HFSPLUS_SB_UID, &sbi->flags)) || (!i_uid_read(inode) && !mode)) @@ -212,6 +228,10 @@ static void hfsplus_get_perms(struct inode *inode, inode->i_flags |= S_APPEND; else inode->i_flags &= ~S_APPEND; + return 0; +bad_type: + pr_err("invalid file type 0%04o for inode %lu\n", mode, inode->i_ino); + return -EIO; } static int hfsplus_file_open(struct inode *inode, struct file *file) @@ -516,7 +536,9 @@ int hfsplus_cat_read_inode(struct inode *inode, struct hfs_find_data *fd) } hfs_bnode_read(fd->bnode, &entry, fd->entryoffset, sizeof(struct hfsplus_cat_folder)); - hfsplus_get_perms(inode, &folder->permissions, 1); + res = hfsplus_get_perms(inode, &folder->permissions, 1); + if (res) + goto out; set_nlink(inode, 1); inode->i_size = 2 + be32_to_cpu(folder->valence); inode_set_atime_to_ts(inode, hfsp_mt2ut(folder->access_date)); @@ -545,7 +567,9 @@ int hfsplus_cat_read_inode(struct inode *inode, struct hfs_find_data *fd) hfsplus_inode_read_fork(inode, HFSPLUS_IS_RSRC(inode) ? &file->rsrc_fork : &file->data_fork); - hfsplus_get_perms(inode, &file->permissions, 0); + res = hfsplus_get_perms(inode, &file->permissions, 0); + if (res) + goto out; set_nlink(inode, 1); if (S_ISREG(inode->i_mode)) { if (file->permissions.dev) From 282214ddf84727ca1b8ee44636da8c20114a82c7 Mon Sep 17 00:00:00 2001 From: Viacheslav Dubeyko Date: Wed, 12 Nov 2025 15:25:23 -0800 Subject: [PATCH 1035/2333] hfsplus: fix volume corruption issue for generic/073 [ Upstream commit 24e17a29cf7537f0947f26a50f85319abd723c6c ] The xfstests' test-case generic/073 leaves HFS+ volume in corrupted state: sudo ./check generic/073 FSTYP -- hfsplus PLATFORM -- Linux/x86_64 hfsplus-testing-0001 6.17.0-rc1+ #4 SMP PREEMPT_DYNAMIC Wed Oct 1 15:02:44 PDT 2025 MKFS_OPTIONS -- /dev/loop51 MOUNT_OPTIONS -- /dev/loop51 /mnt/scratch generic/073 _check_generic_filesystem: filesystem on /dev/loop51 is inconsistent (see XFSTESTS-2/xfstests-dev/results//generic/073.full for details) Ran: generic/073 Failures: generic/073 Failed 1 of 1 tests sudo fsck.hfsplus -d /dev/loop51 ** /dev/loop51 Using cacheBlockSize=32K cacheTotalBlock=1024 cacheSize=32768K. Executing fsck_hfs (version 540.1-Linux). ** Checking non-journaled HFS Plus Volume. The volume name is untitled ** Checking extents overflow file. ** Checking catalog file. ** Checking multi-linked files. ** Checking catalog hierarchy. Invalid directory item count (It should be 1 instead of 0) ** Checking extended attributes file. ** Checking volume bitmap. ** Checking volume information. Verify Status: VIStat = 0x0000, ABTStat = 0x0000 EBTStat = 0x0000 CBTStat = 0x0000 CatStat = 0x00004000 ** Repairing volume. ** Rechecking volume. ** Checking non-journaled HFS Plus Volume. The volume name is untitled ** Checking extents overflow file. ** Checking catalog file. ** Checking multi-linked files. ** Checking catalog hierarchy. ** Checking extended attributes file. ** Checking volume bitmap. ** Checking volume information. ** The volume untitled was repaired successfully. The test is doing these steps on final phase: mv $SCRATCH_MNT/testdir_1/bar $SCRATCH_MNT/testdir_2/bar $XFS_IO_PROG -c "fsync" $SCRATCH_MNT/testdir_1 $XFS_IO_PROG -c "fsync" $SCRATCH_MNT/foo So, we move file bar from testdir_1 into testdir_2 folder. It means that HFS+ logic decrements the number of entries in testdir_1 and increments number of entries in testdir_2. Finally, we do fsync only for testdir_1 and foo but not for testdir_2. As a result, this is the reason why fsck.hfsplus detects the volume corruption afterwards. This patch fixes the issue by means of adding the hfsplus_cat_write_inode() call for old_dir and new_dir in hfsplus_rename() after the successful ending of hfsplus_rename_cat(). This method makes modification of in-core inode objects for old_dir and new_dir but it doesn't save these modifications in Catalog File's entries. It was expected that hfsplus_write_inode() will save these modifications afterwards. However, because generic/073 does fsync only for testdir_1 and foo then testdir_2 modification hasn't beed saved into Catalog File's entry and it was flushed without this modification. And it was detected by fsck.hfsplus. Now, hfsplus_rename() stores in Catalog File all modified entries and correct state of Catalog File will be flushed during hfsplus_file_fsync() call. Finally, it makes fsck.hfsplus happy. sudo ./check generic/073 FSTYP -- hfsplus PLATFORM -- Linux/x86_64 hfsplus-testing-0001 6.18.0-rc3+ #93 SMP PREEMPT_DYNAMIC Wed Nov 12 14:37:49 PST 2025 MKFS_OPTIONS -- /dev/loop51 MOUNT_OPTIONS -- /dev/loop51 /mnt/scratch generic/073 32s ... 32s Ran: generic/073 Passed all 1 tests Signed-off-by: Viacheslav Dubeyko cc: John Paul Adrian Glaubitz cc: Yangtao Li cc: linux-fsdevel@vger.kernel.org Link: https://lore.kernel.org/r/20251112232522.814038-1-slava@dubeyko.com Signed-off-by: Viacheslav Dubeyko Signed-off-by: Sasha Levin --- fs/hfsplus/dir.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/fs/hfsplus/dir.c b/fs/hfsplus/dir.c index 1b3e27a0d5e03..cadf0b5f93422 100644 --- a/fs/hfsplus/dir.c +++ b/fs/hfsplus/dir.c @@ -552,8 +552,13 @@ static int hfsplus_rename(struct mnt_idmap *idmap, res = hfsplus_rename_cat((u32)(unsigned long)old_dentry->d_fsdata, old_dir, &old_dentry->d_name, new_dir, &new_dentry->d_name); - if (!res) + if (!res) { new_dentry->d_fsdata = old_dentry->d_fsdata; + + res = hfsplus_cat_write_inode(old_dir); + if (!res) + res = hfsplus_cat_write_inode(new_dir); + } return res; } From d5fb4e2c9bb01f65713dfd5f58be42176411fa56 Mon Sep 17 00:00:00 2001 From: Konstantin Komarov Date: Thu, 6 Nov 2025 16:17:19 +0300 Subject: [PATCH 1036/2333] fs/ntfs3: check for shutdown in fsync [ Upstream commit 1b2ae190ea43bebb8c73d21f076addc8a8c71849 ] Ensure fsync() returns -EIO when the ntfs3 filesystem is in forced shutdown, instead of silently succeeding via generic_file_fsync(). Signed-off-by: Konstantin Komarov Signed-off-by: Sasha Levin --- fs/ntfs3/file.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/fs/ntfs3/file.c b/fs/ntfs3/file.c index 4c90ec2fa2eae..83f0072f0896c 100644 --- a/fs/ntfs3/file.c +++ b/fs/ntfs3/file.c @@ -1375,6 +1375,18 @@ static ssize_t ntfs_file_splice_write(struct pipe_inode_info *pipe, return iter_file_splice_write(pipe, file, ppos, len, flags); } +/* + * ntfs_file_fsync - file_operations::fsync + */ +static int ntfs_file_fsync(struct file *file, loff_t start, loff_t end, int datasync) +{ + struct inode *inode = file_inode(file); + if (unlikely(ntfs3_forced_shutdown(inode->i_sb))) + return -EIO; + + return generic_file_fsync(file, start, end, datasync); +} + // clang-format off const struct inode_operations ntfs_file_inode_operations = { .getattr = ntfs_getattr, @@ -1397,7 +1409,7 @@ const struct file_operations ntfs_file_operations = { .splice_write = ntfs_file_splice_write, .mmap_prepare = ntfs_file_mmap_prepare, .open = ntfs_file_open, - .fsync = generic_file_fsync, + .fsync = ntfs_file_fsync, .fallocate = ntfs_fallocate, .release = ntfs_file_release, }; From 40257a2ef1bc19805af016e8213fcfb8a085f6cf Mon Sep 17 00:00:00 2001 From: Bitterblue Smith Date: Thu, 20 Nov 2025 16:10:01 +0200 Subject: [PATCH 1037/2333] wifi: rtl8xxxu: Fix HT40 channel config for RTL8192CU, RTL8723AU [ Upstream commit 5511ba3de434892e5ef3594d6eabbd12b1629356 ] Flip the response rate subchannel. It was backwards, causing low speeds when using 40 MHz channel width. "iw dev ... station dump" showed a low RX rate, 11M or less. Also fix the channel width field of RF6052_REG_MODE_AG. Tested only with RTL8192CU, but these settings are identical for RTL8723AU. Signed-off-by: Bitterblue Smith Reviewed-by: Ping-Ke Shih Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/1f46571d-855b-43e1-8bfc-abacceb96043@gmail.com Signed-off-by: Sasha Levin --- drivers/net/wireless/realtek/rtl8xxxu/core.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/realtek/rtl8xxxu/core.c b/drivers/net/wireless/realtek/rtl8xxxu/core.c index be39463bd6c46..3e87c571e2419 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/core.c @@ -1252,7 +1252,7 @@ void rtl8xxxu_gen1_config_channel(struct ieee80211_hw *hw) opmode &= ~BW_OPMODE_20MHZ; rtl8xxxu_write8(priv, REG_BW_OPMODE, opmode); rsr &= ~RSR_RSC_BANDWIDTH_40M; - if (sec_ch_above) + if (!sec_ch_above) rsr |= RSR_RSC_UPPER_SUB_CHANNEL; else rsr |= RSR_RSC_LOWER_SUB_CHANNEL; @@ -1321,9 +1321,8 @@ void rtl8xxxu_gen1_config_channel(struct ieee80211_hw *hw) for (i = RF_A; i < priv->rf_paths; i++) { val32 = rtl8xxxu_read_rfreg(priv, i, RF6052_REG_MODE_AG); - if (hw->conf.chandef.width == NL80211_CHAN_WIDTH_40) - val32 &= ~MODE_AG_CHANNEL_20MHZ; - else + val32 &= ~MODE_AG_BW_MASK; + if (hw->conf.chandef.width != NL80211_CHAN_WIDTH_40) val32 |= MODE_AG_CHANNEL_20MHZ; rtl8xxxu_write_rfreg(priv, i, RF6052_REG_MODE_AG, val32); } From c3ab9657866fc39a03ac8a797758924cfcd2c98c Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 21 Nov 2025 17:40:21 +0100 Subject: [PATCH 1038/2333] wifi: cfg80211: stop radar detection in cfg80211_leave() [ Upstream commit 9f33477b9a31a1edfe2df9f1a0359cccb0e16b4c ] If an interface is set down or, per the previous patch, changes type, radar detection for it should be cancelled. This is done for AP mode in mac80211 (somewhat needlessly, since cfg80211 can do it, but didn't until now), but wasn't handled for mesh, so if radar detection was started and then the interface set down or its type switched (the latter sometimes happning in the hwsim test 'mesh_peer_connected_dfs'), radar detection would be around with the interface unknown to the driver, later leading to some warnings around chanctx usage. Link: https://patch.msgid.link/20251121174021.290120e419e3.I2a5650c9062e29c988992dd8ce0d8eb570d23267@changeid Signed-off-by: Johannes Berg Signed-off-by: Sasha Levin --- net/wireless/core.c | 1 + net/wireless/core.h | 1 + net/wireless/mlme.c | 19 +++++++++++++++++++ 3 files changed, 21 insertions(+) diff --git a/net/wireless/core.c b/net/wireless/core.c index 54a34d8d356e0..5e5c1bc380a89 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -1365,6 +1365,7 @@ void cfg80211_leave(struct cfg80211_registered_device *rdev, cfg80211_pmsr_wdev_down(wdev); + cfg80211_stop_radar_detection(wdev); cfg80211_stop_background_radar_detection(wdev); switch (wdev->iftype) { diff --git a/net/wireless/core.h b/net/wireless/core.h index b6bd7f4d6385a..d5d78752227af 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -489,6 +489,7 @@ cfg80211_start_background_radar_detection(struct cfg80211_registered_device *rde struct wireless_dev *wdev, struct cfg80211_chan_def *chandef); +void cfg80211_stop_radar_detection(struct wireless_dev *wdev); void cfg80211_stop_background_radar_detection(struct wireless_dev *wdev); void cfg80211_background_cac_done_wk(struct work_struct *work); diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 46394eb2086f6..3fc175f9f8686 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -1295,6 +1295,25 @@ cfg80211_start_background_radar_detection(struct cfg80211_registered_device *rde return 0; } +void cfg80211_stop_radar_detection(struct wireless_dev *wdev) +{ + struct wiphy *wiphy = wdev->wiphy; + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); + int link_id; + + for_each_valid_link(wdev, link_id) { + struct cfg80211_chan_def chandef; + + if (!wdev->links[link_id].cac_started) + continue; + + chandef = *wdev_chandef(wdev, link_id); + rdev_end_cac(rdev, wdev->netdev, link_id); + nl80211_radar_notify(rdev, &chandef, NL80211_RADAR_CAC_ABORTED, + wdev->netdev, GFP_KERNEL); + } +} + void cfg80211_stop_background_radar_detection(struct wireless_dev *wdev) { struct wiphy *wiphy = wdev->wiphy; From 0283fac52b42712196e23509283f634ffa6c3b65 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 21 Nov 2025 17:40:20 +0100 Subject: [PATCH 1039/2333] wifi: cfg80211: use cfg80211_leave() in iftype change [ Upstream commit 7a27b73943a70ee226fa125327101fb18e94701d ] When changing the interface type, all activity on the interface has to be stopped first. This was done independent of existing code in cfg80211_leave(), so didn't handle e.g. background radar detection. Use cfg80211_leave() to handle it the same way. Note that cfg80211_leave() behaves slightly differently for IBSS in wireless extensions, it won't send an event in that case. We could handle that, but since nl80211 was used to change the type, IBSS is rare, and wext is already a corner case, it doesn't seem worth it. Link: https://patch.msgid.link/20251121174021.922ef48ce007.I970c8514252ef8a864a7fbdab9591b71031dee03@changeid Signed-off-by: Johannes Berg Signed-off-by: Sasha Levin --- net/wireless/util.c | 23 +---------------------- 1 file changed, 1 insertion(+), 22 deletions(-) diff --git a/net/wireless/util.c b/net/wireless/util.c index 56724b33af045..4eb028ad16836 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -1203,28 +1203,7 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, dev->ieee80211_ptr->use_4addr = false; rdev_set_qos_map(rdev, dev, NULL); - switch (otype) { - case NL80211_IFTYPE_AP: - case NL80211_IFTYPE_P2P_GO: - cfg80211_stop_ap(rdev, dev, -1, true); - break; - case NL80211_IFTYPE_ADHOC: - cfg80211_leave_ibss(rdev, dev, false); - break; - case NL80211_IFTYPE_STATION: - case NL80211_IFTYPE_P2P_CLIENT: - cfg80211_disconnect(rdev, dev, - WLAN_REASON_DEAUTH_LEAVING, true); - break; - case NL80211_IFTYPE_MESH_POINT: - /* mesh should be handled? */ - break; - case NL80211_IFTYPE_OCB: - cfg80211_leave_ocb(rdev, dev); - break; - default: - break; - } + cfg80211_leave(rdev, dev->ieee80211_ptr); cfg80211_process_rdev_events(rdev); cfg80211_mlme_purge_registrations(dev->ieee80211_ptr); From 9c6f9b2a80ed7a877008491593eeddea17625b9c Mon Sep 17 00:00:00 2001 From: Quan Zhou Date: Tue, 18 Nov 2025 19:54:54 +0800 Subject: [PATCH 1040/2333] wifi: mt76: mt792x: fix wifi init fail by setting MCU_RUNNING after CLC load [ Upstream commit 066f417be5fd8c7fe581c5550206364735dad7a3 ] Set the MT76_STATE_MCU_RUNNING bit only after mt7921_load_clc() has successfully completed. Previously, the MCU_RUNNING state was set before loading CLC, which could cause conflict between chip mcu_init retry and mac_reset flow, result in chip init fail and chip abnormal status. By moving the state set after CLC load, firmware initialization becomes robust and resolves init fail issue. Signed-off-by: Quan Zhou Reviewed-by: druth@chromium.org Link: https://patch.msgid.link/19ec8e4465142e774f17801025accd0ae2214092.1763465933.git.quan.zhou@mediatek.com Signed-off-by: Felix Fietkau Signed-off-by: Sasha Levin --- drivers/net/wireless/mediatek/mt76/mt7921/mcu.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7925/mcu.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c index 86bd33b916a9d..edc1df3c071e5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c @@ -646,10 +646,10 @@ int mt7921_run_firmware(struct mt792x_dev *dev) if (err) return err; - set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state); err = mt7921_load_clc(dev, mt792x_ram_name(dev)); if (err) return err; + set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state); return mt7921_mcu_fw_log_2_host(dev, 1); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index 8eda407e4135e..c12b71b71cfc7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -1003,10 +1003,10 @@ int mt7925_run_firmware(struct mt792x_dev *dev) if (err) return err; - set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state); err = mt7925_load_clc(dev, mt792x_ram_name(dev)); if (err) return err; + set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state); return mt7925_mcu_fw_log_2_host(dev, 1); } From f5323b43019d8fb834f3aa1efe752303c09b2971 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 3 Nov 2025 11:03:14 +0100 Subject: [PATCH 1041/2333] wifi: brcmfmac: Add DMI nvram filename quirk for Acer A1 840 tablet [ Upstream commit a8e5a110c0c38e08e5dd66356cd1156e91cf88e1 ] The Acer A1 840 tablet contains quite generic names in the sys_vendor and product_name DMI strings, without this patch brcmfmac will try to load: brcmfmac43340-sdio.Insyde-BayTrail.txt as nvram file which is a bit too generic. Add a DMI quirk so that a unique and clearly identifiable nvram file name is used on the Acer A1 840 tablet. Acked-by: Arend van Spriel Signed-off-by: Hans de Goede Link: https://patch.msgid.link/20251103100314.353826-1-hansg@kernel.org Signed-off-by: Johannes Berg Signed-off-by: Sasha Levin --- .../net/wireless/broadcom/brcm80211/brcmfmac/dmi.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/dmi.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/dmi.c index c3a602197662b..abe7f6501e5ed 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/dmi.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/dmi.c @@ -24,6 +24,10 @@ static const struct brcmf_dmi_data acepc_t8_data = { BRCM_CC_4345_CHIP_ID, 6, "acepc-t8" }; +static const struct brcmf_dmi_data acer_a1_840_data = { + BRCM_CC_43340_CHIP_ID, 2, "acer-a1-840" +}; + /* The Chuwi Hi8 Pro uses the same Ampak AP6212 module as the Chuwi Vi8 Plus * and the nvram for the Vi8 Plus is already in linux-firmware, so use that. */ @@ -91,6 +95,16 @@ static const struct dmi_system_id dmi_platform_data[] = { }, .driver_data = (void *)&acepc_t8_data, }, + { + /* Acer Iconia One 8 A1-840 (non FHD version) */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Insyde"), + DMI_MATCH(DMI_PRODUCT_NAME, "BayTrail"), + /* Above strings are too generic also match BIOS date */ + DMI_MATCH(DMI_BIOS_DATE, "04/01/2014"), + }, + .driver_data = (void *)&acer_a1_840_data, + }, { /* Chuwi Hi8 Pro with D2D3_Hi8Pro.233 BIOS */ .matches = { From 306d8449af7c8253664b74aa77ba45543eaaaec1 Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Mon, 3 Nov 2025 12:51:09 +1030 Subject: [PATCH 1042/2333] btrfs: scrub: always update btrfs_scrub_progress::last_physical [ Upstream commit 54df8b80cc63aa0f22c4590cad11542731ed43ff ] [BUG] When a scrub failed immediately without any byte scrubbed, the returned btrfs_scrub_progress::last_physical will always be 0, even if there is a non-zero @start passed into btrfs_scrub_dev() for resume cases. This will reset the progress and make later scrub resume start from the beginning. [CAUSE] The function btrfs_scrub_dev() accepts a @progress parameter to copy its updated progress to the caller, there are cases where we either don't touch progress::last_physical at all or copy 0 into last_physical: - last_physical not updated at all If some error happened before scrubbing any super block or chunk, we will not copy the progress, leaving the @last_physical untouched. E.g. failed to allocate @sctx, scrubbing a missing device or even there is already a running scrub and so on. All those cases won't touch @progress at all, resulting the last_physical untouched and will be left as 0 for most cases. - Error out before scrubbing any bytes In those case we allocated @sctx, and sctx->stat.last_physical is all zero (initialized by kvzalloc()). Unfortunately some critical errors happened during scrub_enumerate_chunks() or scrub_supers() before any stripe is really scrubbed. In that case although we will copy sctx->stat back to @progress, since no byte is really scrubbed, last_physical will be overwritten to 0. [FIX] Make sure the parameter @progress always has its @last_physical member updated to @start parameter inside btrfs_scrub_dev(). At the very beginning of the function, set @progress->last_physical to @start, so that even if we error out without doing progress copying, last_physical is still at @start. Then after we got @sctx allocated, set sctx->stat.last_physical to @start, this will make sure even if we didn't get any byte scrubbed, at the progress copying stage the @last_physical is not left as zero. This should resolve the resume progress reset problem. Signed-off-by: Qu Wenruo Reviewed-by: David Sterba Signed-off-by: David Sterba Signed-off-by: Sasha Levin --- fs/btrfs/scrub.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index 65361af302343..b6a7ea105eb13 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c @@ -3039,6 +3039,10 @@ int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start, unsigned int nofs_flag; bool need_commit = false; + /* Set the basic fallback @last_physical before we got a sctx. */ + if (progress) + progress->last_physical = start; + if (btrfs_fs_closing(fs_info)) return -EAGAIN; @@ -3057,6 +3061,7 @@ int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start, sctx = scrub_setup_ctx(fs_info, is_dev_replace); if (IS_ERR(sctx)) return PTR_ERR(sctx); + sctx->stat.last_physical = start; ret = scrub_workers_get(fs_info); if (ret) From 66e2f3c1aefea54f80f9010f75815b668bbc50f1 Mon Sep 17 00:00:00 2001 From: Viacheslav Dubeyko Date: Wed, 19 Nov 2025 14:32:20 -0800 Subject: [PATCH 1043/2333] hfsplus: fix volume corruption issue for generic/101 [ Upstream commit 3f04ee216bc1406cb6214ceaa7e544114108e0fa ] The xfstests' test-case generic/101 leaves HFS+ volume in corrupted state: sudo ./check generic/101 FSTYP -- hfsplus PLATFORM -- Linux/x86_64 hfsplus-testing-0001 6.17.0-rc1+ #4 SMP PREEMPT_DYNAMIC Wed Oct 1 15:02:44 PDT 2025 MKFS_OPTIONS -- /dev/loop51 MOUNT_OPTIONS -- /dev/loop51 /mnt/scratch generic/101 _check_generic_filesystem: filesystem on /dev/loop51 is inconsistent (see XFSTESTS-2/xfstests-dev/results//generic/101.full for details) Ran: generic/101 Failures: generic/101 Failed 1 of 1 tests sudo fsck.hfsplus -d /dev/loop51 ** /dev/loop51 Using cacheBlockSize=32K cacheTotalBlock=1024 cacheSize=32768K. Executing fsck_hfs (version 540.1-Linux). ** Checking non-journaled HFS Plus Volume. The volume name is untitled ** Checking extents overflow file. ** Checking catalog file. ** Checking multi-linked files. ** Checking catalog hierarchy. ** Checking extended attributes file. ** Checking volume bitmap. ** Checking volume information. Invalid volume free block count (It should be 2614350 instead of 2614382) Verify Status: VIStat = 0x8000, ABTStat = 0x0000 EBTStat = 0x0000 CBTStat = 0x0000 CatStat = 0x00000000 ** Repairing volume. ** Rechecking volume. ** Checking non-journaled HFS Plus Volume. The volume name is untitled ** Checking extents overflow file. ** Checking catalog file. ** Checking multi-linked files. ** Checking catalog hierarchy. ** Checking extended attributes file. ** Checking volume bitmap. ** Checking volume information. ** The volume untitled was repaired successfully. This test executes such steps: "Test that if we truncate a file to a smaller size, then truncate it to its original size or a larger size, then fsyncing it and a power failure happens, the file will have the range [first_truncate_size, last_size[ with all bytes having a value of 0x00 if we read it the next time the filesystem is mounted.". HFS+ keeps volume's free block count in the superblock. However, hfsplus_file_fsync() doesn't store superblock's content. As a result, superblock contains not correct value of free blocks if a power failure happens. This patch adds functionality of saving superblock's content during hfsplus_file_fsync() call. sudo ./check generic/101 FSTYP -- hfsplus PLATFORM -- Linux/x86_64 hfsplus-testing-0001 6.18.0-rc3+ #96 SMP PREEMPT_DYNAMIC Wed Nov 19 12:47:37 PST 2025 MKFS_OPTIONS -- /dev/loop51 MOUNT_OPTIONS -- /dev/loop51 /mnt/scratch generic/101 32s ... 30s Ran: generic/101 Passed all 1 tests sudo fsck.hfsplus -d /dev/loop51 ** /dev/loop51 Using cacheBlockSize=32K cacheTotalBlock=1024 cacheSize=32768K. Executing fsck_hfs (version 540.1-Linux). ** Checking non-journaled HFS Plus Volume. The volume name is untitled ** Checking extents overflow file. ** Checking catalog file. ** Checking multi-linked files. ** Checking catalog hierarchy. ** Checking extended attributes file. ** Checking volume bitmap. ** Checking volume information. ** The volume untitled appears to be OK. Signed-off-by: Viacheslav Dubeyko cc: John Paul Adrian Glaubitz cc: Yangtao Li cc: linux-fsdevel@vger.kernel.org Link: https://lore.kernel.org/r/20251119223219.1824434-1-slava@dubeyko.com Signed-off-by: Viacheslav Dubeyko Signed-off-by: Sasha Levin --- fs/hfsplus/hfsplus_fs.h | 2 + fs/hfsplus/inode.c | 9 +++++ fs/hfsplus/super.c | 87 +++++++++++++++++++++++++---------------- 3 files changed, 65 insertions(+), 33 deletions(-) diff --git a/fs/hfsplus/hfsplus_fs.h b/fs/hfsplus/hfsplus_fs.h index 89e8b19c127b0..de801942ae471 100644 --- a/fs/hfsplus/hfsplus_fs.h +++ b/fs/hfsplus/hfsplus_fs.h @@ -477,6 +477,8 @@ int hfs_part_find(struct super_block *sb, sector_t *part_start, /* super.c */ struct inode *hfsplus_iget(struct super_block *sb, unsigned long ino); void hfsplus_mark_mdb_dirty(struct super_block *sb); +void hfsplus_prepare_volume_header_for_commit(struct hfsplus_vh *vhdr); +int hfsplus_commit_superblock(struct super_block *sb); /* tables.c */ extern u16 hfsplus_case_fold_table[]; diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c index e290e417ed3a7..7ae6745ca7ae1 100644 --- a/fs/hfsplus/inode.c +++ b/fs/hfsplus/inode.c @@ -325,6 +325,7 @@ int hfsplus_file_fsync(struct file *file, loff_t start, loff_t end, struct inode *inode = file->f_mapping->host; struct hfsplus_inode_info *hip = HFSPLUS_I(inode); struct hfsplus_sb_info *sbi = HFSPLUS_SB(inode->i_sb); + struct hfsplus_vh *vhdr = sbi->s_vhdr; int error = 0, error2; error = file_write_and_wait_range(file, start, end); @@ -368,6 +369,14 @@ int hfsplus_file_fsync(struct file *file, loff_t start, loff_t end, error = error2; } + mutex_lock(&sbi->vh_mutex); + hfsplus_prepare_volume_header_for_commit(vhdr); + mutex_unlock(&sbi->vh_mutex); + + error2 = hfsplus_commit_superblock(inode->i_sb); + if (!error) + error = error2; + if (!test_bit(HFSPLUS_SB_NOBARRIER, &sbi->flags)) blkdev_issue_flush(inode->i_sb->s_bdev); diff --git a/fs/hfsplus/super.c b/fs/hfsplus/super.c index 16bc4abc67e08..67a7a2a093476 100644 --- a/fs/hfsplus/super.c +++ b/fs/hfsplus/super.c @@ -187,40 +187,15 @@ static void hfsplus_evict_inode(struct inode *inode) } } -static int hfsplus_sync_fs(struct super_block *sb, int wait) +int hfsplus_commit_superblock(struct super_block *sb) { struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb); struct hfsplus_vh *vhdr = sbi->s_vhdr; int write_backup = 0; - int error, error2; - - if (!wait) - return 0; + int error = 0, error2; hfs_dbg("starting...\n"); - /* - * Explicitly write out the special metadata inodes. - * - * While these special inodes are marked as hashed and written - * out peridocically by the flusher threads we redirty them - * during writeout of normal inodes, and thus the life lock - * prevents us from getting the latest state to disk. - */ - error = filemap_write_and_wait(sbi->cat_tree->inode->i_mapping); - error2 = filemap_write_and_wait(sbi->ext_tree->inode->i_mapping); - if (!error) - error = error2; - if (sbi->attr_tree) { - error2 = - filemap_write_and_wait(sbi->attr_tree->inode->i_mapping); - if (!error) - error = error2; - } - error2 = filemap_write_and_wait(sbi->alloc_file->i_mapping); - if (!error) - error = error2; - mutex_lock(&sbi->vh_mutex); mutex_lock(&sbi->alloc_mutex); vhdr->free_blocks = cpu_to_be32(sbi->free_blocks); @@ -249,11 +224,52 @@ static int hfsplus_sync_fs(struct super_block *sb, int wait) sbi->part_start + sbi->sect_count - 2, sbi->s_backup_vhdr_buf, NULL, REQ_OP_WRITE); if (!error) - error2 = error; + error = error2; out: mutex_unlock(&sbi->alloc_mutex); mutex_unlock(&sbi->vh_mutex); + hfs_dbg("finished: err %d\n", error); + + return error; +} + +static int hfsplus_sync_fs(struct super_block *sb, int wait) +{ + struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb); + int error, error2; + + if (!wait) + return 0; + + hfs_dbg("starting...\n"); + + /* + * Explicitly write out the special metadata inodes. + * + * While these special inodes are marked as hashed and written + * out peridocically by the flusher threads we redirty them + * during writeout of normal inodes, and thus the life lock + * prevents us from getting the latest state to disk. + */ + error = filemap_write_and_wait(sbi->cat_tree->inode->i_mapping); + error2 = filemap_write_and_wait(sbi->ext_tree->inode->i_mapping); + if (!error) + error = error2; + if (sbi->attr_tree) { + error2 = + filemap_write_and_wait(sbi->attr_tree->inode->i_mapping); + if (!error) + error = error2; + } + error2 = filemap_write_and_wait(sbi->alloc_file->i_mapping); + if (!error) + error = error2; + + error2 = hfsplus_commit_superblock(sb); + if (!error) + error = error2; + if (!test_bit(HFSPLUS_SB_NOBARRIER, &sbi->flags)) blkdev_issue_flush(sb->s_bdev); @@ -395,6 +411,15 @@ static const struct super_operations hfsplus_sops = { .show_options = hfsplus_show_options, }; +void hfsplus_prepare_volume_header_for_commit(struct hfsplus_vh *vhdr) +{ + vhdr->last_mount_vers = cpu_to_be32(HFSP_MOUNT_VERSION); + vhdr->modify_date = hfsp_now2mt(); + be32_add_cpu(&vhdr->write_count, 1); + vhdr->attributes &= cpu_to_be32(~HFSPLUS_VOL_UNMNT); + vhdr->attributes |= cpu_to_be32(HFSPLUS_VOL_INCNSTNT); +} + static int hfsplus_fill_super(struct super_block *sb, struct fs_context *fc) { struct hfsplus_vh *vhdr; @@ -562,11 +587,7 @@ static int hfsplus_fill_super(struct super_block *sb, struct fs_context *fc) * H+LX == hfsplusutils, H+Lx == this driver, H+lx is unused * all three are registered with Apple for our use */ - vhdr->last_mount_vers = cpu_to_be32(HFSP_MOUNT_VERSION); - vhdr->modify_date = hfsp_now2mt(); - be32_add_cpu(&vhdr->write_count, 1); - vhdr->attributes &= cpu_to_be32(~HFSPLUS_VOL_UNMNT); - vhdr->attributes |= cpu_to_be32(HFSPLUS_VOL_INCNSTNT); + hfsplus_prepare_volume_header_for_commit(vhdr); hfsplus_sync_fs(sb, 1); if (!sbi->hidden_dir) { From a2046f5916c25c609db6a2c7e7d796f600a9eafe Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Wed, 19 Nov 2025 12:14:24 +0000 Subject: [PATCH 1044/2333] gfs2: fix remote evict for read-only filesystems [ Upstream commit 64c10ed9274bc46416f502afea48b4ae11279669 ] When a node tries to delete an inode, it first requests exclusive access to the iopen glock. This triggers demote requests on all remote nodes currently holding the iopen glock. To satisfy those requests, the remote nodes evict the inode in question, or they poke the corresponding inode glock to signal that the inode is still in active use. This behavior doesn't depend on whether or not a filesystem is read-only, so remove the incorrect read-only check. Signed-off-by: Andreas Gruenbacher Signed-off-by: Sasha Levin --- fs/gfs2/glops.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c index 0c0a80b3bacab..0c68ab4432b08 100644 --- a/fs/gfs2/glops.c +++ b/fs/gfs2/glops.c @@ -630,8 +630,7 @@ static void iopen_go_callback(struct gfs2_glock *gl, bool remote) struct gfs2_inode *ip = gl->gl_object; struct gfs2_sbd *sdp = gl->gl_name.ln_sbd; - if (!remote || sb_rdonly(sdp->sd_vfs) || - test_bit(SDF_KILL, &sdp->sd_flags)) + if (!remote || test_bit(SDF_KILL, &sdp->sd_flags)) return; if (gl->gl_demote_state == LM_ST_UNLOCKED && From 32c3960b421240534669f7bfb0c4ebb56dd799e7 Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Wed, 26 Nov 2025 23:27:14 +0000 Subject: [PATCH 1045/2333] gfs2: Fix "gfs2: Switch to wait_event in gfs2_quotad" [ Upstream commit dff1fb6d8b7abe5b1119fa060f5d6b3370bf10ac ] Commit e4a8b5481c59a ("gfs2: Switch to wait_event in gfs2_quotad") broke cyclic statfs syncing, so the numbers reported by "df" could easily get completely out of sync with reality. Fix this by reverting part of commit e4a8b5481c59a for now. A follow-up commit will clean this code up later. Signed-off-by: Andreas Gruenbacher Signed-off-by: Sasha Levin --- fs/gfs2/quota.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index 2298e06797ac3..f2df01f801b81 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -1616,7 +1616,7 @@ int gfs2_quotad(void *data) t = min(quotad_timeo, statfs_timeo); - t = wait_event_freezable_timeout(sdp->sd_quota_wait, + t -= wait_event_freezable_timeout(sdp->sd_quota_wait, sdp->sd_statfs_force_sync || gfs2_withdrawing_or_withdrawn(sdp) || kthread_should_stop(), From d8c5009bf41db126e284864748f2d0e947bc436c Mon Sep 17 00:00:00 2001 From: ChenXiaoSong Date: Fri, 17 Oct 2025 18:46:10 +0800 Subject: [PATCH 1046/2333] smb/server: fix return value of smb2_ioctl() [ Upstream commit 269df046c1e15ab34fa26fd90db9381f022a0963 ] __process_request() will not print error messages if smb2_ioctl() always returns 0. Fix this by returning the correct value at the end of function. Signed-off-by: ChenXiaoSong Acked-by: Namjae Jeon Signed-off-by: Steve French Signed-off-by: Sasha Levin --- fs/smb/server/smb2pdu.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c index f901ae18e68ad..a2830ec67e782 100644 --- a/fs/smb/server/smb2pdu.c +++ b/fs/smb/server/smb2pdu.c @@ -8164,7 +8164,7 @@ int smb2_ioctl(struct ksmbd_work *work) id = req->VolatileFileId; if (req->Flags != cpu_to_le32(SMB2_0_IOCTL_IS_FSCTL)) { - rsp->hdr.Status = STATUS_NOT_SUPPORTED; + ret = -EOPNOTSUPP; goto out; } @@ -8184,8 +8184,9 @@ int smb2_ioctl(struct ksmbd_work *work) case FSCTL_DFS_GET_REFERRALS: case FSCTL_DFS_GET_REFERRALS_EX: /* Not support DFS yet */ + ret = -EOPNOTSUPP; rsp->hdr.Status = STATUS_FS_DRIVER_REQUIRED; - goto out; + goto out2; case FSCTL_CREATE_OR_GET_OBJECT_ID: { struct file_object_buf_type1_ioctl_rsp *obj_buf; @@ -8475,8 +8476,10 @@ int smb2_ioctl(struct ksmbd_work *work) rsp->hdr.Status = STATUS_BUFFER_TOO_SMALL; else if (ret < 0 || rsp->hdr.Status == 0) rsp->hdr.Status = STATUS_INVALID_PARAMETER; + +out2: smb2_set_err_rsp(work); - return 0; + return ret; } /** From 063cbbc6f595ea36ad146e1b7d2af820894beb21 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Tue, 18 Nov 2025 09:05:46 +0900 Subject: [PATCH 1047/2333] ksmbd: fix use-after-free in ksmbd_tree_connect_put under concurrency [ Upstream commit b39a1833cc4a2755b02603eec3a71a85e9dff926 ] Under high concurrency, A tree-connection object (tcon) is freed on a disconnect path while another path still holds a reference and later executes *_put()/write on it. Reported-by: Qianchang Zhao Reported-by: Zhitong Liu Signed-off-by: Namjae Jeon Signed-off-by: Steve French Signed-off-by: Sasha Levin --- fs/smb/server/mgmt/tree_connect.c | 18 ++++-------------- fs/smb/server/mgmt/tree_connect.h | 1 - fs/smb/server/smb2pdu.c | 3 --- 3 files changed, 4 insertions(+), 18 deletions(-) diff --git a/fs/smb/server/mgmt/tree_connect.c b/fs/smb/server/mgmt/tree_connect.c index ecfc575086712..d3483d9c757c7 100644 --- a/fs/smb/server/mgmt/tree_connect.c +++ b/fs/smb/server/mgmt/tree_connect.c @@ -78,7 +78,6 @@ ksmbd_tree_conn_connect(struct ksmbd_work *work, const char *share_name) tree_conn->t_state = TREE_NEW; status.tree_conn = tree_conn; atomic_set(&tree_conn->refcount, 1); - init_waitqueue_head(&tree_conn->refcount_q); ret = xa_err(xa_store(&sess->tree_conns, tree_conn->id, tree_conn, KSMBD_DEFAULT_GFP)); @@ -100,14 +99,8 @@ ksmbd_tree_conn_connect(struct ksmbd_work *work, const char *share_name) void ksmbd_tree_connect_put(struct ksmbd_tree_connect *tcon) { - /* - * Checking waitqueue to releasing tree connect on - * tree disconnect. waitqueue_active is safe because it - * uses atomic operation for condition. - */ - if (!atomic_dec_return(&tcon->refcount) && - waitqueue_active(&tcon->refcount_q)) - wake_up(&tcon->refcount_q); + if (atomic_dec_and_test(&tcon->refcount)) + kfree(tcon); } int ksmbd_tree_conn_disconnect(struct ksmbd_session *sess, @@ -119,14 +112,11 @@ int ksmbd_tree_conn_disconnect(struct ksmbd_session *sess, xa_erase(&sess->tree_conns, tree_conn->id); write_unlock(&sess->tree_conns_lock); - if (!atomic_dec_and_test(&tree_conn->refcount)) - wait_event(tree_conn->refcount_q, - atomic_read(&tree_conn->refcount) == 0); - ret = ksmbd_ipc_tree_disconnect_request(sess->id, tree_conn->id); ksmbd_release_tree_conn_id(sess, tree_conn->id); ksmbd_share_config_put(tree_conn->share_conf); - kfree(tree_conn); + if (atomic_dec_and_test(&tree_conn->refcount)) + kfree(tree_conn); return ret; } diff --git a/fs/smb/server/mgmt/tree_connect.h b/fs/smb/server/mgmt/tree_connect.h index a42cdd0510411..f0023d86716f2 100644 --- a/fs/smb/server/mgmt/tree_connect.h +++ b/fs/smb/server/mgmt/tree_connect.h @@ -33,7 +33,6 @@ struct ksmbd_tree_connect { int maximal_access; bool posix_extensions; atomic_t refcount; - wait_queue_head_t refcount_q; unsigned int t_state; }; diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c index a2830ec67e782..dba29881debdc 100644 --- a/fs/smb/server/smb2pdu.c +++ b/fs/smb/server/smb2pdu.c @@ -2200,7 +2200,6 @@ int smb2_tree_disconnect(struct ksmbd_work *work) goto err_out; } - WARN_ON_ONCE(atomic_dec_and_test(&tcon->refcount)); tcon->t_state = TREE_DISCONNECTED; write_unlock(&sess->tree_conns_lock); @@ -2210,8 +2209,6 @@ int smb2_tree_disconnect(struct ksmbd_work *work) goto err_out; } - work->tcon = NULL; - rsp->StructureSize = cpu_to_le16(4); err = ksmbd_iov_pin_rsp(work, rsp, sizeof(struct smb2_tree_disconnect_rsp)); From ee63729760f5b61a66f345c54dc4c7514e62383d Mon Sep 17 00:00:00 2001 From: Qianchang Zhao Date: Mon, 24 Nov 2025 16:05:09 +0900 Subject: [PATCH 1048/2333] ksmbd: vfs: fix race on m_flags in vfs_cache [ Upstream commit 991f8a79db99b14c48d20d2052c82d65b9186cad ] ksmbd maintains delete-on-close and pending-delete state in ksmbd_inode->m_flags. In vfs_cache.c this field is accessed under inconsistent locking: some paths read and modify m_flags under ci->m_lock while others do so without taking the lock at all. Examples: - ksmbd_query_inode_status() and __ksmbd_inode_close() use ci->m_lock when checking or updating m_flags. - ksmbd_inode_pending_delete(), ksmbd_set_inode_pending_delete(), ksmbd_clear_inode_pending_delete() and ksmbd_fd_set_delete_on_close() used to read and modify m_flags without ci->m_lock. This creates a potential data race on m_flags when multiple threads open, close and delete the same file concurrently. In the worst case delete-on-close and pending-delete bits can be lost or observed in an inconsistent state, leading to confusing delete semantics (files that stay on disk after delete-on-close, or files that disappear while still in use). Fix it by: - Making ksmbd_query_inode_status() look at m_flags under ci->m_lock after dropping inode_hash_lock. - Adding ci->m_lock protection to all helpers that read or modify m_flags (ksmbd_inode_pending_delete(), ksmbd_set_inode_pending_delete(), ksmbd_clear_inode_pending_delete(), ksmbd_fd_set_delete_on_close()). - Keeping the existing ci->m_lock protection in __ksmbd_inode_close(), and moving the actual unlink/xattr removal outside the lock. This unifies the locking around m_flags and removes the data race while preserving the existing delete-on-close behaviour. Reported-by: Qianchang Zhao Reported-by: Zhitong Liu Signed-off-by: Qianchang Zhao Acked-by: Namjae Jeon Signed-off-by: Steve French Signed-off-by: Sasha Levin --- fs/smb/server/vfs_cache.c | 88 +++++++++++++++++++++++++++------------ 1 file changed, 62 insertions(+), 26 deletions(-) diff --git a/fs/smb/server/vfs_cache.c b/fs/smb/server/vfs_cache.c index dfed6fce89049..6ef116585af64 100644 --- a/fs/smb/server/vfs_cache.c +++ b/fs/smb/server/vfs_cache.c @@ -112,40 +112,62 @@ int ksmbd_query_inode_status(struct dentry *dentry) read_lock(&inode_hash_lock); ci = __ksmbd_inode_lookup(dentry); - if (ci) { - ret = KSMBD_INODE_STATUS_OK; - if (ci->m_flags & (S_DEL_PENDING | S_DEL_ON_CLS)) - ret = KSMBD_INODE_STATUS_PENDING_DELETE; - atomic_dec(&ci->m_count); - } read_unlock(&inode_hash_lock); + if (!ci) + return ret; + + down_read(&ci->m_lock); + if (ci->m_flags & (S_DEL_PENDING | S_DEL_ON_CLS)) + ret = KSMBD_INODE_STATUS_PENDING_DELETE; + else + ret = KSMBD_INODE_STATUS_OK; + up_read(&ci->m_lock); + + atomic_dec(&ci->m_count); return ret; } bool ksmbd_inode_pending_delete(struct ksmbd_file *fp) { - return (fp->f_ci->m_flags & (S_DEL_PENDING | S_DEL_ON_CLS)); + struct ksmbd_inode *ci = fp->f_ci; + int ret; + + down_read(&ci->m_lock); + ret = (ci->m_flags & (S_DEL_PENDING | S_DEL_ON_CLS)); + up_read(&ci->m_lock); + + return ret; } void ksmbd_set_inode_pending_delete(struct ksmbd_file *fp) { - fp->f_ci->m_flags |= S_DEL_PENDING; + struct ksmbd_inode *ci = fp->f_ci; + + down_write(&ci->m_lock); + ci->m_flags |= S_DEL_PENDING; + up_write(&ci->m_lock); } void ksmbd_clear_inode_pending_delete(struct ksmbd_file *fp) { - fp->f_ci->m_flags &= ~S_DEL_PENDING; + struct ksmbd_inode *ci = fp->f_ci; + + down_write(&ci->m_lock); + ci->m_flags &= ~S_DEL_PENDING; + up_write(&ci->m_lock); } void ksmbd_fd_set_delete_on_close(struct ksmbd_file *fp, int file_info) { - if (ksmbd_stream_fd(fp)) { - fp->f_ci->m_flags |= S_DEL_ON_CLS_STREAM; - return; - } + struct ksmbd_inode *ci = fp->f_ci; - fp->f_ci->m_flags |= S_DEL_ON_CLS; + down_write(&ci->m_lock); + if (ksmbd_stream_fd(fp)) + ci->m_flags |= S_DEL_ON_CLS_STREAM; + else + ci->m_flags |= S_DEL_ON_CLS; + up_write(&ci->m_lock); } static void ksmbd_inode_hash(struct ksmbd_inode *ci) @@ -257,27 +279,41 @@ static void __ksmbd_inode_close(struct ksmbd_file *fp) struct file *filp; filp = fp->filp; - if (ksmbd_stream_fd(fp) && (ci->m_flags & S_DEL_ON_CLS_STREAM)) { - ci->m_flags &= ~S_DEL_ON_CLS_STREAM; - err = ksmbd_vfs_remove_xattr(file_mnt_idmap(filp), - &filp->f_path, - fp->stream.name, - true); - if (err) - pr_err("remove xattr failed : %s\n", - fp->stream.name); + + if (ksmbd_stream_fd(fp)) { + bool remove_stream_xattr = false; + + down_write(&ci->m_lock); + if (ci->m_flags & S_DEL_ON_CLS_STREAM) { + ci->m_flags &= ~S_DEL_ON_CLS_STREAM; + remove_stream_xattr = true; + } + up_write(&ci->m_lock); + + if (remove_stream_xattr) { + err = ksmbd_vfs_remove_xattr(file_mnt_idmap(filp), + &filp->f_path, + fp->stream.name, + true); + if (err) + pr_err("remove xattr failed : %s\n", + fp->stream.name); + } } if (atomic_dec_and_test(&ci->m_count)) { + bool do_unlink = false; + down_write(&ci->m_lock); if (ci->m_flags & (S_DEL_ON_CLS | S_DEL_PENDING)) { ci->m_flags &= ~(S_DEL_ON_CLS | S_DEL_PENDING); - up_write(&ci->m_lock); - ksmbd_vfs_unlink(filp); - down_write(&ci->m_lock); + do_unlink = true; } up_write(&ci->m_lock); + if (do_unlink) + ksmbd_vfs_unlink(filp); + ksmbd_inode_free(ci); } } From 112a000505b88e71024943399c518932c9c9768c Mon Sep 17 00:00:00 2001 From: Chingbin Li Date: Mon, 6 Oct 2025 16:46:47 +0800 Subject: [PATCH 1049/2333] Bluetooth: btusb: Add new VID/PID 2b89/6275 for RTL8761BUV [ Upstream commit 8dbbb5423c0802ec21266765de80fd491868fab1 ] Add VID 2b89 & PID 6275 for Realtek RTL8761BUV USB Bluetooth chip. The information in /sys/kernel/debug/usb/devices about the Bluetooth device is listed as the below. T: Bus=01 Lev=01 Prnt=01 Port=02 Cnt=01 Dev#= 6 Spd=12 MxCh= 0 D: Ver= 1.10 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=2b89 ProdID=6275 Rev= 2.00 S: Manufacturer=Realtek S: Product=Bluetooth Radio S: SerialNumber=00E04C239987 C:* #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=500mA I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=1ms E: Ad=02(O) Atr=02(Bulk) MxPS= 64 Ivl=0ms E: Ad=82(I) Atr=02(Bulk) MxPS= 64 Ivl=0ms I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms I: If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms I: If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms I: If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms I: If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms I: If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms Signed-off-by: Chingbin Li Signed-off-by: Luiz Augusto von Dentz Signed-off-by: Sasha Levin --- drivers/bluetooth/btusb.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index fa683bb7f0b49..c70e79e69be8d 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -781,6 +781,8 @@ static const struct usb_device_id quirks_table[] = { BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x2b89, 0x8761), .driver_info = BTUSB_REALTEK | BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x2b89, 0x6275), .driver_info = BTUSB_REALTEK | + BTUSB_WIDEBAND_SPEECH }, /* Additional Realtek 8821AE Bluetooth devices */ { USB_DEVICE(0x0b05, 0x17dc), .driver_info = BTUSB_REALTEK }, From c5f173e20fdd7d44c16bc412c3d94f8bc0c5f632 Mon Sep 17 00:00:00 2001 From: Chris Lu Date: Wed, 15 Oct 2025 11:31:50 +0800 Subject: [PATCH 1050/2333] Bluetooth: btusb: MT7922: Add VID/PID 0489/e170 [ Upstream commit 5a6700a31c953af9a17a7e2681335f31d922614d ] Add VID 0489 & PID e170 for MediaTek MT7922 USB Bluetooth chip. The information in /sys/kernel/debug/usb/devices about the Bluetooth device is listed as the below. T: Bus=06 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 2 Spd=480 MxCh= 0 D: Ver= 2.10 Cls=ef(misc ) Sub=02 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=0489 ProdID=e170 Rev= 1.00 S: Manufacturer=MediaTek Inc. S: Product=Wireless_Device S: SerialNumber=000000000 C:* #Ifs= 3 Cfg#= 1 Atr=e0 MxPwr=100mA A: FirstIf#= 0 IfCount= 3 Cls=e0(wlcon) Sub=01 Prot=01 I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=125us E: Ad=82(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms I: If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms I: If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms I: If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms I: If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms I: If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms I: If#= 1 Alt= 6 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 63 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 63 Ivl=1ms I:* If#= 2 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=(none) E: Ad=8a(I) Atr=03(Int.) MxPS= 64 Ivl=125us E: Ad=0a(O) Atr=03(Int.) MxPS= 64 Ivl=125us I: If#= 2 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=(none) E: Ad=8a(I) Atr=03(Int.) MxPS= 512 Ivl=125us E: Ad=0a(O) Atr=03(Int.) MxPS= 512 Ivl=125us Signed-off-by: Chris Lu Reviewed-by: Paul Menzel Signed-off-by: Luiz Augusto von Dentz Signed-off-by: Sasha Levin --- drivers/bluetooth/btusb.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index c70e79e69be8d..36f18f2657ab8 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -685,6 +685,8 @@ static const struct usb_device_id quirks_table[] = { BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x0489, 0xe153), .driver_info = BTUSB_MEDIATEK | BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x0489, 0xe170), .driver_info = BTUSB_MEDIATEK | + BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x04ca, 0x3804), .driver_info = BTUSB_MEDIATEK | BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x04ca, 0x38e4), .driver_info = BTUSB_MEDIATEK | From a8c7343e2a044bb121ba76c005f6392120d199d0 Mon Sep 17 00:00:00 2001 From: Chris Lu Date: Wed, 15 Oct 2025 11:31:49 +0800 Subject: [PATCH 1051/2333] Bluetooth: btusb: MT7920: Add VID/PID 0489/e135 [ Upstream commit c126f98c011f5796ba118ef2093122d02809d30d ] Add VID 0489 & PID e135 for MediaTek MT7920 USB Bluetooth chip. The information in /sys/kernel/debug/usb/devices about the Bluetooth device is listed as the below. T: Bus=06 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 2 Spd=480 MxCh= 0 D: Ver= 2.10 Cls=ef(misc ) Sub=02 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=0489 ProdID=e135 Rev= 1.00 S: Manufacturer=MediaTek Inc. S: Product=Wireless_Device S: SerialNumber=000000000 C:* #Ifs= 3 Cfg#= 1 Atr=e0 MxPwr=100mA A: FirstIf#= 0 IfCount= 3 Cls=e0(wlcon) Sub=01 Prot=01 I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=125us E: Ad=82(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms I: If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms I: If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms I: If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms I: If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms I: If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms I: If#= 1 Alt= 6 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 63 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 63 Ivl=1ms I:* If#= 2 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=(none) E: Ad=8a(I) Atr=03(Int.) MxPS= 64 Ivl=125us E: Ad=0a(O) Atr=03(Int.) MxPS= 64 Ivl=125us I: If#= 2 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=(none) E: Ad=8a(I) Atr=03(Int.) MxPS= 64 Ivl=125us E: Ad=0a(O) Atr=03(Int.) MxPS= 64 Ivl=125us Signed-off-by: Chris Lu Reviewed-by: Paul Menzel Signed-off-by: Luiz Augusto von Dentz Signed-off-by: Sasha Levin --- drivers/bluetooth/btusb.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 36f18f2657ab8..cc03c8c38b16f 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -621,6 +621,8 @@ static const struct usb_device_id quirks_table[] = { /* Additional MediaTek MT7920 Bluetooth devices */ { USB_DEVICE(0x0489, 0xe134), .driver_info = BTUSB_MEDIATEK | BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x0489, 0xe135), .driver_info = BTUSB_MEDIATEK | + BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x13d3, 0x3620), .driver_info = BTUSB_MEDIATEK | BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x13d3, 0x3621), .driver_info = BTUSB_MEDIATEK | From a35109f796db972cc6c7b087a9319a5918e2a5aa Mon Sep 17 00:00:00 2001 From: Shuai Zhang Date: Sun, 9 Nov 2025 17:24:37 +0800 Subject: [PATCH 1052/2333] Bluetooth: btusb: add new custom firmwares [ Upstream commit a8b38d19857d42a1f2e90c9d9b0f74de2500acd7 ] The new platform uses the QCA2066 chip along with a new board ID, which requires a dedicated firmware file to ensure proper initialization. Without this entry, the driver cannot locate and load the correct firmware, resulting in Bluetooth bring-up failure. This patch adds a new entry to the firmware table for QCA2066 so that the driver can correctly identify the board ID and load the appropriate firmware from 'qca/QCA2066/' in the linux-firmware repository. Signed-off-by: Shuai Zhang Acked-by: Dmitry Baryshkov Signed-off-by: Luiz Augusto von Dentz Signed-off-by: Sasha Levin --- drivers/bluetooth/btusb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index cc03c8c38b16f..22f1932fe9126 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -3267,6 +3267,7 @@ static const struct qca_device_info qca_devices_table[] = { static const struct qca_custom_firmware qca_custom_btfws[] = { { 0x00130201, 0x030A, "QCA2066" }, + { 0x00130201, 0x030B, "QCA2066" }, { }, }; From 81b702a5486c9d4c569b95ded28be9950db08489 Mon Sep 17 00:00:00 2001 From: Gongwei Li Date: Wed, 19 Nov 2025 15:33:38 +0800 Subject: [PATCH 1053/2333] Bluetooth: btusb: Add new VID/PID 13d3/3533 for RTL8821CE [ Upstream commit 525459da4bd62a81142fea3f3d52188ceb4d8907 ] Add VID 13d3 & PID 3533 for Realtek RTL8821CE USB Bluetooth chip. The information in /sys/kernel/debug/usb/devices about the Bluetooth device is listed as the below. T: Bus=01 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 2 Spd=12 MxCh= 0 D: Ver= 1.10 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=13d3 ProdID=3533 Rev= 1.10 S: Manufacturer=Realtek S: Product=Bluetooth Radio S: SerialNumber=00e04c000001 C:* #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=500mA I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=1ms E: Ad=02(O) Atr=02(Bulk) MxPS= 64 Ivl=0ms E: Ad=82(I) Atr=02(Bulk) MxPS= 64 Ivl=0ms I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms I: If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms I: If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms I: If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms I: If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms I: If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms Signed-off-by: Gongwei Li Signed-off-by: Luiz Augusto von Dentz Signed-off-by: Sasha Levin --- drivers/bluetooth/btusb.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 22f1932fe9126..bd26a8db64096 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -504,6 +504,8 @@ static const struct usb_device_id quirks_table[] = { /* Realtek 8821CE Bluetooth devices */ { USB_DEVICE(0x13d3, 0x3529), .driver_info = BTUSB_REALTEK | BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x13d3, 0x3533), .driver_info = BTUSB_REALTEK | + BTUSB_WIDEBAND_SPEECH }, /* Realtek 8822CE Bluetooth devices */ { USB_DEVICE(0x0bda, 0xb00c), .driver_info = BTUSB_REALTEK | From e84d2d5f3680148882b5b40914dc768819b90e29 Mon Sep 17 00:00:00 2001 From: Max Chou Date: Wed, 5 Nov 2025 13:50:39 +0800 Subject: [PATCH 1054/2333] Bluetooth: btusb: Add new VID/PID 0x0489/0xE12F for RTL8852BE-VT [ Upstream commit 32caa197b9b603e20f49fd3a0dffecd0cd620499 ] Add the support ID(0x0489, 0xE12F) to usb_device_id table for Realtek RTL8852BE-VT. The device info from /sys/kernel/debug/usb/devices as below. T: Bus=04 Lev=02 Prnt=02 Port=05 Cnt=01 Dev#= 86 Spd=12 MxCh= 0 D: Ver= 1.00 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=0489 ProdID=e12f Rev= 0.00 S: Manufacturer=Realtek S: Product=Bluetooth Radio S: SerialNumber=00e04c000001 C:* #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=500mA I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=1ms E: Ad=02(O) Atr=02(Bulk) MxPS= 64 Ivl=0ms E: Ad=82(I) Atr=02(Bulk) MxPS= 64 Ivl=0ms I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms I: If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms I: If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms I: If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms I: If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms I: If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms Signed-off-by: Max Chou Signed-off-by: Luiz Augusto von Dentz Signed-off-by: Sasha Levin --- drivers/bluetooth/btusb.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index bd26a8db64096..b92bfd131567e 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -587,6 +587,8 @@ static const struct usb_device_id quirks_table[] = { /* Realtek 8852BT/8852BE-VT Bluetooth devices */ { USB_DEVICE(0x0bda, 0x8520), .driver_info = BTUSB_REALTEK | BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x0489, 0xe12f), .driver_info = BTUSB_REALTEK | + BTUSB_WIDEBAND_SPEECH }, /* Realtek 8922AE Bluetooth devices */ { USB_DEVICE(0x0bda, 0x8922), .driver_info = BTUSB_REALTEK | From 6938e2fb4b4bbeb28112e716f749ef91600e2ff1 Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Sun, 30 Nov 2025 21:19:52 +0000 Subject: [PATCH 1055/2333] gfs2: Fix use of bio_chain [ Upstream commit 8a157e0a0aa5143b5d94201508c0ca1bb8cfb941 ] In gfs2_chain_bio(), the call to bio_chain() has its arguments swapped. The result is leaked bios and incorrect synchronization (only the last bio will actually be waited for). This code is only used during mount and filesystem thaw, so the bug normally won't be noticeable. Reported-by: Stephen Zhang Signed-off-by: Andreas Gruenbacher Signed-off-by: Sasha Levin --- fs/gfs2/lops.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c index 9c8c305a75c46..914d03f6c4e82 100644 --- a/fs/gfs2/lops.c +++ b/fs/gfs2/lops.c @@ -487,7 +487,7 @@ static struct bio *gfs2_chain_bio(struct bio *prev, unsigned int nr_iovecs) new = bio_alloc(prev->bi_bdev, nr_iovecs, prev->bi_opf, GFP_NOIO); bio_clone_blkg_association(new, prev); new->bi_iter.bi_sector = bio_end_sector(prev); - bio_chain(new, prev); + bio_chain(prev, new); submit_bio(prev); return new; } From ef4943d8c55c561a6c5a5370d7a95bf765cb59b2 Mon Sep 17 00:00:00 2001 From: Wei Fang Date: Fri, 28 Nov 2025 10:59:15 +0800 Subject: [PATCH 1056/2333] net: fec: ERR007885 Workaround for XDP TX path [ Upstream commit e8e032cd24dda7cceaa27bc2eb627f82843f0466 ] The ERR007885 will lead to a TDAR race condition for mutliQ when the driver sets TDAR and the UDMA clears TDAR simultaneously or in a small window (2-4 cycles). And it will cause the udma_tx and udma_tx_arbiter state machines to hang. Therefore, the commit 53bb20d1faba ("net: fec: add variable reg_desc_active to speed things up") and the commit a179aad12bad ("net: fec: ERR007885 Workaround for conventional TX") have added the workaround to fix the potential issue for the conventional TX path. Similarly, the XDP TX path should also have the potential hang issue, so add the workaround for XDP TX path. Fixes: 6d6b39f180b8 ("net: fec: add initial XDP support") Signed-off-by: Wei Fang Link: https://patch.msgid.link/20251128025915.2486943-1-wei.fang@nxp.com Signed-off-by: Paolo Abeni Signed-off-by: Sasha Levin --- drivers/net/ethernet/freescale/fec_main.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index 3222359ac15b7..e2b75d1970ae6 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -3948,7 +3948,12 @@ static int fec_enet_txq_xmit_frame(struct fec_enet_private *fep, txq->bd.cur = bdp; /* Trigger transmission start */ - writel(0, txq->bd.reg_desc_active); + if (!(fep->quirks & FEC_QUIRK_ERR007885) || + !readl(txq->bd.reg_desc_active) || + !readl(txq->bd.reg_desc_active) || + !readl(txq->bd.reg_desc_active) || + !readl(txq->bd.reg_desc_active)) + writel(0, txq->bd.reg_desc_active); return 0; } From 51f5fbc1681bdcffcc7d18bf3dfdb2b1278d3977 Mon Sep 17 00:00:00 2001 From: Wang Liang Date: Sat, 29 Nov 2025 12:13:15 +0800 Subject: [PATCH 1057/2333] netrom: Fix memory leak in nr_sendmsg() [ Upstream commit 613d12dd794e078be8ff3cf6b62a6b9acf7f4619 ] syzbot reported a memory leak [1]. When function sock_alloc_send_skb() return NULL in nr_output(), the original skb is not freed, which was allocated in nr_sendmsg(). Fix this by freeing it before return. [1] BUG: memory leak unreferenced object 0xffff888129f35500 (size 240): comm "syz.0.17", pid 6119, jiffies 4294944652 hex dump (first 32 bytes): 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00 00 00 00 00 00 00 00 00 10 52 28 81 88 ff ff ..........R(.... backtrace (crc 1456a3e4): kmemleak_alloc_recursive include/linux/kmemleak.h:44 [inline] slab_post_alloc_hook mm/slub.c:4983 [inline] slab_alloc_node mm/slub.c:5288 [inline] kmem_cache_alloc_node_noprof+0x36f/0x5e0 mm/slub.c:5340 __alloc_skb+0x203/0x240 net/core/skbuff.c:660 alloc_skb include/linux/skbuff.h:1383 [inline] alloc_skb_with_frags+0x69/0x3f0 net/core/skbuff.c:6671 sock_alloc_send_pskb+0x379/0x3e0 net/core/sock.c:2965 sock_alloc_send_skb include/net/sock.h:1859 [inline] nr_sendmsg+0x287/0x450 net/netrom/af_netrom.c:1105 sock_sendmsg_nosec net/socket.c:727 [inline] __sock_sendmsg net/socket.c:742 [inline] sock_write_iter+0x293/0x2a0 net/socket.c:1195 new_sync_write fs/read_write.c:593 [inline] vfs_write+0x45d/0x710 fs/read_write.c:686 ksys_write+0x143/0x170 fs/read_write.c:738 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] do_syscall_64+0xa4/0xfa0 arch/x86/entry/syscall_64.c:94 entry_SYSCALL_64_after_hwframe+0x77/0x7f Reported-by: syzbot+d7abc36bbbb6d7d40b58@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=d7abc36bbbb6d7d40b58 Tested-by: syzbot+d7abc36bbbb6d7d40b58@syzkaller.appspotmail.com Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Signed-off-by: Wang Liang Link: https://patch.msgid.link/20251129041315.1550766-1-wangliang74@huawei.com Signed-off-by: Paolo Abeni Signed-off-by: Sasha Levin --- net/netrom/nr_out.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/netrom/nr_out.c b/net/netrom/nr_out.c index 5e531394a724b..2b3cbceb0b52d 100644 --- a/net/netrom/nr_out.c +++ b/net/netrom/nr_out.c @@ -43,8 +43,10 @@ void nr_output(struct sock *sk, struct sk_buff *skb) frontlen = skb_headroom(skb); while (skb->len > 0) { - if ((skbn = sock_alloc_send_skb(sk, frontlen + NR_MAX_PACKET_SIZE, 0, &err)) == NULL) + if ((skbn = sock_alloc_send_skb(sk, frontlen + NR_MAX_PACKET_SIZE, 0, &err)) == NULL) { + kfree_skb(skb); return; + } skb_reserve(skbn, frontlen); From 45466141da3c98a0c5fa88be0bc14b4b6a4bd75c Mon Sep 17 00:00:00 2001 From: Jamal Hadi Salim Date: Fri, 28 Nov 2025 10:19:19 -0500 Subject: [PATCH 1058/2333] net/sched: ets: Always remove class from active list before deleting in ets_qdisc_change [ Upstream commit ce052b9402e461a9aded599f5b47e76bc727f7de ] zdi-disclosures@trendmicro.com says: The vulnerability is a race condition between `ets_qdisc_dequeue` and `ets_qdisc_change`. It leads to UAF on `struct Qdisc` object. Attacker requires the capability to create new user and network namespace in order to trigger the bug. See my additional commentary at the end of the analysis. Analysis: static int ets_qdisc_change(struct Qdisc *sch, struct nlattr *opt, struct netlink_ext_ack *extack) { ... // (1) this lock is preventing .change handler (`ets_qdisc_change`) //to race with .dequeue handler (`ets_qdisc_dequeue`) sch_tree_lock(sch); for (i = nbands; i < oldbands; i++) { if (i >= q->nstrict && q->classes[i].qdisc->q.qlen) list_del_init(&q->classes[i].alist); qdisc_purge_queue(q->classes[i].qdisc); } WRITE_ONCE(q->nbands, nbands); for (i = nstrict; i < q->nstrict; i++) { if (q->classes[i].qdisc->q.qlen) { // (2) the class is added to the q->active list_add_tail(&q->classes[i].alist, &q->active); q->classes[i].deficit = quanta[i]; } } WRITE_ONCE(q->nstrict, nstrict); memcpy(q->prio2band, priomap, sizeof(priomap)); for (i = 0; i < q->nbands; i++) WRITE_ONCE(q->classes[i].quantum, quanta[i]); for (i = oldbands; i < q->nbands; i++) { q->classes[i].qdisc = queues[i]; if (q->classes[i].qdisc != &noop_qdisc) qdisc_hash_add(q->classes[i].qdisc, true); } // (3) the qdisc is unlocked, now dequeue can be called in parallel // to the rest of .change handler sch_tree_unlock(sch); ets_offload_change(sch); for (i = q->nbands; i < oldbands; i++) { // (4) we're reducing the refcount for our class's qdisc and // freeing it qdisc_put(q->classes[i].qdisc); // (5) If we call .dequeue between (4) and (5), we will have // a strong UAF and we can control RIP q->classes[i].qdisc = NULL; WRITE_ONCE(q->classes[i].quantum, 0); q->classes[i].deficit = 0; gnet_stats_basic_sync_init(&q->classes[i].bstats); memset(&q->classes[i].qstats, 0, sizeof(q->classes[i].qstats)); } return 0; } Comment: This happens because some of the classes have their qdiscs assigned to NULL, but remain in the active list. This commit fixes this issue by always removing the class from the active list before deleting and freeing its associated qdisc Reproducer Steps (trimmed version of what was sent by zdi-disclosures@trendmicro.com) ``` DEV="${DEV:-lo}" ROOT_HANDLE="${ROOT_HANDLE:-1:}" BAND2_HANDLE="${BAND2_HANDLE:-20:}" # child under 1:2 PING_BYTES="${PING_BYTES:-48}" PING_COUNT="${PING_COUNT:-200000}" PING_DST="${PING_DST:-127.0.0.1}" SLOW_TBF_RATE="${SLOW_TBF_RATE:-8bit}" SLOW_TBF_BURST="${SLOW_TBF_BURST:-100b}" SLOW_TBF_LAT="${SLOW_TBF_LAT:-1s}" cleanup() { tc qdisc del dev "$DEV" root 2>/dev/null } trap cleanup EXIT ip link set "$DEV" up tc qdisc del dev "$DEV" root 2>/dev/null || true tc qdisc add dev "$DEV" root handle "$ROOT_HANDLE" ets bands 2 strict 2 tc qdisc add dev "$DEV" parent 1:2 handle "$BAND2_HANDLE" \ tbf rate "$SLOW_TBF_RATE" burst "$SLOW_TBF_BURST" latency "$SLOW_TBF_LAT" tc filter add dev "$DEV" parent 1: protocol all prio 1 u32 match u32 0 0 flowid 1:2 tc -s qdisc ls dev $DEV ping -I "$DEV" -f -c "$PING_COUNT" -s "$PING_BYTES" -W 0.001 "$PING_DST" \ >/dev/null 2>&1 & tc qdisc change dev "$DEV" root handle "$ROOT_HANDLE" ets bands 2 strict 0 tc qdisc change dev "$DEV" root handle "$ROOT_HANDLE" ets bands 2 strict 2 tc -s qdisc ls dev $DEV tc qdisc del dev "$DEV" parent 1:2 || true tc -s qdisc ls dev $DEV tc qdisc change dev "$DEV" root handle "$ROOT_HANDLE" ets bands 1 strict 1 ``` KASAN report ``` ================================================================== BUG: KASAN: slab-use-after-free in ets_qdisc_dequeue+0x1071/0x11b0 kernel/net/sched/sch_ets.c:481 Read of size 8 at addr ffff8880502fc018 by task ping/12308 > CPU: 0 UID: 0 PID: 12308 Comm: ping Not tainted 6.18.0-rc4-dirty #1 PREEMPT(full) Hardware name: QEMU Ubuntu 25.04 PC (i440FX + PIIX, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 Call Trace: __dump_stack kernel/lib/dump_stack.c:94 dump_stack_lvl+0x100/0x190 kernel/lib/dump_stack.c:120 print_address_description kernel/mm/kasan/report.c:378 print_report+0x156/0x4c9 kernel/mm/kasan/report.c:482 kasan_report+0xdf/0x110 kernel/mm/kasan/report.c:595 ets_qdisc_dequeue+0x1071/0x11b0 kernel/net/sched/sch_ets.c:481 dequeue_skb kernel/net/sched/sch_generic.c:294 qdisc_restart kernel/net/sched/sch_generic.c:399 __qdisc_run+0x1c9/0x1b00 kernel/net/sched/sch_generic.c:417 __dev_xmit_skb kernel/net/core/dev.c:4221 __dev_queue_xmit+0x2848/0x4410 kernel/net/core/dev.c:4729 dev_queue_xmit kernel/./include/linux/netdevice.h:3365 [...] Allocated by task 17115: kasan_save_stack+0x30/0x50 kernel/mm/kasan/common.c:56 kasan_save_track+0x14/0x30 kernel/mm/kasan/common.c:77 poison_kmalloc_redzone kernel/mm/kasan/common.c:400 __kasan_kmalloc+0xaa/0xb0 kernel/mm/kasan/common.c:417 kasan_kmalloc kernel/./include/linux/kasan.h:262 __do_kmalloc_node kernel/mm/slub.c:5642 __kmalloc_node_noprof+0x34e/0x990 kernel/mm/slub.c:5648 kmalloc_node_noprof kernel/./include/linux/slab.h:987 qdisc_alloc+0xb8/0xc30 kernel/net/sched/sch_generic.c:950 qdisc_create_dflt+0x93/0x490 kernel/net/sched/sch_generic.c:1012 ets_class_graft+0x4fd/0x800 kernel/net/sched/sch_ets.c:261 qdisc_graft+0x3e4/0x1780 kernel/net/sched/sch_api.c:1196 [...] Freed by task 9905: kasan_save_stack+0x30/0x50 kernel/mm/kasan/common.c:56 kasan_save_track+0x14/0x30 kernel/mm/kasan/common.c:77 __kasan_save_free_info+0x3b/0x70 kernel/mm/kasan/generic.c:587 kasan_save_free_info kernel/mm/kasan/kasan.h:406 poison_slab_object kernel/mm/kasan/common.c:252 __kasan_slab_free+0x5f/0x80 kernel/mm/kasan/common.c:284 kasan_slab_free kernel/./include/linux/kasan.h:234 slab_free_hook kernel/mm/slub.c:2539 slab_free kernel/mm/slub.c:6630 kfree+0x144/0x700 kernel/mm/slub.c:6837 rcu_do_batch kernel/kernel/rcu/tree.c:2605 rcu_core+0x7c0/0x1500 kernel/kernel/rcu/tree.c:2861 handle_softirqs+0x1ea/0x8a0 kernel/kernel/softirq.c:622 __do_softirq kernel/kernel/softirq.c:656 [...] Commentary: 1. Maher Azzouzi working with Trend Micro Zero Day Initiative was reported as the person who found the issue. I requested to get a proper email to add to the reported-by tag but got no response. For this reason i will credit the person i exchanged emails with i.e zdi-disclosures@trendmicro.com 2. Neither i nor Victor who did a much more thorough testing was able to reproduce a UAF with the PoC or other approaches we tried. We were both able to reproduce a null ptr deref. After exchange with zdi-disclosures@trendmicro.com they sent a small change to be made to the code to add an extra delay which was able to simulate the UAF. i.e, this: qdisc_put(q->classes[i].qdisc); mdelay(90); q->classes[i].qdisc = NULL; I was informed by Thomas Gleixner(tglx@linutronix.de) that adding delays was acceptable approach for demonstrating the bug, quote: "Adding such delays is common exploit validation practice" The equivalent delay could happen "by virt scheduling the vCPU out, SMIs, NMIs, PREEMPT_RT enabled kernel" 3. I asked the OP to test and report back but got no response and after a few days gave up and proceeded to submit this fix. Fixes: de6d25924c2a ("net/sched: sch_ets: don't peek at classes beyond 'nbands'") Reported-by: zdi-disclosures@trendmicro.com Tested-by: Victor Nogueira Signed-off-by: Jamal Hadi Salim Reviewed-by: Davide Caratti Link: https://patch.msgid.link/20251128151919.576920-1-jhs@mojatatu.com Signed-off-by: Paolo Abeni Signed-off-by: Sasha Levin --- net/sched/sch_ets.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/sched/sch_ets.c b/net/sched/sch_ets.c index 82635dd2cfa59..ae46643e596d3 100644 --- a/net/sched/sch_ets.c +++ b/net/sched/sch_ets.c @@ -652,7 +652,7 @@ static int ets_qdisc_change(struct Qdisc *sch, struct nlattr *opt, sch_tree_lock(sch); for (i = nbands; i < oldbands; i++) { - if (i >= q->nstrict && q->classes[i].qdisc->q.qlen) + if (cl_is_active(&q->classes[i])) list_del_init(&q->classes[i].alist); qdisc_purge_queue(q->classes[i].qdisc); } From f4a16bb7f8b5bf0074ad1707ecf9c76acd7e2ff1 Mon Sep 17 00:00:00 2001 From: Moshe Shemesh Date: Mon, 1 Dec 2025 17:13:27 +0200 Subject: [PATCH 1059/2333] net/mlx5: make enable_mpesw idempotent [ Upstream commit cd7671ef4cf2edf73cd2a3dca3a2f522a4525bf5 ] The enable_mpesw() function returns -EINVAL if ldev->mode is not MLX5_LAG_MODE_NONE. This means attempting to enable MPESW mode when it's already enabled will fail. In contrast, disable_mpesw() properly checks if the mode is MLX5_LAG_MODE_MPESW before proceeding, making it naturally idempotent and safe to call multiple times. Fix enable_mpesw() to return success if mpesw is already enabled. Fixes: a32327a3a02c ("net/mlx5: Lag, Control MultiPort E-Switch single FDB mode") Signed-off-by: Moshe Shemesh Reviewed-by: Shay Drori Signed-off-by: Tariq Toukan Reviewed-by: Simon Horman Link: https://patch.msgid.link/1764602008-1334866-2-git-send-email-tariqt@nvidia.com Signed-off-by: Paolo Abeni Signed-off-by: Sasha Levin --- drivers/net/ethernet/mellanox/mlx5/core/lag/mpesw.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/mpesw.c b/drivers/net/ethernet/mellanox/mlx5/core/lag/mpesw.c index aad52d3a90e68..2d86af8f0d9b8 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lag/mpesw.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/mpesw.c @@ -67,12 +67,19 @@ static int mlx5_mpesw_metadata_set(struct mlx5_lag *ldev) static int enable_mpesw(struct mlx5_lag *ldev) { - int idx = mlx5_lag_get_dev_index_by_seq(ldev, MLX5_LAG_P1); struct mlx5_core_dev *dev0; int err; + int idx; int i; - if (idx < 0 || ldev->mode != MLX5_LAG_MODE_NONE) + if (ldev->mode == MLX5_LAG_MODE_MPESW) + return 0; + + if (ldev->mode != MLX5_LAG_MODE_NONE) + return -EINVAL; + + idx = mlx5_lag_get_dev_index_by_seq(ldev, MLX5_LAG_P1); + if (idx < 0) return -EINVAL; dev0 = ldev->pf[idx].dev; From e12c912f92ccea671b514caf371f28485714bb4b Mon Sep 17 00:00:00 2001 From: Cosmin Ratiu Date: Mon, 1 Dec 2025 17:13:28 +0200 Subject: [PATCH 1060/2333] net/mlx5e: Avoid unregistering PSP twice [ Upstream commit 35e93736f69963337912594eb3951ab320b77521 ] PSP is unregistered twice in: _mlx5e_remove -> mlx5e_psp_unregister mlx5e_nic_cleanup -> mlx5e_psp_unregister This leads to a refcount underflow in some conditions: ------------[ cut here ]------------ refcount_t: underflow; use-after-free. WARNING: CPU: 2 PID: 1694 at lib/refcount.c:28 refcount_warn_saturate+0xd8/0xe0 [...] mlx5e_psp_unregister+0x26/0x50 [mlx5_core] mlx5e_nic_cleanup+0x26/0x90 [mlx5_core] mlx5e_remove+0xe6/0x1f0 [mlx5_core] auxiliary_bus_remove+0x18/0x30 device_release_driver_internal+0x194/0x1f0 bus_remove_device+0xc6/0x130 device_del+0x159/0x3c0 mlx5_rescan_drivers_locked+0xbc/0x2a0 [mlx5_core] [...] Do not directly remove psp from the _mlx5e_remove path, the PSP cleanup happens as part of profile cleanup. Fixes: 89ee2d92f66c ("net/mlx5e: Support PSP offload functionality") Signed-off-by: Cosmin Ratiu Reviewed-by: Dragos Tatulea Signed-off-by: Tariq Toukan Reviewed-by: Simon Horman Link: https://patch.msgid.link/1764602008-1334866-3-git-send-email-tariqt@nvidia.com Signed-off-by: Paolo Abeni Signed-off-by: Sasha Levin --- drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index 5e17eae81f4b3..1545f9c008f49 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -6805,7 +6805,6 @@ static void _mlx5e_remove(struct auxiliary_device *adev) * is already unregistered before changing to NIC profile. */ if (priv->netdev->reg_state == NETREG_REGISTERED) { - mlx5e_psp_unregister(priv); unregister_netdev(priv->netdev); _mlx5e_suspend(adev, false); } else { From 7ec73f0e16000e10c0a4e023ce7f2115d8ef6601 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Tue, 18 Nov 2025 01:40:29 +0200 Subject: [PATCH 1061/2333] net: phy: realtek: eliminate priv->phycr2 variable [ Upstream commit 27033d06917758d47162581da7e9de8004049dee ] The RTL8211F(D)(I)-VD-CG PHY also has support for disabling the CLKOUT, and we'd like to introduce the "realtek,clkout-disable" property for that. But it isn't done through the PHYCR2 register, and it becomes awkward to have the driver pretend that it is. So just replace the machine-level "u16 phycr2" variable with a logical "bool disable_clk_out", which scales better to the other PHY as well. The change is a complete functional equivalent. Before, if the device tree property was absent, priv->phycr2 would contain the RTL8211F_CLKOUT_EN bit as read from hardware. Now, we don't save priv->phycr2, but we just don't call phy_modify_paged() on it. Also, we can simply call phy_modify_paged() with the "set" argument to 0. Signed-off-by: Vladimir Oltean Link: https://patch.msgid.link/20251117234033.345679-3-vladimir.oltean@nxp.com Signed-off-by: Jakub Kicinski Stable-dep-of: 4f0638b12451 ("net: phy: RTL8211FVD: Restore disabling of PHY-mode EEE") Signed-off-by: Sasha Levin --- drivers/net/phy/realtek/realtek_main.c | 38 ++++++++++++++++---------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/drivers/net/phy/realtek/realtek_main.c b/drivers/net/phy/realtek/realtek_main.c index b26f4d1c6bbfa..1625919a47be8 100644 --- a/drivers/net/phy/realtek/realtek_main.c +++ b/drivers/net/phy/realtek/realtek_main.c @@ -167,8 +167,8 @@ MODULE_LICENSE("GPL"); struct rtl821x_priv { u16 phycr1; - u16 phycr2; bool has_phycr2; + bool disable_clk_out; struct clk *clk; /* rtl8211f */ u16 iner; @@ -239,15 +239,8 @@ static int rtl821x_probe(struct phy_device *phydev) priv->phycr1 |= RTL8211F_ALDPS_PLL_OFF | RTL8211F_ALDPS_ENABLE | RTL8211F_ALDPS_XTAL_OFF; priv->has_phycr2 = !(phy_id == RTL_8211FVD_PHYID); - if (priv->has_phycr2) { - ret = phy_read_paged(phydev, RTL8211F_PHYCR_PAGE, RTL8211F_PHYCR2); - if (ret < 0) - return ret; - - priv->phycr2 = ret & RTL8211F_CLKOUT_EN; - if (of_property_read_bool(dev->of_node, "realtek,clkout-disable")) - priv->phycr2 &= ~RTL8211F_CLKOUT_EN; - } + priv->disable_clk_out = of_property_read_bool(dev->of_node, + "realtek,clkout-disable"); phydev->priv = priv; @@ -627,6 +620,23 @@ static int rtl8211f_config_rgmii_delay(struct phy_device *phydev) return 0; } +static int rtl8211f_config_clk_out(struct phy_device *phydev) +{ + struct rtl821x_priv *priv = phydev->priv; + int ret; + + /* The value is preserved if the device tree property is absent */ + if (!priv->disable_clk_out) + return 0; + + ret = phy_modify_paged(phydev, RTL8211F_PHYCR_PAGE, + RTL8211F_PHYCR2, RTL8211F_CLKOUT_EN, 0); + if (ret) + return ret; + + return genphy_soft_reset(phydev); +} + static int rtl8211f_config_init(struct phy_device *phydev) { struct rtl821x_priv *priv = phydev->priv; @@ -655,16 +665,14 @@ static int rtl8211f_config_init(struct phy_device *phydev) if (ret) return ret; - ret = phy_modify_paged(phydev, RTL8211F_PHYCR_PAGE, - RTL8211F_PHYCR2, RTL8211F_CLKOUT_EN, - priv->phycr2); - if (ret < 0) { + ret = rtl8211f_config_clk_out(phydev); + if (ret) { dev_err(dev, "clkout configuration failed: %pe\n", ERR_PTR(ret)); return ret; } - return genphy_soft_reset(phydev); + return 0; } static int rtl821x_suspend(struct phy_device *phydev) From d064d95c74d33bc2a2c21b65a45679a71eabab3a Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Tue, 18 Nov 2025 01:40:30 +0200 Subject: [PATCH 1062/2333] net: phy: realtek: eliminate has_phycr2 variable [ Upstream commit 910ac7bfb1af1ae4cd141ef80e03a6729213c189 ] This variable is assigned in rtl821x_probe() and used in rtl8211f_config_init(), which is more complex than it needs to be. Simply testing the same condition from rtl821x_probe() in rtl8211f_config_init() yields the same result (the PHY driver ID is a runtime invariant), but with one temporary variable less. Signed-off-by: Vladimir Oltean Reviewed-by: Andrew Lunn Link: https://patch.msgid.link/20251117234033.345679-4-vladimir.oltean@nxp.com Signed-off-by: Jakub Kicinski Stable-dep-of: 4f0638b12451 ("net: phy: RTL8211FVD: Restore disabling of PHY-mode EEE") Signed-off-by: Sasha Levin --- drivers/net/phy/realtek/realtek_main.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/phy/realtek/realtek_main.c b/drivers/net/phy/realtek/realtek_main.c index 1625919a47be8..daf2457b378bf 100644 --- a/drivers/net/phy/realtek/realtek_main.c +++ b/drivers/net/phy/realtek/realtek_main.c @@ -167,7 +167,6 @@ MODULE_LICENSE("GPL"); struct rtl821x_priv { u16 phycr1; - bool has_phycr2; bool disable_clk_out; struct clk *clk; /* rtl8211f */ @@ -218,7 +217,6 @@ static int rtl821x_probe(struct phy_device *phydev) { struct device *dev = &phydev->mdio.dev; struct rtl821x_priv *priv; - u32 phy_id = phydev->drv->phy_id; int ret; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); @@ -238,7 +236,6 @@ static int rtl821x_probe(struct phy_device *phydev) if (of_property_read_bool(dev->of_node, "realtek,aldps-enable")) priv->phycr1 |= RTL8211F_ALDPS_PLL_OFF | RTL8211F_ALDPS_ENABLE | RTL8211F_ALDPS_XTAL_OFF; - priv->has_phycr2 = !(phy_id == RTL_8211FVD_PHYID); priv->disable_clk_out = of_property_read_bool(dev->of_node, "realtek,clkout-disable"); @@ -656,7 +653,8 @@ static int rtl8211f_config_init(struct phy_device *phydev) if (ret) return ret; - if (!priv->has_phycr2) + /* RTL8211FVD has no PHYCR2 register */ + if (phydev->drv->phy_id == RTL_8211FVD_PHYID) return 0; /* Disable PHY-mode EEE so LPI is passed to the MAC */ From ce370d988122db1aab79b99419e7444dfe31996d Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Tue, 18 Nov 2025 01:40:31 +0200 Subject: [PATCH 1063/2333] net: phy: realtek: allow CLKOUT to be disabled on RTL8211F(D)(I)-VD-CG [ Upstream commit e1a31c41bef678afe0d99b7f0dc3711a80c68447 ] Add CLKOUT disable support for RTL8211F(D)(I)-VD-CG. Like with other PHY variants, this feature might be requested by customers when the clock output is not used, in order to reduce electromagnetic interference (EMI). In the common driver, the CLKOUT configuration is done through PHYCR2. The RTL_8211FVD_PHYID is singled out as not having that register, and execution in rtl8211f_config_init() returns early after commit 2c67301584f2 ("net: phy: realtek: Avoid PHYCR2 access if PHYCR2 not present"). But actually CLKOUT is configured through a different register for this PHY. Instead of pretending this is PHYCR2 (which it is not), just add some code for modifying this register inside the rtl8211f_disable_clk_out() function, and move that outside the code portion that runs only if PHYCR2 exists. In practice this reorders the PHYCR2 writes to disable PHY-mode EEE and to disable the CLKOUT for the normal RTL8211F variants, but this should be perfectly fine. It was not noted that RTL8211F(D)(I)-VD-CG would need a genphy_soft_reset() call after disabling the CLKOUT. Despite that, we do it out of caution and for symmetry with the other RTL8211F models. Co-developed-by: Clark Wang Signed-off-by: Clark Wang Signed-off-by: Vladimir Oltean Reviewed-by: Andrew Lunn Link: https://patch.msgid.link/20251117234033.345679-5-vladimir.oltean@nxp.com Signed-off-by: Jakub Kicinski Stable-dep-of: 4f0638b12451 ("net: phy: RTL8211FVD: Restore disabling of PHY-mode EEE") Signed-off-by: Sasha Levin --- drivers/net/phy/realtek/realtek_main.c | 31 ++++++++++++++++++-------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/drivers/net/phy/realtek/realtek_main.c b/drivers/net/phy/realtek/realtek_main.c index daf2457b378bf..f0348b92beec3 100644 --- a/drivers/net/phy/realtek/realtek_main.c +++ b/drivers/net/phy/realtek/realtek_main.c @@ -89,6 +89,14 @@ #define RTL8211F_LEDCR_MASK GENMASK(4, 0) #define RTL8211F_LEDCR_SHIFT 5 +/* RTL8211F(D)(I)-VD-CG CLKOUT configuration is specified via magic values + * to undocumented register pages. The names here do not reflect the datasheet. + * Unlike other PHY models, CLKOUT configuration does not go through PHYCR2. + */ +#define RTL8211FVD_CLKOUT_PAGE 0xd05 +#define RTL8211FVD_CLKOUT_REG 0x11 +#define RTL8211FVD_CLKOUT_EN BIT(8) + /* RTL8211F RGMII configuration */ #define RTL8211F_RGMII_PAGE 0xd08 @@ -626,8 +634,13 @@ static int rtl8211f_config_clk_out(struct phy_device *phydev) if (!priv->disable_clk_out) return 0; - ret = phy_modify_paged(phydev, RTL8211F_PHYCR_PAGE, - RTL8211F_PHYCR2, RTL8211F_CLKOUT_EN, 0); + if (phydev->drv->phy_id == RTL_8211FVD_PHYID) + ret = phy_modify_paged(phydev, RTL8211FVD_CLKOUT_PAGE, + RTL8211FVD_CLKOUT_REG, + RTL8211FVD_CLKOUT_EN, 0); + else + ret = phy_modify_paged(phydev, RTL8211F_PHYCR_PAGE, + RTL8211F_PHYCR2, RTL8211F_CLKOUT_EN, 0); if (ret) return ret; @@ -653,6 +666,13 @@ static int rtl8211f_config_init(struct phy_device *phydev) if (ret) return ret; + ret = rtl8211f_config_clk_out(phydev); + if (ret) { + dev_err(dev, "clkout configuration failed: %pe\n", + ERR_PTR(ret)); + return ret; + } + /* RTL8211FVD has no PHYCR2 register */ if (phydev->drv->phy_id == RTL_8211FVD_PHYID) return 0; @@ -663,13 +683,6 @@ static int rtl8211f_config_init(struct phy_device *phydev) if (ret) return ret; - ret = rtl8211f_config_clk_out(phydev); - if (ret) { - dev_err(dev, "clkout configuration failed: %pe\n", - ERR_PTR(ret)); - return ret; - } - return 0; } From c6a23498f795fd286acddd912bc1b2de79ab0306 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Tue, 18 Nov 2025 01:40:32 +0200 Subject: [PATCH 1064/2333] net: phy: realtek: eliminate priv->phycr1 variable [ Upstream commit bb78b71faf60d11a15f07e3390fcfd31e5e523bb ] Previous changes have replaced the machine-level priv->phycr2 with a high-level priv->disable_clk_out. This created a discrepancy with priv->phycr1 which is resolved here, for uniformity. One advantage of this new implementation is that we don't read priv->phycr1 in rtl821x_probe() if we're never going to modify it. We never test the positive return code from phy_modify_mmd_changed(), so we could just as well use phy_modify_mmd(). I took the ALDPS feature description from commit d90db36a9e74 ("net: phy: realtek: add dt property to enable ALDPS mode") and transformed it into a function comment - the feature is sufficiently non-obvious to deserve that. Signed-off-by: Vladimir Oltean Reviewed-by: Andrew Lunn Link: https://patch.msgid.link/20251117234033.345679-6-vladimir.oltean@nxp.com Signed-off-by: Jakub Kicinski Stable-dep-of: 4f0638b12451 ("net: phy: RTL8211FVD: Restore disabling of PHY-mode EEE") Signed-off-by: Sasha Levin --- drivers/net/phy/realtek/realtek_main.c | 44 ++++++++++++++++---------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/drivers/net/phy/realtek/realtek_main.c b/drivers/net/phy/realtek/realtek_main.c index f0348b92beec3..35f40bfdaf113 100644 --- a/drivers/net/phy/realtek/realtek_main.c +++ b/drivers/net/phy/realtek/realtek_main.c @@ -174,7 +174,7 @@ MODULE_AUTHOR("Johnson Leung"); MODULE_LICENSE("GPL"); struct rtl821x_priv { - u16 phycr1; + bool enable_aldps; bool disable_clk_out; struct clk *clk; /* rtl8211f */ @@ -225,7 +225,6 @@ static int rtl821x_probe(struct phy_device *phydev) { struct device *dev = &phydev->mdio.dev; struct rtl821x_priv *priv; - int ret; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) @@ -236,14 +235,8 @@ static int rtl821x_probe(struct phy_device *phydev) return dev_err_probe(dev, PTR_ERR(priv->clk), "failed to get phy clock\n"); - ret = phy_read_paged(phydev, RTL8211F_PHYCR_PAGE, RTL8211F_PHYCR1); - if (ret < 0) - return ret; - - priv->phycr1 = ret & (RTL8211F_ALDPS_PLL_OFF | RTL8211F_ALDPS_ENABLE | RTL8211F_ALDPS_XTAL_OFF); - if (of_property_read_bool(dev->of_node, "realtek,aldps-enable")) - priv->phycr1 |= RTL8211F_ALDPS_PLL_OFF | RTL8211F_ALDPS_ENABLE | RTL8211F_ALDPS_XTAL_OFF; - + priv->enable_aldps = of_property_read_bool(dev->of_node, + "realtek,aldps-enable"); priv->disable_clk_out = of_property_read_bool(dev->of_node, "realtek,clkout-disable"); @@ -647,17 +640,36 @@ static int rtl8211f_config_clk_out(struct phy_device *phydev) return genphy_soft_reset(phydev); } -static int rtl8211f_config_init(struct phy_device *phydev) +/* Advance Link Down Power Saving (ALDPS) mode changes crystal/clock behaviour, + * which causes the RXC clock signal to stop for tens to hundreds of + * milliseconds. + * + * Some MACs need the RXC clock to support their internal RX logic, so ALDPS is + * only enabled based on an opt-in device tree property. + */ +static int rtl8211f_config_aldps(struct phy_device *phydev) { struct rtl821x_priv *priv = phydev->priv; + u16 mask = RTL8211F_ALDPS_PLL_OFF | + RTL8211F_ALDPS_ENABLE | + RTL8211F_ALDPS_XTAL_OFF; + + /* The value is preserved if the device tree property is absent */ + if (!priv->enable_aldps) + return 0; + + return phy_modify_paged(phydev, RTL8211F_PHYCR_PAGE, RTL8211F_PHYCR1, + mask, mask); +} + +static int rtl8211f_config_init(struct phy_device *phydev) +{ struct device *dev = &phydev->mdio.dev; int ret; - ret = phy_modify_paged_changed(phydev, RTL8211F_PHYCR_PAGE, RTL8211F_PHYCR1, - RTL8211F_ALDPS_PLL_OFF | RTL8211F_ALDPS_ENABLE | RTL8211F_ALDPS_XTAL_OFF, - priv->phycr1); - if (ret < 0) { - dev_err(dev, "aldps mode configuration failed: %pe\n", + ret = rtl8211f_config_aldps(phydev); + if (ret) { + dev_err(dev, "aldps mode configuration failed: %pe\n", ERR_PTR(ret)); return ret; } From e3859271c72cafc081756bfc1ab9f4e19a5e5215 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Tue, 18 Nov 2025 01:40:33 +0200 Subject: [PATCH 1065/2333] net: phy: realtek: create rtl8211f_config_phy_eee() helper [ Upstream commit 4465ae435ddc0162d5033a543658449d53d46d08 ] To simplify the rtl8211f_config_init() control flow and get rid of "early" returns for PHYs where the PHYCR2 register is absent, move the entire logic sub-block that deals with disabling PHY-mode EEE to a separate function. There, it is much more obvious what the early "return 0" skips, and it becomes more difficult to accidentally skip unintended stuff. Signed-off-by: Vladimir Oltean Link: https://patch.msgid.link/20251117234033.345679-7-vladimir.oltean@nxp.com Signed-off-by: Jakub Kicinski Stable-dep-of: 4f0638b12451 ("net: phy: RTL8211FVD: Restore disabling of PHY-mode EEE") Signed-off-by: Sasha Levin --- drivers/net/phy/realtek/realtek_main.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/drivers/net/phy/realtek/realtek_main.c b/drivers/net/phy/realtek/realtek_main.c index 35f40bfdaf113..2c661346050f1 100644 --- a/drivers/net/phy/realtek/realtek_main.c +++ b/drivers/net/phy/realtek/realtek_main.c @@ -662,6 +662,17 @@ static int rtl8211f_config_aldps(struct phy_device *phydev) mask, mask); } +static int rtl8211f_config_phy_eee(struct phy_device *phydev) +{ + /* RTL8211FVD has no PHYCR2 register */ + if (phydev->drv->phy_id == RTL_8211FVD_PHYID) + return 0; + + /* Disable PHY-mode EEE so LPI is passed to the MAC */ + return phy_modify_paged(phydev, RTL8211F_PHYCR_PAGE, RTL8211F_PHYCR2, + RTL8211F_PHYCR2_PHY_EEE_ENABLE, 0); +} + static int rtl8211f_config_init(struct phy_device *phydev) { struct device *dev = &phydev->mdio.dev; @@ -685,17 +696,7 @@ static int rtl8211f_config_init(struct phy_device *phydev) return ret; } - /* RTL8211FVD has no PHYCR2 register */ - if (phydev->drv->phy_id == RTL_8211FVD_PHYID) - return 0; - - /* Disable PHY-mode EEE so LPI is passed to the MAC */ - ret = phy_modify_paged(phydev, RTL8211F_PHYCR_PAGE, RTL8211F_PHYCR2, - RTL8211F_PHYCR2_PHY_EEE_ENABLE, 0); - if (ret) - return ret; - - return 0; + return rtl8211f_config_phy_eee(phydev); } static int rtl821x_suspend(struct phy_device *phydev) From 90206ede631836277eee7c1ff03288e5b8420b7a Mon Sep 17 00:00:00 2001 From: Ivan Galkin Date: Tue, 2 Dec 2025 10:07:42 +0100 Subject: [PATCH 1066/2333] net: phy: RTL8211FVD: Restore disabling of PHY-mode EEE [ Upstream commit 4f0638b12451112de4138689fa679315c8d388dc ] When support for RTL8211F(D)(I)-VD-CG was introduced in commit bb726b753f75 ("net: phy: realtek: add support for RTL8211F(D)(I)-VD-CG") the implementation assumed that this PHY model doesn't have the control register PHYCR2 (Page 0xa43 Address 0x19). This assumption was based on the differences in CLKOUT configurations between RTL8211FVD and the remaining RTL8211F PHYs. In the latter commit 2c67301584f2 ("net: phy: realtek: Avoid PHYCR2 access if PHYCR2 not present") this assumption was expanded to the PHY-mode EEE. I performed tests on RTL8211FI-VD-CG and confirmed that disabling PHY-mode EEE works correctly and is uniform with other PHYs supported by the driver. To validate the correctness, I contacted Realtek support. Realtek confirmed that PHY-mode EEE on RTL8211F(D)(I)-VD-CG is configured via Page 0xa43 Address 0x19 bit 5. Moreover, Realtek informed me that the most recent datasheet for RTL8211F(D)(I)-VD-CG v1.1 is incomplete and the naming of control registers is partly inconsistent. The errata I received from Realtek corrects the naming as follows: | Register | Datasheet v1.1 | Errata | |-------------------------|----------------|--------| | Page 0xa44 Address 0x11 | PHYCR2 | PHYCR3 | | Page 0xa43 Address 0x19 | N/A | PHYCR2 | This information confirms that the supposedly missing control register, PHYCR2, exists in the RTL8211F(D)(I)-VD-CG under the same address and the same name. It controls widely the same configs as other PHYs from the RTL8211F series (e.g. PHY-mode EEE). Clock out configuration is an exception. Given all this information, restore disabling of the PHY-mode EEE. Fixes: 2c67301584f2 ("net: phy: realtek: Avoid PHYCR2 access if PHYCR2 not present") Signed-off-by: Ivan Galkin Reviewed-by: Vladimir Oltean Link: https://patch.msgid.link/20251202-phy_eee-v1-1-fe0bf6ab3df0@axis.com Signed-off-by: Paolo Abeni Signed-off-by: Sasha Levin --- drivers/net/phy/realtek/realtek_main.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/net/phy/realtek/realtek_main.c b/drivers/net/phy/realtek/realtek_main.c index 2c661346050f1..7c3d277efaf07 100644 --- a/drivers/net/phy/realtek/realtek_main.c +++ b/drivers/net/phy/realtek/realtek_main.c @@ -664,10 +664,6 @@ static int rtl8211f_config_aldps(struct phy_device *phydev) static int rtl8211f_config_phy_eee(struct phy_device *phydev) { - /* RTL8211FVD has no PHYCR2 register */ - if (phydev->drv->phy_id == RTL_8211FVD_PHYID) - return 0; - /* Disable PHY-mode EEE so LPI is passed to the MAC */ return phy_modify_paged(phydev, RTL8211F_PHYCR_PAGE, RTL8211F_PHYCR2, RTL8211F_PHYCR2_PHY_EEE_ENABLE, 0); From 7aa2085ca72b140f0895b25c766da924656827aa Mon Sep 17 00:00:00 2001 From: Dmitry Skorodumov Date: Tue, 2 Dec 2025 13:39:03 +0300 Subject: [PATCH 1067/2333] ipvlan: Ignore PACKET_LOOPBACK in handle_mode_l2() [ Upstream commit 0c57ff008a11f24f7f05fa760222692a00465fec ] Packets with pkt_type == PACKET_LOOPBACK are captured by handle_frame() function, but they don't have L2 header. We should not process them in handle_mode_l2(). This doesn't affect old L2 functionality, since handling was anyway incorrect. Handle them the same way as in br_handle_frame(): just pass the skb. To observe invalid behaviour, just start "ping -b" on bcast address of port-interface. Fixes: 2ad7bf363841 ("ipvlan: Initial check-in of the IPVLAN driver.") Signed-off-by: Dmitry Skorodumov Link: https://patch.msgid.link/20251202103906.4087675-1-skorodumov.dmitry@huawei.com Signed-off-by: Paolo Abeni Signed-off-by: Sasha Levin --- drivers/net/ipvlan/ipvlan_core.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/ipvlan/ipvlan_core.c b/drivers/net/ipvlan/ipvlan_core.c index d7e3ddbcab6f4..baf2ef3bcd54b 100644 --- a/drivers/net/ipvlan/ipvlan_core.c +++ b/drivers/net/ipvlan/ipvlan_core.c @@ -737,6 +737,9 @@ static rx_handler_result_t ipvlan_handle_mode_l2(struct sk_buff **pskb, struct ethhdr *eth = eth_hdr(skb); rx_handler_result_t ret = RX_HANDLER_PASS; + if (unlikely(skb->pkt_type == PACKET_LOOPBACK)) + return RX_HANDLER_PASS; + if (is_multicast_ether_addr(eth->h_dest)) { if (ipvlan_external_frame(skb, port)) { struct sk_buff *nskb = skb_clone(skb, GFP_ATOMIC); From d2495f529d60e8e8c43e6ad524089c38b8be7bc4 Mon Sep 17 00:00:00 2001 From: Gerd Bayer Date: Tue, 2 Dec 2025 12:12:57 +0100 Subject: [PATCH 1068/2333] net/mlx5: Fix double unregister of HCA_PORTS component [ Upstream commit 6a107cfe9c99a079e578a4c5eb70038101a3599f ] Clear hca_devcom_comp in device's private data after unregistering it in LAG teardown. Otherwise a slightly lagging second pass through mlx5_unload_one() might try to unregister it again and trip over use-after-free. On s390 almost all PCI level recovery events trigger two passes through mxl5_unload_one() - one through the poll_health() method and one through mlx5_pci_err_detected() as callback from generic PCI error recovery. While testing PCI error recovery paths with more kernel debug features enabled, this issue reproducibly led to kernel panics with the following call chain: Unable to handle kernel pointer dereference in virtual kernel address space Failing address: 6b6b6b6b6b6b6000 TEID: 6b6b6b6b6b6b6803 ESOP-2 FSI Fault in home space mode while using kernel ASCE. AS:00000000705c4007 R3:0000000000000024 Oops: 0038 ilc:3 [#1]SMP CPU: 14 UID: 0 PID: 156 Comm: kmcheck Kdump: loaded Not tainted 6.18.0-20251130.rc7.git0.16131a59cab1.300.fc43.s390x+debug #1 PREEMPT Krnl PSW : 0404e00180000000 0000020fc86aa1dc (__lock_acquire+0x5c/0x15f0) R:0 T:1 IO:0 EX:0 Key:0 M:1 W:0 P:0 AS:3 CC:2 PM:0 RI:0 EA:3 Krnl GPRS: 0000000000000000 0000020f00000001 6b6b6b6b6b6b6c33 0000000000000000 0000000000000000 0000000000000000 0000000000000001 0000000000000000 0000000000000000 0000020fca28b820 0000000000000000 0000010a1ced8100 0000010a1ced8100 0000020fc9775068 0000018fce14f8b8 0000018fce14f7f8 Krnl Code: 0000020fc86aa1cc: e3b003400004 lg %r11,832 0000020fc86aa1d2: a7840211 brc 8,0000020fc86aa5f4 *0000020fc86aa1d6: c09000df0b25 larl %r9,0000020fca28b820 >0000020fc86aa1dc: d50790002000 clc 0(8,%r9),0(%r2) 0000020fc86aa1e2: a7840209 brc 8,0000020fc86aa5f4 0000020fc86aa1e6: c0e001100401 larl %r14,0000020fca8aa9e8 0000020fc86aa1ec: c01000e25a00 larl %r1,0000020fca2f55ec 0000020fc86aa1f2: a7eb00e8 aghi %r14,232 Call Trace: __lock_acquire+0x5c/0x15f0 lock_acquire.part.0+0xf8/0x270 lock_acquire+0xb0/0x1b0 down_write+0x5a/0x250 mlx5_detach_device+0x42/0x110 [mlx5_core] mlx5_unload_one_devl_locked+0x50/0xc0 [mlx5_core] mlx5_unload_one+0x42/0x60 [mlx5_core] mlx5_pci_err_detected+0x94/0x150 [mlx5_core] zpci_event_attempt_error_recovery+0xcc/0x388 Fixes: 5a977b5833b7 ("net/mlx5: Lag, move devcom registration to LAG layer") Signed-off-by: Gerd Bayer Reviewed-by: Moshe Shemesh Acked-by: Tariq Toukan Link: https://patch.msgid.link/20251202-fix_lag-v1-1-59e8177ffce0@linux.ibm.com Signed-off-by: Paolo Abeni Signed-off-by: Sasha Levin --- drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c index 3db0387bf6dcb..8ec04a5f434dd 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c @@ -1413,6 +1413,7 @@ static int __mlx5_lag_dev_add_mdev(struct mlx5_core_dev *dev) static void mlx5_lag_unregister_hca_devcom_comp(struct mlx5_core_dev *dev) { mlx5_devcom_unregister_component(dev->priv.hca_devcom_comp); + dev->priv.hca_devcom_comp = NULL; } static int mlx5_lag_register_hca_devcom_comp(struct mlx5_core_dev *dev) From fcb9e2e5cf0497df47f8f9191ab99fdae6e65dbe Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Tue, 2 Dec 2025 18:44:11 +0100 Subject: [PATCH 1069/2333] mlxsw: spectrum_router: Fix possible neighbour reference count leak [ Upstream commit b6b638bda240395dff49a87403b2e32493e56d2a ] mlxsw_sp_router_schedule_work() takes a reference on a neighbour, expecting a work item to release it later on. However, we might fail to schedule the work item, in which case the neighbour reference count will be leaked. Fix by taking the reference just before scheduling the work item. Note that mlxsw_sp_router_schedule_work() can receive a NULL neighbour pointer, but neigh_clone() handles that correctly. Spotted during code review, did not actually observe the reference count leak. Fixes: 151b89f6025a ("mlxsw: spectrum_router: Reuse work neighbor initialization in work scheduler") Reviewed-by: Petr Machata Signed-off-by: Ido Schimmel Signed-off-by: Petr Machata Reviewed-by: Simon Horman Link: https://patch.msgid.link/ec2934ae4aca187a8d8c9329a08ce93cca411378.1764695650.git.petrm@nvidia.com Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index a2033837182e8..f4e9ecaeb104f 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -2858,6 +2858,11 @@ static int mlxsw_sp_router_schedule_work(struct net *net, if (!net_work) return NOTIFY_BAD; + /* Take a reference to ensure the neighbour won't be destructed until + * we drop the reference in the work item. + */ + neigh_clone(n); + INIT_WORK(&net_work->work, cb); net_work->mlxsw_sp = router->mlxsw_sp; net_work->n = n; @@ -2881,11 +2886,6 @@ static int mlxsw_sp_router_schedule_neigh_work(struct mlxsw_sp_router *router, struct net *net; net = neigh_parms_net(n->parms); - - /* Take a reference to ensure the neighbour won't be destructed until we - * drop the reference in delayed work. - */ - neigh_clone(n); return mlxsw_sp_router_schedule_work(net, router, n, mlxsw_sp_router_neigh_event_work); } From 675c5aeadf6472672c472dc0f26401e4fcfbf254 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Tue, 2 Dec 2025 18:44:12 +0100 Subject: [PATCH 1070/2333] mlxsw: spectrum_router: Fix neighbour use-after-free [ Upstream commit 8b0e69763ef948fb872a7767df4be665d18f5fd4 ] We sometimes observe use-after-free when dereferencing a neighbour [1]. The problem seems to be that the driver stores a pointer to the neighbour, but without holding a reference on it. A reference is only taken when the neighbour is used by a nexthop. Fix by simplifying the reference counting scheme. Always take a reference when storing a neighbour pointer in a neighbour entry. Avoid taking a referencing when the neighbour is used by a nexthop as the neighbour entry associated with the nexthop already holds a reference. Tested by running the test that uncovered the problem over 300 times. Without this patch the problem was reproduced after a handful of iterations. [1] BUG: KASAN: slab-use-after-free in mlxsw_sp_neigh_entry_update+0x2d4/0x310 Read of size 8 at addr ffff88817f8e3420 by task ip/3929 CPU: 3 UID: 0 PID: 3929 Comm: ip Not tainted 6.18.0-rc4-virtme-g36b21a067510 #3 PREEMPT(full) Hardware name: Nvidia SN5600/VMOD0013, BIOS 5.13 05/31/2023 Call Trace: dump_stack_lvl+0x6f/0xa0 print_address_description.constprop.0+0x6e/0x300 print_report+0xfc/0x1fb kasan_report+0xe4/0x110 mlxsw_sp_neigh_entry_update+0x2d4/0x310 mlxsw_sp_router_rif_gone_sync+0x35f/0x510 mlxsw_sp_rif_destroy+0x1ea/0x730 mlxsw_sp_inetaddr_port_vlan_event+0xa1/0x1b0 __mlxsw_sp_inetaddr_lag_event+0xcc/0x130 __mlxsw_sp_inetaddr_event+0xf5/0x3c0 mlxsw_sp_router_netdevice_event+0x1015/0x1580 notifier_call_chain+0xcc/0x150 call_netdevice_notifiers_info+0x7e/0x100 __netdev_upper_dev_unlink+0x10b/0x210 netdev_upper_dev_unlink+0x79/0xa0 vrf_del_slave+0x18/0x50 do_set_master+0x146/0x7d0 do_setlink.isra.0+0x9a0/0x2880 rtnl_newlink+0x637/0xb20 rtnetlink_rcv_msg+0x6fe/0xb90 netlink_rcv_skb+0x123/0x380 netlink_unicast+0x4a3/0x770 netlink_sendmsg+0x75b/0xc90 __sock_sendmsg+0xbe/0x160 ____sys_sendmsg+0x5b2/0x7d0 ___sys_sendmsg+0xfd/0x180 __sys_sendmsg+0x124/0x1c0 do_syscall_64+0xbb/0xfd0 entry_SYSCALL_64_after_hwframe+0x4b/0x53 [...] Allocated by task 109: kasan_save_stack+0x30/0x50 kasan_save_track+0x14/0x30 __kasan_kmalloc+0x7b/0x90 __kmalloc_noprof+0x2c1/0x790 neigh_alloc+0x6af/0x8f0 ___neigh_create+0x63/0xe90 mlxsw_sp_nexthop_neigh_init+0x430/0x7e0 mlxsw_sp_nexthop_type_init+0x212/0x960 mlxsw_sp_nexthop6_group_info_init.constprop.0+0x81f/0x1280 mlxsw_sp_nexthop6_group_get+0x392/0x6a0 mlxsw_sp_fib6_entry_create+0x46a/0xfd0 mlxsw_sp_router_fib6_replace+0x1ed/0x5f0 mlxsw_sp_router_fib6_event_work+0x10a/0x2a0 process_one_work+0xd57/0x1390 worker_thread+0x4d6/0xd40 kthread+0x355/0x5b0 ret_from_fork+0x1d4/0x270 ret_from_fork_asm+0x11/0x20 Freed by task 154: kasan_save_stack+0x30/0x50 kasan_save_track+0x14/0x30 __kasan_save_free_info+0x3b/0x60 __kasan_slab_free+0x43/0x70 kmem_cache_free_bulk.part.0+0x1eb/0x5e0 kvfree_rcu_bulk+0x1f2/0x260 kfree_rcu_work+0x130/0x1b0 process_one_work+0xd57/0x1390 worker_thread+0x4d6/0xd40 kthread+0x355/0x5b0 ret_from_fork+0x1d4/0x270 ret_from_fork_asm+0x11/0x20 Last potentially related work creation: kasan_save_stack+0x30/0x50 kasan_record_aux_stack+0x8c/0xa0 kvfree_call_rcu+0x93/0x5b0 mlxsw_sp_router_neigh_event_work+0x67d/0x860 process_one_work+0xd57/0x1390 worker_thread+0x4d6/0xd40 kthread+0x355/0x5b0 ret_from_fork+0x1d4/0x270 ret_from_fork_asm+0x11/0x20 Fixes: 6cf3c971dc84 ("mlxsw: spectrum_router: Add private neigh table") Signed-off-by: Ido Schimmel Reviewed-by: Petr Machata Signed-off-by: Petr Machata Reviewed-by: Simon Horman Link: https://patch.msgid.link/92d75e21d95d163a41b5cea67a15cd33f547cba6.1764695650.git.petrm@nvidia.com Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- .../ethernet/mellanox/mlxsw/spectrum_router.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index f4e9ecaeb104f..2d0e89bd2fb9c 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -2265,6 +2265,7 @@ mlxsw_sp_neigh_entry_alloc(struct mlxsw_sp *mlxsw_sp, struct neighbour *n, if (!neigh_entry) return NULL; + neigh_hold(n); neigh_entry->key.n = n; neigh_entry->rif = rif; INIT_LIST_HEAD(&neigh_entry->nexthop_list); @@ -2274,6 +2275,7 @@ mlxsw_sp_neigh_entry_alloc(struct mlxsw_sp *mlxsw_sp, struct neighbour *n, static void mlxsw_sp_neigh_entry_free(struct mlxsw_sp_neigh_entry *neigh_entry) { + neigh_release(neigh_entry->key.n); kfree(neigh_entry); } @@ -4320,6 +4322,8 @@ mlxsw_sp_nexthop_dead_neigh_replace(struct mlxsw_sp *mlxsw_sp, if (err) goto err_neigh_entry_insert; + neigh_release(old_n); + read_lock_bh(&n->lock); nud_state = n->nud_state; dead = n->dead; @@ -4328,14 +4332,10 @@ mlxsw_sp_nexthop_dead_neigh_replace(struct mlxsw_sp *mlxsw_sp, list_for_each_entry(nh, &neigh_entry->nexthop_list, neigh_list_node) { - neigh_release(old_n); - neigh_clone(n); __mlxsw_sp_nexthop_neigh_update(nh, !entry_connected); mlxsw_sp_nexthop_group_refresh(mlxsw_sp, nh->nhgi->nh_grp); } - neigh_release(n); - return 0; err_neigh_entry_insert: @@ -4428,6 +4428,11 @@ static int mlxsw_sp_nexthop_neigh_init(struct mlxsw_sp *mlxsw_sp, } } + /* Release the reference taken by neigh_lookup() / neigh_create() since + * neigh_entry already holds one. + */ + neigh_release(n); + /* If that is the first nexthop connected to that neigh, add to * nexthop_neighs_list */ @@ -4454,11 +4459,9 @@ static void mlxsw_sp_nexthop_neigh_fini(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_nexthop *nh) { struct mlxsw_sp_neigh_entry *neigh_entry = nh->neigh_entry; - struct neighbour *n; if (!neigh_entry) return; - n = neigh_entry->key.n; __mlxsw_sp_nexthop_neigh_update(nh, true); list_del(&nh->neigh_list_node); @@ -4472,8 +4475,6 @@ static void mlxsw_sp_nexthop_neigh_fini(struct mlxsw_sp *mlxsw_sp, if (!neigh_entry->connected && list_empty(&neigh_entry->nexthop_list)) mlxsw_sp_neigh_entry_destroy(mlxsw_sp, neigh_entry); - - neigh_release(n); } static bool mlxsw_sp_ipip_netdev_ul_up(struct net_device *ol_dev) From 4049a6ace209f4ed150429f86ae796d7d6a4c22b Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Tue, 2 Dec 2025 18:44:13 +0100 Subject: [PATCH 1071/2333] mlxsw: spectrum_mr: Fix use-after-free when updating multicast route stats [ Upstream commit 8ac1dacec458f55f871f7153242ed6ab60373b90 ] Cited commit added a dedicated mutex (instead of RTNL) to protect the multicast route list, so that it will not change while the driver periodically traverses it in order to update the kernel about multicast route stats that were queried from the device. One instance of list entry deletion (during route replace) was missed and it can result in a use-after-free [1]. Fix by acquiring the mutex before deleting the entry from the list and releasing it afterwards. [1] BUG: KASAN: slab-use-after-free in mlxsw_sp_mr_stats_update+0x4a5/0x540 drivers/net/ethernet/mellanox/mlxsw/spectrum_mr.c:1006 [mlxsw_spectrum] Read of size 8 at addr ffff8881523c2fa8 by task kworker/2:5/22043 CPU: 2 UID: 0 PID: 22043 Comm: kworker/2:5 Not tainted 6.18.0-rc1-custom-g1a3d6d7cd014 #1 PREEMPT(full) Hardware name: Mellanox Technologies Ltd. MSN2010/SA002610, BIOS 5.6.5 08/24/2017 Workqueue: mlxsw_core mlxsw_sp_mr_stats_update [mlxsw_spectrum] Call Trace: dump_stack_lvl+0xba/0x110 print_report+0x174/0x4f5 kasan_report+0xdf/0x110 mlxsw_sp_mr_stats_update+0x4a5/0x540 drivers/net/ethernet/mellanox/mlxsw/spectrum_mr.c:1006 [mlxsw_spectrum] process_one_work+0x9cc/0x18e0 worker_thread+0x5df/0xe40 kthread+0x3b8/0x730 ret_from_fork+0x3e9/0x560 ret_from_fork_asm+0x1a/0x30 Allocated by task 29933: kasan_save_stack+0x30/0x50 kasan_save_track+0x14/0x30 __kasan_kmalloc+0x8f/0xa0 mlxsw_sp_mr_route_add+0xd8/0x4770 [mlxsw_spectrum] mlxsw_sp_router_fibmr_event_work+0x371/0xad0 drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c:7965 [mlxsw_spectrum] process_one_work+0x9cc/0x18e0 worker_thread+0x5df/0xe40 kthread+0x3b8/0x730 ret_from_fork+0x3e9/0x560 ret_from_fork_asm+0x1a/0x30 Freed by task 29933: kasan_save_stack+0x30/0x50 kasan_save_track+0x14/0x30 __kasan_save_free_info+0x3b/0x70 __kasan_slab_free+0x43/0x70 kfree+0x14e/0x700 mlxsw_sp_mr_route_add+0x2dea/0x4770 drivers/net/ethernet/mellanox/mlxsw/spectrum_mr.c:444 [mlxsw_spectrum] mlxsw_sp_router_fibmr_event_work+0x371/0xad0 drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c:7965 [mlxsw_spectrum] process_one_work+0x9cc/0x18e0 worker_thread+0x5df/0xe40 kthread+0x3b8/0x730 ret_from_fork+0x3e9/0x560 ret_from_fork_asm+0x1a/0x30 Fixes: f38656d06725 ("mlxsw: spectrum_mr: Protect multicast route list with a lock") Signed-off-by: Ido Schimmel Reviewed-by: Petr Machata Signed-off-by: Petr Machata Reviewed-by: Simon Horman Link: https://patch.msgid.link/f996feecfd59fde297964bfc85040b6d83ec6089.1764695650.git.petrm@nvidia.com Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- drivers/net/ethernet/mellanox/mlxsw/spectrum_mr.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_mr.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_mr.c index 5afe6b155ef0d..81935f87bfcd7 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_mr.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_mr.c @@ -440,7 +440,9 @@ int mlxsw_sp_mr_route_add(struct mlxsw_sp_mr_table *mr_table, rhashtable_remove_fast(&mr_table->route_ht, &mr_orig_route->ht_node, mlxsw_sp_mr_route_ht_params); + mutex_lock(&mr_table->route_list_lock); list_del(&mr_orig_route->node); + mutex_unlock(&mr_table->route_list_lock); mlxsw_sp_mr_route_destroy(mr_table, mr_orig_route); } From f17e0c1208485b24d61271bc1ddc8f2087e71561 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Tue, 2 Dec 2025 16:30:24 -0800 Subject: [PATCH 1072/2333] bnxt_en: Fix XDP_TX path [ Upstream commit 0373d5c387f24de749cc22e694a14b3a7c7eb515 ] For XDP_TX action in bnxt_rx_xdp(), clearing of the event flags is not correct. __bnxt_poll_work() -> bnxt_rx_pkt() -> bnxt_rx_xdp() may be looping within NAPI and some event flags may be set in earlier iterations. In particular, if BNXT_TX_EVENT is set earlier indicating some XDP_TX packets are ready and pending, it will be cleared if it is XDP_TX action again. Normally, we will set BNXT_TX_EVENT again when we successfully call __bnxt_xmit_xdp(). But if the TX ring has no more room, the flag will not be set. This will cause the TX producer to be ahead but the driver will not hit the TX doorbell. For multi-buf XDP_TX, there is no need to clear the event flags and set BNXT_AGG_EVENT. The BNXT_AGG_EVENT flag should have been set earlier in bnxt_rx_pkt(). The visible symptom of this is that the RX ring associated with the TX XDP ring will eventually become empty and all packets will be dropped. Because this condition will cause the driver to not refill the RX ring seeing that the TX ring has forever pending XDP_TX packets. The fix is to only clear BNXT_RX_EVENT when we have successfully called __bnxt_xmit_xdp(). Fixes: 7f0a168b0441 ("bnxt_en: Add completion ring pointer in TX and RX ring structures") Reported-by: Pavel Dubovitsky Reviewed-by: Andy Gospodarek Reviewed-by: Pavan Chebbi Reviewed-by: Kalesh AP Signed-off-by: Michael Chan Reviewed-by: Jacob Keller Link: https://patch.msgid.link/20251203003024.2246699-1-michael.chan@broadcom.com Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c index 3e77a96e5a3e3..c94a391b1ba5b 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c @@ -268,13 +268,11 @@ bool bnxt_rx_xdp(struct bnxt *bp, struct bnxt_rx_ring_info *rxr, u16 cons, case XDP_TX: rx_buf = &rxr->rx_buf_ring[cons]; mapping = rx_buf->mapping - bp->rx_dma_offset; - *event &= BNXT_TX_CMP_EVENT; if (unlikely(xdp_buff_has_frags(xdp))) { struct skb_shared_info *sinfo = xdp_get_shared_info_from_buff(xdp); tx_needed += sinfo->nr_frags; - *event = BNXT_AGG_EVENT; } if (tx_avail < tx_needed) { @@ -287,6 +285,7 @@ bool bnxt_rx_xdp(struct bnxt *bp, struct bnxt_rx_ring_info *rxr, u16 cons, dma_sync_single_for_device(&pdev->dev, mapping + offset, *len, bp->rx_dir); + *event &= ~BNXT_RX_EVENT; *event |= BNXT_TX_EVENT; __bnxt_xmit_xdp(bp, txr, mapping + offset, *len, NEXT_RX(rxr->rx_prod), xdp); From c999153bfb2d1d9b295b7010d920f2a7c6d7595f Mon Sep 17 00:00:00 2001 From: Ilya Maximets Date: Thu, 4 Dec 2025 11:53:32 +0100 Subject: [PATCH 1073/2333] net: openvswitch: fix middle attribute validation in push_nsh() action [ Upstream commit 5ace7ef87f059d68b5f50837ef3e8a1a4870c36e ] The push_nsh() action structure looks like this: OVS_ACTION_ATTR_PUSH_NSH(OVS_KEY_ATTR_NSH(OVS_NSH_KEY_ATTR_BASE,...)) The outermost OVS_ACTION_ATTR_PUSH_NSH attribute is OK'ed by the nla_for_each_nested() inside __ovs_nla_copy_actions(). The innermost OVS_NSH_KEY_ATTR_BASE/MD1/MD2 are OK'ed by the nla_for_each_nested() inside nsh_key_put_from_nlattr(). But nothing checks if the attribute in the middle is OK. We don't even check that this attribute is the OVS_KEY_ATTR_NSH. We just do a double unwrap with a pair of nla_data() calls - first time directly while calling validate_push_nsh() and the second time as part of the nla_for_each_nested() macro, which isn't safe, potentially causing invalid memory access if the size of this attribute is incorrect. The failure may not be noticed during validation due to larger netlink buffer, but cause trouble later during action execution where the buffer is allocated exactly to the size: BUG: KASAN: slab-out-of-bounds in nsh_hdr_from_nlattr+0x1dd/0x6a0 [openvswitch] Read of size 184 at addr ffff88816459a634 by task a.out/22624 CPU: 8 UID: 0 PID: 22624 6.18.0-rc7+ #115 PREEMPT(voluntary) Call Trace: dump_stack_lvl+0x51/0x70 print_address_description.constprop.0+0x2c/0x390 kasan_report+0xdd/0x110 kasan_check_range+0x35/0x1b0 __asan_memcpy+0x20/0x60 nsh_hdr_from_nlattr+0x1dd/0x6a0 [openvswitch] push_nsh+0x82/0x120 [openvswitch] do_execute_actions+0x1405/0x2840 [openvswitch] ovs_execute_actions+0xd5/0x3b0 [openvswitch] ovs_packet_cmd_execute+0x949/0xdb0 [openvswitch] genl_family_rcv_msg_doit+0x1d6/0x2b0 genl_family_rcv_msg+0x336/0x580 genl_rcv_msg+0x9f/0x130 netlink_rcv_skb+0x11f/0x370 genl_rcv+0x24/0x40 netlink_unicast+0x73e/0xaa0 netlink_sendmsg+0x744/0xbf0 __sys_sendto+0x3d6/0x450 do_syscall_64+0x79/0x2c0 entry_SYSCALL_64_after_hwframe+0x76/0x7e Let's add some checks that the attribute is properly sized and it's the only one attribute inside the action. Technically, there is no real reason for OVS_KEY_ATTR_NSH to be there, as we know that we're pushing an NSH header already, it just creates extra nesting, but that's how uAPI works today. So, keeping as it is. Fixes: b2d0f5d5dc53 ("openvswitch: enable NSH support") Reported-by: Junvy Yang Signed-off-by: Ilya Maximets Acked-by: Eelco Chaudron echaudro@redhat.com Reviewed-by: Aaron Conole Link: https://patch.msgid.link/20251204105334.900379-1-i.maximets@ovn.org Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- net/openvswitch/flow_netlink.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/net/openvswitch/flow_netlink.c b/net/openvswitch/flow_netlink.c index 1cb4f97335d87..2d536901309ea 100644 --- a/net/openvswitch/flow_netlink.c +++ b/net/openvswitch/flow_netlink.c @@ -2802,13 +2802,20 @@ static int validate_and_copy_set_tun(const struct nlattr *attr, return err; } -static bool validate_push_nsh(const struct nlattr *attr, bool log) +static bool validate_push_nsh(const struct nlattr *a, bool log) { + struct nlattr *nsh_key = nla_data(a); struct sw_flow_match match; struct sw_flow_key key; + /* There must be one and only one NSH header. */ + if (!nla_ok(nsh_key, nla_len(a)) || + nla_total_size(nla_len(nsh_key)) != nla_len(a) || + nla_type(nsh_key) != OVS_KEY_ATTR_NSH) + return false; + ovs_match_init(&match, &key, true, NULL); - return !nsh_key_put_from_nlattr(attr, &match, false, true, log); + return !nsh_key_put_from_nlattr(nsh_key, &match, false, true, log); } /* Return false if there are any non-masked bits set. @@ -3389,7 +3396,7 @@ static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr, return -EINVAL; } mac_proto = MAC_PROTO_NONE; - if (!validate_push_nsh(nla_data(a), log)) + if (!validate_push_nsh(a, log)) return -EINVAL; break; From 698f389552abc34531c277cd4dde9c846a976f1b Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 4 Dec 2025 11:01:28 +0100 Subject: [PATCH 1074/2333] net: ti: icssg-prueth: add PTP_1588_CLOCK_OPTIONAL dependency [ Upstream commit 9e7477a427449a8a3cd00c188e20a880e3d94638 ] The new icssg-prueth driver needs the same dependency as the other parts that use the ptp-1588: WARNING: unmet direct dependencies detected for TI_ICSS_IEP Depends on [m]: NETDEVICES [=y] && ETHERNET [=y] && NET_VENDOR_TI [=y] && PTP_1588_CLOCK_OPTIONAL [=m] && TI_PRUSS [=y] Selected by [y]: - TI_PRUETH [=y] && NETDEVICES [=y] && ETHERNET [=y] && NET_VENDOR_TI [=y] && PRU_REMOTEPROC [=y] && NET_SWITCHDEV [=y] Add the correct dependency on the two drivers missing it, and remove the pointless 'imply' in the process. Fixes: e654b85a693e ("net: ti: icssg-prueth: Add ICSSG Ethernet driver for AM65x SR1.0 platforms") Fixes: 511f6c1ae093 ("net: ti: icssm-prueth: Adds ICSSM Ethernet driver") Signed-off-by: Arnd Bergmann Reviewed-by: Vadim Fedorenko Link: https://patch.msgid.link/20251204100138.1034175-1-arnd@kernel.org Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- drivers/net/ethernet/ti/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/ti/Kconfig b/drivers/net/ethernet/ti/Kconfig index a54d71155263c..fe5b2926d8ab0 100644 --- a/drivers/net/ethernet/ti/Kconfig +++ b/drivers/net/ethernet/ti/Kconfig @@ -209,6 +209,7 @@ config TI_ICSSG_PRUETH_SR1 depends on PRU_REMOTEPROC depends on NET_SWITCHDEV depends on ARCH_K3 && OF && TI_K3_UDMA_GLUE_LAYER + depends on PTP_1588_CLOCK_OPTIONAL help Support dual Gigabit Ethernet ports over the ICSSG PRU Subsystem. This subsystem is available on the AM65 SR1.0 platform. @@ -234,7 +235,7 @@ config TI_PRUETH depends on PRU_REMOTEPROC depends on NET_SWITCHDEV select TI_ICSS_IEP - imply PTP_1588_CLOCK + depends on PTP_1588_CLOCK_OPTIONAL help Some TI SoCs has Programmable Realtime Unit (PRU) cores which can support Single or Dual Ethernet ports with the help of firmware code From 1d18e7155f64d283561fd97d474b966de8444812 Mon Sep 17 00:00:00 2001 From: Alexey Simakov Date: Fri, 5 Dec 2025 18:58:16 +0300 Subject: [PATCH 1075/2333] broadcom: b44: prevent uninitialized value usage [ Upstream commit 50b3db3e11864cb4e18ff099cfb38e11e7f87a68 ] On execution path with raised B44_FLAG_EXTERNAL_PHY, b44_readphy() leaves bmcr value uninitialized and it is used later in the code. Add check of this flag at the beginning of the b44_nway_reset() and exit early of the function with restarting autonegotiation if an external PHY is used. Fixes: 753f492093da ("[B44]: port to native ssb support") Reviewed-by: Jonas Gorski Reviewed-by: Andrew Lunn Signed-off-by: Alexey Simakov Reviewed-by: Michael Chan Link: https://patch.msgid.link/20251205155815.4348-1-bigalex934@gmail.com Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- drivers/net/ethernet/broadcom/b44.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/ethernet/broadcom/b44.c b/drivers/net/ethernet/broadcom/b44.c index 0353359c3fe96..073d7d490d4b6 100644 --- a/drivers/net/ethernet/broadcom/b44.c +++ b/drivers/net/ethernet/broadcom/b44.c @@ -1789,6 +1789,9 @@ static int b44_nway_reset(struct net_device *dev) u32 bmcr; int r; + if (bp->flags & B44_FLAG_EXTERNAL_PHY) + return phy_ethtool_nway_reset(dev); + spin_lock_irq(&bp->lock); b44_readphy(bp, MII_BMCR, &bmcr); b44_readphy(bp, MII_BMCR, &bmcr); From 008fd87cd7082ba3bd9db7df275ffdabab647524 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Fri, 5 Dec 2025 09:10:00 -0800 Subject: [PATCH 1076/2333] selftest: af_unix: Support compilers without flex-array-member-not-at-end support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 06f7cae92fe346fa49a8a9b161124b26cc5c3ed1 ] Fix: gcc: error: unrecognized command-line option ‘-Wflex-array-member-not-at-end’ by making the compiler option dependent on its support. Fixes: 1838731f1072c ("selftest: af_unix: Add -Wall and -Wflex-array-member-not-at-end to CFLAGS.") Cc: Kuniyuki Iwashima Signed-off-by: Guenter Roeck Link: https://patch.msgid.link/20251205171010.515236-7-linux@roeck-us.net Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- tools/testing/selftests/net/af_unix/Makefile | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/net/af_unix/Makefile b/tools/testing/selftests/net/af_unix/Makefile index 528d14c598bb5..2889403e35468 100644 --- a/tools/testing/selftests/net/af_unix/Makefile +++ b/tools/testing/selftests/net/af_unix/Makefile @@ -1,4 +1,9 @@ -CFLAGS += $(KHDR_INCLUDES) -Wall -Wflex-array-member-not-at-end +top_srcdir := ../../../../.. +include $(top_srcdir)/scripts/Makefile.compiler + +cc-option = $(call __cc-option, $(CC),,$(1),$(2)) + +CFLAGS += $(KHDR_INCLUDES) -Wall $(call cc-option,-Wflex-array-member-not-at-end) TEST_GEN_PROGS := \ diag_uid \ From aa3f345dbac252f54aeebdb384ef3af78dd77219 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Fri, 5 Dec 2025 09:10:04 -0800 Subject: [PATCH 1077/2333] selftests: net: Fix build warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 59546e874403c1dd0cbc42df06fdf8c113f72022 ] Fix ksft.h: In function ‘ksft_ready’: ksft.h:27:9: warning: ignoring return value of ‘write’ declared with attribute ‘warn_unused_result’ ksft.h: In function ‘ksft_wait’: ksft.h:51:9: warning: ignoring return value of ‘read’ declared with attribute ‘warn_unused_result’ by checking the return value of the affected functions and displaying an error message if an error is seen. Fixes: 2b6d490b82668 ("selftests: drv-net: Factor out ksft C helpers") Cc: Joe Damato Signed-off-by: Guenter Roeck Link: https://patch.msgid.link/20251205171010.515236-11-linux@roeck-us.net Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- tools/testing/selftests/net/lib/ksft.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/net/lib/ksft.h b/tools/testing/selftests/net/lib/ksft.h index 17dc34a612c64..03912902a6d30 100644 --- a/tools/testing/selftests/net/lib/ksft.h +++ b/tools/testing/selftests/net/lib/ksft.h @@ -24,7 +24,8 @@ static inline void ksft_ready(void) fd = STDOUT_FILENO; } - write(fd, msg, sizeof(msg)); + if (write(fd, msg, sizeof(msg)) < 0) + perror("write()"); if (fd != STDOUT_FILENO) close(fd); } @@ -48,7 +49,8 @@ static inline void ksft_wait(void) fd = STDIN_FILENO; } - read(fd, &byte, sizeof(byte)); + if (read(fd, &byte, sizeof(byte)) < 0) + perror("read()"); if (fd != STDIN_FILENO) close(fd); } From 9ed53331e41895cd603c168ba1c0619a14520921 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Fri, 5 Dec 2025 09:10:07 -0800 Subject: [PATCH 1078/2333] selftests: net: tfo: Fix build warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 91dc09a609d9443e6b34bdb355a18d579a95e132 ] Fix tfo.c: In function ‘run_server’: tfo.c:84:9: warning: ignoring return value of ‘read’ declared with attribute ‘warn_unused_result’ by evaluating the return value from read() and displaying an error message if it reports an error. Fixes: c65b5bb2329e3 ("selftests: net: add passive TFO test binary") Cc: David Wei Signed-off-by: Guenter Roeck Link: https://patch.msgid.link/20251205171010.515236-14-linux@roeck-us.net Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- tools/testing/selftests/net/tfo.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/net/tfo.c b/tools/testing/selftests/net/tfo.c index eb3cac5e583c9..8d82140f0f767 100644 --- a/tools/testing/selftests/net/tfo.c +++ b/tools/testing/selftests/net/tfo.c @@ -81,7 +81,8 @@ static void run_server(void) if (getsockopt(connfd, SOL_SOCKET, SO_INCOMING_NAPI_ID, &opt, &len) < 0) error(1, errno, "getsockopt(SO_INCOMING_NAPI_ID)"); - read(connfd, buf, 64); + if (read(connfd, buf, 64) < 0) + perror("read()"); fprintf(outfile, "%d\n", opt); fclose(outfile); From 1b5c3b8826d4550513aa2191885a35f98a9f2f09 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Sat, 6 Dec 2025 17:09:39 -0800 Subject: [PATCH 1079/2333] inet: frags: avoid theoretical race in ip_frag_reinit() [ Upstream commit 8ef522c8a59a048117f7e05eb5213043c02f986f ] In ip_frag_reinit() we want to move the frag timeout timer into the future. If the timer fires in the meantime we inadvertently scheduled it again, and since the timer assumes a ref on frag_queue we need to acquire one to balance things out. This is technically racy, we should have acquired the reference _before_ we touch the timer, it may fire again before we take the ref. Avoid this entire dance by using mod_timer_pending() which only modifies the timer if its pending (and which exists since Linux v2.6.30) Note that this was the only place we ever took a ref on frag_queue since Eric's conversion to RCU. So we could potentially replace the whole refcnt field with an atomic flag and a bit more RCU. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Reviewed-by: Eric Dumazet Link: https://patch.msgid.link/20251207010942.1672972-2-kuba@kernel.org Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- net/ipv4/inet_fragment.c | 4 +++- net/ipv4/ip_fragment.c | 4 +--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/net/ipv4/inet_fragment.c b/net/ipv4/inet_fragment.c index 025895eb6ec59..30f4fa50ee2d7 100644 --- a/net/ipv4/inet_fragment.c +++ b/net/ipv4/inet_fragment.c @@ -327,7 +327,9 @@ static struct inet_frag_queue *inet_frag_alloc(struct fqdir *fqdir, timer_setup(&q->timer, f->frag_expire, 0); spin_lock_init(&q->lock); - /* One reference for the timer, one for the hash table. */ + /* One reference for the timer, one for the hash table. + * We never take any extra references, only decrement this field. + */ refcount_set(&q->refcnt, 2); return q; diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index f7012479713ba..d7bccdc9dc693 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c @@ -242,10 +242,8 @@ static int ip_frag_reinit(struct ipq *qp) { unsigned int sum_truesize = 0; - if (!mod_timer(&qp->q.timer, jiffies + qp->q.fqdir->timeout)) { - refcount_inc(&qp->q.refcnt); + if (!mod_timer_pending(&qp->q.timer, jiffies + qp->q.fqdir->timeout)) return -ETIMEDOUT; - } sum_truesize = inet_frag_rbtree_purge(&qp->q.rb_fragments, SKB_DROP_REASON_FRAG_TOO_FAR); From 58e7108971fa61f280590903223a2ced65a1e942 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Sat, 6 Dec 2025 17:09:40 -0800 Subject: [PATCH 1080/2333] inet: frags: add inet_frag_queue_flush() [ Upstream commit 1231eec6994be29d6bb5c303dfa54731ed9fc0e6 ] Instead of exporting inet_frag_rbtree_purge() which requires that caller takes care of memory accounting, add a new helper. We will need to call it from a few places in the next patch. Reviewed-by: Eric Dumazet Link: https://patch.msgid.link/20251207010942.1672972-3-kuba@kernel.org Signed-off-by: Jakub Kicinski Stable-dep-of: 006a5035b495 ("inet: frags: flush pending skbs in fqdir_pre_exit()") Signed-off-by: Sasha Levin --- include/net/inet_frag.h | 5 ++--- net/ipv4/inet_fragment.c | 15 ++++++++++++--- net/ipv4/ip_fragment.c | 6 +----- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/include/net/inet_frag.h b/include/net/inet_frag.h index 0eccd9c3a883f..3ffaceee7bbc0 100644 --- a/include/net/inet_frag.h +++ b/include/net/inet_frag.h @@ -141,9 +141,8 @@ void inet_frag_kill(struct inet_frag_queue *q, int *refs); void inet_frag_destroy(struct inet_frag_queue *q); struct inet_frag_queue *inet_frag_find(struct fqdir *fqdir, void *key); -/* Free all skbs in the queue; return the sum of their truesizes. */ -unsigned int inet_frag_rbtree_purge(struct rb_root *root, - enum skb_drop_reason reason); +void inet_frag_queue_flush(struct inet_frag_queue *q, + enum skb_drop_reason reason); static inline void inet_frag_putn(struct inet_frag_queue *q, int refs) { diff --git a/net/ipv4/inet_fragment.c b/net/ipv4/inet_fragment.c index 30f4fa50ee2d7..1bf969b5a1cb5 100644 --- a/net/ipv4/inet_fragment.c +++ b/net/ipv4/inet_fragment.c @@ -263,8 +263,8 @@ static void inet_frag_destroy_rcu(struct rcu_head *head) kmem_cache_free(f->frags_cachep, q); } -unsigned int inet_frag_rbtree_purge(struct rb_root *root, - enum skb_drop_reason reason) +static unsigned int +inet_frag_rbtree_purge(struct rb_root *root, enum skb_drop_reason reason) { struct rb_node *p = rb_first(root); unsigned int sum = 0; @@ -284,7 +284,16 @@ unsigned int inet_frag_rbtree_purge(struct rb_root *root, } return sum; } -EXPORT_SYMBOL(inet_frag_rbtree_purge); + +void inet_frag_queue_flush(struct inet_frag_queue *q, + enum skb_drop_reason reason) +{ + unsigned int sum; + + sum = inet_frag_rbtree_purge(&q->rb_fragments, reason); + sub_frag_mem_limit(q->fqdir, sum); +} +EXPORT_SYMBOL(inet_frag_queue_flush); void inet_frag_destroy(struct inet_frag_queue *q) { diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index d7bccdc9dc693..32f1c1a46ba72 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c @@ -240,14 +240,10 @@ static int ip_frag_too_far(struct ipq *qp) static int ip_frag_reinit(struct ipq *qp) { - unsigned int sum_truesize = 0; - if (!mod_timer_pending(&qp->q.timer, jiffies + qp->q.fqdir->timeout)) return -ETIMEDOUT; - sum_truesize = inet_frag_rbtree_purge(&qp->q.rb_fragments, - SKB_DROP_REASON_FRAG_TOO_FAR); - sub_frag_mem_limit(qp->q.fqdir, sum_truesize); + inet_frag_queue_flush(&qp->q, SKB_DROP_REASON_FRAG_TOO_FAR); qp->q.flags = 0; qp->q.len = 0; From c70df25214ac9b32b53e18e6ae3b8f073ffa6903 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Sat, 6 Dec 2025 17:09:41 -0800 Subject: [PATCH 1081/2333] inet: frags: flush pending skbs in fqdir_pre_exit() [ Upstream commit 006a5035b495dec008805df249f92c22c89c3d2e ] We have been seeing occasional deadlocks on pernet_ops_rwsem since September in NIPA. The stuck task was usually modprobe (often loading a driver like ipvlan), trying to take the lock as a Writer. lockdep does not track readers for rwsems so the read wasn't obvious from the reports. On closer inspection the Reader holding the lock was conntrack looping forever in nf_conntrack_cleanup_net_list(). Based on past experience with occasional NIPA crashes I looked thru the tests which run before the crash and noticed that the crash follows ip_defrag.sh. An immediate red flag. Scouring thru (de)fragmentation queues reveals skbs sitting around, holding conntrack references. The problem is that since conntrack depends on nf_defrag_ipv6, nf_defrag_ipv6 will load first. Since nf_defrag_ipv6 loads first its netns exit hooks run _after_ conntrack's netns exit hook. Flush all fragment queue SKBs during fqdir_pre_exit() to release conntrack references before conntrack cleanup runs. Also flush the queues in timer expiry handlers when they discover fqdir->dead is set, in case packet sneaks in while we're running the pre_exit flush. The commit under Fixes is not exactly the culprit, but I think previously the timer firing would eventually unblock the spinning conntrack. Fixes: d5dd88794a13 ("inet: fix various use-after-free in defrags units") Reviewed-by: Eric Dumazet Link: https://patch.msgid.link/20251207010942.1672972-4-kuba@kernel.org Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- include/net/inet_frag.h | 13 +------------ include/net/ipv6_frag.h | 9 ++++++--- net/ipv4/inet_fragment.c | 36 ++++++++++++++++++++++++++++++++++++ net/ipv4/ip_fragment.c | 12 +++++++----- 4 files changed, 50 insertions(+), 20 deletions(-) diff --git a/include/net/inet_frag.h b/include/net/inet_frag.h index 3ffaceee7bbc0..365925c9d2628 100644 --- a/include/net/inet_frag.h +++ b/include/net/inet_frag.h @@ -123,18 +123,7 @@ void inet_frags_fini(struct inet_frags *); int fqdir_init(struct fqdir **fqdirp, struct inet_frags *f, struct net *net); -static inline void fqdir_pre_exit(struct fqdir *fqdir) -{ - /* Prevent creation of new frags. - * Pairs with READ_ONCE() in inet_frag_find(). - */ - WRITE_ONCE(fqdir->high_thresh, 0); - - /* Pairs with READ_ONCE() in inet_frag_kill(), ip_expire() - * and ip6frag_expire_frag_queue(). - */ - WRITE_ONCE(fqdir->dead, true); -} +void fqdir_pre_exit(struct fqdir *fqdir); void fqdir_exit(struct fqdir *fqdir); void inet_frag_kill(struct inet_frag_queue *q, int *refs); diff --git a/include/net/ipv6_frag.h b/include/net/ipv6_frag.h index 38ef66826939e..41d9fc6965f9a 100644 --- a/include/net/ipv6_frag.h +++ b/include/net/ipv6_frag.h @@ -69,9 +69,6 @@ ip6frag_expire_frag_queue(struct net *net, struct frag_queue *fq) int refs = 1; rcu_read_lock(); - /* Paired with the WRITE_ONCE() in fqdir_pre_exit(). */ - if (READ_ONCE(fq->q.fqdir->dead)) - goto out_rcu_unlock; spin_lock(&fq->q.lock); if (fq->q.flags & INET_FRAG_COMPLETE) @@ -80,6 +77,12 @@ ip6frag_expire_frag_queue(struct net *net, struct frag_queue *fq) fq->q.flags |= INET_FRAG_DROP; inet_frag_kill(&fq->q, &refs); + /* Paired with the WRITE_ONCE() in fqdir_pre_exit(). */ + if (READ_ONCE(fq->q.fqdir->dead)) { + inet_frag_queue_flush(&fq->q, 0); + goto out; + } + dev = dev_get_by_index_rcu(net, fq->iif); if (!dev) goto out; diff --git a/net/ipv4/inet_fragment.c b/net/ipv4/inet_fragment.c index 1bf969b5a1cb5..001ee5c4d962e 100644 --- a/net/ipv4/inet_fragment.c +++ b/net/ipv4/inet_fragment.c @@ -218,6 +218,41 @@ static int __init inet_frag_wq_init(void) pure_initcall(inet_frag_wq_init); +void fqdir_pre_exit(struct fqdir *fqdir) +{ + struct inet_frag_queue *fq; + struct rhashtable_iter hti; + + /* Prevent creation of new frags. + * Pairs with READ_ONCE() in inet_frag_find(). + */ + WRITE_ONCE(fqdir->high_thresh, 0); + + /* Pairs with READ_ONCE() in inet_frag_kill(), ip_expire() + * and ip6frag_expire_frag_queue(). + */ + WRITE_ONCE(fqdir->dead, true); + + rhashtable_walk_enter(&fqdir->rhashtable, &hti); + rhashtable_walk_start(&hti); + + while ((fq = rhashtable_walk_next(&hti))) { + if (IS_ERR(fq)) { + if (PTR_ERR(fq) != -EAGAIN) + break; + continue; + } + spin_lock_bh(&fq->lock); + if (!(fq->flags & INET_FRAG_COMPLETE)) + inet_frag_queue_flush(fq, 0); + spin_unlock_bh(&fq->lock); + } + + rhashtable_walk_stop(&hti); + rhashtable_walk_exit(&hti); +} +EXPORT_SYMBOL(fqdir_pre_exit); + void fqdir_exit(struct fqdir *fqdir) { INIT_WORK(&fqdir->destroy_work, fqdir_work_fn); @@ -290,6 +325,7 @@ void inet_frag_queue_flush(struct inet_frag_queue *q, { unsigned int sum; + reason = reason ?: SKB_DROP_REASON_FRAG_REASM_TIMEOUT; sum = inet_frag_rbtree_purge(&q->rb_fragments, reason); sub_frag_mem_limit(q->fqdir, sum); } diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index 32f1c1a46ba72..56b0f738d2f27 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c @@ -134,11 +134,6 @@ static void ip_expire(struct timer_list *t) net = qp->q.fqdir->net; rcu_read_lock(); - - /* Paired with WRITE_ONCE() in fqdir_pre_exit(). */ - if (READ_ONCE(qp->q.fqdir->dead)) - goto out_rcu_unlock; - spin_lock(&qp->q.lock); if (qp->q.flags & INET_FRAG_COMPLETE) @@ -146,6 +141,13 @@ static void ip_expire(struct timer_list *t) qp->q.flags |= INET_FRAG_DROP; inet_frag_kill(&qp->q, &refs); + + /* Paired with WRITE_ONCE() in fqdir_pre_exit(). */ + if (READ_ONCE(qp->q.fqdir->dead)) { + inet_frag_queue_flush(&qp->q, 0); + goto out; + } + __IP_INC_STATS(net, IPSTATS_MIB_REASMFAILS); __IP_INC_STATS(net, IPSTATS_MIB_REASMTIMEOUT); From 4bd2b89f4028f250dd1c1625eb3da1979b04a5e8 Mon Sep 17 00:00:00 2001 From: Fernando Fernandez Mancera Date: Fri, 5 Dec 2025 12:58:01 +0100 Subject: [PATCH 1082/2333] netfilter: nf_conncount: fix leaked ct in error paths [ Upstream commit 2e2a720766886190a6d35c116794693aabd332b6 ] There are some situations where ct might be leaked as error paths are skipping the refcounted check and return immediately. In order to solve it make sure that the check is always called. Fixes: be102eb6a0e7 ("netfilter: nf_conncount: rework API to use sk_buff directly") Signed-off-by: Fernando Fernandez Mancera Signed-off-by: Florian Westphal Signed-off-by: Sasha Levin --- net/netfilter/nf_conncount.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/net/netfilter/nf_conncount.c b/net/netfilter/nf_conncount.c index b84cfb5616df4..3c1b155f7a0ea 100644 --- a/net/netfilter/nf_conncount.c +++ b/net/netfilter/nf_conncount.c @@ -172,14 +172,14 @@ static int __nf_conncount_add(struct net *net, struct nf_conn *found_ct; unsigned int collect = 0; bool refcounted = false; + int err = 0; if (!get_ct_or_tuple_from_skb(net, skb, l3num, &ct, &tuple, &zone, &refcounted)) return -ENOENT; if (ct && nf_ct_is_confirmed(ct)) { - if (refcounted) - nf_ct_put(ct); - return -EEXIST; + err = -EEXIST; + goto out_put; } if ((u32)jiffies == list->last_gc) @@ -231,12 +231,16 @@ static int __nf_conncount_add(struct net *net, } add_new_node: - if (WARN_ON_ONCE(list->count > INT_MAX)) - return -EOVERFLOW; + if (WARN_ON_ONCE(list->count > INT_MAX)) { + err = -EOVERFLOW; + goto out_put; + } conn = kmem_cache_alloc(conncount_conn_cachep, GFP_ATOMIC); - if (conn == NULL) - return -ENOMEM; + if (conn == NULL) { + err = -ENOMEM; + goto out_put; + } conn->tuple = tuple; conn->zone = *zone; @@ -249,7 +253,7 @@ static int __nf_conncount_add(struct net *net, out_put: if (refcounted) nf_ct_put(ct); - return 0; + return err; } int nf_conncount_add_skb(struct net *net, @@ -446,11 +450,10 @@ insert_tree(struct net *net, rb_link_node_rcu(&rbconn->node, parent, rbnode); rb_insert_color(&rbconn->node, root); - - if (refcounted) - nf_ct_put(ct); } out_unlock: + if (refcounted) + nf_ct_put(ct); spin_unlock_bh(&nf_conncount_locks[hash]); return count; } From 689a627d14788ad772e0fa24c2e57a23dbc7ce90 Mon Sep 17 00:00:00 2001 From: Slavin Liu Date: Fri, 21 Nov 2025 16:52:13 +0800 Subject: [PATCH 1083/2333] ipvs: fix ipv4 null-ptr-deref in route error path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit ad891bb3d079a46a821bf2b8867854645191bab0 ] The IPv4 code path in __ip_vs_get_out_rt() calls dst_link_failure() without ensuring skb->dev is set, leading to a NULL pointer dereference in fib_compute_spec_dst() when ipv4_link_failure() attempts to send ICMP destination unreachable messages. The issue emerged after commit ed0de45a1008 ("ipv4: recompile ip options in ipv4_link_failure") started calling __ip_options_compile() from ipv4_link_failure(). This code path eventually calls fib_compute_spec_dst() which dereferences skb->dev. An attempt was made to fix the NULL skb->dev dereference in commit 0113d9c9d1cc ("ipv4: fix null-deref in ipv4_link_failure"), but it only addressed the immediate dev_net(skb->dev) dereference by using a fallback device. The fix was incomplete because fib_compute_spec_dst() later in the call chain still accesses skb->dev directly, which remains NULL when IPVS calls dst_link_failure(). The crash occurs when: 1. IPVS processes a packet in NAT mode with a misconfigured destination 2. Route lookup fails in __ip_vs_get_out_rt() before establishing a route 3. The error path calls dst_link_failure(skb) with skb->dev == NULL 4. ipv4_link_failure() → ipv4_send_dest_unreach() → __ip_options_compile() → fib_compute_spec_dst() 5. fib_compute_spec_dst() dereferences NULL skb->dev Apply the same fix used for IPv6 in commit 326bf17ea5d4 ("ipvs: fix ipv6 route unreach panic"): set skb->dev from skb_dst(skb)->dev before calling dst_link_failure(). KASAN: null-ptr-deref in range [0x0000000000000328-0x000000000000032f] CPU: 1 PID: 12732 Comm: syz.1.3469 Not tainted 6.6.114 #2 RIP: 0010:__in_dev_get_rcu include/linux/inetdevice.h:233 RIP: 0010:fib_compute_spec_dst+0x17a/0x9f0 net/ipv4/fib_frontend.c:285 Call Trace: spec_dst_fill net/ipv4/ip_options.c:232 spec_dst_fill net/ipv4/ip_options.c:229 __ip_options_compile+0x13a1/0x17d0 net/ipv4/ip_options.c:330 ipv4_send_dest_unreach net/ipv4/route.c:1252 ipv4_link_failure+0x702/0xb80 net/ipv4/route.c:1265 dst_link_failure include/net/dst.h:437 __ip_vs_get_out_rt+0x15fd/0x19e0 net/netfilter/ipvs/ip_vs_xmit.c:412 ip_vs_nat_xmit+0x1d8/0xc80 net/netfilter/ipvs/ip_vs_xmit.c:764 Fixes: ed0de45a1008 ("ipv4: recompile ip options in ipv4_link_failure") Signed-off-by: Slavin Liu Acked-by: Julian Anastasov Signed-off-by: Florian Westphal Signed-off-by: Sasha Levin --- net/netfilter/ipvs/ip_vs_xmit.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/netfilter/ipvs/ip_vs_xmit.c b/net/netfilter/ipvs/ip_vs_xmit.c index 95af252b29397..618fbe1240b54 100644 --- a/net/netfilter/ipvs/ip_vs_xmit.c +++ b/net/netfilter/ipvs/ip_vs_xmit.c @@ -409,6 +409,9 @@ __ip_vs_get_out_rt(struct netns_ipvs *ipvs, int skb_af, struct sk_buff *skb, return -1; err_unreach: + if (!skb->dev) + skb->dev = skb_dst(skb)->dev; + dst_link_failure(skb); return -1; } From 82abf247e013330a43580880e47290c8782ac791 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Tue, 9 Dec 2025 00:03:36 +0100 Subject: [PATCH 1084/2333] selftests: netfilter: prefer xfail in case race wasn't triggered [ Upstream commit b8a81b0ce539e021ac72825238aea1eb657000f0 ] Jakub says: "We try to reserve SKIP for tests skipped because tool is missing in env, something isn't built into the kernel etc." use xfail, we can't force the race condition to appear at will so its expected that the test 'fails' occasionally. Fixes: 78a588363587 ("selftests: netfilter: add conntrack clash resolution test case") Reported-by: Jakub Kicinski Closes: https://lore.kernel.org/netdev/20251206175647.5c32f419@kernel.org/ Signed-off-by: Florian Westphal Signed-off-by: Sasha Levin --- tools/testing/selftests/net/netfilter/conntrack_clash.sh | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/tools/testing/selftests/net/netfilter/conntrack_clash.sh b/tools/testing/selftests/net/netfilter/conntrack_clash.sh index 7fc6c5dbd5516..84b8eb12143ae 100755 --- a/tools/testing/selftests/net/netfilter/conntrack_clash.sh +++ b/tools/testing/selftests/net/netfilter/conntrack_clash.sh @@ -116,7 +116,7 @@ run_one_clash_test() # not a failure: clash resolution logic did not trigger. # With right timing, xmit completed sequentially and # no parallel insertion occurs. - return $ksft_skip + return $ksft_xfail } run_clash_test() @@ -133,12 +133,12 @@ run_clash_test() if [ $rv -eq 0 ];then echo "PASS: clash resolution test for $daddr:$dport on attempt $i" return 0 - elif [ $rv -eq $ksft_skip ]; then + elif [ $rv -eq $ksft_xfail ]; then softerr=1 fi done - [ $softerr -eq 1 ] && echo "SKIP: clash resolution for $daddr:$dport did not trigger" + [ $softerr -eq 1 ] && echo "XFAIL: clash resolution for $daddr:$dport did not trigger" } ip link add veth0 netns "$nsclient1" type veth peer name veth0 netns "$nsrouter" @@ -167,8 +167,7 @@ load_simple_ruleset "$nsclient2" run_clash_test "$nsclient2" "$nsclient2" 127.0.0.1 9001 if [ $clash_resolution_active -eq 0 ];then - [ "$ret" -eq 0 ] && ret=$ksft_skip - echo "SKIP: Clash resolution did not trigger" + [ "$ret" -eq 0 ] && ret=$ksft_xfail fi exit $ret From 21fdcc00656a60af3c7aae2dea8dd96abd35519c Mon Sep 17 00:00:00 2001 From: Junrui Luo Date: Thu, 4 Dec 2025 21:30:47 +0800 Subject: [PATCH 1085/2333] caif: fix integer underflow in cffrml_receive() [ Upstream commit 8a11ff0948b5ad09b71896b7ccc850625f9878d1 ] The cffrml_receive() function extracts a length field from the packet header and, when FCS is disabled, subtracts 2 from this length without validating that len >= 2. If an attacker sends a malicious packet with a length field of 0 or 1 to an interface with FCS disabled, the subtraction causes an integer underflow. This can lead to memory exhaustion and kernel instability, potential information disclosure if padding contains uninitialized kernel memory. Fix this by validating that len >= 2 before performing the subtraction. Reported-by: Yuhao Jiang Reported-by: Junrui Luo Fixes: b482cd2053e3 ("net-caif: add CAIF core protocol stack") Signed-off-by: Junrui Luo Reviewed-by: Simon Horman Link: https://patch.msgid.link/SYBPR01MB7881511122BAFEA8212A1608AFA6A@SYBPR01MB7881.ausprd01.prod.outlook.com Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- net/caif/cffrml.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/net/caif/cffrml.c b/net/caif/cffrml.c index 6651a8dc62e04..d4d63586053ad 100644 --- a/net/caif/cffrml.c +++ b/net/caif/cffrml.c @@ -92,8 +92,15 @@ static int cffrml_receive(struct cflayer *layr, struct cfpkt *pkt) len = le16_to_cpu(tmp); /* Subtract for FCS on length if FCS is not used. */ - if (!this->dofcs) + if (!this->dofcs) { + if (len < 2) { + ++cffrml_rcv_error; + pr_err("Invalid frame length (%d)\n", len); + cfpkt_destroy(pkt); + return -EPROTO; + } len -= 2; + } if (cfpkt_setlen(pkt, len) < 0) { ++cffrml_rcv_error; From 43d9a530c8c094d137159784e7c951c65f11ec6c Mon Sep 17 00:00:00 2001 From: Victor Nogueira Date: Mon, 8 Dec 2025 16:01:24 -0300 Subject: [PATCH 1086/2333] net/sched: ets: Remove drr class from the active list if it changes to strict [ Upstream commit b1e125ae425aba9b45252e933ca8df52a843ec70 ] Whenever a user issues an ets qdisc change command, transforming a drr class into a strict one, the ets code isn't checking whether that class was in the active list and removing it. This means that, if a user changes a strict class (which was in the active list) back to a drr one, that class will be added twice to the active list [1]. Doing so with the following commands: tc qdisc add dev lo root handle 1: ets bands 2 strict 1 tc qdisc add dev lo parent 1:2 handle 20: \ tbf rate 8bit burst 100b latency 1s tc filter add dev lo parent 1: basic classid 1:2 ping -c1 -W0.01 -s 56 127.0.0.1 tc qdisc change dev lo root handle 1: ets bands 2 strict 2 tc qdisc change dev lo root handle 1: ets bands 2 strict 1 ping -c1 -W0.01 -s 56 127.0.0.1 Will trigger the following splat with list debug turned on: [ 59.279014][ T365] ------------[ cut here ]------------ [ 59.279452][ T365] list_add double add: new=ffff88801d60e350, prev=ffff88801d60e350, next=ffff88801d60e2c0. [ 59.280153][ T365] WARNING: CPU: 3 PID: 365 at lib/list_debug.c:35 __list_add_valid_or_report+0x17f/0x220 [ 59.280860][ T365] Modules linked in: [ 59.281165][ T365] CPU: 3 UID: 0 PID: 365 Comm: tc Not tainted 6.18.0-rc7-00105-g7e9f13163c13-dirty #239 PREEMPT(voluntary) [ 59.281977][ T365] Hardware name: Bochs Bochs, BIOS Bochs 01/01/2011 [ 59.282391][ T365] RIP: 0010:__list_add_valid_or_report+0x17f/0x220 [ 59.282842][ T365] Code: 89 c6 e8 d4 b7 0d ff 90 0f 0b 90 90 31 c0 e9 31 ff ff ff 90 48 c7 c7 e0 a0 22 9f 48 89 f2 48 89 c1 4c 89 c6 e8 b2 b7 0d ff 90 <0f> 0b 90 90 31 c0 e9 0f ff ff ff 48 89 f7 48 89 44 24 10 4c 89 44 ... [ 59.288812][ T365] Call Trace: [ 59.289056][ T365] [ 59.289224][ T365] ? srso_alias_return_thunk+0x5/0xfbef5 [ 59.289546][ T365] ets_qdisc_change+0xd2b/0x1e80 [ 59.289891][ T365] ? __lock_acquire+0x7e7/0x1be0 [ 59.290223][ T365] ? __pfx_ets_qdisc_change+0x10/0x10 [ 59.290546][ T365] ? srso_alias_return_thunk+0x5/0xfbef5 [ 59.290898][ T365] ? __mutex_trylock_common+0xda/0x240 [ 59.291228][ T365] ? __pfx___mutex_trylock_common+0x10/0x10 [ 59.291655][ T365] ? srso_alias_return_thunk+0x5/0xfbef5 [ 59.291993][ T365] ? srso_alias_return_thunk+0x5/0xfbef5 [ 59.292313][ T365] ? trace_contention_end+0xc8/0x110 [ 59.292656][ T365] ? srso_alias_return_thunk+0x5/0xfbef5 [ 59.293022][ T365] ? srso_alias_return_thunk+0x5/0xfbef5 [ 59.293351][ T365] tc_modify_qdisc+0x63a/0x1cf0 Fix this by always checking and removing an ets class from the active list when changing it to strict. [1] https://git.kernel.org/pub/scm/linux/kernel/git/netdev/net.git/tree/net/sched/sch_ets.c?id=ce052b9402e461a9aded599f5b47e76bc727f7de#n663 Fixes: cd9b50adc6bb9 ("net/sched: ets: fix crash when flipping from 'strict' to 'quantum'") Acked-by: Jamal Hadi Salim Signed-off-by: Victor Nogueira Reviewed-by: Petr Machata Link: https://patch.msgid.link/20251208190125.1868423-1-victor@mojatatu.com Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- net/sched/sch_ets.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/net/sched/sch_ets.c b/net/sched/sch_ets.c index ae46643e596d3..306e046276d46 100644 --- a/net/sched/sch_ets.c +++ b/net/sched/sch_ets.c @@ -664,6 +664,10 @@ static int ets_qdisc_change(struct Qdisc *sch, struct nlattr *opt, q->classes[i].deficit = quanta[i]; } } + for (i = q->nstrict; i < nstrict; i++) { + if (cl_is_active(&q->classes[i])) + list_del_init(&q->classes[i].alist); + } WRITE_ONCE(q->nstrict, nstrict); memcpy(q->prio2band, priomap, sizeof(priomap)); From c59137e1314dd7a88b4920d5bf8b9bdeb5b74cb8 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 9 Dec 2025 09:56:39 +0300 Subject: [PATCH 1087/2333] nfc: pn533: Fix error code in pn533_acr122_poweron_rdr() [ Upstream commit 885bebac9909994050bbbeed0829c727e42bd1b7 ] Set the error code if "transferred != sizeof(cmd)" instead of returning success. Fixes: dbafc28955fa ("NFC: pn533: don't send USB data off of the stack") Signed-off-by: Dan Carpenter Link: https://patch.msgid.link/aTfIJ9tZPmeUF4W1@stanley.mountain Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- drivers/nfc/pn533/usb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/nfc/pn533/usb.c b/drivers/nfc/pn533/usb.c index ffd7367ce1194..018a80674f06e 100644 --- a/drivers/nfc/pn533/usb.c +++ b/drivers/nfc/pn533/usb.c @@ -406,7 +406,7 @@ static int pn533_acr122_poweron_rdr(struct pn533_usb_phy *phy) if (rc || (transferred != sizeof(cmd))) { nfc_err(&phy->udev->dev, "Reader power on cmd error %d\n", rc); - return rc; + return rc ?: -EINVAL; } rc = usb_submit_urb(phy->in_urb, GFP_KERNEL); From 79ea9102e66b9d8b8400a6ae5861f5ef06b4112e Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Mon, 8 Dec 2025 16:00:34 +0100 Subject: [PATCH 1088/2333] netfilter: nf_nat: remove bogus direction check [ Upstream commit 5ec8ca26fe93103577c904644b0957f069d0051a ] Jakub reports spurious failures of the 'conntrack_reverse_clash.sh' selftest. A bogus test makes nat core resort to port rewrite even though there is no need for this. When the test is made, nf_nat_used_tuple() would already have caused us to return if no other CPU had added a colliding entry. Moreover, nf_nat_used_tuple() would have ignored the colliding entry if their origin tuples had been the same. All that is left to check is if the colliding entry in the hash table is subject to NAT, and, if its not, if our entry matches in the reverse direction, e.g. hash table has addr1:1234 -> addr2:80, and we want to commit addr2:80 -> addr1:1234. Because we already checked that neither the new nor the committed entry is subject to NAT we only have to check origin vs. reply tuple: for non-nat entries, the reply tuple is always the inverted original. Just in case there are more problems extend the error reporting in the selftest while at it and dump conntrack table/stats on error. Reported-by: Jakub Kicinski Closes: https://lore.kernel.org/netdev/20251206175135.4a56591b@kernel.org/ Fixes: d8f84a9bc7c4 ("netfilter: nf_nat: don't try nat source port reallocation for reverse dir clash") Signed-off-by: Florian Westphal Signed-off-by: Sasha Levin --- net/netfilter/nf_nat_core.c | 14 +------------- .../net/netfilter/conntrack_reverse_clash.c | 13 +++++++++---- .../net/netfilter/conntrack_reverse_clash.sh | 2 ++ 3 files changed, 12 insertions(+), 17 deletions(-) diff --git a/net/netfilter/nf_nat_core.c b/net/netfilter/nf_nat_core.c index 78a61dac4ade8..e6b24586d2fed 100644 --- a/net/netfilter/nf_nat_core.c +++ b/net/netfilter/nf_nat_core.c @@ -294,25 +294,13 @@ nf_nat_used_tuple_new(const struct nf_conntrack_tuple *tuple, ct = nf_ct_tuplehash_to_ctrack(thash); - /* NB: IP_CT_DIR_ORIGINAL should be impossible because - * nf_nat_used_tuple() handles origin collisions. - * - * Handle remote chance other CPU confirmed its ct right after. - */ - if (thash->tuple.dst.dir != IP_CT_DIR_REPLY) - goto out; - /* clashing connection subject to NAT? Retry with new tuple. */ if (READ_ONCE(ct->status) & uses_nat) goto out; if (nf_ct_tuple_equal(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple, - &ignored_ct->tuplehash[IP_CT_DIR_REPLY].tuple) && - nf_ct_tuple_equal(&ct->tuplehash[IP_CT_DIR_REPLY].tuple, - &ignored_ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple)) { + &ignored_ct->tuplehash[IP_CT_DIR_REPLY].tuple)) taken = false; - goto out; - } out: nf_ct_put(ct); return taken; diff --git a/tools/testing/selftests/net/netfilter/conntrack_reverse_clash.c b/tools/testing/selftests/net/netfilter/conntrack_reverse_clash.c index 507930cee8cb6..462d628cc3bdb 100644 --- a/tools/testing/selftests/net/netfilter/conntrack_reverse_clash.c +++ b/tools/testing/selftests/net/netfilter/conntrack_reverse_clash.c @@ -33,9 +33,14 @@ static void die(const char *e) exit(111); } -static void die_port(uint16_t got, uint16_t want) +static void die_port(const struct sockaddr_in *sin, uint16_t want) { - fprintf(stderr, "Port number changed, wanted %d got %d\n", want, ntohs(got)); + uint16_t got = ntohs(sin->sin_port); + char str[INET_ADDRSTRLEN]; + + inet_ntop(AF_INET, &sin->sin_addr, str, sizeof(str)); + + fprintf(stderr, "Port number changed, wanted %d got %d from %s\n", want, got, str); exit(1); } @@ -100,7 +105,7 @@ int main(int argc, char *argv[]) die("child recvfrom"); if (peer.sin_port != htons(PORT)) - die_port(peer.sin_port, PORT); + die_port(&peer, PORT); } else { if (sendto(s2, buf, LEN, 0, (struct sockaddr *)&sa1, sizeof(sa1)) != LEN) continue; @@ -109,7 +114,7 @@ int main(int argc, char *argv[]) die("parent recvfrom"); if (peer.sin_port != htons((PORT + 1))) - die_port(peer.sin_port, PORT + 1); + die_port(&peer, PORT + 1); } } diff --git a/tools/testing/selftests/net/netfilter/conntrack_reverse_clash.sh b/tools/testing/selftests/net/netfilter/conntrack_reverse_clash.sh index a24c896347a88..dc7e9d6da0624 100755 --- a/tools/testing/selftests/net/netfilter/conntrack_reverse_clash.sh +++ b/tools/testing/selftests/net/netfilter/conntrack_reverse_clash.sh @@ -45,6 +45,8 @@ if ip netns exec "$ns0" ./conntrack_reverse_clash; then echo "PASS: No SNAT performed for null bindings" else echo "ERROR: SNAT performed without any matching snat rule" + ip netns exec "$ns0" conntrack -L + ip netns exec "$ns0" conntrack -S exit 1 fi From 95b2dac3aaee87140b260b4f8e33389da102f582 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Wed, 19 Nov 2025 13:42:05 +0100 Subject: [PATCH 1089/2333] netfilter: nf_tables: remove redundant chain validation on register store [ Upstream commit a67fd55f6a09f4119b7232c19e0f348fe31ab0db ] This validation predates the introduction of the state machine that determines when to enter slow path validation for error reporting. Currently, table validation is perform when: - new rule contains expressions that need validation. - new set element with jump/goto verdict. Validation on register store skips most checks with no basechains, still this walks the graph searching for loops and ensuring expressions are called from the right hook. Remove this. Fixes: a654de8fdc18 ("netfilter: nf_tables: fix chain dependency validation") Signed-off-by: Pablo Neira Ayuso Signed-off-by: Florian Westphal Signed-off-by: Sasha Levin --- net/netfilter/nf_tables_api.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index eed434e0a9702..1a204f6371ad1 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c @@ -11678,21 +11678,10 @@ static int nft_validate_register_store(const struct nft_ctx *ctx, enum nft_data_types type, unsigned int len) { - int err; - switch (reg) { case NFT_REG_VERDICT: if (type != NFT_DATA_VERDICT) return -EINVAL; - - if (data != NULL && - (data->verdict.code == NFT_GOTO || - data->verdict.code == NFT_JUMP)) { - err = nft_chain_validate(ctx, data->verdict.chain); - if (err < 0) - return err; - } - break; default: if (type != NFT_DATA_VALUE) From 365417a77d385b481958d3ff0143c47ebb0bfffe Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Thu, 11 Dec 2025 13:16:49 +0100 Subject: [PATCH 1090/2333] selftests: netfilter: packetdrill: avoid failure on HZ=100 kernel [ Upstream commit fec7b0795548b43e2c3c46e3143c34ef6070341c ] packetdrill --ip_version=ipv4 --mtu=1500 --tolerance_usecs=1000000 --non_fatal packet conntrack_syn_challenge_ack.pkt conntrack v1.4.8 (conntrack-tools): 1 flow entries have been shown. conntrack_syn_challenge_ack.pkt:32: error executing `conntrack -f $NFCT_IP_VERSION \ -L -p tcp --dport 8080 | grep UNREPLIED | grep -q SYN_SENT` command: non-zero status 1 Affected kernel had CONFIG_HZ=100; reset packet was still sitting in backlog. Reported-by: Yi Chen Fixes: a8a388c2aae4 ("selftests: netfilter: add packetdrill based conntrack tests") Signed-off-by: Florian Westphal Signed-off-by: Sasha Levin --- .../net/netfilter/packetdrill/conntrack_syn_challenge_ack.pkt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/net/netfilter/packetdrill/conntrack_syn_challenge_ack.pkt b/tools/testing/selftests/net/netfilter/packetdrill/conntrack_syn_challenge_ack.pkt index 3442cd29bc932..cdb3910af95b4 100644 --- a/tools/testing/selftests/net/netfilter/packetdrill/conntrack_syn_challenge_ack.pkt +++ b/tools/testing/selftests/net/netfilter/packetdrill/conntrack_syn_challenge_ack.pkt @@ -26,7 +26,7 @@ +0.01 > R 643160523:643160523(0) win 0 -+0.01 `conntrack -f $NFCT_IP_VERSION -L -p tcp --dport 8080 2>/dev/null | grep UNREPLIED | grep -q SYN_SENT` ++0.1 `conntrack -f $NFCT_IP_VERSION -L -p tcp --dport 8080 2>/dev/null | grep UNREPLIED | grep -q SYN_SENT` // Must go through. +0.01 > S 0:0(0) win 65535 From 9bec0d7064873639818a622992bdfe652738310f Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Fri, 5 Dec 2025 14:56:12 -0400 Subject: [PATCH 1091/2333] iommufd/selftest: Make it clearer to gcc that the access is not out of bounds [ Upstream commit 5b244b077c0b0e76573fbb9542cf038e42368901 ] GCC gets a bit confused and reports: In function '_test_cmd_get_hw_info', inlined from 'iommufd_ioas_get_hw_info' at iommufd.c:779:3, inlined from 'wrapper_iommufd_ioas_get_hw_info' at iommufd.c:752:1: >> iommufd_utils.h:804:37: warning: array subscript 'struct iommu_test_hw_info[0]' is partly outside array bounds of 'struct iommu_test_hw_info_buffer_smaller[1]' [-Warray-bounds=] 804 | assert(!info->flags); | ~~~~^~~~~~~ iommufd.c: In function 'wrapper_iommufd_ioas_get_hw_info': iommufd.c:761:11: note: object 'buffer_smaller' of size 4 761 | } buffer_smaller; | ^~~~~~~~~~~~~~ While it is true that "struct iommu_test_hw_info[0]" is partly out of bounds of the input pointer, it is not true that info->flags is out of bounds. Unclear why it warns on this. Reuse an existing properly sized stack buffer and pass a truncated length instead to test the same thing. Fixes: af4fde93c319 ("iommufd/selftest: Add coverage for IOMMU_GET_HW_INFO ioctl") Link: https://patch.msgid.link/r/0-v1-63a2cffb09da+4486-iommufd_gcc_bounds_jgg@nvidia.com Reviewed-by: Kevin Tian Reviewed-by: Nicolin Chen Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202512032344.kaAcKFIM-lkp@intel.com/ Signed-off-by: Jason Gunthorpe Signed-off-by: Sasha Levin --- tools/testing/selftests/iommu/iommufd.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/tools/testing/selftests/iommu/iommufd.c b/tools/testing/selftests/iommu/iommufd.c index bb4d33dde3c89..1f52140d9d9ee 100644 --- a/tools/testing/selftests/iommu/iommufd.c +++ b/tools/testing/selftests/iommu/iommufd.c @@ -758,9 +758,6 @@ TEST_F(iommufd_ioas, get_hw_info) struct iommu_test_hw_info info; uint64_t trailing_bytes; } buffer_larger; - struct iommu_test_hw_info_buffer_smaller { - __u32 flags; - } buffer_smaller; if (self->device_id) { uint8_t max_pasid = 0; @@ -792,8 +789,9 @@ TEST_F(iommufd_ioas, get_hw_info) * the fields within the size range still gets updated. */ test_cmd_get_hw_info(self->device_id, - IOMMU_HW_INFO_TYPE_DEFAULT, - &buffer_smaller, sizeof(buffer_smaller)); + IOMMU_HW_INFO_TYPE_DEFAULT, &buffer_exact, + offsetofend(struct iommu_test_hw_info, + flags)); test_cmd_get_hw_info_pasid(self->device_id, &max_pasid); ASSERT_EQ(0, max_pasid); if (variant->pasid_capable) { From b166b8e0a381429fefd9180e67fbc834b3cee82f Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Tue, 16 Dec 2025 11:53:40 -0400 Subject: [PATCH 1092/2333] iommufd/selftest: Check for overflow in IOMMU_TEST_OP_ADD_RESERVED [ Upstream commit e6a973af11135439de32ece3b9cbe3bfc043bea8 ] syzkaller found it could overflow math in the test infrastructure and cause a WARN_ON by corrupting the reserved interval tree. This only effects test kernels with CONFIG_IOMMUFD_TEST. Validate the user input length in the test ioctl. Fixes: f4b20bb34c83 ("iommufd: Add kernel support for testing iommufd") Link: https://patch.msgid.link/r/0-v1-cd99f6049ba5+51-iommufd_syz_add_resv_jgg@nvidia.com Reviewed-by: Samiullah Khawaja Reviewed-by: Kevin Tian Tested-by: Yi Liu Reported-by: syzbot+57fdb0cf6a0c5d1f15a2@syzkaller.appspotmail.com Closes: https://lore.kernel.org/all/69368129.a70a0220.38f243.008f.GAE@google.com Signed-off-by: Jason Gunthorpe Signed-off-by: Sasha Levin --- drivers/iommu/iommufd/selftest.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/iommu/iommufd/selftest.c b/drivers/iommu/iommufd/selftest.c index de178827a078a..dc0947aaac625 100644 --- a/drivers/iommu/iommufd/selftest.c +++ b/drivers/iommu/iommufd/selftest.c @@ -1257,14 +1257,20 @@ static int iommufd_test_add_reserved(struct iommufd_ucmd *ucmd, unsigned int mockpt_id, unsigned long start, size_t length) { + unsigned long last; struct iommufd_ioas *ioas; int rc; + if (!length) + return -EINVAL; + if (check_add_overflow(start, length - 1, &last)) + return -EOVERFLOW; + ioas = iommufd_get_ioas(ucmd->ictx, mockpt_id); if (IS_ERR(ioas)) return PTR_ERR(ioas); down_write(&ioas->iopt.iova_rwsem); - rc = iopt_reserve_iova(&ioas->iopt, start, start + length - 1, NULL); + rc = iopt_reserve_iova(&ioas->iopt, start, last, NULL); up_write(&ioas->iopt.iova_rwsem); iommufd_put_object(ucmd->ictx, &ioas->obj); return rc; From 730a125ec4678ddeca965fb8a78767b51518769e Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Tue, 25 Nov 2025 22:43:12 +0900 Subject: [PATCH 1093/2333] can: j1939: make j1939_sk_bind() fail if device is no longer registered [ Upstream commit 46cea215dc9444ec32a76b1b6a9cb809e17b64d5 ] There is a theoretical race window in j1939_sk_netdev_event_unregister() where two j1939_sk_bind() calls jump in between read_unlock_bh() and lock_sock(). The assumption jsk->priv == priv can fail if the first j1939_sk_bind() call once made jsk->priv == NULL due to failed j1939_local_ecu_get() call and the second j1939_sk_bind() call again made jsk->priv != NULL due to successful j1939_local_ecu_get() call. Since the socket lock is held by both j1939_sk_netdev_event_unregister() and j1939_sk_bind(), checking ndev->reg_state with the socket lock held can reliably make the second j1939_sk_bind() call fail (and close this race window). Fixes: 7fcbe5b2c6a4 ("can: j1939: implement NETDEV_UNREGISTER notification handler") Signed-off-by: Tetsuo Handa Acked-by: Oleksij Rempel Link: https://patch.msgid.link/5732921e-247e-4957-a364-da74bd7031d7@I-love.SAKURA.ne.jp Signed-off-by: Marc Kleine-Budde Signed-off-by: Sasha Levin --- net/can/j1939/socket.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/net/can/j1939/socket.c b/net/can/j1939/socket.c index 88e7160d42489..e3ba2e9fc0e9b 100644 --- a/net/can/j1939/socket.c +++ b/net/can/j1939/socket.c @@ -482,6 +482,12 @@ static int j1939_sk_bind(struct socket *sock, struct sockaddr *uaddr, int len) goto out_release_sock; } + if (ndev->reg_state != NETREG_REGISTERED) { + dev_put(ndev); + ret = -ENODEV; + goto out_release_sock; + } + can_ml = can_get_ml_priv(ndev); if (!can_ml) { dev_put(ndev); From 4066b5b546293f44cd6d0e84ece6e3ee7ff27093 Mon Sep 17 00:00:00 2001 From: Gal Pressman Date: Mon, 8 Dec 2025 14:19:01 +0200 Subject: [PATCH 1094/2333] ethtool: Avoid overflowing userspace buffer on stats query [ Upstream commit 7b07be1ff1cb6c49869910518650e8d0abc7d25f ] The ethtool -S command operates across three ioctl calls: ETHTOOL_GSSET_INFO for the size, ETHTOOL_GSTRINGS for the names, and ETHTOOL_GSTATS for the values. If the number of stats changes between these calls (e.g., due to device reconfiguration), userspace's buffer allocation will be incorrect, potentially leading to buffer overflow. Drivers are generally expected to maintain stable stat counts, but some drivers (e.g., mlx5, bnx2x, bna, ksz884x) use dynamic counters, making this scenario possible. Some drivers try to handle this internally: - bnad_get_ethtool_stats() returns early in case stats.n_stats is not equal to the driver's stats count. - micrel/ksz884x also makes sure not to write anything beyond stats.n_stats and overflow the buffer. However, both use stats.n_stats which is already assigned with the value returned from get_sset_count(), hence won't solve the issue described here. Change ethtool_get_strings(), ethtool_get_stats(), ethtool_get_phy_stats() to not return anything in case of a mismatch between userspace's size and get_sset_size(), to prevent buffer overflow. The returned n_stats value will be equal to zero, to reflect that nothing has been returned. This could result in one of two cases when using upstream ethtool, depending on when the size change is detected: 1. When detected in ethtool_get_strings(): # ethtool -S eth2 no stats available 2. When detected in get stats, all stats will be reported as zero. Both cases are presumably transient, and a subsequent ethtool call should succeed. Other than the overflow avoidance, these two cases are very evident (no output/cleared stats), which is arguably better than presenting incorrect/shifted stats. I also considered returning an error instead of a "silent" response, but that seems more destructive towards userspace apps. Notes: - This patch does not claim to fix the inherent race, it only makes sure that we do not overflow the userspace buffer, and makes for a more predictable behavior. - RTNL lock is held during each ioctl, the race window exists between the separate ioctl calls when the lock is released. - Userspace ethtool always fills stats.n_stats, but it is likely that these stats ioctls are implemented in other userspace applications which might not fill it. The added code checks that it's not zero, to prevent any regressions. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Reviewed-by: Dragos Tatulea Reviewed-by: Tariq Toukan Signed-off-by: Gal Pressman Link: https://patch.msgid.link/20251208121901.3203692-1-gal@nvidia.com Signed-off-by: Paolo Abeni Signed-off-by: Sasha Levin --- net/ethtool/ioctl.c | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/net/ethtool/ioctl.c b/net/ethtool/ioctl.c index fa83ddade4f81..9431e305b2333 100644 --- a/net/ethtool/ioctl.c +++ b/net/ethtool/ioctl.c @@ -2383,7 +2383,10 @@ static int ethtool_get_strings(struct net_device *dev, void __user *useraddr) return -ENOMEM; WARN_ON_ONCE(!ret); - gstrings.len = ret; + if (gstrings.len && gstrings.len != ret) + gstrings.len = 0; + else + gstrings.len = ret; if (gstrings.len) { data = vzalloc(array_size(gstrings.len, ETH_GSTRING_LEN)); @@ -2509,10 +2512,13 @@ static int ethtool_get_stats(struct net_device *dev, void __user *useraddr) if (copy_from_user(&stats, useraddr, sizeof(stats))) return -EFAULT; - stats.n_stats = n_stats; + if (stats.n_stats && stats.n_stats != n_stats) + stats.n_stats = 0; + else + stats.n_stats = n_stats; - if (n_stats) { - data = vzalloc(array_size(n_stats, sizeof(u64))); + if (stats.n_stats) { + data = vzalloc(array_size(stats.n_stats, sizeof(u64))); if (!data) return -ENOMEM; ops->get_ethtool_stats(dev, &stats, data); @@ -2524,7 +2530,9 @@ static int ethtool_get_stats(struct net_device *dev, void __user *useraddr) if (copy_to_user(useraddr, &stats, sizeof(stats))) goto out; useraddr += sizeof(stats); - if (n_stats && copy_to_user(useraddr, data, array_size(n_stats, sizeof(u64)))) + if (stats.n_stats && + copy_to_user(useraddr, data, + array_size(stats.n_stats, sizeof(u64)))) goto out; ret = 0; @@ -2560,6 +2568,10 @@ static int ethtool_get_phy_stats_phydev(struct phy_device *phydev, return -EOPNOTSUPP; n_stats = phy_ops->get_sset_count(phydev); + if (stats->n_stats && stats->n_stats != n_stats) { + stats->n_stats = 0; + return 0; + } ret = ethtool_vzalloc_stats_array(n_stats, data); if (ret) @@ -2580,6 +2592,10 @@ static int ethtool_get_phy_stats_ethtool(struct net_device *dev, return -EOPNOTSUPP; n_stats = ops->get_sset_count(dev, ETH_SS_PHY_STATS); + if (stats->n_stats && stats->n_stats != n_stats) { + stats->n_stats = 0; + return 0; + } ret = ethtool_vzalloc_stats_array(n_stats, data); if (ret) @@ -2616,7 +2632,9 @@ static int ethtool_get_phy_stats(struct net_device *dev, void __user *useraddr) } useraddr += sizeof(stats); - if (copy_to_user(useraddr, data, array_size(stats.n_stats, sizeof(u64)))) + if (stats.n_stats && + copy_to_user(useraddr, data, + array_size(stats.n_stats, sizeof(u64)))) ret = -EFAULT; out: From 5af49c5c3bdb6bc0bf4c58b2177ef7cee7f2c5e7 Mon Sep 17 00:00:00 2001 From: Moshe Shemesh Date: Tue, 9 Dec 2025 14:56:09 +0200 Subject: [PATCH 1095/2333] net/mlx5: fw reset, clear reset requested on drain_fw_reset [ Upstream commit 89a898d63f6f588acf5c104c65c94a38b68c69a6 ] drain_fw_reset() waits for ongoing firmware reset events and blocks new event handling, but does not clear the reset requested flag, and may keep sync reset polling. To fix it, call mlx5_sync_reset_clear_reset_requested() to clear the flag, stop sync reset polling, and resume health polling, ensuring health issues are still detected after the firmware reset drain. Fixes: 16d42d313350 ("net/mlx5: Drain fw_reset when removing device") Signed-off-by: Moshe Shemesh Reviewed-by: Shay Drori Signed-off-by: Tariq Toukan Link: https://patch.msgid.link/1765284977-1363052-2-git-send-email-tariqt@nvidia.com Signed-off-by: Paolo Abeni Signed-off-by: Sasha Levin --- drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c b/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c index 89e399606877b..33df0418e5754 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c @@ -843,7 +843,8 @@ void mlx5_drain_fw_reset(struct mlx5_core_dev *dev) cancel_work_sync(&fw_reset->reset_reload_work); cancel_work_sync(&fw_reset->reset_now_work); cancel_work_sync(&fw_reset->reset_abort_work); - cancel_delayed_work(&fw_reset->reset_timeout_work); + if (test_bit(MLX5_FW_RESET_FLAGS_RESET_REQUESTED, &fw_reset->reset_flags)) + mlx5_sync_reset_clear_reset_requested(dev, true); } static const struct devlink_param mlx5_fw_reset_devlink_params[] = { From 2d2d97d8a644d3c29cfc3e0783eebea57441cebd Mon Sep 17 00:00:00 2001 From: Moshe Shemesh Date: Tue, 9 Dec 2025 14:56:10 +0200 Subject: [PATCH 1096/2333] net/mlx5: Drain firmware reset in shutdown callback [ Upstream commit 5846a365fc6476b02d6766963cf0985520f0385f ] Invoke drain_fw_reset() in the shutdown callback to ensure all firmware reset handling is completed before shutdown proceeds. Fixes: 16d42d313350 ("net/mlx5: Drain fw_reset when removing device") Signed-off-by: Moshe Shemesh Reviewed-by: Shay Drori Signed-off-by: Tariq Toukan Link: https://patch.msgid.link/1765284977-1363052-3-git-send-email-tariqt@nvidia.com Signed-off-by: Paolo Abeni Signed-off-by: Sasha Levin --- drivers/net/ethernet/mellanox/mlx5/core/main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c index 70c156591b0ba..9e0c9e6266a47 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c @@ -2189,6 +2189,7 @@ static void shutdown(struct pci_dev *pdev) mlx5_core_info(dev, "Shutdown was called\n"); set_bit(MLX5_BREAK_FW_WAIT, &dev->intf_state); + mlx5_drain_fw_reset(dev); mlx5_drain_health_wq(dev); err = mlx5_try_fast_unload(dev); if (err) From 8c35c2448086870509ede43947845be0833251f0 Mon Sep 17 00:00:00 2001 From: Shay Drory Date: Tue, 9 Dec 2025 14:56:11 +0200 Subject: [PATCH 1097/2333] net/mlx5: fw_tracer, Validate format string parameters [ Upstream commit b35966042d20b14e2d83330049f77deec5229749 ] Add validation for format string parameters in the firmware tracer to prevent potential security vulnerabilities and crashes from malformed format strings received from firmware. The firmware tracer receives format strings from the device firmware and uses them to format trace messages. Without proper validation, bad firmware could provide format strings with invalid format specifiers (e.g., %s, %p, %n) that could lead to crashes, or other undefined behavior. Add mlx5_tracer_validate_params() to validate that all format specifiers in trace strings are limited to safe integer/hex formats (%x, %d, %i, %u, %llx, %lx, etc.). Reject strings containing other format types that could be used to access arbitrary memory or cause crashes. Invalid format strings are added to the trace output for visibility with "BAD_FORMAT: " prefix. Fixes: 70dd6fdb8987 ("net/mlx5: FW tracer, parse traces and kernel tracing support") Signed-off-by: Shay Drory Reviewed-by: Moshe Shemesh Reported-by: Breno Leitao Closes: https://lore.kernel.org/netdev/hanz6rzrb2bqbplryjrakvkbmv4y5jlmtthnvi3thg5slqvelp@t3s3erottr6s/ Signed-off-by: Tariq Toukan Link: https://patch.msgid.link/1765284977-1363052-4-git-send-email-tariqt@nvidia.com Signed-off-by: Paolo Abeni Signed-off-by: Sasha Levin --- .../mellanox/mlx5/core/diag/fw_tracer.c | 83 ++++++++++++++++--- .../mellanox/mlx5/core/diag/fw_tracer.h | 1 + 2 files changed, 74 insertions(+), 10 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c b/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c index 080e7eab52c7e..9c86c8c72d049 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c @@ -33,6 +33,7 @@ #include "lib/eq.h" #include "fw_tracer.h" #include "fw_tracer_tracepoint.h" +#include static int mlx5_query_mtrc_caps(struct mlx5_fw_tracer *tracer) { @@ -358,6 +359,43 @@ static const char *VAL_PARM = "%llx"; static const char *REPLACE_64_VAL_PARM = "%x%x"; static const char *PARAM_CHAR = "%"; +static bool mlx5_is_valid_spec(const char *str) +{ + /* Parse format specifiers to find the actual type. + * Structure: %[flags][width][.precision][length]type + * Skip flags, width, precision & length. + */ + while (isdigit(*str) || *str == '#' || *str == '.' || *str == 'l') + str++; + + /* Check if it's a valid integer/hex specifier: + * Valid formats: %x, %d, %i, %u, etc. + */ + if (*str != 'x' && *str != 'X' && *str != 'd' && *str != 'i' && + *str != 'u' && *str != 'c') + return false; + + return true; +} + +static bool mlx5_tracer_validate_params(const char *str) +{ + const char *substr = str; + + if (!str) + return false; + + substr = strstr(substr, PARAM_CHAR); + while (substr) { + if (!mlx5_is_valid_spec(substr + 1)) + return false; + + substr = strstr(substr + 1, PARAM_CHAR); + } + + return true; +} + static int mlx5_tracer_message_hash(u32 message_id) { return jhash_1word(message_id, 0) & (MESSAGE_HASH_SIZE - 1); @@ -419,6 +457,10 @@ static int mlx5_tracer_get_num_of_params(char *str) char *substr, *pstr = str; int num_of_params = 0; + /* Validate that all parameters are valid before processing */ + if (!mlx5_tracer_validate_params(str)) + return -EINVAL; + /* replace %llx with %x%x */ substr = strstr(pstr, VAL_PARM); while (substr) { @@ -570,14 +612,17 @@ void mlx5_tracer_print_trace(struct tracer_string_format *str_frmt, { char tmp[512]; - snprintf(tmp, sizeof(tmp), str_frmt->string, - str_frmt->params[0], - str_frmt->params[1], - str_frmt->params[2], - str_frmt->params[3], - str_frmt->params[4], - str_frmt->params[5], - str_frmt->params[6]); + if (str_frmt->invalid_string) + snprintf(tmp, sizeof(tmp), "BAD_FORMAT: %s", str_frmt->string); + else + snprintf(tmp, sizeof(tmp), str_frmt->string, + str_frmt->params[0], + str_frmt->params[1], + str_frmt->params[2], + str_frmt->params[3], + str_frmt->params[4], + str_frmt->params[5], + str_frmt->params[6]); trace_mlx5_fw(dev->tracer, trace_timestamp, str_frmt->lost, str_frmt->event_id, tmp); @@ -609,6 +654,13 @@ static int mlx5_tracer_handle_raw_string(struct mlx5_fw_tracer *tracer, return 0; } +static void mlx5_tracer_handle_bad_format_string(struct mlx5_fw_tracer *tracer, + struct tracer_string_format *cur_string) +{ + cur_string->invalid_string = true; + list_add_tail(&cur_string->list, &tracer->ready_strings_list); +} + static int mlx5_tracer_handle_string_trace(struct mlx5_fw_tracer *tracer, struct tracer_event *tracer_event) { @@ -619,12 +671,18 @@ static int mlx5_tracer_handle_string_trace(struct mlx5_fw_tracer *tracer, if (!cur_string) return mlx5_tracer_handle_raw_string(tracer, tracer_event); - cur_string->num_of_params = mlx5_tracer_get_num_of_params(cur_string->string); - cur_string->last_param_num = 0; cur_string->event_id = tracer_event->event_id; cur_string->tmsn = tracer_event->string_event.tmsn; cur_string->timestamp = tracer_event->string_event.timestamp; cur_string->lost = tracer_event->lost_event; + cur_string->last_param_num = 0; + cur_string->num_of_params = mlx5_tracer_get_num_of_params(cur_string->string); + if (cur_string->num_of_params < 0) { + pr_debug("%s Invalid format string parameters\n", + __func__); + mlx5_tracer_handle_bad_format_string(tracer, cur_string); + return 0; + } if (cur_string->num_of_params == 0) /* trace with no params */ list_add_tail(&cur_string->list, &tracer->ready_strings_list); } else { @@ -634,6 +692,11 @@ static int mlx5_tracer_handle_string_trace(struct mlx5_fw_tracer *tracer, __func__, tracer_event->string_event.tmsn); return mlx5_tracer_handle_raw_string(tracer, tracer_event); } + if (cur_string->num_of_params < 0) { + pr_debug("%s string parameter of invalid string, dumping\n", + __func__); + return 0; + } cur_string->last_param_num += 1; if (cur_string->last_param_num > TRACER_MAX_PARAMS) { pr_debug("%s Number of params exceeds the max (%d)\n", diff --git a/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.h b/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.h index 5c548bb74f07b..30d0bcba88479 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.h @@ -125,6 +125,7 @@ struct tracer_string_format { struct list_head list; u32 timestamp; bool lost; + bool invalid_string; }; enum mlx5_fw_tracer_ownership_state { From d173741ab4cb7c58c8c9e5cea88b2a0f366e668e Mon Sep 17 00:00:00 2001 From: Shay Drory Date: Tue, 9 Dec 2025 14:56:12 +0200 Subject: [PATCH 1098/2333] net/mlx5: fw_tracer, Handle escaped percent properly [ Upstream commit c0289f67f7d6a0dfba0e92cfe661a5c70c8c6e92 ] The firmware tracer's format string validation and parameter counting did not properly handle escaped percent signs (%%). This caused fw_tracer to count more parameters when trace format strings contained literal percent characters. To fix it, allow %% to pass string validation and skip %% sequences when counting parameters since they represent literal percent signs rather than format specifiers. Fixes: 70dd6fdb8987 ("net/mlx5: FW tracer, parse traces and kernel tracing support") Signed-off-by: Shay Drory Reported-by: Breno Leitao Reviewed-by: Moshe Shemesh Closes: https://lore.kernel.org/netdev/hanz6rzrb2bqbplryjrakvkbmv4y5jlmtthnvi3thg5slqvelp@t3s3erottr6s/ Signed-off-by: Tariq Toukan Link: https://patch.msgid.link/1765284977-1363052-5-git-send-email-tariqt@nvidia.com Signed-off-by: Paolo Abeni Signed-off-by: Sasha Levin --- .../mellanox/mlx5/core/diag/fw_tracer.c | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c b/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c index 9c86c8c72d049..0b82a6a133d6c 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c @@ -368,11 +368,11 @@ static bool mlx5_is_valid_spec(const char *str) while (isdigit(*str) || *str == '#' || *str == '.' || *str == 'l') str++; - /* Check if it's a valid integer/hex specifier: + /* Check if it's a valid integer/hex specifier or %%: * Valid formats: %x, %d, %i, %u, etc. */ if (*str != 'x' && *str != 'X' && *str != 'd' && *str != 'i' && - *str != 'u' && *str != 'c') + *str != 'u' && *str != 'c' && *str != '%') return false; return true; @@ -390,7 +390,11 @@ static bool mlx5_tracer_validate_params(const char *str) if (!mlx5_is_valid_spec(substr + 1)) return false; - substr = strstr(substr + 1, PARAM_CHAR); + if (*(substr + 1) == '%') + substr = strstr(substr + 2, PARAM_CHAR); + else + substr = strstr(substr + 1, PARAM_CHAR); + } return true; @@ -469,11 +473,15 @@ static int mlx5_tracer_get_num_of_params(char *str) substr = strstr(pstr, VAL_PARM); } - /* count all the % characters */ + /* count all the % characters, but skip %% (escaped percent) */ substr = strstr(str, PARAM_CHAR); while (substr) { - num_of_params += 1; - str = substr + 1; + if (*(substr + 1) != '%') { + num_of_params += 1; + str = substr + 1; + } else { + str = substr + 2; + } substr = strstr(str, PARAM_CHAR); } From a935b5993b9ed52e348d013cd00b8486d9be72d0 Mon Sep 17 00:00:00 2001 From: Shay Drory Date: Tue, 9 Dec 2025 14:56:13 +0200 Subject: [PATCH 1099/2333] net/mlx5: Serialize firmware reset with devlink [ Upstream commit 367e501f8b095eca08d2eb0ba4ccea5b5e82c169 ] The firmware reset mechanism can be triggered by asynchronous events, which may race with other devlink operations like devlink reload or devlink dev eswitch set, potentially leading to inconsistent states. This patch addresses the race by using the devl_lock to serialize the firmware reset against other devlink operations. When a reset is requested, the driver attempts to acquire the lock. If successful, it sets a flag to block devlink reload or eswitch changes, ACKs the reset to firmware and then releases the lock. If the lock is already held by another operation, the driver NACKs the firmware reset request, indicating that the reset cannot proceed. Firmware reset does not keep the devl_lock and instead uses an internal firmware reset bit. This is because firmware resets can be triggered by asynchronous events, and processed in different threads. It is illegal and unsafe to acquire a lock in one thread and attempt to release it in another, as lock ownership is intrinsically thread-specific. This change ensures that firmware resets and other devlink operations are mutually exclusive during the critical reset request phase, preventing race conditions. Fixes: 38b9f903f22b ("net/mlx5: Handle sync reset request event") Signed-off-by: Shay Drory Reviewed-by: Mateusz Berezecki Reviewed-by: Moshe Shemesh Signed-off-by: Tariq Toukan Link: https://patch.msgid.link/1765284977-1363052-6-git-send-email-tariqt@nvidia.com Signed-off-by: Paolo Abeni Signed-off-by: Sasha Levin --- .../net/ethernet/mellanox/mlx5/core/devlink.c | 5 +++ .../mellanox/mlx5/core/eswitch_offloads.c | 6 +++ .../ethernet/mellanox/mlx5/core/fw_reset.c | 45 +++++++++++++++++-- .../ethernet/mellanox/mlx5/core/fw_reset.h | 1 + 4 files changed, 53 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/devlink.c b/drivers/net/ethernet/mellanox/mlx5/core/devlink.c index 887adf4807d16..ea77fbd98396a 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/devlink.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/devlink.c @@ -197,6 +197,11 @@ static int mlx5_devlink_reload_down(struct devlink *devlink, bool netns_change, struct pci_dev *pdev = dev->pdev; int ret = 0; + if (mlx5_fw_reset_in_progress(dev)) { + NL_SET_ERR_MSG_MOD(extack, "Can't reload during firmware reset"); + return -EBUSY; + } + if (mlx5_dev_is_lightweight(dev)) { if (action != DEVLINK_RELOAD_ACTION_DRIVER_REINIT) return -EOPNOTSUPP; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c index 44a142a041b2f..784130cdf6c07 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c @@ -52,6 +52,7 @@ #include "devlink.h" #include "lag/lag.h" #include "en/tc/post_meter.h" +#include "fw_reset.h" /* There are two match-all miss flows, one for unicast dst mac and * one for multicast. @@ -3807,6 +3808,11 @@ int mlx5_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode, if (IS_ERR(esw)) return PTR_ERR(esw); + if (mlx5_fw_reset_in_progress(esw->dev)) { + NL_SET_ERR_MSG_MOD(extack, "Can't change eswitch mode during firmware reset"); + return -EBUSY; + } + if (esw_mode_from_devlink(mode, &mlx5_mode)) return -EINVAL; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c b/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c index 33df0418e5754..4544f1968f73f 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c @@ -15,6 +15,7 @@ enum { MLX5_FW_RESET_FLAGS_DROP_NEW_REQUESTS, MLX5_FW_RESET_FLAGS_RELOAD_REQUIRED, MLX5_FW_RESET_FLAGS_UNLOAD_EVENT, + MLX5_FW_RESET_FLAGS_RESET_IN_PROGRESS, }; struct mlx5_fw_reset { @@ -127,6 +128,16 @@ int mlx5_fw_reset_query(struct mlx5_core_dev *dev, u8 *reset_level, u8 *reset_ty return mlx5_reg_mfrl_query(dev, reset_level, reset_type, NULL, NULL); } +bool mlx5_fw_reset_in_progress(struct mlx5_core_dev *dev) +{ + struct mlx5_fw_reset *fw_reset = dev->priv.fw_reset; + + if (!fw_reset) + return false; + + return test_bit(MLX5_FW_RESET_FLAGS_RESET_IN_PROGRESS, &fw_reset->reset_flags); +} + static int mlx5_fw_reset_get_reset_method(struct mlx5_core_dev *dev, u8 *reset_method) { @@ -242,6 +253,8 @@ static void mlx5_fw_reset_complete_reload(struct mlx5_core_dev *dev) BIT(DEVLINK_RELOAD_ACTION_FW_ACTIVATE)); devl_unlock(devlink); } + + clear_bit(MLX5_FW_RESET_FLAGS_RESET_IN_PROGRESS, &fw_reset->reset_flags); } static void mlx5_stop_sync_reset_poll(struct mlx5_core_dev *dev) @@ -461,27 +474,48 @@ static void mlx5_sync_reset_request_event(struct work_struct *work) struct mlx5_fw_reset *fw_reset = container_of(work, struct mlx5_fw_reset, reset_request_work); struct mlx5_core_dev *dev = fw_reset->dev; + bool nack_request = false; + struct devlink *devlink; int err; err = mlx5_fw_reset_get_reset_method(dev, &fw_reset->reset_method); - if (err) + if (err) { + nack_request = true; mlx5_core_warn(dev, "Failed reading MFRL, err %d\n", err); + } else if (!mlx5_is_reset_now_capable(dev, fw_reset->reset_method) || + test_bit(MLX5_FW_RESET_FLAGS_NACK_RESET_REQUEST, + &fw_reset->reset_flags)) { + nack_request = true; + } - if (err || test_bit(MLX5_FW_RESET_FLAGS_NACK_RESET_REQUEST, &fw_reset->reset_flags) || - !mlx5_is_reset_now_capable(dev, fw_reset->reset_method)) { + devlink = priv_to_devlink(dev); + /* For external resets, try to acquire devl_lock. Skip if devlink reset is + * pending (lock already held) + */ + if (nack_request || + (!test_bit(MLX5_FW_RESET_FLAGS_PENDING_COMP, + &fw_reset->reset_flags) && + !devl_trylock(devlink))) { err = mlx5_fw_reset_set_reset_sync_nack(dev); mlx5_core_warn(dev, "PCI Sync FW Update Reset Nack %s", err ? "Failed" : "Sent"); return; } + if (mlx5_sync_reset_set_reset_requested(dev)) - return; + goto unlock; + + set_bit(MLX5_FW_RESET_FLAGS_RESET_IN_PROGRESS, &fw_reset->reset_flags); err = mlx5_fw_reset_set_reset_sync_ack(dev); if (err) mlx5_core_warn(dev, "PCI Sync FW Update Reset Ack Failed. Error code: %d\n", err); else mlx5_core_warn(dev, "PCI Sync FW Update Reset Ack. Device reset is expected.\n"); + +unlock: + if (!test_bit(MLX5_FW_RESET_FLAGS_PENDING_COMP, &fw_reset->reset_flags)) + devl_unlock(devlink); } static int mlx5_pci_link_toggle(struct mlx5_core_dev *dev, u16 dev_id) @@ -721,6 +755,8 @@ static void mlx5_sync_reset_abort_event(struct work_struct *work) if (mlx5_sync_reset_clear_reset_requested(dev, true)) return; + + clear_bit(MLX5_FW_RESET_FLAGS_RESET_IN_PROGRESS, &fw_reset->reset_flags); mlx5_core_warn(dev, "PCI Sync FW Update Reset Aborted.\n"); } @@ -757,6 +793,7 @@ static void mlx5_sync_reset_timeout_work(struct work_struct *work) if (mlx5_sync_reset_clear_reset_requested(dev, true)) return; + clear_bit(MLX5_FW_RESET_FLAGS_RESET_IN_PROGRESS, &fw_reset->reset_flags); mlx5_core_warn(dev, "PCI Sync FW Update Reset Timeout.\n"); } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.h b/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.h index d5b28525c960d..2d96b2adc1cdf 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.h @@ -10,6 +10,7 @@ int mlx5_fw_reset_query(struct mlx5_core_dev *dev, u8 *reset_level, u8 *reset_ty int mlx5_fw_reset_set_reset_sync(struct mlx5_core_dev *dev, u8 reset_type_sel, struct netlink_ext_ack *extack); int mlx5_fw_reset_set_live_patch(struct mlx5_core_dev *dev); +bool mlx5_fw_reset_in_progress(struct mlx5_core_dev *dev); int mlx5_fw_reset_wait_reset_done(struct mlx5_core_dev *dev); void mlx5_sync_reset_unload_flow(struct mlx5_core_dev *dev, bool locked); From 2d2e05d3c2afc485a1f5d808b0b1b6bed4364e4e Mon Sep 17 00:00:00 2001 From: Jianbo Liu Date: Tue, 9 Dec 2025 14:56:14 +0200 Subject: [PATCH 1100/2333] net/mlx5e: Use ip6_dst_lookup instead of ipv6_dst_lookup_flow for MAC init [ Upstream commit e35d7da8dd9e55b37c3e8ab548f6793af0c2ab49 ] Replace ipv6_stub->ipv6_dst_lookup_flow() with ip6_dst_lookup() in mlx5e_ipsec_init_macs() since IPsec transformations are not needed during Security Association setup - only basic routing information is required for nexthop MAC address resolution. This resolves an issue where XfrmOutNoStates error counter would be incremented when xfrm policy is configured before xfrm state, as the IPsec-aware routing function would attempt policy checks during SA initialization. Fixes: 71670f766b8f ("net/mlx5e: Support routed networks during IPsec MACs initialization") Signed-off-by: Jianbo Liu Reviewed-by: Leon Romanovsky Signed-off-by: Tariq Toukan Link: https://patch.msgid.link/1765284977-1363052-7-git-send-email-tariqt@nvidia.com Signed-off-by: Paolo Abeni Signed-off-by: Sasha Levin --- drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c index 35d9530037a65..6c79b9cea2efb 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c @@ -342,9 +342,8 @@ static void mlx5e_ipsec_init_macs(struct mlx5e_ipsec_sa_entry *sa_entry, rt_dst_entry = &rt->dst; break; case AF_INET6: - rt_dst_entry = ipv6_stub->ipv6_dst_lookup_flow( - dev_net(netdev), NULL, &fl6, NULL); - if (IS_ERR(rt_dst_entry)) + if (!IS_ENABLED(CONFIG_IPV6) || + ip6_dst_lookup(dev_net(netdev), NULL, &rt_dst_entry, &fl6)) goto neigh; break; default: From 52f7785dad93275cc4e6948c10e15baed7f8de93 Mon Sep 17 00:00:00 2001 From: Jianbo Liu Date: Tue, 9 Dec 2025 14:56:15 +0200 Subject: [PATCH 1101/2333] net/mlx5e: Trigger neighbor resolution for unresolved destinations [ Upstream commit 9ab89bde13e5251e1d0507e1cc426edcdfe19142 ] When initializing the MAC addresses for an outbound IPsec packet offload rule in mlx5e_ipsec_init_macs, the call to dst_neigh_lookup is used to find the next-hop neighbor (typically the gateway in tunnel mode). This call might create a new neighbor entry if one doesn't already exist. This newly created entry starts in the INCOMPLETE state, as the kernel hasn't yet sent an ARP or NDISC probe to resolve the MAC address. In this case, neigh_ha_snapshot will correctly return an all-zero MAC address. IPsec packet offload requires the actual next-hop MAC address to program the rule correctly. If the neighbor state is INCOMPLETE when the rule is created, the hardware rule is programmed with an all-zero destination MAC address. Packets sent using this rule will be subsequently dropped by the receiving network infrastructure or host. This patch adds a check specifically for the outbound offload path. If neigh_ha_snapshot returns an all-zero MAC address, it proactively calls neigh_event_send(n, NULL). This ensures the kernel immediately sends the initial ARP or NDISC probe if one isn't already pending, accelerating the resolution process. This helps prevent the hardware rule from being programmed with an invalid MAC address and avoids packet drops due to unresolved neighbors. Fixes: 71670f766b8f ("net/mlx5e: Support routed networks during IPsec MACs initialization") Signed-off-by: Jianbo Liu Reviewed-by: Leon Romanovsky Signed-off-by: Tariq Toukan Link: https://patch.msgid.link/1765284977-1363052-8-git-send-email-tariqt@nvidia.com Signed-off-by: Paolo Abeni Signed-off-by: Sasha Levin --- drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c index 6c79b9cea2efb..a8fb4bec369cf 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c @@ -358,6 +358,9 @@ static void mlx5e_ipsec_init_macs(struct mlx5e_ipsec_sa_entry *sa_entry, neigh_ha_snapshot(addr, n, netdev); ether_addr_copy(dst, addr); + if (attrs->dir == XFRM_DEV_OFFLOAD_OUT && + is_zero_ether_addr(addr)) + neigh_event_send(n, NULL); dst_release(rt_dst_entry); neigh_release(n); return; From 4af9c2cd9a841592d30af3f976f874490affdcad Mon Sep 17 00:00:00 2001 From: Cosmin Ratiu Date: Tue, 9 Dec 2025 14:56:17 +0200 Subject: [PATCH 1102/2333] net/mlx5e: Don't include PSP in the hard MTU calculations [ Upstream commit 4198a14c8c6252fd1191afaa742dd515dcaf3487 ] Commit [1] added the 40 bytes required by the PSP header+trailer and the UDP header to MLX5E_ETH_HARD_MTU, which limits the device-wide max software MTU that could be set. This is not okay, because most packets are not PSP packets and it doesn't make sense to always reserve space for headers which won't get added in most cases. As it turns out, for TCP connections, PSP overhead is already taken into account in the TCP MSS calculations via inet_csk(sk)->icsk_ext_hdr_len. This was added in commit [2]. This means that the extra space reserved in the hard MTU for mlx5 ends up unused and wasted. Remove the unnecessary 40 byte reservation from hard MTU. [1] commit e5a1861a298e ("net/mlx5e: Implement PSP Tx data path") [2] commit e97269257fe4 ("net: psp: update the TCP MSS to reflect PSP packet overhead") Fixes: e5a1861a298e ("net/mlx5e: Implement PSP Tx data path") Signed-off-by: Cosmin Ratiu Reviewed-by: Shahar Shitrit Signed-off-by: Tariq Toukan Link: https://patch.msgid.link/1765284977-1363052-10-git-send-email-tariqt@nvidia.com Signed-off-by: Paolo Abeni Signed-off-by: Sasha Levin --- drivers/net/ethernet/mellanox/mlx5/core/en.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h index a163f81f07c13..a6479e4d8d8c6 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h @@ -69,7 +69,7 @@ struct page_pool; #define MLX5E_METADATA_ETHER_TYPE (0x8CE4) #define MLX5E_METADATA_ETHER_LEN 8 -#define MLX5E_ETH_HARD_MTU (ETH_HLEN + PSP_ENCAP_HLEN + PSP_TRL_SIZE + VLAN_HLEN + ETH_FCS_LEN) +#define MLX5E_ETH_HARD_MTU (ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN) #define MLX5E_HW2SW_MTU(params, hwmtu) ((hwmtu) - ((params)->hard_mtu)) #define MLX5E_SW2HW_MTU(params, swmtu) ((swmtu) + ((params)->hard_mtu)) From 3c330f1dee3cd92b57e19b9d21dc8ce5970b09be Mon Sep 17 00:00:00 2001 From: Scott Mayhew Date: Tue, 9 Dec 2025 14:30:15 -0500 Subject: [PATCH 1103/2333] net/handshake: duplicate handshake cancellations leak socket [ Upstream commit 15564bd67e2975002f2a8e9defee33e321d3183f ] When a handshake request is cancelled it is removed from the handshake_net->hn_requests list, but it is still present in the handshake_rhashtbl until it is destroyed. If a second cancellation request arrives for the same handshake request, then remove_pending() will return false... and assuming HANDSHAKE_F_REQ_COMPLETED isn't set in req->hr_flags, we'll continue processing through the out_true label, where we put another reference on the sock and a refcount underflow occurs. This can happen for example if a handshake times out - particularly if the SUNRPC client sends the AUTH_TLS probe to the server but doesn't follow it up with the ClientHello due to a problem with tlshd. When the timeout is hit on the server, the server will send a FIN, which triggers a cancellation request via xs_reset_transport(). When the timeout is hit on the client, another cancellation request happens via xs_tls_handshake_sync(). Add a test_and_set_bit(HANDSHAKE_F_REQ_COMPLETED) in the pending cancel path so duplicate cancels can be detected. Fixes: 3b3009ea8abb ("net/handshake: Create a NETLINK service for handling handshake requests") Suggested-by: Chuck Lever Signed-off-by: Scott Mayhew Reviewed-by: Chuck Lever Link: https://patch.msgid.link/20251209193015.3032058-1-smayhew@redhat.com Signed-off-by: Paolo Abeni Signed-off-by: Sasha Levin --- net/handshake/request.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/net/handshake/request.c b/net/handshake/request.c index 274d2c89b6b20..f78091680bca5 100644 --- a/net/handshake/request.c +++ b/net/handshake/request.c @@ -324,7 +324,11 @@ bool handshake_req_cancel(struct sock *sk) hn = handshake_pernet(net); if (hn && remove_pending(hn, req)) { - /* Request hadn't been accepted */ + /* Request hadn't been accepted - mark cancelled */ + if (test_and_set_bit(HANDSHAKE_F_REQ_COMPLETED, &req->hr_flags)) { + trace_handshake_cancel_busy(net, req, sk); + return false; + } goto out_true; } if (test_and_set_bit(HANDSHAKE_F_REQ_COMPLETED, &req->hr_flags)) { From 918aafade36d2f2f73e638bd5d6f1f488aeb91ef Mon Sep 17 00:00:00 2001 From: Wei Fang Date: Thu, 11 Dec 2025 10:09:19 +0800 Subject: [PATCH 1104/2333] net: enetc: do not transmit redirected XDP frames when the link is down [ Upstream commit 2939203ffee818f1e5ebd60bbb85a174d63aab9c ] In the current implementation, the enetc_xdp_xmit() always transmits redirected XDP frames even if the link is down, but the frames cannot be transmitted from TX BD rings when the link is down, so the frames are still kept in the TX BD rings. If the XDP program is uninstalled, users will see the following warning logs. fsl_enetc 0000:00:00.0 eno0: timeout for tx ring #6 clear More worse, the TX BD ring cannot work properly anymore, because the HW PIR and CIR are not equal after the re-initialization of the TX BD ring. At this point, the BDs between CIR and PIR are invalid, which will cause a hardware malfunction. Another reason is that there is internal context in the ring prefetch logic that will retain the state from the first incarnation of the ring and continue prefetching from the stale location when we re-initialize the ring. The internal context is only reset by an FLR. That is to say, for LS1028A ENETC, software cannot set the HW CIR and PIR when initializing the TX BD ring. It does not make sense to transmit redirected XDP frames when the link is down. Add a link status check to prevent transmission in this condition. This fixes part of the issue, but more complex cases remain. For example, the TX BD ring may still contain unsent frames when the link goes down. Those situations require additional patches, which will build on this one. Fixes: 9d2b68cc108d ("net: enetc: add support for XDP_REDIRECT") Signed-off-by: Wei Fang Reviewed-by: Frank Li Reviewed-by: Hariprasad Kelam Reviewed-by: Vladimir Oltean Link: https://patch.msgid.link/20251211020919.121113-1-wei.fang@nxp.com Signed-off-by: Paolo Abeni Signed-off-by: Sasha Levin --- drivers/net/ethernet/freescale/enetc/enetc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/freescale/enetc/enetc.c b/drivers/net/ethernet/freescale/enetc/enetc.c index 0535e92404e3c..f410c245ea918 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc.c +++ b/drivers/net/ethernet/freescale/enetc/enetc.c @@ -1778,7 +1778,8 @@ int enetc_xdp_xmit(struct net_device *ndev, int num_frames, int xdp_tx_bd_cnt, i, k; int xdp_tx_frm_cnt = 0; - if (unlikely(test_bit(ENETC_TX_DOWN, &priv->flags))) + if (unlikely(test_bit(ENETC_TX_DOWN, &priv->flags) || + !netif_carrier_ok(ndev))) return -ENETDOWN; enetc_lock_mdio(); From 62f28d79a6186a602a9d926a2dbb5b12b6867df7 Mon Sep 17 00:00:00 2001 From: Jian Shen Date: Thu, 11 Dec 2025 10:37:35 +0800 Subject: [PATCH 1105/2333] net: hns3: using the num_tqps in the vf driver to apply for resources [ Upstream commit c2a16269742e176fccdd0ef9c016a233491a49ad ] Currently, hdev->htqp is allocated using hdev->num_tqps, and kinfo->tqp is allocated using kinfo->num_tqps. However, kinfo->num_tqps is set to min(new_tqps, hdev->num_tqps); Therefore, kinfo->num_tqps may be smaller than hdev->num_tqps, which causes some hdev->htqp[i] to remain uninitialized in hclgevf_knic_setup(). Thus, this patch allocates hdev->htqp and kinfo->tqp using hdev->num_tqps, ensuring that the lengths of hdev->htqp and kinfo->tqp are consistent and that all elements are properly initialized. Fixes: e2cb1dec9779 ("net: hns3: Add HNS3 VF HCL(Hardware Compatibility Layer) Support") Signed-off-by: Jian Shen Signed-off-by: Jijie Shao Reviewed-by: Simon Horman Link: https://patch.msgid.link/20251211023737.2327018-2-shaojijie@huawei.com Signed-off-by: Paolo Abeni Signed-off-by: Sasha Levin --- drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c index 8fcf220a120d2..70327a73dee32 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c @@ -368,12 +368,12 @@ static int hclgevf_knic_setup(struct hclgevf_dev *hdev) new_tqps = kinfo->rss_size * num_tc; kinfo->num_tqps = min(new_tqps, hdev->num_tqps); - kinfo->tqp = devm_kcalloc(&hdev->pdev->dev, kinfo->num_tqps, + kinfo->tqp = devm_kcalloc(&hdev->pdev->dev, hdev->num_tqps, sizeof(struct hnae3_queue *), GFP_KERNEL); if (!kinfo->tqp) return -ENOMEM; - for (i = 0; i < kinfo->num_tqps; i++) { + for (i = 0; i < hdev->num_tqps; i++) { hdev->htqp[i].q.handle = &hdev->nic; hdev->htqp[i].q.tqp_index = i; kinfo->tqp[i] = &hdev->htqp[i].q; From f02f283ebfaf2b28b28615c29084b8bfb14f93d5 Mon Sep 17 00:00:00 2001 From: Jian Shen Date: Thu, 11 Dec 2025 10:37:36 +0800 Subject: [PATCH 1106/2333] net: hns3: using the num_tqps to check whether tqp_index is out of range when vf get ring info from mbx [ Upstream commit d180c11aa8a6fa735f9ac2c72c61364a9afc2ba7 ] Currently, rss_size = num_tqps / tc_num. If tc_num is 1, then num_tqps equals rss_size. However, if the tc_num is greater than 1, then rss_size will be less than num_tqps, causing the tqp_index check for subsequent TCs using rss_size to always fail. This patch uses the num_tqps to check whether tqp_index is out of range, instead of rss_size. Fixes: 326334aad024 ("net: hns3: add a check for tqp_index in hclge_get_ring_chain_from_mbx()") Signed-off-by: Jian Shen Signed-off-by: Jijie Shao Reviewed-by: Simon Horman Link: https://patch.msgid.link/20251211023737.2327018-3-shaojijie@huawei.com Signed-off-by: Paolo Abeni Signed-off-by: Sasha Levin --- drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c index c7ff12a6c0764..b7d4e06a55d40 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c @@ -193,10 +193,10 @@ static int hclge_get_ring_chain_from_mbx( return -EINVAL; for (i = 0; i < ring_num; i++) { - if (req->msg.param[i].tqp_index >= vport->nic.kinfo.rss_size) { + if (req->msg.param[i].tqp_index >= vport->nic.kinfo.num_tqps) { dev_err(&hdev->pdev->dev, "tqp index(%u) is out of range(0-%u)\n", req->msg.param[i].tqp_index, - vport->nic.kinfo.rss_size - 1U); + vport->nic.kinfo.num_tqps - 1U); return -EINVAL; } } From 91a51d01be5c9f82c12c2921ca5cceaa31b67128 Mon Sep 17 00:00:00 2001 From: Jian Shen Date: Thu, 11 Dec 2025 10:37:37 +0800 Subject: [PATCH 1107/2333] net: hns3: add VLAN id validation before using [ Upstream commit 6ef935e65902bfed53980ad2754b06a284ea8ac1 ] Currently, the VLAN id may be used without validation when receive a VLAN configuration mailbox from VF. The length of vlan_del_fail_bmap is BITS_TO_LONGS(VLAN_N_VID). It may cause out-of-bounds memory access once the VLAN id is bigger than or equal to VLAN_N_VID. Therefore, VLAN id needs to be checked to ensure it is within the range of VLAN_N_VID. Fixes: fe4144d47eef ("net: hns3: sync VLAN filter entries when kill VLAN ID failed") Signed-off-by: Jian Shen Signed-off-by: Jijie Shao Reviewed-by: Simon Horman Link: https://patch.msgid.link/20251211023737.2327018-4-shaojijie@huawei.com Signed-off-by: Paolo Abeni Signed-off-by: Sasha Levin --- drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index 782bb48c9f3d7..1b103d1154da9 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -10562,6 +10562,9 @@ int hclge_set_vlan_filter(struct hnae3_handle *handle, __be16 proto, bool writen_to_tbl = false; int ret = 0; + if (vlan_id >= VLAN_N_VID) + return -EINVAL; + /* When device is resetting or reset failed, firmware is unable to * handle mailbox. Just record the vlan id, and remove it after * reset finished. From c35d4fba2e0b5f1bbcaa2ab7e085267af318ddca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Exp=C3=B3sito?= Date: Tue, 4 Nov 2025 11:22:35 +0100 Subject: [PATCH 1108/2333] drm/tests: hdmi: Handle drm_kunit_helper_enable_crtc_connector() returning EDEADLK MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit fe27e709d91fb645182751b602cb88966b4a1bb6 ] Fedora/CentOS/RHEL CI is reporting intermittent failures while running the KUnit tests present in drm_hdmi_state_helper_test.c [1]. While the specific test causing the failure change between runs, all of them are caused by drm_kunit_helper_enable_crtc_connector() returning -EDEADLK. The error trace always follow this structure: # : ASSERTION FAILED at # drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c: Expected ret == 0, but ret == -35 (0xffffffffffffffdd) As documented, if the drm_kunit_helper_enable_crtc_connector() function returns -EDEADLK (-35), the entire atomic sequence must be restarted. Handle this error code for all function calls. Closes: https://datawarehouse.cki-project.org/issue/4039 [1] Fixes: 6a5c0ad7e08e ("drm/tests: hdmi_state_helpers: Switch to new helper") Reviewed-by: Maxime Ripard Signed-off-by: José Expósito Link: https://patch.msgid.link/20251104102258.10026-1-jose.exposito89@gmail.com Signed-off-by: Sasha Levin --- .../drm/tests/drm_hdmi_state_helper_test.c | 143 ++++++++++++++++++ 1 file changed, 143 insertions(+) diff --git a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c b/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c index 8bd412735000c..70f9aa7021430 100644 --- a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c +++ b/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c @@ -257,10 +257,16 @@ static void drm_test_check_broadcast_rgb_crtc_mode_changed(struct kunit *test) drm_modeset_acquire_init(&ctx, 0); +retry_conn_enable: ret = drm_kunit_helper_enable_crtc_connector(test, drm, crtc, conn, preferred, &ctx); + if (ret == -EDEADLK) { + ret = drm_modeset_backoff(&ctx); + if (!ret) + goto retry_conn_enable; + } KUNIT_ASSERT_EQ(test, ret, 0); state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx); @@ -326,10 +332,16 @@ static void drm_test_check_broadcast_rgb_crtc_mode_not_changed(struct kunit *tes drm_modeset_acquire_init(&ctx, 0); +retry_conn_enable: ret = drm_kunit_helper_enable_crtc_connector(test, drm, crtc, conn, preferred, &ctx); + if (ret == -EDEADLK) { + ret = drm_modeset_backoff(&ctx); + if (!ret) + goto retry_conn_enable; + } KUNIT_ASSERT_EQ(test, ret, 0); state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx); @@ -397,10 +409,16 @@ static void drm_test_check_broadcast_rgb_auto_cea_mode(struct kunit *test) drm_modeset_acquire_init(&ctx, 0); +retry_conn_enable: ret = drm_kunit_helper_enable_crtc_connector(test, drm, crtc, conn, preferred, &ctx); + if (ret == -EDEADLK) { + ret = drm_modeset_backoff(&ctx); + if (!ret) + goto retry_conn_enable; + } KUNIT_ASSERT_EQ(test, ret, 0); state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx); @@ -457,10 +475,17 @@ static void drm_test_check_broadcast_rgb_auto_cea_mode_vic_1(struct kunit *test) KUNIT_ASSERT_NOT_NULL(test, mode); crtc = priv->crtc; + +retry_conn_enable: ret = drm_kunit_helper_enable_crtc_connector(test, drm, crtc, conn, mode, &ctx); + if (ret == -EDEADLK) { + ret = drm_modeset_backoff(&ctx); + if (!ret) + goto retry_conn_enable; + } KUNIT_ASSERT_EQ(test, ret, 0); state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx); @@ -518,10 +543,16 @@ static void drm_test_check_broadcast_rgb_full_cea_mode(struct kunit *test) drm_modeset_acquire_init(&ctx, 0); +retry_conn_enable: ret = drm_kunit_helper_enable_crtc_connector(test, drm, crtc, conn, preferred, &ctx); + if (ret == -EDEADLK) { + ret = drm_modeset_backoff(&ctx); + if (!ret) + goto retry_conn_enable; + } KUNIT_ASSERT_EQ(test, ret, 0); state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx); @@ -580,10 +611,17 @@ static void drm_test_check_broadcast_rgb_full_cea_mode_vic_1(struct kunit *test) KUNIT_ASSERT_NOT_NULL(test, mode); crtc = priv->crtc; + +retry_conn_enable: ret = drm_kunit_helper_enable_crtc_connector(test, drm, crtc, conn, mode, &ctx); + if (ret == -EDEADLK) { + ret = drm_modeset_backoff(&ctx); + if (!ret) + goto retry_conn_enable; + } KUNIT_ASSERT_EQ(test, ret, 0); state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx); @@ -643,10 +681,16 @@ static void drm_test_check_broadcast_rgb_limited_cea_mode(struct kunit *test) drm_modeset_acquire_init(&ctx, 0); +retry_conn_enable: ret = drm_kunit_helper_enable_crtc_connector(test, drm, crtc, conn, preferred, &ctx); + if (ret == -EDEADLK) { + ret = drm_modeset_backoff(&ctx); + if (!ret) + goto retry_conn_enable; + } KUNIT_ASSERT_EQ(test, ret, 0); state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx); @@ -705,10 +749,17 @@ static void drm_test_check_broadcast_rgb_limited_cea_mode_vic_1(struct kunit *te KUNIT_ASSERT_NOT_NULL(test, mode); crtc = priv->crtc; + +retry_conn_enable: ret = drm_kunit_helper_enable_crtc_connector(test, drm, crtc, conn, mode, &ctx); + if (ret == -EDEADLK) { + ret = drm_modeset_backoff(&ctx); + if (!ret) + goto retry_conn_enable; + } KUNIT_ASSERT_EQ(test, ret, 0); state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx); @@ -870,10 +921,16 @@ static void drm_test_check_output_bpc_crtc_mode_changed(struct kunit *test) drm_modeset_acquire_init(&ctx, 0); +retry_conn_enable: ret = drm_kunit_helper_enable_crtc_connector(test, drm, crtc, conn, preferred, &ctx); + if (ret == -EDEADLK) { + ret = drm_modeset_backoff(&ctx); + if (!ret) + goto retry_conn_enable; + } KUNIT_ASSERT_EQ(test, ret, 0); state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx); @@ -946,10 +1003,16 @@ static void drm_test_check_output_bpc_crtc_mode_not_changed(struct kunit *test) drm_modeset_acquire_init(&ctx, 0); +retry_conn_enable: ret = drm_kunit_helper_enable_crtc_connector(test, drm, crtc, conn, preferred, &ctx); + if (ret == -EDEADLK) { + ret = drm_modeset_backoff(&ctx); + if (!ret) + goto retry_conn_enable; + } KUNIT_ASSERT_EQ(test, ret, 0); state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx); @@ -1022,10 +1085,16 @@ static void drm_test_check_output_bpc_dvi(struct kunit *test) drm_modeset_acquire_init(&ctx, 0); +retry_conn_enable: ret = drm_kunit_helper_enable_crtc_connector(test, drm, crtc, conn, preferred, &ctx); + if (ret == -EDEADLK) { + ret = drm_modeset_backoff(&ctx); + if (!ret) + goto retry_conn_enable; + } KUNIT_ASSERT_EQ(test, ret, 0); conn_state = conn->state; @@ -1069,10 +1138,16 @@ static void drm_test_check_tmds_char_rate_rgb_8bpc(struct kunit *test) drm_modeset_acquire_init(&ctx, 0); +retry_conn_enable: ret = drm_kunit_helper_enable_crtc_connector(test, drm, crtc, conn, preferred, &ctx); + if (ret == -EDEADLK) { + ret = drm_modeset_backoff(&ctx); + if (!ret) + goto retry_conn_enable; + } KUNIT_ASSERT_EQ(test, ret, 0); conn_state = conn->state; @@ -1118,10 +1193,16 @@ static void drm_test_check_tmds_char_rate_rgb_10bpc(struct kunit *test) drm_modeset_acquire_init(&ctx, 0); +retry_conn_enable: ret = drm_kunit_helper_enable_crtc_connector(test, drm, crtc, conn, preferred, &ctx); + if (ret == -EDEADLK) { + ret = drm_modeset_backoff(&ctx); + if (!ret) + goto retry_conn_enable; + } KUNIT_ASSERT_EQ(test, ret, 0); conn_state = conn->state; @@ -1167,10 +1248,16 @@ static void drm_test_check_tmds_char_rate_rgb_12bpc(struct kunit *test) drm_modeset_acquire_init(&ctx, 0); +retry_conn_enable: ret = drm_kunit_helper_enable_crtc_connector(test, drm, crtc, conn, preferred, &ctx); + if (ret == -EDEADLK) { + ret = drm_modeset_backoff(&ctx); + if (!ret) + goto retry_conn_enable; + } KUNIT_ASSERT_EQ(test, ret, 0); conn_state = conn->state; @@ -1218,10 +1305,16 @@ static void drm_test_check_hdmi_funcs_reject_rate(struct kunit *test) drm_modeset_acquire_init(&ctx, 0); +retry_conn_enable: ret = drm_kunit_helper_enable_crtc_connector(test, drm, crtc, conn, preferred, &ctx); + if (ret == -EDEADLK) { + ret = drm_modeset_backoff(&ctx); + if (!ret) + goto retry_conn_enable; + } KUNIT_ASSERT_EQ(test, ret, 0); /* You shouldn't be doing that at home. */ @@ -1292,10 +1385,16 @@ static void drm_test_check_max_tmds_rate_bpc_fallback_rgb(struct kunit *test) drm_modeset_acquire_init(&ctx, 0); +retry_conn_enable: ret = drm_kunit_helper_enable_crtc_connector(test, drm, crtc, conn, preferred, &ctx); + if (ret == -EDEADLK) { + ret = drm_modeset_backoff(&ctx); + if (!ret) + goto retry_conn_enable; + } KUNIT_EXPECT_EQ(test, ret, 0); conn_state = conn->state; @@ -1440,10 +1539,16 @@ static void drm_test_check_max_tmds_rate_bpc_fallback_ignore_yuv422(struct kunit drm_modeset_acquire_init(&ctx, 0); +retry_conn_enable: ret = drm_kunit_helper_enable_crtc_connector(test, drm, crtc, conn, preferred, &ctx); + if (ret == -EDEADLK) { + ret = drm_modeset_backoff(&ctx); + if (!ret) + goto retry_conn_enable; + } KUNIT_EXPECT_EQ(test, ret, 0); conn_state = conn->state; @@ -1669,10 +1774,17 @@ static void drm_test_check_output_bpc_format_vic_1(struct kunit *test) drm_modeset_acquire_init(&ctx, 0); crtc = priv->crtc; + +retry_conn_enable: ret = drm_kunit_helper_enable_crtc_connector(test, drm, crtc, conn, mode, &ctx); + if (ret == -EDEADLK) { + ret = drm_modeset_backoff(&ctx); + if (!ret) + goto retry_conn_enable; + } KUNIT_EXPECT_EQ(test, ret, 0); conn_state = conn->state; @@ -1736,10 +1848,16 @@ static void drm_test_check_output_bpc_format_driver_rgb_only(struct kunit *test) drm_modeset_acquire_init(&ctx, 0); +retry_conn_enable: ret = drm_kunit_helper_enable_crtc_connector(test, drm, crtc, conn, preferred, &ctx); + if (ret == -EDEADLK) { + ret = drm_modeset_backoff(&ctx); + if (!ret) + goto retry_conn_enable; + } KUNIT_EXPECT_EQ(test, ret, 0); conn_state = conn->state; @@ -1805,10 +1923,16 @@ static void drm_test_check_output_bpc_format_display_rgb_only(struct kunit *test drm_modeset_acquire_init(&ctx, 0); +retry_conn_enable: ret = drm_kunit_helper_enable_crtc_connector(test, drm, crtc, conn, preferred, &ctx); + if (ret == -EDEADLK) { + ret = drm_modeset_backoff(&ctx); + if (!ret) + goto retry_conn_enable; + } KUNIT_EXPECT_EQ(test, ret, 0); conn_state = conn->state; @@ -1865,10 +1989,16 @@ static void drm_test_check_output_bpc_format_driver_8bpc_only(struct kunit *test drm_modeset_acquire_init(&ctx, 0); +retry_conn_enable: ret = drm_kunit_helper_enable_crtc_connector(test, drm, crtc, conn, preferred, &ctx); + if (ret == -EDEADLK) { + ret = drm_modeset_backoff(&ctx); + if (!ret) + goto retry_conn_enable; + } KUNIT_EXPECT_EQ(test, ret, 0); conn_state = conn->state; @@ -1927,10 +2057,16 @@ static void drm_test_check_output_bpc_format_display_8bpc_only(struct kunit *tes drm_modeset_acquire_init(&ctx, 0); +retry_conn_enable: ret = drm_kunit_helper_enable_crtc_connector(test, drm, crtc, conn, preferred, &ctx); + if (ret == -EDEADLK) { + ret = drm_modeset_backoff(&ctx); + if (!ret) + goto retry_conn_enable; + } KUNIT_EXPECT_EQ(test, ret, 0); conn_state = conn->state; @@ -1970,10 +2106,17 @@ static void drm_test_check_disable_connector(struct kunit *test) drm = &priv->drm; crtc = priv->crtc; + +retry_conn_enable: ret = drm_kunit_helper_enable_crtc_connector(test, drm, crtc, conn, preferred, &ctx); + if (ret == -EDEADLK) { + ret = drm_modeset_backoff(&ctx); + if (!ret) + goto retry_conn_enable; + } KUNIT_ASSERT_EQ(test, ret, 0); state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx); From 5ffc53a58a755b4b9f907afcbcec771777e9f120 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Exp=C3=B3sito?= Date: Tue, 4 Nov 2025 11:25:21 +0100 Subject: [PATCH 1109/2333] drm/tests: Handle EDEADLK in drm_test_check_valid_clones() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 141d95e42884628314f5ad9394657b0b35424300 ] Fedora/CentOS/RHEL CI is reporting intermittent failures while running the drm_test_check_valid_clones() KUnit test. The error log can be either [1]: # drm_test_check_valid_clones: ASSERTION FAILED at # drivers/gpu/drm/tests/drm_atomic_state_test.c:295 Expected ret == param->expected_result, but ret == -35 (0xffffffffffffffdd) param->expected_result == 0 (0x0) Or [2] depending on the test case: # drm_test_check_valid_clones: ASSERTION FAILED at # drivers/gpu/drm/tests/drm_atomic_state_test.c:295 Expected ret == param->expected_result, but ret == -35 (0xffffffffffffffdd) param->expected_result == -22 (0xffffffffffffffea) Restart the atomic sequence when EDEADLK is returned. [1] https://s3.amazonaws.com/arr-cki-prod-trusted-artifacts/trusted-artifacts/2113057246/test_x86_64/11802139999/artifacts/jobwatch/logs/recipes/19824965/tasks/204347800/results/946112713/logs/dmesg.log [2] https://s3.amazonaws.com/arr-cki-prod-trusted-artifacts/trusted-artifacts/2106744297/test_aarch64/11762450907/artifacts/jobwatch/logs/recipes/19797942/tasks/204139727/results/945094561/logs/dmesg.log Fixes: 88849f24e2ab ("drm/tests: Add test for drm_atomic_helper_check_modeset()") Closes: https://datawarehouse.cki-project.org/issue/4004 Reviewed-by: Maxime Ripard Signed-off-by: José Expósito Link: https://patch.msgid.link/20251104102535.12212-1-jose.exposito89@gmail.com Signed-off-by: Sasha Levin --- drivers/gpu/drm/tests/drm_atomic_state_test.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/gpu/drm/tests/drm_atomic_state_test.c b/drivers/gpu/drm/tests/drm_atomic_state_test.c index 2f6ac7a09f445..1e857d86574cc 100644 --- a/drivers/gpu/drm/tests/drm_atomic_state_test.c +++ b/drivers/gpu/drm/tests/drm_atomic_state_test.c @@ -283,7 +283,14 @@ static void drm_test_check_valid_clones(struct kunit *test) state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state); +retry: crtc_state = drm_atomic_get_crtc_state(state, priv->crtc); + if (PTR_ERR(crtc_state) == -EDEADLK) { + drm_atomic_state_clear(state); + ret = drm_modeset_backoff(&ctx); + if (!ret) + goto retry; + } KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state); crtc_state->encoder_mask = param->encoder_mask; @@ -292,6 +299,12 @@ static void drm_test_check_valid_clones(struct kunit *test) crtc_state->mode_changed = true; ret = drm_atomic_helper_check_modeset(drm, state); + if (ret == -EDEADLK) { + drm_atomic_state_clear(state); + ret = drm_modeset_backoff(&ctx); + if (!ret) + goto retry; + } KUNIT_ASSERT_EQ(test, ret, param->expected_result); drm_modeset_drop_locks(&ctx); From 9c0dc1d40b693a4b2a608fc3008fb2daa3970363 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Exp=C3=B3sito?= Date: Tue, 4 Nov 2025 11:25:22 +0100 Subject: [PATCH 1110/2333] drm/tests: Handle EDEADLK in set_up_atomic_state() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 526aafabd756cc56401b383d6ae554af3e21dcdd ] Fedora/CentOS/RHEL CI is reporting intermittent failures while running the drm_validate_modeset test [1]: # drm_test_check_connector_changed_modeset: EXPECTATION FAILED at # drivers/gpu/drm/tests/drm_atomic_state_test.c:162 Expected ret == 0, but ret == -35 (0xffffffffffffffdd) Change the set_up_atomic_state() helper function to return on error and restart the atomic sequence when the returned error is EDEADLK. [1] https://s3.amazonaws.com/arr-cki-prod-trusted-artifacts/trusted-artifacts/2106744096/test_x86_64/11762450343/artifacts/jobwatch/logs/recipes/19797909/tasks/204139142/results/945095586/logs/dmesg.log Fixes: 73d934d7b6e3 ("drm/tests: Add test for drm_atomic_helper_commit_modeset_disables()") Closes: https://datawarehouse.cki-project.org/issue/4004 Reviewed-by: Maxime Ripard Signed-off-by: José Expósito Link: https://patch.msgid.link/20251104102535.12212-2-jose.exposito89@gmail.com Signed-off-by: Sasha Levin --- drivers/gpu/drm/tests/drm_atomic_state_test.c | 27 +++++++++++++++---- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/tests/drm_atomic_state_test.c b/drivers/gpu/drm/tests/drm_atomic_state_test.c index 1e857d86574cc..bc27f65b28233 100644 --- a/drivers/gpu/drm/tests/drm_atomic_state_test.c +++ b/drivers/gpu/drm/tests/drm_atomic_state_test.c @@ -156,24 +156,29 @@ static int set_up_atomic_state(struct kunit *test, if (connector) { conn_state = drm_atomic_get_connector_state(state, connector); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state); + if (IS_ERR(conn_state)) + return PTR_ERR(conn_state); ret = drm_atomic_set_crtc_for_connector(conn_state, crtc); - KUNIT_EXPECT_EQ(test, ret, 0); + if (ret) + return ret; } crtc_state = drm_atomic_get_crtc_state(state, crtc); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state); + if (IS_ERR(crtc_state)) + return PTR_ERR(crtc_state); ret = drm_atomic_set_mode_for_crtc(crtc_state, &drm_atomic_test_mode); - KUNIT_EXPECT_EQ(test, ret, 0); + if (ret) + return ret; crtc_state->enable = true; crtc_state->active = true; if (connector) { ret = drm_atomic_commit(state); - KUNIT_ASSERT_EQ(test, ret, 0); + if (ret) + return ret; } else { // dummy connector mask crtc_state->connector_mask = DRM_TEST_CONN_0; @@ -206,7 +211,13 @@ static void drm_test_check_connector_changed_modeset(struct kunit *test) drm_modeset_acquire_init(&ctx, 0); // first modeset to enable +retry_set_up: ret = set_up_atomic_state(test, priv, old_conn, &ctx); + if (ret == -EDEADLK) { + ret = drm_modeset_backoff(&ctx); + if (!ret) + goto retry_set_up; + } KUNIT_ASSERT_EQ(test, ret, 0); state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx); @@ -277,7 +288,13 @@ static void drm_test_check_valid_clones(struct kunit *test) drm_modeset_acquire_init(&ctx, 0); +retry_set_up: ret = set_up_atomic_state(test, priv, NULL, &ctx); + if (ret == -EDEADLK) { + ret = drm_modeset_backoff(&ctx); + if (!ret) + goto retry_set_up; + } KUNIT_ASSERT_EQ(test, ret, 0); state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx); From 322d0132d8b55a24825e6ef683cdf88a5a6265a6 Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Fri, 12 Dec 2025 10:16:59 -0700 Subject: [PATCH 1111/2333] selftests: ublk: fix overflow in ublk_queue_auto_zc_fallback() [ Upstream commit 9637fc3bdd10c8e073f71897bd35babbd21e9b29 ] The functions ublk_queue_use_zc(), ublk_queue_use_auto_zc(), and ublk_queue_auto_zc_fallback() were returning int, but performing bitwise AND on q->flags which is __u64. When a flag bit is set in the upper 32 bits (beyond INT_MAX), the result of the bitwise AND operation could overflow when cast to int, leading to incorrect boolean evaluation. For example, if UBLKS_Q_AUTO_BUF_REG_FALLBACK is 0x8000000000000000: - (u64)flags & 0x8000000000000000 = 0x8000000000000000 - Cast to int: undefined behavior / incorrect value - Used in if(): may evaluate incorrectly Fix by: 1. Changing return type from int to bool for semantic correctness 2. Using !! to explicitly convert to boolean (0 or 1) This ensures the functions return proper boolean values regardless of which bit position the flags occupy in the 64-bit field. Fixes: c3a6d48f86da ("selftests: ublk: remove ublk queue self-defined flags") Signed-off-by: Ming Lei Signed-off-by: Jens Axboe Signed-off-by: Sasha Levin --- tools/testing/selftests/ublk/kublk.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tools/testing/selftests/ublk/kublk.h b/tools/testing/selftests/ublk/kublk.h index 5e55484fb0aa2..1b8833a400643 100644 --- a/tools/testing/selftests/ublk/kublk.h +++ b/tools/testing/selftests/ublk/kublk.h @@ -393,19 +393,19 @@ static inline int ublk_completed_tgt_io(struct ublk_thread *t, return --io->tgt_ios == 0; } -static inline int ublk_queue_use_zc(const struct ublk_queue *q) +static inline bool ublk_queue_use_zc(const struct ublk_queue *q) { - return q->flags & UBLK_F_SUPPORT_ZERO_COPY; + return !!(q->flags & UBLK_F_SUPPORT_ZERO_COPY); } -static inline int ublk_queue_use_auto_zc(const struct ublk_queue *q) +static inline bool ublk_queue_use_auto_zc(const struct ublk_queue *q) { - return q->flags & UBLK_F_AUTO_BUF_REG; + return !!(q->flags & UBLK_F_AUTO_BUF_REG); } -static inline int ublk_queue_auto_zc_fallback(const struct ublk_queue *q) +static inline bool ublk_queue_auto_zc_fallback(const struct ublk_queue *q) { - return q->flags & UBLKS_Q_AUTO_BUF_REG_FALLBACK; + return !!(q->flags & UBLKS_Q_AUTO_BUF_REG_FALLBACK); } static inline int ublk_queue_no_buf(const struct ublk_queue *q) From 22f98de8fa78f5e245046e2714244479e0ffd371 Mon Sep 17 00:00:00 2001 From: Nilay Shroff Date: Thu, 13 Nov 2025 14:28:18 +0530 Subject: [PATCH 1112/2333] block: unify elevator tags and type xarrays into struct elv_change_ctx MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 232143b605387b372dee0ec7830f93b93df5f67d ] Currently, the nr_hw_queues update path manages two disjoint xarrays — one for elevator tags and another for elevator type — both used during elevator switching. Maintaining these two parallel structures for the same purpose adds unnecessary complexity and potential for mismatched state. This patch unifies both xarrays into a single structure, struct elv_change_ctx, which holds all per-queue elevator change context. A single xarray, named elv_tbl, now maps each queue (q->id) in a tagset to its corresponding elv_change_ctx entry, encapsulating the elevator tags, type and name references. This unification simplifies the code, improves maintainability, and clarifies ownership of per-queue elevator state. Reviewed-by: Ming Lei Reviewed-by: Yu Kuai Signed-off-by: Nilay Shroff Signed-off-by: Jens Axboe Stable-dep-of: 9869d3a6fed3 ("block: fix race between wbt_enable_default and IO submission") Signed-off-by: Sasha Levin --- block/blk-mq-sched.c | 76 +++++++++++++++++++++++++++++++++----------- block/blk-mq-sched.h | 3 ++ block/blk-mq.c | 50 +++++++++++++++++------------ block/blk.h | 7 ++-- block/elevator.c | 31 ++++-------------- block/elevator.h | 15 +++++++++ 6 files changed, 115 insertions(+), 67 deletions(-) diff --git a/block/blk-mq-sched.c b/block/blk-mq-sched.c index e0bed16485c34..3d9386555a50a 100644 --- a/block/blk-mq-sched.c +++ b/block/blk-mq-sched.c @@ -427,11 +427,11 @@ void blk_mq_free_sched_tags(struct elevator_tags *et, kfree(et); } -void blk_mq_free_sched_tags_batch(struct xarray *et_table, +void blk_mq_free_sched_tags_batch(struct xarray *elv_tbl, struct blk_mq_tag_set *set) { struct request_queue *q; - struct elevator_tags *et; + struct elv_change_ctx *ctx; lockdep_assert_held_write(&set->update_nr_hwq_lock); @@ -444,13 +444,47 @@ void blk_mq_free_sched_tags_batch(struct xarray *et_table, * concurrently. */ if (q->elevator) { - et = xa_load(et_table, q->id); - if (unlikely(!et)) + ctx = xa_load(elv_tbl, q->id); + if (!ctx || !ctx->et) { WARN_ON_ONCE(1); - else - blk_mq_free_sched_tags(et, set); + continue; + } + blk_mq_free_sched_tags(ctx->et, set); + ctx->et = NULL; + } + } +} + +void blk_mq_free_sched_ctx_batch(struct xarray *elv_tbl) +{ + unsigned long i; + struct elv_change_ctx *ctx; + + xa_for_each(elv_tbl, i, ctx) { + xa_erase(elv_tbl, i); + kfree(ctx); + } +} + +int blk_mq_alloc_sched_ctx_batch(struct xarray *elv_tbl, + struct blk_mq_tag_set *set) +{ + struct request_queue *q; + struct elv_change_ctx *ctx; + + lockdep_assert_held_write(&set->update_nr_hwq_lock); + + list_for_each_entry(q, &set->tag_list, tag_set_list) { + ctx = kzalloc(sizeof(struct elv_change_ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + if (xa_insert(elv_tbl, q->id, ctx, GFP_KERNEL)) { + kfree(ctx); + return -ENOMEM; } } + return 0; } struct elevator_tags *blk_mq_alloc_sched_tags(struct blk_mq_tag_set *set, @@ -498,12 +532,13 @@ struct elevator_tags *blk_mq_alloc_sched_tags(struct blk_mq_tag_set *set, return NULL; } -int blk_mq_alloc_sched_tags_batch(struct xarray *et_table, +int blk_mq_alloc_sched_tags_batch(struct xarray *elv_tbl, struct blk_mq_tag_set *set, unsigned int nr_hw_queues) { + struct elv_change_ctx *ctx; struct request_queue *q; struct elevator_tags *et; - gfp_t gfp = GFP_NOIO | __GFP_ZERO | __GFP_NOWARN | __GFP_NORETRY; + int ret = -ENOMEM; lockdep_assert_held_write(&set->update_nr_hwq_lock); @@ -516,26 +551,31 @@ int blk_mq_alloc_sched_tags_batch(struct xarray *et_table, * concurrently. */ if (q->elevator) { - et = blk_mq_alloc_sched_tags(set, nr_hw_queues, + ctx = xa_load(elv_tbl, q->id); + if (WARN_ON_ONCE(!ctx)) { + ret = -ENOENT; + goto out_unwind; + } + + ctx->et = blk_mq_alloc_sched_tags(set, nr_hw_queues, blk_mq_default_nr_requests(set)); - if (!et) + if (!ctx->et) goto out_unwind; - if (xa_insert(et_table, q->id, et, gfp)) - goto out_free_tags; + } } return 0; -out_free_tags: - blk_mq_free_sched_tags(et, set); out_unwind: list_for_each_entry_continue_reverse(q, &set->tag_list, tag_set_list) { if (q->elevator) { - et = xa_load(et_table, q->id); - if (et) - blk_mq_free_sched_tags(et, set); + ctx = xa_load(elv_tbl, q->id); + if (ctx && ctx->et) { + blk_mq_free_sched_tags(ctx->et, set); + ctx->et = NULL; + } } } - return -ENOMEM; + return ret; } /* caller must have a reference to @e, will grab another one if successful */ diff --git a/block/blk-mq-sched.h b/block/blk-mq-sched.h index 8e21a6b1415d9..2fddbc91a2359 100644 --- a/block/blk-mq-sched.h +++ b/block/blk-mq-sched.h @@ -27,6 +27,9 @@ struct elevator_tags *blk_mq_alloc_sched_tags(struct blk_mq_tag_set *set, unsigned int nr_hw_queues, unsigned int nr_requests); int blk_mq_alloc_sched_tags_batch(struct xarray *et_table, struct blk_mq_tag_set *set, unsigned int nr_hw_queues); +int blk_mq_alloc_sched_ctx_batch(struct xarray *elv_tbl, + struct blk_mq_tag_set *set); +void blk_mq_free_sched_ctx_batch(struct xarray *elv_tbl); void blk_mq_free_sched_tags(struct elevator_tags *et, struct blk_mq_tag_set *set); void blk_mq_free_sched_tags_batch(struct xarray *et_table, diff --git a/block/blk-mq.c b/block/blk-mq.c index f901aeba85522..180d45db56246 100644 --- a/block/blk-mq.c +++ b/block/blk-mq.c @@ -4996,27 +4996,28 @@ struct elevator_tags *blk_mq_update_nr_requests(struct request_queue *q, * Switch back to the elevator type stored in the xarray. */ static void blk_mq_elv_switch_back(struct request_queue *q, - struct xarray *elv_tbl, struct xarray *et_tbl) + struct xarray *elv_tbl) { - struct elevator_type *e = xa_load(elv_tbl, q->id); - struct elevator_tags *t = xa_load(et_tbl, q->id); + struct elv_change_ctx *ctx = xa_load(elv_tbl, q->id); + + if (WARN_ON_ONCE(!ctx)) + return; /* The elv_update_nr_hw_queues unfreezes the queue. */ - elv_update_nr_hw_queues(q, e, t); + elv_update_nr_hw_queues(q, ctx); /* Drop the reference acquired in blk_mq_elv_switch_none. */ - if (e) - elevator_put(e); + if (ctx->type) + elevator_put(ctx->type); } /* - * Stores elevator type in xarray and set current elevator to none. It uses - * q->id as an index to store the elevator type into the xarray. + * Stores elevator name and type in ctx and set current elevator to none. */ static int blk_mq_elv_switch_none(struct request_queue *q, struct xarray *elv_tbl) { - int ret = 0; + struct elv_change_ctx *ctx; lockdep_assert_held_write(&q->tag_set->update_nr_hwq_lock); @@ -5028,10 +5029,11 @@ static int blk_mq_elv_switch_none(struct request_queue *q, * can't run concurrently. */ if (q->elevator) { + ctx = xa_load(elv_tbl, q->id); + if (WARN_ON_ONCE(!ctx)) + return -ENOENT; - ret = xa_insert(elv_tbl, q->id, q->elevator->type, GFP_KERNEL); - if (WARN_ON_ONCE(ret)) - return ret; + ctx->name = q->elevator->type->elevator_name; /* * Before we switch elevator to 'none', take a reference to @@ -5042,9 +5044,14 @@ static int blk_mq_elv_switch_none(struct request_queue *q, */ __elevator_get(q->elevator->type); + /* + * Store elevator type so that we can release the reference + * taken above later. + */ + ctx->type = q->elevator->type; elevator_set_none(q); } - return ret; + return 0; } static void __blk_mq_update_nr_hw_queues(struct blk_mq_tag_set *set, @@ -5054,7 +5061,7 @@ static void __blk_mq_update_nr_hw_queues(struct blk_mq_tag_set *set, int prev_nr_hw_queues = set->nr_hw_queues; unsigned int memflags; int i; - struct xarray elv_tbl, et_tbl; + struct xarray elv_tbl; bool queues_frozen = false; lockdep_assert_held(&set->tag_list_lock); @@ -5068,11 +5075,12 @@ static void __blk_mq_update_nr_hw_queues(struct blk_mq_tag_set *set, memflags = memalloc_noio_save(); - xa_init(&et_tbl); - if (blk_mq_alloc_sched_tags_batch(&et_tbl, set, nr_hw_queues) < 0) - goto out_memalloc_restore; - xa_init(&elv_tbl); + if (blk_mq_alloc_sched_ctx_batch(&elv_tbl, set) < 0) + goto out_free_ctx; + + if (blk_mq_alloc_sched_tags_batch(&elv_tbl, set, nr_hw_queues) < 0) + goto out_free_ctx; list_for_each_entry(q, &set->tag_list, tag_set_list) { blk_mq_debugfs_unregister_hctxs(q); @@ -5118,7 +5126,7 @@ static void __blk_mq_update_nr_hw_queues(struct blk_mq_tag_set *set, /* switch_back expects queue to be frozen */ if (!queues_frozen) blk_mq_freeze_queue_nomemsave(q); - blk_mq_elv_switch_back(q, &elv_tbl, &et_tbl); + blk_mq_elv_switch_back(q, &elv_tbl); } list_for_each_entry(q, &set->tag_list, tag_set_list) { @@ -5129,9 +5137,9 @@ static void __blk_mq_update_nr_hw_queues(struct blk_mq_tag_set *set, blk_mq_add_hw_queues_cpuhp(q); } +out_free_ctx: + blk_mq_free_sched_ctx_batch(&elv_tbl); xa_destroy(&elv_tbl); - xa_destroy(&et_tbl); -out_memalloc_restore: memalloc_noio_restore(memflags); /* Free the excess tags when nr_hw_queues shrink. */ diff --git a/block/blk.h b/block/blk.h index 170794632135d..a7992680f9e14 100644 --- a/block/blk.h +++ b/block/blk.h @@ -11,8 +11,7 @@ #include #include "blk-crypto-internal.h" -struct elevator_type; -struct elevator_tags; +struct elv_change_ctx; /* * Default upper limit for the software max_sectors limit used for regular I/Os. @@ -333,8 +332,8 @@ bool blk_bio_list_merge(struct request_queue *q, struct list_head *list, bool blk_insert_flush(struct request *rq); -void elv_update_nr_hw_queues(struct request_queue *q, struct elevator_type *e, - struct elevator_tags *t); +void elv_update_nr_hw_queues(struct request_queue *q, + struct elv_change_ctx *ctx); void elevator_set_default(struct request_queue *q); void elevator_set_none(struct request_queue *q); diff --git a/block/elevator.c b/block/elevator.c index e2ebfbf107b3a..cd7bdff205c8c 100644 --- a/block/elevator.c +++ b/block/elevator.c @@ -45,19 +45,6 @@ #include "blk-wbt.h" #include "blk-cgroup.h" -/* Holding context data for changing elevator */ -struct elv_change_ctx { - const char *name; - bool no_uevent; - - /* for unregistering old elevator */ - struct elevator_queue *old; - /* for registering new elevator */ - struct elevator_queue *new; - /* holds sched tags data */ - struct elevator_tags *et; -}; - static DEFINE_SPINLOCK(elv_list_lock); static LIST_HEAD(elv_list); @@ -706,32 +693,28 @@ static int elevator_change(struct request_queue *q, struct elv_change_ctx *ctx) * The I/O scheduler depends on the number of hardware queues, this forces a * reattachment when nr_hw_queues changes. */ -void elv_update_nr_hw_queues(struct request_queue *q, struct elevator_type *e, - struct elevator_tags *t) +void elv_update_nr_hw_queues(struct request_queue *q, + struct elv_change_ctx *ctx) { struct blk_mq_tag_set *set = q->tag_set; - struct elv_change_ctx ctx = {}; int ret = -ENODEV; WARN_ON_ONCE(q->mq_freeze_depth == 0); - if (e && !blk_queue_dying(q) && blk_queue_registered(q)) { - ctx.name = e->elevator_name; - ctx.et = t; - + if (ctx->type && !blk_queue_dying(q) && blk_queue_registered(q)) { mutex_lock(&q->elevator_lock); /* force to reattach elevator after nr_hw_queue is updated */ - ret = elevator_switch(q, &ctx); + ret = elevator_switch(q, ctx); mutex_unlock(&q->elevator_lock); } blk_mq_unfreeze_queue_nomemrestore(q); if (!ret) - WARN_ON_ONCE(elevator_change_done(q, &ctx)); + WARN_ON_ONCE(elevator_change_done(q, ctx)); /* * Free sched tags if it's allocated but we couldn't switch elevator. */ - if (t && !ctx.new) - blk_mq_free_sched_tags(t, set); + if (ctx->et && !ctx->new) + blk_mq_free_sched_tags(ctx->et, set); } /* diff --git a/block/elevator.h b/block/elevator.h index c4d20155065e8..bad43182361e5 100644 --- a/block/elevator.h +++ b/block/elevator.h @@ -32,6 +32,21 @@ struct elevator_tags { struct blk_mq_tags *tags[]; }; +/* Holding context data for changing elevator */ +struct elv_change_ctx { + const char *name; + bool no_uevent; + + /* for unregistering old elevator */ + struct elevator_queue *old; + /* for registering new elevator */ + struct elevator_queue *new; + /* store elevator type */ + struct elevator_type *type; + /* holds sched tags data */ + struct elevator_tags *et; +}; + struct elevator_mq_ops { int (*init_sched)(struct request_queue *, struct elevator_queue *); void (*exit_sched)(struct elevator_queue *); From aa81ed74af25ac10fcf69515eae18e14a0709f2b Mon Sep 17 00:00:00 2001 From: Nilay Shroff Date: Thu, 13 Nov 2025 14:28:19 +0530 Subject: [PATCH 1113/2333] block: move elevator tags into struct elevator_resources [ Upstream commit 04728ce90966c54417fd8120a3820104d18ba68d ] This patch introduces a new structure, struct elevator_resources, to group together all elevator-related resources that share the same lifetime. As a first step, this change moves the elevator tag pointer from struct elv_change_ctx into the new struct elevator_resources. Additionally, rename blk_mq_alloc_sched_tags_batch() and blk_mq_free_sched_tags_batch() to blk_mq_alloc_sched_res_batch() and blk_mq_free_sched_res_batch(), respectively. Introduce two new wrapper helpers, blk_mq_alloc_sched_res() and blk_mq_free_sched_res(), around blk_mq_alloc_sched_tags() and blk_mq_free_sched_tags(). These changes pave the way for consolidating the allocation and freeing of elevator-specific resources into common helper functions. This refactoring improves encapsulation and prepares the code for future extensions, allowing additional elevator-specific data to be added to struct elevator_resources without cluttering struct elv_change_ctx. Subsequent patches will extend struct elevator_resources to include other elevator-related data. Reviewed-by: Ming Lei Reviewed-by: Yu Kuai Signed-off-by: Nilay Shroff Signed-off-by: Jens Axboe Stable-dep-of: 9869d3a6fed3 ("block: fix race between wbt_enable_default and IO submission") Signed-off-by: Sasha Levin --- block/blk-mq-sched.c | 48 ++++++++++++++++++++++++++++++-------------- block/blk-mq-sched.h | 10 ++++++--- block/blk-mq.c | 2 +- block/elevator.c | 31 ++++++++++++++-------------- block/elevator.h | 9 +++++++-- 5 files changed, 64 insertions(+), 36 deletions(-) diff --git a/block/blk-mq-sched.c b/block/blk-mq-sched.c index 3d9386555a50a..03ff16c49976a 100644 --- a/block/blk-mq-sched.c +++ b/block/blk-mq-sched.c @@ -427,7 +427,16 @@ void blk_mq_free_sched_tags(struct elevator_tags *et, kfree(et); } -void blk_mq_free_sched_tags_batch(struct xarray *elv_tbl, +void blk_mq_free_sched_res(struct elevator_resources *res, + struct blk_mq_tag_set *set) +{ + if (res->et) { + blk_mq_free_sched_tags(res->et, set); + res->et = NULL; + } +} + +void blk_mq_free_sched_res_batch(struct xarray *elv_tbl, struct blk_mq_tag_set *set) { struct request_queue *q; @@ -445,12 +454,11 @@ void blk_mq_free_sched_tags_batch(struct xarray *elv_tbl, */ if (q->elevator) { ctx = xa_load(elv_tbl, q->id); - if (!ctx || !ctx->et) { + if (!ctx) { WARN_ON_ONCE(1); continue; } - blk_mq_free_sched_tags(ctx->et, set); - ctx->et = NULL; + blk_mq_free_sched_res(&ctx->res, set); } } } @@ -532,12 +540,24 @@ struct elevator_tags *blk_mq_alloc_sched_tags(struct blk_mq_tag_set *set, return NULL; } -int blk_mq_alloc_sched_tags_batch(struct xarray *elv_tbl, +int blk_mq_alloc_sched_res(struct request_queue *q, + struct elevator_resources *res, unsigned int nr_hw_queues) +{ + struct blk_mq_tag_set *set = q->tag_set; + + res->et = blk_mq_alloc_sched_tags(set, nr_hw_queues, + blk_mq_default_nr_requests(set)); + if (!res->et) + return -ENOMEM; + + return 0; +} + +int blk_mq_alloc_sched_res_batch(struct xarray *elv_tbl, struct blk_mq_tag_set *set, unsigned int nr_hw_queues) { struct elv_change_ctx *ctx; struct request_queue *q; - struct elevator_tags *et; int ret = -ENOMEM; lockdep_assert_held_write(&set->update_nr_hwq_lock); @@ -557,11 +577,10 @@ int blk_mq_alloc_sched_tags_batch(struct xarray *elv_tbl, goto out_unwind; } - ctx->et = blk_mq_alloc_sched_tags(set, nr_hw_queues, - blk_mq_default_nr_requests(set)); - if (!ctx->et) + ret = blk_mq_alloc_sched_res(q, &ctx->res, + nr_hw_queues); + if (ret) goto out_unwind; - } } return 0; @@ -569,10 +588,8 @@ int blk_mq_alloc_sched_tags_batch(struct xarray *elv_tbl, list_for_each_entry_continue_reverse(q, &set->tag_list, tag_set_list) { if (q->elevator) { ctx = xa_load(elv_tbl, q->id); - if (ctx && ctx->et) { - blk_mq_free_sched_tags(ctx->et, set); - ctx->et = NULL; - } + if (ctx) + blk_mq_free_sched_res(&ctx->res, set); } } return ret; @@ -580,9 +597,10 @@ int blk_mq_alloc_sched_tags_batch(struct xarray *elv_tbl, /* caller must have a reference to @e, will grab another one if successful */ int blk_mq_init_sched(struct request_queue *q, struct elevator_type *e, - struct elevator_tags *et) + struct elevator_resources *res) { unsigned int flags = q->tag_set->flags; + struct elevator_tags *et = res->et; struct blk_mq_hw_ctx *hctx; struct elevator_queue *eq; unsigned long i; diff --git a/block/blk-mq-sched.h b/block/blk-mq-sched.h index 2fddbc91a2359..1f8e58dd4b497 100644 --- a/block/blk-mq-sched.h +++ b/block/blk-mq-sched.h @@ -19,20 +19,24 @@ void __blk_mq_sched_restart(struct blk_mq_hw_ctx *hctx); void blk_mq_sched_dispatch_requests(struct blk_mq_hw_ctx *hctx); int blk_mq_init_sched(struct request_queue *q, struct elevator_type *e, - struct elevator_tags *et); + struct elevator_resources *res); void blk_mq_exit_sched(struct request_queue *q, struct elevator_queue *e); void blk_mq_sched_free_rqs(struct request_queue *q); struct elevator_tags *blk_mq_alloc_sched_tags(struct blk_mq_tag_set *set, unsigned int nr_hw_queues, unsigned int nr_requests); -int blk_mq_alloc_sched_tags_batch(struct xarray *et_table, +int blk_mq_alloc_sched_res(struct request_queue *q, + struct elevator_resources *res, unsigned int nr_hw_queues); +int blk_mq_alloc_sched_res_batch(struct xarray *elv_tbl, struct blk_mq_tag_set *set, unsigned int nr_hw_queues); int blk_mq_alloc_sched_ctx_batch(struct xarray *elv_tbl, struct blk_mq_tag_set *set); void blk_mq_free_sched_ctx_batch(struct xarray *elv_tbl); void blk_mq_free_sched_tags(struct elevator_tags *et, struct blk_mq_tag_set *set); -void blk_mq_free_sched_tags_batch(struct xarray *et_table, +void blk_mq_free_sched_res(struct elevator_resources *res, + struct blk_mq_tag_set *set); +void blk_mq_free_sched_res_batch(struct xarray *et_table, struct blk_mq_tag_set *set); static inline void blk_mq_sched_restart(struct blk_mq_hw_ctx *hctx) diff --git a/block/blk-mq.c b/block/blk-mq.c index 180d45db56246..ea5f948af7a42 100644 --- a/block/blk-mq.c +++ b/block/blk-mq.c @@ -5079,7 +5079,7 @@ static void __blk_mq_update_nr_hw_queues(struct blk_mq_tag_set *set, if (blk_mq_alloc_sched_ctx_batch(&elv_tbl, set) < 0) goto out_free_ctx; - if (blk_mq_alloc_sched_tags_batch(&elv_tbl, set, nr_hw_queues) < 0) + if (blk_mq_alloc_sched_res_batch(&elv_tbl, set, nr_hw_queues) < 0) goto out_free_ctx; list_for_each_entry(q, &set->tag_list, tag_set_list) { diff --git a/block/elevator.c b/block/elevator.c index cd7bdff205c8c..cbec292a4af5b 100644 --- a/block/elevator.c +++ b/block/elevator.c @@ -580,7 +580,7 @@ static int elevator_switch(struct request_queue *q, struct elv_change_ctx *ctx) } if (new_e) { - ret = blk_mq_init_sched(q, new_e, ctx->et); + ret = blk_mq_init_sched(q, new_e, &ctx->res); if (ret) goto out_unfreeze; ctx->new = q->elevator; @@ -604,7 +604,8 @@ static int elevator_switch(struct request_queue *q, struct elv_change_ctx *ctx) return ret; } -static void elv_exit_and_release(struct request_queue *q) +static void elv_exit_and_release(struct elv_change_ctx *ctx, + struct request_queue *q) { struct elevator_queue *e; unsigned memflags; @@ -616,7 +617,7 @@ static void elv_exit_and_release(struct request_queue *q) mutex_unlock(&q->elevator_lock); blk_mq_unfreeze_queue(q, memflags); if (e) { - blk_mq_free_sched_tags(e->et, q->tag_set); + blk_mq_free_sched_res(&ctx->res, q->tag_set); kobject_put(&e->kobj); } } @@ -627,11 +628,12 @@ static int elevator_change_done(struct request_queue *q, int ret = 0; if (ctx->old) { + struct elevator_resources res = {.et = ctx->old->et}; bool enable_wbt = test_bit(ELEVATOR_FLAG_ENABLE_WBT_ON_EXIT, &ctx->old->flags); elv_unregister_queue(q, ctx->old); - blk_mq_free_sched_tags(ctx->old->et, q->tag_set); + blk_mq_free_sched_res(&res, q->tag_set); kobject_put(&ctx->old->kobj); if (enable_wbt) wbt_enable_default(q->disk); @@ -639,7 +641,7 @@ static int elevator_change_done(struct request_queue *q, if (ctx->new) { ret = elv_register_queue(q, ctx->new, !ctx->no_uevent); if (ret) - elv_exit_and_release(q); + elv_exit_and_release(ctx, q); } return ret; } @@ -656,10 +658,9 @@ static int elevator_change(struct request_queue *q, struct elv_change_ctx *ctx) lockdep_assert_held(&set->update_nr_hwq_lock); if (strncmp(ctx->name, "none", 4)) { - ctx->et = blk_mq_alloc_sched_tags(set, set->nr_hw_queues, - blk_mq_default_nr_requests(set)); - if (!ctx->et) - return -ENOMEM; + ret = blk_mq_alloc_sched_res(q, &ctx->res, set->nr_hw_queues); + if (ret) + return ret; } memflags = blk_mq_freeze_queue(q); @@ -681,10 +682,10 @@ static int elevator_change(struct request_queue *q, struct elv_change_ctx *ctx) if (!ret) ret = elevator_change_done(q, ctx); /* - * Free sched tags if it's allocated but we couldn't switch elevator. + * Free sched resource if it's allocated but we couldn't switch elevator. */ - if (ctx->et && !ctx->new) - blk_mq_free_sched_tags(ctx->et, set); + if (!ctx->new) + blk_mq_free_sched_res(&ctx->res, set); return ret; } @@ -711,10 +712,10 @@ void elv_update_nr_hw_queues(struct request_queue *q, if (!ret) WARN_ON_ONCE(elevator_change_done(q, ctx)); /* - * Free sched tags if it's allocated but we couldn't switch elevator. + * Free sched resource if it's allocated but we couldn't switch elevator. */ - if (ctx->et && !ctx->new) - blk_mq_free_sched_tags(ctx->et, set); + if (!ctx->new) + blk_mq_free_sched_res(&ctx->res, set); } /* diff --git a/block/elevator.h b/block/elevator.h index bad43182361e5..621a63597249e 100644 --- a/block/elevator.h +++ b/block/elevator.h @@ -32,6 +32,11 @@ struct elevator_tags { struct blk_mq_tags *tags[]; }; +struct elevator_resources { + /* holds elevator tags */ + struct elevator_tags *et; +}; + /* Holding context data for changing elevator */ struct elv_change_ctx { const char *name; @@ -43,8 +48,8 @@ struct elv_change_ctx { struct elevator_queue *new; /* store elevator type */ struct elevator_type *type; - /* holds sched tags data */ - struct elevator_tags *et; + /* store elevator resources */ + struct elevator_resources res; }; struct elevator_mq_ops { From 93869ded0cccf27fbb82d5356afd66d711f88230 Mon Sep 17 00:00:00 2001 From: Nilay Shroff Date: Thu, 13 Nov 2025 14:28:20 +0530 Subject: [PATCH 1114/2333] block: introduce alloc_sched_data and free_sched_data elevator methods [ Upstream commit 61019afdf6ac17c8e8f9c42665aa1fa82f04a3e2 ] The recent lockdep splat [1] highlights a potential deadlock risk involving ->elevator_lock and ->freeze_lock dependencies on -pcpu_alloc_ mutex. The trace shows that the issue occurs when the Kyber scheduler allocates dynamic memory for its elevator data during initialization. To address this, introduce two new elevator operation callbacks: ->alloc_sched_data and ->free_sched_data. The subsequent patch would build upon these newly introduced methods to suppress lockdep splat[1]. [1] https://lore.kernel.org/all/CAGVVp+VNW4M-5DZMNoADp6o2VKFhi7KxWpTDkcnVyjO0=-D5+A@mail.gmail.com/ Signed-off-by: Nilay Shroff Reviewed-by: Ming Lei Signed-off-by: Jens Axboe Stable-dep-of: 9869d3a6fed3 ("block: fix race between wbt_enable_default and IO submission") Signed-off-by: Sasha Levin --- block/blk-mq-sched.h | 24 ++++++++++++++++++++++++ block/elevator.h | 2 ++ 2 files changed, 26 insertions(+) diff --git a/block/blk-mq-sched.h b/block/blk-mq-sched.h index 1f8e58dd4b497..4e1b86e85a8a9 100644 --- a/block/blk-mq-sched.h +++ b/block/blk-mq-sched.h @@ -38,6 +38,30 @@ void blk_mq_free_sched_res(struct elevator_resources *res, struct blk_mq_tag_set *set); void blk_mq_free_sched_res_batch(struct xarray *et_table, struct blk_mq_tag_set *set); +/* + * blk_mq_alloc_sched_data() - Allocates scheduler specific data + * Returns: + * - Pointer to allocated data on success + * - NULL if no allocation needed + * - ERR_PTR(-ENOMEM) in case of failure + */ +static inline void *blk_mq_alloc_sched_data(struct request_queue *q, + struct elevator_type *e) +{ + void *sched_data; + + if (!e || !e->ops.alloc_sched_data) + return NULL; + + sched_data = e->ops.alloc_sched_data(q); + return (sched_data) ?: ERR_PTR(-ENOMEM); +} + +static inline void blk_mq_free_sched_data(struct elevator_type *e, void *data) +{ + if (e && e->ops.free_sched_data) + e->ops.free_sched_data(data); +} static inline void blk_mq_sched_restart(struct blk_mq_hw_ctx *hctx) { diff --git a/block/elevator.h b/block/elevator.h index 621a63597249e..e34043f6da26e 100644 --- a/block/elevator.h +++ b/block/elevator.h @@ -58,6 +58,8 @@ struct elevator_mq_ops { int (*init_hctx)(struct blk_mq_hw_ctx *, unsigned int); void (*exit_hctx)(struct blk_mq_hw_ctx *, unsigned int); void (*depth_updated)(struct request_queue *); + void *(*alloc_sched_data)(struct request_queue *); + void (*free_sched_data)(void *); bool (*allow_merge)(struct request_queue *, struct request *, struct bio *); bool (*bio_merge)(struct request_queue *, struct bio *, unsigned int); From ef8178f8100249e066bf70fe8305481eb3e149a1 Mon Sep 17 00:00:00 2001 From: Nilay Shroff Date: Thu, 13 Nov 2025 14:28:21 +0530 Subject: [PATCH 1115/2333] block: use {alloc|free}_sched data methods [ Upstream commit 0315476e78c050048e80f66334a310e5581b46bb ] The previous patch introduced ->alloc_sched_data and ->free_sched_data methods. This patch builds upon that by now using these methods during elevator switch and nr_hw_queue update. It's also ensured that scheduler-specific data is allocated and freed through the new callbacks outside of the ->freeze_lock and ->elevator_lock locking contexts, thereby preventing any dependency on pcpu_alloc_mutex. Reviewed-by: Ming Lei Reviewed-by: Yu Kuai Signed-off-by: Nilay Shroff Signed-off-by: Jens Axboe Stable-dep-of: 9869d3a6fed3 ("block: fix race between wbt_enable_default and IO submission") Signed-off-by: Sasha Levin --- block/blk-mq-sched.c | 27 +++++++++++++++++++++------ block/blk-mq-sched.h | 5 ++++- block/elevator.c | 34 ++++++++++++++++++++++------------ block/elevator.h | 4 +++- 4 files changed, 50 insertions(+), 20 deletions(-) diff --git a/block/blk-mq-sched.c b/block/blk-mq-sched.c index 03ff16c49976a..128f2be9d4207 100644 --- a/block/blk-mq-sched.c +++ b/block/blk-mq-sched.c @@ -428,12 +428,17 @@ void blk_mq_free_sched_tags(struct elevator_tags *et, } void blk_mq_free_sched_res(struct elevator_resources *res, + struct elevator_type *type, struct blk_mq_tag_set *set) { if (res->et) { blk_mq_free_sched_tags(res->et, set); res->et = NULL; } + if (res->data) { + blk_mq_free_sched_data(type, res->data); + res->data = NULL; + } } void blk_mq_free_sched_res_batch(struct xarray *elv_tbl, @@ -458,7 +463,7 @@ void blk_mq_free_sched_res_batch(struct xarray *elv_tbl, WARN_ON_ONCE(1); continue; } - blk_mq_free_sched_res(&ctx->res, set); + blk_mq_free_sched_res(&ctx->res, ctx->type, set); } } } @@ -541,7 +546,9 @@ struct elevator_tags *blk_mq_alloc_sched_tags(struct blk_mq_tag_set *set, } int blk_mq_alloc_sched_res(struct request_queue *q, - struct elevator_resources *res, unsigned int nr_hw_queues) + struct elevator_type *type, + struct elevator_resources *res, + unsigned int nr_hw_queues) { struct blk_mq_tag_set *set = q->tag_set; @@ -550,6 +557,12 @@ int blk_mq_alloc_sched_res(struct request_queue *q, if (!res->et) return -ENOMEM; + res->data = blk_mq_alloc_sched_data(q, type); + if (IS_ERR(res->data)) { + blk_mq_free_sched_tags(res->et, set); + return -ENOMEM; + } + return 0; } @@ -577,19 +590,21 @@ int blk_mq_alloc_sched_res_batch(struct xarray *elv_tbl, goto out_unwind; } - ret = blk_mq_alloc_sched_res(q, &ctx->res, - nr_hw_queues); + ret = blk_mq_alloc_sched_res(q, q->elevator->type, + &ctx->res, nr_hw_queues); if (ret) goto out_unwind; } } return 0; + out_unwind: list_for_each_entry_continue_reverse(q, &set->tag_list, tag_set_list) { if (q->elevator) { ctx = xa_load(elv_tbl, q->id); if (ctx) - blk_mq_free_sched_res(&ctx->res, set); + blk_mq_free_sched_res(&ctx->res, + ctx->type, set); } } return ret; @@ -606,7 +621,7 @@ int blk_mq_init_sched(struct request_queue *q, struct elevator_type *e, unsigned long i; int ret; - eq = elevator_alloc(q, e, et); + eq = elevator_alloc(q, e, res); if (!eq) return -ENOMEM; diff --git a/block/blk-mq-sched.h b/block/blk-mq-sched.h index 4e1b86e85a8a9..02c40a72e9598 100644 --- a/block/blk-mq-sched.h +++ b/block/blk-mq-sched.h @@ -26,7 +26,9 @@ void blk_mq_sched_free_rqs(struct request_queue *q); struct elevator_tags *blk_mq_alloc_sched_tags(struct blk_mq_tag_set *set, unsigned int nr_hw_queues, unsigned int nr_requests); int blk_mq_alloc_sched_res(struct request_queue *q, - struct elevator_resources *res, unsigned int nr_hw_queues); + struct elevator_type *type, + struct elevator_resources *res, + unsigned int nr_hw_queues); int blk_mq_alloc_sched_res_batch(struct xarray *elv_tbl, struct blk_mq_tag_set *set, unsigned int nr_hw_queues); int blk_mq_alloc_sched_ctx_batch(struct xarray *elv_tbl, @@ -35,6 +37,7 @@ void blk_mq_free_sched_ctx_batch(struct xarray *elv_tbl); void blk_mq_free_sched_tags(struct elevator_tags *et, struct blk_mq_tag_set *set); void blk_mq_free_sched_res(struct elevator_resources *res, + struct elevator_type *type, struct blk_mq_tag_set *set); void blk_mq_free_sched_res_batch(struct xarray *et_table, struct blk_mq_tag_set *set); diff --git a/block/elevator.c b/block/elevator.c index cbec292a4af5b..5b37ef44f52d7 100644 --- a/block/elevator.c +++ b/block/elevator.c @@ -121,7 +121,7 @@ static struct elevator_type *elevator_find_get(const char *name) static const struct kobj_type elv_ktype; struct elevator_queue *elevator_alloc(struct request_queue *q, - struct elevator_type *e, struct elevator_tags *et) + struct elevator_type *e, struct elevator_resources *res) { struct elevator_queue *eq; @@ -134,7 +134,8 @@ struct elevator_queue *elevator_alloc(struct request_queue *q, kobject_init(&eq->kobj, &elv_ktype); mutex_init(&eq->sysfs_lock); hash_init(eq->hash); - eq->et = et; + eq->et = res->et; + eq->elevator_data = res->data; return eq; } @@ -617,7 +618,7 @@ static void elv_exit_and_release(struct elv_change_ctx *ctx, mutex_unlock(&q->elevator_lock); blk_mq_unfreeze_queue(q, memflags); if (e) { - blk_mq_free_sched_res(&ctx->res, q->tag_set); + blk_mq_free_sched_res(&ctx->res, ctx->type, q->tag_set); kobject_put(&e->kobj); } } @@ -628,12 +629,15 @@ static int elevator_change_done(struct request_queue *q, int ret = 0; if (ctx->old) { - struct elevator_resources res = {.et = ctx->old->et}; + struct elevator_resources res = { + .et = ctx->old->et, + .data = ctx->old->elevator_data + }; bool enable_wbt = test_bit(ELEVATOR_FLAG_ENABLE_WBT_ON_EXIT, &ctx->old->flags); elv_unregister_queue(q, ctx->old); - blk_mq_free_sched_res(&res, q->tag_set); + blk_mq_free_sched_res(&res, ctx->old->type, q->tag_set); kobject_put(&ctx->old->kobj); if (enable_wbt) wbt_enable_default(q->disk); @@ -658,7 +662,8 @@ static int elevator_change(struct request_queue *q, struct elv_change_ctx *ctx) lockdep_assert_held(&set->update_nr_hwq_lock); if (strncmp(ctx->name, "none", 4)) { - ret = blk_mq_alloc_sched_res(q, &ctx->res, set->nr_hw_queues); + ret = blk_mq_alloc_sched_res(q, ctx->type, &ctx->res, + set->nr_hw_queues); if (ret) return ret; } @@ -681,11 +686,12 @@ static int elevator_change(struct request_queue *q, struct elv_change_ctx *ctx) blk_mq_unfreeze_queue(q, memflags); if (!ret) ret = elevator_change_done(q, ctx); + /* * Free sched resource if it's allocated but we couldn't switch elevator. */ if (!ctx->new) - blk_mq_free_sched_res(&ctx->res, set); + blk_mq_free_sched_res(&ctx->res, ctx->type, set); return ret; } @@ -711,11 +717,12 @@ void elv_update_nr_hw_queues(struct request_queue *q, blk_mq_unfreeze_queue_nomemrestore(q); if (!ret) WARN_ON_ONCE(elevator_change_done(q, ctx)); + /* * Free sched resource if it's allocated but we couldn't switch elevator. */ if (!ctx->new) - blk_mq_free_sched_res(&ctx->res, set); + blk_mq_free_sched_res(&ctx->res, ctx->type, set); } /* @@ -729,7 +736,6 @@ void elevator_set_default(struct request_queue *q) .no_uevent = true, }; int err; - struct elevator_type *e; /* now we allow to switch elevator */ blk_queue_flag_clear(QUEUE_FLAG_NO_ELV_SWITCH, q); @@ -742,8 +748,8 @@ void elevator_set_default(struct request_queue *q) * have multiple queues or mq-deadline is not available, default * to "none". */ - e = elevator_find_get(ctx.name); - if (!e) + ctx.type = elevator_find_get(ctx.name); + if (!ctx.type) return; if ((q->nr_hw_queues == 1 || @@ -753,7 +759,7 @@ void elevator_set_default(struct request_queue *q) pr_warn("\"%s\" elevator initialization, failed %d, falling back to \"none\"\n", ctx.name, err); } - elevator_put(e); + elevator_put(ctx.type); } void elevator_set_none(struct request_queue *q) @@ -802,6 +808,7 @@ ssize_t elv_iosched_store(struct gendisk *disk, const char *buf, ctx.name = strstrip(elevator_name); elv_iosched_load_module(ctx.name); + ctx.type = elevator_find_get(ctx.name); down_read(&set->update_nr_hwq_lock); if (!blk_queue_no_elv_switch(q)) { @@ -812,6 +819,9 @@ ssize_t elv_iosched_store(struct gendisk *disk, const char *buf, ret = -ENOENT; } up_read(&set->update_nr_hwq_lock); + + if (ctx.type) + elevator_put(ctx.type); return ret; } diff --git a/block/elevator.h b/block/elevator.h index e34043f6da26e..3ee1d494f48af 100644 --- a/block/elevator.h +++ b/block/elevator.h @@ -33,6 +33,8 @@ struct elevator_tags { }; struct elevator_resources { + /* holds elevator data */ + void *data; /* holds elevator tags */ struct elevator_tags *et; }; @@ -185,7 +187,7 @@ ssize_t elv_iosched_store(struct gendisk *disk, const char *page, size_t count); extern bool elv_bio_merge_ok(struct request *, struct bio *); struct elevator_queue *elevator_alloc(struct request_queue *, - struct elevator_type *, struct elevator_tags *); + struct elevator_type *, struct elevator_resources *); /* * Helper functions. From f55201fb3becff6a903fd29f4d1147cc7e91eb0c Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Fri, 12 Dec 2025 22:35:00 +0800 Subject: [PATCH 1116/2333] block: fix race between wbt_enable_default and IO submission [ Upstream commit 9869d3a6fed381f3b98404e26e1afc75d680cbf9 ] When wbt_enable_default() is moved out of queue freezing in elevator_change(), it can cause the wbt inflight counter to become negative (-1), leading to hung tasks in the writeback path. Tasks get stuck in wbt_wait() because the counter is in an inconsistent state. The issue occurs because wbt_enable_default() could race with IO submission, allowing the counter to be decremented before proper initialization. This manifests as: rq_wait[0]: inflight: -1 has_waiters: True rwb_enabled() checks the state, which can be updated exactly between wbt_wait() (rq_qos_throttle()) and wbt_track()(rq_qos_track()), then the inflight counter will become negative. And results in hung task warnings like: task:kworker/u24:39 state:D stack:0 pid:14767 Call Trace: rq_qos_wait+0xb4/0x150 wbt_wait+0xa9/0x100 __rq_qos_throttle+0x24/0x40 blk_mq_submit_bio+0x672/0x7b0 ... Fix this by: 1. Splitting wbt_enable_default() into: - __wbt_enable_default(): Returns true if wbt_init() should be called - wbt_enable_default(): Wrapper for existing callers (no init) - wbt_init_enable_default(): New function that checks and inits WBT 2. Using wbt_init_enable_default() in blk_register_queue() to ensure proper initialization during queue registration 3. Move wbt_init() out of wbt_enable_default() which is only for enabling disabled wbt from bfq and iocost, and wbt_init() isn't needed. Then the original lock warning can be avoided. 4. Removing the ELEVATOR_FLAG_ENABLE_WBT_ON_EXIT flag and its handling code since it's no longer needed This ensures WBT is properly initialized before any IO can be submitted, preventing the counter from going negative. Cc: Nilay Shroff Cc: Yu Kuai Cc: Guangwu Zhang Fixes: 78c271344b6f ("block: move wbt_enable_default() out of queue freezing from sched ->exit()") Signed-off-by: Ming Lei Reviewed-by: Nilay Shroff Signed-off-by: Jens Axboe Signed-off-by: Sasha Levin --- block/bfq-iosched.c | 2 +- block/blk-sysfs.c | 2 +- block/blk-wbt.c | 20 ++++++++++++++++---- block/blk-wbt.h | 5 +++++ block/elevator.c | 4 ---- block/elevator.h | 1 - 6 files changed, 23 insertions(+), 11 deletions(-) diff --git a/block/bfq-iosched.c b/block/bfq-iosched.c index 4a8d3d96bfe49..6e54b1d3d8bc2 100644 --- a/block/bfq-iosched.c +++ b/block/bfq-iosched.c @@ -7181,7 +7181,7 @@ static void bfq_exit_queue(struct elevator_queue *e) blk_stat_disable_accounting(bfqd->queue); blk_queue_flag_clear(QUEUE_FLAG_DISABLE_WBT_DEF, bfqd->queue); - set_bit(ELEVATOR_FLAG_ENABLE_WBT_ON_EXIT, &e->flags); + wbt_enable_default(bfqd->queue->disk); kfree(bfqd); } diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c index 76c47fe9b8d68..c0e4daaf96100 100644 --- a/block/blk-sysfs.c +++ b/block/blk-sysfs.c @@ -942,7 +942,7 @@ int blk_register_queue(struct gendisk *disk) elevator_set_default(q); blk_queue_flag_set(QUEUE_FLAG_REGISTERED, q); - wbt_enable_default(disk); + wbt_init_enable_default(disk); /* Now everything is ready and send out KOBJ_ADD uevent */ kobject_uevent(&disk->queue_kobj, KOBJ_ADD); diff --git a/block/blk-wbt.c b/block/blk-wbt.c index eb8037bae0bda..0974875f77bda 100644 --- a/block/blk-wbt.c +++ b/block/blk-wbt.c @@ -699,7 +699,7 @@ static void wbt_requeue(struct rq_qos *rqos, struct request *rq) /* * Enable wbt if defaults are configured that way */ -void wbt_enable_default(struct gendisk *disk) +static bool __wbt_enable_default(struct gendisk *disk) { struct request_queue *q = disk->queue; struct rq_qos *rqos; @@ -716,19 +716,31 @@ void wbt_enable_default(struct gendisk *disk) if (enable && RQWB(rqos)->enable_state == WBT_STATE_OFF_DEFAULT) RQWB(rqos)->enable_state = WBT_STATE_ON_DEFAULT; mutex_unlock(&disk->rqos_state_mutex); - return; + return false; } mutex_unlock(&disk->rqos_state_mutex); /* Queue not registered? Maybe shutting down... */ if (!blk_queue_registered(q)) - return; + return false; if (queue_is_mq(q) && enable) - wbt_init(disk); + return true; + return false; +} + +void wbt_enable_default(struct gendisk *disk) +{ + __wbt_enable_default(disk); } EXPORT_SYMBOL_GPL(wbt_enable_default); +void wbt_init_enable_default(struct gendisk *disk) +{ + if (__wbt_enable_default(disk)) + WARN_ON_ONCE(wbt_init(disk)); +} + u64 wbt_default_latency_nsec(struct request_queue *q) { /* diff --git a/block/blk-wbt.h b/block/blk-wbt.h index e5fc653b9b76f..925f224757383 100644 --- a/block/blk-wbt.h +++ b/block/blk-wbt.h @@ -5,6 +5,7 @@ #ifdef CONFIG_BLK_WBT int wbt_init(struct gendisk *disk); +void wbt_init_enable_default(struct gendisk *disk); void wbt_disable_default(struct gendisk *disk); void wbt_enable_default(struct gendisk *disk); @@ -16,6 +17,10 @@ u64 wbt_default_latency_nsec(struct request_queue *); #else +static inline void wbt_init_enable_default(struct gendisk *disk) +{ +} + static inline void wbt_disable_default(struct gendisk *disk) { } diff --git a/block/elevator.c b/block/elevator.c index 5b37ef44f52d7..a2f8b2251dc6e 100644 --- a/block/elevator.c +++ b/block/elevator.c @@ -633,14 +633,10 @@ static int elevator_change_done(struct request_queue *q, .et = ctx->old->et, .data = ctx->old->elevator_data }; - bool enable_wbt = test_bit(ELEVATOR_FLAG_ENABLE_WBT_ON_EXIT, - &ctx->old->flags); elv_unregister_queue(q, ctx->old); blk_mq_free_sched_res(&res, ctx->old->type, q->tag_set); kobject_put(&ctx->old->kobj); - if (enable_wbt) - wbt_enable_default(q->disk); } if (ctx->new) { ret = elv_register_queue(q, ctx->new, !ctx->no_uevent); diff --git a/block/elevator.h b/block/elevator.h index 3ee1d494f48af..0217263760423 100644 --- a/block/elevator.h +++ b/block/elevator.h @@ -156,7 +156,6 @@ struct elevator_queue #define ELEVATOR_FLAG_REGISTERED 0 #define ELEVATOR_FLAG_DYING 1 -#define ELEVATOR_FLAG_ENABLE_WBT_ON_EXIT 2 /* * block elevator interface From c062e2785bbea7aebc1f8dbe82d9b63afdb7872a Mon Sep 17 00:00:00 2001 From: Prajna Rajendra Kumar Date: Fri, 14 Nov 2025 10:45:43 +0000 Subject: [PATCH 1117/2333] spi: microchip: rename driver file and internal identifiers [ Upstream commit 71c814e98696f2cd53e9e6cef7501c2d667d4c5a ] The spi-microchip-core.c driver provides support for the Microchip PolarFire SoC (MPFS) "hard" SPI controller. It was originally named "core" with the expectation that it might also cover Microchip's CoreSPI "soft" IP, but that never materialized. The CoreSPI IP cannot be supported by this driver because its register layout differs substantially from the MPFS SPI controller. In practice most of the code would need to be replaced to handle those differences so keeping the drivers separate is the simpler approach. The file and internal symbols are renamed to reflect MPFS support and to free up "spi-microchip-core.c" for CoreSPI driver. Fixes: 9ac8d17694b6 ("spi: add support for microchip fpga spi controllers") Signed-off-by: Prajna Rajendra Kumar Acked-by: Conor Dooley Link: https://patch.msgid.link/20251114104545.284765-2-prajna.rajendrakumar@microchip.com Signed-off-by: Mark Brown Stable-dep-of: a8a313612af7 ("spi: mpfs: Fix an error handling path in mpfs_spi_probe()") Signed-off-by: Sasha Levin --- drivers/spi/Kconfig | 19 +- drivers/spi/Makefile | 2 +- .../spi/{spi-microchip-core.c => spi-mpfs.c} | 207 +++++++++--------- 3 files changed, 115 insertions(+), 113 deletions(-) rename drivers/spi/{spi-microchip-core.c => spi-mpfs.c} (68%) diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 55675750182e3..1872f9d54a5cc 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -706,15 +706,6 @@ config SPI_MESON_SPIFC This enables master mode support for the SPIFC (SPI flash controller) available in Amlogic Meson SoCs. -config SPI_MICROCHIP_CORE - tristate "Microchip FPGA SPI controllers" - depends on SPI_MASTER - help - This enables the SPI driver for Microchip FPGA SPI controllers. - Say Y or M here if you want to use the "hard" controllers on - PolarFire SoC. - If built as a module, it will be called spi-microchip-core. - config SPI_MICROCHIP_CORE_QSPI tristate "Microchip FPGA QSPI controllers" depends on SPI_MASTER @@ -871,6 +862,16 @@ config SPI_PL022 controller. If you have an embedded system with an AMBA(R) bus and a PL022 controller, say Y or M here. +config SPI_POLARFIRE_SOC + + tristate "Microchip FPGA SPI controllers" + depends on SPI_MASTER && ARCH_MICROCHIP + help + This enables the SPI driver for Microchip FPGA SPI controllers. + Say Y or M here if you want to use the "hard" controllers on + PolarFire SoC. + If built as a module, it will be called spi-mpfs. + config SPI_PPC4xx tristate "PPC4xx SPI Controller" depends on PPC32 && 4xx diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 8ff74a13faaa8..1f7c06a3091d9 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -86,7 +86,6 @@ obj-$(CONFIG_SPI_LOONGSON_PLATFORM) += spi-loongson-plat.o obj-$(CONFIG_SPI_LP8841_RTC) += spi-lp8841-rtc.o obj-$(CONFIG_SPI_MESON_SPICC) += spi-meson-spicc.o obj-$(CONFIG_SPI_MESON_SPIFC) += spi-meson-spifc.o -obj-$(CONFIG_SPI_MICROCHIP_CORE) += spi-microchip-core.o obj-$(CONFIG_SPI_MICROCHIP_CORE_QSPI) += spi-microchip-core-qspi.o obj-$(CONFIG_SPI_MPC512x_PSC) += spi-mpc512x-psc.o obj-$(CONFIG_SPI_MPC52xx_PSC) += spi-mpc52xx-psc.o @@ -97,6 +96,7 @@ obj-$(CONFIG_SPI_MTK_NOR) += spi-mtk-nor.o obj-$(CONFIG_SPI_MTK_SNFI) += spi-mtk-snfi.o obj-$(CONFIG_SPI_MXIC) += spi-mxic.o obj-$(CONFIG_SPI_MXS) += spi-mxs.o +obj-$(CONFIG_SPI_POLARFIRE_SOC) += spi-mpfs.o obj-$(CONFIG_SPI_WPCM_FIU) += spi-wpcm-fiu.o obj-$(CONFIG_SPI_NPCM_FIU) += spi-npcm-fiu.o obj-$(CONFIG_SPI_NPCM_PSPI) += spi-npcm-pspi.o diff --git a/drivers/spi/spi-microchip-core.c b/drivers/spi/spi-mpfs.c similarity index 68% rename from drivers/spi/spi-microchip-core.c rename to drivers/spi/spi-mpfs.c index 9128b86c53660..9a14d1732a159 100644 --- a/drivers/spi/spi-microchip-core.c +++ b/drivers/spi/spi-mpfs.c @@ -99,7 +99,7 @@ #define REG_CTRL2 (0x48) #define REG_FRAMESUP (0x50) -struct mchp_corespi { +struct mpfs_spi { void __iomem *regs; struct clk *clk; const u8 *tx_buf; @@ -113,34 +113,34 @@ struct mchp_corespi { int n_bytes; }; -static inline u32 mchp_corespi_read(struct mchp_corespi *spi, unsigned int reg) +static inline u32 mpfs_spi_read(struct mpfs_spi *spi, unsigned int reg) { return readl(spi->regs + reg); } -static inline void mchp_corespi_write(struct mchp_corespi *spi, unsigned int reg, u32 val) +static inline void mpfs_spi_write(struct mpfs_spi *spi, unsigned int reg, u32 val) { writel(val, spi->regs + reg); } -static inline void mchp_corespi_disable(struct mchp_corespi *spi) +static inline void mpfs_spi_disable(struct mpfs_spi *spi) { - u32 control = mchp_corespi_read(spi, REG_CONTROL); + u32 control = mpfs_spi_read(spi, REG_CONTROL); control &= ~CONTROL_ENABLE; - mchp_corespi_write(spi, REG_CONTROL, control); + mpfs_spi_write(spi, REG_CONTROL, control); } -static inline void mchp_corespi_read_fifo(struct mchp_corespi *spi, int fifo_max) +static inline void mpfs_spi_read_fifo(struct mpfs_spi *spi, int fifo_max) { for (int i = 0; i < fifo_max; i++) { u32 data; - while (mchp_corespi_read(spi, REG_STATUS) & STATUS_RXFIFO_EMPTY) + while (mpfs_spi_read(spi, REG_STATUS) & STATUS_RXFIFO_EMPTY) ; - data = mchp_corespi_read(spi, REG_RX_DATA); + data = mpfs_spi_read(spi, REG_RX_DATA); spi->rx_len -= spi->n_bytes; @@ -158,34 +158,34 @@ static inline void mchp_corespi_read_fifo(struct mchp_corespi *spi, int fifo_max } } -static void mchp_corespi_enable_ints(struct mchp_corespi *spi) +static void mpfs_spi_enable_ints(struct mpfs_spi *spi) { - u32 control = mchp_corespi_read(spi, REG_CONTROL); + u32 control = mpfs_spi_read(spi, REG_CONTROL); control |= INT_ENABLE_MASK; - mchp_corespi_write(spi, REG_CONTROL, control); + mpfs_spi_write(spi, REG_CONTROL, control); } -static void mchp_corespi_disable_ints(struct mchp_corespi *spi) +static void mpfs_spi_disable_ints(struct mpfs_spi *spi) { - u32 control = mchp_corespi_read(spi, REG_CONTROL); + u32 control = mpfs_spi_read(spi, REG_CONTROL); control &= ~INT_ENABLE_MASK; - mchp_corespi_write(spi, REG_CONTROL, control); + mpfs_spi_write(spi, REG_CONTROL, control); } -static inline void mchp_corespi_set_xfer_size(struct mchp_corespi *spi, int len) +static inline void mpfs_spi_set_xfer_size(struct mpfs_spi *spi, int len) { u32 control; u32 lenpart; - u32 frames = mchp_corespi_read(spi, REG_FRAMESUP); + u32 frames = mpfs_spi_read(spi, REG_FRAMESUP); /* * Writing to FRAMECNT in REG_CONTROL will reset the frame count, taking * a shortcut requires an explicit clear. */ if (frames == len) { - mchp_corespi_write(spi, REG_COMMAND, COMMAND_CLRFRAMECNT); + mpfs_spi_write(spi, REG_COMMAND, COMMAND_CLRFRAMECNT); return; } @@ -208,20 +208,20 @@ static inline void mchp_corespi_set_xfer_size(struct mchp_corespi *spi, int len) * that matches the documentation. */ lenpart = len & 0xffff; - control = mchp_corespi_read(spi, REG_CONTROL); + control = mpfs_spi_read(spi, REG_CONTROL); control &= ~CONTROL_FRAMECNT_MASK; control |= lenpart << CONTROL_FRAMECNT_SHIFT; - mchp_corespi_write(spi, REG_CONTROL, control); - mchp_corespi_write(spi, REG_FRAMESUP, len); + mpfs_spi_write(spi, REG_CONTROL, control); + mpfs_spi_write(spi, REG_FRAMESUP, len); } -static inline void mchp_corespi_write_fifo(struct mchp_corespi *spi, int fifo_max) +static inline void mpfs_spi_write_fifo(struct mpfs_spi *spi, int fifo_max) { int i = 0; - mchp_corespi_set_xfer_size(spi, fifo_max); + mpfs_spi_set_xfer_size(spi, fifo_max); - while ((i < fifo_max) && !(mchp_corespi_read(spi, REG_STATUS) & STATUS_TXFIFO_FULL)) { + while ((i < fifo_max) && !(mpfs_spi_read(spi, REG_STATUS) & STATUS_TXFIFO_FULL)) { u32 word; if (spi->n_bytes == 4) @@ -231,7 +231,7 @@ static inline void mchp_corespi_write_fifo(struct mchp_corespi *spi, int fifo_ma else word = spi->tx_buf ? *spi->tx_buf : 0xaa; - mchp_corespi_write(spi, REG_TX_DATA, word); + mpfs_spi_write(spi, REG_TX_DATA, word); if (spi->tx_buf) spi->tx_buf += spi->n_bytes; i++; @@ -240,9 +240,9 @@ static inline void mchp_corespi_write_fifo(struct mchp_corespi *spi, int fifo_ma spi->tx_len -= i * spi->n_bytes; } -static inline void mchp_corespi_set_framesize(struct mchp_corespi *spi, int bt) +static inline void mpfs_spi_set_framesize(struct mpfs_spi *spi, int bt) { - u32 frame_size = mchp_corespi_read(spi, REG_FRAME_SIZE); + u32 frame_size = mpfs_spi_read(spi, REG_FRAME_SIZE); u32 control; if ((frame_size & FRAME_SIZE_MASK) == bt) @@ -252,25 +252,25 @@ static inline void mchp_corespi_set_framesize(struct mchp_corespi *spi, int bt) * Disable the SPI controller. Writes to the frame size have * no effect when the controller is enabled. */ - control = mchp_corespi_read(spi, REG_CONTROL); + control = mpfs_spi_read(spi, REG_CONTROL); control &= ~CONTROL_ENABLE; - mchp_corespi_write(spi, REG_CONTROL, control); + mpfs_spi_write(spi, REG_CONTROL, control); - mchp_corespi_write(spi, REG_FRAME_SIZE, bt); + mpfs_spi_write(spi, REG_FRAME_SIZE, bt); control |= CONTROL_ENABLE; - mchp_corespi_write(spi, REG_CONTROL, control); + mpfs_spi_write(spi, REG_CONTROL, control); } -static void mchp_corespi_set_cs(struct spi_device *spi, bool disable) +static void mpfs_spi_set_cs(struct spi_device *spi, bool disable) { u32 reg; - struct mchp_corespi *corespi = spi_controller_get_devdata(spi->controller); + struct mpfs_spi *mspi = spi_controller_get_devdata(spi->controller); - reg = mchp_corespi_read(corespi, REG_SLAVE_SELECT); + reg = mpfs_spi_read(mspi, REG_SLAVE_SELECT); reg &= ~BIT(spi_get_chipselect(spi, 0)); reg |= !disable << spi_get_chipselect(spi, 0); - corespi->pending_slave_select = reg; + mspi->pending_slave_select = reg; /* * Only deassert chip select immediately. Writing to some registers @@ -281,12 +281,12 @@ static void mchp_corespi_set_cs(struct spi_device *spi, bool disable) * doesn't see any spurious clock transitions whilst CS is enabled. */ if (((spi->mode & SPI_CS_HIGH) == 0) == disable) - mchp_corespi_write(corespi, REG_SLAVE_SELECT, reg); + mpfs_spi_write(mspi, REG_SLAVE_SELECT, reg); } -static int mchp_corespi_setup(struct spi_device *spi) +static int mpfs_spi_setup(struct spi_device *spi) { - struct mchp_corespi *corespi = spi_controller_get_devdata(spi->controller); + struct mpfs_spi *mspi = spi_controller_get_devdata(spi->controller); u32 reg; if (spi_is_csgpiod(spi)) @@ -298,21 +298,21 @@ static int mchp_corespi_setup(struct spi_device *spi) * driving their select line low. */ if (spi->mode & SPI_CS_HIGH) { - reg = mchp_corespi_read(corespi, REG_SLAVE_SELECT); + reg = mpfs_spi_read(mspi, REG_SLAVE_SELECT); reg |= BIT(spi_get_chipselect(spi, 0)); - corespi->pending_slave_select = reg; - mchp_corespi_write(corespi, REG_SLAVE_SELECT, reg); + mspi->pending_slave_select = reg; + mpfs_spi_write(mspi, REG_SLAVE_SELECT, reg); } return 0; } -static void mchp_corespi_init(struct spi_controller *host, struct mchp_corespi *spi) +static void mpfs_spi_init(struct spi_controller *host, struct mpfs_spi *spi) { unsigned long clk_hz; - u32 control = mchp_corespi_read(spi, REG_CONTROL); + u32 control = mpfs_spi_read(spi, REG_CONTROL); control &= ~CONTROL_ENABLE; - mchp_corespi_write(spi, REG_CONTROL, control); + mpfs_spi_write(spi, REG_CONTROL, control); control |= CONTROL_MASTER; control &= ~CONTROL_MODE_MASK; @@ -328,15 +328,15 @@ static void mchp_corespi_init(struct spi_controller *host, struct mchp_corespi * */ control |= CONTROL_SPS | CONTROL_BIGFIFO; - mchp_corespi_write(spi, REG_CONTROL, control); + mpfs_spi_write(spi, REG_CONTROL, control); - mchp_corespi_set_framesize(spi, DEFAULT_FRAMESIZE); + mpfs_spi_set_framesize(spi, DEFAULT_FRAMESIZE); /* max. possible spi clock rate is the apb clock rate */ clk_hz = clk_get_rate(spi->clk); host->max_speed_hz = clk_hz; - mchp_corespi_enable_ints(spi); + mpfs_spi_enable_ints(spi); /* * It is required to enable direct mode, otherwise control over the chip @@ -344,34 +344,34 @@ static void mchp_corespi_init(struct spi_controller *host, struct mchp_corespi * * can deal with active high targets. */ spi->pending_slave_select = SSELOUT | SSEL_DIRECT; - mchp_corespi_write(spi, REG_SLAVE_SELECT, spi->pending_slave_select); + mpfs_spi_write(spi, REG_SLAVE_SELECT, spi->pending_slave_select); - control = mchp_corespi_read(spi, REG_CONTROL); + control = mpfs_spi_read(spi, REG_CONTROL); control &= ~CONTROL_RESET; control |= CONTROL_ENABLE; - mchp_corespi_write(spi, REG_CONTROL, control); + mpfs_spi_write(spi, REG_CONTROL, control); } -static inline void mchp_corespi_set_clk_gen(struct mchp_corespi *spi) +static inline void mpfs_spi_set_clk_gen(struct mpfs_spi *spi) { u32 control; - control = mchp_corespi_read(spi, REG_CONTROL); + control = mpfs_spi_read(spi, REG_CONTROL); if (spi->clk_mode) control |= CONTROL_CLKMODE; else control &= ~CONTROL_CLKMODE; - mchp_corespi_write(spi, REG_CLK_GEN, spi->clk_gen); - mchp_corespi_write(spi, REG_CONTROL, control); + mpfs_spi_write(spi, REG_CLK_GEN, spi->clk_gen); + mpfs_spi_write(spi, REG_CONTROL, control); } -static inline void mchp_corespi_set_mode(struct mchp_corespi *spi, unsigned int mode) +static inline void mpfs_spi_set_mode(struct mpfs_spi *spi, unsigned int mode) { u32 mode_val; - u32 control = mchp_corespi_read(spi, REG_CONTROL); + u32 control = mpfs_spi_read(spi, REG_CONTROL); switch (mode & SPI_MODE_X_MASK) { case SPI_MODE_0: @@ -394,22 +394,22 @@ static inline void mchp_corespi_set_mode(struct mchp_corespi *spi, unsigned int */ control &= ~CONTROL_ENABLE; - mchp_corespi_write(spi, REG_CONTROL, control); + mpfs_spi_write(spi, REG_CONTROL, control); control &= ~(SPI_MODE_X_MASK << MODE_X_MASK_SHIFT); control |= mode_val; - mchp_corespi_write(spi, REG_CONTROL, control); + mpfs_spi_write(spi, REG_CONTROL, control); control |= CONTROL_ENABLE; - mchp_corespi_write(spi, REG_CONTROL, control); + mpfs_spi_write(spi, REG_CONTROL, control); } -static irqreturn_t mchp_corespi_interrupt(int irq, void *dev_id) +static irqreturn_t mpfs_spi_interrupt(int irq, void *dev_id) { struct spi_controller *host = dev_id; - struct mchp_corespi *spi = spi_controller_get_devdata(host); - u32 intfield = mchp_corespi_read(spi, REG_MIS) & 0xf; + struct mpfs_spi *spi = spi_controller_get_devdata(host); + u32 intfield = mpfs_spi_read(spi, REG_MIS) & 0xf; bool finalise = false; /* Interrupt line may be shared and not for us at all */ @@ -417,7 +417,7 @@ static irqreturn_t mchp_corespi_interrupt(int irq, void *dev_id) return IRQ_NONE; if (intfield & INT_RX_CHANNEL_OVERFLOW) { - mchp_corespi_write(spi, REG_INT_CLEAR, INT_RX_CHANNEL_OVERFLOW); + mpfs_spi_write(spi, REG_INT_CLEAR, INT_RX_CHANNEL_OVERFLOW); finalise = true; dev_err(&host->dev, "%s: RX OVERFLOW: rxlen: %d, txlen: %d\n", __func__, @@ -425,7 +425,7 @@ static irqreturn_t mchp_corespi_interrupt(int irq, void *dev_id) } if (intfield & INT_TX_CHANNEL_UNDERRUN) { - mchp_corespi_write(spi, REG_INT_CLEAR, INT_TX_CHANNEL_UNDERRUN); + mpfs_spi_write(spi, REG_INT_CLEAR, INT_TX_CHANNEL_UNDERRUN); finalise = true; dev_err(&host->dev, "%s: TX UNDERFLOW: rxlen: %d, txlen: %d\n", __func__, @@ -438,8 +438,8 @@ static irqreturn_t mchp_corespi_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -static int mchp_corespi_calculate_clkgen(struct mchp_corespi *spi, - unsigned long target_hz) +static int mpfs_spi_calculate_clkgen(struct mpfs_spi *spi, + unsigned long target_hz) { unsigned long clk_hz, spi_hz, clk_gen; @@ -475,20 +475,20 @@ static int mchp_corespi_calculate_clkgen(struct mchp_corespi *spi, return 0; } -static int mchp_corespi_transfer_one(struct spi_controller *host, - struct spi_device *spi_dev, - struct spi_transfer *xfer) +static int mpfs_spi_transfer_one(struct spi_controller *host, + struct spi_device *spi_dev, + struct spi_transfer *xfer) { - struct mchp_corespi *spi = spi_controller_get_devdata(host); + struct mpfs_spi *spi = spi_controller_get_devdata(host); int ret; - ret = mchp_corespi_calculate_clkgen(spi, (unsigned long)xfer->speed_hz); + ret = mpfs_spi_calculate_clkgen(spi, (unsigned long)xfer->speed_hz); if (ret) { dev_err(&host->dev, "failed to set clk_gen for target %u Hz\n", xfer->speed_hz); return ret; } - mchp_corespi_set_clk_gen(spi); + mpfs_spi_set_clk_gen(spi); spi->tx_buf = xfer->tx_buf; spi->rx_buf = xfer->rx_buf; @@ -496,45 +496,46 @@ static int mchp_corespi_transfer_one(struct spi_controller *host, spi->rx_len = xfer->len; spi->n_bytes = roundup_pow_of_two(DIV_ROUND_UP(xfer->bits_per_word, BITS_PER_BYTE)); - mchp_corespi_set_framesize(spi, xfer->bits_per_word); + mpfs_spi_set_framesize(spi, xfer->bits_per_word); - mchp_corespi_write(spi, REG_COMMAND, COMMAND_RXFIFORST | COMMAND_TXFIFORST); + mpfs_spi_write(spi, REG_COMMAND, COMMAND_RXFIFORST | COMMAND_TXFIFORST); - mchp_corespi_write(spi, REG_SLAVE_SELECT, spi->pending_slave_select); + mpfs_spi_write(spi, REG_SLAVE_SELECT, spi->pending_slave_select); while (spi->tx_len) { int fifo_max = DIV_ROUND_UP(min(spi->tx_len, FIFO_DEPTH), spi->n_bytes); - mchp_corespi_write_fifo(spi, fifo_max); - mchp_corespi_read_fifo(spi, fifo_max); + mpfs_spi_write_fifo(spi, fifo_max); + mpfs_spi_read_fifo(spi, fifo_max); } spi_finalize_current_transfer(host); return 1; } -static int mchp_corespi_prepare_message(struct spi_controller *host, - struct spi_message *msg) +static int mpfs_spi_prepare_message(struct spi_controller *host, + struct spi_message *msg) { struct spi_device *spi_dev = msg->spi; - struct mchp_corespi *spi = spi_controller_get_devdata(host); + struct mpfs_spi *spi = spi_controller_get_devdata(host); - mchp_corespi_set_mode(spi, spi_dev->mode); + mpfs_spi_set_mode(spi, spi_dev->mode); return 0; } -static int mchp_corespi_probe(struct platform_device *pdev) +static int mpfs_spi_probe(struct platform_device *pdev) { struct spi_controller *host; - struct mchp_corespi *spi; + struct mpfs_spi *spi; struct resource *res; u32 num_cs; int ret = 0; host = devm_spi_alloc_host(&pdev->dev, sizeof(*spi)); if (!host) - return -ENOMEM; + return dev_err_probe(&pdev->dev, -ENOMEM, + "unable to allocate host for SPI controller\n"); platform_set_drvdata(pdev, host); @@ -544,11 +545,11 @@ static int mchp_corespi_probe(struct platform_device *pdev) host->num_chipselect = num_cs; host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; host->use_gpio_descriptors = true; - host->setup = mchp_corespi_setup; + host->setup = mpfs_spi_setup; host->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32); - host->transfer_one = mchp_corespi_transfer_one; - host->prepare_message = mchp_corespi_prepare_message; - host->set_cs = mchp_corespi_set_cs; + host->transfer_one = mpfs_spi_transfer_one; + host->prepare_message = mpfs_spi_prepare_message; + host->set_cs = mpfs_spi_set_cs; host->dev.of_node = pdev->dev.of_node; spi = spi_controller_get_devdata(host); @@ -561,7 +562,7 @@ static int mchp_corespi_probe(struct platform_device *pdev) if (spi->irq < 0) return spi->irq; - ret = devm_request_irq(&pdev->dev, spi->irq, mchp_corespi_interrupt, + ret = devm_request_irq(&pdev->dev, spi->irq, mpfs_spi_interrupt, IRQF_SHARED, dev_name(&pdev->dev), host); if (ret) return dev_err_probe(&pdev->dev, ret, @@ -572,11 +573,11 @@ static int mchp_corespi_probe(struct platform_device *pdev) return dev_err_probe(&pdev->dev, PTR_ERR(spi->clk), "could not get clk\n"); - mchp_corespi_init(host, spi); + mpfs_spi_init(host, spi); ret = devm_spi_register_controller(&pdev->dev, host); if (ret) { - mchp_corespi_disable(spi); + mpfs_spi_disable(spi); return dev_err_probe(&pdev->dev, ret, "unable to register host for SPI controller\n"); } @@ -586,13 +587,13 @@ static int mchp_corespi_probe(struct platform_device *pdev) return 0; } -static void mchp_corespi_remove(struct platform_device *pdev) +static void mpfs_spi_remove(struct platform_device *pdev) { struct spi_controller *host = platform_get_drvdata(pdev); - struct mchp_corespi *spi = spi_controller_get_devdata(host); + struct mpfs_spi *spi = spi_controller_get_devdata(host); - mchp_corespi_disable_ints(spi); - mchp_corespi_disable(spi); + mpfs_spi_disable_ints(spi); + mpfs_spi_disable(spi); } #define MICROCHIP_SPI_PM_OPS (NULL) @@ -602,23 +603,23 @@ static void mchp_corespi_remove(struct platform_device *pdev) */ #if defined(CONFIG_OF) -static const struct of_device_id mchp_corespi_dt_ids[] = { +static const struct of_device_id mpfs_spi_dt_ids[] = { { .compatible = "microchip,mpfs-spi" }, { /* sentinel */ } }; -MODULE_DEVICE_TABLE(of, mchp_corespi_dt_ids); +MODULE_DEVICE_TABLE(of, mpfs_spi_dt_ids); #endif -static struct platform_driver mchp_corespi_driver = { - .probe = mchp_corespi_probe, +static struct platform_driver mpfs_spi_driver = { + .probe = mpfs_spi_probe, .driver = { - .name = "microchip-corespi", + .name = "microchip-spi", .pm = MICROCHIP_SPI_PM_OPS, - .of_match_table = of_match_ptr(mchp_corespi_dt_ids), + .of_match_table = of_match_ptr(mpfs_spi_dt_ids), }, - .remove = mchp_corespi_remove, + .remove = mpfs_spi_remove, }; -module_platform_driver(mchp_corespi_driver); +module_platform_driver(mpfs_spi_driver); MODULE_DESCRIPTION("Microchip coreSPI SPI controller driver"); MODULE_AUTHOR("Daire McNamara "); MODULE_AUTHOR("Conor Dooley "); From 5e4481ef397ea22b9d4fedb2fdef7865ece9fabe Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 13 Dec 2025 08:48:51 +0100 Subject: [PATCH 1118/2333] spi: mpfs: Fix an error handling path in mpfs_spi_probe() [ Upstream commit a8a313612af7a55083ba5720f14f1835319debee ] mpfs_spi_init() calls mpfs_spi_enable_ints(), so mpfs_spi_disable_ints() should be called if an error occurs after calling mpfs_spi_init(), as already done in the remove function. Fixes: 9ac8d17694b6 ("spi: add support for microchip fpga spi controllers") Signed-off-by: Christophe JAILLET Link: https://patch.msgid.link/eb35f168517cc402ef7e78f26da02863e2f45c03.1765612110.git.christophe.jaillet@wanadoo.fr Signed-off-by: Mark Brown Signed-off-by: Sasha Levin --- drivers/spi/spi-mpfs.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/spi/spi-mpfs.c b/drivers/spi/spi-mpfs.c index 9a14d1732a159..7e9e64d8e6c81 100644 --- a/drivers/spi/spi-mpfs.c +++ b/drivers/spi/spi-mpfs.c @@ -577,6 +577,7 @@ static int mpfs_spi_probe(struct platform_device *pdev) ret = devm_spi_register_controller(&pdev->dev, host); if (ret) { + mpfs_spi_disable_ints(spi); mpfs_spi_disable(spi); return dev_err_probe(&pdev->dev, ret, "unable to register host for SPI controller\n"); From e52b375b7dae7999107e54ea92c70dc3cc12533f Mon Sep 17 00:00:00 2001 From: Denis Sergeev Date: Tue, 9 Dec 2025 09:37:06 +0300 Subject: [PATCH 1119/2333] hwmon: (dell-smm) Limit fan multiplier to avoid overflow [ Upstream commit 46c28bbbb150b80827e4bcbea231560af9d16854 ] The fan nominal speed returned by SMM is limited to 16 bits, but the driver allows the fan multiplier to be set via a module parameter. Clamp the computed fan multiplier so that fan_nominal_speed * i8k_fan_mult always fits into a signed 32-bit integer and refuse to initialize the driver if the value is too large. Found by Linux Verification Center (linuxtesting.org) with SVACE. Fixes: 20bdeebc88269 ("hwmon: (dell-smm) Introduce helper function for data init") Signed-off-by: Denis Sergeev Link: https://lore.kernel.org/r/20251209063706.49008-1-denserg.edu@gmail.com Signed-off-by: Guenter Roeck Signed-off-by: Sasha Levin --- drivers/hwmon/dell-smm-hwmon.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/hwmon/dell-smm-hwmon.c b/drivers/hwmon/dell-smm-hwmon.c index cbe1a74a3deea..f0e8a9bc0d0e0 100644 --- a/drivers/hwmon/dell-smm-hwmon.c +++ b/drivers/hwmon/dell-smm-hwmon.c @@ -76,6 +76,9 @@ #define DELL_SMM_NO_TEMP 10 #define DELL_SMM_NO_FANS 4 +/* limit fan multiplier to avoid overflow */ +#define DELL_SMM_MAX_FAN_MULT (INT_MAX / U16_MAX) + struct smm_regs { unsigned int eax; unsigned int ebx; @@ -1253,6 +1256,12 @@ static int dell_smm_init_data(struct device *dev, const struct dell_smm_ops *ops data->ops = ops; /* All options must not be 0 */ data->i8k_fan_mult = fan_mult ? : I8K_FAN_MULT; + if (data->i8k_fan_mult > DELL_SMM_MAX_FAN_MULT) { + dev_err(dev, + "fan multiplier %u is too large (max %u)\n", + data->i8k_fan_mult, DELL_SMM_MAX_FAN_MULT); + return -EINVAL; + } data->i8k_fan_max = fan_max ? : I8K_FAN_HIGH; data->i8k_pwm_mult = DIV_ROUND_UP(255, data->i8k_fan_max); From 5aa2139201667c1f644601e4529c4acd6bf8db5a Mon Sep 17 00:00:00 2001 From: Junrui Luo Date: Wed, 10 Dec 2025 17:48:08 +0800 Subject: [PATCH 1120/2333] hwmon: (ibmpex) fix use-after-free in high/low store [ Upstream commit 6946c726c3f4c36f0f049e6f97e88c510b15f65d ] The ibmpex_high_low_store() function retrieves driver data using dev_get_drvdata() and uses it without validation. This creates a race condition where the sysfs callback can be invoked after the data structure is freed, leading to use-after-free. Fix by adding a NULL check after dev_get_drvdata(), and reordering operations in the deletion path to prevent TOCTOU. Reported-by: Yuhao Jiang Reported-by: Junrui Luo Fixes: 57c7c3a0fdea ("hwmon: IBM power meter driver") Signed-off-by: Junrui Luo Link: https://lore.kernel.org/r/MEYPR01MB7886BE2F51BFE41875B74B60AFA0A@MEYPR01MB7886.ausprd01.prod.outlook.com Signed-off-by: Guenter Roeck Signed-off-by: Sasha Levin --- drivers/hwmon/ibmpex.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/hwmon/ibmpex.c b/drivers/hwmon/ibmpex.c index 228c5f6c6f383..129f3a9e8fe96 100644 --- a/drivers/hwmon/ibmpex.c +++ b/drivers/hwmon/ibmpex.c @@ -277,6 +277,9 @@ static ssize_t ibmpex_high_low_store(struct device *dev, { struct ibmpex_bmc_data *data = dev_get_drvdata(dev); + if (!data) + return -ENODEV; + ibmpex_reset_high_low_data(data); return count; @@ -508,6 +511,9 @@ static void ibmpex_bmc_delete(struct ibmpex_bmc_data *data) { int i, j; + hwmon_device_unregister(data->hwmon_dev); + dev_set_drvdata(data->bmc_device, NULL); + device_remove_file(data->bmc_device, &sensor_dev_attr_reset_high_low.dev_attr); device_remove_file(data->bmc_device, &dev_attr_name.attr); @@ -521,8 +527,7 @@ static void ibmpex_bmc_delete(struct ibmpex_bmc_data *data) } list_del(&data->list); - dev_set_drvdata(data->bmc_device, NULL); - hwmon_device_unregister(data->hwmon_dev); + ipmi_destroy_user(data->user); kfree(data->sensors); kfree(data); From ea62d22f577248f2145b006f73445b26143618f1 Mon Sep 17 00:00:00 2001 From: Alexey Simakov Date: Thu, 11 Dec 2025 19:43:43 +0300 Subject: [PATCH 1121/2333] hwmon: (tmp401) fix overflow caused by default conversion rate value [ Upstream commit 82f2aab35a1ab2e1460de06ef04c726460aed51c ] The driver computes conversion intervals using the formula: interval = (1 << (7 - rate)) * 125ms where 'rate' is the sensor's conversion rate register value. According to the datasheet, the power-on reset value of this register is 0x8, which could be assigned to the register, after handling i2c general call. Using this default value causes a result greater than the bit width of left operand and an undefined behaviour in the calculation above, since shifting by values larger than the bit width is undefined behaviour as per C language standard. Limit the maximum usable 'rate' value to 7 to prevent undefined behaviour in calculations. Found by Linux Verification Center (linuxtesting.org) with Svace. Note (groeck): This does not matter in practice unless someone overwrites the chip configuration from outside the driver while the driver is loaded. The conversion time register is initialized with a value of 5 (500ms) when the driver is loaded, and the driver never writes a bad value. Fixes: ca53e7640de7 ("hwmon: (tmp401) Convert to _info API") Signed-off-by: Alexey Simakov Link: https://lore.kernel.org/r/20251211164342.6291-1-bigalex934@gmail.com Signed-off-by: Guenter Roeck Signed-off-by: Sasha Levin --- drivers/hwmon/tmp401.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hwmon/tmp401.c b/drivers/hwmon/tmp401.c index 02c5a3bb1071c..84aaf817144cf 100644 --- a/drivers/hwmon/tmp401.c +++ b/drivers/hwmon/tmp401.c @@ -401,7 +401,7 @@ static int tmp401_chip_read(struct device *dev, u32 attr, int channel, long *val ret = regmap_read(data->regmap, TMP401_CONVERSION_RATE, ®val); if (ret < 0) return ret; - *val = (1 << (7 - regval)) * 125; + *val = (1 << (7 - min(regval, 7))) * 125; break; case hwmon_chip_temp_reset_history: *val = 0; From f6ec2d5c21b14966c396cc2d55a5d883e84fd6b5 Mon Sep 17 00:00:00 2001 From: Shuicheng Lin Date: Fri, 14 Nov 2025 20:56:39 +0000 Subject: [PATCH 1122/2333] drm/xe: Fix freq kobject leak on sysfs_create_files failure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit b32045d73bb4333a2cebc5d3c005807adb03ab58 ] Ensure gt->freq is released when sysfs_create_files() fails in xe_gt_freq_init(). Without this, the kobject would leak. Add kobject_put() before returning the error. Fixes: fdc81c43f0c1 ("drm/xe: use devm_add_action_or_reset() helper") Signed-off-by: Shuicheng Lin Reviewed-by: Alex Zuo Reviewed-by: Xin Wang Link: https://patch.msgid.link/20251114205638.2184529-2-shuicheng.lin@intel.com Signed-off-by: Matt Roper (cherry picked from commit 251be5fb4982ebb0f5a81b62d975bd770f3ad5c2) Signed-off-by: Thomas Hellström Signed-off-by: Sasha Levin --- drivers/gpu/drm/xe/xe_gt_freq.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/xe/xe_gt_freq.c b/drivers/gpu/drm/xe/xe_gt_freq.c index 4ff1b6b58d6be..e8e70fd2e8c42 100644 --- a/drivers/gpu/drm/xe/xe_gt_freq.c +++ b/drivers/gpu/drm/xe/xe_gt_freq.c @@ -296,8 +296,10 @@ int xe_gt_freq_init(struct xe_gt *gt) return -ENOMEM; err = sysfs_create_files(gt->freq, freq_attrs); - if (err) + if (err) { + kobject_put(gt->freq); return err; + } err = devm_add_action_or_reset(xe->drm.dev, freq_fini, gt->freq); if (err) From 3a3612dc705513498471187787314db57b2ab1df Mon Sep 17 00:00:00 2001 From: Vinay Belgaumkar Date: Fri, 28 Nov 2025 21:25:48 -0800 Subject: [PATCH 1123/2333] drm/xe: Apply Wa_14020316580 in xe_gt_idle_enable_pg() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit c88a0731ed95f9705deb127a7f1927fa59aa742b ] Wa_14020316580 was getting clobbered by power gating init code later in the driver load sequence. Move the Wa so that it applies correctly. Fixes: 7cd05ef89c9d ("drm/xe/xe2hpm: Add initial set of workarounds") Suggested-by: Matt Roper Signed-off-by: Vinay Belgaumkar Reviewed-by: Riana Tauro Reviewed-by: Matt Roper Link: https://patch.msgid.link/20251129052548.70766-1-vinay.belgaumkar@intel.com Signed-off-by: Matt Roper (cherry picked from commit 8b5502145351bde87f522df082b9e41356898ba3) Signed-off-by: Thomas Hellström Signed-off-by: Sasha Levin --- drivers/gpu/drm/xe/xe_gt_idle.c | 8 ++++++++ drivers/gpu/drm/xe/xe_wa.c | 8 -------- drivers/gpu/drm/xe/xe_wa_oob.rules | 1 + 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_gt_idle.c b/drivers/gpu/drm/xe/xe_gt_idle.c index bdc9d9877ec49..3e3d1d52f6302 100644 --- a/drivers/gpu/drm/xe/xe_gt_idle.c +++ b/drivers/gpu/drm/xe/xe_gt_idle.c @@ -5,6 +5,7 @@ #include +#include #include "xe_force_wake.h" #include "xe_device.h" #include "xe_gt.h" @@ -16,6 +17,7 @@ #include "xe_mmio.h" #include "xe_pm.h" #include "xe_sriov.h" +#include "xe_wa.h" /** * DOC: Xe GT Idle @@ -145,6 +147,12 @@ void xe_gt_idle_enable_pg(struct xe_gt *gt) xe_mmio_write32(mmio, RENDER_POWERGATE_IDLE_HYSTERESIS, 25); } + if (XE_GT_WA(gt, 14020316580)) + gtidle->powergate_enable &= ~(VDN_HCP_POWERGATE_ENABLE(0) | + VDN_MFXVDENC_POWERGATE_ENABLE(0) | + VDN_HCP_POWERGATE_ENABLE(2) | + VDN_MFXVDENC_POWERGATE_ENABLE(2)); + xe_mmio_write32(mmio, POWERGATE_ENABLE, gtidle->powergate_enable); xe_force_wake_put(gt_to_fw(gt), fw_ref); } diff --git a/drivers/gpu/drm/xe/xe_wa.c b/drivers/gpu/drm/xe/xe_wa.c index 3cf30718b2003..d209434fd7fc2 100644 --- a/drivers/gpu/drm/xe/xe_wa.c +++ b/drivers/gpu/drm/xe/xe_wa.c @@ -270,14 +270,6 @@ static const struct xe_rtp_entry_sr gt_was[] = { XE_RTP_ACTIONS(SET(VDBOX_CGCTL3F1C(0), MFXPIPE_CLKGATE_DIS)), XE_RTP_ENTRY_FLAG(FOREACH_ENGINE), }, - { XE_RTP_NAME("14020316580"), - XE_RTP_RULES(MEDIA_VERSION(1301)), - XE_RTP_ACTIONS(CLR(POWERGATE_ENABLE, - VDN_HCP_POWERGATE_ENABLE(0) | - VDN_MFXVDENC_POWERGATE_ENABLE(0) | - VDN_HCP_POWERGATE_ENABLE(2) | - VDN_MFXVDENC_POWERGATE_ENABLE(2))), - }, { XE_RTP_NAME("14019449301"), XE_RTP_RULES(MEDIA_VERSION(1301), ENGINE_CLASS(VIDEO_DECODE)), XE_RTP_ACTIONS(SET(VDBOX_CGCTL3F08(0), CG3DDISHRS_CLKGATE_DIS)), diff --git a/drivers/gpu/drm/xe/xe_wa_oob.rules b/drivers/gpu/drm/xe/xe_wa_oob.rules index f3a6d5d239cec..1d32fa1c3b2d7 100644 --- a/drivers/gpu/drm/xe/xe_wa_oob.rules +++ b/drivers/gpu/drm/xe/xe_wa_oob.rules @@ -81,3 +81,4 @@ 15015404425_disable PLATFORM(PANTHERLAKE), MEDIA_STEP(B0, FOREVER) 16026007364 MEDIA_VERSION(3000) +14020316580 MEDIA_VERSION(1301) From 754b10c067f0faf0302ef30b176bcb4b479dd361 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 4 Dec 2025 10:46:58 +0100 Subject: [PATCH 1124/2333] drm/xe: fix drm_gpusvm_init() arguments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 9acc3295813b9b846791fd3eab0a78a3144af560 ] The Xe driver fails to build when CONFIG_DRM_XE_GPUSVM is disabled but CONFIG_DRM_GPUSVM is turned on, due to the clash of two commits: In file included from drivers/gpu/drm/xe/xe_vm_madvise.c:8: drivers/gpu/drm/xe/xe_svm.h: In function 'xe_svm_init': include/linux/stddef.h:8:14: error: passing argument 5 of 'drm_gpusvm_init' makes integer from pointer without a cast [-Wint-conversion] drivers/gpu/drm/xe/xe_svm.h:217:38: note: in expansion of macro 'NULL' 217 | NULL, NULL, 0, 0, 0, NULL, NULL, 0); | ^~~~ In file included from drivers/gpu/drm/xe/xe_bo_types.h:11, from drivers/gpu/drm/xe/xe_bo.h:11, from drivers/gpu/drm/xe/xe_vm_madvise.c:11: include/drm/drm_gpusvm.h:254:35: note: expected 'long unsigned int' but argument is of type 'void *' 254 | unsigned long mm_start, unsigned long mm_range, | ~~~~~~~~~~~~~~^~~~~~~~ In file included from drivers/gpu/drm/xe/xe_vm_madvise.c:14: drivers/gpu/drm/xe/xe_svm.h:216:16: error: too many arguments to function 'drm_gpusvm_init'; expected 10, have 11 216 | return drm_gpusvm_init(&vm->svm.gpusvm, "Xe SVM (simple)", &vm->xe->drm, | ^~~~~~~~~~~~~~~ 217 | NULL, NULL, 0, 0, 0, NULL, NULL, 0); | ~ include/drm/drm_gpusvm.h:251:5: note: declared here Adapt the caller to the new argument list by removing the extraneous NULL argument. Fixes: 9e9787414882 ("drm/xe/userptr: replace xe_hmm with gpusvm") Fixes: 10aa5c806030 ("drm/gpusvm, drm/xe: Fix userptr to not allow device private pages") Signed-off-by: Arnd Bergmann Reviewed-by: Thomas Hellström Signed-off-by: Thomas Hellström Link: https://patch.msgid.link/20251204094704.1030933-1-arnd@kernel.org (cherry picked from commit 29bce9c8b41d5c378263a927acb9a9074d0e7a0e) Signed-off-by: Thomas Hellström Signed-off-by: Sasha Levin --- drivers/gpu/drm/xe/xe_svm.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/xe/xe_svm.h b/drivers/gpu/drm/xe/xe_svm.h index 0955d2ac8d744..fa757dd07954d 100644 --- a/drivers/gpu/drm/xe/xe_svm.h +++ b/drivers/gpu/drm/xe/xe_svm.h @@ -214,7 +214,7 @@ int xe_svm_init(struct xe_vm *vm) { #if IS_ENABLED(CONFIG_DRM_GPUSVM) return drm_gpusvm_init(&vm->svm.gpusvm, "Xe SVM (simple)", &vm->xe->drm, - NULL, NULL, 0, 0, 0, NULL, NULL, 0); + NULL, 0, 0, 0, NULL, NULL, 0); #else return 0; #endif From f72c9ecd4b258d0fdd8205eba294afdf9f8ec668 Mon Sep 17 00:00:00 2001 From: Junxiao Chang Date: Fri, 7 Nov 2025 11:31:52 +0800 Subject: [PATCH 1125/2333] drm/me/gsc: mei interrupt top half should be in irq disabled context MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 17445af7dcc7d645b6fb8951fd10c8b72cc7f23f ] MEI GSC interrupt comes from i915 or xe driver. It has top half and bottom half. Top half is called from i915/xe interrupt handler. It should be in irq disabled context. With RT kernel(PREEMPT_RT enabled), by default IRQ handler is in threaded IRQ. MEI GSC top half might be in threaded IRQ context. generic_handle_irq_safe API could be called from either IRQ or process context, it disables local IRQ then calls MEI GSC interrupt top half. This change fixes B580 GPU boot issue with RT enabled. Fixes: e02cea83d32d ("drm/xe/gsc: add Battlemage support") Tested-by: Baoli Zhang Signed-off-by: Junxiao Chang Reviewed-by: Sebastian Andrzej Siewior Reviewed-by: Matthew Brost Link: https://patch.msgid.link/20251107033152.834960-1-junxiao.chang@intel.com Signed-off-by: Maarten Lankhorst (cherry picked from commit 3efadf028783a49ab2941294187c8b6dd86bf7da) Signed-off-by: Thomas Hellström Signed-off-by: Sasha Levin --- drivers/gpu/drm/xe/xe_heci_gsc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_heci_gsc.c b/drivers/gpu/drm/xe/xe_heci_gsc.c index a415ca4887914..32d509b113915 100644 --- a/drivers/gpu/drm/xe/xe_heci_gsc.c +++ b/drivers/gpu/drm/xe/xe_heci_gsc.c @@ -221,7 +221,7 @@ void xe_heci_gsc_irq_handler(struct xe_device *xe, u32 iir) if (xe->heci_gsc.irq < 0) return; - ret = generic_handle_irq(xe->heci_gsc.irq); + ret = generic_handle_irq_safe(xe->heci_gsc.irq); if (ret) drm_err_ratelimited(&xe->drm, "error handling GSC irq: %d\n", ret); } @@ -241,7 +241,7 @@ void xe_heci_csc_irq_handler(struct xe_device *xe, u32 iir) if (xe->heci_gsc.irq < 0) return; - ret = generic_handle_irq(xe->heci_gsc.irq); + ret = generic_handle_irq_safe(xe->heci_gsc.irq); if (ret) drm_err_ratelimited(&xe->drm, "error handling GSC irq: %d\n", ret); } From 4c8a881044e1a5b501a5cf47af768992e065a4c2 Mon Sep 17 00:00:00 2001 From: Jagmeet Randhawa Date: Fri, 12 Dec 2025 05:21:46 +0800 Subject: [PATCH 1126/2333] drm/xe: Increase TDF timeout MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit eafb6f62093f756535a7be1fc4559374a511e460 ] There are some corner cases where flushing transient data may take slightly longer than the 150us timeout we currently allow. Update the driver to use a 300us timeout instead based on the latest guidance from the hardware team. An update to the bspec to formally document this is expected to arrive soon. Fixes: c01c6066e6fa ("drm/xe/device: implement transient flush") Signed-off-by: Jagmeet Randhawa Reviewed-by: Jonathan Cavitt Reviewed-by: Matt Roper Link: https://patch.msgid.link/0201b1d6ec64d3651fcbff1ea21026efa915126a.1765487866.git.jagmeet.randhawa@intel.com Signed-off-by: Matt Roper (cherry picked from commit d69d3636f5f7a84bae7cd43473b3701ad9b7d544) Signed-off-by: Thomas Hellström Signed-off-by: Sasha Levin --- drivers/gpu/drm/xe/xe_device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c index 456899238377e..5f757790d6f53 100644 --- a/drivers/gpu/drm/xe/xe_device.c +++ b/drivers/gpu/drm/xe/xe_device.c @@ -1046,7 +1046,7 @@ static void tdf_request_sync(struct xe_device *xe) * transient and need to be flushed.. */ if (xe_mmio_wait32(>->mmio, XE2_TDF_CTRL, TRANSIENT_FLUSH_REQUEST, 0, - 150, NULL, false)) + 300, NULL, false)) xe_gt_err_once(gt, "TD flush timeout\n"); xe_force_wake_put(gt_to_fw(gt), fw_ref); From 63cc97bd85e38257e58e9601d727a7d4632b7a3b Mon Sep 17 00:00:00 2001 From: Jan Maslak Date: Wed, 10 Dec 2025 15:56:18 +0100 Subject: [PATCH 1127/2333] drm/xe: Restore engine registers before restarting schedulers after GT reset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit eed5b815fa49c17d513202f54e980eb91955d3ed ] During GT reset recovery in do_gt_restart(), xe_uc_start() was called before xe_reg_sr_apply_mmio() restored engine-specific registers. This created a race window where the scheduler could run jobs before hardware state was fully restored. This caused failures in eudebug tests (xe_exec_sip_eudebug@breakpoint- waitsip-*) where TD_CTL register (containing TD_CTL_GLOBAL_DEBUG_ENABLE) wasn't restored before jobs started executing. Breakpoints would fail to trigger SIP entry because the debug enable bit wasn't set yet. Fix by moving xe_uc_start() after all MMIO register restoration, including engine registers and CCS mode configuration, ensuring all hardware state is fully restored before any jobs can be scheduled. Fixes: dd08ebf6c352 ("drm/xe: Introduce a new DRM driver for Intel GPUs") Signed-off-by: Jan Maslak Reviewed-by: Jonathan Cavitt Reviewed-by: Matthew Brost Signed-off-by: Matthew Brost Link: https://patch.msgid.link/20251210145618.169625-2-jan.maslak@intel.com (cherry picked from commit 825aed0328588b2837636c1c5a0c48795d724617) Signed-off-by: Thomas Hellström Signed-off-by: Sasha Levin --- drivers/gpu/drm/xe/xe_gt.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_gt.c b/drivers/gpu/drm/xe/xe_gt.c index 6d3db5e55d98a..61bed3b04dedd 100644 --- a/drivers/gpu/drm/xe/xe_gt.c +++ b/drivers/gpu/drm/xe/xe_gt.c @@ -784,9 +784,6 @@ static int do_gt_restart(struct xe_gt *gt) xe_gt_sriov_pf_init_hw(gt); xe_mocs_init(gt); - err = xe_uc_start(>->uc); - if (err) - return err; for_each_hw_engine(hwe, gt, id) xe_reg_sr_apply_mmio(&hwe->reg_sr, gt); @@ -794,6 +791,10 @@ static int do_gt_restart(struct xe_gt *gt) /* Get CCS mode in sync between sw/hw */ xe_gt_apply_ccs_mode(gt); + err = xe_uc_start(>->uc); + if (err) + return err; + /* Restore GT freq to expected values */ xe_gt_sanitize_freq(gt); From 548e158dbf5786635357429556d01e7938712f71 Mon Sep 17 00:00:00 2001 From: Haoxiang Li Date: Thu, 4 Dec 2025 18:36:18 +0800 Subject: [PATCH 1128/2333] MIPS: Fix a reference leak bug in ip22_check_gio() [ Upstream commit 680ad315caaa2860df411cb378bf3614d96c7648 ] If gio_device_register fails, gio_dev_put() is required to drop the gio_dev device reference. Fixes: e84de0c61905 ("MIPS: GIO bus support for SGI IP22/28") Signed-off-by: Haoxiang Li Signed-off-by: Thomas Bogendoerfer Signed-off-by: Sasha Levin --- arch/mips/sgi-ip22/ip22-gio.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/mips/sgi-ip22/ip22-gio.c b/arch/mips/sgi-ip22/ip22-gio.c index 5893ea4e382ca..19b70928d6dc3 100644 --- a/arch/mips/sgi-ip22/ip22-gio.c +++ b/arch/mips/sgi-ip22/ip22-gio.c @@ -372,7 +372,8 @@ static void ip22_check_gio(int slotno, unsigned long addr, int irq) gio_dev->resource.flags = IORESOURCE_MEM; gio_dev->irq = irq; dev_set_name(&gio_dev->dev, "%d", slotno); - gio_device_register(gio_dev); + if (gio_device_register(gio_dev)) + gio_dev_put(gio_dev); } else printk(KERN_INFO "GIO: slot %d : Empty\n", slotno); } From 09fe52c728e098e47eecd683e770c5e5deb71388 Mon Sep 17 00:00:00 2001 From: Marijn Suijten Date: Sun, 30 Nov 2025 23:40:05 +0100 Subject: [PATCH 1129/2333] drm/panel: sony-td4353-jdi: Enable prepare_prev_first [ Upstream commit 2b973ca48ff3ef1952091c8f988d7796781836c8 ] The DSI host must be enabled before our prepare function can run, which has to send its init sequence over DSI. Without enabling the host first the panel will not probe. Fixes: 9e15123eca79 ("drm/msm/dsi: Stop unconditionally powering up DSI hosts at modeset") Signed-off-by: Marijn Suijten Reviewed-by: Douglas Anderson Reviewed-by: AngeloGioacchino Del Regno Reviewed-by: Martin Botka Signed-off-by: Douglas Anderson Link: https://patch.msgid.link/20251130-sony-akari-fix-panel-v1-1-1d27c60a55f5@somainline.org Signed-off-by: Sasha Levin --- drivers/gpu/drm/panel/panel-sony-td4353-jdi.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/panel/panel-sony-td4353-jdi.c b/drivers/gpu/drm/panel/panel-sony-td4353-jdi.c index 7c989b70ab513..a14c86c60d19d 100644 --- a/drivers/gpu/drm/panel/panel-sony-td4353-jdi.c +++ b/drivers/gpu/drm/panel/panel-sony-td4353-jdi.c @@ -212,6 +212,8 @@ static int sony_td4353_jdi_probe(struct mipi_dsi_device *dsi) if (ret) return dev_err_probe(dev, ret, "Failed to get backlight\n"); + ctx->panel.prepare_prev_first = true; + drm_panel_add(&ctx->panel); ret = mipi_dsi_attach(dsi); From 0901f5fe2a01ed93be105bea58bcb5d4ab5ecee6 Mon Sep 17 00:00:00 2001 From: Juergen Gross Date: Mon, 15 Dec 2025 12:51:12 +0100 Subject: [PATCH 1130/2333] x86/xen: Fix sparse warning in enlighten_pv.c [ Upstream commit e5aff444e3a7bdeef5ea796a2099fc3c60a070fa ] The sparse tool issues a warning for arch/x76/xen/enlighten_pv.c: arch/x86/xen/enlighten_pv.c:120:9: sparse: sparse: incorrect type in initializer (different address spaces) expected void const [noderef] __percpu *__vpp_verify got bool * This is due to the percpu variable xen_in_preemptible_hcall being exported via EXPORT_SYMBOL_GPL() instead of EXPORT_PER_CPU_SYMBOL_GPL(). Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202512140856.Ic6FetG6-lkp@intel.com/ Fixes: fdfd811ddde3 ("x86/xen: allow privcmd hypercalls to be preempted") Reviewed-by: Boris Ostrovsky Signed-off-by: Juergen Gross Message-ID: <20251215115112.15072-1-jgross@suse.com> Signed-off-by: Sasha Levin --- arch/x86/xen/enlighten_pv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/xen/enlighten_pv.c b/arch/x86/xen/enlighten_pv.c index 4806cc28d7ca7..b74ff8bc7f2a8 100644 --- a/arch/x86/xen/enlighten_pv.c +++ b/arch/x86/xen/enlighten_pv.c @@ -108,7 +108,7 @@ static int xen_cpu_dead_pv(unsigned int cpu); * calls. */ DEFINE_PER_CPU(bool, xen_in_preemptible_hcall); -EXPORT_SYMBOL_GPL(xen_in_preemptible_hcall); +EXPORT_PER_CPU_SYMBOL_GPL(xen_in_preemptible_hcall); /* * In case of scheduling the flag must be cleared and restored after From f51cc7aeb3d0ac3ea4fd08c83e0a9d807507c1b1 Mon Sep 17 00:00:00 2001 From: Jianpeng Chang Date: Fri, 5 Dec 2025 09:59:34 +0800 Subject: [PATCH 1131/2333] arm64: kdump: Fix elfcorehdr overlap caused by reserved memory processing reorder [ Upstream commit 3e8ade58b71b48913d21b647b2089e03e81f117e ] Commit 8a6e02d0c00e ("of: reserved_mem: Restructure how the reserved memory regions are processed") changed the processing order of reserved memory regions, causing elfcorehdr to overlap with dynamically allocated reserved memory regions during kdump kernel boot. The issue occurs because: 1. kexec-tools allocates elfcorehdr in the last crashkernel reserved memory region and passes it to the second kernel 2. The problematic commit moved dynamic reserved memory allocation (like bman-fbpr) to occur during fdt_scan_reserved_mem(), before elfcorehdr reservation in fdt_reserve_elfcorehdr() 3. bman-fbpr with 16MB alignment requirement can get allocated at addresses that overlap with the elfcorehdr location 4. When fdt_reserve_elfcorehdr() tries to reserve elfcorehdr memory, overlap detection identifies the conflict and skips reservation 5. kdump kernel fails with "Unable to handle kernel paging request" because elfcorehdr memory is not properly reserved The boot log: Before 8a6e02d0c00e: OF: fdt: Reserving 1 KiB of memory at 0xf4fff000 for elfcorehdr OF: reserved mem: 0xf3000000..0xf3ffffff bman-fbpr After 8a6e02d0c00e: OF: reserved mem: 0xf4000000..0xf4ffffff bman-fbpr OF: fdt: elfcorehdr is overlapped Fix this by ensuring elfcorehdr reservation occurs before dynamic reserved memory allocation. Fixes: 8a6e02d0c00e ("of: reserved_mem: Restructure how the reserved memory regions are processed") Signed-off-by: Jianpeng Chang Link: https://patch.msgid.link/20251205015934.700016-1-jianpeng.chang.cn@windriver.com Signed-off-by: Rob Herring (Arm) Signed-off-by: Sasha Levin --- drivers/of/fdt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index fdaee4906836f..3851ce2445858 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -503,8 +503,8 @@ void __init early_init_fdt_scan_reserved_mem(void) if (!initial_boot_params) return; - fdt_scan_reserved_mem(); fdt_reserve_elfcorehdr(); + fdt_scan_reserved_mem(); /* Process header /memreserve/ fields */ for (n = 0; ; n++) { From dac58c012c47cadf337a35eb05d44498c43e5cd0 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 10 Dec 2025 11:02:30 -0500 Subject: [PATCH 1132/2333] drm/amdgpu: fix a job->pasid access race in gpu recovery MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 77f73253015cbc7893fca1821ac3eae9eb4bc943 ] Avoid a possible UAF in GPU recovery due to a race between the sched timeout callback and the tdr work queue. The gpu recovery function calls drm_sched_stop() and later drm_sched_start(). drm_sched_start() restarts the tdr queue which will eventually free the job. If the tdr queue frees the job before time out callback completes, the job will be freed and we'll get a UAF when accessing the pasid. Cache it early to avoid the UAF. Example KASAN trace: [ 493.058141] BUG: KASAN: slab-use-after-free in amdgpu_device_gpu_recover+0x968/0x990 [amdgpu] [ 493.067530] Read of size 4 at addr ffff88b0ce3f794c by task kworker/u128:1/323 [ 493.074892] [ 493.076485] CPU: 9 UID: 0 PID: 323 Comm: kworker/u128:1 Tainted: G E 6.16.0-1289896.2.zuul.bf4f11df81c1410bbe901c4373305a31 #1 PREEMPT(voluntary) [ 493.076493] Tainted: [E]=UNSIGNED_MODULE [ 493.076495] Hardware name: TYAN B8021G88V2HR-2T/S8021GM2NR-2T, BIOS V1.03.B10 04/01/2019 [ 493.076500] Workqueue: amdgpu-reset-dev drm_sched_job_timedout [gpu_sched] [ 493.076512] Call Trace: [ 493.076515] [ 493.076518] dump_stack_lvl+0x64/0x80 [ 493.076529] print_report+0xce/0x630 [ 493.076536] ? _raw_spin_lock_irqsave+0x86/0xd0 [ 493.076541] ? __pfx__raw_spin_lock_irqsave+0x10/0x10 [ 493.076545] ? amdgpu_device_gpu_recover+0x968/0x990 [amdgpu] [ 493.077253] kasan_report+0xb8/0xf0 [ 493.077258] ? amdgpu_device_gpu_recover+0x968/0x990 [amdgpu] [ 493.077965] amdgpu_device_gpu_recover+0x968/0x990 [amdgpu] [ 493.078672] ? __pfx_amdgpu_device_gpu_recover+0x10/0x10 [amdgpu] [ 493.079378] ? amdgpu_coredump+0x1fd/0x4c0 [amdgpu] [ 493.080111] amdgpu_job_timedout+0x642/0x1400 [amdgpu] [ 493.080903] ? pick_task_fair+0x24e/0x330 [ 493.080910] ? __pfx_amdgpu_job_timedout+0x10/0x10 [amdgpu] [ 493.081702] ? _raw_spin_lock+0x75/0xc0 [ 493.081708] ? __pfx__raw_spin_lock+0x10/0x10 [ 493.081712] drm_sched_job_timedout+0x1b0/0x4b0 [gpu_sched] [ 493.081721] ? __pfx__raw_spin_lock_irq+0x10/0x10 [ 493.081725] process_one_work+0x679/0xff0 [ 493.081732] worker_thread+0x6ce/0xfd0 [ 493.081736] ? __pfx_worker_thread+0x10/0x10 [ 493.081739] kthread+0x376/0x730 [ 493.081744] ? __pfx_kthread+0x10/0x10 [ 493.081748] ? __pfx__raw_spin_lock_irq+0x10/0x10 [ 493.081751] ? __pfx_kthread+0x10/0x10 [ 493.081755] ret_from_fork+0x247/0x330 [ 493.081761] ? __pfx_kthread+0x10/0x10 [ 493.081764] ret_from_fork_asm+0x1a/0x30 [ 493.081771] Fixes: a72002cb181f ("drm/amdgpu: Make use of drm_wedge_task_info") Link: https://github.com/HansKristian-Work/vkd3d-proton/pull/2670 Cc: SRINIVASAN.SHANMUGAM@amd.com Cc: vitaly.prosyak@amd.com Cc: christian.koenig@amd.com Suggested-by: Matthew Brost Reviewed-by: Srinivasan Shanmugam Reviewed-by: Lijo Lazar Reviewed-by: Christian König Signed-off-by: Alex Deucher (cherry picked from commit 20880a3fd5dd7bca1a079534cf6596bda92e107d) Signed-off-by: Sasha Levin --- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index 96b6738e62526..843770e61e421 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -6476,6 +6476,8 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev, struct amdgpu_hive_info *hive = NULL; int r = 0; bool need_emergency_restart = false; + /* save the pasid here as the job may be freed before the end of the reset */ + int pasid = job ? job->pasid : -EINVAL; /* * If it reaches here because of hang/timeout and a RAS error is @@ -6572,8 +6574,12 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev, if (!r) { struct amdgpu_task_info *ti = NULL; - if (job) - ti = amdgpu_vm_get_task_info_pasid(adev, job->pasid); + /* + * The job may already be freed at this point via the sched tdr workqueue so + * use the cached pasid. + */ + if (pasid >= 0) + ti = amdgpu_vm_get_task_info_pasid(adev, pasid); drm_dev_wedged_event(adev_to_drm(adev), DRM_WEDGE_RECOVERY_NONE, ti ? &ti->task : NULL); From 0ab22a1796e04de6a30bde28727ab885d313a16c Mon Sep 17 00:00:00 2001 From: Anurag Dutta Date: Fri, 12 Dec 2025 12:53:12 +0530 Subject: [PATCH 1133/2333] spi: cadence-quadspi: Fix clock disable on probe failure path [ Upstream commit 1889dd2081975ce1f6275b06cdebaa8d154847a9 ] When cqspi_request_mmap_dma() returns -EPROBE_DEFER after runtime PM is enabled, the error path calls clk_disable_unprepare() on an already disabled clock, causing an imbalance. Use pm_runtime_get_sync() to increment the usage counter and resume the device. This prevents runtime_suspend() from being invoked and causing a double clock disable. Fixes: 140623410536 ("mtd: spi-nor: Add driver for Cadence Quad SPI Flash Controller") Signed-off-by: Anurag Dutta Tested-by: Nishanth Menon Link: https://patch.msgid.link/20251212072312.2711806-3-a-dutta@ti.com Signed-off-by: Mark Brown Signed-off-by: Sasha Levin --- drivers/spi/spi-cadence-quadspi.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi-cadence-quadspi.c b/drivers/spi/spi-cadence-quadspi.c index af6d050da1c8a..3231bdaf9bd06 100644 --- a/drivers/spi/spi-cadence-quadspi.c +++ b/drivers/spi/spi-cadence-quadspi.c @@ -2024,7 +2024,9 @@ static int cqspi_probe(struct platform_device *pdev) probe_reset_failed: if (cqspi->is_jh7110) cqspi_jh7110_disable_clk(pdev, cqspi); - clk_disable_unprepare(cqspi->clk); + + if (pm_runtime_get_sync(&pdev->dev) >= 0) + clk_disable_unprepare(cqspi->clk); probe_clk_failed: return ret; } From a4315e409ab0ad8eabca1fc338b9c157c09245d3 Mon Sep 17 00:00:00 2001 From: huang-jl Date: Wed, 17 Dec 2025 14:26:32 +0800 Subject: [PATCH 1134/2333] io_uring: fix nr_segs calculation in io_import_kbuf [ Upstream commit 114ea9bbaf7681c4d363e13b7916e6fef6a4963a ] io_import_kbuf() calculates nr_segs incorrectly when iov_offset is non-zero after iov_iter_advance(). It doesn't account for the partial consumption of the first bvec. The problem comes when meet the following conditions: 1. Use UBLK_F_AUTO_BUF_REG feature of ublk. 2. The kernel will help to register the buffer, into the io uring. 3. Later, the ublk server try to send IO request using the registered buffer in the io uring, to read/write to fuse-based filesystem, with O_DIRECT. >From a userspace perspective, the ublk server thread is blocked in the kernel, and will see "soft lockup" in the kernel dmesg. When ublk registers a buffer with mixed-size bvecs like [4K]*6 + [12K] and a request partially consumes a bvec, the next request's nr_segs calculation uses bvec->bv_len instead of (bv_len - iov_offset). This causes fuse_get_user_pages() to loop forever because nr_segs indicates fewer pages than actually needed. Specifically, the infinite loop happens at: fuse_get_user_pages() -> iov_iter_extract_pages() -> iov_iter_extract_bvec_pages() Since the nr_segs is miscalculated, the iov_iter_extract_bvec_pages returns when finding that i->nr_segs is zero. Then iov_iter_extract_pages returns zero. However, fuse_get_user_pages does still not get enough data/pages, causing infinite loop. Example: - Bvecs: [4K, 4K, 4K, 4K, 4K, 4K, 12K, ...] - Request 1: 32K at offset 0, uses 6*4K + 8K of the 12K bvec - Request 2: 32K at offset 32K - iov_offset = 8K (8K already consumed from 12K bvec) - Bug: calculates using 12K, not (12K - 8K) = 4K - Result: nr_segs too small, infinite loop in fuse_get_user_pages. Fix by accounting for iov_offset when calculating the first segment's available length. Fixes: b419bed4f0a6 ("io_uring/rsrc: ensure segments counts are correct on kbuf buffers") Signed-off-by: huang-jl Reviewed-by: Ming Lei Signed-off-by: Jens Axboe Signed-off-by: Sasha Levin --- io_uring/rsrc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/io_uring/rsrc.c b/io_uring/rsrc.c index 0010c49924906..5b6b73c6a62bd 100644 --- a/io_uring/rsrc.c +++ b/io_uring/rsrc.c @@ -1057,6 +1057,7 @@ static int io_import_kbuf(int ddir, struct iov_iter *iter, if (count < imu->len) { const struct bio_vec *bvec = iter->bvec; + len += iter->iov_offset; while (len > bvec->bv_len) { len -= bvec->bv_len; bvec++; From 0f6f3cf11bfecb0c5dbf849b12aabff85e525ca8 Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Fri, 21 Nov 2025 09:58:24 +0800 Subject: [PATCH 1135/2333] ublk: add parameter `struct io_uring_cmd *` to ublk_prep_auto_buf_reg() [ Upstream commit 3035b9b46b0611898babc0b96ede65790d3566f7 ] Add parameter `struct io_uring_cmd *` to ublk_prep_auto_buf_reg() and prepare for reusing this helper for the coming UBLK_BATCH_IO feature, which can fetch & commit one batch of io commands via single uring_cmd. Reviewed-by: Caleb Sander Mateos Signed-off-by: Ming Lei Signed-off-by: Jens Axboe Stable-dep-of: c258f5c4502c ("ublk: fix deadlock when reading partition table") Signed-off-by: Sasha Levin --- drivers/block/ublk_drv.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c index 359564c40cb50..599571634b7ac 100644 --- a/drivers/block/ublk_drv.c +++ b/drivers/block/ublk_drv.c @@ -1242,11 +1242,12 @@ ublk_auto_buf_reg_fallback(const struct ublk_queue *ubq, struct ublk_io *io) } static bool ublk_auto_buf_reg(const struct ublk_queue *ubq, struct request *req, - struct ublk_io *io, unsigned int issue_flags) + struct ublk_io *io, struct io_uring_cmd *cmd, + unsigned int issue_flags) { int ret; - ret = io_buffer_register_bvec(io->cmd, req, ublk_io_release, + ret = io_buffer_register_bvec(cmd, req, ublk_io_release, io->buf.index, issue_flags); if (ret) { if (io->buf.flags & UBLK_AUTO_BUF_REG_FALLBACK) { @@ -1258,18 +1259,19 @@ static bool ublk_auto_buf_reg(const struct ublk_queue *ubq, struct request *req, } io->task_registered_buffers = 1; - io->buf_ctx_handle = io_uring_cmd_ctx_handle(io->cmd); + io->buf_ctx_handle = io_uring_cmd_ctx_handle(cmd); io->flags |= UBLK_IO_FLAG_AUTO_BUF_REG; return true; } static bool ublk_prep_auto_buf_reg(struct ublk_queue *ubq, struct request *req, struct ublk_io *io, + struct io_uring_cmd *cmd, unsigned int issue_flags) { ublk_init_req_ref(ubq, io); if (ublk_support_auto_buf_reg(ubq) && ublk_rq_has_data(req)) - return ublk_auto_buf_reg(ubq, req, io, issue_flags); + return ublk_auto_buf_reg(ubq, req, io, cmd, issue_flags); return true; } @@ -1344,7 +1346,7 @@ static void ublk_dispatch_req(struct ublk_queue *ubq, if (!ublk_start_io(ubq, req, io)) return; - if (ublk_prep_auto_buf_reg(ubq, req, io, issue_flags)) + if (ublk_prep_auto_buf_reg(ubq, req, io, io->cmd, issue_flags)) ublk_complete_io_cmd(io, req, UBLK_IO_RES_OK, issue_flags); } From 5907d423400e5fe9774dc52f77fa41073131b093 Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Fri, 21 Nov 2025 09:58:25 +0800 Subject: [PATCH 1136/2333] ublk: add `union ublk_io_buf` with improved naming [ Upstream commit 8d61ece156bd4f2b9e7d3b2a374a26d42c7a4a06 ] Add `union ublk_io_buf` for naming the anonymous union of struct ublk_io's addr and buf fields, meantime apply it to `struct ublk_io` for storing either ublk auto buffer register data or ublk server io buffer address. The union uses clear field names: - `addr`: for regular ublk server io buffer addresses - `auto_reg`: for ublk auto buffer registration data This eliminates confusing access patterns and improves code readability. Reviewed-by: Caleb Sander Mateos Signed-off-by: Ming Lei Signed-off-by: Jens Axboe Stable-dep-of: c258f5c4502c ("ublk: fix deadlock when reading partition table") Signed-off-by: Sasha Levin --- drivers/block/ublk_drv.c | 40 ++++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c index 599571634b7ac..c9d258b990907 100644 --- a/drivers/block/ublk_drv.c +++ b/drivers/block/ublk_drv.c @@ -155,12 +155,13 @@ struct ublk_uring_cmd_pdu { */ #define UBLK_REFCOUNT_INIT (REFCOUNT_MAX / 2) +union ublk_io_buf { + __u64 addr; + struct ublk_auto_buf_reg auto_reg; +}; + struct ublk_io { - /* userspace buffer address from io cmd */ - union { - __u64 addr; - struct ublk_auto_buf_reg buf; - }; + union ublk_io_buf buf; unsigned int flags; int res; @@ -499,7 +500,7 @@ static blk_status_t ublk_setup_iod_zoned(struct ublk_queue *ubq, iod->op_flags = ublk_op | ublk_req_build_flags(req); iod->nr_sectors = blk_rq_sectors(req); iod->start_sector = blk_rq_pos(req); - iod->addr = io->addr; + iod->addr = io->buf.addr; return BLK_STS_OK; } @@ -1047,7 +1048,7 @@ static int ublk_map_io(const struct ublk_queue *ubq, const struct request *req, struct iov_iter iter; const int dir = ITER_DEST; - import_ubuf(dir, u64_to_user_ptr(io->addr), rq_bytes, &iter); + import_ubuf(dir, u64_to_user_ptr(io->buf.addr), rq_bytes, &iter); return ublk_copy_user_pages(req, 0, &iter, dir); } return rq_bytes; @@ -1068,7 +1069,7 @@ static int ublk_unmap_io(bool need_map, WARN_ON_ONCE(io->res > rq_bytes); - import_ubuf(dir, u64_to_user_ptr(io->addr), io->res, &iter); + import_ubuf(dir, u64_to_user_ptr(io->buf.addr), io->res, &iter); return ublk_copy_user_pages(req, 0, &iter, dir); } return rq_bytes; @@ -1134,7 +1135,7 @@ static blk_status_t ublk_setup_iod(struct ublk_queue *ubq, struct request *req) iod->op_flags = ublk_op | ublk_req_build_flags(req); iod->nr_sectors = blk_rq_sectors(req); iod->start_sector = blk_rq_pos(req); - iod->addr = io->addr; + iod->addr = io->buf.addr; return BLK_STS_OK; } @@ -1248,9 +1249,9 @@ static bool ublk_auto_buf_reg(const struct ublk_queue *ubq, struct request *req, int ret; ret = io_buffer_register_bvec(cmd, req, ublk_io_release, - io->buf.index, issue_flags); + io->buf.auto_reg.index, issue_flags); if (ret) { - if (io->buf.flags & UBLK_AUTO_BUF_REG_FALLBACK) { + if (io->buf.auto_reg.flags & UBLK_AUTO_BUF_REG_FALLBACK) { ublk_auto_buf_reg_fallback(ubq, io); return true; } @@ -1539,7 +1540,7 @@ static void ublk_queue_reinit(struct ublk_device *ub, struct ublk_queue *ubq) */ io->flags &= UBLK_IO_FLAG_CANCELED; io->cmd = NULL; - io->addr = 0; + io->buf.addr = 0; /* * old task is PF_EXITING, put it now @@ -2100,13 +2101,16 @@ static inline int ublk_check_cmd_op(u32 cmd_op) static inline int ublk_set_auto_buf_reg(struct ublk_io *io, struct io_uring_cmd *cmd) { - io->buf = ublk_sqe_addr_to_auto_buf_reg(READ_ONCE(cmd->sqe->addr)); + struct ublk_auto_buf_reg buf; + + buf = ublk_sqe_addr_to_auto_buf_reg(READ_ONCE(cmd->sqe->addr)); - if (io->buf.reserved0 || io->buf.reserved1) + if (buf.reserved0 || buf.reserved1) return -EINVAL; - if (io->buf.flags & ~UBLK_AUTO_BUF_REG_F_MASK) + if (buf.flags & ~UBLK_AUTO_BUF_REG_F_MASK) return -EINVAL; + io->buf.auto_reg = buf; return 0; } @@ -2128,7 +2132,7 @@ static int ublk_handle_auto_buf_reg(struct ublk_io *io, * this ublk request gets stuck. */ if (io->buf_ctx_handle == io_uring_cmd_ctx_handle(cmd)) - *buf_idx = io->buf.index; + *buf_idx = io->buf.auto_reg.index; } return ublk_set_auto_buf_reg(io, cmd); @@ -2156,7 +2160,7 @@ ublk_config_io_buf(const struct ublk_device *ub, struct ublk_io *io, if (ublk_dev_support_auto_buf_reg(ub)) return ublk_handle_auto_buf_reg(io, cmd, buf_idx); - io->addr = buf_addr; + io->buf.addr = buf_addr; return 0; } @@ -2353,7 +2357,7 @@ static bool ublk_get_data(const struct ublk_queue *ubq, struct ublk_io *io, */ io->flags &= ~UBLK_IO_FLAG_NEED_GET_DATA; /* update iod->addr because ublksrv may have passed a new io buffer */ - ublk_get_iod(ubq, req->tag)->addr = io->addr; + ublk_get_iod(ubq, req->tag)->addr = io->buf.addr; pr_devel("%s: update iod->addr: qid %d tag %d io_flags %x addr %llx\n", __func__, ubq->q_id, req->tag, io->flags, ublk_get_iod(ubq, req->tag)->addr); From 474cf21e0c0ed159839153903455c1aa314c1d07 Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Fri, 21 Nov 2025 09:58:26 +0800 Subject: [PATCH 1137/2333] ublk: refactor auto buffer register in ublk_dispatch_req() [ Upstream commit 0a9beafa7c633e6ff66b05b81eea78231b7e6520 ] Refactor auto buffer register code and prepare for supporting batch IO feature, and the main motivation is to put 'ublk_io' operation code together, so that per-io lock can be applied for the code block. The key changes are: - Rename ublk_auto_buf_reg() as ublk_do_auto_buf_reg() - Introduce an enum `auto_buf_reg_res` to represent the result of the buffer registration attempt (FAIL, FALLBACK, OK). - Split the existing `ublk_do_auto_buf_reg` function into two: - `__ublk_do_auto_buf_reg`: Performs the actual buffer registration and returns the `auto_buf_reg_res` status. - `ublk_do_auto_buf_reg`: A wrapper that calls the internal function and handles the I/O preparation based on the result. - Introduce `ublk_prep_auto_buf_reg_io` to encapsulate the logic for preparing the I/O for completion after buffer registration. - Pass the `tag` directly to `ublk_auto_buf_reg_fallback` to avoid recalculating it. This refactoring makes the control flow clearer and isolates the different stages of the auto buffer registration process. Reviewed-by: Caleb Sander Mateos Signed-off-by: Ming Lei Signed-off-by: Jens Axboe Stable-dep-of: c258f5c4502c ("ublk: fix deadlock when reading partition table") Signed-off-by: Sasha Levin --- drivers/block/ublk_drv.c | 64 +++++++++++++++++++++++++++------------- 1 file changed, 43 insertions(+), 21 deletions(-) diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c index c9d258b990907..bdb897d440897 100644 --- a/drivers/block/ublk_drv.c +++ b/drivers/block/ublk_drv.c @@ -1234,17 +1234,37 @@ static inline void __ublk_abort_rq(struct ublk_queue *ubq, } static void -ublk_auto_buf_reg_fallback(const struct ublk_queue *ubq, struct ublk_io *io) +ublk_auto_buf_reg_fallback(const struct ublk_queue *ubq, unsigned tag) { - unsigned tag = io - ubq->ios; struct ublksrv_io_desc *iod = ublk_get_iod(ubq, tag); iod->op_flags |= UBLK_IO_F_NEED_REG_BUF; } -static bool ublk_auto_buf_reg(const struct ublk_queue *ubq, struct request *req, - struct ublk_io *io, struct io_uring_cmd *cmd, - unsigned int issue_flags) +enum auto_buf_reg_res { + AUTO_BUF_REG_FAIL, + AUTO_BUF_REG_FALLBACK, + AUTO_BUF_REG_OK, +}; + +static void ublk_prep_auto_buf_reg_io(const struct ublk_queue *ubq, + struct request *req, struct ublk_io *io, + struct io_uring_cmd *cmd, + enum auto_buf_reg_res res) +{ + if (res == AUTO_BUF_REG_OK) { + io->task_registered_buffers = 1; + io->buf_ctx_handle = io_uring_cmd_ctx_handle(cmd); + io->flags |= UBLK_IO_FLAG_AUTO_BUF_REG; + } + ublk_init_req_ref(ubq, io); + __ublk_prep_compl_io_cmd(io, req); +} + +static enum auto_buf_reg_res +__ublk_do_auto_buf_reg(const struct ublk_queue *ubq, struct request *req, + struct ublk_io *io, struct io_uring_cmd *cmd, + unsigned int issue_flags) { int ret; @@ -1252,29 +1272,27 @@ static bool ublk_auto_buf_reg(const struct ublk_queue *ubq, struct request *req, io->buf.auto_reg.index, issue_flags); if (ret) { if (io->buf.auto_reg.flags & UBLK_AUTO_BUF_REG_FALLBACK) { - ublk_auto_buf_reg_fallback(ubq, io); - return true; + ublk_auto_buf_reg_fallback(ubq, req->tag); + return AUTO_BUF_REG_FALLBACK; } blk_mq_end_request(req, BLK_STS_IOERR); - return false; + return AUTO_BUF_REG_FAIL; } - io->task_registered_buffers = 1; - io->buf_ctx_handle = io_uring_cmd_ctx_handle(cmd); - io->flags |= UBLK_IO_FLAG_AUTO_BUF_REG; - return true; + return AUTO_BUF_REG_OK; } -static bool ublk_prep_auto_buf_reg(struct ublk_queue *ubq, - struct request *req, struct ublk_io *io, - struct io_uring_cmd *cmd, - unsigned int issue_flags) +static void ublk_do_auto_buf_reg(const struct ublk_queue *ubq, struct request *req, + struct ublk_io *io, struct io_uring_cmd *cmd, + unsigned int issue_flags) { - ublk_init_req_ref(ubq, io); - if (ublk_support_auto_buf_reg(ubq) && ublk_rq_has_data(req)) - return ublk_auto_buf_reg(ubq, req, io, cmd, issue_flags); + enum auto_buf_reg_res res = __ublk_do_auto_buf_reg(ubq, req, io, cmd, + issue_flags); - return true; + if (res != AUTO_BUF_REG_FAIL) { + ublk_prep_auto_buf_reg_io(ubq, req, io, cmd, res); + io_uring_cmd_done(cmd, UBLK_IO_RES_OK, issue_flags); + } } static bool ublk_start_io(const struct ublk_queue *ubq, struct request *req, @@ -1347,8 +1365,12 @@ static void ublk_dispatch_req(struct ublk_queue *ubq, if (!ublk_start_io(ubq, req, io)) return; - if (ublk_prep_auto_buf_reg(ubq, req, io, io->cmd, issue_flags)) + if (ublk_support_auto_buf_reg(ubq) && ublk_rq_has_data(req)) { + ublk_do_auto_buf_reg(ubq, req, io, io->cmd, issue_flags); + } else { + ublk_init_req_ref(ubq, io); ublk_complete_io_cmd(io, req, UBLK_IO_RES_OK, issue_flags); + } } static void ublk_cmd_tw_cb(struct io_uring_cmd *cmd, From 0460e09a614291f06c008443f47393c37b7358e7 Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Fri, 12 Dec 2025 22:34:15 +0800 Subject: [PATCH 1138/2333] ublk: fix deadlock when reading partition table [ Upstream commit c258f5c4502c9667bccf5d76fa731ab9c96687c1 ] When one process(such as udev) opens ublk block device (e.g., to read the partition table via bdev_open()), a deadlock[1] can occur: 1. bdev_open() grabs disk->open_mutex 2. The process issues read I/O to ublk backend to read partition table 3. In __ublk_complete_rq(), blk_update_request() or blk_mq_end_request() runs bio->bi_end_io() callbacks 4. If this triggers fput() on file descriptor of ublk block device, the work may be deferred to current task's task work (see fput() implementation) 5. This eventually calls blkdev_release() from the same context 6. blkdev_release() tries to grab disk->open_mutex again 7. Deadlock: same task waiting for a mutex it already holds The fix is to run blk_update_request() and blk_mq_end_request() with bottom halves disabled. This forces blkdev_release() to run in kernel work-queue context instead of current task work context, and allows ublk server to make forward progress, and avoids the deadlock. Fixes: 71f28f3136af ("ublk_drv: add io_uring based userspace block driver") Link: https://github.com/ublk-org/ublksrv/issues/170 [1] Signed-off-by: Ming Lei Reviewed-by: Caleb Sander Mateos [axboe: rewrite comment in ublk] Signed-off-by: Jens Axboe Signed-off-by: Sasha Levin --- drivers/block/ublk_drv.c | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c index bdb897d440897..fa7b0481ea046 100644 --- a/drivers/block/ublk_drv.c +++ b/drivers/block/ublk_drv.c @@ -1146,12 +1146,20 @@ static inline struct ublk_uring_cmd_pdu *ublk_get_uring_cmd_pdu( return io_uring_cmd_to_pdu(ioucmd, struct ublk_uring_cmd_pdu); } +static void ublk_end_request(struct request *req, blk_status_t error) +{ + local_bh_disable(); + blk_mq_end_request(req, error); + local_bh_enable(); +} + /* todo: handle partial completion */ static inline void __ublk_complete_rq(struct request *req, struct ublk_io *io, bool need_map) { unsigned int unmapped_bytes; blk_status_t res = BLK_STS_OK; + bool requeue; /* failed read IO if nothing is read */ if (!io->res && req_op(req) == REQ_OP_READ) @@ -1183,14 +1191,30 @@ static inline void __ublk_complete_rq(struct request *req, struct ublk_io *io, if (unlikely(unmapped_bytes < io->res)) io->res = unmapped_bytes; - if (blk_update_request(req, BLK_STS_OK, io->res)) + /* + * Run bio->bi_end_io() with softirqs disabled. If the final fput + * happens off this path, then that will prevent ublk's blkdev_release() + * from being called on current's task work, see fput() implementation. + * + * Otherwise, ublk server may not provide forward progress in case of + * reading the partition table from bdev_open() with disk->open_mutex + * held, and causes dead lock as we could already be holding + * disk->open_mutex here. + * + * Preferably we would not be doing IO with a mutex held that is also + * used for release, but this work-around will suffice for now. + */ + local_bh_disable(); + requeue = blk_update_request(req, BLK_STS_OK, io->res); + local_bh_enable(); + if (requeue) blk_mq_requeue_request(req, true); else if (likely(!blk_should_fake_timeout(req->q))) __blk_mq_end_request(req, BLK_STS_OK); return; exit: - blk_mq_end_request(req, res); + ublk_end_request(req, res); } static struct io_uring_cmd *__ublk_prep_compl_io_cmd(struct ublk_io *io, @@ -1230,7 +1254,7 @@ static inline void __ublk_abort_rq(struct ublk_queue *ubq, if (ublk_nosrv_dev_should_queue_io(ubq->dev)) blk_mq_requeue_request(rq, false); else - blk_mq_end_request(rq, BLK_STS_IOERR); + ublk_end_request(rq, BLK_STS_IOERR); } static void @@ -1275,7 +1299,7 @@ __ublk_do_auto_buf_reg(const struct ublk_queue *ubq, struct request *req, ublk_auto_buf_reg_fallback(ubq, req->tag); return AUTO_BUF_REG_FALLBACK; } - blk_mq_end_request(req, BLK_STS_IOERR); + ublk_end_request(req, BLK_STS_IOERR); return AUTO_BUF_REG_FAIL; } From cfc473f29eb5f44516993c14c237b39836bbf80b Mon Sep 17 00:00:00 2001 From: Thomas Fourier Date: Wed, 17 Dec 2025 10:36:48 +0100 Subject: [PATCH 1139/2333] block: rnbd-clt: Fix leaked ID in init_dev() [ Upstream commit c9b5645fd8ca10f310e41b07540f98e6a9720f40 ] If kstrdup() fails in init_dev(), then the newly allocated ID is lost. Fixes: 64e8a6ece1a5 ("block/rnbd-clt: Dynamically alloc buffer for pathname & blk_symlink_name") Signed-off-by: Thomas Fourier Acked-by: Jack Wang Signed-off-by: Jens Axboe Signed-off-by: Sasha Levin --- drivers/block/rnbd/rnbd-clt.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/block/rnbd/rnbd-clt.c b/drivers/block/rnbd/rnbd-clt.c index f1409e54010a6..d1c354636315d 100644 --- a/drivers/block/rnbd/rnbd-clt.c +++ b/drivers/block/rnbd/rnbd-clt.c @@ -1423,9 +1423,11 @@ static struct rnbd_clt_dev *init_dev(struct rnbd_clt_session *sess, goto out_alloc; } - ret = ida_alloc_max(&index_ida, (1 << (MINORBITS - RNBD_PART_BITS)) - 1, - GFP_KERNEL); - if (ret < 0) { + dev->clt_device_id = ida_alloc_max(&index_ida, + (1 << (MINORBITS - RNBD_PART_BITS)) - 1, + GFP_KERNEL); + if (dev->clt_device_id < 0) { + ret = dev->clt_device_id; pr_err("Failed to initialize device '%s' from session %s, allocating idr failed, err: %d\n", pathname, sess->sessname, ret); goto out_queues; @@ -1434,10 +1436,9 @@ static struct rnbd_clt_dev *init_dev(struct rnbd_clt_session *sess, dev->pathname = kstrdup(pathname, GFP_KERNEL); if (!dev->pathname) { ret = -ENOMEM; - goto out_queues; + goto out_ida; } - dev->clt_device_id = ret; dev->sess = sess; dev->access_mode = access_mode; dev->nr_poll_queues = nr_poll_queues; @@ -1453,6 +1454,8 @@ static struct rnbd_clt_dev *init_dev(struct rnbd_clt_session *sess, return dev; +out_ida: + ida_free(&index_ida, dev->clt_device_id); out_queues: kfree(dev->hw_queues); out_alloc: From 1d200017f55f829b9e376093bd31dfbec92081de Mon Sep 17 00:00:00 2001 From: Shuicheng Lin Date: Fri, 5 Dec 2025 23:47:17 +0000 Subject: [PATCH 1140/2333] drm/xe: Limit num_syncs to prevent oversized allocations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 8e461304009135270e9ccf2d7e2dfe29daec9b60 ] The exec and vm_bind ioctl allow userspace to specify an arbitrary num_syncs value. Without bounds checking, a very large num_syncs can force an excessively large allocation, leading to kernel warnings from the page allocator as below. Introduce DRM_XE_MAX_SYNCS (set to 1024) and reject any request exceeding this limit. " ------------[ cut here ]------------ WARNING: CPU: 0 PID: 1217 at mm/page_alloc.c:5124 __alloc_frozen_pages_noprof+0x2f8/0x2180 mm/page_alloc.c:5124 ... Call Trace: alloc_pages_mpol+0xe4/0x330 mm/mempolicy.c:2416 ___kmalloc_large_node+0xd8/0x110 mm/slub.c:4317 __kmalloc_large_node_noprof+0x18/0xe0 mm/slub.c:4348 __do_kmalloc_node mm/slub.c:4364 [inline] __kmalloc_noprof+0x3d4/0x4b0 mm/slub.c:4388 kmalloc_noprof include/linux/slab.h:909 [inline] kmalloc_array_noprof include/linux/slab.h:948 [inline] xe_exec_ioctl+0xa47/0x1e70 drivers/gpu/drm/xe/xe_exec.c:158 drm_ioctl_kernel+0x1f1/0x3e0 drivers/gpu/drm/drm_ioctl.c:797 drm_ioctl+0x5e7/0xc50 drivers/gpu/drm/drm_ioctl.c:894 xe_drm_ioctl+0x10b/0x170 drivers/gpu/drm/xe/xe_device.c:224 vfs_ioctl fs/ioctl.c:51 [inline] __do_sys_ioctl fs/ioctl.c:598 [inline] __se_sys_ioctl fs/ioctl.c:584 [inline] __x64_sys_ioctl+0x18b/0x210 fs/ioctl.c:584 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] do_syscall_64+0xbb/0x380 arch/x86/entry/syscall_64.c:94 entry_SYSCALL_64_after_hwframe+0x77/0x7f ... " v2: Add "Reported-by" and Cc stable kernels. v3: Change XE_MAX_SYNCS from 64 to 1024. (Matt & Ashutosh) v4: s/XE_MAX_SYNCS/DRM_XE_MAX_SYNCS/ (Matt) v5: Do the check at the top of the exec func. (Matt) Fixes: dd08ebf6c352 ("drm/xe: Introduce a new DRM driver for Intel GPUs") Reported-by: Koen Koning Reported-by: Peter Senna Tschudin Closes: https://gitlab.freedesktop.org/drm/xe/kernel/-/issues/6450 Cc: # v6.12+ Cc: Matthew Brost Cc: Michal Mrozek Cc: Carl Zhang Cc: José Roberto de Souza Cc: Lionel Landwerlin Cc: Ivan Briano Cc: Thomas Hellström Cc: Ashutosh Dixit Signed-off-by: Shuicheng Lin Reviewed-by: Matthew Brost Signed-off-by: Matthew Brost Link: https://patch.msgid.link/20251205234715.2476561-5-shuicheng.lin@intel.com (cherry picked from commit b07bac9bd708ec468cd1b8a5fe70ae2ac9b0a11c) Signed-off-by: Thomas Hellström Stable-dep-of: f8dd66bfb4e1 ("drm/xe/oa: Limit num_syncs to prevent oversized allocations") Signed-off-by: Sasha Levin --- drivers/gpu/drm/xe/xe_exec.c | 3 ++- drivers/gpu/drm/xe/xe_vm.c | 3 +++ include/uapi/drm/xe_drm.h | 1 + 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/xe/xe_exec.c b/drivers/gpu/drm/xe/xe_exec.c index a8ab363a80465..ca85f7c15fabe 100644 --- a/drivers/gpu/drm/xe/xe_exec.c +++ b/drivers/gpu/drm/xe/xe_exec.c @@ -130,7 +130,8 @@ int xe_exec_ioctl(struct drm_device *dev, void *data, struct drm_file *file) if (XE_IOCTL_DBG(xe, args->extensions) || XE_IOCTL_DBG(xe, args->pad[0] || args->pad[1] || args->pad[2]) || - XE_IOCTL_DBG(xe, args->reserved[0] || args->reserved[1])) + XE_IOCTL_DBG(xe, args->reserved[0] || args->reserved[1]) || + XE_IOCTL_DBG(xe, args->num_syncs > DRM_XE_MAX_SYNCS)) return -EINVAL; q = xe_exec_queue_lookup(xef, args->exec_queue_id); diff --git a/drivers/gpu/drm/xe/xe_vm.c b/drivers/gpu/drm/xe/xe_vm.c index cdd1dc540a59e..f0f699baa9f6e 100644 --- a/drivers/gpu/drm/xe/xe_vm.c +++ b/drivers/gpu/drm/xe/xe_vm.c @@ -3282,6 +3282,9 @@ static int vm_bind_ioctl_check_args(struct xe_device *xe, struct xe_vm *vm, if (XE_IOCTL_DBG(xe, args->extensions)) return -EINVAL; + if (XE_IOCTL_DBG(xe, args->num_syncs > DRM_XE_MAX_SYNCS)) + return -EINVAL; + if (args->num_binds > 1) { u64 __user *bind_user = u64_to_user_ptr(args->vector_of_binds); diff --git a/include/uapi/drm/xe_drm.h b/include/uapi/drm/xe_drm.h index 517489a7ec60a..400555a8af187 100644 --- a/include/uapi/drm/xe_drm.h +++ b/include/uapi/drm/xe_drm.h @@ -1459,6 +1459,7 @@ struct drm_xe_exec { /** @exec_queue_id: Exec queue ID for the batch buffer */ __u32 exec_queue_id; +#define DRM_XE_MAX_SYNCS 1024 /** @num_syncs: Amount of struct drm_xe_sync in array. */ __u32 num_syncs; From 338849090ee610ff6d11e5e90857d2c27a4121ab Mon Sep 17 00:00:00 2001 From: Shuicheng Lin Date: Fri, 5 Dec 2025 23:47:18 +0000 Subject: [PATCH 1141/2333] drm/xe/oa: Limit num_syncs to prevent oversized allocations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit f8dd66bfb4e184c71bd26418a00546ebe7f5c17a ] The OA open parameters did not validate num_syncs, allowing userspace to pass arbitrarily large values, potentially leading to excessive allocations. Add check to ensure that num_syncs does not exceed DRM_XE_MAX_SYNCS, returning -EINVAL when the limit is violated. v2: use XE_IOCTL_DBG() and drop duplicated check. (Ashutosh) Fixes: c8507a25cebd ("drm/xe/oa/uapi: Define and parse OA sync properties") Cc: Matthew Brost Cc: Ashutosh Dixit Signed-off-by: Shuicheng Lin Reviewed-by: Ashutosh Dixit Signed-off-by: Matthew Brost Link: https://patch.msgid.link/20251205234715.2476561-6-shuicheng.lin@intel.com (cherry picked from commit e057b2d2b8d815df3858a87dffafa2af37e5945b) Signed-off-by: Thomas Hellström Signed-off-by: Sasha Levin --- drivers/gpu/drm/xe/xe_oa.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/xe/xe_oa.c b/drivers/gpu/drm/xe/xe_oa.c index 125698a9ecf1c..10047373e1842 100644 --- a/drivers/gpu/drm/xe/xe_oa.c +++ b/drivers/gpu/drm/xe/xe_oa.c @@ -1253,6 +1253,9 @@ static int xe_oa_set_no_preempt(struct xe_oa *oa, u64 value, static int xe_oa_set_prop_num_syncs(struct xe_oa *oa, u64 value, struct xe_oa_open_param *param) { + if (XE_IOCTL_DBG(oa->xe, value > DRM_XE_MAX_SYNCS)) + return -EINVAL; + param->num_syncs = value; return 0; } From 1e5b2d2138f6b747e716a2e8c7ce22a9c2b7852d Mon Sep 17 00:00:00 2001 From: Ashutosh Dixit Date: Fri, 5 Dec 2025 13:26:13 -0800 Subject: [PATCH 1142/2333] drm/xe/oa: Always set OAG_OAGLBCTXCTRL_COUNTER_RESUME MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 256edb267a9d0b5aef70e408e9fba4f930f9926e ] Reports can be written out to the OA buffer using ways other than periodic sampling. These include mmio trigger and context switches. To support these use cases, when periodic sampling is not enabled, OAG_OAGLBCTXCTRL_COUNTER_RESUME must be set. Fixes: 1db9a9dc90ae ("drm/xe/oa: OA stream initialization (OAG)") Signed-off-by: Ashutosh Dixit Reviewed-by: Umesh Nerlige Ramappa Link: https://patch.msgid.link/20251205212613.826224-4-ashutosh.dixit@intel.com (cherry picked from commit 88d98e74adf3e20f678bb89581a5c3149fdbdeaa) Signed-off-by: Thomas Hellström Signed-off-by: Sasha Levin --- drivers/gpu/drm/xe/xe_oa.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_oa.c b/drivers/gpu/drm/xe/xe_oa.c index 10047373e1842..d0ceb67af83ed 100644 --- a/drivers/gpu/drm/xe/xe_oa.c +++ b/drivers/gpu/drm/xe/xe_oa.c @@ -1104,11 +1104,12 @@ static int xe_oa_enable_metric_set(struct xe_oa_stream *stream) oag_buf_size_select(stream) | oag_configure_mmio_trigger(stream, true)); - xe_mmio_write32(mmio, __oa_regs(stream)->oa_ctx_ctrl, stream->periodic ? - (OAG_OAGLBCTXCTRL_COUNTER_RESUME | + xe_mmio_write32(mmio, __oa_regs(stream)->oa_ctx_ctrl, + OAG_OAGLBCTXCTRL_COUNTER_RESUME | + (stream->periodic ? OAG_OAGLBCTXCTRL_TIMER_ENABLE | REG_FIELD_PREP(OAG_OAGLBCTXCTRL_TIMER_PERIOD_MASK, - stream->period_exponent)) : 0); + stream->period_exponent) : 0)); /* * Initialize Super Queue Internal Cnt Register From 66dce411c7e901631915edd336bf37b03c7a7c4b Mon Sep 17 00:00:00 2001 From: Sairaj Kodilkar Date: Fri, 21 Nov 2025 14:41:15 +0530 Subject: [PATCH 1143/2333] amd/iommu: Preserve domain ids inside the kdump kernel [ Upstream commit c2e8dc1222c2136e714d5d972dce7e64924e4ed8 ] Currently AMD IOMMU driver does not reserve domain ids programmed in the DTE while reusing the device table inside kdump kernel. This can cause reallocation of these domain ids for newer domains that are created by the kdump kernel, which can lead to potential IO_PAGE_FAULTs Hence reserve these ids inside pdom_ids. Fixes: 38e5f33ee359 ("iommu/amd: Reuse device table for kdump") Signed-off-by: Sairaj Kodilkar Reported-by: Jason Gunthorpe Reviewed-by: Vasant Hegde Reviewed-by: Jason Gunthorpe Signed-off-by: Joerg Roedel Signed-off-by: Sasha Levin --- drivers/iommu/amd/init.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c index f2991c11867cb..14eb9de33ccb0 100644 --- a/drivers/iommu/amd/init.c +++ b/drivers/iommu/amd/init.c @@ -1136,9 +1136,13 @@ static void set_dte_bit(struct dev_table_entry *dte, u8 bit) static bool __reuse_device_table(struct amd_iommu *iommu) { struct amd_iommu_pci_seg *pci_seg = iommu->pci_seg; - u32 lo, hi, old_devtb_size; + struct dev_table_entry *old_dev_tbl_entry; + u32 lo, hi, old_devtb_size, devid; phys_addr_t old_devtb_phys; + u16 dom_id; + bool dte_v; u64 entry; + int ret; /* Each IOMMU use separate device table with the same size */ lo = readl(iommu->mmio_base + MMIO_DEV_TABLE_OFFSET); @@ -1173,6 +1177,23 @@ static bool __reuse_device_table(struct amd_iommu *iommu) return false; } + for (devid = 0; devid <= pci_seg->last_bdf; devid++) { + old_dev_tbl_entry = &pci_seg->old_dev_tbl_cpy[devid]; + dte_v = FIELD_GET(DTE_FLAG_V, old_dev_tbl_entry->data[0]); + dom_id = FIELD_GET(DEV_DOMID_MASK, old_dev_tbl_entry->data[1]); + + if (!dte_v || !dom_id) + continue; + /* + * ID reservation can fail with -ENOSPC when there + * are multiple devices present in the same domain, + * hence check only for -ENOMEM. + */ + ret = ida_alloc_range(&pdom_ids, dom_id, dom_id, GFP_KERNEL); + if (ret == -ENOMEM) + return false; + } + return true; } From 0821f3ad2d6e2fd9219ed859ad0f7e5b815766dc Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Fri, 5 Dec 2025 22:59:38 +0100 Subject: [PATCH 1144/2333] arm64: dts: mediatek: Apply mt8395-radxa DT overlay at build time [ Upstream commit ce7b1d58609abc2941a1f38094147f439fb74233 ] It's a requirement that DT overlays be applied at build time in order to validate them as overlays are not validated on their own. Add missing target for mt8395-radxa hd panel overlay. Fixes: 4c8ff61199a7 ("arm64: dts: mediatek: mt8395-radxa-nio-12l: Add Radxa 8 HD panel") Signed-off-by: Frank Wunderlich Acked-by: AngeloGioacchino Del Regno Link: https://patch.msgid.link/20251205215940.19287-1-linux@fw-web.de Signed-off-by: Rob Herring (Arm) Signed-off-by: Sasha Levin --- arch/arm64/boot/dts/mediatek/Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm64/boot/dts/mediatek/Makefile b/arch/arm64/boot/dts/mediatek/Makefile index a4df4c21399ee..b50799b2a65fb 100644 --- a/arch/arm64/boot/dts/mediatek/Makefile +++ b/arch/arm64/boot/dts/mediatek/Makefile @@ -104,6 +104,8 @@ dtb-$(CONFIG_ARCH_MEDIATEK) += mt8390-genio-700-evk.dtb dtb-$(CONFIG_ARCH_MEDIATEK) += mt8395-kontron-3-5-sbc-i1200.dtb dtb-$(CONFIG_ARCH_MEDIATEK) += mt8395-radxa-nio-12l.dtb dtb-$(CONFIG_ARCH_MEDIATEK) += mt8395-radxa-nio-12l-8-hd-panel.dtbo +mt8395-radxa-nio-12l-8-hd-panel-dtbs := mt8395-radxa-nio-12l.dtb mt8395-radxa-nio-12l-8-hd-panel.dtbo +dtb-$(CONFIG_ARCH_MEDIATEK) += mt8395-radxa-nio-12l-8-hd-panel.dtb dtb-$(CONFIG_ARCH_MEDIATEK) += mt8516-pumpkin.dtb # Device tree overlays support From 3041d93301ca6f79db063e868b82d3e7f256dcb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nuno=20S=C3=A1?= Date: Fri, 19 Dec 2025 16:11:05 +0000 Subject: [PATCH 1145/2333] hwmon: (ltc4282): Fix reset_history file permissions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit b3db91c3bfea69a6c6258fea508f25a59c0feb1a ] The reset_history attributes are write only. Hence don't report them as readable just to return -EOPNOTSUPP later on. Fixes: cbc29538dbf7 ("hwmon: Add driver for LTC4282") Signed-off-by: Nuno Sá Link: https://lore.kernel.org/r/20251219-ltc4282-fix-reset-history-v1-1-8eab974c124b@analog.com Signed-off-by: Guenter Roeck Signed-off-by: Sasha Levin --- drivers/hwmon/ltc4282.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/hwmon/ltc4282.c b/drivers/hwmon/ltc4282.c index 1d664a2d7b3cb..58c2d3a624329 100644 --- a/drivers/hwmon/ltc4282.c +++ b/drivers/hwmon/ltc4282.c @@ -1018,8 +1018,9 @@ static umode_t ltc4282_in_is_visible(const struct ltc4282_state *st, u32 attr) case hwmon_in_max: case hwmon_in_min: case hwmon_in_enable: - case hwmon_in_reset_history: return 0644; + case hwmon_in_reset_history: + return 0200; default: return 0; } @@ -1038,8 +1039,9 @@ static umode_t ltc4282_curr_is_visible(u32 attr) return 0444; case hwmon_curr_max: case hwmon_curr_min: - case hwmon_curr_reset_history: return 0644; + case hwmon_curr_reset_history: + return 0200; default: return 0; } @@ -1057,8 +1059,9 @@ static umode_t ltc4282_power_is_visible(u32 attr) return 0444; case hwmon_power_max: case hwmon_power_min: - case hwmon_power_reset_history: return 0644; + case hwmon_power_reset_history: + return 0200; default: return 0; } From 571204e4758a528fbd67330bd4b0dfbdafb33dd8 Mon Sep 17 00:00:00 2001 From: Qianchang Zhao Date: Sun, 9 Nov 2025 10:00:55 +0900 Subject: [PATCH 1146/2333] ksmbd: skip lock-range check on equal size to avoid size==0 underflow commit 5d510ac31626ed157d2182149559430350cf2104 upstream. When size equals the current i_size (including 0), the code used to call check_lock_range(filp, i_size, size - 1, WRITE), which computes `size - 1` and can underflow for size==0. Skip the equal case. Cc: stable@vger.kernel.org Reported-by: Qianchang Zhao Reported-by: Zhitong Liu Signed-off-by: Qianchang Zhao Acked-by: Namjae Jeon Signed-off-by: Steve French Signed-off-by: Greg Kroah-Hartman --- fs/smb/server/vfs.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/fs/smb/server/vfs.c b/fs/smb/server/vfs.c index 891ed2dc2b735..90e693e4e4149 100644 --- a/fs/smb/server/vfs.c +++ b/fs/smb/server/vfs.c @@ -324,6 +324,9 @@ static int check_lock_range(struct file *filp, loff_t start, loff_t end, struct file_lock_context *ctx = locks_inode_context(file_inode(filp)); int error = 0; + if (start == end) + return 0; + if (!ctx || list_empty_careful(&ctx->flc_posix)) return 0; @@ -828,7 +831,7 @@ int ksmbd_vfs_truncate(struct ksmbd_work *work, if (size < inode->i_size) { err = check_lock_range(filp, size, inode->i_size - 1, WRITE); - } else { + } else if (size > inode->i_size) { err = check_lock_range(filp, inode->i_size, size - 1, WRITE); } From 8cabcb4dd3dc85dd83a37d26efcc59a66a4074d7 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Sun, 14 Dec 2025 15:05:56 +0900 Subject: [PATCH 1147/2333] ksmbd: Fix refcount leak when invalid session is found on session lookup commit cafb57f7bdd57abba87725eb4e82bbdca4959644 upstream. When a session is found but its state is not SMB2_SESSION_VALID, It indicates that no valid session was found, but it is missing to decrement the reference count acquired by the session lookup, which results in a reference count leak. This patch fixes the issue by explicitly calling ksmbd_user_session_put to release the reference to the session. Cc: stable@vger.kernel.org Reported-by: Alexandre Reported-by: Stanislas Polu Signed-off-by: Namjae Jeon Signed-off-by: Steve French Signed-off-by: Greg Kroah-Hartman --- fs/smb/server/mgmt/user_session.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fs/smb/server/mgmt/user_session.c b/fs/smb/server/mgmt/user_session.c index 1c181ef999295..7d880ff34402e 100644 --- a/fs/smb/server/mgmt/user_session.c +++ b/fs/smb/server/mgmt/user_session.c @@ -325,8 +325,10 @@ struct ksmbd_session *ksmbd_session_lookup_all(struct ksmbd_conn *conn, sess = ksmbd_session_lookup(conn, id); if (!sess && conn->binding) sess = ksmbd_session_lookup_slowpath(id); - if (sess && sess->state != SMB2_SESSION_VALID) + if (sess && sess->state != SMB2_SESSION_VALID) { + ksmbd_user_session_put(sess); sess = NULL; + } return sess; } From 6dc8cf6e7998ef7aeb9383a4c2904ea5d22fa2e4 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Sun, 14 Dec 2025 15:06:34 +0900 Subject: [PATCH 1148/2333] ksmbd: fix buffer validation by including null terminator size in EA length commit 95d7a890e4b03e198836d49d699408fd1867cb55 upstream. The smb2_set_ea function, which handles Extended Attributes (EA), was performing buffer validation checks that incorrectly omitted the size of the null terminating character (+1 byte) for EA Name. This patch fixes the issue by explicitly adding '+ 1' to EaNameLength where the null terminator is expected to be present in the buffer, ensuring the validation accurately reflects the total required buffer size. Cc: stable@vger.kernel.org Reported-by: Roger Reported-by: Stanislas Polu Signed-off-by: Namjae Jeon Signed-off-by: Steve French Signed-off-by: Greg Kroah-Hartman --- fs/smb/server/smb2pdu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c index dba29881debdc..6a94cda0927d7 100644 --- a/fs/smb/server/smb2pdu.c +++ b/fs/smb/server/smb2pdu.c @@ -2373,7 +2373,7 @@ static int smb2_set_ea(struct smb2_ea_info *eabuf, unsigned int buf_len, int rc = 0; unsigned int next = 0; - if (buf_len < sizeof(struct smb2_ea_info) + eabuf->EaNameLength + + if (buf_len < sizeof(struct smb2_ea_info) + eabuf->EaNameLength + 1 + le16_to_cpu(eabuf->EaValueLength)) return -EINVAL; @@ -2450,7 +2450,7 @@ static int smb2_set_ea(struct smb2_ea_info *eabuf, unsigned int buf_len, break; } - if (buf_len < sizeof(struct smb2_ea_info) + eabuf->EaNameLength + + if (buf_len < sizeof(struct smb2_ea_info) + eabuf->EaNameLength + 1 + le16_to_cpu(eabuf->EaValueLength)) { rc = -EINVAL; break; From 14b1a6009e488db77c454f1286292643532b6585 Mon Sep 17 00:00:00 2001 From: Ping Cheng Date: Mon, 27 Oct 2025 13:37:42 -0700 Subject: [PATCH 1149/2333] HID: input: map HID_GD_Z to ABS_DISTANCE for stylus/pen commit 7953794f741e94d30df9dafaaa4c031c85b891d6 upstream. HID_GD_Z is mapped to ABS_Z for stylus and pen in hid-input.c. But HID_GD_Z should be used to report ABS_DISTANCE for stylus and pen as described at: Documentation/input/event-codes.rst#n226 * ABS_DISTANCE: - Used to describe the distance of a tool from an interaction surface. This event should only be emitted while the tool is hovering, meaning in close proximity of the device and while the value of the BTN_TOUCH code is 0. If the input device may be used freely in three dimensions, consider ABS_Z instead. - BTN_TOOL_ should be set to 1 when the tool comes into detectable proximity and set to 0 when the tool leaves detectable proximity. BTN_TOOL_ signals the type of tool that is currently detected by the hardware and is otherwise independent of ABS_DISTANCE and/or BTN_TOUCH. This patch makes the correct mapping. The ABS_DISTANCE is currently not mapped by any HID usage in hid-generic driver. Signed-off-by: Ping Cheng Cc: stable@kernel.org Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman --- drivers/hid/hid-input.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 2bbb645c2ff41..32a96ae2946f1 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -878,7 +878,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel switch (usage->hid) { /* These usage IDs map directly to the usage codes. */ - case HID_GD_X: case HID_GD_Y: case HID_GD_Z: + case HID_GD_X: case HID_GD_Y: case HID_GD_RX: case HID_GD_RY: case HID_GD_RZ: if (field->flags & HID_MAIN_ITEM_RELATIVE) map_rel(usage->hid & 0xf); @@ -886,6 +886,22 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel map_abs_clear(usage->hid & 0xf); break; + case HID_GD_Z: + /* HID_GD_Z is mapped to ABS_DISTANCE for stylus/pen */ + if (field->flags & HID_MAIN_ITEM_RELATIVE) { + map_rel(usage->hid & 0xf); + } else { + if (field->application == HID_DG_PEN || + field->physical == HID_DG_PEN || + field->logical == HID_DG_STYLUS || + field->physical == HID_DG_STYLUS || + field->application == HID_DG_DIGITIZER) + map_abs_clear(ABS_DISTANCE); + else + map_abs_clear(usage->hid & 0xf); + } + break; + case HID_GD_WHEEL: if (field->flags & HID_MAIN_ITEM_RELATIVE) { set_bit(REL_WHEEL, input->relbit); From cae029e0575dfd2d581bfd82f3031268e445368e Mon Sep 17 00:00:00 2001 From: Sasha Finkelstein Date: Thu, 18 Dec 2025 10:15:23 -0800 Subject: [PATCH 1150/2333] Input: apple_z2 - fix reading incorrect reports after exiting sleep commit d579478cee228bdc0029a0c12a1f6a63ea9d1c77 upstream. Under certain conditions (more prevalent after a suspend/resume cycle), the touchscreen controller can send the "boot complete" interrupt before it actually finished booting. In those cases, attempting to read touch data resuls in a stream of "not ready" messages being read and interpreted as a touch report. Check that the response is in fact a touch report and discard it otherwise. Reported-by: pitust Closes: https://oftc.catirclogs.org/asahi/2025-12-17#34878715; Fixes: 471a92f8a21a ("Input: apple_z2 - add a driver for Apple Z2 touchscreens") Signed-off-by: Sasha Finkelstein Link: https://patch.msgid.link/20251218-z2-init-fix-v1-1-48e3aa239caf@gmail.com Cc: stable@vger.kernel.org Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/input/touchscreen/apple_z2.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/input/touchscreen/apple_z2.c b/drivers/input/touchscreen/apple_z2.c index 0de161eae59a0..271ababf0ad55 100644 --- a/drivers/input/touchscreen/apple_z2.c +++ b/drivers/input/touchscreen/apple_z2.c @@ -21,6 +21,7 @@ #define APPLE_Z2_TOUCH_STARTED 3 #define APPLE_Z2_TOUCH_MOVED 4 #define APPLE_Z2_CMD_READ_INTERRUPT_DATA 0xEB +#define APPLE_Z2_REPLY_INTERRUPT_DATA 0xE1 #define APPLE_Z2_HBPP_CMD_BLOB 0x3001 #define APPLE_Z2_FW_MAGIC 0x5746325A #define LOAD_COMMAND_INIT_PAYLOAD 0 @@ -142,6 +143,9 @@ static int apple_z2_read_packet(struct apple_z2 *z2) if (error) return error; + if (z2->rx_buf[0] != APPLE_Z2_REPLY_INTERRUPT_DATA) + return 0; + pkt_len = (get_unaligned_le16(z2->rx_buf + 1) + 8) & 0xfffffffc; error = spi_read(z2->spidev, z2->rx_buf, pkt_len); From 9d9eab0eb2bf6befde94113fbcd8204a6ff15e0f Mon Sep 17 00:00:00 2001 From: Sanjay Govind Date: Sat, 29 Nov 2025 20:37:11 +1300 Subject: [PATCH 1151/2333] Input: xpad - add support for CRKD Guitars commit 806ec7b797adc1cc9b11535307638a55ddfb873c upstream. Add support for various CRKD Guitar Controllers. Signed-off-by: Sanjay Govind Link: https://patch.msgid.link/20251129073720.2750-2-sanjay.govind9@gmail.com Cc: stable@vger.kernel.org Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/input/joystick/xpad.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index d72e89c25e503..363d509493866 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c @@ -133,6 +133,8 @@ static const struct xpad_device { } xpad_device[] = { /* Please keep this list sorted by vendor and product ID. */ { 0x0079, 0x18d4, "GPD Win 2 X-Box Controller", 0, XTYPE_XBOX360 }, + { 0x0351, 0x1000, "CRKD LP Blueberry Burst Pro Edition (Xbox)", 0, XTYPE_XBOX360 }, + { 0x0351, 0x2000, "CRKD LP Black Tribal Edition (Xbox) ", 0, XTYPE_XBOX360 }, { 0x03eb, 0xff01, "Wooting One (Legacy)", 0, XTYPE_XBOX360 }, { 0x03eb, 0xff02, "Wooting Two (Legacy)", 0, XTYPE_XBOX360 }, { 0x03f0, 0x038D, "HyperX Clutch", 0, XTYPE_XBOX360 }, /* wired */ @@ -420,6 +422,7 @@ static const struct xpad_device { { 0x3285, 0x0663, "Nacon Evol-X", 0, XTYPE_XBOXONE }, { 0x3537, 0x1004, "GameSir T4 Kaleid", 0, XTYPE_XBOX360 }, { 0x3537, 0x1010, "GameSir G7 SE", 0, XTYPE_XBOXONE }, + { 0x3651, 0x1000, "CRKD SG", 0, XTYPE_XBOX360 }, { 0x366c, 0x0005, "ByoWave Proteus Controller", MAP_SHARE_BUTTON, XTYPE_XBOXONE, FLAG_DELAY_INIT }, { 0x3767, 0x0101, "Fanatec Speedster 3 Forceshock Wheel", 0, XTYPE_XBOX }, { 0x37d7, 0x2501, "Flydigi Apex 5", 0, XTYPE_XBOX360 }, @@ -518,6 +521,7 @@ static const struct usb_device_id xpad_table[] = { */ { USB_INTERFACE_INFO('X', 'B', 0) }, /* Xbox USB-IF not-approved class */ XPAD_XBOX360_VENDOR(0x0079), /* GPD Win 2 controller */ + XPAD_XBOX360_VENDOR(0x0351), /* CRKD Controllers */ XPAD_XBOX360_VENDOR(0x03eb), /* Wooting Keyboards (Legacy) */ XPAD_XBOX360_VENDOR(0x03f0), /* HP HyperX Xbox 360 controllers */ XPAD_XBOXONE_VENDOR(0x03f0), /* HP HyperX Xbox One controllers */ @@ -578,6 +582,7 @@ static const struct usb_device_id xpad_table[] = { XPAD_XBOXONE_VENDOR(0x3285), /* Nacon Evol-X */ XPAD_XBOX360_VENDOR(0x3537), /* GameSir Controllers */ XPAD_XBOXONE_VENDOR(0x3537), /* GameSir Controllers */ + XPAD_XBOX360_VENDOR(0x3651), /* CRKD Controllers */ XPAD_XBOXONE_VENDOR(0x366c), /* ByoWave controllers */ XPAD_XBOX360_VENDOR(0x37d7), /* Flydigi Controllers */ XPAD_XBOX360_VENDOR(0x413d), /* Black Shark Green Ghost Controller */ From 40e3042de43ffa0017a8460ff9b4cad7b8c7cb96 Mon Sep 17 00:00:00 2001 From: Junjie Cao Date: Thu, 18 Dec 2025 21:56:59 -0800 Subject: [PATCH 1152/2333] Input: ti_am335x_tsc - fix off-by-one error in wire_order validation commit 248d3a73a0167dce15ba100477c3e778c4787178 upstream. The current validation 'wire_order[i] > ARRAY_SIZE(config_pins)' allows wire_order[i] to equal ARRAY_SIZE(config_pins), which causes out-of-bounds access when used as index in 'config_pins[wire_order[i]]'. Since config_pins has 4 elements (indices 0-3), the valid range for wire_order should be 0-3. Fix the off-by-one error by using >= instead of > in the validation check. Signed-off-by: Junjie Cao Link: https://patch.msgid.link/20251114062817.852698-1-junjie.cao@intel.com Fixes: bb76dc09ddfc ("input: ti_am33x_tsc: Order of TSC wires, made configurable") Cc: stable@vger.kernel.org Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/input/touchscreen/ti_am335x_tsc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/touchscreen/ti_am335x_tsc.c b/drivers/input/touchscreen/ti_am335x_tsc.c index 93d659ff90aa9..73980142f492b 100644 --- a/drivers/input/touchscreen/ti_am335x_tsc.c +++ b/drivers/input/touchscreen/ti_am335x_tsc.c @@ -85,7 +85,7 @@ static int titsc_config_wires(struct titsc *ts_dev) wire_order[i] = ts_dev->config_inp[i] & 0x0F; if (WARN_ON(analog_line[i] > 7)) return -EINVAL; - if (WARN_ON(wire_order[i] > ARRAY_SIZE(config_pins))) + if (WARN_ON(wire_order[i] >= ARRAY_SIZE(config_pins))) return -EINVAL; } From cffc4e29b1e2d44ab094cf142d7c461ff09b9104 Mon Sep 17 00:00:00 2001 From: Minseong Kim Date: Fri, 12 Dec 2025 00:29:23 -0800 Subject: [PATCH 1153/2333] Input: lkkbd - disable pending work before freeing device commit e58c88f0cb2d8ed89de78f6f17409d29cfab6c5c upstream. lkkbd_interrupt() schedules lk->tq via schedule_work(), and the work handler lkkbd_reinit() dereferences the lkkbd structure and its serio/input_dev fields. lkkbd_disconnect() and error paths in lkkbd_connect() free the lkkbd structure without preventing the reinit work from being queued again until serio_close() returns. This can allow the work handler to run after the structure has been freed, leading to a potential use-after-free. Use disable_work_sync() instead of cancel_work_sync() to ensure the reinit work cannot be re-queued, and call it both in lkkbd_disconnect() and in lkkbd_connect() error paths after serio_open(). Signed-off-by: Minseong Kim Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20251212052314.16139-1-ii4gsp@gmail.com Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/input/keyboard/lkkbd.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/input/keyboard/lkkbd.c b/drivers/input/keyboard/lkkbd.c index c035216dd27c1..2f130f819363c 100644 --- a/drivers/input/keyboard/lkkbd.c +++ b/drivers/input/keyboard/lkkbd.c @@ -670,7 +670,8 @@ static int lkkbd_connect(struct serio *serio, struct serio_driver *drv) return 0; - fail3: serio_close(serio); + fail3: disable_work_sync(&lk->tq); + serio_close(serio); fail2: serio_set_drvdata(serio, NULL); fail1: input_free_device(input_dev); kfree(lk); @@ -684,6 +685,8 @@ static void lkkbd_disconnect(struct serio *serio) { struct lkkbd *lk = serio_get_drvdata(serio); + disable_work_sync(&lk->tq); + input_get_device(lk->dev); input_unregister_device(lk->dev); serio_close(serio); From a9c115e017b2c633d25bdfe6709dda6fc36f08c2 Mon Sep 17 00:00:00 2001 From: Duoming Zhou Date: Wed, 17 Dec 2025 11:00:17 +0800 Subject: [PATCH 1154/2333] Input: alps - fix use-after-free bugs caused by dev3_register_work commit bf40644ef8c8a288742fa45580897ed0e0289474 upstream. The dev3_register_work delayed work item is initialized within alps_reconnect() and scheduled upon receipt of the first bare PS/2 packet from an external PS/2 device connected to the ALPS touchpad. During device detachment, the original implementation calls flush_workqueue() in psmouse_disconnect() to ensure completion of dev3_register_work. However, the flush_workqueue() in psmouse_disconnect() only blocks and waits for work items that were already queued to the workqueue prior to its invocation. Any work items submitted after flush_workqueue() is called are not included in the set of tasks that the flush operation awaits. This means that after flush_workqueue() has finished executing, the dev3_register_work could still be scheduled. Although the psmouse state is set to PSMOUSE_CMD_MODE in psmouse_disconnect(), the scheduling of dev3_register_work remains unaffected. The race condition can occur as follows: CPU 0 (cleanup path) | CPU 1 (delayed work) psmouse_disconnect() | psmouse_set_state() | flush_workqueue() | alps_report_bare_ps2_packet() alps_disconnect() | psmouse_queue_work() kfree(priv); // FREE | alps_register_bare_ps2_mouse() | priv = container_of(work...); // USE | priv->dev3 // USE Add disable_delayed_work_sync() in alps_disconnect() to ensure that dev3_register_work is properly canceled and prevented from executing after the alps_data structure has been deallocated. This bug is identified by static analysis. Fixes: 04aae283ba6a ("Input: ALPS - do not mix trackstick and external PS/2 mouse data") Cc: stable@kernel.org Signed-off-by: Duoming Zhou Link: https://patch.msgid.link/b57b0a9ccca51a3f06be141bfc02b9ffe69d1845.1765939397.git.duoming@zju.edu.cn Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/input/mouse/alps.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index d0cb9fb948218..df8953a5196e1 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -2975,6 +2975,7 @@ static void alps_disconnect(struct psmouse *psmouse) psmouse_reset(psmouse); timer_shutdown_sync(&priv->timer); + disable_delayed_work_sync(&priv->dev3_register_work); if (priv->dev2) input_unregister_device(priv->dev2); if (!IS_ERR_OR_NULL(priv->dev3)) From 8722085fd23b72cce302fe072648260ca0bb0e20 Mon Sep 17 00:00:00 2001 From: Christoffer Sandberg Date: Mon, 24 Nov 2025 21:31:34 +0100 Subject: [PATCH 1155/2333] Input: i8042 - add TUXEDO InfinityBook Max Gen10 AMD to i8042 quirk table commit aed3716db7fff74919cc5775ca3a80c8bb246489 upstream. The device occasionally wakes up from suspend with missing input on the internal keyboard and the following suspend attempt results in an instant wake-up. The quirks fix both issues for this device. Signed-off-by: Christoffer Sandberg Signed-off-by: Werner Sembach Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20251124203336.64072-1-wse@tuxedocomputers.com Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/input/serio/i8042-acpipnpio.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/input/serio/i8042-acpipnpio.h b/drivers/input/serio/i8042-acpipnpio.h index 1caa6c4ca435c..654771275ce87 100644 --- a/drivers/input/serio/i8042-acpipnpio.h +++ b/drivers/input/serio/i8042-acpipnpio.h @@ -1169,6 +1169,13 @@ static const struct dmi_system_id i8042_dmi_quirk_table[] __initconst = { .driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS | SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP) }, + { + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "X5KK45xS_X5SP45xS"), + }, + .driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS | + SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP) + }, /* * A lot of modern Clevo barebones have touchpad and/or keyboard issues * after suspend fixable with the forcenorestore quirk. From da852f46c76e4929c8b6559aa2489284291d309b Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 10 Nov 2025 14:22:53 +0100 Subject: [PATCH 1156/2333] xfs: don't leak a locked dquot when xfs_dquot_attach_buf fails commit 204c8f77e8d4a3006f8abe40331f221a597ce608 upstream. xfs_qm_quotacheck_dqadjust acquired the dquot through xfs_qm_dqget, which means it owns a reference and holds q_qlock. Both need to be dropped on an error exit. Cc: # v6.13 Fixes: ca378189fdfa ("xfs: convert quotacheck to attach dquot buffers") Reported-by: kernel test robot Reported-by: Dan Carpenter Signed-off-by: Christoph Hellwig Reviewed-by: Darrick J. Wong Signed-off-by: Carlos Maiolino Signed-off-by: Greg Kroah-Hartman --- fs/xfs/xfs_qm.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c index 23ba84ec919a4..18a19947bbdba 100644 --- a/fs/xfs/xfs_qm.c +++ b/fs/xfs/xfs_qm.c @@ -1318,7 +1318,7 @@ xfs_qm_quotacheck_dqadjust( error = xfs_dquot_attach_buf(NULL, dqp); if (error) - return error; + goto out_unlock; trace_xfs_dqadjust(dqp); @@ -1348,8 +1348,9 @@ xfs_qm_quotacheck_dqadjust( } dqp->q_flags |= XFS_DQFLAG_DIRTY; +out_unlock: xfs_qm_dqput(dqp); - return 0; + return error; } /* From bb958a1320b533077c46aa041a6326b93fc5cb82 Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Mon, 1 Dec 2025 19:26:38 +0100 Subject: [PATCH 1157/2333] can: gs_usb: gs_can_open(): fix error handling commit 3e54d3b4a8437b6783d4145c86962a2aa51022f3 upstream. Commit 2603be9e8167 ("can: gs_usb: gs_can_open(): improve error handling") added missing error handling to the gs_can_open() function. The driver uses 2 USB anchors to track the allocated URBs: the TX URBs in struct gs_can::tx_submitted for each netdev and the RX URBs in struct gs_usb::rx_submitted for the USB device. gs_can_open() allocates the RX URBs, while TX URBs are allocated during gs_can_start_xmit(). The cleanup in gs_can_open() kills all anchored dev->tx_submitted URBs (which is not necessary since the netdev is not yet registered), but misses the parent->rx_submitted URBs. Fix the problem by killing the rx_submitted instead of the tx_submitted. Fixes: 2603be9e8167 ("can: gs_usb: gs_can_open(): improve error handling") Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20251210-gs_usb-fix-error-handling-v1-1-d6a5a03f10bb@pengutronix.de Signed-off-by: Marc Kleine-Budde Signed-off-by: Greg Kroah-Hartman --- drivers/net/can/usb/gs_usb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/can/usb/gs_usb.c b/drivers/net/can/usb/gs_usb.c index 8d8a610f91441..db6885bcba28d 100644 --- a/drivers/net/can/usb/gs_usb.c +++ b/drivers/net/can/usb/gs_usb.c @@ -1074,7 +1074,7 @@ static int gs_can_open(struct net_device *netdev) usb_free_urb(urb); out_usb_kill_anchored_urbs: if (!parent->active_channels) { - usb_kill_anchored_urbs(&dev->tx_submitted); + usb_kill_anchored_urbs(&parent->rx_submitted); if (dev->feature & GS_CAN_FEATURE_HW_TIMESTAMP) gs_usb_timestamp_stop(parent); From 4a4193d9c6dde6e8c69b0d37828493ea449b8988 Mon Sep 17 00:00:00 2001 From: Kartik Rajput Date: Wed, 8 Oct 2025 16:46:18 +0530 Subject: [PATCH 1158/2333] soc/tegra: fuse: Do not register SoC device on ACPI boot commit c87f820bc4748fdd4d50969e8930cd88d1b61582 upstream. On Tegra platforms using ACPI, the SMCCC driver already registers the SoC device. This makes the registration performed by the Tegra fuse driver redundant. When booted via ACPI, skip registering the SoC device and suppress printing SKU information from the Tegra fuse driver, as this information is already provided by the SMCCC driver. Fixes: 972167c69080 ("soc/tegra: fuse: Add ACPI support for Tegra194 and Tegra234") Cc: stable@vger.kernel.org Signed-off-by: Kartik Rajput Signed-off-by: Thierry Reding Signed-off-by: Greg Kroah-Hartman --- drivers/soc/tegra/fuse/fuse-tegra.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/soc/tegra/fuse/fuse-tegra.c b/drivers/soc/tegra/fuse/fuse-tegra.c index d276672838465..74d2fedea71ca 100644 --- a/drivers/soc/tegra/fuse/fuse-tegra.c +++ b/drivers/soc/tegra/fuse/fuse-tegra.c @@ -182,8 +182,6 @@ static int tegra_fuse_probe(struct platform_device *pdev) } fuse->soc->init(fuse); - tegra_fuse_print_sku_info(&tegra_sku_info); - tegra_soc_device_register(); err = tegra_fuse_add_lookups(fuse); if (err) From 76033cf8c2e488c191a64eab11c4858b6d83685d Mon Sep 17 00:00:00 2001 From: Yongxin Liu Date: Fri, 28 Nov 2025 18:24:38 +0800 Subject: [PATCH 1159/2333] platform/x86: intel_pmc_ipc: fix ACPI buffer memory leak MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 611cf41ef6ac8301d23daadd8e78b013db0c5071 upstream. The intel_pmc_ipc() function uses ACPI_ALLOCATE_BUFFER to allocate memory for the ACPI evaluation result but never frees it, causing a 192-byte memory leak on each call. This leak is triggered during network interface initialization when the stmmac driver calls intel_mac_finish() -> intel_pmc_ipc(). unreferenced object 0xffff96a848d6ea80 (size 192): comm "dhcpcd", pid 541, jiffies 4294684345 hex dump (first 32 bytes): 04 00 00 00 05 00 00 00 98 ea d6 48 a8 96 ff ff ...........H.... 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 ................ backtrace (crc b1564374): kmemleak_alloc+0x2d/0x40 __kmalloc_noprof+0x2fa/0x730 acpi_ut_initialize_buffer+0x83/0xc0 acpi_evaluate_object+0x29a/0x2f0 intel_pmc_ipc+0xfd/0x170 intel_mac_finish+0x168/0x230 stmmac_mac_finish+0x3d/0x50 phylink_major_config+0x22b/0x5b0 phylink_mac_initial_config.constprop.0+0xf1/0x1b0 phylink_start+0x8e/0x210 __stmmac_open+0x12c/0x2b0 stmmac_open+0x23c/0x380 __dev_open+0x11d/0x2c0 __dev_change_flags+0x1d2/0x250 netif_change_flags+0x2b/0x70 dev_change_flags+0x40/0xb0 Add __free(kfree) for ACPI object to properly release the allocated buffer. Cc: stable@vger.kernel.org Fixes: 7e2f7e25f6ff ("arch: x86: add IPC mailbox accessor function and add SoC register access") Signed-off-by: Yongxin Liu Link: https://patch.msgid.link/20251128102437.3412891-2-yongxin.liu@windriver.com Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen Signed-off-by: Greg Kroah-Hartman --- include/linux/platform_data/x86/intel_pmc_ipc.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/linux/platform_data/x86/intel_pmc_ipc.h b/include/linux/platform_data/x86/intel_pmc_ipc.h index 1d34435b70016..85ea381e4a275 100644 --- a/include/linux/platform_data/x86/intel_pmc_ipc.h +++ b/include/linux/platform_data/x86/intel_pmc_ipc.h @@ -9,6 +9,7 @@ #ifndef INTEL_PMC_IPC_H #define INTEL_PMC_IPC_H #include +#include #define IPC_SOC_REGISTER_ACCESS 0xAA #define IPC_SOC_SUB_CMD_READ 0x00 @@ -48,7 +49,6 @@ static inline int intel_pmc_ipc(struct pmc_ipc_cmd *ipc_cmd, struct pmc_ipc_rbuf {.type = ACPI_TYPE_INTEGER,}, }; struct acpi_object_list arg_list = { PMC_IPCS_PARAM_COUNT, params }; - union acpi_object *obj; int status; if (!ipc_cmd || !rbuf) @@ -72,7 +72,7 @@ static inline int intel_pmc_ipc(struct pmc_ipc_cmd *ipc_cmd, struct pmc_ipc_rbuf if (ACPI_FAILURE(status)) return -ENODEV; - obj = buffer.pointer; + union acpi_object *obj __free(kfree) = buffer.pointer; if (obj && obj->type == ACPI_TYPE_PACKAGE && obj->package.count == VALID_IPC_RESPONSE) { From 4cb75cd4eeb4bac9d833272832592dac6bdc8626 Mon Sep 17 00:00:00 2001 From: Pengjie Zhang Date: Wed, 10 Dec 2025 21:26:34 +0800 Subject: [PATCH 1160/2333] ACPI: PCC: Fix race condition by removing static qualifier commit f103fa127c93016bcd89b05d8e11dc1a84f6990d upstream. Local variable 'ret' in acpi_pcc_address_space_setup() is currently declared as 'static'. This can lead to race conditions in a multithreaded environment. Remove the 'static' qualifier to ensure that 'ret' will be allocated directly on the stack as a local variable. Fixes: a10b1c99e2dc ("ACPI: PCC: Setup PCC Opregion handler only if platform interrupt is available") Signed-off-by: Pengjie Zhang Reviewed-by: Sudeep Holla Acked-by: lihuisong@huawei.com Cc: 6.2+ # 6.2+ [ rjw: Changelog edits ] Link: https://patch.msgid.link/20251210132634.2050033-1-zhangpengjie2@huawei.com Signed-off-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman --- drivers/acpi/acpi_pcc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/acpi/acpi_pcc.c b/drivers/acpi/acpi_pcc.c index 97064e943768a..e3f302b9dee5f 100644 --- a/drivers/acpi/acpi_pcc.c +++ b/drivers/acpi/acpi_pcc.c @@ -52,7 +52,7 @@ acpi_pcc_address_space_setup(acpi_handle region_handle, u32 function, struct pcc_data *data; struct acpi_pcc_info *ctx = handler_context; struct pcc_mbox_chan *pcc_chan; - static acpi_status ret; + acpi_status ret; data = kzalloc(sizeof(*data), GFP_KERNEL); if (!data) From 7e086c97dd2b746cbbfb813d73ba91d6c270bdb4 Mon Sep 17 00:00:00 2001 From: Pengjie Zhang Date: Wed, 10 Dec 2025 21:22:27 +0800 Subject: [PATCH 1161/2333] ACPI: CPPC: Fix missing PCC check for guaranteed_perf commit 6ea3a44cef28add2d93b1ef119d84886cb1e3c9b upstream. The current implementation overlooks the 'guaranteed_perf' register in this check. If the Guaranteed Performance register is located in the PCC subspace, the function currently attempts to read it without acquiring the lock and without sending the CMD_READ doorbell to the firmware. This can result in reading stale data. Fixes: 29523f095397 ("ACPI / CPPC: Add support for guaranteed performance") Signed-off-by: Pengjie Zhang Cc: 4.20+ # 4.20+ [ rjw: Subject and changelog edits ] Link: https://patch.msgid.link/20251210132227.1988380-1-zhangpengjie2@huawei.com Signed-off-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman --- drivers/acpi/cppc_acpi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c index 3bdeeee3414e6..e66e20d1f31b7 100644 --- a/drivers/acpi/cppc_acpi.c +++ b/drivers/acpi/cppc_acpi.c @@ -1366,7 +1366,8 @@ int cppc_get_perf_caps(int cpunum, struct cppc_perf_caps *perf_caps) /* Are any of the regs PCC ?*/ if (CPC_IN_PCC(highest_reg) || CPC_IN_PCC(lowest_reg) || CPC_IN_PCC(lowest_non_linear_reg) || CPC_IN_PCC(nominal_reg) || - CPC_IN_PCC(low_freq_reg) || CPC_IN_PCC(nom_freq_reg)) { + CPC_IN_PCC(low_freq_reg) || CPC_IN_PCC(nom_freq_reg) || + CPC_IN_PCC(guaranteed_reg)) { if (pcc_ss_id < 0) { pr_debug("Invalid pcc_ss_id\n"); return -ENODEV; From be0b613198e6bfa104ad520397cab82ad3ec1771 Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Thu, 20 Nov 2025 09:34:49 +0100 Subject: [PATCH 1162/2333] spi: fsl-cpm: Check length parity before switching to 16 bit mode commit 1417927df8049a0194933861e9b098669a95c762 upstream. Commit fc96ec826bce ("spi: fsl-cpm: Use 16 bit mode for large transfers with even size") failed to make sure that the size is really even before switching to 16 bit mode. Until recently the problem went unnoticed because kernfs uses a pre-allocated bounce buffer of size PAGE_SIZE for reading EEPROM. But commit 8ad6249c51d0 ("eeprom: at25: convert to spi-mem API") introduced an additional dynamically allocated bounce buffer whose size is exactly the size of the transfer, leading to a buffer overrun in the fsl-cpm driver when that size is odd. Add the missing length parity verification and remain in 8 bit mode when the length is not even. Fixes: fc96ec826bce ("spi: fsl-cpm: Use 16 bit mode for large transfers with even size") Cc: stable@vger.kernel.org Closes: https://lore.kernel.org/all/638496dd-ec60-4e53-bad7-eb657f67d580@csgroup.eu/ Signed-off-by: Christophe Leroy Reviewed-by: Sverdlin Alexander Link: https://patch.msgid.link/3c4d81c3923c93f95ec56702a454744a4bad3cfc.1763627618.git.christophe.leroy@csgroup.eu Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- drivers/spi/spi-fsl-spi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-fsl-spi.c b/drivers/spi/spi-fsl-spi.c index 2f2082652a1a2..481a7b28aacd3 100644 --- a/drivers/spi/spi-fsl-spi.c +++ b/drivers/spi/spi-fsl-spi.c @@ -335,7 +335,7 @@ static int fsl_spi_prepare_message(struct spi_controller *ctlr, if (t->bits_per_word == 16 || t->bits_per_word == 32) t->bits_per_word = 8; /* pretend its 8 bits */ if (t->bits_per_word == 8 && t->len >= 256 && - (mpc8xxx_spi->flags & SPI_CPM1)) + !(t->len & 1) && (mpc8xxx_spi->flags & SPI_CPM1)) t->bits_per_word = 16; } } From 87e74671ddbcf023345d9978d8c67bbfe48e2956 Mon Sep 17 00:00:00 2001 From: Jared Kangas Date: Fri, 12 Dec 2025 07:03:17 -0800 Subject: [PATCH 1163/2333] mmc: sdhci-esdhc-imx: add alternate ARCH_S32 dependency to Kconfig commit d3ecb12e2e04ce53c95f933c462f2d8b150b965b upstream. MMC_SDHCI_ESDHC_IMX requires ARCH_MXC despite also being used on ARCH_S32, which results in unmet dependencies when compiling strictly for ARCH_S32. Resolve this by adding ARCH_S32 as an alternative to ARCH_MXC in the driver's dependencies. Fixes: 5c4f00627c9a ("mmc: sdhci-esdhc-imx: add NXP S32G2 support") Cc: stable@bvger.kernel.org Signed-off-by: Jared Kangas Reviewed-by: Haibo Chen Signed-off-by: Ulf Hansson Signed-off-by: Greg Kroah-Hartman --- drivers/mmc/host/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 10d0ef58ef493..c94ae4794545d 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -315,14 +315,14 @@ config MMC_SDHCI_ESDHC_MCF config MMC_SDHCI_ESDHC_IMX tristate "SDHCI support for the Freescale eSDHC/uSDHC i.MX controller" - depends on ARCH_MXC || COMPILE_TEST + depends on ARCH_MXC || ARCH_S32 || COMPILE_TEST depends on MMC_SDHCI_PLTFM depends on OF select MMC_SDHCI_IO_ACCESSORS select MMC_CQHCI help This selects the Freescale eSDHC/uSDHC controller support - found on i.MX25, i.MX35 i.MX5x and i.MX6x. + found on i.MX25, i.MX35, i.MX5x, i.MX6x, and S32G. If you have a controller with this interface, say Y or M here. From 2ebf2e631d53b42c53bea61569938e4665da1710 Mon Sep 17 00:00:00 2001 From: Sai Krishna Potthuri Date: Fri, 12 Dec 2025 12:05:09 +0530 Subject: [PATCH 1164/2333] mmc: sdhci-of-arasan: Increase CD stable timeout to 2 seconds commit a9c4c9085ec8ce3ce01be21b75184789e74f5f19 upstream. On Xilinx/AMD platforms, the CD stable bit take slightly longer than one second(about an additional 100ms) to assert after a host controller reset. Although no functional failure observed with the existing one second delay but to ensure reliable initialization, increase the CD stable timeout to 2 seconds. Fixes: e251709aaddb ("mmc: sdhci-of-arasan: Ensure CD logic stabilization before power-up") Cc: stable@vger.kernel.org Signed-off-by: Sai Krishna Potthuri Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson Signed-off-by: Greg Kroah-Hartman --- drivers/mmc/host/sdhci-of-arasan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci-of-arasan.c index c6f09b53325d2..0a4b4696bc01c 100644 --- a/drivers/mmc/host/sdhci-of-arasan.c +++ b/drivers/mmc/host/sdhci-of-arasan.c @@ -99,7 +99,7 @@ #define HIWORD_UPDATE(val, mask, shift) \ ((val) << (shift) | (mask) << ((shift) + 16)) -#define CD_STABLE_TIMEOUT_US 1000000 +#define CD_STABLE_TIMEOUT_US 2000000 #define CD_STABLE_MAX_SLEEP_US 10 /** From e1be561f6b14cfd8dc4f17bfb9797377526e18ae Mon Sep 17 00:00:00 2001 From: Andrew Jeffery Date: Thu, 11 Dec 2025 17:45:48 +0900 Subject: [PATCH 1165/2333] dt-bindings: mmc: sdhci-of-aspeed: Switch ref to sdhci-common.yaml commit ed724ea1b82a800af4704311cb89e5ef1b4ea7ac upstream. Enable use of common SDHCI-related properties such as sdhci-caps-mask as found in the AST2600 EVB DTS. Cc: stable@vger.kernel.org # v6.2+ Signed-off-by: Andrew Jeffery Signed-off-by: Ulf Hansson Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/mmc/aspeed,sdhci.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/mmc/aspeed,sdhci.yaml b/Documentation/devicetree/bindings/mmc/aspeed,sdhci.yaml index 9fce8cd7b0b62..d24950ccea952 100644 --- a/Documentation/devicetree/bindings/mmc/aspeed,sdhci.yaml +++ b/Documentation/devicetree/bindings/mmc/aspeed,sdhci.yaml @@ -41,7 +41,7 @@ properties: patternProperties: "^sdhci@[0-9a-f]+$": type: object - $ref: mmc-controller.yaml + $ref: sdhci-common.yaml unevaluatedProperties: false properties: From 6220d38a08f8837575cd8f830928b49a3a5a5095 Mon Sep 17 00:00:00 2001 From: Shaurya Rane Date: Sat, 29 Nov 2025 15:07:18 +0530 Subject: [PATCH 1166/2333] net/hsr: fix NULL pointer dereference in prp_get_untagged_frame() commit 188e0fa5a679570ea35474575e724d8211423d17 upstream. prp_get_untagged_frame() calls __pskb_copy() to create frame->skb_std but doesn't check if the allocation failed. If __pskb_copy() returns NULL, skb_clone() is called with a NULL pointer, causing a crash: Oops: general protection fault, probably for non-canonical address 0xdffffc000000000f: 0000 [#1] SMP KASAN NOPTI KASAN: null-ptr-deref in range [0x0000000000000078-0x000000000000007f] CPU: 0 UID: 0 PID: 5625 Comm: syz.1.18 Not tainted syzkaller #0 PREEMPT(full) Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2~bpo12+1 04/01/2014 RIP: 0010:skb_clone+0xd7/0x3a0 net/core/skbuff.c:2041 Code: 03 42 80 3c 20 00 74 08 4c 89 f7 e8 23 29 05 f9 49 83 3e 00 0f 85 a0 01 00 00 e8 94 dd 9d f8 48 8d 6b 7e 49 89 ee 49 c1 ee 03 <43> 0f b6 04 26 84 c0 0f 85 d1 01 00 00 44 0f b6 7d 00 41 83 e7 0c RSP: 0018:ffffc9000d00f200 EFLAGS: 00010207 RAX: ffffffff892235a1 RBX: 0000000000000000 RCX: ffff88803372a480 RDX: 0000000000000000 RSI: 0000000000000820 RDI: 0000000000000000 RBP: 000000000000007e R08: ffffffff8f7d0f77 R09: 1ffffffff1efa1ee R10: dffffc0000000000 R11: fffffbfff1efa1ef R12: dffffc0000000000 R13: 0000000000000820 R14: 000000000000000f R15: ffff88805144cc00 FS: 0000555557f6d500(0000) GS:ffff88808d72f000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000555581d35808 CR3: 000000005040e000 CR4: 0000000000352ef0 Call Trace: hsr_forward_do net/hsr/hsr_forward.c:-1 [inline] hsr_forward_skb+0x1013/0x2860 net/hsr/hsr_forward.c:741 hsr_handle_frame+0x6ce/0xa70 net/hsr/hsr_slave.c:84 __netif_receive_skb_core+0x10b9/0x4380 net/core/dev.c:5966 __netif_receive_skb_one_core net/core/dev.c:6077 [inline] __netif_receive_skb+0x72/0x380 net/core/dev.c:6192 netif_receive_skb_internal net/core/dev.c:6278 [inline] netif_receive_skb+0x1cb/0x790 net/core/dev.c:6337 tun_rx_batched+0x1b9/0x730 drivers/net/tun.c:1485 tun_get_user+0x2b65/0x3e90 drivers/net/tun.c:1953 tun_chr_write_iter+0x113/0x200 drivers/net/tun.c:1999 new_sync_write fs/read_write.c:593 [inline] vfs_write+0x5c9/0xb30 fs/read_write.c:686 ksys_write+0x145/0x250 fs/read_write.c:738 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] do_syscall_64+0xfa/0xfa0 arch/x86/entry/syscall_64.c:94 entry_SYSCALL_64_after_hwframe+0x77/0x7f RIP: 0033:0x7f0449f8e1ff Code: 89 54 24 18 48 89 74 24 10 89 7c 24 08 e8 f9 92 02 00 48 8b 54 24 18 48 8b 74 24 10 41 89 c0 8b 7c 24 08 b8 01 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 31 44 89 c7 48 89 44 24 08 e8 4c 93 02 00 48 RSP: 002b:00007ffd7ad94c90 EFLAGS: 00000293 ORIG_RAX: 0000000000000001 RAX: ffffffffffffffda RBX: 00007f044a1e5fa0 RCX: 00007f0449f8e1ff RDX: 000000000000003e RSI: 0000200000000500 RDI: 00000000000000c8 RBP: 00007ffd7ad94d20 R08: 0000000000000000 R09: 0000000000000000 R10: 000000000000003e R11: 0000000000000293 R12: 0000000000000001 R13: 00007f044a1e5fa0 R14: 00007f044a1e5fa0 R15: 0000000000000003 Add a NULL check immediately after __pskb_copy() to handle allocation failures gracefully. Reported-by: syzbot+2fa344348a579b779e05@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=2fa344348a579b779e05 Fixes: f266a683a480 ("net/hsr: Better frame dispatch") Cc: stable@vger.kernel.org Signed-off-by: Shaurya Rane Reviewed-by: Felix Maurer Tested-by: Felix Maurer Link: https://patch.msgid.link/20251129093718.25320-1-ssrane_b23@ee.vjti.ac.in Signed-off-by: Paolo Abeni Signed-off-by: Greg Kroah-Hartman --- net/hsr/hsr_forward.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/hsr/hsr_forward.c b/net/hsr/hsr_forward.c index 339f0d2202129..aefc9b6936ba0 100644 --- a/net/hsr/hsr_forward.c +++ b/net/hsr/hsr_forward.c @@ -205,6 +205,8 @@ struct sk_buff *prp_get_untagged_frame(struct hsr_frame_info *frame, __pskb_copy(frame->skb_prp, skb_headroom(frame->skb_prp), GFP_ATOMIC); + if (!frame->skb_std) + return NULL; } else { /* Unexpected */ WARN_ONCE(1, "%s:%d: Unexpected frame received (port_src %s)\n", From 34c0e95524d61b8c0a10c828470d0810b81bb7b6 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Thu, 18 Dec 2025 11:47:38 +0100 Subject: [PATCH 1167/2333] x86/bug: Fix old GCC compile fails commit c56a12c71ad38f381105f6e5036dede64ad2dfee upstream. For some mysterious reasons the GCC 8 and 9 preprocessor manages to sporadically fumble _ASM_BYTES(0x0f, 0x0b): $ grep ".byte[ ]*0x0f" defconfig-build/drivers/net/wireless/realtek/rtlwifi/base.s 1: .byte0x0f,0x0b ; 1: .byte 0x0f,0x0b ; which makes the assembler upset and all that. While there are more _ASM_BYTES() users (notably the NOP instructions), those don't seem affected. Therefore replace the offending ASM_UD2 with one using the ud2 mnemonic. Reported-by: Jean Delvare Suggested-by: Uros Bizjak Fixes: 85a2d4a890dc ("x86,ibt: Use UDB instead of 0xEA") Cc: stable@kernel.org Signed-off-by: Peter Zijlstra (Intel) Link: https://patch.msgid.link/20251218104659.GT3911114@noisy.programming.kicks-ass.net Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/bug.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/include/asm/bug.h b/arch/x86/include/asm/bug.h index 880ca15073ed1..99017bb1031e9 100644 --- a/arch/x86/include/asm/bug.h +++ b/arch/x86/include/asm/bug.h @@ -10,7 +10,7 @@ /* * Despite that some emulators terminate on UD2, we use it for WARN(). */ -#define ASM_UD2 _ASM_BYTES(0x0f, 0x0b) +#define ASM_UD2 __ASM_FORM(ud2) #define INSN_UD2 0x0b0f #define LEN_UD2 2 From f01e9f891c3791960dedd417a0b6571d13b1a28e Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 25 Nov 2025 22:50:45 +0100 Subject: [PATCH 1168/2333] x86/msi: Make irq_retrigger() functional for posted MSI commit 0edc78b82bea85e1b2165d8e870a5c3535919695 upstream. Luigi reported that retriggering a posted MSI interrupt does not work correctly. The reason is that the retrigger happens at the vector domain by sending an IPI to the actual vector on the target CPU. That works correctly exactly once because the posted MSI interrupt chip does not issue an EOI as that's only required for the posted MSI notification vector itself. As a consequence the vector becomes stale in the ISR, which not only affects this vector but also any lower priority vector in the affected APIC because the ISR bit is not cleared. Luigi proposed to set the vector in the remap PIR bitmap and raise the posted MSI notification vector. That works, but that still does not cure a related problem: If there is ever a stray interrupt on such a vector, then the related APIC ISR bit becomes stale due to the lack of EOI as described above. Unlikely to happen, but if it happens it's not debuggable at all. So instead of playing games with the PIR, this can be actually solved for both cases by: 1) Keeping track of the posted interrupt vector handler state 2) Implementing a posted MSI specific irq_ack() callback which checks that state. If the posted vector handler is inactive it issues an EOI, otherwise it delegates that to the posted handler. This is correct versus affinity changes and concurrent events on the posted vector as the actual handler invocation is serialized through the interrupt descriptor lock. Fixes: ed1e48ea4370 ("iommu/vt-d: Enable posted mode for device MSIs") Reported-by: Luigi Rizzo Signed-off-by: Thomas Gleixner Tested-by: Luigi Rizzo Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20251125214631.044440658@linutronix.de Closes: https://lore.kernel.org/lkml/20251124104836.3685533-1-lrizzo@google.com Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/irq_remapping.h | 7 +++++++ arch/x86/kernel/irq.c | 23 +++++++++++++++++++++++ drivers/iommu/intel/irq_remapping.c | 8 ++++---- 3 files changed, 34 insertions(+), 4 deletions(-) diff --git a/arch/x86/include/asm/irq_remapping.h b/arch/x86/include/asm/irq_remapping.h index 5a0d42464d442..4e55d17558465 100644 --- a/arch/x86/include/asm/irq_remapping.h +++ b/arch/x86/include/asm/irq_remapping.h @@ -87,4 +87,11 @@ static inline void panic_if_irq_remap(const char *msg) } #endif /* CONFIG_IRQ_REMAP */ + +#ifdef CONFIG_X86_POSTED_MSI +void intel_ack_posted_msi_irq(struct irq_data *irqd); +#else +#define intel_ack_posted_msi_irq NULL +#endif + #endif /* __X86_IRQ_REMAPPING_H */ diff --git a/arch/x86/kernel/irq.c b/arch/x86/kernel/irq.c index 10721a1252269..59d38411a1d99 100644 --- a/arch/x86/kernel/irq.c +++ b/arch/x86/kernel/irq.c @@ -396,6 +396,7 @@ DEFINE_IDTENTRY_SYSVEC_SIMPLE(sysvec_kvm_posted_intr_nested_ipi) /* Posted Interrupt Descriptors for coalesced MSIs to be posted */ DEFINE_PER_CPU_ALIGNED(struct pi_desc, posted_msi_pi_desc); +static DEFINE_PER_CPU_CACHE_HOT(bool, posted_msi_handler_active); void intel_posted_msi_init(void) { @@ -413,6 +414,25 @@ void intel_posted_msi_init(void) this_cpu_write(posted_msi_pi_desc.ndst, destination); } +void intel_ack_posted_msi_irq(struct irq_data *irqd) +{ + irq_move_irq(irqd); + + /* + * Handle the rare case that irq_retrigger() raised the actual + * assigned vector on the target CPU, which means that it was not + * invoked via the posted MSI handler below. In that case APIC EOI + * is required as otherwise the ISR entry becomes stale and lower + * priority interrupts are never going to be delivered after that. + * + * If the posted handler invoked the device interrupt handler then + * the EOI would be premature because it would acknowledge the + * posted vector. + */ + if (unlikely(!__this_cpu_read(posted_msi_handler_active))) + apic_eoi(); +} + static __always_inline bool handle_pending_pir(unsigned long *pir, struct pt_regs *regs) { unsigned long pir_copy[NR_PIR_WORDS]; @@ -445,6 +465,8 @@ DEFINE_IDTENTRY_SYSVEC(sysvec_posted_msi_notification) pid = this_cpu_ptr(&posted_msi_pi_desc); + /* Mark the handler active for intel_ack_posted_msi_irq() */ + __this_cpu_write(posted_msi_handler_active, true); inc_irq_stat(posted_msi_notification_count); irq_enter(); @@ -473,6 +495,7 @@ DEFINE_IDTENTRY_SYSVEC(sysvec_posted_msi_notification) apic_eoi(); irq_exit(); + __this_cpu_write(posted_msi_handler_active, false); set_irq_regs(old_regs); } #endif /* X86_POSTED_MSI */ diff --git a/drivers/iommu/intel/irq_remapping.c b/drivers/iommu/intel/irq_remapping.c index 4f9b01dc91e86..8bcbfe3d9c722 100644 --- a/drivers/iommu/intel/irq_remapping.c +++ b/drivers/iommu/intel/irq_remapping.c @@ -1303,17 +1303,17 @@ static struct irq_chip intel_ir_chip = { * irq_enter(); * handle_edge_irq() * irq_chip_ack_parent() - * irq_move_irq(); // No EOI + * intel_ack_posted_msi_irq(); // No EOI * handle_irq_event() * driver_handler() * handle_edge_irq() * irq_chip_ack_parent() - * irq_move_irq(); // No EOI + * intel_ack_posted_msi_irq(); // No EOI * handle_irq_event() * driver_handler() * handle_edge_irq() * irq_chip_ack_parent() - * irq_move_irq(); // No EOI + * intel_ack_posted_msi_irq(); // No EOI * handle_irq_event() * driver_handler() * apic_eoi() @@ -1322,7 +1322,7 @@ static struct irq_chip intel_ir_chip = { */ static struct irq_chip intel_ir_chip_post_msi = { .name = "INTEL-IR-POST", - .irq_ack = irq_move_irq, + .irq_ack = intel_ack_posted_msi_irq, .irq_set_affinity = intel_ir_set_affinity, .irq_compose_msi_msg = intel_ir_compose_msi_msg, .irq_set_vcpu_affinity = intel_ir_set_vcpu_affinity, From 82b6dfc0aa60de28a7a7631adb8eaaddde638dd6 Mon Sep 17 00:00:00 2001 From: Yongxin Liu Date: Wed, 10 Dec 2025 08:02:20 +0800 Subject: [PATCH 1169/2333] x86/fpu: Fix FPU state core dump truncation on CPUs with no extended xfeatures [ Upstream commit c8161e5304abb26e6c0bec6efc947992500fa6c5 ] Zero can be a valid value of num_records. For example, on Intel Atom x6425RE, only x87 and SSE are supported (features 0, 1), and fpu_user_cfg.max_features is 3. The for_each_extended_xfeature() loop only iterates feature 2, which is not enabled, so num_records = 0. This is valid and should not cause core dump failure. The issue is that dump_xsave_layout_desc() returns 0 for both genuine errors (dump_emit() failure) and valid cases (no extended features). Use negative return values for errors and only abort on genuine failures. Fixes: ba386777a30b ("x86/elf: Add a new FPU buffer layout info to x86 core files") Signed-off-by: Yongxin Liu Signed-off-by: Ingo Molnar Link: https://patch.msgid.link/20251210000219.4094353-2-yongxin.liu@windriver.com Signed-off-by: Sasha Levin --- arch/x86/kernel/fpu/xstate.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86/kernel/fpu/xstate.c b/arch/x86/kernel/fpu/xstate.c index 28e4fd65c9da7..5f54a207ace46 100644 --- a/arch/x86/kernel/fpu/xstate.c +++ b/arch/x86/kernel/fpu/xstate.c @@ -1945,7 +1945,7 @@ static int dump_xsave_layout_desc(struct coredump_params *cprm) }; if (!dump_emit(cprm, &xc, sizeof(xc))) - return 0; + return -1; num_records++; } @@ -1983,7 +1983,7 @@ int elf_coredump_extra_notes_write(struct coredump_params *cprm) return 1; num_records = dump_xsave_layout_desc(cprm); - if (!num_records) + if (num_records < 0) return 1; /* Total size should be equal to the number of records */ From 425672fdb7b6f9897be6a7b1a077da1f9f2ecbe9 Mon Sep 17 00:00:00 2001 From: Tal Zussman Date: Fri, 12 Dec 2025 04:08:07 -0500 Subject: [PATCH 1170/2333] x86/mm/tlb/trace: Export the TLB_REMOTE_WRONG_CPU enum in [ Upstream commit 8b62e64e6d30fa047b3aefb1a36e1f80c8acb3d2 ] When the TLB_REMOTE_WRONG_CPU enum was introduced for the tlb_flush tracepoint, the enum was not exported to user-space. Add it to the appropriate macro definition to enable parsing by userspace tools, as per: Link: https://lore.kernel.org/all/20150403013802.220157513@goodmis.org [ mingo: Capitalize IPI, etc. ] Fixes: 2815a56e4b72 ("x86/mm/tlb: Add tracepoint for TLB flush IPI to stale CPU") Signed-off-by: Tal Zussman Signed-off-by: Ingo Molnar Reviewed-by: Steven Rostedt (Google) Reviewed-by: David Hildenbrand Reviewed-by: Rik van Riel Link: https://patch.msgid.link/20251212-tlb-trace-fix-v2-1-d322e0ad9b69@columbia.edu Signed-off-by: Sasha Levin --- include/trace/events/tlb.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/include/trace/events/tlb.h b/include/trace/events/tlb.h index b4d8e7dc38f88..fb83695116856 100644 --- a/include/trace/events/tlb.h +++ b/include/trace/events/tlb.h @@ -12,8 +12,9 @@ EM( TLB_FLUSH_ON_TASK_SWITCH, "flush on task switch" ) \ EM( TLB_REMOTE_SHOOTDOWN, "remote shootdown" ) \ EM( TLB_LOCAL_SHOOTDOWN, "local shootdown" ) \ - EM( TLB_LOCAL_MM_SHOOTDOWN, "local mm shootdown" ) \ - EMe( TLB_REMOTE_SEND_IPI, "remote ipi send" ) + EM( TLB_LOCAL_MM_SHOOTDOWN, "local MM shootdown" ) \ + EM( TLB_REMOTE_SEND_IPI, "remote IPI send" ) \ + EMe( TLB_REMOTE_WRONG_CPU, "remote wrong CPU" ) /* * First define the enums in TLB_FLUSH_REASON to be exported to userspace From 2068cf6f827650071f32c411045efd76bd40d73b Mon Sep 17 00:00:00 2001 From: Chancel Liu Date: Wed, 10 Dec 2025 15:21:09 +0900 Subject: [PATCH 1171/2333] ASoC: fsl_sai: Constrain sample rates from audio PLLs only in master mode [ Upstream commit 9f4d0899efd9892fc7514c9488270e1bb7dedd2b ] If SAI works in master mode it will generate clocks for external codec from audio PLLs. Thus sample rates should be constrained according to audio PLL clocks. While SAI works in slave mode which means clocks are generated externally then constraints are independent of audio PLLs. Fixes: 4edc98598be4 ("ASoC: fsl_sai: Add sample rate constraint") Signed-off-by: Chancel Liu Link: https://patch.msgid.link/20251210062109.2577735-1-chancel.liu@nxp.com Signed-off-by: Mark Brown Signed-off-by: Sasha Levin --- sound/soc/fsl/fsl_sai.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index 72bfc91e21b9b..86730c2149146 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -917,8 +917,14 @@ static int fsl_sai_startup(struct snd_pcm_substream *substream, tx ? sai->dma_params_tx.maxburst : sai->dma_params_rx.maxburst); - ret = snd_pcm_hw_constraint_list(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, &sai->constraint_rates); + if (sai->is_consumer_mode[tx]) + ret = snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, + &fsl_sai_rate_constraints); + else + ret = snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, + &sai->constraint_rates); return ret; } From 042e9e86d8e170bffd0f8aff7717cee55e33f797 Mon Sep 17 00:00:00 2001 From: Haotian Zhang Date: Mon, 15 Dec 2025 12:26:52 +0800 Subject: [PATCH 1172/2333] ALSA: vxpocket: Fix resource leak in vxpocket_probe error path [ Upstream commit 2a03b40deacbd293ac9aed0f9b11197dad54fe5f ] When vxpocket_config() fails, vxpocket_probe() returns the error code directly without freeing the sound card resources allocated by snd_card_new(), which leads to a memory leak. Add proper error handling to free the sound card and clear the allocation bit when vxpocket_config() fails. Fixes: 15b99ac17295 ("[PATCH] pcmcia: add return value to _config() functions") Signed-off-by: Haotian Zhang Link: https://patch.msgid.link/20251215042652.695-1-vulab@iscas.ac.cn Signed-off-by: Takashi Iwai Signed-off-by: Sasha Levin --- sound/pcmcia/vx/vxpocket.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/sound/pcmcia/vx/vxpocket.c b/sound/pcmcia/vx/vxpocket.c index 2e09f2a513a6a..9a5c9aa8eec4a 100644 --- a/sound/pcmcia/vx/vxpocket.c +++ b/sound/pcmcia/vx/vxpocket.c @@ -284,7 +284,13 @@ static int vxpocket_probe(struct pcmcia_device *p_dev) vxp->p_dev = p_dev; - return vxpocket_config(p_dev); + err = vxpocket_config(p_dev); + if (err < 0) { + card_alloc &= ~(1 << i); + snd_card_free(card); + return err; + } + return 0; } static void vxpocket_detach(struct pcmcia_device *link) From 499057a7cc6b33fd34a4a0339d48e3b09863ca6c Mon Sep 17 00:00:00 2001 From: Haotian Zhang Date: Mon, 15 Dec 2025 17:04:33 +0800 Subject: [PATCH 1173/2333] ALSA: pcmcia: Fix resource leak in snd_pdacf_probe error path [ Upstream commit 5032347c04ba7ff9ba878f262e075d745c06a2a8 ] When pdacf_config() fails, snd_pdacf_probe() returns the error code directly without freeing the sound card resources allocated by snd_card_new(), which leads to a memory leak. Add proper error handling to free the sound card and clear the card list entry when pdacf_config() fails. Fixes: 15b99ac17295 ("[PATCH] pcmcia: add return value to _config() functions") Suggested-by: Takashi Iwai Signed-off-by: Haotian Zhang Link: https://patch.msgid.link/20251215090433.211-1-vulab@iscas.ac.cn Signed-off-by: Takashi Iwai Signed-off-by: Sasha Levin --- sound/pcmcia/pdaudiocf/pdaudiocf.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf.c b/sound/pcmcia/pdaudiocf/pdaudiocf.c index 13419837dfb7c..a3291e626440e 100644 --- a/sound/pcmcia/pdaudiocf/pdaudiocf.c +++ b/sound/pcmcia/pdaudiocf/pdaudiocf.c @@ -131,7 +131,13 @@ static int snd_pdacf_probe(struct pcmcia_device *link) link->config_index = 1; link->config_regs = PRESENT_OPTION; - return pdacf_config(link); + err = pdacf_config(link); + if (err < 0) { + card_list[i] = NULL; + snd_card_free(card); + return err; + } + return 0; } From eaa95228b8a56c4880a182c0350d67922b22408f Mon Sep 17 00:00:00 2001 From: Shipei Qu Date: Wed, 17 Dec 2025 10:46:30 +0800 Subject: [PATCH 1174/2333] ALSA: usb-mixer: us16x08: validate meter packet indices [ Upstream commit 5526c1c6ba1d0913c7dfcbbd6fe1744ea7c55f1e ] get_meter_levels_from_urb() parses the 64-byte meter packets sent by the device and fills the per-channel arrays meter_level[], comp_level[] and master_level[] in struct snd_us16x08_meter_store. Currently the function derives the channel index directly from the meter packet (MUB2(meter_urb, s) - 1) and uses it to index those arrays without validating the range. If the packet contains a negative or out-of-range channel number, the driver may write past the end of these arrays. Introduce a local channel variable and validate it before updating the arrays. We reject negative indices, limit meter_level[] and comp_level[] to SND_US16X08_MAX_CHANNELS, and guard master_level[] updates with ARRAY_SIZE(master_level). Fixes: d2bb390a2081 ("ALSA: usb-audio: Tascam US-16x08 DSP mixer quirk") Reported-by: DARKNAVY (@DarkNavyOrg) Closes: https://lore.kernel.org/tencent_21C112743C44C1A2517FF219@qq.com Signed-off-by: Shipei Qu Link: https://patch.msgid.link/20251217024630.59576-1-qu@darknavy.com Signed-off-by: Takashi Iwai Signed-off-by: Sasha Levin --- sound/usb/mixer_us16x08.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/sound/usb/mixer_us16x08.c b/sound/usb/mixer_us16x08.c index 1c5712c31f5e2..f9df40730effd 100644 --- a/sound/usb/mixer_us16x08.c +++ b/sound/usb/mixer_us16x08.c @@ -655,17 +655,25 @@ static void get_meter_levels_from_urb(int s, u8 *meter_urb) { int val = MUC2(meter_urb, s) + (MUC3(meter_urb, s) << 8); + int ch = MUB2(meter_urb, s) - 1; + + if (ch < 0) + return; if (MUA0(meter_urb, s) == 0x61 && MUA1(meter_urb, s) == 0x02 && MUA2(meter_urb, s) == 0x04 && MUB0(meter_urb, s) == 0x62) { - if (MUC0(meter_urb, s) == 0x72) - store->meter_level[MUB2(meter_urb, s) - 1] = val; - if (MUC0(meter_urb, s) == 0xb2) - store->comp_level[MUB2(meter_urb, s) - 1] = val; + if (ch < SND_US16X08_MAX_CHANNELS) { + if (MUC0(meter_urb, s) == 0x72) + store->meter_level[ch] = val; + if (MUC0(meter_urb, s) == 0xb2) + store->comp_level[ch] = val; + } } if (MUA0(meter_urb, s) == 0x61 && MUA1(meter_urb, s) == 0x02 && - MUA2(meter_urb, s) == 0x02 && MUB0(meter_urb, s) == 0x62) - store->master_level[MUB2(meter_urb, s) - 1] = val; + MUA2(meter_urb, s) == 0x02 && MUB0(meter_urb, s) == 0x62) { + if (ch < ARRAY_SIZE(store->master_level)) + store->master_level[ch] = val; + } } /* Function to retrieve current meter values from the device. From 74fd0ae1a7de0a0da236877acd23e22f54d7d084 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Tue, 16 Dec 2025 15:02:01 +0800 Subject: [PATCH 1175/2333] ASoC: ak4458: remove the reset operation in probe and remove [ Upstream commit 00b960a83c764208b0623089eb70af3685e3906f ] The reset_control handler has the reference count for usage, as there is reset operation in runtime suspend and resume, then reset operation in probe() would cause the reference count of reset not balanced. Previously add reset operation in probe and remove is to fix the compile issue with !CONFIG_PM, as the driver has been update to use RUNTIME_PM_OPS(), so that change can be reverted. Fixes: 1e0dff741b0a ("ASoC: ak4458: remove "reset-gpios" property handler") Signed-off-by: Shengjiu Wang Link: https://patch.msgid.link/20251216070201.358477-1-shengjiu.wang@nxp.com Signed-off-by: Mark Brown Signed-off-by: Sasha Levin --- sound/soc/codecs/ak4458.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/sound/soc/codecs/ak4458.c b/sound/soc/codecs/ak4458.c index a6c04dd3de3ed..abe742edb10fe 100644 --- a/sound/soc/codecs/ak4458.c +++ b/sound/soc/codecs/ak4458.c @@ -783,16 +783,12 @@ static int ak4458_i2c_probe(struct i2c_client *i2c) pm_runtime_enable(&i2c->dev); regcache_cache_only(ak4458->regmap, true); - ak4458_reset(ak4458, false); return 0; } static void ak4458_i2c_remove(struct i2c_client *i2c) { - struct ak4458_priv *ak4458 = i2c_get_clientdata(i2c); - - ak4458_reset(ak4458, true); pm_runtime_disable(&i2c->dev); } From 523c21a04c1764ac231c29ddb911335a8430849e Mon Sep 17 00:00:00 2001 From: Shardul Bankar Date: Mon, 17 Nov 2025 17:41:21 +0530 Subject: [PATCH 1176/2333] nfsd: fix memory leak in nfsd_create_serv error paths [ Upstream commit df8d829bba3adcf3cc744c01d933b6fd7cf06e91 ] When nfsd_create_serv() calls percpu_ref_init() to initialize nn->nfsd_net_ref, it allocates both a percpu reference counter and a percpu_ref_data structure (64 bytes). However, if the function fails later due to svc_create_pooled() returning NULL or svc_bind() returning an error, these allocations are not cleaned up, resulting in a memory leak. The leak manifests as: - Unreferenced percpu allocation (8 bytes per CPU) - Unreferenced percpu_ref_data structure (64 bytes) Fix this by adding percpu_ref_exit() calls in both error paths to properly clean up the percpu_ref_init() allocations. This patch fixes the percpu_ref leak in nfsd_create_serv() seen as an auxiliary leak in syzbot report 099461f8558eb0a1f4f3; the prepare_creds() and vsock-related leaks in the same report remain to be addressed separately. Reported-by: syzbot+099461f8558eb0a1f4f3@syzkaller.appspotmail.com Link: https://syzkaller.appspot.com/bug?extid=099461f8558eb0a1f4f3 Fixes: 47e988147f40 ("nfsd: add nfsd_serv_try_get and nfsd_serv_put") Signed-off-by: Shardul Bankar Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever Signed-off-by: Sasha Levin --- fs/nfsd/nfssvc.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 7057ddd7a0a87..32cc03a7e7bec 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -633,12 +633,15 @@ int nfsd_create_serv(struct net *net) serv = svc_create_pooled(nfsd_programs, ARRAY_SIZE(nfsd_programs), &nn->nfsd_svcstats, nfsd_max_blksize, nfsd); - if (serv == NULL) + if (serv == NULL) { + percpu_ref_exit(&nn->nfsd_net_ref); return -ENOMEM; + } error = svc_bind(serv, net); if (error < 0) { svc_destroy(&serv); + percpu_ref_exit(&nn->nfsd_net_ref); return error; } spin_lock(&nfsd_notifier_lock); From aa0449550e1ea938d64057d64e00c29cf4a76c57 Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Thu, 6 Nov 2025 17:33:35 +0800 Subject: [PATCH 1177/2333] ASoC: SDCA: support Q7.8 volume format [ Upstream commit 1b0f3f9ee41ee2bdd206667f85ea2aa36dfe6e69 ] The SDCA specification uses Q7.8 volume format. This patch adds a field to indicate whether it is SDCA volume control and supports the volume settings. Signed-off-by: Shuming Fan Reviewed-by: Charles Keepax Link: https://patch.msgid.link/20251106093335.1363237-1-shumingf@realtek.com Signed-off-by: Mark Brown Stable-dep-of: 095d62114182 ("ASoC: ops: fix snd_soc_get_volsw for sx controls") Signed-off-by: Sasha Levin --- include/sound/soc.h | 1 + sound/soc/sdca/sdca_asoc.c | 34 ++++++--------------- sound/soc/soc-ops.c | 62 +++++++++++++++++++++++++++++++------- 3 files changed, 61 insertions(+), 36 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index ddc508ff7b9be..a9c058b06ab42 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1225,6 +1225,7 @@ struct soc_mixer_control { unsigned int sign_bit; unsigned int invert:1; unsigned int autodisable:1; + unsigned int sdca_q78:1; #ifdef CONFIG_SND_SOC_TOPOLOGY struct snd_soc_dobj dobj; #endif diff --git a/sound/soc/sdca/sdca_asoc.c b/sound/soc/sdca/sdca_asoc.c index c493ec530cc5c..892b7c028faea 100644 --- a/sound/soc/sdca/sdca_asoc.c +++ b/sound/soc/sdca/sdca_asoc.c @@ -795,7 +795,6 @@ static int control_limit_kctl(struct device *dev, struct sdca_control_range *range; int min, max, step; unsigned int *tlv; - int shift; if (control->type != SDCA_CTL_DATATYPE_Q7P8DB) return 0; @@ -814,37 +813,22 @@ static int control_limit_kctl(struct device *dev, min = sign_extend32(min, control->nbits - 1); max = sign_extend32(max, control->nbits - 1); - /* - * FIXME: Only support power of 2 step sizes as this can be supported - * by a simple shift. - */ - if (hweight32(step) != 1) { - dev_err(dev, "%s: %s: currently unsupported step size\n", - entity->label, control->label); - return -EINVAL; - } - - /* - * The SDCA volumes are in steps of 1/256th of a dB, a step down of - * 64 (shift of 6) gives 1/4dB. 1/4dB is the smallest unit that is also - * representable in the ALSA TLVs which are in 1/100ths of a dB. - */ - shift = max(ffs(step) - 1, 6); - tlv = devm_kcalloc(dev, 4, sizeof(*tlv), GFP_KERNEL); if (!tlv) return -ENOMEM; - tlv[0] = SNDRV_CTL_TLVT_DB_SCALE; + tlv[0] = SNDRV_CTL_TLVT_DB_MINMAX; tlv[1] = 2 * sizeof(*tlv); tlv[2] = (min * 100) >> 8; - tlv[3] = ((1 << shift) * 100) >> 8; + tlv[3] = (max * 100) >> 8; + + step = (step * 100) >> 8; - mc->min = min >> shift; - mc->max = max >> shift; - mc->shift = shift; - mc->rshift = shift; - mc->sign_bit = 15 - shift; + mc->min = ((int)tlv[2] / step); + mc->max = ((int)tlv[3] / step); + mc->shift = step; + mc->sign_bit = 15; + mc->sdca_q78 = 1; kctl->tlv.p = tlv; kctl->access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ; diff --git a/sound/soc/soc-ops.c b/sound/soc/soc-ops.c index d2b6fb8e0b6c6..ce86978c158d6 100644 --- a/sound/soc/soc-ops.c +++ b/sound/soc/soc-ops.c @@ -110,6 +110,36 @@ int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol, } EXPORT_SYMBOL_GPL(snd_soc_put_enum_double); +static int sdca_soc_q78_reg_to_ctl(struct soc_mixer_control *mc, unsigned int reg_val, + unsigned int mask, unsigned int shift, int max) +{ + int val = reg_val; + + if (WARN_ON(!mc->shift)) + return -EINVAL; + + val = sign_extend32(val, mc->sign_bit); + val = (((val * 100) >> 8) / (int)mc->shift); + val -= mc->min; + + return val & mask; +} + +static unsigned int sdca_soc_q78_ctl_to_reg(struct soc_mixer_control *mc, int val, + unsigned int mask, unsigned int shift, int max) +{ + unsigned int ret_val; + int reg_val; + + if (WARN_ON(!mc->shift)) + return -EINVAL; + + reg_val = val + mc->min; + ret_val = (int)((reg_val * mc->shift) << 8) / 100; + + return ret_val & mask; +} + static int soc_mixer_reg_to_ctl(struct soc_mixer_control *mc, unsigned int reg_val, unsigned int mask, unsigned int shift, int max) { @@ -197,19 +227,27 @@ static int soc_put_volsw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol, struct soc_mixer_control *mc, int mask, int max) { + unsigned int (*ctl_to_reg)(struct soc_mixer_control *, int, unsigned int, unsigned int, int); struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); unsigned int val1, val_mask; unsigned int val2 = 0; bool double_r = false; int ret; + if (mc->sdca_q78) { + ctl_to_reg = sdca_soc_q78_ctl_to_reg; + val_mask = mask; + } else { + ctl_to_reg = soc_mixer_ctl_to_reg; + val_mask = mask << mc->shift; + } + ret = soc_mixer_valid_ctl(mc, ucontrol->value.integer.value[0], max); if (ret) return ret; - val1 = soc_mixer_ctl_to_reg(mc, ucontrol->value.integer.value[0], + val1 = ctl_to_reg(mc, ucontrol->value.integer.value[0], mask, mc->shift, max); - val_mask = mask << mc->shift; if (snd_soc_volsw_is_stereo(mc)) { ret = soc_mixer_valid_ctl(mc, ucontrol->value.integer.value[1], max); @@ -217,14 +255,10 @@ static int soc_put_volsw(struct snd_kcontrol *kcontrol, return ret; if (mc->reg == mc->rreg) { - val1 |= soc_mixer_ctl_to_reg(mc, - ucontrol->value.integer.value[1], - mask, mc->rshift, max); + val1 |= ctl_to_reg(mc, ucontrol->value.integer.value[1], mask, mc->rshift, max); val_mask |= mask << mc->rshift; } else { - val2 = soc_mixer_ctl_to_reg(mc, - ucontrol->value.integer.value[1], - mask, mc->shift, max); + val2 = ctl_to_reg(mc, ucontrol->value.integer.value[1], mask, mc->shift, max); double_r = true; } } @@ -248,21 +282,27 @@ static int soc_get_volsw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol, struct soc_mixer_control *mc, int mask, int max) { + int (*reg_to_ctl)(struct soc_mixer_control *, unsigned int, unsigned int, unsigned int, int); struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); unsigned int reg_val; int val; + if (mc->sdca_q78) + reg_to_ctl = sdca_soc_q78_reg_to_ctl; + else + reg_to_ctl = soc_mixer_reg_to_ctl; + reg_val = snd_soc_component_read(component, mc->reg); - val = soc_mixer_reg_to_ctl(mc, reg_val, mask, mc->shift, max); + val = reg_to_ctl(mc, reg_val, mask, mc->shift, max); ucontrol->value.integer.value[0] = val; if (snd_soc_volsw_is_stereo(mc)) { if (mc->reg == mc->rreg) { - val = soc_mixer_reg_to_ctl(mc, reg_val, mask, mc->rshift, max); + val = reg_to_ctl(mc, reg_val, mask, mc->rshift, max); } else { reg_val = snd_soc_component_read(component, mc->rreg); - val = soc_mixer_reg_to_ctl(mc, reg_val, mask, mc->shift, max); + val = reg_to_ctl(mc, reg_val, mask, mc->shift, max); } ucontrol->value.integer.value[1] = val; From 8a9c52cbaf96417ecc48023318ffec0acef2f656 Mon Sep 17 00:00:00 2001 From: Stefan Binding Date: Tue, 16 Dec 2025 13:49:20 +0000 Subject: [PATCH 1178/2333] ASoC: ops: fix snd_soc_get_volsw for sx controls [ Upstream commit 095d621141826a2841dae85b52c784c147ea99d3 ] SX controls are currently broken, since the clamp introduced in commit a0ce874cfaaa ("ASoC: ops: improve snd_soc_get_volsw") does not handle SX controls, for example where the min value in the clamp is greater than the max value in the clamp. Add clamp parameter to prevent clamping in SX controls. The nature of SX controls mean that it wraps around 0, with a variable number of bits, therefore clamping the value becomes complicated and prone to error. Fixes 35 kunit tests for soc_ops_test_access. Fixes: a0ce874cfaaa ("ASoC: ops: improve snd_soc_get_volsw") Co-developed-by: Charles Keepax Signed-off-by: Stefan Binding Tested-by: Peter Ujfalusi Link: https://patch.msgid.link/20251216134938.788625-1-sbinding@opensource.cirrus.com Signed-off-by: Mark Brown Signed-off-by: Sasha Levin --- sound/soc/soc-ops.c | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/sound/soc/soc-ops.c b/sound/soc/soc-ops.c index ce86978c158d6..624e9269fc25b 100644 --- a/sound/soc/soc-ops.c +++ b/sound/soc/soc-ops.c @@ -111,7 +111,8 @@ int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol, EXPORT_SYMBOL_GPL(snd_soc_put_enum_double); static int sdca_soc_q78_reg_to_ctl(struct soc_mixer_control *mc, unsigned int reg_val, - unsigned int mask, unsigned int shift, int max) + unsigned int mask, unsigned int shift, int max, + bool sx) { int val = reg_val; @@ -141,20 +142,26 @@ static unsigned int sdca_soc_q78_ctl_to_reg(struct soc_mixer_control *mc, int va } static int soc_mixer_reg_to_ctl(struct soc_mixer_control *mc, unsigned int reg_val, - unsigned int mask, unsigned int shift, int max) + unsigned int mask, unsigned int shift, int max, + bool sx) { int val = (reg_val >> shift) & mask; if (mc->sign_bit) val = sign_extend32(val, mc->sign_bit); - val = clamp(val, mc->min, mc->max); - val -= mc->min; + if (sx) { + val -= mc->min; // SX controls intentionally can overflow here + val = min_t(unsigned int, val & mask, max); + } else { + val = clamp(val, mc->min, mc->max); + val -= mc->min; + } if (mc->invert) val = max - val; - return val & mask; + return val; } static unsigned int soc_mixer_ctl_to_reg(struct soc_mixer_control *mc, int val, @@ -280,9 +287,10 @@ static int soc_put_volsw(struct snd_kcontrol *kcontrol, static int soc_get_volsw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol, - struct soc_mixer_control *mc, int mask, int max) + struct soc_mixer_control *mc, int mask, int max, bool sx) { - int (*reg_to_ctl)(struct soc_mixer_control *, unsigned int, unsigned int, unsigned int, int); + int (*reg_to_ctl)(struct soc_mixer_control *, unsigned int, unsigned int, + unsigned int, int, bool); struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); unsigned int reg_val; int val; @@ -293,16 +301,16 @@ static int soc_get_volsw(struct snd_kcontrol *kcontrol, reg_to_ctl = soc_mixer_reg_to_ctl; reg_val = snd_soc_component_read(component, mc->reg); - val = reg_to_ctl(mc, reg_val, mask, mc->shift, max); + val = reg_to_ctl(mc, reg_val, mask, mc->shift, max, sx); ucontrol->value.integer.value[0] = val; if (snd_soc_volsw_is_stereo(mc)) { if (mc->reg == mc->rreg) { - val = reg_to_ctl(mc, reg_val, mask, mc->rshift, max); + val = reg_to_ctl(mc, reg_val, mask, mc->rshift, max, sx); } else { reg_val = snd_soc_component_read(component, mc->rreg); - val = reg_to_ctl(mc, reg_val, mask, mc->shift, max); + val = reg_to_ctl(mc, reg_val, mask, mc->shift, max, sx); } ucontrol->value.integer.value[1] = val; @@ -371,7 +379,7 @@ int snd_soc_get_volsw(struct snd_kcontrol *kcontrol, (struct soc_mixer_control *)kcontrol->private_value; unsigned int mask = soc_mixer_mask(mc); - return soc_get_volsw(kcontrol, ucontrol, mc, mask, mc->max - mc->min); + return soc_get_volsw(kcontrol, ucontrol, mc, mask, mc->max - mc->min, false); } EXPORT_SYMBOL_GPL(snd_soc_get_volsw); @@ -413,7 +421,7 @@ int snd_soc_get_volsw_sx(struct snd_kcontrol *kcontrol, (struct soc_mixer_control *)kcontrol->private_value; unsigned int mask = soc_mixer_sx_mask(mc); - return soc_get_volsw(kcontrol, ucontrol, mc, mask, mc->max); + return soc_get_volsw(kcontrol, ucontrol, mc, mask, mc->max, true); } EXPORT_SYMBOL_GPL(snd_soc_get_volsw_sx); From 235ae3fc9e9c9fbcd4245ec6f6b5423ed47fcda9 Mon Sep 17 00:00:00 2001 From: Jinhui Guo Date: Tue, 30 Sep 2025 15:42:37 +0800 Subject: [PATCH 1179/2333] ipmi: Fix the race between __scan_channels() and deliver_response() [ Upstream commit 936750fdba4c45e13bbd17f261bb140dd55f5e93 ] The race window between __scan_channels() and deliver_response() causes the parameters of some channels to be set to 0. 1.[CPUA] __scan_channels() issues an IPMI request and waits with wait_event() until all channels have been scanned. wait_event() internally calls might_sleep(), which might yield the CPU. (Moreover, an interrupt can preempt wait_event() and force the task to yield the CPU.) 2.[CPUB] deliver_response() is invoked when the CPU receives the IPMI response. After processing a IPMI response, deliver_response() directly assigns intf->wchannels to intf->channel_list and sets intf->channels_ready to true. However, not all channels are actually ready for use. 3.[CPUA] Since intf->channels_ready is already true, wait_event() never enters __wait_event(). __scan_channels() immediately clears intf->null_user_handler and exits. 4.[CPUB] Once intf->null_user_handler is set to NULL, deliver_response() ignores further IPMI responses, leaving the remaining channels zero-initialized and unusable. CPUA CPUB ------------------------------- ----------------------------- __scan_channels() intf->null_user_handler = channel_handler; send_channel_info_cmd(intf, 0); wait_event(intf->waitq, intf->channels_ready); do { might_sleep(); deliver_response() channel_handler() intf->channel_list = intf->wchannels + set; intf->channels_ready = true; send_channel_info_cmd(intf, intf->curr_channel); if (condition) break; __wait_event(wq_head, condition); } while(0) intf->null_user_handler = NULL; deliver_response() if (!msg->user) if (intf->null_user_handler) rv = -EINVAL; return rv; ------------------------------- ----------------------------- Fix the race between __scan_channels() and deliver_response() by deferring both the assignment intf->channel_list = intf->wchannels and the flag intf->channels_ready = true until all channels have been successfully scanned or until the IPMI request has failed. Signed-off-by: Jinhui Guo Message-ID: <20250930074239.2353-2-guojinhui.liam@bytedance.com> Signed-off-by: Corey Minyard Signed-off-by: Sasha Levin --- drivers/char/ipmi/ipmi_msghandler.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index 3700ab4eba3e7..d3f84deee4513 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -3417,8 +3417,6 @@ channel_handler(struct ipmi_smi *intf, struct ipmi_recv_msg *msg) intf->channels_ready = true; wake_up(&intf->waitq); } else { - intf->channel_list = intf->wchannels + set; - intf->channels_ready = true; rv = send_channel_info_cmd(intf, intf->curr_channel); } From eb8d9fb6280dac6df702e0899b590b4daadf2e8a Mon Sep 17 00:00:00 2001 From: Jinhui Guo Date: Tue, 30 Sep 2025 15:42:38 +0800 Subject: [PATCH 1180/2333] ipmi: Fix __scan_channels() failing to rescan channels [ Upstream commit 6bd30d8fc523fb880b4be548e8501bc0fe8f42d4 ] channel_handler() sets intf->channels_ready to true but never clears it, so __scan_channels() skips any rescan. When the BMC firmware changes a rescan is required. Allow it by clearing the flag before starting a new scan. Signed-off-by: Jinhui Guo Message-ID: <20250930074239.2353-3-guojinhui.liam@bytedance.com> Signed-off-by: Corey Minyard Signed-off-by: Sasha Levin --- drivers/char/ipmi/ipmi_msghandler.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index d3f84deee4513..0a886399f9daf 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -599,7 +599,8 @@ static void __ipmi_bmc_unregister(struct ipmi_smi *intf); static int __ipmi_bmc_register(struct ipmi_smi *intf, struct ipmi_device_id *id, bool guid_set, guid_t *guid, int intf_num); -static int __scan_channels(struct ipmi_smi *intf, struct ipmi_device_id *id); +static int __scan_channels(struct ipmi_smi *intf, + struct ipmi_device_id *id, bool rescan); static void free_ipmi_user(struct kref *ref) { @@ -2668,7 +2669,7 @@ static int __bmc_get_device_id(struct ipmi_smi *intf, struct bmc_device *bmc, if (__ipmi_bmc_register(intf, &id, guid_set, &guid, intf_num)) need_waiter(intf); /* Retry later on an error. */ else - __scan_channels(intf, &id); + __scan_channels(intf, &id, false); if (!intf_set) { @@ -2688,7 +2689,7 @@ static int __bmc_get_device_id(struct ipmi_smi *intf, struct bmc_device *bmc, goto out_noprocessing; } else if (memcmp(&bmc->fetch_id, &bmc->id, sizeof(bmc->id))) /* Version info changes, scan the channels again. */ - __scan_channels(intf, &bmc->fetch_id); + __scan_channels(intf, &bmc->fetch_id, true); bmc->dyn_id_expiry = jiffies + IPMI_DYN_DEV_ID_EXPIRY; @@ -3438,10 +3439,17 @@ channel_handler(struct ipmi_smi *intf, struct ipmi_recv_msg *msg) /* * Must be holding intf->bmc_reg_mutex to call this. */ -static int __scan_channels(struct ipmi_smi *intf, struct ipmi_device_id *id) +static int __scan_channels(struct ipmi_smi *intf, + struct ipmi_device_id *id, + bool rescan) { int rv; + if (rescan) { + /* Clear channels_ready to force channels rescan. */ + intf->channels_ready = false; + } + if (ipmi_version_major(id) > 1 || (ipmi_version_major(id) == 1 && ipmi_version_minor(id) >= 5)) { @@ -3656,7 +3664,7 @@ int ipmi_add_smi(struct module *owner, } mutex_lock(&intf->bmc_reg_mutex); - rv = __scan_channels(intf, &id); + rv = __scan_channels(intf, &id, false); mutex_unlock(&intf->bmc_reg_mutex); if (rv) goto out_err_bmc_reg; From 9f2ff08737c4bf99b784adc921de9a64a03984c3 Mon Sep 17 00:00:00 2001 From: Peter Wang Date: Wed, 24 Sep 2025 17:43:27 +0800 Subject: [PATCH 1181/2333] scsi: ufs: host: mediatek: Fix shutdown/suspend race condition [ Upstream commit 014de20bb36ba03e0e0b0a7e0a1406ab900c9fda ] Address a race condition between shutdown and suspend operations in the UFS Mediatek driver. Before entering suspend, check if a shutdown is in progress to prevent conflicts and ensure system stability. Signed-off-by: Peter Wang Acked-by: Chun-Hung Wu Link: https://patch.msgid.link/20250924094527.2992256-6-peter.wang@mediatek.com Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin --- drivers/ufs/host/ufs-mediatek.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/ufs/host/ufs-mediatek.c b/drivers/ufs/host/ufs-mediatek.c index 758a393a9de1a..d0cbd96ad29dc 100644 --- a/drivers/ufs/host/ufs-mediatek.c +++ b/drivers/ufs/host/ufs-mediatek.c @@ -2373,6 +2373,11 @@ static int ufs_mtk_system_suspend(struct device *dev) struct arm_smccc_res res; int ret; + if (hba->shutting_down) { + ret = -EBUSY; + goto out; + } + ret = ufshcd_system_suspend(dev); if (ret) goto out; From 64b989a051b00d7babecb7f8574c6034e15bdc80 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Fri, 17 Oct 2025 09:56:26 +0800 Subject: [PATCH 1182/2333] firmware: imx: scu-irq: Init workqueue before request mbox channel [ Upstream commit 81fb53feb66a3aefbf6fcab73bb8d06f5b0c54ad ] With mailbox channel requested, there is possibility that interrupts may come in, so need to make sure the workqueue is initialized before the queue is scheduled by mailbox rx callback. Reviewed-by: Frank Li Signed-off-by: Peng Fan Signed-off-by: Shawn Guo Signed-off-by: Sasha Levin --- drivers/firmware/imx/imx-scu-irq.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/firmware/imx/imx-scu-irq.c b/drivers/firmware/imx/imx-scu-irq.c index f2b902e95b738..b9f6128d56f70 100644 --- a/drivers/firmware/imx/imx-scu-irq.c +++ b/drivers/firmware/imx/imx-scu-irq.c @@ -214,6 +214,8 @@ int imx_scu_enable_general_irq_channel(struct device *dev) cl->dev = dev; cl->rx_callback = imx_scu_irq_callback; + INIT_WORK(&imx_sc_irq_work, imx_scu_irq_work_handler); + /* SCU general IRQ uses general interrupt channel 3 */ ch = mbox_request_channel_byname(cl, "gip3"); if (IS_ERR(ch)) { @@ -223,8 +225,6 @@ int imx_scu_enable_general_irq_channel(struct device *dev) return ret; } - INIT_WORK(&imx_sc_irq_work, imx_scu_irq_work_handler); - if (!of_parse_phandle_with_args(dev->of_node, "mboxes", "#mbox-cells", 0, &spec)) { i = of_alias_get_id(spec.np, "mu"); From dbbf6d47130674640cd12a0781a0fb2a575d0e44 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 24 Sep 2025 11:32:13 +0200 Subject: [PATCH 1183/2333] um: init cpu_tasks[] earlier [ Upstream commit 7b5d4416964c07c902163822a30a622111172b01 ] This is currently done in uml_finishsetup(), but e.g. with KCOV enabled we'll crash because some init code can call into e.g. memparse(), which has coverage annotations, and then the checks in check_kcov_mode() crash because current is NULL. Simply initialize the cpu_tasks[] array statically, which fixes the crash. For the later SMP work, it seems to have not really caused any problems yet, but initialize all of the entries anyway. Link: https://patch.msgid.link/20250924113214.c76cd74d0583.I974f691ebb1a2b47915bd2b04cc38e5263b9447f@changeid Signed-off-by: Johannes Berg Signed-off-by: Sasha Levin --- arch/um/kernel/process.c | 4 +++- arch/um/kernel/um_arch.c | 2 -- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c index 9c9c66dc45f05..13d461712c997 100644 --- a/arch/um/kernel/process.c +++ b/arch/um/kernel/process.c @@ -43,7 +43,9 @@ * cares about its entry, so it's OK if another processor is modifying its * entry. */ -struct task_struct *cpu_tasks[NR_CPUS]; +struct task_struct *cpu_tasks[NR_CPUS] = { + [0 ... NR_CPUS - 1] = &init_task, +}; EXPORT_SYMBOL(cpu_tasks); void free_stack(unsigned long stack, int order) diff --git a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c index cfbbbf8500c34..ed2f67848a50e 100644 --- a/arch/um/kernel/um_arch.c +++ b/arch/um/kernel/um_arch.c @@ -239,8 +239,6 @@ static struct notifier_block panic_exit_notifier = { void uml_finishsetup(void) { - cpu_tasks[0] = &init_task; - atomic_notifier_chain_register(&panic_notifier_list, &panic_exit_notifier); From 15108657bce0ac6111c0beb17246c563648f2d0d Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Mon, 25 Aug 2025 15:11:13 +0200 Subject: [PATCH 1184/2333] ti-sysc: allow OMAP2 and OMAP4 timers to be reserved on AM33xx [ Upstream commit 3f61783920504b2cf99330b372d82914bb004d8e ] am33xx.dtsi has the same clock setup as am35xx.dtsi, setting ti,no-reset-on-init and ti,no-idle on timer1_target and timer2_target, so AM33 needs the same workaround as AM35 to avoid ti-sysc probe failing on certain target modules. Signed-off-by: Matthias Schiffer Signed-off-by: Alexander Stein Link: https://lore.kernel.org/r/20250825131114.2206804-1-alexander.stein@ew.tq-group.com Signed-off-by: Kevin Hilman Signed-off-by: Sasha Levin --- drivers/bus/ti-sysc.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/bus/ti-sysc.c b/drivers/bus/ti-sysc.c index 5566ad11399e7..610354ce7f8f0 100644 --- a/drivers/bus/ti-sysc.c +++ b/drivers/bus/ti-sysc.c @@ -48,6 +48,7 @@ enum sysc_soc { SOC_UNKNOWN, SOC_2420, SOC_2430, + SOC_AM33, SOC_3430, SOC_AM35, SOC_3630, @@ -2912,6 +2913,7 @@ static void ti_sysc_idle(struct work_struct *work) static const struct soc_device_attribute sysc_soc_match[] = { SOC_FLAG("OMAP242*", SOC_2420), SOC_FLAG("OMAP243*", SOC_2430), + SOC_FLAG("AM33*", SOC_AM33), SOC_FLAG("AM35*", SOC_AM35), SOC_FLAG("OMAP3[45]*", SOC_3430), SOC_FLAG("OMAP3[67]*", SOC_3630), @@ -3117,10 +3119,15 @@ static int sysc_check_active_timer(struct sysc *ddata) * can be dropped if we stop supporting old beagleboard revisions * A to B4 at some point. */ - if (sysc_soc->soc == SOC_3430 || sysc_soc->soc == SOC_AM35) + switch (sysc_soc->soc) { + case SOC_AM33: + case SOC_3430: + case SOC_AM35: error = -ENXIO; - else + break; + default: error = -EBUSY; + } if ((ddata->cfg.quirks & SYSC_QUIRK_NO_RESET_ON_INIT) && (ddata->cfg.quirks & SYSC_QUIRK_NO_IDLE)) From 4ca4c0b6c34ffc5cfd99312d751c95fc693c92e8 Mon Sep 17 00:00:00 2001 From: David Strahan Date: Thu, 6 Nov 2025 10:38:21 -0600 Subject: [PATCH 1185/2333] scsi: smartpqi: Add support for Hurray Data new controller PCI device [ Upstream commit 48e6b7e708029cea451e53a8c16fc8c16039ecdc ] Add support for new Hurray Data controller. All entries are in HEX. Add PCI IDs for Hurray Data controllers: VID / DID / SVID / SDID ---- ---- ---- ---- 9005 028f 207d 4840 Reviewed-by: Scott Benesh Reviewed-by: Scott Teel Reviewed-by: Mike McGowen Signed-off-by: David Strahan Signed-off-by: Don Brace Link: https://patch.msgid.link/20251106163823.786828-4-don.brace@microchip.com Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin --- drivers/scsi/smartpqi/smartpqi_init.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/scsi/smartpqi/smartpqi_init.c b/drivers/scsi/smartpqi/smartpqi_init.c index fdc856845a05d..98e93900254cb 100644 --- a/drivers/scsi/smartpqi/smartpqi_init.c +++ b/drivers/scsi/smartpqi/smartpqi_init.c @@ -10127,6 +10127,10 @@ static const struct pci_device_id pqi_pci_id_table[] = { PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, 0x207d, 0x4240) }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + 0x207d, 0x4840) + }, { PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, PCI_VENDOR_ID_ADVANTECH, 0x8312) From 5f9a7a00a2be5734ef0934566feabe17eb094786 Mon Sep 17 00:00:00 2001 From: Justin Tee Date: Thu, 6 Nov 2025 14:46:36 -0800 Subject: [PATCH 1186/2333] scsi: lpfc: Fix reusing an ndlp that is marked NLP_DROPPED during FLOGI [ Upstream commit 07caedc6a3887938813727beafea40f07c497705 ] It's possible for an unstable link to repeatedly bounce allowing a FLOGI retry, but then bounce again forcing an abort of the FLOGI. Ensure that the initial reference count on the FLOGI ndlp is restored in this faulty link scenario. Signed-off-by: Justin Tee Link: https://patch.msgid.link/20251106224639.139176-8-justintee8345@gmail.com Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin --- drivers/scsi/lpfc/lpfc_els.c | 36 +++++++++++++++++++++++++------- drivers/scsi/lpfc/lpfc_hbadisc.c | 4 +++- 2 files changed, 32 insertions(+), 8 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index b71db7d7d747d..c08237f04bce2 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -934,10 +934,15 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, /* Check to see if link went down during discovery */ if (lpfc_els_chk_latt(vport)) { /* One additional decrement on node reference count to - * trigger the release of the node + * trigger the release of the node. Make sure the ndlp + * is marked NLP_DROPPED. */ - if (!(ndlp->fc4_xpt_flags & SCSI_XPT_REGD)) + if (!test_bit(NLP_IN_DEV_LOSS, &ndlp->nlp_flag) && + !test_bit(NLP_DROPPED, &ndlp->nlp_flag) && + !(ndlp->fc4_xpt_flags & SCSI_XPT_REGD)) { + set_bit(NLP_DROPPED, &ndlp->nlp_flag); lpfc_nlp_put(ndlp); + } goto out; } @@ -995,9 +1000,10 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, IOERR_LOOP_OPEN_FAILURE))) lpfc_vlog_msg(vport, KERN_WARNING, LOG_ELS, "2858 FLOGI Status:x%x/x%x TMO" - ":x%x Data x%lx x%x\n", + ":x%x Data x%lx x%x x%lx x%x\n", ulp_status, ulp_word4, tmo, - phba->hba_flag, phba->fcf.fcf_flag); + phba->hba_flag, phba->fcf.fcf_flag, + ndlp->nlp_flag, ndlp->fc4_xpt_flags); /* Check for retry */ if (lpfc_els_retry(phba, cmdiocb, rspiocb)) { @@ -1015,14 +1021,17 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, * reference to trigger node release. */ if (!test_bit(NLP_IN_DEV_LOSS, &ndlp->nlp_flag) && - !(ndlp->fc4_xpt_flags & SCSI_XPT_REGD)) + !test_bit(NLP_DROPPED, &ndlp->nlp_flag) && + !(ndlp->fc4_xpt_flags & SCSI_XPT_REGD)) { + set_bit(NLP_DROPPED, &ndlp->nlp_flag); lpfc_nlp_put(ndlp); + } lpfc_printf_vlog(vport, KERN_WARNING, LOG_ELS, "0150 FLOGI Status:x%x/x%x " - "xri x%x TMO:x%x refcnt %d\n", + "xri x%x iotag x%x TMO:x%x refcnt %d\n", ulp_status, ulp_word4, cmdiocb->sli4_xritag, - tmo, kref_read(&ndlp->kref)); + cmdiocb->iotag, tmo, kref_read(&ndlp->kref)); /* If this is not a loop open failure, bail out */ if (!(ulp_status == IOSTAT_LOCAL_REJECT && @@ -1279,6 +1288,19 @@ lpfc_issue_els_flogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, uint32_t tmo, did; int rc; + /* It's possible for lpfc to reissue a FLOGI on an ndlp that is marked + * NLP_DROPPED. This happens when the FLOGI completed with the XB bit + * set causing lpfc to reference the ndlp until the XRI_ABORTED CQE is + * issued. The time window for the XRI_ABORTED CQE can be as much as + * 2*2*RA_TOV allowing for ndlp reuse of this type when the link is + * cycling quickly. When true, restore the initial reference and remove + * the NLP_DROPPED flag as lpfc is retrying. + */ + if (test_and_clear_bit(NLP_DROPPED, &ndlp->nlp_flag)) { + if (!lpfc_nlp_get(ndlp)) + return 1; + } + cmdsize = (sizeof(uint32_t) + sizeof(struct serv_parm)); elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp, ndlp->nlp_DID, ELS_CMD_FLOGI); diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 43d246c5c049c..717ae56c8e4bd 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -424,6 +424,7 @@ lpfc_check_nlp_post_devloss(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) { if (test_and_clear_bit(NLP_IN_RECOV_POST_DEV_LOSS, &ndlp->save_flags)) { + clear_bit(NLP_DROPPED, &ndlp->nlp_flag); lpfc_nlp_get(ndlp); lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY | LOG_NODE, "8438 Devloss timeout reversed on DID x%x " @@ -566,7 +567,8 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp) return fcf_inuse; } - lpfc_nlp_put(ndlp); + if (!test_and_set_bit(NLP_DROPPED, &ndlp->nlp_flag)) + lpfc_nlp_put(ndlp); return fcf_inuse; } From d45fcd38c692b13784a61e77d2e5ea5f4dacc79b Mon Sep 17 00:00:00 2001 From: Josua Mayer Date: Thu, 30 Oct 2025 16:16:26 +0100 Subject: [PATCH 1187/2333] clk: mvebu: cp110 add CLK_IGNORE_UNUSED to pcie_x10, pcie_x11 & pcie_x4 [ Upstream commit f0e6bc0c3ef4b4afb299bd6912586cafd5d864e9 ] CP110 based platforms rely on the bootloader for pci port initialization. TF-A actively prevents non-uboot re-configuration of pci lanes, and many boards do not have software control over the pci card reset. If a pci port had link at boot-time and the clock is stopped at a later point, the link fails and can not be recovered. PCI controller driver probe - and by extension ownership of a driver for the pci clocks - may be delayed especially on large modular kernels, causing the clock core to start disabling unused clocks. Add the CLK_IGNORE_UNUSED flag to the three pci port's clocks to ensure they are not stopped before the pci controller driver has taken ownership and tested for an existing link. This fixes failed pci link detection when controller driver probes late, e.g. with arm64 defconfig and CONFIG_PHY_MVEBU_CP110_COMPHY=m. Closes: https://lore.kernel.org/r/b71596c7-461b-44b6-89ab-3cfbd492639f@solid-run.com Signed-off-by: Josua Mayer Reviewed-by: Andrew Lunn Signed-off-by: Gregory CLEMENT Signed-off-by: Sasha Levin --- drivers/clk/mvebu/cp110-system-controller.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/drivers/clk/mvebu/cp110-system-controller.c b/drivers/clk/mvebu/cp110-system-controller.c index 03c59bf221060..b47c869060466 100644 --- a/drivers/clk/mvebu/cp110-system-controller.c +++ b/drivers/clk/mvebu/cp110-system-controller.c @@ -110,6 +110,25 @@ static const char * const gate_base_names[] = { [CP110_GATE_EIP197] = "eip197" }; +static unsigned long gate_flags(const u8 bit_idx) +{ + switch (bit_idx) { + case CP110_GATE_PCIE_X1_0: + case CP110_GATE_PCIE_X1_1: + case CP110_GATE_PCIE_X4: + /* + * If a port had an active link at boot time, stopping + * the clock creates a failed state from which controller + * driver can not recover. + * Prevent stopping this clock till after a driver has taken + * ownership. + */ + return CLK_IGNORE_UNUSED; + default: + return 0; + } +}; + struct cp110_gate_clk { struct clk_hw hw; struct regmap *regmap; @@ -171,6 +190,7 @@ static struct clk_hw *cp110_register_gate(const char *name, init.ops = &cp110_gate_ops; init.parent_names = &parent_name; init.num_parents = 1; + init.flags = gate_flags(bit_idx); gate->regmap = regmap; gate->bit_idx = bit_idx; From 095704d7f334d2efcc0a225ce086a6d423523935 Mon Sep 17 00:00:00 2001 From: Ben Collins Date: Mon, 21 Apr 2025 22:31:13 -0400 Subject: [PATCH 1188/2333] powerpc/addnote: Fix overflow on 32-bit builds [ Upstream commit 825ce89a3ef17f84cf2c0eacfa6b8dc9fd11d13f ] The PUT_64[LB]E() macros need to cast the value to unsigned long long like the GET_64[LB]E() macros. Caused lots of warnings when compiled on 32-bit, and clobbered addresses (36-bit P4080). Signed-off-by: Ben Collins Reviewed-by: Christophe Leroy Signed-off-by: Madhavan Srinivasan Link: https://patch.msgid.link/2025042122-mustard-wrasse-694572@boujee-and-buff Signed-off-by: Sasha Levin --- arch/powerpc/boot/addnote.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/arch/powerpc/boot/addnote.c b/arch/powerpc/boot/addnote.c index 53b3b2621457d..78704927453aa 100644 --- a/arch/powerpc/boot/addnote.c +++ b/arch/powerpc/boot/addnote.c @@ -68,8 +68,8 @@ static int e_class = ELFCLASS32; #define PUT_16BE(off, v)(buf[off] = ((v) >> 8) & 0xff, \ buf[(off) + 1] = (v) & 0xff) #define PUT_32BE(off, v)(PUT_16BE((off), (v) >> 16L), PUT_16BE((off) + 2, (v))) -#define PUT_64BE(off, v)((PUT_32BE((off), (v) >> 32L), \ - PUT_32BE((off) + 4, (v)))) +#define PUT_64BE(off, v)((PUT_32BE((off), (unsigned long long)(v) >> 32L), \ + PUT_32BE((off) + 4, (unsigned long long)(v)))) #define GET_16LE(off) ((buf[off]) + (buf[(off)+1] << 8)) #define GET_32LE(off) (GET_16LE(off) + (GET_16LE((off)+2U) << 16U)) @@ -78,7 +78,8 @@ static int e_class = ELFCLASS32; #define PUT_16LE(off, v) (buf[off] = (v) & 0xff, \ buf[(off) + 1] = ((v) >> 8) & 0xff) #define PUT_32LE(off, v) (PUT_16LE((off), (v)), PUT_16LE((off) + 2, (v) >> 16L)) -#define PUT_64LE(off, v) (PUT_32LE((off), (v)), PUT_32LE((off) + 4, (v) >> 32L)) +#define PUT_64LE(off, v) (PUT_32LE((off), (unsigned long long)(v)), \ + PUT_32LE((off) + 4, (unsigned long long)(v) >> 32L)) #define GET_16(off) (e_data == ELFDATA2MSB ? GET_16BE(off) : GET_16LE(off)) #define GET_32(off) (e_data == ELFDATA2MSB ? GET_32BE(off) : GET_32LE(off)) From 45185214175c72da7b9d37f8374a6e1294f33302 Mon Sep 17 00:00:00 2001 From: Tony Battersby Date: Mon, 10 Nov 2025 10:50:05 -0500 Subject: [PATCH 1189/2333] scsi: qla2xxx: Fix lost interrupts with qlini_mode=disabled [ Upstream commit 4f6aaade2a22ac428fa99ed716cf2b87e79c9837 ] When qla2xxx is loaded with qlini_mode=disabled, ha->flags.disable_msix_handshake is used before it is set, resulting in the wrong interrupt handler being used on certain HBAs (qla2xxx_msix_rsp_q_hs() is used when qla2xxx_msix_rsp_q() should be used). The only difference between these two interrupt handlers is that the _hs() version writes to a register to clear the "RISC" interrupt, whereas the other version does not. So this bug results in the RISC interrupt being cleared when it should not be. This occasionally causes a different interrupt handler qla24xx_msix_default() for a different vector to see ((stat & HSRX_RISC_INT) == 0) and ignore its interrupt, which then causes problems like: qla2xxx [0000:02:00.0]-d04c:6: MBX Command timeout for cmd 20, iocontrol=8 jiffies=1090c0300 mb[0-3]=[0x4000 0x0 0x40 0xda] mb7 0x500 host_status 0x40000010 hccr 0x3f00 qla2xxx [0000:02:00.0]-101e:6: Mailbox cmd timeout occurred, cmd=0x20, mb[0]=0x20. Scheduling ISP abort (the cmd varies; sometimes it is 0x20, 0x22, 0x54, 0x5a, 0x5d, or 0x6a) This problem can be reproduced with a 16 or 32 Gbps HBA by loading qla2xxx with qlini_mode=disabled and running a high IOPS test while triggering frequent RSCN database change events. While analyzing the problem I discovered that even with disable_msix_handshake forced to 0, it is not necessary to clear the RISC interrupt from qla2xxx_msix_rsp_q_hs() (more below). So just completely remove qla2xxx_msix_rsp_q_hs() and the logic for selecting it, which also fixes the bug with qlini_mode=disabled. The test below describes the justification for not needing qla2xxx_msix_rsp_q_hs(): Force disable_msix_handshake to 0: qla24xx_config_rings(): if (0 && (ha->fw_attributes & BIT_6) && (IS_MSIX_NACK_CAPABLE(ha)) && (ha->flags.msix_enabled)) { In qla24xx_msix_rsp_q() and qla2xxx_msix_rsp_q_hs(), check: (rd_reg_dword(®->host_status) & HSRX_RISC_INT) Count the number of calls to each function with HSRX_RISC_INT set and the number with HSRX_RISC_INT not set while performing some I/O. If qla2xxx_msix_rsp_q_hs() clears the RISC interrupt (original code): qla24xx_msix_rsp_q: 50% of calls have HSRX_RISC_INT set qla2xxx_msix_rsp_q_hs: 5% of calls have HSRX_RISC_INT set (# of qla2xxx_msix_rsp_q_hs interrupts) = (# of qla24xx_msix_rsp_q interrupts) * 3 If qla2xxx_msix_rsp_q_hs() does not clear the RISC interrupt (patched code): qla24xx_msix_rsp_q: 100% of calls have HSRX_RISC_INT set qla2xxx_msix_rsp_q_hs: 9% of calls have HSRX_RISC_INT set (# of qla2xxx_msix_rsp_q_hs interrupts) = (# of qla24xx_msix_rsp_q interrupts) * 3 In the case of the original code, qla24xx_msix_rsp_q() was seeing HSRX_RISC_INT set only 50% of the time because qla2xxx_msix_rsp_q_hs() was clearing it when it shouldn't have been. In the patched code, qla24xx_msix_rsp_q() sees HSRX_RISC_INT set 100% of the time, which makes sense if that interrupt handler needs to clear the RISC interrupt (which it does). qla2xxx_msix_rsp_q_hs() sees HSRX_RISC_INT only 9% of the time, which is just overlap from the other interrupt during the high IOPS test. Tested with SCST on: QLE2742 FW:v9.08.02 (32 Gbps 2-port) QLE2694L FW:v9.10.11 (16 Gbps 4-port) QLE2694L FW:v9.08.02 (16 Gbps 4-port) QLE2672 FW:v8.07.12 (16 Gbps 2-port) both initiator and target mode Signed-off-by: Tony Battersby Link: https://patch.msgid.link/56d378eb-14ad-49c7-bae9-c649b6c7691e@cybernetics.com Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin --- drivers/scsi/qla2xxx/qla_def.h | 1 - drivers/scsi/qla2xxx/qla_gbl.h | 2 +- drivers/scsi/qla2xxx/qla_isr.c | 32 +++----------------------------- drivers/scsi/qla2xxx/qla_mid.c | 4 +--- 4 files changed, 5 insertions(+), 34 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index cb95b7b12051d..b3265952c4bed 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -3503,7 +3503,6 @@ struct isp_operations { #define QLA_MSIX_RSP_Q 0x01 #define QLA_ATIO_VECTOR 0x02 #define QLA_MSIX_QPAIR_MULTIQ_RSP_Q 0x03 -#define QLA_MSIX_QPAIR_MULTIQ_RSP_Q_HS 0x04 #define QLA_MIDX_DEFAULT 0 #define QLA_MIDX_RSP_Q 1 diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index 145defc420f27..55d531c19e6b2 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -766,7 +766,7 @@ extern int qla2x00_dfs_remove(scsi_qla_host_t *); /* Globa function prototypes for multi-q */ extern int qla25xx_request_irq(struct qla_hw_data *, struct qla_qpair *, - struct qla_msix_entry *, int); + struct qla_msix_entry *); extern int qla25xx_init_req_que(struct scsi_qla_host *, struct req_que *); extern int qla25xx_init_rsp_que(struct scsi_qla_host *, struct rsp_que *); extern int qla25xx_create_req_que(struct qla_hw_data *, uint16_t, uint8_t, diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index c4c6b5c6658c0..a3971afc2dd1e 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -4467,32 +4467,6 @@ qla2xxx_msix_rsp_q(int irq, void *dev_id) return IRQ_HANDLED; } -irqreturn_t -qla2xxx_msix_rsp_q_hs(int irq, void *dev_id) -{ - struct qla_hw_data *ha; - struct qla_qpair *qpair; - struct device_reg_24xx __iomem *reg; - unsigned long flags; - - qpair = dev_id; - if (!qpair) { - ql_log(ql_log_info, NULL, 0x505b, - "%s: NULL response queue pointer.\n", __func__); - return IRQ_NONE; - } - ha = qpair->hw; - - reg = &ha->iobase->isp24; - spin_lock_irqsave(&ha->hardware_lock, flags); - wrt_reg_dword(®->hccr, HCCRX_CLR_RISC_INT); - spin_unlock_irqrestore(&ha->hardware_lock, flags); - - queue_work(ha->wq, &qpair->q_work); - - return IRQ_HANDLED; -} - /* Interrupt handling helpers. */ struct qla_init_msix_entry { @@ -4505,7 +4479,6 @@ static const struct qla_init_msix_entry msix_entries[] = { { "rsp_q", qla24xx_msix_rsp_q }, { "atio_q", qla83xx_msix_atio_q }, { "qpair_multiq", qla2xxx_msix_rsp_q }, - { "qpair_multiq_hs", qla2xxx_msix_rsp_q_hs }, }; static const struct qla_init_msix_entry qla82xx_msix_entries[] = { @@ -4792,9 +4765,10 @@ qla2x00_free_irqs(scsi_qla_host_t *vha) } int qla25xx_request_irq(struct qla_hw_data *ha, struct qla_qpair *qpair, - struct qla_msix_entry *msix, int vector_type) + struct qla_msix_entry *msix) { - const struct qla_init_msix_entry *intr = &msix_entries[vector_type]; + const struct qla_init_msix_entry *intr = + &msix_entries[QLA_MSIX_QPAIR_MULTIQ_RSP_Q]; scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev); int ret; diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c index 8b71ac0b1d999..0abc47e72e0bf 100644 --- a/drivers/scsi/qla2xxx/qla_mid.c +++ b/drivers/scsi/qla2xxx/qla_mid.c @@ -899,9 +899,7 @@ qla25xx_create_rsp_que(struct qla_hw_data *ha, uint16_t options, rsp->options, rsp->id, rsp->rsp_q_in, rsp->rsp_q_out); - ret = qla25xx_request_irq(ha, qpair, qpair->msix, - ha->flags.disable_msix_handshake ? - QLA_MSIX_QPAIR_MULTIQ_RSP_Q : QLA_MSIX_QPAIR_MULTIQ_RSP_Q_HS); + ret = qla25xx_request_irq(ha, qpair, qpair->msix); if (ret) goto que_failed; From 6407b63db802cf68ee40cd1677a01215216cd62d Mon Sep 17 00:00:00 2001 From: Tony Battersby Date: Mon, 10 Nov 2025 10:48:45 -0500 Subject: [PATCH 1190/2333] scsi: qla2xxx: Fix initiator mode with qlini_mode=exclusive [ Upstream commit 8f58fc64d559b5fda1b0a5e2a71422be61e79ab9 ] When given the module parameter qlini_mode=exclusive, qla2xxx in initiator mode is initially unable to successfully send SCSI commands to devices it finds while scanning, resulting in an escalating series of resets until an adapter reset clears the issue. Fix by checking the active mode instead of the module parameter. Signed-off-by: Tony Battersby Link: https://patch.msgid.link/1715ec14-ba9a-45dc-9cf2-d41aa6b81b5e@cybernetics.com Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin --- drivers/scsi/qla2xxx/qla_os.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 70a579cf9c3fd..6b0f616b1ca0a 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -3460,13 +3460,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) ha->mqenable = 0; if (ha->mqenable) { - bool startit = false; - - if (QLA_TGT_MODE_ENABLED()) - startit = false; - - if (ql2x_ini_mode == QLA2XXX_INI_MODE_ENABLED) - startit = true; + bool startit = !!(host->active_mode & MODE_INITIATOR); /* Create start of day qpairs for Block MQ */ for (i = 0; i < ha->max_qpairs; i++) From 05f9aa19fdc169196c22b62ba3d81ba94d8575ea Mon Sep 17 00:00:00 2001 From: Tony Battersby Date: Mon, 10 Nov 2025 10:51:28 -0500 Subject: [PATCH 1191/2333] scsi: qla2xxx: Use reinit_completion on mbx_intr_comp [ Upstream commit 957aa5974989fba4ae4f807ebcb27f12796edd4d ] If a mailbox command completes immediately after wait_for_completion_timeout() times out, ha->mbx_intr_comp could be left in an inconsistent state, causing the next mailbox command not to wait for the hardware. Fix by reinitializing the completion before use. Signed-off-by: Tony Battersby Link: https://patch.msgid.link/11b6485e-0bfd-4784-8f99-c06a196dad94@cybernetics.com Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin --- drivers/scsi/qla2xxx/qla_mbx.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index 32eb0ce8b170d..1f01576f044b8 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -253,6 +253,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp) /* Issue set host interrupt command to send cmd out. */ ha->flags.mbox_int = 0; clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags); + reinit_completion(&ha->mbx_intr_comp); /* Unlock mbx registers and wait for interrupt */ ql_dbg(ql_dbg_mbx, vha, 0x100f, @@ -279,6 +280,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp) "cmd=%x Timeout.\n", command); spin_lock_irqsave(&ha->hardware_lock, flags); clear_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags); + reinit_completion(&ha->mbx_intr_comp); spin_unlock_irqrestore(&ha->hardware_lock, flags); if (chip_reset != ha->chip_reset) { From b88dd8517ec8de43e03395609236fe3f94680099 Mon Sep 17 00:00:00 2001 From: Bernd Schubert Date: Thu, 23 Oct 2025 00:21:18 +0200 Subject: [PATCH 1192/2333] fuse: Always flush the page cache before FOPEN_DIRECT_IO write [ Upstream commit 1ce120dcefc056ce8af2486cebbb77a458aad4c3 ] This was done as condition on direct_io_allow_mmap, but I believe this is not right, as a file might be open two times - once with write-back enabled another time with FOPEN_DIRECT_IO. Signed-off-by: Bernd Schubert Signed-off-by: Miklos Szeredi Signed-off-by: Sasha Levin --- fs/fuse/file.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/fuse/file.c b/fs/fuse/file.c index f1ef77a0be05b..c5c82b3807911 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -1607,7 +1607,7 @@ ssize_t fuse_direct_io(struct fuse_io_priv *io, struct iov_iter *iter, if (!ia) return -ENOMEM; - if (fopen_direct_io && fc->direct_io_allow_mmap) { + if (fopen_direct_io) { res = filemap_write_and_wait_range(mapping, pos, pos + count - 1); if (res) { fuse_io_free(ia); From ea0c31c521439d8c16cdebe305fa7c9d90811566 Mon Sep 17 00:00:00 2001 From: Bernd Schubert Date: Thu, 23 Oct 2025 00:21:17 +0200 Subject: [PATCH 1193/2333] fuse: Invalidate the page cache after FOPEN_DIRECT_IO write [ Upstream commit b359af8275a982a458e8df6c6beab1415be1f795 ] generic_file_direct_write() also does this and has a large comment about. Reproducer here is xfstest's generic/209, which is exactly to have competing DIO write and cached IO read. Signed-off-by: Bernd Schubert Signed-off-by: Miklos Szeredi Signed-off-by: Sasha Levin --- fs/fuse/file.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/fs/fuse/file.c b/fs/fuse/file.c index c5c82b3807911..bb4ecfd469a5e 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -1681,6 +1681,15 @@ ssize_t fuse_direct_io(struct fuse_io_priv *io, struct iov_iter *iter, if (res > 0) *ppos = pos; + if (res > 0 && write && fopen_direct_io) { + /* + * As in generic_file_direct_write(), invalidate after the + * write, to invalidate read-ahead cache that may have competed + * with the write. + */ + invalidate_inode_pages2_range(mapping, idx_from, idx_to); + } + return res > 0 ? res : err; } EXPORT_SYMBOL_GPL(fuse_direct_io); From c6a2dd4f2e4e6cbdfe7a1618160281af897b75db Mon Sep 17 00:00:00 2001 From: Li Qiang Date: Sun, 28 Sep 2025 16:33:32 +0800 Subject: [PATCH 1194/2333] via_wdt: fix critical boot hang due to unnamed resource allocation [ Upstream commit 7aa31ee9ec92915926e74731378c009c9cc04928 ] The VIA watchdog driver uses allocate_resource() to reserve a MMIO region for the watchdog control register. However, the allocated resource was not given a name, which causes the kernel resource tree to contain an entry marked as "" under /proc/iomem on x86 platforms. During boot, this unnamed resource can lead to a critical hang because subsequent resource lookups and conflict checks fail to handle the invalid entry properly. Signed-off-by: Li Qiang Reviewed-by: Guenter Roeck Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck Signed-off-by: Sasha Levin --- drivers/watchdog/via_wdt.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/watchdog/via_wdt.c b/drivers/watchdog/via_wdt.c index d647923d68fed..f555763926518 100644 --- a/drivers/watchdog/via_wdt.c +++ b/drivers/watchdog/via_wdt.c @@ -165,6 +165,7 @@ static int wdt_probe(struct pci_dev *pdev, dev_err(&pdev->dev, "cannot enable PCI device\n"); return -ENODEV; } + wdt_res.name = "via_wdt"; /* * Allocate a MMIO region which contains watchdog control register From b49c766856fb5901490de577e046149ebf15e39d Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 14 Nov 2025 02:18:22 -0500 Subject: [PATCH 1195/2333] functionfs: fix the open/removal races [ Upstream commit e5bf5ee266633cb18fff6f98f0b7d59a62819eee ] ffs_epfile_open() can race with removal, ending up with file->private_data pointing to freed object. There is a total count of opened files on functionfs (both ep0 and dynamic ones) and when it hits zero, dynamic files get removed. Unfortunately, that removal can happen while another thread is in ffs_epfile_open(), but has not incremented the count yet. In that case open will succeed, leaving us with UAF on any subsequent read() or write(). The root cause is that ffs->opened is misused; atomic_dec_and_test() vs. atomic_add_return() is not a good idea, when object remains visible all along. To untangle that * serialize openers on ffs->mutex (both for ep0 and for dynamic files) * have dynamic ones use atomic_inc_not_zero() and fail if we had zero ->opened; in that case the file we are opening is doomed. * have the inodes of dynamic files marked on removal (from the callback of simple_recursive_removal()) - clear ->i_private there. * have open of dynamic ones verify they hadn't been already removed, along with checking that state is FFS_ACTIVE. Reviewed-by: Greg Kroah-Hartman Signed-off-by: Al Viro Signed-off-by: Sasha Levin --- drivers/usb/gadget/function/f_fs.c | 53 ++++++++++++++++++++++++------ 1 file changed, 43 insertions(+), 10 deletions(-) diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index 47cfbe41fdff8..69f6e3c0f7e00 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -640,13 +640,22 @@ static ssize_t ffs_ep0_read(struct file *file, char __user *buf, static int ffs_ep0_open(struct inode *inode, struct file *file) { - struct ffs_data *ffs = inode->i_private; + struct ffs_data *ffs = inode->i_sb->s_fs_info; + int ret; - if (ffs->state == FFS_CLOSING) - return -EBUSY; + /* Acquire mutex */ + ret = ffs_mutex_lock(&ffs->mutex, file->f_flags & O_NONBLOCK); + if (ret < 0) + return ret; - file->private_data = ffs; ffs_data_opened(ffs); + if (ffs->state == FFS_CLOSING) { + ffs_data_closed(ffs); + mutex_unlock(&ffs->mutex); + return -EBUSY; + } + mutex_unlock(&ffs->mutex); + file->private_data = ffs; return stream_open(inode, file); } @@ -1193,14 +1202,33 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) static int ffs_epfile_open(struct inode *inode, struct file *file) { - struct ffs_epfile *epfile = inode->i_private; + struct ffs_data *ffs = inode->i_sb->s_fs_info; + struct ffs_epfile *epfile; + int ret; - if (WARN_ON(epfile->ffs->state != FFS_ACTIVE)) + /* Acquire mutex */ + ret = ffs_mutex_lock(&ffs->mutex, file->f_flags & O_NONBLOCK); + if (ret < 0) + return ret; + + if (!atomic_inc_not_zero(&ffs->opened)) { + mutex_unlock(&ffs->mutex); + return -ENODEV; + } + /* + * we want the state to be FFS_ACTIVE; FFS_ACTIVE alone is + * not enough, though - we might have been through FFS_CLOSING + * and back to FFS_ACTIVE, with our file already removed. + */ + epfile = smp_load_acquire(&inode->i_private); + if (unlikely(ffs->state != FFS_ACTIVE || !epfile)) { + mutex_unlock(&ffs->mutex); + ffs_data_closed(ffs); return -ENODEV; + } + mutex_unlock(&ffs->mutex); file->private_data = epfile; - ffs_data_opened(epfile->ffs); - return stream_open(inode, file); } @@ -1332,7 +1360,7 @@ static void ffs_dmabuf_put(struct dma_buf_attachment *attach) static int ffs_epfile_release(struct inode *inode, struct file *file) { - struct ffs_epfile *epfile = inode->i_private; + struct ffs_epfile *epfile = file->private_data; struct ffs_dmabuf_priv *priv, *tmp; struct ffs_data *ffs = epfile->ffs; @@ -2352,6 +2380,11 @@ static int ffs_epfiles_create(struct ffs_data *ffs) return 0; } +static void clear_one(struct dentry *dentry) +{ + smp_store_release(&dentry->d_inode->i_private, NULL); +} + static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count) { struct ffs_epfile *epfile = epfiles; @@ -2359,7 +2392,7 @@ static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count) for (; count; --count, ++epfile) { BUG_ON(mutex_is_locked(&epfile->mutex)); if (epfile->dentry) { - simple_recursive_removal(epfile->dentry, NULL); + simple_recursive_removal(epfile->dentry, clear_one); epfile->dentry = NULL; } } From f04d53f6e3ff2d682cbc9d6c05e7daf935232856 Mon Sep 17 00:00:00 2001 From: Encrow Thorne Date: Mon, 10 Nov 2025 14:10:37 +0800 Subject: [PATCH 1196/2333] reset: fix BIT macro reference [ Upstream commit f3d8b64ee46c9b4b0b82b1a4642027728bac95b8 ] RESET_CONTROL_FLAGS_BIT_* macros use BIT(), but reset.h does not include bits.h. This causes compilation errors when including reset.h standalone. Include bits.h to make reset.h self-contained. Suggested-by: Troy Mitchell Reviewed-by: Troy Mitchell Reviewed-by: Philipp Zabel Signed-off-by: Encrow Thorne Signed-off-by: Philipp Zabel Signed-off-by: Sasha Levin --- include/linux/reset.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/reset.h b/include/linux/reset.h index 840d75d172f62..44f9e3415f92c 100644 --- a/include/linux/reset.h +++ b/include/linux/reset.h @@ -2,6 +2,7 @@ #ifndef _LINUX_RESET_H_ #define _LINUX_RESET_H_ +#include #include #include #include From ff3e06e80c9e4c81e0038155c5a185e9a0079dbb Mon Sep 17 00:00:00 2001 From: Yuezhang Mo Date: Fri, 28 Nov 2025 17:51:10 +0800 Subject: [PATCH 1197/2333] exfat: fix remount failure in different process environments [ Upstream commit 51fc7b4ce10ccab8ea5e4876bcdc42cf5202a0ef ] The kernel test robot reported that the exFAT remount operation failed. The reason for the failure was that the process's umask is different between mount and remount, causing fs_fmask and fs_dmask are changed. Potentially, both gid and uid may also be changed. Therefore, when initializing fs_context for remount, inherit these mount options from the options used during mount. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-lkp/202511251637.81670f5c-lkp@intel.com Signed-off-by: Yuezhang Mo Signed-off-by: Namjae Jeon Signed-off-by: Sasha Levin --- fs/exfat/super.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/fs/exfat/super.c b/fs/exfat/super.c index 74d451f732c73..581754001128b 100644 --- a/fs/exfat/super.c +++ b/fs/exfat/super.c @@ -813,10 +813,21 @@ static int exfat_init_fs_context(struct fs_context *fc) ratelimit_state_init(&sbi->ratelimit, DEFAULT_RATELIMIT_INTERVAL, DEFAULT_RATELIMIT_BURST); - sbi->options.fs_uid = current_uid(); - sbi->options.fs_gid = current_gid(); - sbi->options.fs_fmask = current->fs->umask; - sbi->options.fs_dmask = current->fs->umask; + if (fc->purpose == FS_CONTEXT_FOR_RECONFIGURE && fc->root) { + struct super_block *sb = fc->root->d_sb; + struct exfat_mount_options *cur_opts = &EXFAT_SB(sb)->options; + + sbi->options.fs_uid = cur_opts->fs_uid; + sbi->options.fs_gid = cur_opts->fs_gid; + sbi->options.fs_fmask = cur_opts->fs_fmask; + sbi->options.fs_dmask = cur_opts->fs_dmask; + } else { + sbi->options.fs_uid = current_uid(); + sbi->options.fs_gid = current_gid(); + sbi->options.fs_fmask = current->fs->umask; + sbi->options.fs_dmask = current->fs->umask; + } + sbi->options.allow_utime = -1; sbi->options.errors = EXFAT_ERRORS_RO; exfat_set_iocharset(&sbi->options, exfat_default_iocharset); From 967ac825b4f61ee6a268faedb6cd6393ad903210 Mon Sep 17 00:00:00 2001 From: Yuezhang Mo Date: Mon, 27 Oct 2025 17:03:41 +0800 Subject: [PATCH 1198/2333] exfat: zero out post-EOF page cache on file extension [ Upstream commit 4e163c39dd4e70fcdce948b8774d96e0482b4a11 ] xfstests generic/363 was failing due to unzeroed post-EOF page cache that allowed mmap writes beyond EOF to become visible after file extension. For example, in following xfs_io sequence, 0x22 should not be written to the file but would become visible after the extension: xfs_io -f -t -c "pwrite -S 0x11 0 8" \ -c "mmap 0 4096" \ -c "mwrite -S 0x22 32 32" \ -c "munmap" \ -c "pwrite -S 0x33 512 32" \ $testfile This violates the expected behavior where writes beyond EOF via mmap should not persist after the file is extended. Instead, the extended region should contain zeros. Fix this by using truncate_pagecache() to truncate the page cache after the current EOF when extending the file. Signed-off-by: Yuezhang Mo Signed-off-by: Namjae Jeon Signed-off-by: Sasha Levin --- fs/exfat/file.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/fs/exfat/file.c b/fs/exfat/file.c index adc37b4d7fc2d..536c8078f0c19 100644 --- a/fs/exfat/file.c +++ b/fs/exfat/file.c @@ -25,6 +25,8 @@ static int exfat_cont_expand(struct inode *inode, loff_t size) struct exfat_sb_info *sbi = EXFAT_SB(sb); struct exfat_chain clu; + truncate_pagecache(inode, i_size_read(inode)); + ret = inode_newsize_ok(inode, size); if (ret) return ret; @@ -639,6 +641,9 @@ static ssize_t exfat_file_write_iter(struct kiocb *iocb, struct iov_iter *iter) inode_lock(inode); + if (pos > i_size_read(inode)) + truncate_pagecache(inode, i_size_read(inode)); + valid_size = ei->valid_size; ret = generic_write_checks(iocb, iter); From 1681cf6da695b9cc1c4f3411b230e1af98d6e1d3 Mon Sep 17 00:00:00 2001 From: Lizhi Xu Date: Tue, 16 Sep 2025 09:41:43 +0800 Subject: [PATCH 1199/2333] usbip: Fix locking bug in RT-enabled kernels [ Upstream commit 09bf21bf5249880f62fe759b53b14b4b52900c6c ] Interrupts are disabled before entering usb_hcd_giveback_urb(). A spinlock_t becomes a sleeping lock on PREEMPT_RT, so it cannot be acquired with disabled interrupts. Save the interrupt status and restore it after usb_hcd_giveback_urb(). syz reported: BUG: sleeping function called from invalid context at kernel/locking/spinlock_rt.c:48 Call Trace: dump_stack_lvl+0x189/0x250 lib/dump_stack.c:120 rt_spin_lock+0xc7/0x2c0 kernel/locking/spinlock_rt.c:57 spin_lock include/linux/spinlock_rt.h:44 [inline] mon_bus_complete drivers/usb/mon/mon_main.c:134 [inline] mon_complete+0x5c/0x200 drivers/usb/mon/mon_main.c:147 usbmon_urb_complete include/linux/usb/hcd.h:738 [inline] __usb_hcd_giveback_urb+0x254/0x5e0 drivers/usb/core/hcd.c:1647 vhci_urb_enqueue+0xb4f/0xe70 drivers/usb/usbip/vhci_hcd.c:818 Reported-by: syzbot+205ef33a3b636b4181fb@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=205ef33a3b636b4181fb Signed-off-by: Lizhi Xu Acked-by: Shuah Khan Link: https://lore.kernel.org/r/20250916014143.1439759-1-lizhi.xu@windriver.com Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin --- drivers/usb/usbip/vhci_hcd.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/usb/usbip/vhci_hcd.c b/drivers/usb/usbip/vhci_hcd.c index 0d6c10a8490c0..f7e405abe6084 100644 --- a/drivers/usb/usbip/vhci_hcd.c +++ b/drivers/usb/usbip/vhci_hcd.c @@ -831,15 +831,15 @@ static int vhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flag no_need_xmit: usb_hcd_unlink_urb_from_ep(hcd, urb); no_need_unlink: - spin_unlock_irqrestore(&vhci->lock, flags); if (!ret) { /* usb_hcd_giveback_urb() should be called with * irqs disabled */ - local_irq_disable(); + spin_unlock(&vhci->lock); usb_hcd_giveback_urb(hcd, urb, urb->status); - local_irq_enable(); + spin_lock(&vhci->lock); } + spin_unlock_irqrestore(&vhci->lock, flags); return ret; } From 132fe187e0d940f388f839fe2cde9b84106ad20d Mon Sep 17 00:00:00 2001 From: Mark Pearson Date: Thu, 21 Aug 2025 14:53:07 -0400 Subject: [PATCH 1200/2333] usb: typec: ucsi: Handle incorrect num_connectors capability [ Upstream commit 30cd2cb1abf4c4acdb1ddb468c946f68939819fb ] The UCSI spec states that the num_connectors field is 7 bits, and the 8th bit is reserved and should be set to zero. Some buggy FW has been known to set this bit, and it can lead to a system not booting. Flag that the FW is not behaving correctly, and auto-fix the value so that the system boots correctly. Found on Lenovo P1 G8 during Linux enablement program. The FW will be fixed, but seemed worth addressing in case it hit platforms that aren't officially Linux supported. Signed-off-by: Mark Pearson Reviewed-by: Heikki Krogerus Link: https://lore.kernel.org/r/20250821185319.2585023-1-mpearson-lenovo@squebb.ca Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin --- drivers/usb/typec/ucsi/ucsi.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c index 3f568f790f39b..3995483a0aa09 100644 --- a/drivers/usb/typec/ucsi/ucsi.c +++ b/drivers/usb/typec/ucsi/ucsi.c @@ -1807,6 +1807,12 @@ static int ucsi_init(struct ucsi *ucsi) ret = -ENODEV; goto err_reset; } + /* Check if reserved bit set. This is out of spec but happens in buggy FW */ + if (ucsi->cap.num_connectors & 0x80) { + dev_warn(ucsi->dev, "UCSI: Invalid num_connectors %d. Likely buggy FW\n", + ucsi->cap.num_connectors); + ucsi->cap.num_connectors &= 0x7f; // clear bit and carry on + } /* Allocate the connectors. Released in ucsi_unregister() */ connector = kcalloc(ucsi->cap.num_connectors + 1, sizeof(*connector), GFP_KERNEL); From 41374236a556d25266f4f3d70d857ab658e5b063 Mon Sep 17 00:00:00 2001 From: Pei Xiao Date: Tue, 14 Oct 2025 17:12:50 +0800 Subject: [PATCH 1201/2333] iio: adc: ti_am335x_adc: Limit step_avg to valid range for gcc complains [ Upstream commit c9fb952360d0c78bbe98239bd6b702f05c2dbb31 ] FIELD_PREP() checks that a value fits into the available bitfield, add a check for step_avg to fix gcc complains. which gcc complains about: drivers/iio/adc/ti_am335x_adc.c: In function 'tiadc_step_config': include/linux/compiler_types.h:572:38: error: call to '__compiletime_assert_491' declared with attribute error: FIELD_PREP: value too large for the field include/linux/mfd/ti_am335x_tscadc.h:58:29: note: in expansion of macro 'FIELD_PREP' #define STEPCONFIG_AVG(val) FIELD_PREP(GENMASK(4, 2), (val)) ^~~~~~~~~~ drivers/iio/adc/ti_am335x_adc.c:127:17: note: in expansion of macro 'STEPCONFIG_AVG' stepconfig = STEPCONFIG_AVG(ffs(adc_dev->step_avg[i]) - 1) Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202510102117.Jqxrw1vF-lkp@intel.com/ Signed-off-by: Pei Xiao Signed-off-by: Jonathan Cameron Signed-off-by: Sasha Levin --- drivers/iio/adc/ti_am335x_adc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/adc/ti_am335x_adc.c b/drivers/iio/adc/ti_am335x_adc.c index 99f274adc870d..a1a28584de930 100644 --- a/drivers/iio/adc/ti_am335x_adc.c +++ b/drivers/iio/adc/ti_am335x_adc.c @@ -123,7 +123,7 @@ static void tiadc_step_config(struct iio_dev *indio_dev) chan = adc_dev->channel_line[i]; - if (adc_dev->step_avg[i]) + if (adc_dev->step_avg[i] && adc_dev->step_avg[i] <= STEPCONFIG_AVG_16) stepconfig = STEPCONFIG_AVG(ffs(adc_dev->step_avg[i]) - 1) | STEPCONFIG_FIFO1; else From 6dc09b9b211b35e8c9372a777499f0612a4f0cd5 Mon Sep 17 00:00:00 2001 From: Hongyu Xie Date: Wed, 19 Nov 2025 16:23:55 +0200 Subject: [PATCH 1202/2333] usb: xhci: limit run_graceperiod for only usb 3.0 devices [ Upstream commit 8d34983720155b8f05de765f0183d9b0e1345cc0 ] run_graceperiod blocks usb 2.0 devices from auto suspending after xhci_start for 500ms. Log shows: [ 13.387170] xhci_hub_control:1271: xhci-hcd PNP0D10:03: Get port status 7-1 read: 0x2a0, return 0x100 [ 13.387177] hub_event:5779: hub 7-0:1.0: state 7 ports 1 chg 0000 evt 0000 [ 13.387182] hub_suspend:3903: hub 7-0:1.0: hub_suspend [ 13.387188] hcd_bus_suspend:2250: usb usb7: bus auto-suspend, wakeup 1 [ 13.387191] hcd_bus_suspend:2279: usb usb7: suspend raced with wakeup event [ 13.387193] hcd_bus_resume:2303: usb usb7: usb auto-resume [ 13.387296] hub_event:5779: hub 3-0:1.0: state 7 ports 1 chg 0000 evt 0000 [ 13.393343] handle_port_status:2034: xhci-hcd PNP0D10:02: handle_port_status: starting usb5 port polling. [ 13.393353] xhci_hub_control:1271: xhci-hcd PNP0D10:02: Get port status 5-1 read: 0x206e1, return 0x10101 [ 13.400047] hub_suspend:3903: hub 3-0:1.0: hub_suspend [ 13.403077] hub_resume:3948: hub 7-0:1.0: hub_resume [ 13.403080] xhci_hub_control:1271: xhci-hcd PNP0D10:03: Get port status 7-1 read: 0x2a0, return 0x100 [ 13.403085] hub_event:5779: hub 7-0:1.0: state 7 ports 1 chg 0000 evt 0000 [ 13.403087] hub_suspend:3903: hub 7-0:1.0: hub_suspend [ 13.403090] hcd_bus_suspend:2250: usb usb7: bus auto-suspend, wakeup 1 [ 13.403093] hcd_bus_suspend:2279: usb usb7: suspend raced with wakeup event [ 13.403095] hcd_bus_resume:2303: usb usb7: usb auto-resume [ 13.405002] handle_port_status:1913: xhci-hcd PNP0D10:04: Port change event, 9-1, id 1, portsc: 0x6e1 [ 13.405016] hub_activate:1169: usb usb5-port1: status 0101 change 0001 [ 13.405026] xhci_clear_port_change_bit:658: xhci-hcd PNP0D10:02: clear port1 connect change, portsc: 0x6e1 [ 13.413275] hcd_bus_suspend:2250: usb usb3: bus auto-suspend, wakeup 1 [ 13.419081] hub_resume:3948: hub 7-0:1.0: hub_resume [ 13.419086] xhci_hub_control:1271: xhci-hcd PNP0D10:03: Get port status 7-1 read: 0x2a0, return 0x100 [ 13.419095] hub_event:5779: hub 7-0:1.0: state 7 ports 1 chg 0000 evt 0000 [ 13.419100] hub_suspend:3903: hub 7-0:1.0: hub_suspend [ 13.419106] hcd_bus_suspend:2250: usb usb7: bus auto-suspend, wakeup 1 [ 13.419110] hcd_bus_suspend:2279: usb usb7: suspend raced with wakeup event [ 13.419112] hcd_bus_resume:2303: usb usb7: usb auto-resume [ 13.420455] handle_port_status:2034: xhci-hcd PNP0D10:04: handle_port_status: starting usb9 port polling. [ 13.420493] handle_port_status:1913: xhci-hcd PNP0D10:05: Port change event, 10-1, id 1, portsc: 0x6e1 [ 13.425332] hcd_bus_suspend:2279: usb usb3: suspend raced with wakeup event [ 13.431931] handle_port_status:2034: xhci-hcd PNP0D10:05: handle_port_status: starting usb10 port polling. [ 13.435080] hub_resume:3948: hub 7-0:1.0: hub_resume [ 13.435084] xhci_hub_control:1271: xhci-hcd PNP0D10:03: Get port status 7-1 read: 0x2a0, return 0x100 [ 13.435092] hub_event:5779: hub 7-0:1.0: state 7 ports 1 chg 0000 evt 0000 [ 13.435096] hub_suspend:3903: hub 7-0:1.0: hub_suspend [ 13.435102] hcd_bus_suspend:2250: usb usb7: bus auto-suspend, wakeup 1 [ 13.435106] hcd_bus_suspend:2279: usb usb7: suspend raced with wakeup event usb7 and other usb 2.0 root hub were rapidly toggling between suspend and resume states. More, "suspend raced with wakeup event" confuses people. So, limit run_graceperiod for only usb 3.0 devices Signed-off-by: Hongyu Xie Signed-off-by: Mathias Nyman Link: https://patch.msgid.link/20251119142417.2820519-2-mathias.nyman@linux.intel.com Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin --- drivers/usb/host/xhci-hub.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index b3a59ce1b3f41..5e1442e91743d 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -1671,7 +1671,7 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf) * SS devices are only visible to roothub after link training completes. * Keep polling roothubs for a grace period after xHC start */ - if (xhci->run_graceperiod) { + if (hcd->speed >= HCD_USB3 && xhci->run_graceperiod) { if (time_before(jiffies, xhci->run_graceperiod)) status = 1; else From e375aa7f5a1eea7f5a5887da0bd156939b00cc17 Mon Sep 17 00:00:00 2001 From: Chen Changcheng Date: Fri, 21 Nov 2025 14:40:20 +0800 Subject: [PATCH 1203/2333] usb: usb-storage: No additional quirks need to be added to the EL-R12 optical drive. [ Upstream commit 955a48a5353f4fe009704a9a4272a3adf627cd35 ] The optical drive of EL-R12 has the same vid and pid as INIC-3069, as follows: T: Bus=02 Lev=02 Prnt=02 Port=01 Cnt=01 Dev#= 3 Spd=5000 MxCh= 0 D: Ver= 3.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 9 #Cfgs= 1 P: Vendor=13fd ProdID=3940 Rev= 3.10 S: Manufacturer=HL-DT-ST S: Product= DVD+-RW GT80N S: SerialNumber=423349524E4E38303338323439202020 C:* #Ifs= 1 Cfg#= 1 Atr=80 MxPwr=144mA I:* If#= 0 Alt= 0 #EPs= 2 Cls=08(stor.) Sub=02 Prot=50 Driver=usb-storage E: Ad=83(I) Atr=02(Bulk) MxPS=1024 Ivl=0ms E: Ad=0a(O) Atr=02(Bulk) MxPS=1024 Ivl=0ms This will result in the optical drive device also adding the quirks of US_FL_NO_ATA_1X. When performing an erase operation, it will fail, and the reason for the failure is as follows: [ 388.967742] sr 5:0:0:0: [sr0] tag#0 Send: scmd 0x00000000d20c33a7 [ 388.967742] sr 5:0:0:0: [sr0] tag#0 CDB: ATA command pass through(12)/Blank a1 11 00 00 00 00 00 00 00 00 00 00 [ 388.967773] sr 5:0:0:0: [sr0] tag#0 Done: SUCCESS Result: hostbyte=DID_TARGET_FAILURE driverbyte=DRIVER_OK cmd_age=0s [ 388.967773] sr 5:0:0:0: [sr0] tag#0 CDB: ATA command pass through(12)/Blank a1 11 00 00 00 00 00 00 00 00 00 00 [ 388.967803] sr 5:0:0:0: [sr0] tag#0 Sense Key : Illegal Request [current] [ 388.967803] sr 5:0:0:0: [sr0] tag#0 Add. Sense: Invalid field in cdb [ 388.967803] sr 5:0:0:0: [sr0] tag#0 scsi host busy 1 failed 0 [ 388.967803] sr 5:0:0:0: Notifying upper driver of completion (result 8100002) [ 388.967834] sr 5:0:0:0: [sr0] tag#0 0 sectors total, 0 bytes done. For the EL-R12 standard optical drive, all operational commands and usage scenarios were tested without adding the IGNORE_RESIDUE quirks, and no issues were encountered. It can be reasonably concluded that removing the IGNORE_RESIDUE quirks has no impact. Signed-off-by: Chen Changcheng Link: https://patch.msgid.link/20251121064020.29332-1-chenchangcheng@kylinos.cn Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin --- drivers/usb/storage/unusual_uas.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/storage/unusual_uas.h b/drivers/usb/storage/unusual_uas.h index 1477e31d77632..b695f5ba9a409 100644 --- a/drivers/usb/storage/unusual_uas.h +++ b/drivers/usb/storage/unusual_uas.h @@ -98,7 +98,7 @@ UNUSUAL_DEV(0x125f, 0xa94a, 0x0160, 0x0160, US_FL_NO_ATA_1X), /* Reported-by: Benjamin Tissoires */ -UNUSUAL_DEV(0x13fd, 0x3940, 0x0000, 0x9999, +UNUSUAL_DEV(0x13fd, 0x3940, 0x0309, 0x0309, "Initio Corporation", "INIC-3069", USB_SC_DEVICE, USB_PR_DEVICE, NULL, From e63d2173887c1c7c66898fecd35d4a9eceffd063 Mon Sep 17 00:00:00 2001 From: Michal Pecio Date: Wed, 19 Nov 2025 16:24:04 +0200 Subject: [PATCH 1204/2333] usb: xhci: Don't unchain link TRBs on quirky HCs [ Upstream commit e6aec6d9f5794e85d2312497a5d81296d885090e ] Some old HCs ignore transfer ring link TRBs whose chain bit is unset. This breaks endpoint operation and sometimes makes it execute other ring's TDs, which may corrupt their buffers or cause unwanted device action. We avoid this by chaining all link TRBs on affected rings. Fix an omission which allows them to be unchained by cancelling TDs. The patch was tested by reproducing this condition on an isochronous endpoint (non-power-of-two TDs are sometimes split not to cross 64K) and printing link TRBs in trb_to_noop() on good and buggy HCs. Actual hardware malfunction is rare since it requires Missed Service Error shortly before the unchained link TRB, at least on NEC and AMD. I have never seen it after commit bb0ba4cb1065 ("usb: xhci: Apply the link chain quirk on NEC isoc endpoints"), but it's Russian roulette and I can't test all affected hosts and workloads. Fairly often MSEs happen after cancellation because the endpoint was stopped. Signed-off-by: Michal Pecio Signed-off-by: Mathias Nyman Link: https://patch.msgid.link/20251119142417.2820519-11-mathias.nyman@linux.intel.com Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin --- drivers/usb/host/xhci-ring.c | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 5bdcf9ab2b99d..25185552287c0 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -128,11 +128,11 @@ static void inc_td_cnt(struct urb *urb) urb_priv->num_tds_done++; } -static void trb_to_noop(union xhci_trb *trb, u32 noop_type) +static void trb_to_noop(union xhci_trb *trb, u32 noop_type, bool unchain_links) { if (trb_is_link(trb)) { - /* unchain chained link TRBs */ - trb->link.control &= cpu_to_le32(~TRB_CHAIN); + if (unchain_links) + trb->link.control &= cpu_to_le32(~TRB_CHAIN); } else { trb->generic.field[0] = 0; trb->generic.field[1] = 0; @@ -465,7 +465,7 @@ static void xhci_handle_stopped_cmd_ring(struct xhci_hcd *xhci, xhci_dbg(xhci, "Turn aborted command %p to no-op\n", i_cmd->command_trb); - trb_to_noop(i_cmd->command_trb, TRB_CMD_NOOP); + trb_to_noop(i_cmd->command_trb, TRB_CMD_NOOP, false); /* * caller waiting for completion is called when command @@ -797,13 +797,18 @@ static int xhci_move_dequeue_past_td(struct xhci_hcd *xhci, * (The last TRB actually points to the ring enqueue pointer, which is not part * of this TD.) This is used to remove partially enqueued isoc TDs from a ring. */ -static void td_to_noop(struct xhci_td *td, bool flip_cycle) +static void td_to_noop(struct xhci_hcd *xhci, struct xhci_virt_ep *ep, + struct xhci_td *td, bool flip_cycle) { + bool unchain_links; struct xhci_segment *seg = td->start_seg; union xhci_trb *trb = td->start_trb; + /* link TRBs should now be unchained, but some old HCs expect otherwise */ + unchain_links = !xhci_link_chain_quirk(xhci, ep->ring ? ep->ring->type : TYPE_STREAM); + while (1) { - trb_to_noop(trb, TRB_TR_NOOP); + trb_to_noop(trb, TRB_TR_NOOP, unchain_links); /* flip cycle if asked to */ if (flip_cycle && trb != td->start_trb && trb != td->end_trb) @@ -1091,16 +1096,16 @@ static int xhci_invalidate_cancelled_tds(struct xhci_virt_ep *ep) "Found multiple active URBs %p and %p in stream %u?\n", td->urb, cached_td->urb, td->urb->stream_id); - td_to_noop(cached_td, false); + td_to_noop(xhci, ep, cached_td, false); cached_td->cancel_status = TD_CLEARED; } - td_to_noop(td, false); + td_to_noop(xhci, ep, td, false); td->cancel_status = TD_CLEARING_CACHE; cached_td = td; break; } } else { - td_to_noop(td, false); + td_to_noop(xhci, ep, td, false); td->cancel_status = TD_CLEARED; } } @@ -1125,7 +1130,7 @@ static int xhci_invalidate_cancelled_tds(struct xhci_virt_ep *ep) continue; xhci_warn(xhci, "Failed to clear cancelled cached URB %p, mark clear anyway\n", td->urb); - td_to_noop(td, false); + td_to_noop(xhci, ep, td, false); td->cancel_status = TD_CLEARED; } } @@ -4273,7 +4278,7 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags, */ urb_priv->td[0].end_trb = ep_ring->enqueue; /* Every TRB except the first & last will have its cycle bit flipped. */ - td_to_noop(&urb_priv->td[0], true); + td_to_noop(xhci, xep, &urb_priv->td[0], true); /* Reset the ring enqueue back to the first TRB and its cycle bit. */ ep_ring->enqueue = urb_priv->td[0].start_trb; From ad9f0f01373c985b61e0e6be5e85685ab2a11635 Mon Sep 17 00:00:00 2001 From: Wenhua Lin Date: Wed, 22 Oct 2025 11:08:40 +0800 Subject: [PATCH 1205/2333] serial: sprd: Return -EPROBE_DEFER when uart clock is not ready [ Upstream commit 29e8a0c587e328ed458380a45d6028adf64d7487 ] In sprd_clk_init(), when devm_clk_get() returns -EPROBE_DEFER for either uart or source clock, we should propagate the error instead of just warning and continuing with NULL clocks. Currently the driver only emits a warning when clock acquisition fails and proceeds with NULL clock pointers. This can lead to issues later when the clocks are actually needed. More importantly, when the clock provider is not ready yet and returns -EPROBE_DEFER, we should return this error to allow deferred probing. This change adds explicit checks for -EPROBE_DEFER after both: 1. devm_clk_get(uport->dev, uart) 2. devm_clk_get(uport->dev, source) When -EPROBE_DEFER is encountered, the function now returns -EPROBE_DEFER to let the driver framework retry probing later when the clock dependencies are resolved. Signed-off-by: Wenhua Lin Link: https://patch.msgid.link/20251022030840.956589-1-Wenhua.Lin@unisoc.com Reviewed-by: Cixi Geng Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin --- drivers/tty/serial/sprd_serial.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/tty/serial/sprd_serial.c b/drivers/tty/serial/sprd_serial.c index 8c9366321f8e7..092755f356836 100644 --- a/drivers/tty/serial/sprd_serial.c +++ b/drivers/tty/serial/sprd_serial.c @@ -1133,6 +1133,9 @@ static int sprd_clk_init(struct uart_port *uport) clk_uart = devm_clk_get(uport->dev, "uart"); if (IS_ERR(clk_uart)) { + if (PTR_ERR(clk_uart) == -EPROBE_DEFER) + return -EPROBE_DEFER; + dev_warn(uport->dev, "uart%d can't get uart clock\n", uport->line); clk_uart = NULL; @@ -1140,6 +1143,9 @@ static int sprd_clk_init(struct uart_port *uport) clk_parent = devm_clk_get(uport->dev, "source"); if (IS_ERR(clk_parent)) { + if (PTR_ERR(clk_parent) == -EPROBE_DEFER) + return -EPROBE_DEFER; + dev_warn(uport->dev, "uart%d can't get source clock\n", uport->line); clk_parent = NULL; From 9a9a9b88a8d8120ac139fc18057cdf088cb3d9b0 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Wed, 3 Dec 2025 13:47:01 -0800 Subject: [PATCH 1206/2333] libperf cpumap: Fix perf_cpu_map__max for an empty/NULL map [ Upstream commit a0a4173631bfcfd3520192c0a61cf911d6a52c3a ] Passing an empty map to perf_cpu_map__max triggered a SEGV. Explicitly test for the empty map. Reported-by: Ingo Molnar Closes: https://lore.kernel.org/linux-perf-users/aSwt7yzFjVJCEmVp@gmail.com/ Tested-by: Ingo Molnar Signed-off-by: Ian Rogers Tested-by: Thomas Richter Signed-off-by: Namhyung Kim Signed-off-by: Sasha Levin --- tools/lib/perf/cpumap.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tools/lib/perf/cpumap.c b/tools/lib/perf/cpumap.c index b20a5280f2b33..2bbbe1c782b8a 100644 --- a/tools/lib/perf/cpumap.c +++ b/tools/lib/perf/cpumap.c @@ -368,10 +368,12 @@ struct perf_cpu perf_cpu_map__max(const struct perf_cpu_map *map) .cpu = -1 }; - // cpu_map__trim_new() qsort()s it, cpu_map__default_new() sorts it as well. - return __perf_cpu_map__nr(map) > 0 - ? __perf_cpu_map__cpu(map, __perf_cpu_map__nr(map) - 1) - : result; + if (!map) + return result; + + // The CPUs are always sorted and nr is always > 0 as 0 length map is + // encoded as NULL. + return __perf_cpu_map__cpu(map, __perf_cpu_map__nr(map) - 1); } /** Is 'b' a subset of 'a'. */ From 7b85814424575ef499fd99071a6444615b52f6fe Mon Sep 17 00:00:00 2001 From: Jens Reidel Date: Fri, 19 Sep 2025 14:34:32 +0200 Subject: [PATCH 1207/2333] clk: qcom: dispcc-sm7150: Fix dispcc_mdss_pclk0_clk_src [ Upstream commit e3c13e0caa8ceb7dec1a7c4fcfd9dbef56a69fbe ] Set CLK_OPS_PARENT_ENABLE to ensure the parent gets prepared and enabled when switching to it, fixing an "rcg didn't update its configuration" warning. Signed-off-by: Jens Reidel Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20250919-sm7150-dispcc-fixes-v1-3-308ad47c5fce@mainlining.org Signed-off-by: Bjorn Andersson Signed-off-by: Sasha Levin --- drivers/clk/qcom/dispcc-sm7150.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/qcom/dispcc-sm7150.c b/drivers/clk/qcom/dispcc-sm7150.c index bdfff246ed3fe..ddc7230b8aea7 100644 --- a/drivers/clk/qcom/dispcc-sm7150.c +++ b/drivers/clk/qcom/dispcc-sm7150.c @@ -356,7 +356,7 @@ static struct clk_rcg2 dispcc_mdss_pclk0_clk_src = { .name = "dispcc_mdss_pclk0_clk_src", .parent_data = dispcc_parent_data_4, .num_parents = ARRAY_SIZE(dispcc_parent_data_4), - .flags = CLK_SET_RATE_PARENT, + .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE, .ops = &clk_pixel_ops, }, }; From ef7653481a059e12c42e01893fd15497330b2e4d Mon Sep 17 00:00:00 2001 From: Jinhui Guo Date: Tue, 21 Oct 2025 15:57:14 +0800 Subject: [PATCH 1208/2333] i2c: designware: Disable SMBus interrupts to prevent storms from mis-configured firmware [ Upstream commit d3429178ee51dd7155445d15a5ab87a45fae3c73 ] When probing the I2C master, disable SMBus interrupts to prevent storms caused by broken firmware mis-configuring IC_SMBUS=1; the handler never services them and a mis-configured SMBUS Master extend-clock timeout or SMBUS Slave extend-clock timeout can flood the CPU. Signed-off-by: Jinhui Guo Reviewed-by: Andy Shevchenko Acked-by: Mika Westerberg Signed-off-by: Andi Shyti Link: https://lore.kernel.org/r/20251021075714.3712-2-guojinhui.liam@bytedance.com Signed-off-by: Sasha Levin --- drivers/i2c/busses/i2c-designware-core.h | 1 + drivers/i2c/busses/i2c-designware-master.c | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h index 347843b4f5dd7..436555543c79d 100644 --- a/drivers/i2c/busses/i2c-designware-core.h +++ b/drivers/i2c/busses/i2c-designware-core.h @@ -78,6 +78,7 @@ #define DW_IC_TX_ABRT_SOURCE 0x80 #define DW_IC_ENABLE_STATUS 0x9c #define DW_IC_CLR_RESTART_DET 0xa8 +#define DW_IC_SMBUS_INTR_MASK 0xcc #define DW_IC_COMP_PARAM_1 0xf4 #define DW_IC_COMP_VERSION 0xf8 #define DW_IC_SDA_HOLD_MIN_VERS 0x3131312A /* "111*" == v1.11* */ diff --git a/drivers/i2c/busses/i2c-designware-master.c b/drivers/i2c/busses/i2c-designware-master.c index 41e9b5ecad201..45bfca05bb300 100644 --- a/drivers/i2c/busses/i2c-designware-master.c +++ b/drivers/i2c/busses/i2c-designware-master.c @@ -220,6 +220,13 @@ static int i2c_dw_init_master(struct dw_i2c_dev *dev) /* Disable the adapter */ __i2c_dw_disable(dev); + /* + * Mask SMBus interrupts to block storms from broken + * firmware that leaves IC_SMBUS=1; the handler never + * services them. + */ + regmap_write(dev->map, DW_IC_SMBUS_INTR_MASK, 0); + /* Write standard speed timing parameters */ regmap_write(dev->map, DW_IC_SS_SCL_HCNT, dev->ss_hcnt); regmap_write(dev->map, DW_IC_SS_SCL_LCNT, dev->ss_lcnt); From 3b96dc29e385edd25b3f2ec9f3c705702a7dc982 Mon Sep 17 00:00:00 2001 From: "Derek J. Clark" Date: Thu, 27 Nov 2025 07:16:05 -0800 Subject: [PATCH 1209/2333] platform/x86: wmi-gamezone: Add Legion Go 2 Quirks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 55715d7ad5e772d621c3201da3895f250591bce8 ] Add Legion Go 2 SKU's to the Extreme Mode quirks table. Signed-off-by: Derek J. Clark Reviewed-by: Armin Wolf Reviewed-by: Mark Pearson Link: https://patch.msgid.link/20251127151605.1018026-4-derekjohn.clark@gmail.com Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen Signed-off-by: Sasha Levin --- drivers/platform/x86/lenovo/wmi-gamezone.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/drivers/platform/x86/lenovo/wmi-gamezone.c b/drivers/platform/x86/lenovo/wmi-gamezone.c index 0eb7fe8222f4a..b26806b37d960 100644 --- a/drivers/platform/x86/lenovo/wmi-gamezone.c +++ b/drivers/platform/x86/lenovo/wmi-gamezone.c @@ -274,8 +274,23 @@ static const struct dmi_system_id fwbug_list[] = { }, .driver_data = &quirk_no_extreme_bug, }, + { + .ident = "Legion Go 8ASP2", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "Legion Go 8ASP2"), + }, + .driver_data = &quirk_no_extreme_bug, + }, + { + .ident = "Legion Go 8AHP2", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "Legion Go 8AHP2"), + }, + .driver_data = &quirk_no_extreme_bug, + }, {}, - }; /** From 4f7d90c7184a14dda6c1d38b5017ed0184357e9a Mon Sep 17 00:00:00 2001 From: Daniel Wagner Date: Thu, 30 Oct 2025 11:05:45 +0100 Subject: [PATCH 1210/2333] nvme-fc: don't hold rport lock when putting ctrl [ Upstream commit b71cbcf7d170e51148d5467820ae8a72febcb651 ] nvme_fc_ctrl_put can acquire the rport lock when freeing the ctrl object: nvme_fc_ctrl_put nvme_fc_ctrl_free spin_lock_irqsave(rport->lock) Thus we can't hold the rport lock when calling nvme_fc_ctrl_put. Justin suggested use the safe list iterator variant because nvme_fc_ctrl_put will also modify the rport->list. Cc: Justin Tee Reviewed-by: Christoph Hellwig Signed-off-by: Daniel Wagner Signed-off-by: Keith Busch Signed-off-by: Sasha Levin --- drivers/nvme/host/fc.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c index 2c903729b0b90..8324230c53719 100644 --- a/drivers/nvme/host/fc.c +++ b/drivers/nvme/host/fc.c @@ -1468,14 +1468,14 @@ nvme_fc_match_disconn_ls(struct nvme_fc_rport *rport, { struct fcnvme_ls_disconnect_assoc_rqst *rqst = &lsop->rqstbuf->rq_dis_assoc; - struct nvme_fc_ctrl *ctrl, *ret = NULL; + struct nvme_fc_ctrl *ctrl, *tmp, *ret = NULL; struct nvmefc_ls_rcv_op *oldls = NULL; u64 association_id = be64_to_cpu(rqst->associd.association_id); unsigned long flags; spin_lock_irqsave(&rport->lock, flags); - list_for_each_entry(ctrl, &rport->ctrl_list, ctrl_list) { + list_for_each_entry_safe(ctrl, tmp, &rport->ctrl_list, ctrl_list) { if (!nvme_fc_ctrl_get(ctrl)) continue; spin_lock(&ctrl->lock); @@ -1488,7 +1488,9 @@ nvme_fc_match_disconn_ls(struct nvme_fc_rport *rport, if (ret) /* leave the ctrl get reference */ break; + spin_unlock_irqrestore(&rport->lock, flags); nvme_fc_ctrl_put(ctrl); + spin_lock_irqsave(&rport->lock, flags); } spin_unlock_irqrestore(&rport->lock, flags); From 76bced5efbf429c1f70475b4e29840b08ad816f2 Mon Sep 17 00:00:00 2001 From: Pei Xiao Date: Fri, 5 Dec 2025 11:15:13 +0800 Subject: [PATCH 1211/2333] hwmon: (emc2305) fix device node refcount leak in error path [ Upstream commit 4910da6b36b122db50a27fabf6ab7f8611b60bf8 ] The for_each_child_of_node() macro automatically manages device node reference counts during normal iteration. However, when breaking out of the loop early with return, the current iteration's node is not automatically released, leading to a reference count leak. Fix this by adding of_node_put(child) before returning from the loop when emc2305_set_single_tz() fails. This issue could lead to memory leaks over multiple probe cycles. Signed-off-by: Pei Xiao Link: https://lore.kernel.org/r/tencent_5CDC08544C901D5ECA270573D5AEE3117108@qq.com Signed-off-by: Guenter Roeck Signed-off-by: Sasha Levin --- drivers/hwmon/emc2305.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/hwmon/emc2305.c b/drivers/hwmon/emc2305.c index 60809289f8169..84cb9b72cb6c2 100644 --- a/drivers/hwmon/emc2305.c +++ b/drivers/hwmon/emc2305.c @@ -685,8 +685,10 @@ static int emc2305_probe(struct i2c_client *client) i = 0; for_each_child_of_node(dev->of_node, child) { ret = emc2305_set_single_tz(dev, child, i); - if (ret != 0) + if (ret != 0) { + of_node_put(child); return ret; + } i++; } } else { From 6c95c2e00996ce1d1aedf437311d1d3526c05d04 Mon Sep 17 00:00:00 2001 From: Justin Tee Date: Mon, 17 Nov 2025 10:43:43 -0800 Subject: [PATCH 1212/2333] nvme-fabrics: add ENOKEY to no retry criteria for authentication failures [ Upstream commit 13989207ee29c40501e719512e8dc90768325895 ] With authentication, in addition to EKEYREJECTED there is also no point in retrying reconnects when status is ENOKEY. Thus, add -ENOKEY as another criteria to determine when to stop retries. Cc: Daniel Wagner Cc: Hannes Reinecke Closes: https://lore.kernel.org/linux-nvme/20250829-nvme-fc-sync-v3-0-d69c87e63aee@kernel.org/ Signed-off-by: Justin Tee Tested-by: Daniel Wagner Reviewed-by: Daniel Wagner Reviewed-by: Hannes Reinecke Signed-off-by: Keith Busch Signed-off-by: Sasha Levin --- drivers/nvme/host/fabrics.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/nvme/host/fabrics.c b/drivers/nvme/host/fabrics.c index 2e58a7ce10905..55a8afd2efd50 100644 --- a/drivers/nvme/host/fabrics.c +++ b/drivers/nvme/host/fabrics.c @@ -592,7 +592,7 @@ bool nvmf_should_reconnect(struct nvme_ctrl *ctrl, int status) if (status > 0 && (status & NVME_STATUS_DNR)) return false; - if (status == -EKEYREJECTED) + if (status == -EKEYREJECTED || status == -ENOKEY) return false; if (ctrl->opts->max_reconnects == -1 || From c3cd1d514eb03c55c986a20bee8ea86c96682aff Mon Sep 17 00:00:00 2001 From: Pei Xiao Date: Fri, 5 Dec 2025 10:02:41 +0800 Subject: [PATCH 1213/2333] hwmon: (emc2305) fix double put in emc2305_probe_childs_from_dt [ Upstream commit 541dfb49dcb80c2509e030842de77adfb77820f5 ] ./drivers/hwmon/emc2305.c:597:4-15: ERROR: probable double put Device node iterators put the previous value of the index variable, so an explicit put causes a double put. Signed-off-by: Pei Xiao Link: https://lore.kernel.org/r/tencent_CD373F952BE48697C949E39CB5EB77841D06@qq.com Signed-off-by: Guenter Roeck Signed-off-by: Sasha Levin --- drivers/hwmon/emc2305.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/hwmon/emc2305.c b/drivers/hwmon/emc2305.c index 84cb9b72cb6c2..ceae96c07ac45 100644 --- a/drivers/hwmon/emc2305.c +++ b/drivers/hwmon/emc2305.c @@ -593,10 +593,8 @@ static int emc2305_probe_childs_from_dt(struct device *dev) for_each_child_of_node(dev->of_node, child) { if (of_property_present(child, "reg")) { ret = emc2305_of_parse_pwm_child(dev, child, data); - if (ret) { - of_node_put(child); + if (ret) continue; - } count++; } } From 6455d25857f21841daa33bf8d732ebc134280a02 Mon Sep 17 00:00:00 2001 From: "Chia-Lin Kao (AceLan)" Date: Thu, 27 Nov 2025 15:04:07 +0800 Subject: [PATCH 1214/2333] platform/x86/intel/hid: Add Dell Pro Rugged 10/12 tablet to VGBS DMI quirks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit b169e1733cadb614e87f69d7a5ae1b186c50d313 ] Dell Pro Rugged 10/12 tablets has a reliable VGBS method. If VGBS is not called on boot, the on-screen keyboard won't appear if the device is booted without a keyboard. Call VGBS on boot on thess devices to get the initial state of SW_TABLET_MODE in a reliable way. Signed-off-by: Chia-Lin Kao (AceLan) Reviewed-by: Hans de Goede Link: https://patch.msgid.link/20251127070407.656463-1-acelan.kao@canonical.com Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen Signed-off-by: Sasha Levin --- drivers/platform/x86/intel/hid.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/platform/x86/intel/hid.c b/drivers/platform/x86/intel/hid.c index 9c07a7faf18fe..560cc063198e1 100644 --- a/drivers/platform/x86/intel/hid.c +++ b/drivers/platform/x86/intel/hid.c @@ -177,6 +177,18 @@ static const struct dmi_system_id dmi_vgbs_allow_list[] = { DMI_MATCH(DMI_PRODUCT_NAME, "HP Elite Dragonfly G2 Notebook PC"), }, }, + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Dell Pro Rugged 10 Tablet RA00260"), + }, + }, + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Dell Pro Rugged 12 Tablet RA02260"), + }, + }, { } }; From 7f39b9d0e86ed6236b9a5fb67616ab1f76c4f150 Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Fri, 28 Nov 2025 09:30:06 +0100 Subject: [PATCH 1215/2333] MIPS: ftrace: Fix memory corruption when kernel is located beyond 32 bits [ Upstream commit 36dac9a3dda1f2bae343191bc16b910c603cac25 ] Since commit e424054000878 ("MIPS: Tracing: Reduce the overhead of dynamic Function Tracer"), the macro UASM_i_LA_mostly has been used, and this macro can generate more than 2 instructions. At the same time, the code in ftrace assumes that no more than 2 instructions can be generated, which is why it stores them in an int[2] array. However, as previously noted, the macro UASM_i_LA_mostly (and now UASM_i_LA) causes a buffer overflow when _mcount is beyond 32 bits. This leads to corruption of the variables located in the __read_mostly section. This corruption was observed because the variable __cpu_primary_thread_mask was corrupted, causing a hang very early during boot. This fix prevents the corruption by avoiding the generation of instructions if they could exceed 2 instructions in length. Fortunately, insn_la_mcount is only used if the instrumented code is located outside the kernel code section, so dynamic ftrace can still be used, albeit in a more limited scope. This is still preferable to corrupting memory and/or crashing the kernel. Signed-off-by: Gregory CLEMENT Signed-off-by: Thomas Bogendoerfer Signed-off-by: Sasha Levin --- arch/mips/kernel/ftrace.c | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/arch/mips/kernel/ftrace.c b/arch/mips/kernel/ftrace.c index f39e85fd58fa9..b15615b285690 100644 --- a/arch/mips/kernel/ftrace.c +++ b/arch/mips/kernel/ftrace.c @@ -54,10 +54,20 @@ static inline void ftrace_dyn_arch_init_insns(void) u32 *buf; unsigned int v1; - /* la v1, _mcount */ - v1 = 3; - buf = (u32 *)&insn_la_mcount[0]; - UASM_i_LA(&buf, v1, MCOUNT_ADDR); + /* If we are not in compat space, the number of generated + * instructions will exceed the maximum expected limit of 2. + * To prevent buffer overflow, we avoid generating them. + * insn_la_mcount will not be used later in ftrace_make_call. + */ + if (uasm_in_compat_space_p(MCOUNT_ADDR)) { + /* la v1, _mcount */ + v1 = 3; + buf = (u32 *)&insn_la_mcount[0]; + UASM_i_LA(&buf, v1, MCOUNT_ADDR); + } else { + pr_warn("ftrace: mcount address beyond 32 bits is not supported (%lX)\n", + MCOUNT_ADDR); + } /* jal (ftrace_caller + 8), jump over the first two instruction */ buf = (u32 *)&insn_jal_ftrace_caller; @@ -189,6 +199,13 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) unsigned int new; unsigned long ip = rec->ip; + /* When the code to patch does not belong to the kernel code + * space, we must use insn_la_mcount. However, if MCOUNT_ADDR + * is not in compat space, insn_la_mcount is not usable. + */ + if (!core_kernel_text(ip) && !uasm_in_compat_space_p(MCOUNT_ADDR)) + return -EFAULT; + new = core_kernel_text(ip) ? insn_jal_ftrace_caller : insn_la_mcount[0]; #ifdef CONFIG_64BIT From e64d5d45ffa80ef61f762dfa357aea5d6dc0e245 Mon Sep 17 00:00:00 2001 From: John Garry Date: Thu, 11 Dec 2025 10:06:51 +0000 Subject: [PATCH 1216/2333] scsi: scsi_debug: Fix atomic write enable module param description [ Upstream commit 1f7d6e2efeedd8f545d3e0e9bf338023bf4ea584 ] The atomic write enable module param is "atomic_wr", and not "atomic_write", so fix the module param description. Fixes: 84f3a3c01d70 ("scsi: scsi_debug: Atomic write support") Signed-off-by: John Garry Reviewed-by: Bart Van Assche Link: https://patch.msgid.link/20251211100651.9056-1-john.g.garry@oracle.com Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin --- drivers/scsi/scsi_debug.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index b2ab97be5db3d..047d56d23beab 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -7410,7 +7410,7 @@ MODULE_PARM_DESC(lbprz, MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)"); MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)"); MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)"); -MODULE_PARM_DESC(atomic_write, "enable ATOMIC WRITE support, support WRITE ATOMIC(16) (def=0)"); +MODULE_PARM_DESC(atomic_wr, "enable ATOMIC WRITE support, support WRITE ATOMIC(16) (def=0)"); MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)"); MODULE_PARM_DESC(lun_format, "LUN format: 0->peripheral (def); 1 --> flat address method"); MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)"); From 19648135e904bce447d368ecb6136e5da809639c Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Mon, 17 Nov 2025 15:51:35 +0100 Subject: [PATCH 1217/2333] drm/msm: adreno: fix deferencing ifpc_reglist when not declared [ Upstream commit 129049d4fe22c998ae9fd1ec479fbb4ed5338c15 ] On plaforms with an a7xx GPU not supporting IFPC, the ifpc_reglist if still deferenced in a7xx_patch_pwrup_reglist() which causes a kernel crash: Unable to handle kernel NULL pointer dereference at virtual address 0000000000000008 ... pc : a6xx_hw_init+0x155c/0x1e4c [msm] lr : a6xx_hw_init+0x9a8/0x1e4c [msm] ... Call trace: a6xx_hw_init+0x155c/0x1e4c [msm] (P) msm_gpu_hw_init+0x58/0x88 [msm] adreno_load_gpu+0x94/0x1fc [msm] msm_open+0xe4/0xf4 [msm] drm_file_alloc+0x1a0/0x2e4 [drm] drm_client_init+0x7c/0x104 [drm] drm_fbdev_client_setup+0x94/0xcf0 [drm_client_lib] drm_client_setup+0xb4/0xd8 [drm_client_lib] msm_drm_kms_post_init+0x2c/0x3c [msm] msm_drm_init+0x1a4/0x228 [msm] msm_drm_bind+0x30/0x3c [msm] ... Check the validity of ifpc_reglist before deferencing the table to setup the register values. Fixes: a6a0157cc68e ("drm/msm/a6xx: Enable IFPC on Adreno X1-85") Signed-off-by: Neil Armstrong Reviewed-by: Akhil P Oommen Patchwork: https://patchwork.freedesktop.org/patch/688944/ Message-ID: <20251117-topic-sm8x50-fix-a6xx-non-ifpc-v1-1-e4473cbf5903@linaro.org> Signed-off-by: Rob Clark Signed-off-by: Sasha Levin --- drivers/gpu/drm/msm/adreno/a6xx_gpu.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c index 6f7ed07670b12..d1eaa849b1978 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c @@ -837,15 +837,17 @@ static void a7xx_patch_pwrup_reglist(struct msm_gpu *gpu) lock->gpu_req = lock->cpu_req = lock->turn = 0; reglist = adreno_gpu->info->a6xx->ifpc_reglist; - lock->ifpc_list_len = reglist->count; + if (reglist) { + lock->ifpc_list_len = reglist->count; - /* - * For each entry in each of the lists, write the offset and the current - * register value into the GPU buffer - */ - for (i = 0; i < reglist->count; i++) { - *dest++ = reglist->regs[i]; - *dest++ = gpu_read(gpu, reglist->regs[i]); + /* + * For each entry in each of the lists, write the offset and the current + * register value into the GPU buffer + */ + for (i = 0; i < reglist->count; i++) { + *dest++ = reglist->regs[i]; + *dest++ = gpu_read(gpu, reglist->regs[i]); + } } reglist = adreno_gpu->info->a6xx->pwrup_reglist; From 2c46497eb148ec61909f4101b8443f3c4c2daaec Mon Sep 17 00:00:00 2001 From: Alok Tiwari Date: Thu, 13 Nov 2025 00:28:31 -0800 Subject: [PATCH 1218/2333] drm/msm/a6xx: move preempt_prepare_postamble after error check [ Upstream commit ef3b04091fd8bc737dc45312375df8625b8318e2 ] Move the call to preempt_prepare_postamble() after verifying that preempt_postamble_ptr is valid. If preempt_postamble_ptr is NULL, dereferencing it in preempt_prepare_postamble() would lead to a crash. This change avoids calling the preparation function when the postamble allocation has failed, preventing potential NULL pointer dereference and ensuring proper error handling. Fixes: 50117cad0c50 ("drm/msm/a6xx: Use posamble to reset counters on preemption") Signed-off-by: Alok Tiwari Patchwork: https://patchwork.freedesktop.org/patch/687659/ Message-ID: <20251113082839.3821867-1-alok.a.tiwari@oracle.com> Signed-off-by: Rob Clark Signed-off-by: Sasha Levin --- drivers/gpu/drm/msm/adreno/a6xx_preempt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/msm/adreno/a6xx_preempt.c b/drivers/gpu/drm/msm/adreno/a6xx_preempt.c index afc5f4aa3b173..747a22afad9f6 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_preempt.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_preempt.c @@ -454,11 +454,11 @@ void a6xx_preempt_init(struct msm_gpu *gpu) gpu->vm, &a6xx_gpu->preempt_postamble_bo, &a6xx_gpu->preempt_postamble_iova); - preempt_prepare_postamble(a6xx_gpu); - if (IS_ERR(a6xx_gpu->preempt_postamble_ptr)) goto fail; + preempt_prepare_postamble(a6xx_gpu); + timer_setup(&a6xx_gpu->preempt_timer, a6xx_preempt_timer, 0); return; From 13456b4f1033d911f8bf3a0a1195656f293ba0f6 Mon Sep 17 00:00:00 2001 From: Caleb Sander Mateos Date: Fri, 12 Dec 2025 17:19:49 -0700 Subject: [PATCH 1219/2333] ublk: clean up user copy references on ublk server exit [ Upstream commit daa24603d9f0808929514ee62ced30052ca7221c ] If a ublk server process releases a ublk char device file, any requests dispatched to the ublk server but not yet completed will retain a ref value of UBLK_REFCOUNT_INIT. Before commit e63d2228ef83 ("ublk: simplify aborting ublk request"), __ublk_fail_req() would decrement the reference count before completing the failed request. However, that commit optimized __ublk_fail_req() to call __ublk_complete_rq() directly without decrementing the request reference count. The leaked reference count incorrectly allows user copy and zero copy operations on the completed ublk request. It also triggers the WARN_ON_ONCE(refcount_read(&io->ref)) warnings in ublk_queue_reinit() and ublk_deinit_queue(). Commit c5c5eb24ed61 ("ublk: avoid ublk_io_release() called after ublk char dev is closed") already fixed the issue for ublk devices using UBLK_F_SUPPORT_ZERO_COPY or UBLK_F_AUTO_BUF_REG. However, the reference count leak also affects UBLK_F_USER_COPY, the other reference-counted data copy mode. Fix the condition in ublk_check_and_reset_active_ref() to include all reference-counted data copy modes. This ensures that any ublk requests still owned by the ublk server when it exits have their reference counts reset to 0. Signed-off-by: Caleb Sander Mateos Fixes: e63d2228ef83 ("ublk: simplify aborting ublk request") Reviewed-by: Ming Lei Signed-off-by: Jens Axboe Signed-off-by: Sasha Levin --- drivers/block/ublk_drv.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c index fa7b0481ea046..d8079ea8f8ca1 100644 --- a/drivers/block/ublk_drv.c +++ b/drivers/block/ublk_drv.c @@ -1674,8 +1674,7 @@ static bool ublk_check_and_reset_active_ref(struct ublk_device *ub) { int i, j; - if (!(ub->dev_info.flags & (UBLK_F_SUPPORT_ZERO_COPY | - UBLK_F_AUTO_BUF_REG))) + if (!ublk_dev_need_req_ref(ub)) return false; for (i = 0; i < ub->dev_info.nr_hw_queues; i++) { From 74dd8b66f9d242e9a79a54d67605e7aa97def214 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sat, 20 Dec 2025 11:46:10 +0300 Subject: [PATCH 1220/2333] block: rnbd-clt: Fix signedness bug in init_dev() [ Upstream commit 1ddb815fdfd45613c32e9bd1f7137428f298e541 ] The "dev->clt_device_id" variable is set using ida_alloc_max() which returns an int and in particular it returns negative error codes. Change the type from u32 to int to fix the error checking. Fixes: c9b5645fd8ca ("block: rnbd-clt: Fix leaked ID in init_dev()") Signed-off-by: Dan Carpenter Signed-off-by: Jens Axboe Signed-off-by: Sasha Levin --- drivers/block/rnbd/rnbd-clt.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/block/rnbd/rnbd-clt.h b/drivers/block/rnbd/rnbd-clt.h index a48e040abe639..fbc1ed766025c 100644 --- a/drivers/block/rnbd/rnbd-clt.h +++ b/drivers/block/rnbd/rnbd-clt.h @@ -112,7 +112,7 @@ struct rnbd_clt_dev { struct rnbd_queue *hw_queues; u32 device_id; /* local Idr index - used to track minor number allocations. */ - u32 clt_device_id; + int clt_device_id; struct mutex lock; enum rnbd_clt_dev_state dev_state; refcount_t refcount; From f8b19571b1db094525a7d4db9e16df2a1b4a6cfd Mon Sep 17 00:00:00 2001 From: Stefano Garzarella Date: Wed, 26 Nov 2025 14:38:26 +0100 Subject: [PATCH 1221/2333] vhost/vsock: improve RCU read sections around vhost_vsock_get() [ Upstream commit d8ee3cfdc89b75dc059dc21c27bef2c1440f67eb ] vhost_vsock_get() uses hash_for_each_possible_rcu() to find the `vhost_vsock` associated with the `guest_cid`. hash_for_each_possible_rcu() should only be called within an RCU read section, as mentioned in the following comment in include/linux/rculist.h: /** * hlist_for_each_entry_rcu - iterate over rcu list of given type * @pos: the type * to use as a loop cursor. * @head: the head for your list. * @member: the name of the hlist_node within the struct. * @cond: optional lockdep expression if called from non-RCU protection. * * This list-traversal primitive may safely run concurrently with * the _rcu list-mutation primitives such as hlist_add_head_rcu() * as long as the traversal is guarded by rcu_read_lock(). */ Currently, all calls to vhost_vsock_get() are between rcu_read_lock() and rcu_read_unlock() except for calls in vhost_vsock_set_cid() and vhost_vsock_reset_orphans(). In both cases, the current code is safe, but we can make improvements to make it more robust. About vhost_vsock_set_cid(), when building the kernel with CONFIG_PROVE_RCU_LIST enabled, we get the following RCU warning when the user space issues `ioctl(dev, VHOST_VSOCK_SET_GUEST_CID, ...)` : WARNING: suspicious RCU usage 6.18.0-rc7 #62 Not tainted ----------------------------- drivers/vhost/vsock.c:74 RCU-list traversed in non-reader section!! other info that might help us debug this: rcu_scheduler_active = 2, debug_locks = 1 1 lock held by rpc-libvirtd/3443: #0: ffffffffc05032a8 (vhost_vsock_mutex){+.+.}-{4:4}, at: vhost_vsock_dev_ioctl+0x2ff/0x530 [vhost_vsock] stack backtrace: CPU: 2 UID: 0 PID: 3443 Comm: rpc-libvirtd Not tainted 6.18.0-rc7 #62 PREEMPT(none) Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.17.0-7.fc42 06/10/2025 Call Trace: dump_stack_lvl+0x75/0xb0 dump_stack+0x14/0x1a lockdep_rcu_suspicious.cold+0x4e/0x97 vhost_vsock_get+0x8f/0xa0 [vhost_vsock] vhost_vsock_dev_ioctl+0x307/0x530 [vhost_vsock] __x64_sys_ioctl+0x4f2/0xa00 x64_sys_call+0xed0/0x1da0 do_syscall_64+0x73/0xfa0 entry_SYSCALL_64_after_hwframe+0x76/0x7e ... This is not a real problem, because the vhost_vsock_get() caller, i.e. vhost_vsock_set_cid(), holds the `vhost_vsock_mutex` used by the hash table writers. Anyway, to prevent that warning, add lockdep_is_held() condition to hash_for_each_possible_rcu() to verify that either the caller is in an RCU read section or `vhost_vsock_mutex` is held when CONFIG_PROVE_RCU_LIST is enabled; and also clarify the comment for vhost_vsock_get() to better describe the locking requirements and the scope of the returned pointer validity. About vhost_vsock_reset_orphans(), currently this function is only called via vsock_for_each_connected_socket(), which holds the `vsock_table_lock` spinlock (which is also an RCU read-side critical section). However, add an explicit RCU read lock there to make the code more robust and explicit about the RCU requirements, and to prevent issues if the calling context changes in the future or if vhost_vsock_reset_orphans() is called from other contexts. Fixes: 834e772c8db0 ("vhost/vsock: fix use-after-free in network stack callers") Cc: stefanha@redhat.com Signed-off-by: Stefano Garzarella Reviewed-by: Stefan Hajnoczi Message-Id: <20251126133826.142496-1-sgarzare@redhat.com> Message-ID: <20251126210313.GA499503@fedora> Acked-by: Jason Wang Signed-off-by: Michael S. Tsirkin Signed-off-by: Sasha Levin --- drivers/vhost/vsock.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/drivers/vhost/vsock.c b/drivers/vhost/vsock.c index ae01457ea2cdb..78cc66fbb3dd6 100644 --- a/drivers/vhost/vsock.c +++ b/drivers/vhost/vsock.c @@ -64,14 +64,15 @@ static u32 vhost_transport_get_local_cid(void) return VHOST_VSOCK_DEFAULT_HOST_CID; } -/* Callers that dereference the return value must hold vhost_vsock_mutex or the - * RCU read lock. +/* Callers must be in an RCU read section or hold the vhost_vsock_mutex. + * The return value can only be dereferenced while within the section. */ static struct vhost_vsock *vhost_vsock_get(u32 guest_cid) { struct vhost_vsock *vsock; - hash_for_each_possible_rcu(vhost_vsock_hash, vsock, hash, guest_cid) { + hash_for_each_possible_rcu(vhost_vsock_hash, vsock, hash, guest_cid, + lockdep_is_held(&vhost_vsock_mutex)) { u32 other_cid = vsock->guest_cid; /* Skip instances that have no CID yet */ @@ -707,9 +708,15 @@ static void vhost_vsock_reset_orphans(struct sock *sk) * executing. */ + rcu_read_lock(); + /* If the peer is still valid, no need to reset connection */ - if (vhost_vsock_get(vsk->remote_addr.svm_cid)) + if (vhost_vsock_get(vsk->remote_addr.svm_cid)) { + rcu_read_unlock(); return; + } + + rcu_read_unlock(); /* If the close timeout is pending, let it expire. This avoids races * with the timeout callback. From bb82aaee16907dc4d0b9b0ca7953ceb3edc328c6 Mon Sep 17 00:00:00 2001 From: Zilin Guan Date: Wed, 24 Dec 2025 15:21:42 +0000 Subject: [PATCH 1222/2333] cifs: Fix memory and information leak in smb3_reconfigure() [ Upstream commit cb6d5aa9c0f10074f1ad056c3e2278ad2cc7ec8d ] In smb3_reconfigure(), if smb3_sync_session_ctx_passwords() fails, the function returns immediately without freeing and erasing the newly allocated new_password and new_password2. This causes both a memory leak and a potential information leak. Fix this by calling kfree_sensitive() on both password buffers before returning in this error case. Fixes: 0f0e357902957 ("cifs: during remount, make sure passwords are in sync") Signed-off-by: Zilin Guan Reviewed-by: ChenXiaoSong Signed-off-by: Steve French Signed-off-by: Sasha Levin --- fs/smb/client/fs_context.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/smb/client/fs_context.c b/fs/smb/client/fs_context.c index 2a0d8b87bd8ea..d8bd3cdc535df 100644 --- a/fs/smb/client/fs_context.c +++ b/fs/smb/client/fs_context.c @@ -1080,6 +1080,8 @@ static int smb3_reconfigure(struct fs_context *fc) rc = smb3_sync_session_ctx_passwords(cifs_sb, ses); if (rc) { mutex_unlock(&ses->session_mutex); + kfree_sensitive(new_password); + kfree_sensitive(new_password2); return rc; } From 505e8c7f6ca1c3e8f4caa2bc598f47fa3ac664e3 Mon Sep 17 00:00:00 2001 From: Lyude Paul Date: Fri, 7 Nov 2025 15:25:56 -0500 Subject: [PATCH 1223/2333] rust/drm/gem: Fix missing header in `Object` rustdoc commit e54ad0cd3673c93cdafda58505eaa81610fe3aef upstream. Invariants should be prefixed with a # to turn it into a header. There are no functional changes in this patch. Cc: stable@vger.kernel.org Fixes: c284d3e42338 ("rust: drm: gem: Add GEM object abstraction") Signed-off-by: Lyude Paul Link: https://patch.msgid.link/20251107202603.465932-1-lyude@redhat.com Signed-off-by: Alice Ryhl Signed-off-by: Greg Kroah-Hartman --- rust/kernel/drm/gem/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust/kernel/drm/gem/mod.rs b/rust/kernel/drm/gem/mod.rs index 30c853988b942..73b5f0bf3f85d 100644 --- a/rust/kernel/drm/gem/mod.rs +++ b/rust/kernel/drm/gem/mod.rs @@ -184,7 +184,7 @@ impl BaseObject for T {} /// A base GEM object. /// -/// Invariants +/// # Invariants /// /// - `self.obj` is a valid instance of a `struct drm_gem_object`. /// - `self.dev` is always a valid pointer to a `struct drm_device`. From bee1f36801dba1d079c9eaf9a7d1263ea90cbaff Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Tue, 11 Nov 2025 14:23:33 +0000 Subject: [PATCH 1224/2333] rust_binder: avoid mem::take on delivered_deaths commit 6c37bebd8c926ad01ef157c0d123633a203e5c0d upstream. Similar to the previous commit, List::remove is used on delivered_deaths, so do not use mem::take on it as that may result in violations of the List::remove safety requirements. I don't think this particular case can be triggered because it requires fd close to run in parallel with an ioctl on the same fd. But let's not tempt fate. Cc: stable@vger.kernel.org Fixes: eafedbc7c050 ("rust_binder: add Rust Binder driver") Signed-off-by: Alice Ryhl Acked-by: Miguel Ojeda Link: https://patch.msgid.link/20251111-binder-fix-list-remove-v1-2-8ed14a0da63d@google.com Signed-off-by: Greg Kroah-Hartman Signed-off-by: Greg Kroah-Hartman --- drivers/android/binder/process.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/android/binder/process.rs b/drivers/android/binder/process.rs index 7607353a5e924..ef4dbb2b571c7 100644 --- a/drivers/android/binder/process.rs +++ b/drivers/android/binder/process.rs @@ -1362,8 +1362,12 @@ impl Process { work.into_arc().cancel(); } - let delivered_deaths = take(&mut self.inner.lock().delivered_deaths); - drop(delivered_deaths); + // Clear delivered_deaths list. + // + // Scope ensures that MutexGuard is dropped while executing the body. + while let Some(delivered_death) = { self.inner.lock().delivered_deaths.pop_front() } { + drop(delivered_death); + } // Free any resources kept alive by allocated buffers. let omapping = self.inner.lock().mapping.take(); From 48298e1ba378c04876dc8feb8dfc412706403762 Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Fri, 5 Dec 2025 01:06:39 +0900 Subject: [PATCH 1225/2333] rust: dma: add helpers for architectures without CONFIG_HAS_DMA commit d8932355f8c5673106eca49abd142f8fe0c1fe8b upstream. Add dma_set_mask(), dma_set_coherent_mask(), dma_map_sgtable(), and dma_max_mapping_size() helpers to fix a build error when CONFIG_HAS_DMA is not enabled. Note that when CONFIG_HAS_DMA is enabled, they are included in both bindings_generated.rs and bindings_helpers_generated.rs. The former takes precedence so behavior remains unchanged in that case. This fixes the following build error on UML: error[E0425]: cannot find function `dma_set_mask` in crate `bindings` --> rust/kernel/dma.rs:46:38 | 46 | to_result(unsafe { bindings::dma_set_mask(self.as_ref().as_raw(), mask.value()) }) | ^^^^^^^^^^^^ help: a function with a similar name exists: `xa_set_mark` | ::: rust/bindings/bindings_generated.rs:24690:5 | 24690 | pub fn xa_set_mark(arg1: *mut xarray, index: ffi::c_ulong, arg2: xa_mark_t); | ---------------------------------------------------------------------------- similarly named function `xa_set_mark` defined here error[E0425]: cannot find function `dma_set_coherent_mask` in crate `bindings` --> rust/kernel/dma.rs:63:38 | 63 | to_result(unsafe { bindings::dma_set_coherent_mask(self.as_ref().as_raw(), mask.value()) }) | ^^^^^^^^^^^^^^^^^^^^^ help: a function with a similar name exists: `dma_coherent_ok` | ::: rust/bindings/bindings_generated.rs:52745:5 | 52745 | pub fn dma_coherent_ok(dev: *mut device, phys: phys_addr_t, size: usize) -> bool_; | ---------------------------------------------------------------------------------- similarly named function `dma_coherent_ok` defined here error[E0425]: cannot find function `dma_map_sgtable` in crate `bindings` --> rust/kernel/scatterlist.rs:212:23 | 212 | bindings::dma_map_sgtable(dev.as_raw(), sgt.as_ptr(), dir.into(), 0) | ^^^^^^^^^^^^^^^ help: a function with a similar name exists: `dma_unmap_sgtable` | ::: rust/bindings/bindings_helpers_generated.rs:1351:5 | 1351 | / pub fn dma_unmap_sgtable( 1352 | | dev: *mut device, 1353 | | sgt: *mut sg_table, 1354 | | dir: dma_data_direction, 1355 | | attrs: ffi::c_ulong, 1356 | | ); | |______- similarly named function `dma_unmap_sgtable` defined here error[E0425]: cannot find function `dma_max_mapping_size` in crate `bindings` --> rust/kernel/scatterlist.rs:356:52 | 356 | let max_segment = match unsafe { bindings::dma_max_mapping_size(dev.as_raw()) } { | ^^^^^^^^^^^^^^^^^^^^ not found in `bindings` error: aborting due to 4 previous errors Cc: stable@vger.kernel.org # v6.17+ Fixes: 101d66828a4ee ("rust: dma: add DMA addressing capabilities") Signed-off-by: FUJITA Tomonori Reviewed-by: David Gow Reviewed-by: Alice Ryhl Link: https://patch.msgid.link/20251204160639.364936-1-fujita.tomonori@gmail.com [ Use relative paths in the error splat; add 'dma' prefix. - Danilo ] Signed-off-by: Danilo Krummrich Signed-off-by: Greg Kroah-Hartman --- rust/helpers/dma.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/rust/helpers/dma.c b/rust/helpers/dma.c index 6e741c1972425..2afa32c21c946 100644 --- a/rust/helpers/dma.c +++ b/rust/helpers/dma.c @@ -19,3 +19,24 @@ int rust_helper_dma_set_mask_and_coherent(struct device *dev, u64 mask) { return dma_set_mask_and_coherent(dev, mask); } + +int rust_helper_dma_set_mask(struct device *dev, u64 mask) +{ + return dma_set_mask(dev, mask); +} + +int rust_helper_dma_set_coherent_mask(struct device *dev, u64 mask) +{ + return dma_set_coherent_mask(dev, mask); +} + +int rust_helper_dma_map_sgtable(struct device *dev, struct sg_table *sgt, + enum dma_data_direction dir, unsigned long attrs) +{ + return dma_map_sgtable(dev, sgt, dir, attrs); +} + +size_t rust_helper_dma_max_mapping_size(struct device *dev) +{ + return dma_max_mapping_size(dev); +} From 93b3274587e8d747d99c2cb77164a9b2304c0935 Mon Sep 17 00:00:00 2001 From: Marko Turk Date: Wed, 10 Dec 2025 12:25:51 +0100 Subject: [PATCH 1226/2333] samples: rust: fix endianness issue in rust_driver_pci commit e2f1081ca8f18c146e8f928486deac61eca2b517 upstream. MMIO backend of PCI Bar always assumes little-endian devices and will convert to CPU endianness automatically. Remove the u32::from_le conversion which would cause a bug on big-endian machines. Cc: stable@vger.kernel.org Reviewed-by: Dirk Behme Signed-off-by: Marko Turk Fixes: 685376d18e9a ("samples: rust: add Rust PCI sample driver") Link: https://patch.msgid.link/20251210112503.62925-2-mt@markoturk.info Signed-off-by: Danilo Krummrich Signed-off-by: Greg Kroah-Hartman --- samples/rust/rust_driver_pci.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/rust/rust_driver_pci.rs b/samples/rust/rust_driver_pci.rs index 55a683c39ed91..ea3063e558b1a 100644 --- a/samples/rust/rust_driver_pci.rs +++ b/samples/rust/rust_driver_pci.rs @@ -48,7 +48,7 @@ impl SampleDriver { // Select the test. bar.write8(index.0, Regs::TEST); - let offset = u32::from_le(bar.read32(Regs::OFFSET)) as usize; + let offset = bar.read32(Regs::OFFSET) as usize; let data = bar.read8(Regs::DATA); // Write `data` to `offset` to increase `count` by one. From 0bf59179bdef493a39061cfd3263bc0578f852b0 Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Wed, 12 Nov 2025 09:48:32 +0000 Subject: [PATCH 1227/2333] rust: io: define ResourceSize as resource_size_t commit 919b72922717e396be9435c83916b9969505bd23 upstream. These typedefs are always equivalent so this should not change anything, but the code makes a lot more sense like this. Cc: stable@vger.kernel.org Signed-off-by: Alice Ryhl Fixes: 493fc33ec252 ("rust: io: add resource abstraction") Link: https://patch.msgid.link/20251112-resource-phys-typedefs-v2-1-538307384f82@google.com Signed-off-by: Danilo Krummrich Signed-off-by: Greg Kroah-Hartman --- rust/kernel/io/resource.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust/kernel/io/resource.rs b/rust/kernel/io/resource.rs index bea3ee0ed87b5..11b6bb9678b4e 100644 --- a/rust/kernel/io/resource.rs +++ b/rust/kernel/io/resource.rs @@ -16,7 +16,7 @@ use crate::types::Opaque; /// /// This is a type alias to either `u32` or `u64` depending on the config option /// `CONFIG_PHYS_ADDR_T_64BIT`, and it can be a u64 even on 32-bit architectures. -pub type ResourceSize = bindings::phys_addr_t; +pub type ResourceSize = bindings::resource_size_t; /// A region allocated from a parent [`Resource`]. /// From 52df55b21ede5fc0418972754f516a200a460709 Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Wed, 12 Nov 2025 09:48:33 +0000 Subject: [PATCH 1228/2333] rust: io: move ResourceSize to top-level io module commit dfd67993044f507ba8fd6ee9956f923ba4b7e851 upstream. Resource sizes are a general concept for dealing with physical addresses, and not specific to the Resource type, which is just one way to access physical addresses. Thus, move the typedef to the io module. Still keep a re-export under resource. This avoids this commit from being a flag-day, but I also think it's a useful re-export in general so that you can import use kernel::io::resource::{Resource, ResourceSize}; instead of having to write use kernel::io::{ resource::Resource, ResourceSize, }; in the specific cases where you need ResourceSize because you are using the Resource type. Therefore I think it makes sense to keep this re-export indefinitely and it is *not* intended as a temporary re-export for migration purposes. Cc: stable@vger.kernel.org # for v6.18 [1] Signed-off-by: Alice Ryhl Link: https://patch.msgid.link/20251112-resource-phys-typedefs-v2-2-538307384f82@google.com Link: https://lore.kernel.org/all/20251112-resource-phys-typedefs-v2-0-538307384f82@google.com/ [1] Signed-off-by: Danilo Krummrich Signed-off-by: Greg Kroah-Hartman --- rust/kernel/io.rs | 6 ++++++ rust/kernel/io/resource.rs | 6 +----- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/rust/kernel/io.rs b/rust/kernel/io.rs index ee182b0b5452d..6465ea94e85d6 100644 --- a/rust/kernel/io.rs +++ b/rust/kernel/io.rs @@ -13,6 +13,12 @@ pub mod resource; pub use resource::Resource; +/// Resource Size type. +/// +/// This is a type alias to either `u32` or `u64` depending on the config option +/// `CONFIG_PHYS_ADDR_T_64BIT`, and it can be a u64 even on 32-bit architectures. +pub type ResourceSize = bindings::resource_size_t; + /// Raw representation of an MMIO region. /// /// By itself, the existence of an instance of this structure does not provide any guarantees that diff --git a/rust/kernel/io/resource.rs b/rust/kernel/io/resource.rs index 11b6bb9678b4e..7fed41fc20307 100644 --- a/rust/kernel/io/resource.rs +++ b/rust/kernel/io/resource.rs @@ -12,11 +12,7 @@ use crate::prelude::*; use crate::str::{CStr, CString}; use crate::types::Opaque; -/// Resource Size type. -/// -/// This is a type alias to either `u32` or `u64` depending on the config option -/// `CONFIG_PHYS_ADDR_T_64BIT`, and it can be a u64 even on 32-bit architectures. -pub type ResourceSize = bindings::resource_size_t; +pub use super::ResourceSize; /// A region allocated from a parent [`Resource`]. /// From c30ed32690b23e5994ec8de4338896b687d46287 Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Wed, 12 Nov 2025 09:48:35 +0000 Subject: [PATCH 1229/2333] rust: io: add typedef for phys_addr_t commit dd6ff5cf56fb183fce605ca6a5bfce228cd8888b upstream. The C typedef phys_addr_t is missing an analogue in Rust, meaning that we end up using bindings::phys_addr_t or ResourceSize as a replacement in various places throughout the kernel. Fix that by introducing a new typedef on the Rust side. Place it next to the existing ResourceSize typedef since they're quite related to each other. Cc: stable@vger.kernel.org # for v6.18 [1] Signed-off-by: Alice Ryhl Link: https://patch.msgid.link/20251112-resource-phys-typedefs-v2-4-538307384f82@google.com Link: https://lore.kernel.org/all/20251112-resource-phys-typedefs-v2-0-538307384f82@google.com/ [1] Signed-off-by: Danilo Krummrich Signed-off-by: Greg Kroah-Hartman --- rust/kernel/devres.rs | 18 +++++++++++++++--- rust/kernel/io.rs | 20 +++++++++++++++++--- rust/kernel/io/resource.rs | 9 ++++++--- 3 files changed, 38 insertions(+), 9 deletions(-) diff --git a/rust/kernel/devres.rs b/rust/kernel/devres.rs index 2392c281459ef..835d9c11948e7 100644 --- a/rust/kernel/devres.rs +++ b/rust/kernel/devres.rs @@ -52,8 +52,20 @@ struct Inner { /// # Examples /// /// ```no_run -/// # use kernel::{bindings, device::{Bound, Device}, devres::Devres, io::{Io, IoRaw}}; -/// # use core::ops::Deref; +/// use kernel::{ +/// bindings, +/// device::{ +/// Bound, +/// Device, +/// }, +/// devres::Devres, +/// io::{ +/// Io, +/// IoRaw, +/// PhysAddr, +/// }, +/// }; +/// use core::ops::Deref; /// /// // See also [`pci::Bar`] for a real example. /// struct IoMem(IoRaw); @@ -66,7 +78,7 @@ struct Inner { /// unsafe fn new(paddr: usize) -> Result{ /// // SAFETY: By the safety requirements of this function [`paddr`, `paddr` + `SIZE`) is /// // valid for `ioremap`. -/// let addr = unsafe { bindings::ioremap(paddr as bindings::phys_addr_t, SIZE) }; +/// let addr = unsafe { bindings::ioremap(paddr as PhysAddr, SIZE) }; /// if addr.is_null() { /// return Err(ENOMEM); /// } diff --git a/rust/kernel/io.rs b/rust/kernel/io.rs index 6465ea94e85d6..56a435eb14e3a 100644 --- a/rust/kernel/io.rs +++ b/rust/kernel/io.rs @@ -13,6 +13,12 @@ pub mod resource; pub use resource::Resource; +/// Physical address type. +/// +/// This is a type alias to either `u32` or `u64` depending on the config option +/// `CONFIG_PHYS_ADDR_T_64BIT`, and it can be a u64 even on 32-bit architectures. +pub type PhysAddr = bindings::phys_addr_t; + /// Resource Size type. /// /// This is a type alias to either `u32` or `u64` depending on the config option @@ -68,8 +74,16 @@ impl IoRaw { /// # Examples /// /// ```no_run -/// # use kernel::{bindings, ffi::c_void, io::{Io, IoRaw}}; -/// # use core::ops::Deref; +/// use kernel::{ +/// bindings, +/// ffi::c_void, +/// io::{ +/// Io, +/// IoRaw, +/// PhysAddr, +/// }, +/// }; +/// use core::ops::Deref; /// /// // See also [`pci::Bar`] for a real example. /// struct IoMem(IoRaw); @@ -82,7 +96,7 @@ impl IoRaw { /// unsafe fn new(paddr: usize) -> Result{ /// // SAFETY: By the safety requirements of this function [`paddr`, `paddr` + `SIZE`) is /// // valid for `ioremap`. -/// let addr = unsafe { bindings::ioremap(paddr as bindings::phys_addr_t, SIZE) }; +/// let addr = unsafe { bindings::ioremap(paddr as PhysAddr, SIZE) }; /// if addr.is_null() { /// return Err(ENOMEM); /// } diff --git a/rust/kernel/io/resource.rs b/rust/kernel/io/resource.rs index 7fed41fc20307..0e86ee9c98d84 100644 --- a/rust/kernel/io/resource.rs +++ b/rust/kernel/io/resource.rs @@ -12,7 +12,10 @@ use crate::prelude::*; use crate::str::{CStr, CString}; use crate::types::Opaque; -pub use super::ResourceSize; +pub use super::{ + PhysAddr, + ResourceSize, // +}; /// A region allocated from a parent [`Resource`]. /// @@ -93,7 +96,7 @@ impl Resource { /// the region, or a part of it, is already in use. pub fn request_region( &self, - start: ResourceSize, + start: PhysAddr, size: ResourceSize, name: CString, flags: Flags, @@ -127,7 +130,7 @@ impl Resource { } /// Returns the start address of the resource. - pub fn start(&self) -> ResourceSize { + pub fn start(&self) -> PhysAddr { let inner = self.0.get(); // SAFETY: Safe as per the invariants of `Resource`. unsafe { (*inner).start } From 9e7c63c69f57b1db1a8a1542359a6167ff8fcef1 Mon Sep 17 00:00:00 2001 From: Jarkko Sakkinen Date: Sat, 18 Oct 2025 13:30:36 +0300 Subject: [PATCH 1230/2333] KEYS: trusted: Fix a memory leak in tpm2_load_cmd commit 62cd5d480b9762ce70d720a81fa5b373052ae05f upstream. 'tpm2_load_cmd' allocates a tempoary blob indirectly via 'tpm2_key_decode' but it is not freed in the failure paths. Address this by wrapping the blob into with a cleanup helper. Cc: stable@vger.kernel.org # v5.13+ Fixes: f2219745250f ("security: keys: trusted: use ASN.1 TPM2 key format for the blobs") Signed-off-by: Jarkko Sakkinen Signed-off-by: Greg Kroah-Hartman --- security/keys/trusted-keys/trusted_tpm2.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/security/keys/trusted-keys/trusted_tpm2.c b/security/keys/trusted-keys/trusted_tpm2.c index 024be262702fe..76a86f8a8d6c8 100644 --- a/security/keys/trusted-keys/trusted_tpm2.c +++ b/security/keys/trusted-keys/trusted_tpm2.c @@ -387,6 +387,7 @@ static int tpm2_load_cmd(struct tpm_chip *chip, struct trusted_key_options *options, u32 *blob_handle) { + u8 *blob_ref __free(kfree) = NULL; struct tpm_buf buf; unsigned int private_len; unsigned int public_len; @@ -400,6 +401,9 @@ static int tpm2_load_cmd(struct tpm_chip *chip, /* old form */ blob = payload->blob; payload->old_format = 1; + } else { + /* Bind for cleanup: */ + blob_ref = blob; } /* new format carries keyhandle but old format doesn't */ @@ -464,8 +468,6 @@ static int tpm2_load_cmd(struct tpm_chip *chip, (__be32 *) &buf.data[TPM_HEADER_SIZE]); out: - if (blob != payload->blob) - kfree(blob); tpm_buf_destroy(&buf); if (rc > 0) From 3dfe2e1531c837f18c541e1db90f6ef7890a497c Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 27 Nov 2025 14:42:43 +0100 Subject: [PATCH 1231/2333] clk: keystone: syscon-clk: fix regmap leak on probe failure commit 9c75986a298f121ed2c6599b05e51d9a34e77068 upstream. The mmio regmap allocated during probe is never freed. Switch to using the device managed allocator so that the regmap is released on probe failures (e.g. probe deferral) and on driver unbind. Fixes: a250cd4c1901 ("clk: keystone: syscon-clk: Do not use syscon helper to build regmap") Cc: stable@vger.kernel.org # 6.15 Cc: Andrew Davis Signed-off-by: Johan Hovold Signed-off-by: Stephen Boyd Signed-off-by: Greg Kroah-Hartman --- drivers/clk/keystone/syscon-clk.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/keystone/syscon-clk.c b/drivers/clk/keystone/syscon-clk.c index c509929da8545..ecf180a7949c9 100644 --- a/drivers/clk/keystone/syscon-clk.c +++ b/drivers/clk/keystone/syscon-clk.c @@ -129,7 +129,7 @@ static int ti_syscon_gate_clk_probe(struct platform_device *pdev) if (IS_ERR(base)) return PTR_ERR(base); - regmap = regmap_init_mmio(dev, base, &ti_syscon_regmap_cfg); + regmap = devm_regmap_init_mmio(dev, base, &ti_syscon_regmap_cfg); if (IS_ERR(regmap)) return dev_err_probe(dev, PTR_ERR(regmap), "failed to get regmap\n"); From 13a8f7b88c2d40c6b33f6216190478dda95d385f Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Mon, 1 Dec 2025 13:25:22 -0700 Subject: [PATCH 1232/2333] io_uring/poll: correctly handle io_poll_add() return value on update commit 84230ad2d2afbf0c44c32967e525c0ad92e26b4e upstream. When the core of io_uring was updated to handle completions consistently and with fixed return codes, the POLL_REMOVE opcode with updates got slightly broken. If a POLL_ADD is pending and then POLL_REMOVE is used to update the events of that request, if that update causes the POLL_ADD to now trigger, then that completion is lost and a CQE is never posted. Additionally, ensure that if an update does cause an existing POLL_ADD to complete, that the completion value isn't always overwritten with -ECANCELED. For that case, whatever io_poll_add() set the value to should just be retained. Cc: stable@vger.kernel.org Fixes: 97b388d70b53 ("io_uring: handle completions in the core") Reported-by: syzbot+641eec6b7af1f62f2b99@syzkaller.appspotmail.com Tested-by: syzbot+641eec6b7af1f62f2b99@syzkaller.appspotmail.com Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman --- io_uring/poll.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/io_uring/poll.c b/io_uring/poll.c index b9681d0f9f131..0d5bb90d47433 100644 --- a/io_uring/poll.c +++ b/io_uring/poll.c @@ -936,12 +936,17 @@ int io_poll_remove(struct io_kiocb *req, unsigned int issue_flags) ret2 = io_poll_add(preq, issue_flags & ~IO_URING_F_UNLOCKED); /* successfully updated, don't complete poll request */ - if (!ret2 || ret2 == -EIOCBQUEUED) + if (ret2 == IOU_ISSUE_SKIP_COMPLETE) goto out; + /* request completed as part of the update, complete it */ + else if (ret2 == IOU_COMPLETE) + goto complete; } - req_set_fail(preq); io_req_set_res(preq, -ECANCELED, 0); +complete: + if (preq->cqe.res < 0) + req_set_fail(preq); preq->io_task_work.func = io_req_task_complete; io_req_task_work_add(preq); out: From dcb0d8bf1771fd7b6b92fda8bc2da47a7dacff39 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Tue, 9 Dec 2025 13:25:23 -0700 Subject: [PATCH 1233/2333] io_uring: fix min_wait wakeups for SQPOLL commit e15cb2200b934e507273510ba6bc747d5cde24a3 upstream. Using min_wait, two timeouts are given: 1) The min_wait timeout, within which up to 'wait_nr' events are waited for. 2) The overall long timeout, which is entered if no events are generated in the min_wait window. If the min_wait has expired, any event being posted must wake the task. For SQPOLL, that isn't the case, as it won't trigger the io_has_work() condition, as it will have already processed the task_work that happened when an event was posted. This causes any event to trigger post the min_wait to not always cause the waiting application to wakeup, and instead it will wait until the overall timeout has expired. This can be shown in a test case that has a 1 second min_wait, with a 5 second overall wait, even if an event triggers after 1.5 seconds: axboe@m2max-kvm /d/iouring-mre (master)> zig-out/bin/iouring info: MIN_TIMEOUT supported: true, features: 0x3ffff info: Testing: min_wait=1000ms, timeout=5s, wait_nr=4 info: 1 cqes in 5000.2ms where the expected result should be: axboe@m2max-kvm /d/iouring-mre (master)> zig-out/bin/iouring info: MIN_TIMEOUT supported: true, features: 0x3ffff info: Testing: min_wait=1000ms, timeout=5s, wait_nr=4 info: 1 cqes in 1500.3ms When the min_wait timeout triggers, reset the number of completions needed to wake the task. This should ensure that any future events will wake the task, regardless of how many events it originally wanted to wait for. Reported-by: Tip ten Brink Cc: stable@vger.kernel.org Fixes: 1100c4a2656d ("io_uring: add support for batch wait timeout") Link: https://github.com/axboe/liburing/issues/1477 Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman --- io_uring/io_uring.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/io_uring/io_uring.c b/io_uring/io_uring.c index 765abec2571f0..60adab71ad2d2 100644 --- a/io_uring/io_uring.c +++ b/io_uring/io_uring.c @@ -2551,6 +2551,9 @@ static enum hrtimer_restart io_cqring_min_timer_wakeup(struct hrtimer *timer) goto out_wake; } + /* any generated CQE posted past this time should wake us up */ + iowq->cq_tail = iowq->cq_min_tail; + hrtimer_update_function(&iowq->t, io_cqring_timer_wakeup); hrtimer_set_expires(timer, iowq->timeout); return HRTIMER_RESTART; From 7fbfb85b05bc960cc50e09d03e5e562131e48d45 Mon Sep 17 00:00:00 2001 From: Prithvi Tambewagh Date: Thu, 25 Dec 2025 12:58:29 +0530 Subject: [PATCH 1234/2333] io_uring: fix filename leak in __io_openat_prep() commit b14fad555302a2104948feaff70503b64c80ac01 upstream. __io_openat_prep() allocates a struct filename using getname(). However, for the condition of the file being installed in the fixed file table as well as having O_CLOEXEC flag set, the function returns early. At that point, the request doesn't have REQ_F_NEED_CLEANUP flag set. Due to this, the memory for the newly allocated struct filename is not cleaned up, causing a memory leak. Fix this by setting the REQ_F_NEED_CLEANUP for the request just after the successful getname() call, so that when the request is torn down, the filename will be cleaned up, along with other resources needing cleanup. Reported-by: syzbot+00e61c43eb5e4740438f@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=00e61c43eb5e4740438f Tested-by: syzbot+00e61c43eb5e4740438f@syzkaller.appspotmail.com Cc: stable@vger.kernel.org Signed-off-by: Prithvi Tambewagh Fixes: b9445598d8c6 ("io_uring: openat directly into fixed fd table") Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman --- io_uring/openclose.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/io_uring/openclose.c b/io_uring/openclose.c index bfeb91b31bba5..15dde9bd6ff67 100644 --- a/io_uring/openclose.c +++ b/io_uring/openclose.c @@ -73,13 +73,13 @@ static int __io_openat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe open->filename = NULL; return ret; } + req->flags |= REQ_F_NEED_CLEANUP; open->file_slot = READ_ONCE(sqe->file_index); if (open->file_slot && (open->how.flags & O_CLOEXEC)) return -EINVAL; open->nofile = rlimit(RLIMIT_NOFILE); - req->flags |= REQ_F_NEED_CLEANUP; if (io_openat_force_async(open)) req->flags |= REQ_F_FORCE_ASYNC; return 0; From 3192204aa77fb6b3b95bb88795b9978fe467f811 Mon Sep 17 00:00:00 2001 From: John Ogness Date: Thu, 13 Nov 2025 17:09:48 +0106 Subject: [PATCH 1235/2333] printk: Avoid scheduling irq_work on suspend commit 26873e3e7f0cb26c45e6ad63656f9fe36b2aa31b upstream. Allowing irq_work to be scheduled while trying to suspend has shown to cause problems as some architectures interpret the pending interrupts as a reason to not suspend. This became a problem for printk() with the introduction of NBCON consoles. With every printk() call, NBCON console printing kthreads are woken by queueing irq_work. This means that irq_work continues to be queued due to printk() calls late in the suspend procedure. Avoid this problem by preventing printk() from queueing irq_work once console suspending has begun. This applies to triggering NBCON and legacy deferred printing as well as klogd waiters. Since triggering of NBCON threaded printing relies on irq_work, the pr_flush() within console_suspend_all() is used to perform the final flushing before suspending consoles and blocking irq_work queueing. NBCON consoles that are not suspended (due to the usage of the "no_console_suspend" boot argument) transition to atomic flushing. Introduce a new global variable @console_irqwork_blocked to flag when irq_work queueing is to be avoided. The flag is used by printk_get_console_flush_type() to avoid allowing deferred printing and switch NBCON consoles to atomic flushing. It is also used by vprintk_emit() to avoid klogd waking. Add WARN_ON_ONCE(console_irqwork_blocked) to the irq_work queuing functions to catch any code that attempts to queue printk irq_work during the suspending/resuming procedure. Cc: stable@vger.kernel.org # 6.13.x because no drivers in 6.12.x Fixes: 6b93bb41f6ea ("printk: Add non-BKL (nbcon) console basic infrastructure") Closes: https://lore.kernel.org/lkml/DB9PR04MB8429E7DDF2D93C2695DE401D92C4A@DB9PR04MB8429.eurprd04.prod.outlook.com Signed-off-by: John Ogness Reviewed-by: Petr Mladek Tested-by: Sherry Sun Link: https://patch.msgid.link/20251113160351.113031-3-john.ogness@linutronix.de Signed-off-by: Petr Mladek Signed-off-by: Greg Kroah-Hartman --- kernel/printk/internal.h | 8 +++--- kernel/printk/nbcon.c | 7 +++++ kernel/printk/printk.c | 58 +++++++++++++++++++++++++++++----------- 3 files changed, 55 insertions(+), 18 deletions(-) diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h index f72bbfa266d6c..b20929b7d71f5 100644 --- a/kernel/printk/internal.h +++ b/kernel/printk/internal.h @@ -230,6 +230,8 @@ struct console_flush_type { bool legacy_offload; }; +extern bool console_irqwork_blocked; + /* * Identify which console flushing methods should be used in the context of * the caller. @@ -241,7 +243,7 @@ static inline void printk_get_console_flush_type(struct console_flush_type *ft) switch (nbcon_get_default_prio()) { case NBCON_PRIO_NORMAL: if (have_nbcon_console && !have_boot_console) { - if (printk_kthreads_running) + if (printk_kthreads_running && !console_irqwork_blocked) ft->nbcon_offload = true; else ft->nbcon_atomic = true; @@ -251,7 +253,7 @@ static inline void printk_get_console_flush_type(struct console_flush_type *ft) if (have_legacy_console || have_boot_console) { if (!is_printk_legacy_deferred()) ft->legacy_direct = true; - else + else if (!console_irqwork_blocked) ft->legacy_offload = true; } break; @@ -264,7 +266,7 @@ static inline void printk_get_console_flush_type(struct console_flush_type *ft) if (have_legacy_console || have_boot_console) { if (!is_printk_legacy_deferred()) ft->legacy_direct = true; - else + else if (!console_irqwork_blocked) ft->legacy_offload = true; } break; diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c index 558ef31779760..da07c59f7aa2e 100644 --- a/kernel/printk/nbcon.c +++ b/kernel/printk/nbcon.c @@ -1276,6 +1276,13 @@ void nbcon_kthreads_wake(void) if (!printk_kthreads_running) return; + /* + * It is not allowed to call this function when console irq_work + * is blocked. + */ + if (WARN_ON_ONCE(console_irqwork_blocked)) + return; + cookie = console_srcu_read_lock(); for_each_console_srcu(con) { if (!(console_srcu_read_flags(con) & CON_NBCON)) diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index 5aee9ffb16b9a..e850c237b4ba9 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -462,6 +462,9 @@ bool have_boot_console; /* See printk_legacy_allow_panic_sync() for details. */ bool legacy_allow_panic_sync; +/* Avoid using irq_work when suspending. */ +bool console_irqwork_blocked; + #ifdef CONFIG_PRINTK DECLARE_WAIT_QUEUE_HEAD(log_wait); static DECLARE_WAIT_QUEUE_HEAD(legacy_wait); @@ -2426,7 +2429,7 @@ asmlinkage int vprintk_emit(int facility, int level, if (ft.legacy_offload) defer_console_output(); - else + else if (!console_irqwork_blocked) wake_up_klogd(); return printed_len; @@ -2730,10 +2733,20 @@ void console_suspend_all(void) { struct console *con; + if (console_suspend_enabled) + pr_info("Suspending console(s) (use no_console_suspend to debug)\n"); + + /* + * Flush any console backlog and then avoid queueing irq_work until + * console_resume_all(). Until then deferred printing is no longer + * triggered, NBCON consoles transition to atomic flushing, and + * any klogd waiters are not triggered. + */ + pr_flush(1000, true); + console_irqwork_blocked = true; + if (!console_suspend_enabled) return; - pr_info("Suspending console(s) (use no_console_suspend to debug)\n"); - pr_flush(1000, true); console_list_lock(); for_each_console(con) @@ -2754,26 +2767,34 @@ void console_resume_all(void) struct console_flush_type ft; struct console *con; - if (!console_suspend_enabled) - return; - - console_list_lock(); - for_each_console(con) - console_srcu_write_flags(con, con->flags & ~CON_SUSPENDED); - console_list_unlock(); - /* - * Ensure that all SRCU list walks have completed. All printing - * contexts must be able to see they are no longer suspended so - * that they are guaranteed to wake up and resume printing. + * Allow queueing irq_work. After restoring console state, deferred + * printing and any klogd waiters need to be triggered in case there + * is now a console backlog. */ - synchronize_srcu(&console_srcu); + console_irqwork_blocked = false; + + if (console_suspend_enabled) { + console_list_lock(); + for_each_console(con) + console_srcu_write_flags(con, con->flags & ~CON_SUSPENDED); + console_list_unlock(); + + /* + * Ensure that all SRCU list walks have completed. All printing + * contexts must be able to see they are no longer suspended so + * that they are guaranteed to wake up and resume printing. + */ + synchronize_srcu(&console_srcu); + } printk_get_console_flush_type(&ft); if (ft.nbcon_offload) nbcon_kthreads_wake(); if (ft.legacy_offload) defer_console_output(); + else + wake_up_klogd(); pr_flush(1000, true); } @@ -4511,6 +4532,13 @@ static void __wake_up_klogd(int val) if (!printk_percpu_data_ready()) return; + /* + * It is not allowed to call this function when console irq_work + * is blocked. + */ + if (WARN_ON_ONCE(console_irqwork_blocked)) + return; + preempt_disable(); /* * Guarantee any new records can be seen by tasks preparing to wait From 514d605ab6ce88f45f551ebaade2f5e52c1bb6ed Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 11 Dec 2025 15:45:03 -1000 Subject: [PATCH 1236/2333] sched_ext: Factor out local_dsq_post_enq() from dispatch_enqueue() commit 530b6637c79e728d58f1d9b66bd4acf4b735b86d upstream. Factor out local_dsq_post_enq() which performs post-enqueue handling for local DSQs - triggering resched_curr() if SCX_ENQ_PREEMPT is specified or if the current CPU is idle. No functional change. This will be used by the next patch to fix move_local_task_to_local_dsq(). Cc: stable@vger.kernel.org # v6.12+ Reviewed-by: Andrea Righi Reviewed-by: Emil Tsalapatis Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- kernel/sched/ext.c | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/kernel/sched/ext.c b/kernel/sched/ext.c index 979484dab2d3d..34d0d569548cc 100644 --- a/kernel/sched/ext.c +++ b/kernel/sched/ext.c @@ -906,6 +906,22 @@ static void refill_task_slice_dfl(struct scx_sched *sch, struct task_struct *p) __scx_add_event(sch, SCX_EV_REFILL_SLICE_DFL, 1); } +static void local_dsq_post_enq(struct scx_dispatch_q *dsq, struct task_struct *p, + u64 enq_flags) +{ + struct rq *rq = container_of(dsq, struct rq, scx.local_dsq); + bool preempt = false; + + if ((enq_flags & SCX_ENQ_PREEMPT) && p != rq->curr && + rq->curr->sched_class == &ext_sched_class) { + rq->curr->scx.slice = 0; + preempt = true; + } + + if (preempt || sched_class_above(&ext_sched_class, rq->curr->sched_class)) + resched_curr(rq); +} + static void dispatch_enqueue(struct scx_sched *sch, struct scx_dispatch_q *dsq, struct task_struct *p, u64 enq_flags) { @@ -1003,22 +1019,10 @@ static void dispatch_enqueue(struct scx_sched *sch, struct scx_dispatch_q *dsq, if (enq_flags & SCX_ENQ_CLEAR_OPSS) atomic_long_set_release(&p->scx.ops_state, SCX_OPSS_NONE); - if (is_local) { - struct rq *rq = container_of(dsq, struct rq, scx.local_dsq); - bool preempt = false; - - if ((enq_flags & SCX_ENQ_PREEMPT) && p != rq->curr && - rq->curr->sched_class == &ext_sched_class) { - rq->curr->scx.slice = 0; - preempt = true; - } - - if (preempt || sched_class_above(&ext_sched_class, - rq->curr->sched_class)) - resched_curr(rq); - } else { + if (is_local) + local_dsq_post_enq(dsq, p, enq_flags); + else raw_spin_unlock(&dsq->lock); - } } static void task_unlink_from_dsq(struct task_struct *p, From ff67270a177f4fea5a78f6d8ac799e0ee1b05b5e Mon Sep 17 00:00:00 2001 From: Zqiang Date: Mon, 8 Dec 2025 19:23:19 +0800 Subject: [PATCH 1237/2333] sched_ext: Fix the memleak for sch->helper objects commit 517a44d18537ef8ab888f71197c80116c14cee0a upstream. This commit use kthread_destroy_worker() to release sch->helper objects to fix the following kmemleak: unreferenced object 0xffff888121ec7b00 (size 128): comm "scx_simple", pid 1197, jiffies 4295884415 hex dump (first 32 bytes): 00 00 00 00 00 00 00 00 00 00 00 00 ad 4e ad de .............N.. ff ff ff ff 00 00 00 00 ff ff ff ff ff ff ff ff ................ backtrace (crc 587b3352): kmemleak_alloc+0x62/0xa0 __kmalloc_cache_noprof+0x28d/0x3e0 kthread_create_worker_on_node+0xd5/0x1f0 scx_enable.isra.210+0x6c2/0x25b0 bpf_scx_reg+0x12/0x20 bpf_struct_ops_link_create+0x2c3/0x3b0 __sys_bpf+0x3102/0x4b00 __x64_sys_bpf+0x79/0xc0 x64_sys_call+0x15d9/0x1dd0 do_syscall_64+0xf0/0x470 entry_SYSCALL_64_after_hwframe+0x77/0x7f Fixes: bff3b5aec1b7 ("sched_ext: Move disable machinery into scx_sched") Cc: stable@vger.kernel.org # v6.16+ Signed-off-by: Zqiang Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- kernel/sched/ext.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/sched/ext.c b/kernel/sched/ext.c index 34d0d569548cc..836a33e01cc86 100644 --- a/kernel/sched/ext.c +++ b/kernel/sched/ext.c @@ -3512,7 +3512,7 @@ static void scx_sched_free_rcu_work(struct work_struct *work) int node; irq_work_sync(&sch->error_irq_work); - kthread_stop(sch->helper->task); + kthread_destroy_worker(sch->helper); free_percpu(sch->pcpu); @@ -4504,7 +4504,7 @@ static struct scx_sched *scx_alloc_and_add_sched(struct sched_ext_ops *ops) return sch; err_stop_helper: - kthread_stop(sch->helper->task); + kthread_destroy_worker(sch->helper); err_free_pcpu: free_percpu(sch->pcpu); err_free_gdsqs: From 5ddd444484bea3e70521f6136cda9caf3d77adcc Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 9 Dec 2025 11:04:33 -1000 Subject: [PATCH 1238/2333] sched_ext: Fix bypass depth leak on scx_enable() failure commit 9f769637a93fac81689b80df6855f545839cf999 upstream. scx_enable() calls scx_bypass(true) to initialize in bypass mode and then scx_bypass(false) on success to exit. If scx_enable() fails during task initialization - e.g. scx_cgroup_init() or scx_init_task() returns an error - it jumps to err_disable while bypass is still active. scx_disable_workfn() then calls scx_bypass(true/false) for its own bypass, leaving the bypass depth at 1 instead of 0. This causes the system to remain permanently in bypass mode after a failed scx_enable(). Failures after task initialization is complete - e.g. scx_tryset_enable_state() at the end - already call scx_bypass(false) before reaching the error path and are not affected. This only affects a subset of failure modes. Fix it by tracking whether scx_enable() called scx_bypass(true) in a bool and having scx_disable_workfn() call an extra scx_bypass(false) to clear it. This is a temporary measure as the bypass depth will be moved into the sched instance, which will make this tracking unnecessary. Fixes: 8c2090c504e9 ("sched_ext: Initialize in bypass mode") Cc: stable@vger.kernel.org # v6.12+ Reported-by: Chris Mason Reviewed-by: Emil Tsalapatis Link: https://lore.kernel.org/stable/286e6f7787a81239e1ce2989b52391ce%40kernel.org Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- kernel/sched/ext.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/kernel/sched/ext.c b/kernel/sched/ext.c index 836a33e01cc86..29901d11b2604 100644 --- a/kernel/sched/ext.c +++ b/kernel/sched/ext.c @@ -40,6 +40,13 @@ static bool scx_init_task_enabled; static bool scx_switching_all; DEFINE_STATIC_KEY_FALSE(__scx_switched_all); +/* + * Tracks whether scx_enable() called scx_bypass(true). Used to balance bypass + * depth on enable failure. Will be removed when bypass depth is moved into the + * sched instance. + */ +static bool scx_bypassed_for_enable; + static atomic_long_t scx_nr_rejected = ATOMIC_LONG_INIT(0); static atomic_long_t scx_hotplug_seq = ATOMIC_LONG_INIT(0); @@ -4051,6 +4058,11 @@ static void scx_disable_workfn(struct kthread_work *work) scx_dsp_max_batch = 0; free_kick_pseqs(); + if (scx_bypassed_for_enable) { + scx_bypassed_for_enable = false; + scx_bypass(false); + } + mutex_unlock(&scx_enable_mutex); WARN_ON_ONCE(scx_set_enable_state(SCX_DISABLED) != SCX_DISABLING); @@ -4676,6 +4688,7 @@ static int scx_enable(struct sched_ext_ops *ops, struct bpf_link *link) * Init in bypass mode to guarantee forward progress. */ scx_bypass(true); + scx_bypassed_for_enable = true; for (i = SCX_OPI_NORMAL_BEGIN; i < SCX_OPI_NORMAL_END; i++) if (((void (**)(void))ops)[i]) @@ -4780,6 +4793,7 @@ static int scx_enable(struct sched_ext_ops *ops, struct bpf_link *link) scx_task_iter_stop(&sti); percpu_up_write(&scx_fork_rwsem); + scx_bypassed_for_enable = false; scx_bypass(false); if (!scx_tryset_enable_state(SCX_ENABLED, SCX_ENABLING)) { From 2ad1e2faebbdba686fcdf4d38a530763cf729244 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 11 Dec 2025 15:45:04 -1000 Subject: [PATCH 1239/2333] sched_ext: Fix missing post-enqueue handling in move_local_task_to_local_dsq() commit f5e1e5ec204da11fa87fdf006d451d80ce06e118 upstream. move_local_task_to_local_dsq() is used when moving a task from a non-local DSQ to a local DSQ on the same CPU. It directly manipulates the local DSQ without going through dispatch_enqueue() and was missing the post-enqueue handling that triggers preemption when SCX_ENQ_PREEMPT is set or the idle task is running. The function is used by move_task_between_dsqs() which backs scx_bpf_dsq_move() and may be called while the CPU is busy. Add local_dsq_post_enq() call to move_local_task_to_local_dsq(). As the dispatch path doesn't need post-enqueue handling, add SCX_RQ_IN_BALANCE early exit to keep consume_dispatch_q() behavior unchanged and avoid triggering unnecessary resched when scx_bpf_dsq_move() is used from the dispatch path. Fixes: 4c30f5ce4f7a ("sched_ext: Implement scx_bpf_dispatch[_vtime]_from_dsq()") Cc: stable@vger.kernel.org # v6.12+ Reviewed-by: Andrea Righi Reviewed-by: Emil Tsalapatis Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- kernel/sched/ext.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/kernel/sched/ext.c b/kernel/sched/ext.c index 29901d11b2604..b959a70471c10 100644 --- a/kernel/sched/ext.c +++ b/kernel/sched/ext.c @@ -919,6 +919,14 @@ static void local_dsq_post_enq(struct scx_dispatch_q *dsq, struct task_struct *p struct rq *rq = container_of(dsq, struct rq, scx.local_dsq); bool preempt = false; + /* + * If @rq is in balance, the CPU is already vacant and looking for the + * next task to run. No need to preempt or trigger resched after moving + * @p into its local DSQ. + */ + if (rq->scx.flags & SCX_RQ_IN_BALANCE) + return; + if ((enq_flags & SCX_ENQ_PREEMPT) && p != rq->curr && rq->curr->sched_class == &ext_sched_class) { rq->curr->scx.slice = 0; @@ -1524,6 +1532,8 @@ static void move_local_task_to_local_dsq(struct task_struct *p, u64 enq_flags, dsq_mod_nr(dst_dsq, 1); p->scx.dsq = dst_dsq; + + local_dsq_post_enq(dst_dsq, p, enq_flags); } /** From 4bb9164e8f21ecb3372dfa051450bdcc1490dbaa Mon Sep 17 00:00:00 2001 From: Avadhut Naik Date: Fri, 21 Nov 2025 19:04:04 +0000 Subject: [PATCH 1240/2333] x86/mce: Do not clear bank's poll bit in mce_poll_banks on AMD SMCA systems commit d7ac083f095d894a0b8ac0573516bfd035e6b25a upstream. Currently, when a CMCI storm detected on a Machine Check bank, subsides, the bank's corresponding bit in the mce_poll_banks per-CPU variable is cleared unconditionally by cmci_storm_end(). On AMD SMCA systems, this essentially disables polling on that particular bank on that CPU. Consequently, any subsequent correctable errors or storms will not be logged. Since AMD SMCA systems allow banks to be managed by both polling and interrupts, the polling banks bitmap for a CPU, i.e., mce_poll_banks, should not be modified when a storm subsides. Fixes: 7eae17c4add5 ("x86/mce: Add per-bank CMCI storm mitigation") Signed-off-by: Avadhut Naik Signed-off-by: Borislav Petkov (AMD) Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20251121190542.2447913-2-avadhut.naik@amd.com Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/cpu/mce/threshold.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/x86/kernel/cpu/mce/threshold.c b/arch/x86/kernel/cpu/mce/threshold.c index f4a007616468e..61eaa17749311 100644 --- a/arch/x86/kernel/cpu/mce/threshold.c +++ b/arch/x86/kernel/cpu/mce/threshold.c @@ -85,7 +85,8 @@ void cmci_storm_end(unsigned int bank) { struct mca_storm_desc *storm = this_cpu_ptr(&storm_desc); - __clear_bit(bank, this_cpu_ptr(mce_poll_banks)); + if (!mce_flags.amd_threshold) + __clear_bit(bank, this_cpu_ptr(mce_poll_banks)); storm->banks[bank].history = 0; storm->banks[bank].in_storm_mode = false; From 9285d04830639e4bfe05a94fef50296014f9bffe Mon Sep 17 00:00:00 2001 From: Sarthak Garg Date: Fri, 14 Nov 2025 13:58:24 +0530 Subject: [PATCH 1241/2333] mmc: sdhci-msm: Avoid early clock doubling during HS400 transition commit b1f856b1727c2eaa4be2c6d7cd7a8ed052bbeb87 upstream. According to the hardware programming guide, the clock frequency must remain below 52MHz during the transition to HS400 mode. However,in the current implementation, the timing is set to HS400 (a DDR mode) before adjusting the clock. This causes the clock to double prematurely to 104MHz during the transition phase, violating the specification and potentially resulting in CRC errors or CMD timeouts. This change ensures that clock doubling is avoided during intermediate transitions and is applied only when the card requires a 200MHz clock for HS400 operation. Signed-off-by: Sarthak Garg Reviewed-by: Bjorn Andersson Acked-by: Adrian Hunter Cc: stable@vger.kernel.org Signed-off-by: Ulf Hansson Signed-off-by: Greg Kroah-Hartman --- drivers/mmc/host/sdhci-msm.c | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index 4e5edbf2fc9b6..3b85233131b38 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -344,41 +344,43 @@ static void sdhci_msm_v5_variant_writel_relaxed(u32 val, writel_relaxed(val, host->ioaddr + offset); } -static unsigned int msm_get_clock_mult_for_bus_mode(struct sdhci_host *host) +static unsigned int msm_get_clock_mult_for_bus_mode(struct sdhci_host *host, + unsigned int clock, + unsigned int timing) { - struct mmc_ios ios = host->mmc->ios; /* * The SDHC requires internal clock frequency to be double the * actual clock that will be set for DDR mode. The controller * uses the faster clock(100/400MHz) for some of its parts and * send the actual required clock (50/200MHz) to the card. */ - if (ios.timing == MMC_TIMING_UHS_DDR50 || - ios.timing == MMC_TIMING_MMC_DDR52 || - ios.timing == MMC_TIMING_MMC_HS400 || + if (timing == MMC_TIMING_UHS_DDR50 || + timing == MMC_TIMING_MMC_DDR52 || + (timing == MMC_TIMING_MMC_HS400 && + clock == MMC_HS200_MAX_DTR) || host->flags & SDHCI_HS400_TUNING) return 2; return 1; } static void msm_set_clock_rate_for_bus_mode(struct sdhci_host *host, - unsigned int clock) + unsigned int clock, + unsigned int timing) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); - struct mmc_ios curr_ios = host->mmc->ios; struct clk *core_clk = msm_host->bulk_clks[0].clk; unsigned long achieved_rate; unsigned int desired_rate; unsigned int mult; int rc; - mult = msm_get_clock_mult_for_bus_mode(host); + mult = msm_get_clock_mult_for_bus_mode(host, clock, timing); desired_rate = clock * mult; rc = dev_pm_opp_set_rate(mmc_dev(host->mmc), desired_rate); if (rc) { pr_err("%s: Failed to set clock at rate %u at timing %d\n", - mmc_hostname(host->mmc), desired_rate, curr_ios.timing); + mmc_hostname(host->mmc), desired_rate, timing); return; } @@ -397,7 +399,7 @@ static void msm_set_clock_rate_for_bus_mode(struct sdhci_host *host, msm_host->clk_rate = desired_rate; pr_debug("%s: Setting clock at rate %lu at timing %d\n", - mmc_hostname(host->mmc), achieved_rate, curr_ios.timing); + mmc_hostname(host->mmc), achieved_rate, timing); } /* Platform specific tuning */ @@ -1239,7 +1241,7 @@ static int sdhci_msm_execute_tuning(struct mmc_host *mmc, u32 opcode) */ if (host->flags & SDHCI_HS400_TUNING) { sdhci_msm_hc_select_mode(host); - msm_set_clock_rate_for_bus_mode(host, ios.clock); + msm_set_clock_rate_for_bus_mode(host, ios.clock, ios.timing); host->flags &= ~SDHCI_HS400_TUNING; } @@ -1864,6 +1866,7 @@ static void sdhci_msm_set_clock(struct sdhci_host *host, unsigned int clock) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); + struct mmc_ios ios = host->mmc->ios; if (!clock) { host->mmc->actual_clock = msm_host->clk_rate = 0; @@ -1872,7 +1875,7 @@ static void sdhci_msm_set_clock(struct sdhci_host *host, unsigned int clock) sdhci_msm_hc_select_mode(host); - msm_set_clock_rate_for_bus_mode(host, clock); + msm_set_clock_rate_for_bus_mode(host, ios.clock, ios.timing); out: __sdhci_msm_set_clock(host, clock); } From 344057b2605d53b325ce029d0c07ad5892ce6974 Mon Sep 17 00:00:00 2001 From: Alexey Minnekhanov Date: Sun, 16 Nov 2025 04:12:33 +0300 Subject: [PATCH 1242/2333] dt-bindings: clock: mmcc-sdm660: Add missing MDSS reset commit c57210bc15371caa06a5d4040e7d8aaeed4cb661 upstream. Add definition for display subsystem reset control, so display driver can reset display controller properly, clearing any configuration left there by bootloader. Since 6.17 after PM domains rework it became necessary for display to function. Fixes: 0e789b491ba0 ("pmdomain: core: Leave powered-on genpds on until sync_state") Cc: stable@vger.kernel.org # 6.17 Signed-off-by: Alexey Minnekhanov Acked-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20251116-sdm660-mdss-reset-v2-1-6219bec0a97f@postmarketos.org Signed-off-by: Bjorn Andersson Signed-off-by: Greg Kroah-Hartman --- include/dt-bindings/clock/qcom,mmcc-sdm660.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/dt-bindings/clock/qcom,mmcc-sdm660.h b/include/dt-bindings/clock/qcom,mmcc-sdm660.h index f9dbc21cb5c7c..ee2a89dae72dc 100644 --- a/include/dt-bindings/clock/qcom,mmcc-sdm660.h +++ b/include/dt-bindings/clock/qcom,mmcc-sdm660.h @@ -157,6 +157,7 @@ #define BIMC_SMMU_GDSC 7 #define CAMSS_MICRO_BCR 0 +#define MDSS_BCR 1 #endif From 265fad7d9c42cb7b29c2de06a645dce33e7b9f42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Draszik?= Date: Mon, 6 Oct 2025 09:07:12 +0100 Subject: [PATCH 1243/2333] phy: exynos5-usbdrd: fix clock prepare imbalance MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 5e428e45bf17a8f3784099ca5ded16e3b5d59766 upstream. Commit f4fb9c4d7f94 ("phy: exynos5-usbdrd: allow DWC3 runtime suspend with UDC bound (E850+)") incorrectly added clk_bulk_disable() as the inverse of clk_bulk_prepare_enable() while it should have of course used clk_bulk_disable_unprepare(). This means incorrect reference counts to the CMU driver remain. Update the code accordingly. Fixes: f4fb9c4d7f94 ("phy: exynos5-usbdrd: allow DWC3 runtime suspend with UDC bound (E850+)") CC: stable@vger.kernel.org Signed-off-by: André Draszik Reviewed-by: Sam Protsenko Reviewed-by: Peter Griffin Link: https://patch.msgid.link/20251006-gs101-usb-phy-clk-imbalance-v1-1-205b206126cf@linaro.org Signed-off-by: Vinod Koul Signed-off-by: Greg Kroah-Hartman --- drivers/phy/samsung/phy-exynos5-usbdrd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/phy/samsung/phy-exynos5-usbdrd.c b/drivers/phy/samsung/phy-exynos5-usbdrd.c index a88ba95bdc8f5..1c8bf80119f11 100644 --- a/drivers/phy/samsung/phy-exynos5-usbdrd.c +++ b/drivers/phy/samsung/phy-exynos5-usbdrd.c @@ -1823,7 +1823,7 @@ static int exynos5_usbdrd_orien_sw_set(struct typec_switch_dev *sw, phy_drd->orientation = orientation; } - clk_bulk_disable(phy_drd->drv_data->n_clks, phy_drd->clks); + clk_bulk_disable_unprepare(phy_drd->drv_data->n_clks, phy_drd->clks); return 0; } From bacecf370e0cca03bd45a4f4bfc500be3a37bd35 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Wed, 15 Oct 2025 22:56:36 +0200 Subject: [PATCH 1244/2333] efi: Add missing static initializer for efi_mm::cpus_allowed_lock commit 40374d308e4e456048d83991e937f13fc8bda8bf upstream. Initialize the cpus_allowed_lock struct member of efi_mm. Cc: stable@vger.kernel.org Signed-off-by: Ard Biesheuvel Acked-by: Catalin Marinas Signed-off-by: Catalin Marinas Signed-off-by: Greg Kroah-Hartman --- drivers/firmware/efi/efi.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index 1ce428e2ac8a0..fc407d891348f 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c @@ -74,6 +74,9 @@ struct mm_struct efi_mm = { .page_table_lock = __SPIN_LOCK_UNLOCKED(efi_mm.page_table_lock), .mmlist = LIST_HEAD_INIT(efi_mm.mmlist), .cpu_bitmap = { [BITS_TO_LONGS(NR_CPUS)] = 0}, +#ifdef CONFIG_SCHED_MM_CID + .cpus_allowed_lock = __RAW_SPIN_LOCK_UNLOCKED(efi_mm.cpus_allowed_lock), +#endif }; struct workqueue_struct *efi_rts_wq; From 0eeaa2ba3b43cc7b0608b6e467ed9ff0ae527847 Mon Sep 17 00:00:00 2001 From: Ma Ke Date: Wed, 22 Oct 2025 19:53:25 +0800 Subject: [PATCH 1245/2333] perf: arm_cspmu: fix error handling in arm_cspmu_impl_unregister() commit 970e1e41805f0bd49dc234330a9390f4708d097d upstream. driver_find_device() calls get_device() to increment the reference count once a matching device is found. device_release_driver() releases the driver, but it does not decrease the reference count that was incremented by driver_find_device(). At the end of the loop, there is no put_device() to balance the reference count. To avoid reference count leakage, add put_device() to decrease the reference count. Found by code review. Cc: stable@vger.kernel.org Fixes: bfc653aa89cb ("perf: arm_cspmu: Separate Arm and vendor module") Signed-off-by: Ma Ke Signed-off-by: Will Deacon Signed-off-by: Greg Kroah-Hartman --- drivers/perf/arm_cspmu/arm_cspmu.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/perf/arm_cspmu/arm_cspmu.c b/drivers/perf/arm_cspmu/arm_cspmu.c index efa9b229e7012..e0d4293f06f93 100644 --- a/drivers/perf/arm_cspmu/arm_cspmu.c +++ b/drivers/perf/arm_cspmu/arm_cspmu.c @@ -1365,8 +1365,10 @@ void arm_cspmu_impl_unregister(const struct arm_cspmu_impl_match *impl_match) /* Unbind the driver from all matching backend devices. */ while ((dev = driver_find_device(&arm_cspmu_driver.driver, NULL, - match, arm_cspmu_match_device))) + match, arm_cspmu_match_device))) { device_release_driver(dev); + put_device(dev); + } mutex_lock(&arm_cspmu_lock); From 3b95fdb75d74c9bc4aee5868f7b3499af00c1632 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sun, 2 Nov 2025 15:42:04 -0800 Subject: [PATCH 1246/2333] lib/crypto: x86/blake2s: Fix 32-bit arg treated as 64-bit commit 2f22115709fc7ebcfa40af3367a508fbbd2f71e9 upstream. In the C code, the 'inc' argument to the assembly functions blake2s_compress_ssse3() and blake2s_compress_avx512() is declared with type u32, matching blake2s_compress(). The assembly code then reads it from the 64-bit %rcx. However, the ABI doesn't guarantee zero-extension to 64 bits, nor do gcc or clang guarantee it. Therefore, fix these functions to read this argument from the 32-bit %ecx. In theory, this bug could have caused the wrong 'inc' value to be used, causing incorrect BLAKE2s hashes. In practice, probably not: I've fixed essentially this same bug in many other assembly files too, but there's never been a real report of it having caused a problem. In x86_64, all writes to 32-bit registers are zero-extended to 64 bits. That results in zero-extension in nearly all situations. I've only been able to demonstrate a lack of zero-extension with a somewhat contrived example involving truncation, e.g. when the C code has a u64 variable holding 0x1234567800000040 and passes it as a u32 expecting it to be truncated to 0x40 (64). But that's not what the real code does, of course. Fixes: ed0356eda153 ("crypto: blake2s - x86_64 SIMD implementation") Cc: stable@vger.kernel.org Reviewed-by: Ard Biesheuvel Link: https://lore.kernel.org/r/20251102234209.62133-2-ebiggers@kernel.org Signed-off-by: Eric Biggers Signed-off-by: Greg Kroah-Hartman --- lib/crypto/x86/blake2s-core.S | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/crypto/x86/blake2s-core.S b/lib/crypto/x86/blake2s-core.S index ef8e9f427aab3..093e7814f3879 100644 --- a/lib/crypto/x86/blake2s-core.S +++ b/lib/crypto/x86/blake2s-core.S @@ -52,7 +52,7 @@ SYM_FUNC_START(blake2s_compress_ssse3) movdqa ROT16(%rip),%xmm12 movdqa ROR328(%rip),%xmm13 movdqu 0x20(%rdi),%xmm14 - movq %rcx,%xmm15 + movd %ecx,%xmm15 leaq SIGMA+0xa0(%rip),%r8 jmp .Lbeginofloop .align 32 @@ -176,7 +176,7 @@ SYM_FUNC_START(blake2s_compress_avx512) vmovdqu (%rdi),%xmm0 vmovdqu 0x10(%rdi),%xmm1 vmovdqu 0x20(%rdi),%xmm4 - vmovq %rcx,%xmm5 + vmovd %ecx,%xmm5 vmovdqa IV(%rip),%xmm14 vmovdqa IV+16(%rip),%xmm15 jmp .Lblake2s_compress_avx512_mainloop From aceaa18f791add733b969f8b70fe614a3e43f183 Mon Sep 17 00:00:00 2001 From: Stefan Haberland Date: Wed, 26 Nov 2025 17:06:31 +0100 Subject: [PATCH 1247/2333] s390/dasd: Fix gendisk parent after copy pair swap commit c943bfc6afb8d0e781b9b7406f36caa8bbf95cb9 upstream. After a copy pair swap the block device's "device" symlink points to the secondary CCW device, but the gendisk's parent remained the primary, leaving /sys/block/ under the wrong parent. Move the gendisk to the secondary's device with device_move(), keeping the sysfs topology consistent after the swap. Fixes: 413862caad6f ("s390/dasd: add copy pair swap capability") Cc: stable@vger.kernel.org #6.1 Reviewed-by: Jan Hoeppner Signed-off-by: Stefan Haberland Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman --- drivers/s390/block/dasd_eckd.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 88fa17aea2ec8..ec0c62e5ef73b 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -6150,6 +6150,7 @@ static int dasd_eckd_copy_pair_swap(struct dasd_device *device, char *prim_busid struct dasd_copy_relation *copy; struct dasd_block *block; struct gendisk *gdp; + int rc; copy = device->copy; if (!copy) @@ -6184,6 +6185,13 @@ static int dasd_eckd_copy_pair_swap(struct dasd_device *device, char *prim_busid /* swap blocklayer device link */ gdp = block->gdp; dasd_add_link_to_gendisk(gdp, secondary); + rc = device_move(disk_to_dev(gdp), &secondary->cdev->dev, DPM_ORDER_NONE); + if (rc) { + dev_err(&primary->cdev->dev, + "copy_pair_swap: moving blockdevice parent %s->%s failed (%d)\n", + dev_name(&primary->cdev->dev), + dev_name(&secondary->cdev->dev), rc); + } /* re-enable device */ dasd_device_remove_stop_bits(primary, DASD_STOPPED_PPRC); From 498e286941b961903be570d52d44e57f150d55ea Mon Sep 17 00:00:00 2001 From: "Sven Eckelmann (Plasma Cloud)" Date: Fri, 26 Sep 2025 11:32:54 +0200 Subject: [PATCH 1248/2333] wifi: mt76: Fix DTS power-limits on little endian systems commit 38b845e1f9e810869b0a0b69f202b877b7b7fb12 upstream. The power-limits for ru and mcs and stored in the devicetree as bytewise array (often with sizes which are not a multiple of 4). These arrays have a prefix which defines for how many modes a line is applied. This prefix is also only a byte - but the code still tried to fix the endianness of this byte with a be32 operation. As result, loading was mostly failing or was sending completely unexpected values to the firmware. Since the other rates are also stored in the devicetree as bytewise arrays, just drop the u32 access + be32_to_cpu conversion and directly access them as bytes arrays. Cc: stable@vger.kernel.org Fixes: 22b980badc0f ("mt76: add functions for parsing rate power limits from DT") Fixes: a9627d992b5e ("mt76: extend DT rate power limits to support 11ax devices") Signed-off-by: Sven Eckelmann (Plasma Cloud) Signed-off-by: Felix Fietkau Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/mediatek/mt76/eeprom.c | 37 +++++++++++++-------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/eeprom.c b/drivers/net/wireless/mediatek/mt76/eeprom.c index a987c5e4eff6c..6ce8e4af18fe5 100644 --- a/drivers/net/wireless/mediatek/mt76/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/eeprom.c @@ -253,6 +253,19 @@ mt76_get_of_array(struct device_node *np, char *name, size_t *len, int min) return prop->value; } +static const s8 * +mt76_get_of_array_s8(struct device_node *np, char *name, size_t *len, int min) +{ + struct property *prop = of_find_property(np, name, NULL); + + if (!prop || !prop->value || prop->length < min) + return NULL; + + *len = prop->length; + + return prop->value; +} + struct device_node * mt76_find_channel_node(struct device_node *np, struct ieee80211_channel *chan) { @@ -294,7 +307,7 @@ mt76_get_txs_delta(struct device_node *np, u8 nss) } static void -mt76_apply_array_limit(s8 *pwr, size_t pwr_len, const __be32 *data, +mt76_apply_array_limit(s8 *pwr, size_t pwr_len, const s8 *data, s8 target_power, s8 nss_delta, s8 *max_power) { int i; @@ -303,15 +316,14 @@ mt76_apply_array_limit(s8 *pwr, size_t pwr_len, const __be32 *data, return; for (i = 0; i < pwr_len; i++) { - pwr[i] = min_t(s8, target_power, - be32_to_cpu(data[i]) + nss_delta); + pwr[i] = min_t(s8, target_power, data[i] + nss_delta); *max_power = max(*max_power, pwr[i]); } } static void mt76_apply_multi_array_limit(s8 *pwr, size_t pwr_len, s8 pwr_num, - const __be32 *data, size_t len, s8 target_power, + const s8 *data, size_t len, s8 target_power, s8 nss_delta, s8 *max_power) { int i, cur; @@ -319,8 +331,7 @@ mt76_apply_multi_array_limit(s8 *pwr, size_t pwr_len, s8 pwr_num, if (!data) return; - len /= 4; - cur = be32_to_cpu(data[0]); + cur = data[0]; for (i = 0; i < pwr_num; i++) { if (len < pwr_len + 1) break; @@ -335,7 +346,7 @@ mt76_apply_multi_array_limit(s8 *pwr, size_t pwr_len, s8 pwr_num, if (!len) break; - cur = be32_to_cpu(data[0]); + cur = data[0]; } } @@ -346,7 +357,7 @@ s8 mt76_get_rate_power_limits(struct mt76_phy *phy, { struct mt76_dev *dev = phy->dev; struct device_node *np; - const __be32 *val; + const s8 *val; char name[16]; u32 mcs_rates = dev->drv->mcs_rates; u32 ru_rates = ARRAY_SIZE(dest->ru[0]); @@ -392,21 +403,21 @@ s8 mt76_get_rate_power_limits(struct mt76_phy *phy, txs_delta = mt76_get_txs_delta(np, hweight16(phy->chainmask)); - val = mt76_get_of_array(np, "rates-cck", &len, ARRAY_SIZE(dest->cck)); + val = mt76_get_of_array_s8(np, "rates-cck", &len, ARRAY_SIZE(dest->cck)); mt76_apply_array_limit(dest->cck, ARRAY_SIZE(dest->cck), val, target_power, txs_delta, &max_power); - val = mt76_get_of_array(np, "rates-ofdm", - &len, ARRAY_SIZE(dest->ofdm)); + val = mt76_get_of_array_s8(np, "rates-ofdm", + &len, ARRAY_SIZE(dest->ofdm)); mt76_apply_array_limit(dest->ofdm, ARRAY_SIZE(dest->ofdm), val, target_power, txs_delta, &max_power); - val = mt76_get_of_array(np, "rates-mcs", &len, mcs_rates + 1); + val = mt76_get_of_array_s8(np, "rates-mcs", &len, mcs_rates + 1); mt76_apply_multi_array_limit(dest->mcs[0], ARRAY_SIZE(dest->mcs[0]), ARRAY_SIZE(dest->mcs), val, len, target_power, txs_delta, &max_power); - val = mt76_get_of_array(np, "rates-ru", &len, ru_rates + 1); + val = mt76_get_of_array_s8(np, "rates-ru", &len, ru_rates + 1); mt76_apply_multi_array_limit(dest->ru[0], ARRAY_SIZE(dest->ru[0]), ARRAY_SIZE(dest->ru), val, len, target_power, txs_delta, &max_power); From 98d65b62ddf84db83aafe4a9ef914428c835cd07 Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Tue, 18 Nov 2025 17:08:41 +0100 Subject: [PATCH 1249/2333] btrfs: don't rewrite ret from inode_permission commit 0185c2292c600993199bc6b1f342ad47a9e8c678 upstream. In our user safe ino resolve ioctl we'll just turn any ret into -EACCES from inode_permission(). This is redundant, and could potentially be wrong if we had an ENOMEM in the security layer or some such other error, so simply return the actual return value. Note: The patch was taken from v5 of fscrypt patchset (https://lore.kernel.org/linux-btrfs/cover.1706116485.git.josef@toxicpanda.com/) which was handled over time by various people: Omar Sandoval, Sweet Tea Dorminy, Josef Bacik. Fixes: 23d0b79dfaed ("btrfs: Add unprivileged version of ino_lookup ioctl") CC: stable@vger.kernel.org # 5.4+ Reviewed-by: Johannes Thumshirn Signed-off-by: Josef Bacik Signed-off-by: Daniel Vacek Reviewed-by: David Sterba [ add note ] Signed-off-by: David Sterba Signed-off-by: Greg Kroah-Hartman --- fs/btrfs/ioctl.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 8cb7d5a462ef7..9a34d6530658e 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -1913,10 +1913,8 @@ static int btrfs_search_path_in_tree_user(struct mnt_idmap *idmap, ret = inode_permission(idmap, &temp_inode->vfs_inode, MAY_READ | MAY_EXEC); iput(&temp_inode->vfs_inode); - if (ret) { - ret = -EACCES; + if (ret) goto out_put; - } if (key.offset == upper_limit) break; From 3715bb43ccd3ce2a04fa50e8007c1c81e29360ed Mon Sep 17 00:00:00 2001 From: Alexey Velichayshiy Date: Mon, 17 Nov 2025 12:05:18 +0300 Subject: [PATCH 1250/2333] gfs2: fix freeze error handling commit 4cfc7d5a4a01d2133b278cdbb1371fba1b419174 upstream. After commit b77b4a4815a9 ("gfs2: Rework freeze / thaw logic"), the freeze error handling is broken because gfs2_do_thaw() overwrites the 'error' variable, causing incorrect processing of the original freeze error. Fix this by calling gfs2_do_thaw() when gfs2_lock_fs_check_clean() fails but ignoring its return value to preserve the original freeze error for proper reporting. Found by Linux Verification Center (linuxtesting.org) with SVACE. Fixes: b77b4a4815a9 ("gfs2: Rework freeze / thaw logic") Cc: stable@vger.kernel.org # v6.5+ Signed-off-by: Alexey Velichayshiy Signed-off-by: Andreas Gruenbacher Signed-off-by: Greg Kroah-Hartman --- fs/gfs2/super.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index 644b2d1e72769..54c6f2098f01e 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c @@ -749,9 +749,7 @@ static int gfs2_freeze_super(struct super_block *sb, enum freeze_holder who, break; } - error = gfs2_do_thaw(sdp, who, freeze_owner); - if (error) - goto out; + (void)gfs2_do_thaw(sdp, who, freeze_owner); if (error == -EBUSY) fs_err(sdp, "waiting for recovery before freeze\n"); From 8dd553771afe454ca2c4a3ad66d7d51b50f436df Mon Sep 17 00:00:00 2001 From: Li Chen Date: Mon, 17 Nov 2025 13:34:07 +0800 Subject: [PATCH 1251/2333] block: rate-limit capacity change info log commit 3179a5f7f86bcc3acd5d6fb2a29f891ef5615852 upstream. loop devices under heavy stress-ng loop streessor can trigger many capacity change events in a short time. Each event prints an info message from set_capacity_and_notify(), flooding the console and contributing to soft lockups on slow consoles. Switch the printk in set_capacity_and_notify() to pr_info_ratelimited() so frequent capacity changes do not spam the log while still reporting occasional changes. Cc: stable@vger.kernel.org Signed-off-by: Li Chen Reviewed-by: Chaitanya Kulkarni Reviewed-by: Bart Van Assche Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman --- block/genhd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/block/genhd.c b/block/genhd.c index 9bbc38d127926..bd3a6841e5b59 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -90,7 +90,7 @@ bool set_capacity_and_notify(struct gendisk *disk, sector_t size) (disk->flags & GENHD_FL_HIDDEN)) return false; - pr_info("%s: detected capacity change from %lld to %lld\n", + pr_info_ratelimited("%s: detected capacity change from %lld to %lld\n", disk->disk_name, capacity, size); /* From cbaae7bb64d40e49928e3428faa7a5c3d0217ee7 Mon Sep 17 00:00:00 2001 From: Ye Bin Date: Mon, 3 Nov 2025 09:01:23 +0800 Subject: [PATCH 1252/2333] jbd2: fix the inconsistency between checksum and data in memory for journal sb commit 6abfe107894af7e8ce3a2e120c619d81ee764ad5 upstream. Copying the file system while it is mounted as read-only results in a mount failure: [~]# mkfs.ext4 -F /dev/sdc [~]# mount /dev/sdc -o ro /mnt/test [~]# dd if=/dev/sdc of=/dev/sda bs=1M [~]# mount /dev/sda /mnt/test1 [ 1094.849826] JBD2: journal checksum error [ 1094.850927] EXT4-fs (sda): Could not load journal inode mount: mount /dev/sda on /mnt/test1 failed: Bad message The process described above is just an abstracted way I came up with to reproduce the issue. In the actual scenario, the file system was mounted read-only and then copied while it was still mounted. It was found that the mount operation failed. The user intended to verify the data or use it as a backup, and this action was performed during a version upgrade. Above issue may happen as follows: ext4_fill_super set_journal_csum_feature_set(sb) if (ext4_has_metadata_csum(sb)) incompat = JBD2_FEATURE_INCOMPAT_CSUM_V3; if (test_opt(sb, JOURNAL_CHECKSUM) jbd2_journal_set_features(sbi->s_journal, compat, 0, incompat); lock_buffer(journal->j_sb_buffer); sb->s_feature_incompat |= cpu_to_be32(incompat); //The data in the journal sb was modified, but the checksum was not updated, so the data remaining in memory has a mismatch between the data and the checksum. unlock_buffer(journal->j_sb_buffer); In this case, the journal sb copied over is in a state where the checksum and data are inconsistent, so mounting fails. To solve the above issue, update the checksum in memory after modifying the journal sb. Fixes: 4fd5ea43bc11 ("jbd2: checksum journal superblock") Signed-off-by: Ye Bin Reviewed-by: Baokun Li Reviewed-by: Darrick J. Wong Reviewed-by: Jan Kara Message-ID: <20251103010123.3753631-1-yebin@huaweicloud.com> Signed-off-by: Theodore Ts'o Cc: stable@kernel.org Signed-off-by: Greg Kroah-Hartman --- fs/jbd2/journal.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c index d480b94117cd7..bf255f8b5eebf 100644 --- a/fs/jbd2/journal.c +++ b/fs/jbd2/journal.c @@ -2349,6 +2349,12 @@ int jbd2_journal_set_features(journal_t *journal, unsigned long compat, sb->s_feature_compat |= cpu_to_be32(compat); sb->s_feature_ro_compat |= cpu_to_be32(ro); sb->s_feature_incompat |= cpu_to_be32(incompat); + /* + * Update the checksum now so that it is valid even for read-only + * filesystems where jbd2_write_superblock() doesn't get called. + */ + if (jbd2_journal_has_csum_v2or3(journal)) + sb->s_checksum = jbd2_superblock_csum(sb); unlock_buffer(journal->j_sb_buffer); jbd2_journal_init_transaction_limits(journal); @@ -2378,9 +2384,17 @@ void jbd2_journal_clear_features(journal_t *journal, unsigned long compat, sb = journal->j_superblock; + lock_buffer(journal->j_sb_buffer); sb->s_feature_compat &= ~cpu_to_be32(compat); sb->s_feature_ro_compat &= ~cpu_to_be32(ro); sb->s_feature_incompat &= ~cpu_to_be32(incompat); + /* + * Update the checksum now so that it is valid even for read-only + * filesystems where jbd2_write_superblock() doesn't get called. + */ + if (jbd2_journal_has_csum_v2or3(journal)) + sb->s_checksum = jbd2_superblock_csum(sb); + unlock_buffer(journal->j_sb_buffer); jbd2_journal_init_transaction_limits(journal); } EXPORT_SYMBOL(jbd2_journal_clear_features); From 3312f03e9948ce538800cd5ca5d4bf3370e9da8f Mon Sep 17 00:00:00 2001 From: Rene Rebe Date: Fri, 14 Nov 2025 14:41:27 +0100 Subject: [PATCH 1253/2333] floppy: fix for PAGE_SIZE != 4KB MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 82d20481024cbae2ea87fe8b86d12961bfda7169 upstream. For years I wondered why the floppy driver does not just work on sparc64, e.g: root@SUNW_375_0066:# disktype /dev/fd0 disktype: Can't open /dev/fd0: No such device or address [ 525.341906] disktype: attempt to access beyond end of device fd0: rw=0, sector=0, nr_sectors = 16 limit=8 [ 525.341991] floppy: error 10 while reading block 0 Turns out floppy.c __floppy_read_block_0 tries to read one page for the first test read to determine the disk size and thus fails if that is greater than 4k. Adjust minimum MAX_DISK_SIZE to PAGE_SIZE to fix floppy on sparc64 and likely all other PAGE_SIZE != 4KB configs. Cc: stable@vger.kernel.org Signed-off-by: René Rebe Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman --- drivers/block/floppy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index 5336c3c5ca362..c28786e0fe1c8 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -329,7 +329,7 @@ static bool initialized; * This default is used whenever the current disk size is unknown. * [Now it is rather a minimum] */ -#define MAX_DISK_SIZE 4 /* 3984 */ +#define MAX_DISK_SIZE (PAGE_SIZE / 1024) /* * globals used by 'result()' From 17900c56e263732687989b606ba5a6d1c44a0fa1 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sat, 15 Nov 2025 15:08:16 -0800 Subject: [PATCH 1254/2333] crypto: scatterwalk - Fix memcpy_sglist() to always succeed commit 4dffc9bbffb9ccfcda730d899c97c553599e7ca8 upstream. The original implementation of memcpy_sglist() was broken because it didn't handle scatterlists that describe exactly the same memory, which is a case that many callers rely on. The current implementation is broken too because it calls the skcipher_walk functions which can fail. It ignores any errors from those functions. Fix it by replacing it with a new implementation written from scratch. It always succeeds. It's also a bit faster, since it avoids the overhead of skcipher_walk. skcipher_walk includes a lot of functionality (such as alignmask handling) that's irrelevant here. Reported-by: Colin Ian King Closes: https://lore.kernel.org/r/20251114122620.111623-1-coking@nvidia.com Fixes: 131bdceca1f0 ("crypto: scatterwalk - Add memcpy_sglist") Fixes: 0f8d42bf128d ("crypto: scatterwalk - Move skcipher walk and use it for memcpy_sglist") Cc: stable@vger.kernel.org Signed-off-by: Eric Biggers Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman --- crypto/scatterwalk.c | 97 +++++++++++++++++++++++++++++++----- include/crypto/scatterwalk.h | 52 +++++++++++-------- 2 files changed, 115 insertions(+), 34 deletions(-) diff --git a/crypto/scatterwalk.c b/crypto/scatterwalk.c index 1d010e2a1b1a2..b95e5974e327b 100644 --- a/crypto/scatterwalk.c +++ b/crypto/scatterwalk.c @@ -101,26 +101,97 @@ void memcpy_to_sglist(struct scatterlist *sg, unsigned int start, } EXPORT_SYMBOL_GPL(memcpy_to_sglist); +/** + * memcpy_sglist() - Copy data from one scatterlist to another + * @dst: The destination scatterlist. Can be NULL if @nbytes == 0. + * @src: The source scatterlist. Can be NULL if @nbytes == 0. + * @nbytes: Number of bytes to copy + * + * The scatterlists can describe exactly the same memory, in which case this + * function is a no-op. No other overlaps are supported. + * + * Context: Any context + */ void memcpy_sglist(struct scatterlist *dst, struct scatterlist *src, unsigned int nbytes) { - struct skcipher_walk walk = {}; + unsigned int src_offset, dst_offset; - if (unlikely(nbytes == 0)) /* in case sg == NULL */ + if (unlikely(nbytes == 0)) /* in case src and/or dst is NULL */ return; - walk.total = nbytes; - - scatterwalk_start(&walk.in, src); - scatterwalk_start(&walk.out, dst); + src_offset = src->offset; + dst_offset = dst->offset; + for (;;) { + /* Compute the length to copy this step. */ + unsigned int len = min3(src->offset + src->length - src_offset, + dst->offset + dst->length - dst_offset, + nbytes); + struct page *src_page = sg_page(src); + struct page *dst_page = sg_page(dst); + const void *src_virt; + void *dst_virt; + + if (IS_ENABLED(CONFIG_HIGHMEM)) { + /* HIGHMEM: we may have to actually map the pages. */ + const unsigned int src_oip = offset_in_page(src_offset); + const unsigned int dst_oip = offset_in_page(dst_offset); + const unsigned int limit = PAGE_SIZE; + + /* Further limit len to not cross a page boundary. */ + len = min3(len, limit - src_oip, limit - dst_oip); + + /* Compute the source and destination pages. */ + src_page += src_offset / PAGE_SIZE; + dst_page += dst_offset / PAGE_SIZE; + + if (src_page != dst_page) { + /* Copy between different pages. */ + memcpy_page(dst_page, dst_oip, + src_page, src_oip, len); + flush_dcache_page(dst_page); + } else if (src_oip != dst_oip) { + /* Copy between different parts of same page. */ + dst_virt = kmap_local_page(dst_page); + memcpy(dst_virt + dst_oip, dst_virt + src_oip, + len); + kunmap_local(dst_virt); + flush_dcache_page(dst_page); + } /* Else, it's the same memory. No action needed. */ + } else { + /* + * !HIGHMEM: no mapping needed. Just work in the linear + * buffer of each sg entry. Note that we can cross page + * boundaries, as they are not significant in this case. + */ + src_virt = page_address(src_page) + src_offset; + dst_virt = page_address(dst_page) + dst_offset; + if (src_virt != dst_virt) { + memcpy(dst_virt, src_virt, len); + if (ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE) + __scatterwalk_flush_dcache_pages( + dst_page, dst_offset, len); + } /* Else, it's the same memory. No action needed. */ + } + nbytes -= len; + if (nbytes == 0) /* No more to copy? */ + break; - skcipher_walk_first(&walk, true); - do { - if (walk.src.virt.addr != walk.dst.virt.addr) - memcpy(walk.dst.virt.addr, walk.src.virt.addr, - walk.nbytes); - skcipher_walk_done(&walk, 0); - } while (walk.nbytes); + /* + * There's more to copy. Advance the offsets by the length + * copied this step, and advance the sg entries as needed. + */ + src_offset += len; + if (src_offset >= src->offset + src->length) { + src = sg_next(src); + src_offset = src->offset; + } + dst_offset += len; + if (dst_offset >= dst->offset + dst->length) { + dst = sg_next(dst); + dst_offset = dst->offset; + } + } } EXPORT_SYMBOL_GPL(memcpy_sglist); diff --git a/include/crypto/scatterwalk.h b/include/crypto/scatterwalk.h index 83d14376ff2bc..f485454e3955c 100644 --- a/include/crypto/scatterwalk.h +++ b/include/crypto/scatterwalk.h @@ -227,6 +227,34 @@ static inline void scatterwalk_done_src(struct scatter_walk *walk, scatterwalk_advance(walk, nbytes); } +/* + * Flush the dcache of any pages that overlap the region + * [offset, offset + nbytes) relative to base_page. + * + * This should be called only when ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE, to ensure + * that all relevant code (including the call to sg_page() in the caller, if + * applicable) gets fully optimized out when !ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE. + */ +static inline void __scatterwalk_flush_dcache_pages(struct page *base_page, + unsigned int offset, + unsigned int nbytes) +{ + unsigned int num_pages; + + base_page += offset / PAGE_SIZE; + offset %= PAGE_SIZE; + + /* + * This is an overflow-safe version of + * num_pages = DIV_ROUND_UP(offset + nbytes, PAGE_SIZE). + */ + num_pages = nbytes / PAGE_SIZE; + num_pages += DIV_ROUND_UP(offset + (nbytes % PAGE_SIZE), PAGE_SIZE); + + for (unsigned int i = 0; i < num_pages; i++) + flush_dcache_page(base_page + i); +} + /** * scatterwalk_done_dst() - Finish one step of a walk of destination scatterlist * @walk: the scatter_walk @@ -240,27 +268,9 @@ static inline void scatterwalk_done_dst(struct scatter_walk *walk, unsigned int nbytes) { scatterwalk_unmap(walk); - /* - * Explicitly check ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE instead of just - * relying on flush_dcache_page() being a no-op when not implemented, - * since otherwise the BUG_ON in sg_page() does not get optimized out. - * This also avoids having to consider whether the loop would get - * reliably optimized out or not. - */ - if (ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE) { - struct page *base_page; - unsigned int offset; - int start, end, i; - - base_page = sg_page(walk->sg); - offset = walk->offset; - start = offset >> PAGE_SHIFT; - end = start + (nbytes >> PAGE_SHIFT); - end += (offset_in_page(offset) + offset_in_page(nbytes) + - PAGE_SIZE - 1) >> PAGE_SHIFT; - for (i = start; i < end; i++) - flush_dcache_page(base_page + i); - } + if (ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE) + __scatterwalk_flush_dcache_pages(sg_page(walk->sg), + walk->offset, nbytes); scatterwalk_advance(walk, nbytes); } From 419b1ea754c9d09eec3ee06bbedc1b749f06b732 Mon Sep 17 00:00:00 2001 From: Zheng Yejian Date: Fri, 11 Oct 2024 22:38:53 +0800 Subject: [PATCH 1255/2333] kallsyms: Fix wrong "big" kernel symbol type read from procfs commit f3f9f42232dee596d15491ca3f611d02174db49c upstream. Currently when the length of a symbol is longer than 0x7f characters, its type shown in /proc/kallsyms can be incorrect. I found this issue when reading the code, but it can be reproduced by following steps: 1. Define a function which symbol length is 130 characters: #define X13(x) x##x##x##x##x##x##x##x##x##x##x##x##x static noinline void X13(x123456789)(void) { printk("hello world\n"); } 2. The type in vmlinux is 't': $ nm vmlinux | grep x123456 ffffffff816290f0 t x123456789x123456789x123456789x12[...] 3. Then boot the kernel, the type shown in /proc/kallsyms becomes 'g' instead of the expected 't': # cat /proc/kallsyms | grep x123456 ffffffff816290f0 g x123456789x123456789x123456789x12[...] The root cause is that, after commit 73bbb94466fd ("kallsyms: support "big" kernel symbols"), ULEB128 was used to encode symbol name length. That is, for "big" kernel symbols of which name length is longer than 0x7f characters, the length info is encoded into 2 bytes. kallsyms_get_symbol_type() expects to read the first char of the symbol name which indicates the symbol type. However, due to the "big" symbol case not being handled, the symbol type read from /proc/kallsyms may be wrong, so handle it properly. Cc: stable@vger.kernel.org Fixes: 73bbb94466fd ("kallsyms: support "big" kernel symbols") Signed-off-by: Zheng Yejian Acked-by: Gary Guo Link: https://patch.msgid.link/20241011143853.3022643-1-zhengyejian@huaweicloud.com Signed-off-by: Miguel Ojeda Signed-off-by: Greg Kroah-Hartman --- kernel/kallsyms.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/kernel/kallsyms.c b/kernel/kallsyms.c index 1e76358641247..049e296f586cc 100644 --- a/kernel/kallsyms.c +++ b/kernel/kallsyms.c @@ -103,8 +103,11 @@ static char kallsyms_get_symbol_type(unsigned int off) { /* * Get just the first code, look it up in the token table, - * and return the first char from this token. + * and return the first char from this token. If MSB of length + * is 1, it is a "big" symbol, so needs an additional byte. */ + if (kallsyms_names[off] & 0x80) + off++; return kallsyms_token_table[kallsyms_token_index[kallsyms_names[off + 1]]]; } From b3b036bac7c91629a25250e9f40ab32f868bd4ba Mon Sep 17 00:00:00 2001 From: Konstantin Komarov Date: Thu, 18 Sep 2025 13:35:24 +0300 Subject: [PATCH 1256/2333] fs/ntfs3: fix mount failure for sparse runs in run_unpack() commit 801f614ba263cb37624982b27b4c82f3c3c597a9 upstream. Some NTFS volumes failed to mount because sparse data runs were not handled correctly during runlist unpacking. The code performed arithmetic on the special SPARSE_LCN64 marker, leading to invalid LCN values and mount errors. Add an explicit check for the case described above, marking the run as sparse without applying arithmetic. Fixes: 736fc7bf5f68 ("fs: ntfs3: Fix integer overflow in run_unpack()") Cc: stable@vger.kernel.org Signed-off-by: Konstantin Komarov Signed-off-by: Greg Kroah-Hartman --- fs/ntfs3/run.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/fs/ntfs3/run.c b/fs/ntfs3/run.c index 88550085f7457..5df55e4adbb11 100644 --- a/fs/ntfs3/run.c +++ b/fs/ntfs3/run.c @@ -984,8 +984,12 @@ int run_unpack(struct runs_tree *run, struct ntfs_sb_info *sbi, CLST ino, if (!dlcn) return -EINVAL; - if (check_add_overflow(prev_lcn, dlcn, &lcn)) + /* Check special combination: 0 + SPARSE_LCN64. */ + if (!prev_lcn && dlcn == SPARSE_LCN64) { + lcn = SPARSE_LCN64; + } else if (check_add_overflow(prev_lcn, dlcn, &lcn)) { return -EINVAL; + } prev_lcn = lcn; } else { /* The size of 'dlcn' can't be > 8. */ From 2b78da4cc75d26069017e949af0d7f44447a4161 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Wed, 3 Dec 2025 18:09:24 -0500 Subject: [PATCH 1257/2333] ktest.pl: Fix uninitialized var in config-bisect.pl commit d3042cbe84a060b4df764eb6c5300bbe20d125ca upstream. The error path of copying the old config used the wrong variable in the error message: $ mkdir /tmp/build $ ./tools/testing/ktest/config-bisect.pl -b /tmp/build config-good /tmp/config-bad $ chmod 0 /tmp/build $ ./tools/testing/ktest/config-bisect.pl -b /tmp/build config-good /tmp/config-bad good cp /tmp/build//.config config-good.tmp ... [0 seconds] FAILED! Use of uninitialized value $config in concatenation (.) or string at ./tools/testing/ktest/config-bisect.pl line 744. failed to copy to config-good.tmp When it should have shown: failed to copy /tmp/build//.config to config-good.tmp Cc: stable@vger.kernel.org Cc: John 'Warthog9' Hawley Fixes: 0f0db065999cf ("ktest: Add standalone config-bisect.pl program") Link: https://patch.msgid.link/20251203180924.6862bd26@gandalf.local.home Reported-by: "John W. Krahn" Signed-off-by: Steven Rostedt Signed-off-by: Greg Kroah-Hartman --- tools/testing/ktest/config-bisect.pl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/testing/ktest/config-bisect.pl b/tools/testing/ktest/config-bisect.pl index 6fd8649353195..bee7cb34a289c 100755 --- a/tools/testing/ktest/config-bisect.pl +++ b/tools/testing/ktest/config-bisect.pl @@ -741,9 +741,9 @@ sub config_bisect { die "Can not find file $bad\n"; } if ($val eq "good") { - run_command "cp $output_config $good" or die "failed to copy $config to $good\n"; + run_command "cp $output_config $good" or die "failed to copy $output_config to $good\n"; } elsif ($val eq "bad") { - run_command "cp $output_config $bad" or die "failed to copy $config to $bad\n"; + run_command "cp $output_config $bad" or die "failed to copy $output_config to $bad\n"; } } From 858344bc9210bea9ab2bdc7e9e331ba84c164e50 Mon Sep 17 00:00:00 2001 From: Jarkko Sakkinen Date: Tue, 30 Sep 2025 15:58:02 +0300 Subject: [PATCH 1258/2333] tpm: Cap the number of PCR banks commit faf07e611dfa464b201223a7253e9dc5ee0f3c9e upstream. tpm2_get_pcr_allocation() does not cap any upper limit for the number of banks. Cap the limit to eight banks so that out of bounds values coming from external I/O cause on only limited harm. Cc: stable@vger.kernel.org # v5.10+ Fixes: bcfff8384f6c ("tpm: dynamically allocate the allocated_banks array") Tested-by: Lai Yi Reviewed-by: Jonathan McDowell Reviewed-by: Roberto Sassu Signed-off-by: Jarkko Sakkinen Signed-off-by: Greg Kroah-Hartman --- drivers/char/tpm/tpm-chip.c | 1 - drivers/char/tpm/tpm1-cmd.c | 5 ----- drivers/char/tpm/tpm2-cmd.c | 8 +++----- include/linux/tpm.h | 8 +++++--- 4 files changed, 8 insertions(+), 14 deletions(-) diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c index e25daf2396d37..dfeb28866a327 100644 --- a/drivers/char/tpm/tpm-chip.c +++ b/drivers/char/tpm/tpm-chip.c @@ -282,7 +282,6 @@ static void tpm_dev_release(struct device *dev) kfree(chip->work_space.context_buf); kfree(chip->work_space.session_buf); - kfree(chip->allocated_banks); #ifdef CONFIG_TCG_TPM2_HMAC kfree(chip->auth); #endif diff --git a/drivers/char/tpm/tpm1-cmd.c b/drivers/char/tpm/tpm1-cmd.c index cf64c73851052..b49a790f1bd53 100644 --- a/drivers/char/tpm/tpm1-cmd.c +++ b/drivers/char/tpm/tpm1-cmd.c @@ -799,11 +799,6 @@ int tpm1_pm_suspend(struct tpm_chip *chip, u32 tpm_suspend_pcr) */ int tpm1_get_pcr_allocation(struct tpm_chip *chip) { - chip->allocated_banks = kcalloc(1, sizeof(*chip->allocated_banks), - GFP_KERNEL); - if (!chip->allocated_banks) - return -ENOMEM; - chip->allocated_banks[0].alg_id = TPM_ALG_SHA1; chip->allocated_banks[0].digest_size = hash_digest_size[HASH_ALGO_SHA1]; chip->allocated_banks[0].crypto_id = HASH_ALGO_SHA1; diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c index 7d77f6fbc1520..5b6ccf901623c 100644 --- a/drivers/char/tpm/tpm2-cmd.c +++ b/drivers/char/tpm/tpm2-cmd.c @@ -538,11 +538,9 @@ ssize_t tpm2_get_pcr_allocation(struct tpm_chip *chip) nr_possible_banks = be32_to_cpup( (__be32 *)&buf.data[TPM_HEADER_SIZE + 5]); - - chip->allocated_banks = kcalloc(nr_possible_banks, - sizeof(*chip->allocated_banks), - GFP_KERNEL); - if (!chip->allocated_banks) { + if (nr_possible_banks > TPM2_MAX_PCR_BANKS) { + pr_err("tpm: out of bank capacity: %u > %u\n", + nr_possible_banks, TPM2_MAX_PCR_BANKS); rc = -ENOMEM; goto out; } diff --git a/include/linux/tpm.h b/include/linux/tpm.h index dc0338a783f37..eb0ff071bcaed 100644 --- a/include/linux/tpm.h +++ b/include/linux/tpm.h @@ -26,7 +26,9 @@ #include #define TPM_DIGEST_SIZE 20 /* Max TPM v1.2 PCR size */ -#define TPM_MAX_DIGEST_SIZE SHA512_DIGEST_SIZE + +#define TPM2_MAX_DIGEST_SIZE SHA512_DIGEST_SIZE +#define TPM2_MAX_PCR_BANKS 8 struct tpm_chip; struct trusted_key_payload; @@ -68,7 +70,7 @@ enum tpm2_curves { struct tpm_digest { u16 alg_id; - u8 digest[TPM_MAX_DIGEST_SIZE]; + u8 digest[TPM2_MAX_DIGEST_SIZE]; } __packed; struct tpm_bank_info { @@ -189,7 +191,7 @@ struct tpm_chip { unsigned int groups_cnt; u32 nr_allocated_banks; - struct tpm_bank_info *allocated_banks; + struct tpm_bank_info allocated_banks[TPM2_MAX_PCR_BANKS]; #ifdef CONFIG_ACPI acpi_handle acpi_dev_handle; char ppi_version[TPM_PPI_VERSION_LEN + 1]; From b107196729ff6b9d6cde0a71f49c1243def43328 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 2 Dec 2025 19:27:29 +0100 Subject: [PATCH 1259/2333] fs: PM: Fix reverse check in filesystems_freeze_callback() commit 222047f68e8565c558728f792f6fef152a1d4d51 upstream. The freeze_all_ptr check in filesystems_freeze_callback() introduced by commit a3f8f8662771 ("power: always freeze efivarfs") is reverse which quite confusingly causes all file systems to be frozen when filesystem_freeze_enabled is false. On my systems it causes the WARN_ON_ONCE() in __set_task_frozen() to trigger, most likely due to an attempt to freeze a file system that is not ready for that. Add a logical negation to the check in question to reverse it as appropriate. Fixes: a3f8f8662771 ("power: always freeze efivarfs") Cc: 6.18+ # 6.18+ Signed-off-by: Rafael J. Wysocki Link: https://patch.msgid.link/12788397.O9o76ZdvQC@rafael.j.wysocki Signed-off-by: Christian Brauner Signed-off-by: Greg Kroah-Hartman --- fs/super.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/super.c b/fs/super.c index 277b84e5c2791..4c79f170ac0d2 100644 --- a/fs/super.c +++ b/fs/super.c @@ -1188,7 +1188,7 @@ static void filesystems_freeze_callback(struct super_block *sb, void *freeze_all if (!sb->s_op->freeze_fs && !sb->s_op->freeze_super) return; - if (freeze_all_ptr && !(sb->s_type->fs_flags & FS_POWER_FREEZE)) + if (!freeze_all_ptr && !(sb->s_type->fs_flags & FS_POWER_FREEZE)) return; if (!get_active_super(sb)) From be8ba672cc5ae52e8a10ac8eddb89d88f66b3cab Mon Sep 17 00:00:00 2001 From: John Ogness Date: Thu, 13 Nov 2025 17:09:47 +0106 Subject: [PATCH 1260/2333] printk: Allow printk_trigger_flush() to flush all types commit d01ff281bd9b1bfeac9ab98ec8a9ee41da900d5e upstream. Currently printk_trigger_flush() only triggers legacy offloaded flushing, even if that may not be the appropriate method to flush for currently registered consoles. (The function predates the NBCON consoles.) Since commit 6690d6b52726 ("printk: Add helper for flush type logic") there is printk_get_console_flush_type(), which also considers NBCON consoles and reports all the methods of flushing appropriate based on the system state and consoles available. Update printk_trigger_flush() to use printk_get_console_flush_type() to appropriately flush registered consoles. Suggested-by: Petr Mladek Signed-off-by: John Ogness Reviewed-by: Petr Mladek Link: https://lore.kernel.org/stable/20251113160351.113031-2-john.ogness%40linutronix.de Tested-by: Sherry Sun Link: https://patch.msgid.link/20251113160351.113031-2-john.ogness@linutronix.de Signed-off-by: Petr Mladek Signed-off-by: Greg Kroah-Hartman --- kernel/printk/nbcon.c | 2 +- kernel/printk/printk.c | 23 ++++++++++++++++++++++- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c index da07c59f7aa2e..730d14f6cbc58 100644 --- a/kernel/printk/nbcon.c +++ b/kernel/printk/nbcon.c @@ -1856,7 +1856,7 @@ void nbcon_device_release(struct console *con) if (console_trylock()) console_unlock(); } else if (ft.legacy_offload) { - printk_trigger_flush(); + defer_console_output(); } } console_srcu_read_unlock(cookie); diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index e850c237b4ba9..b1c0d35cf3caa 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -4595,9 +4595,30 @@ void defer_console_output(void) __wake_up_klogd(PRINTK_PENDING_WAKEUP | PRINTK_PENDING_OUTPUT); } +/** + * printk_trigger_flush - Attempt to flush printk buffer to consoles. + * + * If possible, flush the printk buffer to all consoles in the caller's + * context. If offloading is available, trigger deferred printing. + * + * This is best effort. Depending on the system state, console states, + * and caller context, no actual flushing may result from this call. + */ void printk_trigger_flush(void) { - defer_console_output(); + struct console_flush_type ft; + + printk_get_console_flush_type(&ft); + if (ft.nbcon_atomic) + nbcon_atomic_flush_pending(); + if (ft.nbcon_offload) + nbcon_kthreads_wake(); + if (ft.legacy_direct) { + if (console_trylock()) + console_unlock(); + } + if (ft.legacy_offload) + defer_console_output(); } int vprintk_deferred(const char *fmt, va_list args) From 8626a78ce7ddaa807324a8e0056817ac8d1b0267 Mon Sep 17 00:00:00 2001 From: John Ogness Date: Fri, 21 Nov 2025 11:26:00 +0106 Subject: [PATCH 1261/2333] printk: Avoid irq_work for printk_deferred() on suspend commit 66e7c1e0ee08cfb6db64f8f3f6e5a3cc930145c8 upstream. With commit ("printk: Avoid scheduling irq_work on suspend") the implementation of printk_get_console_flush_type() was modified to avoid offloading when irq_work should be blocked during suspend. Since printk uses the returned flush type to determine what flushing methods are used, this was thought to be sufficient for avoiding irq_work usage during the suspend phase. However, vprintk_emit() implements a hack to support printk_deferred(). In this hack, the returned flush type is adjusted to make sure no legacy direct printing occurs when printk_deferred() was used. Because of this hack, the legacy offloading flushing method can still be used, causing irq_work to be queued when it should not be. Adjust the vprintk_emit() hack to also consider @console_irqwork_blocked so that legacy offloading will not be chosen when irq_work should be blocked. Link: https://lore.kernel.org/lkml/87fra90xv4.fsf@jogness.linutronix.de Signed-off-by: John Ogness Fixes: 26873e3e7f0c ("printk: Avoid scheduling irq_work on suspend") Reviewed-by: Petr Mladek Signed-off-by: Petr Mladek Signed-off-by: Greg Kroah-Hartman --- kernel/printk/printk.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index b1c0d35cf3caa..c27fc7fc64eb5 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -2393,7 +2393,7 @@ asmlinkage int vprintk_emit(int facility, int level, /* If called from the scheduler, we can not call up(). */ if (level == LOGLEVEL_SCHED) { level = LOGLEVEL_DEFAULT; - ft.legacy_offload |= ft.legacy_direct; + ft.legacy_offload |= ft.legacy_direct && !console_irqwork_blocked; ft.legacy_direct = false; } From 5bbacbbf1ca4419861dca3c6b82707c10e9c021c Mon Sep 17 00:00:00 2001 From: Fedor Pchelkin Date: Sat, 1 Nov 2025 19:04:28 +0300 Subject: [PATCH 1262/2333] ext4: fix string copying in parse_apply_sb_mount_options() commit ee5a977b4e771cc181f39d504426dbd31ed701cc upstream. strscpy_pad() can't be used to copy a non-NUL-term string into a NUL-term string of possibly bigger size. Commit 0efc5990bca5 ("string.h: Introduce memtostr() and memtostr_pad()") provides additional information in that regard. So if this happens, the following warning is observed: strnlen: detected buffer overflow: 65 byte read of buffer size 64 WARNING: CPU: 0 PID: 28655 at lib/string_helpers.c:1032 __fortify_report+0x96/0xc0 lib/string_helpers.c:1032 Modules linked in: CPU: 0 UID: 0 PID: 28655 Comm: syz-executor.3 Not tainted 6.12.54-syzkaller-00144-g5f0270f1ba00 #0 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 RIP: 0010:__fortify_report+0x96/0xc0 lib/string_helpers.c:1032 Call Trace: __fortify_panic+0x1f/0x30 lib/string_helpers.c:1039 strnlen include/linux/fortify-string.h:235 [inline] sized_strscpy include/linux/fortify-string.h:309 [inline] parse_apply_sb_mount_options fs/ext4/super.c:2504 [inline] __ext4_fill_super fs/ext4/super.c:5261 [inline] ext4_fill_super+0x3c35/0xad00 fs/ext4/super.c:5706 get_tree_bdev_flags+0x387/0x620 fs/super.c:1636 vfs_get_tree+0x93/0x380 fs/super.c:1814 do_new_mount fs/namespace.c:3553 [inline] path_mount+0x6ae/0x1f70 fs/namespace.c:3880 do_mount fs/namespace.c:3893 [inline] __do_sys_mount fs/namespace.c:4103 [inline] __se_sys_mount fs/namespace.c:4080 [inline] __x64_sys_mount+0x280/0x300 fs/namespace.c:4080 do_syscall_x64 arch/x86/entry/common.c:52 [inline] do_syscall_64+0x64/0x140 arch/x86/entry/common.c:83 entry_SYSCALL_64_after_hwframe+0x76/0x7e Since userspace is expected to provide s_mount_opts field to be at most 63 characters long with the ending byte being NUL-term, use a 64-byte buffer which matches the size of s_mount_opts, so that strscpy_pad() does its job properly. Return with error if the user still managed to provide a non-NUL-term string here. Found by Linux Verification Center (linuxtesting.org) with Syzkaller. Fixes: 8ecb790ea8c3 ("ext4: avoid potential buffer over-read in parse_apply_sb_mount_options()") Cc: stable@vger.kernel.org Signed-off-by: Fedor Pchelkin Reviewed-by: Baokun Li Reviewed-by: Jan Kara Message-ID: <20251101160430.222297-1-pchelkin@ispras.ru> Signed-off-by: Theodore Ts'o Signed-off-by: Greg Kroah-Hartman --- fs/ext4/super.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 33e7c08c9529c..15bef41f08bd1 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -2475,7 +2475,7 @@ static int parse_apply_sb_mount_options(struct super_block *sb, struct ext4_fs_context *m_ctx) { struct ext4_sb_info *sbi = EXT4_SB(sb); - char s_mount_opts[65]; + char s_mount_opts[64]; struct ext4_fs_context *s_ctx = NULL; struct fs_context *fc = NULL; int ret = -ENOMEM; @@ -2483,7 +2483,8 @@ static int parse_apply_sb_mount_options(struct super_block *sb, if (!sbi->s_es->s_mount_opts[0]) return 0; - strscpy_pad(s_mount_opts, sbi->s_es->s_mount_opts); + if (strscpy_pad(s_mount_opts, sbi->s_es->s_mount_opts) < 0) + return -E2BIG; fc = kzalloc(sizeof(struct fs_context), GFP_KERNEL); if (!fc) From ecb7e5603b57e4e0182cd648937b7dbd89122285 Mon Sep 17 00:00:00 2001 From: Fedor Pchelkin Date: Sat, 1 Nov 2025 19:04:29 +0300 Subject: [PATCH 1263/2333] ext4: check if mount_opts is NUL-terminated in ext4_ioctl_set_tune_sb() commit 3db63d2c2d1d1e78615dd742568c5a2d55291ad1 upstream. params.mount_opts may come as potentially non-NUL-term string. Userspace is expected to pass a NUL-term string. Add an extra check to ensure this holds true. Note that further code utilizes strscpy_pad() so this is just for proper informing the user of incorrect data being provided. Found by Linux Verification Center (linuxtesting.org). Signed-off-by: Fedor Pchelkin Reviewed-by: Baokun Li Reviewed-by: Jan Kara Message-ID: <20251101160430.222297-2-pchelkin@ispras.ru> Signed-off-by: Theodore Ts'o Cc: stable@kernel.org Signed-off-by: Greg Kroah-Hartman --- fs/ext4/ioctl.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c index a93a7baae990c..3dec26c939fde 100644 --- a/fs/ext4/ioctl.c +++ b/fs/ext4/ioctl.c @@ -1394,6 +1394,10 @@ static int ext4_ioctl_set_tune_sb(struct file *filp, if (copy_from_user(¶ms, in, sizeof(params))) return -EFAULT; + if (strnlen(params.mount_opts, sizeof(params.mount_opts)) == + sizeof(params.mount_opts)) + return -E2BIG; + if ((params.set_flags & ~TUNE_OPS_SUPPORTED) != 0) return -EOPNOTSUPP; From ce5f54c065a4a7cbb92787f4f140917112350142 Mon Sep 17 00:00:00 2001 From: Karina Yankevich Date: Wed, 22 Oct 2025 12:32:53 +0300 Subject: [PATCH 1264/2333] ext4: xattr: fix null pointer deref in ext4_raw_inode() commit b97cb7d6a051aa6ebd57906df0e26e9e36c26d14 upstream. If ext4_get_inode_loc() fails (e.g. if it returns -EFSCORRUPTED), iloc.bh will remain set to NULL. Since ext4_xattr_inode_dec_ref_all() lacks error checking, this will lead to a null pointer dereference in ext4_raw_inode(), called right after ext4_get_inode_loc(). Found by Linux Verification Center (linuxtesting.org) with SVACE. Fixes: c8e008b60492 ("ext4: ignore xattrs past end") Cc: stable@kernel.org Signed-off-by: Karina Yankevich Reviewed-by: Sergey Shtylyov Reviewed-by: Baokun Li Message-ID: <20251022093253.3546296-1-k.yankevich@omp.ru> Signed-off-by: Theodore Ts'o Signed-off-by: Greg Kroah-Hartman --- fs/ext4/xattr.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c index ce7253b3f5499..2e02efbddaacc 100644 --- a/fs/ext4/xattr.c +++ b/fs/ext4/xattr.c @@ -1174,7 +1174,11 @@ ext4_xattr_inode_dec_ref_all(handle_t *handle, struct inode *parent, if (block_csum) end = (void *)bh->b_data + bh->b_size; else { - ext4_get_inode_loc(parent, &iloc); + err = ext4_get_inode_loc(parent, &iloc); + if (err) { + EXT4_ERROR_INODE(parent, "parent inode loc (error %d)", err); + return; + } end = (void *)ext4_raw_inode(&iloc) + EXT4_SB(parent->i_sb)->s_inode_size; } From 8cde2072825bd0e47478e8dbf0353f6a0b7107d5 Mon Sep 17 00:00:00 2001 From: Haibo Chen Date: Tue, 4 Nov 2025 16:12:24 +0800 Subject: [PATCH 1265/2333] ext4: clear i_state_flags when alloc inode commit 4091c8206cfd2e3bb529ef260887296b90d9b6a2 upstream. i_state_flags used on 32-bit archs, need to clear this flag when alloc inode. Find this issue when umount ext4, sometimes track the inode as orphan accidently, cause ext4 mesg dump. Fixes: acf943e9768e ("ext4: fix checks for orphan inodes") Signed-off-by: Haibo Chen Reviewed-by: Baokun Li Reviewed-by: Zhang Yi Reviewed-by: Jan Kara Message-ID: <20251104-ext4-v1-1-73691a0800f9@nxp.com> Signed-off-by: Theodore Ts'o Cc: stable@kernel.org Signed-off-by: Greg Kroah-Hartman --- fs/ext4/ialloc.c | 1 - fs/ext4/inode.c | 1 - fs/ext4/super.c | 1 + 3 files changed, 1 insertion(+), 2 deletions(-) diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c index ba4fd9aba1c14..b20a1bf866abe 100644 --- a/fs/ext4/ialloc.c +++ b/fs/ext4/ialloc.c @@ -1293,7 +1293,6 @@ struct inode *__ext4_new_inode(struct mnt_idmap *idmap, ei->i_csum_seed = ext4_chksum(csum, (__u8 *)&gen, sizeof(gen)); } - ext4_clear_state_flags(ei); /* Only relevant on 32-bit archs */ ext4_set_inode_state(inode, EXT4_STATE_NEW); ei->i_extra_isize = sbi->s_want_extra_isize; diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index e99306a8f47ce..5fbe1a2ab81c3 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -5288,7 +5288,6 @@ struct inode *__ext4_iget(struct super_block *sb, unsigned long ino, ei->i_projid = make_kprojid(&init_user_ns, i_projid); set_nlink(inode, le16_to_cpu(raw_inode->i_links_count)); - ext4_clear_state_flags(ei); /* Only relevant on 32-bit archs */ ei->i_inline_off = 0; ei->i_dir_start_lookup = 0; ei->i_dtime = le32_to_cpu(raw_inode->i_dtime); diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 15bef41f08bd1..4ef5590c73fda 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -1396,6 +1396,7 @@ static struct inode *ext4_alloc_inode(struct super_block *sb) inode_set_iversion(&ei->vfs_inode, 1); ei->i_flags = 0; + ext4_clear_state_flags(ei); /* Only relevant on 32-bit archs */ spin_lock_init(&ei->i_raw_lock); ei->i_prealloc_node = RB_ROOT; atomic_set(&ei->i_prealloc_active, 0); From e70d561d9d8393acbf5db1fc2e0f4d2e488a12b6 Mon Sep 17 00:00:00 2001 From: Yongjian Sun Date: Thu, 6 Nov 2025 14:06:13 +0800 Subject: [PATCH 1266/2333] ext4: fix incorrect group number assertion in mb_check_buddy commit 3f7a79d05c692c7cfec70bf104b1b3c3d0ce6247 upstream. When the MB_CHECK_ASSERT macro is enabled, an assertion failure can occur in __mb_check_buddy when checking preallocated blocks (pa) in a block group: Assertion failure in mb_free_blocks() : "groupnr == e4b->bd_group" This happens when a pa at the very end of a block group (e.g., pa_pstart=32765, pa_len=3 in a group of 32768 blocks) becomes exhausted - its pa_pstart is advanced by pa_len to 32768, which lies in the next block group. If this exhausted pa (with pa_len == 0) is still in the bb_prealloc_list during the buddy check, the assertion incorrectly flags it as belonging to the wrong group. A possible sequence is as follows: ext4_mb_new_blocks ext4_mb_release_context pa->pa_pstart += EXT4_C2B(sbi, ac->ac_b_ex.fe_len) pa->pa_len -= ac->ac_b_ex.fe_len __mb_check_buddy for each pa in group ext4_get_group_no_and_offset MB_CHECK_ASSERT(groupnr == e4b->bd_group) To fix this, we modify the check to skip block group validation for exhausted preallocations (where pa_len == 0). Such entries are in a transitional state and will be removed from the list soon, so they should not trigger an assertion. This change prevents the false positive while maintaining the integrity of the checks for active allocations. Fixes: c9de560ded61f ("ext4: Add multi block allocator for ext4") Signed-off-by: Yongjian Sun Reviewed-by: Baokun Li Reviewed-by: Jan Kara Message-ID: <20251106060614.631382-2-sunyongjian@huaweicloud.com> Signed-off-by: Theodore Ts'o Cc: stable@kernel.org Signed-off-by: Greg Kroah-Hartman --- fs/ext4/mballoc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c index c56b51e1162eb..65335248825ce 100644 --- a/fs/ext4/mballoc.c +++ b/fs/ext4/mballoc.c @@ -783,6 +783,8 @@ static void __mb_check_buddy(struct ext4_buddy *e4b, char *file, ext4_group_t groupnr; struct ext4_prealloc_space *pa; pa = list_entry(cur, struct ext4_prealloc_space, pa_group_list); + if (!pa->pa_len) + continue; ext4_get_group_no_and_offset(sb, pa->pa_pstart, &groupnr, &k); MB_CHECK_ASSERT(groupnr == e4b->bd_group); for (i = 0; i < pa->pa_len; i++) From b59fa60114806fa57961f23fa2c626ba3211f28b Mon Sep 17 00:00:00 2001 From: Baokun Li Date: Thu, 20 Nov 2025 21:42:33 +0800 Subject: [PATCH 1267/2333] ext4: align max orphan file size with e2fsprogs limit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 7c11c56eb32eae96893eebafdbe3decadefe88ad upstream. Kernel commit 0a6ce20c1564 ("ext4: verify orphan file size is not too big") limits the maximum supported orphan file size to 8 << 20. However, in e2fsprogs, the orphan file size is set to 32–512 filesystem blocks when creating a filesystem. With 64k block size, formatting an ext4 fs >32G gives an orphan file bigger than the kernel allows, so mount prints an error and fails: EXT4-fs (vdb): orphan file too big: 8650752 EXT4-fs (vdb): mount failed To prevent this issue and allow previously created 64KB filesystems to mount, we updates the maximum allowed orphan file size in the kernel to 512 filesystem blocks. Fixes: 0a6ce20c1564 ("ext4: verify orphan file size is not too big") Signed-off-by: Baokun Li Reviewed-by: Jan Kara Message-ID: <20251120134233.2994147-1-libaokun@huaweicloud.com> Signed-off-by: Theodore Ts'o Cc: stable@kernel.org Signed-off-by: Greg Kroah-Hartman --- fs/ext4/orphan.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fs/ext4/orphan.c b/fs/ext4/orphan.c index 82d5e75014555..fb57bba0d19d1 100644 --- a/fs/ext4/orphan.c +++ b/fs/ext4/orphan.c @@ -8,6 +8,8 @@ #include "ext4.h" #include "ext4_jbd2.h" +#define EXT4_MAX_ORPHAN_FILE_BLOCKS 512 + static int ext4_orphan_file_add(handle_t *handle, struct inode *inode) { int i, j, start; @@ -588,7 +590,7 @@ int ext4_init_orphan_info(struct super_block *sb) * consuming absurd amounts of memory when pinning blocks of orphan * file in memory. */ - if (inode->i_size > 8 << 20) { + if (inode->i_size > (EXT4_MAX_ORPHAN_FILE_BLOCKS << inode->i_blkbits)) { ext4_msg(sb, KERN_ERR, "orphan file too big: %llu", (unsigned long long)inode->i_size); ret = -EFSCORRUPTED; From 4a9e50d881f5aac9ee01edc41abce9588982c0fc Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Wed, 22 Oct 2025 20:11:37 +0900 Subject: [PATCH 1268/2333] jbd2: use a per-journal lock_class_key for jbd2_trans_commit_key commit 524c3853831cf4f7e1db579e487c757c3065165c upstream. syzbot is reporting possibility of deadlock due to sharing lock_class_key for jbd2_handle across ext4 and ocfs2. But this is a false positive, for one disk partition can't have two filesystems at the same time. Reported-by: syzbot+6e493c165d26d6fcbf72@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=6e493c165d26d6fcbf72 Signed-off-by: Tetsuo Handa Tested-by: syzbot+6e493c165d26d6fcbf72@syzkaller.appspotmail.com Reviewed-by: Jan Kara Message-ID: <987110fc-5470-457a-a218-d286a09dd82f@I-love.SAKURA.ne.jp> Signed-off-by: Theodore Ts'o Cc: stable@kernel.org Signed-off-by: Greg Kroah-Hartman --- fs/jbd2/journal.c | 6 ++++-- include/linux/jbd2.h | 6 ++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c index bf255f8b5eebf..d02fc04e60d08 100644 --- a/fs/jbd2/journal.c +++ b/fs/jbd2/journal.c @@ -1521,7 +1521,6 @@ static journal_t *journal_init_common(struct block_device *bdev, struct block_device *fs_dev, unsigned long long start, int len, int blocksize) { - static struct lock_class_key jbd2_trans_commit_key; journal_t *journal; int err; int n; @@ -1530,6 +1529,7 @@ static journal_t *journal_init_common(struct block_device *bdev, if (!journal) return ERR_PTR(-ENOMEM); + lockdep_register_key(&journal->jbd2_trans_commit_key); journal->j_blocksize = blocksize; journal->j_dev = bdev; journal->j_fs_dev = fs_dev; @@ -1560,7 +1560,7 @@ static journal_t *journal_init_common(struct block_device *bdev, journal->j_max_batch_time = 15000; /* 15ms */ atomic_set(&journal->j_reserved_credits, 0); lockdep_init_map(&journal->j_trans_commit_map, "jbd2_handle", - &jbd2_trans_commit_key, 0); + &journal->jbd2_trans_commit_key, 0); /* The journal is marked for error until we succeed with recovery! */ journal->j_flags = JBD2_ABORT; @@ -1611,6 +1611,7 @@ static journal_t *journal_init_common(struct block_device *bdev, kfree(journal->j_wbuf); jbd2_journal_destroy_revoke(journal); journal_fail_superblock(journal); + lockdep_unregister_key(&journal->jbd2_trans_commit_key); kfree(journal); return ERR_PTR(err); } @@ -2187,6 +2188,7 @@ int jbd2_journal_destroy(journal_t *journal) jbd2_journal_destroy_revoke(journal); kfree(journal->j_fc_wbuf); kfree(journal->j_wbuf); + lockdep_unregister_key(&journal->jbd2_trans_commit_key); kfree(journal); return err; diff --git a/include/linux/jbd2.h b/include/linux/jbd2.h index 43b9297fe8a75..f5eaf76198f37 100644 --- a/include/linux/jbd2.h +++ b/include/linux/jbd2.h @@ -1253,6 +1253,12 @@ struct journal_s */ struct lockdep_map j_trans_commit_map; #endif + /** + * @jbd2_trans_commit_key: + * + * "struct lock_class_key" for @j_trans_commit_map + */ + struct lock_class_key jbd2_trans_commit_key; /** * @j_fc_cleanup_callback: From f0dba761b2824a82d13bf2fc605a86b157c825f7 Mon Sep 17 00:00:00 2001 From: Byungchul Park Date: Fri, 24 Oct 2025 16:39:40 +0900 Subject: [PATCH 1269/2333] jbd2: use a weaker annotation in journal handling commit 40a71b53d5a6d4ea17e4d54b99b2ac03a7f5e783 upstream. jbd2 journal handling code doesn't want jbd2_might_wait_for_commit() to be placed between start_this_handle() and stop_this_handle(). So it marks the region with rwsem_acquire_read() and rwsem_release(). However, the annotation is too strong for that purpose. We don't have to use more than try lock annotation for that. rwsem_acquire_read() implies: 1. might be a waiter on contention of the lock. 2. enter to the critical section of the lock. All we need in here is to act 2, not 1. So trylock version of annotation is sufficient for that purpose. Now that dept partially relies on lockdep annotaions, dept interpets rwsem_acquire_read() as a potential wait and might report a deadlock by the wait. Replace it with trylock version of annotation. Signed-off-by: Byungchul Park Reviewed-by: Jan Kara Cc: stable@kernel.org Message-ID: <20251024073940.1063-1-byungchul@sk.com> Signed-off-by: Theodore Ts'o Signed-off-by: Greg Kroah-Hartman --- fs/jbd2/transaction.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c index 9ce626ac947e3..653ee540c4a1b 100644 --- a/fs/jbd2/transaction.c +++ b/fs/jbd2/transaction.c @@ -441,7 +441,7 @@ static int start_this_handle(journal_t *journal, handle_t *handle, read_unlock(&journal->j_state_lock); current->journal_info = handle; - rwsem_acquire_read(&journal->j_trans_commit_map, 0, 0, _THIS_IP_); + rwsem_acquire_read(&journal->j_trans_commit_map, 0, 1, _THIS_IP_); jbd2_journal_free_transaction(new_transaction); /* * Ensure that no allocations done while the transaction is open are From 3997b3147c7b68b0308378fa95a766015f8ceb1c Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 14 Nov 2025 13:04:07 -0800 Subject: [PATCH 1270/2333] block: Remove queue freezing from several sysfs store callbacks commit 935a20d1bebf6236076785fac3ff81e3931834e9 upstream. Freezing the request queue from inside sysfs store callbacks may cause a deadlock in combination with the dm-multipath driver and the queue_if_no_path option. Additionally, freezing the request queue slows down system boot on systems where sysfs attributes are set synchronously. Fix this by removing the blk_mq_freeze_queue() / blk_mq_unfreeze_queue() calls from the store callbacks that do not strictly need these callbacks. Add the __data_racy annotation to request_queue.rq_timeout to suppress KCSAN data race reports about the rq_timeout reads. This patch may cause a small delay in applying the new settings. For all the attributes affected by this patch, I/O will complete correctly whether the old or the new value of the attribute is used. This patch affects the following sysfs attributes: * io_poll_delay * io_timeout * nomerges * read_ahead_kb * rq_affinity Here is an example of a deadlock triggered by running test srp/002 if this patch is not applied: task:multipathd Call Trace: __schedule+0x8c1/0x1bf0 schedule+0xdd/0x270 schedule_preempt_disabled+0x1c/0x30 __mutex_lock+0xb89/0x1650 mutex_lock_nested+0x1f/0x30 dm_table_set_restrictions+0x823/0xdf0 __bind+0x166/0x590 dm_swap_table+0x2a7/0x490 do_resume+0x1b1/0x610 dev_suspend+0x55/0x1a0 ctl_ioctl+0x3a5/0x7e0 dm_ctl_ioctl+0x12/0x20 __x64_sys_ioctl+0x127/0x1a0 x64_sys_call+0xe2b/0x17d0 do_syscall_64+0x96/0x3a0 entry_SYSCALL_64_after_hwframe+0x4b/0x53 task:(udev-worker) Call Trace: __schedule+0x8c1/0x1bf0 schedule+0xdd/0x270 blk_mq_freeze_queue_wait+0xf2/0x140 blk_mq_freeze_queue_nomemsave+0x23/0x30 queue_ra_store+0x14e/0x290 queue_attr_store+0x23e/0x2c0 sysfs_kf_write+0xde/0x140 kernfs_fop_write_iter+0x3b2/0x630 vfs_write+0x4fd/0x1390 ksys_write+0xfd/0x230 __x64_sys_write+0x76/0xc0 x64_sys_call+0x276/0x17d0 do_syscall_64+0x96/0x3a0 entry_SYSCALL_64_after_hwframe+0x4b/0x53 Cc: Christoph Hellwig Cc: Ming Lei Cc: Nilay Shroff Cc: Martin Wilck Cc: Benjamin Marzinski Cc: stable@vger.kernel.org Fixes: af2814149883 ("block: freeze the queue in queue_attr_store") Signed-off-by: Bart Van Assche Reviewed-by: Nilay Shroff Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman --- block/blk-sysfs.c | 26 ++++++++------------------ include/linux/blkdev.h | 2 +- 2 files changed, 9 insertions(+), 19 deletions(-) diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c index c0e4daaf96100..e0a70d26972b3 100644 --- a/block/blk-sysfs.c +++ b/block/blk-sysfs.c @@ -143,21 +143,22 @@ queue_ra_store(struct gendisk *disk, const char *page, size_t count) { unsigned long ra_kb; ssize_t ret; - unsigned int memflags; struct request_queue *q = disk->queue; ret = queue_var_store(&ra_kb, page, count); if (ret < 0) return ret; /* - * ->ra_pages is protected by ->limits_lock because it is usually - * calculated from the queue limits by queue_limits_commit_update. + * The ->ra_pages change below is protected by ->limits_lock because it + * is usually calculated from the queue limits by + * queue_limits_commit_update(). + * + * bdi->ra_pages reads are not serialized against bdi->ra_pages writes. + * Use WRITE_ONCE() to write bdi->ra_pages once. */ mutex_lock(&q->limits_lock); - memflags = blk_mq_freeze_queue(q); - disk->bdi->ra_pages = ra_kb >> (PAGE_SHIFT - 10); + WRITE_ONCE(disk->bdi->ra_pages, ra_kb >> (PAGE_SHIFT - 10)); mutex_unlock(&q->limits_lock); - blk_mq_unfreeze_queue(q, memflags); return ret; } @@ -375,21 +376,18 @@ static ssize_t queue_nomerges_store(struct gendisk *disk, const char *page, size_t count) { unsigned long nm; - unsigned int memflags; struct request_queue *q = disk->queue; ssize_t ret = queue_var_store(&nm, page, count); if (ret < 0) return ret; - memflags = blk_mq_freeze_queue(q); blk_queue_flag_clear(QUEUE_FLAG_NOMERGES, q); blk_queue_flag_clear(QUEUE_FLAG_NOXMERGES, q); if (nm == 2) blk_queue_flag_set(QUEUE_FLAG_NOMERGES, q); else if (nm) blk_queue_flag_set(QUEUE_FLAG_NOXMERGES, q); - blk_mq_unfreeze_queue(q, memflags); return ret; } @@ -409,7 +407,6 @@ queue_rq_affinity_store(struct gendisk *disk, const char *page, size_t count) #ifdef CONFIG_SMP struct request_queue *q = disk->queue; unsigned long val; - unsigned int memflags; ret = queue_var_store(&val, page, count); if (ret < 0) @@ -421,7 +418,6 @@ queue_rq_affinity_store(struct gendisk *disk, const char *page, size_t count) * are accessed individually using atomic test_bit operation. So we * don't grab any lock while updating these flags. */ - memflags = blk_mq_freeze_queue(q); if (val == 2) { blk_queue_flag_set(QUEUE_FLAG_SAME_COMP, q); blk_queue_flag_set(QUEUE_FLAG_SAME_FORCE, q); @@ -432,7 +428,6 @@ queue_rq_affinity_store(struct gendisk *disk, const char *page, size_t count) blk_queue_flag_clear(QUEUE_FLAG_SAME_COMP, q); blk_queue_flag_clear(QUEUE_FLAG_SAME_FORCE, q); } - blk_mq_unfreeze_queue(q, memflags); #endif return ret; } @@ -446,11 +441,9 @@ static ssize_t queue_poll_delay_store(struct gendisk *disk, const char *page, static ssize_t queue_poll_store(struct gendisk *disk, const char *page, size_t count) { - unsigned int memflags; ssize_t ret = count; struct request_queue *q = disk->queue; - memflags = blk_mq_freeze_queue(q); if (!(q->limits.features & BLK_FEAT_POLL)) { ret = -EINVAL; goto out; @@ -459,7 +452,6 @@ static ssize_t queue_poll_store(struct gendisk *disk, const char *page, pr_info_ratelimited("writes to the poll attribute are ignored.\n"); pr_info_ratelimited("please use driver specific parameters instead.\n"); out: - blk_mq_unfreeze_queue(q, memflags); return ret; } @@ -472,7 +464,7 @@ static ssize_t queue_io_timeout_show(struct gendisk *disk, char *page) static ssize_t queue_io_timeout_store(struct gendisk *disk, const char *page, size_t count) { - unsigned int val, memflags; + unsigned int val; int err; struct request_queue *q = disk->queue; @@ -480,9 +472,7 @@ static ssize_t queue_io_timeout_store(struct gendisk *disk, const char *page, if (err || val == 0) return -EINVAL; - memflags = blk_mq_freeze_queue(q); blk_queue_rq_timeout(q, msecs_to_jiffies(val)); - blk_mq_unfreeze_queue(q, memflags); return count; } diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 70b671a9a7f77..59e54550a053f 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -485,7 +485,7 @@ struct request_queue { */ unsigned long queue_flags; - unsigned int rq_timeout; + unsigned int __data_racy rq_timeout; unsigned int queue_depth; From 2c636fb02af2e80f36686e297c0f295c019937be Mon Sep 17 00:00:00 2001 From: xu xin Date: Tue, 7 Oct 2025 18:28:21 +0800 Subject: [PATCH 1271/2333] mm/ksm: fix exec/fork inheritance support for prctl commit 590c03ca6a3fbb114396673314e2aa483839608b upstream. Patch series "ksm: fix exec/fork inheritance", v2. This series fixes exec/fork inheritance. See the detailed description of the issue below. This patch (of 2): Background ========== commit d7597f59d1d33 ("mm: add new api to enable ksm per process") introduced MMF_VM_MERGE_ANY for mm->flags, and allowed user to set it by prctl() so that the process's VMAs are forcibly scanned by ksmd. Subsequently, the 3c6f33b7273a ("mm/ksm: support fork/exec for prctl") supported inheriting the MMF_VM_MERGE_ANY flag when a task calls execve(). Finally, commit 3a9e567ca45fb ("mm/ksm: fix ksm exec support for prctl") fixed the issue that ksmd doesn't scan the mm_struct with MMF_VM_MERGE_ANY by adding the mm_slot to ksm_mm_head in __bprm_mm_init(). Problem ======= In some extreme scenarios, however, this inheritance of MMF_VM_MERGE_ANY during exec/fork can fail. For example, when the scanning frequency of ksmd is tuned extremely high, a process carrying MMF_VM_MERGE_ANY may still fail to pass it to the newly exec'd process. This happens because ksm_execve() is executed too early in the do_execve flow (prematurely adding the new mm_struct to the ksm_mm_slot list). As a result, before do_execve completes, ksmd may have already performed a scan and found that this new mm_struct has no VM_MERGEABLE VMAs, thus clearing its MMF_VM_MERGE_ANY flag. Consequently, when the new program executes, the flag MMF_VM_MERGE_ANY inheritance missed. Root reason =========== commit d7597f59d1d33 ("mm: add new api to enable ksm per process") clear the flag MMF_VM_MERGE_ANY when ksmd found no VM_MERGEABLE VMAs. Solution ======== Firstly, Don't clear MMF_VM_MERGE_ANY when ksmd found no VM_MERGEABLE VMAs, because perhaps their mm_struct has just been added to ksm_mm_slot list, and its process has not yet officially started running or has not yet performed mmap/brk to allocate anonymous VMAS. Secondly, recheck MMF_VM_MERGEABLE again if a process takes MMF_VM_MERGE_ANY, and create a mm_slot and join it into ksm_scan_list again. Link: https://lkml.kernel.org/r/20251007182504440BJgK8VXRHh8TD7IGSUIY4@zte.com.cn Link: https://lkml.kernel.org/r/20251007182821572h_SoFqYZXEP1mvWI4n9VL@zte.com.cn Fixes: 3c6f33b7273a ("mm/ksm: support fork/exec for prctl") Fixes: d7597f59d1d3 ("mm: add new api to enable ksm per process") Signed-off-by: xu xin Cc: Stefan Roesch Cc: David Hildenbrand Cc: Jinjiang Tu Cc: Wang Yaxin Cc: Yang Yang Cc: Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- include/linux/ksm.h | 4 ++-- mm/ksm.c | 20 +++++++++++++++++--- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/include/linux/ksm.h b/include/linux/ksm.h index 067538fc4d585..c982694c987b9 100644 --- a/include/linux/ksm.h +++ b/include/linux/ksm.h @@ -17,7 +17,7 @@ #ifdef CONFIG_KSM int ksm_madvise(struct vm_area_struct *vma, unsigned long start, unsigned long end, int advice, vm_flags_t *vm_flags); -vm_flags_t ksm_vma_flags(const struct mm_struct *mm, const struct file *file, +vm_flags_t ksm_vma_flags(struct mm_struct *mm, const struct file *file, vm_flags_t vm_flags); int ksm_enable_merge_any(struct mm_struct *mm); int ksm_disable_merge_any(struct mm_struct *mm); @@ -103,7 +103,7 @@ bool ksm_process_mergeable(struct mm_struct *mm); #else /* !CONFIG_KSM */ -static inline vm_flags_t ksm_vma_flags(const struct mm_struct *mm, +static inline vm_flags_t ksm_vma_flags(struct mm_struct *mm, const struct file *file, vm_flags_t vm_flags) { return vm_flags; diff --git a/mm/ksm.c b/mm/ksm.c index c4e7304099499..ba97828f32903 100644 --- a/mm/ksm.c +++ b/mm/ksm.c @@ -2712,8 +2712,14 @@ static struct ksm_rmap_item *scan_get_next_rmap_item(struct page **page) spin_unlock(&ksm_mmlist_lock); mm_slot_free(mm_slot_cache, mm_slot); + /* + * Only clear MMF_VM_MERGEABLE. We must not clear + * MMF_VM_MERGE_ANY, because for those MMF_VM_MERGE_ANY process, + * perhaps their mm_struct has just been added to ksm_mm_slot + * list, and its process has not yet officially started running + * or has not yet performed mmap/brk to allocate anonymous VMAS. + */ mm_flags_clear(MMF_VM_MERGEABLE, mm); - mm_flags_clear(MMF_VM_MERGE_ANY, mm); mmap_read_unlock(mm); mmdrop(mm); } else { @@ -2831,12 +2837,20 @@ static int __ksm_del_vma(struct vm_area_struct *vma) * * Returns: @vm_flags possibly updated to mark mergeable. */ -vm_flags_t ksm_vma_flags(const struct mm_struct *mm, const struct file *file, +vm_flags_t ksm_vma_flags(struct mm_struct *mm, const struct file *file, vm_flags_t vm_flags) { if (mm_flags_test(MMF_VM_MERGE_ANY, mm) && - __ksm_should_add_vma(file, vm_flags)) + __ksm_should_add_vma(file, vm_flags)) { vm_flags |= VM_MERGEABLE; + /* + * Generally, the flags here always include MMF_VM_MERGEABLE. + * However, in rare cases, this flag may be cleared by ksmd who + * scans a cycle without finding any mergeable vma. + */ + if (unlikely(!mm_flags_test(MMF_VM_MERGEABLE, mm))) + __ksm_enter(mm); + } return vm_flags; } From d710b4a2c7130627f6ddfefab0ebd3740d96d1e4 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 8 Oct 2025 12:55:18 +0300 Subject: [PATCH 1272/2333] media: v4l2-mem2mem: Fix outdated documentation commit 082b86919b7a94de01d849021b4da820a6cb89dc upstream. Commit cbd9463da1b1 ("media: v4l2-mem2mem: Avoid calling .device_run in v4l2_m2m_job_finish") deferred calls to .device_run() to a work queue to avoid recursive calls when a job is finished right away from .device_run(). It failed to update the v4l2_m2m_job_finish() documentation that still states the function must not be called from .device_run(). Fix it. Fixes: cbd9463da1b1 ("media: v4l2-mem2mem: Avoid calling .device_run in v4l2_m2m_job_finish") Cc: stable@vger.kernel.org Signed-off-by: Laurent Pinchart Signed-off-by: Hans Verkuil Signed-off-by: Greg Kroah-Hartman --- include/media/v4l2-mem2mem.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/include/media/v4l2-mem2mem.h b/include/media/v4l2-mem2mem.h index 09c6164577ccf..500f81f399dfa 100644 --- a/include/media/v4l2-mem2mem.h +++ b/include/media/v4l2-mem2mem.h @@ -192,8 +192,7 @@ void v4l2_m2m_try_schedule(struct v4l2_m2m_ctx *m2m_ctx); * other instances to take control of the device. * * This function has to be called only after &v4l2_m2m_ops->device_run - * callback has been called on the driver. To prevent recursion, it should - * not be called directly from the &v4l2_m2m_ops->device_run callback though. + * callback has been called on the driver. */ void v4l2_m2m_job_finish(struct v4l2_m2m_dev *m2m_dev, struct v4l2_m2m_ctx *m2m_ctx); From cebbf5d16bb2bd86f90f32e6a912d7730ca0699a Mon Sep 17 00:00:00 2001 From: Wei Yang Date: Wed, 8 Oct 2025 09:54:52 +0000 Subject: [PATCH 1273/2333] mm/huge_memory: add pmd folio to ds_queue in do_huge_zero_wp_pmd() commit 2a1351cd4176ee1809b0900d386919d03b7652f8 upstream. We add pmd folio into ds_queue on the first page fault in __do_huge_pmd_anonymous_page(), so that we can split it in case of memory pressure. This should be the same for a pmd folio during wp page fault. Commit 1ced09e0331f ("mm: allocate THP on hugezeropage wp-fault") miss to add it to ds_queue, which means system may not reclaim enough memory in case of memory pressure even the pmd folio is under used. Move deferred_split_folio() into map_anon_folio_pmd() to make the pmd folio installation consistent. Link: https://lkml.kernel.org/r/20251008095453.18772-2-richard.weiyang@gmail.com Fixes: 1ced09e0331f ("mm: allocate THP on hugezeropage wp-fault") Signed-off-by: Wei Yang Acked-by: David Hildenbrand Reviewed-by: Lance Yang Reviewed-by: Dev Jain Acked-by: Usama Arif Reviewed-by: Zi Yan Reviewed-by: Baolin Wang Cc: Matthew Wilcox Cc: Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- mm/huge_memory.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/huge_memory.c b/mm/huge_memory.c index 6cba1cb14b23a..f66a4b15cb336 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -1233,6 +1233,7 @@ static void map_anon_folio_pmd(struct folio *folio, pmd_t *pmd, count_vm_event(THP_FAULT_ALLOC); count_mthp_stat(HPAGE_PMD_ORDER, MTHP_STAT_ANON_FAULT_ALLOC); count_memcg_event_mm(vma->vm_mm, THP_FAULT_ALLOC); + deferred_split_folio(folio, false); } static vm_fault_t __do_huge_pmd_anonymous_page(struct vm_fault *vmf) @@ -1273,7 +1274,6 @@ static vm_fault_t __do_huge_pmd_anonymous_page(struct vm_fault *vmf) pgtable_trans_huge_deposit(vma->vm_mm, vmf->pmd, pgtable); map_anon_folio_pmd(folio, vmf->pmd, vma, haddr); mm_inc_nr_ptes(vma->vm_mm); - deferred_split_folio(folio, false); spin_unlock(vmf->ptl); } From 04a3aa6e8c5f878cc51a8a1c90b6d3c54079bc43 Mon Sep 17 00:00:00 2001 From: Jarkko Sakkinen Date: Sun, 30 Nov 2025 21:07:12 +0200 Subject: [PATCH 1274/2333] tpm2-sessions: Fix out of range indexing in name_size commit 6e9722e9a7bfe1bbad649937c811076acf86e1fd upstream. 'name_size' does not have any range checks, and it just directly indexes with TPM_ALG_ID, which could lead into memory corruption at worst. Address the issue by only processing known values and returning -EINVAL for unrecognized values. Make also 'tpm_buf_append_name' and 'tpm_buf_fill_hmac_session' fallible so that errors are detected before causing any spurious TPM traffic. End also the authorization session on failure in both of the functions, as the session state would be then by definition corrupted. Cc: stable@vger.kernel.org # v6.10+ Fixes: 1085b8276bb4 ("tpm: Add the rest of the session HMAC API") Reviewed-by: Jonathan McDowell Signed-off-by: Jarkko Sakkinen Signed-off-by: Greg Kroah-Hartman --- drivers/char/tpm/tpm2-cmd.c | 23 +++- drivers/char/tpm/tpm2-sessions.c | 132 +++++++++++++++------- include/linux/tpm.h | 13 ++- security/keys/trusted-keys/trusted_tpm2.c | 29 ++++- 4 files changed, 142 insertions(+), 55 deletions(-) diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c index 5b6ccf901623c..4473b81122e87 100644 --- a/drivers/char/tpm/tpm2-cmd.c +++ b/drivers/char/tpm/tpm2-cmd.c @@ -187,7 +187,11 @@ int tpm2_pcr_extend(struct tpm_chip *chip, u32 pcr_idx, } if (!disable_pcr_integrity) { - tpm_buf_append_name(chip, &buf, pcr_idx, NULL); + rc = tpm_buf_append_name(chip, &buf, pcr_idx, NULL); + if (rc) { + tpm_buf_destroy(&buf); + return rc; + } tpm_buf_append_hmac_session(chip, &buf, 0, NULL, 0); } else { tpm_buf_append_handle(chip, &buf, pcr_idx); @@ -202,8 +206,14 @@ int tpm2_pcr_extend(struct tpm_chip *chip, u32 pcr_idx, chip->allocated_banks[i].digest_size); } - if (!disable_pcr_integrity) - tpm_buf_fill_hmac_session(chip, &buf); + if (!disable_pcr_integrity) { + rc = tpm_buf_fill_hmac_session(chip, &buf); + if (rc) { + tpm_buf_destroy(&buf); + return rc; + } + } + rc = tpm_transmit_cmd(chip, &buf, 0, "attempting extend a PCR value"); if (!disable_pcr_integrity) rc = tpm_buf_check_hmac_response(chip, &buf, rc); @@ -261,7 +271,12 @@ int tpm2_get_random(struct tpm_chip *chip, u8 *dest, size_t max) | TPM2_SA_CONTINUE_SESSION, NULL, 0); tpm_buf_append_u16(&buf, num_bytes); - tpm_buf_fill_hmac_session(chip, &buf); + err = tpm_buf_fill_hmac_session(chip, &buf); + if (err) { + tpm_buf_destroy(&buf); + return err; + } + err = tpm_transmit_cmd(chip, &buf, offsetof(struct tpm2_get_random_out, buffer), diff --git a/drivers/char/tpm/tpm2-sessions.c b/drivers/char/tpm/tpm2-sessions.c index 6d03c224e6b21..385014dbca39d 100644 --- a/drivers/char/tpm/tpm2-sessions.c +++ b/drivers/char/tpm/tpm2-sessions.c @@ -144,16 +144,23 @@ struct tpm2_auth { /* * Name Size based on TPM algorithm (assumes no hash bigger than 255) */ -static u8 name_size(const u8 *name) +static int name_size(const u8 *name) { - static u8 size_map[] = { - [TPM_ALG_SHA1] = SHA1_DIGEST_SIZE, - [TPM_ALG_SHA256] = SHA256_DIGEST_SIZE, - [TPM_ALG_SHA384] = SHA384_DIGEST_SIZE, - [TPM_ALG_SHA512] = SHA512_DIGEST_SIZE, - }; - u16 alg = get_unaligned_be16(name); - return size_map[alg] + 2; + u16 hash_alg = get_unaligned_be16(name); + + switch (hash_alg) { + case TPM_ALG_SHA1: + return SHA1_DIGEST_SIZE + 2; + case TPM_ALG_SHA256: + return SHA256_DIGEST_SIZE + 2; + case TPM_ALG_SHA384: + return SHA384_DIGEST_SIZE + 2; + case TPM_ALG_SHA512: + return SHA512_DIGEST_SIZE + 2; + default: + pr_warn("tpm: unsupported name algorithm: 0x%04x\n", hash_alg); + return -EINVAL; + } } static int tpm2_parse_read_public(char *name, struct tpm_buf *buf) @@ -161,6 +168,7 @@ static int tpm2_parse_read_public(char *name, struct tpm_buf *buf) struct tpm_header *head = (struct tpm_header *)buf->data; off_t offset = TPM_HEADER_SIZE; u32 tot_len = be32_to_cpu(head->length); + int ret; u32 val; /* we're starting after the header so adjust the length */ @@ -173,8 +181,13 @@ static int tpm2_parse_read_public(char *name, struct tpm_buf *buf) offset += val; /* name */ val = tpm_buf_read_u16(buf, &offset); - if (val != name_size(&buf->data[offset])) + ret = name_size(&buf->data[offset]); + if (ret < 0) + return ret; + + if (val != ret) return -EINVAL; + memcpy(name, &buf->data[offset], val); /* forget the rest */ return 0; @@ -221,46 +234,72 @@ static int tpm2_read_public(struct tpm_chip *chip, u32 handle, char *name) * As with most tpm_buf operations, success is assumed because failure * will be caused by an incorrect programming model and indicated by a * kernel message. + * + * Ends the authorization session on failure. */ -void tpm_buf_append_name(struct tpm_chip *chip, struct tpm_buf *buf, - u32 handle, u8 *name) +int tpm_buf_append_name(struct tpm_chip *chip, struct tpm_buf *buf, + u32 handle, u8 *name) { #ifdef CONFIG_TCG_TPM2_HMAC enum tpm2_mso_type mso = tpm2_handle_mso(handle); struct tpm2_auth *auth; int slot; + int ret; #endif if (!tpm2_chip_auth(chip)) { tpm_buf_append_handle(chip, buf, handle); - return; + return 0; } #ifdef CONFIG_TCG_TPM2_HMAC slot = (tpm_buf_length(buf) - TPM_HEADER_SIZE) / 4; if (slot >= AUTH_MAX_NAMES) { - dev_err(&chip->dev, "TPM: too many handles\n"); - return; + dev_err(&chip->dev, "too many handles\n"); + ret = -EIO; + goto err; } auth = chip->auth; - WARN(auth->session != tpm_buf_length(buf), - "name added in wrong place\n"); + if (auth->session != tpm_buf_length(buf)) { + dev_err(&chip->dev, "session state malformed"); + ret = -EIO; + goto err; + } tpm_buf_append_u32(buf, handle); auth->session += 4; if (mso == TPM2_MSO_PERSISTENT || mso == TPM2_MSO_VOLATILE || mso == TPM2_MSO_NVRAM) { - if (!name) - tpm2_read_public(chip, handle, auth->name[slot]); + if (!name) { + ret = tpm2_read_public(chip, handle, auth->name[slot]); + if (ret) + goto err; + } } else { - if (name) - dev_err(&chip->dev, "TPM: Handle does not require name but one is specified\n"); + if (name) { + dev_err(&chip->dev, "handle 0x%08x does not use a name\n", + handle); + ret = -EIO; + goto err; + } } auth->name_h[slot] = handle; - if (name) - memcpy(auth->name[slot], name, name_size(name)); + if (name) { + ret = name_size(name); + if (ret < 0) + goto err; + + memcpy(auth->name[slot], name, ret); + } +#endif + return 0; + +#ifdef CONFIG_TCG_TPM2_HMAC +err: + tpm2_end_auth_session(chip); + return tpm_ret_to_err(ret); #endif } EXPORT_SYMBOL_GPL(tpm_buf_append_name); @@ -533,11 +572,9 @@ static void tpm_buf_append_salt(struct tpm_buf *buf, struct tpm_chip *chip, * encryption key and encrypts the first parameter of the command * buffer with it. * - * As with most tpm_buf operations, success is assumed because failure - * will be caused by an incorrect programming model and indicated by a - * kernel message. + * Ends the authorization session on failure. */ -void tpm_buf_fill_hmac_session(struct tpm_chip *chip, struct tpm_buf *buf) +int tpm_buf_fill_hmac_session(struct tpm_chip *chip, struct tpm_buf *buf) { u32 cc, handles, val; struct tpm2_auth *auth = chip->auth; @@ -549,9 +586,12 @@ void tpm_buf_fill_hmac_session(struct tpm_chip *chip, struct tpm_buf *buf) u8 cphash[SHA256_DIGEST_SIZE]; struct sha256_ctx sctx; struct hmac_sha256_ctx hctx; + int ret; - if (!auth) - return; + if (!auth) { + ret = -EIO; + goto err; + } /* save the command code in BE format */ auth->ordinal = head->ordinal; @@ -560,9 +600,11 @@ void tpm_buf_fill_hmac_session(struct tpm_chip *chip, struct tpm_buf *buf) i = tpm2_find_cc(chip, cc); if (i < 0) { - dev_err(&chip->dev, "Command 0x%x not found in TPM\n", cc); - return; + dev_err(&chip->dev, "command 0x%08x not found\n", cc); + ret = -EIO; + goto err; } + attrs = chip->cc_attrs_tbl[i]; handles = (attrs >> TPM2_CC_ATTR_CHANDLES) & GENMASK(2, 0); @@ -576,9 +618,9 @@ void tpm_buf_fill_hmac_session(struct tpm_chip *chip, struct tpm_buf *buf) u32 handle = tpm_buf_read_u32(buf, &offset_s); if (auth->name_h[i] != handle) { - dev_err(&chip->dev, "TPM: handle %d wrong for name\n", - i); - return; + dev_err(&chip->dev, "invalid handle 0x%08x\n", handle); + ret = -EIO; + goto err; } } /* point offset_s to the start of the sessions */ @@ -609,12 +651,14 @@ void tpm_buf_fill_hmac_session(struct tpm_chip *chip, struct tpm_buf *buf) offset_s += len; } if (offset_s != offset_p) { - dev_err(&chip->dev, "TPM session length is incorrect\n"); - return; + dev_err(&chip->dev, "session length is incorrect\n"); + ret = -EIO; + goto err; } if (!hmac) { - dev_err(&chip->dev, "TPM could not find HMAC session\n"); - return; + dev_err(&chip->dev, "could not find HMAC session\n"); + ret = -EIO; + goto err; } /* encrypt before HMAC */ @@ -646,8 +690,11 @@ void tpm_buf_fill_hmac_session(struct tpm_chip *chip, struct tpm_buf *buf) if (mso == TPM2_MSO_PERSISTENT || mso == TPM2_MSO_VOLATILE || mso == TPM2_MSO_NVRAM) { - sha256_update(&sctx, auth->name[i], - name_size(auth->name[i])); + ret = name_size(auth->name[i]); + if (ret < 0) + goto err; + + sha256_update(&sctx, auth->name[i], ret); } else { __be32 h = cpu_to_be32(auth->name_h[i]); @@ -668,6 +715,11 @@ void tpm_buf_fill_hmac_session(struct tpm_chip *chip, struct tpm_buf *buf) hmac_sha256_update(&hctx, auth->tpm_nonce, sizeof(auth->tpm_nonce)); hmac_sha256_update(&hctx, &auth->attrs, 1); hmac_sha256_final(&hctx, hmac); + return 0; + +err: + tpm2_end_auth_session(chip); + return ret; } EXPORT_SYMBOL(tpm_buf_fill_hmac_session); diff --git a/include/linux/tpm.h b/include/linux/tpm.h index eb0ff071bcaed..5d5c926a71119 100644 --- a/include/linux/tpm.h +++ b/include/linux/tpm.h @@ -526,8 +526,8 @@ static inline struct tpm2_auth *tpm2_chip_auth(struct tpm_chip *chip) #endif } -void tpm_buf_append_name(struct tpm_chip *chip, struct tpm_buf *buf, - u32 handle, u8 *name); +int tpm_buf_append_name(struct tpm_chip *chip, struct tpm_buf *buf, + u32 handle, u8 *name); void tpm_buf_append_hmac_session(struct tpm_chip *chip, struct tpm_buf *buf, u8 attributes, u8 *passphrase, int passphraselen); @@ -560,7 +560,7 @@ static inline void tpm_buf_append_hmac_session_opt(struct tpm_chip *chip, #ifdef CONFIG_TCG_TPM2_HMAC int tpm2_start_auth_session(struct tpm_chip *chip); -void tpm_buf_fill_hmac_session(struct tpm_chip *chip, struct tpm_buf *buf); +int tpm_buf_fill_hmac_session(struct tpm_chip *chip, struct tpm_buf *buf); int tpm_buf_check_hmac_response(struct tpm_chip *chip, struct tpm_buf *buf, int rc); void tpm2_end_auth_session(struct tpm_chip *chip); @@ -574,10 +574,13 @@ static inline int tpm2_start_auth_session(struct tpm_chip *chip) static inline void tpm2_end_auth_session(struct tpm_chip *chip) { } -static inline void tpm_buf_fill_hmac_session(struct tpm_chip *chip, - struct tpm_buf *buf) + +static inline int tpm_buf_fill_hmac_session(struct tpm_chip *chip, + struct tpm_buf *buf) { + return 0; } + static inline int tpm_buf_check_hmac_response(struct tpm_chip *chip, struct tpm_buf *buf, int rc) diff --git a/security/keys/trusted-keys/trusted_tpm2.c b/security/keys/trusted-keys/trusted_tpm2.c index 76a86f8a8d6c8..7187768716b78 100644 --- a/security/keys/trusted-keys/trusted_tpm2.c +++ b/security/keys/trusted-keys/trusted_tpm2.c @@ -283,7 +283,10 @@ int tpm2_seal_trusted(struct tpm_chip *chip, goto out_put; } - tpm_buf_append_name(chip, &buf, options->keyhandle, NULL); + rc = tpm_buf_append_name(chip, &buf, options->keyhandle, NULL); + if (rc) + goto out; + tpm_buf_append_hmac_session(chip, &buf, TPM2_SA_DECRYPT, options->keyauth, TPM_DIGEST_SIZE); @@ -331,7 +334,10 @@ int tpm2_seal_trusted(struct tpm_chip *chip, goto out; } - tpm_buf_fill_hmac_session(chip, &buf); + rc = tpm_buf_fill_hmac_session(chip, &buf); + if (rc) + goto out; + rc = tpm_transmit_cmd(chip, &buf, 4, "sealing data"); rc = tpm_buf_check_hmac_response(chip, &buf, rc); if (rc) @@ -448,7 +454,10 @@ static int tpm2_load_cmd(struct tpm_chip *chip, return rc; } - tpm_buf_append_name(chip, &buf, options->keyhandle, NULL); + rc = tpm_buf_append_name(chip, &buf, options->keyhandle, NULL); + if (rc) + goto out; + tpm_buf_append_hmac_session(chip, &buf, 0, options->keyauth, TPM_DIGEST_SIZE); @@ -460,7 +469,10 @@ static int tpm2_load_cmd(struct tpm_chip *chip, goto out; } - tpm_buf_fill_hmac_session(chip, &buf); + rc = tpm_buf_fill_hmac_session(chip, &buf); + if (rc) + goto out; + rc = tpm_transmit_cmd(chip, &buf, 4, "loading blob"); rc = tpm_buf_check_hmac_response(chip, &buf, rc); if (!rc) @@ -508,7 +520,9 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip, return rc; } - tpm_buf_append_name(chip, &buf, blob_handle, NULL); + rc = tpm_buf_append_name(chip, &buf, options->keyhandle, NULL); + if (rc) + goto out; if (!options->policyhandle) { tpm_buf_append_hmac_session(chip, &buf, TPM2_SA_ENCRYPT, @@ -533,7 +547,10 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip, NULL, 0); } - tpm_buf_fill_hmac_session(chip, &buf); + rc = tpm_buf_fill_hmac_session(chip, &buf); + if (rc) + goto out; + rc = tpm_transmit_cmd(chip, &buf, 6, "unsealing"); rc = tpm_buf_check_hmac_response(chip, &buf, rc); if (rc > 0) From 20eda7c74b69fe9e1caf9b930a5c016bf8d755fa Mon Sep 17 00:00:00 2001 From: Jarkko Sakkinen Date: Mon, 1 Dec 2025 15:38:02 +0200 Subject: [PATCH 1275/2333] tpm2-sessions: Fix tpm2_read_public range checks commit bda1cbf73c6e241267c286427f2ed52b5735d872 upstream. tpm2_read_public() has some rudimentary range checks but the function does not ensure that the response buffer has enough bytes for the full TPMT_HA payload. Re-implement the function with necessary checks and validation, and return name and name size for all handle types back to the caller. Cc: stable@vger.kernel.org # v6.10+ Fixes: d0a25bb961e6 ("tpm: Add HMAC session name/handle append") Signed-off-by: Jarkko Sakkinen Reviewed-by: Jonathan McDowell Signed-off-by: Greg Kroah-Hartman --- drivers/char/tpm/tpm2-cmd.c | 3 + drivers/char/tpm/tpm2-sessions.c | 94 +++++++++++++++++--------------- 2 files changed, 53 insertions(+), 44 deletions(-) diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c index 4473b81122e87..58a8477cda851 100644 --- a/drivers/char/tpm/tpm2-cmd.c +++ b/drivers/char/tpm/tpm2-cmd.c @@ -11,8 +11,11 @@ * used by the kernel internally. */ +#include "linux/dev_printk.h" +#include "linux/tpm.h" #include "tpm.h" #include +#include static bool disable_pcr_integrity; module_param(disable_pcr_integrity, bool, 0444); diff --git a/drivers/char/tpm/tpm2-sessions.c b/drivers/char/tpm/tpm2-sessions.c index 385014dbca39d..3f389e2f6f580 100644 --- a/drivers/char/tpm/tpm2-sessions.c +++ b/drivers/char/tpm/tpm2-sessions.c @@ -163,53 +163,61 @@ static int name_size(const u8 *name) } } -static int tpm2_parse_read_public(char *name, struct tpm_buf *buf) +static int tpm2_read_public(struct tpm_chip *chip, u32 handle, void *name) { - struct tpm_header *head = (struct tpm_header *)buf->data; + u32 mso = tpm2_handle_mso(handle); off_t offset = TPM_HEADER_SIZE; - u32 tot_len = be32_to_cpu(head->length); - int ret; - u32 val; - - /* we're starting after the header so adjust the length */ - tot_len -= TPM_HEADER_SIZE; - - /* skip public */ - val = tpm_buf_read_u16(buf, &offset); - if (val > tot_len) - return -EINVAL; - offset += val; - /* name */ - val = tpm_buf_read_u16(buf, &offset); - ret = name_size(&buf->data[offset]); - if (ret < 0) - return ret; - - if (val != ret) - return -EINVAL; - - memcpy(name, &buf->data[offset], val); - /* forget the rest */ - return 0; -} - -static int tpm2_read_public(struct tpm_chip *chip, u32 handle, char *name) -{ + int rc, name_size_alg; struct tpm_buf buf; - int rc; + + if (mso != TPM2_MSO_PERSISTENT && mso != TPM2_MSO_VOLATILE && + mso != TPM2_MSO_NVRAM) { + memcpy(name, &handle, sizeof(u32)); + return sizeof(u32); + } rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_READ_PUBLIC); if (rc) return rc; tpm_buf_append_u32(&buf, handle); - rc = tpm_transmit_cmd(chip, &buf, 0, "read public"); - if (rc == TPM2_RC_SUCCESS) - rc = tpm2_parse_read_public(name, &buf); - tpm_buf_destroy(&buf); + rc = tpm_transmit_cmd(chip, &buf, 0, "TPM2_ReadPublic"); + if (rc) { + tpm_buf_destroy(&buf); + return tpm_ret_to_err(rc); + } - return rc; + /* Skip TPMT_PUBLIC: */ + offset += tpm_buf_read_u16(&buf, &offset); + + /* + * Ensure space for the length field of TPM2B_NAME and hashAlg field of + * TPMT_HA (the extra four bytes). + */ + if (offset + 4 > tpm_buf_length(&buf)) { + tpm_buf_destroy(&buf); + return -EIO; + } + + rc = tpm_buf_read_u16(&buf, &offset); + name_size_alg = name_size(&buf.data[offset]); + + if (name_size_alg < 0) + return name_size_alg; + + if (rc != name_size_alg) { + tpm_buf_destroy(&buf); + return -EIO; + } + + if (offset + rc > tpm_buf_length(&buf)) { + tpm_buf_destroy(&buf); + return -EIO; + } + + memcpy(name, &buf.data[offset], rc); + return name_size_alg; } #endif /* CONFIG_TCG_TPM2_HMAC */ @@ -243,6 +251,7 @@ int tpm_buf_append_name(struct tpm_chip *chip, struct tpm_buf *buf, #ifdef CONFIG_TCG_TPM2_HMAC enum tpm2_mso_type mso = tpm2_handle_mso(handle); struct tpm2_auth *auth; + u16 name_size_alg; int slot; int ret; #endif @@ -273,8 +282,10 @@ int tpm_buf_append_name(struct tpm_chip *chip, struct tpm_buf *buf, mso == TPM2_MSO_NVRAM) { if (!name) { ret = tpm2_read_public(chip, handle, auth->name[slot]); - if (ret) + if (ret < 0) goto err; + + name_size_alg = ret; } } else { if (name) { @@ -286,13 +297,8 @@ int tpm_buf_append_name(struct tpm_chip *chip, struct tpm_buf *buf, } auth->name_h[slot] = handle; - if (name) { - ret = name_size(name); - if (ret < 0) - goto err; - - memcpy(auth->name[slot], name, ret); - } + if (name) + memcpy(auth->name[slot], name, name_size_alg); #endif return 0; From d519d23a6b1c2306571f19f7d8e39bceee681e3c Mon Sep 17 00:00:00 2001 From: Sourabh Jain Date: Thu, 16 Oct 2025 19:58:31 +0530 Subject: [PATCH 1276/2333] crash: let architecture decide crash memory export to iomem_resource commit adc15829fb73e402903b7030729263b6ee4a7232 upstream. With the generic crashkernel reservation, the kernel emits the following warning on powerpc: WARNING: CPU: 0 PID: 1 at arch/powerpc/mm/mem.c:341 add_system_ram_resources+0xfc/0x180 Modules linked in: CPU: 0 UID: 0 PID: 1 Comm: swapper/0 Not tainted 6.17.0-auto-12607-g5472d60c129f #1 VOLUNTARY Hardware name: IBM,9080-HEX Power11 (architected) 0x820200 0xf000007 of:IBM,FW1110.01 (NH1110_069) hv:phyp pSeries NIP: c00000000201de3c LR: c00000000201de34 CTR: 0000000000000000 REGS: c000000127cef8a0 TRAP: 0700 Not tainted (6.17.0-auto-12607-g5472d60c129f) MSR: 8000000002029033 CR: 84000840 XER: 20040010 CFAR: c00000000017eed0 IRQMASK: 0 GPR00: c00000000201de34 c000000127cefb40 c0000000016a8100 0000000000000001 GPR04: c00000012005aa00 0000000020000000 c000000002b705c8 0000000000000000 GPR08: 000000007fffffff fffffffffffffff0 c000000002db8100 000000011fffffff GPR12: c00000000201dd40 c000000002ff0000 c0000000000112bc 0000000000000000 GPR16: 0000000000000000 0000000000000000 0000000000000000 0000000000000000 GPR20: 0000000000000000 0000000000000000 0000000000000000 c0000000015a3808 GPR24: c00000000200468c c000000001699888 0000000000000106 c0000000020d1950 GPR28: c0000000014683f8 0000000081000200 c0000000015c1868 c000000002b9f710 NIP [c00000000201de3c] add_system_ram_resources+0xfc/0x180 LR [c00000000201de34] add_system_ram_resources+0xf4/0x180 Call Trace: add_system_ram_resources+0xf4/0x180 (unreliable) do_one_initcall+0x60/0x36c do_initcalls+0x120/0x220 kernel_init_freeable+0x23c/0x390 kernel_init+0x34/0x26c ret_from_kernel_user_thread+0x14/0x1c This warning occurs due to a conflict between crashkernel and System RAM iomem resources. The generic crashkernel reservation adds the crashkernel memory range to /proc/iomem during early initialization. Later, all memblock ranges are added to /proc/iomem as System RAM. If the crashkernel region overlaps with any memblock range, it causes a conflict while adding those memblock regions as iomem resources, triggering the above warning. The conflicting memblock regions are then omitted from /proc/iomem. For example, if the following crashkernel region is added to /proc/iomem: 20000000-11fffffff : Crash kernel then the following memblock regions System RAM regions fail to be inserted: 00000000-7fffffff : System RAM 80000000-257fffffff : System RAM Fix this by not adding the crashkernel memory to /proc/iomem on powerpc. Introduce an architecture hook to let each architecture decide whether to export the crashkernel region to /proc/iomem. For more info checkout commit c40dd2f766440 ("powerpc: Add System RAM to /proc/iomem") and commit bce074bdbc36 ("powerpc: insert System RAM resource to prevent crashkernel conflict") Note: Before switching to the generic crashkernel reservation, powerpc never exported the crashkernel region to /proc/iomem. Link: https://lkml.kernel.org/r/20251016142831.144515-1-sourabhjain@linux.ibm.com Fixes: e3185ee438c2 ("powerpc/crash: use generic crashkernel reservation"). Signed-off-by: Sourabh Jain Reported-by: Venkat Rao Bagalkote Closes: https://lore.kernel.org/all/90937fe0-2e76-4c82-b27e-7b8a7fe3ac69@linux.ibm.com/ Tested-by: Venkat Rao Bagalkote Cc: Baoquan he Cc: Hari Bathini Cc: Madhavan Srinivasan Cc: Mahesh Salgaonkar Cc: Michael Ellerman Cc: Ritesh Harjani (IBM) Cc: Vivek Goyal Cc: Dave Young Cc: Mike Rapoport Cc: Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/include/asm/crash_reserve.h | 8 ++++++++ include/linux/crash_reserve.h | 6 ++++++ kernel/crash_reserve.c | 3 +++ 3 files changed, 17 insertions(+) diff --git a/arch/powerpc/include/asm/crash_reserve.h b/arch/powerpc/include/asm/crash_reserve.h index 6467ce29b1fab..d1b570ddbf98b 100644 --- a/arch/powerpc/include/asm/crash_reserve.h +++ b/arch/powerpc/include/asm/crash_reserve.h @@ -5,4 +5,12 @@ /* crash kernel regions are Page size agliged */ #define CRASH_ALIGN PAGE_SIZE +#ifdef CONFIG_ARCH_HAS_GENERIC_CRASHKERNEL_RESERVATION +static inline bool arch_add_crash_res_to_iomem(void) +{ + return false; +} +#define arch_add_crash_res_to_iomem arch_add_crash_res_to_iomem +#endif + #endif /* _ASM_POWERPC_CRASH_RESERVE_H */ diff --git a/include/linux/crash_reserve.h b/include/linux/crash_reserve.h index 7b44b41d0a20d..f0dc03d94ca2c 100644 --- a/include/linux/crash_reserve.h +++ b/include/linux/crash_reserve.h @@ -32,6 +32,12 @@ int __init parse_crashkernel(char *cmdline, unsigned long long system_ram, void __init reserve_crashkernel_cma(unsigned long long cma_size); #ifdef CONFIG_ARCH_HAS_GENERIC_CRASHKERNEL_RESERVATION +#ifndef arch_add_crash_res_to_iomem +static inline bool arch_add_crash_res_to_iomem(void) +{ + return true; +} +#endif #ifndef DEFAULT_CRASH_KERNEL_LOW_SIZE #define DEFAULT_CRASH_KERNEL_LOW_SIZE (128UL << 20) #endif diff --git a/kernel/crash_reserve.c b/kernel/crash_reserve.c index 87bf4d41eabba..62e60e0223cff 100644 --- a/kernel/crash_reserve.c +++ b/kernel/crash_reserve.c @@ -524,6 +524,9 @@ void __init reserve_crashkernel_cma(unsigned long long cma_size) #ifndef HAVE_ARCH_ADD_CRASH_RES_TO_IOMEM_EARLY static __init int insert_crashkernel_resources(void) { + if (!arch_add_crash_res_to_iomem()) + return 0; + if (crashk_res.start < crashk_res.end) insert_resource(&iomem_resource, &crashk_res); From 2766fae7c4c6741e2e4bb01ed485347d84df7f6d Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 7 Dec 2025 19:47:56 +0100 Subject: [PATCH 1277/2333] dma-mapping: Fix DMA_BIT_MASK() macro being broken commit 31b931bebd11a0f00967114f62c8c38952f483e5 upstream. After commit a50f7456f853 ("dma-mapping: Allow use of DMA_BIT_MASK(64) in global scope"), the DMA_BIT_MASK() macro is broken when passed non trivial statements for the value of 'n'. This is caused by the new version missing parenthesis around 'n' when evaluating 'n'. One example of this breakage is the IPU6 driver now crashing due to it getting DMA-addresses with address bit 32 set even though it has tried to set a 32 bit DMA mask. The IPU6 CSI2 engine has a DMA mask of either 31 or 32 bits depending on if it is in secure mode or not and it sets this masks like this: mmu_info->aperture_end = (dma_addr_t)DMA_BIT_MASK(isp->secure_mode ? IPU6_MMU_ADDR_BITS : IPU6_MMU_ADDR_BITS_NON_SECURE); So the 'n' argument here is "isp->secure_mode ? IPU6_MMU_ADDR_BITS : IPU6_MMU_ADDR_BITS_NON_SECURE" which gets expanded into: isp->secure_mode ? IPU6_MMU_ADDR_BITS : IPU6_MMU_ADDR_BITS_NON_SECURE - 1 With the -1 only being applied in the non secure case, causing the secure mode mask to be one 1 bit too large. Fixes: a50f7456f853 ("dma-mapping: Allow use of DMA_BIT_MASK(64) in global scope") Cc: Sakari Ailus Cc: James Clark Cc: Nathan Chancellor Cc: stable@vger.kernel.org Signed-off-by: Hans de Goede Reviewed-by: Nathan Chancellor Signed-off-by: Marek Szyprowski Link: https://lore.kernel.org/r/20251207184756.97904-1-johannes.goede@oss.qualcomm.com Signed-off-by: Greg Kroah-Hartman --- include/linux/dma-mapping.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h index 2ceda49c609fb..aa36a0d1d9df6 100644 --- a/include/linux/dma-mapping.h +++ b/include/linux/dma-mapping.h @@ -90,7 +90,7 @@ */ #define DMA_MAPPING_ERROR (~(dma_addr_t)0) -#define DMA_BIT_MASK(n) GENMASK_ULL(n - 1, 0) +#define DMA_BIT_MASK(n) GENMASK_ULL((n) - 1, 0) struct dma_iova_state { dma_addr_t addr; From 344789964c6ca16a28b6ff493152c94eb01c0601 Mon Sep 17 00:00:00 2001 From: Harry Yoo Date: Mon, 8 Dec 2025 00:41:47 +0900 Subject: [PATCH 1278/2333] mm/slab: introduce kvfree_rcu_barrier_on_cache() for cache destruction commit 0f35040de59371ad542b915d7b91176c9910dadc upstream. Currently, kvfree_rcu_barrier() flushes RCU sheaves across all slab caches when a cache is destroyed. This is unnecessary; only the RCU sheaves belonging to the cache being destroyed need to be flushed. As suggested by Vlastimil Babka, introduce a weaker form of kvfree_rcu_barrier() that operates on a specific slab cache. Factor out flush_rcu_sheaves_on_cache() from flush_all_rcu_sheaves() and call it from flush_all_rcu_sheaves() and kvfree_rcu_barrier_on_cache(). Call kvfree_rcu_barrier_on_cache() instead of kvfree_rcu_barrier() on cache destruction. The performance benefit is evaluated on a 12 core 24 threads AMD Ryzen 5900X machine (1 socket), by loading slub_kunit module. Before: Total calls: 19 Average latency (us): 18127 Total time (us): 344414 After: Total calls: 19 Average latency (us): 10066 Total time (us): 191264 Two performance regression have been reported: - stress module loader test's runtime increases by 50-60% (Daniel) - internal graphics test's runtime on Tegra234 increases by 35% (Jon) They are fixed by this change. Suggested-by: Vlastimil Babka Fixes: ec66e0d59952 ("slab: add sheaf support for batching kfree_rcu() operations") Cc: stable@vger.kernel.org Link: https://lore.kernel.org/linux-mm/1bda09da-93be-4737-aef0-d47f8c5c9301@suse.cz Reported-and-tested-by: Daniel Gomez Closes: https://lore.kernel.org/linux-mm/0406562e-2066-4cf8-9902-b2b0616dd742@kernel.org Reported-and-tested-by: Jon Hunter Closes: https://lore.kernel.org/linux-mm/e988eff6-1287-425e-a06c-805af5bbf262@nvidia.com Signed-off-by: Harry Yoo Link: https://patch.msgid.link/20251207154148.117723-1-harry.yoo@oracle.com Signed-off-by: Vlastimil Babka Signed-off-by: Greg Kroah-Hartman --- include/linux/slab.h | 7 ++++++ mm/slab.h | 1 + mm/slab_common.c | 52 +++++++++++++++++++++++++++++------------ mm/slub.c | 55 ++++++++++++++++++++++++-------------------- 4 files changed, 75 insertions(+), 40 deletions(-) diff --git a/include/linux/slab.h b/include/linux/slab.h index cf443f064a667..2482992248dc9 100644 --- a/include/linux/slab.h +++ b/include/linux/slab.h @@ -1150,10 +1150,17 @@ static inline void kvfree_rcu_barrier(void) rcu_barrier(); } +static inline void kvfree_rcu_barrier_on_cache(struct kmem_cache *s) +{ + rcu_barrier(); +} + static inline void kfree_rcu_scheduler_running(void) { } #else void kvfree_rcu_barrier(void); +void kvfree_rcu_barrier_on_cache(struct kmem_cache *s); + void kfree_rcu_scheduler_running(void); #endif diff --git a/mm/slab.h b/mm/slab.h index 078daecc7cf50..bf9d8940b8f21 100644 --- a/mm/slab.h +++ b/mm/slab.h @@ -442,6 +442,7 @@ static inline bool is_kmalloc_normal(struct kmem_cache *s) bool __kfree_rcu_sheaf(struct kmem_cache *s, void *obj); void flush_all_rcu_sheaves(void); +void flush_rcu_sheaves_on_cache(struct kmem_cache *s); #define SLAB_CORE_FLAGS (SLAB_HWCACHE_ALIGN | SLAB_CACHE_DMA | \ SLAB_CACHE_DMA32 | SLAB_PANIC | \ diff --git a/mm/slab_common.c b/mm/slab_common.c index 932d13ada36c0..29be54153fa91 100644 --- a/mm/slab_common.c +++ b/mm/slab_common.c @@ -492,7 +492,7 @@ void kmem_cache_destroy(struct kmem_cache *s) return; /* in-flight kfree_rcu()'s may include objects from our cache */ - kvfree_rcu_barrier(); + kvfree_rcu_barrier_on_cache(s); if (IS_ENABLED(CONFIG_SLUB_RCU_DEBUG) && (s->flags & SLAB_TYPESAFE_BY_RCU)) { @@ -2039,25 +2039,13 @@ void kvfree_call_rcu(struct rcu_head *head, void *ptr) } EXPORT_SYMBOL_GPL(kvfree_call_rcu); -/** - * kvfree_rcu_barrier - Wait until all in-flight kvfree_rcu() complete. - * - * Note that a single argument of kvfree_rcu() call has a slow path that - * triggers synchronize_rcu() following by freeing a pointer. It is done - * before the return from the function. Therefore for any single-argument - * call that will result in a kfree() to a cache that is to be destroyed - * during module exit, it is developer's responsibility to ensure that all - * such calls have returned before the call to kmem_cache_destroy(). - */ -void kvfree_rcu_barrier(void) +static inline void __kvfree_rcu_barrier(void) { struct kfree_rcu_cpu_work *krwp; struct kfree_rcu_cpu *krcp; bool queued; int i, cpu; - flush_all_rcu_sheaves(); - /* * Firstly we detach objects and queue them over an RCU-batch * for all CPUs. Finally queued works are flushed for each CPU. @@ -2119,8 +2107,43 @@ void kvfree_rcu_barrier(void) } } } + +/** + * kvfree_rcu_barrier - Wait until all in-flight kvfree_rcu() complete. + * + * Note that a single argument of kvfree_rcu() call has a slow path that + * triggers synchronize_rcu() following by freeing a pointer. It is done + * before the return from the function. Therefore for any single-argument + * call that will result in a kfree() to a cache that is to be destroyed + * during module exit, it is developer's responsibility to ensure that all + * such calls have returned before the call to kmem_cache_destroy(). + */ +void kvfree_rcu_barrier(void) +{ + flush_all_rcu_sheaves(); + __kvfree_rcu_barrier(); +} EXPORT_SYMBOL_GPL(kvfree_rcu_barrier); +/** + * kvfree_rcu_barrier_on_cache - Wait for in-flight kvfree_rcu() calls on a + * specific slab cache. + * @s: slab cache to wait for + * + * See the description of kvfree_rcu_barrier() for details. + */ +void kvfree_rcu_barrier_on_cache(struct kmem_cache *s) +{ + if (s->cpu_sheaves) + flush_rcu_sheaves_on_cache(s); + /* + * TODO: Introduce a version of __kvfree_rcu_barrier() that works + * on a specific slab cache. + */ + __kvfree_rcu_barrier(); +} +EXPORT_SYMBOL_GPL(kvfree_rcu_barrier_on_cache); + static unsigned long kfree_rcu_shrink_count(struct shrinker *shrink, struct shrink_control *sc) { @@ -2216,4 +2239,3 @@ void __init kvfree_rcu_init(void) } #endif /* CONFIG_KVFREE_RCU_BATCHED */ - diff --git a/mm/slub.c b/mm/slub.c index a0b905c2a557e..e4aaaf0a5e040 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -4118,42 +4118,47 @@ static void flush_rcu_sheaf(struct work_struct *w) /* needed for kvfree_rcu_barrier() */ -void flush_all_rcu_sheaves(void) +void flush_rcu_sheaves_on_cache(struct kmem_cache *s) { struct slub_flush_work *sfw; - struct kmem_cache *s; unsigned int cpu; - cpus_read_lock(); - mutex_lock(&slab_mutex); + mutex_lock(&flush_lock); - list_for_each_entry(s, &slab_caches, list) { - if (!s->cpu_sheaves) - continue; + for_each_online_cpu(cpu) { + sfw = &per_cpu(slub_flush, cpu); - mutex_lock(&flush_lock); + /* + * we don't check if rcu_free sheaf exists - racing + * __kfree_rcu_sheaf() might have just removed it. + * by executing flush_rcu_sheaf() on the cpu we make + * sure the __kfree_rcu_sheaf() finished its call_rcu() + */ - for_each_online_cpu(cpu) { - sfw = &per_cpu(slub_flush, cpu); + INIT_WORK(&sfw->work, flush_rcu_sheaf); + sfw->s = s; + queue_work_on(cpu, flushwq, &sfw->work); + } - /* - * we don't check if rcu_free sheaf exists - racing - * __kfree_rcu_sheaf() might have just removed it. - * by executing flush_rcu_sheaf() on the cpu we make - * sure the __kfree_rcu_sheaf() finished its call_rcu() - */ + for_each_online_cpu(cpu) { + sfw = &per_cpu(slub_flush, cpu); + flush_work(&sfw->work); + } - INIT_WORK(&sfw->work, flush_rcu_sheaf); - sfw->s = s; - queue_work_on(cpu, flushwq, &sfw->work); - } + mutex_unlock(&flush_lock); +} - for_each_online_cpu(cpu) { - sfw = &per_cpu(slub_flush, cpu); - flush_work(&sfw->work); - } +void flush_all_rcu_sheaves(void) +{ + struct kmem_cache *s; + + cpus_read_lock(); + mutex_lock(&slab_mutex); - mutex_unlock(&flush_lock); + list_for_each_entry(s, &slab_caches, list) { + if (!s->cpu_sheaves) + continue; + flush_rcu_sheaves_on_cache(s); } mutex_unlock(&slab_mutex); From ec4358c724915df67cac2eb2f01b79270f91bc9a Mon Sep 17 00:00:00 2001 From: "Matthieu Baerts (NGI0)" Date: Fri, 5 Dec 2025 19:55:14 +0100 Subject: [PATCH 1279/2333] mptcp: pm: ignore unknown endpoint flags commit 0ace3297a7301911e52d8195cb1006414897c859 upstream. Before this patch, the kernel was saving any flags set by the userspace, even unknown ones. This doesn't cause critical issues because the kernel is only looking at specific ones. But on the other hand, endpoints dumps could tell the userspace some recent flags seem to be supported on older kernel versions. Instead, ignore all unknown flags when parsing them. By doing that, the userspace can continue to set unsupported flags, but it has a way to verify what is supported by the kernel. Note that it sounds better to continue accepting unsupported flags not to change the behaviour, but also that eases things on the userspace side by adding "optional" endpoint types only supported by newer kernel versions without having to deal with the different kernel versions. A note for the backports: there will be conflicts in mptcp.h on older versions not having the mentioned flags, the new line should still be added last, and the '5' needs to be adapted to have the same value as the last entry. Fixes: 01cacb00b35c ("mptcp: add netlink-based PM") Cc: stable@vger.kernel.org Reviewed-by: Mat Martineau Signed-off-by: Matthieu Baerts (NGI0) Link: https://patch.msgid.link/20251205-net-mptcp-misc-fixes-6-19-rc1-v1-1-9e4781a6c1b8@kernel.org Signed-off-by: Jakub Kicinski Signed-off-by: Greg Kroah-Hartman --- include/uapi/linux/mptcp.h | 1 + net/mptcp/pm_netlink.c | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/include/uapi/linux/mptcp.h b/include/uapi/linux/mptcp.h index 87cfab874e241..49e9b4e98c8b4 100644 --- a/include/uapi/linux/mptcp.h +++ b/include/uapi/linux/mptcp.h @@ -40,6 +40,7 @@ #define MPTCP_PM_ADDR_FLAG_FULLMESH _BITUL(3) #define MPTCP_PM_ADDR_FLAG_IMPLICIT _BITUL(4) #define MPTCP_PM_ADDR_FLAG_LAMINAR _BITUL(5) +#define MPTCP_PM_ADDR_FLAGS_MASK GENMASK(5, 0) struct mptcp_info { __u8 mptcpi_subflows; diff --git a/net/mptcp/pm_netlink.c b/net/mptcp/pm_netlink.c index d5b383870f799..7aa42de9c47b5 100644 --- a/net/mptcp/pm_netlink.c +++ b/net/mptcp/pm_netlink.c @@ -119,7 +119,8 @@ int mptcp_pm_parse_entry(struct nlattr *attr, struct genl_info *info, } if (tb[MPTCP_PM_ADDR_ATTR_FLAGS]) - entry->flags = nla_get_u32(tb[MPTCP_PM_ADDR_ATTR_FLAGS]); + entry->flags = nla_get_u32(tb[MPTCP_PM_ADDR_ATTR_FLAGS]) & + MPTCP_PM_ADDR_FLAGS_MASK; if (tb[MPTCP_PM_ADDR_ATTR_PORT]) entry->addr.port = htons(nla_get_u16(tb[MPTCP_PM_ADDR_ATTR_PORT])); From ea0129061d61665f4b8e9ff09bafe0554824207f Mon Sep 17 00:00:00 2001 From: "Matthieu Baerts (NGI0)" Date: Fri, 5 Dec 2025 19:55:15 +0100 Subject: [PATCH 1280/2333] selftests: mptcp: pm: ensure unknown flags are ignored commit 29f4801e9c8dfd12bdcb33b61a6ac479c7162bd7 upstream. This validates the previous commit: the userspace can set unknown flags -- the 7th bit is currently unused -- without errors, but only the supported ones are printed in the endpoints dumps. The 'Fixes' tag here below is the same as the one from the previous commit: this patch here is not fixing anything wrong in the selftests, but it validates the previous fix for an issue introduced by this commit ID. Fixes: 01cacb00b35c ("mptcp: add netlink-based PM") Cc: stable@vger.kernel.org Reviewed-by: Mat Martineau Signed-off-by: Matthieu Baerts (NGI0) Link: https://patch.msgid.link/20251205-net-mptcp-misc-fixes-6-19-rc1-v1-2-9e4781a6c1b8@kernel.org Signed-off-by: Jakub Kicinski Signed-off-by: Greg Kroah-Hartman --- tools/testing/selftests/net/mptcp/pm_netlink.sh | 4 ++++ tools/testing/selftests/net/mptcp/pm_nl_ctl.c | 11 +++++++++++ 2 files changed, 15 insertions(+) diff --git a/tools/testing/selftests/net/mptcp/pm_netlink.sh b/tools/testing/selftests/net/mptcp/pm_netlink.sh index ec6a875881919..123d9d7a0278c 100755 --- a/tools/testing/selftests/net/mptcp/pm_netlink.sh +++ b/tools/testing/selftests/net/mptcp/pm_netlink.sh @@ -192,6 +192,10 @@ check "show_endpoints" \ flush_endpoint check "show_endpoints" "" "flush addrs" +add_endpoint 10.0.1.1 flags unknown +check "show_endpoints" "$(format_endpoints "1,10.0.1.1")" "ignore unknown flags" +flush_endpoint + set_limits 9 1 2>/dev/null check "get_limits" "${default_limits}" "rcv addrs above hard limit" diff --git a/tools/testing/selftests/net/mptcp/pm_nl_ctl.c b/tools/testing/selftests/net/mptcp/pm_nl_ctl.c index 65b374232ff5a..99eecccbf0c87 100644 --- a/tools/testing/selftests/net/mptcp/pm_nl_ctl.c +++ b/tools/testing/selftests/net/mptcp/pm_nl_ctl.c @@ -24,6 +24,8 @@ #define IPPROTO_MPTCP 262 #endif +#define MPTCP_PM_ADDR_FLAG_UNKNOWN _BITUL(7) + static void syntax(char *argv[]) { fprintf(stderr, "%s add|ann|rem|csf|dsf|get|set|del|flush|dump|events|listen|accept []\n", argv[0]); @@ -836,6 +838,8 @@ int add_addr(int fd, int pm_family, int argc, char *argv[]) flags |= MPTCP_PM_ADDR_FLAG_BACKUP; else if (!strcmp(tok, "fullmesh")) flags |= MPTCP_PM_ADDR_FLAG_FULLMESH; + else if (!strcmp(tok, "unknown")) + flags |= MPTCP_PM_ADDR_FLAG_UNKNOWN; else error(1, errno, "unknown flag %s", argv[arg]); @@ -1048,6 +1052,13 @@ static void print_addr(struct rtattr *attrs, int len) printf(","); } + if (flags & MPTCP_PM_ADDR_FLAG_UNKNOWN) { + printf("unknown"); + flags &= ~MPTCP_PM_ADDR_FLAG_UNKNOWN; + if (flags) + printf(","); + } + /* bump unknown flags, if any */ if (flags) printf("0x%x", flags); From 77ea2657b4704f978d3504883bb57a7ea08ecf47 Mon Sep 17 00:00:00 2001 From: Paolo Abeni Date: Fri, 5 Dec 2025 19:55:16 +0100 Subject: [PATCH 1281/2333] mptcp: schedule rtx timer only after pushing data commit 2ea6190f42d0416a4310e60a7fcb0b49fcbbd4fb upstream. The MPTCP protocol usually schedule the retransmission timer only when there is some chances for such retransmissions to happen. With a notable exception: __mptcp_push_pending() currently schedule such timer unconditionally, potentially leading to unnecessary rtx timer expiration. The issue is present since the blamed commit below but become easily reproducible after commit 27b0e701d387 ("mptcp: drop bogus optimization in __mptcp_check_push()") Fixes: 33d41c9cd74c ("mptcp: more accurate timeout") Cc: stable@vger.kernel.org Signed-off-by: Paolo Abeni Reviewed-by: Matthieu Baerts (NGI0) Signed-off-by: Matthieu Baerts (NGI0) Link: https://patch.msgid.link/20251205-net-mptcp-misc-fixes-6-19-rc1-v1-3-9e4781a6c1b8@kernel.org Signed-off-by: Jakub Kicinski Signed-off-by: Greg Kroah-Hartman --- net/mptcp/protocol.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index 1e413426deeec..cd5edc19cb345 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -1597,7 +1597,7 @@ void __mptcp_push_pending(struct sock *sk, unsigned int flags) struct mptcp_sendmsg_info info = { .flags = flags, }; - bool do_check_data_fin = false; + bool copied = false; int push_count = 1; while (mptcp_send_head(sk) && (push_count > 0)) { @@ -1639,7 +1639,7 @@ void __mptcp_push_pending(struct sock *sk, unsigned int flags) push_count--; continue; } - do_check_data_fin = true; + copied = true; } } } @@ -1648,11 +1648,14 @@ void __mptcp_push_pending(struct sock *sk, unsigned int flags) if (ssk) mptcp_push_release(ssk, &info); - /* ensure the rtx timer is running */ - if (!mptcp_rtx_timer_pending(sk)) - mptcp_reset_rtx_timer(sk); - if (do_check_data_fin) + /* Avoid scheduling the rtx timer if no data has been pushed; the timer + * will be updated on positive acks by __mptcp_cleanup_una(). + */ + if (copied) { + if (!mptcp_rtx_timer_pending(sk)) + mptcp_reset_rtx_timer(sk); mptcp_check_send_data_fin(sk); + } } static void __mptcp_subflow_push_pending(struct sock *sk, struct sock *ssk, bool first) From 50f47c02be419bf0a3ae94c118addf67beef359f Mon Sep 17 00:00:00 2001 From: Paolo Abeni Date: Fri, 5 Dec 2025 19:55:17 +0100 Subject: [PATCH 1282/2333] mptcp: avoid deadlock on fallback while reinjecting commit ffb8c27b0539dd90262d1021488e7817fae57c42 upstream. Jakub reported an MPTCP deadlock at fallback time: WARNING: possible recursive locking detected 6.18.0-rc7-virtme #1 Not tainted -------------------------------------------- mptcp_connect/20858 is trying to acquire lock: ff1100001da18b60 (&msk->fallback_lock){+.-.}-{3:3}, at: __mptcp_try_fallback+0xd8/0x280 but task is already holding lock: ff1100001da18b60 (&msk->fallback_lock){+.-.}-{3:3}, at: __mptcp_retrans+0x352/0xaa0 other info that might help us debug this: Possible unsafe locking scenario: CPU0 ---- lock(&msk->fallback_lock); lock(&msk->fallback_lock); *** DEADLOCK *** May be due to missing lock nesting notation 3 locks held by mptcp_connect/20858: #0: ff1100001da18290 (sk_lock-AF_INET){+.+.}-{0:0}, at: mptcp_sendmsg+0x114/0x1bc0 #1: ff1100001db40fd0 (k-sk_lock-AF_INET#2){+.+.}-{0:0}, at: __mptcp_retrans+0x2cb/0xaa0 #2: ff1100001da18b60 (&msk->fallback_lock){+.-.}-{3:3}, at: __mptcp_retrans+0x352/0xaa0 stack backtrace: CPU: 0 UID: 0 PID: 20858 Comm: mptcp_connect Not tainted 6.18.0-rc7-virtme #1 PREEMPT(full) Hardware name: Bochs, BIOS Bochs 01/01/2011 Call Trace: dump_stack_lvl+0x6f/0xa0 print_deadlock_bug.cold+0xc0/0xcd validate_chain+0x2ff/0x5f0 __lock_acquire+0x34c/0x740 lock_acquire.part.0+0xbc/0x260 _raw_spin_lock_bh+0x38/0x50 __mptcp_try_fallback+0xd8/0x280 mptcp_sendmsg_frag+0x16c2/0x3050 __mptcp_retrans+0x421/0xaa0 mptcp_release_cb+0x5aa/0xa70 release_sock+0xab/0x1d0 mptcp_sendmsg+0xd5b/0x1bc0 sock_write_iter+0x281/0x4d0 new_sync_write+0x3c5/0x6f0 vfs_write+0x65e/0xbb0 ksys_write+0x17e/0x200 do_syscall_64+0xbb/0xfd0 entry_SYSCALL_64_after_hwframe+0x4b/0x53 RIP: 0033:0x7fa5627cbc5e Code: 4d 89 d8 e8 14 bd 00 00 4c 8b 5d f8 41 8b 93 08 03 00 00 59 5e 48 83 f8 fc 74 11 c9 c3 0f 1f 80 00 00 00 00 48 8b 45 10 0f 05 c3 83 e2 39 83 fa 08 75 e7 e8 13 ff ff ff 0f 1f 00 f3 0f 1e fa RSP: 002b:00007fff1fe14700 EFLAGS: 00000202 ORIG_RAX: 0000000000000001 RAX: ffffffffffffffda RBX: 0000000000000005 RCX: 00007fa5627cbc5e RDX: 0000000000001f9c RSI: 00007fff1fe16984 RDI: 0000000000000005 RBP: 00007fff1fe14710 R08: 0000000000000000 R09: 0000000000000000 R10: 0000000000000000 R11: 0000000000000202 R12: 00007fff1fe16920 R13: 0000000000002000 R14: 0000000000001f9c R15: 0000000000001f9c The packet scheduler could attempt a reinjection after receiving an MP_FAIL and before the infinite map has been transmitted, causing a deadlock since MPTCP needs to do the reinjection atomically from WRT fallback. Address the issue explicitly avoiding the reinjection in the critical scenario. Note that this is the only fallback critical section that could potentially send packets and hit the double-lock. Reported-by: Jakub Kicinski Closes: https://netdev-ctrl.bots.linux.dev/logs/vmksft/mptcp-dbg/results/412720/1-mptcp-join-sh/stderr Fixes: f8a1d9b18c5e ("mptcp: make fallback action and fallback decision atomic") Cc: stable@vger.kernel.org Signed-off-by: Paolo Abeni Reviewed-by: Matthieu Baerts (NGI0) Signed-off-by: Matthieu Baerts (NGI0) Link: https://patch.msgid.link/20251205-net-mptcp-misc-fixes-6-19-rc1-v1-4-9e4781a6c1b8@kernel.org Signed-off-by: Jakub Kicinski Signed-off-by: Greg Kroah-Hartman --- net/mptcp/protocol.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index cd5edc19cb345..221a5ea019e69 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -2693,10 +2693,13 @@ static void __mptcp_retrans(struct sock *sk) /* * make the whole retrans decision, xmit, disallow - * fallback atomic + * fallback atomic, note that we can't retrans even + * when an infinite fallback is in progress, i.e. new + * subflows are disallowed. */ spin_lock_bh(&msk->fallback_lock); - if (__mptcp_check_fallback(msk)) { + if (__mptcp_check_fallback(msk) || + !msk->allow_subflows) { spin_unlock_bh(&msk->fallback_lock); release_sock(ssk); goto clear_scheduled; From 207d2d90ad871cfdd9915d48816285214699b785 Mon Sep 17 00:00:00 2001 From: Chen Changcheng Date: Thu, 18 Dec 2025 09:23:18 +0800 Subject: [PATCH 1283/2333] usb: usb-storage: Maintain minimal modifications to the bcdDevice range. commit 0831269b5f71594882accfceb02638124f88955d upstream. We cannot determine which models require the NO_ATA_1X and IGNORE_RESIDUE quirks aside from the EL-R12 optical drive device. Fixes: 955a48a5353f ("usb: usb-storage: No additional quirks need to be added to the EL-R12 optical drive.") Signed-off-by: Chen Changcheng Link: https://patch.msgid.link/20251218012318.15978-1-chenchangcheng@kylinos.cn Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/unusual_uas.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/storage/unusual_uas.h b/drivers/usb/storage/unusual_uas.h index b695f5ba9a409..939a98c2d3f74 100644 --- a/drivers/usb/storage/unusual_uas.h +++ b/drivers/usb/storage/unusual_uas.h @@ -98,7 +98,7 @@ UNUSUAL_DEV(0x125f, 0xa94a, 0x0160, 0x0160, US_FL_NO_ATA_1X), /* Reported-by: Benjamin Tissoires */ -UNUSUAL_DEV(0x13fd, 0x3940, 0x0309, 0x0309, +UNUSUAL_DEV(0x13fd, 0x3940, 0x0000, 0x0309, "Initio Corporation", "INIC-3069", USB_SC_DEVICE, USB_PR_DEVICE, NULL, From ac92151ff2494130d9fc686055d6bbb9743a673e Mon Sep 17 00:00:00 2001 From: Jeongjun Park Date: Mon, 21 Apr 2025 21:52:44 +0900 Subject: [PATCH 1284/2333] media: dvb-usb: dtv5100: fix out-of-bounds in dtv5100_i2c_msg() commit b91e6aafe8d356086cc621bc03e35ba2299e4788 upstream. rlen value is a user-controlled value, but dtv5100_i2c_msg() does not check the size of the rlen value. Therefore, if it is set to a value larger than sizeof(st->data), an out-of-bounds vuln occurs for st->data. Therefore, we need to add proper range checking to prevent this vuln. Fixes: 60688d5e6e6e ("V4L/DVB (8735): dtv5100: replace dummy frontend by zl10353") Cc: stable@vger.kernel.org Signed-off-by: Jeongjun Park Signed-off-by: Hans Verkuil Signed-off-by: Greg Kroah-Hartman --- drivers/media/usb/dvb-usb/dtv5100.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/media/usb/dvb-usb/dtv5100.c b/drivers/media/usb/dvb-usb/dtv5100.c index 3d85c6f7f6ecf..c448e2ebda1ac 100644 --- a/drivers/media/usb/dvb-usb/dtv5100.c +++ b/drivers/media/usb/dvb-usb/dtv5100.c @@ -55,6 +55,11 @@ static int dtv5100_i2c_msg(struct dvb_usb_device *d, u8 addr, } index = (addr << 8) + wbuf[0]; + if (rlen > sizeof(st->data)) { + warn("rlen = %x is too big!\n", rlen); + return -EINVAL; + } + memcpy(st->data, rbuf, rlen); msleep(1); /* avoid I2C errors */ return usb_control_msg(d->udev, pipe, request, From b07bfaf62d07844c48270c4d0f390722d3953e0e Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 3 Sep 2025 09:44:16 +0100 Subject: [PATCH 1285/2333] media: pvrusb2: Fix incorrect variable used in trace message commit be440980eace19c035a0745fd6b6e42707bc4f49 upstream. The pvr2_trace message is reporting an error about control read transfers, however it is using the incorrect variable write_len instead of read_lean. Fix this by using the correct variable read_len. Fixes: d855497edbfb ("V4L/DVB (4228a): pvrusb2 to kernel 2.6.18") Cc: stable@vger.kernel.org Signed-off-by: Colin Ian King Signed-off-by: Hans Verkuil Signed-off-by: Greg Kroah-Hartman --- drivers/media/usb/pvrusb2/pvrusb2-hdw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/usb/pvrusb2/pvrusb2-hdw.c b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c index f21c2806eb9fe..b32bb906a9de2 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c @@ -3622,7 +3622,7 @@ static int pvr2_send_request_ex(struct pvr2_hdw *hdw, pvr2_trace( PVR2_TRACE_ERROR_LEGS, "Attempted to execute %d byte control-read transfer (limit=%d)", - write_len,PVR2_CTL_BUFFSIZE); + read_len, PVR2_CTL_BUFFSIZE); return -EINVAL; } if ((!write_len) && (!read_len)) { From 987c0ddfe8bb23f5700c2512efd4ba273967ed6d Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Fri, 17 Oct 2025 07:45:37 +0200 Subject: [PATCH 1286/2333] phy: broadcom: bcm63xx-usbh: fix section mismatches MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 356d1924b9a6bc2164ce2bf1fad147b0c37ae085 upstream. Platform drivers can be probed after their init sections have been discarded (e.g. on probe deferral or manual rebind through sysfs) so the probe function and match table must not live in init. Fixes: 783f6d3dcf35 ("phy: bcm63xx-usbh: Add BCM63xx USBH driver") Cc: stable@vger.kernel.org # 5.9 Cc: Álvaro Fernández Rojas Signed-off-by: Johan Hovold Reviewed-by: Neil Armstrong Link: https://patch.msgid.link/20251017054537.6884-1-johan@kernel.org Signed-off-by: Vinod Koul Signed-off-by: Greg Kroah-Hartman --- drivers/phy/broadcom/phy-bcm63xx-usbh.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/phy/broadcom/phy-bcm63xx-usbh.c b/drivers/phy/broadcom/phy-bcm63xx-usbh.c index 647644de041bb..29fd6791bae64 100644 --- a/drivers/phy/broadcom/phy-bcm63xx-usbh.c +++ b/drivers/phy/broadcom/phy-bcm63xx-usbh.c @@ -375,7 +375,7 @@ static struct phy *bcm63xx_usbh_phy_xlate(struct device *dev, return of_phy_simple_xlate(dev, args); } -static int __init bcm63xx_usbh_phy_probe(struct platform_device *pdev) +static int bcm63xx_usbh_phy_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct bcm63xx_usbh_phy *usbh; @@ -432,7 +432,7 @@ static int __init bcm63xx_usbh_phy_probe(struct platform_device *pdev) return 0; } -static const struct of_device_id bcm63xx_usbh_phy_ids[] __initconst = { +static const struct of_device_id bcm63xx_usbh_phy_ids[] = { { .compatible = "brcm,bcm6318-usbh-phy", .data = &usbh_bcm6318 }, { .compatible = "brcm,bcm6328-usbh-phy", .data = &usbh_bcm6328 }, { .compatible = "brcm,bcm6358-usbh-phy", .data = &usbh_bcm6358 }, @@ -443,7 +443,7 @@ static const struct of_device_id bcm63xx_usbh_phy_ids[] __initconst = { }; MODULE_DEVICE_TABLE(of, bcm63xx_usbh_phy_ids); -static struct platform_driver bcm63xx_usbh_phy_driver __refdata = { +static struct platform_driver bcm63xx_usbh_phy_driver = { .driver = { .name = "bcm63xx-usbh-phy", .of_match_table = bcm63xx_usbh_phy_ids, From a9cd9a4846ef4898c012932c6ca33a814b9ab6c4 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 18 Dec 2025 16:35:17 +0100 Subject: [PATCH 1287/2333] usb: ohci-nxp: fix device leak on probe failure commit b4c61e542faf8c9131d69ecfc3ad6de96d1b2ab8 upstream. Make sure to drop the reference taken when looking up the PHY I2C device during probe on probe failure (e.g. probe deferral) and on driver unbind. Fixes: 73108aa90cbf ("USB: ohci-nxp: Use isp1301 driver") Cc: stable@vger.kernel.org # 3.5 Reported-by: Ma Ke Link: https://lore.kernel.org/lkml/20251117013428.21840-1-make24@iscas.ac.cn/ Signed-off-by: Johan Hovold Acked-by: Alan Stern Reviewed-by: Vladimir Zapolskiy Link: https://patch.msgid.link/20251218153519.19453-4-johan@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-nxp.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/usb/host/ohci-nxp.c b/drivers/usb/host/ohci-nxp.c index 24d5a1dc50560..509ca7d8d5138 100644 --- a/drivers/usb/host/ohci-nxp.c +++ b/drivers/usb/host/ohci-nxp.c @@ -223,6 +223,7 @@ static int ohci_hcd_nxp_probe(struct platform_device *pdev) fail_resource: usb_put_hcd(hcd); fail_disable: + put_device(&isp1301_i2c_client->dev); isp1301_i2c_client = NULL; return ret; } @@ -234,6 +235,7 @@ static void ohci_hcd_nxp_remove(struct platform_device *pdev) usb_remove_hcd(hcd); ohci_nxp_stop_hc(); usb_put_hcd(hcd); + put_device(&isp1301_i2c_client->dev); isp1301_i2c_client = NULL; } From 8422cdf91db1dc73f371adbc8af6d24d1908d1d3 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 4 Dec 2025 11:11:07 +0100 Subject: [PATCH 1288/2333] usb: typec: ucsi: huawei-gaokin: add DRM dependency commit d14cd998e67ba8f1cca52a260a1ce1a60954fd8b upstream. Selecting DRM_AUX_HPD_BRIDGE is not possible from a built-in driver when CONFIG_DRM=m: WARNING: unmet direct dependencies detected for DRM_AUX_HPD_BRIDGE Depends on [m]: HAS_IOMEM [=y] && DRM [=m] && DRM_BRIDGE [=y] && OF [=y] Selected by [y]: - UCSI_HUAWEI_GAOKUN [=y] && USB_SUPPORT [=y] && TYPEC [=y] && TYPEC_UCSI [=y] && EC_HUAWEI_GAOKUN [=y] && DRM_BRIDGE [=y] && OF [=y] Add the same dependency we have in similar drivers to work around this. Fixes: 00327d7f2c8c ("usb: typec: ucsi: add Huawei Matebook E Go ucsi driver") Cc: stable Signed-off-by: Arnd Bergmann Reviewed-by: Heikki Krogerus Link: https://patch.msgid.link/20251204101111.1035975-1-arnd@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/ucsi/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/typec/ucsi/Kconfig b/drivers/usb/typec/ucsi/Kconfig index 7fcb1e1de5d6d..b812be4d0e674 100644 --- a/drivers/usb/typec/ucsi/Kconfig +++ b/drivers/usb/typec/ucsi/Kconfig @@ -96,6 +96,7 @@ config UCSI_LENOVO_YOGA_C630 config UCSI_HUAWEI_GAOKUN tristate "UCSI Interface Driver for Huawei Matebook E Go" depends on EC_HUAWEI_GAOKUN + depends on DRM || !DRM select DRM_AUX_HPD_BRIDGE if DRM_BRIDGE && OF help This driver enables UCSI support on the Huawei Matebook E Go tablet, From d377fe40ff5a4d7ccb0e3efa9381adfd4238f3b2 Mon Sep 17 00:00:00 2001 From: Haoxiang Li Date: Sat, 6 Dec 2025 15:04:45 +0800 Subject: [PATCH 1289/2333] usb: typec: altmodes/displayport: Drop the device reference in dp_altmode_probe() commit 128bb7fab342546352603bde8b49ff54e3af0529 upstream. In error paths, call typec_altmode_put_plug() to drop the device reference obtained by typec_altmode_get_plug(). Fixes: 71ba4fe56656 ("usb: typec: altmodes/displayport: add SOP' support") Cc: stable Signed-off-by: Haoxiang Li Reviewed-by: Heikki Krogerus Link: https://patch.msgid.link/20251206070445.190770-1-lihaoxiang@isrc.iscas.ac.cn Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/altmodes/displayport.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/usb/typec/altmodes/displayport.c b/drivers/usb/typec/altmodes/displayport.c index 1dcb77faf85d4..6462705604510 100644 --- a/drivers/usb/typec/altmodes/displayport.c +++ b/drivers/usb/typec/altmodes/displayport.c @@ -764,12 +764,16 @@ int dp_altmode_probe(struct typec_altmode *alt) if (!(DP_CAP_PIN_ASSIGN_DFP_D(port->vdo) & DP_CAP_PIN_ASSIGN_UFP_D(alt->vdo)) && !(DP_CAP_PIN_ASSIGN_UFP_D(port->vdo) & - DP_CAP_PIN_ASSIGN_DFP_D(alt->vdo))) + DP_CAP_PIN_ASSIGN_DFP_D(alt->vdo))) { + typec_altmode_put_plug(plug); return -ENODEV; + } dp = devm_kzalloc(&alt->dev, sizeof(*dp), GFP_KERNEL); - if (!dp) + if (!dp) { + typec_altmode_put_plug(plug); return -ENOMEM; + } INIT_WORK(&dp->work, dp_altmode_work); mutex_init(&dp->lock); From cefaad839a384a72331aedad927b1944fb6943dc Mon Sep 17 00:00:00 2001 From: Ma Ke Date: Mon, 15 Dec 2025 10:09:31 +0800 Subject: [PATCH 1290/2333] USB: lpc32xx_udc: Fix error handling in probe commit c84117912bddd9e5d87e68daf182410c98181407 upstream. lpc32xx_udc_probe() acquires an i2c_client reference through isp1301_get_client() but fails to release it in both error handling paths and the normal removal path. This could result in a reference count leak for the I2C device, preventing proper cleanup and potentially leading to resource exhaustion. Add put_device() to release the reference in the probe failure path and in the remove function. Calling path: isp1301_get_client() -> of_find_i2c_device_by_node() -> i2c_find_device_by_fwnode(). As comments of i2c_find_device_by_fwnode() says, 'The user must call put_device(&client->dev) once done with the i2c client.' Found by code review. Cc: stable Fixes: 24a28e428351 ("USB: gadget driver for LPC32xx") Signed-off-by: Ma Ke Link: https://patch.msgid.link/20251215020931.15324-1-make24@iscas.ac.cn Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/udc/lpc32xx_udc.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/drivers/usb/gadget/udc/lpc32xx_udc.c b/drivers/usb/gadget/udc/lpc32xx_udc.c index 1a7d3c4f652fe..73c0f28a85852 100644 --- a/drivers/usb/gadget/udc/lpc32xx_udc.c +++ b/drivers/usb/gadget/udc/lpc32xx_udc.c @@ -3020,7 +3020,7 @@ static int lpc32xx_udc_probe(struct platform_device *pdev) pdev->dev.dma_mask = &lpc32xx_usbd_dmamask; retval = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); if (retval) - return retval; + goto i2c_fail; udc->board = &lpc32xx_usbddata; @@ -3038,28 +3038,32 @@ static int lpc32xx_udc_probe(struct platform_device *pdev) /* Get IRQs */ for (i = 0; i < 4; i++) { udc->udp_irq[i] = platform_get_irq(pdev, i); - if (udc->udp_irq[i] < 0) - return udc->udp_irq[i]; + if (udc->udp_irq[i] < 0) { + retval = udc->udp_irq[i]; + goto i2c_fail; + } } udc->udp_baseaddr = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(udc->udp_baseaddr)) { dev_err(udc->dev, "IO map failure\n"); - return PTR_ERR(udc->udp_baseaddr); + retval = PTR_ERR(udc->udp_baseaddr); + goto i2c_fail; } /* Get USB device clock */ udc->usb_slv_clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(udc->usb_slv_clk)) { dev_err(udc->dev, "failed to acquire USB device clock\n"); - return PTR_ERR(udc->usb_slv_clk); + retval = PTR_ERR(udc->usb_slv_clk); + goto i2c_fail; } /* Enable USB device clock */ retval = clk_prepare_enable(udc->usb_slv_clk); if (retval < 0) { dev_err(udc->dev, "failed to start USB device clock\n"); - return retval; + goto i2c_fail; } /* Setup deferred workqueue data */ @@ -3161,6 +3165,8 @@ static int lpc32xx_udc_probe(struct platform_device *pdev) dma_free_coherent(&pdev->dev, UDCA_BUFF_SIZE, udc->udca_v_base, udc->udca_p_base); i2c_fail: + if (udc->isp1301_i2c_client) + put_device(&udc->isp1301_i2c_client->dev); clk_disable_unprepare(udc->usb_slv_clk); dev_err(udc->dev, "%s probe failed, %d\n", driver_name, retval); @@ -3189,6 +3195,9 @@ static void lpc32xx_udc_remove(struct platform_device *pdev) dma_free_coherent(&pdev->dev, UDCA_BUFF_SIZE, udc->udca_v_base, udc->udca_p_base); + if (udc->isp1301_i2c_client) + put_device(&udc->isp1301_i2c_client->dev); + clk_disable_unprepare(udc->usb_slv_clk); } From 2e7c47e2eb3cfeadf78a1ccbac8492c60d508f23 Mon Sep 17 00:00:00 2001 From: Duoming Zhou Date: Fri, 5 Dec 2025 11:48:31 +0800 Subject: [PATCH 1291/2333] usb: phy: fsl-usb: Fix use-after-free in delayed work during device removal commit 41ca62e3e21e48c2903b3b45e232cf4f2ff7434f upstream. The delayed work item otg_event is initialized in fsl_otg_conf() and scheduled under two conditions: 1. When a host controller binds to the OTG controller. 2. When the USB ID pin state changes (cable insertion/removal). A race condition occurs when the device is removed via fsl_otg_remove(): the fsl_otg instance may be freed while the delayed work is still pending or executing. This leads to use-after-free when the work function fsl_otg_event() accesses the already freed memory. The problematic scenario: (detach thread) | (delayed work) fsl_otg_remove() | kfree(fsl_otg_dev) //FREE| fsl_otg_event() | og = container_of(...) //USE | og-> //USE Fix this by calling disable_delayed_work_sync() in fsl_otg_remove() before deallocating the fsl_otg structure. This ensures the delayed work is properly canceled and completes execution prior to memory deallocation. This bug was identified through static analysis. Fixes: 0807c500a1a6 ("USB: add Freescale USB OTG Transceiver driver") Cc: stable Signed-off-by: Duoming Zhou Link: https://patch.msgid.link/20251205034831.12846-1-duoming@zju.edu.cn Signed-off-by: Greg Kroah-Hartman --- drivers/usb/phy/phy-fsl-usb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/phy/phy-fsl-usb.c b/drivers/usb/phy/phy-fsl-usb.c index 40ac68e52cee7..e266a47c4d483 100644 --- a/drivers/usb/phy/phy-fsl-usb.c +++ b/drivers/usb/phy/phy-fsl-usb.c @@ -988,6 +988,7 @@ static void fsl_otg_remove(struct platform_device *pdev) { struct fsl_usb2_platform_data *pdata = dev_get_platdata(&pdev->dev); + disable_delayed_work_sync(&fsl_otg_dev->otg_event); usb_remove_phy(&fsl_otg_dev->phy); free_irq(fsl_otg_dev->irq, fsl_otg_dev); From 7501ecfe3e5202490c2d13dc7e181203601fcd69 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 18 Dec 2025 16:35:16 +0100 Subject: [PATCH 1292/2333] usb: phy: isp1301: fix non-OF device reference imbalance commit b4b64fda4d30a83a7f00e92a0c8a1d47699609f3 upstream. A recent change fixing a device reference leak in a UDC driver introduced a potential use-after-free in the non-OF case as the isp1301_get_client() helper only increases the reference count for the returned I2C device in the OF case. Increment the reference count also for non-OF so that the caller can decrement it unconditionally. Note that this is inherently racy just as using the returned I2C device is since nothing is preventing the PHY driver from being unbound while in use. Fixes: c84117912bdd ("USB: lpc32xx_udc: Fix error handling in probe") Cc: stable@vger.kernel.org Cc: Ma Ke Signed-off-by: Johan Hovold Reviewed-by: Vladimir Zapolskiy Link: https://patch.msgid.link/20251218153519.19453-3-johan@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/phy/phy-isp1301.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/usb/phy/phy-isp1301.c b/drivers/usb/phy/phy-isp1301.c index f9b5c411aee4e..2940f0c84e1b7 100644 --- a/drivers/usb/phy/phy-isp1301.c +++ b/drivers/usb/phy/phy-isp1301.c @@ -149,7 +149,12 @@ struct i2c_client *isp1301_get_client(struct device_node *node) return client; /* non-DT: only one ISP1301 chip supported */ - return isp1301_i2c_client; + if (isp1301_i2c_client) { + get_device(&isp1301_i2c_client->dev); + return isp1301_i2c_client; + } + + return NULL; } EXPORT_SYMBOL_GPL(isp1301_get_client); From 9f4bc5c304028795ac525b31192534b4bd7ca272 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 18 Dec 2025 16:35:15 +0100 Subject: [PATCH 1293/2333] usb: gadget: lpc32xx_udc: fix clock imbalance in error path commit 782be79e4551550d7a82b1957fc0f7347e6d461f upstream. A recent change fixing a device reference leak introduced a clock imbalance by reusing an error path so that the clock may be disabled before having been enabled. Note that the clock framework allows for passing in NULL clocks so there is no risk for a NULL pointer dereference. Also drop the bogus I2C client NULL check added by the offending commit as the pointer has already been verified to be non-NULL. Fixes: c84117912bdd ("USB: lpc32xx_udc: Fix error handling in probe") Cc: stable@vger.kernel.org Cc: Ma Ke Signed-off-by: Johan Hovold Reviewed-by: Vladimir Zapolskiy Link: https://patch.msgid.link/20251218153519.19453-2-johan@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/udc/lpc32xx_udc.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/usb/gadget/udc/lpc32xx_udc.c b/drivers/usb/gadget/udc/lpc32xx_udc.c index 73c0f28a85852..a962d4294fbec 100644 --- a/drivers/usb/gadget/udc/lpc32xx_udc.c +++ b/drivers/usb/gadget/udc/lpc32xx_udc.c @@ -3020,7 +3020,7 @@ static int lpc32xx_udc_probe(struct platform_device *pdev) pdev->dev.dma_mask = &lpc32xx_usbd_dmamask; retval = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); if (retval) - goto i2c_fail; + goto err_put_client; udc->board = &lpc32xx_usbddata; @@ -3040,7 +3040,7 @@ static int lpc32xx_udc_probe(struct platform_device *pdev) udc->udp_irq[i] = platform_get_irq(pdev, i); if (udc->udp_irq[i] < 0) { retval = udc->udp_irq[i]; - goto i2c_fail; + goto err_put_client; } } @@ -3048,7 +3048,7 @@ static int lpc32xx_udc_probe(struct platform_device *pdev) if (IS_ERR(udc->udp_baseaddr)) { dev_err(udc->dev, "IO map failure\n"); retval = PTR_ERR(udc->udp_baseaddr); - goto i2c_fail; + goto err_put_client; } /* Get USB device clock */ @@ -3056,14 +3056,14 @@ static int lpc32xx_udc_probe(struct platform_device *pdev) if (IS_ERR(udc->usb_slv_clk)) { dev_err(udc->dev, "failed to acquire USB device clock\n"); retval = PTR_ERR(udc->usb_slv_clk); - goto i2c_fail; + goto err_put_client; } /* Enable USB device clock */ retval = clk_prepare_enable(udc->usb_slv_clk); if (retval < 0) { dev_err(udc->dev, "failed to start USB device clock\n"); - goto i2c_fail; + goto err_put_client; } /* Setup deferred workqueue data */ @@ -3165,9 +3165,10 @@ static int lpc32xx_udc_probe(struct platform_device *pdev) dma_free_coherent(&pdev->dev, UDCA_BUFF_SIZE, udc->udca_v_base, udc->udca_p_base); i2c_fail: - if (udc->isp1301_i2c_client) - put_device(&udc->isp1301_i2c_client->dev); clk_disable_unprepare(udc->usb_slv_clk); +err_put_client: + put_device(&udc->isp1301_i2c_client->dev); + dev_err(udc->dev, "%s probe failed, %d\n", driver_name, retval); return retval; @@ -3195,10 +3196,9 @@ static void lpc32xx_udc_remove(struct platform_device *pdev) dma_free_coherent(&pdev->dev, UDCA_BUFF_SIZE, udc->udca_v_base, udc->udca_p_base); - if (udc->isp1301_i2c_client) - put_device(&udc->isp1301_i2c_client->dev); - clk_disable_unprepare(udc->usb_slv_clk); + + put_device(&udc->isp1301_i2c_client->dev); } #ifdef CONFIG_PM From 5a45d75da3b79abe0edf3608ecd58f751ffe5bbf Mon Sep 17 00:00:00 2001 From: Miaoqian Lin Date: Thu, 11 Dec 2025 10:49:36 +0400 Subject: [PATCH 1294/2333] usb: dwc3: of-simple: fix clock resource leak in dwc3_of_simple_probe commit 3b4961313d31e200c9e974bb1536cdea217f78b5 upstream. When clk_bulk_prepare_enable() fails, the error path jumps to err_resetc_assert, skipping clk_bulk_put_all() and leaking the clock references acquired by clk_bulk_get_all(). Add err_clk_put_all label to properly release clock resources in all error paths. Found via static analysis and code review. Fixes: c0c61471ef86 ("usb: dwc3: of-simple: Convert to bulk clk API") Cc: stable Signed-off-by: Miaoqian Lin Acked-by: Thinh Nguyen Link: https://patch.msgid.link/20251211064937.2360510-1-linmq006@gmail.com Signed-off-by: Greg Kroah-Hartman Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/dwc3-of-simple.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/usb/dwc3/dwc3-of-simple.c b/drivers/usb/dwc3/dwc3-of-simple.c index a4954a21be930..c116143335d9f 100644 --- a/drivers/usb/dwc3/dwc3-of-simple.c +++ b/drivers/usb/dwc3/dwc3-of-simple.c @@ -70,11 +70,11 @@ static int dwc3_of_simple_probe(struct platform_device *pdev) simple->num_clocks = ret; ret = clk_bulk_prepare_enable(simple->num_clocks, simple->clks); if (ret) - goto err_resetc_assert; + goto err_clk_put_all; ret = of_platform_populate(np, NULL, NULL, dev); if (ret) - goto err_clk_put; + goto err_clk_disable; pm_runtime_set_active(dev); pm_runtime_enable(dev); @@ -82,8 +82,9 @@ static int dwc3_of_simple_probe(struct platform_device *pdev) return 0; -err_clk_put: +err_clk_disable: clk_bulk_disable_unprepare(simple->num_clocks, simple->clks); +err_clk_put_all: clk_bulk_put_all(simple->num_clocks, simple->clks); err_resetc_assert: From 1f069425f4f089d3c92064f276e90cf8170df182 Mon Sep 17 00:00:00 2001 From: Udipto Goswami Date: Wed, 26 Nov 2025 11:12:21 +0530 Subject: [PATCH 1295/2333] usb: dwc3: keep susphy enabled during exit to avoid controller faults commit e1003aa7ec9eccdde4c926bd64ef42816ad55f25 upstream. On some platforms, switching USB roles from host to device can trigger controller faults due to premature PHY power-down. This occurs when the PHY is disabled too early during teardown, causing synchronization issues between the PHY and controller. Keep susphy enabled during dwc3_host_exit() and dwc3_gadget_exit() ensures the PHY remains in a low-power state capable of handling required commands during role switch. Cc: stable Fixes: 6d735722063a ("usb: dwc3: core: Prevent phy suspend during init") Suggested-by: Thinh Nguyen Signed-off-by: Udipto Goswami Acked-by: Thinh Nguyen Link: https://patch.msgid.link/20251126054221.120638-1-udipto.goswami@oss.qualcomm.com Signed-off-by: Greg Kroah-Hartman Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/gadget.c | 2 +- drivers/usb/dwc3/host.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 5e4997f974ddd..17eebb60900bf 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -4825,7 +4825,7 @@ void dwc3_gadget_exit(struct dwc3 *dwc) if (!dwc->gadget) return; - dwc3_enable_susphy(dwc, false); + dwc3_enable_susphy(dwc, true); usb_del_gadget(dwc->gadget); dwc3_gadget_free_endpoints(dwc); usb_put_gadget(dwc->gadget); diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c index e77fd86d09cf0..3f075c57605cb 100644 --- a/drivers/usb/dwc3/host.c +++ b/drivers/usb/dwc3/host.c @@ -226,7 +226,7 @@ void dwc3_host_exit(struct dwc3 *dwc) if (dwc->sys_wakeup) device_init_wakeup(&dwc->xhci->dev, false); - dwc3_enable_susphy(dwc, false); + dwc3_enable_susphy(dwc, true); platform_device_unregister(dwc->xhci); dwc->xhci = NULL; } From fd00f88ef36bbd850cbd409b210fe86aa53a2746 Mon Sep 17 00:00:00 2001 From: Haoxiang Li Date: Thu, 4 Dec 2025 21:21:29 +0800 Subject: [PATCH 1296/2333] usb: renesas_usbhs: Fix a resource leak in usbhs_pipe_malloc() commit 36cc7e09df9e43db21b46519b740145410dd9f4a upstream. usbhsp_get_pipe() set pipe's flags to IS_USED. In error paths, usbhsp_put_pipe() is required to clear pipe's flags to prevent pipe exhaustion. Fixes: f1407d5c6624 ("usb: renesas_usbhs: Add Renesas USBHS common code") Cc: stable Signed-off-by: Haoxiang Li Link: https://patch.msgid.link/20251204132129.109234-1-haoxiang_li2024@163.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/renesas_usbhs/pipe.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/usb/renesas_usbhs/pipe.c b/drivers/usb/renesas_usbhs/pipe.c index 75fff2e4cbc65..56fc3ff5016fc 100644 --- a/drivers/usb/renesas_usbhs/pipe.c +++ b/drivers/usb/renesas_usbhs/pipe.c @@ -713,11 +713,13 @@ struct usbhs_pipe *usbhs_pipe_malloc(struct usbhs_priv *priv, /* make sure pipe is not busy */ ret = usbhsp_pipe_barrier(pipe); if (ret < 0) { + usbhsp_put_pipe(pipe); dev_err(dev, "pipe setup failed %d\n", usbhs_pipe_number(pipe)); return NULL; } if (usbhsp_setup_pipecfg(pipe, is_host, dir_in, &pipecfg)) { + usbhsp_put_pipe(pipe); dev_err(dev, "can't setup pipe\n"); return NULL; } From 687ccc341f63cf21a351faa2196c82f0c90aff6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Bartosik?= Date: Thu, 27 Nov 2025 11:16:44 +0000 Subject: [PATCH 1297/2333] xhci: dbgtty: fix device unregister: fixup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 74098cc06e753d3ffd8398b040a3a1dfb65260c0 upstream. This fixup replaces tty_vhangup() call with call to tty_port_tty_vhangup(). Both calls hangup tty device synchronously however tty_port_tty_vhangup() increases reference count during the hangup operation using scoped_guard(tty_port_tty). Cc: stable Fixes: 1f73b8b56cf3 ("xhci: dbgtty: fix device unregister") Signed-off-by: Łukasz Bartosik Link: https://patch.msgid.link/20251127111644.3161386-1-ukaszb@google.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-dbgtty.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/host/xhci-dbgtty.c b/drivers/usb/host/xhci-dbgtty.c index 57cdda4e09c8e..90282e51e23ec 100644 --- a/drivers/usb/host/xhci-dbgtty.c +++ b/drivers/usb/host/xhci-dbgtty.c @@ -554,7 +554,7 @@ static void xhci_dbc_tty_unregister_device(struct xhci_dbc *dbc) * Hang up the TTY. This wakes up any blocked * writers and causes subsequent writes to fail. */ - tty_vhangup(port->port.tty); + tty_port_tty_vhangup(&port->port); tty_unregister_device(dbc_tty_driver, port->minor); xhci_dbc_tty_exit_port(port); From f83e3e9f89181b42f6076a115d767a7552c4a39e Mon Sep 17 00:00:00 2001 From: Tianchu Chen Date: Fri, 28 Nov 2025 15:53:23 +0800 Subject: [PATCH 1298/2333] char: applicom: fix NULL pointer dereference in ac_ioctl commit 82d12088c297fa1cef670e1718b3d24f414c23f7 upstream. Discovered by Atuin - Automated Vulnerability Discovery Engine. In ac_ioctl, the validation of IndexCard and the check for a valid RamIO pointer are skipped when cmd is 6. However, the function unconditionally executes readb(apbs[IndexCard].RamIO + VERS) at the end. If cmd is 6, IndexCard may reference a board that does not exist (where RamIO is NULL), leading to a NULL pointer dereference. Fix this by skipping the readb access when cmd is 6, as this command is a global information query and does not target a specific board context. Signed-off-by: Tianchu Chen Acked-by: Arnd Bergmann Cc: stable Link: https://patch.msgid.link/20251128155323.a786fde92ebb926cbe96fcb1@linux.dev Signed-off-by: Greg Kroah-Hartman --- drivers/char/applicom.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/char/applicom.c b/drivers/char/applicom.c index 9fed9706d9cd2..c138c468f3a44 100644 --- a/drivers/char/applicom.c +++ b/drivers/char/applicom.c @@ -835,7 +835,10 @@ static long ac_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ret = -ENOTTY; break; } - Dummy = readb(apbs[IndexCard].RamIO + VERS); + + if (cmd != 6) + Dummy = readb(apbs[IndexCard].RamIO + VERS); + kfree(adgl); mutex_unlock(&ac_mutex); return ret; From 1f53652922cd39d4547268f2962c24e1b7dfc8b0 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Fri, 14 Nov 2025 11:05:05 +0000 Subject: [PATCH 1299/2333] dt-bindings: slimbus: fix warning from example commit 4d4e746aa9f0f07261dcb41e4f51edb98723dcaa upstream. Fix below warnings generated dt_bindings_check for examples in the bindings. Documentation/devicetree/bindings/slimbus/slimbus.example.dtb: slim@28080000 (qcom,slim-ngd-v1.5.0): 'audio-codec@1,0' does not match any of the regexes: '^pinctrl-[0-9]+$', '^slim@[0-9a-f]+$' from schema $id: http://devicetree.org/schemas/slimbus/qcom,slim-ngd.yaml# Documentation/devicetree/bindings/slimbus/slimbus.example.dtb: slim@28080000 (qcom,slim-ngd-v1.5.0): #address-cells: 1 was expected from schema $id: http://devicetree.org/schemas/slimbus/qcom,slim-ngd.yaml# Documentation/devicetree/bindings/slimbus/slimbus.example.dtb: slim@28080000 (qcom,slim-ngd-v1.5.0): 'dmas' is a required property from schema $id: http://devicetree.org/schemas/slimbus/qcom,slim-ngd.yaml# Documentation/devicetree/bindings/slimbus/slimbus.example.dtb: slim@28080000 (qcom,slim-ngd-v1.5.0): 'dma-names' is a required property from schema $id: http://devicetree.org/schemas/slimbus/qcom,slim-ngd.yaml# Fixes: 7cbba32a2d62 ("slimbus: qcom: remove unused qcom controller driver") Cc: stable Reported-by: Rob Herring Signed-off-by: Srinivas Kandagatla Acked-by: Rob Herring (Arm) Signed-off-by: Srinivas Kandagatla Link: https://patch.msgid.link/20251114110505.143105-1-srini@kernel.org Signed-off-by: Greg Kroah-Hartman --- .../devicetree/bindings/slimbus/slimbus.yaml | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/Documentation/devicetree/bindings/slimbus/slimbus.yaml b/Documentation/devicetree/bindings/slimbus/slimbus.yaml index 89017d9cda109..5a941610ce4ed 100644 --- a/Documentation/devicetree/bindings/slimbus/slimbus.yaml +++ b/Documentation/devicetree/bindings/slimbus/slimbus.yaml @@ -75,16 +75,22 @@ examples: #size-cells = <1>; ranges; - slim@28080000 { + controller@28080000 { compatible = "qcom,slim-ngd-v1.5.0"; reg = <0x091c0000 0x2c000>; interrupts = ; - #address-cells = <2>; + dmas = <&slimbam 3>, <&slimbam 4>; + dma-names = "rx", "tx"; + #address-cells = <1>; #size-cells = <0>; - - audio-codec@1,0 { + slim@1 { + reg = <1>; + #address-cells = <2>; + #size-cells = <0>; + codec@1,0 { compatible = "slim217,1a0"; reg = <1 0>; + }; }; + }; }; - }; From 4157f7bba6299d4288f95e935a01beba82ebffb5 Mon Sep 17 00:00:00 2001 From: Ma Ke Date: Wed, 12 Nov 2025 17:17:23 +0800 Subject: [PATCH 1300/2333] intel_th: Fix error handling in intel_th_output_open commit 6d5925b667e4ed9e77c8278cc215191d29454a3f upstream. intel_th_output_open() calls bus_find_device_by_devt() which internally increments the device reference count via get_device(), but this reference is not properly released in several error paths. When device driver is unavailable, file operations cannot be obtained, or the driver's open method fails, the function returns without calling put_device(), leading to a permanent device reference count leak. This prevents the device from being properly released and could cause resource exhaustion over time. Found by code review. Cc: stable Fixes: 39f4034693b7 ("intel_th: Add driver infrastructure for Intel(R) Trace Hub devices") Signed-off-by: Ma Ke Link: https://patch.msgid.link/20251112091723.35963-1-make24@iscas.ac.cn Signed-off-by: Greg Kroah-Hartman --- drivers/hwtracing/intel_th/core.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/drivers/hwtracing/intel_th/core.c b/drivers/hwtracing/intel_th/core.c index 47d9e6c3bac04..fdb9d022d8753 100644 --- a/drivers/hwtracing/intel_th/core.c +++ b/drivers/hwtracing/intel_th/core.c @@ -810,13 +810,17 @@ static int intel_th_output_open(struct inode *inode, struct file *file) int err; dev = bus_find_device_by_devt(&intel_th_bus, inode->i_rdev); - if (!dev || !dev->driver) - return -ENODEV; + if (!dev || !dev->driver) { + err = -ENODEV; + goto out_no_device; + } thdrv = to_intel_th_driver(dev->driver); fops = fops_get(thdrv->fops); - if (!fops) - return -ENODEV; + if (!fops) { + err = -ENODEV; + goto out_put_device; + } replace_fops(file, fops); @@ -824,10 +828,16 @@ static int intel_th_output_open(struct inode *inode, struct file *file) if (file->f_op->open) { err = file->f_op->open(inode, file); - return err; + if (err) + goto out_put_device; } return 0; + +out_put_device: + put_device(dev); +out_no_device: + return err; } static const struct file_operations intel_th_output_fops = { From 670c2d09ac5708f6cfd85f9ecd77e9276c8ac948 Mon Sep 17 00:00:00 2001 From: Ma Ke Date: Tue, 4 Nov 2025 10:01:33 +0800 Subject: [PATCH 1301/2333] mei: Fix error handling in mei_register commit a6dab2f61d23c1eb32f1d08fa7b4919a2478950b upstream. mei_register() fails to release the device reference in error paths after device_initialize(). During normal device registration, the reference is properly handled through mei_deregister() which calls device_destroy(). However, in error handling paths (such as cdev_alloc failure, cdev_add failure, etc.), missing put_device() calls cause reference count leaks, preventing the device's release function (mei_device_release) from being called and resulting in memory leaks of mei_device. Found by code review. Cc: stable Fixes: 7704e6be4ed2 ("mei: hook mei_device on class device") Signed-off-by: Ma Ke Acked-by: Alexander Usyskin Link: https://patch.msgid.link/20251104020133.5017-1-make24@iscas.ac.cn Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c index 86a73684a3732..6f26d51607883 100644 --- a/drivers/misc/mei/main.c +++ b/drivers/misc/mei/main.c @@ -1307,6 +1307,7 @@ int mei_register(struct mei_device *dev, struct device *parent) err_del_cdev: cdev_del(dev->cdev); err: + put_device(&dev->dev); mei_minor_free(minor); return ret; } From 864deb6cf1c071cf10ef138e184c4666631dbcf8 Mon Sep 17 00:00:00 2001 From: Junxiao Chang Date: Sun, 9 Nov 2025 17:35:33 +0200 Subject: [PATCH 1302/2333] mei: gsc: add dependency on Xe driver commit 5d92c3b41f0bddfa416130c6e1b424414f3d2acf upstream. INTEL_MEI_GSC depends on either i915 or Xe and can be present when either of above is present. Cc: stable Fixes: 87a4c85d3a3e ("drm/xe/gsc: add gsc device support") Tested-by: Baoli Zhang Signed-off-by: Junxiao Chang Signed-off-by: Alexander Usyskin Link: https://patch.msgid.link/20251109153533.3179787-1-alexander.usyskin@intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/misc/mei/Kconfig b/drivers/misc/mei/Kconfig index f8b04e49e4baf..f4eb307cd35ed 100644 --- a/drivers/misc/mei/Kconfig +++ b/drivers/misc/mei/Kconfig @@ -49,7 +49,7 @@ config INTEL_MEI_TXE config INTEL_MEI_GSC tristate "Intel MEI GSC embedded device" depends on INTEL_MEI_ME - depends on DRM_I915 + depends on DRM_I915 || DRM_XE help Intel auxiliary driver for GSC devices embedded in Intel graphics devices. From c255a5164c58ae6c0f993e431843a965088e6ed8 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 27 Nov 2025 17:36:50 +0100 Subject: [PATCH 1303/2333] serial: core: Restore sysfs fwnode information commit 24ec03cc55126b7b3adf102f4b3d9f716532b329 upstream. The change that restores sysfs fwnode information does it only for OF cases. Update the fix to cover all possible types of fwnodes. Fixes: d36f0e9a0002 ("serial: core: restore of_node information in sysfs") Cc: stable Signed-off-by: Andy Shevchenko Link: https://patch.msgid.link/20251127163650.2942075-1-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial_base_bus.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/tty/serial/serial_base_bus.c b/drivers/tty/serial/serial_base_bus.c index 22749ab0428a7..8e891984cdc0d 100644 --- a/drivers/tty/serial/serial_base_bus.c +++ b/drivers/tty/serial/serial_base_bus.c @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include #include @@ -60,6 +60,7 @@ void serial_base_driver_unregister(struct device_driver *driver) driver_unregister(driver); } +/* On failure the caller must put device @dev with put_device() */ static int serial_base_device_init(struct uart_port *port, struct device *dev, struct device *parent_dev, @@ -73,7 +74,8 @@ static int serial_base_device_init(struct uart_port *port, dev->parent = parent_dev; dev->bus = &serial_base_bus_type; dev->release = release; - device_set_of_node_from_dev(dev, parent_dev); + + device_set_node(dev, fwnode_handle_get(dev_fwnode(parent_dev))); if (!serial_base_initialized) { dev_dbg(port->dev, "uart_add_one_port() called before arch_initcall()?\n"); @@ -94,7 +96,7 @@ static void serial_base_ctrl_release(struct device *dev) { struct serial_ctrl_device *ctrl_dev = to_serial_base_ctrl_device(dev); - of_node_put(dev->of_node); + fwnode_handle_put(dev_fwnode(dev)); kfree(ctrl_dev); } @@ -142,7 +144,7 @@ static void serial_base_port_release(struct device *dev) { struct serial_port_device *port_dev = to_serial_base_port_device(dev); - of_node_put(dev->of_node); + fwnode_handle_put(dev_fwnode(dev)); kfree(port_dev); } From 320578703ebeca2d96f818d547bacc8ea9afac3c Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Fri, 19 Dec 2025 16:28:12 +0100 Subject: [PATCH 1304/2333] serial: core: Fix serial device initialization commit f54151148b969fb4b62bec8093d255306d20df30 upstream. During restoring sysfs fwnode information the information of_node_reused was dropped. This was previously set by device_set_of_node_from_dev(). Add it back manually Fixes: 24ec03cc5512 ("serial: core: Restore sysfs fwnode information") Cc: stable Suggested-by: Cosmin Tanislav Signed-off-by: Alexander Stein Tested-by: Michael Walle Tested-by: Marek Szyprowski Tested-by: Cosmin Tanislav Link: https://patch.msgid.link/20251219152813.1893982-1-alexander.stein@ew.tq-group.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial_base_bus.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/tty/serial/serial_base_bus.c b/drivers/tty/serial/serial_base_bus.c index 8e891984cdc0d..1e1ad28d83fcf 100644 --- a/drivers/tty/serial/serial_base_bus.c +++ b/drivers/tty/serial/serial_base_bus.c @@ -74,6 +74,7 @@ static int serial_base_device_init(struct uart_port *port, dev->parent = parent_dev; dev->bus = &serial_base_bus_type; dev->release = release; + dev->of_node_reused = true; device_set_node(dev, fwnode_handle_get(dev_fwnode(parent_dev))); From 190dc4b74800746146db12ed669b26ac773003eb Mon Sep 17 00:00:00 2001 From: "j.turek" Date: Sun, 21 Dec 2025 11:32:21 +0100 Subject: [PATCH 1305/2333] serial: xilinx_uartps: fix rs485 delay_rts_after_send commit 267ee93c417e685d9f8e079e41c70ba6ee4df5a5 upstream. RTS line control with delay should be triggered when there is no more bytes in kfifo and hardware buffer is empty. Without this patch RTS control is scheduled right after feeding hardware buffer and this is too early. RTS line may change state before hardware buffer is empty. With this patch delayed RTS state change is triggered when function cdns_uart_handle_tx is called from cdns_uart_isr on CDNS_UART_IXR_TXEMPTY exactly when hardware completed transmission Fixes: fccc9d9233f9 ("tty: serial: uartps: Add rs485 support to uartps driver") Cc: stable Link: https://patch.msgid.link/20251221103221.1971125-1-jakub.turek@elsta.tech Signed-off-by: Jakub Turek Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/xilinx_uartps.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c index a66b44d21fba2..a354326a4242a 100644 --- a/drivers/tty/serial/xilinx_uartps.c +++ b/drivers/tty/serial/xilinx_uartps.c @@ -430,10 +430,17 @@ static void cdns_uart_handle_tx(void *dev_id) struct tty_port *tport = &port->state->port; unsigned int numbytes; unsigned char ch; + ktime_t rts_delay; if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port)) { /* Disable the TX Empty interrupt */ writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_IDR); + /* Set RTS line after delay */ + if (cdns_uart->port->rs485.flags & SER_RS485_ENABLED) { + cdns_uart->tx_timer.function = &cdns_rs485_rx_callback; + rts_delay = ns_to_ktime(cdns_calc_after_tx_delay(cdns_uart)); + hrtimer_start(&cdns_uart->tx_timer, rts_delay, HRTIMER_MODE_REL); + } return; } @@ -450,13 +457,6 @@ static void cdns_uart_handle_tx(void *dev_id) /* Enable the TX Empty interrupt */ writel(CDNS_UART_IXR_TXEMPTY, cdns_uart->port->membase + CDNS_UART_IER); - - if (cdns_uart->port->rs485.flags & SER_RS485_ENABLED && - (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port))) { - hrtimer_update_function(&cdns_uart->tx_timer, cdns_rs485_rx_callback); - hrtimer_start(&cdns_uart->tx_timer, - ns_to_ktime(cdns_calc_after_tx_delay(cdns_uart)), HRTIMER_MODE_REL); - } } /** From 17157612e40d90c13e5b571c91b0cf2b5b825770 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Wed, 17 Dec 2025 15:57:59 +0200 Subject: [PATCH 1306/2333] serial: sh-sci: Check that the DMA cookie is valid commit c3ca8a0aac832fe8047608bb2ae2cca314c6d717 upstream. The driver updates struct sci_port::tx_cookie to zero right before the TX work is scheduled, or to -EINVAL when DMA is disabled. dma_async_is_complete(), called through dma_cookie_status() (and possibly through dmaengine_tx_status()), considers cookies valid only if they have values greater than or equal to 1. Passing zero or -EINVAL to dmaengine_tx_status() before any TX DMA transfer has started leads to an incorrect TX status being reported, as the cookie is invalid for the DMA subsystem. This may cause long wait times when the serial device is opened for configuration before any TX activity has occurred. Check that the TX cookie is valid before passing it to dmaengine_tx_status(). Fixes: 7cc0e0a43a91 ("serial: sh-sci: Check if TX data was written to device in .tx_empty()") Cc: stable Signed-off-by: Claudiu Beznea Link: https://patch.msgid.link/20251217135759.402015-1-claudiu.beznea.uj@bp.renesas.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sh-sci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 1db4af6fe5909..d91b1fb69bebd 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -1740,7 +1740,7 @@ static void sci_dma_check_tx_occurred(struct sci_port *s) struct dma_tx_state state; enum dma_status status; - if (!s->chan_tx) + if (!s->chan_tx || s->cookie_tx <= 0) return; status = dmaengine_tx_status(s->chan_tx, s->cookie_tx, &state); From 87f11fea5acb300dfe491715868367a1d4bdd9a4 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 13 Nov 2025 14:24:31 +0100 Subject: [PATCH 1307/2333] cpuidle: governors: teo: Drop misguided target residency check commit a03b2011808ab02ccb7ab6b573b013b77fbb5921 upstream. When the target residency of the current candidate idle state is greater than the expected time till the closest timer (the sleep length), it does not matter whether or not the tick has already been stopped or if it is going to be stopped. The closest timer will trigger anyway at its due time, so if an idle state with target residency above the sleep length is selected, energy will be wasted and there may be excess latency. Of course, if the closest timer were canceled before it could trigger, a deeper idle state would be more suitable, but this is not expected to happen (generally speaking, hrtimers are not expected to be canceled as a rule). Accordingly, the teo_state_ok() check done in that case causes energy to be wasted more often than it allows any energy to be saved (if it allows any energy to be saved at all), so drop it and let the governor use the teo_find_shallower_state() return value as the new candidate idle state index. Fixes: 21d28cd2fa5f ("cpuidle: teo: Do not call tick_nohz_get_sleep_length() upfront") Cc: All applicable Signed-off-by: Rafael J. Wysocki Reviewed-by: Christian Loehle Tested-by: Christian Loehle Link: https://patch.msgid.link/5955081.DvuYhMxLoT@rafael.j.wysocki Signed-off-by: Greg Kroah-Hartman --- drivers/cpuidle/governors/teo.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/cpuidle/governors/teo.c b/drivers/cpuidle/governors/teo.c index bfa55c1eab5bc..8078eca72ca53 100644 --- a/drivers/cpuidle/governors/teo.c +++ b/drivers/cpuidle/governors/teo.c @@ -458,11 +458,8 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, * If the closest expected timer is before the target residency of the * candidate state, a shallower one needs to be found. */ - if (drv->states[idx].target_residency_ns > duration_ns) { - i = teo_find_shallower_state(drv, dev, idx, duration_ns, false); - if (teo_state_ok(i, drv)) - idx = i; - } + if (drv->states[idx].target_residency_ns > duration_ns) + idx = teo_find_shallower_state(drv, dev, idx, duration_ns, false); /* * If the selected state's target residency is below the tick length From 8f92817b6f100397d24a59a153f96a67fee2a7bc Mon Sep 17 00:00:00 2001 From: Miaoqian Lin Date: Mon, 27 Oct 2025 23:04:45 +0800 Subject: [PATCH 1308/2333] cpufreq: nforce2: fix reference count leak in nforce2 commit 9600156bb99852c216a2128cdf9f114eb67c350f upstream. There are two reference count leaks in this driver: 1. In nforce2_fsb_read(): pci_get_subsys() increases the reference count of the PCI device, but pci_dev_put() is never called to release it, thus leaking the reference. 2. In nforce2_detect_chipset(): pci_get_subsys() gets a reference to the nforce2_dev which is stored in a global variable, but the reference is never released when the module is unloaded. Fix both by: - Adding pci_dev_put(nforce2_sub5) in nforce2_fsb_read() after reading the configuration. - Adding pci_dev_put(nforce2_dev) in nforce2_exit() to release the global device reference. Found via static analysis. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Cc: stable@vger.kernel.org Signed-off-by: Miaoqian Lin Signed-off-by: Viresh Kumar Signed-off-by: Greg Kroah-Hartman --- drivers/cpufreq/cpufreq-nforce2.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/cpufreq/cpufreq-nforce2.c b/drivers/cpufreq/cpufreq-nforce2.c index fedad1081973f..fbbbe501cf2dc 100644 --- a/drivers/cpufreq/cpufreq-nforce2.c +++ b/drivers/cpufreq/cpufreq-nforce2.c @@ -145,6 +145,8 @@ static unsigned int nforce2_fsb_read(int bootfsb) pci_read_config_dword(nforce2_sub5, NFORCE2_BOOTFSB, &fsb); fsb /= 1000000; + pci_dev_put(nforce2_sub5); + /* Check if PLL register is already set */ pci_read_config_byte(nforce2_dev, NFORCE2_PLLENABLE, (u8 *)&temp); @@ -426,6 +428,7 @@ static int __init nforce2_init(void) static void __exit nforce2_exit(void) { cpufreq_unregister_driver(&nforce2_driver); + pci_dev_put(nforce2_dev); } module_init(nforce2_init); From 1c728951bc769b795d377852eae1abddad88635d Mon Sep 17 00:00:00 2001 From: Tony Battersby Date: Mon, 10 Nov 2025 10:47:35 -0500 Subject: [PATCH 1309/2333] scsi: Revert "scsi: qla2xxx: Perform lockless command completion in abort path" commit b57fbc88715b6d18f379463f48a15b560b087ffe upstream. This reverts commit 0367076b0817d5c75dfb83001ce7ce5c64d803a9. The commit being reverted added code to __qla2x00_abort_all_cmds() to call sp->done() without holding a spinlock. But unlike the older code below it, this new code failed to check sp->cmd_type and just assumed TYPE_SRB, which results in a jump to an invalid pointer in target-mode with TYPE_TGT_CMD: qla2xxx [0000:65:00.0]-d034:8: qla24xx_do_nack_work create sess success 0000000009f7a79b qla2xxx [0000:65:00.0]-5003:8: ISP System Error - mbx1=1ff5h mbx2=10h mbx3=0h mbx4=0h mbx5=191h mbx6=0h mbx7=0h. qla2xxx [0000:65:00.0]-d01e:8: -> fwdump no buffer qla2xxx [0000:65:00.0]-f03a:8: qla_target(0): System error async event 0x8002 occurred qla2xxx [0000:65:00.0]-00af:8: Performing ISP error recovery - ha=0000000058183fda. BUG: kernel NULL pointer dereference, address: 0000000000000000 PF: supervisor instruction fetch in kernel mode PF: error_code(0x0010) - not-present page PGD 0 P4D 0 Oops: 0010 [#1] SMP CPU: 2 PID: 9446 Comm: qla2xxx_8_dpc Tainted: G O 6.1.133 #1 Hardware name: Supermicro Super Server/X11SPL-F, BIOS 4.2 12/15/2023 RIP: 0010:0x0 Code: Unable to access opcode bytes at 0xffffffffffffffd6. RSP: 0018:ffffc90001f93dc8 EFLAGS: 00010206 RAX: 0000000000000282 RBX: 0000000000000355 RCX: ffff88810d16a000 RDX: ffff88810dbadaa8 RSI: 0000000000080000 RDI: ffff888169dc38c0 RBP: ffff888169dc38c0 R08: 0000000000000001 R09: 0000000000000045 R10: ffffffffa034bdf0 R11: 0000000000000000 R12: ffff88810800bb40 R13: 0000000000001aa8 R14: ffff888100136610 R15: ffff8881070f7400 FS: 0000000000000000(0000) GS:ffff88bf80080000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: ffffffffffffffd6 CR3: 000000010c8ff006 CR4: 00000000003706e0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 Call Trace: ? __die+0x4d/0x8b ? page_fault_oops+0x91/0x180 ? trace_buffer_unlock_commit_regs+0x38/0x1a0 ? exc_page_fault+0x391/0x5e0 ? asm_exc_page_fault+0x22/0x30 __qla2x00_abort_all_cmds+0xcb/0x3e0 [qla2xxx_scst] qla2x00_abort_all_cmds+0x50/0x70 [qla2xxx_scst] qla2x00_abort_isp_cleanup+0x3b7/0x4b0 [qla2xxx_scst] qla2x00_abort_isp+0xfd/0x860 [qla2xxx_scst] qla2x00_do_dpc+0x581/0xa40 [qla2xxx_scst] kthread+0xa8/0xd0 Then commit 4475afa2646d ("scsi: qla2xxx: Complete command early within lock") added the spinlock back, because not having the lock caused a race and a crash. But qla2x00_abort_srb() in the switch below already checks for qla2x00_chip_is_down() and handles it the same way, so the code above the switch is now redundant and still buggy in target-mode. Remove it. Cc: stable@vger.kernel.org Signed-off-by: Tony Battersby Link: https://patch.msgid.link/3a8022dc-bcfd-4b01-9f9b-7a9ec61fa2a3@cybernetics.com Signed-off-by: Martin K. Petersen Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/qla2xxx/qla_os.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 6b0f616b1ca0a..fd32b30a5b38b 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -1862,12 +1862,6 @@ __qla2x00_abort_all_cmds(struct qla_qpair *qp, int res) for (cnt = 1; cnt < req->num_outstanding_cmds; cnt++) { sp = req->outstanding_cmds[cnt]; if (sp) { - if (qla2x00_chip_is_down(vha)) { - req->outstanding_cmds[cnt] = NULL; - sp->done(sp, res); - continue; - } - switch (sp->cmd_type) { case TYPE_SRB: qla2x00_abort_srb(qp, sp, res, &flags); From 751c19635c2bfaaf2836a533caa3663633066dcf Mon Sep 17 00:00:00 2001 From: Junrui Luo Date: Wed, 29 Oct 2025 00:29:04 +0800 Subject: [PATCH 1310/2333] scsi: aic94xx: fix use-after-free in device removal path commit f6ab594672d4cba08540919a4e6be2e202b60007 upstream. The asd_pci_remove() function fails to synchronize with pending tasklets before freeing the asd_ha structure, leading to a potential use-after-free vulnerability. When a device removal is triggered (via hot-unplug or module unload), race condition can occur. The fix adds tasklet_kill() before freeing the asd_ha structure, ensuring all scheduled tasklets complete before cleanup proceeds. Reported-by: Yuhao Jiang Reported-by: Junrui Luo Fixes: 2908d778ab3e ("[SCSI] aic94xx: new driver") Cc: stable@vger.kernel.org Signed-off-by: Junrui Luo Link: https://patch.msgid.link/ME2PR01MB3156AB7DCACA206C845FC7E8AFFDA@ME2PR01MB3156.ausprd01.prod.outlook.com Signed-off-by: Martin K. Petersen Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/aic94xx/aic94xx_init.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/scsi/aic94xx/aic94xx_init.c b/drivers/scsi/aic94xx/aic94xx_init.c index adf3d91456064..95f3620059f7d 100644 --- a/drivers/scsi/aic94xx/aic94xx_init.c +++ b/drivers/scsi/aic94xx/aic94xx_init.c @@ -882,6 +882,9 @@ static void asd_pci_remove(struct pci_dev *dev) asd_disable_ints(asd_ha); + /* Ensure all scheduled tasklets complete before freeing resources */ + tasklet_kill(&asd_ha->seq.dl_tasklet); + asd_remove_dev_attrs(asd_ha); /* XXX more here as needed */ From 8c5ce5fafe9c78426ab66416b3373796b9b1db45 Mon Sep 17 00:00:00 2001 From: Dai Ngo Date: Wed, 5 Nov 2025 12:45:54 -0800 Subject: [PATCH 1311/2333] NFSD: use correct reservation type in nfsd4_scsi_fence_client commit 6f52063db9aabdaabea929b1e998af98c2e8d917 upstream. The reservation type argument for the pr_preempt call should match the one used in nfsd4_block_get_device_info_scsi. Fixes: f99d4fbdae67 ("nfsd: add SCSI layout support") Cc: stable@vger.kernel.org Signed-off-by: Dai Ngo Reviewed-by: Christoph Hellwig Signed-off-by: Chuck Lever Signed-off-by: Greg Kroah-Hartman --- fs/nfsd/blocklayout.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/nfsd/blocklayout.c b/fs/nfsd/blocklayout.c index 425648565ab2d..e9512c34c9dcf 100644 --- a/fs/nfsd/blocklayout.c +++ b/fs/nfsd/blocklayout.c @@ -344,7 +344,8 @@ nfsd4_scsi_fence_client(struct nfs4_layout_stateid *ls, struct nfsd_file *file) struct block_device *bdev = file->nf_file->f_path.mnt->mnt_sb->s_bdev; bdev->bd_disk->fops->pr_ops->pr_preempt(bdev, NFSD_MDS_PR_KEY, - nfsd4_scsi_pr_key(clp), 0, true); + nfsd4_scsi_pr_key(clp), + PR_EXCLUSIVE_ACCESS_REG_ONLY, true); } const struct nfsd4_layout_ops scsi_layout_ops = { From 8edbb9e371af186b4cf40819dab65fafe109df4d Mon Sep 17 00:00:00 2001 From: Andrey Vatoropin Date: Tue, 18 Nov 2025 08:42:31 +0000 Subject: [PATCH 1312/2333] scsi: target: Reset t_task_cdb pointer in error case commit 5053eab38a4c4543522d0c320c639c56a8b59908 upstream. If allocation of cmd->t_task_cdb fails, it remains NULL but is later dereferenced in the 'err' path. In case of error, reset NULL t_task_cdb value to point at the default fixed-size buffer. Found by Linux Verification Center (linuxtesting.org) with SVACE. Fixes: 9e95fb805dc0 ("scsi: target: Fix NULL pointer dereference") Cc: stable@vger.kernel.org Signed-off-by: Andrey Vatoropin Reviewed-by: Mike Christie Link: https://patch.msgid.link/20251118084014.324940-1-a.vatoropin@crpt.ru Signed-off-by: Martin K. Petersen Signed-off-by: Greg Kroah-Hartman --- drivers/target/target_core_transport.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 0a76bdfe55282..88544c911949c 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -1524,6 +1524,7 @@ target_cmd_init_cdb(struct se_cmd *cmd, unsigned char *cdb, gfp_t gfp) if (scsi_command_size(cdb) > sizeof(cmd->__t_task_cdb)) { cmd->t_task_cdb = kzalloc(scsi_command_size(cdb), gfp); if (!cmd->t_task_cdb) { + cmd->t_task_cdb = &cmd->__t_task_cdb[0]; pr_err("Unable to allocate cmd->t_task_cdb" " %u > sizeof(cmd->__t_task_cdb): %lu ops\n", scsi_command_size(cdb), From a0d4e9e24474fa739cea696b5757071e80cb6858 Mon Sep 17 00:00:00 2001 From: Chandrakanth Patil Date: Thu, 11 Dec 2025 05:59:29 +0530 Subject: [PATCH 1313/2333] scsi: mpi3mr: Read missing IOCFacts flag for reply queue full overflow commit d373163194982f43b92c552c138c29d9f0b79553 upstream. The driver was not reading the MAX_REQ_PER_REPLY_QUEUE_LIMIT IOCFacts flag, so the reply-queue-full handling was never enabled, even on firmware that supports it. Reading this flag enables the feature and prevents reply queue overflow. Fixes: f08b24d82749 ("scsi: mpi3mr: Avoid reply queue full condition") Cc: stable@vger.kernel.org Signed-off-by: Chandrakanth Patil Link: https://patch.msgid.link/20251211002929.22071-1-chandrakanth.patil@broadcom.com Signed-off-by: Martin K. Petersen Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/mpi3mr/mpi/mpi30_ioc.h | 1 + drivers/scsi/mpi3mr/mpi3mr_fw.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/drivers/scsi/mpi3mr/mpi/mpi30_ioc.h b/drivers/scsi/mpi3mr/mpi/mpi30_ioc.h index b42933fcd4233..6561f98c3cb2d 100644 --- a/drivers/scsi/mpi3mr/mpi/mpi30_ioc.h +++ b/drivers/scsi/mpi3mr/mpi/mpi30_ioc.h @@ -166,6 +166,7 @@ struct mpi3_ioc_facts_data { #define MPI3_IOCFACTS_FLAGS_SIGNED_NVDATA_REQUIRED (0x00010000) #define MPI3_IOCFACTS_FLAGS_DMA_ADDRESS_WIDTH_MASK (0x0000ff00) #define MPI3_IOCFACTS_FLAGS_DMA_ADDRESS_WIDTH_SHIFT (8) +#define MPI3_IOCFACTS_FLAGS_MAX_REQ_PER_REPLY_QUEUE_LIMIT (0x00000040) #define MPI3_IOCFACTS_FLAGS_INITIAL_PORT_ENABLE_MASK (0x00000030) #define MPI3_IOCFACTS_FLAGS_INITIAL_PORT_ENABLE_SHIFT (4) #define MPI3_IOCFACTS_FLAGS_INITIAL_PORT_ENABLE_NOT_STARTED (0x00000000) diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c index 8fe6e0bf342e2..8c4bb7169a87c 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_fw.c +++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c @@ -3158,6 +3158,8 @@ static void mpi3mr_process_factsdata(struct mpi3mr_ioc *mrioc, mrioc->facts.dma_mask = (facts_flags & MPI3_IOCFACTS_FLAGS_DMA_ADDRESS_WIDTH_MASK) >> MPI3_IOCFACTS_FLAGS_DMA_ADDRESS_WIDTH_SHIFT; + mrioc->facts.max_req_limit = (facts_flags & + MPI3_IOCFACTS_FLAGS_MAX_REQ_PER_REPLY_QUEUE_LIMIT); mrioc->facts.protocol_flags = facts_data->protocol_flags; mrioc->facts.mpi_version = le32_to_cpu(facts_data->mpi_version.word); mrioc->facts.max_reqs = le16_to_cpu(facts_data->max_outstanding_requests); From 3fb2db6f50eab78f81455d137ed8987541d16e9f Mon Sep 17 00:00:00 2001 From: Seunghwan Baek Date: Wed, 10 Dec 2025 15:38:54 +0900 Subject: [PATCH 1314/2333] scsi: ufs: core: Add ufshcd_update_evt_hist() for UFS suspend error commit c9f36f04a8a2725172cdf2b5e32363e4addcb14c upstream. If UFS resume fails, the event history is updated in ufshcd_resume(), but there is no code anywhere to record UFS suspend. Therefore, add code to record UFS suspend error event history. Fixes: dd11376b9f1b ("scsi: ufs: Split the drivers/scsi/ufs directory") Cc: stable@vger.kernel.org Signed-off-by: Seunghwan Baek Reviewed-by: Peter Wang Link: https://patch.msgid.link/20251210063854.1483899-2-sh8267.baek@samsung.com Signed-off-by: Martin K. Petersen Signed-off-by: Greg Kroah-Hartman --- drivers/ufs/core/ufshcd.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index a921a9098a291..ba1bb3953cf69 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -10223,7 +10223,7 @@ static int ufshcd_suspend(struct ufs_hba *hba) ret = ufshcd_setup_clocks(hba, false); if (ret) { ufshcd_enable_irq(hba); - return ret; + goto out; } if (ufshcd_is_clkgating_allowed(hba)) { hba->clk_gating.state = CLKS_OFF; @@ -10235,6 +10235,9 @@ static int ufshcd_suspend(struct ufs_hba *hba) /* Put the host controller in low power mode if possible */ ufshcd_hba_vreg_set_lpm(hba); ufshcd_pm_qos_update(hba, false); +out: + if (ret) + ufshcd_update_evt_hist(hba, UFS_EVT_SUSPEND_ERR, (u32)ret); return ret; } From 0b36fae23621a09e772c8adf918b9011158f8511 Mon Sep 17 00:00:00 2001 From: Jan Prusakowski Date: Mon, 6 Oct 2025 10:46:15 +0200 Subject: [PATCH 1315/2333] f2fs: ensure node page reads complete before f2fs_put_super() finishes commit 297baa4aa263ff8f5b3d246ee16a660d76aa82c4 upstream. Xfstests generic/335, generic/336 sometimes crash with the following message: F2FS-fs (dm-0): detect filesystem reference count leak during umount, type: 9, count: 1 ------------[ cut here ]------------ kernel BUG at fs/f2fs/super.c:1939! Oops: invalid opcode: 0000 [#1] SMP NOPTI CPU: 1 UID: 0 PID: 609351 Comm: umount Tainted: G W 6.17.0-rc5-xfstests-g9dd1835ecda5 #1 PREEMPT(none) Tainted: [W]=WARN Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 RIP: 0010:f2fs_put_super+0x3b3/0x3c0 Call Trace: generic_shutdown_super+0x7e/0x190 kill_block_super+0x1a/0x40 kill_f2fs_super+0x9d/0x190 deactivate_locked_super+0x30/0xb0 cleanup_mnt+0xba/0x150 task_work_run+0x5c/0xa0 exit_to_user_mode_loop+0xb7/0xc0 do_syscall_64+0x1ae/0x1c0 entry_SYSCALL_64_after_hwframe+0x76/0x7e ---[ end trace 0000000000000000 ]--- It appears that sometimes it is possible that f2fs_put_super() is called before all node page reads are completed. Adding a call to f2fs_wait_on_all_pages() for F2FS_RD_NODE fixes the problem. Cc: stable@kernel.org Fixes: 20872584b8c0b ("f2fs: fix to drop all dirty meta/node pages during umount()") Signed-off-by: Jan Prusakowski Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim Signed-off-by: Greg Kroah-Hartman --- fs/f2fs/super.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 9085b4a511a48..256cb567b0724 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -1988,14 +1988,6 @@ static void f2fs_put_super(struct super_block *sb) truncate_inode_pages_final(META_MAPPING(sbi)); } - for (i = 0; i < NR_COUNT_TYPE; i++) { - if (!get_pages(sbi, i)) - continue; - f2fs_err(sbi, "detect filesystem reference count leak during " - "umount, type: %d, count: %lld", i, get_pages(sbi, i)); - f2fs_bug_on(sbi, 1); - } - f2fs_bug_on(sbi, sbi->fsync_node_num); f2fs_destroy_compress_inode(sbi); @@ -2006,6 +1998,15 @@ static void f2fs_put_super(struct super_block *sb) iput(sbi->meta_inode); sbi->meta_inode = NULL; + /* Should check the page counts after dropping all node/meta pages */ + for (i = 0; i < NR_COUNT_TYPE; i++) { + if (!get_pages(sbi, i)) + continue; + f2fs_err(sbi, "detect filesystem reference count leak during " + "umount, type: %d, count: %lld", i, get_pages(sbi, i)); + f2fs_bug_on(sbi, 1); + } + /* * iput() can update stat information, if f2fs_write_checkpoint() * above failed with error. From 0df713a9c082a474c8b0bcf670edc8e98461d5a0 Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Wed, 22 Oct 2025 11:06:36 +0800 Subject: [PATCH 1316/2333] f2fs: fix to avoid updating compression context during writeback commit 10b591e7fb7cdc8c1e53e9c000dc0ef7069aaa76 upstream. Bai, Shuangpeng reported a bug as below: Oops: divide error: 0000 [#1] SMP KASAN PTI CPU: 0 UID: 0 PID: 11441 Comm: syz.0.46 Not tainted 6.17.0 #1 PREEMPT(full) Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.15.0-1 04/01/2014 RIP: 0010:f2fs_all_cluster_page_ready+0x106/0x550 fs/f2fs/compress.c:857 Call Trace: f2fs_write_cache_pages fs/f2fs/data.c:3078 [inline] __f2fs_write_data_pages fs/f2fs/data.c:3290 [inline] f2fs_write_data_pages+0x1c19/0x3600 fs/f2fs/data.c:3317 do_writepages+0x38e/0x640 mm/page-writeback.c:2634 filemap_fdatawrite_wbc mm/filemap.c:386 [inline] __filemap_fdatawrite_range mm/filemap.c:419 [inline] file_write_and_wait_range+0x2ba/0x3e0 mm/filemap.c:794 f2fs_do_sync_file+0x6e6/0x1b00 fs/f2fs/file.c:294 generic_write_sync include/linux/fs.h:3043 [inline] f2fs_file_write_iter+0x76e/0x2700 fs/f2fs/file.c:5259 new_sync_write fs/read_write.c:593 [inline] vfs_write+0x7e9/0xe00 fs/read_write.c:686 ksys_write+0x19d/0x2d0 fs/read_write.c:738 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] do_syscall_64+0xf7/0x470 arch/x86/entry/syscall_64.c:94 entry_SYSCALL_64_after_hwframe+0x77/0x7f The bug was triggered w/ below race condition: fsync setattr ioctl - f2fs_do_sync_file - file_write_and_wait_range - f2fs_write_cache_pages : inode is non-compressed : cc.cluster_size = F2FS_I(inode)->i_cluster_size = 0 - tag_pages_for_writeback - f2fs_setattr - truncate_setsize - f2fs_truncate - f2fs_fileattr_set - f2fs_setflags_common - set_compress_context : F2FS_I(inode)->i_cluster_size = 4 : set_inode_flag(inode, FI_COMPRESSED_FILE) - f2fs_compressed_file : return true - f2fs_all_cluster_page_ready : "pgidx % cc->cluster_size" trigger dividing 0 issue Let's change as below to fix this issue: - introduce a new atomic type variable .writeback in structure f2fs_inode_info to track the number of threads which calling f2fs_write_cache_pages(). - use .i_sem lock to protect .writeback update. - check .writeback before update compression context in f2fs_setflags_common() to avoid race w/ ->writepages. Fixes: 4c8ff7095bef ("f2fs: support data compression") Cc: stable@kernel.org Reported-by: Bai, Shuangpeng Tested-by: Bai, Shuangpeng Closes: https://lore.kernel.org/lkml/44D8F7B3-68AD-425F-9915-65D27591F93F@psu.edu Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim Signed-off-by: Greg Kroah-Hartman --- fs/f2fs/data.c | 17 +++++++++++++++++ fs/f2fs/f2fs.h | 3 ++- fs/f2fs/file.c | 5 +++-- fs/f2fs/super.c | 1 + 4 files changed, 23 insertions(+), 3 deletions(-) diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index 775aa4f63aa30..0f9446143c8e1 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -3224,6 +3224,19 @@ static inline bool __should_serialize_io(struct inode *inode, return false; } +static inline void account_writeback(struct inode *inode, bool inc) +{ + if (!f2fs_sb_has_compression(F2FS_I_SB(inode))) + return; + + f2fs_down_read(&F2FS_I(inode)->i_sem); + if (inc) + atomic_inc(&F2FS_I(inode)->writeback); + else + atomic_dec(&F2FS_I(inode)->writeback); + f2fs_up_read(&F2FS_I(inode)->i_sem); +} + static int __f2fs_write_data_pages(struct address_space *mapping, struct writeback_control *wbc, enum iostat_type io_type) @@ -3269,10 +3282,14 @@ static int __f2fs_write_data_pages(struct address_space *mapping, locked = true; } + account_writeback(inode, true); + blk_start_plug(&plug); ret = f2fs_write_cache_pages(mapping, wbc, io_type); blk_finish_plug(&plug); + account_writeback(inode, false); + if (locked) mutex_unlock(&sbi->writepages); diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 5149f351f03d2..2ff617820f13a 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -948,6 +948,7 @@ struct f2fs_inode_info { unsigned char i_compress_level; /* compress level (lz4hc,zstd) */ unsigned char i_compress_flag; /* compress flag */ unsigned int i_cluster_size; /* cluster size */ + atomic_t writeback; /* count # of writeback thread */ unsigned int atomic_write_cnt; loff_t original_i_size; /* original i_size before atomic write */ @@ -4675,7 +4676,7 @@ static inline bool f2fs_disable_compressed_file(struct inode *inode) f2fs_up_write(&fi->i_sem); return true; } - if (f2fs_is_mmap_file(inode) || + if (f2fs_is_mmap_file(inode) || atomic_read(&fi->writeback) || (S_ISREG(inode->i_mode) && F2FS_HAS_BLOCKS(inode))) { f2fs_up_write(&fi->i_sem); return false; diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index ffa045b39c01d..c641a0209956e 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -2125,8 +2125,9 @@ static int f2fs_setflags_common(struct inode *inode, u32 iflags, u32 mask) f2fs_down_write(&fi->i_sem); if (!f2fs_may_compress(inode) || - (S_ISREG(inode->i_mode) && - F2FS_HAS_BLOCKS(inode))) { + atomic_read(&fi->writeback) || + (S_ISREG(inode->i_mode) && + F2FS_HAS_BLOCKS(inode))) { f2fs_up_write(&fi->i_sem); return -EINVAL; } diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 256cb567b0724..10f09c85b4628 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -1759,6 +1759,7 @@ static struct inode *f2fs_alloc_inode(struct super_block *sb) atomic_set(&fi->dirty_pages, 0); atomic_set(&fi->i_compr_blocks, 0); atomic_set(&fi->open_count, 0); + atomic_set(&fi->writeback, 0); init_f2fs_rwsem(&fi->i_sem); spin_lock_init(&fi->i_size_lock); INIT_LIST_HEAD(&fi->dirty_list); From 86a85a7b622e6e8dba69810257733ce5eab5ed55 Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Tue, 14 Oct 2025 19:47:35 +0800 Subject: [PATCH 1317/2333] f2fs: fix to avoid potential deadlock commit ca8b201f28547e28343a6f00a6e91fa8c09572fe upstream. As Jiaming Zhang and syzbot reported, there is potential deadlock in f2fs as below: Chain exists of: &sbi->cp_rwsem --> fs_reclaim --> sb_internal#2 Possible unsafe locking scenario: CPU0 CPU1 ---- ---- rlock(sb_internal#2); lock(fs_reclaim); lock(sb_internal#2); rlock(&sbi->cp_rwsem); *** DEADLOCK *** 3 locks held by kswapd0/73: #0: ffffffff8e247a40 (fs_reclaim){+.+.}-{0:0}, at: balance_pgdat mm/vmscan.c:7015 [inline] #0: ffffffff8e247a40 (fs_reclaim){+.+.}-{0:0}, at: kswapd+0x951/0x2800 mm/vmscan.c:7389 #1: ffff8880118400e0 (&type->s_umount_key#50){.+.+}-{4:4}, at: super_trylock_shared fs/super.c:562 [inline] #1: ffff8880118400e0 (&type->s_umount_key#50){.+.+}-{4:4}, at: super_cache_scan+0x91/0x4b0 fs/super.c:197 #2: ffff888011840610 (sb_internal#2){.+.+}-{0:0}, at: f2fs_evict_inode+0x8d9/0x1b60 fs/f2fs/inode.c:890 stack backtrace: CPU: 0 UID: 0 PID: 73 Comm: kswapd0 Not tainted syzkaller #0 PREEMPT(full) Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2~bpo12+1 04/01/2014 Call Trace: dump_stack_lvl+0x189/0x250 lib/dump_stack.c:120 print_circular_bug+0x2ee/0x310 kernel/locking/lockdep.c:2043 check_noncircular+0x134/0x160 kernel/locking/lockdep.c:2175 check_prev_add kernel/locking/lockdep.c:3165 [inline] check_prevs_add kernel/locking/lockdep.c:3284 [inline] validate_chain+0xb9b/0x2140 kernel/locking/lockdep.c:3908 __lock_acquire+0xab9/0xd20 kernel/locking/lockdep.c:5237 lock_acquire+0x120/0x360 kernel/locking/lockdep.c:5868 down_read+0x46/0x2e0 kernel/locking/rwsem.c:1537 f2fs_down_read fs/f2fs/f2fs.h:2278 [inline] f2fs_lock_op fs/f2fs/f2fs.h:2357 [inline] f2fs_do_truncate_blocks+0x21c/0x10c0 fs/f2fs/file.c:791 f2fs_truncate_blocks+0x10a/0x300 fs/f2fs/file.c:867 f2fs_truncate+0x489/0x7c0 fs/f2fs/file.c:925 f2fs_evict_inode+0x9f2/0x1b60 fs/f2fs/inode.c:897 evict+0x504/0x9c0 fs/inode.c:810 f2fs_evict_inode+0x1dc/0x1b60 fs/f2fs/inode.c:853 evict+0x504/0x9c0 fs/inode.c:810 dispose_list fs/inode.c:852 [inline] prune_icache_sb+0x21b/0x2c0 fs/inode.c:1000 super_cache_scan+0x39b/0x4b0 fs/super.c:224 do_shrink_slab+0x6ef/0x1110 mm/shrinker.c:437 shrink_slab_memcg mm/shrinker.c:550 [inline] shrink_slab+0x7ef/0x10d0 mm/shrinker.c:628 shrink_one+0x28a/0x7c0 mm/vmscan.c:4955 shrink_many mm/vmscan.c:5016 [inline] lru_gen_shrink_node mm/vmscan.c:5094 [inline] shrink_node+0x315d/0x3780 mm/vmscan.c:6081 kswapd_shrink_node mm/vmscan.c:6941 [inline] balance_pgdat mm/vmscan.c:7124 [inline] kswapd+0x147c/0x2800 mm/vmscan.c:7389 kthread+0x70e/0x8a0 kernel/kthread.c:463 ret_from_fork+0x4bc/0x870 arch/x86/kernel/process.c:158 ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245 The root cause is deadlock among four locks as below: kswapd - fs_reclaim --- Lock A - shrink_one - evict - f2fs_evict_inode - sb_start_intwrite --- Lock B - iput - evict - f2fs_evict_inode - sb_start_intwrite --- Lock B - f2fs_truncate - f2fs_truncate_blocks - f2fs_do_truncate_blocks - f2fs_lock_op --- Lock C ioctl - f2fs_ioc_commit_atomic_write - f2fs_lock_op --- Lock C - __f2fs_commit_atomic_write - __replace_atomic_write_block - f2fs_get_dnode_of_data - __get_node_folio - f2fs_check_nid_range - f2fs_handle_error - f2fs_record_errors - f2fs_down_write --- Lock D open - do_open - do_truncate - security_inode_need_killpriv - f2fs_getxattr - lookup_all_xattrs - f2fs_handle_error - f2fs_record_errors - f2fs_down_write --- Lock D - f2fs_commit_super - read_mapping_folio - filemap_alloc_folio_noprof - prepare_alloc_pages - fs_reclaim_acquire --- Lock A In order to avoid such deadlock, we need to avoid grabbing sb_lock in f2fs_handle_error(), so, let's use asynchronous method instead: - remove f2fs_handle_error() implementation - rename f2fs_handle_error_async() to f2fs_handle_error() - spread f2fs_handle_error() Fixes: 95fa90c9e5a7 ("f2fs: support recording errors into superblock") Cc: stable@kernel.org Reported-by: syzbot+14b90e1156b9f6fc1266@syzkaller.appspotmail.com Closes: https://lore.kernel.org/linux-f2fs-devel/68eae49b.050a0220.ac43.0001.GAE@google.com Reported-by: Jiaming Zhang Closes: https://lore.kernel.org/lkml/CANypQFa-Gy9sD-N35o3PC+FystOWkNuN8pv6S75HLT0ga-Tzgw@mail.gmail.com Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim Signed-off-by: Greg Kroah-Hartman --- fs/f2fs/compress.c | 5 +---- fs/f2fs/f2fs.h | 1 - fs/f2fs/super.c | 41 ----------------------------------------- 3 files changed, 1 insertion(+), 46 deletions(-) diff --git a/fs/f2fs/compress.c b/fs/f2fs/compress.c index 6ad8d3bc6df7a..811bfe38e5c09 100644 --- a/fs/f2fs/compress.c +++ b/fs/f2fs/compress.c @@ -759,10 +759,7 @@ void f2fs_decompress_cluster(struct decompress_io_ctx *dic, bool in_task) ret = -EFSCORRUPTED; /* Avoid f2fs_commit_super in irq context */ - if (!in_task) - f2fs_handle_error_async(sbi, ERROR_FAIL_DECOMPRESSION); - else - f2fs_handle_error(sbi, ERROR_FAIL_DECOMPRESSION); + f2fs_handle_error(sbi, ERROR_FAIL_DECOMPRESSION); goto out_release; } diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 2ff617820f13a..a10c62f031626 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -3812,7 +3812,6 @@ void f2fs_quota_off_umount(struct super_block *sb); void f2fs_save_errors(struct f2fs_sb_info *sbi, unsigned char flag); void f2fs_handle_critical_error(struct f2fs_sb_info *sbi, unsigned char reason); void f2fs_handle_error(struct f2fs_sb_info *sbi, unsigned char error); -void f2fs_handle_error_async(struct f2fs_sb_info *sbi, unsigned char error); int f2fs_commit_super(struct f2fs_sb_info *sbi, bool recover); int f2fs_sync_fs(struct super_block *sb, int sync); int f2fs_sanity_check_ckpt(struct f2fs_sb_info *sbi); diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 10f09c85b4628..679dc4aef7466 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -4560,48 +4560,7 @@ void f2fs_save_errors(struct f2fs_sb_info *sbi, unsigned char flag) spin_unlock_irqrestore(&sbi->error_lock, flags); } -static bool f2fs_update_errors(struct f2fs_sb_info *sbi) -{ - unsigned long flags; - bool need_update = false; - - spin_lock_irqsave(&sbi->error_lock, flags); - if (sbi->error_dirty) { - memcpy(F2FS_RAW_SUPER(sbi)->s_errors, sbi->errors, - MAX_F2FS_ERRORS); - sbi->error_dirty = false; - need_update = true; - } - spin_unlock_irqrestore(&sbi->error_lock, flags); - - return need_update; -} - -static void f2fs_record_errors(struct f2fs_sb_info *sbi, unsigned char error) -{ - int err; - - f2fs_down_write(&sbi->sb_lock); - - if (!f2fs_update_errors(sbi)) - goto out_unlock; - - err = f2fs_commit_super(sbi, false); - if (err) - f2fs_err_ratelimited(sbi, - "f2fs_commit_super fails to record errors:%u, err:%d", - error, err); -out_unlock: - f2fs_up_write(&sbi->sb_lock); -} - void f2fs_handle_error(struct f2fs_sb_info *sbi, unsigned char error) -{ - f2fs_save_errors(sbi, error); - f2fs_record_errors(sbi, error); -} - -void f2fs_handle_error_async(struct f2fs_sb_info *sbi, unsigned char error) { f2fs_save_errors(sbi, error); From 40409e089b41b5dc3d96f2916a9af291f577f228 Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Mon, 27 Oct 2025 14:35:33 +0800 Subject: [PATCH 1318/2333] f2fs: fix to propagate error from f2fs_enable_checkpoint() commit be112e7449a6e1b54aa9feac618825d154b3a5c7 upstream. In order to let userspace detect such error rather than suffering silent failure. Fixes: 4354994f097d ("f2fs: checkpoint disabling") Cc: stable@kernel.org Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim Signed-off-by: Greg Kroah-Hartman --- fs/f2fs/super.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 679dc4aef7466..d11ea4fd43839 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -2634,10 +2634,11 @@ static int f2fs_disable_checkpoint(struct f2fs_sb_info *sbi) return err; } -static void f2fs_enable_checkpoint(struct f2fs_sb_info *sbi) +static int f2fs_enable_checkpoint(struct f2fs_sb_info *sbi) { unsigned int nr_pages = get_pages(sbi, F2FS_DIRTY_DATA) / 16; long long start, writeback, end; + int ret; f2fs_info(sbi, "f2fs_enable_checkpoint() starts, meta: %lld, node: %lld, data: %lld", get_pages(sbi, F2FS_DIRTY_META), @@ -2671,7 +2672,9 @@ static void f2fs_enable_checkpoint(struct f2fs_sb_info *sbi) set_sbi_flag(sbi, SBI_IS_DIRTY); f2fs_up_write(&sbi->gc_lock); - f2fs_sync_fs(sbi->sb, 1); + ret = f2fs_sync_fs(sbi->sb, 1); + if (ret) + f2fs_err(sbi, "%s sync_fs failed, ret: %d", __func__, ret); /* Let's ensure there's no pending checkpoint anymore */ f2fs_flush_ckpt_thread(sbi); @@ -2681,6 +2684,7 @@ static void f2fs_enable_checkpoint(struct f2fs_sb_info *sbi) f2fs_info(sbi, "f2fs_enable_checkpoint() finishes, writeback:%llu, sync:%llu", ktime_ms_delta(writeback, start), ktime_ms_delta(end, writeback)); + return ret; } static int __f2fs_remount(struct fs_context *fc, struct super_block *sb) @@ -2894,7 +2898,9 @@ static int __f2fs_remount(struct fs_context *fc, struct super_block *sb) goto restore_discard; need_enable_checkpoint = true; } else { - f2fs_enable_checkpoint(sbi); + err = f2fs_enable_checkpoint(sbi); + if (err) + goto restore_discard; need_disable_checkpoint = true; } } @@ -2937,7 +2943,8 @@ static int __f2fs_remount(struct fs_context *fc, struct super_block *sb) return 0; restore_checkpoint: if (need_enable_checkpoint) { - f2fs_enable_checkpoint(sbi); + if (f2fs_enable_checkpoint(sbi)) + f2fs_warn(sbi, "checkpoint has not been enabled"); } else if (need_disable_checkpoint) { if (f2fs_disable_checkpoint(sbi)) f2fs_warn(sbi, "checkpoint has not been disabled"); @@ -5232,13 +5239,12 @@ static int f2fs_fill_super(struct super_block *sb, struct fs_context *fc) if (err) goto sync_free_meta; - if (test_opt(sbi, DISABLE_CHECKPOINT)) { + if (test_opt(sbi, DISABLE_CHECKPOINT)) err = f2fs_disable_checkpoint(sbi); - if (err) - goto sync_free_meta; - } else if (is_set_ckpt_flags(sbi, CP_DISABLED_FLAG)) { - f2fs_enable_checkpoint(sbi); - } + else if (is_set_ckpt_flags(sbi, CP_DISABLED_FLAG)) + err = f2fs_enable_checkpoint(sbi); + if (err) + goto sync_free_meta; /* * If filesystem is not mounted as read-only then From bac23833220a1f8fe8dfab7e16efa20ff64d7589 Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Mon, 20 Oct 2025 10:42:12 +0800 Subject: [PATCH 1319/2333] f2fs: fix to avoid updating zero-sized extent in extent cache commit 7c37c79510329cd951a4dedf3f7bf7e2b18dccec upstream. As syzbot reported: F2FS-fs (loop0): __update_extent_tree_range: extent len is zero, type: 0, extent [0, 0, 0], age [0, 0] ------------[ cut here ]------------ kernel BUG at fs/f2fs/extent_cache.c:678! Oops: invalid opcode: 0000 [#1] SMP KASAN NOPTI CPU: 0 UID: 0 PID: 5336 Comm: syz.0.0 Not tainted syzkaller #0 PREEMPT(full) Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2~bpo12+1 04/01/2014 RIP: 0010:__update_extent_tree_range+0x13bc/0x1500 fs/f2fs/extent_cache.c:678 Call Trace: f2fs_update_read_extent_cache_range+0x192/0x3e0 fs/f2fs/extent_cache.c:1085 f2fs_do_zero_range fs/f2fs/file.c:1657 [inline] f2fs_zero_range+0x10c1/0x1580 fs/f2fs/file.c:1737 f2fs_fallocate+0x583/0x990 fs/f2fs/file.c:2030 vfs_fallocate+0x669/0x7e0 fs/open.c:342 ioctl_preallocate fs/ioctl.c:289 [inline] file_ioctl+0x611/0x780 fs/ioctl.c:-1 do_vfs_ioctl+0xb33/0x1430 fs/ioctl.c:576 __do_sys_ioctl fs/ioctl.c:595 [inline] __se_sys_ioctl+0x82/0x170 fs/ioctl.c:583 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] do_syscall_64+0xfa/0x3b0 arch/x86/entry/syscall_64.c:94 entry_SYSCALL_64_after_hwframe+0x77/0x7f RIP: 0033:0x7f07bc58eec9 In error path of f2fs_zero_range(), it may add a zero-sized extent into extent cache, it should be avoided. Fixes: 6e9619499f53 ("f2fs: support in batch fzero in dnode page") Cc: stable@kernel.org Reported-by: syzbot+24124df3170c3638b35f@syzkaller.appspotmail.com Closes: https://lore.kernel.org/linux-f2fs-devel/68e5d698.050a0220.256323.0032.GAE@google.com Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim Signed-off-by: Greg Kroah-Hartman --- fs/f2fs/file.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index c641a0209956e..6d42e2d28861c 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -1654,8 +1654,11 @@ static int f2fs_do_zero_range(struct dnode_of_data *dn, pgoff_t start, f2fs_set_data_blkaddr(dn, NEW_ADDR); } - f2fs_update_read_extent_cache_range(dn, start, 0, index - start); - f2fs_update_age_extent_cache_range(dn, start, index - start); + if (index > start) { + f2fs_update_read_extent_cache_range(dn, start, 0, + index - start); + f2fs_update_age_extent_cache_range(dn, start, index - start); + } return ret; } From 0dde30753c1e8648665dbe069d814e540ce2fd37 Mon Sep 17 00:00:00 2001 From: Deepanshu Kartikey Date: Mon, 27 Oct 2025 18:36:34 +0530 Subject: [PATCH 1320/2333] f2fs: invalidate dentry cache on failed whiteout creation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit d33f89b34aa313f50f9a512d58dd288999f246b0 upstream. F2FS can mount filesystems with corrupted directory depth values that get runtime-clamped to MAX_DIR_HASH_DEPTH. When RENAME_WHITEOUT operations are performed on such directories, f2fs_rename performs directory modifications (updating target entry and deleting source entry) before attempting to add the whiteout entry via f2fs_add_link. If f2fs_add_link fails due to the corrupted directory structure, the function returns an error to VFS, but the partial directory modifications have already been committed to disk. VFS assumes the entire rename operation failed and does not update the dentry cache, leaving stale mappings. In the error path, VFS does not call d_move() to update the dentry cache. This results in new_dentry still pointing to the old inode (new_inode) which has already had its i_nlink decremented to zero. The stale cache causes subsequent operations to incorrectly reference the freed inode. This causes subsequent operations to use cached dentry information that no longer matches the on-disk state. When a second rename targets the same entry, VFS attempts to decrement i_nlink on the stale inode, which may already have i_nlink=0, triggering a WARNING in drop_nlink(). Example sequence: 1. First rename (RENAME_WHITEOUT): file2 → file1 - f2fs updates file1 entry on disk (points to inode 8) - f2fs deletes file2 entry on disk - f2fs_add_link(whiteout) fails (corrupted directory) - Returns error to VFS - VFS does not call d_move() due to error - VFS cache still has: file1 → inode 7 (stale!) - inode 7 has i_nlink=0 (already decremented) 2. Second rename: file3 → file1 - VFS uses stale cache: file1 → inode 7 - Tries to drop_nlink on inode 7 (i_nlink already 0) - WARNING in drop_nlink() Fix this by explicitly invalidating old_dentry and new_dentry when f2fs_add_link fails during whiteout creation. This forces VFS to refresh from disk on subsequent operations, ensuring cache consistency even when the rename partially succeeds. Reproducer: 1. Mount F2FS image with corrupted i_current_depth 2. renameat2(file2, file1, RENAME_WHITEOUT) 3. renameat2(file3, file1, 0) 4. System triggers WARNING in drop_nlink() Fixes: 7e01e7ad746b ("f2fs: support RENAME_WHITEOUT") Reported-by: syzbot+632cf32276a9a564188d@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=632cf32276a9a564188d Suggested-by: Chao Yu Link: https://lore.kernel.org/all/20251022233349.102728-1-kartikey406@gmail.com/ [v1] Cc: stable@vger.kernel.org Signed-off-by: Deepanshu Kartikey Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim Signed-off-by: Greg Kroah-Hartman --- fs/f2fs/namei.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c index b882771e46997..712479b7b93d7 100644 --- a/fs/f2fs/namei.c +++ b/fs/f2fs/namei.c @@ -1053,9 +1053,11 @@ static int f2fs_rename(struct mnt_idmap *idmap, struct inode *old_dir, if (whiteout) { set_inode_flag(whiteout, FI_INC_LINK); err = f2fs_add_link(old_dentry, whiteout); - if (err) + if (err) { + d_invalidate(old_dentry); + d_invalidate(new_dentry); goto put_out_dir; - + } spin_lock(&whiteout->i_lock); whiteout->i_state &= ~I_LINKABLE; spin_unlock(&whiteout->i_lock); From e6d828eae00ec192e18c2ddaa2fd32050a96048a Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Tue, 21 Oct 2025 11:48:56 +0800 Subject: [PATCH 1321/2333] f2fs: use global inline_xattr_slab instead of per-sb slab cache MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 1f27ef42bb0b7c0740c5616ec577ec188b8a1d05 upstream. As Hong Yun reported in mailing list: loop7: detected capacity change from 0 to 131072 ------------[ cut here ]------------ kmem_cache of name 'f2fs_xattr_entry-7:7' already exists WARNING: CPU: 0 PID: 24426 at mm/slab_common.c:110 kmem_cache_sanity_check mm/slab_common.c:109 [inline] WARNING: CPU: 0 PID: 24426 at mm/slab_common.c:110 __kmem_cache_create_args+0xa6/0x320 mm/slab_common.c:307 CPU: 0 UID: 0 PID: 24426 Comm: syz.7.1370 Not tainted 6.17.0-rc4 #1 PREEMPT(full) Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.13.0-1ubuntu1.1 04/01/2014 RIP: 0010:kmem_cache_sanity_check mm/slab_common.c:109 [inline] RIP: 0010:__kmem_cache_create_args+0xa6/0x320 mm/slab_common.c:307 Call Trace:  __kmem_cache_create include/linux/slab.h:353 [inline]  f2fs_kmem_cache_create fs/f2fs/f2fs.h:2943 [inline]  f2fs_init_xattr_caches+0xa5/0xe0 fs/f2fs/xattr.c:843  f2fs_fill_super+0x1645/0x2620 fs/f2fs/super.c:4918  get_tree_bdev_flags+0x1fb/0x260 fs/super.c:1692  vfs_get_tree+0x43/0x140 fs/super.c:1815  do_new_mount+0x201/0x550 fs/namespace.c:3808  do_mount fs/namespace.c:4136 [inline]  __do_sys_mount fs/namespace.c:4347 [inline]  __se_sys_mount+0x298/0x2f0 fs/namespace.c:4324  do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]  do_syscall_64+0x8e/0x3a0 arch/x86/entry/syscall_64.c:94  entry_SYSCALL_64_after_hwframe+0x76/0x7e The bug can be reproduced w/ below scripts: - mount /dev/vdb /mnt1 - mount /dev/vdc /mnt2 - umount /mnt1 - mounnt /dev/vdb /mnt1 The reason is if we created two slab caches, named f2fs_xattr_entry-7:3 and f2fs_xattr_entry-7:7, and they have the same slab size. Actually, slab system will only create one slab cache core structure which has slab name of "f2fs_xattr_entry-7:3", and two slab caches share the same structure and cache address. So, if we destroy f2fs_xattr_entry-7:3 cache w/ cache address, it will decrease reference count of slab cache, rather than release slab cache entirely, since there is one more user has referenced the cache. Then, if we try to create slab cache w/ name "f2fs_xattr_entry-7:3" again, slab system will find that there is existed cache which has the same name and trigger the warning. Let's changes to use global inline_xattr_slab instead of per-sb slab cache for fixing. Fixes: a999150f4fe3 ("f2fs: use kmem_cache pool during inline xattr lookups") Cc: stable@kernel.org Reported-by: Hong Yun Tested-by: Hong Yun Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim Signed-off-by: Greg Kroah-Hartman --- fs/f2fs/f2fs.h | 3 --- fs/f2fs/super.c | 17 ++++++++--------- fs/f2fs/xattr.c | 32 +++++++++++--------------------- fs/f2fs/xattr.h | 10 ++++++---- 4 files changed, 25 insertions(+), 37 deletions(-) diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index a10c62f031626..6c9c0e3857789 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -1886,9 +1886,6 @@ struct f2fs_sb_info { spinlock_t error_lock; /* protect errors/stop_reason array */ bool error_dirty; /* errors of sb is dirty */ - struct kmem_cache *inline_xattr_slab; /* inline xattr entry */ - unsigned int inline_xattr_slab_size; /* default inline xattr slab size */ - /* For reclaimed segs statistics per each GC mode */ unsigned int gc_segment_mode; /* GC state for reclaimed segments */ unsigned int gc_reclaimed_segs[MAX_GC_MODE]; /* Reclaimed segs for each mode */ diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index d11ea4fd43839..41b38e557046e 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -2028,7 +2028,6 @@ static void f2fs_put_super(struct super_block *sb) kfree(sbi->raw_super); f2fs_destroy_page_array_cache(sbi); - f2fs_destroy_xattr_caches(sbi); #ifdef CONFIG_QUOTA for (i = 0; i < MAXQUOTAS; i++) kfree(F2FS_OPTION(sbi).s_qf_names[i]); @@ -4997,13 +4996,9 @@ static int f2fs_fill_super(struct super_block *sb, struct fs_context *fc) if (err) goto free_iostat; - /* init per sbi slab cache */ - err = f2fs_init_xattr_caches(sbi); - if (err) - goto free_percpu; err = f2fs_init_page_array_cache(sbi); if (err) - goto free_xattr_cache; + goto free_percpu; /* get an inode for meta space */ sbi->meta_inode = f2fs_iget(sb, F2FS_META_INO(sbi)); @@ -5331,8 +5326,6 @@ static int f2fs_fill_super(struct super_block *sb, struct fs_context *fc) sbi->meta_inode = NULL; free_page_array_cache: f2fs_destroy_page_array_cache(sbi); -free_xattr_cache: - f2fs_destroy_xattr_caches(sbi); free_percpu: destroy_percpu_info(sbi); free_iostat: @@ -5535,10 +5528,15 @@ static int __init init_f2fs_fs(void) err = f2fs_create_casefold_cache(); if (err) goto free_compress_cache; - err = register_filesystem(&f2fs_fs_type); + err = f2fs_init_xattr_cache(); if (err) goto free_casefold_cache; + err = register_filesystem(&f2fs_fs_type); + if (err) + goto free_xattr_cache; return 0; +free_xattr_cache: + f2fs_destroy_xattr_cache(); free_casefold_cache: f2fs_destroy_casefold_cache(); free_compress_cache: @@ -5579,6 +5577,7 @@ static int __init init_f2fs_fs(void) static void __exit exit_f2fs_fs(void) { unregister_filesystem(&f2fs_fs_type); + f2fs_destroy_xattr_cache(); f2fs_destroy_casefold_cache(); f2fs_destroy_compress_cache(); f2fs_destroy_compress_mempool(); diff --git a/fs/f2fs/xattr.c b/fs/f2fs/xattr.c index 58632a2b66136..b4e5c406632f8 100644 --- a/fs/f2fs/xattr.c +++ b/fs/f2fs/xattr.c @@ -23,11 +23,12 @@ #include "xattr.h" #include "segment.h" +static struct kmem_cache *inline_xattr_slab; static void *xattr_alloc(struct f2fs_sb_info *sbi, int size, bool *is_inline) { - if (likely(size == sbi->inline_xattr_slab_size)) { + if (likely(size == DEFAULT_XATTR_SLAB_SIZE)) { *is_inline = true; - return f2fs_kmem_cache_alloc(sbi->inline_xattr_slab, + return f2fs_kmem_cache_alloc(inline_xattr_slab, GFP_F2FS_ZERO, false, sbi); } *is_inline = false; @@ -38,7 +39,7 @@ static void xattr_free(struct f2fs_sb_info *sbi, void *xattr_addr, bool is_inline) { if (is_inline) - kmem_cache_free(sbi->inline_xattr_slab, xattr_addr); + kmem_cache_free(inline_xattr_slab, xattr_addr); else kfree(xattr_addr); } @@ -830,25 +831,14 @@ int f2fs_setxattr(struct inode *inode, int index, const char *name, return err; } -int f2fs_init_xattr_caches(struct f2fs_sb_info *sbi) +int __init f2fs_init_xattr_cache(void) { - dev_t dev = sbi->sb->s_bdev->bd_dev; - char slab_name[32]; - - sprintf(slab_name, "f2fs_xattr_entry-%u:%u", MAJOR(dev), MINOR(dev)); - - sbi->inline_xattr_slab_size = F2FS_OPTION(sbi).inline_xattr_size * - sizeof(__le32) + XATTR_PADDING_SIZE; - - sbi->inline_xattr_slab = f2fs_kmem_cache_create(slab_name, - sbi->inline_xattr_slab_size); - if (!sbi->inline_xattr_slab) - return -ENOMEM; - - return 0; + inline_xattr_slab = f2fs_kmem_cache_create("f2fs_xattr_entry", + DEFAULT_XATTR_SLAB_SIZE); + return inline_xattr_slab ? 0 : -ENOMEM; } -void f2fs_destroy_xattr_caches(struct f2fs_sb_info *sbi) +void f2fs_destroy_xattr_cache(void) { - kmem_cache_destroy(sbi->inline_xattr_slab); -} + kmem_cache_destroy(inline_xattr_slab); +} \ No newline at end of file diff --git a/fs/f2fs/xattr.h b/fs/f2fs/xattr.h index 4fc0b2305fbd8..bce3d93e4755b 100644 --- a/fs/f2fs/xattr.h +++ b/fs/f2fs/xattr.h @@ -89,6 +89,8 @@ struct f2fs_xattr_entry { F2FS_TOTAL_EXTRA_ATTR_SIZE / sizeof(__le32) - \ DEF_INLINE_RESERVED_SIZE - \ MIN_INLINE_DENTRY_SIZE / sizeof(__le32)) +#define DEFAULT_XATTR_SLAB_SIZE (DEFAULT_INLINE_XATTR_ADDRS * \ + sizeof(__le32) + XATTR_PADDING_SIZE) /* * On-disk structure of f2fs_xattr @@ -132,8 +134,8 @@ int f2fs_setxattr(struct inode *, int, const char *, const void *, int f2fs_getxattr(struct inode *, int, const char *, void *, size_t, struct folio *); ssize_t f2fs_listxattr(struct dentry *, char *, size_t); -int f2fs_init_xattr_caches(struct f2fs_sb_info *); -void f2fs_destroy_xattr_caches(struct f2fs_sb_info *); +int __init f2fs_init_xattr_cache(void); +void f2fs_destroy_xattr_cache(void); #else #define f2fs_xattr_handlers NULL @@ -150,8 +152,8 @@ static inline int f2fs_getxattr(struct inode *inode, int index, { return -EOPNOTSUPP; } -static inline int f2fs_init_xattr_caches(struct f2fs_sb_info *sbi) { return 0; } -static inline void f2fs_destroy_xattr_caches(struct f2fs_sb_info *sbi) { } +static inline int __init f2fs_init_xattr_cache(void) { return 0; } +static inline void f2fs_destroy_xattr_cache(void) { } #endif #ifdef CONFIG_F2FS_FS_SECURITY From b355d300f51b0f67552cec6ea2709ba54738d285 Mon Sep 17 00:00:00 2001 From: Xiaole He Date: Mon, 27 Oct 2025 17:23:41 +0800 Subject: [PATCH 1322/2333] f2fs: fix age extent cache insertion skip on counter overflow commit 27bf6a637b7613fc85fa6af468b7d612d78cd5c0 upstream. The age extent cache uses last_blocks (derived from allocated_data_blocks) to determine data age. However, there's a conflict between the deletion marker (last_blocks=0) and legitimate last_blocks=0 cases when allocated_data_blocks overflows to 0 after reaching ULLONG_MAX. In this case, valid extents are incorrectly skipped due to the "if (!tei->last_blocks)" check in __update_extent_tree_range(). This patch fixes the issue by: 1. Reserving ULLONG_MAX as an invalid/deletion marker 2. Limiting allocated_data_blocks to range [0, ULLONG_MAX-1] 3. Using F2FS_EXTENT_AGE_INVALID for deletion scenarios 4. Adjusting overflow age calculation from ULLONG_MAX to (ULLONG_MAX-1) Reproducer (using a patched kernel with allocated_data_blocks initialized to ULLONG_MAX - 3 for quick testing): Step 1: Mount and check initial state # dd if=/dev/zero of=/tmp/test.img bs=1M count=100 # mkfs.f2fs -f /tmp/test.img # mkdir -p /mnt/f2fs_test # mount -t f2fs -o loop,age_extent_cache /tmp/test.img /mnt/f2fs_test # cat /sys/kernel/debug/f2fs/status | grep -A 4 "Block Age" Allocated Data Blocks: 18446744073709551612 # ULLONG_MAX - 3 Inner Struct Count: tree: 1(0), node: 0 Step 2: Create files and write data to trigger overflow # touch /mnt/f2fs_test/{1,2,3,4}.txt; sync # cat /sys/kernel/debug/f2fs/status | grep -A 4 "Block Age" Allocated Data Blocks: 18446744073709551613 # ULLONG_MAX - 2 Inner Struct Count: tree: 5(0), node: 1 # dd if=/dev/urandom of=/mnt/f2fs_test/1.txt bs=4K count=1; sync # cat /sys/kernel/debug/f2fs/status | grep -A 4 "Block Age" Allocated Data Blocks: 18446744073709551614 # ULLONG_MAX - 1 Inner Struct Count: tree: 5(0), node: 2 # dd if=/dev/urandom of=/mnt/f2fs_test/2.txt bs=4K count=1; sync # cat /sys/kernel/debug/f2fs/status | grep -A 4 "Block Age" Allocated Data Blocks: 18446744073709551615 # ULLONG_MAX Inner Struct Count: tree: 5(0), node: 3 # dd if=/dev/urandom of=/mnt/f2fs_test/3.txt bs=4K count=1; sync # cat /sys/kernel/debug/f2fs/status | grep -A 4 "Block Age" Allocated Data Blocks: 0 # Counter overflowed! Inner Struct Count: tree: 5(0), node: 4 Step 3: Trigger the bug - next write should create node but gets skipped # dd if=/dev/urandom of=/mnt/f2fs_test/4.txt bs=4K count=1; sync # cat /sys/kernel/debug/f2fs/status | grep -A 4 "Block Age" Allocated Data Blocks: 1 Inner Struct Count: tree: 5(0), node: 4 Expected: node: 5 (new extent node for 4.txt) Actual: node: 4 (extent insertion was incorrectly skipped due to last_blocks = allocated_data_blocks = 0 in __get_new_block_age) After this fix, the extent node is correctly inserted and node count becomes 5 as expected. Fixes: 71644dff4811 ("f2fs: add block_age-based extent cache") Cc: stable@kernel.org Signed-off-by: Xiaole He Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim Signed-off-by: Greg Kroah-Hartman --- fs/f2fs/extent_cache.c | 5 +++-- fs/f2fs/f2fs.h | 6 ++++++ fs/f2fs/segment.c | 9 +++++++-- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/fs/f2fs/extent_cache.c b/fs/f2fs/extent_cache.c index 33e09c453c703..0ed84cc065a7e 100644 --- a/fs/f2fs/extent_cache.c +++ b/fs/f2fs/extent_cache.c @@ -808,7 +808,7 @@ static void __update_extent_tree_range(struct inode *inode, } goto out_read_extent_cache; update_age_extent_cache: - if (!tei->last_blocks) + if (tei->last_blocks == F2FS_EXTENT_AGE_INVALID) goto out_read_extent_cache; __set_extent_info(&ei, fofs, len, 0, false, @@ -912,7 +912,7 @@ static int __get_new_block_age(struct inode *inode, struct extent_info *ei, cur_age = cur_blocks - tei.last_blocks; else /* allocated_data_blocks overflow */ - cur_age = ULLONG_MAX - tei.last_blocks + cur_blocks; + cur_age = (ULLONG_MAX - 1) - tei.last_blocks + cur_blocks; if (tei.age) ei->age = __calculate_block_age(sbi, cur_age, tei.age); @@ -1114,6 +1114,7 @@ void f2fs_update_age_extent_cache_range(struct dnode_of_data *dn, struct extent_info ei = { .fofs = fofs, .len = len, + .last_blocks = F2FS_EXTENT_AGE_INVALID, }; if (!__may_extent_tree(dn->inode, EX_BLOCK_AGE)) diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 6c9c0e3857789..37ad0c27c5b48 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -708,6 +708,12 @@ enum extent_type { NR_EXTENT_CACHES, }; +/* + * Reserved value to mark invalid age extents, hence valid block range + * from 0 to ULLONG_MAX-1 + */ +#define F2FS_EXTENT_AGE_INVALID ULLONG_MAX + struct extent_info { unsigned int fofs; /* start offset in a file */ unsigned int len; /* length of the extent */ diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index ac84559dc2693..10d873d1b328c 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -3881,8 +3881,13 @@ int f2fs_allocate_data_block(struct f2fs_sb_info *sbi, struct folio *folio, locate_dirty_segment(sbi, GET_SEGNO(sbi, old_blkaddr)); locate_dirty_segment(sbi, GET_SEGNO(sbi, *new_blkaddr)); - if (IS_DATASEG(curseg->seg_type)) - atomic64_inc(&sbi->allocated_data_blocks); + if (IS_DATASEG(curseg->seg_type)) { + unsigned long long new_val; + + new_val = atomic64_inc_return(&sbi->allocated_data_blocks); + if (unlikely(new_val == ULLONG_MAX)) + atomic64_set(&sbi->allocated_data_blocks, 0); + } up_write(&sit_i->sentry_lock); From 57e36f84f2b5bf1535452d277f825784960a649e Mon Sep 17 00:00:00 2001 From: Xiaole He Date: Wed, 29 Oct 2025 13:18:07 +0800 Subject: [PATCH 1323/2333] f2fs: fix uninitialized one_time_gc in victim_sel_policy commit 392711ef18bff524a873b9c239a73148c5432262 upstream. The one_time_gc field in struct victim_sel_policy is conditionally initialized but unconditionally read, leading to undefined behavior that triggers UBSAN warnings. In f2fs_get_victim() at fs/f2fs/gc.c:774, the victim_sel_policy structure is declared without initialization: struct victim_sel_policy p; The field p.one_time_gc is only assigned when the 'one_time' parameter is true (line 789): if (one_time) { p.one_time_gc = one_time; ... } However, this field is unconditionally read in subsequent get_gc_cost() at line 395: if (p->one_time_gc && (valid_thresh_ratio < 100) && ...) When one_time is false, p.one_time_gc contains uninitialized stack memory. Hence p.one_time_gc is an invalid bool value. UBSAN detects this invalid bool value: UBSAN: invalid-load in fs/f2fs/gc.c:395:7 load of value 77 is not a valid value for type '_Bool' CPU: 3 UID: 0 PID: 1297 Comm: f2fs_gc-252:16 Not tainted 6.18.0-rc3 #5 PREEMPT(voluntary) Hardware name: OpenStack Foundation OpenStack Nova, BIOS 1.13.0-1ubuntu1.1 04/01/2014 Call Trace: dump_stack_lvl+0x70/0x90 dump_stack+0x14/0x20 __ubsan_handle_load_invalid_value+0xb3/0xf0 ? dl_server_update+0x2e/0x40 ? update_curr+0x147/0x170 f2fs_get_victim.cold+0x66/0x134 [f2fs] ? sched_balance_newidle+0x2ca/0x470 ? finish_task_switch.isra.0+0x8d/0x2a0 f2fs_gc+0x2ba/0x8e0 [f2fs] ? _raw_spin_unlock_irqrestore+0x12/0x40 ? __timer_delete_sync+0x80/0xe0 ? timer_delete_sync+0x14/0x20 ? schedule_timeout+0x82/0x100 gc_thread_func+0x38b/0x860 [f2fs] ? gc_thread_func+0x38b/0x860 [f2fs] ? __pfx_autoremove_wake_function+0x10/0x10 kthread+0x10b/0x220 ? __pfx_gc_thread_func+0x10/0x10 [f2fs] ? _raw_spin_unlock_irq+0x12/0x40 ? __pfx_kthread+0x10/0x10 ret_from_fork+0x11a/0x160 ? __pfx_kthread+0x10/0x10 ret_from_fork_asm+0x1a/0x30 This issue is reliably reproducible with the following steps on a 100GB SSD /dev/vdb: mkfs.f2fs -f /dev/vdb mount /dev/vdb /mnt/f2fs_test fio --name=gc --directory=/mnt/f2fs_test --rw=randwrite \ --bs=4k --size=8G --numjobs=12 --fsync=4 --runtime=10 \ --time_based echo 1 > /sys/fs/f2fs/vdb/gc_urgent The uninitialized value causes incorrect GC victim selection, leading to unpredictable garbage collection behavior. Fix by zero-initializing the entire victim_sel_policy structure to ensure all fields have defined values. Fixes: e791d00bd06c ("f2fs: add valid block ratio not to do excessive GC for one time GC") Cc: stable@kernel.org Signed-off-by: Xiaole He Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim Signed-off-by: Greg Kroah-Hartman --- fs/f2fs/gc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c index af2f4d28462c0..5f90cca64c7aa 100644 --- a/fs/f2fs/gc.c +++ b/fs/f2fs/gc.c @@ -774,7 +774,7 @@ int f2fs_get_victim(struct f2fs_sb_info *sbi, unsigned int *result, { struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); struct sit_info *sm = SIT_I(sbi); - struct victim_sel_policy p; + struct victim_sel_policy p = {0}; unsigned int secno, last_victim; unsigned int last_segment; unsigned int nsearched; From 2efb6b9c5bd27ff11abfc80e3b4ec59f3335c9d4 Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Wed, 5 Nov 2025 14:50:23 +0800 Subject: [PATCH 1324/2333] f2fs: fix to detect recoverable inode during dryrun of find_fsync_dnodes() commit 68d05693f8c031257a0822464366e1c2a239a512 upstream. mkfs.f2fs -f /dev/vdd mount /dev/vdd /mnt/f2fs touch /mnt/f2fs/foo sync # avoid CP_UMOUNT_FLAG in last f2fs_checkpoint.ckpt_flags touch /mnt/f2fs/bar f2fs_io fsync /mnt/f2fs/bar f2fs_io shutdown 2 /mnt/f2fs umount /mnt/f2fs blockdev --setro /dev/vdd mount /dev/vdd /mnt/f2fs mount: /mnt/f2fs: WARNING: source write-protected, mounted read-only. For the case if we create and fsync a new inode before sudden power-cut, without norecovery or disable_roll_forward mount option, the following mount will succeed w/o recovering last fsynced inode. The problem here is that we only check inode_list list after find_fsync_dnodes() in f2fs_recover_fsync_data() to find out whether there is recoverable data in the iamge, but there is a missed case, if last fsynced inode is not existing in last checkpoint, then, we will fail to get its inode due to nat of inode node is not existing in last checkpoint, so the inode won't be linked in inode_list. Let's detect such case in dyrun mode to fix this issue. After this change, mount will fail as expected below: mount: /mnt/f2fs: cannot mount /dev/vdd read-only. dmesg(1) may have more information after failed mount system call. demsg: F2FS-fs (vdd): Need to recover fsync data, but write access unavailable, please try mount w/ disable_roll_forward or norecovery Cc: stable@kernel.org Fixes: 6781eabba1bd ("f2fs: give -EINVAL for norecovery and rw mount") Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim Signed-off-by: Greg Kroah-Hartman --- fs/f2fs/recovery.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/fs/f2fs/recovery.c b/fs/f2fs/recovery.c index af72309b9bfc6..62a0c71b5b75d 100644 --- a/fs/f2fs/recovery.c +++ b/fs/f2fs/recovery.c @@ -399,7 +399,7 @@ static int sanity_check_node_chain(struct f2fs_sb_info *sbi, block_t blkaddr, } static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head, - bool check_only) + bool check_only, bool *new_inode) { struct curseg_info *curseg; block_t blkaddr, blkaddr_fast; @@ -447,16 +447,19 @@ static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head, quota_inode = true; } - /* - * CP | dnode(F) | inode(DF) - * For this case, we should not give up now. - */ entry = add_fsync_inode(sbi, head, ino_of_node(folio), quota_inode); if (IS_ERR(entry)) { err = PTR_ERR(entry); - if (err == -ENOENT) + /* + * CP | dnode(F) | inode(DF) + * For this case, we should not give up now. + */ + if (err == -ENOENT) { + if (check_only) + *new_inode = true; goto next; + } f2fs_folio_put(folio, true); break; } @@ -875,6 +878,7 @@ int f2fs_recover_fsync_data(struct f2fs_sb_info *sbi, bool check_only) int ret = 0; unsigned long s_flags = sbi->sb->s_flags; bool need_writecp = false; + bool new_inode = false; f2fs_notice(sbi, "f2fs_recover_fsync_data: recovery fsync data, " "check_only: %d", check_only); @@ -890,8 +894,8 @@ int f2fs_recover_fsync_data(struct f2fs_sb_info *sbi, bool check_only) f2fs_down_write(&sbi->cp_global_sem); /* step #1: find fsynced inode numbers */ - err = find_fsync_dnodes(sbi, &inode_list, check_only); - if (err || list_empty(&inode_list)) + err = find_fsync_dnodes(sbi, &inode_list, check_only, &new_inode); + if (err < 0 || (list_empty(&inode_list) && (!check_only || !new_inode))) goto skip; if (check_only) { From 51659b91898f2bc4441d597042223e1b644237fc Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Fri, 28 Nov 2025 17:25:07 +0800 Subject: [PATCH 1325/2333] f2fs: fix to not account invalid blocks in get_left_section_blocks() commit 37345eae9deaa2e4f372eeb98f6594cd0ee0916e upstream. w/ LFS mode, in get_left_section_blocks(), we should not account the blocks which were used before and now are invalided, otherwise those blocks will be counted as freed one in has_curseg_enough_space(), result in missing to trigger GC in time. Cc: stable@kernel.org Fixes: 249ad438e1d9 ("f2fs: add a method for calculating the remaining blocks in the current segment in LFS mode.") Fixes: bf34c93d2645 ("f2fs: check curseg space before foreground GC") Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim Signed-off-by: Greg Kroah-Hartman --- fs/f2fs/segment.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/fs/f2fs/segment.h b/fs/f2fs/segment.h index e883f14c228f2..f3e2fff45cf53 100644 --- a/fs/f2fs/segment.h +++ b/fs/f2fs/segment.h @@ -607,10 +607,12 @@ static inline int reserved_sections(struct f2fs_sb_info *sbi) static inline unsigned int get_left_section_blocks(struct f2fs_sb_info *sbi, enum log_type type, unsigned int segno) { - if (f2fs_lfs_mode(sbi) && __is_large_section(sbi)) - return CAP_BLKS_PER_SEC(sbi) - SEGS_TO_BLKS(sbi, - (segno - GET_START_SEG_FROM_SEC(sbi, segno))) - + if (f2fs_lfs_mode(sbi)) { + unsigned int used_blocks = __is_large_section(sbi) ? SEGS_TO_BLKS(sbi, + (segno - GET_START_SEG_FROM_SEC(sbi, segno))) : 0; + return CAP_BLKS_PER_SEC(sbi) - used_blocks - CURSEG_I(sbi, type)->next_blkoff; + } return CAP_BLKS_PER_SEC(sbi) - get_ckpt_valid_blocks(sbi, segno, true); } From 4560db9678a2c5952b6205fbca468c6805c2ba2a Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Wed, 5 Nov 2025 14:50:22 +0800 Subject: [PATCH 1326/2333] f2fs: fix return value of f2fs_recover_fsync_data() commit 01fba45deaddcce0d0b01c411435d1acf6feab7b upstream. With below scripts, it will trigger panic in f2fs: mkfs.f2fs -f /dev/vdd mount /dev/vdd /mnt/f2fs touch /mnt/f2fs/foo sync echo 111 >> /mnt/f2fs/foo f2fs_io fsync /mnt/f2fs/foo f2fs_io shutdown 2 /mnt/f2fs umount /mnt/f2fs mount -o ro,norecovery /dev/vdd /mnt/f2fs or mount -o ro,disable_roll_forward /dev/vdd /mnt/f2fs F2FS-fs (vdd): f2fs_recover_fsync_data: recovery fsync data, check_only: 0 F2FS-fs (vdd): Mounted with checkpoint version = 7f5c361f F2FS-fs (vdd): Stopped filesystem due to reason: 0 F2FS-fs (vdd): f2fs_recover_fsync_data: recovery fsync data, check_only: 1 Filesystem f2fs get_tree() didn't set fc->root, returned 1 ------------[ cut here ]------------ kernel BUG at fs/super.c:1761! Oops: invalid opcode: 0000 [#1] SMP PTI CPU: 3 UID: 0 PID: 722 Comm: mount Not tainted 6.18.0-rc2+ #721 PREEMPT(voluntary) Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 RIP: 0010:vfs_get_tree.cold+0x18/0x1a Call Trace: fc_mount+0x13/0xa0 path_mount+0x34e/0xc50 __x64_sys_mount+0x121/0x150 do_syscall_64+0x84/0x800 entry_SYSCALL_64_after_hwframe+0x76/0x7e RIP: 0033:0x7fa6cc126cfe The root cause is we missed to handle error number returned from f2fs_recover_fsync_data() when mounting image w/ ro,norecovery or ro,disable_roll_forward mount option, result in returning a positive error number to vfs_get_tree(), fix it. Cc: stable@kernel.org Fixes: 6781eabba1bd ("f2fs: give -EINVAL for norecovery and rw mount") Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim Signed-off-by: Greg Kroah-Hartman --- fs/f2fs/super.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 41b38e557046e..eb466a11d9d7f 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -5203,11 +5203,15 @@ static int f2fs_fill_super(struct super_block *sb, struct fs_context *fc) } } else { err = f2fs_recover_fsync_data(sbi, true); - - if (!f2fs_readonly(sb) && err > 0) { - err = -EINVAL; - f2fs_err(sbi, "Need to recover fsync data"); - goto free_meta; + if (err > 0) { + if (!f2fs_readonly(sb)) { + f2fs_err(sbi, "Need to recover fsync data"); + err = -EINVAL; + goto free_meta; + } else { + f2fs_info(sbi, "drop all fsynced data"); + err = 0; + } } } From a1223a72c419452ce7f36584e9610f2408277c40 Mon Sep 17 00:00:00 2001 From: Alison Schofield Date: Fri, 31 Oct 2025 16:42:20 -0700 Subject: [PATCH 1327/2333] tools/testing/nvdimm: Use per-DIMM device handle commit f59b701b4674f7955170b54c4167c5590f4714eb upstream. KASAN reports a global-out-of-bounds access when running these nfit tests: clear.sh, pmem-errors.sh, pfn-meta-errors.sh, btt-errors.sh, daxdev-errors.sh, and inject-error.sh. [] BUG: KASAN: global-out-of-bounds in nfit_test_ctl+0x769f/0x7840 [nfit_test] [] Read of size 4 at addr ffffffffc03ea01c by task ndctl/1215 [] The buggy address belongs to the variable: [] handle+0x1c/0x1df4 [nfit_test] nfit_test_search_spa() uses handle[nvdimm->id] to retrieve a device handle and triggers a KASAN error when it reads past the end of the handle array. It should not be indexing the handle array at all. The correct device handle is stored in per-DIMM test data. Each DIMM has a struct nfit_mem that embeds a struct acpi_nfit_memdev that describes the NFIT device handle. Use that device handle here. Fixes: 10246dc84dfc ("acpi nfit: nfit_test supports translate SPA") Cc: stable@vger.kernel.org Signed-off-by: Alison Schofield Reviewed-by: Dave Jiang > --- Link: https://patch.msgid.link/20251031234227.1303113-1-alison.schofield@intel.com Signed-off-by: Ira Weiny Signed-off-by: Greg Kroah-Hartman --- tools/testing/nvdimm/test/nfit.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tools/testing/nvdimm/test/nfit.c b/tools/testing/nvdimm/test/nfit.c index cfd4378e2129b..f87e9f251d131 100644 --- a/tools/testing/nvdimm/test/nfit.c +++ b/tools/testing/nvdimm/test/nfit.c @@ -670,6 +670,7 @@ static int nfit_test_search_spa(struct nvdimm_bus *bus, .addr = spa->spa, .region = NULL, }; + struct nfit_mem *nfit_mem; u64 dpa; ret = device_for_each_child(&bus->dev, &ctx, @@ -687,8 +688,12 @@ static int nfit_test_search_spa(struct nvdimm_bus *bus, */ nd_mapping = &nd_region->mapping[nd_region->ndr_mappings - 1]; nvdimm = nd_mapping->nvdimm; + nfit_mem = nvdimm_provider_data(nvdimm); + if (!nfit_mem) + return -EINVAL; - spa->devices[0].nfit_device_handle = handle[nvdimm->id]; + spa->devices[0].nfit_device_handle = + __to_nfit_memdev(nfit_mem)->device_handle; spa->num_nvdimms = 1; spa->devices[0].dpa = dpa; From dd6e519ba91e41cc336bdbbe6e9c7b247aead280 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Fri, 12 Sep 2025 12:53:08 +0300 Subject: [PATCH 1328/2333] pinctrl: renesas: rzg2l: Fix ISEL restore on resume commit 44bf66122c12ef6d3382a9b84b9be1802e5f0e95 upstream. Commit 1d2da79708cb ("pinctrl: renesas: rzg2l: Avoid configuring ISEL in gpio_irq_{en,dis}able*()") dropped the configuration of ISEL from struct irq_chip::{irq_enable, irq_disable} APIs and moved it to struct gpio_chip::irq::{child_to_parent_hwirq, child_irq_domain_ops::free} APIs to fix spurious IRQs. After commit 1d2da79708cb ("pinctrl: renesas: rzg2l: Avoid configuring ISEL in gpio_irq_{en,dis}able*()"), ISEL was no longer configured properly on resume. This is because the pinctrl resume code used struct irq_chip::irq_enable (called from rzg2l_gpio_irq_restore()) to reconfigure the wakeup interrupts. Some drivers (e.g. Ethernet) may also reconfigure non-wakeup interrupts on resume through their own code, eventually calling struct irq_chip::irq_enable. Fix this by adding ISEL configuration back into the struct irq_chip::irq_enable API and on resume path for wakeup interrupts. As struct irq_chip::irq_enable needs now to lock to update the ISEL, convert the struct rzg2l_pinctrl::lock to a raw spinlock and replace the locking API calls with the raw variants. Otherwise the lockdep reports invalid wait context when probing the adv7511 module on RZ/G2L: [ BUG: Invalid wait context ] 6.17.0-rc5-next-20250911-00001-gfcfac22533c9 #18 Not tainted ----------------------------- (udev-worker)/165 is trying to lock: ffff00000e3664a8 (&pctrl->lock){....}-{3:3}, at: rzg2l_gpio_irq_enable+0x38/0x78 other info that might help us debug this: context-{5:5} 3 locks held by (udev-worker)/165: #0: ffff00000e890108 (&dev->mutex){....}-{4:4}, at: __driver_attach+0x90/0x1ac #1: ffff000011c07240 (request_class){+.+.}-{4:4}, at: __setup_irq+0xb4/0x6dc #2: ffff000011c070c8 (lock_class){....}-{2:2}, at: __setup_irq+0xdc/0x6dc stack backtrace: CPU: 1 UID: 0 PID: 165 Comm: (udev-worker) Not tainted 6.17.0-rc5-next-20250911-00001-gfcfac22533c9 #18 PREEMPT Hardware name: Renesas SMARC EVK based on r9a07g044l2 (DT) Call trace: show_stack+0x18/0x24 (C) dump_stack_lvl+0x90/0xd0 dump_stack+0x18/0x24 __lock_acquire+0xa14/0x20b4 lock_acquire+0x1c8/0x354 _raw_spin_lock_irqsave+0x60/0x88 rzg2l_gpio_irq_enable+0x38/0x78 irq_enable+0x40/0x8c __irq_startup+0x78/0xa4 irq_startup+0x108/0x16c __setup_irq+0x3c0/0x6dc request_threaded_irq+0xec/0x1ac devm_request_threaded_irq+0x80/0x134 adv7511_probe+0x928/0x9a4 [adv7511] i2c_device_probe+0x22c/0x3dc really_probe+0xbc/0x2a0 __driver_probe_device+0x78/0x12c driver_probe_device+0x40/0x164 __driver_attach+0x9c/0x1ac bus_for_each_dev+0x74/0xd0 driver_attach+0x24/0x30 bus_add_driver+0xe4/0x208 driver_register+0x60/0x128 i2c_register_driver+0x48/0xd0 adv7511_init+0x5c/0x1000 [adv7511] do_one_initcall+0x64/0x30c do_init_module+0x58/0x23c load_module+0x1bcc/0x1d40 init_module_from_file+0x88/0xc4 idempotent_init_module+0x188/0x27c __arm64_sys_finit_module+0x68/0xac invoke_syscall+0x48/0x110 el0_svc_common.constprop.0+0xc0/0xe0 do_el0_svc+0x1c/0x28 el0_svc+0x4c/0x160 el0t_64_sync_handler+0xa0/0xe4 el0t_64_sync+0x198/0x19c Having ISEL configuration back into the struct irq_chip::irq_enable API should be safe with respect to spurious IRQs, as in the probe case IRQs are enabled anyway in struct gpio_chip::irq::child_to_parent_hwirq. No spurious IRQs were detected on suspend/resume, boot, ethernet link insert/remove tests (executed on RZ/G3S). Boot, ethernet link insert/remove tests were also executed successfully on RZ/G2L. Fixes: 1d2da79708cb ("pinctrl: renesas: rzg2l: Avoid configuring ISEL in gpio_irq_{en,dis}able*(") Cc: stable@vger.kernel.org Signed-off-by: Claudiu Beznea Reviewed-by: Geert Uytterhoeven Link: https://patch.msgid.link/20250912095308.3603704-1-claudiu.beznea.uj@bp.renesas.com Signed-off-by: Geert Uytterhoeven Signed-off-by: Greg Kroah-Hartman --- drivers/pinctrl/renesas/pinctrl-rzg2l.c | 71 +++++++++++++++---------- 1 file changed, 44 insertions(+), 27 deletions(-) diff --git a/drivers/pinctrl/renesas/pinctrl-rzg2l.c b/drivers/pinctrl/renesas/pinctrl-rzg2l.c index 94cb77949f595..c2711b2de374d 100644 --- a/drivers/pinctrl/renesas/pinctrl-rzg2l.c +++ b/drivers/pinctrl/renesas/pinctrl-rzg2l.c @@ -359,7 +359,7 @@ struct rzg2l_pinctrl { spinlock_t bitmap_lock; /* protect tint_slot bitmap */ unsigned int hwirq[RZG2L_TINT_MAX_INTERRUPT]; - spinlock_t lock; /* lock read/write registers */ + raw_spinlock_t lock; /* lock read/write registers */ struct mutex mutex; /* serialize adding groups and functions */ struct rzg2l_pinctrl_pin_settings *settings; @@ -543,7 +543,7 @@ static void rzg2l_pinctrl_set_pfc_mode(struct rzg2l_pinctrl *pctrl, unsigned long flags; u32 reg; - spin_lock_irqsave(&pctrl->lock, flags); + raw_spin_lock_irqsave(&pctrl->lock, flags); /* Set pin to 'Non-use (Hi-Z input protection)' */ reg = readw(pctrl->base + PM(off)); @@ -567,7 +567,7 @@ static void rzg2l_pinctrl_set_pfc_mode(struct rzg2l_pinctrl *pctrl, pctrl->data->pwpr_pfc_lock_unlock(pctrl, true); - spin_unlock_irqrestore(&pctrl->lock, flags); + raw_spin_unlock_irqrestore(&pctrl->lock, flags); }; static int rzg2l_pinctrl_set_mux(struct pinctrl_dev *pctldev, @@ -882,10 +882,10 @@ static void rzg2l_rmw_pin_config(struct rzg2l_pinctrl *pctrl, u32 offset, addr += 4; } - spin_lock_irqsave(&pctrl->lock, flags); + raw_spin_lock_irqsave(&pctrl->lock, flags); reg = readl(addr) & ~(mask << (bit * 8)); writel(reg | (val << (bit * 8)), addr); - spin_unlock_irqrestore(&pctrl->lock, flags); + raw_spin_unlock_irqrestore(&pctrl->lock, flags); } static int rzg2l_caps_to_pwr_reg(const struct rzg2l_register_offsets *regs, u32 caps) @@ -1121,7 +1121,7 @@ static int rzg2l_write_oen(struct rzg2l_pinctrl *pctrl, unsigned int _pin, u8 oe if (bit < 0) return -EINVAL; - spin_lock_irqsave(&pctrl->lock, flags); + raw_spin_lock_irqsave(&pctrl->lock, flags); val = readb(pctrl->base + oen_offset); if (oen) val &= ~BIT(bit); @@ -1134,7 +1134,7 @@ static int rzg2l_write_oen(struct rzg2l_pinctrl *pctrl, unsigned int _pin, u8 oe writeb(val, pctrl->base + oen_offset); if (pctrl->data->hwcfg->oen_pwpr_lock) writeb(pwpr & ~PWPR_REGWE_B, pctrl->base + regs->pwpr); - spin_unlock_irqrestore(&pctrl->lock, flags); + raw_spin_unlock_irqrestore(&pctrl->lock, flags); return 0; } @@ -1687,14 +1687,14 @@ static int rzg2l_gpio_request(struct gpio_chip *chip, unsigned int offset) if (ret) return ret; - spin_lock_irqsave(&pctrl->lock, flags); + raw_spin_lock_irqsave(&pctrl->lock, flags); /* Select GPIO mode in PMC Register */ reg8 = readb(pctrl->base + PMC(off)); reg8 &= ~BIT(bit); pctrl->data->pmc_writeb(pctrl, reg8, PMC(off)); - spin_unlock_irqrestore(&pctrl->lock, flags); + raw_spin_unlock_irqrestore(&pctrl->lock, flags); return 0; } @@ -1709,7 +1709,7 @@ static void rzg2l_gpio_set_direction(struct rzg2l_pinctrl *pctrl, u32 offset, unsigned long flags; u16 reg16; - spin_lock_irqsave(&pctrl->lock, flags); + raw_spin_lock_irqsave(&pctrl->lock, flags); reg16 = readw(pctrl->base + PM(off)); reg16 &= ~(PM_MASK << (bit * 2)); @@ -1717,7 +1717,7 @@ static void rzg2l_gpio_set_direction(struct rzg2l_pinctrl *pctrl, u32 offset, reg16 |= (output ? PM_OUTPUT : PM_INPUT) << (bit * 2); writew(reg16, pctrl->base + PM(off)); - spin_unlock_irqrestore(&pctrl->lock, flags); + raw_spin_unlock_irqrestore(&pctrl->lock, flags); } static int rzg2l_gpio_get_direction(struct gpio_chip *chip, unsigned int offset) @@ -1761,7 +1761,7 @@ static int rzg2l_gpio_set(struct gpio_chip *chip, unsigned int offset, unsigned long flags; u8 reg8; - spin_lock_irqsave(&pctrl->lock, flags); + raw_spin_lock_irqsave(&pctrl->lock, flags); reg8 = readb(pctrl->base + P(off)); @@ -1770,7 +1770,7 @@ static int rzg2l_gpio_set(struct gpio_chip *chip, unsigned int offset, else writeb(reg8 & ~BIT(bit), pctrl->base + P(off)); - spin_unlock_irqrestore(&pctrl->lock, flags); + raw_spin_unlock_irqrestore(&pctrl->lock, flags); return 0; } @@ -2429,14 +2429,13 @@ static int rzg2l_gpio_get_gpioint(unsigned int virq, struct rzg2l_pinctrl *pctrl return gpioint; } -static void rzg2l_gpio_irq_endisable(struct rzg2l_pinctrl *pctrl, - unsigned int hwirq, bool enable) +static void __rzg2l_gpio_irq_endisable(struct rzg2l_pinctrl *pctrl, + unsigned int hwirq, bool enable) { const struct pinctrl_pin_desc *pin_desc = &pctrl->desc.pins[hwirq]; u64 *pin_data = pin_desc->drv_data; u32 off = RZG2L_PIN_CFG_TO_PORT_OFFSET(*pin_data); u8 bit = RZG2L_PIN_ID_TO_PIN(hwirq); - unsigned long flags; void __iomem *addr; addr = pctrl->base + ISEL(off); @@ -2445,12 +2444,20 @@ static void rzg2l_gpio_irq_endisable(struct rzg2l_pinctrl *pctrl, addr += 4; } - spin_lock_irqsave(&pctrl->lock, flags); if (enable) writel(readl(addr) | BIT(bit * 8), addr); else writel(readl(addr) & ~BIT(bit * 8), addr); - spin_unlock_irqrestore(&pctrl->lock, flags); +} + +static void rzg2l_gpio_irq_endisable(struct rzg2l_pinctrl *pctrl, + unsigned int hwirq, bool enable) +{ + unsigned long flags; + + raw_spin_lock_irqsave(&pctrl->lock, flags); + __rzg2l_gpio_irq_endisable(pctrl, hwirq, enable); + raw_spin_unlock_irqrestore(&pctrl->lock, flags); } static void rzg2l_gpio_irq_disable(struct irq_data *d) @@ -2462,15 +2469,25 @@ static void rzg2l_gpio_irq_disable(struct irq_data *d) gpiochip_disable_irq(gc, hwirq); } -static void rzg2l_gpio_irq_enable(struct irq_data *d) +static void __rzg2l_gpio_irq_enable(struct irq_data *d, bool lock) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct rzg2l_pinctrl *pctrl = container_of(gc, struct rzg2l_pinctrl, gpio_chip); unsigned int hwirq = irqd_to_hwirq(d); gpiochip_enable_irq(gc, hwirq); + if (lock) + rzg2l_gpio_irq_endisable(pctrl, hwirq, true); + else + __rzg2l_gpio_irq_endisable(pctrl, hwirq, true); irq_chip_enable_parent(d); } +static void rzg2l_gpio_irq_enable(struct irq_data *d) +{ + __rzg2l_gpio_irq_enable(d, true); +} + static int rzg2l_gpio_irq_set_type(struct irq_data *d, unsigned int type) { return irq_chip_set_type_parent(d, type); @@ -2616,11 +2633,11 @@ static void rzg2l_gpio_irq_restore(struct rzg2l_pinctrl *pctrl) * This has to be atomically executed to protect against a concurrent * interrupt. */ - spin_lock_irqsave(&pctrl->lock, flags); + raw_spin_lock_irqsave(&pctrl->lock, flags); ret = rzg2l_gpio_irq_set_type(data, irqd_get_trigger_type(data)); if (!ret && !irqd_irq_disabled(data)) - rzg2l_gpio_irq_enable(data); - spin_unlock_irqrestore(&pctrl->lock, flags); + __rzg2l_gpio_irq_enable(data, false); + raw_spin_unlock_irqrestore(&pctrl->lock, flags); if (ret) dev_crit(pctrl->dev, "Failed to set IRQ type for virq=%u\n", virq); @@ -2950,7 +2967,7 @@ static int rzg2l_pinctrl_probe(struct platform_device *pdev) "failed to enable GPIO clk\n"); } - spin_lock_init(&pctrl->lock); + raw_spin_lock_init(&pctrl->lock); spin_lock_init(&pctrl->bitmap_lock); mutex_init(&pctrl->mutex); atomic_set(&pctrl->wakeup_path, 0); @@ -3097,7 +3114,7 @@ static void rzg2l_pinctrl_pm_setup_pfc(struct rzg2l_pinctrl *pctrl) u32 nports = pctrl->data->n_port_pins / RZG2L_PINS_PER_PORT; unsigned long flags; - spin_lock_irqsave(&pctrl->lock, flags); + raw_spin_lock_irqsave(&pctrl->lock, flags); pctrl->data->pwpr_pfc_lock_unlock(pctrl, false); /* Restore port registers. */ @@ -3142,7 +3159,7 @@ static void rzg2l_pinctrl_pm_setup_pfc(struct rzg2l_pinctrl *pctrl) } pctrl->data->pwpr_pfc_lock_unlock(pctrl, true); - spin_unlock_irqrestore(&pctrl->lock, flags); + raw_spin_unlock_irqrestore(&pctrl->lock, flags); } static int rzg2l_pinctrl_suspend_noirq(struct device *dev) @@ -3191,14 +3208,14 @@ static int rzg2l_pinctrl_resume_noirq(struct device *dev) writeb(cache->qspi, pctrl->base + QSPI); if (pctrl->data->hwcfg->oen_pwpr_lock) { - spin_lock_irqsave(&pctrl->lock, flags); + raw_spin_lock_irqsave(&pctrl->lock, flags); pwpr = readb(pctrl->base + regs->pwpr); writeb(pwpr | PWPR_REGWE_B, pctrl->base + regs->pwpr); } writeb(cache->oen, pctrl->base + pctrl->data->hwcfg->regs.oen); if (pctrl->data->hwcfg->oen_pwpr_lock) { writeb(pwpr & ~PWPR_REGWE_B, pctrl->base + regs->pwpr); - spin_unlock_irqrestore(&pctrl->lock, flags); + raw_spin_unlock_irqrestore(&pctrl->lock, flags); } for (u8 i = 0; i < 2; i++) { if (regs->sd_ch) From cb51bef465d8ec60a968507330e01020e35dc127 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Mon, 1 Dec 2025 18:03:33 -0800 Subject: [PATCH 1329/2333] KVM: Disallow toggling KVM_MEM_GUEST_MEMFD on an existing memslot commit 9935df5333aa503a18de5071f53762b65c783c4c upstream. Reject attempts to disable KVM_MEM_GUEST_MEMFD on a memslot that was initially created with a guest_memfd binding, as KVM doesn't support toggling KVM_MEM_GUEST_MEMFD on existing memslots. KVM prevents enabling KVM_MEM_GUEST_MEMFD, but doesn't prevent clearing the flag. Failure to reject the new memslot results in a use-after-free due to KVM not unbinding from the guest_memfd instance. Unbinding on a FLAGS_ONLY change is easy enough, and can/will be done as a hardening measure (in anticipation of KVM supporting dirty logging on guest_memfd at some point), but fixing the use-after-free would only address the immediate symptom. ================================================================== BUG: KASAN: slab-use-after-free in kvm_gmem_release+0x362/0x400 [kvm] Write of size 8 at addr ffff8881111ae908 by task repro/745 CPU: 7 UID: 1000 PID: 745 Comm: repro Not tainted 6.18.0-rc6-115d5de2eef3-next-kasan #3 NONE Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 0.0.0 02/06/2015 Call Trace: dump_stack_lvl+0x51/0x60 print_report+0xcb/0x5c0 kasan_report+0xb4/0xe0 kvm_gmem_release+0x362/0x400 [kvm] __fput+0x2fa/0x9d0 task_work_run+0x12c/0x200 do_exit+0x6ae/0x2100 do_group_exit+0xa8/0x230 __x64_sys_exit_group+0x3a/0x50 x64_sys_call+0x737/0x740 do_syscall_64+0x5b/0x900 entry_SYSCALL_64_after_hwframe+0x4b/0x53 RIP: 0033:0x7f581f2eac31 Allocated by task 745 on cpu 6 at 9.746971s: kasan_save_stack+0x20/0x40 kasan_save_track+0x13/0x50 __kasan_kmalloc+0x77/0x90 kvm_set_memory_region.part.0+0x652/0x1110 [kvm] kvm_vm_ioctl+0x14b0/0x3290 [kvm] __x64_sys_ioctl+0x129/0x1a0 do_syscall_64+0x5b/0x900 entry_SYSCALL_64_after_hwframe+0x4b/0x53 Freed by task 745 on cpu 6 at 9.747467s: kasan_save_stack+0x20/0x40 kasan_save_track+0x13/0x50 __kasan_save_free_info+0x37/0x50 __kasan_slab_free+0x3b/0x60 kfree+0xf5/0x440 kvm_set_memslot+0x3c2/0x1160 [kvm] kvm_set_memory_region.part.0+0x86a/0x1110 [kvm] kvm_vm_ioctl+0x14b0/0x3290 [kvm] __x64_sys_ioctl+0x129/0x1a0 do_syscall_64+0x5b/0x900 entry_SYSCALL_64_after_hwframe+0x4b/0x53 Reported-by: Alexander Potapenko Fixes: a7800aa80ea4 ("KVM: Add KVM_CREATE_GUEST_MEMFD ioctl() for guest-specific backing memory") Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20251202020334.1171351-2-seanjc@google.com Signed-off-by: Sean Christopherson Signed-off-by: Greg Kroah-Hartman --- virt/kvm/kvm_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index b7a0ae2a7b205..01ea4f8351a61 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -2085,7 +2085,7 @@ static int kvm_set_memory_region(struct kvm *kvm, return -EINVAL; if ((mem->userspace_addr != old->userspace_addr) || (npages != old->npages) || - ((mem->flags ^ old->flags) & KVM_MEM_READONLY)) + ((mem->flags ^ old->flags) & (KVM_MEM_READONLY | KVM_MEM_GUEST_MEMFD))) return -EINVAL; if (base_gfn != old->base_gfn) From 65d4e5af2a2e82f4fc50d8259aee208fbc6b2c1d Mon Sep 17 00:00:00 2001 From: Deepanshu Kartikey Date: Wed, 10 Dec 2025 07:50:24 +0530 Subject: [PATCH 1330/2333] mm/slub: reset KASAN tag in defer_free() before accessing freed memory commit 53ca00a19d345197a37a1bf552e8d1e7b091666c upstream. When CONFIG_SLUB_TINY is enabled, kfree_nolock() calls kasan_slab_free() before defer_free(). On ARM64 with MTE (Memory Tagging Extension), kasan_slab_free() poisons the memory and changes the tag from the original (e.g., 0xf3) to a poison tag (0xfe). When defer_free() then tries to write to the freed object to build the deferred free list via llist_add(), the pointer still has the old tag, causing a tag mismatch and triggering a KASAN use-after-free report: BUG: KASAN: slab-use-after-free in defer_free+0x3c/0xbc mm/slub.c:6537 Write at addr f3f000000854f020 by task kworker/u8:6/983 Pointer tag: [f3], memory tag: [fe] Fix this by calling kasan_reset_tag() before accessing the freed memory. This is safe because defer_free() is part of the allocator itself and is expected to manipulate freed memory for bookkeeping purposes. Fixes: af92793e52c3 ("slab: Introduce kmalloc_nolock() and kfree_nolock().") Cc: stable@vger.kernel.org Reported-by: syzbot+7a25305a76d872abcfa1@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=7a25305a76d872abcfa1 Tested-by: syzbot+7a25305a76d872abcfa1@syzkaller.appspotmail.com Signed-off-by: Deepanshu Kartikey Acked-by: Alexei Starovoitov Link: https://patch.msgid.link/20251210022024.3255826-1-kartikey406@gmail.com Signed-off-by: Vlastimil Babka Signed-off-by: Greg Kroah-Hartman --- mm/slub.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mm/slub.c b/mm/slub.c index e4aaaf0a5e040..507f346102256 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -6509,6 +6509,8 @@ static void defer_free(struct kmem_cache *s, void *head) guard(preempt)(); + head = kasan_reset_tag(head); + df = this_cpu_ptr(&defer_free_objects); if (llist_add(head + s->offset, &df->objects)) irq_work_queue(&df->work); From 30f4d4e5224a9e44e9ceb3956489462319d804ce Mon Sep 17 00:00:00 2001 From: Jeongjun Park Date: Fri, 5 Sep 2025 14:18:16 +0900 Subject: [PATCH 1331/2333] media: vidtv: initialize local pointers upon transfer of memory ownership commit 98aabfe2d79f74613abc2b0b1cef08f97eaf5322 upstream. vidtv_channel_si_init() creates a temporary list (program, service, event) and ownership of the memory itself is transferred to the PAT/SDT/EIT tables through vidtv_psi_pat_program_assign(), vidtv_psi_sdt_service_assign(), vidtv_psi_eit_event_assign(). The problem here is that the local pointer where the memory ownership transfer was completed is not initialized to NULL. This causes the vidtv_psi_pmt_create_sec_for_each_pat_entry() function to fail, and in the flow that jumps to free_eit, the memory that was freed by vidtv_psi_*_table_destroy() can be accessed again by vidtv_psi_*_event_destroy() due to the uninitialized local pointer, so it is freed once again. Therefore, to prevent use-after-free and double-free vulnerability, local pointers must be initialized to NULL when transferring memory ownership. Cc: Reported-by: syzbot+1d9c0edea5907af239e0@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=1d9c0edea5907af239e0 Fixes: 3be8037960bc ("media: vidtv: add error checks") Signed-off-by: Jeongjun Park Reviewed-by: Daniel Almeida Signed-off-by: Hans Verkuil Signed-off-by: Greg Kroah-Hartman --- drivers/media/test-drivers/vidtv/vidtv_channel.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/media/test-drivers/vidtv/vidtv_channel.c b/drivers/media/test-drivers/vidtv/vidtv_channel.c index f3023e91b3ebc..3541155c6fc63 100644 --- a/drivers/media/test-drivers/vidtv/vidtv_channel.c +++ b/drivers/media/test-drivers/vidtv/vidtv_channel.c @@ -461,12 +461,15 @@ int vidtv_channel_si_init(struct vidtv_mux *m) /* assemble all programs and assign to PAT */ vidtv_psi_pat_program_assign(m->si.pat, programs); + programs = NULL; /* assemble all services and assign to SDT */ vidtv_psi_sdt_service_assign(m->si.sdt, services); + services = NULL; /* assemble all events and assign to EIT */ vidtv_psi_eit_event_assign(m->si.eit, events); + events = NULL; m->si.pmt_secs = vidtv_psi_pmt_create_sec_for_each_pat_entry(m->si.pat, m->pcr_pid); From 7acc0390e0dd7474c4451d05465a677d55ad4268 Mon Sep 17 00:00:00 2001 From: Prithvi Tambewagh Date: Mon, 1 Dec 2025 18:37:11 +0530 Subject: [PATCH 1332/2333] ocfs2: fix kernel BUG in ocfs2_find_victim_chain commit 039bef30e320827bac8990c9f29d2a68cd8adb5f upstream. syzbot reported a kernel BUG in ocfs2_find_victim_chain() because the `cl_next_free_rec` field of the allocation chain list (next free slot in the chain list) is 0, triggring the BUG_ON(!cl->cl_next_free_rec) condition in ocfs2_find_victim_chain() and panicking the kernel. To fix this, an if condition is introduced in ocfs2_claim_suballoc_bits(), just before calling ocfs2_find_victim_chain(), the code block in it being executed when either of the following conditions is true: 1. `cl_next_free_rec` is equal to 0, indicating that there are no free chains in the allocation chain list 2. `cl_next_free_rec` is greater than `cl_count` (the total number of chains in the allocation chain list) Either of them being true is indicative of the fact that there are no chains left for usage. This is addressed using ocfs2_error(), which prints the error log for debugging purposes, rather than panicking the kernel. Link: https://lkml.kernel.org/r/20251201130711.143900-1-activprithvi@gmail.com Signed-off-by: Prithvi Tambewagh Reported-by: syzbot+96d38c6e1655c1420a72@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=96d38c6e1655c1420a72 Tested-by: syzbot+96d38c6e1655c1420a72@syzkaller.appspotmail.com Reviewed-by: Joseph Qi Cc: Mark Fasheh Cc: Joel Becker Cc: Junxiao Bi Cc: Changwei Ge Cc: Jun Piao Cc: Heming Zhao Cc: Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- fs/ocfs2/suballoc.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/fs/ocfs2/suballoc.c b/fs/ocfs2/suballoc.c index 6ac4dcd54588c..e93fc842bb203 100644 --- a/fs/ocfs2/suballoc.c +++ b/fs/ocfs2/suballoc.c @@ -1992,6 +1992,16 @@ static int ocfs2_claim_suballoc_bits(struct ocfs2_alloc_context *ac, } cl = (struct ocfs2_chain_list *) &fe->id2.i_chain; + if (!le16_to_cpu(cl->cl_next_free_rec) || + le16_to_cpu(cl->cl_next_free_rec) > le16_to_cpu(cl->cl_count)) { + status = ocfs2_error(ac->ac_inode->i_sb, + "Chain allocator dinode %llu has invalid next " + "free chain record %u, but only %u total\n", + (unsigned long long)le64_to_cpu(fe->i_blkno), + le16_to_cpu(cl->cl_next_free_rec), + le16_to_cpu(cl->cl_count)); + goto bail; + } victim = ocfs2_find_victim_chain(cl); ac->ac_chain = victim; From f73b74dafa3c888c62618c3b8c39fba3b058cfc0 Mon Sep 17 00:00:00 2001 From: Maxim Levitsky Date: Tue, 14 Oct 2025 23:32:58 -0400 Subject: [PATCH 1333/2333] KVM: x86: Don't clear async #PF queue when CR0.PG is disabled (e.g. on #SMI) commit ab4e41eb9fabd4607304fa7cfe8ec9c0bd8e1552 upstream. Fix an interaction between SMM and PV asynchronous #PFs where an #SMI can cause KVM to drop an async #PF ready event, and thus result in guest tasks becoming permanently stuck due to the task that encountered the #PF never being resumed. Specifically, don't clear the completion queue when paging is disabled, and re-check for completed async #PFs if/when paging is enabled. Prior to commit 2635b5c4a0e4 ("KVM: x86: interrupt based APF 'page ready' event delivery"), flushing the APF queue without notifying the guest of completed APF requests when paging is disabled was "necessary", in that delivering a #PF to the guest when paging is disabled would likely confuse and/or crash the guest. And presumably the original async #PF development assumed that a guest would only disable paging when there was no intent to ever re-enable paging. That assumption fails in several scenarios, most visibly on an emulated SMI, as entering SMM always disables CR0.PG (i.e. initially runs with paging disabled). When the SMM handler eventually executes RSM, the interrupted paging-enabled is restored, and the async #PF event is lost. Similarly, invoking firmware, e.g. via EFI runtime calls, might require a transition through paging modes and thus also disable paging with valid entries in the competion queue. To avoid dropping completion events, drop the "clear" entirely, and handle paging-enable transitions in the same way KVM already handles APIC enable/disable events: if a vCPU's APIC is disabled, APF completion events are not kept pending and not injected while APIC is disabled. Once a vCPU's APIC is re-enabled, KVM raises KVM_REQ_APF_READY so that the vCPU recognizes any pending pending #APF ready events. Signed-off-by: Maxim Levitsky Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20251015033258.50974-4-mlevitsk@redhat.com [sean: rework changelog to call out #PF injection, drop "real mode" references, expand the code comment] Signed-off-by: Sean Christopherson Signed-off-by: Greg Kroah-Hartman --- arch/x86/kvm/x86.c | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index e6f2e34ec97d1..5d3297cef8a99 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -1045,6 +1045,13 @@ bool kvm_require_dr(struct kvm_vcpu *vcpu, int dr) } EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_require_dr); +static bool kvm_pv_async_pf_enabled(struct kvm_vcpu *vcpu) +{ + u64 mask = KVM_ASYNC_PF_ENABLED | KVM_ASYNC_PF_DELIVERY_AS_INT; + + return (vcpu->arch.apf.msr_en_val & mask) == mask; +} + static inline u64 pdptr_rsvd_bits(struct kvm_vcpu *vcpu) { return vcpu->arch.reserved_gpa_bits | rsvd_bits(5, 8) | rsvd_bits(1, 2); @@ -1137,15 +1144,20 @@ void kvm_post_set_cr0(struct kvm_vcpu *vcpu, unsigned long old_cr0, unsigned lon } if ((cr0 ^ old_cr0) & X86_CR0_PG) { - kvm_clear_async_pf_completion_queue(vcpu); - kvm_async_pf_hash_reset(vcpu); - /* * Clearing CR0.PG is defined to flush the TLB from the guest's * perspective. */ if (!(cr0 & X86_CR0_PG)) kvm_make_request(KVM_REQ_TLB_FLUSH_GUEST, vcpu); + /* + * Check for async #PF completion events when enabling paging, + * as the vCPU may have previously encountered async #PFs (it's + * entirely legal for the guest to toggle paging on/off without + * waiting for the async #PF queue to drain). + */ + else if (kvm_pv_async_pf_enabled(vcpu)) + kvm_make_request(KVM_REQ_APF_READY, vcpu); } if ((cr0 ^ old_cr0) & KVM_MMU_CR0_ROLE_BITS) @@ -3650,13 +3662,6 @@ static int set_msr_mce(struct kvm_vcpu *vcpu, struct msr_data *msr_info) return 0; } -static inline bool kvm_pv_async_pf_enabled(struct kvm_vcpu *vcpu) -{ - u64 mask = KVM_ASYNC_PF_ENABLED | KVM_ASYNC_PF_DELIVERY_AS_INT; - - return (vcpu->arch.apf.msr_en_val & mask) == mask; -} - static int kvm_pv_enable_async_pf(struct kvm_vcpu *vcpu, u64 data) { gpa_t gpa = data & ~0x3f; From 24a2062257bbdfc831de5ed21c27b04b5bdf2437 Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Fri, 31 Oct 2025 03:39:00 +0000 Subject: [PATCH 1334/2333] platform/chrome: cros_ec_ishtp: Fix UAF after unbinding driver commit 944edca81e7aea15f83cf9a13a6ab67f711e8abd upstream. After unbinding the driver, another kthread `cros_ec_console_log_work` is still accessing the device, resulting an UAF and crash. The driver doesn't unregister the EC device in .remove() which should shutdown sub-devices synchronously. Fix it. Fixes: 26a14267aff2 ("platform/chrome: Add ChromeOS EC ISHTP driver") Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20251031033900.3577394-1-tzungbi@kernel.org Signed-off-by: Tzung-Bi Shih Signed-off-by: Greg Kroah-Hartman --- drivers/platform/chrome/cros_ec_ishtp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/platform/chrome/cros_ec_ishtp.c b/drivers/platform/chrome/cros_ec_ishtp.c index 4e74e702c5a24..3766cef81fe82 100644 --- a/drivers/platform/chrome/cros_ec_ishtp.c +++ b/drivers/platform/chrome/cros_ec_ishtp.c @@ -667,6 +667,7 @@ static void cros_ec_ishtp_remove(struct ishtp_cl_device *cl_device) cancel_work_sync(&client_data->work_ishtp_reset); cancel_work_sync(&client_data->work_ec_evt); + cros_ec_unregister(client_data->ec_dev); cros_ish_deinit(cros_ish_cl); ishtp_put_device(cl_device); } From f8b136296722e258ec43237a35f72c92a6d4501a Mon Sep 17 00:00:00 2001 From: Wangao Wang Date: Mon, 27 Oct 2025 17:35:59 +0800 Subject: [PATCH 1335/2333] media: iris: Add sanity check for stop streaming commit ad699fa78b59241c9d71a8cafb51525f3dab04d4 upstream. Add sanity check in iris_vb2_stop_streaming. If inst->state is already IRIS_INST_ERROR, we should skip the stream_off operation because it would still send packets to the firmware. In iris_kill_session, inst->state is set to IRIS_INST_ERROR and session_close is executed, which will kfree(inst_hfi_gen2->packet). If stop_streaming is called afterward, it will cause a crash. Fixes: 11712ce70f8e5 ("media: iris: implement vb2 streaming ops") Cc: stable@vger.kernel.org Reviewed-by: Bryan O'Donoghue Reviewed-by: Dikshita Agarwal Signed-off-by: Wangao Wang Reviewed-by: Vikash Garodia [bod: remove qcom from patch title] Signed-off-by: Bryan O'Donoghue Signed-off-by: Hans Verkuil Signed-off-by: Greg Kroah-Hartman --- drivers/media/platform/qcom/iris/iris_vb2.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/qcom/iris/iris_vb2.c b/drivers/media/platform/qcom/iris/iris_vb2.c index 139b821f7952f..db8768d8a8f61 100644 --- a/drivers/media/platform/qcom/iris/iris_vb2.c +++ b/drivers/media/platform/qcom/iris/iris_vb2.c @@ -231,6 +231,8 @@ void iris_vb2_stop_streaming(struct vb2_queue *q) return; mutex_lock(&inst->lock); + if (inst->state == IRIS_INST_ERROR) + goto exit; if (!V4L2_TYPE_IS_OUTPUT(q->type) && !V4L2_TYPE_IS_CAPTURE(q->type)) @@ -241,10 +243,10 @@ void iris_vb2_stop_streaming(struct vb2_queue *q) goto exit; exit: - iris_helper_buffers_done(inst, q->type, VB2_BUF_STATE_ERROR); - if (ret) + if (ret) { + iris_helper_buffers_done(inst, q->type, VB2_BUF_STATE_ERROR); iris_inst_change_state(inst, IRIS_INST_ERROR); - + } mutex_unlock(&inst->lock); } From a19fb3611e4c06624fc0f83ef19f4fb8d57d4751 Mon Sep 17 00:00:00 2001 From: Zhichi Lin Date: Sat, 11 Oct 2025 16:22:22 +0800 Subject: [PATCH 1336/2333] scs: fix a wrong parameter in __scs_magic commit 08bd4c46d5e63b78e77f2605283874bbe868ab19 upstream. __scs_magic() needs a 'void *' variable, but a 'struct task_struct *' is given. 'task_scs(tsk)' is the starting address of the task's shadow call stack, and '__scs_magic(task_scs(tsk))' is the end address of the task's shadow call stack. Here should be '__scs_magic(task_scs(tsk))'. The user-visible effect of this bug is that when CONFIG_DEBUG_STACK_USAGE is enabled, the shadow call stack usage checking function (scs_check_usage) would scan an incorrect memory range. This could lead to: 1. **Inaccurate stack usage reporting**: The function would calculate wrong usage statistics for the shadow call stack, potentially showing incorrect value in kmsg. 2. **Potential kernel crash**: If the value of __scs_magic(tsk)is greater than that of __scs_magic(task_scs(tsk)), the for loop may access unmapped memory, potentially causing a kernel panic. However, this scenario is unlikely because task_struct is allocated via the slab allocator (which typically returns lower addresses), while the shadow call stack returned by task_scs(tsk) is allocated via vmalloc(which typically returns higher addresses). However, since this is purely a debugging feature (CONFIG_DEBUG_STACK_USAGE), normal production systems should be not unaffected. The bug only impacts developers and testers who are actively debugging stack usage with this configuration enabled. Link: https://lkml.kernel.org/r/20251011082222.12965-1-zhichi.lin@vivo.com Fixes: 5bbaf9d1fcb9 ("scs: Add support for stack usage debugging") Signed-off-by: Jiyuan Xie Signed-off-by: Zhichi Lin Reviewed-by: Sami Tolvanen Acked-by: Will Deacon Cc: Andrey Konovalov Cc: Kees Cook Cc: Marco Elver Cc: Will Deacon Cc: Yee Lee Cc: Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- kernel/scs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/scs.c b/kernel/scs.c index d7809affe7404..772488afd5b97 100644 --- a/kernel/scs.c +++ b/kernel/scs.c @@ -135,7 +135,7 @@ static void scs_check_usage(struct task_struct *tsk) if (!IS_ENABLED(CONFIG_DEBUG_STACK_USAGE)) return; - for (p = task_scs(tsk); p < __scs_magic(tsk); ++p) { + for (p = task_scs(tsk); p < __scs_magic(task_scs(tsk)); ++p) { if (!READ_ONCE_NOCHECK(*p)) break; used += sizeof(*p); From c8f810e20f4bbe50b49f73429d9fa6efad00623e Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Tue, 25 Nov 2025 15:23:02 +0100 Subject: [PATCH 1337/2333] parisc: Do not reprogram affinitiy on ASP chip commit dca7da244349eef4d78527cafc0bf80816b261f5 upstream. The ASP chip is a very old variant of the GSP chip and is used e.g. in HP 730 workstations. When trying to reprogram the affinity it will crash with a HPMC as the relevant registers don't seem to be at the usual location. Let's avoid the crash by checking the sversion. Also note, that reprogramming isn't necessary either, as the HP730 is a just a single-CPU machine. Signed-off-by: Helge Deller Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/parisc/gsc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/parisc/gsc.c b/drivers/parisc/gsc.c index a0daaa548bc39..8ba778170447e 100644 --- a/drivers/parisc/gsc.c +++ b/drivers/parisc/gsc.c @@ -154,7 +154,9 @@ static int gsc_set_affinity_irq(struct irq_data *d, const struct cpumask *dest, gsc_dev->eim = ((u32) gsc_dev->gsc_irq.txn_addr) | gsc_dev->gsc_irq.txn_data; /* switch IRQ's for devices below LASI/WAX to other CPU */ - gsc_writel(gsc_dev->eim, gsc_dev->hpa + OFFSET_IAR); + /* ASP chip (svers 0x70) does not support reprogramming */ + if (gsc_dev->gsc->id.sversion != 0x70) + gsc_writel(gsc_dev->eim, gsc_dev->hpa + OFFSET_IAR); irq_data_update_effective_affinity(d, &tmask); From 3383f16f7870e4cd81e326c9a32f3416305b24b5 Mon Sep 17 00:00:00 2001 From: Dongsheng Yang Date: Fri, 5 Dec 2025 05:46:18 +0000 Subject: [PATCH 1338/2333] dm-pcache: advance slot index before writing slot MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit ebbb90344a7da2421e4b54668b94e81828b8b308 upstream. In dm-pcache, in order to ensure crash-consistency, a dual-copy scheme is used to alternately update metadata, and there is a slot index that records the current slot. However, in the write path the current implementation writes directly to the current slot indexed by slot index, and then advances the slot — which ends up overwriting the existing slot, violating the crash-consistency guarantee. This patch fixes that behavior, preventing metadata from being overwritten incorrectly. In addition, this patch add a missing pmem_wmb() after memcpy_flushcache(). Signed-off-by: Dongsheng Yang Signed-off-by: Mikulas Patocka Reviewed-by: Zheng Gu Cc: stable@vger.kernel.org # 6.18 Signed-off-by: Greg Kroah-Hartman --- drivers/md/dm-pcache/cache.c | 8 ++++---- drivers/md/dm-pcache/cache_segment.c | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/md/dm-pcache/cache.c b/drivers/md/dm-pcache/cache.c index 698697a7a73c6..d4385d76ac36d 100644 --- a/drivers/md/dm-pcache/cache.c +++ b/drivers/md/dm-pcache/cache.c @@ -21,10 +21,10 @@ static void cache_info_write(struct pcache_cache *cache) cache_info->header.crc = pcache_meta_crc(&cache_info->header, sizeof(struct pcache_cache_info)); + cache->info_index = (cache->info_index + 1) % PCACHE_META_INDEX_MAX; memcpy_flushcache(get_cache_info_addr(cache), cache_info, sizeof(struct pcache_cache_info)); - - cache->info_index = (cache->info_index + 1) % PCACHE_META_INDEX_MAX; + pmem_wmb(); } static void cache_info_init_default(struct pcache_cache *cache); @@ -93,10 +93,10 @@ void cache_pos_encode(struct pcache_cache *cache, pos_onmedia.header.seq = seq; pos_onmedia.header.crc = cache_pos_onmedia_crc(&pos_onmedia); + *index = (*index + 1) % PCACHE_META_INDEX_MAX; + memcpy_flushcache(pos_onmedia_addr, &pos_onmedia, sizeof(struct pcache_cache_pos_onmedia)); pmem_wmb(); - - *index = (*index + 1) % PCACHE_META_INDEX_MAX; } int cache_pos_decode(struct pcache_cache *cache, diff --git a/drivers/md/dm-pcache/cache_segment.c b/drivers/md/dm-pcache/cache_segment.c index f0b58980806e0..ae57cc261422d 100644 --- a/drivers/md/dm-pcache/cache_segment.c +++ b/drivers/md/dm-pcache/cache_segment.c @@ -26,11 +26,11 @@ static void cache_seg_info_write(struct pcache_cache_segment *cache_seg) seg_info->header.seq++; seg_info->header.crc = pcache_meta_crc(&seg_info->header, sizeof(struct pcache_segment_info)); + cache_seg->info_index = (cache_seg->info_index + 1) % PCACHE_META_INDEX_MAX; + seg_info_addr = get_seg_info_addr(cache_seg); memcpy_flushcache(seg_info_addr, seg_info, sizeof(struct pcache_segment_info)); pmem_wmb(); - - cache_seg->info_index = (cache_seg->info_index + 1) % PCACHE_META_INDEX_MAX; mutex_unlock(&cache_seg->info_lock); } @@ -129,10 +129,10 @@ static void cache_seg_ctrl_write(struct pcache_cache_segment *cache_seg) cache_seg_gen.header.crc = pcache_meta_crc(&cache_seg_gen.header, sizeof(struct pcache_cache_seg_gen)); + cache_seg->gen_index = (cache_seg->gen_index + 1) % PCACHE_META_INDEX_MAX; + memcpy_flushcache(get_cache_seg_gen_addr(cache_seg), &cache_seg_gen, sizeof(struct pcache_cache_seg_gen)); pmem_wmb(); - - cache_seg->gen_index = (cache_seg->gen_index + 1) % PCACHE_META_INDEX_MAX; } static void cache_seg_ctrl_init(struct pcache_cache_segment *cache_seg) From 37a691ed7942feec5a91d602290818f128a635f8 Mon Sep 17 00:00:00 2001 From: Vivian Wang Date: Tue, 2 Dec 2025 13:25:07 +0800 Subject: [PATCH 1339/2333] lib/crypto: riscv/chacha: Avoid s0/fp register commit 43169328c7b4623b54b7713ec68479cebda5465f upstream. In chacha_zvkb, avoid using the s0 register, which is the frame pointer, by reallocating KEY0 to t5. This makes stack traces available if e.g. a crash happens in chacha_zvkb. No frame pointer maintenance is otherwise required since this is a leaf function. Signed-off-by: Vivian Wang Fixes: bb54668837a0 ("crypto: riscv - add vector crypto accelerated ChaCha20") Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20251202-riscv-chacha_zvkb-fp-v2-1-7bd00098c9dc@iscas.ac.cn Signed-off-by: Eric Biggers Signed-off-by: Greg Kroah-Hartman --- lib/crypto/riscv/chacha-riscv64-zvkb.S | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/crypto/riscv/chacha-riscv64-zvkb.S b/lib/crypto/riscv/chacha-riscv64-zvkb.S index b777d0b4e3796..3d183ec818f52 100644 --- a/lib/crypto/riscv/chacha-riscv64-zvkb.S +++ b/lib/crypto/riscv/chacha-riscv64-zvkb.S @@ -60,7 +60,8 @@ #define VL t2 #define STRIDE t3 #define ROUND_CTR t4 -#define KEY0 s0 +#define KEY0 t5 +// Avoid s0/fp to allow for unwinding #define KEY1 s1 #define KEY2 s2 #define KEY3 s3 @@ -143,7 +144,6 @@ // The updated 32-bit counter is written back to state->x[12] before returning. SYM_FUNC_START(chacha_zvkb) addi sp, sp, -96 - sd s0, 0(sp) sd s1, 8(sp) sd s2, 16(sp) sd s3, 24(sp) @@ -280,7 +280,6 @@ SYM_FUNC_START(chacha_zvkb) bnez NBLOCKS, .Lblock_loop sw COUNTER, 48(STATEP) - ld s0, 0(sp) ld s1, 8(sp) ld s2, 16(sp) ld s3, 24(sp) From 2acb8517429ab42146c6c0ac1daed1f03d2fd125 Mon Sep 17 00:00:00 2001 From: Ilya Dryomov Date: Tue, 2 Dec 2025 10:32:31 +0100 Subject: [PATCH 1340/2333] libceph: make decode_pool() more resilient against corrupted osdmaps commit 8c738512714e8c0aa18f8a10c072d5b01c83db39 upstream. If the osdmap is (maliciously) corrupted such that the encoded length of ceph_pg_pool envelope is less than what is expected for a particular encoding version, out-of-bounds reads may ensue because the only bounds check that is there is based on that length value. This patch adds explicit bounds checks for each field that is decoded or skipped. Cc: stable@vger.kernel.org Reported-by: ziming zhang Signed-off-by: Ilya Dryomov Reviewed-by: Xiubo Li Tested-by: ziming zhang Signed-off-by: Greg Kroah-Hartman --- net/ceph/osdmap.c | 116 +++++++++++++++++++++------------------------- 1 file changed, 52 insertions(+), 64 deletions(-) diff --git a/net/ceph/osdmap.c b/net/ceph/osdmap.c index d245fa508e1cc..f5f60deb680ae 100644 --- a/net/ceph/osdmap.c +++ b/net/ceph/osdmap.c @@ -806,51 +806,49 @@ static int decode_pool(void **p, void *end, struct ceph_pg_pool_info *pi) ceph_decode_need(p, end, len, bad); pool_end = *p + len; + ceph_decode_need(p, end, 4 + 4 + 4, bad); pi->type = ceph_decode_8(p); pi->size = ceph_decode_8(p); pi->crush_ruleset = ceph_decode_8(p); pi->object_hash = ceph_decode_8(p); - pi->pg_num = ceph_decode_32(p); pi->pgp_num = ceph_decode_32(p); - *p += 4 + 4; /* skip lpg* */ - *p += 4; /* skip last_change */ - *p += 8 + 4; /* skip snap_seq, snap_epoch */ + /* lpg*, last_change, snap_seq, snap_epoch */ + ceph_decode_skip_n(p, end, 8 + 4 + 8 + 4, bad); /* skip snaps */ - num = ceph_decode_32(p); + ceph_decode_32_safe(p, end, num, bad); while (num--) { - *p += 8; /* snapid key */ - *p += 1 + 1; /* versions */ - len = ceph_decode_32(p); - *p += len; + /* snapid key, pool snap (with versions) */ + ceph_decode_skip_n(p, end, 8 + 2, bad); + ceph_decode_skip_string(p, end, bad); } - /* skip removed_snaps */ - num = ceph_decode_32(p); - *p += num * (8 + 8); + /* removed_snaps */ + ceph_decode_skip_map(p, end, 64, 64, bad); + ceph_decode_need(p, end, 8 + 8 + 4, bad); *p += 8; /* skip auid */ pi->flags = ceph_decode_64(p); *p += 4; /* skip crash_replay_interval */ if (ev >= 7) - pi->min_size = ceph_decode_8(p); + ceph_decode_8_safe(p, end, pi->min_size, bad); else pi->min_size = pi->size - pi->size / 2; if (ev >= 8) - *p += 8 + 8; /* skip quota_max_* */ + /* quota_max_* */ + ceph_decode_skip_n(p, end, 8 + 8, bad); if (ev >= 9) { - /* skip tiers */ - num = ceph_decode_32(p); - *p += num * 8; + /* tiers */ + ceph_decode_skip_set(p, end, 64, bad); + ceph_decode_need(p, end, 8 + 1 + 8 + 8, bad); *p += 8; /* skip tier_of */ *p += 1; /* skip cache_mode */ - pi->read_tier = ceph_decode_64(p); pi->write_tier = ceph_decode_64(p); } else { @@ -858,86 +856,76 @@ static int decode_pool(void **p, void *end, struct ceph_pg_pool_info *pi) pi->write_tier = -1; } - if (ev >= 10) { - /* skip properties */ - num = ceph_decode_32(p); - while (num--) { - len = ceph_decode_32(p); - *p += len; /* key */ - len = ceph_decode_32(p); - *p += len; /* val */ - } - } + if (ev >= 10) + /* properties */ + ceph_decode_skip_map(p, end, string, string, bad); if (ev >= 11) { - /* skip hit_set_params */ - *p += 1 + 1; /* versions */ - len = ceph_decode_32(p); - *p += len; + /* hit_set_params (with versions) */ + ceph_decode_skip_n(p, end, 2, bad); + ceph_decode_skip_string(p, end, bad); - *p += 4; /* skip hit_set_period */ - *p += 4; /* skip hit_set_count */ + /* hit_set_period, hit_set_count */ + ceph_decode_skip_n(p, end, 4 + 4, bad); } if (ev >= 12) - *p += 4; /* skip stripe_width */ + /* stripe_width */ + ceph_decode_skip_32(p, end, bad); - if (ev >= 13) { - *p += 8; /* skip target_max_bytes */ - *p += 8; /* skip target_max_objects */ - *p += 4; /* skip cache_target_dirty_ratio_micro */ - *p += 4; /* skip cache_target_full_ratio_micro */ - *p += 4; /* skip cache_min_flush_age */ - *p += 4; /* skip cache_min_evict_age */ - } + if (ev >= 13) + /* target_max_*, cache_target_*, cache_min_* */ + ceph_decode_skip_n(p, end, 16 + 8 + 8, bad); - if (ev >= 14) { - /* skip erasure_code_profile */ - len = ceph_decode_32(p); - *p += len; - } + if (ev >= 14) + /* erasure_code_profile */ + ceph_decode_skip_string(p, end, bad); /* * last_force_op_resend_preluminous, will be overridden if the * map was encoded with RESEND_ON_SPLIT */ if (ev >= 15) - pi->last_force_request_resend = ceph_decode_32(p); + ceph_decode_32_safe(p, end, pi->last_force_request_resend, bad); else pi->last_force_request_resend = 0; if (ev >= 16) - *p += 4; /* skip min_read_recency_for_promote */ + /* min_read_recency_for_promote */ + ceph_decode_skip_32(p, end, bad); if (ev >= 17) - *p += 8; /* skip expected_num_objects */ + /* expected_num_objects */ + ceph_decode_skip_64(p, end, bad); if (ev >= 19) - *p += 4; /* skip cache_target_dirty_high_ratio_micro */ + /* cache_target_dirty_high_ratio_micro */ + ceph_decode_skip_32(p, end, bad); if (ev >= 20) - *p += 4; /* skip min_write_recency_for_promote */ + /* min_write_recency_for_promote */ + ceph_decode_skip_32(p, end, bad); if (ev >= 21) - *p += 1; /* skip use_gmt_hitset */ + /* use_gmt_hitset */ + ceph_decode_skip_8(p, end, bad); if (ev >= 22) - *p += 1; /* skip fast_read */ + /* fast_read */ + ceph_decode_skip_8(p, end, bad); - if (ev >= 23) { - *p += 4; /* skip hit_set_grade_decay_rate */ - *p += 4; /* skip hit_set_search_last_n */ - } + if (ev >= 23) + /* hit_set_grade_decay_rate, hit_set_search_last_n */ + ceph_decode_skip_n(p, end, 4 + 4, bad); if (ev >= 24) { - /* skip opts */ - *p += 1 + 1; /* versions */ - len = ceph_decode_32(p); - *p += len; + /* opts (with versions) */ + ceph_decode_skip_n(p, end, 2, bad); + ceph_decode_skip_string(p, end, bad); } if (ev >= 25) - pi->last_force_request_resend = ceph_decode_32(p); + ceph_decode_32_safe(p, end, pi->last_force_request_resend, bad); /* ignore the rest */ From b3b320a900a54c48ff134131dfff962f48e7264f Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Mon, 10 Nov 2025 10:30:22 +1100 Subject: [PATCH 1341/2333] powerpc: Add reloc_offset() to font bitmap pointer used for bootx_printf() commit b94b73567561642323617155bf4ee24ef0d258fe upstream. Since Linux v6.7, booting using BootX on an Old World PowerMac produces an early crash. Stan Johnson writes, "the symptoms are that the screen goes blank and the backlight stays on, and the system freezes (Linux doesn't boot)." Further testing revealed that the failure can be avoided by disabling CONFIG_BOOTX_TEXT. Bisection revealed that the regression was caused by a change to the font bitmap pointer that's used when btext_init() begins painting characters on the display, early in the boot process. Christophe Leroy explains, "before kernel text is relocated to its final location ... data is addressed with an offset which is added to the Global Offset Table (GOT) entries at the start of bootx_init() by function reloc_got2(). But the pointers that are located inside a structure are not referenced in the GOT and are therefore not updated by reloc_got2(). It is therefore needed to apply the offset manually by using PTRRELOC() macro." Cc: stable@vger.kernel.org Link: https://lists.debian.org/debian-powerpc/2025/10/msg00111.html Link: https://lore.kernel.org/linuxppc-dev/d81ddca8-c5ee-d583-d579-02b19ed95301@yahoo.com/ Reported-by: Cedar Maxwell Closes: https://lists.debian.org/debian-powerpc/2025/09/msg00031.html Bisected-by: Stan Johnson Tested-by: Stan Johnson Fixes: 0ebc7feae79a ("powerpc: Use shared font data") Suggested-by: Christophe Leroy Signed-off-by: Finn Thain Reviewed-by: Christophe Leroy Signed-off-by: Madhavan Srinivasan Link: https://patch.msgid.link/22b3b247425a052b079ab84da926706b3702c2c7.1762731022.git.fthain@linux-m68k.org Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/kernel/btext.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/kernel/btext.c b/arch/powerpc/kernel/btext.c index 7f63f1cdc6c39..ca00c4824e313 100644 --- a/arch/powerpc/kernel/btext.c +++ b/arch/powerpc/kernel/btext.c @@ -20,6 +20,7 @@ #include #include #include +#include #define NO_SCROLL @@ -463,7 +464,7 @@ static noinline void draw_byte(unsigned char c, long locX, long locY) { unsigned char *base = calc_base(locX << 3, locY << 4); unsigned int font_index = c * 16; - const unsigned char *font = font_sun_8x16.data + font_index; + const unsigned char *font = PTRRELOC(font_sun_8x16.data) + font_index; int rb = dispDeviceRowBytes; rmci_maybe_on(); From 16fa73b11a9472444f855b386e478d6ebfb2348a Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Thu, 13 Nov 2025 12:51:11 -0800 Subject: [PATCH 1342/2333] KVM: x86: WARN if hrtimer callback for periodic APIC timer fires with period=0 commit 0ea9494be9c931ddbc084ad5e11fda91b554cf47 upstream. WARN and don't restart the hrtimer if KVM's callback runs with the guest's APIC timer in periodic mode but with a period of '0', as not advancing the hrtimer's deadline would put the CPU into an infinite loop of hrtimer events. Observing a period of '0' should be impossible, even when the hrtimer is running on a different CPU than the vCPU, as KVM is supposed to cancel the hrtimer before changing (or zeroing) the period, e.g. when switching from periodic to one-shot. Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20251113205114.1647493-2-seanjc@google.com Signed-off-by: Sean Christopherson Signed-off-by: Greg Kroah-Hartman --- arch/x86/kvm/lapic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index 0ae7f913d7826..78b74ba17592b 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -2970,7 +2970,7 @@ static enum hrtimer_restart apic_timer_fn(struct hrtimer *data) apic_timer_expired(apic, true); - if (lapic_is_periodic(apic)) { + if (lapic_is_periodic(apic) && !WARN_ON_ONCE(!apic->lapic_timer.period)) { advance_periodic_target_expiration(apic); hrtimer_add_expires_ns(&ktimer->timer, ktimer->period); return HRTIMER_RESTART; From a16ccbffb144f2b91084375bd77a1b1aab01d28e Mon Sep 17 00:00:00 2001 From: fuqiang wang Date: Thu, 13 Nov 2025 12:51:12 -0800 Subject: [PATCH 1343/2333] KVM: x86: Explicitly set new periodic hrtimer expiration in apic_timer_fn() commit 9633f180ce994ab293ce4924a9b7aaf4673aa114 upstream. When restarting an hrtimer to emulate a the guest's APIC timer in periodic mode, explicitly set the expiration using the target expiration computed by advance_periodic_target_expiration() instead of adding the period to the existing timer. This will allow making adjustments to the expiration, e.g. to deal with expirations far in the past, without having to implement the same logic in both advance_periodic_target_expiration() and apic_timer_fn(). Cc: stable@vger.kernel.org Signed-off-by: fuqiang wang [sean: split to separate patch, write changelog] Link: https://patch.msgid.link/20251113205114.1647493-3-seanjc@google.com Signed-off-by: Sean Christopherson Signed-off-by: Greg Kroah-Hartman --- arch/x86/kvm/lapic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index 78b74ba17592b..a5c927e7bae68 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -2972,7 +2972,7 @@ static enum hrtimer_restart apic_timer_fn(struct hrtimer *data) if (lapic_is_periodic(apic) && !WARN_ON_ONCE(!apic->lapic_timer.period)) { advance_periodic_target_expiration(apic); - hrtimer_add_expires_ns(&ktimer->timer, ktimer->period); + hrtimer_set_expires(&ktimer->timer, ktimer->target_expiration); return HRTIMER_RESTART; } else return HRTIMER_NORESTART; From e23f46f1a971c73dad2fd63e1408696114ddebe2 Mon Sep 17 00:00:00 2001 From: fuqiang wang Date: Thu, 13 Nov 2025 12:51:13 -0800 Subject: [PATCH 1344/2333] KVM: x86: Fix VM hard lockup after prolonged inactivity with periodic HV timer commit 18ab3fc8e880791aa9f7c000261320fc812b5465 upstream. When advancing the target expiration for the guest's APIC timer in periodic mode, set the expiration to "now" if the target expiration is in the past (similar to what is done in update_target_expiration()). Blindly adding the period to the previous target expiration can result in KVM generating a practically unbounded number of hrtimer IRQs due to programming an expired timer over and over. In extreme scenarios, e.g. if userspace pauses/suspends a VM for an extended duration, this can even cause hard lockups in the host. Currently, the bug only affects Intel CPUs when using the hypervisor timer (HV timer), a.k.a. the VMX preemption timer. Unlike the software timer, a.k.a. hrtimer, which KVM keeps running even on exits to userspace, the HV timer only runs while the guest is active. As a result, if the vCPU does not run for an extended duration, there will be a huge gap between the target expiration and the current time the vCPU resumes running. Because the target expiration is incremented by only one period on each timer expiration, this leads to a series of timer expirations occurring rapidly after the vCPU/VM resumes. More critically, when the vCPU first triggers a periodic HV timer expiration after resuming, advancing the expiration by only one period will result in a target expiration in the past. As a result, the delta may be calculated as a negative value. When the delta is converted into an absolute value (tscdeadline is an unsigned u64), the resulting value can overflow what the HV timer is capable of programming. I.e. the large value will exceed the VMX Preemption Timer's maximum bit width of cpu_preemption_timer_multi + 32, and thus cause KVM to switch from the HV timer to the software timer (hrtimers). After switching to the software timer, periodic timer expiration callbacks may be executed consecutively within a single clock interrupt handler, because hrtimers honors KVM's request for an expiration in the past and immediately re-invokes KVM's callback after reprogramming. And because the interrupt handler runs with IRQs disabled, restarting KVM's hrtimer over and over until the target expiration is advanced to "now" can result in a hard lockup. E.g. the following hard lockup was triggered in the host when running a Windows VM (only relevant because it used the APIC timer in periodic mode) after resuming the VM from a long suspend (in the host). NMI watchdog: Watchdog detected hard LOCKUP on cpu 45 ... RIP: 0010:advance_periodic_target_expiration+0x4d/0x80 [kvm] ... RSP: 0018:ff4f88f5d98d8ef0 EFLAGS: 00000046 RAX: fff0103f91be678e RBX: fff0103f91be678e RCX: 00843a7d9e127bcc RDX: 0000000000000002 RSI: 0052ca4003697505 RDI: ff440d5bfbdbd500 RBP: ff440d5956f99200 R08: ff2ff2a42deb6a84 R09: 000000000002a6c0 R10: 0122d794016332b3 R11: 0000000000000000 R12: ff440db1af39cfc0 R13: ff440db1af39cfc0 R14: ffffffffc0d4a560 R15: ff440db1af39d0f8 FS: 00007f04a6ffd700(0000) GS:ff440db1af380000(0000) knlGS:000000e38a3b8000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 000000d5651feff8 CR3: 000000684e038002 CR4: 0000000000773ee0 PKRU: 55555554 Call Trace: apic_timer_fn+0x31/0x50 [kvm] __hrtimer_run_queues+0x100/0x280 hrtimer_interrupt+0x100/0x210 ? ttwu_do_wakeup+0x19/0x160 smp_apic_timer_interrupt+0x6a/0x130 apic_timer_interrupt+0xf/0x20 Moreover, if the suspend duration of the virtual machine is not long enough to trigger a hard lockup in this scenario, since commit 98c25ead5eda ("KVM: VMX: Move preemption timer <=> hrtimer dance to common x86"), KVM will continue using the software timer until the guest reprograms the APIC timer in some way. Since the periodic timer does not require frequent APIC timer register programming, the guest may continue to use the software timer in perpetuity. Fixes: d8f2f498d9ed ("x86/kvm: fix LAPIC timer drift when guest uses periodic mode") Cc: stable@vger.kernel.org Signed-off-by: fuqiang wang [sean: massage comments and changelog] Link: https://patch.msgid.link/20251113205114.1647493-4-seanjc@google.com Signed-off-by: Sean Christopherson Signed-off-by: Greg Kroah-Hartman --- arch/x86/kvm/lapic.c | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index a5c927e7bae68..8b6ec3304100f 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -2131,15 +2131,33 @@ static void advance_periodic_target_expiration(struct kvm_lapic *apic) ktime_t delta; /* - * Synchronize both deadlines to the same time source or - * differences in the periods (caused by differences in the - * underlying clocks or numerical approximation errors) will - * cause the two to drift apart over time as the errors - * accumulate. + * Use kernel time as the time source for both the hrtimer deadline and + * TSC-based deadline so that they stay synchronized. Computing each + * deadline independently will cause the two deadlines to drift apart + * over time as differences in the periods accumulate, e.g. due to + * differences in the underlying clocks or numerical approximation errors. */ apic->lapic_timer.target_expiration = ktime_add_ns(apic->lapic_timer.target_expiration, apic->lapic_timer.period); + + /* + * If the new expiration is in the past, e.g. because userspace stopped + * running the VM for an extended duration, then force the expiration + * to "now" and don't try to play catch-up with the missed events. KVM + * will only deliver a single interrupt regardless of how many events + * are pending, i.e. restarting the timer with an expiration in the + * past will do nothing more than waste host cycles, and can even lead + * to a hard lockup in extreme cases. + */ + if (ktime_before(apic->lapic_timer.target_expiration, now)) + apic->lapic_timer.target_expiration = now; + + /* + * Note, ensuring the expiration isn't in the past also prevents delta + * from going negative, which could cause the TSC deadline to become + * excessively large due to it an unsigned value. + */ delta = ktime_sub(apic->lapic_timer.target_expiration, now); apic->lapic_timer.tscdeadline = kvm_read_l1_tsc(apic->vcpu, tscl) + nsec_to_cycles(apic->vcpu, delta); From c1f8d4d41ed3c0f8b429cfbe2c6d4ca5477ad418 Mon Sep 17 00:00:00 2001 From: Yosry Ahmed Date: Fri, 24 Oct 2025 19:29:18 +0000 Subject: [PATCH 1345/2333] KVM: nSVM: Avoid incorrect injection of SVM_EXIT_CR0_SEL_WRITE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 3d80f4c93d3d26d0f9a0dd2844961a632eeea634 upstream. When emulating L2 instructions, svm_check_intercept() checks whether a write to CR0 should trigger a synthesized #VMEXIT with SVM_EXIT_CR0_SEL_WRITE. However, it does not check whether L1 enabled the intercept for SVM_EXIT_WRITE_CR0, which has higher priority according to the APM (24593—Rev. 3.42—March 2024, Table 15-7): When both selective and non-selective CR0-write intercepts are active at the same time, the non-selective intercept takes priority. With respect to exceptions, the priority of this intercept is the same as the generic CR0-write intercept. Make sure L1 does NOT intercept SVM_EXIT_WRITE_CR0 before checking if SVM_EXIT_CR0_SEL_WRITE needs to be injected. Opportunistically tweak the "not CR0" logic to explicitly bail early so that it's more obvious that only CR0 has a selective intercept, and that modifying icpt_info.exit_code is functionally necessary so that the call to nested_svm_exit_handled() checks the correct exit code. Fixes: cfec82cb7d31 ("KVM: SVM: Add intercept check for emulated cr accesses") Cc: stable@vger.kernel.org Signed-off-by: Yosry Ahmed Link: https://patch.msgid.link/20251024192918.3191141-4-yosry.ahmed@linux.dev [sean: isolate non-CR0 write logic, tweak comments accordingly] Signed-off-by: Sean Christopherson Signed-off-by: Greg Kroah-Hartman --- arch/x86/kvm/svm/svm.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index f2fa69dd5cc72..4154b220fec95 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -4528,15 +4528,29 @@ static int svm_check_intercept(struct kvm_vcpu *vcpu, case SVM_EXIT_WRITE_CR0: { unsigned long cr0, val; - if (info->intercept == x86_intercept_cr_write) + /* + * Adjust the exit code accordingly if a CR other than CR0 is + * being written, and skip straight to the common handling as + * only CR0 has an additional selective intercept. + */ + if (info->intercept == x86_intercept_cr_write && info->modrm_reg) { icpt_info.exit_code += info->modrm_reg; + break; + } - if (icpt_info.exit_code != SVM_EXIT_WRITE_CR0 || - info->intercept == x86_intercept_clts) + /* + * Convert the exit_code to SVM_EXIT_CR0_SEL_WRITE if a + * selective CR0 intercept is triggered (the common logic will + * treat the selective intercept as being enabled). Note, the + * unconditional intercept has higher priority, i.e. this is + * only relevant if *only* the selective intercept is enabled. + */ + if (vmcb12_is_intercept(&svm->nested.ctl, INTERCEPT_CR0_WRITE) || + !(vmcb12_is_intercept(&svm->nested.ctl, INTERCEPT_SELECTIVE_CR0))) break; - if (!(vmcb12_is_intercept(&svm->nested.ctl, - INTERCEPT_SELECTIVE_CR0))) + /* CLTS never triggers INTERCEPT_SELECTIVE_CR0 */ + if (info->intercept == x86_intercept_clts) break; cr0 = vcpu->arch.cr0 & ~SVM_CR0_SELECTIVE_MASK; From 201b4a7ebbe0bcc67010ee364a4f93b0e7e18984 Mon Sep 17 00:00:00 2001 From: Jim Mattson Date: Mon, 22 Sep 2025 09:29:23 -0700 Subject: [PATCH 1346/2333] KVM: SVM: Mark VMCB_NPT as dirty on nested VMRUN commit 7c8b465a1c91f674655ea9cec5083744ec5f796a upstream. Mark the VMCB_NPT bit as dirty in nested_vmcb02_prepare_save() on every nested VMRUN. If L1 changes the PAT MSR between two VMRUN instructions on the same L1 vCPU, the g_pat field in the associated vmcb02 will change, and the VMCB_NPT clean bit should be cleared. Fixes: 4bb170a5430b ("KVM: nSVM: do not mark all VMCB02 fields dirty on nested vmexit") Cc: stable@vger.kernel.org Signed-off-by: Jim Mattson Link: https://lore.kernel.org/r/20250922162935.621409-3-jmattson@google.com Signed-off-by: Sean Christopherson Signed-off-by: Greg Kroah-Hartman --- arch/x86/kvm/svm/nested.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/x86/kvm/svm/nested.c b/arch/x86/kvm/svm/nested.c index da6e80b3ac353..6ae021b3630bd 100644 --- a/arch/x86/kvm/svm/nested.c +++ b/arch/x86/kvm/svm/nested.c @@ -613,6 +613,7 @@ static void nested_vmcb02_prepare_save(struct vcpu_svm *svm, struct vmcb *vmcb12 struct kvm_vcpu *vcpu = &svm->vcpu; nested_vmcb02_compute_g_pat(svm); + vmcb_mark_dirty(vmcb02, VMCB_NPT); /* Load the nested guest state */ if (svm->nested.vmcb12_gpa != svm->nested.last_vmcb12_gpa) { From 2853896ef465fca266f0fa27abd3eddaecdace8f Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 7 Oct 2025 15:30:57 -0700 Subject: [PATCH 1347/2333] KVM: selftests: Forcefully override ARCH from x86_64 to x86 commit 17e5a9b77716564540d81f0c1e6082d28cf305c9 upstream. Forcefully override ARCH from x86_64 to x86 to handle the scenario where the user specifies ARCH=x86_64 on the command line. Fixes: 9af04539d474 ("KVM: selftests: Override ARCH for x86_64 instead of using ARCH_DIR") Cc: stable@vger.kernel.org Reported-by: David Matlack Closes: https://lore.kernel.org/all/20250724213130.3374922-1-dmatlack@google.com Link: https://lore.kernel.org/r/20251007223057.368082-1-seanjc@google.com Signed-off-by: Sean Christopherson Signed-off-by: Greg Kroah-Hartman --- tools/testing/selftests/kvm/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile index d9fffe06d3eae..f2b223072b626 100644 --- a/tools/testing/selftests/kvm/Makefile +++ b/tools/testing/selftests/kvm/Makefile @@ -6,7 +6,7 @@ ARCH ?= $(SUBARCH) ifeq ($(ARCH),$(filter $(ARCH),arm64 s390 riscv x86 x86_64 loongarch)) # Top-level selftests allows ARCH=x86_64 :-( ifeq ($(ARCH),x86_64) - ARCH := x86 + override ARCH := x86 endif include Makefile.kvm else From 691ff7e13f0d825b91bc50cb4ceb00af2178e9ec Mon Sep 17 00:00:00 2001 From: Yosry Ahmed Date: Fri, 24 Oct 2025 19:29:17 +0000 Subject: [PATCH 1348/2333] KVM: nSVM: Propagate SVM_EXIT_CR0_SEL_WRITE correctly for LMSW emulation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 5674a76db0213f9db1e4d08e847ff649b46889c0 upstream. When emulating L2 instructions, svm_check_intercept() checks whether a write to CR0 should trigger a synthesized #VMEXIT with SVM_EXIT_CR0_SEL_WRITE. For MOV-to-CR0, SVM_EXIT_CR0_SEL_WRITE is only triggered if any bit other than CR0.MP and CR0.TS is updated. However, according to the APM (24593—Rev. 3.42—March 2024, Table 15-7): The LMSW instruction treats the selective CR0-write intercept as a non-selective intercept (i.e., it intercepts regardless of the value being written). Skip checking the changed bits for x86_intercept_lmsw and always inject SVM_EXIT_CR0_SEL_WRITE. Fixes: cfec82cb7d31 ("KVM: SVM: Add intercept check for emulated cr accesses") Cc: stable@vger.kernel.org Reported-by: Matteo Rizzo Signed-off-by: Yosry Ahmed Link: https://patch.msgid.link/20251024192918.3191141-3-yosry.ahmed@linux.dev Signed-off-by: Sean Christopherson Signed-off-by: Greg Kroah-Hartman --- arch/x86/kvm/svm/svm.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index 4154b220fec95..a856f063b8250 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -4553,20 +4553,20 @@ static int svm_check_intercept(struct kvm_vcpu *vcpu, if (info->intercept == x86_intercept_clts) break; - cr0 = vcpu->arch.cr0 & ~SVM_CR0_SELECTIVE_MASK; - val = info->src_val & ~SVM_CR0_SELECTIVE_MASK; - + /* LMSW always triggers INTERCEPT_SELECTIVE_CR0 */ if (info->intercept == x86_intercept_lmsw) { - cr0 &= 0xfUL; - val &= 0xfUL; - /* lmsw can't clear PE - catch this here */ - if (cr0 & X86_CR0_PE) - val |= X86_CR0_PE; + icpt_info.exit_code = SVM_EXIT_CR0_SEL_WRITE; + break; } + /* + * MOV-to-CR0 only triggers INTERCEPT_SELECTIVE_CR0 if any bit + * other than SVM_CR0_SELECTIVE_MASK is changed. + */ + cr0 = vcpu->arch.cr0 & ~SVM_CR0_SELECTIVE_MASK; + val = info->src_val & ~SVM_CR0_SELECTIVE_MASK; if (cr0 ^ val) icpt_info.exit_code = SVM_EXIT_CR0_SEL_WRITE; - break; } case SVM_EXIT_READ_DR0: From 2c3719a04b04a251782e77618d4255907ea4bbc8 Mon Sep 17 00:00:00 2001 From: Wanpeng Li Date: Mon, 10 Nov 2025 11:32:27 +0800 Subject: [PATCH 1349/2333] KVM: Fix last_boosted_vcpu index assignment bug commit 32bd348be3fa07b26c5ea6b818a161c142dcc2f2 upstream. In kvm_vcpu_on_spin(), the loop counter 'i' is incorrectly written to last_boosted_vcpu instead of the actual vCPU index 'idx'. This causes last_boosted_vcpu to store the loop iteration count rather than the vCPU index, leading to incorrect round-robin behavior in subsequent directed yield operations. Fix this by using 'idx' instead of 'i' in the assignment. Signed-off-by: Wanpeng Li Reviewed-by: Sean Christopherson Message-ID: <20251110033232.12538-7-kernellwp@gmail.com> Cc: stable@vger.kernel.org Signed-off-by: Paolo Bonzini Signed-off-by: Greg Kroah-Hartman --- virt/kvm/kvm_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 01ea4f8351a61..7fea6ba91c1ef 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -4026,7 +4026,7 @@ void kvm_vcpu_on_spin(struct kvm_vcpu *me, bool yield_to_kernel_mode) yielded = kvm_vcpu_yield_to(vcpu); if (yielded > 0) { - WRITE_ONCE(kvm->last_boosted_vcpu, i); + WRITE_ONCE(kvm->last_boosted_vcpu, idx); break; } else if (yielded < 0 && !--try) { break; From da28922a8c600574fac7366c0f2e5005f41b1326 Mon Sep 17 00:00:00 2001 From: Jim Mattson Date: Mon, 22 Sep 2025 09:29:22 -0700 Subject: [PATCH 1350/2333] KVM: SVM: Mark VMCB_PERM_MAP as dirty on nested VMRUN commit 93c9e107386dbe1243287a5b14ceca894de372b9 upstream. Mark the VMCB_PERM_MAP bit as dirty in nested_vmcb02_prepare_control() on every nested VMRUN. If L1 changes MSR interception (INTERCEPT_MSR_PROT) between two VMRUN instructions on the same L1 vCPU, the msrpm_base_pa in the associated vmcb02 will change, and the VMCB_PERM_MAP clean bit should be cleared. Fixes: 4bb170a5430b ("KVM: nSVM: do not mark all VMCB02 fields dirty on nested vmexit") Reported-by: Matteo Rizzo Cc: stable@vger.kernel.org Signed-off-by: Jim Mattson Link: https://lore.kernel.org/r/20250922162935.621409-2-jmattson@google.com Signed-off-by: Sean Christopherson Signed-off-by: Greg Kroah-Hartman --- arch/x86/kvm/svm/nested.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/x86/kvm/svm/nested.c b/arch/x86/kvm/svm/nested.c index 6ae021b3630bd..2df6ec74d6ee6 100644 --- a/arch/x86/kvm/svm/nested.c +++ b/arch/x86/kvm/svm/nested.c @@ -752,6 +752,7 @@ static void nested_vmcb02_prepare_control(struct vcpu_svm *svm, vmcb02->control.nested_ctl = vmcb01->control.nested_ctl; vmcb02->control.iopm_base_pa = vmcb01->control.iopm_base_pa; vmcb02->control.msrpm_base_pa = vmcb01->control.msrpm_base_pa; + vmcb_mark_dirty(vmcb02, VMCB_PERM_MAP); /* * Stash vmcb02's counter if the guest hasn't moved past the guilty From 3fe48378e53fe38948ab06cfde0a4cea5f53258a Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Thu, 30 Oct 2025 12:15:25 -0700 Subject: [PATCH 1351/2333] KVM: TDX: Explicitly set user-return MSRs that *may* be clobbered by the TDX-Module commit c0711f8c610e1634ed54fb04da1e82252730306a upstream. Set all user-return MSRs to their post-TD-exit value when preparing to run a TDX vCPU to ensure the value that KVM expects to be loaded after running the vCPU is indeed the value that's loaded in hardware. If the TDX-Module doesn't actually enter the guest, i.e. doesn't do VM-Enter, then it won't "restore" VMM state, i.e. won't clobber user-return MSRs to their expected post-run values, in which case simply updating KVM's "cached" value will effectively corrupt the cache due to hardware still holding the original value. In theory, KVM could conditionally update the current user-return value if and only if tdh_vp_enter() succeeds, but in practice "success" doesn't guarantee the TDX-Module actually entered the guest, e.g. if the TDX-Module synthesizes an EPT Violation because it suspects a zero-step attack. Force-load the expected values instead of trying to decipher whether or not the TDX-Module restored/clobbered MSRs, as the risk doesn't justify the benefits. Effectively avoiding four WRMSRs once per run loop (even if the vCPU is scheduled out, user-return MSRs only need to be reloaded if the CPU exits to userspace or runs a non-TDX vCPU) is likely in the noise when amortized over all entries, given the cost of running a TDX vCPU. E.g. the cost of the WRMSRs is somewhere between ~300 and ~500 cycles, whereas the cost of a _single_ roundtrip to/from a TDX guest is thousands of cycles. Fixes: e0b4f31a3c65 ("KVM: TDX: restore user ret MSRs") Cc: stable@vger.kernel.org Cc: Yan Zhao Cc: Xiaoyao Li Cc: Rick Edgecombe Reviewed-by: Xiaoyao Li Link: https://patch.msgid.link/20251030191528.3380553-2-seanjc@google.com Signed-off-by: Sean Christopherson Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/kvm_host.h | 1 - arch/x86/kvm/vmx/tdx.c | 56 ++++++++++++++------------------- arch/x86/kvm/vmx/tdx.h | 1 - arch/x86/kvm/x86.c | 9 ------ 4 files changed, 23 insertions(+), 44 deletions(-) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 974d64bf0a4d2..b74ae7183f3ae 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -2387,7 +2387,6 @@ int kvm_pv_send_ipi(struct kvm *kvm, unsigned long ipi_bitmap_low, int kvm_add_user_return_msr(u32 msr); int kvm_find_user_return_msr(u32 msr); int kvm_set_user_return_msr(unsigned index, u64 val, u64 mask); -void kvm_user_return_msr_update_cache(unsigned int index, u64 val); u64 kvm_get_user_return_msr(unsigned int slot); static inline bool kvm_is_supported_user_return_msr(u32 msr) diff --git a/arch/x86/kvm/vmx/tdx.c b/arch/x86/kvm/vmx/tdx.c index 0a49c863c811b..d9ffc16dfefe6 100644 --- a/arch/x86/kvm/vmx/tdx.c +++ b/arch/x86/kvm/vmx/tdx.c @@ -763,25 +763,6 @@ static bool tdx_protected_apic_has_interrupt(struct kvm_vcpu *vcpu) return tdx_vcpu_state_details_intr_pending(vcpu_state_details); } -/* - * Compared to vmx_prepare_switch_to_guest(), there is not much to do - * as SEAMCALL/SEAMRET calls take care of most of save and restore. - */ -void tdx_prepare_switch_to_guest(struct kvm_vcpu *vcpu) -{ - struct vcpu_vt *vt = to_vt(vcpu); - - if (vt->guest_state_loaded) - return; - - if (likely(is_64bit_mm(current->mm))) - vt->msr_host_kernel_gs_base = current->thread.gsbase; - else - vt->msr_host_kernel_gs_base = read_msr(MSR_KERNEL_GS_BASE); - - vt->guest_state_loaded = true; -} - struct tdx_uret_msr { u32 msr; unsigned int slot; @@ -795,19 +776,38 @@ static struct tdx_uret_msr tdx_uret_msrs[] = { {.msr = MSR_TSC_AUX,}, }; -static void tdx_user_return_msr_update_cache(void) +void tdx_prepare_switch_to_guest(struct kvm_vcpu *vcpu) { + struct vcpu_vt *vt = to_vt(vcpu); int i; + if (vt->guest_state_loaded) + return; + + if (likely(is_64bit_mm(current->mm))) + vt->msr_host_kernel_gs_base = current->thread.gsbase; + else + vt->msr_host_kernel_gs_base = read_msr(MSR_KERNEL_GS_BASE); + + vt->guest_state_loaded = true; + + /* + * Explicitly set user-return MSRs that are clobbered by the TDX-Module + * if VP.ENTER succeeds, i.e. on TD-Exit, with the values that would be + * written by the TDX-Module. Don't rely on the TDX-Module to actually + * clobber the MSRs, as the contract is poorly defined and not upheld. + * E.g. the TDX-Module will synthesize an EPT Violation without doing + * VM-Enter if it suspects a zero-step attack, and never "restore" VMM + * state. + */ for (i = 0; i < ARRAY_SIZE(tdx_uret_msrs); i++) - kvm_user_return_msr_update_cache(tdx_uret_msrs[i].slot, - tdx_uret_msrs[i].defval); + kvm_set_user_return_msr(tdx_uret_msrs[i].slot, + tdx_uret_msrs[i].defval, -1ull); } static void tdx_prepare_switch_to_host(struct kvm_vcpu *vcpu) { struct vcpu_vt *vt = to_vt(vcpu); - struct vcpu_tdx *tdx = to_tdx(vcpu); if (!vt->guest_state_loaded) return; @@ -815,11 +815,6 @@ static void tdx_prepare_switch_to_host(struct kvm_vcpu *vcpu) ++vcpu->stat.host_state_reload; wrmsrl(MSR_KERNEL_GS_BASE, vt->msr_host_kernel_gs_base); - if (tdx->guest_entered) { - tdx_user_return_msr_update_cache(); - tdx->guest_entered = false; - } - vt->guest_state_loaded = false; } @@ -1059,7 +1054,6 @@ fastpath_t tdx_vcpu_run(struct kvm_vcpu *vcpu, u64 run_flags) update_debugctlmsr(vcpu->arch.host_debugctl); tdx_load_host_xsave_state(vcpu); - tdx->guest_entered = true; vcpu->arch.regs_avail &= TDX_REGS_AVAIL_SET; @@ -3447,10 +3441,6 @@ static int __init __tdx_bringup(void) /* * Check if MSRs (tdx_uret_msrs) can be saved/restored * before returning to user space. - * - * this_cpu_ptr(user_return_msrs)->registered isn't checked - * because the registration is done at vcpu runtime by - * tdx_user_return_msr_update_cache(). */ tdx_uret_msrs[i].slot = kvm_find_user_return_msr(tdx_uret_msrs[i].msr); if (tdx_uret_msrs[i].slot == -1) { diff --git a/arch/x86/kvm/vmx/tdx.h b/arch/x86/kvm/vmx/tdx.h index ca39a9391db1e..7f258870dc410 100644 --- a/arch/x86/kvm/vmx/tdx.h +++ b/arch/x86/kvm/vmx/tdx.h @@ -67,7 +67,6 @@ struct vcpu_tdx { u64 vp_enter_ret; enum vcpu_tdx_state state; - bool guest_entered; u64 map_gpa_next; u64 map_gpa_end; diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 5d3297cef8a99..19d2d6d9e64ab 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -681,15 +681,6 @@ int kvm_set_user_return_msr(unsigned slot, u64 value, u64 mask) } EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_set_user_return_msr); -void kvm_user_return_msr_update_cache(unsigned int slot, u64 value) -{ - struct kvm_user_return_msrs *msrs = this_cpu_ptr(user_return_msrs); - - msrs->values[slot].curr = value; - kvm_user_return_register_notifier(msrs); -} -EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_user_return_msr_update_cache); - u64 kvm_get_user_return_msr(unsigned int slot) { return this_cpu_ptr(user_return_msrs)->values[slot].curr; From 6617e02cf8dfb71b406f94337df8083bb9d5ac02 Mon Sep 17 00:00:00 2001 From: Dongli Zhang Date: Fri, 5 Dec 2025 15:19:05 -0800 Subject: [PATCH 1352/2333] KVM: nVMX: Immediately refresh APICv controls as needed on nested VM-Exit commit 29763138830916f46daaa50e83e7f4f907a3236b upstream. If an APICv status updated was pended while L2 was active, immediately refresh vmcs01's controls instead of pending KVM_REQ_APICV_UPDATE as kvm_vcpu_update_apicv() only calls into vendor code if a change is necessary. E.g. if APICv is inhibited, and then activated while L2 is running: kvm_vcpu_update_apicv() | -> __kvm_vcpu_update_apicv() | -> apic->apicv_active = true | -> vmx_refresh_apicv_exec_ctrl() | -> vmx->nested.update_vmcs01_apicv_status = true | -> return Then L2 exits to L1: __nested_vmx_vmexit() | -> kvm_make_request(KVM_REQ_APICV_UPDATE) vcpu_enter_guest(): KVM_REQ_APICV_UPDATE -> kvm_vcpu_update_apicv() | -> __kvm_vcpu_update_apicv() | -> return // because if (apic->apicv_active == activate) Reported-by: Chao Gao Closes: https://lore.kernel.org/all/aQ2jmnN8wUYVEawF@intel.com Fixes: 7c69661e225c ("KVM: nVMX: Defer APICv updates while L2 is active until L1 is active") Cc: stable@vger.kernel.org Signed-off-by: Dongli Zhang [sean: write changelog] Link: https://patch.msgid.link/20251205231913.441872-3-seanjc@google.com Signed-off-by: Sean Christopherson Signed-off-by: Greg Kroah-Hartman --- arch/x86/kvm/vmx/nested.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c index bcea087b642fd..1725c6a94f99b 100644 --- a/arch/x86/kvm/vmx/nested.c +++ b/arch/x86/kvm/vmx/nested.c @@ -19,6 +19,7 @@ #include "trace.h" #include "vmx.h" #include "smm.h" +#include "x86_ops.h" static bool __read_mostly enable_shadow_vmcs = 1; module_param_named(enable_shadow_vmcs, enable_shadow_vmcs, bool, S_IRUGO); @@ -5216,7 +5217,7 @@ void __nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 vm_exit_reason, if (vmx->nested.update_vmcs01_apicv_status) { vmx->nested.update_vmcs01_apicv_status = false; - kvm_make_request(KVM_REQ_APICV_UPDATE, vcpu); + vmx_refresh_apicv_exec_ctrl(vcpu); } if (vmx->nested.update_vmcs01_hwapic_isr) { From acffd1cee6887e83f2efe90a481c71a3804257c9 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Thu, 13 Nov 2025 14:56:14 -0800 Subject: [PATCH 1353/2333] KVM: nSVM: Set exit_code_hi to -1 when synthesizing SVM_EXIT_ERR (failed VMRUN) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit f402ecd7a8b6446547076f4bd24bd5d4dcc94481 upstream. Set exit_code_hi to -1u as a temporary band-aid to fix a long-standing (effectively since KVM's inception) bug where KVM treats the exit code as a 32-bit value, when in reality it's a 64-bit value. Per the APM, offset 0x70 is a single 64-bit value: 070h 63:0 EXITCODE And a sane reading of the error values defined in "Table C-1. SVM Intercept Codes" is that negative values use the full 64 bits: –1 VMEXIT_INVALID Invalid guest state in VMCB. –2 VMEXIT_BUSYBUSY bit was set in the VMSA –3 VMEXIT_IDLE_REQUIREDThe sibling thread is not in an idle state -4 VMEXIT_INVALID_PMC Invalid PMC state And that interpretation is confirmed by testing on Milan and Turin (by setting bits in CR0[63:32] to generate VMEXIT_INVALID on VMRUN). Furthermore, Xen has treated exitcode as a 64-bit value since HVM support was adding in 2006 (see Xen commit d1bd157fbc ("Big merge the HVM full-virtualisation abstractions.")). Cc: Jim Mattson Cc: Yosry Ahmed Cc: stable@vger.kernel.org Reviewed-by: Yosry Ahmed Link: https://patch.msgid.link/20251113225621.1688428-3-seanjc@google.com Signed-off-by: Sean Christopherson Signed-off-by: Greg Kroah-Hartman --- arch/x86/kvm/svm/nested.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86/kvm/svm/nested.c b/arch/x86/kvm/svm/nested.c index 2df6ec74d6ee6..e56c9b37e2b5b 100644 --- a/arch/x86/kvm/svm/nested.c +++ b/arch/x86/kvm/svm/nested.c @@ -985,7 +985,7 @@ int nested_svm_vmrun(struct kvm_vcpu *vcpu) if (!nested_vmcb_check_save(vcpu) || !nested_vmcb_check_controls(vcpu)) { vmcb12->control.exit_code = SVM_EXIT_ERR; - vmcb12->control.exit_code_hi = 0; + vmcb12->control.exit_code_hi = -1u; vmcb12->control.exit_info_1 = 0; vmcb12->control.exit_info_2 = 0; goto out; @@ -1018,7 +1018,7 @@ int nested_svm_vmrun(struct kvm_vcpu *vcpu) svm->soft_int_injected = false; svm->vmcb->control.exit_code = SVM_EXIT_ERR; - svm->vmcb->control.exit_code_hi = 0; + svm->vmcb->control.exit_code_hi = -1u; svm->vmcb->control.exit_info_1 = 0; svm->vmcb->control.exit_info_2 = 0; From aedf238216636cd10de024f79b6b151a3148bfe9 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Thu, 13 Nov 2025 14:56:13 -0800 Subject: [PATCH 1354/2333] KVM: nSVM: Clear exit_code_hi in VMCB when synthesizing nested VM-Exits commit da01f64e7470988f8607776aa7afa924208863fb upstream. Explicitly clear exit_code_hi in the VMCB when synthesizing "normal" nested VM-Exits, as the full exit code is a 64-bit value (spoiler alert), and all exit codes for non-failing VMRUN use only bits 31:0. Cc: Jim Mattson Cc: Yosry Ahmed Cc: stable@vger.kernel.org Reviewed-by: Yosry Ahmed Link: https://patch.msgid.link/20251113225621.1688428-2-seanjc@google.com Signed-off-by: Sean Christopherson Signed-off-by: Greg Kroah-Hartman --- arch/x86/kvm/svm/svm.c | 2 ++ arch/x86/kvm/svm/svm.h | 7 ++++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index a856f063b8250..3b215c5b5b01d 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -2438,6 +2438,7 @@ static bool check_selective_cr0_intercepted(struct kvm_vcpu *vcpu, if (cr0 ^ val) { svm->vmcb->control.exit_code = SVM_EXIT_CR0_SEL_WRITE; + svm->vmcb->control.exit_code_hi = 0; ret = (nested_svm_exit_handled(svm) == NESTED_EXIT_DONE); } @@ -4627,6 +4628,7 @@ static int svm_check_intercept(struct kvm_vcpu *vcpu, if (static_cpu_has(X86_FEATURE_NRIPS)) vmcb->control.next_rip = info->next_rip; vmcb->control.exit_code = icpt_info.exit_code; + vmcb->control.exit_code_hi = 0; vmexit = nested_svm_exit_handled(svm); ret = (vmexit == NESTED_EXIT_DONE) ? X86EMUL_INTERCEPTED diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h index dd78e64023450..e66a16e59b1a5 100644 --- a/arch/x86/kvm/svm/svm.h +++ b/arch/x86/kvm/svm/svm.h @@ -764,9 +764,10 @@ int nested_svm_vmexit(struct vcpu_svm *svm); static inline int nested_svm_simple_vmexit(struct vcpu_svm *svm, u32 exit_code) { - svm->vmcb->control.exit_code = exit_code; - svm->vmcb->control.exit_info_1 = 0; - svm->vmcb->control.exit_info_2 = 0; + svm->vmcb->control.exit_code = exit_code; + svm->vmcb->control.exit_code_hi = 0; + svm->vmcb->control.exit_info_1 = 0; + svm->vmcb->control.exit_info_2 = 0; return nested_svm_vmexit(svm); } From caf68b6da38957e78c8d83df4553542102366449 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Mon, 1 Dec 2025 17:50:48 -0800 Subject: [PATCH 1355/2333] KVM: x86: Apply runtime updates to current CPUID during KVM_SET_CPUID{,2} commit e2b43fb25243d502ad36b07bab9de09f4b76fff9 upstream. When handling KVM_SET_CPUID{,2}, do runtime CPUID updates on the vCPU's current CPUID (and caps) prior to swapping in the incoming CPUID state so that KVM doesn't lose pending updates if the incoming CPUID is rejected, and to prevent a false failure on the equality check. Note, runtime updates are unconditionally performed on the incoming/new CPUID (and associated caps), i.e. clearing the dirty flag won't negatively affect the new CPUID. Fixes: 93da6af3ae56 ("KVM: x86: Defer runtime updates of dynamic CPUID bits until CPUID emulation") Reported-by: Igor Mammedov Closes: https://lore.kernel.org/all/20251128123202.68424a95@imammedo Cc: stable@vger.kernel.org Acked-by: Igor Mammedov Tested-by: Igor Mammedov Link: https://patch.msgid.link/20251202015049.1167490-2-seanjc@google.com Signed-off-by: Sean Christopherson Signed-off-by: Greg Kroah-Hartman --- arch/x86/kvm/cpuid.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c index 52524e0ca97f7..913ffb995279a 100644 --- a/arch/x86/kvm/cpuid.c +++ b/arch/x86/kvm/cpuid.c @@ -509,11 +509,18 @@ static int kvm_set_cpuid(struct kvm_vcpu *vcpu, struct kvm_cpuid_entry2 *e2, u32 vcpu_caps[NR_KVM_CPU_CAPS]; int r; + /* + * Apply pending runtime CPUID updates to the current CPUID entries to + * avoid false positives due to mismatches on KVM-owned feature flags. + */ + if (vcpu->arch.cpuid_dynamic_bits_dirty) + kvm_update_cpuid_runtime(vcpu); + /* * Swap the existing (old) entries with the incoming (new) entries in * order to massage the new entries, e.g. to account for dynamic bits - * that KVM controls, without clobbering the current guest CPUID, which - * KVM needs to preserve in order to unwind on failure. + * that KVM controls, without losing the current guest CPUID, which KVM + * needs to preserve in order to unwind on failure. * * Similarly, save the vCPU's current cpu_caps so that the capabilities * can be updated alongside the CPUID entries when performing runtime From 0c01fa83c09beb5095aa16c16b5cc3f8b7220499 Mon Sep 17 00:00:00 2001 From: Gavin Shan Date: Mon, 24 Nov 2025 15:04:27 +1000 Subject: [PATCH 1356/2333] KVM: selftests: Add missing "break" in rseq_test's param parsing commit 1b9439c933b500cb24710bbd81fe56e9b0025b6f upstream. In commit 0297cdc12a87 ("KVM: selftests: Add option to rseq test to override /dev/cpu_dma_latency"), a 'break' is missed before the option 'l' in the argument parsing loop, which leads to an unexpected core dump in atoi_paranoid(). It tries to get the latency from non-existent argument. host$ ./rseq_test -u Random seed: 0x6b8b4567 Segmentation fault (core dumped) Add a 'break' before the option 'l' in the argument parsing loop to avoid the unexpected core dump. Fixes: 0297cdc12a87 ("KVM: selftests: Add option to rseq test to override /dev/cpu_dma_latency") Cc: stable@vger.kernel.org # v6.15+ Signed-off-by: Gavin Shan Link: https://patch.msgid.link/20251124050427.1924591-1-gshan@redhat.com [sean: describe code change in shortlog] Signed-off-by: Sean Christopherson Signed-off-by: Greg Kroah-Hartman --- tools/testing/selftests/kvm/rseq_test.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/testing/selftests/kvm/rseq_test.c b/tools/testing/selftests/kvm/rseq_test.c index 1375fca80bcdb..f80ad6b47d16b 100644 --- a/tools/testing/selftests/kvm/rseq_test.c +++ b/tools/testing/selftests/kvm/rseq_test.c @@ -215,6 +215,7 @@ int main(int argc, char *argv[]) switch (opt) { case 'u': skip_sanity_check = true; + break; case 'l': latency = atoi_paranoid(optarg); break; From 55c28a875425c9975a9414a247e8e6709d3bf528 Mon Sep 17 00:00:00 2001 From: Haoxiang Li Date: Wed, 10 Dec 2025 17:06:01 +0800 Subject: [PATCH 1357/2333] xfs: fix a memory leak in xfs_buf_item_init() commit fc40459de82543b565ebc839dca8f7987f16f62e upstream. xfs_buf_item_get_format() may allocate memory for bip->bli_formats, free the memory in the error path. Fixes: c3d5f0c2fb85 ("xfs: complain if anyone tries to create a too-large buffer log item") Cc: stable@vger.kernel.org Signed-off-by: Haoxiang Li Reviewed-by: Christoph Hellwig Reviewed-by: Carlos Maiolino Signed-off-by: Carlos Maiolino Signed-off-by: Greg Kroah-Hartman --- fs/xfs/xfs_buf_item.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/xfs/xfs_buf_item.c b/fs/xfs/xfs_buf_item.c index 8d85b5eee4444..f4c5be67826e2 100644 --- a/fs/xfs/xfs_buf_item.c +++ b/fs/xfs/xfs_buf_item.c @@ -896,6 +896,7 @@ xfs_buf_item_init( map_size = DIV_ROUND_UP(chunks, NBWORD); if (map_size > XFS_BLF_DATAMAP_SIZE) { + xfs_buf_item_free_format(bip); kmem_cache_free(xfs_buf_item_cache, bip); xfs_err(mp, "buffer item dirty bitmap (%u uints) too small to reflect %u bytes!", From 0f3b87c66d892c4b23233585612affb74bd18441 Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Thu, 4 Dec 2025 13:44:15 -0800 Subject: [PATCH 1358/2333] xfs: fix stupid compiler warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit f06725052098d7b1133ac3846d693c383dc427a2 upstream. gcc 14.2 warns about: xfs_attr_item.c: In function ‘xfs_attr_recover_work’: xfs_attr_item.c:785:9: warning: ‘ip’ may be used uninitialized [-Wmaybe-uninitialized] 785 | xfs_trans_ijoin(tp, ip, 0); | ^~~~~~~~~~~~~~~~~~~~~~~~~~ xfs_attr_item.c:740:42: note: ‘ip’ was declared here 740 | struct xfs_inode *ip; | ^~ I think this is bogus since xfs_attri_recover_work either returns a real pointer having initialized ip or an ERR_PTR having not touched it, but the tools are smarter than me so let's just null-init the variable anyway. Cc: stable@vger.kernel.org # v6.8 Fixes: e70fb328d52772 ("xfs: recreate work items when recovering intent items") Signed-off-by: Darrick J. Wong Reviewed-by: Carlos Maiolino Reviewed-by: Christoph Hellwig Signed-off-by: Carlos Maiolino Signed-off-by: Greg Kroah-Hartman --- fs/xfs/xfs_attr_item.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/xfs/xfs_attr_item.c b/fs/xfs/xfs_attr_item.c index c3a593319bee7..e8fa326ac995b 100644 --- a/fs/xfs/xfs_attr_item.c +++ b/fs/xfs/xfs_attr_item.c @@ -737,7 +737,7 @@ xfs_attr_recover_work( struct xfs_attri_log_item *attrip = ATTRI_ITEM(lip); struct xfs_attr_intent *attr; struct xfs_mount *mp = lip->li_log->l_mp; - struct xfs_inode *ip; + struct xfs_inode *ip = NULL; struct xfs_da_args *args; struct xfs_trans *tp; struct xfs_trans_res resv; From 92f6a7b6cfda18b3da0862e402d849efd79c80a3 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 16 Dec 2025 18:30:09 +0100 Subject: [PATCH 1359/2333] xfs: fix the zoned RT growfs check for zone alignment commit dc68c0f601691010dd5ae53442f8523f41a53131 upstream. The grofs code for zoned RT subvolums already tries to check for zone alignment, but gets it wrong by using the old instead of the new mount structure. Fixes: 01b71e64bb87 ("xfs: support growfs on zoned file systems") Signed-off-by: Christoph Hellwig Reviewed-by: Darrick J. Wong Cc: stable@vger.kernel.org # v6.15 Signed-off-by: Carlos Maiolino Signed-off-by: Greg Kroah-Hartman --- fs/xfs/xfs_rtalloc.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/fs/xfs/xfs_rtalloc.c b/fs/xfs/xfs_rtalloc.c index 6907e871fa151..e063f4f2f2e61 100644 --- a/fs/xfs/xfs_rtalloc.c +++ b/fs/xfs/xfs_rtalloc.c @@ -1255,12 +1255,10 @@ xfs_growfs_check_rtgeom( min_logfsbs = min_t(xfs_extlen_t, xfs_log_calc_minimum_size(nmp), nmp->m_rsumblocks * 2); - kfree(nmp); - trace_xfs_growfs_check_rtgeom(mp, min_logfsbs); if (min_logfsbs > mp->m_sb.sb_logblocks) - return -EINVAL; + goto out_inval; if (xfs_has_zoned(mp)) { uint32_t gblocks = mp->m_groups[XG_TYPE_RTG].blocks; @@ -1268,16 +1266,20 @@ xfs_growfs_check_rtgeom( if (rextsize != 1) return -EINVAL; - div_u64_rem(mp->m_sb.sb_rblocks, gblocks, &rem); + div_u64_rem(nmp->m_sb.sb_rblocks, gblocks, &rem); if (rem) { xfs_warn(mp, "new RT volume size (%lld) not aligned to RT group size (%d)", - mp->m_sb.sb_rblocks, gblocks); - return -EINVAL; + nmp->m_sb.sb_rblocks, gblocks); + goto out_inval; } } + kfree(nmp); return 0; +out_inval: + kfree(nmp); + return -EINVAL; } /* From d29ed9ff972afe17c215cab171761d7a15d7063f Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Thu, 4 Dec 2025 13:43:50 -0800 Subject: [PATCH 1360/2333] xfs: fix a UAF problem in xattr repair commit 5990fd756943836978ad184aac980e2b36ab7e01 upstream. The xchk_setup_xattr_buf function can allocate a new value buffer, which means that any reference to ab->value before the call could become a dangling pointer. Fix this by moving an assignment to after the buffer setup. Cc: stable@vger.kernel.org # v6.10 Fixes: e47dcf113ae348 ("xfs: repair extended attributes") Signed-off-by: Darrick J. Wong Reviewed-by: Christoph Hellwig Signed-off-by: Carlos Maiolino Signed-off-by: Greg Kroah-Hartman --- fs/xfs/scrub/attr_repair.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/xfs/scrub/attr_repair.c b/fs/xfs/scrub/attr_repair.c index c7eb94069cafc..09d63aa10314b 100644 --- a/fs/xfs/scrub/attr_repair.c +++ b/fs/xfs/scrub/attr_repair.c @@ -333,7 +333,6 @@ xrep_xattr_salvage_remote_attr( .attr_filter = ent->flags & XFS_ATTR_NSP_ONDISK_MASK, .namelen = rentry->namelen, .name = rentry->name, - .value = ab->value, .valuelen = be32_to_cpu(rentry->valuelen), }; unsigned int namesize; @@ -363,6 +362,7 @@ xrep_xattr_salvage_remote_attr( error = -EDEADLOCK; if (error) return error; + args.value = ab->value; /* Look up the remote value and stash it for reconstruction. */ error = xfs_attr3_leaf_getvalue(leaf_bp, &args); From cec87632c34afc4589a315448690e1812c635c78 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 16 Dec 2025 18:30:08 +0100 Subject: [PATCH 1361/2333] xfs: validate that zoned RT devices are zone aligned commit 982d2616a2906113e433fdc0cfcc122f8d1bb60a upstream. Garbage collection assumes all zones contain the full amount of blocks. Mkfs already ensures this happens, but make the kernel check it as well to avoid getting into trouble due to fuzzers or mkfs bugs. Fixes: 2167eaabe2fa ("xfs: define the zoned on-disk format") Signed-off-by: Christoph Hellwig Reviewed-by: Darrick J. Wong Cc: stable@vger.kernel.org # v6.15 Signed-off-by: Carlos Maiolino Signed-off-by: Greg Kroah-Hartman --- fs/xfs/libxfs/xfs_sb.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/fs/xfs/libxfs/xfs_sb.c b/fs/xfs/libxfs/xfs_sb.c index cdd16dd805d77..94c272a2ae262 100644 --- a/fs/xfs/libxfs/xfs_sb.c +++ b/fs/xfs/libxfs/xfs_sb.c @@ -301,6 +301,21 @@ xfs_validate_rt_geometry( sbp->sb_rbmblocks != xfs_expected_rbmblocks(sbp)) return false; + if (xfs_sb_is_v5(sbp) && + (sbp->sb_features_incompat & XFS_SB_FEAT_INCOMPAT_ZONED)) { + uint32_t mod; + + /* + * Zoned RT devices must be aligned to the RT group size, + * because garbage collection assumes that all zones have the + * same size to avoid insane complexity if that weren't the + * case. + */ + div_u64_rem(sbp->sb_rextents, sbp->sb_rgextents, &mod); + if (mod) + return false; + } + return true; } From 6df47e5bb9b62d72f186f826ab643ea1856877c7 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Tue, 16 Dec 2025 18:24:40 -0500 Subject: [PATCH 1362/2333] tracing: Do not register unsupported perf events commit ef7f38df890f5dcd2ae62f8dbde191d72f3bebae upstream. Synthetic events currently do not have a function to register perf events. This leads to calling the tracepoint register functions with a NULL function pointer which triggers: ------------[ cut here ]------------ WARNING: kernel/tracepoint.c:175 at tracepoint_add_func+0x357/0x370, CPU#2: perf/2272 Modules linked in: kvm_intel kvm irqbypass CPU: 2 UID: 0 PID: 2272 Comm: perf Not tainted 6.18.0-ftest-11964-ge022764176fc-dirty #323 PREEMPTLAZY Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.17.0-debian-1.17.0-1 04/01/2014 RIP: 0010:tracepoint_add_func+0x357/0x370 Code: 28 9c e8 4c 0b f5 ff eb 0f 4c 89 f7 48 c7 c6 80 4d 28 9c e8 ab 89 f4 ff 31 c0 5b 41 5c 41 5d 41 5e 41 5f 5d c3 cc cc cc cc cc <0f> 0b 49 c7 c6 ea ff ff ff e9 ee fe ff ff 0f 0b e9 f9 fe ff ff 0f RSP: 0018:ffffabc0c44d3c40 EFLAGS: 00010246 RAX: 0000000000000001 RBX: ffff9380aa9e4060 RCX: 0000000000000000 RDX: 000000000000000a RSI: ffffffff9e1d4a98 RDI: ffff937fcf5fd6c8 RBP: 0000000000000001 R08: 0000000000000007 R09: ffff937fcf5fc780 R10: 0000000000000003 R11: ffffffff9c193910 R12: 000000000000000a R13: ffffffff9e1e5888 R14: 0000000000000000 R15: ffffabc0c44d3c78 FS: 00007f6202f5f340(0000) GS:ffff93819f00f000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 000055d3162281a8 CR3: 0000000106a56003 CR4: 0000000000172ef0 Call Trace: tracepoint_probe_register+0x5d/0x90 synth_event_reg+0x3c/0x60 perf_trace_event_init+0x204/0x340 perf_trace_init+0x85/0xd0 perf_tp_event_init+0x2e/0x50 perf_try_init_event+0x6f/0x230 ? perf_event_alloc+0x4bb/0xdc0 perf_event_alloc+0x65a/0xdc0 __se_sys_perf_event_open+0x290/0x9f0 do_syscall_64+0x93/0x7b0 ? entry_SYSCALL_64_after_hwframe+0x76/0x7e ? trace_hardirqs_off+0x53/0xc0 entry_SYSCALL_64_after_hwframe+0x76/0x7e Instead, have the code return -ENODEV, which doesn't warn and has perf error out with: # perf record -e synthetic:futex_wait Error: The sys_perf_event_open() syscall returned with 19 (No such device) for event (synthetic:futex_wait). "dmesg | grep -i perf" may provide additional information. Ideally perf should support synthetic events, but for now just fix the warning. The support can come later. Cc: stable@vger.kernel.org Cc: Masami Hiramatsu Cc: Mathieu Desnoyers Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Namhyung Kim Link: https://patch.msgid.link/20251216182440.147e4453@gandalf.local.home Fixes: 4b147936fa509 ("tracing: Add support for 'synthetic' events") Reported-by: Ian Rogers Signed-off-by: Steven Rostedt (Google) Signed-off-by: Greg Kroah-Hartman --- kernel/trace/trace_events.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index e00da4182deb7..099f081329021 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c @@ -700,6 +700,8 @@ int trace_event_reg(struct trace_event_call *call, #ifdef CONFIG_PERF_EVENTS case TRACE_REG_PERF_REGISTER: + if (!call->class->perf_probe) + return -ENODEV; return tracepoint_probe_register(call->tp, call->class->perf_probe, call); From 7992a8c946890a1a6d870bfac4e737a71a8a1676 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 15 Dec 2025 15:21:34 +0100 Subject: [PATCH 1363/2333] PM: runtime: Do not clear needs_force_resume with enabled runtime PM commit 359afc8eb02a518fbdd0cbd462c8c2827c6cbec2 upstream. Commit 89d9cec3b1e9 ("PM: runtime: Clear power.needs_force_resume in pm_runtime_reinit()") added provisional clearing of power.needs_force_resume to pm_runtime_reinit(), but it is done unconditionally which is a mistake because pm_runtime_reinit() may race with driver probing and removal [1]. To address this, notice that power.needs_force_resume should never be set when runtime PM is enabled and so it only needs to be cleared when runtime PM is disabled, and update pm_runtime_init() to only clear that flag when runtime PM is disabled. Fixes: 89d9cec3b1e9 ("PM: runtime: Clear power.needs_force_resume in pm_runtime_reinit()") Reported-by: Ed Tsai Closes: https://lore.kernel.org/linux-pm/20251215122154.3180001-1-ed.tsai@mediatek.com/ [1] Signed-off-by: Rafael J. Wysocki Cc: 6.17+ # 6.17+ Reviewed-by: Ulf Hansson Link: https://patch.msgid.link/12807571.O9o76ZdvQC@rafael.j.wysocki Signed-off-by: Greg Kroah-Hartman --- drivers/base/power/runtime.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index 1b11a3cd4acc2..e882b5269ebec 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c @@ -1869,16 +1869,18 @@ void pm_runtime_init(struct device *dev) */ void pm_runtime_reinit(struct device *dev) { - if (!pm_runtime_enabled(dev)) { - if (dev->power.runtime_status == RPM_ACTIVE) - pm_runtime_set_suspended(dev); - if (dev->power.irq_safe) { - spin_lock_irq(&dev->power.lock); - dev->power.irq_safe = 0; - spin_unlock_irq(&dev->power.lock); - if (dev->parent) - pm_runtime_put(dev->parent); - } + if (pm_runtime_enabled(dev)) + return; + + if (dev->power.runtime_status == RPM_ACTIVE) + pm_runtime_set_suspended(dev); + + if (dev->power.irq_safe) { + spin_lock_irq(&dev->power.lock); + dev->power.irq_safe = 0; + spin_unlock_irq(&dev->power.lock); + if (dev->parent) + pm_runtime_put(dev->parent); } /* * Clear power.needs_force_resume in case it has been set by From 5bb88024409ef7bb53e5d42d35097a7a3157f764 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sat, 29 Nov 2025 00:48:45 +0000 Subject: [PATCH 1364/2333] arm64/gcs: Flush the GCS locking state on exec commit 98a97bf41528ef738b06eb07ec2b2eb1cfde6ce6 upstream. When we exec a new task we forget to flush the set of locked GCS mode bits. Since we do flush the rest of the state this means that if GCS is locked the new task will be unable to enable GCS, it will be locked as being disabled. Add the expected flush. Fixes: fc84bc5378a8 ("arm64/gcs: Context switch GCS state for EL0") Cc: # 6.13.x Reported-by: Yury Khrustalev Signed-off-by: Mark Brown Tested-by: Yury Khrustalev Signed-off-by: Catalin Marinas Signed-off-by: Greg Kroah-Hartman --- arch/arm64/kernel/process.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c index fba7ca102a8c4..489554931231e 100644 --- a/arch/arm64/kernel/process.c +++ b/arch/arm64/kernel/process.c @@ -292,6 +292,7 @@ static void flush_gcs(void) current->thread.gcs_base = 0; current->thread.gcs_size = 0; current->thread.gcs_el0_mode = 0; + current->thread.gcs_el0_locked = 0; write_sysreg_s(GCSCRE0_EL1_nTR, SYS_GCSCRE0_EL1); write_sysreg_s(0, SYS_GCSPR_EL0); } From 681fd588733cd9e3ca033474f6b46ed147331af7 Mon Sep 17 00:00:00 2001 From: Charles Mirabile Date: Fri, 12 Dec 2025 13:47:17 -0500 Subject: [PATCH 1365/2333] lib/crypto: riscv: Add poly1305-core.S to .gitignore commit 5a0b1882506858b12cc77f0e2439a5f3c5052761 upstream. poly1305-core.S is an auto-generated file, so it should be ignored. Fixes: bef9c7559869 ("lib/crypto: riscv/poly1305: Import OpenSSL/CRYPTOGAMS implementation") Cc: stable@vger.kernel.org Signed-off-by: Charles Mirabile Link: https://lore.kernel.org/r/20251212184717.133701-1-cmirabil@redhat.com Signed-off-by: Eric Biggers Signed-off-by: Greg Kroah-Hartman --- lib/crypto/riscv/.gitignore | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 lib/crypto/riscv/.gitignore diff --git a/lib/crypto/riscv/.gitignore b/lib/crypto/riscv/.gitignore new file mode 100644 index 0000000000000..0d47d4f21c6de --- /dev/null +++ b/lib/crypto/riscv/.gitignore @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0-only +poly1305-core.S From 779fa2a063d4603da4b9b5c89c326da2d0f5e253 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Rebe?= Date: Tue, 2 Dec 2025 19:41:37 +0100 Subject: [PATCH 1366/2333] r8169: fix RTL8117 Wake-on-Lan in DASH mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit dd75c723ef566f7f009c047f47e0eee95fe348ab upstream. Wake-on-Lan does currently not work for r8169 in DASH mode, e.g. the ASUS Pro WS X570-ACE with RTL8168fp/RTL8117. Fix by not returning early in rtl_prepare_power_down when dash_enabled. While this fixes WoL, it still kills the OOB RTL8117 remote management BMC connection. Fix by not calling rtl8168_driver_stop if WoL is enabled. Fixes: 065c27c184d6 ("r8169: phy power ops") Signed-off-by: René Rebe Cc: stable@vger.kernel.org Reviewed-by: Heiner Kallweit Link: https://patch.msgid.link/20251202.194137.1647877804487085954.rene@exactco.de Signed-off-by: Jakub Kicinski Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/realtek/r8169_main.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index 853aabedb128d..d407b031cc2ae 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -2669,9 +2669,6 @@ static void rtl_wol_enable_rx(struct rtl8169_private *tp) static void rtl_prepare_power_down(struct rtl8169_private *tp) { - if (tp->dash_enabled) - return; - if (tp->mac_version == RTL_GIGA_MAC_VER_32 || tp->mac_version == RTL_GIGA_MAC_VER_33) rtl_ephy_write(tp, 0x19, 0xff64); @@ -4807,7 +4804,7 @@ static void rtl8169_down(struct rtl8169_private *tp) rtl_disable_exit_l1(tp); rtl_prepare_power_down(tp); - if (tp->dash_type != RTL_DASH_NONE) + if (tp->dash_type != RTL_DASH_NONE && !tp->saved_wolopts) rtl8168_driver_stop(tp); } From 7b9ea7aa24bd1cafa12aab519c8023048033fafc Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Tue, 2 Dec 2025 18:27:44 +0100 Subject: [PATCH 1367/2333] net: phy: marvell-88q2xxx: Fix clamped value in mv88q2xxx_hwmon_write commit c4cdf7376271bce5714c06d79ec67759b18910eb upstream. The local variable 'val' was never clamped to -75000 or 180000 because the return value of clamp_val() was not used. Fix this by assigning the clamped value back to 'val', and use clamp() instead of clamp_val(). Cc: stable@vger.kernel.org Fixes: a557a92e6881 ("net: phy: marvell-88q2xxx: add support for temperature sensor") Signed-off-by: Thorsten Blum Reviewed-by: Dimitri Fedrau Reviewed-by: Andrew Lunn Link: https://patch.msgid.link/20251202172743.453055-3-thorsten.blum@linux.dev Signed-off-by: Jakub Kicinski Signed-off-by: Greg Kroah-Hartman --- drivers/net/phy/marvell-88q2xxx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/phy/marvell-88q2xxx.c b/drivers/net/phy/marvell-88q2xxx.c index f3d83b04c9535..201dee1a16985 100644 --- a/drivers/net/phy/marvell-88q2xxx.c +++ b/drivers/net/phy/marvell-88q2xxx.c @@ -698,7 +698,7 @@ static int mv88q2xxx_hwmon_write(struct device *dev, switch (attr) { case hwmon_temp_max: - clamp_val(val, -75000, 180000); + val = clamp(val, -75000, 180000); val = (val / 1000) + 75; val = FIELD_PREP(MDIO_MMD_PCS_MV_TEMP_SENSOR3_INT_THRESH_MASK, val); From 7a93edb23bcf07a3aaf8b598edfc2faa8fbcc0b6 Mon Sep 17 00:00:00 2001 From: Amir Goldstein Date: Sun, 7 Dec 2025 11:44:55 +0100 Subject: [PATCH 1368/2333] fsnotify: do not generate ACCESS/MODIFY events on child for special files commit 635bc4def026a24e071436f4f356ea08c0eed6ff upstream. inotify/fanotify do not allow users with no read access to a file to subscribe to events (e.g. IN_ACCESS/IN_MODIFY), but they do allow the same user to subscribe for watching events on children when the user has access to the parent directory (e.g. /dev). Users with no read access to a file but with read access to its parent directory can still stat the file and see if it was accessed/modified via atime/mtime change. The same is not true for special files (e.g. /dev/null). Users will not generally observe atime/mtime changes when other users read/write to special files, only when someone sets atime/mtime via utimensat(). Align fsnotify events with this stat behavior and do not generate ACCESS/MODIFY events to parent watchers on read/write of special files. The events are still generated to parent watchers on utimensat(). This closes some side-channels that could be possibly used for information exfiltration [1]. [1] https://snee.la/pdf/pubs/file-notification-attacks.pdf Reported-by: Sudheendra Raghav Neela CC: stable@vger.kernel.org Signed-off-by: Amir Goldstein Signed-off-by: Jan Kara Signed-off-by: Greg Kroah-Hartman --- fs/notify/fsnotify.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c index 46bfc543f9467..63dd44931989d 100644 --- a/fs/notify/fsnotify.c +++ b/fs/notify/fsnotify.c @@ -270,8 +270,15 @@ int __fsnotify_parent(struct dentry *dentry, __u32 mask, const void *data, /* * Include parent/name in notification either if some notification * groups require parent info or the parent is interested in this event. + * The parent interest in ACCESS/MODIFY events does not apply to special + * files, where read/write are not on the filesystem of the parent and + * events can provide an undesirable side-channel for information + * exfiltration. */ - parent_interested = mask & p_mask & ALL_FSNOTIFY_EVENTS; + parent_interested = mask & p_mask & ALL_FSNOTIFY_EVENTS && + !(data_type == FSNOTIFY_EVENT_PATH && + d_is_special(dentry) && + (mask & (FS_ACCESS | FS_MODIFY))); if (parent_needed || parent_interested) { /* When notifying parent, child should be passed as data */ WARN_ON_ONCE(inode != fsnotify_data_inode(data, data_type)); From b225325be7b247c7268e65eea6090db1fc786d1f Mon Sep 17 00:00:00 2001 From: caoping Date: Thu, 4 Dec 2025 01:10:58 -0800 Subject: [PATCH 1369/2333] net/handshake: restore destructor on submit failure commit 6af2a01d65f89e73c1cbb9267f8880d83a88cee4 upstream. handshake_req_submit() replaces sk->sk_destruct but never restores it when submission fails before the request is hashed. handshake_sk_destruct() then returns early and the original destructor never runs, leaking the socket. Restore sk_destruct on the error path. Fixes: 3b3009ea8abb ("net/handshake: Create a NETLINK service for handling handshake requests") Reviewed-by: Chuck Lever Cc: stable@vger.kernel.org Signed-off-by: caoping Link: https://patch.msgid.link/20251204091058.1545151-1-caoping@cmss.chinamobile.com Signed-off-by: Jakub Kicinski Signed-off-by: Greg Kroah-Hartman --- net/handshake/request.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/handshake/request.c b/net/handshake/request.c index f78091680bca5..6b7e3e0bf3996 100644 --- a/net/handshake/request.c +++ b/net/handshake/request.c @@ -276,6 +276,8 @@ int handshake_req_submit(struct socket *sock, struct handshake_req *req, out_unlock: spin_unlock(&hn->hn_lock); out_err: + /* Restore original destructor so socket teardown still runs on failure */ + req->hr_sk->sk_destruct = req->hr_odestruct; trace_handshake_submit_err(net, req, req->hr_sk, ret); handshake_req_destroy(req); return ret; From b8db16f97d086fb6e14d6a5c0b1f5b862c230443 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 17 Nov 2025 11:00:49 -0500 Subject: [PATCH 1370/2333] NFSD: Clear SECLABEL in the suppattr_exclcreat bitmap commit 27d17641cacfedd816789b75d342430f6b912bd2 upstream. >From RFC 8881: 5.8.1.14. Attribute 75: suppattr_exclcreat > The bit vector that would set all REQUIRED and RECOMMENDED > attributes that are supported by the EXCLUSIVE4_1 method of file > creation via the OPEN operation. The scope of this attribute > applies to all objects with a matching fsid. There's nothing in RFC 8881 that states that suppattr_exclcreat is or is not allowed to contain bits for attributes that are clear in the reported supported_attrs bitmask. But it doesn't make sense for an NFS server to indicate that it /doesn't/ implement an attribute, but then also indicate that clients /are/ allowed to set that attribute using OPEN(create) with EXCLUSIVE4_1. Ensure that the SECURITY_LABEL and ACL bits are not set in the suppattr_exclcreat bitmask when they are also not set in the supported_attrs bitmask. Fixes: 8c18f2052e75 ("nfsd41: SUPPATTR_EXCLCREAT attribute") Cc: stable@vger.kernel.org Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever Signed-off-by: Greg Kroah-Hartman --- fs/nfsd/nfs4xdr.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 67bb9c0b9fcb1..4a403ce4fd468 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -3375,6 +3375,11 @@ static __be32 nfsd4_encode_fattr4_suppattr_exclcreat(struct xdr_stream *xdr, u32 supp[3]; memcpy(supp, nfsd_suppattrs[resp->cstate.minorversion], sizeof(supp)); + if (!IS_POSIXACL(d_inode(args->dentry))) + supp[0] &= ~FATTR4_WORD0_ACL; + if (!args->contextsupport) + supp[2] &= ~FATTR4_WORD2_SECURITY_LABEL; + supp[0] &= NFSD_SUPPATTR_EXCLCREAT_WORD0; supp[1] &= NFSD_SUPPATTR_EXCLCREAT_WORD1; supp[2] &= NFSD_SUPPATTR_EXCLCREAT_WORD2; From 214b396480061cbc8b16f2c518b2add7fbfa5192 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Tue, 18 Nov 2025 19:51:19 -0500 Subject: [PATCH 1371/2333] NFSD: NFSv4 file creation neglects setting ACL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 913f7cf77bf14c13cfea70e89bcb6d0b22239562 upstream. An NFSv4 client that sets an ACL with a named principal during file creation retrieves the ACL afterwards, and finds that it is only a default ACL (based on the mode bits) and not the ACL that was requested during file creation. This violates RFC 8881 section 6.4.1.3: "the ACL attribute is set as given". The issue occurs in nfsd_create_setattr(), which calls nfsd_attrs_valid() to determine whether to call nfsd_setattr(). However, nfsd_attrs_valid() checks only for iattr changes and security labels, but not POSIX ACLs. When only an ACL is present, the function returns false, nfsd_setattr() is skipped, and the POSIX ACL is never applied to the inode. Subsequently, when the client retrieves the ACL, the server finds no POSIX ACL on the inode and returns one generated from the file's mode bits rather than returning the originally-specified ACL. Reported-by: Aurélien Couderc Fixes: c0cbe70742f4 ("NFSD: add posix ACLs to struct nfsd_attrs") Cc: Roland Mainz Cc: stable@vger.kernel.org Signed-off-by: Chuck Lever Signed-off-by: Greg Kroah-Hartman --- fs/nfsd/vfs.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h index 0c0292611c6de..9652c1de53ec1 100644 --- a/fs/nfsd/vfs.h +++ b/fs/nfsd/vfs.h @@ -67,7 +67,8 @@ static inline bool nfsd_attrs_valid(struct nfsd_attrs *attrs) struct iattr *iap = attrs->na_iattr; return (iap->ia_valid || (attrs->na_seclabel && - attrs->na_seclabel->len)); + attrs->na_seclabel->len) || + attrs->na_pacl || attrs->na_dpacl); } __be32 nfserrno (int errno); From 134436e66019d1176d0ebd74b9aedff6deb79534 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Mon, 15 Dec 2025 14:06:47 +0200 Subject: [PATCH 1372/2333] ASoC: SOF: ipc4-topology: Prefer 32-bit DMIC blobs for 8-bit formats as well commit 26e455064983e00013c0a63ffe0eed9e9ec2fa89 upstream. With the introduction of 8-bit formats the DMIC blob lookup also needs to be modified to prefer the 32-bit blob when 8-bit format is used on FE. At the same time we also need to make sure that in case 8-bit format is used, but only 16-bit blob is available for DMIC then we will not try to look for 8-bit blob (which is invalid) as fallback, but for a 16-bit one. Fixes: c04c2e829649 ("ASoC: SOF: ipc4-topology: Add support for 8-bit formats") Cc: stable@vger.kernel.org Signed-off-by: Peter Ujfalusi Reviewed-by: Bard Liao Reviewed-by: Seppo Ingalsuo Reviewed-by: Kai Vehmanen Reviewed-by: Ranjani Sridharan Link: https://patch.msgid.link/20251215120648.4827-2-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/sof/ipc4-topology.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index 221e9d4052b8f..47959f182f4be 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -1752,11 +1752,9 @@ snd_sof_get_nhlt_endpoint_data(struct snd_sof_dev *sdev, struct snd_sof_dai *dai channel_count = params_channels(params); sample_rate = params_rate(params); bit_depth = params_width(params); - /* - * Look for 32-bit blob first instead of 16-bit if copier - * supports multiple formats - */ - if (bit_depth == 16 && !single_bitdepth) { + + /* Prefer 32-bit blob if copier supports multiple formats */ + if (bit_depth <= 16 && !single_bitdepth) { dev_dbg(sdev->dev, "Looking for 32-bit blob first for DMIC\n"); format_change = true; bit_depth = 32; @@ -1799,10 +1797,18 @@ snd_sof_get_nhlt_endpoint_data(struct snd_sof_dev *sdev, struct snd_sof_dai *dai if (format_change) { /* * The 32-bit blob was not found in NHLT table, try to - * look for one based on the params + * look for 16-bit for DMIC or based on the params for + * SSP */ - bit_depth = params_width(params); - format_change = false; + if (linktype == SOF_DAI_INTEL_DMIC) { + bit_depth = 16; + if (params_width(params) == 16) + format_change = false; + } else { + bit_depth = params_width(params); + format_change = false; + } + get_new_blob = true; } else if (linktype == SOF_DAI_INTEL_DMIC && !single_bitdepth) { /* From 5060592025103e78cc90854a9c8d64591fbeccf1 Mon Sep 17 00:00:00 2001 From: Antheas Kapenekakis Date: Tue, 16 Dec 2025 22:17:14 +0100 Subject: [PATCH 1373/2333] ALSA: hda/realtek: Add Asus quirk for TAS amplifiers commit f7cede182c963720edd1e5fb50ea4f1c7eafa30e upstream. By default, these devices use the quirk ALC294_FIXUP_ASUS_SPK. Not using it causes the headphone jack to stop working. Therefore, introduce a new quirk ALC287_FIXUP_TXNW2781_I2C_ASUS that binds to the TAS amplifier while using that quirk. Cc: stable@kernel.org Fixes: 18a4895370a7 ("ALSA: hda/realtek: Add match for ASUS Xbox Ally projects") Signed-off-by: Antheas Kapenekakis Link: https://patch.msgid.link/20251216211714.1116898-1-lkml@antheas.dev Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/hda/codecs/realtek/alc269.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/sound/hda/codecs/realtek/alc269.c b/sound/hda/codecs/realtek/alc269.c index a6d494dab5b6d..b3582e390dfa3 100644 --- a/sound/hda/codecs/realtek/alc269.c +++ b/sound/hda/codecs/realtek/alc269.c @@ -3703,6 +3703,7 @@ enum { ALC295_FIXUP_DELL_TAS2781_I2C, ALC245_FIXUP_TAS2781_SPI_2, ALC287_FIXUP_TXNW2781_I2C, + ALC287_FIXUP_TXNW2781_I2C_ASUS, ALC287_FIXUP_YOGA7_14ARB7_I2C, ALC245_FIXUP_HP_MUTE_LED_COEFBIT, ALC245_FIXUP_HP_MUTE_LED_V1_COEFBIT, @@ -5993,6 +5994,12 @@ static const struct hda_fixup alc269_fixups[] = { .chained = true, .chain_id = ALC285_FIXUP_THINKPAD_HEADSET_JACK, }, + [ALC287_FIXUP_TXNW2781_I2C_ASUS] = { + .type = HDA_FIXUP_FUNC, + .v.func = tas2781_fixup_txnw_i2c, + .chained = true, + .chain_id = ALC294_FIXUP_ASUS_SPK, + }, [ALC287_FIXUP_YOGA7_14ARB7_I2C] = { .type = HDA_FIXUP_FUNC, .v.func = yoga7_14arb7_fixup_i2c, @@ -6736,8 +6743,8 @@ static const struct hda_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1043, 0x12f0, "ASUS X541UV", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1043, 0x1313, "Asus K42JZ", ALC269VB_FIXUP_ASUS_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1043, 0x1314, "ASUS GA605K", ALC285_FIXUP_ASUS_GA605K_HEADSET_MIC), - SND_PCI_QUIRK(0x1043, 0x1384, "ASUS RC73XA", ALC287_FIXUP_TXNW2781_I2C), - SND_PCI_QUIRK(0x1043, 0x1394, "ASUS RC73YA", ALC287_FIXUP_TXNW2781_I2C), + SND_PCI_QUIRK(0x1043, 0x1384, "ASUS RC73XA", ALC287_FIXUP_TXNW2781_I2C_ASUS), + SND_PCI_QUIRK(0x1043, 0x1394, "ASUS RC73YA", ALC287_FIXUP_TXNW2781_I2C_ASUS), SND_PCI_QUIRK(0x1043, 0x13b0, "ASUS Z550SA", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1043, 0x1427, "Asus Zenbook UX31E", ALC269VB_FIXUP_ASUS_ZENBOOK), SND_PCI_QUIRK(0x1043, 0x1433, "ASUS GX650PY/PZ/PV/PU/PYV/PZV/PIV/PVV", ALC285_FIXUP_ASUS_I2C_HEADSET_MIC), From 42ed4c781019e4c19af74b9edd1f7e31b439c2c9 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 17 Nov 2025 11:00:50 -0500 Subject: [PATCH 1374/2333] NFSD: Clear TIME_DELEG in the suppattr_exclcreat bitmap commit ad3cbbb0c1892c48919727fcb8dec5965da8bacb upstream. >From RFC 8881: 5.8.1.14. Attribute 75: suppattr_exclcreat > The bit vector that would set all REQUIRED and RECOMMENDED > attributes that are supported by the EXCLUSIVE4_1 method of file > creation via the OPEN operation. The scope of this attribute > applies to all objects with a matching fsid. There's nothing in RFC 8881 that states that suppattr_exclcreat is or is not allowed to contain bits for attributes that are clear in the reported supported_attrs bitmask. But it doesn't make sense for an NFS server to indicate that it /doesn't/ implement an attribute, but then also indicate that clients /are/ allowed to set that attribute using OPEN(create) with EXCLUSIVE4_1. The FATTR4_WORD2_TIME_DELEG attributes are also not to be allowed for OPEN(create) with EXCLUSIVE4_1. It doesn't make sense to set a delegated timestamp on a new file. Fixes: 7e13f4f8d27d ("nfsd: handle delegated timestamps in SETATTR") Cc: stable@vger.kernel.org Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever Signed-off-by: Greg Kroah-Hartman --- fs/nfsd/nfsd.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h index b752433c3c2c4..191cbf9320c0f 100644 --- a/fs/nfsd/nfsd.h +++ b/fs/nfsd/nfsd.h @@ -547,8 +547,14 @@ static inline bool nfsd_attrs_supported(u32 minorversion, const u32 *bmval) #define NFSD_SUPPATTR_EXCLCREAT_WORD1 \ (NFSD_WRITEABLE_ATTRS_WORD1 & \ ~(FATTR4_WORD1_TIME_ACCESS_SET | FATTR4_WORD1_TIME_MODIFY_SET)) +/* + * The FATTR4_WORD2_TIME_DELEG attributes are not to be allowed for + * OPEN(create) with EXCLUSIVE4_1. It doesn't make sense to set a + * delegated timestamp on a new file. + */ #define NFSD_SUPPATTR_EXCLCREAT_WORD2 \ - NFSD_WRITEABLE_ATTRS_WORD2 + (NFSD_WRITEABLE_ATTRS_WORD2 & \ + ~(FATTR4_WORD2_TIME_DELEG_ACCESS | FATTR4_WORD2_TIME_DELEG_MODIFY)) extern int nfsd4_is_junction(struct dentry *dentry); extern int register_cld_notifier(void); From 7d17693eb79d3fe6c81066b6ca566546fd38ba1f Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Mon, 15 Dec 2025 14:06:48 +0200 Subject: [PATCH 1375/2333] ASoC: SOF: ipc4-topology: Convert FLOAT to S32 during blob selection commit 816f291fc23f325d31509d0e97873249ad75ae9a upstream. SSP/DMIC blobs have no support for FLOAT type, they are using S32 on data bus. Convert the format from FLOAT_LE to S32_LE to make sure that the correct format is used within the path. FLOAT conversion will be done on the host side (or within the path). Fixes: f7c41911ad74 ("ASoC: SOF: ipc4-topology: Add support for float sample type") Cc: stable@vger.kernel.org Signed-off-by: Peter Ujfalusi Reviewed-by: Bard Liao Reviewed-by: Seppo Ingalsuo Reviewed-by: Kai Vehmanen Reviewed-by: Ranjani Sridharan Link: https://patch.msgid.link/20251215120648.4827-3-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/sof/ipc4-topology.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index 47959f182f4be..32b628e2fe29b 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -1843,7 +1843,7 @@ snd_sof_get_nhlt_endpoint_data(struct snd_sof_dev *sdev, struct snd_sof_dai *dai *len = cfg->size >> 2; *dst = (u32 *)cfg->caps; - if (format_change) { + if (format_change || params_format(params) == SNDRV_PCM_FORMAT_FLOAT_LE) { /* * Update the params to reflect that different blob was loaded * instead of the requested bit depth (16 -> 32 or 32 -> 16). From da1ccfc4c452541584a4eae89e337cfa21be6d5a Mon Sep 17 00:00:00 2001 From: Joshua Rogers Date: Fri, 7 Nov 2025 10:09:49 -0500 Subject: [PATCH 1376/2333] svcrdma: bound check rq_pages index in inline path commit d1bea0ce35b6095544ee82bb54156fc62c067e58 upstream. svc_rdma_copy_inline_range indexed rqstp->rq_pages[rc_curpage] without verifying rc_curpage stays within the allocated page array. Add guards before the first use and after advancing to a new page. Fixes: d7cc73972661 ("svcrdma: support multiple Read chunks per RPC") Cc: stable@vger.kernel.org Signed-off-by: Joshua Rogers Signed-off-by: Chuck Lever Signed-off-by: Greg Kroah-Hartman --- net/sunrpc/xprtrdma/svc_rdma_rw.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/sunrpc/xprtrdma/svc_rdma_rw.c b/net/sunrpc/xprtrdma/svc_rdma_rw.c index 661b3fe2779f0..b5cd37884f53d 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_rw.c +++ b/net/sunrpc/xprtrdma/svc_rdma_rw.c @@ -841,6 +841,9 @@ static int svc_rdma_copy_inline_range(struct svc_rqst *rqstp, for (page_no = 0; page_no < numpages; page_no++) { unsigned int page_len; + if (head->rc_curpage >= rqstp->rq_maxpages) + return -EINVAL; + page_len = min_t(unsigned int, remaining, PAGE_SIZE - head->rc_pageoff); From 433bb1344ef66cc071d7e1977744ef9b06a15c2b Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 13 Nov 2025 09:31:31 +0100 Subject: [PATCH 1377/2333] nfsd: Mark variable __maybe_unused to avoid W=1 build break commit ebae102897e760e9e6bc625f701dd666b2163bd1 upstream. Clang is not happy about set but (in some cases) unused variable: fs/nfsd/export.c:1027:17: error: variable 'inode' set but not used [-Werror,-Wunused-but-set-variable] since it's used as a parameter to dprintk() which might be configured a no-op. To avoid uglifying code with the specific ifdeffery just mark the variable __maybe_unused. The commit [1], which introduced this behaviour, is quite old and hence the Fixes tag points to the first of the Git era. Link: https://git.kernel.org/pub/scm/linux/kernel/git/history/history.git/commit/?id=0431923fb7a1 [1] Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Cc: stable@vger.kernel.org Signed-off-by: Andy Shevchenko Signed-off-by: Chuck Lever Signed-off-by: Greg Kroah-Hartman --- fs/nfsd/export.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index 9d55512d0cc97..2a1499f2ad196 100644 --- a/fs/nfsd/export.c +++ b/fs/nfsd/export.c @@ -1024,7 +1024,7 @@ exp_rootfh(struct net *net, struct auth_domain *clp, char *name, { struct svc_export *exp; struct path path; - struct inode *inode; + struct inode *inode __maybe_unused; struct svc_fh fh; int err; struct nfsd_net *nn = net_generic(net, nfsd_net_id); From 4846a4c6acb98efdefc1274c735746c3c31090e4 Mon Sep 17 00:00:00 2001 From: Joshua Rogers Date: Fri, 7 Nov 2025 10:09:48 -0500 Subject: [PATCH 1378/2333] svcrdma: return 0 on success from svc_rdma_copy_inline_range commit 94972027ab55b200e031059fd6c7a649f8248020 upstream. The function comment specifies 0 on success and -EINVAL on invalid parameters. Make the tail return 0 after a successful copy loop. Fixes: d7cc73972661 ("svcrdma: support multiple Read chunks per RPC") Cc: stable@vger.kernel.org Signed-off-by: Joshua Rogers Signed-off-by: Chuck Lever Signed-off-by: Greg Kroah-Hartman --- net/sunrpc/xprtrdma/svc_rdma_rw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/sunrpc/xprtrdma/svc_rdma_rw.c b/net/sunrpc/xprtrdma/svc_rdma_rw.c index b5cd37884f53d..5bc950d29366b 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_rw.c +++ b/net/sunrpc/xprtrdma/svc_rdma_rw.c @@ -863,7 +863,7 @@ static int svc_rdma_copy_inline_range(struct svc_rqst *rqstp, offset += page_len; } - return -EINVAL; + return 0; } /** From 2a77c8dd49bccf0ca232be7c836cec1209abb8da Mon Sep 17 00:00:00 2001 From: Joshua Rogers Date: Fri, 7 Nov 2025 10:09:47 -0500 Subject: [PATCH 1379/2333] svcrdma: use rc_pageoff for memcpy byte offset commit a8ee9099f30654917aa68f55d707b5627e1dbf77 upstream. svc_rdma_copy_inline_range added rc_curpage (page index) to the page base instead of the byte offset rc_pageoff. Use rc_pageoff so copies land within the current page. Found by ZeroPath (https://zeropath.com) Fixes: 8e122582680c ("svcrdma: Move svc_rdma_read_info::ri_pageno to struct svc_rdma_recv_ctxt") Cc: stable@vger.kernel.org Signed-off-by: Joshua Rogers Signed-off-by: Chuck Lever Signed-off-by: Greg Kroah-Hartman --- net/sunrpc/xprtrdma/svc_rdma_rw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/sunrpc/xprtrdma/svc_rdma_rw.c b/net/sunrpc/xprtrdma/svc_rdma_rw.c index 5bc950d29366b..310de7a80be52 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_rw.c +++ b/net/sunrpc/xprtrdma/svc_rdma_rw.c @@ -851,7 +851,7 @@ static int svc_rdma_copy_inline_range(struct svc_rqst *rqstp, head->rc_page_count++; dst = page_address(rqstp->rq_pages[head->rc_curpage]); - memcpy(dst + head->rc_curpage, src + offset, page_len); + memcpy((unsigned char *)dst + head->rc_pageoff, src + offset, page_len); head->rc_readbytes += page_len; head->rc_pageoff += page_len; From 1c8bb965e9b0559ff0f5690615a527c30f651dd8 Mon Sep 17 00:00:00 2001 From: Joshua Rogers Date: Fri, 7 Nov 2025 10:05:33 -0500 Subject: [PATCH 1380/2333] SUNRPC: svcauth_gss: avoid NULL deref on zero length gss_token in gss_read_proxy_verf commit d4b69a6186b215d2dc1ebcab965ed88e8d41768d upstream. A zero length gss_token results in pages == 0 and in_token->pages[0] is NULL. The code unconditionally evaluates page_address(in_token->pages[0]) for the initial memcpy, which can dereference NULL even when the copy length is 0. Guard the first memcpy so it only runs when length > 0. Fixes: 5866efa8cbfb ("SUNRPC: Fix svcauth_gss_proxy_init()") Cc: stable@vger.kernel.org Signed-off-by: Joshua Rogers Signed-off-by: Chuck Lever Signed-off-by: Greg Kroah-Hartman --- net/sunrpc/auth_gss/svcauth_gss.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c index a8ec30759a184..e2f0df8cdaa6a 100644 --- a/net/sunrpc/auth_gss/svcauth_gss.c +++ b/net/sunrpc/auth_gss/svcauth_gss.c @@ -1083,7 +1083,8 @@ static int gss_read_proxy_verf(struct svc_rqst *rqstp, } length = min_t(unsigned int, inlen, (char *)xdr->end - (char *)xdr->p); - memcpy(page_address(in_token->pages[0]), xdr->p, length); + if (length) + memcpy(page_address(in_token->pages[0]), xdr->p, length); inlen -= length; to_offs = length; From 0d5c9e901ad40bd39b38e119c0454b52d7663930 Mon Sep 17 00:00:00 2001 From: "Nysal Jan K.A." Date: Tue, 28 Oct 2025 16:25:12 +0530 Subject: [PATCH 1381/2333] powerpc/kexec: Enable SMT before waking offline CPUs commit c2296a1e42418556efbeb5636c4fa6aa6106713a upstream. If SMT is disabled or a partial SMT state is enabled, when a new kernel image is loaded for kexec, on reboot the following warning is observed: kexec: Waking offline cpu 228. WARNING: CPU: 0 PID: 9062 at arch/powerpc/kexec/core_64.c:223 kexec_prepare_cpus+0x1b0/0x1bc [snip] NIP kexec_prepare_cpus+0x1b0/0x1bc LR kexec_prepare_cpus+0x1a0/0x1bc Call Trace: kexec_prepare_cpus+0x1a0/0x1bc (unreliable) default_machine_kexec+0x160/0x19c machine_kexec+0x80/0x88 kernel_kexec+0xd0/0x118 __do_sys_reboot+0x210/0x2c4 system_call_exception+0x124/0x320 system_call_vectored_common+0x15c/0x2ec This occurs as add_cpu() fails due to cpu_bootable() returning false for CPUs that fail the cpu_smt_thread_allowed() check or non primary threads if SMT is disabled. Fix the issue by enabling SMT and resetting the number of SMT threads to the number of threads per core, before attempting to wake up all present CPUs. Fixes: 38253464bc82 ("cpu/SMT: Create topology_smt_thread_allowed()") Reported-by: Sachin P Bappalige Cc: stable@vger.kernel.org # v6.6+ Reviewed-by: Srikar Dronamraju Signed-off-by: Nysal Jan K.A. Tested-by: Samir M Reviewed-by: Sourabh Jain Signed-off-by: Madhavan Srinivasan Link: https://patch.msgid.link/20251028105516.26258-1-nysal@linux.ibm.com Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/kexec/core_64.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/arch/powerpc/kexec/core_64.c b/arch/powerpc/kexec/core_64.c index 222aa326dacee..825ab8a88f18e 100644 --- a/arch/powerpc/kexec/core_64.c +++ b/arch/powerpc/kexec/core_64.c @@ -202,6 +202,23 @@ static void kexec_prepare_cpus_wait(int wait_state) mb(); } + +/* + * The add_cpu() call in wake_offline_cpus() can fail as cpu_bootable() + * returns false for CPUs that fail the cpu_smt_thread_allowed() check + * or non primary threads if SMT is disabled. Re-enable SMT and set the + * number of SMT threads to threads per core. + */ +static void kexec_smt_reenable(void) +{ +#if defined(CONFIG_SMP) && defined(CONFIG_HOTPLUG_SMT) + lock_device_hotplug(); + cpu_smt_num_threads = threads_per_core; + cpu_smt_control = CPU_SMT_ENABLED; + unlock_device_hotplug(); +#endif +} + /* * We need to make sure each present CPU is online. The next kernel will scan * the device tree and assume primary threads are online and query secondary @@ -216,6 +233,8 @@ static void wake_offline_cpus(void) { int cpu = 0; + kexec_smt_reenable(); + for_each_present_cpu(cpu) { if (!cpu_online(cpu)) { printk(KERN_INFO "kexec: Waking offline cpu %d.\n", From a35788ddf8df65837897ecbb0ddb2896b863159e Mon Sep 17 00:00:00 2001 From: Filipe Manana Date: Thu, 27 Nov 2025 16:35:59 +0000 Subject: [PATCH 1382/2333] btrfs: don't log conflicting inode if it's a dir moved in the current transaction commit 266273eaf4d99475f1ae57f687b3e42bc71ec6f0 upstream. We can't log a conflicting inode if it's a directory and it was moved from one parent directory to another parent directory in the current transaction, as this can result an attempt to have a directory with two hard links during log replay, one for the old parent directory and another for the new parent directory. The following scenario triggers that issue: 1) We have directories "dir1" and "dir2" created in a past transaction. Directory "dir1" has inode A as its parent directory; 2) We move "dir1" to some other directory; 3) We create a file with the name "dir1" in directory inode A; 4) We fsync the new file. This results in logging the inode of the new file and the inode for the directory "dir1" that was previously moved in the current transaction. So the log tree has the INODE_REF item for the new location of "dir1"; 5) We move the new file to some other directory. This results in updating the log tree to included the new INODE_REF for the new location of the file and removes the INODE_REF for the old location. This happens during the rename when we call btrfs_log_new_name(); 6) We fsync the file, and that persists the log tree changes done in the previous step (btrfs_log_new_name() only updates the log tree in memory); 7) We have a power failure; 8) Next time the fs is mounted, log replay happens and when processing the inode for directory "dir1" we find a new INODE_REF and add that link, but we don't remove the old link of the inode since we have not logged the old parent directory of the directory inode "dir1". As a result after log replay finishes when we trigger writeback of the subvolume tree's extent buffers, the tree check will detect that we have a directory a hard link count of 2 and we get a mount failure. The errors and stack traces reported in dmesg/syslog are like this: [ 3845.729764] BTRFS info (device dm-0): start tree-log replay [ 3845.730304] page: refcount:3 mapcount:0 mapping:000000005c8a3027 index:0x1d00 pfn:0x11510c [ 3845.731236] memcg:ffff9264c02f4e00 [ 3845.731751] aops:btree_aops [btrfs] ino:1 [ 3845.732300] flags: 0x17fffc00000400a(uptodate|private|writeback|node=0|zone=2|lastcpupid=0x1ffff) [ 3845.733346] raw: 017fffc00000400a 0000000000000000 dead000000000122 ffff9264d978aea8 [ 3845.734265] raw: 0000000000001d00 ffff92650e6d4738 00000003ffffffff ffff9264c02f4e00 [ 3845.735305] page dumped because: eb page dump [ 3845.735981] BTRFS critical (device dm-0): corrupt leaf: root=5 block=30408704 slot=6 ino=257, invalid nlink: has 2 expect no more than 1 for dir [ 3845.737786] BTRFS info (device dm-0): leaf 30408704 gen 10 total ptrs 17 free space 14881 owner 5 [ 3845.737789] BTRFS info (device dm-0): refs 4 lock_owner 0 current 30701 [ 3845.737792] item 0 key (256 INODE_ITEM 0) itemoff 16123 itemsize 160 [ 3845.737794] inode generation 3 transid 9 size 16 nbytes 16384 [ 3845.737795] block group 0 mode 40755 links 1 uid 0 gid 0 [ 3845.737797] rdev 0 sequence 2 flags 0x0 [ 3845.737798] atime 1764259517.0 [ 3845.737800] ctime 1764259517.572889464 [ 3845.737801] mtime 1764259517.572889464 [ 3845.737802] otime 1764259517.0 [ 3845.737803] item 1 key (256 INODE_REF 256) itemoff 16111 itemsize 12 [ 3845.737805] index 0 name_len 2 [ 3845.737807] item 2 key (256 DIR_ITEM 2363071922) itemoff 16077 itemsize 34 [ 3845.737808] location key (257 1 0) type 2 [ 3845.737810] transid 9 data_len 0 name_len 4 [ 3845.737811] item 3 key (256 DIR_ITEM 2676584006) itemoff 16043 itemsize 34 [ 3845.737813] location key (258 1 0) type 2 [ 3845.737814] transid 9 data_len 0 name_len 4 [ 3845.737815] item 4 key (256 DIR_INDEX 2) itemoff 16009 itemsize 34 [ 3845.737816] location key (257 1 0) type 2 [ 3845.737818] transid 9 data_len 0 name_len 4 [ 3845.737819] item 5 key (256 DIR_INDEX 3) itemoff 15975 itemsize 34 [ 3845.737820] location key (258 1 0) type 2 [ 3845.737821] transid 9 data_len 0 name_len 4 [ 3845.737822] item 6 key (257 INODE_ITEM 0) itemoff 15815 itemsize 160 [ 3845.737824] inode generation 9 transid 10 size 6 nbytes 0 [ 3845.737825] block group 0 mode 40755 links 2 uid 0 gid 0 [ 3845.737826] rdev 0 sequence 1 flags 0x0 [ 3845.737827] atime 1764259517.572889464 [ 3845.737828] ctime 1764259517.572889464 [ 3845.737830] mtime 1764259517.572889464 [ 3845.737831] otime 1764259517.572889464 [ 3845.737832] item 7 key (257 INODE_REF 256) itemoff 15801 itemsize 14 [ 3845.737833] index 2 name_len 4 [ 3845.737834] item 8 key (257 INODE_REF 258) itemoff 15787 itemsize 14 [ 3845.737836] index 2 name_len 4 [ 3845.737837] item 9 key (257 DIR_ITEM 2507850652) itemoff 15754 itemsize 33 [ 3845.737838] location key (259 1 0) type 1 [ 3845.737839] transid 10 data_len 0 name_len 3 [ 3845.737840] item 10 key (257 DIR_INDEX 2) itemoff 15721 itemsize 33 [ 3845.737842] location key (259 1 0) type 1 [ 3845.737843] transid 10 data_len 0 name_len 3 [ 3845.737844] item 11 key (258 INODE_ITEM 0) itemoff 15561 itemsize 160 [ 3845.737846] inode generation 9 transid 10 size 8 nbytes 0 [ 3845.737847] block group 0 mode 40755 links 1 uid 0 gid 0 [ 3845.737848] rdev 0 sequence 1 flags 0x0 [ 3845.737849] atime 1764259517.572889464 [ 3845.737850] ctime 1764259517.572889464 [ 3845.737851] mtime 1764259517.572889464 [ 3845.737852] otime 1764259517.572889464 [ 3845.737853] item 12 key (258 INODE_REF 256) itemoff 15547 itemsize 14 [ 3845.737855] index 3 name_len 4 [ 3845.737856] item 13 key (258 DIR_ITEM 1843588421) itemoff 15513 itemsize 34 [ 3845.737857] location key (257 1 0) type 2 [ 3845.737858] transid 10 data_len 0 name_len 4 [ 3845.737860] item 14 key (258 DIR_INDEX 2) itemoff 15479 itemsize 34 [ 3845.737861] location key (257 1 0) type 2 [ 3845.737862] transid 10 data_len 0 name_len 4 [ 3845.737863] item 15 key (259 INODE_ITEM 0) itemoff 15319 itemsize 160 [ 3845.737865] inode generation 10 transid 10 size 0 nbytes 0 [ 3845.737866] block group 0 mode 100600 links 1 uid 0 gid 0 [ 3845.737867] rdev 0 sequence 2 flags 0x0 [ 3845.737868] atime 1764259517.580874966 [ 3845.737869] ctime 1764259517.586121869 [ 3845.737870] mtime 1764259517.580874966 [ 3845.737872] otime 1764259517.580874966 [ 3845.737873] item 16 key (259 INODE_REF 257) itemoff 15306 itemsize 13 [ 3845.737874] index 2 name_len 3 [ 3845.737875] BTRFS error (device dm-0): block=30408704 write time tree block corruption detected [ 3845.739448] ------------[ cut here ]------------ [ 3845.740092] WARNING: CPU: 5 PID: 30701 at fs/btrfs/disk-io.c:335 btree_csum_one_bio+0x25a/0x270 [btrfs] [ 3845.741439] Modules linked in: btrfs dm_flakey crc32c_cryptoapi (...) [ 3845.750626] CPU: 5 UID: 0 PID: 30701 Comm: mount Tainted: G W 6.18.0-rc6-btrfs-next-218+ #1 PREEMPT(full) [ 3845.752414] Tainted: [W]=WARN [ 3845.752828] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.16.2-0-gea1b7a073390-prebuilt.qemu.org 04/01/2014 [ 3845.754499] RIP: 0010:btree_csum_one_bio+0x25a/0x270 [btrfs] [ 3845.755460] Code: 31 f6 48 89 (...) [ 3845.758685] RSP: 0018:ffffa8d9c5677678 EFLAGS: 00010246 [ 3845.759450] RAX: 0000000000000000 RBX: ffff92650e6d4738 RCX: 0000000000000000 [ 3845.760309] RDX: 0000000000000000 RSI: ffffffff9aab45b9 RDI: ffff9264c4748000 [ 3845.761239] RBP: ffff9264d4324000 R08: 0000000000000000 R09: ffffa8d9c5677468 [ 3845.762607] R10: ffff926bdc1fffa8 R11: 0000000000000003 R12: ffffa8d9c5677680 [ 3845.764099] R13: 0000000000004000 R14: ffff9264dd624000 R15: ffff9264d978aba8 [ 3845.765094] FS: 00007f751fa5a840(0000) GS:ffff926c42a82000(0000) knlGS:0000000000000000 [ 3845.766226] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 3845.766970] CR2: 0000558df1815380 CR3: 000000010ed88003 CR4: 0000000000370ef0 [ 3845.768009] Call Trace: [ 3845.768392] [ 3845.768714] btrfs_submit_bbio+0x6ee/0x7f0 [btrfs] [ 3845.769640] ? write_one_eb+0x28e/0x340 [btrfs] [ 3845.770588] btree_write_cache_pages+0x2f0/0x550 [btrfs] [ 3845.771286] ? alloc_extent_state+0x19/0x100 [btrfs] [ 3845.771967] ? merge_next_state+0x1a/0x90 [btrfs] [ 3845.772586] ? set_extent_bit+0x233/0x8b0 [btrfs] [ 3845.773198] ? xas_load+0x9/0xc0 [ 3845.773589] ? xas_find+0x14d/0x1a0 [ 3845.773969] do_writepages+0xc6/0x160 [ 3845.774367] filemap_fdatawrite_wbc+0x48/0x60 [ 3845.775003] __filemap_fdatawrite_range+0x5b/0x80 [ 3845.775902] btrfs_write_marked_extents+0x61/0x170 [btrfs] [ 3845.776707] btrfs_write_and_wait_transaction+0x4e/0xc0 [btrfs] [ 3845.777379] ? _raw_spin_unlock_irqrestore+0x23/0x40 [ 3845.777923] btrfs_commit_transaction+0x5ea/0xd20 [btrfs] [ 3845.778551] ? _raw_spin_unlock+0x15/0x30 [ 3845.778986] ? release_extent_buffer+0x34/0x160 [btrfs] [ 3845.779659] btrfs_recover_log_trees+0x7a3/0x7c0 [btrfs] [ 3845.780416] ? __pfx_replay_one_buffer+0x10/0x10 [btrfs] [ 3845.781499] open_ctree+0x10bb/0x15f0 [btrfs] [ 3845.782194] btrfs_get_tree.cold+0xb/0x16c [btrfs] [ 3845.782764] ? fscontext_read+0x15c/0x180 [ 3845.783202] ? rw_verify_area+0x50/0x180 [ 3845.783667] vfs_get_tree+0x25/0xd0 [ 3845.784047] vfs_cmd_create+0x59/0xe0 [ 3845.784458] __do_sys_fsconfig+0x4f6/0x6b0 [ 3845.784914] do_syscall_64+0x50/0x1220 [ 3845.785340] entry_SYSCALL_64_after_hwframe+0x76/0x7e [ 3845.785980] RIP: 0033:0x7f751fc7f4aa [ 3845.786759] Code: 73 01 c3 48 (...) [ 3845.789951] RSP: 002b:00007ffcdba45dc8 EFLAGS: 00000246 ORIG_RAX: 00000000000001af [ 3845.791402] RAX: ffffffffffffffda RBX: 000055ccc8291c20 RCX: 00007f751fc7f4aa [ 3845.792688] RDX: 0000000000000000 RSI: 0000000000000006 RDI: 0000000000000003 [ 3845.794308] RBP: 000055ccc8292120 R08: 0000000000000000 R09: 0000000000000000 [ 3845.795829] R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000 [ 3845.797183] R13: 00007f751fe11580 R14: 00007f751fe1326c R15: 00007f751fdf8a23 [ 3845.798633] [ 3845.799067] ---[ end trace 0000000000000000 ]--- [ 3845.800215] BTRFS: error (device dm-0) in btrfs_commit_transaction:2553: errno=-5 IO failure (Error while writing out transaction) [ 3845.801860] BTRFS warning (device dm-0 state E): Skipping commit of aborted transaction. [ 3845.802815] BTRFS error (device dm-0 state EA): Transaction aborted (error -5) [ 3845.803728] BTRFS: error (device dm-0 state EA) in cleanup_transaction:2036: errno=-5 IO failure [ 3845.805374] BTRFS: error (device dm-0 state EA) in btrfs_replay_log:2083: errno=-5 IO failure (Failed to recover log tree) [ 3845.807919] BTRFS error (device dm-0 state EA): open_ctree failed: -5 Fix this by never logging a conflicting inode that is a directory and was moved in the current transaction (its last_unlink_trans equals the current transaction) and instead fallback to a transaction commit. A test case for fstests will follow soon. Reported-by: Vyacheslav Kovalevsky Link: https://lore.kernel.org/linux-btrfs/7bbc9419-5c56-450a-b5a0-efeae7457113@gmail.com/ CC: stable@vger.kernel.org # 6.1+ Signed-off-by: Filipe Manana Signed-off-by: David Sterba Signed-off-by: Greg Kroah-Hartman --- fs/btrfs/tree-log.c | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index f55d886debe2f..e0b0750696a15 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -6050,6 +6050,33 @@ static int conflicting_inode_is_dir(struct btrfs_root *root, u64 ino, return ret; } +static bool can_log_conflicting_inode(const struct btrfs_trans_handle *trans, + const struct btrfs_inode *inode) +{ + if (!S_ISDIR(inode->vfs_inode.i_mode)) + return true; + + if (inode->last_unlink_trans < trans->transid) + return true; + + /* + * If this is a directory and its unlink_trans is not from a past + * transaction then we must fallback to a transaction commit in order + * to avoid getting a directory with 2 hard links after log replay. + * + * This happens if a directory A is renamed, moved from one parent + * directory to another one, a new file is created in the old parent + * directory with the old name of our directory A, the new file is + * fsynced, then we moved the new file to some other parent directory + * and fsync again the new file. This results in a log tree where we + * logged that directory A existed, with the INODE_REF item for the + * new location but without having logged its old parent inode, so + * that on log replay we add a new link for the new location but the + * old link remains, resulting in a link count of 2. + */ + return false; +} + static int add_conflicting_inode(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, @@ -6153,6 +6180,11 @@ static int add_conflicting_inode(struct btrfs_trans_handle *trans, return 0; } + if (!can_log_conflicting_inode(trans, inode)) { + btrfs_add_delayed_iput(inode); + return BTRFS_LOG_FORCE_COMMIT; + } + btrfs_add_delayed_iput(inode); ino_elem = kmalloc(sizeof(*ino_elem), GFP_NOFS); @@ -6217,6 +6249,12 @@ static int log_conflicting_inodes(struct btrfs_trans_handle *trans, break; } + if (!can_log_conflicting_inode(trans, inode)) { + btrfs_add_delayed_iput(inode); + ret = BTRFS_LOG_FORCE_COMMIT; + break; + } + /* * Always log the directory, we cannot make this * conditional on need_log_inode() because the directory From 5fcdaa29e5992c2bb66cc93aa78337d0bc5982dc Mon Sep 17 00:00:00 2001 From: Shakeel Butt Date: Fri, 5 Dec 2025 12:01:06 -0800 Subject: [PATCH 1383/2333] cgroup: rstat: use LOCK CMPXCHG in css_rstat_updated commit 3309b63a2281efb72df7621d60cc1246b6286ad3 upstream. On x86-64, this_cpu_cmpxchg() uses CMPXCHG without LOCK prefix which means it is only safe for the local CPU and not for multiple CPUs. Recently the commit 36df6e3dbd7e ("cgroup: make css_rstat_updated nmi safe") make css_rstat_updated lockless and uses lockless list to allow reentrancy. Since css_rstat_updated can invoked from process context, IRQ and NMI, it uses this_cpu_cmpxchg() to select the winner which will inset the lockless lnode into the global per-cpu lockless list. However the commit missed one case where lockless node of a cgroup can be accessed and modified by another CPU doing the flushing. Basically llist_del_first_init() in css_process_update_tree(). On a cursory look, it can be questioned how css_process_update_tree() can see a lockless node in global lockless list where the updater is at this_cpu_cmpxchg() and before llist_add() call in css_rstat_updated(). This can indeed happen in the presence of IRQs/NMI. Consider this scenario: Updater for cgroup stat C on CPU A in process context is after llist_on_list() check and before this_cpu_cmpxchg() in css_rstat_updated() where it get interrupted by IRQ/NMI. In the IRQ/NMI context, a new updater calls css_rstat_updated() for same cgroup C and successfully inserts rstatc_pcpu->lnode. Now concurrently CPU B is running the flusher and it calls llist_del_first_init() for CPU A and got rstatc_pcpu->lnode of cgroup C which was added by the IRQ/NMI updater. Now imagine CPU B calling init_llist_node() on cgroup C's rstatc_pcpu->lnode of CPU A and on CPU A, the process context updater calling this_cpu_cmpxchg(rstatc_pcpu->lnode) concurrently. The CMPXCNG without LOCK on CPU A is not safe and thus we need LOCK prefix. In Meta's fleet running the kernel with the commit 36df6e3dbd7e, we are observing on some machines the memcg stats are getting skewed by more than the actual memory on the system. On close inspection, we noticed that lockless node for a workload for specific CPU was in the bad state and thus all the updates on that CPU for that cgroup was being lost. To confirm if this skew was indeed due to this CMPXCHG without LOCK in css_rstat_updated(), we created a repro (using AI) at [1] which shows that CMPXCHG without LOCK creates almost the same lnode corruption as seem in Meta's fleet and with LOCK CMPXCHG the issue does not reproduces. Link: http://lore.kernel.org/efiagdwmzfwpdzps74fvcwq3n4cs36q33ij7eebcpssactv3zu@se4hqiwxcfxq [1] Signed-off-by: Shakeel Butt Cc: stable@vger.kernel.org # v6.17+ Fixes: 36df6e3dbd7e ("cgroup: make css_rstat_updated nmi safe") Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- kernel/cgroup/rstat.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/kernel/cgroup/rstat.c b/kernel/cgroup/rstat.c index a198e40c799b4..150e5871e66f2 100644 --- a/kernel/cgroup/rstat.c +++ b/kernel/cgroup/rstat.c @@ -71,7 +71,6 @@ __bpf_kfunc void css_rstat_updated(struct cgroup_subsys_state *css, int cpu) { struct llist_head *lhead; struct css_rstat_cpu *rstatc; - struct css_rstat_cpu __percpu *rstatc_pcpu; struct llist_node *self; /* @@ -104,18 +103,22 @@ __bpf_kfunc void css_rstat_updated(struct cgroup_subsys_state *css, int cpu) /* * This function can be renentered by irqs and nmis for the same cgroup * and may try to insert the same per-cpu lnode into the llist. Note - * that llist_add() does not protect against such scenarios. + * that llist_add() does not protect against such scenarios. In addition + * this same per-cpu lnode can be modified through init_llist_node() + * from css_rstat_flush() running on a different CPU. * * To protect against such stacked contexts of irqs/nmis, we use the * fact that lnode points to itself when not on a list and then use - * this_cpu_cmpxchg() to atomically set to NULL to select the winner + * try_cmpxchg() to atomically set to NULL to select the winner * which will call llist_add(). The losers can assume the insertion is * successful and the winner will eventually add the per-cpu lnode to * the llist. + * + * Please note that we can not use this_cpu_cmpxchg() here as on some + * archs it is not safe against modifications from multiple CPUs. */ self = &rstatc->lnode; - rstatc_pcpu = css->rstat_cpu; - if (this_cpu_cmpxchg(rstatc_pcpu->lnode.next, self, NULL) != self) + if (!try_cmpxchg(&rstatc->lnode.next, &self, NULL)) return; lhead = ss_lhead_cpu(css->ss, cpu); From 0f5940176ad6f43b7a182612460b4df84368a09a Mon Sep 17 00:00:00 2001 From: Sven Schnelle Date: Fri, 5 Dec 2025 10:58:57 +0100 Subject: [PATCH 1384/2333] s390/ipl: Clear SBP flag when bootprog is set commit b1aa01d31249bd116b18c7f512d3e46b4b4ad83b upstream. With z16 a new flag 'search boot program' was introduced for list-directed IPL (SCSI, NVMe, ECKD DASD). If this flag is set, e.g. via selecting the "Automatic" value for the "Boot program selector" control on an HMC load panel, it is copied to the reipl structure from the initial ipl structure. When a user now sets a boot prog via sysfs, the flag is not cleared and the bootloader will again automatically select the boot program, ignoring user configuration. To avoid that, clear the SBP flag when a bootprog sysfs file is written. Cc: stable@vger.kernel.org Reviewed-by: Peter Oberparleiter Reviewed-by: Heiko Carstens Signed-off-by: Sven Schnelle Signed-off-by: Heiko Carstens Signed-off-by: Greg Kroah-Hartman --- arch/s390/include/uapi/asm/ipl.h | 1 + arch/s390/kernel/ipl.c | 48 ++++++++++++++++++++++++-------- 2 files changed, 37 insertions(+), 12 deletions(-) diff --git a/arch/s390/include/uapi/asm/ipl.h b/arch/s390/include/uapi/asm/ipl.h index 2cd28af50dd43..3d64a22516994 100644 --- a/arch/s390/include/uapi/asm/ipl.h +++ b/arch/s390/include/uapi/asm/ipl.h @@ -15,6 +15,7 @@ struct ipl_pl_hdr { #define IPL_PL_FLAG_IPLPS 0x80 #define IPL_PL_FLAG_SIPL 0x40 #define IPL_PL_FLAG_IPLSR 0x20 +#define IPL_PL_FLAG_SBP 0x10 /* IPL Parameter Block header */ struct ipl_pb_hdr { diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c index 961a3d60a4ddd..dcdc7e2748486 100644 --- a/arch/s390/kernel/ipl.c +++ b/arch/s390/kernel/ipl.c @@ -262,6 +262,24 @@ static struct kobj_attribute sys_##_prefix##_##_name##_attr = \ sys_##_prefix##_##_name##_show, \ sys_##_prefix##_##_name##_store) +#define DEFINE_IPL_ATTR_BOOTPROG_RW(_prefix, _name, _fmt_out, _fmt_in, _hdr, _value) \ + IPL_ATTR_SHOW_FN(_prefix, _name, _fmt_out, (unsigned long long) _value) \ +static ssize_t sys_##_prefix##_##_name##_store(struct kobject *kobj, \ + struct kobj_attribute *attr, \ + const char *buf, size_t len) \ +{ \ + unsigned long long value; \ + if (sscanf(buf, _fmt_in, &value) != 1) \ + return -EINVAL; \ + (_value) = value; \ + (_hdr).flags &= ~IPL_PL_FLAG_SBP; \ + return len; \ +} \ +static struct kobj_attribute sys_##_prefix##_##_name##_attr = \ + __ATTR(_name, 0644, \ + sys_##_prefix##_##_name##_show, \ + sys_##_prefix##_##_name##_store) + #define DEFINE_IPL_ATTR_STR_RW(_prefix, _name, _fmt_out, _fmt_in, _value)\ IPL_ATTR_SHOW_FN(_prefix, _name, _fmt_out, _value) \ static ssize_t sys_##_prefix##_##_name##_store(struct kobject *kobj, \ @@ -818,12 +836,13 @@ DEFINE_IPL_ATTR_RW(reipl_fcp, wwpn, "0x%016llx\n", "%llx\n", reipl_block_fcp->fcp.wwpn); DEFINE_IPL_ATTR_RW(reipl_fcp, lun, "0x%016llx\n", "%llx\n", reipl_block_fcp->fcp.lun); -DEFINE_IPL_ATTR_RW(reipl_fcp, bootprog, "%lld\n", "%lld\n", - reipl_block_fcp->fcp.bootprog); DEFINE_IPL_ATTR_RW(reipl_fcp, br_lba, "%lld\n", "%lld\n", reipl_block_fcp->fcp.br_lba); DEFINE_IPL_ATTR_RW(reipl_fcp, device, "0.0.%04llx\n", "0.0.%llx\n", reipl_block_fcp->fcp.devno); +DEFINE_IPL_ATTR_BOOTPROG_RW(reipl_fcp, bootprog, "%lld\n", "%lld\n", + reipl_block_fcp->hdr, + reipl_block_fcp->fcp.bootprog); static void reipl_get_ascii_loadparm(char *loadparm, struct ipl_parameter_block *ibp) @@ -942,10 +961,11 @@ DEFINE_IPL_ATTR_RW(reipl_nvme, fid, "0x%08llx\n", "%llx\n", reipl_block_nvme->nvme.fid); DEFINE_IPL_ATTR_RW(reipl_nvme, nsid, "0x%08llx\n", "%llx\n", reipl_block_nvme->nvme.nsid); -DEFINE_IPL_ATTR_RW(reipl_nvme, bootprog, "%lld\n", "%lld\n", - reipl_block_nvme->nvme.bootprog); DEFINE_IPL_ATTR_RW(reipl_nvme, br_lba, "%lld\n", "%lld\n", reipl_block_nvme->nvme.br_lba); +DEFINE_IPL_ATTR_BOOTPROG_RW(reipl_nvme, bootprog, "%lld\n", "%lld\n", + reipl_block_nvme->hdr, + reipl_block_nvme->nvme.bootprog); static struct attribute *reipl_nvme_attrs[] = { &sys_reipl_nvme_fid_attr.attr, @@ -1038,8 +1058,9 @@ static const struct bin_attribute *const reipl_eckd_bin_attrs[] = { }; DEFINE_IPL_CCW_ATTR_RW(reipl_eckd, device, reipl_block_eckd->eckd); -DEFINE_IPL_ATTR_RW(reipl_eckd, bootprog, "%lld\n", "%lld\n", - reipl_block_eckd->eckd.bootprog); +DEFINE_IPL_ATTR_BOOTPROG_RW(reipl_eckd, bootprog, "%lld\n", "%lld\n", + reipl_block_eckd->hdr, + reipl_block_eckd->eckd.bootprog); static struct attribute *reipl_eckd_attrs[] = { &sys_reipl_eckd_device_attr.attr, @@ -1567,12 +1588,13 @@ DEFINE_IPL_ATTR_RW(dump_fcp, wwpn, "0x%016llx\n", "%llx\n", dump_block_fcp->fcp.wwpn); DEFINE_IPL_ATTR_RW(dump_fcp, lun, "0x%016llx\n", "%llx\n", dump_block_fcp->fcp.lun); -DEFINE_IPL_ATTR_RW(dump_fcp, bootprog, "%lld\n", "%lld\n", - dump_block_fcp->fcp.bootprog); DEFINE_IPL_ATTR_RW(dump_fcp, br_lba, "%lld\n", "%lld\n", dump_block_fcp->fcp.br_lba); DEFINE_IPL_ATTR_RW(dump_fcp, device, "0.0.%04llx\n", "0.0.%llx\n", dump_block_fcp->fcp.devno); +DEFINE_IPL_ATTR_BOOTPROG_RW(dump_fcp, bootprog, "%lld\n", "%lld\n", + dump_block_fcp->hdr, + dump_block_fcp->fcp.bootprog); DEFINE_IPL_ATTR_SCP_DATA_RW(dump_fcp, dump_block_fcp->hdr, dump_block_fcp->fcp, @@ -1604,10 +1626,11 @@ DEFINE_IPL_ATTR_RW(dump_nvme, fid, "0x%08llx\n", "%llx\n", dump_block_nvme->nvme.fid); DEFINE_IPL_ATTR_RW(dump_nvme, nsid, "0x%08llx\n", "%llx\n", dump_block_nvme->nvme.nsid); -DEFINE_IPL_ATTR_RW(dump_nvme, bootprog, "%lld\n", "%llx\n", - dump_block_nvme->nvme.bootprog); DEFINE_IPL_ATTR_RW(dump_nvme, br_lba, "%lld\n", "%llx\n", dump_block_nvme->nvme.br_lba); +DEFINE_IPL_ATTR_BOOTPROG_RW(dump_nvme, bootprog, "%lld\n", "%llx\n", + dump_block_nvme->hdr, + dump_block_nvme->nvme.bootprog); DEFINE_IPL_ATTR_SCP_DATA_RW(dump_nvme, dump_block_nvme->hdr, dump_block_nvme->nvme, @@ -1635,8 +1658,9 @@ static const struct attribute_group dump_nvme_attr_group = { /* ECKD dump device attributes */ DEFINE_IPL_CCW_ATTR_RW(dump_eckd, device, dump_block_eckd->eckd); -DEFINE_IPL_ATTR_RW(dump_eckd, bootprog, "%lld\n", "%llx\n", - dump_block_eckd->eckd.bootprog); +DEFINE_IPL_ATTR_BOOTPROG_RW(dump_eckd, bootprog, "%lld\n", "%llx\n", + dump_block_eckd->hdr, + dump_block_eckd->eckd.bootprog); IPL_ATTR_BR_CHR_SHOW_FN(dump, dump_block_eckd->eckd); IPL_ATTR_BR_CHR_STORE_FN(dump, dump_block_eckd->eckd); From efdcbc1b10354661178305a07c6a9f8872ff31a9 Mon Sep 17 00:00:00 2001 From: Wentao Guan Date: Thu, 4 Dec 2025 18:13:04 +0800 Subject: [PATCH 1385/2333] gpio: regmap: Fix memleak in error path in gpio_regmap_register() commit 52721cfc78c76b09c66e092b52617006390ae96a upstream. Call gpiochip_remove() to free the resources allocated by gpiochip_add_data() in error path. Fixes: 553b75d4bfe9 ("gpio: regmap: Allow to allocate regmap-irq device") Fixes: ae495810cffe ("gpio: regmap: add the .fixed_direction_output configuration parameter") CC: stable@vger.kernel.org Co-developed-by: WangYuli Signed-off-by: WangYuli Signed-off-by: Wentao Guan Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20251204101303.30353-1-guanwentao@uniontech.com [Bartosz: reworked the commit message] Signed-off-by: Bartosz Golaszewski Signed-off-by: Greg Kroah-Hartman --- drivers/gpio/gpio-regmap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-regmap.c b/drivers/gpio/gpio-regmap.c index f4267af00027e..c64805dcb9f88 100644 --- a/drivers/gpio/gpio-regmap.c +++ b/drivers/gpio/gpio-regmap.c @@ -328,7 +328,7 @@ struct gpio_regmap *gpio_regmap_register(const struct gpio_regmap_config *config config->regmap_irq_line, config->regmap_irq_flags, 0, config->regmap_irq_chip, &gpio->irq_chip_data); if (ret) - goto err_free_bitmap; + goto err_remove_gpiochip; irq_domain = regmap_irq_get_domain(gpio->irq_chip_data); } else From 5f8dc9f0327e8cc3ca508bf99223b88f4773b669 Mon Sep 17 00:00:00 2001 From: Askar Safin Date: Sat, 6 Dec 2025 18:04:13 +0000 Subject: [PATCH 1386/2333] gpiolib: acpi: Add quirk for Dell Precision 7780 commit 2d967310c49ed93ac11cef408a55ddf15c3dd52e upstream. Dell Precision 7780 often wakes up on its own from suspend. Sometimes wake up happens immediately (i. e. within 7 seconds), sometimes it happens after, say, 30 minutes. Fixes: 1796f808e4bb ("HID: i2c-hid: acpi: Stop setting wakeup_capable") Link: https://lore.kernel.org/linux-i2c/197ae95ffd8.dc819e60457077.7692120488609091556@zohomail.com/ Cc: stable@vger.kernel.org Reviewed-by: Andy Shevchenko Signed-off-by: Askar Safin Link: https://lore.kernel.org/r/20251206180414.3183334-2-safinaskar@gmail.com Signed-off-by: Bartosz Golaszewski Signed-off-by: Greg Kroah-Hartman --- drivers/gpio/gpiolib-acpi-quirks.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/drivers/gpio/gpiolib-acpi-quirks.c b/drivers/gpio/gpiolib-acpi-quirks.c index 7b95d1b033614..a0116f004975a 100644 --- a/drivers/gpio/gpiolib-acpi-quirks.c +++ b/drivers/gpio/gpiolib-acpi-quirks.c @@ -370,6 +370,28 @@ static const struct dmi_system_id gpiolib_acpi_quirks[] __initconst = { .ignore_wake = "ASCP1A00:00@8", }, }, + { + /* + * Spurious wakeups, likely from touchpad controller + * Dell Precision 7780 + * Found in BIOS 1.24.1 + * + * Found in touchpad firmware, installed by Dell Touchpad Firmware Update Utility version 1160.4196.9, A01 + * ( Dell-Touchpad-Firmware-Update-Utility_VYGNN_WIN64_1160.4196.9_A00.EXE ), + * released on 11 Jul 2024 + * + * https://lore.kernel.org/linux-i2c/197ae95ffd8.dc819e60457077.7692120488609091556@zohomail.com/ + */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_FAMILY, "Precision"), + DMI_MATCH(DMI_PRODUCT_NAME, "Precision 7780"), + DMI_MATCH(DMI_BOARD_NAME, "0C6JVW"), + }, + .driver_data = &(struct acpi_gpiolib_dmi_quirk) { + .ignore_wake = "VEN_0488:00@355", + }, + }, {} /* Terminating entry */ }; From acb3a68f2170e8c7b5c1461d999a333c21a5dba9 Mon Sep 17 00:00:00 2001 From: Xi Ruoyao Date: Fri, 28 Nov 2025 15:50:32 +0800 Subject: [PATCH 1387/2333] gpio: loongson: Switch 2K2000/3000 GPIO to BYTE_CTRL_MODE commit dae9750105cf93ac1e156ef91f4beeb53bd64777 upstream. The manuals of 2K2000 says both BIT_CTRL_MODE and BYTE_CTRL_MODE are supported but the latter is recommended. Also on 2K3000, per the ACPI DSDT the GPIO controller is compatible with 2K2000, but it fails to operate GPIOs 62 and 63 (and maybe others) using BIT_CTRL_MODE. Using BYTE_CTRL_MODE also makes those 2K3000 GPIOs work. Fixes: 3feb70a61740 ("gpio: loongson: add more gpio chip support") Cc: stable@vger.kernel.org Signed-off-by: Xi Ruoyao Reviewed-by: Huacai Chen Link: https://lore.kernel.org/r/20251128075033.255821-1-xry111@xry111.site Signed-off-by: Bartosz Golaszewski Signed-off-by: Greg Kroah-Hartman --- drivers/gpio/gpio-loongson-64bit.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpio/gpio-loongson-64bit.c b/drivers/gpio/gpio-loongson-64bit.c index 02f181cb219e9..82d4c3aa4d2fc 100644 --- a/drivers/gpio/gpio-loongson-64bit.c +++ b/drivers/gpio/gpio-loongson-64bit.c @@ -407,11 +407,11 @@ static const struct loongson_gpio_chip_data loongson_gpio_ls2k2000_data0 = { static const struct loongson_gpio_chip_data loongson_gpio_ls2k2000_data1 = { .label = "ls2k2000_gpio", - .mode = BIT_CTRL_MODE, - .conf_offset = 0x0, - .in_offset = 0x20, - .out_offset = 0x10, - .inten_offset = 0x30, + .mode = BYTE_CTRL_MODE, + .conf_offset = 0x800, + .in_offset = 0xa00, + .out_offset = 0x900, + .inten_offset = 0xb00, }; static const struct loongson_gpio_chip_data loongson_gpio_ls2k2000_data2 = { From 9837f8d57a54984e7516c7faeac4049f599f3942 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Tue, 9 Dec 2025 11:14:47 -0600 Subject: [PATCH 1388/2333] Revert "drm/amd/display: Fix pbn to kbps Conversion" commit 72e24456a54fe04710d89626cc5a88703e2f6202 upstream. Deeply daisy chained DP/MST displays are no longer able to light up. This reverts commit e0dec00f3d05 ("drm/amd/display: Fix pbn to kbps Conversion") Cc: Jerry Zuo Reported-by: nat@nullable.se Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/4756 Signed-off-by: Mario Limonciello Acked-by: Alex Deucher Signed-off-by: Alex Deucher (cherry picked from commit e1c94109c76e8a77a21531bd53f6c63356c81158) Cc: stable@vger.kernel.org # 6.17+ Signed-off-by: Greg Kroah-Hartman --- .../display/amdgpu_dm/amdgpu_dm_mst_types.c | 59 +++++++++++-------- 1 file changed, 36 insertions(+), 23 deletions(-) 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 dbd1da4d85d32..5e92eaa67aa33 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 @@ -884,28 +884,26 @@ struct dsc_mst_fairness_params { }; #if defined(CONFIG_DRM_AMD_DC_FP) -static uint64_t kbps_to_pbn(int kbps, bool is_peak_pbn) +static uint16_t get_fec_overhead_multiplier(struct dc_link *dc_link) { - uint64_t effective_kbps = (uint64_t)kbps; + u8 link_coding_cap; + uint16_t fec_overhead_multiplier_x1000 = PBN_FEC_OVERHEAD_MULTIPLIER_8B_10B; - if (is_peak_pbn) { // add 0.6% (1006/1000) overhead into effective kbps - effective_kbps *= 1006; - effective_kbps = div_u64(effective_kbps, 1000); - } + link_coding_cap = dc_link_dp_mst_decide_link_encoding_format(dc_link); + if (link_coding_cap == DP_128b_132b_ENCODING) + fec_overhead_multiplier_x1000 = PBN_FEC_OVERHEAD_MULTIPLIER_128B_132B; - return (uint64_t) DIV64_U64_ROUND_UP(effective_kbps * 64, (54 * 8 * 1000)); + return fec_overhead_multiplier_x1000; } -static uint32_t pbn_to_kbps(unsigned int pbn, bool with_margin) +static int kbps_to_peak_pbn(int kbps, uint16_t fec_overhead_multiplier_x1000) { - uint64_t pbn_effective = (uint64_t)pbn; - - if (with_margin) // deduct 0.6% (994/1000) overhead from effective pbn - pbn_effective *= (1000000 / PEAK_FACTOR_X1000); - else - pbn_effective *= 1000; + u64 peak_kbps = kbps; - return DIV_U64_ROUND_UP(pbn_effective * 8 * 54, 64); + peak_kbps *= 1006; + peak_kbps *= fec_overhead_multiplier_x1000; + peak_kbps = div_u64(peak_kbps, 1000 * 1000); + return (int) DIV64_U64_ROUND_UP(peak_kbps * 64, (54 * 8 * 1000)); } static void set_dsc_configs_from_fairness_vars(struct dsc_mst_fairness_params *params, @@ -976,7 +974,7 @@ static int bpp_x16_from_pbn(struct dsc_mst_fairness_params param, int pbn) dc_dsc_get_default_config_option(param.sink->ctx->dc, &dsc_options); dsc_options.max_target_bpp_limit_override_x16 = drm_connector->display_info.max_dsc_bpp * 16; - kbps = pbn_to_kbps(pbn, false); + kbps = div_u64((u64)pbn * 994 * 8 * 54, 64); dc_dsc_compute_config( param.sink->ctx->dc->res_pool->dscs[0], ¶m.sink->dsc_caps.dsc_dec_caps, @@ -1005,11 +1003,12 @@ static int increase_dsc_bpp(struct drm_atomic_state *state, int link_timeslots_used; int fair_pbn_alloc; int ret = 0; + uint16_t fec_overhead_multiplier_x1000 = get_fec_overhead_multiplier(dc_link); for (i = 0; i < count; i++) { if (vars[i + k].dsc_enabled) { initial_slack[i] = - kbps_to_pbn(params[i].bw_range.max_kbps, false) - vars[i + k].pbn; + kbps_to_peak_pbn(params[i].bw_range.max_kbps, fec_overhead_multiplier_x1000) - vars[i + k].pbn; bpp_increased[i] = false; remaining_to_increase += 1; } else { @@ -1105,6 +1104,7 @@ static int try_disable_dsc(struct drm_atomic_state *state, int next_index; int remaining_to_try = 0; int ret; + uint16_t fec_overhead_multiplier_x1000 = get_fec_overhead_multiplier(dc_link); int var_pbn; for (i = 0; i < count; i++) { @@ -1137,7 +1137,7 @@ static int try_disable_dsc(struct drm_atomic_state *state, DRM_DEBUG_DRIVER("MST_DSC index #%d, try no compression\n", next_index); var_pbn = vars[next_index].pbn; - vars[next_index].pbn = kbps_to_pbn(params[next_index].bw_range.stream_kbps, true); + vars[next_index].pbn = kbps_to_peak_pbn(params[next_index].bw_range.stream_kbps, fec_overhead_multiplier_x1000); ret = drm_dp_atomic_find_time_slots(state, params[next_index].port->mgr, params[next_index].port, @@ -1197,6 +1197,7 @@ static int compute_mst_dsc_configs_for_link(struct drm_atomic_state *state, int count = 0; int i, k, ret; bool debugfs_overwrite = false; + uint16_t fec_overhead_multiplier_x1000 = get_fec_overhead_multiplier(dc_link); struct drm_connector_state *new_conn_state; memset(params, 0, sizeof(params)); @@ -1277,7 +1278,7 @@ static int compute_mst_dsc_configs_for_link(struct drm_atomic_state *state, DRM_DEBUG_DRIVER("MST_DSC Try no compression\n"); for (i = 0; i < count; i++) { vars[i + k].aconnector = params[i].aconnector; - vars[i + k].pbn = kbps_to_pbn(params[i].bw_range.stream_kbps, false); + vars[i + k].pbn = kbps_to_peak_pbn(params[i].bw_range.stream_kbps, fec_overhead_multiplier_x1000); vars[i + k].dsc_enabled = false; vars[i + k].bpp_x16 = 0; ret = drm_dp_atomic_find_time_slots(state, params[i].port->mgr, params[i].port, @@ -1299,7 +1300,7 @@ static int compute_mst_dsc_configs_for_link(struct drm_atomic_state *state, DRM_DEBUG_DRIVER("MST_DSC Try max compression\n"); for (i = 0; i < count; i++) { if (params[i].compression_possible && params[i].clock_force_enable != DSC_CLK_FORCE_DISABLE) { - vars[i + k].pbn = kbps_to_pbn(params[i].bw_range.min_kbps, false); + vars[i + k].pbn = kbps_to_peak_pbn(params[i].bw_range.min_kbps, fec_overhead_multiplier_x1000); vars[i + k].dsc_enabled = true; vars[i + k].bpp_x16 = params[i].bw_range.min_target_bpp_x16; ret = drm_dp_atomic_find_time_slots(state, params[i].port->mgr, @@ -1307,7 +1308,7 @@ static int compute_mst_dsc_configs_for_link(struct drm_atomic_state *state, if (ret < 0) return ret; } else { - vars[i + k].pbn = kbps_to_pbn(params[i].bw_range.stream_kbps, false); + vars[i + k].pbn = kbps_to_peak_pbn(params[i].bw_range.stream_kbps, fec_overhead_multiplier_x1000); vars[i + k].dsc_enabled = false; vars[i + k].bpp_x16 = 0; ret = drm_dp_atomic_find_time_slots(state, params[i].port->mgr, @@ -1762,6 +1763,18 @@ int pre_validate_dsc(struct drm_atomic_state *state, return ret; } +static uint32_t kbps_from_pbn(unsigned int pbn) +{ + uint64_t kbps = (uint64_t)pbn; + + kbps *= (1000000 / PEAK_FACTOR_X1000); + kbps *= 8; + kbps *= 54; + kbps /= 64; + + return (uint32_t)kbps; +} + static bool is_dsc_common_config_possible(struct dc_stream_state *stream, struct dc_dsc_bw_range *bw_range) { @@ -1860,7 +1873,7 @@ enum dc_status dm_dp_mst_is_port_support_mode( dc_link_get_highest_encoding_format(stream->link)); cur_link_settings = stream->link->verified_link_cap; root_link_bw_in_kbps = dc_link_bandwidth_kbps(aconnector->dc_link, &cur_link_settings); - virtual_channel_bw_in_kbps = pbn_to_kbps(aconnector->mst_output_port->full_pbn, true); + virtual_channel_bw_in_kbps = kbps_from_pbn(aconnector->mst_output_port->full_pbn); /* pick the end to end bw bottleneck */ end_to_end_bw_in_kbps = min(root_link_bw_in_kbps, virtual_channel_bw_in_kbps); @@ -1913,7 +1926,7 @@ enum dc_status dm_dp_mst_is_port_support_mode( immediate_upstream_port = aconnector->mst_output_port->parent->port_parent; if (immediate_upstream_port) { - virtual_channel_bw_in_kbps = pbn_to_kbps(immediate_upstream_port->full_pbn, true); + virtual_channel_bw_in_kbps = kbps_from_pbn(immediate_upstream_port->full_pbn); virtual_channel_bw_in_kbps = min(root_link_bw_in_kbps, virtual_channel_bw_in_kbps); } else { /* For topology LCT 1 case - only one mstb*/ From ede98c3943cd6141b6657e23b03a5ca838d3e8e4 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 11 Nov 2025 11:17:22 -0500 Subject: [PATCH 1389/2333] drm/amd/display: Use GFP_ATOMIC in dc_create_plane_state() commit 3c41114dcdabb7b25f5bc33273c6db9c7af7f4a7 upstream. This can get called from an atomic context. Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/4470 Reviewed-by: Harry Wentland Signed-off-by: Alex Deucher (cherry picked from commit 8acdad9344cc7b4e7bc01f0dfea80093eb3768db) Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/amd/display/dc/core/dc_surface.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_surface.c b/drivers/gpu/drm/amd/display/dc/core/dc_surface.c index 922f23557f5d9..0971dfa258454 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_surface.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_surface.c @@ -86,7 +86,7 @@ uint8_t dc_plane_get_pipe_mask(struct dc_state *dc_state, const struct dc_plane struct dc_plane_state *dc_create_plane_state(const struct dc *dc) { struct dc_plane_state *plane_state = kvzalloc(sizeof(*plane_state), - GFP_KERNEL); + GFP_ATOMIC); if (NULL == plane_state) return NULL; From 7d5df9dd6343964e831847a0c18ea55a393bb2e3 Mon Sep 17 00:00:00 2001 From: Ray Wu Date: Fri, 28 Nov 2025 08:58:13 +0800 Subject: [PATCH 1390/2333] drm/amd/display: Fix scratch registers offsets for DCN35 commit 69741d9ccc7222e6b6f138db67b012ecc0d72542 upstream. [Why] Different platforms use differnet NBIO header files, causing display code to use differnt offset and read wrong accelerated status. [How] - Unified NBIO offset header file across platform. - Correct scratch registers offsets to proper locations. Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/4667 Cc: Mario Limonciello Cc: Alex Deucher Reviewed-by: Mario Limonciello Signed-off-by: Ray Wu Signed-off-by: Chenyu Chen Tested-by: Daniel Wheeler Signed-off-by: Alex Deucher (cherry picked from commit 49a63bc8eda0304ba307f5ba68305f936174f72d) Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- .../drm/amd/display/dc/resource/dcn35/dcn35_resource.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c index fff57f23f4f7a..06bec7dcc7556 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c @@ -203,12 +203,12 @@ enum dcn35_clk_src_array_id { NBIO_BASE_INNER(seg) #define NBIO_SR(reg_name)\ - REG_STRUCT.reg_name = NBIO_BASE(regBIF_BX2_ ## reg_name ## _BASE_IDX) + \ - regBIF_BX2_ ## reg_name + REG_STRUCT.reg_name = NBIO_BASE(regBIF_BX1_ ## reg_name ## _BASE_IDX) + \ + regBIF_BX1_ ## reg_name #define NBIO_SR_ARR(reg_name, id)\ - REG_STRUCT[id].reg_name = NBIO_BASE(regBIF_BX2_ ## reg_name ## _BASE_IDX) + \ - regBIF_BX2_ ## reg_name + REG_STRUCT[id].reg_name = NBIO_BASE(regBIF_BX1_ ## reg_name ## _BASE_IDX) + \ + regBIF_BX1_ ## reg_name #define bios_regs_init() \ ( \ From f9e805fa1fe8443af0d64a31e039554f3f0cbe5c Mon Sep 17 00:00:00 2001 From: Ray Wu Date: Fri, 28 Nov 2025 09:14:09 +0800 Subject: [PATCH 1391/2333] drm/amd/display: Fix scratch registers offsets for DCN351 commit fd62aa13d3ee0f21c756a40a7c2f900f98992d6a upstream. [Why] Different platforms use different NBIO header files, causing display code to use differnt offset and read wrong accelerated status. [How] - Unified NBIO offset header file across platform. - Correct scratch registers offsets to proper locations. Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/4667 Cc: Mario Limonciello Cc: Alex Deucher Reviewed-by: Mario Limonciello Signed-off-by: Ray Wu Signed-off-by: Chenyu Chen Tested-by: Daniel Wheeler Signed-off-by: Alex Deucher (cherry picked from commit 576e032e909c8a6bb3d907b4ef5f6abe0f644199) Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- .../drm/amd/display/dc/resource/dcn351/dcn351_resource.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn351/dcn351_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn351/dcn351_resource.c index 0abd163b425e5..7974e306126e0 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn351/dcn351_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn351/dcn351_resource.c @@ -183,12 +183,12 @@ enum dcn351_clk_src_array_id { NBIO_BASE_INNER(seg) #define NBIO_SR(reg_name)\ - REG_STRUCT.reg_name = NBIO_BASE(regBIF_BX2_ ## reg_name ## _BASE_IDX) + \ - regBIF_BX2_ ## reg_name + REG_STRUCT.reg_name = NBIO_BASE(regBIF_BX1_ ## reg_name ## _BASE_IDX) + \ + regBIF_BX1_ ## reg_name #define NBIO_SR_ARR(reg_name, id)\ - REG_STRUCT[id].reg_name = NBIO_BASE(regBIF_BX2_ ## reg_name ## _BASE_IDX) + \ - regBIF_BX2_ ## reg_name + REG_STRUCT[id].reg_name = NBIO_BASE(regBIF_BX1_ ## reg_name ## _BASE_IDX) + \ + regBIF_BX1_ ## reg_name #define bios_regs_init() \ ( \ From 149b97dc329533b20172cb7bc3f40c073d414801 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 28 Oct 2025 22:07:25 +0200 Subject: [PATCH 1392/2333] drm/displayid: pass iter to drm_find_displayid_extension() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 520f37c30992fd0c212a34fbe99c062b7a3dc52e upstream. It's more convenient to pass iter than a handful of its members to drm_find_displayid_extension(), especially as we're about to add another member. Rename the function find_next_displayid_extension() while at it, to be more descriptive. Cc: Tiago Martins Araújo Acked-by: Alex Deucher Tested-by: Tiago Martins Araújo Cc: stable@vger.kernel.org Link: https://patch.msgid.link/3837ae7f095e77a082ac2422ce2fac96c4f9373d.1761681968.git.jani.nikula@intel.com Signed-off-by: Jani Nikula Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/drm_displayid.c | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/drm_displayid.c b/drivers/gpu/drm/drm_displayid.c index b4fd43783c509..20b453d2b8547 100644 --- a/drivers/gpu/drm/drm_displayid.c +++ b/drivers/gpu/drm/drm_displayid.c @@ -48,26 +48,24 @@ validate_displayid(const u8 *displayid, int length, int idx) return base; } -static const u8 *drm_find_displayid_extension(const struct drm_edid *drm_edid, - int *length, int *idx, - int *ext_index) +static const u8 *find_next_displayid_extension(struct displayid_iter *iter) { const struct displayid_header *base; const u8 *displayid; - displayid = drm_edid_find_extension(drm_edid, DISPLAYID_EXT, ext_index); + displayid = drm_edid_find_extension(iter->drm_edid, DISPLAYID_EXT, &iter->ext_index); if (!displayid) return NULL; /* EDID extensions block checksum isn't for us */ - *length = EDID_LENGTH - 1; - *idx = 1; + iter->length = EDID_LENGTH - 1; + iter->idx = 1; - base = validate_displayid(displayid, *length, *idx); + base = validate_displayid(displayid, iter->length, iter->idx); if (IS_ERR(base)) return NULL; - *length = *idx + sizeof(*base) + base->bytes; + iter->length = iter->idx + sizeof(*base) + base->bytes; return displayid; } @@ -126,10 +124,7 @@ __displayid_iter_next(struct displayid_iter *iter) /* The first section we encounter is the base section */ bool base_section = !iter->section; - iter->section = drm_find_displayid_extension(iter->drm_edid, - &iter->length, - &iter->idx, - &iter->ext_index); + iter->section = find_next_displayid_extension(iter); if (!iter->section) { iter->drm_edid = NULL; return NULL; From 37f52c4554f3e97fdc096b21c5a3cd67fe6575ee Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 30 Oct 2025 09:50:45 +0100 Subject: [PATCH 1393/2333] dt-bindings: PCI: qcom,pcie-sc7280: Add missing required power-domains and resets commit ef99c2efeacac7758cc8c2d00e3200100a4da16c upstream. Commit 756485bfbb85 ("dt-bindings: PCI: qcom,pcie-sc7280: Move SC7280 to dedicated schema") move the device schema to separate file, but it missed a "if:not:...then:" clause in the original binding which was requiring power-domains and resets for this particular chip. Fixes: 756485bfbb85 ("dt-bindings: PCI: qcom,pcie-sc7280: Move SC7280 to dedicated schema") Signed-off-by: Krzysztof Kozlowski Signed-off-by: Manivannan Sadhasivam Reviewed-by: Rob Herring (Arm) Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20251030-dt-bindings-pci-qcom-fixes-power-domains-v2-2-28c1f11599fe@linaro.org Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/pci/qcom,pcie-sc7280.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Documentation/devicetree/bindings/pci/qcom,pcie-sc7280.yaml b/Documentation/devicetree/bindings/pci/qcom,pcie-sc7280.yaml index 4d0a915566030..f760807b5feb6 100644 --- a/Documentation/devicetree/bindings/pci/qcom,pcie-sc7280.yaml +++ b/Documentation/devicetree/bindings/pci/qcom,pcie-sc7280.yaml @@ -76,6 +76,11 @@ properties: items: - const: pci +required: + - power-domains + - resets + - reset-names + allOf: - $ref: qcom,pcie-common.yaml# From c3823d1243d3c6c5e4cf5813622d553a9aa60cb7 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 30 Oct 2025 09:50:46 +0100 Subject: [PATCH 1394/2333] dt-bindings: PCI: qcom,pcie-sc8280xp: Add missing required power-domains and resets commit ea551601404d286813aef6819ddf0bf1d7d69a24 upstream. Commit c007a5505504 ("dt-bindings: PCI: qcom,pcie-sc8280xp: Move SC8280XP to dedicated schema") move the device schema to separate file, but it missed a "if:not:...then:" clause in the original binding which was requiring power-domains and resets for this particular chip. Fixes: c007a5505504 ("dt-bindings: PCI: qcom,pcie-sc8280xp: Move SC8280XP to dedicated schema") Signed-off-by: Krzysztof Kozlowski Signed-off-by: Manivannan Sadhasivam Reviewed-by: Rob Herring (Arm) Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20251030-dt-bindings-pci-qcom-fixes-power-domains-v2-3-28c1f11599fe@linaro.org Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/pci/qcom,pcie-sc8280xp.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/pci/qcom,pcie-sc8280xp.yaml b/Documentation/devicetree/bindings/pci/qcom,pcie-sc8280xp.yaml index 15ba2385eb73c..b6fb0e37cec59 100644 --- a/Documentation/devicetree/bindings/pci/qcom,pcie-sc8280xp.yaml +++ b/Documentation/devicetree/bindings/pci/qcom,pcie-sc8280xp.yaml @@ -61,6 +61,9 @@ properties: required: - interconnects - interconnect-names + - power-domains + - resets + - reset-names allOf: - $ref: qcom,pcie-common.yaml# From f3510ba5e2652d98209ce00233df1d14e7e7e3b5 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 30 Oct 2025 09:50:47 +0100 Subject: [PATCH 1395/2333] dt-bindings: PCI: qcom,pcie-sm8150: Add missing required power-domains and resets commit 31cb432b62fb796e0c1084542ba39311d2f716d5 upstream. Commit 51bc04d5b49d ("dt-bindings: PCI: qcom,pcie-sm8150: Move SM8150 to dedicated schema") move the device schema to separate file, but it missed a "if:not:...then:" clause in the original binding which was requiring power-domains and resets for this particular chip. Fixes: 51bc04d5b49d ("dt-bindings: PCI: qcom,pcie-sm8150: Move SM8150 to dedicated schema") Signed-off-by: Krzysztof Kozlowski Signed-off-by: Manivannan Sadhasivam Reviewed-by: Rob Herring (Arm) Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20251030-dt-bindings-pci-qcom-fixes-power-domains-v2-4-28c1f11599fe@linaro.org Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/pci/qcom,pcie-sm8150.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Documentation/devicetree/bindings/pci/qcom,pcie-sm8150.yaml b/Documentation/devicetree/bindings/pci/qcom,pcie-sm8150.yaml index 26b247a41785f..17c0d58af37c6 100644 --- a/Documentation/devicetree/bindings/pci/qcom,pcie-sm8150.yaml +++ b/Documentation/devicetree/bindings/pci/qcom,pcie-sm8150.yaml @@ -74,6 +74,11 @@ properties: items: - const: pci +required: + - power-domains + - resets + - reset-names + allOf: - $ref: qcom,pcie-common.yaml# From 4eee447b5bd43871097cc8c2727dd0896459da75 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 30 Oct 2025 09:50:48 +0100 Subject: [PATCH 1396/2333] dt-bindings: PCI: qcom,pcie-sm8250: Add missing required power-domains and resets commit 2620c6bcd8c141b79ff2afe95dc814dfab644f63 upstream. Commit 4891b66185c1 ("dt-bindings: PCI: qcom,pcie-sm8250: Move SM8250 to dedicated schema") move the device schema to separate file, but it missed a "if:not:...then:" clause in the original binding which was requiring power-domains and resets for this particular chip. Fixes: 4891b66185c1 ("dt-bindings: PCI: qcom,pcie-sm8250: Move SM8250 to dedicated schema") Signed-off-by: Krzysztof Kozlowski Signed-off-by: Manivannan Sadhasivam Reviewed-by: Rob Herring (Arm) Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20251030-dt-bindings-pci-qcom-fixes-power-domains-v2-5-28c1f11599fe@linaro.org Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/pci/qcom,pcie-sm8250.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Documentation/devicetree/bindings/pci/qcom,pcie-sm8250.yaml b/Documentation/devicetree/bindings/pci/qcom,pcie-sm8250.yaml index af4dae68d5087..591f1a1eddde1 100644 --- a/Documentation/devicetree/bindings/pci/qcom,pcie-sm8250.yaml +++ b/Documentation/devicetree/bindings/pci/qcom,pcie-sm8250.yaml @@ -83,6 +83,11 @@ properties: items: - const: pci +required: + - power-domains + - resets + - reset-names + allOf: - $ref: qcom,pcie-common.yaml# From d06674a1ca79cc5e8d273bf9f772252f9046e598 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 30 Oct 2025 09:50:49 +0100 Subject: [PATCH 1397/2333] dt-bindings: PCI: qcom,pcie-sm8350: Add missing required power-domains and resets commit 012ba0d5f02e1f192eda263b5f9f826e47d607bb upstream. Commit 2278b8b54773 ("dt-bindings: PCI: qcom,pcie-sm8350: Move SM8350 to dedicated schema") move the device schema to separate file, but it missed a "if:not:...then:" clause in the original binding which was requiring power-domains and resets for this particular chip. Fixes: 2278b8b54773 ("dt-bindings: PCI: qcom,pcie-sm8350: Move SM8350 to dedicated schema") Signed-off-by: Krzysztof Kozlowski Signed-off-by: Manivannan Sadhasivam Reviewed-by: Rob Herring (Arm) Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20251030-dt-bindings-pci-qcom-fixes-power-domains-v2-6-28c1f11599fe@linaro.org Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/pci/qcom,pcie-sm8350.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Documentation/devicetree/bindings/pci/qcom,pcie-sm8350.yaml b/Documentation/devicetree/bindings/pci/qcom,pcie-sm8350.yaml index dde3079adbb33..299473af51d19 100644 --- a/Documentation/devicetree/bindings/pci/qcom,pcie-sm8350.yaml +++ b/Documentation/devicetree/bindings/pci/qcom,pcie-sm8350.yaml @@ -73,6 +73,11 @@ properties: items: - const: pci +required: + - power-domains + - resets + - reset-names + allOf: - $ref: qcom,pcie-common.yaml# From 1bff3e35ed44d36462dc5fab595a85391e6513d0 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 30 Oct 2025 09:50:50 +0100 Subject: [PATCH 1398/2333] dt-bindings: PCI: qcom,pcie-sm8450: Add missing required power-domains and resets commit 667facc4000c49a7c280097ef6638f133bcb1e59 upstream. Commit 88c9b3af4e31 ("dt-bindings: PCI: qcom,pcie-sm8450: Move SM8450 to dedicated schema") move the device schema to separate file, but it missed a "if:not:...then:" clause in the original binding which was requiring power-domains and resets for this particular chip. Fixes: 88c9b3af4e31 ("dt-bindings: PCI: qcom,pcie-sm8450: Move SM8450 to dedicated schema") Signed-off-by: Krzysztof Kozlowski Signed-off-by: Manivannan Sadhasivam Reviewed-by: Rob Herring (Arm) Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20251030-dt-bindings-pci-qcom-fixes-power-domains-v2-7-28c1f11599fe@linaro.org Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/pci/qcom,pcie-sm8450.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Documentation/devicetree/bindings/pci/qcom,pcie-sm8450.yaml b/Documentation/devicetree/bindings/pci/qcom,pcie-sm8450.yaml index 6e0a6d8f0ed07..6a17d753122c6 100644 --- a/Documentation/devicetree/bindings/pci/qcom,pcie-sm8450.yaml +++ b/Documentation/devicetree/bindings/pci/qcom,pcie-sm8450.yaml @@ -77,6 +77,11 @@ properties: items: - const: pci +required: + - power-domains + - resets + - reset-names + allOf: - $ref: qcom,pcie-common.yaml# From c549b9e0b87730ea2ed2cc7cfc74f786adb8ae03 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 30 Oct 2025 09:50:51 +0100 Subject: [PATCH 1399/2333] dt-bindings: PCI: qcom,pcie-sm8550: Add missing required power-domains and resets commit e60c6f34b9f3a83f96006243c0ef96c134520257 upstream. Commit b8d3404058a6 ("dt-bindings: PCI: qcom,pcie-sm8550: Move SM8550 to dedicated schema") move the device schema to separate file, but it missed a "if:not:...then:" clause in the original binding which was requiring power-domains and resets for this particular chip. Fixes: b8d3404058a6 ("dt-bindings: PCI: qcom,pcie-sm8550: Move SM8550 to dedicated schema") Signed-off-by: Krzysztof Kozlowski Signed-off-by: Manivannan Sadhasivam Reviewed-by: Rob Herring (Arm) Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20251030-dt-bindings-pci-qcom-fixes-power-domains-v2-8-28c1f11599fe@linaro.org Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/pci/qcom,pcie-sm8550.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Documentation/devicetree/bindings/pci/qcom,pcie-sm8550.yaml b/Documentation/devicetree/bindings/pci/qcom,pcie-sm8550.yaml index 38b561e23c1fd..29d7df7aca60b 100644 --- a/Documentation/devicetree/bindings/pci/qcom,pcie-sm8550.yaml +++ b/Documentation/devicetree/bindings/pci/qcom,pcie-sm8550.yaml @@ -83,6 +83,11 @@ properties: - const: pci # PCIe core reset - const: link_down # PCIe link down reset +required: + - power-domains + - resets + - reset-names + allOf: - $ref: qcom,pcie-common.yaml# From 51a5ab36084f3251ef87eda3e6a6236f6488925e Mon Sep 17 00:00:00 2001 From: Shivani Agarwal Date: Tue, 23 Sep 2025 23:01:48 -0700 Subject: [PATCH 1400/2333] crypto: af_alg - zero initialize memory allocated via sock_kmalloc commit 6f6e309328d53a10c0fe1f77dec2db73373179b6 upstream. Several crypto user API contexts and requests allocated with sock_kmalloc() were left uninitialized, relying on callers to set fields explicitly. This resulted in the use of uninitialized data in certain error paths or when new fields are added in the future. The ACVP patches also contain two user-space interface files: algif_kpp.c and algif_akcipher.c. These too rely on proper initialization of their context structures. A particular issue has been observed with the newly added 'inflight' variable introduced in af_alg_ctx by commit: 67b164a871af ("crypto: af_alg - Disallow multiple in-flight AIO requests") Because the context is not memset to zero after allocation, the inflight variable has contained garbage values. As a result, af_alg_alloc_areq() has incorrectly returned -EBUSY randomly when the garbage value was interpreted as true: https://github.com/gregkh/linux/blame/master/crypto/af_alg.c#L1209 The check directly tests ctx->inflight without explicitly comparing against true/false. Since inflight is only ever set to true or false later, an uninitialized value has triggered -EBUSY failures. Zero-initializing memory allocated with sock_kmalloc() ensures inflight and other fields start in a known state, removing random issues caused by uninitialized data. Fixes: fe869cdb89c9 ("crypto: algif_hash - User-space interface for hash operations") Fixes: 5afdfd22e6ba ("crypto: algif_rng - add random number generator support") Fixes: 2d97591ef43d ("crypto: af_alg - consolidation of duplicate code") Fixes: 67b164a871af ("crypto: af_alg - Disallow multiple in-flight AIO requests") Cc: stable@vger.kernel.org Signed-off-by: Shivani Agarwal Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman --- crypto/af_alg.c | 5 ++--- crypto/algif_hash.c | 3 +-- crypto/algif_rng.c | 3 +-- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/crypto/af_alg.c b/crypto/af_alg.c index ca6fdcc6c54ac..6c271e55f44d9 100644 --- a/crypto/af_alg.c +++ b/crypto/af_alg.c @@ -1212,15 +1212,14 @@ struct af_alg_async_req *af_alg_alloc_areq(struct sock *sk, if (unlikely(!areq)) return ERR_PTR(-ENOMEM); + memset(areq, 0, areqlen); + ctx->inflight = true; areq->areqlen = areqlen; areq->sk = sk; areq->first_rsgl.sgl.sgt.sgl = areq->first_rsgl.sgl.sgl; - areq->last_rsgl = NULL; INIT_LIST_HEAD(&areq->rsgl_list); - areq->tsgl = NULL; - areq->tsgl_entries = 0; return areq; } diff --git a/crypto/algif_hash.c b/crypto/algif_hash.c index e3f1a4852737b..4d3dfc60a16a6 100644 --- a/crypto/algif_hash.c +++ b/crypto/algif_hash.c @@ -416,9 +416,8 @@ static int hash_accept_parent_nokey(void *private, struct sock *sk) if (!ctx) return -ENOMEM; - ctx->result = NULL; + memset(ctx, 0, len); ctx->len = len; - ctx->more = false; crypto_init_wait(&ctx->wait); ask->private = ctx; diff --git a/crypto/algif_rng.c b/crypto/algif_rng.c index 10c41adac3b1f..1a86e40c8372e 100644 --- a/crypto/algif_rng.c +++ b/crypto/algif_rng.c @@ -248,9 +248,8 @@ static int rng_accept_parent(void *private, struct sock *sk) if (!ctx) return -ENOMEM; + memset(ctx, 0, len); ctx->len = len; - ctx->addtl = NULL; - ctx->addtl_len = 0; /* * No seeding done at that point -- if multiple accepts are From b674e3522b6748aa3b73156a51ac304a421af074 Mon Sep 17 00:00:00 2001 From: Guangshuo Li Date: Tue, 23 Sep 2025 20:44:18 +0800 Subject: [PATCH 1401/2333] crypto: caam - Add check for kcalloc() in test_len() commit 7cf6e0b69b0d90ab042163e5bbddda0dfcf8b6a7 upstream. As kcalloc() may fail, check its return value to avoid a NULL pointer dereference when passing the buffer to rng->read(). On allocation failure, log the error and return since test_len() returns void. Fixes: 2be0d806e25e ("crypto: caam - add a test for the RNG") Cc: stable@vger.kernel.org Signed-off-by: Guangshuo Li Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman --- drivers/crypto/caam/caamrng.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/crypto/caam/caamrng.c b/drivers/crypto/caam/caamrng.c index b3d14a7f4dd14..0eb43c8625164 100644 --- a/drivers/crypto/caam/caamrng.c +++ b/drivers/crypto/caam/caamrng.c @@ -181,7 +181,9 @@ static inline void test_len(struct hwrng *rng, size_t len, bool wait) struct device *dev = ctx->ctrldev; buf = kcalloc(CAAM_RNG_MAX_FIFO_STORE_SIZE, sizeof(u8), GFP_KERNEL); - + if (!buf) { + return; + } while (len > 0) { read_len = rng->read(rng, buf, len, wait); From 70cf3d6fe71a6b72548a3f4b7ca25933dd3196f0 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Tue, 9 Dec 2025 14:34:17 -0800 Subject: [PATCH 1402/2333] crypto: arm64/ghash - Fix incorrect output from ghash-neon commit f6a458746f905adb7d70e50e8b9383dc9e3fd75f upstream. Commit 9a7c987fb92b ("crypto: arm64/ghash - Use API partial block handling") made ghash_finup() pass the wrong buffer to ghash_do_simd_update(). As a result, ghash-neon now produces incorrect outputs when the message length isn't divisible by 16 bytes. Fix this. (I didn't notice this earlier because this code is reached only on CPUs that support NEON but not PMULL. I haven't yet found a way to get qemu-system-aarch64 to emulate that configuration.) Fixes: 9a7c987fb92b ("crypto: arm64/ghash - Use API partial block handling") Cc: stable@vger.kernel.org Reported-by: Diederik de Haas Closes: https://lore.kernel.org/linux-crypto/DETXT7QI62KE.F3CGH2VWX1SC@cknow-tech.com/ Tested-by: Diederik de Haas Acked-by: Herbert Xu Link: https://lore.kernel.org/r/20251209223417.112294-1-ebiggers@kernel.org Signed-off-by: Eric Biggers Signed-off-by: Greg Kroah-Hartman --- arch/arm64/crypto/ghash-ce-glue.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/crypto/ghash-ce-glue.c b/arch/arm64/crypto/ghash-ce-glue.c index 4995b6e223350..9625570dc3535 100644 --- a/arch/arm64/crypto/ghash-ce-glue.c +++ b/arch/arm64/crypto/ghash-ce-glue.c @@ -133,7 +133,7 @@ static int ghash_finup(struct shash_desc *desc, const u8 *src, u8 buf[GHASH_BLOCK_SIZE] = {}; memcpy(buf, src, len); - ghash_do_simd_update(1, ctx->digest, src, key, NULL, + ghash_do_simd_update(1, ctx->digest, buf, key, NULL, pmull_ghash_update_p8); memzero_explicit(buf, sizeof(buf)); } From 1d18fb5c71f63c761e426ce8e73e750c6a891ac8 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 25 Sep 2025 17:00:07 +0200 Subject: [PATCH 1403/2333] amba: tegra-ahb: Fix device leak on SMMU enable commit 500e1368e46928f4b2259612dcabb6999afae2a6 upstream. Make sure to drop the reference taken to the AHB platform device when looking up its driver data while enabling the SMMU. Note that holding a reference to a device does not prevent its driver data from going away. Fixes: 89c788bab1f0 ("ARM: tegra: Add SMMU enabler in AHB") Cc: stable@vger.kernel.org # 3.5 Signed-off-by: Johan Hovold Signed-off-by: Thierry Reding Signed-off-by: Greg Kroah-Hartman --- drivers/amba/tegra-ahb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/amba/tegra-ahb.c b/drivers/amba/tegra-ahb.c index c0e8b765522dc..f23c3ed018101 100644 --- a/drivers/amba/tegra-ahb.c +++ b/drivers/amba/tegra-ahb.c @@ -144,6 +144,7 @@ int tegra_ahb_enable_smmu(struct device_node *dn) if (!dev) return -EPROBE_DEFER; ahb = dev_get_drvdata(dev); + put_device(dev); val = gizmo_readl(ahb, AHB_ARBITRATION_XBAR_CTRL); val |= AHB_ARBITRATION_XBAR_CTRL_SMMU_INIT_DONE; gizmo_writel(ahb, val, AHB_ARBITRATION_XBAR_CTRL); From 35eb1ec73f5727e4b4244ee9c181919e9c69a889 Mon Sep 17 00:00:00 2001 From: Damien Le Moal Date: Sat, 15 Nov 2025 21:15:52 +0900 Subject: [PATCH 1404/2333] zloop: fail zone append operations that are targeting full zones commit cf28f6f923cb1dd2765b5c3d7697bb4dcf2096a0 upstream. zloop_rw() will fail any regular write operation that targets a full sequential zone. The check for this is indirect and achieved by checking the write pointer alignment of the write operation. But this check is ineffective for zone append operations since these are alwasy automatically directed at a zone write pointer. Prevent zone append operations from being executed in a full zone with an explicit check of the zone condition. Fixes: eb0570c7df23 ("block: new zoned loop block device driver") Cc: stable@vger.kernel.org Signed-off-by: Damien Le Moal Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman --- drivers/block/zloop.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/block/zloop.c b/drivers/block/zloop.c index a423228e201ba..e0123c16040d7 100644 --- a/drivers/block/zloop.c +++ b/drivers/block/zloop.c @@ -407,6 +407,10 @@ static void zloop_rw(struct zloop_cmd *cmd) mutex_lock(&zone->lock); if (is_append) { + if (zone->cond == BLK_ZONE_COND_FULL) { + ret = -EIO; + goto unlock; + } sector = zone->wp; cmd->sector = sector; } From 3846f8f781cc2758cbb40f99b9765954b1a5b568 Mon Sep 17 00:00:00 2001 From: Damien Le Moal Date: Sat, 15 Nov 2025 21:15:51 +0900 Subject: [PATCH 1405/2333] zloop: make the write pointer of full zones invalid commit 866d65745b635927c3d1343ab67e6fd4a99d116d upstream. The write pointer of zones that are in the full condition is always invalid. Reflect that fact by setting the write pointer of full zones to ULLONG_MAX. Fixes: eb0570c7df23 ("block: new zoned loop block device driver") Cc: stable@vger.kernel.org Signed-off-by: Damien Le Moal Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman --- drivers/block/zloop.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/block/zloop.c b/drivers/block/zloop.c index e0123c16040d7..39a425db670c8 100644 --- a/drivers/block/zloop.c +++ b/drivers/block/zloop.c @@ -177,7 +177,7 @@ static int zloop_update_seq_zone(struct zloop_device *zlo, unsigned int zone_no) zone->wp = zone->start; } else if (file_sectors == zlo->zone_capacity) { zone->cond = BLK_ZONE_COND_FULL; - zone->wp = zone->start + zlo->zone_size; + zone->wp = ULLONG_MAX; } else { zone->cond = BLK_ZONE_COND_CLOSED; zone->wp = zone->start + file_sectors; @@ -326,7 +326,7 @@ static int zloop_finish_zone(struct zloop_device *zlo, unsigned int zone_no) } zone->cond = BLK_ZONE_COND_FULL; - zone->wp = zone->start + zlo->zone_size; + zone->wp = ULLONG_MAX; clear_bit(ZLOOP_ZONE_SEQ_ERROR, &zone->flags); unlock: @@ -437,8 +437,10 @@ static void zloop_rw(struct zloop_cmd *cmd) * copmpletes. */ zone->wp += nr_sectors; - if (zone->wp == zone_end) + if (zone->wp == zone_end) { zone->cond = BLK_ZONE_COND_FULL; + zone->wp = ULLONG_MAX; + } } rq_for_each_bvec(tmp, rq, rq_iter) From 8716a841d1da4113e757b537b7d249c29d82e6db Mon Sep 17 00:00:00 2001 From: Miaoqian Lin Date: Mon, 27 Oct 2025 14:07:35 +0800 Subject: [PATCH 1406/2333] virtio: vdpa: Fix reference count leak in octep_sriov_enable() commit b41ca62c0019de1321d75f2b2f274a28784a41ed upstream. pci_get_device() will increase the reference count for the returned pci_dev, and also decrease the reference count for the input parameter from if it is not NULL. If we break the loop in with 'vf_pdev' not NULL. We need to call pci_dev_put() to decrease the reference count. Found via static anlaysis and this is similar to commit c508eb042d97 ("perf/x86/intel/uncore: Fix reference count leak in sad_cfg_iio_topology()") Fixes: 8b6c724cdab8 ("virtio: vdpa: vDPA driver for Marvell OCTEON DPU devices") Cc: stable@vger.kernel.org Signed-off-by: Miaoqian Lin Signed-off-by: Michael S. Tsirkin Message-Id: <20251027060737.33815-1-linmq006@gmail.com> Signed-off-by: Greg Kroah-Hartman --- drivers/vdpa/octeon_ep/octep_vdpa_main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/vdpa/octeon_ep/octep_vdpa_main.c b/drivers/vdpa/octeon_ep/octep_vdpa_main.c index 9e8d07078606f..31a02e7fd7f27 100644 --- a/drivers/vdpa/octeon_ep/octep_vdpa_main.c +++ b/drivers/vdpa/octeon_ep/octep_vdpa_main.c @@ -736,6 +736,7 @@ static int octep_sriov_enable(struct pci_dev *pdev, int num_vfs) octep_vdpa_assign_barspace(vf_pdev, pdev, index); if (++index == num_vfs) { done = true; + pci_dev_put(vf_pdev); break; } } From 479af0d9c6ba2fc238ceb2e1b704d3335f0428d8 Mon Sep 17 00:00:00 2001 From: Raghavendra Rao Ananta Date: Fri, 31 Oct 2025 17:06:02 +0000 Subject: [PATCH 1407/2333] vfio: Fix ksize arg while copying user struct in vfio_df_ioctl_bind_iommufd() commit 2f03f21fe7516902283b135de272d3c7b10672de upstream. For the cases where user includes a non-zero value in 'token_uuid_ptr' field of 'struct vfio_device_bind_iommufd', the copy_struct_from_user() in vfio_df_ioctl_bind_iommufd() fails with -E2BIG. For the 'minsz' passed, copy_struct_from_user() expects the newly introduced field to be zero-ed, which would be incorrect in this case. Fix this by passing the actual size of the kernel struct. If working with a newer userspace, copy_struct_from_user() would copy the 'token_uuid_ptr' field, and if working with an old userspace, it would zero out this field, thus still retaining backward compatibility. Fixes: 86624ba3b522 ("vfio/pci: Do vf_token checks for VFIO_DEVICE_BIND_IOMMUFD") Cc: stable@vger.kernel.org Signed-off-by: Raghavendra Rao Ananta Reviewed-by: Jason Gunthorpe Link: https://lore.kernel.org/r/20251031170603.2260022-2-rananta@google.com Signed-off-by: Alex Williamson Signed-off-by: Greg Kroah-Hartman --- drivers/vfio/device_cdev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/vfio/device_cdev.c b/drivers/vfio/device_cdev.c index 480cac3a0c274..8ceca24ac136c 100644 --- a/drivers/vfio/device_cdev.c +++ b/drivers/vfio/device_cdev.c @@ -99,7 +99,7 @@ long vfio_df_ioctl_bind_iommufd(struct vfio_device_file *df, return ret; if (user_size < minsz) return -EINVAL; - ret = copy_struct_from_user(&bind, minsz, arg, user_size); + ret = copy_struct_from_user(&bind, sizeof(bind), arg, user_size); if (ret) return ret; From 3ce2b4aec8cd1460629802d9a6c1873abee6a04c Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Thu, 4 Dec 2025 15:19:35 -0500 Subject: [PATCH 1408/2333] tracing: Fix fixed array of synthetic event commit 47ef834209e5981f443240d8a8b45bf680df22aa upstream. The commit 4d38328eb442d ("tracing: Fix synth event printk format for str fields") replaced "%.*s" with "%s" but missed removing the number size of the dynamic and static strings. The commit e1a453a57bc7 ("tracing: Do not add length to print format in synthetic events") fixed the dynamic part but did not fix the static part. That is, with the commands: # echo 's:wake_lat char[] wakee; u64 delta;' >> /sys/kernel/tracing/dynamic_events # echo 'hist:keys=pid:ts=common_timestamp.usecs if !(common_flags & 0x18)' > /sys/kernel/tracing/events/sched/sched_waking/trigger # echo 'hist:keys=next_pid:delta=common_timestamp.usecs-$ts:onmatch(sched.sched_waking).trace(wake_lat,next_comm,$delta)' > /sys/kernel/tracing/events/sched/sched_switch/trigger That caused the output of: -0 [001] d..5. 193.428167: wake_lat: wakee=(efault)sshd-sessiondelta=155 sshd-session-879 [001] d..5. 193.811080: wake_lat: wakee=(efault)kworker/u34:5delta=58 -0 [002] d..5. 193.811198: wake_lat: wakee=(efault)bashdelta=91 The commit e1a453a57bc7 fixed the part where the synthetic event had "char[] wakee". But if one were to replace that with a static size string: # echo 's:wake_lat char[16] wakee; u64 delta;' >> /sys/kernel/tracing/dynamic_events Where "wakee" is defined as "char[16]" and not "char[]" making it a static size, the code triggered the "(efaul)" again. Remove the added STR_VAR_LEN_MAX size as the string is still going to be nul terminated. Cc: stable@vger.kernel.org Cc: Masami Hiramatsu Cc: Mathieu Desnoyers Cc: Douglas Raillard Link: https://patch.msgid.link/20251204151935.5fa30355@gandalf.local.home Fixes: e1a453a57bc7 ("tracing: Do not add length to print format in synthetic events") Signed-off-by: Steven Rostedt (Google) Signed-off-by: Greg Kroah-Hartman --- kernel/trace/trace_events_synth.c | 1 - 1 file changed, 1 deletion(-) diff --git a/kernel/trace/trace_events_synth.c b/kernel/trace/trace_events_synth.c index f24ee61f8884f..8e1524b8667a7 100644 --- a/kernel/trace/trace_events_synth.c +++ b/kernel/trace/trace_events_synth.c @@ -375,7 +375,6 @@ static enum print_line_t print_synth_event(struct trace_iterator *iter, n_u64++; } else { trace_seq_printf(s, print_fmt, se->fields[i]->name, - STR_VAR_LEN_MAX, (char *)&entry->fields[n_u64].as_u64, i == se->n_fields - 1 ? "" : " "); n_u64 += STR_VAR_LEN_MAX / sizeof(u64); From b2d6246ef36f4d3e254e02ca36cdfff5fa6d17fa Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Fri, 21 Nov 2025 13:18:52 +0100 Subject: [PATCH 1409/2333] soc: samsung: exynos-pmu: fix device leak on regmap lookup commit 990eb9a8eb4540ab90c7b34bb07b87ff13881cad upstream. Make sure to drop the reference taken when looking up the PMU device and its regmap. Note that holding a reference to a device does not prevent its regmap from going away so there is no point in keeping the reference. Fixes: 0b7c6075022c ("soc: samsung: exynos-pmu: Add regmap support for SoCs that protect PMU regs") Cc: stable@vger.kernel.org # 6.9 Cc: Peter Griffin Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20251121121852.16825-1-johan@kernel.org Signed-off-by: Krzysztof Kozlowski Signed-off-by: Greg Kroah-Hartman --- drivers/soc/samsung/exynos-pmu.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/soc/samsung/exynos-pmu.c b/drivers/soc/samsung/exynos-pmu.c index df5b1f299a260..f8fe1a5965ab4 100644 --- a/drivers/soc/samsung/exynos-pmu.c +++ b/drivers/soc/samsung/exynos-pmu.c @@ -346,6 +346,8 @@ struct regmap *exynos_get_pmu_regmap_by_phandle(struct device_node *np, if (!dev) return ERR_PTR(-EPROBE_DEFER); + put_device(dev); + return syscon_node_to_regmap(pmu_np); } EXPORT_SYMBOL_GPL(exynos_get_pmu_regmap_by_phandle); From 951515391b8f68ed6230d0a0c59409ec2579dbb8 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Fri, 26 Sep 2025 16:35:11 +0200 Subject: [PATCH 1410/2333] soc: qcom: pbs: fix device leak on lookup commit 94124bf253d24b13e89c45618a168d5a1d8a61e7 upstream. Make sure to drop the reference taken to the pbs platform device when looking up its driver data. Note that holding a reference to a device does not prevent its driver data from going away so there is no point in keeping the reference. Fixes: 5b2dd77be1d8 ("soc: qcom: add QCOM PBS driver") Cc: stable@vger.kernel.org # 6.9 Cc: Anjelique Melendez Signed-off-by: Johan Hovold Link: https://lore.kernel.org/r/20250926143511.6715-3-johan@kernel.org Signed-off-by: Bjorn Andersson Signed-off-by: Greg Kroah-Hartman --- drivers/soc/qcom/qcom-pbs.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/soc/qcom/qcom-pbs.c b/drivers/soc/qcom/qcom-pbs.c index 1cc5d045f9ddf..06b4a596e2757 100644 --- a/drivers/soc/qcom/qcom-pbs.c +++ b/drivers/soc/qcom/qcom-pbs.c @@ -173,6 +173,8 @@ struct pbs_dev *get_pbs_client_device(struct device *dev) return ERR_PTR(-EINVAL); } + platform_device_put(pdev); + return pbs; } EXPORT_SYMBOL_GPL(get_pbs_client_device); From b28fd17adfb2131a7194a917453ed347702251b1 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Fri, 26 Sep 2025 16:35:10 +0200 Subject: [PATCH 1411/2333] soc: qcom: ocmem: fix device leak on lookup commit b5c16ea57b030b8e9428ec726e26219dfe05c3d9 upstream. Make sure to drop the reference taken to the ocmem platform device when looking up its driver data. Note that holding a reference to a device does not prevent its driver data from going away so there is no point in keeping the reference. Also note that commit 0ff027027e05 ("soc: qcom: ocmem: Fix missing put_device() call in of_get_ocmem") fixed the leak in a lookup error path, but the reference is still leaking on success. Fixes: 88c1e9404f1d ("soc: qcom: add OCMEM driver") Cc: stable@vger.kernel.org # 5.5: 0ff027027e05 Cc: Brian Masney Cc: Miaoqian Lin Signed-off-by: Johan Hovold Reviewed-by: Brian Masney Link: https://lore.kernel.org/r/20250926143511.6715-2-johan@kernel.org Signed-off-by: Bjorn Andersson Signed-off-by: Greg Kroah-Hartman --- drivers/soc/qcom/ocmem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/soc/qcom/ocmem.c b/drivers/soc/qcom/ocmem.c index 9c3bd37b6579d..71130a2f62e9e 100644 --- a/drivers/soc/qcom/ocmem.c +++ b/drivers/soc/qcom/ocmem.c @@ -202,9 +202,9 @@ struct ocmem *of_get_ocmem(struct device *dev) } ocmem = platform_get_drvdata(pdev); + put_device(&pdev->dev); if (!ocmem) { dev_err(dev, "Cannot get ocmem\n"); - put_device(&pdev->dev); return ERR_PTR(-ENODEV); } return ocmem; From 25073a05068e681fb61004fab88979d8865ef36d Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Fri, 26 Sep 2025 16:31:31 +0200 Subject: [PATCH 1412/2333] soc: apple: mailbox: fix device leak on lookup commit f401671e90ccc26b3022f177c4156a429c024f6c upstream. Make sure to drop the reference taken to the mbox platform device when looking up its driver data. Note that holding a reference to a device does not prevent its driver data from going away so there is no point in keeping the reference. Fixes: 6e1457fcad3f ("soc: apple: mailbox: Add ASC/M3 mailbox driver") Cc: stable@vger.kernel.org # 6.8 Signed-off-by: Johan Hovold Reviewed-by: Neal Gompa Signed-off-by: Sven Peter Signed-off-by: Greg Kroah-Hartman --- drivers/soc/apple/mailbox.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/drivers/soc/apple/mailbox.c b/drivers/soc/apple/mailbox.c index 8f29108dc69ac..5c48455185c9b 100644 --- a/drivers/soc/apple/mailbox.c +++ b/drivers/soc/apple/mailbox.c @@ -302,11 +302,18 @@ struct apple_mbox *apple_mbox_get(struct device *dev, int index) return ERR_PTR(-EPROBE_DEFER); mbox = platform_get_drvdata(pdev); - if (!mbox) - return ERR_PTR(-EPROBE_DEFER); + if (!mbox) { + mbox = ERR_PTR(-EPROBE_DEFER); + goto out_put_pdev; + } + + if (!device_link_add(dev, &pdev->dev, DL_FLAG_AUTOREMOVE_CONSUMER)) { + mbox = ERR_PTR(-ENODEV); + goto out_put_pdev; + } - if (!device_link_add(dev, &pdev->dev, DL_FLAG_AUTOREMOVE_CONSUMER)) - return ERR_PTR(-ENODEV); +out_put_pdev: + put_device(&pdev->dev); return mbox; } From 81bf2780ba433689f80c43a9ac46c03e916a32a9 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Fri, 26 Sep 2025 16:24:53 +0200 Subject: [PATCH 1413/2333] soc: amlogic: canvas: fix device leak on lookup commit 32200f4828de9d7e6db379909898e718747f4e18 upstream. Make sure to drop the reference taken to the canvas platform device when looking up its driver data. Note that holding a reference to a device does not prevent its driver data from going away so there is no point in keeping the reference. Also note that commit 28f851e6afa8 ("soc: amlogic: canvas: add missing put_device() call in meson_canvas_get()") fixed the leak in a lookup error path, but the reference is still leaking on success. Fixes: d4983983d987 ("soc: amlogic: add meson-canvas driver") Cc: stable@vger.kernel.org # 4.20: 28f851e6afa8 Cc: Yu Kuai Signed-off-by: Johan Hovold Reviewed-by: Martin Blumenstingl Link: https://patch.msgid.link/20250926142454.5929-2-johan@kernel.org Signed-off-by: Neil Armstrong Signed-off-by: Greg Kroah-Hartman --- drivers/soc/amlogic/meson-canvas.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/soc/amlogic/meson-canvas.c b/drivers/soc/amlogic/meson-canvas.c index b6e06c4d2117f..0711088da5dcd 100644 --- a/drivers/soc/amlogic/meson-canvas.c +++ b/drivers/soc/amlogic/meson-canvas.c @@ -73,10 +73,9 @@ struct meson_canvas *meson_canvas_get(struct device *dev) * current state, this driver probe cannot return -EPROBE_DEFER */ canvas = dev_get_drvdata(&canvas_pdev->dev); - if (!canvas) { - put_device(&canvas_pdev->dev); + put_device(&canvas_pdev->dev); + if (!canvas) return ERR_PTR(-EINVAL); - } return canvas; } From 88b71cd0aa39e7c97990a9e9213a360076927610 Mon Sep 17 00:00:00 2001 From: Tomas Glozar Date: Mon, 6 Oct 2025 16:31:00 +0200 Subject: [PATCH 1414/2333] rtla/timerlat_bpf: Stop tracing on user latency commit e4240db9336c25826a2d6634adcca86d5ee01bde upstream. rtla-timerlat allows a *thread* latency threshold to be set via the -T/--thread option. However, the timerlat tracer calls this *total* latency (stop_tracing_total_us), and stops tracing also when the return-to-user latency is over the threshold. Change the behavior of the timerlat BPF program to reflect what the timerlat tracer is doing, to avoid discrepancy between stopping collecting data in the BPF program and stopping tracing in the timerlat tracer. Cc: stable@vger.kernel.org Fixes: e34293ddcebd ("rtla/timerlat: Add BPF skeleton to collect samples") Reviewed-by: Wander Lairson Costa Link: https://lore.kernel.org/r/20251006143100.137255-1-tglozar@redhat.com Signed-off-by: Tomas Glozar Signed-off-by: Greg Kroah-Hartman --- tools/tracing/rtla/src/timerlat.bpf.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/tracing/rtla/src/timerlat.bpf.c b/tools/tracing/rtla/src/timerlat.bpf.c index 084cd10c21fc4..e2265b5d64910 100644 --- a/tools/tracing/rtla/src/timerlat.bpf.c +++ b/tools/tracing/rtla/src/timerlat.bpf.c @@ -148,6 +148,9 @@ int handle_timerlat_sample(struct trace_event_raw_timerlat_sample *tp_args) } else { update_main_hist(&hist_user, bucket); update_summary(&summary_user, latency, bucket); + + if (thread_threshold != 0 && latency_us >= thread_threshold) + set_stop_tracing(); } return 0; From f80e4e91b010ee7d6c52f24d069975ac955ac6b2 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Fri, 22 Aug 2025 11:00:42 +0100 Subject: [PATCH 1415/2333] rpmsg: glink: fix rpmsg device leak commit a53e356df548f6b0e82529ef3cc6070f42622189 upstream. While testing rpmsg-char interface it was noticed that duplicate sysfs entries are getting created and below warning is noticed. Reason for this is that we are leaking rpmsg device pointer, setting it null without actually unregistering device. Any further attempts to unregister fail because rpdev is NULL, resulting in a leak. Fix this by unregistering rpmsg device before removing its reference from rpmsg channel. sysfs: cannot create duplicate filename '/devices/platform/soc@0/3700000.remot eproc/remoteproc/remoteproc1/3700000.remoteproc:glink-edge/3700000.remoteproc: glink-edge.adsp_apps.-1.-1' [ 114.115347] CPU: 0 UID: 0 PID: 9 Comm: kworker/0:0 Not tainted 6.16.0-rc4 #7 PREEMPT [ 114.115355] Hardware name: Qualcomm Technologies, Inc. Robotics RB3gen2 (DT) [ 114.115358] Workqueue: events qcom_glink_work [ 114.115371] Call trace:8 [ 114.115374] show_stack+0x18/0x24 (C) [ 114.115382] dump_stack_lvl+0x60/0x80 [ 114.115388] dump_stack+0x18/0x24 [ 114.115393] sysfs_warn_dup+0x64/0x80 [ 114.115402] sysfs_create_dir_ns+0xf4/0x120 [ 114.115409] kobject_add_internal+0x98/0x260 [ 114.115416] kobject_add+0x9c/0x108 [ 114.115421] device_add+0xc4/0x7a0 [ 114.115429] rpmsg_register_device+0x5c/0xb0 [ 114.115434] qcom_glink_work+0x4bc/0x820 [ 114.115438] process_one_work+0x148/0x284 [ 114.115446] worker_thread+0x2c4/0x3e0 [ 114.115452] kthread+0x12c/0x204 [ 114.115457] ret_from_fork+0x10/0x20 [ 114.115464] kobject: kobject_add_internal failed for 3700000.remoteproc: glink-edge.adsp_apps.-1.-1 with -EEXIST, don't try to register things with the same name in the same directory. [ 114.250045] rpmsg 3700000.remoteproc:glink-edge.adsp_apps.-1.-1: device_add failed: -17 Fixes: 835764ddd9af ("rpmsg: glink: Move the common glink protocol implementation to glink_native.c") Cc: Stable@vger.kernel.org Signed-off-by: Srinivas Kandagatla Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20250822100043.2604794-2-srinivas.kandagatla@oss.qualcomm.com Signed-off-by: Bjorn Andersson Signed-off-by: Greg Kroah-Hartman --- drivers/rpmsg/qcom_glink_native.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c index 820a6ca5b1d7a..3a15d9d108089 100644 --- a/drivers/rpmsg/qcom_glink_native.c +++ b/drivers/rpmsg/qcom_glink_native.c @@ -1399,6 +1399,7 @@ static void qcom_glink_destroy_ept(struct rpmsg_endpoint *ept) { struct glink_channel *channel = to_glink_channel(ept); struct qcom_glink *glink = channel->glink; + struct rpmsg_channel_info chinfo; unsigned long flags; spin_lock_irqsave(&channel->recv_lock, flags); @@ -1406,6 +1407,13 @@ static void qcom_glink_destroy_ept(struct rpmsg_endpoint *ept) spin_unlock_irqrestore(&channel->recv_lock, flags); /* Decouple the potential rpdev from the channel */ + if (channel->rpdev) { + strscpy_pad(chinfo.name, channel->name, sizeof(chinfo.name)); + chinfo.src = RPMSG_ADDR_ANY; + chinfo.dst = RPMSG_ADDR_ANY; + + rpmsg_unregister_device(glink->dev, &chinfo); + } channel->rpdev = NULL; qcom_glink_send_close_req(glink, channel); From 17be376bb250718e466eb33d3538b478781823af Mon Sep 17 00:00:00 2001 From: Biju Das Date: Wed, 26 Nov 2025 10:42:48 +0000 Subject: [PATCH 1416/2333] pwm: rzg2l-gpt: Allow checking period_tick cache value only if sibling channel is enabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit fae00ea9f00367771003ace78f29549dead58fc7 upstream. The rzg2l_gpt_config() tests the rzg2l_gpt->period_tick variable when both channels of a hardware channel are in use. This check is not valid if rzg2l_gpt_config() is called after disabling all the channels, as it tests against the cached value. Hence, allow checking and setting the cached value only if the sibling channel is enabled. While at it, drop else after return statement to fix the check patch warning. Cc: stable@kernel.org Fixes: 061f087f5d0b ("pwm: Add support for RZ/G2L GPT") Signed-off-by: Biju Das Link: https://patch.msgid.link/20251126104308.142302-1-biju.das.jz@bp.renesas.com Signed-off-by: Uwe Kleine-König Signed-off-by: Greg Kroah-Hartman --- drivers/pwm/pwm-rzg2l-gpt.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/drivers/pwm/pwm-rzg2l-gpt.c b/drivers/pwm/pwm-rzg2l-gpt.c index 360c8bf3b1903..4856af080e8e9 100644 --- a/drivers/pwm/pwm-rzg2l-gpt.c +++ b/drivers/pwm/pwm-rzg2l-gpt.c @@ -96,6 +96,11 @@ static inline unsigned int rzg2l_gpt_subchannel(unsigned int hwpwm) return hwpwm & 0x1; } +static inline unsigned int rzg2l_gpt_sibling(unsigned int hwpwm) +{ + return hwpwm ^ 0x1; +} + static void rzg2l_gpt_write(struct rzg2l_gpt_chip *rzg2l_gpt, u32 reg, u32 data) { writel(data, rzg2l_gpt->mmio + reg); @@ -271,10 +276,14 @@ static int rzg2l_gpt_config(struct pwm_chip *chip, struct pwm_device *pwm, * in use with different settings. */ if (rzg2l_gpt->channel_request_count[ch] > 1) { - if (period_ticks < rzg2l_gpt->period_ticks[ch]) - return -EBUSY; - else + u8 sibling_ch = rzg2l_gpt_sibling(pwm->hwpwm); + + if (rzg2l_gpt_is_ch_enabled(rzg2l_gpt, sibling_ch)) { + if (period_ticks < rzg2l_gpt->period_ticks[ch]) + return -EBUSY; + period_ticks = rzg2l_gpt->period_ticks[ch]; + } } prescale = rzg2l_gpt_calculate_prescale(rzg2l_gpt, period_ticks); From 19d61f032c7e052c3afc9a7e8f0aaf136b5732bf Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Fri, 21 Nov 2025 11:04:50 +0100 Subject: [PATCH 1417/2333] platform/x86: intel: chtwc_int33fe: don't dereference swnode args MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 527250cd9092461f1beac3e4180a4481bffa01b5 upstream. Members of struct software_node_ref_args should not be dereferenced directly but set using the provided macros. Commit d7cdbbc93c56 ("software node: allow referencing firmware nodes") changed the name of the software node member and caused a build failure. Remove all direct dereferences of the ref struct as a fix. However, this driver also seems to abuse the software node interface by waiting for a node with an arbitrary name "intel-xhci-usb-sw" to appear in the system before setting up the reference for the I2C device, while the actual software node already exists in the intel-xhci-usb-role-switch module and should be used to set up a static reference. Add a FIXME for a future improvement. Fixes: d7cdbbc93c56 ("software node: allow referencing firmware nodes") Fixes: 53c24c2932e5 ("platform/x86: intel_cht_int33fe: use inline reference properties") Cc: stable@vger.kernel.org Reported-by: Stephen Rothwell Closes: https://lore.kernel.org/all/20251121111534.7cdbfe5c@canb.auug.org.au/ Signed-off-by: Bartosz Golaszewski Reviewed-by: Hans de Goede Acked-by: Ilpo Järvinen Signed-off-by: Philipp Zabel Signed-off-by: Greg Kroah-Hartman --- drivers/platform/x86/intel/chtwc_int33fe.c | 29 +++++++++++++++------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/drivers/platform/x86/intel/chtwc_int33fe.c b/drivers/platform/x86/intel/chtwc_int33fe.c index 29e8b5432f4c9..d183aa53c318b 100644 --- a/drivers/platform/x86/intel/chtwc_int33fe.c +++ b/drivers/platform/x86/intel/chtwc_int33fe.c @@ -77,7 +77,7 @@ static const struct software_node max17047_node = { * software node. */ static struct software_node_ref_args fusb302_mux_refs[] = { - { .node = NULL }, + SOFTWARE_NODE_REFERENCE(NULL), }; static const struct property_entry fusb302_properties[] = { @@ -190,11 +190,6 @@ static void cht_int33fe_remove_nodes(struct cht_int33fe_data *data) { software_node_unregister_node_group(node_group); - if (fusb302_mux_refs[0].node) { - fwnode_handle_put(software_node_fwnode(fusb302_mux_refs[0].node)); - fusb302_mux_refs[0].node = NULL; - } - if (data->dp) { data->dp->secondary = NULL; fwnode_handle_put(data->dp); @@ -202,7 +197,15 @@ static void cht_int33fe_remove_nodes(struct cht_int33fe_data *data) } } -static int cht_int33fe_add_nodes(struct cht_int33fe_data *data) +static void cht_int33fe_put_swnode(void *data) +{ + struct fwnode_handle *fwnode = data; + + fwnode_handle_put(fwnode); + fusb302_mux_refs[0] = SOFTWARE_NODE_REFERENCE(NULL); +} + +static int cht_int33fe_add_nodes(struct device *dev, struct cht_int33fe_data *data) { const struct software_node *mux_ref_node; int ret; @@ -212,17 +215,25 @@ static int cht_int33fe_add_nodes(struct cht_int33fe_data *data) * until the mux driver has created software node for the mux device. * It means we depend on the mux driver. This function will return * -EPROBE_DEFER until the mux device is registered. + * + * FIXME: the relevant software node exists in intel-xhci-usb-role-switch + * and - if exported - could be used to set up a static reference. */ mux_ref_node = software_node_find_by_name(NULL, "intel-xhci-usb-sw"); if (!mux_ref_node) return -EPROBE_DEFER; + ret = devm_add_action_or_reset(dev, cht_int33fe_put_swnode, + software_node_fwnode(mux_ref_node)); + if (ret) + return ret; + /* * Update node used in "usb-role-switch" property. Note that we * rely on software_node_register_node_group() to use the original * instance of properties instead of copying them. */ - fusb302_mux_refs[0].node = mux_ref_node; + fusb302_mux_refs[0] = SOFTWARE_NODE_REFERENCE(mux_ref_node); ret = software_node_register_node_group(node_group); if (ret) @@ -345,7 +356,7 @@ static int cht_int33fe_typec_probe(struct platform_device *pdev) return fusb302_irq; } - ret = cht_int33fe_add_nodes(data); + ret = cht_int33fe_add_nodes(dev, data); if (ret) return ret; From fb5b47ad5387692b39b1f885d81d72501840d86f Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sat, 6 Dec 2025 13:37:50 -0800 Subject: [PATCH 1418/2333] lib/crypto: riscv: Depend on RISCV_EFFICIENT_VECTOR_UNALIGNED_ACCESS commit 1cd5bb6e9e027bab33aafd58fe8340124869ba62 upstream. Replace the RISCV_ISA_V dependency of the RISC-V crypto code with RISCV_EFFICIENT_VECTOR_UNALIGNED_ACCESS, which implies RISCV_ISA_V as well as vector unaligned accesses being efficient. This is necessary because this code assumes that vector unaligned accesses are supported and are efficient. (It does so to avoid having to use lots of extra vsetvli instructions to switch the element width back and forth between 8 and either 32 or 64.) This was omitted from the code originally just because the RISC-V kernel support for detecting this feature didn't exist yet. Support has now been added, but it's fragmented into per-CPU runtime detection, a command-line parameter, and a kconfig option. The kconfig option is the only reasonable way to do it, though, so let's just rely on that. Fixes: eb24af5d7a05 ("crypto: riscv - add vector crypto accelerated AES-{ECB,CBC,CTR,XTS}") Fixes: bb54668837a0 ("crypto: riscv - add vector crypto accelerated ChaCha20") Fixes: 600a3853dfa0 ("crypto: riscv - add vector crypto accelerated GHASH") Fixes: 8c8e40470ffe ("crypto: riscv - add vector crypto accelerated SHA-{256,224}") Fixes: b3415925a08b ("crypto: riscv - add vector crypto accelerated SHA-{512,384}") Fixes: 563a5255afa2 ("crypto: riscv - add vector crypto accelerated SM3") Fixes: b8d06352bbf3 ("crypto: riscv - add vector crypto accelerated SM4") Cc: stable@vger.kernel.org Reported-by: Vivian Wang Closes: https://lore.kernel.org/r/b3cfcdac-0337-4db0-a611-258f2868855f@iscas.ac.cn/ Reviewed-by: Jerry Shih Link: https://lore.kernel.org/r/20251206213750.81474-1-ebiggers@kernel.org Signed-off-by: Eric Biggers Signed-off-by: Greg Kroah-Hartman --- arch/riscv/crypto/Kconfig | 12 ++++++++---- lib/crypto/Kconfig | 9 ++++++--- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/arch/riscv/crypto/Kconfig b/arch/riscv/crypto/Kconfig index a75d6325607b4..14c5acb935e94 100644 --- a/arch/riscv/crypto/Kconfig +++ b/arch/riscv/crypto/Kconfig @@ -4,7 +4,8 @@ menu "Accelerated Cryptographic Algorithms for CPU (riscv)" config CRYPTO_AES_RISCV64 tristate "Ciphers: AES, modes: ECB, CBC, CTS, CTR, XTS" - depends on 64BIT && RISCV_ISA_V && TOOLCHAIN_HAS_VECTOR_CRYPTO + depends on 64BIT && TOOLCHAIN_HAS_VECTOR_CRYPTO && \ + RISCV_EFFICIENT_VECTOR_UNALIGNED_ACCESS select CRYPTO_ALGAPI select CRYPTO_LIB_AES select CRYPTO_SKCIPHER @@ -20,7 +21,8 @@ config CRYPTO_AES_RISCV64 config CRYPTO_GHASH_RISCV64 tristate "Hash functions: GHASH" - depends on 64BIT && RISCV_ISA_V && TOOLCHAIN_HAS_VECTOR_CRYPTO + depends on 64BIT && TOOLCHAIN_HAS_VECTOR_CRYPTO && \ + RISCV_EFFICIENT_VECTOR_UNALIGNED_ACCESS select CRYPTO_GCM help GCM GHASH function (NIST SP 800-38D) @@ -30,7 +32,8 @@ config CRYPTO_GHASH_RISCV64 config CRYPTO_SM3_RISCV64 tristate "Hash functions: SM3 (ShangMi 3)" - depends on 64BIT && RISCV_ISA_V && TOOLCHAIN_HAS_VECTOR_CRYPTO + depends on 64BIT && TOOLCHAIN_HAS_VECTOR_CRYPTO && \ + RISCV_EFFICIENT_VECTOR_UNALIGNED_ACCESS select CRYPTO_HASH select CRYPTO_LIB_SM3 help @@ -42,7 +45,8 @@ config CRYPTO_SM3_RISCV64 config CRYPTO_SM4_RISCV64 tristate "Ciphers: SM4 (ShangMi 4)" - depends on 64BIT && RISCV_ISA_V && TOOLCHAIN_HAS_VECTOR_CRYPTO + depends on 64BIT && TOOLCHAIN_HAS_VECTOR_CRYPTO && \ + RISCV_EFFICIENT_VECTOR_UNALIGNED_ACCESS select CRYPTO_ALGAPI select CRYPTO_SM4 help diff --git a/lib/crypto/Kconfig b/lib/crypto/Kconfig index 16859c6226dd4..fa882108ba62c 100644 --- a/lib/crypto/Kconfig +++ b/lib/crypto/Kconfig @@ -50,7 +50,8 @@ config CRYPTO_LIB_CHACHA_ARCH default y if ARM64 && KERNEL_MODE_NEON default y if MIPS && CPU_MIPS32_R2 default y if PPC64 && CPU_LITTLE_ENDIAN && VSX - default y if RISCV && 64BIT && RISCV_ISA_V && TOOLCHAIN_HAS_VECTOR_CRYPTO + default y if RISCV && 64BIT && TOOLCHAIN_HAS_VECTOR_CRYPTO && \ + RISCV_EFFICIENT_VECTOR_UNALIGNED_ACCESS default y if S390 default y if X86_64 @@ -161,7 +162,8 @@ config CRYPTO_LIB_SHA256_ARCH default y if ARM64 default y if MIPS && CPU_CAVIUM_OCTEON default y if PPC && SPE - default y if RISCV && 64BIT && RISCV_ISA_V && TOOLCHAIN_HAS_VECTOR_CRYPTO + default y if RISCV && 64BIT && TOOLCHAIN_HAS_VECTOR_CRYPTO && \ + RISCV_EFFICIENT_VECTOR_UNALIGNED_ACCESS default y if S390 default y if SPARC64 default y if X86_64 @@ -179,7 +181,8 @@ config CRYPTO_LIB_SHA512_ARCH default y if ARM && !CPU_V7M default y if ARM64 default y if MIPS && CPU_CAVIUM_OCTEON - default y if RISCV && 64BIT && RISCV_ISA_V && TOOLCHAIN_HAS_VECTOR_CRYPTO + default y if RISCV && 64BIT && TOOLCHAIN_HAS_VECTOR_CRYPTO && \ + RISCV_EFFICIENT_VECTOR_UNALIGNED_ACCESS default y if S390 default y if SPARC64 default y if X86_64 From 5fa6c144d3fb8506a5aa925205df8da4ffe0a274 Mon Sep 17 00:00:00 2001 From: Ma Ke Date: Wed, 22 Oct 2025 17:54:02 +0800 Subject: [PATCH 1419/2333] i2c: amd-mp2: fix reference leak in MP2 PCI device commit a6ee6aac66fb394b7f6e6187c73bdcd873f2d139 upstream. In i2c_amd_probe(), amd_mp2_find_device() utilizes driver_find_next_device() which internally calls driver_find_device() to locate the matching device. driver_find_device() increments the reference count of the found device by calling get_device(), but amd_mp2_find_device() fails to call put_device() to decrement the reference count before returning. This results in a reference count leak of the PCI device each time i2c_amd_probe() is executed, which may prevent the device from being properly released and cause a memory leak. Found by code review. Cc: stable@vger.kernel.org Fixes: 529766e0a011 ("i2c: Add drivers for the AMD PCIe MP2 I2C controller") Signed-off-by: Ma Ke Signed-off-by: Andi Shyti Link: https://lore.kernel.org/r/20251022095402.8846-1-make24@iscas.ac.cn Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/busses/i2c-amd-mp2-pci.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-amd-mp2-pci.c b/drivers/i2c/busses/i2c-amd-mp2-pci.c index ef7370d3dbea3..60edbabc2986b 100644 --- a/drivers/i2c/busses/i2c-amd-mp2-pci.c +++ b/drivers/i2c/busses/i2c-amd-mp2-pci.c @@ -458,13 +458,16 @@ struct amd_mp2_dev *amd_mp2_find_device(void) { struct device *dev; struct pci_dev *pci_dev; + struct amd_mp2_dev *mp2_dev; dev = driver_find_next_device(&amd_mp2_pci_driver.driver, NULL); if (!dev) return NULL; pci_dev = to_pci_dev(dev); - return (struct amd_mp2_dev *)pci_get_drvdata(pci_dev); + mp2_dev = (struct amd_mp2_dev *)pci_get_drvdata(pci_dev); + put_device(dev); + return mp2_dev; } EXPORT_SYMBOL_GPL(amd_mp2_find_device); From c95e4c4caf9a652d882431f1254629b2181f33ea Mon Sep 17 00:00:00 2001 From: Raviteja Laggyshetty Date: Fri, 26 Sep 2025 12:12:09 +0530 Subject: [PATCH 1420/2333] interconnect: qcom: sdx75: Drop QPIC interconnect and BCM nodes commit 295f58fdccd05b2d6da1f4a4f81952ccb565c4dc upstream. As like other SDX SoCs, SDX75 SoC's QPIC BCM resource was modeled as a RPMh clock in clk-rpmh driver. However, for SDX75, this resource was also described as an interconnect and BCM node mistakenly. It is incorrect to describe the same resource in two different providers, as it will lead to votes from clients overriding each other. Hence, drop the QPIC interconnect and BCM nodes and let the clients use clk-rpmh driver to vote for this resource. Without this change, the NAND driver fails to probe on SDX75, as the interconnect sync state disables the QPIC nodes as there were no clients voting for this ICC resource. However, the NAND driver had already voted for this BCM resource through the clk-rpmh driver. Since both votes come from Linux, RPMh was unable to distinguish between these two and ends up disabling the QPIC resource during sync state. Cc: stable@vger.kernel.org Fixes: 3642b4e5cbfe ("interconnect: qcom: Add SDX75 interconnect provider driver") Signed-off-by: Raviteja Laggyshetty [mani: dropped the reference to bcm_qp0, reworded description] Signed-off-by: Manivannan Sadhasivam Reviewed-by: Konrad Dybcio Tested-by: Lakshmi Sowjanya D # on SDX75 Link: https://lore.kernel.org/r/20250926-sdx75-icc-v2-1-20d6820e455c@oss.qualcomm.com Signed-off-by: Georgi Djakov Signed-off-by: Greg Kroah-Hartman --- drivers/interconnect/qcom/sdx75.c | 26 -------------------------- drivers/interconnect/qcom/sdx75.h | 2 -- 2 files changed, 28 deletions(-) diff --git a/drivers/interconnect/qcom/sdx75.c b/drivers/interconnect/qcom/sdx75.c index 7ef1f17f3292e..2def75f67eb8e 100644 --- a/drivers/interconnect/qcom/sdx75.c +++ b/drivers/interconnect/qcom/sdx75.c @@ -16,15 +16,6 @@ #include "icc-rpmh.h" #include "sdx75.h" -static struct qcom_icc_node qpic_core_master = { - .name = "qpic_core_master", - .id = SDX75_MASTER_QPIC_CORE, - .channels = 1, - .buswidth = 4, - .num_links = 1, - .links = { SDX75_SLAVE_QPIC_CORE }, -}; - static struct qcom_icc_node qup0_core_master = { .name = "qup0_core_master", .id = SDX75_MASTER_QUP_CORE_0, @@ -375,14 +366,6 @@ static struct qcom_icc_node xm_usb3 = { .links = { SDX75_SLAVE_A1NOC_CFG }, }; -static struct qcom_icc_node qpic_core_slave = { - .name = "qpic_core_slave", - .id = SDX75_SLAVE_QPIC_CORE, - .channels = 1, - .buswidth = 4, - .num_links = 0, -}; - static struct qcom_icc_node qup0_core_slave = { .name = "qup0_core_slave", .id = SDX75_SLAVE_QUP_CORE_0, @@ -831,12 +814,6 @@ static struct qcom_icc_bcm bcm_mc0 = { .nodes = { &ebi }, }; -static struct qcom_icc_bcm bcm_qp0 = { - .name = "QP0", - .num_nodes = 1, - .nodes = { &qpic_core_slave }, -}; - static struct qcom_icc_bcm bcm_qup0 = { .name = "QUP0", .keepalive = true, @@ -898,14 +875,11 @@ static struct qcom_icc_bcm bcm_sn4 = { }; static struct qcom_icc_bcm * const clk_virt_bcms[] = { - &bcm_qp0, &bcm_qup0, }; static struct qcom_icc_node * const clk_virt_nodes[] = { - [MASTER_QPIC_CORE] = &qpic_core_master, [MASTER_QUP_CORE_0] = &qup0_core_master, - [SLAVE_QPIC_CORE] = &qpic_core_slave, [SLAVE_QUP_CORE_0] = &qup0_core_slave, }; diff --git a/drivers/interconnect/qcom/sdx75.h b/drivers/interconnect/qcom/sdx75.h index 24e8871599201..34f51add59dc0 100644 --- a/drivers/interconnect/qcom/sdx75.h +++ b/drivers/interconnect/qcom/sdx75.h @@ -33,7 +33,6 @@ #define SDX75_MASTER_QDSS_ETR 24 #define SDX75_MASTER_QDSS_ETR_1 25 #define SDX75_MASTER_QPIC 26 -#define SDX75_MASTER_QPIC_CORE 27 #define SDX75_MASTER_QUP_0 28 #define SDX75_MASTER_QUP_CORE_0 29 #define SDX75_MASTER_SDCC_1 30 @@ -76,7 +75,6 @@ #define SDX75_SLAVE_QDSS_CFG 67 #define SDX75_SLAVE_QDSS_STM 68 #define SDX75_SLAVE_QPIC 69 -#define SDX75_SLAVE_QPIC_CORE 70 #define SDX75_SLAVE_QUP_0 71 #define SDX75_SLAVE_QUP_CORE_0 72 #define SDX75_SLAVE_SDCC_1 73 From 5b804b8f1e0d66413774d43f7a4b78bba0ca6272 Mon Sep 17 00:00:00 2001 From: Joanne Koong Date: Thu, 4 Dec 2025 13:51:16 -0800 Subject: [PATCH 1421/2333] io_uring/rsrc: fix lost entries after cloned range commit 525916ce496615f531091855604eab9ca573b195 upstream. When cloning with node replacements (IORING_REGISTER_DST_REPLACE), destination entries after the cloned range are not copied over. Add logic to copy them over to the new destination table. Fixes: c1329532d5aa ("io_uring/rsrc: allow cloning with node replacements") Cc: stable@vger.kernel.org Signed-off-by: Joanne Koong Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman --- io_uring/rsrc.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/io_uring/rsrc.c b/io_uring/rsrc.c index 5b6b73c6a62bd..160b4de2d00d3 100644 --- a/io_uring/rsrc.c +++ b/io_uring/rsrc.c @@ -1200,7 +1200,7 @@ static int io_clone_buffers(struct io_ring_ctx *ctx, struct io_ring_ctx *src_ctx if (ret) return ret; - /* Fill entries in data from dst that won't overlap with src */ + /* Copy original dst nodes from before the cloned range */ for (i = 0; i < min(arg->dst_off, ctx->buf_table.nr); i++) { struct io_rsrc_node *src_node = ctx->buf_table.nodes[i]; @@ -1248,6 +1248,16 @@ static int io_clone_buffers(struct io_ring_ctx *ctx, struct io_ring_ctx *src_ctx i++; } + /* Copy original dst nodes from after the cloned range */ + for (i = nbufs; i < ctx->buf_table.nr; i++) { + struct io_rsrc_node *node = ctx->buf_table.nodes[i]; + + if (node) { + data.nodes[i] = node; + node->refs++; + } + } + /* * If asked for replace, put the old table. data->nodes[] holds both * old and new nodes at this point. From ef901d211dcce1bcab6a7e7ee196504c5ae1db10 Mon Sep 17 00:00:00 2001 From: Gui-Dong Han Date: Fri, 28 Nov 2025 20:47:09 +0800 Subject: [PATCH 1422/2333] hwmon: (max16065) Use local variable to avoid TOCTOU commit b8d5acdcf525f44e521ca4ef51dce4dac403dab4 upstream. In max16065_current_show, data->curr_sense is read twice: once for the error check and again for the calculation. Since i2c_smbus_read_byte_data returns negative error codes on failure, if the data changes to an error code between the check and the use, ADC_TO_CURR results in an incorrect calculation. Read data->curr_sense into a local variable to ensure consistency. Note that data->curr_gain is constant and safe to access directly. This aligns max16065_current_show with max16065_input_show, which already uses a local variable for the same reason. Link: https://lore.kernel.org/all/CALbr=LYJ_ehtp53HXEVkSpYoub+XYSTU8Rg=o1xxMJ8=5z8B-g@mail.gmail.com/ Fixes: f5bae2642e3d ("hwmon: Driver for MAX16065 System Manager and compatibles") Cc: stable@vger.kernel.org Signed-off-by: Gui-Dong Han Link: https://lore.kernel.org/r/20251128124709.3876-1-hanguidong02@gmail.com Signed-off-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/max16065.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/hwmon/max16065.c b/drivers/hwmon/max16065.c index 0ccb5eb596fc4..4c9e7892a73c1 100644 --- a/drivers/hwmon/max16065.c +++ b/drivers/hwmon/max16065.c @@ -216,12 +216,13 @@ static ssize_t max16065_current_show(struct device *dev, struct device_attribute *da, char *buf) { struct max16065_data *data = max16065_update_device(dev); + int curr_sense = data->curr_sense; - if (unlikely(data->curr_sense < 0)) - return data->curr_sense; + if (unlikely(curr_sense < 0)) + return curr_sense; return sysfs_emit(buf, "%d\n", - ADC_TO_CURR(data->curr_sense, data->curr_gain)); + ADC_TO_CURR(curr_sense, data->curr_gain)); } static ssize_t max16065_limit_store(struct device *dev, From ffd46e7f2b87a873bd18db946d61e3466f3ca82f Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 27 Nov 2025 14:43:51 +0100 Subject: [PATCH 1423/2333] hwmon: (max6697) fix regmap leak on probe failure commit 02f0ad8e8de8cf5344f8f0fa26d9529b8339da47 upstream. The i2c regmap allocated during probe is never freed. Switch to using the device managed allocator so that the regmap is released on probe failures (e.g. probe deferral) and on driver unbind. Fixes: 3a2a8cc3fe24 ("hwmon: (max6697) Convert to use regmap") Cc: stable@vger.kernel.org # 6.12 Cc: Guenter Roeck Signed-off-by: Johan Hovold Link: https://lore.kernel.org/r/20251127134351.1585-1-johan@kernel.org Signed-off-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/max6697.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hwmon/max6697.c b/drivers/hwmon/max6697.c index 0735a1d2c20fd..6926d787b5ad1 100644 --- a/drivers/hwmon/max6697.c +++ b/drivers/hwmon/max6697.c @@ -548,7 +548,7 @@ static int max6697_probe(struct i2c_client *client) struct regmap *regmap; int err; - regmap = regmap_init_i2c(client, &max6697_regmap_config); + regmap = devm_regmap_init_i2c(client, &max6697_regmap_config); if (IS_ERR(regmap)) return PTR_ERR(regmap); From c8cf0c2bdcccc6634b6915ff793b844e12436680 Mon Sep 17 00:00:00 2001 From: Gui-Dong Han Date: Wed, 3 Dec 2025 02:01:05 +0800 Subject: [PATCH 1424/2333] hwmon: (w83791d) Convert macros to functions to avoid TOCTOU commit 670d7ef945d3a84683594429aea6ab2cdfa5ceb4 upstream. The macro FAN_FROM_REG evaluates its arguments multiple times. When used in lockless contexts involving shared driver data, this leads to Time-of-Check to Time-of-Use (TOCTOU) race conditions, potentially causing divide-by-zero errors. Convert the macro to a static function. This guarantees that arguments are evaluated only once (pass-by-value), preventing the race conditions. Additionally, in store_fan_div, move the calculation of the minimum limit inside the update lock. This ensures that the read-modify-write sequence operates on consistent data. Adhere to the principle of minimal changes by only converting macros that evaluate arguments multiple times and are used in lockless contexts. Link: https://lore.kernel.org/all/CALbr=LYJ_ehtp53HXEVkSpYoub+XYSTU8Rg=o1xxMJ8=5z8B-g@mail.gmail.com/ Fixes: 9873964d6eb2 ("[PATCH] HWMON: w83791d: New hardware monitoring driver for the Winbond W83791D") Cc: stable@vger.kernel.org Signed-off-by: Gui-Dong Han Link: https://lore.kernel.org/r/20251202180105.12842-1-hanguidong02@gmail.com Signed-off-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/w83791d.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/drivers/hwmon/w83791d.c b/drivers/hwmon/w83791d.c index ace854b370a05..996e36951f9da 100644 --- a/drivers/hwmon/w83791d.c +++ b/drivers/hwmon/w83791d.c @@ -218,9 +218,14 @@ static u8 fan_to_reg(long rpm, int div) return clamp_val((1350000 + rpm * div / 2) / (rpm * div), 1, 254); } -#define FAN_FROM_REG(val, div) ((val) == 0 ? -1 : \ - ((val) == 255 ? 0 : \ - 1350000 / ((val) * (div)))) +static int fan_from_reg(int val, int div) +{ + if (val == 0) + return -1; + if (val == 255) + return 0; + return 1350000 / (val * div); +} /* for temp1 which is 8-bit resolution, LSB = 1 degree Celsius */ #define TEMP1_FROM_REG(val) ((val) * 1000) @@ -521,7 +526,7 @@ static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \ struct w83791d_data *data = w83791d_update_device(dev); \ int nr = sensor_attr->index; \ return sprintf(buf, "%d\n", \ - FAN_FROM_REG(data->reg[nr], DIV_FROM_REG(data->fan_div[nr]))); \ + fan_from_reg(data->reg[nr], DIV_FROM_REG(data->fan_div[nr]))); \ } show_fan_reg(fan); @@ -585,10 +590,10 @@ static ssize_t store_fan_div(struct device *dev, struct device_attribute *attr, if (err) return err; + mutex_lock(&data->update_lock); /* Save fan_min */ - min = FAN_FROM_REG(data->fan_min[nr], DIV_FROM_REG(data->fan_div[nr])); + min = fan_from_reg(data->fan_min[nr], DIV_FROM_REG(data->fan_div[nr])); - mutex_lock(&data->update_lock); data->fan_div[nr] = div_to_reg(nr, val); switch (nr) { From 4fc2f8fbfdd43257c9a90b6730e80c0dc952575c Mon Sep 17 00:00:00 2001 From: Gui-Dong Han Date: Fri, 28 Nov 2025 20:38:16 +0800 Subject: [PATCH 1425/2333] hwmon: (w83l786ng) Convert macros to functions to avoid TOCTOU commit 07272e883fc61574b8367d44de48917f622cdd83 upstream. The macros FAN_FROM_REG and TEMP_FROM_REG evaluate their arguments multiple times. When used in lockless contexts involving shared driver data, this causes Time-of-Check to Time-of-Use (TOCTOU) race conditions. Convert the macros to static functions. This guarantees that arguments are evaluated only once (pass-by-value), preventing the race conditions. Adhere to the principle of minimal changes by only converting macros that evaluate arguments multiple times and are used in lockless contexts. Link: https://lore.kernel.org/all/CALbr=LYJ_ehtp53HXEVkSpYoub+XYSTU8Rg=o1xxMJ8=5z8B-g@mail.gmail.com/ Fixes: 85f03bccd6e0 ("hwmon: Add support for Winbond W83L786NG/NR") Cc: stable@vger.kernel.org Signed-off-by: Gui-Dong Han Link: https://lore.kernel.org/r/20251128123816.3670-1-hanguidong02@gmail.com Signed-off-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/w83l786ng.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/drivers/hwmon/w83l786ng.c b/drivers/hwmon/w83l786ng.c index 9b81bd406e059..1d9109ca1585e 100644 --- a/drivers/hwmon/w83l786ng.c +++ b/drivers/hwmon/w83l786ng.c @@ -76,15 +76,25 @@ FAN_TO_REG(long rpm, int div) return clamp_val((1350000 + rpm * div / 2) / (rpm * div), 1, 254); } -#define FAN_FROM_REG(val, div) ((val) == 0 ? -1 : \ - ((val) == 255 ? 0 : \ - 1350000 / ((val) * (div)))) +static int fan_from_reg(int val, int div) +{ + if (val == 0) + return -1; + if (val == 255) + return 0; + return 1350000 / (val * div); +} /* for temp */ #define TEMP_TO_REG(val) (clamp_val(((val) < 0 ? (val) + 0x100 * 1000 \ : (val)) / 1000, 0, 0xff)) -#define TEMP_FROM_REG(val) (((val) & 0x80 ? \ - (val) - 0x100 : (val)) * 1000) + +static int temp_from_reg(int val) +{ + if (val & 0x80) + return (val - 0x100) * 1000; + return val * 1000; +} /* * The analog voltage inputs have 8mV LSB. Since the sysfs output is @@ -280,7 +290,7 @@ static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \ int nr = to_sensor_dev_attr(attr)->index; \ struct w83l786ng_data *data = w83l786ng_update_device(dev); \ return sprintf(buf, "%d\n", \ - FAN_FROM_REG(data->reg[nr], DIV_FROM_REG(data->fan_div[nr]))); \ + fan_from_reg(data->reg[nr], DIV_FROM_REG(data->fan_div[nr]))); \ } show_fan_reg(fan); @@ -347,7 +357,7 @@ store_fan_div(struct device *dev, struct device_attribute *attr, /* Save fan_min */ mutex_lock(&data->update_lock); - min = FAN_FROM_REG(data->fan_min[nr], DIV_FROM_REG(data->fan_div[nr])); + min = fan_from_reg(data->fan_min[nr], DIV_FROM_REG(data->fan_div[nr])); data->fan_div[nr] = DIV_TO_REG(val); @@ -409,7 +419,7 @@ show_temp(struct device *dev, struct device_attribute *attr, char *buf) int nr = sensor_attr->nr; int index = sensor_attr->index; struct w83l786ng_data *data = w83l786ng_update_device(dev); - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[nr][index])); + return sprintf(buf, "%d\n", temp_from_reg(data->temp[nr][index])); } static ssize_t From c2423add62422d8b74b7d7d6e40cd0b1dba188cd Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Fri, 14 Nov 2025 15:02:25 +0100 Subject: [PATCH 1426/2333] ARM: dts: microchip: sama5d2: fix spi flexcom fifo size to 32 commit 7d5864dc5d5ea6a35983dd05295fb17f2f2f44ce upstream. Unlike standalone spi peripherals, on sama5d2, the flexcom spi have fifo size of 32 data. Fix flexcom/spi nodes where this property is wrong. Fixes: 6b9a3584c7ed ("ARM: dts: at91: sama5d2: Add missing flexcom definitions") Cc: stable@vger.kernel.org # 5.8+ Signed-off-by: Nicolas Ferre Link: https://lore.kernel.org/r/20251114140225.30372-1-nicolas.ferre@microchip.com Signed-off-by: Claudiu Beznea Signed-off-by: Greg Kroah-Hartman --- arch/arm/boot/dts/microchip/sama5d2.dtsi | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/arm/boot/dts/microchip/sama5d2.dtsi b/arch/arm/boot/dts/microchip/sama5d2.dtsi index 17430d7f20555..fde890f18d201 100644 --- a/arch/arm/boot/dts/microchip/sama5d2.dtsi +++ b/arch/arm/boot/dts/microchip/sama5d2.dtsi @@ -571,7 +571,7 @@ AT91_XDMAC_DT_PER_IF(1) | AT91_XDMAC_DT_PERID(12))>; dma-names = "tx", "rx"; - atmel,fifo-size = <16>; + atmel,fifo-size = <32>; status = "disabled"; }; @@ -642,7 +642,7 @@ AT91_XDMAC_DT_PER_IF(1) | AT91_XDMAC_DT_PERID(14))>; dma-names = "tx", "rx"; - atmel,fifo-size = <16>; + atmel,fifo-size = <32>; status = "disabled"; }; @@ -854,7 +854,7 @@ AT91_XDMAC_DT_PER_IF(1) | AT91_XDMAC_DT_PERID(16))>; dma-names = "tx", "rx"; - atmel,fifo-size = <16>; + atmel,fifo-size = <32>; status = "disabled"; }; @@ -925,7 +925,7 @@ AT91_XDMAC_DT_PER_IF(1) | AT91_XDMAC_DT_PERID(18))>; dma-names = "tx", "rx"; - atmel,fifo-size = <16>; + atmel,fifo-size = <32>; status = "disabled"; }; @@ -997,7 +997,7 @@ AT91_XDMAC_DT_PER_IF(1) | AT91_XDMAC_DT_PERID(20))>; dma-names = "tx", "rx"; - atmel,fifo-size = <16>; + atmel,fifo-size = <32>; status = "disabled"; }; From 699d66165f6c86ae9127b626045372b7abfb2918 Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Fri, 14 Nov 2025 11:33:12 +0100 Subject: [PATCH 1427/2333] ARM: dts: microchip: sama7d65: fix uart fifo size to 32 commit 1f591be0a02c697f65a21be35f1d74117bbf4be2 upstream. On some flexcom nodes related to uart, the fifo sizes were wrong: fix them to 32 data. Note that product datasheet is being reviewed to fix inconsistency, but this value is validated by product's designers. Fixes: 261dcfad1b59 ("ARM: dts: microchip: add sama7d65 SoC DT") Fixes: b51e4aea3ecf ("ARM: dts: microchip: sama7d65: Add FLEXCOMs to sama7d65 SoC") Cc: stable@vger.kernel.org # 6.16+ Signed-off-by: Nicolas Ferre Link: https://lore.kernel.org/r/20251114103313.20220-1-nicolas.ferre@microchip.com Signed-off-by: Claudiu Beznea Signed-off-by: Greg Kroah-Hartman --- arch/arm/boot/dts/microchip/sama7d65.dtsi | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm/boot/dts/microchip/sama7d65.dtsi b/arch/arm/boot/dts/microchip/sama7d65.dtsi index e53e2dd6d530c..cd2cf9a6f40b8 100644 --- a/arch/arm/boot/dts/microchip/sama7d65.dtsi +++ b/arch/arm/boot/dts/microchip/sama7d65.dtsi @@ -557,7 +557,7 @@ dma-names = "tx", "rx"; atmel,use-dma-rx; atmel,use-dma-tx; - atmel,fifo-size = <16>; + atmel,fifo-size = <32>; atmel,usart-mode = ; status = "disabled"; }; @@ -618,7 +618,7 @@ clocks = <&pmc PMC_TYPE_PERIPHERAL 40>; clock-names = "usart"; atmel,usart-mode = ; - atmel,fifo-size = <16>; + atmel,fifo-size = <32>; status = "disabled"; }; }; @@ -643,7 +643,7 @@ dma-names = "tx", "rx"; atmel,use-dma-rx; atmel,use-dma-tx; - atmel,fifo-size = <16>; + atmel,fifo-size = <32>; atmel,usart-mode = ; status = "disabled"; }; From ce909de4416eb544a9138b3c9be14c986b8d88ae Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Fri, 14 Nov 2025 11:33:13 +0100 Subject: [PATCH 1428/2333] ARM: dts: microchip: sama7g5: fix uart fifo size to 32 commit 5654889a94b0de5ad6ceae3793e7f5e0b61b50b6 upstream. On some flexcom nodes related to uart, the fifo sizes were wrong: fix them to 32 data. Fixes: 7540629e2fc7 ("ARM: dts: at91: add sama7g5 SoC DT and sama7g5-ek") Cc: stable@vger.kernel.org # 5.15+ Signed-off-by: Nicolas Ferre Link: https://lore.kernel.org/r/20251114103313.20220-2-nicolas.ferre@microchip.com Signed-off-by: Claudiu Beznea Signed-off-by: Greg Kroah-Hartman --- arch/arm/boot/dts/microchip/sama7g5.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/microchip/sama7g5.dtsi b/arch/arm/boot/dts/microchip/sama7g5.dtsi index 381cbcfcb34a1..03ef3d9aaeec6 100644 --- a/arch/arm/boot/dts/microchip/sama7g5.dtsi +++ b/arch/arm/boot/dts/microchip/sama7g5.dtsi @@ -824,7 +824,7 @@ dma-names = "tx", "rx"; atmel,use-dma-rx; atmel,use-dma-tx; - atmel,fifo-size = <16>; + atmel,fifo-size = <32>; status = "disabled"; }; }; @@ -850,7 +850,7 @@ dma-names = "tx", "rx"; atmel,use-dma-rx; atmel,use-dma-tx; - atmel,fifo-size = <16>; + atmel,fifo-size = <32>; status = "disabled"; }; }; From bf58ef1c4cd3cd9cfd205f0d3e3bf70085a52e31 Mon Sep 17 00:00:00 2001 From: Damien Le Moal Date: Wed, 5 Nov 2025 06:22:36 +0900 Subject: [PATCH 1429/2333] block: freeze queue when updating zone resources commit bba4322e3f303b2d656e748be758320b567f046f upstream. Modify disk_update_zone_resources() to freeze the device queue before updating the number of zones, zone capacity and other zone related resources. The locking order resulting from the call to queue_limits_commit_update_frozen() is preserved, that is, the queue limits lock is first taken by calling queue_limits_start_update() before freezing the queue, and the queue is unfrozen after executing queue_limits_commit_update(), which replaces the call to queue_limits_commit_update_frozen(). This change ensures that there are no in-flights I/Os when the zone resources are updated due to a zone revalidation. In case of error when the limits are applied, directly call disk_free_zone_resources() from disk_update_zone_resources() while the disk queue is still frozen to avoid needing to freeze & unfreeze the queue again in blk_revalidate_disk_zones(), thus simplifying that function code a little. Fixes: 0b83c86b444a ("block: Prevent potential deadlock in blk_revalidate_disk_zones()") Cc: stable@vger.kernel.org Signed-off-by: Damien Le Moal Reviewed-by: Christoph Hellwig Reviewed-by: Johannes Thumshirn Reviewed-by: Chaitanya Kulkarni Reviewed-by: Hannes Reinecke Reviewed-by: Martin K. Petersen Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman --- block/blk-zoned.c | 42 ++++++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/block/blk-zoned.c b/block/blk-zoned.c index 5e2a5788dc3b2..f60af668ab81e 100644 --- a/block/blk-zoned.c +++ b/block/blk-zoned.c @@ -1516,8 +1516,13 @@ static int disk_update_zone_resources(struct gendisk *disk, { struct request_queue *q = disk->queue; unsigned int nr_seq_zones, nr_conv_zones; - unsigned int pool_size; + unsigned int pool_size, memflags; struct queue_limits lim; + int ret = 0; + + lim = queue_limits_start_update(q); + + memflags = blk_mq_freeze_queue(q); disk->nr_zones = args->nr_zones; disk->zone_capacity = args->zone_capacity; @@ -1527,11 +1532,10 @@ static int disk_update_zone_resources(struct gendisk *disk, if (nr_conv_zones >= disk->nr_zones) { pr_warn("%s: Invalid number of conventional zones %u / %u\n", disk->disk_name, nr_conv_zones, disk->nr_zones); - return -ENODEV; + ret = -ENODEV; + goto unfreeze; } - lim = queue_limits_start_update(q); - /* * Some devices can advertize zone resource limits that are larger than * the number of sequential zones of the zoned block device, e.g. a @@ -1568,7 +1572,15 @@ static int disk_update_zone_resources(struct gendisk *disk, } commit: - return queue_limits_commit_update_frozen(q, &lim); + ret = queue_limits_commit_update(q, &lim); + +unfreeze: + if (ret) + disk_free_zone_resources(disk); + + blk_mq_unfreeze_queue(q, memflags); + + return ret; } static int blk_revalidate_conv_zone(struct blk_zone *zone, unsigned int idx, @@ -1733,7 +1745,7 @@ int blk_revalidate_disk_zones(struct gendisk *disk) sector_t zone_sectors = q->limits.chunk_sectors; sector_t capacity = get_capacity(disk); struct blk_revalidate_zone_args args = { }; - unsigned int noio_flag; + unsigned int memflags, noio_flag; int ret = -ENOMEM; if (WARN_ON_ONCE(!blk_queue_is_zoned(q))) @@ -1783,20 +1795,14 @@ int blk_revalidate_disk_zones(struct gendisk *disk) ret = -ENODEV; } - /* - * Set the new disk zone parameters only once the queue is frozen and - * all I/Os are completed. - */ if (ret > 0) - ret = disk_update_zone_resources(disk, &args); - else - pr_warn("%s: failed to revalidate zones\n", disk->disk_name); - if (ret) { - unsigned int memflags = blk_mq_freeze_queue(q); + return disk_update_zone_resources(disk, &args); - disk_free_zone_resources(disk); - blk_mq_unfreeze_queue(q, memflags); - } + pr_warn("%s: failed to revalidate zones\n", disk->disk_name); + + memflags = blk_mq_freeze_queue(q); + disk_free_zone_resources(disk); + blk_mq_unfreeze_queue(q, memflags); return ret; } From f6c08d3aa441bbc1956e9d65f1cbb89113a5aa8a Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 20 Oct 2025 06:53:10 +0200 Subject: [PATCH 1430/2333] iommu/mediatek: fix use-after-free on probe deferral commit de83d4617f9fe059623e97acf7e1e10d209625b5 upstream. The driver is dropping the references taken to the larb devices during probe after successful lookup as well as on errors. This can potentially lead to a use-after-free in case a larb device has not yet been bound to its driver so that the iommu driver probe defers. Fix this by keeping the references as expected while the iommu driver is bound. Fixes: 26593928564c ("iommu/mediatek: Add error path for loop of mm_dts_parse") Cc: stable@vger.kernel.org Cc: Yong Wu Acked-by: Robin Murphy Signed-off-by: Johan Hovold Reviewed-by: Yong Wu Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Joerg Roedel Signed-off-by: Greg Kroah-Hartman --- drivers/iommu/mtk_iommu.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c index 0e0285348d2b8..319974557f325 100644 --- a/drivers/iommu/mtk_iommu.c +++ b/drivers/iommu/mtk_iommu.c @@ -1211,16 +1211,19 @@ static int mtk_iommu_mm_dts_parse(struct device *dev, struct component_match **m } component_match_add(dev, match, component_compare_dev, &plarbdev->dev); - platform_device_put(plarbdev); } - if (!frst_avail_smicomm_node) - return -EINVAL; + if (!frst_avail_smicomm_node) { + ret = -EINVAL; + goto err_larbdev_put; + } pcommdev = of_find_device_by_node(frst_avail_smicomm_node); of_node_put(frst_avail_smicomm_node); - if (!pcommdev) - return -ENODEV; + if (!pcommdev) { + ret = -ENODEV; + goto err_larbdev_put; + } data->smicomm_dev = &pcommdev->dev; link = device_link_add(data->smicomm_dev, dev, @@ -1228,7 +1231,8 @@ static int mtk_iommu_mm_dts_parse(struct device *dev, struct component_match **m platform_device_put(pcommdev); if (!link) { dev_err(dev, "Unable to link %s.\n", dev_name(data->smicomm_dev)); - return -EINVAL; + ret = -EINVAL; + goto err_larbdev_put; } return 0; @@ -1400,8 +1404,12 @@ static int mtk_iommu_probe(struct platform_device *pdev) iommu_device_sysfs_remove(&data->iommu); out_list_del: list_del(&data->list); - if (MTK_IOMMU_IS_TYPE(data->plat_data, MTK_IOMMU_TYPE_MM)) + if (MTK_IOMMU_IS_TYPE(data->plat_data, MTK_IOMMU_TYPE_MM)) { device_link_remove(data->smicomm_dev, dev); + + for (i = 0; i < MTK_LARB_NR_MAX; i++) + put_device(data->larb_imu[i].dev); + } out_runtime_disable: pm_runtime_disable(dev); return ret; @@ -1421,6 +1429,9 @@ static void mtk_iommu_remove(struct platform_device *pdev) if (MTK_IOMMU_IS_TYPE(data->plat_data, MTK_IOMMU_TYPE_MM)) { device_link_remove(data->smicomm_dev, &pdev->dev); component_master_del(&pdev->dev, &mtk_iommu_com_ops); + + for (i = 0; i < MTK_LARB_NR_MAX; i++) + put_device(data->larb_imu[i].dev); } pm_runtime_disable(&pdev->dev); for (i = 0; i < data->plat_data->banks_num; i++) { From a6d1f1ace16d0e777a85f84267160052d3499b6e Mon Sep 17 00:00:00 2001 From: Joanne Koong Date: Tue, 25 Nov 2025 10:13:47 -0800 Subject: [PATCH 1431/2333] fuse: fix io-uring list corruption for terminated non-committed requests commit 95c39eef7c2b666026c69ab5b30471da94ea2874 upstream. When a request is terminated before it has been committed, the request is not removed from the queue's list. This leaves a dangling list entry that leads to list corruption and use-after-free issues. Remove the request from the queue's list for terminated non-committed requests. Signed-off-by: Joanne Koong Fixes: c090c8abae4b ("fuse: Add io-uring sqe commit and fetch support") Cc: stable@vger.kernel.org Reviewed-by: Bernd Schubert Signed-off-by: Miklos Szeredi Signed-off-by: Greg Kroah-Hartman --- fs/fuse/dev_uring.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/fuse/dev_uring.c b/fs/fuse/dev_uring.c index f6b12aebb8bbe..d2bc05a8b3d10 100644 --- a/fs/fuse/dev_uring.c +++ b/fs/fuse/dev_uring.c @@ -86,6 +86,7 @@ static void fuse_uring_req_end(struct fuse_ring_ent *ent, struct fuse_req *req, lockdep_assert_not_held(&queue->lock); spin_lock(&queue->lock); ent->fuse_req = NULL; + list_del_init(&req->list); if (test_bit(FR_BACKGROUND, &req->flags)) { queue->active_background--; spin_lock(&fc->bg_lock); From e0d6de83a4cc22bbac72713f3a58121af36cc411 Mon Sep 17 00:00:00 2001 From: Joanne Koong Date: Fri, 10 Oct 2025 15:07:38 -0700 Subject: [PATCH 1432/2333] fuse: fix readahead reclaim deadlock commit bd5603eaae0aabf527bfb3ce1bb07e979ce5bd50 upstream. Commit e26ee4efbc79 ("fuse: allocate ff->release_args only if release is needed") skips allocating ff->release_args if the server does not implement open. However in doing so, fuse_prepare_release() now skips grabbing the reference on the inode, which makes it possible for an inode to be evicted from the dcache while there are inflight readahead requests. This causes a deadlock if the server triggers reclaim while servicing the readahead request and reclaim attempts to evict the inode of the file being read ahead. Since the folio is locked during readahead, when reclaim evicts the fuse inode and fuse_evict_inode() attempts to remove all folios associated with the inode from the page cache (truncate_inode_pages_range()), reclaim will block forever waiting for the lock since readahead cannot relinquish the lock because it is itself blocked in reclaim: >>> stack_trace(1504735) folio_wait_bit_common (mm/filemap.c:1308:4) folio_lock (./include/linux/pagemap.h:1052:3) truncate_inode_pages_range (mm/truncate.c:336:10) fuse_evict_inode (fs/fuse/inode.c:161:2) evict (fs/inode.c:704:3) dentry_unlink_inode (fs/dcache.c:412:3) __dentry_kill (fs/dcache.c:615:3) shrink_kill (fs/dcache.c:1060:12) shrink_dentry_list (fs/dcache.c:1087:3) prune_dcache_sb (fs/dcache.c:1168:2) super_cache_scan (fs/super.c:221:10) do_shrink_slab (mm/shrinker.c:435:9) shrink_slab (mm/shrinker.c:626:10) shrink_node (mm/vmscan.c:5951:2) shrink_zones (mm/vmscan.c:6195:3) do_try_to_free_pages (mm/vmscan.c:6257:3) do_swap_page (mm/memory.c:4136:11) handle_pte_fault (mm/memory.c:5562:10) handle_mm_fault (mm/memory.c:5870:9) do_user_addr_fault (arch/x86/mm/fault.c:1338:10) handle_page_fault (arch/x86/mm/fault.c:1481:3) exc_page_fault (arch/x86/mm/fault.c:1539:2) asm_exc_page_fault+0x22/0x27 Fix this deadlock by allocating ff->release_args and grabbing the reference on the inode when preparing the file for release even if the server does not implement open. The inode reference will be dropped when the last reference on the fuse file is dropped (see fuse_file_put() -> fuse_release_end()). Fixes: e26ee4efbc79 ("fuse: allocate ff->release_args only if release is needed") Cc: stable@vger.kernel.org Signed-off-by: Joanne Koong Reported-by: Omar Sandoval Signed-off-by: Miklos Szeredi Signed-off-by: Greg Kroah-Hartman --- fs/fuse/file.c | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/fs/fuse/file.c b/fs/fuse/file.c index bb4ecfd469a5e..6014d588845cd 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -110,7 +110,9 @@ static void fuse_file_put(struct fuse_file *ff, bool sync) fuse_file_io_release(ff, ra->inode); if (!args) { - /* Do nothing when server does not implement 'open' */ + /* Do nothing when server does not implement 'opendir' */ + } else if (args->opcode == FUSE_RELEASE && ff->fm->fc->no_open) { + fuse_release_end(ff->fm, args, 0); } else if (sync) { fuse_simple_request(ff->fm, args); fuse_release_end(ff->fm, args, 0); @@ -131,8 +133,17 @@ struct fuse_file *fuse_file_open(struct fuse_mount *fm, u64 nodeid, struct fuse_file *ff; int opcode = isdir ? FUSE_OPENDIR : FUSE_OPEN; bool open = isdir ? !fc->no_opendir : !fc->no_open; + bool release = !isdir || open; - ff = fuse_file_alloc(fm, open); + /* + * ff->args->release_args still needs to be allocated (so we can hold an + * inode reference while there are pending inflight file operations when + * ->release() is called, see fuse_prepare_release()) even if + * fc->no_open is set else it becomes possible for reclaim to deadlock + * if while servicing the readahead request the server triggers reclaim + * and reclaim evicts the inode of the file being read ahead. + */ + ff = fuse_file_alloc(fm, release); if (!ff) return ERR_PTR(-ENOMEM); @@ -152,13 +163,14 @@ struct fuse_file *fuse_file_open(struct fuse_mount *fm, u64 nodeid, fuse_file_free(ff); return ERR_PTR(err); } else { - /* No release needed */ - kfree(ff->args); - ff->args = NULL; - if (isdir) + if (isdir) { + /* No release needed */ + kfree(ff->args); + ff->args = NULL; fc->no_opendir = 1; - else + } else { fc->no_open = 1; + } } } From b79938863f436960eff209130f025c4bd3026bf8 Mon Sep 17 00:00:00 2001 From: Cheng Ding Date: Tue, 21 Oct 2025 22:46:42 +0200 Subject: [PATCH 1433/2333] fuse: missing copy_finish in fuse-over-io-uring argument copies commit 6e0d7f7f4a43ac8868e98c87ecf48805aa8c24dd upstream. Fix a possible reference count leak of payload pages during fuse argument copies. [Joanne: simplified error cleanup] Fixes: c090c8abae4b ("fuse: Add io-uring sqe commit and fetch support") Cc: stable@vger.kernel.org # v6.14 Signed-off-by: Cheng Ding Signed-off-by: Bernd Schubert Reviewed-by: Joanne Koong Signed-off-by: Miklos Szeredi Signed-off-by: Greg Kroah-Hartman --- fs/fuse/dev.c | 2 +- fs/fuse/dev_uring.c | 5 ++++- fs/fuse/fuse_dev_i.h | 1 + 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index 132f38619d707..49b18d7accb39 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -846,7 +846,7 @@ void fuse_copy_init(struct fuse_copy_state *cs, bool write, } /* Unmap and put previous page of userspace buffer */ -static void fuse_copy_finish(struct fuse_copy_state *cs) +void fuse_copy_finish(struct fuse_copy_state *cs) { if (cs->currbuf) { struct pipe_buffer *buf = cs->currbuf; diff --git a/fs/fuse/dev_uring.c b/fs/fuse/dev_uring.c index d2bc05a8b3d10..f0846694822dd 100644 --- a/fs/fuse/dev_uring.c +++ b/fs/fuse/dev_uring.c @@ -599,7 +599,9 @@ static int fuse_uring_copy_from_ring(struct fuse_ring *ring, cs.is_uring = true; cs.req = req; - return fuse_copy_out_args(&cs, args, ring_in_out.payload_sz); + err = fuse_copy_out_args(&cs, args, ring_in_out.payload_sz); + fuse_copy_finish(&cs); + return err; } /* @@ -650,6 +652,7 @@ static int fuse_uring_args_to_ring(struct fuse_ring *ring, struct fuse_req *req, /* copy the payload */ err = fuse_copy_args(&cs, num_args, args->in_pages, (struct fuse_arg *)in_args, 0); + fuse_copy_finish(&cs); if (err) { pr_info_ratelimited("%s fuse_copy_args failed\n", __func__); return err; diff --git a/fs/fuse/fuse_dev_i.h b/fs/fuse/fuse_dev_i.h index 6e8373f970409..134bf44aff0d3 100644 --- a/fs/fuse/fuse_dev_i.h +++ b/fs/fuse/fuse_dev_i.h @@ -62,6 +62,7 @@ void fuse_dev_end_requests(struct list_head *head); void fuse_copy_init(struct fuse_copy_state *cs, bool write, struct iov_iter *iter); +void fuse_copy_finish(struct fuse_copy_state *cs); int fuse_copy_args(struct fuse_copy_state *cs, unsigned int numargs, unsigned int argpages, struct fuse_arg *args, int zeroing); From a607c8f744340ad2c2486d46e96b66df47caffba Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 2 Jan 2026 12:57:31 +0100 Subject: [PATCH 1434/2333] Linux 6.18.3 Link: https://lore.kernel.org/r/20251229160724.139406961@linuxfoundation.org Tested-by: Brett A C Sheffield Tested-by: Salvatore Bonaccorso Tested-by: Ronald Warsow Tested-by: Takeshi Ogasawara Tested-by: Ron Economos Tested-by: Peter Schneider Tested-by: Justin M. Forbes Tested-by: Linux Kernel Functional Testing Tested-by: Jeffrin Jose T Tested-by: Dileep Malepu dileep.debian@gmail.com Tested-by: Miguel Ojeda Tested-by: Florian Fainelli Tested-by: Jon Hunter Signed-off-by: Greg Kroah-Hartman --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index c2b5cfd2fce01..17415fdcd358d 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 VERSION = 6 PATCHLEVEL = 18 -SUBLEVEL = 2 +SUBLEVEL = 3 EXTRAVERSION = NAME = Baby Opossum Posse From 2c5bb0639325d212c731e7d54234d6c8757a245a Mon Sep 17 00:00:00 2001 From: Gaurav Kohli Date: Tue, 23 Dec 2025 18:02:20 +0530 Subject: [PATCH 1435/2333] FROMLIST: thermal: Add Remote Proc cooling driver Add a new generic driver for thermal cooling devices that control remote processors (modem, DSP, etc.) through various communication channels. This driver provides an abstraction layer between the thermal subsystem and vendor-specific remote processor communication mechanisms. Suggested-by: Amit Kucheria Signed-off-by: Gaurav Kohli Link: https://lore.kernel.org/r/20251223123227.1317244-2-gaurav.kohli@oss.qualcomm.com --- MAINTAINERS | 8 ++ drivers/thermal/Kconfig | 11 ++ drivers/thermal/Makefile | 2 + drivers/thermal/remoteproc_cooling.c | 153 +++++++++++++++++++++++++++ include/linux/remoteproc_cooling.h | 52 +++++++++ 5 files changed, 226 insertions(+) create mode 100644 drivers/thermal/remoteproc_cooling.c create mode 100644 include/linux/remoteproc_cooling.h diff --git a/MAINTAINERS b/MAINTAINERS index bfd5ce9b30049..242ebd77dda67 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -25539,6 +25539,14 @@ F: drivers/thermal/cpufreq_cooling.c F: drivers/thermal/cpuidle_cooling.c F: include/linux/cpu_cooling.h +THERMAL/REMOTEPROC_COOLING +M: Gaurav Kohli +L: linux-pm@vger.kernel.org +S: Supported +F: drivers/thermal/remoteproc_cooling.c +F: include/linux/remoteproc_cooling.h + + THERMAL/POWER_ALLOCATOR M: Lukasz Luba L: linux-pm@vger.kernel.org diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index a09c188b9ad11..c455a273a62d2 100644 --- a/drivers/thermal/Kconfig +++ b/drivers/thermal/Kconfig @@ -229,6 +229,17 @@ config PCIE_THERMAL If you want this support, you should say Y here. + +config REMOTEPROC_THERMAL + bool "Remote processor cooling support" + help + This implements a generic cooling mechanism for remote processors + (modem, DSP, etc.) that allows vendor-specific implementations to + register thermal cooling devices and provide callbacks for thermal + mitigation. + + If you want this support, you should say Y here. + config THERMAL_EMULATION bool "Thermal emulation mode support" help diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile index d7718978db245..4f4c80afb1ec4 100644 --- a/drivers/thermal/Makefile +++ b/drivers/thermal/Makefile @@ -34,6 +34,8 @@ thermal_sys-$(CONFIG_DEVFREQ_THERMAL) += devfreq_cooling.o thermal_sys-$(CONFIG_PCIE_THERMAL) += pcie_cooling.o +thermal_sys-$(CONFIG_REMOTEPROC_THERMAL) += remoteproc_cooling.o + obj-$(CONFIG_K3_THERMAL) += k3_bandgap.o k3_j72xx_bandgap.o # platform thermal drivers obj-y += broadcom/ diff --git a/drivers/thermal/remoteproc_cooling.c b/drivers/thermal/remoteproc_cooling.c new file mode 100644 index 0000000000000..b5ea200f485b8 --- /dev/null +++ b/drivers/thermal/remoteproc_cooling.c @@ -0,0 +1,153 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Remote Processor Cooling Device + * + * Copyright (c) 2025, Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define REMOTEPROC_PREFIX "rproc_" + +struct remoteproc_cooling_ops { + int (*get_max_level)(void *devdata, unsigned long *level); + int (*get_cur_level)(void *devdata, unsigned long *level); + int (*set_cur_level)(void *devdata, unsigned long level); +}; + +/** + * struct remoteproc_cdev - Remote processor cooling device + * @cdev: Thermal cooling device handle + * @ops: Vendor-specific operation callbacks + * @devdata: Private data for vendor implementation + * @np: Device tree node associated with this cooling device + * @lock: Mutex to protect cooling device operations + */ +struct remoteproc_cdev { + struct thermal_cooling_device *cdev; + const struct remoteproc_cooling_ops *ops; + void *devdata; + struct device_node *np; + struct mutex lock; +}; + +/* Thermal cooling device callbacks */ + +static int remoteproc_get_max_state(struct thermal_cooling_device *cdev, + unsigned long *state) +{ + struct remoteproc_cdev *rproc_cdev = cdev->devdata; + int ret; + + if (!rproc_cdev || !rproc_cdev->ops) + return -EINVAL; + + mutex_lock(&rproc_cdev->lock); + ret = rproc_cdev->ops->get_max_level(rproc_cdev->devdata, state); + mutex_unlock(&rproc_cdev->lock); + + return ret; +} + +static int remoteproc_get_cur_state(struct thermal_cooling_device *cdev, + unsigned long *state) +{ + struct remoteproc_cdev *rproc_cdev = cdev->devdata; + int ret; + + if (!rproc_cdev || !rproc_cdev->ops) + return -EINVAL; + + mutex_lock(&rproc_cdev->lock); + ret = rproc_cdev->ops->get_cur_level(rproc_cdev->devdata, state); + mutex_unlock(&rproc_cdev->lock); + + return ret; +} + +static int remoteproc_set_cur_state(struct thermal_cooling_device *cdev, + unsigned long state) +{ + struct remoteproc_cdev *rproc_cdev = cdev->devdata; + int ret; + + if (!rproc_cdev || !rproc_cdev->ops) + return -EINVAL; + + mutex_lock(&rproc_cdev->lock); + ret = rproc_cdev->ops->set_cur_level(rproc_cdev->devdata, state); + mutex_unlock(&rproc_cdev->lock); + + return ret; +} + +static const struct thermal_cooling_device_ops remoteproc_cooling_ops = { + .get_max_state = remoteproc_get_max_state, + .get_cur_state = remoteproc_get_cur_state, + .set_cur_state = remoteproc_set_cur_state, +}; + +struct remoteproc_cdev * +remoteproc_cooling_register(struct device_node *np, + const char *name, const struct remoteproc_cooling_ops *ops, + void *devdata) +{ + struct remoteproc_cdev *rproc_cdev; + struct thermal_cooling_device *cdev; + int ret; + + if (!name || !ops) { + return ERR_PTR(-EINVAL); + } + + rproc_cdev = kzalloc(sizeof(*rproc_cdev), GFP_KERNEL); + if (!rproc_cdev) + return ERR_PTR(-ENOMEM); + + rproc_cdev->ops = ops; + rproc_cdev->devdata = devdata; + rproc_cdev->np = np; + mutex_init(&rproc_cdev->lock); + + char *rproc_name __free(kfree) = + kasprintf(GFP_KERNEL, REMOTEPROC_PREFIX "%s", name); + /* Register with thermal framework */ + if (np) { + cdev = thermal_of_cooling_device_register(np, rproc_name, rproc_cdev, + &remoteproc_cooling_ops); + } + + if (IS_ERR(cdev)) { + ret = PTR_ERR(cdev); + goto free_rproc_cdev; + } + + rproc_cdev->cdev = cdev; + + return rproc_cdev; + +free_rproc_cdev: + kfree(rproc_cdev); + return ERR_PTR(ret); +} +EXPORT_SYMBOL_GPL(remoteproc_cooling_register); + +void remoteproc_cooling_unregister(struct remoteproc_cdev *rproc_cdev) +{ + if (!rproc_cdev) + return; + + thermal_cooling_device_unregister(rproc_cdev->cdev); + mutex_destroy(&rproc_cdev->lock); + kfree(rproc_cdev); +} +EXPORT_SYMBOL_GPL(remoteproc_cooling_unregister); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Remote Processor Cooling Device"); diff --git a/include/linux/remoteproc_cooling.h b/include/linux/remoteproc_cooling.h new file mode 100644 index 0000000000000..721912d1a5eca --- /dev/null +++ b/include/linux/remoteproc_cooling.h @@ -0,0 +1,52 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Remote Processor Cooling Device + * + * Copyright (c) 2025, Qualcomm Innovation Center + */ + +#ifndef __REMOTEPROC_COOLING_H__ +#define __REMOTEPROC_COOLING_H__ + +#include + +struct device; +struct device_node; + +struct remoteproc_cooling_ops { + int (*get_max_level)(void *devdata, unsigned long *level); + int (*get_cur_level)(void *devdata, unsigned long *level); + int (*set_cur_level)(void *devdata, unsigned long level); +}; + +struct remoteproc_cdev; + +#ifdef CONFIG_REMOTEPROC_THERMAL + +struct remoteproc_cdev * +remoteproc_cooling_register(struct device_node *np, + const char *name, + const struct remoteproc_cooling_ops *ops, + void *devdata); + +void remoteproc_cooling_unregister(struct remoteproc_cdev *rproc_cdev); + +#else /* !CONFIG_REMOTEPROC_THERMAL */ + +static inline struct remoteproc_cdev * +remoteproc_cooling_register(struct device_node *np, + const char *name, + const struct remoteproc_cooling_ops *ops, + void *devdata) +{ + return ERR_PTR(-EINVAL); +} + +static inline void +remoteproc_cooling_unregister(struct remoteproc_cdev *rproc_cdev) +{ +} + +#endif /* CONFIG_REMOTEPROC_THERMAL */ + +#endif /* __REMOTEPROC_COOLING_H__ */ From 8c11c7cc84c6faa2719d4b12f9217a3b2eba391a Mon Sep 17 00:00:00 2001 From: Gaurav Kohli Date: Tue, 23 Dec 2025 18:02:22 +0530 Subject: [PATCH 1436/2333] FROMLIST: dt-bindings: thermal: Add qcom,qmi-cooling yaml bindings The cooling subnode of a remoteproc represents a client of the Thermal Mitigation Device QMI service running on it. Each subnode of the cooling node represents a single control exposed by the service. Add maintainer name also and update this binding for cdsp substem. Co-developed-by: Casey Connolly Signed-off-by: Casey Connolly Signed-off-by: Gaurav Kohli Link: https://lore.kernel.org/r/20251223123227.1317244-4-gaurav.kohli@oss.qualcomm.com --- .../bindings/remoteproc/qcom,pas-common.yaml | 6 ++ .../bindings/thermal/qcom,qmi-cooling.yaml | 99 +++++++++++++++++++ 2 files changed, 105 insertions(+) create mode 100644 Documentation/devicetree/bindings/thermal/qcom,qmi-cooling.yaml diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml index 68c17bf18987c..6a736161d5aed 100644 --- a/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml +++ b/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml @@ -80,6 +80,12 @@ properties: and devices related to the ADSP. unevaluatedProperties: false + cooling: + $ref: /schemas/thermal/qcom,qmi-cooling.yaml# + description: + Cooling subnode which represents the cooling devices exposed by the Modem. + unevaluatedProperties: false + required: - clocks - clock-names diff --git a/Documentation/devicetree/bindings/thermal/qcom,qmi-cooling.yaml b/Documentation/devicetree/bindings/thermal/qcom,qmi-cooling.yaml new file mode 100644 index 0000000000000..90b46712d2412 --- /dev/null +++ b/Documentation/devicetree/bindings/thermal/qcom,qmi-cooling.yaml @@ -0,0 +1,99 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +# Copyright 2023 (c), Linaro Limited + +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/thermal/qcom,qmi-cooling.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm QMI based thermal mitigation (TMD) cooling devices. + +maintainers: + - Caleb Connolly + - Gaurav Kohli + +description: + Qualcomm QMI-based TMD cooling devices are used to mitigate thermal conditions + across multiple remote subsystems. These devices operate based on junction temperature + sensors (TSENS) associated with thermal zones for each subsystem. + + Each subnode corresponds to a control interface for a single instance of the TMD + service running on a remote subsystem. + +definitions: + tmd: + type: object + description: | + A single Thermal Mitigation Device exposed by a remote subsystem. + properties: + label: + maxItems: 1 + "#cooling-cells": + $ref: /schemas/thermal/thermal-cooling-devices.yaml#/properties/#cooling-cells + phandle: true + + required: + - label + - "#cooling-cells" + + additionalProperties: false + +properties: + compatible: + enum: + - qcom,qmi-cooling-modem + - qcom,qmi-cooling-cdsp + + vdd: + $ref: "#/definitions/tmd" + description: + Modem processor temperature TMD + properties: + label: + const: modem + +required: + - compatible + +allOf: + - if: + properties: + compatible: + contains: + const: qcom,qmi-cooling-cdsp + then: + properties: + cdsp_sw: + $ref: "#/definitions/tmd" + description: + CDSP software TMD + properties: + label: + const: cdsp_sw + +unevaluatedProperties: false + +examples: + - | + remoteproc-cdsp { + cooling { + compatible = "qcom,qmi-cooling-cdsp"; + + cdsp_sw0: cdsp_sw { + label = "cdsp_sw"; + #cooling-cells = <2>; + }; + }; + }; + + remoteproc-cdsp1 { + cooling { + compatible = "qcom,qmi-cooling-cdsp1"; + + cdsp_sw1: cdsp_sw { + label = "cdsp_sw"; + #cooling-cells = <2>; + }; + }; + }; +... From fbd8a5623e2b7efa1bab266dd3e5282978e7e3f7 Mon Sep 17 00:00:00 2001 From: Casey Connolly Date: Tue, 23 Dec 2025 18:02:23 +0530 Subject: [PATCH 1437/2333] FROMLIST: thermal: qcom: add qmi-cooling driver The Thermal Mitigation Device (TMD) service exposes various platform specific thermal mitigations available on remote subsystems (ie the modem and cdsp). The service is exposed via the QMI messaging interface, usually over the QRTR transport. Qualcomm QMI-based TMD cooling devices are used to mitigate thermal conditions across multiple remote subsystems. These devices operate based on junction temperature sensors (TSENS) associated with thermal zones for each subsystem. Co-developed-by: Gaurav Kohli Signed-off-by: Gaurav Kohli Signed-off-by: Casey Connolly Link: https://lore.kernel.org/r/20251223123227.1317244-5-gaurav.kohli@oss.qualcomm.com --- drivers/soc/qcom/Kconfig | 13 + drivers/soc/qcom/Makefile | 1 + drivers/soc/qcom/qmi-cooling.c | 498 +++++++++++++++++++++++++++++++++ drivers/soc/qcom/qmi-cooling.h | 428 ++++++++++++++++++++++++++++ 4 files changed, 940 insertions(+) create mode 100644 drivers/soc/qcom/qmi-cooling.c create mode 100644 drivers/soc/qcom/qmi-cooling.h diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index 2caadbbcf8307..905a24b42fe69 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -124,6 +124,19 @@ config QCOM_PMIC_GLINK Say yes here to support USB-C and battery status on modern Qualcomm platforms. +config QCOM_QMI_COOLING + tristate "Qualcomm QMI cooling drivers" + depends on QCOM_RPROC_COMMON + depends on ARCH_QCOM || COMPILE_TEST + select QCOM_QMI_HELPERS + help + This enables the remote subsystem cooling devices. These cooling + devices will be used by Qualcomm chipset to place various remote + subsystem mitigations like remote processor passive mitigation, + remote subsystem voltage restriction at low temperatures etc. + The QMI cooling device will interface with remote subsystem + using Qualcomm remoteproc interface. + config QCOM_QMI_HELPERS tristate depends on NET diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile index b7f1d2a573674..b6728f54944b1 100644 --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile @@ -14,6 +14,7 @@ obj-$(CONFIG_QCOM_PMIC_GLINK) += pmic_glink.o obj-$(CONFIG_QCOM_PMIC_GLINK) += pmic_glink_altmode.o obj-$(CONFIG_QCOM_PMIC_PDCHARGER_ULOG) += pmic_pdcharger_ulog.o CFLAGS_pmic_pdcharger_ulog.o := -I$(src) +obj-$(CONFIG_QCOM_QMI_COOLING) += qmi-cooling.o obj-$(CONFIG_QCOM_QMI_HELPERS) += qmi_helpers.o qmi_helpers-y += qmi_encdec.o qmi_interface.o obj-$(CONFIG_QCOM_RAMP_CTRL) += ramp_controller.o diff --git a/drivers/soc/qcom/qmi-cooling.c b/drivers/soc/qcom/qmi-cooling.c new file mode 100644 index 0000000000000..5f3a72376033f --- /dev/null +++ b/drivers/soc/qcom/qmi-cooling.c @@ -0,0 +1,498 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2017, The Linux Foundation + * Copyright (c) 2025, Linaro Limited + * + * QMI Thermal Mitigation Device (TMD) client driver. + * This driver provides an in-kernel client to handle hot and cold thermal + * mitigations for remote subsystems (modem and DSPs) running the TMD service. + * It doesn't implement any handling of reports from remote subsystems. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "qmi-cooling.h" + +#define MODEM0_INSTANCE_ID 0x0 +#define ADSP_INSTANCE_ID 0x1 +#define CDSP_INSTANCE_ID 0x43 +#define SLPI_INSTANCE_ID 0x53 + +#define QMI_TMD_RESP_TIMEOUT msecs_to_jiffies(100) + +/** + * struct qmi_tmd_client - TMD client state + * @dev: Device associated with this client + * @name: Friendly name for the remote TMD service + * @handle: QMI connection handle + * @mutex: Lock to synchronise QMI communication + * @id: The QMI TMD service instance ID + * @cdev_list: The list of cooling devices (controls) enabled for this instance + * @svc_arrive_work: Work item for initialising the client when the TMD service + * starts. + * @connection_active: Whether or not we're connected to the QMI TMD service + */ +struct qmi_tmd_client { + struct device *dev; + const char *name; + struct qmi_handle handle; + struct mutex mutex; + u32 id; + struct list_head cdev_list; + struct work_struct svc_arrive_work; + bool connection_active; +}; + +/** + * struct qmi_tmd - A TMD cooling device + * @np: OF node associated with this control + * @type: The control type (exposed via sysfs) + * @qmi_name: The common name of this control shared by the remote subsystem + * @rproc_cdev: Remote processor cooling device handle + * @cur_state: The current cooling/warming/mitigation state + * @max_state: The maximum state + * @client: The TMD client instance this control is associated with + */ +struct qmi_tmd { + struct device_node *np; + const char *type; + char qmi_name[QMI_TMD_MITIGATION_DEV_ID_LENGTH_MAX_V01 + 1]; + struct list_head node; + struct remoteproc_cdev *rproc_cdev; + unsigned int cur_state; + unsigned int max_state; + struct qmi_tmd_client *client; +}; + +/** + * struct qmi_instance_id - QMI instance match data + * @id: The QMI instance ID + * @name: Friendly name for this instance + */ +struct qmi_instance_data { + u32 id; + const char *name; +}; + +/* Notify the remote subsystem of the requested cooling state */ +static int qmi_tmd_send_state_request(struct qmi_tmd *tmd) +{ + struct tmd_set_mitigation_level_resp_msg_v01 tmd_resp = { 0 }; + struct tmd_set_mitigation_level_req_msg_v01 req = { 0 }; + struct qmi_tmd_client *client; + struct qmi_txn txn; + int ret = 0; + + client = tmd->client; + + guard(mutex)(&client->mutex); + + /* + * This function is called by qmi_set_cur_state() which does not know if + * the QMI service is actually online. If it isn't then we noop here. + * The state is cached in tmd->cur_state and will be broadcast via + * qmi_tmd_init_control() when the service comes up. + */ + if (!client->connection_active) + return 0; + + strscpy(req.mitigation_dev_id.mitigation_dev_id, tmd->qmi_name, + QMI_TMD_MITIGATION_DEV_ID_LENGTH_MAX_V01 + 1); + req.mitigation_level = tmd->cur_state; + + ret = qmi_txn_init(&client->handle, &txn, + tmd_set_mitigation_level_resp_msg_v01_ei, &tmd_resp); + if (ret < 0) { + dev_err(client->dev, "qmi set state %d txn init failed for %s ret %d\n", + tmd->cur_state, tmd->type, ret); + return ret; + } + + ret = qmi_send_request(&client->handle, NULL, &txn, + QMI_TMD_SET_MITIGATION_LEVEL_REQ_V01, + TMD_SET_MITIGATION_LEVEL_REQ_MSG_V01_MAX_MSG_LEN, + tmd_set_mitigation_level_req_msg_v01_ei, &req); + if (ret < 0) { + dev_err(client->dev, "qmi set state %d txn send failed for %s ret %d\n", + tmd->cur_state, tmd->type, ret); + qmi_txn_cancel(&txn); + return ret; + } + + ret = qmi_txn_wait(&txn, QMI_TMD_RESP_TIMEOUT); + if (ret < 0) { + dev_err(client->dev, "qmi set state %d txn wait failed for %s ret %d\n", + tmd->cur_state, tmd->type, ret); + return ret; + } + + if (tmd_resp.resp.result != QMI_RESULT_SUCCESS_V01) { + ret = -tmd_resp.resp.result; + dev_err(client->dev, "qmi set state %d NOT success for %s ret %d\n", + tmd->cur_state, tmd->type, ret); + return ret; + } + + dev_dbg(client->dev, "Requested state %d/%d for %s\n", tmd->cur_state, + tmd->max_state, tmd->type); + + return 0; +} + +static int qmi_get_max_level(void *devdata, unsigned long *level) +{ + struct qmi_tmd *tmd = devdata; + + if (!tmd) + return -EINVAL; + + *level = tmd->max_state; + + return 0; +} + +static int qmi_get_cur_level(void *devdata, unsigned long *level) +{ + struct qmi_tmd *tmd = devdata; + + if (!tmd) + return -EINVAL; + + *level = tmd->cur_state; + + return 0; +} + +static int qmi_set_cur_level(void *devdata, unsigned long level) +{ + struct qmi_tmd *tmd = devdata; + + if (!tmd) + return -EINVAL; + + if (level > tmd->max_state) + return -EINVAL; + + if (tmd->cur_state == level) + return 0; + + tmd->cur_state = level; + + return qmi_tmd_send_state_request(tmd); +} + +static const struct remoteproc_cooling_ops qmi_rproc_ops = { + .get_max_level = qmi_get_max_level, + .get_cur_level = qmi_get_cur_level, + .set_cur_level = qmi_set_cur_level, +}; + +static int qmi_register_cooling_device(struct qmi_tmd *tmd) +{ + struct remoteproc_cdev *rproc_cdev; + + rproc_cdev = remoteproc_cooling_register(tmd->np, + tmd->type, + &qmi_rproc_ops, + tmd); + + if (IS_ERR(rproc_cdev)) + return dev_err_probe(tmd->client->dev, PTR_ERR(rproc_cdev), + "Failed to register cooling device %s\n", + tmd->qmi_name); + + tmd->rproc_cdev = rproc_cdev; + return 0; +} + +/* + * Init a single TMD control by registering a cooling device for it, or + * synchronising state with the remote subsystem if recovering from a service + * restart. This is called when the TMD service starts up. + */ +static int qmi_tmd_init_control(struct qmi_tmd_client *client, const char *label, + u8 max_state) +{ + struct qmi_tmd *tmd = NULL; + + list_for_each_entry(tmd, &client->cdev_list, node) + if (!strncasecmp(tmd->qmi_name, label, + QMI_TMD_MITIGATION_DEV_ID_LENGTH_MAX_V01 + 1)) + goto found; + + dev_dbg(client->dev, + "TMD '%s' available in firmware but not specified in DT\n", + label); + return 0; + +found: + tmd->max_state = max_state; + /* + * If the cooling device already exists then the QMI service went away and + * came back. So just make sure the current cooling device state is + * reflected on the remote side and then return. + */ + if (tmd->rproc_cdev) + return qmi_tmd_send_state_request(tmd); + + return qmi_register_cooling_device(tmd); +} + +/* + * When the QMI service starts up on a remote subsystem this function will fetch + * the list of TMDs on the subsystem, match it to the TMDs specified in devicetree + * and call qmi_tmd_init_control() for each + */ +static void qmi_tmd_svc_arrive(struct work_struct *work) +{ + struct qmi_tmd_client *client = + container_of(work, struct qmi_tmd_client, svc_arrive_work); + + struct tmd_get_mitigation_device_list_req_msg_v01 req = { 0 }; + struct tmd_get_mitigation_device_list_resp_msg_v01 *resp __free(kfree); + int ret = 0, i; + struct qmi_txn txn; + + /* resp struct is 1.1kB, allocate it on the heap. */ + resp = kzalloc(sizeof(*resp), GFP_KERNEL); + if (!resp) + return; + + /* Get a list of TMDs supported by the remoteproc */ + scoped_guard(mutex, &client->mutex) { + ret = qmi_txn_init(&client->handle, &txn, + tmd_get_mitigation_device_list_resp_msg_v01_ei, resp); + if (ret < 0) { + dev_err(client->dev, + "Transaction init error for instance_id: %#x ret %d\n", + client->id, ret); + return; + } + + ret = qmi_send_request(&client->handle, NULL, &txn, + QMI_TMD_GET_MITIGATION_DEVICE_LIST_REQ_V01, + TMD_GET_MITIGATION_DEVICE_LIST_REQ_MSG_V01_MAX_MSG_LEN, + tmd_get_mitigation_device_list_req_msg_v01_ei, &req); + if (ret < 0) { + qmi_txn_cancel(&txn); + return; + } + + ret = qmi_txn_wait(&txn, QMI_TMD_RESP_TIMEOUT); + if (ret < 0) { + dev_err(client->dev, "Transaction wait error for client %#x ret:%d\n", + client->id, ret); + return; + } + if (resp->resp.result != QMI_RESULT_SUCCESS_V01) { + ret = resp->resp.result; + dev_err(client->dev, "Failed to get device list for client %#x ret:%d\n", + client->id, ret); + return; + } + + client->connection_active = true; + } + + for (i = 0; i < resp->mitigation_device_list_len; i++) { + struct tmd_mitigation_dev_list_type_v01 *device = + &resp->mitigation_device_list[i]; + + ret = qmi_tmd_init_control(client, + device->mitigation_dev_id.mitigation_dev_id, + device->max_mitigation_level); + if (ret) + break; + } +} + +static void thermal_qmi_net_reset(struct qmi_handle *qmi) +{ + struct qmi_tmd_client *client = container_of(qmi, struct qmi_tmd_client, handle); + struct qmi_tmd *tmd = NULL; + + list_for_each_entry(tmd, &client->cdev_list, node) { + qmi_tmd_send_state_request(tmd); + } +} + +static void thermal_qmi_del_server(struct qmi_handle *qmi, struct qmi_service *service) +{ + struct qmi_tmd_client *client = container_of(qmi, struct qmi_tmd_client, handle); + + scoped_guard(mutex, &client->mutex) + client->connection_active = false; +} + +static int thermal_qmi_new_server(struct qmi_handle *qmi, struct qmi_service *service) +{ + struct qmi_tmd_client *client = container_of(qmi, struct qmi_tmd_client, handle); + struct sockaddr_qrtr sq = { AF_QIPCRTR, service->node, service->port }; + + scoped_guard(mutex, &client->mutex) + kernel_connect(qmi->sock, (struct sockaddr *)&sq, sizeof(sq), 0); + + queue_work(system_highpri_wq, &client->svc_arrive_work); + + return 0; +} + +static struct qmi_ops thermal_qmi_event_ops = { + .new_server = thermal_qmi_new_server, + .del_server = thermal_qmi_del_server, + .net_reset = thermal_qmi_net_reset, +}; + +static void qmi_tmd_cleanup(struct qmi_tmd_client *client) +{ + struct qmi_tmd *tmd, *c_next; + + guard(mutex)(&client->mutex); + + client->connection_active = false; + + qmi_handle_release(&client->handle); + cancel_work(&client->svc_arrive_work); + list_for_each_entry_safe(tmd, c_next, &client->cdev_list, node) { + if (tmd->rproc_cdev) + remoteproc_cooling_unregister(tmd->rproc_cdev); + + list_del(&tmd->node); + } +} + +/* Parse the controls and allocate a qmi_tmd for each of them */ +static int qmi_tmd_alloc_cdevs(struct qmi_tmd_client *client) +{ + struct device *dev = client->dev; + struct qmi_tmd *tmd; + struct device_node *subnode, *node = dev->of_node; + int ret; + + for_each_available_child_of_node(node, subnode) { + const char *name; + + tmd = devm_kzalloc(dev, sizeof(*tmd), GFP_KERNEL); + if (!tmd) + return dev_err_probe(client->dev, -ENOMEM, + "Couldn't allocate tmd\n"); + + tmd->type = devm_kasprintf(client->dev, GFP_KERNEL, "%s:%s", + client->name, subnode->name); + if (!tmd->type) + return dev_err_probe(dev, -ENOMEM, + "Couldn't allocate cooling device name\n"); + + if (of_property_read_string(subnode, "label", &name)) { + return dev_err_probe(client->dev, -EINVAL, + "Failed to parse dev name for %s\n", + subnode->name); + } + + ret = strscpy(tmd->qmi_name, name, + QMI_TMD_MITIGATION_DEV_ID_LENGTH_MAX_V01 + 1); + if (ret == -E2BIG) { + return dev_err_probe(dev, -EINVAL, "TMD label %s is too long\n", + name); + } + + tmd->client = client; + tmd->np = subnode; + tmd->cur_state = 0; + list_add(&tmd->node, &client->cdev_list); + } + + if (list_empty(&client->cdev_list)) + return dev_err_probe(client->dev, -EINVAL, + "No cooling devices specified for client %s (%#x)\n", + client->name, client->id); + + return 0; +} + +static int qmi_tmd_client_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct qmi_tmd_client *client; + const struct qmi_instance_data *match; + int ret; + + client = devm_kzalloc(dev, sizeof(*client), GFP_KERNEL); + if (!client) + return -ENOMEM; + + client->dev = dev; + + match = of_device_get_match_data(dev); + if (!match) + return dev_err_probe(dev, -EINVAL, "No match data\n"); + + client->id = match->id; + client->name = match->name; + + mutex_init(&client->mutex); + INIT_LIST_HEAD(&client->cdev_list); + INIT_WORK(&client->svc_arrive_work, qmi_tmd_svc_arrive); + + ret = qmi_tmd_alloc_cdevs(client); + if (ret) + return ret; + + platform_set_drvdata(pdev, client); + + ret = qmi_handle_init(&client->handle, + TMD_GET_MITIGATION_DEVICE_LIST_RESP_MSG_V01_MAX_MSG_LEN, + &thermal_qmi_event_ops, NULL); + if (ret < 0) + return dev_err_probe(client->dev, ret, "QMI handle init failed for client %#x\n", + client->id); + + ret = qmi_add_lookup(&client->handle, TMD_SERVICE_ID_V01, TMD_SERVICE_VERS_V01, + client->id); + if (ret < 0) { + qmi_handle_release(&client->handle); + return dev_err_probe(client->dev, ret, "QMI register failed for client 0x%x\n", + client->id); + } + + return 0; +} + +static void qmi_tmd_client_remove(struct platform_device *pdev) +{ + struct qmi_tmd_client *client = platform_get_drvdata(pdev); + + qmi_tmd_cleanup(client); +} + +static const struct of_device_id qmi_tmd_device_table[] = { + { + .compatible = "qcom,qmi-cooling-cdsp", + .data = &((struct qmi_instance_data) { CDSP_INSTANCE_ID, "cdsp" }), + }, + {} +}; +MODULE_DEVICE_TABLE(of, qmi_tmd_device_table); + +static struct platform_driver qmi_tmd_device_driver = { + .probe = qmi_tmd_client_probe, + .remove = qmi_tmd_client_remove, + .driver = { + .name = "qcom-qmi-cooling", + .of_match_table = qmi_tmd_device_table, + }, +}; + +module_platform_driver(qmi_tmd_device_driver); + +MODULE_LICENSE("GPL"); diff --git a/drivers/soc/qcom/qmi-cooling.h b/drivers/soc/qcom/qmi-cooling.h new file mode 100644 index 0000000000000..f46b827b4ce64 --- /dev/null +++ b/drivers/soc/qcom/qmi-cooling.h @@ -0,0 +1,428 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017, The Linux Foundation + * Copyright (c) 2023, Linaro Limited + */ + +#ifndef __QCOM_COOLING_H__ +#define __QCOM_COOLING_H__ + +#include + +#define TMD_SERVICE_ID_V01 0x18 +#define TMD_SERVICE_VERS_V01 0x01 + +#define QMI_TMD_GET_MITIGATION_DEVICE_LIST_RESP_V01 0x0020 +#define QMI_TMD_GET_MITIGATION_LEVEL_REQ_V01 0x0022 +#define QMI_TMD_GET_SUPPORTED_MSGS_REQ_V01 0x001E +#define QMI_TMD_SET_MITIGATION_LEVEL_REQ_V01 0x0021 +#define QMI_TMD_REGISTER_NOTIFICATION_MITIGATION_LEVEL_RESP_V01 0x0023 +#define QMI_TMD_GET_SUPPORTED_MSGS_RESP_V01 0x001E +#define QMI_TMD_SET_MITIGATION_LEVEL_RESP_V01 0x0021 +#define QMI_TMD_DEREGISTER_NOTIFICATION_MITIGATION_LEVEL_RESP_V01 0x0024 +#define QMI_TMD_MITIGATION_LEVEL_REPORT_IND_V01 0x0025 +#define QMI_TMD_GET_MITIGATION_LEVEL_RESP_V01 0x0022 +#define QMI_TMD_GET_SUPPORTED_FIELDS_REQ_V01 0x001F +#define QMI_TMD_GET_MITIGATION_DEVICE_LIST_REQ_V01 0x0020 +#define QMI_TMD_REGISTER_NOTIFICATION_MITIGATION_LEVEL_REQ_V01 0x0023 +#define QMI_TMD_DEREGISTER_NOTIFICATION_MITIGATION_LEVEL_REQ_V01 0x0024 +#define QMI_TMD_GET_SUPPORTED_FIELDS_RESP_V01 0x001F + +#define QMI_TMD_MITIGATION_DEV_ID_LENGTH_MAX_V01 32 +#define QMI_TMD_MITIGATION_DEV_LIST_MAX_V01 32 + +struct tmd_mitigation_dev_id_type_v01 { + char mitigation_dev_id[QMI_TMD_MITIGATION_DEV_ID_LENGTH_MAX_V01 + 1]; +}; + +static const struct qmi_elem_info tmd_mitigation_dev_id_type_v01_ei[] = { + { + .data_type = QMI_STRING, + .elem_len = QMI_TMD_MITIGATION_DEV_ID_LENGTH_MAX_V01 + 1, + .elem_size = sizeof(char), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct tmd_mitigation_dev_id_type_v01, + mitigation_dev_id), + }, + { + .data_type = QMI_EOTI, + .array_type = NO_ARRAY, + .tlv_type = QMI_COMMON_TLV_TYPE, + }, +}; + +struct tmd_mitigation_dev_list_type_v01 { + struct tmd_mitigation_dev_id_type_v01 mitigation_dev_id; + uint8_t max_mitigation_level; +}; + +static const struct qmi_elem_info tmd_mitigation_dev_list_type_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct tmd_mitigation_dev_id_type_v01), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct tmd_mitigation_dev_list_type_v01, + mitigation_dev_id), + .ei_array = tmd_mitigation_dev_id_type_v01_ei, + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct tmd_mitigation_dev_list_type_v01, + max_mitigation_level), + }, + { + .data_type = QMI_EOTI, + .array_type = NO_ARRAY, + .tlv_type = QMI_COMMON_TLV_TYPE, + }, +}; + +struct tmd_get_mitigation_device_list_req_msg_v01 { + char placeholder; +}; + +#define TMD_GET_MITIGATION_DEVICE_LIST_REQ_MSG_V01_MAX_MSG_LEN 0 +const struct qmi_elem_info tmd_get_mitigation_device_list_req_msg_v01_ei[] = { + { + .data_type = QMI_EOTI, + .array_type = NO_ARRAY, + .tlv_type = QMI_COMMON_TLV_TYPE, + }, +}; + +struct tmd_get_mitigation_device_list_resp_msg_v01 { + struct qmi_response_type_v01 resp; + uint8_t mitigation_device_list_valid; + uint32_t mitigation_device_list_len; + struct tmd_mitigation_dev_list_type_v01 + mitigation_device_list[QMI_TMD_MITIGATION_DEV_LIST_MAX_V01]; +}; + +#define TMD_GET_MITIGATION_DEVICE_LIST_RESP_MSG_V01_MAX_MSG_LEN 1099 +static const struct qmi_elem_info tmd_get_mitigation_device_list_resp_msg_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct qmi_response_type_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct tmd_get_mitigation_device_list_resp_msg_v01, + resp), + .ei_array = qmi_response_type_v01_ei, + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct tmd_get_mitigation_device_list_resp_msg_v01, + mitigation_device_list_valid), + }, + { + .data_type = QMI_DATA_LEN, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct tmd_get_mitigation_device_list_resp_msg_v01, + mitigation_device_list_len), + }, + { + .data_type = QMI_STRUCT, + .elem_len = QMI_TMD_MITIGATION_DEV_LIST_MAX_V01, + .elem_size = sizeof(struct tmd_mitigation_dev_list_type_v01), + .array_type = VAR_LEN_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct tmd_get_mitigation_device_list_resp_msg_v01, + mitigation_device_list), + .ei_array = tmd_mitigation_dev_list_type_v01_ei, + }, + { + .data_type = QMI_EOTI, + .array_type = NO_ARRAY, + .tlv_type = QMI_COMMON_TLV_TYPE, + }, +}; + +struct tmd_set_mitigation_level_req_msg_v01 { + struct tmd_mitigation_dev_id_type_v01 mitigation_dev_id; + uint8_t mitigation_level; +}; + +#define TMD_SET_MITIGATION_LEVEL_REQ_MSG_V01_MAX_MSG_LEN 40 +static const struct qmi_elem_info tmd_set_mitigation_level_req_msg_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct tmd_mitigation_dev_id_type_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x01, + .offset = offsetof(struct tmd_set_mitigation_level_req_msg_v01, + mitigation_dev_id), + .ei_array = tmd_mitigation_dev_id_type_v01_ei, + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct tmd_set_mitigation_level_req_msg_v01, + mitigation_level), + }, + { + .data_type = QMI_EOTI, + .array_type = NO_ARRAY, + .tlv_type = QMI_COMMON_TLV_TYPE, + }, +}; + +struct tmd_set_mitigation_level_resp_msg_v01 { + struct qmi_response_type_v01 resp; +}; + +#define TMD_SET_MITIGATION_LEVEL_RESP_MSG_V01_MAX_MSG_LEN 7 +static const struct qmi_elem_info tmd_set_mitigation_level_resp_msg_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct qmi_response_type_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct tmd_set_mitigation_level_resp_msg_v01, resp), + .ei_array = qmi_response_type_v01_ei, + }, + { + .data_type = QMI_EOTI, + .array_type = NO_ARRAY, + .tlv_type = QMI_COMMON_TLV_TYPE, + }, +}; + +struct tmd_get_mitigation_level_req_msg_v01 { + struct tmd_mitigation_dev_id_type_v01 mitigation_device; +}; +#define TMD_GET_MITIGATION_LEVEL_REQ_MSG_V01_MAX_MSG_LEN 36 + +static const struct qmi_elem_info tmd_get_mitigation_level_req_msg_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct tmd_mitigation_dev_id_type_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x01, + .offset = offsetof(struct tmd_get_mitigation_level_req_msg_v01, + mitigation_device), + .ei_array = tmd_mitigation_dev_id_type_v01_ei, + }, + { + .data_type = QMI_EOTI, + .array_type = NO_ARRAY, + .tlv_type = QMI_COMMON_TLV_TYPE, + }, +}; + +struct tmd_get_mitigation_level_resp_msg_v01 { + struct qmi_response_type_v01 resp; + uint8_t current_mitigation_level_valid; + uint8_t current_mitigation_level; + uint8_t requested_mitigation_level_valid; + uint8_t requested_mitigation_level; +}; + +#define TMD_GET_MITIGATION_LEVEL_RESP_MSG_V01_MAX_MSG_LEN 15 +static const struct qmi_elem_info tmd_get_mitigation_level_resp_msg_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct qmi_response_type_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct tmd_get_mitigation_level_resp_msg_v01, resp), + .ei_array = qmi_response_type_v01_ei, + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct tmd_get_mitigation_level_resp_msg_v01, + current_mitigation_level_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct tmd_get_mitigation_level_resp_msg_v01, + current_mitigation_level), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .array_type = NO_ARRAY, + .tlv_type = 0x11, + .offset = offsetof(struct tmd_get_mitigation_level_resp_msg_v01, + requested_mitigation_level_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .array_type = NO_ARRAY, + .tlv_type = 0x11, + .offset = offsetof(struct tmd_get_mitigation_level_resp_msg_v01, + requested_mitigation_level), + }, + { + .data_type = QMI_EOTI, + .array_type = NO_ARRAY, + .tlv_type = QMI_COMMON_TLV_TYPE, + }, +}; + +struct tmd_register_notification_mitigation_level_req_msg_v01 { + struct tmd_mitigation_dev_id_type_v01 mitigation_device; +}; + +#define TMD_REGISTER_NOTIFICATION_MITIGATION_LEVEL_REQ_MSG_V01_MAX_MSG_LEN 36 +static const struct qmi_elem_info + tmd_register_notification_mitigation_level_req_msg_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct tmd_mitigation_dev_id_type_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x01, + .offset = offsetof( + struct tmd_register_notification_mitigation_level_req_msg_v01, + mitigation_device), + .ei_array = tmd_mitigation_dev_id_type_v01_ei, + }, + { + .data_type = QMI_EOTI, + .array_type = NO_ARRAY, + .tlv_type = QMI_COMMON_TLV_TYPE, + }, + }; + +struct tmd_register_notification_mitigation_level_resp_msg_v01 { + struct qmi_response_type_v01 resp; +}; + +#define TMD_REGISTER_NOTIFICATION_MITIGATION_LEVEL_RESP_MSG_V01_MAX_MSG_LEN 7 +static const struct qmi_elem_info + tmd_register_notification_mitigation_level_resp_msg_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct qmi_response_type_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof( + struct tmd_register_notification_mitigation_level_resp_msg_v01, + resp), + .ei_array = qmi_response_type_v01_ei, + }, + { + .data_type = QMI_EOTI, + .array_type = NO_ARRAY, + .tlv_type = QMI_COMMON_TLV_TYPE, + }, + }; + +struct tmd_deregister_notification_mitigation_level_req_msg_v01 { + struct tmd_mitigation_dev_id_type_v01 mitigation_device; +}; + +#define TMD_DEREGISTER_NOTIFICATION_MITIGATION_LEVEL_REQ_MSG_V01_MAX_MSG_LEN 36 +static const struct qmi_elem_info + tmd_deregister_notification_mitigation_level_req_msg_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct tmd_mitigation_dev_id_type_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x01, + .offset = offsetof( + struct tmd_deregister_notification_mitigation_level_req_msg_v01, + mitigation_device), + .ei_array = tmd_mitigation_dev_id_type_v01_ei, + }, + { + .data_type = QMI_EOTI, + .array_type = NO_ARRAY, + .tlv_type = QMI_COMMON_TLV_TYPE, + }, + }; + +struct tmd_deregister_notification_mitigation_level_resp_msg_v01 { + struct qmi_response_type_v01 resp; +}; + +#define TMD_DEREGISTER_NOTIFICATION_MITIGATION_LEVEL_RESP_MSG_V01_MAX_MSG_LEN 7 +static const struct qmi_elem_info + tmd_deregister_notification_mitigation_level_resp_msg_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct qmi_response_type_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof( + struct tmd_deregister_notification_mitigation_level_resp_msg_v01, + resp), + .ei_array = qmi_response_type_v01_ei, + }, + { + .data_type = QMI_EOTI, + .array_type = NO_ARRAY, + .tlv_type = QMI_COMMON_TLV_TYPE, + }, + }; + +struct tmd_mitigation_level_report_ind_msg_v01 { + struct tmd_mitigation_dev_id_type_v01 mitigation_device; + uint8_t current_mitigation_level; +}; + +#define TMD_MITIGATION_LEVEL_REPORT_IND_MSG_V01_MAX_MSG_LEN 40 +static const struct qmi_elem_info tmd_mitigation_level_report_ind_msg_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct tmd_mitigation_dev_id_type_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x01, + .offset = offsetof(struct tmd_mitigation_level_report_ind_msg_v01, + mitigation_device), + .ei_array = tmd_mitigation_dev_id_type_v01_ei, + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct tmd_mitigation_level_report_ind_msg_v01, + current_mitigation_level), + }, + { + .data_type = QMI_EOTI, + .array_type = NO_ARRAY, + .tlv_type = QMI_COMMON_TLV_TYPE, + }, +}; + +#endif /* __QMI_COOLING_INTERNAL_H__ */ From 026f1068ed5c717e9069f7ed47da7ada21678481 Mon Sep 17 00:00:00 2001 From: Casey Connolly Date: Tue, 23 Dec 2025 18:02:21 +0530 Subject: [PATCH 1438/2333] FROMLIST: remoteproc: qcom: probe all child devices Generalise the qcom,bam-dmux child node support by probing all remoteproc children with of_platform_populate(). This will be used to enable support for devices which are best represented as subnodes of the remoteproc, such as those representing QMI clients. Signed-off-by: Casey Connolly Link: https://lore.kernel.org/r/20251223123227.1317244-3-gaurav.kohli@oss.qualcomm.com --- drivers/remoteproc/qcom_q6v5.c | 4 ++++ drivers/remoteproc/qcom_q6v5_mss.c | 8 -------- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/remoteproc/qcom_q6v5.c b/drivers/remoteproc/qcom_q6v5.c index 58d5b85e58cda..a02839c7ed8c2 100644 --- a/drivers/remoteproc/qcom_q6v5.c +++ b/drivers/remoteproc/qcom_q6v5.c @@ -6,6 +6,7 @@ * Copyright (C) 2014 Sony Mobile Communications AB * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. */ +#include #include #include #include @@ -351,6 +352,8 @@ int qcom_q6v5_init(struct qcom_q6v5 *q6v5, struct platform_device *pdev, return dev_err_probe(&pdev->dev, PTR_ERR(q6v5->path), "failed to acquire interconnect path\n"); + of_platform_populate(q6v5->dev->of_node, NULL, NULL, q6v5->dev); + return 0; } EXPORT_SYMBOL_GPL(qcom_q6v5_init); @@ -361,6 +364,7 @@ EXPORT_SYMBOL_GPL(qcom_q6v5_init); */ void qcom_q6v5_deinit(struct qcom_q6v5 *q6v5) { + of_platform_depopulate(q6v5->dev); qmp_put(q6v5->qmp); } EXPORT_SYMBOL_GPL(qcom_q6v5_deinit); diff --git a/drivers/remoteproc/qcom_q6v5_mss.c b/drivers/remoteproc/qcom_q6v5_mss.c index 3087d895b87f4..e4f25be4f6438 100644 --- a/drivers/remoteproc/qcom_q6v5_mss.c +++ b/drivers/remoteproc/qcom_q6v5_mss.c @@ -238,7 +238,6 @@ struct q6v5 { struct qcom_rproc_pdm pdm_subdev; struct qcom_rproc_ssr ssr_subdev; struct qcom_sysmon *sysmon; - struct platform_device *bam_dmux; bool need_mem_protection; bool has_alt_reset; bool has_mba_logs; @@ -2051,7 +2050,6 @@ static int q6v5_alloc_memory_region(struct q6v5 *qproc) static int q6v5_probe(struct platform_device *pdev) { const struct rproc_hexagon_res *desc; - struct device_node *node; struct q6v5 *qproc; struct rproc *rproc; const char *mba_image; @@ -2185,10 +2183,6 @@ static int q6v5_probe(struct platform_device *pdev) if (ret) goto remove_sysmon_subdev; - node = of_get_compatible_child(pdev->dev.of_node, "qcom,bam-dmux"); - qproc->bam_dmux = of_platform_device_create(node, NULL, &pdev->dev); - of_node_put(node); - return 0; remove_sysmon_subdev: @@ -2208,8 +2202,6 @@ static void q6v5_remove(struct platform_device *pdev) struct q6v5 *qproc = platform_get_drvdata(pdev); struct rproc *rproc = qproc->rproc; - if (qproc->bam_dmux) - of_platform_device_destroy(&qproc->bam_dmux->dev, NULL); rproc_del(rproc); qcom_q6v5_deinit(&qproc->q6v5); From 87db14067b0d5c33218817384265c9c15de071d9 Mon Sep 17 00:00:00 2001 From: Gaurav Kohli Date: Tue, 23 Dec 2025 18:02:24 +0530 Subject: [PATCH 1439/2333] FROMLIST: arm64: dts: qcom: Enable cdsp qmi tmd devices for lemans Enable cdsp cooling devices and thermal zone cooling map bindings for both cdsp and cdsp1. Signed-off-by: Gaurav Kohli Link: https://lore.kernel.org/r/20251223123227.1317244-6-gaurav.kohli@oss.qualcomm.com --- arch/arm64/boot/dts/qcom/lemans.dtsi | 137 ++++++++++++++++++++++++--- 1 file changed, 125 insertions(+), 12 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/lemans.dtsi b/arch/arm64/boot/dts/qcom/lemans.dtsi index 8b77e2a5ef01f..5fd68b5a491be 100644 --- a/arch/arm64/boot/dts/qcom/lemans.dtsi +++ b/arch/arm64/boot/dts/qcom/lemans.dtsi @@ -7129,6 +7129,14 @@ }; }; }; + + cooling { + compatible = "qcom,qmi-cooling-cdsp"; + cdsp_sw0: cdsp_sw { + label = "cdsp_sw"; + #cooling-cells = <2>; + }; + }; }; remoteproc_cdsp1: remoteproc@2a300000 { @@ -7285,6 +7293,15 @@ }; }; }; + + + cooling { + compatible = "qcom,qmi-cooling-cdsp"; + cdsp_sw1: cdsp_sw { + label = "cdsp_sw"; + #cooling-cells = <2>; + }; + }; }; remoteproc_adsp: remoteproc@30000000 { @@ -8009,7 +8026,7 @@ thermal-sensors = <&tsens2 5>; trips { - trip-point0 { + nsp_0_0_0_alert0: trip-point0 { temperature = <105000>; hysteresis = <5000>; type = "passive"; @@ -8021,6 +8038,14 @@ type = "passive"; }; }; + + cooling-maps { + map0 { + trip = <&nsp_0_0_0_alert0>; + cooling-device = <&cdsp_sw0 + THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + }; }; nsp-0-1-0-thermal { @@ -8029,7 +8054,7 @@ thermal-sensors = <&tsens2 6>; trips { - trip-point0 { + nsp_0_1_0_alert0: trip-point0 { temperature = <105000>; hysteresis = <5000>; type = "passive"; @@ -8041,6 +8066,14 @@ type = "passive"; }; }; + + cooling-maps { + map0 { + trip = <&nsp_0_1_0_alert0>; + cooling-device = <&cdsp_sw0 + THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + }; }; nsp-0-2-0-thermal { @@ -8049,7 +8082,7 @@ thermal-sensors = <&tsens2 7>; trips { - trip-point0 { + nsp_0_2_0_alert0: trip-point0 { temperature = <105000>; hysteresis = <5000>; type = "passive"; @@ -8061,6 +8094,14 @@ type = "passive"; }; }; + + cooling-maps { + map0 { + trip = <&nsp_0_2_0_alert0>; + cooling-device = <&cdsp_sw0 + THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + }; }; nsp-1-0-0-thermal { @@ -8069,7 +8110,7 @@ thermal-sensors = <&tsens2 8>; trips { - trip-point0 { + nsp_1_0_0_alert0: trip-point0 { temperature = <105000>; hysteresis = <5000>; type = "passive"; @@ -8081,6 +8122,14 @@ type = "passive"; }; }; + + cooling-maps { + map0 { + trip = <&nsp_1_0_0_alert0>; + cooling-device = <&cdsp_sw1 + THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + }; }; nsp-1-1-0-thermal { @@ -8089,7 +8138,7 @@ thermal-sensors = <&tsens2 9>; trips { - trip-point0 { + nsp_1_1_0_alert0: trip-point0 { temperature = <105000>; hysteresis = <5000>; type = "passive"; @@ -8101,6 +8150,14 @@ type = "passive"; }; }; + + cooling-maps { + map0 { + trip = <&nsp_1_1_0_alert0>; + cooling-device = <&cdsp_sw1 + THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + }; }; nsp-1-2-0-thermal { @@ -8109,7 +8166,7 @@ thermal-sensors = <&tsens2 10>; trips { - trip-point0 { + nsp_1_2_0_alert0: trip-point0 { temperature = <105000>; hysteresis = <5000>; type = "passive"; @@ -8121,6 +8178,14 @@ type = "passive"; }; }; + + cooling-maps { + map0 { + trip = <&nsp_1_2_0_alert0>; + cooling-device = <&cdsp_sw1 + THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + }; }; ddrss-0-thermal { @@ -8263,7 +8328,7 @@ thermal-sensors = <&tsens3 5>; trips { - trip-point0 { + nsp_0_0_1_alert0: trip-point0 { temperature = <105000>; hysteresis = <5000>; type = "passive"; @@ -8275,6 +8340,14 @@ type = "passive"; }; }; + + cooling-maps { + map0 { + trip = <&nsp_0_0_1_alert0>; + cooling-device = <&cdsp_sw0 + THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + }; }; nsp-0-1-1-thermal { @@ -8283,7 +8356,7 @@ thermal-sensors = <&tsens3 6>; trips { - trip-point0 { + nsp_0_1_1_alert0: trip-point0 { temperature = <105000>; hysteresis = <5000>; type = "passive"; @@ -8295,6 +8368,14 @@ type = "passive"; }; }; + + cooling-maps { + map0 { + trip = <&nsp_0_1_1_alert0>; + cooling-device = <&cdsp_sw0 + THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + }; }; nsp-0-2-1-thermal { @@ -8303,7 +8384,7 @@ thermal-sensors = <&tsens3 7>; trips { - trip-point0 { + nsp_0_2_1_alert0: trip-point0 { temperature = <105000>; hysteresis = <5000>; type = "passive"; @@ -8315,6 +8396,14 @@ type = "passive"; }; }; + + cooling-maps { + map0 { + trip = <&nsp_0_2_1_alert0>; + cooling-device = <&cdsp_sw0 + THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + }; }; nsp-1-0-1-thermal { @@ -8323,7 +8412,7 @@ thermal-sensors = <&tsens3 8>; trips { - trip-point0 { + nsp_1_0_1_alert0: trip-point0 { temperature = <105000>; hysteresis = <5000>; type = "passive"; @@ -8335,6 +8424,14 @@ type = "passive"; }; }; + + cooling-maps { + map0 { + trip = <&nsp_1_0_1_alert0>; + cooling-device = <&cdsp_sw1 + THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + }; }; nsp-1-1-1-thermal { @@ -8343,7 +8440,7 @@ thermal-sensors = <&tsens3 9>; trips { - trip-point0 { + nsp_1_1_1_alert0: trip-point0 { temperature = <105000>; hysteresis = <5000>; type = "passive"; @@ -8355,6 +8452,14 @@ type = "passive"; }; }; + + cooling-maps { + map0 { + trip = <&nsp_1_1_1_alert0>; + cooling-device = <&cdsp_sw1 + THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + }; }; nsp-1-2-1-thermal { @@ -8363,7 +8468,7 @@ thermal-sensors = <&tsens3 10>; trips { - trip-point0 { + nsp_1_2_1_alert0: trip-point0 { temperature = <105000>; hysteresis = <5000>; type = "passive"; @@ -8375,6 +8480,14 @@ type = "passive"; }; }; + + cooling-maps { + map0 { + trip = <&nsp_1_2_1_alert0>; + cooling-device = <&cdsp_sw1 + THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + }; }; ddrss-1-thermal { From 7781a719ee2b1191ddf2b313a69a4c35b18dbdf2 Mon Sep 17 00:00:00 2001 From: Gaurav Kohli Date: Wed, 3 Dec 2025 14:13:57 +0530 Subject: [PATCH 1440/2333] FROMLIST: arm64: dts: qcom: Enable cdsp qmi tmd devices for monaco Enable cdsp cooling devices and thermal zone cooling map bindings for cdsp. Signed-off-by: Gaurav Kohli Link: https://lore.kernel.org/all/20251223123227.1317244-9-gaurav.kohli@oss.qualcomm.com/ --- arch/arm64/boot/dts/qcom/qcs8300.dtsi | 92 +++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/qcs8300.dtsi b/arch/arm64/boot/dts/qcom/qcs8300.dtsi index 44b18be1bbd8a..04d1fea53ea1e 100644 --- a/arch/arm64/boot/dts/qcom/qcs8300.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs8300.dtsi @@ -7313,6 +7313,14 @@ }; }; }; + + cooling { + compatible = "qcom,qmi-cooling-cdsp"; + cdsp_sw: cdsp_sw { + label = "cdsp_sw"; + #cooling-cells = <2>; + }; + }; }; tsens2: thermal-sensor@c251000 { @@ -7691,36 +7699,78 @@ thermal-sensors = <&tsens2 5>; trips { + nsp_0_0_0_alert0: trip-point0 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + nsp-critical { temperature = <125000>; hysteresis = <1000>; type = "critical"; }; }; + + cooling-maps { + map0 { + trip = <&nsp_0_0_0_alert0>; + cooling-device = <&cdsp_sw + THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + }; }; nsp-0-1-0-thermal { thermal-sensors = <&tsens2 6>; trips { + nsp_0_1_0_alert0: trip-point0 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + nsp-critical { temperature = <125000>; hysteresis = <1000>; type = "critical"; }; }; + + cooling-maps { + map0 { + trip = <&nsp_0_1_0_alert0>; + cooling-device = <&cdsp_sw + THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + }; }; nsp-0-2-0-thermal { thermal-sensors = <&tsens2 7>; trips { + nsp_0_2_0_alert0: trip-point0 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + nsp-critical { temperature = <125000>; hysteresis = <1000>; type = "critical"; }; }; + + cooling-maps { + map0 { + trip = <&nsp_0_2_0_alert0>; + cooling-device = <&cdsp_sw + THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + }; }; ddrss-0-thermal { @@ -7811,36 +7861,78 @@ thermal-sensors = <&tsens3 5>; trips { + nsp_0_0_1_alert0: trip-point0 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + nsp-critical { temperature = <125000>; hysteresis = <1000>; type = "critical"; }; }; + + cooling-maps { + map0 { + trip = <&nsp_0_0_1_alert0>; + cooling-device = <&cdsp_sw + THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + }; }; nsp-0-1-1-thermal { thermal-sensors = <&tsens3 6>; trips { + nsp_0_1_1_alert0: trip-point0 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + nsp-critical { temperature = <125000>; hysteresis = <1000>; type = "critical"; }; }; + + cooling-maps { + map0 { + trip = <&nsp_0_1_1_alert0>; + cooling-device = <&cdsp_sw + THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + }; }; nsp-0-2-1-thermal { thermal-sensors = <&tsens3 7>; trips { + nsp_0_2_1_alert0: trip-point0 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + nsp-critical { temperature = <125000>; hysteresis = <1000>; type = "critical"; }; }; + + cooling-maps { + map0 { + trip = <&nsp_0_2_1_alert0>; + cooling-device = <&cdsp_sw + THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + }; }; ddrss-1-thermal { From 01b9a1b7bb24b8eb96640a8d155b8a6b16729662 Mon Sep 17 00:00:00 2001 From: Gaurav Kohli Date: Tue, 23 Dec 2025 18:02:26 +0530 Subject: [PATCH 1441/2333] FROMLIST: arm64: dts: qcom: Enable cdsp qmi tmd devices for kodiak Enable cdsp cooling devices and cooling map bindings for cdsp. Signed-off-by: Gaurav Kohli Link: https://lore.kernel.org/r/20251223123227.1317244-8-gaurav.kohli@oss.qualcomm.com --- arch/arm64/boot/dts/qcom/sc7280.dtsi | 36 ++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sc7280.dtsi b/arch/arm64/boot/dts/qcom/sc7280.dtsi index 4cc459802b9a4..68ed072389372 100644 --- a/arch/arm64/boot/dts/qcom/sc7280.dtsi +++ b/arch/arm64/boot/dts/qcom/sc7280.dtsi @@ -4780,6 +4780,14 @@ }; }; }; + + cooling { + compatible = "qcom,qmi-cooling-cdsp"; + cdsp_sw: cdsp_sw { + label = "cdsp_sw"; + #cooling-cells = <2>; + }; + }; }; usb_1: usb@a600000 { @@ -7585,12 +7593,26 @@ type = "hot"; }; + nspss0_alert1: trip-point1 { + temperature = <100000>; + hysteresis = <5000>; + type = "passive"; + }; + nspss0_crit: nspss0-crit { temperature = <110000>; hysteresis = <0>; type = "critical"; }; }; + + cooling-maps { + map0 { + trip = <&nspss0_alert1>; + cooling-device = <&cdsp_sw + THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + }; }; nspss1-thermal { @@ -7603,12 +7625,26 @@ type = "hot"; }; + nspss1_alert1: trip-point1 { + temperature = <100000>; + hysteresis = <5000>; + type = "passive"; + }; + nspss1_crit: nspss1-crit { temperature = <110000>; hysteresis = <0>; type = "critical"; }; }; + + cooling-maps { + map0 { + trip = <&nspss1_alert1>; + cooling-device = <&cdsp_sw + THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + }; }; video-thermal { From b21bab7770b82e9ce7b9f8353e62aa3ee7a613e9 Mon Sep 17 00:00:00 2001 From: Gaurav Kohli Date: Tue, 23 Dec 2025 18:02:25 +0530 Subject: [PATCH 1442/2333] FROMLIST: arm64: dts: qcom: Enable cdsp qmi tmd devices for talos Enable cdsp cooling devices and thermal zone cooling map bindings for cdsp. Signed-off-by: Gaurav Kohli Link: https://lore.kernel.org/r/20251223123227.1317244-7-gaurav.kohli@oss.qualcomm.com --- arch/arm64/boot/dts/qcom/talos.dtsi | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/talos.dtsi b/arch/arm64/boot/dts/qcom/talos.dtsi index eff8f9f78c6f5..cc89d3936d214 100644 --- a/arch/arm64/boot/dts/qcom/talos.dtsi +++ b/arch/arm64/boot/dts/qcom/talos.dtsi @@ -18,6 +18,7 @@ #include #include #include +#include / { interrupt-parent = <&intc>; @@ -3412,6 +3413,14 @@ }; }; }; + + cooling { + compatible = "qcom,qmi-cooling-cdsp"; + cdsp_sw: cdsp_sw { + label = "cdsp_sw"; + #cooling-cells = <2>; + }; + }; }; pmu@90b6300 { @@ -4683,12 +4692,26 @@ thermal-sensors = <&tsens0 10>; trips { + q6_hvx_alert0: trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + q6-hvx-critical { temperature = <115000>; hysteresis = <1000>; type = "critical"; }; }; + + cooling-maps { + map0 { + trip = <&q6_hvx_alert0>; + cooling-device = <&cdsp_sw + THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + }; }; mdm-core-thermal { From 39f9838e6c358cde5b06c8beac32674ad0dba420 Mon Sep 17 00:00:00 2001 From: Gaurav Kohli Date: Wed, 24 Dec 2025 18:34:18 +0530 Subject: [PATCH 1443/2333] QCLINUX: defconfig: Enable Remoteproc cooling feature Enable Remoteproc cooling feature config. Signed-off-by: Gaurav Kohli --- arch/arm64/configs/qcom.config | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm64/configs/qcom.config b/arch/arm64/configs/qcom.config index d2fe51d328e50..3230432a99dd1 100644 --- a/arch/arm64/configs/qcom.config +++ b/arch/arm64/configs/qcom.config @@ -39,6 +39,8 @@ CONFIG_PM_WAKELOCKS_LIMIT=0 CONFIG_PM=y CONFIG_POWERCAP=y CONFIG_QCA808X_PHY=m +CONFIG_QCOM_QMI_COOLING=y +CONFIG_REMOTEPROC_THERMAL=y CONFIG_SCHED_DEBUG=y CONFIG_SCHEDSTATS=y CONFIG_STM_PROTO_BASIC=m From 05854b0787ea409e3ca8b63d7d637ad1f6edad6e Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 23 Dec 2025 18:24:35 +0530 Subject: [PATCH 1444/2333] FROMLIST: drm/msm/a6xx: fix bogus hwcg register updates The hw clock gating register sequence consists of register value pairs that are written to the GPU during initialisation. The a690 hwcg sequence has two GMU registers in it that used to amount to random writes in the GPU mapping, but since commit 188db3d7fe66 ("drm/msm/a6xx: Rebase GMU register offsets") they trigger a fault as the updated offsets now lie outside the mapping. This in turn breaks boot of machines like the Lenovo ThinkPad X13s. Note that the updates of these GMU registers is already taken care of properly since commit 40c297eb245b ("drm/msm/a6xx: Set GMU CGC properties on a6xx too"), but for some reason these two entries were left in the table. Fixes: 5e7665b5e484 ("drm/msm/adreno: Add Adreno A690 support") Cc: stable@vger.kernel.org # 6.5 Cc: Bjorn Andersson Cc: Konrad Dybcio Signed-off-by: Johan Hovold Reviewed-by: Akhil P Oommen Link: https://lore.kernel.org/lkml/20251221164552.19990-1-johan@kernel.org/ --- drivers/gpu/drm/msm/adreno/a6xx_catalog.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/msm/adreno/a6xx_catalog.c b/drivers/gpu/drm/msm/adreno/a6xx_catalog.c index 5db01fa2ed441..255e793c8794d 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_catalog.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_catalog.c @@ -501,8 +501,6 @@ static const struct adreno_reglist a690_hwcg[] = { {REG_A6XX_RBBM_CLOCK_CNTL_GMU_GX, 0x00000222}, {REG_A6XX_RBBM_CLOCK_DELAY_GMU_GX, 0x00000111}, {REG_A6XX_RBBM_CLOCK_HYST_GMU_GX, 0x00000555}, - {REG_A6XX_GPU_GMU_AO_GMU_CGC_DELAY_CNTL, 0x10111}, - {REG_A6XX_GPU_GMU_AO_GMU_CGC_HYST_CNTL, 0x5555}, {} }; From ed30fd79d3de201f51181583fed2f849173470d7 Mon Sep 17 00:00:00 2001 From: Manish Dharanenthiran Date: Fri, 31 Oct 2025 08:37:45 +0530 Subject: [PATCH 1445/2333] UPSTREAM: wifi: ath12k: Make firmware stats reset caller-driven Currently, ath12k_fw_stats_reset() is called in ath12k_mac_get_fw_stats() before fetching the required stats from the firmware. However, ath12k_open_bcn_stats() requests firmware stats for each enabled BSS individually. Since the firmware stats are reset before fetching, only the last BSS's data is displayed. Also, in ath12k_mac_op_get_txpower(), ath12k_mac_op_sta_statistics(), and ath12k_mac_op_link_sta_statistics(), after getting the stats from the firmware, the reset function is not called until the next firmware stats are requested or while unloading the module. Hence, the stats buffer will not be freed until one of the above sequences is executed. However, in ath12k_open_vdev_stats(), ath12k_open_bcn_stats() and ath12k_open_pdev_stats(), firmware stats are reset after copying the necessary data in ath12k_wmi_fw_stats_dump(). This leads to inconsistent usage of ath12k_fw_stats_reset() for freeing the firmware stats. Avoid these discrepancies by making it the caller's responsibility to free the stats buffer, thereby removing the need to free the stats buffer in ath12k_mac_get_fw_stats() and ath12k_wmi_fw_stats_dump(). Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.4.1-00199-QCAHKSWPL_SILICONZ-1 Signed-off-by: Manish Dharanenthiran Reviewed-by: Vasanthakumar Thiagarajan Reviewed-by: Baochen Qiang Signed-off-by: Qian Zhang Link: https://lore.kernel.org/all/20251031-beacon_stats-v1-1-f52fce7b03ac@qti.qualcomm.com/ --- drivers/net/wireless/ath/ath12k/debugfs.c | 9 +++------ drivers/net/wireless/ath/ath12k/mac.c | 15 ++++++++++----- drivers/net/wireless/ath/ath12k/wmi.c | 2 -- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/debugfs.c b/drivers/net/wireless/ath/ath12k/debugfs.c index 16601a8c36448..d4bfe0944e4e7 100644 --- a/drivers/net/wireless/ath/ath12k/debugfs.c +++ b/drivers/net/wireless/ath/ath12k/debugfs.c @@ -1283,6 +1283,7 @@ static int ath12k_open_vdev_stats(struct inode *inode, struct file *file) ath12k_wmi_fw_stats_dump(ar, &ar->fw_stats, param.stats_id, buf); + ath12k_fw_stats_reset(ar); file->private_data = no_free_ptr(buf); @@ -1349,12 +1350,7 @@ static int ath12k_open_bcn_stats(struct inode *inode, struct file *file) ath12k_wmi_fw_stats_dump(ar, &ar->fw_stats, param.stats_id, buf); - /* since beacon stats request is looped for all active VDEVs, saved fw - * stats is not freed for each request until done for all active VDEVs - */ - spin_lock_bh(&ar->data_lock); - ath12k_fw_stats_bcn_free(&ar->fw_stats.bcn); - spin_unlock_bh(&ar->data_lock); + ath12k_fw_stats_reset(ar); file->private_data = no_free_ptr(buf); @@ -1415,6 +1411,7 @@ static int ath12k_open_pdev_stats(struct inode *inode, struct file *file) ath12k_wmi_fw_stats_dump(ar, &ar->fw_stats, param.stats_id, buf); + ath12k_fw_stats_reset(ar); file->private_data = no_free_ptr(buf); diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index db351c9220181..97ec054b99176 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -4837,8 +4837,6 @@ int ath12k_mac_get_fw_stats(struct ath12k *ar, if (ah->state != ATH12K_HW_STATE_ON) return -ENETDOWN; - ath12k_fw_stats_reset(ar); - reinit_completion(&ar->fw_stats_complete); reinit_completion(&ar->fw_stats_done); @@ -4936,6 +4934,7 @@ static int ath12k_mac_op_get_txpower(struct ieee80211_hw *hw, ar->chan_tx_pwr = pdev->chan_tx_power / 2; spin_unlock_bh(&ar->data_lock); ar->last_tx_power_update = jiffies; + ath12k_fw_stats_reset(ar); send_tx_power: *dbm = ar->chan_tx_pwr; @@ -12701,14 +12700,18 @@ static void ath12k_mac_op_sta_statistics(struct ieee80211_hw *hw, if (!signal && ahsta->ahvif->vdev_type == WMI_VDEV_TYPE_STA && - !(ath12k_mac_get_fw_stats(ar, ¶ms))) + !(ath12k_mac_get_fw_stats(ar, ¶ms))) { signal = arsta->rssi_beacon; + ath12k_fw_stats_reset(ar); + } params.stats_id = WMI_REQUEST_RSSI_PER_CHAIN_STAT; if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_CHAIN_SIGNAL)) && ahsta->ahvif->vdev_type == WMI_VDEV_TYPE_STA && - !(ath12k_mac_get_fw_stats(ar, ¶ms))) + !(ath12k_mac_get_fw_stats(ar, ¶ms))) { ath12k_mac_put_chain_rssi(sinfo, arsta); + ath12k_fw_stats_reset(ar); + } spin_lock_bh(&ar->data_lock); noise_floor = ath12k_pdev_get_noise_floor(ar); @@ -12792,8 +12795,10 @@ static void ath12k_mac_op_link_sta_statistics(struct ieee80211_hw *hw, if (!signal && ahsta->ahvif->vdev_type == WMI_VDEV_TYPE_STA && - !(ath12k_mac_get_fw_stats(ar, ¶ms))) + !(ath12k_mac_get_fw_stats(ar, ¶ms))) { signal = arsta->rssi_beacon; + ath12k_fw_stats_reset(ar); + } if (signal) { link_sinfo->signal = diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index ff6b3d4ea8208..455ae32c8afd9 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -8017,8 +8017,6 @@ void ath12k_wmi_fw_stats_dump(struct ath12k *ar, buf[len - 1] = 0; else buf[len] = 0; - - ath12k_fw_stats_reset(ar); } static void From 597aa8b0cccce21299853ac917a39d223904354d Mon Sep 17 00:00:00 2001 From: Manish Dharanenthiran Date: Fri, 31 Oct 2025 08:37:46 +0530 Subject: [PATCH 1446/2333] UPSTREAM: wifi: ath12k: Fix timeout error during beacon stats retrieval Currently, for beacon_stats, ath12k_mac_get_fw_stats() is called for each started BSS on the specified hardware. ath12k_mac_get_fw_stats() will wait for the fw_stats_done completion after fetching the requested data from firmware. For the beacon_stats, fw_stats_done completion will be set only when stats are received for all BSSes. However, for other stats like vdev_stats or pdev_stats, there is one request to the firmware for all enabled BSSes. Since beacon_stats is fetched individually for all BSSes enabled in that pdev, waiting for the completion event results in a timeout error when multiple BSSes are enabled. Avoid this by completing the fw_stats_done immediately after updating the requested BSS's beacon stats in the list. Subsequently, this list will be used to display the beacon stats for all enabled BSSes in the requested pdev. Additionally, remove 'num_bcn_recvd' from the ath12k_fw_stats struct as it is no longer needed. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.4.1-00199-QCAHKSWPL_SILICONZ-1 Fixes: 9fe4669ae919 ("wifi: ath12k: Request beacon stats from firmware") Signed-off-by: Manish Dharanenthiran Reviewed-by: Vasanthakumar Thiagarajan Reviewed-by: Baochen Qiang Signed-off-by: Qian Zhang Link: https://lore.kernel.org/all/20251031-beacon_stats-v1-2-f52fce7b03ac@qti.qualcomm.com/ --- drivers/net/wireless/ath/ath12k/core.c | 2 -- drivers/net/wireless/ath/ath12k/core.h | 1 - drivers/net/wireless/ath/ath12k/wmi.c | 10 +--------- 3 files changed, 1 insertion(+), 12 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c index 5d494c5cdc0da..f0994f3918f5c 100644 --- a/drivers/net/wireless/ath/ath12k/core.c +++ b/drivers/net/wireless/ath/ath12k/core.c @@ -1,7 +1,6 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ @@ -1250,7 +1249,6 @@ void ath12k_fw_stats_reset(struct ath12k *ar) spin_lock_bh(&ar->data_lock); ath12k_fw_stats_free(&ar->fw_stats); ar->fw_stats.num_vdev_recvd = 0; - ar->fw_stats.num_bcn_recvd = 0; spin_unlock_bh(&ar->data_lock); } diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index 3d1956966a485..d7688b383f62c 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -644,7 +644,6 @@ struct ath12k_fw_stats { struct list_head vdevs; struct list_head bcn; u32 num_vdev_recvd; - u32 num_bcn_recvd; }; struct ath12k_dbg_htt_stats { diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index 455ae32c8afd9..8250fd5a75b7f 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -8413,18 +8413,10 @@ static void ath12k_wmi_fw_stats_process(struct ath12k *ar, ath12k_warn(ab, "empty beacon stats"); return; } - /* Mark end until we reached the count of all started VDEVs - * within the PDEV - */ - if (ar->num_started_vdevs) - is_end = ((++ar->fw_stats.num_bcn_recvd) == - ar->num_started_vdevs); list_splice_tail_init(&stats->bcn, &ar->fw_stats.bcn); - - if (is_end) - complete(&ar->fw_stats_done); + complete(&ar->fw_stats_done); } } From 0522222f2ac243ca69e245ab856ce6e047d09781 Mon Sep 17 00:00:00 2001 From: Fernand Sieber Date: Thu, 6 Nov 2025 12:40:10 +0200 Subject: [PATCH 1447/2333] sched/proxy: Yield the donor task MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 127b90315ca07ccad2618db7ba950a63e3b32d22 upstream. When executing a task in proxy context, handle yields as if they were requested by the donor task. This matches the traditional PI semantics of yield() as well. This avoids scenario like proxy task yielding, pick next task selecting the same previous blocked donor, running the proxy task again, etc. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-lkp/202510211205.1e0f5223-lkp@intel.com Suggested-by: Peter Zijlstra Signed-off-by: Fernand Sieber Signed-off-by: Peter Zijlstra (Intel) Link: https://patch.msgid.link/20251106104022.195157-1-sieberf@amazon.com Cc: Holger Hoffstätte Signed-off-by: Greg Kroah-Hartman --- kernel/sched/deadline.c | 2 +- kernel/sched/ext.c | 4 ++-- kernel/sched/fair.c | 2 +- kernel/sched/rt.c | 2 +- kernel/sched/syscalls.c | 5 +++-- 5 files changed, 8 insertions(+), 7 deletions(-) diff --git a/kernel/sched/deadline.c b/kernel/sched/deadline.c index 19b1a8b81c76c..d3be71d5a9ccc 100644 --- a/kernel/sched/deadline.c +++ b/kernel/sched/deadline.c @@ -2143,7 +2143,7 @@ static void yield_task_dl(struct rq *rq) * it and the bandwidth timer will wake it up and will give it * new scheduling parameters (thanks to dl_yielded=1). */ - rq->curr->dl.dl_yielded = 1; + rq->donor->dl.dl_yielded = 1; update_rq_clock(rq); update_curr_dl(rq); diff --git a/kernel/sched/ext.c b/kernel/sched/ext.c index b959a70471c10..907eea83294ce 100644 --- a/kernel/sched/ext.c +++ b/kernel/sched/ext.c @@ -1493,7 +1493,7 @@ static bool dequeue_task_scx(struct rq *rq, struct task_struct *p, int deq_flags static void yield_task_scx(struct rq *rq) { struct scx_sched *sch = scx_root; - struct task_struct *p = rq->curr; + struct task_struct *p = rq->donor; if (SCX_HAS_OP(sch, yield)) SCX_CALL_OP_2TASKS_RET(sch, SCX_KF_REST, yield, rq, p, NULL); @@ -1504,7 +1504,7 @@ static void yield_task_scx(struct rq *rq) static bool yield_to_task_scx(struct rq *rq, struct task_struct *to) { struct scx_sched *sch = scx_root; - struct task_struct *from = rq->curr; + struct task_struct *from = rq->donor; if (SCX_HAS_OP(sch, yield)) return SCX_CALL_OP_2TASKS_RET(sch, SCX_KF_REST, yield, rq, diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 967ca52fb2311..5c965666d1663 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -8993,7 +8993,7 @@ static void put_prev_task_fair(struct rq *rq, struct task_struct *prev, struct t */ static void yield_task_fair(struct rq *rq) { - struct task_struct *curr = rq->curr; + struct task_struct *curr = rq->donor; struct cfs_rq *cfs_rq = task_cfs_rq(curr); struct sched_entity *se = &curr->se; diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c index 7936d43337313..fb07dcfc60a24 100644 --- a/kernel/sched/rt.c +++ b/kernel/sched/rt.c @@ -1490,7 +1490,7 @@ static void requeue_task_rt(struct rq *rq, struct task_struct *p, int head) static void yield_task_rt(struct rq *rq) { - requeue_task_rt(rq, rq->curr, 0); + requeue_task_rt(rq, rq->donor, 0); } static int find_lowest_rq(struct task_struct *task); diff --git a/kernel/sched/syscalls.c b/kernel/sched/syscalls.c index 77ae87f36e841..bf360a6fbb800 100644 --- a/kernel/sched/syscalls.c +++ b/kernel/sched/syscalls.c @@ -1351,7 +1351,7 @@ static void do_sched_yield(void) rq = this_rq_lock_irq(&rf); schedstat_inc(rq->yld_count); - current->sched_class->yield_task(rq); + rq->donor->sched_class->yield_task(rq); preempt_disable(); rq_unlock_irq(rq, &rf); @@ -1420,12 +1420,13 @@ EXPORT_SYMBOL(yield); */ int __sched yield_to(struct task_struct *p, bool preempt) { - struct task_struct *curr = current; + struct task_struct *curr; struct rq *rq, *p_rq; int yielded = 0; scoped_guard (raw_spinlock_irqsave, &p->pi_lock) { rq = this_rq(); + curr = rq->donor; again: p_rq = task_rq(p); From 5a7ba9b599fc7b1843adc012bc84d2c2c64afed9 Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Tue, 28 Oct 2025 12:00:52 +0100 Subject: [PATCH 1448/2333] drm: nova: depend on CONFIG_64BIT commit ba1b40ed0e34bab597fd90d4c4e9f7397f878c8f upstream. nova-core already depends on CONFIG_64BIT, hence also depend on CONFIG_64BIT for nova-drm. Reviewed-by: Alexandre Courbot Reviewed-by: John Hubbard Link: https://patch.msgid.link/20251028110058.340320-1-dakr@kernel.org Signed-off-by: Danilo Krummrich Cc: Miguel Ojeda Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/nova/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/nova/Kconfig b/drivers/gpu/drm/nova/Kconfig index bd1df08791911..3e637ad7b5bad 100644 --- a/drivers/gpu/drm/nova/Kconfig +++ b/drivers/gpu/drm/nova/Kconfig @@ -1,5 +1,6 @@ config DRM_NOVA tristate "Nova DRM driver" + depends on 64BIT depends on DRM=y depends on PCI depends on RUST From d75aa97c90da26ee4f29c768762061cf45c3106e Mon Sep 17 00:00:00 2001 From: "Borislav Petkov (AMD)" Date: Thu, 25 Sep 2025 13:46:00 +0200 Subject: [PATCH 1449/2333] x86/microcode/AMD: Select which microcode patch to load commit 8d171045069c804e5ffaa18be590c42c6af0cf3f upstream. All microcode patches up to the proper BIOS Entrysign fix are loaded only after the sha256 signature carried in the driver has been verified. Microcode patches after the Entrysign fix has been applied, do not need that signature verification anymore. In order to not abandon machines which haven't received the BIOS update yet, add the capability to select which microcode patch to load. The corresponding microcode container supplied through firmware-linux has been modified to carry two patches per CPU type (family/model/stepping) so that the proper one gets selected. Signed-off-by: Borislav Petkov (AMD) Tested-by: Waiman Long Link: https://patch.msgid.link/20251027133818.4363-1-bp@kernel.org Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/cpu/microcode/amd.c | 113 ++++++++++++++++++---------- 1 file changed, 72 insertions(+), 41 deletions(-) diff --git a/arch/x86/kernel/cpu/microcode/amd.c b/arch/x86/kernel/cpu/microcode/amd.c index a881bf4c20114..3821a985f4ffe 100644 --- a/arch/x86/kernel/cpu/microcode/amd.c +++ b/arch/x86/kernel/cpu/microcode/amd.c @@ -186,50 +186,61 @@ static u32 cpuid_to_ucode_rev(unsigned int val) return p.ucode_rev; } +static u32 get_cutoff_revision(u32 rev) +{ + switch (rev >> 8) { + case 0x80012: return 0x8001277; break; + case 0x80082: return 0x800820f; break; + case 0x83010: return 0x830107c; break; + case 0x86001: return 0x860010e; break; + case 0x86081: return 0x8608108; break; + case 0x87010: return 0x8701034; break; + case 0x8a000: return 0x8a0000a; break; + case 0xa0010: return 0xa00107a; break; + case 0xa0011: return 0xa0011da; break; + case 0xa0012: return 0xa001243; break; + case 0xa0082: return 0xa00820e; break; + case 0xa1011: return 0xa101153; break; + case 0xa1012: return 0xa10124e; break; + case 0xa1081: return 0xa108109; break; + case 0xa2010: return 0xa20102f; break; + case 0xa2012: return 0xa201212; break; + case 0xa4041: return 0xa404109; break; + case 0xa5000: return 0xa500013; break; + case 0xa6012: return 0xa60120a; break; + case 0xa7041: return 0xa704109; break; + case 0xa7052: return 0xa705208; break; + case 0xa7080: return 0xa708009; break; + case 0xa70c0: return 0xa70C009; break; + case 0xaa001: return 0xaa00116; break; + case 0xaa002: return 0xaa00218; break; + case 0xb0021: return 0xb002146; break; + case 0xb0081: return 0xb008111; break; + case 0xb1010: return 0xb101046; break; + case 0xb2040: return 0xb204031; break; + case 0xb4040: return 0xb404031; break; + case 0xb4041: return 0xb404101; break; + case 0xb6000: return 0xb600031; break; + case 0xb6080: return 0xb608031; break; + case 0xb7000: return 0xb700031; break; + default: break; + + } + return 0; +} + static bool need_sha_check(u32 cur_rev) { + u32 cutoff; + if (!cur_rev) { cur_rev = cpuid_to_ucode_rev(bsp_cpuid_1_eax); pr_info_once("No current revision, generating the lowest one: 0x%x\n", cur_rev); } - switch (cur_rev >> 8) { - case 0x80012: return cur_rev <= 0x8001277; break; - case 0x80082: return cur_rev <= 0x800820f; break; - case 0x83010: return cur_rev <= 0x830107c; break; - case 0x86001: return cur_rev <= 0x860010e; break; - case 0x86081: return cur_rev <= 0x8608108; break; - case 0x87010: return cur_rev <= 0x8701034; break; - case 0x8a000: return cur_rev <= 0x8a0000a; break; - case 0xa0010: return cur_rev <= 0xa00107a; break; - case 0xa0011: return cur_rev <= 0xa0011da; break; - case 0xa0012: return cur_rev <= 0xa001243; break; - case 0xa0082: return cur_rev <= 0xa00820e; break; - case 0xa1011: return cur_rev <= 0xa101153; break; - case 0xa1012: return cur_rev <= 0xa10124e; break; - case 0xa1081: return cur_rev <= 0xa108109; break; - case 0xa2010: return cur_rev <= 0xa20102f; break; - case 0xa2012: return cur_rev <= 0xa201212; break; - case 0xa4041: return cur_rev <= 0xa404109; break; - case 0xa5000: return cur_rev <= 0xa500013; break; - case 0xa6012: return cur_rev <= 0xa60120a; break; - case 0xa7041: return cur_rev <= 0xa704109; break; - case 0xa7052: return cur_rev <= 0xa705208; break; - case 0xa7080: return cur_rev <= 0xa708009; break; - case 0xa70c0: return cur_rev <= 0xa70C009; break; - case 0xaa001: return cur_rev <= 0xaa00116; break; - case 0xaa002: return cur_rev <= 0xaa00218; break; - case 0xb0021: return cur_rev <= 0xb002146; break; - case 0xb0081: return cur_rev <= 0xb008111; break; - case 0xb1010: return cur_rev <= 0xb101046; break; - case 0xb2040: return cur_rev <= 0xb204031; break; - case 0xb4040: return cur_rev <= 0xb404031; break; - case 0xb4041: return cur_rev <= 0xb404101; break; - case 0xb6000: return cur_rev <= 0xb600031; break; - case 0xb6080: return cur_rev <= 0xb608031; break; - case 0xb7000: return cur_rev <= 0xb700031; break; - default: break; - } + cutoff = get_cutoff_revision(cur_rev); + if (cutoff) + return cur_rev <= cutoff; pr_info("You should not be seeing this. Please send the following couple of lines to x86--kernel.org\n"); pr_info("CPUID(1).EAX: 0x%x, current revision: 0x%x\n", bsp_cpuid_1_eax, cur_rev); @@ -494,6 +505,7 @@ static int verify_patch(const u8 *buf, size_t buf_size, u32 *patch_size) { u8 family = x86_family(bsp_cpuid_1_eax); struct microcode_header_amd *mc_hdr; + u32 cur_rev, cutoff, patch_rev; u32 sh_psize; u16 proc_id; u8 patch_fam; @@ -533,11 +545,32 @@ static int verify_patch(const u8 *buf, size_t buf_size, u32 *patch_size) proc_id = mc_hdr->processor_rev_id; patch_fam = 0xf + (proc_id >> 12); - ucode_dbg("Patch-ID 0x%08x: family: 0x%x\n", mc_hdr->patch_id, patch_fam); - if (patch_fam != family) return 1; + cur_rev = get_patch_level(); + + /* No cutoff revision means old/unaffected by signing algorithm weakness => matches */ + cutoff = get_cutoff_revision(cur_rev); + if (!cutoff) + goto ok; + + patch_rev = mc_hdr->patch_id; + + ucode_dbg("cur_rev: 0x%x, cutoff: 0x%x, patch_rev: 0x%x\n", + cur_rev, cutoff, patch_rev); + + if (cur_rev <= cutoff && patch_rev <= cutoff) + goto ok; + + if (cur_rev > cutoff && patch_rev > cutoff) + goto ok; + + return 1; + +ok: + ucode_dbg("Patch-ID 0x%08x: family: 0x%x\n", mc_hdr->patch_id, patch_fam); + return 0; } @@ -606,8 +639,6 @@ static size_t parse_container(u8 *ucode, size_t size, struct cont_desc *desc) mc = (struct microcode_amd *)(buf + SECTION_HDR_SIZE); - ucode_dbg("patch_id: 0x%x\n", mc->hdr.patch_id); - if (mc_patch_matches(mc, eq_id)) { desc->psize = patch_size; desc->mc = mc; From fc83284e75274dbf99c716a5a9f370fe041abe3d Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Mon, 29 Dec 2025 14:35:37 -0500 Subject: [PATCH 1450/2333] sched/core: Add comment explaining force-idle vruntime snapshots [ Upstream commit 9359d9785d85bb53f1ff1738a59aeeec4b878906 ] I always end up having to re-read these emails every time I look at this code. And a future patch is going to change this story a little. This means it is past time to stick them in a comment so it can be modified and stay current. Signed-off-by: Peter Zijlstra (Intel) Link: https://lkml.kernel.org/r/20200506143506.GH5298@hirez.programming.kicks-ass.net Link: https://lkml.kernel.org/r/20200515103844.GG2978@hirez.programming.kicks-ass.net Link: https://patch.msgid.link/20251106111603.GB4068168@noisy.programming.kicks-ass.net Stable-dep-of: 79f3f9bedd14 ("sched/eevdf: Fix min_vruntime vs avg_vruntime") Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- kernel/sched/fair.c | 181 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 181 insertions(+) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 5c965666d1663..94a45a2d43422 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -13013,6 +13013,187 @@ static inline void task_tick_core(struct rq *rq, struct task_struct *curr) resched_curr(rq); } +/* + * Consider any infeasible weight scenario. Take for instance two tasks, + * each bound to their respective sibling, one with weight 1 and one with + * weight 2. Then the lower weight task will run ahead of the higher weight + * task without bound. + * + * This utterly destroys the concept of a shared time base. + * + * Remember; all this is about a proportionally fair scheduling, where each + * tasks receives: + * + * w_i + * dt_i = ---------- dt (1) + * \Sum_j w_j + * + * which we do by tracking a virtual time, s_i: + * + * 1 + * s_i = --- d[t]_i (2) + * w_i + * + * Where d[t] is a delta of discrete time, while dt is an infinitesimal. + * The immediate corollary is that the ideal schedule S, where (2) to use + * an infinitesimal delta, is: + * + * 1 + * S = ---------- dt (3) + * \Sum_i w_i + * + * From which we can define the lag, or deviation from the ideal, as: + * + * lag(i) = S - s_i (4) + * + * And since the one and only purpose is to approximate S, we get that: + * + * \Sum_i w_i lag(i) := 0 (5) + * + * If this were not so, we no longer converge to S, and we can no longer + * claim our scheduler has any of the properties we derive from S. This is + * exactly what you did above, you broke it! + * + * + * Let's continue for a while though; to see if there is anything useful to + * be learned. We can combine (1)-(3) or (4)-(5) and express S in s_i: + * + * \Sum_i w_i s_i + * S = -------------- (6) + * \Sum_i w_i + * + * Which gives us a way to compute S, given our s_i. Now, if you've read + * our code, you know that we do not in fact do this, the reason for this + * is two-fold. Firstly, computing S in that way requires a 64bit division + * for every time we'd use it (see 12), and secondly, this only describes + * the steady-state, it doesn't handle dynamics. + * + * Anyway, in (6): s_i -> x + (s_i - x), to get: + * + * \Sum_i w_i (s_i - x) + * S - x = -------------------- (7) + * \Sum_i w_i + * + * Which shows that S and s_i transform alike (which makes perfect sense + * given that S is basically the (weighted) average of s_i). + * + * Then: + * + * x -> s_min := min{s_i} (8) + * + * to obtain: + * + * \Sum_i w_i (s_i - s_min) + * S = s_min + ------------------------ (9) + * \Sum_i w_i + * + * Which already looks familiar, and is the basis for our current + * approximation: + * + * S ~= s_min (10) + * + * Now, obviously, (10) is absolute crap :-), but it sorta works. + * + * So the thing to remember is that the above is strictly UP. It is + * possible to generalize to multiple runqueues -- however it gets really + * yuck when you have to add affinity support, as illustrated by our very + * first counter-example. + * + * Luckily I think we can avoid needing a full multi-queue variant for + * core-scheduling (or load-balancing). The crucial observation is that we + * only actually need this comparison in the presence of forced-idle; only + * then do we need to tell if the stalled rq has higher priority over the + * other. + * + * [XXX assumes SMT2; better consider the more general case, I suspect + * it'll work out because our comparison is always between 2 rqs and the + * answer is only interesting if one of them is forced-idle] + * + * And (under assumption of SMT2) when there is forced-idle, there is only + * a single queue, so everything works like normal. + * + * Let, for our runqueue 'k': + * + * T_k = \Sum_i w_i s_i + * W_k = \Sum_i w_i ; for all i of k (11) + * + * Then we can write (6) like: + * + * T_k + * S_k = --- (12) + * W_k + * + * From which immediately follows that: + * + * T_k + T_l + * S_k+l = --------- (13) + * W_k + W_l + * + * On which we can define a combined lag: + * + * lag_k+l(i) := S_k+l - s_i (14) + * + * And that gives us the tools to compare tasks across a combined runqueue. + * + * + * Combined this gives the following: + * + * a) when a runqueue enters force-idle, sync it against it's sibling rq(s) + * using (7); this only requires storing single 'time'-stamps. + * + * b) when comparing tasks between 2 runqueues of which one is forced-idle, + * compare the combined lag, per (14). + * + * Now, of course cgroups (I so hate them) make this more interesting in + * that a) seems to suggest we need to iterate all cgroup on a CPU at such + * boundaries, but I think we can avoid that. The force-idle is for the + * whole CPU, all it's rqs. So we can mark it in the root and lazily + * propagate downward on demand. + */ + +/* + * So this sync is basically a relative reset of S to 0. + * + * So with 2 queues, when one goes idle, we drop them both to 0 and one + * then increases due to not being idle, and the idle one builds up lag to + * get re-elected. So far so simple, right? + * + * When there's 3, we can have the situation where 2 run and one is idle, + * we sync to 0 and let the idle one build up lag to get re-election. Now + * suppose another one also drops idle. At this point dropping all to 0 + * again would destroy the built-up lag from the queue that was already + * idle, not good. + * + * So instead of syncing everything, we can: + * + * less := !((s64)(s_a - s_b) <= 0) + * + * (v_a - S_a) - (v_b - S_b) == v_a - v_b - S_a + S_b + * == v_a - (v_b - S_a + S_b) + * + * IOW, we can recast the (lag) comparison to a one-sided difference. + * So if then, instead of syncing the whole queue, sync the idle queue + * against the active queue with S_a + S_b at the point where we sync. + * + * (XXX consider the implication of living in a cyclic group: N / 2^n N) + * + * This gives us means of syncing single queues against the active queue, + * and for already idle queues to preserve their build-up lag. + * + * Of course, then we get the situation where there's 2 active and one + * going idle, who do we pick to sync against? Theory would have us sync + * against the combined S, but as we've already demonstrated, there is no + * such thing in infeasible weight scenarios. + * + * One thing I've considered; and this is where that core_active rudiment + * came from, is having active queues sync up between themselves after + * every tick. This limits the observed divergence due to the work + * conservancy. + * + * On top of that, we can improve upon things by moving away from our + * horrible (10) hack and moving to (9) and employing (13) here. + */ + /* * se_fi_update - Update the cfs_rq->min_vruntime_fi in a CFS hierarchy if needed. */ From b29d5e3a5625e1172518ae306ffd731a166e58c5 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Mon, 29 Dec 2025 14:35:38 -0500 Subject: [PATCH 1451/2333] sched/eevdf: Fix min_vruntime vs avg_vruntime [ Upstream commit 79f3f9bedd149ea438aaeb0fb6a083637affe205 ] Basically, from the constraint that the sum of lag is zero, you can infer that the 0-lag point is the weighted average of the individual vruntime, which is what we're trying to compute: \Sum w_i * v_i avg = -------------- \Sum w_i Now, since vruntime takes the whole u64 (worse, it wraps), this multiplication term in the numerator is not something we can compute; instead we do the min_vruntime (v0 henceforth) thing like: v_i = (v_i - v0) + v0 This does two things: - it keeps the key: (v_i - v0) 'small'; - it creates a relative 0-point in the modular space. If you do that subtitution and work it all out, you end up with: \Sum w_i * (v_i - v0) avg = --------------------- + v0 \Sum w_i Since you cannot very well track a ratio like that (and not suffer terrible numerical problems) we simpy track the numerator and denominator individually and only perform the division when strictly needed. Notably, the numerator lives in cfs_rq->avg_vruntime and the denominator lives in cfs_rq->avg_load. The one extra 'funny' is that these numbers track the entities in the tree, and current is typically outside of the tree, so avg_vruntime() adds current when needed before doing the division. (vruntime_eligible() elides the division by cross-wise multiplication) Anyway, as mentioned above, we currently use the CFS era min_vruntime for this purpose. However, this thing can only move forward, while the above avg can in fact move backward (when a non-eligible task leaves, the average becomes smaller), this can cause trouble when through happenstance (or construction) these values drift far enough apart to wreck the game. Replace cfs_rq::min_vruntime with cfs_rq::zero_vruntime which is kept near/at avg_vruntime, following its motion. The down-side is that this requires computing the avg more often. Fixes: 147f3efaa241 ("sched/fair: Implement an EEVDF-like scheduling policy") Reported-by: Zicheng Qu Signed-off-by: Peter Zijlstra (Intel) Link: https://patch.msgid.link/20251106111741.GC4068168@noisy.programming.kicks-ass.net Cc: stable@vger.kernel.org Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- kernel/sched/debug.c | 8 +-- kernel/sched/fair.c | 114 ++++++++++--------------------------------- kernel/sched/sched.h | 4 +- 3 files changed, 31 insertions(+), 95 deletions(-) diff --git a/kernel/sched/debug.c b/kernel/sched/debug.c index 02e16b70a7901..41caa22e0680a 100644 --- a/kernel/sched/debug.c +++ b/kernel/sched/debug.c @@ -796,7 +796,7 @@ static void print_rq(struct seq_file *m, struct rq *rq, int rq_cpu) void print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq) { - s64 left_vruntime = -1, min_vruntime, right_vruntime = -1, left_deadline = -1, spread; + s64 left_vruntime = -1, zero_vruntime, right_vruntime = -1, left_deadline = -1, spread; struct sched_entity *last, *first, *root; struct rq *rq = cpu_rq(cpu); unsigned long flags; @@ -819,15 +819,15 @@ void print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq) last = __pick_last_entity(cfs_rq); if (last) right_vruntime = last->vruntime; - min_vruntime = cfs_rq->min_vruntime; + zero_vruntime = cfs_rq->zero_vruntime; raw_spin_rq_unlock_irqrestore(rq, flags); SEQ_printf(m, " .%-30s: %Ld.%06ld\n", "left_deadline", SPLIT_NS(left_deadline)); SEQ_printf(m, " .%-30s: %Ld.%06ld\n", "left_vruntime", SPLIT_NS(left_vruntime)); - SEQ_printf(m, " .%-30s: %Ld.%06ld\n", "min_vruntime", - SPLIT_NS(min_vruntime)); + SEQ_printf(m, " .%-30s: %Ld.%06ld\n", "zero_vruntime", + SPLIT_NS(zero_vruntime)); SEQ_printf(m, " .%-30s: %Ld.%06ld\n", "avg_vruntime", SPLIT_NS(avg_vruntime(cfs_rq))); SEQ_printf(m, " .%-30s: %Ld.%06ld\n", "right_vruntime", diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 94a45a2d43422..bfce451f1210c 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -554,7 +554,7 @@ static inline bool entity_before(const struct sched_entity *a, static inline s64 entity_key(struct cfs_rq *cfs_rq, struct sched_entity *se) { - return (s64)(se->vruntime - cfs_rq->min_vruntime); + return (s64)(se->vruntime - cfs_rq->zero_vruntime); } #define __node_2_se(node) \ @@ -606,13 +606,13 @@ static inline s64 entity_key(struct cfs_rq *cfs_rq, struct sched_entity *se) * * Which we track using: * - * v0 := cfs_rq->min_vruntime + * v0 := cfs_rq->zero_vruntime * \Sum (v_i - v0) * w_i := cfs_rq->avg_vruntime * \Sum w_i := cfs_rq->avg_load * - * Since min_vruntime is a monotonic increasing variable that closely tracks - * the per-task service, these deltas: (v_i - v), will be in the order of the - * maximal (virtual) lag induced in the system due to quantisation. + * Since zero_vruntime closely tracks the per-task service, these + * deltas: (v_i - v), will be in the order of the maximal (virtual) lag + * induced in the system due to quantisation. * * Also, we use scale_load_down() to reduce the size. * @@ -671,7 +671,7 @@ u64 avg_vruntime(struct cfs_rq *cfs_rq) avg = div_s64(avg, load); } - return cfs_rq->min_vruntime + avg; + return cfs_rq->zero_vruntime + avg; } /* @@ -732,7 +732,7 @@ static int vruntime_eligible(struct cfs_rq *cfs_rq, u64 vruntime) load += weight; } - return avg >= (s64)(vruntime - cfs_rq->min_vruntime) * load; + return avg >= (s64)(vruntime - cfs_rq->zero_vruntime) * load; } int entity_eligible(struct cfs_rq *cfs_rq, struct sched_entity *se) @@ -740,42 +740,14 @@ int entity_eligible(struct cfs_rq *cfs_rq, struct sched_entity *se) return vruntime_eligible(cfs_rq, se->vruntime); } -static u64 __update_min_vruntime(struct cfs_rq *cfs_rq, u64 vruntime) +static void update_zero_vruntime(struct cfs_rq *cfs_rq) { - u64 min_vruntime = cfs_rq->min_vruntime; - /* - * open coded max_vruntime() to allow updating avg_vruntime - */ - s64 delta = (s64)(vruntime - min_vruntime); - if (delta > 0) { - avg_vruntime_update(cfs_rq, delta); - min_vruntime = vruntime; - } - return min_vruntime; -} + u64 vruntime = avg_vruntime(cfs_rq); + s64 delta = (s64)(vruntime - cfs_rq->zero_vruntime); -static void update_min_vruntime(struct cfs_rq *cfs_rq) -{ - struct sched_entity *se = __pick_root_entity(cfs_rq); - struct sched_entity *curr = cfs_rq->curr; - u64 vruntime = cfs_rq->min_vruntime; - - if (curr) { - if (curr->on_rq) - vruntime = curr->vruntime; - else - curr = NULL; - } + avg_vruntime_update(cfs_rq, delta); - if (se) { - if (!curr) - vruntime = se->min_vruntime; - else - vruntime = min_vruntime(vruntime, se->min_vruntime); - } - - /* ensure we never gain time by being placed backwards. */ - cfs_rq->min_vruntime = __update_min_vruntime(cfs_rq, vruntime); + cfs_rq->zero_vruntime = vruntime; } static inline u64 cfs_rq_min_slice(struct cfs_rq *cfs_rq) @@ -848,6 +820,7 @@ RB_DECLARE_CALLBACKS(static, min_vruntime_cb, struct sched_entity, static void __enqueue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se) { avg_vruntime_add(cfs_rq, se); + update_zero_vruntime(cfs_rq); se->min_vruntime = se->vruntime; se->min_slice = se->slice; rb_add_augmented_cached(&se->run_node, &cfs_rq->tasks_timeline, @@ -859,6 +832,7 @@ static void __dequeue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se) rb_erase_augmented_cached(&se->run_node, &cfs_rq->tasks_timeline, &min_vruntime_cb); avg_vruntime_sub(cfs_rq, se); + update_zero_vruntime(cfs_rq); } struct sched_entity *__pick_root_entity(struct cfs_rq *cfs_rq) @@ -1226,7 +1200,6 @@ static void update_curr(struct cfs_rq *cfs_rq) curr->vruntime += calc_delta_fair(delta_exec, curr); resched = update_deadline(cfs_rq, curr); - update_min_vruntime(cfs_rq); if (entity_is_task(curr)) { /* @@ -3808,15 +3781,6 @@ static void reweight_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, if (!curr) __enqueue_entity(cfs_rq, se); cfs_rq->nr_queued++; - - /* - * The entity's vruntime has been adjusted, so let's check - * whether the rq-wide min_vruntime needs updated too. Since - * the calculations above require stable min_vruntime rather - * than up-to-date one, we do the update at the end of the - * reweight process. - */ - update_min_vruntime(cfs_rq); } } @@ -5432,15 +5396,6 @@ dequeue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags) update_cfs_group(se); - /* - * Now advance min_vruntime if @se was the entity holding it back, - * except when: DEQUEUE_SAVE && !DEQUEUE_MOVE, in this case we'll be - * put back on, and if we advance min_vruntime, we'll be placed back - * further than we started -- i.e. we'll be penalized. - */ - if ((flags & (DEQUEUE_SAVE | DEQUEUE_MOVE)) != DEQUEUE_SAVE) - update_min_vruntime(cfs_rq); - if (flags & DEQUEUE_DELAYED) finish_delayed_dequeue_entity(se); @@ -9028,7 +8983,6 @@ static void yield_task_fair(struct rq *rq) if (entity_eligible(cfs_rq, se)) { se->vruntime = se->deadline; se->deadline += calc_delta_fair(se->slice, se); - update_min_vruntime(cfs_rq); } } @@ -13077,23 +13031,6 @@ static inline void task_tick_core(struct rq *rq, struct task_struct *curr) * Which shows that S and s_i transform alike (which makes perfect sense * given that S is basically the (weighted) average of s_i). * - * Then: - * - * x -> s_min := min{s_i} (8) - * - * to obtain: - * - * \Sum_i w_i (s_i - s_min) - * S = s_min + ------------------------ (9) - * \Sum_i w_i - * - * Which already looks familiar, and is the basis for our current - * approximation: - * - * S ~= s_min (10) - * - * Now, obviously, (10) is absolute crap :-), but it sorta works. - * * So the thing to remember is that the above is strictly UP. It is * possible to generalize to multiple runqueues -- however it gets really * yuck when you have to add affinity support, as illustrated by our very @@ -13115,23 +13052,23 @@ static inline void task_tick_core(struct rq *rq, struct task_struct *curr) * Let, for our runqueue 'k': * * T_k = \Sum_i w_i s_i - * W_k = \Sum_i w_i ; for all i of k (11) + * W_k = \Sum_i w_i ; for all i of k (8) * * Then we can write (6) like: * * T_k - * S_k = --- (12) + * S_k = --- (9) * W_k * * From which immediately follows that: * * T_k + T_l - * S_k+l = --------- (13) + * S_k+l = --------- (10) * W_k + W_l * * On which we can define a combined lag: * - * lag_k+l(i) := S_k+l - s_i (14) + * lag_k+l(i) := S_k+l - s_i (11) * * And that gives us the tools to compare tasks across a combined runqueue. * @@ -13142,7 +13079,7 @@ static inline void task_tick_core(struct rq *rq, struct task_struct *curr) * using (7); this only requires storing single 'time'-stamps. * * b) when comparing tasks between 2 runqueues of which one is forced-idle, - * compare the combined lag, per (14). + * compare the combined lag, per (11). * * Now, of course cgroups (I so hate them) make this more interesting in * that a) seems to suggest we need to iterate all cgroup on a CPU at such @@ -13190,12 +13127,11 @@ static inline void task_tick_core(struct rq *rq, struct task_struct *curr) * every tick. This limits the observed divergence due to the work * conservancy. * - * On top of that, we can improve upon things by moving away from our - * horrible (10) hack and moving to (9) and employing (13) here. + * On top of that, we can improve upon things by employing (10) here. */ /* - * se_fi_update - Update the cfs_rq->min_vruntime_fi in a CFS hierarchy if needed. + * se_fi_update - Update the cfs_rq->zero_vruntime_fi in a CFS hierarchy if needed. */ static void se_fi_update(const struct sched_entity *se, unsigned int fi_seq, bool forceidle) @@ -13209,7 +13145,7 @@ static void se_fi_update(const struct sched_entity *se, unsigned int fi_seq, cfs_rq->forceidle_seq = fi_seq; } - cfs_rq->min_vruntime_fi = cfs_rq->min_vruntime; + cfs_rq->zero_vruntime_fi = cfs_rq->zero_vruntime; } } @@ -13262,11 +13198,11 @@ bool cfs_prio_less(const struct task_struct *a, const struct task_struct *b, /* * Find delta after normalizing se's vruntime with its cfs_rq's - * min_vruntime_fi, which would have been updated in prior calls + * zero_vruntime_fi, which would have been updated in prior calls * to se_fi_update(). */ delta = (s64)(sea->vruntime - seb->vruntime) + - (s64)(cfs_rqb->min_vruntime_fi - cfs_rqa->min_vruntime_fi); + (s64)(cfs_rqb->zero_vruntime_fi - cfs_rqa->zero_vruntime_fi); return delta > 0; } @@ -13502,7 +13438,7 @@ static void set_next_task_fair(struct rq *rq, struct task_struct *p, bool first) void init_cfs_rq(struct cfs_rq *cfs_rq) { cfs_rq->tasks_timeline = RB_ROOT_CACHED; - cfs_rq->min_vruntime = (u64)(-(1LL << 20)); + cfs_rq->zero_vruntime = (u64)(-(1LL << 20)); raw_spin_lock_init(&cfs_rq->removed.lock); } diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index adfb6e3409d72..92ec751799f55 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -682,10 +682,10 @@ struct cfs_rq { s64 avg_vruntime; u64 avg_load; - u64 min_vruntime; + u64 zero_vruntime; #ifdef CONFIG_SCHED_CORE unsigned int forceidle_seq; - u64 min_vruntime_fi; + u64 zero_vruntime_fi; #endif struct rb_root_cached tasks_timeline; From aeabe44c5019327f171973e357d634e42bf038cf Mon Sep 17 00:00:00 2001 From: Zqiang Date: Mon, 29 Dec 2025 14:36:40 -0500 Subject: [PATCH 1452/2333] sched_ext: Fix incorrect sched_class settings for per-cpu migration tasks [ Upstream commit 1dd6c84f1c544e552848a8968599220bd464e338 ] When loading the ebpf scheduler, the tasks in the scx_tasks list will be traversed and invoke __setscheduler_class() to get new sched_class. however, this would also incorrectly set the per-cpu migration task's->sched_class to rt_sched_class, even after unload, the per-cpu migration task's->sched_class remains sched_rt_class. The log for this issue is as follows: ./scx_rustland --stats 1 [ 199.245639][ T630] sched_ext: "rustland" does not implement cgroup cpu.weight [ 199.269213][ T630] sched_ext: BPF scheduler "rustland" enabled 04:25:09 [INFO] RustLand scheduler attached bpftrace -e 'iter:task /strcontains(ctx->task->comm, "migration")/ { printf("%s:%d->%pS\n", ctx->task->comm, ctx->task->pid, ctx->task->sched_class); }' Attaching 1 probe... migration/0:24->rt_sched_class+0x0/0xe0 migration/1:27->rt_sched_class+0x0/0xe0 migration/2:33->rt_sched_class+0x0/0xe0 migration/3:39->rt_sched_class+0x0/0xe0 migration/4:45->rt_sched_class+0x0/0xe0 migration/5:52->rt_sched_class+0x0/0xe0 migration/6:58->rt_sched_class+0x0/0xe0 migration/7:64->rt_sched_class+0x0/0xe0 sched_ext: BPF scheduler "rustland" disabled (unregistered from user space) EXIT: unregistered from user space 04:25:21 [INFO] Unregister RustLand scheduler bpftrace -e 'iter:task /strcontains(ctx->task->comm, "migration")/ { printf("%s:%d->%pS\n", ctx->task->comm, ctx->task->pid, ctx->task->sched_class); }' Attaching 1 probe... migration/0:24->rt_sched_class+0x0/0xe0 migration/1:27->rt_sched_class+0x0/0xe0 migration/2:33->rt_sched_class+0x0/0xe0 migration/3:39->rt_sched_class+0x0/0xe0 migration/4:45->rt_sched_class+0x0/0xe0 migration/5:52->rt_sched_class+0x0/0xe0 migration/6:58->rt_sched_class+0x0/0xe0 migration/7:64->rt_sched_class+0x0/0xe0 This commit therefore generate a new scx_setscheduler_class() and add check for stop_sched_class to replace __setscheduler_class(). Fixes: f0e1a0643a59 ("sched_ext: Implement BPF extensible scheduler class") Cc: stable@vger.kernel.org # v6.12+ Signed-off-by: Zqiang Reviewed-by: Andrea Righi Signed-off-by: Tejun Heo [ Adjust context ] Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- kernel/sched/ext.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/kernel/sched/ext.c b/kernel/sched/ext.c index 907eea83294ce..6139263afd598 100644 --- a/kernel/sched/ext.c +++ b/kernel/sched/ext.c @@ -210,6 +210,14 @@ static struct scx_dispatch_q *find_user_dsq(struct scx_sched *sch, u64 dsq_id) return rhashtable_lookup_fast(&sch->dsq_hash, &dsq_id, dsq_hash_params); } +static const struct sched_class *scx_setscheduler_class(struct task_struct *p) +{ + if (p->sched_class == &stop_sched_class) + return &stop_sched_class; + + return __setscheduler_class(p->policy, p->prio); +} + /* * scx_kf_mask enforcement. Some kfuncs can only be called from specific SCX * ops. When invoking SCX ops, SCX_CALL_OP[_RET]() should be used to indicate @@ -3994,8 +4002,7 @@ static void scx_disable_workfn(struct kthread_work *work) scx_task_iter_start(&sti); while ((p = scx_task_iter_next_locked(&sti))) { const struct sched_class *old_class = p->sched_class; - const struct sched_class *new_class = - __setscheduler_class(p->policy, p->prio); + const struct sched_class *new_class = scx_setscheduler_class(p); struct sched_enq_and_set_ctx ctx; if (old_class != new_class && p->se.sched_delayed) @@ -4779,8 +4786,7 @@ static int scx_enable(struct sched_ext_ops *ops, struct bpf_link *link) scx_task_iter_start(&sti); while ((p = scx_task_iter_next_locked(&sti))) { const struct sched_class *old_class = p->sched_class; - const struct sched_class *new_class = - __setscheduler_class(p->policy, p->prio); + const struct sched_class *new_class = scx_setscheduler_class(p); struct sched_enq_and_set_ctx ctx; if (!tryget_task_struct(p)) From 2a30b3c9eae1ca45cd0c7232a3d78b62d5dcd7c3 Mon Sep 17 00:00:00 2001 From: Wei Yang Date: Mon, 29 Dec 2025 21:48:31 -0500 Subject: [PATCH 1453/2333] mm/huge_memory: merge uniform_split_supported() and non_uniform_split_supported() [ Upstream commit 8a0e4bdddd1c998b894d879a1d22f1e745606215 ] uniform_split_supported() and non_uniform_split_supported() share significantly similar logic. The only functional difference is that uniform_split_supported() includes an additional check on the requested @new_order. The reason for this check comes from the following two aspects: * some file system or swap cache just supports order-0 folio * the behavioral difference between uniform/non-uniform split The behavioral difference between uniform split and non-uniform: * uniform split splits folio directly to @new_order * non-uniform split creates after-split folios with orders from folio_order(folio) - 1 to new_order. This means for non-uniform split or !new_order split we should check the file system and swap cache respectively. This commit unifies the logic and merge the two functions into a single combined helper, removing redundant code and simplifying the split support checking mechanism. Link: https://lkml.kernel.org/r/20251106034155.21398-3-richard.weiyang@gmail.com Fixes: c010d47f107f ("mm: thp: split huge page to any lower order pages") Signed-off-by: Wei Yang Reviewed-by: Zi Yan Cc: Zi Yan Cc: "David Hildenbrand (Red Hat)" Cc: Baolin Wang Cc: Barry Song Cc: Dev Jain Cc: Lance Yang Cc: Liam Howlett Cc: Lorenzo Stoakes Cc: Nico Pache Cc: Ryan Roberts Cc: Signed-off-by: Andrew Morton [ split_type => uniform_split and replaced SPLIT_TYPE_NON_UNIFORM checks ] Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- include/linux/huge_mm.h | 8 ++--- mm/huge_memory.c | 71 +++++++++++++++++------------------------ 2 files changed, 33 insertions(+), 46 deletions(-) diff --git a/include/linux/huge_mm.h b/include/linux/huge_mm.h index 71ac78b9f834f..240cbc6764809 100644 --- a/include/linux/huge_mm.h +++ b/include/linux/huge_mm.h @@ -369,10 +369,8 @@ int split_huge_page_to_list_to_order(struct page *page, struct list_head *list, unsigned int new_order); int min_order_for_split(struct folio *folio); int split_folio_to_list(struct folio *folio, struct list_head *list); -bool uniform_split_supported(struct folio *folio, unsigned int new_order, - bool warns); -bool non_uniform_split_supported(struct folio *folio, unsigned int new_order, - bool warns); +bool folio_split_supported(struct folio *folio, unsigned int new_order, + bool uniform_split, bool warns); int folio_split(struct folio *folio, unsigned int new_order, struct page *page, struct list_head *list); /* @@ -392,7 +390,7 @@ int folio_split(struct folio *folio, unsigned int new_order, struct page *page, static inline int try_folio_split_to_order(struct folio *folio, struct page *page, unsigned int new_order) { - if (!non_uniform_split_supported(folio, new_order, /* warns= */ false)) + if (!folio_split_supported(folio, new_order, false, /* warns= */ false)) return split_huge_page_to_list_to_order(&folio->page, NULL, new_order); return folio_split(folio, new_order, page, NULL); diff --git a/mm/huge_memory.c b/mm/huge_memory.c index f66a4b15cb336..8ad170b9855a5 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -3515,8 +3515,8 @@ static int __split_unmapped_folio(struct folio *folio, int new_order, return ret; } -bool non_uniform_split_supported(struct folio *folio, unsigned int new_order, - bool warns) +bool folio_split_supported(struct folio *folio, unsigned int new_order, + bool uniform_split, bool warns) { if (folio_test_anon(folio)) { /* order-1 is not supported for anonymous THP. */ @@ -3524,48 +3524,41 @@ bool non_uniform_split_supported(struct folio *folio, unsigned int new_order, "Cannot split to order-1 folio"); if (new_order == 1) return false; - } else if (IS_ENABLED(CONFIG_READ_ONLY_THP_FOR_FS) && - !mapping_large_folio_support(folio->mapping)) { - /* - * No split if the file system does not support large folio. - * Note that we might still have THPs in such mappings due to - * CONFIG_READ_ONLY_THP_FOR_FS. But in that case, the mapping - * does not actually support large folios properly. - */ - VM_WARN_ONCE(warns, - "Cannot split file folio to non-0 order"); - return false; - } - - /* Only swapping a whole PMD-mapped folio is supported */ - if (folio_test_swapcache(folio)) { - VM_WARN_ONCE(warns, - "Cannot split swapcache folio to non-0 order"); - return false; - } - - return true; -} - -/* See comments in non_uniform_split_supported() */ -bool uniform_split_supported(struct folio *folio, unsigned int new_order, - bool warns) -{ - if (folio_test_anon(folio)) { - VM_WARN_ONCE(warns && new_order == 1, - "Cannot split to order-1 folio"); - if (new_order == 1) - return false; - } else if (new_order) { + } else if (!uniform_split || new_order) { if (IS_ENABLED(CONFIG_READ_ONLY_THP_FOR_FS) && !mapping_large_folio_support(folio->mapping)) { + /* + * We can always split a folio down to a single page + * (new_order == 0) uniformly. + * + * For any other scenario + * a) uniform split targeting a large folio + * (new_order > 0) + * b) any non-uniform split + * we must confirm that the file system supports large + * folios. + * + * Note that we might still have THPs in such + * mappings, which is created from khugepaged when + * CONFIG_READ_ONLY_THP_FOR_FS is enabled. But in that + * case, the mapping does not actually support large + * folios properly. + */ VM_WARN_ONCE(warns, "Cannot split file folio to non-0 order"); return false; } } - if (new_order && folio_test_swapcache(folio)) { + /* + * swapcache folio could only be split to order 0 + * + * non-uniform split creates after-split folios with orders from + * folio_order(folio) - 1 to new_order, making it not suitable for any + * swapcache folio split. Only uniform split to order-0 can be used + * here. + */ + if ((!uniform_split || new_order) && folio_test_swapcache(folio)) { VM_WARN_ONCE(warns, "Cannot split swapcache folio to non-0 order"); return false; @@ -3632,11 +3625,7 @@ static int __folio_split(struct folio *folio, unsigned int new_order, if (new_order >= folio_order(folio)) return -EINVAL; - if (uniform_split && !uniform_split_supported(folio, new_order, true)) - return -EINVAL; - - if (!uniform_split && - !non_uniform_split_supported(folio, new_order, true)) + if (!folio_split_supported(folio, new_order, uniform_split, /* warn = */ true)) return -EINVAL; is_hzp = is_huge_zero_folio(folio); From 2af2abbcbf8573100288e8f8aea2dab8a2a0ceb7 Mon Sep 17 00:00:00 2001 From: Claudio Imbrenda Date: Tue, 30 Dec 2025 22:16:26 -0500 Subject: [PATCH 1454/2333] KVM: s390: Fix gmap_helper_zap_one_page() again [ Upstream commit 2f393c228cc519ddf19b8c6c05bf15723241aa96 ] A few checks were missing in gmap_helper_zap_one_page(), which can lead to memory corruption in the guest under specific circumstances. Add the missing checks. Fixes: 5deafa27d9ae ("KVM: s390: Fix to clear PTE when discarding a swapped page") Cc: stable@vger.kernel.org Reported-by: Marc Hartmayer Tested-by: Marc Hartmayer Acked-by: Christian Borntraeger Signed-off-by: Claudio Imbrenda Signed-off-by: Heiko Carstens [ adapted ptep_zap_softleaf_entry() and softleaf_from_pte() calls to ptep_zap_swap_entry() and pte_to_swp_entry() ] Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/s390/mm/gmap_helpers.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/arch/s390/mm/gmap_helpers.c b/arch/s390/mm/gmap_helpers.c index d4c3c36855e26..38a2d82cd88a7 100644 --- a/arch/s390/mm/gmap_helpers.c +++ b/arch/s390/mm/gmap_helpers.c @@ -47,6 +47,7 @@ static void ptep_zap_swap_entry(struct mm_struct *mm, swp_entry_t entry) void gmap_helper_zap_one_page(struct mm_struct *mm, unsigned long vmaddr) { struct vm_area_struct *vma; + unsigned long pgstev; spinlock_t *ptl; pgste_t pgste; pte_t *ptep; @@ -65,9 +66,13 @@ void gmap_helper_zap_one_page(struct mm_struct *mm, unsigned long vmaddr) if (pte_swap(*ptep)) { preempt_disable(); pgste = pgste_get_lock(ptep); + pgstev = pgste_val(pgste); - ptep_zap_swap_entry(mm, pte_to_swp_entry(*ptep)); - pte_clear(mm, vmaddr, ptep); + if ((pgstev & _PGSTE_GPS_USAGE_MASK) == _PGSTE_GPS_USAGE_UNUSED || + (pgstev & _PGSTE_GPS_ZERO)) { + ptep_zap_swap_entry(mm, pte_to_swp_entry(*ptep)); + pte_clear(mm, vmaddr, ptep); + } pgste_set_unlock(ptep, pgste); preempt_enable(); From 61c0901cbd7220434c0e019db888b45e064420ec Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 31 Dec 2025 11:18:55 -0500 Subject: [PATCH 1455/2333] drm/edid: add DRM_EDID_IDENT_INIT() to initialize struct drm_edid_ident MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 8b61583f993589a64c061aa91b44f5bd350d90a5 ] Add a convenience helper for initializing struct drm_edid_ident. Cc: Tiago Martins Araújo Acked-by: Alex Deucher Tested-by: Tiago Martins Araújo Cc: stable@vger.kernel.org Link: https://patch.msgid.link/710b2ac6a211606ec1f90afa57b79e8c7375a27e.1761681968.git.jani.nikula@intel.com Signed-off-by: Jani Nikula Stable-dep-of: 83cbb4d33dc2 ("drm/displayid: add quirk to ignore DisplayID checksum errors") Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- include/drm/drm_edid.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h index 3d1aecfec9b2a..04f7a7f1f1082 100644 --- a/include/drm/drm_edid.h +++ b/include/drm/drm_edid.h @@ -340,6 +340,12 @@ struct drm_edid_ident { const char *name; }; +#define DRM_EDID_IDENT_INIT(_vend_chr_0, _vend_chr_1, _vend_chr_2, _product_id, _name) \ +{ \ + .panel_id = drm_edid_encode_panel_id(_vend_chr_0, _vend_chr_1, _vend_chr_2, _product_id), \ + .name = _name, \ +} + #define EDID_PRODUCT_ID(e) ((e)->prod_code[0] | ((e)->prod_code[1] << 8)) /* Short Audio Descriptor */ From 99204fdc989ca6abb74526200020c2069d139814 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 31 Dec 2025 11:18:56 -0500 Subject: [PATCH 1456/2333] drm/displayid: add quirk to ignore DisplayID checksum errors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 83cbb4d33dc22b0ca1a4e85c6e892c9b729e28d4 ] Add a mechanism for DisplayID specific quirks, and add the first quirk to ignore DisplayID section checksum errors. It would be quite inconvenient to pass existing EDID quirks from drm_edid.c for DisplayID parsing. Not all places doing DisplayID iteration have the quirks readily available, and would have to pass it in all places. Simply add a separate array of DisplayID specific EDID quirks. We do end up checking it every time we iterate DisplayID blocks, but hopefully the number of quirks remains small. There are a few laptop models with DisplayID checksum failures, leading to higher refresh rates only present in the DisplayID blocks being ignored. Add a quirk for the panel in the machines. Reported-by: Tiago Martins Araújo Closes: https://lore.kernel.org/r/CACRbrPGvLP5LANXuFi6z0S7XMbAG4X5y2YOLBDxfOVtfGGqiKQ@mail.gmail.com Closes: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/14703 Acked-by: Alex Deucher Tested-by: Tiago Martins Araújo Cc: stable@vger.kernel.org Link: https://patch.msgid.link/c04d81ae648c5f21b3f5b7953f924718051f2798.1761681968.git.jani.nikula@intel.com Signed-off-by: Jani Nikula Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/drm_displayid.c | 41 +++++++++++++++++++++--- drivers/gpu/drm/drm_displayid_internal.h | 2 ++ 2 files changed, 39 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/drm_displayid.c b/drivers/gpu/drm/drm_displayid.c index 20b453d2b8547..58d0bb6d26768 100644 --- a/drivers/gpu/drm/drm_displayid.c +++ b/drivers/gpu/drm/drm_displayid.c @@ -9,6 +9,34 @@ #include "drm_crtc_internal.h" #include "drm_displayid_internal.h" +enum { + QUIRK_IGNORE_CHECKSUM, +}; + +struct displayid_quirk { + const struct drm_edid_ident ident; + u8 quirks; +}; + +static const struct displayid_quirk quirks[] = { + { + .ident = DRM_EDID_IDENT_INIT('C', 'S', 'O', 5142, "MNE007ZA1-5"), + .quirks = BIT(QUIRK_IGNORE_CHECKSUM), + }, +}; + +static u8 get_quirks(const struct drm_edid *drm_edid) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(quirks); i++) { + if (drm_edid_match(drm_edid, &quirks[i].ident)) + return quirks[i].quirks; + } + + return 0; +} + static const struct displayid_header * displayid_get_header(const u8 *displayid, int length, int index) { @@ -23,7 +51,7 @@ displayid_get_header(const u8 *displayid, int length, int index) } static const struct displayid_header * -validate_displayid(const u8 *displayid, int length, int idx) +validate_displayid(const u8 *displayid, int length, int idx, bool ignore_checksum) { int i, dispid_length; u8 csum = 0; @@ -41,8 +69,11 @@ validate_displayid(const u8 *displayid, int length, int idx) for (i = 0; i < dispid_length; i++) csum += displayid[idx + i]; if (csum) { - DRM_NOTE("DisplayID checksum invalid, remainder is %d\n", csum); - return ERR_PTR(-EINVAL); + DRM_NOTE("DisplayID checksum invalid, remainder is %d%s\n", csum, + ignore_checksum ? " (ignoring)" : ""); + + if (!ignore_checksum) + return ERR_PTR(-EINVAL); } return base; @@ -52,6 +83,7 @@ static const u8 *find_next_displayid_extension(struct displayid_iter *iter) { const struct displayid_header *base; const u8 *displayid; + bool ignore_checksum = iter->quirks & BIT(QUIRK_IGNORE_CHECKSUM); displayid = drm_edid_find_extension(iter->drm_edid, DISPLAYID_EXT, &iter->ext_index); if (!displayid) @@ -61,7 +93,7 @@ static const u8 *find_next_displayid_extension(struct displayid_iter *iter) iter->length = EDID_LENGTH - 1; iter->idx = 1; - base = validate_displayid(displayid, iter->length, iter->idx); + base = validate_displayid(displayid, iter->length, iter->idx, ignore_checksum); if (IS_ERR(base)) return NULL; @@ -76,6 +108,7 @@ void displayid_iter_edid_begin(const struct drm_edid *drm_edid, memset(iter, 0, sizeof(*iter)); iter->drm_edid = drm_edid; + iter->quirks = get_quirks(drm_edid); } static const struct displayid_block * diff --git a/drivers/gpu/drm/drm_displayid_internal.h b/drivers/gpu/drm/drm_displayid_internal.h index 957dd0619f5c5..5b1b32f735166 100644 --- a/drivers/gpu/drm/drm_displayid_internal.h +++ b/drivers/gpu/drm/drm_displayid_internal.h @@ -167,6 +167,8 @@ struct displayid_iter { u8 version; u8 primary_use; + + u8 quirks; }; void displayid_iter_edid_begin(const struct drm_edid *drm_edid, From 7f1f50c2055b0d19534e4615b653af936a967d79 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 2 Dec 2025 14:24:03 -0500 Subject: [PATCH 1457/2333] drm/amdgpu: don't attach the tlb fence for SI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit eb296c09805ee37dd4ea520a7fb3ec157c31090f upstream. SI hardware doesn't support pasids, user mode queues, or KIQ/MES so there is no need for this. Doing so results in a segfault as these callbacks are non-existent for SI. Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/4744 Fixes: f3854e04b708 ("drm/amdgpu: attach tlb fence to the PTs update") Reviewed-by: Timur Kristóf Signed-off-by: Alex Deucher (cherry picked from commit 820b3d376e8a102c6aeab737ec6edebbbb710e04) Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index 676e24fb88647..cdcafde3c71a1 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -1066,7 +1066,9 @@ amdgpu_vm_tlb_flush(struct amdgpu_vm_update_params *params, } /* Prepare a TLB flush fence to be attached to PTs */ - if (!params->unlocked) { + if (!params->unlocked && + /* SI doesn't support pasid or KIQ/MES */ + params->adev->family > AMDGPU_FAMILY_SI) { amdgpu_vm_tlb_fence_create(params->adev, vm, fence); /* Makes sure no PD/PT is freed before the flush */ From e5c129a0553101250ef53c274d2ef7a8c39d76b1 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Tue, 25 Nov 2025 09:38:49 +0800 Subject: [PATCH 1458/2333] wifi: rtw88: limit indirect IO under powered off for RTL8822CS [ Upstream commit f3ccdfda345ca9a624ea425840a926b8338c1e25 ] The indirect IO is necessary for RTL8822CS, but not necessary for other chips. Otherwiese, it throws errors and becomes unusable. rtw88_8723cs mmc1:0001:1: WOW Firmware version 11.0.0, H2C version 0 rtw88_8723cs mmc1:0001:1: Firmware version 11.0.0, H2C version 0 rtw88_8723cs mmc1:0001:1: sdio read32 failed (0xf0): -110 rtw88_8723cs mmc1:0001:1: sdio write8 failed (0x1c): -110 rtw88_8723cs mmc1:0001:1: sdio read32 failed (0xf0): -110 By vendor driver, only RTL8822CS and RTL8822ES need indirect IO, but RTL8822ES isn't supported yet. Therefore, limit it to RTL8822CS only. Reported-by: Andrey Skvortsov Closes: https://lore.kernel.org/linux-wireless/07a32e2d6c764eb1bd9415b5a921a652@realtek.com/T/#m997b4522f7209ba629561c776bfd1d13ab24c1d4 Fixes: 58de1f91e033 ("wifi: rtw88: sdio: use indirect IO for device registers before power-on") Signed-off-by: Ping-Ke Shih Tested-by: Andrey Skvortsov Link: https://patch.msgid.link/1764034729-1251-1-git-send-email-pkshih@realtek.com Signed-off-by: Sasha Levin --- drivers/net/wireless/realtek/rtw88/sdio.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw88/sdio.c b/drivers/net/wireless/realtek/rtw88/sdio.c index 99d7c629eac6f..e35de52d8eb43 100644 --- a/drivers/net/wireless/realtek/rtw88/sdio.c +++ b/drivers/net/wireless/realtek/rtw88/sdio.c @@ -144,8 +144,10 @@ static u32 rtw_sdio_to_io_address(struct rtw_dev *rtwdev, u32 addr, static bool rtw_sdio_use_direct_io(struct rtw_dev *rtwdev, u32 addr) { + bool might_indirect_under_power_off = rtwdev->chip->id == RTW_CHIP_TYPE_8822C; + if (!test_bit(RTW_FLAG_POWERON, rtwdev->flags) && - !rtw_sdio_is_bus_addr(addr)) + !rtw_sdio_is_bus_addr(addr) && might_indirect_under_power_off) return false; return !rtw_sdio_is_sdio30_supported(rtwdev) || From 90a15ff324645aa806d81fa349497cd964861b66 Mon Sep 17 00:00:00 2001 From: Morning Star Date: Thu, 27 Nov 2025 16:37:08 +0800 Subject: [PATCH 1459/2333] wifi: rtlwifi: 8192cu: fix tid out of range in rtl92cu_tx_fill_desc() [ Upstream commit dd39edb445f07400e748da967a07d5dca5c5f96e ] TID getting from ieee80211_get_tid() might be out of range of array size of sta_entry->tids[], so check TID is less than MAX_TID_COUNT. Othwerwise, UBSAN warn: UBSAN: array-index-out-of-bounds in drivers/net/wireless/realtek/rtlwifi/rtl8192cu/trx.c:514:30 index 10 is out of range for type 'rtl_tid_data [9]' Fixes: 8ca4cdef9329 ("wifi: rtlwifi: rtl8192cu: Fix TX aggregation") Signed-off-by: Morning Star Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/1764232628-13625-1-git-send-email-pkshih@realtek.com Signed-off-by: Sasha Levin --- drivers/net/wireless/realtek/rtlwifi/rtl8192cu/trx.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/trx.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/trx.c index aa702ba7c9f54..d6c35e8d02a58 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/trx.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/trx.c @@ -511,7 +511,8 @@ void rtl92cu_tx_fill_desc(struct ieee80211_hw *hw, if (sta) { sta_entry = (struct rtl_sta_info *)sta->drv_priv; tid = ieee80211_get_tid(hdr); - agg_state = sta_entry->tids[tid].agg.agg_state; + if (tid < MAX_TID_COUNT) + agg_state = sta_entry->tids[tid].agg.agg_state; ampdu_density = sta->deflink.ht_cap.ampdu_density; } From 7ea38152a2895fd7bf0f28802bab858451ff94fb Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 3 Dec 2025 14:14:47 +0300 Subject: [PATCH 1460/2333] wifi: cfg80211: sme: store capped length in __cfg80211_connect_result() [ Upstream commit 2b77b9551d1184cb5af8271ff350e6e2c1b3db0d ] The QGenie AI code review tool says we should store the capped length to wdev->u.client.ssid_len. The AI is correct. Fixes: 62b635dcd69c ("wifi: cfg80211: sme: cap SSID length in __cfg80211_connect_result()") Signed-off-by: Dan Carpenter Link: https://patch.msgid.link/aTAbp5RleyH_lnZE@stanley.mountain Signed-off-by: Johannes Berg Signed-off-by: Sasha Levin --- net/wireless/sme.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/wireless/sme.c b/net/wireless/sme.c index 3a028ff287fbb..4e629ca305bcc 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -910,7 +910,7 @@ void __cfg80211_connect_result(struct net_device *dev, ssid_len = min(ssid->datalen, IEEE80211_MAX_SSID_LEN); memcpy(wdev->u.client.ssid, ssid->data, ssid_len); - wdev->u.client.ssid_len = ssid->datalen; + wdev->u.client.ssid_len = ssid_len; break; } rcu_read_unlock(); From 182a2786d248e5051c55e1710643e7af32a98453 Mon Sep 17 00:00:00 2001 From: Aloka Dixit Date: Mon, 15 Dec 2025 09:46:56 -0800 Subject: [PATCH 1461/2333] wifi: mac80211: do not use old MBSSID elements [ Upstream commit a519be2f5d958c5804f2cfd68f1f384291271fab ] When userspace brings down and deletes a non-transmitted profile, it is expected to send a new updated Beacon template for the transmitted profile of that multiple BSSID (MBSSID) group which does not include the removed profile in MBSSID element. This update comes via NL80211_CMD_SET_BEACON. Such updates work well as long as the group continues to have at least one non-transmitted profile as NL80211_ATTR_MBSSID_ELEMS is included in the new Beacon template. But when the last non-trasmitted profile is removed, it still gets included in Beacon templates sent to driver. This happens because when no MBSSID elements are sent by the userspace, ieee80211_assign_beacon() ends up using the element stored from earlier Beacon template. Do not copy old MBSSID elements, instead userspace should always include these when applicable. Fixes: 2b3171c6fe0a ("mac80211: MBSSID beacon handling in AP mode") Signed-off-by: Aloka Dixit Link: https://patch.msgid.link/20251215174656.2866319-2-aloka.dixit@oss.qualcomm.com Signed-off-by: Johannes Berg Signed-off-by: Sasha Levin --- net/mac80211/cfg.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index c52b0456039dd..e18df59951a82 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1328,7 +1328,6 @@ ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata, size = sizeof(*new) + new_head_len + new_tail_len; - /* new or old multiple BSSID elements? */ if (params->mbssid_ies) { mbssid = params->mbssid_ies; size += struct_size(new->mbssid_ies, elem, mbssid->cnt); @@ -1338,15 +1337,6 @@ ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata, } size += ieee80211_get_mbssid_beacon_len(mbssid, rnr, mbssid->cnt); - } else if (old && old->mbssid_ies) { - mbssid = old->mbssid_ies; - size += struct_size(new->mbssid_ies, elem, mbssid->cnt); - if (old && old->rnr_ies) { - rnr = old->rnr_ies; - size += struct_size(new->rnr_ies, elem, rnr->cnt); - } - size += ieee80211_get_mbssid_beacon_len(mbssid, rnr, - mbssid->cnt); } new = kzalloc(size, GFP_KERNEL); From f9cb8a49f7a5db234b171d78ee25b6c6c9aa6fdb Mon Sep 17 00:00:00 2001 From: Liang Jie Date: Tue, 16 Dec 2025 17:39:55 +0800 Subject: [PATCH 1462/2333] sched_ext: fix uninitialized ret on alloc_percpu() failure [ Upstream commit b0101ccb5b4641885f30fecc352ef891ed06e083 ] Smatch reported: kernel/sched/ext.c:5332 scx_alloc_and_add_sched() warn: passing zero to 'ERR_PTR' In scx_alloc_and_add_sched(), the alloc_percpu() failure path jumps to err_free_gdsqs without initializing @ret. That can lead to returning ERR_PTR(0), which violates the ERR_PTR() convention and confuses callers. Set @ret to -ENOMEM before jumping to the error path when alloc_percpu() fails. Reported-by: kernel test robot Closes: https://lore.kernel.org/r/202512141601.yAXDAeA9-lkp@intel.com/ Reported-by: Dan Carpenter Fixes: c201ea1578d3 ("sched_ext: Move event_stats_cpu into scx_sched") Signed-off-by: Liang Jie Reviewed-by: Emil Tsalapatis Reviewed-by: Andrea Righi Signed-off-by: Tejun Heo Signed-off-by: Sasha Levin --- kernel/sched/ext.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/kernel/sched/ext.c b/kernel/sched/ext.c index 6139263afd598..31eda2a56920d 100644 --- a/kernel/sched/ext.c +++ b/kernel/sched/ext.c @@ -4508,8 +4508,10 @@ static struct scx_sched *scx_alloc_and_add_sched(struct sched_ext_ops *ops) } sch->pcpu = alloc_percpu(struct scx_sched_pcpu); - if (!sch->pcpu) + if (!sch->pcpu) { + ret = -ENOMEM; goto err_free_gdsqs; + } sch->helper = kthread_run_worker(0, "sched_ext_helper"); if (IS_ERR(sch->helper)) { From db54feefa859bd5d9d3d2d67ba39c65392fadb77 Mon Sep 17 00:00:00 2001 From: Przemyslaw Korba Date: Thu, 20 Nov 2025 13:07:28 +0100 Subject: [PATCH 1463/2333] i40e: fix scheduling in set_rx_mode [ Upstream commit be43abc5514167cc129a8d8e9727b89b8e1d9719 ] Add service task schedule to set_rx_mode. In some cases there are error messages printed out in PTP application (ptp4l): ptp4l[13848.762]: port 1 (ens2f3np3): received SYNC without timestamp ptp4l[13848.825]: port 1 (ens2f3np3): received SYNC without timestamp ptp4l[13848.887]: port 1 (ens2f3np3): received SYNC without timestamp This happens when service task would not run immediately after set_rx_mode, and we need it for setup tasks. This service task checks, if PTP RX packets are hung in firmware, and propagate correct settings such as multicast address for IEEE 1588 Precision Time Protocol. RX timestamping depends on some of these filters set. Bug happens only with high PTP packets frequency incoming, and not every run since sometimes service task is being ran from a different place immediately after starting ptp4l. Fixes: 0e4425ed641f ("i40e: fix: do not sleep in netdev_ops") Reviewed-by: Grzegorz Nitka Reviewed-by: Jacob Keller Reviewed-by: Aleksandr Loktionov Signed-off-by: Przemyslaw Korba Tested-by: Rinitha S (A Contingent worker at Intel) Signed-off-by: Tony Nguyen Signed-off-by: Sasha Levin --- drivers/net/ethernet/intel/i40e/i40e_main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 50be0a60ae13b..07d32f2586c80 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -2234,6 +2234,7 @@ static void i40e_set_rx_mode(struct net_device *netdev) vsi->flags |= I40E_VSI_FLAG_FILTER_CHANGED; set_bit(__I40E_MACVLAN_SYNC_PENDING, vsi->back->state); } + i40e_service_event_schedule(vsi->back); } /** From 5e703706b6eaf6f6dfc7b3c02244d590d1904155 Mon Sep 17 00:00:00 2001 From: Gregory Herrero Date: Fri, 12 Dec 2025 22:06:43 +0100 Subject: [PATCH 1464/2333] i40e: validate ring_len parameter against hardware-specific values [ Upstream commit 69942834215323cd9131db557091b4dec43f19c5 ] The maximum number of descriptors supported by the hardware is hardware-dependent and can be retrieved using i40e_get_max_num_descriptors(). Move this function to a shared header and use it when checking for valid ring_len parameter rather than using hardcoded value. By fixing an over-acceptance issue, behavior change could be seen where ring_len could now be rejected while configuring rx and tx queues if its size is larger than the hardware-dependent maximum number of descriptors. Fixes: 55d225670def ("i40e: add validation for ring_len param") Signed-off-by: Gregory Herrero Tested-by: Rafal Romanowski Reviewed-by: Aleksandr Loktionov Signed-off-by: Tony Nguyen Signed-off-by: Sasha Levin --- drivers/net/ethernet/intel/i40e/i40e.h | 11 +++++++++++ drivers/net/ethernet/intel/i40e/i40e_ethtool.c | 12 ------------ drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c | 4 ++-- 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h index 801a57a925dad..feec9e1e13b36 100644 --- a/drivers/net/ethernet/intel/i40e/i40e.h +++ b/drivers/net/ethernet/intel/i40e/i40e.h @@ -1418,4 +1418,15 @@ static inline struct i40e_veb *i40e_pf_get_main_veb(struct i40e_pf *pf) return (pf->lan_veb != I40E_NO_VEB) ? pf->veb[pf->lan_veb] : NULL; } +static inline u32 i40e_get_max_num_descriptors(const struct i40e_pf *pf) +{ + const struct i40e_hw *hw = &pf->hw; + + switch (hw->mac.type) { + case I40E_MAC_XL710: + return I40E_MAX_NUM_DESCRIPTORS_XL710; + default: + return I40E_MAX_NUM_DESCRIPTORS; + } +} #endif /* _I40E_H_ */ diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index 86c72596617a3..61c39e881b008 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -2013,18 +2013,6 @@ static void i40e_get_drvinfo(struct net_device *netdev, drvinfo->n_priv_flags += I40E_GL_PRIV_FLAGS_STR_LEN; } -static u32 i40e_get_max_num_descriptors(struct i40e_pf *pf) -{ - struct i40e_hw *hw = &pf->hw; - - switch (hw->mac.type) { - case I40E_MAC_XL710: - return I40E_MAX_NUM_DESCRIPTORS_XL710; - default: - return I40E_MAX_NUM_DESCRIPTORS; - } -} - static void i40e_get_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring, struct kernel_ethtool_ringparam *kernel_ring, diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c index 081a4526a2f00..cf831c649c9c5 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c @@ -656,7 +656,7 @@ static int i40e_config_vsi_tx_queue(struct i40e_vf *vf, u16 vsi_id, /* ring_len has to be multiple of 8 */ if (!IS_ALIGNED(info->ring_len, 8) || - info->ring_len > I40E_MAX_NUM_DESCRIPTORS_XL710) { + info->ring_len > i40e_get_max_num_descriptors(pf)) { ret = -EINVAL; goto error_context; } @@ -726,7 +726,7 @@ static int i40e_config_vsi_rx_queue(struct i40e_vf *vf, u16 vsi_id, /* ring_len has to be multiple of 32 */ if (!IS_ALIGNED(info->ring_len, 32) || - info->ring_len > I40E_MAX_NUM_DESCRIPTORS_XL710) { + info->ring_len > i40e_get_max_num_descriptors(pf)) { ret = -EINVAL; goto error_param; } From 3095228e1320371e143835d0cebeef1a8a754c66 Mon Sep 17 00:00:00 2001 From: Kohei Enju Date: Sun, 26 Oct 2025 01:58:50 +0900 Subject: [PATCH 1465/2333] iavf: fix off-by-one issues in iavf_config_rss_reg() [ Upstream commit 6daa2893f323981c7894c68440823326e93a7d61 ] There are off-by-one bugs when configuring RSS hash key and lookup table, causing out-of-bounds reads to memory [1] and out-of-bounds writes to device registers. Before commit 43a3d9ba34c9 ("i40evf: Allow PF driver to configure RSS"), the loop upper bounds were: i <= I40E_VFQF_{HKEY,HLUT}_MAX_INDEX which is safe since the value is the last valid index. That commit changed the bounds to: i <= adapter->rss_{key,lut}_size / 4 where `rss_{key,lut}_size / 4` is the number of dwords, so the last valid index is `(rss_{key,lut}_size / 4) - 1`. Therefore, using `<=` accesses one element past the end. Fix the issues by using `<` instead of `<=`, ensuring we do not exceed the bounds. [1] KASAN splat about rss_key_size off-by-one BUG: KASAN: slab-out-of-bounds in iavf_config_rss+0x619/0x800 Read of size 4 at addr ffff888102c50134 by task kworker/u8:6/63 CPU: 0 UID: 0 PID: 63 Comm: kworker/u8:6 Not tainted 6.18.0-rc2-enjuk-tnguy-00378-g3005f5b77652-dirty #156 PREEMPT(voluntary) Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 Workqueue: iavf iavf_watchdog_task Call Trace: dump_stack_lvl+0x6f/0xb0 print_report+0x170/0x4f3 kasan_report+0xe1/0x1a0 iavf_config_rss+0x619/0x800 iavf_watchdog_task+0x2be7/0x3230 process_one_work+0x7fd/0x1420 worker_thread+0x4d1/0xd40 kthread+0x344/0x660 ret_from_fork+0x249/0x320 ret_from_fork_asm+0x1a/0x30 Allocated by task 63: kasan_save_stack+0x30/0x50 kasan_save_track+0x14/0x30 __kasan_kmalloc+0x7f/0x90 __kmalloc_noprof+0x246/0x6f0 iavf_watchdog_task+0x28fc/0x3230 process_one_work+0x7fd/0x1420 worker_thread+0x4d1/0xd40 kthread+0x344/0x660 ret_from_fork+0x249/0x320 ret_from_fork_asm+0x1a/0x30 The buggy address belongs to the object at ffff888102c50100 which belongs to the cache kmalloc-64 of size 64 The buggy address is located 0 bytes to the right of allocated 52-byte region [ffff888102c50100, ffff888102c50134) The buggy address belongs to the physical page: page: refcount:0 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x102c50 flags: 0x200000000000000(node=0|zone=2) page_type: f5(slab) raw: 0200000000000000 ffff8881000418c0 dead000000000122 0000000000000000 raw: 0000000000000000 0000000080200020 00000000f5000000 0000000000000000 page dumped because: kasan: bad access detected Memory state around the buggy address: ffff888102c50000: 00 00 00 00 00 00 00 fc fc fc fc fc fc fc fc fc ffff888102c50080: 00 00 00 00 00 00 00 fc fc fc fc fc fc fc fc fc >ffff888102c50100: 00 00 00 00 00 00 04 fc fc fc fc fc fc fc fc fc ^ ffff888102c50180: 00 00 00 00 00 00 00 00 fc fc fc fc fc fc fc fc ffff888102c50200: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc Fixes: 43a3d9ba34c9 ("i40evf: Allow PF driver to configure RSS") Signed-off-by: Kohei Enju Reviewed-by: Aleksandr Loktionov Reviewed-by: Przemek Kitszel Tested-by: Rafal Romanowski Signed-off-by: Tony Nguyen Signed-off-by: Sasha Levin --- drivers/net/ethernet/intel/iavf/iavf_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/iavf/iavf_main.c b/drivers/net/ethernet/intel/iavf/iavf_main.c index c2fbe443ef853..4b0fc8f354bc9 100644 --- a/drivers/net/ethernet/intel/iavf/iavf_main.c +++ b/drivers/net/ethernet/intel/iavf/iavf_main.c @@ -1726,11 +1726,11 @@ static int iavf_config_rss_reg(struct iavf_adapter *adapter) u16 i; dw = (u32 *)adapter->rss_key; - for (i = 0; i <= adapter->rss_key_size / 4; i++) + for (i = 0; i < adapter->rss_key_size / 4; i++) wr32(hw, IAVF_VFQF_HKEY(i), dw[i]); dw = (u32 *)adapter->rss_lut; - for (i = 0; i <= adapter->rss_lut_size / 4; i++) + for (i = 0; i < adapter->rss_lut_size / 4; i++) wr32(hw, IAVF_VFQF_HLUT(i), dw[i]); iavf_flush(hw); From 85230d7ab57edeb0413bdfe307894549106209bc Mon Sep 17 00:00:00 2001 From: Larysa Zaremba Date: Tue, 7 Oct 2025 13:46:22 +0200 Subject: [PATCH 1466/2333] idpf: fix LAN memory regions command on some NVMs [ Upstream commit 4af1f9a47291f7d446398065e0d6eb4943f7e184 ] IPU SDK versions 1.9 through 2.0.5 require send buffer to contain a single empty memory region. Set number of regions to 1 and use appropriate send buffer size to satisfy this requirement. Fixes: 6aa53e861c1a ("idpf: implement get LAN MMIO memory regions") Suggested-by: Michal Swiatkowski Reviewed-by: Aleksandr Loktionov Signed-off-by: Larysa Zaremba Tested-by: Krishneil Singh Signed-off-by: Tony Nguyen Signed-off-by: Sasha Levin --- drivers/net/ethernet/intel/idpf/idpf_virtchnl.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c index cbb5fa30f5a0e..fc03d55bc9b90 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c +++ b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c @@ -1016,6 +1016,9 @@ static int idpf_send_get_lan_memory_regions(struct idpf_adapter *adapter) struct idpf_vc_xn_params xn_params = { .vc_op = VIRTCHNL2_OP_GET_LAN_MEMORY_REGIONS, .recv_buf.iov_len = IDPF_CTLQ_MAX_BUF_LEN, + .send_buf.iov_len = + sizeof(struct virtchnl2_get_lan_memory_regions) + + sizeof(struct virtchnl2_mem_region), .timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC, }; int num_regions, size; @@ -1028,6 +1031,8 @@ static int idpf_send_get_lan_memory_regions(struct idpf_adapter *adapter) return -ENOMEM; xn_params.recv_buf.iov_base = rcvd_regions; + rcvd_regions->num_memory_regions = cpu_to_le16(1); + xn_params.send_buf.iov_base = rcvd_regions; reply_sz = idpf_vc_xn_exec(adapter, &xn_params); if (reply_sz < 0) return reply_sz; From 5a7ba7e66b54adea1896917d5f5d4781e69f2a59 Mon Sep 17 00:00:00 2001 From: Brian Vazquez Date: Mon, 10 Nov 2025 20:58:37 +0000 Subject: [PATCH 1467/2333] idpf: reduce mbx_task schedule delay to 300us [ Upstream commit b3d6bbae1d6d5638a4ab702ab195476787cde857 ] During the IDPF init phase, the mailbox runs in poll mode until it is configured to properly handle interrupts. The previous delay of 300ms is excessively long for the mailbox polling mechanism, which causes a slow initialization of ~2s: echo 0000:06:12.4 > /sys/bus/pci/drivers/idpf/bind [ 52.444239] idpf 0000:06:12.4: enabling device (0000 -> 0002) [ 52.485005] idpf 0000:06:12.4: Device HW Reset initiated [ 54.177181] idpf 0000:06:12.4: PTP init failed, err=-EOPNOTSUPP [ 54.206177] idpf 0000:06:12.4: Minimum RX descriptor support not provided, using the default [ 54.206182] idpf 0000:06:12.4: Minimum TX descriptor support not provided, using the default Changing the delay to 300us avoids the delays during the initial mailbox transactions, making the init phase much faster: [ 83.342590] idpf 0000:06:12.4: enabling device (0000 -> 0002) [ 83.384402] idpf 0000:06:12.4: Device HW Reset initiated [ 83.518323] idpf 0000:06:12.4: PTP init failed, err=-EOPNOTSUPP [ 83.547430] idpf 0000:06:12.4: Minimum RX descriptor support not provided, using the default [ 83.547435] idpf 0000:06:12.4: Minimum TX descriptor support not provided, using the default Fixes: 4930fbf419a7 ("idpf: add core init and interrupt request") Signed-off-by: Brian Vazquez Reviewed-by: Aleksandr Loktionov Tested-by: Samuel Salin Signed-off-by: Tony Nguyen Signed-off-by: Sasha Levin --- drivers/net/ethernet/intel/idpf/idpf_lib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/idpf/idpf_lib.c b/drivers/net/ethernet/intel/idpf/idpf_lib.c index 8a941f0fb048b..aaafe40f5eaf7 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_lib.c +++ b/drivers/net/ethernet/intel/idpf/idpf_lib.c @@ -1271,7 +1271,7 @@ void idpf_mbx_task(struct work_struct *work) idpf_mb_irq_enable(adapter); else queue_delayed_work(adapter->mbx_wq, &adapter->mbx_task, - msecs_to_jiffies(300)); + usecs_to_jiffies(300)); idpf_recv_mb_msg(adapter); } From 5d8b9d38a7676be7bb5e7d57f92156a98dab39fb Mon Sep 17 00:00:00 2001 From: Chen Ridong Date: Thu, 18 Dec 2025 01:59:50 +0000 Subject: [PATCH 1468/2333] cpuset: fix warning when disabling remote partition [ Upstream commit aa7d3a56a20f07978d9f401e13637a6479b13bd0 ] A warning was triggered as follows: WARNING: kernel/cgroup/cpuset.c:1651 at remote_partition_disable+0xf7/0x110 RIP: 0010:remote_partition_disable+0xf7/0x110 RSP: 0018:ffffc90001947d88 EFLAGS: 00000206 RAX: 0000000000007fff RBX: ffff888103b6e000 RCX: 0000000000006f40 RDX: 0000000000006f00 RSI: ffffc90001947da8 RDI: ffff888103b6e000 RBP: ffff888103b6e000 R08: 0000000000000000 R09: 0000000000000000 R10: 0000000000000001 R11: ffff88810b2e2728 R12: ffffc90001947da8 R13: 0000000000000000 R14: ffffc90001947da8 R15: ffff8881081f1c00 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007f55c8bbe0b2 CR3: 000000010b14c000 CR4: 00000000000006f0 Call Trace: update_prstate+0x2d3/0x580 cpuset_partition_write+0x94/0xf0 kernfs_fop_write_iter+0x147/0x200 vfs_write+0x35d/0x500 ksys_write+0x66/0xe0 do_syscall_64+0x6b/0x390 entry_SYSCALL_64_after_hwframe+0x4b/0x53 RIP: 0033:0x7f55c8cd4887 Reproduction steps (on a 16-CPU machine): # cd /sys/fs/cgroup/ # mkdir A1 # echo +cpuset > A1/cgroup.subtree_control # echo "0-14" > A1/cpuset.cpus.exclusive # mkdir A1/A2 # echo "0-14" > A1/A2/cpuset.cpus.exclusive # echo "root" > A1/A2/cpuset.cpus.partition # echo 0 > /sys/devices/system/cpu/cpu15/online # echo member > A1/A2/cpuset.cpus.partition When CPU 15 is offlined, subpartitions_cpus gets cleared because no CPUs remain available for the top_cpuset, forcing partitions to share CPUs with the top_cpuset. In this scenario, disabling the remote partition triggers a warning stating that effective_xcpus is not a subset of subpartitions_cpus. Partitions should be invalidated in this case to inform users that the partition is now invalid(cpus are shared with top_cpuset). To fix this issue: 1. Only emit the warning only if subpartitions_cpus is not empty and the effective_xcpus is not a subset of subpartitions_cpus. 2. During the CPU hotplug process, invalidate partitions if subpartitions_cpus is empty. Fixes: f62a5d39368e ("cgroup/cpuset: Remove remote_partition_check() & make update_cpumasks_hier() handle remote partition") Signed-off-by: Chen Ridong Reviewed-by: Waiman Long Signed-off-by: Tejun Heo Signed-off-by: Sasha Levin --- kernel/cgroup/cpuset.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c index 4dcd633fd6df5..61b56b6ca66a7 100644 --- a/kernel/cgroup/cpuset.c +++ b/kernel/cgroup/cpuset.c @@ -1600,7 +1600,14 @@ static void remote_partition_disable(struct cpuset *cs, struct tmpmasks *tmp) bool isolcpus_updated; WARN_ON_ONCE(!is_remote_partition(cs)); - WARN_ON_ONCE(!cpumask_subset(cs->effective_xcpus, subpartitions_cpus)); + /* + * When a CPU is offlined, top_cpuset may end up with no available CPUs, + * which should clear subpartitions_cpus. We should not emit a warning for this + * scenario: the hierarchy is updated from top to bottom, so subpartitions_cpus + * may already be cleared when disabling the partition. + */ + WARN_ON_ONCE(!cpumask_subset(cs->effective_xcpus, subpartitions_cpus) && + !cpumask_empty(subpartitions_cpus)); spin_lock_irq(&callback_lock); list_del_init(&cs->remote_sibling); @@ -3927,8 +3934,9 @@ static void cpuset_hotplug_update_tasks(struct cpuset *cs, struct tmpmasks *tmp) if (remote || (is_partition_valid(cs) && is_partition_valid(parent))) compute_partition_effective_cpumask(cs, &new_cpus); - if (remote && cpumask_empty(&new_cpus) && - partition_is_populated(cs, NULL)) { + if (remote && (cpumask_empty(subpartitions_cpus) || + (cpumask_empty(&new_cpus) && + partition_is_populated(cs, NULL)))) { cs->prs_err = PERR_HOTPLUG; remote_partition_disable(cs, tmp); compute_effective_cpumask(&new_cpus, cs, parent); @@ -3941,9 +3949,12 @@ static void cpuset_hotplug_update_tasks(struct cpuset *cs, struct tmpmasks *tmp) * 1) empty effective cpus but not valid empty partition. * 2) parent is invalid or doesn't grant any cpus to child * partitions. + * 3) subpartitions_cpus is empty. */ - if (is_local_partition(cs) && (!is_partition_valid(parent) || - tasks_nocpu_error(parent, cs, &new_cpus))) + if (is_local_partition(cs) && + (!is_partition_valid(parent) || + tasks_nocpu_error(parent, cs, &new_cpus) || + cpumask_empty(subpartitions_cpus))) partcmd = partcmd_invalidate; /* * On the other hand, an invalid partition root may be transitioned From 5476f7f8a311236604b78fcc5b2a63b3a61b0169 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Wed, 17 Dec 2025 14:15:41 +0800 Subject: [PATCH 1469/2333] crypto: seqiv - Do not use req->iv after crypto_aead_encrypt [ Upstream commit 50fdb78b7c0bcc550910ef69c0984e751cac72fa ] As soon as crypto_aead_encrypt is called, the underlying request may be freed by an asynchronous completion. Thus dereferencing req->iv after it returns is invalid. Instead of checking req->iv against info, create a new variable unaligned_info and use it for that purpose instead. Fixes: 0a270321dbf9 ("[CRYPTO] seqiv: Add Sequence Number IV Generator") Reported-by: Xiumei Mu Reported-by: Xin Long Signed-off-by: Herbert Xu Signed-off-by: Sasha Levin --- crypto/seqiv.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/crypto/seqiv.c b/crypto/seqiv.c index 2bae99e335268..678bb4145d783 100644 --- a/crypto/seqiv.c +++ b/crypto/seqiv.c @@ -50,6 +50,7 @@ static int seqiv_aead_encrypt(struct aead_request *req) struct aead_geniv_ctx *ctx = crypto_aead_ctx(geniv); struct aead_request *subreq = aead_request_ctx(req); crypto_completion_t compl; + bool unaligned_info; void *data; u8 *info; unsigned int ivsize = 8; @@ -68,8 +69,9 @@ static int seqiv_aead_encrypt(struct aead_request *req) memcpy_sglist(req->dst, req->src, req->assoclen + req->cryptlen); - if (unlikely(!IS_ALIGNED((unsigned long)info, - crypto_aead_alignmask(geniv) + 1))) { + unaligned_info = !IS_ALIGNED((unsigned long)info, + crypto_aead_alignmask(geniv) + 1); + if (unlikely(unaligned_info)) { info = kmemdup(req->iv, ivsize, req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP ? GFP_KERNEL : GFP_ATOMIC); @@ -89,7 +91,7 @@ static int seqiv_aead_encrypt(struct aead_request *req) scatterwalk_map_and_copy(info, req->dst, req->assoclen, ivsize, 1); err = crypto_aead_encrypt(subreq); - if (unlikely(info != req->iv)) + if (unlikely(unaligned_info)) seqiv_aead_encrypt_complete2(req, err); return err; } From d084061f3360fe8d2b855276ee6e436b177bea65 Mon Sep 17 00:00:00 2001 From: Pauli Virtanen Date: Thu, 4 Dec 2025 22:40:20 +0200 Subject: [PATCH 1470/2333] Bluetooth: MGMT: report BIS capability flags in supported settings [ Upstream commit 348240e5fa901d3d4ba8dffa0e2ba9fc7aba93ab ] MGMT_SETTING_ISO_BROADCASTER and MGMT_SETTING_ISO_RECEIVER flags are missing from supported_settings although they are in current_settings. Report them also in supported_settings to be consistent. Fixes: ae7533613133 ("Bluetooth: Check for ISO support in controller") Signed-off-by: Pauli Virtanen Signed-off-by: Luiz Augusto von Dentz Signed-off-by: Sasha Levin --- net/bluetooth/mgmt.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 262bf984d2aaf..211951eb832af 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -849,6 +849,12 @@ static u32 get_supported_settings(struct hci_dev *hdev) if (cis_peripheral_capable(hdev)) settings |= MGMT_SETTING_CIS_PERIPHERAL; + if (bis_capable(hdev)) + settings |= MGMT_SETTING_ISO_BROADCASTER; + + if (sync_recv_capable(hdev)) + settings |= MGMT_SETTING_ISO_SYNC_RECEIVER; + if (ll_privacy_capable(hdev)) settings |= MGMT_SETTING_LL_PRIVACY; From fdf7c640fb8a44a59b0671143d8c2f738bc48003 Mon Sep 17 00:00:00 2001 From: Raphael Pinsonneault-Thibeault Date: Wed, 10 Dec 2025 11:02:28 -0500 Subject: [PATCH 1471/2333] Bluetooth: btusb: revert use of devm_kzalloc in btusb [ Upstream commit 252714f1e8bdd542025b16321c790458014d6880 ] This reverts commit 98921dbd00c4e ("Bluetooth: Use devm_kzalloc in btusb.c file"). In btusb_probe(), we use devm_kzalloc() to allocate the btusb data. This ties the lifetime of all the btusb data to the binding of a driver to one interface, INTF. In a driver that binds to other interfaces, ISOC and DIAG, this is an accident waiting to happen. The issue is revealed in btusb_disconnect(), where calling usb_driver_release_interface(&btusb_driver, data->intf) will have devm free the data that is also being used by the other interfaces of the driver that may not be released yet. To fix this, revert the use of devm and go back to freeing memory explicitly. Fixes: 98921dbd00c4e ("Bluetooth: Use devm_kzalloc in btusb.c file") Signed-off-by: Raphael Pinsonneault-Thibeault Signed-off-by: Luiz Augusto von Dentz Signed-off-by: Sasha Levin --- drivers/bluetooth/btusb.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index b92bfd131567e..3420f711f0f08 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -4017,7 +4017,7 @@ static int btusb_probe(struct usb_interface *intf, return -ENODEV; } - data = devm_kzalloc(&intf->dev, sizeof(*data), GFP_KERNEL); + data = kzalloc(sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; @@ -4040,8 +4040,10 @@ static int btusb_probe(struct usb_interface *intf, } } - if (!data->intr_ep || !data->bulk_tx_ep || !data->bulk_rx_ep) + if (!data->intr_ep || !data->bulk_tx_ep || !data->bulk_rx_ep) { + kfree(data); return -ENODEV; + } if (id->driver_info & BTUSB_AMP) { data->cmdreq_type = USB_TYPE_CLASS | 0x01; @@ -4096,8 +4098,10 @@ static int btusb_probe(struct usb_interface *intf, data->recv_acl = hci_recv_frame; hdev = hci_alloc_dev_priv(priv_size); - if (!hdev) + if (!hdev) { + kfree(data); return -ENOMEM; + } hdev->bus = HCI_USB; hci_set_drvdata(hdev, data); @@ -4370,6 +4374,7 @@ static int btusb_probe(struct usb_interface *intf, if (data->reset_gpio) gpiod_put(data->reset_gpio); hci_free_dev(hdev); + kfree(data); return err; } @@ -4418,6 +4423,7 @@ static void btusb_disconnect(struct usb_interface *intf) } hci_free_dev(hdev); + kfree(data); } #ifdef CONFIG_PM From 05359659c110482b5a667c79d77eeff484e11388 Mon Sep 17 00:00:00 2001 From: Jacky Chou Date: Thu, 11 Dec 2025 14:24:58 +0800 Subject: [PATCH 1472/2333] net: mdio: aspeed: add dummy read to avoid read-after-write issue [ Upstream commit d1a1a4bade4b20c0858d0b2f81d2611de055f675 ] The Aspeed MDIO controller may return incorrect data when a read operation follows immediately after a write. Due to a controller bug, the subsequent read can latch stale data, causing the polling logic to terminate earlier than expected. To work around this hardware issue, insert a dummy read after each write operation. This ensures that the next actual read returns the correct data and prevents premature polling exit. This workaround has been verified to stabilize MDIO transactions on affected Aspeed platforms. Fixes: f160e99462c6 ("net: phy: Add mdio-aspeed") Signed-off-by: Jacky Chou Reviewed-by: Andrew Lunn Link: https://patch.msgid.link/20251211-aspeed_mdio_add_dummy_read-v3-1-382868869004@aspeedtech.com Signed-off-by: Paolo Abeni Signed-off-by: Sasha Levin --- drivers/net/mdio/mdio-aspeed.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/net/mdio/mdio-aspeed.c b/drivers/net/mdio/mdio-aspeed.c index e55be6dc9ae70..d6b9004c61dc1 100644 --- a/drivers/net/mdio/mdio-aspeed.c +++ b/drivers/net/mdio/mdio-aspeed.c @@ -63,6 +63,13 @@ static int aspeed_mdio_op(struct mii_bus *bus, u8 st, u8 op, u8 phyad, u8 regad, iowrite32(ctrl, ctx->base + ASPEED_MDIO_CTRL); + /* Workaround for read-after-write issue. + * The controller may return stale data if a read follows immediately + * after a write. A dummy read forces the hardware to update its + * internal state, ensuring that the next real read returns correct data. + */ + ioread32(ctx->base + ASPEED_MDIO_CTRL); + return readl_poll_timeout(ctx->base + ASPEED_MDIO_CTRL, ctrl, !(ctrl & ASPEED_MDIO_CTRL_FIRE), ASPEED_MDIO_INTERVAL_US, From f31557fb1b35332cca9994aa196cef284bcf3807 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Toke=20H=C3=B8iland-J=C3=B8rgensen?= Date: Thu, 11 Dec 2025 12:50:05 +0100 Subject: [PATCH 1473/2333] net: openvswitch: Avoid needlessly taking the RTNL on vport destroy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 5498227676303e3ffa9a3a46214af96bc3e81314 ] The openvswitch teardown code will immediately call ovs_netdev_detach_dev() in response to a NETDEV_UNREGISTER notification. It will then start the dp_notify_work workqueue, which will later end up calling the vport destroy() callback. This callback takes the RTNL to do another ovs_netdev_detach_port(), which in this case is unnecessary. This causes extra pressure on the RTNL, in some cases leading to "unregister_netdevice: waiting for XX to become free" warnings on teardown. We can straight-forwardly avoid the extra RTNL lock acquisition by checking the device flags before taking the lock, and skip the locking altogether if the IFF_OVS_DATAPATH flag has already been unset. Fixes: b07c26511e94 ("openvswitch: fix vport-netdev unregister") Tested-by: Adrian Moreno Signed-off-by: Toke Høiland-Jørgensen Acked-by: Eelco Chaudron Acked-by: Aaron Conole Link: https://patch.msgid.link/20251211115006.228876-1-toke@redhat.com Signed-off-by: Paolo Abeni Signed-off-by: Sasha Levin --- net/openvswitch/vport-netdev.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/net/openvswitch/vport-netdev.c b/net/openvswitch/vport-netdev.c index 91a11067e4588..6574f9bcdc026 100644 --- a/net/openvswitch/vport-netdev.c +++ b/net/openvswitch/vport-netdev.c @@ -160,10 +160,19 @@ void ovs_netdev_detach_dev(struct vport *vport) static void netdev_destroy(struct vport *vport) { - rtnl_lock(); - if (netif_is_ovs_port(vport->dev)) - ovs_netdev_detach_dev(vport); - rtnl_unlock(); + /* When called from ovs_db_notify_wq() after a dp_device_event(), the + * port has already been detached, so we can avoid taking the RTNL by + * checking this first. + */ + if (netif_is_ovs_port(vport->dev)) { + rtnl_lock(); + /* Check again while holding the lock to ensure we don't race + * with the netdev notifier and detach twice. + */ + if (netif_is_ovs_port(vport->dev)) + ovs_netdev_detach_dev(vport); + rtnl_unlock(); + } call_rcu(&vport->rcu, vport_netdev_free); } From 91a2b25be07ce1a7549ceebbe82017551d2eec92 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 11 Dec 2025 17:35:50 +0000 Subject: [PATCH 1474/2333] ip6_gre: make ip6gre_header() robust [ Upstream commit db5b4e39c4e63700c68a7e65fc4e1f1375273476 ] Over the years, syzbot found many ways to crash the kernel in ip6gre_header() [1]. This involves team or bonding drivers ability to dynamically change their dev->needed_headroom and/or dev->hard_header_len In this particular crash mld_newpack() allocated an skb with a too small reserve/headroom, and by the time mld_sendpack() was called, syzbot managed to attach an ip6gre device. [1] skbuff: skb_under_panic: text:ffffffff8a1d69a8 len:136 put:40 head:ffff888059bc7000 data:ffff888059bc6fe8 tail:0x70 end:0x6c0 dev:team0 ------------[ cut here ]------------ kernel BUG at net/core/skbuff.c:213 ! skb_under_panic net/core/skbuff.c:223 [inline] skb_push+0xc3/0xe0 net/core/skbuff.c:2641 ip6gre_header+0xc8/0x790 net/ipv6/ip6_gre.c:1371 dev_hard_header include/linux/netdevice.h:3436 [inline] neigh_connected_output+0x286/0x460 net/core/neighbour.c:1618 neigh_output include/net/neighbour.h:556 [inline] ip6_finish_output2+0xfb3/0x1480 net/ipv6/ip6_output.c:136 __ip6_finish_output net/ipv6/ip6_output.c:-1 [inline] ip6_finish_output+0x234/0x7d0 net/ipv6/ip6_output.c:220 NF_HOOK_COND include/linux/netfilter.h:307 [inline] ip6_output+0x340/0x550 net/ipv6/ip6_output.c:247 NF_HOOK+0x9e/0x380 include/linux/netfilter.h:318 mld_sendpack+0x8d4/0xe60 net/ipv6/mcast.c:1855 mld_send_cr net/ipv6/mcast.c:2154 [inline] mld_ifc_work+0x83e/0xd60 net/ipv6/mcast.c:2693 Fixes: c12b395a4664 ("gre: Support GRE over IPv6") Reported-by: syzbot+43a2ebcf2a64b1102d64@syzkaller.appspotmail.com Closes: https://lore.kernel.org/netdev/693b002c.a70a0220.33cd7b.0033.GAE@google.com/T/#u Signed-off-by: Eric Dumazet Link: https://patch.msgid.link/20251211173550.2032674-1-edumazet@google.com Signed-off-by: Paolo Abeni Signed-off-by: Sasha Levin --- net/ipv6/ip6_gre.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c index c82a75510c0e2..8bc3f05f594ed 100644 --- a/net/ipv6/ip6_gre.c +++ b/net/ipv6/ip6_gre.c @@ -1366,9 +1366,16 @@ static int ip6gre_header(struct sk_buff *skb, struct net_device *dev, { struct ip6_tnl *t = netdev_priv(dev); struct ipv6hdr *ipv6h; + int needed; __be16 *p; - ipv6h = skb_push(skb, t->hlen + sizeof(*ipv6h)); + needed = t->hlen + sizeof(*ipv6h); + if (skb_headroom(skb) < needed && + pskb_expand_head(skb, HH_DATA_ALIGN(needed - skb_headroom(skb)), + 0, GFP_ATOMIC)) + return -needed; + + ipv6h = skb_push(skb, needed); ip6_flow_hdr(ipv6h, 0, ip6_make_flowlabel(dev_net(dev), skb, t->fl.u.ip6.flowlabel, true, &t->fl.u.ip6)); From 26cca984de64f7a89787eed936503964c8d17587 Mon Sep 17 00:00:00 2001 From: Jan Stancek Date: Tue, 23 Sep 2025 17:32:16 +0200 Subject: [PATCH 1475/2333] powerpc/tools: drop `-o pipefail` in gcc check scripts [ Upstream commit f1164534ad62f0cc247d99650b07bd59ad2a49fd ] Fixes: 0f71dcfb4aef ("powerpc/ftrace: Add support for -fpatchable-function-entry") Fixes: b71c9ffb1405 ("powerpc: Add arch/powerpc/tools directory") Reported-by: Joe Lawrence Acked-by: Joe Lawrence Signed-off-by: Jan Stancek Fixes: 8c50b72a3b4f ("powerpc/ftrace: Add Kconfig & Make glue for mprofile-kernel") Fixes: abba759796f9 ("powerpc/kbuild: move -mprofile-kernel check to Kconfig") Tested-by: Justin M. Forbes Reviewed-by: Naveen N Rao (AMD) Reviewed-by: Josh Poimboeuf Signed-off-by: Madhavan Srinivasan Link: https://patch.msgid.link/cc6cdd116c3ad9d990df21f13c6d8e8a83815bbd.1758641374.git.jstancek@redhat.com Signed-off-by: Sasha Levin --- arch/powerpc/tools/gcc-check-fpatchable-function-entry.sh | 1 - arch/powerpc/tools/gcc-check-mprofile-kernel.sh | 1 - 2 files changed, 2 deletions(-) diff --git a/arch/powerpc/tools/gcc-check-fpatchable-function-entry.sh b/arch/powerpc/tools/gcc-check-fpatchable-function-entry.sh index 06706903503b6..baed467a016b3 100755 --- a/arch/powerpc/tools/gcc-check-fpatchable-function-entry.sh +++ b/arch/powerpc/tools/gcc-check-fpatchable-function-entry.sh @@ -2,7 +2,6 @@ # SPDX-License-Identifier: GPL-2.0 set -e -set -o pipefail # To debug, uncomment the following line # set -x diff --git a/arch/powerpc/tools/gcc-check-mprofile-kernel.sh b/arch/powerpc/tools/gcc-check-mprofile-kernel.sh index 73e331e7660ef..6193b0ed0c775 100755 --- a/arch/powerpc/tools/gcc-check-mprofile-kernel.sh +++ b/arch/powerpc/tools/gcc-check-mprofile-kernel.sh @@ -2,7 +2,6 @@ # SPDX-License-Identifier: GPL-2.0 set -e -set -o pipefail # To debug, uncomment the following line # set -x From f1c7923932bbcbc4faa0daa961075edd4f3d327a Mon Sep 17 00:00:00 2001 From: Shravan Kumar Ramani Date: Thu, 18 Dec 2025 12:18:13 +0000 Subject: [PATCH 1476/2333] platform/mellanox: mlxbf-pmc: Remove trailing whitespaces from event names MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit f13bce715d1600698310a4a7832f6a52499d5395 ] Some event names have trailing whitespaces at the end which causes programming of counters using the name for these specific events to fail and hence need to be removed. Fixes: 423c3361855c ("platform/mellanox: mlxbf-pmc: Add support for BlueField-3") Signed-off-by: Shravan Kumar Ramani Reviewed-by: David Thompson Link: https://patch.msgid.link/065cbae0717dcc1169681c4dbb1a6e050b8574b3.1766059953.git.shravankr@nvidia.com Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen Signed-off-by: Sasha Levin --- drivers/platform/mellanox/mlxbf-pmc.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/platform/mellanox/mlxbf-pmc.c b/drivers/platform/mellanox/mlxbf-pmc.c index 16a2fd9fdd9b8..5ec1ad4716967 100644 --- a/drivers/platform/mellanox/mlxbf-pmc.c +++ b/drivers/platform/mellanox/mlxbf-pmc.c @@ -801,18 +801,18 @@ static const struct mlxbf_pmc_events mlxbf_pmc_llt_miss_events[] = { {11, "GDC_MISS_MACHINE_CHI_TXDAT"}, {12, "GDC_MISS_MACHINE_CHI_RXDAT"}, {13, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC0_0"}, - {14, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC0_1 "}, + {14, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC0_1"}, {15, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC0_2"}, - {16, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC0_3 "}, - {17, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC1_0 "}, - {18, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC1_1 "}, - {19, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC1_2 "}, - {20, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC1_3 "}, + {16, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC0_3"}, + {17, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC1_0"}, + {18, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC1_1"}, + {19, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC1_2"}, + {20, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC1_3"}, {21, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC_DONE0_0"}, {22, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC_DONE0_1"}, {23, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC_DONE0_2"}, {24, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC_DONE0_3"}, - {25, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC_DONE1_0 "}, + {25, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC_DONE1_0"}, {26, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC_DONE1_1"}, {27, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC_DONE1_2"}, {28, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC_DONE1_3"}, From 8f2ba8ac9ca5027f06c0e6d8074640d2e639c0d6 Mon Sep 17 00:00:00 2001 From: Thomas Fourier Date: Wed, 17 Dec 2025 11:36:13 +0100 Subject: [PATCH 1477/2333] platform/x86: msi-laptop: add missing sysfs_remove_group() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 1461209cf813b6ee6d40f29b96b544587df6d2b1 ] A sysfs group is created in msi_init() when old_ec_model is enabled, but never removed. Remove the msipf_old_attribute_group in that case. Fixes: 03696e51d75a ("msi-laptop: Disable brightness control for new EC") Signed-off-by: Thomas Fourier Link: https://patch.msgid.link/20251217103617.27668-2-fourier.thomas@gmail.com Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen Signed-off-by: Sasha Levin --- drivers/platform/x86/msi-laptop.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/platform/x86/msi-laptop.c b/drivers/platform/x86/msi-laptop.c index c4b150fa093fe..ddef6b78d2fa9 100644 --- a/drivers/platform/x86/msi-laptop.c +++ b/drivers/platform/x86/msi-laptop.c @@ -1130,6 +1130,9 @@ static void __exit msi_cleanup(void) sysfs_remove_group(&msipf_device->dev.kobj, &msipf_attribute_group); if (!quirks->old_ec_model && threeg_exists) device_remove_file(&msipf_device->dev, &dev_attr_threeg); + if (quirks->old_ec_model) + sysfs_remove_group(&msipf_device->dev.kobj, + &msipf_old_attribute_group); platform_device_unregister(msipf_device); platform_driver_unregister(&msipf_driver); backlight_device_unregister(msibl_device); From 4defca287bae36a08159952b378ae30255d6d3f1 Mon Sep 17 00:00:00 2001 From: Junrui Luo Date: Fri, 19 Dec 2025 16:30:29 +0800 Subject: [PATCH 1478/2333] platform/x86: ibm_rtl: fix EBDA signature search pointer arithmetic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 15dd100349b8526cbdf2de0ce3e72e700eb6c208 ] The ibm_rtl_init() function searches for the signature but has a pointer arithmetic error. The loop counter suggests searching at 4-byte intervals but the implementation only advances by 1 byte per iteration. Fix by properly advancing the pointer by sizeof(unsigned int) bytes each iteration. Reported-by: Yuhao Jiang Reported-by: Junrui Luo Fixes: 35f0ce032b0f ("IBM Real-Time "SMI Free" mode driver -v7") Signed-off-by: Junrui Luo Link: https://patch.msgid.link/SYBPR01MB78812D887A92DE3802D0D06EAFA9A@SYBPR01MB7881.ausprd01.prod.outlook.com Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen Signed-off-by: Sasha Levin --- drivers/platform/x86/ibm_rtl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/x86/ibm_rtl.c b/drivers/platform/x86/ibm_rtl.c index 231b379098017..139956168cf94 100644 --- a/drivers/platform/x86/ibm_rtl.c +++ b/drivers/platform/x86/ibm_rtl.c @@ -273,7 +273,7 @@ static int __init ibm_rtl_init(void) { /* search for the _RTL_ signature at the start of the table */ for (i = 0 ; i < ebda_size/sizeof(unsigned int); i++) { struct ibm_rtl_table __iomem * tmp; - tmp = (struct ibm_rtl_table __iomem *) (ebda_map+i); + tmp = (struct ibm_rtl_table __iomem *) (ebda_map + i*sizeof(unsigned int)); if ((readq(&tmp->signature) & RTL_MASK) == RTL_SIGNATURE) { phys_addr_t addr; unsigned int plen; From b71187648ef2349254673d0523fdf96d1fe3d758 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Fri, 12 Dec 2025 11:29:53 +0100 Subject: [PATCH 1479/2333] team: fix check for port enabled in team_queue_override_port_prio_changed() [ Upstream commit 932ac51d9953eaf77a1252f79b656d4ca86163c6 ] There has been a syzkaller bug reported recently with the following trace: list_del corruption, ffff888058bea080->prev is LIST_POISON2 (dead000000000122) ------------[ cut here ]------------ kernel BUG at lib/list_debug.c:59! Oops: invalid opcode: 0000 [#1] SMP KASAN NOPTI CPU: 3 UID: 0 PID: 21246 Comm: syz.0.2928 Not tainted syzkaller #0 PREEMPT(full) Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2~bpo12+1 04/01/2014 RIP: 0010:__list_del_entry_valid_or_report+0x13e/0x200 lib/list_debug.c:59 Code: 48 c7 c7 e0 71 f0 8b e8 30 08 ef fc 90 0f 0b 48 89 ef e8 a5 02 55 fd 48 89 ea 48 89 de 48 c7 c7 40 72 f0 8b e8 13 08 ef fc 90 <0f> 0b 48 89 ef e8 88 02 55 fd 48 89 ea 48 b8 00 00 00 00 00 fc ff RSP: 0018:ffffc9000d49f370 EFLAGS: 00010286 RAX: 000000000000004e RBX: ffff888058bea080 RCX: ffffc9002817d000 RDX: 0000000000000000 RSI: ffffffff819becc6 RDI: 0000000000000005 RBP: dead000000000122 R08: 0000000000000005 R09: 0000000000000000 R10: 0000000080000000 R11: 0000000000000001 R12: ffff888039e9c230 R13: ffff888058bea088 R14: ffff888058bea080 R15: ffff888055461480 FS: 00007fbbcfe6f6c0(0000) GS:ffff8880d6d0a000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 000000110c3afcb0 CR3: 00000000382c7000 CR4: 0000000000352ef0 Call Trace: __list_del_entry_valid include/linux/list.h:132 [inline] __list_del_entry include/linux/list.h:223 [inline] list_del_rcu include/linux/rculist.h:178 [inline] __team_queue_override_port_del drivers/net/team/team_core.c:826 [inline] __team_queue_override_port_del drivers/net/team/team_core.c:821 [inline] team_queue_override_port_prio_changed drivers/net/team/team_core.c:883 [inline] team_priority_option_set+0x171/0x2f0 drivers/net/team/team_core.c:1534 team_option_set drivers/net/team/team_core.c:376 [inline] team_nl_options_set_doit+0x8ae/0xe60 drivers/net/team/team_core.c:2653 genl_family_rcv_msg_doit+0x209/0x2f0 net/netlink/genetlink.c:1115 genl_family_rcv_msg net/netlink/genetlink.c:1195 [inline] genl_rcv_msg+0x55c/0x800 net/netlink/genetlink.c:1210 netlink_rcv_skb+0x158/0x420 net/netlink/af_netlink.c:2552 genl_rcv+0x28/0x40 net/netlink/genetlink.c:1219 netlink_unicast_kernel net/netlink/af_netlink.c:1320 [inline] netlink_unicast+0x5aa/0x870 net/netlink/af_netlink.c:1346 netlink_sendmsg+0x8c8/0xdd0 net/netlink/af_netlink.c:1896 sock_sendmsg_nosec net/socket.c:727 [inline] __sock_sendmsg net/socket.c:742 [inline] ____sys_sendmsg+0xa98/0xc70 net/socket.c:2630 ___sys_sendmsg+0x134/0x1d0 net/socket.c:2684 __sys_sendmsg+0x16d/0x220 net/socket.c:2716 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] do_syscall_64+0xcd/0xfa0 arch/x86/entry/syscall_64.c:94 entry_SYSCALL_64_after_hwframe+0x77/0x7f The problem is in this flow: 1) Port is enabled, queue_id != 0, in qom_list 2) Port gets disabled -> team_port_disable() -> team_queue_override_port_del() -> del (removed from list) 3) Port is disabled, queue_id != 0, not in any list 4) Priority changes -> team_queue_override_port_prio_changed() -> checks: port disabled && queue_id != 0 -> calls del - hits the BUG as it is removed already To fix this, change the check in team_queue_override_port_prio_changed() so it returns early if port is not enabled. Reported-by: syzbot+422806e5f4cce722a71f@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=422806e5f4cce722a71f Fixes: 6c31ff366c11 ("team: remove synchronize_rcu() called during queue override change") Signed-off-by: Jiri Pirko Reviewed-by: Simon Horman Link: https://patch.msgid.link/20251212102953.167287-1-jiri@resnulli.us Signed-off-by: Paolo Abeni Signed-off-by: Sasha Levin --- drivers/net/team/team_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/team/team_core.c b/drivers/net/team/team_core.c index 25562b17debe1..2fd3469d10464 100644 --- a/drivers/net/team/team_core.c +++ b/drivers/net/team/team_core.c @@ -878,7 +878,7 @@ static void __team_queue_override_enabled_check(struct team *team) static void team_queue_override_port_prio_changed(struct team *team, struct team_port *port) { - if (!port->queue_id || team_port_enabled(port)) + if (!port->queue_id || !team_port_enabled(port)) return; __team_queue_override_port_del(team, port); __team_queue_override_port_add(team, port); From 0b4fa7ac13061158030744f6991b0aa696e0f173 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sun, 14 Dec 2025 10:30:07 +0100 Subject: [PATCH 1480/2333] net: airoha: Move net_devs registration in a dedicated routine [ Upstream commit 5e7365b5a1ac8f517a7a84442289d7de242deb76 ] Since airoha_probe() is not executed under rtnl lock, there is small race where a given device is configured by user-space while the remaining ones are not completely loaded from the dts yet. This condition will allow a hw device misconfiguration since there are some conditions (e.g. GDM2 check in airoha_dev_init()) that require all device are properly loaded from the device tree. Fix the issue moving net_devices registration at the end of the airoha_probe routine. Fixes: 9cd451d414f6e ("net: airoha: Add loopback support for GDM2") Signed-off-by: Lorenzo Bianconi Reviewed-by: Simon Horman Link: https://patch.msgid.link/20251214-airoha-fix-dev-registration-v1-1-860e027ad4c6@kernel.org Signed-off-by: Paolo Abeni Signed-off-by: Sasha Levin --- drivers/net/ethernet/airoha/airoha_eth.c | 39 ++++++++++++++++-------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c index 433a646e98317..0394ba6a90a9b 100644 --- a/drivers/net/ethernet/airoha/airoha_eth.c +++ b/drivers/net/ethernet/airoha/airoha_eth.c @@ -2900,19 +2900,26 @@ static int airoha_alloc_gdm_port(struct airoha_eth *eth, port->id = id; eth->ports[p] = port; - err = airoha_metadata_dst_alloc(port); - if (err) - return err; + return airoha_metadata_dst_alloc(port); +} - err = register_netdev(dev); - if (err) - goto free_metadata_dst; +static int airoha_register_gdm_devices(struct airoha_eth *eth) +{ + int i; - return 0; + for (i = 0; i < ARRAY_SIZE(eth->ports); i++) { + struct airoha_gdm_port *port = eth->ports[i]; + int err; -free_metadata_dst: - airoha_metadata_dst_free(port); - return err; + if (!port) + continue; + + err = register_netdev(port->dev); + if (err) + return err; + } + + return 0; } static int airoha_probe(struct platform_device *pdev) @@ -2993,6 +3000,10 @@ static int airoha_probe(struct platform_device *pdev) } } + err = airoha_register_gdm_devices(eth); + if (err) + goto error_napi_stop; + return 0; error_napi_stop: @@ -3006,10 +3017,12 @@ static int airoha_probe(struct platform_device *pdev) for (i = 0; i < ARRAY_SIZE(eth->ports); i++) { struct airoha_gdm_port *port = eth->ports[i]; - if (port && port->dev->reg_state == NETREG_REGISTERED) { + if (!port) + continue; + + if (port->dev->reg_state == NETREG_REGISTERED) unregister_netdev(port->dev); - airoha_metadata_dst_free(port); - } + airoha_metadata_dst_free(port); } free_netdev(eth->napi_dev); platform_set_drvdata(pdev, NULL); From 0e766b77ba5093583dfe609fae0aa1545c46dbbd Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Mon, 15 Dec 2025 17:02:35 +0200 Subject: [PATCH 1481/2333] net: dsa: properly keep track of conduit reference [ Upstream commit 06e219f6a706c367c93051f408ac61417643d2f9 ] Problem description ------------------- DSA has a mumbo-jumbo of reference handling of the conduit net device and its kobject which, sadly, is just wrong and doesn't make sense. There are two distinct problems. 1. The OF path, which uses of_find_net_device_by_node(), never releases the elevated refcount on the conduit's kobject. Nominally, the OF and non-OF paths should result in objects having identical reference counts taken, and it is already suspicious that dsa_dev_to_net_device() has a put_device() call which is missing in dsa_port_parse_of(), but we can actually even verify that an issue exists. With CONFIG_DEBUG_KOBJECT_RELEASE=y, if we run this command "before" and "after" applying this patch: (unbind the conduit driver for net device eno2) echo 0000:00:00.2 > /sys/bus/pci/drivers/fsl_enetc/unbind we see these lines in the output diff which appear only with the patch applied: kobject: 'eno2' (ffff002009a3a6b8): kobject_release, parent 0000000000000000 (delayed 1000) kobject: '109' (ffff0020099d59a0): kobject_release, parent 0000000000000000 (delayed 1000) 2. After we find the conduit interface one way (OF) or another (non-OF), it can get unregistered at any time, and DSA remains with a long-lived, but in this case stale, cpu_dp->conduit pointer. Holding the net device's underlying kobject isn't actually of much help, it just prevents it from being freed (but we never need that kobject directly). What helps us to prevent the net device from being unregistered is the parallel netdev reference mechanism (dev_hold() and dev_put()). Actually we actually use that netdev tracker mechanism implicitly on user ports since commit 2f1e8ea726e9 ("net: dsa: link interfaces with the DSA master to get rid of lockdep warnings"), via netdev_upper_dev_link(). But time still passes at DSA switch probe time between the initial of_find_net_device_by_node() code and the user port creation time, time during which the conduit could unregister itself and DSA wouldn't know about it. So we have to run of_find_net_device_by_node() under rtnl_lock() to prevent that from happening, and release the lock only with the netdev tracker having acquired the reference. Do we need to keep the reference until dsa_unregister_switch() / dsa_switch_shutdown()? 1: Maybe yes. A switch device will still be registered even if all user ports failed to probe, see commit 86f8b1c01a0a ("net: dsa: Do not make user port errors fatal"), and the cpu_dp->conduit pointers remain valid. I haven't audited all call paths to see whether they will actually use the conduit in lack of any user port, but if they do, it seems safer to not rely on user ports for that reference. 2. Definitely yes. We support changing the conduit which a user port is associated to, and we can get into a situation where we've moved all user ports away from a conduit, thus no longer hold any reference to it via the net device tracker. But we shouldn't let it go nonetheless - see the next change in relation to dsa_tree_find_first_conduit() and LAG conduits which disappear. We have to be prepared to return to the physical conduit, so the CPU port must explicitly keep another reference to it. This is also to say: the user ports and their CPU ports may not always keep a reference to the same conduit net device, and both are needed. As for the conduit's kobject for the /sys/class/net/ entry, we don't care about it, we can release it as soon as we hold the net device object itself. History and blame attribution ----------------------------- The code has been refactored so many times, it is very difficult to follow and properly attribute a blame, but I'll try to make a short history which I hope to be correct. We have two distinct probing paths: - one for OF, introduced in 2016 in commit 83c0afaec7b7 ("net: dsa: Add new binding implementation") - one for non-OF, introduced in 2017 in commit 71e0bbde0d88 ("net: dsa: Add support for platform data") These are both complete rewrites of the original probing paths (which used struct dsa_switch_driver and other weird stuff, instead of regular devices on their respective buses for register access, like MDIO, SPI, I2C etc): - one for OF, introduced in 2013 in commit 5e95329b701c ("dsa: add device tree bindings to register DSA switches") - one for non-OF, introduced in 2008 in commit 91da11f870f0 ("net: Distributed Switch Architecture protocol support") except for tiny bits and pieces like dsa_dev_to_net_device() which were seemingly carried over since the original commit, and used to this day. The point is that the original probing paths received a fix in 2015 in the form of commit 679fb46c5785 ("net: dsa: Add missing master netdev dev_put() calls"), but the fix never made it into the "new" (dsa2) probing paths that can still be traced to today, and the fixed probing path was later deleted in 2019 in commit 93e86b3bc842 ("net: dsa: Remove legacy probing support"). That is to say, the new probing paths were never quite correct in this area. The existence of the legacy probing support which was deleted in 2019 explains why dsa_dev_to_net_device() returns a conduit with elevated refcount (because it was supposed to be released during dsa_remove_dst()). After the removal of the legacy code, the only user of dsa_dev_to_net_device() calls dev_put(conduit) immediately after this function returns. This pattern makes no sense today, and can only be interpreted historically to understand why dev_hold() was there in the first place. Change details -------------- Today we have a better netdev tracking infrastructure which we should use. Logically netdev_hold() belongs in common code (dsa_port_parse_cpu(), where dp->conduit is assigned), but there is a tradeoff to be made with the rtnl_lock() section which would become a bit too long if we did that - dsa_port_parse_cpu() also calls request_module(). So we duplicate a bit of logic in order for the callers of dsa_port_parse_cpu() to be the ones responsible of holding the conduit reference and releasing it on error. This shortens the rtnl_lock() section significantly. In the dsa_switch_probe() error path, dsa_switch_release_ports() will be called in a number of situations, one being where dsa_port_parse_cpu() maybe didn't get the chance to run at all (a different port failed earlier, etc). So we have to test for the conduit being NULL prior to calling netdev_put(). There have still been so many transformations to the code since the blamed commits (rename master -> conduit, commit 0650bf52b31f ("net: dsa: be compatible with masters which unregister on shutdown")), that it only makes sense to fix the code using the best methods available today and see how it can be backported to stable later. I suspect the fix cannot even be backported to kernels which lack dsa_switch_shutdown(), and I suspect this is also maybe why the long-lived conduit reference didn't make it into the new DSA probing paths at the time (problems during shutdown). Because dsa_dev_to_net_device() has a single call site and has to be changed anyway, the logic was just absorbed into the non-OF dsa_port_parse(). Tested on the ocelot/felix switch and on dsa_loop, both on the NXP LS1028A with CONFIG_DEBUG_KOBJECT_RELEASE=y. Reported-by: Ma Ke Closes: https://lore.kernel.org/netdev/20251214131204.4684-1-make24@iscas.ac.cn/ Fixes: 83c0afaec7b7 ("net: dsa: Add new binding implementation") Fixes: 71e0bbde0d88 ("net: dsa: Add support for platform data") Reviewed-by: Jonas Gorski Signed-off-by: Vladimir Oltean Link: https://patch.msgid.link/20251215150236.3931670-1-vladimir.oltean@nxp.com Signed-off-by: Paolo Abeni Signed-off-by: Sasha Levin --- include/net/dsa.h | 1 + net/dsa/dsa.c | 59 +++++++++++++++++++++++++++-------------------- 2 files changed, 35 insertions(+), 25 deletions(-) diff --git a/include/net/dsa.h b/include/net/dsa.h index d73ea08800660..5cb456bf46394 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -298,6 +298,7 @@ struct dsa_port { struct devlink_port devlink_port; struct phylink *pl; struct phylink_config pl_config; + netdevice_tracker conduit_tracker; struct dsa_lag *lag; struct net_device *hsr_dev; diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c index 5b01a0e43ebe8..d466d02340872 100644 --- a/net/dsa/dsa.c +++ b/net/dsa/dsa.c @@ -1252,14 +1252,25 @@ static int dsa_port_parse_of(struct dsa_port *dp, struct device_node *dn) if (ethernet) { struct net_device *conduit; const char *user_protocol; + int err; + rtnl_lock(); conduit = of_find_net_device_by_node(ethernet); of_node_put(ethernet); - if (!conduit) + if (!conduit) { + rtnl_unlock(); return -EPROBE_DEFER; + } + + netdev_hold(conduit, &dp->conduit_tracker, GFP_KERNEL); + put_device(&conduit->dev); + rtnl_unlock(); user_protocol = of_get_property(dn, "dsa-tag-protocol", NULL); - return dsa_port_parse_cpu(dp, conduit, user_protocol); + err = dsa_port_parse_cpu(dp, conduit, user_protocol); + if (err) + netdev_put(conduit, &dp->conduit_tracker); + return err; } if (link) @@ -1392,37 +1403,30 @@ static struct device *dev_find_class(struct device *parent, char *class) return device_find_child(parent, class, dev_is_class); } -static struct net_device *dsa_dev_to_net_device(struct device *dev) -{ - struct device *d; - - d = dev_find_class(dev, "net"); - if (d != NULL) { - struct net_device *nd; - - nd = to_net_dev(d); - dev_hold(nd); - put_device(d); - - return nd; - } - - return NULL; -} - static int dsa_port_parse(struct dsa_port *dp, const char *name, struct device *dev) { if (!strcmp(name, "cpu")) { struct net_device *conduit; + struct device *d; + int err; - conduit = dsa_dev_to_net_device(dev); - if (!conduit) + rtnl_lock(); + d = dev_find_class(dev, "net"); + if (!d) { + rtnl_unlock(); return -EPROBE_DEFER; + } - dev_put(conduit); + conduit = to_net_dev(d); + netdev_hold(conduit, &dp->conduit_tracker, GFP_KERNEL); + put_device(d); + rtnl_unlock(); - return dsa_port_parse_cpu(dp, conduit, NULL); + err = dsa_port_parse_cpu(dp, conduit, NULL); + if (err) + netdev_put(conduit, &dp->conduit_tracker); + return err; } if (!strcmp(name, "dsa")) @@ -1490,6 +1494,9 @@ static void dsa_switch_release_ports(struct dsa_switch *ds) struct dsa_vlan *v, *n; dsa_switch_for_each_port_safe(dp, next, ds) { + if (dsa_port_is_cpu(dp) && dp->conduit) + netdev_put(dp->conduit, &dp->conduit_tracker); + /* These are either entries that upper layers lost track of * (probably due to bugs), or installed through interfaces * where one does not necessarily have to remove them, like @@ -1634,8 +1641,10 @@ void dsa_switch_shutdown(struct dsa_switch *ds) /* Disconnect from further netdevice notifiers on the conduit, * since netdev_uses_dsa() will now return false. */ - dsa_switch_for_each_cpu_port(dp, ds) + dsa_switch_for_each_cpu_port(dp, ds) { dp->conduit->dsa_ptr = NULL; + netdev_put(dp->conduit, &dp->conduit_tracker); + } rtnl_unlock(); out: From ddbb72c338d9655cdb2f95d56223e909f51597bd Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Mon, 15 Dec 2025 17:02:36 +0200 Subject: [PATCH 1482/2333] net: dsa: fix missing put_device() in dsa_tree_find_first_conduit() [ Upstream commit a9f96dc59b4a50ffbf86158f315e115969172d48 ] of_find_net_device_by_node() searches net devices by their /sys/class/net/, entry. It is documented in its kernel-doc that: * If successful, returns a pointer to the net_device with the embedded * struct device refcount incremented by one, or NULL on failure. The * refcount must be dropped when done with the net_device. We are missing a put_device(&conduit->dev) which we could place at the end of dsa_tree_find_first_conduit(). But to explain why calling put_device() right away is safe is the same as to explain why the chosen solution is different. The code is very poorly split: dsa_tree_find_first_conduit() was first introduced in commit 95f510d0b792 ("net: dsa: allow the DSA master to be seen and changed through rtnetlink") but was first used several commits later, in commit acc43b7bf52a ("net: dsa: allow masters to join a LAG"). Assume there is a switch with 2 CPU ports and 2 conduits, eno2 and eno3. When we create a LAG (bonding or team device) and place eno2 and eno3 beneath it, we create a 3rd conduit (the LAG device itself), but this is slightly different than the first two. Namely, the cpu_dp->conduit pointer of the CPU ports does not change, and remains pointing towards the physical Ethernet controllers which are now LAG ports. Only 2 things change: - the LAG device has a dev->dsa_ptr which marks it as a DSA conduit - dsa_port_to_conduit(user port) finds the LAG and not the physical conduit, because of the dp->cpu_port_in_lag bit being set. When the LAG device is destroyed, dsa_tree_migrate_ports_from_lag_conduit() is called and this is where dsa_tree_find_first_conduit() kicks in. This is the logical mistake and the reason why introducing code in one patch and using it from another is bad practice. I didn't realize that I don't have to call of_find_net_device_by_node() again; the cpu_dp->conduit association was never undone, and is still available for direct (re)use. There's only one concern - maybe the conduit disappeared in the meantime, but the netdev_hold() call we made during dsa_port_parse_cpu() (see previous change) ensures that this was not the case. Therefore, fixing the code means reimplementing it in the simplest way. I am blaming the time of use, since this is what "git blame" would show if we were to monitor for the conduit's kobject's refcount remaining elevated instead of being freed. Tested on the NXP LS1028A, using the steps from Documentation/networking/dsa/configuration.rst section "Affinity of user ports to CPU ports", followed by (extra prints added by me): $ ip link del bond0 mscc_felix 0000:00:00.5 swp3: Link is Down bond0 (unregistering): (slave eno2): Releasing backup interface fsl_enetc 0000:00:00.2 eno2: Link is Down mscc_felix 0000:00:00.5 swp0: bond0 disappeared, migrating to eno2 mscc_felix 0000:00:00.5 swp1: bond0 disappeared, migrating to eno2 mscc_felix 0000:00:00.5 swp2: bond0 disappeared, migrating to eno2 mscc_felix 0000:00:00.5 swp3: bond0 disappeared, migrating to eno2 Fixes: acc43b7bf52a ("net: dsa: allow masters to join a LAG") Signed-off-by: Vladimir Oltean Link: https://patch.msgid.link/20251215150236.3931670-2-vladimir.oltean@nxp.com Signed-off-by: Paolo Abeni Signed-off-by: Sasha Levin --- net/dsa/dsa.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c index d466d02340872..ded9a291e6204 100644 --- a/net/dsa/dsa.c +++ b/net/dsa/dsa.c @@ -366,16 +366,10 @@ static struct dsa_port *dsa_tree_find_first_cpu(struct dsa_switch_tree *dst) struct net_device *dsa_tree_find_first_conduit(struct dsa_switch_tree *dst) { - struct device_node *ethernet; - struct net_device *conduit; struct dsa_port *cpu_dp; cpu_dp = dsa_tree_find_first_cpu(dst); - ethernet = of_parse_phandle(cpu_dp->dn, "ethernet", 0); - conduit = of_find_net_device_by_node(ethernet); - of_node_put(ethernet); - - return conduit; + return cpu_dp->conduit; } /* Assign the default CPU port (the first one in the tree) to all ports of the From 6602403b2fa19d9df89d63323bce5ffe335ae0bf Mon Sep 17 00:00:00 2001 From: Raju Rangoju Date: Mon, 15 Dec 2025 20:47:28 +0530 Subject: [PATCH 1483/2333] amd-xgbe: reset retries and mode on RX adapt failures [ Upstream commit df60c332caf95d70f967aeace826e7e2f0847361 ] During the stress tests, early RX adaptation handshakes can fail, such as missing the RX_ADAPT ACK or not receiving a coefficient update before block lock is established. Continuing to retry RX adaptation in this state is often ineffective if the current mode selection is not viable. Resetting the RX adaptation retry counter when an RX_ADAPT request fails to receive ACK or a coefficient update prior to block lock, and clearing mode_set so the next bring-up performs a fresh mode selection rather than looping on a likely invalid configuration. Fixes: 4f3b20bfbb75 ("amd-xgbe: add support for rx-adaptation") Signed-off-by: Raju Rangoju Reviewed-by: Simon Horman Reviewed-by: Shyam Sundar S K Link: https://patch.msgid.link/20251215151728.311713-1-Raju.Rangoju@amd.com Signed-off-by: Paolo Abeni Signed-off-by: Sasha Levin --- drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c b/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c index a56efc1bee339..450a573960e7a 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c @@ -1927,6 +1927,7 @@ static void xgbe_set_rx_adap_mode(struct xgbe_prv_data *pdata, { if (pdata->rx_adapt_retries++ >= MAX_RX_ADAPT_RETRIES) { pdata->rx_adapt_retries = 0; + pdata->mode_set = false; return; } @@ -1973,6 +1974,7 @@ static void xgbe_rx_adaptation(struct xgbe_prv_data *pdata) */ netif_dbg(pdata, link, pdata->netdev, "Block_lock done"); pdata->rx_adapt_done = true; + pdata->rx_adapt_retries = 0; pdata->mode_set = false; return; } From 018071d06c3b1dd09adf8f5d6dffbc7b275b10d3 Mon Sep 17 00:00:00 2001 From: Daniel Zahka Date: Tue, 16 Dec 2025 06:21:35 -0800 Subject: [PATCH 1484/2333] selftests: drv-net: psp: fix templated test names in psp_ip_ver_test_builder() [ Upstream commit d52668cac3f98f86aa1fb238dec1320c80fbefea ] test_case will only take on its formatted name after it is called by the test runner. Move the assignment to test_case.__name__ to when the test_case is constructed, not called. Fixes: 8f90dc6e417a ("selftests: drv-net: psp: add basic data transfer and key rotation tests") Signed-off-by: Daniel Zahka Link: https://patch.msgid.link/20251216-psp-test-fix-v1-1-3b5a6dde186f@gmail.com Signed-off-by: Paolo Abeni Signed-off-by: Sasha Levin --- tools/testing/selftests/drivers/net/psp.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/drivers/net/psp.py b/tools/testing/selftests/drivers/net/psp.py index 4ae7a785ff10a..827e04cc8423f 100755 --- a/tools/testing/selftests/drivers/net/psp.py +++ b/tools/testing/selftests/drivers/net/psp.py @@ -560,8 +560,9 @@ def psp_ip_ver_test_builder(name, test_func, psp_ver, ipver): """Build test cases for each combo of PSP version and IP version""" def test_case(cfg): cfg.require_ipver(ipver) - test_case.__name__ = f"{name}_v{psp_ver}_ip{ipver}" test_func(cfg, psp_ver, ipver) + + test_case.__name__ = f"{name}_v{psp_ver}_ip{ipver}" return test_case From e4e5c21a9cd5ae00efcb33752ea44d8aef115f6e Mon Sep 17 00:00:00 2001 From: Daniel Zahka Date: Tue, 16 Dec 2025 06:21:36 -0800 Subject: [PATCH 1485/2333] selftests: drv-net: psp: fix test names in ipver_test_builder() [ Upstream commit f0e5126f5e55d4939784ff61b0b7e9f9636d787d ] test_case will only take on the formatted name after being called. This does not work with the way ksft_run() currently works. Assign the name after the test_case is created. Fixes: 81236c74dba6 ("selftests: drv-net: psp: add test for auto-adjusting TCP MSS") Signed-off-by: Daniel Zahka Link: https://patch.msgid.link/20251216-psp-test-fix-v1-2-3b5a6dde186f@gmail.com Signed-off-by: Paolo Abeni Signed-off-by: Sasha Levin --- tools/testing/selftests/drivers/net/psp.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/drivers/net/psp.py b/tools/testing/selftests/drivers/net/psp.py index 827e04cc8423f..473573e216e34 100755 --- a/tools/testing/selftests/drivers/net/psp.py +++ b/tools/testing/selftests/drivers/net/psp.py @@ -570,8 +570,9 @@ def ipver_test_builder(name, test_func, ipver): """Build test cases for each IP version""" def test_case(cfg): cfg.require_ipver(ipver) - test_case.__name__ = f"{name}_ip{ipver}" test_func(cfg, ipver) + + test_case.__name__ = f"{name}_ip{ipver}" return test_case From 151403e903840c9cf06754097b6732c14f26c532 Mon Sep 17 00:00:00 2001 From: Deepakkumar Karn Date: Tue, 16 Dec 2025 20:43:05 +0530 Subject: [PATCH 1486/2333] net: usb: rtl8150: fix memory leak on usb_submit_urb() failure [ Upstream commit 12cab1191d9890097171156d06bfa8d31f1e39c8 ] In async_set_registers(), when usb_submit_urb() fails, the allocated async_req structure and URB are not freed, causing a memory leak. The completion callback async_set_reg_cb() is responsible for freeing these allocations, but it is only called after the URB is successfully submitted and completes (successfully or with error). If submission fails, the callback never runs and the memory is leaked. Fix this by freeing both the URB and the request structure in the error path when usb_submit_urb() fails. Reported-by: syzbot+8dd915c7cb0490fc8c52@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=8dd915c7cb0490fc8c52 Fixes: 4d12997a9bb3 ("drivers: net: usb: rtl8150: concurrent URB bugfix") Signed-off-by: Deepakkumar Karn Link: https://patch.msgid.link/20251216151304.59865-2-dkarn@redhat.com Signed-off-by: Paolo Abeni Signed-off-by: Sasha Levin --- drivers/net/usb/rtl8150.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c index 278e6cb6f4d99..e40b0669d9f4b 100644 --- a/drivers/net/usb/rtl8150.c +++ b/drivers/net/usb/rtl8150.c @@ -211,6 +211,8 @@ static int async_set_registers(rtl8150_t *dev, u16 indx, u16 size, u16 reg) if (res == -ENODEV) netif_device_detach(dev->netdev); dev_err(&dev->udev->dev, "%s failed with %d\n", __func__, res); + kfree(req); + usb_free_urb(async_urb); } return res; } From 9b91553a30a632edde7497e50fd8aa512229efc2 Mon Sep 17 00:00:00 2001 From: "Alice C. Munduruca" Date: Tue, 16 Dec 2025 12:06:41 -0500 Subject: [PATCH 1487/2333] selftests: net: fix "buffer overflow detected" for tap.c [ Upstream commit 472c5dd6b95c02b3e5d7395acf542150e91165e7 ] When the selftest 'tap.c' is compiled with '-D_FORTIFY_SOURCE=3', the strcpy() in rtattr_add_strsz() is replaced with a checked version which causes the test to consistently fail when compiled with toolchains for which this option is enabled by default. TAP version 13 1..3 # Starting 3 tests from 1 test cases. # RUN tap.test_packet_valid_udp_gso ... *** buffer overflow detected ***: terminated # test_packet_valid_udp_gso: Test terminated by assertion # FAIL tap.test_packet_valid_udp_gso not ok 1 tap.test_packet_valid_udp_gso # RUN tap.test_packet_valid_udp_csum ... *** buffer overflow detected ***: terminated # test_packet_valid_udp_csum: Test terminated by assertion # FAIL tap.test_packet_valid_udp_csum not ok 2 tap.test_packet_valid_udp_csum # RUN tap.test_packet_crash_tap_invalid_eth_proto ... *** buffer overflow detected ***: terminated # test_packet_crash_tap_invalid_eth_proto: Test terminated by assertion # FAIL tap.test_packet_crash_tap_invalid_eth_proto not ok 3 tap.test_packet_crash_tap_invalid_eth_proto # FAILED: 0 / 3 tests passed. # Totals: pass:0 fail:3 xfail:0 xpass:0 skip:0 error:0 A buffer overflow is detected by the fortified glibc __strcpy_chk() since the __builtin_object_size() of `RTA_DATA(rta)` is incorrectly reported as 1, even though there is ample space in its bounding buffer `req`. Additionally, given that IFLA_IFNAME also expects a null-terminated string, callers of rtaddr_add_str{,sz}() could simply use the rtaddr_add_strsz() variant. (which has been renamed to remove the trailing `sz`) memset() has been used for this function since it is unchecked and thus circumvents the issue discussed in the previous paragraph. Fixes: 2e64fe4624d1 ("selftests: add few test cases for tap driver") Signed-off-by: Alice C. Munduruca Reviewed-by: Cengiz Can Reviewed-by: Willem de Bruijn Link: https://patch.msgid.link/20251216170641.250494-1-alice.munduruca@canonical.com Signed-off-by: Paolo Abeni Signed-off-by: Sasha Levin --- tools/testing/selftests/net/tap.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/tools/testing/selftests/net/tap.c b/tools/testing/selftests/net/tap.c index 247c3b3ac1c97..51a209014f1cf 100644 --- a/tools/testing/selftests/net/tap.c +++ b/tools/testing/selftests/net/tap.c @@ -56,18 +56,12 @@ static void rtattr_end(struct nlmsghdr *nh, struct rtattr *attr) static struct rtattr *rtattr_add_str(struct nlmsghdr *nh, unsigned short type, const char *s) { - struct rtattr *rta = rtattr_add(nh, type, strlen(s)); + unsigned int strsz = strlen(s) + 1; + struct rtattr *rta; - memcpy(RTA_DATA(rta), s, strlen(s)); - return rta; -} - -static struct rtattr *rtattr_add_strsz(struct nlmsghdr *nh, unsigned short type, - const char *s) -{ - struct rtattr *rta = rtattr_add(nh, type, strlen(s) + 1); + rta = rtattr_add(nh, type, strsz); - strcpy(RTA_DATA(rta), s); + memcpy(RTA_DATA(rta), s, strsz); return rta; } @@ -119,7 +113,7 @@ static int dev_create(const char *dev, const char *link_type, link_info = rtattr_begin(&req.nh, IFLA_LINKINFO); - rtattr_add_strsz(&req.nh, IFLA_INFO_KIND, link_type); + rtattr_add_str(&req.nh, IFLA_INFO_KIND, link_type); if (fill_info_data) { info_data = rtattr_begin(&req.nh, IFLA_INFO_DATA); From 66299520bb6e88caf4638104b65a8b4248ca64a8 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 16 Dec 2025 22:35:42 +0100 Subject: [PATCH 1488/2333] net: wangxun: move PHYLINK dependency [ Upstream commit b94f11af9d9201426f4d6c8a753493fd58d6ac16 ] The LIBWX library code is what calls into phylink, so any user of it has to select CONFIG_PHYLINK at the moment, with NGBEVF missing this: x86_64-linux-ld: drivers/net/ethernet/wangxun/libwx/wx_ethtool.o: in function `wx_nway_reset': wx_ethtool.c:(.text+0x613): undefined reference to `phylink_ethtool_nway_reset' x86_64-linux-ld: drivers/net/ethernet/wangxun/libwx/wx_ethtool.o: in function `wx_get_link_ksettings': wx_ethtool.c:(.text+0x62b): undefined reference to `phylink_ethtool_ksettings_get' x86_64-linux-ld: drivers/net/ethernet/wangxun/libwx/wx_ethtool.o: in function `wx_set_link_ksettings': wx_ethtool.c:(.text+0x643): undefined reference to `phylink_ethtool_ksettings_set' x86_64-linux-ld: drivers/net/ethernet/wangxun/libwx/wx_ethtool.o: in function `wx_get_pauseparam': wx_ethtool.c:(.text+0x65b): undefined reference to `phylink_ethtool_get_pauseparam' x86_64-linux-ld: drivers/net/ethernet/wangxun/libwx/wx_ethtool.o: in function `wx_set_pauseparam': wx_ethtool.c:(.text+0x677): undefined reference to `phylink_ethtool_set_pauseparam' Add the 'select PHYLINK' line in the libwx option directly so this will always be enabled for all current and future wangxun drivers, and remove the now duplicate lines. Fixes: a0008a3658a3 ("net: wangxun: add ngbevf build") Signed-off-by: Arnd Bergmann Reviewed-by: Vadim Fedorenko Link: https://patch.msgid.link/20251216213547.115026-1-arnd@kernel.org Signed-off-by: Paolo Abeni Signed-off-by: Sasha Levin --- drivers/net/ethernet/wangxun/Kconfig | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/net/ethernet/wangxun/Kconfig b/drivers/net/ethernet/wangxun/Kconfig index d138dea7d208d..ec278f99d2955 100644 --- a/drivers/net/ethernet/wangxun/Kconfig +++ b/drivers/net/ethernet/wangxun/Kconfig @@ -21,6 +21,7 @@ config LIBWX depends on PTP_1588_CLOCK_OPTIONAL select PAGE_POOL select DIMLIB + select PHYLINK help Common library for Wangxun(R) Ethernet drivers. @@ -29,7 +30,6 @@ config NGBE depends on PCI depends on PTP_1588_CLOCK_OPTIONAL select LIBWX - select PHYLINK help This driver supports Wangxun(R) GbE PCI Express family of adapters. @@ -48,7 +48,6 @@ config TXGBE depends on PTP_1588_CLOCK_OPTIONAL select MARVELL_10G_PHY select REGMAP - select PHYLINK select HWMON if TXGBE=y select SFP select GPIOLIB @@ -71,7 +70,6 @@ config TXGBEVF depends on PCI_MSI depends on PTP_1588_CLOCK_OPTIONAL select LIBWX - select PHYLINK help This driver supports virtual functions for SP1000A, WX1820AL, WX5XXX, WX5XXXAL. From 277b256f579ae8966bc3eeb27bbfc6de7ad17010 Mon Sep 17 00:00:00 2001 From: Kaushlendra Kumar Date: Tue, 23 Dec 2025 14:10:41 +0530 Subject: [PATCH 1489/2333] platform/x86/intel/pmt: Fix kobject memory leak on init failure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 00c22b1e84288bf0e17ab1e7e59d75237cf0d0dc ] When kobject_init_and_add() fails in pmt_features_discovery(), the function returns without calling kobject_put(). This violates the kobject API contract where kobject_put() must be called even on initialization failure to properly release allocated resources. Fixes: d9a078809356 ("platform/x86/intel/pmt: Add PMT Discovery driver") Signed-off-by: Kaushlendra Kumar Link: https://patch.msgid.link/20251223084041.3832933-1-kaushlendra.kumar@intel.com Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen Signed-off-by: Sasha Levin --- drivers/platform/x86/intel/pmt/discovery.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/platform/x86/intel/pmt/discovery.c b/drivers/platform/x86/intel/pmt/discovery.c index 32713a194a550..9c5b4d0e1fae6 100644 --- a/drivers/platform/x86/intel/pmt/discovery.c +++ b/drivers/platform/x86/intel/pmt/discovery.c @@ -503,8 +503,10 @@ static int pmt_features_discovery(struct pmt_features_priv *priv, ret = kobject_init_and_add(&feature->kobj, ktype, &priv->dev->kobj, "%s", pmt_feature_names[feature->id]); - if (ret) + if (ret) { + kobject_put(&feature->kobj); return ret; + } kobject_uevent(&feature->kobj, KOBJ_ADD); pmt_features_add_feat(feature); From b6018d5c1a8f09d5efe4d6961d7ee45fdf3a7ce3 Mon Sep 17 00:00:00 2001 From: Yeoreum Yun Date: Wed, 17 Dec 2025 08:51:15 +0000 Subject: [PATCH 1490/2333] smc91x: fix broken irq-context in PREEMPT_RT [ Upstream commit 6402078bd9d1ed46e79465e1faaa42e3458f8a33 ] When smc91x.c is built with PREEMPT_RT, the following splat occurs in FVP_RevC: [ 13.055000] smc91x LNRO0003:00 eth0: link up, 10Mbps, half-duplex, lpa 0x0000 [ 13.062137] BUG: workqueue leaked atomic, lock or RCU: kworker/2:1[106] [ 13.062137] preempt=0x00000000 lock=0->0 RCU=0->1 workfn=mld_ifc_work [ 13.062266] C ** replaying previous printk message ** [ 13.062266] CPU: 2 UID: 0 PID: 106 Comm: kworker/2:1 Not tainted 6.18.0-dirty #179 PREEMPT_{RT,(full)} [ 13.062353] Hardware name: , BIOS [ 13.062382] Workqueue: mld mld_ifc_work [ 13.062469] Call trace: [ 13.062494] show_stack+0x24/0x40 (C) [ 13.062602] __dump_stack+0x28/0x48 [ 13.062710] dump_stack_lvl+0x7c/0xb0 [ 13.062818] dump_stack+0x18/0x34 [ 13.062926] process_scheduled_works+0x294/0x450 [ 13.063043] worker_thread+0x260/0x3d8 [ 13.063124] kthread+0x1c4/0x228 [ 13.063235] ret_from_fork+0x10/0x20 This happens because smc_special_trylock() disables IRQs even on PREEMPT_RT, but smc_special_unlock() does not restore IRQs on PREEMPT_RT. The reason is that smc_special_unlock() calls spin_unlock_irqrestore(), and rcu_read_unlock_bh() in __dev_queue_xmit() cannot invoke rcu_read_unlock() through __local_bh_enable_ip() when current->softirq_disable_cnt becomes zero. To address this issue, replace smc_special_trylock() with spin_trylock_irqsave(). Fixes: 342a93247e08 ("locking/spinlock: Provide RT variant header: ") Signed-off-by: Yeoreum Yun Reviewed-by: Simon Horman Link: https://patch.msgid.link/20251217085115.1730036-1-yeoreum.yun@arm.com Signed-off-by: Paolo Abeni Signed-off-by: Sasha Levin --- drivers/net/ethernet/smsc/smc91x.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/drivers/net/ethernet/smsc/smc91x.c b/drivers/net/ethernet/smsc/smc91x.c index 9d1a83a5fa7e5..d16c178d10344 100644 --- a/drivers/net/ethernet/smsc/smc91x.c +++ b/drivers/net/ethernet/smsc/smc91x.c @@ -516,15 +516,7 @@ static inline void smc_rcv(struct net_device *dev) * any other concurrent access and C would always interrupt B. But life * isn't that easy in a SMP world... */ -#define smc_special_trylock(lock, flags) \ -({ \ - int __ret; \ - local_irq_save(flags); \ - __ret = spin_trylock(lock); \ - if (!__ret) \ - local_irq_restore(flags); \ - __ret; \ -}) +#define smc_special_trylock(lock, flags) spin_trylock_irqsave(lock, flags) #define smc_special_lock(lock, flags) spin_lock_irqsave(lock, flags) #define smc_special_unlock(lock, flags) spin_unlock_irqrestore(lock, flags) #else From 3411103f6b3e0ce1725a5fe161f290dd4dd7c5eb Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Thu, 27 Nov 2025 10:39:24 -0800 Subject: [PATCH 1491/2333] genalloc.h: fix htmldocs warning [ Upstream commit 5393802c94e0ab1295c04c94c57bcb00222d4674 ] WARNING: include/linux/genalloc.h:52 function parameter 'start_addr' not described in 'genpool_algo_t' Fixes: 52fbf1134d47 ("lib/genalloc.c: fix allocation of aligned buffer from non-aligned chunk") Reported-by: Stephen Rothwell Closes: https://lkml.kernel.org/r/20251127130624.563597e3@canb.auug.org.au Acked-by: Randy Dunlap Tested-by: Randy Dunlap Cc: Alexey Skidanov Signed-off-by: Andrew Morton Signed-off-by: Sasha Levin --- include/linux/genalloc.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/genalloc.h b/include/linux/genalloc.h index 0bd581003cd5d..60de63e46b33d 100644 --- a/include/linux/genalloc.h +++ b/include/linux/genalloc.h @@ -44,6 +44,7 @@ struct gen_pool; * @nr: The number of zeroed bits we're looking for * @data: optional additional data used by the callback * @pool: the pool being allocated from + * @start_addr: start address of memory chunk */ typedef unsigned long (*genpool_algo_t)(unsigned long *map, unsigned long size, From f7d95f9ee070486db6f919023c0796c33344805c Mon Sep 17 00:00:00 2001 From: Thomas Fourier Date: Tue, 16 Dec 2025 17:54:18 +0100 Subject: [PATCH 1492/2333] firewire: nosy: Fix dma_free_coherent() size [ Upstream commit c48c0fd0e19684b6ecdb4108a429e3a4e73f5e21 ] It looks like the buffer allocated and mapped in add_card() is done with size RCV_BUFFER_SIZE which is 16 KB and 4KB. Fixes: 286468210d83 ("firewire: new driver: nosy - IEEE 1394 traffic sniffer") Co-developed-by: Thomas Fourier Signed-off-by: Thomas Fourier Co-developed-by: Christophe JAILLET Signed-off-by: Christophe JAILLET Link: https://lore.kernel.org/r/20251216165420.38355-2-fourier.thomas@gmail.com Signed-off-by: Takashi Sakamoto Signed-off-by: Sasha Levin --- drivers/firewire/nosy.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/firewire/nosy.c b/drivers/firewire/nosy.c index ea31ac7ac1ca9..e59053738a432 100644 --- a/drivers/firewire/nosy.c +++ b/drivers/firewire/nosy.c @@ -36,6 +36,8 @@ static char driver_name[] = KBUILD_MODNAME; +#define RCV_BUFFER_SIZE (16 * 1024) + /* this is the physical layout of a PCL, its size is 128 bytes */ struct pcl { __le32 next; @@ -517,16 +519,14 @@ remove_card(struct pci_dev *dev) lynx->rcv_start_pcl, lynx->rcv_start_pcl_bus); dma_free_coherent(&lynx->pci_device->dev, sizeof(struct pcl), lynx->rcv_pcl, lynx->rcv_pcl_bus); - dma_free_coherent(&lynx->pci_device->dev, PAGE_SIZE, lynx->rcv_buffer, - lynx->rcv_buffer_bus); + dma_free_coherent(&lynx->pci_device->dev, RCV_BUFFER_SIZE, + lynx->rcv_buffer, lynx->rcv_buffer_bus); iounmap(lynx->registers); pci_disable_device(dev); lynx_put(lynx); } -#define RCV_BUFFER_SIZE (16 * 1024) - static int add_card(struct pci_dev *dev, const struct pci_device_id *unused) { @@ -680,7 +680,7 @@ add_card(struct pci_dev *dev, const struct pci_device_id *unused) dma_free_coherent(&lynx->pci_device->dev, sizeof(struct pcl), lynx->rcv_pcl, lynx->rcv_pcl_bus); if (lynx->rcv_buffer) - dma_free_coherent(&lynx->pci_device->dev, PAGE_SIZE, + dma_free_coherent(&lynx->pci_device->dev, RCV_BUFFER_SIZE, lynx->rcv_buffer, lynx->rcv_buffer_bus); iounmap(lynx->registers); From 3b3ddded9c8624d2dbfc77a5d1fbd8211825142b Mon Sep 17 00:00:00 2001 From: Rajashekar Hudumula Date: Wed, 17 Dec 2025 02:47:48 -0800 Subject: [PATCH 1493/2333] bng_en: update module description [ Upstream commit d5dc28305143f126dc3d8da21e1ad75865b194e2 ] The Broadcom BCM57708/800G NIC family is branded as ThorUltra. Update the driver description accordingly. Fixes: 74715c4ab0fa0 ("bng_en: Add PCI interface") Signed-off-by: Rajashekar Hudumula Reviewed-by: Vikas Gupta Reviewed-by: Bhargava Chenna Marreddy Link: https://patch.msgid.link/20251217104748.3004706-1-rajashekar.hudumula@broadcom.com Signed-off-by: Paolo Abeni Signed-off-by: Sasha Levin --- drivers/net/ethernet/broadcom/Kconfig | 8 ++++---- drivers/net/ethernet/broadcom/bnge/bnge.h | 2 +- drivers/net/ethernet/broadcom/bnge/bnge_core.c | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/broadcom/Kconfig b/drivers/net/ethernet/broadcom/Kconfig index 9fdef874f5ca3..fe15d684990fc 100644 --- a/drivers/net/ethernet/broadcom/Kconfig +++ b/drivers/net/ethernet/broadcom/Kconfig @@ -254,14 +254,14 @@ config BNXT_HWMON devices, via the hwmon sysfs interface. config BNGE - tristate "Broadcom Ethernet device support" + tristate "Broadcom ThorUltra Ethernet device support" depends on PCI select NET_DEVLINK select PAGE_POOL help - This driver supports Broadcom 50/100/200/400/800 gigabit Ethernet cards. - The module will be called bng_en. To compile this driver as a module, - choose M here. + This driver supports Broadcom ThorUltra 50/100/200/400/800 gigabit + Ethernet cards. The module will be called bng_en. To compile this + driver as a module, choose M here. config BCMASP tristate "Broadcom ASP 2.0 Ethernet support" diff --git a/drivers/net/ethernet/broadcom/bnge/bnge.h b/drivers/net/ethernet/broadcom/bnge/bnge.h index 7aed5f81cd51e..0c154995d9ab5 100644 --- a/drivers/net/ethernet/broadcom/bnge/bnge.h +++ b/drivers/net/ethernet/broadcom/bnge/bnge.h @@ -5,7 +5,7 @@ #define _BNGE_H_ #define DRV_NAME "bng_en" -#define DRV_SUMMARY "Broadcom 800G Ethernet Linux Driver" +#define DRV_SUMMARY "Broadcom ThorUltra NIC Ethernet Driver" #include #include diff --git a/drivers/net/ethernet/broadcom/bnge/bnge_core.c b/drivers/net/ethernet/broadcom/bnge/bnge_core.c index 2c72dd34d50d0..312a9db4d75d1 100644 --- a/drivers/net/ethernet/broadcom/bnge/bnge_core.c +++ b/drivers/net/ethernet/broadcom/bnge/bnge_core.c @@ -19,7 +19,7 @@ char bnge_driver_name[] = DRV_NAME; static const struct { char *name; } board_info[] = { - [BCM57708] = { "Broadcom BCM57708 50Gb/100Gb/200Gb/400Gb/800Gb Ethernet" }, + [BCM57708] = { "Broadcom BCM57708 ThorUltra 50Gb/100Gb/200Gb/400Gb/800Gb Ethernet" }, }; static const struct pci_device_id bnge_pci_tbl[] = { From 6ddf3ae19574095d46c5a65f421f104d5aaac7c6 Mon Sep 17 00:00:00 2001 From: Jonas Gorski Date: Wed, 17 Dec 2025 21:57:56 +0100 Subject: [PATCH 1494/2333] net: dsa: b53: skip multicast entries for fdb_dump() [ Upstream commit d42bce414d1c5c0b536758466a1f63ac358e613c ] port_fdb_dump() is supposed to only add fdb entries, but we iterate over the full ARL table, which also includes multicast entries. So check if the entry is a multicast entry before passing it on to the callback(). Additionally, the port of those entries is a bitmask, not a port number, so any included entries would have even be for the wrong port. Fixes: 1da6df85c6fb ("net: dsa: b53: Implement ARL add/del/dump operations") Signed-off-by: Jonas Gorski Reviewed-by: Florian Fainelli Link: https://patch.msgid.link/20251217205756.172123-1-jonas.gorski@gmail.com Signed-off-by: Paolo Abeni Signed-off-by: Sasha Levin --- drivers/net/dsa/b53/b53_common.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c index 62cafced758e7..7d6ec2eb7c75e 100644 --- a/drivers/net/dsa/b53/b53_common.c +++ b/drivers/net/dsa/b53/b53_common.c @@ -2155,6 +2155,9 @@ static int b53_fdb_copy(int port, const struct b53_arl_entry *ent, if (!ent->is_valid) return 0; + if (is_multicast_ether_addr(ent->mac)) + return 0; + if (port != ent->port) return 0; From 0c1df928f0b87cc672ab46bdd51412d5d776c327 Mon Sep 17 00:00:00 2001 From: Thomas De Schampheleire Date: Wed, 26 Nov 2025 11:00:16 +0100 Subject: [PATCH 1495/2333] kbuild: fix compilation of dtb specified on command-line without make rule [ Upstream commit b08fc4d0ec2466558f6d5511434efdfabbddf2a6 ] Since commit e7e2941300d2 ("kbuild: split device tree build rules into scripts/Makefile.dtbs"), it is no longer possible to compile a device tree blob that is not specified in a make rule like: dtb-$(CONFIG_FOO) += foo.dtb Before the mentioned commit, one could copy a dts file to e.g. arch/arm64/boot/dts/ (or a new subdirectory) and then convert it to a dtb file using: make ARCH=arm64 foo.dtb In this scenario, both 'dtb-y' and 'dtb-' are empty, and the inclusion of scripts/Makefile.dtbs relies on 'targets' to contain the MAKECMDGOALS. The value of 'targets', however, is only final later in the code. Move the conditional include of scripts/Makefile.dtbs down to where the value of 'targets' is final. Since Makefile.dtbs updates 'always-y' which is used as a prerequisite in the build rule, the build rule also needs to move down. Fixes: e7e2941300d2 ("kbuild: split device tree build rules into scripts/Makefile.dtbs") Signed-off-by: Thomas De Schampheleire Reviewed-by: Nathan Chancellor Tested-by: Nathan Chancellor Acked-by: Rob Herring (Arm) Link: https://patch.msgid.link/20251126100017.1162330-1-thomas.de_schampheleire@nokia.com Signed-off-by: Nicolas Schier Signed-off-by: Sasha Levin --- scripts/Makefile.build | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/scripts/Makefile.build b/scripts/Makefile.build index 52c08c4eb0b9a..5037f4715d749 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build @@ -527,18 +527,6 @@ ifneq ($(userprogs),) include $(srctree)/scripts/Makefile.userprogs endif -ifneq ($(need-dtbslist)$(dtb-y)$(dtb-)$(filter %.dtb %.dtb.o %.dtbo.o,$(targets)),) -include $(srctree)/scripts/Makefile.dtbs -endif - -# Build -# --------------------------------------------------------------------------- - -$(obj)/: $(if $(KBUILD_BUILTIN), $(targets-for-builtin)) \ - $(if $(KBUILD_MODULES), $(targets-for-modules)) \ - $(subdir-ym) $(always-y) - @: - # Single targets # --------------------------------------------------------------------------- @@ -568,6 +556,20 @@ FORCE: targets += $(filter-out $(single-subdir-goals), $(MAKECMDGOALS)) targets := $(filter-out $(PHONY), $(targets)) +# Now that targets is fully known, include dtb rules if needed +ifneq ($(need-dtbslist)$(dtb-y)$(dtb-)$(filter %.dtb %.dtb.o %.dtbo.o,$(targets)),) +include $(srctree)/scripts/Makefile.dtbs +endif + +# Build +# Needs to be after the include of Makefile.dtbs, which updates always-y +# --------------------------------------------------------------------------- + +$(obj)/: $(if $(KBUILD_BUILTIN), $(targets-for-builtin)) \ + $(if $(KBUILD_MODULES), $(targets-for-modules)) \ + $(subdir-ym) $(always-y) + @: + # Read all saved command lines and dependencies for the $(targets) we # may be building above, using $(if_changed{,_dep}). As an # optimization, we don't need to read them if the target does not From 937c7172d1e36d23a1e7c36220f636c2d9483f58 Mon Sep 17 00:00:00 2001 From: Jose Javier Rodriguez Barbarin Date: Tue, 2 Dec 2025 09:42:00 +0100 Subject: [PATCH 1496/2333] mcb: Add missing modpost build support [ Upstream commit 1f4ea4838b13c3b2278436a8dcb148e3c23f4b64 ] mcb bus is not prepared to autoload client drivers with the data defined on the drivers' MODULE_DEVICE_TABLE. modpost cannot access to mcb_table_id inside MODULE_DEVICE_TABLE so the data declared inside is ignored. Add modpost build support for accessing to the mcb_table_id coded on device drivers' MODULE_DEVICE_TABLE. Fixes: 3764e82e5150 ("drivers: Introduce MEN Chameleon Bus") Reviewed-by: Jorge Sanjuan Garcia Signed-off-by: Jose Javier Rodriguez Barbarin Acked-by: Nathan Chancellor Reviewed-by: Andy Shevchenko Link: https://patch.msgid.link/20251202084200.10410-1-dev-josejavier.rodriguez@duagon.com Signed-off-by: Nicolas Schier Signed-off-by: Sasha Levin --- scripts/mod/devicetable-offsets.c | 3 +++ scripts/mod/file2alias.c | 9 +++++++++ 2 files changed, 12 insertions(+) diff --git a/scripts/mod/devicetable-offsets.c b/scripts/mod/devicetable-offsets.c index d3d00e85edf73..0470ba7c796d4 100644 --- a/scripts/mod/devicetable-offsets.c +++ b/scripts/mod/devicetable-offsets.c @@ -198,6 +198,9 @@ int main(void) DEVID(cpu_feature); DEVID_FIELD(cpu_feature, feature); + DEVID(mcb_device_id); + DEVID_FIELD(mcb_device_id, device); + DEVID(mei_cl_device_id); DEVID_FIELD(mei_cl_device_id, name); DEVID_FIELD(mei_cl_device_id, uuid); diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c index b3333560b95ee..4e99393a35f15 100644 --- a/scripts/mod/file2alias.c +++ b/scripts/mod/file2alias.c @@ -1110,6 +1110,14 @@ static void do_cpu_entry(struct module *mod, void *symval) module_alias_printf(mod, false, "cpu:type:*:feature:*%04X*", feature); } +/* Looks like: mcb:16zN */ +static void do_mcb_entry(struct module *mod, void *symval) +{ + DEF_FIELD(symval, mcb_device_id, device); + + module_alias_printf(mod, false, "mcb:16z%03d", device); +} + /* Looks like: mei:S:uuid:N:* */ static void do_mei_entry(struct module *mod, void *symval) { @@ -1444,6 +1452,7 @@ static const struct devtable devtable[] = { {"mipscdmm", SIZE_mips_cdmm_device_id, do_mips_cdmm_entry}, {"x86cpu", SIZE_x86_cpu_id, do_x86cpu_entry}, {"cpu", SIZE_cpu_feature, do_cpu_entry}, + {"mcb", SIZE_mcb_device_id, do_mcb_entry}, {"mei", SIZE_mei_cl_device_id, do_mei_entry}, {"rapidio", SIZE_rio_device_id, do_rio_entry}, {"ulpi", SIZE_ulpi_device_id, do_ulpi_entry}, From 93a880f73b8867d2bb30ae91539a3b0e915a23ac Mon Sep 17 00:00:00 2001 From: Rosen Penev Date: Wed, 17 Dec 2025 13:01:53 -0800 Subject: [PATCH 1497/2333] net: mdio: rtl9300: use scoped for loops [ Upstream commit a4f800c4487dc5d6fcc28da89c7cc3c187ccc731 ] Currently in the return path, fwnode_handle_put calls are missing. Just use _scoped to avoid the issue. Fixes: 24e31e474769 ("net: mdio: Add RTL9300 MDIO driver") Signed-off-by: Rosen Penev Link: https://patch.msgid.link/20251217210153.14641-1-rosenp@gmail.com Signed-off-by: Paolo Abeni Signed-off-by: Sasha Levin --- drivers/net/mdio/mdio-realtek-rtl9300.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/mdio/mdio-realtek-rtl9300.c b/drivers/net/mdio/mdio-realtek-rtl9300.c index 33694c3ff9a71..405a07075dd11 100644 --- a/drivers/net/mdio/mdio-realtek-rtl9300.c +++ b/drivers/net/mdio/mdio-realtek-rtl9300.c @@ -354,7 +354,6 @@ static int rtl9300_mdiobus_probe_one(struct device *dev, struct rtl9300_mdio_pri struct fwnode_handle *node) { struct rtl9300_mdio_chan *chan; - struct fwnode_handle *child; struct mii_bus *bus; u32 mdio_bus; int err; @@ -371,7 +370,7 @@ static int rtl9300_mdiobus_probe_one(struct device *dev, struct rtl9300_mdio_pri * compatible = "ethernet-phy-ieee802.3-c45". This does mean we can't * support both c45 and c22 on the same MDIO bus. */ - fwnode_for_each_child_node(node, child) + fwnode_for_each_child_node_scoped(node, child) if (fwnode_device_is_compatible(child, "ethernet-phy-ieee802.3-c45")) priv->smi_bus_is_c45[mdio_bus] = true; @@ -409,7 +408,6 @@ static int rtl9300_mdiobus_map_ports(struct device *dev) { struct rtl9300_mdio_priv *priv = dev_get_drvdata(dev); struct device *parent = dev->parent; - struct fwnode_handle *port; int err; struct fwnode_handle *ports __free(fwnode_handle) = @@ -418,7 +416,7 @@ static int rtl9300_mdiobus_map_ports(struct device *dev) return dev_err_probe(dev, -EINVAL, "%pfwP missing ethernet-ports\n", dev_fwnode(parent)); - fwnode_for_each_child_node(ports, port) { + fwnode_for_each_child_node_scoped(ports, port) { struct device_node *mdio_dn; u32 addr; u32 bus; From bf8a0f3b787ca7c5889bfca12c60c483041fbee3 Mon Sep 17 00:00:00 2001 From: Deepanshu Kartikey Date: Thu, 18 Dec 2025 06:41:56 +0530 Subject: [PATCH 1498/2333] net: usb: asix: validate PHY address before use [ Upstream commit a1e077a3f76eea0dc671ed6792e7d543946227e8 ] The ASIX driver reads the PHY address from the USB device via asix_read_phy_addr(). A malicious or faulty device can return an invalid address (>= PHY_MAX_ADDR), which causes a warning in mdiobus_get_phy(): addr 207 out of range WARNING: drivers/net/phy/mdio_bus.c:76 Validate the PHY address in asix_read_phy_addr() and remove the now-redundant check in ax88172a.c. Reported-by: syzbot+3d43c9066a5b54902232@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=3d43c9066a5b54902232 Tested-by: syzbot+3d43c9066a5b54902232@syzkaller.appspotmail.com Fixes: 7e88b11a862a ("net: usb: asix: refactor asix_read_phy_addr() and handle errors on return") Link: https://lore.kernel.org/all/20251217085057.270704-1-kartikey406@gmail.com/T/ [v1] Signed-off-by: Deepanshu Kartikey Reviewed-by: Andrew Lunn Link: https://patch.msgid.link/20251218011156.276824-1-kartikey406@gmail.com Signed-off-by: Paolo Abeni Signed-off-by: Sasha Levin --- drivers/net/usb/asix_common.c | 5 +++++ drivers/net/usb/ax88172a.c | 6 +----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/net/usb/asix_common.c b/drivers/net/usb/asix_common.c index 7fd763917ae2c..6ab3486072cb0 100644 --- a/drivers/net/usb/asix_common.c +++ b/drivers/net/usb/asix_common.c @@ -335,6 +335,11 @@ int asix_read_phy_addr(struct usbnet *dev, bool internal) offset = (internal ? 1 : 0); ret = buf[offset]; + if (ret >= PHY_MAX_ADDR) { + netdev_err(dev->net, "invalid PHY address: %d\n", ret); + return -ENODEV; + } + netdev_dbg(dev->net, "%s PHY address 0x%x\n", internal ? "internal" : "external", ret); diff --git a/drivers/net/usb/ax88172a.c b/drivers/net/usb/ax88172a.c index f613e4bc68c85..758a423a459b8 100644 --- a/drivers/net/usb/ax88172a.c +++ b/drivers/net/usb/ax88172a.c @@ -210,11 +210,7 @@ static int ax88172a_bind(struct usbnet *dev, struct usb_interface *intf) ret = asix_read_phy_addr(dev, priv->use_embdphy); if (ret < 0) goto free; - if (ret >= PHY_MAX_ADDR) { - netdev_err(dev->net, "Invalid PHY address %#x\n", ret); - ret = -ENODEV; - goto free; - } + priv->phy_addr = ret; ax88172a_reset_phy(dev, priv->use_embdphy); From 6081ef09c54e0a943dfed11bb8ea149865bc3177 Mon Sep 17 00:00:00 2001 From: Bagas Sanjaya Date: Thu, 18 Dec 2025 11:29:37 +0700 Subject: [PATCH 1499/2333] net: bridge: Describe @tunnel_hash member in net_bridge_vlan_group struct [ Upstream commit f79f9b7ace1713e4b83888c385f5f55519dfb687 ] Sphinx reports kernel-doc warning: WARNING: ./net/bridge/br_private.h:267 struct member 'tunnel_hash' not described in 'net_bridge_vlan_group' Fix it by describing @tunnel_hash member. Fixes: efa5356b0d9753 ("bridge: per vlan dst_metadata netlink support") Signed-off-by: Bagas Sanjaya Acked-by: Nikolay Aleksandrov Reviewed-by: Ido Schimmel Link: https://patch.msgid.link/20251218042936.24175-2-bagasdotme@gmail.com Signed-off-by: Paolo Abeni Signed-off-by: Sasha Levin --- net/bridge/br_private.h | 1 + 1 file changed, 1 insertion(+) diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index 7280c4e9305f3..b9b2981c48414 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -247,6 +247,7 @@ struct net_bridge_vlan { * struct net_bridge_vlan_group * * @vlan_hash: VLAN entry rhashtable + * @tunnel_hash: Hash table to map from tunnel key ID (e.g. VXLAN VNI) to VLAN * @vlan_list: sorted VLAN entry list * @num_vlans: number of total VLAN entries * @pvid: PVID VLAN id From 4904161220d4869298ca2754d2c82ff6677825ed Mon Sep 17 00:00:00 2001 From: Kohei Enju Date: Fri, 26 Dec 2025 17:46:49 +0900 Subject: [PATCH 1500/2333] tools/sched_ext: fix scx_show_state.py for scx_root change [ Upstream commit f92ff79ba2640fc482bf2bfb5b42e33957f90caf ] Commit 48e126777386 ("sched_ext: Introduce scx_sched") introduced scx_root and removed scx_ops, causing scx_show_state.py to fail when searching for the 'scx_ops' object. [1] Fix by using 'scx_root' instead, with NULL pointer handling. [1] # drgn -s vmlinux ./tools/sched_ext/scx_show_state.py Traceback (most recent call last): File "/root/.venv/bin/drgn", line 8, in sys.exit(_main()) ~~~~~^^ File "/root/.venv/lib64/python3.14/site-packages/drgn/cli.py", line 625, in _main runpy.run_path( ~~~~~~~~~~~~~~^ script_path, init_globals={"prog": prog}, run_name="__main__" ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ) ^ File "", line 287, in run_path File "", line 98, in _run_module_code File "", line 88, in _run_code File "./tools/sched_ext/scx_show_state.py", line 30, in ops = prog['scx_ops'] ~~~~^^^^^^^^^^^ _drgn.ObjectNotFoundError: could not find 'scx_ops' Fixes: 48e126777386 ("sched_ext: Introduce scx_sched") Signed-off-by: Kohei Enju Reviewed-by: Emil Tsalapatis Signed-off-by: Tejun Heo Signed-off-by: Sasha Levin --- tools/sched_ext/scx_show_state.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tools/sched_ext/scx_show_state.py b/tools/sched_ext/scx_show_state.py index 7cdcc6729ea4e..aec4a4498140f 100644 --- a/tools/sched_ext/scx_show_state.py +++ b/tools/sched_ext/scx_show_state.py @@ -27,10 +27,13 @@ def read_static_key(name): def state_str(state): return prog['scx_enable_state_str'][state].string_().decode() -ops = prog['scx_ops'] +root = prog['scx_root'] enable_state = read_atomic("scx_enable_state_var") -print(f'ops : {ops.name.string_().decode()}') +if root: + print(f'ops : {root.ops.name.string_().decode()}') +else: + print('ops : ') print(f'enabled : {read_static_key("__scx_enabled")}') print(f'switching_all : {read_int("scx_switching_all")}') print(f'switched_all : {read_static_key("__scx_switched_all")}') From fe9339b33e2b28d88946bacae7baaf24d467783a Mon Sep 17 00:00:00 2001 From: Zilin Guan Date: Thu, 25 Dec 2025 14:31:50 +0000 Subject: [PATCH 1501/2333] vfio/pds: Fix memory leak in pds_vfio_dirty_enable() [ Upstream commit 665077d78dc7941ce6a330c02023a2b469cc8cc7 ] pds_vfio_dirty_enable() allocates memory for region_info. If interval_tree_iter_first() returns NULL, the function returns -EINVAL immediately without freeing the allocated memory, causing a memory leak. Fix this by jumping to the out_free_region_info label to ensure region_info is freed. Fixes: 2e7c6feb4ef52 ("vfio/pds: Add multi-region support") Signed-off-by: Zilin Guan Link: https://lore.kernel.org/r/20251225143150.1117366-1-zilin@seu.edu.cn Signed-off-by: Alex Williamson Signed-off-by: Sasha Levin --- drivers/vfio/pci/pds/dirty.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/vfio/pci/pds/dirty.c b/drivers/vfio/pci/pds/dirty.c index 481992142f790..4915a7c1c4916 100644 --- a/drivers/vfio/pci/pds/dirty.c +++ b/drivers/vfio/pci/pds/dirty.c @@ -292,8 +292,11 @@ static int pds_vfio_dirty_enable(struct pds_vfio_pci_device *pds_vfio, len = num_ranges * sizeof(*region_info); node = interval_tree_iter_first(ranges, 0, ULONG_MAX); - if (!node) - return -EINVAL; + if (!node) { + err = -EINVAL; + goto out_free_region_info; + } + for (int i = 0; i < num_ranges; i++) { struct pds_lm_dirty_region_info *ri = ®ion_info[i]; u64 region_size = node->last - node->start + 1; From 79cab730dbaaac03b946c7f5681bd08c986e2abd Mon Sep 17 00:00:00 2001 From: Junrui Luo Date: Fri, 26 Dec 2025 19:42:05 +0800 Subject: [PATCH 1502/2333] platform/x86: hp-bioscfg: Fix out-of-bounds array access in ACPI package parsing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit e44c42c830b7ab36e3a3a86321c619f24def5206 ] The hp_populate_*_elements_from_package() functions in the hp-bioscfg driver contain out-of-bounds array access vulnerabilities. These functions parse ACPI packages into internal data structures using a for loop with index variable 'elem' that iterates through enum_obj/integer_obj/order_obj/password_obj/string_obj arrays. When processing multi-element fields like PREREQUISITES and ENUM_POSSIBLE_VALUES, these functions read multiple consecutive array elements using expressions like 'enum_obj[elem + reqs]' and 'enum_obj[elem + pos_values]' within nested loops. The bug is that the bounds check only validated elem, but did not consider the additional offset when accessing elem + reqs or elem + pos_values. The fix changes the bounds check to validate the actual accessed index. Reported-by: Yuhao Jiang Reported-by: Junrui Luo Fixes: e6c7b3e15559 ("platform/x86: hp-bioscfg: string-attributes") Signed-off-by: Junrui Luo Link: https://patch.msgid.link/SYBPR01MB788173D7DD4EA2CB6383683DAFB0A@SYBPR01MB7881.ausprd01.prod.outlook.com Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen Signed-off-by: Sasha Levin --- drivers/platform/x86/hp/hp-bioscfg/enum-attributes.c | 4 ++-- drivers/platform/x86/hp/hp-bioscfg/int-attributes.c | 2 +- drivers/platform/x86/hp/hp-bioscfg/order-list-attributes.c | 5 +++++ drivers/platform/x86/hp/hp-bioscfg/passwdobj-attributes.c | 5 +++++ drivers/platform/x86/hp/hp-bioscfg/string-attributes.c | 2 +- 5 files changed, 14 insertions(+), 4 deletions(-) diff --git a/drivers/platform/x86/hp/hp-bioscfg/enum-attributes.c b/drivers/platform/x86/hp/hp-bioscfg/enum-attributes.c index c50ad58805038..f346aad8e9d89 100644 --- a/drivers/platform/x86/hp/hp-bioscfg/enum-attributes.c +++ b/drivers/platform/x86/hp/hp-bioscfg/enum-attributes.c @@ -207,7 +207,7 @@ static int hp_populate_enumeration_elements_from_package(union acpi_object *enum case PREREQUISITES: size = min_t(u32, enum_data->common.prerequisites_size, MAX_PREREQUISITES_SIZE); for (reqs = 0; reqs < size; reqs++) { - if (elem >= enum_obj_count) { + if (elem + reqs >= enum_obj_count) { pr_err("Error enum-objects package is too small\n"); return -EINVAL; } @@ -255,7 +255,7 @@ static int hp_populate_enumeration_elements_from_package(union acpi_object *enum for (pos_values = 0; pos_values < size && pos_values < MAX_VALUES_SIZE; pos_values++) { - if (elem >= enum_obj_count) { + if (elem + pos_values >= enum_obj_count) { pr_err("Error enum-objects package is too small\n"); return -EINVAL; } diff --git a/drivers/platform/x86/hp/hp-bioscfg/int-attributes.c b/drivers/platform/x86/hp/hp-bioscfg/int-attributes.c index 6c7f4d5fa9cb9..63b1fda2be4e2 100644 --- a/drivers/platform/x86/hp/hp-bioscfg/int-attributes.c +++ b/drivers/platform/x86/hp/hp-bioscfg/int-attributes.c @@ -227,7 +227,7 @@ static int hp_populate_integer_elements_from_package(union acpi_object *integer_ size = min_t(u32, integer_data->common.prerequisites_size, MAX_PREREQUISITES_SIZE); for (reqs = 0; reqs < size; reqs++) { - if (elem >= integer_obj_count) { + if (elem + reqs >= integer_obj_count) { pr_err("Error elem-objects package is too small\n"); return -EINVAL; } diff --git a/drivers/platform/x86/hp/hp-bioscfg/order-list-attributes.c b/drivers/platform/x86/hp/hp-bioscfg/order-list-attributes.c index c6e57bb9d8b74..6a31f47ce3f5b 100644 --- a/drivers/platform/x86/hp/hp-bioscfg/order-list-attributes.c +++ b/drivers/platform/x86/hp/hp-bioscfg/order-list-attributes.c @@ -216,6 +216,11 @@ static int hp_populate_ordered_list_elements_from_package(union acpi_object *ord size = min_t(u32, ordered_list_data->common.prerequisites_size, MAX_PREREQUISITES_SIZE); for (reqs = 0; reqs < size; reqs++) { + if (elem + reqs >= order_obj_count) { + pr_err("Error elem-objects package is too small\n"); + return -EINVAL; + } + ret = hp_convert_hexstr_to_str(order_obj[elem + reqs].string.pointer, order_obj[elem + reqs].string.length, &str_value, &value_len); diff --git a/drivers/platform/x86/hp/hp-bioscfg/passwdobj-attributes.c b/drivers/platform/x86/hp/hp-bioscfg/passwdobj-attributes.c index 187b372123ed3..ec79d9d50377a 100644 --- a/drivers/platform/x86/hp/hp-bioscfg/passwdobj-attributes.c +++ b/drivers/platform/x86/hp/hp-bioscfg/passwdobj-attributes.c @@ -303,6 +303,11 @@ static int hp_populate_password_elements_from_package(union acpi_object *passwor MAX_PREREQUISITES_SIZE); for (reqs = 0; reqs < size; reqs++) { + if (elem + reqs >= password_obj_count) { + pr_err("Error elem-objects package is too small\n"); + return -EINVAL; + } + ret = hp_convert_hexstr_to_str(password_obj[elem + reqs].string.pointer, password_obj[elem + reqs].string.length, &str_value, &value_len); diff --git a/drivers/platform/x86/hp/hp-bioscfg/string-attributes.c b/drivers/platform/x86/hp/hp-bioscfg/string-attributes.c index 27758b779b2d3..7b885d25650c5 100644 --- a/drivers/platform/x86/hp/hp-bioscfg/string-attributes.c +++ b/drivers/platform/x86/hp/hp-bioscfg/string-attributes.c @@ -217,7 +217,7 @@ static int hp_populate_string_elements_from_package(union acpi_object *string_ob MAX_PREREQUISITES_SIZE); for (reqs = 0; reqs < size; reqs++) { - if (elem >= string_obj_count) { + if (elem + reqs >= string_obj_count) { pr_err("Error elem-objects package is too small\n"); return -EINVAL; } From 7f18ebf8c455f9b51a2e58c62f98310357069ada Mon Sep 17 00:00:00 2001 From: Alok Tiwari Date: Wed, 24 Dec 2025 01:51:09 -0800 Subject: [PATCH 1503/2333] platform/x86/intel/pmt/discovery: use valid device pointer in dev_err_probe MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 66e245db16f0175af656cd812b6dc1a5e1f7b80a ] The PMT feature probe creates a child device with device_create(). If device creation fail, the code pass priv->dev (which is an ERR_PTR) to dev_err_probe(), which is not a valid device pointer. This patch change the dev_err_probe() call to use the parent auxiliary device (&auxdev->dev) and update the error message to reference the parent device name. It ensure correct error reporting and avoid passing an invalid device pointer. Fixes: d9a078809356 ("platform/x86/intel/pmt: Add PMT Discovery driver") Signed-off-by: Alok Tiwari Link: https://patch.msgid.link/20251224095133.115678-1-alok.a.tiwari@oracle.com Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen Signed-off-by: Sasha Levin --- drivers/platform/x86/intel/pmt/discovery.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/platform/x86/intel/pmt/discovery.c b/drivers/platform/x86/intel/pmt/discovery.c index 9c5b4d0e1fae6..e500aa327d237 100644 --- a/drivers/platform/x86/intel/pmt/discovery.c +++ b/drivers/platform/x86/intel/pmt/discovery.c @@ -548,9 +548,9 @@ static int pmt_features_probe(struct auxiliary_device *auxdev, const struct auxi priv->dev = device_create(&intel_pmt_class, &auxdev->dev, MKDEV(0, 0), priv, "%s-%s", "features", dev_name(priv->parent)); if (IS_ERR(priv->dev)) - return dev_err_probe(priv->dev, PTR_ERR(priv->dev), + return dev_err_probe(&auxdev->dev, PTR_ERR(priv->dev), "Could not create %s-%s device node\n", - "features", dev_name(priv->dev)); + "features", dev_name(priv->parent)); /* Initialize each feature */ for (i = 0; i < ivdev->num_resources; i++) { From 442848e457f5a9f71a4e7e14d24d73dae278ebe3 Mon Sep 17 00:00:00 2001 From: Anshumali Gaur Date: Fri, 19 Dec 2025 11:52:26 +0530 Subject: [PATCH 1504/2333] octeontx2-pf: fix "UBSAN: shift-out-of-bounds error" [ Upstream commit 85f4b0c650d9f9db10bda8d3acfa1af83bf78cf7 ] This patch ensures that the RX ring size (rx_pending) is not set below the permitted length. This avoids UBSAN shift-out-of-bounds errors when users passes small or zero ring sizes via ethtool -G. Fixes: d45d8979840d ("octeontx2-pf: Add basic ethtool support") Signed-off-by: Anshumali Gaur Link: https://patch.msgid.link/20251219062226.524844-1-agaur@marvell.com Signed-off-by: Paolo Abeni Signed-off-by: Sasha Levin --- drivers/net/ethernet/marvell/octeontx2/nic/otx2_ethtool.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_ethtool.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_ethtool.c index b90e23dc49de9..b6449f0a9e7dd 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_ethtool.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_ethtool.c @@ -418,6 +418,14 @@ static int otx2_set_ringparam(struct net_device *netdev, */ if (rx_count < pfvf->hw.rq_skid) rx_count = pfvf->hw.rq_skid; + + if (ring->rx_pending < 16) { + netdev_err(netdev, + "rx ring size %u invalid, min is 16\n", + ring->rx_pending); + return -EINVAL; + } + rx_count = Q_COUNT(Q_SIZE(rx_count, 3)); /* Due pipelining impact minimum 2000 unused SQ CQE's From 5e5988736a95b1de7f91b10ac2575454b70e4897 Mon Sep 17 00:00:00 2001 From: Wei Fang Date: Thu, 4 Dec 2025 15:13:32 +0800 Subject: [PATCH 1505/2333] net: stmmac: fix the crash issue for zero copy XDP_TX action [ Upstream commit a48e232210009be50591fdea8ba7c07b0f566a13 ] There is a crash issue when running zero copy XDP_TX action, the crash log is shown below. [ 216.122464] Unable to handle kernel paging request at virtual address fffeffff80000000 [ 216.187524] Internal error: Oops: 0000000096000144 [#1] SMP [ 216.301694] Call trace: [ 216.304130] dcache_clean_poc+0x20/0x38 (P) [ 216.308308] __dma_sync_single_for_device+0x1bc/0x1e0 [ 216.313351] stmmac_xdp_xmit_xdpf+0x354/0x400 [ 216.317701] __stmmac_xdp_run_prog+0x164/0x368 [ 216.322139] stmmac_napi_poll_rxtx+0xba8/0xf00 [ 216.326576] __napi_poll+0x40/0x218 [ 216.408054] Kernel panic - not syncing: Oops: Fatal exception in interrupt For XDP_TX action, the xdp_buff is converted to xdp_frame by xdp_convert_buff_to_frame(). The memory type of the resulting xdp_frame depends on the memory type of the xdp_buff. For page pool based xdp_buff it produces xdp_frame with memory type MEM_TYPE_PAGE_POOL. For zero copy XSK pool based xdp_buff it produces xdp_frame with memory type MEM_TYPE_PAGE_ORDER0. However, stmmac_xdp_xmit_back() does not check the memory type and always uses the page pool type, this leads to invalid mappings and causes the crash. Therefore, check the xdp_buff memory type in stmmac_xdp_xmit_back() to fix this issue. Fixes: bba2556efad6 ("net: stmmac: Enable RX via AF_XDP zero-copy") Signed-off-by: Wei Fang Reviewed-by: Hariprasad Kelam Link: https://patch.msgid.link/20251204071332.1907111-1-wei.fang@nxp.com Signed-off-by: Paolo Abeni Signed-off-by: Sasha Levin --- .../net/ethernet/stmicro/stmmac/stmmac_main.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 86e912471dead..0dd17179c85d2 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -88,6 +88,7 @@ MODULE_PARM_DESC(phyaddr, "Physical device address"); #define STMMAC_XDP_CONSUMED BIT(0) #define STMMAC_XDP_TX BIT(1) #define STMMAC_XDP_REDIRECT BIT(2) +#define STMMAC_XSK_CONSUMED BIT(3) static int flow_ctrl = 0xdead; module_param(flow_ctrl, int, 0644); @@ -4988,6 +4989,7 @@ static int stmmac_xdp_get_tx_queue(struct stmmac_priv *priv, static int stmmac_xdp_xmit_back(struct stmmac_priv *priv, struct xdp_buff *xdp) { + bool zc = !!(xdp->rxq->mem.type == MEM_TYPE_XSK_BUFF_POOL); struct xdp_frame *xdpf = xdp_convert_buff_to_frame(xdp); int cpu = smp_processor_id(); struct netdev_queue *nq; @@ -5004,9 +5006,18 @@ static int stmmac_xdp_xmit_back(struct stmmac_priv *priv, /* Avoids TX time-out as we are sharing with slow path */ txq_trans_cond_update(nq); - res = stmmac_xdp_xmit_xdpf(priv, queue, xdpf, false); - if (res == STMMAC_XDP_TX) + /* For zero copy XDP_TX action, dma_map is true */ + res = stmmac_xdp_xmit_xdpf(priv, queue, xdpf, zc); + if (res == STMMAC_XDP_TX) { stmmac_flush_tx_descriptors(priv, queue); + } else if (res == STMMAC_XDP_CONSUMED && zc) { + /* xdp has been freed by xdp_convert_buff_to_frame(), + * no need to call xsk_buff_free() again, so return + * STMMAC_XSK_CONSUMED. + */ + res = STMMAC_XSK_CONSUMED; + xdp_return_frame(xdpf); + } __netif_tx_unlock(nq); @@ -5356,6 +5367,8 @@ static int stmmac_rx_zc(struct stmmac_priv *priv, int limit, u32 queue) break; case STMMAC_XDP_CONSUMED: xsk_buff_free(buf->xdp); + fallthrough; + case STMMAC_XSK_CONSUMED: rx_dropped++; break; case STMMAC_XDP_TX: From 73744ad5696dce0e0f43872aba8de6a83d6ad570 Mon Sep 17 00:00:00 2001 From: Will Rosenberg Date: Fri, 19 Dec 2025 10:36:37 -0700 Subject: [PATCH 1506/2333] ipv6: BUG() in pskb_expand_head() as part of calipso_skbuff_setattr() [ Upstream commit 58fc7342b529803d3c221101102fe913df7adb83 ] There exists a kernel oops caused by a BUG_ON(nhead < 0) at net/core/skbuff.c:2232 in pskb_expand_head(). This bug is triggered as part of the calipso_skbuff_setattr() routine when skb_cow() is passed headroom > INT_MAX (i.e. (int)(skb_headroom(skb) + len_delta) < 0). The root cause of the bug is due to an implicit integer cast in __skb_cow(). The check (headroom > skb_headroom(skb)) is meant to ensure that delta = headroom - skb_headroom(skb) is never negative, otherwise we will trigger a BUG_ON in pskb_expand_head(). However, if headroom > INT_MAX and delta <= -NET_SKB_PAD, the check passes, delta becomes negative, and pskb_expand_head() is passed a negative value for nhead. Fix the trigger condition in calipso_skbuff_setattr(). Avoid passing "negative" headroom sizes to skb_cow() within calipso_skbuff_setattr() by only using skb_cow() to grow headroom. PoC: Using `netlabelctl` tool: netlabelctl map del default netlabelctl calipso add pass doi:7 netlabelctl map add default address:0::1/128 protocol:calipso,7 Then run the following PoC: int fd = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); // setup msghdr int cmsg_size = 2; int cmsg_len = 0x60; struct msghdr msg; struct sockaddr_in6 dest_addr; struct cmsghdr * cmsg = (struct cmsghdr *) calloc(1, sizeof(struct cmsghdr) + cmsg_len); msg.msg_name = &dest_addr; msg.msg_namelen = sizeof(dest_addr); msg.msg_iov = NULL; msg.msg_iovlen = 0; msg.msg_control = cmsg; msg.msg_controllen = cmsg_len; msg.msg_flags = 0; // setup sockaddr dest_addr.sin6_family = AF_INET6; dest_addr.sin6_port = htons(31337); dest_addr.sin6_flowinfo = htonl(31337); dest_addr.sin6_addr = in6addr_loopback; dest_addr.sin6_scope_id = 31337; // setup cmsghdr cmsg->cmsg_len = cmsg_len; cmsg->cmsg_level = IPPROTO_IPV6; cmsg->cmsg_type = IPV6_HOPOPTS; char * hop_hdr = (char *)cmsg + sizeof(struct cmsghdr); hop_hdr[1] = 0x9; //set hop size - (0x9 + 1) * 8 = 80 sendmsg(fd, &msg, 0); Fixes: 2917f57b6bc1 ("calipso: Allow the lsm to label the skbuff directly.") Suggested-by: Paul Moore Signed-off-by: Will Rosenberg Acked-by: Paul Moore Link: https://patch.msgid.link/20251219173637.797418-1-whrosenb@asu.edu Signed-off-by: Paolo Abeni Signed-off-by: Sasha Levin --- net/ipv6/calipso.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/ipv6/calipso.c b/net/ipv6/calipso.c index df1986973430c..21f6ed126253a 100644 --- a/net/ipv6/calipso.c +++ b/net/ipv6/calipso.c @@ -1342,7 +1342,8 @@ static int calipso_skbuff_setattr(struct sk_buff *skb, /* At this point new_end aligns to 4n, so (new_end & 4) pads to 8n */ pad = ((new_end & 4) + (end & 7)) & 7; len_delta = new_end - (int)end + pad; - ret_val = skb_cow(skb, skb_headroom(skb) + len_delta); + ret_val = skb_cow(skb, + skb_headroom(skb) + (len_delta > 0 ? len_delta : 0)); if (ret_val < 0) return ret_val; From e3fc381320d04e4a74311e576a86cac49a16fc43 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Sun, 21 Dec 2025 16:48:28 +0200 Subject: [PATCH 1507/2333] ipv4: Fix reference count leak when using error routes with nexthop objects [ Upstream commit ac782f4e3bfcde145b8a7f8af31d9422d94d172a ] When a nexthop object is deleted, it is marked as dead and then fib_table_flush() is called to flush all the routes that are using the dead nexthop. The current logic in fib_table_flush() is to only flush error routes (e.g., blackhole) when it is called as part of network namespace dismantle (i.e., with flush_all=true). Therefore, error routes are not flushed when their nexthop object is deleted: # ip link add name dummy1 up type dummy # ip nexthop add id 1 dev dummy1 # ip route add 198.51.100.1/32 nhid 1 # ip route add blackhole 198.51.100.2/32 nhid 1 # ip nexthop del id 1 # ip route show blackhole 198.51.100.2 nhid 1 dev dummy1 As such, they keep holding a reference on the nexthop object which in turn holds a reference on the nexthop device, resulting in a reference count leak: # ip link del dev dummy1 [ 70.516258] unregister_netdevice: waiting for dummy1 to become free. Usage count = 2 Fix by flushing error routes when their nexthop is marked as dead. IPv6 does not suffer from this problem. Fixes: 493ced1ac47c ("ipv4: Allow routes to use nexthop objects") Reported-by: Tetsuo Handa Closes: https://lore.kernel.org/netdev/d943f806-4da6-4970-ac28-b9373b0e63ac@I-love.SAKURA.ne.jp/ Reported-by: syzbot+881d65229ca4f9ae8c84@syzkaller.appspotmail.com Signed-off-by: Ido Schimmel Reviewed-by: David Ahern Link: https://patch.msgid.link/20251221144829.197694-1-idosch@nvidia.com Signed-off-by: Paolo Abeni Signed-off-by: Sasha Levin --- net/ipv4/fib_trie.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index 59a6f0a9638f9..7e2c17fec3fc4 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c @@ -2053,10 +2053,11 @@ int fib_table_flush(struct net *net, struct fib_table *tb, bool flush_all) continue; } - /* Do not flush error routes if network namespace is - * not being dismantled + /* When not flushing the entire table, skip error + * routes that are not marked for deletion. */ - if (!flush_all && fib_props[fa->fa_type].error) { + if (!flush_all && fib_props[fa->fa_type].error && + !(fi->fib_flags & RTNH_F_DEAD)) { slen = fa->fa_slen; continue; } From ffd335167d7edc171380546a0f204d4c680d690d Mon Sep 17 00:00:00 2001 From: Vadim Fedorenko Date: Sun, 21 Dec 2025 19:26:38 +0000 Subject: [PATCH 1508/2333] net: fib: restore ECMP balance from loopback [ Upstream commit 6e17474aa9fe15015c9921a5081c7ca71783aac6 ] Preference of nexthop with source address broke ECMP for packets with source addresses which are not in the broadcast domain, but rather added to loopback/dummy interfaces. Original behaviour was to balance over nexthops while now it uses the latest nexthop from the group. To fix the issue introduce next hop scoring system where next hops with source address equal to requested will always have higher priority. For the case with 198.51.100.1/32 assigned to dummy0 and routed using 192.0.2.0/24 and 203.0.113.0/24 networks: 2: dummy0: mtu 1500 qdisc noqueue state UNKNOWN group default qlen 1000 link/ether d6:54:8a:ff:78:f5 brd ff:ff:ff:ff:ff:ff inet 198.51.100.1/32 scope global dummy0 valid_lft forever preferred_lft forever 7: veth1@if6: mtu 1500 qdisc noqueue state UP group default qlen 1000 link/ether 06:ed:98:87:6d:8a brd ff:ff:ff:ff:ff:ff link-netnsid 0 inet 192.0.2.2/24 scope global veth1 valid_lft forever preferred_lft forever inet6 fe80::4ed:98ff:fe87:6d8a/64 scope link proto kernel_ll valid_lft forever preferred_lft forever 9: veth3@if8: mtu 1500 qdisc noqueue state UP group default qlen 1000 link/ether ae:75:23:38:a0:d2 brd ff:ff:ff:ff:ff:ff link-netnsid 0 inet 203.0.113.2/24 scope global veth3 valid_lft forever preferred_lft forever inet6 fe80::ac75:23ff:fe38:a0d2/64 scope link proto kernel_ll valid_lft forever preferred_lft forever ~ ip ro list: default nexthop via 192.0.2.1 dev veth1 weight 1 nexthop via 203.0.113.1 dev veth3 weight 1 192.0.2.0/24 dev veth1 proto kernel scope link src 192.0.2.2 203.0.113.0/24 dev veth3 proto kernel scope link src 203.0.113.2 before: for i in {1..255} ; do ip ro get 10.0.0.$i; done | grep veth | awk ' {print $(NF-2)}' | sort | uniq -c: 255 veth3 after: for i in {1..255} ; do ip ro get 10.0.0.$i; done | grep veth | awk ' {print $(NF-2)}' | sort | uniq -c: 122 veth1 133 veth3 Fixes: 32607a332cfe ("ipv4: prefer multipath nexthop that matches source address") Signed-off-by: Vadim Fedorenko Reviewed-by: Ido Schimmel Reviewed-by: Willem de Bruijn Link: https://patch.msgid.link/20251221192639.3911901-1-vadim.fedorenko@linux.dev Signed-off-by: Paolo Abeni Signed-off-by: Sasha Levin --- net/ipv4/fib_semantics.c | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c index a5f3c8459758f..0caf38e44c738 100644 --- a/net/ipv4/fib_semantics.c +++ b/net/ipv4/fib_semantics.c @@ -2167,8 +2167,8 @@ void fib_select_multipath(struct fib_result *res, int hash, { struct fib_info *fi = res->fi; struct net *net = fi->fib_net; - bool found = false; bool use_neigh; + int score = -1; __be32 saddr; if (unlikely(res->fi->nh)) { @@ -2180,7 +2180,7 @@ void fib_select_multipath(struct fib_result *res, int hash, saddr = fl4 ? fl4->saddr : 0; change_nexthops(fi) { - int nh_upper_bound; + int nh_upper_bound, nh_score = 0; /* Nexthops without a carrier are assigned an upper bound of * minus one when "ignore_routes_with_linkdown" is set. @@ -2190,24 +2190,18 @@ void fib_select_multipath(struct fib_result *res, int hash, (use_neigh && !fib_good_nh(nexthop_nh))) continue; - if (!found) { + if (saddr && nexthop_nh->nh_saddr == saddr) + nh_score += 2; + if (hash <= nh_upper_bound) + nh_score++; + if (score < nh_score) { res->nh_sel = nhsel; res->nhc = &nexthop_nh->nh_common; - found = !saddr || nexthop_nh->nh_saddr == saddr; + if (nh_score == 3 || (!saddr && nh_score == 1)) + return; + score = nh_score; } - if (hash > nh_upper_bound) - continue; - - if (!saddr || nexthop_nh->nh_saddr == saddr) { - res->nh_sel = nhsel; - res->nhc = &nexthop_nh->nh_common; - return; - } - - if (found) - return; - } endfor_nexthops(fi); } #endif From 92d900aac3a5721fb54f3328f1e089b44a861c38 Mon Sep 17 00:00:00 2001 From: Pwnverse Date: Mon, 22 Dec 2025 21:22:27 +0000 Subject: [PATCH 1509/2333] net: rose: fix invalid array index in rose_kill_by_device() [ Upstream commit 6595beb40fb0ec47223d3f6058ee40354694c8e4 ] rose_kill_by_device() collects sockets into a local array[] and then iterates over them to disconnect sockets bound to a device being brought down. The loop mistakenly indexes array[cnt] instead of array[i]. For cnt < ARRAY_SIZE(array), this reads an uninitialized entry; for cnt == ARRAY_SIZE(array), it is an out-of-bounds read. Either case can lead to an invalid socket pointer dereference and also leaks references taken via sock_hold(). Fix the index to use i. Fixes: 64b8bc7d5f143 ("net/rose: fix races in rose_kill_by_device()") Co-developed-by: Fatma Alwasmi Signed-off-by: Fatma Alwasmi Signed-off-by: Pwnverse Link: https://patch.msgid.link/20251222212227.4116041-1-ritviktanksalkar@gmail.com Signed-off-by: Paolo Abeni Signed-off-by: Sasha Levin --- net/rose/af_rose.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c index 543f9e8ebb693..fad6518e6e39b 100644 --- a/net/rose/af_rose.c +++ b/net/rose/af_rose.c @@ -205,7 +205,7 @@ static void rose_kill_by_device(struct net_device *dev) spin_unlock_bh(&rose_list_lock); for (i = 0; i < cnt; i++) { - sk = array[cnt]; + sk = array[i]; rose = rose_sk(sk); lock_sock(sk); spin_lock_bh(&rose_list_lock); From 787515ccb2292f82eb0876993129154629a49651 Mon Sep 17 00:00:00 2001 From: Jiayuan Chen Date: Tue, 23 Dec 2025 13:14:12 +0800 Subject: [PATCH 1510/2333] ipv6: fix a BUG in rt6_get_pcpu_route() under PREEMPT_RT [ Upstream commit 1adaea51c61b52e24e7ab38f7d3eba023b2d050d ] On PREEMPT_RT kernels, after rt6_get_pcpu_route() returns NULL, the current task can be preempted. Another task running on the same CPU may then execute rt6_make_pcpu_route() and successfully install a pcpu_rt entry. When the first task resumes execution, its cmpxchg() in rt6_make_pcpu_route() will fail because rt6i_pcpu is no longer NULL, triggering the BUG_ON(prev). It's easy to reproduce it by adding mdelay() after rt6_get_pcpu_route(). Using preempt_disable/enable is not appropriate here because ip6_rt_pcpu_alloc() may sleep. Fix this by handling the cmpxchg() failure gracefully on PREEMPT_RT: free our allocation and return the existing pcpu_rt installed by another task. The BUG_ON is replaced by WARN_ON_ONCE for non-PREEMPT_RT kernels where such races should not occur. Link: https://syzkaller.appspot.com/bug?extid=9b35e9bc0951140d13e6 Fixes: d2d6422f8bd1 ("x86: Allow to enable PREEMPT_RT.") Reported-by: syzbot+9b35e9bc0951140d13e6@syzkaller.appspotmail.com Closes: https://lore.kernel.org/all/6918cd88.050a0220.1c914e.0045.GAE@google.com/T/ Signed-off-by: Jiayuan Chen Link: https://patch.msgid.link/20251223051413.124687-1-jiayuan.chen@linux.dev Signed-off-by: Paolo Abeni Signed-off-by: Sasha Levin --- net/ipv6/route.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/net/ipv6/route.c b/net/ipv6/route.c index aee6a10b112aa..a3e051dc66ee0 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -1470,7 +1470,18 @@ static struct rt6_info *rt6_make_pcpu_route(struct net *net, p = this_cpu_ptr(res->nh->rt6i_pcpu); prev = cmpxchg(p, NULL, pcpu_rt); - BUG_ON(prev); + if (unlikely(prev)) { + /* + * Another task on this CPU already installed a pcpu_rt. + * This can happen on PREEMPT_RT where preemption is possible. + * Free our allocation and return the existing one. + */ + WARN_ON_ONCE(!IS_ENABLED(CONFIG_PREEMPT_RT)); + + dst_dev_put(&pcpu_rt->dst); + dst_release(&pcpu_rt->dst); + return prev; + } if (res->f6i->fib6_destroying) { struct fib6_info *from; From 263255a62cea53699aa52cd033fcf765513f815f Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 8 Dec 2025 14:33:05 +0100 Subject: [PATCH 1511/2333] RDMA/ucma: Fix rdma_ucm_query_ib_service_resp struct padding [ Upstream commit 2dc675f614850b80deab7cf6d12902636ed8a7f4 ] On a few 32-bit architectures, the newly added ib_user_service_rec structure is not 64-bit aligned the way it is on most regular ones. Add explicit padding into the rdma_ucm_query_ib_service_resp and rdma_ucm_resolve_ib_service structures that embed it, so that the layout is compatible across all of them. This is an ABI change on i386, aligning it with x86_64 and the other 64-bit architectures to avoid having to use a compat ioctl handler. Fixes: 810f874eda8e ("RDMA/ucma: Support query resolved service records") Link: https://patch.msgid.link/r/20251208133311.313977-1-arnd@kernel.org Signed-off-by: Arnd Bergmann Signed-off-by: Jason Gunthorpe Signed-off-by: Sasha Levin --- include/uapi/rdma/rdma_user_cm.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/uapi/rdma/rdma_user_cm.h b/include/uapi/rdma/rdma_user_cm.h index 5ded174687ee0..838f8d4602560 100644 --- a/include/uapi/rdma/rdma_user_cm.h +++ b/include/uapi/rdma/rdma_user_cm.h @@ -192,6 +192,7 @@ struct rdma_ucm_query_path_resp { struct rdma_ucm_query_ib_service_resp { __u32 num_service_recs; + __u32 reserved; struct ib_user_service_rec recs[]; }; @@ -354,7 +355,7 @@ enum { #define RDMA_USER_CM_IB_SERVICE_NAME_SIZE 64 struct rdma_ucm_ib_service { - __u64 service_id; + __aligned_u64 service_id; __u8 service_name[RDMA_USER_CM_IB_SERVICE_NAME_SIZE]; __u32 flags; __u32 reserved; @@ -362,6 +363,7 @@ struct rdma_ucm_ib_service { struct rdma_ucm_resolve_ib_service { __u32 id; + __u32 reserved; struct rdma_ucm_ib_service ibs; }; From 20710399c9b5ef80e21d13fa0138b1370e358c8f Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 8 Dec 2025 14:38:44 +0100 Subject: [PATCH 1512/2333] RDMA/irdma: Fix irdma_alloc_ucontext_resp padding [ Upstream commit d95e99a74eaf35c070f5939295331e5d7857c723 ] A recent commit modified struct irdma_alloc_ucontext_resp by adding a member with implicit padding in front of it, though this does not change the offset of the data members other than m68k. Reported by scripts/check-uapi.sh: ==== ABI differences detected in include/rdma/irdma-abi.h from 1dd7bde2e91c -> HEAD ==== [C] 'struct irdma_alloc_ucontext_resp' changed: type size changed from 704 to 640 (in bits) 1 data member deletion: '__u8 rsvd3[2]', at offset 640 (in bits) at irdma-abi.h:61:1 1 data member insertion: '__u8 revd3[2]', at offset 592 (in bits) at irdma-abi.h:60:1 Change the size back to the previous version, and remove the implicit padding by making it explicit and matching what x86-64 would do by placing max_hw_srq_quanta member into a naturally aligned location. Fixes: 563e1feb5f6e ("RDMA/irdma: Add SRQ support") Link: https://patch.msgid.link/r/20251208133849.315451-1-arnd@kernel.org Signed-off-by: Arnd Bergmann Reviewed-by: Geert Uytterhoeven Tested-by: Jacob Moroni Signed-off-by: Jason Gunthorpe Signed-off-by: Sasha Levin --- include/uapi/rdma/irdma-abi.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/uapi/rdma/irdma-abi.h b/include/uapi/rdma/irdma-abi.h index f7788d33376b8..36f20802bcc84 100644 --- a/include/uapi/rdma/irdma-abi.h +++ b/include/uapi/rdma/irdma-abi.h @@ -57,8 +57,8 @@ struct irdma_alloc_ucontext_resp { __u8 rsvd2; __aligned_u64 comp_mask; __u16 min_hw_wq_size; + __u8 revd3[2]; __u32 max_hw_srq_quanta; - __u8 rsvd3[2]; }; struct irdma_alloc_pd_resp { From 94dda131004e7218b465ac95c52dd6eeee5cd6be Mon Sep 17 00:00:00 2001 From: Konstantin Taranov Date: Thu, 23 Oct 2025 03:03:00 -0700 Subject: [PATCH 1513/2333] RDMA/mana_ib: check cqe length for kernel CQs [ Upstream commit 887bfe5986396aca908b7afd2d214471ba7d5544 ] Check queue size during kernel CQ creation to prevent overflow of u32. Fixes: bec127e45d9f ("RDMA/mana_ib: create kernel-level CQs") Link: https://patch.msgid.link/r/1761213780-5457-1-git-send-email-kotaranov@linux.microsoft.com Signed-off-by: Konstantin Taranov Reviewed-by: Long Li Signed-off-by: Jason Gunthorpe Signed-off-by: Sasha Levin --- drivers/infiniband/hw/mana/cq.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/infiniband/hw/mana/cq.c b/drivers/infiniband/hw/mana/cq.c index 1becc87791235..7600412b0739f 100644 --- a/drivers/infiniband/hw/mana/cq.c +++ b/drivers/infiniband/hw/mana/cq.c @@ -56,6 +56,10 @@ int mana_ib_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr, doorbell = mana_ucontext->doorbell; } else { is_rnic_cq = true; + if (attr->cqe > U32_MAX / COMP_ENTRY_SIZE / 2 + 1) { + ibdev_dbg(ibdev, "CQE %d exceeding limit\n", attr->cqe); + return -EINVAL; + } buf_size = MANA_PAGE_ALIGN(roundup_pow_of_two(attr->cqe * COMP_ENTRY_SIZE)); cq->cqe = buf_size / COMP_ENTRY_SIZE; err = mana_ib_create_kernel_queue(mdev, buf_size, GDMA_CQ, &cq->queue); From d9b9affd103f51b42322da4ed5ac025b560bc354 Mon Sep 17 00:00:00 2001 From: Michal Schmidt Date: Thu, 27 Nov 2025 15:31:50 +0100 Subject: [PATCH 1514/2333] RDMA/irdma: avoid invalid read in irdma_net_event [ Upstream commit 6f05611728e9d0ab024832a4f1abb74a5f5d0bb0 ] irdma_net_event() should not dereference anything from "neigh" (alias "ptr") until it has checked that the event is NETEVENT_NEIGH_UPDATE. Other events come with different structures pointed to by "ptr" and they may be smaller than struct neighbour. Move the read of neigh->dev under the NETEVENT_NEIGH_UPDATE case. The bug is mostly harmless, but it triggers KASAN on debug kernels: BUG: KASAN: stack-out-of-bounds in irdma_net_event+0x32e/0x3b0 [irdma] Read of size 8 at addr ffffc900075e07f0 by task kworker/27:2/542554 CPU: 27 PID: 542554 Comm: kworker/27:2 Kdump: loaded Not tainted 5.14.0-630.el9.x86_64+debug #1 Hardware name: [...] Workqueue: events rt6_probe_deferred Call Trace: dump_stack_lvl+0x60/0xb0 print_address_description.constprop.0+0x2c/0x3f0 print_report+0xb4/0x270 kasan_report+0x92/0xc0 irdma_net_event+0x32e/0x3b0 [irdma] notifier_call_chain+0x9e/0x180 atomic_notifier_call_chain+0x5c/0x110 rt6_do_redirect+0xb91/0x1080 tcp_v6_err+0xe9b/0x13e0 icmpv6_notify+0x2b2/0x630 ndisc_redirect_rcv+0x328/0x530 icmpv6_rcv+0xc16/0x1360 ip6_protocol_deliver_rcu+0xb84/0x12e0 ip6_input_finish+0x117/0x240 ip6_input+0xc4/0x370 ipv6_rcv+0x420/0x7d0 __netif_receive_skb_one_core+0x118/0x1b0 process_backlog+0xd1/0x5d0 __napi_poll.constprop.0+0xa3/0x440 net_rx_action+0x78a/0xba0 handle_softirqs+0x2d4/0x9c0 do_softirq+0xad/0xe0 Fixes: 915cc7ac0f8e ("RDMA/irdma: Add miscellaneous utility definitions") Link: https://patch.msgid.link/r/20251127143150.121099-1-mschmidt@redhat.com Signed-off-by: Michal Schmidt Signed-off-by: Jason Gunthorpe Signed-off-by: Sasha Levin --- drivers/infiniband/hw/irdma/utils.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/irdma/utils.c b/drivers/infiniband/hw/irdma/utils.c index 8b94d87b01923..b6c4ccf38eb78 100644 --- a/drivers/infiniband/hw/irdma/utils.c +++ b/drivers/infiniband/hw/irdma/utils.c @@ -251,7 +251,7 @@ int irdma_net_event(struct notifier_block *notifier, unsigned long event, void *ptr) { struct neighbour *neigh = ptr; - struct net_device *real_dev, *netdev = (struct net_device *)neigh->dev; + struct net_device *real_dev, *netdev; struct irdma_device *iwdev; struct ib_device *ibdev; __be32 *p; @@ -260,6 +260,7 @@ int irdma_net_event(struct notifier_block *notifier, unsigned long event, switch (event) { case NETEVENT_NEIGH_UPDATE: + netdev = neigh->dev; real_dev = rdma_vlan_dev_real_dev(netdev); if (!real_dev) real_dev = netdev; From 277f1f4a80b40e5c12489f59b77ea4e2402cd765 Mon Sep 17 00:00:00 2001 From: Michael Margolin Date: Wed, 10 Dec 2025 17:36:56 +0000 Subject: [PATCH 1515/2333] RDMA/efa: Remove possible negative shift [ Upstream commit 85463eb6a46caf2f1e0e1a6d0731f2f3bab17780 ] The page size used for device might in some cases be smaller than PAGE_SIZE what results in a negative shift when calculating the number of host pages in PAGE_SIZE for a debug log. Remove the debug line together with the calculation. Fixes: 40909f664d27 ("RDMA/efa: Add EFA verbs implementation") Link: https://patch.msgid.link/r/20251210173656.8180-1-mrgolin@amazon.com Reviewed-by: Tom Sela Reviewed-by: Yonatan Nachum Signed-off-by: Michael Margolin Reviewed-by: Gal Pressman Signed-off-by: Jason Gunthorpe Signed-off-by: Sasha Levin --- drivers/infiniband/hw/efa/efa_verbs.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/infiniband/hw/efa/efa_verbs.c b/drivers/infiniband/hw/efa/efa_verbs.c index 22d3e25c3b9d1..755bba8d58bbc 100644 --- a/drivers/infiniband/hw/efa/efa_verbs.c +++ b/drivers/infiniband/hw/efa/efa_verbs.c @@ -1320,13 +1320,9 @@ static int umem_to_page_list(struct efa_dev *dev, u32 hp_cnt, u8 hp_shift) { - u32 pages_in_hp = BIT(hp_shift - PAGE_SHIFT); struct ib_block_iter biter; unsigned int hp_idx = 0; - ibdev_dbg(&dev->ibdev, "hp_cnt[%u], pages_in_hp[%u]\n", - hp_cnt, pages_in_hp); - rdma_umem_for_each_dma_block(umem, &biter, BIT(hp_shift)) page_list[hp_idx++] = rdma_block_iter_dma_address(&biter); From 868197d9f85ba7a68eacd8bacf28292b1b7345b9 Mon Sep 17 00:00:00 2001 From: Jang Ingyu Date: Fri, 19 Dec 2025 13:15:08 +0900 Subject: [PATCH 1516/2333] RDMA/core: Fix logic error in ib_get_gids_from_rdma_hdr() [ Upstream commit 8aaa848eaddd9ef8680fc6aafbd3a0646da5df40 ] Fix missing comparison operator for RDMA_NETWORK_ROCE_V1 in the conditional statement. The constant was used directly instead of being compared with net_type, causing the condition to always evaluate to true. Fixes: 1c15b4f2a42f ("RDMA/core: Modify enum ib_gid_type and enum rdma_network_type") Signed-off-by: Jang Ingyu Link: https://patch.msgid.link/20251219041508.1725947-1-ingyujang25@korea.ac.kr Signed-off-by: Leon Romanovsky Signed-off-by: Sasha Levin --- drivers/infiniband/core/verbs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c index 3a5f81402d2f8..d279e301f5a1a 100644 --- a/drivers/infiniband/core/verbs.c +++ b/drivers/infiniband/core/verbs.c @@ -735,7 +735,7 @@ int ib_get_gids_from_rdma_hdr(const union rdma_network_hdr *hdr, (struct in6_addr *)dgid); return 0; } else if (net_type == RDMA_NETWORK_IPV6 || - net_type == RDMA_NETWORK_IB || RDMA_NETWORK_ROCE_V1) { + net_type == RDMA_NETWORK_IB || net_type == RDMA_NETWORK_ROCE_V1) { *dgid = hdr->ibgrh.dgid; *sgid = hdr->ibgrh.sgid; return 0; From b20d6455f5372171cc3f2cc40763393f384433ea Mon Sep 17 00:00:00 2001 From: Alok Tiwari Date: Wed, 17 Dec 2025 02:01:41 -0800 Subject: [PATCH 1517/2333] RDMA/bnxt_re: Fix incorrect BAR check in bnxt_qplib_map_creq_db() [ Upstream commit 145a417a39d7efbc881f52e829817376972b278c ] RCFW_COMM_CONS_PCI_BAR_REGION is defined as BAR 2, so checking !creq_db->reg.bar_id is incorrect and always false. pci_resource_start() returns the BAR base address, and a value of 0 indicates that the BAR is unassigned. Update the condition to test bar_base == 0 instead. This ensures the driver detects and logs an error for an unassigned RCFW communication BAR. Fixes: cee0c7bba486 ("RDMA/bnxt_re: Refactor command queue management code") Signed-off-by: Alok Tiwari Link: https://patch.msgid.link/20251217100158.752504-1-alok.a.tiwari@oracle.com Reviewed-by: Kalesh AP Signed-off-by: Leon Romanovsky Signed-off-by: Sasha Levin --- drivers/infiniband/hw/bnxt_re/qplib_rcfw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c index 295a9610f3e67..4dad0cfcfa98d 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c +++ b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c @@ -1112,7 +1112,7 @@ static int bnxt_qplib_map_creq_db(struct bnxt_qplib_rcfw *rcfw, u32 reg_offt) 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) + if (!creq_db->reg.bar_base) dev_err(&pdev->dev, "QPLIB: CREQ BAR region %d resc start is 0!", creq_db->reg.bar_id); From fe8d456080423b9ed410469fbd1e2098d3acce2b Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Sat, 20 Dec 2025 11:11:33 +0900 Subject: [PATCH 1518/2333] RDMA/core: always drop device refcount in ib_del_sub_device_and_put() [ Upstream commit fa3c411d21ebc26ffd175c7256c37cefa35020aa ] Since nldev_deldev() (introduced by commit 060c642b2ab8 ("RDMA/nldev: Add support to add/delete a sub IB device through netlink") grabs a reference using ib_device_get_by_index() before calling ib_del_sub_device_and_put(), we need to drop that reference before returning -EOPNOTSUPP error. Reported-by: syzbot+881d65229ca4f9ae8c84@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=881d65229ca4f9ae8c84 Fixes: bca51197620a ("RDMA/core: Support IB sub device with type "SMI"") Signed-off-by: Tetsuo Handa Link: https://patch.msgid.link/80749a85-cbe2-460c-8451-42516013f9fa@I-love.SAKURA.ne.jp Reviewed-by: Parav Pandit Signed-off-by: Leon Romanovsky Signed-off-by: Sasha Levin --- drivers/infiniband/core/device.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/core/device.c b/drivers/infiniband/core/device.c index b4f3c835844a9..e3ba236d7c09f 100644 --- a/drivers/infiniband/core/device.c +++ b/drivers/infiniband/core/device.c @@ -2881,8 +2881,10 @@ int ib_del_sub_device_and_put(struct ib_device *sub) { struct ib_device *parent = sub->parent; - if (!parent) + if (!parent) { + ib_device_put(sub); return -EOPNOTSUPP; + } mutex_lock(&parent->subdev_lock); list_del(&sub->subdev_list); From 08e98ad766b1d59a4569aedffb09a60fc545c758 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Tue, 9 Dec 2025 14:41:59 +0100 Subject: [PATCH 1519/2333] drm/gem-shmem: Fix the MODULE_LICENSE() string [ Upstream commit 3fbd97618f49e07e05aad96510e5f2ed22d68809 ] Replace the bogus "GPL v2" with "GPL" as MODULE_LICNSE() string. The value does not declare the module's exact license, but only lets the module loader test whether the module is Free Software or not. See commit bf7fbeeae6db ("module: Cure the MODULE_LICENSE "GPL" vs. "GPL v2" bogosity") in the details of the issue. The fix is to use "GPL" for all modules under any variant of the GPL. Signed-off-by: Thomas Zimmermann Reviewed-by: Boris Brezillon Fixes: 4b2b5e142ff4 ("drm: Move GEM memory managers into modules") Link: https://patch.msgid.link/20251209140141.94407-3-tzimmermann@suse.de Signed-off-by: Sasha Levin --- drivers/gpu/drm/drm_gem_shmem_helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_gem_shmem_helper.c index 5d1349c34afd3..365b5737ca2c6 100644 --- a/drivers/gpu/drm/drm_gem_shmem_helper.c +++ b/drivers/gpu/drm/drm_gem_shmem_helper.c @@ -863,4 +863,4 @@ EXPORT_SYMBOL_GPL(drm_gem_shmem_prime_import_no_map); MODULE_DESCRIPTION("DRM SHMEM memory-management helpers"); MODULE_IMPORT_NS("DMA_BUF"); -MODULE_LICENSE("GPL v2"); +MODULE_LICENSE("GPL"); From ac4567773ce505763b0d2fb9c0b876db419676c6 Mon Sep 17 00:00:00 2001 From: Alok Tiwari Date: Fri, 19 Dec 2025 01:32:57 -0800 Subject: [PATCH 1520/2333] RDMA/bnxt_re: Fix IB_SEND_IP_CSUM handling in post_send [ Upstream commit f01765a2361323e78e3d91b1cb1d5527a83c5cf7 ] The bnxt_re SEND path checks wr->send_flags to enable features such as IP checksum offload. However, send_flags is a bitmask and may contain multiple flags (e.g. IB_SEND_SIGNALED | IB_SEND_IP_CSUM), while the existing code uses a switch() statement that only matches when send_flags is exactly IB_SEND_IP_CSUM. As a result, checksum offload is not enabled when additional SEND flags are present. Replace the switch() with a bitmask test: if (wr->send_flags & IB_SEND_IP_CSUM) This ensures IP checksum offload is enabled correctly when multiple SEND flags are used. Fixes: 1ac5a4047975 ("RDMA/bnxt_re: Add bnxt_re RoCE driver") Signed-off-by: Alok Tiwari Link: https://patch.msgid.link/20251219093308.2415620-1-alok.a.tiwari@oracle.com Reviewed-by: Kalesh AP Signed-off-by: Leon Romanovsky Signed-off-by: Sasha Levin --- drivers/infiniband/hw/bnxt_re/ib_verbs.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.c b/drivers/infiniband/hw/bnxt_re/ib_verbs.c index f19b55c13d580..ff91511bd3389 100644 --- a/drivers/infiniband/hw/bnxt_re/ib_verbs.c +++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.c @@ -2919,14 +2919,9 @@ int bnxt_re_post_send(struct ib_qp *ib_qp, const struct ib_send_wr *wr, wqe.rawqp1.lflags |= SQ_SEND_RAWETH_QP1_LFLAGS_ROCE_CRC; } - switch (wr->send_flags) { - case IB_SEND_IP_CSUM: + if (wr->send_flags & IB_SEND_IP_CSUM) wqe.rawqp1.lflags |= SQ_SEND_RAWETH_QP1_LFLAGS_IP_CHKSUM; - break; - default: - break; - } fallthrough; case IB_WR_SEND_WITH_INV: rc = bnxt_re_build_send_wqe(qp, wr, &wqe); From 369a161c48723f60f06f3510b82ea7d96d0499ab Mon Sep 17 00:00:00 2001 From: Ding Hui Date: Mon, 8 Dec 2025 15:21:10 +0800 Subject: [PATCH 1521/2333] RDMA/bnxt_re: Fix OOB write in bnxt_re_copy_err_stats() [ Upstream commit 9b68a1cc966bc947d00e4c0df7722d118125aa37 ] Commit ef56081d1864 ("RDMA/bnxt_re: RoCE related hardware counters update") added three new counters and placed them after BNXT_RE_OUT_OF_SEQ_ERR. BNXT_RE_OUT_OF_SEQ_ERR acts as a boundary marker for allocating hardware statistics with different num_counters values on chip_gen_p5_p7 devices. As a result, BNXT_RE_NUM_STD_COUNTERS are used when allocating hw_stats, which leads to an out-of-bounds write in bnxt_re_copy_err_stats(). The counters BNXT_RE_REQ_CQE_ERROR, BNXT_RE_RESP_CQE_ERROR, and BNXT_RE_RESP_REMOTE_ACCESS_ERRS are applicable to generic hardware, not only p5/p7 devices. Fix this by moving these counters before BNXT_RE_OUT_OF_SEQ_ERR so they are included in the generic counter set. Fixes: ef56081d1864 ("RDMA/bnxt_re: RoCE related hardware counters update") Reported-by: Yingying Zheng Signed-off-by: Ding Hui Link: https://patch.msgid.link/20251208072110.28874-1-dinghui@sangfor.com.cn Reviewed-by: Kalesh AP Tested-by: Kalesh AP Signed-off-by: Leon Romanovsky Signed-off-by: Sasha Levin --- drivers/infiniband/hw/bnxt_re/hw_counters.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/infiniband/hw/bnxt_re/hw_counters.h b/drivers/infiniband/hw/bnxt_re/hw_counters.h index 09d371d442aa7..cebec033f4a01 100644 --- a/drivers/infiniband/hw/bnxt_re/hw_counters.h +++ b/drivers/infiniband/hw/bnxt_re/hw_counters.h @@ -89,6 +89,9 @@ enum bnxt_re_hw_stats { BNXT_RE_RES_SRQ_LOAD_ERR, BNXT_RE_RES_TX_PCI_ERR, BNXT_RE_RES_RX_PCI_ERR, + BNXT_RE_REQ_CQE_ERROR, + BNXT_RE_RESP_CQE_ERROR, + BNXT_RE_RESP_REMOTE_ACCESS_ERRS, BNXT_RE_OUT_OF_SEQ_ERR, BNXT_RE_TX_ATOMIC_REQ, BNXT_RE_TX_READ_REQ, @@ -110,9 +113,6 @@ enum bnxt_re_hw_stats { BNXT_RE_TX_CNP, BNXT_RE_RX_CNP, BNXT_RE_RX_ECN, - BNXT_RE_REQ_CQE_ERROR, - BNXT_RE_RESP_CQE_ERROR, - BNXT_RE_RESP_REMOTE_ACCESS_ERRS, BNXT_RE_NUM_EXT_COUNTERS }; From e6d8d31d6e8721e3d94d09af0cbafa0eb77eddbd Mon Sep 17 00:00:00 2001 From: David Gow Date: Fri, 19 Dec 2025 16:52:58 +0800 Subject: [PATCH 1522/2333] kunit: Enforce task execution in {soft,hard}irq contexts [ Upstream commit c31f4aa8fed048fa70e742c4bb49bb48dc489ab3 ] The kunit_run_irq_test() helper allows a function to be run in hardirq and softirq contexts (in addition to the task context). It does this by running the user-provided function concurrently in the three contexts, until either a timeout has expired or a number of iterations have completed in the normal task context. However, on setups where the initialisation of the hardirq and softirq contexts (or, indeed, the scheduling of those tasks) is significantly slower than the function execution, it's possible for that number of iterations to be exceeded before any runs in irq contexts actually occur. This occurs with the polyval.test_polyval_preparekey_in_irqs test, which runs 20000 iterations of the relatively fast preparekey function, and therefore fails often under many UML, 32-bit arm, m68k and other environments. Instead, ensure that the max_iterations limit counts executions in all three contexts, and requires at least one of each. This will cause the test to continue iterating until at least the irq contexts have been tested, or the 1s wall-clock limit has been exceeded. This causes the test to pass in all of my environments. In so doing, we also update the task counters to atomic ints, to better match both the 'int' max_iterations input, and to ensure they are correctly updated across contexts. Finally, we also fix a few potential assertion messages to be less-specific to the original crypto usecases. Fixes: 950a81224e8b ("lib/crypto: tests: Add hash-test-template.h and gen-hash-testvecs.py") Signed-off-by: David Gow Link: https://lore.kernel.org/r/20251219085259.1163048-1-davidgow@google.com Signed-off-by: Eric Biggers Signed-off-by: Sasha Levin --- include/kunit/run-in-irq-context.h | 53 +++++++++++++++++++----------- 1 file changed, 33 insertions(+), 20 deletions(-) diff --git a/include/kunit/run-in-irq-context.h b/include/kunit/run-in-irq-context.h index 108e96433ea45..c89b1b1b12dd5 100644 --- a/include/kunit/run-in-irq-context.h +++ b/include/kunit/run-in-irq-context.h @@ -20,8 +20,8 @@ struct kunit_irq_test_state { bool task_func_reported_failure; bool hardirq_func_reported_failure; bool softirq_func_reported_failure; - unsigned long hardirq_func_calls; - unsigned long softirq_func_calls; + atomic_t hardirq_func_calls; + atomic_t softirq_func_calls; struct hrtimer timer; struct work_struct bh_work; }; @@ -32,7 +32,7 @@ static enum hrtimer_restart kunit_irq_test_timer_func(struct hrtimer *timer) container_of(timer, typeof(*state), timer); WARN_ON_ONCE(!in_hardirq()); - state->hardirq_func_calls++; + atomic_inc(&state->hardirq_func_calls); if (!state->func(state->test_specific_state)) state->hardirq_func_reported_failure = true; @@ -48,7 +48,7 @@ static void kunit_irq_test_bh_work_func(struct work_struct *work) container_of(work, typeof(*state), bh_work); WARN_ON_ONCE(!in_serving_softirq()); - state->softirq_func_calls++; + atomic_inc(&state->softirq_func_calls); if (!state->func(state->test_specific_state)) state->softirq_func_reported_failure = true; @@ -59,7 +59,10 @@ static void kunit_irq_test_bh_work_func(struct work_struct *work) * hardirq context concurrently, and reports a failure to KUnit if any * invocation of @func in any context returns false. @func is passed * @test_specific_state as its argument. At most 3 invocations of @func will - * run concurrently: one in each of task, softirq, and hardirq context. + * run concurrently: one in each of task, softirq, and hardirq context. @func + * will continue running until either @max_iterations calls have been made (so + * long as at least one each runs in task, softirq, and hardirq contexts), or + * one second has passed. * * The main purpose of this interrupt context testing is to validate fallback * code paths that run in contexts where the normal code path cannot be used, @@ -85,6 +88,8 @@ static inline void kunit_run_irq_test(struct kunit *test, bool (*func)(void *), .test_specific_state = test_specific_state, }; unsigned long end_jiffies; + int hardirq_calls, softirq_calls; + bool allctx = false; /* * Set up a hrtimer (the way we access hardirq context) and a work @@ -94,14 +99,25 @@ static inline void kunit_run_irq_test(struct kunit *test, bool (*func)(void *), CLOCK_MONOTONIC, HRTIMER_MODE_REL_HARD); INIT_WORK_ONSTACK(&state.bh_work, kunit_irq_test_bh_work_func); - /* Run for up to max_iterations or 1 second, whichever comes first. */ + /* + * Run for up to max_iterations (including at least one task, softirq, + * and hardirq), or 1 second, whichever comes first. + */ end_jiffies = jiffies + HZ; hrtimer_start(&state.timer, KUNIT_IRQ_TEST_HRTIMER_INTERVAL, HRTIMER_MODE_REL_HARD); - for (int i = 0; i < max_iterations && !time_after(jiffies, end_jiffies); - i++) { + for (int task_calls = 0, calls = 0; + ((calls < max_iterations) || !allctx) && + !time_after(jiffies, end_jiffies); + task_calls++) { if (!func(test_specific_state)) state.task_func_reported_failure = true; + + hardirq_calls = atomic_read(&state.hardirq_func_calls); + softirq_calls = atomic_read(&state.softirq_func_calls); + calls = task_calls + hardirq_calls + softirq_calls; + allctx = (task_calls > 0) && (hardirq_calls > 0) && + (softirq_calls > 0); } /* Cancel the timer and work. */ @@ -109,21 +125,18 @@ static inline void kunit_run_irq_test(struct kunit *test, bool (*func)(void *), flush_work(&state.bh_work); /* Sanity check: the timer and BH functions should have been run. */ - KUNIT_EXPECT_GT_MSG(test, state.hardirq_func_calls, 0, + KUNIT_EXPECT_GT_MSG(test, atomic_read(&state.hardirq_func_calls), 0, "Timer function was not called"); - KUNIT_EXPECT_GT_MSG(test, state.softirq_func_calls, 0, + KUNIT_EXPECT_GT_MSG(test, atomic_read(&state.softirq_func_calls), 0, "BH work function was not called"); - /* Check for incorrect hash values reported from any context. */ - KUNIT_EXPECT_FALSE_MSG( - test, state.task_func_reported_failure, - "Incorrect hash values reported from task context"); - KUNIT_EXPECT_FALSE_MSG( - test, state.hardirq_func_reported_failure, - "Incorrect hash values reported from hardirq context"); - KUNIT_EXPECT_FALSE_MSG( - test, state.softirq_func_reported_failure, - "Incorrect hash values reported from softirq context"); + /* Check for failure reported from any context. */ + KUNIT_EXPECT_FALSE_MSG(test, state.task_func_reported_failure, + "Failure reported from task context"); + KUNIT_EXPECT_FALSE_MSG(test, state.hardirq_func_reported_failure, + "Failure reported from hardirq context"); + KUNIT_EXPECT_FALSE_MSG(test, state.softirq_func_reported_failure, + "Failure reported from softirq context"); } #endif /* _KUNIT_RUN_IN_IRQ_CONTEXT_H */ From e0321917c03ba1dcc6c755ee1067570d9f63e754 Mon Sep 17 00:00:00 2001 From: Kalesh AP Date: Tue, 23 Dec 2025 18:48:55 +0530 Subject: [PATCH 1523/2333] RDMA/bnxt_re: Fix to use correct page size for PDE table [ Upstream commit 3d70e0fb0f289b0c778041c5bb04d099e1aa7c1c ] In bnxt_qplib_alloc_init_hwq(), while allocating memory for PDE table driver incorrectly is using the "pg_size" value passed to the function. Fixed to use the right value 4K. Also, fixed the allocation size for PBL table. Fixes: 0c4dcd602817 ("RDMA/bnxt_re: Refactor hardware queue memory allocation") Signed-off-by: Damodharam Ammepalli Signed-off-by: Kalesh AP Link: https://patch.msgid.link/20251223131855.145955-1-kalesh-anakkur.purayil@broadcom.com Reviewed-by: Selvin Xavier Signed-off-by: Leon Romanovsky Signed-off-by: Sasha Levin --- drivers/infiniband/hw/bnxt_re/qplib_res.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/hw/bnxt_re/qplib_res.c b/drivers/infiniband/hw/bnxt_re/qplib_res.c index 875d7b52c06ab..d5c12a51aa438 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_res.c +++ b/drivers/infiniband/hw/bnxt_re/qplib_res.c @@ -237,7 +237,7 @@ int bnxt_qplib_alloc_init_hwq(struct bnxt_qplib_hwq *hwq, if (npbl % BIT(MAX_PDL_LVL_SHIFT)) npde++; /* Alloc PDE pages */ - sginfo.pgsize = npde * pg_size; + sginfo.pgsize = npde * ROCE_PG_SIZE_4K; sginfo.npages = 1; rc = __alloc_pbl(res, &hwq->pbl[PBL_LVL_0], &sginfo); if (rc) @@ -245,7 +245,7 @@ int bnxt_qplib_alloc_init_hwq(struct bnxt_qplib_hwq *hwq, /* Alloc PBL pages */ sginfo.npages = npbl; - sginfo.pgsize = PAGE_SIZE; + sginfo.pgsize = ROCE_PG_SIZE_4K; rc = __alloc_pbl(res, &hwq->pbl[PBL_LVL_1], &sginfo); if (rc) goto fail; From b53635e0e42b08e8b6a8d3479449b8b9fc2cb618 Mon Sep 17 00:00:00 2001 From: Li Nan Date: Mon, 15 Dec 2025 20:44:12 +0800 Subject: [PATCH 1524/2333] md: Fix static checker warning in analyze_sbs [ Upstream commit 00f6c1b4d15d35fadb7f34768a1831c81aaa8936 ] The following warn is reported: drivers/md/md.c:3912 analyze_sbs() warn: iterator 'i' not incremented Fixes: d8730f0cf4ef ("md: Remove deprecated CONFIG_MD_MULTIPATH") Reported-by: Dan Carpenter Closes: https://lore.kernel.org/linux-raid/7e2e95ce-3740-09d8-a561-af6bfb767f18@huaweicloud.com/T/#t Signed-off-by: Li Nan Link: https://lore.kernel.org/linux-raid/20251215124412.4015572-1-linan666@huaweicloud.com Signed-off-by: Yu Kuai Signed-off-by: Sasha Levin --- drivers/md/md.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/md/md.c b/drivers/md/md.c index cef5b2954ac5a..7b1365143f58d 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -3874,7 +3874,6 @@ static struct md_rdev *md_import_device(dev_t newdev, int super_format, int supe static int analyze_sbs(struct mddev *mddev) { - int i; struct md_rdev *rdev, *freshest, *tmp; freshest = NULL; @@ -3901,11 +3900,9 @@ static int analyze_sbs(struct mddev *mddev) super_types[mddev->major_version]. validate_super(mddev, NULL/*freshest*/, freshest); - i = 0; rdev_for_each_safe(rdev, tmp, mddev) { if (mddev->max_disks && - (rdev->desc_nr >= mddev->max_disks || - i > mddev->max_disks)) { + rdev->desc_nr >= mddev->max_disks) { pr_warn("md: %s: %pg: only %d devices permitted\n", mdname(mddev), rdev->bdev, mddev->max_disks); From e5abb6af905de6b2fead8a0b3f32ab0b81468a01 Mon Sep 17 00:00:00 2001 From: Tuo Li Date: Thu, 25 Dec 2025 21:03:26 +0800 Subject: [PATCH 1525/2333] md/raid5: fix possible null-pointer dereferences in raid5_store_group_thread_cnt() [ Upstream commit 7ad6ef91d8745d04aff9cce7bdbc6320d8e05fe9 ] The variable mddev->private is first assigned to conf and then checked: conf = mddev->private; if (!conf) ... If conf is NULL, then mddev->private is also NULL. In this case, null-pointer dereferences can occur when calling raid5_quiesce(): raid5_quiesce(mddev, true); raid5_quiesce(mddev, false); since mddev->private is assigned to conf again in raid5_quiesce(), and conf is dereferenced in several places, for example: conf->quiesce = 0; wake_up(&conf->wait_for_quiescent); To fix this issue, the function should unlock mddev and return before invoking raid5_quiesce() when conf is NULL, following the existing pattern in raid5_change_consistency_policy(). Fixes: fa1944bbe622 ("md/raid5: Wait sync io to finish before changing group cnt") Signed-off-by: Tuo Li Reviewed-by: Xiao Ni Reviewed-by: Paul Menzel Link: https://lore.kernel.org/linux-raid/20251225130326.67780-1-islituo@gmail.com Signed-off-by: Yu Kuai Signed-off-by: Sasha Levin --- drivers/md/raid5.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 8b5f8a12d4179..41de29206402a 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -7187,12 +7187,14 @@ raid5_store_group_thread_cnt(struct mddev *mddev, const char *page, size_t len) err = mddev_suspend_and_lock(mddev); if (err) return err; + conf = mddev->private; + if (!conf) { + mddev_unlock_and_resume(mddev); + return -ENODEV; + } raid5_quiesce(mddev, true); - conf = mddev->private; - if (!conf) - err = -ENODEV; - else if (new != conf->worker_cnt_per_group) { + if (new != conf->worker_cnt_per_group) { old_groups = conf->worker_groups; if (old_groups) flush_workqueue(raid5_wq); From 92f024b8d47ac06621d4903e7ad29a62c5c962ca Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Sat, 1 Nov 2025 21:31:17 +0800 Subject: [PATCH 1526/2333] ublk: implement NUMA-aware memory allocation [ Upstream commit 529d4d6327880e5c60f4e0def39b3faaa7954e54 ] Implement NUMA-friendly memory allocation for ublk driver to improve performance on multi-socket systems. This commit includes the following changes: 1. Rename __queues to queues, dropping the __ prefix since the field is now accessed directly throughout the codebase rather than only through the ublk_get_queue() helper. 2. Remove the queue_size field from struct ublk_device as it is no longer needed. 3. Move queue allocation and deallocation into ublk_init_queue() and ublk_deinit_queue() respectively, improving encapsulation. This simplifies ublk_init_queues() and ublk_deinit_queues() to just iterate and call the per-queue functions. 4. Add ublk_get_queue_numa_node() helper function to determine the appropriate NUMA node for a queue by finding the first CPU mapped to that queue via tag_set.map[HCTX_TYPE_DEFAULT].mq_map[] and converting it to a NUMA node using cpu_to_node(). This function is called internally by ublk_init_queue() to determine the allocation node. 5. Allocate each queue structure on its local NUMA node using kvzalloc_node() in ublk_init_queue(). 6. Allocate the I/O command buffer on the same NUMA node using alloc_pages_node(). This reduces memory access latency on multi-socket NUMA systems by ensuring each queue's data structures are local to the CPUs that access them. Reviewed-by: Caleb Sander Mateos Signed-off-by: Ming Lei Signed-off-by: Jens Axboe Stable-dep-of: 7fc4da6a304b ("ublk: scan partition in async way") Signed-off-by: Sasha Levin --- drivers/block/ublk_drv.c | 84 +++++++++++++++++++++++++--------------- 1 file changed, 53 insertions(+), 31 deletions(-) diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c index d8079ea8f8ca1..796035891888c 100644 --- a/drivers/block/ublk_drv.c +++ b/drivers/block/ublk_drv.c @@ -210,9 +210,6 @@ struct ublk_queue { struct ublk_device { struct gendisk *ub_disk; - char *__queues; - - unsigned int queue_size; struct ublksrv_ctrl_dev_info dev_info; struct blk_mq_tag_set tag_set; @@ -240,6 +237,8 @@ struct ublk_device { bool canceling; pid_t ublksrv_tgid; struct delayed_work exit_work; + + struct ublk_queue *queues[]; }; /* header of ublk_params */ @@ -782,7 +781,7 @@ static noinline void ublk_put_device(struct ublk_device *ub) static inline struct ublk_queue *ublk_get_queue(struct ublk_device *dev, int qid) { - return (struct ublk_queue *)&(dev->__queues[qid * dev->queue_size]); + return dev->queues[qid]; } static inline bool ublk_rq_has_data(const struct request *rq) @@ -2713,9 +2712,13 @@ static const struct file_operations ublk_ch_fops = { static void ublk_deinit_queue(struct ublk_device *ub, int q_id) { - int size = ublk_queue_cmd_buf_size(ub); - struct ublk_queue *ubq = ublk_get_queue(ub, q_id); - int i; + struct ublk_queue *ubq = ub->queues[q_id]; + int size, i; + + if (!ubq) + return; + + size = ublk_queue_cmd_buf_size(ub); for (i = 0; i < ubq->q_depth; i++) { struct ublk_io *io = &ubq->ios[i]; @@ -2727,57 +2730,76 @@ static void ublk_deinit_queue(struct ublk_device *ub, int q_id) if (ubq->io_cmd_buf) free_pages((unsigned long)ubq->io_cmd_buf, get_order(size)); + + kvfree(ubq); + ub->queues[q_id] = NULL; +} + +static int ublk_get_queue_numa_node(struct ublk_device *ub, int q_id) +{ + unsigned int cpu; + + /* Find first CPU mapped to this queue */ + for_each_possible_cpu(cpu) { + if (ub->tag_set.map[HCTX_TYPE_DEFAULT].mq_map[cpu] == q_id) + return cpu_to_node(cpu); + } + + return NUMA_NO_NODE; } static int ublk_init_queue(struct ublk_device *ub, int q_id) { - struct ublk_queue *ubq = ublk_get_queue(ub, q_id); + int depth = ub->dev_info.queue_depth; + int ubq_size = sizeof(struct ublk_queue) + depth * sizeof(struct ublk_io); gfp_t gfp_flags = GFP_KERNEL | __GFP_ZERO; - void *ptr; + struct ublk_queue *ubq; + struct page *page; + int numa_node; int size; + /* Determine NUMA node based on queue's CPU affinity */ + numa_node = ublk_get_queue_numa_node(ub, q_id); + + /* Allocate queue structure on local NUMA node */ + ubq = kvzalloc_node(ubq_size, GFP_KERNEL, numa_node); + if (!ubq) + return -ENOMEM; + spin_lock_init(&ubq->cancel_lock); ubq->flags = ub->dev_info.flags; ubq->q_id = q_id; - ubq->q_depth = ub->dev_info.queue_depth; + ubq->q_depth = depth; size = ublk_queue_cmd_buf_size(ub); - ptr = (void *) __get_free_pages(gfp_flags, get_order(size)); - if (!ptr) + /* Allocate I/O command buffer on local NUMA node */ + page = alloc_pages_node(numa_node, gfp_flags, get_order(size)); + if (!page) { + kvfree(ubq); return -ENOMEM; + } + ubq->io_cmd_buf = page_address(page); - ubq->io_cmd_buf = ptr; + ub->queues[q_id] = ubq; ubq->dev = ub; return 0; } static void ublk_deinit_queues(struct ublk_device *ub) { - int nr_queues = ub->dev_info.nr_hw_queues; int i; - if (!ub->__queues) - return; - - for (i = 0; i < nr_queues; i++) + for (i = 0; i < ub->dev_info.nr_hw_queues; i++) ublk_deinit_queue(ub, i); - kvfree(ub->__queues); } static int ublk_init_queues(struct ublk_device *ub) { - int nr_queues = ub->dev_info.nr_hw_queues; - int depth = ub->dev_info.queue_depth; - int ubq_size = sizeof(struct ublk_queue) + depth * sizeof(struct ublk_io); - int i, ret = -ENOMEM; + int i, ret; - ub->queue_size = ubq_size; - ub->__queues = kvcalloc(nr_queues, ubq_size, GFP_KERNEL); - if (!ub->__queues) - return ret; - - for (i = 0; i < nr_queues; i++) { - if (ublk_init_queue(ub, i)) + for (i = 0; i < ub->dev_info.nr_hw_queues; i++) { + ret = ublk_init_queue(ub, i); + if (ret) goto fail; } @@ -3179,7 +3201,7 @@ static int ublk_ctrl_add_dev(const struct ublksrv_ctrl_cmd *header) goto out_unlock; ret = -ENOMEM; - ub = kzalloc(sizeof(*ub), GFP_KERNEL); + ub = kzalloc(struct_size(ub, queues, info.nr_hw_queues), GFP_KERNEL); if (!ub) goto out_unlock; mutex_init(&ub->mutex); From 63dfbcd59b4b823eac4441efff10b1c303c8f49f Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Tue, 23 Dec 2025 11:27:40 +0800 Subject: [PATCH 1527/2333] ublk: scan partition in async way [ Upstream commit 7fc4da6a304bdcd3de14fc946dc2c19437a9cc5a ] Implement async partition scan to avoid IO hang when reading partition tables. Similar to nvme_partition_scan_work(), partition scanning is deferred to a work queue to prevent deadlocks. When partition scan happens synchronously during add_disk(), IO errors can cause the partition scan to wait while holding ub->mutex, which can deadlock with other operations that need the mutex. Changes: - Add partition_scan_work to ublk_device structure - Implement ublk_partition_scan_work() to perform async scan - Always suppress sync partition scan during add_disk() - Schedule async work after add_disk() for trusted daemons - Add flush_work() in ublk_stop_dev() before grabbing ub->mutex Reviewed-by: Caleb Sander Mateos Reported-by: Yoav Cohen Closes: https://lore.kernel.org/linux-block/DM4PR12MB63280C5637917C071C2F0D65A9A8A@DM4PR12MB6328.namprd12.prod.outlook.com/ Fixes: 71f28f3136af ("ublk_drv: add io_uring based userspace block driver") Signed-off-by: Ming Lei Signed-off-by: Jens Axboe Signed-off-by: Sasha Levin --- drivers/block/ublk_drv.c | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c index 796035891888c..23aba73d24dc2 100644 --- a/drivers/block/ublk_drv.c +++ b/drivers/block/ublk_drv.c @@ -237,6 +237,7 @@ struct ublk_device { bool canceling; pid_t ublksrv_tgid; struct delayed_work exit_work; + struct work_struct partition_scan_work; struct ublk_queue *queues[]; }; @@ -254,6 +255,20 @@ static inline struct request *__ublk_check_and_get_req(struct ublk_device *ub, u16 q_id, u16 tag, struct ublk_io *io, size_t offset); static inline unsigned int ublk_req_build_flags(struct request *req); +static void ublk_partition_scan_work(struct work_struct *work) +{ + struct ublk_device *ub = + container_of(work, struct ublk_device, partition_scan_work); + + if (WARN_ON_ONCE(!test_and_clear_bit(GD_SUPPRESS_PART_SCAN, + &ub->ub_disk->state))) + return; + + mutex_lock(&ub->ub_disk->open_mutex); + bdev_disk_changed(ub->ub_disk, false); + mutex_unlock(&ub->ub_disk->open_mutex); +} + static inline struct ublksrv_io_desc * ublk_get_iod(const struct ublk_queue *ubq, unsigned tag) { @@ -2092,6 +2107,7 @@ static void ublk_stop_dev(struct ublk_device *ub) mutex_lock(&ub->mutex); ublk_stop_dev_unlocked(ub); mutex_unlock(&ub->mutex); + flush_work(&ub->partition_scan_work); ublk_cancel_dev(ub); } @@ -3023,9 +3039,17 @@ static int ublk_ctrl_start_dev(struct ublk_device *ub, ublk_apply_params(ub); - /* don't probe partitions if any daemon task is un-trusted */ - if (ub->unprivileged_daemons) - set_bit(GD_SUPPRESS_PART_SCAN, &disk->state); + /* + * Suppress partition scan to avoid potential IO hang. + * + * If ublk server error occurs during partition scan, the IO may + * wait while holding ub->mutex, which can deadlock with other + * operations that need the mutex. Defer partition scan to async + * work. + * For unprivileged daemons, keep GD_SUPPRESS_PART_SCAN set + * permanently. + */ + set_bit(GD_SUPPRESS_PART_SCAN, &disk->state); ublk_get_device(ub); ub->dev_info.state = UBLK_S_DEV_LIVE; @@ -3042,6 +3066,10 @@ static int ublk_ctrl_start_dev(struct ublk_device *ub, set_bit(UB_STATE_USED, &ub->state); + /* Schedule async partition scan for trusted daemons */ + if (!ub->unprivileged_daemons) + schedule_work(&ub->partition_scan_work); + out_put_cdev: if (ret) { ublk_detach_disk(ub); @@ -3207,6 +3235,7 @@ static int ublk_ctrl_add_dev(const struct ublksrv_ctrl_cmd *header) mutex_init(&ub->mutex); spin_lock_init(&ub->lock); mutex_init(&ub->cancel_mutex); + INIT_WORK(&ub->partition_scan_work, ublk_partition_scan_work); ret = ublk_alloc_dev_number(ub, header->dev_id); if (ret < 0) From d260dff568ad6d0f0f2aef4a85058e0832d772c4 Mon Sep 17 00:00:00 2001 From: Jonathan Cavitt Date: Mon, 22 Dec 2025 20:19:59 +0000 Subject: [PATCH 1528/2333] drm/xe/guc: READ/WRITE_ONCE g2h_fence->done MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit bed2a6bd20681aacfb063015c1edfab6f58a333e ] Use READ_ONCE and WRITE_ONCE when operating on g2h_fence->done to prevent the compiler from ignoring important modifications to its value. Fixes: dd08ebf6c352 ("drm/xe: Introduce a new DRM driver for Intel GPUs") Suggested-by: Matthew Brost Signed-off-by: Jonathan Cavitt Cc: Rodrigo Vivi Reviewed-by: Matthew Brost Link: https://patch.msgid.link/20251222201957.63245-5-jonathan.cavitt@intel.com Signed-off-by: Rodrigo Vivi (cherry picked from commit b5179dbd1c14743ae80f0aaa28eaaf35c361608f) Signed-off-by: Thomas Hellström Signed-off-by: Sasha Levin --- drivers/gpu/drm/xe/xe_guc_ct.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_guc_ct.c b/drivers/gpu/drm/xe/xe_guc_ct.c index b7afe8e983cb7..3aac1a7aa2e7b 100644 --- a/drivers/gpu/drm/xe/xe_guc_ct.c +++ b/drivers/gpu/drm/xe/xe_guc_ct.c @@ -106,7 +106,9 @@ static void g2h_fence_cancel(struct g2h_fence *g2h_fence) { g2h_fence->cancel = true; g2h_fence->fail = true; - g2h_fence->done = true; + + /* WRITE_ONCE pairs with READ_ONCEs in guc_ct_send_recv. */ + WRITE_ONCE(g2h_fence->done, true); } static bool g2h_fence_needs_alloc(struct g2h_fence *g2h_fence) @@ -1128,10 +1130,13 @@ static int guc_ct_send_recv(struct xe_guc_ct *ct, const u32 *action, u32 len, return ret; } - ret = wait_event_timeout(ct->g2h_fence_wq, g2h_fence.done, HZ); + /* READ_ONCEs pairs with WRITE_ONCEs in parse_g2h_response + * and g2h_fence_cancel. + */ + ret = wait_event_timeout(ct->g2h_fence_wq, READ_ONCE(g2h_fence.done), HZ); if (!ret) { LNL_FLUSH_WORK(&ct->g2h_worker); - if (g2h_fence.done) { + if (READ_ONCE(g2h_fence.done)) { xe_gt_warn(gt, "G2H fence %u, action %04x, done\n", g2h_fence.seqno, action[0]); ret = 1; @@ -1375,7 +1380,8 @@ static int parse_g2h_response(struct xe_guc_ct *ct, u32 *msg, u32 len) g2h_release_space(ct, GUC_CTB_HXG_MSG_MAX_LEN); - g2h_fence->done = true; + /* WRITE_ONCE pairs with READ_ONCEs in guc_ct_send_recv. */ + WRITE_ONCE(g2h_fence->done, true); smp_mb(); wake_up_all(&ct->g2h_fence_wq); From d026f47db68638521df8543535ef863814fb01b1 Mon Sep 17 00:00:00 2001 From: Zilin Guan Date: Wed, 24 Dec 2025 14:20:16 +0000 Subject: [PATCH 1529/2333] ksmbd: Fix memory leak in get_file_all_info() [ Upstream commit 0c56693b06a68476ba113db6347e7897475f9e4c ] In get_file_all_info(), if vfs_getattr() fails, the function returns immediately without freeing the allocated filename, leading to a memory leak. Fix this by freeing the filename before returning in this error case. Fixes: 5614c8c487f6a ("ksmbd: replace generic_fillattr with vfs_getattr") Signed-off-by: Zilin Guan Acked-by: Namjae Jeon Signed-off-by: Steve French Signed-off-by: Sasha Levin --- fs/smb/server/smb2pdu.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c index 6a94cda0927d7..2b59c282cda59 100644 --- a/fs/smb/server/smb2pdu.c +++ b/fs/smb/server/smb2pdu.c @@ -4933,8 +4933,10 @@ static int get_file_all_info(struct ksmbd_work *work, ret = vfs_getattr(&fp->filp->f_path, &stat, STATX_BASIC_STATS, AT_STATX_SYNC_AS_STAT); - if (ret) + if (ret) { + kfree(filename); return ret; + } ksmbd_debug(SMB, "filename = %s\n", filename); delete_pending = ksmbd_inode_pending_delete(fp); From cf49ffdf57b6902edc14277659debc5fe28a2db1 Mon Sep 17 00:00:00 2001 From: Li Zhijian Date: Fri, 26 Dec 2025 17:41:12 +0800 Subject: [PATCH 1530/2333] IB/rxe: Fix missing umem_odp->umem_mutex unlock on error path [ Upstream commit 3c68cf68233e556e0102f45b69f7448908dc1f44 ] rxe_odp_map_range_and_lock() must release umem_odp->umem_mutex when an error occurs, including cases where rxe_check_pagefault() fails. Fixes: 2fae67ab63db ("RDMA/rxe: Add support for Send/Recv/Write/Read with ODP") Signed-off-by: Li Zhijian Link: https://patch.msgid.link/20251226094112.3042583-1-lizhijian@fujitsu.com Reviewed-by: Zhu Yanjun Signed-off-by: Leon Romanovsky Signed-off-by: Sasha Levin --- drivers/infiniband/sw/rxe/rxe_odp.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/sw/rxe/rxe_odp.c b/drivers/infiniband/sw/rxe/rxe_odp.c index f58e3ec6252f5..4d4e3b324dd29 100644 --- a/drivers/infiniband/sw/rxe/rxe_odp.c +++ b/drivers/infiniband/sw/rxe/rxe_odp.c @@ -179,8 +179,10 @@ static int rxe_odp_map_range_and_lock(struct rxe_mr *mr, u64 iova, int length, u return err; need_fault = rxe_check_pagefault(umem_odp, iova, length); - if (need_fault) + if (need_fault) { + mutex_unlock(&umem_odp->umem_mutex); return -EFAULT; + } } return 0; From e4ee11c00d2396991958dbffb430833bfaa451c8 Mon Sep 17 00:00:00 2001 From: Honggang LI Date: Mon, 29 Dec 2025 10:56:17 +0800 Subject: [PATCH 1531/2333] RDMA/rtrs: Fix clt_path::max_pages_per_mr calculation [ Upstream commit 43bd09d5b750f700499ae8ec45fd41a4c48673e6 ] If device max_mr_size bits in the range [mr_page_shift+31:mr_page_shift] are zero, the `min3` function will set clt_path::max_pages_per_mr to zero. `alloc_path_reqs` will pass zero, which is invalid, as the third parameter to `ib_alloc_mr`. Fixes: 6a98d71daea1 ("RDMA/rtrs: client: main functionality") Signed-off-by: Honggang LI Link: https://patch.msgid.link/20251229025617.13241-1-honggangli@163.com Signed-off-by: Leon Romanovsky Signed-off-by: Sasha Levin --- drivers/infiniband/ulp/rtrs/rtrs-clt.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/infiniband/ulp/rtrs/rtrs-clt.c b/drivers/infiniband/ulp/rtrs/rtrs-clt.c index 71387811b2815..2b397a544cb93 100644 --- a/drivers/infiniband/ulp/rtrs/rtrs-clt.c +++ b/drivers/infiniband/ulp/rtrs/rtrs-clt.c @@ -1464,6 +1464,7 @@ static void query_fast_reg_mode(struct rtrs_clt_path *clt_path) mr_page_shift = max(12, ffs(ib_dev->attrs.page_size_cap) - 1); max_pages_per_mr = ib_dev->attrs.max_mr_size; do_div(max_pages_per_mr, (1ull << mr_page_shift)); + max_pages_per_mr = min_not_zero((u32)max_pages_per_mr, U32_MAX); clt_path->max_pages_per_mr = min3(clt_path->max_pages_per_mr, (u32)max_pages_per_mr, ib_dev->attrs.max_fast_reg_page_list_len); From 4f6e92b7c2a7952eb23a119104a42964f4c6562b Mon Sep 17 00:00:00 2001 From: Thomas Fourier Date: Tue, 30 Dec 2025 09:51:21 +0100 Subject: [PATCH 1532/2333] RDMA/bnxt_re: fix dma_free_coherent() pointer [ Upstream commit fcd431a9627f272b4c0bec445eba365fe2232a94 ] The dma_alloc_coherent() allocates a dma-mapped buffer, pbl->pg_arr[i]. The dma_free_coherent() should pass the same buffer to dma_free_coherent() and not page-aligned. Fixes: 1ac5a4047975 ("RDMA/bnxt_re: Add bnxt_re RoCE driver") Signed-off-by: Thomas Fourier Link: https://patch.msgid.link/20251230085121.8023-2-fourier.thomas@gmail.com Signed-off-by: Leon Romanovsky Signed-off-by: Sasha Levin --- drivers/infiniband/hw/bnxt_re/qplib_res.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/infiniband/hw/bnxt_re/qplib_res.c b/drivers/infiniband/hw/bnxt_re/qplib_res.c index d5c12a51aa438..4d674a3aee1aa 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_res.c +++ b/drivers/infiniband/hw/bnxt_re/qplib_res.c @@ -64,9 +64,7 @@ static void __free_pbl(struct bnxt_qplib_res *res, struct bnxt_qplib_pbl *pbl, for (i = 0; i < pbl->pg_count; i++) { if (pbl->pg_arr[i]) dma_free_coherent(&pdev->dev, pbl->pg_size, - (void *)((unsigned long) - pbl->pg_arr[i] & - PAGE_MASK), + pbl->pg_arr[i], pbl->pg_map_arr[i]); else dev_warn(&pdev->dev, From 7d8a5b44b9f2403f874a158498022f936fe7765f Mon Sep 17 00:00:00 2001 From: Cong Zhang Date: Tue, 30 Dec 2025 17:17:05 +0800 Subject: [PATCH 1533/2333] blk-mq: skip CPU offline notify on unmapped hctx [ Upstream commit 10845a105bbcb030647a729f1716c2309da71d33 ] If an hctx has no software ctx mapped, blk_mq_map_swqueue() never allocates tags and leaves hctx->tags NULL. The CPU hotplug offline notifier can still run for that hctx, return early since hctx cannot hold any requests. Signed-off-by: Cong Zhang Fixes: bf0beec0607d ("blk-mq: drain I/O when all CPUs in a hctx are offline") Reviewed-by: Ming Lei Signed-off-by: Jens Axboe Signed-off-by: Sasha Levin --- block/blk-mq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/block/blk-mq.c b/block/blk-mq.c index ea5f948af7a42..a03f52ab87d64 100644 --- a/block/blk-mq.c +++ b/block/blk-mq.c @@ -3710,7 +3710,7 @@ static int blk_mq_hctx_notify_offline(unsigned int cpu, struct hlist_node *node) struct blk_mq_hw_ctx, cpuhp_online); int ret = 0; - if (blk_mq_hctx_has_online_cpu(hctx, cpu)) + if (!hctx->nr_ctx || blk_mq_hctx_has_online_cpu(hctx, cpu)) return 0; /* From caf7a6e95854af9bec0b87f5927f0bbb019c8298 Mon Sep 17 00:00:00 2001 From: Yipeng Zou Date: Fri, 18 Aug 2023 09:32:26 +0800 Subject: [PATCH 1534/2333] selftests/ftrace: traceonoff_triggers: strip off names [ Upstream commit b889b4fb4cbea3ca7eb9814075d6a51936394bd9 ] The func_traceonoff_triggers.tc sometimes goes to fail on my board, Kunpeng-920. [root@localhost]# ./ftracetest ./test.d/ftrace/func_traceonoff_triggers.tc -l fail.log === Ftrace unit tests === [1] ftrace - test for function traceon/off triggers [FAIL] [2] (instance) ftrace - test for function traceon/off triggers [UNSUPPORTED] I look up the log, and it shows that the md5sum is different between csum1 and csum2. ++ cnt=611 ++ sleep .1 +++ cnt_trace +++ grep -v '^#' trace +++ wc -l ++ cnt2=611 ++ '[' 611 -ne 611 ']' +++ cat tracing_on ++ on=0 ++ '[' 0 '!=' 0 ']' +++ md5sum trace ++ csum1='76896aa74362fff66a6a5f3cf8a8a500 trace' ++ sleep .1 +++ md5sum trace ++ csum2='ee8625a21c058818fc26e45c1ed3f6de trace' ++ '[' '76896aa74362fff66a6a5f3cf8a8a500 trace' '!=' 'ee8625a21c058818fc26e45c1ed3f6de trace' ']' ++ fail 'Tracing file is still changing' ++ echo Tracing file is still changing Tracing file is still changing ++ exit_fail ++ exit 1 So I directly dump the trace file before md5sum, the diff shows that: [root@localhost]# diff trace_1.log trace_2.log -y --suppress-common-lines dockerd-12285 [036] d.... 18385.510290: sched_stat | <...>-12285 [036] d.... 18385.510290: sched_stat dockerd-12285 [036] d.... 18385.510291: sched_swit | <...>-12285 [036] d.... 18385.510291: sched_swit <...>-740 [044] d.... 18385.602859: sched_stat | kworker/44:1-740 [044] d.... 18385.602859: sched_stat <...>-740 [044] d.... 18385.602860: sched_swit | kworker/44:1-740 [044] d.... 18385.602860: sched_swit And we can see that <...> filed be filled with names. We can strip off the names there to fix that. After strip off the names: kworker/u257:0-12 [019] d..2. 2528.758910: sched_stat | -12 [019] d..2. 2528.758910: sched_stat_runtime: comm=k kworker/u257:0-12 [019] d..2. 2528.758912: sched_swit | -12 [019] d..2. 2528.758912: sched_switch: prev_comm=kw -0 [000] d.s5. 2528.762318: sched_waki | -0 [000] d.s5. 2528.762318: sched_waking: comm=sshd pi -0 [037] dNh2. 2528.762326: sched_wake | -0 [037] dNh2. 2528.762326: sched_wakeup: comm=sshd pi -0 [037] d..2. 2528.762334: sched_swit | -0 [037] d..2. 2528.762334: sched_switch: prev_comm=sw Link: https://lore.kernel.org/r/20230818013226.2182299-1-zouyipeng@huawei.com Fixes: d87b29179aa0 ("selftests: ftrace: Use md5sum to take less time of checking logs") Suggested-by: Steven Rostedt (Google) Signed-off-by: Yipeng Zou Acked-by: Masami Hiramatsu (Google) Reviewed-by: Steven Rostedt (Google) Signed-off-by: Shuah Khan Signed-off-by: Sasha Levin --- .../ftrace/test.d/ftrace/func_traceonoff_triggers.tc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/ftrace/test.d/ftrace/func_traceonoff_triggers.tc b/tools/testing/selftests/ftrace/test.d/ftrace/func_traceonoff_triggers.tc index aee22289536b1..1b57771dbfdf0 100644 --- a/tools/testing/selftests/ftrace/test.d/ftrace/func_traceonoff_triggers.tc +++ b/tools/testing/selftests/ftrace/test.d/ftrace/func_traceonoff_triggers.tc @@ -90,9 +90,10 @@ if [ $on != "0" ]; then fail "Tracing is not off" fi -csum1=`md5sum trace` +# Cannot rely on names being around as they are only cached, strip them +csum1=`cat trace | sed -e 's/^ *[^ ]*\(-[0-9][0-9]*\)/\1/' | md5sum` sleep $SLEEP_TIME -csum2=`md5sum trace` +csum2=`cat trace | sed -e 's/^ *[^ ]*\(-[0-9][0-9]*\)/\1/' | md5sum` if [ "$csum1" != "$csum2" ]; then fail "Tracing file is still changing" From 7c87afd13484f1399cd7a7ac4d9c1e611d0f222f Mon Sep 17 00:00:00 2001 From: Damien Le Moal Date: Wed, 5 Nov 2025 06:22:35 +0900 Subject: [PATCH 1535/2333] block: handle zone management operations completions commit efae226c2ef19528ffd81d29ba0eecf1b0896ca2 upstream. The functions blk_zone_wplug_handle_reset_or_finish() and blk_zone_wplug_handle_reset_all() both modify the zone write pointer offset of zone write plugs that are the target of a reset, reset all or finish zone management operation. However, these functions do this modification before the BIO is executed. So if the zone operation fails, the modified zone write pointer offsets become invalid. Avoid this by modifying the zone write pointer offset of a zone write plug that is the target of a zone management operation when the operation completes. To do so, modify blk_zone_bio_endio() to call the new function blk_zone_mgmt_bio_endio() which in turn calls the functions blk_zone_reset_all_bio_endio(), blk_zone_reset_bio_endio() or blk_zone_finish_bio_endio() depending on the operation of the completed BIO, to modify a zone write plug write pointer offset accordingly. These functions are called only if the BIO execution was successful. Fixes: dd291d77cc90 ("block: Introduce zone write plugging") Cc: stable@vger.kernel.org Signed-off-by: Damien Le Moal Reviewed-by: Christoph Hellwig Reviewed-by: Johannes Thumshirn Reviewed-by: Chaitanya Kulkarni Reviewed-by: Hannes Reinecke Reviewed-by: Martin K. Petersen Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman --- block/blk-zoned.c | 139 ++++++++++++++++++++++++++++++---------------- block/blk.h | 14 +++++ 2 files changed, 104 insertions(+), 49 deletions(-) diff --git a/block/blk-zoned.c b/block/blk-zoned.c index f60af668ab81e..39381f2b2e947 100644 --- a/block/blk-zoned.c +++ b/block/blk-zoned.c @@ -71,6 +71,11 @@ struct blk_zone_wplug { struct gendisk *disk; }; +static inline unsigned int disk_zone_wplugs_hash_size(struct gendisk *disk) +{ + return 1U << disk->zone_wplugs_hash_bits; +} + /* * Zone write plug flags bits: * - BLK_ZONE_WPLUG_PLUGGED: Indicates that the zone write plug is plugged, @@ -698,71 +703,91 @@ static int disk_zone_sync_wp_offset(struct gendisk *disk, sector_t sector) disk_report_zones_cb, &args); } -static bool blk_zone_wplug_handle_reset_or_finish(struct bio *bio, - unsigned int wp_offset) +static void blk_zone_reset_bio_endio(struct bio *bio) { struct gendisk *disk = bio->bi_bdev->bd_disk; - sector_t sector = bio->bi_iter.bi_sector; struct blk_zone_wplug *zwplug; - unsigned long flags; - - /* Conventional zones cannot be reset nor finished. */ - if (!bdev_zone_is_seq(bio->bi_bdev, sector)) { - bio_io_error(bio); - return true; - } - - /* - * No-wait reset or finish BIOs do not make much sense as the callers - * issue these as blocking operations in most cases. To avoid issues - * the BIO execution potentially failing with BLK_STS_AGAIN, warn about - * REQ_NOWAIT being set and ignore that flag. - */ - if (WARN_ON_ONCE(bio->bi_opf & REQ_NOWAIT)) - bio->bi_opf &= ~REQ_NOWAIT; /* - * If we have a zone write plug, set its write pointer offset to 0 - * (reset case) or to the zone size (finish case). This will abort all - * BIOs plugged for the target zone. It is fine as resetting or - * finishing zones while writes are still in-flight will result in the + * If we have a zone write plug, set its write pointer offset to 0. + * This will abort all BIOs plugged for the target zone. It is fine as + * resetting zones while writes are still in-flight will result in the * writes failing anyway. */ - zwplug = disk_get_zone_wplug(disk, sector); + zwplug = disk_get_zone_wplug(disk, bio->bi_iter.bi_sector); if (zwplug) { + unsigned long flags; + spin_lock_irqsave(&zwplug->lock, flags); - disk_zone_wplug_set_wp_offset(disk, zwplug, wp_offset); + disk_zone_wplug_set_wp_offset(disk, zwplug, 0); spin_unlock_irqrestore(&zwplug->lock, flags); disk_put_zone_wplug(zwplug); } - - return false; } -static bool blk_zone_wplug_handle_reset_all(struct bio *bio) +static void blk_zone_reset_all_bio_endio(struct bio *bio) { struct gendisk *disk = bio->bi_bdev->bd_disk; struct blk_zone_wplug *zwplug; unsigned long flags; - sector_t sector; + unsigned int i; - /* - * Set the write pointer offset of all zone write plugs to 0. This will - * abort all plugged BIOs. It is fine as resetting zones while writes - * are still in-flight will result in the writes failing anyway. - */ - for (sector = 0; sector < get_capacity(disk); - sector += disk->queue->limits.chunk_sectors) { - zwplug = disk_get_zone_wplug(disk, sector); - if (zwplug) { + /* Update the condition of all zone write plugs. */ + rcu_read_lock(); + for (i = 0; i < disk_zone_wplugs_hash_size(disk); i++) { + hlist_for_each_entry_rcu(zwplug, &disk->zone_wplugs_hash[i], + node) { spin_lock_irqsave(&zwplug->lock, flags); disk_zone_wplug_set_wp_offset(disk, zwplug, 0); spin_unlock_irqrestore(&zwplug->lock, flags); - disk_put_zone_wplug(zwplug); } } + rcu_read_unlock(); +} - return false; +static void blk_zone_finish_bio_endio(struct bio *bio) +{ + struct block_device *bdev = bio->bi_bdev; + struct gendisk *disk = bdev->bd_disk; + struct blk_zone_wplug *zwplug; + + /* + * If we have a zone write plug, set its write pointer offset to the + * zone size. This will abort all BIOs plugged for the target zone. It + * is fine as resetting zones while writes are still in-flight will + * result in the writes failing anyway. + */ + zwplug = disk_get_zone_wplug(disk, bio->bi_iter.bi_sector); + if (zwplug) { + unsigned long flags; + + spin_lock_irqsave(&zwplug->lock, flags); + disk_zone_wplug_set_wp_offset(disk, zwplug, + bdev_zone_sectors(bdev)); + spin_unlock_irqrestore(&zwplug->lock, flags); + disk_put_zone_wplug(zwplug); + } +} + +void blk_zone_mgmt_bio_endio(struct bio *bio) +{ + /* If the BIO failed, we have nothing to do. */ + if (bio->bi_status != BLK_STS_OK) + return; + + switch (bio_op(bio)) { + case REQ_OP_ZONE_RESET: + blk_zone_reset_bio_endio(bio); + return; + case REQ_OP_ZONE_RESET_ALL: + blk_zone_reset_all_bio_endio(bio); + return; + case REQ_OP_ZONE_FINISH: + blk_zone_finish_bio_endio(bio); + return; + default: + return; + } } static void disk_zone_wplug_schedule_bio_work(struct gendisk *disk, @@ -1106,6 +1131,30 @@ static void blk_zone_wplug_handle_native_zone_append(struct bio *bio) disk_put_zone_wplug(zwplug); } +static bool blk_zone_wplug_handle_zone_mgmt(struct bio *bio) +{ + if (bio_op(bio) != REQ_OP_ZONE_RESET_ALL && + !bdev_zone_is_seq(bio->bi_bdev, bio->bi_iter.bi_sector)) { + /* + * Zone reset and zone finish operations do not apply to + * conventional zones. + */ + bio_io_error(bio); + return true; + } + + /* + * No-wait zone management BIOs do not make much sense as the callers + * issue these as blocking operations in most cases. To avoid issues + * with the BIO execution potentially failing with BLK_STS_AGAIN, warn + * about REQ_NOWAIT being set and ignore that flag. + */ + if (WARN_ON_ONCE(bio->bi_opf & REQ_NOWAIT)) + bio->bi_opf &= ~REQ_NOWAIT; + + return false; +} + /** * blk_zone_plug_bio - Handle a zone write BIO with zone write plugging * @bio: The BIO being submitted @@ -1153,12 +1202,9 @@ bool blk_zone_plug_bio(struct bio *bio, unsigned int nr_segs) case REQ_OP_WRITE_ZEROES: return blk_zone_wplug_handle_write(bio, nr_segs); case REQ_OP_ZONE_RESET: - return blk_zone_wplug_handle_reset_or_finish(bio, 0); case REQ_OP_ZONE_FINISH: - return blk_zone_wplug_handle_reset_or_finish(bio, - bdev_zone_sectors(bdev)); case REQ_OP_ZONE_RESET_ALL: - return blk_zone_wplug_handle_reset_all(bio); + return blk_zone_wplug_handle_zone_mgmt(bio); default: return false; } @@ -1332,11 +1378,6 @@ static void blk_zone_wplug_bio_work(struct work_struct *work) disk_put_zone_wplug(zwplug); } -static inline unsigned int disk_zone_wplugs_hash_size(struct gendisk *disk) -{ - return 1U << disk->zone_wplugs_hash_bits; -} - void disk_init_zone_resources(struct gendisk *disk) { spin_lock_init(&disk->zone_wplugs_lock); diff --git a/block/blk.h b/block/blk.h index a7992680f9e14..37b9b6a95c11c 100644 --- a/block/blk.h +++ b/block/blk.h @@ -488,9 +488,23 @@ static inline bool blk_req_bio_is_zone_append(struct request *rq, void blk_zone_write_plug_bio_merged(struct bio *bio); void blk_zone_write_plug_init_request(struct request *rq); void blk_zone_append_update_request_bio(struct request *rq, struct bio *bio); +void blk_zone_mgmt_bio_endio(struct bio *bio); void blk_zone_write_plug_bio_endio(struct bio *bio); static inline void blk_zone_bio_endio(struct bio *bio) { + /* + * Zone management BIOs may impact zone write plugs (e.g. a zone reset + * changes a zone write plug zone write pointer offset), but these + * operation do not go through zone write plugging as they may operate + * on zones that do not have a zone write + * plug. blk_zone_mgmt_bio_endio() handles the potential changes to zone + * write plugs that are present. + */ + if (op_is_zone_mgmt(bio_op(bio))) { + blk_zone_mgmt_bio_endio(bio); + return; + } + /* * For write BIOs to zoned devices, signal the completion of the BIO so * that the next write BIO can be submitted by zone write plugging. From 791bc3890d6fa56c9de803d601402919d189687f Mon Sep 17 00:00:00 2001 From: "Matthew Wilcox (Oracle)" Date: Fri, 18 Jul 2025 20:53:58 +0100 Subject: [PATCH 1536/2333] ntfs: Do not overwrite uptodate pages commit 68f6bd128e75a032432eda9d16676ed2969a1096 upstream. When reading a compressed file, we may read several pages in addition to the one requested. The current code will overwrite pages in the page cache with the data from disc which can definitely result in changes that have been made being lost. For example if we have four consecutie pages ABCD in the file compressed into a single extent, on first access, we'll bring in ABCD. Then we write to page B. Memory pressure results in the eviction of ACD. When we attempt to write to page C, we will overwrite the data in page B with the data currently on disk. I haven't investigated the decompression code to check whether it's OK to overwrite a clean page or whether it might be possible to see corrupt data. Out of an abundance of caution, decline to overwrite uptodate pages, not just dirty pages. Fixes: 4342306f0f0d (fs/ntfs3: Add file operations and implementation) Signed-off-by: Matthew Wilcox (Oracle) Cc: stable@vger.kernel.org Signed-off-by: Konstantin Komarov Signed-off-by: Greg Kroah-Hartman --- fs/ntfs3/frecord.c | 35 +++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/fs/ntfs3/frecord.c b/fs/ntfs3/frecord.c index e5a005d216f31..295f6936a3e58 100644 --- a/fs/ntfs3/frecord.c +++ b/fs/ntfs3/frecord.c @@ -2022,6 +2022,29 @@ int ni_fiemap(struct ntfs_inode *ni, struct fiemap_extent_info *fieinfo, return err; } +static struct page *ntfs_lock_new_page(struct address_space *mapping, + pgoff_t index, gfp_t gfp) +{ + struct folio *folio = __filemap_get_folio(mapping, index, + FGP_LOCK | FGP_ACCESSED | FGP_CREAT, gfp); + struct page *page; + + if (IS_ERR(folio)) + return ERR_CAST(folio); + + if (!folio_test_uptodate(folio)) + return folio_file_page(folio, index); + + /* Use a temporary page to avoid data corruption */ + folio_unlock(folio); + folio_put(folio); + page = alloc_page(gfp); + if (!page) + return ERR_PTR(-ENOMEM); + __SetPageLocked(page); + return page; +} + /* * ni_readpage_cmpr * @@ -2076,9 +2099,9 @@ int ni_readpage_cmpr(struct ntfs_inode *ni, struct folio *folio) if (i == idx) continue; - pg = find_or_create_page(mapping, index, gfp_mask); - if (!pg) { - err = -ENOMEM; + pg = ntfs_lock_new_page(mapping, index, gfp_mask); + if (IS_ERR(pg)) { + err = PTR_ERR(pg); goto out1; } pages[i] = pg; @@ -2177,13 +2200,13 @@ int ni_decompress_file(struct ntfs_inode *ni) for (i = 0; i < pages_per_frame; i++, index++) { struct page *pg; - pg = find_or_create_page(mapping, index, gfp_mask); - if (!pg) { + pg = ntfs_lock_new_page(mapping, index, gfp_mask); + if (IS_ERR(pg)) { while (i--) { unlock_page(pages[i]); put_page(pages[i]); } - err = -ENOMEM; + err = PTR_ERR(pg); goto out; } pages[i] = pg; From 042169940f6adf0ca966ba3bef3ad2ebe361f72b Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 27 Nov 2025 14:50:57 +0100 Subject: [PATCH 1537/2333] ASoC: codecs: wcd939x: fix regmap leak on probe failure commit 86dc090f737953f16f8dc60c546ae7854690d4f6 upstream. The soundwire regmap that may be allocated during probe is not freed on late probe failures. Add the missing error handling. Fixes: be2af391cea0 ("ASoC: codecs: Add WCD939x Soundwire devices driver") Cc: stable@vger.kernel.org # 6.9 Cc: Neil Armstrong Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20251127135057.2216-1-johan@kernel.org Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/codecs/wcd939x-sdw.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/wcd939x-sdw.c b/sound/soc/codecs/wcd939x-sdw.c index d369100a24574..da342a0c95a52 100644 --- a/sound/soc/codecs/wcd939x-sdw.c +++ b/sound/soc/codecs/wcd939x-sdw.c @@ -1400,12 +1400,18 @@ static int wcd9390_probe(struct sdw_slave *pdev, const struct sdw_device_id *id) ret = component_add(dev, &wcd_sdw_component_ops); if (ret) - return ret; + goto err_free_regmap; /* Set suspended until aggregate device is bind */ pm_runtime_set_suspended(dev); return 0; + +err_free_regmap: + if (wcd->regmap) + regmap_exit(wcd->regmap); + + return ret; } static int wcd9390_remove(struct sdw_slave *pdev) From 88baed15284e4dd177373494777aac709b23b95d Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 24 Nov 2025 11:49:05 +0100 Subject: [PATCH 1538/2333] ASoC: stm32: sai: fix device leak on probe commit e26ff429eaf10c4ef1bc3dabd9bf27eb54b7e1f4 upstream. Make sure to drop the reference taken when looking up the sync provider device and its driver data during DAI probe on probe failures and on unbind. Note that holding a reference to a device does not prevent its driver data from going away so there is no point in keeping the reference. Fixes: 7dd0d835582f ("ASoC: stm32: sai: simplify sync modes management") Fixes: 1c3816a19487 ("ASoC: stm32: sai: add missing put_device()") Cc: stable@vger.kernel.org # 4.16: 1c3816a19487 Cc: olivier moysan Cc: Wen Yang Signed-off-by: Johan Hovold Reviewed-by: olivier moysan Link: https://patch.msgid.link/20251124104908.15754-2-johan@kernel.org Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/stm/stm32_sai.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/stm/stm32_sai.c b/sound/soc/stm/stm32_sai.c index fa821e3fb427e..7065aeb0e524a 100644 --- a/sound/soc/stm/stm32_sai.c +++ b/sound/soc/stm/stm32_sai.c @@ -143,6 +143,7 @@ static int stm32_sai_set_sync(struct stm32_sai_data *sai_client, } sai_provider = platform_get_drvdata(pdev); + put_device(&pdev->dev); if (!sai_provider) { dev_err(&sai_client->pdev->dev, "SAI sync provider data not found\n"); @@ -159,7 +160,6 @@ static int stm32_sai_set_sync(struct stm32_sai_data *sai_client, ret = stm32_sai_sync_conf_provider(sai_provider, synco); error: - put_device(&pdev->dev); of_node_put(np_provider); return ret; } From 88636450c4add16f3a63149606aa75603ea5a981 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 24 Nov 2025 11:49:06 +0100 Subject: [PATCH 1539/2333] ASoC: stm32: sai: fix clk prepare imbalance on probe failure commit 312ec2f0d9d1a5656f76d770bbf1d967e9289aa7 upstream. Make sure to unprepare the parent clock also on probe failures (e.g. probe deferral). Fixes: a14bf98c045b ("ASoC: stm32: sai: fix possible circular locking") Cc: stable@vger.kernel.org # 5.5 Cc: Olivier Moysan Signed-off-by: Johan Hovold Reviewed-by: olivier moysan Link: https://patch.msgid.link/20251124104908.15754-3-johan@kernel.org Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/stm/stm32_sai_sub.c | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c index 0ae1eae2a59e2..7a005b4ad3048 100644 --- a/sound/soc/stm/stm32_sai_sub.c +++ b/sound/soc/stm/stm32_sai_sub.c @@ -1634,14 +1634,21 @@ static int stm32_sai_sub_parse_of(struct platform_device *pdev, if (of_property_present(np, "#clock-cells")) { ret = stm32_sai_add_mclk_provider(sai); if (ret < 0) - return ret; + goto err_unprepare_pclk; } else { sai->sai_mclk = devm_clk_get_optional(&pdev->dev, "MCLK"); - if (IS_ERR(sai->sai_mclk)) - return PTR_ERR(sai->sai_mclk); + if (IS_ERR(sai->sai_mclk)) { + ret = PTR_ERR(sai->sai_mclk); + goto err_unprepare_pclk; + } } return 0; + +err_unprepare_pclk: + clk_unprepare(sai->pdata->pclk); + + return ret; } static int stm32_sai_sub_probe(struct platform_device *pdev) @@ -1688,26 +1695,33 @@ static int stm32_sai_sub_probe(struct platform_device *pdev) IRQF_SHARED, dev_name(&pdev->dev), sai); if (ret) { dev_err(&pdev->dev, "IRQ request returned %d\n", ret); - return ret; + goto err_unprepare_pclk; } if (STM_SAI_PROTOCOL_IS_SPDIF(sai)) conf = &stm32_sai_pcm_config_spdif; ret = snd_dmaengine_pcm_register(&pdev->dev, conf, 0); - if (ret) - return dev_err_probe(&pdev->dev, ret, "Could not register pcm dma\n"); + if (ret) { + ret = dev_err_probe(&pdev->dev, ret, "Could not register pcm dma\n"); + goto err_unprepare_pclk; + } ret = snd_soc_register_component(&pdev->dev, &stm32_component, &sai->cpu_dai_drv, 1); if (ret) { snd_dmaengine_pcm_unregister(&pdev->dev); - return ret; + goto err_unprepare_pclk; } pm_runtime_enable(&pdev->dev); return 0; + +err_unprepare_pclk: + clk_unprepare(sai->pdata->pclk); + + return ret; } static void stm32_sai_sub_remove(struct platform_device *pdev) From 3752afcc6d80d5525e236e329895ba2cb93bcb26 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 24 Nov 2025 11:49:07 +0100 Subject: [PATCH 1540/2333] ASoC: stm32: sai: fix OF node leak on probe commit 23261f0de09427367e99f39f588e31e2856a690e upstream. The reference taken to the sync provider OF node when probing the platform device is currently only dropped if the set_sync() callback fails during DAI probe. Make sure to drop the reference on platform probe failures (e.g. probe deferral) and on driver unbind. This also avoids a potential use-after-free in case the DAI is ever reprobed without first rebinding the platform driver. Fixes: 5914d285f6b7 ("ASoC: stm32: sai: Add synchronization support") Fixes: d4180b4c02e7 ("ASoC: stm32: sai: fix set_sync service") Cc: Olivier Moysan Cc: stable@vger.kernel.org # 4.16: d4180b4c02e7 Signed-off-by: Johan Hovold Reviewed-by: olivier moysan Link: https://patch.msgid.link/20251124104908.15754-4-johan@kernel.org Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/stm/stm32_sai.c | 12 +++--------- sound/soc/stm/stm32_sai_sub.c | 23 ++++++++++++++++------- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/sound/soc/stm/stm32_sai.c b/sound/soc/stm/stm32_sai.c index 7065aeb0e524a..00cf24ceca2d4 100644 --- a/sound/soc/stm/stm32_sai.c +++ b/sound/soc/stm/stm32_sai.c @@ -138,7 +138,6 @@ static int stm32_sai_set_sync(struct stm32_sai_data *sai_client, if (!pdev) { dev_err(&sai_client->pdev->dev, "Device not found for node %pOFn\n", np_provider); - of_node_put(np_provider); return -ENODEV; } @@ -147,21 +146,16 @@ static int stm32_sai_set_sync(struct stm32_sai_data *sai_client, if (!sai_provider) { dev_err(&sai_client->pdev->dev, "SAI sync provider data not found\n"); - ret = -EINVAL; - goto error; + return -EINVAL; } /* Configure sync client */ ret = stm32_sai_sync_conf_client(sai_client, synci); if (ret < 0) - goto error; + return ret; /* Configure sync provider */ - ret = stm32_sai_sync_conf_provider(sai_provider, synco); - -error: - of_node_put(np_provider); - return ret; + return stm32_sai_sync_conf_provider(sai_provider, synco); } static int stm32_sai_get_parent_clk(struct stm32_sai_data *sai) diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c index 7a005b4ad3048..5ae4d2577f28b 100644 --- a/sound/soc/stm/stm32_sai_sub.c +++ b/sound/soc/stm/stm32_sai_sub.c @@ -1586,7 +1586,8 @@ static int stm32_sai_sub_parse_of(struct platform_device *pdev, dev_err(&pdev->dev, "External synchro not supported\n"); of_node_put(args.np); - return -EINVAL; + ret = -EINVAL; + goto err_put_sync_provider; } sai->sync = SAI_SYNC_EXTERNAL; @@ -1595,7 +1596,8 @@ static int stm32_sai_sub_parse_of(struct platform_device *pdev, (sai->synci > (SAI_GCR_SYNCIN_MAX + 1))) { dev_err(&pdev->dev, "Wrong SAI index\n"); of_node_put(args.np); - return -EINVAL; + ret = -EINVAL; + goto err_put_sync_provider; } if (of_property_match_string(args.np, "compatible", @@ -1609,7 +1611,8 @@ static int stm32_sai_sub_parse_of(struct platform_device *pdev, if (!sai->synco) { dev_err(&pdev->dev, "Unknown SAI sub-block\n"); of_node_put(args.np); - return -EINVAL; + ret = -EINVAL; + goto err_put_sync_provider; } } @@ -1619,13 +1622,15 @@ static int stm32_sai_sub_parse_of(struct platform_device *pdev, of_node_put(args.np); sai->sai_ck = devm_clk_get(&pdev->dev, "sai_ck"); - if (IS_ERR(sai->sai_ck)) - return dev_err_probe(&pdev->dev, PTR_ERR(sai->sai_ck), - "Missing kernel clock sai_ck\n"); + if (IS_ERR(sai->sai_ck)) { + ret = dev_err_probe(&pdev->dev, PTR_ERR(sai->sai_ck), + "Missing kernel clock sai_ck\n"); + goto err_put_sync_provider; + } ret = clk_prepare(sai->pdata->pclk); if (ret < 0) - return ret; + goto err_put_sync_provider; if (STM_SAI_IS_F4(sai->pdata)) return 0; @@ -1647,6 +1652,8 @@ static int stm32_sai_sub_parse_of(struct platform_device *pdev, err_unprepare_pclk: clk_unprepare(sai->pdata->pclk); +err_put_sync_provider: + of_node_put(sai->np_sync_provider); return ret; } @@ -1720,6 +1727,7 @@ static int stm32_sai_sub_probe(struct platform_device *pdev) err_unprepare_pclk: clk_unprepare(sai->pdata->pclk); + of_node_put(sai->np_sync_provider); return ret; } @@ -1732,6 +1740,7 @@ static void stm32_sai_sub_remove(struct platform_device *pdev) snd_dmaengine_pcm_unregister(&pdev->dev); snd_soc_unregister_component(&pdev->dev); pm_runtime_disable(&pdev->dev); + of_node_put(sai->np_sync_provider); } static int stm32_sai_sub_suspend(struct device *dev) From 4d2ae0495c75a97fa6e09cb6d61a162f7b5345ba Mon Sep 17 00:00:00 2001 From: Biju Das Date: Fri, 14 Nov 2025 07:37:05 +0000 Subject: [PATCH 1541/2333] ASoC: renesas: rz-ssi: Fix channel swap issue in full duplex mode commit 52a525011cb8e293799a085436f026f2958403f9 upstream. The full duplex audio starts with half duplex mode and then switch to full duplex mode (another FIFO reset) when both playback/capture streams available leading to random audio left/right channel swap issue. Fix this channel swap issue by detecting the full duplex condition by populating struct dup variable in startup() callback and synchronize starting both the play and capture at the same time in rz_ssi_start(). Cc: stable@kernel.org Fixes: 4f8cd05a4305 ("ASoC: sh: rz-ssi: Add full duplex support") Co-developed-by: Tony Tang Signed-off-by: Tony Tang Reviewed-by: Kuninori Morimoto Signed-off-by: Biju Das Link: https://patch.msgid.link/20251114073709.4376-2-biju.das.jz@bp.renesas.com Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/renesas/rz-ssi.c | 51 ++++++++++++++++++++++++++++++++------ 1 file changed, 43 insertions(+), 8 deletions(-) diff --git a/sound/soc/renesas/rz-ssi.c b/sound/soc/renesas/rz-ssi.c index 81b883e8ac92a..62d3222c510f8 100644 --- a/sound/soc/renesas/rz-ssi.c +++ b/sound/soc/renesas/rz-ssi.c @@ -133,6 +133,12 @@ struct rz_ssi_priv { bool bckp_rise; /* Bit clock polarity (SSICR.BCKP) */ bool dma_rt; + struct { + bool tx_active; + bool rx_active; + bool one_stream_triggered; + } dup; + /* Full duplex communication support */ struct { unsigned int rate; @@ -332,13 +338,12 @@ static int rz_ssi_start(struct rz_ssi_priv *ssi, struct rz_ssi_stream *strm) bool is_full_duplex; u32 ssicr, ssifcr; - is_full_duplex = rz_ssi_is_stream_running(&ssi->playback) || - rz_ssi_is_stream_running(&ssi->capture); + is_full_duplex = ssi->dup.tx_active && ssi->dup.rx_active; ssicr = rz_ssi_reg_readl(ssi, SSICR); ssifcr = rz_ssi_reg_readl(ssi, SSIFCR); if (!is_full_duplex) { ssifcr &= ~0xF; - } else { + } else if (ssi->dup.one_stream_triggered) { rz_ssi_reg_mask_setl(ssi, SSICR, SSICR_TEN | SSICR_REN, 0); rz_ssi_set_idle(ssi); ssifcr &= ~SSIFCR_FIFO_RST; @@ -374,12 +379,16 @@ static int rz_ssi_start(struct rz_ssi_priv *ssi, struct rz_ssi_stream *strm) SSISR_RUIRQ), 0); strm->running = 1; - if (is_full_duplex) - ssicr |= SSICR_TEN | SSICR_REN; - else + if (!is_full_duplex) { ssicr |= is_play ? SSICR_TEN : SSICR_REN; - - rz_ssi_reg_writel(ssi, SSICR, ssicr); + rz_ssi_reg_writel(ssi, SSICR, ssicr); + } else if (ssi->dup.one_stream_triggered) { + ssicr |= SSICR_TEN | SSICR_REN; + rz_ssi_reg_writel(ssi, SSICR, ssicr); + ssi->dup.one_stream_triggered = false; + } else { + ssi->dup.one_stream_triggered = true; + } return 0; } @@ -915,6 +924,30 @@ static int rz_ssi_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) return 0; } +static int rz_ssi_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct rz_ssi_priv *ssi = snd_soc_dai_get_drvdata(dai); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + ssi->dup.tx_active = true; + else + ssi->dup.rx_active = true; + + return 0; +} + +static void rz_ssi_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct rz_ssi_priv *ssi = snd_soc_dai_get_drvdata(dai); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + ssi->dup.tx_active = false; + else + ssi->dup.rx_active = false; +} + static bool rz_ssi_is_valid_hw_params(struct rz_ssi_priv *ssi, unsigned int rate, unsigned int channels, unsigned int sample_width, @@ -985,6 +1018,8 @@ static int rz_ssi_dai_hw_params(struct snd_pcm_substream *substream, } static const struct snd_soc_dai_ops rz_ssi_dai_ops = { + .startup = rz_ssi_startup, + .shutdown = rz_ssi_shutdown, .trigger = rz_ssi_dai_trigger, .set_fmt = rz_ssi_dai_set_fmt, .hw_params = rz_ssi_dai_hw_params, From 21d87fde367a50464fa312e197c74f0e3387cae6 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Fri, 14 Nov 2025 07:37:06 +0000 Subject: [PATCH 1542/2333] ASoC: renesas: rz-ssi: Fix rz_ssi_priv::hw_params_cache::sample_width commit 2bae7beda19f3b2dc6ab2062c94df19c27923712 upstream. The strm->sample_width is not filled during rz_ssi_dai_hw_params(). This wrong value is used for caching sample_width in struct hw_params_cache. Fix this issue by replacing 'strm->sample_width'->'params_width(params)' in rz_ssi_dai_hw_params(). After this drop the variable sample_width from struct rz_ssi_stream as it is unused. Cc: stable@kernel.org Fixes: 4f8cd05a4305 ("ASoC: sh: rz-ssi: Add full duplex support") Reviewed-by: Kuninori Morimoto Signed-off-by: Biju Das Link: https://patch.msgid.link/20251114073709.4376-3-biju.das.jz@bp.renesas.com Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/renesas/rz-ssi.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/sound/soc/renesas/rz-ssi.c b/sound/soc/renesas/rz-ssi.c index 62d3222c510f8..f4dc2f68deada 100644 --- a/sound/soc/renesas/rz-ssi.c +++ b/sound/soc/renesas/rz-ssi.c @@ -13,6 +13,7 @@ #include #include #include +#include #include /* REGISTER OFFSET */ @@ -87,7 +88,6 @@ struct rz_ssi_stream { int dma_buffer_pos; /* The address for the next DMA descriptor */ int completed_dma_buf_pos; /* The address of the last completed DMA descriptor. */ int period_counter; /* for keeping track of periods transferred */ - int sample_width; int buffer_pos; /* current frame position in the buffer */ int running; /* 0=stopped, 1=running */ @@ -217,10 +217,7 @@ static inline bool rz_ssi_is_stream_running(struct rz_ssi_stream *strm) static void rz_ssi_stream_init(struct rz_ssi_stream *strm, struct snd_pcm_substream *substream) { - struct snd_pcm_runtime *runtime = substream->runtime; - rz_ssi_set_substream(strm, substream); - strm->sample_width = samples_to_bytes(runtime, 1); strm->dma_buffer_pos = 0; strm->completed_dma_buf_pos = 0; strm->period_counter = 0; @@ -978,9 +975,9 @@ static int rz_ssi_dai_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct rz_ssi_priv *ssi = snd_soc_dai_get_drvdata(dai); - struct rz_ssi_stream *strm = rz_ssi_stream_get(ssi, substream); unsigned int sample_bits = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS)->min; + unsigned int sample_width = params_width(params); unsigned int channels = params_channels(params); unsigned int rate = params_rate(params); int ret; @@ -999,16 +996,14 @@ static int rz_ssi_dai_hw_params(struct snd_pcm_substream *substream, if (rz_ssi_is_stream_running(&ssi->playback) || rz_ssi_is_stream_running(&ssi->capture)) { - if (rz_ssi_is_valid_hw_params(ssi, rate, channels, - strm->sample_width, sample_bits)) + if (rz_ssi_is_valid_hw_params(ssi, rate, channels, sample_width, sample_bits)) return 0; dev_err(ssi->dev, "Full duplex needs same HW params\n"); return -EINVAL; } - rz_ssi_cache_hw_params(ssi, rate, channels, strm->sample_width, - sample_bits); + rz_ssi_cache_hw_params(ssi, rate, channels, sample_width, sample_bits); ret = rz_ssi_swreset(ssi); if (ret) From 15424b48e226e4d9876d39433670c729338eef2b Mon Sep 17 00:00:00 2001 From: Ma Ke Date: Sun, 16 Nov 2025 14:16:23 +0800 Subject: [PATCH 1543/2333] ASoC: codecs: wcd937x: Fix error handling in wcd937x codec driver commit 578ccfe344c5f421c2c6343b872995b397ffd3ff upstream. In wcd937x_bind(), the driver calls of_sdw_find_device_by_node() to obtain references to RX and TX SoundWire devices, which increment the device reference counts. However, the corresponding put_device() are missing in both the error paths and the normal unbind path in wcd937x_unbind(). Add proper error handling with put_device() calls in all error paths of wcd937x_bind() and ensure devices are released in wcd937x_unbind(). Found by code review. Cc: stable@vger.kernel.org Fixes: 772ed12bd04e ("ASoC: codecs: wcdxxxx: use of_sdw_find_device_by_node helper") Signed-off-by: Ma Ke Reviewed-by: David Heidelberg Link: https://patch.msgid.link/20251116061623.11830-1-make24@iscas.ac.cn Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/codecs/wcd937x.c | 43 ++++++++++++++++++++++++++++++-------- 1 file changed, 34 insertions(+), 9 deletions(-) diff --git a/sound/soc/codecs/wcd937x.c b/sound/soc/codecs/wcd937x.c index 421ec7a2d6bdc..ed0ff45a89649 100644 --- a/sound/soc/codecs/wcd937x.c +++ b/sound/soc/codecs/wcd937x.c @@ -2748,7 +2748,8 @@ static int wcd937x_bind(struct device *dev) wcd937x->rxdev = of_sdw_find_device_by_node(wcd937x->rxnode); if (!wcd937x->rxdev) { dev_err(dev, "could not find slave with matching of node\n"); - return -EINVAL; + ret = -EINVAL; + goto err_component_unbind; } wcd937x->sdw_priv[AIF1_PB] = dev_get_drvdata(wcd937x->rxdev); @@ -2757,7 +2758,8 @@ static int wcd937x_bind(struct device *dev) wcd937x->txdev = of_sdw_find_device_by_node(wcd937x->txnode); if (!wcd937x->txdev) { dev_err(dev, "could not find txslave with matching of node\n"); - return -EINVAL; + ret = -EINVAL; + goto err_put_rxdev; } wcd937x->sdw_priv[AIF1_CAP] = dev_get_drvdata(wcd937x->txdev); @@ -2765,7 +2767,8 @@ static int wcd937x_bind(struct device *dev) wcd937x->tx_sdw_dev = dev_to_sdw_dev(wcd937x->txdev); if (!wcd937x->tx_sdw_dev) { dev_err(dev, "could not get txslave with matching of dev\n"); - return -EINVAL; + ret = -EINVAL; + goto err_put_txdev; } /* @@ -2775,31 +2778,35 @@ static int wcd937x_bind(struct device *dev) if (!device_link_add(wcd937x->rxdev, wcd937x->txdev, DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME)) { dev_err(dev, "Could not devlink TX and RX\n"); - return -EINVAL; + ret = -EINVAL; + goto err_put_txdev; } if (!device_link_add(dev, wcd937x->txdev, DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME)) { dev_err(dev, "Could not devlink WCD and TX\n"); - return -EINVAL; + ret = -EINVAL; + goto err_remove_link1; } if (!device_link_add(dev, wcd937x->rxdev, DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME)) { dev_err(dev, "Could not devlink WCD and RX\n"); - return -EINVAL; + ret = -EINVAL; + goto err_remove_link2; } wcd937x->regmap = wcd937x->sdw_priv[AIF1_CAP]->regmap; if (!wcd937x->regmap) { dev_err(dev, "could not get TX device regmap\n"); - return -EINVAL; + ret = -EINVAL; + goto err_remove_link3; } ret = wcd937x_irq_init(wcd937x, dev); if (ret) { dev_err(dev, "IRQ init failed: %d\n", ret); - return ret; + goto err_remove_link3; } wcd937x->sdw_priv[AIF1_PB]->slave_irq = wcd937x->virq; @@ -2809,10 +2816,26 @@ static int wcd937x_bind(struct device *dev) ret = snd_soc_register_component(dev, &soc_codec_dev_wcd937x, wcd937x_dais, ARRAY_SIZE(wcd937x_dais)); - if (ret) + if (ret) { dev_err(dev, "Codec registration failed\n"); + goto err_remove_link3; + } return ret; + +err_remove_link3: + device_link_remove(dev, wcd937x->rxdev); +err_remove_link2: + device_link_remove(dev, wcd937x->txdev); +err_remove_link1: + device_link_remove(wcd937x->rxdev, wcd937x->txdev); +err_put_txdev: + put_device(wcd937x->txdev); +err_put_rxdev: + put_device(wcd937x->rxdev); +err_component_unbind: + component_unbind_all(dev, wcd937x); + return ret; } static void wcd937x_unbind(struct device *dev) @@ -2825,6 +2848,8 @@ static void wcd937x_unbind(struct device *dev) device_link_remove(wcd937x->rxdev, wcd937x->txdev); component_unbind_all(dev, wcd937x); mutex_destroy(&wcd937x->micb_lock); + put_device(wcd937x->txdev); + put_device(wcd937x->rxdev); } static const struct component_master_ops wcd937x_comp_ops = { From 28bcaff809cb8d836e77929bb9d7ab41d80f7271 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 23 Oct 2025 11:02:50 +0200 Subject: [PATCH 1544/2333] ASoC: codecs: pm4125: Fix potential conflict when probing two devices commit fd94857a934cbe613353810a024c84d54826ead3 upstream. Qualcomm PM4125 codec is always a single device on the board, however nothing stops board designers to have two of them, thus same device driver could probe twice. Device driver is not ready for that case, because it allocates statically 'struct regmap_irq_chip' as non-const and stores during component bind in 'irq_drv_data' member a pointer to per-probe state container ('struct pm4125_priv'). Second component bind would overwrite the 'irq_drv_data' from previous device probe, so interrupts would be executed in wrong context. The fix makes use of currently unused 'struct pm4125_priv' member 'pm4125_regmap_irq_chip', but renames it to a shorter name. Fixes: 8ad529484937 ("ASoC: codecs: add new pm4125 audio codec driver") Cc: stable@vger.kernel.org Signed-off-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20251023-asoc-regmap-irq-chip-v1-1-17ad32680913@linaro.org Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/codecs/pm4125.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/sound/soc/codecs/pm4125.c b/sound/soc/codecs/pm4125.c index 706fc668ffe2a..1d3a019b1b4f2 100644 --- a/sound/soc/codecs/pm4125.c +++ b/sound/soc/codecs/pm4125.c @@ -70,7 +70,7 @@ struct pm4125_priv { struct wcd_mbhc_config mbhc_cfg; struct wcd_mbhc_intr intr_ids; struct irq_domain *virq; - const struct regmap_irq_chip *pm4125_regmap_irq_chip; + const struct regmap_irq_chip *chip_desc; struct regmap_irq_chip_data *irq_chip; struct snd_soc_jack *jack; unsigned long status_mask; @@ -179,7 +179,7 @@ static const u32 pm4125_config_regs[] = { PM4125_DIG_SWR_INTR_LEVEL_0, }; -static struct regmap_irq_chip pm4125_regmap_irq_chip = { +static const struct regmap_irq_chip pm4125_regmap_irq_chip = { .name = "pm4125", .irqs = pm4125_irqs, .num_irqs = ARRAY_SIZE(pm4125_irqs), @@ -1320,10 +1320,8 @@ static int pm4125_irq_init(struct pm4125_priv *pm4125, struct device *dev) return -EINVAL; } - pm4125_regmap_irq_chip.irq_drv_data = pm4125; - return devm_regmap_add_irq_chip(dev, pm4125->regmap, irq_create_mapping(pm4125->virq, 0), - IRQF_ONESHOT, 0, &pm4125_regmap_irq_chip, + IRQF_ONESHOT, 0, pm4125->chip_desc, &pm4125->irq_chip); } @@ -1695,6 +1693,7 @@ static int pm4125_probe(struct platform_device *pdev) { struct component_match *match = NULL; struct device *dev = &pdev->dev; + struct regmap_irq_chip *chip_desc; struct pm4125_priv *pm4125; struct wcd_mbhc_config *cfg; int ret; @@ -1705,6 +1704,14 @@ static int pm4125_probe(struct platform_device *pdev) dev_set_drvdata(dev, pm4125); + chip_desc = devm_kmemdup(dev, &pm4125_regmap_irq_chip, + sizeof(pm4125_regmap_irq_chip), + GFP_KERNEL); + if (!chip_desc) + return -ENOMEM; + chip_desc->irq_drv_data = pm4125; + pm4125->chip_desc = chip_desc; + ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(pm4125_power_supplies), pm4125_power_supplies); if (ret) From 341902036870705629d9c9d7784ca4079c8c4a85 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 23 Oct 2025 11:02:51 +0200 Subject: [PATCH 1545/2333] ASoC: codecs: pm4125: Remove irq_chip on component unbind commit e65b871c9b5af9265aefc5b8cd34993586d93aab upstream. Component bind uses devm_regmap_add_irq_chip() to add IRQ chip, so it will be removed only during driver unbind, not component unbind. A component unbind-bind cycle for the same Linux device lifetime would result in two chips added. Fix this by manually removing the IRQ chip during component unbind. Fixes: 8ad529484937 ("ASoC: codecs: add new pm4125 audio codec driver") Cc: stable@vger.kernel.org Signed-off-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20251023-asoc-regmap-irq-chip-v1-2-17ad32680913@linaro.org Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/codecs/pm4125.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/codecs/pm4125.c b/sound/soc/codecs/pm4125.c index 1d3a019b1b4f2..3657a4a759855 100644 --- a/sound/soc/codecs/pm4125.c +++ b/sound/soc/codecs/pm4125.c @@ -1658,6 +1658,8 @@ static void pm4125_unbind(struct device *dev) struct pm4125_priv *pm4125 = dev_get_drvdata(dev); snd_soc_unregister_component(dev); + devm_regmap_del_irq_chip(dev, irq_find_mapping(pm4125->virq, 0), + pm4125->irq_chip); device_link_remove(dev, pm4125->txdev); device_link_remove(dev, pm4125->rxdev); device_link_remove(pm4125->rxdev, pm4125->txdev); From a619ebcf3e977630f3831b83e98c6945eade8348 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Fri, 31 Oct 2025 12:06:58 +0000 Subject: [PATCH 1546/2333] ASoC: codecs: lpass-tx-macro: fix SM6115 support commit 7c63b5a8ed972a2c8c03d984f6a43349007cea93 upstream. SM6115 does have soundwire controller in tx. For some reason we ended up with this incorrect patch. Fix this by adding the flag to reflect this in SoC data. Fixes: 510c46884299 ("ASoC: codecs: lpass-tx-macro: Add SM6115 support") Cc: Stable@vger.kernel.org Signed-off-by: Srinivas Kandagatla Link: https://patch.msgid.link/20251031120703.590201-2-srinivas.kandagatla@oss.qualcomm.com Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/codecs/lpass-tx-macro.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/lpass-tx-macro.c b/sound/soc/codecs/lpass-tx-macro.c index 1da34cb3505f3..c7d4dc553e6aa 100644 --- a/sound/soc/codecs/lpass-tx-macro.c +++ b/sound/soc/codecs/lpass-tx-macro.c @@ -2473,7 +2473,8 @@ static const struct tx_macro_data lpass_ver_9_2 = { }; static const struct tx_macro_data lpass_ver_10_sm6115 = { - .flags = LPASS_MACRO_FLAG_HAS_NPL_CLOCK, + .flags = LPASS_MACRO_FLAG_HAS_NPL_CLOCK | + LPASS_MACRO_FLAG_RESET_SWR, .ver = LPASS_VER_10_0_0, .extra_widgets = tx_macro_dapm_widgets_v9_2, .extra_widgets_num = ARRAY_SIZE(tx_macro_dapm_widgets_v9_2), From b79b8613c0c4606edc08b93ae7ad1a82df131f8f Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Wed, 22 Oct 2025 15:33:46 +0100 Subject: [PATCH 1547/2333] ASoC: qcom: sdw: fix memory leak for sdw_stream_runtime commit bcba17279327c6e85dee6a97014dc642e2dc93cc upstream. For some reason we endedup allocating sdw_stream_runtime for every cpu dai, this has two issues. 1. we never set snd_soc_dai_set_stream for non soundwire dai, which means there is no way that we can free this, resulting in memory leak 2. startup and shutdown callbacks can be called without hw_params callback called. This combination results in memory leak because machine driver sruntime array pointer is only set in hw_params callback. Fix this by 1. adding a helper function to get sdw_runtime for substream which can be used by shutdown callback to get hold of sruntime to free. 2. only allocate sdw_runtime for soundwire dais. Fixes: d32bac9cb09c ("ASoC: qcom: Add helper for allocating Soundwire stream runtime") Cc: Krzysztof Kozlowski Cc: Stable@vger.kernel.org Signed-off-by: Srinivas Kandagatla Tested-by: Steev Klimaszewski # Thinkpad X13s Link: https://patch.msgid.link/20251022143349.1081513-2-srinivas.kandagatla@oss.qualcomm.com Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/qcom/sc7280.c | 2 +- sound/soc/qcom/sc8280xp.c | 2 +- sound/soc/qcom/sdw.c | 105 +++++++++++++++++++++----------------- sound/soc/qcom/sdw.h | 1 + sound/soc/qcom/sm8250.c | 2 +- sound/soc/qcom/x1e80100.c | 2 +- 6 files changed, 64 insertions(+), 50 deletions(-) diff --git a/sound/soc/qcom/sc7280.c b/sound/soc/qcom/sc7280.c index af412bd0c89ff..c444dae563c75 100644 --- a/sound/soc/qcom/sc7280.c +++ b/sound/soc/qcom/sc7280.c @@ -317,7 +317,7 @@ static void sc7280_snd_shutdown(struct snd_pcm_substream *substream) struct snd_soc_card *card = rtd->card; struct sc7280_snd_data *data = snd_soc_card_get_drvdata(card); struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); - struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id]; + struct sdw_stream_runtime *sruntime = qcom_snd_sdw_get_stream(substream); switch (cpu_dai->id) { case MI2S_PRIMARY: diff --git a/sound/soc/qcom/sc8280xp.c b/sound/soc/qcom/sc8280xp.c index 187f37ffe3283..ed8b04c6022e9 100644 --- a/sound/soc/qcom/sc8280xp.c +++ b/sound/soc/qcom/sc8280xp.c @@ -73,7 +73,7 @@ static void sc8280xp_snd_shutdown(struct snd_pcm_substream *substream) struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); struct sc8280xp_snd_data *pdata = snd_soc_card_get_drvdata(rtd->card); - struct sdw_stream_runtime *sruntime = pdata->sruntime[cpu_dai->id]; + struct sdw_stream_runtime *sruntime = qcom_snd_sdw_get_stream(substream); pdata->sruntime[cpu_dai->id] = NULL; sdw_release_stream(sruntime); diff --git a/sound/soc/qcom/sdw.c b/sound/soc/qcom/sdw.c index 7d7981d4295b4..7b2cae92c8129 100644 --- a/sound/soc/qcom/sdw.c +++ b/sound/soc/qcom/sdw.c @@ -7,6 +7,37 @@ #include #include "sdw.h" +static bool qcom_snd_is_sdw_dai(int id) +{ + switch (id) { + case WSA_CODEC_DMA_RX_0: + case WSA_CODEC_DMA_TX_0: + case WSA_CODEC_DMA_RX_1: + case WSA_CODEC_DMA_TX_1: + case WSA_CODEC_DMA_TX_2: + case RX_CODEC_DMA_RX_0: + case TX_CODEC_DMA_TX_0: + case RX_CODEC_DMA_RX_1: + case TX_CODEC_DMA_TX_1: + case RX_CODEC_DMA_RX_2: + case TX_CODEC_DMA_TX_2: + case RX_CODEC_DMA_RX_3: + case TX_CODEC_DMA_TX_3: + case RX_CODEC_DMA_RX_4: + case TX_CODEC_DMA_TX_4: + case RX_CODEC_DMA_RX_5: + case TX_CODEC_DMA_TX_5: + case RX_CODEC_DMA_RX_6: + case RX_CODEC_DMA_RX_7: + case SLIMBUS_0_RX...SLIMBUS_6_TX: + return true; + default: + break; + } + + return false; +} + /** * qcom_snd_sdw_startup() - Helper to start Soundwire stream for SoC audio card * @substream: The PCM substream from audio, as passed to snd_soc_ops->startup() @@ -29,6 +60,9 @@ int qcom_snd_sdw_startup(struct snd_pcm_substream *substream) u32 rx_ch_cnt = 0, tx_ch_cnt = 0; int ret, i, j; + if (!qcom_snd_is_sdw_dai(cpu_dai->id)) + return 0; + sruntime = sdw_alloc_stream(cpu_dai->name, SDW_STREAM_PCM); if (!sruntime) return -ENOMEM; @@ -89,19 +123,8 @@ int qcom_snd_sdw_prepare(struct snd_pcm_substream *substream, if (!sruntime) return 0; - switch (cpu_dai->id) { - case WSA_CODEC_DMA_RX_0: - case WSA_CODEC_DMA_RX_1: - case RX_CODEC_DMA_RX_0: - case RX_CODEC_DMA_RX_1: - case TX_CODEC_DMA_TX_0: - case TX_CODEC_DMA_TX_1: - case TX_CODEC_DMA_TX_2: - case TX_CODEC_DMA_TX_3: - break; - default: + if (!qcom_snd_is_sdw_dai(cpu_dai->id)) return 0; - } if (*stream_prepared) return 0; @@ -129,9 +152,7 @@ int qcom_snd_sdw_prepare(struct snd_pcm_substream *substream, } EXPORT_SYMBOL_GPL(qcom_snd_sdw_prepare); -int qcom_snd_sdw_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct sdw_stream_runtime **psruntime) +struct sdw_stream_runtime *qcom_snd_sdw_get_stream(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct snd_soc_dai *codec_dai; @@ -139,21 +160,23 @@ int qcom_snd_sdw_hw_params(struct snd_pcm_substream *substream, struct sdw_stream_runtime *sruntime; int i; - switch (cpu_dai->id) { - case WSA_CODEC_DMA_RX_0: - case RX_CODEC_DMA_RX_0: - case RX_CODEC_DMA_RX_1: - case TX_CODEC_DMA_TX_0: - case TX_CODEC_DMA_TX_1: - case TX_CODEC_DMA_TX_2: - case TX_CODEC_DMA_TX_3: - for_each_rtd_codec_dais(rtd, i, codec_dai) { - sruntime = snd_soc_dai_get_stream(codec_dai, substream->stream); - if (sruntime != ERR_PTR(-ENOTSUPP)) - *psruntime = sruntime; - } - break; + if (!qcom_snd_is_sdw_dai(cpu_dai->id)) + return NULL; + + for_each_rtd_codec_dais(rtd, i, codec_dai) { + sruntime = snd_soc_dai_get_stream(codec_dai, substream->stream); + if (sruntime != ERR_PTR(-ENOTSUPP)) + return sruntime; } + return NULL; +} +EXPORT_SYMBOL_GPL(qcom_snd_sdw_get_stream); + +int qcom_snd_sdw_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct sdw_stream_runtime **psruntime) +{ + *psruntime = qcom_snd_sdw_get_stream(substream); return 0; @@ -166,23 +189,13 @@ int qcom_snd_sdw_hw_free(struct snd_pcm_substream *substream, struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); - switch (cpu_dai->id) { - case WSA_CODEC_DMA_RX_0: - case WSA_CODEC_DMA_RX_1: - case RX_CODEC_DMA_RX_0: - case RX_CODEC_DMA_RX_1: - case TX_CODEC_DMA_TX_0: - case TX_CODEC_DMA_TX_1: - case TX_CODEC_DMA_TX_2: - case TX_CODEC_DMA_TX_3: - if (sruntime && *stream_prepared) { - sdw_disable_stream(sruntime); - sdw_deprepare_stream(sruntime); - *stream_prepared = false; - } - break; - default: - break; + if (!qcom_snd_is_sdw_dai(cpu_dai->id)) + return 0; + + if (sruntime && *stream_prepared) { + sdw_disable_stream(sruntime); + sdw_deprepare_stream(sruntime); + *stream_prepared = false; } return 0; diff --git a/sound/soc/qcom/sdw.h b/sound/soc/qcom/sdw.h index 392e3455f1b19..b8bc5beb05223 100644 --- a/sound/soc/qcom/sdw.h +++ b/sound/soc/qcom/sdw.h @@ -10,6 +10,7 @@ int qcom_snd_sdw_startup(struct snd_pcm_substream *substream); int qcom_snd_sdw_prepare(struct snd_pcm_substream *substream, struct sdw_stream_runtime *runtime, bool *stream_prepared); +struct sdw_stream_runtime *qcom_snd_sdw_get_stream(struct snd_pcm_substream *stream); int qcom_snd_sdw_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct sdw_stream_runtime **psruntime); diff --git a/sound/soc/qcom/sm8250.c b/sound/soc/qcom/sm8250.c index f5b75a06e5bd2..ce5b0059207f1 100644 --- a/sound/soc/qcom/sm8250.c +++ b/sound/soc/qcom/sm8250.c @@ -117,7 +117,7 @@ static void sm8250_snd_shutdown(struct snd_pcm_substream *substream) struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); struct sm8250_snd_data *data = snd_soc_card_get_drvdata(rtd->card); - struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id]; + struct sdw_stream_runtime *sruntime = qcom_snd_sdw_get_stream(substream); data->sruntime[cpu_dai->id] = NULL; sdw_release_stream(sruntime); diff --git a/sound/soc/qcom/x1e80100.c b/sound/soc/qcom/x1e80100.c index 444f2162889f7..2e3599516aa2a 100644 --- a/sound/soc/qcom/x1e80100.c +++ b/sound/soc/qcom/x1e80100.c @@ -55,7 +55,7 @@ static void x1e80100_snd_shutdown(struct snd_pcm_substream *substream) struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); struct x1e80100_snd_data *data = snd_soc_card_get_drvdata(rtd->card); - struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id]; + struct sdw_stream_runtime *sruntime = qcom_snd_sdw_get_stream(substream); data->sruntime[cpu_dai->id] = NULL; sdw_release_stream(sruntime); From fb7d608aa7c4f5dbbdccf6bf035f714c0197f4b6 Mon Sep 17 00:00:00 2001 From: Eric Naim Date: Sun, 7 Dec 2025 03:38:12 +0800 Subject: [PATCH 1548/2333] ASoC: cs35l41: Always return 0 when a subsystem ID is found commit b0ff70e9d4fe46cece25eb97b9b9b0166624af95 upstream. When trying to get the system name in the _HID path, after successfully retrieving the subsystem ID the return value isn't set to 0 but instead still kept at -ENODATA, leading to a false negative: [ 12.382507] cs35l41 spi-VLV1776:00: Subsystem ID: VLV1776 [ 12.382521] cs35l41 spi-VLV1776:00: probe with driver cs35l41 failed with error -61 Always return 0 when a subsystem ID is found to mitigate these false negatives. Link: https://github.com/CachyOS/CachyOS-Handheld/issues/83 Fixes: 46c8b4d2a693 ("ASoC: cs35l41: Fallback to reading Subsystem ID property if not ACPI") Cc: stable@vger.kernel.org # 6.18 Signed-off-by: Eric Naim Reviewed-by: Richard Fitzgerald Link: https://patch.msgid.link/20251206193813.56955-1-dnaim@cachyos.org Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/codecs/cs35l41.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/cs35l41.c b/sound/soc/codecs/cs35l41.c index 173d7c59b7254..5001a546a3e75 100644 --- a/sound/soc/codecs/cs35l41.c +++ b/sound/soc/codecs/cs35l41.c @@ -1188,13 +1188,14 @@ static int cs35l41_get_system_name(struct cs35l41_private *cs35l41) } } -err: if (sub) { cs35l41->dsp.system_name = sub; dev_info(cs35l41->dev, "Subsystem ID: %s\n", cs35l41->dsp.system_name); - } else - dev_warn(cs35l41->dev, "Subsystem ID not found\n"); + return 0; + } +err: + dev_warn(cs35l41->dev, "Subsystem ID not found\n"); return ret; } From 150352153ac9aa3fc995b94946dc7d897f0be354 Mon Sep 17 00:00:00 2001 From: Ma Ke Date: Sun, 16 Nov 2025 11:37:16 +0800 Subject: [PATCH 1549/2333] ASoC: codecs: Fix error handling in pm4125 audio codec driver commit 2196e8172bee2002e9baaa0d02b2f9f2dd213949 upstream. pm4125_bind() acquires references through pm4125_sdw_device_get() but fails to release them in error paths and during normal unbind operations. This could result in reference count leaks, preventing proper cleanup and potentially causing resource exhaustion over multiple bind/unbind cycles. Calling path: pm4125_sdw_device_get() -> bus_find_device_by_of_node() -> bus_find_device() -> get_device. Found by code review. Cc: stable@vger.kernel.org Fixes: 8ad529484937 ("ASoC: codecs: add new pm4125 audio codec driver") Signed-off-by: Ma Ke Reviewed-by: Dmitry Baryshkov Link: https://patch.msgid.link/20251116033716.29369-1-make24@iscas.ac.cn Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/codecs/pm4125.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/pm4125.c b/sound/soc/codecs/pm4125.c index 3657a4a759855..3d7b07624ee61 100644 --- a/sound/soc/codecs/pm4125.c +++ b/sound/soc/codecs/pm4125.c @@ -1549,6 +1549,10 @@ static int pm4125_bind(struct device *dev) struct device_link *devlink; int ret; + /* Initialize device pointers to NULL for safe cleanup */ + pm4125->rxdev = NULL; + pm4125->txdev = NULL; + /* Give the soundwire subdevices some more time to settle */ usleep_range(15000, 15010); @@ -1572,7 +1576,7 @@ static int pm4125_bind(struct device *dev) if (!pm4125->txdev) { dev_err(dev, "could not find txslave with matching of node\n"); ret = -EINVAL; - goto error_unbind_all; + goto error_put_rx; } pm4125->sdw_priv[AIF1_CAP] = dev_get_drvdata(pm4125->txdev); @@ -1582,7 +1586,7 @@ static int pm4125_bind(struct device *dev) if (!pm4125->tx_sdw_dev) { dev_err(dev, "could not get txslave with matching of dev\n"); ret = -EINVAL; - goto error_unbind_all; + goto error_put_tx; } /* @@ -1594,7 +1598,7 @@ static int pm4125_bind(struct device *dev) if (!devlink) { dev_err(dev, "Could not devlink TX and RX\n"); ret = -EINVAL; - goto error_unbind_all; + goto error_put_tx; } devlink = device_link_add(dev, pm4125->txdev, @@ -1648,6 +1652,10 @@ static int pm4125_bind(struct device *dev) device_link_remove(dev, pm4125->txdev); link_remove_rx_tx: device_link_remove(pm4125->rxdev, pm4125->txdev); +error_put_tx: + put_device(pm4125->txdev); +error_put_rx: + put_device(pm4125->rxdev); error_unbind_all: component_unbind_all(dev, pm4125); return ret; @@ -1663,6 +1671,13 @@ static void pm4125_unbind(struct device *dev) device_link_remove(dev, pm4125->txdev); device_link_remove(dev, pm4125->rxdev); device_link_remove(pm4125->rxdev, pm4125->txdev); + + /* Release device references acquired in bind */ + if (pm4125->txdev) + put_device(pm4125->txdev); + if (pm4125->rxdev) + put_device(pm4125->rxdev); + component_unbind_all(dev, pm4125); } From c5c85ef27db6ae6e949baa73b7768857431c2863 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Thu, 23 Oct 2025 11:24:25 +0100 Subject: [PATCH 1550/2333] ASoC: qcom: q6apm-dai: set flags to reflect correct operation of appl_ptr commit 950a4e5788fc7dc6e8e93614a7d4d0449c39fb8d upstream. Driver does not expect the appl_ptr to move backward and requires explict sync. Make sure that the userspace does not do appl_ptr rewinds by specifying the correct flags in pcm_info. Without this patch, the result could be a forever loop as current logic assumes that appl_ptr can only move forward. Fixes: 3d4a4411aa8b ("ASoC: q6apm-dai: schedule all available frames to avoid dsp under-runs") Cc: Stable@vger.kernel.org Signed-off-by: Srinivas Kandagatla Tested-by: Alexey Klimov # RB5, RB3 Link: https://patch.msgid.link/20251023102444.88158-2-srinivas.kandagatla@oss.qualcomm.com Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/qcom/qdsp6/q6apm-dai.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/qcom/qdsp6/q6apm-dai.c b/sound/soc/qcom/qdsp6/q6apm-dai.c index 4ecaff45c5186..786ab3222515c 100644 --- a/sound/soc/qcom/qdsp6/q6apm-dai.c +++ b/sound/soc/qcom/qdsp6/q6apm-dai.c @@ -86,6 +86,7 @@ static const struct snd_pcm_hardware q6apm_dai_hardware_capture = { .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME | + SNDRV_PCM_INFO_NO_REWINDS | SNDRV_PCM_INFO_SYNC_APPLPTR | SNDRV_PCM_INFO_BATCH), .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE), .rates = SNDRV_PCM_RATE_8000_48000, @@ -105,6 +106,7 @@ static const struct snd_pcm_hardware q6apm_dai_hardware_playback = { .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME | + SNDRV_PCM_INFO_NO_REWINDS | SNDRV_PCM_INFO_SYNC_APPLPTR | SNDRV_PCM_INFO_BATCH), .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE), .rates = SNDRV_PCM_RATE_8000_192000, From cd5691807ba602fd3ec40625d2c68614eaa505dc Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Thu, 23 Oct 2025 11:24:28 +0100 Subject: [PATCH 1551/2333] ASoC: qcom: q6asm-dai: perform correct state check before closing commit bfbb12dfa144d45575bcfe139a71360b3ce80237 upstream. Do not stop a q6asm stream if its not started, this can result in unnecessary dsp command which will timeout anyway something like below: q6asm-dai ab00000.remoteproc:glink-edge:apr:service@7:dais: CMD 10bcd timeout Fix this by correctly checking the state. Fixes: 2a9e92d371db ("ASoC: qdsp6: q6asm: Add q6asm dai driver") Cc: Stable@vger.kernel.org Signed-off-by: Srinivas Kandagatla Tested-by: Alexey Klimov # RB5, RB3 Link: https://patch.msgid.link/20251023102444.88158-5-srinivas.kandagatla@oss.qualcomm.com Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/qcom/qdsp6/q6asm-dai.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/qcom/qdsp6/q6asm-dai.c b/sound/soc/qcom/qdsp6/q6asm-dai.c index b616ce316d2f1..8e0b2db8a2db0 100644 --- a/sound/soc/qcom/qdsp6/q6asm-dai.c +++ b/sound/soc/qcom/qdsp6/q6asm-dai.c @@ -233,13 +233,14 @@ static int q6asm_dai_prepare(struct snd_soc_component *component, prtd->pcm_count = snd_pcm_lib_period_bytes(substream); prtd->pcm_irq_pos = 0; /* rate and channels are sent to audio driver */ - if (prtd->state) { + if (prtd->state == Q6ASM_STREAM_RUNNING) { /* clear the previous setup if any */ q6asm_cmd(prtd->audio_client, prtd->stream_id, CMD_CLOSE); q6asm_unmap_memory_regions(substream->stream, prtd->audio_client); q6routing_stream_close(soc_prtd->dai_link->id, substream->stream); + prtd->state = Q6ASM_STREAM_STOPPED; } ret = q6asm_map_memory_regions(substream->stream, prtd->audio_client, From 372796af87d3d0ddccae4f19d930efc367913e5c Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Thu, 23 Oct 2025 11:24:26 +0100 Subject: [PATCH 1552/2333] ASoC: qcom: q6adm: the the copp device only during last instance commit 74cc4f3ea4e99262ba0d619c6a4ee33e2cd47f65 upstream. A matching Common object post processing instance is normally resused across multiple streams. However currently we close this on DSP even though there is a refcount on this copp object, this can result in below error. q6routing ab00000.remoteproc:glink-edge:apr:service@8:routing: Found Matching Copp 0x0 qcom-q6adm aprsvc:service:4:8: cmd = 0x10325 return error = 0x2 q6routing ab00000.remoteproc:glink-edge:apr:service@8:routing: DSP returned error[2] q6routing ab00000.remoteproc:glink-edge:apr:service@8:routing: Found Matching Copp 0x0 qcom-q6adm aprsvc:service:4:8: cmd = 0x10325 return error = 0x2 q6routing ab00000.remoteproc:glink-edge:apr:service@8:routing: DSP returned error[2] qcom-q6adm aprsvc:service:4:8: cmd = 0x10327 return error = 0x2 qcom-q6adm aprsvc:service:4:8: DSP returned error[2] qcom-q6adm aprsvc:service:4:8: Failed to close copp -22 qcom-q6adm aprsvc:service:4:8: cmd = 0x10327 return error = 0x2 qcom-q6adm aprsvc:service:4:8: DSP returned error[2] qcom-q6adm aprsvc:service:4:8: Failed to close copp -22 Fix this by addressing moving the adm_close to copp_kref destructor callback. Fixes: 7b20b2be51e1 ("ASoC: qdsp6: q6adm: Add q6adm driver") Cc: Stable@vger.kernel.org Reported-by: Martino Facchin Signed-off-by: Srinivas Kandagatla Tested-by: Alexey Klimov # RB5, RB3 Link: https://patch.msgid.link/20251023102444.88158-3-srinivas.kandagatla@oss.qualcomm.com Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/qcom/qdsp6/q6adm.c | 146 +++++++++++++++++------------------ 1 file changed, 71 insertions(+), 75 deletions(-) diff --git a/sound/soc/qcom/qdsp6/q6adm.c b/sound/soc/qcom/qdsp6/q6adm.c index 1530e98df1656..75a029a696ac9 100644 --- a/sound/soc/qcom/qdsp6/q6adm.c +++ b/sound/soc/qcom/qdsp6/q6adm.c @@ -109,11 +109,75 @@ static struct q6copp *q6adm_find_copp(struct q6adm *adm, int port_idx, } +static int q6adm_apr_send_copp_pkt(struct q6adm *adm, struct q6copp *copp, + struct apr_pkt *pkt, uint32_t rsp_opcode) +{ + struct device *dev = adm->dev; + uint32_t opcode = pkt->hdr.opcode; + int ret; + + mutex_lock(&adm->lock); + copp->result.opcode = 0; + copp->result.status = 0; + ret = apr_send_pkt(adm->apr, pkt); + if (ret < 0) { + dev_err(dev, "Failed to send APR packet\n"); + ret = -EINVAL; + goto err; + } + + /* Wait for the callback with copp id */ + if (rsp_opcode) + ret = wait_event_timeout(copp->wait, + (copp->result.opcode == opcode) || + (copp->result.opcode == rsp_opcode), + msecs_to_jiffies(TIMEOUT_MS)); + else + ret = wait_event_timeout(copp->wait, + (copp->result.opcode == opcode), + msecs_to_jiffies(TIMEOUT_MS)); + + if (!ret) { + dev_err(dev, "ADM copp cmd timedout\n"); + ret = -ETIMEDOUT; + } else if (copp->result.status > 0) { + dev_err(dev, "DSP returned error[%d]\n", + copp->result.status); + ret = -EINVAL; + } + +err: + mutex_unlock(&adm->lock); + return ret; +} + +static int q6adm_device_close(struct q6adm *adm, struct q6copp *copp, + int port_id, int copp_idx) +{ + struct apr_pkt close; + + close.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, + APR_HDR_LEN(APR_HDR_SIZE), + APR_PKT_VER); + close.hdr.pkt_size = sizeof(close); + close.hdr.src_port = port_id; + close.hdr.dest_port = copp->id; + close.hdr.token = port_id << 16 | copp_idx; + close.hdr.opcode = ADM_CMD_DEVICE_CLOSE_V5; + + return q6adm_apr_send_copp_pkt(adm, copp, &close, 0); +} + static void q6adm_free_copp(struct kref *ref) { struct q6copp *c = container_of(ref, struct q6copp, refcount); struct q6adm *adm = c->adm; unsigned long flags; + int ret; + + ret = q6adm_device_close(adm, c, c->afe_port, c->copp_idx); + if (ret < 0) + dev_err(adm->dev, "Failed to close copp %d\n", ret); spin_lock_irqsave(&adm->copps_list_lock, flags); clear_bit(c->copp_idx, &adm->copp_bitmap[c->afe_port]); @@ -155,13 +219,13 @@ static int q6adm_callback(struct apr_device *adev, struct apr_resp_pkt *data) switch (result->opcode) { case ADM_CMD_DEVICE_OPEN_V5: case ADM_CMD_DEVICE_CLOSE_V5: - copp = q6adm_find_copp(adm, port_idx, copp_idx); - if (!copp) - return 0; - - copp->result = *result; - wake_up(&copp->wait); - kref_put(&copp->refcount, q6adm_free_copp); + list_for_each_entry(copp, &adm->copps_list, node) { + if ((port_idx == copp->afe_port) && (copp_idx == copp->copp_idx)) { + copp->result = *result; + wake_up(&copp->wait); + break; + } + } break; case ADM_CMD_MATRIX_MAP_ROUTINGS_V5: adm->result = *result; @@ -234,65 +298,6 @@ static struct q6copp *q6adm_alloc_copp(struct q6adm *adm, int port_idx) return c; } -static int q6adm_apr_send_copp_pkt(struct q6adm *adm, struct q6copp *copp, - struct apr_pkt *pkt, uint32_t rsp_opcode) -{ - struct device *dev = adm->dev; - uint32_t opcode = pkt->hdr.opcode; - int ret; - - mutex_lock(&adm->lock); - copp->result.opcode = 0; - copp->result.status = 0; - ret = apr_send_pkt(adm->apr, pkt); - if (ret < 0) { - dev_err(dev, "Failed to send APR packet\n"); - ret = -EINVAL; - goto err; - } - - /* Wait for the callback with copp id */ - if (rsp_opcode) - ret = wait_event_timeout(copp->wait, - (copp->result.opcode == opcode) || - (copp->result.opcode == rsp_opcode), - msecs_to_jiffies(TIMEOUT_MS)); - else - ret = wait_event_timeout(copp->wait, - (copp->result.opcode == opcode), - msecs_to_jiffies(TIMEOUT_MS)); - - if (!ret) { - dev_err(dev, "ADM copp cmd timedout\n"); - ret = -ETIMEDOUT; - } else if (copp->result.status > 0) { - dev_err(dev, "DSP returned error[%d]\n", - copp->result.status); - ret = -EINVAL; - } - -err: - mutex_unlock(&adm->lock); - return ret; -} - -static int q6adm_device_close(struct q6adm *adm, struct q6copp *copp, - int port_id, int copp_idx) -{ - struct apr_pkt close; - - close.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, - APR_HDR_LEN(APR_HDR_SIZE), - APR_PKT_VER); - close.hdr.pkt_size = sizeof(close); - close.hdr.src_port = port_id; - close.hdr.dest_port = copp->id; - close.hdr.token = port_id << 16 | copp_idx; - close.hdr.opcode = ADM_CMD_DEVICE_CLOSE_V5; - - return q6adm_apr_send_copp_pkt(adm, copp, &close, 0); -} - static struct q6copp *q6adm_find_matching_copp(struct q6adm *adm, int port_id, int topology, int mode, int rate, @@ -567,15 +572,6 @@ EXPORT_SYMBOL_GPL(q6adm_matrix_map); */ int q6adm_close(struct device *dev, struct q6copp *copp) { - struct q6adm *adm = dev_get_drvdata(dev->parent); - int ret = 0; - - ret = q6adm_device_close(adm, copp, copp->afe_port, copp->copp_idx); - if (ret < 0) { - dev_err(adm->dev, "Failed to close copp %d\n", ret); - return ret; - } - kref_put(&copp->refcount, q6adm_free_copp); return 0; From 00ed0cc57232a453f825bcbe0bf7367c9aeceab3 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Thu, 23 Oct 2025 11:24:27 +0100 Subject: [PATCH 1553/2333] ASoC: qcom: qdsp6: q6asm-dai: set 10 ms period and buffer alignment. commit 81c53b52de21b8d5a3de55ebd06b6bf188bf7efd upstream. DSP expects the periods to be aligned to fragment sizes, currently setting up to hw constriants on periods bytes is not going to work correctly as we can endup with periods sizes aligned to 32 bytes however not aligned to fragment size. Update the constriants to use fragment size, and also set at step of 10ms for period size to accommodate DSP requirements of 10ms latency. Fixes: 2a9e92d371db ("ASoC: qdsp6: q6asm: Add q6asm dai driver") Cc: Stable@vger.kernel.org Signed-off-by: Srinivas Kandagatla Tested-by: Alexey Klimov # RB5, RB3 Link: https://patch.msgid.link/20251023102444.88158-4-srinivas.kandagatla@oss.qualcomm.com Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/qcom/qdsp6/q6asm-dai.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/qcom/qdsp6/q6asm-dai.c b/sound/soc/qcom/qdsp6/q6asm-dai.c index 8e0b2db8a2db0..0eae8c6e42b8a 100644 --- a/sound/soc/qcom/qdsp6/q6asm-dai.c +++ b/sound/soc/qcom/qdsp6/q6asm-dai.c @@ -404,13 +404,13 @@ static int q6asm_dai_open(struct snd_soc_component *component, } ret = snd_pcm_hw_constraint_step(runtime, 0, - SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 32); + SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 480); if (ret < 0) { dev_err(dev, "constraint for period bytes step ret = %d\n", ret); } ret = snd_pcm_hw_constraint_step(runtime, 0, - SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 32); + SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 480); if (ret < 0) { dev_err(dev, "constraint for buffer bytes step ret = %d\n", ret); From 47bed96dc7d5151dadd66f60509a75eb33f7d6ef Mon Sep 17 00:00:00 2001 From: Jinhui Guo Date: Tue, 28 Oct 2025 00:50:17 +0800 Subject: [PATCH 1554/2333] iommu/amd: Fix pci_segment memleak in alloc_pci_segment() commit 75ba146c2674ba49ed8a222c67f9abfb4a4f2a4f upstream. Fix a memory leak of struct amd_iommu_pci_segment in alloc_pci_segment() when system memory (or contiguous memory) is insufficient. Fixes: 04230c119930 ("iommu/amd: Introduce per PCI segment device table") Fixes: eda797a27795 ("iommu/amd: Introduce per PCI segment rlookup table") Fixes: 99fc4ac3d297 ("iommu/amd: Introduce per PCI segment alias_table") Cc: stable@vger.kernel.org Signed-off-by: Jinhui Guo Signed-off-by: Joerg Roedel Signed-off-by: Greg Kroah-Hartman --- drivers/iommu/amd/init.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c index 14eb9de33ccb0..034edce816d01 100644 --- a/drivers/iommu/amd/init.c +++ b/drivers/iommu/amd/init.c @@ -1731,13 +1731,22 @@ static struct amd_iommu_pci_seg *__init alloc_pci_segment(u16 id, list_add_tail(&pci_seg->list, &amd_iommu_pci_seg_list); if (alloc_dev_table(pci_seg)) - return NULL; + goto err_free_pci_seg; if (alloc_alias_table(pci_seg)) - return NULL; + goto err_free_dev_table; if (alloc_rlookup_table(pci_seg)) - return NULL; + goto err_free_alias_table; return pci_seg; + +err_free_alias_table: + free_alias_table(pci_seg); +err_free_dev_table: + free_dev_table(pci_seg); +err_free_pci_seg: + list_del(&pci_seg->list); + kfree(pci_seg); + return NULL; } static struct amd_iommu_pci_seg *__init get_pci_segment(u16 id, From 67c5f84f9b1cd76664528cb39697fa57b8945724 Mon Sep 17 00:00:00 2001 From: Jinhui Guo Date: Thu, 20 Nov 2025 23:47:25 +0800 Subject: [PATCH 1555/2333] iommu/amd: Propagate the error code returned by __modify_irte_ga() in modify_irte_ga() commit 2381a1b40be4b286062fb3cf67dd7f005692aa2a upstream. The return type of __modify_irte_ga() is int, but modify_irte_ga() treats it as a bool. Casting the int to bool discards the error code. To fix the issue, change the type of ret to int in modify_irte_ga(). Fixes: 57cdb720eaa5 ("iommu/amd: Do not flush IRTE when only updating isRun and destination fields") Cc: stable@vger.kernel.org Signed-off-by: Jinhui Guo Reviewed-by: Vasant Hegde Signed-off-by: Joerg Roedel Signed-off-by: Greg Kroah-Hartman --- drivers/iommu/amd/iommu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c index 2e1865daa1cee..a38304f1a8df5 100644 --- a/drivers/iommu/amd/iommu.c +++ b/drivers/iommu/amd/iommu.c @@ -3354,7 +3354,7 @@ static int __modify_irte_ga(struct amd_iommu *iommu, u16 devid, int index, static int modify_irte_ga(struct amd_iommu *iommu, u16 devid, int index, struct irte_ga *irte) { - bool ret; + int ret; ret = __modify_irte_ga(iommu, devid, index, irte); if (ret) From 9bb0b50a759ee1b37abfc945152d64414fe92c7b Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 20 Oct 2025 06:53:05 +0200 Subject: [PATCH 1556/2333] iommu/apple-dart: fix device leak on of_xlate() commit a6eaa872c52a181ae9a290fd4e40c9df91166d7a upstream. Make sure to drop the reference taken to the iommu platform device when looking up its driver data during of_xlate(). Fixes: 46d1fb072e76 ("iommu/dart: Add DART iommu driver") Cc: stable@vger.kernel.org # 5.15 Cc: Sven Peter Acked-by: Robin Murphy Signed-off-by: Johan Hovold Signed-off-by: Joerg Roedel Signed-off-by: Greg Kroah-Hartman --- drivers/iommu/apple-dart.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/iommu/apple-dart.c b/drivers/iommu/apple-dart.c index 95a4e62b8f63c..9804022c7f590 100644 --- a/drivers/iommu/apple-dart.c +++ b/drivers/iommu/apple-dart.c @@ -802,6 +802,8 @@ static int apple_dart_of_xlate(struct device *dev, struct apple_dart *cfg_dart; int i, sid; + put_device(&iommu_pdev->dev); + if (args->args_count != 1) return -EINVAL; sid = args->args[0]; From b35eeae8a566fe7f32b2a80b7ef2c752d473226a Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 20 Oct 2025 06:53:07 +0200 Subject: [PATCH 1557/2333] iommu/exynos: fix device leak on of_xlate() commit 05913cc43cb122f9afecdbe775115c058b906e1b upstream. Make sure to drop the reference taken to the iommu platform device when looking up its driver data during of_xlate(). Note that commit 1a26044954a6 ("iommu/exynos: add missing put_device() call in exynos_iommu_of_xlate()") fixed the leak in a couple of error paths, but the reference is still leaking on success. Fixes: aa759fd376fb ("iommu/exynos: Add callback for initializing devices from device tree") Cc: stable@vger.kernel.org # 4.2: 1a26044954a6 Cc: Yu Kuai Acked-by: Robin Murphy Acked-by: Marek Szyprowski Signed-off-by: Johan Hovold Signed-off-by: Joerg Roedel Signed-off-by: Greg Kroah-Hartman --- drivers/iommu/exynos-iommu.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c index b6edd178fe25e..ce9e935cb84c3 100644 --- a/drivers/iommu/exynos-iommu.c +++ b/drivers/iommu/exynos-iommu.c @@ -1446,17 +1446,14 @@ static int exynos_iommu_of_xlate(struct device *dev, return -ENODEV; data = platform_get_drvdata(sysmmu); - if (!data) { - put_device(&sysmmu->dev); + put_device(&sysmmu->dev); + if (!data) return -ENODEV; - } if (!owner) { owner = kzalloc(sizeof(*owner), GFP_KERNEL); - if (!owner) { - put_device(&sysmmu->dev); + if (!owner) return -ENOMEM; - } INIT_LIST_HEAD(&owner->controllers); mutex_init(&owner->rpm_lock); From ba202227f98d1ba4505134e8c88135c1a6b6993b Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 20 Oct 2025 06:53:08 +0200 Subject: [PATCH 1558/2333] iommu/ipmmu-vmsa: fix device leak on of_xlate() commit 80aa518452c4aceb9459f9a8e3184db657d1b441 upstream. Make sure to drop the reference taken to the iommu platform device when looking up its driver data during of_xlate(). Fixes: 7b2d59611fef ("iommu/ipmmu-vmsa: Replace local utlb code with fwspec ids") Cc: stable@vger.kernel.org # 4.14 Cc: Magnus Damm Acked-by: Robin Murphy Signed-off-by: Johan Hovold Signed-off-by: Joerg Roedel Signed-off-by: Greg Kroah-Hartman --- drivers/iommu/ipmmu-vmsa.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/iommu/ipmmu-vmsa.c b/drivers/iommu/ipmmu-vmsa.c index ffa892f657140..02a2a55ffa0a0 100644 --- a/drivers/iommu/ipmmu-vmsa.c +++ b/drivers/iommu/ipmmu-vmsa.c @@ -720,6 +720,8 @@ static int ipmmu_init_platform_device(struct device *dev, dev_iommu_priv_set(dev, platform_get_drvdata(ipmmu_pdev)); + put_device(&ipmmu_pdev->dev); + return 0; } From 574635a02526b37626d60187b4036d19c1fdb7e1 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 20 Oct 2025 06:53:12 +0200 Subject: [PATCH 1559/2333] iommu/mediatek-v1: fix device leak on probe_device() commit c77ad28bfee0df9cbc719eb5adc9864462cfb65b upstream. Make sure to drop the reference taken to the iommu platform device when looking up its driver data during probe_device(). Fixes: b17336c55d89 ("iommu/mediatek: add support for mtk iommu generation one HW") Cc: stable@vger.kernel.org # 4.8 Cc: Honghui Zhang Acked-by: Robin Murphy Reviewed-by: Yong Wu Signed-off-by: Johan Hovold Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Joerg Roedel Signed-off-by: Greg Kroah-Hartman --- drivers/iommu/mtk_iommu_v1.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/iommu/mtk_iommu_v1.c b/drivers/iommu/mtk_iommu_v1.c index 10cc0b1197e80..de9153c0a82f7 100644 --- a/drivers/iommu/mtk_iommu_v1.c +++ b/drivers/iommu/mtk_iommu_v1.c @@ -435,6 +435,8 @@ static int mtk_iommu_v1_create_mapping(struct device *dev, return -EINVAL; dev_iommu_priv_set(dev, platform_get_drvdata(m4updev)); + + put_device(&m4updev->dev); } ret = iommu_fwspec_add_ids(dev, args->args, 1); From fa3cb4012fb22ad7e64a47e55c0598577be492c6 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 20 Oct 2025 06:53:13 +0200 Subject: [PATCH 1560/2333] iommu/mediatek-v1: fix device leaks on probe() commit 46207625c9f33da0e43bb4ae1e91f0791b6ed633 upstream. Make sure to drop the references taken to the larb devices during probe on probe failure (e.g. probe deferral) and on driver unbind. Fixes: b17336c55d89 ("iommu/mediatek: add support for mtk iommu generation one HW") Cc: stable@vger.kernel.org # 4.8 Cc: Honghui Zhang Acked-by: Robin Murphy Signed-off-by: Johan Hovold Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Joerg Roedel Signed-off-by: Greg Kroah-Hartman --- drivers/iommu/mtk_iommu_v1.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/drivers/iommu/mtk_iommu_v1.c b/drivers/iommu/mtk_iommu_v1.c index de9153c0a82f7..44b965a2db923 100644 --- a/drivers/iommu/mtk_iommu_v1.c +++ b/drivers/iommu/mtk_iommu_v1.c @@ -648,8 +648,10 @@ static int mtk_iommu_v1_probe(struct platform_device *pdev) struct platform_device *plarbdev; larbnode = of_parse_phandle(dev->of_node, "mediatek,larbs", i); - if (!larbnode) - return -EINVAL; + if (!larbnode) { + ret = -EINVAL; + goto out_put_larbs; + } if (!of_device_is_available(larbnode)) { of_node_put(larbnode); @@ -659,11 +661,14 @@ static int mtk_iommu_v1_probe(struct platform_device *pdev) plarbdev = of_find_device_by_node(larbnode); if (!plarbdev) { of_node_put(larbnode); - return -ENODEV; + ret = -ENODEV; + goto out_put_larbs; } if (!plarbdev->dev.driver) { of_node_put(larbnode); - return -EPROBE_DEFER; + put_device(&plarbdev->dev); + ret = -EPROBE_DEFER; + goto out_put_larbs; } data->larb_imu[i].dev = &plarbdev->dev; @@ -675,7 +680,7 @@ static int mtk_iommu_v1_probe(struct platform_device *pdev) ret = mtk_iommu_v1_hw_init(data); if (ret) - return ret; + goto out_put_larbs; ret = iommu_device_sysfs_add(&data->iommu, &pdev->dev, NULL, dev_name(&pdev->dev)); @@ -697,12 +702,17 @@ static int mtk_iommu_v1_probe(struct platform_device *pdev) iommu_device_sysfs_remove(&data->iommu); out_clk_unprepare: clk_disable_unprepare(data->bclk); +out_put_larbs: + for (i = 0; i < MTK_LARB_NR_MAX; i++) + put_device(data->larb_imu[i].dev); + return ret; } static void mtk_iommu_v1_remove(struct platform_device *pdev) { struct mtk_iommu_v1_data *data = platform_get_drvdata(pdev); + int i; iommu_device_sysfs_remove(&data->iommu); iommu_device_unregister(&data->iommu); @@ -710,6 +720,9 @@ static void mtk_iommu_v1_remove(struct platform_device *pdev) clk_disable_unprepare(data->bclk); devm_free_irq(&pdev->dev, data->irq, data); component_master_del(&pdev->dev, &mtk_iommu_v1_com_ops); + + for (i = 0; i < MTK_LARB_NR_MAX; i++) + put_device(data->larb_imu[i].dev); } static int __maybe_unused mtk_iommu_v1_suspend(struct device *dev) From c2a13167991fa306ebf657a81d13d3f3070eb9d9 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 20 Oct 2025 06:53:09 +0200 Subject: [PATCH 1561/2333] iommu/mediatek: fix device leak on of_xlate() commit b3f1ee18280363ef17f82b564fc379ceba9ec86f upstream. Make sure to drop the reference taken to the iommu platform device when looking up its driver data during of_xlate(). Fixes: 0df4fabe208d ("iommu/mediatek: Add mt8173 IOMMU driver") Cc: stable@vger.kernel.org # 4.6 Acked-by: Robin Murphy Reviewed-by: Yong Wu Signed-off-by: Johan Hovold Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Joerg Roedel Signed-off-by: Greg Kroah-Hartman --- drivers/iommu/mtk_iommu.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c index 319974557f325..64ce041238fd3 100644 --- a/drivers/iommu/mtk_iommu.c +++ b/drivers/iommu/mtk_iommu.c @@ -974,6 +974,8 @@ static int mtk_iommu_of_xlate(struct device *dev, return -EINVAL; dev_iommu_priv_set(dev, platform_get_drvdata(m4updev)); + + put_device(&m4updev->dev); } return iommu_fwspec_add_ids(dev, args->args, 1); From d496519ccd7ebd0eb038cd4ef41b70422100d0c5 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 20 Oct 2025 06:53:15 +0200 Subject: [PATCH 1562/2333] iommu/omap: fix device leaks on probe_device() commit b5870691065e6bbe6ba0650c0412636c6a239c5a upstream. Make sure to drop the references taken to the iommu platform devices when looking up their driver data during probe_device(). Note that the arch data device pointer added by commit 604629bcb505 ("iommu/omap: add support for late attachment of iommu devices") has never been used. Remove it to underline that the references are not needed. Fixes: 9d5018deec86 ("iommu/omap: Add support to program multiple iommus") Fixes: 7d6827748d54 ("iommu/omap: Fix iommu archdata name for DT-based devices") Cc: stable@vger.kernel.org # 3.18 Cc: Suman Anna Acked-by: Robin Murphy Signed-off-by: Johan Hovold Signed-off-by: Joerg Roedel Signed-off-by: Greg Kroah-Hartman --- drivers/iommu/omap-iommu.c | 2 +- drivers/iommu/omap-iommu.h | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/iommu/omap-iommu.c b/drivers/iommu/omap-iommu.c index 5c6f5943f44b1..c0315c86cd187 100644 --- a/drivers/iommu/omap-iommu.c +++ b/drivers/iommu/omap-iommu.c @@ -1675,6 +1675,7 @@ static struct iommu_device *omap_iommu_probe_device(struct device *dev) } oiommu = platform_get_drvdata(pdev); + put_device(&pdev->dev); if (!oiommu) { of_node_put(np); kfree(arch_data); @@ -1682,7 +1683,6 @@ static struct iommu_device *omap_iommu_probe_device(struct device *dev) } tmp->iommu_dev = oiommu; - tmp->dev = &pdev->dev; of_node_put(np); } diff --git a/drivers/iommu/omap-iommu.h b/drivers/iommu/omap-iommu.h index 27697109ec79a..50b39be61abc7 100644 --- a/drivers/iommu/omap-iommu.h +++ b/drivers/iommu/omap-iommu.h @@ -88,7 +88,6 @@ struct omap_iommu { /** * struct omap_iommu_arch_data - omap iommu private data * @iommu_dev: handle of the OMAP iommu device - * @dev: handle of the iommu device * * This is an omap iommu private data object, which binds an iommu user * to its iommu device. This object should be placed at the iommu user's @@ -97,7 +96,6 @@ struct omap_iommu { */ struct omap_iommu_arch_data { struct omap_iommu *iommu_dev; - struct device *dev; }; struct cr_regs { From 6b8390fcef610432686b464079955381dcce2c78 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 20 Oct 2025 06:53:06 +0200 Subject: [PATCH 1563/2333] iommu/qcom: fix device leak on of_xlate() commit 6a3908ce56e6879920b44ef136252b2f0c954194 upstream. Make sure to drop the reference taken to the iommu platform device when looking up its driver data during of_xlate(). Note that commit e2eae09939a8 ("iommu/qcom: add missing put_device() call in qcom_iommu_of_xlate()") fixed the leak in a couple of error paths, but the reference is still leaking on success and late failures. Fixes: 0ae349a0f33f ("iommu/qcom: Add qcom_iommu") Cc: stable@vger.kernel.org # 4.14: e2eae09939a8 Cc: Rob Clark Cc: Yu Kuai Acked-by: Robin Murphy Signed-off-by: Johan Hovold Signed-off-by: Joerg Roedel Signed-off-by: Greg Kroah-Hartman --- drivers/iommu/arm/arm-smmu/qcom_iommu.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/iommu/arm/arm-smmu/qcom_iommu.c b/drivers/iommu/arm/arm-smmu/qcom_iommu.c index c5be95e560317..9c1166a3af6c9 100644 --- a/drivers/iommu/arm/arm-smmu/qcom_iommu.c +++ b/drivers/iommu/arm/arm-smmu/qcom_iommu.c @@ -565,14 +565,14 @@ static int qcom_iommu_of_xlate(struct device *dev, qcom_iommu = platform_get_drvdata(iommu_pdev); + put_device(&iommu_pdev->dev); + /* make sure the asid specified in dt is valid, so we don't have * to sanity check this elsewhere: */ if (WARN_ON(asid > qcom_iommu->max_asid) || - WARN_ON(qcom_iommu->ctxs[asid] == NULL)) { - put_device(&iommu_pdev->dev); + WARN_ON(qcom_iommu->ctxs[asid] == NULL)) return -EINVAL; - } if (!dev_iommu_priv_get(dev)) { dev_iommu_priv_set(dev, qcom_iommu); @@ -581,10 +581,8 @@ static int qcom_iommu_of_xlate(struct device *dev, * multiple different iommu devices. Multiple context * banks are ok, but multiple devices are not: */ - if (WARN_ON(qcom_iommu != dev_iommu_priv_get(dev))) { - put_device(&iommu_pdev->dev); + if (WARN_ON(qcom_iommu != dev_iommu_priv_get(dev))) return -EINVAL; - } } return iommu_fwspec_add_ids(dev, &asid, 1); From bd2f551f575c72e326a4eafa23dd7e47cfafc754 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 20 Oct 2025 06:53:17 +0200 Subject: [PATCH 1564/2333] iommu/sun50i: fix device leak on of_xlate() commit f916109bf53864605d10bf6f4215afa023a80406 upstream. Make sure to drop the reference taken to the iommu platform device when looking up its driver data during of_xlate(). Fixes: 4100b8c229b3 ("iommu: Add Allwinner H6 IOMMU driver") Cc: stable@vger.kernel.org # 5.8 Cc: Maxime Ripard Acked-by: Robin Murphy Signed-off-by: Johan Hovold Signed-off-by: Joerg Roedel Signed-off-by: Greg Kroah-Hartman --- drivers/iommu/sun50i-iommu.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/iommu/sun50i-iommu.c b/drivers/iommu/sun50i-iommu.c index de10b569d9a94..6306570d57db4 100644 --- a/drivers/iommu/sun50i-iommu.c +++ b/drivers/iommu/sun50i-iommu.c @@ -839,6 +839,8 @@ static int sun50i_iommu_of_xlate(struct device *dev, dev_iommu_priv_set(dev, platform_get_drvdata(iommu_pdev)); + put_device(&iommu_pdev->dev); + return iommu_fwspec_add_ids(dev, &id, 1); } From b16243e7164c0584049a640e3efa2d3e750f7d33 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 20 Oct 2025 06:53:18 +0200 Subject: [PATCH 1565/2333] iommu/tegra: fix device leak on probe_device() commit c08934a61201db8f1d1c66fcc63fb2eb526b656d upstream. Make sure to drop the reference taken to the iommu platform device when looking up its driver data during probe_device(). Note that commit 9826e393e4a8 ("iommu/tegra-smmu: Fix missing put_device() call in tegra_smmu_find") fixed the leak in an error path, but the reference is still leaking on success. Fixes: 891846516317 ("memory: Add NVIDIA Tegra memory controller support") Cc: stable@vger.kernel.org # 3.19: 9826e393e4a8 Cc: Miaoqian Lin Acked-by: Robin Murphy Acked-by: Thierry Reding Signed-off-by: Johan Hovold Signed-off-by: Joerg Roedel Signed-off-by: Greg Kroah-Hartman --- drivers/iommu/tegra-smmu.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c index 36cdd5fbab077..f6f26a0728208 100644 --- a/drivers/iommu/tegra-smmu.c +++ b/drivers/iommu/tegra-smmu.c @@ -830,10 +830,9 @@ static struct tegra_smmu *tegra_smmu_find(struct device_node *np) return NULL; mc = platform_get_drvdata(pdev); - if (!mc) { - put_device(&pdev->dev); + put_device(&pdev->dev); + if (!mc) return NULL; - } return mc->smmu; } From c341dee80b5df49a936182341b36395c831c2661 Mon Sep 17 00:00:00 2001 From: Lu Baolu Date: Wed, 22 Oct 2025 16:26:27 +0800 Subject: [PATCH 1566/2333] iommu: disable SVA when CONFIG_X86 is set commit 72f98ef9a4be30d2a60136dd6faee376f780d06c upstream. Patch series "Fix stale IOTLB entries for kernel address space", v7. This proposes a fix for a security vulnerability related to IOMMU Shared Virtual Addressing (SVA). In an SVA context, an IOMMU can cache kernel page table entries. When a kernel page table page is freed and reallocated for another purpose, the IOMMU might still hold stale, incorrect entries. This can be exploited to cause a use-after-free or write-after-free condition, potentially leading to privilege escalation or data corruption. This solution introduces a deferred freeing mechanism for kernel page table pages, which provides a safe window to notify the IOMMU to invalidate its caches before the page is reused. This patch (of 8): In the IOMMU Shared Virtual Addressing (SVA) context, the IOMMU hardware shares and walks the CPU's page tables. The x86 architecture maps the kernel's virtual address space into the upper portion of every process's page table. Consequently, in an SVA context, the IOMMU hardware can walk and cache kernel page table entries. The Linux kernel currently lacks a notification mechanism for kernel page table changes, specifically when page table pages are freed and reused. The IOMMU driver is only notified of changes to user virtual address mappings. This can cause the IOMMU's internal caches to retain stale entries for kernel VA. Use-After-Free (UAF) and Write-After-Free (WAF) conditions arise when kernel page table pages are freed and later reallocated. The IOMMU could misinterpret the new data as valid page table entries. The IOMMU might then walk into attacker-controlled memory, leading to arbitrary physical memory DMA access or privilege escalation. This is also a Write-After-Free issue, as the IOMMU will potentially continue to write Accessed and Dirty bits to the freed memory while attempting to walk the stale page tables. Currently, SVA contexts are unprivileged and cannot access kernel mappings. However, the IOMMU will still walk kernel-only page tables all the way down to the leaf entries, where it realizes the mapping is for the kernel and errors out. This means the IOMMU still caches these intermediate page table entries, making the described vulnerability a real concern. Disable SVA on x86 architecture until the IOMMU can receive notification to flush the paging cache before freeing the CPU kernel page table pages. Link: https://lkml.kernel.org/r/20251022082635.2462433-1-baolu.lu@linux.intel.com Link: https://lkml.kernel.org/r/20251022082635.2462433-2-baolu.lu@linux.intel.com Fixes: 26b25a2b98e4 ("iommu: Bind process address spaces to devices") Signed-off-by: Lu Baolu Suggested-by: Jason Gunthorpe Reviewed-by: Jason Gunthorpe Cc: Alistair Popple Cc: Andy Lutomirski Cc: Borislav Betkov Cc: Dave Hansen Cc: David Hildenbrand Cc: Ingo Molnar Cc: Jann Horn Cc: Jean-Philippe Brucker Cc: Joerg Roedel Cc: Kevin Tian Cc: Liam Howlett Cc: Lorenzo Stoakes Cc: Matthew Wilcox (Oracle) Cc: Michal Hocko Cc: Mike Rapoport Cc: Peter Zijlstra Cc: Robin Murohy Cc: Thomas Gleinxer Cc: "Uladzislau Rezki (Sony)" Cc: Vasant Hegde Cc: Vinicius Costa Gomes Cc: Vlastimil Babka Cc: Will Deacon Cc: Yi Lai Cc: Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/iommu/iommu-sva.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/iommu/iommu-sva.c b/drivers/iommu/iommu-sva.c index 1a51cfd82808d..a0442faad952c 100644 --- a/drivers/iommu/iommu-sva.c +++ b/drivers/iommu/iommu-sva.c @@ -77,6 +77,9 @@ struct iommu_sva *iommu_sva_bind_device(struct device *dev, struct mm_struct *mm if (!group) return ERR_PTR(-ENODEV); + if (IS_ENABLED(CONFIG_X86)) + return ERR_PTR(-EOPNOTSUPP); + mutex_lock(&iommu_sva_lock); /* Allocate mm->pasid if necessary. */ From 1e9cf600da98affcc652857a35ba637d13126bfc Mon Sep 17 00:00:00 2001 From: Armin Wolf Date: Wed, 3 Dec 2025 21:21:09 +0100 Subject: [PATCH 1567/2333] hwmon: (dell-smm) Fix off-by-one error in dell_smm_is_visible() commit fae00a7186cecf90a57757a63b97a0cbcf384fe9 upstream. The documentation states that on machines supporting only global fan mode control, the pwmX_enable attributes should only be created for the first fan channel (pwm1_enable, aka channel 0). Fix the off-by-one error caused by the fact that fan channels have a zero-based index. Cc: stable@vger.kernel.org Fixes: 1c1658058c99 ("hwmon: (dell-smm) Add support for automatic fan mode") Signed-off-by: Armin Wolf Link: https://lore.kernel.org/r/20251203202109.331528-1-W_Armin@gmx.de Signed-off-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/dell-smm-hwmon.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/hwmon/dell-smm-hwmon.c b/drivers/hwmon/dell-smm-hwmon.c index f0e8a9bc0d0e0..8cf12b9bae2a7 100644 --- a/drivers/hwmon/dell-smm-hwmon.c +++ b/drivers/hwmon/dell-smm-hwmon.c @@ -864,9 +864,9 @@ static umode_t dell_smm_is_visible(const void *drvdata, enum hwmon_sensor_types if (auto_fan) { /* * The setting affects all fans, so only create a - * single attribute. + * single attribute for the first fan channel. */ - if (channel != 1) + if (channel != 0) return 0; /* From 36b5f6b52ca7ba98249591cf5f62f6e1fbe23749 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 8 Nov 2025 22:03:18 +0100 Subject: [PATCH 1568/2333] HID: logitech-dj: Remove duplicate error logging commit ca389a55d8b2d86a817433bf82e0602b68c4d541 upstream. logi_dj_recv_query_paired_devices() and logi_dj_recv_switch_to_dj_mode() both have 2 callers which all log an error if the function fails. Move the error logging to inside these 2 functions to remove the duplicated error logging in the callers. While at it also move the logi_dj_recv_send_report() call error handling in logi_dj_recv_switch_to_dj_mode() to directly after the call. That call only fails if the report cannot be found and in that case it does nothing, so the msleep() is not necessary on failures. Fixes: 6f20d3261265 ("HID: logitech-dj: Fix error handling in logi_dj_recv_switch_to_dj_mode()") Cc: stable@vger.kernel.org Signed-off-by: Hans de Goede Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman --- drivers/hid/hid-logitech-dj.c | 56 ++++++++++++++--------------------- 1 file changed, 23 insertions(+), 33 deletions(-) diff --git a/drivers/hid/hid-logitech-dj.c b/drivers/hid/hid-logitech-dj.c index cce54dd9884a3..3b5412541c925 100644 --- a/drivers/hid/hid-logitech-dj.c +++ b/drivers/hid/hid-logitech-dj.c @@ -805,7 +805,6 @@ static void delayedwork_callback(struct work_struct *work) struct dj_workitem workitem; unsigned long flags; int count; - int retval; dbg_hid("%s\n", __func__); @@ -842,11 +841,7 @@ static void delayedwork_callback(struct work_struct *work) logi_dj_recv_destroy_djhid_device(djrcv_dev, &workitem); break; case WORKITEM_TYPE_UNKNOWN: - retval = logi_dj_recv_query_paired_devices(djrcv_dev); - if (retval) { - hid_err(djrcv_dev->hidpp, "%s: logi_dj_recv_query_paired_devices error: %d\n", - __func__, retval); - } + logi_dj_recv_query_paired_devices(djrcv_dev); break; case WORKITEM_TYPE_EMPTY: dbg_hid("%s: device list is empty\n", __func__); @@ -1239,8 +1234,10 @@ static int logi_dj_recv_query_paired_devices(struct dj_receiver_dev *djrcv_dev) djrcv_dev->last_query = jiffies; - if (djrcv_dev->type != recvr_type_dj) - return logi_dj_recv_query_hidpp_devices(djrcv_dev); + if (djrcv_dev->type != recvr_type_dj) { + retval = logi_dj_recv_query_hidpp_devices(djrcv_dev); + goto out; + } dj_report = kzalloc(sizeof(struct dj_report), GFP_KERNEL); if (!dj_report) @@ -1250,6 +1247,10 @@ static int logi_dj_recv_query_paired_devices(struct dj_receiver_dev *djrcv_dev) dj_report->report_type = REPORT_TYPE_CMD_GET_PAIRED_DEVICES; retval = logi_dj_recv_send_report(djrcv_dev, dj_report); kfree(dj_report); +out: + if (retval < 0) + hid_err(djrcv_dev->hidpp, "%s error:%d\n", __func__, retval); + return retval; } @@ -1275,6 +1276,8 @@ static int logi_dj_recv_switch_to_dj_mode(struct dj_receiver_dev *djrcv_dev, (u8)timeout; retval = logi_dj_recv_send_report(djrcv_dev, dj_report); + if (retval) + goto out; /* * Ugly sleep to work around a USB 3.0 bug when the receiver is @@ -1283,11 +1286,6 @@ static int logi_dj_recv_switch_to_dj_mode(struct dj_receiver_dev *djrcv_dev, * 50 msec should gives enough time to the receiver to be ready. */ msleep(50); - - if (retval) { - kfree(dj_report); - return retval; - } } /* @@ -1313,7 +1311,12 @@ static int logi_dj_recv_switch_to_dj_mode(struct dj_receiver_dev *djrcv_dev, HIDPP_REPORT_SHORT_LENGTH, HID_OUTPUT_REPORT, HID_REQ_SET_REPORT); +out: kfree(dj_report); + + if (retval < 0) + hid_err(hdev, "%s error:%d\n", __func__, retval); + return retval; } @@ -1835,11 +1838,8 @@ static int logi_dj_probe(struct hid_device *hdev, if (has_hidpp) { retval = logi_dj_recv_switch_to_dj_mode(djrcv_dev, 0); - if (retval < 0) { - hid_err(hdev, "%s: logi_dj_recv_switch_to_dj_mode returned error:%d\n", - __func__, retval); + if (retval < 0) goto switch_to_dj_mode_fail; - } } /* This is enabling the polling urb on the IN endpoint */ @@ -1857,15 +1857,11 @@ static int logi_dj_probe(struct hid_device *hdev, spin_lock_irqsave(&djrcv_dev->lock, flags); djrcv_dev->ready = true; spin_unlock_irqrestore(&djrcv_dev->lock, flags); - retval = logi_dj_recv_query_paired_devices(djrcv_dev); - if (retval < 0) { - hid_err(hdev, "%s: logi_dj_recv_query_paired_devices error:%d\n", - __func__, retval); - /* - * This can happen with a KVM, let the probe succeed, - * logi_dj_recv_queue_unknown_work will retry later. - */ - } + /* + * This can fail with a KVM. Ignore errors to let the probe + * succeed, logi_dj_recv_queue_unknown_work will retry later. + */ + logi_dj_recv_query_paired_devices(djrcv_dev); } return 0; @@ -1882,18 +1878,12 @@ static int logi_dj_probe(struct hid_device *hdev, #ifdef CONFIG_PM static int logi_dj_reset_resume(struct hid_device *hdev) { - int retval; struct dj_receiver_dev *djrcv_dev = hid_get_drvdata(hdev); if (!djrcv_dev || djrcv_dev->hidpp != hdev) return 0; - retval = logi_dj_recv_switch_to_dj_mode(djrcv_dev, 0); - if (retval < 0) { - hid_err(hdev, "%s: logi_dj_recv_switch_to_dj_mode returned error:%d\n", - __func__, retval); - } - + logi_dj_recv_switch_to_dj_mode(djrcv_dev, 0); return 0; } #endif From 7c8b636d3ce7cca14ca29fbbe0621a59f73ac67e Mon Sep 17 00:00:00 2001 From: Raghavendra Rao Ananta Date: Fri, 31 Oct 2025 17:06:03 +0000 Subject: [PATCH 1569/2333] hisi_acc_vfio_pci: Add .match_token_uuid callback in hisi_acc_vfio_pci_migrn_ops commit 0ed3a30fd996cb0cac872432cf25185fda7e5316 upstream. The commit, <86624ba3b522> ("vfio/pci: Do vf_token checks for VFIO_DEVICE_BIND_IOMMUFD") accidentally ignored including the .match_token_uuid callback in the hisi_acc_vfio_pci_migrn_ops struct. Introduce the missed callback here. Fixes: 86624ba3b522 ("vfio/pci: Do vf_token checks for VFIO_DEVICE_BIND_IOMMUFD") Cc: stable@vger.kernel.org Suggested-by: Longfang Liu Signed-off-by: Raghavendra Rao Ananta Reviewed-by: Longfang Liu Reviewed-by: Jason Gunthorpe Link: https://lore.kernel.org/r/20251031170603.2260022-3-rananta@google.com Signed-off-by: Alex Williamson Signed-off-by: Greg Kroah-Hartman --- drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c b/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c index fde33f54e99ec..d07093d7cc3f5 100644 --- a/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c +++ b/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c @@ -1564,6 +1564,7 @@ static const struct vfio_device_ops hisi_acc_vfio_pci_migrn_ops = { .mmap = hisi_acc_vfio_pci_mmap, .request = vfio_pci_core_request, .match = vfio_pci_core_match, + .match_token_uuid = vfio_pci_core_match_token_uuid, .bind_iommufd = vfio_iommufd_physical_bind, .unbind_iommufd = vfio_iommufd_physical_unbind, .attach_ioas = vfio_iommufd_physical_attach_ioas, From c0a565f133f385f15e69db46e4a9f8d35fe2afca Mon Sep 17 00:00:00 2001 From: Shengming Hu Date: Wed, 26 Nov 2025 17:29:26 +0800 Subject: [PATCH 1570/2333] fgraph: Initialize ftrace_ops->private for function graph ops commit b5d6d3f73d0bac4a7e3a061372f6da166fc6ee5c upstream. The ftrace_pids_enabled(op) check relies on op->private being properly initialized, but fgraph_ops's underlying ftrace_ops->private was left uninitialized. This caused ftrace_pids_enabled() to always return false, effectively disabling PID filtering for function graph tracing. Fix this by copying src_ops->private to dst_ops->private in fgraph_init_ops(), ensuring PID filter state is correctly propagated. Cc: stable@vger.kernel.org Cc: Cc: Cc: Cc: Cc: Cc: Fixes: c132be2c4fcc1 ("function_graph: Have the instances use their own ftrace_ops for filtering") Link: https://patch.msgid.link/20251126172926004y3hC8QyU4WFOjBkU_UxLC@zte.com.cn Signed-off-by: Shengming Hu Signed-off-by: Steven Rostedt (Google) Signed-off-by: Greg Kroah-Hartman --- kernel/trace/fgraph.c | 1 + 1 file changed, 1 insertion(+) diff --git a/kernel/trace/fgraph.c b/kernel/trace/fgraph.c index 484ad7a18463a..d6222bb99d1d7 100644 --- a/kernel/trace/fgraph.c +++ b/kernel/trace/fgraph.c @@ -1019,6 +1019,7 @@ void fgraph_init_ops(struct ftrace_ops *dst_ops, mutex_init(&dst_ops->local_hash.regex_lock); INIT_LIST_HEAD(&dst_ops->subop_list); dst_ops->flags |= FTRACE_OPS_FL_INITIALIZED; + dst_ops->private = src_ops->private; } #endif } From 1a793f06aa69c59024019dadf09dd736954f2a9b Mon Sep 17 00:00:00 2001 From: Shengming Hu Date: Wed, 26 Nov 2025 17:33:31 +0800 Subject: [PATCH 1571/2333] fgraph: Check ftrace_pids_enabled on registration for early filtering commit 1650a1b6cb1ae6cb99bb4fce21b30ebdf9fc238e upstream. When registering ftrace_graph, check if ftrace_pids_enabled is active. If enabled, assign entryfunc to fgraph_pid_func to ensure filtering is performed before executing the saved original entry function. Cc: stable@vger.kernel.org Cc: Cc: Cc: Cc: Cc: Cc: Link: https://patch.msgid.link/20251126173331679XGVF98NLhyLJRdtNkVZ6w@zte.com.cn Fixes: df3ec5da6a1e7 ("function_graph: Add pid tracing back to function graph tracer") Signed-off-by: Shengming Hu Signed-off-by: Steven Rostedt (Google) Signed-off-by: Greg Kroah-Hartman --- kernel/trace/fgraph.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/kernel/trace/fgraph.c b/kernel/trace/fgraph.c index d6222bb99d1d7..599f2939cd940 100644 --- a/kernel/trace/fgraph.c +++ b/kernel/trace/fgraph.c @@ -1377,6 +1377,13 @@ int register_ftrace_graph(struct fgraph_ops *gops) ftrace_graph_active++; + /* Always save the function, and reset at unregistering */ + gops->saved_func = gops->entryfunc; +#ifdef CONFIG_DYNAMIC_FTRACE + if (ftrace_pids_enabled(&gops->ops)) + gops->entryfunc = fgraph_pid_func; +#endif + if (ftrace_graph_active == 2) ftrace_graph_disable_direct(true); @@ -1396,8 +1403,6 @@ int register_ftrace_graph(struct fgraph_ops *gops) } else { init_task_vars(gops->idx); } - /* Always save the function, and reset at unregistering */ - gops->saved_func = gops->entryfunc; gops->ops.flags |= FTRACE_OPS_FL_GRAPH; From 382895a288515f6f5b151dfb13e7722c332113ed Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Wed, 19 Nov 2025 09:50:01 +0100 Subject: [PATCH 1572/2333] PCI/PM: Reinstate clearing state_saved in legacy and !PM codepaths commit 894f475f88e06c0f352c829849560790dbdedbe5 upstream. When a PCI device is suspended, it is normally the PCI core's job to save Config Space and put the device into a low power state. However drivers are allowed to assume these responsibilities. When they do, the PCI core can tell by looking at the state_saved flag in struct pci_dev: The flag is cleared before commencing the suspend sequence and it is set when pci_save_state() is called. If the PCI core finds the flag set late in the suspend sequence, it refrains from calling pci_save_state() itself. But there are two corner cases where the PCI core neglects to clear the flag before commencing the suspend sequence: * If a driver has legacy PCI PM callbacks, pci_legacy_suspend() neglects to clear the flag. The (stale) flag is subsequently queried by pci_legacy_suspend() itself and pci_legacy_suspend_late(). * If a device has no driver or its driver has no PCI PM callbacks, pci_pm_freeze() neglects to clear the flag. The (stale) flag is subsequently queried by pci_pm_freeze_noirq(). The flag may be set prior to suspend if the device went through error recovery: Drivers commonly invoke pci_restore_state() + pci_save_state() to restore Config Space after reset. The flag may also be set if drivers call pci_save_state() on probe to allow for recovery from subsequent errors. The result is that pci_legacy_suspend_late() and pci_pm_freeze_noirq() don't call pci_save_state() and so the state that will be restored on resume is the one recorded on last error recovery or on probe, not the one that the device had on suspend. If the two states happen to be identical, there's no problem. Reinstate clearing the flag in pci_legacy_suspend() and pci_pm_freeze(). The two functions used to do that until commit 4b77b0a2ba27 ("PCI: Clear saved_state after the state has been restored") deemed it unnecessary because it assumed that it's sufficient to clear the flag on resume in pci_restore_state(). The commit seemingly did not take into account that pci_save_state() and pci_restore_state() are not only used by power management code, but also for error recovery. Devices without driver or whose driver has no PCI PM callbacks may be in runtime suspend when pci_pm_freeze() is called. Their state has already been saved, so don't clear the flag to skip a pointless pci_save_state() in pci_pm_freeze_noirq(). None of the drivers with legacy PCI PM callbacks seem to use runtime PM, so clear the flag unconditionally in their case. Fixes: 4b77b0a2ba27 ("PCI: Clear saved_state after the state has been restored") Signed-off-by: Lukas Wunner Signed-off-by: Bjorn Helgaas Reviewed-by: Rafael J. Wysocki (Intel) Cc: stable@vger.kernel.org # v2.6.32+ Link: https://patch.msgid.link/094f2aad64418710daf0940112abe5a0afdc6bce.1763483367.git.lukas@wunner.de Signed-off-by: Greg Kroah-Hartman --- drivers/pci/pci-driver.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 302d61783f6c0..327b21c48614d 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -629,6 +629,8 @@ static int pci_legacy_suspend(struct device *dev, pm_message_t state) struct pci_dev *pci_dev = to_pci_dev(dev); struct pci_driver *drv = pci_dev->driver; + pci_dev->state_saved = false; + if (drv && drv->suspend) { pci_power_t prev = pci_dev->current_state; int error; @@ -1036,6 +1038,8 @@ static int pci_pm_freeze(struct device *dev) if (!pm) { pci_pm_default_suspend(pci_dev); + if (!pm_runtime_suspended(dev)) + pci_dev->state_saved = false; return 0; } From f1765578621f4c7b32627059b966ccc3930872a5 Mon Sep 17 00:00:00 2001 From: Siddharth Vadapalli Date: Wed, 19 Nov 2025 21:31:05 +0530 Subject: [PATCH 1573/2333] arm64: dts: ti: k3-j721e-sk: Fix pinmux for pin Y1 used by power regulator commit 51f89c488f2ecc020f82bfedd77482584ce8027a upstream. The SoC pin Y1 is incorrectly defined in the WKUP Pinmux device-tree node (pinctrl@4301c000) leading to the following silent failure: pinctrl-single 4301c000.pinctrl: mux offset out of range: 0x1dc (0x178) According to the datasheet for the J721E SoC [0], the pin Y1 belongs to the MAIN Pinmux device-tree node (pinctrl@11c000). This is confirmed by the address of the pinmux register for it on page 142 of the datasheet which is 0x00011C1DC. Hence fix it. [0]: https://www.ti.com/lit/ds/symlink/tda4vm.pdf Fixes: 97b67cc102dc ("arm64: dts: ti: k3-j721e-sk: Add DT nodes for power regulators") Cc: stable@vger.kernel.org Signed-off-by: Siddharth Vadapalli Reviewed-by: Yemike Abhilash Chandra Link: https://patch.msgid.link/20251119160148.2752616-1-s-vadapalli@ti.com Signed-off-by: Vignesh Raghavendra Signed-off-by: Greg Kroah-Hartman --- arch/arm64/boot/dts/ti/k3-j721e-sk.dts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/arm64/boot/dts/ti/k3-j721e-sk.dts b/arch/arm64/boot/dts/ti/k3-j721e-sk.dts index 5e5784ef6f858..77dcc160eda3f 100644 --- a/arch/arm64/boot/dts/ti/k3-j721e-sk.dts +++ b/arch/arm64/boot/dts/ti/k3-j721e-sk.dts @@ -474,6 +474,12 @@ J721E_IOPAD(0x234, PIN_INPUT, 7) /* (U3) EXT_REFCLK1.GPIO1_12 */ >; }; + + vdd_sd_dv_pins_default: vdd-sd-dv-default-pins { + pinctrl-single,pins = < + J721E_IOPAD(0x1dc, PIN_OUTPUT, 7) /* (Y1) SPI1_CLK.GPIO0_118 */ + >; + }; }; &wkup_pmx0 { @@ -536,12 +542,6 @@ >; }; - vdd_sd_dv_pins_default: vdd-sd-dv-default-pins { - pinctrl-single,pins = < - J721E_IOPAD(0x1dc, PIN_OUTPUT, 7) /* (Y1) SPI1_CLK.GPIO0_118 */ - >; - }; - wkup_uart0_pins_default: wkup-uart0-default-pins { pinctrl-single,pins = < J721E_WKUP_IOPAD(0xa0, PIN_INPUT, 0) /* (J29) WKUP_UART0_RXD */ From 96bdd7ba179fca2946a914df1df47836795f2206 Mon Sep 17 00:00:00 2001 From: Dave Vasilevsky Date: Sun, 16 Nov 2025 01:40:46 -0500 Subject: [PATCH 1574/2333] powerpc, mm: Fix mprotect on book3s 32-bit commit 78fc63ffa7813e33681839bb33826c24195f0eb7 upstream. On 32-bit book3s with hash-MMUs, tlb_flush() was a no-op. This was unnoticed because all uses until recently were for unmaps, and thus handled by __tlb_remove_tlb_entry(). After commit 4a18419f71cd ("mm/mprotect: use mmu_gather") in kernel 5.19, tlb_gather_mmu() started being used for mprotect as well. This caused mprotect to simply not work on these machines: int *ptr = mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); *ptr = 1; // force HPTE to be created mprotect(ptr, 4096, PROT_READ); *ptr = 2; // should segfault, but succeeds Fixed by making tlb_flush() actually flush TLB pages. This finally agrees with the behaviour of boot3s64's tlb_flush(). Fixes: 4a18419f71cd ("mm/mprotect: use mmu_gather") Cc: stable@vger.kernel.org Reviewed-by: Christophe Leroy Reviewed-by: Ritesh Harjani (IBM) Signed-off-by: Dave Vasilevsky Signed-off-by: Madhavan Srinivasan Link: https://patch.msgid.link/20251116-vasi-mprotect-g3-v3-1-59a9bd33ba00@vasilevsky.ca Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/include/asm/book3s/32/tlbflush.h | 5 ++++- arch/powerpc/mm/book3s32/tlb.c | 9 +++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/include/asm/book3s/32/tlbflush.h b/arch/powerpc/include/asm/book3s/32/tlbflush.h index e43534da5207a..4be2200a3c7e1 100644 --- a/arch/powerpc/include/asm/book3s/32/tlbflush.h +++ b/arch/powerpc/include/asm/book3s/32/tlbflush.h @@ -11,6 +11,7 @@ void hash__flush_tlb_mm(struct mm_struct *mm); void hash__flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr); void hash__flush_range(struct mm_struct *mm, unsigned long start, unsigned long end); +void hash__flush_gather(struct mmu_gather *tlb); #ifdef CONFIG_SMP void _tlbie(unsigned long address); @@ -29,7 +30,9 @@ void _tlbia(void); static inline void tlb_flush(struct mmu_gather *tlb) { /* 603 needs to flush the whole TLB here since it doesn't use a hash table. */ - if (!mmu_has_feature(MMU_FTR_HPTE_TABLE)) + if (mmu_has_feature(MMU_FTR_HPTE_TABLE)) + hash__flush_gather(tlb); + else _tlbia(); } diff --git a/arch/powerpc/mm/book3s32/tlb.c b/arch/powerpc/mm/book3s32/tlb.c index 9ad6b56bfec96..e54a7b0112322 100644 --- a/arch/powerpc/mm/book3s32/tlb.c +++ b/arch/powerpc/mm/book3s32/tlb.c @@ -105,3 +105,12 @@ void hash__flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr) flush_hash_pages(mm->context.id, vmaddr, pmd_val(*pmd), 1); } EXPORT_SYMBOL(hash__flush_tlb_page); + +void hash__flush_gather(struct mmu_gather *tlb) +{ + if (tlb->fullmm || tlb->need_flush_all) + hash__flush_tlb_mm(tlb->mm); + else + hash__flush_range(tlb->mm, tlb->start, tlb->end); +} +EXPORT_SYMBOL(hash__flush_gather); From 4ae1e46d8a290319f33f71a2710a1382ba5431e8 Mon Sep 17 00:00:00 2001 From: Donet Tom Date: Thu, 30 Oct 2025 20:27:26 +0530 Subject: [PATCH 1575/2333] powerpc/64s/slb: Fix SLB multihit issue during SLB preload MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 00312419f0863964625d6dcda8183f96849412c6 upstream. On systems using the hash MMU, there is a software SLB preload cache that mirrors the entries loaded into the hardware SLB buffer. This preload cache is subject to periodic eviction — typically after every 256 context switches — to remove old entry. To optimize performance, the kernel skips switch_mmu_context() in switch_mm_irqs_off() when the prev and next mm_struct are the same. However, on hash MMU systems, this can lead to inconsistencies between the hardware SLB and the software preload cache. If an SLB entry for a process is evicted from the software cache on one CPU, and the same process later runs on another CPU without executing switch_mmu_context(), the hardware SLB may retain stale entries. If the kernel then attempts to reload that entry, it can trigger an SLB multi-hit error. The following timeline shows how stale SLB entries are created and can cause a multi-hit error when a process moves between CPUs without a MMU context switch. CPU 0 CPU 1 ----- ----- Process P exec swapper/1 load_elf_binary begin_new_exc activate_mm switch_mm_irqs_off switch_mmu_context switch_slb /* * This invalidates all * the entries in the HW * and setup the new HW * SLB entries as per the * preload cache. */ context_switch sched_migrate_task migrates process P to cpu-1 Process swapper/0 context switch (to process P) (uses mm_struct of Process P) switch_mm_irqs_off() switch_slb load_slb++ /* * load_slb becomes 0 here * and we evict an entry from * the preload cache with * preload_age(). We still * keep HW SLB and preload * cache in sync, that is * because all HW SLB entries * anyways gets evicted in * switch_slb during SLBIA. * We then only add those * entries back in HW SLB, * which are currently * present in preload_cache * (after eviction). */ load_elf_binary continues... setup_new_exec() slb_setup_new_exec() sched_switch event sched_migrate_task migrates process P to cpu-0 context_switch from swapper/0 to Process P switch_mm_irqs_off() /* * Since both prev and next mm struct are same we don't call * switch_mmu_context(). This will cause the HW SLB and SW preload * cache to go out of sync in preload_new_slb_context. Because there * was an SLB entry which was evicted from both HW and preload cache * on cpu-1. Now later in preload_new_slb_context(), when we will try * to add the same preload entry again, we will add this to the SW * preload cache and then will add it to the HW SLB. Since on cpu-0 * this entry was never invalidated, hence adding this entry to the HW * SLB will cause a SLB multi-hit error. */ load_elf_binary continues... START_THREAD start_thread preload_new_slb_context /* * This tries to add a new EA to preload cache which was earlier * evicted from both cpu-1 HW SLB and preload cache. This caused the * HW SLB of cpu-0 to go out of sync with the SW preload cache. The * reason for this was, that when we context switched back on CPU-0, * we should have ideally called switch_mmu_context() which will * bring the HW SLB entries on CPU-0 in sync with SW preload cache * entries by setting up the mmu context properly. But we didn't do * that since the prev mm_struct running on cpu-0 was same as the * next mm_struct (which is true for swapper / kernel threads). So * now when we try to add this new entry into the HW SLB of cpu-0, * we hit a SLB multi-hit error. */ WARNING: CPU: 0 PID: 1810970 at arch/powerpc/mm/book3s64/slb.c:62 assert_slb_presence+0x2c/0x50(48 results) 02:47:29 [20157/42149] Modules linked in: CPU: 0 UID: 0 PID: 1810970 Comm: dd Not tainted 6.16.0-rc3-dirty #12 VOLUNTARY Hardware name: IBM pSeries (emulated by qemu) POWER8 (architected) 0x4d0200 0xf000004 of:SLOF,HEAD hv:linux,kvm pSeries NIP: c00000000015426c LR: c0000000001543b4 CTR: 0000000000000000 REGS: c0000000497c77e0 TRAP: 0700 Not tainted (6.16.0-rc3-dirty) MSR: 8000000002823033 CR: 28888482 XER: 00000000 CFAR: c0000000001543b0 IRQMASK: 3 <...> NIP [c00000000015426c] assert_slb_presence+0x2c/0x50 LR [c0000000001543b4] slb_insert_entry+0x124/0x390 Call Trace: 0x7fffceb5ffff (unreliable) preload_new_slb_context+0x100/0x1a0 start_thread+0x26c/0x420 load_elf_binary+0x1b04/0x1c40 bprm_execve+0x358/0x680 do_execveat_common+0x1f8/0x240 sys_execve+0x58/0x70 system_call_exception+0x114/0x300 system_call_common+0x160/0x2c4 >From the above analysis, during early exec the hardware SLB is cleared, and entries from the software preload cache are reloaded into hardware by switch_slb. However, preload_new_slb_context and slb_setup_new_exec also attempt to load some of the same entries, which can trigger a multi-hit. In most cases, these additional preloads simply hit existing entries and add nothing new. Removing these functions avoids redundant preloads and eliminates the multi-hit issue. This patch removes these two functions. We tested process switching performance using the context_switch benchmark on POWER9/hash, and observed no regression. Without this patch: 129041 ops/sec With this patch: 129341 ops/sec We also measured SLB faults during boot, and the counts are essentially the same with and without this patch. SLB faults without this patch: 19727 SLB faults with this patch: 19786 Fixes: 5434ae74629a ("powerpc/64s/hash: Add a SLB preload cache") cc: stable@vger.kernel.org Suggested-by: Nicholas Piggin Signed-off-by: Donet Tom Signed-off-by: Ritesh Harjani (IBM) Signed-off-by: Madhavan Srinivasan Link: https://patch.msgid.link/0ac694ae683494fe8cadbd911a1a5018d5d3c541.1761834163.git.ritesh.list@gmail.com Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/include/asm/book3s/64/mmu-hash.h | 1 - arch/powerpc/kernel/process.c | 5 -- arch/powerpc/mm/book3s64/internal.h | 2 - arch/powerpc/mm/book3s64/mmu_context.c | 2 - arch/powerpc/mm/book3s64/slb.c | 88 ------------------- 5 files changed, 98 deletions(-) diff --git a/arch/powerpc/include/asm/book3s/64/mmu-hash.h b/arch/powerpc/include/asm/book3s/64/mmu-hash.h index 3463514232071..af12e2ba8eb85 100644 --- a/arch/powerpc/include/asm/book3s/64/mmu-hash.h +++ b/arch/powerpc/include/asm/book3s/64/mmu-hash.h @@ -524,7 +524,6 @@ void slb_save_contents(struct slb_entry *slb_ptr); void slb_dump_contents(struct slb_entry *slb_ptr); extern void slb_vmalloc_update(void); -void preload_new_slb_context(unsigned long start, unsigned long sp); #ifdef CONFIG_PPC_64S_HASH_MMU void slb_set_size(u16 size); diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index eb23966ac0a9f..a45fe147868bc 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -1897,8 +1897,6 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args) return 0; } -void preload_new_slb_context(unsigned long start, unsigned long sp); - /* * Set up a thread for executing a new program */ @@ -1906,9 +1904,6 @@ void start_thread(struct pt_regs *regs, unsigned long start, unsigned long sp) { #ifdef CONFIG_PPC64 unsigned long load_addr = regs->gpr[2]; /* saved by ELF_PLAT_INIT */ - - if (IS_ENABLED(CONFIG_PPC_BOOK3S_64) && !radix_enabled()) - preload_new_slb_context(start, sp); #endif #ifdef CONFIG_PPC_TRANSACTIONAL_MEM diff --git a/arch/powerpc/mm/book3s64/internal.h b/arch/powerpc/mm/book3s64/internal.h index a57a25f06a215..c26a6f0c90fcd 100644 --- a/arch/powerpc/mm/book3s64/internal.h +++ b/arch/powerpc/mm/book3s64/internal.h @@ -24,8 +24,6 @@ static inline bool stress_hpt(void) void hpt_do_stress(unsigned long ea, unsigned long hpte_group); -void slb_setup_new_exec(void); - void exit_lazy_flush_tlb(struct mm_struct *mm, bool always_flush); #endif /* ARCH_POWERPC_MM_BOOK3S64_INTERNAL_H */ diff --git a/arch/powerpc/mm/book3s64/mmu_context.c b/arch/powerpc/mm/book3s64/mmu_context.c index 4e1e45420bd49..fb9dcf9ca5998 100644 --- a/arch/powerpc/mm/book3s64/mmu_context.c +++ b/arch/powerpc/mm/book3s64/mmu_context.c @@ -150,8 +150,6 @@ static int hash__init_new_context(struct mm_struct *mm) void hash__setup_new_exec(void) { slice_setup_new_exec(); - - slb_setup_new_exec(); } #else static inline int hash__init_new_context(struct mm_struct *mm) diff --git a/arch/powerpc/mm/book3s64/slb.c b/arch/powerpc/mm/book3s64/slb.c index 6b783552403c6..7e053c561a09d 100644 --- a/arch/powerpc/mm/book3s64/slb.c +++ b/arch/powerpc/mm/book3s64/slb.c @@ -328,94 +328,6 @@ static void preload_age(struct thread_info *ti) ti->slb_preload_tail = (ti->slb_preload_tail + 1) % SLB_PRELOAD_NR; } -void slb_setup_new_exec(void) -{ - struct thread_info *ti = current_thread_info(); - struct mm_struct *mm = current->mm; - unsigned long exec = 0x10000000; - - WARN_ON(irqs_disabled()); - - /* - * preload cache can only be used to determine whether a SLB - * entry exists if it does not start to overflow. - */ - if (ti->slb_preload_nr + 2 > SLB_PRELOAD_NR) - return; - - hard_irq_disable(); - - /* - * We have no good place to clear the slb preload cache on exec, - * flush_thread is about the earliest arch hook but that happens - * after we switch to the mm and have already preloaded the SLBEs. - * - * For the most part that's probably okay to use entries from the - * previous exec, they will age out if unused. It may turn out to - * be an advantage to clear the cache before switching to it, - * however. - */ - - /* - * preload some userspace segments into the SLB. - * Almost all 32 and 64bit PowerPC executables are linked at - * 0x10000000 so it makes sense to preload this segment. - */ - if (!is_kernel_addr(exec)) { - if (preload_add(ti, exec)) - slb_allocate_user(mm, exec); - } - - /* Libraries and mmaps. */ - if (!is_kernel_addr(mm->mmap_base)) { - if (preload_add(ti, mm->mmap_base)) - slb_allocate_user(mm, mm->mmap_base); - } - - /* see switch_slb */ - asm volatile("isync" : : : "memory"); - - local_irq_enable(); -} - -void preload_new_slb_context(unsigned long start, unsigned long sp) -{ - struct thread_info *ti = current_thread_info(); - struct mm_struct *mm = current->mm; - unsigned long heap = mm->start_brk; - - WARN_ON(irqs_disabled()); - - /* see above */ - if (ti->slb_preload_nr + 3 > SLB_PRELOAD_NR) - return; - - hard_irq_disable(); - - /* Userspace entry address. */ - if (!is_kernel_addr(start)) { - if (preload_add(ti, start)) - slb_allocate_user(mm, start); - } - - /* Top of stack, grows down. */ - if (!is_kernel_addr(sp)) { - if (preload_add(ti, sp)) - slb_allocate_user(mm, sp); - } - - /* Bottom of heap, grows up. */ - if (heap && !is_kernel_addr(heap)) { - if (preload_add(ti, heap)) - slb_allocate_user(mm, heap); - } - - /* see switch_slb */ - asm volatile("isync" : : : "memory"); - - local_irq_enable(); -} - static void slb_cache_slbie_kernel(unsigned int index) { unsigned long slbie_data = get_paca()->slb_cache[index]; From 2c3edc2b7aa39ea9898adfe92d5ee1ea89abfcea Mon Sep 17 00:00:00 2001 From: Kairui Song Date: Fri, 24 Oct 2025 02:34:11 +0800 Subject: [PATCH 1576/2333] mm, swap: do not perform synchronous discard during allocation commit 9fb749cd15078c7bdc46e5d45c37493f83323e33 upstream. Patch series "mm, swap: misc cleanup and bugfix", v2. A few cleanups and a bugfix that are either suitable after the swap table phase I or found during code review. Patch 1 is a bugfix and needs to be included in the stable branch, the rest have no behavioral change. This patch (of 5): Since commit 1b7e90020eb77 ("mm, swap: use percpu cluster as allocation fast path"), swap allocation is protected by a local lock, which means we can't do any sleeping calls during allocation. However, the discard routine is not taken well care of. When the swap allocator failed to find any usable cluster, it would look at the pending discard cluster and try to issue some blocking discards. It may not necessarily sleep, but the cond_resched at the bio layer indicates this is wrong when combined with a local lock. And the bio GFP flag used for discard bio is also wrong (not atomic). It's arguable whether this synchronous discard is helpful at all. In most cases, the async discard is good enough. And the swap allocator is doing very differently at organizing the clusters since the recent change, so it is very rare to see discard clusters piling up. So far, no issues have been observed or reported with typical SSD setups under months of high pressure. This issue was found during my code review. But by hacking the kernel a bit: adding a mdelay(500) in the async discard path, this issue will be observable with WARNING triggered by the wrong GFP and cond_resched in the bio layer for debug builds. So now let's apply a hotfix for this issue: remove the synchronous discard in the swap allocation path. And when order 0 is failing with all cluster list drained on all swap devices, try to do a discard following the swap device priority list. If any discards released some cluster, try the allocation again. This way, we can still avoid OOM due to swap failure if the hardware is very slow and memory pressure is extremely high. This may cause more fragmentation issues if the discarding hardware is really slow. Ideally, we want to discard pending clusters before continuing to iterate the fragment cluster lists. This can be implemented in a cleaner way if we clean up the device list iteration part first. Link: https://lkml.kernel.org/r/20251024-swap-clean-after-swap-table-p1-v2-0-a709469052e7@tencent.com Link: https://lkml.kernel.org/r/20251024-swap-clean-after-swap-table-p1-v2-1-c5b0e1092927@tencent.com Fixes: 1b7e90020eb7 ("mm, swap: use percpu cluster as allocation fast path") Signed-off-by: Kairui Song Acked-by: Nhat Pham Acked-by: Chris Li Cc: Baolin Wang Cc: Baoquan He Cc: Barry Song Cc: David Hildenbrand Cc: "Huang, Ying" Cc: Kemeng Shi Cc: Matthew Wilcox (Oracle) Cc: Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- mm/swapfile.c | 40 +++++++++++++++++++++++++++++++++------- 1 file changed, 33 insertions(+), 7 deletions(-) diff --git a/mm/swapfile.c b/mm/swapfile.c index a1b4b9d80e3b5..82524f8595eda 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -1101,13 +1101,6 @@ static unsigned long cluster_alloc_swap_entry(struct swap_info_struct *si, int o goto done; } - /* - * We don't have free cluster but have some clusters in discarding, - * do discard now and reclaim them. - */ - if ((si->flags & SWP_PAGE_DISCARD) && swap_do_scheduled_discard(si)) - goto new_cluster; - if (order) goto done; @@ -1394,6 +1387,33 @@ static bool swap_alloc_slow(swp_entry_t *entry, return false; } +/* + * Discard pending clusters in a synchronized way when under high pressure. + * Return: true if any cluster is discarded. + */ +static bool swap_sync_discard(void) +{ + bool ret = false; + int nid = numa_node_id(); + struct swap_info_struct *si, *next; + + spin_lock(&swap_avail_lock); + plist_for_each_entry_safe(si, next, &swap_avail_heads[nid], avail_lists[nid]) { + spin_unlock(&swap_avail_lock); + if (get_swap_device_info(si)) { + if (si->flags & SWP_PAGE_DISCARD) + ret = swap_do_scheduled_discard(si); + put_swap_device(si); + } + if (ret) + return true; + spin_lock(&swap_avail_lock); + } + spin_unlock(&swap_avail_lock); + + return false; +} + /** * folio_alloc_swap - allocate swap space for a folio * @folio: folio we want to move to swap @@ -1432,11 +1452,17 @@ int folio_alloc_swap(struct folio *folio, gfp_t gfp) } } +again: local_lock(&percpu_swap_cluster.lock); if (!swap_alloc_fast(&entry, order)) swap_alloc_slow(&entry, order); local_unlock(&percpu_swap_cluster.lock); + if (unlikely(!order && !entry.val)) { + if (swap_sync_discard()) + goto again; + } + /* Need to call this even if allocation failed, for MEMCG_SWAP_FAIL. */ if (mem_cgroup_try_charge_swap(folio, entry)) goto out_free; From 67bfbc5a558ce07cbdb99503cb4f02a343eabd2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Tue, 28 Oct 2025 16:31:03 +0100 Subject: [PATCH 1577/2333] leds: leds-cros_ec: Skip LEDs without color components MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 4dbf066d965cd3299fb396f1375d10423c9c625c upstream. A user reports that on their Lenovo Corsola Magneton with EC firmware steelix-15194.270.0 the driver probe fails with EINVAL. It turns out that the power LED does not contain any color components as indicated by the following "ectool led power query" output: Brightness range for LED 1: red : 0x0 green : 0x0 blue : 0x0 yellow : 0x0 white : 0x0 amber : 0x0 The LED also does not react to commands sent manually through ectool and is generally non-functional. Instead of failing the probe for all LEDs managed by the EC when one without color components is encountered, silently skip those. Cc: stable@vger.kernel.org Fixes: 8d6ce6f3ec9d ("leds: Add ChromeOS EC driver") Signed-off-by: Thomas Weißschuh Link: https://patch.msgid.link/20251028-cros_ec-leds-no-colors-v1-1-ebe13a02022a@weissschuh.net Signed-off-by: Lee Jones Signed-off-by: Greg Kroah-Hartman --- drivers/leds/leds-cros_ec.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/leds/leds-cros_ec.c b/drivers/leds/leds-cros_ec.c index 377cf04e202a1..bea3cc3fbfd2d 100644 --- a/drivers/leds/leds-cros_ec.c +++ b/drivers/leds/leds-cros_ec.c @@ -142,9 +142,6 @@ static int cros_ec_led_count_subleds(struct device *dev, } } - if (!num_subleds) - return -EINVAL; - *max_brightness = common_range; return num_subleds; } @@ -189,6 +186,8 @@ static int cros_ec_led_probe_one(struct device *dev, struct cros_ec_device *cros &priv->led_mc_cdev.led_cdev.max_brightness); if (num_subleds < 0) return num_subleds; + if (num_subleds == 0) + return 0; /* LED without any colors, skip */ priv->cros_ec = cros_ec; priv->led_id = id; From dcd4efe4817867758905d42762a058d7ca8094c1 Mon Sep 17 00:00:00 2001 From: Christian Hitz Date: Wed, 8 Oct 2025 14:32:21 +0200 Subject: [PATCH 1578/2333] leds: leds-lp50xx: Allow LED 0 to be added to module bank commit 26fe74d598c32e7bc6f150edfc4aa43e1bee55db upstream. led_banks contains LED module number(s) that should be grouped into the module bank. led_banks is 0-initialized. By checking the led_banks entries for 0, un-set entries are detected. But a 0-entry also indicates that LED module 0 should be grouped into the module bank. By only iterating over the available entries no check for unused entries is required and LED module 0 can be added to bank. Cc: stable@vger.kernel.org Fixes: 242b81170fb8 ("leds: lp50xx: Add the LP50XX family of the RGB LED driver") Signed-off-by: Christian Hitz Reviewed-by: Jacek Anaszewski Link: https://patch.msgid.link/20251008123222.1117331-1-christian@klarinett.li Signed-off-by: Lee Jones Signed-off-by: Greg Kroah-Hartman --- drivers/leds/leds-lp50xx.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/leds/leds-lp50xx.c b/drivers/leds/leds-lp50xx.c index 94f8ef6b482c9..d50c7f3e8f999 100644 --- a/drivers/leds/leds-lp50xx.c +++ b/drivers/leds/leds-lp50xx.c @@ -341,17 +341,15 @@ static int lp50xx_brightness_set(struct led_classdev *cdev, return ret; } -static int lp50xx_set_banks(struct lp50xx *priv, u32 led_banks[]) +static int lp50xx_set_banks(struct lp50xx *priv, u32 led_banks[], int num_leds) { u8 led_config_lo, led_config_hi; u32 bank_enable_mask = 0; int ret; int i; - for (i = 0; i < priv->chip_info->max_modules; i++) { - if (led_banks[i]) - bank_enable_mask |= (1 << led_banks[i]); - } + for (i = 0; i < num_leds; i++) + bank_enable_mask |= (1 << led_banks[i]); led_config_lo = bank_enable_mask; led_config_hi = bank_enable_mask >> 8; @@ -405,7 +403,7 @@ static int lp50xx_probe_leds(struct fwnode_handle *child, struct lp50xx *priv, return ret; } - ret = lp50xx_set_banks(priv, led_banks); + ret = lp50xx_set_banks(priv, led_banks, num_leds); if (ret) { dev_err(priv->dev, "Cannot setup banked LEDs\n"); return ret; From c99352597531733705351eb35524f1a19f60fdc7 Mon Sep 17 00:00:00 2001 From: Christian Hitz Date: Wed, 22 Oct 2025 08:33:04 +0200 Subject: [PATCH 1579/2333] leds: leds-lp50xx: LP5009 supports 3 modules for a total of 9 LEDs commit 5246e3673eeeccb4f5bf4f42375dd495d465ac15 upstream. LP5009 supports 9 LED outputs that are grouped into 3 modules. Cc: stable@vger.kernel.org Fixes: 242b81170fb8 ("leds: lp50xx: Add the LP50XX family of the RGB LED driver") Signed-off-by: Christian Hitz Link: https://patch.msgid.link/20251022063305.972190-1-christian@klarinett.li Signed-off-by: Lee Jones Signed-off-by: Greg Kroah-Hartman --- drivers/leds/leds-lp50xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/leds/leds-lp50xx.c b/drivers/leds/leds-lp50xx.c index d50c7f3e8f999..3a0316be96edb 100644 --- a/drivers/leds/leds-lp50xx.c +++ b/drivers/leds/leds-lp50xx.c @@ -54,7 +54,7 @@ /* There are 3 LED outputs per bank */ #define LP50XX_LEDS_PER_MODULE 3 -#define LP5009_MAX_LED_MODULES 2 +#define LP5009_MAX_LED_MODULES 3 #define LP5012_MAX_LED_MODULES 4 #define LP5018_MAX_LED_MODULES 6 #define LP5024_MAX_LED_MODULES 8 From 4d29edea49218a51304facea51357a4ab9a284f5 Mon Sep 17 00:00:00 2001 From: Christian Hitz Date: Tue, 28 Oct 2025 16:51:40 +0100 Subject: [PATCH 1580/2333] leds: leds-lp50xx: Enable chip before any communication MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 434959618c47efe9e5f2e20f4a850caac4f6b823 upstream. If a GPIO is used to control the chip's enable pin, it needs to be pulled high before any i2c communication is attempted. Currently, the enable GPIO handling is not correct. Assume the enable GPIO is low when the probe function is entered. In this case the device is in SHUTDOWN mode and does not react to i2c commands. During probe the following sequence happens: 1. The call to lp50xx_reset() on line 548 has no effect as i2c is not possible yet. 2. Then - on line 552 - lp50xx_enable_disable() is called. As "priv->enable_gpio“ has not yet been initialized, setting the GPIO has no effect. Also the i2c enable command is not executed as the device is still in SHUTDOWN. 3. On line 556 the call to lp50xx_probe_dt() finally parses the rest of the DT and the configured priv->enable_gpio is set up. As a result the device is still in SHUTDOWN mode and not ready for operation. Split lp50xx_enable_disable() into distinct enable and disable functions to enforce correct ordering between enable_gpio manipulations and i2c commands. Read enable_gpio configuration from DT before attempting to manipulate enable_gpio. Add delays to observe correct wait timing after manipulating enable_gpio and before any i2c communication. Cc: stable@vger.kernel.org Fixes: 242b81170fb8 ("leds: lp50xx: Add the LP50XX family of the RGB LED driver") Signed-off-by: Christian Hitz Link: https://patch.msgid.link/20251028155141.1603193-1-christian@klarinett.li Signed-off-by: Lee Jones Signed-off-by: Greg Kroah-Hartman --- drivers/leds/leds-lp50xx.c | 55 +++++++++++++++++++++++++++----------- 1 file changed, 40 insertions(+), 15 deletions(-) diff --git a/drivers/leds/leds-lp50xx.c b/drivers/leds/leds-lp50xx.c index 3a0316be96edb..e2a9c8592953c 100644 --- a/drivers/leds/leds-lp50xx.c +++ b/drivers/leds/leds-lp50xx.c @@ -50,6 +50,12 @@ #define LP50XX_SW_RESET 0xff #define LP50XX_CHIP_EN BIT(6) +#define LP50XX_CHIP_DISABLE 0x00 +#define LP50XX_START_TIME_US 500 +#define LP50XX_RESET_TIME_US 3 + +#define LP50XX_EN_GPIO_LOW 0 +#define LP50XX_EN_GPIO_HIGH 1 /* There are 3 LED outputs per bank */ #define LP50XX_LEDS_PER_MODULE 3 @@ -369,19 +375,42 @@ static int lp50xx_reset(struct lp50xx *priv) return regmap_write(priv->regmap, priv->chip_info->reset_reg, LP50XX_SW_RESET); } -static int lp50xx_enable_disable(struct lp50xx *priv, int enable_disable) +static int lp50xx_enable(struct lp50xx *priv) { int ret; - ret = gpiod_direction_output(priv->enable_gpio, enable_disable); + if (priv->enable_gpio) { + ret = gpiod_direction_output(priv->enable_gpio, LP50XX_EN_GPIO_HIGH); + if (ret) + return ret; + + udelay(LP50XX_START_TIME_US); + } + + ret = lp50xx_reset(priv); if (ret) return ret; - if (enable_disable) - return regmap_write(priv->regmap, LP50XX_DEV_CFG0, LP50XX_CHIP_EN); - else - return regmap_write(priv->regmap, LP50XX_DEV_CFG0, 0); + return regmap_write(priv->regmap, LP50XX_DEV_CFG0, LP50XX_CHIP_EN); +} +static int lp50xx_disable(struct lp50xx *priv) +{ + int ret; + + ret = regmap_write(priv->regmap, LP50XX_DEV_CFG0, LP50XX_CHIP_DISABLE); + if (ret) + return ret; + + if (priv->enable_gpio) { + ret = gpiod_direction_output(priv->enable_gpio, LP50XX_EN_GPIO_LOW); + if (ret) + return ret; + + udelay(LP50XX_RESET_TIME_US); + } + + return 0; } static int lp50xx_probe_leds(struct fwnode_handle *child, struct lp50xx *priv, @@ -445,6 +474,10 @@ static int lp50xx_probe_dt(struct lp50xx *priv) return dev_err_probe(priv->dev, PTR_ERR(priv->enable_gpio), "Failed to get enable GPIO\n"); + ret = lp50xx_enable(priv); + if (ret) + return ret; + priv->regulator = devm_regulator_get(priv->dev, "vled"); if (IS_ERR(priv->regulator)) priv->regulator = NULL; @@ -545,14 +578,6 @@ static int lp50xx_probe(struct i2c_client *client) return ret; } - ret = lp50xx_reset(led); - if (ret) - return ret; - - ret = lp50xx_enable_disable(led, 1); - if (ret) - return ret; - return lp50xx_probe_dt(led); } @@ -561,7 +586,7 @@ static void lp50xx_remove(struct i2c_client *client) struct lp50xx *led = i2c_get_clientdata(client); int ret; - ret = lp50xx_enable_disable(led, 0); + ret = lp50xx_disable(led); if (ret) dev_err(led->dev, "Failed to disable chip\n"); From 1c678ce2f56be2b66c2b17b4d7311de6fd6e283d Mon Sep 17 00:00:00 2001 From: Damien Le Moal Date: Thu, 4 Dec 2025 19:59:52 +0900 Subject: [PATCH 1581/2333] block: Clear BLK_ZONE_WPLUG_PLUGGED when aborting plugged BIOs commit 552c1149af7ac0cffab6fccd13feeaf816dd1f53 upstream. Commit fe0418eb9bd6 ("block: Prevent potential deadlocks in zone write plug error recovery") added a WARN check in disk_put_zone_wplug() to verify that when the last reference to a zone write plug is dropped, this zone write plug does not have the BLK_ZONE_WPLUG_PLUGGED flag set, that is, that it is not plugged. However, the function disk_zone_wplug_abort(), which is called for zone reset and zone finish operations, does not clear this flag after emptying a zone write plug BIO list. This can result in the disk_put_zone_wplug() warning to trigger if the user (erroneously as that is bad pratcice) issues zone reset or zone finish operations while the target zone still has plugged BIOs. Modify disk_put_zone_wplug() to clear the BLK_ZONE_WPLUG_PLUGGED flag. And while at it, also add a lockdep annotation to ensure that this function is called with the zone write plug spinlock held. Fixes: fe0418eb9bd6 ("block: Prevent potential deadlocks in zone write plug error recovery") Cc: stable@vger.kernel.org Signed-off-by: Damien Le Moal Reviewed-by: Niklas Cassel Reviewed-by: Johannes Thumshirn Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman --- block/blk-zoned.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/block/blk-zoned.c b/block/blk-zoned.c index 39381f2b2e947..3a3cbee60591b 100644 --- a/block/blk-zoned.c +++ b/block/blk-zoned.c @@ -616,6 +616,8 @@ static void disk_zone_wplug_abort(struct blk_zone_wplug *zwplug) { struct bio *bio; + lockdep_assert_held(&zwplug->lock); + if (bio_list_empty(&zwplug->bio_list)) return; @@ -623,6 +625,8 @@ static void disk_zone_wplug_abort(struct blk_zone_wplug *zwplug) zwplug->disk->disk_name, zwplug->zone_no); while ((bio = bio_list_pop(&zwplug->bio_list))) blk_zone_wplug_bio_io_error(zwplug, bio); + + zwplug->flags &= ~BLK_ZONE_WPLUG_PLUGGED; } /* From a317f63255ebc3dac378c79c5bff4f8d0561c290 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Mon, 24 Nov 2025 12:11:06 -0700 Subject: [PATCH 1582/2333] clk: samsung: exynos-clkout: Assign .num before accessing .hws commit cf33f0b7df13685234ccea7be7bfe316b60db4db upstream. Commit f316cdff8d67 ("clk: Annotate struct clk_hw_onecell_data with __counted_by") annotated the hws member of 'struct clk_hw_onecell_data' with __counted_by, which informs the bounds sanitizer (UBSAN_BOUNDS) about the number of elements in .hws[], so that it can warn when .hws[] is accessed out of bounds. As noted in that change, the __counted_by member must be initialized with the number of elements before the first array access happens, otherwise there will be a warning from each access prior to the initialization because the number of elements is zero. This occurs in exynos_clkout_probe() due to .num being assigned after .hws[] has been accessed: UBSAN: array-index-out-of-bounds in drivers/clk/samsung/clk-exynos-clkout.c:178:18 index 0 is out of range for type 'clk_hw *[*]' Move the .num initialization to before the first access of .hws[], clearing up the warning. Cc: stable@vger.kernel.org Fixes: f316cdff8d67 ("clk: Annotate struct clk_hw_onecell_data with __counted_by") Reported-by: Jochen Sprickerhof Closes: https://lore.kernel.org/aSIYDN5eyKFKoXKL@eldamar.lan/ Tested-by: Jochen Sprickerhof Signed-off-by: Nathan Chancellor Reviewed-by: Kees Cook Reviewed-by: Sam Protsenko Reviewed-by: Krzysztof Kozlowski Signed-off-by: Stephen Boyd Signed-off-by: Greg Kroah-Hartman --- drivers/clk/samsung/clk-exynos-clkout.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/samsung/clk-exynos-clkout.c b/drivers/clk/samsung/clk-exynos-clkout.c index 5f1a4f5e2e594..5b21025338bd5 100644 --- a/drivers/clk/samsung/clk-exynos-clkout.c +++ b/drivers/clk/samsung/clk-exynos-clkout.c @@ -175,6 +175,7 @@ static int exynos_clkout_probe(struct platform_device *pdev) clkout->mux.shift = EXYNOS_CLKOUT_MUX_SHIFT; clkout->mux.lock = &clkout->slock; + clkout->data.num = EXYNOS_CLKOUT_NR_CLKS; clkout->data.hws[0] = clk_hw_register_composite(NULL, "clkout", parent_names, parent_count, &clkout->mux.hw, &clk_mux_ops, NULL, NULL, &clkout->gate.hw, @@ -185,7 +186,6 @@ static int exynos_clkout_probe(struct platform_device *pdev) goto err_unmap; } - clkout->data.num = EXYNOS_CLKOUT_NR_CLKS; ret = of_clk_add_hw_provider(clkout->np, of_clk_hw_onecell_get, &clkout->data); if (ret) goto err_clk_unreg; From 34322b533390533feb49b2c29961159328bf04db Mon Sep 17 00:00:00 2001 From: Alexey Minnekhanov Date: Sun, 16 Nov 2025 04:12:34 +0300 Subject: [PATCH 1583/2333] clk: qcom: mmcc-sdm660: Add missing MDSS reset commit 0a0ea5541d30c0fbb3dac975bd1983f299cd6948 upstream. Add offset for display subsystem reset in multimedia clock controller block, which is necessary to reset display when there is some configuration in display controller left by previous stock (Android) bootloader to provide continuous splash functionaluty. Before 6.17 power domains were turned off for long enough to clear registers, now this is not the case and a proper reset is needed to have functioning display. Fixes: 0e789b491ba0 ("pmdomain: core: Leave powered-on genpds on until sync_state") Cc: stable@vger.kernel.org # 6.17 Signed-off-by: Alexey Minnekhanov Reviewed-by: Taniya Das Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20251116-sdm660-mdss-reset-v2-2-6219bec0a97f@postmarketos.org Signed-off-by: Bjorn Andersson Signed-off-by: Greg Kroah-Hartman --- drivers/clk/qcom/mmcc-sdm660.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/qcom/mmcc-sdm660.c b/drivers/clk/qcom/mmcc-sdm660.c index b723c536dfb6c..dbd3f561dc6d0 100644 --- a/drivers/clk/qcom/mmcc-sdm660.c +++ b/drivers/clk/qcom/mmcc-sdm660.c @@ -2781,6 +2781,7 @@ static struct gdsc *mmcc_sdm660_gdscs[] = { }; static const struct qcom_reset_map mmcc_660_resets[] = { + [MDSS_BCR] = { 0x2300 }, [CAMSS_MICRO_BCR] = { 0x3490 }, }; From 8f41129c4b5ba5bb2444a6157630550fa0cc7110 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Tue, 30 Sep 2025 11:56:08 -0700 Subject: [PATCH 1584/2333] clk: qcom: Fix SM_VIDEOCC_6350 dependencies commit f0691a3f7558d33b5b4a900e8312613fbe4afb9d upstream. It is possible to select CONFIG_SM_GCC_6350 when targeting ARCH=arm, causing a Kconfig warning when selecting CONFIG_SM_GCC_6350 without its dependencies, CONFIG_ARM64 or CONFIG_COMPILE_TEST. WARNING: unmet direct dependencies detected for SM_GCC_6350 Depends on [n]: COMMON_CLK [=y] && COMMON_CLK_QCOM [=m] && (ARM64 || COMPILE_TEST [=n]) Selected by [m]: - SM_VIDEOCC_6350 [=m] && COMMON_CLK [=y] && COMMON_CLK_QCOM [=m] Add the same dependency to clear up the warning. Cc: stable@vger.kernel.org Fixes: 720b1e8f2004 ("clk: qcom: Add video clock controller driver for SM6350") Signed-off-by: Nathan Chancellor Reviewed-by: Imran Shaik Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20250930-clk-qcom-kconfig-fixes-arm-v1-1-15ae1ae9ec9f@kernel.org Signed-off-by: Bjorn Andersson Signed-off-by: Greg Kroah-Hartman --- drivers/clk/qcom/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index 78a3038426136..ec7d1a9b578e6 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -1448,6 +1448,7 @@ config SA_VIDEOCC_8775P config SM_VIDEOCC_6350 tristate "SM6350 Video Clock Controller" + depends on ARM64 || COMPILE_TEST select SM_GCC_6350 select QCOM_GDSC help From deb4bc9fc8d0ba2c7b4a224c6f72cacaafa65d61 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Tue, 30 Sep 2025 11:56:09 -0700 Subject: [PATCH 1585/2333] clk: qcom: Fix dependencies of QCS_{DISP,GPU,VIDEO}CC_615 commit 7ec1ba01ae37897f0ecf6ab0c980378cb8a2f388 upstream. It is possible to select CONFIG_QCS_{DISP,GPU,VIDEO}CC_615 when targeting ARCH=arm, causing a Kconfig warning when selecting CONFIG_QCS_GCC_615 without its dependencies, CONFIG_ARM64 or CONFIG_COMPILE_TEST. WARNING: unmet direct dependencies detected for QCS_GCC_615 Depends on [n]: COMMON_CLK [=y] && COMMON_CLK_QCOM [=m] && (ARM64 || COMPILE_TEST [=n]) Selected by [m]: - QCS_DISPCC_615 [=m] && COMMON_CLK [=y] && COMMON_CLK_QCOM [=m] - QCS_GPUCC_615 [=m] && COMMON_CLK [=y] && COMMON_CLK_QCOM [=m] - QCS_VIDEOCC_615 [=m] && COMMON_CLK [=y] && COMMON_CLK_QCOM [=m] Add the same dependency to these configurations to clear up the warnings. Cc: stable@vger.kernel.org Fixes: 9b47105f5434 ("clk: qcom: dispcc-qcs615: Add QCS615 display clock controller driver") Fixes: f4b5b40805ab ("clk: qcom: gpucc-qcs615: Add QCS615 graphics clock controller driver") Fixes: f6a8abe0cc16 ("clk: qcom: videocc-qcs615: Add QCS615 video clock controller driver") Signed-off-by: Nathan Chancellor Reviewed-by: Imran Shaik Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20250930-clk-qcom-kconfig-fixes-arm-v1-2-15ae1ae9ec9f@kernel.org Signed-off-by: Bjorn Andersson Signed-off-by: Greg Kroah-Hartman --- drivers/clk/qcom/Kconfig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index ec7d1a9b578e6..6fef0bfc17736 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -531,6 +531,7 @@ config QCM_DISPCC_2290 config QCS_DISPCC_615 tristate "QCS615 Display Clock Controller" + depends on ARM64 || COMPILE_TEST select QCS_GCC_615 help Support for the display clock controller on Qualcomm Technologies, Inc @@ -586,6 +587,7 @@ config QCS_GCC_615 config QCS_GPUCC_615 tristate "QCS615 Graphics clock controller" + depends on ARM64 || COMPILE_TEST select QCS_GCC_615 help Support for the graphics clock controller on QCS615 devices. @@ -594,6 +596,7 @@ config QCS_GPUCC_615 config QCS_VIDEOCC_615 tristate "QCS615 Video Clock Controller" + depends on ARM64 || COMPILE_TEST select QCS_GCC_615 help Support for the video clock controller on QCS615 devices. From e4077fcb1479405bbe902eac600092583e066359 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 25 Sep 2025 17:02:19 +0200 Subject: [PATCH 1586/2333] mfd: altera-sysmgr: Fix device leak on sysmgr regmap lookup commit ccb7cd3218e48665f3c7e19eede0da5f069c323d upstream. Make sure to drop the reference taken to the sysmgr platform device when retrieving its driver data. Note that holding a reference to a device does not prevent its driver data from going away. Fixes: f36e789a1f8d ("mfd: altera-sysmgr: Add SOCFPGA System Manager") Cc: stable@vger.kernel.org # 5.2 Signed-off-by: Johan Hovold Signed-off-by: Lee Jones Signed-off-by: Greg Kroah-Hartman --- drivers/mfd/altera-sysmgr.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/mfd/altera-sysmgr.c b/drivers/mfd/altera-sysmgr.c index fb5f988e61f37..90c6902d537da 100644 --- a/drivers/mfd/altera-sysmgr.c +++ b/drivers/mfd/altera-sysmgr.c @@ -117,6 +117,8 @@ struct regmap *altr_sysmgr_regmap_lookup_by_phandle(struct device_node *np, sysmgr = dev_get_drvdata(dev); + put_device(dev); + return sysmgr->regmap; } EXPORT_SYMBOL_GPL(altr_sysmgr_regmap_lookup_by_phandle); From 10eecb592afc854683366a8936accf43a197052c Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 23 Oct 2025 12:19:40 +0200 Subject: [PATCH 1587/2333] mfd: max77620: Fix potential IRQ chip conflict when probing two devices commit 2bac49bad1f3553cc3b3bfb22cc194e9bd9e8427 upstream. MAX77620 is most likely always a single device on the board, however nothing stops board designers to have two of them, thus same device driver could probe twice. Or user could manually try to probing second time. Device driver is not ready for that case, because it allocates statically 'struct regmap_irq_chip' as non-const and stores during probe in 'irq_drv_data' member a pointer to per-probe state container ('struct max77620_chip'). devm_regmap_add_irq_chip() does not make a copy of 'struct regmap_irq_chip' but store the pointer. Second probe - either successful or failure - would overwrite the 'irq_drv_data' from previous device probe, so interrupts would be executed in a wrong context. Cc: stable@vger.kernel.org Fixes: 3df140d11c6d ("mfd: max77620: Mask/unmask interrupt before/after servicing it") Signed-off-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20251023101939.67991-2-krzysztof.kozlowski@linaro.org Signed-off-by: Lee Jones Signed-off-by: Greg Kroah-Hartman --- drivers/mfd/max77620.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/drivers/mfd/max77620.c b/drivers/mfd/max77620.c index 21d2ab3db2542..3af2974b30232 100644 --- a/drivers/mfd/max77620.c +++ b/drivers/mfd/max77620.c @@ -254,7 +254,7 @@ static int max77620_irq_global_unmask(void *irq_drv_data) return ret; } -static struct regmap_irq_chip max77620_top_irq_chip = { +static const struct regmap_irq_chip max77620_top_irq_chip = { .name = "max77620-top", .irqs = max77620_top_irqs, .num_irqs = ARRAY_SIZE(max77620_top_irqs), @@ -498,6 +498,7 @@ static int max77620_probe(struct i2c_client *client) const struct i2c_device_id *id = i2c_client_get_device_id(client); const struct regmap_config *rmap_config; struct max77620_chip *chip; + struct regmap_irq_chip *chip_desc; const struct mfd_cell *mfd_cells; int n_mfd_cells; bool pm_off; @@ -508,6 +509,14 @@ static int max77620_probe(struct i2c_client *client) return -ENOMEM; i2c_set_clientdata(client, chip); + + chip_desc = devm_kmemdup(&client->dev, &max77620_top_irq_chip, + sizeof(max77620_top_irq_chip), + GFP_KERNEL); + if (!chip_desc) + return -ENOMEM; + chip_desc->irq_drv_data = chip; + chip->dev = &client->dev; chip->chip_irq = client->irq; chip->chip_id = (enum max77620_chip_id)id->driver_data; @@ -544,11 +553,9 @@ static int max77620_probe(struct i2c_client *client) if (ret < 0) return ret; - max77620_top_irq_chip.irq_drv_data = chip; ret = devm_regmap_add_irq_chip(chip->dev, chip->rmap, client->irq, IRQF_ONESHOT | IRQF_SHARED, 0, - &max77620_top_irq_chip, - &chip->top_irq_data); + chip_desc, &chip->top_irq_data); if (ret < 0) { dev_err(chip->dev, "Failed to add regmap irq: %d\n", ret); return ret; From e9918c6a0044b9e224bc8b1ceb6d7d956b3f4cab Mon Sep 17 00:00:00 2001 From: Haotian Zhang Date: Fri, 31 Oct 2025 14:03:32 +0800 Subject: [PATCH 1588/2333] media: rc: st_rc: Fix reset control resource leak commit 1240abf4b71f632f0117b056e22488e4d9808938 upstream. The driver calls reset_control_get_optional_exclusive() but never calls reset_control_put() in error paths or in the remove function. This causes a resource leak when probe fails after successfully acquiring the reset control, or when the driver is unloaded. Switch to devm_reset_control_get_optional_exclusive() to automatically manage the reset control resource. Fixes: a4b80242d046 ("media: st-rc: explicitly request exclusive reset control") Cc: stable@vger.kernel.org Signed-off-by: Haotian Zhang Reviewed-by: Patrice Chotard Signed-off-by: Sean Young Signed-off-by: Hans Verkuil Signed-off-by: Greg Kroah-Hartman --- drivers/media/rc/st_rc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/rc/st_rc.c b/drivers/media/rc/st_rc.c index 6539fa0a6e790..6b70bac5f45d6 100644 --- a/drivers/media/rc/st_rc.c +++ b/drivers/media/rc/st_rc.c @@ -284,7 +284,7 @@ static int st_rc_probe(struct platform_device *pdev) else rc_dev->rx_base = rc_dev->base; - rc_dev->rstc = reset_control_get_optional_exclusive(dev, NULL); + rc_dev->rstc = devm_reset_control_get_optional_exclusive(dev, NULL); if (IS_ERR(rc_dev->rstc)) { ret = PTR_ERR(rc_dev->rstc); goto err; From e768a9d22d38f5eaee245692455bc7764b251408 Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Mon, 22 Sep 2025 14:43:38 -0400 Subject: [PATCH 1589/2333] media: verisilicon: Fix CPU stalls on G2 bus error commit 19c286b755072a22a063052f530a6b1fac8a1f63 upstream. In some seek stress tests, we are getting IRQ from the G2 decoder where the dec_bus_int and the dec_e bits are high, meaning the decoder is still running despite the error. Fix this by reworking the IRQ handler to only finish the job once we have reached completion and move the software reset to when our software watchdog triggers. This way, we let the hardware continue on errors when it did not self reset and in worse case scenario the hardware timeout will automatically stop it. The actual error will be fixed in a follow up patch. Fixes: 3385c514ecc5a ("media: hantro: Convert imx8m_vpu_g2_irq to helper") Cc: stable@vger.kernel.org Reviewed-by: Benjamin Gaignard Signed-off-by: Nicolas Dufresne Signed-off-by: Hans Verkuil Signed-off-by: Greg Kroah-Hartman --- .../media/platform/verisilicon/hantro_g2.c | 88 +++++++++++++++---- .../platform/verisilicon/hantro_g2_hevc_dec.c | 2 - .../platform/verisilicon/hantro_g2_regs.h | 13 +++ .../platform/verisilicon/hantro_g2_vp9_dec.c | 2 - .../media/platform/verisilicon/hantro_hw.h | 1 + .../media/platform/verisilicon/imx8m_vpu_hw.c | 2 + 6 files changed, 85 insertions(+), 23 deletions(-) diff --git a/drivers/media/platform/verisilicon/hantro_g2.c b/drivers/media/platform/verisilicon/hantro_g2.c index aae0b562fabb1..318673b66da88 100644 --- a/drivers/media/platform/verisilicon/hantro_g2.c +++ b/drivers/media/platform/verisilicon/hantro_g2.c @@ -5,43 +5,93 @@ * Copyright (C) 2021 Collabora Ltd, Andrzej Pietrasiewicz */ +#include #include "hantro_hw.h" #include "hantro_g2_regs.h" #define G2_ALIGN 16 -void hantro_g2_check_idle(struct hantro_dev *vpu) +static bool hantro_g2_active(struct hantro_ctx *ctx) { - int i; - - for (i = 0; i < 3; i++) { - u32 status; - - /* Make sure the VPU is idle */ - status = vdpu_read(vpu, G2_REG_INTERRUPT); - if (status & G2_REG_INTERRUPT_DEC_E) { - dev_warn(vpu->dev, "device still running, aborting"); - status |= G2_REG_INTERRUPT_DEC_ABORT_E | G2_REG_INTERRUPT_DEC_IRQ_DIS; - vdpu_write(vpu, status, G2_REG_INTERRUPT); - } + struct hantro_dev *vpu = ctx->dev; + u32 status; + + status = vdpu_read(vpu, G2_REG_INTERRUPT); + + return (status & G2_REG_INTERRUPT_DEC_E); +} + +/** + * hantro_g2_reset: + * @ctx: the hantro context + * + * Emulates a reset using Hantro abort function. Failing this procedure would + * results in programming a running IP which leads to CPU hang. + * + * Using a hard reset procedure instead is prefferred. + */ +void hantro_g2_reset(struct hantro_ctx *ctx) +{ + struct hantro_dev *vpu = ctx->dev; + u32 status; + + status = vdpu_read(vpu, G2_REG_INTERRUPT); + if (status & G2_REG_INTERRUPT_DEC_E) { + dev_warn_ratelimited(vpu->dev, "device still running, aborting"); + status |= G2_REG_INTERRUPT_DEC_ABORT_E | G2_REG_INTERRUPT_DEC_IRQ_DIS; + vdpu_write(vpu, status, G2_REG_INTERRUPT); + + do { + mdelay(1); + } while (hantro_g2_active(ctx)); } } irqreturn_t hantro_g2_irq(int irq, void *dev_id) { struct hantro_dev *vpu = dev_id; - enum vb2_buffer_state state; u32 status; status = vdpu_read(vpu, G2_REG_INTERRUPT); - state = (status & G2_REG_INTERRUPT_DEC_RDY_INT) ? - VB2_BUF_STATE_DONE : VB2_BUF_STATE_ERROR; - vdpu_write(vpu, 0, G2_REG_INTERRUPT); - vdpu_write(vpu, G2_REG_CONFIG_DEC_CLK_GATE_E, G2_REG_CONFIG); + if (!(status & G2_REG_INTERRUPT_DEC_IRQ)) + return IRQ_NONE; + + hantro_reg_write(vpu, &g2_dec_irq, 0); + hantro_reg_write(vpu, &g2_dec_int_stat, 0); + hantro_reg_write(vpu, &g2_clk_gate_e, 1); + + if (status & G2_REG_INTERRUPT_DEC_RDY_INT) { + hantro_irq_done(vpu, VB2_BUF_STATE_DONE); + return IRQ_HANDLED; + } + + if (status & G2_REG_INTERRUPT_DEC_ABORT_INT) { + /* disabled on abort, though lets be safe and handle it */ + dev_warn_ratelimited(vpu->dev, "decode operation aborted."); + return IRQ_HANDLED; + } + + if (status & G2_REG_INTERRUPT_DEC_LAST_SLICE_INT) + dev_warn_ratelimited(vpu->dev, "not all macroblocks were decoded."); + + if (status & G2_REG_INTERRUPT_DEC_BUS_INT) + dev_warn_ratelimited(vpu->dev, "bus error detected."); + + if (status & G2_REG_INTERRUPT_DEC_ERROR_INT) + dev_warn_ratelimited(vpu->dev, "decode error detected."); + + if (status & G2_REG_INTERRUPT_DEC_TIMEOUT) + dev_warn_ratelimited(vpu->dev, "frame decode timed out."); - hantro_irq_done(vpu, state); + /** + * If the decoding haven't stopped, let it continue. The hardware timeout + * will trigger if it is trully stuck. + */ + if (status & G2_REG_INTERRUPT_DEC_E) + return IRQ_HANDLED; + hantro_irq_done(vpu, VB2_BUF_STATE_ERROR); return IRQ_HANDLED; } diff --git a/drivers/media/platform/verisilicon/hantro_g2_hevc_dec.c b/drivers/media/platform/verisilicon/hantro_g2_hevc_dec.c index 0e212198dd65b..f066636e56f98 100644 --- a/drivers/media/platform/verisilicon/hantro_g2_hevc_dec.c +++ b/drivers/media/platform/verisilicon/hantro_g2_hevc_dec.c @@ -582,8 +582,6 @@ int hantro_g2_hevc_dec_run(struct hantro_ctx *ctx) struct hantro_dev *vpu = ctx->dev; int ret; - hantro_g2_check_idle(vpu); - /* Prepare HEVC decoder context. */ ret = hantro_hevc_dec_prepare_run(ctx); if (ret) diff --git a/drivers/media/platform/verisilicon/hantro_g2_regs.h b/drivers/media/platform/verisilicon/hantro_g2_regs.h index b943b1816db7f..c614951121c79 100644 --- a/drivers/media/platform/verisilicon/hantro_g2_regs.h +++ b/drivers/media/platform/verisilicon/hantro_g2_regs.h @@ -22,7 +22,14 @@ #define G2_REG_VERSION G2_SWREG(0) #define G2_REG_INTERRUPT G2_SWREG(1) +#define G2_REG_INTERRUPT_DEC_LAST_SLICE_INT BIT(19) +#define G2_REG_INTERRUPT_DEC_TIMEOUT BIT(18) +#define G2_REG_INTERRUPT_DEC_ERROR_INT BIT(16) +#define G2_REG_INTERRUPT_DEC_BUF_INT BIT(14) +#define G2_REG_INTERRUPT_DEC_BUS_INT BIT(13) #define G2_REG_INTERRUPT_DEC_RDY_INT BIT(12) +#define G2_REG_INTERRUPT_DEC_ABORT_INT BIT(11) +#define G2_REG_INTERRUPT_DEC_IRQ BIT(8) #define G2_REG_INTERRUPT_DEC_ABORT_E BIT(5) #define G2_REG_INTERRUPT_DEC_IRQ_DIS BIT(4) #define G2_REG_INTERRUPT_DEC_E BIT(0) @@ -35,6 +42,9 @@ #define BUS_WIDTH_128 2 #define BUS_WIDTH_256 3 +#define g2_dec_int_stat G2_DEC_REG(1, 11, 0xf) +#define g2_dec_irq G2_DEC_REG(1, 8, 0x1) + #define g2_strm_swap G2_DEC_REG(2, 28, 0xf) #define g2_strm_swap_old G2_DEC_REG(2, 27, 0x1f) #define g2_pic_swap G2_DEC_REG(2, 22, 0x1f) @@ -225,6 +235,9 @@ #define vp9_filt_level_seg5 G2_DEC_REG(19, 8, 0x3f) #define vp9_quant_seg5 G2_DEC_REG(19, 0, 0xff) +#define g2_timemout_override_e G2_DEC_REG(45, 31, 0x1) +#define g2_timemout_cycles G2_DEC_REG(45, 0, 0x7fffffff) + #define hevc_cur_poc_00 G2_DEC_REG(46, 24, 0xff) #define hevc_cur_poc_01 G2_DEC_REG(46, 16, 0xff) #define hevc_cur_poc_02 G2_DEC_REG(46, 8, 0xff) diff --git a/drivers/media/platform/verisilicon/hantro_g2_vp9_dec.c b/drivers/media/platform/verisilicon/hantro_g2_vp9_dec.c index 82a478ac645e1..56c79e339030e 100644 --- a/drivers/media/platform/verisilicon/hantro_g2_vp9_dec.c +++ b/drivers/media/platform/verisilicon/hantro_g2_vp9_dec.c @@ -893,8 +893,6 @@ int hantro_g2_vp9_dec_run(struct hantro_ctx *ctx) struct vb2_v4l2_buffer *dst; int ret; - hantro_g2_check_idle(ctx->dev); - ret = start_prepare_run(ctx, &decode_params); if (ret) { hantro_end_prepare_run(ctx); diff --git a/drivers/media/platform/verisilicon/hantro_hw.h b/drivers/media/platform/verisilicon/hantro_hw.h index c9b6556f8b2b7..5f2011529f02d 100644 --- a/drivers/media/platform/verisilicon/hantro_hw.h +++ b/drivers/media/platform/verisilicon/hantro_hw.h @@ -583,6 +583,7 @@ void hantro_g2_vp9_dec_done(struct hantro_ctx *ctx); int hantro_vp9_dec_init(struct hantro_ctx *ctx); void hantro_vp9_dec_exit(struct hantro_ctx *ctx); void hantro_g2_check_idle(struct hantro_dev *vpu); +void hantro_g2_reset(struct hantro_ctx *ctx); irqreturn_t hantro_g2_irq(int irq, void *dev_id); #endif /* HANTRO_HW_H_ */ diff --git a/drivers/media/platform/verisilicon/imx8m_vpu_hw.c b/drivers/media/platform/verisilicon/imx8m_vpu_hw.c index f9f276385c117..5be0e2e76882f 100644 --- a/drivers/media/platform/verisilicon/imx8m_vpu_hw.c +++ b/drivers/media/platform/verisilicon/imx8m_vpu_hw.c @@ -294,11 +294,13 @@ static const struct hantro_codec_ops imx8mq_vpu_g1_codec_ops[] = { static const struct hantro_codec_ops imx8mq_vpu_g2_codec_ops[] = { [HANTRO_MODE_HEVC_DEC] = { .run = hantro_g2_hevc_dec_run, + .reset = hantro_g2_reset, .init = hantro_hevc_dec_init, .exit = hantro_hevc_dec_exit, }, [HANTRO_MODE_VP9_DEC] = { .run = hantro_g2_vp9_dec_run, + .reset = hantro_g2_reset, .done = hantro_g2_vp9_dec_done, .init = hantro_vp9_dec_init, .exit = hantro_vp9_dec_exit, From 51615b85109b6d92a3df78b251c3539af00c2eff Mon Sep 17 00:00:00 2001 From: Paresh Bhagat Date: Wed, 29 Oct 2025 02:31:53 +0530 Subject: [PATCH 1590/2333] arm64: dts: ti: k3-am62d2-evm: Fix regulator properties commit 0103435072bf5c54bb43d1a9376d08396c825827 upstream. Fix missing supply for regulators TLV7103318QDSERQ1 and TPS22918DBVR. Correct padconfig and gpio for TLV7103318QDSERQ1. Reference Docs Datasheet - https://www.ti.com/lit/ug/sprujd4/sprujd4.pdf Schematics - https://www.ti.com/lit/zip/sprcal5 Fixes: 1544bca2f188e ("arm64: dts: ti: Add support for AM62D2-EVM") Cc: stable@vger.kernel.org Signed-off-by: Paresh Bhagat Reviewed-by: Shree Ramamoorthy Link: https://patch.msgid.link/20251028210153.420473-1-p-bhagat@ti.com Signed-off-by: Vignesh Raghavendra Signed-off-by: Greg Kroah-Hartman --- arch/arm64/boot/dts/ti/k3-am62d2-evm.dts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/ti/k3-am62d2-evm.dts b/arch/arm64/boot/dts/ti/k3-am62d2-evm.dts index 83af889e790ae..d202484eec3fb 100644 --- a/arch/arm64/boot/dts/ti/k3-am62d2-evm.dts +++ b/arch/arm64/boot/dts/ti/k3-am62d2-evm.dts @@ -146,6 +146,7 @@ regulator-name = "vdd_mmc1"; regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; + vin-supply = <&vcc_3v3_sys>; regulator-boot-on; enable-active-high; gpio = <&exp1 3 GPIO_ACTIVE_HIGH>; @@ -165,14 +166,16 @@ }; vddshv_sdio: regulator-6 { + /* output of TLV7103318QDSERQ1 */ compatible = "regulator-gpio"; regulator-name = "vddshv_sdio"; pinctrl-names = "default"; pinctrl-0 = <&vddshv_sdio_pins_default>; regulator-min-microvolt = <1800000>; regulator-max-microvolt = <3300000>; + vin-supply = <&vcc_5v0>; regulator-boot-on; - gpios = <&main_gpio1 31 GPIO_ACTIVE_HIGH>; + gpios = <&main_gpio0 59 GPIO_ACTIVE_HIGH>; states = <1800000 0x0>, <3300000 0x1>; bootph-all; @@ -334,7 +337,7 @@ vddshv_sdio_pins_default: vddshv-sdio-default-pins { pinctrl-single,pins = < - AM62DX_IOPAD(0x1f4, PIN_OUTPUT, 7) /* (M19) GPMC0_CLK.GPIO1_31 */ + AM62DX_IOPAD(0x00f0, PIN_INPUT, 7) /* (Y21) GPIO0_59 */ >; bootph-all; }; From 0b963a6b61373c7f113ce98f6408dfb422caa79f Mon Sep 17 00:00:00 2001 From: Paresh Bhagat Date: Wed, 29 Oct 2025 03:06:44 +0530 Subject: [PATCH 1591/2333] arm64: dts: ti: k3-am62d2-evm: Fix PMIC padconfig commit 394b02210a81c06c4cb879d65ba83d0f1c468c84 upstream. Fix the PMIC padconfig for AM62D. PMIC's INT pin is connected to the SoC's EXTINTn input. Reference Docs Datasheet - https://www.ti.com/lit/ug/sprujd4/sprujd4.pdf Schematics - https://www.ti.com/lit/zip/sprcal5 Fixes: 1544bca2f188e ("arm64: dts: ti: Add support for AM62D2-EVM") Cc: stable@vger.kernel.org Signed-off-by: Paresh Bhagat Link: https://patch.msgid.link/20251028213645.437957-2-p-bhagat@ti.com Signed-off-by: Vignesh Raghavendra Signed-off-by: Greg Kroah-Hartman --- arch/arm64/boot/dts/ti/k3-am62d2-evm.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/ti/k3-am62d2-evm.dts b/arch/arm64/boot/dts/ti/k3-am62d2-evm.dts index d202484eec3fb..9a74df221f2ad 100644 --- a/arch/arm64/boot/dts/ti/k3-am62d2-evm.dts +++ b/arch/arm64/boot/dts/ti/k3-am62d2-evm.dts @@ -201,7 +201,7 @@ pmic_irq_pins_default: pmic-irq-default-pins { pinctrl-single,pins = < - AM62DX_MCU_IOPAD(0x000, PIN_INPUT, 7) /* (E11) MCU_GPIO0_0 */ + AM62DX_IOPAD(0x01f4, PIN_INPUT, 7) /* (F17) EXTINTn.GPIO1_31 */ >; }; From 29dc88cc131de7eda2587ba9c3057cfb847ea93f Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Fri, 31 Oct 2025 15:07:03 +0100 Subject: [PATCH 1592/2333] arm64: dts: st: Add memory-region-names property for stm32mp257f-ev1 commit 22f0ae971cf5536349521853737d3e06203286d8 upstream. In order to set the AMCR register, which configures the memory-region split between ospi1 and ospi2, we need to identify the ospi instance. By using memory-region-names, it allows to identify the ospi instance this memory-region belongs to. Fixes: cad2492de91c ("arm64: dts: st: Add SPI NOR flash support on stm32mp257f-ev1 board") Signed-off-by: Patrice Chotard Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20251031-upstream_fix_dts_omm-v4-1-e4a059a50074@foss.st.com Signed-off-by: Alexandre Torgue Signed-off-by: Greg Kroah-Hartman --- arch/arm64/boot/dts/st/stm32mp257f-ev1.dts | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/boot/dts/st/stm32mp257f-ev1.dts b/arch/arm64/boot/dts/st/stm32mp257f-ev1.dts index 6e165073f7329..bb6d6393d2e46 100644 --- a/arch/arm64/boot/dts/st/stm32mp257f-ev1.dts +++ b/arch/arm64/boot/dts/st/stm32mp257f-ev1.dts @@ -266,6 +266,7 @@ &ommanager { memory-region = <&mm_ospi1>; + memory-region-names = "ospi1"; pinctrl-0 = <&ospi_port1_clk_pins_a &ospi_port1_io03_pins_a &ospi_port1_cs0_pins_a>; From 65b96ed954b4eacf64e07e5574757009d0b5dff0 Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Thu, 23 Oct 2025 13:39:26 +0200 Subject: [PATCH 1593/2333] arm64: dts: qcom: sm6350: Fix wrong order of freq-table-hz for UFS commit ec9d588391761a08aab5eb4523a48ef3df2c910f upstream. During upstreaming the order of clocks was adjusted to match the upstream sort order, but mistakently freq-table-hz wasn't re-ordered with the new order. Fix that by moving the entry for the ICE clk to the last place. Fixes: 5a814af5fc22 ("arm64: dts: qcom: sm6350: Add UFS nodes") Cc: stable@vger.kernel.org Reviewed-by: Dmitry Baryshkov Reviewed-by: Konrad Dybcio Signed-off-by: Luca Weiss Link: https://lore.kernel.org/r/20251023-sm6350-ufs-things-v3-1-b68b74e29d35@fairphone.com Signed-off-by: Bjorn Andersson Signed-off-by: Greg Kroah-Hartman --- arch/arm64/boot/dts/qcom/sm6350.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm6350.dtsi b/arch/arm64/boot/dts/qcom/sm6350.dtsi index 8459b27cacc72..19a7b9f9ea8bc 100644 --- a/arch/arm64/boot/dts/qcom/sm6350.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6350.dtsi @@ -1180,11 +1180,11 @@ <0 0>, <0 0>, <37500000 150000000>, - <75000000 300000000>, <0 0>, <0 0>, <0 0>, - <0 0>; + <0 0>, + <75000000 300000000>; status = "disabled"; }; From 69a585efbf9c145d6b6d39d9c9dc7a0d6eef8473 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Sun, 9 Nov 2025 12:52:44 +0100 Subject: [PATCH 1594/2333] mtd: mtdpart: ignore error -ENOENT from parsers on subpartitions commit 64ef5f454e167bb66cf70104f033c3d71e6ef9c0 upstream. Commit 5c2f7727d437 ("mtd: mtdpart: check for subpartitions parsing result") introduced some kind of regression with parser on subpartitions where if a parser emits an error then the entire parsing process from the upper parser fails and partitions are deleted. Not checking for error in subpartitions was originally intended as special parser can emit error also in the case of the partition not correctly init (for example a wiped partition) or special case where the partition should be skipped due to some ENV variables externally provided (from bootloader for example) One example case is the TRX partition where, in the context of a wiped partition, returns a -ENOENT as the trx_magic is not found in the expected TRX header (as the partition is wiped) To better handle this and still keep some kind of error tracking (for example to catch -ENOMEM errors or -EINVAL errors), permit parser on subpartition to emit -ENOENT error, print a debug log and skip them accordingly. This results in giving better tracking of the status of the parser (instead of returning just 0, dropping any kind of signal that there is something wrong with the parser) and to some degree restore the original logic of the subpartitions parse. (worth to notice that some special partition might have all the special header present for the parser and declare 0 partition in it, this is why it would be wrong to simply return 0 in the case of a special partition that is NOT init for the scanning parser) Cc: stable@vger.kernel.org Fixes: 5c2f7727d437 ("mtd: mtdpart: check for subpartitions parsing result") Signed-off-by: Christian Marangi Signed-off-by: Miquel Raynal Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/mtdpart.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index 994e8c51e6743..2876501a78145 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c @@ -425,9 +425,12 @@ int add_mtd_partitions(struct mtd_info *parent, mtd_add_partition_attrs(child); - /* Look for subpartitions */ + /* Look for subpartitions (skip if no maching parser found) */ ret = parse_mtd_partitions(child, parts[i].types, NULL); - if (ret < 0) { + if (ret < 0 && ret == -ENOENT) { + pr_debug("Skip parsing subpartitions: %d\n", ret); + continue; + } else if (ret < 0) { pr_err("Failed to parse subpartitions: %d\n", ret); goto err_del_partitions; } From 0066afc04fd92d62c2ab3990a3241dadf90c2342 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Wed, 5 Nov 2025 18:27:00 +0100 Subject: [PATCH 1595/2333] mtd: spi-nor: winbond: Add support for W25Q01NWxxIQ chips commit aee8c4d9d48d661624d72de670ebe5c6b5687842 upstream. This chip must be described as none of the block protection information are discoverable. This chip supports 4 bits plus the top/bottom addressing capability to identify the protected blocks. Cc: stable@vger.kernel.org Signed-off-by: Miquel Raynal Reviewed-by: Michael Walle Signed-off-by: Pratyush Yadav Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/spi-nor/winbond.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/mtd/spi-nor/winbond.c b/drivers/mtd/spi-nor/winbond.c index 63a93c9eb9174..a13a1201eae92 100644 --- a/drivers/mtd/spi-nor/winbond.c +++ b/drivers/mtd/spi-nor/winbond.c @@ -343,6 +343,10 @@ static const struct flash_info winbond_nor_parts[] = { .id = SNOR_ID(0xef, 0x80, 0x20), .name = "w25q512nwm", .otp = SNOR_OTP(256, 3, 0x1000, 0x1000), + }, { + /* W25Q01NWxxIQ */ + .id = SNOR_ID(0xef, 0x60, 0x21), + .flags = SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_TB_SR_BIT6 | SPI_NOR_4BIT_BP, }, }; From 609b73efab92e3d3240e64008aa2373da58e1752 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Wed, 5 Nov 2025 18:27:01 +0100 Subject: [PATCH 1596/2333] mtd: spi-nor: winbond: Add support for W25Q01NWxxIM chips commit a607e676c8b9258eabc3fc88f45bcd70ea178b41 upstream. These chips must be described as none of the block protection information are discoverable. This chip supports 4 bits plus the top/bottom addressing capability to identify the protected blocks. Cc: stable@vger.kernel.org Signed-off-by: Miquel Raynal Reviewed-by: Michael Walle Signed-off-by: Pratyush Yadav Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/spi-nor/winbond.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/mtd/spi-nor/winbond.c b/drivers/mtd/spi-nor/winbond.c index a13a1201eae92..580c9cb379581 100644 --- a/drivers/mtd/spi-nor/winbond.c +++ b/drivers/mtd/spi-nor/winbond.c @@ -347,6 +347,10 @@ static const struct flash_info winbond_nor_parts[] = { /* W25Q01NWxxIQ */ .id = SNOR_ID(0xef, 0x60, 0x21), .flags = SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_TB_SR_BIT6 | SPI_NOR_4BIT_BP, + }, { + /* W25Q01NWxxIM */ + .id = SNOR_ID(0xef, 0x80, 0x21), + .flags = SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_TB_SR_BIT6 | SPI_NOR_4BIT_BP, }, }; From ac1a8b2244dd112ed1f2b1c242ea553af217c73e Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Wed, 5 Nov 2025 18:27:02 +0100 Subject: [PATCH 1597/2333] mtd: spi-nor: winbond: Add support for W25Q02NWxxIM chips commit 71c239348d9fbdb1f0d6f36013f1697cc06c3e9c upstream. These chips must be described as none of the block protection information are discoverable. This chip supports 4 bits plus the top/bottom addressing capability to identify the protected blocks. Cc: stable@vger.kernel.org Signed-off-by: Miquel Raynal Reviewed-by: Michael Walle Signed-off-by: Pratyush Yadav Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/spi-nor/winbond.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/mtd/spi-nor/winbond.c b/drivers/mtd/spi-nor/winbond.c index 580c9cb379581..a65cbbccbbac6 100644 --- a/drivers/mtd/spi-nor/winbond.c +++ b/drivers/mtd/spi-nor/winbond.c @@ -351,6 +351,10 @@ static const struct flash_info winbond_nor_parts[] = { /* W25Q01NWxxIM */ .id = SNOR_ID(0xef, 0x80, 0x21), .flags = SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_TB_SR_BIT6 | SPI_NOR_4BIT_BP, + }, { + /* W25Q02NWxxIM */ + .id = SNOR_ID(0xef, 0x80, 0x22), + .flags = SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_TB_SR_BIT6 | SPI_NOR_4BIT_BP, }, }; From c54fec6b0cb954ebf7a7354d3a017c3a29244d91 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Wed, 5 Nov 2025 18:27:03 +0100 Subject: [PATCH 1598/2333] mtd: spi-nor: winbond: Add support for W25H512NWxxAM chips commit f21d2c7d37553b24825918f2f61df123e182b712 upstream. These chips must be described as none of the block protection information are discoverable. This chip supports 4 bits plus the top/bottom addressing capability to identify the protected blocks. Cc: stable@vger.kernel.org Signed-off-by: Miquel Raynal Reviewed-by: Michael Walle Signed-off-by: Pratyush Yadav Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/spi-nor/winbond.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/mtd/spi-nor/winbond.c b/drivers/mtd/spi-nor/winbond.c index a65cbbccbbac6..781ca0abfcdca 100644 --- a/drivers/mtd/spi-nor/winbond.c +++ b/drivers/mtd/spi-nor/winbond.c @@ -355,6 +355,10 @@ static const struct flash_info winbond_nor_parts[] = { /* W25Q02NWxxIM */ .id = SNOR_ID(0xef, 0x80, 0x22), .flags = SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_TB_SR_BIT6 | SPI_NOR_4BIT_BP, + }, { + /* W25H512NWxxAM */ + .id = SNOR_ID(0xef, 0xa0, 0x20), + .flags = SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_TB_SR_BIT6 | SPI_NOR_4BIT_BP, }, }; From 7708a5031a404a5a24d324dd461b0fa00cf6d67e Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Wed, 5 Nov 2025 18:27:04 +0100 Subject: [PATCH 1599/2333] mtd: spi-nor: winbond: Add support for W25H01NWxxAM chips commit 1df1fdbc7e63350b2962dc7d87ded124ee26f3ad upstream. These chips must be described as none of the block protection information are discoverable. This chip supports 4 bits plus the top/bottom addressing capability to identify the protected blocks. Cc: stable@vger.kernel.org Signed-off-by: Miquel Raynal Reviewed-by: Michael Walle Signed-off-by: Pratyush Yadav Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/spi-nor/winbond.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/mtd/spi-nor/winbond.c b/drivers/mtd/spi-nor/winbond.c index 781ca0abfcdca..338e44db506a8 100644 --- a/drivers/mtd/spi-nor/winbond.c +++ b/drivers/mtd/spi-nor/winbond.c @@ -359,6 +359,10 @@ static const struct flash_info winbond_nor_parts[] = { /* W25H512NWxxAM */ .id = SNOR_ID(0xef, 0xa0, 0x20), .flags = SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_TB_SR_BIT6 | SPI_NOR_4BIT_BP, + }, { + /* W25H01NWxxAM */ + .id = SNOR_ID(0xef, 0xa0, 0x21), + .flags = SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_TB_SR_BIT6 | SPI_NOR_4BIT_BP, }, }; From 71f630e367541808ff7e2166f57af6c075b132b9 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Wed, 5 Nov 2025 18:27:05 +0100 Subject: [PATCH 1600/2333] mtd: spi-nor: winbond: Add support for W25H02NWxxAM chips commit 604cf6a40157abba4677dea9834de8df9047d798 upstream. These chips must be described as none of the block protection information are discoverable. This chip supports 4 bits plus the top/bottom addressing capability to identify the protected blocks. Cc: stable@vger.kernel.org Signed-off-by: Miquel Raynal Reviewed-by: Michael Walle Signed-off-by: Pratyush Yadav Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/spi-nor/winbond.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/mtd/spi-nor/winbond.c b/drivers/mtd/spi-nor/winbond.c index 338e44db506a8..fb855fe44733d 100644 --- a/drivers/mtd/spi-nor/winbond.c +++ b/drivers/mtd/spi-nor/winbond.c @@ -363,6 +363,10 @@ static const struct flash_info winbond_nor_parts[] = { /* W25H01NWxxAM */ .id = SNOR_ID(0xef, 0xa0, 0x21), .flags = SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_TB_SR_BIT6 | SPI_NOR_4BIT_BP, + }, { + /* W25H02NWxxAM */ + .id = SNOR_ID(0xef, 0xa0, 0x22), + .flags = SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_TB_SR_BIT6 | SPI_NOR_4BIT_BP, }, }; From 7d94efe685186816e7e33f9fbe95e13747a1036d Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Tue, 11 Nov 2025 09:59:30 -0500 Subject: [PATCH 1601/2333] NFSD: Make FILE_SYNC WRITEs comply with spec commit e3e8e176ca4876e6212582022ad80835dddc9de4 upstream. Mike noted that when NFSD responds to an NFS_FILE_SYNC WRITE, it does not also persist file time stamps. To wit, Section 18.32.3 of RFC 8881 mandates: > The client specifies with the stable parameter the method of how > the data is to be processed by the server. If stable is > FILE_SYNC4, the server MUST commit the data written plus all file > system metadata to stable storage before returning results. This > corresponds to the NFSv2 protocol semantics. Any other behavior > constitutes a protocol violation. If stable is DATA_SYNC4, then > the server MUST commit all of the data to stable storage and > enough of the metadata to retrieve the data before returning. Commit 3f3503adb332 ("NFSD: Use vfs_iocb_iter_write()") replaced: - flags |= RWF_SYNC; with: + kiocb.ki_flags |= IOCB_DSYNC; which appears to be correct given: if (flags & RWF_SYNC) kiocb_flags |= IOCB_DSYNC; in kiocb_set_rw_flags(). However the author of that commit did not appreciate that the previous line in kiocb_set_rw_flags() results in IOCB_SYNC also being set: kiocb_flags |= (__force int) (flags & RWF_SUPPORTED); RWF_SUPPORTED contains RWF_SYNC, and RWF_SYNC is the same bit as IOCB_SYNC. Reviewers at the time did not catch the omission. Reported-by: Mike Snitzer Closes: https://lore.kernel.org/linux-nfs/20251018005431.3403-1-cel@kernel.org/T/#t Fixes: 3f3503adb332 ("NFSD: Use vfs_iocb_iter_write()") Cc: stable@vger.kernel.org Reviewed-by: Jeff Layton Reviewed-by: NeilBrown Reviewed-by: Christoph Hellwig Signed-off-by: Chuck Lever Signed-off-by: Greg Kroah-Hartman --- fs/nfsd/vfs.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 9cb20d4aeab15..9f0b8bbc41442 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -1228,8 +1228,18 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, stable = NFS_UNSTABLE; init_sync_kiocb(&kiocb, file); kiocb.ki_pos = offset; - if (stable && !fhp->fh_use_wgather) - kiocb.ki_flags |= IOCB_DSYNC; + if (likely(!fhp->fh_use_wgather)) { + switch (stable) { + case NFS_FILE_SYNC: + /* persist data and timestamps */ + kiocb.ki_flags |= IOCB_DSYNC | IOCB_SYNC; + break; + case NFS_DATA_SYNC: + /* persist data only */ + kiocb.ki_flags |= IOCB_DSYNC; + break; + } + } nvecs = xdr_buf_to_bvec(rqstp->rq_bvec, rqstp->rq_maxpages, payload); iov_iter_bvec(&iter, ITER_SOURCE, rqstp->rq_bvec, nvecs, *cnt); From 116f511839e1a851b3d8be8e63b9c46d3e145774 Mon Sep 17 00:00:00 2001 From: Shin'ichiro Kawasaki Date: Tue, 9 Sep 2025 13:21:22 +0200 Subject: [PATCH 1602/2333] nvmet: pci-epf: move DMA initialization to EPC init callback commit 511b3b644e28d9b66e32515a74c57ff599e89035 upstream. For DMA initialization to work across all EPC drivers, the DMA initialization has to be done in the .init() callback. This is because not all EPC drivers will have a refclock (which is often needed to access registers of a DMA controller embedded in a PCIe controller) at the time the .bind() callback is called. However, all EPC drivers are guaranteed to have a refclock by the time the .init() callback is called. Thus, move the DMA initialization to the .init() callback. This change was already done for other EPF drivers in commit 60bd3e039aa2 ("PCI: endpoint: pci-epf-{mhi/test}: Move DMA initialization to EPC init callback"). Cc: stable@vger.kernel.org Fixes: 0faa0fe6f90e ("nvmet: New NVMe PCI endpoint function target driver") Signed-off-by: Shin'ichiro Kawasaki Signed-off-by: Niklas Cassel Reviewed-by: Damien Le Moal Signed-off-by: Keith Busch Signed-off-by: Greg Kroah-Hartman --- drivers/nvme/target/pci-epf.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/nvme/target/pci-epf.c b/drivers/nvme/target/pci-epf.c index 2e78397a7373a..9c5b0f78ce8df 100644 --- a/drivers/nvme/target/pci-epf.c +++ b/drivers/nvme/target/pci-epf.c @@ -2325,6 +2325,8 @@ static int nvmet_pci_epf_epc_init(struct pci_epf *epf) return ret; } + nvmet_pci_epf_init_dma(nvme_epf); + /* Set device ID, class, etc. */ epf->header->vendorid = ctrl->tctrl->subsys->vendor_id; epf->header->subsys_vendor_id = ctrl->tctrl->subsys->subsys_vendor_id; @@ -2422,8 +2424,6 @@ static int nvmet_pci_epf_bind(struct pci_epf *epf) if (ret) return ret; - nvmet_pci_epf_init_dma(nvme_epf); - return 0; } From 1d0cebc41d83a93655e0d507a8ee358d4c75d836 Mon Sep 17 00:00:00 2001 From: Sven Schnelle Date: Thu, 30 Oct 2025 08:56:05 +0100 Subject: [PATCH 1603/2333] parisc: entry.S: fix space adjustment on interruption for 64-bit userspace commit 1aa4524c0c1b54842c4c0a370171d11b12d0709b upstream. In wide mode, the IASQ contain the upper part of the GVA during interruption. This needs to be reversed before the space is used - otherwise it contains parts of IAOQ. See Page 2-13 "Processing Resources / Interruption Instruction Address Queues" in the Parisc 2.0 Architecture Manual page 2-13 for an explanation. The IAOQ/IASQ space_adjust was skipped for other interruptions than itlb misses. However, the code in handle_interruption() checks whether iasq[0] contains a valid space. Due to the not masked out bits this match failed and the process was killed. Also add space_adjust for IAOQ1/IASQ1 so ptregs contains sane values. Signed-off-by: Sven Schnelle Cc: stable@vger.kernel.org # v6.0+ Signed-off-by: Helge Deller Signed-off-by: Greg Kroah-Hartman --- arch/parisc/kernel/entry.S | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/arch/parisc/kernel/entry.S b/arch/parisc/kernel/entry.S index f4bf61a34701e..bb383487e302d 100644 --- a/arch/parisc/kernel/entry.S +++ b/arch/parisc/kernel/entry.S @@ -1059,8 +1059,6 @@ ENTRY_CFI(intr_save) /* for os_hpmc */ STREG %r17, PT_IOR(%r29) #if defined(CONFIG_64BIT) - b,n intr_save2 - skip_save_ior: /* We have a itlb miss, and when executing code above 4 Gb on ILP64, we * need to adjust iasq/iaoq here in the same way we adjusted isr/ior @@ -1069,10 +1067,17 @@ skip_save_ior: bb,COND(>=),n %r8,PSW_W_BIT,intr_save2 LDREG PT_IASQ0(%r29), %r16 LDREG PT_IAOQ0(%r29), %r17 - /* adjust iasq/iaoq */ + /* adjust iasq0/iaoq0 */ space_adjust %r16,%r17,%r1 STREG %r16, PT_IASQ0(%r29) STREG %r17, PT_IAOQ0(%r29) + + LDREG PT_IASQ1(%r29), %r16 + LDREG PT_IAOQ1(%r29), %r17 + /* adjust iasq1/iaoq1 */ + space_adjust %r16,%r17,%r1 + STREG %r16, PT_IASQ1(%r29) + STREG %r17, PT_IAOQ1(%r29) #else skip_save_ior: #endif From a66cd0e5e034e323d04083c1902cc471806b5a9a Mon Sep 17 00:00:00 2001 From: Sven Schnelle Date: Wed, 15 Oct 2025 23:21:41 +0200 Subject: [PATCH 1604/2333] parisc: entry: set W bit for !compat tasks in syscall_restore_rfi() commit 5fb1d3ce3e74a4530042795e1e065422295f1371 upstream. When the kernel leaves to userspace via syscall_restore_rfi(), the W bit is not set in the new PSW. This doesn't cause any problems because there's no 64 bit userspace for parisc. Simple static binaries are usually loaded at addresses way below the 32 bit limit so the W bit doesn't matter. Fix this by setting the W bit when TIF_32BIT is not set. Signed-off-by: Sven Schnelle Cc: stable@vger.kernel.org Signed-off-by: Helge Deller Signed-off-by: Greg Kroah-Hartman --- arch/parisc/kernel/asm-offsets.c | 2 ++ arch/parisc/kernel/entry.S | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/arch/parisc/kernel/asm-offsets.c b/arch/parisc/kernel/asm-offsets.c index 9abfe65492c65..3de4b5933b107 100644 --- a/arch/parisc/kernel/asm-offsets.c +++ b/arch/parisc/kernel/asm-offsets.c @@ -258,6 +258,8 @@ int main(void) BLANK(); DEFINE(TIF_BLOCKSTEP_PA_BIT, 31-TIF_BLOCKSTEP); DEFINE(TIF_SINGLESTEP_PA_BIT, 31-TIF_SINGLESTEP); + DEFINE(TIF_32BIT_PA_BIT, 31-TIF_32BIT); + BLANK(); DEFINE(ASM_PMD_SHIFT, PMD_SHIFT); DEFINE(ASM_PGDIR_SHIFT, PGDIR_SHIFT); diff --git a/arch/parisc/kernel/entry.S b/arch/parisc/kernel/entry.S index bb383487e302d..e04c5d806c105 100644 --- a/arch/parisc/kernel/entry.S +++ b/arch/parisc/kernel/entry.S @@ -1846,6 +1846,10 @@ syscall_restore_rfi: extru,= %r19,TIF_BLOCKSTEP_PA_BIT,1,%r0 depi -1,7,1,%r20 /* T bit */ +#ifdef CONFIG_64BIT + extru,<> %r19,TIF_32BIT_PA_BIT,1,%r0 + depi -1,4,1,%r20 /* W bit */ +#endif STREG %r20,TASK_PT_PSW(%r1) /* Always store space registers, since sr3 can be changed (e.g. fork) */ @@ -1859,7 +1863,6 @@ syscall_restore_rfi: STREG %r25,TASK_PT_IASQ0(%r1) STREG %r25,TASK_PT_IASQ1(%r1) - /* XXX W bit??? */ /* Now if old D bit is clear, it means we didn't save all registers * on syscall entry, so do that now. This only happens on TRACEME * calls, or if someone attached to us while we were on a syscall. From 96ce6629d470c055f10034de7356ff36d120fa3d Mon Sep 17 00:00:00 2001 From: Jim Quinlan Date: Fri, 3 Oct 2025 13:04:36 -0400 Subject: [PATCH 1605/2333] PCI: brcmstb: Fix disabling L0s capability commit 9583f9d22991d2cfb5cc59a2552040c4ae98d998 upstream. caab002d5069 ("PCI: brcmstb: Disable L0s component of ASPM if requested") set PCI_EXP_LNKCAP_ASPM_L1 and (optionally) PCI_EXP_LNKCAP_ASPM_L0S in PCI_EXP_LNKCAP (aka PCIE_RC_CFG_PRIV1_LINK_CAPABILITY in brcmstb). But instead of using PCI_EXP_LNKCAP_ASPM_L1 and PCI_EXP_LNKCAP_ASPM_L0S directly, it used PCIE_LINK_STATE_L1 and PCIE_LINK_STATE_L0S, which are Linux-created values that only coincidentally matched the PCIe spec. b478e162f227 ("PCI/ASPM: Consolidate link state defines") later changed them so they no longer matched the PCIe spec, so the bits ended up in the wrong place in PCI_EXP_LNKCAP. Use PCI_EXP_LNKCAP_ASPM_L0S to clear L0s support when there's an 'aspm-no-l0s' property. Rely on brcmstb hardware to advertise L0s and/or L1 support otherwise. Fixes: caab002d5069 ("PCI: brcmstb: Disable L0s component of ASPM if requested") Reported-by: Bjorn Helgaas Closes: https://lore.kernel.org/linux-pci/20250925194424.GA2197200@bhelgaas Signed-off-by: Jim Quinlan [mani: reworded subject and description, added closes tag and CCed stable] Signed-off-by: Manivannan Sadhasivam [bhelgaas: commit log] Signed-off-by: Bjorn Helgaas Reviewed-by: Florian Fainelli Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20251003170436.1446030-1-james.quinlan@broadcom.com Signed-off-by: Greg Kroah-Hartman --- drivers/pci/controller/pcie-brcmstb.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/pci/controller/pcie-brcmstb.c b/drivers/pci/controller/pcie-brcmstb.c index 9afbd02ded35e..7e9b2f6a604a5 100644 --- a/drivers/pci/controller/pcie-brcmstb.c +++ b/drivers/pci/controller/pcie-brcmstb.c @@ -48,7 +48,6 @@ #define PCIE_RC_CFG_PRIV1_LINK_CAPABILITY 0x04dc #define PCIE_RC_CFG_PRIV1_LINK_CAPABILITY_MAX_LINK_WIDTH_MASK 0x1f0 -#define PCIE_RC_CFG_PRIV1_LINK_CAPABILITY_ASPM_SUPPORT_MASK 0xc00 #define PCIE_RC_CFG_PRIV1_ROOT_CAP 0x4f8 #define PCIE_RC_CFG_PRIV1_ROOT_CAP_L1SS_MODE_MASK 0xf8 @@ -1075,7 +1074,7 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie) void __iomem *base = pcie->base; struct pci_host_bridge *bridge; struct resource_entry *entry; - u32 tmp, burst, aspm_support, num_lanes, num_lanes_cap; + u32 tmp, burst, num_lanes, num_lanes_cap; u8 num_out_wins = 0; int num_inbound_wins = 0; int memc, ret; @@ -1175,12 +1174,9 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie) /* Don't advertise L0s capability if 'aspm-no-l0s' */ - aspm_support = PCIE_LINK_STATE_L1; - if (!of_property_read_bool(pcie->np, "aspm-no-l0s")) - aspm_support |= PCIE_LINK_STATE_L0S; tmp = readl(base + PCIE_RC_CFG_PRIV1_LINK_CAPABILITY); - u32p_replace_bits(&tmp, aspm_support, - PCIE_RC_CFG_PRIV1_LINK_CAPABILITY_ASPM_SUPPORT_MASK); + if (of_property_read_bool(pcie->np, "aspm-no-l0s")) + tmp &= ~PCI_EXP_LNKCAP_ASPM_L0S; writel(tmp, base + PCIE_RC_CFG_PRIV1_LINK_CAPABILITY); /* 'tmp' still holds the contents of PRIV1_LINK_CAPABILITY */ From b635895918d856527593f8bc5c4974a53b3eadfe Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Sat, 1 Nov 2025 09:59:42 +0530 Subject: [PATCH 1606/2333] PCI: meson: Fix parsing the DBI register region commit eff0306b109f2d611e44f0155b0324f6cfec3ef4 upstream. First of all, the driver was parsing the 'dbi' register region as 'elbi'. This was due to DT mistakenly passing 'dbi' as 'elbi'. Since the DT is now fixed to supply 'dbi' region, this driver can rely on the DWC core driver to parse and map it. However, to support the old DTs, if the 'elbi' region is found in DT, parse and map the region as both 'dw_pcie::elbi_base' as 'dw_pcie::dbi_base'. This will allow the driver to work with both broken and fixed DTs. Also, skip parsing the 'elbi' region in DWC core if 'pci->elbi_base' was already populated. Fixes: 9c0ef6d34fdb ("PCI: amlogic: Add the Amlogic Meson PCIe controller driver") Fixes: c96992a24bec ("PCI: dwc: Add support for ELBI resource mapping") Reported-by: Linnaea Lavia Closes: https://lore.kernel.org/linux-pci/DM4PR05MB102707B8CDF84D776C39F22F2C7F0A@DM4PR05MB10270.namprd05.prod.outlook.com/ Signed-off-by: Manivannan Sadhasivam Signed-off-by: Manivannan Sadhasivam Tested-by: Neil Armstrong # on Bananapi-M2S Reviewed-by: Neil Armstrong Cc: stable@vger.kernel.org # 6.2 Link: https://patch.msgid.link/20251101-pci-meson-fix-v1-3-c50dcc56ed6a@oss.qualcomm.com Signed-off-by: Greg Kroah-Hartman --- drivers/pci/controller/dwc/pci-meson.c | 18 +++++++++++++++--- drivers/pci/controller/dwc/pcie-designware.c | 12 +++++++----- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/drivers/pci/controller/dwc/pci-meson.c b/drivers/pci/controller/dwc/pci-meson.c index 787469d1b396d..54b6a4196f176 100644 --- a/drivers/pci/controller/dwc/pci-meson.c +++ b/drivers/pci/controller/dwc/pci-meson.c @@ -108,10 +108,22 @@ static int meson_pcie_get_mems(struct platform_device *pdev, struct meson_pcie *mp) { struct dw_pcie *pci = &mp->pci; + struct resource *res; - pci->dbi_base = devm_platform_ioremap_resource_byname(pdev, "elbi"); - if (IS_ERR(pci->dbi_base)) - return PTR_ERR(pci->dbi_base); + /* + * For the broken DTs that supply 'dbi' as 'elbi', parse the 'elbi' + * region and assign it to both 'pci->elbi_base' and 'pci->dbi_space' so + * that the DWC core can skip parsing both regions. + */ + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "elbi"); + if (res) { + pci->elbi_base = devm_pci_remap_cfg_resource(pci->dev, res); + if (IS_ERR(pci->elbi_base)) + return PTR_ERR(pci->elbi_base); + + pci->dbi_base = pci->elbi_base; + pci->dbi_phys_addr = res->start; + } mp->cfg_base = devm_platform_ioremap_resource_byname(pdev, "cfg"); if (IS_ERR(mp->cfg_base)) diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c index c644216995f69..06eca858eb1b3 100644 --- a/drivers/pci/controller/dwc/pcie-designware.c +++ b/drivers/pci/controller/dwc/pcie-designware.c @@ -168,11 +168,13 @@ int dw_pcie_get_resources(struct dw_pcie *pci) } /* ELBI is an optional resource */ - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "elbi"); - if (res) { - pci->elbi_base = devm_ioremap_resource(pci->dev, res); - if (IS_ERR(pci->elbi_base)) - return PTR_ERR(pci->elbi_base); + if (!pci->elbi_base) { + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "elbi"); + if (res) { + pci->elbi_base = devm_ioremap_resource(pci->dev, res); + if (IS_ERR(pci->elbi_base)) + return PTR_ERR(pci->elbi_base); + } } /* LLDD is supposed to manually switch the clocks and resets state */ From c540db17e4afeaf1f4467b76c62b72ac4e2b001b Mon Sep 17 00:00:00 2001 From: Sandipan Das Date: Tue, 9 Dec 2025 13:56:38 +0530 Subject: [PATCH 1607/2333] perf/x86/amd/uncore: Fix the return value of amd_uncore_df_event_init() on error commit 01439286514ce9d13b8123f8ec3717d7135ff1d6 upstream. If amd_uncore_event_init() fails, return an error irrespective of the pmu_version. Setting hwc->config should be safe even if there is an error so use this opportunity to simplify the code. Closes: https://lore.kernel.org/all/aTaI0ci3vZ44lmBn@stanley.mountain/ Fixes: d6389d3ccc13 ("perf/x86/amd/uncore: Refactor uncore management") Reported-by: Dan Carpenter Signed-off-by: Sandipan Das Signed-off-by: Ingo Molnar Cc: Peter Zijlstra Cc: stable@vger.kernel.org Link: https://patch.msgid.link/076935e23a70335d33bd6e23308b75ae0ad35ba2.1765268667.git.sandipan.das@amd.com Signed-off-by: Greg Kroah-Hartman --- arch/x86/events/amd/uncore.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/arch/x86/events/amd/uncore.c b/arch/x86/events/amd/uncore.c index e8b6af199c738..9293ce50574da 100644 --- a/arch/x86/events/amd/uncore.c +++ b/arch/x86/events/amd/uncore.c @@ -656,14 +656,11 @@ static int amd_uncore_df_event_init(struct perf_event *event) struct hw_perf_event *hwc = &event->hw; int ret = amd_uncore_event_init(event); - if (ret || pmu_version < 2) - return ret; - hwc->config = event->attr.config & (pmu_version >= 2 ? AMD64_PERFMON_V2_RAW_EVENT_MASK_NB : AMD64_RAW_EVENT_MASK_NB); - return 0; + return ret; } static int amd_uncore_df_add(struct perf_event *event, int flags) From 8a241df8cf6d05607ec1b754bd52e7440097a56a Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 23 Oct 2025 12:29:06 +0200 Subject: [PATCH 1608/2333] power: supply: max77705: Fix potential IRQ chip conflict when probing two devices commit 1cb053ea2e1dedd8f2d9653b7c3ca5b93c8c9275 upstream. MAX77705 charger is most likely always a single device on the board, however nothing stops board designers to have two of them, thus same device driver could probe twice. Or user could manually try to probing second time. Device driver is not ready for that case, because it allocates statically 'struct regmap_irq_chip' as non-const and stores during probe in 'irq_drv_data' member a pointer to per-probe state container ('struct max77705_charger_data'). devm_regmap_add_irq_chip() does not make a copy of 'struct regmap_irq_chip' but stores the pointer. Second probe - either successful or failure - would overwrite the 'irq_drv_data' from previous device probe, so interrupts would be executed in a wrong context. Fixes: a6a494c8e3ce ("power: supply: max77705: Add charger driver for Maxim 77705") Cc: stable@vger.kernel.org Signed-off-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20251023102905.71535-2-krzysztof.kozlowski@linaro.org Signed-off-by: Sebastian Reichel Signed-off-by: Greg Kroah-Hartman --- drivers/power/supply/max77705_charger.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/power/supply/max77705_charger.c b/drivers/power/supply/max77705_charger.c index b1a227bf72e26..1044bf58aeaca 100644 --- a/drivers/power/supply/max77705_charger.c +++ b/drivers/power/supply/max77705_charger.c @@ -60,7 +60,7 @@ static const struct regmap_irq max77705_charger_irqs[] = { REGMAP_IRQ_REG_LINE(MAX77705_AICL_I, BITS_PER_BYTE), }; -static struct regmap_irq_chip max77705_charger_irq_chip = { +static const struct regmap_irq_chip max77705_charger_irq_chip = { .name = "max77705-charger", .status_base = MAX77705_CHG_REG_INT, .mask_base = MAX77705_CHG_REG_INT_MASK, @@ -567,6 +567,7 @@ static int max77705_charger_probe(struct i2c_client *i2c) { struct power_supply_config pscfg = {}; struct max77705_charger_data *chg; + struct regmap_irq_chip *chip_desc; struct device *dev; struct regmap_irq_chip_data *irq_data; int ret; @@ -580,6 +581,13 @@ static int max77705_charger_probe(struct i2c_client *i2c) chg->dev = dev; i2c_set_clientdata(i2c, chg); + chip_desc = devm_kmemdup(dev, &max77705_charger_irq_chip, + sizeof(max77705_charger_irq_chip), + GFP_KERNEL); + if (!chip_desc) + return -ENOMEM; + chip_desc->irq_drv_data = chg; + chg->regmap = devm_regmap_init_i2c(i2c, &max77705_chg_regmap_config); if (IS_ERR(chg->regmap)) return PTR_ERR(chg->regmap); @@ -599,11 +607,9 @@ static int max77705_charger_probe(struct i2c_client *i2c) if (IS_ERR(chg->psy_chg)) return PTR_ERR(chg->psy_chg); - max77705_charger_irq_chip.irq_drv_data = chg; ret = devm_regmap_add_irq_chip(chg->dev, chg->regmap, i2c->irq, IRQF_ONESHOT, 0, - &max77705_charger_irq_chip, - &irq_data); + chip_desc, &irq_data); if (ret) return dev_err_probe(dev, ret, "failed to add irq chip\n"); From 40a2a25aff5c1d896d426f3184d726fbaf7bf321 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Tue, 21 Oct 2025 12:06:06 +0200 Subject: [PATCH 1609/2333] powerpc/pseries/cmm: adjust BALLOON_MIGRATE when migrating pages commit 0da2ba35c0d532ca0fe7af698b17d74c4d084b9a upstream. Let's properly adjust BALLOON_MIGRATE like the other drivers. Note that the INFLATE/DEFLATE events are triggered from the core when enqueueing/dequeueing pages. This was found by code inspection. Link: https://lkml.kernel.org/r/20251021100606.148294-3-david@redhat.com Fixes: fe030c9b85e6 ("powerpc/pseries/cmm: Implement balloon compaction") Signed-off-by: David Hildenbrand Reviewed-by: Ritesh Harjani (IBM) Cc: Christophe Leroy Cc: Madhavan Srinivasan Cc: Michael Ellerman Cc: Nicholas Piggin Cc: Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/platforms/pseries/cmm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/powerpc/platforms/pseries/cmm.c b/arch/powerpc/platforms/pseries/cmm.c index 0823fa2da1516..fd958b444adcd 100644 --- a/arch/powerpc/platforms/pseries/cmm.c +++ b/arch/powerpc/platforms/pseries/cmm.c @@ -532,6 +532,7 @@ static int cmm_migratepage(struct balloon_dev_info *b_dev_info, spin_lock_irqsave(&b_dev_info->pages_lock, flags); balloon_page_insert(b_dev_info, newpage); + __count_vm_event(BALLOON_MIGRATE); b_dev_info->isolated_pages--; spin_unlock_irqrestore(&b_dev_info->pages_lock, flags); From 8fb48de871a5feee1b68130eedcd304be44b103e Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Tue, 21 Oct 2025 12:06:05 +0200 Subject: [PATCH 1610/2333] powerpc/pseries/cmm: call balloon_devinfo_init() also without CONFIG_BALLOON_COMPACTION commit fc6bcf9ac4de76f5e7bcd020b3c0a86faff3f2d5 upstream. Patch series "powerpc/pseries/cmm: two smaller fixes". Two smaller fixes identified while doing a bigger rework. This patch (of 2): We always have to initialize the balloon_dev_info, even when compaction is not configured in: otherwise the containing list and the lock are left uninitialized. Likely not many such configs exist in practice, but let's CC stable to be sure. This was found by code inspection. Link: https://lkml.kernel.org/r/20251021100606.148294-1-david@redhat.com Link: https://lkml.kernel.org/r/20251021100606.148294-2-david@redhat.com Fixes: fe030c9b85e6 ("powerpc/pseries/cmm: Implement balloon compaction") Signed-off-by: David Hildenbrand Reviewed-by: Ritesh Harjani (IBM) Cc: Christophe Leroy Cc: Madhavan Srinivasan Cc: Michael Ellerman Cc: Nicholas Piggin Cc: Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/platforms/pseries/cmm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/platforms/pseries/cmm.c b/arch/powerpc/platforms/pseries/cmm.c index fd958b444adcd..310dab4bc8679 100644 --- a/arch/powerpc/platforms/pseries/cmm.c +++ b/arch/powerpc/platforms/pseries/cmm.c @@ -551,7 +551,6 @@ static int cmm_migratepage(struct balloon_dev_info *b_dev_info, static void cmm_balloon_compaction_init(void) { - balloon_devinfo_init(&b_dev_info); b_dev_info.migratepage = cmm_migratepage; } #else /* CONFIG_BALLOON_COMPACTION */ @@ -573,6 +572,7 @@ static int cmm_init(void) if (!firmware_has_feature(FW_FEATURE_CMO) && !simulate) return -EOPNOTSUPP; + balloon_devinfo_init(&b_dev_info); cmm_balloon_compaction_init(); rc = register_oom_notifier(&cmm_oom_nb); From b693d48a6ed0cd09171103ad418e4a693203d6e4 Mon Sep 17 00:00:00 2001 From: Ivan Abramov Date: Wed, 3 Sep 2025 02:23:31 +0300 Subject: [PATCH 1611/2333] media: adv7842: Avoid possible out-of-bounds array accesses in adv7842_cp_log_status() commit 8163419e3e05d71dcfa8fb49c8fdf8d76908fe51 upstream. It's possible for cp_read() and hdmi_read() to return -EIO. Those values are further used as indexes for accessing arrays. Fix that by checking return values where it's needed. Found by Linux Verification Center (linuxtesting.org) with SVACE. Fixes: a89bcd4c6c20 ("[media] adv7842: add new video decoder driver") Cc: stable@vger.kernel.org Signed-off-by: Ivan Abramov Signed-off-by: Hans Verkuil Signed-off-by: Greg Kroah-Hartman --- drivers/media/i2c/adv7842.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/media/i2c/adv7842.c b/drivers/media/i2c/adv7842.c index 9780082db8415..111186529ed40 100644 --- a/drivers/media/i2c/adv7842.c +++ b/drivers/media/i2c/adv7842.c @@ -2699,6 +2699,7 @@ static int adv7842_cp_log_status(struct v4l2_subdev *sd) /* CP block */ struct adv7842_state *state = to_state(sd); struct v4l2_dv_timings timings; + int temp; u8 reg_io_0x02 = io_read(sd, 0x02); u8 reg_io_0x21 = io_read(sd, 0x21); u8 reg_rep_0x77 = rep_read(sd, 0x77); @@ -2821,8 +2822,9 @@ static int adv7842_cp_log_status(struct v4l2_subdev *sd) (((reg_io_0x02 >> 2) & 0x01) ^ (reg_io_0x02 & 0x01)) ? "(16-235)" : "(0-255)", (reg_io_0x02 & 0x08) ? "enabled" : "disabled"); + temp = cp_read(sd, 0xf4) >> 4; v4l2_info(sd, "Color space conversion: %s\n", - csc_coeff_sel_rb[cp_read(sd, 0xf4) >> 4]); + temp < 0 ? "" : csc_coeff_sel_rb[temp]); if (!is_digital_input(sd)) return 0; @@ -2852,8 +2854,9 @@ static int adv7842_cp_log_status(struct v4l2_subdev *sd) hdmi_read(sd, 0x5f)); v4l2_info(sd, "AV Mute: %s\n", (hdmi_read(sd, 0x04) & 0x40) ? "on" : "off"); + temp = hdmi_read(sd, 0x0b) >> 6; v4l2_info(sd, "Deep color mode: %s\n", - deep_color_mode_txt[hdmi_read(sd, 0x0b) >> 6]); + temp < 0 ? "" : deep_color_mode_txt[temp]); adv7842_log_infoframes(sd); From 69a5f0fa6e559356b2f0933649e43d2bea928e56 Mon Sep 17 00:00:00 2001 From: Mahesh Rao Date: Mon, 27 Oct 2025 22:54:40 +0800 Subject: [PATCH 1612/2333] firmware: stratix10-svc: Add mutex in stratix10 memory management commit 85f96cbbbc67b59652b2c1ec394b8ddc0ddf1b0b upstream. Add mutex lock to stratix10_svc_allocate_memory and stratix10_svc_free_memory for thread safety. This prevents race conditions and ensures proper synchronization during memory operations. This is required for parallel communication with the Stratix10 service channel. Fixes: 7ca5ce896524f ("firmware: add Intel Stratix10 service layer driver") Cc: stable@vger.kernel.org Signed-off-by: Mahesh Rao Reviewed-by: Matthew Gerlach Signed-off-by: Dinh Nguyen Signed-off-by: Greg Kroah-Hartman --- drivers/firmware/stratix10-svc.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/firmware/stratix10-svc.c b/drivers/firmware/stratix10-svc.c index deee0e7be34bd..1d24e82f3d09d 100644 --- a/drivers/firmware/stratix10-svc.c +++ b/drivers/firmware/stratix10-svc.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2017-2018, Intel Corporation + * Copyright (C) 2025, Altera Corporation */ #include @@ -175,6 +176,12 @@ struct stratix10_svc_chan { static LIST_HEAD(svc_ctrl); static LIST_HEAD(svc_data_mem); +/** + * svc_mem_lock protects access to the svc_data_mem list for + * concurrent multi-client operations + */ +static DEFINE_MUTEX(svc_mem_lock); + /** * svc_pa_to_va() - translate physical address to virtual address * @addr: to be translated physical address @@ -187,6 +194,7 @@ static void *svc_pa_to_va(unsigned long addr) struct stratix10_svc_data_mem *pmem; pr_debug("claim back P-addr=0x%016x\n", (unsigned int)addr); + guard(mutex)(&svc_mem_lock); list_for_each_entry(pmem, &svc_data_mem, node) if (pmem->paddr == addr) return pmem->vaddr; @@ -993,6 +1001,7 @@ int stratix10_svc_send(struct stratix10_svc_chan *chan, void *msg) p_data->flag = ct->flags; } } else { + guard(mutex)(&svc_mem_lock); list_for_each_entry(p_mem, &svc_data_mem, node) if (p_mem->vaddr == p_msg->payload) { p_data->paddr = p_mem->paddr; @@ -1075,6 +1084,7 @@ void *stratix10_svc_allocate_memory(struct stratix10_svc_chan *chan, if (!pmem) return ERR_PTR(-ENOMEM); + guard(mutex)(&svc_mem_lock); va = gen_pool_alloc(genpool, s); if (!va) return ERR_PTR(-ENOMEM); @@ -1103,6 +1113,7 @@ EXPORT_SYMBOL_GPL(stratix10_svc_allocate_memory); void stratix10_svc_free_memory(struct stratix10_svc_chan *chan, void *kaddr) { struct stratix10_svc_data_mem *pmem; + guard(mutex)(&svc_mem_lock); list_for_each_entry(pmem, &svc_data_mem, node) if (pmem->vaddr == kaddr) { From e36fd1a4c2ec8485b3ad48833c1fed4bb02348e6 Mon Sep 17 00:00:00 2001 From: "Uladzislau Rezki (Sony)" Date: Mon, 17 Nov 2025 11:59:45 +0100 Subject: [PATCH 1613/2333] dm-ebs: Mark full buffer dirty even on partial write commit 7fa3e7d114abc9cc71cc35d768e116641074ddb4 upstream. When performing a read-modify-write(RMW) operation, any modification to a buffered block must cause the entire buffer to be marked dirty. Marking only a subrange as dirty is incorrect because the underlying device block size(ubs) defines the minimum read/write granularity. A lower device can perform I/O only on regions which are fully aligned and sized to ubs. This change ensures that write-back operations always occur in full ubs-sized chunks, matching the intended emulation semantics of the EBS target. As for user space visible impact, submitting sub-ubs and misaligned I/O for devices which are tuned to ubs sizes only, will reject such requests, therefore it can lead to losing data. Example: 1) Create a 8K nvme device in qemu by adding -device nvme,drive=drv0,serial=foo,logical_block_size=8192,physical_block_size=8192 2) Setup dm-ebs to emulate 512B to 8K mapping urezki@pc638:~/bin$ cat dmsetup.sh lower=/dev/nvme0n1 len=$(blockdev --getsz "$lower") echo "0 $len ebs $lower 0 1 16" | dmsetup create nvme-8k urezki@pc638:~/bin$ offset 0, ebs=1 and ubs=16(in sectors). 3) Create an ext4 filesystem(default 4K block size) urezki@pc638:~/bin$ sudo mkfs.ext4 -F /dev/dm-0 mke2fs 1.47.0 (5-Feb-2023) Discarding device blocks: done Creating filesystem with 2072576 4k blocks and 518144 inodes Filesystem UUID: bd0b6ca6-0506-4e31-86da-8d22c9d50b63 Superblock backups stored on blocks: 32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632 Allocating group tables: done Writing inode tables: done Creating journal (16384 blocks): done Writing superblocks and filesystem accounting information: mkfs.ext4: Input/output error while writing out and closing file system urezki@pc638:~/bin$ dmesg [ 1618.875449] buffer_io_error: 1028 callbacks suppressed [ 1618.875456] Buffer I/O error on dev dm-0, logical block 0, lost async page write [ 1618.875527] Buffer I/O error on dev dm-0, logical block 1, lost async page write [ 1618.875602] Buffer I/O error on dev dm-0, logical block 2, lost async page write [ 1618.875620] Buffer I/O error on dev dm-0, logical block 3, lost async page write [ 1618.875639] Buffer I/O error on dev dm-0, logical block 4, lost async page write [ 1618.894316] Buffer I/O error on dev dm-0, logical block 5, lost async page write [ 1618.894358] Buffer I/O error on dev dm-0, logical block 6, lost async page write [ 1618.894380] Buffer I/O error on dev dm-0, logical block 7, lost async page write [ 1618.894405] Buffer I/O error on dev dm-0, logical block 8, lost async page write [ 1618.894427] Buffer I/O error on dev dm-0, logical block 9, lost async page write Many I/O errors because the lower 8K device rejects sub-ubs/misaligned requests. with a patch: urezki@pc638:~/bin$ sudo mkfs.ext4 -F /dev/dm-0 mke2fs 1.47.0 (5-Feb-2023) Discarding device blocks: done Creating filesystem with 2072576 4k blocks and 518144 inodes Filesystem UUID: 9b54f44f-ef55-4bd4-9e40-c8b775a616ac Superblock backups stored on blocks: 32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632 Allocating group tables: done Writing inode tables: done Creating journal (16384 blocks): done Writing superblocks and filesystem accounting information: done urezki@pc638:~/bin$ sudo mount /dev/dm-0 /mnt/ urezki@pc638:~/bin$ ls -al /mnt/ total 24 drwxr-xr-x 3 root root 4096 Oct 17 15:13 . drwxr-xr-x 19 root root 4096 Jul 10 19:42 .. drwx------ 2 root root 16384 Oct 17 15:13 lost+found urezki@pc638:~/bin$ After this change: mkfs completes; mount succeeds. Signed-off-by: Uladzislau Rezki (Sony) Signed-off-by: Mikulas Patocka Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/md/dm-ebs-target.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/md/dm-ebs-target.c b/drivers/md/dm-ebs-target.c index 6abb31ca96623..b354e74a670e0 100644 --- a/drivers/md/dm-ebs-target.c +++ b/drivers/md/dm-ebs-target.c @@ -103,7 +103,7 @@ static int __ebs_rw_bvec(struct ebs_c *ec, enum req_op op, struct bio_vec *bv, } else { flush_dcache_page(bv->bv_page); memcpy(ba, pa, cur_len); - dm_bufio_mark_partial_buffer_dirty(b, buf_off, buf_off + cur_len); + dm_bufio_mark_buffer_dirty(b); } dm_bufio_release(b); From c7d8c1018aa6b898b03ec15ae4a66b602a868af3 Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Mon, 20 Oct 2025 14:48:13 +0200 Subject: [PATCH 1614/2333] dm-bufio: align write boundary on physical block size commit d0ac06ae53be0cdb61f5fe6b62d25d3317c51657 upstream. There may be devices with physical block size larger than 4k. If dm-bufio sends I/O that is not aligned on physical block size, performance is degraded. The 4k minimum alignment limit is there because some SSDs report logical and physical block size 512 despite having 4k internally - so dm-bufio shouldn't send I/Os not aligned on 4k boundary, because they perform badly (the SSD does read-modify-write for them). Signed-off-by: Mikulas Patocka Reported-by: Uladzislau Rezki (Sony) Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/md/dm-bufio.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/md/dm-bufio.c b/drivers/md/dm-bufio.c index e6d28be11c5c6..5235f3e4924b7 100644 --- a/drivers/md/dm-bufio.c +++ b/drivers/md/dm-bufio.c @@ -1374,7 +1374,7 @@ static void submit_io(struct dm_buffer *b, enum req_op op, unsigned short ioprio { unsigned int n_sectors; sector_t sector; - unsigned int offset, end; + unsigned int offset, end, align; b->end_io = end_io; @@ -1388,9 +1388,11 @@ static void submit_io(struct dm_buffer *b, enum req_op op, unsigned short ioprio b->c->write_callback(b); offset = b->write_start; end = b->write_end; - offset &= -DM_BUFIO_WRITE_ALIGN; - end += DM_BUFIO_WRITE_ALIGN - 1; - end &= -DM_BUFIO_WRITE_ALIGN; + align = max(DM_BUFIO_WRITE_ALIGN, + bdev_physical_block_size(b->c->bdev)); + offset &= -align; + end += align - 1; + end &= -align; if (unlikely(end > b->c->block_size)) end = b->c->block_size; From 87f7a7e2ed5715a120d4c601c2b67ae84525d2a2 Mon Sep 17 00:00:00 2001 From: Li Chen Date: Fri, 5 Dec 2025 05:46:19 +0000 Subject: [PATCH 1615/2333] dm pcache: fix cache info indexing commit ee7633178321f5d983db3adfdea9322456cfdaaa upstream. The on-media cache_info index used sizeof(struct) instead of the 4K metadata stride, so gc_percent updates from dmsetup message were written between slots and lost after reboot. Use PCACHE_CACHE_INFO_SIZE in get_cache_info_addr() and align info_index with the slot returned by pcache_meta_find_latest(). Signed-off-by: Li Chen Signed-off-by: Dongsheng Yang Signed-off-by: Mikulas Patocka Reviewed-by: Zheng Gu Cc: stable@vger.kernel.org # 6.18 Signed-off-by: Greg Kroah-Hartman --- drivers/md/dm-pcache/cache.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/md/dm-pcache/cache.c b/drivers/md/dm-pcache/cache.c index d4385d76ac36d..534bf07b794f1 100644 --- a/drivers/md/dm-pcache/cache.c +++ b/drivers/md/dm-pcache/cache.c @@ -10,7 +10,8 @@ struct kmem_cache *key_cache; static inline struct pcache_cache_info *get_cache_info_addr(struct pcache_cache *cache) { - return cache->cache_info_addr + cache->info_index; + return (struct pcache_cache_info *)((char *)cache->cache_info_addr + + (size_t)cache->info_index * PCACHE_CACHE_INFO_SIZE); } static void cache_info_write(struct pcache_cache *cache) @@ -49,6 +50,8 @@ static int cache_info_init(struct pcache_cache *cache, struct pcache_cache_optio return -EINVAL; } + cache->info_index = ((char *)cache_info_addr - (char *)cache->cache_info_addr) / PCACHE_CACHE_INFO_SIZE; + return 0; } From 527f5ea4ced1b3bc99f2cba619c4886ef6abe80d Mon Sep 17 00:00:00 2001 From: Li Chen Date: Fri, 5 Dec 2025 05:46:20 +0000 Subject: [PATCH 1616/2333] dm pcache: fix segment info indexing commit 13ea55ea20176736516b20b9ea2d8cf97dbe74f5 upstream. Segment info indexing also used sizeof(struct) instead of the 4K metadata stride, so info_index could point between slots and subsequent writes would advance incorrectly. Derive info_index from the pointer returned by the segment meta search using PCACHE_SEG_INFO_SIZE and advance to the next slot for future updates. Signed-off-by: Li Chen Signed-off-by: Dongsheng Yang Signed-off-by: Mikulas Patocka Reviewed-by: Zheng Gu Cc: stable@vger.kernel.org # 6.18 Signed-off-by: Greg Kroah-Hartman --- drivers/md/dm-pcache/cache_segment.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/md/dm-pcache/cache_segment.c b/drivers/md/dm-pcache/cache_segment.c index ae57cc261422d..9d92e2b067ed0 100644 --- a/drivers/md/dm-pcache/cache_segment.c +++ b/drivers/md/dm-pcache/cache_segment.c @@ -56,7 +56,10 @@ static int cache_seg_info_load(struct pcache_cache_segment *cache_seg) ret = -EIO; goto out; } - cache_seg->info_index = cache_seg_info_addr - cache_seg_info_addr_base; + + cache_seg->info_index = + ((char *)cache_seg_info_addr - (char *)cache_seg_info_addr_base) / + PCACHE_SEG_INFO_SIZE; out: mutex_unlock(&cache_seg->info_lock); From f21b17cb5ed5966c5a1c94afd329b9fb570affe1 Mon Sep 17 00:00:00 2001 From: Rene Rebe Date: Fri, 14 Nov 2025 16:00:42 +0100 Subject: [PATCH 1617/2333] fbdev: gbefb: fix to use physical address instead of dma address MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit e3f44742bbb10537fe53d83d20dea2a7c167674d upstream. While debuggigng why X would not start on mips64 Sgi/O2 I found the phys adress being off. Turns out the gbefb passed the internal dma_addr as phys. May be broken pre git history. Fix by converting dma_to_phys. Signed-off-by: René Rebe Cc: # v4.0+ Signed-off-by: Helge Deller Signed-off-by: Greg Kroah-Hartman --- drivers/video/fbdev/gbefb.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/video/fbdev/gbefb.c b/drivers/video/fbdev/gbefb.c index 4c36a3e409bea..cb6ff15a21dbf 100644 --- a/drivers/video/fbdev/gbefb.c +++ b/drivers/video/fbdev/gbefb.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -65,7 +66,7 @@ struct gbefb_par { static unsigned int gbe_mem_size = CONFIG_FB_GBE_MEM * 1024*1024; static void *gbe_mem; static dma_addr_t gbe_dma_addr; -static unsigned long gbe_mem_phys; +static phys_addr_t gbe_mem_phys; static struct { uint16_t *cpu; @@ -1183,7 +1184,7 @@ static int gbefb_probe(struct platform_device *p_dev) goto out_release_mem_region; } - gbe_mem_phys = (unsigned long) gbe_dma_addr; + gbe_mem_phys = dma_to_phys(&p_dev->dev, gbe_dma_addr); } par = info->par; From 1470cccf067e7c1be523b9920a36ed1a3883cdd2 Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Tue, 2 Dec 2025 19:15:32 +0100 Subject: [PATCH 1618/2333] fbdev: pxafb: Fix multiple clamped values in pxafb_adjust_timing commit 0155e868cbc111846cc2809c1546ea53810a56ae upstream. The variables were never clamped because the return value of clamp_val() was not used. Fix this by assigning the clamped values, and use clamp() instead of clamp_val(). Cc: stable@vger.kernel.org Fixes: 3f16ff608a75 ("[ARM] pxafb: cleanup of the timing checking code") Signed-off-by: Thorsten Blum Signed-off-by: Helge Deller Signed-off-by: Greg Kroah-Hartman --- drivers/video/fbdev/pxafb.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/video/fbdev/pxafb.c b/drivers/video/fbdev/pxafb.c index b96a8a96bce8d..e418eee825fb2 100644 --- a/drivers/video/fbdev/pxafb.c +++ b/drivers/video/fbdev/pxafb.c @@ -419,12 +419,12 @@ static int pxafb_adjust_timing(struct pxafb_info *fbi, var->yres = max_t(int, var->yres, MIN_YRES); if (!(fbi->lccr0 & LCCR0_LCDT)) { - clamp_val(var->hsync_len, 1, 64); - clamp_val(var->vsync_len, 1, 64); - clamp_val(var->left_margin, 1, 255); - clamp_val(var->right_margin, 1, 255); - clamp_val(var->upper_margin, 1, 255); - clamp_val(var->lower_margin, 1, 255); + var->hsync_len = clamp(var->hsync_len, 1, 64); + var->vsync_len = clamp(var->vsync_len, 1, 64); + var->left_margin = clamp(var->left_margin, 1, 255); + var->right_margin = clamp(var->right_margin, 1, 255); + var->upper_margin = clamp(var->upper_margin, 1, 255); + var->lower_margin = clamp(var->lower_margin, 1, 255); } /* make sure each line is aligned on word boundary */ From 4357fa7bc03c312a666742c4958ad8d183b2fd37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Rebe?= Date: Thu, 20 Nov 2025 14:24:00 +0100 Subject: [PATCH 1619/2333] fbdev: tcx.c fix mem_map to correct smem_start offset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 35fa2b4bf96415b88d7edaa5cf8af5185d9ce76e upstream. 403ae52ac047 ("sparc: fix drivers/video/tcx.c warning") changed the physbase initializing breaking the user-space mmap, e.g. for Xorg entirely. Fix fbdev mmap table so the sbus mmap helper work correctly, and not try to map vastly (physbase) offset memory. Fixes: 403ae52ac047 ("sparc: fix drivers/video/tcx.c warning") Cc: Signed-off-by: René Rebe Signed-off-by: Helge Deller Signed-off-by: Greg Kroah-Hartman --- drivers/video/fbdev/tcx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/video/fbdev/tcx.c b/drivers/video/fbdev/tcx.c index f9a0085ad72bf..ca9e84e8d8605 100644 --- a/drivers/video/fbdev/tcx.c +++ b/drivers/video/fbdev/tcx.c @@ -428,7 +428,7 @@ static int tcx_probe(struct platform_device *op) j = i; break; } - par->mmap_map[i].poff = op->resource[j].start; + par->mmap_map[i].poff = op->resource[j].start - info->fix.smem_start; } info->fbops = &tcx_ops; From d786859abab36070bb24d8ed655f377680a9b198 Mon Sep 17 00:00:00 2001 From: Haotian Zhang Date: Mon, 29 Sep 2025 19:12:29 +0800 Subject: [PATCH 1620/2333] media: cec: Fix debugfs leak on bus_register() failure commit c43bcd2b2aa3c2ca9d2433c3990ecbc2c47d10eb upstream. In cec_devnode_init(), the debugfs directory created with debugfs_create_dir() is not removed if bus_register() fails. This leaves a stale "cec" entry in debugfs and prevents proper module reloading. Fix this by removing the debugfs directory in the error path. Fixes: a56960e8b406 ("[media] cec: add HDMI CEC framework (core)") Cc: stable@vger.kernel.org Signed-off-by: Haotian Zhang Signed-off-by: Hans Verkuil Signed-off-by: Greg Kroah-Hartman --- drivers/media/cec/core/cec-core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/cec/core/cec-core.c b/drivers/media/cec/core/cec-core.c index d7259599029f8..dd6e24a0899bd 100644 --- a/drivers/media/cec/core/cec-core.c +++ b/drivers/media/cec/core/cec-core.c @@ -421,6 +421,7 @@ static int __init cec_devnode_init(void) ret = bus_register(&cec_bus_type); if (ret < 0) { + debugfs_remove_recursive(top_cec_dir); unregister_chrdev_region(cec_dev_t, CEC_NUM_DEVICES); pr_warn("cec: bus_register failed\n"); return -EIO; From 7cd1d942b87e2a4a652281f04d5c8cd20854a555 Mon Sep 17 00:00:00 2001 From: Dikshita Agarwal Date: Wed, 5 Nov 2025 11:17:37 +0530 Subject: [PATCH 1621/2333] media: iris: Refine internal buffer reconfiguration logic for resolution change commit aec75e355c633e4b0967c99580bd8ef93e0cdc98 upstream. Improve the condition used to determine when input internal buffers need to be reconfigured during streamon on the capture port. Previously, the check relied on the INPUT_PAUSE sub-state, which was also being set during seek operations. This led to input buffers being queued multiple times to the firmware, causing session errors due to duplicate buffer submissions. This change introduces a more accurate check using the FIRST_IPSC and DRC sub-states to ensure that input buffer reconfiguration is triggered only during resolution change scenarios, such as streamoff/on on the capture port. This avoids duplicate buffer queuing during seek operations. Fixes: c1f8b2cc72ec ("media: iris: handle streamoff/on from client in dynamic resolution change") Cc: stable@vger.kernel.org Reported-by: Val Packett Closes: https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/4700 Signed-off-by: Dikshita Agarwal Reviewed-by: Vikash Garodia Signed-off-by: Bryan O'Donoghue Signed-off-by: Hans Verkuil Signed-off-by: Greg Kroah-Hartman --- drivers/media/platform/qcom/iris/iris_common.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/qcom/iris/iris_common.c b/drivers/media/platform/qcom/iris/iris_common.c index 9fc663bdaf3fc..7f1c7fe144f70 100644 --- a/drivers/media/platform/qcom/iris/iris_common.c +++ b/drivers/media/platform/qcom/iris/iris_common.c @@ -91,12 +91,14 @@ int iris_process_streamon_input(struct iris_inst *inst) int iris_process_streamon_output(struct iris_inst *inst) { const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; - bool drain_active = false, drc_active = false; enum iris_inst_sub_state clear_sub_state = 0; + bool drain_active, drc_active, first_ipsc; int ret = 0; iris_scale_power(inst); + first_ipsc = inst->sub_state & IRIS_INST_SUB_FIRST_IPSC; + drain_active = inst->sub_state & IRIS_INST_SUB_DRAIN && inst->sub_state & IRIS_INST_SUB_DRAIN_LAST; @@ -108,7 +110,8 @@ int iris_process_streamon_output(struct iris_inst *inst) else if (drain_active) clear_sub_state = IRIS_INST_SUB_DRAIN | IRIS_INST_SUB_DRAIN_LAST; - if (inst->domain == DECODER && inst->sub_state & IRIS_INST_SUB_INPUT_PAUSE) { + /* Input internal buffer reconfiguration required in case of resolution change */ + if (first_ipsc || drc_active) { ret = iris_alloc_and_queue_input_int_bufs(inst); if (ret) return ret; From a003505a5c8c758ccd1beb48e8238ace7e14707b Mon Sep 17 00:00:00 2001 From: Ivan Abramov Date: Wed, 3 Sep 2025 02:28:14 +0300 Subject: [PATCH 1622/2333] media: msp3400: Avoid possible out-of-bounds array accesses in msp3400c_thread() commit d2bceb2e20e783d57e739c71e4e50b4b9f4a3953 upstream. It's possible for max1 to remain -1 if msp_read() always fail. This variable is further used as index for accessing arrays. Fix that by checking max1 prior to array accesses. It seems that restart is the preferable action in case of out-of-bounds value. Found by Linux Verification Center (linuxtesting.org) with SVACE. Fixes: 8a4b275f9c19 ("V4L/DVB (3427): audmode and rxsubchans fixes (VIDIOC_G/S_TUNER)") Cc: stable@vger.kernel.org Signed-off-by: Ivan Abramov Signed-off-by: Hans Verkuil Signed-off-by: Greg Kroah-Hartman --- drivers/media/i2c/msp3400-kthreads.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/media/i2c/msp3400-kthreads.c b/drivers/media/i2c/msp3400-kthreads.c index ecabc0e1d32e6..1d9f41dd7c212 100644 --- a/drivers/media/i2c/msp3400-kthreads.c +++ b/drivers/media/i2c/msp3400-kthreads.c @@ -596,6 +596,8 @@ int msp3400c_thread(void *data) "carrier2 val: %5d / %s\n", val, cd[i].name); } + if (max1 < 0 || max1 > 3) + goto restart; /* program the msp3400 according to the results */ state->main = msp3400c_carrier_detect_main[max1].cdo; switch (max1) { From 31ba1a4d7a5d9466f6ef4910a372b8200f8aad19 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 24 Sep 2025 16:39:19 +0200 Subject: [PATCH 1623/2333] media: platform: mtk-mdp3: fix device leaks at probe commit 8f6f3aa21517ef34d50808af0c572e69580dca20 upstream. Make sure to drop the references taken when looking up the subsys devices during probe on probe failure (e.g. probe deferral) and on driver unbind. Similarly, drop the SCP device reference after retrieving its platform data during probe to avoid leaking it. Note that holding a reference to a device does not prevent its driver data from going away. Fixes: 61890ccaefaf ("media: platform: mtk-mdp3: add MediaTek MDP3 driver") Cc: stable@vger.kernel.org # 6.1 Cc: Moudy Ho Signed-off-by: Johan Hovold Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Nicolas Dufresne Signed-off-by: Hans Verkuil Signed-off-by: Greg Kroah-Hartman --- .../media/platform/mediatek/mdp3/mtk-mdp3-core.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c index 6559d72d5d427..6d26d4aa1eef2 100644 --- a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c +++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c @@ -157,10 +157,18 @@ void mdp_video_device_release(struct video_device *vdev) kfree(mdp); } +static void mdp_put_device(void *_dev) +{ + struct device *dev = _dev; + + put_device(dev); +} + static int mdp_mm_subsys_deploy(struct mdp_dev *mdp, enum mdp_infra_id id) { struct platform_device *mm_pdev = NULL; struct device **dev; + int ret; int i; if (!mdp) @@ -194,6 +202,11 @@ static int mdp_mm_subsys_deploy(struct mdp_dev *mdp, enum mdp_infra_id id) if (WARN_ON(!mm_pdev)) return -ENODEV; + ret = devm_add_action_or_reset(&mdp->pdev->dev, mdp_put_device, + &mm_pdev->dev); + if (ret) + return ret; + *dev = &mm_pdev->dev; } @@ -279,6 +292,7 @@ static int mdp_probe(struct platform_device *pdev) goto err_destroy_clock_wq; } mdp->scp = platform_get_drvdata(mm_pdev); + put_device(&mm_pdev->dev); } mdp->rproc_handle = scp_get_rproc(mdp->scp); From ca31135ad666c0650bf2805fcbe71903fad5f671 Mon Sep 17 00:00:00 2001 From: Miaoqian Lin Date: Wed, 3 Sep 2025 21:37:29 +0800 Subject: [PATCH 1624/2333] media: renesas: rcar_drif: fix device node reference leak in rcar_drif_bond_enabled commit 445e1658894fd74eab7e53071fa16233887574ed upstream. The function calls of_parse_phandle() which returns a device node with an incremented reference count. When the bonded device is not available, the function returns NULL without releasing the reference, causing a reference leak. Add of_node_put(np) to release the device node reference. The of_node_put function handles NULL pointers. Found through static analysis by reviewing the doc of of_parse_phandle() and cross-checking its usage patterns across the codebase. Fixes: 7625ee981af1 ("[media] media: platform: rcar_drif: Add DRIF support") Cc: stable@vger.kernel.org Signed-off-by: Miaoqian Lin Reviewed-by: Geert Uytterhoeven Reviewed-by: Fabrizio Castro Signed-off-by: Hans Verkuil Signed-off-by: Greg Kroah-Hartman --- drivers/media/platform/renesas/rcar_drif.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/platform/renesas/rcar_drif.c b/drivers/media/platform/renesas/rcar_drif.c index 11bf47fb8266d..0844934f7aa68 100644 --- a/drivers/media/platform/renesas/rcar_drif.c +++ b/drivers/media/platform/renesas/rcar_drif.c @@ -1246,6 +1246,7 @@ static struct device_node *rcar_drif_bond_enabled(struct platform_device *p) if (np && of_device_is_available(np)) return np; + of_node_put(np); return NULL; } From f65ef4b8415e2c8f6b8efdae2a7916efe1f63f1d Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Tue, 14 Oct 2025 12:46:43 +0200 Subject: [PATCH 1625/2333] media: samsung: exynos4-is: fix potential ABBA deadlock on init commit 17dc8ccd6dd5ffe30aa9b0d36e2af1389344ce2b upstream. v4l2_device_register_subdev_nodes() must called without taking media_dev->graph_mutex to avoid potential AB-BA deadlock on further subdevice driver initialization. Fixes: fa91f1056f17 ("[media] exynos4-is: Add support for asynchronous subdevices registration") Cc: stable@vger.kernel.org Signed-off-by: Marek Szyprowski Acked-by: Sylwester Nawrocki Signed-off-by: Hans Verkuil Signed-off-by: Greg Kroah-Hartman --- drivers/media/platform/samsung/exynos4-is/media-dev.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/media/platform/samsung/exynos4-is/media-dev.c b/drivers/media/platform/samsung/exynos4-is/media-dev.c index c781853586fd2..e9d7875cf01ec 100644 --- a/drivers/media/platform/samsung/exynos4-is/media-dev.c +++ b/drivers/media/platform/samsung/exynos4-is/media-dev.c @@ -1399,12 +1399,14 @@ static int subdev_notifier_complete(struct v4l2_async_notifier *notifier) mutex_lock(&fmd->media_dev.graph_mutex); ret = fimc_md_create_links(fmd); - if (ret < 0) - goto unlock; + if (ret < 0) { + mutex_unlock(&fmd->media_dev.graph_mutex); + return ret; + } - ret = v4l2_device_register_subdev_nodes(&fmd->v4l2_dev); -unlock: mutex_unlock(&fmd->media_dev.graph_mutex); + + ret = v4l2_device_register_subdev_nodes(&fmd->v4l2_dev); if (ret < 0) return ret; From 49446f8e73e27c154f4423c768f6e230f00ab77e Mon Sep 17 00:00:00 2001 From: Duoming Zhou Date: Mon, 1 Sep 2025 21:26:17 +0800 Subject: [PATCH 1626/2333] media: TDA1997x: Remove redundant cancel_delayed_work in probe commit 29de195ca39fc2ac0af6fd45522994df9f431f80 upstream. The delayed_work delayed_work_enable_hpd is initialized with INIT_DELAYED_WORK(), but it is never scheduled in tda1997x_probe(). Calling cancel_delayed_work() on a work that has never been scheduled is redundant and unnecessary, as there is no pending work to cancel. Remove the redundant cancel_delayed_work() from error handling path in tda1997x_probe() to avoid potential confusion. Fixes: 9ac0038db9a7 ("media: i2c: Add TDA1997x HDMI receiver driver") Cc: stable@vger.kernel.org Signed-off-by: Duoming Zhou Signed-off-by: Hans Verkuil Signed-off-by: Greg Kroah-Hartman --- drivers/media/i2c/tda1997x.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/media/i2c/tda1997x.c b/drivers/media/i2c/tda1997x.c index 1087d2bddaf29..3532766cd795d 100644 --- a/drivers/media/i2c/tda1997x.c +++ b/drivers/media/i2c/tda1997x.c @@ -2797,7 +2797,6 @@ static int tda1997x_probe(struct i2c_client *client) err_free_handler: v4l2_ctrl_handler_free(&state->hdl); err_free_mutex: - cancel_delayed_work(&state->delayed_work_enable_hpd); mutex_destroy(&state->page_lock); mutex_destroy(&state->lock); tda1997x_set_power(state, 0); From 3cbf9ef5ce849f5c99a936e8482176b70d223011 Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Mon, 22 Sep 2025 14:43:39 -0400 Subject: [PATCH 1627/2333] media: verisilicon: Protect G2 HEVC decoder against invalid DPB index commit 47825b1646a6a9eca0f90baa3d4f98947c2add96 upstream. Fix the Hantro G2 HEVC decoder so that we use DPB index 0 whenever a ninvalid index is received from user space. This protects the hardware from doing faulty memory access which then leads to bus errors. To be noted that when a reference is missing, userspace such as GStreamer passes an invalid DPB index of 255. This issue was found by seeking to a CRA picture using GStreamer. The framework is currently missing the code to skip over RASL pictures placed after the CRA. This situation can also occur while doing live streaming over lossy transport. Fixes: cb5dd5a0fa518 ("media: hantro: Introduce G2/HEVC decoder") Cc: stable@vger.kernel.org Reviewed-by: Benjamin Gaignard Signed-off-by: Nicolas Dufresne Signed-off-by: Hans Verkuil Signed-off-by: Greg Kroah-Hartman --- .../platform/verisilicon/hantro_g2_hevc_dec.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/verisilicon/hantro_g2_hevc_dec.c b/drivers/media/platform/verisilicon/hantro_g2_hevc_dec.c index f066636e56f98..e8c2e83379def 100644 --- a/drivers/media/platform/verisilicon/hantro_g2_hevc_dec.c +++ b/drivers/media/platform/verisilicon/hantro_g2_hevc_dec.c @@ -283,6 +283,15 @@ static void set_params(struct hantro_ctx *ctx) hantro_reg_write(vpu, &g2_apf_threshold, 8); } +static u32 get_dpb_index(const struct v4l2_ctrl_hevc_decode_params *decode_params, + const u32 index) +{ + if (index > decode_params->num_active_dpb_entries) + return 0; + + return index; +} + static void set_ref_pic_list(struct hantro_ctx *ctx) { const struct hantro_hevc_dec_ctrls *ctrls = &ctx->hevc_dec.ctrls; @@ -355,8 +364,10 @@ static void set_ref_pic_list(struct hantro_ctx *ctx) list1[j++] = list1[i++]; for (i = 0; i < V4L2_HEVC_DPB_ENTRIES_NUM_MAX; i++) { - hantro_reg_write(vpu, &ref_pic_regs0[i], list0[i]); - hantro_reg_write(vpu, &ref_pic_regs1[i], list1[i]); + hantro_reg_write(vpu, &ref_pic_regs0[i], + get_dpb_index(decode_params, list0[i])); + hantro_reg_write(vpu, &ref_pic_regs1[i], + get_dpb_index(decode_params, list1[i])); } } From 19f7dfa0c1d2f0b0208ecb5d76c74b7eec1035d1 Mon Sep 17 00:00:00 2001 From: Haotian Zhang Date: Tue, 28 Oct 2025 14:44:43 +0800 Subject: [PATCH 1628/2333] media: videobuf2: Fix device reference leak in vb2_dc_alloc error path commit 94de23a9aa487d7c1372efb161721d7949a177ae upstream. In vb2_dc_alloc(), get_device() is called to increment the device reference count. However, if subsequent DMA allocation fails (vb2_dc_alloc_coherent or vb2_dc_alloc_non_coherent returns error), the function returns without calling put_device(), causing a device reference leak. Add put_device() call in the error path before kfree() to properly release the device reference acquired earlier. Fixes: de27891f675e ("media: videobuf2: handle non-contiguous DMA allocations") Cc: stable@vger.kernel.org Signed-off-by: Haotian Zhang Reviewed-by: Marek Szyprowski Signed-off-by: Hans Verkuil Signed-off-by: Greg Kroah-Hartman --- drivers/media/common/videobuf2/videobuf2-dma-contig.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/common/videobuf2/videobuf2-dma-contig.c b/drivers/media/common/videobuf2/videobuf2-dma-contig.c index a13ec569c82f6..7123c5fae92ce 100644 --- a/drivers/media/common/videobuf2/videobuf2-dma-contig.c +++ b/drivers/media/common/videobuf2/videobuf2-dma-contig.c @@ -258,6 +258,7 @@ static void *vb2_dc_alloc(struct vb2_buffer *vb, if (ret) { dev_err(dev, "dma alloc of size %lu failed\n", size); + put_device(buf->dev); kfree(buf); return ERR_PTR(-ENOMEM); } From 5d25f923bdb4e37680b01037ec197593a3a5b78a Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Fri, 17 Oct 2025 07:33:20 +0200 Subject: [PATCH 1629/2333] media: vpif_capture: fix section mismatch commit 0ef841113724166c3c484d0e9ae6db1eb5634fde upstream. Platform drivers can be probed after their init sections have been discarded (e.g. on probe deferral or manual rebind through sysfs) so the probe function must not live in init. Note that commit ffa1b391c61b ("V4L/DVB: vpif_cap/disp: Removed section mismatch warning") incorrectly suppressed the modpost warning. Fixes: ffa1b391c61b ("V4L/DVB: vpif_cap/disp: Removed section mismatch warning") Fixes: 6ffefff5a9e7 ("V4L/DVB (12906c): V4L : vpif capture driver for DM6467") Cc: stable@vger.kernel.org # 2.6.32 Signed-off-by: Johan Hovold Signed-off-by: Hans Verkuil Signed-off-by: Greg Kroah-Hartman --- drivers/media/platform/ti/davinci/vpif_capture.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/ti/davinci/vpif_capture.c b/drivers/media/platform/ti/davinci/vpif_capture.c index d053972888d1b..243c6196b0247 100644 --- a/drivers/media/platform/ti/davinci/vpif_capture.c +++ b/drivers/media/platform/ti/davinci/vpif_capture.c @@ -1600,7 +1600,7 @@ vpif_capture_get_pdata(struct platform_device *pdev, * This creates device entries by register itself to the V4L2 driver and * initializes fields of each channel objects */ -static __init int vpif_probe(struct platform_device *pdev) +static int vpif_probe(struct platform_device *pdev) { struct vpif_subdev_info *subdevdata; struct i2c_adapter *i2c_adap; @@ -1807,7 +1807,7 @@ static int vpif_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(vpif_pm_ops, vpif_suspend, vpif_resume); -static __refdata struct platform_driver vpif_driver = { +static struct platform_driver vpif_driver = { .driver = { .name = VPIF_DRIVER_NAME, .pm = &vpif_pm_ops, From 6132c3e5592683e58ad9ebd97a117855084dd457 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Fri, 17 Oct 2025 07:33:21 +0200 Subject: [PATCH 1630/2333] media: vpif_display: fix section mismatch commit 59ca64bf98e4209df8ace8057d31ae3c80f948cd upstream. Platform drivers can be probed after their init sections have been discarded (e.g. on probe deferral or manual rebind through sysfs) so the probe function must not live in init. Note that commit ffa1b391c61b ("V4L/DVB: vpif_cap/disp: Removed section mismatch warning") incorrectly suppressed the modpost warning. Fixes: ffa1b391c61b ("V4L/DVB: vpif_cap/disp: Removed section mismatch warning") Fixes: e7332e3a552f ("V4L/DVB (12176): davinci/vpif_display: Add VPIF display driver") Cc: stable@vger.kernel.org # 2.6.32 Signed-off-by: Johan Hovold Signed-off-by: Hans Verkuil Signed-off-by: Greg Kroah-Hartman --- drivers/media/platform/ti/davinci/vpif_display.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/ti/davinci/vpif_display.c b/drivers/media/platform/ti/davinci/vpif_display.c index 70c89549f4b61..1e7815e9f8e07 100644 --- a/drivers/media/platform/ti/davinci/vpif_display.c +++ b/drivers/media/platform/ti/davinci/vpif_display.c @@ -1214,7 +1214,7 @@ static int vpif_probe_complete(void) * vpif_probe: This function creates device entries by register itself to the * V4L2 driver and initializes fields of each channel objects */ -static __init int vpif_probe(struct platform_device *pdev) +static int vpif_probe(struct platform_device *pdev) { struct vpif_subdev_info *subdevdata; struct i2c_adapter *i2c_adap; @@ -1390,7 +1390,7 @@ static int vpif_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(vpif_pm_ops, vpif_suspend, vpif_resume); -static __refdata struct platform_driver vpif_driver = { +static struct platform_driver vpif_driver = { .driver = { .name = VPIF_DRIVER_NAME, .pm = &vpif_pm_ops, From b9b29dae5962c4f1561f6ca8d20b6a9907a1be79 Mon Sep 17 00:00:00 2001 From: Ming Qian Date: Tue, 16 Sep 2025 14:08:53 +0800 Subject: [PATCH 1631/2333] media: amphion: Remove vpu_vb_is_codecconfig commit 634c2cd17bd021487c57b95973bddb14be8002ff upstream. Currently the function vpu_vb_is_codecconfig() always returns 0. Delete it and its related code. Fixes: 3cd084519c6f ("media: amphion: add vpu v4l2 m2m support") Cc: stable@vger.kernel.org Signed-off-by: Ming Qian Signed-off-by: Nicolas Dufresne Signed-off-by: Hans Verkuil Signed-off-by: Greg Kroah-Hartman --- drivers/media/platform/amphion/vpu_malone.c | 23 +++------------------ drivers/media/platform/amphion/vpu_v4l2.c | 10 --------- drivers/media/platform/amphion/vpu_v4l2.h | 10 --------- 3 files changed, 3 insertions(+), 40 deletions(-) diff --git a/drivers/media/platform/amphion/vpu_malone.c b/drivers/media/platform/amphion/vpu_malone.c index ba688566dffd0..80802975c4f16 100644 --- a/drivers/media/platform/amphion/vpu_malone.c +++ b/drivers/media/platform/amphion/vpu_malone.c @@ -1337,22 +1337,18 @@ static int vpu_malone_insert_scode_vc1_g_seq(struct malone_scode_t *scode) { if (!scode->inst->total_input_count) return 0; - if (vpu_vb_is_codecconfig(to_vb2_v4l2_buffer(scode->vb))) - scode->need_data = 0; return 0; } static int vpu_malone_insert_scode_vc1_g_pic(struct malone_scode_t *scode) { - struct vb2_v4l2_buffer *vbuf; u8 nal_hdr[MALONE_VC1_NAL_HEADER_LEN]; u32 *data = NULL; int ret; - vbuf = to_vb2_v4l2_buffer(scode->vb); data = vb2_plane_vaddr(scode->vb, 0); - if (scode->inst->total_input_count == 0 || vpu_vb_is_codecconfig(vbuf)) + if (scode->inst->total_input_count == 0) return 0; if (MALONE_VC1_CONTAIN_NAL(*data)) return 0; @@ -1373,8 +1369,6 @@ static int vpu_malone_insert_scode_vc1_l_seq(struct malone_scode_t *scode) int size = 0; u8 rcv_seqhdr[MALONE_VC1_RCV_SEQ_HEADER_LEN]; - if (vpu_vb_is_codecconfig(to_vb2_v4l2_buffer(scode->vb))) - scode->need_data = 0; if (scode->inst->total_input_count) return 0; scode->need_data = 0; @@ -1560,7 +1554,7 @@ static int vpu_malone_input_frame_data(struct vpu_malone_str_buffer __iomem *str scode.vb = vb; scode.wptr = wptr; scode.need_data = 1; - if (vbuf->sequence == 0 || vpu_vb_is_codecconfig(vbuf)) + if (vbuf->sequence == 0) ret = vpu_malone_insert_scode(&scode, SCODE_SEQUENCE); if (ret < 0) @@ -1596,7 +1590,7 @@ static int vpu_malone_input_frame_data(struct vpu_malone_str_buffer __iomem *str * This module is currently only supported for the H264 and HEVC formats, * for other formats, vpu_malone_add_scode() will return 0. */ - if ((disp_imm || low_latency) && !vpu_vb_is_codecconfig(vbuf)) { + if (disp_imm || low_latency) { ret = vpu_malone_add_scode(inst->core->iface, inst->id, &inst->stream_buffer, @@ -1643,7 +1637,6 @@ int vpu_malone_input_frame(struct vpu_shared_addr *shared, struct vpu_inst *inst, struct vb2_buffer *vb) { struct vpu_dec_ctrl *hc = shared->priv; - struct vb2_v4l2_buffer *vbuf; struct vpu_malone_str_buffer __iomem *str_buf = hc->str_buf[inst->id]; u32 disp_imm = hc->codec_param[inst->id].disp_imm; u32 size; @@ -1657,16 +1650,6 @@ int vpu_malone_input_frame(struct vpu_shared_addr *shared, return ret; size = ret; - /* - * if buffer only contain codec data, and the timestamp is invalid, - * don't put the invalid timestamp to resync - * merge the data to next frame - */ - vbuf = to_vb2_v4l2_buffer(vb); - if (vpu_vb_is_codecconfig(vbuf)) { - inst->extra_size += size; - return 0; - } if (inst->extra_size) { size += inst->extra_size; inst->extra_size = 0; diff --git a/drivers/media/platform/amphion/vpu_v4l2.c b/drivers/media/platform/amphion/vpu_v4l2.c index fcb2eff813ac4..511881a131b70 100644 --- a/drivers/media/platform/amphion/vpu_v4l2.c +++ b/drivers/media/platform/amphion/vpu_v4l2.c @@ -349,16 +349,6 @@ struct vb2_v4l2_buffer *vpu_next_src_buf(struct vpu_inst *inst) if (!src_buf || vpu_get_buffer_state(src_buf) == VPU_BUF_STATE_IDLE) return NULL; - while (vpu_vb_is_codecconfig(src_buf)) { - v4l2_m2m_src_buf_remove(inst->fh.m2m_ctx); - vpu_set_buffer_state(src_buf, VPU_BUF_STATE_IDLE); - v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); - - src_buf = v4l2_m2m_next_src_buf(inst->fh.m2m_ctx); - if (!src_buf || vpu_get_buffer_state(src_buf) == VPU_BUF_STATE_IDLE) - return NULL; - } - return src_buf; } diff --git a/drivers/media/platform/amphion/vpu_v4l2.h b/drivers/media/platform/amphion/vpu_v4l2.h index 4a87b06ae5203..da9945f25e327 100644 --- a/drivers/media/platform/amphion/vpu_v4l2.h +++ b/drivers/media/platform/amphion/vpu_v4l2.h @@ -39,14 +39,4 @@ static inline struct vpu_format *vpu_get_format(struct vpu_inst *inst, u32 type) else return &inst->cap_format; } - -static inline int vpu_vb_is_codecconfig(struct vb2_v4l2_buffer *vbuf) -{ -#ifdef V4L2_BUF_FLAG_CODECCONFIG - return (vbuf->flags & V4L2_BUF_FLAG_CODECCONFIG) ? 1 : 0; -#else - return 0; -#endif -} - #endif From 4d08b38a9828481cb0d33686fdce6f9d90a0350f Mon Sep 17 00:00:00 2001 From: Ming Qian Date: Tue, 16 Sep 2025 14:10:07 +0800 Subject: [PATCH 1632/2333] media: amphion: Cancel message work before releasing the VPU core commit ae246b0032146e352c4c06a7bf03cd3d5bcb2ecd upstream. To avoid accessing the VPU register after release of the VPU core, cancel the message work and destroy the workqueue that handles the VPU message before release of the VPU core. Fixes: 3cd084519c6f ("media: amphion: add vpu v4l2 m2m support") Cc: stable@vger.kernel.org Signed-off-by: Ming Qian Signed-off-by: Nicolas Dufresne Signed-off-by: Hans Verkuil Signed-off-by: Greg Kroah-Hartman --- drivers/media/platform/amphion/vpu_v4l2.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/amphion/vpu_v4l2.c b/drivers/media/platform/amphion/vpu_v4l2.c index 511881a131b70..47dff9a35bb46 100644 --- a/drivers/media/platform/amphion/vpu_v4l2.c +++ b/drivers/media/platform/amphion/vpu_v4l2.c @@ -703,15 +703,15 @@ static int vpu_v4l2_release(struct vpu_inst *inst) { vpu_trace(inst->vpu->dev, "%p\n", inst); - vpu_release_core(inst->core); - put_device(inst->dev); - if (inst->workqueue) { cancel_work_sync(&inst->msg_work); destroy_workqueue(inst->workqueue); inst->workqueue = NULL; } + vpu_release_core(inst->core); + put_device(inst->dev); + v4l2_ctrl_handler_free(&inst->ctrl_handler); mutex_destroy(&inst->lock); From 4d3c49fea27956dd82aadcb20949f1cf9222e8c1 Mon Sep 17 00:00:00 2001 From: Duoming Zhou Date: Tue, 2 Sep 2025 09:53:37 +0800 Subject: [PATCH 1633/2333] media: i2c: ADV7604: Remove redundant cancel_delayed_work in probe commit 8f34f24355a607b98ecd9924837aab13c676eeca upstream. The delayed_work delayed_work_enable_hotplug is initialized with INIT_DELAYED_WORK() in adv76xx_probe(), but it is never scheduled anywhere in the probe function. Calling cancel_delayed_work() on a work that has never been scheduled is redundant and unnecessary, as there is no pending work to cancel. Remove the redundant cancel_delayed_work() from error handling path and adjust the goto label accordingly to simplify the code and avoid potential confusion. Fixes: 54450f591c99 ("[media] adv7604: driver for the Analog Devices ADV7604 video decoder") Cc: stable@vger.kernel.org Signed-off-by: Duoming Zhou Signed-off-by: Hans Verkuil Signed-off-by: Greg Kroah-Hartman --- drivers/media/i2c/adv7604.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index 8fe7c2f728839..516553fb17e98 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c @@ -3670,7 +3670,7 @@ static int adv76xx_probe(struct i2c_client *client) err = media_entity_pads_init(&sd->entity, state->source_pad + 1, state->pads); if (err) - goto err_work_queues; + goto err_i2c; /* Configure regmaps */ err = configure_regmaps(state); @@ -3711,8 +3711,6 @@ static int adv76xx_probe(struct i2c_client *client) err_entity: media_entity_cleanup(&sd->entity); -err_work_queues: - cancel_delayed_work(&state->delayed_work_enable_hotplug); err_i2c: adv76xx_unregister_clients(state); err_hdl: From 2e9b9a658d42cd13dec9e900c261e7ead0d589db Mon Sep 17 00:00:00 2001 From: Duoming Zhou Date: Tue, 2 Sep 2025 09:10:31 +0800 Subject: [PATCH 1634/2333] media: i2c: adv7842: Remove redundant cancel_delayed_work in probe commit e66a5cc606c58e72f18f9cdd868a3672e918f9f8 upstream. The delayed_work delayed_work_enable_hotplug is initialized with INIT_DELAYED_WORK() in adv7842_probe(), but it is never scheduled anywhere in the probe function. Calling cancel_delayed_work() on a work that has never been scheduled is redundant and unnecessary, as there is no pending work to cancel. Remove the redundant cancel_delayed_work() from error handling path and adjust the goto label accordingly to simplify the code and avoid potential confusion. Fixes: a89bcd4c6c20 ("[media] adv7842: add new video decoder driver") Cc: stable@vger.kernel.org Signed-off-by: Duoming Zhou Signed-off-by: Hans Verkuil Signed-off-by: Greg Kroah-Hartman --- drivers/media/i2c/adv7842.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/media/i2c/adv7842.c b/drivers/media/i2c/adv7842.c index 111186529ed40..21c3d3682e0b4 100644 --- a/drivers/media/i2c/adv7842.c +++ b/drivers/media/i2c/adv7842.c @@ -3629,7 +3629,7 @@ static int adv7842_probe(struct i2c_client *client) err = media_entity_pads_init(&sd->entity, ADV7842_PAD_SOURCE + 1, state->pads); if (err) - goto err_work_queues; + goto err_i2c; err = adv7842_core_init(sd); if (err) @@ -3650,8 +3650,6 @@ static int adv7842_probe(struct i2c_client *client) err_entity: media_entity_cleanup(&sd->entity); -err_work_queues: - cancel_delayed_work(&state->delayed_work_enable_hotplug); err_i2c: adv7842_unregister_clients(sd); err_hdl: From 378deae752a229b018ab546b551897d4ab705c2d Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Fri, 17 Oct 2025 13:43:49 +0530 Subject: [PATCH 1635/2333] media: i2c: imx219: Fix 1920x1080 mode to use 1:1 pixel aspect ratio commit 9ef6e4db152c34580cc52792f32485c193945395 upstream. Commit 0af46fbc333d ("media: i2c: imx219: Calculate crop rectangle dynamically") meant that the 1920x1080 mode switched from using no binning to using vertical binning but no horizontal binning, which resulted in stretched pixels. Until proper controls are available to independently select horizontal and vertical binning, restore the original 1:1 pixel aspect ratio by forcing binning to be uniform in both directions. Cc: stable@vger.kernel.org Fixes: 0af46fbc333d ("media: i2c: imx219: Calculate crop rectangle dynamically") Signed-off-by: Dave Stevenson [Add comment & reword commit message] Signed-off-by: Jai Luthra Reviewed-by: Jacopo Mondi Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil Signed-off-by: Greg Kroah-Hartman --- drivers/media/i2c/imx219.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c index c680aa6c3a55a..300935b1ef249 100644 --- a/drivers/media/i2c/imx219.c +++ b/drivers/media/i2c/imx219.c @@ -856,7 +856,7 @@ static int imx219_set_pad_format(struct v4l2_subdev *sd, const struct imx219_mode *mode; struct v4l2_mbus_framefmt *format; struct v4l2_rect *crop; - u8 bin_h, bin_v; + u8 bin_h, bin_v, binning; u32 prev_line_len; format = v4l2_subdev_state_get_format(state, 0); @@ -877,9 +877,12 @@ static int imx219_set_pad_format(struct v4l2_subdev *sd, bin_h = min(IMX219_PIXEL_ARRAY_WIDTH / format->width, 2U); bin_v = min(IMX219_PIXEL_ARRAY_HEIGHT / format->height, 2U); + /* Ensure bin_h and bin_v are same to avoid 1:2 or 2:1 stretching */ + binning = min(bin_h, bin_v); + crop = v4l2_subdev_state_get_crop(state, 0); - crop->width = format->width * bin_h; - crop->height = format->height * bin_v; + crop->width = format->width * binning; + crop->height = format->height * binning; crop->left = (IMX219_NATIVE_WIDTH - crop->width) / 2; crop->top = (IMX219_NATIVE_HEIGHT - crop->height) / 2; From 3e858938b0e659f6ec9ddcf853a87f1c5c3f44e1 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Wed, 20 Aug 2025 15:54:05 +0800 Subject: [PATCH 1636/2333] media: mediatek: vcodec: Use spinlock for context list protection lock commit a5844227e0f030d2af2d85d4aed10c5eca6ca176 upstream. Previously a mutex was added to protect the encoder and decoder context lists from unexpected changes originating from the SCP IP block, causing the context pointer to go invalid, resulting in a NULL pointer dereference in the IPI handler. Turns out on the MT8173, the VPU IPI handler is called from hard IRQ context. This causes a big warning from the scheduler. This was first reported downstream on the ChromeOS kernels, but is also reproducible on mainline using Fluster with the FFmpeg v4l2m2m decoders. Even though the actual capture format is not supported, the affected code paths are triggered. Since this lock just protects the context list and operations on it are very fast, it should be OK to switch to a spinlock. Fixes: 6467cda18c9f ("media: mediatek: vcodec: adding lock to protect decoder context list") Fixes: afaaf3a0f647 ("media: mediatek: vcodec: adding lock to protect encoder context list") Cc: Yunfei Dong Cc: stable@vger.kernel.org Signed-off-by: Chen-Yu Tsai Reviewed-by: Fei Shao Reviewed-by: Tomasz Figa Signed-off-by: Nicolas Dufresne Signed-off-by: Hans Verkuil Signed-off-by: Greg Kroah-Hartman --- .../mediatek/vcodec/common/mtk_vcodec_fw_vpu.c | 10 ++++++---- .../mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c | 12 +++++++----- .../mediatek/vcodec/decoder/mtk_vcodec_dec_drv.h | 2 +- .../platform/mediatek/vcodec/decoder/vdec_vpu_if.c | 5 +++-- .../mediatek/vcodec/encoder/mtk_vcodec_enc_drv.c | 12 +++++++----- .../mediatek/vcodec/encoder/mtk_vcodec_enc_drv.h | 2 +- .../platform/mediatek/vcodec/encoder/venc_vpu_if.c | 5 +++-- 7 files changed, 28 insertions(+), 20 deletions(-) diff --git a/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw_vpu.c b/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw_vpu.c index d7027d600208f..223fb22948944 100644 --- a/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw_vpu.c +++ b/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw_vpu.c @@ -47,30 +47,32 @@ static void mtk_vcodec_vpu_reset_dec_handler(void *priv) { struct mtk_vcodec_dec_dev *dev = priv; struct mtk_vcodec_dec_ctx *ctx; + unsigned long flags; dev_err(&dev->plat_dev->dev, "Watchdog timeout!!"); - mutex_lock(&dev->dev_ctx_lock); + spin_lock_irqsave(&dev->dev_ctx_lock, flags); list_for_each_entry(ctx, &dev->ctx_list, list) { ctx->state = MTK_STATE_ABORT; mtk_v4l2_vdec_dbg(0, ctx, "[%d] Change to state MTK_STATE_ABORT", ctx->id); } - mutex_unlock(&dev->dev_ctx_lock); + spin_unlock_irqrestore(&dev->dev_ctx_lock, flags); } static void mtk_vcodec_vpu_reset_enc_handler(void *priv) { struct mtk_vcodec_enc_dev *dev = priv; struct mtk_vcodec_enc_ctx *ctx; + unsigned long flags; dev_err(&dev->plat_dev->dev, "Watchdog timeout!!"); - mutex_lock(&dev->dev_ctx_lock); + spin_lock_irqsave(&dev->dev_ctx_lock, flags); list_for_each_entry(ctx, &dev->ctx_list, list) { ctx->state = MTK_STATE_ABORT; mtk_v4l2_vdec_dbg(0, ctx, "[%d] Change to state MTK_STATE_ABORT", ctx->id); } - mutex_unlock(&dev->dev_ctx_lock); + spin_unlock_irqrestore(&dev->dev_ctx_lock, flags); } static const struct mtk_vcodec_fw_ops mtk_vcodec_vpu_msg = { diff --git a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c index 46d176e6de63e..3b81fae9f9135 100644 --- a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c +++ b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c @@ -198,6 +198,7 @@ static int fops_vcodec_open(struct file *file) struct mtk_vcodec_dec_ctx *ctx = NULL; int ret = 0, i, hw_count; struct vb2_queue *src_vq; + unsigned long flags; ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); if (!ctx) @@ -267,9 +268,9 @@ static int fops_vcodec_open(struct file *file) ctx->dev->vdec_pdata->init_vdec_params(ctx); - mutex_lock(&dev->dev_ctx_lock); + spin_lock_irqsave(&dev->dev_ctx_lock, flags); list_add(&ctx->list, &dev->ctx_list); - mutex_unlock(&dev->dev_ctx_lock); + spin_unlock_irqrestore(&dev->dev_ctx_lock, flags); mtk_vcodec_dbgfs_create(ctx); mutex_unlock(&dev->dev_mutex); @@ -294,6 +295,7 @@ static int fops_vcodec_release(struct file *file) { struct mtk_vcodec_dec_dev *dev = video_drvdata(file); struct mtk_vcodec_dec_ctx *ctx = file_to_dec_ctx(file); + unsigned long flags; mtk_v4l2_vdec_dbg(0, ctx, "[%d] decoder", ctx->id); mutex_lock(&dev->dev_mutex); @@ -312,9 +314,9 @@ static int fops_vcodec_release(struct file *file) v4l2_ctrl_handler_free(&ctx->ctrl_hdl); mtk_vcodec_dbgfs_remove(dev, ctx->id); - mutex_lock(&dev->dev_ctx_lock); + spin_lock_irqsave(&dev->dev_ctx_lock, flags); list_del_init(&ctx->list); - mutex_unlock(&dev->dev_ctx_lock); + spin_unlock_irqrestore(&dev->dev_ctx_lock, flags); kfree(ctx); mutex_unlock(&dev->dev_mutex); return 0; @@ -407,7 +409,7 @@ static int mtk_vcodec_probe(struct platform_device *pdev) for (i = 0; i < MTK_VDEC_HW_MAX; i++) mutex_init(&dev->dec_mutex[i]); mutex_init(&dev->dev_mutex); - mutex_init(&dev->dev_ctx_lock); + spin_lock_init(&dev->dev_ctx_lock); spin_lock_init(&dev->irqlock); snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name), "%s", diff --git a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.h b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.h index d047d7c580fb6..9d68808e8f9c3 100644 --- a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.h +++ b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.h @@ -285,7 +285,7 @@ struct mtk_vcodec_dec_dev { /* decoder hardware mutex lock */ struct mutex dec_mutex[MTK_VDEC_HW_MAX]; struct mutex dev_mutex; - struct mutex dev_ctx_lock; + spinlock_t dev_ctx_lock; struct workqueue_struct *decode_workqueue; spinlock_t irqlock; diff --git a/drivers/media/platform/mediatek/vcodec/decoder/vdec_vpu_if.c b/drivers/media/platform/mediatek/vcodec/decoder/vdec_vpu_if.c index 145958206e38a..40b97f114cf6f 100644 --- a/drivers/media/platform/mediatek/vcodec/decoder/vdec_vpu_if.c +++ b/drivers/media/platform/mediatek/vcodec/decoder/vdec_vpu_if.c @@ -75,16 +75,17 @@ static void handle_get_param_msg_ack(const struct vdec_vpu_ipi_get_param_ack *ms static bool vpu_dec_check_ap_inst(struct mtk_vcodec_dec_dev *dec_dev, struct vdec_vpu_inst *vpu) { struct mtk_vcodec_dec_ctx *ctx; + unsigned long flags; int ret = false; - mutex_lock(&dec_dev->dev_ctx_lock); + spin_lock_irqsave(&dec_dev->dev_ctx_lock, flags); list_for_each_entry(ctx, &dec_dev->ctx_list, list) { if (!IS_ERR_OR_NULL(ctx) && ctx->vpu_inst == vpu) { ret = true; break; } } - mutex_unlock(&dec_dev->dev_ctx_lock); + spin_unlock_irqrestore(&dec_dev->dev_ctx_lock, flags); return ret; } diff --git a/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_drv.c b/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_drv.c index fb1c3bdc2daeb..82b8ff38e8f1a 100644 --- a/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_drv.c +++ b/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_drv.c @@ -117,6 +117,7 @@ static int fops_vcodec_open(struct file *file) struct mtk_vcodec_enc_ctx *ctx = NULL; int ret = 0; struct vb2_queue *src_vq; + unsigned long flags; ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); if (!ctx) @@ -176,9 +177,9 @@ static int fops_vcodec_open(struct file *file) mtk_v4l2_venc_dbg(2, ctx, "Create instance [%d]@%p m2m_ctx=%p ", ctx->id, ctx, ctx->m2m_ctx); - mutex_lock(&dev->dev_ctx_lock); + spin_lock_irqsave(&dev->dev_ctx_lock, flags); list_add(&ctx->list, &dev->ctx_list); - mutex_unlock(&dev->dev_ctx_lock); + spin_unlock_irqrestore(&dev->dev_ctx_lock, flags); mutex_unlock(&dev->dev_mutex); mtk_v4l2_venc_dbg(0, ctx, "%s encoder [%d]", dev_name(&dev->plat_dev->dev), @@ -203,6 +204,7 @@ static int fops_vcodec_release(struct file *file) { struct mtk_vcodec_enc_dev *dev = video_drvdata(file); struct mtk_vcodec_enc_ctx *ctx = file_to_enc_ctx(file); + unsigned long flags; mtk_v4l2_venc_dbg(1, ctx, "[%d] encoder", ctx->id); mutex_lock(&dev->dev_mutex); @@ -213,9 +215,9 @@ static int fops_vcodec_release(struct file *file) v4l2_fh_exit(&ctx->fh); v4l2_ctrl_handler_free(&ctx->ctrl_hdl); - mutex_lock(&dev->dev_ctx_lock); + spin_lock_irqsave(&dev->dev_ctx_lock, flags); list_del_init(&ctx->list); - mutex_unlock(&dev->dev_ctx_lock); + spin_unlock_irqrestore(&dev->dev_ctx_lock, flags); kfree(ctx); mutex_unlock(&dev->dev_mutex); return 0; @@ -297,7 +299,7 @@ static int mtk_vcodec_probe(struct platform_device *pdev) mutex_init(&dev->enc_mutex); mutex_init(&dev->dev_mutex); - mutex_init(&dev->dev_ctx_lock); + spin_lock_init(&dev->dev_ctx_lock); spin_lock_init(&dev->irqlock); snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name), "%s", diff --git a/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_drv.h b/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_drv.h index 5b304a5512366..0cddfa13594f5 100644 --- a/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_drv.h +++ b/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_drv.h @@ -206,7 +206,7 @@ struct mtk_vcodec_enc_dev { /* encoder hardware mutex lock */ struct mutex enc_mutex; struct mutex dev_mutex; - struct mutex dev_ctx_lock; + spinlock_t dev_ctx_lock; struct workqueue_struct *encode_workqueue; int enc_irq; diff --git a/drivers/media/platform/mediatek/vcodec/encoder/venc_vpu_if.c b/drivers/media/platform/mediatek/vcodec/encoder/venc_vpu_if.c index 51bb7ee141b9e..3c229b1f6b21f 100644 --- a/drivers/media/platform/mediatek/vcodec/encoder/venc_vpu_if.c +++ b/drivers/media/platform/mediatek/vcodec/encoder/venc_vpu_if.c @@ -45,16 +45,17 @@ static void handle_enc_encode_msg(struct venc_vpu_inst *vpu, const void *data) static bool vpu_enc_check_ap_inst(struct mtk_vcodec_enc_dev *enc_dev, struct venc_vpu_inst *vpu) { struct mtk_vcodec_enc_ctx *ctx; + unsigned long flags; int ret = false; - mutex_lock(&enc_dev->dev_ctx_lock); + spin_lock_irqsave(&enc_dev->dev_ctx_lock, flags); list_for_each_entry(ctx, &enc_dev->ctx_list, list) { if (!IS_ERR_OR_NULL(ctx) && ctx->vpu_inst == vpu) { ret = true; break; } } - mutex_unlock(&enc_dev->dev_ctx_lock); + spin_unlock_irqrestore(&enc_dev->dev_ctx_lock, flags); return ret; } From f736a3f4787b0a74df7f410e87f33cc550d85890 Mon Sep 17 00:00:00 2001 From: Haoxiang Li Date: Mon, 15 Sep 2025 20:09:38 +0800 Subject: [PATCH 1637/2333] media: mediatek: vcodec: Fix a reference leak in mtk_vcodec_fw_vpu_init() commit cdd0f118ef87db8a664fb5ea366fd1766d2df1cd upstream. vpu_get_plat_device() increases the reference count of the returned platform device. However, when devm_kzalloc() fails, the reference is not released, causing a reference leak. Fix this by calling put_device() on fw_pdev->dev before returning on the error path. Fixes: e25a89f743b1 ("media: mtk-vcodec: potential dereference of null pointer") Cc: stable@vger.kernel.org Signed-off-by: Haoxiang Li Reviewed-by: AngeloGioacchino Del Regno Reviewed-by: Tzung-Bi Shih Signed-off-by: Nicolas Dufresne Signed-off-by: Hans Verkuil Signed-off-by: Greg Kroah-Hartman --- .../media/platform/mediatek/vcodec/common/mtk_vcodec_fw_vpu.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw_vpu.c b/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw_vpu.c index 223fb22948944..3632037f78f50 100644 --- a/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw_vpu.c +++ b/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw_vpu.c @@ -119,8 +119,10 @@ struct mtk_vcodec_fw *mtk_vcodec_fw_vpu_init(void *priv, enum mtk_vcodec_fw_use vpu_wdt_reg_handler(fw_pdev, mtk_vcodec_vpu_reset_enc_handler, priv, rst_id); fw = devm_kzalloc(&plat_dev->dev, sizeof(*fw), GFP_KERNEL); - if (!fw) + if (!fw) { + put_device(&fw_pdev->dev); return ERR_PTR(-ENOMEM); + } fw->type = VPU; fw->ops = &mtk_vcodec_vpu_msg; fw->pdev = fw_pdev; From eea343099facd13d27df4629198e9af98d126afe Mon Sep 17 00:00:00 2001 From: Huacai Chen Date: Sat, 6 Dec 2025 10:39:49 +0800 Subject: [PATCH 1638/2333] LoongArch: Add new PCI ID for pci_fixup_vgadev() commit bf3fa8f232a1eec8d7b88dcd9e925e60f04f018d upstream. Loongson-2K3000 has a new PCI ID (0x7a46) for its display controller, Add it for pci_fixup_vgadev() since we prefer a discrete graphics card as default boot device if present. Cc: stable@vger.kernel.org Signed-off-by: Tianrui Zhao Signed-off-by: Huacai Chen Signed-off-by: Greg Kroah-Hartman --- arch/loongarch/pci/pci.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/loongarch/pci/pci.c b/arch/loongarch/pci/pci.c index d9fc5d520b377..d923295ab8c66 100644 --- a/arch/loongarch/pci/pci.c +++ b/arch/loongarch/pci/pci.c @@ -14,6 +14,7 @@ #define PCI_DEVICE_ID_LOONGSON_HOST 0x7a00 #define PCI_DEVICE_ID_LOONGSON_DC1 0x7a06 #define PCI_DEVICE_ID_LOONGSON_DC2 0x7a36 +#define PCI_DEVICE_ID_LOONGSON_DC3 0x7a46 int raw_pci_read(unsigned int domain, unsigned int bus, unsigned int devfn, int reg, int len, u32 *val) @@ -97,3 +98,4 @@ static void pci_fixup_vgadev(struct pci_dev *pdev) } DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LOONGSON, PCI_DEVICE_ID_LOONGSON_DC1, pci_fixup_vgadev); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LOONGSON, PCI_DEVICE_ID_LOONGSON_DC2, pci_fixup_vgadev); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LOONGSON, PCI_DEVICE_ID_LOONGSON_DC3, pci_fixup_vgadev); From a6021c133ed8dad7db7eabd6c507264d9aea4375 Mon Sep 17 00:00:00 2001 From: Qiang Ma Date: Sat, 6 Dec 2025 10:39:49 +0800 Subject: [PATCH 1639/2333] LoongArch: Correct the calculation logic of thread_count commit 1de0ae21f136efa6c5d8a4d3e07b7d1ca39c750f upstream. For thread_count, the current calculation method has a maximum of 255, which may not be sufficient in the future. Therefore, we are correcting it now. Reference: SMBIOS Specification, 7.5 Processor Information (Type 4)[1] [1]: https://www.dmtf.org/sites/default/files/standards/documents/DSP0134_3.9.0.pdf Cc: stable@vger.kernel.org Signed-off-by: Qiang Ma Signed-off-by: Huacai Chen Signed-off-by: Greg Kroah-Hartman --- arch/loongarch/kernel/setup.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/arch/loongarch/kernel/setup.c b/arch/loongarch/kernel/setup.c index 25a87378e48e4..20cb6f3064568 100644 --- a/arch/loongarch/kernel/setup.c +++ b/arch/loongarch/kernel/setup.c @@ -56,6 +56,7 @@ #define SMBIOS_FREQLOW_MASK 0xFF #define SMBIOS_CORE_PACKAGE_OFFSET 0x23 #define SMBIOS_THREAD_PACKAGE_OFFSET 0x25 +#define SMBIOS_THREAD_PACKAGE_2_OFFSET 0x2E #define LOONGSON_EFI_ENABLE (1 << 3) unsigned long fw_arg0, fw_arg1, fw_arg2; @@ -126,7 +127,12 @@ static void __init parse_cpu_table(const struct dmi_header *dm) cpu_clock_freq = freq_temp * 1000000; loongson_sysconf.cpuname = (void *)dmi_string_parse(dm, dmi_data[16]); - loongson_sysconf.cores_per_package = *(dmi_data + SMBIOS_THREAD_PACKAGE_OFFSET); + loongson_sysconf.cores_per_package = *(u8 *)(dmi_data + SMBIOS_THREAD_PACKAGE_OFFSET); + if (dm->length >= 0x30 && loongson_sysconf.cores_per_package == 0xff) { + /* SMBIOS 3.0+ has ThreadCount2 for more than 255 threads */ + loongson_sysconf.cores_per_package = + *(u16 *)(dmi_data + SMBIOS_THREAD_PACKAGE_2_OFFSET); + } pr_info("CpuClock = %llu\n", cpu_clock_freq); } From 1f8330dcdc6084b10768f159cbb93269b392cc71 Mon Sep 17 00:00:00 2001 From: Huacai Chen Date: Sat, 6 Dec 2025 10:39:48 +0800 Subject: [PATCH 1640/2333] LoongArch: Fix arch_dup_task_struct() for CONFIG_RANDSTRUCT commit a91b446e359aa96cc2655318789fd37441337415 upstream. Now the optimized version of arch_dup_task_struct() for LoongArch assumes 'thread' is the last member of 'task_struct'. But this is not true if CONFIG_RANDSTRUCT is enabled after Linux-6.16. So fix the arch_dup_task_struct() function for CONFIG_RANDSTRUCT by copying the whole 'task_struct'. Cc: stable@vger.kernel.org # 6.16+ Signed-off-by: Huacai Chen Signed-off-by: Greg Kroah-Hartman --- arch/loongarch/kernel/process.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/loongarch/kernel/process.c b/arch/loongarch/kernel/process.c index efd9edf65603c..d1e04f9e0f795 100644 --- a/arch/loongarch/kernel/process.c +++ b/arch/loongarch/kernel/process.c @@ -130,6 +130,11 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src) preempt_enable(); + if (IS_ENABLED(CONFIG_RANDSTRUCT)) { + memcpy(dst, src, sizeof(struct task_struct)); + return 0; + } + if (!used_math()) memcpy(dst, src, offsetof(struct task_struct, thread.fpu.fpr)); else From 73a0059dcf26eeb07bebbcd1d95bde84fdaae7cd Mon Sep 17 00:00:00 2001 From: Huacai Chen Date: Sat, 6 Dec 2025 10:39:40 +0800 Subject: [PATCH 1641/2333] LoongArch: Fix build errors for CONFIG_RANDSTRUCT commit 3c250aecef62da81deb38ac6738ac0a88d91f1fc upstream. When CONFIG_RANDSTRUCT enabled, members of task_struct are randomized. There is a chance that TASK_STACK_CANARY be out of 12bit immediate's range and causes build errors. TASK_STACK_CANARY is naturally aligned, so fix it by replacing ld.d/st.d with ldptr.d/stptr.d which have 14bit immediates. Cc: stable@vger.kernel.org Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202511240656.0NaPcJs1-lkp@intel.com/ Suggested-by: Rui Wang Signed-off-by: Huacai Chen Signed-off-by: Greg Kroah-Hartman --- arch/loongarch/kernel/switch.S | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/loongarch/kernel/switch.S b/arch/loongarch/kernel/switch.S index 9c23cb7e432f1..3007e909e0d80 100644 --- a/arch/loongarch/kernel/switch.S +++ b/arch/loongarch/kernel/switch.S @@ -25,8 +25,8 @@ SYM_FUNC_START(__switch_to) stptr.d a4, a0, THREAD_SCHED_CFA #if defined(CONFIG_STACKPROTECTOR) && !defined(CONFIG_SMP) la t7, __stack_chk_guard - LONG_L t8, a1, TASK_STACK_CANARY - LONG_S t8, t7, 0 + ldptr.d t8, a1, TASK_STACK_CANARY + stptr.d t8, t7, 0 #endif move tp, a2 cpu_restore_nonscratch a1 From f92ac4ad6c8634d82f79a76fa995d7b1b7b35584 Mon Sep 17 00:00:00 2001 From: WangYuli Date: Sat, 6 Dec 2025 10:39:48 +0800 Subject: [PATCH 1642/2333] LoongArch: Use __pmd()/__pte() for swap entry conversions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 4a71df151e703b5e7e85b33369cee59ef2665e61 upstream. The __pmd() and __pte() helper macros provide the correct initialization syntax and abstraction for the pmd_t and pte_t types. Use __pmd() to fix follow warning about __swp_entry_to_pmd() with gcc-15 under specific configs [1] : In file included from ./include/linux/pgtable.h:6, from ./include/linux/mm.h:31, from ./include/linux/pagemap.h:8, from arch/loongarch/mm/init.c:14: ./include/linux/swapops.h: In function ‘swp_entry_to_pmd’: ./arch/loongarch/include/asm/pgtable.h:302:34: error: missing braces around initializer [-Werror=missing-braces] 302 | #define __swp_entry_to_pmd(x) ((pmd_t) { (x).val | _PAGE_HUGE }) | ^ ./include/linux/swapops.h:559:16: note: in expansion of macro ‘__swp_entry_to_pmd’ 559 | return __swp_entry_to_pmd(arch_entry); | ^~~~~~~~~~~~~~~~~~ cc1: all warnings being treated as errors Also update __swp_entry_to_pte() to use __pte() for consistency. [1]. https://download.01.org/0day-ci/archive/20251119/202511190316.luI90kAo-lkp@intel.com/config Cc: stable@vger.kernel.org Signed-off-by: Yuli Wang Signed-off-by: Huacai Chen Signed-off-by: Greg Kroah-Hartman --- arch/loongarch/include/asm/pgtable.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/loongarch/include/asm/pgtable.h b/arch/loongarch/include/asm/pgtable.h index 03fb60432fde7..9a7029285fd51 100644 --- a/arch/loongarch/include/asm/pgtable.h +++ b/arch/loongarch/include/asm/pgtable.h @@ -297,9 +297,9 @@ static inline pte_t mk_swap_pte(unsigned long type, unsigned long offset) #define __swp_offset(x) ((x).val >> 24) #define __swp_entry(type, offset) ((swp_entry_t) { pte_val(mk_swap_pte((type), (offset))) }) #define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) -#define __swp_entry_to_pte(x) ((pte_t) { (x).val }) +#define __swp_entry_to_pte(x) __pte((x).val) #define __pmd_to_swp_entry(pmd) ((swp_entry_t) { pmd_val(pmd) }) -#define __swp_entry_to_pmd(x) ((pmd_t) { (x).val | _PAGE_HUGE }) +#define __swp_entry_to_pmd(x) __pmd((x).val | _PAGE_HUGE) static inline bool pte_swp_exclusive(pte_t pte) { From ef17c7e2acda23ba6e60eaac197305cc6a6511a6 Mon Sep 17 00:00:00 2001 From: Tiezhu Yang Date: Sat, 6 Dec 2025 10:39:48 +0800 Subject: [PATCH 1643/2333] LoongArch: Use unsigned long for _end and _text commit a258a3cb1895e3acf5f2fe245d17426e894bc935 upstream. It is better to use unsigned long rather than long for _end and _text to calculate the kernel length. Cc: stable@vger.kernel.org # v6.3+ Fixes: e5f02b51fa0c ("LoongArch: Add support for kernel address space layout randomization (KASLR)") Signed-off-by: Tiezhu Yang Signed-off-by: Huacai Chen Signed-off-by: Greg Kroah-Hartman --- arch/loongarch/kernel/relocate.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/loongarch/kernel/relocate.c b/arch/loongarch/kernel/relocate.c index b5e2312a2fca5..76abbb8d29316 100644 --- a/arch/loongarch/kernel/relocate.c +++ b/arch/loongarch/kernel/relocate.c @@ -183,7 +183,7 @@ static inline void __init *determine_relocation_address(void) if (kaslr_disabled()) return destination; - kernel_length = (long)_end - (long)_text; + kernel_length = (unsigned long)_end - (unsigned long)_text; random_offset = get_random_boot() << 16; random_offset &= (CONFIG_RANDOMIZE_BASE_MAX_OFFSET - 1); @@ -232,7 +232,7 @@ unsigned long __init relocate_kernel(void) early_memunmap(cmdline, COMMAND_LINE_SIZE); if (random_offset) { - kernel_length = (long)(_end) - (long)(_text); + kernel_length = (unsigned long)(_end) - (unsigned long)(_text); /* Copy the kernel to it's new location */ memcpy(location_new, _text, kernel_length); From 33cf4171196debf6009e33d96dccdd7929071db5 Mon Sep 17 00:00:00 2001 From: SeongJae Park Date: Sat, 1 Nov 2025 11:20:14 -0700 Subject: [PATCH 1644/2333] mm/damon/tests/sysfs-kunit: handle alloc failures on damon_sysfs_test_add_targets() commit 7d808bf13943f4c6a6142400bffe14267f6dc997 upstream. damon_sysfs_test_add_targets() is assuming all dynamic memory allocation in it will succeed. Those are indeed likely in the real use cases since those allocations are too small to fail, but theoretically those could fail. In the case, inappropriate memory access can happen. Fix it by appropriately cleanup pre-allocated memory and skip the execution of the remaining tests in the failure cases. Link: https://lkml.kernel.org/r/20251101182021.74868-21-sj@kernel.org Fixes: b8ee5575f763 ("mm/damon/sysfs-test: add a unit test for damon_sysfs_set_targets()") Signed-off-by: SeongJae Park Cc: Brendan Higgins Cc: David Gow Cc: Kefeng Wang Cc: [6.7+] Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- mm/damon/tests/sysfs-kunit.h | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/mm/damon/tests/sysfs-kunit.h b/mm/damon/tests/sysfs-kunit.h index 7b5c7b307da99..ce7218469f20b 100644 --- a/mm/damon/tests/sysfs-kunit.h +++ b/mm/damon/tests/sysfs-kunit.h @@ -45,16 +45,41 @@ static void damon_sysfs_test_add_targets(struct kunit *test) struct damon_ctx *ctx; sysfs_targets = damon_sysfs_targets_alloc(); + if (!sysfs_targets) + kunit_skip(test, "sysfs_targets alloc fail"); sysfs_targets->nr = 1; sysfs_targets->targets_arr = kmalloc_array(1, sizeof(*sysfs_targets->targets_arr), GFP_KERNEL); + if (!sysfs_targets->targets_arr) { + kfree(sysfs_targets); + kunit_skip(test, "targets_arr alloc fail"); + } sysfs_target = damon_sysfs_target_alloc(); + if (!sysfs_target) { + kfree(sysfs_targets->targets_arr); + kfree(sysfs_targets); + kunit_skip(test, "sysfs_target alloc fail"); + } sysfs_target->pid = __damon_sysfs_test_get_any_pid(12, 100); sysfs_target->regions = damon_sysfs_regions_alloc(); + if (!sysfs_target->regions) { + kfree(sysfs_targets->targets_arr); + kfree(sysfs_targets); + kfree(sysfs_target); + kunit_skip(test, "sysfs_regions alloc fail"); + } + sysfs_targets->targets_arr[0] = sysfs_target; ctx = damon_new_ctx(); + if (!ctx) { + kfree(sysfs_targets->targets_arr); + kfree(sysfs_targets); + kfree(sysfs_target); + kfree(sysfs_target->regions); + kunit_skip(test, "ctx alloc fail"); + } damon_sysfs_add_targets(ctx, sysfs_targets); KUNIT_EXPECT_EQ(test, 1u, nr_damon_targets(ctx)); From 6fd615cb0440da435b9fdc1fbc5fadec9038db66 Mon Sep 17 00:00:00 2001 From: SeongJae Park Date: Sat, 1 Nov 2025 11:20:11 -0700 Subject: [PATCH 1645/2333] mm/damon/tests/vaddr-kunit: handle alloc failures on damon_do_test_apply_three_regions() commit 2b22d0fcc6320ba29b2122434c1d2f0785fb0a25 upstream. damon_do_test_apply_three_regions() is assuming all dynamic memory allocation in it will succeed. Those are indeed likely in the real use cases since those allocations are too small to fail, but theoretically those could fail. In the case, inappropriate memory access can happen. Fix it by appropriately cleanup pre-allocated memory and skip the execution of the remaining tests in the failure cases. Link: https://lkml.kernel.org/r/20251101182021.74868-18-sj@kernel.org Fixes: 17ccae8bb5c9 ("mm/damon: add kunit tests") Signed-off-by: SeongJae Park Cc: Brendan Higgins Cc: David Gow Cc: Kefeng Wang Cc: [5.15+] Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- mm/damon/tests/vaddr-kunit.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/mm/damon/tests/vaddr-kunit.h b/mm/damon/tests/vaddr-kunit.h index fce38dd53cf8f..484223f195459 100644 --- a/mm/damon/tests/vaddr-kunit.h +++ b/mm/damon/tests/vaddr-kunit.h @@ -136,8 +136,14 @@ static void damon_do_test_apply_three_regions(struct kunit *test, int i; t = damon_new_target(); + if (!t) + kunit_skip(test, "target alloc fail"); for (i = 0; i < nr_regions / 2; i++) { r = damon_new_region(regions[i * 2], regions[i * 2 + 1]); + if (!r) { + damon_destroy_target(t, NULL); + kunit_skip(test, "region alloc fail"); + } damon_add_region(r, t); } From 89532a71288cdcbfb6a6dfda331a939c87b08cec Mon Sep 17 00:00:00 2001 From: SeongJae Park Date: Sat, 1 Nov 2025 11:20:12 -0700 Subject: [PATCH 1646/2333] mm/damon/tests/vaddr-kunit: handle alloc failures in damon_test_split_evenly_fail() commit 7890e5b5bb6e386155c6e755fe70e0cdcc77f18e upstream. damon_test_split_evenly_fail() is assuming all dynamic memory allocation in it will succeed. Those are indeed likely in the real use cases since those allocations are too small to fail, but theoretically those could fail. In the case, inappropriate memory access can happen. Fix it by appropriately cleanup pre-allocated memory and skip the execution of the remaining tests in the failure cases. Link: https://lkml.kernel.org/r/20251101182021.74868-19-sj@kernel.org Fixes: 17ccae8bb5c9 ("mm/damon: add kunit tests") Signed-off-by: SeongJae Park Cc: Brendan Higgins Cc: David Gow Cc: Kefeng Wang Cc: [5.15+] Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- mm/damon/tests/vaddr-kunit.h | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/mm/damon/tests/vaddr-kunit.h b/mm/damon/tests/vaddr-kunit.h index 484223f195459..1b0f21c2e3763 100644 --- a/mm/damon/tests/vaddr-kunit.h +++ b/mm/damon/tests/vaddr-kunit.h @@ -256,7 +256,16 @@ static void damon_test_split_evenly_fail(struct kunit *test, unsigned long start, unsigned long end, unsigned int nr_pieces) { struct damon_target *t = damon_new_target(); - struct damon_region *r = damon_new_region(start, end); + struct damon_region *r; + + if (!t) + kunit_skip(test, "target alloc fail"); + + r = damon_new_region(start, end); + if (!r) { + damon_free_target(t); + kunit_skip(test, "region alloc fail"); + } damon_add_region(r, t); KUNIT_EXPECT_EQ(test, From 6e0090114d663b55a95dfa45bd1a5ed4483399b7 Mon Sep 17 00:00:00 2001 From: SeongJae Park Date: Sat, 1 Nov 2025 11:20:13 -0700 Subject: [PATCH 1647/2333] mm/damon/tests/vaddr-kunit: handle alloc failures on damon_test_split_evenly_succ() commit 0a63a0e7570b9b2631dfb8d836dc572709dce39e upstream. damon_test_split_evenly_succ() is assuming all dynamic memory allocation in it will succeed. Those are indeed likely in the real use cases since those allocations are too small to fail, but theoretically those could fail. In the case, inappropriate memory access can happen. Fix it by appropriately cleanup pre-allocated memory and skip the execution of the remaining tests in the failure cases. Link: https://lkml.kernel.org/r/20251101182021.74868-20-sj@kernel.org Fixes: 17ccae8bb5c9 ("mm/damon: add kunit tests") Signed-off-by: SeongJae Park Cc: Brendan Higgins Cc: David Gow Cc: Kefeng Wang Cc: [5.15+] Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- mm/damon/tests/vaddr-kunit.h | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/mm/damon/tests/vaddr-kunit.h b/mm/damon/tests/vaddr-kunit.h index 1b0f21c2e3763..30dc5459f1d2c 100644 --- a/mm/damon/tests/vaddr-kunit.h +++ b/mm/damon/tests/vaddr-kunit.h @@ -284,10 +284,17 @@ static void damon_test_split_evenly_succ(struct kunit *test, unsigned long start, unsigned long end, unsigned int nr_pieces) { struct damon_target *t = damon_new_target(); - struct damon_region *r = damon_new_region(start, end); + struct damon_region *r; unsigned long expected_width = (end - start) / nr_pieces; unsigned long i = 0; + if (!t) + kunit_skip(test, "target alloc fail"); + r = damon_new_region(start, end); + if (!r) { + damon_free_target(t); + kunit_skip(test, "region alloc fail"); + } damon_add_region(r, t); KUNIT_EXPECT_EQ(test, damon_va_evenly_split_region(t, r, nr_pieces), 0); From b55a42c605afa9450dc3637e55c30326cde41347 Mon Sep 17 00:00:00 2001 From: SeongJae Park Date: Sat, 1 Nov 2025 11:19:55 -0700 Subject: [PATCH 1648/2333] mm/damon/tests/core-kunit: fix memory leak in damon_test_set_filters_default_reject() commit b5ab490d85b772bc99d2648182a282f39f08feb6 upstream. Patch series "mm/damon/tests: fix memory bugs in kunit tests". DAMON kunit tests were initially written assuming those will be run on environments that are well controlled and therefore tolerant to transient test failures and bugs in the test code itself. The user-mode linux based manual run of the tests is one example of such an environment. And the test code was written for adding more test coverage as fast as possible, over making those safe and reliable. As a result, the tests resulted in having a number of bugs including real memory leaks, theoretical unhandled memory allocation failures, and unused memory allocations. The allocation failures that are not handled well are unlikely in the real world, since those allocations are too small to fail. But in theory, it can happen and cause inappropriate memory access. It is arguable if bugs in test code can really harm users. But, anyway bugs are bugs that need to be fixed. Fix the bugs one by one. Also Cc stable@ for the fixes of memory leak and unhandled memory allocation failures. The unused memory allocations are only a matter of memory efficiency, so not Cc-ing stable@. The first patch fixes memory leaks in the test code for the DAMON core layer. Following fifteen, three, and one patches respectively fix unhandled memory allocation failures in the test code for DAMON core layer, virtual address space DAMON operation set, and DAMON sysfs interface, one by one per test function. Final two patches remove memory allocations that are correctly deallocated at the end, but not really being used by any code. This patch (of 22): Kunit test function for damos_set_filters_default_reject() allocates two 'struct damos_filter' objects and not deallocates those, so that the memory for the two objects are leaked for every time the test runs. Fix this by deallocating those objects at the end of the test code. Link: https://lkml.kernel.org/r/20251101182021.74868-1-sj@kernel.org Link: https://lkml.kernel.org/r/20251101182021.74868-2-sj@kernel.org Fixes: 094fb14913c7 ("mm/damon/tests/core-kunit: add a test for damos_set_filters_default_reject()") Signed-off-by: SeongJae Park Cc: Brendan Higgins Cc: David Gow Cc: Kefeng Wang Cc: [6.16+] Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- mm/damon/tests/core-kunit.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mm/damon/tests/core-kunit.h b/mm/damon/tests/core-kunit.h index 51369e35298b1..69ca44f9270bb 100644 --- a/mm/damon/tests/core-kunit.h +++ b/mm/damon/tests/core-kunit.h @@ -598,6 +598,9 @@ static void damon_test_set_filters_default_reject(struct kunit *test) */ KUNIT_EXPECT_EQ(test, scheme.core_filters_default_reject, false); KUNIT_EXPECT_EQ(test, scheme.ops_filters_default_reject, true); + + damos_free_filter(anon_filter); + damos_free_filter(target_filter); } static struct kunit_case damon_test_cases[] = { From 9c46f119b70d38443711f27b438cfe303aaaab50 Mon Sep 17 00:00:00 2001 From: SeongJae Park Date: Sat, 1 Nov 2025 11:20:07 -0700 Subject: [PATCH 1649/2333] mm/damon/tests/core-kunit: handle alloc failres in damon_test_new_filter() commit 28ab2265e9422ccd81e4beafc0ace90f78de04c4 upstream. damon_test_new_filter() is assuming all dynamic memory allocation in it will succeed. Those are indeed likely in the real use cases since those allocations are too small to fail, but theoretically those could fail. In the case, inappropriate memory access can happen. Fix it by appropriately cleanup pre-allocated memory and skip the execution of the remaining tests in the failure cases. Link: https://lkml.kernel.org/r/20251101182021.74868-14-sj@kernel.org Fixes: 2a158e956b98 ("mm/damon/core-test: add a test for damos_new_filter()") Signed-off-by: SeongJae Park Cc: Brendan Higgins Cc: David Gow Cc: Kefeng Wang Cc: [6.6+] Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- mm/damon/tests/core-kunit.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mm/damon/tests/core-kunit.h b/mm/damon/tests/core-kunit.h index 69ca44f9270bb..3d10a5fad5e0c 100644 --- a/mm/damon/tests/core-kunit.h +++ b/mm/damon/tests/core-kunit.h @@ -412,6 +412,8 @@ static void damos_test_new_filter(struct kunit *test) struct damos_filter *filter; filter = damos_new_filter(DAMOS_FILTER_TYPE_ANON, true, false); + if (!filter) + kunit_skip(test, "filter alloc fail"); KUNIT_EXPECT_EQ(test, filter->type, DAMOS_FILTER_TYPE_ANON); KUNIT_EXPECT_EQ(test, filter->matching, true); KUNIT_EXPECT_PTR_EQ(test, filter->list.prev, &filter->list); From ead9dd2174e9deb2b29a235632cc5cba23811586 Mon Sep 17 00:00:00 2001 From: SeongJae Park Date: Sat, 1 Nov 2025 11:19:59 -0700 Subject: [PATCH 1650/2333] mm/damon/tests/core-kunit: handle alloc failures on damon_test_split_at() commit 5e80d73f22043c59c8ad36452a3253937ed77955 upstream. damon_test_split_at() is assuming all dynamic memory allocation in it will succeed. Those are indeed likely in the real use cases since those allocations are too small to fail, but theoretically those could fail. In the case, inappropriate memory access can happen. Fix it by appropriately cleanup pre-allocated memory and skip the execution of the remaining tests in the failure cases. Link: https://lkml.kernel.org/r/20251101182021.74868-6-sj@kernel.org Fixes: 17ccae8bb5c9 ("mm/damon: add kunit tests") Signed-off-by: SeongJae Park Cc: Brendan Higgins Cc: David Gow Cc: Kefeng Wang Cc: [5.15+] Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- mm/damon/tests/core-kunit.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/mm/damon/tests/core-kunit.h b/mm/damon/tests/core-kunit.h index 3d10a5fad5e0c..efe4789ab9627 100644 --- a/mm/damon/tests/core-kunit.h +++ b/mm/damon/tests/core-kunit.h @@ -124,8 +124,19 @@ static void damon_test_split_at(struct kunit *test) struct damon_target *t; struct damon_region *r, *r_new; + if (!c) + kunit_skip(test, "ctx alloc fail"); t = damon_new_target(); + if (!t) { + damon_destroy_ctx(c); + kunit_skip(test, "target alloc fail"); + } r = damon_new_region(0, 100); + if (!r) { + damon_destroy_ctx(c); + damon_free_target(t); + kunit_skip(test, "region alloc fail"); + } r->nr_accesses_bp = 420000; r->nr_accesses = 42; r->last_nr_accesses = 15; From d0870d0fe61338f0c7bbda07e22682e570823d03 Mon Sep 17 00:00:00 2001 From: SeongJae Park Date: Sat, 1 Nov 2025 11:19:56 -0700 Subject: [PATCH 1651/2333] mm/damon/tests/core-kunit: handle allocation failures in damon_test_regions() commit e16fdd4f754048d6e23c56bd8d920b71e41e3777 upstream. damon_test_regions() is assuming all dynamic memory allocation in it will succeed. Those are indeed likely in the real use cases since those allocations are too small to fail, but theoretically those could fail. In the case, inappropriate memory access can happen. Fix it by appropriately cleanup pre-allocated memory and skip the execution of the remaining tests in the failure cases. Link: https://lkml.kernel.org/r/20251101182021.74868-3-sj@kernel.org Fixes: 17ccae8bb5c9 ("mm/damon: add kunit tests") Signed-off-by: SeongJae Park Cc: Brendan Higgins Cc: David Gow Cc: Kefeng Wang Cc: [5.15+] Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- mm/damon/tests/core-kunit.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/mm/damon/tests/core-kunit.h b/mm/damon/tests/core-kunit.h index efe4789ab9627..22d5ff51fa0b9 100644 --- a/mm/damon/tests/core-kunit.h +++ b/mm/damon/tests/core-kunit.h @@ -20,11 +20,17 @@ static void damon_test_regions(struct kunit *test) struct damon_target *t; r = damon_new_region(1, 2); + if (!r) + kunit_skip(test, "region alloc fail"); KUNIT_EXPECT_EQ(test, 1ul, r->ar.start); KUNIT_EXPECT_EQ(test, 2ul, r->ar.end); KUNIT_EXPECT_EQ(test, 0u, r->nr_accesses); t = damon_new_target(); + if (!t) { + damon_free_region(r); + kunit_skip(test, "target alloc fail"); + } KUNIT_EXPECT_EQ(test, 0u, damon_nr_regions(t)); damon_add_region(r, t); From 63669f6b729f49e397aa1e26a3647ac73fc54fc5 Mon Sep 17 00:00:00 2001 From: SeongJae Park Date: Sat, 1 Nov 2025 11:19:57 -0700 Subject: [PATCH 1652/2333] mm/damon/tests/core-kunit: handle memory failure from damon_test_target() commit fafe953de2c661907c94055a2497c6b8dbfd26f3 upstream. damon_test_target() is assuming all dynamic memory allocation in it will succeed. Those are indeed likely in the real use cases since those allocations are too small to fail, but theoretically those could fail. In the case, inappropriate memory access can happen. Fix it by appropriately cleanup pre-allocated memory and skip the execution of the remaining tests in the failure cases. Link: https://lkml.kernel.org/r/20251101182021.74868-4-sj@kernel.org Fixes: 17ccae8bb5c9 ("mm/damon: add kunit tests") Signed-off-by: SeongJae Park Cc: Brendan Higgins Cc: David Gow Cc: Kefeng Wang Cc: [5.15+] Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- mm/damon/tests/core-kunit.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/mm/damon/tests/core-kunit.h b/mm/damon/tests/core-kunit.h index 22d5ff51fa0b9..fb42763e4cf18 100644 --- a/mm/damon/tests/core-kunit.h +++ b/mm/damon/tests/core-kunit.h @@ -58,7 +58,14 @@ static void damon_test_target(struct kunit *test) struct damon_ctx *c = damon_new_ctx(); struct damon_target *t; + if (!c) + kunit_skip(test, "ctx alloc fail"); + t = damon_new_target(); + if (!t) { + damon_destroy_ctx(c); + kunit_skip(test, "target alloc fail"); + } KUNIT_EXPECT_EQ(test, 0u, nr_damon_targets(c)); damon_add_target(c, t); From 8ac54bafd439bd670945497ac6b9d3b05d645fe2 Mon Sep 17 00:00:00 2001 From: SeongJae Park Date: Sat, 1 Nov 2025 11:19:58 -0700 Subject: [PATCH 1653/2333] mm/damon/tests/core-kunit: handle memory alloc failure from damon_test_aggregate() commit f79f2fc44ebd0ed655239046be3e80e8804b5545 upstream. damon_test_aggregate() is assuming all dynamic memory allocation in it will succeed. Those are indeed likely in the real use cases since those allocations are too small to fail, but theoretically those could fail. In the case, inappropriate memory access can happen. Fix it by appropriately cleanup pre-allocated memory and skip the execution of the remaining tests in the failure cases. Link: https://lkml.kernel.org/r/20251101182021.74868-5-sj@kernel.org Fixes: 17ccae8bb5c9 ("mm/damon: add kunit tests") Signed-off-by: SeongJae Park Cc: Brendan Higgins Cc: David Gow Cc: Kefeng Wang Cc: [5.15+] Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- mm/damon/tests/core-kunit.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/mm/damon/tests/core-kunit.h b/mm/damon/tests/core-kunit.h index fb42763e4cf18..948b1b4ab1685 100644 --- a/mm/damon/tests/core-kunit.h +++ b/mm/damon/tests/core-kunit.h @@ -97,8 +97,15 @@ static void damon_test_aggregate(struct kunit *test) struct damon_region *r; int it, ir; + if (!ctx) + kunit_skip(test, "ctx alloc fail"); + for (it = 0; it < 3; it++) { t = damon_new_target(); + if (!t) { + damon_destroy_ctx(ctx); + kunit_skip(test, "target alloc fail"); + } damon_add_target(ctx, t); } @@ -106,6 +113,10 @@ static void damon_test_aggregate(struct kunit *test) damon_for_each_target(t, ctx) { for (ir = 0; ir < 3; ir++) { r = damon_new_region(saddr[it][ir], eaddr[it][ir]); + if (!r) { + damon_destroy_ctx(ctx); + kunit_skip(test, "region alloc fail"); + } r->nr_accesses = accesses[it][ir]; r->nr_accesses_bp = accesses[it][ir] * 10000; damon_add_region(r, t); From 753c12ff6d25d6c40f7df347760a52a42f0805b3 Mon Sep 17 00:00:00 2001 From: SeongJae Park Date: Sat, 1 Nov 2025 11:20:01 -0700 Subject: [PATCH 1654/2333] mm/damon/tests/core-kunit: handle alloc failures on dasmon_test_merge_regions_of() commit 0998d2757218771c59d5ca59ccf13d1542a38f17 upstream. damon_test_merge_regions_of() is assuming all dynamic memory allocation in it will succeed. Those are indeed likely in the real use cases since those allocations are too small to fail, but theoretically those could fail. In the case, inappropriate memory access can happen. Fix it by appropriately cleanup pre-allocated memory and skip the execution of the remaining tests in the failure cases. Link: https://lkml.kernel.org/r/20251101182021.74868-8-sj@kernel.org Fixes: 17ccae8bb5c9 ("mm/damon: add kunit tests") Signed-off-by: SeongJae Park Cc: Brendan Higgins Cc: David Gow Cc: Kefeng Wang Cc: [5.15+] Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- mm/damon/tests/core-kunit.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/mm/damon/tests/core-kunit.h b/mm/damon/tests/core-kunit.h index 948b1b4ab1685..f00edabc5ddbb 100644 --- a/mm/damon/tests/core-kunit.h +++ b/mm/damon/tests/core-kunit.h @@ -238,8 +238,14 @@ static void damon_test_merge_regions_of(struct kunit *test) int i; t = damon_new_target(); + if (!t) + kunit_skip(test, "target alloc fail"); for (i = 0; i < ARRAY_SIZE(sa); i++) { r = damon_new_region(sa[i], ea[i]); + if (!r) { + damon_free_target(t); + kunit_skip(test, "region alloc fail"); + } r->nr_accesses = nrs[i]; r->nr_accesses_bp = nrs[i] * 10000; damon_add_region(r, t); From 65807e05960b07d6f9b0840bc2c0bb23b50af54a Mon Sep 17 00:00:00 2001 From: SeongJae Park Date: Sat, 1 Nov 2025 11:20:00 -0700 Subject: [PATCH 1655/2333] mm/damon/tests/core-kunit: handle alloc failures on damon_test_merge_two() commit 3d443dd29a1db7efa587a4bb0c06a497e13ca9e4 upstream. damon_test_merge_two() is assuming all dynamic memory allocation in it will succeed. Those are indeed likely in the real use cases since those allocations are too small to fail, but theoretically those could fail. In the case, inappropriate memory access can happen. Fix it by appropriately cleanup pre-allocated memory and skip the execution of the remaining tests in the failure cases. Link: https://lkml.kernel.org/r/20251101182021.74868-7-sj@kernel.org Fixes: 17ccae8bb5c9 ("mm/damon: add kunit tests") Signed-off-by: SeongJae Park Cc: Brendan Higgins Cc: David Gow Cc: Kefeng Wang Cc: [5.15+] Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- mm/damon/tests/core-kunit.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/mm/damon/tests/core-kunit.h b/mm/damon/tests/core-kunit.h index f00edabc5ddbb..359dce4e7353a 100644 --- a/mm/damon/tests/core-kunit.h +++ b/mm/damon/tests/core-kunit.h @@ -188,11 +188,21 @@ static void damon_test_merge_two(struct kunit *test) int i; t = damon_new_target(); + if (!t) + kunit_skip(test, "target alloc fail"); r = damon_new_region(0, 100); + if (!r) { + damon_free_target(t); + kunit_skip(test, "region alloc fail"); + } r->nr_accesses = 10; r->nr_accesses_bp = 100000; damon_add_region(r, t); r2 = damon_new_region(100, 300); + if (!r2) { + damon_free_target(t); + kunit_skip(test, "second region alloc fail"); + } r2->nr_accesses = 20; r2->nr_accesses_bp = 200000; damon_add_region(r2, t); From 8ce6a884fd4b282121b72476fcceb2710c4f0e5e Mon Sep 17 00:00:00 2001 From: SeongJae Park Date: Sat, 1 Nov 2025 11:20:04 -0700 Subject: [PATCH 1656/2333] mm/damon/tests/core-kunit: handle alloc failures in damon_test_set_regions() commit 74d5969995d129fd59dd93b9c7daa6669cb6810f upstream. damon_test_set_regions() is assuming all dynamic memory allocation in it will succeed. Those are indeed likely in the real use cases since those allocations are too small to fail, but theoretically those could fail. In the case, inappropriate memory access can happen. Fix it by appropriately cleanup pre-allocated memory and skip the execution of the remaining tests in the failure cases. Link: https://lkml.kernel.org/r/20251101182021.74868-11-sj@kernel.org Fixes: 62f409560eb2 ("mm/damon/core-test: test damon_set_regions") Signed-off-by: SeongJae Park Cc: Brendan Higgins Cc: David Gow Cc: Kefeng Wang Cc: [6.1+] Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- mm/damon/tests/core-kunit.h | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/mm/damon/tests/core-kunit.h b/mm/damon/tests/core-kunit.h index 359dce4e7353a..2173686f6776f 100644 --- a/mm/damon/tests/core-kunit.h +++ b/mm/damon/tests/core-kunit.h @@ -345,13 +345,26 @@ static void damon_test_ops_registration(struct kunit *test) static void damon_test_set_regions(struct kunit *test) { struct damon_target *t = damon_new_target(); - struct damon_region *r1 = damon_new_region(4, 16); - struct damon_region *r2 = damon_new_region(24, 32); + struct damon_region *r1, *r2; struct damon_addr_range range = {.start = 8, .end = 28}; unsigned long expects[] = {8, 16, 16, 24, 24, 28}; int expect_idx = 0; struct damon_region *r; + if (!t) + kunit_skip(test, "target alloc fail"); + r1 = damon_new_region(4, 16); + if (!r1) { + damon_free_target(t); + kunit_skip(test, "region alloc fail"); + } + r2 = damon_new_region(24, 32); + if (!r2) { + damon_free_target(t); + damon_free_region(r1); + kunit_skip(test, "second region alloc fail"); + } + damon_add_region(r1, t); damon_add_region(r2, t); damon_set_regions(t, &range, 1, DAMON_MIN_REGION); From 1e88ea25235544a51faa889846f13de88b6e9a2e Mon Sep 17 00:00:00 2001 From: SeongJae Park Date: Sat, 1 Nov 2025 11:20:05 -0700 Subject: [PATCH 1657/2333] mm/damon/tests/core-kunit: handle alloc failures in damon_test_update_monitoring_result() commit 8cf298c01b7fdb08eef5b6b26d0fe98d48134d72 upstream. damon_test_update_monitoring_result() is assuming all dynamic memory allocation in it will succeed. Those are indeed likely in the real use cases since those allocations are too small to fail, but theoretically those could fail. In the case, inappropriate memory access can happen. Fix it by appropriately cleanup pre-allocated memory and skip the execution of the remaining tests in the failure cases. Link: https://lkml.kernel.org/r/20251101182021.74868-12-sj@kernel.org Fixes: f4c978b6594b ("mm/damon/core-test: add a test for damon_update_monitoring_results()") Signed-off-by: SeongJae Park Cc: Brendan Higgins Cc: David Gow Cc: Kefeng Wang Cc: [6.3+] Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- mm/damon/tests/core-kunit.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mm/damon/tests/core-kunit.h b/mm/damon/tests/core-kunit.h index 2173686f6776f..51051834e1772 100644 --- a/mm/damon/tests/core-kunit.h +++ b/mm/damon/tests/core-kunit.h @@ -406,6 +406,9 @@ static void damon_test_update_monitoring_result(struct kunit *test) struct damon_attrs new_attrs; struct damon_region *r = damon_new_region(3, 7); + if (!r) + kunit_skip(test, "region alloc fail"); + r->nr_accesses = 15; r->nr_accesses_bp = 150000; r->age = 20; From 7d0299ff888319a03c4a929ea2230cac11816cb8 Mon Sep 17 00:00:00 2001 From: SeongJae Park Date: Sat, 1 Nov 2025 11:20:10 -0700 Subject: [PATCH 1658/2333] mm/damon/tests/core-kunit: handle alloc failures on damon_test_set_filters_default_reject() commit 84be856cc87317bc60ff54bd7c8f8a5aa8f0e2c8 upstream. damon_test_set_filters_default_reject() is assuming all dynamic memory allocation in it will succeed. Those are indeed likely in the real use cases since those allocations are too small to fail, but theoretically those could fail. In the case, inappropriate memory access can happen. Fix it by appropriately cleanup pre-allocated memory and skip the execution of the remaining tests in the failure cases. Link: https://lkml.kernel.org/r/20251101182021.74868-17-sj@kernel.org Fixes: 094fb14913c7 ("mm/damon/tests/core-kunit: add a test for damos_set_filters_default_reject()") Signed-off-by: SeongJae Park Cc: Brendan Higgins Cc: David Gow Cc: Kefeng Wang Cc: [6.16+] Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- mm/damon/tests/core-kunit.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/mm/damon/tests/core-kunit.h b/mm/damon/tests/core-kunit.h index 51051834e1772..62e5bb465a922 100644 --- a/mm/damon/tests/core-kunit.h +++ b/mm/damon/tests/core-kunit.h @@ -617,6 +617,8 @@ static void damon_test_set_filters_default_reject(struct kunit *test) KUNIT_EXPECT_EQ(test, scheme.ops_filters_default_reject, false); target_filter = damos_new_filter(DAMOS_FILTER_TYPE_TARGET, true, true); + if (!target_filter) + kunit_skip(test, "filter alloc fail"); damos_add_filter(&scheme, target_filter); damos_set_filters_default_reject(&scheme); /* @@ -642,6 +644,10 @@ static void damon_test_set_filters_default_reject(struct kunit *test) KUNIT_EXPECT_EQ(test, scheme.ops_filters_default_reject, false); anon_filter = damos_new_filter(DAMOS_FILTER_TYPE_ANON, true, true); + if (!anon_filter) { + damos_free_filter(target_filter); + kunit_skip(test, "anon_filter alloc fail"); + } damos_add_filter(&scheme, anon_filter); damos_set_filters_default_reject(&scheme); From 3987bd5706c91325ad8d26e5052c60dbd1cc7ed2 Mon Sep 17 00:00:00 2001 From: SeongJae Park Date: Sat, 1 Nov 2025 11:20:09 -0700 Subject: [PATCH 1659/2333] mm/damon/tests/core-kunit: handle alloc failures on damos_test_filter_out() commit d14d5671e7c9cc788c5a1edfa94e6f9064275905 upstream. damon_test_filter_out() is assuming all dynamic memory allocation in it will succeed. Those are indeed likely in the real use cases since those allocations are too small to fail, but theoretically those could fail. In the case, inappropriate memory access can happen. Fix it by appropriately cleanup pre-allocated memory and skip the execution of the remaining tests in the failure cases. Link: https://lkml.kernel.org/r/20251101182021.74868-16-sj@kernel.org Fixes: 26713c890875 ("mm/damon/core-test: add a unit test for __damos_filter_out()") Signed-off-by: SeongJae Park Cc: Brendan Higgins Cc: David Gow Cc: Kefeng Wang Cc: [6.6+] Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- mm/damon/tests/core-kunit.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/mm/damon/tests/core-kunit.h b/mm/damon/tests/core-kunit.h index 62e5bb465a922..f37344ee809c3 100644 --- a/mm/damon/tests/core-kunit.h +++ b/mm/damon/tests/core-kunit.h @@ -511,11 +511,22 @@ static void damos_test_filter_out(struct kunit *test) struct damos_filter *f; f = damos_new_filter(DAMOS_FILTER_TYPE_ADDR, true, false); + if (!f) + kunit_skip(test, "filter alloc fail"); f->addr_range = (struct damon_addr_range){ .start = DAMON_MIN_REGION * 2, .end = DAMON_MIN_REGION * 6}; t = damon_new_target(); + if (!t) { + damos_destroy_filter(f); + kunit_skip(test, "target alloc fail"); + } r = damon_new_region(DAMON_MIN_REGION * 3, DAMON_MIN_REGION * 5); + if (!r) { + damos_destroy_filter(f); + damon_free_target(t); + kunit_skip(test, "region alloc fail"); + } damon_add_region(r, t); /* region in the range */ From 4b03893690658ff245f9ef1a5905df4f797b5664 Mon Sep 17 00:00:00 2001 From: SeongJae Park Date: Sat, 1 Nov 2025 11:20:03 -0700 Subject: [PATCH 1660/2333] mm/damon/tests/core-kunit: handle alloc failures in damon_test_ops_registration() commit 4f835f4e8c863985f15abd69db033c2f66546094 upstream. damon_test_ops_registration() is assuming all dynamic memory allocation in it will succeed. Those are indeed likely in the real use cases since those allocations are too small to fail, but theoretically those could fail. In the case, inappropriate memory access can happen. Fix it by appropriately cleanup pre-allocated memory and skip the execution of the remaining tests in the failure cases. Link: https://lkml.kernel.org/r/20251101182021.74868-10-sj@kernel.org Fixes: 4f540f5ab4f2 ("mm/damon/core-test: add a kunit test case for ops registration") Signed-off-by: SeongJae Park Cc: Brendan Higgins Cc: David Gow Cc: Kefeng Wang Cc: [5.19+] Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- mm/damon/tests/core-kunit.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mm/damon/tests/core-kunit.h b/mm/damon/tests/core-kunit.h index f37344ee809c3..63474ada21d56 100644 --- a/mm/damon/tests/core-kunit.h +++ b/mm/damon/tests/core-kunit.h @@ -300,6 +300,9 @@ static void damon_test_ops_registration(struct kunit *test) struct damon_operations ops = {.id = DAMON_OPS_VADDR}, bak; bool need_cleanup = false; + if (!c) + kunit_skip(test, "ctx alloc fail"); + /* DAMON_OPS_VADDR is registered only if CONFIG_DAMON_VADDR is set */ if (!damon_is_registered_ops(DAMON_OPS_VADDR)) { bak.id = DAMON_OPS_VADDR; From 792515de4e9d0ac923c0194063f10d7f9e228244 Mon Sep 17 00:00:00 2001 From: SeongJae Park Date: Sat, 1 Nov 2025 11:20:06 -0700 Subject: [PATCH 1661/2333] mm/damon/tests/core-kunit: handle alloc failure on damon_test_set_attrs() commit 915a2453d824a9b6bf724e3f970d86ae1d092a61 upstream. damon_test_set_attrs() is assuming all dynamic memory allocation in it will succeed. Those are indeed likely in the real use cases since those allocations are too small to fail, but theoretically those could fail. In the case, inappropriate memory access can happen. Fix it by appropriately cleanup pre-allocated memory and skip the execution of the remaining tests in the failure cases. Link: https://lkml.kernel.org/r/20251101182021.74868-13-sj@kernel.org Fixes: aa13779be6b7 ("mm/damon/core-test: add a test for damon_set_attrs()") Signed-off-by: SeongJae Park Cc: Brendan Higgins Cc: David Gow Cc: Kefeng Wang Cc: [6.5+] Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- mm/damon/tests/core-kunit.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mm/damon/tests/core-kunit.h b/mm/damon/tests/core-kunit.h index 63474ada21d56..3ad9b851a19e6 100644 --- a/mm/damon/tests/core-kunit.h +++ b/mm/damon/tests/core-kunit.h @@ -445,6 +445,9 @@ static void damon_test_set_attrs(struct kunit *test) .sample_interval = 5000, .aggr_interval = 100000,}; struct damon_attrs invalid_attrs; + if (!c) + kunit_skip(test, "ctx alloc fail"); + KUNIT_EXPECT_EQ(test, damon_set_attrs(c, &valid_attrs), 0); invalid_attrs = valid_attrs; From 11ccb3476ead90e7da669a0d0a5b74ac8819208a Mon Sep 17 00:00:00 2001 From: SeongJae Park Date: Sat, 1 Nov 2025 11:20:08 -0700 Subject: [PATCH 1662/2333] mm/damon/tests/core-kunit: handle alloc failure on damos_test_commit_filter() commit 3e5c4a1a1737bd79abaaa184233d0f815e62273b upstream. damon_test_commit_filter() is assuming all dynamic memory allocation in it will succeed. Those are indeed likely in the real use cases since those allocations are too small to fail, but theoretically those could fail. In the case, inappropriate memory access can happen. Fix it by appropriately cleanup pre-allocated memory and skip the execution of the remaining tests in the failure cases. Link: https://lkml.kernel.org/r/20251101182021.74868-15-sj@kernel.org Fixes: f6a4a150f1ec ("mm/damon/tests/core-kunit: add damos_commit_filter test") Signed-off-by: SeongJae Park Cc: Brendan Higgins Cc: David Gow Cc: Kefeng Wang Cc: [6.18+] Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- mm/damon/tests/core-kunit.h | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/mm/damon/tests/core-kunit.h b/mm/damon/tests/core-kunit.h index 3ad9b851a19e6..63d10ca934f61 100644 --- a/mm/damon/tests/core-kunit.h +++ b/mm/damon/tests/core-kunit.h @@ -496,11 +496,16 @@ static void damos_test_new_filter(struct kunit *test) static void damos_test_commit_filter(struct kunit *test) { - struct damos_filter *src_filter = damos_new_filter( - DAMOS_FILTER_TYPE_ANON, true, true); - struct damos_filter *dst_filter = damos_new_filter( - DAMOS_FILTER_TYPE_ACTIVE, false, false); - + struct damos_filter *src_filter, *dst_filter; + + src_filter = damos_new_filter(DAMOS_FILTER_TYPE_ANON, true, true); + if (!src_filter) + kunit_skip(test, "src filter alloc fail"); + dst_filter = damos_new_filter(DAMOS_FILTER_TYPE_ACTIVE, false, false); + if (!dst_filter) { + damos_destroy_filter(src_filter); + kunit_skip(test, "dst filter alloc fail"); + } damos_commit_filter(dst_filter, src_filter); KUNIT_EXPECT_EQ(test, dst_filter->type, src_filter->type); KUNIT_EXPECT_EQ(test, dst_filter->matching, src_filter->matching); From 744e1bdd1471b7c914bf9fc06666f8960f149aad Mon Sep 17 00:00:00 2001 From: Macpaul Lin Date: Fri, 28 Nov 2025 12:17:22 +0800 Subject: [PATCH 1663/2333] pmdomain: mtk-pm-domains: Fix spinlock recursion fix in probe commit 305f254727bd379bbed0385afa0162f5bde1f51c upstream. Remove scpsys_get_legacy_regmap(), replacing its usage with of_find_node_with_property(). Explicitly call of_node_get(np) before each of_find_node_with_property() to maintain correct node reference counting. The of_find_node_with_property() function "consumes" its input by calling of_node_put() internally, whether or not it finds a match. Currently, dev->of_node (np) is passed multiple times in sequence without incrementing its reference count, causing it to be decremented multiple times and risking early memory release. Adding of_node_get(np) before each call balances the reference count, preventing premature node release. Fixes: c1bac49fe91f ("pmdomains: mtk-pm-domains: Fix spinlock recursion in probe") Cc: stable@vger.kernel.org Signed-off-by: Macpaul Lin Tested-by: Louis-Alexis Eyraud Signed-off-by: Ulf Hansson Signed-off-by: Greg Kroah-Hartman --- drivers/pmdomain/mediatek/mtk-pm-domains.c | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/drivers/pmdomain/mediatek/mtk-pm-domains.c b/drivers/pmdomain/mediatek/mtk-pm-domains.c index 9c9323c8c93a7..269634bcd9a40 100644 --- a/drivers/pmdomain/mediatek/mtk-pm-domains.c +++ b/drivers/pmdomain/mediatek/mtk-pm-domains.c @@ -748,18 +748,6 @@ static void scpsys_domain_cleanup(struct scpsys *scpsys) } } -static struct device_node *scpsys_get_legacy_regmap(struct device_node *np, const char *pn) -{ - struct device_node *local_node; - - for_each_child_of_node(np, local_node) { - if (of_property_present(local_node, pn)) - return local_node; - } - - return NULL; -} - static int scpsys_get_bus_protection_legacy(struct device *dev, struct scpsys *scpsys) { const u8 bp_blocks[3] = { @@ -781,7 +769,8 @@ static int scpsys_get_bus_protection_legacy(struct device *dev, struct scpsys *s * this makes it then possible to allocate the array of bus_prot * regmaps and convert all to the new style handling. */ - node = scpsys_get_legacy_regmap(np, "mediatek,infracfg"); + of_node_get(np); + node = of_find_node_with_property(np, "mediatek,infracfg"); if (node) { regmap[0] = syscon_regmap_lookup_by_phandle(node, "mediatek,infracfg"); of_node_put(node); @@ -794,7 +783,8 @@ static int scpsys_get_bus_protection_legacy(struct device *dev, struct scpsys *s regmap[0] = NULL; } - node = scpsys_get_legacy_regmap(np, "mediatek,smi"); + of_node_get(np); + node = of_find_node_with_property(np, "mediatek,smi"); if (node) { smi_np = of_parse_phandle(node, "mediatek,smi", 0); of_node_put(node); @@ -812,7 +802,8 @@ static int scpsys_get_bus_protection_legacy(struct device *dev, struct scpsys *s regmap[1] = NULL; } - node = scpsys_get_legacy_regmap(np, "mediatek,infracfg-nao"); + of_node_get(np); + node = of_find_node_with_property(np, "mediatek,infracfg-nao"); if (node) { regmap[2] = syscon_regmap_lookup_by_phandle(node, "mediatek,infracfg-nao"); num_regmaps++; From 87f09d9245f1e537a579a54d22a4661bebe72e5a Mon Sep 17 00:00:00 2001 From: Wentao Liang Date: Thu, 11 Dec 2025 04:02:52 +0000 Subject: [PATCH 1664/2333] pmdomain: imx: Fix reference count leak in imx_gpc_probe() commit 73cb5f6eafb0ac7aea8cdeb8ff12981aa741d8fb upstream. of_get_child_by_name() returns a node pointer with refcount incremented. Use the __free() attribute to manage the pgc_node reference, ensuring automatic of_node_put() cleanup when pgc_node goes out of scope. This eliminates the need for explicit error handling paths and avoids reference count leaks. Fixes: 721cabf6c660 ("soc: imx: move PGC handling to a new GPC driver") Cc: stable@vger.kernel.org Signed-off-by: Wentao Liang Reviewed-by: Frank Li Signed-off-by: Ulf Hansson Signed-off-by: Greg Kroah-Hartman --- drivers/pmdomain/imx/gpc.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/pmdomain/imx/gpc.c b/drivers/pmdomain/imx/gpc.c index a34b260274f7b..de695f1944ab3 100644 --- a/drivers/pmdomain/imx/gpc.c +++ b/drivers/pmdomain/imx/gpc.c @@ -402,13 +402,12 @@ static int imx_gpc_old_dt_init(struct device *dev, struct regmap *regmap, static int imx_gpc_probe(struct platform_device *pdev) { const struct imx_gpc_dt_data *of_id_data = device_get_match_data(&pdev->dev); - struct device_node *pgc_node; + struct device_node *pgc_node __free(device_node) + = of_get_child_by_name(pdev->dev.of_node, "pgc"); struct regmap *regmap; void __iomem *base; int ret; - pgc_node = of_get_child_by_name(pdev->dev.of_node, "pgc"); - /* bail out if DT too old and doesn't provide the necessary info */ if (!of_property_present(pdev->dev.of_node, "#power-domain-cells") && !pgc_node) From 089e50f29eeec8eef6ae1450fc88138d719291cb Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Thu, 18 Dec 2025 15:21:28 -0700 Subject: [PATCH 1665/2333] af_unix: don't post cmsg for SO_INQ unless explicitly asked for commit 4d1442979e4a53b9457ce1e373e187e1511ff688 upstream. A previous commit added SO_INQ support for AF_UNIX (SOCK_STREAM), but it posts a SCM_INQ cmsg even if just msg->msg_get_inq is set. This is incorrect, as ->msg_get_inq is just the caller asking for the remainder to be passed back in msg->msg_inq, it has nothing to do with cmsg. The original commit states that this is done to make sockets io_uring-friendly", but it's actually incorrect as io_uring doesn't use cmsg headers internally at all, and it's actively wrong as this means that cmsg's are always posted if someone does recvmsg via io_uring. Fix that up by only posting a cmsg if u->recvmsg_inq is set. Additionally, mirror how TCP handles inquiry handling in that it should only be done for a successful return. This makes the logic for the two identical. Cc: stable@vger.kernel.org Fixes: df30285b3670 ("af_unix: Introduce SO_INQ.") Reported-by: Julian Orth Link: https://github.com/axboe/liburing/issues/1509 Signed-off-by: Jens Axboe Reviewed-by: Willem de Bruijn Link: https://patch.msgid.link/07adc0c2-2c3b-4d08-8af1-1c466a40b6a8@kernel.dk Signed-off-by: Paolo Abeni Signed-off-by: Greg Kroah-Hartman --- net/unix/af_unix.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 833c3616d2a2b..f6f01f514933b 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -2929,6 +2929,7 @@ static int unix_stream_read_generic(struct unix_stream_read_state *state, unsigned int last_len; struct unix_sock *u; int copied = 0; + bool do_cmsg; int err = 0; long timeo; int target; @@ -2954,6 +2955,9 @@ static int unix_stream_read_generic(struct unix_stream_read_state *state, u = unix_sk(sk); + do_cmsg = READ_ONCE(u->recvmsg_inq); + if (do_cmsg) + msg->msg_get_inq = 1; redo: /* Lock the socket to prevent queue disordering * while sleeps in memcpy_tomsg @@ -3113,10 +3117,11 @@ static int unix_stream_read_generic(struct unix_stream_read_state *state, if (msg) { scm_recv_unix(sock, msg, &scm, flags); - if (READ_ONCE(u->recvmsg_inq) || msg->msg_get_inq) { + if (msg->msg_get_inq && (copied ?: err) >= 0) { msg->msg_inq = READ_ONCE(u->inq_len); - put_cmsg(msg, SOL_SOCKET, SCM_INQ, - sizeof(msg->msg_inq), &msg->msg_inq); + if (do_cmsg) + put_cmsg(msg, SOL_SOCKET, SCM_INQ, + sizeof(msg->msg_inq), &msg->msg_inq); } } else { scm_destroy(&scm); From 6cce897a37dc9813c7b70a7ebe4f5f14aa604c8d Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Fri, 18 Jul 2025 11:35:00 -0700 Subject: [PATCH 1666/2333] compiler_types.h: add "auto" as a macro for "__auto_type" commit 2fb6915fa22dc5524d704afba58a13305dd9f533 upstream. "auto" was defined as a keyword back in the K&R days, but as a storage type specifier. No one ever used it, since it was and is the default storage type for local variables. C++11 recycled the keyword to allow a type to be declared based on the type of an initializer. This was finally adopted into standard C in C23. gcc and clang provide the "__auto_type" alias keyword as an extension for pre-C23, however, there is no reason to pollute the bulk of the source base with this temporary keyword; instead define "auto" as a macro unless the compiler is running in C23+ mode. This macro is added in because that header is included in some of the tools headers, wheres is not as it has a bunch of very kernel-specific things in it. [ Cc: stable to reduce potential backporting burden. ] Signed-off-by: H. Peter Anvin (Intel) Acked-by: Miguel Ojeda Cc: Signed-off-by: Greg Kroah-Hartman --- include/linux/compiler_types.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/include/linux/compiler_types.h b/include/linux/compiler_types.h index 0a1b9598940d0..8128a445f0480 100644 --- a/include/linux/compiler_types.h +++ b/include/linux/compiler_types.h @@ -13,6 +13,19 @@ #ifndef __ASSEMBLY__ +/* + * C23 introduces "auto" as a standard way to define type-inferred + * variables, but "auto" has been a (useless) keyword even since K&R C, + * so it has always been "namespace reserved." + * + * Until at some future time we require C23 support, we need the gcc + * extension __auto_type, but there is no reason to put that elsewhere + * in the source code. + */ +#if __STDC_VERSION__ < 202311L +# define auto __auto_type +#endif + /* * Skipped when running bindgen due to a libclang issue; * see https://github.com/rust-lang/rust-bindgen/issues/2244. From 25f1ae942c097b7ae4ce5c2b9c6fefb8e3672b86 Mon Sep 17 00:00:00 2001 From: Paolo Abeni Date: Fri, 12 Dec 2025 13:54:03 +0100 Subject: [PATCH 1667/2333] mptcp: fallback earlier on simult connection commit 71154bbe49423128c1c8577b6576de1ed6836830 upstream. Syzkaller reports a simult-connect race leading to inconsistent fallback status: WARNING: CPU: 3 PID: 33 at net/mptcp/subflow.c:1515 subflow_data_ready+0x40b/0x7c0 net/mptcp/subflow.c:1515 Modules linked in: CPU: 3 UID: 0 PID: 33 Comm: ksoftirqd/3 Not tainted syzkaller #0 PREEMPT(full) Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2~bpo12+1 04/01/2014 RIP: 0010:subflow_data_ready+0x40b/0x7c0 net/mptcp/subflow.c:1515 Code: 89 ee e8 78 61 3c f6 40 84 ed 75 21 e8 8e 66 3c f6 44 89 fe bf 07 00 00 00 e8 c1 61 3c f6 41 83 ff 07 74 09 e8 76 66 3c f6 90 <0f> 0b 90 e8 6d 66 3c f6 48 89 df e8 e5 ad ff ff 31 ff 89 c5 89 c6 RSP: 0018:ffffc900006cf338 EFLAGS: 00010246 RAX: 0000000000000000 RBX: ffff888031acd100 RCX: ffffffff8b7f2abf RDX: ffff88801e6ea440 RSI: ffffffff8b7f2aca RDI: 0000000000000005 RBP: 0000000000000000 R08: 0000000000000005 R09: 0000000000000007 R10: 0000000000000004 R11: 0000000000002c10 R12: ffff88802ba69900 R13: 1ffff920000d9e67 R14: ffff888046f81800 R15: 0000000000000004 FS: 0000000000000000(0000) GS:ffff8880d69bc000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000560fc0ca1670 CR3: 0000000032c3a000 CR4: 0000000000352ef0 Call Trace: tcp_data_queue+0x13b0/0x4f90 net/ipv4/tcp_input.c:5197 tcp_rcv_state_process+0xfdf/0x4ec0 net/ipv4/tcp_input.c:6922 tcp_v6_do_rcv+0x492/0x1740 net/ipv6/tcp_ipv6.c:1672 tcp_v6_rcv+0x2976/0x41e0 net/ipv6/tcp_ipv6.c:1918 ip6_protocol_deliver_rcu+0x188/0x1520 net/ipv6/ip6_input.c:438 ip6_input_finish+0x1e4/0x4b0 net/ipv6/ip6_input.c:489 NF_HOOK include/linux/netfilter.h:318 [inline] NF_HOOK include/linux/netfilter.h:312 [inline] ip6_input+0x105/0x2f0 net/ipv6/ip6_input.c:500 dst_input include/net/dst.h:471 [inline] ip6_rcv_finish net/ipv6/ip6_input.c:79 [inline] NF_HOOK include/linux/netfilter.h:318 [inline] NF_HOOK include/linux/netfilter.h:312 [inline] ipv6_rcv+0x264/0x650 net/ipv6/ip6_input.c:311 __netif_receive_skb_one_core+0x12d/0x1e0 net/core/dev.c:5979 __netif_receive_skb+0x1d/0x160 net/core/dev.c:6092 process_backlog+0x442/0x15e0 net/core/dev.c:6444 __napi_poll.constprop.0+0xba/0x550 net/core/dev.c:7494 napi_poll net/core/dev.c:7557 [inline] net_rx_action+0xa9f/0xfe0 net/core/dev.c:7684 handle_softirqs+0x216/0x8e0 kernel/softirq.c:579 run_ksoftirqd kernel/softirq.c:968 [inline] run_ksoftirqd+0x3a/0x60 kernel/softirq.c:960 smpboot_thread_fn+0x3f7/0xae0 kernel/smpboot.c:160 kthread+0x3c2/0x780 kernel/kthread.c:463 ret_from_fork+0x5d7/0x6f0 arch/x86/kernel/process.c:148 ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245 The TCP subflow can process the simult-connect syn-ack packet after transitioning to TCP_FIN1 state, bypassing the MPTCP fallback check, as the sk_state_change() callback is not invoked for * -> FIN_WAIT1 transitions. That will move the msk socket to an inconsistent status and the next incoming data will hit the reported splat. Close the race moving the simult-fallback check at the earliest possible stage - that is at syn-ack generation time. About the fixes tags: [2] was supposed to also fix this issue introduced by [3]. [1] is required as a dependence: it was not explicitly marked as a fix, but it is one and it has already been backported before [3]. In other words, this commit should be backported up to [3], including [2] and [1] if that's not already there. Fixes: 23e89e8ee7be ("tcp: Don't drop SYN+ACK for simultaneous connect().") [1] Fixes: 4fd19a307016 ("mptcp: fix inconsistent state on fastopen race") [2] Fixes: 1e777f39b4d7 ("mptcp: add MSG_FASTOPEN sendmsg flag support") [3] Cc: stable@vger.kernel.org Reported-by: syzbot+0ff6b771b4f7a5bce83b@syzkaller.appspotmail.com Closes: https://github.com/multipath-tcp/mptcp_net-next/issues/586 Signed-off-by: Paolo Abeni Reviewed-by: Matthieu Baerts (NGI0) Signed-off-by: Matthieu Baerts (NGI0) Link: https://patch.msgid.link/20251212-net-mptcp-subflow_data_ready-warn-v1-1-d1f9fd1c36c8@kernel.org Signed-off-by: Paolo Abeni Signed-off-by: Greg Kroah-Hartman --- net/mptcp/options.c | 10 ++++++++++ net/mptcp/protocol.h | 6 ++---- net/mptcp/subflow.c | 6 ------ 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/net/mptcp/options.c b/net/mptcp/options.c index f24ae7d40e883..43df4293f58bf 100644 --- a/net/mptcp/options.c +++ b/net/mptcp/options.c @@ -408,6 +408,16 @@ bool mptcp_syn_options(struct sock *sk, const struct sk_buff *skb, */ subflow->snd_isn = TCP_SKB_CB(skb)->end_seq; if (subflow->request_mptcp) { + if (unlikely(subflow_simultaneous_connect(sk))) { + WARN_ON_ONCE(!mptcp_try_fallback(sk, MPTCP_MIB_SIMULTCONNFALLBACK)); + + /* Ensure mptcp_finish_connect() will not process the + * MPC handshake. + */ + subflow->request_mptcp = 0; + return false; + } + opts->suboptions = OPTION_MPTCP_MPC_SYN; opts->csum_reqd = mptcp_is_checksum_enabled(sock_net(sk)); opts->allow_join_id0 = mptcp_allow_join_id0(sock_net(sk)); diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index 6ca97096607c3..0e8b0a650108c 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -1293,10 +1293,8 @@ static inline bool subflow_simultaneous_connect(struct sock *sk) { struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk); - return (1 << sk->sk_state) & - (TCPF_ESTABLISHED | TCPF_FIN_WAIT1 | TCPF_FIN_WAIT2 | TCPF_CLOSING) && - is_active_ssk(subflow) && - !subflow->conn_finished; + /* Note that the sk state implies !subflow->conn_finished. */ + return sk->sk_state == TCP_SYN_RECV && is_active_ssk(subflow); } #ifdef CONFIG_SYN_COOKIES diff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c index af707ce0f6244..a8c281bc53778 100644 --- a/net/mptcp/subflow.c +++ b/net/mptcp/subflow.c @@ -1856,12 +1856,6 @@ static void subflow_state_change(struct sock *sk) __subflow_state_change(sk); - if (subflow_simultaneous_connect(sk)) { - WARN_ON_ONCE(!mptcp_try_fallback(sk, MPTCP_MIB_SIMULTCONNFALLBACK)); - subflow->conn_finished = 1; - mptcp_propagate_state(parent, sk, subflow, NULL); - } - /* as recvmsg() does not acquire the subflow socket for ssk selection * a fin packet carrying a DSS can be unnoticed if we don't trigger * the data available machinery here. From 234ede2960d56a9f772b2612ec1414176b592b6b Mon Sep 17 00:00:00 2001 From: Jiayuan Chen Date: Thu, 4 Dec 2025 18:59:55 +0000 Subject: [PATCH 1668/2333] mm/kasan: fix incorrect unpoisoning in vrealloc for KASAN commit 007f5da43b3d0ecff972e2616062b8da1f862f5e upstream. Patch series "kasan: vmalloc: Fixes for the percpu allocator and vrealloc", v3. Patches fix two issues related to KASAN and vmalloc. The first one, a KASAN tag mismatch, possibly resulting in a kernel panic, can be observed on systems with a tag-based KASAN enabled and with multiple NUMA nodes. Initially it was only noticed on x86 [1] but later a similar issue was also reported on arm64 [2]. Specifically the problem is related to how vm_structs interact with pcpu_chunks - both when they are allocated, assigned and when pcpu_chunk addresses are derived. When vm_structs are allocated they are unpoisoned, each with a different random tag, if vmalloc support is enabled along the KASAN mode. Later when first pcpu chunk is allocated it gets its 'base_addr' field set to the first allocated vm_struct. With that it inherits that vm_struct's tag. When pcpu_chunk addresses are later derived (by pcpu_chunk_addr(), for example in pcpu_alloc_noprof()) the base_addr field is used and offsets are added to it. If the initial conditions are satisfied then some of the offsets will point into memory allocated with a different vm_struct. So while the lower bits will get accurately derived the tag bits in the top of the pointer won't match the shadow memory contents. The solution (proposed at v2 of the x86 KASAN series [3]) is to unpoison the vm_structs with the same tag when allocating them for the per cpu allocator (in pcpu_get_vm_areas()). The second one reported by syzkaller [4] is related to vrealloc and happens because of random tag generation when unpoisoning memory without allocating new pages. This breaks shadow memory tracking and needs to reuse the existing tag instead of generating a new one. At the same time an inconsistency in used flags is corrected. This patch (of 3): Syzkaller reported a memory out-of-bounds bug [4]. This patch fixes two issues: 1. In vrealloc the KASAN_VMALLOC_VM_ALLOC flag is missing when unpoisoning the extended region. This flag is required to correctly associate the allocation with KASAN's vmalloc tracking. Note: In contrast, vzalloc (via __vmalloc_node_range_noprof) explicitly sets KASAN_VMALLOC_VM_ALLOC and calls kasan_unpoison_vmalloc() with it. vrealloc must behave consistently -- especially when reusing existing vmalloc regions -- to ensure KASAN can track allocations correctly. 2. When vrealloc reuses an existing vmalloc region (without allocating new pages) KASAN generates a new tag, which breaks tag-based memory access tracking. Introduce KASAN_VMALLOC_KEEP_TAG, a new KASAN flag that allows reusing the tag already attached to the pointer, ensuring consistent tag behavior during reallocation. Pass KASAN_VMALLOC_KEEP_TAG and KASAN_VMALLOC_VM_ALLOC to the kasan_unpoison_vmalloc inside vrealloc_node_align_noprof(). Link: https://lkml.kernel.org/r/cover.1765978969.git.m.wieczorretman@pm.me Link: https://lkml.kernel.org/r/38dece0a4074c43e48150d1e242f8242c73bf1a5.1764874575.git.m.wieczorretman@pm.me Link: https://lore.kernel.org/all/e7e04692866d02e6d3b32bb43b998e5d17092ba4.1738686764.git.maciej.wieczor-retman@intel.com/ [1] Link: https://lore.kernel.org/all/aMUrW1Znp1GEj7St@MiWiFi-R3L-srv/ [2] Link: https://lore.kernel.org/all/CAPAsAGxDRv_uFeMYu9TwhBVWHCCtkSxoWY4xmFB_vowMbi8raw@mail.gmail.com/ [3] Link: https://syzkaller.appspot.com/bug?extid=997752115a851cb0cf36 [4] Fixes: a0309faf1cb0 ("mm: vmalloc: support more granular vrealloc() sizing") Signed-off-by: Jiayuan Chen Co-developed-by: Maciej Wieczor-Retman Signed-off-by: Maciej Wieczor-Retman Reported-by: syzbot+997752115a851cb0cf36@syzkaller.appspotmail.com Closes: https://lore.kernel.org/all/68e243a2.050a0220.1696c6.007d.GAE@google.com/T/ Reviewed-by: Andrey Konovalov Cc: Alexander Potapenko Cc: Andrey Ryabinin Cc: Danilo Krummrich Cc: Dmitriy Vyukov Cc: Kees Cook Cc: Marco Elver Cc: "Uladzislau Rezki (Sony)" Cc: Vincenzo Frascino Cc: Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- include/linux/kasan.h | 1 + mm/kasan/hw_tags.c | 2 +- mm/kasan/shadow.c | 4 +++- mm/vmalloc.c | 4 +++- 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/include/linux/kasan.h b/include/linux/kasan.h index d12e1a5f5a9af..6d7972bb390ca 100644 --- a/include/linux/kasan.h +++ b/include/linux/kasan.h @@ -28,6 +28,7 @@ typedef unsigned int __bitwise kasan_vmalloc_flags_t; #define KASAN_VMALLOC_INIT ((__force kasan_vmalloc_flags_t)0x01u) #define KASAN_VMALLOC_VM_ALLOC ((__force kasan_vmalloc_flags_t)0x02u) #define KASAN_VMALLOC_PROT_NORMAL ((__force kasan_vmalloc_flags_t)0x04u) +#define KASAN_VMALLOC_KEEP_TAG ((__force kasan_vmalloc_flags_t)0x08u) #define KASAN_VMALLOC_PAGE_RANGE 0x1 /* Apply exsiting page range */ #define KASAN_VMALLOC_TLB_FLUSH 0x2 /* TLB flush */ diff --git a/mm/kasan/hw_tags.c b/mm/kasan/hw_tags.c index 1c373cc4b3fa5..cbef5e450954e 100644 --- a/mm/kasan/hw_tags.c +++ b/mm/kasan/hw_tags.c @@ -361,7 +361,7 @@ void *__kasan_unpoison_vmalloc(const void *start, unsigned long size, return (void *)start; } - tag = kasan_random_tag(); + tag = (flags & KASAN_VMALLOC_KEEP_TAG) ? get_tag(start) : kasan_random_tag(); start = set_tag(start, tag); /* Unpoison and initialize memory up to size. */ diff --git a/mm/kasan/shadow.c b/mm/kasan/shadow.c index 5d2a876035d65..5e47ae7fdd590 100644 --- a/mm/kasan/shadow.c +++ b/mm/kasan/shadow.c @@ -648,7 +648,9 @@ void *__kasan_unpoison_vmalloc(const void *start, unsigned long size, !(flags & KASAN_VMALLOC_PROT_NORMAL)) return (void *)start; - start = set_tag(start, kasan_random_tag()); + if (unlikely(!(flags & KASAN_VMALLOC_KEEP_TAG))) + start = set_tag(start, kasan_random_tag()); + kasan_unpoison(start, size, false); return (void *)start; } diff --git a/mm/vmalloc.c b/mm/vmalloc.c index 798b2ed21e460..22a73a087135b 100644 --- a/mm/vmalloc.c +++ b/mm/vmalloc.c @@ -4176,7 +4176,9 @@ void *vrealloc_node_align_noprof(const void *p, size_t size, unsigned long align */ if (size <= alloced_size) { kasan_unpoison_vmalloc(p + old_size, size - old_size, - KASAN_VMALLOC_PROT_NORMAL); + KASAN_VMALLOC_PROT_NORMAL | + KASAN_VMALLOC_VM_ALLOC | + KASAN_VMALLOC_KEEP_TAG); /* * No need to zero memory here, as unused memory will have * already been zeroed at initial allocation time or during From 9548f154f79cefdf3fba9601c92e2237d4f88091 Mon Sep 17 00:00:00 2001 From: Maciej Wieczor-Retman Date: Thu, 4 Dec 2025 19:00:04 +0000 Subject: [PATCH 1669/2333] kasan: refactor pcpu kasan vmalloc unpoison commit 6f13db031e27e88213381039032a9cc061578ea6 upstream. A KASAN tag mismatch, possibly causing a kernel panic, can be observed on systems with a tag-based KASAN enabled and with multiple NUMA nodes. It was reported on arm64 and reproduced on x86. It can be explained in the following points: 1. There can be more than one virtual memory chunk. 2. Chunk's base address has a tag. 3. The base address points at the first chunk and thus inherits the tag of the first chunk. 4. The subsequent chunks will be accessed with the tag from the first chunk. 5. Thus, the subsequent chunks need to have their tag set to match that of the first chunk. Refactor code by reusing __kasan_unpoison_vmalloc in a new helper in preparation for the actual fix. Link: https://lkml.kernel.org/r/eb61d93b907e262eefcaa130261a08bcb6c5ce51.1764874575.git.m.wieczorretman@pm.me Fixes: 1d96320f8d53 ("kasan, vmalloc: add vmalloc tagging for SW_TAGS") Signed-off-by: Maciej Wieczor-Retman Reviewed-by: Andrey Konovalov Cc: Alexander Potapenko Cc: Andrey Ryabinin Cc: Danilo Krummrich Cc: Dmitriy Vyukov Cc: Jiayuan Chen Cc: Kees Cook Cc: Marco Elver Cc: "Uladzislau Rezki (Sony)" Cc: Vincenzo Frascino Cc: [6.1+] Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- include/linux/kasan.h | 15 +++++++++++++++ mm/kasan/common.c | 17 +++++++++++++++++ mm/vmalloc.c | 4 +--- 3 files changed, 33 insertions(+), 3 deletions(-) diff --git a/include/linux/kasan.h b/include/linux/kasan.h index 6d7972bb390ca..cde493cb7702d 100644 --- a/include/linux/kasan.h +++ b/include/linux/kasan.h @@ -615,6 +615,16 @@ static __always_inline void kasan_poison_vmalloc(const void *start, __kasan_poison_vmalloc(start, size); } +void __kasan_unpoison_vmap_areas(struct vm_struct **vms, int nr_vms, + kasan_vmalloc_flags_t flags); +static __always_inline void +kasan_unpoison_vmap_areas(struct vm_struct **vms, int nr_vms, + kasan_vmalloc_flags_t flags) +{ + if (kasan_enabled()) + __kasan_unpoison_vmap_areas(vms, nr_vms, flags); +} + #else /* CONFIG_KASAN_VMALLOC */ static inline void kasan_populate_early_vm_area_shadow(void *start, @@ -639,6 +649,11 @@ static inline void *kasan_unpoison_vmalloc(const void *start, static inline void kasan_poison_vmalloc(const void *start, unsigned long size) { } +static __always_inline void +kasan_unpoison_vmap_areas(struct vm_struct **vms, int nr_vms, + kasan_vmalloc_flags_t flags) +{ } + #endif /* CONFIG_KASAN_VMALLOC */ #if (defined(CONFIG_KASAN_GENERIC) || defined(CONFIG_KASAN_SW_TAGS)) && \ diff --git a/mm/kasan/common.c b/mm/kasan/common.c index d4c14359feaf9..1ed6289d471aa 100644 --- a/mm/kasan/common.c +++ b/mm/kasan/common.c @@ -28,6 +28,7 @@ #include #include #include +#include #include "kasan.h" #include "../slab.h" @@ -582,3 +583,19 @@ bool __kasan_check_byte(const void *address, unsigned long ip) } return true; } + +#ifdef CONFIG_KASAN_VMALLOC +void __kasan_unpoison_vmap_areas(struct vm_struct **vms, int nr_vms, + kasan_vmalloc_flags_t flags) +{ + unsigned long size; + void *addr; + int area; + + for (area = 0 ; area < nr_vms ; area++) { + size = vms[area]->size; + addr = vms[area]->addr; + vms[area]->addr = __kasan_unpoison_vmalloc(addr, size, flags); + } +} +#endif diff --git a/mm/vmalloc.c b/mm/vmalloc.c index 22a73a087135b..33e705ccafbaa 100644 --- a/mm/vmalloc.c +++ b/mm/vmalloc.c @@ -4872,9 +4872,7 @@ struct vm_struct **pcpu_get_vm_areas(const unsigned long *offsets, * With hardware tag-based KASAN, marking is skipped for * non-VM_ALLOC mappings, see __kasan_unpoison_vmalloc(). */ - for (area = 0; area < nr_vms; area++) - vms[area]->addr = kasan_unpoison_vmalloc(vms[area]->addr, - vms[area]->size, KASAN_VMALLOC_PROT_NORMAL); + kasan_unpoison_vmap_areas(vms, nr_vms, KASAN_VMALLOC_PROT_NORMAL); kfree(vas); return vms; From d16a38f3d908b75c5c20c93b8ae9d831cc73a4c9 Mon Sep 17 00:00:00 2001 From: Maciej Wieczor-Retman Date: Thu, 4 Dec 2025 19:00:11 +0000 Subject: [PATCH 1670/2333] kasan: unpoison vms[area] addresses with a common tag commit 6a0e5b333842cf65d6f4e4f0a2a4386504802515 upstream. A KASAN tag mismatch, possibly causing a kernel panic, can be observed on systems with a tag-based KASAN enabled and with multiple NUMA nodes. It was reported on arm64 and reproduced on x86. It can be explained in the following points: 1. There can be more than one virtual memory chunk. 2. Chunk's base address has a tag. 3. The base address points at the first chunk and thus inherits the tag of the first chunk. 4. The subsequent chunks will be accessed with the tag from the first chunk. 5. Thus, the subsequent chunks need to have their tag set to match that of the first chunk. Use the new vmalloc flag that disables random tag assignment in __kasan_unpoison_vmalloc() - pass the same random tag to all the vm_structs by tagging the pointers before they go inside __kasan_unpoison_vmalloc(). Assigning a common tag resolves the pcpu chunk address mismatch. [akpm@linux-foundation.org: use WARN_ON_ONCE(), per Andrey] Link: https://lkml.kernel.org/r/CA+fCnZeuGdKSEm11oGT6FS71_vGq1vjq-xY36kxVdFvwmag2ZQ@mail.gmail.com [maciej.wieczor-retman@intel.com: remove unneeded pr_warn()] Link: https://lkml.kernel.org/r/919897daaaa3c982a27762a2ee038769ad033991.1764945396.git.m.wieczorretman@pm.me Link: https://lkml.kernel.org/r/873821114a9f722ffb5d6702b94782e902883fdf.1764874575.git.m.wieczorretman@pm.me Fixes: 1d96320f8d53 ("kasan, vmalloc: add vmalloc tagging for SW_TAGS") Signed-off-by: Maciej Wieczor-Retman Reviewed-by: Andrey Konovalov Cc: Alexander Potapenko Cc: Andrey Ryabinin Cc: Danilo Krummrich Cc: Dmitriy Vyukov Cc: Jiayuan Chen Cc: Kees Cook Cc: Marco Elver Cc: "Uladzislau Rezki (Sony)" Cc: Vincenzo Frascino Cc: [6.1+] Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- mm/kasan/common.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/mm/kasan/common.c b/mm/kasan/common.c index 1ed6289d471aa..589be3d867357 100644 --- a/mm/kasan/common.c +++ b/mm/kasan/common.c @@ -591,11 +591,26 @@ void __kasan_unpoison_vmap_areas(struct vm_struct **vms, int nr_vms, unsigned long size; void *addr; int area; + u8 tag; + + /* + * If KASAN_VMALLOC_KEEP_TAG was set at this point, all vms[] pointers + * would be unpoisoned with the KASAN_TAG_KERNEL which would disable + * KASAN checks down the line. + */ + if (WARN_ON_ONCE(flags & KASAN_VMALLOC_KEEP_TAG)) + return; + + size = vms[0]->size; + addr = vms[0]->addr; + vms[0]->addr = __kasan_unpoison_vmalloc(addr, size, flags); + tag = get_tag(vms[0]->addr); - for (area = 0 ; area < nr_vms ; area++) { + for (area = 1 ; area < nr_vms ; area++) { size = vms[area]->size; - addr = vms[area]->addr; - vms[area]->addr = __kasan_unpoison_vmalloc(addr, size, flags); + addr = set_tag(vms[area]->addr, tag); + vms[area]->addr = + __kasan_unpoison_vmalloc(addr, size, flags | KASAN_VMALLOC_KEEP_TAG); } } #endif From 282ac3cf9bc79c75fd3196be2caba06e033e403d Mon Sep 17 00:00:00 2001 From: Pingfan Liu Date: Tue, 16 Dec 2025 09:48:51 +0800 Subject: [PATCH 1671/2333] kernel/kexec: change the prototype of kimage_map_segment() commit fe55ea85939efcbf0e6baa234f0d70acb79e7b58 upstream. The kexec segment index will be required to extract the corresponding information for that segment in kimage_map_segment(). Additionally, kexec_segment already holds the kexec relocation destination address and size. Therefore, the prototype of kimage_map_segment() can be changed. Link: https://lkml.kernel.org/r/20251216014852.8737-1-piliu@redhat.com Fixes: 07d24902977e ("kexec: enable CMA based contiguous allocation") Signed-off-by: Pingfan Liu Acked-by: Baoquan He Cc: Mimi Zohar Cc: Roberto Sassu Cc: Alexander Graf Cc: Steven Chen Cc: Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- include/linux/kexec.h | 4 ++-- kernel/kexec_core.c | 9 ++++++--- security/integrity/ima/ima_kexec.c | 4 +--- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/include/linux/kexec.h b/include/linux/kexec.h index ff7e231b0485a..8a22bc9b8c6c8 100644 --- a/include/linux/kexec.h +++ b/include/linux/kexec.h @@ -530,7 +530,7 @@ extern bool kexec_file_dbg_print; #define kexec_dprintk(fmt, arg...) \ do { if (kexec_file_dbg_print) pr_info(fmt, ##arg); } while (0) -extern void *kimage_map_segment(struct kimage *image, unsigned long addr, unsigned long size); +extern void *kimage_map_segment(struct kimage *image, int idx); extern void kimage_unmap_segment(void *buffer); #else /* !CONFIG_KEXEC_CORE */ struct pt_regs; @@ -540,7 +540,7 @@ static inline void __crash_kexec(struct pt_regs *regs) { } static inline void crash_kexec(struct pt_regs *regs) { } static inline int kexec_should_crash(struct task_struct *p) { return 0; } static inline int kexec_crash_loaded(void) { return 0; } -static inline void *kimage_map_segment(struct kimage *image, unsigned long addr, unsigned long size) +static inline void *kimage_map_segment(struct kimage *image, int idx) { return NULL; } static inline void kimage_unmap_segment(void *buffer) { } #define kexec_in_progress false diff --git a/kernel/kexec_core.c b/kernel/kexec_core.c index fa00b239c5d9a..9a1966207041c 100644 --- a/kernel/kexec_core.c +++ b/kernel/kexec_core.c @@ -960,17 +960,20 @@ int kimage_load_segment(struct kimage *image, int idx) return result; } -void *kimage_map_segment(struct kimage *image, - unsigned long addr, unsigned long size) +void *kimage_map_segment(struct kimage *image, int idx) { + unsigned long addr, size, eaddr; unsigned long src_page_addr, dest_page_addr = 0; - unsigned long eaddr = addr + size; kimage_entry_t *ptr, entry; struct page **src_pages; unsigned int npages; void *vaddr = NULL; int i; + addr = image->segment[idx].mem; + size = image->segment[idx].memsz; + eaddr = addr + size; + /* * Collect the source pages and map them in a contiguous VA range. */ diff --git a/security/integrity/ima/ima_kexec.c b/security/integrity/ima/ima_kexec.c index 7362f68f2d8b1..5beb69edd12fd 100644 --- a/security/integrity/ima/ima_kexec.c +++ b/security/integrity/ima/ima_kexec.c @@ -250,9 +250,7 @@ void ima_kexec_post_load(struct kimage *image) if (!image->ima_buffer_addr) return; - ima_kexec_buffer = kimage_map_segment(image, - image->ima_buffer_addr, - image->ima_buffer_size); + ima_kexec_buffer = kimage_map_segment(image, image->ima_segment_index); if (!ima_kexec_buffer) { pr_err("Could not map measurements buffer.\n"); return; From a843e4155c83211c55b1b6cc17eab27a6a2c5b6f Mon Sep 17 00:00:00 2001 From: Pingfan Liu Date: Tue, 16 Dec 2025 09:48:52 +0800 Subject: [PATCH 1672/2333] kernel/kexec: fix IMA when allocation happens in CMA area commit a3785ae5d334bb71d47a593d54c686a03fb9d136 upstream. *** Bug description *** When I tested kexec with the latest kernel, I ran into the following warning: [ 40.712410] ------------[ cut here ]------------ [ 40.712576] WARNING: CPU: 2 PID: 1562 at kernel/kexec_core.c:1001 kimage_map_segment+0x144/0x198 [...] [ 40.816047] Call trace: [ 40.818498] kimage_map_segment+0x144/0x198 (P) [ 40.823221] ima_kexec_post_load+0x58/0xc0 [ 40.827246] __do_sys_kexec_file_load+0x29c/0x368 [...] [ 40.855423] ---[ end trace 0000000000000000 ]--- *** How to reproduce *** This bug is only triggered when the kexec target address is allocated in the CMA area. If no CMA area is reserved in the kernel, use the "cma=" option in the kernel command line to reserve one. *** Root cause *** The commit 07d24902977e ("kexec: enable CMA based contiguous allocation") allocates the kexec target address directly on the CMA area to avoid copying during the jump. In this case, there is no IND_SOURCE for the kexec segment. But the current implementation of kimage_map_segment() assumes that IND_SOURCE pages exist and map them into a contiguous virtual address by vmap(). *** Solution *** If IMA segment is allocated in the CMA area, use its page_address() directly. Link: https://lkml.kernel.org/r/20251216014852.8737-2-piliu@redhat.com Fixes: 07d24902977e ("kexec: enable CMA based contiguous allocation") Signed-off-by: Pingfan Liu Acked-by: Baoquan He Cc: Alexander Graf Cc: Steven Chen Cc: Mimi Zohar Cc: Roberto Sassu Cc: Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- kernel/kexec_core.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/kernel/kexec_core.c b/kernel/kexec_core.c index 9a1966207041c..08ae3c64caca5 100644 --- a/kernel/kexec_core.c +++ b/kernel/kexec_core.c @@ -967,13 +967,17 @@ void *kimage_map_segment(struct kimage *image, int idx) kimage_entry_t *ptr, entry; struct page **src_pages; unsigned int npages; + struct page *cma; void *vaddr = NULL; int i; + cma = image->segment_cma[idx]; + if (cma) + return page_address(cma); + addr = image->segment[idx].mem; size = image->segment[idx].memsz; eaddr = addr + size; - /* * Collect the source pages and map them in a contiguous VA range. */ @@ -1014,7 +1018,8 @@ void *kimage_map_segment(struct kimage *image, int idx) void kimage_unmap_segment(void *segment_buffer) { - vunmap(segment_buffer); + if (is_vmalloc_addr(segment_buffer)) + vunmap(segment_buffer); } struct kexec_load_limit { From 7da6f40d2662a222dac6bf3ff457d7a4b9d487a3 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Sat, 22 Nov 2025 12:00:36 +1100 Subject: [PATCH 1673/2333] lockd: fix vfs_test_lock() calls commit a49a2a1baa0c553c3548a1c414b6a3c005a8deba upstream. Usage of vfs_test_lock() is somewhat confused. Documentation suggests it is given a "lock" but this is not the case. It is given a struct file_lock which contains some details of the sort of lock it should be looking for. In particular passing a "file_lock" containing fl_lmops or fl_ops is meaningless and possibly confusing. This is particularly problematic in lockd. nlmsvc_testlock() receives an initialised "file_lock" from xdr-decode, including manager ops and an owner. It then mistakenly passes this to vfs_test_lock() which might replace the owner and the ops. This can lead to confusion when freeing the lock. The primary role of the 'struct file_lock' passed to vfs_test_lock() is to report a conflicting lock that was found, so it makes more sense for nlmsvc_testlock() to pass "conflock", which it uses for returning the conflicting lock. With this change, freeing of the lock is not confused and code in __nlm4svc_proc_test() and __nlmsvc_proc_test() can be simplified. Documentation for vfs_test_lock() is improved to reflect its real purpose, and a WARN_ON_ONCE() is added to avoid a similar problem in the future. Reported-by: Olga Kornievskaia Closes: https://lore.kernel.org/all/20251021130506.45065-1-okorniev@redhat.com Signed-off-by: NeilBrown Fixes: 20fa19027286 ("nfs: add export operations") Cc: stable@vger.kernel.org Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever Signed-off-by: Greg Kroah-Hartman --- fs/lockd/svc4proc.c | 4 +--- fs/lockd/svclock.c | 21 ++++++++++++--------- fs/lockd/svcproc.c | 5 +---- fs/locks.c | 12 ++++++++++-- 4 files changed, 24 insertions(+), 18 deletions(-) diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c index 109e5caae8c70..4b6f18d977343 100644 --- a/fs/lockd/svc4proc.c +++ b/fs/lockd/svc4proc.c @@ -97,7 +97,6 @@ __nlm4svc_proc_test(struct svc_rqst *rqstp, struct nlm_res *resp) struct nlm_args *argp = rqstp->rq_argp; struct nlm_host *host; struct nlm_file *file; - struct nlm_lockowner *test_owner; __be32 rc = rpc_success; dprintk("lockd: TEST4 called\n"); @@ -107,7 +106,6 @@ __nlm4svc_proc_test(struct svc_rqst *rqstp, struct nlm_res *resp) if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file))) return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success; - test_owner = argp->lock.fl.c.flc_owner; /* Now check for conflicting locks */ resp->status = nlmsvc_testlock(rqstp, file, host, &argp->lock, &resp->lock); @@ -116,7 +114,7 @@ __nlm4svc_proc_test(struct svc_rqst *rqstp, struct nlm_res *resp) else dprintk("lockd: TEST4 status %d\n", ntohl(resp->status)); - nlmsvc_put_lockowner(test_owner); + nlmsvc_release_lockowner(&argp->lock); nlmsvc_release_host(host); nlm_release_file(file); return rc; diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c index a31dc9588eb80..d66e828515999 100644 --- a/fs/lockd/svclock.c +++ b/fs/lockd/svclock.c @@ -627,7 +627,13 @@ nlmsvc_testlock(struct svc_rqst *rqstp, struct nlm_file *file, } mode = lock_to_openmode(&lock->fl); - error = vfs_test_lock(file->f_file[mode], &lock->fl); + locks_init_lock(&conflock->fl); + /* vfs_test_lock only uses start, end, and owner, but tests flc_file */ + conflock->fl.c.flc_file = lock->fl.c.flc_file; + conflock->fl.fl_start = lock->fl.fl_start; + conflock->fl.fl_end = lock->fl.fl_end; + conflock->fl.c.flc_owner = lock->fl.c.flc_owner; + error = vfs_test_lock(file->f_file[mode], &conflock->fl); if (error) { /* We can't currently deal with deferred test requests */ if (error == FILE_LOCK_DEFERRED) @@ -637,22 +643,19 @@ nlmsvc_testlock(struct svc_rqst *rqstp, struct nlm_file *file, goto out; } - if (lock->fl.c.flc_type == F_UNLCK) { + if (conflock->fl.c.flc_type == F_UNLCK) { ret = nlm_granted; goto out; } dprintk("lockd: conflicting lock(ty=%d, %Ld-%Ld)\n", - lock->fl.c.flc_type, (long long)lock->fl.fl_start, - (long long)lock->fl.fl_end); + conflock->fl.c.flc_type, (long long)conflock->fl.fl_start, + (long long)conflock->fl.fl_end); conflock->caller = "somehost"; /* FIXME */ conflock->len = strlen(conflock->caller); conflock->oh.len = 0; /* don't return OH info */ - conflock->svid = lock->fl.c.flc_pid; - conflock->fl.c.flc_type = lock->fl.c.flc_type; - conflock->fl.fl_start = lock->fl.fl_start; - conflock->fl.fl_end = lock->fl.fl_end; - locks_release_private(&lock->fl); + conflock->svid = conflock->fl.c.flc_pid; + locks_release_private(&conflock->fl); ret = nlm_lck_denied; out: diff --git a/fs/lockd/svcproc.c b/fs/lockd/svcproc.c index f53d5177f2673..5817ef272332d 100644 --- a/fs/lockd/svcproc.c +++ b/fs/lockd/svcproc.c @@ -117,7 +117,6 @@ __nlmsvc_proc_test(struct svc_rqst *rqstp, struct nlm_res *resp) struct nlm_args *argp = rqstp->rq_argp; struct nlm_host *host; struct nlm_file *file; - struct nlm_lockowner *test_owner; __be32 rc = rpc_success; dprintk("lockd: TEST called\n"); @@ -127,8 +126,6 @@ __nlmsvc_proc_test(struct svc_rqst *rqstp, struct nlm_res *resp) if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file))) return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success; - test_owner = argp->lock.fl.c.flc_owner; - /* Now check for conflicting locks */ resp->status = cast_status(nlmsvc_testlock(rqstp, file, host, &argp->lock, &resp->lock)); @@ -138,7 +135,7 @@ __nlmsvc_proc_test(struct svc_rqst *rqstp, struct nlm_res *resp) dprintk("lockd: TEST status %d vers %d\n", ntohl(resp->status), rqstp->rq_vers); - nlmsvc_put_lockowner(test_owner); + nlmsvc_release_lockowner(&argp->lock); nlmsvc_release_host(host); nlm_release_file(file); return rc; diff --git a/fs/locks.c b/fs/locks.c index 04a3f0e207246..bf5e0d05a0269 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -2185,13 +2185,21 @@ SYSCALL_DEFINE2(flock, unsigned int, fd, unsigned int, cmd) /** * vfs_test_lock - test file byte range lock * @filp: The file to test lock for - * @fl: The lock to test; also used to hold result + * @fl: The byte-range in the file to test; also used to hold result * + * On entry, @fl does not contain a lock, but identifies a range (fl_start, fl_end) + * in the file (c.flc_file), and an owner (c.flc_owner) for whom existing locks + * should be ignored. c.flc_type and c.flc_flags are ignored. + * Both fl_lmops and fl_ops in @fl must be NULL. * Returns -ERRNO on failure. Indicates presence of conflicting lock by - * setting conf->fl_type to something other than F_UNLCK. + * setting fl->fl_type to something other than F_UNLCK. + * + * If vfs_test_lock() does find a lock and return it, the caller must + * use locks_free_lock() or locks_release_private() on the returned lock. */ int vfs_test_lock(struct file *filp, struct file_lock *fl) { + WARN_ON_ONCE(fl->fl_ops || fl->fl_lmops); WARN_ON_ONCE(filp != fl->c.flc_file); if (filp->f_op->lock) return filp->f_op->lock(filp, F_GETLK, fl); From fcbe159c90603b0ffb9c214b002edc3f198354c1 Mon Sep 17 00:00:00 2001 From: "Matthew Wilcox (Oracle)" Date: Fri, 28 Nov 2025 16:18:32 +0000 Subject: [PATCH 1674/2333] idr: fix idr_alloc() returning an ID out of range MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit c6e8e595a0798ad67da0f7bebaf69c31ef70dfff upstream. If you use an IDR with a non-zero base, and specify a range that lies entirely below the base, 'max - base' becomes very large and idr_get_free() can return an ID that lies outside of the requested range. Link: https://lkml.kernel.org/r/20251128161853.3200058-1-willy@infradead.org Fixes: 6ce711f27500 ("idr: Make 1-based IDRs more efficient") Signed-off-by: Matthew Wilcox (Oracle) Reported-by: Jan Sokolowski Reported-by: Koen Koning Reported-by: Peter Senna Tschudin Closes: https://gitlab.freedesktop.org/drm/xe/kernel/-/issues/6449 Reviewed-by: Christian König Cc: Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- lib/idr.c | 2 ++ tools/testing/radix-tree/idr-test.c | 21 +++++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/lib/idr.c b/lib/idr.c index e2adc457abb4b..457430cff8c5e 100644 --- a/lib/idr.c +++ b/lib/idr.c @@ -40,6 +40,8 @@ int idr_alloc_u32(struct idr *idr, void *ptr, u32 *nextid, if (WARN_ON_ONCE(!(idr->idr_rt.xa_flags & ROOT_IS_IDR))) idr->idr_rt.xa_flags |= IDR_RT_MARKER; + if (max < base) + return -ENOSPC; id = (id < base) ? 0 : id - base; radix_tree_iter_init(&iter, id); diff --git a/tools/testing/radix-tree/idr-test.c b/tools/testing/radix-tree/idr-test.c index 2f830ff8396cc..945144e985072 100644 --- a/tools/testing/radix-tree/idr-test.c +++ b/tools/testing/radix-tree/idr-test.c @@ -57,6 +57,26 @@ void idr_alloc_test(void) idr_destroy(&idr); } +void idr_alloc2_test(void) +{ + int id; + struct idr idr = IDR_INIT_BASE(idr, 1); + + id = idr_alloc(&idr, idr_alloc2_test, 0, 1, GFP_KERNEL); + assert(id == -ENOSPC); + + id = idr_alloc(&idr, idr_alloc2_test, 1, 2, GFP_KERNEL); + assert(id == 1); + + id = idr_alloc(&idr, idr_alloc2_test, 0, 1, GFP_KERNEL); + assert(id == -ENOSPC); + + id = idr_alloc(&idr, idr_alloc2_test, 0, 2, GFP_KERNEL); + assert(id == -ENOSPC); + + idr_destroy(&idr); +} + void idr_replace_test(void) { DEFINE_IDR(idr); @@ -409,6 +429,7 @@ void idr_checks(void) idr_replace_test(); idr_alloc_test(); + idr_alloc2_test(); idr_null_test(); idr_nowait_test(); idr_get_next_test(0); From a794d65b132107a085d165caba33aae1101316a5 Mon Sep 17 00:00:00 2001 From: Alexander Gordeev Date: Fri, 12 Dec 2025 16:14:57 +0100 Subject: [PATCH 1675/2333] mm/page_alloc: change all pageblocks migrate type on coalescing commit 7838a4eb8a1d23160bd3f588ea7f2b8f7c00c55b upstream. When a page is freed it coalesces with a buddy into a higher order page while possible. When the buddy page migrate type differs, it is expected to be updated to match the one of the page being freed. However, only the first pageblock of the buddy page is updated, while the rest of the pageblocks are left unchanged. That causes warnings in later expand() and other code paths (like below), since an inconsistency between migration type of the list containing the page and the page-owned pageblocks migration types is introduced. [ 308.986589] ------------[ cut here ]------------ [ 308.987227] page type is 0, passed migratetype is 1 (nr=256) [ 308.987275] WARNING: CPU: 1 PID: 5224 at mm/page_alloc.c:812 expand+0x23c/0x270 [ 308.987293] Modules linked in: algif_hash(E) af_alg(E) nft_fib_inet(E) nft_fib_ipv4(E) nft_fib_ipv6(E) nft_fib(E) nft_reject_inet(E) nf_reject_ipv4(E) nf_reject_ipv6(E) nft_reject(E) nft_ct(E) nft_chain_nat(E) nf_nat(E) nf_conntrack(E) nf_defrag_ipv6(E) nf_defrag_ipv4(E) nf_tables(E) s390_trng(E) vfio_ccw(E) mdev(E) vfio_iommu_type1(E) vfio(E) sch_fq_codel(E) drm(E) i2c_core(E) drm_panel_orientation_quirks(E) loop(E) nfnetlink(E) vsock_loopback(E) vmw_vsock_virtio_transport_common(E) vsock(E) ctcm(E) fsm(E) diag288_wdt(E) watchdog(E) zfcp(E) scsi_transport_fc(E) ghash_s390(E) prng(E) aes_s390(E) des_generic(E) des_s390(E) libdes(E) sha3_512_s390(E) sha3_256_s390(E) sha_common(E) paes_s390(E) crypto_engine(E) pkey_cca(E) pkey_ep11(E) zcrypt(E) rng_core(E) pkey_pckmo(E) pkey(E) autofs4(E) [ 308.987439] Unloaded tainted modules: hmac_s390(E):2 [ 308.987650] CPU: 1 UID: 0 PID: 5224 Comm: mempig_verify Kdump: loaded Tainted: G E 6.18.0-gcc-bpf-debug #431 PREEMPT [ 308.987657] Tainted: [E]=UNSIGNED_MODULE [ 308.987661] Hardware name: IBM 3906 M04 704 (z/VM 7.3.0) [ 308.987666] Krnl PSW : 0404f00180000000 00000349976fa600 (expand+0x240/0x270) [ 308.987676] R:0 T:1 IO:0 EX:0 Key:0 M:1 W:0 P:0 AS:3 CC:3 PM:0 RI:0 EA:3 [ 308.987682] Krnl GPRS: 0000034980000004 0000000000000005 0000000000000030 000003499a0e6d88 [ 308.987688] 0000000000000005 0000034980000005 000002be803ac000 0000023efe6c8300 [ 308.987692] 0000000000000008 0000034998d57290 000002be00000100 0000023e00000008 [ 308.987696] 0000000000000000 0000000000000000 00000349976fa5fc 000002c99b1eb6f0 [ 308.987708] Krnl Code: 00000349976fa5f0: c020008a02f2 larl %r2,000003499883abd4 00000349976fa5f6: c0e5ffe3f4b5 brasl %r14,0000034997378f60 #00000349976fa5fc: af000000 mc 0,0 >00000349976fa600: a7f4ff4c brc 15,00000349976fa498 00000349976fa604: b9040026 lgr %r2,%r6 00000349976fa608: c0300088317f larl %r3,0000034998800906 00000349976fa60e: c0e5fffdb6e1 brasl %r14,00000349976b13d0 00000349976fa614: af000000 mc 0,0 [ 308.987734] Call Trace: [ 308.987738] [<00000349976fa600>] expand+0x240/0x270 [ 308.987744] ([<00000349976fa5fc>] expand+0x23c/0x270) [ 308.987749] [<00000349976ff95e>] rmqueue_bulk+0x71e/0x940 [ 308.987754] [<00000349976ffd7e>] __rmqueue_pcplist+0x1fe/0x2a0 [ 308.987759] [<0000034997700966>] rmqueue.isra.0+0xb46/0xf40 [ 308.987763] [<0000034997703ec8>] get_page_from_freelist+0x198/0x8d0 [ 308.987768] [<0000034997706fa8>] __alloc_frozen_pages_noprof+0x198/0x400 [ 308.987774] [<00000349977536f8>] alloc_pages_mpol+0xb8/0x220 [ 308.987781] [<0000034997753bf6>] folio_alloc_mpol_noprof+0x26/0xc0 [ 308.987786] [<0000034997753e4c>] vma_alloc_folio_noprof+0x6c/0xa0 [ 308.987791] [<0000034997775b22>] vma_alloc_anon_folio_pmd+0x42/0x240 [ 308.987799] [<000003499777bfea>] __do_huge_pmd_anonymous_page+0x3a/0x210 [ 308.987804] [<00000349976cb08e>] __handle_mm_fault+0x4de/0x500 [ 308.987809] [<00000349976cb14c>] handle_mm_fault+0x9c/0x3a0 [ 308.987813] [<000003499734d70e>] do_exception+0x1de/0x540 [ 308.987822] [<0000034998387390>] __do_pgm_check+0x130/0x220 [ 308.987830] [<000003499839a934>] pgm_check_handler+0x114/0x160 [ 308.987838] 3 locks held by mempig_verify/5224: [ 308.987842] #0: 0000023ea44c1e08 (vm_lock){++++}-{0:0}, at: lock_vma_under_rcu+0xb2/0x2a0 [ 308.987859] #1: 0000023ee4d41b18 (&pcp->lock){+.+.}-{2:2}, at: rmqueue.isra.0+0xad6/0xf40 [ 308.987871] #2: 0000023efe6c8998 (&zone->lock){..-.}-{2:2}, at: rmqueue_bulk+0x5a/0x940 [ 308.987886] Last Breaking-Event-Address: [ 308.987890] [<0000034997379096>] __warn_printk+0x136/0x140 [ 308.987897] irq event stamp: 52330356 [ 308.987901] hardirqs last enabled at (52330355): [<000003499838742e>] __do_pgm_check+0x1ce/0x220 [ 308.987907] hardirqs last disabled at (52330356): [<000003499839932e>] _raw_spin_lock_irqsave+0x9e/0xe0 [ 308.987913] softirqs last enabled at (52329882): [<0000034997383786>] handle_softirqs+0x2c6/0x530 [ 308.987922] softirqs last disabled at (52329859): [<0000034997382f86>] __irq_exit_rcu+0x126/0x140 [ 308.987929] ---[ end trace 0000000000000000 ]--- [ 308.987936] ------------[ cut here ]------------ [ 308.987940] page type is 0, passed migratetype is 1 (nr=256) [ 308.987951] WARNING: CPU: 1 PID: 5224 at mm/page_alloc.c:860 __del_page_from_free_list+0x1be/0x1e0 [ 308.987960] Modules linked in: algif_hash(E) af_alg(E) nft_fib_inet(E) nft_fib_ipv4(E) nft_fib_ipv6(E) nft_fib(E) nft_reject_inet(E) nf_reject_ipv4(E) nf_reject_ipv6(E) nft_reject(E) nft_ct(E) nft_chain_nat(E) nf_nat(E) nf_conntrack(E) nf_defrag_ipv6(E) nf_defrag_ipv4(E) nf_tables(E) s390_trng(E) vfio_ccw(E) mdev(E) vfio_iommu_type1(E) vfio(E) sch_fq_codel(E) drm(E) i2c_core(E) drm_panel_orientation_quirks(E) loop(E) nfnetlink(E) vsock_loopback(E) vmw_vsock_virtio_transport_common(E) vsock(E) ctcm(E) fsm(E) diag288_wdt(E) watchdog(E) zfcp(E) scsi_transport_fc(E) ghash_s390(E) prng(E) aes_s390(E) des_generic(E) des_s390(E) libdes(E) sha3_512_s390(E) sha3_256_s390(E) sha_common(E) paes_s390(E) crypto_engine(E) pkey_cca(E) pkey_ep11(E) zcrypt(E) rng_core(E) pkey_pckmo(E) pkey(E) autofs4(E) [ 308.988070] Unloaded tainted modules: hmac_s390(E):2 [ 308.988087] CPU: 1 UID: 0 PID: 5224 Comm: mempig_verify Kdump: loaded Tainted: G W E 6.18.0-gcc-bpf-debug #431 PREEMPT [ 308.988095] Tainted: [W]=WARN, [E]=UNSIGNED_MODULE [ 308.988100] Hardware name: IBM 3906 M04 704 (z/VM 7.3.0) [ 308.988105] Krnl PSW : 0404f00180000000 00000349976f9e32 (__del_page_from_free_list+0x1c2/0x1e0) [ 308.988118] R:0 T:1 IO:0 EX:0 Key:0 M:1 W:0 P:0 AS:3 CC:3 PM:0 RI:0 EA:3 [ 308.988127] Krnl GPRS: 0000034980000004 0000000000000005 0000000000000030 000003499a0e6d88 [ 308.988133] 0000000000000005 0000034980000005 0000034998d57290 0000023efe6c8300 [ 308.988139] 0000000000000001 0000000000000008 000002be00000100 000002be803ac000 [ 308.988144] 0000000000000000 0000000000000001 00000349976f9e2e 000002c99b1eb728 [ 308.988153] Krnl Code: 00000349976f9e22: c020008a06d9 larl %r2,000003499883abd4 00000349976f9e28: c0e5ffe3f89c brasl %r14,0000034997378f60 #00000349976f9e2e: af000000 mc 0,0 >00000349976f9e32: a7f4ff4e brc 15,00000349976f9cce 00000349976f9e36: b904002b lgr %r2,%r11 00000349976f9e3a: c030008a06e7 larl %r3,000003499883ac08 00000349976f9e40: c0e5fffdbac8 brasl %r14,00000349976b13d0 00000349976f9e46: af000000 mc 0,0 [ 308.988184] Call Trace: [ 308.988188] [<00000349976f9e32>] __del_page_from_free_list+0x1c2/0x1e0 [ 308.988195] ([<00000349976f9e2e>] __del_page_from_free_list+0x1be/0x1e0) [ 308.988202] [<00000349976ff946>] rmqueue_bulk+0x706/0x940 [ 308.988208] [<00000349976ffd7e>] __rmqueue_pcplist+0x1fe/0x2a0 [ 308.988214] [<0000034997700966>] rmqueue.isra.0+0xb46/0xf40 [ 308.988221] [<0000034997703ec8>] get_page_from_freelist+0x198/0x8d0 [ 308.988227] [<0000034997706fa8>] __alloc_frozen_pages_noprof+0x198/0x400 [ 308.988233] [<00000349977536f8>] alloc_pages_mpol+0xb8/0x220 [ 308.988240] [<0000034997753bf6>] folio_alloc_mpol_noprof+0x26/0xc0 [ 308.988247] [<0000034997753e4c>] vma_alloc_folio_noprof+0x6c/0xa0 [ 308.988253] [<0000034997775b22>] vma_alloc_anon_folio_pmd+0x42/0x240 [ 308.988260] [<000003499777bfea>] __do_huge_pmd_anonymous_page+0x3a/0x210 [ 308.988267] [<00000349976cb08e>] __handle_mm_fault+0x4de/0x500 [ 308.988273] [<00000349976cb14c>] handle_mm_fault+0x9c/0x3a0 [ 308.988279] [<000003499734d70e>] do_exception+0x1de/0x540 [ 308.988286] [<0000034998387390>] __do_pgm_check+0x130/0x220 [ 308.988293] [<000003499839a934>] pgm_check_handler+0x114/0x160 [ 308.988300] 3 locks held by mempig_verify/5224: [ 308.988305] #0: 0000023ea44c1e08 (vm_lock){++++}-{0:0}, at: lock_vma_under_rcu+0xb2/0x2a0 [ 308.988322] #1: 0000023ee4d41b18 (&pcp->lock){+.+.}-{2:2}, at: rmqueue.isra.0+0xad6/0xf40 [ 308.988334] #2: 0000023efe6c8998 (&zone->lock){..-.}-{2:2}, at: rmqueue_bulk+0x5a/0x940 [ 308.988346] Last Breaking-Event-Address: [ 308.988350] [<0000034997379096>] __warn_printk+0x136/0x140 [ 308.988356] irq event stamp: 52330356 [ 308.988360] hardirqs last enabled at (52330355): [<000003499838742e>] __do_pgm_check+0x1ce/0x220 [ 308.988366] hardirqs last disabled at (52330356): [<000003499839932e>] _raw_spin_lock_irqsave+0x9e/0xe0 [ 308.988373] softirqs last enabled at (52329882): [<0000034997383786>] handle_softirqs+0x2c6/0x530 [ 308.988380] softirqs last disabled at (52329859): [<0000034997382f86>] __irq_exit_rcu+0x126/0x140 [ 308.988388] ---[ end trace 0000000000000000 ]--- Link: https://lkml.kernel.org/r/20251215081002.3353900A9c-agordeev@linux.ibm.com Link: https://lkml.kernel.org/r/20251212151457.3898073Add-agordeev@linux.ibm.com Fixes: e6cf9e1c4cde ("mm: page_alloc: fix up block types when merging compatible blocks") Signed-off-by: Alexander Gordeev Reported-by: Marc Hartmayer Closes: https://lore.kernel.org/linux-mm/87wmalyktd.fsf@linux.ibm.com/ Acked-by: Vlastimil Babka Acked-by: Johannes Weiner Reviewed-by: Wei Yang Cc: Marc Hartmayer Cc: Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- mm/page_alloc.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/mm/page_alloc.c b/mm/page_alloc.c index ed82ee55e66af..6e644f2744c2d 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -913,6 +913,17 @@ buddy_merge_likely(unsigned long pfn, unsigned long buddy_pfn, NULL) != NULL; } +static void change_pageblock_range(struct page *pageblock_page, + int start_order, int migratetype) +{ + int nr_pageblocks = 1 << (start_order - pageblock_order); + + while (nr_pageblocks--) { + set_pageblock_migratetype(pageblock_page, migratetype); + pageblock_page += pageblock_nr_pages; + } +} + /* * Freeing function for a buddy system allocator. * @@ -999,7 +1010,7 @@ static inline void __free_one_page(struct page *page, * expand() down the line puts the sub-blocks * on the right freelists. */ - set_pageblock_migratetype(buddy, migratetype); + change_pageblock_range(buddy, order, migratetype); } combined_pfn = buddy_pfn & pfn; @@ -2146,17 +2157,6 @@ bool pageblock_unisolate_and_move_free_pages(struct zone *zone, struct page *pag #endif /* CONFIG_MEMORY_ISOLATION */ -static void change_pageblock_range(struct page *pageblock_page, - int start_order, int migratetype) -{ - int nr_pageblocks = 1 << (start_order - pageblock_order); - - while (nr_pageblocks--) { - set_pageblock_migratetype(pageblock_page, migratetype); - pageblock_page += pageblock_nr_pages; - } -} - static inline bool boost_watermark(struct zone *zone) { unsigned long max_boost; From 05a8edf607be826738dfc620a17d9d98e8976762 Mon Sep 17 00:00:00 2001 From: Ran Xiaokai Date: Fri, 19 Dec 2025 07:42:32 +0000 Subject: [PATCH 1676/2333] mm/page_owner: fix memory leak in page_owner_stack_fops->release() commit a76a5ae2c6c645005672c2caf2d49361c6f2500f upstream. The page_owner_stack_fops->open() callback invokes seq_open_private(), therefore its corresponding ->release() callback must call seq_release_private(). Otherwise it will cause a memory leak of struct stack_print_ctx. Link: https://lkml.kernel.org/r/20251219074232.136482-1-ranxiaokai627@163.com Fixes: 765973a09803 ("mm,page_owner: display all stacks and their count") Signed-off-by: Ran Xiaokai Acked-by: Michal Hocko Acked-by: Vlastimil Babka Cc: Andrey Konovalov Cc: Brendan Jackman Cc: Johannes Weiner Cc: Marco Elver Cc: Suren Baghdasaryan Cc: Zi Yan Cc: Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- mm/page_owner.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/page_owner.c b/mm/page_owner.c index 589ec37c94aab..bc26764142ba5 100644 --- a/mm/page_owner.c +++ b/mm/page_owner.c @@ -936,7 +936,7 @@ static const struct file_operations page_owner_stack_operations = { .open = page_owner_stack_open, .read = seq_read, .llseek = seq_lseek, - .release = seq_release, + .release = seq_release_private, }; static int page_owner_threshold_get(void *data, u64 *val) From 4bae7111bf299097ef7ba715f9e5be09fe2b1346 Mon Sep 17 00:00:00 2001 From: Bijan Tabatabai Date: Tue, 16 Dec 2025 14:07:27 -0600 Subject: [PATCH 1677/2333] mm: consider non-anon swap cache folios in folio_expected_ref_count() commit f183663901f21fe0fba8bd31ae894bc529709ee0 upstream. Currently, folio_expected_ref_count() only adds references for the swap cache if the folio is anonymous. However, according to the comment above the definition of PG_swapcache in enum pageflags, shmem folios can also have PG_swapcache set. This patch makes sure references for the swap cache are added if folio_test_swapcache(folio) is true. This issue was found when trying to hot-unplug memory in a QEMU/KVM virtual machine. When initiating hot-unplug when most of the guest memory is allocated, hot-unplug hangs partway through removal due to migration failures. The following message would be printed several times, and would be printed again about every five seconds: [ 49.641309] migrating pfn b12f25 failed ret:7 [ 49.641310] page: refcount:2 mapcount:0 mapping:0000000033bd8fe2 index:0x7f404d925 pfn:0xb12f25 [ 49.641311] aops:swap_aops [ 49.641313] flags: 0x300000000030508(uptodate|active|owner_priv_1|reclaim|swapbacked|node=0|zone=3) [ 49.641314] raw: 0300000000030508 ffffed312c4bc908 ffffed312c4bc9c8 0000000000000000 [ 49.641315] raw: 00000007f404d925 00000000000c823b 00000002ffffffff 0000000000000000 [ 49.641315] page dumped because: migration failure When debugging this, I found that these migration failures were due to __migrate_folio() returning -EAGAIN for a small set of folios because the expected reference count it calculates via folio_expected_ref_count() is one less than the actual reference count of the folios. Furthermore, all of the affected folios were not anonymous, but had the PG_swapcache flag set, inspiring this patch. After applying this patch, the memory hot-unplug behaves as expected. I tested this on a machine running Ubuntu 24.04 with kernel version 6.8.0-90-generic and 64GB of memory. The guest VM is managed by libvirt and runs Ubuntu 24.04 with kernel version 6.18 (though the head of the mm-unstable branch as a Dec 16, 2025 was also tested and behaves the same) and 48GB of memory. The libvirt XML definition for the VM can be found at [1]. CONFIG_MHP_DEFAULT_ONLINE_TYPE_ONLINE_MOVABLE is set in the guest kernel so the hot-pluggable memory is automatically onlined. Below are the steps to reproduce this behavior: 1) Define and start and virtual machine host$ virsh -c qemu:///system define ./test_vm.xml # test_vm.xml from [1] host$ virsh -c qemu:///system start test_vm 2) Setup swap in the guest guest$ sudo fallocate -l 32G /swapfile guest$ sudo chmod 0600 /swapfile guest$ sudo mkswap /swapfile guest$ sudo swapon /swapfile 3) Use alloc_data [2] to allocate most of the remaining guest memory guest$ ./alloc_data 45 4) In a separate guest terminal, monitor the amount of used memory guest$ watch -n1 free -h 5) When alloc_data has finished allocating, initiate the memory hot-unplug using the provided xml file [3] host$ virsh -c qemu:///system detach-device test_vm ./remove.xml --live After initiating the memory hot-unplug, you should see the amount of available memory in the guest decrease, and the amount of used swap data increase. If everything works as expected, when all of the memory is unplugged, there should be around 8.5-9GB of data in swap. If the unplugging is unsuccessful, the amount of used swap data will settle below that. If that happens, you should be able to see log messages in dmesg similar to the one posted above. Link: https://lkml.kernel.org/r/20251216200727.2360228-1-bijan311@gmail.com Link: https://github.com/BijanT/linux_patch_files/blob/main/test_vm.xml [1] Link: https://github.com/BijanT/linux_patch_files/blob/main/alloc_data.c [2] Link: https://github.com/BijanT/linux_patch_files/blob/main/remove.xml [3] Fixes: 86ebd50224c0 ("mm: add folio_expected_ref_count() for reference count calculation") Signed-off-by: Bijan Tabatabai Acked-by: David Hildenbrand (Red Hat) Acked-by: Zi Yan Reviewed-by: Baolin Wang Cc: Liam Howlett Cc: Lorenzo Stoakes Cc: Michal Hocko Cc: Mike Rapoport Cc: Shivank Garg Cc: Suren Baghdasaryan Cc: Vlastimil Babka Cc: Kairui Song Cc: Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- include/linux/mm.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/linux/mm.h b/include/linux/mm.h index 7c79b3369b82c..8631c9424987d 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -2272,10 +2272,10 @@ static inline int folio_expected_ref_count(const struct folio *folio) if (WARN_ON_ONCE(page_has_type(&folio->page) && !folio_test_hugetlb(folio))) return 0; - if (folio_test_anon(folio)) { - /* One reference per page from the swapcache. */ - ref_count += folio_test_swapcache(folio) << order; - } else { + /* One reference per page from the swapcache. */ + ref_count += folio_test_swapcache(folio) << order; + + if (!folio_test_anon(folio)) { /* One reference per page from the pagecache. */ ref_count += !!folio->mapping << order; /* One reference from PG_private. */ From 54e9bd5025a071058965e12d34caea1a1229e143 Mon Sep 17 00:00:00 2001 From: Rong Zhang Date: Tue, 30 Dec 2025 02:22:21 +0800 Subject: [PATCH 1678/2333] x86/microcode/AMD: Fix Entrysign revision check for Zen5/Strix Halo commit 150b1b97e27513535dcd3795d5ecd28e61b6cb8c upstream. Zen5 also contains family 1Ah, models 70h-7Fh, which are mistakenly missing from cpu_has_entrysign(). Add the missing range. Fixes: 8a9fb5129e8e ("x86/microcode/AMD: Limit Entrysign signature checking to known generations") Signed-off-by: Rong Zhang Signed-off-by: Borislav Petkov (AMD) Cc: stable@kernel.org Link: https://patch.msgid.link/20251229182245.152747-1-i@rong.moe Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/cpu/microcode/amd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kernel/cpu/microcode/amd.c b/arch/x86/kernel/cpu/microcode/amd.c index 3821a985f4ffe..46673530bc6f0 100644 --- a/arch/x86/kernel/cpu/microcode/amd.c +++ b/arch/x86/kernel/cpu/microcode/amd.c @@ -258,7 +258,7 @@ static bool cpu_has_entrysign(void) if (fam == 0x1a) { if (model <= 0x2f || (0x40 <= model && model <= 0x4f) || - (0x60 <= model && model <= 0x6f)) + (0x60 <= model && model <= 0x7f)) return true; } From 4df537e2478d2a694a6936ef48d38f90e798282a Mon Sep 17 00:00:00 2001 From: Kaushlendra Kumar Date: Tue, 9 Dec 2025 10:15:52 +0530 Subject: [PATCH 1679/2333] tools/mm/page_owner_sort: fix timestamp comparison for stable sorting commit 7013803444dd3bbbe28fd3360c084cec3057c554 upstream. The ternary operator in compare_ts() returns 1 when timestamps are equal, causing unstable sorting behavior. Replace with explicit three-way comparison that returns 0 for equal timestamps, ensuring stable qsort ordering and consistent output. Link: https://lkml.kernel.org/r/20251209044552.3396468-1-kaushlendra.kumar@intel.com Fixes: 8f9c447e2e2b ("tools/vm/page_owner_sort.c: support sorting pid and time") Signed-off-by: Kaushlendra Kumar Cc: Chongxi Zhao Cc: Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- tools/mm/page_owner_sort.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tools/mm/page_owner_sort.c b/tools/mm/page_owner_sort.c index 880e36df0c118..82d6f6b31348c 100644 --- a/tools/mm/page_owner_sort.c +++ b/tools/mm/page_owner_sort.c @@ -183,7 +183,11 @@ static int compare_ts(const void *p1, const void *p2) { const struct block_list *l1 = p1, *l2 = p2; - return l1->ts_nsec < l2->ts_nsec ? -1 : 1; + if (l1->ts_nsec < l2->ts_nsec) + return -1; + if (l1->ts_nsec > l2->ts_nsec) + return 1; + return 0; } static int compare_cull_condition(const void *p1, const void *p2) From 6f9af862a8595baa13c65e51aa721ca8bbdd608e Mon Sep 17 00:00:00 2001 From: Wake Liu Date: Wed, 10 Dec 2025 17:14:08 +0800 Subject: [PATCH 1680/2333] selftests/mm: fix thread state check in uffd-unit-tests commit 632b874d59a36caf829ab5790dafb90f9b350fd6 upstream. In the thread_state_get() function, the logic to find the thread's state character was using `sizeof(header) - 1` to calculate the offset from the "State:\t" string. The `header` variable is a `const char *` pointer. `sizeof()` on a pointer returns the size of the pointer itself, not the length of the string literal it points to. This makes the code's behavior dependent on the architecture's pointer size. This bug was identified on a 32-bit ARM build (`gsi_tv_arm`) for Android, running on an ARMv8-based device, compiled with Clang 19.0.1. On this 32-bit architecture, `sizeof(char *)` is 4. The expression `sizeof(header) - 1` resulted in an incorrect offset of 3, causing the test to read the wrong character from `/proc/[tid]/status` and fail. On 64-bit architectures, `sizeof(char *)` is 8, so the expression coincidentally evaluates to 7, which matches the length of "State:\t". This is why the bug likely remained hidden on 64-bit builds. To fix this and make the code portable and correct across all architectures, this patch replaces `sizeof(header) - 1` with `strlen(header)`. The `strlen()` function correctly calculates the string's length, ensuring the correct offset is always used. Link: https://lkml.kernel.org/r/20251210091408.3781445-1-wakel@google.com Fixes: f60b6634cd88 ("mm/selftests: add a test to verify mmap_changing race with -EAGAIN") Signed-off-by: Wake Liu Acked-by: Peter Xu Reviewed-by: Mike Rapoport (Microsoft) Cc: Bill Wendling Cc: Justin Stitt Cc: Liam Howlett Cc: Lorenzo Stoakes Cc: Michal Hocko Cc: Nathan Chancellor Cc: Shuah Khan Cc: Suren Baghdasaryan Cc: Vlastimil Babka Cc: Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- tools/testing/selftests/mm/uffd-unit-tests.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/mm/uffd-unit-tests.c b/tools/testing/selftests/mm/uffd-unit-tests.c index f917b4c4c9436..44627d4010f24 100644 --- a/tools/testing/selftests/mm/uffd-unit-tests.c +++ b/tools/testing/selftests/mm/uffd-unit-tests.c @@ -1317,7 +1317,7 @@ static thread_state thread_state_get(pid_t tid) p = strstr(tmp, header); if (p) { /* For example, "State:\tD (disk sleep)" */ - c = *(p + sizeof(header) - 1); + c = *(p + strlen(header)); return c == 'D' ? THR_STATE_UNINTERRUPTIBLE : THR_STATE_UNKNOWN; } From 7d7010f5f0ee21dffeaad375949b2c7d431a2496 Mon Sep 17 00:00:00 2001 From: Chenghao Duan Date: Wed, 31 Dec 2025 15:19:25 +0800 Subject: [PATCH 1681/2333] samples/ftrace: Adjust LoongArch register restore order in direct calls commit bb85d206be208bbf834883e948125a35ac59993a upstream. Ensure that in the ftrace direct call logic, the CPU register state (with ra = parent return address) is restored to the correct state after the execution of the custom trampoline function and before returning to the traced function. Additionally, guarantee the correctness of the jump logic for jr t0 (traced function address). Cc: stable@vger.kernel.org Fixes: 9cdc3b6a299c ("LoongArch: ftrace: Add direct call support") Reported-by: Youling Tang Acked-by: Steven Rostedt (Google) Signed-off-by: Chenghao Duan Signed-off-by: Huacai Chen Signed-off-by: Greg Kroah-Hartman --- samples/ftrace/ftrace-direct-modify.c | 8 ++++---- samples/ftrace/ftrace-direct-multi-modify.c | 8 ++++---- samples/ftrace/ftrace-direct-multi.c | 4 ++-- samples/ftrace/ftrace-direct-too.c | 4 ++-- samples/ftrace/ftrace-direct.c | 4 ++-- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/samples/ftrace/ftrace-direct-modify.c b/samples/ftrace/ftrace-direct-modify.c index da3a9f2091f55..1ba1927b548ee 100644 --- a/samples/ftrace/ftrace-direct-modify.c +++ b/samples/ftrace/ftrace-direct-modify.c @@ -176,8 +176,8 @@ asm ( " st.d $t0, $sp, 0\n" " st.d $ra, $sp, 8\n" " bl my_direct_func1\n" -" ld.d $t0, $sp, 0\n" -" ld.d $ra, $sp, 8\n" +" ld.d $ra, $sp, 0\n" +" ld.d $t0, $sp, 8\n" " addi.d $sp, $sp, 16\n" " jr $t0\n" " .size my_tramp1, .-my_tramp1\n" @@ -189,8 +189,8 @@ asm ( " st.d $t0, $sp, 0\n" " st.d $ra, $sp, 8\n" " bl my_direct_func2\n" -" ld.d $t0, $sp, 0\n" -" ld.d $ra, $sp, 8\n" +" ld.d $ra, $sp, 0\n" +" ld.d $t0, $sp, 8\n" " addi.d $sp, $sp, 16\n" " jr $t0\n" " .size my_tramp2, .-my_tramp2\n" diff --git a/samples/ftrace/ftrace-direct-multi-modify.c b/samples/ftrace/ftrace-direct-multi-modify.c index 8f7986d698d87..7a7822dfeb50a 100644 --- a/samples/ftrace/ftrace-direct-multi-modify.c +++ b/samples/ftrace/ftrace-direct-multi-modify.c @@ -199,8 +199,8 @@ asm ( " move $a0, $t0\n" " bl my_direct_func1\n" " ld.d $a0, $sp, 0\n" -" ld.d $t0, $sp, 8\n" -" ld.d $ra, $sp, 16\n" +" ld.d $ra, $sp, 8\n" +" ld.d $t0, $sp, 16\n" " addi.d $sp, $sp, 32\n" " jr $t0\n" " .size my_tramp1, .-my_tramp1\n" @@ -215,8 +215,8 @@ asm ( " move $a0, $t0\n" " bl my_direct_func2\n" " ld.d $a0, $sp, 0\n" -" ld.d $t0, $sp, 8\n" -" ld.d $ra, $sp, 16\n" +" ld.d $ra, $sp, 8\n" +" ld.d $t0, $sp, 16\n" " addi.d $sp, $sp, 32\n" " jr $t0\n" " .size my_tramp2, .-my_tramp2\n" diff --git a/samples/ftrace/ftrace-direct-multi.c b/samples/ftrace/ftrace-direct-multi.c index db326c81a27dd..3fe6ddaf0b69f 100644 --- a/samples/ftrace/ftrace-direct-multi.c +++ b/samples/ftrace/ftrace-direct-multi.c @@ -131,8 +131,8 @@ asm ( " move $a0, $t0\n" " bl my_direct_func\n" " ld.d $a0, $sp, 0\n" -" ld.d $t0, $sp, 8\n" -" ld.d $ra, $sp, 16\n" +" ld.d $ra, $sp, 8\n" +" ld.d $t0, $sp, 16\n" " addi.d $sp, $sp, 32\n" " jr $t0\n" " .size my_tramp, .-my_tramp\n" diff --git a/samples/ftrace/ftrace-direct-too.c b/samples/ftrace/ftrace-direct-too.c index 3d0fa260332d4..bf2411aa6fd7a 100644 --- a/samples/ftrace/ftrace-direct-too.c +++ b/samples/ftrace/ftrace-direct-too.c @@ -143,8 +143,8 @@ asm ( " ld.d $a0, $sp, 0\n" " ld.d $a1, $sp, 8\n" " ld.d $a2, $sp, 16\n" -" ld.d $t0, $sp, 24\n" -" ld.d $ra, $sp, 32\n" +" ld.d $ra, $sp, 24\n" +" ld.d $t0, $sp, 32\n" " addi.d $sp, $sp, 48\n" " jr $t0\n" " .size my_tramp, .-my_tramp\n" diff --git a/samples/ftrace/ftrace-direct.c b/samples/ftrace/ftrace-direct.c index 956834b0d19ac..5368c8c39cbb4 100644 --- a/samples/ftrace/ftrace-direct.c +++ b/samples/ftrace/ftrace-direct.c @@ -124,8 +124,8 @@ asm ( " st.d $ra, $sp, 16\n" " bl my_direct_func\n" " ld.d $a0, $sp, 0\n" -" ld.d $t0, $sp, 8\n" -" ld.d $ra, $sp, 16\n" +" ld.d $ra, $sp, 8\n" +" ld.d $t0, $sp, 16\n" " addi.d $sp, $sp, 32\n" " jr $t0\n" " .size my_tramp, .-my_tramp\n" From 3b8caba9326746c9ebc2cc66f63cc0e509752a55 Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Wed, 17 Dec 2025 13:10:37 +0000 Subject: [PATCH 1682/2333] rust: maple_tree: rcu_read_lock() in destructor to silence lockdep MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 6558749ef3405c143711cbdc67ec88cbc1582d91 upstream. When running the Rust maple tree kunit tests with lockdep, you may trigger a warning that looks like this: lib/maple_tree.c:780 suspicious rcu_dereference_check() usage! other info that might help us debug this: rcu_scheduler_active = 2, debug_locks = 1 no locks held by kunit_try_catch/344. stack backtrace: CPU: 3 UID: 0 PID: 344 Comm: kunit_try_catch Tainted: G N 6.19.0-rc1+ #2 NONE Tainted: [N]=TEST Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.17.0-0-gb52ca86e094d-prebuilt.qemu.org 04/01/2014 Call Trace: dump_stack_lvl+0x71/0x90 lockdep_rcu_suspicious+0x150/0x190 mas_start+0x104/0x150 mas_find+0x179/0x240 _RINvNtCs5QSdWC790r4_4core3ptr13drop_in_placeINtNtCs1cdwasc6FUb_6kernel10maple_tree9MapleTreeINtNtNtBL_5alloc4kbox3BoxlNtNtB1x_9allocator7KmallocEEECsgxAQYCfdR72_25doctests_kernel_generated+0xaf/0x130 rust_doctest_kernel_maple_tree_rs_0+0x600/0x6b0 ? lock_release+0xeb/0x2a0 ? kunit_try_catch_run+0x210/0x210 kunit_try_run_case+0x74/0x160 ? kunit_try_catch_run+0x210/0x210 kunit_generic_run_threadfn_adapter+0x12/0x30 kthread+0x21c/0x230 ? __do_trace_sched_kthread_stop_ret+0x40/0x40 ret_from_fork+0x16c/0x270 ? __do_trace_sched_kthread_stop_ret+0x40/0x40 ret_from_fork_asm+0x11/0x20 This is because the destructor of maple tree calls mas_find() without taking rcu_read_lock() or the spinlock. Doing that is actually ok in this case since the destructor has exclusive access to the entire maple tree, but it triggers a lockdep warning. To fix that, take the rcu read lock. In the future, it's possible that memory reclaim could gain a feature where it reallocates entries in maple trees even if no user-code is touching it. If that feature is added, then this use of rcu read lock would become load-bearing, so I did not make it conditional on lockdep. We have to repeatedly take and release rcu because the destructor of T might perform operations that sleep. Link: https://lkml.kernel.org/r/20251217-maple-drop-rcu-v1-1-702af063573f@google.com Fixes: da939ef4c494 ("rust: maple_tree: add MapleTree") Signed-off-by: Alice Ryhl Reported-by: Andreas Hindborg Closes: https://rust-for-linux.zulipchat.com/#narrow/channel/x/topic/x/near/564215108 Reviewed-by: Gary Guo Reviewed-by: Daniel Almeida Cc: Andrew Ballance Cc: Björn Roy Baron Cc: Boqun Feng Cc: Danilo Krummrich Cc: Liam Howlett Cc: Matthew Wilcox (Oracle) Cc: Miguel Ojeda Cc: Trevor Gross Cc: Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- rust/kernel/maple_tree.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/rust/kernel/maple_tree.rs b/rust/kernel/maple_tree.rs index e72eec56bf577..265d6396a78a1 100644 --- a/rust/kernel/maple_tree.rs +++ b/rust/kernel/maple_tree.rs @@ -265,7 +265,16 @@ impl MapleTree { loop { // This uses the raw accessor because we're destroying pointers without removing them // from the maple tree, which is only valid because this is the destructor. - let ptr = ma_state.mas_find_raw(usize::MAX); + // + // Take the rcu lock because mas_find_raw() requires that you hold either the spinlock + // or the rcu read lock. This is only really required if memory reclaim might + // reallocate entries in the tree, as we otherwise have exclusive access. That feature + // doesn't exist yet, so for now, taking the rcu lock only serves the purpose of + // silencing lockdep. + let ptr = { + let _rcu = kernel::sync::rcu::Guard::new(); + ma_state.mas_find_raw(usize::MAX) + }; if ptr.is_null() { break; } From 0b948afc1ded88b3562c893114387f34389eeb94 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Fri, 28 Nov 2025 13:37:28 -0400 Subject: [PATCH 1683/2333] RDMA/core: Check for the presence of LS_NLA_TYPE_DGID correctly commit a7b8e876e0ef0232b8076972c57ce9a7286b47ca upstream. The netlink response for RDMA_NL_LS_OP_IP_RESOLVE should always have a LS_NLA_TYPE_DGID attribute, it is invalid if it does not. Use the nl parsing logic properly and call nla_parse_deprecated() to fill the nlattrs array and then directly index that array to get the data for the DGID. Just fail if it is NULL. Remove the for loop searching for the nla, and squash the validation and parsing into one function. Fixes an uninitialized read from the stack triggered by userspace if it does not provide the DGID to a kernel initiated RDMA_NL_LS_OP_IP_RESOLVE query. BUG: KMSAN: uninit-value in hex_byte_pack include/linux/hex.h:13 [inline] BUG: KMSAN: uninit-value in ip6_string+0xef4/0x13a0 lib/vsprintf.c:1490 hex_byte_pack include/linux/hex.h:13 [inline] ip6_string+0xef4/0x13a0 lib/vsprintf.c:1490 ip6_addr_string+0x18a/0x3e0 lib/vsprintf.c:1509 ip_addr_string+0x245/0xee0 lib/vsprintf.c:1633 pointer+0xc09/0x1bd0 lib/vsprintf.c:2542 vsnprintf+0xf8a/0x1bd0 lib/vsprintf.c:2930 vprintk_store+0x3ae/0x1530 kernel/printk/printk.c:2279 vprintk_emit+0x307/0xcd0 kernel/printk/printk.c:2426 vprintk_default+0x3f/0x50 kernel/printk/printk.c:2465 vprintk+0x36/0x50 kernel/printk/printk_safe.c:82 _printk+0x17e/0x1b0 kernel/printk/printk.c:2475 ib_nl_process_good_ip_rsep drivers/infiniband/core/addr.c:128 [inline] ib_nl_handle_ip_res_resp+0x963/0x9d0 drivers/infiniband/core/addr.c:141 rdma_nl_rcv_msg drivers/infiniband/core/netlink.c:-1 [inline] rdma_nl_rcv_skb drivers/infiniband/core/netlink.c:239 [inline] rdma_nl_rcv+0xefa/0x11c0 drivers/infiniband/core/netlink.c:259 netlink_unicast_kernel net/netlink/af_netlink.c:1320 [inline] netlink_unicast+0xf04/0x12b0 net/netlink/af_netlink.c:1346 netlink_sendmsg+0x10b3/0x1250 net/netlink/af_netlink.c:1896 sock_sendmsg_nosec net/socket.c:714 [inline] __sock_sendmsg+0x333/0x3d0 net/socket.c:729 ____sys_sendmsg+0x7e0/0xd80 net/socket.c:2617 ___sys_sendmsg+0x271/0x3b0 net/socket.c:2671 __sys_sendmsg+0x1aa/0x300 net/socket.c:2703 __compat_sys_sendmsg net/compat.c:346 [inline] __do_compat_sys_sendmsg net/compat.c:353 [inline] __se_compat_sys_sendmsg net/compat.c:350 [inline] __ia32_compat_sys_sendmsg+0xa4/0x100 net/compat.c:350 ia32_sys_call+0x3f6c/0x4310 arch/x86/include/generated/asm/syscalls_32.h:371 do_syscall_32_irqs_on arch/x86/entry/syscall_32.c:83 [inline] __do_fast_syscall_32+0xb0/0x150 arch/x86/entry/syscall_32.c:306 do_fast_syscall_32+0x38/0x80 arch/x86/entry/syscall_32.c:331 do_SYSENTER_32+0x1f/0x30 arch/x86/entry/syscall_32.c:3 Link: https://patch.msgid.link/r/0-v1-3fbaef094271+2cf-rdma_op_ip_rslv_syz_jgg@nvidia.com Cc: stable@vger.kernel.org Fixes: ae43f8286730 ("IB/core: Add IP to GID netlink offload") Reported-by: syzbot+938fcd548c303fe33c1a@syzkaller.appspotmail.com Closes: https://lore.kernel.org/r/68dc3dac.a00a0220.102ee.004f.GAE@google.com Signed-off-by: Jason Gunthorpe Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/core/addr.c | 33 ++++++++++----------------------- 1 file changed, 10 insertions(+), 23 deletions(-) diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c index 61596cda2b65f..35ba852a172aa 100644 --- a/drivers/infiniband/core/addr.c +++ b/drivers/infiniband/core/addr.c @@ -80,37 +80,25 @@ static const struct nla_policy ib_nl_addr_policy[LS_NLA_TYPE_MAX] = { .min = sizeof(struct rdma_nla_ls_gid)}, }; -static inline bool ib_nl_is_good_ip_resp(const struct nlmsghdr *nlh) +static void ib_nl_process_ip_rsep(const struct nlmsghdr *nlh) { struct nlattr *tb[LS_NLA_TYPE_MAX] = {}; + union ib_gid gid; + struct addr_req *req; + int found = 0; int ret; if (nlh->nlmsg_flags & RDMA_NL_LS_F_ERR) - return false; + return; ret = nla_parse_deprecated(tb, LS_NLA_TYPE_MAX - 1, nlmsg_data(nlh), nlmsg_len(nlh), ib_nl_addr_policy, NULL); if (ret) - return false; - - return true; -} - -static void ib_nl_process_good_ip_rsep(const struct nlmsghdr *nlh) -{ - const struct nlattr *head, *curr; - union ib_gid gid; - struct addr_req *req; - int len, rem; - int found = 0; - - head = (const struct nlattr *)nlmsg_data(nlh); - len = nlmsg_len(nlh); + return; - nla_for_each_attr(curr, head, len, rem) { - if (curr->nla_type == LS_NLA_TYPE_DGID) - memcpy(&gid, nla_data(curr), nla_len(curr)); - } + if (!tb[LS_NLA_TYPE_DGID]) + return; + memcpy(&gid, nla_data(tb[LS_NLA_TYPE_DGID]), sizeof(gid)); spin_lock_bh(&lock); list_for_each_entry(req, &req_list, list) { @@ -137,8 +125,7 @@ int ib_nl_handle_ip_res_resp(struct sk_buff *skb, !(NETLINK_CB(skb).sk)) return -EPERM; - if (ib_nl_is_good_ip_resp(nlh)) - ib_nl_process_good_ip_rsep(nlh); + ib_nl_process_ip_rsep(nlh); return 0; } From 3ba6d01c4b3c584264dc733c6a2ecc5bbc8e0bb5 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Fri, 28 Nov 2025 20:53:21 -0400 Subject: [PATCH 1684/2333] RDMA/cm: Fix leaking the multicast GID table reference commit 57f3cb6c84159d12ba343574df2115fb18dd83ca upstream. If the CM ID is destroyed while the CM event for multicast creating is still queued the cancel_work_sync() will prevent the work from running which also prevents destroying the ah_attr. This leaks a refcount and triggers a WARN: GID entry ref leak for dev syz1 index 2 ref=573 WARNING: CPU: 1 PID: 655 at drivers/infiniband/core/cache.c:809 release_gid_table drivers/infiniband/core/cache.c:806 [inline] WARNING: CPU: 1 PID: 655 at drivers/infiniband/core/cache.c:809 gid_table_release_one+0x284/0x3cc drivers/infiniband/core/cache.c:886 Destroy the ah_attr after canceling the work, it is safe to call this twice. Link: https://patch.msgid.link/r/0-v1-4285d070a6b2+20a-rdma_mc_gid_leak_syz_jgg@nvidia.com Cc: stable@vger.kernel.org Fixes: fe454dc31e84 ("RDMA/ucma: Fix use-after-free bug in ucma_create_uevent") Reported-by: syzbot+b0da83a6c0e2e2bddbd4@syzkaller.appspotmail.com Closes: https://lore.kernel.org/all/68232e7b.050a0220.f2294.09f6.GAE@google.com Signed-off-by: Jason Gunthorpe Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/core/cma.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index 5b2d3ae3f9fce..ce511800b056c 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -2009,6 +2009,7 @@ static void destroy_mc(struct rdma_id_private *id_priv, ib_sa_free_multicast(mc->sa_mc); if (rdma_protocol_roce(id_priv->id.device, id_priv->id.port_num)) { + struct rdma_cm_event *event = &mc->iboe_join.event; struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr; struct net_device *ndev = NULL; @@ -2031,6 +2032,8 @@ static void destroy_mc(struct rdma_id_private *id_priv, dev_put(ndev); cancel_work_sync(&mc->iboe_join.work); + if (event->event == RDMA_CM_EVENT_MULTICAST_JOIN) + rdma_destroy_ah_attr(&event->param.ud.ah_attr); } kfree(mc); } From de5eb6b65e9f51773627bf1ea13d63a67a85d090 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 14 Nov 2025 00:28:52 +0200 Subject: [PATCH 1685/2333] wifi: iwlwifi: Fix firmware version handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit ca5898222914f399797cea1aeb0ce77109ca2e62 upstream. On my system the arithmetic done on the firmware numbers results in a negative number, but since the types are unsigned it gets interpreted as a large positive number. The end result is that the firmware gets rejected and wifi is defunct. Switch to signed types to handle this case correctly. iwlwifi 0000:0c:00.0: Driver unable to support your firmware API. Driver supports FW core 4294967294..2, firmware is 2. iwlwifi 0000:0c:00.0: Direct firmware load for iwlwifi-5000-4.ucode failed with error -2 iwlwifi 0000:0c:00.0: Direct firmware load for iwlwifi-5000-3.ucode failed with error -2 iwlwifi 0000:0c:00.0: Direct firmware load for iwlwifi-5000-2.ucode failed with error -2 iwlwifi 0000:0c:00.0: Direct firmware load for iwlwifi-5000-1.ucode failed with error -2 iwlwifi 0000:0c:00.0: no suitable firmware found! iwlwifi 0000:0c:00.0: minimum version required: iwlwifi-5000-1 iwlwifi 0000:0c:00.0: maximum version supported: iwlwifi-5000-5 iwlwifi 0000:0c:00.0: check git://git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git Cc: stable@vger.kernel.org Fixes: 5f708cccde9d ("wifi: iwlwifi: add a new FW file numbering scheme") Signed-off-by: Ville Syrjälä Closes: https://bugzilla.kernel.org/show_bug.cgi?id=220805 Link: https://patch.msgid.link/20251113222852.15896-1-ville.syrjala@linux.intel.com Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/intel/iwlwifi/iwl-drv.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c index 607fcea6f4efc..0f002ef261fcc 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c @@ -1599,7 +1599,7 @@ static void _iwl_op_mode_stop(struct iwl_drv *drv) */ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context) { - unsigned int min_core, max_core, loaded_core; + int min_core, max_core, loaded_core; struct iwl_drv *drv = context; struct iwl_fw *fw = &drv->fw; const struct iwl_ucode_header *ucode; @@ -1678,7 +1678,7 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context) if (loaded_core < min_core || loaded_core > max_core) { IWL_ERR(drv, "Driver unable to support your firmware API. " - "Driver supports FW core %u..%u, firmware is %u.\n", + "Driver supports FW core %d..%d, firmware is %d.\n", min_core, max_core, loaded_core); goto try_again; } From a21704df4024708be698fb3fd5830d5b113b70e0 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Mon, 15 Dec 2025 17:11:34 +0200 Subject: [PATCH 1686/2333] wifi: mac80211: Discard Beacon frames to non-broadcast address commit 193d18f60588e95d62e0f82b6a53893e5f2f19f8 upstream. Beacon frames are required to be sent to the broadcast address, see IEEE Std 802.11-2020, 11.1.3.1 ("The Address 1 field of the Beacon .. frame shall be set to the broadcast address"). A unicast Beacon frame might be used as a targeted attack to get one of the associated STAs to do something (e.g., using CSA to move it to another channel). As such, it is better have strict filtering for this on the received side and discard all Beacon frames that are sent to an unexpected address. This is even more important for cases where beacon protection is used. The current implementation in mac80211 is correctly discarding unicast Beacon frames if the Protected Frame bit in the Frame Control field is set to 0. However, if that bit is set to 1, the logic used for checking for configured BIGTK(s) does not actually work. If the driver does not have logic for dropping unicast Beacon frames with Protected Frame bit 1, these frames would be accepted in mac80211 processing as valid Beacon frames even though they are not protected. This would allow beacon protection to be bypassed. While the logic for checking beacon protection could be extended to cover this corner case, a more generic check for discard all Beacon frames based on A1=unicast address covers this without needing additional changes. Address all these issues by dropping received Beacon frames if they are sent to a non-broadcast address. Cc: stable@vger.kernel.org Fixes: af2d14b01c32 ("mac80211: Beacon protection using the new BIGTK (STA)") Signed-off-by: Jouni Malinen Link: https://patch.msgid.link/20251215151134.104501-1-jouni.malinen@oss.qualcomm.com Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman --- net/mac80211/rx.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 5b4c3fe9970ad..5091a3c15b0b4 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -3428,6 +3428,11 @@ ieee80211_rx_h_mgmt_check(struct ieee80211_rx_data *rx) rx->skb->len < IEEE80211_MIN_ACTION_SIZE) return RX_DROP_U_RUNT_ACTION; + /* Drop non-broadcast Beacon frames */ + if (ieee80211_is_beacon(mgmt->frame_control) && + !is_broadcast_ether_addr(mgmt->da)) + return RX_DROP; + if (rx->sdata->vif.type == NL80211_IFTYPE_AP && ieee80211_is_beacon(mgmt->frame_control) && !(rx->flags & IEEE80211_RX_BEACON_REPORTED)) { From ee7c125fb3e8b04dd46510130b9fc92380e5d578 Mon Sep 17 00:00:00 2001 From: Guangshuo Li Date: Mon, 1 Dec 2025 11:40:58 +0800 Subject: [PATCH 1687/2333] e1000: fix OOB in e1000_tbi_should_accept() commit 9c72a5182ed92904d01057f208c390a303f00a0f upstream. In e1000_tbi_should_accept() we read the last byte of the frame via 'data[length - 1]' to evaluate the TBI workaround. If the descriptor- reported length is zero or larger than the actual RX buffer size, this read goes out of bounds and can hit unrelated slab objects. The issue is observed from the NAPI receive path (e1000_clean_rx_irq): ================================================================== BUG: KASAN: slab-out-of-bounds in e1000_tbi_should_accept+0x610/0x790 Read of size 1 at addr ffff888014114e54 by task sshd/363 CPU: 0 PID: 363 Comm: sshd Not tainted 5.18.0-rc1 #1 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.12.0-59-gc9ba5276e321-prebuilt.qemu.org 04/01/2014 Call Trace: dump_stack_lvl+0x5a/0x74 print_address_description+0x7b/0x440 print_report+0x101/0x200 kasan_report+0xc1/0xf0 e1000_tbi_should_accept+0x610/0x790 e1000_clean_rx_irq+0xa8c/0x1110 e1000_clean+0xde2/0x3c10 __napi_poll+0x98/0x380 net_rx_action+0x491/0xa20 __do_softirq+0x2c9/0x61d do_softirq+0xd1/0x120 __local_bh_enable_ip+0xfe/0x130 ip_finish_output2+0x7d5/0xb00 __ip_queue_xmit+0xe24/0x1ab0 __tcp_transmit_skb+0x1bcb/0x3340 tcp_write_xmit+0x175d/0x6bd0 __tcp_push_pending_frames+0x7b/0x280 tcp_sendmsg_locked+0x2e4f/0x32d0 tcp_sendmsg+0x24/0x40 sock_write_iter+0x322/0x430 vfs_write+0x56c/0xa60 ksys_write+0xd1/0x190 do_syscall_64+0x43/0x90 entry_SYSCALL_64_after_hwframe+0x44/0xae RIP: 0033:0x7f511b476b10 Code: 73 01 c3 48 8b 0d 88 d3 2b 00 f7 d8 64 89 01 48 83 c8 ff c3 66 0f 1f 44 00 00 83 3d f9 2b 2c 00 00 75 10 b8 01 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 31 c3 48 83 ec 08 e8 8e 9b 01 00 48 89 04 24 RSP: 002b:00007ffc9211d4e8 EFLAGS: 00000246 ORIG_RAX: 0000000000000001 RAX: ffffffffffffffda RBX: 0000000000004024 RCX: 00007f511b476b10 RDX: 0000000000004024 RSI: 0000559a9385962c RDI: 0000000000000003 RBP: 0000559a9383a400 R08: fffffffffffffff0 R09: 0000000000004f00 R10: 0000000000000070 R11: 0000000000000246 R12: 0000000000000000 R13: 00007ffc9211d57f R14: 0000559a9347bde7 R15: 0000000000000003 Allocated by task 1: __kasan_krealloc+0x131/0x1c0 krealloc+0x90/0xc0 add_sysfs_param+0xcb/0x8a0 kernel_add_sysfs_param+0x81/0xd4 param_sysfs_builtin+0x138/0x1a6 param_sysfs_init+0x57/0x5b do_one_initcall+0x104/0x250 do_initcall_level+0x102/0x132 do_initcalls+0x46/0x74 kernel_init_freeable+0x28f/0x393 kernel_init+0x14/0x1a0 ret_from_fork+0x22/0x30 The buggy address belongs to the object at ffff888014114000 which belongs to the cache kmalloc-2k of size 2048 The buggy address is located 1620 bytes to the right of 2048-byte region [ffff888014114000, ffff888014114800] The buggy address belongs to the physical page: page:ffffea0000504400 refcount:1 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x14110 head:ffffea0000504400 order:3 compound_mapcount:0 compound_pincount:0 flags: 0x100000000010200(slab|head|node=0|zone=1) raw: 0100000000010200 0000000000000000 dead000000000001 ffff888013442000 raw: 0000000000000000 0000000000080008 00000001ffffffff 0000000000000000 page dumped because: kasan: bad access detected ================================================================== This happens because the TBI check unconditionally dereferences the last byte without validating the reported length first: u8 last_byte = *(data + length - 1); Fix by rejecting the frame early if the length is zero, or if it exceeds adapter->rx_buffer_len. This preserves the TBI workaround semantics for valid frames and prevents touching memory beyond the RX buffer. Fixes: 2037110c96d5 ("e1000: move tbi workaround code into helper function") Cc: stable@vger.kernel.org Signed-off-by: Guangshuo Li Reviewed-by: Simon Horman Reviewed-by: Aleksandr Loktionov Signed-off-by: Tony Nguyen Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/intel/e1000/e1000_main.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/e1000/e1000_main.c b/drivers/net/ethernet/intel/e1000/e1000_main.c index 292389aceb2d4..7f078ec9c14c5 100644 --- a/drivers/net/ethernet/intel/e1000/e1000_main.c +++ b/drivers/net/ethernet/intel/e1000/e1000_main.c @@ -4094,7 +4094,15 @@ static bool e1000_tbi_should_accept(struct e1000_adapter *adapter, u32 length, const u8 *data) { struct e1000_hw *hw = &adapter->hw; - u8 last_byte = *(data + length - 1); + u8 last_byte; + + /* Guard against OOB on data[length - 1] */ + if (unlikely(!length)) + return false; + /* Upper bound: length must not exceed rx_buffer_len */ + if (unlikely(length > adapter->rx_buffer_len)) + return false; + last_byte = *(data + length - 1); if (TBI_ACCEPT(hw, status, errors, length, last_byte)) { unsigned long irq_flags; From b282b2a9eed848587c1348abdd5d83fa346a2743 Mon Sep 17 00:00:00 2001 From: Frode Nordahl Date: Sat, 13 Dec 2025 10:13:36 +0000 Subject: [PATCH 1688/2333] erspan: Initialize options_len before referencing options. commit 35ddf66c65eff93fff91406756ba273600bf61a3 upstream. The struct ip_tunnel_info has a flexible array member named options that is protected by a counted_by(options_len) attribute. The compiler will use this information to enforce runtime bounds checking deployed by FORTIFY_SOURCE string helpers. As laid out in the GCC documentation, the counter must be initialized before the first reference to the flexible array member. After scanning through the files that use struct ip_tunnel_info and also refer to options or options_len, it appears the normal case is to use the ip_tunnel_info_opts_set() helper. Said helper would initialize options_len properly before copying data into options, however in the GRE ERSPAN code a partial update is done, preventing the use of the helper function. Before this change the handling of ERSPAN traffic in GRE tunnels would cause a kernel panic when the kernel is compiled with GCC 15+ and having FORTIFY_SOURCE configured: memcpy: detected buffer overflow: 4 byte write of buffer size 0 Call Trace: __fortify_panic+0xd/0xf erspan_rcv.cold+0x68/0x83 ? ip_route_input_slow+0x816/0x9d0 gre_rcv+0x1b2/0x1c0 gre_rcv+0x8e/0x100 ? raw_v4_input+0x2a0/0x2b0 ip_protocol_deliver_rcu+0x1ea/0x210 ip_local_deliver_finish+0x86/0x110 ip_local_deliver+0x65/0x110 ? ip_rcv_finish_core+0xd6/0x360 ip_rcv+0x186/0x1a0 Cc: stable@vger.kernel.org Link: https://gcc.gnu.org/onlinedocs/gcc/Common-Variable-Attributes.html#index-counted_005fby-variable-attribute Reported-at: https://launchpad.net/bugs/2129580 Fixes: bb5e62f2d547 ("net: Add options as a flexible array to struct ip_tunnel_info") Signed-off-by: Frode Nordahl Reviewed-by: Simon Horman Link: https://patch.msgid.link/20251213101338.4693-1-fnordahl@ubuntu.com Signed-off-by: Paolo Abeni Signed-off-by: Greg Kroah-Hartman --- net/ipv4/ip_gre.c | 6 ++++-- net/ipv6/ip6_gre.c | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index 761a53c6a89a6..8178c44a3cdd4 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -330,6 +330,10 @@ static int erspan_rcv(struct sk_buff *skb, struct tnl_ptk_info *tpi, if (!tun_dst) return PACKET_REJECT; + /* MUST set options_len before referencing options */ + info = &tun_dst->u.tun_info; + info->options_len = sizeof(*md); + /* skb can be uncloned in __iptunnel_pull_header, so * old pkt_md is no longer valid and we need to reset * it @@ -344,10 +348,8 @@ static int erspan_rcv(struct sk_buff *skb, struct tnl_ptk_info *tpi, memcpy(md2, pkt_md, ver == 1 ? ERSPAN_V1_MDSIZE : ERSPAN_V2_MDSIZE); - info = &tun_dst->u.tun_info; __set_bit(IP_TUNNEL_ERSPAN_OPT_BIT, info->key.tun_flags); - info->options_len = sizeof(*md); } skb_reset_mac_header(skb); diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c index 8bc3f05f594ed..d19d86ed43766 100644 --- a/net/ipv6/ip6_gre.c +++ b/net/ipv6/ip6_gre.c @@ -535,6 +535,10 @@ static int ip6erspan_rcv(struct sk_buff *skb, if (!tun_dst) return PACKET_REJECT; + /* MUST set options_len before referencing options */ + info = &tun_dst->u.tun_info; + info->options_len = sizeof(*md); + /* skb can be uncloned in __iptunnel_pull_header, so * old pkt_md is no longer valid and we need to reset * it @@ -543,7 +547,6 @@ static int ip6erspan_rcv(struct sk_buff *skb, skb_network_header_len(skb); pkt_md = (struct erspan_metadata *)(gh + gre_hdr_len + sizeof(*ershdr)); - info = &tun_dst->u.tun_info; md = ip_tunnel_info_opts(info); md->version = ver; md2 = &md->u.md2; @@ -551,7 +554,6 @@ static int ip6erspan_rcv(struct sk_buff *skb, ERSPAN_V2_MDSIZE); __set_bit(IP_TUNNEL_ERSPAN_OPT_BIT, info->key.tun_flags); - info->options_len = sizeof(*md); ip6_tnl_rcv(tunnel, skb, tpi, tun_dst, log_ecn_error); From 726fca79cb551fda8ad110b256cfa24b1a5f5ec7 Mon Sep 17 00:00:00 2001 From: Haoxiang Li Date: Thu, 11 Dec 2025 15:37:56 +0800 Subject: [PATCH 1689/2333] fjes: Add missing iounmap in fjes_hw_init() commit 15ef641a0c6728d25a400df73922e80ab2cf029c upstream. In error paths, add fjes_hw_iounmap() to release the resource acquired by fjes_hw_iomap(). Add a goto label to do so. Fixes: 8cdc3f6c5d22 ("fjes: Hardware initialization routine") Cc: stable@vger.kernel.org Signed-off-by: Haoxiang Li Signed-off-by: Simon Horman Reviewed-by: Simon Horman Link: https://patch.msgid.link/20251211073756.101824-1-lihaoxiang@isrc.iscas.ac.cn Signed-off-by: Paolo Abeni Signed-off-by: Greg Kroah-Hartman --- drivers/net/fjes/fjes_hw.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/net/fjes/fjes_hw.c b/drivers/net/fjes/fjes_hw.c index b9b5554ea8620..5ad2673f213d6 100644 --- a/drivers/net/fjes/fjes_hw.c +++ b/drivers/net/fjes/fjes_hw.c @@ -334,7 +334,7 @@ int fjes_hw_init(struct fjes_hw *hw) ret = fjes_hw_reset(hw); if (ret) - return ret; + goto err_iounmap; fjes_hw_set_irqmask(hw, REG_ICTL_MASK_ALL, true); @@ -347,8 +347,10 @@ int fjes_hw_init(struct fjes_hw *hw) hw->max_epid = fjes_hw_get_max_epid(hw); hw->my_epid = fjes_hw_get_my_epid(hw); - if ((hw->max_epid == 0) || (hw->my_epid >= hw->max_epid)) - return -ENXIO; + if ((hw->max_epid == 0) || (hw->my_epid >= hw->max_epid)) { + ret = -ENXIO; + goto err_iounmap; + } ret = fjes_hw_setup(hw); @@ -356,6 +358,10 @@ int fjes_hw_init(struct fjes_hw *hw) hw->hw_info.trace_size = FJES_DEBUG_BUFFER_SIZE; return ret; + +err_iounmap: + fjes_hw_iounmap(hw); + return ret; } void fjes_hw_exit(struct fjes_hw *hw) From 48f9277680925e1a8623d6b2c50aadb7af824ace Mon Sep 17 00:00:00 2001 From: Ankit Garg Date: Fri, 19 Dec 2025 10:29:45 +0000 Subject: [PATCH 1690/2333] gve: defer interrupt enabling until NAPI registration commit 3d970eda003441f66551a91fda16478ac0711617 upstream. Currently, interrupts are automatically enabled immediately upon request. This allows interrupt to fire before the associated NAPI context is fully initialized and cause failures like below: [ 0.946369] Call Trace: [ 0.946369] [ 0.946369] __napi_poll+0x2a/0x1e0 [ 0.946369] net_rx_action+0x2f9/0x3f0 [ 0.946369] handle_softirqs+0xd6/0x2c0 [ 0.946369] ? handle_edge_irq+0xc1/0x1b0 [ 0.946369] __irq_exit_rcu+0xc3/0xe0 [ 0.946369] common_interrupt+0x81/0xa0 [ 0.946369] [ 0.946369] [ 0.946369] asm_common_interrupt+0x22/0x40 [ 0.946369] RIP: 0010:pv_native_safe_halt+0xb/0x10 Use the `IRQF_NO_AUTOEN` flag when requesting interrupts to prevent auto enablement and explicitly enable the interrupt in NAPI initialization path (and disable it during NAPI teardown). This ensures that interrupt lifecycle is strictly coupled with readiness of NAPI context. Cc: stable@vger.kernel.org Fixes: 1dfc2e46117e ("gve: Refactor napi add and remove functions") Signed-off-by: Ankit Garg Reviewed-by: Jordan Rhee Reviewed-by: Joshua Washington Signed-off-by: Harshitha Ramamurthy Link: https://patch.msgid.link/20251219102945.2193617-1-hramamurthy@google.com Signed-off-by: Paolo Abeni Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/google/gve/gve_main.c | 2 +- drivers/net/ethernet/google/gve/gve_utils.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/google/gve/gve_main.c b/drivers/net/ethernet/google/gve/gve_main.c index 1be1b1ef31ee3..e240b7d22a352 100644 --- a/drivers/net/ethernet/google/gve/gve_main.c +++ b/drivers/net/ethernet/google/gve/gve_main.c @@ -558,7 +558,7 @@ static int gve_alloc_notify_blocks(struct gve_priv *priv) block->priv = priv; err = request_irq(priv->msix_vectors[msix_idx].vector, gve_is_gqi(priv) ? gve_intr : gve_intr_dqo, - 0, block->name, block); + IRQF_NO_AUTOEN, block->name, block); if (err) { dev_err(&priv->pdev->dev, "Failed to receive msix vector %d\n", i); diff --git a/drivers/net/ethernet/google/gve/gve_utils.c b/drivers/net/ethernet/google/gve/gve_utils.c index ace9b8698021f..b53b7fcdcdaf1 100644 --- a/drivers/net/ethernet/google/gve/gve_utils.c +++ b/drivers/net/ethernet/google/gve/gve_utils.c @@ -112,11 +112,13 @@ void gve_add_napi(struct gve_priv *priv, int ntfy_idx, netif_napi_add_locked(priv->dev, &block->napi, gve_poll); netif_napi_set_irq_locked(&block->napi, block->irq); + enable_irq(block->irq); } void gve_remove_napi(struct gve_priv *priv, int ntfy_idx) { struct gve_notify_block *block = &priv->ntfy_blocks[ntfy_idx]; + disable_irq(block->irq); netif_napi_del_locked(&block->napi); } From 35bb95c80ddd1a19f02185b6458442f6244e0529 Mon Sep 17 00:00:00 2001 From: Chenghao Duan Date: Wed, 31 Dec 2025 15:19:20 +0800 Subject: [PATCH 1691/2333] LoongArch: Refactor register restoration in ftrace_common_return commit 45cb47c628dfbd1994c619f3eac271a780602826 upstream. Refactor the register restoration sequence in the ftrace_common_return function to clearly distinguish between the logic of normal returns and direct call returns in function tracing scenarios. The logic is as follows: 1. In the case of a normal return, the execution flow returns to the traced function, and ftrace must ensure that the register data is consistent with the state when the function was entered. ra = parent return address; t0 = traced function return address. 2. In the case of a direct call return, the execution flow jumps to the custom trampoline function, and ftrace must ensure that the register data is consistent with the state when ftrace was entered. ra = traced function return address; t0 = parent return address. Cc: stable@vger.kernel.org Fixes: 9cdc3b6a299c ("LoongArch: ftrace: Add direct call support") Signed-off-by: Chenghao Duan Signed-off-by: Huacai Chen Signed-off-by: Greg Kroah-Hartman --- arch/loongarch/kernel/mcount_dyn.S | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/arch/loongarch/kernel/mcount_dyn.S b/arch/loongarch/kernel/mcount_dyn.S index d6b474ad1d5e5..5729c20e5b8b0 100644 --- a/arch/loongarch/kernel/mcount_dyn.S +++ b/arch/loongarch/kernel/mcount_dyn.S @@ -94,7 +94,6 @@ SYM_INNER_LABEL(ftrace_graph_call, SYM_L_GLOBAL) * at the callsite, so there is no need to restore the T series regs. */ ftrace_common_return: - PTR_L ra, sp, PT_R1 PTR_L a0, sp, PT_R4 PTR_L a1, sp, PT_R5 PTR_L a2, sp, PT_R6 @@ -104,12 +103,17 @@ ftrace_common_return: PTR_L a6, sp, PT_R10 PTR_L a7, sp, PT_R11 PTR_L fp, sp, PT_R22 - PTR_L t0, sp, PT_ERA PTR_L t1, sp, PT_R13 - PTR_ADDI sp, sp, PT_SIZE bnez t1, .Ldirect + + PTR_L ra, sp, PT_R1 + PTR_L t0, sp, PT_ERA + PTR_ADDI sp, sp, PT_SIZE jr t0 .Ldirect: + PTR_L t0, sp, PT_R1 + PTR_L ra, sp, PT_ERA + PTR_ADDI sp, sp, PT_SIZE jr t1 SYM_CODE_END(ftrace_common) @@ -161,6 +165,8 @@ SYM_CODE_END(return_to_handler) #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS SYM_CODE_START(ftrace_stub_direct_tramp) UNWIND_HINT_UNDEFINED - jr t0 + move t1, ra + move ra, t0 + jr t1 SYM_CODE_END(ftrace_stub_direct_tramp) #endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */ From 2617bbdead6359de809022fea66b28e48784f040 Mon Sep 17 00:00:00 2001 From: Hengqi Chen Date: Wed, 31 Dec 2025 15:19:20 +0800 Subject: [PATCH 1692/2333] LoongArch: BPF: Zero-extend bpf_tail_call() index commit eb71f5c433e1c6dff089b315881dec40a88a7baf upstream. The bpf_tail_call() index should be treated as a u32 value. Let's zero-extend it to avoid calling wrong BPF progs. See similar fixes for x86 [1]) and arm64 ([2]) for more details. [1]: https://github.com/torvalds/linux/commit/90caccdd8cc0215705f18b92771b449b01e2474a [2]: https://github.com/torvalds/linux/commit/16338a9b3ac30740d49f5dfed81bac0ffa53b9c7 Cc: stable@vger.kernel.org Fixes: 5dc615520c4d ("LoongArch: Add BPF JIT support") Signed-off-by: Hengqi Chen Signed-off-by: Huacai Chen Signed-off-by: Greg Kroah-Hartman --- arch/loongarch/net/bpf_jit.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/loongarch/net/bpf_jit.c b/arch/loongarch/net/bpf_jit.c index f97dc99364017..9d9948e549de4 100644 --- a/arch/loongarch/net/bpf_jit.c +++ b/arch/loongarch/net/bpf_jit.c @@ -280,6 +280,8 @@ static int emit_bpf_tail_call(struct jit_ctx *ctx, int insn) * goto out; */ tc_ninsn = insn ? ctx->offset[insn+1] - ctx->offset[insn] : ctx->offset[0]; + emit_zext_32(ctx, a2, true); + off = offsetof(struct bpf_array, map.max_entries); emit_insn(ctx, ldwu, t1, a1, off); /* bgeu $a2, $t1, jmp_offset */ From 321993a874f571a94b5a596f1132f798c663b56e Mon Sep 17 00:00:00 2001 From: Hengqi Chen Date: Wed, 31 Dec 2025 15:19:20 +0800 Subject: [PATCH 1693/2333] LoongArch: BPF: Sign extend kfunc call arguments commit 3f5a238f24d7b75f9efe324d3539ad388f58536e upstream. The kfunc calls are native calls so they should follow LoongArch calling conventions. Sign extend its arguments properly to avoid kernel panic. This is done by adding a new emit_abi_ext() helper. The emit_abi_ext() helper performs extension in place meaning a value already store in the target register (Note: this is different from the existing sign_extend() helper and thus we can't reuse it). Cc: stable@vger.kernel.org Fixes: 5dc615520c4d ("LoongArch: Add BPF JIT support") Signed-off-by: Hengqi Chen Signed-off-by: Huacai Chen Signed-off-by: Greg Kroah-Hartman --- arch/loongarch/net/bpf_jit.c | 16 ++++++++++++++++ arch/loongarch/net/bpf_jit.h | 26 ++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/arch/loongarch/net/bpf_jit.c b/arch/loongarch/net/bpf_jit.c index 9d9948e549de4..4be8515197ce0 100644 --- a/arch/loongarch/net/bpf_jit.c +++ b/arch/loongarch/net/bpf_jit.c @@ -952,6 +952,22 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext emit_insn(ctx, ldd, REG_TCC, LOONGARCH_GPR_SP, tcc_ptr_off); } + if (insn->src_reg == BPF_PSEUDO_KFUNC_CALL) { + const struct btf_func_model *m; + int i; + + m = bpf_jit_find_kfunc_model(ctx->prog, insn); + if (!m) + return -EINVAL; + + for (i = 0; i < m->nr_args; i++) { + u8 reg = regmap[BPF_REG_1 + i]; + bool sign = m->arg_flags[i] & BTF_FMODEL_SIGNED_ARG; + + emit_abi_ext(ctx, reg, m->arg_size[i], sign); + } + } + move_addr(ctx, t1, func_addr); emit_insn(ctx, jirl, LOONGARCH_GPR_RA, t1, 0); diff --git a/arch/loongarch/net/bpf_jit.h b/arch/loongarch/net/bpf_jit.h index 5697158fd1645..75b6330030a9d 100644 --- a/arch/loongarch/net/bpf_jit.h +++ b/arch/loongarch/net/bpf_jit.h @@ -88,6 +88,32 @@ static inline void emit_sext_32(struct jit_ctx *ctx, enum loongarch_gpr reg, boo emit_insn(ctx, addiw, reg, reg, 0); } +/* Emit proper extension according to ABI requirements. + * Note that it requires a value of size `size` already resides in register `reg`. + */ +static inline void emit_abi_ext(struct jit_ctx *ctx, int reg, u8 size, bool sign) +{ + /* ABI requires unsigned char/short to be zero-extended */ + if (!sign && (size == 1 || size == 2)) + return; + + switch (size) { + case 1: + emit_insn(ctx, extwb, reg, reg); + break; + case 2: + emit_insn(ctx, extwh, reg, reg); + break; + case 4: + emit_insn(ctx, addiw, reg, reg, 0); + break; + case 8: + break; + default: + pr_warn("bpf_jit: invalid size %d for extension\n", size); + } +} + static inline void move_addr(struct jit_ctx *ctx, enum loongarch_gpr rd, u64 addr) { u64 imm_11_0, imm_31_12, imm_51_32, imm_63_52; From 8b3c00c060187dccd9961877ba328cd969522dba Mon Sep 17 00:00:00 2001 From: Chenghao Duan Date: Wed, 31 Dec 2025 15:19:20 +0800 Subject: [PATCH 1694/2333] LoongArch: BPF: Save return address register ra to t0 before trampoline commit d314e1f48260cef3f869e3edc02a02c8a48b08e1 upstream. Modify the build_prologue() function to ensure the return address register ra is saved to t0 before entering trampoline operations. This change ensures the accurate return address handling when a BPF program calls another BPF program, preventing errors in the BPF-to-BPF call chain. Cc: stable@vger.kernel.org Fixes: 677e6123e3d2 ("LoongArch: BPF: Disable trampoline for kernel module function trace") Signed-off-by: Chenghao Duan Signed-off-by: Huacai Chen Signed-off-by: Greg Kroah-Hartman --- arch/loongarch/net/bpf_jit.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/loongarch/net/bpf_jit.c b/arch/loongarch/net/bpf_jit.c index 4be8515197ce0..1d09c0d8082e1 100644 --- a/arch/loongarch/net/bpf_jit.c +++ b/arch/loongarch/net/bpf_jit.c @@ -139,6 +139,7 @@ static void build_prologue(struct jit_ctx *ctx) stack_adjust = round_up(stack_adjust, 16); stack_adjust += bpf_stack_adjust; + move_reg(ctx, LOONGARCH_GPR_T0, LOONGARCH_GPR_RA); /* Reserve space for the move_imm + jirl instruction */ for (i = 0; i < LOONGARCH_LONG_JUMP_NINSNS; i++) emit_insn(ctx, nop); From 85fdef3dcc1007ba8619589fa38014628f88854f Mon Sep 17 00:00:00 2001 From: Chenghao Duan Date: Wed, 31 Dec 2025 15:19:21 +0800 Subject: [PATCH 1695/2333] LoongArch: BPF: Enable trampoline-based tracing for module functions commit 26138762d9a27a7f1c33f467c4123c600f64a36e upstream. Remove the previous restrictions that blocked the tracing of kernel module functions. Fix the issue that previously caused kernel lockups when attempting to trace module functions. Before entering the trampoline code, the return address register ra shall store the address of the next assembly instruction after the 'bl trampoline' instruction, which is the traced function address, and the register t0 shall store the parent function return address. Refine the trampoline return logic to ensure that register data remains correct when returning to both the traced function and the parent function. Before this patch was applied, the module_attach test in selftests/bpf encountered a deadlock issue. This was caused by an incorrect jump address after the trampoline execution, which resulted in an infinite loop within the module function. Cc: stable@vger.kernel.org Fixes: 677e6123e3d2 ("LoongArch: BPF: Disable trampoline for kernel module function trace") Signed-off-by: Chenghao Duan Signed-off-by: Huacai Chen Signed-off-by: Greg Kroah-Hartman --- arch/loongarch/net/bpf_jit.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/arch/loongarch/net/bpf_jit.c b/arch/loongarch/net/bpf_jit.c index 1d09c0d8082e1..39753ce2d017e 100644 --- a/arch/loongarch/net/bpf_jit.c +++ b/arch/loongarch/net/bpf_jit.c @@ -1284,7 +1284,7 @@ static int emit_jump_or_nops(void *target, void *ip, u32 *insns, bool is_call) return 0; } - return emit_jump_and_link(&ctx, is_call ? LOONGARCH_GPR_T0 : LOONGARCH_GPR_ZERO, (u64)target); + return emit_jump_and_link(&ctx, is_call ? LOONGARCH_GPR_RA : LOONGARCH_GPR_ZERO, (u64)target); } static int emit_call(struct jit_ctx *ctx, u64 addr) @@ -1638,14 +1638,12 @@ static int __arch_prepare_bpf_trampoline(struct jit_ctx *ctx, struct bpf_tramp_i /* To traced function */ /* Ftrace jump skips 2 NOP instructions */ - if (is_kernel_text((unsigned long)orig_call)) + if (is_kernel_text((unsigned long)orig_call) || + is_module_text_address((unsigned long)orig_call)) orig_call += LOONGARCH_FENTRY_NBYTES; /* Direct jump skips 5 NOP instructions */ else if (is_bpf_text_address((unsigned long)orig_call)) orig_call += LOONGARCH_BPF_FENTRY_NBYTES; - /* Module tracing not supported - cause kernel lockups */ - else if (is_module_text_address((unsigned long)orig_call)) - return -ENOTSUPP; if (flags & BPF_TRAMP_F_CALL_ORIG) { move_addr(ctx, LOONGARCH_GPR_A0, (const u64)im); @@ -1738,12 +1736,16 @@ static int __arch_prepare_bpf_trampoline(struct jit_ctx *ctx, struct bpf_tramp_i emit_insn(ctx, ldd, LOONGARCH_GPR_FP, LOONGARCH_GPR_SP, 0); emit_insn(ctx, addid, LOONGARCH_GPR_SP, LOONGARCH_GPR_SP, 16); - if (flags & BPF_TRAMP_F_SKIP_FRAME) + if (flags & BPF_TRAMP_F_SKIP_FRAME) { /* return to parent function */ - emit_insn(ctx, jirl, LOONGARCH_GPR_ZERO, LOONGARCH_GPR_RA, 0); - else - /* return to traced function */ + move_reg(ctx, LOONGARCH_GPR_RA, LOONGARCH_GPR_T0); emit_insn(ctx, jirl, LOONGARCH_GPR_ZERO, LOONGARCH_GPR_T0, 0); + } else { + /* return to traced function */ + move_reg(ctx, LOONGARCH_GPR_T1, LOONGARCH_GPR_RA); + move_reg(ctx, LOONGARCH_GPR_RA, LOONGARCH_GPR_T0); + emit_insn(ctx, jirl, LOONGARCH_GPR_ZERO, LOONGARCH_GPR_T1, 0); + } } ret = ctx->idx; From a6493ebd6dd5160764fb8d784a0e28b14b8a4d7b Mon Sep 17 00:00:00 2001 From: Chenghao Duan Date: Wed, 31 Dec 2025 15:19:21 +0800 Subject: [PATCH 1696/2333] LoongArch: BPF: Adjust the jump offset of tail calls commit 61319d15a56093358c6822d30659fe2941f589f1 upstream. Call the next bpf prog and skip the first instruction of TCC initialization. A total of 7 instructions are skipped: 'move t0, ra' 1 inst 'move_imm + jirl' 5 inst 'addid REG_TCC, zero, 0' 1 inst Relevant test cases: the tailcalls test item in selftests/bpf. Cc: stable@vger.kernel.org Fixes: 677e6123e3d2 ("LoongArch: BPF: Disable trampoline for kernel module function trace") Signed-off-by: Chenghao Duan Signed-off-by: Huacai Chen Signed-off-by: Greg Kroah-Hartman --- arch/loongarch/net/bpf_jit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/loongarch/net/bpf_jit.c b/arch/loongarch/net/bpf_jit.c index 39753ce2d017e..95c214e2cf096 100644 --- a/arch/loongarch/net/bpf_jit.c +++ b/arch/loongarch/net/bpf_jit.c @@ -239,7 +239,7 @@ static void __build_epilogue(struct jit_ctx *ctx, bool is_tail_call) * Call the next bpf prog and skip the first instruction * of TCC initialization. */ - emit_insn(ctx, jirl, LOONGARCH_GPR_ZERO, LOONGARCH_GPR_T3, 6); + emit_insn(ctx, jirl, LOONGARCH_GPR_ZERO, LOONGARCH_GPR_T3, 7); } } From c07dc84ed67c5a182273171639bacbbb87c12175 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 1 Dec 2025 17:09:55 -0500 Subject: [PATCH 1697/2333] nfsd: fix nfsd_file reference leak in nfsd4_add_rdaccess_to_wrdeleg() commit 8072e34e1387d03102b788677d491e2bcceef6f5 upstream. nfsd4_add_rdaccess_to_wrdeleg() unconditionally overwrites fp->fi_fds[O_RDONLY] with a newly acquired nfsd_file. However, if the client already has a SHARE_ACCESS_READ open from a previous OPEN operation, this action overwrites the existing pointer without releasing its reference, orphaning the previous reference. Additionally, the function originally stored the same nfsd_file pointer in both fp->fi_fds[O_RDONLY] and fp->fi_rdeleg_file with only a single reference. When put_deleg_file() runs, it clears fi_rdeleg_file and calls nfs4_file_put_access() to release the file. However, nfs4_file_put_access() only releases fi_fds[O_RDONLY] when the fi_access[O_RDONLY] counter drops to zero. If another READ open exists on the file, the counter remains elevated and the nfsd_file reference from the delegation is never released. This potentially causes open conflicts on that file. Then, on server shutdown, these leaks cause __nfsd_file_cache_purge() to encounter files with an elevated reference count that cannot be cleaned up, ultimately triggering a BUG() in kmem_cache_destroy() because there are still nfsd_file objects allocated in that cache. Fixes: e7a8ebc305f2 ("NFSD: Offer write delegation for OPEN with OPEN4_SHARE_ACCESS_WRITE") Cc: stable@vger.kernel.org Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever Signed-off-by: Greg Kroah-Hartman --- fs/nfsd/nfs4state.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 8a69605002174..302974c922234 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -1218,8 +1218,10 @@ static void put_deleg_file(struct nfs4_file *fp) if (nf) nfsd_file_put(nf); - if (rnf) + if (rnf) { + nfsd_file_put(rnf); nfs4_file_put_access(fp, NFS4_SHARE_ACCESS_READ); + } } static void nfsd4_finalize_deleg_timestamps(struct nfs4_delegation *dp, struct file *f) @@ -6253,10 +6255,14 @@ nfsd4_add_rdaccess_to_wrdeleg(struct svc_rqst *rqstp, struct nfsd4_open *open, fp = stp->st_stid.sc_file; spin_lock(&fp->fi_lock); __nfs4_file_get_access(fp, NFS4_SHARE_ACCESS_READ); - fp = stp->st_stid.sc_file; - fp->fi_fds[O_RDONLY] = nf; - fp->fi_rdeleg_file = nf; + if (!fp->fi_fds[O_RDONLY]) { + fp->fi_fds[O_RDONLY] = nf; + nf = NULL; + } + fp->fi_rdeleg_file = nfsd_file_get(fp->fi_fds[O_RDONLY]); spin_unlock(&fp->fi_lock); + if (nf) + nfsd_file_put(nf); } return true; } From 1285073c878aac838dfadb6e19acdd65c30c2a76 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Wed, 3 Dec 2025 10:52:15 -0500 Subject: [PATCH 1698/2333] nfsd: use ATTR_DELEG in nfsd4_finalize_deleg_timestamps() commit 8f9e967830ff32ab7756f530a36adf74a9f12b76 upstream. When finalizing timestamps that have never been updated and preparing to release the delegation lease, the notify_change() call can trigger a delegation break, and fail to update the timestamps. When this happens, there will be messages like this in dmesg: [ 2709.375785] Unable to update timestamps on inode 00:39:263: -11 Since this code is going to release the lease just after updating the timestamps, breaking the delegation is undesirable. Fix this by setting ATTR_DELEG in ia_valid, in order to avoid the delegation break. Fixes: e5e9b24ab8fa ("nfsd: freeze c/mtime updates with outstanding WRITE_ATTRS delegation") Cc: stable@vger.kernel.org Signed-off-by: Jeff Layton Signed-off-by: Chuck Lever Signed-off-by: Greg Kroah-Hartman --- fs/nfsd/nfs4state.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 302974c922234..e3f33d3e291cf 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -1226,7 +1226,7 @@ static void put_deleg_file(struct nfs4_file *fp) static void nfsd4_finalize_deleg_timestamps(struct nfs4_delegation *dp, struct file *f) { - struct iattr ia = { .ia_valid = ATTR_ATIME | ATTR_CTIME | ATTR_MTIME }; + struct iattr ia = { .ia_valid = ATTR_ATIME | ATTR_CTIME | ATTR_MTIME | ATTR_DELEG }; struct inode *inode = file_inode(f); int ret; From a78ee50545ee6dbf587764c72581c341dddef2cd Mon Sep 17 00:00:00 2001 From: Haoxiang Li Date: Sat, 6 Dec 2025 15:38:42 +0800 Subject: [PATCH 1699/2333] nfsd: Drop the client reference in client_states_open() commit 1f941b2c23fd34c6f3b76d36f9d0a2528fa92b8f upstream. In error path, call drop_client() to drop the reference obtained by get_nfsdfs_clp(). Fixes: 78599c42ae3c ("nfsd4: add file to display list of client's opens") Cc: stable@vger.kernel.org Reviewed-by: Jeff Layton Signed-off-by: Haoxiang Li Signed-off-by: Chuck Lever Signed-off-by: Greg Kroah-Hartman --- fs/nfsd/nfs4state.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index e3f33d3e291cf..bdd20fddbb986 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -3099,8 +3099,10 @@ static int client_states_open(struct inode *inode, struct file *file) return -ENXIO; ret = seq_open(file, &states_seq_ops); - if (ret) + if (ret) { + drop_client(clp); return ret; + } s = file->private_data; s->private = clp; return 0; From c9a8cd3ac85cdf5de80c8a45536974f4f6a64bbe Mon Sep 17 00:00:00 2001 From: Ethan Nelson-Moore Date: Sun, 21 Dec 2025 00:24:00 -0800 Subject: [PATCH 1700/2333] net: usb: sr9700: fix incorrect command used to write single register commit fa0b198be1c6775bc7804731a43be5d899d19e7a upstream. This fixes the device failing to initialize with "error reading MAC address" for me, probably because the incorrect write of NCR_RST to SR_NCR is not actually resetting the device. Fixes: c9b37458e95629b1d1171457afdcc1bf1eb7881d ("USB2NET : SR9700 : One chip USB 1.1 USB2NET SR9700Device Driver Support") Cc: stable@vger.kernel.org Signed-off-by: Ethan Nelson-Moore Link: https://patch.msgid.link/20251221082400.50688-1-enelsonmoore@gmail.com Signed-off-by: Paolo Abeni Signed-off-by: Greg Kroah-Hartman --- drivers/net/usb/sr9700.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/usb/sr9700.c b/drivers/net/usb/sr9700.c index 091bc2aca7e8e..5d97e95a17b0d 100644 --- a/drivers/net/usb/sr9700.c +++ b/drivers/net/usb/sr9700.c @@ -52,7 +52,7 @@ static int sr_read_reg(struct usbnet *dev, u8 reg, u8 *value) static int sr_write_reg(struct usbnet *dev, u8 reg, u8 value) { - return usbnet_write_cmd(dev, SR_WR_REGS, SR_REQ_WR_REG, + return usbnet_write_cmd(dev, SR_WR_REG, SR_REQ_WR_REG, value, reg, NULL, 0); } @@ -65,7 +65,7 @@ static void sr_write_async(struct usbnet *dev, u8 reg, u16 length, static void sr_write_reg_async(struct usbnet *dev, u8 reg, u8 value) { - usbnet_write_cmd_async(dev, SR_WR_REGS, SR_REQ_WR_REG, + usbnet_write_cmd_async(dev, SR_WR_REG, SR_REQ_WR_REG, value, reg, NULL, 0); } From 2431c1e4765a93f9358da530d54a5c20d3f5ed5a Mon Sep 17 00:00:00 2001 From: Miaoqian Lin Date: Thu, 11 Dec 2025 12:13:13 +0400 Subject: [PATCH 1701/2333] net: phy: mediatek: fix nvmem cell reference leak in mt798x_phy_calibration commit 1e5a541420b8c6d87d88eb50b6b978cdeafee1c9 upstream. When nvmem_cell_read() fails in mt798x_phy_calibration(), the function returns without calling nvmem_cell_put(), leaking the cell reference. Move nvmem_cell_put() right after nvmem_cell_read() to ensure the cell reference is always released regardless of the read result. Found via static analysis and code review. Fixes: 98c485eaf509 ("net: phy: add driver for MediaTek SoC built-in GE PHYs") Cc: stable@vger.kernel.org Signed-off-by: Miaoqian Lin Reviewed-by: Daniel Golle Reviewed-by: Andrew Lunn Link: https://patch.msgid.link/20251211081313.2368460-1-linmq006@gmail.com Signed-off-by: Paolo Abeni Signed-off-by: Greg Kroah-Hartman --- drivers/net/phy/mediatek/mtk-ge-soc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/phy/mediatek/mtk-ge-soc.c b/drivers/net/phy/mediatek/mtk-ge-soc.c index cd09fbf92ef23..2c4bbc236202b 100644 --- a/drivers/net/phy/mediatek/mtk-ge-soc.c +++ b/drivers/net/phy/mediatek/mtk-ge-soc.c @@ -1167,9 +1167,9 @@ static int mt798x_phy_calibration(struct phy_device *phydev) } buf = (u32 *)nvmem_cell_read(cell, &len); + nvmem_cell_put(cell); if (IS_ERR(buf)) return PTR_ERR(buf); - nvmem_cell_put(cell); if (!buf[0] || !buf[1] || !buf[2] || !buf[3] || len < 4 * sizeof(u32)) { phydev_err(phydev, "invalid efuse data\n"); From f3a8a7c1aa278f2378b2f3a10500c6674dffdfda Mon Sep 17 00:00:00 2001 From: Deepanshu Kartikey Date: Thu, 18 Dec 2025 06:53:54 +0530 Subject: [PATCH 1702/2333] net: nfc: fix deadlock between nfc_unregister_device and rfkill_fop_write commit 1ab526d97a57e44d26fadcc0e9adeb9c0c0182f5 upstream. A deadlock can occur between nfc_unregister_device() and rfkill_fop_write() due to lock ordering inversion between device_lock and rfkill_global_mutex. The problematic lock order is: Thread A (rfkill_fop_write): rfkill_fop_write() mutex_lock(&rfkill_global_mutex) rfkill_set_block() nfc_rfkill_set_block() nfc_dev_down() device_lock(&dev->dev) <- waits for device_lock Thread B (nfc_unregister_device): nfc_unregister_device() device_lock(&dev->dev) rfkill_unregister() mutex_lock(&rfkill_global_mutex) <- waits for rfkill_global_mutex This creates a classic ABBA deadlock scenario. Fix this by moving rfkill_unregister() and rfkill_destroy() outside the device_lock critical section. Store the rfkill pointer in a local variable before releasing the lock, then call rfkill_unregister() after releasing device_lock. This change is safe because rfkill_fop_write() holds rfkill_global_mutex while calling the rfkill callbacks, and rfkill_unregister() also acquires rfkill_global_mutex before cleanup. Therefore, rfkill_unregister() will wait for any ongoing callback to complete before proceeding, and device_del() is only called after rfkill_unregister() returns, preventing any use-after-free. The similar lock ordering in nfc_register_device() (device_lock -> rfkill_global_mutex via rfkill_register) is safe because during registration the device is not yet in rfkill_list, so no concurrent rfkill operations can occur on this device. Fixes: 3e3b5dfcd16a ("NFC: reorder the logic in nfc_{un,}register_device") Cc: stable@vger.kernel.org Reported-by: syzbot+4ef89409a235d804c6c2@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=4ef89409a235d804c6c2 Link: https://lore.kernel.org/all/20251217054908.178907-1-kartikey406@gmail.com/T/ [v1] Signed-off-by: Deepanshu Kartikey Reviewed-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20251218012355.279940-1-kartikey406@gmail.com Signed-off-by: Paolo Abeni Signed-off-by: Greg Kroah-Hartman --- net/nfc/core.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/net/nfc/core.c b/net/nfc/core.c index ae1c842f9c642..82f023f377541 100644 --- a/net/nfc/core.c +++ b/net/nfc/core.c @@ -1154,6 +1154,7 @@ EXPORT_SYMBOL(nfc_register_device); void nfc_unregister_device(struct nfc_dev *dev) { int rc; + struct rfkill *rfk = NULL; pr_debug("dev_name=%s\n", dev_name(&dev->dev)); @@ -1164,13 +1165,17 @@ void nfc_unregister_device(struct nfc_dev *dev) device_lock(&dev->dev); if (dev->rfkill) { - rfkill_unregister(dev->rfkill); - rfkill_destroy(dev->rfkill); + rfk = dev->rfkill; dev->rfkill = NULL; } dev->shutting_down = true; device_unlock(&dev->dev); + if (rfk) { + rfkill_unregister(rfk); + rfkill_destroy(rfk); + } + if (dev->ops->check_presence) { timer_delete_sync(&dev->check_pres_timer); cancel_work_sync(&dev->check_pres_work); From 64b6cd5f7b5abcd4f4552b43664d33abafd4c67f Mon Sep 17 00:00:00 2001 From: Xiaolei Wang Date: Mon, 22 Dec 2025 09:56:24 +0800 Subject: [PATCH 1703/2333] net: macb: Relocate mog_init_rings() callback from macb_mac_link_up() to macb_open() commit 99537d5c476cada9cf75aef9fa75579a31faadb9 upstream. In the non-RT kernel, local_bh_disable() merely disables preemption, whereas it maps to an actual spin lock in the RT kernel. Consequently, when attempting to refill RX buffers via netdev_alloc_skb() in macb_mac_link_up(), a deadlock scenario arises as follows: WARNING: possible circular locking dependency detected 6.18.0-08691-g2061f18ad76e #39 Not tainted ------------------------------------------------------ kworker/0:0/8 is trying to acquire lock: ffff00080369bbe0 (&bp->lock){+.+.}-{3:3}, at: macb_start_xmit+0x808/0xb7c but task is already holding lock: ffff000803698e58 (&queue->tx_ptr_lock){+...}-{3:3}, at: macb_start_xmit +0x148/0xb7c which lock already depends on the new lock. the existing dependency chain (in reverse order) is: -> #3 (&queue->tx_ptr_lock){+...}-{3:3}: rt_spin_lock+0x50/0x1f0 macb_start_xmit+0x148/0xb7c dev_hard_start_xmit+0x94/0x284 sch_direct_xmit+0x8c/0x37c __dev_queue_xmit+0x708/0x1120 neigh_resolve_output+0x148/0x28c ip6_finish_output2+0x2c0/0xb2c __ip6_finish_output+0x114/0x308 ip6_output+0xc4/0x4a4 mld_sendpack+0x220/0x68c mld_ifc_work+0x2a8/0x4f4 process_one_work+0x20c/0x5f8 worker_thread+0x1b0/0x35c kthread+0x144/0x200 ret_from_fork+0x10/0x20 -> #2 (_xmit_ETHER#2){+...}-{3:3}: rt_spin_lock+0x50/0x1f0 sch_direct_xmit+0x11c/0x37c __dev_queue_xmit+0x708/0x1120 neigh_resolve_output+0x148/0x28c ip6_finish_output2+0x2c0/0xb2c __ip6_finish_output+0x114/0x308 ip6_output+0xc4/0x4a4 mld_sendpack+0x220/0x68c mld_ifc_work+0x2a8/0x4f4 process_one_work+0x20c/0x5f8 worker_thread+0x1b0/0x35c kthread+0x144/0x200 ret_from_fork+0x10/0x20 -> #1 ((softirq_ctrl.lock)){+.+.}-{3:3}: lock_release+0x250/0x348 __local_bh_enable_ip+0x7c/0x240 __netdev_alloc_skb+0x1b4/0x1d8 gem_rx_refill+0xdc/0x240 gem_init_rings+0xb4/0x108 macb_mac_link_up+0x9c/0x2b4 phylink_resolve+0x170/0x614 process_one_work+0x20c/0x5f8 worker_thread+0x1b0/0x35c kthread+0x144/0x200 ret_from_fork+0x10/0x20 -> #0 (&bp->lock){+.+.}-{3:3}: __lock_acquire+0x15a8/0x2084 lock_acquire+0x1cc/0x350 rt_spin_lock+0x50/0x1f0 macb_start_xmit+0x808/0xb7c dev_hard_start_xmit+0x94/0x284 sch_direct_xmit+0x8c/0x37c __dev_queue_xmit+0x708/0x1120 neigh_resolve_output+0x148/0x28c ip6_finish_output2+0x2c0/0xb2c __ip6_finish_output+0x114/0x308 ip6_output+0xc4/0x4a4 mld_sendpack+0x220/0x68c mld_ifc_work+0x2a8/0x4f4 process_one_work+0x20c/0x5f8 worker_thread+0x1b0/0x35c kthread+0x144/0x200 ret_from_fork+0x10/0x20 other info that might help us debug this: Chain exists of: &bp->lock --> _xmit_ETHER#2 --> &queue->tx_ptr_lock Possible unsafe locking scenario: CPU0 CPU1 ---- ---- lock(&queue->tx_ptr_lock); lock(_xmit_ETHER#2); lock(&queue->tx_ptr_lock); lock(&bp->lock); *** DEADLOCK *** Call trace: show_stack+0x18/0x24 (C) dump_stack_lvl+0xa0/0xf0 dump_stack+0x18/0x24 print_circular_bug+0x28c/0x370 check_noncircular+0x198/0x1ac __lock_acquire+0x15a8/0x2084 lock_acquire+0x1cc/0x350 rt_spin_lock+0x50/0x1f0 macb_start_xmit+0x808/0xb7c dev_hard_start_xmit+0x94/0x284 sch_direct_xmit+0x8c/0x37c __dev_queue_xmit+0x708/0x1120 neigh_resolve_output+0x148/0x28c ip6_finish_output2+0x2c0/0xb2c __ip6_finish_output+0x114/0x308 ip6_output+0xc4/0x4a4 mld_sendpack+0x220/0x68c mld_ifc_work+0x2a8/0x4f4 process_one_work+0x20c/0x5f8 worker_thread+0x1b0/0x35c kthread+0x144/0x200 ret_from_fork+0x10/0x20 Notably, invoking the mog_init_rings() callback upon link establishment is unnecessary. Instead, we can exclusively call mog_init_rings() within the ndo_open() callback. This adjustment resolves the deadlock issue. Furthermore, since MACB_CAPS_MACB_IS_EMAC cases do not use mog_init_rings() when opening the network interface via at91ether_open(), moving mog_init_rings() to macb_open() also eliminates the MACB_CAPS_MACB_IS_EMAC check. Fixes: 633e98a711ac ("net: macb: use resolved link config in mac_link_up()") Cc: stable@vger.kernel.org Suggested-by: Kevin Hao Signed-off-by: Xiaolei Wang Link: https://patch.msgid.link/20251222015624.1994551-1-xiaolei.wang@windriver.com Signed-off-by: Paolo Abeni Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/cadence/macb_main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c index ca2386b834737..064fccdcf6994 100644 --- a/drivers/net/ethernet/cadence/macb_main.c +++ b/drivers/net/ethernet/cadence/macb_main.c @@ -744,7 +744,6 @@ static void macb_mac_link_up(struct phylink_config *config, /* Initialize rings & buffers as clearing MACB_BIT(TE) in link down * cleared the pipeline and control registers. */ - bp->macbgem_ops.mog_init_rings(bp); macb_init_buffers(bp); for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) @@ -2991,6 +2990,8 @@ static int macb_open(struct net_device *dev) goto pm_exit; } + bp->macbgem_ops.mog_init_rings(bp); + for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) { napi_enable(&queue->napi_rx); napi_enable(&queue->napi_tx); From ace965a386253c9a4eba1296d54b79a90f342a1c Mon Sep 17 00:00:00 2001 From: Armin Wolf Date: Sun, 28 Dec 2025 22:41:31 +0100 Subject: [PATCH 1704/2333] platform/x86: samsung-galaxybook: Fix problematic pointer cast MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit d37cd54ebeac37a763fbf303ed25f8a6e98328ff upstream. A user reported that reading the charge threshold on his device results in very strange values (like 78497792) being returned. The reason for this seems to be the fact that the driver casts the int pointer to an u8 pointer, leaving the last 3 bytes of the destination uninitialized. Fix this by using a temporary variable instead. Cc: stable@vger.kernel.org Fixes: 56f529ce4370 ("platform/x86: samsung-galaxybook: Add samsung-galaxybook driver") Reported-by: Gianni Ceccarelli Closes: https://lore.kernel.org/platform-driver-x86/20251228115556.14362d66@thenautilus.net/ Tested-by: Gianni Ceccarelli Signed-off-by: Armin Wolf Link: https://patch.msgid.link/20251228214217.35972-1-W_Armin@gmx.de Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen Signed-off-by: Greg Kroah-Hartman --- drivers/platform/x86/samsung-galaxybook.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/platform/x86/samsung-galaxybook.c b/drivers/platform/x86/samsung-galaxybook.c index 3c13e13d48858..755cb82bdb606 100644 --- a/drivers/platform/x86/samsung-galaxybook.c +++ b/drivers/platform/x86/samsung-galaxybook.c @@ -442,12 +442,13 @@ static int galaxybook_battery_ext_property_get(struct power_supply *psy, union power_supply_propval *val) { struct samsung_galaxybook *galaxybook = ext_data; + u8 value; int err; if (psp != POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD) return -EINVAL; - err = charge_control_end_threshold_acpi_get(galaxybook, (u8 *)&val->intval); + err = charge_control_end_threshold_acpi_get(galaxybook, &value); if (err) return err; @@ -455,8 +456,10 @@ static int galaxybook_battery_ext_property_get(struct power_supply *psy, * device stores "no end threshold" as 0 instead of 100; * if device has 0, report 100 */ - if (val->intval == 0) - val->intval = 100; + if (value == 0) + value = 100; + + val->intval = value; return 0; } From d1cb71222a27a31f29ed777edb46069ec808ded4 Mon Sep 17 00:00:00 2001 From: Kurt Borja Date: Fri, 5 Dec 2025 13:50:10 -0500 Subject: [PATCH 1705/2333] platform/x86: alienware-wmi-wmax: Add support for new Area-51 laptops MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 433f7744cb302ac22800dc0cd50494319ce64ba0 upstream. Add AWCC support for new Alienware Area-51 laptops. Cc: stable@vger.kernel.org Signed-off-by: Kurt Borja Reviewed-by: Ilpo Järvinen Link: https://patch.msgid.link/20251205-area-51-v1-1-d2cb13530851@gmail.com Signed-off-by: Ilpo Järvinen Signed-off-by: Greg Kroah-Hartman --- drivers/platform/x86/dell/alienware-wmi-wmax.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/platform/x86/dell/alienware-wmi-wmax.c b/drivers/platform/x86/dell/alienware-wmi-wmax.c index fadf7aac6779f..b7b684fda22e0 100644 --- a/drivers/platform/x86/dell/alienware-wmi-wmax.c +++ b/drivers/platform/x86/dell/alienware-wmi-wmax.c @@ -89,6 +89,22 @@ static struct awcc_quirks generic_quirks = { static struct awcc_quirks empty_quirks; static const struct dmi_system_id awcc_dmi_table[] __initconst = { + { + .ident = "Alienware 16 Area-51", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Alienware"), + DMI_MATCH(DMI_PRODUCT_NAME, "Alienware 16 Area-51"), + }, + .driver_data = &g_series_quirks, + }, + { + .ident = "Alienware 18 Area-51", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Alienware"), + DMI_MATCH(DMI_PRODUCT_NAME, "Alienware 18 Area-51"), + }, + .driver_data = &g_series_quirks, + }, { .ident = "Alienware 16 Aurora", .matches = { From 7ba7c591ce05f446f68343933978a6d07618f380 Mon Sep 17 00:00:00 2001 From: Kurt Borja Date: Fri, 5 Dec 2025 13:50:11 -0500 Subject: [PATCH 1706/2333] platform/x86: alienware-wmi-wmax: Add AWCC support for Alienware x16 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit a584644a490d276907e56817694859eaac2a4199 upstream. Add AWCC support for Alienware x16 laptops. Cc: stable@vger.kernel.org Signed-off-by: Kurt Borja Reviewed-by: Ilpo Järvinen Link: https://patch.msgid.link/20251205-area-51-v1-2-d2cb13530851@gmail.com Signed-off-by: Ilpo Järvinen Signed-off-by: Greg Kroah-Hartman --- drivers/platform/x86/dell/alienware-wmi-wmax.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/platform/x86/dell/alienware-wmi-wmax.c b/drivers/platform/x86/dell/alienware-wmi-wmax.c index b7b684fda22e0..baea397e0530b 100644 --- a/drivers/platform/x86/dell/alienware-wmi-wmax.c +++ b/drivers/platform/x86/dell/alienware-wmi-wmax.c @@ -177,6 +177,14 @@ static const struct dmi_system_id awcc_dmi_table[] __initconst = { }, .driver_data = &generic_quirks, }, + { + .ident = "Alienware x16", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Alienware"), + DMI_MATCH(DMI_PRODUCT_NAME, "Alienware x16"), + }, + .driver_data = &g_series_quirks, + }, { .ident = "Alienware x17", .matches = { From 3dad9330f71f7f0d2d63cf4ddc28d9a1323ac5e7 Mon Sep 17 00:00:00 2001 From: Kurt Borja Date: Fri, 5 Dec 2025 13:50:12 -0500 Subject: [PATCH 1707/2333] platform/x86: alienware-wmi-wmax: Add support for Alienware 16X Aurora MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 7f3c2499da24551968640528fee9aed3bb4f0c3f upstream. Add AWCC support for Alienware 16X Aurora laptops. Cc: stable@vger.kernel.org Signed-off-by: Kurt Borja Reviewed-by: Ilpo Järvinen Link: https://patch.msgid.link/20251205-area-51-v1-3-d2cb13530851@gmail.com Signed-off-by: Ilpo Järvinen Signed-off-by: Greg Kroah-Hartman --- drivers/platform/x86/dell/alienware-wmi-wmax.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/platform/x86/dell/alienware-wmi-wmax.c b/drivers/platform/x86/dell/alienware-wmi-wmax.c index baea397e0530b..01af6dde9057f 100644 --- a/drivers/platform/x86/dell/alienware-wmi-wmax.c +++ b/drivers/platform/x86/dell/alienware-wmi-wmax.c @@ -97,6 +97,14 @@ static const struct dmi_system_id awcc_dmi_table[] __initconst = { }, .driver_data = &g_series_quirks, }, + { + .ident = "Alienware 16X Aurora", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Alienware"), + DMI_MATCH(DMI_PRODUCT_NAME, "Alienware 16X Aurora"), + }, + .driver_data = &g_series_quirks, + }, { .ident = "Alienware 18 Area-51", .matches = { From 60da8c352cdc37d6587977da7c9ac186e14dc0ff Mon Sep 17 00:00:00 2001 From: "Mario Limonciello (AMD)" Date: Sat, 29 Nov 2025 19:46:31 -0600 Subject: [PATCH 1708/2333] Revert "drm/amd: Skip power ungate during suspend for VPE" commit 3925683515e93844be204381d2d5a1df5de34f31 upstream. Skipping power ungate exposed some scenarios that will fail like below: ``` amdgpu: Register(0) [regVPEC_QUEUE_RESET_REQ] failed to reach value 0x00000000 != 0x00000001n amdgpu 0000:c1:00.0: amdgpu: VPE queue reset failed ... amdgpu: [drm] *ERROR* wait_for_completion_timeout timeout! ``` The underlying s2idle issue that prompted this commit is going to be fixed in BIOS. This reverts commit 2a6c826cfeedd7714611ac115371a959ead55bda. Fixes: 2a6c826cfeed ("drm/amd: Skip power ungate during suspend for VPE") Cc: stable@vger.kernel.org Signed-off-by: Mario Limonciello (AMD) Acked-by: Alex Deucher Reported-by: Konstantin Closes: https://bugzilla.kernel.org/show_bug.cgi?id=220812 Reported-by: Matthew Schwartz Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index 843770e61e421..0cba31ec025c0 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -3416,11 +3416,10 @@ int amdgpu_device_set_pg_state(struct amdgpu_device *adev, (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_GFX || adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_SDMA)) continue; - /* skip CG for VCE/UVD/VPE, it's handled specially */ + /* skip CG for VCE/UVD, it's handled specially */ if (adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_UVD && adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_VCE && adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_VCN && - adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_VPE && adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_JPEG && adev->ip_blocks[i].version->funcs->set_powergating_state) { /* enable powergating to save power */ From 8b74d0d7f6a512ed50571015d649cf9861008309 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 13 Nov 2025 15:57:43 -0500 Subject: [PATCH 1709/2333] drm/amdgpu/gmc12: add amdgpu_vm_handle_fault() handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit ff28ff98db6a8eeb469e02fb8bd1647b353232a9 upstream. We need to call amdgpu_vm_handle_fault() on page fault on all gfx9 and newer parts to properly update the page tables, not just for recoverable page faults. Cc: stable@vger.kernel.org Reviewed-by: Timur Kristóf Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/amd/amdgpu/gmc_v12_0.c | 27 ++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v12_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v12_0.c index f4a19357ccbc6..3746d39182707 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v12_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v12_0.c @@ -91,6 +91,8 @@ static int gmc_v12_0_process_interrupt(struct amdgpu_device *adev, struct amdgpu_iv_entry *entry) { struct amdgpu_vmhub *hub; + bool retry_fault = !!(entry->src_data[1] & 0x80); + bool write_fault = !!(entry->src_data[1] & 0x20); uint32_t status = 0; u64 addr; @@ -102,6 +104,31 @@ static int gmc_v12_0_process_interrupt(struct amdgpu_device *adev, else hub = &adev->vmhub[AMDGPU_GFXHUB(0)]; + if (retry_fault) { + /* Returning 1 here also prevents sending the IV to the KFD */ + + /* Process it only if it's the first fault for this address */ + if (entry->ih != &adev->irq.ih_soft && + amdgpu_gmc_filter_faults(adev, entry->ih, addr, entry->pasid, + entry->timestamp)) + return 1; + + /* Delegate it to a different ring if the hardware hasn't + * already done it. + */ + if (entry->ih == &adev->irq.ih) { + amdgpu_irq_delegate(adev, entry, 8); + return 1; + } + + /* Try to handle the recoverable page faults by filling page + * tables + */ + if (amdgpu_vm_handle_fault(adev, entry->pasid, 0, 0, addr, + entry->timestamp, write_fault)) + return 1; + } + if (!amdgpu_sriov_vf(adev)) { /* * Issue a dummy read to wait for the status register to From 0b48f98f092bd246964465f16f2e321ee619988c Mon Sep 17 00:00:00 2001 From: Natalie Vock Date: Mon, 1 Dec 2025 12:52:38 -0500 Subject: [PATCH 1710/2333] drm/amdgpu: Forward VMID reservation errors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 8defb4f081a5feccc3ea8372d0c7af3522124e1f upstream. Otherwise userspace may be fooled into believing it has a reserved VMID when in reality it doesn't, ultimately leading to GPU hangs when SPM is used. Fixes: 80e709ee6ecc ("drm/amdgpu: add option params to enforce process isolation between graphics and compute") Cc: stable@vger.kernel.org Reviewed-by: Christian König Signed-off-by: Natalie Vock Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index cdcafde3c71a1..3d2f9d0e2d239 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -2910,8 +2910,7 @@ int amdgpu_vm_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) switch (args->in.op) { case AMDGPU_VM_OP_RESERVE_VMID: /* We only have requirement to reserve vmid from gfxhub */ - amdgpu_vmid_alloc_reserved(adev, vm, AMDGPU_GFXHUB(0)); - break; + return amdgpu_vmid_alloc_reserved(adev, vm, AMDGPU_GFXHUB(0)); case AMDGPU_VM_OP_UNRESERVE_VMID: amdgpu_vmid_free_reserved(adev, vm, AMDGPU_GFXHUB(0)); break; From 431b9cd093635b8a650df3fcf351180260d8c04b Mon Sep 17 00:00:00 2001 From: Pierre-Eric Pelloux-Prayer Date: Tue, 25 Nov 2025 10:48:39 +0100 Subject: [PATCH 1711/2333] drm/amdgpu: add missing lock to amdgpu_ttm_access_memory_sdma MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 4fa944255be521b1bbd9780383f77206303a3a5c upstream. Users of ttm entities need to hold the gtt_window_lock before using them to guarantee proper ordering of jobs. Cc: stable@vger.kernel.org Fixes: cb5cc4f573e1 ("drm/amdgpu: improve debug VRAM access performance using sdma") Signed-off-by: Pierre-Eric Pelloux-Prayer Reviewed-by: Christian König Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index 9d568c16beb1e..4183e5301cffc 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -1529,6 +1529,7 @@ static int amdgpu_ttm_access_memory_sdma(struct ttm_buffer_object *bo, if (r) goto out; + mutex_lock(&adev->mman.gtt_window_lock); amdgpu_res_first(abo->tbo.resource, offset, len, &src_mm); src_addr = amdgpu_ttm_domain_start(adev, bo->resource->mem_type) + src_mm.start; @@ -1543,6 +1544,7 @@ static int amdgpu_ttm_access_memory_sdma(struct ttm_buffer_object *bo, WARN_ON(job->ibs[0].length_dw > num_dw); fence = amdgpu_job_submit(job); + mutex_unlock(&adev->mman.gtt_window_lock); if (!dma_fence_wait_timeout(fence, false, adev->sdma_timeout)) r = -ETIMEDOUT; From 16a3106cff4aeac48f17dda67f3be8548300a563 Mon Sep 17 00:00:00 2001 From: Srinivasan Shanmugam Date: Tue, 25 Nov 2025 21:20:45 +0530 Subject: [PATCH 1712/2333] drm/amdgpu/sdma6: Update SDMA 6.0.3 FW version to include UMQ protected-fence fix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit c8e7e3c2215e286ebfe66fe828ed426546c519e6 upstream. On GFX11.0.3, earlier SDMA firmware versions issue the PROTECTED_FENCE write from the user VMID (e.g. VMID 8) instead of VMID 0. This causes a GPU VM protection fault when SDMA tries to write the secure fence location, as seen in the UMQ SDMA test (cs-sdma-with-IP-DMA-UMQ) Fixes the below GPU page fault: [ 514.037189] amdgpu 0000:0b:00.0: amdgpu: [gfxhub] page fault (src_id:0 ring:40 vmid:8 pasid:32770) [ 514.037199] amdgpu 0000:0b:00.0: amdgpu: Process pid 0 thread pid 0 [ 514.037205] amdgpu 0000:0b:00.0: amdgpu: in page starting at address 0x00007fff00409000 from client 10 [ 514.037212] amdgpu 0000:0b:00.0: amdgpu: GCVM_L2_PROTECTION_FAULT_STATUS:0x00841A51 [ 514.037217] amdgpu 0000:0b:00.0: amdgpu: Faulty UTCL2 client ID: SDMA0 (0xd) [ 514.037223] amdgpu 0000:0b:00.0: amdgpu: MORE_FAULTS: 0x1 [ 514.037227] amdgpu 0000:0b:00.0: amdgpu: WALKER_ERROR: 0x0 [ 514.037232] amdgpu 0000:0b:00.0: amdgpu: PERMISSION_FAULTS: 0x5 [ 514.037236] amdgpu 0000:0b:00.0: amdgpu: MAPPING_ERROR: 0x0 [ 514.037241] amdgpu 0000:0b:00.0: amdgpu: RW: 0x1 v2: Updated commit message v3: s/gfx11.0.3/sdma 6.0.3/ in patch title (Alex) Cc: Alex Deucher Cc: Christian König Cc: stable@vger.kernel.org Signed-off-by: Srinivasan Shanmugam Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c index db6e41967f126..3c6568d501994 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c @@ -1389,7 +1389,7 @@ static int sdma_v6_0_sw_init(struct amdgpu_ip_block *ip_block) adev->userq_funcs[AMDGPU_HW_IP_DMA] = &userq_mes_funcs; break; case IP_VERSION(6, 0, 3): - if ((adev->sdma.instance[0].fw_version >= 27) && !adev->sdma.disable_uq) + if (adev->sdma.instance[0].fw_version >= 29 && !adev->sdma.disable_uq) adev->userq_funcs[AMDGPU_HW_IP_DMA] = &userq_mes_funcs; break; case IP_VERSION(6, 1, 0): From b89cd47c4c92b5864488ea80556191a7a1b7074e Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 13 Nov 2025 15:55:19 -0500 Subject: [PATCH 1713/2333] drm/amdgpu/gmc11: add amdgpu_vm_handle_fault() handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 3f2289b56cd98f5741056bdb6e521324eff07ce5 upstream. We need to call amdgpu_vm_handle_fault() on page fault on all gfx9 and newer parts to properly update the page tables, not just for recoverable page faults. Cc: stable@vger.kernel.org Reviewed-by: Timur Kristóf Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c | 27 ++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c index 7bc389d9f5c48..8acc912e7e4cb 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c @@ -103,12 +103,39 @@ static int gmc_v11_0_process_interrupt(struct amdgpu_device *adev, uint32_t vmhub_index = entry->client_id == SOC21_IH_CLIENTID_VMC ? AMDGPU_MMHUB0(0) : AMDGPU_GFXHUB(0); struct amdgpu_vmhub *hub = &adev->vmhub[vmhub_index]; + bool retry_fault = !!(entry->src_data[1] & 0x80); + bool write_fault = !!(entry->src_data[1] & 0x20); uint32_t status = 0; u64 addr; addr = (u64)entry->src_data[0] << 12; addr |= ((u64)entry->src_data[1] & 0xf) << 44; + if (retry_fault) { + /* Returning 1 here also prevents sending the IV to the KFD */ + + /* Process it only if it's the first fault for this address */ + if (entry->ih != &adev->irq.ih_soft && + amdgpu_gmc_filter_faults(adev, entry->ih, addr, entry->pasid, + entry->timestamp)) + return 1; + + /* Delegate it to a different ring if the hardware hasn't + * already done it. + */ + if (entry->ih == &adev->irq.ih) { + amdgpu_irq_delegate(adev, entry, 8); + return 1; + } + + /* Try to handle the recoverable page faults by filling page + * tables + */ + if (amdgpu_vm_handle_fault(adev, entry->pasid, 0, 0, addr, + entry->timestamp, write_fault)) + return 1; + } + if (!amdgpu_sriov_vf(adev)) { /* * Issue a dummy read to wait for the status register to From 2c9ba2fbcd97c02c1cb23ec80290494a808f1690 Mon Sep 17 00:00:00 2001 From: Akhil P Oommen Date: Tue, 18 Nov 2025 14:20:28 +0530 Subject: [PATCH 1714/2333] drm/msm/a6xx: Fix out of bound IO access in a6xx_get_gmu_registers commit 779b68a5bf2764c8ed3aa800e41ba0d5d007e1e7 upstream. REG_A6XX_GMU_AO_AHB_FENCE_CTRL register falls under GMU's register range. So, use gmu_write() routines to write to this register. Fixes: 1707add81551 ("drm/msm/a6xx: Add a6xx gpu state") Cc: stable@vger.kernel.org Signed-off-by: Akhil P Oommen Reviewed-by: Konrad Dybcio Patchwork: https://patchwork.freedesktop.org/patch/688993/ Message-ID: <20251118-kaana-gpu-support-v4-1-86eeb8e93fb6@oss.qualcomm.com> Signed-off-by: Rob Clark Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c index 4c7f3c642f6ac..9cec333e23e15 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c @@ -1255,7 +1255,7 @@ static void a6xx_get_gmu_registers(struct msm_gpu *gpu, return; /* Set the fence to ALLOW mode so we can access the registers */ - gpu_write(gpu, REG_A6XX_GMU_AO_AHB_FENCE_CTRL, 0); + gmu_write(&a6xx_gpu->gmu, REG_A6XX_GMU_AO_AHB_FENCE_CTRL, 0); _a6xx_get_gmu_registers(gpu, a6xx_state, &a6xx_gmu_reglist[2], &a6xx_state->gmu_registers[3], false); From e983164f179e22f095db0842bb2a6d6495ea44df Mon Sep 17 00:00:00 2001 From: Arunpravin Paneer Selvam Date: Mon, 6 Oct 2025 15:21:22 +0530 Subject: [PATCH 1715/2333] drm/buddy: Optimize free block management with RB tree commit c178e534fff1d5a74da80ea03b20e2b948a00113 upstream. Replace the freelist (O(n)) used for free block management with a red-black tree, providing more efficient O(log n) search, insert, and delete operations. This improves scalability and performance when managing large numbers of free blocks per order (e.g., hundreds or thousands). In the VK-CTS memory stress subtest, the buddy manager merges fragmented memory and inserts freed blocks into the freelist. Since freelist insertion is O(n), this becomes a bottleneck as fragmentation increases. Benchmarking shows list_insert_sorted() consumes ~52.69% CPU with the freelist, compared to just 0.03% with the RB tree (rbtree_insert.isra.0), despite performing the same sorted insert. This also improves performance in heavily fragmented workloads, such as games or graphics tests that stress memory. As the buddy allocator evolves with new features such as clear-page tracking, the resulting fragmentation and complexity have grown. These RB-tree based design changes are introduced to address that growth and ensure the allocator continues to perform efficiently under fragmented conditions. The RB tree implementation with separate clear/dirty trees provides: - O(n log n) aggregate complexity for all operations instead of O(n^2) - Elimination of soft lockups and system instability - Improved code maintainability and clarity - Better scalability for large memory systems - Predictable performance under fragmentation v3(Matthew): - Remove RB_EMPTY_NODE check in force_merge function. - Rename rb for loop macros to have less generic names and move to .c file. - Make the rb node rb and link field as union. v4(Jani Nikula): - The kernel-doc comment should be "/**" - Move all the rbtree macros to rbtree.h and add parens to ensure correct precedence. v5: - Remove the inline in a .c file (Jani Nikula). v6(Peter Zijlstra): - Add rb_add() function replacing the existing rbtree_insert() code. v7: - A full walk iteration in rbtree is slower than the list (Peter Zijlstra). - The existing rbtree_postorder_for_each_entry_safe macro should be used in scenarios where traversal order is not a critical factor (Christian). v8(Matthew): - Remove the rbtree_is_empty() check in this patch as well. Cc: stable@vger.kernel.org Fixes: a68c7eaa7a8f ("drm/amdgpu: Enable clear page functionality") Signed-off-by: Arunpravin Paneer Selvam Reviewed-by: Matthew Auld Link: https://lore.kernel.org/r/20251006095124.1663-1-Arunpravin.PaneerSelvam@amd.com Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/drm_buddy.c | 195 ++++++++++++++++++++++-------------- include/drm/drm_buddy.h | 11 +- 2 files changed, 126 insertions(+), 80 deletions(-) diff --git a/drivers/gpu/drm/drm_buddy.c b/drivers/gpu/drm/drm_buddy.c index a94061f373de5..c87210a06c318 100644 --- a/drivers/gpu/drm/drm_buddy.c +++ b/drivers/gpu/drm/drm_buddy.c @@ -14,6 +14,8 @@ static struct kmem_cache *slab_blocks; +#define rbtree_get_free_block(node) rb_entry((node), struct drm_buddy_block, rb) + static struct drm_buddy_block *drm_block_alloc(struct drm_buddy *mm, struct drm_buddy_block *parent, unsigned int order, @@ -31,6 +33,8 @@ static struct drm_buddy_block *drm_block_alloc(struct drm_buddy *mm, block->header |= order; block->parent = parent; + RB_CLEAR_NODE(&block->rb); + BUG_ON(block->header & DRM_BUDDY_HEADER_UNUSED); return block; } @@ -41,23 +45,49 @@ static void drm_block_free(struct drm_buddy *mm, kmem_cache_free(slab_blocks, block); } -static void list_insert_sorted(struct drm_buddy *mm, - struct drm_buddy_block *block) +static bool drm_buddy_block_offset_less(const struct drm_buddy_block *block, + const struct drm_buddy_block *node) { - struct drm_buddy_block *node; - struct list_head *head; + return drm_buddy_block_offset(block) < drm_buddy_block_offset(node); +} - head = &mm->free_list[drm_buddy_block_order(block)]; - if (list_empty(head)) { - list_add(&block->link, head); - return; - } +static bool rbtree_block_offset_less(struct rb_node *block, + const struct rb_node *node) +{ + return drm_buddy_block_offset_less(rbtree_get_free_block(block), + rbtree_get_free_block(node)); +} - list_for_each_entry(node, head, link) - if (drm_buddy_block_offset(block) < drm_buddy_block_offset(node)) - break; +static void rbtree_insert(struct drm_buddy *mm, + struct drm_buddy_block *block) +{ + rb_add(&block->rb, + &mm->free_tree[drm_buddy_block_order(block)], + rbtree_block_offset_less); +} + +static void rbtree_remove(struct drm_buddy *mm, + struct drm_buddy_block *block) +{ + struct rb_root *root; + + root = &mm->free_tree[drm_buddy_block_order(block)]; + rb_erase(&block->rb, root); + + RB_CLEAR_NODE(&block->rb); +} + +static struct drm_buddy_block * +rbtree_last_entry(struct drm_buddy *mm, unsigned int order) +{ + struct rb_node *node = rb_last(&mm->free_tree[order]); + + return node ? rb_entry(node, struct drm_buddy_block, rb) : NULL; +} - __list_add(&block->link, node->link.prev, &node->link); +static bool rbtree_is_empty(struct drm_buddy *mm, unsigned int order) +{ + return RB_EMPTY_ROOT(&mm->free_tree[order]); } static void clear_reset(struct drm_buddy_block *block) @@ -70,12 +100,13 @@ static void mark_cleared(struct drm_buddy_block *block) block->header |= DRM_BUDDY_HEADER_CLEAR; } -static void mark_allocated(struct drm_buddy_block *block) +static void mark_allocated(struct drm_buddy *mm, + struct drm_buddy_block *block) { block->header &= ~DRM_BUDDY_HEADER_STATE; block->header |= DRM_BUDDY_ALLOCATED; - list_del(&block->link); + rbtree_remove(mm, block); } static void mark_free(struct drm_buddy *mm, @@ -84,15 +115,16 @@ static void mark_free(struct drm_buddy *mm, block->header &= ~DRM_BUDDY_HEADER_STATE; block->header |= DRM_BUDDY_FREE; - list_insert_sorted(mm, block); + rbtree_insert(mm, block); } -static void mark_split(struct drm_buddy_block *block) +static void mark_split(struct drm_buddy *mm, + struct drm_buddy_block *block) { block->header &= ~DRM_BUDDY_HEADER_STATE; block->header |= DRM_BUDDY_SPLIT; - list_del(&block->link); + rbtree_remove(mm, block); } static inline bool overlaps(u64 s1, u64 e1, u64 s2, u64 e2) @@ -148,7 +180,7 @@ static unsigned int __drm_buddy_free(struct drm_buddy *mm, mark_cleared(parent); } - list_del(&buddy->link); + rbtree_remove(mm, buddy); if (force_merge && drm_buddy_block_is_clear(buddy)) mm->clear_avail -= drm_buddy_block_size(mm, buddy); @@ -179,13 +211,19 @@ static int __force_merge(struct drm_buddy *mm, return -EINVAL; for (i = min_order - 1; i >= 0; i--) { - struct drm_buddy_block *block, *prev; + struct rb_root *root = &mm->free_tree[i]; + struct rb_node *iter; + + iter = rb_last(root); - list_for_each_entry_safe_reverse(block, prev, &mm->free_list[i], link) { - struct drm_buddy_block *buddy; + while (iter) { + struct drm_buddy_block *block, *buddy; u64 block_start, block_end; - if (!block->parent) + block = rbtree_get_free_block(iter); + iter = rb_prev(iter); + + if (!block || !block->parent) continue; block_start = drm_buddy_block_offset(block); @@ -201,15 +239,10 @@ static int __force_merge(struct drm_buddy *mm, WARN_ON(drm_buddy_block_is_clear(block) == drm_buddy_block_is_clear(buddy)); - /* - * If the prev block is same as buddy, don't access the - * block in the next iteration as we would free the - * buddy block as part of the free function. - */ - if (prev == buddy) - prev = list_prev_entry(prev, link); + if (iter == &buddy->rb) + iter = rb_prev(iter); - list_del(&block->link); + rbtree_remove(mm, block); if (drm_buddy_block_is_clear(block)) mm->clear_avail -= drm_buddy_block_size(mm, block); @@ -237,7 +270,7 @@ static int __force_merge(struct drm_buddy *mm, int drm_buddy_init(struct drm_buddy *mm, u64 size, u64 chunk_size) { unsigned int i; - u64 offset; + u64 offset = 0; if (size < chunk_size) return -EINVAL; @@ -258,14 +291,14 @@ int drm_buddy_init(struct drm_buddy *mm, u64 size, u64 chunk_size) BUG_ON(mm->max_order > DRM_BUDDY_MAX_ORDER); - mm->free_list = kmalloc_array(mm->max_order + 1, - sizeof(struct list_head), + mm->free_tree = kmalloc_array(mm->max_order + 1, + sizeof(struct rb_root), GFP_KERNEL); - if (!mm->free_list) + if (!mm->free_tree) return -ENOMEM; for (i = 0; i <= mm->max_order; ++i) - INIT_LIST_HEAD(&mm->free_list[i]); + mm->free_tree[i] = RB_ROOT; mm->n_roots = hweight64(size); @@ -273,9 +306,8 @@ int drm_buddy_init(struct drm_buddy *mm, u64 size, u64 chunk_size) sizeof(struct drm_buddy_block *), GFP_KERNEL); if (!mm->roots) - goto out_free_list; + goto out_free_tree; - offset = 0; i = 0; /* @@ -312,8 +344,8 @@ int drm_buddy_init(struct drm_buddy *mm, u64 size, u64 chunk_size) while (i--) drm_block_free(mm, mm->roots[i]); kfree(mm->roots); -out_free_list: - kfree(mm->free_list); +out_free_tree: + kfree(mm->free_tree); return -ENOMEM; } EXPORT_SYMBOL(drm_buddy_init); @@ -323,7 +355,7 @@ EXPORT_SYMBOL(drm_buddy_init); * * @mm: DRM buddy manager to free * - * Cleanup memory manager resources and the freelist + * Cleanup memory manager resources and the freetree */ void drm_buddy_fini(struct drm_buddy *mm) { @@ -350,7 +382,7 @@ void drm_buddy_fini(struct drm_buddy *mm) WARN_ON(mm->avail != mm->size); kfree(mm->roots); - kfree(mm->free_list); + kfree(mm->free_tree); } EXPORT_SYMBOL(drm_buddy_fini); @@ -383,7 +415,7 @@ static int split_block(struct drm_buddy *mm, clear_reset(block); } - mark_split(block); + mark_split(mm, block); return 0; } @@ -412,7 +444,7 @@ EXPORT_SYMBOL(drm_get_buddy); * @is_clear: blocks clear state * * Reset the clear state based on @is_clear value for each block - * in the freelist. + * in the freetree. */ void drm_buddy_reset_clear(struct drm_buddy *mm, bool is_clear) { @@ -431,9 +463,9 @@ void drm_buddy_reset_clear(struct drm_buddy *mm, bool is_clear) } for (i = 0; i <= mm->max_order; ++i) { - struct drm_buddy_block *block; + struct drm_buddy_block *block, *tmp; - list_for_each_entry_reverse(block, &mm->free_list[i], link) { + rbtree_postorder_for_each_entry_safe(block, tmp, &mm->free_tree[i], rb) { if (is_clear != drm_buddy_block_is_clear(block)) { if (is_clear) { mark_cleared(block); @@ -639,14 +671,18 @@ get_maxblock(struct drm_buddy *mm, unsigned int order, unsigned int i; for (i = order; i <= mm->max_order; ++i) { + struct rb_node *iter = rb_last(&mm->free_tree[i]); struct drm_buddy_block *tmp_block; - list_for_each_entry_reverse(tmp_block, &mm->free_list[i], link) { - if (block_incompatible(tmp_block, flags)) - continue; + while (iter) { + tmp_block = rbtree_get_free_block(iter); - block = tmp_block; - break; + if (!block_incompatible(tmp_block, flags)) { + block = tmp_block; + break; + } + + iter = rb_prev(iter); } if (!block) @@ -667,7 +703,7 @@ get_maxblock(struct drm_buddy *mm, unsigned int order, } static struct drm_buddy_block * -alloc_from_freelist(struct drm_buddy *mm, +alloc_from_freetree(struct drm_buddy *mm, unsigned int order, unsigned long flags) { @@ -682,14 +718,18 @@ alloc_from_freelist(struct drm_buddy *mm, tmp = drm_buddy_block_order(block); } else { for (tmp = order; tmp <= mm->max_order; ++tmp) { + struct rb_node *iter = rb_last(&mm->free_tree[tmp]); struct drm_buddy_block *tmp_block; - list_for_each_entry_reverse(tmp_block, &mm->free_list[tmp], link) { - if (block_incompatible(tmp_block, flags)) - continue; + while (iter) { + tmp_block = rbtree_get_free_block(iter); - block = tmp_block; - break; + if (!block_incompatible(tmp_block, flags)) { + block = tmp_block; + break; + } + + iter = rb_prev(iter); } if (block) @@ -700,13 +740,9 @@ alloc_from_freelist(struct drm_buddy *mm, if (!block) { /* Fallback method */ for (tmp = order; tmp <= mm->max_order; ++tmp) { - if (!list_empty(&mm->free_list[tmp])) { - block = list_last_entry(&mm->free_list[tmp], - struct drm_buddy_block, - link); - if (block) - break; - } + block = rbtree_last_entry(mm, tmp); + if (block) + break; } if (!block) @@ -771,7 +807,7 @@ static int __alloc_range(struct drm_buddy *mm, if (contains(start, end, block_start, block_end)) { if (drm_buddy_block_is_free(block)) { - mark_allocated(block); + mark_allocated(mm, block); total_allocated += drm_buddy_block_size(mm, block); mm->avail -= drm_buddy_block_size(mm, block); if (drm_buddy_block_is_clear(block)) @@ -849,8 +885,8 @@ static int __alloc_contig_try_harder(struct drm_buddy *mm, { u64 rhs_offset, lhs_offset, lhs_size, filled; struct drm_buddy_block *block; - struct list_head *list; LIST_HEAD(blocks_lhs); + struct rb_node *iter; unsigned long pages; unsigned int order; u64 modify_size; @@ -862,11 +898,14 @@ static int __alloc_contig_try_harder(struct drm_buddy *mm, if (order == 0) return -ENOSPC; - list = &mm->free_list[order]; - if (list_empty(list)) + if (rbtree_is_empty(mm, order)) return -ENOSPC; - list_for_each_entry_reverse(block, list, link) { + iter = rb_last(&mm->free_tree[order]); + + while (iter) { + block = rbtree_get_free_block(iter); + /* Allocate blocks traversing RHS */ rhs_offset = drm_buddy_block_offset(block); err = __drm_buddy_alloc_range(mm, rhs_offset, size, @@ -891,6 +930,8 @@ static int __alloc_contig_try_harder(struct drm_buddy *mm, } /* Free blocks for the next iteration */ drm_buddy_free_list_internal(mm, blocks); + + iter = rb_prev(iter); } return -ENOSPC; @@ -976,7 +1017,7 @@ int drm_buddy_block_trim(struct drm_buddy *mm, list_add(&block->tmp_link, &dfs); err = __alloc_range(mm, &dfs, new_start, new_size, blocks, NULL); if (err) { - mark_allocated(block); + mark_allocated(mm, block); mm->avail -= drm_buddy_block_size(mm, block); if (drm_buddy_block_is_clear(block)) mm->clear_avail -= drm_buddy_block_size(mm, block); @@ -999,8 +1040,8 @@ __drm_buddy_alloc_blocks(struct drm_buddy *mm, return __drm_buddy_alloc_range_bias(mm, start, end, order, flags); else - /* Allocate from freelist */ - return alloc_from_freelist(mm, order, flags); + /* Allocate from freetree */ + return alloc_from_freetree(mm, order, flags); } /** @@ -1017,8 +1058,8 @@ __drm_buddy_alloc_blocks(struct drm_buddy *mm, * alloc_range_bias() called on range limitations, which traverses * the tree and returns the desired block. * - * alloc_from_freelist() called when *no* range restrictions - * are enforced, which picks the block from the freelist. + * alloc_from_freetree() called when *no* range restrictions + * are enforced, which picks the block from the freetree. * * Returns: * 0 on success, error code on failure. @@ -1120,7 +1161,7 @@ int drm_buddy_alloc_blocks(struct drm_buddy *mm, } } while (1); - mark_allocated(block); + mark_allocated(mm, block); mm->avail -= drm_buddy_block_size(mm, block); if (drm_buddy_block_is_clear(block)) mm->clear_avail -= drm_buddy_block_size(mm, block); @@ -1201,10 +1242,10 @@ void drm_buddy_print(struct drm_buddy *mm, struct drm_printer *p) mm->chunk_size >> 10, mm->size >> 20, mm->avail >> 20, mm->clear_avail >> 20); for (order = mm->max_order; order >= 0; order--) { - struct drm_buddy_block *block; + struct drm_buddy_block *block, *tmp; u64 count = 0, free; - list_for_each_entry(block, &mm->free_list[order], link) { + rbtree_postorder_for_each_entry_safe(block, tmp, &mm->free_tree[order], rb) { BUG_ON(!drm_buddy_block_is_free(block)); count++; } diff --git a/include/drm/drm_buddy.h b/include/drm/drm_buddy.h index 04afd7c21a82e..f22d292443dbf 100644 --- a/include/drm/drm_buddy.h +++ b/include/drm/drm_buddy.h @@ -10,6 +10,7 @@ #include #include #include +#include #include @@ -44,7 +45,11 @@ struct drm_buddy_block { * a list, if so desired. As soon as the block is freed with * drm_buddy_free* ownership is given back to the mm. */ - struct list_head link; + union { + struct rb_node rb; + struct list_head link; + }; + struct list_head tmp_link; }; @@ -59,7 +64,7 @@ struct drm_buddy_block { */ struct drm_buddy { /* Maintain a free list for each order. */ - struct list_head *free_list; + struct rb_root *free_tree; /* * Maintain explicit binary tree(s) to track the allocation of the @@ -85,7 +90,7 @@ struct drm_buddy { }; static inline u64 -drm_buddy_block_offset(struct drm_buddy_block *block) +drm_buddy_block_offset(const struct drm_buddy_block *block) { return block->header & DRM_BUDDY_HEADER_OFFSET; } From 391f53db144511cd7f5655eac2b4f8efe0a7b0d4 Mon Sep 17 00:00:00 2001 From: Arunpravin Paneer Selvam Date: Mon, 6 Oct 2025 15:21:23 +0530 Subject: [PATCH 1716/2333] drm/buddy: Separate clear and dirty free block trees commit d4cd665c98c144dd6ad5d66d30396e13d23118c9 upstream. Maintain two separate RB trees per order - one for clear (zeroed) blocks and another for dirty (uncleared) blocks. This separation improves code clarity and makes it more obvious which tree is being searched during allocation. It also improves scalability and efficiency when searching for a specific type of block, avoiding unnecessary checks and making the allocator more predictable under fragmentation. The changes have been validated using the existing drm_buddy_test KUnit test cases, along with selected graphics workloads, to ensure correctness and avoid regressions. v2: Missed adding the suggested-by tag. Added it in v2. v3(Matthew): - Remove the double underscores from the internal functions. - Rename the internal functions to have less generic names. - Fix the error handling code. - Pass tree argument for the tree macro. - Use the existing dirty/free bit instead of new tree field. - Make free_trees[] instead of clear_tree and dirty_tree for more cleaner approach. v4: - A bug was reported by Intel CI and it is fixed by Matthew Auld. - Replace the get_root function with &mm->free_trees[tree][order] (Matthew) - Remove the unnecessary rbtree_is_empty() check (Matthew) - Remove the unnecessary get_tree_for_flags() function. - Rename get_tree_for_block() name with get_block_tree() for more clarity. v5(Jani Nikula): - Don't use static inline in .c files. - enum free_tree and enumerator names are quite generic for a header and usage and the whole enum should be an implementation detail. v6: - Rewrite the __force_merge() function using the rb_last() and rb_prev(). v7(Matthew): - Replace the open-coded tree iteration for loops with the for_each_free_tree() macro throughout the code. - Fixed out_free_roots to prevent double decrement of i, addressing potential crash. - Replaced enum drm_buddy_free_tree with unsigned int in for_each_free_tree loops. Cc: stable@vger.kernel.org Fixes: a68c7eaa7a8f ("drm/amdgpu: Enable clear page functionality") Signed-off-by: Arunpravin Paneer Selvam Suggested-by: Matthew Auld Reviewed-by: Matthew Auld Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/4260 Link: https://lore.kernel.org/r/20251006095124.1663-2-Arunpravin.PaneerSelvam@amd.com Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/drm_buddy.c | 333 ++++++++++++++++++++---------------- include/drm/drm_buddy.h | 2 +- 2 files changed, 188 insertions(+), 147 deletions(-) diff --git a/drivers/gpu/drm/drm_buddy.c b/drivers/gpu/drm/drm_buddy.c index c87210a06c318..f2c92902e4a30 100644 --- a/drivers/gpu/drm/drm_buddy.c +++ b/drivers/gpu/drm/drm_buddy.c @@ -12,9 +12,16 @@ #include +enum drm_buddy_free_tree { + DRM_BUDDY_CLEAR_TREE = 0, + DRM_BUDDY_DIRTY_TREE, + DRM_BUDDY_MAX_FREE_TREES, +}; + static struct kmem_cache *slab_blocks; -#define rbtree_get_free_block(node) rb_entry((node), struct drm_buddy_block, rb) +#define for_each_free_tree(tree) \ + for ((tree) = 0; (tree) < DRM_BUDDY_MAX_FREE_TREES; (tree)++) static struct drm_buddy_block *drm_block_alloc(struct drm_buddy *mm, struct drm_buddy_block *parent, @@ -45,6 +52,30 @@ static void drm_block_free(struct drm_buddy *mm, kmem_cache_free(slab_blocks, block); } +static enum drm_buddy_free_tree +get_block_tree(struct drm_buddy_block *block) +{ + return drm_buddy_block_is_clear(block) ? + DRM_BUDDY_CLEAR_TREE : DRM_BUDDY_DIRTY_TREE; +} + +static struct drm_buddy_block * +rbtree_get_free_block(const struct rb_node *node) +{ + return node ? rb_entry(node, struct drm_buddy_block, rb) : NULL; +} + +static struct drm_buddy_block * +rbtree_last_free_block(struct rb_root *root) +{ + return rbtree_get_free_block(rb_last(root)); +} + +static bool rbtree_is_empty(struct rb_root *root) +{ + return RB_EMPTY_ROOT(root); +} + static bool drm_buddy_block_offset_less(const struct drm_buddy_block *block, const struct drm_buddy_block *node) { @@ -59,37 +90,28 @@ static bool rbtree_block_offset_less(struct rb_node *block, } static void rbtree_insert(struct drm_buddy *mm, - struct drm_buddy_block *block) + struct drm_buddy_block *block, + enum drm_buddy_free_tree tree) { rb_add(&block->rb, - &mm->free_tree[drm_buddy_block_order(block)], + &mm->free_trees[tree][drm_buddy_block_order(block)], rbtree_block_offset_less); } static void rbtree_remove(struct drm_buddy *mm, struct drm_buddy_block *block) { + unsigned int order = drm_buddy_block_order(block); + enum drm_buddy_free_tree tree; struct rb_root *root; - root = &mm->free_tree[drm_buddy_block_order(block)]; - rb_erase(&block->rb, root); + tree = get_block_tree(block); + root = &mm->free_trees[tree][order]; + rb_erase(&block->rb, root); RB_CLEAR_NODE(&block->rb); } -static struct drm_buddy_block * -rbtree_last_entry(struct drm_buddy *mm, unsigned int order) -{ - struct rb_node *node = rb_last(&mm->free_tree[order]); - - return node ? rb_entry(node, struct drm_buddy_block, rb) : NULL; -} - -static bool rbtree_is_empty(struct drm_buddy *mm, unsigned int order) -{ - return RB_EMPTY_ROOT(&mm->free_tree[order]); -} - static void clear_reset(struct drm_buddy_block *block) { block->header &= ~DRM_BUDDY_HEADER_CLEAR; @@ -112,10 +134,13 @@ static void mark_allocated(struct drm_buddy *mm, static void mark_free(struct drm_buddy *mm, struct drm_buddy_block *block) { + enum drm_buddy_free_tree tree; + block->header &= ~DRM_BUDDY_HEADER_STATE; block->header |= DRM_BUDDY_FREE; - rbtree_insert(mm, block); + tree = get_block_tree(block); + rbtree_insert(mm, block, tree); } static void mark_split(struct drm_buddy *mm, @@ -201,7 +226,7 @@ static int __force_merge(struct drm_buddy *mm, u64 end, unsigned int min_order) { - unsigned int order; + unsigned int tree, order; int i; if (!min_order) @@ -210,45 +235,48 @@ static int __force_merge(struct drm_buddy *mm, if (min_order > mm->max_order) return -EINVAL; - for (i = min_order - 1; i >= 0; i--) { - struct rb_root *root = &mm->free_tree[i]; - struct rb_node *iter; + for_each_free_tree(tree) { + for (i = min_order - 1; i >= 0; i--) { + struct rb_node *iter = rb_last(&mm->free_trees[tree][i]); - iter = rb_last(root); - - while (iter) { - struct drm_buddy_block *block, *buddy; - u64 block_start, block_end; + while (iter) { + struct drm_buddy_block *block, *buddy; + u64 block_start, block_end; - block = rbtree_get_free_block(iter); - iter = rb_prev(iter); + block = rbtree_get_free_block(iter); + iter = rb_prev(iter); - if (!block || !block->parent) - continue; + if (!block || !block->parent) + continue; - block_start = drm_buddy_block_offset(block); - block_end = block_start + drm_buddy_block_size(mm, block) - 1; + block_start = drm_buddy_block_offset(block); + block_end = block_start + drm_buddy_block_size(mm, block) - 1; - if (!contains(start, end, block_start, block_end)) - continue; + if (!contains(start, end, block_start, block_end)) + continue; - buddy = __get_buddy(block); - if (!drm_buddy_block_is_free(buddy)) - continue; + buddy = __get_buddy(block); + if (!drm_buddy_block_is_free(buddy)) + continue; - WARN_ON(drm_buddy_block_is_clear(block) == - drm_buddy_block_is_clear(buddy)); + WARN_ON(drm_buddy_block_is_clear(block) == + drm_buddy_block_is_clear(buddy)); - if (iter == &buddy->rb) - iter = rb_prev(iter); + /* + * Advance to the next node when the current node is the buddy, + * as freeing the block will also remove its buddy from the tree. + */ + if (iter == &buddy->rb) + iter = rb_prev(iter); - rbtree_remove(mm, block); - if (drm_buddy_block_is_clear(block)) - mm->clear_avail -= drm_buddy_block_size(mm, block); + rbtree_remove(mm, block); + if (drm_buddy_block_is_clear(block)) + mm->clear_avail -= drm_buddy_block_size(mm, block); - order = __drm_buddy_free(mm, block, true); - if (order >= min_order) - return 0; + order = __drm_buddy_free(mm, block, true); + if (order >= min_order) + return 0; + } } } @@ -269,7 +297,7 @@ static int __force_merge(struct drm_buddy *mm, */ int drm_buddy_init(struct drm_buddy *mm, u64 size, u64 chunk_size) { - unsigned int i; + unsigned int i, j, root_count = 0; u64 offset = 0; if (size < chunk_size) @@ -291,14 +319,22 @@ int drm_buddy_init(struct drm_buddy *mm, u64 size, u64 chunk_size) BUG_ON(mm->max_order > DRM_BUDDY_MAX_ORDER); - mm->free_tree = kmalloc_array(mm->max_order + 1, - sizeof(struct rb_root), - GFP_KERNEL); - if (!mm->free_tree) + mm->free_trees = kmalloc_array(DRM_BUDDY_MAX_FREE_TREES, + sizeof(*mm->free_trees), + GFP_KERNEL); + if (!mm->free_trees) return -ENOMEM; - for (i = 0; i <= mm->max_order; ++i) - mm->free_tree[i] = RB_ROOT; + for_each_free_tree(i) { + mm->free_trees[i] = kmalloc_array(mm->max_order + 1, + sizeof(struct rb_root), + GFP_KERNEL); + if (!mm->free_trees[i]) + goto out_free_tree; + + for (j = 0; j <= mm->max_order; ++j) + mm->free_trees[i][j] = RB_ROOT; + } mm->n_roots = hweight64(size); @@ -308,8 +344,6 @@ int drm_buddy_init(struct drm_buddy *mm, u64 size, u64 chunk_size) if (!mm->roots) goto out_free_tree; - i = 0; - /* * Split into power-of-two blocks, in case we are given a size that is * not itself a power-of-two. @@ -328,24 +362,26 @@ int drm_buddy_init(struct drm_buddy *mm, u64 size, u64 chunk_size) mark_free(mm, root); - BUG_ON(i > mm->max_order); + BUG_ON(root_count > mm->max_order); BUG_ON(drm_buddy_block_size(mm, root) < chunk_size); - mm->roots[i] = root; + mm->roots[root_count] = root; offset += root_size; size -= root_size; - i++; + root_count++; } while (size); return 0; out_free_roots: - while (i--) - drm_block_free(mm, mm->roots[i]); + while (root_count--) + drm_block_free(mm, mm->roots[root_count]); kfree(mm->roots); out_free_tree: - kfree(mm->free_tree); + while (i--) + kfree(mm->free_trees[i]); + kfree(mm->free_trees); return -ENOMEM; } EXPORT_SYMBOL(drm_buddy_init); @@ -381,8 +417,9 @@ void drm_buddy_fini(struct drm_buddy *mm) WARN_ON(mm->avail != mm->size); + for_each_free_tree(i) + kfree(mm->free_trees[i]); kfree(mm->roots); - kfree(mm->free_tree); } EXPORT_SYMBOL(drm_buddy_fini); @@ -406,8 +443,7 @@ static int split_block(struct drm_buddy *mm, return -ENOMEM; } - mark_free(mm, block->left); - mark_free(mm, block->right); + mark_split(mm, block); if (drm_buddy_block_is_clear(block)) { mark_cleared(block->left); @@ -415,7 +451,8 @@ static int split_block(struct drm_buddy *mm, clear_reset(block); } - mark_split(mm, block); + mark_free(mm, block->left); + mark_free(mm, block->right); return 0; } @@ -448,6 +485,7 @@ EXPORT_SYMBOL(drm_get_buddy); */ void drm_buddy_reset_clear(struct drm_buddy *mm, bool is_clear) { + enum drm_buddy_free_tree src_tree, dst_tree; u64 root_size, size, start; unsigned int order; int i; @@ -462,19 +500,24 @@ void drm_buddy_reset_clear(struct drm_buddy *mm, bool is_clear) size -= root_size; } + src_tree = is_clear ? DRM_BUDDY_DIRTY_TREE : DRM_BUDDY_CLEAR_TREE; + dst_tree = is_clear ? DRM_BUDDY_CLEAR_TREE : DRM_BUDDY_DIRTY_TREE; + for (i = 0; i <= mm->max_order; ++i) { + struct rb_root *root = &mm->free_trees[src_tree][i]; struct drm_buddy_block *block, *tmp; - rbtree_postorder_for_each_entry_safe(block, tmp, &mm->free_tree[i], rb) { - if (is_clear != drm_buddy_block_is_clear(block)) { - if (is_clear) { - mark_cleared(block); - mm->clear_avail += drm_buddy_block_size(mm, block); - } else { - clear_reset(block); - mm->clear_avail -= drm_buddy_block_size(mm, block); - } + rbtree_postorder_for_each_entry_safe(block, tmp, root, rb) { + rbtree_remove(mm, block); + if (is_clear) { + mark_cleared(block); + mm->clear_avail += drm_buddy_block_size(mm, block); + } else { + clear_reset(block); + mm->clear_avail -= drm_buddy_block_size(mm, block); } + + rbtree_insert(mm, block, dst_tree); } } } @@ -664,27 +707,17 @@ __drm_buddy_alloc_range_bias(struct drm_buddy *mm, } static struct drm_buddy_block * -get_maxblock(struct drm_buddy *mm, unsigned int order, - unsigned long flags) +get_maxblock(struct drm_buddy *mm, + unsigned int order, + enum drm_buddy_free_tree tree) { struct drm_buddy_block *max_block = NULL, *block = NULL; + struct rb_root *root; unsigned int i; for (i = order; i <= mm->max_order; ++i) { - struct rb_node *iter = rb_last(&mm->free_tree[i]); - struct drm_buddy_block *tmp_block; - - while (iter) { - tmp_block = rbtree_get_free_block(iter); - - if (!block_incompatible(tmp_block, flags)) { - block = tmp_block; - break; - } - - iter = rb_prev(iter); - } - + root = &mm->free_trees[tree][i]; + block = rbtree_last_free_block(root); if (!block) continue; @@ -708,39 +741,37 @@ alloc_from_freetree(struct drm_buddy *mm, unsigned long flags) { struct drm_buddy_block *block = NULL; + struct rb_root *root; + enum drm_buddy_free_tree tree; unsigned int tmp; int err; + tree = (flags & DRM_BUDDY_CLEAR_ALLOCATION) ? + DRM_BUDDY_CLEAR_TREE : DRM_BUDDY_DIRTY_TREE; + if (flags & DRM_BUDDY_TOPDOWN_ALLOCATION) { - block = get_maxblock(mm, order, flags); + block = get_maxblock(mm, order, tree); if (block) /* Store the obtained block order */ tmp = drm_buddy_block_order(block); } else { for (tmp = order; tmp <= mm->max_order; ++tmp) { - struct rb_node *iter = rb_last(&mm->free_tree[tmp]); - struct drm_buddy_block *tmp_block; - - while (iter) { - tmp_block = rbtree_get_free_block(iter); - - if (!block_incompatible(tmp_block, flags)) { - block = tmp_block; - break; - } - - iter = rb_prev(iter); - } - + /* Get RB tree root for this order and tree */ + root = &mm->free_trees[tree][tmp]; + block = rbtree_last_free_block(root); if (block) break; } } if (!block) { - /* Fallback method */ + /* Try allocating from the other tree */ + tree = (tree == DRM_BUDDY_CLEAR_TREE) ? + DRM_BUDDY_DIRTY_TREE : DRM_BUDDY_CLEAR_TREE; + for (tmp = order; tmp <= mm->max_order; ++tmp) { - block = rbtree_last_entry(mm, tmp); + root = &mm->free_trees[tree][tmp]; + block = rbtree_last_free_block(root); if (block) break; } @@ -885,10 +916,9 @@ static int __alloc_contig_try_harder(struct drm_buddy *mm, { u64 rhs_offset, lhs_offset, lhs_size, filled; struct drm_buddy_block *block; + unsigned int tree, order; LIST_HEAD(blocks_lhs); - struct rb_node *iter; unsigned long pages; - unsigned int order; u64 modify_size; int err; @@ -898,40 +928,45 @@ static int __alloc_contig_try_harder(struct drm_buddy *mm, if (order == 0) return -ENOSPC; - if (rbtree_is_empty(mm, order)) - return -ENOSPC; + for_each_free_tree(tree) { + struct rb_root *root; + struct rb_node *iter; - iter = rb_last(&mm->free_tree[order]); - - while (iter) { - block = rbtree_get_free_block(iter); - - /* Allocate blocks traversing RHS */ - rhs_offset = drm_buddy_block_offset(block); - err = __drm_buddy_alloc_range(mm, rhs_offset, size, - &filled, blocks); - if (!err || err != -ENOSPC) - return err; - - lhs_size = max((size - filled), min_block_size); - if (!IS_ALIGNED(lhs_size, min_block_size)) - lhs_size = round_up(lhs_size, min_block_size); - - /* Allocate blocks traversing LHS */ - lhs_offset = drm_buddy_block_offset(block) - lhs_size; - err = __drm_buddy_alloc_range(mm, lhs_offset, lhs_size, - NULL, &blocks_lhs); - if (!err) { - list_splice(&blocks_lhs, blocks); - return 0; - } else if (err != -ENOSPC) { + root = &mm->free_trees[tree][order]; + if (rbtree_is_empty(root)) + continue; + + iter = rb_last(root); + while (iter) { + block = rbtree_get_free_block(iter); + + /* Allocate blocks traversing RHS */ + rhs_offset = drm_buddy_block_offset(block); + err = __drm_buddy_alloc_range(mm, rhs_offset, size, + &filled, blocks); + if (!err || err != -ENOSPC) + return err; + + lhs_size = max((size - filled), min_block_size); + if (!IS_ALIGNED(lhs_size, min_block_size)) + lhs_size = round_up(lhs_size, min_block_size); + + /* Allocate blocks traversing LHS */ + lhs_offset = drm_buddy_block_offset(block) - lhs_size; + err = __drm_buddy_alloc_range(mm, lhs_offset, lhs_size, + NULL, &blocks_lhs); + if (!err) { + list_splice(&blocks_lhs, blocks); + return 0; + } else if (err != -ENOSPC) { + drm_buddy_free_list_internal(mm, blocks); + return err; + } + /* Free blocks for the next iteration */ drm_buddy_free_list_internal(mm, blocks); - return err; - } - /* Free blocks for the next iteration */ - drm_buddy_free_list_internal(mm, blocks); - iter = rb_prev(iter); + iter = rb_prev(iter); + } } return -ENOSPC; @@ -1243,11 +1278,17 @@ void drm_buddy_print(struct drm_buddy *mm, struct drm_printer *p) for (order = mm->max_order; order >= 0; order--) { struct drm_buddy_block *block, *tmp; + struct rb_root *root; u64 count = 0, free; + unsigned int tree; + + for_each_free_tree(tree) { + root = &mm->free_trees[tree][order]; - rbtree_postorder_for_each_entry_safe(block, tmp, &mm->free_tree[order], rb) { - BUG_ON(!drm_buddy_block_is_free(block)); - count++; + rbtree_postorder_for_each_entry_safe(block, tmp, root, rb) { + BUG_ON(!drm_buddy_block_is_free(block)); + count++; + } } drm_printf(p, "order-%2d ", order); diff --git a/include/drm/drm_buddy.h b/include/drm/drm_buddy.h index f22d292443dbf..c2e05a2812522 100644 --- a/include/drm/drm_buddy.h +++ b/include/drm/drm_buddy.h @@ -64,7 +64,7 @@ struct drm_buddy_block { */ struct drm_buddy { /* Maintain a free list for each order. */ - struct rb_root *free_tree; + struct rb_root **free_trees; /* * Maintain explicit binary tree(s) to track the allocation of the From e2e980f091332789fc64da6a278fe35e129e4644 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Mon, 29 Sep 2025 10:23:23 +0200 Subject: [PATCH 1717/2333] drm/gma500: Remove unused helper psb_fbdev_fb_setcolreg() commit be729f9de6c64240645dc80a24162ac4d3fe00a8 upstream. Remove psb_fbdev_fb_setcolreg(), which hasn't been called in almost a decade. Gma500 commit 4d8d096e9ae8 ("gma500: introduce the framebuffer support code") added the helper psb_fbdev_fb_setcolreg() for setting the fbdev palette via fbdev's fb_setcolreg callback. Later commit 3da6c2f3b730 ("drm/gma500: use DRM_FB_HELPER_DEFAULT_OPS for fb_ops") set several default helpers for fbdev emulation, including fb_setcmap. The fbdev subsystem always prefers fb_setcmap over fb_setcolreg. [1] Hence, the gma500 code is no longer in use and gma500 has been using drm_fb_helper_setcmap() for several years without issues. Fixes: 3da6c2f3b730 ("drm/gma500: use DRM_FB_HELPER_DEFAULT_OPS for fb_ops") Cc: Patrik Jakobsson Cc: Stefan Christ Cc: Daniel Vetter Cc: dri-devel@lists.freedesktop.org Cc: # v4.10+ Link: https://elixir.bootlin.com/linux/v6.16.9/source/drivers/video/fbdev/core/fbcmap.c#L246 # [1] Signed-off-by: Thomas Zimmermann Acked-by: Patrik Jakobsson Link: https://lore.kernel.org/r/20250929082338.18845-1-tzimmermann@suse.de Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/gma500/fbdev.c | 43 ---------------------------------- 1 file changed, 43 deletions(-) diff --git a/drivers/gpu/drm/gma500/fbdev.c b/drivers/gpu/drm/gma500/fbdev.c index 32d31e5f5f1a7..a6af21514cff7 100644 --- a/drivers/gpu/drm/gma500/fbdev.c +++ b/drivers/gpu/drm/gma500/fbdev.c @@ -50,48 +50,6 @@ static const struct vm_operations_struct psb_fbdev_vm_ops = { * struct fb_ops */ -#define CMAP_TOHW(_val, _width) ((((_val) << (_width)) + 0x7FFF - (_val)) >> 16) - -static int psb_fbdev_fb_setcolreg(unsigned int regno, - unsigned int red, unsigned int green, - unsigned int blue, unsigned int transp, - struct fb_info *info) -{ - struct drm_fb_helper *fb_helper = info->par; - struct drm_framebuffer *fb = fb_helper->fb; - uint32_t v; - - if (!fb) - return -ENOMEM; - - if (regno > 255) - return 1; - - red = CMAP_TOHW(red, info->var.red.length); - blue = CMAP_TOHW(blue, info->var.blue.length); - green = CMAP_TOHW(green, info->var.green.length); - transp = CMAP_TOHW(transp, info->var.transp.length); - - v = (red << info->var.red.offset) | - (green << info->var.green.offset) | - (blue << info->var.blue.offset) | - (transp << info->var.transp.offset); - - if (regno < 16) { - switch (fb->format->cpp[0] * 8) { - case 16: - ((uint32_t *) info->pseudo_palette)[regno] = v; - break; - case 24: - case 32: - ((uint32_t *) info->pseudo_palette)[regno] = v; - break; - } - } - - return 0; -} - static int psb_fbdev_fb_mmap(struct fb_info *info, struct vm_area_struct *vma) { if (vma->vm_pgoff != 0) @@ -135,7 +93,6 @@ static const struct fb_ops psb_fbdev_fb_ops = { .owner = THIS_MODULE, __FB_DEFAULT_IOMEM_OPS_RDWR, DRM_FB_HELPER_DEFAULT_OPS, - .fb_setcolreg = psb_fbdev_fb_setcolreg, __FB_DEFAULT_IOMEM_OPS_DRAW, .fb_mmap = psb_fbdev_fb_mmap, .fb_destroy = psb_fbdev_fb_destroy, From 7cdb9a9da935c687563cc682155461fef5f9b48d Mon Sep 17 00:00:00 2001 From: Sanjay Yadav Date: Tue, 18 Nov 2025 17:19:00 +0530 Subject: [PATCH 1718/2333] drm/xe/oa: Fix potential UAF in xe_oa_add_config_ioctl() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit dcb171931954c51a1a7250d558f02b8f36570783 upstream. In xe_oa_add_config_ioctl(), we accessed oa_config->id after dropping metrics_lock. Since this lock protects the lifetime of oa_config, an attacker could guess the id and call xe_oa_remove_config_ioctl() with perfect timing, freeing oa_config before we dereference it, leading to a potential use-after-free. Fix this by caching the id in a local variable while holding the lock. v2: (Matt A) - Dropped mutex_unlock(&oa->metrics_lock) ordering change from xe_oa_remove_config_ioctl() Closes: https://gitlab.freedesktop.org/drm/xe/kernel/-/issues/6614 Fixes: cdf02fe1a94a7 ("drm/xe/oa/uapi: Add/remove OA config perf ops") Cc: # v6.11+ Suggested-by: Matthew Auld Signed-off-by: Sanjay Yadav Reviewed-by: Matthew Auld Signed-off-by: Matthew Auld Link: https://patch.msgid.link/20251118114859.3379952-2-sanjay.kumar.yadav@intel.com (cherry picked from commit 28aeaed130e8e587fd1b73b6d66ca41ccc5a1a31) Signed-off-by: Thomas Hellström Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/xe/xe_oa.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_oa.c b/drivers/gpu/drm/xe/xe_oa.c index d0ceb67af83ed..1cb7e4791c6db 100644 --- a/drivers/gpu/drm/xe/xe_oa.c +++ b/drivers/gpu/drm/xe/xe_oa.c @@ -2407,11 +2407,13 @@ int xe_oa_add_config_ioctl(struct drm_device *dev, u64 data, struct drm_file *fi goto sysfs_err; } - mutex_unlock(&oa->metrics_lock); + id = oa_config->id; + + drm_dbg(&oa->xe->drm, "Added config %s id=%i\n", oa_config->uuid, id); - drm_dbg(&oa->xe->drm, "Added config %s id=%i\n", oa_config->uuid, oa_config->id); + mutex_unlock(&oa->metrics_lock); - return oa_config->id; + return id; sysfs_err: mutex_unlock(&oa->metrics_lock); From 78bc88fda96c1759ced089a65747be37daa06928 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Wed, 22 Oct 2025 19:19:48 +0300 Subject: [PATCH 1719/2333] drm/rockchip: Set VOP for the DRM DMA device commit 7d7bb790aced3b1b8550b74e02fdfc001d044bee upstream. Use VOP for DMA operations performed by DRM core. Rockchip DRM driver is backed by a virtual device that isn't IOMMU-capable, while VOP is the actual display controller device backed by IOMMU. Fixes "swiotlb buffer is full" warning messages originated from GEM prime code paths. Note, that backporting is non-trivial as this depends on commit 143ec8d3f9396 ("drm/prime: Support dedicated DMA device for dma-buf imports"), which landed in v6.16 and commit 421be3ee36a4 ("drm/rockchip: Refactor IOMMU initialisation"), which landed in v5.19. Reported-by: Daniel Stone Fixes: 2048e3286f34 ("drm: rockchip: Add basic drm driver") Cc: stable@vger.kernel.org # v6.16+ Reviewed-by: Sebastian Reichel Signed-off-by: Dmitry Osipenko Tested-by: Cristian Ciocaltea Signed-off-by: Heiko Stuebner Link: https://lore.kernel.org/r/20251022161948.199731-1-dmitry.osipenko@collabora.com Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c index eb77bde9f6283..e693160e9b7f5 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c @@ -96,6 +96,9 @@ void rockchip_drm_dma_init_device(struct drm_device *drm_dev, private->iommu_dev = ERR_PTR(-ENODEV); else if (!private->iommu_dev) private->iommu_dev = dev; + + if (!IS_ERR(private->iommu_dev)) + drm_dev_set_dma_dev(drm_dev, private->iommu_dev); } static int rockchip_drm_init_iommu(struct drm_device *drm_dev) From 4fcb7f89479b2427f216ad62d8b1519d213bd38a Mon Sep 17 00:00:00 2001 From: Miaoqian Lin Date: Wed, 29 Oct 2025 15:23:06 +0800 Subject: [PATCH 1720/2333] drm/mediatek: Fix device node reference leak in mtk_dp_dt_parse() commit a846505a193d7492ad3531e33cacfca31e4bcdd1 upstream. The function mtk_dp_dt_parse() calls of_graph_get_endpoint_by_regs() to get the endpoint device node, but fails to call of_node_put() to release the reference when the function returns. This results in a device node reference leak. Fix this by adding the missing of_node_put() call before returning from the function. Found via static analysis and code review. Fixes: f70ac097a2cf ("drm/mediatek: Add MT8195 Embedded DisplayPort driver") Cc: stable@vger.kernel.org Signed-off-by: Miaoqian Lin Reviewed-by: Markus Schneider-Pargmann Reviewed-by: CK Hu Link: https://patchwork.kernel.org/project/dri-devel/patch/20251029072307.10955-1-linmq006@gmail.com/ Signed-off-by: Chun-Kuang Hu Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/mediatek/mtk_dp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c b/drivers/gpu/drm/mediatek/mtk_dp.c index bef6eeb30d3ec..b0b1e158600f3 100644 --- a/drivers/gpu/drm/mediatek/mtk_dp.c +++ b/drivers/gpu/drm/mediatek/mtk_dp.c @@ -2087,6 +2087,7 @@ static int mtk_dp_dt_parse(struct mtk_dp *mtk_dp, endpoint = of_graph_get_endpoint_by_regs(pdev->dev.of_node, 1, -1); len = of_property_count_elems_of_size(endpoint, "data-lanes", sizeof(u32)); + of_node_put(endpoint); if (len < 0 || len > 4 || len == 3) { dev_err(dev, "invalid data lane size: %d\n", len); return -EINVAL; From 54291161eeaaea7b3e1d059a9ec9295337af636c Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 23 Sep 2025 17:23:36 +0200 Subject: [PATCH 1721/2333] drm/mediatek: Fix probe resource leaks commit 07c7c640a8eb9e196f357d15d88a59602a947197 upstream. Make sure to unmap and release the component iomap and clock on probe failure (e.g. probe deferral) and on driver unbind. Note that unlike of_iomap(), devm_of_iomap() also checks whether the region is already mapped. Fixes: 119f5173628a ("drm/mediatek: Add DRM Driver for Mediatek SoC MT8173.") Cc: stable@vger.kernel.org # 4.7 Cc: CK Hu Signed-off-by: Johan Hovold Reviewed-by: AngeloGioacchino Del Regno Link: https://patchwork.kernel.org/project/dri-devel/patch/20250923152340.18234-2-johan@kernel.org/ Signed-off-by: Chun-Kuang Hu Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/mediatek/mtk_ddp_comp.c | 20 ++++++++++++++++---- drivers/gpu/drm/mediatek/mtk_ddp_comp.h | 2 +- drivers/gpu/drm/mediatek/mtk_drm_drv.c | 4 ++-- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/mediatek/mtk_ddp_comp.c b/drivers/gpu/drm/mediatek/mtk_ddp_comp.c index ac6620e10262e..0264017806adc 100644 --- a/drivers/gpu/drm/mediatek/mtk_ddp_comp.c +++ b/drivers/gpu/drm/mediatek/mtk_ddp_comp.c @@ -621,15 +621,20 @@ int mtk_find_possible_crtcs(struct drm_device *drm, struct device *dev) return ret; } -int mtk_ddp_comp_init(struct device_node *node, struct mtk_ddp_comp *comp, +static void mtk_ddp_comp_clk_put(void *_clk) +{ + struct clk *clk = _clk; + + clk_put(clk); +} + +int mtk_ddp_comp_init(struct device *dev, struct device_node *node, struct mtk_ddp_comp *comp, unsigned int comp_id) { struct platform_device *comp_pdev; enum mtk_ddp_comp_type type; struct mtk_ddp_comp_dev *priv; -#if IS_REACHABLE(CONFIG_MTK_CMDQ) int ret; -#endif if (comp_id >= DDP_COMPONENT_DRM_ID_MAX) return -EINVAL; @@ -670,11 +675,18 @@ int mtk_ddp_comp_init(struct device_node *node, struct mtk_ddp_comp *comp, if (!priv) return -ENOMEM; - priv->regs = of_iomap(node, 0); + priv->regs = devm_of_iomap(dev, node, 0, NULL); + if (IS_ERR(priv->regs)) + return PTR_ERR(priv->regs); + priv->clk = of_clk_get(node, 0); if (IS_ERR(priv->clk)) return PTR_ERR(priv->clk); + ret = devm_add_action_or_reset(dev, mtk_ddp_comp_clk_put, priv->clk); + if (ret) + return ret; + #if IS_REACHABLE(CONFIG_MTK_CMDQ) ret = cmdq_dev_get_client_reg(comp->dev, &priv->cmdq_reg, 0); if (ret) diff --git a/drivers/gpu/drm/mediatek/mtk_ddp_comp.h b/drivers/gpu/drm/mediatek/mtk_ddp_comp.h index 7289b3dcf22f2..3f3d43f4330da 100644 --- a/drivers/gpu/drm/mediatek/mtk_ddp_comp.h +++ b/drivers/gpu/drm/mediatek/mtk_ddp_comp.h @@ -350,7 +350,7 @@ static inline void mtk_ddp_comp_encoder_index_set(struct mtk_ddp_comp *comp) int mtk_ddp_comp_get_id(struct device_node *node, enum mtk_ddp_comp_type comp_type); int mtk_find_possible_crtcs(struct drm_device *drm, struct device *dev); -int mtk_ddp_comp_init(struct device_node *comp_node, struct mtk_ddp_comp *comp, +int mtk_ddp_comp_init(struct device *dev, struct device_node *comp_node, struct mtk_ddp_comp *comp, unsigned int comp_id); enum mtk_ddp_comp_type mtk_ddp_comp_get_type(unsigned int comp_id); void mtk_ddp_write(struct cmdq_pkt *cmdq_pkt, unsigned int value, diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c index 31ff2922758a4..a94c51a832616 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c @@ -1123,7 +1123,7 @@ static int mtk_drm_probe(struct platform_device *pdev) (void *)private->mmsys_dev, sizeof(*private->mmsys_dev)); private->ddp_comp[DDP_COMPONENT_DRM_OVL_ADAPTOR].dev = &ovl_adaptor->dev; - mtk_ddp_comp_init(NULL, &private->ddp_comp[DDP_COMPONENT_DRM_OVL_ADAPTOR], + mtk_ddp_comp_init(dev, NULL, &private->ddp_comp[DDP_COMPONENT_DRM_OVL_ADAPTOR], DDP_COMPONENT_DRM_OVL_ADAPTOR); component_match_add(dev, &match, compare_dev, &ovl_adaptor->dev); } @@ -1189,7 +1189,7 @@ static int mtk_drm_probe(struct platform_device *pdev) node); } - ret = mtk_ddp_comp_init(node, &private->ddp_comp[comp_id], comp_id); + ret = mtk_ddp_comp_init(dev, node, &private->ddp_comp[comp_id], comp_id); if (ret) { of_node_put(node); goto err_node; From e048e15c97e827ef7f6500292dc3d528f556742f Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 23 Sep 2025 17:23:37 +0200 Subject: [PATCH 1722/2333] drm/mediatek: Fix probe memory leak commit 5e49200593f331cd0629b5376fab9192f698e8ef upstream. The Mediatek DRM driver allocates private data for components without a platform driver but as the lifetime is tied to each component device, the memory is never freed. Tie the allocation lifetime to the DRM platform device so that the memory is released on probe failure (e.g. probe deferral) and when the driver is unbound. Fixes: c0d36de868a6 ("drm/mediatek: Move clk info from struct mtk_ddp_comp to sub driver private data") Cc: stable@vger.kernel.org # 5.12 Cc: CK Hu Signed-off-by: Johan Hovold Reviewed-by: AngeloGioacchino Del Regno Link: https://patchwork.kernel.org/project/dri-devel/patch/20250923152340.18234-3-johan@kernel.org/ Signed-off-by: Chun-Kuang Hu Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/mediatek/mtk_ddp_comp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/mediatek/mtk_ddp_comp.c b/drivers/gpu/drm/mediatek/mtk_ddp_comp.c index 0264017806adc..31d67a131c503 100644 --- a/drivers/gpu/drm/mediatek/mtk_ddp_comp.c +++ b/drivers/gpu/drm/mediatek/mtk_ddp_comp.c @@ -671,7 +671,7 @@ int mtk_ddp_comp_init(struct device *dev, struct device_node *node, struct mtk_d type == MTK_DSI) return 0; - priv = devm_kzalloc(comp->dev, sizeof(*priv), GFP_KERNEL); + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; From 8f059592969d0b21b873be5db26df262d1dc1fa1 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 23 Sep 2025 17:23:38 +0200 Subject: [PATCH 1723/2333] drm/mediatek: Fix probe device leaks commit 2a2a04be8e869a19c9f950b89b1e05832a0f7ec7 upstream. Make sure to drop the reference taken to each component device during probe on probe failure (e.g. probe deferral) and on driver unbind. Fixes: 6ea6f8276725 ("drm/mediatek: Use correct device pointer to get CMDQ client register") Cc: stable@vger.kernel.org # 5.12 Cc: Chun-Kuang Hu Signed-off-by: Johan Hovold Reviewed-by: AngeloGioacchino Del Regno Link: https://patchwork.kernel.org/project/dri-devel/patch/20250923152340.18234-4-johan@kernel.org/ Signed-off-by: Chun-Kuang Hu Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/mediatek/mtk_ddp_comp.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/gpu/drm/mediatek/mtk_ddp_comp.c b/drivers/gpu/drm/mediatek/mtk_ddp_comp.c index 31d67a131c503..9672ea1f91a2b 100644 --- a/drivers/gpu/drm/mediatek/mtk_ddp_comp.c +++ b/drivers/gpu/drm/mediatek/mtk_ddp_comp.c @@ -621,6 +621,13 @@ int mtk_find_possible_crtcs(struct drm_device *drm, struct device *dev) return ret; } +static void mtk_ddp_comp_put_device(void *_dev) +{ + struct device *dev = _dev; + + put_device(dev); +} + static void mtk_ddp_comp_clk_put(void *_clk) { struct clk *clk = _clk; @@ -656,6 +663,10 @@ int mtk_ddp_comp_init(struct device *dev, struct device_node *node, struct mtk_d } comp->dev = &comp_pdev->dev; + ret = devm_add_action_or_reset(dev, mtk_ddp_comp_put_device, comp->dev); + if (ret) + return ret; + if (type == MTK_DISP_AAL || type == MTK_DISP_BLS || type == MTK_DISP_CCORR || From b3e92227862263570172887af33d034f2c777793 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 23 Sep 2025 17:23:39 +0200 Subject: [PATCH 1724/2333] drm/mediatek: mtk_hdmi: Fix probe device leaks commit 9545bae5c8acd5a47af7add606718d94578bd838 upstream. Make sure to drop the references to the DDC adapter and CEC device taken during probe on probe failure (e.g. probe deferral) and on driver unbind. Fixes: 8f83f26891e1 ("drm/mediatek: Add HDMI support") Cc: stable@vger.kernel.org # 4.8 Cc: Jie Qiu Signed-off-by: Johan Hovold Reviewed-by: AngeloGioacchino Del Regno Link: https://patchwork.kernel.org/project/dri-devel/patch/20250923152340.18234-5-johan@kernel.org/ Signed-off-by: Chun-Kuang Hu Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/mediatek/mtk_hdmi.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi.c b/drivers/gpu/drm/mediatek/mtk_hdmi.c index b766dd5e6c8de..306e2c9073114 100644 --- a/drivers/gpu/drm/mediatek/mtk_hdmi.c +++ b/drivers/gpu/drm/mediatek/mtk_hdmi.c @@ -1345,6 +1345,13 @@ static const struct drm_bridge_funcs mtk_hdmi_bridge_funcs = { .edid_read = mtk_hdmi_bridge_edid_read, }; +static void mtk_hdmi_put_device(void *_dev) +{ + struct device *dev = _dev; + + put_device(dev); +} + static int mtk_hdmi_get_cec_dev(struct mtk_hdmi *hdmi, struct device *dev, struct device_node *np) { struct platform_device *cec_pdev; @@ -1369,6 +1376,10 @@ static int mtk_hdmi_get_cec_dev(struct mtk_hdmi *hdmi, struct device *dev, struc } of_node_put(cec_np); + ret = devm_add_action_or_reset(dev, mtk_hdmi_put_device, &cec_pdev->dev); + if (ret) + return ret; + /* * The mediatek,syscon-hdmi property contains a phandle link to the * MMSYS_CONFIG device and the register offset of the HDMI_SYS_CFG @@ -1423,6 +1434,10 @@ static int mtk_hdmi_dt_parse_pdata(struct mtk_hdmi *hdmi, if (!hdmi->ddc_adpt) return dev_err_probe(dev, -EINVAL, "Failed to get ddc i2c adapter by node\n"); + ret = devm_add_action_or_reset(dev, mtk_hdmi_put_device, &hdmi->ddc_adpt->dev); + if (ret) + return ret; + ret = mtk_hdmi_get_cec_dev(hdmi, dev, np); if (ret) return ret; From fa6cd92304447571813df840323855a7e0f95953 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 23 Sep 2025 17:23:40 +0200 Subject: [PATCH 1725/2333] drm/mediatek: ovl_adaptor: Fix probe device leaks commit e0f44f74ed6313e50b38eb39a2c7f210ae208db2 upstream. Make sure to drop the references taken to the component devices by of_find_device_by_node() during probe on probe failure (e.g. probe deferral) and on driver unbind. Fixes: 453c3364632a ("drm/mediatek: Add ovl_adaptor support for MT8195") Cc: stable@vger.kernel.org # 6.4 Cc: Nancy.Lin Signed-off-by: Johan Hovold Reviewed-by: AngeloGioacchino Del Regno Link: https://patchwork.kernel.org/project/dri-devel/patch/20250923152340.18234-6-johan@kernel.org/ Signed-off-by: Chun-Kuang Hu Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/mediatek/mtk_disp_ovl_adaptor.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ovl_adaptor.c b/drivers/gpu/drm/mediatek/mtk_disp_ovl_adaptor.c index fe97bb97e004a..c0af3e3b51d55 100644 --- a/drivers/gpu/drm/mediatek/mtk_disp_ovl_adaptor.c +++ b/drivers/gpu/drm/mediatek/mtk_disp_ovl_adaptor.c @@ -527,6 +527,13 @@ bool mtk_ovl_adaptor_is_comp_present(struct device_node *node) type == OVL_ADAPTOR_TYPE_PADDING; } +static void ovl_adaptor_put_device(void *_dev) +{ + struct device *dev = _dev; + + put_device(dev); +} + static int ovl_adaptor_comp_init(struct device *dev, struct component_match **match) { struct mtk_disp_ovl_adaptor *priv = dev_get_drvdata(dev); @@ -560,6 +567,11 @@ static int ovl_adaptor_comp_init(struct device *dev, struct component_match **ma if (!comp_pdev) return -EPROBE_DEFER; + ret = devm_add_action_or_reset(dev, ovl_adaptor_put_device, + &comp_pdev->dev); + if (ret) + return ret; + priv->ovl_adaptor_comp[id] = &comp_pdev->dev; drm_of_component_match_add(dev, match, component_compare_of, node); From 355d4d4ffaf853200149faf6d1da9d9b2ddfbe92 Mon Sep 17 00:00:00 2001 From: "Mario Limonciello (AMD)" Date: Mon, 8 Dec 2025 22:46:46 -0600 Subject: [PATCH 1726/2333] drm/amd: Fix unbind/rebind for VCN 4.0.5 commit 93a01629c8bfd30906c76921ec986802d76920c6 upstream. Unbinding amdgpu has no problems, but binding it again leads to an error of sysfs file already existing. This is because it wasn't actually cleaned up on unbind. Add the missing cleanup step. Fixes: 547aad32edac ("drm/amdgpu: add VCN4 ip block support") Signed-off-by: Mario Limonciello (AMD) Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher (cherry picked from commit d717e62e9b6ccff0e3cec78a58dfbd00858448b3) Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c index b107ee80e4728..1f6a22983c0dd 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c @@ -265,6 +265,8 @@ static int vcn_v4_0_5_sw_fini(struct amdgpu_ip_block *ip_block) if (amdgpu_sriov_vf(adev)) amdgpu_virt_free_mm_table(adev); + amdgpu_vcn_sysfs_reset_mask_fini(adev); + for (i = 0; i < adev->vcn.num_vcn_inst; i++) { r = amdgpu_vcn_suspend(adev, i); if (r) From ec648d8c2db78a6c31e43c3896378eb3dbbe2fd7 Mon Sep 17 00:00:00 2001 From: Andy Yan Date: Wed, 12 Nov 2025 16:50:23 +0800 Subject: [PATCH 1727/2333] drm/rockchip: vop2: Use OVL_LAYER_SEL configuration instead of use win_mask calculate used layers commit d3fe9aa495854f8d88c69c41a4b31e69424656ad upstream. When there are multiple Video Ports, and only one of them is working (for example, VP1 is working while VP0 is not), in this case, the win_mask of VP0 is 0. However, we have already set the port mux for VP0 according to vp0->nlayers, and at the same time, in the OVL_LAYER_SEL register, there are windows will also be assigned to layers which will map to the inactive VPs. In this situation, vp0->win_mask is zero as it now working, it is more reliable to calculate the used layers based on the configuration of the OVL_LAYER_SEL register. Note: as the configuration of OVL_LAYER_SEL is take effect when the vsync is come, so we use the value backup in vop2->old_layer_sel instead of read OVL_LAYER_SEL directly. Fixes: 3e89a8c68354 ("drm/rockchip: vop2: Fix the update of LAYER/PORT select registers when there are multi display output on rk3588/rk3568") Cc: stable@vger.kernel.org Reported-by: Diederik de Haas Closes: https://bugs.kde.org/show_bug.cgi?id=511274 Signed-off-by: Andy Yan Tested-by: Dang Huynh Tested-by: Diederik de Haas Signed-off-by: Heiko Stuebner Link: https://lore.kernel.org/r/20251112085024.2480111-1-andyshrk@163.com Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/rockchip/rockchip_vop2_reg.c | 49 +++++++++++++++++--- 1 file changed, 42 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c index 38c49030c7ab6..cd8380f0eddc8 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c +++ b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c @@ -1369,6 +1369,25 @@ static const struct vop2_regs_dump rk3588_regs_dump[] = { }, }; +/* + * phys_id is used to identify a main window(Cluster Win/Smart Win, not + * include the sub win of a cluster or the multi area) that can do overlay + * in main overlay stage. + */ +static struct vop2_win *vop2_find_win_by_phys_id(struct vop2 *vop2, uint8_t phys_id) +{ + struct vop2_win *win; + int i; + + for (i = 0; i < vop2->data->win_size; i++) { + win = &vop2->win[i]; + if (win->data->phys_id == phys_id) + return win; + } + + return NULL; +} + static unsigned long rk3568_set_intf_mux(struct vop2_video_port *vp, int id, u32 polflags) { struct vop2 *vop2 = vp->vop2; @@ -1842,15 +1861,31 @@ static void vop2_parse_alpha(struct vop2_alpha_config *alpha_config, alpha->dst_alpha_ctrl.bits.factor_mode = ALPHA_SRC_INVERSE; } -static int vop2_find_start_mixer_id_for_vp(struct vop2 *vop2, u8 port_id) +static int vop2_find_start_mixer_id_for_vp(struct vop2_video_port *vp) { - struct vop2_video_port *vp; - int used_layer = 0; + struct vop2 *vop2 = vp->vop2; + struct vop2_win *win; + u32 layer_sel = vop2->old_layer_sel; + u32 used_layer = 0; + unsigned long win_mask = vp->win_mask; + unsigned long phys_id; + bool match; int i; - for (i = 0; i < port_id; i++) { - vp = &vop2->vps[i]; - used_layer += hweight32(vp->win_mask); + for (i = 0; i < 31; i += 4) { + match = false; + for_each_set_bit(phys_id, &win_mask, ROCKCHIP_VOP2_ESMART3) { + win = vop2_find_win_by_phys_id(vop2, phys_id); + if (win->data->layer_sel_id[vp->id] == ((layer_sel >> i) & 0xf)) { + match = true; + break; + } + } + + if (!match) + used_layer += 1; + else + break; } return used_layer; @@ -1935,7 +1970,7 @@ static void vop2_setup_alpha(struct vop2_video_port *vp) u32 dst_global_alpha = DRM_BLEND_ALPHA_OPAQUE; if (vop2->version <= VOP_VERSION_RK3588) - mixer_id = vop2_find_start_mixer_id_for_vp(vop2, vp->id); + mixer_id = vop2_find_start_mixer_id_for_vp(vp); else mixer_id = 0; From 07bcf0498047e468c4d5f78c075fbf371d8fd6e7 Mon Sep 17 00:00:00 2001 From: Luca Ceresoli Date: Thu, 27 Nov 2025 09:42:40 +0100 Subject: [PATCH 1728/2333] drm/bridge: ti-sn65dsi83: ignore PLL_UNLOCK errors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 35e282c1868de3c9d15f9a8812cbb2e7da06b0c1 upstream. On hardware based on Toradex Verdin AM62 the recovery mechanism added by commit ad5c6ecef27e ("drm: bridge: ti-sn65dsi83: Add error recovery mechanism") has been reported [0] to make the display turn on and off and and the kernel logging "Unexpected link status 0x01". According to the report, the error recovery mechanism is triggered by the PLL_UNLOCK error going active. Analysis suggested the board is unable to provide the correct DSI clock neede by the SN65DSI84, to which the TI SN65DSI84 reacts by raising the PLL_UNLOCK, while the display still works apparently without issues. On other hardware, where all the clocks are within the components specifications, the PLL_UNLOCK bit does not trigger while the display is in normal use. It can trigger for e.g. electromagnetic interference, which is a transient event and exactly the reason why the error recovery mechanism has been implemented. Idelly the PLL_UNLOCK bit could be ignored when working out of specification, but this requires to detect in software whether it triggers because the device is working out of specification but visually correctly for the user or for good reasons (e.g. EMI, or even because working out of specifications but compromising the visual output). The ongoing analysis as of this writing [1][2] has not yet found a way for the driver to discriminate among the two cases. So as a temporary measure mask the PLL_UNLOCK error bit unconditionally. [0] https://lore.kernel.org/r/bhkn6hley4xrol5o3ytn343h4unkwsr26p6s6ltcwexnrsjsdx@mgkdf6ztow42 [1] https://lore.kernel.org/all/b71e941c-fc8a-4ac1-9407-0fe7df73b412@gmail.com/ [2] https://lore.kernel.org/all/20251125103900.31750-1-francesco@dolcini.it/ Fixes: ad5c6ecef27e ("drm: bridge: ti-sn65dsi83: Add error recovery mechanism") Closes: https://lore.kernel.org/r/bhkn6hley4xrol5o3ytn343h4unkwsr26p6s6ltcwexnrsjsdx@mgkdf6ztow42 Cc: stable@vger.kernel.org # 6.15+ Reported-by: João Paulo Gonçalves Tested-by: Emanuele Ghidoli Co-developed-by: Hervé Codina Signed-off-by: Hervé Codina Signed-off-by: Luca Ceresoli Link: https://patch.msgid.link/20251127-drm-ti-sn65dsi83-ignore-pll-unlock-v1-1-8a03fdf562e9@bootlin.com Signed-off-by: Maxime Ripard Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/bridge/ti-sn65dsi83.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi83.c b/drivers/gpu/drm/bridge/ti-sn65dsi83.c index 033c44326552a..fffb47b62f437 100644 --- a/drivers/gpu/drm/bridge/ti-sn65dsi83.c +++ b/drivers/gpu/drm/bridge/ti-sn65dsi83.c @@ -429,7 +429,14 @@ static void sn65dsi83_handle_errors(struct sn65dsi83 *ctx) */ ret = regmap_read(ctx->regmap, REG_IRQ_STAT, &irq_stat); - if (ret || irq_stat) { + + /* + * Some hardware (Toradex Verdin AM62) is known to report the + * PLL_UNLOCK error interrupt while working without visible + * problems. In lack of a reliable way to discriminate such cases + * from user-visible PLL_UNLOCK cases, ignore that bit entirely. + */ + if (ret || irq_stat & ~REG_IRQ_STAT_CHA_PLL_UNLOCK) { /* * IRQ acknowledged is not always possible (the bridge can be in * a state where it doesn't answer anymore). To prevent an @@ -654,7 +661,7 @@ static void sn65dsi83_atomic_enable(struct drm_bridge *bridge, if (ctx->irq) { /* Enable irq to detect errors */ regmap_write(ctx->regmap, REG_IRQ_GLOBAL, REG_IRQ_GLOBAL_IRQ_EN); - regmap_write(ctx->regmap, REG_IRQ_EN, 0xff); + regmap_write(ctx->regmap, REG_IRQ_EN, 0xff & ~REG_IRQ_EN_CHA_PLL_UNLOCK_EN); } else { /* Use the polling task */ sn65dsi83_monitor_start(ctx); From 7e56e90b988ccb5ceb77bfa4e5ebc0c6b8265bad Mon Sep 17 00:00:00 2001 From: Lyude Paul Date: Tue, 2 Dec 2025 12:59:12 -0500 Subject: [PATCH 1729/2333] drm/nouveau/gsp: Allocate fwsec-sb at boot commit da67179e5538b473a47c87e87cb35b1a7551ad9b upstream. At the moment - the memory allocation for fwsec-sb is created as-needed and is released after being used. Typically this is at some point well after driver load, which can cause runtime suspend/resume to initially work on driver load but then later fail on a machine that has been running for long enough with sufficiently high enough memory pressure: kworker/7:1: page allocation failure: order:5, mode:0xcc0(GFP_KERNEL), nodemask=(null),cpuset=/,mems_allowed=0 CPU: 7 UID: 0 PID: 875159 Comm: kworker/7:1 Not tainted 6.17.8-300.fc43.x86_64 #1 PREEMPT(lazy) Hardware name: SLIMBOOK Executive/Executive, BIOS N.1.10GRU06 02/02/2024 Workqueue: pm pm_runtime_work Call Trace: dump_stack_lvl+0x5d/0x80 warn_alloc+0x163/0x190 ? __alloc_pages_direct_compact+0x1b3/0x220 __alloc_pages_slowpath.constprop.0+0x57a/0xb10 __alloc_frozen_pages_noprof+0x334/0x350 __alloc_pages_noprof+0xe/0x20 __dma_direct_alloc_pages.isra.0+0x1eb/0x330 dma_direct_alloc_pages+0x3c/0x190 dma_alloc_pages+0x29/0x130 nvkm_firmware_ctor+0x1ae/0x280 [nouveau] nvkm_falcon_fw_ctor+0x3e/0x60 [nouveau] nvkm_gsp_fwsec+0x10e/0x2c0 [nouveau] ? sysvec_apic_timer_interrupt+0xe/0x90 nvkm_gsp_fwsec_sb+0x27/0x70 [nouveau] tu102_gsp_fini+0x65/0x110 [nouveau] ? ktime_get+0x3c/0xf0 nvkm_subdev_fini+0x67/0xc0 [nouveau] nvkm_device_fini+0x94/0x140 [nouveau] nvkm_udevice_fini+0x50/0x70 [nouveau] nvkm_object_fini+0xb1/0x140 [nouveau] nvkm_object_fini+0x70/0x140 [nouveau] ? __pfx_pci_pm_runtime_suspend+0x10/0x10 nouveau_do_suspend+0xe4/0x170 [nouveau] nouveau_pmops_runtime_suspend+0x3e/0xb0 [nouveau] pci_pm_runtime_suspend+0x67/0x1a0 ? __pfx_pci_pm_runtime_suspend+0x10/0x10 __rpm_callback+0x45/0x1f0 ? __pfx_pci_pm_runtime_suspend+0x10/0x10 rpm_callback+0x6d/0x80 rpm_suspend+0xe5/0x5e0 ? finish_task_switch.isra.0+0x99/0x2c0 pm_runtime_work+0x98/0xb0 process_one_work+0x18f/0x350 worker_thread+0x25a/0x3a0 ? __pfx_worker_thread+0x10/0x10 kthread+0xf9/0x240 ? __pfx_kthread+0x10/0x10 ? __pfx_kthread+0x10/0x10 ret_from_fork+0xf1/0x110 ? __pfx_kthread+0x10/0x10 ret_from_fork_asm+0x1a/0x30 The reason this happens is because the fwsec-sb firmware image only supports being booted from a contiguous coherent sysmem allocation. If a system runs into enough memory fragmentation from memory pressure, such as what can happen on systems with low amounts of memory, this can lead to a situation where it later becomes impossible to find space for a large enough contiguous allocation to hold fwsec-sb. This causes us to fail to boot the firmware image, causing the GPU to fail booting and causing the driver to fail. Since this firmware can't use non-contiguous allocations, the best solution to avoid this issue is to simply allocate the memory for fwsec-sb during initial driver-load, and reuse the memory allocation when fwsec-sb needs to be used. We then release the memory allocations on driver unload. Signed-off-by: Lyude Paul Fixes: 594766ca3e53 ("drm/nouveau/gsp: move booter handling to GPU-specific code") Cc: # v6.16+ Reviewed-by: Timur Tabi Link: https://patch.msgid.link/20251202175918.63533-1-lyude@redhat.com Signed-off-by: Greg Kroah-Hartman --- .../gpu/drm/nouveau/include/nvkm/subdev/gsp.h | 4 ++ .../gpu/drm/nouveau/nvkm/subdev/gsp/fwsec.c | 61 +++++++++++++------ .../gpu/drm/nouveau/nvkm/subdev/gsp/priv.h | 3 + .../drm/nouveau/nvkm/subdev/gsp/rm/r535/gsp.c | 10 ++- 4 files changed, 58 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/gsp.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/gsp.h index 226c7ec56b8ed..b8b97e10ae83e 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/gsp.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/gsp.h @@ -73,6 +73,10 @@ struct nvkm_gsp { const struct firmware *bl; const struct firmware *rm; + + struct { + struct nvkm_falcon_fw sb; + } falcon; } fws; struct nvkm_firmware fw; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/fwsec.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/fwsec.c index 5b721bd9d7994..5037602466604 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/fwsec.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/fwsec.c @@ -259,18 +259,16 @@ nvkm_gsp_fwsec_v3(struct nvkm_gsp *gsp, const char *name, } static int -nvkm_gsp_fwsec(struct nvkm_gsp *gsp, const char *name, u32 init_cmd) +nvkm_gsp_fwsec_init(struct nvkm_gsp *gsp, struct nvkm_falcon_fw *fw, const char *name, u32 init_cmd) { struct nvkm_subdev *subdev = &gsp->subdev; struct nvkm_device *device = subdev->device; struct nvkm_bios *bios = device->bios; const union nvfw_falcon_ucode_desc *desc; struct nvbios_pmuE flcn_ucode; - u8 idx, ver, hdr; u32 data; u16 size, vers; - struct nvkm_falcon_fw fw = {}; - u32 mbox0 = 0; + u8 idx, ver, hdr; int ret; /* Lookup in VBIOS. */ @@ -291,8 +289,8 @@ nvkm_gsp_fwsec(struct nvkm_gsp *gsp, const char *name, u32 init_cmd) vers = (desc->v2.Hdr & 0x0000ff00) >> 8; switch (vers) { - case 2: ret = nvkm_gsp_fwsec_v2(gsp, name, &desc->v2, size, init_cmd, &fw); break; - case 3: ret = nvkm_gsp_fwsec_v3(gsp, name, &desc->v3, size, init_cmd, &fw); break; + case 2: ret = nvkm_gsp_fwsec_v2(gsp, name, &desc->v2, size, init_cmd, fw); break; + case 3: ret = nvkm_gsp_fwsec_v3(gsp, name, &desc->v3, size, init_cmd, fw); break; default: nvkm_error(subdev, "%s(v%d): version unknown\n", name, vers); return -EINVAL; @@ -303,15 +301,19 @@ nvkm_gsp_fwsec(struct nvkm_gsp *gsp, const char *name, u32 init_cmd) return ret; } - /* Boot. */ - ret = nvkm_falcon_fw_boot(&fw, subdev, true, &mbox0, NULL, 0, 0); - nvkm_falcon_fw_dtor(&fw); - if (ret) - return ret; - return 0; } +static int +nvkm_gsp_fwsec_boot(struct nvkm_gsp *gsp, struct nvkm_falcon_fw *fw) +{ + struct nvkm_subdev *subdev = &gsp->subdev; + u32 mbox0 = 0; + + /* Boot */ + return nvkm_falcon_fw_boot(fw, subdev, true, &mbox0, NULL, 0, 0); +} + int nvkm_gsp_fwsec_sb(struct nvkm_gsp *gsp) { @@ -320,7 +322,7 @@ nvkm_gsp_fwsec_sb(struct nvkm_gsp *gsp) int ret; u32 err; - ret = nvkm_gsp_fwsec(gsp, "fwsec-sb", NVFW_FALCON_APPIF_DMEMMAPPER_CMD_SB); + ret = nvkm_gsp_fwsec_boot(gsp, &gsp->fws.falcon.sb); if (ret) return ret; @@ -334,27 +336,48 @@ nvkm_gsp_fwsec_sb(struct nvkm_gsp *gsp) return 0; } +int +nvkm_gsp_fwsec_sb_ctor(struct nvkm_gsp *gsp) +{ + return nvkm_gsp_fwsec_init(gsp, &gsp->fws.falcon.sb, "fwsec-sb", + NVFW_FALCON_APPIF_DMEMMAPPER_CMD_SB); +} + +void +nvkm_gsp_fwsec_sb_dtor(struct nvkm_gsp *gsp) +{ + nvkm_falcon_fw_dtor(&gsp->fws.falcon.sb); +} + int nvkm_gsp_fwsec_frts(struct nvkm_gsp *gsp) { struct nvkm_subdev *subdev = &gsp->subdev; struct nvkm_device *device = subdev->device; + struct nvkm_falcon_fw fw = {}; int ret; u32 err, wpr2_lo, wpr2_hi; - ret = nvkm_gsp_fwsec(gsp, "fwsec-frts", NVFW_FALCON_APPIF_DMEMMAPPER_CMD_FRTS); + ret = nvkm_gsp_fwsec_init(gsp, &fw, "fwsec-frts", NVFW_FALCON_APPIF_DMEMMAPPER_CMD_FRTS); if (ret) return ret; + ret = nvkm_gsp_fwsec_boot(gsp, &fw); + if (ret) + goto fwsec_dtor; + /* Verify. */ err = nvkm_rd32(device, 0x001400 + (0xe * 4)) >> 16; if (err) { nvkm_error(subdev, "fwsec-frts: 0x%04x\n", err); - return -EIO; + ret = -EIO; + } else { + wpr2_lo = nvkm_rd32(device, 0x1fa824); + wpr2_hi = nvkm_rd32(device, 0x1fa828); + nvkm_debug(subdev, "fwsec-frts: WPR2 @ %08x - %08x\n", wpr2_lo, wpr2_hi); } - wpr2_lo = nvkm_rd32(device, 0x1fa824); - wpr2_hi = nvkm_rd32(device, 0x1fa828); - nvkm_debug(subdev, "fwsec-frts: WPR2 @ %08x - %08x\n", wpr2_lo, wpr2_hi); - return 0; +fwsec_dtor: + nvkm_falcon_fw_dtor(&fw); + return ret; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/priv.h index c3494b7ac572b..86bdd203bc107 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/priv.h @@ -6,7 +6,10 @@ enum nvkm_acr_lsf_id; int nvkm_gsp_fwsec_frts(struct nvkm_gsp *); + +int nvkm_gsp_fwsec_sb_ctor(struct nvkm_gsp *); int nvkm_gsp_fwsec_sb(struct nvkm_gsp *); +void nvkm_gsp_fwsec_sb_dtor(struct nvkm_gsp *); struct nvkm_gsp_fwif { int version; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/gsp.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/gsp.c index 32e6a065d6d7a..2a7e80c6d70f3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/gsp.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/gsp.c @@ -1817,12 +1817,16 @@ r535_gsp_rm_boot_ctor(struct nvkm_gsp *gsp) RM_RISCV_UCODE_DESC *desc; int ret; + ret = nvkm_gsp_fwsec_sb_ctor(gsp); + if (ret) + return ret; + hdr = nvfw_bin_hdr(&gsp->subdev, fw->data); desc = (void *)fw->data + hdr->header_offset; ret = nvkm_gsp_mem_ctor(gsp, hdr->data_size, &gsp->boot.fw); if (ret) - return ret; + goto dtor_fwsec; memcpy(gsp->boot.fw.data, fw->data + hdr->data_offset, hdr->data_size); @@ -1831,6 +1835,9 @@ r535_gsp_rm_boot_ctor(struct nvkm_gsp *gsp) gsp->boot.manifest_offset = desc->manifestOffset; gsp->boot.app_version = desc->appVersion; return 0; +dtor_fwsec: + nvkm_gsp_fwsec_sb_dtor(gsp); + return ret; } static const struct nvkm_firmware_func @@ -2101,6 +2108,7 @@ r535_gsp_dtor(struct nvkm_gsp *gsp) mutex_destroy(&gsp->cmdq.mutex); nvkm_gsp_dtor_fws(gsp); + nvkm_gsp_fwsec_sb_dtor(gsp); nvkm_gsp_mem_dtor(&gsp->rmargs); nvkm_gsp_mem_dtor(&gsp->wpr_meta); From 7445db6a7d5a0242d8214582b480600b266cba9e Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Fri, 5 Dec 2025 12:41:58 -0600 Subject: [PATCH 1730/2333] drm/amdkfd: Export the cwsr_size and ctl_stack_size to userspace commit 8fc2796dea6f1210e1a01573961d5836a7ce531e upstream. This is important for userspace to avoid hardcoding VGPR size. Reviewed-by: Kent Russell Signed-off-by: Mario Limonciello Signed-off-by: Alex Deucher (cherry picked from commit 71776e0965f9f730af19c5f548827f2a7c91f5a8) Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/amd/amdkfd/kfd_topology.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c index 811636af14eaa..3eb32d58a1200 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c @@ -491,6 +491,10 @@ static ssize_t node_show(struct kobject *kobj, struct attribute *attr, dev->node_props.num_sdma_queues_per_engine); sysfs_show_32bit_prop(buffer, offs, "num_cp_queues", dev->node_props.num_cp_queues); + sysfs_show_32bit_prop(buffer, offs, "cwsr_size", + dev->node_props.cwsr_size); + sysfs_show_32bit_prop(buffer, offs, "ctl_stack_size", + dev->node_props.ctl_stack_size); if (dev->gpu) { log_max_watch_addr = From 7f26af7bf9b76c2c2a1a761aab5803e52be21eea Mon Sep 17 00:00:00 2001 From: Jonathan Kim Date: Fri, 5 Dec 2025 14:41:08 -0500 Subject: [PATCH 1731/2333] drm/amdkfd: bump minimum vgpr size for gfx1151 commit cf326449637a566ba98fb82c47d46cd479608c88 upstream. GFX1151 has 1.5x the number of available physical VGPRs per SIMD. Bump total memory availability for acquire checks on queue creation. Signed-off-by: Jonathan Kim Reviewed-by: Mario Limonciello Signed-off-by: Alex Deucher (cherry picked from commit b42f3bf9536c9b710fd1d4deb7d1b0dc819dc72d) Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/amd/amdkfd/kfd_queue.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_queue.c b/drivers/gpu/drm/amd/amdkfd/kfd_queue.c index f1e7583650c41..80c4fa2b0975d 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_queue.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_queue.c @@ -409,6 +409,7 @@ static u32 kfd_get_vgpr_size_per_cu(u32 gfxv) vgpr_size = 0x80000; else if (gfxv == 110000 || /* GFX_VERSION_PLUM_BONITO */ gfxv == 110001 || /* GFX_VERSION_WHEAT_NAS */ + gfxv == 110501 || /* GFX_VERSION_GFX1151 */ gfxv == 120000 || /* GFX_VERSION_GFX1200 */ gfxv == 120001) /* GFX_VERSION_GFX1201 */ vgpr_size = 0x60000; From eb1494204d717eede1f0316c349a047dc61b5669 Mon Sep 17 00:00:00 2001 From: Jay Cornwall Date: Fri, 14 Nov 2025 14:32:42 -0600 Subject: [PATCH 1732/2333] drm/amdkfd: Trap handler support for expert scheduling mode commit b7851f8c66191cd23a0a08bd484465ad74bbbb7d upstream. The trap may be entered with dependency checking disabled. Wait for dependency counters and save/restore scheduling mode. v2: Use ttmp1 instead of ttmp11. ttmp11 is not zero-initialized. While the trap handler does zero this field before use, a user-mode second-level trap handler could not rely on this being zero when using an older kernel mode driver. v3: Use ttmp11 primarily but copy to ttmp1 before jumping to the second level trap handler. ttmp1 is inspectable by a debugger. Unexpected bits in the unused space may regress existing software. Signed-off-by: Jay Cornwall Reviewed-by: Lancelot Six Signed-off-by: Alex Deucher (cherry picked from commit 423888879412e94725ca2bdccd89414887d98e31) Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- .../gpu/drm/amd/amdkfd/cwsr_trap_handler.h | 62 +++++++++++-------- .../amd/amdkfd/cwsr_trap_handler_gfx12.asm | 37 +++++++++++ 2 files changed, 73 insertions(+), 26 deletions(-) diff --git a/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler.h b/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler.h index 0320163b6e740..f98c735b2905f 100644 --- a/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler.h +++ b/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler.h @@ -3644,14 +3644,18 @@ static const uint32_t cwsr_trap_gfx9_4_3_hex[] = { }; static const uint32_t cwsr_trap_gfx12_hex[] = { - 0xbfa00001, 0xbfa002a2, - 0xb0804009, 0xb8f8f804, + 0xbfa00001, 0xbfa002b2, + 0xb0804009, 0xb8eef81a, + 0xbf880000, 0xb980081a, + 0x00000000, 0xb8f8f804, + 0x9177ff77, 0x0c000000, + 0x846e9a6e, 0x8c776e77, 0x9178ff78, 0x00008c00, 0xb8fbf811, 0x8b6eff78, 0x00004000, 0xbfa10008, 0x8b6eff7b, 0x00000080, 0xbfa20018, 0x8b6ea07b, - 0xbfa20042, 0xbf830010, + 0xbfa2004a, 0xbf830010, 0xb8fbf811, 0xbfa0fffb, 0x8b6eff7b, 0x00000bd0, 0xbfa20010, 0xb8eef812, @@ -3662,28 +3666,32 @@ static const uint32_t cwsr_trap_gfx12_hex[] = { 0xf0000000, 0xbfa20005, 0x8b6fff6f, 0x00000200, 0xbfa20002, 0x8b6ea07b, - 0xbfa2002c, 0xbefa4d82, + 0xbfa20034, 0xbefa4d82, 0xbf8a0000, 0x84fa887a, 0xbf0d8f7b, 0xbfa10002, 0x8c7bff7b, 0xffff0000, - 0xf4601bbd, 0xf8000010, - 0xbf8a0000, 0x846e976e, - 0x9177ff77, 0x00800000, - 0x8c776e77, 0xf4603bbd, - 0xf8000000, 0xbf8a0000, - 0xf4603ebd, 0xf8000008, - 0xbf8a0000, 0x8bee6e6e, - 0xbfa10001, 0xbe80486e, - 0x8b6eff6d, 0xf0000000, - 0xbfa20009, 0xb8eef811, - 0x8b6eff6e, 0x00000080, - 0xbfa20007, 0x8c78ff78, - 0x00004000, 0x80ec886c, - 0x82ed806d, 0xbfa00002, - 0x806c846c, 0x826d806d, - 0x8b6dff6d, 0x0000ffff, - 0x8bfe7e7e, 0x8bea6a6a, - 0x85788978, 0xb9783244, + 0x8b6eff77, 0x0c000000, + 0x916dff6d, 0x0c000000, + 0x8c6d6e6d, 0xf4601bbd, + 0xf8000010, 0xbf8a0000, + 0x846e976e, 0x9177ff77, + 0x00800000, 0x8c776e77, + 0xf4603bbd, 0xf8000000, + 0xbf8a0000, 0xf4603ebd, + 0xf8000008, 0xbf8a0000, + 0x8bee6e6e, 0xbfa10001, + 0xbe80486e, 0x8b6eff6d, + 0xf0000000, 0xbfa20009, + 0xb8eef811, 0x8b6eff6e, + 0x00000080, 0xbfa20007, + 0x8c78ff78, 0x00004000, + 0x80ec886c, 0x82ed806d, + 0xbfa00002, 0x806c846c, + 0x826d806d, 0x8b6dff6d, + 0x0000ffff, 0x8bfe7e7e, + 0x8bea6a6a, 0x85788978, + 0x936eff77, 0x0002001a, + 0xb96ef81a, 0xb9783244, 0xbe804a6c, 0xb8faf802, 0xbf0d987a, 0xbfa10001, 0xbfb00000, 0x8b6dff6d, @@ -3981,7 +3989,7 @@ static const uint32_t cwsr_trap_gfx12_hex[] = { 0x008ce800, 0x00000000, 0x807d817d, 0x8070ff70, 0x00000080, 0xbf0a7b7d, - 0xbfa2fff7, 0xbfa0016e, + 0xbfa2fff7, 0xbfa00171, 0xbef4007e, 0x8b75ff7f, 0x0000ffff, 0x8c75ff75, 0x00040000, 0xbef60080, @@ -4163,12 +4171,14 @@ static const uint32_t cwsr_trap_gfx12_hex[] = { 0xf8000074, 0xbf8a0000, 0x8b6dff6d, 0x0000ffff, 0x8bfe7e7e, 0x8bea6a6a, - 0xb97af804, 0xbe804ec2, - 0xbf94fffe, 0xbe804a6c, + 0x936eff77, 0x0002001a, + 0xb96ef81a, 0xb97af804, 0xbe804ec2, 0xbf94fffe, - 0xbfb10000, 0xbf9f0000, + 0xbe804a6c, 0xbe804ec2, + 0xbf94fffe, 0xbfb10000, 0xbf9f0000, 0xbf9f0000, 0xbf9f0000, 0xbf9f0000, + 0xbf9f0000, 0x00000000, }; static const uint32_t cwsr_trap_gfx9_5_0_hex[] = { diff --git a/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler_gfx12.asm b/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler_gfx12.asm index 5a1a1b1f897fe..07999b4649ded 100644 --- a/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler_gfx12.asm +++ b/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler_gfx12.asm @@ -78,9 +78,16 @@ var SQ_WAVE_EXCP_FLAG_PRIV_RESTORE_PART_2_SHIFT = SQ_WAVE_EXCP_FLAG_PRIV_ILLEGAL var SQ_WAVE_EXCP_FLAG_PRIV_RESTORE_PART_2_SIZE = SQ_WAVE_EXCP_FLAG_PRIV_HOST_TRAP_SHIFT - SQ_WAVE_EXCP_FLAG_PRIV_ILLEGAL_INST_SHIFT var SQ_WAVE_EXCP_FLAG_PRIV_RESTORE_PART_3_SHIFT = SQ_WAVE_EXCP_FLAG_PRIV_WAVE_START_SHIFT var SQ_WAVE_EXCP_FLAG_PRIV_RESTORE_PART_3_SIZE = 32 - SQ_WAVE_EXCP_FLAG_PRIV_RESTORE_PART_3_SHIFT + +var SQ_WAVE_SCHED_MODE_DEP_MODE_SHIFT = 0 +var SQ_WAVE_SCHED_MODE_DEP_MODE_SIZE = 2 + var BARRIER_STATE_SIGNAL_OFFSET = 16 var BARRIER_STATE_VALID_OFFSET = 0 +var TTMP11_SCHED_MODE_SHIFT = 26 +var TTMP11_SCHED_MODE_SIZE = 2 +var TTMP11_SCHED_MODE_MASK = 0xC000000 var TTMP11_DEBUG_TRAP_ENABLED_SHIFT = 23 var TTMP11_DEBUG_TRAP_ENABLED_MASK = 0x800000 @@ -160,8 +167,19 @@ L_JUMP_TO_RESTORE: s_branch L_RESTORE L_SKIP_RESTORE: + // Assume most relaxed scheduling mode is set. Save and revert to normal mode. + s_getreg_b32 ttmp2, hwreg(HW_REG_WAVE_SCHED_MODE) + s_wait_alu 0 + s_setreg_imm32_b32 hwreg(HW_REG_WAVE_SCHED_MODE, \ + SQ_WAVE_SCHED_MODE_DEP_MODE_SHIFT, SQ_WAVE_SCHED_MODE_DEP_MODE_SIZE), 0 + s_getreg_b32 s_save_state_priv, hwreg(HW_REG_WAVE_STATE_PRIV) //save STATUS since we will change SCC + // Save SCHED_MODE[1:0] into ttmp11[27:26]. + s_andn2_b32 ttmp11, ttmp11, TTMP11_SCHED_MODE_MASK + s_lshl_b32 ttmp2, ttmp2, TTMP11_SCHED_MODE_SHIFT + s_or_b32 ttmp11, ttmp11, ttmp2 + // Clear SPI_PRIO: do not save with elevated priority. // Clear ECC_ERR: prevents SQC store and triggers FATAL_HALT if setreg'd. s_andn2_b32 s_save_state_priv, s_save_state_priv, SQ_WAVE_STATE_PRIV_ALWAYS_CLEAR_MASK @@ -238,6 +256,13 @@ L_FETCH_2ND_TRAP: s_cbranch_scc0 L_NO_SIGN_EXTEND_TMA s_or_b32 ttmp15, ttmp15, 0xFFFF0000 L_NO_SIGN_EXTEND_TMA: +#if ASIC_FAMILY == CHIP_GFX12 + // Move SCHED_MODE[1:0] from ttmp11 to unused bits in ttmp1[27:26] (return PC_HI). + // The second-level trap will restore from ttmp1 for backwards compatibility. + s_and_b32 ttmp2, ttmp11, TTMP11_SCHED_MODE_MASK + s_andn2_b32 ttmp1, ttmp1, TTMP11_SCHED_MODE_MASK + s_or_b32 ttmp1, ttmp1, ttmp2 +#endif s_load_dword ttmp2, [ttmp14, ttmp15], 0x10 scope:SCOPE_SYS // debug trap enabled flag s_wait_idle @@ -287,6 +312,10 @@ L_EXIT_TRAP: // STATE_PRIV.BARRIER_COMPLETE may have changed since we read it. // Only restore fields which the trap handler changes. s_lshr_b32 s_save_state_priv, s_save_state_priv, SQ_WAVE_STATE_PRIV_SCC_SHIFT + + // Assume relaxed scheduling mode after this point. + restore_sched_mode(ttmp2) + s_setreg_b32 hwreg(HW_REG_WAVE_STATE_PRIV, SQ_WAVE_STATE_PRIV_SCC_SHIFT, \ SQ_WAVE_STATE_PRIV_POISON_ERR_SHIFT - SQ_WAVE_STATE_PRIV_SCC_SHIFT + 1), s_save_state_priv @@ -1043,6 +1072,9 @@ L_SKIP_BARRIER_RESTORE: s_and_b64 exec, exec, exec // Restore STATUS.EXECZ, not writable by s_setreg_b32 s_and_b64 vcc, vcc, vcc // Restore STATUS.VCCZ, not writable by s_setreg_b32 + // Assume relaxed scheduling mode after this point. + restore_sched_mode(s_restore_tmp) + s_setreg_b32 hwreg(HW_REG_WAVE_STATE_PRIV), s_restore_state_priv // SCC is included, which is changed by previous salu // Make barrier and LDS state visible to all waves in the group. @@ -1134,3 +1166,8 @@ function valu_sgpr_hazard end #endif end + +function restore_sched_mode(s_tmp) + s_bfe_u32 s_tmp, ttmp11, (TTMP11_SCHED_MODE_SHIFT | (TTMP11_SCHED_MODE_SIZE << 0x10)) + s_setreg_b32 hwreg(HW_REG_WAVE_SCHED_MODE), s_tmp +end From 5457bdfab729c8523220d302565e10adb57cc1a1 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Fri, 5 Dec 2025 12:35:01 +0100 Subject: [PATCH 1733/2333] drm/i915: Fix format string truncation warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 1c7f9e528f8f488b060b786bfb90b40540854db3 upstream. GCC notices that the 16-byte uabi_name field could theoretically be too small for the formatted string if the instance number exceeds 100. So grow the field to 20 bytes. drivers/gpu/drm/i915/intel_memory_region.c: In function ‘intel_memory_region_create’: drivers/gpu/drm/i915/intel_memory_region.c:273:61: error: ‘%u’ directive output may be truncated writing between 1 and 5 bytes into a region of size between 3 and 11 [-Werror=format-truncation=] 273 | snprintf(mem->uabi_name, sizeof(mem->uabi_name), "%s%u", | ^~ drivers/gpu/drm/i915/intel_memory_region.c:273:58: note: directive argument in the range [0, 65535] 273 | snprintf(mem->uabi_name, sizeof(mem->uabi_name), "%s%u", | ^~~~~~ drivers/gpu/drm/i915/intel_memory_region.c:273:9: note: ‘snprintf’ output between 7 and 19 bytes into a destination of size 16 273 | snprintf(mem->uabi_name, sizeof(mem->uabi_name), "%s%u", | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 274 | intel_memory_type_str(type), instance); | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Fixes: 3b38d3515753 ("drm/i915: Add stable memory region names") Cc: # v6.8+ Signed-off-by: Ard Biesheuvel Signed-off-by: Tvrtko Ursulin Link: https://lore.kernel.org/r/20251205113500.684286-2-ardb@kernel.org (cherry picked from commit 18476087f1a18dc279d200d934ad94fba1fb51d5) Signed-off-by: Jani Nikula Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/intel_memory_region.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_memory_region.h b/drivers/gpu/drm/i915/intel_memory_region.h index b3b75be9ced5d..e9a4e6090fe0a 100644 --- a/drivers/gpu/drm/i915/intel_memory_region.h +++ b/drivers/gpu/drm/i915/intel_memory_region.h @@ -72,7 +72,7 @@ struct intel_memory_region { u16 instance; enum intel_region_id id; char name[16]; - char uabi_name[16]; + char uabi_name[20]; bool private; /* not for userspace */ struct { From 71be8825e83c90c1e020feb77b29e6a99629e642 Mon Sep 17 00:00:00 2001 From: "Kory Maincent (TI.com)" Date: Tue, 25 Nov 2025 10:05:44 +0100 Subject: [PATCH 1734/2333] drm/tilcdc: Fix removal actions in case of failed probe commit a585c7ef9cabda58088916baedc6573e9a5cd2a7 upstream. The drm_kms_helper_poll_fini() and drm_atomic_helper_shutdown() helpers should only be called when the device has been successfully registered. Currently, these functions are called unconditionally in tilcdc_fini(), which causes warnings during probe deferral scenarios. [ 7.972317] WARNING: CPU: 0 PID: 23 at drivers/gpu/drm/drm_atomic_state_helper.c:175 drm_atomic_helper_crtc_duplicate_state+0x60/0x68 ... [ 8.005820] drm_atomic_helper_crtc_duplicate_state from drm_atomic_get_crtc_state+0x68/0x108 [ 8.005858] drm_atomic_get_crtc_state from drm_atomic_helper_disable_all+0x90/0x1c8 [ 8.005885] drm_atomic_helper_disable_all from drm_atomic_helper_shutdown+0x90/0x144 [ 8.005911] drm_atomic_helper_shutdown from tilcdc_fini+0x68/0xf8 [tilcdc] [ 8.005957] tilcdc_fini [tilcdc] from tilcdc_pdev_probe+0xb0/0x6d4 [tilcdc] Fix this by rewriting the failed probe cleanup path using the standard goto error handling pattern, which ensures that cleanup functions are only called on successfully initialized resources. Additionally, remove the now-unnecessary is_registered flag. Cc: stable@vger.kernel.org Fixes: 3c4babae3c4a ("drm: Call drm_atomic_helper_shutdown() at shutdown/remove time for misc drivers") Signed-off-by: Kory Maincent (TI.com) Reviewed-by: Douglas Anderson Reviewed-by: Luca Ceresoli Signed-off-by: Douglas Anderson Link: https://patch.msgid.link/20251125090546.137193-1-kory.maincent@bootlin.com Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/tilcdc/tilcdc_crtc.c | 2 +- drivers/gpu/drm/tilcdc/tilcdc_drv.c | 53 ++++++++++++++++++---------- drivers/gpu/drm/tilcdc/tilcdc_drv.h | 2 +- 3 files changed, 37 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c index b5f60b2b2d0e7..41802c9bd1475 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c @@ -586,7 +586,7 @@ static void tilcdc_crtc_recover_work(struct work_struct *work) drm_modeset_unlock(&crtc->mutex); } -static void tilcdc_crtc_destroy(struct drm_crtc *crtc) +void tilcdc_crtc_destroy(struct drm_crtc *crtc) { struct tilcdc_drm_private *priv = crtc->dev->dev_private; diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c index 7caec4d38ddf0..3dcbec312bacb 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c @@ -172,8 +172,7 @@ static void tilcdc_fini(struct drm_device *dev) if (priv->crtc) tilcdc_crtc_shutdown(priv->crtc); - if (priv->is_registered) - drm_dev_unregister(dev); + drm_dev_unregister(dev); drm_kms_helper_poll_fini(dev); drm_atomic_helper_shutdown(dev); @@ -220,21 +219,21 @@ static int tilcdc_init(const struct drm_driver *ddrv, struct device *dev) priv->wq = alloc_ordered_workqueue("tilcdc", 0); if (!priv->wq) { ret = -ENOMEM; - goto init_failed; + goto put_drm; } priv->mmio = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(priv->mmio)) { dev_err(dev, "failed to request / ioremap\n"); ret = PTR_ERR(priv->mmio); - goto init_failed; + goto free_wq; } priv->clk = clk_get(dev, "fck"); if (IS_ERR(priv->clk)) { dev_err(dev, "failed to get functional clock\n"); ret = -ENODEV; - goto init_failed; + goto free_wq; } pm_runtime_enable(dev); @@ -313,7 +312,7 @@ static int tilcdc_init(const struct drm_driver *ddrv, struct device *dev) ret = tilcdc_crtc_create(ddev); if (ret < 0) { dev_err(dev, "failed to create crtc\n"); - goto init_failed; + goto disable_pm; } modeset_init(ddev); @@ -324,46 +323,46 @@ static int tilcdc_init(const struct drm_driver *ddrv, struct device *dev) if (ret) { dev_err(dev, "failed to register cpufreq notifier\n"); priv->freq_transition.notifier_call = NULL; - goto init_failed; + goto destroy_crtc; } #endif if (priv->is_componentized) { ret = component_bind_all(dev, ddev); if (ret < 0) - goto init_failed; + goto unregister_cpufreq_notif; ret = tilcdc_add_component_encoder(ddev); if (ret < 0) - goto init_failed; + goto unbind_component; } else { ret = tilcdc_attach_external_device(ddev); if (ret) - goto init_failed; + goto unregister_cpufreq_notif; } if (!priv->external_connector && ((priv->num_encoders == 0) || (priv->num_connectors == 0))) { dev_err(dev, "no encoders/connectors found\n"); ret = -EPROBE_DEFER; - goto init_failed; + goto unbind_component; } ret = drm_vblank_init(ddev, 1); if (ret < 0) { dev_err(dev, "failed to initialize vblank\n"); - goto init_failed; + goto unbind_component; } ret = platform_get_irq(pdev, 0); if (ret < 0) - goto init_failed; + goto unbind_component; priv->irq = ret; ret = tilcdc_irq_install(ddev, priv->irq); if (ret < 0) { dev_err(dev, "failed to install IRQ handler\n"); - goto init_failed; + goto unbind_component; } drm_mode_config_reset(ddev); @@ -372,16 +371,34 @@ static int tilcdc_init(const struct drm_driver *ddrv, struct device *dev) ret = drm_dev_register(ddev, 0); if (ret) - goto init_failed; - priv->is_registered = true; + goto stop_poll; drm_client_setup_with_color_mode(ddev, bpp); return 0; -init_failed: - tilcdc_fini(ddev); +stop_poll: + drm_kms_helper_poll_fini(ddev); + tilcdc_irq_uninstall(ddev); +unbind_component: + if (priv->is_componentized) + component_unbind_all(dev, ddev); +unregister_cpufreq_notif: +#ifdef CONFIG_CPU_FREQ + cpufreq_unregister_notifier(&priv->freq_transition, + CPUFREQ_TRANSITION_NOTIFIER); +destroy_crtc: +#endif + tilcdc_crtc_destroy(priv->crtc); +disable_pm: + pm_runtime_disable(dev); + clk_put(priv->clk); +free_wq: + destroy_workqueue(priv->wq); +put_drm: platform_set_drvdata(pdev, NULL); + ddev->dev_private = NULL; + drm_dev_put(ddev); return ret; } diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.h b/drivers/gpu/drm/tilcdc/tilcdc_drv.h index b818448c83f61..58b276f82a669 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.h +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.h @@ -82,7 +82,6 @@ struct tilcdc_drm_private { struct drm_encoder *external_encoder; struct drm_connector *external_connector; - bool is_registered; bool is_componentized; bool irq_enabled; }; @@ -164,6 +163,7 @@ void tilcdc_crtc_set_panel_info(struct drm_crtc *crtc, void tilcdc_crtc_set_simulate_vesa_sync(struct drm_crtc *crtc, bool simulate_vesa_sync); void tilcdc_crtc_shutdown(struct drm_crtc *crtc); +void tilcdc_crtc_destroy(struct drm_crtc *crtc); int tilcdc_crtc_update_fb(struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_pending_vblank_event *event); From b94182b3d7228aec18d069cba56d5982e9bfe1b1 Mon Sep 17 00:00:00 2001 From: Simon Richter Date: Tue, 14 Oct 2025 01:11:33 +0900 Subject: [PATCH 1735/2333] drm/ttm: Avoid NULL pointer deref for evicted BOs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 491adc6a0f9903c32b05f284df1148de39e8e644 upstream. It is possible for a BO to exist that is not currently associated with a resource, e.g. because it has been evicted. When devcoredump tries to read the contents of all BOs for dumping, we need to expect this as well -- in this case, ENODATA is recorded instead of the buffer contents. Fixes: 7d08df5d0bd3 ("drm/ttm: Add ttm_bo_access") Fixes: 09ac4fcb3f25 ("drm/ttm: Implement vm_operations_struct.access v2") Cc: stable Closes: https://gitlab.freedesktop.org/drm/xe/kernel/-/issues/6271 Signed-off-by: Simon Richter Reviewed-by: Matthew Brost Reviewed-by: Shuicheng Lin Reviewed-by: Christian König Signed-off-by: Matthew Brost Link: https://patch.msgid.link/20251013161241.709916-1-Simon.Richter@hogyros.de Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/ttm/ttm_bo_vm.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/gpu/drm/ttm/ttm_bo_vm.c b/drivers/gpu/drm/ttm/ttm_bo_vm.c index b47020fca1992..e6abc7b40b189 100644 --- a/drivers/gpu/drm/ttm/ttm_bo_vm.c +++ b/drivers/gpu/drm/ttm/ttm_bo_vm.c @@ -434,6 +434,11 @@ int ttm_bo_access(struct ttm_buffer_object *bo, unsigned long offset, if (ret) return ret; + if (!bo->resource) { + ret = -ENODATA; + goto unlock; + } + switch (bo->resource->mem_type) { case TTM_PL_SYSTEM: fallthrough; @@ -448,6 +453,7 @@ int ttm_bo_access(struct ttm_buffer_object *bo, unsigned long offset, ret = -EIO; } +unlock: ttm_bo_unreserve(bo); return ret; From 635c8d6e72f6e6912b11fd8d534f35062221fbd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Rebe?= Date: Mon, 8 Dec 2025 14:18:27 +0100 Subject: [PATCH 1736/2333] drm/mgag200: Fix big-endian support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 6cb31fba137d45e682ce455b8ea364f44d5d4f98 upstream. Unlike the original, deleted Matrox mga driver, the new mgag200 driver has the XRGB frame-buffer byte swapped on big-endian "RISC" systems. Fix by enabling byte swapping "PowerPC" OPMODE for any __BIG_ENDIAN config. Fixes: 414c45310625 ("mgag200: initial g200se driver (v2)") Signed-off-by: René Rebe Cc: stable@kernel.org Reviewed-by: Thomas Zimmermann Signed-off-by: Thomas Zimmermann Link: https://patch.msgid.link/20251208.141827.965103015954471168.rene@exactco.de Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/mgag200/mgag200_mode.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index 951d715dea301..d019177462cf7 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -161,6 +161,30 @@ static void mgag200_set_startadd(struct mga_device *mdev, WREG_ECRT(0x00, crtcext0); } +/* + * Set the opmode for the hardware swapper for Big-Endian processor + * support for the frame buffer aperture and DMAWIN space. + */ +static void mgag200_set_datasiz(struct mga_device *mdev, u32 format) +{ +#if defined(__BIG_ENDIAN) + u32 opmode = RREG32(MGAREG_OPMODE); + + opmode &= ~(GENMASK(17, 16) | GENMASK(9, 8) | GENMASK(3, 2)); + + /* Big-endian byte-swapping */ + switch (format) { + case DRM_FORMAT_RGB565: + opmode |= 0x10100; + break; + case DRM_FORMAT_XRGB8888: + opmode |= 0x20200; + break; + } + WREG32(MGAREG_OPMODE, opmode); +#endif +} + void mgag200_init_registers(struct mga_device *mdev) { u8 crtc11, misc; @@ -496,6 +520,7 @@ void mgag200_primary_plane_helper_atomic_update(struct drm_plane *plane, struct drm_atomic_helper_damage_iter iter; struct drm_rect damage; + mgag200_set_datasiz(mdev, fb->format->format); drm_atomic_helper_damage_iter_init(&iter, old_plane_state, plane_state); drm_atomic_for_each_plane_damage(&iter, &damage) { mgag200_handle_damage(mdev, shadow_plane_state->data, fb, &damage); From 7b2e6ca716816dfe394e53fdde123a036637f599 Mon Sep 17 00:00:00 2001 From: Karol Wachowski Date: Fri, 12 Dec 2025 14:41:33 +0100 Subject: [PATCH 1737/2333] drm: Fix object leak in DRM_IOCTL_GEM_CHANGE_HANDLE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 630efee9493cf64ff7b9a1652978807fef385fdd upstream. Add missing drm_gem_object_put() call when drm_gem_object_lookup() successfully returns an object. This fixes a GEM object reference leak that can prevent driver modules from unloading when using prime buffers. Fixes: 53096728b891 ("drm: Add DRM prime interface to reassign GEM handle") Cc: # v6.18+ Signed-off-by: Karol Wachowski Reviewed-by: Christian König Reviewed-by: Maciej Falkowski Signed-off-by: Christian König Link: https://lore.kernel.org/r/20251212134133.475218-1-karol.wachowski@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/drm_gem.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c index f884d155a832a..3b9df655e8377 100644 --- a/drivers/gpu/drm/drm_gem.c +++ b/drivers/gpu/drm/drm_gem.c @@ -979,8 +979,10 @@ int drm_gem_change_handle_ioctl(struct drm_device *dev, void *data, if (!obj) return -ENOENT; - if (args->handle == args->new_handle) - return 0; + if (args->handle == args->new_handle) { + ret = 0; + goto out; + } mutex_lock(&file_priv->prime.lock); @@ -1012,6 +1014,8 @@ int drm_gem_change_handle_ioctl(struct drm_device *dev, void *data, out_unlock: mutex_unlock(&file_priv->prime.lock); +out: + drm_gem_object_put(obj); return ret; } From a965d4869eefe50767966f1973cc5bb06e2eedf0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Hellstr=C3=B6m?= Date: Tue, 9 Dec 2025 21:49:20 +0100 Subject: [PATCH 1738/2333] drm/xe/bo: Don't include the CCS metadata in the dma-buf sg-table MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 449bcd5d45eb4ce26740f11f8601082fe734bed2 upstream. Some Xe bos are allocated with extra backing-store for the CCS metadata. It's never been the intention to share the CCS metadata when exporting such bos as dma-buf. Don't include it in the dma-buf sg-table. Fixes: dd08ebf6c352 ("drm/xe: Introduce a new DRM driver for Intel GPUs") Cc: Rodrigo Vivi Cc: Matthew Brost Cc: Maarten Lankhorst Cc: # v6.8+ Signed-off-by: Thomas Hellström Reviewed-by: Matthew Brost Reviewed-by: Karol Wachowski Link: https://patch.msgid.link/20251209204920.224374-1-thomas.hellstrom@linux.intel.com (cherry picked from commit a4ebfb9d95d78a12512b435a698ee6886d712571) Signed-off-by: Thomas Hellström Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/xe/xe_dma_buf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/xe/xe_dma_buf.c b/drivers/gpu/drm/xe/xe_dma_buf.c index a7d67725c3ee1..2650c5abb3654 100644 --- a/drivers/gpu/drm/xe/xe_dma_buf.c +++ b/drivers/gpu/drm/xe/xe_dma_buf.c @@ -113,7 +113,7 @@ static struct sg_table *xe_dma_buf_map(struct dma_buf_attachment *attach, case XE_PL_TT: sgt = drm_prime_pages_to_sg(obj->dev, bo->ttm.ttm->pages, - bo->ttm.ttm->num_pages); + obj->size >> PAGE_SHIFT); if (IS_ERR(sgt)) return sgt; From f19cb78876f90d424ca14949b185a6668b05aecd Mon Sep 17 00:00:00 2001 From: Ashutosh Dixit Date: Thu, 11 Dec 2025 22:18:49 -0800 Subject: [PATCH 1739/2333] drm/xe/oa: Disallow 0 OA property values MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 3595114bc31d1eb5e1996164c901485c1ffac6f7 upstream. An OA property value of 0 is invalid and will cause a NPD. Reported-by: Peter Senna Tschudin Closes: https://gitlab.freedesktop.org/drm/xe/kernel/-/issues/6452 Fixes: cc4e6994d5a2 ("drm/xe/oa: Move functions up so they can be reused for config ioctl") Cc: stable@vger.kernel.org Signed-off-by: Ashutosh Dixit Reviewed-by: Harish Chegondi Link: https://patch.msgid.link/20251212061850.1565459-3-ashutosh.dixit@intel.com (cherry picked from commit 7a100e6ddcc47c1f6ba7a19402de86ce24790621) Signed-off-by: Thomas Hellström Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/xe/xe_oa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/xe/xe_oa.c b/drivers/gpu/drm/xe/xe_oa.c index 1cb7e4791c6db..7fbce93f07193 100644 --- a/drivers/gpu/drm/xe/xe_oa.c +++ b/drivers/gpu/drm/xe/xe_oa.c @@ -1346,7 +1346,7 @@ static int xe_oa_user_ext_set_property(struct xe_oa *oa, enum xe_oa_user_extn_fr ARRAY_SIZE(xe_oa_set_property_funcs_config)); if (XE_IOCTL_DBG(oa->xe, ext.property >= ARRAY_SIZE(xe_oa_set_property_funcs_open)) || - XE_IOCTL_DBG(oa->xe, ext.pad)) + XE_IOCTL_DBG(oa->xe, !ext.property) || XE_IOCTL_DBG(oa->xe, ext.pad)) return -EINVAL; idx = array_index_nospec(ext.property, ARRAY_SIZE(xe_oa_set_property_funcs_open)); From 3570a24eb05e9af3a8a07335c8449ebb0dee1eea Mon Sep 17 00:00:00 2001 From: Ashutosh Dixit Date: Thu, 11 Dec 2025 22:18:50 -0800 Subject: [PATCH 1740/2333] drm/xe/eustall: Disallow 0 EU stall property values MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 3767ca4166ad42fa9e34269efeaf9f15995cd92d upstream. An EU stall property value of 0 is invalid and will cause a NPD. Reported-by: Peter Senna Tschudin Closes: https://gitlab.freedesktop.org/drm/xe/kernel/-/issues/6453 Fixes: 1537ec85ebd7 ("drm/xe/uapi: Introduce API for EU stall sampling") Cc: stable@vger.kernel.org Signed-off-by: Ashutosh Dixit Reviewed-by: Harish Chegondi Link: https://patch.msgid.link/20251212061850.1565459-4-ashutosh.dixit@intel.com (cherry picked from commit 5bf763e908bf795da4ad538d21c1ec41f8021f76) Signed-off-by: Thomas Hellström Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/xe/xe_eu_stall.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/xe/xe_eu_stall.c b/drivers/gpu/drm/xe/xe_eu_stall.c index f5cfdf29fde34..33a3764e3e71b 100644 --- a/drivers/gpu/drm/xe/xe_eu_stall.c +++ b/drivers/gpu/drm/xe/xe_eu_stall.c @@ -290,7 +290,7 @@ static int xe_eu_stall_user_ext_set_property(struct xe_device *xe, u64 extension return -EFAULT; if (XE_IOCTL_DBG(xe, ext.property >= ARRAY_SIZE(xe_set_eu_stall_property_funcs)) || - XE_IOCTL_DBG(xe, ext.pad)) + XE_IOCTL_DBG(xe, !ext.property) || XE_IOCTL_DBG(xe, ext.pad)) return -EINVAL; idx = array_index_nospec(ext.property, ARRAY_SIZE(xe_set_eu_stall_property_funcs)); From a7229c1ebeed5768c5263766d0424c480a5e0966 Mon Sep 17 00:00:00 2001 From: Matthew Brost Date: Fri, 12 Dec 2025 10:28:41 -0800 Subject: [PATCH 1741/2333] drm/xe: Adjust long-running workload timeslices to reasonable values MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 6f0f404bd289d79a260b634c5b3f4d330b13472c upstream. A 10ms timeslice for long-running workloads is far too long and causes significant jitter in benchmarks when the system is shared. Adjust the value to 5ms for preempt-fencing VMs, as the resume step there is quite costly as memory is moved around, and set it to zero for pagefault VMs, since switching back to pagefault mode after dma-fence mode is relatively fast. Also change min_run_period_ms to 'unsiged int' type rather than 's64' as only positive values make sense. Fixes: dd08ebf6c352 ("drm/xe: Introduce a new DRM driver for Intel GPUs") Cc: stable@vger.kernel.org Signed-off-by: Matthew Brost Reviewed-by: Thomas Hellström Link: https://patch.msgid.link/20251212182847.1683222-2-matthew.brost@intel.com (cherry picked from commit 33a5abd9a68394aa67f9618b20eee65ee8702ff4) Signed-off-by: Thomas Hellström Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/xe/xe_vm.c | 5 ++++- drivers/gpu/drm/xe/xe_vm_types.h | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_vm.c b/drivers/gpu/drm/xe/xe_vm.c index f0f699baa9f6e..747aa8cff60d4 100644 --- a/drivers/gpu/drm/xe/xe_vm.c +++ b/drivers/gpu/drm/xe/xe_vm.c @@ -1481,7 +1481,10 @@ struct xe_vm *xe_vm_create(struct xe_device *xe, u32 flags, struct xe_file *xef) INIT_WORK(&vm->destroy_work, vm_destroy_work_func); INIT_LIST_HEAD(&vm->preempt.exec_queues); - vm->preempt.min_run_period_ms = 10; /* FIXME: Wire up to uAPI */ + if (flags & XE_VM_FLAG_FAULT_MODE) + vm->preempt.min_run_period_ms = 0; + else + vm->preempt.min_run_period_ms = 5; for_each_tile(tile, xe, id) xe_range_fence_tree_init(&vm->rftree[id]); diff --git a/drivers/gpu/drm/xe/xe_vm_types.h b/drivers/gpu/drm/xe/xe_vm_types.h index d6e2a0fdd4b35..fd5b5919c4020 100644 --- a/drivers/gpu/drm/xe/xe_vm_types.h +++ b/drivers/gpu/drm/xe/xe_vm_types.h @@ -268,7 +268,7 @@ struct xe_vm { * @min_run_period_ms: The minimum run period before preempting * an engine again */ - s64 min_run_period_ms; + unsigned int min_run_period_ms; /** @exec_queues: list of exec queues attached to this VM */ struct list_head exec_queues; /** @num_exec_queues: number exec queues attached to this VM */ From e85d0e02121db79de94777dde20ee02be3415690 Mon Sep 17 00:00:00 2001 From: Matthew Brost Date: Fri, 12 Dec 2025 10:28:42 -0800 Subject: [PATCH 1742/2333] drm/xe: Use usleep_range for accurate long-running workload timeslicing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 80f9c601d9c4d26f00356c0a9c461650e7089273 upstream. msleep is not very accurate in terms of how long it actually sleeps, whereas usleep_range is precise. Replace the timeslice sleep for long-running workloads with the more accurate usleep_range to avoid jitter if the sleep period is less than 20ms. Fixes: dd08ebf6c352 ("drm/xe: Introduce a new DRM driver for Intel GPUs") Cc: stable@vger.kernel.org Signed-off-by: Matthew Brost Reviewed-by: Thomas Hellström Link: https://patch.msgid.link/20251212182847.1683222-3-matthew.brost@intel.com (cherry picked from commit ca415c4d4c17ad676a2c8981e1fcc432221dce79) Signed-off-by: Thomas Hellström Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/xe/xe_guc_submit.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/xe/xe_guc_submit.c b/drivers/gpu/drm/xe/xe_guc_submit.c index 94ed8159496f1..474789bf6506f 100644 --- a/drivers/gpu/drm/xe/xe_guc_submit.c +++ b/drivers/gpu/drm/xe/xe_guc_submit.c @@ -670,6 +670,24 @@ static u32 wq_space_until_wrap(struct xe_exec_queue *q) return (WQ_SIZE - q->guc->wqi_tail); } +static inline void relaxed_ms_sleep(unsigned int delay_ms) +{ + unsigned long min_us, max_us; + + if (!delay_ms) + return; + + if (delay_ms > 20) { + msleep(delay_ms); + return; + } + + min_us = mul_u32_u32(delay_ms, 1000); + max_us = min_us + 500; + + usleep_range(min_us, max_us); +} + static int wq_wait_for_space(struct xe_exec_queue *q, u32 wqi_size) { struct xe_guc *guc = exec_queue_to_guc(q); @@ -1559,7 +1577,7 @@ static void __guc_exec_queue_process_msg_suspend(struct xe_sched_msg *msg) since_resume_ms; if (wait_ms > 0 && q->guc->resume_time) - msleep(wait_ms); + relaxed_ms_sleep(wait_ms); set_exec_queue_suspended(q); disable_scheduling(q, false); From 8d9df6d3fa49c18547896d16a5414a09c0c386b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Hellstr=C3=B6m?= Date: Wed, 17 Dec 2025 10:34:41 +0100 Subject: [PATCH 1743/2333] drm/xe: Drop preempt-fences when destroying imported dma-bufs. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit fe3ccd24138fd391ae8e32289d492c85f67770fc upstream. When imported dma-bufs are destroyed, TTM is not fully individualizing the dma-resv, but it *is* copying the fences that need to be waited for before declaring idle. So in the case where the bo->resv != bo->_resv we can still drop the preempt-fences, but make sure we do that on bo->_resv which contains the fence-pointer copy. In the case where the copying fails, bo->_resv will typically not contain any fences pointers at all, so there will be nothing to drop. In that case, TTM would have ensured all fences that would have been copied are signaled, including any remaining preempt fences. Fixes: dd08ebf6c352 ("drm/xe: Introduce a new DRM driver for Intel GPUs") Fixes: fa0af721bd1f ("drm/ttm: test private resv obj on release/destroy") Cc: Matthew Brost Cc: # v6.16+ Signed-off-by: Thomas Hellström Tested-by: Matthew Brost Reviewed-by: Matthew Brost Link: https://patch.msgid.link/20251217093441.5073-1-thomas.hellstrom@linux.intel.com (cherry picked from commit 425fe550fb513b567bd6d01f397d274092a9c274) Signed-off-by: Thomas Hellström Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/xe/xe_bo.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_bo.c b/drivers/gpu/drm/xe/xe_bo.c index 4410e28dee54b..d5b8332a04ecf 100644 --- a/drivers/gpu/drm/xe/xe_bo.c +++ b/drivers/gpu/drm/xe/xe_bo.c @@ -1480,7 +1480,7 @@ static bool xe_ttm_bo_lock_in_destructor(struct ttm_buffer_object *ttm_bo) * always succeed here, as long as we hold the lru lock. */ spin_lock(&ttm_bo->bdev->lru_lock); - locked = dma_resv_trylock(ttm_bo->base.resv); + locked = dma_resv_trylock(&ttm_bo->base._resv); spin_unlock(&ttm_bo->bdev->lru_lock); xe_assert(xe, locked); @@ -1500,13 +1500,6 @@ static void xe_ttm_bo_release_notify(struct ttm_buffer_object *ttm_bo) bo = ttm_to_xe_bo(ttm_bo); xe_assert(xe_bo_device(bo), !(bo->created && kref_read(&ttm_bo->base.refcount))); - /* - * Corner case where TTM fails to allocate memory and this BOs resv - * still points the VMs resv - */ - if (ttm_bo->base.resv != &ttm_bo->base._resv) - return; - if (!xe_ttm_bo_lock_in_destructor(ttm_bo)) return; @@ -1516,14 +1509,14 @@ static void xe_ttm_bo_release_notify(struct ttm_buffer_object *ttm_bo) * TODO: Don't do this for external bos once we scrub them after * unbind. */ - dma_resv_for_each_fence(&cursor, ttm_bo->base.resv, + dma_resv_for_each_fence(&cursor, &ttm_bo->base._resv, DMA_RESV_USAGE_BOOKKEEP, fence) { if (xe_fence_is_xe_preempt(fence) && !dma_fence_is_signaled(fence)) { if (!replacement) replacement = dma_fence_get_stub(); - dma_resv_replace_fences(ttm_bo->base.resv, + dma_resv_replace_fences(&ttm_bo->base._resv, fence->context, replacement, DMA_RESV_USAGE_BOOKKEEP); @@ -1531,7 +1524,7 @@ static void xe_ttm_bo_release_notify(struct ttm_buffer_object *ttm_bo) } dma_fence_put(replacement); - dma_resv_unlock(ttm_bo->base.resv); + dma_resv_unlock(&ttm_bo->base._resv); } static void xe_ttm_bo_delete_mem_notify(struct ttm_buffer_object *ttm_bo) From 35ea3282136a630a3fd92b76f5a3a02651145ef1 Mon Sep 17 00:00:00 2001 From: Nikolay Kuratov Date: Thu, 11 Dec 2025 12:36:30 +0300 Subject: [PATCH 1744/2333] drm/msm/dpu: Add missing NULL pointer check for pingpong interface commit 88733a0b64872357e5ecd82b7488121503cb9cc6 upstream. It is checked almost always in dpu_encoder_phys_wb_setup_ctl(), but in a single place the check is missing. Also use convenient locals instead of phys_enc->* where available. Cc: stable@vger.kernel.org Fixes: d7d0e73f7de33 ("drm/msm/dpu: introduce the dpu_encoder_phys_* for writeback") Signed-off-by: Nikolay Kuratov Reviewed-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/693860/ Link: https://lore.kernel.org/r/20251211093630.171014-1-kniv@yandex-team.ru Signed-off-by: Dmitry Baryshkov Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) 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 46f348972a975..6d28f2281c765 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 @@ -247,14 +247,12 @@ static void dpu_encoder_phys_wb_setup_ctl(struct dpu_encoder_phys *phys_enc) if (hw_cdm) intf_cfg.cdm = hw_cdm->idx; - if (phys_enc->hw_pp->merge_3d && phys_enc->hw_pp->merge_3d->ops.setup_3d_mode) - phys_enc->hw_pp->merge_3d->ops.setup_3d_mode(phys_enc->hw_pp->merge_3d, - mode_3d); + if (hw_pp && hw_pp->merge_3d && hw_pp->merge_3d->ops.setup_3d_mode) + hw_pp->merge_3d->ops.setup_3d_mode(hw_pp->merge_3d, mode_3d); /* setup which pp blk will connect to this wb */ - if (hw_pp && phys_enc->hw_wb->ops.bind_pingpong_blk) - phys_enc->hw_wb->ops.bind_pingpong_blk(phys_enc->hw_wb, - phys_enc->hw_pp->idx); + if (hw_pp && hw_wb->ops.bind_pingpong_blk) + hw_wb->ops.bind_pingpong_blk(hw_wb, hw_pp->idx); phys_enc->hw_ctl->ops.setup_intf_cfg(phys_enc->hw_ctl, &intf_cfg); } else if (phys_enc->hw_ctl && phys_enc->hw_ctl->ops.setup_intf_cfg) { From 3165fcd7a1cbdf1d7bf2fed74ef13cbd2367d782 Mon Sep 17 00:00:00 2001 From: Anna Maniscalco Date: Thu, 27 Nov 2025 19:22:35 +0100 Subject: [PATCH 1745/2333] drm/msm: add PERFCTR_CNTL to ifpc_reglist commit 6c6915bfea212d32844b2b7f22bc1aa3669eabc4 upstream. Previously this register would become 0 after IFPC took place which broke all usages of counters. Fixes: a6a0157cc68e ("drm/msm/a6xx: Enable IFPC on Adreno X1-85") Cc: stable@vger.kernel.org Signed-off-by: Anna Maniscalco Reviewed-by: Akhil P Oommen Reviewed-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/690960/ Message-ID: <20251127-ifpc_counters-v3-1-fac0a126bc88@gmail.com> Signed-off-by: Rob Clark Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/msm/adreno/a6xx_catalog.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/msm/adreno/a6xx_catalog.c b/drivers/gpu/drm/msm/adreno/a6xx_catalog.c index 44df6410bce17..2adbc198ecf26 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_catalog.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_catalog.c @@ -1360,6 +1360,7 @@ static const u32 a750_ifpc_reglist_regs[] = { REG_A6XX_TPL1_BICUBIC_WEIGHTS_TABLE(2), REG_A6XX_TPL1_BICUBIC_WEIGHTS_TABLE(3), REG_A6XX_TPL1_BICUBIC_WEIGHTS_TABLE(4), + REG_A6XX_RBBM_PERFCTR_CNTL, REG_A6XX_TPL1_NC_MODE_CNTL, REG_A6XX_SP_NC_MODE_CNTL, REG_A6XX_CP_DBG_ECO_CNTL, From 63f23aa2fbb823c8b15a29269fde220d227ce5b3 Mon Sep 17 00:00:00 2001 From: Krzysztof Niemiec Date: Tue, 16 Dec 2025 19:09:01 +0100 Subject: [PATCH 1746/2333] drm/i915/gem: Zero-initialize the eb.vma array in i915_gem_do_execbuffer commit 4fe2bd195435e71c117983d87f278112c5ab364c upstream. Initialize the eb.vma array with values of 0 when the eb structure is first set up. In particular, this sets the eb->vma[i].vma pointers to NULL, simplifying cleanup and getting rid of the bug described below. During the execution of eb_lookup_vmas(), the eb->vma array is successively filled up with struct eb_vma objects. This process includes calling eb_add_vma(), which might fail; however, even in the event of failure, eb->vma[i].vma is set for the currently processed buffer. If eb_add_vma() fails, eb_lookup_vmas() returns with an error, which prompts a call to eb_release_vmas() to clean up the mess. Since eb_lookup_vmas() might fail during processing any (possibly not first) buffer, eb_release_vmas() checks whether a buffer's vma is NULL to know at what point did the lookup function fail. In eb_lookup_vmas(), eb->vma[i].vma is set to NULL if either the helper function eb_lookup_vma() or eb_validate_vma() fails. eb->vma[i+1].vma is set to NULL in case i915_gem_object_userptr_submit_init() fails; the current one needs to be cleaned up by eb_release_vmas() at this point, so the next one is set. If eb_add_vma() fails, neither the current nor the next vma is set to NULL, which is a source of a NULL deref bug described in the issue linked in the Closes tag. When entering eb_lookup_vmas(), the vma pointers are set to the slab poison value, instead of NULL. This doesn't matter for the actual lookup, since it gets overwritten anyway, however the eb_release_vmas() function only recognizes NULL as the stopping value, hence the pointers are being set to NULL as they go in case of intermediate failure. This patch changes the approach to filling them all with NULL at the start instead, rather than handling that manually during failure. Reported-by: Gangmin Kim Closes: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/15062 Fixes: 544460c33821 ("drm/i915: Multi-BB execbuf") Cc: stable@vger.kernel.org # 5.16.x Signed-off-by: Krzysztof Niemiec Reviewed-by: Janusz Krzysztofik Reviewed-by: Krzysztof Karas Reviewed-by: Andi Shyti Signed-off-by: Andi Shyti Link: https://lore.kernel.org/r/20251216180900.54294-2-krzysztof.niemiec@intel.com (cherry picked from commit 08889b706d4f0b8d2352b7ca29c2d8df4d0787cd) Signed-off-by: Jani Nikula Signed-off-by: Greg Kroah-Hartman --- .../gpu/drm/i915/gem/i915_gem_execbuffer.c | 37 +++++++++---------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c index 39c7c32e1e74e..bcae382acdf56 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c @@ -950,13 +950,13 @@ static int eb_lookup_vmas(struct i915_execbuffer *eb) vma = eb_lookup_vma(eb, eb->exec[i].handle); if (IS_ERR(vma)) { err = PTR_ERR(vma); - goto err; + return err; } err = eb_validate_vma(eb, &eb->exec[i], vma); if (unlikely(err)) { i915_vma_put(vma); - goto err; + return err; } err = eb_add_vma(eb, ¤t_batch, i, vma); @@ -965,19 +965,8 @@ static int eb_lookup_vmas(struct i915_execbuffer *eb) if (i915_gem_object_is_userptr(vma->obj)) { err = i915_gem_object_userptr_submit_init(vma->obj); - if (err) { - if (i + 1 < eb->buffer_count) { - /* - * Execbuffer code expects last vma entry to be NULL, - * since we already initialized this entry, - * set the next value to NULL or we mess up - * cleanup handling. - */ - eb->vma[i + 1].vma = NULL; - } - + if (err) return err; - } eb->vma[i].flags |= __EXEC_OBJECT_USERPTR_INIT; eb->args->flags |= __EXEC_USERPTR_USED; @@ -985,10 +974,6 @@ static int eb_lookup_vmas(struct i915_execbuffer *eb) } return 0; - -err: - eb->vma[i].vma = NULL; - return err; } static int eb_lock_vmas(struct i915_execbuffer *eb) @@ -3374,7 +3359,8 @@ i915_gem_do_execbuffer(struct drm_device *dev, eb.exec = exec; eb.vma = (struct eb_vma *)(exec + args->buffer_count + 1); - eb.vma[0].vma = NULL; + memset(eb.vma, 0, (args->buffer_count + 1) * sizeof(struct eb_vma)); + eb.batch_pool = NULL; eb.invalid_flags = __EXEC_OBJECT_UNKNOWN_FLAGS; @@ -3583,7 +3569,18 @@ i915_gem_execbuffer2_ioctl(struct drm_device *dev, void *data, if (err) return err; - /* Allocate extra slots for use by the command parser */ + /* + * Allocate extra slots for use by the command parser. + * + * Note that this allocation handles two different arrays (the + * exec2_list array, and the eventual eb.vma array introduced in + * i915_gem_do_execbuffer()), that reside in virtually contiguous + * memory. Also note that the allocation intentionally doesn't fill the + * area with zeros, because the exec2_list part doesn't need to be, as + * it's immediately overwritten by user data a few lines below. + * However, the eb.vma part is explicitly zeroed later in + * i915_gem_do_execbuffer(). + */ exec2_list = kvmalloc_array(count + 2, eb_element_size(), __GFP_NOWARN | GFP_KERNEL); if (exec2_list == NULL) { From 548f139d3c17209a50522e41258b206c31f4ff7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Hellstr=C3=B6m?= Date: Fri, 19 Dec 2025 12:32:57 +0100 Subject: [PATCH 1747/2333] drm/xe/svm: Fix a debug printout MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit d2d7f5636f0d752a1e0e7eadbbc1839c29177bba upstream. Avoid spamming the log with drm_info(). Use drm_dbg() instead. Fixes: cc795e041034 ("drm/xe/svm: Make xe_svm_range_needs_migrate_to_vram() public") Cc: Matthew Brost Cc: Himal Prasad Ghimiray Cc: # v6.17+ Signed-off-by: Thomas Hellström Reviewed-by: Himal Prasad Ghimiray Link: https://patch.msgid.link/20251219113320.183860-2-thomas.hellstrom@linux.intel.com (cherry picked from commit 72aee5f70ba47b939345a0d3414b51b0639c5b88) Signed-off-by: Thomas Hellström Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/xe/xe_svm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/xe/xe_svm.c b/drivers/gpu/drm/xe/xe_svm.c index 129e7818565c8..d0d9415a7b03c 100644 --- a/drivers/gpu/drm/xe/xe_svm.c +++ b/drivers/gpu/drm/xe/xe_svm.c @@ -942,7 +942,7 @@ bool xe_svm_range_needs_migrate_to_vram(struct xe_svm_range *range, struct xe_vm xe_assert(vm->xe, IS_DGFX(vm->xe)); if (xe_svm_range_in_vram(range)) { - drm_info(&vm->xe->drm, "Range is already in VRAM\n"); + drm_dbg(&vm->xe->drm, "Range is already in VRAM\n"); return false; } From c79ee71f45987a753789c3fede6a34499080584e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Hellstr=C3=B6m?= Date: Fri, 19 Dec 2025 12:32:59 +0100 Subject: [PATCH 1748/2333] drm/pagemap, drm/xe: Ensure that the devmem allocation is idle before use MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 754c23238438600e9236719f7e67aff2c4d02093 upstream. In situations where no system memory is migrated to devmem, and in upcoming patches where another GPU is performing the migration to the newly allocated devmem buffer, there is nothing to ensure any ongoing clear to the devmem allocation or async eviction from the devmem allocation is complete. Address that by passing a struct dma_fence down to the copy functions, and ensure it is waited for before migration is marked complete. v3: - New patch. v4: - Update the logic used for determining when to wait for the pre_migrate_fence. - Update the logic used for determining when to warn for the pre_migrate_fence since the scheduler fences apparently can signal out-of-order. v5: - Fix a UAF (CI) - Remove references to source P2P migration (Himal) - Put the pre_migrate_fence after migration. v6: - Pipeline the pre_migrate_fence dependency (Matt Brost) Fixes: c5b3eb5a906c ("drm/xe: Add GPUSVM device memory copy vfunc functions") Cc: Matthew Brost Cc: # v6.15+ Signed-off-by: Thomas Hellström Reviewed-by: Matthew Brost Acked-by: Maarten Lankhorst # For merging through drm-xe. Link: https://patch.msgid.link/20251219113320.183860-4-thomas.hellstrom@linux.intel.com (cherry picked from commit 16b5ad31952476fb925c401897fc171cd37f536b) Signed-off-by: Thomas Hellström Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/drm_pagemap.c | 17 +++++++++--- drivers/gpu/drm/xe/xe_migrate.c | 25 +++++++++++++---- drivers/gpu/drm/xe/xe_migrate.h | 6 ++-- drivers/gpu/drm/xe/xe_svm.c | 49 +++++++++++++++++++++++++-------- include/drm/drm_pagemap.h | 17 ++++++++++-- 5 files changed, 88 insertions(+), 26 deletions(-) diff --git a/drivers/gpu/drm/drm_pagemap.c b/drivers/gpu/drm/drm_pagemap.c index 22c44807e3fe9..445cf0e6589fa 100644 --- a/drivers/gpu/drm/drm_pagemap.c +++ b/drivers/gpu/drm/drm_pagemap.c @@ -3,6 +3,7 @@ * Copyright © 2024-2025 Intel Corporation */ +#include #include #include #include @@ -408,10 +409,14 @@ int drm_pagemap_migrate_to_devmem(struct drm_pagemap_devmem *devmem_allocation, drm_pagemap_get_devmem_page(page, zdd); } - err = ops->copy_to_devmem(pages, pagemap_addr, npages); + err = ops->copy_to_devmem(pages, pagemap_addr, npages, + devmem_allocation->pre_migrate_fence); if (err) goto err_finalize; + dma_fence_put(devmem_allocation->pre_migrate_fence); + devmem_allocation->pre_migrate_fence = NULL; + /* Upon success bind devmem allocation to range and zdd */ devmem_allocation->timeslice_expiration = get_jiffies_64() + msecs_to_jiffies(timeslice_ms); @@ -596,7 +601,7 @@ int drm_pagemap_evict_to_ram(struct drm_pagemap_devmem *devmem_allocation) for (i = 0; i < npages; ++i) pages[i] = migrate_pfn_to_page(src[i]); - err = ops->copy_to_ram(pages, pagemap_addr, npages); + err = ops->copy_to_ram(pages, pagemap_addr, npages, NULL); if (err) goto err_finalize; @@ -732,7 +737,7 @@ static int __drm_pagemap_migrate_to_ram(struct vm_area_struct *vas, for (i = 0; i < npages; ++i) pages[i] = migrate_pfn_to_page(migrate.src[i]); - err = ops->copy_to_ram(pages, pagemap_addr, npages); + err = ops->copy_to_ram(pages, pagemap_addr, npages, NULL); if (err) goto err_finalize; @@ -813,11 +818,14 @@ EXPORT_SYMBOL_GPL(drm_pagemap_pagemap_ops_get); * @ops: Pointer to the operations structure for GPU SVM device memory * @dpagemap: The struct drm_pagemap we're allocating from. * @size: Size of device memory allocation + * @pre_migrate_fence: Fence to wait for or pipeline behind before migration starts. + * (May be NULL). */ void drm_pagemap_devmem_init(struct drm_pagemap_devmem *devmem_allocation, struct device *dev, struct mm_struct *mm, const struct drm_pagemap_devmem_ops *ops, - struct drm_pagemap *dpagemap, size_t size) + struct drm_pagemap *dpagemap, size_t size, + struct dma_fence *pre_migrate_fence) { init_completion(&devmem_allocation->detached); devmem_allocation->dev = dev; @@ -825,6 +833,7 @@ void drm_pagemap_devmem_init(struct drm_pagemap_devmem *devmem_allocation, devmem_allocation->ops = ops; devmem_allocation->dpagemap = dpagemap; devmem_allocation->size = size; + devmem_allocation->pre_migrate_fence = pre_migrate_fence; } EXPORT_SYMBOL_GPL(drm_pagemap_devmem_init); diff --git a/drivers/gpu/drm/xe/xe_migrate.c b/drivers/gpu/drm/xe/xe_migrate.c index a36ce7dce8cc0..3acdcbf41887f 100644 --- a/drivers/gpu/drm/xe/xe_migrate.c +++ b/drivers/gpu/drm/xe/xe_migrate.c @@ -1813,6 +1813,7 @@ static struct dma_fence *xe_migrate_vram(struct xe_migrate *m, unsigned long sram_offset, struct drm_pagemap_addr *sram_addr, u64 vram_addr, + struct dma_fence *deps, const enum xe_migrate_copy_dir dir) { struct xe_gt *gt = m->tile->primary_gt; @@ -1890,6 +1891,14 @@ static struct dma_fence *xe_migrate_vram(struct xe_migrate *m, xe_sched_job_add_migrate_flush(job, MI_INVALIDATE_TLB); + if (deps && !dma_fence_is_signaled(deps)) { + dma_fence_get(deps); + err = drm_sched_job_add_dependency(&job->drm, deps); + if (err) + dma_fence_wait(deps, false); + err = 0; + } + mutex_lock(&m->job_mutex); xe_sched_job_arm(job); fence = dma_fence_get(&job->drm.s_fence->finished); @@ -1915,6 +1924,8 @@ static struct dma_fence *xe_migrate_vram(struct xe_migrate *m, * @npages: Number of pages to migrate. * @src_addr: Array of DMA information (source of migrate) * @dst_addr: Device physical address of VRAM (destination of migrate) + * @deps: struct dma_fence representing the dependencies that need + * to be signaled before migration. * * Copy from an array dma addresses to a VRAM device physical address * @@ -1924,10 +1935,11 @@ static struct dma_fence *xe_migrate_vram(struct xe_migrate *m, struct dma_fence *xe_migrate_to_vram(struct xe_migrate *m, unsigned long npages, struct drm_pagemap_addr *src_addr, - u64 dst_addr) + u64 dst_addr, + struct dma_fence *deps) { return xe_migrate_vram(m, npages * PAGE_SIZE, 0, src_addr, dst_addr, - XE_MIGRATE_COPY_TO_VRAM); + deps, XE_MIGRATE_COPY_TO_VRAM); } /** @@ -1936,6 +1948,8 @@ struct dma_fence *xe_migrate_to_vram(struct xe_migrate *m, * @npages: Number of pages to migrate. * @src_addr: Device physical address of VRAM (source of migrate) * @dst_addr: Array of DMA information (destination of migrate) + * @deps: struct dma_fence representing the dependencies that need + * to be signaled before migration. * * Copy from a VRAM device physical address to an array dma addresses * @@ -1945,10 +1959,11 @@ struct dma_fence *xe_migrate_to_vram(struct xe_migrate *m, struct dma_fence *xe_migrate_from_vram(struct xe_migrate *m, unsigned long npages, u64 src_addr, - struct drm_pagemap_addr *dst_addr) + struct drm_pagemap_addr *dst_addr, + struct dma_fence *deps) { return xe_migrate_vram(m, npages * PAGE_SIZE, 0, dst_addr, src_addr, - XE_MIGRATE_COPY_TO_SRAM); + deps, XE_MIGRATE_COPY_TO_SRAM); } static void xe_migrate_dma_unmap(struct xe_device *xe, @@ -2121,7 +2136,7 @@ int xe_migrate_access_memory(struct xe_migrate *m, struct xe_bo *bo, __fence = xe_migrate_vram(m, current_bytes, (unsigned long)buf & ~PAGE_MASK, &pagemap_addr[current_page], - vram_addr, write ? + vram_addr, NULL, write ? XE_MIGRATE_COPY_TO_VRAM : XE_MIGRATE_COPY_TO_SRAM); if (IS_ERR(__fence)) { diff --git a/drivers/gpu/drm/xe/xe_migrate.h b/drivers/gpu/drm/xe/xe_migrate.h index 4fad324b62535..bc55f650204b8 100644 --- a/drivers/gpu/drm/xe/xe_migrate.h +++ b/drivers/gpu/drm/xe/xe_migrate.h @@ -111,12 +111,14 @@ int xe_migrate_init(struct xe_migrate *m); struct dma_fence *xe_migrate_to_vram(struct xe_migrate *m, unsigned long npages, struct drm_pagemap_addr *src_addr, - u64 dst_addr); + u64 dst_addr, + struct dma_fence *deps); struct dma_fence *xe_migrate_from_vram(struct xe_migrate *m, unsigned long npages, u64 src_addr, - struct drm_pagemap_addr *dst_addr); + struct drm_pagemap_addr *dst_addr, + struct dma_fence *deps); struct dma_fence *xe_migrate_copy(struct xe_migrate *m, struct xe_bo *src_bo, diff --git a/drivers/gpu/drm/xe/xe_svm.c b/drivers/gpu/drm/xe/xe_svm.c index d0d9415a7b03c..65452c20609ed 100644 --- a/drivers/gpu/drm/xe/xe_svm.c +++ b/drivers/gpu/drm/xe/xe_svm.c @@ -477,7 +477,8 @@ static void xe_svm_copy_us_stats_incr(struct xe_gt *gt, static int xe_svm_copy(struct page **pages, struct drm_pagemap_addr *pagemap_addr, - unsigned long npages, const enum xe_svm_copy_dir dir) + unsigned long npages, const enum xe_svm_copy_dir dir, + struct dma_fence *pre_migrate_fence) { struct xe_vram_region *vr = NULL; struct xe_gt *gt = NULL; @@ -566,7 +567,8 @@ static int xe_svm_copy(struct page **pages, __fence = xe_migrate_from_vram(vr->migrate, i - pos + incr, vram_addr, - &pagemap_addr[pos]); + &pagemap_addr[pos], + pre_migrate_fence); } else { vm_dbg(&xe->drm, "COPY TO VRAM - 0x%016llx -> 0x%016llx, NPAGES=%ld", @@ -575,13 +577,14 @@ static int xe_svm_copy(struct page **pages, __fence = xe_migrate_to_vram(vr->migrate, i - pos + incr, &pagemap_addr[pos], - vram_addr); + vram_addr, + pre_migrate_fence); } if (IS_ERR(__fence)) { err = PTR_ERR(__fence); goto err_out; } - + pre_migrate_fence = NULL; dma_fence_put(fence); fence = __fence; } @@ -604,20 +607,22 @@ static int xe_svm_copy(struct page **pages, vram_addr, (u64)pagemap_addr[pos].addr, 1); __fence = xe_migrate_from_vram(vr->migrate, 1, vram_addr, - &pagemap_addr[pos]); + &pagemap_addr[pos], + pre_migrate_fence); } else { vm_dbg(&xe->drm, "COPY TO VRAM - 0x%016llx -> 0x%016llx, NPAGES=%d", (u64)pagemap_addr[pos].addr, vram_addr, 1); __fence = xe_migrate_to_vram(vr->migrate, 1, &pagemap_addr[pos], - vram_addr); + vram_addr, + pre_migrate_fence); } if (IS_ERR(__fence)) { err = PTR_ERR(__fence); goto err_out; } - + pre_migrate_fence = NULL; dma_fence_put(fence); fence = __fence; } @@ -630,6 +635,8 @@ static int xe_svm_copy(struct page **pages, dma_fence_wait(fence, false); dma_fence_put(fence); } + if (pre_migrate_fence) + dma_fence_wait(pre_migrate_fence, false); /* * XXX: We can't derive the GT here (or anywhere in this functions, but @@ -646,16 +653,20 @@ static int xe_svm_copy(struct page **pages, static int xe_svm_copy_to_devmem(struct page **pages, struct drm_pagemap_addr *pagemap_addr, - unsigned long npages) + unsigned long npages, + struct dma_fence *pre_migrate_fence) { - return xe_svm_copy(pages, pagemap_addr, npages, XE_SVM_COPY_TO_VRAM); + return xe_svm_copy(pages, pagemap_addr, npages, XE_SVM_COPY_TO_VRAM, + pre_migrate_fence); } static int xe_svm_copy_to_ram(struct page **pages, struct drm_pagemap_addr *pagemap_addr, - unsigned long npages) + unsigned long npages, + struct dma_fence *pre_migrate_fence) { - return xe_svm_copy(pages, pagemap_addr, npages, XE_SVM_COPY_TO_SRAM); + return xe_svm_copy(pages, pagemap_addr, npages, XE_SVM_COPY_TO_SRAM, + pre_migrate_fence); } static struct xe_bo *to_xe_bo(struct drm_pagemap_devmem *devmem_allocation) @@ -668,6 +679,7 @@ static void xe_svm_devmem_release(struct drm_pagemap_devmem *devmem_allocation) struct xe_bo *bo = to_xe_bo(devmem_allocation); struct xe_device *xe = xe_bo_device(bo); + dma_fence_put(devmem_allocation->pre_migrate_fence); xe_bo_put_async(bo); xe_pm_runtime_put(xe); } @@ -862,6 +874,7 @@ static int xe_drm_pagemap_populate_mm(struct drm_pagemap *dpagemap, unsigned long timeslice_ms) { struct xe_vram_region *vr = container_of(dpagemap, typeof(*vr), dpagemap); + struct dma_fence *pre_migrate_fence = NULL; struct xe_device *xe = vr->xe; struct device *dev = xe->drm.dev; struct drm_buddy_block *block; @@ -888,8 +901,20 @@ static int xe_drm_pagemap_populate_mm(struct drm_pagemap *dpagemap, break; } + /* Ensure that any clearing or async eviction will complete before migration. */ + if (!dma_resv_test_signaled(bo->ttm.base.resv, DMA_RESV_USAGE_KERNEL)) { + err = dma_resv_get_singleton(bo->ttm.base.resv, DMA_RESV_USAGE_KERNEL, + &pre_migrate_fence); + if (err) + dma_resv_wait_timeout(bo->ttm.base.resv, DMA_RESV_USAGE_KERNEL, + false, MAX_SCHEDULE_TIMEOUT); + else if (pre_migrate_fence) + dma_fence_enable_sw_signaling(pre_migrate_fence); + } + drm_pagemap_devmem_init(&bo->devmem_allocation, dev, mm, - &dpagemap_devmem_ops, dpagemap, end - start); + &dpagemap_devmem_ops, dpagemap, end - start, + pre_migrate_fence); blocks = &to_xe_ttm_vram_mgr_resource(bo->ttm.resource)->blocks; list_for_each_entry(block, blocks, link) diff --git a/include/drm/drm_pagemap.h b/include/drm/drm_pagemap.h index f6e7e234c0892..70a7991f784f9 100644 --- a/include/drm/drm_pagemap.h +++ b/include/drm/drm_pagemap.h @@ -8,6 +8,7 @@ #define NR_PAGES(order) (1U << (order)) +struct dma_fence; struct drm_pagemap; struct drm_pagemap_zdd; struct device; @@ -174,6 +175,8 @@ struct drm_pagemap_devmem_ops { * @pages: Pointer to array of device memory pages (destination) * @pagemap_addr: Pointer to array of DMA information (source) * @npages: Number of pages to copy + * @pre_migrate_fence: dma-fence to wait for before migration start. + * May be NULL. * * Copy pages to device memory. If the order of a @pagemap_addr entry * is greater than 0, the entry is populated but subsequent entries @@ -183,13 +186,16 @@ struct drm_pagemap_devmem_ops { */ int (*copy_to_devmem)(struct page **pages, struct drm_pagemap_addr *pagemap_addr, - unsigned long npages); + unsigned long npages, + struct dma_fence *pre_migrate_fence); /** * @copy_to_ram: Copy to system RAM (required for migration) * @pages: Pointer to array of device memory pages (source) * @pagemap_addr: Pointer to array of DMA information (destination) * @npages: Number of pages to copy + * @pre_migrate_fence: dma-fence to wait for before migration start. + * May be NULL. * * Copy pages to system RAM. If the order of a @pagemap_addr entry * is greater than 0, the entry is populated but subsequent entries @@ -199,7 +205,8 @@ struct drm_pagemap_devmem_ops { */ int (*copy_to_ram)(struct page **pages, struct drm_pagemap_addr *pagemap_addr, - unsigned long npages); + unsigned long npages, + struct dma_fence *pre_migrate_fence); }; /** @@ -212,6 +219,8 @@ struct drm_pagemap_devmem_ops { * @dpagemap: The struct drm_pagemap of the pages this allocation belongs to. * @size: Size of device memory allocation * @timeslice_expiration: Timeslice expiration in jiffies + * @pre_migrate_fence: Fence to wait for or pipeline behind before migration starts. + * (May be NULL). */ struct drm_pagemap_devmem { struct device *dev; @@ -221,6 +230,7 @@ struct drm_pagemap_devmem { struct drm_pagemap *dpagemap; size_t size; u64 timeslice_expiration; + struct dma_fence *pre_migrate_fence; }; int drm_pagemap_migrate_to_devmem(struct drm_pagemap_devmem *devmem_allocation, @@ -238,7 +248,8 @@ struct drm_pagemap *drm_pagemap_page_to_dpagemap(struct page *page); void drm_pagemap_devmem_init(struct drm_pagemap_devmem *devmem_allocation, struct device *dev, struct mm_struct *mm, const struct drm_pagemap_devmem_ops *ops, - struct drm_pagemap *dpagemap, size_t size); + struct drm_pagemap *dpagemap, size_t size, + struct dma_fence *pre_migrate_fence); int drm_pagemap_populate_mm(struct drm_pagemap *dpagemap, unsigned long start, unsigned long end, From 5487edb7b8ede8a6f2d034a6da6ee4a56f5b1626 Mon Sep 17 00:00:00 2001 From: Lyude Paul Date: Thu, 11 Dec 2025 14:02:54 -0500 Subject: [PATCH 1749/2333] drm/nouveau/dispnv50: Don't call drm_atomic_get_crtc_state() in prepare_fb commit 560271e10b2c86e95ea35afa9e79822e4847f07a upstream. Since we recently started warning about uses of this function after the atomic check phase completes, we've started getting warnings about this in nouveau. It appears a misplaced drm_atomic_get_crtc_state() call has been hiding in our .prepare_fb callback for a while. So, fix this by adding a new nv50_head_atom_get_new() function and use that in our .prepare_fb callback instead. Signed-off-by: Lyude Paul Reviewed-by: Dave Airlie Fixes: 1590700d94ac ("drm/nouveau/kms/nv50-: split each resource type into their own source files") Cc: # v4.18+ Link: https://patch.msgid.link/20251211190256.396742-1-lyude@redhat.com Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/nouveau/dispnv50/atom.h | 13 +++++++++++++ drivers/gpu/drm/nouveau/dispnv50/wndw.c | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/dispnv50/atom.h b/drivers/gpu/drm/nouveau/dispnv50/atom.h index 93f8f4f645784..b43c4f9bbcdf5 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/atom.h +++ b/drivers/gpu/drm/nouveau/dispnv50/atom.h @@ -152,8 +152,21 @@ static inline struct nv50_head_atom * nv50_head_atom_get(struct drm_atomic_state *state, struct drm_crtc *crtc) { struct drm_crtc_state *statec = drm_atomic_get_crtc_state(state, crtc); + if (IS_ERR(statec)) return (void *)statec; + + return nv50_head_atom(statec); +} + +static inline struct nv50_head_atom * +nv50_head_atom_get_new(struct drm_atomic_state *state, struct drm_crtc *crtc) +{ + struct drm_crtc_state *statec = drm_atomic_get_new_crtc_state(state, crtc); + + if (!statec) + return NULL; + return nv50_head_atom(statec); } diff --git a/drivers/gpu/drm/nouveau/dispnv50/wndw.c b/drivers/gpu/drm/nouveau/dispnv50/wndw.c index ef9e410babbfb..9a2c20fce0f3e 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/wndw.c +++ b/drivers/gpu/drm/nouveau/dispnv50/wndw.c @@ -583,7 +583,7 @@ nv50_wndw_prepare_fb(struct drm_plane *plane, struct drm_plane_state *state) asyw->image.offset[0] = nvbo->offset; if (wndw->func->prepare) { - asyh = nv50_head_atom_get(asyw->state.state, asyw->state.crtc); + asyh = nv50_head_atom_get_new(asyw->state.state, asyw->state.crtc); if (IS_ERR(asyh)) return PTR_ERR(asyh); From e8469ef3d480130a47008f523c9808ffc05fe31e Mon Sep 17 00:00:00 2001 From: Alessio Belle Date: Mon, 8 Dec 2025 09:11:00 +0000 Subject: [PATCH 1750/2333] drm/imagination: Disallow exporting of PM/FW protected objects commit 6b991ad8dc3abfe5720fc2e9ee96be63ae43e362 upstream. These objects are meant to be used by the GPU firmware or by the PM unit within the GPU, in which case they may contain physical addresses. This adds a layer of protection against exposing potentially exploitable information outside of the driver. Fixes: ff5f643de0bf ("drm/imagination: Add GEM and VM related code") Signed-off-by: Alessio Belle Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20251208-no-export-pm-fw-obj-v1-1-83ab12c61693@imgtec.com Signed-off-by: Matt Coster Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/imagination/pvr_gem.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/gpu/drm/imagination/pvr_gem.c b/drivers/gpu/drm/imagination/pvr_gem.c index a66cf082af244..c07c9a9151903 100644 --- a/drivers/gpu/drm/imagination/pvr_gem.c +++ b/drivers/gpu/drm/imagination/pvr_gem.c @@ -28,6 +28,16 @@ static void pvr_gem_object_free(struct drm_gem_object *obj) drm_gem_shmem_object_free(obj); } +static struct dma_buf *pvr_gem_export(struct drm_gem_object *obj, int flags) +{ + struct pvr_gem_object *pvr_obj = gem_to_pvr_gem(obj); + + if (pvr_obj->flags & DRM_PVR_BO_PM_FW_PROTECT) + return ERR_PTR(-EPERM); + + return drm_gem_prime_export(obj, flags); +} + static int pvr_gem_mmap(struct drm_gem_object *gem_obj, struct vm_area_struct *vma) { struct pvr_gem_object *pvr_obj = gem_to_pvr_gem(gem_obj); @@ -42,6 +52,7 @@ static int pvr_gem_mmap(struct drm_gem_object *gem_obj, struct vm_area_struct *v static const struct drm_gem_object_funcs pvr_gem_object_funcs = { .free = pvr_gem_object_free, .print_info = drm_gem_shmem_object_print_info, + .export = pvr_gem_export, .pin = drm_gem_shmem_object_pin, .unpin = drm_gem_shmem_object_unpin, .get_sg_table = drm_gem_shmem_object_get_sg_table, From 28a6c420f0e7832a5f2104ef176f9eec7a4e90a1 Mon Sep 17 00:00:00 2001 From: Junbeom Yeom Date: Fri, 19 Dec 2025 21:40:31 +0900 Subject: [PATCH 1751/2333] erofs: fix unexpected EIO under memory pressure commit 4012d78562193ef5eb613bad4b0c0fa187637cfe upstream. erofs readahead could fail with ENOMEM under the memory pressure because it tries to alloc_page with GFP_NOWAIT | GFP_NORETRY, while GFP_KERNEL for a regular read. And if readahead fails (with non-uptodate folios), the original request will then fall back to synchronous read, and `.read_folio()` should return appropriate errnos. However, in scenarios where readahead and read operations compete, read operation could return an unintended EIO because of an incorrect error propagation. To resolve this, this patch modifies the behavior so that, when the PCL is for read(which means pcl.besteffort is true), it attempts actual decompression instead of propagating the privios error except initial EIO. - Page size: 4K - The original size of FileA: 16K - Compress-ratio per PCL: 50% (Uncompressed 8K -> Compressed 4K) [page0, page1] [page2, page3] [PCL0]---------[PCL1] - functions declaration: . pread(fd, buf, count, offset) . readahead(fd, offset, count) - Thread A tries to read the last 4K - Thread B tries to do readahead 8K from 4K - RA, besteffort == false - R, besteffort == true pread(FileA, buf, 4K, 12K) do readahead(page3) // failed with ENOMEM wait_lock(page3) if (!uptodate(page3)) goto do_read readahead(FileA, 4K, 8K) // Here create PCL-chain like below: // [null, page1] [page2, null] // [PCL0:RA]-----[PCL1:RA] ... do read(page3) // found [PCL1:RA] and add page3 into it, // and then, change PCL1 from RA to R ... // Now, PCL-chain is as below: // [null, page1] [page2, page3] // [PCL0:RA]-----[PCL1:R] // try to decompress PCL-chain... z_erofs_decompress_queue err = 0; // failed with ENOMEM, so page 1 // only for RA will not be uptodated. // it's okay. err = decompress([PCL0:RA], err) // However, ENOMEM propagated to next // PCL, even though PCL is not only // for RA but also for R. As a result, // it just failed with ENOMEM without // trying any decompression, so page2 // and page3 will not be uptodated. ** BUG HERE ** --> err = decompress([PCL1:R], err) return err as ENOMEM ... wait_lock(page3) if (!uptodate(page3)) return EIO <-- Return an unexpected EIO! ... Fixes: 2349d2fa02db ("erofs: sunset unneeded NOFAILs") Cc: stable@vger.kernel.org Reviewed-by: Jaewook Kim Reviewed-by: Sungjong Seo Signed-off-by: Junbeom Yeom Reviewed-by: Gao Xiang Signed-off-by: Gao Xiang Reviewed-by: Gao Xiang Signed-off-by: Gao Xiang Signed-off-by: Greg Kroah-Hartman --- fs/erofs/zdata.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/fs/erofs/zdata.c b/fs/erofs/zdata.c index bc80cfe482f73..683703aee5ef2 100644 --- a/fs/erofs/zdata.c +++ b/fs/erofs/zdata.c @@ -1262,17 +1262,17 @@ static int z_erofs_parse_in_bvecs(struct z_erofs_backend *be, bool *overlapped) return err; } -static int z_erofs_decompress_pcluster(struct z_erofs_backend *be, int err) +static int z_erofs_decompress_pcluster(struct z_erofs_backend *be, bool eio) { struct erofs_sb_info *const sbi = EROFS_SB(be->sb); struct z_erofs_pcluster *pcl = be->pcl; unsigned int pclusterpages = z_erofs_pclusterpages(pcl); const struct z_erofs_decompressor *decomp = z_erofs_decomp[pcl->algorithmformat]; - int i, j, jtop, err2; + bool try_free = true; + int i, j, jtop, err2, err = eio ? -EIO : 0; struct page *page; bool overlapped; - bool try_free = true; mutex_lock(&pcl->lock); be->nr_pages = PAGE_ALIGN(pcl->length + pcl->pageofs_out) >> PAGE_SHIFT; @@ -1400,12 +1400,12 @@ static int z_erofs_decompress_queue(const struct z_erofs_decompressqueue *io, .pcl = io->head, }; struct z_erofs_pcluster *next; - int err = io->eio ? -EIO : 0; + int err = 0; for (; be.pcl != Z_EROFS_PCLUSTER_TAIL; be.pcl = next) { DBG_BUGON(!be.pcl); next = READ_ONCE(be.pcl->next); - err = z_erofs_decompress_pcluster(&be, err) ?: err; + err = z_erofs_decompress_pcluster(&be, io->eio) ?: err; } return err; } From 142dbd7ed190679c7cac335833f313d56e0f1dd2 Mon Sep 17 00:00:00 2001 From: Damien Le Moal Date: Thu, 13 Nov 2025 22:40:26 +0900 Subject: [PATCH 1752/2333] block: fix NULL pointer dereference in blk_zone_reset_all_bio_endio() commit c2b8d20628ca789640f64074a642f9440eefc623 upstream. For zoned block devices that do not need zone write plugs (e.g. most device mapper devices that support zones), the disk hash table of zone write plugs is NULL. For such devices, blk_zone_reset_all_bio_endio() should not attempt to scan this has table as that causes a NULL pointer dereference. Fix this by checking that the disk does have zone write plugs using the atomic counter. This is equivalent to checking for a non-NULL hash table but has the advantage to also speed up the execution of blk_zone_reset_all_bio_endio() for devices that do use zone write plugs but do not have any plug in the hash table (e.g. a disk with only full zones). Fixes: efae226c2ef1 ("block: handle zone management operations completions") Reported-by: Shin'ichiro Kawasaki Signed-off-by: Damien Le Moal Reviewed-by: Christoph Hellwig Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman --- block/blk-zoned.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/block/blk-zoned.c b/block/blk-zoned.c index 3a3cbee60591b..0c812f3bd7df3 100644 --- a/block/blk-zoned.c +++ b/block/blk-zoned.c @@ -736,17 +736,20 @@ static void blk_zone_reset_all_bio_endio(struct bio *bio) unsigned long flags; unsigned int i; - /* Update the condition of all zone write plugs. */ - rcu_read_lock(); - for (i = 0; i < disk_zone_wplugs_hash_size(disk); i++) { - hlist_for_each_entry_rcu(zwplug, &disk->zone_wplugs_hash[i], - node) { - spin_lock_irqsave(&zwplug->lock, flags); - disk_zone_wplug_set_wp_offset(disk, zwplug, 0); - spin_unlock_irqrestore(&zwplug->lock, flags); + if (atomic_read(&disk->nr_zone_wplugs)) { + /* Update the condition of all zone write plugs. */ + rcu_read_lock(); + for (i = 0; i < disk_zone_wplugs_hash_size(disk); i++) { + hlist_for_each_entry_rcu(zwplug, + &disk->zone_wplugs_hash[i], + node) { + spin_lock_irqsave(&zwplug->lock, flags); + disk_zone_wplug_set_wp_offset(disk, zwplug, 0); + spin_unlock_irqrestore(&zwplug->lock, flags); + } } + rcu_read_unlock(); } - rcu_read_unlock(); } static void blk_zone_finish_bio_endio(struct bio *bio) From 77aa0f5223ffc33545712ec73392822614ed2e9d Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Thu, 23 Oct 2025 10:45:32 -0700 Subject: [PATCH 1753/2333] powercap: intel_rapl: Add support for Wildcat Lake platform commit 39f421f2e301f995c17c35b783e2863155b3f647 upstream. Add Wildcat Lake to the list of supported processors for RAPL. Signed-off-by: Srinivas Pandruvada Link: https://patch.msgid.link/20251023174532.1882008-1-srinivas.pandruvada@linux.intel.com Signed-off-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman --- drivers/powercap/intel_rapl_common.c | 1 + drivers/powercap/intel_rapl_msr.c | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/powercap/intel_rapl_common.c b/drivers/powercap/intel_rapl_common.c index c7e7f9bf53137..cdb4363589e9c 100644 --- a/drivers/powercap/intel_rapl_common.c +++ b/drivers/powercap/intel_rapl_common.c @@ -1284,6 +1284,7 @@ static const struct x86_cpu_id rapl_ids[] __initconst = { X86_MATCH_VFM(INTEL_EMERALDRAPIDS_X, &rapl_defaults_spr_server), X86_MATCH_VFM(INTEL_LUNARLAKE_M, &rapl_defaults_core), X86_MATCH_VFM(INTEL_PANTHERLAKE_L, &rapl_defaults_core), + X86_MATCH_VFM(INTEL_WILDCATLAKE_L, &rapl_defaults_core), X86_MATCH_VFM(INTEL_ARROWLAKE_H, &rapl_defaults_core), X86_MATCH_VFM(INTEL_ARROWLAKE, &rapl_defaults_core), X86_MATCH_VFM(INTEL_ARROWLAKE_U, &rapl_defaults_core), diff --git a/drivers/powercap/intel_rapl_msr.c b/drivers/powercap/intel_rapl_msr.c index 4ed06c71a3ac4..c4d536c2f9893 100644 --- a/drivers/powercap/intel_rapl_msr.c +++ b/drivers/powercap/intel_rapl_msr.c @@ -151,6 +151,7 @@ static const struct x86_cpu_id pl4_support_ids[] = { X86_MATCH_VFM(INTEL_ARROWLAKE_U, NULL), X86_MATCH_VFM(INTEL_ARROWLAKE_H, NULL), X86_MATCH_VFM(INTEL_PANTHERLAKE_L, NULL), + X86_MATCH_VFM(INTEL_WILDCATLAKE_L, NULL), {} }; From 845306163962454083f97d9a2e22f67f94ac8e1f Mon Sep 17 00:00:00 2001 From: Kaushlendra Kumar Date: Tue, 28 Oct 2025 15:48:14 +0530 Subject: [PATCH 1754/2333] powercap: intel_rapl: Add support for Nova Lake processors commit 58075aec92a8141fd7f42e1c36d1bc54552c015e upstream. Add RAPL support for Intel Nova Lake and Nova Lake L processors using the core defaults configuration. Signed-off-by: Kaushlendra Kumar [ rjw: Subject and changelog edits, rebase ] Link: https://patch.msgid.link/20251028101814.3482508-1-kaushlendra.kumar@intel.com Signed-off-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman --- drivers/powercap/intel_rapl_common.c | 2 ++ drivers/powercap/intel_rapl_msr.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/drivers/powercap/intel_rapl_common.c b/drivers/powercap/intel_rapl_common.c index cdb4363589e9c..57bebd07c7d0d 100644 --- a/drivers/powercap/intel_rapl_common.c +++ b/drivers/powercap/intel_rapl_common.c @@ -1285,6 +1285,8 @@ static const struct x86_cpu_id rapl_ids[] __initconst = { X86_MATCH_VFM(INTEL_LUNARLAKE_M, &rapl_defaults_core), X86_MATCH_VFM(INTEL_PANTHERLAKE_L, &rapl_defaults_core), X86_MATCH_VFM(INTEL_WILDCATLAKE_L, &rapl_defaults_core), + X86_MATCH_VFM(INTEL_NOVALAKE, &rapl_defaults_core), + X86_MATCH_VFM(INTEL_NOVALAKE_L, &rapl_defaults_core), X86_MATCH_VFM(INTEL_ARROWLAKE_H, &rapl_defaults_core), X86_MATCH_VFM(INTEL_ARROWLAKE, &rapl_defaults_core), X86_MATCH_VFM(INTEL_ARROWLAKE_U, &rapl_defaults_core), diff --git a/drivers/powercap/intel_rapl_msr.c b/drivers/powercap/intel_rapl_msr.c index c4d536c2f9893..c6b9a7debc354 100644 --- a/drivers/powercap/intel_rapl_msr.c +++ b/drivers/powercap/intel_rapl_msr.c @@ -152,6 +152,8 @@ static const struct x86_cpu_id pl4_support_ids[] = { X86_MATCH_VFM(INTEL_ARROWLAKE_H, NULL), X86_MATCH_VFM(INTEL_PANTHERLAKE_L, NULL), X86_MATCH_VFM(INTEL_WILDCATLAKE_L, NULL), + X86_MATCH_VFM(INTEL_NOVALAKE, NULL), + X86_MATCH_VFM(INTEL_NOVALAKE_L, NULL), {} }; From e7a7d7e629c2abcc0ade47b148ebe71d5832ead9 Mon Sep 17 00:00:00 2001 From: Chenghao Duan Date: Tue, 6 Jan 2026 10:55:02 +0800 Subject: [PATCH 1755/2333] LoongArch: BPF: Enhance the bpf_arch_text_poke() function commit 73721d8676771c6c7b06d4e636cc053fc76afefd upstream. Enhance the bpf_arch_text_poke() function to enable accurate location of BPF program entry points. When modifying the entry point of a BPF program, skip the "move t0, ra" instruction to ensure the correct logic and copy of the jump address. Cc: stable@vger.kernel.org Fixes: 677e6123e3d2 ("LoongArch: BPF: Disable trampoline for kernel module function trace") Signed-off-by: Chenghao Duan Signed-off-by: Huacai Chen Signed-off-by: Greg Kroah-Hartman --- arch/loongarch/net/bpf_jit.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/arch/loongarch/net/bpf_jit.c b/arch/loongarch/net/bpf_jit.c index 95c214e2cf096..87ff025137873 100644 --- a/arch/loongarch/net/bpf_jit.c +++ b/arch/loongarch/net/bpf_jit.c @@ -1307,6 +1307,10 @@ int bpf_arch_text_poke(void *ip, enum bpf_text_poke_type poke_type, void *old_addr, void *new_addr) { int ret; + unsigned long size = 0; + unsigned long offset = 0; + void *image = NULL; + char namebuf[KSYM_NAME_LEN]; bool is_call = (poke_type == BPF_MOD_CALL); u32 old_insns[LOONGARCH_LONG_JUMP_NINSNS] = {[0 ... 4] = INSN_NOP}; u32 new_insns[LOONGARCH_LONG_JUMP_NINSNS] = {[0 ... 4] = INSN_NOP}; @@ -1314,9 +1318,20 @@ int bpf_arch_text_poke(void *ip, enum bpf_text_poke_type poke_type, /* Only poking bpf text is supported. Since kernel function entry * is set up by ftrace, we rely on ftrace to poke kernel functions. */ - if (!is_bpf_text_address((unsigned long)ip)) + if (!__bpf_address_lookup((unsigned long)ip, &size, &offset, namebuf)) return -ENOTSUPP; + image = ip - offset; + + /* zero offset means we're poking bpf prog entry */ + if (offset == 0) { + /* skip to the nop instruction in bpf prog entry: + * move t0, ra + * nop + */ + ip = image + LOONGARCH_INSN_SIZE; + } + ret = emit_jump_or_nops(old_addr, ip, old_insns, is_call); if (ret) return ret; From a9040eac434b1f0dbc85bbe50bce50d94afc6a91 Mon Sep 17 00:00:00 2001 From: Kevin Tian Date: Tue, 6 Jan 2026 02:11:44 +0000 Subject: [PATCH 1756/2333] vfio/pci: Disable qword access to the PCI ROM bar [ Upstream commit dc85a46928c41423ad89869baf05a589e2975575 ] Commit 2b938e3db335 ("vfio/pci: Enable iowrite64 and ioread64 for vfio pci") enables qword access to the PCI bar resources. However certain devices (e.g. Intel X710) are observed with problem upon qword accesses to the rom bar, e.g. triggering PCI aer errors. This is triggered by Qemu which caches the rom content by simply does a pread() of the remaining size until it gets the full contents. The other bars would only perform operations at the same access width as their guest drivers. Instead of trying to identify all broken devices, universally disable qword access to the rom bar i.e. going back to the old way which worked reliably for years. Reported-by: Farrah Chen Closes: https://bugzilla.kernel.org/show_bug.cgi?id=220740 Fixes: 2b938e3db335 ("vfio/pci: Enable iowrite64 and ioread64 for vfio pci") Cc: stable@vger.kernel.org Signed-off-by: Kevin Tian Tested-by: Farrah Chen Link: https://lore.kernel.org/r/20251218081650.555015-2-kevin.tian@intel.com Signed-off-by: Alex Williamson Signed-off-by: Greg Kroah-Hartman --- drivers/vfio/pci/nvgrace-gpu/main.c | 4 ++-- drivers/vfio/pci/vfio_pci_rdwr.c | 25 ++++++++++++++++++------- include/linux/vfio_pci_core.h | 10 +++++++++- 3 files changed, 29 insertions(+), 10 deletions(-) diff --git a/drivers/vfio/pci/nvgrace-gpu/main.c b/drivers/vfio/pci/nvgrace-gpu/main.c index e346392b72f6a..3dc3c2432b5e0 100644 --- a/drivers/vfio/pci/nvgrace-gpu/main.c +++ b/drivers/vfio/pci/nvgrace-gpu/main.c @@ -491,7 +491,7 @@ nvgrace_gpu_map_and_read(struct nvgrace_gpu_pci_core_device *nvdev, ret = vfio_pci_core_do_io_rw(&nvdev->core_device, false, nvdev->resmem.ioaddr, buf, offset, mem_count, - 0, 0, false); + 0, 0, false, VFIO_PCI_IO_WIDTH_8); } return ret; @@ -609,7 +609,7 @@ nvgrace_gpu_map_and_write(struct nvgrace_gpu_pci_core_device *nvdev, ret = vfio_pci_core_do_io_rw(&nvdev->core_device, false, nvdev->resmem.ioaddr, (char __user *)buf, pos, mem_count, - 0, 0, true); + 0, 0, true, VFIO_PCI_IO_WIDTH_8); } return ret; diff --git a/drivers/vfio/pci/vfio_pci_rdwr.c b/drivers/vfio/pci/vfio_pci_rdwr.c index 6192788c8ba39..25380b7dfe18a 100644 --- a/drivers/vfio/pci/vfio_pci_rdwr.c +++ b/drivers/vfio/pci/vfio_pci_rdwr.c @@ -135,7 +135,8 @@ VFIO_IORDWR(64) ssize_t vfio_pci_core_do_io_rw(struct vfio_pci_core_device *vdev, bool test_mem, void __iomem *io, char __user *buf, loff_t off, size_t count, size_t x_start, - size_t x_end, bool iswrite) + size_t x_end, bool iswrite, + enum vfio_pci_io_width max_width) { ssize_t done = 0; int ret; @@ -150,20 +151,19 @@ ssize_t vfio_pci_core_do_io_rw(struct vfio_pci_core_device *vdev, bool test_mem, else fillable = 0; - if (fillable >= 8 && !(off % 8)) { + if (fillable >= 8 && !(off % 8) && max_width >= 8) { ret = vfio_pci_iordwr64(vdev, iswrite, test_mem, io, buf, off, &filled); if (ret) return ret; - } else - if (fillable >= 4 && !(off % 4)) { + } else if (fillable >= 4 && !(off % 4) && max_width >= 4) { ret = vfio_pci_iordwr32(vdev, iswrite, test_mem, io, buf, off, &filled); if (ret) return ret; - } else if (fillable >= 2 && !(off % 2)) { + } else if (fillable >= 2 && !(off % 2) && max_width >= 2) { ret = vfio_pci_iordwr16(vdev, iswrite, test_mem, io, buf, off, &filled); if (ret) @@ -234,6 +234,7 @@ ssize_t vfio_pci_bar_rw(struct vfio_pci_core_device *vdev, char __user *buf, void __iomem *io; struct resource *res = &vdev->pdev->resource[bar]; ssize_t done; + enum vfio_pci_io_width max_width = VFIO_PCI_IO_WIDTH_8; if (pci_resource_start(pdev, bar)) end = pci_resource_len(pdev, bar); @@ -262,6 +263,16 @@ ssize_t vfio_pci_bar_rw(struct vfio_pci_core_device *vdev, char __user *buf, if (!io) return -ENOMEM; x_end = end; + + /* + * Certain devices (e.g. Intel X710) don't support qword + * access to the ROM bar. Otherwise PCI AER errors might be + * triggered. + * + * Disable qword access to the ROM bar universally, which + * worked reliably for years before qword access is enabled. + */ + max_width = VFIO_PCI_IO_WIDTH_4; } else { int ret = vfio_pci_core_setup_barmap(vdev, bar); if (ret) { @@ -278,7 +289,7 @@ ssize_t vfio_pci_bar_rw(struct vfio_pci_core_device *vdev, char __user *buf, } done = vfio_pci_core_do_io_rw(vdev, res->flags & IORESOURCE_MEM, io, buf, pos, - count, x_start, x_end, iswrite); + count, x_start, x_end, iswrite, max_width); if (done >= 0) *ppos += done; @@ -352,7 +363,7 @@ ssize_t vfio_pci_vga_rw(struct vfio_pci_core_device *vdev, char __user *buf, * to the memory enable bit in the command register. */ done = vfio_pci_core_do_io_rw(vdev, false, iomem, buf, off, count, - 0, 0, iswrite); + 0, 0, iswrite, VFIO_PCI_IO_WIDTH_8); vga_put(vdev->pdev, rsrc); diff --git a/include/linux/vfio_pci_core.h b/include/linux/vfio_pci_core.h index f5c93787f8e0b..7aa29428982aa 100644 --- a/include/linux/vfio_pci_core.h +++ b/include/linux/vfio_pci_core.h @@ -102,6 +102,13 @@ struct vfio_pci_core_device { struct rw_semaphore memory_lock; }; +enum vfio_pci_io_width { + VFIO_PCI_IO_WIDTH_1 = 1, + VFIO_PCI_IO_WIDTH_2 = 2, + VFIO_PCI_IO_WIDTH_4 = 4, + VFIO_PCI_IO_WIDTH_8 = 8, +}; + /* Will be exported for vfio pci drivers usage */ int vfio_pci_core_register_dev_region(struct vfio_pci_core_device *vdev, unsigned int type, unsigned int subtype, @@ -139,7 +146,8 @@ pci_ers_result_t vfio_pci_core_aer_err_detected(struct pci_dev *pdev, ssize_t vfio_pci_core_do_io_rw(struct vfio_pci_core_device *vdev, bool test_mem, void __iomem *io, char __user *buf, loff_t off, size_t count, size_t x_start, - size_t x_end, bool iswrite); + size_t x_end, bool iswrite, + enum vfio_pci_io_width max_width); bool vfio_pci_core_range_intersect_range(loff_t buf_start, size_t buf_cnt, loff_t reg_start, size_t reg_cnt, loff_t *buf_offset, From 1ba137c89ff03e27dbf01abb0b04fe751d254e31 Mon Sep 17 00:00:00 2001 From: SeongJae Park Date: Mon, 5 Jan 2026 17:42:49 -0800 Subject: [PATCH 1757/2333] mm/damon/tests/core-kunit: handle alloc failures on damon_test_split_regions_of() damon_test_split_regions_of() is assuming all dynamic memory allocation in it will succeed. Those are indeed likely in the real use cases since those allocations are too small to fail, but theoretically those could fail. In the case, inappropriate memory access can happen. Fix it by appropriately cleanup pre-allocated memory and skip the execution of the remaining tests in the failure cases. Link: https://lkml.kernel.org/r/20251101182021.74868-9-sj@kernel.org Fixes: 17ccae8bb5c9 ("mm/damon: add kunit tests") Signed-off-by: SeongJae Park Cc: Brendan Higgins Cc: David Gow Cc: Kefeng Wang Cc: [5.15+] Signed-off-by: Andrew Morton (cherry picked from commit eded254cb69044bd4abde87394ea44909708d7c0) Signed-off-by: SeongJae Park Signed-off-by: Greg Kroah-Hartman --- mm/damon/tests/core-kunit.h | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/mm/damon/tests/core-kunit.h b/mm/damon/tests/core-kunit.h index 63d10ca934f61..6687778752728 100644 --- a/mm/damon/tests/core-kunit.h +++ b/mm/damon/tests/core-kunit.h @@ -278,15 +278,35 @@ static void damon_test_split_regions_of(struct kunit *test) struct damon_target *t; struct damon_region *r; + if (!c) + kunit_skip(test, "ctx alloc fail"); t = damon_new_target(); + if (!t) { + damon_destroy_ctx(c); + kunit_skip(test, "target alloc fail"); + } r = damon_new_region(0, 22); + if (!r) { + damon_destroy_ctx(c); + damon_free_target(t); + kunit_skip(test, "region alloc fail"); + } damon_add_region(r, t); damon_split_regions_of(t, 2, DAMON_MIN_REGION); KUNIT_EXPECT_LE(test, damon_nr_regions(t), 2u); damon_free_target(t); t = damon_new_target(); + if (!t) { + damon_destroy_ctx(c); + kunit_skip(test, "second target alloc fail"); + } r = damon_new_region(0, 220); + if (!r) { + damon_destroy_ctx(c); + damon_free_target(t); + kunit_skip(test, "second region alloc fail"); + } damon_add_region(r, t); damon_split_regions_of(t, 4, DAMON_MIN_REGION); KUNIT_EXPECT_LE(test, damon_nr_regions(t), 4u); From 2d48340ccc9d49b22f922e3a0562da32866e218b Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 6 Jan 2026 15:53:21 +0000 Subject: [PATCH 1758/2333] Revert "gpio: swnode: don't use the swnode's name as the key for GPIO lookup" This reverts commit e5d527be7e6984882306b49c067f1fec18920735. This software node change doesn't actually fix any current issues with the kernel, it is an improvement to the lookup process rather than fixing a live bug. It also causes a couple of regressions with shipping laptops, which relied on the label based lookup. There is a fix for the regressions in mainline, the first 5 patches of [1]. However, those patches are fairly substantial changes and given the patch causing the regression doesn't actually fix a bug it seems better to just revert it in stable. CC: stable@vger.kernel.org # 6.18 Link: https://lore.kernel.org/linux-sound/20251120-reset-gpios-swnodes-v7-0-a100493a0f4b@linaro.org/ [1] Closes: https://github.com/thesofproject/linux/issues/5599 Closes: https://github.com/thesofproject/linux/issues/5603 Acked-by: Bartosz Golaszewski Signed-off-by: Charles Keepax Signed-off-by: Greg Kroah-Hartman --- drivers/gpio/gpiolib-swnode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpiolib-swnode.c b/drivers/gpio/gpiolib-swnode.c index e3806db1c0e07..f21dbc28cf2c8 100644 --- a/drivers/gpio/gpiolib-swnode.c +++ b/drivers/gpio/gpiolib-swnode.c @@ -41,7 +41,7 @@ static struct gpio_device *swnode_get_gpio_device(struct fwnode_handle *fwnode) !strcmp(gdev_node->name, GPIOLIB_SWNODE_UNDEFINED_NAME)) return ERR_PTR(-ENOENT); - gdev = gpio_device_find_by_fwnode(fwnode); + gdev = gpio_device_find_by_label(gdev_node->name); return gdev ?: ERR_PTR(-EPROBE_DEFER); } From 3aa9aac0e8b767a7c6fac33ae626a332c2ba1389 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 8 Jan 2026 10:17:22 +0100 Subject: [PATCH 1759/2333] Linux 6.18.4 Link: https://lore.kernel.org/r/20260106170547.832845344@linuxfoundation.org Tested-by: Brett A C Sheffield Tested-by: Ronald Warsow Tested-by: Peter Schneider Tested-by: Shuah Khan Tested-by: Justin M. Forbes Tested-by: Florian Fainelli Tested-by: Christian Heusel Tested-by: Ron Economos Tested-by: Mark Brown Tested-by: Jeffrin Jose T Tested-by: Salvatore Bonaccorso Tested-by: Takeshi Ogasawara Tested-by: Miguel Ojeda Tested-by: Jon Hunter Tested-by: Hardik Garg Tested-by: Brett Mastbergen Signed-off-by: Greg Kroah-Hartman --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 17415fdcd358d..7b431af09b322 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 VERSION = 6 PATCHLEVEL = 18 -SUBLEVEL = 3 +SUBLEVEL = 4 EXTRAVERSION = NAME = Baby Opossum Posse From 9b500985da8308903c6d33173f4dfab0280afd7a Mon Sep 17 00:00:00 2001 From: Anurag Pateriya Date: Wed, 17 Dec 2025 18:42:40 +0530 Subject: [PATCH 1760/2333] QCLINUX: arm64: configs: Added new rt.config for RT kernel Enabled PREEMPT_RT in new rt.config to enable RT kernel features. Signed-off-by: Anurag Pateriya --- arch/arm64/configs/rt.config | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 arch/arm64/configs/rt.config diff --git a/arch/arm64/configs/rt.config b/arch/arm64/configs/rt.config new file mode 100644 index 0000000000000..ca92615d38a17 --- /dev/null +++ b/arch/arm64/configs/rt.config @@ -0,0 +1,3 @@ +# rt.config for Real time kernel features +CONFIG_EXPERT=y +CONFIG_PREEMPT_RT=y From f1a77dfc3b045c3dd5f6e64189b9f52b90399f07 Mon Sep 17 00:00:00 2001 From: Paolo Abeni Date: Tue, 6 Jan 2026 15:55:58 -0500 Subject: [PATCH 1761/2333] mptcp: ensure context reset on disconnect() [ Upstream commit 86730ac255b0497a272704de9a1df559f5d6602e ] After the blamed commit below, if the MPC subflow is already in TCP_CLOSE status or has fallback to TCP at mptcp_disconnect() time, mptcp_do_fastclose() skips setting the `send_fastclose flag` and the later __mptcp_close_ssk() does not reset anymore the related subflow context. Any later connection will be created with both the `request_mptcp` flag and the msk-level fallback status off (it is unconditionally cleared at MPTCP disconnect time), leading to a warning in subflow_data_ready(): WARNING: CPU: 26 PID: 8996 at net/mptcp/subflow.c:1519 subflow_data_ready (net/mptcp/subflow.c:1519 (discriminator 13)) Modules linked in: CPU: 26 UID: 0 PID: 8996 Comm: syz.22.39 Not tainted 6.18.0-rc7-05427-g11fc074f6c36 #1 PREEMPT(voluntary) Hardware name: Bochs Bochs, BIOS Bochs 01/01/2011 RIP: 0010:subflow_data_ready (net/mptcp/subflow.c:1519 (discriminator 13)) Code: 90 0f 0b 90 90 e9 04 fe ff ff e8 b7 1e f5 fe 89 ee bf 07 00 00 00 e8 db 19 f5 fe 83 fd 07 0f 84 35 ff ff ff e8 9d 1e f5 fe 90 <0f> 0b 90 e9 27 ff ff ff e8 8f 1e f5 fe 4c 89 e7 48 89 de e8 14 09 RSP: 0018:ffffc9002646fb30 EFLAGS: 00010293 RAX: 0000000000000000 RBX: ffff88813b218000 RCX: ffffffff825c8435 RDX: ffff8881300b3580 RSI: ffffffff825c8443 RDI: 0000000000000005 RBP: 000000000000000b R08: ffffffff825c8435 R09: 000000000000000b R10: 0000000000000005 R11: 0000000000000007 R12: ffff888131ac0000 R13: 0000000000000000 R14: 0000000000000000 R15: 0000000000000000 FS: 00007f88330af6c0(0000) GS:ffff888a93dd2000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007f88330aefe8 CR3: 000000010ff59000 CR4: 0000000000350ef0 Call Trace: tcp_data_ready (net/ipv4/tcp_input.c:5356) tcp_data_queue (net/ipv4/tcp_input.c:5445) tcp_rcv_state_process (net/ipv4/tcp_input.c:7165) tcp_v4_do_rcv (net/ipv4/tcp_ipv4.c:1955) __release_sock (include/net/sock.h:1158 (discriminator 6) net/core/sock.c:3180 (discriminator 6)) release_sock (net/core/sock.c:3737) mptcp_sendmsg (net/mptcp/protocol.c:1763 net/mptcp/protocol.c:1857) inet_sendmsg (net/ipv4/af_inet.c:853 (discriminator 7)) __sys_sendto (net/socket.c:727 (discriminator 15) net/socket.c:742 (discriminator 15) net/socket.c:2244 (discriminator 15)) __x64_sys_sendto (net/socket.c:2247) do_syscall_64 (arch/x86/entry/syscall_64.c:63 (discriminator 1) arch/x86/entry/syscall_64.c:94 (discriminator 1)) entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:130) RIP: 0033:0x7f883326702d Address the issue setting an explicit `fastclosing` flag at fastclose time, and checking such flag after mptcp_do_fastclose(). Fixes: ae155060247b ("mptcp: fix duplicate reset on fastclose") Cc: stable@vger.kernel.org Signed-off-by: Paolo Abeni Reviewed-by: Matthieu Baerts (NGI0) Signed-off-by: Matthieu Baerts (NGI0) Link: https://patch.msgid.link/20251212-net-mptcp-subflow_data_ready-warn-v1-2-d1f9fd1c36c8@kernel.org Signed-off-by: Paolo Abeni [ Adjust context ] Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- net/mptcp/protocol.c | 8 +++++--- net/mptcp/protocol.h | 3 ++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index 221a5ea019e69..d4e3111ba643f 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -2421,10 +2421,10 @@ bool __mptcp_retransmit_pending_data(struct sock *sk) */ static void __mptcp_subflow_disconnect(struct sock *ssk, struct mptcp_subflow_context *subflow, - unsigned int flags) + bool fastclosing) { if (((1 << ssk->sk_state) & (TCPF_CLOSE | TCPF_LISTEN)) || - subflow->send_fastclose) { + fastclosing) { /* The MPTCP code never wait on the subflow sockets, TCP-level * disconnect should never fail */ @@ -2476,7 +2476,7 @@ static void __mptcp_close_ssk(struct sock *sk, struct sock *ssk, need_push = (flags & MPTCP_CF_PUSH) && __mptcp_retransmit_pending_data(sk); if (!dispose_it) { - __mptcp_subflow_disconnect(ssk, subflow, flags); + __mptcp_subflow_disconnect(ssk, subflow, msk->fastclosing); release_sock(ssk); goto out; @@ -2789,6 +2789,7 @@ static void mptcp_do_fastclose(struct sock *sk) struct mptcp_sock *msk = mptcp_sk(sk); mptcp_set_state(sk, TCP_CLOSE); + msk->fastclosing = 1; /* Explicitly send the fastclose reset as need */ if (__mptcp_check_fallback(msk)) @@ -3299,6 +3300,7 @@ static int mptcp_disconnect(struct sock *sk, int flags) msk->bytes_sent = 0; msk->bytes_retrans = 0; msk->rcvspace_init = 0; + msk->fastclosing = 0; WRITE_ONCE(sk->sk_shutdown, 0); sk_error_report(sk); diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index 0e8b0a650108c..30d5e57197936 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -321,7 +321,8 @@ struct mptcp_sock { fastopening:1, in_accept_queue:1, free_first:1, - rcvspace_init:1; + rcvspace_init:1, + fastclosing:1; u32 notsent_lowat; int keepalive_cnt; int keepalive_idle; From c7ca7e0ff6f0f55ef57c1596286076492f199f9a Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Fri, 7 Nov 2025 17:01:24 +0100 Subject: [PATCH 1762/2333] sched/fair: Small cleanup to sched_balance_newidle() commit e78e70dbf603c1425f15f32b455ca148c932f6c1 upstream. Pull out the !sd check to simplify code. Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: Dietmar Eggemann Tested-by: Dietmar Eggemann Tested-by: Chris Mason Link: https://patch.msgid.link/20251107161739.525916173@infradead.org Signed-off-by: Greg Kroah-Hartman --- kernel/sched/fair.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index bfce451f1210c..3dd12dcf6e6d1 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -12787,14 +12787,16 @@ static int sched_balance_newidle(struct rq *this_rq, struct rq_flags *rf) rcu_read_lock(); sd = rcu_dereference_check_sched_domain(this_rq->sd); + if (!sd) { + rcu_read_unlock(); + goto out; + } if (!get_rd_overloaded(this_rq->rd) || - (sd && this_rq->avg_idle < sd->max_newidle_lb_cost)) { + this_rq->avg_idle < sd->max_newidle_lb_cost) { - if (sd) - update_next_balance(sd, &next_balance); + update_next_balance(sd, &next_balance); rcu_read_unlock(); - goto out; } rcu_read_unlock(); From d4ffb9ce8e6501bebbf833cd7ae3f34eab1f76ba Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Fri, 7 Nov 2025 17:01:27 +0100 Subject: [PATCH 1763/2333] sched/fair: Small cleanup to update_newidle_cost() commit 08d473dd8718e4a4d698b1113a14a40ad64a909b upstream. Simplify code by adding a few variables. Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: Dietmar Eggemann Tested-by: Dietmar Eggemann Tested-by: Chris Mason Link: https://patch.msgid.link/20251107161739.655208666@infradead.org Signed-off-by: Greg Kroah-Hartman --- kernel/sched/fair.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 3dd12dcf6e6d1..8369dadf19580 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -12124,22 +12124,25 @@ void update_max_interval(void) static inline bool update_newidle_cost(struct sched_domain *sd, u64 cost) { + unsigned long next_decay = sd->last_decay_max_lb_cost + HZ; + unsigned long now = jiffies; + if (cost > sd->max_newidle_lb_cost) { /* * Track max cost of a domain to make sure to not delay the * next wakeup on the CPU. */ sd->max_newidle_lb_cost = cost; - sd->last_decay_max_lb_cost = jiffies; - } else if (time_after(jiffies, sd->last_decay_max_lb_cost + HZ)) { + sd->last_decay_max_lb_cost = now; + + } else if (time_after(now, next_decay)) { /* * Decay the newidle max times by ~1% per second to ensure that * it is not outdated and the current max cost is actually * shorter. */ sd->max_newidle_lb_cost = (sd->max_newidle_lb_cost * 253) / 256; - sd->last_decay_max_lb_cost = jiffies; - + sd->last_decay_max_lb_cost = now; return true; } From 98a26893fad4180d8ea210d8749392790dfddc81 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Fri, 7 Nov 2025 17:01:31 +0100 Subject: [PATCH 1764/2333] sched/fair: Proportional newidle balance commit 33cf66d88306663d16e4759e9d24766b0aaa2e17 upstream. Add a randomized algorithm that runs newidle balancing proportional to its success rate. This improves schbench significantly: 6.18-rc4: 2.22 Mrps/s 6.18-rc4+revert: 2.04 Mrps/s 6.18-rc4+revert+random: 2.18 Mrps/S Conversely, per Adam Li this affects SpecJBB slightly, reducing it by 1%: 6.17: -6% 6.17+revert: 0% 6.17+revert+random: -1% Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: Dietmar Eggemann Tested-by: Dietmar Eggemann Tested-by: Chris Mason Link: https://lkml.kernel.org/r/6825c50d-7fa7-45d8-9b81-c6e7e25738e2@meta.com Link: https://patch.msgid.link/20251107161739.770122091@infradead.org Signed-off-by: Greg Kroah-Hartman --- include/linux/sched/topology.h | 3 +++ kernel/sched/core.c | 3 +++ kernel/sched/fair.c | 44 ++++++++++++++++++++++++++++++---- kernel/sched/features.h | 5 ++++ kernel/sched/sched.h | 7 ++++++ kernel/sched/topology.c | 6 +++++ 6 files changed, 64 insertions(+), 4 deletions(-) diff --git a/include/linux/sched/topology.h b/include/linux/sched/topology.h index bbcfdf12aa6e5..45c0022b91ced 100644 --- a/include/linux/sched/topology.h +++ b/include/linux/sched/topology.h @@ -92,6 +92,9 @@ struct sched_domain { unsigned int nr_balance_failed; /* initialise to 0 */ /* idle_balance() stats */ + unsigned int newidle_call; + unsigned int newidle_success; + unsigned int newidle_ratio; u64 max_newidle_lb_cost; unsigned long last_decay_max_lb_cost; diff --git a/kernel/sched/core.c b/kernel/sched/core.c index f754a60de8484..eb47d294e2c5a 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -121,6 +121,7 @@ EXPORT_TRACEPOINT_SYMBOL_GPL(sched_update_nr_running_tp); EXPORT_TRACEPOINT_SYMBOL_GPL(sched_compute_energy_tp); DEFINE_PER_CPU_SHARED_ALIGNED(struct rq, runqueues); +DEFINE_PER_CPU(struct rnd_state, sched_rnd_state); #ifdef CONFIG_SCHED_PROXY_EXEC DEFINE_STATIC_KEY_TRUE(__sched_proxy_exec); @@ -8591,6 +8592,8 @@ void __init sched_init_smp(void) { sched_init_numa(NUMA_NO_NODE); + prandom_init_once(&sched_rnd_state); + /* * There's no userspace yet to cause hotplug operations; hence all the * CPU masks are stable and all blatant races in the below code cannot diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 8369dadf19580..d1206f81f8b2e 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -12122,11 +12122,27 @@ void update_max_interval(void) max_load_balance_interval = HZ*num_online_cpus()/10; } -static inline bool update_newidle_cost(struct sched_domain *sd, u64 cost) +static inline void update_newidle_stats(struct sched_domain *sd, unsigned int success) +{ + sd->newidle_call++; + sd->newidle_success += success; + + if (sd->newidle_call >= 1024) { + sd->newidle_ratio = sd->newidle_success; + sd->newidle_call /= 2; + sd->newidle_success /= 2; + } +} + +static inline bool +update_newidle_cost(struct sched_domain *sd, u64 cost, unsigned int success) { unsigned long next_decay = sd->last_decay_max_lb_cost + HZ; unsigned long now = jiffies; + if (cost) + update_newidle_stats(sd, success); + if (cost > sd->max_newidle_lb_cost) { /* * Track max cost of a domain to make sure to not delay the @@ -12174,7 +12190,7 @@ static void sched_balance_domains(struct rq *rq, enum cpu_idle_type idle) * Decay the newidle max times here because this is a regular * visit to all the domains. */ - need_decay = update_newidle_cost(sd, 0); + need_decay = update_newidle_cost(sd, 0, 0); max_cost += sd->max_newidle_lb_cost; /* @@ -12819,6 +12835,22 @@ static int sched_balance_newidle(struct rq *this_rq, struct rq_flags *rf) break; if (sd->flags & SD_BALANCE_NEWIDLE) { + unsigned int weight = 1; + + if (sched_feat(NI_RANDOM)) { + /* + * Throw a 1k sided dice; and only run + * newidle_balance according to the success + * rate. + */ + u32 d1k = sched_rng() % 1024; + weight = 1 + sd->newidle_ratio; + if (d1k > weight) { + update_newidle_stats(sd, 0); + continue; + } + weight = (1024 + weight/2) / weight; + } pulled_task = sched_balance_rq(this_cpu, this_rq, sd, CPU_NEWLY_IDLE, @@ -12826,10 +12858,14 @@ static int sched_balance_newidle(struct rq *this_rq, struct rq_flags *rf) t1 = sched_clock_cpu(this_cpu); domain_cost = t1 - t0; - update_newidle_cost(sd, domain_cost); - curr_cost += domain_cost; t0 = t1; + + /* + * Track max cost of a domain to make sure to not delay the + * next wakeup on the CPU. + */ + update_newidle_cost(sd, domain_cost, weight * !!pulled_task); } /* diff --git a/kernel/sched/features.h b/kernel/sched/features.h index 3c12d9f93331d..136a6584be797 100644 --- a/kernel/sched/features.h +++ b/kernel/sched/features.h @@ -121,3 +121,8 @@ SCHED_FEAT(WA_BIAS, true) SCHED_FEAT(UTIL_EST, true) SCHED_FEAT(LATENCY_WARN, false) + +/* + * Do newidle balancing proportional to its success rate using randomization. + */ +SCHED_FEAT(NI_RANDOM, true) diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index 92ec751799f55..2f8b06b12a98f 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -5,6 +5,7 @@ #ifndef _KERNEL_SCHED_SCHED_H #define _KERNEL_SCHED_SCHED_H +#include #include #include #include @@ -1349,6 +1350,12 @@ static inline bool is_migration_disabled(struct task_struct *p) } DECLARE_PER_CPU_SHARED_ALIGNED(struct rq, runqueues); +DECLARE_PER_CPU(struct rnd_state, sched_rnd_state); + +static inline u32 sched_rng(void) +{ + return prandom_u32_state(this_cpu_ptr(&sched_rnd_state)); +} #define cpu_rq(cpu) (&per_cpu(runqueues, (cpu))) #define this_rq() this_cpu_ptr(&runqueues) diff --git a/kernel/sched/topology.c b/kernel/sched/topology.c index 444bdfdab7318..c7a4d2fff5718 100644 --- a/kernel/sched/topology.c +++ b/kernel/sched/topology.c @@ -1662,6 +1662,12 @@ sd_init(struct sched_domain_topology_level *tl, .last_balance = jiffies, .balance_interval = sd_weight, + + /* 50% success rate */ + .newidle_call = 512, + .newidle_success = 256, + .newidle_ratio = 512, + .max_newidle_lb_cost = 0, .last_decay_max_lb_cost = jiffies, .child = child, From 7a28d65e4beb7627738b75c6a23f36ae54470f93 Mon Sep 17 00:00:00 2001 From: Mike Snitzer Date: Wed, 26 Nov 2025 01:01:25 -0500 Subject: [PATCH 1765/2333] nfs/localio: fix regression due to out-of-order __put_cred commit 3af870aedbff10bfed220e280b57a405e972229f upstream. Commit f2060bdc21d7 ("nfs/localio: add refcounting for each iocb IO associated with NFS pgio header") inadvertantly reintroduced the same potential for __put_cred() triggering BUG_ON(cred == current->cred) that commit 992203a1fba5 ("nfs/localio: restore creds before releasing pageio data") fixed. Fix this by saving and restoring the cred around each {read,write}_iter call within the respective for loop of nfs_local_call_{read,write} using scoped_with_creds(). NOTE: this fix started by first reverting the following commits: 94afb627dfc2 ("nfs: use credential guards in nfs_local_call_read()") bff3c841f7bd ("nfs: use credential guards in nfs_local_call_write()") 1d18101a644e ("Merge tag 'kernel-6.19-rc1.cred' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs") followed by narrowly fixing the cred lifetime issue by using scoped_with_creds(). In doing so, this commit's changes appear more extensive than they really are (as evidenced by comparing to v6.18's fs/nfs/localio.c). Reported-by: Zorro Lang Signed-off-by: Mike Snitzer Acked-by: Trond Myklebust Reviewed-by: Christian Brauner Link: https://lore.kernel.org/linux-next/20251205111942.4150b06f@canb.auug.org.au/ Signed-off-by: Linus Torvalds Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman --- fs/nfs/localio.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/fs/nfs/localio.c b/fs/nfs/localio.c index b98bb292fef0c..ed2a7efaf8f20 100644 --- a/fs/nfs/localio.c +++ b/fs/nfs/localio.c @@ -623,8 +623,6 @@ static void nfs_local_call_read(struct work_struct *work) ssize_t status; int n_iters; - save_cred = override_creds(filp->f_cred); - n_iters = atomic_read(&iocb->n_iters); for (int i = 0; i < n_iters ; i++) { if (iocb->iter_is_dio_aligned[i]) { @@ -637,7 +635,10 @@ static void nfs_local_call_read(struct work_struct *work) } else iocb->kiocb.ki_flags &= ~IOCB_DIRECT; + save_cred = override_creds(filp->f_cred); status = filp->f_op->read_iter(&iocb->kiocb, &iocb->iters[i]); + revert_creds(save_cred); + if (status != -EIOCBQUEUED) { if (unlikely(status >= 0 && status < iocb->iters[i].count)) force_done = true; /* Partial read */ @@ -647,8 +648,6 @@ static void nfs_local_call_read(struct work_struct *work) } } } - - revert_creds(save_cred); } static int @@ -830,7 +829,6 @@ static void nfs_local_call_write(struct work_struct *work) int n_iters; current->flags |= PF_LOCAL_THROTTLE | PF_MEMALLOC_NOIO; - save_cred = override_creds(filp->f_cred); file_start_write(filp); n_iters = atomic_read(&iocb->n_iters); @@ -845,7 +843,10 @@ static void nfs_local_call_write(struct work_struct *work) } else iocb->kiocb.ki_flags &= ~IOCB_DIRECT; + save_cred = override_creds(filp->f_cred); status = filp->f_op->write_iter(&iocb->kiocb, &iocb->iters[i]); + revert_creds(save_cred); + if (status != -EIOCBQUEUED) { if (unlikely(status >= 0 && status < iocb->iters[i].count)) force_done = true; /* Partial write */ @@ -857,7 +858,6 @@ static void nfs_local_call_write(struct work_struct *work) } file_end_write(filp); - revert_creds(save_cred); current->flags = old_flags; } From dc554c8fb361f13580da3f5a98ad8b494a788666 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Sun, 11 Jan 2026 15:26:20 +0100 Subject: [PATCH 1766/2333] Linux 6.18.5 Link: https://lore.kernel.org/r/20260109111950.344681501@linuxfoundation.org Tested-by: Ronald Warsow Tested-by: Slade Watkins Tested-by: Achill Gilgenast = Tested-by: Jon Hunter Tested-by: Brett A C Sheffield Tested-by: Brett Mastbergen Tested-by: Florian Fainelli Tested-by: Shuah Khan Tested-by: Peter Schneider Tested-by: Takeshi Ogasawara Tested-by: Ron Economos Tested-by: Salvatore Bonaccorso Tested-by: Jeffrin Jose T Tested-by: Mark Brown Tested-by: Miguel Ojeda Signed-off-by: Greg Kroah-Hartman --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 7b431af09b322..30c332829b0fc 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 VERSION = 6 PATCHLEVEL = 18 -SUBLEVEL = 4 +SUBLEVEL = 5 EXTRAVERSION = NAME = Baby Opossum Posse From abf62a55166853845d52deec5b4ec3577931a64d Mon Sep 17 00:00:00 2001 From: Raviteja Laggyshetty Date: Tue, 19 Aug 2025 11:24:47 +0000 Subject: [PATCH 1767/2333] BACKPORT: FROM GIT: arm64: dts: qcom: qcs615: Add OSM l3 interconnect provider node and CPU OPP tables to scale DDR/L3 Add Operation State Manager (OSM) L3 interconnect provide node and OPP tables required to scale DDR and L3 per freq-domain on QCS615 SoC. As QCS615 and SM8150 SoCs have same OSM hardware, added SM8150 compatible as fallback for QCS615 OSM device node. Signed-off-by: Imran Shaik Signed-off-by: Raviteja Laggyshetty Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20250819-talos-l3-icc-v3-2-04529e85dac7@oss.qualcomm.com --- arch/arm64/boot/dts/qcom/talos.dtsi | 148 ++++++++++++++++++++++++++++ 1 file changed, 148 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/talos.dtsi b/arch/arm64/boot/dts/qcom/talos.dtsi index eff8f9f78c6f5..b8fee8dd962dd 100644 --- a/arch/arm64/boot/dts/qcom/talos.dtsi +++ b/arch/arm64/boot/dts/qcom/talos.dtsi @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -41,6 +42,10 @@ clocks = <&cpufreq_hw 0>; qcom,freq-domain = <&cpufreq_hw 0>; #cooling-cells = <2>; + operating-points-v2 = <&cpu0_opp_table>; + interconnects = <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ACTIVE_ONLY + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ACTIVE_ONLY>, + <&osm_l3 MASTER_OSM_L3_APPS &osm_l3 SLAVE_OSM_L3>; l2_0: l2-cache { compatible = "cache"; @@ -62,6 +67,10 @@ next-level-cache = <&l2_100>; clocks = <&cpufreq_hw 0>; qcom,freq-domain = <&cpufreq_hw 0>; + operating-points-v2 = <&cpu0_opp_table>; + interconnects = <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ACTIVE_ONLY + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ACTIVE_ONLY>, + <&osm_l3 MASTER_OSM_L3_APPS &osm_l3 SLAVE_OSM_L3>; l2_100: l2-cache { compatible = "cache"; @@ -83,6 +92,10 @@ next-level-cache = <&l2_200>; clocks = <&cpufreq_hw 0>; qcom,freq-domain = <&cpufreq_hw 0>; + operating-points-v2 = <&cpu0_opp_table>; + interconnects = <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ACTIVE_ONLY + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ACTIVE_ONLY>, + <&osm_l3 MASTER_OSM_L3_APPS &osm_l3 SLAVE_OSM_L3>; l2_200: l2-cache { compatible = "cache"; @@ -104,6 +117,10 @@ next-level-cache = <&l2_300>; clocks = <&cpufreq_hw 0>; qcom,freq-domain = <&cpufreq_hw 0>; + operating-points-v2 = <&cpu0_opp_table>; + interconnects = <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ACTIVE_ONLY + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ACTIVE_ONLY>, + <&osm_l3 MASTER_OSM_L3_APPS &osm_l3 SLAVE_OSM_L3>; l2_300: l2-cache { compatible = "cache"; @@ -125,6 +142,10 @@ next-level-cache = <&l2_400>; clocks = <&cpufreq_hw 0>; qcom,freq-domain = <&cpufreq_hw 0>; + operating-points-v2 = <&cpu0_opp_table>; + interconnects = <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ACTIVE_ONLY + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ACTIVE_ONLY>, + <&osm_l3 MASTER_OSM_L3_APPS &osm_l3 SLAVE_OSM_L3>; l2_400: l2-cache { compatible = "cache"; @@ -146,6 +167,10 @@ next-level-cache = <&l2_500>; clocks = <&cpufreq_hw 0>; qcom,freq-domain = <&cpufreq_hw 0>; + operating-points-v2 = <&cpu0_opp_table>; + interconnects = <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ACTIVE_ONLY + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ACTIVE_ONLY>, + <&osm_l3 MASTER_OSM_L3_APPS &osm_l3 SLAVE_OSM_L3>; l2_500: l2-cache { compatible = "cache"; @@ -168,6 +193,10 @@ clocks = <&cpufreq_hw 1>; qcom,freq-domain = <&cpufreq_hw 1>; #cooling-cells = <2>; + operating-points-v2 = <&cpu6_opp_table>; + interconnects = <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ACTIVE_ONLY + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ACTIVE_ONLY>, + <&osm_l3 MASTER_OSM_L3_APPS &osm_l3 SLAVE_OSM_L3>; l2_600: l2-cache { compatible = "cache"; @@ -189,6 +218,10 @@ next-level-cache = <&l2_700>; clocks = <&cpufreq_hw 1>; qcom,freq-domain = <&cpufreq_hw 1>; + operating-points-v2 = <&cpu6_opp_table>; + interconnects = <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ACTIVE_ONLY + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ACTIVE_ONLY>, + <&osm_l3 MASTER_OSM_L3_APPS &osm_l3 SLAVE_OSM_L3>; l2_700: l2-cache { compatible = "cache"; @@ -241,6 +274,111 @@ }; }; + cpu0_opp_table: opp-table-cpu0 { + compatible = "operating-points-v2"; + opp-shared; + + opp-300000000 { + opp-hz = /bits/ 64 <300000000>; + opp-peak-kBps = <(300000 * 4) (300000 * 16)>; + }; + + opp-576000000 { + opp-hz = /bits/ 64 <576000000>; + opp-peak-kBps = <(300000 * 4) (576000 * 16)>; + }; + + opp-748800000 { + opp-hz = /bits/ 64 <748800000>; + opp-peak-kBps = <(300000 * 4) (576000 * 16)>; + }; + + opp-998400000 { + opp-hz = /bits/ 64 <998400000>; + opp-peak-kBps = <(451000 * 4) (806400 * 16)>; + }; + + opp-1209600000 { + opp-hz = /bits/ 64 <1209600000>; + opp-peak-kBps = <(547000 * 4) (1017600 * 16)>; + }; + + opp-1363200000 { + opp-hz = /bits/ 64 <1363200000>; + opp-peak-kBps = <(768000 * 4) (1209600 * 16)>; + }; + + opp-1516800000 { + opp-hz = /bits/ 64 <1516800000>; + opp-peak-kBps = <(768000 * 4) (1209600 * 16)>; + }; + + opp-1593600000 { + opp-hz = /bits/ 64 <1593600000>; + opp-peak-kBps = <(1017000 * 4) (1363200 * 16)>; + }; + }; + + cpu6_opp_table: opp-table-cpu6 { + compatible = "operating-points-v2"; + opp-shared; + + opp-300000000 { + opp-hz = /bits/ 64 <300000000>; + opp-peak-kBps = <(451000 * 4) (300000 * 16)>; + }; + + opp-652800000 { + opp-hz = /bits/ 64 <652800000>; + opp-peak-kBps = <(451000 * 4) (576000 * 16)>; + }; + + opp-768000000 { + opp-hz = /bits/ 64 <768000000>; + opp-peak-kBps = <(451000 * 4) (576000 * 16)>; + }; + + opp-979200000 { + opp-hz = /bits/ 64 <979200000>; + opp-peak-kBps = <(547000 * 4) (806400 * 16)>; + }; + + opp-1017600000 { + opp-hz = /bits/ 64 <1017600000>; + opp-peak-kBps = <(547000 * 4) (806400 * 16)>; + }; + + opp-1094400000 { + opp-hz = /bits/ 64 <109440000>; + opp-peak-kBps = <(1017600 * 4) (940800 * 16)>; + }; + + opp-1209600000 { + opp-hz = /bits/ 64 <1209600000>; + opp-peak-kBps = <(1017600 * 4) (1017600 * 16)>; + }; + + opp-1363200000 { + opp-hz = /bits/ 64 <1363200000>; + opp-peak-kBps = <(1555000 * 4) (1209600 * 16)>; + }; + + opp-1516800000 { + opp-hz = /bits/ 64 <1516800000>; + opp-peak-kBps = <(1555000 * 4) (1209600 * 16)>; + }; + + opp-1708800000 { + opp-hz = /bits/ 64 <1708800000>; + opp-peak-kBps = <(1555000 * 4) (1363200 * 16)>; + }; + + opp-1900800000 { + opp-hz = /bits/ 64 <1900800000>; + opp-peak-kBps = <(1555000 * 4) (1363200 * 16)>; + }; + }; + dummy_eud: dummy-sink { compatible = "arm,coresight-dummy-sink"; @@ -4240,6 +4378,16 @@ }; }; + osm_l3: interconnect@18321000 { + compatible = "qcom,qcs615-osm-l3", "qcom,sm8150-osm-l3", "qcom,osm-l3"; + reg = <0x0 0x18321000 0x0 0x1400>; + + clocks = <&rpmhcc RPMH_CXO_CLK>, <&gcc GPLL0>; + clock-names = "xo", "alternate"; + + #interconnect-cells = <1>; + }; + usb_1_hsphy: phy@88e2000 { compatible = "qcom,qcs615-qusb2-phy"; reg = <0x0 0x88e2000 0x0 0x180>; From a339b0168251e4d7fa84725b77f4a46f77f70472 Mon Sep 17 00:00:00 2001 From: Scott Mayhew Date: Thu, 11 Dec 2025 07:34:34 -0500 Subject: [PATCH 1768/2333] NFSD: Fix permission check for read access to executable-only files commit e901c7fce59e72d9f3c92733c379849c4034ac50 upstream. Commit abc02e5602f7 ("NFSD: Support write delegations in LAYOUTGET") added NFSD_MAY_OWNER_OVERRIDE to the access flags passed from nfsd4_layoutget() to fh_verify(). This causes LAYOUTGET to fail for executable-only files, and causes xfstests generic/126 to fail on pNFS SCSI. To allow read access to executable-only files, what we really want is: 1. The "permissions" portion of the access flags (the lower 6 bits) must be exactly NFSD_MAY_READ 2. The "hints" portion of the access flags (the upper 26 bits) can contain any combination of NFSD_MAY_OWNER_OVERRIDE and NFSD_MAY_READ_IF_EXEC Fixes: abc02e5602f7 ("NFSD: Support write delegations in LAYOUTGET") Cc: stable@vger.kernel.org # v6.6+ Signed-off-by: Scott Mayhew Reviewed-by: Jeff Layton Reviewed-by: NeilBrown Signed-off-by: Chuck Lever Signed-off-by: Greg Kroah-Hartman --- fs/nfsd/vfs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 9f0b8bbc41442..e32a5fcd6ac85 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -2683,8 +2683,8 @@ nfsd_permission(struct svc_cred *cred, struct svc_export *exp, /* Allow read access to binaries even when mode 111 */ if (err == -EACCES && S_ISREG(inode->i_mode) && - (acc == (NFSD_MAY_READ | NFSD_MAY_OWNER_OVERRIDE) || - acc == (NFSD_MAY_READ | NFSD_MAY_READ_IF_EXEC))) + (((acc & NFSD_MAY_MASK) == NFSD_MAY_READ) && + (acc & (NFSD_MAY_OWNER_OVERRIDE | NFSD_MAY_READ_IF_EXEC)))) err = inode_permission(&nop_mnt_idmap, inode, MAY_EXEC); return err? nfserrno(err) : 0; From 53f07d095e7e680c5e4569a55a019f2c0348cdc6 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Sat, 13 Dec 2025 13:41:59 -0500 Subject: [PATCH 1769/2333] nfsd: provide locking for v4_end_grace commit 2857bd59feb63fcf40fe4baf55401baea6b4feb4 upstream. Writing to v4_end_grace can race with server shutdown and result in memory being accessed after it was freed - reclaim_str_hashtbl in particularly. We cannot hold nfsd_mutex across the nfsd4_end_grace() call as that is held while client_tracking_op->init() is called and that can wait for an upcall to nfsdcltrack which can write to v4_end_grace, resulting in a deadlock. nfsd4_end_grace() is also called by the landromat work queue and this doesn't require locking as server shutdown will stop the work and wait for it before freeing anything that nfsd4_end_grace() might access. However, we must be sure that writing to v4_end_grace doesn't restart the work item after shutdown has already waited for it. For this we add a new flag protected with nn->client_lock. It is set only while it is safe to make client tracking calls, and v4_end_grace only schedules work while the flag is set with the spinlock held. So this patch adds a nfsd_net field "client_tracking_active" which is set as described. Another field "grace_end_forced", is set when v4_end_grace is written. After this is set, and providing client_tracking_active is set, the laundromat is scheduled. This "grace_end_forced" field bypasses other checks for whether the grace period has finished. This resolves a race which can result in use-after-free. Reported-by: Li Lingfeng Closes: https://lore.kernel.org/linux-nfs/20250623030015.2353515-1-neil@brown.name/T/#t Fixes: 7f5ef2e900d9 ("nfsd: add a v4_end_grace file to /proc/fs/nfsd") Cc: stable@vger.kernel.org Signed-off-by: NeilBrown Tested-by: Li Lingfeng Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever Signed-off-by: Greg Kroah-Hartman --- fs/nfsd/netns.h | 2 ++ fs/nfsd/nfs4state.c | 42 ++++++++++++++++++++++++++++++++++++++++-- fs/nfsd/nfsctl.c | 3 +-- fs/nfsd/state.h | 2 +- 4 files changed, 44 insertions(+), 5 deletions(-) diff --git a/fs/nfsd/netns.h b/fs/nfsd/netns.h index 3e2d0fde80a7c..fe8338735e7cc 100644 --- a/fs/nfsd/netns.h +++ b/fs/nfsd/netns.h @@ -66,6 +66,8 @@ struct nfsd_net { struct lock_manager nfsd4_manager; bool grace_ended; + bool grace_end_forced; + bool client_tracking_active; time64_t boot_time; struct dentry *nfsd_client_dir; diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index bdd20fddbb986..70b5c478541b6 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -84,7 +84,7 @@ static u64 current_sessionid = 1; /* forward declarations */ static bool check_for_locks(struct nfs4_file *fp, struct nfs4_lockowner *lowner); static void nfs4_free_ol_stateid(struct nfs4_stid *stid); -void nfsd4_end_grace(struct nfsd_net *nn); +static void nfsd4_end_grace(struct nfsd_net *nn); static void _free_cpntf_state_locked(struct nfsd_net *nn, struct nfs4_cpntf_state *cps); static void nfsd4_file_hash_remove(struct nfs4_file *fi); static void deleg_reaper(struct nfsd_net *nn); @@ -6597,7 +6597,7 @@ nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, return nfs_ok; } -void +static void nfsd4_end_grace(struct nfsd_net *nn) { /* do nothing if grace period already ended */ @@ -6630,6 +6630,33 @@ nfsd4_end_grace(struct nfsd_net *nn) */ } +/** + * nfsd4_force_end_grace - forcibly end the NFSv4 grace period + * @nn: network namespace for the server instance to be updated + * + * Forces bypass of normal grace period completion, then schedules + * the laundromat to end the grace period immediately. Does not wait + * for the grace period to fully terminate before returning. + * + * Return values: + * %true: Grace termination schedule + * %false: No action was taken + */ +bool nfsd4_force_end_grace(struct nfsd_net *nn) +{ + if (!nn->client_tracking_ops) + return false; + spin_lock(&nn->client_lock); + if (nn->grace_ended || !nn->client_tracking_active) { + spin_unlock(&nn->client_lock); + return false; + } + WRITE_ONCE(nn->grace_end_forced, true); + mod_delayed_work(laundry_wq, &nn->laundromat_work, 0); + spin_unlock(&nn->client_lock); + return true; +} + /* * If we've waited a lease period but there are still clients trying to * reclaim, wait a little longer to give them a chance to finish. @@ -6639,6 +6666,8 @@ static bool clients_still_reclaiming(struct nfsd_net *nn) time64_t double_grace_period_end = nn->boot_time + 2 * nn->nfsd4_lease; + if (READ_ONCE(nn->grace_end_forced)) + return false; if (nn->track_reclaim_completes && atomic_read(&nn->nr_reclaim_complete) == nn->reclaim_str_hashtbl_size) @@ -8942,6 +8971,8 @@ static int nfs4_state_create_net(struct net *net) nn->unconf_name_tree = RB_ROOT; nn->boot_time = ktime_get_real_seconds(); nn->grace_ended = false; + nn->grace_end_forced = false; + nn->client_tracking_active = false; nn->nfsd4_manager.block_opens = true; INIT_LIST_HEAD(&nn->nfsd4_manager.list); INIT_LIST_HEAD(&nn->client_lru); @@ -9022,6 +9053,10 @@ nfs4_state_start_net(struct net *net) return ret; locks_start_grace(net, &nn->nfsd4_manager); nfsd4_client_tracking_init(net); + /* safe for laundromat to run now */ + spin_lock(&nn->client_lock); + nn->client_tracking_active = true; + spin_unlock(&nn->client_lock); if (nn->track_reclaim_completes && nn->reclaim_str_hashtbl_size == 0) goto skip_grace; printk(KERN_INFO "NFSD: starting %lld-second grace period (net %x)\n", @@ -9070,6 +9105,9 @@ nfs4_state_shutdown_net(struct net *net) shrinker_free(nn->nfsd_client_shrinker); cancel_work_sync(&nn->nfsd_shrinker_work); + spin_lock(&nn->client_lock); + nn->client_tracking_active = false; + spin_unlock(&nn->client_lock); cancel_delayed_work_sync(&nn->laundromat_work); locks_end_grace(&nn->nfsd4_manager); diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index 2b79129703d54..36ce3ca97d978 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c @@ -1082,10 +1082,9 @@ static ssize_t write_v4_end_grace(struct file *file, char *buf, size_t size) case 'Y': case 'y': case '1': - if (!nn->nfsd_serv) + if (!nfsd4_force_end_grace(nn)) return -EBUSY; trace_nfsd_end_grace(netns(file)); - nfsd4_end_grace(nn); break; default: return -EINVAL; diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index 1e736f4024263..50d2b29633903 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h @@ -849,7 +849,7 @@ static inline void nfsd4_revoke_states(struct net *net, struct super_block *sb) #endif /* grace period management */ -void nfsd4_end_grace(struct nfsd_net *nn); +bool nfsd4_force_end_grace(struct nfsd_net *nn); /* nfs4recover operations */ extern int nfsd4_client_tracking_init(struct net *net); From 099a880ef541ea599c16e7957b51675b7676b062 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 15 Dec 2025 08:07:28 +1100 Subject: [PATCH 1770/2333] nfsd: use correct loop termination in nfsd4_revoke_states() commit fb321998de7639f1954430674475e469fb529d9c upstream. The loop in nfsd4_revoke_states() stops one too early because the end value given is CLIENT_HASH_MASK where it should be CLIENT_HASH_SIZE. This means that an admin request to drop all locks for a filesystem will miss locks held by clients which hash to the maximum possible hash value. Fixes: 1ac3629bf012 ("nfsd: prepare for supporting admin-revocation of state") Cc: stable@vger.kernel.org Signed-off-by: NeilBrown Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever Signed-off-by: Greg Kroah-Hartman --- fs/nfsd/nfs4state.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 70b5c478541b6..ae39e563c2641 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -1780,7 +1780,7 @@ void nfsd4_revoke_states(struct net *net, struct super_block *sb) sc_types = SC_TYPE_OPEN | SC_TYPE_LOCK | SC_TYPE_DELEG | SC_TYPE_LAYOUT; spin_lock(&nn->client_lock); - for (idhashval = 0; idhashval < CLIENT_HASH_MASK; idhashval++) { + for (idhashval = 0; idhashval < CLIENT_HASH_SIZE; idhashval++) { struct list_head *head = &nn->conf_id_hashtbl[idhashval]; struct nfs4_client *clp; retry: From e06c9f6c0f554148d4921c2a15bd054260a054ac Mon Sep 17 00:00:00 2001 From: Olga Kornievskaia Date: Mon, 15 Dec 2025 14:10:36 -0500 Subject: [PATCH 1771/2333] nfsd: check that server is running in unlock_filesystem commit d0424066fcd294977f310964bed6f2a487fa4515 upstream. If we are trying to unlock the filesystem via an administrative interface and nfsd isn't running, it crashes the server. This happens currently because nfsd4_revoke_states() access state structures (eg., conf_id_hashtbl) that has been freed as a part of the server shutdown. [ 59.465072] Call trace: [ 59.465308] nfsd4_revoke_states+0x1b4/0x898 [nfsd] (P) [ 59.465830] write_unlock_fs+0x258/0x440 [nfsd] [ 59.466278] nfsctl_transaction_write+0xb0/0x120 [nfsd] [ 59.466780] vfs_write+0x1f0/0x938 [ 59.467088] ksys_write+0xfc/0x1f8 [ 59.467395] __arm64_sys_write+0x74/0xb8 [ 59.467746] invoke_syscall.constprop.0+0xdc/0x1e8 [ 59.468177] do_el0_svc+0x154/0x1d8 [ 59.468489] el0_svc+0x40/0xe0 [ 59.468767] el0t_64_sync_handler+0xa0/0xe8 [ 59.469138] el0t_64_sync+0x1ac/0x1b0 Ensure this can't happen by taking the nfsd_mutex and checking that the server is still up, and then holding the mutex across the call to nfsd4_revoke_states(). Reviewed-by: NeilBrown Reviewed-by: Jeff Layton Fixes: 1ac3629bf0125 ("nfsd: prepare for supporting admin-revocation of state") Cc: stable@vger.kernel.org Signed-off-by: Olga Kornievskaia Signed-off-by: Chuck Lever Signed-off-by: Greg Kroah-Hartman --- fs/nfsd/nfs4state.c | 5 ++--- fs/nfsd/nfsctl.c | 9 ++++++++- fs/nfsd/state.h | 4 ++-- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index ae39e563c2641..740c40eb5b366 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -1759,7 +1759,7 @@ static struct nfs4_stid *find_one_sb_stid(struct nfs4_client *clp, /** * nfsd4_revoke_states - revoke all nfsv4 states associated with given filesystem - * @net: used to identify instance of nfsd (there is one per net namespace) + * @nn: used to identify instance of nfsd (there is one per net namespace) * @sb: super_block used to identify target filesystem * * All nfs4 states (open, lock, delegation, layout) held by the server instance @@ -1771,9 +1771,8 @@ static struct nfs4_stid *find_one_sb_stid(struct nfs4_client *clp, * The clients which own the states will subsequently being notified that the * states have been "admin-revoked". */ -void nfsd4_revoke_states(struct net *net, struct super_block *sb) +void nfsd4_revoke_states(struct nfsd_net *nn, struct super_block *sb) { - struct nfsd_net *nn = net_generic(net, nfsd_net_id); unsigned int idhashval; unsigned int sc_types; diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index 36ce3ca97d978..8cbfb9dc3abb7 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c @@ -259,6 +259,7 @@ static ssize_t write_unlock_fs(struct file *file, char *buf, size_t size) struct path path; char *fo_path; int error; + struct nfsd_net *nn; /* sanity check */ if (size == 0) @@ -285,7 +286,13 @@ static ssize_t write_unlock_fs(struct file *file, char *buf, size_t size) * 3. Is that directory the root of an exported file system? */ error = nlmsvc_unlock_all_by_sb(path.dentry->d_sb); - nfsd4_revoke_states(netns(file), path.dentry->d_sb); + mutex_lock(&nfsd_mutex); + nn = net_generic(netns(file), nfsd_net_id); + if (nn->nfsd_serv) + nfsd4_revoke_states(nn, path.dentry->d_sb); + else + error = -EINVAL; + mutex_unlock(&nfsd_mutex); path_put(&path); return error; diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index 50d2b29633903..c75bf3abec40a 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h @@ -841,9 +841,9 @@ static inline void get_nfs4_file(struct nfs4_file *fi) struct nfsd_file *find_any_file(struct nfs4_file *f); #ifdef CONFIG_NFSD_V4 -void nfsd4_revoke_states(struct net *net, struct super_block *sb); +void nfsd4_revoke_states(struct nfsd_net *nn, struct super_block *sb); #else -static inline void nfsd4_revoke_states(struct net *net, struct super_block *sb) +static inline void nfsd4_revoke_states(struct nfsd_net *nn, struct super_block *sb) { } #endif From db78fa4b9f1fbedcb979b5d0c486d4f451ee7799 Mon Sep 17 00:00:00 2001 From: Edward Adam Davis Date: Tue, 16 Dec 2025 18:27:37 +0800 Subject: [PATCH 1772/2333] NFSD: net ref data still needs to be freed even if net hasn't startup commit 0b88bfa42e5468baff71909c2f324a495318532b upstream. When the NFSD instance doesn't to startup, the net ref data memory is not properly reclaimed, which triggers the memory leak issue reported by syzbot [1]. To avoid the problem reported in [1], the net ref data memory reclamation action is moved outside of nfsd_net_up when the net is shutdown. [1] unreferenced object 0xffff88812a39dfc0 (size 64): backtrace (crc a2262fc6): percpu_ref_init+0x94/0x1e0 lib/percpu-refcount.c:76 nfsd_create_serv+0xbe/0x260 fs/nfsd/nfssvc.c:605 nfsd_nl_listener_set_doit+0x62/0xb00 fs/nfsd/nfsctl.c:1882 genl_family_rcv_msg_doit+0x11e/0x190 net/netlink/genetlink.c:1115 genl_family_rcv_msg net/netlink/genetlink.c:1195 [inline] genl_rcv_msg+0x2fd/0x440 net/netlink/genetlink.c:1210 BUG: memory leak Reported-by: syzbot+6ee3b889bdeada0a6226@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=6ee3b889bdeada0a6226 Fixes: 39972494e318 ("nfsd: update percpu_ref to manage references on nfsd_net") Cc: stable@vger.kernel.org Signed-off-by: Edward Adam Davis Signed-off-by: Chuck Lever Signed-off-by: Greg Kroah-Hartman --- fs/nfsd/nfssvc.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 32cc03a7e7bec..fcb47f344e32f 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -424,26 +424,26 @@ static void nfsd_shutdown_net(struct net *net) { struct nfsd_net *nn = net_generic(net, nfsd_net_id); - if (!nn->nfsd_net_up) - return; - - percpu_ref_kill_and_confirm(&nn->nfsd_net_ref, nfsd_net_done); - wait_for_completion(&nn->nfsd_net_confirm_done); - - nfsd_export_flush(net); - nfs4_state_shutdown_net(net); - nfsd_reply_cache_shutdown(nn); - nfsd_file_cache_shutdown_net(net); - if (nn->lockd_up) { - lockd_down(net); - nn->lockd_up = false; + if (nn->nfsd_net_up) { + percpu_ref_kill_and_confirm(&nn->nfsd_net_ref, nfsd_net_done); + wait_for_completion(&nn->nfsd_net_confirm_done); + + nfsd_export_flush(net); + nfs4_state_shutdown_net(net); + nfsd_reply_cache_shutdown(nn); + nfsd_file_cache_shutdown_net(net); + if (nn->lockd_up) { + lockd_down(net); + nn->lockd_up = false; + } + wait_for_completion(&nn->nfsd_net_free_done); } - wait_for_completion(&nn->nfsd_net_free_done); percpu_ref_exit(&nn->nfsd_net_ref); + if (nn->nfsd_net_up) + nfsd_shutdown_generic(); nn->nfsd_net_up = false; - nfsd_shutdown_generic(); } static DEFINE_SPINLOCK(nfsd_notifier_lock); From 0f7fb819d63f3339c1a4eaf81d9edc28c34fca2b Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Tue, 9 Dec 2025 19:28:49 -0500 Subject: [PATCH 1773/2333] NFSD: Remove NFSERR_EAGAIN commit c6c209ceb87f64a6ceebe61761951dcbbf4a0baa upstream. I haven't found an NFSERR_EAGAIN in RFCs 1094, 1813, 7530, or 8881. None of these RFCs have an NFS status code that match the numeric value "11". Based on the meaning of the EAGAIN errno, I presume the use of this status in NFSD means NFS4ERR_DELAY. So replace the one usage of nfserr_eagain, and remove it from NFSD's NFS status conversion tables. As far as I can tell, NFSERR_EAGAIN has existed since the pre-git era, but was not actually used by any code until commit f4e44b393389 ("NFSD: delay unmount source's export after inter-server copy completed."), at which time it become possible for NFSD to return a status code of 11 (which is not valid NFS protocol). Fixes: f4e44b393389 ("NFSD: delay unmount source's export after inter-server copy completed.") Cc: stable@vger.kernel.org Reviewed-by: NeilBrown Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever Signed-off-by: Greg Kroah-Hartman --- fs/nfs_common/common.c | 1 - fs/nfsd/nfs4proc.c | 2 +- fs/nfsd/nfsd.h | 1 - include/trace/misc/nfs.h | 2 -- include/uapi/linux/nfs.h | 1 - 5 files changed, 1 insertion(+), 6 deletions(-) diff --git a/fs/nfs_common/common.c b/fs/nfs_common/common.c index af09aed09fd27..0778743ae2c2c 100644 --- a/fs/nfs_common/common.c +++ b/fs/nfs_common/common.c @@ -17,7 +17,6 @@ static const struct { { NFSERR_NOENT, -ENOENT }, { NFSERR_IO, -EIO }, { NFSERR_NXIO, -ENXIO }, -/* { NFSERR_EAGAIN, -EAGAIN }, */ { NFSERR_ACCES, -EACCES }, { NFSERR_EXIST, -EEXIST }, { NFSERR_XDEV, -EXDEV }, diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 7f7e6bb23a90d..42a6b914c0fe6 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -1506,7 +1506,7 @@ static __be32 nfsd4_ssc_setup_dul(struct nfsd_net *nn, char *ipaddr, (schedule_timeout(20*HZ) == 0)) { finish_wait(&nn->nfsd_ssc_waitq, &wait); kfree(work); - return nfserr_eagain; + return nfserr_jukebox; } finish_wait(&nn->nfsd_ssc_waitq, &wait); goto try_again; diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h index 191cbf9320c0f..8cecccdaf9ee5 100644 --- a/fs/nfsd/nfsd.h +++ b/fs/nfsd/nfsd.h @@ -232,7 +232,6 @@ void nfsd_lockd_shutdown(void); #define nfserr_noent cpu_to_be32(NFSERR_NOENT) #define nfserr_io cpu_to_be32(NFSERR_IO) #define nfserr_nxio cpu_to_be32(NFSERR_NXIO) -#define nfserr_eagain cpu_to_be32(NFSERR_EAGAIN) #define nfserr_acces cpu_to_be32(NFSERR_ACCES) #define nfserr_exist cpu_to_be32(NFSERR_EXIST) #define nfserr_xdev cpu_to_be32(NFSERR_XDEV) diff --git a/include/trace/misc/nfs.h b/include/trace/misc/nfs.h index c82233e950ac0..a394b4d38e18f 100644 --- a/include/trace/misc/nfs.h +++ b/include/trace/misc/nfs.h @@ -16,7 +16,6 @@ TRACE_DEFINE_ENUM(NFSERR_PERM); TRACE_DEFINE_ENUM(NFSERR_NOENT); TRACE_DEFINE_ENUM(NFSERR_IO); TRACE_DEFINE_ENUM(NFSERR_NXIO); -TRACE_DEFINE_ENUM(NFSERR_EAGAIN); TRACE_DEFINE_ENUM(NFSERR_ACCES); TRACE_DEFINE_ENUM(NFSERR_EXIST); TRACE_DEFINE_ENUM(NFSERR_XDEV); @@ -52,7 +51,6 @@ TRACE_DEFINE_ENUM(NFSERR_JUKEBOX); { NFSERR_NXIO, "NXIO" }, \ { ECHILD, "CHILD" }, \ { ETIMEDOUT, "TIMEDOUT" }, \ - { NFSERR_EAGAIN, "AGAIN" }, \ { NFSERR_ACCES, "ACCES" }, \ { NFSERR_EXIST, "EXIST" }, \ { NFSERR_XDEV, "XDEV" }, \ diff --git a/include/uapi/linux/nfs.h b/include/uapi/linux/nfs.h index f356f2ba38142..71c7196d32817 100644 --- a/include/uapi/linux/nfs.h +++ b/include/uapi/linux/nfs.h @@ -49,7 +49,6 @@ NFSERR_NOENT = 2, /* v2 v3 v4 */ NFSERR_IO = 5, /* v2 v3 v4 */ NFSERR_NXIO = 6, /* v2 v3 v4 */ - NFSERR_EAGAIN = 11, /* v2 v3 */ NFSERR_ACCES = 13, /* v2 v3 v4 */ NFSERR_EXIST = 17, /* v2 v3 v4 */ NFSERR_XDEV = 18, /* v3 v4 */ From 4ae815bfcfadeb173b47a1de62ca00d36c815460 Mon Sep 17 00:00:00 2001 From: Thomas Fourier Date: Wed, 7 Jan 2026 10:01:36 +0100 Subject: [PATCH 1774/2333] atm: Fix dma_free_coherent() size commit 4d984b0574ff708e66152763fbfdef24ea40933f upstream. The size of the buffer is not the same when alloc'd with dma_alloc_coherent() in he_init_tpdrq() and freed. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Cc: Signed-off-by: Thomas Fourier Link: https://patch.msgid.link/20260107090141.80900-2-fourier.thomas@gmail.com Signed-off-by: Jakub Kicinski Signed-off-by: Greg Kroah-Hartman --- drivers/atm/he.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/atm/he.c b/drivers/atm/he.c index ad91cc6a34fc5..92a041d5387bd 100644 --- a/drivers/atm/he.c +++ b/drivers/atm/he.c @@ -1587,7 +1587,8 @@ he_stop(struct he_dev *he_dev) he_dev->tbrq_base, he_dev->tbrq_phys); if (he_dev->tpdrq_base) - dma_free_coherent(&he_dev->pci_dev->dev, CONFIG_TBRQ_SIZE * sizeof(struct he_tbrq), + dma_free_coherent(&he_dev->pci_dev->dev, + CONFIG_TPDRQ_SIZE * sizeof(struct he_tpdrq), he_dev->tpdrq_base, he_dev->tpdrq_phys); dma_pool_destroy(he_dev->tpd_pool); From d82796a57cc0dac1dbef19d913c8f02a8cc7b1a7 Mon Sep 17 00:00:00 2001 From: Thomas Fourier Date: Tue, 6 Jan 2026 10:47:21 +0100 Subject: [PATCH 1775/2333] net: 3com: 3c59x: fix possible null dereference in vortex_probe1() commit a4e305ed60f7c41bbf9aabc16dd75267194e0de3 upstream. pdev can be null and free_ring: can be called in 1297 with a null pdev. Fixes: 55c82617c3e8 ("3c59x: convert to generic DMA API") Cc: Signed-off-by: Thomas Fourier Link: https://patch.msgid.link/20260106094731.25819-2-fourier.thomas@gmail.com Signed-off-by: Jakub Kicinski Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/3com/3c59x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/3com/3c59x.c b/drivers/net/ethernet/3com/3c59x.c index 8c9cc97efd4ee..4fe4efdb3737f 100644 --- a/drivers/net/ethernet/3com/3c59x.c +++ b/drivers/net/ethernet/3com/3c59x.c @@ -1473,7 +1473,7 @@ static int vortex_probe1(struct device *gendev, void __iomem *ioaddr, int irq, return 0; free_ring: - dma_free_coherent(&pdev->dev, + dma_free_coherent(gendev, sizeof(struct boom_rx_desc) * RX_RING_SIZE + sizeof(struct boom_tx_desc) * TX_RING_SIZE, vp->rx_ring, vp->rx_ring_dma); From ffa2be496ef65055b28b39c6bd9a7d66943ee89a Mon Sep 17 00:00:00 2001 From: Willem de Bruijn Date: Tue, 6 Jan 2026 10:05:46 -0500 Subject: [PATCH 1776/2333] net: do not write to msg_get_inq in callee commit 7d11e047eda5f98514ae62507065ac961981c025 upstream. NULL pointer dereference fix. msg_get_inq is an input field from caller to callee. Don't set it in the callee, as the caller may not clear it on struct reuse. This is a kernel-internal variant of msghdr only, and the only user does reinitialize the field. So this is not critical for that reason. But it is more robust to avoid the write, and slightly simpler code. And it fixes a bug, see below. Callers set msg_get_inq to request the input queue length to be returned in msg_inq. This is equivalent to but independent from the SO_INQ request to return that same info as a cmsg (tp->recvmsg_inq). To reduce branching in the hot path the second also sets the msg_inq. That is WAI. This is a fix to commit 4d1442979e4a ("af_unix: don't post cmsg for SO_INQ unless explicitly asked for"), which fixed the inverse. Also avoid NULL pointer dereference in unix_stream_read_generic if state->msg is NULL and msg->msg_get_inq is written. A NULL state->msg can happen when splicing as of commit 2b514574f7e8 ("net: af_unix: implement splice for stream af_unix sockets"). Also collapse two branches using a bitwise or. Cc: stable@vger.kernel.org Fixes: 4d1442979e4a ("af_unix: don't post cmsg for SO_INQ unless explicitly asked for") Link: https://lore.kernel.org/netdev/willemdebruijn.kernel.24d8030f7a3de@gmail.com/ Signed-off-by: Willem de Bruijn Reviewed-by: Jens Axboe Reviewed-by: Eric Dumazet Reviewed-by: Kuniyuki Iwashima Link: https://patch.msgid.link/20260106150626.3944363-1-willemdebruijn.kernel@gmail.com Signed-off-by: Jakub Kicinski Signed-off-by: Greg Kroah-Hartman --- net/ipv4/tcp.c | 8 +++----- net/unix/af_unix.c | 8 +++----- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 8a18aeca7ab07..74079eab89804 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -2651,10 +2651,8 @@ static int tcp_recvmsg_locked(struct sock *sk, struct msghdr *msg, size_t len, if (sk->sk_state == TCP_LISTEN) goto out; - if (tp->recvmsg_inq) { + if (tp->recvmsg_inq) *cmsg_flags = TCP_CMSG_INQ; - msg->msg_get_inq = 1; - } timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT); /* Urgent data needs to be handled specially. */ @@ -2928,10 +2926,10 @@ int tcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int flags, ret = tcp_recvmsg_locked(sk, msg, len, flags, &tss, &cmsg_flags); release_sock(sk); - if ((cmsg_flags || msg->msg_get_inq) && ret >= 0) { + if ((cmsg_flags | msg->msg_get_inq) && ret >= 0) { if (cmsg_flags & TCP_CMSG_TS) tcp_recv_timestamp(msg, sk, &tss); - if (msg->msg_get_inq) { + if ((cmsg_flags & TCP_CMSG_INQ) | msg->msg_get_inq) { msg->msg_inq = tcp_inq_hint(sk); if (cmsg_flags & TCP_CMSG_INQ) put_cmsg(msg, SOL_TCP, TCP_CM_INQ, diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index f6f01f514933b..c634a7fc86090 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -2929,7 +2929,6 @@ static int unix_stream_read_generic(struct unix_stream_read_state *state, unsigned int last_len; struct unix_sock *u; int copied = 0; - bool do_cmsg; int err = 0; long timeo; int target; @@ -2955,9 +2954,6 @@ static int unix_stream_read_generic(struct unix_stream_read_state *state, u = unix_sk(sk); - do_cmsg = READ_ONCE(u->recvmsg_inq); - if (do_cmsg) - msg->msg_get_inq = 1; redo: /* Lock the socket to prevent queue disordering * while sleeps in memcpy_tomsg @@ -3115,9 +3111,11 @@ static int unix_stream_read_generic(struct unix_stream_read_state *state, mutex_unlock(&u->iolock); if (msg) { + bool do_cmsg = READ_ONCE(u->recvmsg_inq); + scm_recv_unix(sock, msg, &scm, flags); - if (msg->msg_get_inq && (copied ?: err) >= 0) { + if ((do_cmsg | msg->msg_get_inq) && (copied ?: err) >= 0) { msg->msg_inq = READ_ONCE(u->inq_len); if (do_cmsg) put_cmsg(msg, SOL_SOCKET, SCM_INQ, From e86c4ee5a029665e5cfcca990d896a07b2403e51 Mon Sep 17 00:00:00 2001 From: Yeoreum Yun Date: Wed, 7 Jan 2026 16:21:15 +0000 Subject: [PATCH 1777/2333] arm64: Fix cleared E0POE bit after cpu_suspend()/resume() commit bdf3f4176092df5281877cacf42f843063b4784d upstream. TCR2_ELx.E0POE is set during smp_init(). However, this bit is not reprogrammed when the CPU enters suspension and later resumes via cpu_resume(), as __cpu_setup() does not re-enable E0POE and there is no save/restore logic for the TCR2_ELx system register. As a result, the E0POE feature no longer works after cpu_resume(). To address this, save and restore TCR2_EL1 in the cpu_suspend()/cpu_resume() path, rather than adding related logic to __cpu_setup(), taking into account possible future extensions of the TCR2_ELx feature. Fixes: bf83dae90fbc ("arm64: enable the Permission Overlay Extension for EL0") Cc: # 6.12.x Signed-off-by: Yeoreum Yun Reviewed-by: Anshuman Khandual Reviewed-by: Kevin Brodsky Signed-off-by: Catalin Marinas Signed-off-by: Greg Kroah-Hartman --- arch/arm64/include/asm/suspend.h | 2 +- arch/arm64/mm/proc.S | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/arch/arm64/include/asm/suspend.h b/arch/arm64/include/asm/suspend.h index 0cde2f473971e..eb60c97355530 100644 --- a/arch/arm64/include/asm/suspend.h +++ b/arch/arm64/include/asm/suspend.h @@ -2,7 +2,7 @@ #ifndef __ASM_SUSPEND_H #define __ASM_SUSPEND_H -#define NR_CTX_REGS 13 +#define NR_CTX_REGS 14 #define NR_CALLEE_SAVED_REGS 12 /* diff --git a/arch/arm64/mm/proc.S b/arch/arm64/mm/proc.S index 86818511962b6..17df19647556f 100644 --- a/arch/arm64/mm/proc.S +++ b/arch/arm64/mm/proc.S @@ -100,6 +100,10 @@ SYM_FUNC_START(cpu_do_suspend) * call stack. */ str x18, [x0, #96] +alternative_if ARM64_HAS_TCR2 + mrs x2, REG_TCR2_EL1 + str x2, [x0, #104] +alternative_else_nop_endif ret SYM_FUNC_END(cpu_do_suspend) @@ -134,6 +138,10 @@ SYM_FUNC_START(cpu_do_resume) msr tcr_el1, x8 msr vbar_el1, x9 msr mdscr_el1, x10 +alternative_if ARM64_HAS_TCR2 + ldr x2, [x0, #104] + msr REG_TCR2_EL1, x2 +alternative_else_nop_endif msr sctlr_el1, x12 set_this_cpu_offset x13 From 0174d5466caefc22f03a36c43b2a3cce7e332627 Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Tue, 6 Jan 2026 06:31:14 -0800 Subject: [PATCH 1778/2333] bnxt_en: Fix NULL pointer crash in bnxt_ptp_enable during error cleanup commit 3358995b1a7f9dcb52a56ec8251570d71024dad0 upstream. When bnxt_init_one() fails during initialization (e.g., bnxt_init_int_mode returns -ENODEV), the error path calls bnxt_free_hwrm_resources() which destroys the DMA pool and sets bp->hwrm_dma_pool to NULL. Subsequently, bnxt_ptp_clear() is called, which invokes ptp_clock_unregister(). Since commit a60fc3294a37 ("ptp: rework ptp_clock_unregister() to disable events"), ptp_clock_unregister() now calls ptp_disable_all_events(), which in turn invokes the driver's .enable() callback (bnxt_ptp_enable()) to disable PTP events before completing the unregistration. bnxt_ptp_enable() attempts to send HWRM commands via bnxt_ptp_cfg_pin() and bnxt_ptp_cfg_event(), both of which call hwrm_req_init(). This function tries to allocate from bp->hwrm_dma_pool, causing a NULL pointer dereference: bnxt_en 0000:01:00.0 (unnamed net_device) (uninitialized): bnxt_init_int_mode err: ffffffed KASAN: null-ptr-deref in range [0x0000000000000028-0x000000000000002f] Call Trace: __hwrm_req_init (drivers/net/ethernet/broadcom/bnxt/bnxt_hwrm.c:72) bnxt_ptp_enable (drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.c:323 drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.c:517) ptp_disable_all_events (drivers/ptp/ptp_chardev.c:66) ptp_clock_unregister (drivers/ptp/ptp_clock.c:518) bnxt_ptp_clear (drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.c:1134) bnxt_init_one (drivers/net/ethernet/broadcom/bnxt/bnxt.c:16889) Lines are against commit f8f9c1f4d0c7 ("Linux 6.19-rc3") Fix this by clearing and unregistering ptp (bnxt_ptp_clear()) before freeing HWRM resources. Suggested-by: Pavan Chebbi Signed-off-by: Breno Leitao Fixes: a60fc3294a37 ("ptp: rework ptp_clock_unregister() to disable events") Cc: stable@vger.kernel.org Reviewed-by: Pavan Chebbi Link: https://patch.msgid.link/20260106-bnxt-v3-1-71f37e11446a@debian.org Signed-off-by: Jakub Kicinski Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index a625e7c311dd7..0366323ab0676 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -16856,12 +16856,12 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) init_err_pci_clean: bnxt_hwrm_func_drv_unrgtr(bp); - bnxt_free_hwrm_resources(bp); - bnxt_hwmon_uninit(bp); - bnxt_ethtool_free(bp); bnxt_ptp_clear(bp); kfree(bp->ptp_cfg); bp->ptp_cfg = NULL; + bnxt_free_hwrm_resources(bp); + bnxt_hwmon_uninit(bp); + bnxt_ethtool_free(bp); kfree(bp->fw_health); bp->fw_health = NULL; bnxt_cleanup_pci(bp); From d52af58dd463821c5c516aebb031a58934f696ea Mon Sep 17 00:00:00 2001 From: Filipe Manana Date: Thu, 11 Dec 2025 15:06:26 +0000 Subject: [PATCH 1779/2333] btrfs: always detect conflicting inodes when logging inode refs commit 7ba0b6461bc4edb3005ea6e00cdae189bcf908a5 upstream. After rename exchanging (either with the rename exchange operation or regular renames in multiple non-atomic steps) two inodes and at least one of them is a directory, we can end up with a log tree that contains only of the inodes and after a power failure that can result in an attempt to delete the other inode when it should not because it was not deleted before the power failure. In some case that delete attempt fails when the target inode is a directory that contains a subvolume inside it, since the log replay code is not prepared to deal with directory entries that point to root items (only inode items). 1) We have directories "dir1" (inode A) and "dir2" (inode B) under the same parent directory; 2) We have a file (inode C) under directory "dir1" (inode A); 3) We have a subvolume inside directory "dir2" (inode B); 4) All these inodes were persisted in a past transaction and we are currently at transaction N; 5) We rename the file (inode C), so at btrfs_log_new_name() we update inode C's last_unlink_trans to N; 6) We get a rename exchange for "dir1" (inode A) and "dir2" (inode B), so after the exchange "dir1" is inode B and "dir2" is inode A. During the rename exchange we call btrfs_log_new_name() for inodes A and B, but because they are directories, we don't update their last_unlink_trans to N; 7) An fsync against the file (inode C) is done, and because its inode has a last_unlink_trans with a value of N we log its parent directory (inode A) (through btrfs_log_all_parents(), called from btrfs_log_inode_parent()). 8) So we end up with inode B not logged, which now has the old name of inode A. At copy_inode_items_to_log(), when logging inode A, we did not check if we had any conflicting inode to log because inode A has a generation lower than the current transaction (created in a past transaction); 9) After a power failure, when replaying the log tree, since we find that inode A has a new name that conflicts with the name of inode B in the fs tree, we attempt to delete inode B... this is wrong since that directory was never deleted before the power failure, and because there is a subvolume inside that directory, attempting to delete it will fail since replay_dir_deletes() and btrfs_unlink_inode() are not prepared to deal with dir items that point to roots instead of inodes. When that happens the mount fails and we get a stack trace like the following: [87.2314] BTRFS info (device dm-0): start tree-log replay [87.2318] BTRFS critical (device dm-0): failed to delete reference to subvol, root 5 inode 256 parent 259 [87.2332] ------------[ cut here ]------------ [87.2338] BTRFS: Transaction aborted (error -2) [87.2346] WARNING: CPU: 1 PID: 638968 at fs/btrfs/inode.c:4345 __btrfs_unlink_inode+0x416/0x440 [btrfs] [87.2368] Modules linked in: btrfs loop dm_thin_pool (...) [87.2470] CPU: 1 UID: 0 PID: 638968 Comm: mount Tainted: G W 6.18.0-rc7-btrfs-next-218+ #2 PREEMPT(full) [87.2489] Tainted: [W]=WARN [87.2494] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.16.2-0-gea1b7a073390-prebuilt.qemu.org 04/01/2014 [87.2514] RIP: 0010:__btrfs_unlink_inode+0x416/0x440 [btrfs] [87.2538] Code: c0 89 04 24 (...) [87.2568] RSP: 0018:ffffc0e741f4b9b8 EFLAGS: 00010286 [87.2574] RAX: 0000000000000000 RBX: ffff9d3ec8a6cf60 RCX: 0000000000000000 [87.2582] RDX: 0000000000000002 RSI: ffffffff84ab45a1 RDI: 00000000ffffffff [87.2591] RBP: ffff9d3ec8a6ef20 R08: 0000000000000000 R09: ffffc0e741f4b840 [87.2599] R10: ffff9d45dc1fffa8 R11: 0000000000000003 R12: ffff9d3ee26d77e0 [87.2608] R13: ffffc0e741f4ba98 R14: ffff9d4458040800 R15: ffff9d44b6b7ca10 [87.2618] FS: 00007f7b9603a840(0000) GS:ffff9d4658982000(0000) knlGS:0000000000000000 [87.2629] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [87.2637] CR2: 00007ffc9ec33b98 CR3: 000000011273e003 CR4: 0000000000370ef0 [87.2648] Call Trace: [87.2651] [87.2654] btrfs_unlink_inode+0x15/0x40 [btrfs] [87.2661] unlink_inode_for_log_replay+0x27/0xf0 [btrfs] [87.2669] check_item_in_log+0x1ea/0x2c0 [btrfs] [87.2676] replay_dir_deletes+0x16b/0x380 [btrfs] [87.2684] fixup_inode_link_count+0x34b/0x370 [btrfs] [87.2696] fixup_inode_link_counts+0x41/0x160 [btrfs] [87.2703] btrfs_recover_log_trees+0x1ff/0x7c0 [btrfs] [87.2711] ? __pfx_replay_one_buffer+0x10/0x10 [btrfs] [87.2719] open_ctree+0x10bb/0x15f0 [btrfs] [87.2726] btrfs_get_tree.cold+0xb/0x16c [btrfs] [87.2734] ? fscontext_read+0x15c/0x180 [87.2740] ? rw_verify_area+0x50/0x180 [87.2746] vfs_get_tree+0x25/0xd0 [87.2750] vfs_cmd_create+0x59/0xe0 [87.2755] __do_sys_fsconfig+0x4f6/0x6b0 [87.2760] do_syscall_64+0x50/0x1220 [87.2764] entry_SYSCALL_64_after_hwframe+0x76/0x7e [87.2770] RIP: 0033:0x7f7b9625f4aa [87.2775] Code: 73 01 c3 48 (...) [87.2803] RSP: 002b:00007ffc9ec35b08 EFLAGS: 00000246 ORIG_RAX: 00000000000001af [87.2817] RAX: ffffffffffffffda RBX: 0000558bfa91ac20 RCX: 00007f7b9625f4aa [87.2829] RDX: 0000000000000000 RSI: 0000000000000006 RDI: 0000000000000003 [87.2842] RBP: 0000558bfa91b120 R08: 0000000000000000 R09: 0000000000000000 [87.2854] R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000 [87.2864] R13: 00007f7b963f1580 R14: 00007f7b963f326c R15: 00007f7b963d8a23 [87.2877] [87.2882] ---[ end trace 0000000000000000 ]--- [87.2891] BTRFS: error (device dm-0 state A) in __btrfs_unlink_inode:4345: errno=-2 No such entry [87.2904] BTRFS: error (device dm-0 state EAO) in do_abort_log_replay:191: errno=-2 No such entry [87.2915] BTRFS critical (device dm-0 state EAO): log tree (for root 5) leaf currently being processed (slot 7 key (258 12 257)): [87.2929] BTRFS info (device dm-0 state EAO): leaf 30736384 gen 10 total ptrs 7 free space 15712 owner 18446744073709551610 [87.2929] BTRFS info (device dm-0 state EAO): refs 3 lock_owner 0 current 638968 [87.2929] item 0 key (257 INODE_ITEM 0) itemoff 16123 itemsize 160 [87.2929] inode generation 9 transid 10 size 0 nbytes 0 [87.2929] block group 0 mode 40755 links 1 uid 0 gid 0 [87.2929] rdev 0 sequence 7 flags 0x0 [87.2929] atime 1765464494.678070921 [87.2929] ctime 1765464494.686606513 [87.2929] mtime 1765464494.686606513 [87.2929] otime 1765464494.678070921 [87.2929] item 1 key (257 INODE_REF 256) itemoff 16109 itemsize 14 [87.2929] index 4 name_len 4 [87.2929] item 2 key (257 DIR_LOG_INDEX 2) itemoff 16101 itemsize 8 [87.2929] dir log end 2 [87.2929] item 3 key (257 DIR_LOG_INDEX 3) itemoff 16093 itemsize 8 [87.2929] dir log end 18446744073709551615 [87.2930] item 4 key (257 DIR_INDEX 3) itemoff 16060 itemsize 33 [87.2930] location key (258 1 0) type 1 [87.2930] transid 10 data_len 0 name_len 3 [87.2930] item 5 key (258 INODE_ITEM 0) itemoff 15900 itemsize 160 [87.2930] inode generation 9 transid 10 size 0 nbytes 0 [87.2930] block group 0 mode 100644 links 1 uid 0 gid 0 [87.2930] rdev 0 sequence 2 flags 0x0 [87.2930] atime 1765464494.678456467 [87.2930] ctime 1765464494.686606513 [87.2930] mtime 1765464494.678456467 [87.2930] otime 1765464494.678456467 [87.2930] item 6 key (258 INODE_REF 257) itemoff 15887 itemsize 13 [87.2930] index 3 name_len 3 [87.2930] BTRFS critical (device dm-0 state EAO): log replay failed in unlink_inode_for_log_replay:1045 for root 5, stage 3, with error -2: failed to unlink inode 256 parent dir 259 name subvol root 5 [87.2963] BTRFS: error (device dm-0 state EAO) in btrfs_recover_log_trees:7743: errno=-2 No such entry [87.2981] BTRFS: error (device dm-0 state EAO) in btrfs_replay_log:2083: errno=-2 No such entry (Failed to recover log tr So fix this by changing copy_inode_items_to_log() to always detect if there are conflicting inodes for the ref/extref of the inode being logged even if the inode was created in a past transaction. A test case for fstests will follow soon. CC: stable@vger.kernel.org # 6.1+ Signed-off-by: Filipe Manana Signed-off-by: David Sterba Signed-off-by: Greg Kroah-Hartman --- fs/btrfs/tree-log.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index e0b0750696a15..de9ea9d52482f 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -6348,10 +6348,8 @@ static int copy_inode_items_to_log(struct btrfs_trans_handle *trans, * and no keys greater than that, so bail out. */ break; - } else if ((min_key->type == BTRFS_INODE_REF_KEY || - min_key->type == BTRFS_INODE_EXTREF_KEY) && - (inode->generation == trans->transid || - ctx->logging_conflict_inodes)) { + } else if (min_key->type == BTRFS_INODE_REF_KEY || + min_key->type == BTRFS_INODE_EXTREF_KEY) { u64 other_ino = 0; u64 other_parent = 0; From 86e49948b0e62a72b3b91f8485ca74fe5b71e81b Mon Sep 17 00:00:00 2001 From: Alexander Usyskin Date: Mon, 15 Dec 2025 12:59:15 +0200 Subject: [PATCH 1780/2333] mei: me: add nova lake point S DID commit 420f423defcf6d0af2263d38da870ca4a20c0990 upstream. Add Nova Lake S device id. Cc: stable Co-developed-by: Tomas Winkler Signed-off-by: Tomas Winkler Signed-off-by: Alexander Usyskin Link: https://patch.msgid.link/20251215105915.1672659-1-alexander.usyskin@intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/hw-me-regs.h | 2 ++ drivers/misc/mei/pci-me.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h index a4f75dc369292..fa30899a5fa26 100644 --- a/drivers/misc/mei/hw-me-regs.h +++ b/drivers/misc/mei/hw-me-regs.h @@ -122,6 +122,8 @@ #define MEI_DEV_ID_WCL_P 0x4D70 /* Wildcat Lake P */ +#define MEI_DEV_ID_NVL_S 0x6E68 /* Nova Lake Point S */ + /* * MEI HW Section */ diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c index 73cad914be9f9..2a6e569558b94 100644 --- a/drivers/misc/mei/pci-me.c +++ b/drivers/misc/mei/pci-me.c @@ -129,6 +129,8 @@ static const struct pci_device_id mei_me_pci_tbl[] = { {MEI_PCI_DEVICE(MEI_DEV_ID_WCL_P, MEI_ME_PCH15_CFG)}, + {MEI_PCI_DEVICE(MEI_DEV_ID_NVL_S, MEI_ME_PCH15_CFG)}, + /* required last entry */ {0, } }; From 30a98c97f7874031f2e1de19c777ce011143cba4 Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Tue, 2 Dec 2025 11:24:24 +0000 Subject: [PATCH 1781/2333] rust_binder: remove spin_lock() in rust_shrink_free_page() commit 361e0ff456a8daf9753c18030533256e4133ce7a upstream. When forward-porting Rust Binder to 6.18, I neglected to take commit fb56fdf8b9a2 ("mm/list_lru: split the lock to per-cgroup scope") into account, and apparently I did not end up running the shrinker callback when I sanity tested the driver before submission. This leads to crashes like the following: ============================================ WARNING: possible recursive locking detected 6.18.0-mainline-maybe-dirty #1 Tainted: G IO -------------------------------------------- kswapd0/68 is trying to acquire lock: ffff956000fa18b0 (&l->lock){+.+.}-{2:2}, at: lock_list_lru_of_memcg+0x128/0x230 but task is already holding lock: ffff956000fa18b0 (&l->lock){+.+.}-{2:2}, at: rust_helper_spin_lock+0xd/0x20 other info that might help us debug this: Possible unsafe locking scenario: CPU0 ---- lock(&l->lock); lock(&l->lock); *** DEADLOCK *** May be due to missing lock nesting notation 3 locks held by kswapd0/68: #0: ffffffff90d2e260 (fs_reclaim){+.+.}-{0:0}, at: kswapd+0x597/0x1160 #1: ffff956000fa18b0 (&l->lock){+.+.}-{2:2}, at: rust_helper_spin_lock+0xd/0x20 #2: ffffffff90cf3680 (rcu_read_lock){....}-{1:2}, at: lock_list_lru_of_memcg+0x2d/0x230 To fix this, remove the spin_lock() call from rust_shrink_free_page(). Cc: stable Fixes: eafedbc7c050 ("rust_binder: add Rust Binder driver") Signed-off-by: Alice Ryhl Link: https://patch.msgid.link/20251202-binder-shrink-unspin-v1-1-263efb9ad625@google.com Signed-off-by: Greg Kroah-Hartman --- drivers/android/binder/page_range.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/android/binder/page_range.rs b/drivers/android/binder/page_range.rs index 9379038f61f51..fdd97112ef5c8 100644 --- a/drivers/android/binder/page_range.rs +++ b/drivers/android/binder/page_range.rs @@ -727,8 +727,5 @@ unsafe extern "C" fn rust_shrink_free_page( drop(mm); drop(page); - // SAFETY: We just unlocked the lru lock, but it should be locked when we return. - unsafe { bindings::spin_lock(&raw mut (*lru).lock) }; - LRU_REMOVED_ENTRY } From a0b28dd06a9a754da0f0fcb94296e92048e6f911 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Tue, 6 Jan 2026 21:20:23 -0800 Subject: [PATCH 1782/2333] lib/crypto: aes: Fix missing MMU protection for AES S-box commit 74d74bb78aeccc9edc10db216d6be121cf7ec176 upstream. __cacheline_aligned puts the data in the ".data..cacheline_aligned" section, which isn't marked read-only i.e. it doesn't receive MMU protection. Replace it with ____cacheline_aligned which does the right thing and just aligns the data while keeping it in ".rodata". Fixes: b5e0b032b6c3 ("crypto: aes - add generic time invariant AES cipher") Cc: stable@vger.kernel.org Reported-by: Qingfang Deng Closes: https://lore.kernel.org/r/20260105074712.498-1-dqfext@gmail.com/ Acked-by: Ard Biesheuvel Link: https://lore.kernel.org/r/20260107052023.174620-1-ebiggers@kernel.org Signed-off-by: Eric Biggers Signed-off-by: Greg Kroah-Hartman --- lib/crypto/aes.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/crypto/aes.c b/lib/crypto/aes.c index b57fda3460f1b..102aaa76bc8d7 100644 --- a/lib/crypto/aes.c +++ b/lib/crypto/aes.c @@ -13,7 +13,7 @@ * Emit the sbox as volatile const to prevent the compiler from doing * constant folding on sbox references involving fixed indexes. */ -static volatile const u8 __cacheline_aligned aes_sbox[] = { +static volatile const u8 ____cacheline_aligned aes_sbox[] = { 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, @@ -48,7 +48,7 @@ static volatile const u8 __cacheline_aligned aes_sbox[] = { 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16, }; -static volatile const u8 __cacheline_aligned aes_inv_sbox[] = { +static volatile const u8 ____cacheline_aligned aes_inv_sbox[] = { 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, From 844f521604bdef93fd3b648673e75528d8e9ef78 Mon Sep 17 00:00:00 2001 From: Haotian Zhang Date: Mon, 15 Dec 2025 10:01:14 +0800 Subject: [PATCH 1783/2333] counter: 104-quad-8: Fix incorrect return value in IRQ handler commit 9517d76dd160208b7a432301ce7bec8fc1ddc305 upstream. quad8_irq_handler() should return irqreturn_t enum values, but it directly returns negative errno codes from regmap operations on error. Return IRQ_NONE if the interrupt status cannot be read. If clearing the interrupt fails, return IRQ_HANDLED to prevent the kernel from disabling the IRQ line due to a spurious interrupt storm. Also, log these regmap failures with dev_WARN_ONCE. Fixes: 98ffe0252911 ("counter: 104-quad-8: Migrate to the regmap API") Suggested-by: Andy Shevchenko Signed-off-by: Haotian Zhang Link: https://lore.kernel.org/r/20251215020114.1913-1-vulab@iscas.ac.cn Cc: stable@vger.kernel.org Signed-off-by: William Breathitt Gray Signed-off-by: Greg Kroah-Hartman --- drivers/counter/104-quad-8.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/drivers/counter/104-quad-8.c b/drivers/counter/104-quad-8.c index ce81fc4e1ae76..573b2fe93253e 100644 --- a/drivers/counter/104-quad-8.c +++ b/drivers/counter/104-quad-8.c @@ -1192,6 +1192,7 @@ static irqreturn_t quad8_irq_handler(int irq, void *private) { struct counter_device *counter = private; struct quad8 *const priv = counter_priv(counter); + struct device *dev = counter->parent; unsigned int status; unsigned long irq_status; unsigned long channel; @@ -1200,8 +1201,11 @@ static irqreturn_t quad8_irq_handler(int irq, void *private) int ret; ret = regmap_read(priv->map, QUAD8_INTERRUPT_STATUS, &status); - if (ret) - return ret; + if (ret) { + dev_WARN_ONCE(dev, true, + "Attempt to read Interrupt Status Register failed: %d\n", ret); + return IRQ_NONE; + } if (!status) return IRQ_NONE; @@ -1223,8 +1227,9 @@ static irqreturn_t quad8_irq_handler(int irq, void *private) break; default: /* should never reach this path */ - WARN_ONCE(true, "invalid interrupt trigger function %u configured for channel %lu\n", - flg_pins, channel); + dev_WARN_ONCE(dev, true, + "invalid interrupt trigger function %u configured for channel %lu\n", + flg_pins, channel); continue; } @@ -1232,8 +1237,11 @@ static irqreturn_t quad8_irq_handler(int irq, void *private) } ret = regmap_write(priv->map, QUAD8_CHANNEL_OPERATION, CLEAR_PENDING_INTERRUPTS); - if (ret) - return ret; + if (ret) { + dev_WARN_ONCE(dev, true, + "Attempt to clear pending interrupts by writing to Channel Operation Register failed: %d\n", ret); + return IRQ_HANDLED; + } return IRQ_HANDLED; } From 425886b1f8304621b3f16632b274357067d5f13f Mon Sep 17 00:00:00 2001 From: Alexander Sverdlin Date: Tue, 18 Nov 2025 09:35:48 +0100 Subject: [PATCH 1784/2333] counter: interrupt-cnt: Drop IRQF_NO_THREAD flag commit 23f9485510c338476b9735d516c1d4aacb810d46 upstream. An IRQ handler can either be IRQF_NO_THREAD or acquire spinlock_t, as CONFIG_PROVE_RAW_LOCK_NESTING warns: ============================= [ BUG: Invalid wait context ] 6.18.0-rc1+git... #1 ----------------------------- some-user-space-process/1251 is trying to lock: (&counter->events_list_lock){....}-{3:3}, at: counter_push_event [counter] other info that might help us debug this: context-{2:2} no locks held by some-user-space-process/.... stack backtrace: CPU: 0 UID: 0 PID: 1251 Comm: some-user-space-process 6.18.0-rc1+git... #1 PREEMPT Call trace: show_stack (C) dump_stack_lvl dump_stack __lock_acquire lock_acquire _raw_spin_lock_irqsave counter_push_event [counter] interrupt_cnt_isr [interrupt_cnt] __handle_irq_event_percpu handle_irq_event handle_simple_irq handle_irq_desc generic_handle_domain_irq gpio_irq_handler handle_irq_desc generic_handle_domain_irq gic_handle_irq call_on_irq_stack do_interrupt_handler el0_interrupt __el0_irq_handler_common el0t_64_irq_handler el0t_64_irq ... and Sebastian correctly points out. Remove IRQF_NO_THREAD as an alternative to switching to raw_spinlock_t, because the latter would limit all potential nested locks to raw_spinlock_t only. Cc: Sebastian Andrzej Siewior Cc: stable@vger.kernel.org Link: https://lore.kernel.org/all/20251117151314.xwLAZrWY@linutronix.de/ Fixes: a55ebd47f21f ("counter: add IRQ or GPIO based counter") Signed-off-by: Alexander Sverdlin Reviewed-by: Sebastian Andrzej Siewior Reviewed-by: Oleksij Rempel Link: https://lore.kernel.org/r/20251118083603.778626-1-alexander.sverdlin@siemens.com Signed-off-by: William Breathitt Gray Signed-off-by: Greg Kroah-Hartman --- drivers/counter/interrupt-cnt.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/counter/interrupt-cnt.c b/drivers/counter/interrupt-cnt.c index 6c0c1d2d7027d..e6100b5fb082e 100644 --- a/drivers/counter/interrupt-cnt.c +++ b/drivers/counter/interrupt-cnt.c @@ -229,8 +229,7 @@ static int interrupt_cnt_probe(struct platform_device *pdev) irq_set_status_flags(priv->irq, IRQ_NOAUTOEN); ret = devm_request_irq(dev, priv->irq, interrupt_cnt_isr, - IRQF_TRIGGER_RISING | IRQF_NO_THREAD, - dev_name(dev), counter); + IRQF_TRIGGER_RISING, dev_name(dev), counter); if (ret) return ret; From 5b7f91acffd2c4c000971553d22efa1e1bb4feae Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Mon, 5 Jan 2026 20:31:41 -0500 Subject: [PATCH 1785/2333] tracing: Add recursion protection in kernel stack trace recording commit 5f1ef0dfcb5b7f4a91a9b0e0ba533efd9f7e2cdb upstream. A bug was reported about an infinite recursion caused by tracing the rcu events with the kernel stack trace trigger enabled. The stack trace code called back into RCU which then called the stack trace again. Expand the ftrace recursion protection to add a set of bits to protect events from recursion. Each bit represents the context that the event is in (normal, softirq, interrupt and NMI). Have the stack trace code use the interrupt context to protect against recursion. Note, the bug showed an issue in both the RCU code as well as the tracing stacktrace code. This only handles the tracing stack trace side of the bug. The RCU fix will be handled separately. Link: https://lore.kernel.org/all/20260102122807.7025fc87@gandalf.local.home/ Cc: stable@vger.kernel.org Cc: Masami Hiramatsu Cc: Mathieu Desnoyers Cc: Joel Fernandes Cc: "Paul E. McKenney" Cc: Boqun Feng Link: https://patch.msgid.link/20260105203141.515cd49f@gandalf.local.home Reported-by: Yao Kai Tested-by: Yao Kai Fixes: 5f5fa7ea89dc ("rcu: Don't use negative nesting depth in __rcu_read_unlock()") Signed-off-by: Steven Rostedt (Google) Signed-off-by: Greg Kroah-Hartman --- include/linux/trace_recursion.h | 9 +++++++++ kernel/trace/trace.c | 6 ++++++ 2 files changed, 15 insertions(+) diff --git a/include/linux/trace_recursion.h b/include/linux/trace_recursion.h index ae04054a1be36..e6ca052b2a85a 100644 --- a/include/linux/trace_recursion.h +++ b/include/linux/trace_recursion.h @@ -34,6 +34,13 @@ enum { TRACE_INTERNAL_SIRQ_BIT, TRACE_INTERNAL_TRANSITION_BIT, + /* Internal event use recursion bits */ + TRACE_INTERNAL_EVENT_BIT, + TRACE_INTERNAL_EVENT_NMI_BIT, + TRACE_INTERNAL_EVENT_IRQ_BIT, + TRACE_INTERNAL_EVENT_SIRQ_BIT, + TRACE_INTERNAL_EVENT_TRANSITION_BIT, + TRACE_BRANCH_BIT, /* * Abuse of the trace_recursion. @@ -58,6 +65,8 @@ enum { #define TRACE_LIST_START TRACE_INTERNAL_BIT +#define TRACE_EVENT_START TRACE_INTERNAL_EVENT_BIT + #define TRACE_CONTEXT_MASK ((1 << (TRACE_LIST_START + TRACE_CONTEXT_BITS)) - 1) /* diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 304e93597126e..ddff2af3cd3f7 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -3003,6 +3003,11 @@ static void __ftrace_trace_stack(struct trace_array *tr, struct ftrace_stack *fstack; struct stack_entry *entry; int stackidx; + int bit; + + bit = trace_test_and_set_recursion(_THIS_IP_, _RET_IP_, TRACE_EVENT_START); + if (bit < 0) + return; /* * Add one, for this function and the call to save_stack_trace() @@ -3071,6 +3076,7 @@ static void __ftrace_trace_stack(struct trace_array *tr, /* Again, don't let gcc optimize things here */ barrier(); __this_cpu_dec(ftrace_stack_reserve); + trace_clear_recursion(bit); } static inline void ftrace_trace_stack(struct trace_array *tr, From 64a0d47e0c3227b13d08bf01de78508e3bf8058d Mon Sep 17 00:00:00 2001 From: Vivian Wang Date: Tue, 30 Dec 2025 21:39:17 +0800 Subject: [PATCH 1786/2333] riscv: boot: Always make Image from vmlinux, not vmlinux.unstripped commit 66562b66dcbc8f93c1e28632299f449bb2f5c47d upstream. Since commit 4b47a3aefb29 ("kbuild: Restore pattern to avoid stripping .rela.dyn from vmlinux") vmlinux has .rel*.dyn preserved. Therefore, use vmlinux to produce Image, not vmlinux.unstripped. Doing so fixes booting a RELOCATABLE=y Image with kexec. The problem is caused by this chain of events: - Since commit 3e86e4d74c04 ("kbuild: keep .modinfo section in vmlinux.unstripped"), vmlinux.unstripped gets a .modinfo section. - The .modinfo section has SHF_ALLOC, so it ends up in Image, at the end of it. - The Image header's image_size field does not expect to include .modinfo and does not account for it, since it should not be in Image. - If .modinfo is large enough, the file size of Image ends up larger than image_size, which eventually leads to it failing sanity_check_segment_list(). Using vmlinux instead of vmlinux.unstripped means that the unexpected .modinfo section is gone from Image, fixing the file size problem. Cc: stable@vger.kernel.org Fixes: 3e86e4d74c04 ("kbuild: keep .modinfo section in vmlinux.unstripped") Signed-off-by: Vivian Wang Reviewed-by: Nathan Chancellor Tested-by: Han Gao Link: https://patch.msgid.link/20251230-riscv-vmlinux-not-unstripped-v1-1-15f49df880df@iscas.ac.cn Signed-off-by: Paul Walmsley Signed-off-by: Greg Kroah-Hartman --- arch/riscv/boot/Makefile | 4 ---- 1 file changed, 4 deletions(-) diff --git a/arch/riscv/boot/Makefile b/arch/riscv/boot/Makefile index bfc3d0b75b9b2..5301adf5f3f5d 100644 --- a/arch/riscv/boot/Makefile +++ b/arch/riscv/boot/Makefile @@ -31,11 +31,7 @@ $(obj)/xipImage: vmlinux FORCE endif -ifdef CONFIG_RELOCATABLE -$(obj)/Image: vmlinux.unstripped FORCE -else $(obj)/Image: vmlinux FORCE -endif $(call if_changed,objcopy) $(obj)/Image.gz: $(obj)/Image FORCE From 0ce45b2426f966736459758f9829a1fe79a07338 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 2 Jan 2026 14:18:29 +1000 Subject: [PATCH 1787/2333] nouveau: don't attempt fwsec on sb on newer platforms. commit e8b3627bec357698f2d4d6dbf27cdcfa0e9d8715 upstream. The changes to always loads fwsec sb causes problems on newer GPUs which don't use this path. Add hooks and pass through the device specific layers. Fixes: da67179e5538 ("drm/nouveau/gsp: Allocate fwsec-sb at boot") Cc: # v6.16+ Cc: Lyude Paul Cc: Timur Tabi Tested-by: Matthew Schwartz Tested-by: Christopher Snowhill Reviewed-by: Lyude Paul Signed-off-by: Dave Airlie Link: https://patch.msgid.link/20260102041829.2748009-1-airlied@gmail.com Signed-off-by: Greg Kroah-Hartman --- .../gpu/drm/nouveau/nvkm/subdev/gsp/ad102.c | 3 +++ .../gpu/drm/nouveau/nvkm/subdev/gsp/fwsec.c | 8 +------ .../gpu/drm/nouveau/nvkm/subdev/gsp/ga100.c | 3 +++ .../gpu/drm/nouveau/nvkm/subdev/gsp/ga102.c | 3 +++ .../gpu/drm/nouveau/nvkm/subdev/gsp/priv.h | 23 +++++++++++++++++-- .../gpu/drm/nouveau/nvkm/subdev/gsp/tu102.c | 15 ++++++++++++ .../gpu/drm/nouveau/nvkm/subdev/gsp/tu116.c | 3 +++ 7 files changed, 49 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/ad102.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/ad102.c index 35d1fcef520bf..c456a96268231 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/ad102.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/ad102.c @@ -30,6 +30,9 @@ ad102_gsp = { .booter.ctor = ga102_gsp_booter_ctor, + .fwsec_sb.ctor = tu102_gsp_fwsec_sb_ctor, + .fwsec_sb.dtor = tu102_gsp_fwsec_sb_dtor, + .dtor = r535_gsp_dtor, .oneinit = tu102_gsp_oneinit, .init = tu102_gsp_init, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/fwsec.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/fwsec.c index 5037602466604..851140e801220 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/fwsec.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/fwsec.c @@ -337,18 +337,12 @@ nvkm_gsp_fwsec_sb(struct nvkm_gsp *gsp) } int -nvkm_gsp_fwsec_sb_ctor(struct nvkm_gsp *gsp) +nvkm_gsp_fwsec_sb_init(struct nvkm_gsp *gsp) { return nvkm_gsp_fwsec_init(gsp, &gsp->fws.falcon.sb, "fwsec-sb", NVFW_FALCON_APPIF_DMEMMAPPER_CMD_SB); } -void -nvkm_gsp_fwsec_sb_dtor(struct nvkm_gsp *gsp) -{ - nvkm_falcon_fw_dtor(&gsp->fws.falcon.sb); -} - int nvkm_gsp_fwsec_frts(struct nvkm_gsp *gsp) { diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/ga100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/ga100.c index d201e8697226b..27a13aeccd3cb 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/ga100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/ga100.c @@ -47,6 +47,9 @@ ga100_gsp = { .booter.ctor = tu102_gsp_booter_ctor, + .fwsec_sb.ctor = tu102_gsp_fwsec_sb_ctor, + .fwsec_sb.dtor = tu102_gsp_fwsec_sb_dtor, + .dtor = r535_gsp_dtor, .oneinit = tu102_gsp_oneinit, .init = tu102_gsp_init, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/ga102.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/ga102.c index 917f7e2f6c466..b6b3eb6f4c006 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/ga102.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/ga102.c @@ -158,6 +158,9 @@ ga102_gsp_r535 = { .booter.ctor = ga102_gsp_booter_ctor, + .fwsec_sb.ctor = tu102_gsp_fwsec_sb_ctor, + .fwsec_sb.dtor = tu102_gsp_fwsec_sb_dtor, + .dtor = r535_gsp_dtor, .oneinit = tu102_gsp_oneinit, .init = tu102_gsp_init, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/priv.h index 86bdd203bc107..9dd66a2e38017 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/priv.h @@ -7,9 +7,8 @@ enum nvkm_acr_lsf_id; int nvkm_gsp_fwsec_frts(struct nvkm_gsp *); -int nvkm_gsp_fwsec_sb_ctor(struct nvkm_gsp *); int nvkm_gsp_fwsec_sb(struct nvkm_gsp *); -void nvkm_gsp_fwsec_sb_dtor(struct nvkm_gsp *); +int nvkm_gsp_fwsec_sb_init(struct nvkm_gsp *gsp); struct nvkm_gsp_fwif { int version; @@ -52,6 +51,11 @@ struct nvkm_gsp_func { struct nvkm_falcon *, struct nvkm_falcon_fw *); } booter; + struct { + int (*ctor)(struct nvkm_gsp *); + void (*dtor)(struct nvkm_gsp *); + } fwsec_sb; + void (*dtor)(struct nvkm_gsp *); int (*oneinit)(struct nvkm_gsp *); int (*init)(struct nvkm_gsp *); @@ -67,6 +71,8 @@ extern const struct nvkm_falcon_func tu102_gsp_flcn; extern const struct nvkm_falcon_fw_func tu102_gsp_fwsec; int tu102_gsp_booter_ctor(struct nvkm_gsp *, const char *, const struct firmware *, struct nvkm_falcon *, struct nvkm_falcon_fw *); +int tu102_gsp_fwsec_sb_ctor(struct nvkm_gsp *); +void tu102_gsp_fwsec_sb_dtor(struct nvkm_gsp *); int tu102_gsp_oneinit(struct nvkm_gsp *); int tu102_gsp_init(struct nvkm_gsp *); int tu102_gsp_fini(struct nvkm_gsp *, bool suspend); @@ -91,5 +97,18 @@ int r535_gsp_fini(struct nvkm_gsp *, bool suspend); int nvkm_gsp_new_(const struct nvkm_gsp_fwif *, struct nvkm_device *, enum nvkm_subdev_type, int, struct nvkm_gsp **); +static inline int nvkm_gsp_fwsec_sb_ctor(struct nvkm_gsp *gsp) +{ + if (gsp->func->fwsec_sb.ctor) + return gsp->func->fwsec_sb.ctor(gsp); + return 0; +} + +static inline void nvkm_gsp_fwsec_sb_dtor(struct nvkm_gsp *gsp) +{ + if (gsp->func->fwsec_sb.dtor) + gsp->func->fwsec_sb.dtor(gsp); +} + extern const struct nvkm_gsp_func gv100_gsp; #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/tu102.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/tu102.c index 81e56da0474a1..04b642a1f7305 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/tu102.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/tu102.c @@ -30,6 +30,18 @@ #include #include +int +tu102_gsp_fwsec_sb_ctor(struct nvkm_gsp *gsp) +{ + return nvkm_gsp_fwsec_sb_init(gsp); +} + +void +tu102_gsp_fwsec_sb_dtor(struct nvkm_gsp *gsp) +{ + nvkm_falcon_fw_dtor(&gsp->fws.falcon.sb); +} + static int tu102_gsp_booter_unload(struct nvkm_gsp *gsp, u32 mbox0, u32 mbox1) { @@ -370,6 +382,9 @@ tu102_gsp = { .booter.ctor = tu102_gsp_booter_ctor, + .fwsec_sb.ctor = tu102_gsp_fwsec_sb_ctor, + .fwsec_sb.dtor = tu102_gsp_fwsec_sb_dtor, + .dtor = r535_gsp_dtor, .oneinit = tu102_gsp_oneinit, .init = tu102_gsp_init, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/tu116.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/tu116.c index 97eb046c25d07..58cf258424218 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/tu116.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/tu116.c @@ -30,6 +30,9 @@ tu116_gsp = { .booter.ctor = tu102_gsp_booter_ctor, + .fwsec_sb.ctor = tu102_gsp_fwsec_sb_ctor, + .fwsec_sb.dtor = tu102_gsp_fwsec_sb_dtor, + .dtor = r535_gsp_dtor, .oneinit = tu102_gsp_oneinit, .init = tu102_gsp_init, From c12df0f5ca410ce09198d695206b24c4e6bfd073 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Fri, 5 Dec 2025 11:51:48 +0200 Subject: [PATCH 1788/2333] Revert "drm/atomic-helper: Re-order bridge chain pre-enable and post-disable" commit c1ef9a6cabb34dbc09e31417b0c0a672fe0de13a upstream. This reverts commit c9b1150a68d9362a0827609fc0dc1664c0d8bfe1. Changing the enable/disable sequence has caused regressions on multiple platforms: R-Car, MCDE, Rockchip. A series (see link below) was sent to fix these, but it was decided that it's better to revert the original patch and change the enable/disable sequence only in the tidss driver. Reverting this commit breaks tidss's DSI and OLDI outputs, which will be fixed in the following commits. Signed-off-by: Tomi Valkeinen Link: https://lore.kernel.org/all/20251202-mcde-drm-regression-thirdfix-v6-0-f1bffd4ec0fa%40kernel.org/ Fixes: c9b1150a68d9 ("drm/atomic-helper: Re-order bridge chain pre-enable and post-disable") Cc: stable@vger.kernel.org # v6.17+ Reviewed-by: Aradhya Bhatia Reviewed-by: Maxime Ripard Reviewed-by: Linus Walleij Tested-by: Linus Walleij Signed-off-by: Linus Walleij Link: https://patch.msgid.link/20251205-drm-seq-fix-v1-1-fda68fa1b3de@ideasonboard.com Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/drm_atomic_helper.c | 8 +- include/drm/drm_bridge.h | 249 ++++++++-------------------- 2 files changed, 70 insertions(+), 187 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index d5ebe6ea0acbc..1f5808b8fd5d9 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -1341,9 +1341,9 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *state) { encoder_bridge_disable(dev, state); - crtc_disable(dev, state); - encoder_bridge_post_disable(dev, state); + + crtc_disable(dev, state); } /** @@ -1682,10 +1682,10 @@ encoder_bridge_enable(struct drm_device *dev, struct drm_atomic_state *state) void drm_atomic_helper_commit_modeset_enables(struct drm_device *dev, struct drm_atomic_state *state) { - encoder_bridge_pre_enable(dev, state); - crtc_enable(dev, state); + encoder_bridge_pre_enable(dev, state); + encoder_bridge_enable(dev, state); drm_atomic_helper_commit_writebacks(dev, state); diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h index 76e05930f50e0..57d9a3c062124 100644 --- a/include/drm/drm_bridge.h +++ b/include/drm/drm_bridge.h @@ -176,33 +176,17 @@ struct drm_bridge_funcs { /** * @disable: * - * The @disable callback should disable the bridge. + * This callback should disable the bridge. It is called right before + * the preceding element in the display pipe is disabled. If the + * preceding element is a bridge this means it's called before that + * bridge's @disable vfunc. If the preceding element is a &drm_encoder + * it's called right before the &drm_encoder_helper_funcs.disable, + * &drm_encoder_helper_funcs.prepare or &drm_encoder_helper_funcs.dpms + * hook. * * The bridge can assume that the display pipe (i.e. clocks and timing * signals) feeding it is still running when this callback is called. * - * - * If the preceding element is a &drm_bridge, then this is called before - * that bridge is disabled via one of: - * - * - &drm_bridge_funcs.disable - * - &drm_bridge_funcs.atomic_disable - * - * If the preceding element of the bridge is a display controller, then - * this callback is called before the encoder is disabled via one of: - * - * - &drm_encoder_helper_funcs.atomic_disable - * - &drm_encoder_helper_funcs.prepare - * - &drm_encoder_helper_funcs.disable - * - &drm_encoder_helper_funcs.dpms - * - * and the CRTC is disabled via one of: - * - * - &drm_crtc_helper_funcs.prepare - * - &drm_crtc_helper_funcs.atomic_disable - * - &drm_crtc_helper_funcs.disable - * - &drm_crtc_helper_funcs.dpms. - * * The @disable callback is optional. * * NOTE: @@ -215,34 +199,17 @@ struct drm_bridge_funcs { /** * @post_disable: * - * The bridge must assume that the display pipe (i.e. clocks and timing - * signals) feeding this bridge is no longer running when the - * @post_disable is called. + * This callback should disable the bridge. It is called right after the + * preceding element in the display pipe is disabled. If the preceding + * element is a bridge this means it's called after that bridge's + * @post_disable function. If the preceding element is a &drm_encoder + * it's called right after the encoder's + * &drm_encoder_helper_funcs.disable, &drm_encoder_helper_funcs.prepare + * or &drm_encoder_helper_funcs.dpms hook. * - * This callback should perform all the actions required by the hardware - * after it has stopped receiving signals from the preceding element. - * - * If the preceding element is a &drm_bridge, then this is called after - * that bridge is post-disabled (unless marked otherwise by the - * @pre_enable_prev_first flag) via one of: - * - * - &drm_bridge_funcs.post_disable - * - &drm_bridge_funcs.atomic_post_disable - * - * If the preceding element of the bridge is a display controller, then - * this callback is called after the encoder is disabled via one of: - * - * - &drm_encoder_helper_funcs.atomic_disable - * - &drm_encoder_helper_funcs.prepare - * - &drm_encoder_helper_funcs.disable - * - &drm_encoder_helper_funcs.dpms - * - * and the CRTC is disabled via one of: - * - * - &drm_crtc_helper_funcs.prepare - * - &drm_crtc_helper_funcs.atomic_disable - * - &drm_crtc_helper_funcs.disable - * - &drm_crtc_helper_funcs.dpms + * The bridge must assume that the display pipe (i.e. clocks and timing + * signals) feeding it is no longer running when this callback is + * called. * * The @post_disable callback is optional. * @@ -285,30 +252,18 @@ struct drm_bridge_funcs { /** * @pre_enable: * - * The display pipe (i.e. clocks and timing signals) feeding this bridge - * will not yet be running when the @pre_enable is called. - * - * This callback should perform all the necessary actions to prepare the - * bridge to accept signals from the preceding element. - * - * If the preceding element is a &drm_bridge, then this is called before - * that bridge is pre-enabled (unless marked otherwise by - * @pre_enable_prev_first flag) via one of: - * - * - &drm_bridge_funcs.pre_enable - * - &drm_bridge_funcs.atomic_pre_enable - * - * If the preceding element of the bridge is a display controller, then - * this callback is called before the CRTC is enabled via one of: - * - * - &drm_crtc_helper_funcs.atomic_enable - * - &drm_crtc_helper_funcs.commit - * - * and the encoder is enabled via one of: + * This callback should enable the bridge. It is called right before + * the preceding element in the display pipe is enabled. If the + * preceding element is a bridge this means it's called before that + * bridge's @pre_enable function. If the preceding element is a + * &drm_encoder it's called right before the encoder's + * &drm_encoder_helper_funcs.enable, &drm_encoder_helper_funcs.commit or + * &drm_encoder_helper_funcs.dpms hook. * - * - &drm_encoder_helper_funcs.atomic_enable - * - &drm_encoder_helper_funcs.enable - * - &drm_encoder_helper_funcs.commit + * The display pipe (i.e. clocks and timing signals) feeding this bridge + * will not yet be running when this callback is called. The bridge must + * not enable the display link feeding the next bridge in the chain (if + * there is one) when this callback is called. * * The @pre_enable callback is optional. * @@ -322,31 +277,19 @@ struct drm_bridge_funcs { /** * @enable: * - * The @enable callback should enable the bridge. + * This callback should enable the bridge. It is called right after + * the preceding element in the display pipe is enabled. If the + * preceding element is a bridge this means it's called after that + * bridge's @enable function. If the preceding element is a + * &drm_encoder it's called right after the encoder's + * &drm_encoder_helper_funcs.enable, &drm_encoder_helper_funcs.commit or + * &drm_encoder_helper_funcs.dpms hook. * * The bridge can assume that the display pipe (i.e. clocks and timing * signals) feeding it is running when this callback is called. This * callback must enable the display link feeding the next bridge in the * chain if there is one. * - * If the preceding element is a &drm_bridge, then this is called after - * that bridge is enabled via one of: - * - * - &drm_bridge_funcs.enable - * - &drm_bridge_funcs.atomic_enable - * - * If the preceding element of the bridge is a display controller, then - * this callback is called after the CRTC is enabled via one of: - * - * - &drm_crtc_helper_funcs.atomic_enable - * - &drm_crtc_helper_funcs.commit - * - * and the encoder is enabled via one of: - * - * - &drm_encoder_helper_funcs.atomic_enable - * - &drm_encoder_helper_funcs.enable - * - drm_encoder_helper_funcs.commit - * * The @enable callback is optional. * * NOTE: @@ -359,30 +302,17 @@ struct drm_bridge_funcs { /** * @atomic_pre_enable: * - * The display pipe (i.e. clocks and timing signals) feeding this bridge - * will not yet be running when the @atomic_pre_enable is called. - * - * This callback should perform all the necessary actions to prepare the - * bridge to accept signals from the preceding element. - * - * If the preceding element is a &drm_bridge, then this is called before - * that bridge is pre-enabled (unless marked otherwise by - * @pre_enable_prev_first flag) via one of: - * - * - &drm_bridge_funcs.pre_enable - * - &drm_bridge_funcs.atomic_pre_enable + * This callback should enable the bridge. It is called right before + * the preceding element in the display pipe is enabled. If the + * preceding element is a bridge this means it's called before that + * bridge's @atomic_pre_enable or @pre_enable function. If the preceding + * element is a &drm_encoder it's called right before the encoder's + * &drm_encoder_helper_funcs.atomic_enable hook. * - * If the preceding element of the bridge is a display controller, then - * this callback is called before the CRTC is enabled via one of: - * - * - &drm_crtc_helper_funcs.atomic_enable - * - &drm_crtc_helper_funcs.commit - * - * and the encoder is enabled via one of: - * - * - &drm_encoder_helper_funcs.atomic_enable - * - &drm_encoder_helper_funcs.enable - * - &drm_encoder_helper_funcs.commit + * The display pipe (i.e. clocks and timing signals) feeding this bridge + * will not yet be running when this callback is called. The bridge must + * not enable the display link feeding the next bridge in the chain (if + * there is one) when this callback is called. * * The @atomic_pre_enable callback is optional. */ @@ -392,31 +322,18 @@ struct drm_bridge_funcs { /** * @atomic_enable: * - * The @atomic_enable callback should enable the bridge. + * This callback should enable the bridge. It is called right after + * the preceding element in the display pipe is enabled. If the + * preceding element is a bridge this means it's called after that + * bridge's @atomic_enable or @enable function. If the preceding element + * is a &drm_encoder it's called right after the encoder's + * &drm_encoder_helper_funcs.atomic_enable hook. * * The bridge can assume that the display pipe (i.e. clocks and timing * signals) feeding it is running when this callback is called. This * callback must enable the display link feeding the next bridge in the * chain if there is one. * - * If the preceding element is a &drm_bridge, then this is called after - * that bridge is enabled via one of: - * - * - &drm_bridge_funcs.enable - * - &drm_bridge_funcs.atomic_enable - * - * If the preceding element of the bridge is a display controller, then - * this callback is called after the CRTC is enabled via one of: - * - * - &drm_crtc_helper_funcs.atomic_enable - * - &drm_crtc_helper_funcs.commit - * - * and the encoder is enabled via one of: - * - * - &drm_encoder_helper_funcs.atomic_enable - * - &drm_encoder_helper_funcs.enable - * - drm_encoder_helper_funcs.commit - * * The @atomic_enable callback is optional. */ void (*atomic_enable)(struct drm_bridge *bridge, @@ -424,32 +341,16 @@ struct drm_bridge_funcs { /** * @atomic_disable: * - * The @atomic_disable callback should disable the bridge. + * This callback should disable the bridge. It is called right before + * the preceding element in the display pipe is disabled. If the + * preceding element is a bridge this means it's called before that + * bridge's @atomic_disable or @disable vfunc. If the preceding element + * is a &drm_encoder it's called right before the + * &drm_encoder_helper_funcs.atomic_disable hook. * * The bridge can assume that the display pipe (i.e. clocks and timing * signals) feeding it is still running when this callback is called. * - * If the preceding element is a &drm_bridge, then this is called before - * that bridge is disabled via one of: - * - * - &drm_bridge_funcs.disable - * - &drm_bridge_funcs.atomic_disable - * - * If the preceding element of the bridge is a display controller, then - * this callback is called before the encoder is disabled via one of: - * - * - &drm_encoder_helper_funcs.atomic_disable - * - &drm_encoder_helper_funcs.prepare - * - &drm_encoder_helper_funcs.disable - * - &drm_encoder_helper_funcs.dpms - * - * and the CRTC is disabled via one of: - * - * - &drm_crtc_helper_funcs.prepare - * - &drm_crtc_helper_funcs.atomic_disable - * - &drm_crtc_helper_funcs.disable - * - &drm_crtc_helper_funcs.dpms. - * * The @atomic_disable callback is optional. */ void (*atomic_disable)(struct drm_bridge *bridge, @@ -458,34 +359,16 @@ struct drm_bridge_funcs { /** * @atomic_post_disable: * - * The bridge must assume that the display pipe (i.e. clocks and timing - * signals) feeding this bridge is no longer running when the - * @atomic_post_disable is called. - * - * This callback should perform all the actions required by the hardware - * after it has stopped receiving signals from the preceding element. + * This callback should disable the bridge. It is called right after the + * preceding element in the display pipe is disabled. If the preceding + * element is a bridge this means it's called after that bridge's + * @atomic_post_disable or @post_disable function. If the preceding + * element is a &drm_encoder it's called right after the encoder's + * &drm_encoder_helper_funcs.atomic_disable hook. * - * If the preceding element is a &drm_bridge, then this is called after - * that bridge is post-disabled (unless marked otherwise by the - * @pre_enable_prev_first flag) via one of: - * - * - &drm_bridge_funcs.post_disable - * - &drm_bridge_funcs.atomic_post_disable - * - * If the preceding element of the bridge is a display controller, then - * this callback is called after the encoder is disabled via one of: - * - * - &drm_encoder_helper_funcs.atomic_disable - * - &drm_encoder_helper_funcs.prepare - * - &drm_encoder_helper_funcs.disable - * - &drm_encoder_helper_funcs.dpms - * - * and the CRTC is disabled via one of: - * - * - &drm_crtc_helper_funcs.prepare - * - &drm_crtc_helper_funcs.atomic_disable - * - &drm_crtc_helper_funcs.disable - * - &drm_crtc_helper_funcs.dpms + * The bridge must assume that the display pipe (i.e. clocks and timing + * signals) feeding it is no longer running when this callback is + * called. * * The @atomic_post_disable callback is optional. */ From cb73d37ac18bc1716690ff5255a0ef1952827e9e Mon Sep 17 00:00:00 2001 From: Haoxiang Li Date: Sat, 20 Dec 2025 00:28:45 +0800 Subject: [PATCH 1789/2333] ALSA: ac97: fix a double free in snd_ac97_controller_register() commit 830988b6cf197e6dcffdfe2008c5738e6c6c3c0f upstream. If ac97_add_adapter() fails, put_device() is the correct way to drop the device reference. kfree() is not required. Add kfree() if idr_alloc() fails and in ac97_adapter_release() to do the cleanup. Found by code review. Fixes: 74426fbff66e ("ALSA: ac97: add an ac97 bus") Cc: stable@vger.kernel.org Signed-off-by: Haoxiang Li Link: https://patch.msgid.link/20251219162845.657525-1-lihaoxiang@isrc.iscas.ac.cn Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/ac97/bus.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sound/ac97/bus.c b/sound/ac97/bus.c index f4254703d29f7..bb9b795e02262 100644 --- a/sound/ac97/bus.c +++ b/sound/ac97/bus.c @@ -298,6 +298,7 @@ static void ac97_adapter_release(struct device *dev) idr_remove(&ac97_adapter_idr, ac97_ctrl->nr); dev_dbg(&ac97_ctrl->adap, "adapter unregistered by %s\n", dev_name(ac97_ctrl->parent)); + kfree(ac97_ctrl); } static const struct device_type ac97_adapter_type = { @@ -319,7 +320,9 @@ static int ac97_add_adapter(struct ac97_controller *ac97_ctrl) ret = device_register(&ac97_ctrl->adap); if (ret) put_device(&ac97_ctrl->adap); - } + } else + kfree(ac97_ctrl); + if (!ret) { list_add(&ac97_ctrl->controllers, &ac97_controllers); dev_dbg(&ac97_ctrl->adap, "adapter registered by %s\n", @@ -361,14 +364,11 @@ struct ac97_controller *snd_ac97_controller_register( ret = ac97_add_adapter(ac97_ctrl); if (ret) - goto err; + return ERR_PTR(ret); ac97_bus_reset(ac97_ctrl); ac97_bus_scan(ac97_ctrl); return ac97_ctrl; -err: - kfree(ac97_ctrl); - return ERR_PTR(ret); } EXPORT_SYMBOL_GPL(snd_ac97_controller_register); From 00d880c469b75ab4ad9e436e8079229e1e7ae4e4 Mon Sep 17 00:00:00 2001 From: August Wikerfors Date: Mon, 22 Dec 2025 20:47:04 +0100 Subject: [PATCH 1790/2333] ALSA: hda/tas2781: properly initialize speaker_id for TAS2563 commit e340663bbf2a75dae5d4fddf90b49281f5c9df3f upstream. After speaker id retrieval was refactored to happen in tas2781_read_acpi, devices that do not use a speaker id need a negative speaker_id value instead of NULL, but no initialization was added to the TAS2563 code path. This causes the driver to attempt to load a non-existent firmware file name with a speaker id of 0 ("TAS2XXX38700.bin") instead of the correct file name without a speaker id ("TAS2XXX3870.bin"), resulting in low volume and these dmesg errors: tas2781-hda i2c-INT8866:00: Direct firmware load for TAS2XXX38700.bin failed with error -2 tas2781-hda i2c-INT8866:00: tasdevice_dsp_parser: load TAS2XXX38700.bin error tas2781-hda i2c-INT8866:00: dspfw load TAS2XXX38700.bin error [...] tas2781-hda i2c-INT8866:00: tasdevice_prmg_load: Firmware is NULL Fix this by setting speaker_id to -1 as is done for other models. Fixes: 945865a0ddf3 ("ALSA: hda/tas2781: fix speaker id retrieval for multiple probes") Cc: stable@vger.kernel.org Signed-off-by: August Wikerfors Link: https://patch.msgid.link/20251222194704.87232-1-git@augustwikerfors.se Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/hda/codecs/side-codecs/tas2781_hda_i2c.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c b/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c index c8619995b1d78..f7a7f216d5865 100644 --- a/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c +++ b/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c @@ -111,8 +111,10 @@ static int tas2781_read_acpi(struct tasdevice_priv *p, const char *hid) sub = acpi_get_subsystem_id(ACPI_HANDLE(physdev)); if (IS_ERR(sub)) { /* No subsys id in older tas2563 projects. */ - if (!strncmp(hid, "INT8866", sizeof("INT8866"))) + if (!strncmp(hid, "INT8866", sizeof("INT8866"))) { + p->speaker_id = -1; goto end_2563; + } dev_err(p->dev, "Failed to get SUBSYS ID.\n"); ret = PTR_ERR(sub); goto err; From 1d8b1ac985c912cbdc47b9a992af377113fa8f2e Mon Sep 17 00:00:00 2001 From: Carlos Song Date: Tue, 18 Nov 2025 14:28:54 +0800 Subject: [PATCH 1791/2333] arm64: dts: imx95: correct I3C2 pclk to IMX95_CLK_BUSWAKEUP commit cd0caaf2005547eaef8170356939aaabfcad4837 upstream. I3C2 is in WAKEUP domain. Its pclk should be IMX95_CLK_BUSWAKEUP. Fixes: 969497ebefcf ("arm64: dts: imx95: Add i3c1 and i3c2") Signed-off-by: Carlos Song Cc: stable@vger.kernel.org Reviewed-by: Frank Li Signed-off-by: Shawn Guo Signed-off-by: Greg Kroah-Hartman --- arch/arm64/boot/dts/freescale/imx95.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/freescale/imx95.dtsi b/arch/arm64/boot/dts/freescale/imx95.dtsi index 6da961eb3fe5c..583c5f7a84b54 100644 --- a/arch/arm64/boot/dts/freescale/imx95.dtsi +++ b/arch/arm64/boot/dts/freescale/imx95.dtsi @@ -806,7 +806,7 @@ interrupts = ; #address-cells = <3>; #size-cells = <0>; - clocks = <&scmi_clk IMX95_CLK_BUSAON>, + clocks = <&scmi_clk IMX95_CLK_BUSWAKEUP>, <&scmi_clk IMX95_CLK_I3C2SLOW>; clock-names = "pclk", "fast_clk"; status = "disabled"; From b023b3f236e84ce57da67ca96d6da44b6db1f7ed Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Sat, 13 Dec 2025 15:16:43 +0900 Subject: [PATCH 1792/2333] drm/amd/display: Apply e4479aecf658 to dml commit 70740454377f1ba3ff32f5df4acd965db99d055b upstream. After an innocuous optimization change in clang-22, allmodconfig (which enables CONFIG_KASAN and CONFIG_WERROR) breaks with: drivers/gpu/drm/amd/amdgpu/../display/dc/dml/dcn32/display_mode_vba_32.c:1724:6: error: stack frame size (3144) exceeds limit (3072) in 'dml32_ModeSupportAndSystemConfigurationFull' [-Werror,-Wframe-larger-than] 1724 | void dml32_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_lib) | ^ With clang-21, this function was already pretty close to the existing limit of 3072 bytes. drivers/gpu/drm/amd/amdgpu/../display/dc/dml/dcn32/display_mode_vba_32.c:1724:6: error: stack frame size (2904) exceeds limit (2048) in 'dml32_ModeSupportAndSystemConfigurationFull' [-Werror,-Wframe-larger-than] 1724 | void dml32_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_lib) | ^ A similar situation occurred in dml2, which was resolved by commit e4479aecf658 ("drm/amd/display: Increase sanitizer frame larger than limit when compile testing with clang") by increasing the limit for clang when compile testing with certain sanitizer enabled, so that allmodconfig (an easy testing target) continues to work. Apply that same change to the dml folder to clear up the warning for allmodconfig, unbreaking the build. Closes: https://github.com/ClangBuiltLinux/linux/issues/2135 Signed-off-by: Nathan Chancellor Signed-off-by: Alex Deucher (cherry picked from commit 25314b453cf812150e9951a32007a32bba85707e) Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/amd/display/dc/dml/Makefile | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/dml/Makefile b/drivers/gpu/drm/amd/display/dc/dml/Makefile index b357683b4255a..268b5fbdb48bd 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dml/Makefile @@ -30,7 +30,11 @@ dml_rcflags := $(CC_FLAGS_NO_FPU) ifneq ($(CONFIG_FRAME_WARN),0) ifeq ($(filter y,$(CONFIG_KASAN)$(CONFIG_KCSAN)),y) - frame_warn_limit := 3072 + ifeq ($(CONFIG_CC_IS_CLANG)$(CONFIG_COMPILE_TEST),yy) + frame_warn_limit := 4096 + else + frame_warn_limit := 3072 + endif else frame_warn_limit := 2048 endif From 1f50931f79dce903c7040bcb15be6bf9a49a7df2 Mon Sep 17 00:00:00 2001 From: Alan Liu Date: Mon, 22 Dec 2025 12:26:35 +0800 Subject: [PATCH 1793/2333] drm/amdgpu: Fix query for VPE block_type and ip_count commit 72d7f4573660287f1b66c30319efecd6fcde92ee upstream. [Why] Query for VPE block_type and ip_count is missing. [How] Add VPE case in ip_block_type and hw_ip_count query. Reviewed-by: Lang Yu Signed-off-by: Alan Liu Signed-off-by: Alex Deucher (cherry picked from commit a6ea0a430aca5932b9c75d8e38deeb45665dd2ae) Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c index b3e6b3fcdf2cb..a8b507fd85673 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c @@ -201,6 +201,9 @@ static enum amd_ip_block_type type = (amdgpu_device_ip_get_ip_block(adev, AMD_IP_BLOCK_TYPE_JPEG)) ? AMD_IP_BLOCK_TYPE_JPEG : AMD_IP_BLOCK_TYPE_VCN; break; + case AMDGPU_HW_IP_VPE: + type = AMD_IP_BLOCK_TYPE_VPE; + break; default: type = AMD_IP_BLOCK_TYPE_NUM; break; @@ -721,6 +724,9 @@ int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) case AMD_IP_BLOCK_TYPE_UVD: count = adev->uvd.num_uvd_inst; break; + case AMD_IP_BLOCK_TYPE_VPE: + count = adev->vpe.num_instances; + break; /* For all other IP block types not listed in the switch statement * the ip status is valid here and the instance count is one. */ From 8a8bf7ed823045b6b97f75b5e62f615fbb8c6ba1 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 5 Dec 2025 11:51:50 +0200 Subject: [PATCH 1794/2333] drm/atomic-helper: Export and namespace some functions commit d1c7dc57ff2400b141e6582a8d2dc5170108cf81 upstream. Export and namespace those not prefixed with drm_* so it becomes possible to write custom commit tail functions in individual drivers using the helper infrastructure. Tested-by: Marek Vasut Reviewed-by: Maxime Ripard Signed-off-by: Tomi Valkeinen Cc: stable@vger.kernel.org # v6.17+ Fixes: c9b1150a68d9 ("drm/atomic-helper: Re-order bridge chain pre-enable and post-disable") Reviewed-by: Aradhya Bhatia Reviewed-by: Linus Walleij Tested-by: Linus Walleij Signed-off-by: Linus Walleij Link: https://patch.msgid.link/20251205-drm-seq-fix-v1-3-fda68fa1b3de@ideasonboard.com Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/drm_atomic_helper.c | 122 ++++++++++++++++++++++------ include/drm/drm_atomic_helper.h | 22 +++++ 2 files changed, 121 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 1f5808b8fd5d9..bbec1c184f652 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -1162,8 +1162,18 @@ crtc_needs_disable(struct drm_crtc_state *old_state, new_state->self_refresh_active; } -static void -encoder_bridge_disable(struct drm_device *dev, struct drm_atomic_state *state) +/** + * drm_atomic_helper_commit_encoder_bridge_disable - disable bridges and encoder + * @dev: DRM device + * @state: the driver state object + * + * Loops over all connectors in the current state and if the CRTC needs + * it, disables the bridge chain all the way, then disables the encoder + * afterwards. + */ +void +drm_atomic_helper_commit_encoder_bridge_disable(struct drm_device *dev, + struct drm_atomic_state *state) { struct drm_connector *connector; struct drm_connector_state *old_conn_state, *new_conn_state; @@ -1229,9 +1239,18 @@ encoder_bridge_disable(struct drm_device *dev, struct drm_atomic_state *state) } } } +EXPORT_SYMBOL(drm_atomic_helper_commit_encoder_bridge_disable); -static void -crtc_disable(struct drm_device *dev, struct drm_atomic_state *state) +/** + * drm_atomic_helper_commit_crtc_disable - disable CRTSs + * @dev: DRM device + * @state: the driver state object + * + * Loops over all CRTCs in the current state and if the CRTC needs + * it, disables it. + */ +void +drm_atomic_helper_commit_crtc_disable(struct drm_device *dev, struct drm_atomic_state *state) { struct drm_crtc *crtc; struct drm_crtc_state *old_crtc_state, *new_crtc_state; @@ -1282,9 +1301,18 @@ crtc_disable(struct drm_device *dev, struct drm_atomic_state *state) drm_crtc_vblank_put(crtc); } } +EXPORT_SYMBOL(drm_atomic_helper_commit_crtc_disable); -static void -encoder_bridge_post_disable(struct drm_device *dev, struct drm_atomic_state *state) +/** + * drm_atomic_helper_commit_encoder_bridge_post_disable - post-disable encoder bridges + * @dev: DRM device + * @state: the driver state object + * + * Loops over all connectors in the current state and if the CRTC needs + * it, post-disables all encoder bridges. + */ +void +drm_atomic_helper_commit_encoder_bridge_post_disable(struct drm_device *dev, struct drm_atomic_state *state) { struct drm_connector *connector; struct drm_connector_state *old_conn_state, *new_conn_state; @@ -1335,15 +1363,16 @@ encoder_bridge_post_disable(struct drm_device *dev, struct drm_atomic_state *sta drm_bridge_put(bridge); } } +EXPORT_SYMBOL(drm_atomic_helper_commit_encoder_bridge_post_disable); static void disable_outputs(struct drm_device *dev, struct drm_atomic_state *state) { - encoder_bridge_disable(dev, state); + drm_atomic_helper_commit_encoder_bridge_disable(dev, state); - encoder_bridge_post_disable(dev, state); + drm_atomic_helper_commit_encoder_bridge_post_disable(dev, state); - crtc_disable(dev, state); + drm_atomic_helper_commit_crtc_disable(dev, state); } /** @@ -1446,8 +1475,17 @@ void drm_atomic_helper_calc_timestamping_constants(struct drm_atomic_state *stat } EXPORT_SYMBOL(drm_atomic_helper_calc_timestamping_constants); -static void -crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *state) +/** + * drm_atomic_helper_commit_crtc_set_mode - set the new mode + * @dev: DRM device + * @state: the driver state object + * + * Loops over all connectors in the current state and if the mode has + * changed, change the mode of the CRTC, then call down the bridge + * chain and change the mode in all bridges as well. + */ +void +drm_atomic_helper_commit_crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *state) { struct drm_crtc *crtc; struct drm_crtc_state *new_crtc_state; @@ -1508,6 +1546,7 @@ crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *state) drm_bridge_put(bridge); } } +EXPORT_SYMBOL(drm_atomic_helper_commit_crtc_set_mode); /** * drm_atomic_helper_commit_modeset_disables - modeset commit to disable outputs @@ -1531,12 +1570,21 @@ void drm_atomic_helper_commit_modeset_disables(struct drm_device *dev, drm_atomic_helper_update_legacy_modeset_state(dev, state); drm_atomic_helper_calc_timestamping_constants(state); - crtc_set_mode(dev, state); + drm_atomic_helper_commit_crtc_set_mode(dev, state); } EXPORT_SYMBOL(drm_atomic_helper_commit_modeset_disables); -static void drm_atomic_helper_commit_writebacks(struct drm_device *dev, - struct drm_atomic_state *state) +/** + * drm_atomic_helper_commit_writebacks - issue writebacks + * @dev: DRM device + * @state: atomic state object being committed + * + * This loops over the connectors, checks if the new state requires + * a writeback job to be issued and in that case issues an atomic + * commit on each connector. + */ +void drm_atomic_helper_commit_writebacks(struct drm_device *dev, + struct drm_atomic_state *state) { struct drm_connector *connector; struct drm_connector_state *new_conn_state; @@ -1555,9 +1603,18 @@ static void drm_atomic_helper_commit_writebacks(struct drm_device *dev, } } } +EXPORT_SYMBOL(drm_atomic_helper_commit_writebacks); -static void -encoder_bridge_pre_enable(struct drm_device *dev, struct drm_atomic_state *state) +/** + * drm_atomic_helper_commit_encoder_bridge_pre_enable - pre-enable bridges + * @dev: DRM device + * @state: atomic state object being committed + * + * This loops over the connectors and if the CRTC needs it, pre-enables + * the entire bridge chain. + */ +void +drm_atomic_helper_commit_encoder_bridge_pre_enable(struct drm_device *dev, struct drm_atomic_state *state) { struct drm_connector *connector; struct drm_connector_state *new_conn_state; @@ -1588,9 +1645,18 @@ encoder_bridge_pre_enable(struct drm_device *dev, struct drm_atomic_state *state drm_bridge_put(bridge); } } +EXPORT_SYMBOL(drm_atomic_helper_commit_encoder_bridge_pre_enable); -static void -crtc_enable(struct drm_device *dev, struct drm_atomic_state *state) +/** + * drm_atomic_helper_commit_crtc_enable - enables the CRTCs + * @dev: DRM device + * @state: atomic state object being committed + * + * This loops over CRTCs in the new state, and of the CRTC needs + * it, enables it. + */ +void +drm_atomic_helper_commit_crtc_enable(struct drm_device *dev, struct drm_atomic_state *state) { struct drm_crtc *crtc; struct drm_crtc_state *old_crtc_state; @@ -1619,9 +1685,18 @@ crtc_enable(struct drm_device *dev, struct drm_atomic_state *state) } } } +EXPORT_SYMBOL(drm_atomic_helper_commit_crtc_enable); -static void -encoder_bridge_enable(struct drm_device *dev, struct drm_atomic_state *state) +/** + * drm_atomic_helper_commit_encoder_bridge_enable - enables the bridges + * @dev: DRM device + * @state: atomic state object being committed + * + * This loops over all connectors in the new state, and of the CRTC needs + * it, enables the entire bridge chain. + */ +void +drm_atomic_helper_commit_encoder_bridge_enable(struct drm_device *dev, struct drm_atomic_state *state) { struct drm_connector *connector; struct drm_connector_state *new_conn_state; @@ -1664,6 +1739,7 @@ encoder_bridge_enable(struct drm_device *dev, struct drm_atomic_state *state) drm_bridge_put(bridge); } } +EXPORT_SYMBOL(drm_atomic_helper_commit_encoder_bridge_enable); /** * drm_atomic_helper_commit_modeset_enables - modeset commit to enable outputs @@ -1682,11 +1758,11 @@ encoder_bridge_enable(struct drm_device *dev, struct drm_atomic_state *state) void drm_atomic_helper_commit_modeset_enables(struct drm_device *dev, struct drm_atomic_state *state) { - crtc_enable(dev, state); + drm_atomic_helper_commit_crtc_enable(dev, state); - encoder_bridge_pre_enable(dev, state); + drm_atomic_helper_commit_encoder_bridge_pre_enable(dev, state); - encoder_bridge_enable(dev, state); + drm_atomic_helper_commit_encoder_bridge_enable(dev, state); drm_atomic_helper_commit_writebacks(dev, state); } diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h index 53382fe93537b..e154ee4f0696c 100644 --- a/include/drm/drm_atomic_helper.h +++ b/include/drm/drm_atomic_helper.h @@ -60,6 +60,12 @@ int drm_atomic_helper_check_plane_state(struct drm_plane_state *plane_state, int drm_atomic_helper_check_planes(struct drm_device *dev, struct drm_atomic_state *state); int drm_atomic_helper_check_crtc_primary_plane(struct drm_crtc_state *crtc_state); +void drm_atomic_helper_commit_encoder_bridge_disable(struct drm_device *dev, + struct drm_atomic_state *state); +void drm_atomic_helper_commit_crtc_disable(struct drm_device *dev, + struct drm_atomic_state *state); +void drm_atomic_helper_commit_encoder_bridge_post_disable(struct drm_device *dev, + struct drm_atomic_state *state); int drm_atomic_helper_check(struct drm_device *dev, struct drm_atomic_state *state); void drm_atomic_helper_commit_tail(struct drm_atomic_state *state); @@ -89,8 +95,24 @@ drm_atomic_helper_update_legacy_modeset_state(struct drm_device *dev, void drm_atomic_helper_calc_timestamping_constants(struct drm_atomic_state *state); +void drm_atomic_helper_commit_crtc_set_mode(struct drm_device *dev, + struct drm_atomic_state *state); + void drm_atomic_helper_commit_modeset_disables(struct drm_device *dev, struct drm_atomic_state *state); + +void drm_atomic_helper_commit_writebacks(struct drm_device *dev, + struct drm_atomic_state *state); + +void drm_atomic_helper_commit_encoder_bridge_pre_enable(struct drm_device *dev, + struct drm_atomic_state *state); + +void drm_atomic_helper_commit_crtc_enable(struct drm_device *dev, + struct drm_atomic_state *state); + +void drm_atomic_helper_commit_encoder_bridge_enable(struct drm_device *dev, + struct drm_atomic_state *state); + void drm_atomic_helper_commit_modeset_enables(struct drm_device *dev, struct drm_atomic_state *old_state); From 124b9d19e1d5013b821ce1a50b6f6e873b06d7ed Mon Sep 17 00:00:00 2001 From: Miaoqian Lin Date: Thu, 11 Dec 2025 16:33:44 +0400 Subject: [PATCH 1795/2333] drm/pl111: Fix error handling in pl111_amba_probe commit 0ddd3bb4b14c9102c0267b3fd916c81fe5ab89c1 upstream. Jump to the existing dev_put label when devm_request_irq() fails so drm_dev_put() and of_reserved_mem_device_release() run instead of returning early and leaking resources. Found via static analysis and code review. Fixes: bed41005e617 ("drm/pl111: Initial drm/kms driver for pl111") Cc: stable@vger.kernel.org Signed-off-by: Miaoqian Lin Reviewed-by: Javier Martinez Canillas Signed-off-by: Linus Walleij Link: https://patch.msgid.link/20251211123345.2392065-1-linmq006@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/pl111/pl111_drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/pl111/pl111_drv.c b/drivers/gpu/drm/pl111/pl111_drv.c index 56ff6a3fb4834..d7dc83cf7b00a 100644 --- a/drivers/gpu/drm/pl111/pl111_drv.c +++ b/drivers/gpu/drm/pl111/pl111_drv.c @@ -295,7 +295,7 @@ static int pl111_amba_probe(struct amba_device *amba_dev, variant->name, priv); if (ret != 0) { dev_err(dev, "%s failed irq %d\n", __func__, ret); - return ret; + goto dev_put; } ret = pl111_modeset_init(drm); From 227997d16a535822efb5ac8e7209cea3ae334b89 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Fri, 5 Dec 2025 11:51:51 +0200 Subject: [PATCH 1796/2333] drm/tidss: Fix enable/disable order commit 2fc04340cf30d7960eed2525d26ffb8905aca02b upstream. TI's OLDI and DSI encoders need to be set up before the crtc is enabled, but the DRM helpers will enable the crtc first. This causes various issues on TI platforms, like visual artifacts or crtc sync lost warnings. Thus drm_atomic_helper_commit_modeset_enables() and drm_atomic_helper_commit_modeset_disables() cannot be used, as they enable the crtc before bridges' pre-enable, and disable the crtc after bridges' post-disable. Open code the drm_atomic_helper_commit_modeset_enables() and drm_atomic_helper_commit_modeset_disables(), and first call the bridges' pre-enables, then crtc enable, then bridges' post-enable (and vice versa for disable). Signed-off-by: Tomi Valkeinen Cc: stable@vger.kernel.org # v6.17+ Fixes: c9b1150a68d9 ("drm/atomic-helper: Re-order bridge chain pre-enable and post-disable") Reviewed-by: Aradhya Bhatia Reviewed-by: Maxime Ripard Reviewed-by: Linus Walleij Tested-by: Linus Walleij Signed-off-by: Linus Walleij Link: https://patch.msgid.link/20251205-drm-seq-fix-v1-4-fda68fa1b3de@ideasonboard.com Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/tidss/tidss_kms.c | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/tidss/tidss_kms.c b/drivers/gpu/drm/tidss/tidss_kms.c index c34eb90cddbea..9f5f98e707f2c 100644 --- a/drivers/gpu/drm/tidss/tidss_kms.c +++ b/drivers/gpu/drm/tidss/tidss_kms.c @@ -28,9 +28,33 @@ static void tidss_atomic_commit_tail(struct drm_atomic_state *old_state) tidss_runtime_get(tidss); - drm_atomic_helper_commit_modeset_disables(ddev, old_state); - drm_atomic_helper_commit_planes(ddev, old_state, DRM_PLANE_COMMIT_ACTIVE_ONLY); - drm_atomic_helper_commit_modeset_enables(ddev, old_state); + /* + * TI's OLDI and DSI encoders need to be set up before the crtc is + * enabled. Thus drm_atomic_helper_commit_modeset_enables() and + * drm_atomic_helper_commit_modeset_disables() cannot be used here, as + * they enable the crtc before bridges' pre-enable, and disable the crtc + * after bridges' post-disable. + * + * Open code the functions here and first call the bridges' pre-enables, + * then crtc enable, then bridges' post-enable (and vice versa for + * disable). + */ + + drm_atomic_helper_commit_encoder_bridge_disable(ddev, old_state); + drm_atomic_helper_commit_crtc_disable(ddev, old_state); + drm_atomic_helper_commit_encoder_bridge_post_disable(ddev, old_state); + + drm_atomic_helper_update_legacy_modeset_state(ddev, old_state); + drm_atomic_helper_calc_timestamping_constants(old_state); + drm_atomic_helper_commit_crtc_set_mode(ddev, old_state); + + drm_atomic_helper_commit_planes(ddev, old_state, + DRM_PLANE_COMMIT_ACTIVE_ONLY); + + drm_atomic_helper_commit_encoder_bridge_pre_enable(ddev, old_state); + drm_atomic_helper_commit_crtc_enable(ddev, old_state); + drm_atomic_helper_commit_encoder_bridge_enable(ddev, old_state); + drm_atomic_helper_commit_writebacks(ddev, old_state); drm_atomic_helper_commit_hw_done(old_state); drm_atomic_helper_wait_for_flip_done(ddev, old_state); From b88191562d92ca1ba6b5a06baec8a288531fa801 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 30 Jun 2025 10:47:09 -0400 Subject: [PATCH 1797/2333] drm/radeon: Remove __counted_by from ClockInfoArray.clockInfo[] commit 19158c7332468bc28572bdca428e89c7954ee1b1 upstream. clockInfo[] is a generic uchar pointer to variable sized structures which vary from ASIC to ASIC. Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/4374 Reviewed-by: Lijo Lazar Signed-off-by: Alex Deucher (cherry picked from commit dc135aa73561b5acc74eadf776e48530996529a3) Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/pptable.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/radeon/pptable.h b/drivers/gpu/drm/radeon/pptable.h index 969a8fb0ee9e0..f4e71046dc91c 100644 --- a/drivers/gpu/drm/radeon/pptable.h +++ b/drivers/gpu/drm/radeon/pptable.h @@ -450,7 +450,7 @@ typedef struct _ClockInfoArray{ //sizeof(ATOM_PPLIB_CLOCK_INFO) UCHAR ucEntrySize; - UCHAR clockInfo[] __counted_by(ucNumEntries); + UCHAR clockInfo[] /*__counted_by(ucNumEntries)*/; }ClockInfoArray; typedef struct _NonClockInfoArray{ From 3aa67687d5582e4fac911a041d375708766ff15a Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Tue, 6 Jan 2026 10:00:11 +0100 Subject: [PATCH 1798/2333] gpio: rockchip: mark the GPIO controller as sleeping commit 20cf2aed89ac6d78a0122e31c875228e15247194 upstream. The GPIO controller is configured as non-sleeping but it uses generic pinctrl helpers which use a mutex for synchronization. This can cause the following lockdep splat with shared GPIOs enabled on boards which have multiple devices using the same GPIO: BUG: sleeping function called from invalid context at kernel/locking/mutex.c:591 in_atomic(): 1, irqs_disabled(): 1, non_block: 0, pid: 12, name: kworker/u16:0 preempt_count: 1, expected: 0 RCU nest depth: 0, expected: 0 6 locks held by kworker/u16:0/12: #0: ffff0001f0018d48 ((wq_completion)events_unbound#2){+.+.}-{0:0}, at: process_one_work+0x18c/0x604 #1: ffff8000842dbdf0 (deferred_probe_work){+.+.}-{0:0}, at: process_one_work+0x1b4/0x604 #2: ffff0001f18498f8 (&dev->mutex){....}-{4:4}, at: __device_attach+0x38/0x1b0 #3: ffff0001f75f1e90 (&gdev->srcu){.+.?}-{0:0}, at: gpiod_direction_output_raw_commit+0x0/0x360 #4: ffff0001f46e3db8 (&shared_desc->spinlock){....}-{3:3}, at: gpio_shared_proxy_direction_output+0xd0/0x144 [gpio_shared_proxy] #5: ffff0001f180ee90 (&gdev->srcu){.+.?}-{0:0}, at: gpiod_direction_output_raw_commit+0x0/0x360 irq event stamp: 81450 hardirqs last enabled at (81449): [] _raw_spin_unlock_irqrestore+0x74/0x78 hardirqs last disabled at (81450): [] _raw_spin_lock_irqsave+0x84/0x88 softirqs last enabled at (79616): [] __alloc_skb+0x17c/0x1e8 softirqs last disabled at (79614): [] __alloc_skb+0x17c/0x1e8 CPU: 2 UID: 0 PID: 12 Comm: kworker/u16:0 Not tainted 6.19.0-rc4-next-20260105+ #11975 PREEMPT Hardware name: Hardkernel ODROID-M1 (DT) Workqueue: events_unbound deferred_probe_work_func Call trace: show_stack+0x18/0x24 (C) dump_stack_lvl+0x90/0xd0 dump_stack+0x18/0x24 __might_resched+0x144/0x248 __might_sleep+0x48/0x98 __mutex_lock+0x5c/0x894 mutex_lock_nested+0x24/0x30 pinctrl_get_device_gpio_range+0x44/0x128 pinctrl_gpio_direction+0x3c/0xe0 pinctrl_gpio_direction_output+0x14/0x20 rockchip_gpio_direction_output+0xb8/0x19c gpiochip_direction_output+0x38/0x94 gpiod_direction_output_raw_commit+0x1d8/0x360 gpiod_direction_output_nonotify+0x7c/0x230 gpiod_direction_output+0x34/0xf8 gpio_shared_proxy_direction_output+0xec/0x144 [gpio_shared_proxy] gpiochip_direction_output+0x38/0x94 gpiod_direction_output_raw_commit+0x1d8/0x360 gpiod_direction_output_nonotify+0x7c/0x230 gpiod_configure_flags+0xbc/0x480 gpiod_find_and_request+0x1a0/0x574 gpiod_get_index+0x58/0x84 devm_gpiod_get_index+0x20/0xb4 devm_gpiod_get_optional+0x18/0x30 rockchip_pcie_probe+0x98/0x380 platform_probe+0x5c/0xac really_probe+0xbc/0x298 Fixes: 936ee2675eee ("gpio/rockchip: add driver for rockchip gpio") Cc: stable@vger.kernel.org Reported-by: Marek Szyprowski Closes: https://lore.kernel.org/all/d035fc29-3b03-4cd6-b8ec-001f93540bc6@samsung.com/ Acked-by: Heiko Stuebner Link: https://lore.kernel.org/r/20260106090011.21603-1-bartosz.golaszewski@oss.qualcomm.com Signed-off-by: Bartosz Golaszewski Signed-off-by: Greg Kroah-Hartman --- drivers/gpio/gpio-rockchip.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpio/gpio-rockchip.c b/drivers/gpio/gpio-rockchip.c index 47174eb3ba76f..bae2061f15fc4 100644 --- a/drivers/gpio/gpio-rockchip.c +++ b/drivers/gpio/gpio-rockchip.c @@ -593,6 +593,7 @@ static int rockchip_gpiolib_register(struct rockchip_pin_bank *bank) gc->ngpio = bank->nr_pins; gc->label = bank->name; gc->parent = bank->dev; + gc->can_sleep = true; ret = gpiochip_add_data(gc, bank); if (ret) { From 2b9c15286a178190e5bc7ee0a1b200c38953fdf4 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Mon, 5 Jan 2026 07:42:48 -0700 Subject: [PATCH 1799/2333] io_uring/io-wq: fix incorrect io_wq_for_each_worker() termination logic commit e0392a10c9e80a3991855a81317da3039fcbe32c upstream. A previous commit added this helper, and had it terminate if false is returned from the handler. However, that is completely opposite, it should abort the loop if true is returned. Fix this up by having io_wq_for_each_worker() keep iterating as long as false is returned, and only abort if true is returned. Cc: stable@vger.kernel.org Fixes: 751eedc4b4b7 ("io_uring/io-wq: move worker lists to struct io_wq_acct") Reported-by: Lewis Campbell Reviewed-by: Gabriel Krisman Bertazi Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman --- io_uring/io-wq.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/io_uring/io-wq.c b/io_uring/io-wq.c index 1d03b2fc4b259..55961da19f3b1 100644 --- a/io_uring/io-wq.c +++ b/io_uring/io-wq.c @@ -951,11 +951,11 @@ static bool io_wq_for_each_worker(struct io_wq *wq, void *data) { for (int i = 0; i < IO_WQ_ACCT_NR; i++) { - if (!io_acct_for_each_worker(&wq->acct[i], func, data)) - return false; + if (io_acct_for_each_worker(&wq->acct[i], func, data)) + return true; } - return true; + return false; } static bool io_wq_worker_wake(struct io_worker *worker, void *data) From 391adca8e2135a9af701a9bec9c843cc4c48cc43 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Mon, 3 Nov 2025 16:19:26 -0600 Subject: [PATCH 1800/2333] PCI: meson: Report that link is up while in ASPM L0s and L1 states commit df27c03b9e3ef2baa9e9c9f56a771d463a84489d upstream. Previously meson_pcie_link_up() only returned true if the link was in the L0 state. This was incorrect because hardware autonomously manages transitions between L0, L0s, and L1 while both components on the link stay in D0. Those states should all be treated as "link is active". Returning false when the device was in L0s or L1 broke config accesses because dw_pcie_other_conf_map_bus() fails if the link is down, which caused errors like this: meson-pcie fc000000.pcie: error: wait linkup timeout pci 0000:01:00.0: BAR 0: error updating (0xfc700004 != 0xffffffff) Remove the LTSSM state check, timeout, speed check, and error message from meson_pcie_link_up(), the dw_pcie_ops.link_up() method, so it is a simple boolean check of whether the link is active. Timeouts and error messages are handled at a higher level, e.g., dw_pcie_wait_for_link(). Fixes: 9c0ef6d34fdb ("PCI: amlogic: Add the Amlogic Meson PCIe controller driver") Reported-by: Linnaea Lavia Closes: https://lore.kernel.org/r/DM4PR05MB102707B8CDF84D776C39F22F2C7F0A@DM4PR05MB10270.namprd05.prod.outlook.com [bhelgaas: squash removal of unused WAIT_LINKUP_TIMEOUT by Martin Blumenstingl : https://patch.msgid.link/20260105125625.239497-1-martin.blumenstingl@googlemail.com] Signed-off-by: Bjorn Helgaas Tested-by: Linnaea Lavia Tested-by: Neil Armstrong # on BananaPi M2S Reviewed-by: Neil Armstrong Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20251103221930.1831376-1-helgaas@kernel.org Link: https://patch.msgid.link/20260105125625.239497-1-martin.blumenstingl@googlemail.com Signed-off-by: Greg Kroah-Hartman --- drivers/pci/controller/dwc/pci-meson.c | 39 +++----------------------- 1 file changed, 4 insertions(+), 35 deletions(-) diff --git a/drivers/pci/controller/dwc/pci-meson.c b/drivers/pci/controller/dwc/pci-meson.c index 54b6a4196f176..0694084f612b7 100644 --- a/drivers/pci/controller/dwc/pci-meson.c +++ b/drivers/pci/controller/dwc/pci-meson.c @@ -37,7 +37,6 @@ #define PCIE_CFG_STATUS17 0x44 #define PM_CURRENT_STATE(x) (((x) >> 7) & 0x1) -#define WAIT_LINKUP_TIMEOUT 4000 #define PORT_CLK_RATE 100000000UL #define MAX_PAYLOAD_SIZE 256 #define MAX_READ_REQ_SIZE 256 @@ -350,40 +349,10 @@ static struct pci_ops meson_pci_ops = { static bool meson_pcie_link_up(struct dw_pcie *pci) { struct meson_pcie *mp = to_meson_pcie(pci); - struct device *dev = pci->dev; - u32 speed_okay = 0; - u32 cnt = 0; - u32 state12, state17, smlh_up, ltssm_up, rdlh_up; - - do { - state12 = meson_cfg_readl(mp, PCIE_CFG_STATUS12); - state17 = meson_cfg_readl(mp, PCIE_CFG_STATUS17); - smlh_up = IS_SMLH_LINK_UP(state12); - rdlh_up = IS_RDLH_LINK_UP(state12); - ltssm_up = IS_LTSSM_UP(state12); - - if (PM_CURRENT_STATE(state17) < PCIE_GEN3) - speed_okay = 1; - - if (smlh_up) - dev_dbg(dev, "smlh_link_up is on\n"); - if (rdlh_up) - dev_dbg(dev, "rdlh_link_up is on\n"); - if (ltssm_up) - dev_dbg(dev, "ltssm_up is on\n"); - if (speed_okay) - dev_dbg(dev, "speed_okay\n"); - - if (smlh_up && rdlh_up && ltssm_up && speed_okay) - return true; - - cnt++; - - udelay(10); - } while (cnt < WAIT_LINKUP_TIMEOUT); - - dev_err(dev, "error: wait linkup timeout\n"); - return false; + u32 state12; + + state12 = meson_cfg_readl(mp, PCIE_CFG_STATUS12); + return IS_SMLH_LINK_UP(state12) && IS_RDLH_LINK_UP(state12); } static int meson_pcie_host_init(struct dw_pcie_rp *pp) From ea7a54393d50c60943c71f15e607d8fac0c686fc Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Wed, 26 Nov 2025 13:22:19 +0100 Subject: [PATCH 1801/2333] pinctrl: qcom: lpass-lpi: mark the GPIO controller as sleeping commit ebc18e9854e5a2b62a041fb57b216a903af45b85 upstream. The gpio_chip settings in this driver say the controller can't sleep but it actually uses a mutex for synchronization. This triggers the following BUG(): [ 9.233659] BUG: sleeping function called from invalid context at kernel/locking/mutex.c:281 [ 9.233665] in_atomic(): 1, irqs_disabled(): 1, non_block: 0, pid: 554, name: (udev-worker) [ 9.233669] preempt_count: 1, expected: 0 [ 9.233673] RCU nest depth: 0, expected: 0 [ 9.233688] Tainted: [W]=WARN [ 9.233690] Hardware name: Dell Inc. Latitude 7455/0FK7MX, BIOS 2.10.1 05/20/2025 [ 9.233694] Call trace: [ 9.233696] show_stack+0x24/0x38 (C) [ 9.233709] dump_stack_lvl+0x40/0x88 [ 9.233716] dump_stack+0x18/0x24 [ 9.233722] __might_resched+0x148/0x160 [ 9.233731] __might_sleep+0x38/0x98 [ 9.233736] mutex_lock+0x30/0xd8 [ 9.233749] lpi_config_set+0x2e8/0x3c8 [pinctrl_lpass_lpi] [ 9.233757] lpi_gpio_direction_output+0x58/0x90 [pinctrl_lpass_lpi] [ 9.233761] gpiod_direction_output_raw_commit+0x110/0x428 [ 9.233772] gpiod_direction_output_nonotify+0x234/0x358 [ 9.233779] gpiod_direction_output+0x38/0xd0 [ 9.233786] gpio_shared_proxy_direction_output+0xb8/0x2a8 [gpio_shared_proxy] [ 9.233792] gpiod_direction_output_raw_commit+0x110/0x428 [ 9.233799] gpiod_direction_output_nonotify+0x234/0x358 [ 9.233806] gpiod_configure_flags+0x2c0/0x580 [ 9.233812] gpiod_find_and_request+0x358/0x4f8 [ 9.233819] gpiod_get_index+0x7c/0x98 [ 9.233826] devm_gpiod_get+0x34/0xb0 [ 9.233829] reset_gpio_probe+0x58/0x128 [reset_gpio] [ 9.233836] auxiliary_bus_probe+0xb0/0xf0 [ 9.233845] really_probe+0x14c/0x450 [ 9.233853] __driver_probe_device+0xb0/0x188 [ 9.233858] driver_probe_device+0x4c/0x250 [ 9.233863] __driver_attach+0xf8/0x2a0 [ 9.233868] bus_for_each_dev+0xf8/0x158 [ 9.233872] driver_attach+0x30/0x48 [ 9.233876] bus_add_driver+0x158/0x2b8 [ 9.233880] driver_register+0x74/0x118 [ 9.233886] __auxiliary_driver_register+0x94/0xe8 [ 9.233893] init_module+0x34/0xfd0 [reset_gpio] [ 9.233898] do_one_initcall+0xec/0x300 [ 9.233903] do_init_module+0x64/0x260 [ 9.233910] load_module+0x16c4/0x1900 [ 9.233915] __arm64_sys_finit_module+0x24c/0x378 [ 9.233919] invoke_syscall+0x4c/0xe8 [ 9.233925] el0_svc_common+0x8c/0xf0 [ 9.233929] do_el0_svc+0x28/0x40 [ 9.233934] el0_svc+0x38/0x100 [ 9.233938] el0t_64_sync_handler+0x84/0x130 [ 9.233943] el0t_64_sync+0x17c/0x180 Mark the controller as sleeping. Fixes: 6e261d1090d6 ("pinctrl: qcom: Add sm8250 lpass lpi pinctrl driver") Cc: stable@vger.kernel.org Reported-by: Val Packett Closes: https://lore.kernel.org/all/98c0f185-b0e0-49ea-896c-f3972dd011ca@packett.cool/ Signed-off-by: Bartosz Golaszewski Reviewed-by: Dmitry Baryshkov Reviewed-by: Bjorn Andersson Signed-off-by: Linus Walleij Signed-off-by: Greg Kroah-Hartman --- drivers/pinctrl/qcom/pinctrl-lpass-lpi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pinctrl/qcom/pinctrl-lpass-lpi.c b/drivers/pinctrl/qcom/pinctrl-lpass-lpi.c index 1c97ec44aa5ff..78212f9928430 100644 --- a/drivers/pinctrl/qcom/pinctrl-lpass-lpi.c +++ b/drivers/pinctrl/qcom/pinctrl-lpass-lpi.c @@ -498,7 +498,7 @@ int lpi_pinctrl_probe(struct platform_device *pdev) pctrl->chip.base = -1; pctrl->chip.ngpio = data->npins; pctrl->chip.label = dev_name(dev); - pctrl->chip.can_sleep = false; + pctrl->chip.can_sleep = true; mutex_init(&pctrl->lock); From b7a883b0135dbc6817e90a829421c9fc8cd94bad Mon Sep 17 00:00:00 2001 From: Malaya Kumar Rout Date: Tue, 30 Dec 2025 17:26:13 +0530 Subject: [PATCH 1802/2333] PM: hibernate: Fix crash when freeing invalid crypto compressor commit 7966cf0ebe32c981bfa3db252cb5fc3bb1bf2e77 upstream. When crypto_alloc_acomp() fails, it returns an ERR_PTR value, not NULL. The cleanup code in save_compressed_image() and load_compressed_image() unconditionally calls crypto_free_acomp() without checking for ERR_PTR, which causes crypto_acomp_tfm() to dereference an invalid pointer and crash the kernel. This can be triggered when the compression algorithm is unavailable (e.g., CONFIG_CRYPTO_LZO not enabled). Fix by adding IS_ERR_OR_NULL() checks before calling crypto_free_acomp() and acomp_request_free(), similar to the existing kthread_stop() check. Fixes: b03d542c3c95 ("PM: hibernate: Use crypto_acomp interface") Signed-off-by: Malaya Kumar Rout Cc: 6.15+ # 6.15+ [ rjw: Added 2 empty code lines ] Link: https://patch.msgid.link/20251230115613.64080-1-mrout@redhat.com Signed-off-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman --- kernel/power/swap.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/kernel/power/swap.c b/kernel/power/swap.c index 70ae21f7370d4..f910a250ccddb 100644 --- a/kernel/power/swap.c +++ b/kernel/power/swap.c @@ -897,8 +897,11 @@ static int save_compressed_image(struct swap_map_handle *handle, for (thr = 0; thr < nr_threads; thr++) { if (data[thr].thr) kthread_stop(data[thr].thr); - acomp_request_free(data[thr].cr); - crypto_free_acomp(data[thr].cc); + if (data[thr].cr) + acomp_request_free(data[thr].cr); + + if (!IS_ERR_OR_NULL(data[thr].cc)) + crypto_free_acomp(data[thr].cc); } vfree(data); } @@ -1519,8 +1522,11 @@ static int load_compressed_image(struct swap_map_handle *handle, for (thr = 0; thr < nr_threads; thr++) { if (data[thr].thr) kthread_stop(data[thr].thr); - acomp_request_free(data[thr].cr); - crypto_free_acomp(data[thr].cc); + if (data[thr].cr) + acomp_request_free(data[thr].cr); + + if (!IS_ERR_OR_NULL(data[thr].cc)) + crypto_free_acomp(data[thr].cc); } vfree(data); } From 5c12a13522f45f4ce0c22c2715879234e38bc12b Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Fri, 5 Dec 2025 11:51:49 +0200 Subject: [PATCH 1803/2333] Revert "drm/mediatek: dsi: Fix DSI host and panel bridge pre-enable order" commit 33e8150bd32d7dc25c977bb455f1f5d54bfd5241 upstream. This reverts commit f5b1819193667bf62c3c99d3921b9429997a14b2. As the original commit (c9b1150a68d9 ("drm/atomic-helper: Re-order bridge chain pre-enable and post-disable")) causing the issue has been reverted, let's revert the fix for mediatek. Signed-off-by: Tomi Valkeinen Cc: stable@vger.kernel.org # v6.17+ Fixes: c9b1150a68d9 ("drm/atomic-helper: Re-order bridge chain pre-enable and post-disable") Reviewed-by: Maxime Ripard Reviewed-by: Linus Walleij Tested-by: Linus Walleij Signed-off-by: Linus Walleij Link: https://patch.msgid.link/20251205-drm-seq-fix-v1-2-fda68fa1b3de@ideasonboard.com Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/mediatek/mtk_dsi.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c b/drivers/gpu/drm/mediatek/mtk_dsi.c index 0e2bcd5f67b76..d7726091819c4 100644 --- a/drivers/gpu/drm/mediatek/mtk_dsi.c +++ b/drivers/gpu/drm/mediatek/mtk_dsi.c @@ -1002,12 +1002,6 @@ static int mtk_dsi_host_attach(struct mipi_dsi_host *host, return PTR_ERR(dsi->next_bridge); } - /* - * set flag to request the DSI host bridge be pre-enabled before device bridge - * in the chain, so the DSI host is ready when the device bridge is pre-enabled - */ - dsi->next_bridge->pre_enable_prev_first = true; - drm_bridge_add(&dsi->bridge); ret = component_add(host->dev, &mtk_dsi_component_ops); From e3c35177103ead4658b8a62f41e3080d45885464 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 8 Jan 2026 10:19:27 +0000 Subject: [PATCH 1804/2333] wifi: avoid kernel-infoleak from struct iw_point commit 21cbf883d073abbfe09e3924466aa5e0449e7261 upstream. struct iw_point has a 32bit hole on 64bit arches. struct iw_point { void __user *pointer; /* Pointer to the data (in user space) */ __u16 length; /* number of fields or size in bytes */ __u16 flags; /* Optional params */ }; Make sure to zero the structure to avoid disclosing 32bits of kernel data to user space. Fixes: 87de87d5e47f ("wext: Dispatch and handle compat ioctls entirely in net/wireless/wext.c") Reported-by: syzbot+bfc7323743ca6dbcc3d3@syzkaller.appspotmail.com Closes: https://lore.kernel.org/netdev/695f83f3.050a0220.1c677c.0392.GAE@google.com/T/#u Signed-off-by: Eric Dumazet Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20260108101927.857582-1-edumazet@google.com Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman --- net/wireless/wext-core.c | 4 ++++ net/wireless/wext-priv.c | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/net/wireless/wext-core.c b/net/wireless/wext-core.c index c32a7c6903d53..7b8e94214b072 100644 --- a/net/wireless/wext-core.c +++ b/net/wireless/wext-core.c @@ -1101,6 +1101,10 @@ static int compat_standard_call(struct net_device *dev, return ioctl_standard_call(dev, iwr, cmd, info, handler); iwp_compat = (struct compat_iw_point *) &iwr->u.data; + + /* struct iw_point has a 32bit hole on 64bit arches. */ + memset(&iwp, 0, sizeof(iwp)); + iwp.pointer = compat_ptr(iwp_compat->pointer); iwp.length = iwp_compat->length; iwp.flags = iwp_compat->flags; diff --git a/net/wireless/wext-priv.c b/net/wireless/wext-priv.c index 674d426a9d24f..37d1147019c2b 100644 --- a/net/wireless/wext-priv.c +++ b/net/wireless/wext-priv.c @@ -228,6 +228,10 @@ int compat_private_call(struct net_device *dev, struct iwreq *iwr, struct iw_point iwp; iwp_compat = (struct compat_iw_point *) &iwr->u.data; + + /* struct iw_point has a 32bit hole on 64bit arches. */ + memset(&iwp, 0, sizeof(iwp)); + iwp.pointer = compat_ptr(iwp_compat->pointer); iwp.length = iwp_compat->length; iwp.flags = iwp_compat->flags; From b97be67dc06ef480ba48c8194fa11697760f7f4a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 16 Dec 2025 11:52:42 +0100 Subject: [PATCH 1805/2333] wifi: mac80211: restore non-chanctx injection behaviour commit d594cc6f2c588810888df70c83a9654b6bc7942d upstream. During the transition to use channel contexts throughout, the ability to do injection while in monitor mode concurrent with another interface was lost, since the (virtual) monitor won't have a chanctx assigned in this scenario. It's harder to fix drivers that actually transitioned to using channel contexts themselves, such as mt76, but it's easy to do those that are (still) just using the emulation. Do that. Cc: stable@vger.kernel.org Link: https://bugzilla.kernel.org/show_bug.cgi?id=218763 Reported-and-tested-by: Oscar Alfonso Diaz Fixes: 0a44dfc07074 ("wifi: mac80211: simplify non-chanctx drivers") Link: https://patch.msgid.link/20251216105242.18366-2-johannes@sipsolutions.net Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman --- net/mac80211/tx.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index e7b141c55f7a9..160667be3f4d2 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -2395,6 +2395,8 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb, if (chanctx_conf) chandef = &chanctx_conf->def; + else if (local->emulate_chanctx) + chandef = &local->hw.conf.chandef; else goto fail_rcu; From 2d653bb63d598ae4b096dd678744bdcc34ee89e8 Mon Sep 17 00:00:00 2001 From: ziming zhang Date: Thu, 11 Dec 2025 16:52:58 +0800 Subject: [PATCH 1806/2333] libceph: prevent potential out-of-bounds reads in handle_auth_done() commit 818156caffbf55cb4d368f9c3cac64e458fb49c9 upstream. Perform an explicit bounds check on payload_len to avoid a possible out-of-bounds access in the callout. [ idryomov: changelog ] Cc: stable@vger.kernel.org Signed-off-by: ziming zhang Reviewed-by: Ilya Dryomov Signed-off-by: Ilya Dryomov Signed-off-by: Greg Kroah-Hartman --- net/ceph/messenger_v2.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/ceph/messenger_v2.c b/net/ceph/messenger_v2.c index 9e48623018a36..061eaa047f765 100644 --- a/net/ceph/messenger_v2.c +++ b/net/ceph/messenger_v2.c @@ -2377,7 +2377,9 @@ static int process_auth_done(struct ceph_connection *con, void *p, void *end) ceph_decode_64_safe(&p, end, global_id, bad); ceph_decode_32_safe(&p, end, con->v2.con_mode, bad); + ceph_decode_32_safe(&p, end, payload_len, bad); + ceph_decode_need(&p, end, payload_len, bad); dout("%s con %p global_id %llu con_mode %d payload_len %d\n", __func__, con, global_id, con->v2.con_mode, payload_len); From 6348d70af847b79805374fe628d3809a63fd7df3 Mon Sep 17 00:00:00 2001 From: Ilya Dryomov Date: Mon, 15 Dec 2025 11:53:31 +0100 Subject: [PATCH 1807/2333] libceph: replace overzealous BUG_ON in osdmap_apply_incremental() commit e00c3f71b5cf75681dbd74ee3f982a99cb690c2b upstream. If the osdmap is (maliciously) corrupted such that the incremental osdmap epoch is different from what is expected, there is no need to BUG. Instead, just declare the incremental osdmap to be invalid. Cc: stable@vger.kernel.org Reported-by: ziming zhang Signed-off-by: Ilya Dryomov Signed-off-by: Greg Kroah-Hartman --- net/ceph/osdmap.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/ceph/osdmap.c b/net/ceph/osdmap.c index f5f60deb680ae..0722e9347a646 100644 --- a/net/ceph/osdmap.c +++ b/net/ceph/osdmap.c @@ -1979,11 +1979,13 @@ struct ceph_osdmap *osdmap_apply_incremental(void **p, void *end, bool msgr2, sizeof(u64) + sizeof(u32), e_inval); ceph_decode_copy(p, &fsid, sizeof(fsid)); epoch = ceph_decode_32(p); - BUG_ON(epoch != map->epoch+1); ceph_decode_copy(p, &modified, sizeof(modified)); new_pool_max = ceph_decode_64(p); new_flags = ceph_decode_32(p); + if (epoch != map->epoch + 1) + goto e_inval; + /* full map? */ ceph_decode_32_safe(p, end, len, e_inval); if (len > 0) { From f21c3fdb96833aac2f533506899fe38c19cf49d5 Mon Sep 17 00:00:00 2001 From: Tuo Li Date: Sun, 21 Dec 2025 02:11:49 +0800 Subject: [PATCH 1808/2333] libceph: make free_choose_arg_map() resilient to partial allocation commit e3fe30e57649c551757a02e1cad073c47e1e075e upstream. free_choose_arg_map() may dereference a NULL pointer if its caller fails after a partial allocation. For example, in decode_choose_args(), if allocation of arg_map->args fails, execution jumps to the fail label and free_choose_arg_map() is called. Since arg_map->size is updated to a non-zero value before memory allocation, free_choose_arg_map() will iterate over arg_map->args and dereference a NULL pointer. To prevent this potential NULL pointer dereference and make free_choose_arg_map() more resilient, add checks for pointers before iterating. Cc: stable@vger.kernel.org Co-authored-by: Ilya Dryomov Signed-off-by: Tuo Li Reviewed-by: Viacheslav Dubeyko Signed-off-by: Ilya Dryomov Signed-off-by: Greg Kroah-Hartman --- net/ceph/osdmap.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/net/ceph/osdmap.c b/net/ceph/osdmap.c index 0722e9347a646..7c76eb9d6ceec 100644 --- a/net/ceph/osdmap.c +++ b/net/ceph/osdmap.c @@ -241,22 +241,26 @@ static struct crush_choose_arg_map *alloc_choose_arg_map(void) static void free_choose_arg_map(struct crush_choose_arg_map *arg_map) { - if (arg_map) { - int i, j; + int i, j; + + if (!arg_map) + return; - WARN_ON(!RB_EMPTY_NODE(&arg_map->node)); + WARN_ON(!RB_EMPTY_NODE(&arg_map->node)); + if (arg_map->args) { for (i = 0; i < arg_map->size; i++) { struct crush_choose_arg *arg = &arg_map->args[i]; - - for (j = 0; j < arg->weight_set_size; j++) - kfree(arg->weight_set[j].weights); - kfree(arg->weight_set); + if (arg->weight_set) { + for (j = 0; j < arg->weight_set_size; j++) + kfree(arg->weight_set[j].weights); + kfree(arg->weight_set); + } kfree(arg->ids); } kfree(arg_map->args); - kfree(arg_map); } + kfree(arg_map); } DEFINE_RB_FUNCS(choose_arg_map, struct crush_choose_arg_map, choose_args_index, From 9e0101e57534ef0e7578dd09608a6106736b82e5 Mon Sep 17 00:00:00 2001 From: Ilya Dryomov Date: Mon, 29 Dec 2025 15:14:48 +0100 Subject: [PATCH 1809/2333] libceph: return the handler error from mon_handle_auth_done() commit e84b48d31b5008932c0a0902982809fbaa1d3b70 upstream. Currently any error from ceph_auth_handle_reply_done() is propagated via finish_auth() but isn't returned from mon_handle_auth_done(). This results in higher layers learning that (despite the monitor considering us to be successfully authenticated) something went wrong in the authentication phase and reacting accordingly, but msgr2 still trying to proceed with establishing the session in the background. In the case of secure mode this can trigger a WARN in setup_crypto() and later lead to a NULL pointer dereference inside of prepare_auth_signature(). Cc: stable@vger.kernel.org Fixes: cd1a677cad99 ("libceph, ceph: implement msgr2.1 protocol (crc and secure modes)") Signed-off-by: Ilya Dryomov Reviewed-by: Viacheslav Dubeyko Signed-off-by: Greg Kroah-Hartman --- net/ceph/mon_client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ceph/mon_client.c b/net/ceph/mon_client.c index c227ececa9254..fa8dd2a20f7d2 100644 --- a/net/ceph/mon_client.c +++ b/net/ceph/mon_client.c @@ -1417,7 +1417,7 @@ static int mon_handle_auth_done(struct ceph_connection *con, if (!ret) finish_hunting(monc); mutex_unlock(&monc->mutex); - return 0; + return ret; } static int mon_handle_auth_bad_method(struct ceph_connection *con, From 10b7c72810364226f7b27916ea3e2a4f870bc04b Mon Sep 17 00:00:00 2001 From: Sam Edwards Date: Tue, 30 Dec 2025 20:05:06 -0800 Subject: [PATCH 1810/2333] libceph: reset sparse-read state in osd_fault() commit 11194b416ef95012c2cfe5f546d71af07b639e93 upstream. When a fault occurs, the connection is abandoned, reestablished, and any pending operations are retried. The OSD client tracks the progress of a sparse-read reply using a separate state machine, largely independent of the messenger's state. If a connection is lost mid-payload or the sparse-read state machine returns an error, the sparse-read state is not reset. The OSD client will then interpret the beginning of a new reply as the continuation of the old one. If this makes the sparse-read machinery enter a failure state, it may never recover, producing loops like: libceph: [0] got 0 extents libceph: data len 142248331 != extent len 0 libceph: osd0 (1)...:6801 socket error on read libceph: data len 142248331 != extent len 0 libceph: osd0 (1)...:6801 socket error on read Therefore, reset the sparse-read state in osd_fault(), ensuring retries start from a clean state. Cc: stable@vger.kernel.org Fixes: f628d7999727 ("libceph: add sparse read support to OSD client") Signed-off-by: Sam Edwards Reviewed-by: Ilya Dryomov Signed-off-by: Ilya Dryomov Signed-off-by: Greg Kroah-Hartman --- net/ceph/osd_client.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c index 6664ea73ccf81..67f7430c77501 100644 --- a/net/ceph/osd_client.c +++ b/net/ceph/osd_client.c @@ -4283,6 +4283,9 @@ static void osd_fault(struct ceph_connection *con) goto out_unlock; } + osd->o_sparse_op_idx = -1; + ceph_init_sparse_read(&osd->o_sparse_read); + if (!reopen_osd(osd)) kick_osd_requests(osd); maybe_request_map(osdc); From 5647d42c47b535573b63e073e91164d6a5bb058c Mon Sep 17 00:00:00 2001 From: Ilya Dryomov Date: Mon, 5 Jan 2026 19:23:19 +0100 Subject: [PATCH 1811/2333] libceph: make calc_target() set t->paused, not just clear it commit c0fe2994f9a9d0a2ec9e42441ea5ba74b6a16176 upstream. Currently calc_target() clears t->paused if the request shouldn't be paused anymore, but doesn't ever set t->paused even though it's able to determine when the request should be paused. Setting t->paused is left to __submit_request() which is fine for regular requests but doesn't work for linger requests -- since __submit_request() doesn't operate on linger requests, there is nowhere for lreq->t.paused to be set. One consequence of this is that watches don't get reestablished on paused -> unpaused transitions in cases where requests have been paused long enough for the (paused) unwatch request to time out and for the subsequent (re)watch request to enter the paused state. On top of the watch not getting reestablished, rbd_reregister_watch() gets stuck with rbd_dev->watch_mutex held: rbd_register_watch __rbd_register_watch ceph_osdc_watch linger_reg_commit_wait It's waiting for lreq->reg_commit_wait to be completed, but for that to happen the respective request needs to end up on need_resend_linger list and be kicked when requests are unpaused. There is no chance for that if the request in question is never marked paused in the first place. The fact that rbd_dev->watch_mutex remains taken out forever then prevents the image from getting unmapped -- "rbd unmap" would inevitably hang in D state on an attempt to grab the mutex. Cc: stable@vger.kernel.org Reported-by: Raphael Zimmer Signed-off-by: Ilya Dryomov Reviewed-by: Viacheslav Dubeyko Signed-off-by: Greg Kroah-Hartman --- net/ceph/osd_client.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c index 67f7430c77501..6d7d8c7d7d3fe 100644 --- a/net/ceph/osd_client.c +++ b/net/ceph/osd_client.c @@ -1588,6 +1588,7 @@ static enum calc_target_result calc_target(struct ceph_osd_client *osdc, struct ceph_pg_pool_info *pi; struct ceph_pg pgid, last_pgid; struct ceph_osds up, acting; + bool should_be_paused; bool is_read = t->flags & CEPH_OSD_FLAG_READ; bool is_write = t->flags & CEPH_OSD_FLAG_WRITE; bool force_resend = false; @@ -1656,10 +1657,16 @@ static enum calc_target_result calc_target(struct ceph_osd_client *osdc, &last_pgid)) force_resend = true; - if (t->paused && !target_should_be_paused(osdc, t, pi)) { - t->paused = false; + should_be_paused = target_should_be_paused(osdc, t, pi); + if (t->paused && !should_be_paused) { unpaused = true; } + if (t->paused != should_be_paused) { + dout("%s t %p paused %d -> %d\n", __func__, t, t->paused, + should_be_paused); + t->paused = should_be_paused; + } + legacy_change = ceph_pg_compare(&t->pgid, &pgid) || ceph_osds_changed(&t->acting, &acting, t->used_replica || any_change); From a1d420370a248cbd940e134ebf2db6d9e9d19b81 Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Sat, 1 Nov 2025 21:31:16 +0800 Subject: [PATCH 1812/2333] ublk: reorder tag_set initialization before queue allocation commit 011af85ccd871526df36988c7ff20ca375fb804d upstream. Move ublk_add_tag_set() before ublk_init_queues() in the device initialization path. This allows us to use the blk-mq CPU-to-queue mapping established by the tag_set to determine the appropriate NUMA node for each queue allocation. The error handling paths are also reordered accordingly. Reviewed-by: Caleb Sander Mateos Signed-off-by: Ming Lei Signed-off-by: Jens Axboe [ Upstream commit 529d4d632788 ("ublk: implement NUMA-aware memory allocation") is ported to linux-6.18.y, but it depends on commit 011af85ccd87 ("ublk: reorder tag_set initialization before queue allocation"). kernel panic is reported on 6.18.y: https://github.com/ublk-org/ublksrv/issues/174 ] Signed-off-by: Greg Kroah-Hartman --- drivers/block/ublk_drv.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c index 23aba73d24dc2..babb58d2dcaf7 100644 --- a/drivers/block/ublk_drv.c +++ b/drivers/block/ublk_drv.c @@ -3280,17 +3280,17 @@ static int ublk_ctrl_add_dev(const struct ublksrv_ctrl_cmd *header) ub->dev_info.nr_hw_queues, nr_cpu_ids); ublk_align_max_io_size(ub); - ret = ublk_init_queues(ub); + ret = ublk_add_tag_set(ub); if (ret) goto out_free_dev_number; - ret = ublk_add_tag_set(ub); + ret = ublk_init_queues(ub); if (ret) - goto out_deinit_queues; + goto out_free_tag_set; ret = -EFAULT; if (copy_to_user(argp, &ub->dev_info, sizeof(info))) - goto out_free_tag_set; + goto out_deinit_queues; /* * Add the char dev so that ublksrv daemon can be setup. @@ -3299,10 +3299,10 @@ static int ublk_ctrl_add_dev(const struct ublksrv_ctrl_cmd *header) ret = ublk_add_chdev(ub); goto out_unlock; -out_free_tag_set: - blk_mq_free_tag_set(&ub->tag_set); out_deinit_queues: ublk_deinit_queues(ub); +out_free_tag_set: + blk_mq_free_tag_set(&ub->tag_set); out_free_dev_number: ublk_free_dev_number(ub); out_free_ub: From c88717b10792210ab48e9df8698a94f12550c220 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 10 Dec 2025 14:15:51 +0100 Subject: [PATCH 1813/2333] ALSA: hda: intel-dsp-config: Prefer legacy driver as fallback commit 161a0c617ab172bbcda7ce61803addeb2124dbff upstream. When config table entries don't match with the device to be probed, currently we fall back to SND_INTEL_DSP_DRIVER_ANY, which means to allow any drivers to bind with it. This was set so with the assumption (or hope) that all controller drivers should cover the devices generally, but in practice, this caused a problem as reported recently. Namely, when a specific kconfig for SOF isn't set for the modern Intel chips like Alderlake, a wrong driver (AVS) got probed and failed. This is because we have entries like: #if IS_ENABLED(CONFIG_SND_SOC_SOF_ALDERLAKE) /* Alder Lake / Raptor Lake */ { .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, .device = PCI_DEVICE_ID_INTEL_HDA_ADL_S, }, .... #endif so this entry is effective only when CONFIG_SND_SOC_SOF_ALDERLAKE is set. If not set, there is no matching entry, hence it returns SND_INTEL_DSP_DRIVER_ANY as fallback. OTOH, if the kconfig is set, it explicitly falls back to SND_INTEL_DSP_DRIVER_LEGACY when no DMIC or SoundWire is found -- that was the working scenario. That being said, the current setup may be broken for modern Intel chips that are supposed to work with either SOF or legacy driver when the corresponding kconfig were missing. For addressing the problem above, this patch changes the fallback driver to the legacy driver, i.e. return SND_INTEL_DSP_DRIVER_LEGACY type as much as possible. When CONFIG_SND_HDA_INTEL is also disabled, the fallback is set to SND_INTEL_DSP_DRIVER_ANY type, just to be sure. Reported-by: Askar Safin Closes: https://lore.kernel.org/all/20251014034156.4480-1-safinaskar@gmail.com/ Tested-by: Askar Safin Reviewed-by: Peter Ujfalusi Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20251210131553.184404-1-tiwai@suse.de Cc: Askar Safin Signed-off-by: Greg Kroah-Hartman --- sound/hda/core/intel-dsp-config.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/hda/core/intel-dsp-config.c b/sound/hda/core/intel-dsp-config.c index 2a9e35cddcf7c..ddb349bc46bbd 100644 --- a/sound/hda/core/intel-dsp-config.c +++ b/sound/hda/core/intel-dsp-config.c @@ -710,7 +710,8 @@ int snd_intel_dsp_driver_probe(struct pci_dev *pci) /* find the configuration for the specific device */ cfg = snd_intel_dsp_find_config(pci, config_table, ARRAY_SIZE(config_table)); if (!cfg) - return SND_INTEL_DSP_DRIVER_ANY; + return IS_ENABLED(CONFIG_SND_HDA_INTEL) ? + SND_INTEL_DSP_DRIVER_LEGACY : SND_INTEL_DSP_DRIVER_ANY; if (cfg->flags & FLAG_SOF) { if (cfg->flags & FLAG_SOF_ONLY_IF_SOUNDWIRE && From 8ad9e930fb910da2daf82f7dc0080ff4c8882826 Mon Sep 17 00:00:00 2001 From: Yang Li Date: Wed, 16 Oct 2024 17:56:26 +0800 Subject: [PATCH 1814/2333] csky: fix csky_cmpxchg_fixup not working [ Upstream commit 809ef03d6d21d5fea016bbf6babeec462e37e68c ] In the csky_cmpxchg_fixup function, it is incorrect to use the global variable csky_cmpxchg_stw to determine the address where the exception occurred.The global variable csky_cmpxchg_stw stores the opcode at the time of the exception, while &csky_cmpxchg_stw shows the address where the exception occurred. Signed-off-by: Yang Li Signed-off-by: Guo Ren Signed-off-by: Sasha Levin --- arch/csky/mm/fault.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/csky/mm/fault.c b/arch/csky/mm/fault.c index a6ca7dff42153..7ff4011089850 100644 --- a/arch/csky/mm/fault.c +++ b/arch/csky/mm/fault.c @@ -45,8 +45,8 @@ static inline void csky_cmpxchg_fixup(struct pt_regs *regs) if (trap_no(regs) != VEC_TLBMODIFIED) return; - if (instruction_pointer(regs) == csky_cmpxchg_stw) - instruction_pointer_set(regs, csky_cmpxchg_ldw); + if (instruction_pointer(regs) == (unsigned long)&csky_cmpxchg_stw) + instruction_pointer_set(regs, (unsigned long)&csky_cmpxchg_ldw); return; } #endif From 9f53cfb9f4c20739bcff20cd52790fb1561d8f85 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Tue, 11 Nov 2025 16:54:37 +0100 Subject: [PATCH 1815/2333] ARM: 9461/1: Disable HIGHPTE on PREEMPT_RT kernels [ Upstream commit fedadc4137234c3d00c4785eeed3e747fe9036ae ] gup_pgd_range() is invoked with disabled interrupts and invokes __kmap_local_page_prot() via pte_offset_map(), gup_p4d_range(). With HIGHPTE enabled, __kmap_local_page_prot() invokes kmap_high_get() which uses a spinlock_t via lock_kmap_any(). This leads to an sleeping-while-atomic error on PREEMPT_RT because spinlock_t becomes a sleeping lock and must not be acquired in atomic context. The loop in map_new_virtual() uses wait_queue_head_t for wake up which also is using a spinlock_t. Since HIGHPTE is rarely needed at all, turn it off for PREEMPT_RT to allow the use of get_user_pages_fast(). [arnd: rework patch to turn off HIGHPTE instead of HAVE_PAST_GUP] Co-developed-by: Arnd Bergmann Acked-by: Linus Walleij Reviewed-by: Arnd Bergmann Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Russell King (Oracle) Signed-off-by: Sasha Levin --- arch/arm/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 4fb985b76e97f..70cd3b5b5a059 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1215,7 +1215,7 @@ config HIGHMEM config HIGHPTE bool "Allocate 2nd-level pagetables from highmem" if EXPERT - depends on HIGHMEM + depends on HIGHMEM && !PREEMPT_RT default y help The VM uses one page of physical memory for each page table. From fea0f86e46133c612a69de2e48fe8772128c70a9 Mon Sep 17 00:00:00 2001 From: Sam James Date: Fri, 5 Dec 2025 08:14:57 +0000 Subject: [PATCH 1816/2333] alpha: don't reference obsolete termio struct for TC* constants [ Upstream commit 9aeed9041929812a10a6d693af050846942a1d16 ] Similar in nature to ab107276607af90b13a5994997e19b7b9731e251. glibc-2.42 drops the legacy termio struct, but the ioctls.h header still defines some TC* constants in terms of termio (via sizeof). Hardcode the values instead. This fixes building Python for example, which falls over like: ./Modules/termios.c:1119:16: error: invalid application of 'sizeof' to incomplete type 'struct termio' Link: https://bugs.gentoo.org/961769 Link: https://bugs.gentoo.org/962600 Signed-off-by: Sam James Reviewed-by: Magnus Lindholm Link: https://lore.kernel.org/r/6ebd3451908785cad53b50ca6bc46cfe9d6bc03c.1764922497.git.sam@gentoo.org Signed-off-by: Magnus Lindholm Signed-off-by: Sasha Levin --- arch/alpha/include/uapi/asm/ioctls.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/alpha/include/uapi/asm/ioctls.h b/arch/alpha/include/uapi/asm/ioctls.h index 971311605288f..a09d04b49cc65 100644 --- a/arch/alpha/include/uapi/asm/ioctls.h +++ b/arch/alpha/include/uapi/asm/ioctls.h @@ -23,10 +23,10 @@ #define TCSETSW _IOW('t', 21, struct termios) #define TCSETSF _IOW('t', 22, struct termios) -#define TCGETA _IOR('t', 23, struct termio) -#define TCSETA _IOW('t', 24, struct termio) -#define TCSETAW _IOW('t', 25, struct termio) -#define TCSETAF _IOW('t', 28, struct termio) +#define TCGETA 0x40127417 +#define TCSETA 0x80127418 +#define TCSETAW 0x80127419 +#define TCSETAF 0x8012741c #define TCSBRK _IO('t', 29) #define TCXONC _IO('t', 30) From 232948cf600fba69aff36b25d85ef91a73a35756 Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Fri, 14 Nov 2025 16:54:01 +0100 Subject: [PATCH 1817/2333] dm-verity: disable recursive forward error correction [ Upstream commit d9f3e47d3fae0c101d9094bc956ed24e7a0ee801 ] There are two problems with the recursive correction: 1. It may cause denial-of-service. In fec_read_bufs, there is a loop that has 253 iterations. For each iteration, we may call verity_hash_for_block recursively. There is a limit of 4 nested recursions - that means that there may be at most 253^4 (4 billion) iterations. Red Hat QE team actually created an image that pushes dm-verity to this limit - and this image just makes the udev-worker process get stuck in the 'D' state. 2. It doesn't work. In fec_read_bufs we store data into the variable "fio->bufs", but fio bufs is shared between recursive invocations, if "verity_hash_for_block" invoked correction recursively, it would overwrite partially filled fio->bufs. Signed-off-by: Mikulas Patocka Reported-by: Guangwu Zhang Reviewed-by: Sami Tolvanen Reviewed-by: Eric Biggers Signed-off-by: Sasha Levin --- drivers/md/dm-verity-fec.c | 4 +--- drivers/md/dm-verity-fec.h | 3 --- drivers/md/dm-verity-target.c | 2 +- 3 files changed, 2 insertions(+), 7 deletions(-) diff --git a/drivers/md/dm-verity-fec.c b/drivers/md/dm-verity-fec.c index 72047b47a7a0a..e41bde1d3b15b 100644 --- a/drivers/md/dm-verity-fec.c +++ b/drivers/md/dm-verity-fec.c @@ -413,10 +413,8 @@ int verity_fec_decode(struct dm_verity *v, struct dm_verity_io *io, if (!verity_fec_is_enabled(v)) return -EOPNOTSUPP; - if (fio->level >= DM_VERITY_FEC_MAX_RECURSION) { - DMWARN_LIMIT("%s: FEC: recursion too deep", v->data_dev->name); + if (fio->level) return -EIO; - } fio->level++; diff --git a/drivers/md/dm-verity-fec.h b/drivers/md/dm-verity-fec.h index 09123a6129538..ec37e607cb3f0 100644 --- a/drivers/md/dm-verity-fec.h +++ b/drivers/md/dm-verity-fec.h @@ -23,9 +23,6 @@ #define DM_VERITY_FEC_BUF_MAX \ (1 << (PAGE_SHIFT - DM_VERITY_FEC_BUF_RS_BITS)) -/* maximum recursion level for verity_fec_decode */ -#define DM_VERITY_FEC_MAX_RECURSION 4 - #define DM_VERITY_OPT_FEC_DEV "use_fec_from_device" #define DM_VERITY_OPT_FEC_BLOCKS "fec_blocks" #define DM_VERITY_OPT_FEC_START "fec_start" diff --git a/drivers/md/dm-verity-target.c b/drivers/md/dm-verity-target.c index 66a00a8ccb398..c8695c079cfe0 100644 --- a/drivers/md/dm-verity-target.c +++ b/drivers/md/dm-verity-target.c @@ -1690,7 +1690,7 @@ static struct target_type verity_target = { .name = "verity", /* Note: the LSMs depend on the singleton and immutable features */ .features = DM_TARGET_SINGLETON | DM_TARGET_IMMUTABLE, - .version = {1, 12, 0}, + .version = {1, 13, 0}, .module = THIS_MODULE, .ctr = verity_ctr, .dtr = verity_dtr, From 6930c0229fb3b3561619c82425712a2928f72be5 Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Mon, 1 Dec 2025 22:13:10 +0100 Subject: [PATCH 1818/2333] dm-snapshot: fix 'scheduling while atomic' on real-time kernels [ Upstream commit 8581b19eb2c5ccf06c195d3b5468c3c9d17a5020 ] There is reported 'scheduling while atomic' bug when using dm-snapshot on real-time kernels. The reason for the bug is that the hlist_bl code does preempt_disable() when taking the lock and the kernel attempts to take other spinlocks while holding the hlist_bl lock. Fix this by converting a hlist_bl spinlock into a regular spinlock. Signed-off-by: Mikulas Patocka Reported-by: Jiping Ma Signed-off-by: Sasha Levin --- drivers/md/dm-exception-store.h | 2 +- drivers/md/dm-snap.c | 73 +++++++++++++++------------------ 2 files changed, 35 insertions(+), 40 deletions(-) diff --git a/drivers/md/dm-exception-store.h b/drivers/md/dm-exception-store.h index b679766375381..061b4d3108132 100644 --- a/drivers/md/dm-exception-store.h +++ b/drivers/md/dm-exception-store.h @@ -29,7 +29,7 @@ typedef sector_t chunk_t; * chunk within the device. */ struct dm_exception { - struct hlist_bl_node hash_list; + struct hlist_node hash_list; chunk_t old_chunk; chunk_t new_chunk; diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c index f40c18da40000..dbd148967de42 100644 --- a/drivers/md/dm-snap.c +++ b/drivers/md/dm-snap.c @@ -40,10 +40,15 @@ static const char dm_snapshot_merge_target_name[] = "snapshot-merge"; #define DM_TRACKED_CHUNK_HASH(x) ((unsigned long)(x) & \ (DM_TRACKED_CHUNK_HASH_SIZE - 1)) +struct dm_hlist_head { + struct hlist_head head; + spinlock_t lock; +}; + struct dm_exception_table { uint32_t hash_mask; unsigned int hash_shift; - struct hlist_bl_head *table; + struct dm_hlist_head *table; }; struct dm_snapshot { @@ -628,8 +633,8 @@ static uint32_t exception_hash(struct dm_exception_table *et, chunk_t chunk); /* Lock to protect access to the completed and pending exception hash tables. */ struct dm_exception_table_lock { - struct hlist_bl_head *complete_slot; - struct hlist_bl_head *pending_slot; + spinlock_t *complete_slot; + spinlock_t *pending_slot; }; static void dm_exception_table_lock_init(struct dm_snapshot *s, chunk_t chunk, @@ -638,20 +643,20 @@ static void dm_exception_table_lock_init(struct dm_snapshot *s, chunk_t chunk, struct dm_exception_table *complete = &s->complete; struct dm_exception_table *pending = &s->pending; - lock->complete_slot = &complete->table[exception_hash(complete, chunk)]; - lock->pending_slot = &pending->table[exception_hash(pending, chunk)]; + lock->complete_slot = &complete->table[exception_hash(complete, chunk)].lock; + lock->pending_slot = &pending->table[exception_hash(pending, chunk)].lock; } static void dm_exception_table_lock(struct dm_exception_table_lock *lock) { - hlist_bl_lock(lock->complete_slot); - hlist_bl_lock(lock->pending_slot); + spin_lock_nested(lock->complete_slot, 1); + spin_lock_nested(lock->pending_slot, 2); } static void dm_exception_table_unlock(struct dm_exception_table_lock *lock) { - hlist_bl_unlock(lock->pending_slot); - hlist_bl_unlock(lock->complete_slot); + spin_unlock(lock->pending_slot); + spin_unlock(lock->complete_slot); } static int dm_exception_table_init(struct dm_exception_table *et, @@ -661,13 +666,15 @@ static int dm_exception_table_init(struct dm_exception_table *et, et->hash_shift = hash_shift; et->hash_mask = size - 1; - et->table = kvmalloc_array(size, sizeof(struct hlist_bl_head), + et->table = kvmalloc_array(size, sizeof(struct dm_hlist_head), GFP_KERNEL); if (!et->table) return -ENOMEM; - for (i = 0; i < size; i++) - INIT_HLIST_BL_HEAD(et->table + i); + for (i = 0; i < size; i++) { + INIT_HLIST_HEAD(&et->table[i].head); + spin_lock_init(&et->table[i].lock); + } return 0; } @@ -675,16 +682,17 @@ static int dm_exception_table_init(struct dm_exception_table *et, static void dm_exception_table_exit(struct dm_exception_table *et, struct kmem_cache *mem) { - struct hlist_bl_head *slot; + struct dm_hlist_head *slot; struct dm_exception *ex; - struct hlist_bl_node *pos, *n; + struct hlist_node *pos; int i, size; size = et->hash_mask + 1; for (i = 0; i < size; i++) { slot = et->table + i; - hlist_bl_for_each_entry_safe(ex, pos, n, slot, hash_list) { + hlist_for_each_entry_safe(ex, pos, &slot->head, hash_list) { + hlist_del(&ex->hash_list); kmem_cache_free(mem, ex); cond_resched(); } @@ -700,7 +708,7 @@ static uint32_t exception_hash(struct dm_exception_table *et, chunk_t chunk) static void dm_remove_exception(struct dm_exception *e) { - hlist_bl_del(&e->hash_list); + hlist_del(&e->hash_list); } /* @@ -710,12 +718,11 @@ static void dm_remove_exception(struct dm_exception *e) static struct dm_exception *dm_lookup_exception(struct dm_exception_table *et, chunk_t chunk) { - struct hlist_bl_head *slot; - struct hlist_bl_node *pos; + struct hlist_head *slot; struct dm_exception *e; - slot = &et->table[exception_hash(et, chunk)]; - hlist_bl_for_each_entry(e, pos, slot, hash_list) + slot = &et->table[exception_hash(et, chunk)].head; + hlist_for_each_entry(e, slot, hash_list) if (chunk >= e->old_chunk && chunk <= e->old_chunk + dm_consecutive_chunk_count(e)) return e; @@ -762,18 +769,17 @@ static void free_pending_exception(struct dm_snap_pending_exception *pe) static void dm_insert_exception(struct dm_exception_table *eh, struct dm_exception *new_e) { - struct hlist_bl_head *l; - struct hlist_bl_node *pos; + struct hlist_head *l; struct dm_exception *e = NULL; - l = &eh->table[exception_hash(eh, new_e->old_chunk)]; + l = &eh->table[exception_hash(eh, new_e->old_chunk)].head; /* Add immediately if this table doesn't support consecutive chunks */ if (!eh->hash_shift) goto out; /* List is ordered by old_chunk */ - hlist_bl_for_each_entry(e, pos, l, hash_list) { + hlist_for_each_entry(e, l, hash_list) { /* Insert after an existing chunk? */ if (new_e->old_chunk == (e->old_chunk + dm_consecutive_chunk_count(e) + 1) && @@ -804,13 +810,13 @@ static void dm_insert_exception(struct dm_exception_table *eh, * Either the table doesn't support consecutive chunks or slot * l is empty. */ - hlist_bl_add_head(&new_e->hash_list, l); + hlist_add_head(&new_e->hash_list, l); } else if (new_e->old_chunk < e->old_chunk) { /* Add before an existing exception */ - hlist_bl_add_before(&new_e->hash_list, &e->hash_list); + hlist_add_before(&new_e->hash_list, &e->hash_list); } else { /* Add to l's tail: e is the last exception in this slot */ - hlist_bl_add_behind(&new_e->hash_list, &e->hash_list); + hlist_add_behind(&new_e->hash_list, &e->hash_list); } } @@ -820,7 +826,6 @@ static void dm_insert_exception(struct dm_exception_table *eh, */ static int dm_add_exception(void *context, chunk_t old, chunk_t new) { - struct dm_exception_table_lock lock; struct dm_snapshot *s = context; struct dm_exception *e; @@ -833,17 +838,7 @@ static int dm_add_exception(void *context, chunk_t old, chunk_t new) /* Consecutive_count is implicitly initialised to zero */ e->new_chunk = new; - /* - * Although there is no need to lock access to the exception tables - * here, if we don't then hlist_bl_add_head(), called by - * dm_insert_exception(), will complain about accessing the - * corresponding list without locking it first. - */ - dm_exception_table_lock_init(s, old, &lock); - - dm_exception_table_lock(&lock); dm_insert_exception(&s->complete, e); - dm_exception_table_unlock(&lock); return 0; } @@ -873,7 +868,7 @@ static int calc_max_buckets(void) /* use a fixed size of 2MB */ unsigned long mem = 2 * 1024 * 1024; - mem /= sizeof(struct hlist_bl_head); + mem /= sizeof(struct dm_hlist_head); return mem; } From d82f6d1d43b316264c5c9d11f2ad99e7048fe498 Mon Sep 17 00:00:00 2001 From: Scott Mayhew Date: Mon, 3 Nov 2025 10:44:15 -0500 Subject: [PATCH 1819/2333] NFSv4: ensure the open stateid seqid doesn't go backwards [ Upstream commit 2e47c3cc64b44b0b06cd68c2801db92ff143f2b2 ] We have observed an NFSv4 client receiving a LOCK reply with a status of NFS4ERR_OLD_STATEID and subsequently retrying the LOCK request with an earlier seqid value in the stateid. As this was for a new lockowner, that would imply that nfs_set_open_stateid_locked() had updated the open stateid seqid with an earlier value. Looking at nfs_set_open_stateid_locked(), if the incoming seqid is out of sequence, the task will sleep on the state->waitq for up to 5 seconds. If the task waits for the full 5 seconds, then after finishing the wait it'll update the open stateid seqid with whatever value the incoming seqid has. If there are multiple waiters in this scenario, then the last one to perform said update may not be the one with the highest seqid. Add a check to ensure that the seqid can only be incremented, and add a tracepoint to indicate when old seqids are skipped. Signed-off-by: Scott Mayhew Reviewed-by: Benjamin Coddington Signed-off-by: Trond Myklebust Signed-off-by: Sasha Levin --- fs/nfs/nfs4proc.c | 13 +++++++++++-- fs/nfs/nfs4trace.h | 1 + 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 6f4e14fb7b9b8..3b436ba2ed3bf 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -1780,8 +1780,17 @@ static void nfs_set_open_stateid_locked(struct nfs4_state *state, if (nfs_stateid_is_sequential(state, stateid)) break; - if (status) - break; + if (status) { + if (nfs4_stateid_match_other(stateid, &state->open_stateid) && + !nfs4_stateid_is_newer(stateid, &state->open_stateid)) { + trace_nfs4_open_stateid_update_skip(state->inode, + stateid, status); + return; + } else { + break; + } + } + /* Rely on seqids for serialisation with NFSv4.0 */ if (!nfs4_has_session(NFS_SERVER(state->inode)->nfs_client)) break; diff --git a/fs/nfs/nfs4trace.h b/fs/nfs/nfs4trace.h index 9776d220cec33..6285128e631a5 100644 --- a/fs/nfs/nfs4trace.h +++ b/fs/nfs/nfs4trace.h @@ -1353,6 +1353,7 @@ DEFINE_NFS4_INODE_STATEID_EVENT(nfs4_setattr); DEFINE_NFS4_INODE_STATEID_EVENT(nfs4_delegreturn); DEFINE_NFS4_INODE_STATEID_EVENT(nfs4_open_stateid_update); DEFINE_NFS4_INODE_STATEID_EVENT(nfs4_open_stateid_update_wait); +DEFINE_NFS4_INODE_STATEID_EVENT(nfs4_open_stateid_update_skip); DEFINE_NFS4_INODE_STATEID_EVENT(nfs4_close_stateid_update_wait); DECLARE_EVENT_CLASS(nfs4_getattr_event, From 8e73e0ee4530a3569e5285a06ac3b0f8d825c72e Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 3 Dec 2025 15:16:45 +0100 Subject: [PATCH 1820/2333] ASoC: rockchip: Fix Wvoid-pointer-to-enum-cast warning (again) [ Upstream commit 57d508b5f718730f74b11e0dc9609ac7976802d1 ] 'version' is an enum, thus cast of pointer on 64-bit compile test with clang W=1 causes: rockchip_pdm.c:583:17: error: cast to smaller integer type 'enum rk_pdm_version' from 'const void *' [-Werror,-Wvoid-pointer-to-enum-cast] This was already fixed in commit 49a4a8d12612 ("ASoC: rockchip: Fix Wvoid-pointer-to-enum-cast warning") but then got bad in commit 9958d85968ed ("ASoC: Use device_get_match_data()"). Discussion on LKML also pointed out that 'uintptr_t' is not the correct type and either 'kernel_ulong_t' or 'unsigned long' should be used, with several arguments towards the latter [1]. Link: https://lore.kernel.org/r/CAMuHMdX7t=mabqFE5O-Cii3REMuyaePHmqX+j_mqyrn6XXzsoA@mail.gmail.com/ [1] Signed-off-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20251203141644.106459-2-krzysztof.kozlowski@oss.qualcomm.com Signed-off-by: Mark Brown Signed-off-by: Sasha Levin --- sound/soc/rockchip/rockchip_pdm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/rockchip/rockchip_pdm.c b/sound/soc/rockchip/rockchip_pdm.c index c1ee470ec6079..c69cdd6f24994 100644 --- a/sound/soc/rockchip/rockchip_pdm.c +++ b/sound/soc/rockchip/rockchip_pdm.c @@ -580,7 +580,7 @@ static int rockchip_pdm_probe(struct platform_device *pdev) if (!pdm) return -ENOMEM; - pdm->version = (enum rk_pdm_version)device_get_match_data(&pdev->dev); + pdm->version = (unsigned long)device_get_match_data(&pdev->dev); if (pdm->version == RK_PDM_RK3308) { pdm->reset = devm_reset_control_get(&pdev->dev, "pdm-m"); if (IS_ERR(pdm->reset)) From ab775cc784f698ced8506baf7003e73fb3935c6c Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Fri, 28 Nov 2025 18:56:46 -0500 Subject: [PATCH 1821/2333] NFS: Fix up the automount fs_context to use the correct cred [ Upstream commit a2a8fc27dd668e7562b5326b5ed2f1604cb1e2e9 ] When automounting, the fs_context should be fixed up to use the cred from the parent filesystem, since the operation is just extending the namespace. Authorisation to enter that namespace will already have been provided by the preceding lookup. Signed-off-by: Trond Myklebust Signed-off-by: Sasha Levin --- fs/nfs/namespace.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c index 9e4d94f41fc67..af9be0c5f5163 100644 --- a/fs/nfs/namespace.c +++ b/fs/nfs/namespace.c @@ -170,6 +170,11 @@ struct vfsmount *nfs_d_automount(struct path *path) if (!ctx->clone_data.fattr) goto out_fc; + if (fc->cred != server->cred) { + put_cred(fc->cred); + fc->cred = get_cred(server->cred); + } + if (fc->net_ns != client->cl_net) { put_net(fc->net_ns); fc->net_ns = get_net(client->cl_net); From 93ee5471731b8ac93927ec725f6969026b7fcb47 Mon Sep 17 00:00:00 2001 From: Stefan Binding Date: Fri, 5 Dec 2025 15:05:55 +0000 Subject: [PATCH 1822/2333] ALSA: hda/realtek: Add support for ASUS UM3406GA [ Upstream commit 826c0b1ed09e5335abcae07292440ce72346e578 ] Laptops use 2 CS35L41 Amps with HDA, using External boost, with I2C Signed-off-by: Stefan Binding Link: https://patch.msgid.link/20251205150614.49590-3-sbinding@opensource.cirrus.com Signed-off-by: Takashi Iwai Signed-off-by: Sasha Levin --- sound/hda/codecs/realtek/alc269.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/hda/codecs/realtek/alc269.c b/sound/hda/codecs/realtek/alc269.c index b3582e390dfa3..eea8399e32588 100644 --- a/sound/hda/codecs/realtek/alc269.c +++ b/sound/hda/codecs/realtek/alc269.c @@ -6761,6 +6761,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1043, 0x1517, "Asus Zenbook UX31A", ALC269VB_FIXUP_ASUS_ZENBOOK_UX31A), SND_PCI_QUIRK(0x1043, 0x1533, "ASUS GV302XA/XJ/XQ/XU/XV/XI", ALC287_FIXUP_CS35L41_I2C_2), SND_PCI_QUIRK(0x1043, 0x1573, "ASUS GZ301VV/VQ/VU/VJ/VA/VC/VE/VVC/VQC/VUC/VJC/VEC/VCC", ALC285_FIXUP_ASUS_HEADSET_MIC), + SND_PCI_QUIRK(0x1043, 0x1584, "ASUS UM3406GA ", ALC287_FIXUP_CS35L41_I2C_2), SND_PCI_QUIRK(0x1043, 0x1652, "ASUS ROG Zephyrus Do 15 SE", ALC289_FIXUP_ASUS_ZEPHYRUS_DUAL_SPK), SND_PCI_QUIRK(0x1043, 0x1662, "ASUS GV301QH", ALC294_FIXUP_ASUS_DUAL_SPK), SND_PCI_QUIRK(0x1043, 0x1663, "ASUS GU603ZI/ZJ/ZQ/ZU/ZV", ALC285_FIXUP_ASUS_HEADSET_MIC), From f1ae589310e1aa58255e8b02c87a6ae97443ccb3 Mon Sep 17 00:00:00 2001 From: Rosen Penev Date: Sat, 8 Nov 2025 09:40:47 -0800 Subject: [PATCH 1823/2333] drm/amd/display: shrink struct members [ Upstream commit 7329417fc9ac128729c3a092b006c8f1fd0d04a6 ] On a 32-bit ARM system, the audio_decoder struct ends up being too large for dp_retrain_link_dp_test. link_dp_cts.c:157:1: error: the frame size of 1328 bytes is larger than 1280 bytes [-Werror=frame-larger-than=] This is mitigated by shrinking the members of the struct and avoids having to deal with dynamic allocation. feed_back_divider is assigned but otherwise unused. Remove both. pixel_repetition looks like it should be a bool since it's only ever assigned to 1. But there are checks for 2 and 4. Reduce to uint8_t. Remove ss_percentage_divider. Unused. Shrink refresh_rate as it gets assigned to at most a 3 digit integer value. Signed-off-by: Rosen Penev Reviewed-by: Alex Hung Signed-off-by: Alex Deucher (cherry picked from commit 3849efdc7888d537f09c3dcfaea4b3cd377a102e) Signed-off-by: Sasha Levin --- .../drm/amd/display/dc/hwss/dce110/dce110_hwseq.c | 3 --- drivers/gpu/drm/amd/display/include/audio_types.h | 12 +++++------- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c index ebc220b29d142..b94fec8347400 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c @@ -1458,9 +1458,6 @@ void build_audio_output( state->clk_mgr); } - audio_output->pll_info.feed_back_divider = - pipe_ctx->pll_settings.feedback_divider; - audio_output->pll_info.dto_source = translate_to_dto_source( pipe_ctx->stream_res.tg->inst + 1); diff --git a/drivers/gpu/drm/amd/display/include/audio_types.h b/drivers/gpu/drm/amd/display/include/audio_types.h index e4a26143f14c9..6699ad4fa825e 100644 --- a/drivers/gpu/drm/amd/display/include/audio_types.h +++ b/drivers/gpu/drm/amd/display/include/audio_types.h @@ -47,15 +47,15 @@ struct audio_crtc_info { uint32_t h_total; uint32_t h_active; uint32_t v_active; - uint32_t pixel_repetition; uint32_t requested_pixel_clock_100Hz; /* in 100Hz */ uint32_t calculated_pixel_clock_100Hz; /* in 100Hz */ - uint32_t refresh_rate; + uint32_t dsc_bits_per_pixel; + uint32_t dsc_num_slices; enum dc_color_depth color_depth; enum dc_pixel_encoding pixel_encoding; + uint16_t refresh_rate; + uint8_t pixel_repetition; bool interlaced; - uint32_t dsc_bits_per_pixel; - uint32_t dsc_num_slices; }; struct azalia_clock_info { uint32_t pixel_clock_in_10khz; @@ -78,11 +78,9 @@ enum audio_dto_source { struct audio_pll_info { uint32_t audio_dto_source_clock_in_khz; - uint32_t feed_back_divider; + uint32_t ss_percentage; enum audio_dto_source dto_source; bool ss_enabled; - uint32_t ss_percentage; - uint32_t ss_percentage_divider; }; struct audio_channel_associate_info { From e2c1462639663ffc3066f37bd7faf5a9baf9612c Mon Sep 17 00:00:00 2001 From: ChenXiaoSong Date: Sun, 7 Dec 2025 09:22:53 +0800 Subject: [PATCH 1824/2333] smb/client: fix NT_STATUS_UNABLE_TO_FREE_VM value [ Upstream commit 9f99caa8950a76f560a90074e3a4b93cfa8b3d84 ] This was reported by the KUnit tests in the later patches. See MS-ERREF 2.3.1 STATUS_UNABLE_TO_FREE_VM. Keep it consistent with the value in the documentation. Signed-off-by: ChenXiaoSong Acked-by: Paulo Alcantara (Red Hat) Signed-off-by: Steve French Signed-off-by: Sasha Levin --- fs/smb/client/nterr.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/smb/client/nterr.h b/fs/smb/client/nterr.h index 180602c22355e..e3a607b45e719 100644 --- a/fs/smb/client/nterr.h +++ b/fs/smb/client/nterr.h @@ -70,7 +70,7 @@ extern const struct nt_err_code_struct nt_errs[]; #define NT_STATUS_NO_MEMORY 0xC0000000 | 0x0017 #define NT_STATUS_CONFLICTING_ADDRESSES 0xC0000000 | 0x0018 #define NT_STATUS_NOT_MAPPED_VIEW 0xC0000000 | 0x0019 -#define NT_STATUS_UNABLE_TO_FREE_VM 0x80000000 | 0x001a +#define NT_STATUS_UNABLE_TO_FREE_VM 0xC0000000 | 0x001a #define NT_STATUS_UNABLE_TO_DELETE_SECTION 0xC0000000 | 0x001b #define NT_STATUS_INVALID_SYSTEM_SERVICE 0xC0000000 | 0x001c #define NT_STATUS_ILLEGAL_INSTRUCTION 0xC0000000 | 0x001d From d4959a7900afef6da232bc6321419f1f93750e20 Mon Sep 17 00:00:00 2001 From: ChenXiaoSong Date: Sun, 7 Dec 2025 09:17:57 +0800 Subject: [PATCH 1825/2333] smb/client: fix NT_STATUS_DEVICE_DOOR_OPEN value [ Upstream commit b2b50fca34da5ec231008edba798ddf92986bd7f ] This was reported by the KUnit tests in the later patches. See MS-ERREF 2.3.1 STATUS_DEVICE_DOOR_OPEN. Keep it consistent with the value in the documentation. Signed-off-by: ChenXiaoSong Acked-by: Paulo Alcantara (Red Hat) Signed-off-by: Steve French Signed-off-by: Sasha Levin --- fs/smb/client/nterr.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/smb/client/nterr.h b/fs/smb/client/nterr.h index e3a607b45e719..b3516c71cff77 100644 --- a/fs/smb/client/nterr.h +++ b/fs/smb/client/nterr.h @@ -44,7 +44,7 @@ extern const struct nt_err_code_struct nt_errs[]; #define NT_STATUS_NO_DATA_DETECTED 0x8000001c #define NT_STATUS_STOPPED_ON_SYMLINK 0x8000002d #define NT_STATUS_DEVICE_REQUIRES_CLEANING 0x80000288 -#define NT_STATUS_DEVICE_DOOR_OPEN 0x80000288 +#define NT_STATUS_DEVICE_DOOR_OPEN 0x80000289 #define NT_STATUS_UNSUCCESSFUL 0xC0000000 | 0x0001 #define NT_STATUS_NOT_IMPLEMENTED 0xC0000000 | 0x0002 #define NT_STATUS_INVALID_INFO_CLASS 0xC0000000 | 0x0003 From aba03b371632a26bee1cdded2cbeb80d84dff06e Mon Sep 17 00:00:00 2001 From: ChenXiaoSong Date: Sun, 7 Dec 2025 09:13:06 +0800 Subject: [PATCH 1826/2333] smb/client: fix NT_STATUS_NO_DATA_DETECTED value [ Upstream commit a1237c203f1757480dc2f3b930608ee00072d3cc ] This was reported by the KUnit tests in the later patches. See MS-ERREF 2.3.1 STATUS_NO_DATA_DETECTED. Keep it consistent with the value in the documentation. Signed-off-by: ChenXiaoSong Acked-by: Paulo Alcantara (Red Hat) Signed-off-by: Steve French Signed-off-by: Sasha Levin --- fs/smb/client/nterr.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/smb/client/nterr.h b/fs/smb/client/nterr.h index b3516c71cff77..09263c91d07a4 100644 --- a/fs/smb/client/nterr.h +++ b/fs/smb/client/nterr.h @@ -41,7 +41,7 @@ extern const struct nt_err_code_struct nt_errs[]; #define NT_STATUS_MEDIA_CHANGED 0x8000001c #define NT_STATUS_END_OF_MEDIA 0x8000001e #define NT_STATUS_MEDIA_CHECK 0x80000020 -#define NT_STATUS_NO_DATA_DETECTED 0x8000001c +#define NT_STATUS_NO_DATA_DETECTED 0x80000022 #define NT_STATUS_STOPPED_ON_SYMLINK 0x8000002d #define NT_STATUS_DEVICE_REQUIRES_CLEANING 0x80000288 #define NT_STATUS_DEVICE_DOOR_OPEN 0x80000289 From 382028023669fea7eb2fd7c13e259abdbc2a8dbf Mon Sep 17 00:00:00 2001 From: Suganath Prabu S Date: Thu, 20 Nov 2025 12:49:55 +0530 Subject: [PATCH 1827/2333] scsi: mpi3mr: Prevent duplicate SAS/SATA device entries in channel 1 [ Upstream commit 4588e65cfd66fc8bbd9969ea730db39b60a36a30 ] Avoid scanning SAS/SATA devices in channel 1 when SAS transport is enabled, as the SAS/SATA devices are exposed through channel 0. Signed-off-by: Suganath Prabu S Signed-off-by: Ranjan Kumar Link: https://lore.kernel.org/stable/20251120071955.463475-1-suganath-prabu.subramani%40broadcom.com Link: https://patch.msgid.link/20251120071955.463475-1-suganath-prabu.subramani@broadcom.com Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin --- drivers/scsi/mpi3mr/mpi3mr.h | 4 ++-- drivers/scsi/mpi3mr/mpi3mr_os.c | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h index 6742684e2990a..31d68c151b207 100644 --- a/drivers/scsi/mpi3mr/mpi3mr.h +++ b/drivers/scsi/mpi3mr/mpi3mr.h @@ -56,8 +56,8 @@ extern struct list_head mrioc_list; extern int prot_mask; extern atomic64_t event_counter; -#define MPI3MR_DRIVER_VERSION "8.15.0.5.50" -#define MPI3MR_DRIVER_RELDATE "12-August-2025" +#define MPI3MR_DRIVER_VERSION "8.15.0.5.51" +#define MPI3MR_DRIVER_RELDATE "18-November-2025" #define MPI3MR_DRIVER_NAME "mpi3mr" #define MPI3MR_DRIVER_LICENSE "GPL" diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c index b88633e1efe27..d4ca878d08869 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_os.c +++ b/drivers/scsi/mpi3mr/mpi3mr_os.c @@ -1184,6 +1184,8 @@ static void mpi3mr_update_tgtdev(struct mpi3mr_ioc *mrioc, if (is_added == true) tgtdev->io_throttle_enabled = (flags & MPI3_DEVICE0_FLAGS_IO_THROTTLING_REQUIRED) ? 1 : 0; + if (!mrioc->sas_transport_enabled) + tgtdev->non_stl = 1; switch (flags & MPI3_DEVICE0_FLAGS_MAX_WRITE_SAME_MASK) { case MPI3_DEVICE0_FLAGS_MAX_WRITE_SAME_256_LB: @@ -4844,7 +4846,7 @@ static int mpi3mr_target_alloc(struct scsi_target *starget) spin_lock_irqsave(&mrioc->tgtdev_lock, flags); if (starget->channel == mrioc->scsi_device_channel) { tgt_dev = __mpi3mr_get_tgtdev_by_perst_id(mrioc, starget->id); - if (tgt_dev && !tgt_dev->is_hidden) { + if (tgt_dev && !tgt_dev->is_hidden && tgt_dev->non_stl) { scsi_tgt_priv_data->starget = starget; scsi_tgt_priv_data->dev_handle = tgt_dev->dev_handle; scsi_tgt_priv_data->perst_id = tgt_dev->perst_id; From 3a96f7f2677af43cb668089904c037b7e5584869 Mon Sep 17 00:00:00 2001 From: Wen Xiong Date: Tue, 28 Oct 2025 09:24:26 -0500 Subject: [PATCH 1828/2333] scsi: ipr: Enable/disable IRQD_NO_BALANCING during reset [ Upstream commit 6ac3484fb13b2fc7f31cfc7f56093e7d0ce646a5 ] A dynamic remove/add storage adapter test hits EEH on PowerPC: EEH: [c00000000004f75c] __eeh_send_failure_event+0x7c/0x160 EEH: [c000000000048444] eeh_dev_check_failure.part.0+0x254/0x650 EEH: [c008000001650678] eeh_readl+0x60/0x90 [ipr] EEH: [c00800000166746c] ipr_cancel_op+0x2b8/0x524 [ipr] EEH: [c008000001656524] ipr_eh_abort+0x6c/0x130 [ipr] EEH: [c000000000ab0d20] scmd_eh_abort_handler+0x140/0x440 EEH: [c00000000017e558] process_one_work+0x298/0x590 EEH: [c00000000017eef8] worker_thread+0xa8/0x620 EEH: [c00000000018be34] kthread+0x124/0x130 EEH: [c00000000000cd64] ret_from_kernel_thread+0x5c/0x64 A PCIe bus trace reveals that a vector of MSI-X is cleared to 0 by irqbalance daemon. If we disable irqbalance daemon, we won't see the issue. With debug enabled in ipr driver: [ 44.103071] ipr: Entering __ipr_remove [ 44.103083] ipr: Entering ipr_initiate_ioa_bringdown [ 44.103091] ipr: Entering ipr_reset_shutdown_ioa [ 44.103099] ipr: Leaving ipr_reset_shutdown_ioa [ 44.103105] ipr: Leaving ipr_initiate_ioa_bringdown [ 44.149918] ipr: Entering ipr_reset_ucode_download [ 44.149935] ipr: Entering ipr_reset_alert [ 44.150032] ipr: Entering ipr_reset_start_timer [ 44.150038] ipr: Leaving ipr_reset_alert [ 44.244343] scsi 1:2:3:0: alua: Detached [ 44.254300] ipr: Entering ipr_reset_start_bist [ 44.254320] ipr: Entering ipr_reset_start_timer [ 44.254325] ipr: Leaving ipr_reset_start_bist [ 44.364329] scsi 1:2:4:0: alua: Detached [ 45.134341] scsi 1:2:5:0: alua: Detached [ 45.860949] ipr: Entering ipr_reset_shutdown_ioa [ 45.860962] ipr: Leaving ipr_reset_shutdown_ioa [ 45.860966] ipr: Entering ipr_reset_alert [ 45.861028] ipr: Entering ipr_reset_start_timer [ 45.861035] ipr: Leaving ipr_reset_alert [ 45.964302] ipr: Entering ipr_reset_start_bist [ 45.964309] ipr: Entering ipr_reset_start_timer [ 45.964313] ipr: Leaving ipr_reset_start_bist [ 46.264301] ipr: Entering ipr_reset_bist_done [ 46.264309] ipr: Leaving ipr_reset_bist_done During adapter reset, ipr device driver blocks config space access but can't block MMIO access for MSI-X entries. There is very small window: irqbalance daemon kicks in during adapter reset before ipr driver calls pci_restore_state(pdev) to restore MSI-X table. irqbalance daemon reads back all 0 for that MSI-X vector in __pci_read_msi_msg(). irqbalance daemon: msi_domain_set_affinity() ->irq_chip_set_affinity_patent() ->xive_irq_set_affinity() ->irq_chip_compose_msi_msg() ->pseries_msi_compose_msg() ->__pci_read_msi_msg(): read all 0 since didn't call pci_restore_state ->irq_chip_write_msi_msg() -> pci_write_msg_msi(): write 0 to the msix vector entry When ipr driver calls pci_restore_state(pdev) in ipr_reset_restore_cfg_space(), the MSI-X vector entry has been cleared by irqbalance daemon in pci_write_msg_msix(). pci_restore_state() ->__pci_restore_msix_state() Below is the MSI-X table for ipr adapter after irqbalance daemon kicked in during adapter reset: Dump MSIx table: index=0 address_lo=c800 address_hi=10000000 msg_data=0 Dump MSIx table: index=1 address_lo=c810 address_hi=10000000 msg_data=0 Dump MSIx table: index=2 address_lo=c820 address_hi=10000000 msg_data=0 Dump MSIx table: index=3 address_lo=c830 address_hi=10000000 msg_data=0 Dump MSIx table: index=4 address_lo=c840 address_hi=10000000 msg_data=0 Dump MSIx table: index=5 address_lo=c850 address_hi=10000000 msg_data=0 Dump MSIx table: index=6 address_lo=c860 address_hi=10000000 msg_data=0 Dump MSIx table: index=7 address_lo=c870 address_hi=10000000 msg_data=0 Dump MSIx table: index=8 address_lo=0 address_hi=0 msg_data=0 ---------> Hit EEH since msix vector of index=8 are 0 Dump MSIx table: index=9 address_lo=c890 address_hi=10000000 msg_data=0 Dump MSIx table: index=10 address_lo=c8a0 address_hi=10000000 msg_data=0 Dump MSIx table: index=11 address_lo=c8b0 address_hi=10000000 msg_data=0 Dump MSIx table: index=12 address_lo=c8c0 address_hi=10000000 msg_data=0 Dump MSIx table: index=13 address_lo=c8d0 address_hi=10000000 msg_data=0 Dump MSIx table: index=14 address_lo=c8e0 address_hi=10000000 msg_data=0 Dump MSIx table: index=15 address_lo=c8f0 address_hi=10000000 msg_data=0 [ 46.264312] ipr: Entering ipr_reset_restore_cfg_space [ 46.267439] ipr: Entering ipr_fail_all_ops [ 46.267447] ipr: Leaving ipr_fail_all_ops [ 46.267451] ipr: Leaving ipr_reset_restore_cfg_space [ 46.267454] ipr: Entering ipr_ioa_bringdown_done [ 46.267458] ipr: Leaving ipr_ioa_bringdown_done [ 46.267467] ipr: Entering ipr_worker_thread [ 46.267470] ipr: Leaving ipr_worker_thread IRQ balancing is not required during adapter reset. Enable "IRQ_NO_BALANCING" flag before starting adapter reset and disable it after calling pci_restore_state(). The irqbalance daemon is disabled for this short period of time (~2s). Co-developed-by: Kyle Mahlkuch Signed-off-by: Kyle Mahlkuch Signed-off-by: Wen Xiong Link: https://patch.msgid.link/20251028142427.3969819-2-wenxiong@linux.ibm.com Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin --- drivers/scsi/ipr.c | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index 44214884deaf5..d62bb7d0e4164 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -61,8 +61,8 @@ #include #include #include +#include #include -#include #include #include #include @@ -7843,6 +7843,30 @@ static int ipr_dump_mailbox_wait(struct ipr_cmnd *ipr_cmd) return IPR_RC_JOB_RETURN; } +/** + * ipr_set_affinity_nobalance + * @ioa_cfg: ipr_ioa_cfg struct for an ipr device + * @flag: bool + * true: ensable "IRQ_NO_BALANCING" bit for msix interrupt + * false: disable "IRQ_NO_BALANCING" bit for msix interrupt + * Description: This function will be called to disable/enable + * "IRQ_NO_BALANCING" to avoid irqbalance daemon + * kicking in during adapter reset. + **/ +static void ipr_set_affinity_nobalance(struct ipr_ioa_cfg *ioa_cfg, bool flag) +{ + int irq, i; + + for (i = 0; i < ioa_cfg->nvectors; i++) { + irq = pci_irq_vector(ioa_cfg->pdev, i); + + if (flag) + irq_set_status_flags(irq, IRQ_NO_BALANCING); + else + irq_clear_status_flags(irq, IRQ_NO_BALANCING); + } +} + /** * ipr_reset_restore_cfg_space - Restore PCI config space. * @ipr_cmd: ipr command struct @@ -7867,6 +7891,7 @@ static int ipr_reset_restore_cfg_space(struct ipr_cmnd *ipr_cmd) return IPR_RC_JOB_CONTINUE; } + ipr_set_affinity_nobalance(ioa_cfg, false); ipr_fail_all_ops(ioa_cfg); if (ioa_cfg->sis64) { @@ -7946,6 +7971,7 @@ static int ipr_reset_start_bist(struct ipr_cmnd *ipr_cmd) rc = pci_write_config_byte(ioa_cfg->pdev, PCI_BIST, PCI_BIST_START); if (rc == PCIBIOS_SUCCESSFUL) { + ipr_set_affinity_nobalance(ioa_cfg, true); ipr_cmd->job_step = ipr_reset_bist_done; ipr_reset_start_timer(ipr_cmd, IPR_WAIT_FOR_BIST_TIMEOUT); rc = IPR_RC_JOB_RETURN; From f1e2d448ccc1d7db2e626a9edcb9ab0930fb6724 Mon Sep 17 00:00:00 2001 From: Brian Kao Date: Wed, 12 Nov 2025 06:32:02 +0000 Subject: [PATCH 1829/2333] scsi: ufs: core: Fix EH failure after W-LUN resume error [ Upstream commit b4bb6daf4ac4d4560044ecdd81e93aa2f6acbb06 ] When a W-LUN resume fails, its parent devices in the SCSI hierarchy, including the scsi_target, may be runtime suspended. Subsequently, the error handler in ufshcd_recover_pm_error() fails to set the W-LUN device back to active because the parent target is not active. This results in the following errors: google-ufshcd 3c2d0000.ufs: ufshcd_err_handler started; HBA state eh_fatal; ... ufs_device_wlun 0:0:0:49488: START_STOP failed for power mode: 1, result 40000 ufs_device_wlun 0:0:0:49488: ufshcd_wl_runtime_resume failed: -5 ... ufs_device_wlun 0:0:0:49488: runtime PM trying to activate child device 0:0:0:49488 but parent (target0:0:0) is not active Address this by: 1. Ensuring the W-LUN's parent scsi_target is runtime resumed before attempting to set the W-LUN to active within ufshcd_recover_pm_error(). 2. Explicitly checking for power.runtime_error on the HBA and W-LUN devices before calling pm_runtime_set_active() to clear the error state. 3. Adding pm_runtime_get_sync(hba->dev) in ufshcd_err_handling_prepare() to ensure the HBA itself is active during error recovery, even if a child device resume failed. These changes ensure the device power states are managed correctly during error recovery. Signed-off-by: Brian Kao Tested-by: Brian Kao Reviewed-by: Bart Van Assche Link: https://patch.msgid.link/20251112063214.1195761-1-powenkao@google.com Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin --- drivers/ufs/core/ufshcd.c | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index ba1bb3953cf69..022810b524e96 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -6498,6 +6498,11 @@ static void ufshcd_clk_scaling_suspend(struct ufs_hba *hba, bool suspend) static void ufshcd_err_handling_prepare(struct ufs_hba *hba) { + /* + * A WLUN resume failure could potentially lead to the HBA being + * runtime suspended, so take an extra reference on hba->dev. + */ + pm_runtime_get_sync(hba->dev); ufshcd_rpm_get_sync(hba); if (pm_runtime_status_suspended(&hba->ufs_device_wlun->sdev_gendev) || hba->is_sys_suspended) { @@ -6537,6 +6542,7 @@ static void ufshcd_err_handling_unprepare(struct ufs_hba *hba) if (ufshcd_is_clkscaling_supported(hba)) ufshcd_clk_scaling_suspend(hba, false); ufshcd_rpm_put(hba); + pm_runtime_put(hba->dev); } static inline bool ufshcd_err_handling_should_stop(struct ufs_hba *hba) @@ -6551,28 +6557,42 @@ static inline bool ufshcd_err_handling_should_stop(struct ufs_hba *hba) #ifdef CONFIG_PM static void ufshcd_recover_pm_error(struct ufs_hba *hba) { + struct scsi_target *starget = hba->ufs_device_wlun->sdev_target; struct Scsi_Host *shost = hba->host; struct scsi_device *sdev; struct request_queue *q; - int ret; + bool resume_sdev_queues = false; hba->is_sys_suspended = false; + /* - * Set RPM status of wlun device to RPM_ACTIVE, - * this also clears its runtime error. + * Ensure the parent's error status is cleared before proceeding + * to the child, as the parent must be active to activate the child. */ - ret = pm_runtime_set_active(&hba->ufs_device_wlun->sdev_gendev); + if (hba->dev->power.runtime_error) { + /* hba->dev has no functional parent thus simplily set RPM_ACTIVE */ + pm_runtime_set_active(hba->dev); + resume_sdev_queues = true; + } + + if (hba->ufs_device_wlun->sdev_gendev.power.runtime_error) { + /* + * starget, parent of wlun, might be suspended if wlun resume failed. + * Make sure parent is resumed before set child (wlun) active. + */ + pm_runtime_get_sync(&starget->dev); + pm_runtime_set_active(&hba->ufs_device_wlun->sdev_gendev); + pm_runtime_put_sync(&starget->dev); + resume_sdev_queues = true; + } - /* hba device might have a runtime error otherwise */ - if (ret) - ret = pm_runtime_set_active(hba->dev); /* * If wlun device had runtime error, we also need to resume those * consumer scsi devices in case any of them has failed to be * resumed due to supplier runtime resume failure. This is to unblock * blk_queue_enter in case there are bios waiting inside it. */ - if (!ret) { + if (resume_sdev_queues) { shost_for_each_device(sdev, shost) { q = sdev->request_queue; if (q->dev && (q->rpm_status == RPM_SUSPENDED || From 5f0fd06d7571abf0a56e7e291e05132efc416a82 Mon Sep 17 00:00:00 2001 From: Xingui Yang Date: Tue, 2 Dec 2025 14:56:27 +0800 Subject: [PATCH 1830/2333] scsi: Revert "scsi: libsas: Fix exp-attached device scan after probe failure scanned in again after probe failed" [ Upstream commit 278712d20bc8ec29d1ad6ef9bdae9000ef2c220c ] This reverts commit ab2068a6fb84751836a84c26ca72b3beb349619d. When probing the exp-attached sata device, libsas/libata will issue a hard reset in sas_probe_sata() -> ata_sas_async_probe(), then a broadcast event will be received after the disk probe fails, and this commit causes the probe will be re-executed on the disk, and a faulty disk may get into an indefinite loop of probe. Therefore, revert this commit, although it can fix some temporary issues with disk probe failure. Signed-off-by: Xingui Yang Reviewed-by: Jason Yan Reviewed-by: John Garry Link: https://patch.msgid.link/20251202065627.140361-1-yangxingui@huawei.com Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin --- drivers/scsi/libsas/sas_internal.h | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/drivers/scsi/libsas/sas_internal.h b/drivers/scsi/libsas/sas_internal.h index 6706f2be8d274..da5408c701cdd 100644 --- a/drivers/scsi/libsas/sas_internal.h +++ b/drivers/scsi/libsas/sas_internal.h @@ -145,20 +145,6 @@ static inline void sas_fail_probe(struct domain_device *dev, const char *func, i func, dev->parent ? "exp-attached" : "direct-attached", SAS_ADDR(dev->sas_addr), err); - - /* - * If the device probe failed, the expander phy attached address - * needs to be reset so that the phy will not be treated as flutter - * in the next revalidation - */ - if (dev->parent && !dev_is_expander(dev->dev_type)) { - struct sas_phy *phy = dev->phy; - struct domain_device *parent = dev->parent; - struct ex_phy *ex_phy = &parent->ex_dev.ex_phy[phy->number]; - - memset(ex_phy->attached_sas_addr, 0, SAS_ADDR_SIZE); - } - sas_unregister_dev(dev->port, dev); } From 7d59377ada9f6986395f3d8a75eceec8ca49c083 Mon Sep 17 00:00:00 2001 From: Boris Burkov Date: Mon, 1 Dec 2025 12:47:14 -0800 Subject: [PATCH 1831/2333] btrfs: fix qgroup_snapshot_quick_inherit() squota bug [ Upstream commit 7ee19a59a75e3d5b9ec00499b86af8e2a46fbe86 ] qgroup_snapshot_quick_inherit() detects conditions where the snapshot destination would land in the same parent qgroup as the snapshot source subvolume. In this case we can avoid costly qgroup calculations and just add the nodesize of the new snapshot to the parent. However, in the case of squotas this is actually a double count, and also an undercount for deeper qgroup nestings. The following annotated script shows the issue: btrfs quota enable --simple "$mnt" # Create 2-level qgroup hierarchy btrfs qgroup create 2/100 "$mnt" # Q2 (level 2) btrfs qgroup create 1/100 "$mnt" # Q1 (level 1) btrfs qgroup assign 1/100 2/100 "$mnt" # Create base subvolume btrfs subvolume create "$mnt/base" >/dev/null base_id=$(btrfs subvolume show "$mnt/base" | grep 'Subvolume ID:' | awk '{print $3}') # Create intermediate snapshot and add to Q1 btrfs subvolume snapshot "$mnt/base" "$mnt/intermediate" >/dev/null inter_id=$(btrfs subvolume show "$mnt/intermediate" | grep 'Subvolume ID:' | awk '{print $3}') btrfs qgroup assign "0/$inter_id" 1/100 "$mnt" # Create working snapshot with --inherit (auto-adds to Q1) # src=intermediate (in only Q1) # dst=snap (inheriting only into Q1) # This double counts the 16k nodesize of the snapshot in Q1, and # undercounts it in Q2. btrfs subvolume snapshot -i 1/100 "$mnt/intermediate" "$mnt/snap" >/dev/null snap_id=$(btrfs subvolume show "$mnt/snap" | grep 'Subvolume ID:' | awk '{print $3}') # Fully complete snapshot creation sync # Delete working snapshot # Q1 and Q2 will lose the full snap usage btrfs subvolume delete "$mnt/snap" >/dev/null # Delete intermediate and remove from Q1 # Q1 and Q2 will lose the full intermediate usage btrfs qgroup remove "0/$inter_id" 1/100 "$mnt" btrfs subvolume delete "$mnt/intermediate" >/dev/null # Q1 should be at 0, but still has 16k. Q2 is "correct" at 0 (for now...) # Trigger cleaner, wait for deletions mount -o remount,sync=1 "$mnt" btrfs subvolume sync "$mnt" "$snap_id" btrfs subvolume sync "$mnt" "$inter_id" # Remove Q1 from Q2 # Frees 16k more from Q2, underflowing it to 16EiB btrfs qgroup remove 1/100 2/100 "$mnt" # And show the bad state: btrfs qgroup show -pc "$mnt" Qgroupid Referenced Exclusive Parent Child Path -------- ---------- --------- ------ ----- ---- 0/5 16.00KiB 16.00KiB - - 0/256 16.00KiB 16.00KiB - - base 1/100 16.00KiB 16.00KiB - - <0 member qgroups> 2/100 16.00EiB 16.00EiB - - <0 member qgroups> Fix this by simply not doing this quick inheritance with squotas. I suspect that it is also wrong in normal qgroups to not recurse up the qgroup tree in the quick inherit case, though other consistency checks will likely fix it anyway. Fixes: b20fe56cd285 ("btrfs: qgroup: allow quick inherit if snapshot is created and added to the same parent") Reviewed-by: Qu Wenruo Signed-off-by: Boris Burkov Signed-off-by: David Sterba Signed-off-by: Sasha Levin --- fs/btrfs/qgroup.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c index 31ad8580322a6..7faaa777010d7 100644 --- a/fs/btrfs/qgroup.c +++ b/fs/btrfs/qgroup.c @@ -3247,6 +3247,9 @@ static int qgroup_snapshot_quick_inherit(struct btrfs_fs_info *fs_info, struct btrfs_qgroup_list *list; int nr_parents = 0; + if (btrfs_qgroup_mode(fs_info) != BTRFS_QGROUP_MODE_FULL) + return 0; + src = find_qgroup_rb(fs_info, srcid); if (!src) return -ENOENT; From 1ee62906cbd9a7d78aee765d15afa2b18aaf5e16 Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Thu, 4 Dec 2025 14:38:23 +1030 Subject: [PATCH 1832/2333] btrfs: qgroup: update all parent qgroups when doing quick inherit [ Upstream commit 68d4b3fa18d72b7f649e83012e7e08f1881f6b75 ] [BUG] There is a bug that if a subvolume has multi-level parent qgroups, and is able to do a quick inherit, only the direct parent qgroup got updated: mkfs.btrfs -f -O quota $dev mount $dev $mnt btrfs subv create $mnt/subv1 btrfs qgroup create 1/100 $mnt btrfs qgroup create 2/100 $mnt btrfs qgroup assign 1/100 2/100 $mnt btrfs qgroup assign 0/256 1/100 $mnt btrfs qgroup show -p --sync $mnt Qgroupid Referenced Exclusive Parent Path -------- ---------- --------- ------ ---- 0/5 16.00KiB 16.00KiB - 0/256 16.00KiB 16.00KiB 1/100 subv1 1/100 16.00KiB 16.00KiB 2/100 2/100<1 member qgroup> 2/100 16.00KiB 16.00KiB - <0 member qgroups> btrfs subv snap -i 1/100 $mnt/subv1 $mnt/snap1 btrfs qgroup show -p --sync $mnt Qgroupid Referenced Exclusive Parent Path -------- ---------- --------- ------ ---- 0/5 16.00KiB 16.00KiB - 0/256 16.00KiB 16.00KiB 1/100 subv1 0/257 16.00KiB 16.00KiB 1/100 snap1 1/100 32.00KiB 32.00KiB 2/100 2/100<1 member qgroup> 2/100 16.00KiB 16.00KiB - <0 member qgroups> # Note that 2/100 is not updated, and qgroup numbers are inconsistent umount $mnt [CAUSE] If the snapshot source subvolume belongs to a parent qgroup, and the new snapshot target is also added to the new same parent qgroup, we allow a quick update without marking qgroup inconsistent. But that quick update only update the parent qgroup, without checking if there is any more parent qgroups. [FIX] Iterate through all parent qgroups during the quick inherit. Reported-by: Boris Burkov Fixes: b20fe56cd285 ("btrfs: qgroup: allow quick inherit if snapshot is created and added to the same parent") Reviewed-by: Boris Burkov Signed-off-by: Qu Wenruo Signed-off-by: David Sterba Signed-off-by: Sasha Levin --- fs/btrfs/qgroup.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c index 7faaa777010d7..febc22d1b6487 100644 --- a/fs/btrfs/qgroup.c +++ b/fs/btrfs/qgroup.c @@ -3244,7 +3244,10 @@ static int qgroup_snapshot_quick_inherit(struct btrfs_fs_info *fs_info, { struct btrfs_qgroup *src; struct btrfs_qgroup *parent; + struct btrfs_qgroup *qgroup; struct btrfs_qgroup_list *list; + LIST_HEAD(qgroup_list); + const u32 nodesize = fs_info->nodesize; int nr_parents = 0; if (btrfs_qgroup_mode(fs_info) != BTRFS_QGROUP_MODE_FULL) @@ -3284,8 +3287,19 @@ static int qgroup_snapshot_quick_inherit(struct btrfs_fs_info *fs_info, if (parent->excl != parent->rfer) return 1; - parent->excl += fs_info->nodesize; - parent->rfer += fs_info->nodesize; + qgroup_iterator_add(&qgroup_list, parent); + list_for_each_entry(qgroup, &qgroup_list, iterator) { + qgroup->rfer += nodesize; + qgroup->rfer_cmpr += nodesize; + qgroup->excl += nodesize; + qgroup->excl_cmpr += nodesize; + qgroup_dirty(fs_info, qgroup); + + /* Append parent qgroups to @qgroup_list. */ + list_for_each_entry(list, &qgroup->groups, next_group) + qgroup_iterator_add(&qgroup_list, list->group); + } + qgroup_iterator_clean(&qgroup_list); return 0; } From 99e057f3d3ef24b99a7b1d84e01dd1bd890098da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miquel=20Sabat=C3=A9=20Sol=C3=A0?= Date: Tue, 21 Oct 2025 11:11:25 +0200 Subject: [PATCH 1833/2333] btrfs: fix NULL dereference on root when tracing inode eviction MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit f157dd661339fc6f5f2b574fe2429c43bd309534 ] When evicting an inode the first thing we do is to setup tracing for it, which implies fetching the root's id. But in btrfs_evict_inode() the root might be NULL, as implied in the next check that we do in btrfs_evict_inode(). Hence, we either should set the ->root_objectid to 0 in case the root is NULL, or we move tracing setup after checking that the root is not NULL. Setting the rootid to 0 at least gives us the possibility to trace this call even in the case when the root is NULL, so that's the solution taken here. Fixes: 1abe9b8a138c ("Btrfs: add initial tracepoint support for btrfs") Reported-by: syzbot+d991fea1b4b23b1f6bf8@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=d991fea1b4b23b1f6bf8 Signed-off-by: Miquel Sabaté Solà Reviewed-by: David Sterba Signed-off-by: David Sterba Signed-off-by: Sasha Levin --- include/trace/events/btrfs.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/trace/events/btrfs.h b/include/trace/events/btrfs.h index 7e418f065b945..125bdc166bfed 100644 --- a/include/trace/events/btrfs.h +++ b/include/trace/events/btrfs.h @@ -224,7 +224,8 @@ DECLARE_EVENT_CLASS(btrfs__inode, __entry->generation = BTRFS_I(inode)->generation; __entry->last_trans = BTRFS_I(inode)->last_trans; __entry->logged_trans = BTRFS_I(inode)->logged_trans; - __entry->root_objectid = btrfs_root_id(BTRFS_I(inode)->root); + __entry->root_objectid = BTRFS_I(inode)->root ? + btrfs_root_id(BTRFS_I(inode)->root) : 0; ), TP_printk_btrfs("root=%llu(%s) gen=%llu ino=%llu blocks=%llu " From c8385851a5435f4006281828d428e5d0b0bbf8af Mon Sep 17 00:00:00 2001 From: Leo Martins Date: Fri, 12 Dec 2025 17:26:26 -0800 Subject: [PATCH 1834/2333] btrfs: fix use-after-free warning in btrfs_get_or_create_delayed_node() [ Upstream commit 83f59076a1ae6f5c6845d6f7ed3a1a373d883684 ] Previously, btrfs_get_or_create_delayed_node() set the delayed_node's refcount before acquiring the root->delayed_nodes lock. Commit e8513c012de7 ("btrfs: implement ref_tracker for delayed_nodes") moved refcount_set inside the critical section, which means there is no longer a memory barrier between setting the refcount and setting btrfs_inode->delayed_node. Without that barrier, the stores to node->refs and btrfs_inode->delayed_node may become visible out of order. Another thread can then read btrfs_inode->delayed_node and attempt to increment a refcount that hasn't been set yet, leading to a refcounting bug and a use-after-free warning. The fix is to move refcount_set back to where it was to take advantage of the implicit memory barrier provided by lock acquisition. Because the allocations now happen outside of the lock's critical section, they can use GFP_NOFS instead of GFP_ATOMIC. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-lkp/202511262228.6dda231e-lkp@intel.com Fixes: e8513c012de7 ("btrfs: implement ref_tracker for delayed_nodes") Tested-by: kernel test robot Reviewed-by: Filipe Manana Signed-off-by: Leo Martins Signed-off-by: David Sterba Signed-off-by: Sasha Levin --- fs/btrfs/delayed-inode.c | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/fs/btrfs/delayed-inode.c b/fs/btrfs/delayed-inode.c index 3df7b9d7fbe8d..59b489d7e4b58 100644 --- a/fs/btrfs/delayed-inode.c +++ b/fs/btrfs/delayed-inode.c @@ -152,37 +152,39 @@ static struct btrfs_delayed_node *btrfs_get_or_create_delayed_node( return ERR_PTR(-ENOMEM); btrfs_init_delayed_node(node, root, ino); + /* Cached in the inode and can be accessed. */ + refcount_set(&node->refs, 2); + btrfs_delayed_node_ref_tracker_alloc(node, tracker, GFP_NOFS); + btrfs_delayed_node_ref_tracker_alloc(node, &node->inode_cache_tracker, GFP_NOFS); + /* Allocate and reserve the slot, from now it can return a NULL from xa_load(). */ ret = xa_reserve(&root->delayed_nodes, ino, GFP_NOFS); - if (ret == -ENOMEM) { - btrfs_delayed_node_ref_tracker_dir_exit(node); - kmem_cache_free(delayed_node_cache, node); - return ERR_PTR(-ENOMEM); - } + if (ret == -ENOMEM) + goto cleanup; + xa_lock(&root->delayed_nodes); ptr = xa_load(&root->delayed_nodes, ino); if (ptr) { /* Somebody inserted it, go back and read it. */ xa_unlock(&root->delayed_nodes); - btrfs_delayed_node_ref_tracker_dir_exit(node); - kmem_cache_free(delayed_node_cache, node); - node = NULL; - goto again; + goto cleanup; } ptr = __xa_store(&root->delayed_nodes, ino, node, GFP_ATOMIC); ASSERT(xa_err(ptr) != -EINVAL); ASSERT(xa_err(ptr) != -ENOMEM); ASSERT(ptr == NULL); - - /* Cached in the inode and can be accessed. */ - refcount_set(&node->refs, 2); - btrfs_delayed_node_ref_tracker_alloc(node, tracker, GFP_ATOMIC); - btrfs_delayed_node_ref_tracker_alloc(node, &node->inode_cache_tracker, GFP_ATOMIC); - btrfs_inode->delayed_node = node; xa_unlock(&root->delayed_nodes); return node; +cleanup: + btrfs_delayed_node_ref_tracker_free(node, tracker); + btrfs_delayed_node_ref_tracker_free(node, &node->inode_cache_tracker); + btrfs_delayed_node_ref_tracker_dir_exit(node); + kmem_cache_free(delayed_node_cache, node); + if (ret) + return ERR_PTR(ret); + goto again; } /* From f09b0f705bd7197863b90256ef533a6414d1db2c Mon Sep 17 00:00:00 2001 From: Zilin Guan Date: Wed, 31 Dec 2025 11:49:15 +0000 Subject: [PATCH 1835/2333] of: unittest: Fix memory leak in unittest_data_add() [ Upstream commit 235a1eb8d2dcc49a6cf0a5ee1aa85544a5d0054b ] In unittest_data_add(), if of_resolve_phandles() fails, the allocated unittest_data is not freed, leading to a memory leak. Fix this by using scope-based cleanup helper __free(kfree) for automatic resource cleanup. This ensures unittest_data is automatically freed when it goes out of scope in error paths. For the success path, use retain_and_null_ptr() to transfer ownership of the memory to the device tree and prevent double freeing. Fixes: 2eb46da2a760 ("of/selftest: Use the resolver to fixup phandles") Suggested-by: Rob Herring Co-developed-by: Jianhao Xu Signed-off-by: Jianhao Xu Signed-off-by: Zilin Guan Link: https://patch.msgid.link/20251231114915.234638-1-zilin@seu.edu.cn Signed-off-by: Rob Herring (Arm) Signed-off-by: Sasha Levin --- drivers/of/unittest.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c index 388e9ec2cccf8..3b773aaf9d050 100644 --- a/drivers/of/unittest.c +++ b/drivers/of/unittest.c @@ -1985,7 +1985,6 @@ static void attach_node_and_children(struct device_node *np) */ static int __init unittest_data_add(void) { - void *unittest_data; void *unittest_data_align; struct device_node *unittest_data_node = NULL, *np; /* @@ -2004,7 +2003,7 @@ static int __init unittest_data_add(void) } /* creating copy */ - unittest_data = kmalloc(size + FDT_ALIGN_SIZE, GFP_KERNEL); + void *unittest_data __free(kfree) = kmalloc(size + FDT_ALIGN_SIZE, GFP_KERNEL); if (!unittest_data) return -ENOMEM; @@ -2014,12 +2013,10 @@ static int __init unittest_data_add(void) ret = of_fdt_unflatten_tree(unittest_data_align, NULL, &unittest_data_node); if (!ret) { pr_warn("%s: unflatten testcases tree failed\n", __func__); - kfree(unittest_data); return -ENODATA; } if (!unittest_data_node) { pr_warn("%s: testcases tree is empty\n", __func__); - kfree(unittest_data); return -ENODATA; } @@ -2038,7 +2035,6 @@ static int __init unittest_data_add(void) /* attach the sub-tree to live tree */ if (!of_root) { pr_warn("%s: no live tree to attach sub-tree\n", __func__); - kfree(unittest_data); rc = -ENODEV; goto unlock; } @@ -2059,6 +2055,8 @@ static int __init unittest_data_add(void) EXPECT_END(KERN_INFO, "Duplicate name in testcase-data, renamed to \"duplicate-name#1\""); + retain_and_null_ptr(unittest_data); + unlock: of_overlay_mutex_unlock(); From 0d4087c7486977960f82b764a4f4df19bba367a6 Mon Sep 17 00:00:00 2001 From: Wadim Egorov Date: Thu, 27 Nov 2025 13:27:31 +0100 Subject: [PATCH 1836/2333] arm64: dts: ti: k3-am642-phyboard-electra-peb-c-010: Fix icssg-prueth schema warning [ Upstream commit 05bbe52d0be5637dcd3c880348e3688f7ec64eb7 ] Reduce length of dma-names and dmas properties for icssg1-ethernet node to comply with ti,icssg-prueth schema constraints. The previous entries exceeded the allowed count and triggered dtschema warnings during validation. Fixes: e53fbf955ea7 ("arm64: dts: ti: k3-am642-phyboard-electra: Add PEB-C-010 Overlay") Signed-off-by: Wadim Egorov Link: https://patch.msgid.link/20251127122733.2523367-1-w.egorov@phytec.de Signed-off-by: Nishanth Menon Signed-off-by: Sasha Levin --- .../boot/dts/ti/k3-am642-phyboard-electra-peb-c-010.dtso | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/arch/arm64/boot/dts/ti/k3-am642-phyboard-electra-peb-c-010.dtso b/arch/arm64/boot/dts/ti/k3-am642-phyboard-electra-peb-c-010.dtso index 7fc73cfacadb8..1176a52d560b7 100644 --- a/arch/arm64/boot/dts/ti/k3-am642-phyboard-electra-peb-c-010.dtso +++ b/arch/arm64/boot/dts/ti/k3-am642-phyboard-electra-peb-c-010.dtso @@ -30,13 +30,10 @@ <&main_pktdma 0xc206 15>, /* egress slice 1 */ <&main_pktdma 0xc207 15>, /* egress slice 1 */ <&main_pktdma 0x4200 15>, /* ingress slice 0 */ - <&main_pktdma 0x4201 15>, /* ingress slice 1 */ - <&main_pktdma 0x4202 0>, /* mgmnt rsp slice 0 */ - <&main_pktdma 0x4203 0>; /* mgmnt rsp slice 1 */ + <&main_pktdma 0x4201 15>; /* ingress slice 1 */ dma-names = "tx0-0", "tx0-1", "tx0-2", "tx0-3", "tx1-0", "tx1-1", "tx1-2", "tx1-3", - "rx0", "rx1", - "rxmgm0", "rxmgm1"; + "rx0", "rx1"; firmware-name = "ti-pruss/am65x-sr2-pru0-prueth-fw.elf", "ti-pruss/am65x-sr2-rtu0-prueth-fw.elf", From c5ebc38066ce10cb329b4f6630f8c74b5dc8496c Mon Sep 17 00:00:00 2001 From: Wadim Egorov Date: Thu, 27 Nov 2025 13:27:32 +0100 Subject: [PATCH 1837/2333] arm64: dts: ti: k3-am642-phyboard-electra-x27-gpio1-spi1-uart3: Fix schema warnings [ Upstream commit d876bb9353d87dee0ae620300106e8def189c785 ] Rename pinctrl nodes to comply with naming conventions required by pinctrl-single schema. Also, replace invalid integer assignment in SPI node with a boolean to align with omap-spi schema. Fixes: 638ab30ce4c6 ("arm64: dts: ti: am64-phyboard-electra: Add DT overlay for X27 connector") Signed-off-by: Wadim Egorov Link: https://patch.msgid.link/20251127122733.2523367-2-w.egorov@phytec.de Signed-off-by: Nishanth Menon Signed-off-by: Sasha Levin --- .../k3-am642-phyboard-electra-x27-gpio1-spi1-uart3.dtso | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/arm64/boot/dts/ti/k3-am642-phyboard-electra-x27-gpio1-spi1-uart3.dtso b/arch/arm64/boot/dts/ti/k3-am642-phyboard-electra-x27-gpio1-spi1-uart3.dtso index 996c42ec4253e..bea8efa3e9094 100644 --- a/arch/arm64/boot/dts/ti/k3-am642-phyboard-electra-x27-gpio1-spi1-uart3.dtso +++ b/arch/arm64/boot/dts/ti/k3-am642-phyboard-electra-x27-gpio1-spi1-uart3.dtso @@ -20,13 +20,13 @@ }; &main_pmx0 { - main_gpio1_exp_header_gpio_pins_default: main-gpio1-exp-header-gpio-pins-default { + main_gpio1_exp_header_gpio_pins_default: main-gpio1-exp-header-gpio-default-pins { pinctrl-single,pins = < AM64X_IOPAD(0x0220, PIN_INPUT, 7) /* (D14) SPI1_CS1.GPIO1_48 */ >; }; - main_spi1_pins_default: main-spi1-pins-default { + main_spi1_pins_default: main-spi1-default-pins { pinctrl-single,pins = < AM64X_IOPAD(0x0224, PIN_INPUT, 0) /* (C14) SPI1_CLK */ AM64X_IOPAD(0x021C, PIN_OUTPUT, 0) /* (B14) SPI1_CS0 */ @@ -35,7 +35,7 @@ >; }; - main_uart3_pins_default: main-uart3-pins-default { + main_uart3_pins_default: main-uart3-default-pins { pinctrl-single,pins = < AM64X_IOPAD(0x0048, PIN_INPUT, 2) /* (U20) GPMC0_AD3.UART3_RXD */ AM64X_IOPAD(0x004c, PIN_OUTPUT, 2) /* (U18) GPMC0_AD4.UART3_TXD */ @@ -52,7 +52,7 @@ &main_spi1 { pinctrl-names = "default"; pinctrl-0 = <&main_spi1_pins_default>; - ti,pindir-d0-out-d1-in = <1>; + ti,pindir-d0-out-d1-in; status = "okay"; }; From 93900292af115ac5a7a378c8f3b658d51863fce9 Mon Sep 17 00:00:00 2001 From: Wadim Egorov Date: Thu, 27 Nov 2025 13:27:33 +0100 Subject: [PATCH 1838/2333] arm64: dts: ti: k3-am62-lp-sk-nand: Rename pinctrls to fix schema warnings [ Upstream commit cf5e8adebe77917a4cc95e43e461cdbd857591ce ] Rename pinctrl nodes to comply with naming conventions required by pinctrl-single schema. Fixes: e569152274fec ("arm64: dts: ti: am62-lp-sk: Add overlay for NAND expansion card") Signed-off-by: Wadim Egorov Link: https://patch.msgid.link/20251127122733.2523367-3-w.egorov@phytec.de Signed-off-by: Nishanth Menon Signed-off-by: Sasha Levin --- arch/arm64/boot/dts/ti/k3-am62-lp-sk-nand.dtso | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/ti/k3-am62-lp-sk-nand.dtso b/arch/arm64/boot/dts/ti/k3-am62-lp-sk-nand.dtso index 173ac60723b64..b4daa674eaa1e 100644 --- a/arch/arm64/boot/dts/ti/k3-am62-lp-sk-nand.dtso +++ b/arch/arm64/boot/dts/ti/k3-am62-lp-sk-nand.dtso @@ -14,7 +14,7 @@ }; &main_pmx0 { - gpmc0_pins_default: gpmc0-pins-default { + gpmc0_pins_default: gpmc0-default-pins { pinctrl-single,pins = < AM62X_IOPAD(0x003c, PIN_INPUT, 0) /* (K19) GPMC0_AD0 */ AM62X_IOPAD(0x0040, PIN_INPUT, 0) /* (L19) GPMC0_AD1 */ From 43c2e3670334f6b9c77626bea03cfc363904b9b2 Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Wed, 5 Nov 2025 09:40:09 +0900 Subject: [PATCH 1839/2333] gpu: nova-core: select RUST_FW_LOADER_ABSTRACTIONS [ Upstream commit 3d3352e73a55a4ccf110f8b3419bbe2fbfd8a030 ] RUST_FW_LOADER_ABSTRACTIONS was depended on by NOVA_CORE, but NOVA_CORE is selected by DRM_NOVA. This creates a situation where, if DRM_NOVA is selected, NOVA_CORE gets enabled but not RUST_FW_LOADER_ABSTRACTIONS, which results in a build error. Since the firmware loader is an implementation detail of the driver, it should be enabled along with it, so change the "depends on" to a "select". Fixes: 54e6baf123fd ("gpu: nova-core: add initial driver stub") Closes: https://lore.kernel.org/oe-kbuild-all/202512061721.rxKGnt5q-lkp@intel.com/ Tested-by: Alyssa Ross Acked-by: Danilo Krummrich Link: https://patch.msgid.link/20251106-b4-select-rust-fw-v3-2-771172257755@nvidia.com Signed-off-by: Alexandre Courbot Signed-off-by: Sasha Levin --- drivers/gpu/nova-core/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/nova-core/Kconfig b/drivers/gpu/nova-core/Kconfig index 20d3e6d0d796e..527920f9c4d39 100644 --- a/drivers/gpu/nova-core/Kconfig +++ b/drivers/gpu/nova-core/Kconfig @@ -3,7 +3,7 @@ config NOVA_CORE depends on 64BIT depends on PCI depends on RUST - depends on RUST_FW_LOADER_ABSTRACTIONS + select RUST_FW_LOADER_ABSTRACTIONS select AUXILIARY_BUS default n help From 737f341080f4c7f3e2455b54042b8c2a30742f18 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Wed, 10 Dec 2025 06:50:26 +0100 Subject: [PATCH 1840/2333] gpio: it87: balance superio enter/exit calls in error path [ Upstream commit a05543d6b05ba998fdbb4b383319ae5121bb7407 ] We always call superio_enter() in it87_gpio_direction_out() but only call superio_exit() if the call to it87_gpio_set() succeeds. Move the label to balance the calls in error path as well. Fixes: ef877a159072 ("gpio: it87: use new line value setter callbacks") Reported-by: Daniel Gibson Closes: https://lore.kernel.org/all/bd0a00e3-9b8c-43e8-8772-e67b91f4c71e@gibson.sh/ Link: https://lore.kernel.org/r/20251210055026.23146-1-bartosz.golaszewski@oss.qualcomm.com Signed-off-by: Bartosz Golaszewski Signed-off-by: Sasha Levin --- drivers/gpio/gpio-it87.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/drivers/gpio/gpio-it87.c b/drivers/gpio/gpio-it87.c index 5d677bcfccf26..2ad3c239367bc 100644 --- a/drivers/gpio/gpio-it87.c +++ b/drivers/gpio/gpio-it87.c @@ -12,6 +12,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include #include #include #include @@ -241,23 +242,17 @@ static int it87_gpio_direction_out(struct gpio_chip *chip, mask = 1 << (gpio_num % 8); group = (gpio_num / 8); - spin_lock(&it87_gpio->lock); + guard(spinlock)(&it87_gpio->lock); rc = superio_enter(); if (rc) - goto exit; + return rc; /* set the output enable bit */ superio_set_mask(mask, group + it87_gpio->output_base); rc = it87_gpio_set(chip, gpio_num, val); - if (rc) - goto exit; - superio_exit(); - -exit: - spin_unlock(&it87_gpio->lock); return rc; } From a5eeebb994bf6456d9bdc8af12d19c9ea38ed8b1 Mon Sep 17 00:00:00 2001 From: Thomas Fourier Date: Wed, 3 Dec 2025 17:56:35 +0100 Subject: [PATCH 1841/2333] HID: Intel-thc-hid: Intel-thc: fix dma_unmap_sg() nents value [ Upstream commit 0e13150c1a13a3a3d6184c24bfd080d5999945d1 ] The `dma_unmap_sg()` functions should be called with the same nents as the `dma_map_sg()`, not the value the map function returned. Save the number of entries in struct thc_dma_configuration. Fixes: a688404b2e20 ("HID: intel-thc-hid: intel-thc: Add THC DMA interfaces") Signed-off-by: Thomas Fourier Reviewed-by: Even Xu Reviewed-by: Andy Shevchenko Signed-off-by: Benjamin Tissoires Signed-off-by: Sasha Levin --- drivers/hid/intel-thc-hid/intel-thc/intel-thc-dma.c | 4 +++- drivers/hid/intel-thc-hid/intel-thc/intel-thc-dma.h | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dma.c b/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dma.c index 82b8854843e05..a0c368aa7979c 100644 --- a/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dma.c +++ b/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dma.c @@ -232,6 +232,7 @@ static int setup_dma_buffers(struct thc_device *dev, return 0; memset(config->sgls, 0, sizeof(config->sgls)); + memset(config->sgls_nent_pages, 0, sizeof(config->sgls_nent_pages)); memset(config->sgls_nent, 0, sizeof(config->sgls_nent)); cpu_addr = dma_alloc_coherent(dev->dev, prd_tbls_size, @@ -254,6 +255,7 @@ static int setup_dma_buffers(struct thc_device *dev, } count = dma_map_sg(dev->dev, config->sgls[i], nent, dir); + config->sgls_nent_pages[i] = nent; config->sgls_nent[i] = count; } @@ -299,7 +301,7 @@ static void release_dma_buffers(struct thc_device *dev, continue; dma_unmap_sg(dev->dev, config->sgls[i], - config->sgls_nent[i], + config->sgls_nent_pages[i], config->dir); sgl_free(config->sgls[i]); diff --git a/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dma.h b/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dma.h index 78917400492ca..541d33995baf3 100644 --- a/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dma.h +++ b/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dma.h @@ -91,6 +91,7 @@ struct thc_prd_table { * @dir: Direction of DMA for this config * @prd_tbls: PRD tables for current DMA * @sgls: Array of pointers to scatter-gather lists + * @sgls_nent_pages: Number of pages per scatter-gather list * @sgls_nent: Actual number of entries per scatter-gather list * @prd_tbl_num: Actual number of PRD tables * @max_packet_size: Size of the buffer needed for 1 DMA message (1 PRD table) @@ -107,6 +108,7 @@ struct thc_dma_configuration { struct thc_prd_table *prd_tbls; struct scatterlist *sgls[PRD_TABLES_NUM]; + u8 sgls_nent_pages[PRD_TABLES_NUM]; u8 sgls_nent[PRD_TABLES_NUM]; u8 prd_tbl_num; From b95a6e3b0d5d7c5643cd223dbbc80ee5ad923b07 Mon Sep 17 00:00:00 2001 From: Even Xu Date: Fri, 19 Dec 2025 09:14:38 +0800 Subject: [PATCH 1842/2333] HID: Intel-thc-hid: Intel-thc: Fix wrong register reading [ Upstream commit f39006965dd37e7be823dba6ca484adccc7a4dff ] Correct the read register for the setting of max input size and interrupt delay. Fixes: 22da60f0304b ("HID: Intel-thc-hid: Intel-thc: Introduce interrupt delay control") Fixes: 45e92a093099 ("HID: Intel-thc-hid: Intel-thc: Introduce max input size control") Signed-off-by: Even Xu Signed-off-by: Benjamin Tissoires Signed-off-by: Sasha Levin --- drivers/hid/intel-thc-hid/intel-thc/intel-thc-dev.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dev.c b/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dev.c index 636a683065015..7e220a4c5ded7 100644 --- a/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dev.c +++ b/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dev.c @@ -1593,7 +1593,7 @@ int thc_i2c_set_rx_max_size(struct thc_device *dev, u32 max_rx_size) if (!max_rx_size) return -EOPNOTSUPP; - ret = regmap_read(dev->thc_regmap, THC_M_PRT_SW_SEQ_STS_OFFSET, &val); + ret = regmap_read(dev->thc_regmap, THC_M_PRT_SPI_ICRRD_OPCODE_OFFSET, &val); if (ret) return ret; @@ -1662,7 +1662,7 @@ int thc_i2c_set_rx_int_delay(struct thc_device *dev, u32 delay_us) if (!delay_us) return -EOPNOTSUPP; - ret = regmap_read(dev->thc_regmap, THC_M_PRT_SW_SEQ_STS_OFFSET, &val); + ret = regmap_read(dev->thc_regmap, THC_M_PRT_SPI_ICRRD_OPCODE_OFFSET, &val); if (ret) return ret; From 5b5482c0e5ee740b35a70759d3582477aea8e8e4 Mon Sep 17 00:00:00 2001 From: David Howells Date: Sat, 20 Dec 2025 12:31:40 +0000 Subject: [PATCH 1843/2333] netfs: Fix early read unlock of page with EOF in middle [ Upstream commit 570ad253a3455a520f03c2136af8714bc780186d ] The read result collection for buffered reads seems to run ahead of the completion of subrequests under some circumstances, as can be seen in the following log snippet: 9p_client_res: client 18446612686390831168 response P9_TREAD tag 0 err 0 ... netfs_sreq: R=00001b55[1] DOWN TERM f=192 s=0 5fb2/5fb2 s=5 e=0 ... netfs_collect_folio: R=00001b55 ix=00004 r=4000-5000 t=4000/5fb2 netfs_folio: i=157f3 ix=00004-00004 read-done netfs_folio: i=157f3 ix=00004-00004 read-unlock netfs_collect_folio: R=00001b55 ix=00005 r=5000-5fb2 t=5000/5fb2 netfs_folio: i=157f3 ix=00005-00005 read-done netfs_folio: i=157f3 ix=00005-00005 read-unlock ... netfs_collect_stream: R=00001b55[0:] cto=5fb2 frn=ffffffff netfs_collect_state: R=00001b55 col=5fb2 cln=6000 n=c netfs_collect_stream: R=00001b55[0:] cto=5fb2 frn=ffffffff netfs_collect_state: R=00001b55 col=5fb2 cln=6000 n=8 ... netfs_sreq: R=00001b55[2] ZERO SUBMT f=000 s=5fb2 0/4e s=0 e=0 netfs_sreq: R=00001b55[2] ZERO TERM f=102 s=5fb2 4e/4e s=5 e=0 The 'cto=5fb2' indicates the collected file pos we've collected results to so far - but we still have 0x4e more bytes to go - so we shouldn't have collected folio ix=00005 yet. The 'ZERO' subreq that clears the tail happens after we unlock the folio, allowing the application to see the uncleared tail through mmap. The problem is that netfs_read_unlock_folios() will unlock a folio in which the amount of read results collected hits EOF position - but the ZERO subreq lies beyond that and so happens after. Fix this by changing the end check to always be the end of the folio and never the end of the file. In the future, I should look at clearing to the end of the folio here rather than adding a ZERO subreq to do this. On the other hand, the ZERO subreq can run in parallel with an async READ subreq. Further, the ZERO subreq may still be necessary to, say, handle extents in a ceph file that don't have any backing store and are thus implicitly all zeros. This can be reproduced by creating a file, the size of which doesn't align to a page boundary, e.g. 24998 (0x5fb2) bytes and then doing something like: xfs_io -c "mmap -r 0 0x6000" -c "madvise -d 0 0x6000" \ -c "mread -v 0 0x6000" /xfstest.test/x The last 0x4e bytes should all be 00, but if the tail hasn't been cleared yet, you may see rubbish there. This can be reproduced with kafs by modifying the kernel to disable the call to netfs_read_subreq_progress() and to stop afs_issue_read() from doing the async call for NETFS_READAHEAD. Reproduction can be made easier by inserting an mdelay(100) in netfs_issue_read() for the ZERO-subreq case. AFS and CIFS are normally unlikely to show this as they dispatch READ ops asynchronously, which allows the ZERO-subreq to finish first. 9P's READ op is completely synchronous, so the ZERO-subreq will always happen after. It isn't seen all the time, though, because the collection may be done in a worker thread. Reported-by: Christian Schoenebeck Link: https://lore.kernel.org/r/8622834.T7Z3S40VBb@weasel/ Signed-off-by: David Howells Link: https://patch.msgid.link/938162.1766233900@warthog.procyon.org.uk Fixes: e2d46f2ec332 ("netfs: Change the read result collector to only use one work item") Tested-by: Christian Schoenebeck Acked-by: Dominique Martinet Suggested-by: Dominique Martinet cc: Dominique Martinet cc: Christian Schoenebeck cc: v9fs@lists.linux.dev cc: netfs@lists.linux.dev cc: linux-fsdevel@vger.kernel.org Signed-off-by: Christian Brauner Signed-off-by: Sasha Levin --- fs/netfs/read_collect.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/netfs/read_collect.c b/fs/netfs/read_collect.c index a95e7aadafd07..7a0ffa675fb17 100644 --- a/fs/netfs/read_collect.c +++ b/fs/netfs/read_collect.c @@ -137,7 +137,7 @@ static void netfs_read_unlock_folios(struct netfs_io_request *rreq, rreq->front_folio_order = order; fsize = PAGE_SIZE << order; fpos = folio_pos(folio); - fend = umin(fpos + fsize, rreq->i_size); + fend = fpos + fsize; trace_netfs_collect_folio(rreq, folio, fend, collected_to); From 7fd534abaa3972cf8b8d63654b36ee26ddfdefaf Mon Sep 17 00:00:00 2001 From: Louis-Alexis Eyraud Date: Wed, 3 Dec 2025 12:32:42 +0100 Subject: [PATCH 1844/2333] pinctrl: mediatek: mt8189: restore previous register base name array order [ Upstream commit fa917d3d570279dc3d699cbd947d0da0fde2e402 ] In mt8189-pinctrl driver, a previous commit changed the register base name array (mt8189_pinctrl_register_base_names) entry name and order to align it with the same name and order as the "mediatek,mt8189-pinctrl" devicetree bindings. The new order (by ascending register address) now causes an issue with MT8189 pinctrl configuration. MT8189 SoC has multiple base addresses for the pin configuration registers. Several constant data structures, declaring each pin configuration, are using PIN_FIELD_BASE() macro which i_base parameter indicates for a given pin the lookup index in the base register address array of the driver internal data for the configuration register read/write accesses. But in practice, this parameter is given a hardcoded numerical value that corresponds to the expected base register entry index in mt8189_pinctrl_register_base_names array. Since this array reordering, the i_base index matching is no more correct. So, in order to avoid modifying over a thousand of PIN_FIELD_BASE() calls, restore previous mt8189_pinctrl_register_base_names entry order. Fixes: 518919276c41 ("pinctrl: mediatek: mt8189: align register base names to dt-bindings ones") Signed-off-by: Louis-Alexis Eyraud Signed-off-by: Linus Walleij Signed-off-by: Sasha Levin --- drivers/pinctrl/mediatek/pinctrl-mt8189.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pinctrl/mediatek/pinctrl-mt8189.c b/drivers/pinctrl/mediatek/pinctrl-mt8189.c index f6a3e584588b0..cd4cdff309a12 100644 --- a/drivers/pinctrl/mediatek/pinctrl-mt8189.c +++ b/drivers/pinctrl/mediatek/pinctrl-mt8189.c @@ -1642,7 +1642,7 @@ static const struct mtk_pin_reg_calc mt8189_reg_cals[PINCTRL_PIN_REG_MAX] = { }; static const char * const mt8189_pinctrl_register_base_names[] = { - "base", "lm", "rb0", "rb1", "bm0", "bm1", "bm2", "lt0", "lt1", "rt", + "base", "bm0", "bm1", "bm2", "lm", "lt0", "lt1", "rb0", "rb1", "rt", }; static const struct mtk_eint_hw mt8189_eint_hw = { From 42b66f4557a2b66268e1048e80f833859d17dc05 Mon Sep 17 00:00:00 2001 From: Harshita Bhilwaria Date: Wed, 17 Dec 2025 11:16:06 +0530 Subject: [PATCH 1845/2333] crypto: qat - fix duplicate restarting msg during AER error [ Upstream commit 961ac9d97be72267255f1ed841aabf6694b17454 ] The restarting message from PF to VF is sent twice during AER error handling: once from adf_error_detected() and again from adf_disable_sriov(). This causes userspace subservices to shutdown unexpectedly when they receive a duplicate restarting message after already being restarted. Avoid calling adf_pf2vf_notify_restarting() and adf_pf2vf_wait_for_restarting_complete() from adf_error_detected() so that the restarting msg is sent only once from PF to VF. Fixes: 9567d3dc760931 ("crypto: qat - improve aer error reset handling") Signed-off-by: Harshita Bhilwaria Reviewed-by: Giovanni Cabiddu Reviewed-by: Ahsan Atta Reviewed-by: Ravikumar PM Reviewed-by: Srikanth Thokala Signed-off-by: Herbert Xu Signed-off-by: Sasha Levin --- drivers/crypto/intel/qat/qat_common/adf_aer.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/crypto/intel/qat/qat_common/adf_aer.c b/drivers/crypto/intel/qat/qat_common/adf_aer.c index 35679b21ff63b..a098689ab5b75 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_aer.c +++ b/drivers/crypto/intel/qat/qat_common/adf_aer.c @@ -41,8 +41,6 @@ static pci_ers_result_t adf_error_detected(struct pci_dev *pdev, adf_error_notifier(accel_dev); adf_pf2vf_notify_fatal_error(accel_dev); adf_dev_restarting_notify(accel_dev); - adf_pf2vf_notify_restarting(accel_dev); - adf_pf2vf_wait_for_restarting_complete(accel_dev); pci_clear_master(pdev); adf_dev_down(accel_dev); From c200328fd57fe74742738f8a822f45cc30b9b3fe Mon Sep 17 00:00:00 2001 From: Haibo Chen Date: Wed, 19 Nov 2025 11:22:39 +0800 Subject: [PATCH 1846/2333] arm64: dts: imx8qm-mek: correct the light sensor interrupt type to low level [ Upstream commit e0d8678c2f09dca22e6197321f223fa9a0ca2839 ] light sensor isl29023 share the interrupt with lsm303arg, but these two devices use different interrupt type. According to the datasheet of these two devides, both support low level trigger type, so correct the interrupt type here to avoid the following error log: irq: type mismatch, failed to map hwirq-11 for gpio@5d0c0000! Fixes: 9918092cbb0e ("arm64: dts: imx8qm-mek: add i2c0 and children devices") Fixes: 1d8a9f043a77 ("arm64: dts: imx8: use defines for interrupts") Signed-off-by: Haibo Chen Reviewed-by: Frank Li Signed-off-by: Shawn Guo Signed-off-by: Sasha Levin --- arch/arm64/boot/dts/freescale/imx8qm-mek.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/freescale/imx8qm-mek.dts b/arch/arm64/boot/dts/freescale/imx8qm-mek.dts index 9c0b6b8d6459d..d4b13cfd87a92 100644 --- a/arch/arm64/boot/dts/freescale/imx8qm-mek.dts +++ b/arch/arm64/boot/dts/freescale/imx8qm-mek.dts @@ -560,7 +560,7 @@ compatible = "isil,isl29023"; reg = <0x44>; interrupt-parent = <&lsio_gpio4>; - interrupts = <11 IRQ_TYPE_EDGE_FALLING>; + interrupts = <11 IRQ_TYPE_LEVEL_LOW>; }; pressure-sensor@60 { From 88244021003ba364704746c837799268842939c4 Mon Sep 17 00:00:00 2001 From: Haibo Chen Date: Wed, 19 Nov 2025 11:22:40 +0800 Subject: [PATCH 1847/2333] arm64: dts: add off-on-delay-us for usdhc2 regulator [ Upstream commit ca643894a37a25713029b36cfe7d1bae515cac08 ] For SD card, according to the spec requirement, for sd card power reset operation, it need sd card supply voltage to be lower than 0.5v and keep over 1ms, otherwise, next time power back the sd card supply voltage to 3.3v, sd card can't support SD3.0 mode again. To match such requirement on imx8qm-mek board, add 4.8ms delay between sd power off and power on. Fixes: 307fd14d4b14 ("arm64: dts: imx: add imx8qm mek support") Reviewed-by: Frank Li Signed-off-by: Haibo Chen Signed-off-by: Shawn Guo Signed-off-by: Sasha Levin --- arch/arm64/boot/dts/freescale/imx8qm-mek.dts | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/boot/dts/freescale/imx8qm-mek.dts b/arch/arm64/boot/dts/freescale/imx8qm-mek.dts index d4b13cfd87a92..df99fe88cf4ac 100644 --- a/arch/arm64/boot/dts/freescale/imx8qm-mek.dts +++ b/arch/arm64/boot/dts/freescale/imx8qm-mek.dts @@ -256,6 +256,7 @@ regulator-max-microvolt = <3000000>; gpio = <&lsio_gpio4 7 GPIO_ACTIVE_HIGH>; enable-active-high; + off-on-delay-us = <4800>; }; reg_audio: regulator-audio { From 2c3f04f1f70c6177a7681f69876963be92fb52c5 Mon Sep 17 00:00:00 2001 From: Ian Ray Date: Mon, 1 Dec 2025 11:56:05 +0200 Subject: [PATCH 1848/2333] ARM: dts: imx6q-ba16: fix RTC interrupt level [ Upstream commit e6a4eedd49ce27c16a80506c66a04707e0ee0116 ] RTC interrupt level should be set to "LOW". This was revealed by the introduction of commit: f181987ef477 ("rtc: m41t80: use IRQ flags obtained from fwnode") which changed the way IRQ type is obtained. Fixes: 56c27310c1b4 ("ARM: dts: imx: Add Advantech BA-16 Qseven module") Signed-off-by: Ian Ray Signed-off-by: Shawn Guo Signed-off-by: Sasha Levin --- arch/arm/boot/dts/nxp/imx/imx6q-ba16.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/nxp/imx/imx6q-ba16.dtsi b/arch/arm/boot/dts/nxp/imx/imx6q-ba16.dtsi index 53013b12c2ecb..02d66523668d2 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6q-ba16.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx6q-ba16.dtsi @@ -337,7 +337,7 @@ pinctrl-0 = <&pinctrl_rtc>; reg = <0x32>; interrupt-parent = <&gpio4>; - interrupts = <10 IRQ_TYPE_LEVEL_HIGH>; + interrupts = <10 IRQ_TYPE_LEVEL_LOW>; }; }; From f267ced2bcb0c9d5f489a75328eb64f8f0af8c40 Mon Sep 17 00:00:00 2001 From: Maud Spierings Date: Mon, 1 Dec 2025 12:56:51 +0100 Subject: [PATCH 1849/2333] arm64: dts: freescale: moduline-display: fix compatible [ Upstream commit 056c68875122dd342782e5956ed145fe9e059614 ] The compatibles should include the SoM compatible, this board is based on the Ka-Ro TX8P-ML81 SoM, so add it to allow using shared code in the bootloader which uses upstream Linux devicetrees as a base. Also add the hardware revision to the board compatible to handle revision specific quirks in the bootloader/userspace. This is a breaking change, but it is early enough that it can be corrected without causing any issues. Fixes: 03f07be54cdc ("arm64: dts: freescale: Add the GOcontroll Moduline Display baseboard") Signed-off-by: Maud Spierings Signed-off-by: Shawn Guo Signed-off-by: Sasha Levin --- .../dts/freescale/imx8mp-tx8p-ml81-moduline-display-106.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/freescale/imx8mp-tx8p-ml81-moduline-display-106.dts b/arch/arm64/boot/dts/freescale/imx8mp-tx8p-ml81-moduline-display-106.dts index 88ad422c27603..399230144ce39 100644 --- a/arch/arm64/boot/dts/freescale/imx8mp-tx8p-ml81-moduline-display-106.dts +++ b/arch/arm64/boot/dts/freescale/imx8mp-tx8p-ml81-moduline-display-106.dts @@ -9,7 +9,7 @@ #include "imx8mp-tx8p-ml81.dtsi" / { - compatible = "gocontroll,moduline-display", "fsl,imx8mp"; + compatible = "gocontroll,moduline-display-106", "karo,tx8p-ml81", "fsl,imx8mp"; chassis-type = "embedded"; hardware = "Moduline Display V1.06"; model = "GOcontroll Moduline Display baseboard"; From 5b5ef7049ebed65de138ce0106fcfd4ea8f31c3a Mon Sep 17 00:00:00 2001 From: Maud Spierings Date: Mon, 1 Dec 2025 12:56:52 +0100 Subject: [PATCH 1850/2333] arm64: dts: freescale: tx8p-ml81: fix eqos nvmem-cells [ Upstream commit cdf4e631eec5ddd49bb625df9fb144d6ecdd6f15 ] On this SoM eqos is the primary ethernet interface, Ka-Ro fuses the address for it in eth_mac1, eth_mac2 seems to be left unfused. In their downstream u-boot they fetch it from eth_mac1 [1][2], by setting alias of eqos to ethernet0, the driver then fetches the mac address based on the alias number. Set eqos to read from eth_mac1 instead of eth_mac2. Also set fec to point at eth_mac2 as it may be fused later even though it is disabled by default. With this changed barebox is now capable of loading the correct address. Link: https://github.com/karo-electronics/karo-tx-uboot/blob/380543278410bbf04264d80a3bfbe340b8e62439/drivers/net/dwc_eth_qos.c#L1167 [1] Link: https://github.com/karo-electronics/karo-tx-uboot/blob/380543278410bbf04264d80a3bfbe340b8e62439/arch/arm/dts/imx8mp-karo.dtsi#L12 [2] Fixes: bac63d7c5f46 ("arm64: dts: freescale: add Ka-Ro Electronics tx8p-ml81 COM") Signed-off-by: Maud Spierings Signed-off-by: Shawn Guo Signed-off-by: Sasha Levin --- arch/arm64/boot/dts/freescale/imx8mp-tx8p-ml81.dtsi | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/arm64/boot/dts/freescale/imx8mp-tx8p-ml81.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-tx8p-ml81.dtsi index fe8ba16eb40e7..761ee046eb72e 100644 --- a/arch/arm64/boot/dts/freescale/imx8mp-tx8p-ml81.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mp-tx8p-ml81.dtsi @@ -47,6 +47,7 @@ <&clk IMX8MP_SYS_PLL2_100M>, <&clk IMX8MP_SYS_PLL2_50M>; assigned-clock-rates = <266000000>, <100000000>, <50000000>; + nvmem-cells = <ð_mac1>; phy-handle = <ðphy0>; phy-mode = "rmii"; pinctrl-0 = <&pinctrl_eqos>; @@ -75,6 +76,10 @@ }; }; +&fec { + nvmem-cells = <ð_mac2>; +}; + &gpio1 { gpio-line-names = "SODIMM_152", "SODIMM_42", From 4977cac699a47fcabb9f25f8ff391ed7d01714c2 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Tue, 2 Dec 2025 14:41:51 +0100 Subject: [PATCH 1851/2333] arm64: dts: imx8mp: Fix LAN8740Ai PHY reference clock on DH electronics i.MX8M Plus DHCOM [ Upstream commit c63749a7ddc59ac6ec0b05abfa0a21af9f2c1d38 ] Add missing 'clocks' property to LAN8740Ai PHY node, to allow the PHY driver to manage LAN8740Ai CLKIN reference clock supply. This fixes sporadic link bouncing caused by interruptions on the PHY reference clock, by letting the PHY driver manage the reference clock and assure there are no interruptions. This follows the matching PHY driver recommendation described in commit bedd8d78aba3 ("net: phy: smsc: LAN8710/20: add phy refclk in support") Fixes: 8d6712695bc8 ("arm64: dts: imx8mp: Add support for DH electronics i.MX8M Plus DHCOM and PDK2") Signed-off-by: Marek Vasut Tested-by: Christoph Niedermaier Signed-off-by: Shawn Guo Signed-off-by: Sasha Levin --- arch/arm64/boot/dts/freescale/imx8mp-dhcom-som.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/boot/dts/freescale/imx8mp-dhcom-som.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-dhcom-som.dtsi index 68c2e0156a5c8..f8303b7e2bd22 100644 --- a/arch/arm64/boot/dts/freescale/imx8mp-dhcom-som.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mp-dhcom-som.dtsi @@ -113,6 +113,7 @@ ethphy0f: ethernet-phy@1 { /* SMSC LAN8740Ai */ compatible = "ethernet-phy-id0007.c110", "ethernet-phy-ieee802.3-c22"; + clocks = <&clk IMX8MP_CLK_ENET_QOS>; interrupt-parent = <&gpio3>; interrupts = <19 IRQ_TYPE_LEVEL_LOW>; pinctrl-0 = <&pinctrl_ethphy0>; From 646d415f9860edb755361de18b7461dad6c08d28 Mon Sep 17 00:00:00 2001 From: Sherry Sun Date: Wed, 3 Dec 2025 09:59:56 +0800 Subject: [PATCH 1852/2333] arm64: dts: imx8qm-ss-dma: correct the dma channels of lpuart [ Upstream commit a988caeed9d918452aa0a68de2c6e94d86aa43ba ] The commit 616effc0272b5 ("arm64: dts: imx8: Fix lpuart DMA channel order") swap uart rx and tx channel at common imx8-ss-dma.dtsi. But miss update imx8qm-ss-dma.dtsi. The commit 5a8e9b022e569 ("arm64: dts: imx8qm-ss-dma: Pass lpuart dma-names") just simple add dma-names as binding doc requirement. Correct lpuart0 - lpuart3 dma rx and tx channels, and use defines for the FSL_EDMA_RX flag. Fixes: 5a8e9b022e56 ("arm64: dts: imx8qm-ss-dma: Pass lpuart dma-names") Signed-off-by: Sherry Sun Reviewed-by: Frank Li Reviewed-by: Alexander Stein Signed-off-by: Shawn Guo Signed-off-by: Sasha Levin --- arch/arm64/boot/dts/freescale/imx8qm-ss-dma.dtsi | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/arm64/boot/dts/freescale/imx8qm-ss-dma.dtsi b/arch/arm64/boot/dts/freescale/imx8qm-ss-dma.dtsi index d4856b8590e0c..e186c31bfd482 100644 --- a/arch/arm64/boot/dts/freescale/imx8qm-ss-dma.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8qm-ss-dma.dtsi @@ -171,25 +171,25 @@ &lpuart0 { compatible = "fsl,imx8qm-lpuart", "fsl,imx8qxp-lpuart"; - dmas = <&edma2 13 0 0>, <&edma2 12 0 1>; + dmas = <&edma2 12 0 FSL_EDMA_RX>, <&edma2 13 0 0>; dma-names = "rx","tx"; }; &lpuart1 { compatible = "fsl,imx8qm-lpuart", "fsl,imx8qxp-lpuart"; - dmas = <&edma2 15 0 0>, <&edma2 14 0 1>; + dmas = <&edma2 14 0 FSL_EDMA_RX>, <&edma2 15 0 0>; dma-names = "rx","tx"; }; &lpuart2 { compatible = "fsl,imx8qm-lpuart", "fsl,imx8qxp-lpuart"; - dmas = <&edma2 17 0 0>, <&edma2 16 0 1>; + dmas = <&edma2 16 0 FSL_EDMA_RX>, <&edma2 17 0 0>; dma-names = "rx","tx"; }; &lpuart3 { compatible = "fsl,imx8qm-lpuart", "fsl,imx8qxp-lpuart"; - dmas = <&edma2 19 0 0>, <&edma2 18 0 1>; + dmas = <&edma2 18 0 FSL_EDMA_RX>, <&edma2 19 0 0>; dma-names = "rx","tx"; }; From 499c0db5862f10ef35402bf99821eac3e91eb743 Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Tue, 16 Dec 2025 14:15:28 +0100 Subject: [PATCH 1853/2333] arm64: dts: mba8mx: Fix Ethernet PHY IRQ support [ Upstream commit 89e87d0dc87eb3654c9ae01afc4a18c1c6d1e523 ] Ethernet PHY interrupt mode is level triggered. Adjust the mode accordingly. Signed-off-by: Alexander Stein Reviewed-by: Andrew Lunn Fixes: 70cf622bb16e ("arm64: dts: mba8mx: Add Ethernet PHY IRQ support") Signed-off-by: Shawn Guo Signed-off-by: Sasha Levin --- arch/arm64/boot/dts/freescale/mba8mx.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/freescale/mba8mx.dtsi b/arch/arm64/boot/dts/freescale/mba8mx.dtsi index 79daba930ad64..3e41da4d6122b 100644 --- a/arch/arm64/boot/dts/freescale/mba8mx.dtsi +++ b/arch/arm64/boot/dts/freescale/mba8mx.dtsi @@ -185,7 +185,7 @@ reset-assert-us = <500000>; reset-deassert-us = <500>; interrupt-parent = <&expander2>; - interrupts = <6 IRQ_TYPE_EDGE_FALLING>; + interrupts = <6 IRQ_TYPE_LEVEL_LOW>; }; }; }; From 704c0258f0d79c876accfa82aa93cc7c2acc91d0 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Thu, 4 Dec 2025 12:20:35 +0100 Subject: [PATCH 1854/2333] netfilter: nft_set_pipapo: fix range overlap detection [ Upstream commit 7711f4bb4b360d9c0ff84db1c0ec91e385625047 ] set->klen has to be used, not sizeof(). The latter only compares a single register but a full check of the entire key is needed. Example: table ip t { map s { typeof iifname . ip saddr : verdict flags interval } } nft add element t s '{ "lo" . 10.0.0.0/24 : drop }' # no error, expected nft add element t s '{ "lo" . 10.0.0.0/24 : drop }' # no error, expected nft add element t s '{ "lo" . 10.0.0.0/8 : drop }' # bug: no error The 3rd 'add element' should be rejected via -ENOTEMPTY, not -EEXIST, so userspace / nft can report an error to the user. The latter is only correct for the 2nd case (re-add of existing element). As-is, userspace is told that the command was successful, but no elements were added. After this patch, 3rd command gives: Error: Could not process rule: File exists add element t s { "lo" . 127.0.0.0/8 . "lo" : drop } ^^^^^^^^^^^^^^^^^^^^^^^^^ Fixes: 0eb4b5ee33f2 ("netfilter: nft_set_pipapo: Separate partial and complete overlap cases on insertion") Signed-off-by: Florian Westphal Signed-off-by: Sasha Levin --- net/netfilter/nft_set_pipapo.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/netfilter/nft_set_pipapo.c b/net/netfilter/nft_set_pipapo.c index 112fe46788b6f..6d77a5f0088ad 100644 --- a/net/netfilter/nft_set_pipapo.c +++ b/net/netfilter/nft_set_pipapo.c @@ -1317,8 +1317,8 @@ static int nft_pipapo_insert(const struct net *net, const struct nft_set *set, else dup_end = dup_key; - if (!memcmp(start, dup_key->data, sizeof(*dup_key->data)) && - !memcmp(end, dup_end->data, sizeof(*dup_end->data))) { + if (!memcmp(start, dup_key->data, set->klen) && + !memcmp(end, dup_end->data, set->klen)) { *elem_priv = &dup->priv; return -EEXIST; } From 75bfb05067d682e4518898f56d370a341df2b566 Mon Sep 17 00:00:00 2001 From: Fernando Fernandez Mancera Date: Wed, 17 Dec 2025 21:21:59 +0100 Subject: [PATCH 1855/2333] netfilter: nft_synproxy: avoid possible data-race on update operation [ Upstream commit 36a3200575642846a96436d503d46544533bb943 ] During nft_synproxy eval we are reading nf_synproxy_info struct which can be modified on update operation concurrently. As nf_synproxy_info struct fits in 32 bits, use READ_ONCE/WRITE_ONCE annotations. Fixes: ee394f96ad75 ("netfilter: nft_synproxy: add synproxy stateful object support") Signed-off-by: Fernando Fernandez Mancera Signed-off-by: Florian Westphal Signed-off-by: Sasha Levin --- net/netfilter/nft_synproxy.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/net/netfilter/nft_synproxy.c b/net/netfilter/nft_synproxy.c index 5d3e518259859..4d3e5a31b4125 100644 --- a/net/netfilter/nft_synproxy.c +++ b/net/netfilter/nft_synproxy.c @@ -48,7 +48,7 @@ static void nft_synproxy_eval_v4(const struct nft_synproxy *priv, struct tcphdr *_tcph, struct synproxy_options *opts) { - struct nf_synproxy_info info = priv->info; + struct nf_synproxy_info info = READ_ONCE(priv->info); struct net *net = nft_net(pkt); struct synproxy_net *snet = synproxy_pernet(net); struct sk_buff *skb = pkt->skb; @@ -79,7 +79,7 @@ static void nft_synproxy_eval_v6(const struct nft_synproxy *priv, struct tcphdr *_tcph, struct synproxy_options *opts) { - struct nf_synproxy_info info = priv->info; + struct nf_synproxy_info info = READ_ONCE(priv->info); struct net *net = nft_net(pkt); struct synproxy_net *snet = synproxy_pernet(net); struct sk_buff *skb = pkt->skb; @@ -340,7 +340,7 @@ static void nft_synproxy_obj_update(struct nft_object *obj, struct nft_synproxy *newpriv = nft_obj_data(newobj); struct nft_synproxy *priv = nft_obj_data(obj); - priv->info = newpriv->info; + WRITE_ONCE(priv->info, newpriv->info); } static struct nft_object_type nft_synproxy_obj_type; From 97531f8e50d99a289e0024e020cfdda5eec36f4d Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 22 Sep 2025 11:54:02 +0200 Subject: [PATCH 1856/2333] gpiolib: remove unnecessary 'out of memory' messages [ Upstream commit 0ba6f1ed3808b1f095fbdb490006f0ecd00f52bd ] We don't need to add additional logs when returning -ENOMEM so remove unnecessary error messages. Reviewed-by: Linus Walleij Signed-off-by: Bartosz Golaszewski Stable-dep-of: a7ac22d53d09 ("gpiolib: fix race condition for gdev->srcu") Signed-off-by: Sasha Levin --- drivers/gpio/gpiolib.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index cd8800ba5825f..f2ed234b4135e 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -2316,10 +2316,8 @@ int gpiochip_add_pingroup_range(struct gpio_chip *gc, int ret; pin_range = kzalloc(sizeof(*pin_range), GFP_KERNEL); - if (!pin_range) { - chip_err(gc, "failed to allocate pin ranges\n"); + if (!pin_range) return -ENOMEM; - } /* Use local offset as range ID */ pin_range->range.id = gpio_offset; @@ -2379,10 +2377,8 @@ int gpiochip_add_pin_range_with_pins(struct gpio_chip *gc, int ret; pin_range = kzalloc(sizeof(*pin_range), GFP_KERNEL); - if (!pin_range) { - chip_err(gc, "failed to allocate pin ranges\n"); + if (!pin_range) return -ENOMEM; - } /* Use local offset as range ID */ pin_range->range.id = gpio_offset; From aaa24eeb63ad0b8de7ebeec603776610c5f805a6 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 22 Sep 2025 11:54:03 +0200 Subject: [PATCH 1857/2333] gpiolib: rename GPIO chip printk macros [ Upstream commit d4f335b410ddbe3e99f48f8b5ea78a25041274f1 ] The chip_$level() macros take struct gpio_chip as argument so make it follow the convention of using the 'gpiochip_' prefix. Reviewed-by: Linus Walleij Signed-off-by: Bartosz Golaszewski Stable-dep-of: a7ac22d53d09 ("gpiolib: fix race condition for gdev->srcu") Signed-off-by: Sasha Levin --- drivers/gpio/gpiolib-cdev.c | 2 +- drivers/gpio/gpiolib-sysfs.c | 2 +- drivers/gpio/gpiolib.c | 80 ++++++++++++++++++------------------ drivers/gpio/gpiolib.h | 8 ++-- 4 files changed, 45 insertions(+), 47 deletions(-) diff --git a/drivers/gpio/gpiolib-cdev.c b/drivers/gpio/gpiolib-cdev.c index d8d93059ac04c..d925e75d1dce1 100644 --- a/drivers/gpio/gpiolib-cdev.c +++ b/drivers/gpio/gpiolib-cdev.c @@ -2828,7 +2828,7 @@ int gpiolib_cdev_register(struct gpio_device *gdev, dev_t devt) if (!gc) return -ENODEV; - chip_dbg(gc, "added GPIO chardev (%d:%d)\n", MAJOR(devt), gdev->id); + gpiochip_dbg(gc, "added GPIO chardev (%d:%d)\n", MAJOR(devt), gdev->id); return 0; } diff --git a/drivers/gpio/gpiolib-sysfs.c b/drivers/gpio/gpiolib-sysfs.c index 9a849245b3588..7d5fc1ea2aa54 100644 --- a/drivers/gpio/gpiolib-sysfs.c +++ b/drivers/gpio/gpiolib-sysfs.c @@ -1091,7 +1091,7 @@ static int gpiofind_sysfs_register(struct gpio_chip *gc, const void *data) ret = gpiochip_sysfs_register(gdev); if (ret) - chip_err(gc, "failed to register the sysfs entry: %d\n", ret); + gpiochip_err(gc, "failed to register the sysfs entry: %d\n", ret); return 0; } diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index f2ed234b4135e..9a4395a29f68e 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -921,8 +921,8 @@ static void gpiochip_machine_hog(struct gpio_chip *gc, struct gpiod_hog *hog) desc = gpiochip_get_desc(gc, hog->chip_hwnum); if (IS_ERR(desc)) { - chip_err(gc, "%s: unable to get GPIO desc: %ld\n", __func__, - PTR_ERR(desc)); + gpiochip_err(gc, "%s: unable to get GPIO desc: %ld\n", + __func__, PTR_ERR(desc)); return; } @@ -1124,7 +1124,7 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data, ret = gpiodev_add_to_list_unlocked(gdev); if (ret) { - chip_err(gc, "GPIO integer space overlap, cannot add chip\n"); + gpiochip_err(gc, "GPIO integer space overlap, cannot add chip\n"); goto err_free_label; } } @@ -1528,8 +1528,7 @@ static void gpiochip_set_hierarchical_irqchip(struct gpio_chip *gc, &parent_hwirq, &parent_type); if (ret) { - chip_err(gc, "skip set-up on hwirq %d\n", - i); + gpiochip_err(gc, "skip set-up on hwirq %d\n", i); continue; } @@ -1542,15 +1541,14 @@ static void gpiochip_set_hierarchical_irqchip(struct gpio_chip *gc, ret = irq_domain_alloc_irqs(gc->irq.domain, 1, NUMA_NO_NODE, &fwspec); if (ret < 0) { - chip_err(gc, - "can not allocate irq for GPIO line %d parent hwirq %d in hierarchy domain: %d\n", - i, parent_hwirq, - ret); + gpiochip_err(gc, + "can not allocate irq for GPIO line %d parent hwirq %d in hierarchy domain: %d\n", + i, parent_hwirq, ret); } } } - chip_err(gc, "%s unknown fwnode type proceed anyway\n", __func__); + gpiochip_err(gc, "%s unknown fwnode type proceed anyway\n", __func__); return; } @@ -1602,15 +1600,15 @@ static int gpiochip_hierarchy_irq_domain_alloc(struct irq_domain *d, if (ret) return ret; - chip_dbg(gc, "allocate IRQ %d, hwirq %lu\n", irq, hwirq); + gpiochip_dbg(gc, "allocate IRQ %d, hwirq %lu\n", irq, hwirq); ret = girq->child_to_parent_hwirq(gc, hwirq, type, &parent_hwirq, &parent_type); if (ret) { - chip_err(gc, "can't look up hwirq %lu\n", hwirq); + gpiochip_err(gc, "can't look up hwirq %lu\n", hwirq); return ret; } - chip_dbg(gc, "found parent hwirq %u\n", parent_hwirq); + gpiochip_dbg(gc, "found parent hwirq %u\n", parent_hwirq); /* * We set handle_bad_irq because the .set_type() should @@ -1631,8 +1629,8 @@ static int gpiochip_hierarchy_irq_domain_alloc(struct irq_domain *d, if (ret) return ret; - chip_dbg(gc, "alloc_irqs_parent for %d parent hwirq %d\n", - irq, parent_hwirq); + gpiochip_dbg(gc, "alloc_irqs_parent for %d parent hwirq %d\n", + irq, parent_hwirq); irq_set_lockdep_class(irq, gc->irq.lock_key, gc->irq.request_key); ret = irq_domain_alloc_irqs_parent(d, irq, 1, &gpio_parent_fwspec); /* @@ -1642,9 +1640,9 @@ static int gpiochip_hierarchy_irq_domain_alloc(struct irq_domain *d, if (irq_domain_is_msi(d->parent) && (ret == -EEXIST)) ret = 0; if (ret) - chip_err(gc, - "failed to allocate parent hwirq %d for hwirq %lu\n", - parent_hwirq, hwirq); + gpiochip_err(gc, + "failed to allocate parent hwirq %d for hwirq %lu\n", + parent_hwirq, hwirq); return ret; } @@ -1720,7 +1718,7 @@ static struct irq_domain *gpiochip_hierarchy_create_domain(struct gpio_chip *gc) if (!gc->irq.child_to_parent_hwirq || !gc->irq.fwnode) { - chip_err(gc, "missing irqdomain vital data\n"); + gpiochip_err(gc, "missing irqdomain vital data\n"); return ERR_PTR(-EINVAL); } @@ -1993,7 +1991,7 @@ static void gpiochip_set_irq_hooks(struct gpio_chip *gc) if (irqchip->flags & IRQCHIP_IMMUTABLE) return; - chip_warn(gc, "not an immutable chip, please consider fixing it!\n"); + gpiochip_warn(gc, "not an immutable chip, please consider fixing it!\n"); if (!irqchip->irq_request_resources && !irqchip->irq_release_resources) { @@ -2009,8 +2007,8 @@ static void gpiochip_set_irq_hooks(struct gpio_chip *gc) * ...and if so, give a gentle warning that this is bad * practice. */ - chip_info(gc, - "detected irqchip that is shared with multiple gpiochips: please fix the driver.\n"); + gpiochip_info(gc, + "detected irqchip that is shared with multiple gpiochips: please fix the driver.\n"); return; } @@ -2039,7 +2037,8 @@ static int gpiochip_irqchip_add_allocated_domain(struct gpio_chip *gc, return -EINVAL; if (gc->to_irq) - chip_warn(gc, "to_irq is redefined in %s and you shouldn't rely on it\n", __func__); + gpiochip_warn(gc, "to_irq is redefined in %s and you shouldn't rely on it\n", + __func__); gc->to_irq = gpiochip_to_irq; gc->irq.domain = domain; @@ -2080,7 +2079,7 @@ static int gpiochip_add_irqchip(struct gpio_chip *gc, return 0; if (gc->irq.parent_handler && gc->can_sleep) { - chip_err(gc, "you cannot have chained interrupts on a chip that may sleep\n"); + gpiochip_err(gc, "you cannot have chained interrupts on a chip that may sleep\n"); return -EINVAL; } @@ -2336,7 +2335,7 @@ int gpiochip_add_pingroup_range(struct gpio_chip *gc, pinctrl_add_gpio_range(pctldev, &pin_range->range); - chip_dbg(gc, "created GPIO range %d->%d ==> %s PINGRP %s\n", + gpiochip_dbg(gc, "created GPIO range %d->%d ==> %s PINGRP %s\n", gpio_offset, gpio_offset + pin_range->range.npins - 1, pinctrl_dev_get_devname(pctldev), pin_group); @@ -2392,19 +2391,18 @@ int gpiochip_add_pin_range_with_pins(struct gpio_chip *gc, &pin_range->range); if (IS_ERR(pin_range->pctldev)) { ret = PTR_ERR(pin_range->pctldev); - chip_err(gc, "could not create pin range\n"); + gpiochip_err(gc, "could not create pin range\n"); kfree(pin_range); return ret; } if (pin_range->range.pins) - chip_dbg(gc, "created GPIO range %d->%d ==> %s %d sparse PIN range { %d, ... }", - gpio_offset, gpio_offset + npins - 1, - pinctl_name, npins, pins[0]); + gpiochip_dbg(gc, "created GPIO range %d->%d ==> %s %d sparse PIN range { %d, ... }", + gpio_offset, gpio_offset + npins - 1, + pinctl_name, npins, pins[0]); else - chip_dbg(gc, "created GPIO range %d->%d ==> %s PIN %d->%d\n", - gpio_offset, gpio_offset + npins - 1, - pinctl_name, - pin_offset, pin_offset + npins - 1); + gpiochip_dbg(gc, "created GPIO range %d->%d ==> %s PIN %d->%d\n", + gpio_offset, gpio_offset + npins - 1, pinctl_name, + pin_offset, pin_offset + npins - 1); list_add_tail(&pin_range->node, &gdev->pin_ranges); @@ -2614,7 +2612,7 @@ struct gpio_desc *gpiochip_request_own_desc(struct gpio_chip *gc, int ret; if (IS_ERR(desc)) { - chip_err(gc, "failed to get GPIO %s descriptor\n", name); + gpiochip_err(gc, "failed to get GPIO %s descriptor\n", name); return desc; } @@ -2625,7 +2623,7 @@ struct gpio_desc *gpiochip_request_own_desc(struct gpio_chip *gc, ret = gpiod_configure_flags(desc, label, lflags, dflags); if (ret) { gpiod_free_commit(desc); - chip_err(gc, "setup of own GPIO %s failed\n", name); + gpiochip_err(gc, "setup of own GPIO %s failed\n", name); return ERR_PTR(ret); } @@ -4052,8 +4050,8 @@ int gpiochip_lock_as_irq(struct gpio_chip *gc, unsigned int offset) int dir = gpiod_get_direction(desc); if (dir < 0) { - chip_err(gc, "%s: cannot get GPIO direction\n", - __func__); + gpiochip_err(gc, "%s: cannot get GPIO direction\n", + __func__); return dir; } } @@ -4061,9 +4059,9 @@ int gpiochip_lock_as_irq(struct gpio_chip *gc, unsigned int offset) /* To be valid for IRQ the line needs to be input or open drain */ if (test_bit(GPIOD_FLAG_IS_OUT, &desc->flags) && !test_bit(GPIOD_FLAG_OPEN_DRAIN, &desc->flags)) { - chip_err(gc, - "%s: tried to flag a GPIO set as output for IRQ\n", - __func__); + gpiochip_err(gc, + "%s: tried to flag a GPIO set as output for IRQ\n", + __func__); return -EIO; } @@ -4140,7 +4138,7 @@ int gpiochip_reqres_irq(struct gpio_chip *gc, unsigned int offset) ret = gpiochip_lock_as_irq(gc, offset); if (ret) { - chip_err(gc, "unable to lock HW IRQ %u for IRQ\n", offset); + gpiochip_err(gc, "unable to lock HW IRQ %u for IRQ\n", offset); module_put(gc->gpiodev->owner); return ret; } diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h index 2a003a7311e7a..6ee29d0222393 100644 --- a/drivers/gpio/gpiolib.h +++ b/drivers/gpio/gpiolib.h @@ -309,13 +309,13 @@ do { \ /* With chip prefix */ -#define chip_err(gc, fmt, ...) \ +#define gpiochip_err(gc, fmt, ...) \ dev_err(&gc->gpiodev->dev, "(%s): " fmt, gc->label, ##__VA_ARGS__) -#define chip_warn(gc, fmt, ...) \ +#define gpiochip_warn(gc, fmt, ...) \ dev_warn(&gc->gpiodev->dev, "(%s): " fmt, gc->label, ##__VA_ARGS__) -#define chip_info(gc, fmt, ...) \ +#define gpiochip_info(gc, fmt, ...) \ dev_info(&gc->gpiodev->dev, "(%s): " fmt, gc->label, ##__VA_ARGS__) -#define chip_dbg(gc, fmt, ...) \ +#define gpiochip_dbg(gc, fmt, ...) \ dev_dbg(&gc->gpiodev->dev, "(%s): " fmt, gc->label, ##__VA_ARGS__) #endif /* GPIOLIB_H */ From fb674c8f1a5d8dd3113a7326030f963fa2d79c02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Narewski?= Date: Wed, 24 Dec 2025 09:26:40 +0100 Subject: [PATCH 1858/2333] gpiolib: fix race condition for gdev->srcu MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit a7ac22d53d0990152b108c3f4fe30df45fcb0181 ] If two drivers were calling gpiochip_add_data_with_key(), one may be traversing the srcu-protected list in gpio_name_to_desc(), meanwhile other has just added its gdev in gpiodev_add_to_list_unlocked(). This creates a non-mutexed and non-protected timeframe, when one instance is dereferencing and using &gdev->srcu, before the other has initialized it, resulting in crash: [ 4.935481] Unable to handle kernel paging request at virtual address ffff800272bcc000 [ 4.943396] Mem abort info: [ 4.943400] ESR = 0x0000000096000005 [ 4.943403] EC = 0x25: DABT (current EL), IL = 32 bits [ 4.943407] SET = 0, FnV = 0 [ 4.943410] EA = 0, S1PTW = 0 [ 4.943413] FSC = 0x05: level 1 translation fault [ 4.943416] Data abort info: [ 4.943418] ISV = 0, ISS = 0x00000005, ISS2 = 0x00000000 [ 4.946220] CM = 0, WnR = 0, TnD = 0, TagAccess = 0 [ 4.955261] GCS = 0, Overlay = 0, DirtyBit = 0, Xs = 0 [ 4.955268] swapper pgtable: 4k pages, 48-bit VAs, pgdp=0000000038e6c000 [ 4.961449] [ffff800272bcc000] pgd=0000000000000000 [ 4.969203] , p4d=1000000039739003 [ 4.979730] , pud=0000000000000000 [ 4.980210] phandle (CPU): 0x0000005e, phandle (BE): 0x5e000000 for node "reset" [ 4.991736] Internal error: Oops: 0000000096000005 [#1] PREEMPT SMP ... [ 5.121359] pc : __srcu_read_lock+0x44/0x98 [ 5.131091] lr : gpio_name_to_desc+0x60/0x1a0 [ 5.153671] sp : ffff8000833bb430 [ 5.298440] [ 5.298443] Call trace: [ 5.298445] __srcu_read_lock+0x44/0x98 [ 5.309484] gpio_name_to_desc+0x60/0x1a0 [ 5.320692] gpiochip_add_data_with_key+0x488/0xf00 5.946419] ---[ end trace 0000000000000000 ]--- Move initialization code for gdev fields before it is added to gpio_devices, with adjacent initialization code. Adjust goto statements to reflect modified order of operations Fixes: 47d8b4c1d868 ("gpio: add SRCU infrastructure to struct gpio_device") Reviewed-by: Jakub Lewalski Signed-off-by: Paweł Narewski [Bartosz: fixed a build issue, removed stray newline] Link: https://lore.kernel.org/r/20251224082641.10769-1-bartosz.golaszewski@oss.qualcomm.com Signed-off-by: Bartosz Golaszewski Signed-off-by: Sasha Levin --- drivers/gpio/gpiolib.c | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 9a4395a29f68e..9aa6ddf6389cc 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1091,6 +1091,18 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data, gdev->ngpio = gc->ngpio; gdev->can_sleep = gc->can_sleep; + rwlock_init(&gdev->line_state_lock); + RAW_INIT_NOTIFIER_HEAD(&gdev->line_state_notifier); + BLOCKING_INIT_NOTIFIER_HEAD(&gdev->device_notifier); + + ret = init_srcu_struct(&gdev->srcu); + if (ret) + goto err_free_label; + + ret = init_srcu_struct(&gdev->desc_srcu); + if (ret) + goto err_cleanup_gdev_srcu; + scoped_guard(mutex, &gpio_devices_lock) { /* * TODO: this allocates a Linux GPIO number base in the global @@ -1105,7 +1117,7 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data, if (base < 0) { ret = base; base = 0; - goto err_free_label; + goto err_cleanup_desc_srcu; } /* @@ -1125,22 +1137,10 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data, ret = gpiodev_add_to_list_unlocked(gdev); if (ret) { gpiochip_err(gc, "GPIO integer space overlap, cannot add chip\n"); - goto err_free_label; + goto err_cleanup_desc_srcu; } } - rwlock_init(&gdev->line_state_lock); - RAW_INIT_NOTIFIER_HEAD(&gdev->line_state_notifier); - BLOCKING_INIT_NOTIFIER_HEAD(&gdev->device_notifier); - - ret = init_srcu_struct(&gdev->srcu); - if (ret) - goto err_remove_from_list; - - ret = init_srcu_struct(&gdev->desc_srcu); - if (ret) - goto err_cleanup_gdev_srcu; - #ifdef CONFIG_PINCTRL INIT_LIST_HEAD(&gdev->pin_ranges); #endif @@ -1150,11 +1150,11 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data, ret = gpiochip_set_names(gc); if (ret) - goto err_cleanup_desc_srcu; + goto err_remove_from_list; ret = gpiochip_init_valid_mask(gc); if (ret) - goto err_cleanup_desc_srcu; + goto err_remove_from_list; for (desc_index = 0; desc_index < gc->ngpio; desc_index++) { struct gpio_desc *desc = &gdev->descs[desc_index]; @@ -1227,10 +1227,6 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data, of_gpiochip_remove(gc); err_free_valid_mask: gpiochip_free_valid_mask(gc); -err_cleanup_desc_srcu: - cleanup_srcu_struct(&gdev->desc_srcu); -err_cleanup_gdev_srcu: - cleanup_srcu_struct(&gdev->srcu); err_remove_from_list: scoped_guard(mutex, &gpio_devices_lock) list_del_rcu(&gdev->list); @@ -1240,6 +1236,10 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data, gpio_device_put(gdev); goto err_print_message; } +err_cleanup_desc_srcu: + cleanup_srcu_struct(&gdev->desc_srcu); +err_cleanup_gdev_srcu: + cleanup_srcu_struct(&gdev->srcu); err_free_label: kfree_const(gdev->label); err_free_descs: From 58dac9b28a57163310fc684fbd038a5a2e1c1a6d Mon Sep 17 00:00:00 2001 From: Ernest Van Hoecke Date: Wed, 17 Dec 2025 16:30:25 +0100 Subject: [PATCH 1859/2333] gpio: pca953x: handle short interrupt pulses on PCAL devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 014a17deb41201449f76df2b20c857a9c3294a7c ] GPIO drivers with latch input support may miss short pulses on input pins even when input latching is enabled. The generic interrupt logic in the pca953x driver reports interrupts by comparing the current input value against the previously sampled one and only signals an event when a level change is observed between two reads. For short pulses, the first edge is captured when the input register is read, but if the signal returns to its previous level before the read, the second edge is not observed. As a result, successive pulses can produce identical input values at read time and no level change is detected, causing interrupts to be missed. Below timing diagram shows this situation where the top signal is the input pin level and the bottom signal indicates the latched value. ─────┐ ┌──*───────────────┐ ┌──*─────────────────┐ ┌──*─── │ │ . │ │ . │ │ . │ │ │ │ │ │ │ │ │ └──*──┘ │ └──*──┘ │ └──*──┘ │ Input │ │ │ │ │ │ ▼ │ ▼ │ ▼ │ IRQ │ IRQ │ IRQ │ . . . ─────┐ .┌──────────────┐ .┌────────────────┐ .┌── │ │ │ │ │ │ │ │ │ │ │ │ └────────*┘ └────────*┘ └────────*┘ Latched │ │ │ ▼ ▼ ▼ READ 0 READ 0 READ 0 NO CHANGE NO CHANGE PCAL variants provide an interrupt status register that records which pins triggered an interrupt, but the status and input registers cannot be read atomically. The interrupt status is only cleared when the input port is read, and the input value must also be read to determine the triggering edge. If another interrupt occurs on a different line after the status register has been read but before the input register is sampled, that event will not be reflected in the earlier status snapshot, so relying solely on the interrupt status register is also insufficient. Support for input latching and interrupt status handling was previously added by [1], but the interrupt status-based logic was reverted by [2] due to these issues. This patch addresses the original problem by combining both sources of information. Events indicated by the interrupt status register are merged with events detected through the existing level-change logic. As a result: * short pulses, whose second edges are invisible, are detected via the interrupt status register, and * interrupts that occur between the status and input reads are still caught by the generic level-change logic. This significantly improves robustness on devices that signal interrupts as short pulses, while avoiding the issues that led to the earlier reversion. In practice, even if only the first edge of a pulse is observable, the interrupt is reliably detected. This fixes missed interrupts from an Ilitek touch controller with its interrupt line connected to a PCAL6416A, where active-low pulses are approximately 200 us long. [1] commit 44896beae605 ("gpio: pca953x: add PCAL9535 interrupt support for Galileo Gen2") [2] commit d6179f6c6204 ("gpio: pca953x: Improve interrupt support") Fixes: d6179f6c6204 ("gpio: pca953x: Improve interrupt support") Signed-off-by: Ernest Van Hoecke Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20251217153050.142057-1-ernestvanhoecke@gmail.com Signed-off-by: Bartosz Golaszewski Signed-off-by: Sasha Levin --- drivers/gpio/gpio-pca953x.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index b46927f550389..b2de916107f42 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -940,14 +940,35 @@ static bool pca953x_irq_pending(struct pca953x_chip *chip, unsigned long *pendin DECLARE_BITMAP(old_stat, MAX_LINE); DECLARE_BITMAP(cur_stat, MAX_LINE); DECLARE_BITMAP(new_stat, MAX_LINE); + DECLARE_BITMAP(int_stat, MAX_LINE); DECLARE_BITMAP(trigger, MAX_LINE); DECLARE_BITMAP(edges, MAX_LINE); int ret; + if (chip->driver_data & PCA_PCAL) { + /* Read INT_STAT before it is cleared by the input-port read. */ + ret = pca953x_read_regs(chip, PCAL953X_INT_STAT, int_stat); + if (ret) + return false; + } + ret = pca953x_read_regs(chip, chip->regs->input, cur_stat); if (ret) return false; + if (chip->driver_data & PCA_PCAL) { + /* Detect short pulses via INT_STAT. */ + bitmap_and(trigger, int_stat, chip->irq_mask, gc->ngpio); + + /* Apply filter for rising/falling edge selection. */ + bitmap_replace(new_stat, chip->irq_trig_fall, chip->irq_trig_raise, + cur_stat, gc->ngpio); + + bitmap_and(int_stat, new_stat, trigger, gc->ngpio); + } else { + bitmap_zero(int_stat, gc->ngpio); + } + /* Remove output pins from the equation */ pca953x_read_regs(chip, chip->regs->direction, reg_direction); @@ -961,7 +982,8 @@ static bool pca953x_irq_pending(struct pca953x_chip *chip, unsigned long *pendin if (bitmap_empty(chip->irq_trig_level_high, gc->ngpio) && bitmap_empty(chip->irq_trig_level_low, gc->ngpio)) { - if (bitmap_empty(trigger, gc->ngpio)) + if (bitmap_empty(trigger, gc->ngpio) && + bitmap_empty(int_stat, gc->ngpio)) return false; } @@ -969,6 +991,7 @@ static bool pca953x_irq_pending(struct pca953x_chip *chip, unsigned long *pendin bitmap_and(old_stat, chip->irq_trig_raise, new_stat, gc->ngpio); bitmap_or(edges, old_stat, cur_stat, gc->ngpio); bitmap_and(pending, edges, trigger, gc->ngpio); + bitmap_or(pending, pending, int_stat, gc->ngpio); bitmap_and(cur_stat, new_stat, chip->irq_trig_level_high, gc->ngpio); bitmap_and(cur_stat, cur_stat, chip->irq_mask, gc->ngpio); From 7f066cba650c584f55c6732d2d99a967928515f7 Mon Sep 17 00:00:00 2001 From: Zilin Guan Date: Wed, 24 Dec 2025 12:48:26 +0000 Subject: [PATCH 1860/2333] netfilter: nf_tables: fix memory leak in nf_tables_newrule() [ Upstream commit d077e8119ddbb4fca67540f1a52453631a47f221 ] In nf_tables_newrule(), if nft_use_inc() fails, the function jumps to the err_release_rule label without freeing the allocated flow, leading to a memory leak. Fix this by adding a new label err_destroy_flow and jumping to it when nft_use_inc() fails. This ensures that the flow is properly released in this error case. Fixes: 1689f25924ada ("netfilter: nf_tables: report use refcount overflow") Signed-off-by: Zilin Guan Signed-off-by: Florian Westphal Signed-off-by: Sasha Levin --- net/netfilter/nf_tables_api.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index 1a204f6371ad1..a3669acd68a32 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c @@ -4378,7 +4378,7 @@ static int nf_tables_newrule(struct sk_buff *skb, const struct nfnl_info *info, if (!nft_use_inc(&chain->use)) { err = -EMFILE; - goto err_release_rule; + goto err_destroy_flow; } if (info->nlh->nlmsg_flags & NLM_F_REPLACE) { @@ -4428,6 +4428,7 @@ static int nf_tables_newrule(struct sk_buff *skb, const struct nfnl_info *info, err_destroy_flow_rule: nft_use_dec_restore(&chain->use); +err_destroy_flow: if (flow) nft_flow_rule_destroy(flow); err_release_rule: From 8bdafdf4900040a81422056cabe5e00a37bd101a Mon Sep 17 00:00:00 2001 From: Fernando Fernandez Mancera Date: Wed, 17 Dec 2025 15:46:40 +0100 Subject: [PATCH 1861/2333] netfilter: nf_conncount: update last_gc only when GC has been performed [ Upstream commit 7811ba452402d58628e68faedf38745b3d485e3c ] Currently last_gc is being updated everytime a new connection is tracked, that means that it is updated even if a GC wasn't performed. With a sufficiently high packet rate, it is possible to always bypass the GC, causing the list to grow infinitely. Update the last_gc value only when a GC has been actually performed. Fixes: d265929930e2 ("netfilter: nf_conncount: reduce unnecessary GC") Signed-off-by: Fernando Fernandez Mancera Signed-off-by: Florian Westphal Signed-off-by: Sasha Levin --- net/netfilter/nf_conncount.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/netfilter/nf_conncount.c b/net/netfilter/nf_conncount.c index 3c1b155f7a0ea..828d5c64c68a3 100644 --- a/net/netfilter/nf_conncount.c +++ b/net/netfilter/nf_conncount.c @@ -229,6 +229,7 @@ static int __nf_conncount_add(struct net *net, nf_ct_put(found_ct); } + list->last_gc = (u32)jiffies; add_new_node: if (WARN_ON_ONCE(list->count > INT_MAX)) { @@ -248,7 +249,6 @@ static int __nf_conncount_add(struct net *net, conn->jiffies32 = (u32)jiffies; list_add_tail(&conn->node, &list->head); list->count++; - list->last_gc = (u32)jiffies; out_put: if (refcounted) From 326a4b7e61d01db3507f71c8bb5e85362f607064 Mon Sep 17 00:00:00 2001 From: Alok Tiwari Date: Mon, 29 Dec 2025 21:21:18 -0800 Subject: [PATCH 1862/2333] net: marvell: prestera: fix NULL dereference on devlink_alloc() failure [ Upstream commit a428e0da1248c353557970848994f35fd3f005e2 ] devlink_alloc() may return NULL on allocation failure, but prestera_devlink_alloc() unconditionally calls devlink_priv() on the returned pointer. This leads to a NULL pointer dereference if devlink allocation fails. Add a check for a NULL devlink pointer and return NULL early to avoid the crash. Fixes: 34dd1710f5a3 ("net: marvell: prestera: Add basic devlink support") Signed-off-by: Alok Tiwari Acked-by: Elad Nachman Link: https://patch.msgid.link/20251230052124.897012-1-alok.a.tiwari@oracle.com Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- drivers/net/ethernet/marvell/prestera/prestera_devlink.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/ethernet/marvell/prestera/prestera_devlink.c b/drivers/net/ethernet/marvell/prestera/prestera_devlink.c index 2a4c9df4eb797..e63d95c1842f3 100644 --- a/drivers/net/ethernet/marvell/prestera/prestera_devlink.c +++ b/drivers/net/ethernet/marvell/prestera/prestera_devlink.c @@ -387,6 +387,8 @@ struct prestera_switch *prestera_devlink_alloc(struct prestera_device *dev) dl = devlink_alloc(&prestera_dl_ops, sizeof(struct prestera_switch), dev->dev); + if (!dl) + return NULL; return devlink_priv(dl); } From b53fca69f45500eb83f379c1804275b8b578b031 Mon Sep 17 00:00:00 2001 From: Alexandre Knecht Date: Sun, 28 Dec 2025 03:00:57 +0100 Subject: [PATCH 1863/2333] bridge: fix C-VLAN preservation in 802.1ad vlan_tunnel egress [ Upstream commit 3128df6be147768fe536986fbb85db1d37806a9f ] When using an 802.1ad bridge with vlan_tunnel, the C-VLAN tag is incorrectly stripped from frames during egress processing. br_handle_egress_vlan_tunnel() uses skb_vlan_pop() to remove the S-VLAN from hwaccel before VXLAN encapsulation. However, skb_vlan_pop() also moves any "next" VLAN from the payload into hwaccel: /* move next vlan tag to hw accel tag */ __skb_vlan_pop(skb, &vlan_tci); __vlan_hwaccel_put_tag(skb, vlan_proto, vlan_tci); For QinQ frames where the C-VLAN sits in the payload, this moves it to hwaccel where it gets lost during VXLAN encapsulation. Fix by calling __vlan_hwaccel_clear_tag() directly, which clears only the hwaccel S-VLAN and leaves the payload untouched. This path is only taken when vlan_tunnel is enabled and tunnel_info is configured, so 802.1Q bridges are unaffected. Tested with 802.1ad bridge + VXLAN vlan_tunnel, verified C-VLAN preserved in VXLAN payload via tcpdump. Fixes: 11538d039ac6 ("bridge: vlan dst_metadata hooks in ingress and egress paths") Signed-off-by: Alexandre Knecht Reviewed-by: Ido Schimmel Acked-by: Nikolay Aleksandrov Link: https://patch.msgid.link/20251228020057.2788865-1-knecht.alexandre@gmail.com Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- net/bridge/br_vlan_tunnel.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/net/bridge/br_vlan_tunnel.c b/net/bridge/br_vlan_tunnel.c index a966a6ec82634..257cae9f15698 100644 --- a/net/bridge/br_vlan_tunnel.c +++ b/net/bridge/br_vlan_tunnel.c @@ -189,7 +189,6 @@ int br_handle_egress_vlan_tunnel(struct sk_buff *skb, IP_TUNNEL_DECLARE_FLAGS(flags) = { }; struct metadata_dst *tunnel_dst; __be64 tunnel_id; - int err; if (!vlan) return 0; @@ -199,9 +198,13 @@ int br_handle_egress_vlan_tunnel(struct sk_buff *skb, return 0; skb_dst_drop(skb); - err = skb_vlan_pop(skb); - if (err) - return err; + /* For 802.1ad (QinQ), skb_vlan_pop() incorrectly moves the C-VLAN + * from payload to hwaccel after clearing S-VLAN. We only need to + * clear the hwaccel S-VLAN; the C-VLAN must stay in payload for + * correct VXLAN encapsulation. This is also correct for 802.1Q + * where no C-VLAN exists in payload. + */ + __vlan_hwaccel_clear_tag(skb); if (BR_INPUT_SKB_CB(skb)->backup_nhid) { __set_bit(IP_TUNNEL_KEY_BIT, flags); From f490af47bbee02441e356a1e0b86e3b3dd5120ff Mon Sep 17 00:00:00 2001 From: Jerry Wu Date: Thu, 25 Dec 2025 20:36:17 +0000 Subject: [PATCH 1864/2333] net: mscc: ocelot: Fix crash when adding interface under a lag [ Upstream commit 34f3ff52cb9fa7dbf04f5c734fcc4cb6ed5d1a95 ] Commit 15faa1f67ab4 ("lan966x: Fix crash when adding interface under a lag") fixed a similar issue in the lan966x driver caused by a NULL pointer dereference. The ocelot_set_aggr_pgids() function in the ocelot driver has similar logic and is susceptible to the same crash. This issue specifically affects the ocelot_vsc7514.c frontend, which leaves unused ports as NULL pointers. The felix_vsc9959.c frontend is unaffected as it uses the DSA framework which registers all ports. Fix this by checking if the port pointer is valid before accessing it. Fixes: 528d3f190c98 ("net: mscc: ocelot: drop the use of the "lags" array") Signed-off-by: Jerry Wu Reviewed-by: Vladimir Oltean Link: https://patch.msgid.link/tencent_75EF812B305E26B0869C673DD1160866C90A@qq.com Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- drivers/net/ethernet/mscc/ocelot.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c index 08bee56aea35f..c345d9b17c892 100644 --- a/drivers/net/ethernet/mscc/ocelot.c +++ b/drivers/net/ethernet/mscc/ocelot.c @@ -2307,14 +2307,16 @@ static void ocelot_set_aggr_pgids(struct ocelot *ocelot) /* Now, set PGIDs for each active LAG */ for (lag = 0; lag < ocelot->num_phys_ports; lag++) { - struct net_device *bond = ocelot->ports[lag]->bond; + struct ocelot_port *ocelot_port = ocelot->ports[lag]; int num_active_ports = 0; + struct net_device *bond; unsigned long bond_mask; u8 aggr_idx[16]; - if (!bond || (visited & BIT(lag))) + if (!ocelot_port || !ocelot_port->bond || (visited & BIT(lag))) continue; + bond = ocelot_port->bond; bond_mask = ocelot_get_bond_mask(ocelot, bond); for_each_set_bit(port, &bond_mask, ocelot->num_phys_ports) { From 1511ba2d68467ab1259d3524dd804d371aadb9dc Mon Sep 17 00:00:00 2001 From: "yuan.gao" Date: Wed, 24 Dec 2025 14:31:45 +0800 Subject: [PATCH 1865/2333] inet: ping: Fix icmp out counting [ Upstream commit 4c0856c225b39b1def6c9a6bc56faca79550da13 ] When the ping program uses an IPPROTO_ICMP socket to send ICMP_ECHO messages, ICMP_MIB_OUTMSGS is counted twice. ping_v4_sendmsg ping_v4_push_pending_frames ip_push_pending_frames ip_finish_skb __ip_make_skb icmp_out_count(net, icmp_type); // first count icmp_out_count(sock_net(sk), user_icmph.type); // second count However, when the ping program uses an IPPROTO_RAW socket, ICMP_MIB_OUTMSGS is counted correctly only once. Therefore, the first count should be removed. Fixes: c319b4d76b9e ("net: ipv4: add IPPROTO_ICMP socket kind") Signed-off-by: yuan.gao Reviewed-by: Ido Schimmel Tested-by: Ido Schimmel Link: https://patch.msgid.link/20251224063145.3615282-1-yuan.gao@ucloud.cn Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- net/ipv4/ping.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c index 5321c5801c64d..a5227d23bb0b5 100644 --- a/net/ipv4/ping.c +++ b/net/ipv4/ping.c @@ -828,10 +828,8 @@ static int ping_v4_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) out_free: if (free) kfree(ipc.opt); - if (!err) { - icmp_out_count(sock_net(sk), user_icmph.type); + if (!err) return len; - } return err; do_confirm: From fe71b71f0fe05e38fdab34a71f26c53e3b09f17c Mon Sep 17 00:00:00 2001 From: Stefano Radaelli Date: Tue, 23 Dec 2025 13:09:39 +0100 Subject: [PATCH 1866/2333] net: phy: mxl-86110: Add power management and soft reset support [ Upstream commit 62f7edd59964eb588e96fce1ad35a2327ea54424 ] Implement soft_reset, suspend, and resume callbacks using genphy_soft_reset(), genphy_suspend(), and genphy_resume() to fix PHY initialization and power management issues. The soft_reset callback is needed to properly recover the PHY after an ifconfig down/up cycle. Without it, the PHY can remain in power-down state, causing MDIO register access failures during config_init(). The soft reset ensures the PHY is operational before configuration. The suspend/resume callbacks enable proper power management during system suspend/resume cycles. Fixes: b2908a989c59 ("net: phy: add driver for MaxLinear MxL86110 PHY") Signed-off-by: Stefano Radaelli Link: https://patch.msgid.link/20251223120940.407195-1-stefano.r@variscite.com Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- drivers/net/phy/mxl-86110.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/phy/mxl-86110.c b/drivers/net/phy/mxl-86110.c index e5d137a37a1d4..42a5fe3f115f4 100644 --- a/drivers/net/phy/mxl-86110.c +++ b/drivers/net/phy/mxl-86110.c @@ -938,6 +938,9 @@ static struct phy_driver mxl_phy_drvs[] = { PHY_ID_MATCH_EXACT(PHY_ID_MXL86110), .name = "MXL86110 Gigabit Ethernet", .config_init = mxl86110_config_init, + .suspend = genphy_suspend, + .resume = genphy_resume, + .soft_reset = genphy_soft_reset, .get_wol = mxl86110_get_wol, .set_wol = mxl86110_set_wol, .led_brightness_set = mxl86110_led_brightness_set, From e00b169eaac5f7cdbf710c354c8fa76d02009115 Mon Sep 17 00:00:00 2001 From: Weiming Shi Date: Wed, 24 Dec 2025 04:35:35 +0800 Subject: [PATCH 1867/2333] net: sock: fix hardened usercopy panic in sock_recv_errqueue [ Upstream commit 2a71a1a8d0ed718b1c7a9ac61f07e5755c47ae20 ] skbuff_fclone_cache was created without defining a usercopy region, [1] unlike skbuff_head_cache which properly whitelists the cb[] field. [2] This causes a usercopy BUG() when CONFIG_HARDENED_USERCOPY is enabled and the kernel attempts to copy sk_buff.cb data to userspace via sock_recv_errqueue() -> put_cmsg(). The crash occurs when: 1. TCP allocates an skb using alloc_skb_fclone() (from skbuff_fclone_cache) [1] 2. The skb is cloned via skb_clone() using the pre-allocated fclone [3] 3. The cloned skb is queued to sk_error_queue for timestamp reporting 4. Userspace reads the error queue via recvmsg(MSG_ERRQUEUE) 5. sock_recv_errqueue() calls put_cmsg() to copy serr->ee from skb->cb [4] 6. __check_heap_object() fails because skbuff_fclone_cache has no usercopy whitelist [5] When cloned skbs allocated from skbuff_fclone_cache are used in the socket error queue, accessing the sock_exterr_skb structure in skb->cb via put_cmsg() triggers a usercopy hardening violation: [ 5.379589] usercopy: Kernel memory exposure attempt detected from SLUB object 'skbuff_fclone_cache' (offset 296, size 16)! [ 5.382796] kernel BUG at mm/usercopy.c:102! [ 5.383923] Oops: invalid opcode: 0000 [#1] SMP KASAN NOPTI [ 5.384903] CPU: 1 UID: 0 PID: 138 Comm: poc_put_cmsg Not tainted 6.12.57 #7 [ 5.384903] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.16.3-0-ga6ed6b701f0a-prebuilt.qemu.org 04/01/2014 [ 5.384903] RIP: 0010:usercopy_abort+0x6c/0x80 [ 5.384903] Code: 1a 86 51 48 c7 c2 40 15 1a 86 41 52 48 c7 c7 c0 15 1a 86 48 0f 45 d6 48 c7 c6 80 15 1a 86 48 89 c1 49 0f 45 f3 e8 84 27 88 ff <0f> 0b 490 [ 5.384903] RSP: 0018:ffffc900006f77a8 EFLAGS: 00010246 [ 5.384903] RAX: 000000000000006f RBX: ffff88800f0ad2a8 RCX: 1ffffffff0f72e74 [ 5.384903] RDX: 0000000000000000 RSI: 0000000000000004 RDI: ffffffff87b973a0 [ 5.384903] RBP: 0000000000000010 R08: 0000000000000000 R09: fffffbfff0f72e74 [ 5.384903] R10: 0000000000000003 R11: 79706f6372657375 R12: 0000000000000001 [ 5.384903] R13: ffff88800f0ad2b8 R14: ffffea00003c2b40 R15: ffffea00003c2b00 [ 5.384903] FS: 0000000011bc4380(0000) GS:ffff8880bf100000(0000) knlGS:0000000000000000 [ 5.384903] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 5.384903] CR2: 000056aa3b8e5fe4 CR3: 000000000ea26004 CR4: 0000000000770ef0 [ 5.384903] PKRU: 55555554 [ 5.384903] Call Trace: [ 5.384903] [ 5.384903] __check_heap_object+0x9a/0xd0 [ 5.384903] __check_object_size+0x46c/0x690 [ 5.384903] put_cmsg+0x129/0x5e0 [ 5.384903] sock_recv_errqueue+0x22f/0x380 [ 5.384903] tls_sw_recvmsg+0x7ed/0x1960 [ 5.384903] ? srso_alias_return_thunk+0x5/0xfbef5 [ 5.384903] ? schedule+0x6d/0x270 [ 5.384903] ? srso_alias_return_thunk+0x5/0xfbef5 [ 5.384903] ? mutex_unlock+0x81/0xd0 [ 5.384903] ? __pfx_mutex_unlock+0x10/0x10 [ 5.384903] ? __pfx_tls_sw_recvmsg+0x10/0x10 [ 5.384903] ? _raw_spin_lock_irqsave+0x8f/0xf0 [ 5.384903] ? _raw_read_unlock_irqrestore+0x20/0x40 [ 5.384903] ? srso_alias_return_thunk+0x5/0xfbef5 The crash offset 296 corresponds to skb2->cb within skbuff_fclones: - sizeof(struct sk_buff) = 232 - offsetof(struct sk_buff, cb) = 40 - offset of skb2.cb in fclones = 232 + 40 = 272 - crash offset 296 = 272 + 24 (inside sock_exterr_skb.ee) This patch uses a local stack variable as a bounce buffer to avoid the hardened usercopy check failure. [1] https://elixir.bootlin.com/linux/v6.12.62/source/net/ipv4/tcp.c#L885 [2] https://elixir.bootlin.com/linux/v6.12.62/source/net/core/skbuff.c#L5104 [3] https://elixir.bootlin.com/linux/v6.12.62/source/net/core/skbuff.c#L5566 [4] https://elixir.bootlin.com/linux/v6.12.62/source/net/core/skbuff.c#L5491 [5] https://elixir.bootlin.com/linux/v6.12.62/source/mm/slub.c#L5719 Fixes: 6d07d1cd300f ("usercopy: Restrict non-usercopy caches to size 0") Reported-by: Xiang Mei Signed-off-by: Weiming Shi Reviewed-by: Eric Dumazet Link: https://patch.msgid.link/20251223203534.1392218-2-bestswngs@gmail.com Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- net/core/sock.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/net/core/sock.c b/net/core/sock.c index dc03d4b5909a2..5a38837a58384 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -3836,7 +3836,7 @@ void sock_enable_timestamp(struct sock *sk, enum sock_flags flag) int sock_recv_errqueue(struct sock *sk, struct msghdr *msg, int len, int level, int type) { - struct sock_exterr_skb *serr; + struct sock_extended_err ee; struct sk_buff *skb; int copied, err; @@ -3856,8 +3856,9 @@ int sock_recv_errqueue(struct sock *sk, struct msghdr *msg, int len, sock_recv_timestamp(msg, sk, skb); - serr = SKB_EXT_ERR(skb); - put_cmsg(msg, level, type, sizeof(serr->ee), &serr->ee); + /* We must use a bounce buffer for CONFIG_HARDENED_USERCOPY=y */ + ee = SKB_EXT_ERR(skb)->ee; + put_cmsg(msg, level, type, sizeof(ee), &ee); msg->msg_flags |= MSG_ERRQUEUE; err = copied; From 8bdc624bf33d36763bcc1211e54ff27494de8a6b Mon Sep 17 00:00:00 2001 From: Di Zhu Date: Wed, 24 Dec 2025 09:22:24 +0800 Subject: [PATCH 1868/2333] netdev: preserve NETIF_F_ALL_FOR_ALL across TSO updates [ Upstream commit 02d1e1a3f9239cdb3ecf2c6d365fb959d1bf39df ] Directly increment the TSO features incurs a side effect: it will also directly clear the flags in NETIF_F_ALL_FOR_ALL on the master device, which can cause issues such as the inability to enable the nocache copy feature on the bonding driver. The fix is to include NETIF_F_ALL_FOR_ALL in the update mask, thereby preventing it from being cleared. Fixes: b0ce3508b25e ("bonding: allow TSO being set on bonding master") Signed-off-by: Di Zhu Link: https://patch.msgid.link/20251224012224.56185-1-zhud@hygon.cn Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- include/linux/netdevice.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 77c46a2823eca..c6c04cd0a6816 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -5299,7 +5299,8 @@ netdev_features_t netdev_increment_features(netdev_features_t all, static inline netdev_features_t netdev_add_tso_features(netdev_features_t features, netdev_features_t mask) { - return netdev_increment_features(features, NETIF_F_ALL_TSO, mask); + return netdev_increment_features(features, NETIF_F_ALL_TSO | + NETIF_F_ALL_FOR_ALL, mask); } int __netdev_update_features(struct net_device *dev); From 6584963258249da7fc6aee5ed27e90cf0d4065a8 Mon Sep 17 00:00:00 2001 From: Patrisious Haddad Date: Thu, 25 Dec 2025 15:27:13 +0200 Subject: [PATCH 1869/2333] net/mlx5: Lag, multipath, give priority for routes with smaller network prefix [ Upstream commit 31057979cdadfee9f934746fd84046b43506ba61 ] Today multipath offload is controlled by a single route and the route controlling is selected if it meets one of the following criteria: 1. No controlling route is set. 2. New route destination is the same as old one. 3. New route metric is lower than old route metric. This can cause unwanted behaviour in case a new route is added with a smaller network prefix which should get the priority. Fix this by adding a new criteria to give priority to new route with a smaller network prefix. Fixes: ad11c4f1d8fd ("net/mlx5e: Lag, Only handle events from highest priority multipath entry") Signed-off-by: Patrisious Haddad Signed-off-by: Mark Bloch Link: https://patch.msgid.link/20251225132717.358820-2-mbloch@nvidia.com Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- drivers/net/ethernet/mellanox/mlx5/core/lag/mp.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/mp.c b/drivers/net/ethernet/mellanox/mlx5/core/lag/mp.c index aee17fcf3b36c..cdc99fe5c9568 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lag/mp.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/mp.c @@ -173,10 +173,15 @@ static void mlx5_lag_fib_route_event(struct mlx5_lag *ldev, unsigned long event, } /* Handle multipath entry with lower priority value */ - if (mp->fib.mfi && mp->fib.mfi != fi && + if (mp->fib.mfi && (mp->fib.dst != fen_info->dst || mp->fib.dst_len != fen_info->dst_len) && - fi->fib_priority >= mp->fib.priority) + mp->fib.dst_len <= fen_info->dst_len && + !(mp->fib.dst_len == fen_info->dst_len && + fi->fib_priority < mp->fib.priority)) { + mlx5_core_dbg(ldev->pf[idx].dev, + "Multipath entry with lower priority was rejected\n"); return; + } nh_dev0 = mlx5_lag_get_next_fib_dev(ldev, fi, NULL); nh_dev1 = mlx5_lag_get_next_fib_dev(ldev, fi, nh_dev0); From cba6cc0f46540350d250e8355c84e339d99310b5 Mon Sep 17 00:00:00 2001 From: Alexei Lazar Date: Thu, 25 Dec 2025 15:27:14 +0200 Subject: [PATCH 1870/2333] net/mlx5e: Don't gate FEC histograms on ppcnt_statistical_group [ Upstream commit 6c75dc9de40ff91ec2b621b78f6cd9031762067c ] Currently, the ppcnt_statistical_group capability check incorrectly gates access to FEC histogram statistics. This capability applies only to statistical and physical counter groups, not for histogram data. Restrict the ppcnt_statistical_group check to the Physical_Layer_Counters and Physical_Layer_Statistical_Counters groups. Histogram statistics access remains gated by the pphcr capability. The issue is harmless as of today, as it happens that ppcnt_statistical_group is set on all existing devices that have pphcr set. Fixes: 6b81b8a0b197 ("net/mlx5e: Don't query FEC statistics when FEC is disabled") Signed-off-by: Alexei Lazar Reviewed-by: Tariq Toukan Signed-off-by: Mark Bloch Link: https://patch.msgid.link/20251225132717.358820-3-mbloch@nvidia.com Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- drivers/net/ethernet/mellanox/mlx5/core/en_stats.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c b/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c index a2802cfc9b989..a8af84fc97638 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c @@ -1608,12 +1608,13 @@ void mlx5e_stats_fec_get(struct mlx5e_priv *priv, { int mode = fec_active_mode(priv->mdev); - if (mode == MLX5E_FEC_NOFEC || - !MLX5_CAP_PCAM_FEATURE(priv->mdev, ppcnt_statistical_group)) + if (mode == MLX5E_FEC_NOFEC) return; - fec_set_corrected_bits_total(priv, fec_stats); - fec_set_block_stats(priv, mode, fec_stats); + if (MLX5_CAP_PCAM_FEATURE(priv->mdev, ppcnt_statistical_group)) { + fec_set_corrected_bits_total(priv, fec_stats); + fec_set_block_stats(priv, mode, fec_stats); + } if (MLX5_CAP_PCAM_REG(priv->mdev, pphcr)) fec_set_histograms_stats(priv, mode, hist); From d35ab9fb57945e3f1eba71fe28ffa43d517217fd Mon Sep 17 00:00:00 2001 From: Gal Pressman Date: Thu, 25 Dec 2025 15:27:16 +0200 Subject: [PATCH 1871/2333] net/mlx5e: Don't print error message due to invalid module [ Upstream commit 144297e2a24e3e54aee1180ec21120ea38822b97 ] Dumping module EEPROM on newer modules is supported through the netlink interface only. Querying with old userspace ethtool (or other tools, such as 'lshw') which still uses the ioctl interface results in an error message that could flood dmesg (in addition to the expected error return value). The original message was added under the assumption that the driver should be able to handle all module types, but now that such flows are easily triggered from userspace, it doesn't serve its purpose. Change the log level of the print in mlx5_query_module_eeprom() to debug. Fixes: bb64143eee8c ("net/mlx5e: Add ethtool support for dump module EEPROM") Signed-off-by: Gal Pressman Reviewed-by: Tariq Toukan Signed-off-by: Mark Bloch Link: https://patch.msgid.link/20251225132717.358820-5-mbloch@nvidia.com Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- drivers/net/ethernet/mellanox/mlx5/core/port.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/port.c b/drivers/net/ethernet/mellanox/mlx5/core/port.c index aa9f2b0a77d36..876e648c91ba8 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/port.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/port.c @@ -430,7 +430,8 @@ int mlx5_query_module_eeprom(struct mlx5_core_dev *dev, mlx5_qsfp_eeprom_params_set(&query.i2c_address, &query.page, &offset); break; default: - mlx5_core_err(dev, "Module ID not recognized: 0x%x\n", module_id); + mlx5_core_dbg(dev, "Module ID not recognized: 0x%x\n", + module_id); return -EINVAL; } From b46675e1c593673f667e75ae14d82bc1f24d87a5 Mon Sep 17 00:00:00 2001 From: Cosmin Ratiu Date: Thu, 25 Dec 2025 15:27:17 +0200 Subject: [PATCH 1872/2333] net/mlx5e: Dealloc forgotten PSP RX modify header [ Upstream commit 0462a15d2d1fafd3d48cf3c7c67393e42d03908c ] The commit which added RX steering rules for PSP forgot to free a modify header HW object on the cleanup path, which lead to health errors when reloading the driver and uninitializing the device: mlx5_core 0000:08:00.0: poll_health:803:(pid 3021): Fatal error 3 detected Fix that by saving the modify header pointer in the PSP steering struct and deallocating it after freeing the rule which references it. Fixes: 9536fbe10c9d ("net/mlx5e: Add PSP steering in local NIC RX") Signed-off-by: Cosmin Ratiu Reviewed-by: Dragos Tatulea Reviewed-by: Tariq Toukan Signed-off-by: Mark Bloch Link: https://patch.msgid.link/20251225132717.358820-6-mbloch@nvidia.com Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- .../net/ethernet/mellanox/mlx5/core/en_accel/psp.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/psp.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/psp.c index 8565cfe8d7dce..943d6fc6e7a04 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/psp.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/psp.c @@ -41,6 +41,7 @@ struct mlx5e_accel_fs_psp_prot { struct mlx5_flow_table *ft; struct mlx5_flow_group *miss_group; struct mlx5_flow_handle *miss_rule; + struct mlx5_modify_hdr *rx_modify_hdr; struct mlx5_flow_destination default_dest; struct mlx5e_psp_rx_err rx_err; u32 refcnt; @@ -217,13 +218,19 @@ static int accel_psp_fs_rx_err_create_ft(struct mlx5e_psp_fs *fs, return err; } -static void accel_psp_fs_rx_fs_destroy(struct mlx5e_accel_fs_psp_prot *fs_prot) +static void accel_psp_fs_rx_fs_destroy(struct mlx5e_psp_fs *fs, + struct mlx5e_accel_fs_psp_prot *fs_prot) { if (fs_prot->def_rule) { mlx5_del_flow_rules(fs_prot->def_rule); fs_prot->def_rule = NULL; } + if (fs_prot->rx_modify_hdr) { + mlx5_modify_header_dealloc(fs->mdev, fs_prot->rx_modify_hdr); + fs_prot->rx_modify_hdr = NULL; + } + if (fs_prot->miss_rule) { mlx5_del_flow_rules(fs_prot->miss_rule); fs_prot->miss_rule = NULL; @@ -327,6 +334,7 @@ static int accel_psp_fs_rx_create_ft(struct mlx5e_psp_fs *fs, modify_hdr = NULL; goto out_err; } + fs_prot->rx_modify_hdr = modify_hdr; flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST | MLX5_FLOW_CONTEXT_ACTION_CRYPTO_DECRYPT | @@ -347,7 +355,7 @@ static int accel_psp_fs_rx_create_ft(struct mlx5e_psp_fs *fs, goto out; out_err: - accel_psp_fs_rx_fs_destroy(fs_prot); + accel_psp_fs_rx_fs_destroy(fs, fs_prot); out: kvfree(flow_group_in); kvfree(spec); @@ -364,7 +372,7 @@ static int accel_psp_fs_rx_destroy(struct mlx5e_psp_fs *fs, enum accel_fs_psp_ty /* The netdev unreg already happened, so all offloaded rule are already removed */ fs_prot = &accel_psp->fs_prot[type]; - accel_psp_fs_rx_fs_destroy(fs_prot); + accel_psp_fs_rx_fs_destroy(fs, fs_prot); accel_psp_fs_rx_err_destroy_ft(fs, &fs_prot->rx_err); From f2c4bcfa193eef1b7457a56be9c47a8de015f225 Mon Sep 17 00:00:00 2001 From: Frank Liang Date: Wed, 31 Dec 2025 22:58:08 +0800 Subject: [PATCH 1873/2333] net/ena: fix missing lock when update devlink params [ Upstream commit 8da901ffe497a53fa4ecc3ceed0e6d771586f88e ] Fix assert lock warning while calling devl_param_driverinit_value_set() in ena. WARNING: net/devlink/core.c:261 at devl_assert_locked+0x62/0x90, CPU#0: kworker/0:0/9 CPU: 0 UID: 0 PID: 9 Comm: kworker/0:0 Not tainted 6.19.0-rc2+ #1 PREEMPT(lazy) Hardware name: Amazon EC2 m8i-flex.4xlarge/, BIOS 1.0 10/16/2017 Workqueue: events work_for_cpu_fn RIP: 0010:devl_assert_locked+0x62/0x90 Call Trace: devl_param_driverinit_value_set+0x15/0x1c0 ena_devlink_alloc+0x18c/0x220 [ena] ? __pfx_ena_devlink_alloc+0x10/0x10 [ena] ? trace_hardirqs_on+0x18/0x140 ? lockdep_hardirqs_on+0x8c/0x130 ? __raw_spin_unlock_irqrestore+0x5d/0x80 ? __raw_spin_unlock_irqrestore+0x46/0x80 ? devm_ioremap_wc+0x9a/0xd0 ena_probe+0x4d2/0x1b20 [ena] ? __lock_acquire+0x56a/0xbd0 ? __pfx_ena_probe+0x10/0x10 [ena] ? local_clock+0x15/0x30 ? __lock_release.isra.0+0x1c9/0x340 ? mark_held_locks+0x40/0x70 ? lockdep_hardirqs_on_prepare.part.0+0x92/0x170 ? trace_hardirqs_on+0x18/0x140 ? lockdep_hardirqs_on+0x8c/0x130 ? __raw_spin_unlock_irqrestore+0x5d/0x80 ? __raw_spin_unlock_irqrestore+0x46/0x80 ? __pfx_ena_probe+0x10/0x10 [ena] ...... Fixes: 816b52624cf6 ("net: ena: Control PHC enable through devlink") Signed-off-by: Frank Liang Reviewed-by: David Arinzon Reviewed-by: Jiri Pirko Link: https://patch.msgid.link/20251231145808.6103-1-xiliang@redhat.com Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- drivers/net/ethernet/amazon/ena/ena_devlink.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/ethernet/amazon/ena/ena_devlink.c b/drivers/net/ethernet/amazon/ena/ena_devlink.c index ac81c24016dd4..4772185e669d2 100644 --- a/drivers/net/ethernet/amazon/ena/ena_devlink.c +++ b/drivers/net/ethernet/amazon/ena/ena_devlink.c @@ -53,10 +53,12 @@ void ena_devlink_disable_phc_param(struct devlink *devlink) { union devlink_param_value value; + devl_lock(devlink); value.vbool = false; devl_param_driverinit_value_set(devlink, DEVLINK_PARAM_GENERIC_ID_ENABLE_PHC, value); + devl_unlock(devlink); } static void ena_devlink_port_register(struct devlink *devlink) @@ -145,10 +147,12 @@ static int ena_devlink_configure_params(struct devlink *devlink) return rc; } + devl_lock(devlink); value.vbool = ena_phc_is_enabled(adapter); devl_param_driverinit_value_set(devlink, DEVLINK_PARAM_GENERIC_ID_ENABLE_PHC, value); + devl_unlock(devlink); return 0; } From 8181c79757cc9383f9697745d24793555429c888 Mon Sep 17 00:00:00 2001 From: Zilin Guan Date: Tue, 30 Dec 2025 07:18:53 +0000 Subject: [PATCH 1874/2333] net: wwan: iosm: Fix memory leak in ipc_mux_deinit() [ Upstream commit 92e6e0a87f6860a4710f9494f8c704d498ae60f8 ] Commit 1f52d7b62285 ("net: wwan: iosm: Enable M.2 7360 WWAN card support") allocated memory for pp_qlt in ipc_mux_init() but did not free it in ipc_mux_deinit(). This results in a memory leak when the driver is unloaded. Free the allocated memory in ipc_mux_deinit() to fix the leak. Fixes: 1f52d7b62285 ("net: wwan: iosm: Enable M.2 7360 WWAN card support") Co-developed-by: Jianhao Xu Signed-off-by: Jianhao Xu Signed-off-by: Zilin Guan Reviewed-by: Loic Poulain Link: https://patch.msgid.link/20251230071853.1062223-1-zilin@seu.edu.cn Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- drivers/net/wwan/iosm/iosm_ipc_mux.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/wwan/iosm/iosm_ipc_mux.c b/drivers/net/wwan/iosm/iosm_ipc_mux.c index fc928b298a984..b846889fcb099 100644 --- a/drivers/net/wwan/iosm/iosm_ipc_mux.c +++ b/drivers/net/wwan/iosm/iosm_ipc_mux.c @@ -456,6 +456,7 @@ void ipc_mux_deinit(struct iosm_mux *ipc_mux) struct sk_buff_head *free_list; union mux_msg mux_msg; struct sk_buff *skb; + int i; if (!ipc_mux->initialized) return; @@ -479,5 +480,10 @@ void ipc_mux_deinit(struct iosm_mux *ipc_mux) ipc_mux->channel->dl_pipe.is_open = false; } + if (ipc_mux->protocol != MUX_LITE) { + for (i = 0; i < IPC_MEM_MUX_IP_SESSION_ENTRIES; i++) + kfree(ipc_mux->ul_adb.pp_qlt[i]); + } + kfree(ipc_mux); } From e3c7381389759ec88aea65b266e7dc7f1f010b25 Mon Sep 17 00:00:00 2001 From: Srijit Bose Date: Wed, 31 Dec 2025 00:36:25 -0800 Subject: [PATCH 1875/2333] bnxt_en: Fix potential data corruption with HW GRO/LRO [ Upstream commit ffeafa65b2b26df2f5b5a6118d3174f17bd12ec5 ] Fix the max number of bits passed to find_first_zero_bit() in bnxt_alloc_agg_idx(). We were incorrectly passing the number of long words. find_first_zero_bit() may fail to find a zero bit and cause a wrong ID to be used. If the wrong ID is already in use, this can cause data corruption. Sometimes an error like this can also be seen: bnxt_en 0000:83:00.0 enp131s0np0: TPA end agg_buf 2 != expected agg_bufs 1 Fix it by passing the correct number of bits MAX_TPA_P5. Use DECLARE_BITMAP() to more cleanly define the bitmap. Add a sanity check to warn if a bit cannot be found and reset the ring [MChan]. Fixes: ec4d8e7cf024 ("bnxt_en: Add TPA ID mapping logic for 57500 chips.") Reviewed-by: Ray Jui Signed-off-by: Srijit Bose Signed-off-by: Michael Chan Reviewed-by: Vadim Fedorenko Link: https://patch.msgid.link/20251231083625.3911652-1-michael.chan@broadcom.com Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 15 ++++++++++++--- drivers/net/ethernet/broadcom/bnxt/bnxt.h | 4 +--- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 0366323ab0676..95c774d98da66 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -1482,9 +1482,11 @@ static u16 bnxt_alloc_agg_idx(struct bnxt_rx_ring_info *rxr, u16 agg_id) struct bnxt_tpa_idx_map *map = rxr->rx_tpa_idx_map; u16 idx = agg_id & MAX_TPA_P5_MASK; - if (test_bit(idx, map->agg_idx_bmap)) - idx = find_first_zero_bit(map->agg_idx_bmap, - BNXT_AGG_IDX_BMAP_SIZE); + if (test_bit(idx, map->agg_idx_bmap)) { + idx = find_first_zero_bit(map->agg_idx_bmap, MAX_TPA_P5); + if (idx >= MAX_TPA_P5) + return INVALID_HW_RING_ID; + } __set_bit(idx, map->agg_idx_bmap); map->agg_id_tbl[agg_id] = idx; return idx; @@ -1548,6 +1550,13 @@ static void bnxt_tpa_start(struct bnxt *bp, struct bnxt_rx_ring_info *rxr, if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) { agg_id = TPA_START_AGG_ID_P5(tpa_start); agg_id = bnxt_alloc_agg_idx(rxr, agg_id); + if (unlikely(agg_id == INVALID_HW_RING_ID)) { + netdev_warn(bp->dev, "Unable to allocate agg ID for ring %d, agg 0x%x\n", + rxr->bnapi->index, + TPA_START_AGG_ID_P5(tpa_start)); + bnxt_sched_reset_rxr(bp, rxr); + return; + } } else { agg_id = TPA_START_AGG_ID(tpa_start); } diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index 3613a172483a1..45bbaec75ded4 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -1079,11 +1079,9 @@ struct bnxt_tpa_info { struct rx_agg_cmp *agg_arr; }; -#define BNXT_AGG_IDX_BMAP_SIZE (MAX_TPA_P5 / BITS_PER_LONG) - struct bnxt_tpa_idx_map { u16 agg_id_tbl[1024]; - unsigned long agg_idx_bmap[BNXT_AGG_IDX_BMAP_SIZE]; + DECLARE_BITMAP(agg_idx_bmap, MAX_TPA_P5); }; struct bnxt_rx_ring_info { From a5e2d902f64c76169c771f584559c82b588090e3 Mon Sep 17 00:00:00 2001 From: Kommula Shiva Shankar Date: Fri, 2 Jan 2026 15:49:00 +0530 Subject: [PATCH 1876/2333] virtio_net: fix device mismatch in devm_kzalloc/devm_kfree [ Upstream commit acb4bc6e1ba34ae1a34a9334a1ce8474c909466e ] Initial rss_hdr allocation uses virtio_device->device, but virtnet_set_queues() frees using net_device->device. This device mismatch causing below devres warning [ 3788.514041] ------------[ cut here ]------------ [ 3788.514044] WARNING: drivers/base/devres.c:1095 at devm_kfree+0x84/0x98, CPU#16: vdpa/1463 [ 3788.514054] Modules linked in: octep_vdpa virtio_net virtio_vdpa [last unloaded: virtio_vdpa] [ 3788.514064] CPU: 16 UID: 0 PID: 1463 Comm: vdpa Tainted: G W 6.18.0 #10 PREEMPT [ 3788.514067] Tainted: [W]=WARN [ 3788.514069] Hardware name: Marvell CN106XX board (DT) [ 3788.514071] pstate: 63400009 (nZCv daif +PAN -UAO +TCO +DIT -SSBS BTYPE=--) [ 3788.514074] pc : devm_kfree+0x84/0x98 [ 3788.514076] lr : devm_kfree+0x54/0x98 [ 3788.514079] sp : ffff800084e2f220 [ 3788.514080] x29: ffff800084e2f220 x28: ffff0003b2366000 x27: 000000000000003f [ 3788.514085] x26: 000000000000003f x25: ffff000106f17c10 x24: 0000000000000080 [ 3788.514089] x23: ffff00045bb8ab08 x22: ffff00045bb8a000 x21: 0000000000000018 [ 3788.514093] x20: ffff0004355c3080 x19: ffff00045bb8aa00 x18: 0000000000080000 [ 3788.514098] x17: 0000000000000040 x16: 000000000000001f x15: 000000000007ffff [ 3788.514102] x14: 0000000000000488 x13: 0000000000000005 x12: 00000000000fffff [ 3788.514106] x11: ffffffffffffffff x10: 0000000000000005 x9 : ffff800080c8c05c [ 3788.514110] x8 : ffff800084e2eeb8 x7 : 0000000000000000 x6 : 000000000000003f [ 3788.514115] x5 : ffff8000831bafe0 x4 : ffff800080c8b010 x3 : ffff0004355c3080 [ 3788.514119] x2 : ffff0004355c3080 x1 : 0000000000000000 x0 : 0000000000000000 [ 3788.514123] Call trace: [ 3788.514125] devm_kfree+0x84/0x98 (P) [ 3788.514129] virtnet_set_queues+0x134/0x2e8 [virtio_net] [ 3788.514135] virtnet_probe+0x9c0/0xe00 [virtio_net] [ 3788.514139] virtio_dev_probe+0x1e0/0x338 [ 3788.514144] really_probe+0xc8/0x3a0 [ 3788.514149] __driver_probe_device+0x84/0x170 [ 3788.514152] driver_probe_device+0x44/0x120 [ 3788.514155] __device_attach_driver+0xc4/0x168 [ 3788.514158] bus_for_each_drv+0x8c/0xf0 [ 3788.514161] __device_attach+0xa4/0x1c0 [ 3788.514164] device_initial_probe+0x1c/0x30 [ 3788.514168] bus_probe_device+0xb4/0xc0 [ 3788.514170] device_add+0x614/0x828 [ 3788.514173] register_virtio_device+0x214/0x258 [ 3788.514175] virtio_vdpa_probe+0xa0/0x110 [virtio_vdpa] [ 3788.514179] vdpa_dev_probe+0xa8/0xd8 [ 3788.514183] really_probe+0xc8/0x3a0 [ 3788.514186] __driver_probe_device+0x84/0x170 [ 3788.514189] driver_probe_device+0x44/0x120 [ 3788.514192] __device_attach_driver+0xc4/0x168 [ 3788.514195] bus_for_each_drv+0x8c/0xf0 [ 3788.514197] __device_attach+0xa4/0x1c0 [ 3788.514200] device_initial_probe+0x1c/0x30 [ 3788.514203] bus_probe_device+0xb4/0xc0 [ 3788.514206] device_add+0x614/0x828 [ 3788.514209] _vdpa_register_device+0x58/0x88 [ 3788.514211] octep_vdpa_dev_add+0x104/0x228 [octep_vdpa] [ 3788.514215] vdpa_nl_cmd_dev_add_set_doit+0x2d0/0x3c0 [ 3788.514218] genl_family_rcv_msg_doit+0xe4/0x158 [ 3788.514222] genl_rcv_msg+0x218/0x298 [ 3788.514225] netlink_rcv_skb+0x64/0x138 [ 3788.514229] genl_rcv+0x40/0x60 [ 3788.514233] netlink_unicast+0x32c/0x3b0 [ 3788.514237] netlink_sendmsg+0x170/0x3b8 [ 3788.514241] __sys_sendto+0x12c/0x1c0 [ 3788.514246] __arm64_sys_sendto+0x30/0x48 [ 3788.514249] invoke_syscall.constprop.0+0x58/0xf8 [ 3788.514255] do_el0_svc+0x48/0xd0 [ 3788.514259] el0_svc+0x48/0x210 [ 3788.514264] el0t_64_sync_handler+0xa0/0xe8 [ 3788.514268] el0t_64_sync+0x198/0x1a0 [ 3788.514271] ---[ end trace 0000000000000000 ]--- Fix by using virtio_device->device consistently for allocation and deallocation Fixes: 4944be2f5ad8c ("virtio_net: Allocate rss_hdr with devres") Signed-off-by: Kommula Shiva Shankar Acked-by: Michael S. Tsirkin Acked-by: Jason Wang Reviewed-by: Xuan Zhuo Link: https://patch.msgid.link/20260102101900.692770-1-kshankar@marvell.com Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- drivers/net/virtio_net.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 8e04adb57f52a..4e1a5291099a5 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -3783,7 +3783,7 @@ static int virtnet_set_queues(struct virtnet_info *vi, u16 queue_pairs) if (vi->has_rss && !netif_is_rxfh_configured(dev)) { old_rss_hdr = vi->rss_hdr; old_rss_trailer = vi->rss_trailer; - vi->rss_hdr = devm_kzalloc(&dev->dev, virtnet_rss_hdr_size(vi), GFP_KERNEL); + vi->rss_hdr = devm_kzalloc(&vi->vdev->dev, virtnet_rss_hdr_size(vi), GFP_KERNEL); if (!vi->rss_hdr) { vi->rss_hdr = old_rss_hdr; return -ENOMEM; @@ -3794,7 +3794,7 @@ static int virtnet_set_queues(struct virtnet_info *vi, u16 queue_pairs) if (!virtnet_commit_rss_command(vi)) { /* restore ctrl_rss if commit_rss_command failed */ - devm_kfree(&dev->dev, vi->rss_hdr); + devm_kfree(&vi->vdev->dev, vi->rss_hdr); vi->rss_hdr = old_rss_hdr; vi->rss_trailer = old_rss_trailer; @@ -3802,7 +3802,7 @@ static int virtnet_set_queues(struct virtnet_info *vi, u16 queue_pairs) queue_pairs); return -EINVAL; } - devm_kfree(&dev->dev, old_rss_hdr); + devm_kfree(&vi->vdev->dev, old_rss_hdr); goto succ; } From 088ca99dbb039c444c3ff987c5412a73f4f0cbf8 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Fri, 2 Jan 2026 15:00:07 +0100 Subject: [PATCH 1877/2333] inet: frags: drop fraglist conntrack references [ Upstream commit 2ef02ac38d3c17f34a00c4b267d961a8d4b45d1a ] Jakub added a warning in nf_conntrack_cleanup_net_list() to make debugging leaked skbs/conntrack references more obvious. syzbot reports this as triggering, and I can also reproduce this via ip_defrag.sh selftest: conntrack cleanup blocked for 60s WARNING: net/netfilter/nf_conntrack_core.c:2512 [..] conntrack clenups gets stuck because there are skbs with still hold nf_conn references via their frag_list. net.core.skb_defer_max=0 makes the hang disappear. Eric Dumazet points out that skb_release_head_state() doesn't follow the fraglist. ip_defrag.sh can only reproduce this problem since commit 6471658dc66c ("udp: use skb_attempt_defer_free()"), but AFAICS this problem could happen with TCP as well if pmtu discovery is off. The relevant problem path for udp is: 1. netns emits fragmented packets 2. nf_defrag_v6_hook reassembles them (in output hook) 3. reassembled skb is tracked (skb owns nf_conn reference) 4. ip6_output refragments 5. refragmented packets also own nf_conn reference (ip6_fragment calls ip6_copy_metadata()) 6. on input path, nf_defrag_v6_hook skips defragmentation: the fragments already have skb->nf_conn attached 7. skbs are reassembled via ipv6_frag_rcv() 8. skb_consume_udp -> skb_attempt_defer_free() -> skb ends up in pcpu freelist, but still has nf_conn reference. Possible solutions: 1 let defrag engine drop nf_conn entry, OR 2 export kick_defer_list_purge() and call it from the conntrack netns exit callback, OR 3 add skb_has_frag_list() check to skb_attempt_defer_free() 2 & 3 also solve ip_defrag.sh hang but share same drawback: Such reassembled skbs, queued to socket, can prevent conntrack module removal until userspace has consumed the packet. While both tcp and udp stack do call nf_reset_ct() before placing skb on socket queue, that function doesn't iterate frag_list skbs. Therefore drop nf_conn entries when they are placed in defrag queue. Keep the nf_conn entry of the first (offset 0) skb so that reassembled skb retains nf_conn entry for sake of TX path. Note that fixes tag is incorrect; it points to the commit introducing the 'ip_defrag.sh reproducible problem': no need to backport this patch to every stable kernel. Reported-by: syzbot+4393c47753b7808dac7d@syzkaller.appspotmail.com Closes: https://lore.kernel.org/netdev/693b0fa7.050a0220.4004e.040d.GAE@google.com/ Fixes: 6471658dc66c ("udp: use skb_attempt_defer_free()") Signed-off-by: Florian Westphal Reviewed-by: Eric Dumazet Link: https://patch.msgid.link/20260102140030.32367-1-fw@strlen.de Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- net/ipv4/inet_fragment.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/ipv4/inet_fragment.c b/net/ipv4/inet_fragment.c index 001ee5c4d962e..4e6d7467ed444 100644 --- a/net/ipv4/inet_fragment.c +++ b/net/ipv4/inet_fragment.c @@ -488,6 +488,8 @@ int inet_frag_queue_insert(struct inet_frag_queue *q, struct sk_buff *skb, } FRAG_CB(skb)->ip_defrag_offset = offset; + if (offset) + nf_reset_ct(skb); return IPFRAG_OK; } From deee9dfb111ab00f9dfd46c0c7e36656b80f5235 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Sat, 20 Dec 2025 14:14:41 +0100 Subject: [PATCH 1878/2333] perf: Ensure swevent hrtimer is properly destroyed [ Upstream commit ff5860f5088e9076ebcccf05a6ca709d5935cfa9 ] With the change to hrtimer_try_to_cancel() in perf_swevent_cancel_hrtimer() it appears possible for the hrtimer to still be active by the time the event gets freed. Make sure the event does a full hrtimer_cancel() on the free path by installing a perf_event::destroy handler. Fixes: eb3182ef0405 ("perf/core: Fix system hang caused by cpu-clock usage") Reported-by: CyberUnicorns Tested-by: CyberUnicorns Debugged-by: Thomas Gleixner Signed-off-by: Peter Zijlstra (Intel) Signed-off-by: Sasha Levin --- kernel/events/core.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/kernel/events/core.c b/kernel/events/core.c index 413b88a4e00fb..d95f9dce018f4 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -11835,6 +11835,11 @@ static void perf_swevent_cancel_hrtimer(struct perf_event *event) } } +static void perf_swevent_destroy_hrtimer(struct perf_event *event) +{ + hrtimer_cancel(&event->hw.hrtimer); +} + static void perf_swevent_init_hrtimer(struct perf_event *event) { struct hw_perf_event *hwc = &event->hw; @@ -11843,6 +11848,7 @@ static void perf_swevent_init_hrtimer(struct perf_event *event) return; hrtimer_setup(&hwc->hrtimer, perf_swevent_hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_HARD); + event->destroy = perf_swevent_destroy_hrtimer; /* * Since hrtimers have a fixed rate, we can do a static freq->period From a1c0a4ccbe6dbe7198eab6cb0e9d23ea3f47d05a Mon Sep 17 00:00:00 2001 From: Yang Wang Date: Thu, 11 Dec 2025 10:47:18 +0800 Subject: [PATCH 1879/2333] drm/amd/pm: fix wrong pcie parameter on navi1x [ Upstream commit 4f74c2dd970611d3ec3bb0d58215e73af5cd7214 ] fix wrong pcie dpm parameter on navi1x Fixes: 1a18607c07bb ("drm/amd/pm: override pcie dpm parameters only if it is necessary") Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/4671 Signed-off-by: Yang Wang Co-developed-by: Kenneth Feng Signed-off-by: Kenneth Feng Acked-by: Alex Deucher Reviewed-by: Lijo Lazar Signed-off-by: Alex Deucher (cherry picked from commit 5c5189cf4b0cc0a22bac74a40743ee711cff07f8) Signed-off-by: Sasha Levin --- drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c index 0028f10ead423..d0fd9537e6236 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c @@ -2463,8 +2463,8 @@ static int navi10_update_pcie_parameters(struct smu_context *smu, pptable->PcieLaneCount[i] > pcie_width_cap ? pcie_width_cap : pptable->PcieLaneCount[i]; smu_pcie_arg = i << 16; - smu_pcie_arg |= pcie_gen_cap << 8; - smu_pcie_arg |= pcie_width_cap; + smu_pcie_arg |= dpm_context->dpm_tables.pcie_table.pcie_gen[i] << 8; + smu_pcie_arg |= dpm_context->dpm_tables.pcie_table.pcie_lane[i]; ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_OverridePcieParameters, smu_pcie_arg, From 543f8537b470340a82e78d7002f293b7aff79619 Mon Sep 17 00:00:00 2001 From: Yang Wang Date: Mon, 15 Dec 2025 17:51:11 +0800 Subject: [PATCH 1880/2333] drm/amd/pm: force send pcie parmater on navi1x [ Upstream commit dc8a887de1a7d397ab4131f45676e89565417aa8 ] v1: the PMFW didn't initialize the PCIe DPM parameters and requires the KMD to actively provide these parameters. v2: clean & remove unused code logic (lijo) Fixes: 1a18607c07bb ("drm/amd/pm: override pcie dpm parameters only if it is necessary") Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/4671 Signed-off-by: Yang Wang Reviewed-by: Lijo Lazar Signed-off-by: Alex Deucher (cherry picked from commit b0dbd5db7cf1f81e4aaedd25cb5e72ce369387b2) Signed-off-by: Sasha Levin --- .../gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c | 33 +++++++++---------- 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c index d0fd9537e6236..a2fcf678182b4 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c @@ -2454,24 +2454,21 @@ static int navi10_update_pcie_parameters(struct smu_context *smu, } for (i = 0; i < NUM_LINK_LEVELS; i++) { - if (pptable->PcieGenSpeed[i] > pcie_gen_cap || - pptable->PcieLaneCount[i] > pcie_width_cap) { - dpm_context->dpm_tables.pcie_table.pcie_gen[i] = - pptable->PcieGenSpeed[i] > pcie_gen_cap ? - pcie_gen_cap : pptable->PcieGenSpeed[i]; - dpm_context->dpm_tables.pcie_table.pcie_lane[i] = - pptable->PcieLaneCount[i] > pcie_width_cap ? - pcie_width_cap : pptable->PcieLaneCount[i]; - smu_pcie_arg = i << 16; - smu_pcie_arg |= dpm_context->dpm_tables.pcie_table.pcie_gen[i] << 8; - smu_pcie_arg |= dpm_context->dpm_tables.pcie_table.pcie_lane[i]; - ret = smu_cmn_send_smc_msg_with_param(smu, - SMU_MSG_OverridePcieParameters, - smu_pcie_arg, - NULL); - if (ret) - break; - } + dpm_context->dpm_tables.pcie_table.pcie_gen[i] = + pptable->PcieGenSpeed[i] > pcie_gen_cap ? + pcie_gen_cap : pptable->PcieGenSpeed[i]; + dpm_context->dpm_tables.pcie_table.pcie_lane[i] = + pptable->PcieLaneCount[i] > pcie_width_cap ? + pcie_width_cap : pptable->PcieLaneCount[i]; + smu_pcie_arg = i << 16; + smu_pcie_arg |= dpm_context->dpm_tables.pcie_table.pcie_gen[i] << 8; + smu_pcie_arg |= dpm_context->dpm_tables.pcie_table.pcie_lane[i]; + ret = smu_cmn_send_smc_msg_with_param(smu, + SMU_MSG_OverridePcieParameters, + smu_pcie_arg, + NULL); + if (ret) + return ret; } return ret; From 0185dc4b5b0e229b0e188dc6cd693e2ebbf58355 Mon Sep 17 00:00:00 2001 From: Michal Luczaj Date: Mon, 29 Dec 2025 20:43:10 +0100 Subject: [PATCH 1881/2333] vsock: Make accept()ed sockets use custom setsockopt() [ Upstream commit ce5e612dd411de096aa041b9e9325ba1bec5f9f4 ] SO_ZEROCOPY handling in vsock_connectible_setsockopt() does not get called on accept()ed sockets due to a missing flag. Flip it. Fixes: e0718bd82e27 ("vsock: enable setting SO_ZEROCOPY") Signed-off-by: Michal Luczaj Link: https://patch.msgid.link/20251229-vsock-child-sock-custom-sockopt-v2-1-64778d6c4f88@rbox.co Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- net/vmw_vsock/af_vsock.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/net/vmw_vsock/af_vsock.c b/net/vmw_vsock/af_vsock.c index a9ca9c3b87b31..cbd649bf01459 100644 --- a/net/vmw_vsock/af_vsock.c +++ b/net/vmw_vsock/af_vsock.c @@ -1787,6 +1787,10 @@ static int vsock_accept(struct socket *sock, struct socket *newsock, } else { newsock->state = SS_CONNECTED; sock_graft(connected, newsock); + + set_bit(SOCK_CUSTOM_SOCKOPT, + &connected->sk_socket->flags); + if (vsock_msgzerocopy_allow(vconnected->transport)) set_bit(SOCK_SUPPORT_ZC, &connected->sk_socket->flags); From 92a5590851144f034adc51fee55e6878ccac716e Mon Sep 17 00:00:00 2001 From: Filipe Manana Date: Tue, 16 Dec 2025 14:51:52 +0000 Subject: [PATCH 1882/2333] btrfs: release path before initializing extent tree in btrfs_read_locked_inode() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 8731f2c50b0b1d2b58ed5b9671ef2c4bdc2f8347 ] In btrfs_read_locked_inode() we are calling btrfs_init_file_extent_tree() while holding a path with a read locked leaf from a subvolume tree, and btrfs_init_file_extent_tree() may do a GFP_KERNEL allocation, which can trigger reclaim. This can create a circular lock dependency which lockdep warns about with the following splat: [6.1433] ====================================================== [6.1574] WARNING: possible circular locking dependency detected [6.1583] 6.18.0+ #4 Tainted: G U [6.1591] ------------------------------------------------------ [6.1599] kswapd0/117 is trying to acquire lock: [6.1606] ffff8d9b6333c5b8 (&delayed_node->mutex){+.+.}-{3:3}, at: __btrfs_release_delayed_node.part.0+0x39/0x2f0 [6.1625] but task is already holding lock: [6.1633] ffffffffa4ab8ce0 (fs_reclaim){+.+.}-{0:0}, at: balance_pgdat+0x195/0xc60 [6.1646] which lock already depends on the new lock. [6.1657] the existing dependency chain (in reverse order) is: [6.1667] -> #2 (fs_reclaim){+.+.}-{0:0}: [6.1677] fs_reclaim_acquire+0x9d/0xd0 [6.1685] __kmalloc_cache_noprof+0x59/0x750 [6.1694] btrfs_init_file_extent_tree+0x90/0x100 [6.1702] btrfs_read_locked_inode+0xc3/0x6b0 [6.1710] btrfs_iget+0xbb/0xf0 [6.1716] btrfs_lookup_dentry+0x3c5/0x8e0 [6.1724] btrfs_lookup+0x12/0x30 [6.1731] lookup_open.isra.0+0x1aa/0x6a0 [6.1739] path_openat+0x5f7/0xc60 [6.1746] do_filp_open+0xd6/0x180 [6.1753] do_sys_openat2+0x8b/0xe0 [6.1760] __x64_sys_openat+0x54/0xa0 [6.1768] do_syscall_64+0x97/0x3e0 [6.1776] entry_SYSCALL_64_after_hwframe+0x76/0x7e [6.1784] -> #1 (btrfs-tree-00){++++}-{3:3}: [6.1794] lock_release+0x127/0x2a0 [6.1801] up_read+0x1b/0x30 [6.1808] btrfs_search_slot+0x8e0/0xff0 [6.1817] btrfs_lookup_inode+0x52/0xd0 [6.1825] __btrfs_update_delayed_inode+0x73/0x520 [6.1833] btrfs_commit_inode_delayed_inode+0x11a/0x120 [6.1842] btrfs_log_inode+0x608/0x1aa0 [6.1849] btrfs_log_inode_parent+0x249/0xf80 [6.1857] btrfs_log_dentry_safe+0x3e/0x60 [6.1865] btrfs_sync_file+0x431/0x690 [6.1872] do_fsync+0x39/0x80 [6.1879] __x64_sys_fsync+0x13/0x20 [6.1887] do_syscall_64+0x97/0x3e0 [6.1894] entry_SYSCALL_64_after_hwframe+0x76/0x7e [6.1903] -> #0 (&delayed_node->mutex){+.+.}-{3:3}: [6.1913] __lock_acquire+0x15e9/0x2820 [6.1920] lock_acquire+0xc9/0x2d0 [6.1927] __mutex_lock+0xcc/0x10a0 [6.1934] __btrfs_release_delayed_node.part.0+0x39/0x2f0 [6.1944] btrfs_evict_inode+0x20b/0x4b0 [6.1952] evict+0x15a/0x2f0 [6.1958] prune_icache_sb+0x91/0xd0 [6.1966] super_cache_scan+0x150/0x1d0 [6.1974] do_shrink_slab+0x155/0x6f0 [6.1981] shrink_slab+0x48e/0x890 [6.1988] shrink_one+0x11a/0x1f0 [6.1995] shrink_node+0xbfd/0x1320 [6.1002] balance_pgdat+0x67f/0xc60 [6.1321] kswapd+0x1dc/0x3e0 [6.1643] kthread+0xff/0x240 [6.1965] ret_from_fork+0x223/0x280 [6.1287] ret_from_fork_asm+0x1a/0x30 [6.1616] other info that might help us debug this: [6.1561] Chain exists of: &delayed_node->mutex --> btrfs-tree-00 --> fs_reclaim [6.1503] Possible unsafe locking scenario: [6.1110] CPU0 CPU1 [6.1411] ---- ---- [6.1707] lock(fs_reclaim); [6.1998] lock(btrfs-tree-00); [6.1291] lock(fs_reclaim); [6.1581] lock(&delayed_node->mutex); [6.1874] *** DEADLOCK *** [6.1716] 2 locks held by kswapd0/117: [6.1999] #0: ffffffffa4ab8ce0 (fs_reclaim){+.+.}-{0:0}, at: balance_pgdat+0x195/0xc60 [6.1294] #1: ffff8d998344b0e0 (&type->s_umount_key#40){++++}- {3:3}, at: super_cache_scan+0x37/0x1d0 [6.1596] stack backtrace: [6.1183] CPU: 11 UID: 0 PID: 117 Comm: kswapd0 Tainted: G U 6.18.0+ #4 PREEMPT(lazy) [6.1185] Tainted: [U]=USER [6.1186] Hardware name: ASUS System Product Name/PRIME B560M-A AC, BIOS 2001 02/01/2023 [6.1187] Call Trace: [6.1187] [6.1189] dump_stack_lvl+0x6e/0xa0 [6.1192] print_circular_bug.cold+0x17a/0x1c0 [6.1194] check_noncircular+0x175/0x190 [6.1197] __lock_acquire+0x15e9/0x2820 [6.1200] lock_acquire+0xc9/0x2d0 [6.1201] ? __btrfs_release_delayed_node.part.0+0x39/0x2f0 [6.1204] __mutex_lock+0xcc/0x10a0 [6.1206] ? __btrfs_release_delayed_node.part.0+0x39/0x2f0 [6.1208] ? __btrfs_release_delayed_node.part.0+0x39/0x2f0 [6.1211] ? __btrfs_release_delayed_node.part.0+0x39/0x2f0 [6.1213] __btrfs_release_delayed_node.part.0+0x39/0x2f0 [6.1215] btrfs_evict_inode+0x20b/0x4b0 [6.1217] ? lock_acquire+0xc9/0x2d0 [6.1220] evict+0x15a/0x2f0 [6.1222] prune_icache_sb+0x91/0xd0 [6.1224] super_cache_scan+0x150/0x1d0 [6.1226] do_shrink_slab+0x155/0x6f0 [6.1228] shrink_slab+0x48e/0x890 [6.1229] ? shrink_slab+0x2d2/0x890 [6.1231] shrink_one+0x11a/0x1f0 [6.1234] shrink_node+0xbfd/0x1320 [6.1236] ? shrink_node+0xa2d/0x1320 [6.1236] ? shrink_node+0xbd3/0x1320 [6.1239] ? balance_pgdat+0x67f/0xc60 [6.1239] balance_pgdat+0x67f/0xc60 [6.1241] ? finish_task_switch.isra.0+0xc4/0x2a0 [6.1246] kswapd+0x1dc/0x3e0 [6.1247] ? __pfx_autoremove_wake_function+0x10/0x10 [6.1249] ? __pfx_kswapd+0x10/0x10 [6.1250] kthread+0xff/0x240 [6.1251] ? __pfx_kthread+0x10/0x10 [6.1253] ret_from_fork+0x223/0x280 [6.1255] ? __pfx_kthread+0x10/0x10 [6.1257] ret_from_fork_asm+0x1a/0x30 [6.1260] This is because: 1) The fsync task is holding an inode's delayed node mutex (for a directory) while calling __btrfs_update_delayed_inode() and that needs to do a search on the subvolume's btree (therefore read lock some extent buffers); 2) The lookup task, at btrfs_lookup(), triggered reclaim with the GFP_KERNEL allocation done by btrfs_init_file_extent_tree() while holding a read lock on a subvolume leaf; 3) The reclaim triggered kswapd which is doing inode eviction for the directory inode the fsync task is using as an argument to btrfs_commit_inode_delayed_inode() - but in that call chain we are trying to read lock the same leaf that the lookup task is holding while calling btrfs_init_file_extent_tree() and doing the GFP_KERNEL allocation. Fix this by calling btrfs_init_file_extent_tree() after we don't need the path anymore and release it in btrfs_read_locked_inode(). Reported-by: Thomas Hellström Link: https://lore.kernel.org/linux-btrfs/6e55113a22347c3925458a5d840a18401a38b276.camel@linux.intel.com/ Fixes: 8679d2687c35 ("btrfs: initialize inode::file_extent_tree after i_mode has been set") Reviewed-by: Qu Wenruo Signed-off-by: Filipe Manana Reviewed-by: David Sterba Signed-off-by: David Sterba Signed-off-by: Sasha Levin --- fs/btrfs/inode.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 51401d586a7b6..27a562bad6e87 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -3976,11 +3976,6 @@ static int btrfs_read_locked_inode(struct btrfs_inode *inode, struct btrfs_path btrfs_set_inode_mapping_order(inode); cache_index: - ret = btrfs_init_file_extent_tree(inode); - if (ret) - goto out; - btrfs_inode_set_file_extent_range(inode, 0, - round_up(i_size_read(vfs_inode), fs_info->sectorsize)); /* * If we were modified in the current generation and evicted from memory * and then re-read we need to do a full sync since we don't have any @@ -4067,6 +4062,20 @@ static int btrfs_read_locked_inode(struct btrfs_inode *inode, struct btrfs_path btrfs_ino(inode), btrfs_root_id(root), ret); } + /* + * We don't need the path anymore, so release it to avoid holding a read + * lock on a leaf while calling btrfs_init_file_extent_tree(), which can + * allocate memory that triggers reclaim (GFP_KERNEL) and cause a locking + * dependency. + */ + btrfs_release_path(path); + + ret = btrfs_init_file_extent_tree(inode); + if (ret) + goto out; + btrfs_inode_set_file_extent_range(inode, 0, + round_up(i_size_read(vfs_inode), fs_info->sectorsize)); + if (!maybe_acls) cache_no_acl(vfs_inode); From 07effd536ddc102bfae763fa836171fff5e6a7fb Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Thu, 18 Dec 2025 15:15:28 +1030 Subject: [PATCH 1883/2333] btrfs: only enforce free space tree if v1 cache is required for bs < ps cases [ Upstream commit 30bcf4e824aa37d305502f52e1527c7b1eabef3d ] [BUG] Since the introduction of btrfs bs < ps support, v1 cache was never on the plan due to its hard coded PAGE_SIZE usage, and the future plan to properly deprecate it. However for bs < ps cases, even if 'nospace_cache,clear_cache' mount option is specified, it's never respected and free space tree is always enabled: mkfs.btrfs -f -O ^bgt,fst $dev mount $dev $mnt -o clear_cache,nospace_cache umount $mnt btrfs ins dump-super $dev ... compat_ro_flags 0x3 ( FREE_SPACE_TREE | FREE_SPACE_TREE_VALID ) ... This means a different behavior compared to bs >= ps cases. [CAUSE] The forcing usage of v2 space cache is done inside btrfs_set_free_space_cache_settings(), however it never checks if we're even using space cache but always enabling v2 cache. [FIX] Instead unconditionally enable v2 cache, only forcing v2 cache if the old v1 cache is required. Now v2 space cache can be properly disabled on bs < ps cases: mkfs.btrfs -f -O ^bgt,fst $dev mount $dev $mnt -o clear_cache,nospace_cache umount $mnt btrfs ins dump-super $dev ... compat_ro_flags 0x0 ... Fixes: 9f73f1aef98b ("btrfs: force v2 space cache usage for subpage mount") Reviewed-by: Filipe Manana Signed-off-by: Qu Wenruo Reviewed-by: David Sterba Signed-off-by: David Sterba Signed-off-by: Sasha Levin --- fs/btrfs/super.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 430e7419349c9..c40944ca7b948 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -736,14 +736,12 @@ bool btrfs_check_options(const struct btrfs_fs_info *info, */ void btrfs_set_free_space_cache_settings(struct btrfs_fs_info *fs_info) { - if (fs_info->sectorsize < PAGE_SIZE) { + if (fs_info->sectorsize < PAGE_SIZE && btrfs_test_opt(fs_info, SPACE_CACHE)) { + btrfs_info(fs_info, + "forcing free space tree for sector size %u with page size %lu", + fs_info->sectorsize, PAGE_SIZE); btrfs_clear_opt(fs_info->mount_opt, SPACE_CACHE); - if (!btrfs_test_opt(fs_info, FREE_SPACE_TREE)) { - btrfs_info(fs_info, - "forcing free space tree for sector size %u with page size %lu", - fs_info->sectorsize, PAGE_SIZE); - btrfs_set_opt(fs_info->mount_opt, FREE_SPACE_TREE); - } + btrfs_set_opt(fs_info->mount_opt, FREE_SPACE_TREE); } /* From 6d1b61b8e1e44888c643d89225ab819b10649b2e Mon Sep 17 00:00:00 2001 From: Suchit Karunakaran Date: Fri, 19 Dec 2025 22:44:34 +0530 Subject: [PATCH 1884/2333] btrfs: fix NULL pointer dereference in do_abort_log_replay() [ Upstream commit 530e3d4af566ca44807d79359b90794dea24c4f3 ] Coverity reported a NULL pointer dereference issue (CID 1666756) in do_abort_log_replay(). When btrfs_alloc_path() fails in replay_one_buffer(), wc->subvol_path is NULL, but btrfs_abort_log_replay() calls do_abort_log_replay() which unconditionally dereferences wc->subvol_path when attempting to print debug information. Fix this by adding a NULL check before dereferencing wc->subvol_path in do_abort_log_replay(). Fixes: 2753e4917624 ("btrfs: dump detailed info and specific messages on log replay failures") Reviewed-by: Filipe Manana Signed-off-by: Suchit Karunakaran Signed-off-by: Filipe Manana Signed-off-by: David Sterba Signed-off-by: Sasha Levin --- fs/btrfs/tree-log.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index de9ea9d52482f..1444857de9fe8 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -189,7 +189,7 @@ static void do_abort_log_replay(struct walk_control *wc, const char *function, btrfs_abort_transaction(wc->trans, error); - if (wc->subvol_path->nodes[0]) { + if (wc->subvol_path && wc->subvol_path->nodes[0]) { btrfs_crit(fs_info, "subvolume (root %llu) leaf currently being processed:", btrfs_root_id(wc->root)); From 8a6b410e3d0f7ece64533a0f4d954fcada0f5d83 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 2 Jan 2026 12:29:38 +0100 Subject: [PATCH 1885/2333] net: airoha: Fix npu rx DMA definitions [ Upstream commit a7fc8c641cab855824c45e5e8877e40fd528b5df ] Fix typos in npu rx DMA descriptor definitions. Fixes: b3ef7bdec66fb ("net: airoha: Add airoha_offload.h header") Signed-off-by: Lorenzo Bianconi Link: https://patch.msgid.link/20260102-airoha-npu-dma-rx-def-fixes-v1-1-205fc6bf7d94@kernel.org Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- include/linux/soc/airoha/airoha_offload.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/linux/soc/airoha/airoha_offload.h b/include/linux/soc/airoha/airoha_offload.h index 6f66eb339b3fc..1a33f846afafa 100644 --- a/include/linux/soc/airoha/airoha_offload.h +++ b/include/linux/soc/airoha/airoha_offload.h @@ -70,12 +70,12 @@ static inline void airoha_ppe_dev_check_skb(struct airoha_ppe_dev *dev, #define NPU_RX1_DESC_NUM 512 /* CTRL */ -#define NPU_RX_DMA_DESC_LAST_MASK BIT(29) -#define NPU_RX_DMA_DESC_LEN_MASK GENMASK(28, 15) -#define NPU_RX_DMA_DESC_CUR_LEN_MASK GENMASK(14, 1) +#define NPU_RX_DMA_DESC_LAST_MASK BIT(27) +#define NPU_RX_DMA_DESC_LEN_MASK GENMASK(26, 14) +#define NPU_RX_DMA_DESC_CUR_LEN_MASK GENMASK(13, 1) #define NPU_RX_DMA_DESC_DONE_MASK BIT(0) /* INFO */ -#define NPU_RX_DMA_PKT_COUNT_MASK GENMASK(31, 28) +#define NPU_RX_DMA_PKT_COUNT_MASK GENMASK(31, 29) #define NPU_RX_DMA_PKT_ID_MASK GENMASK(28, 26) #define NPU_RX_DMA_SRC_PORT_MASK GENMASK(25, 21) #define NPU_RX_DMA_CRSN_MASK GENMASK(20, 16) From 5bfaf4fa3dc29826fd3f0d102636da5af4f8a544 Mon Sep 17 00:00:00 2001 From: Guodong Xu Date: Tue, 23 Dec 2025 10:44:27 +0800 Subject: [PATCH 1886/2333] riscv: cpufeature: Fix Zk bundled extension missing Zknh MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 8632180daf735074a746ce2b3808a8f2c079310e ] The Zk extension is a bundle consisting of Zkn, Zkr, and Zkt. The Zkn extension itself is a bundle consisting of Zbkb, Zbkc, Zbkx, Zknd, Zkne, and Zknh. The current implementation of riscv_zk_bundled_exts manually listed the dependencies but missed RISCV_ISA_EXT_ZKNH. Fix this by introducing a RISCV_ISA_EXT_ZKN macro that lists the Zkn components and using it in both riscv_zk_bundled_exts and riscv_zkn_bundled_exts. This adds the missing Zknh extension to Zk and reduces code duplication. Fixes: 0d8295ed975b ("riscv: add ISA extension parsing for scalar crypto") Link: https://patch.msgid.link/20231114141256.126749-4-cleger@rivosinc.com/ Signed-off-by: Guodong Xu Reviewed-by: Clément Léger Link: https://patch.msgid.link/20251223-zk-missing-zknh-v1-1-b627c990ee1a@riscstar.com Signed-off-by: Paul Walmsley Signed-off-by: Sasha Levin --- arch/riscv/kernel/cpufeature.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c index 72ca768f4e919..2367e9755524a 100644 --- a/arch/riscv/kernel/cpufeature.c +++ b/arch/riscv/kernel/cpufeature.c @@ -279,23 +279,22 @@ static const unsigned int riscv_a_exts[] = { RISCV_ISA_EXT_ZALRSC, }; +#define RISCV_ISA_EXT_ZKN \ + RISCV_ISA_EXT_ZBKB, \ + RISCV_ISA_EXT_ZBKC, \ + RISCV_ISA_EXT_ZBKX, \ + RISCV_ISA_EXT_ZKND, \ + RISCV_ISA_EXT_ZKNE, \ + RISCV_ISA_EXT_ZKNH + static const unsigned int riscv_zk_bundled_exts[] = { - RISCV_ISA_EXT_ZBKB, - RISCV_ISA_EXT_ZBKC, - RISCV_ISA_EXT_ZBKX, - RISCV_ISA_EXT_ZKND, - RISCV_ISA_EXT_ZKNE, + RISCV_ISA_EXT_ZKN, RISCV_ISA_EXT_ZKR, - RISCV_ISA_EXT_ZKT, + RISCV_ISA_EXT_ZKT }; static const unsigned int riscv_zkn_bundled_exts[] = { - RISCV_ISA_EXT_ZBKB, - RISCV_ISA_EXT_ZBKC, - RISCV_ISA_EXT_ZBKX, - RISCV_ISA_EXT_ZKND, - RISCV_ISA_EXT_ZKNE, - RISCV_ISA_EXT_ZKNH, + RISCV_ISA_EXT_ZKN }; static const unsigned int riscv_zks_bundled_exts[] = { From 177c71d2709f861ad95caa429e86e03978474d8d Mon Sep 17 00:00:00 2001 From: "Guo Ren (Alibaba DAMO Academy)" Date: Sun, 30 Nov 2025 19:58:50 -0500 Subject: [PATCH 1887/2333] riscv: pgtable: Cleanup useless VA_USER_XXX definitions [ Upstream commit 5e5be092ffadcab0093464ccd9e30f0c5cce16b9 ] These marcos are not used after commit b5b4287accd7 ("riscv: mm: Use hint address in mmap if available"). Cleanup VA_USER_XXX definitions in asm/pgtable.h. Fixes: b5b4287accd7 ("riscv: mm: Use hint address in mmap if available") Signed-off-by: Guo Ren (Alibaba DAMO Academy) Reviewed-by: Jinjie Ruan Link: https://patch.msgid.link/20251201005850.702569-1-guoren@kernel.org Signed-off-by: Paul Walmsley Signed-off-by: Sasha Levin --- arch/riscv/include/asm/pgtable.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/arch/riscv/include/asm/pgtable.h b/arch/riscv/include/asm/pgtable.h index 5a08eb5fe99fc..30d1ea93dde34 100644 --- a/arch/riscv/include/asm/pgtable.h +++ b/arch/riscv/include/asm/pgtable.h @@ -124,10 +124,6 @@ #ifdef CONFIG_64BIT #include -#define VA_USER_SV39 (UL(1) << (VA_BITS_SV39 - 1)) -#define VA_USER_SV48 (UL(1) << (VA_BITS_SV48 - 1)) -#define VA_USER_SV57 (UL(1) << (VA_BITS_SV57 - 1)) - #define MMAP_VA_BITS_64 ((VA_BITS >= VA_BITS_SV48) ? VA_BITS_SV48 : VA_BITS) #define MMAP_MIN_VA_BITS_64 (VA_BITS_SV39) #define MMAP_VA_BITS (is_compat_task() ? VA_BITS_SV32 : MMAP_VA_BITS_64) From c114a32a2e70b82d447f409f7ffcfa3058f9d5bd Mon Sep 17 00:00:00 2001 From: Mohammad Heib Date: Sun, 4 Jan 2026 23:31:01 +0200 Subject: [PATCH 1888/2333] net: fix memory leak in skb_segment_list for GRO packets [ Upstream commit 238e03d0466239410b72294b79494e43d4fabe77 ] When skb_segment_list() is called during packet forwarding, it handles packets that were aggregated by the GRO engine. Historically, the segmentation logic in skb_segment_list assumes that individual segments are split from a parent SKB and may need to carry their own socket memory accounting. Accordingly, the code transfers truesize from the parent to the newly created segments. Prior to commit ed4cccef64c1 ("gro: fix ownership transfer"), this truesize subtraction in skb_segment_list() was valid because fragments still carry a reference to the original socket. However, commit ed4cccef64c1 ("gro: fix ownership transfer") changed this behavior by ensuring that fraglist entries are explicitly orphaned (skb->sk = NULL) to prevent illegal orphaning later in the stack. This change meant that the entire socket memory charge remained with the head SKB, but the corresponding accounting logic in skb_segment_list() was never updated. As a result, the current code unconditionally adds each fragment's truesize to delta_truesize and subtracts it from the parent SKB. Since the fragments are no longer charged to the socket, this subtraction results in an effective under-count of memory when the head is freed. This causes sk_wmem_alloc to remain non-zero, preventing socket destruction and leading to a persistent memory leak. The leak can be observed via KMEMLEAK when tearing down the networking environment: unreferenced object 0xffff8881e6eb9100 (size 2048): comm "ping", pid 6720, jiffies 4295492526 backtrace: kmem_cache_alloc_noprof+0x5c6/0x800 sk_prot_alloc+0x5b/0x220 sk_alloc+0x35/0xa00 inet6_create.part.0+0x303/0x10d0 __sock_create+0x248/0x640 __sys_socket+0x11b/0x1d0 Since skb_segment_list() is exclusively used for SKB_GSO_FRAGLIST packets constructed by GRO, the truesize adjustment is removed. The call to skb_release_head_state() must be preserved. As documented in commit cf673ed0e057 ("net: fix fraglist segmentation reference count leak"), it is still required to correctly drop references to SKB extensions that may be overwritten during __copy_skb_header(). Fixes: ed4cccef64c1 ("gro: fix ownership transfer") Signed-off-by: Mohammad Heib Reviewed-by: Willem de Bruijn Link: https://patch.msgid.link/20260104213101.352887-1-mheib@redhat.com Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- net/core/skbuff.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 6be01454f262a..9a763d120925a 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -4597,12 +4597,14 @@ struct sk_buff *skb_segment_list(struct sk_buff *skb, { struct sk_buff *list_skb = skb_shinfo(skb)->frag_list; unsigned int tnl_hlen = skb_tnl_header_len(skb); - unsigned int delta_truesize = 0; unsigned int delta_len = 0; struct sk_buff *tail = NULL; struct sk_buff *nskb, *tmp; int len_diff, err; + /* Only skb_gro_receive_list generated skbs arrive here */ + DEBUG_NET_WARN_ON_ONCE(!(skb_shinfo(skb)->gso_type & SKB_GSO_FRAGLIST)); + skb_push(skb, -skb_network_offset(skb) + offset); /* Ensure the head is writeable before touching the shared info */ @@ -4616,8 +4618,9 @@ struct sk_buff *skb_segment_list(struct sk_buff *skb, nskb = list_skb; list_skb = list_skb->next; + DEBUG_NET_WARN_ON_ONCE(nskb->sk); + err = 0; - delta_truesize += nskb->truesize; if (skb_shared(nskb)) { tmp = skb_clone(nskb, GFP_ATOMIC); if (tmp) { @@ -4660,7 +4663,6 @@ struct sk_buff *skb_segment_list(struct sk_buff *skb, goto err_linearize; } - skb->truesize = skb->truesize - delta_truesize; skb->data_len = skb->data_len - delta_len; skb->len = skb->len - delta_len; From 309a4c2fa676af3be92c3ef742cca96872852cc3 Mon Sep 17 00:00:00 2001 From: "Mario Limonciello (AMD)" Date: Mon, 5 Jan 2026 22:46:38 -0600 Subject: [PATCH 1889/2333] PCI/VGA: Don't assume the only VGA device on a system is `boot_vga` [ Upstream commit fd390ff144513eb0310c350b1cf5fa8d6ddd0c53 ] Some systems ship with multiple display class devices but not all of them are VGA devices. If the "only" VGA device on the system is not used for displaying the image on the screen marking it as `boot_vga` because nothing was found is totally wrong. This behavior actually leads to mistakes of the wrong device being advertised to userspace and then userspace can make incorrect decisions. As there is an accurate `boot_display` sysfs file stop lying about `boot_vga` by assuming if nothing is found it's the right device. Reported-by: Aaron Erhardt Closes: https://bugzilla.kernel.org/show_bug.cgi?id=220712 Tested-by: Aaron Erhardt Acked-by: Thomas Zimmermann Fixes: ad90860bd10ee ("fbcon: Use screen info to find primary device") Tested-by: Luke D. Jones Signed-off-by: Mario Limonciello (AMD) Signed-off-by: Thomas Zimmermann Link: https://patch.msgid.link/20260106044638.52906-1-superm1@kernel.org Signed-off-by: Sasha Levin --- drivers/pci/vgaarb.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/pci/vgaarb.c b/drivers/pci/vgaarb.c index 436fa7f4c3873..baa242b140993 100644 --- a/drivers/pci/vgaarb.c +++ b/drivers/pci/vgaarb.c @@ -652,13 +652,6 @@ static bool vga_is_boot_device(struct vga_device *vgadev) return true; } - /* - * Vgadev has neither IO nor MEM enabled. If we haven't found any - * other VGA devices, it is the best candidate so far. - */ - if (!boot_vga) - return true; - return false; } From 14c4fea115361b69a9026f0c7bc46524d4ddd06a Mon Sep 17 00:00:00 2001 From: Emil Tantilov Date: Thu, 20 Nov 2025 16:12:14 -0800 Subject: [PATCH 1890/2333] idpf: keep the netdev when a reset fails [ Upstream commit 083029bd8b445595222a3cd14076b880781c1765 ] During a successful reset the driver would re-allocate vport resources while keeping the netdevs intact. However, in case of an error in the init task, the netdev of the failing vport will be unregistered, effectively removing the network interface: [ 121.211076] idpf 0000:83:00.0: enabling device (0100 -> 0102) [ 121.221976] idpf 0000:83:00.0: Device HW Reset initiated [ 124.161229] idpf 0000:83:00.0 ens801f0: renamed from eth0 [ 124.163364] idpf 0000:83:00.0 ens801f0d1: renamed from eth1 [ 125.934656] idpf 0000:83:00.0 ens801f0d2: renamed from eth2 [ 128.218429] idpf 0000:83:00.0 ens801f0d3: renamed from eth3 ip -br a ens801f0 UP ens801f0d1 UP ens801f0d2 UP ens801f0d3 UP echo 1 > /sys/class/net/ens801f0/device/reset [ 145.885537] idpf 0000:83:00.0: resetting [ 145.990280] idpf 0000:83:00.0: reset done [ 146.284766] idpf 0000:83:00.0: HW reset detected [ 146.296610] idpf 0000:83:00.0: Device HW Reset initiated [ 211.556719] idpf 0000:83:00.0: Transaction timed-out (op:526 cookie:7700 vc_op:526 salt:77 timeout:60000ms) [ 272.996705] idpf 0000:83:00.0: Transaction timed-out (op:502 cookie:7800 vc_op:502 salt:78 timeout:60000ms) ip -br a ens801f0d1 DOWN ens801f0d2 DOWN ens801f0d3 DOWN Re-shuffle the logic in the error path of the init task to make sure the netdevs remain intact. This will allow the driver to attempt recovery via subsequent resets, provided the FW is still functional. The main change is to make sure that idpf_decfg_netdev() is not called should the init task fail during a reset. The error handling is consolidated under unwind_vports, as the removed labels had the same cleanup logic split depending on the point of failure. Fixes: ce1b75d0635c ("idpf: add ptypes and MAC filter support") Signed-off-by: Emil Tantilov Reviewed-by: Aleksandr Loktionov Tested-by: Samuel Salin Signed-off-by: Tony Nguyen Signed-off-by: Sasha Levin --- drivers/net/ethernet/intel/idpf/idpf_lib.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/drivers/net/ethernet/intel/idpf/idpf_lib.c b/drivers/net/ethernet/intel/idpf/idpf_lib.c index aaafe40f5eaf7..452f3107378cb 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_lib.c +++ b/drivers/net/ethernet/intel/idpf/idpf_lib.c @@ -1579,6 +1579,10 @@ void idpf_init_task(struct work_struct *work) goto unwind_vports; } + err = idpf_send_get_rx_ptype_msg(vport); + if (err) + goto unwind_vports; + index = vport->idx; vport_config = adapter->vport_config[index]; @@ -1590,15 +1594,11 @@ void idpf_init_task(struct work_struct *work) err = idpf_check_supported_desc_ids(vport); if (err) { dev_err(&pdev->dev, "failed to get required descriptor ids\n"); - goto cfg_netdev_err; + goto unwind_vports; } if (idpf_cfg_netdev(vport)) - goto cfg_netdev_err; - - err = idpf_send_get_rx_ptype_msg(vport); - if (err) - goto handle_err; + goto unwind_vports; /* Once state is put into DOWN, driver is ready for dev_open */ np = netdev_priv(vport->netdev); @@ -1645,11 +1645,6 @@ void idpf_init_task(struct work_struct *work) return; -handle_err: - idpf_decfg_netdev(vport); -cfg_netdev_err: - idpf_vport_rel(vport); - adapter->vports[index] = NULL; unwind_vports: if (default_vport) { for (index = 0; index < adapter->max_vports; index++) { From a9f5b61591d34cc27a60878e61c929e791fb526b Mon Sep 17 00:00:00 2001 From: Emil Tantilov Date: Tue, 25 Nov 2025 14:36:24 -0800 Subject: [PATCH 1891/2333] idpf: convert vport state to bitmap [ Upstream commit 8dd72ebc73f37b216410db17340f15e6fb2cdb7b ] Convert vport state to a bitmap and remove the DOWN state which is redundant in the existing logic. There are no functional changes aside from the use of bitwise operations when setting and checking the states. Removed the double underscore to be consistent with the naming of other bitmaps in the header and renamed current_state to vport_is_up to match the meaning of the new variable. Reviewed-by: Przemek Kitszel Reviewed-by: Aleksandr Loktionov Reviewed-by: Chittim Madhu Signed-off-by: Emil Tantilov Tested-by: Samuel Salin Signed-off-by: Tony Nguyen Link: https://patch.msgid.link/20251125223632.1857532-6-anthony.l.nguyen@intel.com Signed-off-by: Jakub Kicinski Stable-dep-of: 2e281e1155fc ("idpf: detach and close netdevs while handling a reset") Signed-off-by: Sasha Levin --- drivers/net/ethernet/intel/idpf/idpf.h | 12 ++++------ .../net/ethernet/intel/idpf/idpf_ethtool.c | 12 +++++----- drivers/net/ethernet/intel/idpf/idpf_lib.c | 24 +++++++++---------- .../ethernet/intel/idpf/idpf_singleq_txrx.c | 2 +- drivers/net/ethernet/intel/idpf/idpf_txrx.c | 2 +- .../net/ethernet/intel/idpf/idpf_virtchnl.c | 4 ++-- drivers/net/ethernet/intel/idpf/xdp.c | 2 +- 7 files changed, 28 insertions(+), 30 deletions(-) diff --git a/drivers/net/ethernet/intel/idpf/idpf.h b/drivers/net/ethernet/intel/idpf/idpf.h index ca4da0c899794..64142f8163fed 100644 --- a/drivers/net/ethernet/intel/idpf/idpf.h +++ b/drivers/net/ethernet/intel/idpf/idpf.h @@ -131,14 +131,12 @@ enum idpf_cap_field { /** * enum idpf_vport_state - Current vport state - * @__IDPF_VPORT_DOWN: Vport is down - * @__IDPF_VPORT_UP: Vport is up - * @__IDPF_VPORT_STATE_LAST: Must be last, number of states + * @IDPF_VPORT_UP: Vport is up + * @IDPF_VPORT_STATE_NBITS: Must be last, number of states */ enum idpf_vport_state { - __IDPF_VPORT_DOWN, - __IDPF_VPORT_UP, - __IDPF_VPORT_STATE_LAST, + IDPF_VPORT_UP, + IDPF_VPORT_STATE_NBITS }; /** @@ -162,7 +160,7 @@ struct idpf_netdev_priv { u16 vport_idx; u16 max_tx_hdr_size; u16 tx_max_bufs; - enum idpf_vport_state state; + DECLARE_BITMAP(state, IDPF_VPORT_STATE_NBITS); struct rtnl_link_stats64 netstats; spinlock_t stats_lock; }; diff --git a/drivers/net/ethernet/intel/idpf/idpf_ethtool.c b/drivers/net/ethernet/intel/idpf/idpf_ethtool.c index a5a1eec9ade8b..eed166bc46f38 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_ethtool.c +++ b/drivers/net/ethernet/intel/idpf/idpf_ethtool.c @@ -386,7 +386,7 @@ static int idpf_get_rxfh(struct net_device *netdev, } rss_data = &adapter->vport_config[np->vport_idx]->user_config.rss_data; - if (np->state != __IDPF_VPORT_UP) + if (!test_bit(IDPF_VPORT_UP, np->state)) goto unlock_mutex; rxfh->hfunc = ETH_RSS_HASH_TOP; @@ -436,7 +436,7 @@ static int idpf_set_rxfh(struct net_device *netdev, } rss_data = &adapter->vport_config[vport->idx]->user_config.rss_data; - if (np->state != __IDPF_VPORT_UP) + if (!test_bit(IDPF_VPORT_UP, np->state)) goto unlock_mutex; if (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE && @@ -1167,7 +1167,7 @@ static void idpf_get_ethtool_stats(struct net_device *netdev, idpf_vport_ctrl_lock(netdev); vport = idpf_netdev_to_vport(netdev); - if (np->state != __IDPF_VPORT_UP) { + if (!test_bit(IDPF_VPORT_UP, np->state)) { idpf_vport_ctrl_unlock(netdev); return; @@ -1319,7 +1319,7 @@ static int idpf_get_q_coalesce(struct net_device *netdev, idpf_vport_ctrl_lock(netdev); vport = idpf_netdev_to_vport(netdev); - if (np->state != __IDPF_VPORT_UP) + if (!test_bit(IDPF_VPORT_UP, np->state)) goto unlock_mutex; if (q_num >= vport->num_rxq && q_num >= vport->num_txq) { @@ -1507,7 +1507,7 @@ static int idpf_set_coalesce(struct net_device *netdev, idpf_vport_ctrl_lock(netdev); vport = idpf_netdev_to_vport(netdev); - if (np->state != __IDPF_VPORT_UP) + if (!test_bit(IDPF_VPORT_UP, np->state)) goto unlock_mutex; for (i = 0; i < vport->num_txq; i++) { @@ -1710,7 +1710,7 @@ static void idpf_get_ts_stats(struct net_device *netdev, ts_stats->err = u64_stats_read(&vport->tstamp_stats.discarded); } while (u64_stats_fetch_retry(&vport->tstamp_stats.stats_sync, start)); - if (np->state != __IDPF_VPORT_UP) + if (!test_bit(IDPF_VPORT_UP, np->state)) goto exit; for (u16 i = 0; i < vport->num_txq_grp; i++) { diff --git a/drivers/net/ethernet/intel/idpf/idpf_lib.c b/drivers/net/ethernet/intel/idpf/idpf_lib.c index 452f3107378cb..313803c088478 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_lib.c +++ b/drivers/net/ethernet/intel/idpf/idpf_lib.c @@ -519,7 +519,7 @@ static int idpf_del_mac_filter(struct idpf_vport *vport, } spin_unlock_bh(&vport_config->mac_filter_list_lock); - if (np->state == __IDPF_VPORT_UP) { + if (test_bit(IDPF_VPORT_UP, np->state)) { int err; err = idpf_add_del_mac_filters(vport, np, false, async); @@ -590,7 +590,7 @@ static int idpf_add_mac_filter(struct idpf_vport *vport, if (err) return err; - if (np->state == __IDPF_VPORT_UP) + if (test_bit(IDPF_VPORT_UP, np->state)) err = idpf_add_del_mac_filters(vport, np, true, async); return err; @@ -894,7 +894,7 @@ static void idpf_vport_stop(struct idpf_vport *vport, bool rtnl) { struct idpf_netdev_priv *np = netdev_priv(vport->netdev); - if (np->state <= __IDPF_VPORT_DOWN) + if (!test_bit(IDPF_VPORT_UP, np->state)) return; if (rtnl) @@ -921,7 +921,7 @@ static void idpf_vport_stop(struct idpf_vport *vport, bool rtnl) idpf_xdp_rxq_info_deinit_all(vport); idpf_vport_queues_rel(vport); idpf_vport_intr_rel(vport); - np->state = __IDPF_VPORT_DOWN; + clear_bit(IDPF_VPORT_UP, np->state); if (rtnl) rtnl_unlock(); @@ -1345,7 +1345,7 @@ static int idpf_up_complete(struct idpf_vport *vport) netif_tx_start_all_queues(vport->netdev); } - np->state = __IDPF_VPORT_UP; + set_bit(IDPF_VPORT_UP, np->state); return 0; } @@ -1391,7 +1391,7 @@ static int idpf_vport_open(struct idpf_vport *vport, bool rtnl) struct idpf_vport_config *vport_config; int err; - if (np->state != __IDPF_VPORT_DOWN) + if (test_bit(IDPF_VPORT_UP, np->state)) return -EBUSY; if (rtnl) @@ -1602,7 +1602,7 @@ void idpf_init_task(struct work_struct *work) /* Once state is put into DOWN, driver is ready for dev_open */ np = netdev_priv(vport->netdev); - np->state = __IDPF_VPORT_DOWN; + clear_bit(IDPF_VPORT_UP, np->state); if (test_and_clear_bit(IDPF_VPORT_UP_REQUESTED, vport_config->flags)) idpf_vport_open(vport, true); @@ -1796,7 +1796,7 @@ static void idpf_set_vport_state(struct idpf_adapter *adapter) continue; np = netdev_priv(adapter->netdevs[i]); - if (np->state == __IDPF_VPORT_UP) + if (test_bit(IDPF_VPORT_UP, np->state)) set_bit(IDPF_VPORT_UP_REQUESTED, adapter->vport_config[i]->flags); } @@ -1934,7 +1934,7 @@ int idpf_initiate_soft_reset(struct idpf_vport *vport, enum idpf_vport_reset_cause reset_cause) { struct idpf_netdev_priv *np = netdev_priv(vport->netdev); - enum idpf_vport_state current_state = np->state; + bool vport_is_up = test_bit(IDPF_VPORT_UP, np->state); struct idpf_adapter *adapter = vport->adapter; struct idpf_vport *new_vport; int err; @@ -1985,7 +1985,7 @@ int idpf_initiate_soft_reset(struct idpf_vport *vport, goto free_vport; } - if (current_state <= __IDPF_VPORT_DOWN) { + if (!vport_is_up) { idpf_send_delete_queues_msg(vport); } else { set_bit(IDPF_VPORT_DEL_QUEUES, vport->flags); @@ -2018,7 +2018,7 @@ int idpf_initiate_soft_reset(struct idpf_vport *vport, if (err) goto err_open; - if (current_state == __IDPF_VPORT_UP) + if (vport_is_up) err = idpf_vport_open(vport, false); goto free_vport; @@ -2028,7 +2028,7 @@ int idpf_initiate_soft_reset(struct idpf_vport *vport, vport->num_rxq, vport->num_bufq); err_open: - if (current_state == __IDPF_VPORT_UP) + if (vport_is_up) idpf_vport_open(vport, false); free_vport: diff --git a/drivers/net/ethernet/intel/idpf/idpf_singleq_txrx.c b/drivers/net/ethernet/intel/idpf/idpf_singleq_txrx.c index 61e6130661404..e3ddf18dcbf51 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_singleq_txrx.c +++ b/drivers/net/ethernet/intel/idpf/idpf_singleq_txrx.c @@ -570,7 +570,7 @@ static bool idpf_tx_singleq_clean(struct idpf_tx_queue *tx_q, int napi_budget, np = netdev_priv(tx_q->netdev); nq = netdev_get_tx_queue(tx_q->netdev, tx_q->idx); - dont_wake = np->state != __IDPF_VPORT_UP || + dont_wake = !test_bit(IDPF_VPORT_UP, np->state) || !netif_carrier_ok(tx_q->netdev); __netif_txq_completed_wake(nq, ss.packets, ss.bytes, IDPF_DESC_UNUSED(tx_q), IDPF_TX_WAKE_THRESH, diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.c b/drivers/net/ethernet/intel/idpf/idpf_txrx.c index 828f7c444d309..1993a3b0da59b 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_txrx.c +++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c @@ -2275,7 +2275,7 @@ static bool idpf_tx_clean_complq(struct idpf_compl_queue *complq, int budget, /* Update BQL */ nq = netdev_get_tx_queue(tx_q->netdev, tx_q->idx); - dont_wake = !complq_ok || np->state != __IDPF_VPORT_UP || + dont_wake = !complq_ok || !test_bit(IDPF_VPORT_UP, np->state) || !netif_carrier_ok(tx_q->netdev); /* Check if the TXQ needs to and can be restarted */ __netif_txq_completed_wake(nq, tx_q->cleaned_pkts, tx_q->cleaned_bytes, diff --git a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c index fc03d55bc9b90..5bbe7d9294c14 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c +++ b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c @@ -68,7 +68,7 @@ static void idpf_handle_event_link(struct idpf_adapter *adapter, vport->link_up = v2e->link_status; - if (np->state != __IDPF_VPORT_UP) + if (!test_bit(IDPF_VPORT_UP, np->state)) return; if (vport->link_up) { @@ -2760,7 +2760,7 @@ int idpf_send_get_stats_msg(struct idpf_vport *vport) /* Don't send get_stats message if the link is down */ - if (np->state <= __IDPF_VPORT_DOWN) + if (!test_bit(IDPF_VPORT_UP, np->state)) return 0; stats_msg.vport_id = cpu_to_le32(vport->vport_id); diff --git a/drivers/net/ethernet/intel/idpf/xdp.c b/drivers/net/ethernet/intel/idpf/xdp.c index 21ce25b0567f6..958d16f874248 100644 --- a/drivers/net/ethernet/intel/idpf/xdp.c +++ b/drivers/net/ethernet/intel/idpf/xdp.c @@ -418,7 +418,7 @@ static int idpf_xdp_setup_prog(struct idpf_vport *vport, if (test_bit(IDPF_REMOVE_IN_PROG, vport->adapter->flags) || !test_bit(IDPF_VPORT_REG_NETDEV, cfg->flags) || !!vport->xdp_prog == !!prog) { - if (np->state == __IDPF_VPORT_UP) + if (test_bit(IDPF_VPORT_UP, np->state)) idpf_xdp_copy_prog_to_rqs(vport, prog); old = xchg(&vport->xdp_prog, prog); From ac122f5fb050903b3d262001562c452be95eaf70 Mon Sep 17 00:00:00 2001 From: Emil Tantilov Date: Thu, 20 Nov 2025 16:12:15 -0800 Subject: [PATCH 1892/2333] idpf: detach and close netdevs while handling a reset [ Upstream commit 2e281e1155fc476c571c0bd2ffbfe28ab829a5c3 ] Protect the reset path from callbacks by setting the netdevs to detached state and close any netdevs in UP state until the reset handling has completed. During a reset, the driver will de-allocate resources for the vport, and there is no guarantee that those will recover, which is why the existing vport_ctrl_lock does not provide sufficient protection. idpf_detach_and_close() is called right before reset handling. If the reset handling succeeds, the netdevs state is recovered via call to idpf_attach_and_open(). If the reset handling fails the netdevs remain down. The detach/down calls are protected with RTNL lock to avoid racing with callbacks. On the recovery side the attach can be done without holding the RTNL lock as there are no callbacks expected at that point, due to detach/close always being done first in that flow. The previous logic restoring the netdevs state based on the IDPF_VPORT_UP_REQUESTED flag in the init task is not needed anymore, hence the removal of idpf_set_vport_state(). The IDPF_VPORT_UP_REQUESTED is still being used to restore the state of the netdevs following the reset, but has no use outside of the reset handling flow. idpf_init_hard_reset() is converted to void, since it was used as such and there is no error handling being done based on its return value. Before this change, invoking hard and soft resets simultaneously will cause the driver to lose the vport state: ip -br a UP echo 1 > /sys/class/net/ens801f0/device/reset& \ ethtool -L ens801f0 combined 8 ip -br a DOWN ip link set up ip -br a DOWN Also in case of a failure in the reset path, the netdev is left exposed to external callbacks, while vport resources are not initialized, leading to a crash on subsequent ifup/down: [408471.398966] idpf 0000:83:00.0: HW reset detected [408471.411744] idpf 0000:83:00.0: Device HW Reset initiated [408472.277901] idpf 0000:83:00.0: The driver was unable to contact the device's firmware. Check that the FW is running. Driver state= 0x2 [408508.125551] BUG: kernel NULL pointer dereference, address: 0000000000000078 [408508.126112] #PF: supervisor read access in kernel mode [408508.126687] #PF: error_code(0x0000) - not-present page [408508.127256] PGD 2aae2f067 P4D 0 [408508.127824] Oops: Oops: 0000 [#1] SMP NOPTI ... [408508.130871] RIP: 0010:idpf_stop+0x39/0x70 [idpf] ... [408508.139193] Call Trace: [408508.139637] [408508.140077] __dev_close_many+0xbb/0x260 [408508.140533] __dev_change_flags+0x1cf/0x280 [408508.140987] netif_change_flags+0x26/0x70 [408508.141434] dev_change_flags+0x3d/0xb0 [408508.141878] devinet_ioctl+0x460/0x890 [408508.142321] inet_ioctl+0x18e/0x1d0 [408508.142762] ? _copy_to_user+0x22/0x70 [408508.143207] sock_do_ioctl+0x3d/0xe0 [408508.143652] sock_ioctl+0x10e/0x330 [408508.144091] ? find_held_lock+0x2b/0x80 [408508.144537] __x64_sys_ioctl+0x96/0xe0 [408508.144979] do_syscall_64+0x79/0x3d0 [408508.145415] entry_SYSCALL_64_after_hwframe+0x76/0x7e [408508.145860] RIP: 0033:0x7f3e0bb4caff Fixes: 0fe45467a104 ("idpf: add create vport and netdev configuration") Signed-off-by: Emil Tantilov Reviewed-by: Madhu Chittim Tested-by: Samuel Salin Signed-off-by: Tony Nguyen Signed-off-by: Sasha Levin --- drivers/net/ethernet/intel/idpf/idpf_lib.c | 121 ++++++++++++--------- 1 file changed, 72 insertions(+), 49 deletions(-) diff --git a/drivers/net/ethernet/intel/idpf/idpf_lib.c b/drivers/net/ethernet/intel/idpf/idpf_lib.c index 313803c088478..a964e0f5891eb 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_lib.c +++ b/drivers/net/ethernet/intel/idpf/idpf_lib.c @@ -729,6 +729,65 @@ static int idpf_init_mac_addr(struct idpf_vport *vport, return 0; } +static void idpf_detach_and_close(struct idpf_adapter *adapter) +{ + int max_vports = adapter->max_vports; + + for (int i = 0; i < max_vports; i++) { + struct net_device *netdev = adapter->netdevs[i]; + + /* If the interface is in detached state, that means the + * previous reset was not handled successfully for this + * vport. + */ + if (!netif_device_present(netdev)) + continue; + + /* Hold RTNL to protect racing with callbacks */ + rtnl_lock(); + netif_device_detach(netdev); + if (netif_running(netdev)) { + set_bit(IDPF_VPORT_UP_REQUESTED, + adapter->vport_config[i]->flags); + dev_close(netdev); + } + rtnl_unlock(); + } +} + +static void idpf_attach_and_open(struct idpf_adapter *adapter) +{ + int max_vports = adapter->max_vports; + + for (int i = 0; i < max_vports; i++) { + struct idpf_vport *vport = adapter->vports[i]; + struct idpf_vport_config *vport_config; + struct net_device *netdev; + + /* In case of a critical error in the init task, the vport + * will be freed. Only continue to restore the netdevs + * if the vport is allocated. + */ + if (!vport) + continue; + + /* No need for RTNL on attach as this function is called + * following detach and dev_close(). We do take RTNL for + * dev_open() below as it can race with external callbacks + * following the call to netif_device_attach(). + */ + netdev = adapter->netdevs[i]; + netif_device_attach(netdev); + vport_config = adapter->vport_config[vport->idx]; + if (test_and_clear_bit(IDPF_VPORT_UP_REQUESTED, + vport_config->flags)) { + rtnl_lock(); + dev_open(netdev, NULL); + rtnl_unlock(); + } + } +} + /** * idpf_cfg_netdev - Allocate, configure and register a netdev * @vport: main vport structure @@ -1041,10 +1100,11 @@ static void idpf_vport_dealloc(struct idpf_vport *vport) idpf_idc_deinit_vport_aux_device(vport->vdev_info); idpf_deinit_mac_addr(vport); - idpf_vport_stop(vport, true); - if (!test_bit(IDPF_HR_RESET_IN_PROG, adapter->flags)) + if (!test_bit(IDPF_HR_RESET_IN_PROG, adapter->flags)) { + idpf_vport_stop(vport, true); idpf_decfg_netdev(vport); + } if (test_bit(IDPF_REMOVE_IN_PROG, adapter->flags)) idpf_del_all_mac_filters(vport); @@ -1544,7 +1604,6 @@ void idpf_init_task(struct work_struct *work) struct idpf_vport_config *vport_config; struct idpf_vport_max_q max_q; struct idpf_adapter *adapter; - struct idpf_netdev_priv *np; struct idpf_vport *vport; u16 num_default_vports; struct pci_dev *pdev; @@ -1600,12 +1659,6 @@ void idpf_init_task(struct work_struct *work) if (idpf_cfg_netdev(vport)) goto unwind_vports; - /* Once state is put into DOWN, driver is ready for dev_open */ - np = netdev_priv(vport->netdev); - clear_bit(IDPF_VPORT_UP, np->state); - if (test_and_clear_bit(IDPF_VPORT_UP_REQUESTED, vport_config->flags)) - idpf_vport_open(vport, true); - /* Spawn and return 'idpf_init_task' work queue until all the * default vports are created */ @@ -1781,27 +1834,6 @@ static int idpf_check_reset_complete(struct idpf_hw *hw, return -EBUSY; } -/** - * idpf_set_vport_state - Set the vport state to be after the reset - * @adapter: Driver specific private structure - */ -static void idpf_set_vport_state(struct idpf_adapter *adapter) -{ - u16 i; - - for (i = 0; i < adapter->max_vports; i++) { - struct idpf_netdev_priv *np; - - if (!adapter->netdevs[i]) - continue; - - np = netdev_priv(adapter->netdevs[i]); - if (test_bit(IDPF_VPORT_UP, np->state)) - set_bit(IDPF_VPORT_UP_REQUESTED, - adapter->vport_config[i]->flags); - } -} - /** * idpf_init_hard_reset - Initiate a hardware reset * @adapter: Driver specific private structure @@ -1810,28 +1842,17 @@ static void idpf_set_vport_state(struct idpf_adapter *adapter) * reallocate. Also reinitialize the mailbox. Return 0 on success, * negative on failure. */ -static int idpf_init_hard_reset(struct idpf_adapter *adapter) +static void idpf_init_hard_reset(struct idpf_adapter *adapter) { struct idpf_reg_ops *reg_ops = &adapter->dev_ops.reg_ops; struct device *dev = &adapter->pdev->dev; - struct net_device *netdev; int err; - u16 i; + idpf_detach_and_close(adapter); mutex_lock(&adapter->vport_ctrl_lock); dev_info(dev, "Device HW Reset initiated\n"); - /* Avoid TX hangs on reset */ - for (i = 0; i < adapter->max_vports; i++) { - netdev = adapter->netdevs[i]; - if (!netdev) - continue; - - netif_carrier_off(netdev); - netif_tx_disable(netdev); - } - /* Prepare for reset */ if (test_and_clear_bit(IDPF_HR_DRV_LOAD, adapter->flags)) { reg_ops->trigger_reset(adapter, IDPF_HR_DRV_LOAD); @@ -1840,7 +1861,6 @@ static int idpf_init_hard_reset(struct idpf_adapter *adapter) idpf_idc_issue_reset_event(adapter->cdev_info); - idpf_set_vport_state(adapter); idpf_vc_core_deinit(adapter); if (!is_reset) reg_ops->trigger_reset(adapter, IDPF_HR_FUNC_RESET); @@ -1887,11 +1907,14 @@ static int idpf_init_hard_reset(struct idpf_adapter *adapter) unlock_mutex: mutex_unlock(&adapter->vport_ctrl_lock); - /* Wait until all vports are created to init RDMA CORE AUX */ - if (!err) - err = idpf_idc_init(adapter); - - return err; + /* Attempt to restore netdevs and initialize RDMA CORE AUX device, + * provided vc_core_init succeeded. It is still possible that + * vports are not allocated at this point if the init task failed. + */ + if (!err) { + idpf_attach_and_open(adapter); + idpf_idc_init(adapter); + } } /** From ec602a2a4071eb956d656ba968c58fee09f0622d Mon Sep 17 00:00:00 2001 From: Emil Tantilov Date: Thu, 20 Nov 2025 16:12:16 -0800 Subject: [PATCH 1893/2333] idpf: fix memory leak in idpf_vport_rel() [ Upstream commit f6242b354605faff263ca45882b148200915a3f6 ] Free vport->rx_ptype_lkup in idpf_vport_rel() to avoid leaking memory during a reset. Reported by kmemleak: unreferenced object 0xff450acac838a000 (size 4096): comm "kworker/u258:5", pid 7732, jiffies 4296830044 hex dump (first 32 bytes): 00 00 00 00 00 10 00 00 00 10 00 00 00 00 00 00 ................ 00 00 00 00 00 00 00 00 00 10 00 00 00 00 00 00 ................ backtrace (crc 3da81902): __kmalloc_cache_noprof+0x469/0x7a0 idpf_send_get_rx_ptype_msg+0x90/0x570 [idpf] idpf_init_task+0x1ec/0x8d0 [idpf] process_one_work+0x226/0x6d0 worker_thread+0x19e/0x340 kthread+0x10f/0x250 ret_from_fork+0x251/0x2b0 ret_from_fork_asm+0x1a/0x30 Fixes: 0fe45467a104 ("idpf: add create vport and netdev configuration") Signed-off-by: Emil Tantilov Reviewed-by: Aleksandr Loktionov Reviewed-by: Madhu Chittim Tested-by: Samuel Salin Signed-off-by: Tony Nguyen Signed-off-by: Sasha Levin --- drivers/net/ethernet/intel/idpf/idpf_lib.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/ethernet/intel/idpf/idpf_lib.c b/drivers/net/ethernet/intel/idpf/idpf_lib.c index a964e0f5891eb..04af10cfaa8cb 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_lib.c +++ b/drivers/net/ethernet/intel/idpf/idpf_lib.c @@ -1082,6 +1082,8 @@ static void idpf_vport_rel(struct idpf_vport *vport) kfree(adapter->vport_config[idx]->req_qs_chunks); adapter->vport_config[idx]->req_qs_chunks = NULL; } + kfree(vport->rx_ptype_lkup); + vport->rx_ptype_lkup = NULL; kfree(vport); adapter->num_alloc_vports--; } From 23391db8a00c23854915b8b72ec1aa10080aa540 Mon Sep 17 00:00:00 2001 From: Emil Tantilov Date: Thu, 20 Nov 2025 16:12:17 -0800 Subject: [PATCH 1894/2333] idpf: fix memory leak in idpf_vc_core_deinit() [ Upstream commit e111cbc4adf9f9974eed040aeece7e17460f6bff ] Make sure to free hw->lan_regs. Reported by kmemleak during reset: unreferenced object 0xff1b913d02a936c0 (size 96): comm "kworker/u258:14", pid 2174, jiffies 4294958305 hex dump (first 32 bytes): 00 00 00 c0 a8 ba 2d ff 00 00 00 00 00 00 00 00 ......-......... 00 00 40 08 00 00 00 00 00 00 25 b3 a8 ba 2d ff ..@.......%...-. backtrace (crc 36063c4f): __kmalloc_noprof+0x48f/0x890 idpf_vc_core_init+0x6ce/0x9b0 [idpf] idpf_vc_event_task+0x1fb/0x350 [idpf] process_one_work+0x226/0x6d0 worker_thread+0x19e/0x340 kthread+0x10f/0x250 ret_from_fork+0x251/0x2b0 ret_from_fork_asm+0x1a/0x30 Fixes: 6aa53e861c1a ("idpf: implement get LAN MMIO memory regions") Signed-off-by: Emil Tantilov Reviewed-by: Aleksandr Loktionov Reviewed-by: Joshua Hay Tested-by: Samuel Salin Signed-off-by: Tony Nguyen Signed-off-by: Sasha Levin --- drivers/net/ethernet/intel/idpf/idpf_virtchnl.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c index 5bbe7d9294c14..01bbd12a642a0 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c +++ b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c @@ -3570,6 +3570,7 @@ int idpf_vc_core_init(struct idpf_adapter *adapter) */ void idpf_vc_core_deinit(struct idpf_adapter *adapter) { + struct idpf_hw *hw = &adapter->hw; bool remove_in_prog; if (!test_bit(IDPF_VC_CORE_INIT, adapter->flags)) @@ -3593,6 +3594,9 @@ void idpf_vc_core_deinit(struct idpf_adapter *adapter) idpf_vport_params_buf_rel(adapter); + kfree(hw->lan_regs); + hw->lan_regs = NULL; + kfree(adapter->vports); adapter->vports = NULL; From a514c374edcd33581cdcccf8faa7cc606a600319 Mon Sep 17 00:00:00 2001 From: Emil Tantilov Date: Thu, 20 Nov 2025 16:12:18 -0800 Subject: [PATCH 1895/2333] idpf: fix error handling in the init_task on load [ Upstream commit 4d792219fe6f891b5b557a607ac8a0a14eda6e38 ] If the init_task fails during a driver load, we end up without vports and netdevs, effectively failing the entire process. In that state a subsequent reset will result in a crash as the service task attempts to access uninitialized resources. Following trace is from an error in the init_task where the CREATE_VPORT (op 501) is rejected by the FW: [40922.763136] idpf 0000:83:00.0: Device HW Reset initiated [40924.449797] idpf 0000:83:00.0: Transaction failed (op 501) [40958.148190] idpf 0000:83:00.0: HW reset detected [40958.161202] BUG: kernel NULL pointer dereference, address: 00000000000000a8 ... [40958.168094] Workqueue: idpf-0000:83:00.0-vc_event idpf_vc_event_task [idpf] [40958.168865] RIP: 0010:idpf_vc_event_task+0x9b/0x350 [idpf] ... [40958.177932] Call Trace: [40958.178491] [40958.179040] process_one_work+0x226/0x6d0 [40958.179609] worker_thread+0x19e/0x340 [40958.180158] ? __pfx_worker_thread+0x10/0x10 [40958.180702] kthread+0x10f/0x250 [40958.181238] ? __pfx_kthread+0x10/0x10 [40958.181774] ret_from_fork+0x251/0x2b0 [40958.182307] ? __pfx_kthread+0x10/0x10 [40958.182834] ret_from_fork_asm+0x1a/0x30 [40958.183370] Fix the error handling in the init_task to make sure the service and mailbox tasks are disabled if the error happens during load. These are started in idpf_vc_core_init(), which spawns the init_task and has no way of knowing if it failed. If the error happens on reset, following successful driver load, the tasks can still run, as that will allow the netdevs to attempt recovery through another reset. Stop the PTP callbacks either way as those will be restarted by the call to idpf_vc_core_init() during a successful reset. Fixes: 0fe45467a104 ("idpf: add create vport and netdev configuration") Reported-by: Vivek Kumar Signed-off-by: Emil Tantilov Reviewed-by: Madhu Chittim Tested-by: Samuel Salin Signed-off-by: Tony Nguyen Signed-off-by: Sasha Levin --- drivers/net/ethernet/intel/idpf/idpf_lib.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/intel/idpf/idpf_lib.c b/drivers/net/ethernet/intel/idpf/idpf_lib.c index 04af10cfaa8cb..e2ee8b137421f 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_lib.c +++ b/drivers/net/ethernet/intel/idpf/idpf_lib.c @@ -1690,10 +1690,9 @@ void idpf_init_task(struct work_struct *work) set_bit(IDPF_VPORT_REG_NETDEV, vport_config->flags); } - /* As all the required vports are created, clear the reset flag - * unconditionally here in case we were in reset and the link was down. - */ + /* Clear the reset and load bits as all vports are created */ clear_bit(IDPF_HR_RESET_IN_PROG, adapter->flags); + clear_bit(IDPF_HR_DRV_LOAD, adapter->flags); /* Start the statistics task now */ queue_delayed_work(adapter->stats_wq, &adapter->stats_task, msecs_to_jiffies(10 * (pdev->devfn & 0x07))); @@ -1707,6 +1706,15 @@ void idpf_init_task(struct work_struct *work) idpf_vport_dealloc(adapter->vports[index]); } } + /* Cleanup after vc_core_init, which has no way of knowing the + * init task failed on driver load. + */ + if (test_and_clear_bit(IDPF_HR_DRV_LOAD, adapter->flags)) { + cancel_delayed_work_sync(&adapter->serv_task); + cancel_delayed_work_sync(&adapter->mbx_task); + } + idpf_ptp_release(adapter); + clear_bit(IDPF_HR_RESET_IN_PROG, adapter->flags); } @@ -1856,7 +1864,7 @@ static void idpf_init_hard_reset(struct idpf_adapter *adapter) dev_info(dev, "Device HW Reset initiated\n"); /* Prepare for reset */ - if (test_and_clear_bit(IDPF_HR_DRV_LOAD, adapter->flags)) { + if (test_bit(IDPF_HR_DRV_LOAD, adapter->flags)) { reg_ops->trigger_reset(adapter, IDPF_HR_DRV_LOAD); } else if (test_and_clear_bit(IDPF_HR_FUNC_RESET, adapter->flags)) { bool is_reset = idpf_is_reset_detected(adapter); From 1aedff70a5e97628eaaf17b169774cb6a45a1dc5 Mon Sep 17 00:00:00 2001 From: Sreedevi Joshi Date: Tue, 30 Sep 2025 16:23:51 -0500 Subject: [PATCH 1896/2333] idpf: fix memory leak of flow steer list on rmmod [ Upstream commit f9841bd28b600526ca4f6713b0ca49bf7bb98452 ] The flow steering list maintains entries that are added and removed as ethtool creates and deletes flow steering rules. Module removal with active entries causes memory leak as the list is not properly cleaned up. Prevent this by iterating through the remaining entries in the list and freeing the associated memory during module removal. Add a spinlock (flow_steer_list_lock) to protect the list access from multiple threads. Fixes: ada3e24b84a0 ("idpf: add flow steering support") Reviewed-by: Przemek Kitszel Reviewed-by: Aleksandr Loktionov Signed-off-by: Sreedevi Joshi Reviewed-by: Simon Horman Tested-by: Mina Almasry Signed-off-by: Tony Nguyen Signed-off-by: Sasha Levin --- drivers/net/ethernet/intel/idpf/idpf.h | 2 ++ .../net/ethernet/intel/idpf/idpf_ethtool.c | 15 ++++++++-- drivers/net/ethernet/intel/idpf/idpf_lib.c | 28 ++++++++++++++++++- 3 files changed, 42 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/intel/idpf/idpf.h b/drivers/net/ethernet/intel/idpf/idpf.h index 64142f8163fed..af8deb5fa80f0 100644 --- a/drivers/net/ethernet/intel/idpf/idpf.h +++ b/drivers/net/ethernet/intel/idpf/idpf.h @@ -558,6 +558,7 @@ struct idpf_vector_lifo { * @max_q: Maximum possible queues * @req_qs_chunks: Queue chunk data for requested queues * @mac_filter_list_lock: Lock to protect mac filters + * @flow_steer_list_lock: Lock to protect fsteer filters * @flags: See enum idpf_vport_config_flags */ struct idpf_vport_config { @@ -565,6 +566,7 @@ struct idpf_vport_config { struct idpf_vport_max_q max_q; struct virtchnl2_add_queues *req_qs_chunks; spinlock_t mac_filter_list_lock; + spinlock_t flow_steer_list_lock; DECLARE_BITMAP(flags, IDPF_VPORT_CONFIG_FLAGS_NBITS); }; diff --git a/drivers/net/ethernet/intel/idpf/idpf_ethtool.c b/drivers/net/ethernet/intel/idpf/idpf_ethtool.c index eed166bc46f38..8477e7ba28706 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_ethtool.c +++ b/drivers/net/ethernet/intel/idpf/idpf_ethtool.c @@ -18,6 +18,7 @@ static int idpf_get_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd, { struct idpf_netdev_priv *np = netdev_priv(netdev); struct idpf_vport_user_config_data *user_config; + struct idpf_vport_config *vport_config; struct idpf_fsteer_fltr *f; struct idpf_vport *vport; unsigned int cnt = 0; @@ -25,7 +26,8 @@ static int idpf_get_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd, idpf_vport_ctrl_lock(netdev); vport = idpf_netdev_to_vport(netdev); - user_config = &np->adapter->vport_config[np->vport_idx]->user_config; + vport_config = np->adapter->vport_config[np->vport_idx]; + user_config = &vport_config->user_config; switch (cmd->cmd) { case ETHTOOL_GRXRINGS: @@ -37,15 +39,18 @@ static int idpf_get_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd, break; case ETHTOOL_GRXCLSRULE: err = -EINVAL; + spin_lock_bh(&vport_config->flow_steer_list_lock); list_for_each_entry(f, &user_config->flow_steer_list, list) if (f->loc == cmd->fs.location) { cmd->fs.ring_cookie = f->q_index; err = 0; break; } + spin_unlock_bh(&vport_config->flow_steer_list_lock); break; case ETHTOOL_GRXCLSRLALL: cmd->data = idpf_fsteer_max_rules(vport); + spin_lock_bh(&vport_config->flow_steer_list_lock); list_for_each_entry(f, &user_config->flow_steer_list, list) { if (cnt == cmd->rule_cnt) { err = -EMSGSIZE; @@ -56,6 +61,7 @@ static int idpf_get_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd, } if (!err) cmd->rule_cnt = user_config->num_fsteer_fltrs; + spin_unlock_bh(&vport_config->flow_steer_list_lock); break; default: break; @@ -224,6 +230,7 @@ static int idpf_add_flow_steer(struct net_device *netdev, fltr->loc = fsp->location; fltr->q_index = q_index; + spin_lock_bh(&vport_config->flow_steer_list_lock); list_for_each_entry(f, &user_config->flow_steer_list, list) { if (f->loc >= fltr->loc) break; @@ -234,6 +241,7 @@ static int idpf_add_flow_steer(struct net_device *netdev, list_add(&fltr->list, &user_config->flow_steer_list); user_config->num_fsteer_fltrs++; + spin_unlock_bh(&vport_config->flow_steer_list_lock); out: kfree(rule); @@ -286,17 +294,20 @@ static int idpf_del_flow_steer(struct net_device *netdev, goto out; } + spin_lock_bh(&vport_config->flow_steer_list_lock); list_for_each_entry_safe(f, iter, &user_config->flow_steer_list, list) { if (f->loc == fsp->location) { list_del(&f->list); kfree(f); user_config->num_fsteer_fltrs--; - goto out; + goto out_unlock; } } err = -EINVAL; +out_unlock: + spin_unlock_bh(&vport_config->flow_steer_list_lock); out: kfree(rule); return err; diff --git a/drivers/net/ethernet/intel/idpf/idpf_lib.c b/drivers/net/ethernet/intel/idpf/idpf_lib.c index e2ee8b137421f..d56366e676cf7 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_lib.c +++ b/drivers/net/ethernet/intel/idpf/idpf_lib.c @@ -442,6 +442,29 @@ int idpf_intr_req(struct idpf_adapter *adapter) return err; } +/** + * idpf_del_all_flow_steer_filters - Delete all flow steer filters in list + * @vport: main vport struct + * + * Takes flow_steer_list_lock spinlock. Deletes all filters + */ +static void idpf_del_all_flow_steer_filters(struct idpf_vport *vport) +{ + struct idpf_vport_config *vport_config; + struct idpf_fsteer_fltr *f, *ftmp; + + vport_config = vport->adapter->vport_config[vport->idx]; + + spin_lock_bh(&vport_config->flow_steer_list_lock); + list_for_each_entry_safe(f, ftmp, &vport_config->user_config.flow_steer_list, + list) { + list_del(&f->list); + kfree(f); + } + vport_config->user_config.num_fsteer_fltrs = 0; + spin_unlock_bh(&vport_config->flow_steer_list_lock); +} + /** * idpf_find_mac_filter - Search filter list for specific mac filter * @vconfig: Vport config structure @@ -1107,8 +1130,10 @@ static void idpf_vport_dealloc(struct idpf_vport *vport) idpf_vport_stop(vport, true); idpf_decfg_netdev(vport); } - if (test_bit(IDPF_REMOVE_IN_PROG, adapter->flags)) + if (test_bit(IDPF_REMOVE_IN_PROG, adapter->flags)) { idpf_del_all_mac_filters(vport); + idpf_del_all_flow_steer_filters(vport); + } if (adapter->netdevs[i]) { struct idpf_netdev_priv *np = netdev_priv(adapter->netdevs[i]); @@ -1648,6 +1673,7 @@ void idpf_init_task(struct work_struct *work) vport_config = adapter->vport_config[index]; spin_lock_init(&vport_config->mac_filter_list_lock); + spin_lock_init(&vport_config->flow_steer_list_lock); INIT_LIST_HEAD(&vport_config->user_config.mac_filter_list); INIT_LIST_HEAD(&vport_config->user_config.flow_steer_list); From fe33b4252e4bf9c1af1dcdb2fdce5457d5eb6f3a Mon Sep 17 00:00:00 2001 From: Erik Gabriel Carrillo Date: Tue, 30 Sep 2025 16:23:52 -0500 Subject: [PATCH 1897/2333] idpf: fix issue with ethtool -n command display [ Upstream commit 36aae2ea6bd76b8246caa50e34a4f4824f0a3be8 ] When ethtool -n is executed on an interface to display the flow steering rules, "rxclass: Unknown flow type" error is generated. The flow steering list maintained in the driver currently stores only the location and q_index but other fields of the ethtool_rx_flow_spec are not stored. This may be enough for the virtchnl command to delete the entry. However, when the ethtool -n command is used to query the flow steering rules, the ethtool_rx_flow_spec returned is not complete causing the error below. Resolve this by storing the flow spec (fsp) when rules are added and returning the complete flow spec when rules are queried. Also, change the return value from EINVAL to ENOENT when flow steering entry is not found during query by location or when deleting an entry. Add logic to detect and reject duplicate filter entries at the same location and change logic to perform upfront validation of all error conditions before adding flow rules through virtchnl. This avoids the need for additional virtchnl delete messages when subsequent operations fail, which was missing in the original upstream code. Example: Before the fix: ethtool -n eth1 2 RX rings available Total 2 rules rxclass: Unknown flow type rxclass: Unknown flow type After the fix: ethtool -n eth1 2 RX rings available Total 2 rules Filter: 0 Rule Type: TCP over IPv4 Src IP addr: 10.0.0.1 mask: 0.0.0.0 Dest IP addr: 0.0.0.0 mask: 255.255.255.255 TOS: 0x0 mask: 0xff Src port: 0 mask: 0xffff Dest port: 0 mask: 0xffff Action: Direct to queue 0 Filter: 1 Rule Type: UDP over IPv4 Src IP addr: 10.0.0.1 mask: 0.0.0.0 Dest IP addr: 0.0.0.0 mask: 255.255.255.255 TOS: 0x0 mask: 0xff Src port: 0 mask: 0xffff Dest port: 0 mask: 0xffff Action: Direct to queue 0 Fixes: ada3e24b84a0 ("idpf: add flow steering support") Signed-off-by: Erik Gabriel Carrillo Co-developed-by: Sreedevi Joshi Signed-off-by: Sreedevi Joshi Reviewed-by: Przemek Kitszel Reviewed-by: Aleksandr Loktionov Reviewed-by: Simon Horman Tested-by: Mina Almasry Signed-off-by: Tony Nguyen Signed-off-by: Sasha Levin --- drivers/net/ethernet/intel/idpf/idpf.h | 3 +- .../net/ethernet/intel/idpf/idpf_ethtool.c | 59 ++++++++++++------- 2 files changed, 40 insertions(+), 22 deletions(-) diff --git a/drivers/net/ethernet/intel/idpf/idpf.h b/drivers/net/ethernet/intel/idpf/idpf.h index af8deb5fa80f0..df64d252b5642 100644 --- a/drivers/net/ethernet/intel/idpf/idpf.h +++ b/drivers/net/ethernet/intel/idpf/idpf.h @@ -284,8 +284,7 @@ struct idpf_port_stats { struct idpf_fsteer_fltr { struct list_head list; - u32 loc; - u32 q_index; + struct ethtool_rx_flow_spec fs; }; /** diff --git a/drivers/net/ethernet/intel/idpf/idpf_ethtool.c b/drivers/net/ethernet/intel/idpf/idpf_ethtool.c index 8477e7ba28706..8e9a93125b4aa 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_ethtool.c +++ b/drivers/net/ethernet/intel/idpf/idpf_ethtool.c @@ -38,11 +38,15 @@ static int idpf_get_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd, cmd->data = idpf_fsteer_max_rules(vport); break; case ETHTOOL_GRXCLSRULE: - err = -EINVAL; + err = -ENOENT; spin_lock_bh(&vport_config->flow_steer_list_lock); list_for_each_entry(f, &user_config->flow_steer_list, list) - if (f->loc == cmd->fs.location) { - cmd->fs.ring_cookie = f->q_index; + if (f->fs.location == cmd->fs.location) { + /* Avoid infoleak from padding: zero first, + * then assign fields + */ + memset(&cmd->fs, 0, sizeof(cmd->fs)); + cmd->fs = f->fs; err = 0; break; } @@ -56,7 +60,7 @@ static int idpf_get_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd, err = -EMSGSIZE; break; } - rule_locs[cnt] = f->loc; + rule_locs[cnt] = f->fs.location; cnt++; } if (!err) @@ -158,7 +162,7 @@ static int idpf_add_flow_steer(struct net_device *netdev, struct idpf_vport *vport; u32 flow_type, q_index; u16 num_rxq; - int err; + int err = 0; vport = idpf_netdev_to_vport(netdev); vport_config = vport->adapter->vport_config[np->vport_idx]; @@ -184,6 +188,29 @@ static int idpf_add_flow_steer(struct net_device *netdev, if (!rule) return -ENOMEM; + fltr = kzalloc(sizeof(*fltr), GFP_KERNEL); + if (!fltr) { + err = -ENOMEM; + goto out_free_rule; + } + + /* detect duplicate entry and reject before adding rules */ + spin_lock_bh(&vport_config->flow_steer_list_lock); + list_for_each_entry(f, &user_config->flow_steer_list, list) { + if (f->fs.location == fsp->location) { + err = -EEXIST; + break; + } + + if (f->fs.location > fsp->location) + break; + parent = f; + } + spin_unlock_bh(&vport_config->flow_steer_list_lock); + + if (err) + goto out; + rule->vport_id = cpu_to_le32(vport->vport_id); rule->count = cpu_to_le32(1); info = &rule->rule_info[0]; @@ -222,28 +249,20 @@ static int idpf_add_flow_steer(struct net_device *netdev, goto out; } - fltr = kzalloc(sizeof(*fltr), GFP_KERNEL); - if (!fltr) { - err = -ENOMEM; - goto out; - } + /* Save a copy of the user's flow spec so ethtool can later retrieve it */ + fltr->fs = *fsp; - fltr->loc = fsp->location; - fltr->q_index = q_index; spin_lock_bh(&vport_config->flow_steer_list_lock); - list_for_each_entry(f, &user_config->flow_steer_list, list) { - if (f->loc >= fltr->loc) - break; - parent = f; - } - parent ? list_add(&fltr->list, &parent->list) : list_add(&fltr->list, &user_config->flow_steer_list); user_config->num_fsteer_fltrs++; spin_unlock_bh(&vport_config->flow_steer_list_lock); + goto out_free_rule; out: + kfree(fltr); +out_free_rule: kfree(rule); return err; } @@ -297,14 +316,14 @@ static int idpf_del_flow_steer(struct net_device *netdev, spin_lock_bh(&vport_config->flow_steer_list_lock); list_for_each_entry_safe(f, iter, &user_config->flow_steer_list, list) { - if (f->loc == fsp->location) { + if (f->fs.location == fsp->location) { list_del(&f->list); kfree(f); user_config->num_fsteer_fltrs--; goto out_unlock; } } - err = -EINVAL; + err = -ENOENT; out_unlock: spin_unlock_bh(&vport_config->flow_steer_list_lock); From b29a5a7dd1f4293ee49c469938c25bf85a5aa802 Mon Sep 17 00:00:00 2001 From: Sreedevi Joshi Date: Mon, 24 Nov 2025 12:47:48 -0600 Subject: [PATCH 1898/2333] idpf: Fix RSS LUT NULL pointer crash on early ethtool operations [ Upstream commit 83f38f210b85676f40ba8586b5a8edae19b56995 ] The RSS LUT is not initialized until the interface comes up, causing the following NULL pointer crash when ethtool operations like rxhash on/off are performed before the interface is brought up for the first time. Move RSS LUT initialization from ndo_open to vport creation to ensure LUT is always available. This enables RSS configuration via ethtool before bringing the interface up. Simplify LUT management by maintaining all changes in the driver's soft copy and programming zeros to the indirection table when rxhash is disabled. Defer HW programming until the interface comes up if it is down during rxhash and LUT configuration changes. Steps to reproduce: ** Load idpf driver; interfaces will be created modprobe idpf ** Before bringing the interfaces up, turn rxhash off ethtool -K eth2 rxhash off [89408.371875] BUG: kernel NULL pointer dereference, address: 0000000000000000 [89408.371908] #PF: supervisor read access in kernel mode [89408.371924] #PF: error_code(0x0000) - not-present page [89408.371940] PGD 0 P4D 0 [89408.371953] Oops: Oops: 0000 [#1] SMP NOPTI [89408.372052] RIP: 0010:memcpy_orig+0x16/0x130 [89408.372310] Call Trace: [89408.372317] [89408.372326] ? idpf_set_features+0xfc/0x180 [idpf] [89408.372363] __netdev_update_features+0x295/0xde0 [89408.372384] ethnl_set_features+0x15e/0x460 [89408.372406] genl_family_rcv_msg_doit+0x11f/0x180 [89408.372429] genl_rcv_msg+0x1ad/0x2b0 [89408.372446] ? __pfx_ethnl_set_features+0x10/0x10 [89408.372465] ? __pfx_genl_rcv_msg+0x10/0x10 [89408.372482] netlink_rcv_skb+0x58/0x100 [89408.372502] genl_rcv+0x2c/0x50 [89408.372516] netlink_unicast+0x289/0x3e0 [89408.372533] netlink_sendmsg+0x215/0x440 [89408.372551] __sys_sendto+0x234/0x240 [89408.372571] __x64_sys_sendto+0x28/0x30 [89408.372585] x64_sys_call+0x1909/0x1da0 [89408.372604] do_syscall_64+0x7a/0xfa0 [89408.373140] ? clear_bhb_loop+0x60/0xb0 [89408.373647] entry_SYSCALL_64_after_hwframe+0x76/0x7e [89408.378887] Fixes: a251eee62133 ("idpf: add SRIOV support and other ndo_ops") Signed-off-by: Sreedevi Joshi Reviewed-by: Sridhar Samudrala Reviewed-by: Emil Tantilov Reviewed-by: Aleksandr Loktionov Reviewed-by: Paul Menzel Reviewed-by: Simon Horman Tested-by: Samuel Salin Signed-off-by: Tony Nguyen Signed-off-by: Sasha Levin --- drivers/net/ethernet/intel/idpf/idpf.h | 2 - drivers/net/ethernet/intel/idpf/idpf_lib.c | 94 +++++++++---------- drivers/net/ethernet/intel/idpf/idpf_txrx.c | 36 +++---- drivers/net/ethernet/intel/idpf/idpf_txrx.h | 4 +- .../net/ethernet/intel/idpf/idpf_virtchnl.c | 9 +- 5 files changed, 66 insertions(+), 79 deletions(-) diff --git a/drivers/net/ethernet/intel/idpf/idpf.h b/drivers/net/ethernet/intel/idpf/idpf.h index df64d252b5642..c74c47bc0b9b9 100644 --- a/drivers/net/ethernet/intel/idpf/idpf.h +++ b/drivers/net/ethernet/intel/idpf/idpf.h @@ -423,14 +423,12 @@ enum idpf_user_flags { * @rss_key: RSS hash key * @rss_lut_size: Size of RSS lookup table * @rss_lut: RSS lookup table - * @cached_lut: Used to restore previously init RSS lut */ struct idpf_rss_data { u16 rss_key_size; u8 *rss_key; u16 rss_lut_size; u32 *rss_lut; - u32 *cached_lut; }; /** diff --git a/drivers/net/ethernet/intel/idpf/idpf_lib.c b/drivers/net/ethernet/intel/idpf/idpf_lib.c index d56366e676cf7..51716e5a84ef3 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_lib.c +++ b/drivers/net/ethernet/intel/idpf/idpf_lib.c @@ -1073,7 +1073,7 @@ static void idpf_vport_rel(struct idpf_vport *vport) u16 idx = vport->idx; vport_config = adapter->vport_config[vport->idx]; - idpf_deinit_rss(vport); + idpf_deinit_rss_lut(vport); rss_data = &vport_config->user_config.rss_data; kfree(rss_data->rss_key); rss_data->rss_key = NULL; @@ -1226,6 +1226,7 @@ static struct idpf_vport *idpf_vport_alloc(struct idpf_adapter *adapter, u16 idx = adapter->next_vport; struct idpf_vport *vport; u16 num_max_q; + int err; if (idx == IDPF_NO_FREE_SLOT) return NULL; @@ -1276,10 +1277,11 @@ static struct idpf_vport *idpf_vport_alloc(struct idpf_adapter *adapter, idpf_vport_init(vport, max_q); - /* This alloc is done separate from the LUT because it's not strictly - * dependent on how many queues we have. If we change number of queues - * and soft reset we'll need a new LUT but the key can remain the same - * for as long as the vport exists. + /* LUT and key are both initialized here. Key is not strictly dependent + * on how many queues we have. If we change number of queues and soft + * reset is initiated, LUT will be freed and a new LUT will be allocated + * as per the updated number of queues during vport bringup. However, + * the key remains the same for as long as the vport exists. */ rss_data = &adapter->vport_config[idx]->user_config.rss_data; rss_data->rss_key = kzalloc(rss_data->rss_key_size, GFP_KERNEL); @@ -1289,6 +1291,11 @@ static struct idpf_vport *idpf_vport_alloc(struct idpf_adapter *adapter, /* Initialize default rss key */ netdev_rss_key_fill((void *)rss_data->rss_key, rss_data->rss_key_size); + /* Initialize default rss LUT */ + err = idpf_init_rss_lut(vport); + if (err) + goto free_rss_key; + /* fill vport slot in the adapter struct */ adapter->vports[idx] = vport; adapter->vport_ids[idx] = idpf_get_vport_id(vport); @@ -1299,6 +1306,8 @@ static struct idpf_vport *idpf_vport_alloc(struct idpf_adapter *adapter, return vport; +free_rss_key: + kfree(rss_data->rss_key); free_vector_idxs: kfree(vport->q_vector_idxs); free_vport: @@ -1476,6 +1485,7 @@ static int idpf_vport_open(struct idpf_vport *vport, bool rtnl) struct idpf_netdev_priv *np = netdev_priv(vport->netdev); struct idpf_adapter *adapter = vport->adapter; struct idpf_vport_config *vport_config; + struct idpf_rss_data *rss_data; int err; if (test_bit(IDPF_VPORT_UP, np->state)) @@ -1570,12 +1580,21 @@ static int idpf_vport_open(struct idpf_vport *vport, bool rtnl) idpf_restore_features(vport); vport_config = adapter->vport_config[vport->idx]; - if (vport_config->user_config.rss_data.rss_lut) - err = idpf_config_rss(vport); - else - err = idpf_init_rss(vport); + rss_data = &vport_config->user_config.rss_data; + + if (!rss_data->rss_lut) { + err = idpf_init_rss_lut(vport); + if (err) { + dev_err(&adapter->pdev->dev, + "Failed to initialize RSS LUT for vport %u: %d\n", + vport->vport_id, err); + goto disable_vport; + } + } + + err = idpf_config_rss(vport); if (err) { - dev_err(&adapter->pdev->dev, "Failed to initialize RSS for vport %u: %d\n", + dev_err(&adapter->pdev->dev, "Failed to configure RSS for vport %u: %d\n", vport->vport_id, err); goto disable_vport; } @@ -1584,7 +1603,7 @@ static int idpf_vport_open(struct idpf_vport *vport, bool rtnl) if (err) { dev_err(&adapter->pdev->dev, "Failed to complete interface up for vport %u: %d\n", vport->vport_id, err); - goto deinit_rss; + goto disable_vport; } if (rtnl) @@ -1592,8 +1611,6 @@ static int idpf_vport_open(struct idpf_vport *vport, bool rtnl) return 0; -deinit_rss: - idpf_deinit_rss(vport); disable_vport: idpf_send_disable_vport_msg(vport); disable_queues: @@ -2051,7 +2068,7 @@ int idpf_initiate_soft_reset(struct idpf_vport *vport, idpf_vport_stop(vport, false); } - idpf_deinit_rss(vport); + idpf_deinit_rss_lut(vport); /* We're passing in vport here because we need its wait_queue * to send a message and it should be getting all the vport * config data out of the adapter but we need to be careful not @@ -2219,40 +2236,6 @@ static void idpf_set_rx_mode(struct net_device *netdev) dev_err(dev, "Failed to set promiscuous mode: %d\n", err); } -/** - * idpf_vport_manage_rss_lut - disable/enable RSS - * @vport: the vport being changed - * - * In the event of disable request for RSS, this function will zero out RSS - * LUT, while in the event of enable request for RSS, it will reconfigure RSS - * LUT with the default LUT configuration. - */ -static int idpf_vport_manage_rss_lut(struct idpf_vport *vport) -{ - bool ena = idpf_is_feature_ena(vport, NETIF_F_RXHASH); - struct idpf_rss_data *rss_data; - u16 idx = vport->idx; - int lut_size; - - rss_data = &vport->adapter->vport_config[idx]->user_config.rss_data; - lut_size = rss_data->rss_lut_size * sizeof(u32); - - if (ena) { - /* This will contain the default or user configured LUT */ - memcpy(rss_data->rss_lut, rss_data->cached_lut, lut_size); - } else { - /* Save a copy of the current LUT to be restored later if - * requested. - */ - memcpy(rss_data->cached_lut, rss_data->rss_lut, lut_size); - - /* Zero out the current LUT to disable */ - memset(rss_data->rss_lut, 0, lut_size); - } - - return idpf_config_rss(vport); -} - /** * idpf_set_features - set the netdev feature flags * @netdev: ptr to the netdev being adjusted @@ -2278,10 +2261,19 @@ static int idpf_set_features(struct net_device *netdev, } if (changed & NETIF_F_RXHASH) { + struct idpf_netdev_priv *np = netdev_priv(netdev); + netdev->features ^= NETIF_F_RXHASH; - err = idpf_vport_manage_rss_lut(vport); - if (err) - goto unlock_mutex; + + /* If the interface is not up when changing the rxhash, update + * to the HW is skipped. The updated LUT will be committed to + * the HW when the interface is brought up. + */ + if (test_bit(IDPF_VPORT_UP, np->state)) { + err = idpf_config_rss(vport); + if (err) + goto unlock_mutex; + } } if (changed & NETIF_F_GRO_HW) { diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.c b/drivers/net/ethernet/intel/idpf/idpf_txrx.c index 1993a3b0da59b..39553689ffdbf 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_txrx.c +++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c @@ -4650,57 +4650,47 @@ static void idpf_fill_dflt_rss_lut(struct idpf_vport *vport) rss_data = &adapter->vport_config[vport->idx]->user_config.rss_data; - for (i = 0; i < rss_data->rss_lut_size; i++) { + for (i = 0; i < rss_data->rss_lut_size; i++) rss_data->rss_lut[i] = i % num_active_rxq; - rss_data->cached_lut[i] = rss_data->rss_lut[i]; - } } /** - * idpf_init_rss - Allocate and initialize RSS resources + * idpf_init_rss_lut - Allocate and initialize RSS LUT * @vport: virtual port * - * Return 0 on success, negative on failure + * Return: 0 on success, negative on failure */ -int idpf_init_rss(struct idpf_vport *vport) +int idpf_init_rss_lut(struct idpf_vport *vport) { struct idpf_adapter *adapter = vport->adapter; struct idpf_rss_data *rss_data; - u32 lut_size; rss_data = &adapter->vport_config[vport->idx]->user_config.rss_data; + if (!rss_data->rss_lut) { + u32 lut_size; - lut_size = rss_data->rss_lut_size * sizeof(u32); - rss_data->rss_lut = kzalloc(lut_size, GFP_KERNEL); - if (!rss_data->rss_lut) - return -ENOMEM; - - rss_data->cached_lut = kzalloc(lut_size, GFP_KERNEL); - if (!rss_data->cached_lut) { - kfree(rss_data->rss_lut); - rss_data->rss_lut = NULL; - - return -ENOMEM; + lut_size = rss_data->rss_lut_size * sizeof(u32); + rss_data->rss_lut = kzalloc(lut_size, GFP_KERNEL); + if (!rss_data->rss_lut) + return -ENOMEM; } /* Fill the default RSS lut values */ idpf_fill_dflt_rss_lut(vport); - return idpf_config_rss(vport); + return 0; } /** - * idpf_deinit_rss - Release RSS resources + * idpf_deinit_rss_lut - Release RSS LUT * @vport: virtual port */ -void idpf_deinit_rss(struct idpf_vport *vport) +void idpf_deinit_rss_lut(struct idpf_vport *vport) { struct idpf_adapter *adapter = vport->adapter; struct idpf_rss_data *rss_data; rss_data = &adapter->vport_config[vport->idx]->user_config.rss_data; - kfree(rss_data->cached_lut); - rss_data->cached_lut = NULL; kfree(rss_data->rss_lut); rss_data->rss_lut = NULL; } diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.h b/drivers/net/ethernet/intel/idpf/idpf_txrx.h index 75b977094741f..7d20593bd8778 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_txrx.h +++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.h @@ -1086,8 +1086,8 @@ void idpf_vport_intr_deinit(struct idpf_vport *vport); int idpf_vport_intr_init(struct idpf_vport *vport); void idpf_vport_intr_ena(struct idpf_vport *vport); int idpf_config_rss(struct idpf_vport *vport); -int idpf_init_rss(struct idpf_vport *vport); -void idpf_deinit_rss(struct idpf_vport *vport); +int idpf_init_rss_lut(struct idpf_vport *vport); +void idpf_deinit_rss_lut(struct idpf_vport *vport); int idpf_rx_bufs_init_all(struct idpf_vport *vport); struct idpf_q_vector *idpf_find_rxq_vec(const struct idpf_vport *vport, diff --git a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c index 01bbd12a642a0..cb702eac86c80 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c +++ b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c @@ -2804,6 +2804,10 @@ int idpf_send_get_stats_msg(struct idpf_vport *vport) * @vport: virtual port data structure * @get: flag to set or get rss look up table * + * When rxhash is disabled, RSS LUT will be configured with zeros. If rxhash + * is enabled, the LUT values stored in driver's soft copy will be used to setup + * the HW. + * * Returns 0 on success, negative on failure. */ int idpf_send_get_set_rss_lut_msg(struct idpf_vport *vport, bool get) @@ -2814,10 +2818,12 @@ int idpf_send_get_set_rss_lut_msg(struct idpf_vport *vport, bool get) struct idpf_rss_data *rss_data; int buf_size, lut_buf_size; ssize_t reply_sz; + bool rxhash_ena; int i; rss_data = &vport->adapter->vport_config[vport->idx]->user_config.rss_data; + rxhash_ena = idpf_is_feature_ena(vport, NETIF_F_RXHASH); buf_size = struct_size(rl, lut, rss_data->rss_lut_size); rl = kzalloc(buf_size, GFP_KERNEL); if (!rl) @@ -2839,7 +2845,8 @@ int idpf_send_get_set_rss_lut_msg(struct idpf_vport *vport, bool get) } else { rl->lut_entries = cpu_to_le16(rss_data->rss_lut_size); for (i = 0; i < rss_data->rss_lut_size; i++) - rl->lut[i] = cpu_to_le32(rss_data->rss_lut[i]); + rl->lut[i] = rxhash_ena ? + cpu_to_le32(rss_data->rss_lut[i]) : 0; xn_params.vc_op = VIRTCHNL2_OP_SET_RSS_LUT; } From 9abe73eff87d66241413fe7cb0f54b4fd0869880 Mon Sep 17 00:00:00 2001 From: Sreedevi Joshi Date: Mon, 24 Nov 2025 12:47:49 -0600 Subject: [PATCH 1899/2333] idpf: Fix RSS LUT configuration on down interfaces [ Upstream commit 445b49d13787da2fe8d51891ee196e5077feef44 ] RSS LUT provisioning and queries on a down interface currently return silently without effect. Users should be able to configure RSS settings even when the interface is down. Fix by maintaining RSS configuration changes in the driver's soft copy and deferring HW programming until the interface comes up. Fixes: 02cbfba1add5 ("idpf: add ethtool callbacks") Signed-off-by: Sreedevi Joshi Reviewed-by: Aleksandr Loktionov Reviewed-by: Sridhar Samudrala Reviewed-by: Emil Tantilov Tested-by: Samuel Salin Signed-off-by: Tony Nguyen Signed-off-by: Sasha Levin --- drivers/net/ethernet/intel/idpf/idpf_ethtool.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/intel/idpf/idpf_ethtool.c b/drivers/net/ethernet/intel/idpf/idpf_ethtool.c index 8e9a93125b4aa..3e191cf528b69 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_ethtool.c +++ b/drivers/net/ethernet/intel/idpf/idpf_ethtool.c @@ -395,7 +395,10 @@ static u32 idpf_get_rxfh_indir_size(struct net_device *netdev) * @netdev: network interface device structure * @rxfh: pointer to param struct (indir, key, hfunc) * - * Reads the indirection table directly from the hardware. Always returns 0. + * RSS LUT and Key information are read from driver's cached + * copy. When rxhash is off, rss lut will be displayed as zeros. + * + * Return: 0 on success, -errno otherwise. */ static int idpf_get_rxfh(struct net_device *netdev, struct ethtool_rxfh_param *rxfh) @@ -403,10 +406,13 @@ static int idpf_get_rxfh(struct net_device *netdev, struct idpf_netdev_priv *np = netdev_priv(netdev); struct idpf_rss_data *rss_data; struct idpf_adapter *adapter; + struct idpf_vport *vport; + bool rxhash_ena; int err = 0; u16 i; idpf_vport_ctrl_lock(netdev); + vport = idpf_netdev_to_vport(netdev); adapter = np->adapter; @@ -416,9 +422,8 @@ static int idpf_get_rxfh(struct net_device *netdev, } rss_data = &adapter->vport_config[np->vport_idx]->user_config.rss_data; - if (!test_bit(IDPF_VPORT_UP, np->state)) - goto unlock_mutex; + rxhash_ena = idpf_is_feature_ena(vport, NETIF_F_RXHASH); rxfh->hfunc = ETH_RSS_HASH_TOP; if (rxfh->key) @@ -426,7 +431,7 @@ static int idpf_get_rxfh(struct net_device *netdev, if (rxfh->indir) { for (i = 0; i < rss_data->rss_lut_size; i++) - rxfh->indir[i] = rss_data->rss_lut[i]; + rxfh->indir[i] = rxhash_ena ? rss_data->rss_lut[i] : 0; } unlock_mutex: @@ -466,8 +471,6 @@ static int idpf_set_rxfh(struct net_device *netdev, } rss_data = &adapter->vport_config[vport->idx]->user_config.rss_data; - if (!test_bit(IDPF_VPORT_UP, np->state)) - goto unlock_mutex; if (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE && rxfh->hfunc != ETH_RSS_HASH_TOP) { @@ -483,7 +486,8 @@ static int idpf_set_rxfh(struct net_device *netdev, rss_data->rss_lut[lut] = rxfh->indir[lut]; } - err = idpf_config_rss(vport); + if (test_bit(IDPF_VPORT_UP, np->state)) + err = idpf_config_rss(vport); unlock_mutex: idpf_vport_ctrl_unlock(netdev); From ab92fa4dd81beaaed4e93a851f7a37c9b2d9776f Mon Sep 17 00:00:00 2001 From: Sreedevi Joshi Date: Mon, 24 Nov 2025 12:47:50 -0600 Subject: [PATCH 1900/2333] idpf: Fix RSS LUT NULL ptr issue after soft reset [ Upstream commit ebecca5b093895da801b3eba1a55b4ec4027d196 ] During soft reset, the RSS LUT is freed and not restored unless the interface is up. If an ethtool command that accesses the rss lut is attempted immediately after reset, it will result in NULL ptr dereference. Also, there is no need to reset the rss lut if the soft reset does not involve queue count change. After soft reset, set the RSS LUT to default values based on the updated queue count only if the reset was a result of a queue count change and the LUT was not configured by the user. In all other cases, don't touch the LUT. Steps to reproduce: ** Bring the interface down (if up) ifconfig eth1 down ** update the queue count (eg., 27->20) ethtool -L eth1 combined 20 ** display the RSS LUT ethtool -x eth1 [82375.558338] BUG: kernel NULL pointer dereference, address: 0000000000000000 [82375.558373] #PF: supervisor read access in kernel mode [82375.558391] #PF: error_code(0x0000) - not-present page [82375.558408] PGD 0 P4D 0 [82375.558421] Oops: Oops: 0000 [#1] SMP NOPTI [82375.558516] RIP: 0010:idpf_get_rxfh+0x108/0x150 [idpf] [82375.558786] Call Trace: [82375.558793] [82375.558804] rss_prepare.isra.0+0x187/0x2a0 [82375.558827] rss_prepare_data+0x3a/0x50 [82375.558845] ethnl_default_doit+0x13d/0x3e0 [82375.558863] genl_family_rcv_msg_doit+0x11f/0x180 [82375.558886] genl_rcv_msg+0x1ad/0x2b0 [82375.558902] ? __pfx_ethnl_default_doit+0x10/0x10 [82375.558920] ? __pfx_genl_rcv_msg+0x10/0x10 [82375.558937] netlink_rcv_skb+0x58/0x100 [82375.558957] genl_rcv+0x2c/0x50 [82375.558971] netlink_unicast+0x289/0x3e0 [82375.558988] netlink_sendmsg+0x215/0x440 [82375.559005] __sys_sendto+0x234/0x240 [82375.559555] __x64_sys_sendto+0x28/0x30 [82375.560068] x64_sys_call+0x1909/0x1da0 [82375.560576] do_syscall_64+0x7a/0xfa0 [82375.561076] ? clear_bhb_loop+0x60/0xb0 [82375.561567] entry_SYSCALL_64_after_hwframe+0x76/0x7e Fixes: 02cbfba1add5 ("idpf: add ethtool callbacks") Signed-off-by: Sreedevi Joshi Reviewed-by: Aleksandr Loktionov Reviewed-by: Sridhar Samudrala Reviewed-by: Emil Tantilov Reviewed-by: Simon Horman Tested-by: Samuel Salin Signed-off-by: Tony Nguyen Signed-off-by: Sasha Levin --- drivers/net/ethernet/intel/idpf/idpf_lib.c | 20 ++++---------------- drivers/net/ethernet/intel/idpf/idpf_txrx.c | 2 +- drivers/net/ethernet/intel/idpf/idpf_txrx.h | 1 + 3 files changed, 6 insertions(+), 17 deletions(-) diff --git a/drivers/net/ethernet/intel/idpf/idpf_lib.c b/drivers/net/ethernet/intel/idpf/idpf_lib.c index 51716e5a84ef3..003bab3ce5ae6 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_lib.c +++ b/drivers/net/ethernet/intel/idpf/idpf_lib.c @@ -1484,8 +1484,6 @@ static int idpf_vport_open(struct idpf_vport *vport, bool rtnl) { struct idpf_netdev_priv *np = netdev_priv(vport->netdev); struct idpf_adapter *adapter = vport->adapter; - struct idpf_vport_config *vport_config; - struct idpf_rss_data *rss_data; int err; if (test_bit(IDPF_VPORT_UP, np->state)) @@ -1579,19 +1577,6 @@ static int idpf_vport_open(struct idpf_vport *vport, bool rtnl) idpf_restore_features(vport); - vport_config = adapter->vport_config[vport->idx]; - rss_data = &vport_config->user_config.rss_data; - - if (!rss_data->rss_lut) { - err = idpf_init_rss_lut(vport); - if (err) { - dev_err(&adapter->pdev->dev, - "Failed to initialize RSS LUT for vport %u: %d\n", - vport->vport_id, err); - goto disable_vport; - } - } - err = idpf_config_rss(vport); if (err) { dev_err(&adapter->pdev->dev, "Failed to configure RSS for vport %u: %d\n", @@ -2068,7 +2053,6 @@ int idpf_initiate_soft_reset(struct idpf_vport *vport, idpf_vport_stop(vport, false); } - idpf_deinit_rss_lut(vport); /* We're passing in vport here because we need its wait_queue * to send a message and it should be getting all the vport * config data out of the adapter but we need to be careful not @@ -2094,6 +2078,10 @@ int idpf_initiate_soft_reset(struct idpf_vport *vport, if (err) goto err_open; + if (reset_cause == IDPF_SR_Q_CHANGE && + !netif_is_rxfh_configured(vport->netdev)) + idpf_fill_dflt_rss_lut(vport); + if (vport_is_up) err = idpf_vport_open(vport, false); diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.c b/drivers/net/ethernet/intel/idpf/idpf_txrx.c index 39553689ffdbf..3698979b4c9ee 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_txrx.c +++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c @@ -4641,7 +4641,7 @@ int idpf_config_rss(struct idpf_vport *vport) * idpf_fill_dflt_rss_lut - Fill the indirection table with the default values * @vport: virtual port structure */ -static void idpf_fill_dflt_rss_lut(struct idpf_vport *vport) +void idpf_fill_dflt_rss_lut(struct idpf_vport *vport) { struct idpf_adapter *adapter = vport->adapter; u16 num_active_rxq = vport->num_rxq; diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.h b/drivers/net/ethernet/intel/idpf/idpf_txrx.h index 7d20593bd8778..0472698ca1927 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_txrx.h +++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.h @@ -1085,6 +1085,7 @@ void idpf_vport_intr_update_itr_ena_irq(struct idpf_q_vector *q_vector); void idpf_vport_intr_deinit(struct idpf_vport *vport); int idpf_vport_intr_init(struct idpf_vport *vport); void idpf_vport_intr_ena(struct idpf_vport *vport); +void idpf_fill_dflt_rss_lut(struct idpf_vport *vport); int idpf_config_rss(struct idpf_vport *vport); int idpf_init_rss_lut(struct idpf_vport *vport); void idpf_deinit_rss_lut(struct idpf_vport *vport); From bfeb4dfc805003fe4cfb1923f932581bd7e8db92 Mon Sep 17 00:00:00 2001 From: Sreedevi Joshi Date: Tue, 2 Dec 2025 17:12:46 -0600 Subject: [PATCH 1901/2333] idpf: Fix error handling in idpf_vport_open() [ Upstream commit 87b8ee64685bc096a087af833d4594b2332bfdb1 ] Fix error handling to properly cleanup interrupts when idpf_vport_queue_ids_init() or idpf_rx_bufs_init_all() fail. Jump to 'intr_deinit' instead of 'queues_rel' to ensure interrupts are cleaned up before releasing other resources. Fixes: d4d558718266 ("idpf: initialize interrupts and enable vport") Signed-off-by: Sreedevi Joshi Reviewed-by: Madhu Chittim Reviewed-by: Aleksandr Loktionov Reviewed-by: Simon Horman Tested-by: Samuel Salin Signed-off-by: Tony Nguyen Signed-off-by: Sasha Levin --- drivers/net/ethernet/intel/idpf/idpf_lib.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/idpf/idpf_lib.c b/drivers/net/ethernet/intel/idpf/idpf_lib.c index 003bab3ce5ae6..131a8121839bd 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_lib.c +++ b/drivers/net/ethernet/intel/idpf/idpf_lib.c @@ -1524,14 +1524,14 @@ static int idpf_vport_open(struct idpf_vport *vport, bool rtnl) if (err) { dev_err(&adapter->pdev->dev, "Failed to initialize queue registers for vport %u: %d\n", vport->vport_id, err); - goto queues_rel; + goto intr_deinit; } err = idpf_rx_bufs_init_all(vport); if (err) { dev_err(&adapter->pdev->dev, "Failed to initialize RX buffers for vport %u: %d\n", vport->vport_id, err); - goto queues_rel; + goto intr_deinit; } idpf_rx_init_buf_tail(vport); From 258e7c55f9395b4711afa590fb0230911c602b8c Mon Sep 17 00:00:00 2001 From: Joshua Hay Date: Mon, 3 Nov 2025 13:20:36 -0800 Subject: [PATCH 1902/2333] idpf: cap maximum Rx buffer size [ Upstream commit 086efe0a1ecc36cffe46640ce12649a4cd3ff171 ] The HW only supports a maximum Rx buffer size of 16K-128. On systems using large pages, the libeth logic can configure the buffer size to be larger than this. The upper bound is PAGE_SIZE while the lower bound is MTU rounded up to the nearest power of 2. For example, ARM systems with a 64K page size and an mtu of 9000 will set the Rx buffer size to 16K, which will cause the config Rx queues message to fail. Initialize the bufq/fill queue buf_len field to the maximum supported size. This will trigger the libeth logic to cap the maximum Rx buffer size by reducing the upper bound. Fixes: 74d1412ac8f37 ("idpf: use libeth Rx buffer management for payload buffer") Signed-off-by: Joshua Hay Acked-by: Alexander Lobakin Reviewed-by: Madhu Chittim Reviewed-by: Jacob Keller Reviewed-by: Aleksandr Loktionov Reviewed-by: David Decotigny Signed-off-by: Tony Nguyen Signed-off-by: Sasha Levin --- drivers/net/ethernet/intel/idpf/idpf_txrx.c | 8 +++++--- drivers/net/ethernet/intel/idpf/idpf_txrx.h | 1 + 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.c b/drivers/net/ethernet/intel/idpf/idpf_txrx.c index 3698979b4c9ee..f66948f5de78b 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_txrx.c +++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c @@ -695,9 +695,10 @@ static int idpf_rx_buf_alloc_singleq(struct idpf_rx_queue *rxq) static int idpf_rx_bufs_init_singleq(struct idpf_rx_queue *rxq) { struct libeth_fq fq = { - .count = rxq->desc_count, - .type = LIBETH_FQE_MTU, - .nid = idpf_q_vector_to_mem(rxq->q_vector), + .count = rxq->desc_count, + .type = LIBETH_FQE_MTU, + .buf_len = IDPF_RX_MAX_BUF_SZ, + .nid = idpf_q_vector_to_mem(rxq->q_vector), }; int ret; @@ -754,6 +755,7 @@ static int idpf_rx_bufs_init(struct idpf_buf_queue *bufq, .truesize = bufq->truesize, .count = bufq->desc_count, .type = type, + .buf_len = IDPF_RX_MAX_BUF_SZ, .hsplit = idpf_queue_has(HSPLIT_EN, bufq), .xdp = idpf_xdp_enabled(bufq->q_vector->vport), .nid = idpf_q_vector_to_mem(bufq->q_vector), diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.h b/drivers/net/ethernet/intel/idpf/idpf_txrx.h index 0472698ca1927..423cc9486dce7 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_txrx.h +++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.h @@ -101,6 +101,7 @@ do { \ idx = 0; \ } while (0) +#define IDPF_RX_MAX_BUF_SZ (16384 - 128) #define IDPF_RX_BUF_STRIDE 32 #define IDPF_RX_BUF_POST_STRIDE 16 #define IDPF_LOW_WATERMARK 64 From 0ad6d6e50e9d8bf596cfe77a882ddc20b29f525a Mon Sep 17 00:00:00 2001 From: Larysa Zaremba Date: Mon, 17 Nov 2025 08:03:49 +0100 Subject: [PATCH 1903/2333] idpf: fix aux device unplugging when rdma is not supported by vport [ Upstream commit 4648fb2f2e7210c53b85220ee07d42d1e4bae3f9 ] If vport flags do not contain VIRTCHNL2_VPORT_ENABLE_RDMA, driver does not allocate vdev_info for this vport. This leads to kernel NULL pointer dereference in idpf_idc_vport_dev_down(), which references vdev_info for every vport regardless. Check, if vdev_info was ever allocated before unplugging aux device. Fixes: be91128c579c ("idpf: implement RDMA vport auxiliary dev create, init, and destroy") Reviewed-by: Madhu Chittim Signed-off-by: Larysa Zaremba Reviewed-by: Paul Menzel Reviewed-by: Aleksandr Loktionov Tested-by: Krishneil Singh Signed-off-by: Tony Nguyen Signed-off-by: Sasha Levin --- drivers/net/ethernet/intel/idpf/idpf_idc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/idpf/idpf_idc.c b/drivers/net/ethernet/intel/idpf/idpf_idc.c index 7e20a07e98e53..6dad0593f7f22 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_idc.c +++ b/drivers/net/ethernet/intel/idpf/idpf_idc.c @@ -322,7 +322,7 @@ static void idpf_idc_vport_dev_down(struct idpf_adapter *adapter) for (i = 0; i < adapter->num_alloc_vports; i++) { struct idpf_vport *vport = adapter->vports[i]; - if (!vport) + if (!vport || !vport->vdev_info) continue; idpf_unplug_aux_dev(vport->vdev_info->adev); From 2d6cde9953f9fdb5773825d75e932341365977d8 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Sun, 4 Jan 2026 11:39:52 +0200 Subject: [PATCH 1904/2333] Revert "dsa: mv88e6xxx: make serdes SGMII/Fiber tx amplitude configurable" [ Upstream commit 7801edc9badd972cb62cf11c0427e70b6dca239d ] This reverts commit 926eae604403acfa27ba5b072af458e87e634a50, which never could have produced the intended effect: https://lore.kernel.org/netdev/AM0PR06MB10396BBF8B568D77556FC46F8F7DEA@AM0PR06MB10396.eurprd06.prod.outlook.com/ The reason why it is broken beyond repair in this form is that the mv88e6xxx driver outsources its "tx-p2p-microvolt" property to the OF node of an external Ethernet PHY. This: (a) does not work if there is no external PHY (chip-to-chip connection, or SFP module) (b) pollutes the OF property namespace / bindings of said external PHY ("tx-p2p-microvolt" could have meaning for the Ethernet PHY's SerDes interface as well) We can revisit the idea of making SerDes amplitude configurable once we have proper bindings for the mv88e6xxx SerDes. Until then, remove the code that leaves us with unnecessary baggage. Fixes: 926eae604403 ("dsa: mv88e6xxx: make serdes SGMII/Fiber tx amplitude configurable") Cc: Holger Brunck Signed-off-by: Vladimir Oltean Reviewed-by: Andrew Lunn Link: https://patch.msgid.link/20260104093952.486606-1-vladimir.oltean@nxp.com Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- drivers/net/dsa/mv88e6xxx/chip.c | 23 --------------- drivers/net/dsa/mv88e6xxx/chip.h | 4 --- drivers/net/dsa/mv88e6xxx/serdes.c | 46 ------------------------------ drivers/net/dsa/mv88e6xxx/serdes.h | 5 ---- 4 files changed, 78 deletions(-) diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index b4d48997bf467..09002c853b78e 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -3364,13 +3364,10 @@ static int mv88e6xxx_setup_upstream_port(struct mv88e6xxx_chip *chip, int port) static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port) { - struct device_node *phy_handle = NULL; struct fwnode_handle *ports_fwnode; struct fwnode_handle *port_fwnode; struct dsa_switch *ds = chip->ds; struct mv88e6xxx_port *p; - struct dsa_port *dp; - int tx_amp; int err; u16 reg; u32 val; @@ -3582,23 +3579,6 @@ static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port) return err; } - if (chip->info->ops->serdes_set_tx_amplitude) { - dp = dsa_to_port(ds, port); - if (dp) - phy_handle = of_parse_phandle(dp->dn, "phy-handle", 0); - - if (phy_handle && !of_property_read_u32(phy_handle, - "tx-p2p-microvolt", - &tx_amp)) - err = chip->info->ops->serdes_set_tx_amplitude(chip, - port, tx_amp); - if (phy_handle) { - of_node_put(phy_handle); - if (err) - return err; - } - } - /* Port based VLAN map: give each port the same default address * database, and allow bidirectional communication between the * CPU and DSA port(s), and the other ports. @@ -4768,7 +4748,6 @@ static const struct mv88e6xxx_ops mv88e6176_ops = { .serdes_irq_mapping = mv88e6352_serdes_irq_mapping, .serdes_get_regs_len = mv88e6352_serdes_get_regs_len, .serdes_get_regs = mv88e6352_serdes_get_regs, - .serdes_set_tx_amplitude = mv88e6352_serdes_set_tx_amplitude, .gpio_ops = &mv88e6352_gpio_ops, .phylink_get_caps = mv88e6352_phylink_get_caps, .pcs_ops = &mv88e6352_pcs_ops, @@ -5044,7 +5023,6 @@ static const struct mv88e6xxx_ops mv88e6240_ops = { .serdes_irq_mapping = mv88e6352_serdes_irq_mapping, .serdes_get_regs_len = mv88e6352_serdes_get_regs_len, .serdes_get_regs = mv88e6352_serdes_get_regs, - .serdes_set_tx_amplitude = mv88e6352_serdes_set_tx_amplitude, .gpio_ops = &mv88e6352_gpio_ops, .avb_ops = &mv88e6352_avb_ops, .ptp_ops = &mv88e6352_ptp_ops, @@ -5481,7 +5459,6 @@ static const struct mv88e6xxx_ops mv88e6352_ops = { .serdes_get_stats = mv88e6352_serdes_get_stats, .serdes_get_regs_len = mv88e6352_serdes_get_regs_len, .serdes_get_regs = mv88e6352_serdes_get_regs, - .serdes_set_tx_amplitude = mv88e6352_serdes_set_tx_amplitude, .phylink_get_caps = mv88e6352_phylink_get_caps, .pcs_ops = &mv88e6352_pcs_ops, }; diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h index 2f211e55cb47b..e073446ee7d02 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.h +++ b/drivers/net/dsa/mv88e6xxx/chip.h @@ -642,10 +642,6 @@ struct mv88e6xxx_ops { void (*serdes_get_regs)(struct mv88e6xxx_chip *chip, int port, void *_p); - /* SERDES SGMII/Fiber Output Amplitude */ - int (*serdes_set_tx_amplitude)(struct mv88e6xxx_chip *chip, int port, - int val); - /* Address Translation Unit operations */ int (*atu_get_hash)(struct mv88e6xxx_chip *chip, u8 *hash); int (*atu_set_hash)(struct mv88e6xxx_chip *chip, u8 hash); diff --git a/drivers/net/dsa/mv88e6xxx/serdes.c b/drivers/net/dsa/mv88e6xxx/serdes.c index b3330211edbca..a936ee80ce006 100644 --- a/drivers/net/dsa/mv88e6xxx/serdes.c +++ b/drivers/net/dsa/mv88e6xxx/serdes.c @@ -25,14 +25,6 @@ static int mv88e6352_serdes_read(struct mv88e6xxx_chip *chip, int reg, reg, val); } -static int mv88e6352_serdes_write(struct mv88e6xxx_chip *chip, int reg, - u16 val) -{ - return mv88e6xxx_phy_page_write(chip, MV88E6352_ADDR_SERDES, - MV88E6352_SERDES_PAGE_FIBER, - reg, val); -} - static int mv88e6390_serdes_read(struct mv88e6xxx_chip *chip, int lane, int device, int reg, u16 *val) { @@ -506,41 +498,3 @@ void mv88e6390_serdes_get_regs(struct mv88e6xxx_chip *chip, int port, void *_p) p[i] = reg; } } - -static const int mv88e6352_serdes_p2p_to_reg[] = { - /* Index of value in microvolts corresponds to the register value */ - 14000, 112000, 210000, 308000, 406000, 504000, 602000, 700000, -}; - -int mv88e6352_serdes_set_tx_amplitude(struct mv88e6xxx_chip *chip, int port, - int val) -{ - bool found = false; - u16 ctrl, reg; - int err; - int i; - - err = mv88e6352_g2_scratch_port_has_serdes(chip, port); - if (err <= 0) - return err; - - for (i = 0; i < ARRAY_SIZE(mv88e6352_serdes_p2p_to_reg); ++i) { - if (mv88e6352_serdes_p2p_to_reg[i] == val) { - reg = i; - found = true; - break; - } - } - - if (!found) - return -EINVAL; - - err = mv88e6352_serdes_read(chip, MV88E6352_SERDES_SPEC_CTRL2, &ctrl); - if (err) - return err; - - ctrl &= ~MV88E6352_SERDES_OUT_AMP_MASK; - ctrl |= reg; - - return mv88e6352_serdes_write(chip, MV88E6352_SERDES_SPEC_CTRL2, ctrl); -} diff --git a/drivers/net/dsa/mv88e6xxx/serdes.h b/drivers/net/dsa/mv88e6xxx/serdes.h index ad887d8601bcb..17a3e85fabaa3 100644 --- a/drivers/net/dsa/mv88e6xxx/serdes.h +++ b/drivers/net/dsa/mv88e6xxx/serdes.h @@ -29,8 +29,6 @@ struct phylink_link_state; #define MV88E6352_SERDES_INT_FIBRE_ENERGY BIT(4) #define MV88E6352_SERDES_INT_STATUS 0x13 -#define MV88E6352_SERDES_SPEC_CTRL2 0x1a -#define MV88E6352_SERDES_OUT_AMP_MASK 0x0007 #define MV88E6341_PORT5_LANE 0x15 @@ -140,9 +138,6 @@ void mv88e6352_serdes_get_regs(struct mv88e6xxx_chip *chip, int port, void *_p); int mv88e6390_serdes_get_regs_len(struct mv88e6xxx_chip *chip, int port); void mv88e6390_serdes_get_regs(struct mv88e6xxx_chip *chip, int port, void *_p); -int mv88e6352_serdes_set_tx_amplitude(struct mv88e6xxx_chip *chip, int port, - int val); - /* Return the (first) SERDES lane address a port is using, -errno otherwise. */ static inline int mv88e6xxx_serdes_get_lane(struct mv88e6xxx_chip *chip, int port) From 0c63d5683eae6a7b4d81382bcbecb2a19feff90d Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 5 Jan 2026 09:36:30 +0000 Subject: [PATCH 1905/2333] udp: call skb_orphan() before skb_attempt_defer_free() [ Upstream commit e5c8eda39a9fc1547d1398d707aa06c1d080abdd ] Standard UDP receive path does not use skb->destructor. But skmsg layer does use it, since it calls skb_set_owner_sk_safe() from udp_read_skb(). This then triggers this warning in skb_attempt_defer_free(): DEBUG_NET_WARN_ON_ONCE(skb->destructor); We must call skb_orphan() to fix this issue. Fixes: 6471658dc66c ("udp: use skb_attempt_defer_free()") Reported-by: syzbot+3e68572cf2286ce5ebe9@syzkaller.appspotmail.com Closes: https://lore.kernel.org/netdev/695b83bd.050a0220.1c9965.002b.GAE@google.com/T/#u Signed-off-by: Eric Dumazet Link: https://patch.msgid.link/20260105093630.1976085-1-edumazet@google.com Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- net/ipv4/udp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 30dfbf73729da..860bd61ff047f 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -1851,6 +1851,7 @@ void skb_consume_udp(struct sock *sk, struct sk_buff *skb, int len) sk_peek_offset_bwd(sk, len); if (!skb_shared(skb)) { + skb_orphan(skb); skb_attempt_defer_free(skb); return; } From 06dc322dcb20c71748d8247828895043e9486a74 Mon Sep 17 00:00:00 2001 From: Maxime Chevallier Date: Mon, 5 Jan 2026 16:18:39 +0100 Subject: [PATCH 1906/2333] net: sfp: return the number of written bytes for smbus single byte access [ Upstream commit 13ff3e724207f579d3c814ee05516fefcb4f32e8 ] We expect the SFP write accessors to return the number of written bytes. We fail to do so for single-byte smbus accesses, which may cause errors when setting a module's high-power state and for some cotsworks modules. Let's return the amount of written bytes, as expected. Fixes: 7662abf4db94 ("net: phy: sfp: Add support for SMBus module access") Signed-off-by: Maxime Chevallier Reviewed-by: Andrew Lunn Link: https://patch.msgid.link/20260105151840.144552-1-maxime.chevallier@bootlin.com Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- drivers/net/phy/sfp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c index 0401fa6b24d25..6b4dd906b804f 100644 --- a/drivers/net/phy/sfp.c +++ b/drivers/net/phy/sfp.c @@ -763,7 +763,7 @@ static int sfp_smbus_byte_write(struct sfp *sfp, bool a2, u8 dev_addr, dev_addr++; } - return 0; + return data - (u8 *)buf; } static int sfp_i2c_configure(struct sfp *sfp, struct i2c_adapter *i2c) From 67550a1130b647bb0d093c9c0a810c69aa6a30a8 Mon Sep 17 00:00:00 2001 From: Shivani Gupta Date: Mon, 5 Jan 2026 00:59:05 +0000 Subject: [PATCH 1907/2333] net/sched: act_api: avoid dereferencing ERR_PTR in tcf_idrinfo_destroy [ Upstream commit adb25a46dc0a43173f5ea5f5f58fc8ba28970c7c ] syzbot reported a crash in tc_act_in_hw() during netns teardown where tcf_idrinfo_destroy() passed an ERR_PTR(-EBUSY) value as a tc_action pointer, leading to an invalid dereference. Guard against ERR_PTR entries when iterating the action IDR so teardown does not call tc_act_in_hw() on an error pointer. Fixes: 84a7d6797e6a ("net/sched: acp_api: no longer acquire RTNL in tc_action_net_exit()") Link: https://syzkaller.appspot.com/bug?extid=8f1c492ffa4644ff3826 Reported-by: syzbot+8f1c492ffa4644ff3826@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=8f1c492ffa4644ff3826 Signed-off-by: Shivani Gupta Link: https://patch.msgid.link/20260105005905.243423-1-shivani07g@gmail.com Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- net/sched/act_api.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/sched/act_api.c b/net/sched/act_api.c index ff6be5cfe2b05..e1ab0faeb8113 100644 --- a/net/sched/act_api.c +++ b/net/sched/act_api.c @@ -940,6 +940,8 @@ void tcf_idrinfo_destroy(const struct tc_action_ops *ops, int ret; idr_for_each_entry_ul(idr, p, tmp, id) { + if (IS_ERR(p)) + continue; if (tc_act_in_hw(p) && !mutex_taken) { rtnl_lock(); mutex_taken = true; From 334bbbbf4c809c31722b5cae6c2158d9ff2fdc9f Mon Sep 17 00:00:00 2001 From: Gal Pressman Date: Mon, 5 Jan 2026 18:33:19 +0200 Subject: [PATCH 1908/2333] selftests: drv-net: Bring back tool() to driver __init__s [ Upstream commit 353cfc0ef3f34ef7fe313ae38dac37f2454a7cf5 ] The pp_alloc_fail.py test (which doesn't run in NIPA CI?) uses tool, add back the import. Resolves: ImportError: cannot import name 'tool' from 'lib.py' Fixes: 68a052239fc4 ("selftests: drv-net: update remaining Python init files") Reviewed-by: Nimrod Oren Signed-off-by: Gal Pressman Link: https://patch.msgid.link/20260105163319.47619-1-gal@nvidia.com Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- tools/testing/selftests/drivers/net/hw/lib/py/__init__.py | 4 ++-- tools/testing/selftests/net/lib/py/__init__.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/testing/selftests/drivers/net/hw/lib/py/__init__.py b/tools/testing/selftests/drivers/net/hw/lib/py/__init__.py index fb010a48a5a19..a86f5c311fdcb 100644 --- a/tools/testing/selftests/drivers/net/hw/lib/py/__init__.py +++ b/tools/testing/selftests/drivers/net/hw/lib/py/__init__.py @@ -22,7 +22,7 @@ NlError, RtnlFamily, DevlinkFamily, PSPFamily from net.lib.py import CmdExitFailure from net.lib.py import bkg, cmd, bpftool, bpftrace, defer, ethtool, \ - fd_read_timeout, ip, rand_port, wait_port_listen, wait_file + fd_read_timeout, ip, rand_port, wait_port_listen, wait_file, tool from net.lib.py import KsftSkipEx, KsftFailEx, KsftXfailEx from net.lib.py import ksft_disruptive, ksft_exit, ksft_pr, ksft_run, \ ksft_setup @@ -37,7 +37,7 @@ "CmdExitFailure", "bkg", "cmd", "bpftool", "bpftrace", "defer", "ethtool", "fd_read_timeout", "ip", "rand_port", - "wait_port_listen", "wait_file", + "wait_port_listen", "wait_file", "tool", "KsftSkipEx", "KsftFailEx", "KsftXfailEx", "ksft_disruptive", "ksft_exit", "ksft_pr", "ksft_run", "ksft_setup", diff --git a/tools/testing/selftests/net/lib/py/__init__.py b/tools/testing/selftests/net/lib/py/__init__.py index 97b7cf2b20eb9..8f2da17d53510 100644 --- a/tools/testing/selftests/net/lib/py/__init__.py +++ b/tools/testing/selftests/net/lib/py/__init__.py @@ -12,7 +12,7 @@ from .netns import NetNS, NetNSEnter from .nsim import NetdevSim, NetdevSimDev from .utils import CmdExitFailure, fd_read_timeout, cmd, bkg, defer, \ - bpftool, ip, ethtool, bpftrace, rand_port, wait_port_listen, wait_file + bpftool, ip, ethtool, bpftrace, rand_port, wait_port_listen, wait_file, tool from .ynl import NlError, YnlFamily, EthtoolFamily, NetdevFamily, RtnlFamily, RtnlAddrFamily from .ynl import NetshaperFamily, DevlinkFamily, PSPFamily @@ -25,7 +25,7 @@ "NetNS", "NetNSEnter", "CmdExitFailure", "fd_read_timeout", "cmd", "bkg", "defer", "bpftool", "ip", "ethtool", "bpftrace", "rand_port", - "wait_port_listen", "wait_file", + "wait_port_listen", "wait_file", "tool", "NetdevSim", "NetdevSimDev", "NetshaperFamily", "DevlinkFamily", "PSPFamily", "NlError", "YnlFamily", "EthtoolFamily", "NetdevFamily", "RtnlFamily", From 086e2928c1dacc2840d63eccabcfb557997695e6 Mon Sep 17 00:00:00 2001 From: Yohei Kojima Date: Tue, 6 Jan 2026 00:17:32 +0900 Subject: [PATCH 1909/2333] net: netdevsim: fix inconsistent carrier state after link/unlink [ Upstream commit d83dddffe1904e4a576d11a541878850a8e64cd2 ] This patch fixes the edge case behavior on ifup/ifdown and linking/unlinking two netdevsim interfaces: 1. unlink two interfaces netdevsim1 and netdevsim2 2. ifdown netdevsim1 3. ifup netdevsim1 4. link two interfaces netdevsim1 and netdevsim2 5. (Now two interfaces are linked in terms of netdevsim peer, but carrier state of the two interfaces remains DOWN.) This inconsistent behavior is caused by the current implementation, which only cares about the "link, then ifup" order, not "ifup, then link" order. This patch fixes the inconsistency by calling netif_carrier_on() when two netdevsim interfaces are linked. This patch fixes buggy behavior on NetworkManager-based systems which causes the netdevsim test to fail with the following error: # timeout set to 600 # selftests: drivers/net/netdevsim: peer.sh # 2025/12/25 00:54:03 socat[9115] W address is opened in read-write mode but only supports read-only # 2025/12/25 00:56:17 socat[9115] W connect(7, AF=2 192.168.1.1:1234, 16): Connection timed out # 2025/12/25 00:56:17 socat[9115] E TCP:192.168.1.1:1234: Connection timed out # expected 3 bytes, got 0 # 2025/12/25 00:56:17 socat[9109] W exiting on signal 15 not ok 13 selftests: drivers/net/netdevsim: peer.sh # exit=1 This patch also solves timeout on TCP Fast Open (TFO) test in NetworkManager-based systems because it also depends on netdevsim's carrier consistency. Fixes: 1a8fed52f7be ("netdevsim: set the carrier when the device goes up") Signed-off-by: Yohei Kojima Reviewed-by: Breno Leitao Link: https://patch.msgid.link/602c9e1ba5bb2ee1997bb38b1d866c9c3b807ae9.1767624906.git.yk@y-koj.net Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- drivers/net/netdevsim/bus.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/net/netdevsim/bus.c b/drivers/net/netdevsim/bus.c index 70e8c38ddad6b..d16b95304aa7e 100644 --- a/drivers/net/netdevsim/bus.c +++ b/drivers/net/netdevsim/bus.c @@ -332,6 +332,11 @@ static ssize_t link_device_store(const struct bus_type *bus, const char *buf, si rcu_assign_pointer(nsim_a->peer, nsim_b); rcu_assign_pointer(nsim_b->peer, nsim_a); + if (netif_running(dev_a) && netif_running(dev_b)) { + netif_carrier_on(dev_a); + netif_carrier_on(dev_b); + } + out_err: put_net(ns_b); put_net(ns_a); @@ -381,6 +386,9 @@ static ssize_t unlink_device_store(const struct bus_type *bus, const char *buf, if (!peer) goto out_put_netns; + netif_carrier_off(dev); + netif_carrier_off(peer->netdev); + err = 0; RCU_INIT_POINTER(nsim->peer, NULL); RCU_INIT_POINTER(peer->peer, NULL); From 6c0d642e8c589bf4ca64b4f4abe1bfe1b9c9be10 Mon Sep 17 00:00:00 2001 From: Caleb Sander Mateos Date: Tue, 6 Jan 2026 13:08:37 -0700 Subject: [PATCH 1910/2333] block: don't merge bios with different app_tags [ Upstream commit 6acd4ac5f8f0ec9b946875553e52907700bcfc77 ] nvme_set_app_tag() uses the app_tag value from the bio_integrity_payload of the struct request's first bio. This assumes all the request's bios have the same app_tag. However, it is possible for bios with different app_tag values to be merged into a single request. Add a check in blk_integrity_merge_{bio,rq}() to prevent the merging of bios/requests with different app_tag values if BIP_CHECK_APPTAG is set. Signed-off-by: Caleb Sander Mateos Fixes: 3d8b5a22d404 ("block: add support to pass user meta buffer") Signed-off-by: Jens Axboe Signed-off-by: Sasha Levin --- block/blk-integrity.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/block/blk-integrity.c b/block/blk-integrity.c index 9b27963680dc3..964eebbee14d0 100644 --- a/block/blk-integrity.c +++ b/block/blk-integrity.c @@ -140,14 +140,21 @@ EXPORT_SYMBOL_GPL(blk_rq_integrity_map_user); bool blk_integrity_merge_rq(struct request_queue *q, struct request *req, struct request *next) { + struct bio_integrity_payload *bip, *bip_next; + if (blk_integrity_rq(req) == 0 && blk_integrity_rq(next) == 0) return true; if (blk_integrity_rq(req) == 0 || blk_integrity_rq(next) == 0) return false; - if (bio_integrity(req->bio)->bip_flags != - bio_integrity(next->bio)->bip_flags) + bip = bio_integrity(req->bio); + bip_next = bio_integrity(next->bio); + if (bip->bip_flags != bip_next->bip_flags) + return false; + + if (bip->bip_flags & BIP_CHECK_APPTAG && + bip->app_tag != bip_next->app_tag) return false; if (req->nr_integrity_segments + next->nr_integrity_segments > @@ -163,15 +170,21 @@ bool blk_integrity_merge_rq(struct request_queue *q, struct request *req, bool blk_integrity_merge_bio(struct request_queue *q, struct request *req, struct bio *bio) { + struct bio_integrity_payload *bip, *bip_bio = bio_integrity(bio); int nr_integrity_segs; - if (blk_integrity_rq(req) == 0 && bio_integrity(bio) == NULL) + if (blk_integrity_rq(req) == 0 && bip_bio == NULL) return true; - if (blk_integrity_rq(req) == 0 || bio_integrity(bio) == NULL) + if (blk_integrity_rq(req) == 0 || bip_bio == NULL) + return false; + + bip = bio_integrity(req->bio); + if (bip->bip_flags != bip_bio->bip_flags) return false; - if (bio_integrity(req->bio)->bip_flags != bio_integrity(bio)->bip_flags) + if (bip->bip_flags & BIP_CHECK_APPTAG && + bip->app_tag != bip_bio->app_tag) return false; nr_integrity_segs = blk_rq_count_integrity_sg(q, bio); From 397691633112c6ea3b458211a58f79f678bbeaef Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Tue, 6 Jan 2026 23:10:54 +0000 Subject: [PATCH 1911/2333] trace: ftrace_dump_on_oops[] is not exported, make it static [ Upstream commit 1e2ed4bfd50ace3c4272cfab7e9aa90956fb7ae0 ] The ftrace_dump_on_oops string is not used outside of trace.c so make it static to avoid the export warning from sparse: kernel/trace/trace.c:141:6: warning: symbol 'ftrace_dump_on_oops' was not declared. Should it be static? Fixes: dd293df6395a2 ("tracing: Move trace sysctls into trace.c") Link: https://patch.msgid.link/20260106231054.84270-1-ben.dooks@codethink.co.uk Signed-off-by: Ben Dooks Signed-off-by: Steven Rostedt (Google) Signed-off-by: Sasha Levin --- kernel/trace/trace.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index ddff2af3cd3f7..142e3b737f0bc 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -141,7 +141,7 @@ cpumask_var_t __read_mostly tracing_buffer_mask; * by commas. */ /* Set to string format zero to disable by default */ -char ftrace_dump_on_oops[MAX_TRACER_SIZE] = "0"; +static char ftrace_dump_on_oops[MAX_TRACER_SIZE] = "0"; /* When set, tracing will stop when a WARN*() is hit */ static int __disable_trace_on_warning; From fb08fec72131991bf55c9aee42df3c17669bc634 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Mon, 24 Nov 2025 19:04:11 +0200 Subject: [PATCH 1912/2333] sparc/PCI: Correct 64-bit non-pref -> pref BAR resources MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit bdb32359eab94013e80cf7e3d40a3fd4972da93a ] SPARC T5-2 dts describes some PCI BARs as 64-bit resources without the pref(etchable) bit (0x83... vs 0xc3... in assigned-addresses) for address ranges above the 4G threshold. Such resources cannot be placed into a non-prefetchable PCI bridge window that is capable only of 32-bit addressing. As such, it looks like the platform is improperly described by the dts. The kernel detects this problem (see the IORESOURCE_PREFETCH check in pci_find_parent_resource()) and fails to assign these BAR resources to the resource tree due to lack of a compatible bridge window. Prior to 754babaaf333 ("sparc/PCI: Remove pcibios_enable_device() as they do nothing extra") SPARC arch code did not test whether device resources were successfully in the resource tree when enabling a device, effectively hiding the problem. After removing the arch-specific enable code, pci_enable_resources() refuses to enable the device when it finds not all mem resources are assigned, and therefore mpt3sas can't be enabled: pci 0001:04:00.0: reg 0x14: [mem 0x801110000000-0x80111000ffff 64bit] pci 0001:04:00.0: reg 0x1c: [mem 0x801110040000-0x80111007ffff 64bit] pci 0001:04:00.0: BAR 1 [mem 0x801110000000-0x80111000ffff 64bit]: can't claim; no compatible bridge window pci 0001:04:00.0: BAR 3 [mem 0x801110040000-0x80111007ffff 64bit]: can't claim; no compatible bridge window mpt3sas 0001:04:00.0: BAR 1 [mem size 0x00010000 64bit]: not assigned; can't enable device For clarity, this filtered log only shows failures for one mpt3sas device but other devices fail similarly. In the reported case, the end result with all the failures is an unbootable system. Things appeared to "work" before 754babaaf333 ("sparc/PCI: Remove pcibios_enable_device() as they do nothing extra") because the resource tree is agnostic to whether PCI BAR resources are properly in the tree or not. So as long as there was a parent resource (e.g. a root bus resource) that contains the address range, the resource tree code just places resource request underneath it without any consideration to the intermediate BAR resource. While it worked, it's incorrect setup still. Add an OF fixup to set the IORESOURCE_PREFETCH flag for a 64-bit PCI resource that has the end address above 4G requiring placement into the prefetchable window. Also log the issue. Fixes: 754babaaf333 ("sparc/PCI: Remove pcibios_enable_device() as they do nothing extra") Reported-by: Nathaniel Roach Closes: https://github.com/sparclinux/issues/issues/22 Signed-off-by: Ilpo Järvinen Signed-off-by: Bjorn Helgaas Tested-by: Nathaniel Roach Link: https://patch.msgid.link/20251124170411.3709-1-ilpo.jarvinen@linux.intel.com Signed-off-by: Sasha Levin --- arch/sparc/kernel/pci.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/arch/sparc/kernel/pci.c b/arch/sparc/kernel/pci.c index a9448088e762e..b290107170e94 100644 --- a/arch/sparc/kernel/pci.c +++ b/arch/sparc/kernel/pci.c @@ -181,6 +181,28 @@ static int __init ofpci_debug(char *str) __setup("ofpci_debug=", ofpci_debug); +static void of_fixup_pci_pref(struct pci_dev *dev, int index, + struct resource *res) +{ + struct pci_bus_region region; + + if (!(res->flags & IORESOURCE_MEM_64)) + return; + + if (!resource_size(res)) + return; + + pcibios_resource_to_bus(dev->bus, ®ion, res); + if (region.end <= ~((u32)0)) + return; + + if (!(res->flags & IORESOURCE_PREFETCH)) { + res->flags |= IORESOURCE_PREFETCH; + pci_info(dev, "reg 0x%x: fixup: pref added to 64-bit resource\n", + index); + } +} + static unsigned long pci_parse_of_flags(u32 addr0) { unsigned long flags = 0; @@ -244,6 +266,7 @@ static void pci_parse_of_addrs(struct platform_device *op, res->end = op_res->end; res->flags = flags; res->name = pci_name(dev); + of_fixup_pci_pref(dev, i, res); pci_info(dev, "reg 0x%x: %pR\n", i, res); } From 9e17d06663f3c316248435b9d9b972c09db35f2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Rebe?= Date: Fri, 28 Nov 2025 13:46:41 +0100 Subject: [PATCH 1913/2333] HID: quirks: work around VID/PID conflict for appledisplay MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit c7fabe4ad9219866c203164a214c474c95b36bf2 ] For years I wondered why the Apple Cinema Display driver would not just work for me. Turns out the hidraw driver instantly takes it over. Fix by adding appledisplay VID/PIDs to hid_have_special_driver. Fixes: 069e8a65cd79 ("Driver for Apple Cinema Display") Signed-off-by: René Rebe Signed-off-by: Jiri Kosina Signed-off-by: Sasha Levin --- drivers/hid/hid-quirks.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c index c89a015686c07..6a8a7ca3d8047 100644 --- a/drivers/hid/hid-quirks.c +++ b/drivers/hid/hid-quirks.c @@ -232,6 +232,15 @@ static const struct hid_device_id hid_quirks[] = { * used as a driver. See hid_scan_report(). */ static const struct hid_device_id hid_have_special_driver[] = { +#if IS_ENABLED(CONFIG_APPLEDISPLAY) + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, 0x9218) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, 0x9219) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, 0x921c) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, 0x921d) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, 0x9222) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, 0x9226) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, 0x9236) }, +#endif #if IS_ENABLED(CONFIG_HID_A4TECH) { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU) }, { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_X5_005D) }, From 72f93dc6d1a6b157e0c3d247085c74935893cca0 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 5 Jan 2026 09:43:31 +0100 Subject: [PATCH 1914/2333] net: airoha: Fix schedule while atomic in airoha_ppe_deinit() [ Upstream commit 6abcf751bc084804a9e5b3051442e8a2ce67f48a ] airoha_ppe_deinit() runs airoha_npu_ppe_deinit() in atomic context. airoha_npu_ppe_deinit routine allocates ppe_data buffer with GFP_KERNEL flag. Rely on rcu_replace_pointer in airoha_ppe_deinit routine in order to fix schedule while atomic issue in airoha_npu_ppe_deinit() since we do not need atomic context there. Fixes: 00a7678310fe3 ("net: airoha: Introduce flowtable offload support") Signed-off-by: Lorenzo Bianconi Link: https://patch.msgid.link/20260105-airoha-fw-ethtool-v2-1-3b32b158cc31@kernel.org Signed-off-by: Paolo Abeni Signed-off-by: Sasha Levin --- drivers/net/ethernet/airoha/airoha_ppe.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/airoha/airoha_ppe.c b/drivers/net/ethernet/airoha/airoha_ppe.c index c0e17035db18e..190d98970014f 100644 --- a/drivers/net/ethernet/airoha/airoha_ppe.c +++ b/drivers/net/ethernet/airoha/airoha_ppe.c @@ -1466,13 +1466,16 @@ void airoha_ppe_deinit(struct airoha_eth *eth) { struct airoha_npu *npu; - rcu_read_lock(); - npu = rcu_dereference(eth->npu); + mutex_lock(&flow_offload_mutex); + + npu = rcu_replace_pointer(eth->npu, NULL, + lockdep_is_held(&flow_offload_mutex)); if (npu) { npu->ops.ppe_deinit(npu); airoha_npu_put(npu); } - rcu_read_unlock(); + + mutex_unlock(&flow_offload_mutex); rhashtable_destroy(ð->ppe->l2_flows); rhashtable_destroy(ð->flow_table); From 1251bbdb8f5b2ea86ca9b4268a2e6aa34372ab33 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Wed, 7 Jan 2026 14:36:51 +0100 Subject: [PATCH 1915/2333] wifi: mac80211_hwsim: fix typo in frequency notification [ Upstream commit 333418872bfecf4843f1ded7a4151685dfcf07d5 ] The NAN notification is for 5745 MHz which corresponds to channel 149 and not 5475 which is not actually a valid channel. This could result in a NULL pointer dereference in cfg80211_next_nan_dw_notif. Fixes: a37a6f54439b ("wifi: mac80211_hwsim: Add simulation support for NAN device") Signed-off-by: Benjamin Berg Reviewed-by: Ilan Peer Reviewed-by: Miriam Rachel Korenblit Link: https://patch.msgid.link/20260107143652.7dab2035836f.Iacbaf7bb94ed5c14a0928a625827e4137d8bfede@changeid Signed-off-by: Johannes Berg Signed-off-by: Sasha Levin --- drivers/net/wireless/virtual/mac80211_hwsim.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/virtual/mac80211_hwsim.c b/drivers/net/wireless/virtual/mac80211_hwsim.c index 5903d82e1ab1e..2f263d89d2d69 100644 --- a/drivers/net/wireless/virtual/mac80211_hwsim.c +++ b/drivers/net/wireless/virtual/mac80211_hwsim.c @@ -4040,7 +4040,7 @@ mac80211_hwsim_nan_dw_start(struct hrtimer *timer) ieee80211_vif_to_wdev(data->nan_device_vif); if (data->nan_curr_dw_band == NL80211_BAND_5GHZ) - ch = ieee80211_get_channel(hw->wiphy, 5475); + ch = ieee80211_get_channel(hw->wiphy, 5745); else ch = ieee80211_get_channel(hw->wiphy, 2437); From 51ffd447bc37bf1a5776b85523f51d2bc69977f6 Mon Sep 17 00:00:00 2001 From: Xiang Mei Date: Mon, 5 Jan 2026 20:41:00 -0700 Subject: [PATCH 1916/2333] net/sched: sch_qfq: Fix NULL deref when deactivating inactive aggregate in qfq_reset [ Upstream commit c1d73b1480235731e35c81df70b08f4714a7d095 ] `qfq_class->leaf_qdisc->q.qlen > 0` does not imply that the class itself is active. Two qfq_class objects may point to the same leaf_qdisc. This happens when: 1. one QFQ qdisc is attached to the dev as the root qdisc, and 2. another QFQ qdisc is temporarily referenced (e.g., via qdisc_get() / qdisc_put()) and is pending to be destroyed, as in function tc_new_tfilter. When packets are enqueued through the root QFQ qdisc, the shared leaf_qdisc->q.qlen increases. At the same time, the second QFQ qdisc triggers qdisc_put and qdisc_destroy: the qdisc enters qfq_reset() with its own q->q.qlen == 0, but its class's leaf qdisc->q.qlen > 0. Therefore, the qfq_reset would wrongly deactivate an inactive aggregate and trigger a null-deref in qfq_deactivate_agg: [ 0.903172] BUG: kernel NULL pointer dereference, address: 0000000000000000 [ 0.903571] #PF: supervisor write access in kernel mode [ 0.903860] #PF: error_code(0x0002) - not-present page [ 0.904177] PGD 10299b067 P4D 10299b067 PUD 10299c067 PMD 0 [ 0.904502] Oops: Oops: 0002 [#1] SMP NOPTI [ 0.904737] CPU: 0 UID: 0 PID: 135 Comm: exploit Not tainted 6.19.0-rc3+ #2 NONE [ 0.905157] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.17.0-0-gb52ca86e094d-prebuilt.qemu.org 04/01/2014 [ 0.905754] RIP: 0010:qfq_deactivate_agg (include/linux/list.h:992 (discriminator 2) include/linux/list.h:1006 (discriminator 2) net/sched/sch_qfq.c:1367 (discriminator 2) net/sched/sch_qfq.c:1393 (discriminator 2)) [ 0.906046] Code: 0f 84 4d 01 00 00 48 89 70 18 8b 4b 10 48 c7 c2 ff ff ff ff 48 8b 78 08 48 d3 e2 48 21 f2 48 2b 13 48 8b 30 48 d3 ea 8b 4b 18 0 Code starting with the faulting instruction =========================================== 0: 0f 84 4d 01 00 00 je 0x153 6: 48 89 70 18 mov %rsi,0x18(%rax) a: 8b 4b 10 mov 0x10(%rbx),%ecx d: 48 c7 c2 ff ff ff ff mov $0xffffffffffffffff,%rdx 14: 48 8b 78 08 mov 0x8(%rax),%rdi 18: 48 d3 e2 shl %cl,%rdx 1b: 48 21 f2 and %rsi,%rdx 1e: 48 2b 13 sub (%rbx),%rdx 21: 48 8b 30 mov (%rax),%rsi 24: 48 d3 ea shr %cl,%rdx 27: 8b 4b 18 mov 0x18(%rbx),%ecx ... [ 0.907095] RSP: 0018:ffffc900004a39a0 EFLAGS: 00010246 [ 0.907368] RAX: ffff8881043a0880 RBX: ffff888102953340 RCX: 0000000000000000 [ 0.907723] RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000000 [ 0.908100] RBP: ffff888102952180 R08: 0000000000000000 R09: 0000000000000000 [ 0.908451] R10: ffff8881043a0000 R11: 0000000000000000 R12: ffff888102952000 [ 0.908804] R13: ffff888102952180 R14: ffff8881043a0ad8 R15: ffff8881043a0880 [ 0.909179] FS: 000000002a1a0380(0000) GS:ffff888196d8d000(0000) knlGS:0000000000000000 [ 0.909572] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 0.909857] CR2: 0000000000000000 CR3: 0000000102993002 CR4: 0000000000772ef0 [ 0.910247] PKRU: 55555554 [ 0.910391] Call Trace: [ 0.910527] [ 0.910638] qfq_reset_qdisc (net/sched/sch_qfq.c:357 net/sched/sch_qfq.c:1485) [ 0.910826] qdisc_reset (include/linux/skbuff.h:2195 include/linux/skbuff.h:2501 include/linux/skbuff.h:3424 include/linux/skbuff.h:3430 net/sched/sch_generic.c:1036) [ 0.911040] __qdisc_destroy (net/sched/sch_generic.c:1076) [ 0.911236] tc_new_tfilter (net/sched/cls_api.c:2447) [ 0.911447] rtnetlink_rcv_msg (net/core/rtnetlink.c:6958) [ 0.911663] ? __pfx_rtnetlink_rcv_msg (net/core/rtnetlink.c:6861) [ 0.911894] netlink_rcv_skb (net/netlink/af_netlink.c:2550) [ 0.912100] netlink_unicast (net/netlink/af_netlink.c:1319 net/netlink/af_netlink.c:1344) [ 0.912296] ? __alloc_skb (net/core/skbuff.c:706) [ 0.912484] netlink_sendmsg (net/netlink/af_netlink.c:1894) [ 0.912682] sock_write_iter (net/socket.c:727 (discriminator 1) net/socket.c:742 (discriminator 1) net/socket.c:1195 (discriminator 1)) [ 0.912880] vfs_write (fs/read_write.c:593 fs/read_write.c:686) [ 0.913077] ksys_write (fs/read_write.c:738) [ 0.913252] do_syscall_64 (arch/x86/entry/syscall_64.c:63 (discriminator 1) arch/x86/entry/syscall_64.c:94 (discriminator 1)) [ 0.913438] entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:131) [ 0.913687] RIP: 0033:0x424c34 [ 0.913844] Code: 89 02 48 c7 c0 ff ff ff ff eb bd 66 2e 0f 1f 84 00 00 00 00 00 90 f3 0f 1e fa 80 3d 2d 44 09 00 00 74 13 b8 01 00 00 00 0f 05 9 Code starting with the faulting instruction =========================================== 0: 89 02 mov %eax,(%rdx) 2: 48 c7 c0 ff ff ff ff mov $0xffffffffffffffff,%rax 9: eb bd jmp 0xffffffffffffffc8 b: 66 2e 0f 1f 84 00 00 cs nopw 0x0(%rax,%rax,1) 12: 00 00 00 15: 90 nop 16: f3 0f 1e fa endbr64 1a: 80 3d 2d 44 09 00 00 cmpb $0x0,0x9442d(%rip) # 0x9444e 21: 74 13 je 0x36 23: b8 01 00 00 00 mov $0x1,%eax 28: 0f 05 syscall 2a: 09 .byte 0x9 [ 0.914807] RSP: 002b:00007ffea1938b78 EFLAGS: 00000202 ORIG_RAX: 0000000000000001 [ 0.915197] RAX: ffffffffffffffda RBX: 0000000000000001 RCX: 0000000000424c34 [ 0.915556] RDX: 000000000000003c RSI: 000000002af378c0 RDI: 0000000000000003 [ 0.915912] RBP: 00007ffea1938bc0 R08: 00000000004b8820 R09: 0000000000000000 [ 0.916297] R10: 0000000000000001 R11: 0000000000000202 R12: 00007ffea1938d28 [ 0.916652] R13: 00007ffea1938d38 R14: 00000000004b3828 R15: 0000000000000001 [ 0.917039] [ 0.917158] Modules linked in: [ 0.917316] CR2: 0000000000000000 [ 0.917484] ---[ end trace 0000000000000000 ]--- [ 0.917717] RIP: 0010:qfq_deactivate_agg (include/linux/list.h:992 (discriminator 2) include/linux/list.h:1006 (discriminator 2) net/sched/sch_qfq.c:1367 (discriminator 2) net/sched/sch_qfq.c:1393 (discriminator 2)) [ 0.917978] Code: 0f 84 4d 01 00 00 48 89 70 18 8b 4b 10 48 c7 c2 ff ff ff ff 48 8b 78 08 48 d3 e2 48 21 f2 48 2b 13 48 8b 30 48 d3 ea 8b 4b 18 0 Code starting with the faulting instruction =========================================== 0: 0f 84 4d 01 00 00 je 0x153 6: 48 89 70 18 mov %rsi,0x18(%rax) a: 8b 4b 10 mov 0x10(%rbx),%ecx d: 48 c7 c2 ff ff ff ff mov $0xffffffffffffffff,%rdx 14: 48 8b 78 08 mov 0x8(%rax),%rdi 18: 48 d3 e2 shl %cl,%rdx 1b: 48 21 f2 and %rsi,%rdx 1e: 48 2b 13 sub (%rbx),%rdx 21: 48 8b 30 mov (%rax),%rsi 24: 48 d3 ea shr %cl,%rdx 27: 8b 4b 18 mov 0x18(%rbx),%ecx ... [ 0.918902] RSP: 0018:ffffc900004a39a0 EFLAGS: 00010246 [ 0.919198] RAX: ffff8881043a0880 RBX: ffff888102953340 RCX: 0000000000000000 [ 0.919559] RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000000 [ 0.919908] RBP: ffff888102952180 R08: 0000000000000000 R09: 0000000000000000 [ 0.920289] R10: ffff8881043a0000 R11: 0000000000000000 R12: ffff888102952000 [ 0.920648] R13: ffff888102952180 R14: ffff8881043a0ad8 R15: ffff8881043a0880 [ 0.921014] FS: 000000002a1a0380(0000) GS:ffff888196d8d000(0000) knlGS:0000000000000000 [ 0.921424] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 0.921710] CR2: 0000000000000000 CR3: 0000000102993002 CR4: 0000000000772ef0 [ 0.922097] PKRU: 55555554 [ 0.922240] Kernel panic - not syncing: Fatal exception [ 0.922590] Kernel Offset: disabled Fixes: 0545a3037773 ("pkt_sched: QFQ - quick fair queue scheduler") Signed-off-by: Xiang Mei Link: https://patch.msgid.link/20260106034100.1780779-1-xmei5@asu.edu Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- net/sched/sch_qfq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/sched/sch_qfq.c b/net/sched/sch_qfq.c index 2255355e51d35..a91a5bac8f737 100644 --- a/net/sched/sch_qfq.c +++ b/net/sched/sch_qfq.c @@ -1481,7 +1481,7 @@ static void qfq_reset_qdisc(struct Qdisc *sch) for (i = 0; i < q->clhash.hashsize; i++) { hlist_for_each_entry(cl, &q->clhash.hash[i], common.hnode) { - if (cl->qdisc->q.qlen > 0) + if (cl_is_active(cl)) qfq_deactivate_class(q, cl); qdisc_reset(cl->qdisc); From ce6eef731aba23a988decea1df3b08cf978f7b01 Mon Sep 17 00:00:00 2001 From: Petko Manolov Date: Tue, 6 Jan 2026 10:48:21 +0200 Subject: [PATCH 1917/2333] net: usb: pegasus: fix memory leak in update_eth_regs_async() [ Upstream commit afa27621a28af317523e0836dad430bec551eb54 ] When asynchronously writing to the device registers and if usb_submit_urb() fail, the code fail to release allocated to this point resources. Fixes: 323b34963d11 ("drivers: net: usb: pegasus: fix control urb submission") Signed-off-by: Petko Manolov Link: https://patch.msgid.link/20260106084821.3746677-1-petko.manolov@konsulko.com Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- drivers/net/usb/pegasus.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/usb/pegasus.c b/drivers/net/usb/pegasus.c index 81ca64debc5b9..c514483134f05 100644 --- a/drivers/net/usb/pegasus.c +++ b/drivers/net/usb/pegasus.c @@ -168,6 +168,8 @@ static int update_eth_regs_async(pegasus_t *pegasus) netif_device_detach(pegasus->net); netif_err(pegasus, drv, pegasus->net, "%s returned %d\n", __func__, ret); + usb_free_urb(async_urb); + kfree(req); } return ret; } From d93ba83fc3f5b9a8314ba7b8f633aac7ffb92107 Mon Sep 17 00:00:00 2001 From: Wei Fang Date: Wed, 7 Jan 2026 17:12:04 +0800 Subject: [PATCH 1918/2333] net: enetc: fix build warning when PAGE_SIZE is greater than 128K [ Upstream commit 4b5bdabb5449b652122e43f507f73789041d4abe ] The max buffer size of ENETC RX BD is 0xFFFF bytes, so if the PAGE_SIZE is greater than 128K, ENETC_RXB_DMA_SIZE and ENETC_RXB_DMA_SIZE_XDP will be greater than 0xFFFF, thus causing a build warning. This will not cause any practical issues because ENETC is currently only used on the ARM64 platform, and the max PAGE_SIZE is 64K. So this patch is only for fixing the build warning that occurs when compiling ENETC drivers for other platforms. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202601050637.kHEKKOG7-lkp@intel.com/ Fixes: e59bc32df2e9 ("net: enetc: correct the value of ENETC_RXB_TRUESIZE") Signed-off-by: Wei Fang Reviewed-by: Frank Li Link: https://patch.msgid.link/20260107091204.1980222-1-wei.fang@nxp.com Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- drivers/net/ethernet/freescale/enetc/enetc.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/freescale/enetc/enetc.h b/drivers/net/ethernet/freescale/enetc/enetc.h index f279fa597991e..60c7205ea9ff5 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc.h +++ b/drivers/net/ethernet/freescale/enetc/enetc.h @@ -79,9 +79,9 @@ struct enetc_lso_t { #define ENETC_RXB_TRUESIZE (PAGE_SIZE >> 1) #define ENETC_RXB_PAD NET_SKB_PAD /* add extra space if needed */ #define ENETC_RXB_DMA_SIZE \ - (SKB_WITH_OVERHEAD(ENETC_RXB_TRUESIZE) - ENETC_RXB_PAD) + min(SKB_WITH_OVERHEAD(ENETC_RXB_TRUESIZE) - ENETC_RXB_PAD, 0xffff) #define ENETC_RXB_DMA_SIZE_XDP \ - (SKB_WITH_OVERHEAD(ENETC_RXB_TRUESIZE) - XDP_PACKET_HEADROOM) + min(SKB_WITH_OVERHEAD(ENETC_RXB_TRUESIZE) - XDP_PACKET_HEADROOM, 0xffff) struct enetc_rx_swbd { dma_addr_t dma; From 949647e7771a4a01963fe953a96d81fba7acecf3 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 7 Jan 2026 21:22:50 +0000 Subject: [PATCH 1919/2333] arp: do not assume dev_hard_header() does not change skb->head [ Upstream commit c92510f5e3f82ba11c95991824a41e59a9c5ed81 ] arp_create() is the only dev_hard_header() caller making assumption about skb->head being unchanged. A recent commit broke this assumption. Initialize @arp pointer after dev_hard_header() call. Fixes: db5b4e39c4e6 ("ip6_gre: make ip6gre_header() robust") Reported-by: syzbot+58b44a770a1585795351@syzkaller.appspotmail.com Signed-off-by: Eric Dumazet Link: https://patch.msgid.link/20260107212250.384552-1-edumazet@google.com Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- net/ipv4/arp.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index 833f2cf97178e..3ce1664e8632a 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -564,7 +564,7 @@ struct sk_buff *arp_create(int type, int ptype, __be32 dest_ip, skb_reserve(skb, hlen); skb_reset_network_header(skb); - arp = skb_put(skb, arp_hdr_len(dev)); + skb_put(skb, arp_hdr_len(dev)); skb->dev = dev; skb->protocol = htons(ETH_P_ARP); if (!src_hw) @@ -572,12 +572,13 @@ struct sk_buff *arp_create(int type, int ptype, __be32 dest_ip, if (!dest_hw) dest_hw = dev->broadcast; - /* - * Fill the device header for the ARP frame + /* Fill the device header for the ARP frame. + * Note: skb->head can be changed. */ if (dev_hard_header(skb, dev, ptype, dest_hw, src_hw, skb->len) < 0) goto out; + arp = arp_hdr(skb); /* * Fill out the arp protocol part. * From 72e28774e9644c2bdbb4920842fbf77103a15a85 Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Fri, 9 Jan 2026 20:14:54 +0800 Subject: [PATCH 1920/2333] ublk: fix use-after-free in ublk_partition_scan_work [ Upstream commit f0d385f6689f37a2828c686fb279121df006b4cb ] A race condition exists between the async partition scan work and device teardown that can lead to a use-after-free of ub->ub_disk: 1. ublk_ctrl_start_dev() schedules partition_scan_work after add_disk() 2. ublk_stop_dev() calls ublk_stop_dev_unlocked() which does: - del_gendisk(ub->ub_disk) - ublk_detach_disk() sets ub->ub_disk = NULL - put_disk() which may free the disk 3. The worker ublk_partition_scan_work() then dereferences ub->ub_disk leading to UAF Fix this by using ublk_get_disk()/ublk_put_disk() in the worker to hold a reference to the disk during the partition scan. The spinlock in ublk_get_disk() synchronizes with ublk_detach_disk() ensuring the worker either gets a valid reference or sees NULL and exits early. Also change flush_work() to cancel_work_sync() to avoid running the partition scan work unnecessarily when the disk is already detached. Fixes: 7fc4da6a304b ("ublk: scan partition in async way") Reported-by: Ruikai Peng Signed-off-by: Ming Lei Signed-off-by: Jens Axboe Signed-off-by: Sasha Levin --- drivers/block/ublk_drv.c | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c index babb58d2dcaf7..e09c1b5999b75 100644 --- a/drivers/block/ublk_drv.c +++ b/drivers/block/ublk_drv.c @@ -255,20 +255,6 @@ static inline struct request *__ublk_check_and_get_req(struct ublk_device *ub, u16 q_id, u16 tag, struct ublk_io *io, size_t offset); static inline unsigned int ublk_req_build_flags(struct request *req); -static void ublk_partition_scan_work(struct work_struct *work) -{ - struct ublk_device *ub = - container_of(work, struct ublk_device, partition_scan_work); - - if (WARN_ON_ONCE(!test_and_clear_bit(GD_SUPPRESS_PART_SCAN, - &ub->ub_disk->state))) - return; - - mutex_lock(&ub->ub_disk->open_mutex); - bdev_disk_changed(ub->ub_disk, false); - mutex_unlock(&ub->ub_disk->open_mutex); -} - static inline struct ublksrv_io_desc * ublk_get_iod(const struct ublk_queue *ubq, unsigned tag) { @@ -1663,6 +1649,27 @@ static void ublk_put_disk(struct gendisk *disk) put_device(disk_to_dev(disk)); } +static void ublk_partition_scan_work(struct work_struct *work) +{ + struct ublk_device *ub = + container_of(work, struct ublk_device, partition_scan_work); + /* Hold disk reference to prevent UAF during concurrent teardown */ + struct gendisk *disk = ublk_get_disk(ub); + + if (!disk) + return; + + if (WARN_ON_ONCE(!test_and_clear_bit(GD_SUPPRESS_PART_SCAN, + &disk->state))) + goto out; + + mutex_lock(&disk->open_mutex); + bdev_disk_changed(disk, false); + mutex_unlock(&disk->open_mutex); +out: + ublk_put_disk(disk); +} + /* * Use this function to ensure that ->canceling is consistently set for * the device and all queues. Do not set these flags directly. @@ -2107,7 +2114,7 @@ static void ublk_stop_dev(struct ublk_device *ub) mutex_lock(&ub->mutex); ublk_stop_dev_unlocked(ub); mutex_unlock(&ub->mutex); - flush_work(&ub->partition_scan_work); + cancel_work_sync(&ub->partition_scan_work); ublk_cancel_dev(ub); } From 234409e0db771c77c861134ea7c22c90a411c6eb Mon Sep 17 00:00:00 2001 From: Lorenzo Pieralisi Date: Mon, 22 Dec 2025 11:22:50 +0100 Subject: [PATCH 1921/2333] irqchip/gic-v5: Fix gicv5_its_map_event() ITTE read endianness [ Upstream commit 1690eeb0cb2bb77096cb6c826b6849ef05013e34 ] Kbuild bot (through sparse) reported that the ITTE read to carry out a valid check in gicv5_its_map_event() lacks proper endianness handling. Add the missing endianess conversion. Fixes: 57d72196dfc8 ("irqchip/gic-v5: Add GICv5 ITS support") Reported-by: kernel test robot Signed-off-by: Lorenzo Pieralisi Signed-off-by: Thomas Gleixner Acked-by: Marc Zyngier Link: https://patch.msgid.link/20251222102250.435460-1-lpieralisi@kernel.org Closes: https://lore.kernel.org/oe-kbuild-all/202512131849.30ZRTBeR-lkp@intel.com/ Signed-off-by: Sasha Levin --- drivers/irqchip/irq-gic-v5-its.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/irqchip/irq-gic-v5-its.c b/drivers/irqchip/irq-gic-v5-its.c index 554485f0be1fb..8e22134b9f486 100644 --- a/drivers/irqchip/irq-gic-v5-its.c +++ b/drivers/irqchip/irq-gic-v5-its.c @@ -849,7 +849,7 @@ static int gicv5_its_map_event(struct gicv5_its_dev *its_dev, u16 event_id, u32 itte = gicv5_its_device_get_itte_ref(its_dev, event_id); - if (FIELD_GET(GICV5_ITTL2E_VALID, *itte)) + if (FIELD_GET(GICV5_ITTL2E_VALID, le64_to_cpu(*itte))) return -EEXIST; itt_entry = FIELD_PREP(GICV5_ITTL2E_LPI_ID, lpi) | From c65f0bafc98f1dab9d03d5a013bc06f168908c05 Mon Sep 17 00:00:00 2001 From: Gao Xiang Date: Thu, 8 Jan 2026 10:38:31 +0800 Subject: [PATCH 1922/2333] erofs: don't bother with s_stack_depth increasing for now MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 072a7c7cdbea4f91df854ee2bb216256cd619f2a ] Previously, commit d53cd891f0e4 ("erofs: limit the level of fs stacking for file-backed mounts") bumped `s_stack_depth` by one to avoid kernel stack overflow when stacking an unlimited number of EROFS on top of each other. This fix breaks composefs mounts, which need EROFS+ovl^2 sometimes (and such setups are already used in production for quite a long time). One way to fix this regression is to bump FILESYSTEM_MAX_STACK_DEPTH from 2 to 3, but proving that this is safe in general is a high bar. After a long discussion on GitHub issues [1] about possible solutions, one conclusion is that there is no need to support nesting file-backed EROFS mounts on stacked filesystems, because there is always the option to use loopback devices as a fallback. As a quick fix for the composefs regression for this cycle, instead of bumping `s_stack_depth` for file backed EROFS mounts, we disallow nesting file-backed EROFS over EROFS and over filesystems with `s_stack_depth` > 0. This works for all known file-backed mount use cases (composefs, containerd, and Android APEX for some Android vendors), and the fix is self-contained. Essentially, we are allowing one extra unaccounted fs stacking level of EROFS below stacking filesystems, but EROFS can only be used in the read path (i.e. overlayfs lower layers), which typically has much lower stack usage than the write path. We can consider increasing FILESYSTEM_MAX_STACK_DEPTH later, after more stack usage analysis or using alternative approaches, such as splitting the `s_stack_depth` limitation according to different combinations of stacking. Fixes: d53cd891f0e4 ("erofs: limit the level of fs stacking for file-backed mounts") Reported-and-tested-by: Dusty Mabe Reported-by: Timothée Ravier Closes: https://github.com/coreos/fedora-coreos-tracker/issues/2087 [1] Reported-by: "Alekséi Naidénov" Closes: https://lore.kernel.org/r/CAFHtUiYv4+=+JP_-JjARWjo6OwcvBj1wtYN=z0QXwCpec9sXtg@mail.gmail.com Acked-by: Amir Goldstein Acked-by: Alexander Larsson Reviewed-and-tested-by: Sheng Yong Reviewed-by: Zhiguo Niu Reviewed-by: Chao Yu Cc: Christian Brauner Cc: Miklos Szeredi Signed-off-by: Gao Xiang Signed-off-by: Sasha Levin --- fs/erofs/super.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/fs/erofs/super.c b/fs/erofs/super.c index 937a215f626c1..e93264034b5db 100644 --- a/fs/erofs/super.c +++ b/fs/erofs/super.c @@ -644,14 +644,20 @@ static int erofs_fc_fill_super(struct super_block *sb, struct fs_context *fc) * fs contexts (including its own) due to self-controlled RO * accesses/contexts and no side-effect changes that need to * context save & restore so it can reuse the current thread - * context. However, it still needs to bump `s_stack_depth` to - * avoid kernel stack overflow from nested filesystems. + * context. + * However, we still need to prevent kernel stack overflow due + * to filesystem nesting: just ensure that s_stack_depth is 0 + * to disallow mounting EROFS on stacked filesystems. + * Note: s_stack_depth is not incremented here for now, since + * EROFS is the only fs supporting file-backed mounts for now. + * It MUST change if another fs plans to support them, which + * may also require adjusting FILESYSTEM_MAX_STACK_DEPTH. */ if (erofs_is_fileio_mode(sbi)) { - sb->s_stack_depth = - file_inode(sbi->dif0.file)->i_sb->s_stack_depth + 1; - if (sb->s_stack_depth > FILESYSTEM_MAX_STACK_DEPTH) { - erofs_err(sb, "maximum fs stacking depth exceeded"); + inode = file_inode(sbi->dif0.file); + if ((inode->i_sb->s_op == &erofs_sops && !sb->s_bdev) || + inode->i_sb->s_stack_depth) { + erofs_err(sb, "file-backed mounts cannot be applied to stacked fses"); return -ENOTBLK; } } From ebdc9934539969dfbb2e35ab17799dddcfd50efe Mon Sep 17 00:00:00 2001 From: Gao Xiang Date: Sat, 10 Jan 2026 19:47:03 +0800 Subject: [PATCH 1923/2333] erofs: fix file-backed mounts no longer working on EROFS partitions [ Upstream commit 7893cc12251f6f19e7689a4cf3ba803bddbd8437 ] Sheng Yong reported [1] that Android APEX images didn't work with commit 072a7c7cdbea ("erofs: don't bother with s_stack_depth increasing for now") because "EROFS-formatted APEX file images can be stored within an EROFS-formatted Android system partition." In response, I sent a quick fat-fingered [PATCH v3] to address the report. Unfortunately, the updated condition was incorrect: if (erofs_is_fileio_mode(sbi)) { - sb->s_stack_depth = - file_inode(sbi->dif0.file)->i_sb->s_stack_depth + 1; - if (sb->s_stack_depth > FILESYSTEM_MAX_STACK_DEPTH) { - erofs_err(sb, "maximum fs stacking depth exceeded"); + inode = file_inode(sbi->dif0.file); + if ((inode->i_sb->s_op == &erofs_sops && !sb->s_bdev) || + inode->i_sb->s_stack_depth) { The condition `!sb->s_bdev` is always true for all file-backed EROFS mounts, making the check effectively a no-op. The real fix tested and confirmed by Sheng Yong [2] at that time was [PATCH v3 RESEND], which correctly ensures the following EROFS^2 setup works: EROFS (on a block device) + EROFS (file-backed mount) But sadly I screwed it up again by upstreaming the outdated [PATCH v3]. This patch applies the same logic as the delta between the upstream [PATCH v3] and the real fix [PATCH v3 RESEND]. Reported-by: Sheng Yong Closes: https://lore.kernel.org/r/3acec686-4020-4609-aee4-5dae7b9b0093@gmail.com [1] Fixes: 072a7c7cdbea ("erofs: don't bother with s_stack_depth increasing for now") Link: https://lore.kernel.org/r/243f57b8-246f-47e7-9fb1-27a771e8e9e8@gmail.com [2] Signed-off-by: Gao Xiang Signed-off-by: Linus Torvalds Signed-off-by: Sasha Levin --- fs/erofs/super.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/erofs/super.c b/fs/erofs/super.c index e93264034b5db..5136cda5972a9 100644 --- a/fs/erofs/super.c +++ b/fs/erofs/super.c @@ -655,7 +655,8 @@ static int erofs_fc_fill_super(struct super_block *sb, struct fs_context *fc) */ if (erofs_is_fileio_mode(sbi)) { inode = file_inode(sbi->dif0.file); - if ((inode->i_sb->s_op == &erofs_sops && !sb->s_bdev) || + if ((inode->i_sb->s_op == &erofs_sops && + !inode->i_sb->s_bdev) || inode->i_sb->s_stack_depth) { erofs_err(sb, "file-backed mounts cannot be applied to stacked fses"); return -ENOTBLK; From 3b7ca18f350970132cd31a634b811ea30c8735b0 Mon Sep 17 00:00:00 2001 From: Filipe Manana Date: Mon, 12 Jan 2026 08:54:49 -0500 Subject: [PATCH 1924/2333] btrfs: truncate ordered extent when skipping writeback past i_size [ Upstream commit 18de34daa7c62c830be533aace6b7c271e8e95cf ] While running test case btrfs/192 from fstests with support for large folios (needs CONFIG_BTRFS_EXPERIMENTAL=y) I ended up getting very sporadic btrfs check failures reporting that csum items were missing. Looking into the issue it turned out that btrfs check searches for csum items of a file extent item with a range that spans beyond the i_size of a file and we don't have any, because the kernel's writeback code skips submitting bios for ranges beyond eof. It's not expected however to find a file extent item that crosses the rounded up (by the sector size) i_size value, but there is a short time window where we can end up with a transaction commit leaving this small inconsistency between the i_size and the last file extent item. Example btrfs check output when this happens: $ btrfs check /dev/sdc Opening filesystem to check... Checking filesystem on /dev/sdc UUID: 69642c61-5efb-4367-aa31-cdfd4067f713 [1/8] checking log skipped (none written) [2/8] checking root items [3/8] checking extents [4/8] checking free space tree [5/8] checking fs roots root 5 inode 332 errors 1000, some csum missing ERROR: errors found in fs roots (...) Looking at a tree dump of the fs tree (root 5) for inode 332 we have: $ btrfs inspect-internal dump-tree -t 5 /dev/sdc (...) item 28 key (332 INODE_ITEM 0) itemoff 2006 itemsize 160 generation 17 transid 19 size 610969 nbytes 86016 block group 0 mode 100666 links 1 uid 0 gid 0 rdev 0 sequence 11 flags 0x0(none) atime 1759851068.391327881 (2025-10-07 16:31:08) ctime 1759851068.410098267 (2025-10-07 16:31:08) mtime 1759851068.410098267 (2025-10-07 16:31:08) otime 1759851068.391327881 (2025-10-07 16:31:08) item 29 key (332 INODE_REF 340) itemoff 1993 itemsize 13 index 2 namelen 3 name: f1f item 30 key (332 EXTENT_DATA 589824) itemoff 1940 itemsize 53 generation 19 type 1 (regular) extent data disk byte 21745664 nr 65536 extent data offset 0 nr 65536 ram 65536 extent compression 0 (none) (...) We can see that the file extent item for file offset 589824 has a length of 64K and its number of bytes is 64K. Looking at the inode item we see that its i_size is 610969 bytes which falls within the range of that file extent item [589824, 655360[. Looking into the csum tree: $ btrfs inspect-internal dump-tree /dev/sdc (...) item 15 key (EXTENT_CSUM EXTENT_CSUM 21565440) itemoff 991 itemsize 200 range start 21565440 end 21770240 length 204800 item 16 key (EXTENT_CSUM EXTENT_CSUM 1104576512) itemoff 983 itemsize 8 range start 1104576512 end 1104584704 length 8192 (..) We see that the csum item number 15 covers the first 24K of the file extent item - it ends at offset 21770240 and the extent's disk_bytenr is 21745664, so we have: 21770240 - 21745664 = 24K We see that the next csum item (number 16) is completely outside the range, so the remaining 40K of the extent doesn't have csum items in the tree. If we round up the i_size to the sector size, we get: round_up(610969, 4096) = 614400 If we subtract from that the file offset for the extent item we get: 614400 - 589824 = 24K So the missing 40K corresponds to the end of the file extent item's range minus the rounded up i_size: 655360 - 614400 = 40K Normally we don't expect a file extent item to span over the rounded up i_size of an inode, since when truncating, doing hole punching and other operations that trim a file extent item, the number of bytes is adjusted. There is however a short time window where the kernel can end up, temporarily,persisting an inode with an i_size that falls in the middle of the last file extent item and the file extent item was not yet trimmed (its number of bytes reduced so that it doesn't cross i_size rounded up by the sector size). The steps (in the kernel) that lead to such scenario are the following: 1) We have inode I as an empty file, no allocated extents, i_size is 0; 2) A buffered write is done for file range [589824, 655360[ (length of 64K) and the i_size is updated to 655360. Note that we got a single large folio for the range (64K); 3) A truncate operation starts that reduces the inode's i_size down to 610969 bytes. The truncate sets the inode's new i_size at btrfs_setsize() by calling truncate_setsize() and before calling btrfs_truncate(); 4) At btrfs_truncate() we trigger writeback for the range starting at 610304 (which is the new i_size rounded down to the sector size) and ending at (u64)-1; 5) During the writeback, at extent_write_cache_pages(), we get from the call to filemap_get_folios_tag(), the 64K folio that starts at file offset 589824 since it contains the start offset of the writeback range (610304); 6) At writepage_delalloc() we find the whole range of the folio is dirty and therefore we run delalloc for that 64K range ([589824, 655360[), reserving a 64K extent, creating an ordered extent, etc; 7) At extent_writepage_io() we submit IO only for subrange [589824, 614400[ because the inode's i_size is 610969 bytes (rounded up by sector size is 614400). There, in the while loop we intentionally skip IO beyond i_size to avoid any unnecessay work and just call btrfs_mark_ordered_io_finished() for the range [614400, 655360[ (which has a 40K length); 8) Once the IO finishes we finish the ordered extent by ending up at btrfs_finish_one_ordered(), join transaction N, insert a file extent item in the inode's subvolume tree for file offset 589824 with a number of bytes of 64K, and update the inode's delayed inode item or directly the inode item with a call to btrfs_update_inode_fallback(), which results in storing the new i_size of 610969 bytes; 9) Transaction N is committed either by the transaction kthread or some other task committed it (in response to a sync or fsync for example). At this point we have inode I persisted with an i_size of 610969 bytes and file extent item that starts at file offset 589824 and has a number of bytes of 64K, ending at an offset of 655360 which is beyond the i_size rounded up to the sector size (614400). --> So after a crash or power failure here, the btrfs check program reports that error about missing checksum items for this inode, as it tries to lookup for checksums covering the whole range of the extent; 10) Only after transaction N is committed that at btrfs_truncate() the call to btrfs_start_transaction() starts a new transaction, N + 1, instead of joining transaction N. And it's with transaction N + 1 that it calls btrfs_truncate_inode_items() which updates the file extent item at file offset 589824 to reduce its number of bytes from 64K down to 24K, so that the file extent item's range ends at the i_size rounded up to the sector size (614400 bytes). Fix this by truncating the ordered extent at extent_writepage_io() when we skip writeback because the current offset in the folio is beyond i_size. This ensures we don't ever persist a file extent item with a number of bytes beyond the rounded up (by sector size) value of the i_size. Reviewed-by: Qu Wenruo Reviewed-by: Anand Jain Signed-off-by: Filipe Manana Signed-off-by: David Sterba Stable-dep-of: e9e3b22ddfa7 ("btrfs: fix beyond-EOF write handling") Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- fs/btrfs/extent_io.c | 21 +++++++++++++++++++-- fs/btrfs/ordered-data.c | 5 +++-- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index 23273d0e6f224..7cbccd4604c50 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -1692,13 +1692,13 @@ static noinline_for_stack int extent_writepage_io(struct btrfs_inode *inode, bool submitted_io = false; int found_error = 0; const u64 folio_start = folio_pos(folio); + const u64 folio_end = folio_start + folio_size(folio); const unsigned int blocks_per_folio = btrfs_blocks_per_folio(fs_info, folio); u64 cur; int bit; int ret = 0; - ASSERT(start >= folio_start && - start + len <= folio_start + folio_size(folio)); + ASSERT(start >= folio_start && start + len <= folio_end); ret = btrfs_writepage_cow_fixup(folio); if (ret == -EAGAIN) { @@ -1725,6 +1725,23 @@ static noinline_for_stack int extent_writepage_io(struct btrfs_inode *inode, cur = folio_pos(folio) + (bit << fs_info->sectorsize_bits); if (cur >= i_size) { + struct btrfs_ordered_extent *ordered; + unsigned long flags; + + ordered = btrfs_lookup_first_ordered_range(inode, cur, + folio_end - cur); + /* + * We have just run delalloc before getting here, so + * there must be an ordered extent. + */ + ASSERT(ordered != NULL); + spin_lock_irqsave(&inode->ordered_tree_lock, flags); + set_bit(BTRFS_ORDERED_TRUNCATED, &ordered->flags); + ordered->truncated_len = min(ordered->truncated_len, + cur - ordered->file_offset); + spin_unlock_irqrestore(&inode->ordered_tree_lock, flags); + btrfs_put_ordered_extent(ordered); + btrfs_mark_ordered_io_finished(inode, folio, cur, start + len - cur, true); /* diff --git a/fs/btrfs/ordered-data.c b/fs/btrfs/ordered-data.c index 2829f20d7bb59..8a8aa6ed405bd 100644 --- a/fs/btrfs/ordered-data.c +++ b/fs/btrfs/ordered-data.c @@ -1098,8 +1098,9 @@ struct btrfs_ordered_extent *btrfs_lookup_first_ordered_range( struct rb_node *prev; struct rb_node *next; struct btrfs_ordered_extent *entry = NULL; + unsigned long flags; - spin_lock_irq(&inode->ordered_tree_lock); + spin_lock_irqsave(&inode->ordered_tree_lock, flags); node = inode->ordered_tree.rb_node; /* * Here we don't want to use tree_search() which will use tree->last @@ -1154,7 +1155,7 @@ struct btrfs_ordered_extent *btrfs_lookup_first_ordered_range( trace_btrfs_ordered_extent_lookup_first_range(inode, entry); } - spin_unlock_irq(&inode->ordered_tree_lock); + spin_unlock_irqrestore(&inode->ordered_tree_lock, flags); return entry; } From 9cb1a586c78ad35f9c5c679d8696e7cf38c5e734 Mon Sep 17 00:00:00 2001 From: Filipe Manana Date: Mon, 12 Jan 2026 08:54:50 -0500 Subject: [PATCH 1925/2333] btrfs: use variable for end offset in extent_writepage_io() [ Upstream commit 46a23908598f4b8e61483f04ea9f471b2affc58a ] Instead of repeating the expression "start + len" multiple times, store it in a variable and use it where needed. Reviewed-by: Qu Wenruo Reviewed-by: Anand Jain Signed-off-by: Filipe Manana Reviewed-by: David Sterba Signed-off-by: David Sterba Stable-dep-of: e9e3b22ddfa7 ("btrfs: fix beyond-EOF write handling") Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- fs/btrfs/extent_io.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index 7cbccd4604c50..ca09f42d26aa1 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -1691,6 +1691,7 @@ static noinline_for_stack int extent_writepage_io(struct btrfs_inode *inode, unsigned long range_bitmap = 0; bool submitted_io = false; int found_error = 0; + const u64 end = start + len; const u64 folio_start = folio_pos(folio); const u64 folio_end = folio_start + folio_size(folio); const unsigned int blocks_per_folio = btrfs_blocks_per_folio(fs_info, folio); @@ -1698,7 +1699,7 @@ static noinline_for_stack int extent_writepage_io(struct btrfs_inode *inode, int bit; int ret = 0; - ASSERT(start >= folio_start && start + len <= folio_end); + ASSERT(start >= folio_start && end <= folio_end); ret = btrfs_writepage_cow_fixup(folio); if (ret == -EAGAIN) { @@ -1714,7 +1715,7 @@ static noinline_for_stack int extent_writepage_io(struct btrfs_inode *inode, return ret; } - for (cur = start; cur < start + len; cur += fs_info->sectorsize) + for (cur = start; cur < end; cur += fs_info->sectorsize) set_bit((cur - folio_start) >> fs_info->sectorsize_bits, &range_bitmap); bitmap_and(&bio_ctrl->submit_bitmap, &bio_ctrl->submit_bitmap, &range_bitmap, blocks_per_folio); @@ -1743,7 +1744,7 @@ static noinline_for_stack int extent_writepage_io(struct btrfs_inode *inode, btrfs_put_ordered_extent(ordered); btrfs_mark_ordered_io_finished(inode, folio, cur, - start + len - cur, true); + end - cur, true); /* * This range is beyond i_size, thus we don't need to * bother writing back. @@ -1752,8 +1753,7 @@ static noinline_for_stack int extent_writepage_io(struct btrfs_inode *inode, * writeback the sectors with subpage dirty bits, * causing writeback without ordered extent. */ - btrfs_folio_clear_dirty(fs_info, folio, cur, - start + len - cur); + btrfs_folio_clear_dirty(fs_info, folio, cur, end - cur); break; } ret = submit_one_sector(inode, folio, cur, bio_ctrl, i_size); From 4374a1cac13e1b55a801d44bc9e3204395a252b2 Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Mon, 12 Jan 2026 08:54:51 -0500 Subject: [PATCH 1926/2333] btrfs: fix beyond-EOF write handling [ Upstream commit e9e3b22ddfa760762b696ac6417c8d6edd182e49 ] [BUG] For the following write sequence with 64K page size and 4K fs block size, it will lead to file extent items to be inserted without any data checksum: mkfs.btrfs -s 4k -f $dev > /dev/null mount $dev $mnt xfs_io -f -c "pwrite 0 16k" -c "pwrite 32k 4k" -c pwrite "60k 64K" \ -c "truncate 16k" $mnt/foobar umount $mnt This will result the following 2 file extent items to be inserted (extra trace point added to insert_ordered_extent_file_extent()): btrfs_finish_one_ordered: root=5 ino=257 file_off=61440 num_bytes=4096 csum_bytes=0 btrfs_finish_one_ordered: root=5 ino=257 file_off=0 num_bytes=16384 csum_bytes=16384 Note for file offset 60K, we're inserting a file extent without any data checksum. Also note that range [32K, 36K) didn't reach insert_ordered_extent_file_extent(), which is the correct behavior as that OE is fully truncated, should not result any file extent. Although file extent at 60K will be later dropped by btrfs_truncate(), if the transaction got committed after file extent inserted but before the file extent dropping, we will have a small window where we have a file extent beyond EOF and without any data checksum. That will cause "btrfs check" to report error. [CAUSE] The sequence happens like this: - Buffered write dirtied the page cache and updated isize Now the inode size is 64K, with the following page cache layout: 0 16K 32K 48K 64K |/////////////| |//| |//| - Truncate the inode to 16K Which will trigger writeback through: btrfs_setsize() |- truncate_setsize() | Now the inode size is set to 16K | |- btrfs_truncate() |- btrfs_wait_ordered_range() for [16K, u64(-1)] |- btrfs_fdatawrite_range() for [16K, u64(-1)} |- extent_writepage() for folio 0 |- writepage_delalloc() | Generated OE for [0, 16K), [32K, 36K] and [60K, 64K) | |- extent_writepage_io() Then inside extent_writepage_io(), the dirty fs blocks are handled differently: - Submit write for range [0, 16K) As they are still inside the inode size (16K). - Mark OE [32K, 36K) as truncated Since we only call btrfs_lookup_first_ordered_range() once, which returned the first OE after file offset 16K. - Mark all OEs inside range [16K, 64K) as finished Which will mark OE ranges [32K, 36K) and [60K, 64K) as finished. For OE [32K, 36K) since it's already marked as truncated, and its truncated length is 0, no file extent will be inserted. For OE [60K, 64K) it has never been submitted thus has no data checksum, and we insert the file extent as usual. This is the root cause of file extent at 60K to be inserted without any data checksum. - Clear dirty flags for range [16K, 64K) It is the function btrfs_folio_clear_dirty() which searches and clears any dirty blocks inside that range. [FIX] The bug itself was introduced a long time ago, way before subpage and large folio support. At that time, fs block size must match page size, thus the range [cur, end) is just one fs block. But later with subpage and large folios, the same range [cur, end) can have multiple blocks and ordered extents. Later commit 18de34daa7c6 ("btrfs: truncate ordered extent when skipping writeback past i_size") was fixing a bug related to subpage/large folios, but it's still utilizing the old range [cur, end), meaning only the first OE will be marked as truncated. The proper fix here is to make EOF handling block-by-block, not trying to handle the whole range to @end. By this we always locate and truncate the OE for every dirty block. CC: stable@vger.kernel.org # 5.15+ Reviewed-by: Filipe Manana Signed-off-by: Qu Wenruo Signed-off-by: David Sterba Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- fs/btrfs/extent_io.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index ca09f42d26aa1..1a07edaefaa0f 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -1730,7 +1730,7 @@ static noinline_for_stack int extent_writepage_io(struct btrfs_inode *inode, unsigned long flags; ordered = btrfs_lookup_first_ordered_range(inode, cur, - folio_end - cur); + fs_info->sectorsize); /* * We have just run delalloc before getting here, so * there must be an ordered extent. @@ -1744,7 +1744,7 @@ static noinline_for_stack int extent_writepage_io(struct btrfs_inode *inode, btrfs_put_ordered_extent(ordered); btrfs_mark_ordered_io_finished(inode, folio, cur, - end - cur, true); + fs_info->sectorsize, true); /* * This range is beyond i_size, thus we don't need to * bother writing back. @@ -1753,8 +1753,8 @@ static noinline_for_stack int extent_writepage_io(struct btrfs_inode *inode, * writeback the sectors with subpage dirty bits, * causing writeback without ordered extent. */ - btrfs_folio_clear_dirty(fs_info, folio, cur, end - cur); - break; + btrfs_folio_clear_dirty(fs_info, folio, cur, fs_info->sectorsize); + continue; } ret = submit_one_sector(inode, folio, cur, bio_ctrl, i_size); if (unlikely(ret < 0)) { From 472d900c8bcac301ae0e40fdca7db799bd989ff5 Mon Sep 17 00:00:00 2001 From: Mary Strodl Date: Mon, 12 Jan 2026 12:44:39 -0500 Subject: [PATCH 1927/2333] gpio: mpsse: ensure worker is torn down [ Upstream commit 179ef1127d7a4f09f0e741fa9f30b8a8e7886271 ] When an IRQ worker is running, unplugging the device would cause a crash. The sealevel hardware this driver was written for was not hotpluggable, so I never realized it. This change uses a spinlock to protect a list of workers, which it tears down on disconnect. Signed-off-by: Mary Strodl Reviewed-by: Linus Walleij Link: https://lore.kernel.org/r/20251014133530.3592716-3-mstrodl@csh.rit.edu Signed-off-by: Bartosz Golaszewski Stable-dep-of: 1e876e5a0875 ("gpio: mpsse: fix reference leak in gpio_mpsse_probe() error paths") Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/gpio/gpio-mpsse.c | 106 +++++++++++++++++++++++++++++++++++--- 1 file changed, 99 insertions(+), 7 deletions(-) diff --git a/drivers/gpio/gpio-mpsse.c b/drivers/gpio/gpio-mpsse.c index 9f42bb30b4ec7..8147b3ddb4a27 100644 --- a/drivers/gpio/gpio-mpsse.c +++ b/drivers/gpio/gpio-mpsse.c @@ -10,6 +10,7 @@ #include #include #include +#include #include struct mpsse_priv { @@ -17,8 +18,10 @@ struct mpsse_priv { struct usb_device *udev; /* USB device encompassing all MPSSEs */ struct usb_interface *intf; /* USB interface for this MPSSE */ u8 intf_id; /* USB interface number for this MPSSE */ - struct work_struct irq_work; /* polling work thread */ + struct list_head workers; /* polling work threads */ struct mutex irq_mutex; /* lock over irq_data */ + struct mutex irq_race; /* race for polling worker teardown */ + raw_spinlock_t irq_spin; /* protects worker list */ atomic_t irq_type[16]; /* pin -> edge detection type */ atomic_t irq_enabled; int id; @@ -34,6 +37,14 @@ struct mpsse_priv { struct mutex io_mutex; /* sync I/O with disconnect */ }; +struct mpsse_worker { + struct mpsse_priv *priv; + struct work_struct work; + atomic_t cancelled; + struct list_head list; /* linked list */ + struct list_head destroy; /* teardown linked list */ +}; + struct bulk_desc { bool tx; /* direction of bulk transfer */ u8 *data; /* input (tx) or output (rx) */ @@ -284,18 +295,62 @@ static int gpio_mpsse_get_direction(struct gpio_chip *chip, return ret; } -static void gpio_mpsse_poll(struct work_struct *work) +/* + * Stops all workers except `my_worker`. + * Safe to call only when `irq_race` is held. + */ +static void gpio_mpsse_stop_all_except(struct mpsse_priv *priv, + struct mpsse_worker *my_worker) +{ + struct mpsse_worker *worker, *worker_tmp; + struct list_head destructors = LIST_HEAD_INIT(destructors); + + scoped_guard(raw_spinlock_irqsave, &priv->irq_spin) { + list_for_each_entry_safe(worker, worker_tmp, + &priv->workers, list) { + /* Don't stop ourselves */ + if (worker == my_worker) + continue; + + list_del(&worker->list); + + /* Give worker a chance to terminate itself */ + atomic_set(&worker->cancelled, 1); + /* Keep track of stuff to cancel */ + INIT_LIST_HEAD(&worker->destroy); + list_add(&worker->destroy, &destructors); + } + } + + list_for_each_entry_safe(worker, worker_tmp, + &destructors, destroy) { + list_del(&worker->destroy); + cancel_work_sync(&worker->work); + kfree(worker); + } +} + +static void gpio_mpsse_poll(struct work_struct *my_work) { unsigned long pin_mask, pin_states, flags; int irq_enabled, offset, err, value, fire_irq, irq, old_value[16], irq_type[16]; - struct mpsse_priv *priv = container_of(work, struct mpsse_priv, - irq_work); + struct mpsse_worker *my_worker = container_of(my_work, struct mpsse_worker, work); + struct mpsse_priv *priv = my_worker->priv; for (offset = 0; offset < priv->gpio.ngpio; ++offset) old_value[offset] = -1; - while ((irq_enabled = atomic_read(&priv->irq_enabled))) { + /* + * We only want one worker. Workers race to acquire irq_race and tear + * down all other workers. This is a cond guard so that we don't deadlock + * trying to cancel a worker. + */ + scoped_cond_guard(mutex_try, return, &priv->irq_race) + gpio_mpsse_stop_all_except(priv, my_worker); + + while ((irq_enabled = atomic_read(&priv->irq_enabled)) && + !atomic_read(&my_worker->cancelled)) { usleep_range(MPSSE_POLL_INTERVAL, MPSSE_POLL_INTERVAL + 1000); /* Cleanup will trigger at the end of the loop */ guard(mutex)(&priv->irq_mutex); @@ -370,21 +425,45 @@ static int gpio_mpsse_set_irq_type(struct irq_data *irqd, unsigned int type) static void gpio_mpsse_irq_disable(struct irq_data *irqd) { + struct mpsse_worker *worker; struct mpsse_priv *priv = irq_data_get_irq_chip_data(irqd); atomic_and(~BIT(irqd->hwirq), &priv->irq_enabled); gpiochip_disable_irq(&priv->gpio, irqd->hwirq); + + /* + * Can't actually do teardown in IRQ context (it blocks). + * As a result, these workers will stick around until irq is reenabled + * or device gets disconnected + */ + scoped_guard(raw_spinlock_irqsave, &priv->irq_spin) + list_for_each_entry(worker, &priv->workers, list) + atomic_set(&worker->cancelled, 1); } static void gpio_mpsse_irq_enable(struct irq_data *irqd) { + struct mpsse_worker *worker; struct mpsse_priv *priv = irq_data_get_irq_chip_data(irqd); gpiochip_enable_irq(&priv->gpio, irqd->hwirq); /* If no-one else was using the IRQ, enable it */ if (!atomic_fetch_or(BIT(irqd->hwirq), &priv->irq_enabled)) { - INIT_WORK(&priv->irq_work, gpio_mpsse_poll); - schedule_work(&priv->irq_work); + /* + * Can't be devm because it uses a non-raw spinlock (illegal in + * this context, where a raw spinlock is held by our caller) + */ + worker = kzalloc(sizeof(*worker), GFP_NOWAIT); + if (!worker) + return; + + worker->priv = priv; + INIT_LIST_HEAD(&worker->list); + INIT_WORK(&worker->work, gpio_mpsse_poll); + schedule_work(&worker->work); + + scoped_guard(raw_spinlock_irqsave, &priv->irq_spin) + list_add(&worker->list, &priv->workers); } } @@ -436,6 +515,12 @@ static int gpio_mpsse_probe(struct usb_interface *interface, if (err) return err; + err = devm_mutex_init(dev, &priv->irq_race); + if (err) + return err; + + raw_spin_lock_init(&priv->irq_spin); + priv->gpio.label = devm_kasprintf(dev, GFP_KERNEL, "gpio-mpsse.%d.%d", priv->id, priv->intf_id); @@ -506,6 +591,13 @@ static void gpio_mpsse_disconnect(struct usb_interface *intf) { struct mpsse_priv *priv = usb_get_intfdata(intf); + /* + * Lock prevents double-free of worker from here and the teardown + * step at the beginning of gpio_mpsse_poll + */ + scoped_guard(mutex, &priv->irq_race) + gpio_mpsse_stop_all_except(priv, NULL); + priv->intf = NULL; usb_set_intfdata(intf, NULL); usb_put_dev(priv->udev); From 7882637ea5ccba08ec3674628f03ff0baf48d935 Mon Sep 17 00:00:00 2001 From: Mary Strodl Date: Mon, 12 Jan 2026 12:44:40 -0500 Subject: [PATCH 1928/2333] gpio: mpsse: add quirk support [ Upstream commit f13b0f72af238d63bb9a2e417657da8b45d72544 ] Builds out a facility for specifying compatible lines directions and labels for MPSSE-based devices. * dir_in/out are bitmask of lines that can go in/out. 1 means compatible, 0 means incompatible. * names is an array of line names which will be exposed to userspace. Also changes the chip label format to include some more useful information about the device to help identify it from userspace. Signed-off-by: Mary Strodl Reviewed-by: Dan Carpenter Reviewed-by: Linus Walleij Link: https://lore.kernel.org/r/20251014133530.3592716-4-mstrodl@csh.rit.edu Signed-off-by: Bartosz Golaszewski Stable-dep-of: 1e876e5a0875 ("gpio: mpsse: fix reference leak in gpio_mpsse_probe() error paths") Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/gpio/gpio-mpsse.c | 109 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 106 insertions(+), 3 deletions(-) diff --git a/drivers/gpio/gpio-mpsse.c b/drivers/gpio/gpio-mpsse.c index 8147b3ddb4a27..e68179caafa62 100644 --- a/drivers/gpio/gpio-mpsse.c +++ b/drivers/gpio/gpio-mpsse.c @@ -29,6 +29,9 @@ struct mpsse_priv { u8 gpio_outputs[2]; /* Output states for GPIOs [L, H] */ u8 gpio_dir[2]; /* Directions for GPIOs [L, H] */ + unsigned long dir_in; /* Bitmask of valid input pins */ + unsigned long dir_out; /* Bitmask of valid output pins */ + u8 *bulk_in_buf; /* Extra recv buffer to grab status bytes */ struct usb_endpoint_descriptor *bulk_in; @@ -54,6 +57,14 @@ struct bulk_desc { int timeout; }; +#define MPSSE_NGPIO 16 + +struct mpsse_quirk { + const char *names[MPSSE_NGPIO]; /* Pin names, if applicable */ + unsigned long dir_in; /* Bitmask of valid input pins */ + unsigned long dir_out; /* Bitmask of valid output pins */ +}; + static const struct usb_device_id gpio_mpsse_table[] = { { USB_DEVICE(0x0c52, 0xa064) }, /* SeaLevel Systems, Inc. */ { } /* Terminating entry */ @@ -171,6 +182,32 @@ static int gpio_mpsse_get_bank(struct mpsse_priv *priv, u8 bank) return buf; } +static int mpsse_ensure_supported(struct gpio_chip *chip, + unsigned long mask, int direction) +{ + unsigned long supported, unsupported; + char *type = "input"; + struct mpsse_priv *priv = gpiochip_get_data(chip); + + supported = priv->dir_in; + if (direction == GPIO_LINE_DIRECTION_OUT) { + supported = priv->dir_out; + type = "output"; + } + + /* An invalid bit was in the provided mask */ + unsupported = mask & ~supported; + if (unsupported) { + dev_err(&priv->udev->dev, + "mpsse: GPIO %lu doesn't support %s\n", + find_first_bit(&unsupported, sizeof(unsupported) * 8), + type); + return -EOPNOTSUPP; + } + + return 0; +} + static int gpio_mpsse_set_multiple(struct gpio_chip *chip, unsigned long *mask, unsigned long *bits) { @@ -178,6 +215,10 @@ static int gpio_mpsse_set_multiple(struct gpio_chip *chip, unsigned long *mask, int ret; struct mpsse_priv *priv = gpiochip_get_data(chip); + ret = mpsse_ensure_supported(chip, *mask, GPIO_LINE_DIRECTION_OUT); + if (ret) + return ret; + guard(mutex)(&priv->io_mutex); for_each_set_clump8(i, bank_mask, mask, chip->ngpio) { bank = i / 8; @@ -205,6 +246,10 @@ static int gpio_mpsse_get_multiple(struct gpio_chip *chip, unsigned long *mask, int ret; struct mpsse_priv *priv = gpiochip_get_data(chip); + ret = mpsse_ensure_supported(chip, *mask, GPIO_LINE_DIRECTION_IN); + if (ret) + return ret; + guard(mutex)(&priv->io_mutex); for_each_set_clump8(i, bank_mask, mask, chip->ngpio) { bank = i / 8; @@ -253,10 +298,15 @@ static int gpio_mpsse_gpio_set(struct gpio_chip *chip, unsigned int offset, static int gpio_mpsse_direction_output(struct gpio_chip *chip, unsigned int offset, int value) { + int ret; struct mpsse_priv *priv = gpiochip_get_data(chip); int bank = (offset & 8) >> 3; int bank_offset = offset & 7; + ret = mpsse_ensure_supported(chip, BIT(offset), GPIO_LINE_DIRECTION_OUT); + if (ret) + return ret; + scoped_guard(mutex, &priv->io_mutex) priv->gpio_dir[bank] |= BIT(bank_offset); @@ -266,10 +316,15 @@ static int gpio_mpsse_direction_output(struct gpio_chip *chip, static int gpio_mpsse_direction_input(struct gpio_chip *chip, unsigned int offset) { + int ret; struct mpsse_priv *priv = gpiochip_get_data(chip); int bank = (offset & 8) >> 3; int bank_offset = offset & 7; + ret = mpsse_ensure_supported(chip, BIT(offset), GPIO_LINE_DIRECTION_IN); + if (ret) + return ret; + guard(mutex)(&priv->io_mutex); priv->gpio_dir[bank] &= ~BIT(bank_offset); gpio_mpsse_set_bank(priv, bank); @@ -483,18 +538,49 @@ static void gpio_mpsse_ida_remove(void *data) ida_free(&gpio_mpsse_ida, priv->id); } +static int mpsse_init_valid_mask(struct gpio_chip *chip, + unsigned long *valid_mask, + unsigned int ngpios) +{ + struct mpsse_priv *priv = gpiochip_get_data(chip); + + if (WARN_ON(priv == NULL)) + return -ENODEV; + + *valid_mask = priv->dir_in | priv->dir_out; + + return 0; +} + +static void mpsse_irq_init_valid_mask(struct gpio_chip *chip, + unsigned long *valid_mask, + unsigned int ngpios) +{ + struct mpsse_priv *priv = gpiochip_get_data(chip); + + if (WARN_ON(priv == NULL)) + return; + + /* Can only use IRQ on input capable pins */ + *valid_mask = priv->dir_in; +} + static int gpio_mpsse_probe(struct usb_interface *interface, const struct usb_device_id *id) { struct mpsse_priv *priv; struct device *dev; + char *serial; int err; + struct mpsse_quirk *quirk = (void *)id->driver_info; dev = &interface->dev; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; + INIT_LIST_HEAD(&priv->workers); + priv->udev = usb_get_dev(interface_to_usbdev(interface)); priv->intf = interface; priv->intf_id = interface->cur_altsetting->desc.bInterfaceNumber; @@ -521,9 +607,15 @@ static int gpio_mpsse_probe(struct usb_interface *interface, raw_spin_lock_init(&priv->irq_spin); + serial = priv->udev->serial; + if (!serial) + serial = "NONE"; + priv->gpio.label = devm_kasprintf(dev, GFP_KERNEL, - "gpio-mpsse.%d.%d", - priv->id, priv->intf_id); + "MPSSE%04x:%04x.%d.%d.%s", + id->idVendor, id->idProduct, + priv->intf_id, priv->id, + serial); if (!priv->gpio.label) return -ENOMEM; @@ -537,10 +629,20 @@ static int gpio_mpsse_probe(struct usb_interface *interface, priv->gpio.get_multiple = gpio_mpsse_get_multiple; priv->gpio.set_multiple = gpio_mpsse_set_multiple; priv->gpio.base = -1; - priv->gpio.ngpio = 16; + priv->gpio.ngpio = MPSSE_NGPIO; priv->gpio.offset = priv->intf_id * priv->gpio.ngpio; priv->gpio.can_sleep = 1; + if (quirk) { + priv->dir_out = quirk->dir_out; + priv->dir_in = quirk->dir_in; + priv->gpio.names = quirk->names; + priv->gpio.init_valid_mask = mpsse_init_valid_mask; + } else { + priv->dir_in = U16_MAX; + priv->dir_out = U16_MAX; + } + err = usb_find_common_endpoints(interface->cur_altsetting, &priv->bulk_in, &priv->bulk_out, NULL, NULL); @@ -579,6 +681,7 @@ static int gpio_mpsse_probe(struct usb_interface *interface, priv->gpio.irq.parents = NULL; priv->gpio.irq.default_type = IRQ_TYPE_NONE; priv->gpio.irq.handler = handle_simple_irq; + priv->gpio.irq.init_valid_mask = mpsse_irq_init_valid_mask; err = devm_gpiochip_add_data(dev, &priv->gpio, priv); if (err) From 7ea26e6dcabc270433b6ded2a1aee85b215d1b28 Mon Sep 17 00:00:00 2001 From: Abdun Nihaal Date: Mon, 12 Jan 2026 12:44:41 -0500 Subject: [PATCH 1929/2333] gpio: mpsse: fix reference leak in gpio_mpsse_probe() error paths [ Upstream commit 1e876e5a0875e71e34148c9feb2eedd3bf6b2b43 ] The reference obtained by calling usb_get_dev() is not released in the gpio_mpsse_probe() error paths. Fix that by using device managed helper functions. Also remove the usb_put_dev() call in the disconnect function since now it will be released automatically. Cc: stable@vger.kernel.org Fixes: c46a74ff05c0 ("gpio: add support for FTDI's MPSSE as GPIO") Signed-off-by: Abdun Nihaal Link: https://lore.kernel.org/r/20251226060414.20785-1-nihaal@cse.iitm.ac.in Signed-off-by: Bartosz Golaszewski Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/gpio/gpio-mpsse.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-mpsse.c b/drivers/gpio/gpio-mpsse.c index e68179caafa62..120b27183b1d9 100644 --- a/drivers/gpio/gpio-mpsse.c +++ b/drivers/gpio/gpio-mpsse.c @@ -538,6 +538,13 @@ static void gpio_mpsse_ida_remove(void *data) ida_free(&gpio_mpsse_ida, priv->id); } +static void gpio_mpsse_usb_put_dev(void *data) +{ + struct mpsse_priv *priv = data; + + usb_put_dev(priv->udev); +} + static int mpsse_init_valid_mask(struct gpio_chip *chip, unsigned long *valid_mask, unsigned int ngpios) @@ -582,6 +589,10 @@ static int gpio_mpsse_probe(struct usb_interface *interface, INIT_LIST_HEAD(&priv->workers); priv->udev = usb_get_dev(interface_to_usbdev(interface)); + err = devm_add_action_or_reset(dev, gpio_mpsse_usb_put_dev, priv); + if (err) + return err; + priv->intf = interface; priv->intf_id = interface->cur_altsetting->desc.bInterfaceNumber; @@ -703,7 +714,6 @@ static void gpio_mpsse_disconnect(struct usb_interface *intf) priv->intf = NULL; usb_set_intfdata(intf, NULL); - usb_put_dev(priv->udev); } static struct usb_driver gpio_mpsse_driver = { From 31e37f44b60679d90b9f999c91371b15291be8e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Toke=20H=C3=B8iland-J=C3=B8rgensen?= Date: Mon, 5 Jan 2026 12:47:45 +0100 Subject: [PATCH 1930/2333] bpf, test_run: Subtract size of xdp_frame from allowed metadata size MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit e558cca217790286e799a8baacd1610bda31b261 ] The xdp_frame structure takes up part of the XDP frame headroom, limiting the size of the metadata. However, in bpf_test_run, we don't take this into account, which makes it possible for userspace to supply a metadata size that is too large (taking up the entire headroom). If userspace supplies such a large metadata size in live packet mode, the xdp_update_frame_from_buff() call in xdp_test_run_init_page() call will fail, after which packet transmission proceeds with an uninitialised frame structure, leading to the usual Bad Stuff. The commit in the Fixes tag fixed a related bug where the second check in xdp_update_frame_from_buff() could fail, but did not add any additional constraints on the metadata size. Complete the fix by adding an additional check on the metadata size. Reorder the checks slightly to make the logic clearer and add a comment. Link: https://lore.kernel.org/r/fa2be179-bad7-4ee3-8668-4903d1853461@hust.edu.cn Fixes: b6f1f780b393 ("bpf, test_run: Fix packet size check for live packet mode") Reported-by: Yinhao Hu Reported-by: Kaiyan Mei Signed-off-by: Toke Høiland-Jørgensen Reviewed-by: Amery Hung Link: https://lore.kernel.org/r/20260105114747.1358750-1-toke@redhat.com Signed-off-by: Alexei Starovoitov Signed-off-by: Sasha Levin --- net/bpf/test_run.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/net/bpf/test_run.c b/net/bpf/test_run.c index 55a79337ac51f..59620fdd5cfda 100644 --- a/net/bpf/test_run.c +++ b/net/bpf/test_run.c @@ -1231,8 +1231,6 @@ int bpf_prog_test_run_xdp(struct bpf_prog *prog, const union bpf_attr *kattr, batch_size = NAPI_POLL_WEIGHT; else if (batch_size > TEST_XDP_MAX_BATCH) return -E2BIG; - - headroom += sizeof(struct xdp_page_head); } else if (batch_size) { return -EINVAL; } @@ -1245,16 +1243,26 @@ int bpf_prog_test_run_xdp(struct bpf_prog *prog, const union bpf_attr *kattr, /* There can't be user provided data before the meta data */ if (ctx->data_meta || ctx->data_end > kattr->test.data_size_in || ctx->data > ctx->data_end || - unlikely(xdp_metalen_invalid(ctx->data)) || (do_live && (kattr->test.data_out || kattr->test.ctx_out))) goto free_ctx; - /* Meta data is allocated from the headroom */ - headroom -= ctx->data; meta_sz = ctx->data; + if (xdp_metalen_invalid(meta_sz) || meta_sz > headroom - sizeof(struct xdp_frame)) + goto free_ctx; + + /* Meta data is allocated from the headroom */ + headroom -= meta_sz; linear_sz = ctx->data_end; } + /* The xdp_page_head structure takes up space in each page, limiting the + * size of the packet data; add the extra size to headroom here to make + * sure it's accounted in the length checks below, but not in the + * metadata size check above. + */ + if (do_live) + headroom += sizeof(struct xdp_page_head); + max_linear_sz = PAGE_SIZE - headroom - tailroom; linear_sz = min_t(u32, linear_sz, max_linear_sz); From 737be05a765761d7d7c9f7fe92274bd8e6f6951e Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Thu, 8 Jan 2026 21:36:48 +0900 Subject: [PATCH 1931/2333] bpf: Fix reference count leak in bpf_prog_test_run_xdp() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit ec69daabe45256f98ac86c651b8ad1b2574489a7 ] syzbot is reporting unregister_netdevice: waiting for sit0 to become free. Usage count = 2 problem. A debug printk() patch found that a refcount is obtained at xdp_convert_md_to_buff() from bpf_prog_test_run_xdp(). According to commit ec94670fcb3b ("bpf: Support specifying ingress via xdp_md context in BPF_PROG_TEST_RUN"), the refcount obtained by xdp_convert_md_to_buff() will be released by xdp_convert_buff_to_md(). Therefore, we can consider that the error handling path introduced by commit 1c1949982524 ("bpf: introduce frags support to bpf_prog_test_run_xdp()") forgot to call xdp_convert_buff_to_md(). Reported-by: syzbot+881d65229ca4f9ae8c84@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=881d65229ca4f9ae8c84 Fixes: 1c1949982524 ("bpf: introduce frags support to bpf_prog_test_run_xdp()") Signed-off-by: Tetsuo Handa Reviewed-by: Toke Høiland-Jørgensen Link: https://lore.kernel.org/r/af090e53-9d9b-4412-8acb-957733b3975c@I-love.SAKURA.ne.jp Signed-off-by: Alexei Starovoitov Signed-off-by: Sasha Levin --- net/bpf/test_run.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/net/bpf/test_run.c b/net/bpf/test_run.c index 59620fdd5cfda..6b04f47301c1e 100644 --- a/net/bpf/test_run.c +++ b/net/bpf/test_run.c @@ -1300,13 +1300,13 @@ int bpf_prog_test_run_xdp(struct bpf_prog *prog, const union bpf_attr *kattr, if (sinfo->nr_frags == MAX_SKB_FRAGS) { ret = -ENOMEM; - goto out; + goto out_put_dev; } page = alloc_page(GFP_KERNEL); if (!page) { ret = -ENOMEM; - goto out; + goto out_put_dev; } frag = &sinfo->frags[sinfo->nr_frags++]; @@ -1318,7 +1318,7 @@ int bpf_prog_test_run_xdp(struct bpf_prog *prog, const union bpf_attr *kattr, if (copy_from_user(page_address(page), data_in + size, data_len)) { ret = -EFAULT; - goto out; + goto out_put_dev; } sinfo->xdp_frags_size += data_len; size += data_len; @@ -1333,6 +1333,7 @@ int bpf_prog_test_run_xdp(struct bpf_prog *prog, const union bpf_attr *kattr, ret = bpf_test_run_xdp_live(prog, &xdp, repeat, batch_size, &duration); else ret = bpf_test_run(prog, &xdp, repeat, &retval, &duration, true); +out_put_dev: /* We convert the xdp_buff back to an xdp_md before checking the return * code so the reference count of any held netdevice will be decremented * even if the test run failed. From cbbf6c1fe62b919bcf43f8d0a45a64696158a941 Mon Sep 17 00:00:00 2001 From: Marcus Hughes Date: Sun, 7 Dec 2025 21:03:55 +0000 Subject: [PATCH 1932/2333] net: sfp: extend Potron XGSPON quirk to cover additional EEPROM variant [ Upstream commit 71cfa7c893a05d09e7dc14713b27a8309fd4a2db ] Some Potron SFP+ XGSPON ONU sticks are shipped with different EEPROM vendor ID and vendor name strings, but are otherwise functionally identical to the existing "Potron SFP+ XGSPON ONU Stick" handled by sfp_quirk_potron(). These modules, including units distributed under the "Better Internet" branding, use the same UART pin assignment and require the same TX_FAULT/LOS behaviour and boot delay. Re-use the existing Potron quirk for this EEPROM variant. Signed-off-by: Marcus Hughes Link: https://patch.msgid.link/20251207210355.333451-1-marcus.hughes@betterinternet.ltd Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- drivers/net/phy/sfp.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c index 6b4dd906b804f..84bef5099dda6 100644 --- a/drivers/net/phy/sfp.c +++ b/drivers/net/phy/sfp.c @@ -497,6 +497,8 @@ static const struct sfp_quirk sfp_quirks[] = { SFP_QUIRK("ALCATELLUCENT", "3FE46541AA", sfp_quirk_2500basex, sfp_fixup_nokia), + SFP_QUIRK_F("BIDB", "X-ONU-SFPP", sfp_fixup_potron), + // FLYPRO SFP-10GT-CS-30M uses Rollball protocol to talk to the PHY. SFP_QUIRK_F("FLYPRO", "SFP-10GT-CS-30M", sfp_fixup_rollball), From d33cc39e9f7ef457b0ac4c24be0244ddde4cefca Mon Sep 17 00:00:00 2001 From: Sumeet Pawnikar Date: Sat, 6 Dec 2025 00:32:16 +0530 Subject: [PATCH 1933/2333] powercap: fix race condition in register_control_type() [ Upstream commit 7bda1910c4bccd4b8d4726620bb3d6bbfb62286e ] The device becomes visible to userspace via device_register() even before it fully initialized by idr_init(). If userspace or another thread tries to register a zone immediately after device_register(), the control_type_valid() will fail because the control_type is not yet in the list. The IDR is not yet initialized, so this race condition causes zone registration failure. Move idr_init() and list addition before device_register() fix the race condition. Signed-off-by: Sumeet Pawnikar [ rjw: Subject adjustment, empty line added ] Link: https://patch.msgid.link/20251205190216.5032-1-sumeet4linux@gmail.com Signed-off-by: Rafael J. Wysocki Signed-off-by: Sasha Levin --- drivers/powercap/powercap_sys.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/drivers/powercap/powercap_sys.c b/drivers/powercap/powercap_sys.c index 4112a00973382..d14b36b75189d 100644 --- a/drivers/powercap/powercap_sys.c +++ b/drivers/powercap/powercap_sys.c @@ -625,17 +625,23 @@ struct powercap_control_type *powercap_register_control_type( INIT_LIST_HEAD(&control_type->node); control_type->dev.class = &powercap_class; dev_set_name(&control_type->dev, "%s", name); - result = device_register(&control_type->dev); - if (result) { - put_device(&control_type->dev); - return ERR_PTR(result); - } idr_init(&control_type->idr); mutex_lock(&powercap_cntrl_list_lock); list_add_tail(&control_type->node, &powercap_cntrl_list); mutex_unlock(&powercap_cntrl_list_lock); + result = device_register(&control_type->dev); + if (result) { + mutex_lock(&powercap_cntrl_list_lock); + list_del(&control_type->node); + mutex_unlock(&powercap_cntrl_list_lock); + + idr_destroy(&control_type->idr); + put_device(&control_type->dev); + return ERR_PTR(result); + } + return control_type; } EXPORT_SYMBOL_GPL(powercap_register_control_type); From 9e2fcfc32467bc088d6014ae0337dd8be0680880 Mon Sep 17 00:00:00 2001 From: Sumeet Pawnikar Date: Sun, 7 Dec 2025 20:45:48 +0530 Subject: [PATCH 1934/2333] powercap: fix sscanf() error return value handling [ Upstream commit efc4c35b741af973de90f6826bf35d3b3ac36bf1 ] Fix inconsistent error handling for sscanf() return value check. Implicit boolean conversion is used instead of explicit return value checks. The code checks if (!sscanf(...)) which is incorrect because: 1. sscanf returns the number of successfully parsed items 2. On success, it returns 1 (one item passed) 3. On failure, it returns 0 or EOF 4. The check 'if (!sscanf(...))' is wrong because it treats success (1) as failure All occurrences of sscanf() now uses explicit return value check. With this behavior it returns '-EINVAL' when parsing fails (returns 0 or EOF), and continues when parsing succeeds (returns 1). Signed-off-by: Sumeet Pawnikar [ rjw: Subject and changelog edits ] Link: https://patch.msgid.link/20251207151549.202452-1-sumeet4linux@gmail.com Signed-off-by: Rafael J. Wysocki Signed-off-by: Sasha Levin --- drivers/powercap/powercap_sys.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/powercap/powercap_sys.c b/drivers/powercap/powercap_sys.c index d14b36b75189d..1ff369880beb2 100644 --- a/drivers/powercap/powercap_sys.c +++ b/drivers/powercap/powercap_sys.c @@ -68,7 +68,7 @@ static ssize_t show_constraint_##_attr(struct device *dev, \ int id; \ struct powercap_zone_constraint *pconst;\ \ - if (!sscanf(dev_attr->attr.name, "constraint_%d_", &id)) \ + if (sscanf(dev_attr->attr.name, "constraint_%d_", &id) != 1) \ return -EINVAL; \ if (id >= power_zone->const_id_cnt) \ return -EINVAL; \ @@ -93,7 +93,7 @@ static ssize_t store_constraint_##_attr(struct device *dev,\ int id; \ struct powercap_zone_constraint *pconst;\ \ - if (!sscanf(dev_attr->attr.name, "constraint_%d_", &id)) \ + if (sscanf(dev_attr->attr.name, "constraint_%d_", &id) != 1) \ return -EINVAL; \ if (id >= power_zone->const_id_cnt) \ return -EINVAL; \ @@ -162,7 +162,7 @@ static ssize_t show_constraint_name(struct device *dev, ssize_t len = -ENODATA; struct powercap_zone_constraint *pconst; - if (!sscanf(dev_attr->attr.name, "constraint_%d_", &id)) + if (sscanf(dev_attr->attr.name, "constraint_%d_", &id) != 1) return -EINVAL; if (id >= power_zone->const_id_cnt) return -EINVAL; From 09d6074995c186e449979fe6c1b0f1a69cf9bd3b Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Sun, 7 Jul 2024 01:18:25 +0200 Subject: [PATCH 1935/2333] netfilter: nf_tables: avoid chain re-validation if possible [ Upstream commit 8e1a1bc4f5a42747c08130b8242ebebd1210b32f ] Hamza Mahfooz reports cpu soft lock-ups in nft_chain_validate(): watchdog: BUG: soft lockup - CPU#1 stuck for 27s! [iptables-nft-re:37547] [..] RIP: 0010:nft_chain_validate+0xcb/0x110 [nf_tables] [..] nft_immediate_validate+0x36/0x50 [nf_tables] nft_chain_validate+0xc9/0x110 [nf_tables] nft_immediate_validate+0x36/0x50 [nf_tables] nft_chain_validate+0xc9/0x110 [nf_tables] nft_immediate_validate+0x36/0x50 [nf_tables] nft_chain_validate+0xc9/0x110 [nf_tables] nft_immediate_validate+0x36/0x50 [nf_tables] nft_chain_validate+0xc9/0x110 [nf_tables] nft_immediate_validate+0x36/0x50 [nf_tables] nft_chain_validate+0xc9/0x110 [nf_tables] nft_immediate_validate+0x36/0x50 [nf_tables] nft_chain_validate+0xc9/0x110 [nf_tables] nft_table_validate+0x6b/0xb0 [nf_tables] nf_tables_validate+0x8b/0xa0 [nf_tables] nf_tables_commit+0x1df/0x1eb0 [nf_tables] [..] Currently nf_tables will traverse the entire table (chain graph), starting from the entry points (base chains), exploring all possible paths (chain jumps). But there are cases where we could avoid revalidation. Consider: 1 input -> j2 -> j3 2 input -> j2 -> j3 3 input -> j1 -> j2 -> j3 Then the second rule does not need to revalidate j2, and, by extension j3, because this was already checked during validation of the first rule. We need to validate it only for rule 3. This is needed because chain loop detection also ensures we do not exceed the jump stack: Just because we know that j2 is cycle free, its last jump might now exceed the allowed stack size. We also need to update all reachable chains with the new largest observed call depth. Care has to be taken to revalidate even if the chain depth won't be an issue: chain validation also ensures that expressions are not called from invalid base chains. For example, the masquerade expression can only be called from NAT postrouting base chains. Therefore we also need to keep record of the base chain context (type, hooknum) and revalidate if the chain becomes reachable from a different hook location. Reported-by: Hamza Mahfooz Closes: https://lore.kernel.org/netfilter-devel/20251118221735.GA5477@linuxonhyperv3.guj3yctzbm1etfxqx2vob5hsef.xx.internal.cloudapp.net/ Tested-by: Hamza Mahfooz Signed-off-by: Florian Westphal Signed-off-by: Sasha Levin --- include/net/netfilter/nf_tables.h | 34 +++++++++++---- net/netfilter/nf_tables_api.c | 69 +++++++++++++++++++++++++++++-- 2 files changed, 91 insertions(+), 12 deletions(-) diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h index fab7dc73f738c..0e266c2d0e7f0 100644 --- a/include/net/netfilter/nf_tables.h +++ b/include/net/netfilter/nf_tables.h @@ -1091,6 +1091,29 @@ struct nft_rule_blob { __attribute__((aligned(__alignof__(struct nft_rule_dp)))); }; +enum nft_chain_types { + NFT_CHAIN_T_DEFAULT = 0, + NFT_CHAIN_T_ROUTE, + NFT_CHAIN_T_NAT, + NFT_CHAIN_T_MAX +}; + +/** + * struct nft_chain_validate_state - validation state + * + * If a chain is encountered again during table validation it is + * possible to avoid revalidation provided the calling context is + * compatible. This structure stores relevant calling context of + * previous validations. + * + * @hook_mask: the hook numbers and locations the chain is linked to + * @depth: the deepest call chain level the chain is linked to + */ +struct nft_chain_validate_state { + u8 hook_mask[NFT_CHAIN_T_MAX]; + u8 depth; +}; + /** * struct nft_chain - nf_tables chain * @@ -1109,6 +1132,7 @@ struct nft_rule_blob { * @udlen: user data length * @udata: user data in the chain * @blob_next: rule blob pointer to the next in the chain + * @vstate: validation state */ struct nft_chain { struct nft_rule_blob __rcu *blob_gen_0; @@ -1128,9 +1152,10 @@ struct nft_chain { /* Only used during control plane commit phase: */ struct nft_rule_blob *blob_next; + struct nft_chain_validate_state vstate; }; -int nft_chain_validate(const struct nft_ctx *ctx, const struct nft_chain *chain); +int nft_chain_validate(const struct nft_ctx *ctx, struct nft_chain *chain); int nft_setelem_validate(const struct nft_ctx *ctx, struct nft_set *set, const struct nft_set_iter *iter, struct nft_elem_priv *elem_priv); @@ -1138,13 +1163,6 @@ int nft_set_catchall_validate(const struct nft_ctx *ctx, struct nft_set *set); int nf_tables_bind_chain(const struct nft_ctx *ctx, struct nft_chain *chain); void nf_tables_unbind_chain(const struct nft_ctx *ctx, struct nft_chain *chain); -enum nft_chain_types { - NFT_CHAIN_T_DEFAULT = 0, - NFT_CHAIN_T_ROUTE, - NFT_CHAIN_T_NAT, - NFT_CHAIN_T_MAX -}; - /** * struct nft_chain_type - nf_tables chain type info * diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index a3669acd68a32..3cbf2573b9e90 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c @@ -123,6 +123,29 @@ static void nft_validate_state_update(struct nft_table *table, u8 new_validate_s table->validate_state = new_validate_state; } + +static bool nft_chain_vstate_valid(const struct nft_ctx *ctx, + const struct nft_chain *chain) +{ + const struct nft_base_chain *base_chain; + enum nft_chain_types type; + u8 hooknum; + + if (WARN_ON_ONCE(!nft_is_base_chain(ctx->chain))) + return false; + + base_chain = nft_base_chain(ctx->chain); + hooknum = base_chain->ops.hooknum; + type = base_chain->type->type; + + /* chain is already validated for this call depth */ + if (chain->vstate.depth >= ctx->level && + chain->vstate.hook_mask[type] & BIT(hooknum)) + return true; + + return false; +} + static void nf_tables_trans_destroy_work(struct work_struct *w); static void nft_trans_gc_work(struct work_struct *work); @@ -4079,6 +4102,29 @@ static void nf_tables_rule_release(const struct nft_ctx *ctx, struct nft_rule *r nf_tables_rule_destroy(ctx, rule); } +static void nft_chain_vstate_update(const struct nft_ctx *ctx, struct nft_chain *chain) +{ + const struct nft_base_chain *base_chain; + enum nft_chain_types type; + u8 hooknum; + + /* ctx->chain must hold the calling base chain. */ + if (WARN_ON_ONCE(!nft_is_base_chain(ctx->chain))) { + memset(&chain->vstate, 0, sizeof(chain->vstate)); + return; + } + + base_chain = nft_base_chain(ctx->chain); + hooknum = base_chain->ops.hooknum; + type = base_chain->type->type; + + BUILD_BUG_ON(BIT(NF_INET_NUMHOOKS) > U8_MAX); + + chain->vstate.hook_mask[type] |= BIT(hooknum); + if (chain->vstate.depth < ctx->level) + chain->vstate.depth = ctx->level; +} + /** nft_chain_validate - loop detection and hook validation * * @ctx: context containing call depth and base chain @@ -4088,15 +4134,25 @@ static void nf_tables_rule_release(const struct nft_ctx *ctx, struct nft_rule *r * and set lookups until either the jump limit is hit or all reachable * chains have been validated. */ -int nft_chain_validate(const struct nft_ctx *ctx, const struct nft_chain *chain) +int nft_chain_validate(const struct nft_ctx *ctx, struct nft_chain *chain) { struct nft_expr *expr, *last; struct nft_rule *rule; int err; + BUILD_BUG_ON(NFT_JUMP_STACK_SIZE > 255); if (ctx->level == NFT_JUMP_STACK_SIZE) return -EMLINK; + if (ctx->level > 0) { + /* jumps to base chains are not allowed. */ + if (nft_is_base_chain(chain)) + return -ELOOP; + + if (nft_chain_vstate_valid(ctx, chain)) + return 0; + } + list_for_each_entry(rule, &chain->rules, list) { if (fatal_signal_pending(current)) return -EINTR; @@ -4117,6 +4173,7 @@ int nft_chain_validate(const struct nft_ctx *ctx, const struct nft_chain *chain) } } + nft_chain_vstate_update(ctx, chain); return 0; } EXPORT_SYMBOL_GPL(nft_chain_validate); @@ -4128,7 +4185,7 @@ static int nft_table_validate(struct net *net, const struct nft_table *table) .net = net, .family = table->family, }; - int err; + int err = 0; list_for_each_entry(chain, &table->chains, list) { if (!nft_is_base_chain(chain)) @@ -4137,12 +4194,16 @@ static int nft_table_validate(struct net *net, const struct nft_table *table) ctx.chain = chain; err = nft_chain_validate(&ctx, chain); if (err < 0) - return err; + goto err; cond_resched(); } - return 0; +err: + list_for_each_entry(chain, &table->chains, list) + memset(&chain->vstate, 0, sizeof(chain->vstate)); + + return err; } int nft_setelem_validate(const struct nft_ctx *ctx, struct nft_set *set, From a70fd483c4b936d17771ad77580f78b9c0f65cae Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Tue, 9 Dec 2025 05:24:00 +0100 Subject: [PATCH 1936/2333] ata: libata-core: Disable LPM on ST2000DM008-2FR102 [ Upstream commit ba624ba88d9f5c3e2ace9bb6697dbeb05b2dbc44 ] According to a user report, the ST2000DM008-2FR102 has problems with LPM. Reported-by: Emerson Pinter Closes: https://bugzilla.kernel.org/show_bug.cgi?id=220693 Signed-off-by: Niklas Cassel Signed-off-by: Damien Le Moal Signed-off-by: Sasha Levin --- drivers/ata/libata-core.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index f48fb63d7e854..1216b4f2eb904 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -4132,6 +4132,9 @@ static const struct ata_dev_quirks_entry __ata_dev_quirks[] = { { "ST3320[68]13AS", "SD1[5-9]", ATA_QUIRK_NONCQ | ATA_QUIRK_FIRMWARE_WARN }, + /* Seagate disks with LPM issues */ + { "ST2000DM008-2FR102", NULL, ATA_QUIRK_NOLPM }, + /* drives which fail FPDMA_AA activation (some may freeze afterwards) the ST disks also have LPM issues */ { "ST1000LM024 HN-M101MBB", NULL, ATA_QUIRK_BROKEN_FPDMA_AA | From 6a2049b7391b5cd92839d350614b4e00fa3dfb2f Mon Sep 17 00:00:00 2001 From: "Mario Limonciello (AMD)" Date: Fri, 12 Dec 2025 23:44:47 -0600 Subject: [PATCH 1937/2333] accel/amdxdna: Block running under a hypervisor [ Upstream commit 7bbf6d15e935abbb3d604c1fa157350e84a26f98 ] SVA support is required, which isn't configured by hypervisor solutions. Closes: https://github.com/QubesOS/qubes-issues/issues/10275 Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/4656 Reviewed-by: Lizhi Hou Link: https://patch.msgid.link/20251213054513.87925-1-superm1@kernel.org Signed-off-by: Mario Limonciello (AMD) Signed-off-by: Sasha Levin --- drivers/accel/amdxdna/aie2_pci.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/accel/amdxdna/aie2_pci.c b/drivers/accel/amdxdna/aie2_pci.c index 43f725e1a2d76..6e07793bbeacf 100644 --- a/drivers/accel/amdxdna/aie2_pci.c +++ b/drivers/accel/amdxdna/aie2_pci.c @@ -17,6 +17,7 @@ #include #include #include +#include #include "aie2_msg_priv.h" #include "aie2_pci.h" @@ -486,6 +487,11 @@ static int aie2_init(struct amdxdna_dev *xdna) unsigned long bars = 0; int i, nvec, ret; + if (!hypervisor_is_type(X86_HYPER_NATIVE)) { + XDNA_ERR(xdna, "Running under hypervisor not supported"); + return -EINVAL; + } + ndev = drmm_kzalloc(&xdna->ddev, sizeof(*ndev), GFP_KERNEL); if (!ndev) return -ENOMEM; From 6db8e186c977763542f1c813011bdcad691a73b8 Mon Sep 17 00:00:00 2001 From: Charlene Liu Date: Fri, 28 Nov 2025 19:38:31 -0500 Subject: [PATCH 1938/2333] drm/amd/display: Fix DP no audio issue [ Upstream commit 3886b198bd6e49c801fe9552fcfbfc387a49fbbc ] [why] need to enable APG_CLOCK_ENABLE enable first also need to wake up az from D3 before access az block Reviewed-by: Swapnil Patel Signed-off-by: Charlene Liu Signed-off-by: Chenyu Chen Tested-by: Daniel Wheeler Signed-off-by: Alex Deucher (cherry picked from commit bf5e396957acafd46003318965500914d5f4edfa) Signed-off-by: Sasha Levin --- drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c index b94fec8347400..39be5a58f837a 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c @@ -1098,13 +1098,13 @@ void dce110_enable_audio_stream(struct pipe_ctx *pipe_ctx) if (dc->current_state->res_ctx.pipe_ctx[i].stream_res.audio != NULL) num_audio++; } + if (num_audio >= 1 && clk_mgr->funcs->enable_pme_wa) { + /*wake AZ from D3 first before access az endpoint*/ + clk_mgr->funcs->enable_pme_wa(clk_mgr); + } pipe_ctx->stream_res.audio->funcs->az_enable(pipe_ctx->stream_res.audio); - if (num_audio >= 1 && clk_mgr->funcs->enable_pme_wa) - /*this is the first audio. apply the PME w/a in order to wake AZ from D3*/ - clk_mgr->funcs->enable_pme_wa(clk_mgr); - link_hwss->enable_audio_packet(pipe_ctx); if (pipe_ctx->stream_res.audio) From 6fcfcf792ce8a46c95317ea0099aff5290dda9a6 Mon Sep 17 00:00:00 2001 From: Fei Shao Date: Wed, 17 Dec 2025 18:10:47 +0800 Subject: [PATCH 1939/2333] spi: mt65xx: Use IRQF_ONESHOT with threaded IRQ [ Upstream commit 8c04b77f87e6e321ae6acd28ce1de5553916153f ] This driver is migrated to use threaded IRQ since commit 5972eb05ca32 ("spi: spi-mt65xx: Use threaded interrupt for non-SPIMEM transfer"), and we almost always want to disable the interrupt line to avoid excess interrupts while the threaded handler is processing SPI transfer. Use IRQF_ONESHOT for that purpose. In practice, we see MediaTek devices show SPI transfer timeout errors when communicating with ChromeOS EC in certain scenarios, and with IRQF_ONESHOT, the issue goes away. Signed-off-by: Fei Shao Link: https://patch.msgid.link/20251217101131.1975131-1-fshao@chromium.org Signed-off-by: Mark Brown Signed-off-by: Sasha Levin --- drivers/spi/spi-mt65xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-mt65xx.c b/drivers/spi/spi-mt65xx.c index 4b40985af1eaf..90e5813cfdc33 100644 --- a/drivers/spi/spi-mt65xx.c +++ b/drivers/spi/spi-mt65xx.c @@ -1320,7 +1320,7 @@ static int mtk_spi_probe(struct platform_device *pdev) ret = devm_request_threaded_irq(dev, irq, mtk_spi_interrupt, mtk_spi_interrupt_thread, - IRQF_TRIGGER_NONE, dev_name(dev), host); + IRQF_ONESHOT, dev_name(dev), host); if (ret) return dev_err_probe(dev, ret, "failed to register irq\n"); From 9fd86747daa6c607c33a5b2dfedc2f430d36e4af Mon Sep 17 00:00:00 2001 From: Brian Kocoloski Date: Thu, 20 Nov 2025 13:57:19 -0500 Subject: [PATCH 1940/2333] drm/amdkfd: Fix improper NULL termination of queue restore SMI event string [ Upstream commit 969faea4e9d01787c58bab4d945f7ad82dad222d ] Pass character "0" rather than NULL terminator to properly format queue restoration SMI events. Currently, the NULL terminator precedes the newline character that is intended to delineate separate events in the SMI event buffer, which can break userspace parsers. Signed-off-by: Brian Kocoloski Reviewed-by: Philip Yang Signed-off-by: Alex Deucher (cherry picked from commit 6e7143e5e6e21f9d5572e0390f7089e6d53edf3c) Signed-off-by: Sasha Levin --- drivers/gpu/drm/amd/amdkfd/kfd_smi_events.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_smi_events.c b/drivers/gpu/drm/amd/amdkfd/kfd_smi_events.c index a499449fcb068..d2bc169e84b0b 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_smi_events.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_smi_events.c @@ -312,7 +312,7 @@ void kfd_smi_event_queue_restore(struct kfd_node *node, pid_t pid) { kfd_smi_event_add(pid, node, KFD_SMI_EVENT_QUEUE_RESTORE, KFD_EVENT_FMT_QUEUE_RESTORE(ktime_get_boottime_ns(), pid, - node->id, 0)); + node->id, '0')); } void kfd_smi_event_queue_restore_rescheduled(struct mm_struct *mm) From 79dd3f1d9dd310c2af89b09c71f34d93973b200f Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Tue, 25 Nov 2025 22:39:59 +0900 Subject: [PATCH 1941/2333] can: j1939: make j1939_session_activate() fail if device is no longer registered [ Upstream commit 5d5602236f5db19e8b337a2cd87a90ace5ea776d ] syzbot is still reporting unregister_netdevice: waiting for vcan0 to become free. Usage count = 2 even after commit 93a27b5891b8 ("can: j1939: add missing calls in NETDEV_UNREGISTER notification handler") was added. A debug printk() patch found that j1939_session_activate() can succeed even after j1939_cancel_active_session() from j1939_netdev_notify(NETDEV_UNREGISTER) has completed. Since j1939_cancel_active_session() is processed with the session list lock held, checking ndev->reg_state in j1939_session_activate() with the session list lock held can reliably close the race window. Reported-by: syzbot Closes: https://syzkaller.appspot.com/bug?extid=881d65229ca4f9ae8c84 Signed-off-by: Tetsuo Handa Acked-by: Oleksij Rempel Link: https://patch.msgid.link/b9653191-d479-4c8b-8536-1326d028db5c@I-love.SAKURA.ne.jp Signed-off-by: Marc Kleine-Budde Signed-off-by: Sasha Levin --- net/can/j1939/transport.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/can/j1939/transport.c b/net/can/j1939/transport.c index fbf5c8001c9df..613a911dda100 100644 --- a/net/can/j1939/transport.c +++ b/net/can/j1939/transport.c @@ -1567,6 +1567,8 @@ int j1939_session_activate(struct j1939_session *session) if (active) { j1939_session_put(active); ret = -EAGAIN; + } else if (priv->ndev->reg_state != NETREG_REGISTERED) { + ret = -ENODEV; } else { WARN_ON_ONCE(session->state != J1939_SESSION_NEW); list_add_tail(&session->active_session_list_entry, From 530ec35c211ed1cf8cac1da4a742500932343d4f Mon Sep 17 00:00:00 2001 From: Caleb Sander Mateos Date: Tue, 16 Dec 2025 22:34:35 -0700 Subject: [PATCH 1942/2333] block: validate pi_offset integrity limit [ Upstream commit ccb8a3c08adf8121e2afb8e704f007ce99324d79 ] The PI tuple must be contained within the metadata value, so validate that pi_offset + pi_tuple_size <= metadata_size. This guards against block drivers that report invalid pi_offset values. Signed-off-by: Caleb Sander Mateos Reviewed-by: Christoph Hellwig Signed-off-by: Jens Axboe Signed-off-by: Sasha Levin --- block/blk-settings.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/block/blk-settings.c b/block/blk-settings.c index d74b13ec8e548..f2c1940fe6f1a 100644 --- a/block/blk-settings.c +++ b/block/blk-settings.c @@ -148,10 +148,9 @@ static int blk_validate_integrity_limits(struct queue_limits *lim) return -EINVAL; } - if (bi->pi_tuple_size > bi->metadata_size) { - pr_warn("pi_tuple_size (%u) exceeds metadata_size (%u)\n", - bi->pi_tuple_size, - bi->metadata_size); + if (bi->pi_offset + bi->pi_tuple_size > bi->metadata_size) { + pr_warn("pi_offset (%u) + pi_tuple_size (%u) exceeds metadata_size (%u)\n", + bi->pi_offset, bi->pi_tuple_size, bi->metadata_size); return -EINVAL; } From 003994f3b01495575a05c2042b46ae059db6259c Mon Sep 17 00:00:00 2001 From: Jussi Laako Date: Thu, 11 Dec 2025 17:22:21 +0200 Subject: [PATCH 1943/2333] ALSA: usb-audio: Update for native DSD support quirks [ Upstream commit da3a7efff64ec0d63af4499eea3a46a2e13b5797 ] Maintenance patch for native DSD support. Add set of missing device and vendor quirks; TEAC, Esoteric, Luxman and Musical Fidelity. Signed-off-by: Jussi Laako Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20251211152224.1780782-1-jussi@sonarnerd.net Signed-off-by: Sasha Levin --- sound/usb/quirks.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index 61bd61ffb1b23..94a8fdc9c6d3c 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -2230,6 +2230,12 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = { DEVICE_FLG(0x0644, 0x806b, /* TEAC UD-701 */ QUIRK_FLAG_ITF_USB_DSD_DAC | QUIRK_FLAG_CTL_MSG_DELAY | QUIRK_FLAG_IFACE_DELAY), + DEVICE_FLG(0x0644, 0x807d, /* TEAC UD-507 */ + QUIRK_FLAG_ITF_USB_DSD_DAC | QUIRK_FLAG_CTL_MSG_DELAY | + QUIRK_FLAG_IFACE_DELAY), + DEVICE_FLG(0x0644, 0x806c, /* Esoteric XD */ + QUIRK_FLAG_ITF_USB_DSD_DAC | QUIRK_FLAG_CTL_MSG_DELAY | + QUIRK_FLAG_IFACE_DELAY), DEVICE_FLG(0x06f8, 0xb000, /* Hercules DJ Console (Windows Edition) */ QUIRK_FLAG_IGNORE_CTL_ERROR), DEVICE_FLG(0x06f8, 0xd002, /* Hercules DJ Console (Macintosh Edition) */ @@ -2388,6 +2394,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = { QUIRK_FLAG_CTL_MSG_DELAY_1M), DEVICE_FLG(0x30be, 0x0101, /* Schiit Hel */ QUIRK_FLAG_IGNORE_CTL_ERROR), + DEVICE_FLG(0x3255, 0x0000, /* Luxman D-10X */ + QUIRK_FLAG_ITF_USB_DSD_DAC | QUIRK_FLAG_CTL_MSG_DELAY), DEVICE_FLG(0x339b, 0x3a07, /* Synaptics HONOR USB-C HEADSET */ QUIRK_FLAG_MIXER_PLAYBACK_MIN_MUTE), DEVICE_FLG(0x413c, 0xa506, /* Dell AE515 sound bar */ @@ -2431,6 +2439,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = { QUIRK_FLAG_DSD_RAW), VENDOR_FLG(0x2622, /* IAG Limited devices */ QUIRK_FLAG_DSD_RAW), + VENDOR_FLG(0x2772, /* Musical Fidelity devices */ + QUIRK_FLAG_DSD_RAW), VENDOR_FLG(0x278b, /* Rotel? */ QUIRK_FLAG_DSD_RAW), VENDOR_FLG(0x292b, /* Gustard/Ess based devices */ From 65f6ae1fdf22ac111ffd68d7f66d89484af90c16 Mon Sep 17 00:00:00 2001 From: Andrew Elantsev Date: Wed, 10 Dec 2025 23:38:00 +0300 Subject: [PATCH 1944/2333] ASoC: amd: yc: Add quirk for Honor MagicBook X16 2025 [ Upstream commit e2cb8ef0372665854fca6fa7b30b20dd35acffeb ] Add a DMI quirk for the Honor MagicBook X16 2025 laptop fixing the issue where the internal microphone was not detected. Signed-off-by: Andrew Elantsev Link: https://patch.msgid.link/20251210203800.142822-1-elantsew.andrew@gmail.com Signed-off-by: Mark Brown Signed-off-by: Sasha Levin --- sound/soc/amd/yc/acp6x-mach.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sound/soc/amd/yc/acp6x-mach.c b/sound/soc/amd/yc/acp6x-mach.c index f210a253da9f5..bf4d9d3365617 100644 --- a/sound/soc/amd/yc/acp6x-mach.c +++ b/sound/soc/amd/yc/acp6x-mach.c @@ -661,6 +661,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "Bravo 15 C7UCX"), } }, + { + .driver_data = &acp6x_card, + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "HONOR"), + DMI_MATCH(DMI_PRODUCT_NAME, "GOH-X"), + } + }, {} }; From b3f89f6582e0d5329822f2052134c39f2c3d387d Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Fri, 12 Dec 2025 19:46:58 +0200 Subject: [PATCH 1945/2333] ALSA: hda/realtek: enable woofer speakers on Medion NM14LNL [ Upstream commit e64826e5e367ad45539ab245b92f009ee165025c ] The ALC233 codec on these Medion NM14LNL (SPRCHRGD 14 S2) systems requires a quirk to enable all speakers. Tested-by: davplsm Link: https://github.com/thesofproject/linux/issues/5611 Signed-off-by: Kai Vehmanen Link: https://patch.msgid.link/20251212174658.752641-1-kai.vehmanen@linux.intel.com Signed-off-by: Takashi Iwai Signed-off-by: Sasha Levin --- sound/hda/codecs/realtek/alc269.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/hda/codecs/realtek/alc269.c b/sound/hda/codecs/realtek/alc269.c index eea8399e32588..eb6197d19078c 100644 --- a/sound/hda/codecs/realtek/alc269.c +++ b/sound/hda/codecs/realtek/alc269.c @@ -7211,6 +7211,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1d72, 0x1901, "RedmiBook 14", ALC256_FIXUP_ASUS_HEADSET_MIC), SND_PCI_QUIRK(0x1d72, 0x1945, "Redmi G", ALC256_FIXUP_ASUS_HEADSET_MIC), SND_PCI_QUIRK(0x1d72, 0x1947, "RedmiBook Air", ALC255_FIXUP_XIAOMI_HEADSET_MIC), + SND_PCI_QUIRK(0x1e39, 0xca14, "MEDION NM14LNL", ALC233_FIXUP_MEDION_MTL_SPK), SND_PCI_QUIRK(0x1ee7, 0x2078, "HONOR BRB-X M1010", ALC2XX_FIXUP_HEADSET_MIC), SND_PCI_QUIRK(0x1f66, 0x0105, "Ayaneo Portable Game Player", ALC287_FIXUP_CS35L41_I2C_2), SND_PCI_QUIRK(0x2014, 0x800a, "Positivo ARN50", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), From 90f5dd44d9bf911fa988667d22f668ce5586efdf Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Tue, 16 Dec 2025 11:22:45 +0100 Subject: [PATCH 1946/2333] ASoC: fsl_sai: Add missing registers to cache default [ Upstream commit 90ed688792a6b7012b3e8a2f858bc3fe7454d0eb ] Drivers does cache sync during runtime resume, setting all writable registers. Not all writable registers are set in cache default, resulting in the erorr message: fsl-sai 30c30000.sai: using zero-initialized flat cache, this may cause unexpected behavior Fix this by adding missing writable register defaults. Signed-off-by: Alexander Stein Link: https://patch.msgid.link/20251216102246.676181-1-alexander.stein@ew.tq-group.com Signed-off-by: Mark Brown Signed-off-by: Sasha Levin --- sound/soc/fsl/fsl_sai.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index 86730c2149146..2fa14fbdfe1a8 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -1081,6 +1081,7 @@ static const struct reg_default fsl_sai_reg_defaults_ofs0[] = { {FSL_SAI_TDR6, 0}, {FSL_SAI_TDR7, 0}, {FSL_SAI_TMR, 0}, + {FSL_SAI_TTCTL, 0}, {FSL_SAI_RCR1(0), 0}, {FSL_SAI_RCR2(0), 0}, {FSL_SAI_RCR3(0), 0}, @@ -1104,12 +1105,14 @@ static const struct reg_default fsl_sai_reg_defaults_ofs8[] = { {FSL_SAI_TDR6, 0}, {FSL_SAI_TDR7, 0}, {FSL_SAI_TMR, 0}, + {FSL_SAI_TTCTL, 0}, {FSL_SAI_RCR1(8), 0}, {FSL_SAI_RCR2(8), 0}, {FSL_SAI_RCR3(8), 0}, {FSL_SAI_RCR4(8), 0}, {FSL_SAI_RCR5(8), 0}, {FSL_SAI_RMR, 0}, + {FSL_SAI_RTCTL, 0}, {FSL_SAI_MCTL, 0}, {FSL_SAI_MDIV, 0}, }; From 81531bdea972c3cd8f147f61ca6027fa24e08fc3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20R=C3=A1bek?= Date: Fri, 12 Dec 2025 17:08:23 +0100 Subject: [PATCH 1947/2333] scsi: sg: Fix occasional bogus elapsed time that exceeds timeout MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 0e1677654259a2f3ccf728de1edde922a3c4ba57 ] A race condition was found in sg_proc_debug_helper(). It was observed on a system using an IBM LTO-9 SAS Tape Drive (ULTRIUM-TD9) and monitoring /proc/scsi/sg/debug every second. A very large elapsed time would sometimes appear. This is caused by two race conditions. We reproduced the issue with an IBM ULTRIUM-HH9 tape drive on an x86_64 architecture. A patched kernel was built, and the race condition could not be observed anymore after the application of this patch. A reproducer C program utilising the scsi_debug module was also built by Changhui Zhong and can be viewed here: https://github.com/MichaelRabek/linux-tests/blob/master/drivers/scsi/sg/sg_race_trigger.c The first race happens between the reading of hp->duration in sg_proc_debug_helper() and request completion in sg_rq_end_io(). The hp->duration member variable may hold either of two types of information: #1 - The start time of the request. This value is present while the request is not yet finished. #2 - The total execution time of the request (end_time - start_time). If sg_proc_debug_helper() executes *after* the value of hp->duration was changed from #1 to #2, but *before* srp->done is set to 1 in sg_rq_end_io(), a fresh timestamp is taken in the else branch, and the elapsed time (value type #2) is subtracted from a timestamp, which cannot yield a valid elapsed time (which is a type #2 value as well). To fix this issue, the value of hp->duration must change under the protection of the sfp->rq_list_lock in sg_rq_end_io(). Since sg_proc_debug_helper() takes this read lock, the change to srp->done and srp->header.duration will happen atomically from the perspective of sg_proc_debug_helper() and the race condition is thus eliminated. The second race condition happens between sg_proc_debug_helper() and sg_new_write(). Even though hp->duration is set to the current time stamp in sg_add_request() under the write lock's protection, it gets overwritten by a call to get_sg_io_hdr(), which calls copy_from_user() to copy struct sg_io_hdr from userspace into kernel space. hp->duration is set to the start time again in sg_common_write(). If sg_proc_debug_helper() is called between these two calls, an arbitrary value set by userspace (usually zero) is used to compute the elapsed time. To fix this issue, hp->duration must be set to the current timestamp again after get_sg_io_hdr() returns successfully. A small race window still exists between get_sg_io_hdr() and setting hp->duration, but this window is only a few instructions wide and does not result in observable issues in practice, as confirmed by testing. Additionally, we fix the format specifier from %d to %u for printing unsigned int values in sg_proc_debug_helper(). Signed-off-by: Michal Rábek Suggested-by: Tomas Henzl Tested-by: Changhui Zhong Reviewed-by: Ewan D. Milne Reviewed-by: John Meneghini Reviewed-by: Tomas Henzl Link: https://patch.msgid.link/20251212160900.64924-1-mrabek@redhat.com Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin --- drivers/scsi/sg.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index b3af9b78fa123..57fba34832ad1 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -731,6 +731,8 @@ sg_new_write(Sg_fd *sfp, struct file *file, const char __user *buf, sg_remove_request(sfp, srp); return -EFAULT; } + hp->duration = jiffies_to_msecs(jiffies); + if (hp->interface_id != 'S') { sg_remove_request(sfp, srp); return -ENOSYS; @@ -815,7 +817,6 @@ sg_common_write(Sg_fd * sfp, Sg_request * srp, return -ENODEV; } - hp->duration = jiffies_to_msecs(jiffies); if (hp->interface_id != '\0' && /* v3 (or later) interface */ (SG_FLAG_Q_AT_TAIL & hp->flags)) at_head = 0; @@ -1338,9 +1339,6 @@ sg_rq_end_io(struct request *rq, blk_status_t status) "sg_cmd_done: pack_id=%d, res=0x%x\n", srp->header.pack_id, result)); srp->header.resid = resid; - ms = jiffies_to_msecs(jiffies); - srp->header.duration = (ms > srp->header.duration) ? - (ms - srp->header.duration) : 0; if (0 != result) { struct scsi_sense_hdr sshdr; @@ -1389,6 +1387,9 @@ sg_rq_end_io(struct request *rq, blk_status_t status) done = 0; } srp->done = done; + ms = jiffies_to_msecs(jiffies); + srp->header.duration = (ms > srp->header.duration) ? + (ms - srp->header.duration) : 0; write_unlock_irqrestore(&sfp->rq_list_lock, iflags); if (likely(done)) { @@ -2533,6 +2534,7 @@ static void sg_proc_debug_helper(struct seq_file *s, Sg_device * sdp) const sg_io_hdr_t *hp; const char * cp; unsigned int ms; + unsigned int duration; k = 0; list_for_each_entry(fp, &sdp->sfds, sfd_siblings) { @@ -2570,13 +2572,17 @@ static void sg_proc_debug_helper(struct seq_file *s, Sg_device * sdp) seq_printf(s, " id=%d blen=%d", srp->header.pack_id, blen); if (srp->done) - seq_printf(s, " dur=%d", hp->duration); + seq_printf(s, " dur=%u", hp->duration); else { ms = jiffies_to_msecs(jiffies); - seq_printf(s, " t_o/elap=%d/%d", + duration = READ_ONCE(hp->duration); + if (duration) + duration = (ms > duration ? + ms - duration : 0); + seq_printf(s, " t_o/elap=%u/%u", (new_interface ? hp->timeout : jiffies_to_msecs(fp->timeout)), - (ms > hp->duration ? ms - hp->duration : 0)); + duration); } seq_printf(s, "ms sgat=%d op=0x%02x\n", usg, (int) srp->data.cmd_opcode); From 69695f5331d4d670eff76376faa3aeb5d68733e3 Mon Sep 17 00:00:00 2001 From: Mateusz Litwin Date: Thu, 18 Dec 2025 22:33:04 +0100 Subject: [PATCH 1948/2333] spi: cadence-quadspi: Prevent lost complete() call during indirect read [ Upstream commit d67396c9d697041b385d70ff2fd59cb07ae167e8 ] A race condition exists between the read loop and IRQ `complete()` call. An interrupt could call the complete() between the inner loop and reinit_completion(), potentially losing the completion event and causing an unnecessary timeout. Moving reinit_completion() before the loop prevents this. A premature signal will only result in a spurious wakeup and another wait cycle, which is preferable to waiting for a timeout. Signed-off-by: Mateusz Litwin Link: https://patch.msgid.link/20251218-cqspi_indirect_read_improve-v2-1-396079972f2a@nokia.com Signed-off-by: Mark Brown Signed-off-by: Sasha Levin --- drivers/spi/spi-cadence-quadspi.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi-cadence-quadspi.c b/drivers/spi/spi-cadence-quadspi.c index 3231bdaf9bd06..1cca9d87fbde4 100644 --- a/drivers/spi/spi-cadence-quadspi.c +++ b/drivers/spi/spi-cadence-quadspi.c @@ -769,6 +769,7 @@ static int cqspi_indirect_read_execute(struct cqspi_flash_pdata *f_pdata, readl(reg_base + CQSPI_REG_INDIRECTRD); /* Flush posted write. */ while (remaining > 0) { + ret = 0; if (use_irq && !wait_for_completion_timeout(&cqspi->transfer_complete, msecs_to_jiffies(CQSPI_READ_TIMEOUT_MS))) @@ -781,6 +782,14 @@ static int cqspi_indirect_read_execute(struct cqspi_flash_pdata *f_pdata, if (cqspi->slow_sram) writel(0x0, reg_base + CQSPI_REG_IRQMASK); + /* + * Prevent lost interrupt and race condition by reinitializing early. + * A spurious wakeup and another wait cycle can occur here, + * which is preferable to waiting until timeout if interrupt is lost. + */ + if (use_irq) + reinit_completion(&cqspi->transfer_complete); + bytes_to_read = cqspi_get_rd_sram_level(cqspi); if (ret && bytes_to_read == 0) { @@ -813,7 +822,6 @@ static int cqspi_indirect_read_execute(struct cqspi_flash_pdata *f_pdata, } if (use_irq && remaining > 0) { - reinit_completion(&cqspi->transfer_complete); if (cqspi->slow_sram) writel(CQSPI_REG_IRQ_WATERMARK, reg_base + CQSPI_REG_IRQMASK); } From b6fe42bc55af3fb17c8c03def2f8a1f7fa907af6 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Sat, 17 Jan 2026 16:35:34 +0100 Subject: [PATCH 1949/2333] Linux 6.18.6 Link: https://lore.kernel.org/r/20260115164202.305475649@linuxfoundation.org Tested-by: Ronald Warsow Tested-by: Brett A C Sheffield Tested-by: Slade Watkins Tested-by: Shuah Khan Tested-by: Florian Fainelli Tested-by: Takeshi Ogasawara Tested-by: Salvatore Bonaccorso Tested-by: Ron Economos Tested-by: Jon Hunter Tested-by: Peter Schneider Tested-by: Mark Brown Tested-by: Hardik Garg Tested-by: Brett Mastbergen Tested-by: Miguel Ojeda Signed-off-by: Greg Kroah-Hartman --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 30c332829b0fc..23a575ce425cd 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 VERSION = 6 PATCHLEVEL = 18 -SUBLEVEL = 5 +SUBLEVEL = 6 EXTRAVERSION = NAME = Baby Opossum Posse From 7a49675d6fd6f0df9e3c028d042130e467ec2647 Mon Sep 17 00:00:00 2001 From: Abhinaba Rakshit Date: Mon, 19 Jan 2026 13:35:55 +0530 Subject: [PATCH 1950/2333] FROMGIT: arm64: dts: qcom: monaco: add QCrypto node Add Qualcomm Crypto Engine device node for Monaco platform. QCE and Crypto DMA nodes patch was applied as part of commit a86d84409947 ("arm64: dts: qcom: qcs8300: add QCrypto nodes"), however was partially reverted by commit cdc117c40537 ("arm64: dts: qcom: qcs8300: Partially revert "arm64: dts: qcom: qcs8300: add QCrypto nodes"") due to compatible string being mismatched against schema. Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/all/20251224-enable-qualcomm-crypto-engine-for-monaco-v3-1-6073430bbc13@oss.qualcomm.com/ Signed-off-by: Abhinaba Rakshit --- arch/arm64/boot/dts/qcom/qcs8300.dtsi | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/qcs8300.dtsi b/arch/arm64/boot/dts/qcom/qcs8300.dtsi index 04d1fea53ea1e..dea447857bb5e 100644 --- a/arch/arm64/boot/dts/qcom/qcs8300.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs8300.dtsi @@ -2665,6 +2665,18 @@ clocks = <&gcc GCC_UFS_PHY_ICE_CORE_CLK>; }; + crypto: crypto@1dfa000 { + compatible = "qcom,qcs8300-qce", "qcom,sm8150-qce", "qcom,qce"; + reg = <0x0 0x01dfa000 0x0 0x6000>; + dmas = <&cryptobam 4>, <&cryptobam 5>; + dma-names = "rx", "tx"; + iommus = <&apps_smmu 0x480 0x0>, + <&apps_smmu 0x481 0x0>; + interconnects = <&aggre2_noc MASTER_CRYPTO_CORE0 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "memory"; + }; + tcsr_mutex: hwlock@1f40000 { compatible = "qcom,tcsr-mutex"; reg = <0x0 0x01f40000 0x0 0x20000>; From 192c11a11b854ab6ea012560e6659e9e99c88ca0 Mon Sep 17 00:00:00 2001 From: Harshal Dev Date: Mon, 19 Jan 2026 13:09:02 +0530 Subject: [PATCH 1951/2333] FROMGIT: dt-bindings: crypto: qcom,prng: document x1e80100 Document x1e80100 compatible for the True Random Number Generator. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Harshal Dev Link: https://lore.kernel.org/all/20251223-trng_dt_binding_x1e80100-v4-1-5bfe781f9c7b@oss.qualcomm.com/ Signed-off-by: Abhinaba Rakshit --- Documentation/devicetree/bindings/crypto/qcom,prng.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/crypto/qcom,prng.yaml b/Documentation/devicetree/bindings/crypto/qcom,prng.yaml index ed7e16bd11d33..aa3c097a6acdb 100644 --- a/Documentation/devicetree/bindings/crypto/qcom,prng.yaml +++ b/Documentation/devicetree/bindings/crypto/qcom,prng.yaml @@ -29,6 +29,7 @@ properties: - qcom,sm8550-trng - qcom,sm8650-trng - qcom,sm8750-trng + - qcom,x1e80100-trng - const: qcom,trng reg: From 45b8e5f298da93a2d5cb2b4dbdde714b389b401f Mon Sep 17 00:00:00 2001 From: Harshal Dev Date: Mon, 19 Jan 2026 13:16:48 +0530 Subject: [PATCH 1952/2333] FROMGIT: arm64: dts: qcom: x1e80100: add TRNG node The x1e80100 SoC has a True Random Number Generator, add the node with the correct compatible set. Reviewed-by: Dmitry Baryshkov Tested-by: Wenjia Zhang Reviewed-by: Konrad Dybcio Signed-off-by: Harshal Dev Link: https://lore.kernel.org/all/20251223-trng_dt_binding_x1e80100-v4-2-5bfe781f9c7b@oss.qualcomm.com/ Signed-off-by: Abhinaba Rakshit --- arch/arm64/boot/dts/qcom/x1e80100.dtsi | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/x1e80100.dtsi b/arch/arm64/boot/dts/qcom/x1e80100.dtsi index 7319aef81b782..bcea64e90a4fe 100644 --- a/arch/arm64/boot/dts/qcom/x1e80100.dtsi +++ b/arch/arm64/boot/dts/qcom/x1e80100.dtsi @@ -3057,6 +3057,11 @@ interconnect-names = "memory"; }; + rng: rng@10c3000 { + compatible = "qcom,x1e80100-trng", "qcom,trng"; + reg = <0x0 0x010c3000 0x0 0x1000>; + }; + cnoc_main: interconnect@1500000 { compatible = "qcom,x1e80100-cnoc-main"; reg = <0 0x01500000 0 0x14400>; From 359c23b8d636809abb37f46d9532d9db149acec5 Mon Sep 17 00:00:00 2001 From: Yongxing Mou Date: Mon, 19 Jan 2026 15:47:00 +0800 Subject: [PATCH 1953/2333] QCLINUX: prune.config: Enable backlight config for Hamoa/Purwa Hamoa/Purwa currently requires the backlight node from the eDP device, but this macro was overridden by CONFIG_DRM_NOUVEAU. Remove it from prune.config to properly enable the BACKLIGHT_* related config. Signed-off-by: Yongxing Mou --- arch/arm64/configs/prune.config | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm64/configs/prune.config b/arch/arm64/configs/prune.config index 54cf8fa1cd0e0..fba07d6ebe12d 100644 --- a/arch/arm64/configs/prune.config +++ b/arch/arm64/configs/prune.config @@ -188,7 +188,6 @@ # CONFIG_DRM_I2C_NXP_TDA998X is not set # CONFIG_DRM_MALI_DISPLAY is not set # CONFIG_DRM_KOMEDA is not set -# CONFIG_DRM_NOUVEAU is not set # CONFIG_DRM_PANEL_BOE_TV101WUM_NL6 is not set # CONFIG_DRM_PANEL_MANTIX_MLAF057WE51 is not set # CONFIG_DRM_PANEL_RAYDIUM_RM67191 is not set From 25e9e13d654b8c0867c2ba54f4a119960dbc566b Mon Sep 17 00:00:00 2001 From: Qian Zhang Date: Thu, 8 Jan 2026 11:46:07 +0800 Subject: [PATCH 1954/2333] FROMGIT: wifi: ath11k: Fix failure to connect to a 6 GHz AP STA fails to connect to a 6 GHz AP with the following errors: ath11k_pci 0000:01:00.0: failed to handle chan list with power type 1 wlp1s0: deauthenticating from c8:a3:e8:dd:41:e3 by local choice (Reason: 3=DEAUTH_LEAVING) ath11k_reg_handle_chan_list() treats the update as redundant and returns -EINVAL. That causes the connection attempt to fail. Avoid unnecessary validation during association. Apply the regulatory redundant check only when the power type is IEEE80211_REG_UNSET_AP, which only occurs during core initialization. Tested-on: WCN6855 hw2.1 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.41 Signed-off-by: Qian Zhang Reviewed-by: Baochen Qiang Link: https://patch.msgid.link/20260108034607.812885-1-qian.zhang@oss.qualcomm.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath11k/reg.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/reg.c b/drivers/net/wireless/ath/ath11k/reg.c index d62a2014315a0..49b79648752cf 100644 --- a/drivers/net/wireless/ath/ath11k/reg.c +++ b/drivers/net/wireless/ath/ath11k/reg.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include @@ -926,8 +926,11 @@ int ath11k_reg_handle_chan_list(struct ath11k_base *ab, */ if (ab->default_regd[pdev_idx] && !ab->new_regd[pdev_idx] && !memcmp((char *)ab->default_regd[pdev_idx]->alpha2, - (char *)reg_info->alpha2, 2)) - goto retfail; + (char *)reg_info->alpha2, 2) && + power_type == IEEE80211_REG_UNSET_AP) { + ath11k_reg_reset_info(reg_info); + return 0; + } /* Intersect new rules with default regd if a new country setting was * requested, i.e a default regd was already set during initialization From 9922c3ad25989360ff0f3ec351da333082c9de1e Mon Sep 17 00:00:00 2001 From: Sudarshan Shetty Date: Wed, 14 Jan 2026 15:30:41 +0530 Subject: [PATCH 1955/2333] FROMLIST: dt-bindings: arm: qcom: talos-evk: Add QCS615 Talos EVK SMARC platform Add binding support for the Qualcomm Technologies, Inc. Talos EVK SMARC platform based on the QCS615 SoC. Link: https://lore.kernel.org/all/20260114100043.1310164-2-tessolveupstream@gmail.com/ Acked-by: Krzysztof Kozlowski Signed-off-by: Sudarshan Shetty Signed-off-by: Jie Gan --- Documentation/devicetree/bindings/arm/qcom.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/arm/qcom.yaml b/Documentation/devicetree/bindings/arm/qcom.yaml index ab7de3b0888b8..b56fbf968197a 100644 --- a/Documentation/devicetree/bindings/arm/qcom.yaml +++ b/Documentation/devicetree/bindings/arm/qcom.yaml @@ -874,6 +874,7 @@ properties: - items: - enum: - qcom,qcs615-ride + - qcom,talos-evk - const: qcom,qcs615 - const: qcom,sm6150 From 16c90977dc722989bd52590887dddba3ccca8b93 Mon Sep 17 00:00:00 2001 From: Sudarshan Shetty Date: Wed, 14 Jan 2026 15:30:42 +0530 Subject: [PATCH 1956/2333] FROMLIST: arm64: dts: qcom: talos/qcs615-ride: Fix inconsistent USB PHY node naming The USB PHY nodes has inconsistent labels as 'usb_1_hspy' and 'usb_hsphy_2' across talos.dtsi and qcs615-ride.dts. This patch renames them to follow a consistent naming scheme. No functional changes, only label renaming. Link: https://lore.kernel.org/all/20260114100043.1310164-3-tessolveupstream@gmail.com/ Reviewed-by: Dmitry Baryshkov Signed-off-by: Sudarshan Shetty Signed-off-by: Jie Gan --- arch/arm64/boot/dts/qcom/qcs615-ride.dts | 2 +- arch/arm64/boot/dts/qcom/talos.dtsi | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/qcs615-ride.dts b/arch/arm64/boot/dts/qcom/qcs615-ride.dts index d18a6393c4c2d..39544c04e65a1 100644 --- a/arch/arm64/boot/dts/qcom/qcs615-ride.dts +++ b/arch/arm64/boot/dts/qcom/qcs615-ride.dts @@ -639,7 +639,7 @@ }; }; -&usb_1_hsphy { +&usb_hsphy_1 { vdd-supply = <&vreg_l5a>; vdda-pll-supply = <&vreg_l12a>; vdda-phy-dpdm-supply = <&vreg_l13a>; diff --git a/arch/arm64/boot/dts/qcom/talos.dtsi b/arch/arm64/boot/dts/qcom/talos.dtsi index df165c12a3c96..164b6d0df8532 100644 --- a/arch/arm64/boot/dts/qcom/talos.dtsi +++ b/arch/arm64/boot/dts/qcom/talos.dtsi @@ -4397,7 +4397,7 @@ #interconnect-cells = <1>; }; - usb_1_hsphy: phy@88e2000 { + usb_hsphy_1: phy@88e2000 { compatible = "qcom,qcs615-qusb2-phy"; reg = <0x0 0x88e2000 0x0 0x180>; @@ -4531,7 +4531,7 @@ iommus = <&apps_smmu 0x140 0x0>; interrupts = ; - phys = <&usb_1_hsphy>, <&usb_qmpphy>; + phys = <&usb_hsphy_1>, <&usb_qmpphy>; phy-names = "usb2-phy", "usb3-phy"; snps,dis-u1-entry-quirk; From 565e95718b36de96a5aaa97a0efcbab4f2f08141 Mon Sep 17 00:00:00 2001 From: Sudarshan Shetty Date: Wed, 14 Jan 2026 15:30:43 +0530 Subject: [PATCH 1957/2333] FROMLIST: arm64: dts: qcom: talos-evk: Add support for QCS615 talos evk board Add the device tree for the QCS615-based Talos EVK platform. The platform is composed of a System-on-Module following the SMARC standard, and a Carrier Board. The Carrier Board supports several display configurations, HDMI and LVDS. Both configurations use the same base hardware, with the display selection controlled by a DIP switch. Use a DTBO file, talos-evk-lvds-auo,g133han01.dtso, which defines an overlay that disables HDMI and adds LVDS. The DTs file talos-evk can describe the HDMI display configurations. The initial device tree includes support for: - CPU and memory - UART - GPIOs - Regulators - PMIC - Early console - AT24MAC602 EEPROM - MCP2515 SPI to CAN - ADV7535 DSI-to-HDMI bridge - DisplayPort interface - SN65DSI84ZXHR DSI-to-LVDS bridge - Wi-Fi/BT Link: https://lore.kernel.org/all/20260114100043.1310164-4-tessolveupstream@gmail.com/ Reviewed-by: Dmitry Baryshkov Signed-off-by: Sudarshan Shetty Signed-off-by: Jie Gan --- arch/arm64/boot/dts/qcom/Makefile | 4 + .../qcom/talos-evk-lvds-auo,g133han01.dtso | 131 ++++ arch/arm64/boot/dts/qcom/talos-evk-som.dtsi | 616 ++++++++++++++++++ arch/arm64/boot/dts/qcom/talos-evk.dts | 139 ++++ 4 files changed, 890 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/talos-evk-lvds-auo,g133han01.dtso create mode 100644 arch/arm64/boot/dts/qcom/talos-evk-som.dtsi create mode 100644 arch/arm64/boot/dts/qcom/talos-evk.dts diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile index b30b3e7e37c57..4d9098501f3d7 100644 --- a/arch/arm64/boot/dts/qcom/Makefile +++ b/arch/arm64/boot/dts/qcom/Makefile @@ -364,6 +364,10 @@ dtb-$(CONFIG_ARCH_QCOM) += sm8650-mtp.dtb dtb-$(CONFIG_ARCH_QCOM) += sm8650-qrd.dtb dtb-$(CONFIG_ARCH_QCOM) += sm8750-mtp.dtb dtb-$(CONFIG_ARCH_QCOM) += sm8750-qrd.dtb +dtb-$(CONFIG_ARCH_QCOM) += talos-evk.dtb +talos-evk-lvds-auo,g133han01-dtbs := \ + talos-evk.dtb talos-evk-lvds-auo,g133han01.dtbo +dtb-$(CONFIG_ARCH_QCOM) += talos-evk-lvds-auo,g133han01.dtb x1e001de-devkit-el2-dtbs := x1e001de-devkit.dtb x1-el2.dtbo dtb-$(CONFIG_ARCH_QCOM) += x1e001de-devkit.dtb x1e001de-devkit-el2.dtb x1e78100-lenovo-thinkpad-t14s-el2-dtbs := x1e78100-lenovo-thinkpad-t14s.dtb x1-el2.dtbo diff --git a/arch/arm64/boot/dts/qcom/talos-evk-lvds-auo,g133han01.dtso b/arch/arm64/boot/dts/qcom/talos-evk-lvds-auo,g133han01.dtso new file mode 100644 index 0000000000000..fc2296e346b83 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/talos-evk-lvds-auo,g133han01.dtso @@ -0,0 +1,131 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ +/dts-v1/; +/plugin/; + +#include + +&{/} { + backlight: backlight { + compatible = "gpio-backlight"; + gpios = <&tlmm 59 GPIO_ACTIVE_HIGH>, + <&tlmm 115 GPIO_ACTIVE_HIGH>; + default-on; + }; + + panel-lvds { + compatible = "auo,g133han01"; + power-supply = <&vreg_v3p3>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + /* LVDS A (Odd pixels) */ + port@0 { + reg = <0>; + dual-lvds-odd-pixels; + + lvds_panel_out_a: endpoint { + remote-endpoint = <&sn65dsi84_out_a>; + }; + }; + + /* LVDS B (Even pixels) */ + port@1 { + reg = <1>; + dual-lvds-even-pixels; + + lvds_panel_out_b: endpoint { + remote-endpoint = <&sn65dsi84_out_b>; + }; + }; + }; + }; + + vreg_v3p3: regulator-v3p3 { + compatible = "regulator-fixed"; + regulator-name = "vdd-3v3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; +}; + +&hdmi_connector { + status = "disabled"; +}; + +&i2c1 { + clock-frequency = <400000>; + + status = "okay"; + + hdmi_bridge: bridge@3d { + status = "disabled"; + }; + + lvds_bridge: bridge@2c { + compatible = "ti,sn65dsi84"; + reg = <0x2c>; + enable-gpios = <&tlmm 42 GPIO_ACTIVE_HIGH>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + sn65dsi84_in: endpoint { + data-lanes = <1 2 3 4>; + remote-endpoint = <&mdss_dsi0_out>; + }; + }; + + port@2 { + reg = <2>; + + sn65dsi84_out_a: endpoint { + data-lanes = <1 2 3 4>; + remote-endpoint = <&lvds_panel_out_a>; + }; + }; + + port@3 { + reg = <3>; + + sn65dsi84_out_b: endpoint { + data-lanes = <1 2 3 4>; + remote-endpoint = <&lvds_panel_out_b>; + }; + }; + }; + }; +}; + +&mdss_dsi0 { + vdda-supply = <&vreg_l11a>; + + status = "okay"; +}; + +&mdss_dsi0_out { + remote-endpoint = <&sn65dsi84_in>; + data-lanes = <0 1 2 3>; +}; + +&tlmm { + lcd_bklt_en: lcd-bklt-en-state { + pins = "gpio115"; + function = "gpio"; + bias-disable; + }; + + lcd_bklt_pwm: lcd-bklt-pwm-state { + pins = "gpio59"; + function = "gpio"; + bias-disable; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/talos-evk-som.dtsi b/arch/arm64/boot/dts/qcom/talos-evk-som.dtsi new file mode 100644 index 0000000000000..e63f88da8ff6f --- /dev/null +++ b/arch/arm64/boot/dts/qcom/talos-evk-som.dtsi @@ -0,0 +1,616 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ +/dts-v1/; + +#include +#include +#include "talos.dtsi" +#include "pm8150.dtsi" +/ { + aliases { + mmc0 = &sdhc_1; + serial0 = &uart0; + serial1 = &uart7; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + clocks { + can_osc: can-oscillator { + compatible = "fixed-clock"; + clock-frequency = <20000000>; + #clock-cells = <0>; + }; + + sleep_clk: sleep-clk { + compatible = "fixed-clock"; + clock-frequency = <32764>; + #clock-cells = <0>; + }; + + xo_board_clk: xo-board-clk { + compatible = "fixed-clock"; + clock-frequency = <38400000>; + #clock-cells = <0>; + }; + }; + + regulator-usb2-vbus { + compatible = "regulator-fixed"; + regulator-name = "USB2_VBUS"; + gpio = <&pm8150_gpios 10 GPIO_ACTIVE_HIGH>; + pinctrl-0 = <&usb2_en>; + pinctrl-names = "default"; + enable-active-high; + regulator-always-on; + }; + + vreg_conn_1p8: regulator-conn-1p8 { + compatible = "regulator-fixed"; + regulator-name = "vreg_conn_1p8"; + startup-delay-us = <4000>; + enable-active-high; + gpio = <&pm8150_gpios 1 GPIO_ACTIVE_HIGH>; + }; + + vreg_conn_pa: regulator-conn-pa { + compatible = "regulator-fixed"; + regulator-name = "vreg_conn_pa"; + startup-delay-us = <4000>; + enable-active-high; + gpio = <&pm8150_gpios 6 GPIO_ACTIVE_HIGH>; + }; + + vreg_v3p3_can: regulator-v3p3-can { + compatible = "regulator-fixed"; + regulator-name = "vreg-v3p3-can"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + + vreg_v5p0_can: regulator-v5p0-can { + compatible = "regulator-fixed"; + regulator-name = "vreg-v5p0-can"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + regulator-boot-on; + regulator-always-on; + }; + + wcn6855-pmu { + compatible = "qcom,wcn6855-pmu"; + + pinctrl-0 = <&bt_en_state>, <&wlan_en_state>; + pinctrl-names = "default"; + + bt-enable-gpios = <&tlmm 85 GPIO_ACTIVE_HIGH>; + wlan-enable-gpios = <&tlmm 84 GPIO_ACTIVE_HIGH>; + + vddio-supply = <&vreg_conn_pa>; + vddaon-supply = <&vreg_s5a>; + vddpmu-supply = <&vreg_conn_1p8>; + vddpmumx-supply = <&vreg_conn_1p8>; + vddpmucx-supply = <&vreg_conn_pa>; + vddrfa0p95-supply = <&vreg_s5a>; + vddrfa1p3-supply = <&vreg_s6a>; + vddrfa1p9-supply = <&vreg_l15a>; + vddpcie1p3-supply = <&vreg_s6a>; + vddpcie1p9-supply = <&vreg_l15a>; + + regulators { + vreg_pmu_rfa_cmn: ldo0 { + regulator-name = "vreg_pmu_rfa_cmn"; + }; + + vreg_pmu_aon_0p59: ldo1 { + regulator-name = "vreg_pmu_aon_0p59"; + }; + + vreg_pmu_wlcx_0p8: ldo2 { + regulator-name = "vreg_pmu_wlcx_0p8"; + }; + + vreg_pmu_wlmx_0p85: ldo3 { + regulator-name = "vreg_pmu_wlmx_0p85"; + }; + + vreg_pmu_btcmx_0p85: ldo4 { + regulator-name = "vreg_pmu_btcmx_0p85"; + }; + + vreg_pmu_rfa_0p8: ldo5 { + regulator-name = "vreg_pmu_rfa_0p8"; + }; + + vreg_pmu_rfa_1p2: ldo6 { + regulator-name = "vreg_pmu_rfa_1p2"; + }; + + vreg_pmu_rfa_1p7: ldo7 { + regulator-name = "vreg_pmu_rfa_1p7"; + }; + + vreg_pmu_pcie_0p9: ldo8 { + regulator-name = "vreg_pmu_pcie_0p9"; + }; + + vreg_pmu_pcie_1p8: ldo9 { + regulator-name = "vreg_pmu_pcie_1p8"; + }; + }; + }; + + wifi_1p8v: regulator-wifi-1p8v { + compatible = "regulator-fixed"; + regulator-name = "wifi_1p8v"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + gpio = <&tlmm 91 GPIO_ACTIVE_HIGH>; + enable-active-high; + pinctrl-0 = <&wifi_reg_en_pins_state>; + pinctrl-names = "default"; + regulator-boot-on; + regulator-always-on; + }; + + wifi_3p85v: regulator-wifi-3p85v { + compatible = "regulator-fixed"; + regulator-name = "wifi_3p85v"; + regulator-min-microvolt = <3850000>; + regulator-max-microvolt = <3850000>; + gpio = <&tlmm 91 GPIO_ACTIVE_HIGH>; + enable-active-high; + pinctrl-0 = <&wifi_reg_en_pins_state>; + pinctrl-names = "default"; + regulator-boot-on; + regulator-always-on; + }; +}; + +&apps_rsc { + regulators-0 { + compatible = "qcom,pm8150-rpmh-regulators"; + qcom,pmic-id = "a"; + + vreg_s3a: smps3 { + regulator-name = "vreg_s3a"; + regulator-min-microvolt = <600000>; + regulator-max-microvolt = <650000>; + regulator-initial-mode = ; + }; + + vreg_s4a: smps4 { + regulator-name = "vreg_s4a"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1829000>; + regulator-initial-mode = ; + }; + + vreg_s5a: smps5 { + regulator-name = "vreg_s5a"; + regulator-min-microvolt = <1896000>; + regulator-max-microvolt = <2040000>; + regulator-initial-mode = ; + }; + + vreg_s6a: smps6 { + regulator-name = "vreg_s6a"; + regulator-min-microvolt = <1304000>; + regulator-max-microvolt = <1404000>; + regulator-initial-mode = ; + }; + + vreg_l1a: ldo1 { + regulator-name = "vreg_l1a"; + regulator-min-microvolt = <488000>; + regulator-max-microvolt = <852000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l2a: ldo2 { + regulator-name = "vreg_l2a"; + regulator-min-microvolt = <1650000>; + regulator-max-microvolt = <3100000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l3a: ldo3 { + regulator-name = "vreg_l3a"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1248000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l5a: ldo5 { + regulator-name = "vreg_l5a"; + regulator-min-microvolt = <875000>; + regulator-max-microvolt = <975000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l7a: ldo7 { + regulator-name = "vreg_l7a"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1900000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l8a: ldo8 { + regulator-name = "vreg_l8a"; + regulator-min-microvolt = <1150000>; + regulator-max-microvolt = <1350000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l10a: ldo10 { + regulator-name = "vreg_l10a"; + regulator-min-microvolt = <2950000>; + regulator-max-microvolt = <3312000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l11a: ldo11 { + regulator-name = "vreg_l11a"; + regulator-min-microvolt = <1232000>; + regulator-max-microvolt = <1260000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l12a: ldo12 { + regulator-name = "vreg_l12a"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1890000>; + regulator-initial-mode = ; + }; + + vreg_l13a: ldo13 { + regulator-name = "vreg_l13a"; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3230000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l15a: ldo15 { + regulator-name = "vreg_l15a"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1904000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l16a: ldo16 { + regulator-name = "vreg_l16a"; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3312000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l17a: ldo17 { + regulator-name = "vreg_l17a"; + regulator-min-microvolt = <2950000>; + regulator-max-microvolt = <3312000>; + regulator-initial-mode = ; + }; + }; +}; + +&gpi_dma0 { + status = "okay"; +}; + +&gpi_dma1 { + status = "okay"; +}; + +&i2c5 { + clock-frequency = <400000>; + status = "okay"; + + eeprom@57 { + compatible = "atmel,24c02"; + reg = <0x57>; + pagesize = <16>; + }; + + eeprom@5f { + compatible = "atmel,24mac602"; + reg = <0x5f>; + pagesize = <16>; + }; +}; + +&mdss { + status = "okay"; +}; + +&mdss_dp0 { + status = "okay"; +}; + +&mdss_dp0_out { + link-frequencies = /bits/ 64 <1620000000 2700000000 5400000000>; + remote-endpoint = <&dp0_connector_in>; +}; + +&mdss_dsi0 { + vdda-supply = <&vreg_l11a>; + status = "okay"; +}; + +&mdss_dsi0_phy { + vcca-supply = <&vreg_l5a>; + status = "okay"; +}; + +&pcie { + perst-gpios = <&tlmm 89 GPIO_ACTIVE_LOW>; + wake-gpios = <&tlmm 100 GPIO_ACTIVE_HIGH>; + + pinctrl-0 = <&pcie_default_state>; + pinctrl-names = "default"; + + status = "okay"; +}; + +&pcie_phy { + vdda-phy-supply = <&vreg_l5a>; + vdda-pll-supply = <&vreg_l12a>; + + status = "okay"; +}; + +&pcie_port0 { + wifi@0 { + compatible = "pci17cb,1103"; + reg = <0x10000 0x0 0x0 0x0 0x0>; + + qcom,calibration-variant = "QC_QCS615_Ride"; + + vddrfacmn-supply = <&vreg_pmu_rfa_cmn>; + vddaon-supply = <&vreg_pmu_aon_0p59>; + vddwlcx-supply = <&vreg_pmu_wlcx_0p8>; + vddwlmx-supply = <&vreg_pmu_wlmx_0p85>; + vddrfa0p8-supply = <&vreg_pmu_rfa_0p8>; + vddrfa1p2-supply = <&vreg_pmu_rfa_1p2>; + vddrfa1p8-supply = <&vreg_pmu_rfa_1p7>; + vddpcie0p9-supply = <&vreg_pmu_pcie_0p9>; + vddpcie1p8-supply = <&vreg_pmu_pcie_1p8>; + }; +}; + +&pm8150_gpios { + usb2_en: usb2-en-state { + pins = "gpio10"; + function = "normal"; + output-enable; + power-source = <0>; + }; +}; + +&qupv3_id_0 { + status = "okay"; +}; + +&qupv3_id_1 { + status = "okay"; +}; + +&remoteproc_adsp { + firmware-name = "qcom/qcs615/adsp.mbn"; + + status = "okay"; +}; + +&remoteproc_cdsp { + firmware-name = "qcom/qcs615/cdsp.mbn"; + + status = "okay"; +}; + +&sdhc_1 { + pinctrl-0 = <&sdc1_state_on>; + pinctrl-1 = <&sdc1_state_off>; + pinctrl-names = "default", "sleep"; + + bus-width = <8>; + mmc-ddr-1_8v; + mmc-hs200-1_8v; + mmc-hs400-1_8v; + mmc-hs400-enhanced-strobe; + vmmc-supply = <&vreg_l17a>; + vqmmc-supply = <&vreg_s4a>; + + non-removable; + no-sd; + no-sdio; + + status = "okay"; +}; + +&spi6 { + status = "okay"; + + can@0 { + compatible = "microchip,mcp2515"; + reg = <0>; + clocks = <&can_osc>; + interrupts-extended = <&tlmm 87 IRQ_TYPE_LEVEL_LOW>; + spi-max-frequency = <10000000>; + vdd-supply = <&vreg_v3p3_can>; + xceiver-supply = <&vreg_v5p0_can>; + }; +}; + +&tlmm { + bt_en_state: bt-en-state { + pins = "gpio85"; + function = "gpio"; + bias-pull-down; + }; + + pcie_default_state: pcie-default-state { + clkreq-pins { + pins = "gpio90"; + function = "pcie_clk_req"; + drive-strength = <2>; + bias-pull-up; + }; + + perst-pins { + pins = "gpio89"; + function = "gpio"; + drive-strength = <2>; + bias-disable; + }; + + wake-pins { + pins = "gpio100"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + wifi_reg_en_pins_state: wifi-reg-en-pins-state { + pins = "gpio91"; + function = "gpio"; + drive-strength = <8>; + output-high; + bias-pull-up; + }; + + wlan_en_state: wlan-en-state { + pins = "gpio84"; + function = "gpio"; + drive-strength = <16>; + bias-pull-down; + output-low; + }; +}; + +&uart0 { + status = "okay"; +}; + +&uart7 { + status = "okay"; + + bluetooth { + compatible = "qcom,wcn6855-bt"; + firmware-name = "QCA6698/hpnv21", "QCA6698/hpbtfw21.tlv"; + + vddrfacmn-supply = <&vreg_pmu_rfa_cmn>; + vddaon-supply = <&vreg_pmu_aon_0p59>; + vddwlcx-supply = <&vreg_pmu_wlcx_0p8>; + vddwlmx-supply = <&vreg_pmu_wlmx_0p85>; + vddbtcmx-supply = <&vreg_pmu_btcmx_0p85>; + vddrfa0p8-supply = <&vreg_pmu_rfa_0p8>; + vddrfa1p2-supply = <&vreg_pmu_rfa_1p2>; + vddrfa1p8-supply = <&vreg_pmu_rfa_1p7>; + }; +}; + +&usb_1 { + status = "okay"; +}; + +&usb_1_dwc3 { + dr_mode = "host"; +}; + +&usb_hsphy_1 { + vdd-supply = <&vreg_l5a>; + vdda-pll-supply = <&vreg_l12a>; + vdda-phy-dpdm-supply = <&vreg_l13a>; + + status = "okay"; +}; + +&usb_2 { + status = "okay"; +}; + +&usb_2_dwc3 { + dr_mode = "host"; +}; + +&usb_hsphy_2 { + vdd-supply = <&vreg_l5a>; + vdda-pll-supply = <&vreg_l12a>; + vdda-phy-dpdm-supply = <&vreg_l13a>; + + status = "okay"; +}; + +&usb_qmpphy { + vdda-phy-supply = <&vreg_l5a>; + vdda-pll-supply = <&vreg_l12a>; + + status = "okay"; +}; + +&usb_qmpphy_2 { + vdda-phy-supply = <&vreg_l11a>; + vdda-pll-supply = <&vreg_l5a>; + + status = "okay"; +}; + +&ufs_mem_hc { + reset-gpios = <&tlmm 123 GPIO_ACTIVE_LOW>; + vcc-supply = <&vreg_l17a>; + vcc-max-microamp = <600000>; + vccq2-supply = <&vreg_s4a>; + vccq2-max-microamp = <600000>; + + status = "okay"; +}; + +&ufs_mem_phy { + vdda-phy-supply = <&vreg_l5a>; + vdda-pll-supply = <&vreg_l12a>; + + status = "okay"; +}; + +&venus { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/qcom/talos-evk.dts b/arch/arm64/boot/dts/qcom/talos-evk.dts new file mode 100644 index 0000000000000..af100e22beeec --- /dev/null +++ b/arch/arm64/boot/dts/qcom/talos-evk.dts @@ -0,0 +1,139 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ +/dts-v1/; + +#include "talos-evk-som.dtsi" + +/ { + model = "Qualcomm QCS615 IQ 615 EVK"; + compatible = "qcom,talos-evk", "qcom,qcs615", "qcom,sm6150"; + chassis-type = "embedded"; + + aliases { + mmc1 = &sdhc_2; + }; + + dp0-connector { + compatible = "dp-connector"; + label = "DP0"; + type = "full-size"; + + hpd-gpios = <&tlmm 104 GPIO_ACTIVE_HIGH>; + + port { + dp0_connector_in: endpoint { + remote-endpoint = <&mdss_dp0_out>; + }; + }; + }; + + hdmi_connector: hdmi-out { + compatible = "hdmi-connector"; + type = "d"; + + port { + hdmi_con_out: endpoint { + remote-endpoint = <&adv7535_out>; + }; + }; + }; + + vreg_v1p8_out: regulator-v1p8-out { + compatible = "regulator-fixed"; + regulator-name = "vreg-v1p8-out"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + vin-supply = <&vreg_v5p0_out>; + regulator-boot-on; + regulator-always-on; + }; + + vreg_v3p3_out: regulator-v3p3-out { + compatible = "regulator-fixed"; + regulator-name = "vreg-v3p3-out"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + vin-supply = <&vreg_v5p0_out>; + regulator-boot-on; + regulator-always-on; + }; + + vreg_v5p0_out: regulator-v5p0-out { + compatible = "regulator-fixed"; + regulator-name = "vreg-v5p0-out"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + regulator-boot-on; + regulator-always-on; + /* Powered by system 20V rail (USBC_VBUS_IN) */ + }; +}; + +&i2c1 { + clock-frequency = <400000>; + status = "okay"; + + hdmi_bridge: bridge@3d { + compatible = "adi,adv7535"; + reg = <0x3d>; + avdd-supply = <&vreg_v1p8_out>; + dvdd-supply = <&vreg_v1p8_out>; + pvdd-supply = <&vreg_v1p8_out>; + a2vdd-supply = <&vreg_v1p8_out>; + v3p3-supply = <&vreg_v3p3_out>; + interrupts-extended = <&tlmm 26 IRQ_TYPE_LEVEL_LOW>; + adi,dsi-lanes = <4>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + adv7535_in: endpoint { + remote-endpoint = <&mdss_dsi0_out>; + }; + }; + + port@1 { + reg = <1>; + + adv7535_out: endpoint { + remote-endpoint = <&hdmi_con_out>; + }; + }; + }; + }; +}; + +&mdss_dsi0_out { + remote-endpoint = <&adv7535_in>; + data-lanes = <0 1 2 3>; +}; + +&pon_pwrkey { + status = "okay"; +}; + +&pon_resin { + linux,code = ; + + status = "okay"; +}; + +&sdhc_2 { + pinctrl-0 = <&sdc2_state_on>; + pinctrl-1 = <&sdc2_state_off>; + pinctrl-names = "default", "sleep"; + + bus-width = <4>; + cd-gpios = <&tlmm 99 GPIO_ACTIVE_LOW>; + + vmmc-supply = <&vreg_l10a>; + vqmmc-supply = <&vreg_s4a>; + + status = "okay"; +}; From b86921af4c10a2325fb2026001c41e8cf5a30d26 Mon Sep 17 00:00:00 2001 From: Komal Bajaj Date: Tue, 13 Jan 2026 19:00:16 +0530 Subject: [PATCH 1958/2333] WORKAROUND: drivers: increase deferred probe timeout Certain drivers were failing to probe during boot because their dependencies were not ready within the default deferred probe timeout. To address this, increase the deferred probe timeout to allow dependent drivers sufficient time to register and avoid probe failures during system startup. Signed-off-by: Komal Bajaj --- drivers/base/dd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/base/dd.c b/drivers/base/dd.c index 13ab98e033eaa..b334489ad6633 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -258,7 +258,7 @@ static int deferred_devs_show(struct seq_file *s, void *data) DEFINE_SHOW_ATTRIBUTE(deferred_devs); #ifdef CONFIG_MODULES -static int driver_deferred_probe_timeout = 10; +static int driver_deferred_probe_timeout = 15; #else static int driver_deferred_probe_timeout; #endif From 58796d352d74669eacc4715e0901949e9e66f770 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Fri, 17 Oct 2025 09:56:27 +0800 Subject: [PATCH 1959/2333] firmware: imx: scu-irq: Set mu_resource_id before get handle commit ff3f9913bc0749364fbfd86ea62ba2d31c6136c8 upstream. mu_resource_id is referenced in imx_scu_irq_get_status() and imx_scu_irq_group_enable() which could be used by other modules, so need to set correct value before using imx_sc_irq_ipc_handle in SCU API call. Reviewed-by: Frank Li Signed-off-by: Peng Fan Signed-off-by: Shawn Guo Fixes: 81fb53feb66a ("firmware: imx: scu-irq: Init workqueue before request mbox channel") Cc: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- drivers/firmware/imx/imx-scu-irq.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/firmware/imx/imx-scu-irq.c b/drivers/firmware/imx/imx-scu-irq.c index b9f6128d56f70..f587abcd7ca3a 100644 --- a/drivers/firmware/imx/imx-scu-irq.c +++ b/drivers/firmware/imx/imx-scu-irq.c @@ -203,6 +203,18 @@ int imx_scu_enable_general_irq_channel(struct device *dev) struct mbox_chan *ch; int ret = 0, i = 0; + if (!of_parse_phandle_with_args(dev->of_node, "mboxes", + "#mbox-cells", 0, &spec)) { + i = of_alias_get_id(spec.np, "mu"); + of_node_put(spec.np); + } + + /* use mu1 as general mu irq channel if failed */ + if (i < 0) + i = 1; + + mu_resource_id = IMX_SC_R_MU_0A + i; + ret = imx_scu_get_handle(&imx_sc_irq_ipc_handle); if (ret) return ret; @@ -225,18 +237,6 @@ int imx_scu_enable_general_irq_channel(struct device *dev) return ret; } - if (!of_parse_phandle_with_args(dev->of_node, "mboxes", - "#mbox-cells", 0, &spec)) { - i = of_alias_get_id(spec.np, "mu"); - of_node_put(spec.np); - } - - /* use mu1 as general mu irq channel if failed */ - if (i < 0) - i = 1; - - mu_resource_id = IMX_SC_R_MU_0A + i; - /* Create directory under /sysfs/firmware */ wakeup_obj = kobject_create_and_add("scu_wakeup_source", firmware_kobj); if (!wakeup_obj) { From a2542fe353a40b9b03bffdcedc64107ac9322aab Mon Sep 17 00:00:00 2001 From: Morduan Zang Date: Wed, 14 Jan 2026 13:30:33 +0800 Subject: [PATCH 1960/2333] efi/cper: Fix cper_bits_to_str buffer handling and return value commit d7f1b4bdc7108be1b178e1617b5f45c8918e88d7 upstream. The return value calculation was incorrect: `return len - buf_size;` Initially `len = buf_size`, then `len` decreases with each operation. This results in a negative return value on success. Fix by returning `buf_size - len` which correctly calculates the actual number of bytes written. Fixes: a976d790f494 ("efi/cper: Add a new helper function to print bitmasks") Signed-off-by: Morduan Zang Signed-off-by: Ard Biesheuvel Signed-off-by: Greg Kroah-Hartman --- drivers/firmware/efi/cper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/firmware/efi/cper.c b/drivers/firmware/efi/cper.c index 79ba688a64f8d..322c6bdefb611 100644 --- a/drivers/firmware/efi/cper.c +++ b/drivers/firmware/efi/cper.c @@ -162,7 +162,7 @@ int cper_bits_to_str(char *buf, int buf_size, unsigned long bits, len -= size; str += size; } - return len - buf_size; + return buf_size - len; } EXPORT_SYMBOL_GPL(cper_bits_to_str); From a685f246ad7909b4e24938d570ba5eaad81abfbd Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Wed, 31 Dec 2025 11:10:57 +0100 Subject: [PATCH 1961/2333] nvme-apple: add "apple,t8103-nvme-ans2" as compatible commit 7d3fa7e954934fbda0a017ac1c305b7b10ecceef upstream. After discussion with the devicetree maintainers we agreed to not extend lists with the generic compatible "apple,nvme-ans2" anymore [1]. Add "apple,t8103-nvme-ans2" as fallback compatible as it is the SoC the driver and bindings were written for. [1]: https://lore.kernel.org/asahi/12ab93b7-1fc2-4ce0-926e-c8141cfe81bf@kernel.org/ Cc: stable@vger.kernel.org # v6.18+ Fixes: 5bd2927aceba ("nvme-apple: Add initial Apple SoC NVMe driver") Reviewed-by: Neal Gompa Reviewed-by: Christoph Hellwig Signed-off-by: Janne Grunau Signed-off-by: Keith Busch Signed-off-by: Greg Kroah-Hartman --- drivers/nvme/host/apple.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/nvme/host/apple.c b/drivers/nvme/host/apple.c index f35d3f71d14f3..63819304290a1 100644 --- a/drivers/nvme/host/apple.c +++ b/drivers/nvme/host/apple.c @@ -1703,6 +1703,7 @@ static const struct apple_nvme_hw apple_nvme_t8103_hw = { static const struct of_device_id apple_nvme_of_match[] = { { .compatible = "apple,t8015-nvme-ans2", .data = &apple_nvme_t8015_hw }, + { .compatible = "apple,t8103-nvme-ans2", .data = &apple_nvme_t8103_hw }, { .compatible = "apple,nvme-ans2", .data = &apple_nvme_t8103_hw }, {}, }; From c6a38672067b9332eb6946f7cd04784b2ec9ac9a Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Mon, 12 Jan 2026 11:47:35 +0100 Subject: [PATCH 1962/2333] Revert "gfs2: Fix use of bio_chain" commit 469d71512d135907bf5ea0972dfab8c420f57848 upstream. This reverts commit 8a157e0a0aa5143b5d94201508c0ca1bb8cfb941. That commit incorrectly assumed that the bio_chain() arguments were swapped in gfs2. However, gfs2 intentionally constructs bio chains so that the first bio's bi_end_io callback is invoked when all bios in the chain have completed, unlike bio chains where the last bio's callback is invoked. Fixes: 8a157e0a0aa5 ("gfs2: Fix use of bio_chain") Cc: stable@vger.kernel.org Signed-off-by: Andreas Gruenbacher Signed-off-by: Greg Kroah-Hartman --- fs/gfs2/lops.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c index 914d03f6c4e82..9c8c305a75c46 100644 --- a/fs/gfs2/lops.c +++ b/fs/gfs2/lops.c @@ -487,7 +487,7 @@ static struct bio *gfs2_chain_bio(struct bio *prev, unsigned int nr_iovecs) new = bio_alloc(prev->bi_bdev, nr_iovecs, prev->bi_opf, GFP_NOIO); bio_clone_blkg_association(new, prev); new->bi_iter.bi_sector = bio_end_sector(prev); - bio_chain(prev, new); + bio_chain(new, prev); submit_bio(prev); return new; } From eea6f395ca502c4528314c8112da9b5d65f685eb Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 31 Dec 2025 16:43:15 +0100 Subject: [PATCH 1963/2333] x86/fpu: Clear XSTATE_BV[i] in guest XSAVE state whenever XFD[i]=1 commit b45f721775947a84996deb5c661602254ce25ce6 upstream. When loading guest XSAVE state via KVM_SET_XSAVE, and when updating XFD in response to a guest WRMSR, clear XFD-disabled features in the saved (or to be restored) XSTATE_BV to ensure KVM doesn't attempt to load state for features that are disabled via the guest's XFD. Because the kernel executes XRSTOR with the guest's XFD, saving XSTATE_BV[i]=1 with XFD[i]=1 will cause XRSTOR to #NM and panic the kernel. E.g. if fpu_update_guest_xfd() sets XFD without clearing XSTATE_BV: ------------[ cut here ]------------ WARNING: arch/x86/kernel/traps.c:1524 at exc_device_not_available+0x101/0x110, CPU#29: amx_test/848 Modules linked in: kvm_intel kvm irqbypass CPU: 29 UID: 1000 PID: 848 Comm: amx_test Not tainted 6.19.0-rc2-ffa07f7fd437-x86_amx_nm_xfd_non_init-vm #171 NONE Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 0.0.0 02/06/2015 RIP: 0010:exc_device_not_available+0x101/0x110 Call Trace: asm_exc_device_not_available+0x1a/0x20 RIP: 0010:restore_fpregs_from_fpstate+0x36/0x90 switch_fpu_return+0x4a/0xb0 kvm_arch_vcpu_ioctl_run+0x1245/0x1e40 [kvm] kvm_vcpu_ioctl+0x2c3/0x8f0 [kvm] __x64_sys_ioctl+0x8f/0xd0 do_syscall_64+0x62/0x940 entry_SYSCALL_64_after_hwframe+0x4b/0x53 ---[ end trace 0000000000000000 ]--- This can happen if the guest executes WRMSR(MSR_IA32_XFD) to set XFD[18] = 1, and a host IRQ triggers kernel_fpu_begin() prior to the vmexit handler's call to fpu_update_guest_xfd(). and if userspace stuffs XSTATE_BV[i]=1 via KVM_SET_XSAVE: ------------[ cut here ]------------ WARNING: arch/x86/kernel/traps.c:1524 at exc_device_not_available+0x101/0x110, CPU#14: amx_test/867 Modules linked in: kvm_intel kvm irqbypass CPU: 14 UID: 1000 PID: 867 Comm: amx_test Not tainted 6.19.0-rc2-2dace9faccd6-x86_amx_nm_xfd_non_init-vm #168 NONE Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 0.0.0 02/06/2015 RIP: 0010:exc_device_not_available+0x101/0x110 Call Trace: asm_exc_device_not_available+0x1a/0x20 RIP: 0010:restore_fpregs_from_fpstate+0x36/0x90 fpu_swap_kvm_fpstate+0x6b/0x120 kvm_load_guest_fpu+0x30/0x80 [kvm] kvm_arch_vcpu_ioctl_run+0x85/0x1e40 [kvm] kvm_vcpu_ioctl+0x2c3/0x8f0 [kvm] __x64_sys_ioctl+0x8f/0xd0 do_syscall_64+0x62/0x940 entry_SYSCALL_64_after_hwframe+0x4b/0x53 ---[ end trace 0000000000000000 ]--- The new behavior is consistent with the AMX architecture. Per Intel's SDM, XSAVE saves XSTATE_BV as '0' for components that are disabled via XFD (and non-compacted XSAVE saves the initial configuration of the state component): If XSAVE, XSAVEC, XSAVEOPT, or XSAVES is saving the state component i, the instruction does not generate #NM when XCR0[i] = IA32_XFD[i] = 1; instead, it operates as if XINUSE[i] = 0 (and the state component was in its initial state): it saves bit i of XSTATE_BV field of the XSAVE header as 0; in addition, XSAVE saves the initial configuration of the state component (the other instructions do not save state component i). Alternatively, KVM could always do XRSTOR with XFD=0, e.g. by using a constant XFD based on the set of enabled features when XSAVEing for a struct fpu_guest. However, having XSTATE_BV[i]=1 for XFD-disabled features can only happen in the above interrupt case, or in similar scenarios involving preemption on preemptible kernels, because fpu_swap_kvm_fpstate()'s call to save_fpregs_to_fpstate() saves the outgoing FPU state with the current XFD; and that is (on all but the first WRMSR to XFD) the guest XFD. Therefore, XFD can only go out of sync with XSTATE_BV in the above interrupt case, or in similar scenarios involving preemption on preemptible kernels, and it we can consider it (de facto) part of KVM ABI that KVM_GET_XSAVE returns XSTATE_BV[i]=0 for XFD-disabled features. Reported-by: Paolo Bonzini Cc: stable@vger.kernel.org Fixes: 820a6ee944e7 ("kvm: x86: Add emulation for IA32_XFD", 2022-01-14) Signed-off-by: Sean Christopherson [Move clearing of XSTATE_BV from fpu_copy_uabi_to_guest_fpstate to kvm_vcpu_ioctl_x86_set_xsave. - Paolo] Reviewed-by: Binbin Wu Signed-off-by: Paolo Bonzini Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/fpu/core.c | 32 +++++++++++++++++++++++++++++--- arch/x86/kvm/x86.c | 9 +++++++++ 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/arch/x86/kernel/fpu/core.c b/arch/x86/kernel/fpu/core.c index e88eacb1b5bbf..9badb21e5a5bc 100644 --- a/arch/x86/kernel/fpu/core.c +++ b/arch/x86/kernel/fpu/core.c @@ -318,10 +318,29 @@ EXPORT_SYMBOL_GPL(fpu_enable_guest_xfd_features); #ifdef CONFIG_X86_64 void fpu_update_guest_xfd(struct fpu_guest *guest_fpu, u64 xfd) { + struct fpstate *fpstate = guest_fpu->fpstate; + fpregs_lock(); - guest_fpu->fpstate->xfd = xfd; - if (guest_fpu->fpstate->in_use) - xfd_update_state(guest_fpu->fpstate); + + /* + * KVM's guest ABI is that setting XFD[i]=1 *can* immediately revert the + * save state to its initial configuration. Likewise, KVM_GET_XSAVE does + * the same as XSAVE and returns XSTATE_BV[i]=0 whenever XFD[i]=1. + * + * If the guest's FPU state is in hardware, just update XFD: the XSAVE + * in fpu_swap_kvm_fpstate will clear XSTATE_BV[i] whenever XFD[i]=1. + * + * If however the guest's FPU state is NOT resident in hardware, clear + * disabled components in XSTATE_BV now, or a subsequent XRSTOR will + * attempt to load disabled components and generate #NM _in the host_. + */ + if (xfd && test_thread_flag(TIF_NEED_FPU_LOAD)) + fpstate->regs.xsave.header.xfeatures &= ~xfd; + + fpstate->xfd = xfd; + if (fpstate->in_use) + xfd_update_state(fpstate); + fpregs_unlock(); } EXPORT_SYMBOL_GPL(fpu_update_guest_xfd); @@ -429,6 +448,13 @@ int fpu_copy_uabi_to_guest_fpstate(struct fpu_guest *gfpu, const void *buf, if (ustate->xsave.header.xfeatures & ~xcr0) return -EINVAL; + /* + * Disabled features must be in their initial state, otherwise XRSTOR + * causes an exception. + */ + if (WARN_ON_ONCE(ustate->xsave.header.xfeatures & kstate->xfd)) + return -EINVAL; + /* * Nullify @vpkru to preserve its current value if PKRU's bit isn't set * in the header. KVM's odd ABI is to leave PKRU untouched in this diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 19d2d6d9e64ab..43fb2a05a91c9 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -5842,9 +5842,18 @@ static int kvm_vcpu_ioctl_x86_get_xsave(struct kvm_vcpu *vcpu, static int kvm_vcpu_ioctl_x86_set_xsave(struct kvm_vcpu *vcpu, struct kvm_xsave *guest_xsave) { + union fpregs_state *xstate = (union fpregs_state *)guest_xsave->region; + if (fpstate_is_confidential(&vcpu->arch.guest_fpu)) return vcpu->kvm->arch.has_protected_state ? -EINVAL : 0; + /* + * For backwards compatibility, do not expect disabled features to be in + * their initial state. XSTATE_BV[i] must still be cleared whenever + * XFD[i]=1, or XRSTOR would cause a #NM. + */ + xstate->xsave.header.xfeatures &= ~vcpu->arch.guest_fpu.fpstate->xfd; + return fpu_copy_uabi_to_guest_fpstate(&vcpu->arch.guest_fpu, guest_xsave->region, kvm_caps.supported_xcr0, From 6711f723018ccdf231be9b6c49ba2d6ebbb3a4e5 Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Mon, 5 Jan 2026 10:44:06 +0000 Subject: [PATCH 1964/2333] rust: bitops: fix missing _find_* functions on 32-bit ARM commit 6a069876eb1402478900ee0eb7d7fe276bb1f4e3 upstream. On 32-bit ARM, you may encounter linker errors such as this one: ld.lld: error: undefined symbol: _find_next_zero_bit >>> referenced by rust_binder_main.43196037ba7bcee1-cgu.0 >>> drivers/android/binder/rust_binder_main.o:(::insert_or_update_handle) in archive vmlinux.a >>> referenced by rust_binder_main.43196037ba7bcee1-cgu.0 >>> drivers/android/binder/rust_binder_main.o:(::insert_or_update_handle) in archive vmlinux.a This error occurs because even though the functions are declared by include/linux/find.h, the definition is #ifdef'd out on 32-bit ARM. This is because arch/arm/include/asm/bitops.h contains: #define find_first_zero_bit(p,sz) _find_first_zero_bit_le(p,sz) #define find_next_zero_bit(p,sz,off) _find_next_zero_bit_le(p,sz,off) #define find_first_bit(p,sz) _find_first_bit_le(p,sz) #define find_next_bit(p,sz,off) _find_next_bit_le(p,sz,off) And the underscore-prefixed function is conditional on #ifndef of the non-underscore-prefixed name, but the declaration in find.h is *not* conditional on that #ifndef. To fix the linker error, we ensure that the symbols in question exist when compiling Rust code. We do this by defining them in rust/helpers/ whenever the normal definition is #ifndef'd out. Note that these helpers are somewhat unusual in that they do not have the rust_helper_ prefix that most helpers have. Adding the rust_helper_ prefix does not compile, as 'bindings::_find_next_zero_bit()' will result in a call to a symbol called _find_next_zero_bit as defined by include/linux/find.h rather than a symbol with the rust_helper_ prefix. This is because when a symbol is present in both include/ and rust/helpers/, the one from include/ wins under the assumption that the current configuration is one where that helper is unnecessary. This heuristic fails for _find_next_zero_bit() because the header file always declares it even if the symbol does not exist. The functions still use the __rust_helper annotation. This lets the wrapper function be inlined into Rust code even if full kernel LTO is not used once the patch series for that feature lands. Yury: arches are free to implement they own find_bit() functions. Most rely on generic implementation, but arm32 and m86k - not; so they require custom handling. Alice confirmed it fixes the build for both. Cc: stable@vger.kernel.org Fixes: 6cf93a9ed39e ("rust: add bindings for bitops.h") Reported-by: Andreas Hindborg Closes: https://rust-for-linux.zulipchat.com/#narrow/channel/x/topic/x/near/561677301 Tested-by: Andreas Hindborg Reviewed-by: Dirk Behme Signed-off-by: Alice Ryhl Signed-off-by: Yury Norov (NVIDIA) Signed-off-by: Greg Kroah-Hartman --- rust/helpers/bitops.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/rust/helpers/bitops.c b/rust/helpers/bitops.c index 5d0861d29d3f0..e79ef9e6d98f9 100644 --- a/rust/helpers/bitops.c +++ b/rust/helpers/bitops.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 #include +#include void rust_helper___set_bit(unsigned long nr, unsigned long *addr) { @@ -21,3 +22,44 @@ void rust_helper_clear_bit(unsigned long nr, volatile unsigned long *addr) { clear_bit(nr, addr); } + +/* + * The rust_helper_ prefix is intentionally omitted below so that the + * declarations in include/linux/find.h are compatible with these helpers. + * + * Note that the below #ifdefs mean that the helper is only created if C does + * not provide a definition. + */ +#ifdef find_first_zero_bit +__rust_helper +unsigned long _find_first_zero_bit(const unsigned long *p, unsigned long size) +{ + return find_first_zero_bit(p, size); +} +#endif /* find_first_zero_bit */ + +#ifdef find_next_zero_bit +__rust_helper +unsigned long _find_next_zero_bit(const unsigned long *addr, + unsigned long size, unsigned long offset) +{ + return find_next_zero_bit(addr, size, offset); +} +#endif /* find_next_zero_bit */ + +#ifdef find_first_bit +__rust_helper +unsigned long _find_first_bit(const unsigned long *addr, unsigned long size) +{ + return find_first_bit(addr, size); +} +#endif /* find_first_bit */ + +#ifdef find_next_bit +__rust_helper +unsigned long _find_next_bit(const unsigned long *addr, unsigned long size, + unsigned long offset) +{ + return find_next_bit(addr, size, offset); +} +#endif /* find_next_bit */ From afd7591a4ca92f2853eebe8668a64019e97003c2 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Fri, 2 Jan 2026 12:14:12 +0100 Subject: [PATCH 1965/2333] ASoC: codecs: wsa884x: fix codec initialisation commit 120f3e6ff76209ee2f62a64e5e7e9d70274df42b upstream. The soundwire update_status() callback may be called multiple times with the same ATTACHED status but initialisation should only be done when transitioning from UNATTACHED to ATTACHED. Fix the inverted hw_init flag which was set to false instead of true after initialisation which defeats its purpose and may result in repeated unnecessary initialisation. Similarly, the initial state of the flag was also inverted so that the codec would only be initialised and brought out of regmap cache only mode if its status first transitions to UNATTACHED. Fixes: aa21a7d4f68a ("ASoC: codecs: wsa884x: Add WSA884x family of speakers") Cc: stable@vger.kernel.org # 6.5 Cc: Krzysztof Kozlowski Signed-off-by: Johan Hovold Reviewed-by: Krzysztof Kozlowski Tested-by: Krzysztof Kozlowski Reviewed-by: Srinivas Kandagatla Link: https://patch.msgid.link/20260102111413.9605-4-johan@kernel.org Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/codecs/wsa884x.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/soc/codecs/wsa884x.c b/sound/soc/codecs/wsa884x.c index 2484d4b8e2d94..5ecd7962d77ae 100644 --- a/sound/soc/codecs/wsa884x.c +++ b/sound/soc/codecs/wsa884x.c @@ -1534,7 +1534,7 @@ static void wsa884x_init(struct wsa884x_priv *wsa884x) wsa884x_set_gain_parameters(wsa884x); - wsa884x->hw_init = false; + wsa884x->hw_init = true; } static int wsa884x_update_status(struct sdw_slave *slave, @@ -2109,7 +2109,6 @@ static int wsa884x_probe(struct sdw_slave *pdev, /* Start in cache-only until device is enumerated */ regcache_cache_only(wsa884x->regmap, true); - wsa884x->hw_init = true; if (IS_REACHABLE(CONFIG_HWMON)) { struct device *hwmon; From 67dfd9e8567cc4a1063013bdd14f45ead6ab3297 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Fri, 2 Jan 2026 12:14:10 +0100 Subject: [PATCH 1966/2333] ASoC: codecs: wsa883x: fix unnecessary initialisation commit 49aadf830eb048134d33ad7329d92ecff45d8dbb upstream. The soundwire update_status() callback may be called multiple times with the same ATTACHED status but initialisation should only be done when transitioning from UNATTACHED to ATTACHED. This avoids repeated initialisation of the codecs during boot of machines like the Lenovo ThinkPad X13s: [ 11.614523] wsa883x-codec sdw:1:0:0217:0202:00:1: WSA883X Version 1_1, Variant: WSA8835_V2 [ 11.618022] wsa883x-codec sdw:1:0:0217:0202:00:1: WSA883X Version 1_1, Variant: WSA8835_V2 [ 11.621377] wsa883x-codec sdw:1:0:0217:0202:00:1: WSA883X Version 1_1, Variant: WSA8835_V2 [ 11.624065] wsa883x-codec sdw:1:0:0217:0202:00:1: WSA883X Version 1_1, Variant: WSA8835_V2 [ 11.631382] wsa883x-codec sdw:1:0:0217:0202:00:2: WSA883X Version 1_1, Variant: WSA8835_V2 [ 11.634424] wsa883x-codec sdw:1:0:0217:0202:00:2: WSA883X Version 1_1, Variant: WSA8835_V2 Fixes: 43b8c7dc85a1 ("ASoC: codecs: add wsa883x amplifier support") Cc: stable@vger.kernel.org # 6.0 Cc: Srinivas Kandagatla Signed-off-by: Johan Hovold Reviewed-by: Krzysztof Kozlowski Reviewed-by: Srinivas Kandagatla Link: https://patch.msgid.link/20260102111413.9605-2-johan@kernel.org Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/codecs/wsa883x.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sound/soc/codecs/wsa883x.c b/sound/soc/codecs/wsa883x.c index ca4520ade79aa..5f2ced650dcc8 100644 --- a/sound/soc/codecs/wsa883x.c +++ b/sound/soc/codecs/wsa883x.c @@ -475,6 +475,7 @@ struct wsa883x_priv { int active_ports; int dev_mode; int comp_offset; + bool hw_init; /* * Protects temperature reading code (related to speaker protection) and * fields: temperature and pa_on. @@ -1043,6 +1044,9 @@ static int wsa883x_init(struct wsa883x_priv *wsa883x) struct regmap *regmap = wsa883x->regmap; int variant, version, ret; + if (wsa883x->hw_init) + return 0; + ret = regmap_read(regmap, WSA883X_OTP_REG_0, &variant); if (ret) return ret; @@ -1085,6 +1089,8 @@ static int wsa883x_init(struct wsa883x_priv *wsa883x) wsa883x->comp_offset); } + wsa883x->hw_init = true; + return 0; } @@ -1093,6 +1099,9 @@ static int wsa883x_update_status(struct sdw_slave *slave, { struct wsa883x_priv *wsa883x = dev_get_drvdata(&slave->dev); + if (status == SDW_SLAVE_UNATTACHED) + wsa883x->hw_init = false; + if (status == SDW_SLAVE_ATTACHED && slave->dev_num > 0) return wsa883x_init(wsa883x); From a255ec07f91d4c73a361a28b7a3d82f5710245f1 Mon Sep 17 00:00:00 2001 From: Shenghao Yang Date: Wed, 31 Dec 2025 13:50:26 +0800 Subject: [PATCH 1967/2333] drm/gud: fix NULL fb and crtc dereferences on USB disconnect commit dc2d5ddb193e363187bae2ad358245642d2721fb upstream. On disconnect drm_atomic_helper_disable_all() is called which sets both the fb and crtc for a plane to NULL before invoking a commit. This causes a kernel oops on every display disconnect. Add guards for those dereferences. Cc: # 6.18.x Fixes: 73cfd166e045 ("drm/gud: Replace simple display pipe with DRM atomic helpers") Signed-off-by: Shenghao Yang Reviewed-by: Ruben Wauters Signed-off-by: Ruben Wauters Link: https://patch.msgid.link/20251231055039.44266-1-me@shenghaoyang.info Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/gud/gud_pipe.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/gud/gud_pipe.c b/drivers/gpu/drm/gud/gud_pipe.c index 54d9aa9998e59..cfd66c879ae40 100644 --- a/drivers/gpu/drm/gud/gud_pipe.c +++ b/drivers/gpu/drm/gud/gud_pipe.c @@ -457,27 +457,20 @@ int gud_plane_atomic_check(struct drm_plane *plane, struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane); struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane); struct drm_crtc *crtc = new_plane_state->crtc; - struct drm_crtc_state *crtc_state; + struct drm_crtc_state *crtc_state = NULL; const struct drm_display_mode *mode; struct drm_framebuffer *old_fb = old_plane_state->fb; struct drm_connector_state *connector_state = NULL; struct drm_framebuffer *fb = new_plane_state->fb; - const struct drm_format_info *format = fb->format; + const struct drm_format_info *format; struct drm_connector *connector; unsigned int i, num_properties; struct gud_state_req *req; int idx, ret; size_t len; - if (drm_WARN_ON_ONCE(plane->dev, !fb)) - return -EINVAL; - - if (drm_WARN_ON_ONCE(plane->dev, !crtc)) - return -EINVAL; - - crtc_state = drm_atomic_get_new_crtc_state(state, crtc); - - mode = &crtc_state->mode; + if (crtc) + crtc_state = drm_atomic_get_new_crtc_state(state, crtc); ret = drm_atomic_helper_check_plane_state(new_plane_state, crtc_state, DRM_PLANE_NO_SCALING, @@ -492,6 +485,9 @@ int gud_plane_atomic_check(struct drm_plane *plane, if (old_plane_state->rotation != new_plane_state->rotation) crtc_state->mode_changed = true; + mode = &crtc_state->mode; + format = fb->format; + if (old_fb && old_fb->format != format) crtc_state->mode_changed = true; @@ -598,7 +594,7 @@ void gud_plane_atomic_update(struct drm_plane *plane, struct drm_atomic_helper_damage_iter iter; int ret, idx; - if (crtc->state->mode_changed || !crtc->state->enable) { + if (!crtc || crtc->state->mode_changed || !crtc->state->enable) { cancel_work_sync(&gdrm->work); mutex_lock(&gdrm->damage_lock); if (gdrm->fb) { From ae48108c2310f1dd700e0dbb655c2f1d92ed00fc Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Sat, 10 Jan 2026 17:07:17 +0900 Subject: [PATCH 1968/2333] virtio_net: Fix misalignment bug in struct virtnet_info commit 4156c3745f06bc197094b9ee97a9584e69ed00bf upstream. Use the new TRAILING_OVERLAP() helper to fix a misalignment bug along with the following warning: drivers/net/virtio_net.c:429:46: warning: structure containing a flexible array member is not at the end of another structure [-Wflex-array-member-not-at-end] This helper creates a union between a flexible-array member (FAM) and a set of members that would otherwise follow it (in this case `u8 rss_hash_key_data[VIRTIO_NET_RSS_MAX_KEY_SIZE];`). This overlays the trailing members (rss_hash_key_data) onto the FAM (hash_key_data) while keeping the FAM and the start of MEMBERS aligned. The static_assert() ensures this alignment remains. Notice that due to tail padding in flexible `struct virtio_net_rss_config_trailer`, `rss_trailer.hash_key_data` (at offset 83 in struct virtnet_info) and `rss_hash_key_data` (at offset 84 in struct virtnet_info) are misaligned by one byte. See below: struct virtio_net_rss_config_trailer { __le16 max_tx_vq; /* 0 2 */ __u8 hash_key_length; /* 2 1 */ __u8 hash_key_data[]; /* 3 0 */ /* size: 4, cachelines: 1, members: 3 */ /* padding: 1 */ /* last cacheline: 4 bytes */ }; struct virtnet_info { ... struct virtio_net_rss_config_trailer rss_trailer; /* 80 4 */ /* XXX last struct has 1 byte of padding */ u8 rss_hash_key_data[40]; /* 84 40 */ ... /* size: 832, cachelines: 13, members: 48 */ /* sum members: 801, holes: 8, sum holes: 31 */ /* paddings: 2, sum paddings: 5 */ }; After changes, those members are correctly aligned at offset 795: struct virtnet_info { ... union { struct virtio_net_rss_config_trailer rss_trailer; /* 792 4 */ struct { unsigned char __offset_to_hash_key_data[3]; /* 792 3 */ u8 rss_hash_key_data[40]; /* 795 40 */ }; /* 792 43 */ }; /* 792 44 */ ... /* size: 840, cachelines: 14, members: 47 */ /* sum members: 801, holes: 8, sum holes: 35 */ /* padding: 4 */ /* paddings: 1, sum paddings: 4 */ /* last cacheline: 8 bytes */ }; As a result, the RSS key passed to the device is shifted by 1 byte: the last byte is cut off, and instead a (possibly uninitialized) byte is added at the beginning. As a last note `struct virtio_net_rss_config_hdr *rss_hdr;` is also moved to the end, since it seems those three members should stick around together. :) Cc: stable@vger.kernel.org Fixes: ed3100e90d0d ("virtio_net: Use new RSS config structs") Signed-off-by: Gustavo A. R. Silva Acked-by: Michael S. Tsirkin Link: https://patch.msgid.link/aWIItWq5dV9XTTCJ@kspp Signed-off-by: Paolo Abeni Signed-off-by: Greg Kroah-Hartman --- drivers/net/virtio_net.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 4e1a5291099a5..6b3115cefc248 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -425,9 +425,6 @@ struct virtnet_info { u16 rss_indir_table_size; u32 rss_hash_types_supported; u32 rss_hash_types_saved; - struct virtio_net_rss_config_hdr *rss_hdr; - struct virtio_net_rss_config_trailer rss_trailer; - u8 rss_hash_key_data[VIRTIO_NET_RSS_MAX_KEY_SIZE]; /* Has control virtqueue */ bool has_cvq; @@ -493,7 +490,16 @@ struct virtnet_info { struct failover *failover; u64 device_stats_cap; + + struct virtio_net_rss_config_hdr *rss_hdr; + + /* Must be last as it ends in a flexible-array member. */ + TRAILING_OVERLAP(struct virtio_net_rss_config_trailer, rss_trailer, hash_key_data, + u8 rss_hash_key_data[VIRTIO_NET_RSS_MAX_KEY_SIZE]; + ); }; +static_assert(offsetof(struct virtnet_info, rss_trailer.hash_key_data) == + offsetof(struct virtnet_info, rss_hash_key_data)); struct padded_vnet_hdr { struct virtio_net_hdr_v1_hash hdr; From 704cced8eda4453e96622ea8176434cbf68a8add Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Wed, 14 Jan 2026 16:54:05 +0800 Subject: [PATCH 1969/2333] io_uring: move local task_work in exit cancel loop commit da579f05ef0faada3559e7faddf761c75cdf85e1 upstream. With IORING_SETUP_DEFER_TASKRUN, task work is queued to ctx->work_llist (local work) rather than the fallback list. During io_ring_exit_work(), io_move_task_work_from_local() was called once before the cancel loop, moving work from work_llist to fallback_llist. However, task work can be added to work_llist during the cancel loop itself. There are two cases: 1) io_kill_timeouts() is called from io_uring_try_cancel_requests() to cancel pending timeouts, and it adds task work via io_req_queue_tw_complete() for each cancelled timeout: 2) URING_CMD requests like ublk can be completed via io_uring_cmd_complete_in_task() from ublk_queue_rq() during canceling, given ublk request queue is only quiesced when canceling the 1st uring_cmd. Since io_allowed_defer_tw_run() returns false in io_ring_exit_work() (kworker != submitter_task), io_run_local_work() is never invoked, and the work_llist entries are never processed. This causes io_uring_try_cancel_requests() to loop indefinitely, resulting in 100% CPU usage in kworker threads. Fix this by moving io_move_task_work_from_local() inside the cancel loop, ensuring any work on work_llist is moved to fallback before each cancel attempt. Cc: stable@vger.kernel.org Fixes: c0e0d6ba25f1 ("io_uring: add IORING_SETUP_DEFER_TASKRUN") Signed-off-by: Ming Lei Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman --- io_uring/io_uring.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/io_uring/io_uring.c b/io_uring/io_uring.c index 60adab71ad2d2..e97c495c18065 100644 --- a/io_uring/io_uring.c +++ b/io_uring/io_uring.c @@ -3017,12 +3017,12 @@ static __cold void io_ring_exit_work(struct work_struct *work) mutex_unlock(&ctx->uring_lock); } - if (ctx->flags & IORING_SETUP_DEFER_TASKRUN) - io_move_task_work_from_local(ctx); - /* The SQPOLL thread never reaches this path */ - while (io_uring_try_cancel_requests(ctx, NULL, true, false)) + do { + if (ctx->flags & IORING_SETUP_DEFER_TASKRUN) + io_move_task_work_from_local(ctx); cond_resched(); + } while (io_uring_try_cancel_requests(ctx, NULL, true, false)); if (ctx->sq_data) { struct io_sq_data *sqd = ctx->sq_data; From df1fae862639f518190b132e2119aa98c58ea97d Mon Sep 17 00:00:00 2001 From: Jianbo Liu Date: Thu, 20 Nov 2025 05:56:09 +0200 Subject: [PATCH 1970/2333] xfrm: Fix inner mode lookup in tunnel mode GSO segmentation [ Upstream commit 3d5221af9c7711b7aec8da1298c8fc393ef6183d ] Commit 61fafbee6cfe ("xfrm: Determine inner GSO type from packet inner protocol") attempted to fix GSO segmentation by reading the inner protocol from XFRM_MODE_SKB_CB(skb)->protocol. This was incorrect because the field holds the inner L4 protocol (TCP/UDP) instead of the required tunnel protocol. Also, the memory location (shared by XFRM_SKB_CB(skb) which could be overwritten by xfrm_replay_overflow()) is prone to corruption. This combination caused the kernel to select the wrong inner mode and get the wrong address family. The correct value is in xfrm_offload(skb)->proto, which is set from the outer tunnel header's protocol field by esp[4|6]_gso_encap(). It is initialized by xfrm[4|6]_tunnel_encap_add() to either IPPROTO_IPIP or IPPROTO_IPV6, using xfrm_af2proto() and correctly reflects the inner packet's address family. Fixes: 61fafbee6cfe ("xfrm: Determine inner GSO type from packet inner protocol") Signed-off-by: Jianbo Liu Reviewed-by: Sabrina Dubroca Signed-off-by: Steffen Klassert Signed-off-by: Sasha Levin --- net/ipv4/esp4_offload.c | 4 ++-- net/ipv6/esp6_offload.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/net/ipv4/esp4_offload.c b/net/ipv4/esp4_offload.c index 05828d4cb6cdb..abd77162f5e75 100644 --- a/net/ipv4/esp4_offload.c +++ b/net/ipv4/esp4_offload.c @@ -122,8 +122,8 @@ static struct sk_buff *xfrm4_tunnel_gso_segment(struct xfrm_state *x, struct sk_buff *skb, netdev_features_t features) { - const struct xfrm_mode *inner_mode = xfrm_ip2inner_mode(x, - XFRM_MODE_SKB_CB(skb)->protocol); + struct xfrm_offload *xo = xfrm_offload(skb); + const struct xfrm_mode *inner_mode = xfrm_ip2inner_mode(x, xo->proto); __be16 type = inner_mode->family == AF_INET6 ? htons(ETH_P_IPV6) : htons(ETH_P_IP); diff --git a/net/ipv6/esp6_offload.c b/net/ipv6/esp6_offload.c index 22410243ebe88..22895521a57d0 100644 --- a/net/ipv6/esp6_offload.c +++ b/net/ipv6/esp6_offload.c @@ -158,8 +158,8 @@ static struct sk_buff *xfrm6_tunnel_gso_segment(struct xfrm_state *x, struct sk_buff *skb, netdev_features_t features) { - const struct xfrm_mode *inner_mode = xfrm_ip2inner_mode(x, - XFRM_MODE_SKB_CB(skb)->protocol); + struct xfrm_offload *xo = xfrm_offload(skb); + const struct xfrm_mode *inner_mode = xfrm_ip2inner_mode(x, xo->proto); __be16 type = inner_mode->family == AF_INET ? htons(ETH_P_IP) : htons(ETH_P_IPV6); From b7f9587f317d9faaafb1593b4e9d6b65214f8a5e Mon Sep 17 00:00:00 2001 From: Antony Antony Date: Thu, 11 Dec 2025 11:30:27 +0100 Subject: [PATCH 1971/2333] xfrm: set ipv4 no_pmtu_disc flag only on output sa when direction is set [ Upstream commit c196def07bbc6e8306d7a274433913444b0db20a ] The XFRM_STATE_NOPMTUDISC flag is only meaningful for output SAs, but it was being applied regardless of the SA direction when the sysctl ip_no_pmtu_disc is enabled. This can unintentionally affect input SAs. Limit setting XFRM_STATE_NOPMTUDISC to output SAs when the SA direction is configured. Closes: https://github.com/strongswan/strongswan/issues/2946 Fixes: a4a87fa4e96c ("xfrm: Add Direction to the SA in or out") Signed-off-by: Antony Antony Signed-off-by: Steffen Klassert Signed-off-by: Sasha Levin --- net/xfrm/xfrm_state.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index 9e14e453b55cc..98b362d518363 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c @@ -3151,6 +3151,7 @@ int __xfrm_init_state(struct xfrm_state *x, struct netlink_ext_ack *extack) int err; if (family == AF_INET && + (!x->dir || x->dir == XFRM_SA_DIR_OUT) && READ_ONCE(xs_net(x)->ipv4.sysctl_ip_no_pmtu_disc)) x->props.flags |= XFRM_STATE_NOPMTUDISC; From d6c75aa9d607044d1e5c8498eff0259eed356c32 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 8 Dec 2025 14:45:00 -0500 Subject: [PATCH 1972/2333] pNFS: Fix a deadlock when returning a delegation during open() [ Upstream commit 857bf9056291a16785ae3be1d291026b2437fc48 ] Ben Coddington reports seeing a hang in the following stack trace: 0 [ffffd0b50e1774e0] __schedule at ffffffff9ca05415 1 [ffffd0b50e177548] schedule at ffffffff9ca05717 2 [ffffd0b50e177558] bit_wait at ffffffff9ca061e1 3 [ffffd0b50e177568] __wait_on_bit at ffffffff9ca05cfb 4 [ffffd0b50e1775c8] out_of_line_wait_on_bit at ffffffff9ca05ea5 5 [ffffd0b50e177618] pnfs_roc at ffffffffc154207b [nfsv4] 6 [ffffd0b50e1776b8] _nfs4_proc_delegreturn at ffffffffc1506586 [nfsv4] 7 [ffffd0b50e177788] nfs4_proc_delegreturn at ffffffffc1507480 [nfsv4] 8 [ffffd0b50e1777f8] nfs_do_return_delegation at ffffffffc1523e41 [nfsv4] 9 [ffffd0b50e177838] nfs_inode_set_delegation at ffffffffc1524a75 [nfsv4] 10 [ffffd0b50e177888] nfs4_process_delegation at ffffffffc14f41dd [nfsv4] 11 [ffffd0b50e1778a0] _nfs4_opendata_to_nfs4_state at ffffffffc1503edf [nfsv4] 12 [ffffd0b50e1778c0] _nfs4_open_and_get_state at ffffffffc1504e56 [nfsv4] 13 [ffffd0b50e177978] _nfs4_do_open at ffffffffc15051b8 [nfsv4] 14 [ffffd0b50e1779f8] nfs4_do_open at ffffffffc150559c [nfsv4] 15 [ffffd0b50e177a80] nfs4_atomic_open at ffffffffc15057fb [nfsv4] 16 [ffffd0b50e177ad0] nfs4_file_open at ffffffffc15219be [nfsv4] 17 [ffffd0b50e177b78] do_dentry_open at ffffffff9c09e6ea 18 [ffffd0b50e177ba8] vfs_open at ffffffff9c0a082e 19 [ffffd0b50e177bd0] dentry_open at ffffffff9c0a0935 The issue is that the delegreturn is being asked to wait for a layout return that cannot complete because a state recovery was initiated. The state recovery cannot complete until the open() finishes processing the delegations it was given. The solution is to propagate the existing flags that indicate a non-blocking call to the function pnfs_roc(), so that it knows not to wait in this situation. Reported-by: Benjamin Coddington Fixes: 29ade5db1293 ("pNFS: Wait on outstanding layoutreturns to complete in pnfs_roc()") Signed-off-by: Trond Myklebust Signed-off-by: Sasha Levin --- fs/nfs/nfs4proc.c | 6 ++--- fs/nfs/pnfs.c | 58 +++++++++++++++++++++++++++++++++-------------- fs/nfs/pnfs.h | 17 ++++++-------- 3 files changed, 51 insertions(+), 30 deletions(-) diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 3b436ba2ed3bf..3745c59f0af25 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -3894,8 +3894,8 @@ int nfs4_do_close(struct nfs4_state *state, gfp_t gfp_mask, int wait) calldata->res.seqid = calldata->arg.seqid; calldata->res.server = server; calldata->res.lr_ret = -NFS4ERR_NOMATCHING_LAYOUT; - calldata->lr.roc = pnfs_roc(state->inode, - &calldata->lr.arg, &calldata->lr.res, msg.rpc_cred); + calldata->lr.roc = pnfs_roc(state->inode, &calldata->lr.arg, + &calldata->lr.res, msg.rpc_cred, wait); if (calldata->lr.roc) { calldata->arg.lr_args = &calldata->lr.arg; calldata->res.lr_res = &calldata->lr.res; @@ -6946,7 +6946,7 @@ static int _nfs4_proc_delegreturn(struct inode *inode, const struct cred *cred, data->inode = nfs_igrab_and_active(inode); if (data->inode || issync) { data->lr.roc = pnfs_roc(inode, &data->lr.arg, &data->lr.res, - cred); + cred, issync); if (data->lr.roc) { data->args.lr_args = &data->lr.arg; data->res.lr_res = &data->lr.res; diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index 7ce2e840217cf..33bc6db0dc92f 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c @@ -1533,10 +1533,9 @@ static int pnfs_layout_return_on_reboot(struct pnfs_layout_hdr *lo) PNFS_FL_LAYOUTRETURN_PRIVILEGED); } -bool pnfs_roc(struct inode *ino, - struct nfs4_layoutreturn_args *args, - struct nfs4_layoutreturn_res *res, - const struct cred *cred) +bool pnfs_roc(struct inode *ino, struct nfs4_layoutreturn_args *args, + struct nfs4_layoutreturn_res *res, const struct cred *cred, + bool sync) { struct nfs_inode *nfsi = NFS_I(ino); struct nfs_open_context *ctx; @@ -1547,7 +1546,7 @@ bool pnfs_roc(struct inode *ino, nfs4_stateid stateid; enum pnfs_iomode iomode = 0; bool layoutreturn = false, roc = false; - bool skip_read = false; + bool skip_read; if (!nfs_have_layout(ino)) return false; @@ -1560,20 +1559,14 @@ bool pnfs_roc(struct inode *ino, lo = NULL; goto out_noroc; } - pnfs_get_layout_hdr(lo); - if (test_bit(NFS_LAYOUT_RETURN_LOCK, &lo->plh_flags)) { - spin_unlock(&ino->i_lock); - rcu_read_unlock(); - wait_on_bit(&lo->plh_flags, NFS_LAYOUT_RETURN, - TASK_UNINTERRUPTIBLE); - pnfs_put_layout_hdr(lo); - goto retry; - } /* no roc if we hold a delegation */ + skip_read = false; if (nfs4_check_delegation(ino, FMODE_READ)) { - if (nfs4_check_delegation(ino, FMODE_WRITE)) + if (nfs4_check_delegation(ino, FMODE_WRITE)) { + lo = NULL; goto out_noroc; + } skip_read = true; } @@ -1582,12 +1575,43 @@ bool pnfs_roc(struct inode *ino, if (state == NULL) continue; /* Don't return layout if there is open file state */ - if (state->state & FMODE_WRITE) + if (state->state & FMODE_WRITE) { + lo = NULL; goto out_noroc; + } if (state->state & FMODE_READ) skip_read = true; } + if (skip_read) { + bool writes = false; + + list_for_each_entry(lseg, &lo->plh_segs, pls_list) { + if (lseg->pls_range.iomode != IOMODE_READ) { + writes = true; + break; + } + } + if (!writes) { + lo = NULL; + goto out_noroc; + } + } + + pnfs_get_layout_hdr(lo); + if (test_bit(NFS_LAYOUT_RETURN_LOCK, &lo->plh_flags)) { + if (!sync) { + pnfs_set_plh_return_info( + lo, skip_read ? IOMODE_RW : IOMODE_ANY, 0); + goto out_noroc; + } + spin_unlock(&ino->i_lock); + rcu_read_unlock(); + wait_on_bit(&lo->plh_flags, NFS_LAYOUT_RETURN, + TASK_UNINTERRUPTIBLE); + pnfs_put_layout_hdr(lo); + goto retry; + } list_for_each_entry_safe(lseg, next, &lo->plh_segs, pls_list) { if (skip_read && lseg->pls_range.iomode == IOMODE_READ) @@ -1627,7 +1651,7 @@ bool pnfs_roc(struct inode *ino, out_noroc: spin_unlock(&ino->i_lock); rcu_read_unlock(); - pnfs_layoutcommit_inode(ino, true); + pnfs_layoutcommit_inode(ino, sync); if (roc) { struct pnfs_layoutdriver_type *ld = NFS_SERVER(ino)->pnfs_curr_ld; if (ld->prepare_layoutreturn) diff --git a/fs/nfs/pnfs.h b/fs/nfs/pnfs.h index 91ff877185c8a..3db8f13d8fe4e 100644 --- a/fs/nfs/pnfs.h +++ b/fs/nfs/pnfs.h @@ -303,10 +303,9 @@ int pnfs_mark_matching_lsegs_return(struct pnfs_layout_hdr *lo, u32 seq); int pnfs_mark_layout_stateid_invalid(struct pnfs_layout_hdr *lo, struct list_head *lseg_list); -bool pnfs_roc(struct inode *ino, - struct nfs4_layoutreturn_args *args, - struct nfs4_layoutreturn_res *res, - const struct cred *cred); +bool pnfs_roc(struct inode *ino, struct nfs4_layoutreturn_args *args, + struct nfs4_layoutreturn_res *res, const struct cred *cred, + bool sync); int pnfs_roc_done(struct rpc_task *task, struct nfs4_layoutreturn_args **argpp, struct nfs4_layoutreturn_res **respp, int *ret); void pnfs_roc_release(struct nfs4_layoutreturn_args *args, @@ -773,12 +772,10 @@ pnfs_layoutcommit_outstanding(struct inode *inode) return false; } - -static inline bool -pnfs_roc(struct inode *ino, - struct nfs4_layoutreturn_args *args, - struct nfs4_layoutreturn_res *res, - const struct cred *cred) +static inline bool pnfs_roc(struct inode *ino, + struct nfs4_layoutreturn_args *args, + struct nfs4_layoutreturn_res *res, + const struct cred *cred, bool sync) { return false; } From 19b4d9ab5e77843eac0429c019470c02f8710b55 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 31 Dec 2025 11:42:31 -0500 Subject: [PATCH 1973/2333] NFS: Fix a deadlock involving nfs_release_folio() [ Upstream commit cce0be6eb4971456b703aaeafd571650d314bcca ] Wang Zhaolong reports a deadlock involving NFSv4.1 state recovery waiting on kthreadd, which is attempting to reclaim memory by calling nfs_release_folio(). The latter cannot make progress due to state recovery being needed. It seems that the only safe thing to do here is to kick off a writeback of the folio, without waiting for completion, or else kicking off an asynchronous commit. Reported-by: Wang Zhaolong Fixes: 96780ca55e3c ("NFS: fix up nfs_release_folio() to try to release the page") Signed-off-by: Trond Myklebust Signed-off-by: Sasha Levin --- fs/nfs/file.c | 3 ++- fs/nfs/nfstrace.h | 3 +++ fs/nfs/write.c | 33 +++++++++++++++++++++++++++++++++ include/linux/nfs_fs.h | 1 + 4 files changed, 39 insertions(+), 1 deletion(-) diff --git a/fs/nfs/file.c b/fs/nfs/file.c index d020aab40c64e..d1c138a416cfb 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c @@ -511,7 +511,8 @@ static bool nfs_release_folio(struct folio *folio, gfp_t gfp) if ((current_gfp_context(gfp) & GFP_KERNEL) != GFP_KERNEL || current_is_kswapd() || current_is_kcompactd()) return false; - if (nfs_wb_folio(folio->mapping->host, folio) < 0) + if (nfs_wb_folio_reclaim(folio->mapping->host, folio) < 0 || + folio_test_private(folio)) return false; } return nfs_fscache_release_folio(folio, gfp); diff --git a/fs/nfs/nfstrace.h b/fs/nfs/nfstrace.h index 6ce55e8e6b67c..9f9ce4a565ea6 100644 --- a/fs/nfs/nfstrace.h +++ b/fs/nfs/nfstrace.h @@ -1062,6 +1062,9 @@ DECLARE_EVENT_CLASS(nfs_folio_event_done, DEFINE_NFS_FOLIO_EVENT(nfs_aop_readpage); DEFINE_NFS_FOLIO_EVENT_DONE(nfs_aop_readpage_done); +DEFINE_NFS_FOLIO_EVENT(nfs_writeback_folio_reclaim); +DEFINE_NFS_FOLIO_EVENT_DONE(nfs_writeback_folio_reclaim_done); + DEFINE_NFS_FOLIO_EVENT(nfs_writeback_folio); DEFINE_NFS_FOLIO_EVENT_DONE(nfs_writeback_folio_done); diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 336c510f37502..bf412455e8edf 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -2024,6 +2024,39 @@ int nfs_wb_folio_cancel(struct inode *inode, struct folio *folio) return ret; } +/** + * nfs_wb_folio_reclaim - Write back all requests on one page + * @inode: pointer to page + * @folio: pointer to folio + * + * Assumes that the folio has been locked by the caller + */ +int nfs_wb_folio_reclaim(struct inode *inode, struct folio *folio) +{ + loff_t range_start = folio_pos(folio); + size_t len = folio_size(folio); + struct writeback_control wbc = { + .sync_mode = WB_SYNC_ALL, + .nr_to_write = 0, + .range_start = range_start, + .range_end = range_start + len - 1, + .for_sync = 1, + }; + int ret; + + if (folio_test_writeback(folio)) + return -EBUSY; + if (folio_clear_dirty_for_io(folio)) { + trace_nfs_writeback_folio_reclaim(inode, range_start, len); + ret = nfs_writepage_locked(folio, &wbc); + trace_nfs_writeback_folio_reclaim_done(inode, range_start, len, + ret); + return ret; + } + nfs_commit_inode(inode, 0); + return 0; +} + /** * nfs_wb_folio - Write back all requests on one page * @inode: pointer to page diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index c585939b6cd60..2cf490a3a239b 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -636,6 +636,7 @@ extern int nfs_update_folio(struct file *file, struct folio *folio, extern int nfs_sync_inode(struct inode *inode); extern int nfs_wb_all(struct inode *inode); extern int nfs_wb_folio(struct inode *inode, struct folio *folio); +extern int nfs_wb_folio_reclaim(struct inode *inode, struct folio *folio); int nfs_wb_folio_cancel(struct inode *inode, struct folio *folio); extern int nfs_commit_inode(struct inode *, int); extern struct nfs_commit_data *nfs_commitdata_alloc(void); From ed5d3f2f6885eb99f729e6ffd946e3aa058bd3eb Mon Sep 17 00:00:00 2001 From: Zilin Guan Date: Thu, 25 Dec 2025 07:41:03 +0000 Subject: [PATCH 1974/2333] pnfs/flexfiles: Fix memory leak in nfs4_ff_alloc_deviceid_node() [ Upstream commit 0c728083654f0066f5e10a1d2b0bd0907af19a58 ] In nfs4_ff_alloc_deviceid_node(), if the allocation for ds_versions fails, the function jumps to the out_scratch label without freeing the already allocated dsaddrs list, leading to a memory leak. Fix this by jumping to the out_err_drain_dsaddrs label, which properly frees the dsaddrs list before cleaning up other resources. Fixes: d67ae825a59d6 ("pnfs/flexfiles: Add the FlexFile Layout Driver") Signed-off-by: Zilin Guan Signed-off-by: Trond Myklebust Signed-off-by: Sasha Levin --- fs/nfs/flexfilelayout/flexfilelayoutdev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/nfs/flexfilelayout/flexfilelayoutdev.c b/fs/nfs/flexfilelayout/flexfilelayoutdev.c index c55ea8fa3bfa5..c2d8a13a9dbdd 100644 --- a/fs/nfs/flexfilelayout/flexfilelayoutdev.c +++ b/fs/nfs/flexfilelayout/flexfilelayoutdev.c @@ -103,7 +103,7 @@ nfs4_ff_alloc_deviceid_node(struct nfs_server *server, struct pnfs_device *pdev, sizeof(struct nfs4_ff_ds_version), gfp_flags); if (!ds_versions) - goto out_scratch; + goto out_err_drain_dsaddrs; for (i = 0; i < version_count; i++) { /* 20 = version(4) + minor_version(4) + rsize(4) + wsize(4) + From 51926204465e7d2ce71c396e0403aed58140a292 Mon Sep 17 00:00:00 2001 From: Zilin Guan Date: Thu, 25 Dec 2025 08:45:26 +0000 Subject: [PATCH 1975/2333] pnfs/blocklayout: Fix memory leak in bl_parse_scsi() [ Upstream commit 5a74af51c3a6f4cd22c128b0c1c019f68fa90011 ] In bl_parse_scsi(), if the block device length is zero, the function returns immediately without releasing the file reference obtained via bl_open_path(), leading to a memory leak. Fix this by jumping to the out_blkdev_put label to ensure the file reference is properly released. Fixes: d76c769c8db4c ("pnfs/blocklayout: Don't add zero-length pnfs_block_dev") Signed-off-by: Zilin Guan Signed-off-by: Trond Myklebust Signed-off-by: Sasha Levin --- fs/nfs/blocklayout/dev.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/fs/nfs/blocklayout/dev.c b/fs/nfs/blocklayout/dev.c index ab76120705e20..134d7f760a33a 100644 --- a/fs/nfs/blocklayout/dev.c +++ b/fs/nfs/blocklayout/dev.c @@ -417,8 +417,10 @@ bl_parse_scsi(struct nfs_server *server, struct pnfs_block_dev *d, d->map = bl_map_simple; d->pr_key = v->scsi.pr_key; - if (d->len == 0) - return -ENODEV; + if (d->len == 0) { + error = -ENODEV; + goto out_blkdev_put; + } ops = bdev->bd_disk->fops->pr_ops; if (!ops) { From 282061a7f9f3077c614166444d1f00afbe52bfe1 Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Tue, 14 Oct 2025 18:00:57 +0200 Subject: [PATCH 1976/2333] drm/bridge: dw-hdmi-qp: Fix spurious IRQ on resume [ Upstream commit 14adddc65340f2034751c95616861c0e888e2bb1 ] After resume from suspend to RAM, the following splash is generated if the HDMI driver is probed (independent of a connected cable): [ 1194.484052] irq 80: nobody cared (try booting with the "irqpoll" option) [ 1194.484074] CPU: 0 UID: 0 PID: 627 Comm: rtcwake Not tainted 6.17.0-rc7-g96f1a11414b3 #1 PREEMPT [ 1194.484082] Hardware name: Rockchip RK3576 EVB V10 Board (DT) [ 1194.484085] Call trace: [ 1194.484087] ... (stripped) [ 1194.484283] handlers: [ 1194.484285] [<00000000bc363dcb>] dw_hdmi_qp_main_hardirq [dw_hdmi_qp] [ 1194.484302] Disabling IRQ #80 Apparently the HDMI IP is losing part of its state while the system is suspended and generates spurious interrupts during resume. The bug has not yet been noticed, as system suspend does not yet work properly on upstream kernel with either the Rockchip RK3588 or RK3576 platform. Fixes: 128a9bf8ace2 ("drm/rockchip: Add basic RK3588 HDMI output support") Signed-off-by: Sebastian Reichel Reviewed-by: Cristian Ciocaltea Signed-off-by: Heiko Stuebner Link: https://patch.msgid.link/20251014-rockchip-hdmi-suspend-fix-v1-1-983fcbf44839@collabora.com Signed-off-by: Sasha Levin --- drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c | 9 +++++++++ drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 12 +++++++++++- include/drm/bridge/dw_hdmi_qp.h | 1 + 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c index 39332c57f2c54..c85eb340e5a35 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c @@ -143,6 +143,7 @@ struct dw_hdmi_qp { } phy; struct regmap *regm; + int main_irq; unsigned long tmds_char_rate; }; @@ -1068,6 +1069,7 @@ struct dw_hdmi_qp *dw_hdmi_qp_bind(struct platform_device *pdev, dw_hdmi_qp_init_hw(hdmi); + hdmi->main_irq = plat_data->main_irq; ret = devm_request_threaded_irq(dev, plat_data->main_irq, dw_hdmi_qp_main_hardirq, NULL, IRQF_SHARED, dev_name(dev), hdmi); @@ -1106,9 +1108,16 @@ struct dw_hdmi_qp *dw_hdmi_qp_bind(struct platform_device *pdev, } EXPORT_SYMBOL_GPL(dw_hdmi_qp_bind); +void dw_hdmi_qp_suspend(struct device *dev, struct dw_hdmi_qp *hdmi) +{ + disable_irq(hdmi->main_irq); +} +EXPORT_SYMBOL_GPL(dw_hdmi_qp_suspend); + void dw_hdmi_qp_resume(struct device *dev, struct dw_hdmi_qp *hdmi) { dw_hdmi_qp_init_hw(hdmi); + enable_irq(hdmi->main_irq); } EXPORT_SYMBOL_GPL(dw_hdmi_qp_resume); diff --git a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c index ed6e8f036f4b3..9ac45e7bc987a 100644 --- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c @@ -597,6 +597,15 @@ static void dw_hdmi_qp_rockchip_remove(struct platform_device *pdev) component_del(&pdev->dev, &dw_hdmi_qp_rockchip_ops); } +static int __maybe_unused dw_hdmi_qp_rockchip_suspend(struct device *dev) +{ + struct rockchip_hdmi_qp *hdmi = dev_get_drvdata(dev); + + dw_hdmi_qp_suspend(dev, hdmi->hdmi); + + return 0; +} + static int __maybe_unused dw_hdmi_qp_rockchip_resume(struct device *dev) { struct rockchip_hdmi_qp *hdmi = dev_get_drvdata(dev); @@ -612,7 +621,8 @@ static int __maybe_unused dw_hdmi_qp_rockchip_resume(struct device *dev) } static const struct dev_pm_ops dw_hdmi_qp_rockchip_pm = { - SET_SYSTEM_SLEEP_PM_OPS(NULL, dw_hdmi_qp_rockchip_resume) + SET_SYSTEM_SLEEP_PM_OPS(dw_hdmi_qp_rockchip_suspend, + dw_hdmi_qp_rockchip_resume) }; struct platform_driver dw_hdmi_qp_rockchip_pltfm_driver = { diff --git a/include/drm/bridge/dw_hdmi_qp.h b/include/drm/bridge/dw_hdmi_qp.h index e9be6d507ad9c..8955450663e53 100644 --- a/include/drm/bridge/dw_hdmi_qp.h +++ b/include/drm/bridge/dw_hdmi_qp.h @@ -28,5 +28,6 @@ struct dw_hdmi_qp_plat_data { struct dw_hdmi_qp *dw_hdmi_qp_bind(struct platform_device *pdev, struct drm_encoder *encoder, const struct dw_hdmi_qp_plat_data *plat_data); +void dw_hdmi_qp_suspend(struct device *dev, struct dw_hdmi_qp *hdmi); void dw_hdmi_qp_resume(struct device *dev, struct dw_hdmi_qp *hdmi); #endif /* __DW_HDMI_QP__ */ From a91bdd21d5efb3072beefbec13762b7722200c49 Mon Sep 17 00:00:00 2001 From: Ian Forbes Date: Fri, 14 Nov 2025 14:37:03 -0600 Subject: [PATCH 1977/2333] drm/vmwgfx: Fix KMS with 3D on HW version 10 [ Upstream commit d9186faeae6efb7d0841a5e8eb213ff4c7966614 ] HW version 10 does not have GB Surfaces so there is no backing buffer for surface backed FBs. This would result in a nullptr dereference and crash the driver causing a black screen. Fixes: 965544150d1c ("drm/vmwgfx: Refactor cursor handling") Signed-off-by: Ian Forbes Reviewed-by: Zack Rusin Signed-off-by: Zack Rusin Link: https://patch.msgid.link/20251114203703.1946616-1-ian.forbes@broadcom.com Signed-off-by: Sasha Levin --- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 54ea1b513950a..535d844191e7a 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -763,13 +763,15 @@ static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev, return ERR_PTR(ret); } - ttm_bo_reserve(&bo->tbo, false, false, NULL); - ret = vmw_bo_dirty_add(bo); - if (!ret && surface && surface->res.func->dirty_alloc) { - surface->res.coherent = true; - ret = surface->res.func->dirty_alloc(&surface->res); + if (bo) { + ttm_bo_reserve(&bo->tbo, false, false, NULL); + ret = vmw_bo_dirty_add(bo); + if (!ret && surface && surface->res.func->dirty_alloc) { + surface->res.coherent = true; + ret = surface->res.func->dirty_alloc(&surface->res); + } + ttm_bo_unreserve(&bo->tbo); } - ttm_bo_unreserve(&bo->tbo); return &vfb->base; } From 0674f22eef471f9d1f9ae69bc63e9e14f6ad0049 Mon Sep 17 00:00:00 2001 From: Ian Forbes Date: Wed, 7 Jan 2026 09:20:59 -0600 Subject: [PATCH 1978/2333] drm/vmwgfx: Merge vmw_bo_release and vmw_bo_free functions [ Upstream commit 37a0cff4551c14aca4cfa6ef3f2f0e0f61d66825 ] Some of the warnings need to be reordered between these two functions in order to be correct. This has happened multiple times. Merging them solves this problem once and for all. Fixes: d6667f0ddf46 ("drm/vmwgfx: Fix handling of dumb buffers") Signed-off-by: Ian Forbes Signed-off-by: Zack Rusin Link: https://patch.msgid.link/20260107152059.3048329-1-ian.forbes@broadcom.com Signed-off-by: Sasha Levin --- drivers/gpu/drm/vmwgfx/vmwgfx_bo.c | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c b/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c index f031a312c7835..b22887e8c8815 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c @@ -32,9 +32,15 @@ #include -static void vmw_bo_release(struct vmw_bo *vbo) +/** + * vmw_bo_free - vmw_bo destructor + * + * @bo: Pointer to the embedded struct ttm_buffer_object + */ +static void vmw_bo_free(struct ttm_buffer_object *bo) { struct vmw_resource *res; + struct vmw_bo *vbo = to_vmw_bo(&bo->base); WARN_ON(kref_read(&vbo->tbo.base.refcount) != 0); vmw_bo_unmap(vbo); @@ -62,20 +68,8 @@ static void vmw_bo_release(struct vmw_bo *vbo) } vmw_surface_unreference(&vbo->dumb_surface); } - drm_gem_object_release(&vbo->tbo.base); -} - -/** - * vmw_bo_free - vmw_bo destructor - * - * @bo: Pointer to the embedded struct ttm_buffer_object - */ -static void vmw_bo_free(struct ttm_buffer_object *bo) -{ - struct vmw_bo *vbo = to_vmw_bo(&bo->base); - WARN_ON(!RB_EMPTY_ROOT(&vbo->res_tree)); - vmw_bo_release(vbo); + drm_gem_object_release(&vbo->tbo.base); WARN_ON(vbo->dirty); kfree(vbo); } From d6ea0b7394a443fb6ddd1a3619ccc2f0781a900c Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Fri, 2 Jan 2026 18:55:08 -0500 Subject: [PATCH 1979/2333] NFS/localio: Deal with page bases that are > PAGE_SIZE [ Upstream commit 60699ab7cbf0a4eb19929cce243002b39c67917d ] When resending requests, etc, the page base can quickly grow larger than the page size. Fixes: 091bdcfcece0 ("nfs/localio: refactor iocb and iov_iter_bvec initialization") Signed-off-by: Trond Myklebust Reviewed-by: Mike Snitzer Signed-off-by: Sasha Levin --- fs/nfs/localio.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/nfs/localio.c b/fs/nfs/localio.c index ed2a7efaf8f20..f537bc3386bf2 100644 --- a/fs/nfs/localio.c +++ b/fs/nfs/localio.c @@ -461,6 +461,8 @@ nfs_local_iters_init(struct nfs_local_kiocb *iocb, int rw) v = 0; total = hdr->args.count; base = hdr->args.pgbase; + pagevec += base >> PAGE_SHIFT; + base &= ~PAGE_MASK; while (total && v < hdr->page_array.npages) { len = min_t(size_t, total, PAGE_SIZE - base); bvec_set_page(&iocb->bvec[v], *pagevec, len, base); From 47244c00bc5456d57c2e4d2d82ab4e52adf050cc Mon Sep 17 00:00:00 2001 From: Andy Yan Date: Fri, 18 Jul 2025 14:41:13 +0800 Subject: [PATCH 1980/2333] drm/rockchip: vop2: Add delay between poll registers [ Upstream commit 9fae82450d8a5f9c8fa016cd15186e975609b2ac ] According to the implementation of read_poll_timeout_atomic, if the delay time is 0, it will only use a simple loop based on timeout_us to decrement the count. Therefore, the final timeout time will differ significantly from the set timeout time. So, here we set a specific delay time to ensure that the calculation of the timeout duration is accurate. Fixes: 3e89a8c68354 ("drm/rockchip: vop2: Fix the update of LAYER/PORT select registers when there are multi display output on rk3588/rk3568") Signed-off-by: Andy Yan Signed-off-by: Heiko Stuebner Link: https://patch.msgid.link/20250718064120.8811-1-andyshrk@163.com Signed-off-by: Sasha Levin --- drivers/gpu/drm/rockchip/rockchip_vop2_reg.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c index cd8380f0eddc8..855386a6a9f5c 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c +++ b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c @@ -2104,7 +2104,7 @@ static void rk3568_vop2_wait_for_port_mux_done(struct vop2 *vop2) * Spin until the previous port_mux figuration is done. */ ret = readx_poll_timeout_atomic(rk3568_vop2_read_port_mux, vop2, port_mux_sel, - port_mux_sel == vop2->old_port_sel, 0, 50 * 1000); + port_mux_sel == vop2->old_port_sel, 10, 50 * 1000); if (ret) DRM_DEV_ERROR(vop2->dev, "wait port_mux done timeout: 0x%x--0x%x\n", port_mux_sel, vop2->old_port_sel); @@ -2124,7 +2124,7 @@ static void rk3568_vop2_wait_for_layer_cfg_done(struct vop2 *vop2, u32 cfg) * Spin until the previous layer configuration is done. */ ret = readx_poll_timeout_atomic(rk3568_vop2_read_layer_cfg, vop2, atv_layer_cfg, - atv_layer_cfg == cfg, 0, 50 * 1000); + atv_layer_cfg == cfg, 10, 50 * 1000); if (ret) DRM_DEV_ERROR(vop2->dev, "wait layer cfg done timeout: 0x%x--0x%x\n", atv_layer_cfg, cfg); From 9a88b6c3c8695b708fd83523b3fe5a93e82ef7a4 Mon Sep 17 00:00:00 2001 From: Andy Yan Date: Fri, 18 Jul 2025 14:41:14 +0800 Subject: [PATCH 1981/2333] drm/rockchip: vop2: Only wait for changed layer cfg done when there is pending cfgdone bits [ Upstream commit 7f6721b767e219343cfe9a894f5bd869ff5b9d3a ] The write of cfgdone bits always done at .atomic_flush. When userspace makes plane zpos changes of two crtc within one commit, at the .atomic_begin stage, crtcN will never receive the "layer change cfg done" event of crtcM because crtcM has not yet written "cfgdone". So only wait when there is pending cfgdone bits to avoid long timeout. Fixes: 3e89a8c68354 ("drm/rockchip: vop2: Fix the update of LAYER/PORT select registers when there are multi display output on rk3588/rk3568") Signed-off-by: Andy Yan Signed-off-by: Heiko Stuebner Link: https://patch.msgid.link/20250718064120.8811-2-andyshrk@163.com Signed-off-by: Sasha Levin --- drivers/gpu/drm/rockchip/rockchip_vop2_reg.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c index 855386a6a9f5c..f3950e8476a75 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c +++ b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c @@ -2144,6 +2144,7 @@ static void rk3568_vop2_setup_layer_mixer(struct vop2_video_port *vp) u8 layer_sel_id; unsigned int ofs; u32 ovl_ctrl; + u32 cfg_done; int i; struct vop2_video_port *vp0 = &vop2->vps[0]; struct vop2_video_port *vp1 = &vop2->vps[1]; @@ -2298,8 +2299,16 @@ static void rk3568_vop2_setup_layer_mixer(struct vop2_video_port *vp) rk3568_vop2_wait_for_port_mux_done(vop2); } - if (layer_sel != old_layer_sel && atv_layer_sel != old_layer_sel) - rk3568_vop2_wait_for_layer_cfg_done(vop2, vop2->old_layer_sel); + if (layer_sel != old_layer_sel && atv_layer_sel != old_layer_sel) { + cfg_done = vop2_readl(vop2, RK3568_REG_CFG_DONE); + cfg_done &= (BIT(vop2->data->nr_vps) - 1); + cfg_done &= ~BIT(vp->id); + /* + * Changes of other VPs' overlays have not taken effect + */ + if (cfg_done) + rk3568_vop2_wait_for_layer_cfg_done(vop2, vop2->old_layer_sel); + } vop2_writel(vop2, RK3568_OVL_LAYER_SEL, layer_sel); mutex_unlock(&vop2->ovl_lock); From 754cfada1bbcbeeb922e54007c3c3aaaeeacf23e Mon Sep 17 00:00:00 2001 From: Yaxiong Tian Date: Tue, 30 Dec 2025 14:15:34 +0800 Subject: [PATCH 1982/2333] PM: EM: Fix incorrect description of the cost field in struct em_perf_state [ Upstream commit 54b603f2db6b95495bc33a8f2bde80f044baff9a ] Due to commit 1b600da51073 ("PM: EM: Optimize em_cpu_energy() and remove division"), the logic for energy consumption calculation has been modified. The actual calculation of cost is 10 * power * max_frequency / frequency instead of power * max_frequency / frequency. Therefore, the comment for cost has been updated to reflect the correct content. Fixes: 1b600da51073 ("PM: EM: Optimize em_cpu_energy() and remove division") Signed-off-by: Yaxiong Tian Reviewed-by: Lukasz Luba [ rjw: Added Fixes: tag ] Link: https://patch.msgid.link/20251230061534.816894-1-tianyaxiong@kylinos.cn Signed-off-by: Rafael J. Wysocki Signed-off-by: Sasha Levin --- include/linux/energy_model.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/energy_model.h b/include/linux/energy_model.h index 61d50571ad88a..ce2db5447d221 100644 --- a/include/linux/energy_model.h +++ b/include/linux/energy_model.h @@ -18,7 +18,7 @@ * @power: The power consumed at this level (by 1 CPU or by a registered * device). It can be a total power: static and dynamic. * @cost: The cost coefficient associated with this level, used during - * energy calculation. Equal to: power * max_frequency / frequency + * energy calculation. Equal to: 10 * power * max_frequency / frequency * @flags: see "em_perf_state flags" description below. */ struct em_perf_state { From 5584aa64e806282f4f15e61a2ce7f7b62ad81503 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 6 Jan 2026 17:24:26 +0000 Subject: [PATCH 1983/2333] ipv4: ip_tunnel: spread netdev_lockdep_set_classes() [ Upstream commit 872ac785e7680dac9ec7f8c5ccd4f667f49d6997 ] Inspired by yet another syzbot report. IPv6 tunnels call netdev_lockdep_set_classes() for each tunnel type, while IPv4 currently centralizes netdev_lockdep_set_classes() call from ip_tunnel_init(). Make ip_tunnel_init() a macro, so that we have different lockdep classes per tunnel type. Fixes: 0bef512012b1 ("net: add netdev_lockdep_set_classes() to virtual drivers") Reported-by: syzbot+1240b33467289f5ab50b@syzkaller.appspotmail.com Closes: https://lore.kernel.org/netdev/695d439f.050a0220.1c677c.0347.GAE@google.com/T/#u Signed-off-by: Eric Dumazet Link: https://patch.msgid.link/20260106172426.1760721-1-edumazet@google.com Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- include/net/ip_tunnels.h | 13 ++++++++++++- net/ipv4/ip_tunnel.c | 5 ++--- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/include/net/ip_tunnels.h b/include/net/ip_tunnels.h index ecae35512b9b4..4021e6a73e32b 100644 --- a/include/net/ip_tunnels.h +++ b/include/net/ip_tunnels.h @@ -19,6 +19,7 @@ #include #include #include +#include #if IS_ENABLED(CONFIG_IPV6) #include @@ -372,7 +373,17 @@ static inline void ip_tunnel_init_flow(struct flowi4 *fl4, fl4->flowi4_flags = flow_flags; } -int ip_tunnel_init(struct net_device *dev); +int __ip_tunnel_init(struct net_device *dev); +#define ip_tunnel_init(DEV) \ +({ \ + struct net_device *__dev = (DEV); \ + int __res = __ip_tunnel_init(__dev); \ + \ + if (!__res) \ + netdev_lockdep_set_classes(__dev);\ + __res; \ +}) + void ip_tunnel_uninit(struct net_device *dev); void ip_tunnel_dellink(struct net_device *dev, struct list_head *head); struct net *ip_tunnel_get_link_net(const struct net_device *dev); diff --git a/net/ipv4/ip_tunnel.c b/net/ipv4/ip_tunnel.c index 158a30ae7c5f2..50d0f5fe4e4c6 100644 --- a/net/ipv4/ip_tunnel.c +++ b/net/ipv4/ip_tunnel.c @@ -1281,7 +1281,7 @@ int ip_tunnel_changelink(struct net_device *dev, struct nlattr *tb[], } EXPORT_SYMBOL_GPL(ip_tunnel_changelink); -int ip_tunnel_init(struct net_device *dev) +int __ip_tunnel_init(struct net_device *dev) { struct ip_tunnel *tunnel = netdev_priv(dev); struct iphdr *iph = &tunnel->parms.iph; @@ -1308,10 +1308,9 @@ int ip_tunnel_init(struct net_device *dev) if (tunnel->collect_md) netif_keep_dst(dev); - netdev_lockdep_set_classes(dev); return 0; } -EXPORT_SYMBOL_GPL(ip_tunnel_init); +EXPORT_SYMBOL_GPL(__ip_tunnel_init); void ip_tunnel_uninit(struct net_device *dev) { From 6c5124a60989051799037834f0a1a4b428718157 Mon Sep 17 00:00:00 2001 From: Szymon Wilczek Date: Tue, 23 Dec 2025 02:17:32 +0100 Subject: [PATCH 1984/2333] can: etas_es58x: allow partial RX URB allocation to succeed [ Upstream commit b1979778e98569c1e78c2c7f16bb24d76541ab00 ] When es58x_alloc_rx_urbs() fails to allocate the requested number of URBs but succeeds in allocating some, it returns an error code. This causes es58x_open() to return early, skipping the cleanup label 'free_urbs', which leads to the anchored URBs being leaked. As pointed out by maintainer Vincent Mailhol, the driver is designed to handle partial URB allocation gracefully. Therefore, partial allocation should not be treated as a fatal error. Modify es58x_alloc_rx_urbs() to return 0 if at least one URB has been allocated, restoring the intended behavior and preventing the leak in es58x_open(). Fixes: 8537257874e9 ("can: etas_es58x: add core support for ETAS ES58X CAN USB interfaces") Reported-by: syzbot+e8cb6691a7cf68256cb8@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=e8cb6691a7cf68256cb8 Signed-off-by: Szymon Wilczek Reviewed-by: Vincent Mailhol Link: https://patch.msgid.link/20251223011732.39361-1-swilczek.lx@gmail.com Signed-off-by: Marc Kleine-Budde Signed-off-by: Sasha Levin --- drivers/net/can/usb/etas_es58x/es58x_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/can/usb/etas_es58x/es58x_core.c b/drivers/net/can/usb/etas_es58x/es58x_core.c index adc91873c083f..6eeba9baa1317 100644 --- a/drivers/net/can/usb/etas_es58x/es58x_core.c +++ b/drivers/net/can/usb/etas_es58x/es58x_core.c @@ -1736,7 +1736,7 @@ static int es58x_alloc_rx_urbs(struct es58x_device *es58x_dev) dev_dbg(dev, "%s: Allocated %d rx URBs each of size %u\n", __func__, i, rx_buf_len); - return ret; + return 0; } /** From 374b095e265fa27465f34780e0eb162ff1bef913 Mon Sep 17 00:00:00 2001 From: Shivam Kumar Date: Sat, 13 Dec 2025 13:57:48 -0500 Subject: [PATCH 1985/2333] nvme-tcp: fix NULL pointer dereferences in nvmet_tcp_build_pdu_iovec MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 32b63acd78f577b332d976aa06b56e70d054cbba ] Commit efa56305908b ("nvmet-tcp: Fix a kernel panic when host sends an invalid H2C PDU length") added ttag bounds checking and data_offset validation in nvmet_tcp_handle_h2c_data_pdu(), but it did not validate whether the command's data structures (cmd->req.sg and cmd->iov) have been properly initialized before processing H2C_DATA PDUs. The nvmet_tcp_build_pdu_iovec() function dereferences these pointers without NULL checks. This can be triggered by sending H2C_DATA PDU immediately after the ICREQ/ICRESP handshake, before sending a CONNECT command or NVMe write command. Attack vectors that trigger NULL pointer dereferences: 1. H2C_DATA PDU sent before CONNECT → both pointers NULL 2. H2C_DATA PDU for READ command → cmd->req.sg allocated, cmd->iov NULL 3. H2C_DATA PDU for uninitialized command slot → both pointers NULL The fix validates both cmd->req.sg and cmd->iov before calling nvmet_tcp_build_pdu_iovec(). Both checks are required because: - Uninitialized commands: both NULL - READ commands: cmd->req.sg allocated, cmd->iov NULL - WRITE commands: both allocated Fixes: efa56305908b ("nvmet-tcp: Fix a kernel panic when host sends an invalid H2C PDU length") Reviewed-by: Sagi Grimberg Signed-off-by: Shivam Kumar Signed-off-by: Keith Busch Signed-off-by: Sasha Levin --- drivers/nvme/target/tcp.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c index 470bf37e5a637..41b6fd05519e4 100644 --- a/drivers/nvme/target/tcp.c +++ b/drivers/nvme/target/tcp.c @@ -982,6 +982,18 @@ static int nvmet_tcp_handle_h2c_data_pdu(struct nvmet_tcp_queue *queue) pr_err("H2CData PDU len %u is invalid\n", cmd->pdu_len); goto err_proto; } + /* + * Ensure command data structures are initialized. We must check both + * cmd->req.sg and cmd->iov because they can have different NULL states: + * - Uninitialized commands: both NULL + * - READ commands: cmd->req.sg allocated, cmd->iov NULL + * - WRITE commands: both allocated + */ + if (unlikely(!cmd->req.sg || !cmd->iov)) { + pr_err("queue %d: H2CData PDU received for invalid command state (ttag %u)\n", + queue->idx, data->ttag); + goto err_proto; + } cmd->pdu_recv = 0; nvmet_tcp_build_pdu_iovec(cmd); queue->cmd = cmd; From 48f6cec8aa56bcbca34a9d156e7578ef70529df2 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Thu, 8 Jan 2026 11:13:23 +0100 Subject: [PATCH 1986/2333] cxl/port: Fix target list setup for multiple decoders sharing the same dport [ Upstream commit 3e8aaacdad4f66641f87ab441fe644b45f8ebdff ] If a switch port has more than one decoder that is using the same downstream port, the enumeration of the target lists may fail with: # dmesg | grep target.list update_decoder_targets: cxl decoder1.0: dport3 found in target list, index 3 update_decoder_targets: cxl decoder1.0: dport2 found in target list, index 2 update_decoder_targets: cxl decoder1.0: dport0 found in target list, index 0 update_decoder_targets: cxl decoder2.0: dport3 found in target list, index 1 update_decoder_targets: cxl decoder4.0: dport3 found in target list, index 1 cxl_mem mem6: failed to find endpoint12:0000:00:01.4 in target list of decoder2.1 cxl_mem mem8: failed to find endpoint13:0000:20:01.4 in target list of decoder4.1 The case, that the same downstream port can be used in multiple target lists, is allowed and possible. Fix the update of the target list. Enumerate all children of the switch port and do not stop the iteration after the first matching target was found. With the fix applied: # dmesg | grep target.list update_decoder_targets: cxl decoder1.0: dport2 found in target list, index 2 update_decoder_targets: cxl decoder1.0: dport0 found in target list, index 0 update_decoder_targets: cxl decoder1.0: dport3 found in target list, index 3 update_decoder_targets: cxl decoder2.0: dport3 found in target list, index 1 update_decoder_targets: cxl decoder2.1: dport3 found in target list, index 1 update_decoder_targets: cxl decoder4.0: dport3 found in target list, index 1 update_decoder_targets: cxl decoder4.1: dport3 found in target list, index 1 Analyzing the conditions when this happens: 1) A dport is shared by multiple decoders. 2) The decoders have interleaving configured (ways > 1). The configuration above has the following hierarchy details (fixed version): root0 |_ | | | decoder0.1 | ways: 2 | target_list: 0,1 |_______________________________________ | | | dport0 | dport1 | | port2 port4 | | |___________________ |_____________________ | | | | | | | decoder2.0 decoder2.1 | decoder4.0 decoder4.1 | ways: 2 ways: 2 | ways: 2 ways: 2 | target_list: 2,3 target_list: 2,3 | target_list: 2,3 target_list: 2,3 |___________________ |___________________ | | | | | dport2 | dport3 | dport2 | dport3 | | | | endpoint7 endpoint12 endpoint9 endpoint13 |_ |_ |_ |_ | | | | | | | | | decoder7.0 | decoder12.0 | decoder9.0 | decoder13.0 | decoder7.2 | decoder12.2 | decoder9.2 | decoder13.2 | | | | mem3 mem5 mem6 mem8 Note: Device numbers vary for every boot. Current kernel fails to enumerate endpoint12 and endpoint13 as the target list is not updated for the second decoder. Fixes: 4f06d81e7c6a ("cxl: Defer dport allocation for switch ports") Reviewed-by: Dave Jiang Reviewed-by: Alison Schofield Reviewed-by: Jonathan Cameron Signed-off-by: Robert Richter Link: https://patch.msgid.link/20260108101324.509667-1-rrichter@amd.com Signed-off-by: Dave Jiang Signed-off-by: Sasha Levin --- drivers/cxl/core/port.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c index 8128fd2b5b317..804e4a48540f6 100644 --- a/drivers/cxl/core/port.c +++ b/drivers/cxl/core/port.c @@ -1591,7 +1591,7 @@ static int update_decoder_targets(struct device *dev, void *data) cxlsd->target[i] = dport; dev_dbg(dev, "dport%d found in target list, index %d\n", dport->port_id, i); - return 1; + return 0; } } From 65241e3ddda60b53a4ee3ae12721fc9ee21d5827 Mon Sep 17 00:00:00 2001 From: Filipe Manana Date: Fri, 19 Dec 2025 11:26:02 +0000 Subject: [PATCH 1987/2333] btrfs: release path before iget_failed() in btrfs_read_locked_inode() [ Upstream commit 1e1f2055ad5a7a5d548789b334a4473a7665c418 ] In btrfs_read_locked_inode() if we fail to lookup the inode, we jump to the 'out' label with a path that has a read locked leaf and then we call iget_failed(). This can result in a ABBA deadlock, since iget_failed() triggers inode eviction and that causes the release of the delayed inode, which must lock the delayed inode's mutex, and a task updating a delayed inode starts by taking the node's mutex and then modifying the inode's subvolume btree. Syzbot reported the following lockdep splat for this: ====================================================== WARNING: possible circular locking dependency detected syzkaller #0 Not tainted ------------------------------------------------------ btrfs-cleaner/8725 is trying to acquire lock: ffff0000d6826a48 (&delayed_node->mutex){+.+.}-{4:4}, at: __btrfs_release_delayed_node+0xa0/0x9b0 fs/btrfs/delayed-inode.c:290 but task is already holding lock: ffff0000dbeba878 (btrfs-tree-00){++++}-{4:4}, at: btrfs_tree_read_lock_nested+0x44/0x2ec fs/btrfs/locking.c:145 which lock already depends on the new lock. the existing dependency chain (in reverse order) is: -> #1 (btrfs-tree-00){++++}-{4:4}: __lock_release kernel/locking/lockdep.c:5574 [inline] lock_release+0x198/0x39c kernel/locking/lockdep.c:5889 up_read+0x24/0x3c kernel/locking/rwsem.c:1632 btrfs_tree_read_unlock+0xdc/0x298 fs/btrfs/locking.c:169 btrfs_tree_unlock_rw fs/btrfs/locking.h:218 [inline] btrfs_search_slot+0xa6c/0x223c fs/btrfs/ctree.c:2133 btrfs_lookup_inode+0xd8/0x38c fs/btrfs/inode-item.c:395 __btrfs_update_delayed_inode+0x124/0xed0 fs/btrfs/delayed-inode.c:1032 btrfs_update_delayed_inode fs/btrfs/delayed-inode.c:1118 [inline] __btrfs_commit_inode_delayed_items+0x15f8/0x1748 fs/btrfs/delayed-inode.c:1141 __btrfs_run_delayed_items+0x1ac/0x514 fs/btrfs/delayed-inode.c:1176 btrfs_run_delayed_items_nr+0x28/0x38 fs/btrfs/delayed-inode.c:1219 flush_space+0x26c/0xb68 fs/btrfs/space-info.c:828 do_async_reclaim_metadata_space+0x110/0x364 fs/btrfs/space-info.c:1158 btrfs_async_reclaim_metadata_space+0x90/0xd8 fs/btrfs/space-info.c:1226 process_one_work+0x7e8/0x155c kernel/workqueue.c:3263 process_scheduled_works kernel/workqueue.c:3346 [inline] worker_thread+0x958/0xed8 kernel/workqueue.c:3427 kthread+0x5fc/0x75c kernel/kthread.c:463 ret_from_fork+0x10/0x20 arch/arm64/kernel/entry.S:844 -> #0 (&delayed_node->mutex){+.+.}-{4:4}: check_prev_add kernel/locking/lockdep.c:3165 [inline] check_prevs_add kernel/locking/lockdep.c:3284 [inline] validate_chain kernel/locking/lockdep.c:3908 [inline] __lock_acquire+0x1774/0x30a4 kernel/locking/lockdep.c:5237 lock_acquire+0x14c/0x2e0 kernel/locking/lockdep.c:5868 __mutex_lock_common+0x1d0/0x2678 kernel/locking/mutex.c:598 __mutex_lock kernel/locking/mutex.c:760 [inline] mutex_lock_nested+0x2c/0x38 kernel/locking/mutex.c:812 __btrfs_release_delayed_node+0xa0/0x9b0 fs/btrfs/delayed-inode.c:290 btrfs_release_delayed_node fs/btrfs/delayed-inode.c:315 [inline] btrfs_remove_delayed_node+0x68/0x84 fs/btrfs/delayed-inode.c:1326 btrfs_evict_inode+0x578/0xe28 fs/btrfs/inode.c:5587 evict+0x414/0x928 fs/inode.c:810 iput_final fs/inode.c:1914 [inline] iput+0x95c/0xad4 fs/inode.c:1966 iget_failed+0xec/0x134 fs/bad_inode.c:248 btrfs_read_locked_inode+0xe1c/0x1234 fs/btrfs/inode.c:4101 btrfs_iget+0x1b0/0x264 fs/btrfs/inode.c:5837 btrfs_run_defrag_inode fs/btrfs/defrag.c:237 [inline] btrfs_run_defrag_inodes+0x520/0xdc4 fs/btrfs/defrag.c:309 cleaner_kthread+0x21c/0x418 fs/btrfs/disk-io.c:1516 kthread+0x5fc/0x75c kernel/kthread.c:463 ret_from_fork+0x10/0x20 arch/arm64/kernel/entry.S:844 other info that might help us debug this: Possible unsafe locking scenario: CPU0 CPU1 ---- ---- rlock(btrfs-tree-00); lock(&delayed_node->mutex); lock(btrfs-tree-00); lock(&delayed_node->mutex); *** DEADLOCK *** 1 lock held by btrfs-cleaner/8725: #0: ffff0000dbeba878 (btrfs-tree-00){++++}-{4:4}, at: btrfs_tree_read_lock_nested+0x44/0x2ec fs/btrfs/locking.c:145 stack backtrace: CPU: 0 UID: 0 PID: 8725 Comm: btrfs-cleaner Not tainted syzkaller #0 PREEMPT Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 10/03/2025 Call trace: show_stack+0x2c/0x3c arch/arm64/kernel/stacktrace.c:499 (C) __dump_stack+0x30/0x40 lib/dump_stack.c:94 dump_stack_lvl+0xd8/0x12c lib/dump_stack.c:120 dump_stack+0x1c/0x28 lib/dump_stack.c:129 print_circular_bug+0x324/0x32c kernel/locking/lockdep.c:2043 check_noncircular+0x154/0x174 kernel/locking/lockdep.c:2175 check_prev_add kernel/locking/lockdep.c:3165 [inline] check_prevs_add kernel/locking/lockdep.c:3284 [inline] validate_chain kernel/locking/lockdep.c:3908 [inline] __lock_acquire+0x1774/0x30a4 kernel/locking/lockdep.c:5237 lock_acquire+0x14c/0x2e0 kernel/locking/lockdep.c:5868 __mutex_lock_common+0x1d0/0x2678 kernel/locking/mutex.c:598 __mutex_lock kernel/locking/mutex.c:760 [inline] mutex_lock_nested+0x2c/0x38 kernel/locking/mutex.c:812 __btrfs_release_delayed_node+0xa0/0x9b0 fs/btrfs/delayed-inode.c:290 btrfs_release_delayed_node fs/btrfs/delayed-inode.c:315 [inline] btrfs_remove_delayed_node+0x68/0x84 fs/btrfs/delayed-inode.c:1326 btrfs_evict_inode+0x578/0xe28 fs/btrfs/inode.c:5587 evict+0x414/0x928 fs/inode.c:810 iput_final fs/inode.c:1914 [inline] iput+0x95c/0xad4 fs/inode.c:1966 iget_failed+0xec/0x134 fs/bad_inode.c:248 btrfs_read_locked_inode+0xe1c/0x1234 fs/btrfs/inode.c:4101 btrfs_iget+0x1b0/0x264 fs/btrfs/inode.c:5837 btrfs_run_defrag_inode fs/btrfs/defrag.c:237 [inline] btrfs_run_defrag_inodes+0x520/0xdc4 fs/btrfs/defrag.c:309 cleaner_kthread+0x21c/0x418 fs/btrfs/disk-io.c:1516 kthread+0x5fc/0x75c kernel/kthread.c:463 ret_from_fork+0x10/0x20 arch/arm64/kernel/entry.S:844 Fix this by releasing the path before calling iget_failed(). Reported-by: syzbot+c1c6edb02bea1da754d8@syzkaller.appspotmail.com Link: https://lore.kernel.org/linux-btrfs/694530c2.a70a0220.207337.010d.GAE@google.com/ Fixes: 69673992b1ae ("btrfs: push cleanup into btrfs_read_locked_inode()") Reviewed-by: Boris Burkov Signed-off-by: Filipe Manana Signed-off-by: David Sterba Signed-off-by: Sasha Levin --- fs/btrfs/inode.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 27a562bad6e87..1af9b05328ce8 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -4108,6 +4108,15 @@ static int btrfs_read_locked_inode(struct btrfs_inode *inode, struct btrfs_path return 0; out: + /* + * We may have a read locked leaf and iget_failed() triggers inode + * eviction which needs to release the delayed inode and that needs + * to lock the delayed inode's mutex. This can cause a ABBA deadlock + * with a task running delayed items, as that require first locking + * the delayed inode's mutex and then modifying its subvolume btree. + * So release the path before iget_failed(). + */ + btrfs_release_path(path); iget_failed(vfs_inode); return ret; } From 39f83f10772310ba4a77f2b5256aaf36994ef7e8 Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Tue, 6 Jan 2026 20:26:40 +1030 Subject: [PATCH 1988/2333] btrfs: send: check for inline extents in range_is_hole_in_parent() [ Upstream commit 08b096c1372cd69627f4f559fb47c9fb67a52b39 ] Before accessing the disk_bytenr field of a file extent item we need to check if we are dealing with an inline extent. This is because for inline extents their data starts at the offset of the disk_bytenr field. So accessing the disk_bytenr means we are accessing inline data or in case the inline data is less than 8 bytes we can actually cause an invalid memory access if this inline extent item is the first item in the leaf or access metadata from other items. Fixes: 82bfb2e7b645 ("Btrfs: incremental send, fix unnecessary hole writes for sparse files") Reviewed-by: Filipe Manana Signed-off-by: Qu Wenruo Reviewed-by: David Sterba Signed-off-by: David Sterba Signed-off-by: Sasha Levin --- fs/btrfs/send.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c index 96a030d28e091..9012ce7a742f4 100644 --- a/fs/btrfs/send.c +++ b/fs/btrfs/send.c @@ -6399,6 +6399,8 @@ static int range_is_hole_in_parent(struct send_ctx *sctx, extent_end = btrfs_file_extent_end(path); if (extent_end <= start) goto next; + if (btrfs_file_extent_type(leaf, fi) == BTRFS_FILE_EXTENT_INLINE) + return 0; if (btrfs_file_extent_disk_bytenr(leaf, fi) == 0) { search_start = extent_end; goto next; From 368251745679ea3a055c4d6185a315db7510fb4f Mon Sep 17 00:00:00 2001 From: Yang Li Date: Fri, 19 Dec 2025 10:43:09 +0800 Subject: [PATCH 1989/2333] Bluetooth: hci_sync: enable PA Sync Lost event [ Upstream commit ab749bfe6a1fc233213f2d00facea5233139d509 ] Enable the PA Sync Lost event mask to ensure PA sync loss is properly reported and handled. Fixes: 485e0626e587 ("Bluetooth: hci_event: Fix not handling PA Sync Lost event") Signed-off-by: Yang Li Signed-off-by: Luiz Augusto von Dentz Signed-off-by: Sasha Levin --- net/bluetooth/hci_sync.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c index 6e76798ec786b..f5896c023a9fa 100644 --- a/net/bluetooth/hci_sync.c +++ b/net/bluetooth/hci_sync.c @@ -4402,6 +4402,7 @@ static int hci_le_set_event_mask_sync(struct hci_dev *hdev) if (bis_capable(hdev)) { events[1] |= 0x20; /* LE PA Report */ events[1] |= 0x40; /* LE PA Sync Established */ + events[1] |= 0x80; /* LE PA Sync Lost */ events[3] |= 0x04; /* LE Create BIG Complete */ events[3] |= 0x08; /* LE Terminate BIG Complete */ events[3] |= 0x10; /* LE BIG Sync Established */ From 17071fb5cb9c20cdbcd20322ebe2dd1220228590 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 8 Jan 2026 09:38:06 +0000 Subject: [PATCH 1990/2333] net: bridge: annotate data-races around fdb->{updated,used} [ Upstream commit b25a0b4a2193407aa72a4cd1df66a7ed07dd4f1e ] fdb->updated and fdb->used are read and written locklessly. Add READ_ONCE()/WRITE_ONCE() annotations. Fixes: 31cbc39b6344 ("net: bridge: add option to allow activity notifications for any fdb entries") Reported-by: syzbot+bfab43087ad57222ce96@syzkaller.appspotmail.com Closes: https://lore.kernel.org/netdev/695e3d74.050a0220.1c677c.035f.GAE@google.com/ Signed-off-by: Eric Dumazet Acked-by: Nikolay Aleksandrov Reviewed-by: Ido Schimmel Link: https://patch.msgid.link/20260108093806.834459-1-edumazet@google.com Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- net/bridge/br_fdb.c | 28 ++++++++++++++++------------ net/bridge/br_input.c | 4 ++-- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c index 58d22e2b85fc3..0501ffcb8a3dd 100644 --- a/net/bridge/br_fdb.c +++ b/net/bridge/br_fdb.c @@ -70,7 +70,7 @@ static inline int has_expired(const struct net_bridge *br, { return !test_bit(BR_FDB_STATIC, &fdb->flags) && !test_bit(BR_FDB_ADDED_BY_EXT_LEARN, &fdb->flags) && - time_before_eq(fdb->updated + hold_time(br), jiffies); + time_before_eq(READ_ONCE(fdb->updated) + hold_time(br), jiffies); } static int fdb_to_nud(const struct net_bridge *br, @@ -126,9 +126,9 @@ static int fdb_fill_info(struct sk_buff *skb, const struct net_bridge *br, if (nla_put_u32(skb, NDA_FLAGS_EXT, ext_flags)) goto nla_put_failure; - ci.ndm_used = jiffies_to_clock_t(now - fdb->used); + ci.ndm_used = jiffies_to_clock_t(now - READ_ONCE(fdb->used)); ci.ndm_confirmed = 0; - ci.ndm_updated = jiffies_to_clock_t(now - fdb->updated); + ci.ndm_updated = jiffies_to_clock_t(now - READ_ONCE(fdb->updated)); ci.ndm_refcnt = 0; if (nla_put(skb, NDA_CACHEINFO, sizeof(ci), &ci)) goto nla_put_failure; @@ -551,7 +551,7 @@ void br_fdb_cleanup(struct work_struct *work) */ rcu_read_lock(); hlist_for_each_entry_rcu(f, &br->fdb_list, fdb_node) { - unsigned long this_timer = f->updated + delay; + unsigned long this_timer = READ_ONCE(f->updated) + delay; if (test_bit(BR_FDB_STATIC, &f->flags) || test_bit(BR_FDB_ADDED_BY_EXT_LEARN, &f->flags)) { @@ -924,6 +924,7 @@ int br_fdb_fillbuf(struct net_bridge *br, void *buf, { struct net_bridge_fdb_entry *f; struct __fdb_entry *fe = buf; + unsigned long delta; int num = 0; memset(buf, 0, maxnum*sizeof(struct __fdb_entry)); @@ -953,8 +954,11 @@ int br_fdb_fillbuf(struct net_bridge *br, void *buf, fe->port_hi = f->dst->port_no >> 8; fe->is_local = test_bit(BR_FDB_LOCAL, &f->flags); - if (!test_bit(BR_FDB_STATIC, &f->flags)) - fe->ageing_timer_value = jiffies_delta_to_clock_t(jiffies - f->updated); + if (!test_bit(BR_FDB_STATIC, &f->flags)) { + delta = jiffies - READ_ONCE(f->updated); + fe->ageing_timer_value = + jiffies_delta_to_clock_t(delta); + } ++fe; ++num; } @@ -1002,8 +1006,8 @@ void br_fdb_update(struct net_bridge *br, struct net_bridge_port *source, unsigned long now = jiffies; bool fdb_modified = false; - if (now != fdb->updated) { - fdb->updated = now; + if (now != READ_ONCE(fdb->updated)) { + WRITE_ONCE(fdb->updated, now); fdb_modified = __fdb_mark_active(fdb); } @@ -1242,10 +1246,10 @@ static int fdb_add_entry(struct net_bridge *br, struct net_bridge_port *source, if (fdb_handle_notify(fdb, notify)) modified = true; - fdb->used = jiffies; + WRITE_ONCE(fdb->used, jiffies); if (modified) { if (refresh) - fdb->updated = jiffies; + WRITE_ONCE(fdb->updated, jiffies); fdb_notify(br, fdb, RTM_NEWNEIGH, true); } @@ -1556,7 +1560,7 @@ int br_fdb_external_learn_add(struct net_bridge *br, struct net_bridge_port *p, goto err_unlock; } - fdb->updated = jiffies; + WRITE_ONCE(fdb->updated, jiffies); if (READ_ONCE(fdb->dst) != p) { WRITE_ONCE(fdb->dst, p); @@ -1565,7 +1569,7 @@ int br_fdb_external_learn_add(struct net_bridge *br, struct net_bridge_port *p, if (test_and_set_bit(BR_FDB_ADDED_BY_EXT_LEARN, &fdb->flags)) { /* Refresh entry */ - fdb->used = jiffies; + WRITE_ONCE(fdb->used, jiffies); } else { modified = true; } diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c index 777fa869c1a14..e355a15bf5ab1 100644 --- a/net/bridge/br_input.c +++ b/net/bridge/br_input.c @@ -221,8 +221,8 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb if (test_bit(BR_FDB_LOCAL, &dst->flags)) return br_pass_frame_up(skb, false); - if (now != dst->used) - dst->used = now; + if (now != READ_ONCE(dst->used)) + WRITE_ONCE(dst->used, now); br_forward(dst->dst, skb, local_rcv, false); } else { if (!mcast_hit) From b9f915340f25cae1562f18e1eb52deafca328414 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 7 Jan 2026 16:31:09 +0000 Subject: [PATCH 1991/2333] ip6_tunnel: use skb_vlan_inet_prepare() in __ip6_tnl_rcv() [ Upstream commit 81c734dae203757fb3c9eee6f9896386940776bd ] Blamed commit did not take care of VLAN encapsulations as spotted by syzbot [1]. Use skb_vlan_inet_prepare() instead of pskb_inet_may_pull(). [1] BUG: KMSAN: uninit-value in __INET_ECN_decapsulate include/net/inet_ecn.h:253 [inline] BUG: KMSAN: uninit-value in INET_ECN_decapsulate include/net/inet_ecn.h:275 [inline] BUG: KMSAN: uninit-value in IP6_ECN_decapsulate+0x7a8/0x1fa0 include/net/inet_ecn.h:321 __INET_ECN_decapsulate include/net/inet_ecn.h:253 [inline] INET_ECN_decapsulate include/net/inet_ecn.h:275 [inline] IP6_ECN_decapsulate+0x7a8/0x1fa0 include/net/inet_ecn.h:321 ip6ip6_dscp_ecn_decapsulate+0x16f/0x1b0 net/ipv6/ip6_tunnel.c:729 __ip6_tnl_rcv+0xed9/0x1b50 net/ipv6/ip6_tunnel.c:860 ip6_tnl_rcv+0xc3/0x100 net/ipv6/ip6_tunnel.c:903 gre_rcv+0x1529/0x1b90 net/ipv6/ip6_gre.c:-1 ip6_protocol_deliver_rcu+0x1c89/0x2c60 net/ipv6/ip6_input.c:438 ip6_input_finish+0x1f4/0x4a0 net/ipv6/ip6_input.c:489 NF_HOOK include/linux/netfilter.h:318 [inline] ip6_input+0x9c/0x330 net/ipv6/ip6_input.c:500 ip6_mc_input+0x7ca/0xc10 net/ipv6/ip6_input.c:590 dst_input include/net/dst.h:474 [inline] ip6_rcv_finish+0x958/0x990 net/ipv6/ip6_input.c:79 NF_HOOK include/linux/netfilter.h:318 [inline] ipv6_rcv+0xf1/0x3c0 net/ipv6/ip6_input.c:311 __netif_receive_skb_one_core net/core/dev.c:6139 [inline] __netif_receive_skb+0x1df/0xac0 net/core/dev.c:6252 netif_receive_skb_internal net/core/dev.c:6338 [inline] netif_receive_skb+0x57/0x630 net/core/dev.c:6397 tun_rx_batched+0x1df/0x980 drivers/net/tun.c:1485 tun_get_user+0x5c0e/0x6c60 drivers/net/tun.c:1953 tun_chr_write_iter+0x3e9/0x5c0 drivers/net/tun.c:1999 new_sync_write fs/read_write.c:593 [inline] vfs_write+0xbe2/0x15d0 fs/read_write.c:686 ksys_write fs/read_write.c:738 [inline] __do_sys_write fs/read_write.c:749 [inline] __se_sys_write fs/read_write.c:746 [inline] __x64_sys_write+0x1fb/0x4d0 fs/read_write.c:746 x64_sys_call+0x30ab/0x3e70 arch/x86/include/generated/asm/syscalls_64.h:2 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] do_syscall_64+0xd3/0xf80 arch/x86/entry/syscall_64.c:94 entry_SYSCALL_64_after_hwframe+0x77/0x7f Uninit was created at: slab_post_alloc_hook mm/slub.c:4960 [inline] slab_alloc_node mm/slub.c:5263 [inline] kmem_cache_alloc_node_noprof+0x9e7/0x17a0 mm/slub.c:5315 kmalloc_reserve+0x13c/0x4b0 net/core/skbuff.c:586 __alloc_skb+0x805/0x1040 net/core/skbuff.c:690 alloc_skb include/linux/skbuff.h:1383 [inline] alloc_skb_with_frags+0xc5/0xa60 net/core/skbuff.c:6712 sock_alloc_send_pskb+0xacc/0xc60 net/core/sock.c:2995 tun_alloc_skb drivers/net/tun.c:1461 [inline] tun_get_user+0x1142/0x6c60 drivers/net/tun.c:1794 tun_chr_write_iter+0x3e9/0x5c0 drivers/net/tun.c:1999 new_sync_write fs/read_write.c:593 [inline] vfs_write+0xbe2/0x15d0 fs/read_write.c:686 ksys_write fs/read_write.c:738 [inline] __do_sys_write fs/read_write.c:749 [inline] __se_sys_write fs/read_write.c:746 [inline] __x64_sys_write+0x1fb/0x4d0 fs/read_write.c:746 x64_sys_call+0x30ab/0x3e70 arch/x86/include/generated/asm/syscalls_64.h:2 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] do_syscall_64+0xd3/0xf80 arch/x86/entry/syscall_64.c:94 entry_SYSCALL_64_after_hwframe+0x77/0x7f CPU: 0 UID: 0 PID: 6465 Comm: syz.0.17 Not tainted syzkaller #0 PREEMPT(none) Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 10/25/2025 Fixes: 8d975c15c0cd ("ip6_tunnel: make sure to pull inner header in __ip6_tnl_rcv()") Reported-by: syzbot+d4dda070f833dc5dc89a@syzkaller.appspotmail.com Closes: https://lore.kernel.org/netdev/695e88b2.050a0220.1c677c.036d.GAE@google.com/T/#u Signed-off-by: Eric Dumazet Link: https://patch.msgid.link/20260107163109.4188620-1-edumazet@google.com Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- net/ipv6/ip6_tunnel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index 6405072050e0e..c1f39735a2367 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -844,7 +844,7 @@ static int __ip6_tnl_rcv(struct ip6_tnl *tunnel, struct sk_buff *skb, skb_reset_network_header(skb); - if (!pskb_inet_may_pull(skb)) { + if (skb_vlan_inet_prepare(skb, true)) { DEV_STATS_INC(tunnel->dev, rx_length_errors); DEV_STATS_INC(tunnel->dev, rx_errors); goto drop; From da6d0370eb74e6d15724558117097ccb6bd8482c Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 8 Jan 2026 09:32:44 +0000 Subject: [PATCH 1992/2333] net: update netdev_lock_{type,name} [ Upstream commit eb74c19fe10872ee1f29a8f90ca5ce943921afe9 ] Add missing entries in netdev_lock_type[] and netdev_lock_name[] : CAN, MCTP, RAWIP, CAIF, IP6GRE, 6LOWPAN, NETLINK, VSOCKMON, IEEE802154_MONITOR. Also add a WARN_ONCE() in netdev_lock_pos() to help future bug hunting next time a protocol is added without updating these arrays. Fixes: 1a33e10e4a95 ("net: partially revert dynamic lockdep key changes") Signed-off-by: Eric Dumazet Link: https://patch.msgid.link/20260108093244.830280-1-edumazet@google.com Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- net/core/dev.c | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/net/core/dev.c b/net/core/dev.c index 2acfa44927daa..5b536860138d1 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -478,15 +478,21 @@ static const unsigned short netdev_lock_type[] = { ARPHRD_IEEE1394, ARPHRD_EUI64, ARPHRD_INFINIBAND, ARPHRD_SLIP, ARPHRD_CSLIP, ARPHRD_SLIP6, ARPHRD_CSLIP6, ARPHRD_RSRVD, ARPHRD_ADAPT, ARPHRD_ROSE, ARPHRD_X25, ARPHRD_HWX25, + ARPHRD_CAN, ARPHRD_MCTP, ARPHRD_PPP, ARPHRD_CISCO, ARPHRD_LAPB, ARPHRD_DDCMP, - ARPHRD_RAWHDLC, ARPHRD_TUNNEL, ARPHRD_TUNNEL6, ARPHRD_FRAD, + ARPHRD_RAWHDLC, ARPHRD_RAWIP, + ARPHRD_TUNNEL, ARPHRD_TUNNEL6, ARPHRD_FRAD, ARPHRD_SKIP, ARPHRD_LOOPBACK, ARPHRD_LOCALTLK, ARPHRD_FDDI, ARPHRD_BIF, ARPHRD_SIT, ARPHRD_IPDDP, ARPHRD_IPGRE, ARPHRD_PIMREG, ARPHRD_HIPPI, ARPHRD_ASH, ARPHRD_ECONET, ARPHRD_IRDA, ARPHRD_FCPP, ARPHRD_FCAL, ARPHRD_FCPL, ARPHRD_FCFABRIC, ARPHRD_IEEE80211, ARPHRD_IEEE80211_PRISM, - ARPHRD_IEEE80211_RADIOTAP, ARPHRD_PHONET, ARPHRD_PHONET_PIPE, - ARPHRD_IEEE802154, ARPHRD_VOID, ARPHRD_NONE}; + ARPHRD_IEEE80211_RADIOTAP, + ARPHRD_IEEE802154, ARPHRD_IEEE802154_MONITOR, + ARPHRD_PHONET, ARPHRD_PHONET_PIPE, + ARPHRD_CAIF, ARPHRD_IP6GRE, ARPHRD_NETLINK, ARPHRD_6LOWPAN, + ARPHRD_VSOCKMON, + ARPHRD_VOID, ARPHRD_NONE}; static const char *const netdev_lock_name[] = { "_xmit_NETROM", "_xmit_ETHER", "_xmit_EETHER", "_xmit_AX25", @@ -495,15 +501,21 @@ static const char *const netdev_lock_name[] = { "_xmit_IEEE1394", "_xmit_EUI64", "_xmit_INFINIBAND", "_xmit_SLIP", "_xmit_CSLIP", "_xmit_SLIP6", "_xmit_CSLIP6", "_xmit_RSRVD", "_xmit_ADAPT", "_xmit_ROSE", "_xmit_X25", "_xmit_HWX25", + "_xmit_CAN", "_xmit_MCTP", "_xmit_PPP", "_xmit_CISCO", "_xmit_LAPB", "_xmit_DDCMP", - "_xmit_RAWHDLC", "_xmit_TUNNEL", "_xmit_TUNNEL6", "_xmit_FRAD", + "_xmit_RAWHDLC", "_xmit_RAWIP", + "_xmit_TUNNEL", "_xmit_TUNNEL6", "_xmit_FRAD", "_xmit_SKIP", "_xmit_LOOPBACK", "_xmit_LOCALTLK", "_xmit_FDDI", "_xmit_BIF", "_xmit_SIT", "_xmit_IPDDP", "_xmit_IPGRE", "_xmit_PIMREG", "_xmit_HIPPI", "_xmit_ASH", "_xmit_ECONET", "_xmit_IRDA", "_xmit_FCPP", "_xmit_FCAL", "_xmit_FCPL", "_xmit_FCFABRIC", "_xmit_IEEE80211", "_xmit_IEEE80211_PRISM", - "_xmit_IEEE80211_RADIOTAP", "_xmit_PHONET", "_xmit_PHONET_PIPE", - "_xmit_IEEE802154", "_xmit_VOID", "_xmit_NONE"}; + "_xmit_IEEE80211_RADIOTAP", + "_xmit_IEEE802154", "_xmit_IEEE802154_MONITOR", + "_xmit_PHONET", "_xmit_PHONET_PIPE", + "_xmit_CAIF", "_xmit_IP6GRE", "_xmit_NETLINK", "_xmit_6LOWPAN", + "_xmit_VSOCKMON", + "_xmit_VOID", "_xmit_NONE"}; static struct lock_class_key netdev_xmit_lock_key[ARRAY_SIZE(netdev_lock_type)]; static struct lock_class_key netdev_addr_lock_key[ARRAY_SIZE(netdev_lock_type)]; @@ -516,6 +528,7 @@ static inline unsigned short netdev_lock_pos(unsigned short dev_type) if (netdev_lock_type[i] == dev_type) return i; /* the last key is used by default */ + WARN_ONCE(1, "netdev_lock_pos() could not find dev_type=%u\n", dev_type); return ARRAY_SIZE(netdev_lock_type) - 1; } From 6dbead9c7677186f22b7981dd085a0feec1f038e Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 8 Jan 2026 13:36:51 +0000 Subject: [PATCH 1993/2333] macvlan: fix possible UAF in macvlan_forward_source() [ Upstream commit 7470a7a63dc162f07c26dbf960e41ee1e248d80e ] Add RCU protection on (struct macvlan_source_entry)->vlan. Whenever macvlan_hash_del_source() is called, we must clear entry->vlan pointer before RCU grace period starts. This allows macvlan_forward_source() to skip over entries queued for freeing. Note that macvlan_dev are already RCU protected, as they are embedded in a standard netdev (netdev_priv(ndev)). Fixes: 79cf79abce71 ("macvlan: add source mode") Reported-by: syzbot+7182fbe91e58602ec1fe@syzkaller.appspotmail.com https: //lore.kernel.org/netdev/695fb1e8.050a0220.1c677c.039f.GAE@google.com/T/#u Signed-off-by: Eric Dumazet Link: https://patch.msgid.link/20260108133651.1130486-1-edumazet@google.com Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- drivers/net/macvlan.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 7966545512cfe..b4df7e184791d 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -59,7 +59,7 @@ struct macvlan_port { struct macvlan_source_entry { struct hlist_node hlist; - struct macvlan_dev *vlan; + struct macvlan_dev __rcu *vlan; unsigned char addr[6+2] __aligned(sizeof(u16)); struct rcu_head rcu; }; @@ -146,7 +146,7 @@ static struct macvlan_source_entry *macvlan_hash_lookup_source( hlist_for_each_entry_rcu(entry, h, hlist, lockdep_rtnl_is_held()) { if (ether_addr_equal_64bits(entry->addr, addr) && - entry->vlan == vlan) + rcu_access_pointer(entry->vlan) == vlan) return entry; } return NULL; @@ -168,7 +168,7 @@ static int macvlan_hash_add_source(struct macvlan_dev *vlan, return -ENOMEM; ether_addr_copy(entry->addr, addr); - entry->vlan = vlan; + RCU_INIT_POINTER(entry->vlan, vlan); h = &port->vlan_source_hash[macvlan_eth_hash(addr)]; hlist_add_head_rcu(&entry->hlist, h); vlan->macaddr_count++; @@ -187,6 +187,7 @@ static void macvlan_hash_add(struct macvlan_dev *vlan) static void macvlan_hash_del_source(struct macvlan_source_entry *entry) { + RCU_INIT_POINTER(entry->vlan, NULL); hlist_del_rcu(&entry->hlist); kfree_rcu(entry, rcu); } @@ -390,7 +391,7 @@ static void macvlan_flush_sources(struct macvlan_port *port, int i; hash_for_each_safe(port->vlan_source_hash, i, next, entry, hlist) - if (entry->vlan == vlan) + if (rcu_access_pointer(entry->vlan) == vlan) macvlan_hash_del_source(entry); vlan->macaddr_count = 0; @@ -433,9 +434,14 @@ static bool macvlan_forward_source(struct sk_buff *skb, hlist_for_each_entry_rcu(entry, h, hlist) { if (ether_addr_equal_64bits(entry->addr, addr)) { - if (entry->vlan->flags & MACVLAN_FLAG_NODST) + struct macvlan_dev *vlan = rcu_dereference(entry->vlan); + + if (!vlan) + continue; + + if (vlan->flags & MACVLAN_FLAG_NODST) consume = true; - macvlan_forward_source_one(skb, entry->vlan); + macvlan_forward_source_one(skb, vlan); } } @@ -1680,7 +1686,7 @@ static int macvlan_fill_info_macaddr(struct sk_buff *skb, struct macvlan_source_entry *entry; hlist_for_each_entry_rcu(entry, h, hlist, lockdep_rtnl_is_held()) { - if (entry->vlan != vlan) + if (rcu_access_pointer(entry->vlan) != vlan) continue; if (nla_put(skb, IFLA_MACVLAN_MACADDR, ETH_ALEN, entry->addr)) return 1; From d6072557b90e0c557df319a56f4a9dc482706d2c Mon Sep 17 00:00:00 2001 From: Caleb Sander Mateos Date: Thu, 8 Jan 2026 10:22:10 -0700 Subject: [PATCH 1994/2333] block: zero non-PI portion of auto integrity buffer [ Upstream commit ca22c566b89164f6e670af56ecc45f47ef3df819 ] The auto-generated integrity buffer for writes needs to be fully initialized before being passed to the underlying block device, otherwise the uninitialized memory can be read back by userspace or anyone with physical access to the storage device. If protection information is generated, that portion of the integrity buffer is already initialized. The integrity data is also zeroed if PI generation is disabled via sysfs or the PI tuple size is 0. However, this misses the case where PI is generated and the PI tuple size is nonzero, but the metadata size is larger than the PI tuple. In this case, the remainder ("opaque") of the metadata is left uninitialized. Generalize the BLK_INTEGRITY_CSUM_NONE check to cover any case when the metadata is larger than just the PI tuple. Signed-off-by: Caleb Sander Mateos Fixes: c546d6f43833 ("block: only zero non-PI metadata tuples in bio_integrity_prep") Reviewed-by: Anuj Gupta Reviewed-by: Christoph Hellwig Reviewed-by: Martin K. Petersen Signed-off-by: Jens Axboe Signed-off-by: Sasha Levin --- block/bio-integrity-auto.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/block/bio-integrity-auto.c b/block/bio-integrity-auto.c index 687952f63bbbf..b8b7587be9679 100644 --- a/block/bio-integrity-auto.c +++ b/block/bio-integrity-auto.c @@ -142,7 +142,7 @@ bool bio_integrity_prep(struct bio *bio) return true; set_flags = false; gfp |= __GFP_ZERO; - } else if (bi->csum_type == BLK_INTEGRITY_CSUM_NONE) + } else if (bi->metadata_size > bi->pi_tuple_size) gfp |= __GFP_ZERO; break; default: From 554201ed0a8f4d32e719f42caeaeb2735a9ed6ca Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 8 Jan 2026 19:02:14 +0000 Subject: [PATCH 1995/2333] ipv4: ip_gre: make ipgre_header() robust [ Upstream commit e67c577d89894811ce4dcd1a9ed29d8b63476667 ] Analog to commit db5b4e39c4e6 ("ip6_gre: make ip6gre_header() robust") Over the years, syzbot found many ways to crash the kernel in ipgre_header() [1]. This involves team or bonding drivers ability to dynamically change their dev->needed_headroom and/or dev->hard_header_len In this particular crash mld_newpack() allocated an skb with a too small reserve/headroom, and by the time mld_sendpack() was called, syzbot managed to attach an ipgre device. [1] skbuff: skb_under_panic: text:ffffffff89ea3cb7 len:2030915468 put:2030915372 head:ffff888058b43000 data:ffff887fdfa6e194 tail:0x120 end:0x6c0 dev:team0 kernel BUG at net/core/skbuff.c:213 ! Oops: invalid opcode: 0000 [#1] SMP KASAN PTI CPU: 1 UID: 0 PID: 1322 Comm: kworker/1:9 Not tainted syzkaller #0 PREEMPT(full) Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 10/25/2025 Workqueue: mld mld_ifc_work RIP: 0010:skb_panic+0x157/0x160 net/core/skbuff.c:213 Call Trace: skb_under_panic net/core/skbuff.c:223 [inline] skb_push+0xc3/0xe0 net/core/skbuff.c:2641 ipgre_header+0x67/0x290 net/ipv4/ip_gre.c:897 dev_hard_header include/linux/netdevice.h:3436 [inline] neigh_connected_output+0x286/0x460 net/core/neighbour.c:1618 NF_HOOK_COND include/linux/netfilter.h:307 [inline] ip6_output+0x340/0x550 net/ipv6/ip6_output.c:247 NF_HOOK+0x9e/0x380 include/linux/netfilter.h:318 mld_sendpack+0x8d4/0xe60 net/ipv6/mcast.c:1855 mld_send_cr net/ipv6/mcast.c:2154 [inline] mld_ifc_work+0x83e/0xd60 net/ipv6/mcast.c:2693 process_one_work kernel/workqueue.c:3257 [inline] process_scheduled_works+0xad1/0x1770 kernel/workqueue.c:3340 worker_thread+0x8a0/0xda0 kernel/workqueue.c:3421 kthread+0x711/0x8a0 kernel/kthread.c:463 ret_from_fork+0x510/0xa50 arch/x86/kernel/process.c:158 ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:246 Fixes: c54419321455 ("GRE: Refactor GRE tunneling code.") Reported-by: syzbot+7c134e1c3aa3283790b9@syzkaller.appspotmail.com Closes: https://www.spinics.net/lists/netdev/msg1147302.html Signed-off-by: Eric Dumazet Link: https://patch.msgid.link/20260108190214.1667040-1-edumazet@google.com Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- net/ipv4/ip_gre.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index 8178c44a3cdd4..e13244729ad8d 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -891,10 +891,17 @@ static int ipgre_header(struct sk_buff *skb, struct net_device *dev, const void *daddr, const void *saddr, unsigned int len) { struct ip_tunnel *t = netdev_priv(dev); - struct iphdr *iph; struct gre_base_hdr *greh; + struct iphdr *iph; + int needed; + + needed = t->hlen + sizeof(*iph); + if (skb_headroom(skb) < needed && + pskb_expand_head(skb, HH_DATA_ALIGN(needed - skb_headroom(skb)), + 0, GFP_ATOMIC)) + return -needed; - iph = skb_push(skb, t->hlen + sizeof(*iph)); + iph = skb_push(skb, needed); greh = (struct gre_base_hdr *)(iph+1); greh->flags = gre_tnl_flags_to_gre_flags(t->parms.o_flags); greh->protocol = htons(type); From f39ab11f118b2d22db5a1313260e3977bff02b27 Mon Sep 17 00:00:00 2001 From: Stefano Garzarella Date: Thu, 8 Jan 2026 12:44:19 +0100 Subject: [PATCH 1996/2333] vsock/test: add a final full barrier after run all tests [ Upstream commit c39a6a277e0e67ffff6a8efcbbf7e7e23ce9e38c ] If the last test fails, the other side still completes correctly, which could lead to false positives. Let's add a final barrier that ensures that the last test has finished correctly on both sides, but also that the two sides agree on the number of tests to be performed. Fixes: 2f65b44e199c ("VSOCK: add full barrier between test cases") Reviewed-by: Luigi Leonardi Signed-off-by: Stefano Garzarella Link: https://patch.msgid.link/20260108114419.52747-1-sgarzare@redhat.com Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- tools/testing/vsock/util.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tools/testing/vsock/util.c b/tools/testing/vsock/util.c index d843643ced6b7..9430ef5b8bc3e 100644 --- a/tools/testing/vsock/util.c +++ b/tools/testing/vsock/util.c @@ -511,6 +511,18 @@ void run_tests(const struct test_case *test_cases, printf("ok\n"); } + + printf("All tests have been executed. Waiting other peer..."); + fflush(stdout); + + /* + * Final full barrier, to ensure that all tests have been run and + * that even the last one has been successful on both sides. + */ + control_writeln("COMPLETED"); + control_expectln("COMPLETED"); + + printf("ok\n"); } void list_tests(const struct test_case *test_cases) From e05b8084a20f6bd5827d338c928e5e0fcbafa496 Mon Sep 17 00:00:00 2001 From: Saeed Mahameed Date: Thu, 8 Jan 2026 13:26:54 -0800 Subject: [PATCH 1997/2333] net/mlx5e: Fix crash on profile change rollback failure [ Upstream commit 4dadc4077e3f77d6d31e199a925fc7a705e7adeb ] mlx5e_netdev_change_profile can fail to attach a new profile and can fail to rollback to old profile, in such case, we could end up with a dangling netdev with a fully reset netdev_priv. A retry to change profile, e.g. another attempt to call mlx5e_netdev_change_profile via switchdev mode change, will crash trying to access the now NULL priv->mdev. This fix allows mlx5e_netdev_change_profile() to handle previous failures and an empty priv, by not assuming priv is valid. Pass netdev and mdev to all flows requiring mlx5e_netdev_change_profile() and avoid passing priv. In mlx5e_netdev_change_profile() check if current priv is valid, and if not, just attach the new profile without trying to access the old one. This fixes the following oops, when enabling switchdev mode for the 2nd time after first time failure: ## Enabling switchdev mode first time: mlx5_core 0012:03:00.1: E-Switch: Supported tc chains and prios offload workqueue: Failed to create a rescuer kthread for wq "mlx5e": -EINTR mlx5_core 0012:03:00.1: mlx5e_netdev_init_profile:6214:(pid 37199): mlx5e_priv_init failed, err=-12 mlx5_core 0012:03:00.1 gpu3rdma1: mlx5e_netdev_change_profile: new profile init failed, -12 workqueue: Failed to create a rescuer kthread for wq "mlx5e": -EINTR mlx5_core 0012:03:00.1: mlx5e_netdev_init_profile:6214:(pid 37199): mlx5e_priv_init failed, err=-12 mlx5_core 0012:03:00.1 gpu3rdma1: mlx5e_netdev_change_profile: failed to rollback to orig profile, -12 ^^^^^^^^ mlx5_core 0000:00:03.0: E-Switch: Disable: mode(LEGACY), nvfs(0), necvfs(0), active vports(0) ## retry: Enabling switchdev mode 2nd time: mlx5_core 0000:00:03.0: E-Switch: Supported tc chains and prios offload BUG: kernel NULL pointer dereference, address: 0000000000000038 #PF: supervisor read access in kernel mode #PF: error_code(0x0000) - not-present page PGD 0 P4D 0 Oops: Oops: 0000 [#1] SMP NOPTI CPU: 13 UID: 0 PID: 520 Comm: devlink Not tainted 6.18.0-rc4+ #91 PREEMPT(voluntary) Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-2.fc40 04/01/2014 RIP: 0010:mlx5e_detach_netdev+0x3c/0x90 Code: 50 00 00 f0 80 4f 78 02 48 8b bf e8 07 00 00 48 85 ff 74 16 48 8b 73 78 48 d1 ee 83 e6 01 83 f6 01 40 0f b6 f6 e8 c4 42 00 00 <48> 8b 45 38 48 85 c0 74 08 48 89 df e8 cc 47 40 1e 48 8b bb f0 07 RSP: 0018:ffffc90000673890 EFLAGS: 00010246 RAX: 0000000000000000 RBX: ffff8881036a89c0 RCX: 0000000000000000 RDX: ffff888113f63800 RSI: ffffffff822fe720 RDI: 0000000000000000 RBP: 0000000000000000 R08: 0000000000002dcd R09: 0000000000000000 R10: ffffc900006738e8 R11: 00000000ffffffff R12: 0000000000000000 R13: 0000000000000000 R14: ffff8881036a89c0 R15: 0000000000000000 FS: 00007fdfb8384740(0000) GS:ffff88856a9d6000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000038 CR3: 0000000112ae0005 CR4: 0000000000370ef0 Call Trace: mlx5e_netdev_change_profile+0x45/0xb0 mlx5e_vport_rep_load+0x27b/0x2d0 mlx5_esw_offloads_rep_load+0x72/0xf0 esw_offloads_enable+0x5d0/0x970 mlx5_eswitch_enable_locked+0x349/0x430 ? is_mp_supported+0x57/0xb0 mlx5_devlink_eswitch_mode_set+0x26b/0x430 devlink_nl_eswitch_set_doit+0x6f/0xf0 genl_family_rcv_msg_doit+0xe8/0x140 genl_rcv_msg+0x18b/0x290 ? __pfx_devlink_nl_pre_doit+0x10/0x10 ? __pfx_devlink_nl_eswitch_set_doit+0x10/0x10 ? __pfx_devlink_nl_post_doit+0x10/0x10 ? __pfx_genl_rcv_msg+0x10/0x10 netlink_rcv_skb+0x52/0x100 genl_rcv+0x28/0x40 netlink_unicast+0x282/0x3e0 ? __alloc_skb+0xd6/0x190 netlink_sendmsg+0x1f7/0x430 __sys_sendto+0x213/0x220 ? __sys_recvmsg+0x6a/0xd0 __x64_sys_sendto+0x24/0x30 do_syscall_64+0x50/0x1f0 entry_SYSCALL_64_after_hwframe+0x76/0x7e RIP: 0033:0x7fdfb8495047 Fixes: c4d7eb57687f ("net/mxl5e: Add change profile method") Signed-off-by: Saeed Mahameed Reviewed-by: Tariq Toukan Link: https://patch.msgid.link/20260108212657.25090-2-saeed@kernel.org Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- drivers/net/ethernet/mellanox/mlx5/core/en.h | 9 ++-- .../net/ethernet/mellanox/mlx5/core/en_main.c | 48 +++++++++++++------ .../net/ethernet/mellanox/mlx5/core/en_rep.c | 11 ++--- 3 files changed, 44 insertions(+), 24 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h index a6479e4d8d8c6..cfdbeb21b61cf 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h @@ -1239,9 +1239,12 @@ mlx5e_create_netdev(struct mlx5_core_dev *mdev, const struct mlx5e_profile *prof int mlx5e_attach_netdev(struct mlx5e_priv *priv); void mlx5e_detach_netdev(struct mlx5e_priv *priv); void mlx5e_destroy_netdev(struct mlx5e_priv *priv); -int mlx5e_netdev_change_profile(struct mlx5e_priv *priv, - const struct mlx5e_profile *new_profile, void *new_ppriv); -void mlx5e_netdev_attach_nic_profile(struct mlx5e_priv *priv); +int mlx5e_netdev_change_profile(struct net_device *netdev, + struct mlx5_core_dev *mdev, + const struct mlx5e_profile *new_profile, + void *new_ppriv); +void mlx5e_netdev_attach_nic_profile(struct net_device *netdev, + struct mlx5_core_dev *mdev); void mlx5e_set_netdev_mtu_boundaries(struct mlx5e_priv *priv); void mlx5e_build_nic_params(struct mlx5e_priv *priv, struct mlx5e_xsk *xsk, u16 mtu); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index 1545f9c008f49..3850c267dfc02 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -6564,19 +6564,28 @@ mlx5e_netdev_attach_profile(struct net_device *netdev, struct mlx5_core_dev *mde return err; } -int mlx5e_netdev_change_profile(struct mlx5e_priv *priv, - const struct mlx5e_profile *new_profile, void *new_ppriv) +int mlx5e_netdev_change_profile(struct net_device *netdev, + struct mlx5_core_dev *mdev, + const struct mlx5e_profile *new_profile, + void *new_ppriv) { - const struct mlx5e_profile *orig_profile = priv->profile; - struct net_device *netdev = priv->netdev; - struct mlx5_core_dev *mdev = priv->mdev; - void *orig_ppriv = priv->ppriv; + struct mlx5e_priv *priv = netdev_priv(netdev); + const struct mlx5e_profile *orig_profile; int err, rollback_err; + void *orig_ppriv; - /* cleanup old profile */ - mlx5e_detach_netdev(priv); - priv->profile->cleanup(priv); - mlx5e_priv_cleanup(priv); + orig_profile = priv->profile; + orig_ppriv = priv->ppriv; + + /* NULL could happen if previous change_profile failed to rollback */ + if (priv->profile) { + WARN_ON_ONCE(priv->mdev != mdev); + /* cleanup old profile */ + mlx5e_detach_netdev(priv); + priv->profile->cleanup(priv); + mlx5e_priv_cleanup(priv); + } + /* priv members are not valid from this point ... */ if (mdev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR) { mlx5e_netdev_init_profile(netdev, mdev, new_profile, new_ppriv); @@ -6593,16 +6602,25 @@ int mlx5e_netdev_change_profile(struct mlx5e_priv *priv, return 0; rollback: + if (!orig_profile) { + netdev_warn(netdev, "no original profile to rollback to\n"); + priv->profile = NULL; + return err; + } + rollback_err = mlx5e_netdev_attach_profile(netdev, mdev, orig_profile, orig_ppriv); - if (rollback_err) - netdev_err(netdev, "%s: failed to rollback to orig profile, %d\n", - __func__, rollback_err); + if (rollback_err) { + netdev_err(netdev, "failed to rollback to orig profile, %d\n", + rollback_err); + priv->profile = NULL; + } return err; } -void mlx5e_netdev_attach_nic_profile(struct mlx5e_priv *priv) +void mlx5e_netdev_attach_nic_profile(struct net_device *netdev, + struct mlx5_core_dev *mdev) { - mlx5e_netdev_change_profile(priv, &mlx5e_nic_profile, NULL); + mlx5e_netdev_change_profile(netdev, mdev, &mlx5e_nic_profile, NULL); } void mlx5e_destroy_netdev(struct mlx5e_priv *priv) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c index 0335ca8277efa..2f6aa5e61747c 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c @@ -1508,17 +1508,16 @@ mlx5e_vport_uplink_rep_load(struct mlx5_core_dev *dev, struct mlx5_eswitch_rep * { struct mlx5e_rep_priv *rpriv = mlx5e_rep_to_rep_priv(rep); struct net_device *netdev; - struct mlx5e_priv *priv; int err; netdev = mlx5_uplink_netdev_get(dev); if (!netdev) return 0; - priv = netdev_priv(netdev); - rpriv->netdev = priv->netdev; - err = mlx5e_netdev_change_profile(priv, &mlx5e_uplink_rep_profile, - rpriv); + /* must not use netdev_priv(netdev), it might not be initialized yet */ + rpriv->netdev = netdev; + err = mlx5e_netdev_change_profile(netdev, dev, + &mlx5e_uplink_rep_profile, rpriv); mlx5_uplink_netdev_put(dev, netdev); return err; } @@ -1546,7 +1545,7 @@ mlx5e_vport_uplink_rep_unload(struct mlx5e_rep_priv *rpriv) if (!(priv->mdev->priv.flags & MLX5_PRIV_FLAGS_SWITCH_LEGACY)) unregister_netdev(netdev); - mlx5e_netdev_attach_nic_profile(priv); + mlx5e_netdev_attach_nic_profile(netdev, priv->mdev); } static int From a3d4f87d41f5140f1cf5c02fce5cdad2637f6244 Mon Sep 17 00:00:00 2001 From: Saeed Mahameed Date: Thu, 8 Jan 2026 13:26:55 -0800 Subject: [PATCH 1998/2333] net/mlx5e: Don't store mlx5e_priv in mlx5e_dev devlink priv [ Upstream commit 123eda2e5b1638e298e3a66bb1e64a8da92de5e1 ] mlx5e_priv is an unstable structure that can be memset(0) if profile attaching fails, mlx5e_priv in mlx5e_dev devlink private is used to reference the netdev and mdev associated with that struct. Instead, store netdev directly into mlx5e_dev and get mdev from the containing mlx5_adev aux device structure. This fixes a kernel oops in mlx5e_remove when switchdev mode fails due to change profile failure. $ devlink dev eswitch set pci/0000:00:03.0 mode switchdev Error: mlx5_core: Failed setting eswitch to offloads. dmesg: workqueue: Failed to create a rescuer kthread for wq "mlx5e": -EINTR mlx5_core 0012:03:00.1: mlx5e_netdev_init_profile:6214:(pid 37199): mlx5e_priv_init failed, err=-12 mlx5_core 0012:03:00.1 gpu3rdma1: mlx5e_netdev_change_profile: new profile init failed, -12 workqueue: Failed to create a rescuer kthread for wq "mlx5e": -EINTR mlx5_core 0012:03:00.1: mlx5e_netdev_init_profile:6214:(pid 37199): mlx5e_priv_init failed, err=-12 mlx5_core 0012:03:00.1 gpu3rdma1: mlx5e_netdev_change_profile: failed to rollback to orig profile, -12 $ devlink dev reload pci/0000:00:03.0 ==> oops BUG: kernel NULL pointer dereference, address: 0000000000000520 #PF: supervisor read access in kernel mode #PF: error_code(0x0000) - not-present page PGD 0 P4D 0 Oops: Oops: 0000 [#1] SMP NOPTI CPU: 3 UID: 0 PID: 521 Comm: devlink Not tainted 6.18.0-rc5+ #117 PREEMPT(voluntary) Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-2.fc40 04/01/2014 RIP: 0010:mlx5e_remove+0x68/0x130 RSP: 0018:ffffc900034838f0 EFLAGS: 00010246 RAX: ffff88810283c380 RBX: ffff888101874400 RCX: ffffffff826ffc45 RDX: 0000000000000000 RSI: 0000000000000001 RDI: 0000000000000000 RBP: ffff888102d789c0 R08: ffff8881007137f0 R09: ffff888100264e10 R10: ffffc90003483898 R11: ffffc900034838a0 R12: ffff888100d261a0 R13: ffff888100d261a0 R14: ffff8881018749a0 R15: ffff888101874400 FS: 00007f8565fea740(0000) GS:ffff88856a759000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000520 CR3: 000000010b11a004 CR4: 0000000000370ef0 Call Trace: device_release_driver_internal+0x19c/0x200 bus_remove_device+0xc6/0x130 device_del+0x160/0x3d0 ? devl_param_driverinit_value_get+0x2d/0x90 mlx5_detach_device+0x89/0xe0 mlx5_unload_one_devl_locked+0x3a/0x70 mlx5_devlink_reload_down+0xc8/0x220 devlink_reload+0x7d/0x260 devlink_nl_reload_doit+0x45b/0x5a0 genl_family_rcv_msg_doit+0xe8/0x140 Fixes: ee75f1fc44dd ("net/mlx5e: Create separate devlink instance for ethernet auxiliary device") Fixes: c4d7eb57687f ("net/mxl5e: Add change profile method") Signed-off-by: Saeed Mahameed Link: https://patch.msgid.link/20260108212657.25090-3-saeed@kernel.org Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- drivers/net/ethernet/mellanox/mlx5/core/en.h | 2 +- .../net/ethernet/mellanox/mlx5/core/en_main.c | 20 ++++++++++--------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h index cfdbeb21b61cf..bc1b343f89a25 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h @@ -963,7 +963,7 @@ struct mlx5e_priv { }; struct mlx5e_dev { - struct mlx5e_priv *priv; + struct net_device *netdev; struct devlink_port dl_port; }; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index 3850c267dfc02..dcf1cd3488709 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -6635,8 +6635,8 @@ static int _mlx5e_resume(struct auxiliary_device *adev) { struct mlx5_adev *edev = container_of(adev, struct mlx5_adev, adev); struct mlx5e_dev *mlx5e_dev = auxiliary_get_drvdata(adev); - struct mlx5e_priv *priv = mlx5e_dev->priv; - struct net_device *netdev = priv->netdev; + struct mlx5e_priv *priv = netdev_priv(mlx5e_dev->netdev); + struct net_device *netdev = mlx5e_dev->netdev; struct mlx5_core_dev *mdev = edev->mdev; struct mlx5_core_dev *pos, *to; int err, i; @@ -6682,10 +6682,11 @@ static int mlx5e_resume(struct auxiliary_device *adev) static int _mlx5e_suspend(struct auxiliary_device *adev, bool pre_netdev_reg) { + struct mlx5_adev *edev = container_of(adev, struct mlx5_adev, adev); struct mlx5e_dev *mlx5e_dev = auxiliary_get_drvdata(adev); - struct mlx5e_priv *priv = mlx5e_dev->priv; - struct net_device *netdev = priv->netdev; - struct mlx5_core_dev *mdev = priv->mdev; + struct mlx5e_priv *priv = netdev_priv(mlx5e_dev->netdev); + struct net_device *netdev = mlx5e_dev->netdev; + struct mlx5_core_dev *mdev = edev->mdev; struct mlx5_core_dev *pos; int i; @@ -6746,11 +6747,11 @@ static int _mlx5e_probe(struct auxiliary_device *adev) goto err_devlink_port_unregister; } SET_NETDEV_DEVLINK_PORT(netdev, &mlx5e_dev->dl_port); + mlx5e_dev->netdev = netdev; mlx5e_build_nic_netdev(netdev); priv = netdev_priv(netdev); - mlx5e_dev->priv = priv; priv->profile = profile; priv->ppriv = NULL; @@ -6813,7 +6814,8 @@ static void _mlx5e_remove(struct auxiliary_device *adev) { struct mlx5_adev *edev = container_of(adev, struct mlx5_adev, adev); struct mlx5e_dev *mlx5e_dev = auxiliary_get_drvdata(adev); - struct mlx5e_priv *priv = mlx5e_dev->priv; + struct net_device *netdev = mlx5e_dev->netdev; + struct mlx5e_priv *priv = netdev_priv(netdev); struct mlx5_core_dev *mdev = edev->mdev; mlx5_core_uplink_netdev_set(mdev, NULL); @@ -6822,8 +6824,8 @@ static void _mlx5e_remove(struct auxiliary_device *adev) * if it's from legacy mode. If from switchdev mode, it * is already unregistered before changing to NIC profile. */ - if (priv->netdev->reg_state == NETREG_REGISTERED) { - unregister_netdev(priv->netdev); + if (netdev->reg_state == NETREG_REGISTERED) { + unregister_netdev(netdev); _mlx5e_suspend(adev, false); } else { struct mlx5_core_dev *pos; From 66a25f6b7c0bfd84e6d27b536f5d24116dbd52da Mon Sep 17 00:00:00 2001 From: Saeed Mahameed Date: Thu, 8 Jan 2026 13:26:56 -0800 Subject: [PATCH 1999/2333] net/mlx5e: Pass netdev to mlx5e_destroy_netdev instead of priv [ Upstream commit 4ef8512e1427111f7ba92b4a847d181ff0aeec42 ] mlx5e_priv is an unstable structure that can be memset(0) if profile attaching fails. Pass netdev to mlx5e_destroy_netdev() to guarantee it will work on a valid netdev. On mlx5e_remove: Check validity of priv->profile, before attempting to cleanup any resources that might be not there. This fixes a kernel oops in mlx5e_remove when switchdev mode fails due to change profile failure. $ devlink dev eswitch set pci/0000:00:03.0 mode switchdev Error: mlx5_core: Failed setting eswitch to offloads. dmesg: workqueue: Failed to create a rescuer kthread for wq "mlx5e": -EINTR mlx5_core 0012:03:00.1: mlx5e_netdev_init_profile:6214:(pid 37199): mlx5e_priv_init failed, err=-12 mlx5_core 0012:03:00.1 gpu3rdma1: mlx5e_netdev_change_profile: new profile init failed, -12 workqueue: Failed to create a rescuer kthread for wq "mlx5e": -EINTR mlx5_core 0012:03:00.1: mlx5e_netdev_init_profile:6214:(pid 37199): mlx5e_priv_init failed, err=-12 mlx5_core 0012:03:00.1 gpu3rdma1: mlx5e_netdev_change_profile: failed to rollback to orig profile, -12 $ devlink dev reload pci/0000:00:03.0 ==> oops BUG: kernel NULL pointer dereference, address: 0000000000000370 PGD 0 P4D 0 Oops: Oops: 0000 [#1] SMP NOPTI CPU: 15 UID: 0 PID: 520 Comm: devlink Not tainted 6.18.0-rc5+ #115 PREEMPT(voluntary) Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-2.fc40 04/01/2014 RIP: 0010:mlx5e_dcbnl_dscp_app+0x23/0x100 RSP: 0018:ffffc9000083f8b8 EFLAGS: 00010286 RAX: ffff8881126fc380 RBX: ffff8881015ac400 RCX: ffffffff826ffc45 RDX: 0000000000000000 RSI: 0000000000000001 RDI: ffff8881035109c0 RBP: ffff8881035109c0 R08: ffff888101e3e838 R09: ffff888100264e10 R10: ffffc9000083f898 R11: ffffc9000083f8a0 R12: ffff888101b921a0 R13: ffff888101b921a0 R14: ffff8881015ac9a0 R15: ffff8881015ac400 FS: 00007f789a3c8740(0000) GS:ffff88856aa59000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000370 CR3: 000000010b6c0001 CR4: 0000000000370ef0 Call Trace: mlx5e_remove+0x57/0x110 device_release_driver_internal+0x19c/0x200 bus_remove_device+0xc6/0x130 device_del+0x160/0x3d0 ? devl_param_driverinit_value_get+0x2d/0x90 mlx5_detach_device+0x89/0xe0 mlx5_unload_one_devl_locked+0x3a/0x70 mlx5_devlink_reload_down+0xc8/0x220 devlink_reload+0x7d/0x260 devlink_nl_reload_doit+0x45b/0x5a0 genl_family_rcv_msg_doit+0xe8/0x140 Fixes: c4d7eb57687f ("net/mxl5e: Add change profile method") Signed-off-by: Saeed Mahameed Reviewed-by: Shay Drori Reviewed-by: Tariq Toukan Link: https://patch.msgid.link/20260108212657.25090-4-saeed@kernel.org Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- drivers/net/ethernet/mellanox/mlx5/core/en.h | 2 +- drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 15 +++++++++------ drivers/net/ethernet/mellanox/mlx5/core/en_rep.c | 4 ++-- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h index bc1b343f89a25..b34b85539f3b1 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h @@ -1238,7 +1238,7 @@ struct net_device * mlx5e_create_netdev(struct mlx5_core_dev *mdev, const struct mlx5e_profile *profile); int mlx5e_attach_netdev(struct mlx5e_priv *priv); void mlx5e_detach_netdev(struct mlx5e_priv *priv); -void mlx5e_destroy_netdev(struct mlx5e_priv *priv); +void mlx5e_destroy_netdev(struct net_device *netdev); int mlx5e_netdev_change_profile(struct net_device *netdev, struct mlx5_core_dev *mdev, const struct mlx5e_profile *new_profile, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index dcf1cd3488709..3863fb40ff929 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -6623,11 +6623,12 @@ void mlx5e_netdev_attach_nic_profile(struct net_device *netdev, mlx5e_netdev_change_profile(netdev, mdev, &mlx5e_nic_profile, NULL); } -void mlx5e_destroy_netdev(struct mlx5e_priv *priv) +void mlx5e_destroy_netdev(struct net_device *netdev) { - struct net_device *netdev = priv->netdev; + struct mlx5e_priv *priv = netdev_priv(netdev); - mlx5e_priv_cleanup(priv); + if (priv->profile) + mlx5e_priv_cleanup(priv); free_netdev(netdev); } @@ -6784,7 +6785,7 @@ static int _mlx5e_probe(struct auxiliary_device *adev) err_profile_cleanup: profile->cleanup(priv); err_destroy_netdev: - mlx5e_destroy_netdev(priv); + mlx5e_destroy_netdev(netdev); err_devlink_port_unregister: mlx5e_devlink_port_unregister(mlx5e_dev); err_devlink_unregister: @@ -6819,7 +6820,9 @@ static void _mlx5e_remove(struct auxiliary_device *adev) struct mlx5_core_dev *mdev = edev->mdev; mlx5_core_uplink_netdev_set(mdev, NULL); - mlx5e_dcbnl_delete_app(priv); + + if (priv->profile) + mlx5e_dcbnl_delete_app(priv); /* When unload driver, the netdev is in registered state * if it's from legacy mode. If from switchdev mode, it * is already unregistered before changing to NIC profile. @@ -6840,7 +6843,7 @@ static void _mlx5e_remove(struct auxiliary_device *adev) /* Avoid cleanup if profile rollback failed. */ if (priv->profile) priv->profile->cleanup(priv); - mlx5e_destroy_netdev(priv); + mlx5e_destroy_netdev(netdev); mlx5e_devlink_port_unregister(mlx5e_dev); mlx5e_destroy_devlink(mlx5e_dev); } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c index 2f6aa5e61747c..8b65441246244 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c @@ -1611,7 +1611,7 @@ mlx5e_vport_vf_rep_load(struct mlx5_core_dev *dev, struct mlx5_eswitch_rep *rep) priv->profile->cleanup(priv); err_destroy_netdev: - mlx5e_destroy_netdev(netdev_priv(netdev)); + mlx5e_destroy_netdev(netdev); return err; } @@ -1666,7 +1666,7 @@ mlx5e_vport_rep_unload(struct mlx5_eswitch_rep *rep) mlx5e_rep_vnic_reporter_destroy(priv); mlx5e_detach_netdev(priv); priv->profile->cleanup(priv); - mlx5e_destroy_netdev(priv); + mlx5e_destroy_netdev(netdev); free_ppriv: kvfree(ppriv); /* mlx5e_rep_priv */ } From fcae8e1b9acd8756971fd5bbf1ec1365fd1f68e7 Mon Sep 17 00:00:00 2001 From: Saeed Mahameed Date: Thu, 8 Jan 2026 13:26:57 -0800 Subject: [PATCH 2000/2333] net/mlx5e: Restore destroying state bit after profile cleanup [ Upstream commit 5629f8859dca7ef74d7314b60de6a957f23166c0 ] Profile rollback can fail in mlx5e_netdev_change_profile() and we will end up with invalid mlx5e_priv memset to 0, we must maintain the 'destroying' bit in order to gracefully shutdown even if the profile/priv are not valid. This patch maintains the previous state of the 'destroying' state of mlx5e_priv after priv cleanup, to allow the remove flow to cleanup common resources from mlx5_core to avoid FW fatal errors as seen below: $ devlink dev eswitch set pci/0000:00:03.0 mode switchdev Error: mlx5_core: Failed setting eswitch to offloads. dmesg: mlx5_core 0000:00:03.0 enp0s3np0: failed to rollback to orig profile, ... $ devlink dev reload pci/0000:00:03.0 mlx5_core 0000:00:03.0: E-Switch: Disable: mode(LEGACY), nvfs(0), necvfs(0), active vports(0) mlx5_core 0000:00:03.0: poll_health:803:(pid 519): Fatal error 3 detected mlx5_core 0000:00:03.0: firmware version: 28.41.1000 mlx5_core 0000:00:03.0: 0.000 Gb/s available PCIe bandwidth (Unknown x255 link) mlx5_core 0000:00:03.0: mlx5_function_enable:1200:(pid 519): enable hca failed mlx5_core 0000:00:03.0: mlx5_function_enable:1200:(pid 519): enable hca failed mlx5_core 0000:00:03.0: mlx5_health_try_recover:340:(pid 141): handling bad device here mlx5_core 0000:00:03.0: mlx5_handle_bad_state:285:(pid 141): Expected to see disabled NIC but it is full driver mlx5_core 0000:00:03.0: mlx5_error_sw_reset:236:(pid 141): start mlx5_core 0000:00:03.0: NIC IFC still 0 after 4000ms. Fixes: c4d7eb57687f ("net/mxl5e: Add change profile method") Signed-off-by: Saeed Mahameed Reviewed-by: Tariq Toukan Link: https://patch.msgid.link/20260108212657.25090-5-saeed@kernel.org Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index 3863fb40ff929..f8d9968542d9c 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -6305,6 +6305,7 @@ int mlx5e_priv_init(struct mlx5e_priv *priv, void mlx5e_priv_cleanup(struct mlx5e_priv *priv) { + bool destroying = test_bit(MLX5E_STATE_DESTROYING, &priv->state); int i; /* bail if change profile failed and also rollback failed */ @@ -6332,6 +6333,8 @@ void mlx5e_priv_cleanup(struct mlx5e_priv *priv) } memset(priv, 0, sizeof(*priv)); + if (destroying) /* restore destroying bit, to allow unload */ + set_bit(MLX5E_STATE_DESTROYING, &priv->state); } static unsigned int mlx5e_get_max_num_txqs(struct mlx5_core_dev *mdev, From 6cb008f1bb23e023dfe615cca5df14570dfc8da5 Mon Sep 17 00:00:00 2001 From: Jiasheng Jiang Date: Sun, 11 Jan 2026 19:20:37 +0000 Subject: [PATCH 2001/2333] btrfs: fix memory leaks in create_space_info() error paths [ Upstream commit a11224a016d6d1d46a4d9b6573244448a80d4d7f ] In create_space_info(), the 'space_info' object is allocated at the beginning of the function. However, there are two error paths where the function returns an error code without freeing the allocated memory: 1. When create_space_info_sub_group() fails in zoned mode. 2. When btrfs_sysfs_add_space_info_type() fails. In both cases, 'space_info' has not yet been added to the fs_info->space_info list, resulting in a memory leak. Fix this by adding an error handling label to kfree(space_info) before returning. Fixes: 2be12ef79fe9 ("btrfs: Separate space_info create/update") Reviewed-by: Qu Wenruo Signed-off-by: Jiasheng Jiang Signed-off-by: David Sterba Signed-off-by: Sasha Levin --- fs/btrfs/space-info.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/fs/btrfs/space-info.c b/fs/btrfs/space-info.c index 85c466c85910a..a6f94e9f55915 100644 --- a/fs/btrfs/space-info.c +++ b/fs/btrfs/space-info.c @@ -305,18 +305,22 @@ static int create_space_info(struct btrfs_fs_info *info, u64 flags) 0); if (ret) - return ret; + goto out_free; } ret = btrfs_sysfs_add_space_info_type(info, space_info); if (ret) - return ret; + goto out_free; list_add(&space_info->list, &info->space_info); if (flags & BTRFS_BLOCK_GROUP_DATA) info->data_sinfo = space_info; return ret; + +out_free: + kfree(space_info); + return ret; } int btrfs_init_space_info(struct btrfs_fs_info *fs_info) From 1b3ed6c512cfd49a46977eccd82c5cc1add0e626 Mon Sep 17 00:00:00 2001 From: Li Ming Date: Mon, 12 Jan 2026 20:05:26 +0800 Subject: [PATCH 2002/2333] cxl/hdm: Fix potential infinite loop in __cxl_dpa_reserve() [ Upstream commit d4026a44626490dc4eca4dd2c4d0816338fa179b ] In __cxl_dpa_reserve(), it will check if the new resource range is included in one of paritions of the cxl memory device. cxlds->nr_paritions is used to represent how many partitions information the cxl memory device has. In the loop, if driver cannot find a partition including the new resource range, it will be an infinite loop. [ dj: Removed incorrect fixes tag ] Fixes: 991d98f17d31 ("cxl: Make cxl_dpa_alloc() DPA partition number agnostic") Signed-off-by: Li Ming Reviewed-by: Ira Weiny Reviewed-by: Dave Jiang Link: https://patch.msgid.link/20260112120526.530232-1-ming.li@zohomail.com Signed-off-by: Dave Jiang Signed-off-by: Sasha Levin --- drivers/cxl/core/hdm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/cxl/core/hdm.c b/drivers/cxl/core/hdm.c index d3a094ca01ad9..20dd638108062 100644 --- a/drivers/cxl/core/hdm.c +++ b/drivers/cxl/core/hdm.c @@ -403,7 +403,7 @@ static int __cxl_dpa_reserve(struct cxl_endpoint_decoder *cxled, * is not set. */ if (cxled->part < 0) - for (int i = 0; cxlds->nr_partitions; i++) + for (int i = 0; i < cxlds->nr_partitions; i++) if (resource_contains(&cxlds->part[i].res, res)) { cxled->part = i; break; From aa4c066229b05fc3d3c5f42693d25b1828533b6e Mon Sep 17 00:00:00 2001 From: Kery Qi Date: Fri, 9 Jan 2026 00:42:57 +0800 Subject: [PATCH 2003/2333] net: octeon_ep_vf: fix free_irq dev_id mismatch in IRQ rollback [ Upstream commit f93fc5d12d69012788f82151bee55fce937e1432 ] octep_vf_request_irqs() requests MSI-X queue IRQs with dev_id set to ioq_vector. If request_irq() fails part-way, the rollback loop calls free_irq() with dev_id set to 'oct', which does not match the original dev_id and may leave the irqaction registered. This can keep IRQ handlers alive while ioq_vector is later freed during unwind/teardown, leading to a use-after-free or crash when an interrupt fires. Fix the error path to free IRQs with the same ioq_vector dev_id used during request_irq(). Fixes: 1cd3b407977c ("octeon_ep_vf: add Tx/Rx processing and interrupt support") Signed-off-by: Kery Qi Link: https://patch.msgid.link/20260108164256.1749-2-qikeyu2017@gmail.com Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_main.c b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_main.c index 420c3f4cf7417..1d9760b4b8f47 100644 --- a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_main.c +++ b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_main.c @@ -218,7 +218,7 @@ static int octep_vf_request_irqs(struct octep_vf_device *oct) ioq_irq_err: while (i) { --i; - free_irq(oct->msix_entries[i].vector, oct); + free_irq(oct->msix_entries[i].vector, oct->ioq_vector[i]); } return -1; } From d4416963970880139b31ac25a955b58cd54f4b95 Mon Sep 17 00:00:00 2001 From: Jijie Shao Date: Thu, 8 Jan 2026 15:14:09 +0800 Subject: [PATCH 2004/2333] net: phy: motorcomm: fix duplex setting error for phy leds [ Upstream commit e02f2a0f1f9b6d4f0c620de2ce037d4436b58f70 ] fix duplex setting error for phy leds Fixes: 355b82c54c12 ("net: phy: motorcomm: Add support for PHY LEDs on YT8521") Signed-off-by: Jijie Shao Reviewed-by: Andrew Lunn Link: https://patch.msgid.link/20260108071409.2750607-1-shaojijie@huawei.com Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- drivers/net/phy/motorcomm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/phy/motorcomm.c b/drivers/net/phy/motorcomm.c index a3593e6630594..b49897500a592 100644 --- a/drivers/net/phy/motorcomm.c +++ b/drivers/net/phy/motorcomm.c @@ -1741,10 +1741,10 @@ static int yt8521_led_hw_control_set(struct phy_device *phydev, u8 index, val |= YT8521_LED_1000_ON_EN; if (test_bit(TRIGGER_NETDEV_FULL_DUPLEX, &rules)) - val |= YT8521_LED_HDX_ON_EN; + val |= YT8521_LED_FDX_ON_EN; if (test_bit(TRIGGER_NETDEV_HALF_DUPLEX, &rules)) - val |= YT8521_LED_FDX_ON_EN; + val |= YT8521_LED_HDX_ON_EN; if (test_bit(TRIGGER_NETDEV_TX, &rules) || test_bit(TRIGGER_NETDEV_RX, &rules)) From e1a4a4795c5a1214b32d3b75b454a41f943d7764 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 9 Jan 2026 10:29:06 +0100 Subject: [PATCH 2005/2333] net: airoha: Fix typo in airoha_ppe_setup_tc_block_cb definition [ Upstream commit dfdf774656205515b2d6ad94fce63c7ccbe92d91 ] Fix Typo in airoha_ppe_dev_setup_tc_block_cb routine definition when CONFIG_NET_AIROHA is not enabled. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202601090517.Fj6v501r-lkp@intel.com/ Fixes: f45fc18b6de04 ("net: airoha: Add airoha_ppe_dev struct definition") Signed-off-by: Lorenzo Bianconi Link: https://patch.msgid.link/20260109-airoha_ppe_dev_setup_tc_block_cb-typo-v1-1-282e8834a9f9@kernel.org Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- include/linux/soc/airoha/airoha_offload.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/linux/soc/airoha/airoha_offload.h b/include/linux/soc/airoha/airoha_offload.h index 1a33f846afafa..0e82f1f4d36c4 100644 --- a/include/linux/soc/airoha/airoha_offload.h +++ b/include/linux/soc/airoha/airoha_offload.h @@ -51,8 +51,8 @@ static inline void airoha_ppe_put_dev(struct airoha_ppe_dev *dev) { } -static inline int airoha_ppe_setup_tc_block_cb(struct airoha_ppe_dev *dev, - void *type_data) +static inline int airoha_ppe_dev_setup_tc_block_cb(struct airoha_ppe_dev *dev, + void *type_data) { return -EOPNOTSUPP; } From aaa969ffe3b4da17c96c54d7c88ea838d99cf10e Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Tue, 13 Jan 2026 13:09:54 +0000 Subject: [PATCH 2006/2333] ALSA: hda/cirrus_scodec_test: Fix incorrect setup of gpiochip [ Upstream commit c5e96e54eca3876d4ce8857e2e22adbe9f44f4a2 ] Set gpiochip parent to the struct device of the dummy GPIO driver so that the software node will be associated with the GPIO chip. The recent commit e5d527be7e698 ("gpio: swnode: don't use the swnode's name as the key for GPIO lookup") broke cirrus_scodec_test, because the software node no longer gets associated with the GPIO driver by name. Instead, setting struct gpio_chip.parent to the owning struct device will find the node using a normal fwnode lookup. Signed-off-by: Richard Fitzgerald Fixes: 2144833e7b414 ("ALSA: hda: cirrus_scodec: Add KUnit test") Link: https://patch.msgid.link/20260113130954.574670-1-rf@opensource.cirrus.com Signed-off-by: Takashi Iwai Signed-off-by: Sasha Levin --- sound/hda/codecs/side-codecs/cirrus_scodec_test.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/hda/codecs/side-codecs/cirrus_scodec_test.c b/sound/hda/codecs/side-codecs/cirrus_scodec_test.c index 3cca750857b68..159ac80a93144 100644 --- a/sound/hda/codecs/side-codecs/cirrus_scodec_test.c +++ b/sound/hda/codecs/side-codecs/cirrus_scodec_test.c @@ -103,6 +103,7 @@ static int cirrus_scodec_test_gpio_probe(struct platform_device *pdev) /* GPIO core modifies our struct gpio_chip so use a copy */ gpio_priv->chip = cirrus_scodec_test_gpio_chip; + gpio_priv->chip.parent = &pdev->dev; ret = devm_gpiochip_add_data(&pdev->dev, &gpio_priv->chip, gpio_priv); if (ret) return dev_err_probe(&pdev->dev, ret, "Failed to add gpiochip\n"); From 78ee2958b096c36b5c8b501f758b06ed64dd47ab Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Tue, 13 Jan 2026 13:40:56 +0000 Subject: [PATCH 2007/2333] ALSA: hda/cirrus_scodec_test: Fix test suite name [ Upstream commit 6a0243c4020636482797acfd48d7d9b0ea2f2a20 ] Change the test suite name string to "snd-hda-cirrus-scodec-test". It was incorrectly named "snd-hda-scodec-cs35l56-test", a leftover from when the code under test was actually in the cs35l56 driver. Signed-off-by: Richard Fitzgerald Fixes: 2144833e7b414 ("ALSA: hda: cirrus_scodec: Add KUnit test") Link: https://patch.msgid.link/20260113134056.619051-1-rf@opensource.cirrus.com Signed-off-by: Takashi Iwai Signed-off-by: Sasha Levin --- sound/hda/codecs/side-codecs/cirrus_scodec_test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/hda/codecs/side-codecs/cirrus_scodec_test.c b/sound/hda/codecs/side-codecs/cirrus_scodec_test.c index 159ac80a93144..dc35932b6b22f 100644 --- a/sound/hda/codecs/side-codecs/cirrus_scodec_test.c +++ b/sound/hda/codecs/side-codecs/cirrus_scodec_test.c @@ -320,7 +320,7 @@ static struct kunit_case cirrus_scodec_test_cases[] = { }; static struct kunit_suite cirrus_scodec_test_suite = { - .name = "snd-hda-scodec-cs35l56-test", + .name = "snd-hda-cirrus-scodec-test", .init = cirrus_scodec_test_case_init, .test_cases = cirrus_scodec_test_cases, }; From 11dd9a9ef4dc4507a15a69b8511a0013c6c28fa3 Mon Sep 17 00:00:00 2001 From: Aditya Garg Date: Mon, 12 Jan 2026 02:01:33 -0800 Subject: [PATCH 2008/2333] net: hv_netvsc: reject RSS hash key programming without RX indirection table [ Upstream commit d23564955811da493f34412d7de60fa268c8cb50 ] RSS configuration requires a valid RX indirection table. When the device reports a single receive queue, rndis_filter_device_add() does not allocate an indirection table, accepting RSS hash key updates in this state leads to a hang. Fix this by gating netvsc_set_rxfh() on ndc->rx_table_sz and return -EOPNOTSUPP when the table is absent. This aligns set_rxfh with the device capabilities and prevents incorrect behavior. Fixes: 962f3fee83a4 ("netvsc: add ethtool ops to get/set RSS key") Signed-off-by: Aditya Garg Reviewed-by: Dipayaan Roy Reviewed-by: Haiyang Zhang Link: https://patch.msgid.link/1768212093-1594-1-git-send-email-gargaditya@linux.microsoft.com Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- drivers/net/hyperv/netvsc_drv.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index 39c892e46cb01..25a358524a096 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -1757,6 +1757,9 @@ static int netvsc_set_rxfh(struct net_device *dev, rxfh->hfunc != ETH_RSS_HASH_TOP) return -EOPNOTSUPP; + if (!ndc->rx_table_sz) + return -EOPNOTSUPP; + rndis_dev = ndev->extension; if (rxfh->indir) { for (i = 0; i < ndc->rx_table_sz; i++) From 722de945216144af7cd4d39bdeb936108d2595a7 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 12 Jan 2026 10:38:25 +0000 Subject: [PATCH 2009/2333] dst: fix races in rt6_uncached_list_del() and rt_del_uncached_list() [ Upstream commit 9a6f0c4d5796ab89b5a28a890ce542344d58bd69 ] syzbot was able to crash the kernel in rt6_uncached_list_flush_dev() in an interesting way [1] Crash happens in list_del_init()/INIT_LIST_HEAD() while writing list->prev, while the prior write on list->next went well. static inline void INIT_LIST_HEAD(struct list_head *list) { WRITE_ONCE(list->next, list); // This went well WRITE_ONCE(list->prev, list); // Crash, @list has been freed. } Issue here is that rt6_uncached_list_del() did not attempt to lock ul->lock, as list_empty(&rt->dst.rt_uncached) returned true because the WRITE_ONCE(list->next, list) happened on the other CPU. We might use list_del_init_careful() and list_empty_careful(), or make sure rt6_uncached_list_del() always grabs the spinlock whenever rt->dst.rt_uncached_list has been set. A similar fix is neeed for IPv4. [1] BUG: KASAN: slab-use-after-free in INIT_LIST_HEAD include/linux/list.h:46 [inline] BUG: KASAN: slab-use-after-free in list_del_init include/linux/list.h:296 [inline] BUG: KASAN: slab-use-after-free in rt6_uncached_list_flush_dev net/ipv6/route.c:191 [inline] BUG: KASAN: slab-use-after-free in rt6_disable_ip+0x633/0x730 net/ipv6/route.c:5020 Write of size 8 at addr ffff8880294cfa78 by task kworker/u8:14/3450 CPU: 0 UID: 0 PID: 3450 Comm: kworker/u8:14 Tainted: G L syzkaller #0 PREEMPT_{RT,(full)} Tainted: [L]=SOFTLOCKUP Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 10/25/2025 Workqueue: netns cleanup_net Call Trace: dump_stack_lvl+0xe8/0x150 lib/dump_stack.c:120 print_address_description mm/kasan/report.c:378 [inline] print_report+0xca/0x240 mm/kasan/report.c:482 kasan_report+0x118/0x150 mm/kasan/report.c:595 INIT_LIST_HEAD include/linux/list.h:46 [inline] list_del_init include/linux/list.h:296 [inline] rt6_uncached_list_flush_dev net/ipv6/route.c:191 [inline] rt6_disable_ip+0x633/0x730 net/ipv6/route.c:5020 addrconf_ifdown+0x143/0x18a0 net/ipv6/addrconf.c:3853 addrconf_notify+0x1bc/0x1050 net/ipv6/addrconf.c:-1 notifier_call_chain+0x19d/0x3a0 kernel/notifier.c:85 call_netdevice_notifiers_extack net/core/dev.c:2268 [inline] call_netdevice_notifiers net/core/dev.c:2282 [inline] netif_close_many+0x29c/0x410 net/core/dev.c:1785 unregister_netdevice_many_notify+0xb50/0x2330 net/core/dev.c:12353 ops_exit_rtnl_list net/core/net_namespace.c:187 [inline] ops_undo_list+0x3dc/0x990 net/core/net_namespace.c:248 cleanup_net+0x4de/0x7b0 net/core/net_namespace.c:696 process_one_work kernel/workqueue.c:3257 [inline] process_scheduled_works+0xad1/0x1770 kernel/workqueue.c:3340 worker_thread+0x8a0/0xda0 kernel/workqueue.c:3421 kthread+0x711/0x8a0 kernel/kthread.c:463 ret_from_fork+0x510/0xa50 arch/x86/kernel/process.c:158 ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:246 Allocated by task 803: kasan_save_stack mm/kasan/common.c:57 [inline] kasan_save_track+0x3e/0x80 mm/kasan/common.c:78 unpoison_slab_object mm/kasan/common.c:340 [inline] __kasan_slab_alloc+0x6c/0x80 mm/kasan/common.c:366 kasan_slab_alloc include/linux/kasan.h:253 [inline] slab_post_alloc_hook mm/slub.c:4953 [inline] slab_alloc_node mm/slub.c:5263 [inline] kmem_cache_alloc_noprof+0x18d/0x6c0 mm/slub.c:5270 dst_alloc+0x105/0x170 net/core/dst.c:89 ip6_dst_alloc net/ipv6/route.c:342 [inline] icmp6_dst_alloc+0x75/0x460 net/ipv6/route.c:3333 mld_sendpack+0x683/0xe60 net/ipv6/mcast.c:1844 mld_send_cr net/ipv6/mcast.c:2154 [inline] mld_ifc_work+0x83e/0xd60 net/ipv6/mcast.c:2693 process_one_work kernel/workqueue.c:3257 [inline] process_scheduled_works+0xad1/0x1770 kernel/workqueue.c:3340 worker_thread+0x8a0/0xda0 kernel/workqueue.c:3421 kthread+0x711/0x8a0 kernel/kthread.c:463 ret_from_fork+0x510/0xa50 arch/x86/kernel/process.c:158 ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:246 Freed by task 20: kasan_save_stack mm/kasan/common.c:57 [inline] kasan_save_track+0x3e/0x80 mm/kasan/common.c:78 kasan_save_free_info+0x46/0x50 mm/kasan/generic.c:584 poison_slab_object mm/kasan/common.c:253 [inline] __kasan_slab_free+0x5c/0x80 mm/kasan/common.c:285 kasan_slab_free include/linux/kasan.h:235 [inline] slab_free_hook mm/slub.c:2540 [inline] slab_free mm/slub.c:6670 [inline] kmem_cache_free+0x18f/0x8d0 mm/slub.c:6781 dst_destroy+0x235/0x350 net/core/dst.c:121 rcu_do_batch kernel/rcu/tree.c:2605 [inline] rcu_core kernel/rcu/tree.c:2857 [inline] rcu_cpu_kthread+0xba5/0x1af0 kernel/rcu/tree.c:2945 smpboot_thread_fn+0x542/0xa60 kernel/smpboot.c:160 kthread+0x711/0x8a0 kernel/kthread.c:463 ret_from_fork+0x510/0xa50 arch/x86/kernel/process.c:158 ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:246 Last potentially related work creation: kasan_save_stack+0x3e/0x60 mm/kasan/common.c:57 kasan_record_aux_stack+0xbd/0xd0 mm/kasan/generic.c:556 __call_rcu_common kernel/rcu/tree.c:3119 [inline] call_rcu+0xee/0x890 kernel/rcu/tree.c:3239 refdst_drop include/net/dst.h:266 [inline] skb_dst_drop include/net/dst.h:278 [inline] skb_release_head_state+0x71/0x360 net/core/skbuff.c:1156 skb_release_all net/core/skbuff.c:1180 [inline] __kfree_skb net/core/skbuff.c:1196 [inline] sk_skb_reason_drop+0xe9/0x170 net/core/skbuff.c:1234 kfree_skb_reason include/linux/skbuff.h:1322 [inline] tcf_kfree_skb_list include/net/sch_generic.h:1127 [inline] __dev_xmit_skb net/core/dev.c:4260 [inline] __dev_queue_xmit+0x26aa/0x3210 net/core/dev.c:4785 NF_HOOK_COND include/linux/netfilter.h:307 [inline] ip6_output+0x340/0x550 net/ipv6/ip6_output.c:247 NF_HOOK+0x9e/0x380 include/linux/netfilter.h:318 mld_sendpack+0x8d4/0xe60 net/ipv6/mcast.c:1855 mld_send_cr net/ipv6/mcast.c:2154 [inline] mld_ifc_work+0x83e/0xd60 net/ipv6/mcast.c:2693 process_one_work kernel/workqueue.c:3257 [inline] process_scheduled_works+0xad1/0x1770 kernel/workqueue.c:3340 worker_thread+0x8a0/0xda0 kernel/workqueue.c:3421 kthread+0x711/0x8a0 kernel/kthread.c:463 ret_from_fork+0x510/0xa50 arch/x86/kernel/process.c:158 ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:246 The buggy address belongs to the object at ffff8880294cfa00 which belongs to the cache ip6_dst_cache of size 232 The buggy address is located 120 bytes inside of freed 232-byte region [ffff8880294cfa00, ffff8880294cfae8) The buggy address belongs to the physical page: page: refcount:0 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x294cf memcg:ffff88803536b781 flags: 0x80000000000000(node=0|zone=1) page_type: f5(slab) raw: 0080000000000000 ffff88802ff1c8c0 ffffea0000bf2bc0 dead000000000006 raw: 0000000000000000 00000000800c000c 00000000f5000000 ffff88803536b781 page dumped because: kasan: bad access detected page_owner tracks the page as allocated page last allocated via order 0, migratetype Unmovable, gfp_mask 0x52820(GFP_ATOMIC|__GFP_NOWARN|__GFP_NORETRY|__GFP_COMP), pid 9, tgid 9 (kworker/0:0), ts 91119585830, free_ts 91088628818 set_page_owner include/linux/page_owner.h:32 [inline] post_alloc_hook+0x234/0x290 mm/page_alloc.c:1857 prep_new_page mm/page_alloc.c:1865 [inline] get_page_from_freelist+0x28c0/0x2960 mm/page_alloc.c:3915 __alloc_frozen_pages_noprof+0x181/0x370 mm/page_alloc.c:5210 alloc_pages_mpol+0xd1/0x380 mm/mempolicy.c:2486 alloc_slab_page mm/slub.c:3075 [inline] allocate_slab+0x86/0x3b0 mm/slub.c:3248 new_slab mm/slub.c:3302 [inline] ___slab_alloc+0xb10/0x13e0 mm/slub.c:4656 __slab_alloc+0xc6/0x1f0 mm/slub.c:4779 __slab_alloc_node mm/slub.c:4855 [inline] slab_alloc_node mm/slub.c:5251 [inline] kmem_cache_alloc_noprof+0x101/0x6c0 mm/slub.c:5270 dst_alloc+0x105/0x170 net/core/dst.c:89 ip6_dst_alloc net/ipv6/route.c:342 [inline] icmp6_dst_alloc+0x75/0x460 net/ipv6/route.c:3333 mld_sendpack+0x683/0xe60 net/ipv6/mcast.c:1844 mld_send_cr net/ipv6/mcast.c:2154 [inline] mld_ifc_work+0x83e/0xd60 net/ipv6/mcast.c:2693 process_one_work kernel/workqueue.c:3257 [inline] process_scheduled_works+0xad1/0x1770 kernel/workqueue.c:3340 worker_thread+0x8a0/0xda0 kernel/workqueue.c:3421 kthread+0x711/0x8a0 kernel/kthread.c:463 ret_from_fork+0x510/0xa50 arch/x86/kernel/process.c:158 page last free pid 5859 tgid 5859 stack trace: reset_page_owner include/linux/page_owner.h:25 [inline] free_pages_prepare mm/page_alloc.c:1406 [inline] __free_frozen_pages+0xfe1/0x1170 mm/page_alloc.c:2943 discard_slab mm/slub.c:3346 [inline] __put_partials+0x149/0x170 mm/slub.c:3886 __slab_free+0x2af/0x330 mm/slub.c:5952 qlink_free mm/kasan/quarantine.c:163 [inline] qlist_free_all+0x97/0x100 mm/kasan/quarantine.c:179 kasan_quarantine_reduce+0x148/0x160 mm/kasan/quarantine.c:286 __kasan_slab_alloc+0x22/0x80 mm/kasan/common.c:350 kasan_slab_alloc include/linux/kasan.h:253 [inline] slab_post_alloc_hook mm/slub.c:4953 [inline] slab_alloc_node mm/slub.c:5263 [inline] kmem_cache_alloc_noprof+0x18d/0x6c0 mm/slub.c:5270 getname_flags+0xb8/0x540 fs/namei.c:146 getname include/linux/fs.h:2498 [inline] do_sys_openat2+0xbc/0x200 fs/open.c:1426 do_sys_open fs/open.c:1436 [inline] __do_sys_openat fs/open.c:1452 [inline] __se_sys_openat fs/open.c:1447 [inline] __x64_sys_openat+0x138/0x170 fs/open.c:1447 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] do_syscall_64+0xec/0xf80 arch/x86/entry/syscall_64.c:94 Fixes: 8d0b94afdca8 ("ipv6: Keep track of DST_NOCACHE routes in case of iface down/unregister") Fixes: 78df76a065ae ("ipv4: take rt_uncached_lock only if needed") Reported-by: syzbot+179fc225724092b8b2b2@syzkaller.appspotmail.com Closes: https://lore.kernel.org/netdev/6964cdf2.050a0220.eaf7.009d.GAE@google.com/T/#u Signed-off-by: Eric Dumazet Cc: Martin KaFai Lau Reviewed-by: David Ahern Link: https://patch.msgid.link/20260112103825.3810713-1-edumazet@google.com Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- net/core/dst.c | 1 + net/ipv4/route.c | 4 ++-- net/ipv6/route.c | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/net/core/dst.c b/net/core/dst.c index e9d35f49c9e78..1dae26c51ebec 100644 --- a/net/core/dst.c +++ b/net/core/dst.c @@ -68,6 +68,7 @@ void dst_init(struct dst_entry *dst, struct dst_ops *ops, dst->lwtstate = NULL; rcuref_init(&dst->__rcuref, 1); INIT_LIST_HEAD(&dst->rt_uncached); + dst->rt_uncached_list = NULL; dst->__use = 0; dst->lastuse = jiffies; dst->flags = flags; diff --git a/net/ipv4/route.c b/net/ipv4/route.c index b549d6a573073..11d990703d31a 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -1537,9 +1537,9 @@ void rt_add_uncached_list(struct rtable *rt) void rt_del_uncached_list(struct rtable *rt) { - if (!list_empty(&rt->dst.rt_uncached)) { - struct uncached_list *ul = rt->dst.rt_uncached_list; + struct uncached_list *ul = rt->dst.rt_uncached_list; + if (ul) { spin_lock_bh(&ul->lock); list_del_init(&rt->dst.rt_uncached); spin_unlock_bh(&ul->lock); diff --git a/net/ipv6/route.c b/net/ipv6/route.c index a3e051dc66ee0..e3a260a5564ba 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -148,9 +148,9 @@ void rt6_uncached_list_add(struct rt6_info *rt) void rt6_uncached_list_del(struct rt6_info *rt) { - if (!list_empty(&rt->dst.rt_uncached)) { - struct uncached_list *ul = rt->dst.rt_uncached_list; + struct uncached_list *ul = rt->dst.rt_uncached_list; + if (ul) { spin_lock_bh(&ul->lock); list_del_init(&rt->dst.rt_uncached); spin_unlock_bh(&ul->lock); From 8b6dcb565e419846bd521e31d5e1f98e4d0e1179 Mon Sep 17 00:00:00 2001 From: Kuniyuki Iwashima Date: Tue, 13 Jan 2026 01:05:08 +0000 Subject: [PATCH 2010/2333] ipv6: Fix use-after-free in inet6_addr_del(). [ Upstream commit ddf96c393a33aef4887e2e406c76c2f8cda1419c ] syzbot reported use-after-free of inet6_ifaddr in inet6_addr_del(). [0] The cited commit accidentally moved ipv6_del_addr() for mngtmpaddr before reading its ifp->flags for temporary addresses in inet6_addr_del(). Let's move ipv6_del_addr() down to fix the UAF. [0]: BUG: KASAN: slab-use-after-free in inet6_addr_del.constprop.0+0x67a/0x6b0 net/ipv6/addrconf.c:3117 Read of size 4 at addr ffff88807b89c86c by task syz.3.1618/9593 CPU: 0 UID: 0 PID: 9593 Comm: syz.3.1618 Not tainted syzkaller #0 PREEMPT(full) Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 10/25/2025 Call Trace: __dump_stack lib/dump_stack.c:94 [inline] dump_stack_lvl+0x116/0x1f0 lib/dump_stack.c:120 print_address_description mm/kasan/report.c:378 [inline] print_report+0xcd/0x630 mm/kasan/report.c:482 kasan_report+0xe0/0x110 mm/kasan/report.c:595 inet6_addr_del.constprop.0+0x67a/0x6b0 net/ipv6/addrconf.c:3117 addrconf_del_ifaddr+0x11e/0x190 net/ipv6/addrconf.c:3181 inet6_ioctl+0x1e5/0x2b0 net/ipv6/af_inet6.c:582 sock_do_ioctl+0x118/0x280 net/socket.c:1254 sock_ioctl+0x227/0x6b0 net/socket.c:1375 vfs_ioctl fs/ioctl.c:51 [inline] __do_sys_ioctl fs/ioctl.c:597 [inline] __se_sys_ioctl fs/ioctl.c:583 [inline] __x64_sys_ioctl+0x18e/0x210 fs/ioctl.c:583 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] do_syscall_64+0xcd/0xf80 arch/x86/entry/syscall_64.c:94 entry_SYSCALL_64_after_hwframe+0x77/0x7f RIP: 0033:0x7f164cf8f749 Code: ff ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 40 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 a8 ff ff ff f7 d8 64 89 01 48 RSP: 002b:00007f164de64038 EFLAGS: 00000246 ORIG_RAX: 0000000000000010 RAX: ffffffffffffffda RBX: 00007f164d1e5fa0 RCX: 00007f164cf8f749 RDX: 0000200000000000 RSI: 0000000000008936 RDI: 0000000000000003 RBP: 00007f164d013f91 R08: 0000000000000000 R09: 0000000000000000 R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000 R13: 00007f164d1e6038 R14: 00007f164d1e5fa0 R15: 00007ffde15c8288 Allocated by task 9593: kasan_save_stack+0x33/0x60 mm/kasan/common.c:56 kasan_save_track+0x14/0x30 mm/kasan/common.c:77 poison_kmalloc_redzone mm/kasan/common.c:397 [inline] __kasan_kmalloc+0xaa/0xb0 mm/kasan/common.c:414 kmalloc_noprof include/linux/slab.h:957 [inline] kzalloc_noprof include/linux/slab.h:1094 [inline] ipv6_add_addr+0x4e3/0x2010 net/ipv6/addrconf.c:1120 inet6_addr_add+0x256/0x9b0 net/ipv6/addrconf.c:3050 addrconf_add_ifaddr+0x1fc/0x450 net/ipv6/addrconf.c:3160 inet6_ioctl+0x103/0x2b0 net/ipv6/af_inet6.c:580 sock_do_ioctl+0x118/0x280 net/socket.c:1254 sock_ioctl+0x227/0x6b0 net/socket.c:1375 vfs_ioctl fs/ioctl.c:51 [inline] __do_sys_ioctl fs/ioctl.c:597 [inline] __se_sys_ioctl fs/ioctl.c:583 [inline] __x64_sys_ioctl+0x18e/0x210 fs/ioctl.c:583 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] do_syscall_64+0xcd/0xf80 arch/x86/entry/syscall_64.c:94 entry_SYSCALL_64_after_hwframe+0x77/0x7f Freed by task 6099: kasan_save_stack+0x33/0x60 mm/kasan/common.c:56 kasan_save_track+0x14/0x30 mm/kasan/common.c:77 kasan_save_free_info+0x3b/0x60 mm/kasan/generic.c:584 poison_slab_object mm/kasan/common.c:252 [inline] __kasan_slab_free+0x5f/0x80 mm/kasan/common.c:284 kasan_slab_free include/linux/kasan.h:234 [inline] slab_free_hook mm/slub.c:2540 [inline] slab_free_freelist_hook mm/slub.c:2569 [inline] slab_free_bulk mm/slub.c:6696 [inline] kmem_cache_free_bulk mm/slub.c:7383 [inline] kmem_cache_free_bulk+0x2bf/0x680 mm/slub.c:7362 kfree_bulk include/linux/slab.h:830 [inline] kvfree_rcu_bulk+0x1b7/0x1e0 mm/slab_common.c:1523 kvfree_rcu_drain_ready mm/slab_common.c:1728 [inline] kfree_rcu_monitor+0x1d0/0x2f0 mm/slab_common.c:1801 process_one_work+0x9ba/0x1b20 kernel/workqueue.c:3257 process_scheduled_works kernel/workqueue.c:3340 [inline] worker_thread+0x6c8/0xf10 kernel/workqueue.c:3421 kthread+0x3c5/0x780 kernel/kthread.c:463 ret_from_fork+0x983/0xb10 arch/x86/kernel/process.c:158 ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:246 Fixes: 00b5b7aab9e42 ("net/ipv6: delete temporary address if mngtmpaddr is removed or unmanaged") Reported-by: syzbot+72e610f4f1a930ca9d8a@syzkaller.appspotmail.com Closes: https://lore.kernel.org/netdev/696598e9.050a0220.3be5c5.0009.GAE@google.com/ Signed-off-by: Kuniyuki Iwashima Reviewed-by: Hangbin Liu Reviewed-by: Eric Dumazet Link: https://patch.msgid.link/20260113010538.2019411-1-kuniyu@google.com Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- net/ipv6/addrconf.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 40e9c336f6c55..cad5e4ab8c3db 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -3112,12 +3112,12 @@ static int inet6_addr_del(struct net *net, int ifindex, u32 ifa_flags, in6_ifa_hold(ifp); read_unlock_bh(&idev->lock); - ipv6_del_addr(ifp); - if (!(ifp->flags & IFA_F_TEMPORARY) && (ifp->flags & IFA_F_MANAGETEMPADDR)) delete_tempaddrs(idev, ifp); + ipv6_del_addr(ifp); + addrconf_verify_rtnl(net); if (ipv6_addr_is_multicast(pfx)) { ipv6_mc_config(net->ipv6.mc_autojoin_sk, From a3a4296d8b5b10135248c61e0c06c867c17d80e2 Mon Sep 17 00:00:00 2001 From: Gal Pressman Date: Mon, 12 Jan 2026 19:37:15 +0200 Subject: [PATCH 2011/2333] selftests: drv-net: fix RPS mask handling for high CPU numbers [ Upstream commit cf055f8c000445aa688c53a706ef4f580818eedb ] The RPS bitmask bounds check uses ~(RPS_MAX_CPUS - 1) which equals ~15 = 0xfff0, only allowing CPUs 0-3. Change the mask to ~((1UL << RPS_MAX_CPUS) - 1) = ~0xffff to allow CPUs 0-15. Fixes: 5ebfb4cc3048 ("selftests/net: toeplitz test") Reviewed-by: Nimrod Oren Signed-off-by: Gal Pressman Reviewed-by: Willem de Bruijn Link: https://patch.msgid.link/20260112173715.384843-3-gal@nvidia.com Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- tools/testing/selftests/net/toeplitz.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/net/toeplitz.c b/tools/testing/selftests/net/toeplitz.c index 9ba03164d73a6..5099157f01b9a 100644 --- a/tools/testing/selftests/net/toeplitz.c +++ b/tools/testing/selftests/net/toeplitz.c @@ -473,8 +473,8 @@ static void parse_rps_bitmap(const char *arg) bitmap = strtoul(arg, NULL, 0); - if (bitmap & ~(RPS_MAX_CPUS - 1)) - error(1, 0, "rps bitmap 0x%lx out of bounds 0..%lu", + if (bitmap & ~((1UL << RPS_MAX_CPUS) - 1)) + error(1, 0, "rps bitmap 0x%lx out of bounds, max cpu %lu", bitmap, RPS_MAX_CPUS - 1); for (i = 0; i < RPS_MAX_CPUS; i++) From e9d8f11652fa08c647bf7bba7dd8163241a332cd Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 12 Jan 2026 17:56:56 +0000 Subject: [PATCH 2012/2333] net/sched: sch_qfq: do not free existing class in qfq_change_class() [ Upstream commit 3879cffd9d07aa0377c4b8835c4f64b4fb24ac78 ] Fixes qfq_change_class() error case. cl->qdisc and cl should only be freed if a new class and qdisc were allocated, or we risk various UAF. Fixes: 462dbc9101ac ("pkt_sched: QFQ Plus: fair-queueing service at DRR cost") Reported-by: syzbot+07f3f38f723c335f106d@syzkaller.appspotmail.com Closes: https://lore.kernel.org/netdev/6965351d.050a0220.eaf7.00c5.GAE@google.com/T/#u Signed-off-by: Eric Dumazet Reviewed-by: Jamal Hadi Salim Link: https://patch.msgid.link/20260112175656.17605-1-edumazet@google.com Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- net/sched/sch_qfq.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/net/sched/sch_qfq.c b/net/sched/sch_qfq.c index a91a5bac8f737..9b16ad431028f 100644 --- a/net/sched/sch_qfq.c +++ b/net/sched/sch_qfq.c @@ -529,8 +529,10 @@ static int qfq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, return 0; destroy_class: - qdisc_put(cl->qdisc); - kfree(cl); + if (!existing) { + qdisc_put(cl->qdisc); + kfree(cl); + } return err; } From 07d6d21b85137c6dfc73ba92cf021f1e9f88c5a0 Mon Sep 17 00:00:00 2001 From: Cole Leavitt Date: Tue, 13 Jan 2026 19:55:18 -0700 Subject: [PATCH 2013/2333] ASoC: sdw_utils: cs42l43: Enable Headphone pin for LINEOUT jack type [ Upstream commit 390caeed0897fcac75f3c414dbdd85d593183d9c ] The CS42L43 codec's load detection can return different impedance values that map to either HEADPHONE or LINEOUT jack types. However, the soc_jack_pins array only maps SND_JACK_HEADPHONE to the "Headphone" DAPM pin, not SND_JACK_LINEOUT. When headphones are detected with an impedance that maps to LINEOUT (such as impedance value 0x2), the driver reports SND_JACK_LINEOUT. Since this doesn't match the jack pin mask, the "Headphone" DAPM pin is not activated, and no audio is routed to the headphone outputs. Fix by adding SND_JACK_LINEOUT to the Headphone pin mask, so that both headphone and line-out detection properly enable the headphone output path. This fixes no audio output on devices like the Lenovo ThinkPad P16 Gen 3 where headphones are detected with LINEOUT impedance. Fixes: d74bad3b7452 ("ASoC: intel: sof_sdw_cs42l43: Create separate jacks for hp and mic") Reviewed-by: Charles Keepax Signed-off-by: Cole Leavitt Link: https://patch.msgid.link/20260114025518.28519-1-cole@unwrap.rs Signed-off-by: Mark Brown Signed-off-by: Sasha Levin --- sound/soc/sdw_utils/soc_sdw_cs42l43.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sdw_utils/soc_sdw_cs42l43.c b/sound/soc/sdw_utils/soc_sdw_cs42l43.c index b415d45d520d0..3e8e2e3bdf7c5 100644 --- a/sound/soc/sdw_utils/soc_sdw_cs42l43.c +++ b/sound/soc/sdw_utils/soc_sdw_cs42l43.c @@ -44,7 +44,7 @@ static const struct snd_soc_dapm_route cs42l43_dmic_map[] = { static struct snd_soc_jack_pin soc_jack_pins[] = { { .pin = "Headphone", - .mask = SND_JACK_HEADPHONE, + .mask = SND_JACK_HEADPHONE | SND_JACK_LINEOUT, }, { .pin = "Headset Mic", From 53bd838ed5950cb18927e4b2e8ee841b7cb10929 Mon Sep 17 00:00:00 2001 From: Emil Svendsen Date: Tue, 13 Jan 2026 11:58:45 +0100 Subject: [PATCH 2014/2333] ASoC: tlv320adcx140: fix null pointer [ Upstream commit be7664c81d3129fc313ef62ff275fd3d33cfecd4 ] The "snd_soc_component" in "adcx140_priv" was only used once but never set. It was only used for reaching "dev" which is already present in "adcx140_priv". Fixes: 4e82971f7b55 ("ASoC: tlv320adcx140: Add a new kcontrol") Signed-off-by: Emil Svendsen Signed-off-by: Sascha Hauer Link: https://patch.msgid.link/20260113-sound-soc-codecs-tvl320adcx140-v4-2-8f7ecec525c8@pengutronix.de Signed-off-by: Mark Brown Signed-off-by: Sasha Levin --- sound/soc/codecs/tlv320adcx140.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sound/soc/codecs/tlv320adcx140.c b/sound/soc/codecs/tlv320adcx140.c index d594bf166c0e7..ccfec4c0c159a 100644 --- a/sound/soc/codecs/tlv320adcx140.c +++ b/sound/soc/codecs/tlv320adcx140.c @@ -23,7 +23,6 @@ #include "tlv320adcx140.h" struct adcx140_priv { - struct snd_soc_component *component; struct regulator *supply_areg; struct gpio_desc *gpio_reset; struct regmap *regmap; @@ -701,7 +700,6 @@ static void adcx140_pwr_ctrl(struct adcx140_priv *adcx140, bool power_state) { int pwr_ctrl = 0; int ret = 0; - struct snd_soc_component *component = adcx140->component; if (power_state) pwr_ctrl = ADCX140_PWR_CFG_ADC_PDZ | ADCX140_PWR_CFG_PLL_PDZ; @@ -713,7 +711,7 @@ static void adcx140_pwr_ctrl(struct adcx140_priv *adcx140, bool power_state) ret = regmap_write(adcx140->regmap, ADCX140_PHASE_CALIB, adcx140->phase_calib_on ? 0x00 : 0x40); if (ret) - dev_err(component->dev, "%s: register write error %d\n", + dev_err(adcx140->dev, "%s: register write error %d\n", __func__, ret); } From 7481e7b9d7366d92d17d29a41d2b96a7add007eb Mon Sep 17 00:00:00 2001 From: Emil Svendsen Date: Tue, 13 Jan 2026 11:58:47 +0100 Subject: [PATCH 2015/2333] ASoC: tlv320adcx140: fix word length [ Upstream commit 46378ab9fcb796dca46b51e10646f636e2c661f9 ] The word length is the physical width of the channel slots. So the hw_params would misconfigure when format width and physical width doesn't match. Like S24_LE which has data width of 24 bits but physical width of 32 bits. So if using asymmetric formats you will get a lot of noise. Fixes: 689c7655b50c5 ("ASoC: tlv320adcx140: Add the tlv320adcx140 codec driver family") Signed-off-by: Emil Svendsen Signed-off-by: Sascha Hauer Link: https://patch.msgid.link/20260113-sound-soc-codecs-tvl320adcx140-v4-4-8f7ecec525c8@pengutronix.de Signed-off-by: Mark Brown Signed-off-by: Sasha Levin --- sound/soc/codecs/tlv320adcx140.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/tlv320adcx140.c b/sound/soc/codecs/tlv320adcx140.c index ccfec4c0c159a..62d936c2838c9 100644 --- a/sound/soc/codecs/tlv320adcx140.c +++ b/sound/soc/codecs/tlv320adcx140.c @@ -727,7 +727,7 @@ static int adcx140_hw_params(struct snd_pcm_substream *substream, struct adcx140_priv *adcx140 = snd_soc_component_get_drvdata(component); u8 data = 0; - switch (params_width(params)) { + switch (params_physical_width(params)) { case 16: data = ADCX140_16_BIT_WORD; break; @@ -742,7 +742,7 @@ static int adcx140_hw_params(struct snd_pcm_substream *substream, break; default: dev_err(component->dev, "%s: Unsupported width %d\n", - __func__, params_width(params)); + __func__, params_physical_width(params)); return -EINVAL; } From a1aedf4053af7dad3772b94b057a7d1f5473055f Mon Sep 17 00:00:00 2001 From: Lu Yao Date: Tue, 6 Jan 2026 10:37:12 +0800 Subject: [PATCH 2016/2333] drm/amdgpu: fix drm panic null pointer when driver not support atomic [ Upstream commit 9cb6278b44c38899961b36d303d7b18b38be2a6e ] When driver not support atomic, fb using plane->fb rather than plane->state->fb. Fixes: fe151ed7af54 ("drm/amdgpu: add generic display panic helper code") Signed-off-by: Lu Yao Signed-off-by: Alex Deucher (cherry picked from commit 2f2a72de673513247cd6fae14e53f6c40c5841ef) Signed-off-by: Sasha Levin --- drivers/gpu/drm/amd/amdgpu/amdgpu_display.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c index 51bab32fd8c6f..2f416d12e2e7e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c @@ -1824,7 +1824,12 @@ int amdgpu_display_get_scanout_buffer(struct drm_plane *plane, struct drm_scanout_buffer *sb) { struct amdgpu_bo *abo; - struct drm_framebuffer *fb = plane->state->fb; + struct drm_framebuffer *fb; + + if (drm_drv_uses_atomic_modeset(plane->dev)) + fb = plane->state->fb; + else + fb = plane->fb; if (!fb) return -EINVAL; From e17e32903684e104566768be5a07a94301498b59 Mon Sep 17 00:00:00 2001 From: "Mario Limonciello (AMD)" Date: Sun, 14 Dec 2025 08:59:16 -0600 Subject: [PATCH 2017/2333] drm/amd/display: Show link name in PSR status message [ Upstream commit 0a1253ba5096f531eaaef40caa4c069da6ad48ae ] [Why] The PSR message was moved in commit 4321742c394e ("drm/amd/display: Move PSR support message into amdgpu_dm"). This message however shows for every single link without showing which link is which. This can send a confusing message to the user. [How] Add link name into the message. Fixes: 4321742c394e ("drm/amd/display: Move PSR support message into amdgpu_dm") Reviewed-by: Alex Hung Signed-off-by: Mario Limonciello (AMD) Signed-off-by: Matthew Stewart Tested-by: Dan Wheeler Signed-off-by: Alex Deucher (cherry picked from commit 99f77f6229c0766b980ae05affcf9f742d97de6a) Signed-off-by: Sasha Levin --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 7fe40bbba2658..f4381d44864f1 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -5545,7 +5545,8 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) if (psr_feature_enabled) { amdgpu_dm_set_psr_caps(link); - drm_info(adev_to_drm(adev), "PSR support %d, DC PSR ver %d, sink PSR ver %d DPCD caps 0x%x su_y_granularity %d\n", + drm_info(adev_to_drm(adev), "%s: PSR support %d, DC PSR ver %d, sink PSR ver %d DPCD caps 0x%x su_y_granularity %d\n", + aconnector->base.name, link->psr_settings.psr_feature_enabled, link->psr_settings.psr_version, link->dpcd_caps.psr_info.psr_version, From 226d5d24c7ce12df74fd1a9ebeacff043a75abed Mon Sep 17 00:00:00 2001 From: Yang Wang Date: Tue, 6 Jan 2026 14:42:40 +0800 Subject: [PATCH 2018/2333] drm/amd/pm: fix smu overdrive data type wrong issue on smu 14.0.2 [ Upstream commit 90dbc0bc2aa60021615969841fed06790c992bde ] resolving the issue of incorrect type definitions potentially causing calculation errors. Fixes: 54f7f3ca982a ("drm/amdgpu/swm14: Update power limit logic") Signed-off-by: Yang Wang Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher (cherry picked from commit e3a03d0ae16d6b56e893cce8e52b44140e1ed985) Signed-off-by: Sasha Levin --- drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c index 086501cc5213b..e735da7ab6126 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c @@ -1701,8 +1701,9 @@ static int smu_v14_0_2_get_power_limit(struct smu_context *smu, table_context->power_play_table; PPTable_t *pptable = table_context->driver_pptable; CustomSkuTable_t *skutable = &pptable->CustomSkuTable; - uint32_t power_limit, od_percent_upper = 0, od_percent_lower = 0; + int16_t od_percent_upper = 0, od_percent_lower = 0; uint32_t msg_limit = pptable->SkuTable.MsgLimits.Power[PPT_THROTTLER_PPT0][POWER_SOURCE_AC]; + uint32_t power_limit; if (smu_v14_0_get_current_power_limit(smu, &power_limit)) power_limit = smu->adev->pm.ac_power ? From 3d05c5e1015212ca663561dc91f608ceb612ac8c Mon Sep 17 00:00:00 2001 From: Harish Kasiviswanathan Date: Sun, 11 Jan 2026 16:53:18 -0500 Subject: [PATCH 2019/2333] drm/amdkfd: No need to suspend whole MES to evict process [ Upstream commit 18dbcfb46f692e665c3fe3eee804e56c4eae53d6 ] Each queue of the process is individually removed and there is not need to suspend whole mes. Suspending mes stops kernel mode queues also causing unnecessary timeouts when running mixed work loads Fixes: 079ae5118e1f ("drm/amdkfd: fix suspend/resume all calls in mes based eviction path") Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/4765 Signed-off-by: Harish Kasiviswanathan Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher (cherry picked from commit 3fd20580b96a6e9da65b94ac3b58ee288239b731) Signed-off-by: Sasha Levin --- .../gpu/drm/amd/amdkfd/kfd_device_queue_manager.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c index 6e7bc983fc0b6..36fb3db16572a 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c @@ -1209,14 +1209,8 @@ static int evict_process_queues_cpsch(struct device_queue_manager *dqm, pr_debug_ratelimited("Evicting process pid %d queues\n", pdd->process->lead_thread->pid); - if (dqm->dev->kfd->shared_resources.enable_mes) { + if (dqm->dev->kfd->shared_resources.enable_mes) pdd->last_evict_timestamp = get_jiffies_64(); - retval = suspend_all_queues_mes(dqm); - if (retval) { - dev_err(dev, "Suspending all queues failed"); - goto out; - } - } /* Mark all queues as evicted. Deactivate all active queues on * the qpd. @@ -1246,10 +1240,6 @@ static int evict_process_queues_cpsch(struct device_queue_manager *dqm, KFD_UNMAP_QUEUES_FILTER_ALL_QUEUES : KFD_UNMAP_QUEUES_FILTER_DYNAMIC_QUEUES, 0, USE_DEFAULT_GRACE_PERIOD); - } else { - retval = resume_all_queues_mes(dqm); - if (retval) - dev_err(dev, "Resuming all queues failed"); } out: From e1a30e1ab33fc522785d04bbf7e1b13a5c5c9175 Mon Sep 17 00:00:00 2001 From: Srinivasan Shanmugam Date: Wed, 14 Jan 2026 16:14:53 +0530 Subject: [PATCH 2020/2333] drm/amdgpu/userq: Fix fence reference leak on queue teardown v2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit b2426a211dba6432e32a2e70e9183c6e134475c6 ] The user mode queue keeps a pointer to the most recent fence in userq->last_fence. This pointer holds an extra dma_fence reference. When the queue is destroyed, we free the fence driver and its xarray, but we forgot to drop the last_fence reference. Because of the missing dma_fence_put(), the last fence object can stay alive when the driver unloads. This leaves an allocated object in the amdgpu_userq_fence slab cache and triggers This is visible during driver unload as: BUG amdgpu_userq_fence: Objects remaining on __kmem_cache_shutdown() kmem_cache_destroy amdgpu_userq_fence: Slab cache still has objects Call Trace: kmem_cache_destroy amdgpu_userq_fence_slab_fini amdgpu_exit __do_sys_delete_module Fix this by putting userq->last_fence and clearing the pointer during amdgpu_userq_fence_driver_free(). This makes sure the fence reference is released and the slab cache is empty when the module exits. v2: Update to only release userq->last_fence with dma_fence_put() (Christian) Fixes: edc762a51c71 ("drm/amdgpu/userq: move some code around") Cc: Alex Deucher Cc: Christian König Signed-off-by: Srinivasan Shanmugam Reviewed-by: Christian König Signed-off-by: Alex Deucher (cherry picked from commit 8e051e38a8d45caf6a866d4ff842105b577953bb) Signed-off-by: Sasha Levin --- drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c index 4d0096d0baa9d..53fe10931fab0 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c @@ -141,6 +141,8 @@ static void amdgpu_userq_walk_and_drop_fence_drv(struct xarray *xa) void amdgpu_userq_fence_driver_free(struct amdgpu_usermode_queue *userq) { + dma_fence_put(userq->last_fence); + amdgpu_userq_walk_and_drop_fence_drv(&userq->fence_drv_xa); xa_destroy(&userq->fence_drv_xa); /* Drop the fence_drv reference held by user queue */ From cf6d059b5372880488859f5c41f0bf102c7f7b0c Mon Sep 17 00:00:00 2001 From: Bagas Sanjaya Date: Fri, 19 Dec 2025 08:40:04 +0700 Subject: [PATCH 2021/2333] mm: describe @flags parameter in memalloc_flags_save() [ Upstream commit e2fb7836b01747815f8bb94981c35f2688afb120 ] Patch series "mm kernel-doc fixes". Here are kernel-doc fixes for mm subsystem. I'm also including textsearch fix since there's currently no maintainer for include/linux/textsearch.h (get_maintainer.pl only shows LKML). This patch (of 4): Sphinx reports kernel-doc warning: WARNING: ./include/linux/sched/mm.h:332 function parameter 'flags' not described in 'memalloc_flags_save' Describe @flags to fix it. Link: https://lkml.kernel.org/r/20251219014006.16328-2-bagasdotme@gmail.com Link: https://lkml.kernel.org/r/20251219014006.16328-3-bagasdotme@gmail.com Signed-off-by: Bagas Sanjaya Fixes: 3f6d5e6a468d ("mm: introduce memalloc_flags_{save,restore}") Acked-by: David Hildenbrand (Red Hat) Acked-by: Harry Yoo Signed-off-by: Andrew Morton Signed-off-by: Sasha Levin --- include/linux/sched/mm.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/sched/mm.h b/include/linux/sched/mm.h index 0232d983b7153..a3094379b5790 100644 --- a/include/linux/sched/mm.h +++ b/include/linux/sched/mm.h @@ -323,6 +323,7 @@ static inline void might_alloc(gfp_t gfp_mask) /** * memalloc_flags_save - Add a PF_* flag to current->flags, save old value + * @flags: Flags to add. * * This allows PF_* flags to be conveniently added, irrespective of current * value, and then the old version restored with memalloc_flags_restore(). From cf85a91aa82eaf2886297c5fd38de1b9214e5737 Mon Sep 17 00:00:00 2001 From: Bagas Sanjaya Date: Fri, 19 Dec 2025 08:40:05 +0700 Subject: [PATCH 2022/2333] textsearch: describe @list member in ts_ops search [ Upstream commit f26528478bb102c28e7ac0cbfc8ec8185afdafc7 ] Sphinx reports kernel-doc warning: WARNING: ./include/linux/textsearch.h:49 struct member 'list' not described in 'ts_ops' Describe @list member to fix it. Link: https://lkml.kernel.org/r/20251219014006.16328-4-bagasdotme@gmail.com Fixes: 2de4ff7bd658 ("[LIB]: Textsearch infrastructure.") Signed-off-by: Bagas Sanjaya Cc: Thomas Graf Cc: "David S. Miller" Signed-off-by: Andrew Morton Signed-off-by: Sasha Levin --- include/linux/textsearch.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/textsearch.h b/include/linux/textsearch.h index 6673e4d4ac2e1..4933777404d61 100644 --- a/include/linux/textsearch.h +++ b/include/linux/textsearch.h @@ -35,6 +35,7 @@ struct ts_state * @get_pattern: return head of pattern * @get_pattern_len: return length of pattern * @owner: module reference to algorithm + * @list: list to search */ struct ts_ops { From 2a582a2ca8dae01c5eda1bab528734132da3c50b Mon Sep 17 00:00:00 2001 From: Bagas Sanjaya Date: Fri, 19 Dec 2025 08:40:07 +0700 Subject: [PATCH 2023/2333] mm, kfence: describe @slab parameter in __kfence_obj_info() [ Upstream commit 6cfab50e1440fde19af7c614aacd85e11aa4dcea ] Sphinx reports kernel-doc warning: WARNING: ./include/linux/kfence.h:220 function parameter 'slab' not described in '__kfence_obj_info' Fix it by describing @slab parameter. Link: https://lkml.kernel.org/r/20251219014006.16328-6-bagasdotme@gmail.com Fixes: 2dfe63e61cc3 ("mm, kfence: support kmem_dump_obj() for KFENCE objects") Signed-off-by: Bagas Sanjaya Acked-by: Marco Elver Acked-by: David Hildenbrand (Red Hat) Acked-by: Harry Yoo Signed-off-by: Andrew Morton Signed-off-by: Sasha Levin --- include/linux/kfence.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/kfence.h b/include/linux/kfence.h index 0ad1ddbb8b996..e5822f6e7f279 100644 --- a/include/linux/kfence.h +++ b/include/linux/kfence.h @@ -211,6 +211,7 @@ struct kmem_obj_info; * __kfence_obj_info() - fill kmem_obj_info struct * @kpp: kmem_obj_info to be filled * @object: the object + * @slab: the slab * * Return: * * false - not a KFENCE object From aec20f3aa684baea78b65ce929670ae087f620a4 Mon Sep 17 00:00:00 2001 From: "Mike Rapoport (Microsoft)" Date: Wed, 31 Dec 2025 12:57:01 +0200 Subject: [PATCH 2024/2333] mips: fix HIGHMEM initialization [ Upstream commit f171b55f1441294344b86edfeaa575ea9673fd23 ] Commit 6faea3422e3b ("arch, mm: streamline HIGHMEM freeing") overzealously removed mem_init_free_highmem() function that beside freeing high memory pages checked for CPU support for high memory as a prerequisite. Partially restore mem_init_free_highmem() with a new highmem_init() name and make it discard high memory in case there is no CPU support for it. Link: https://lkml.kernel.org/r/20251231105701.519711-1-rppt@kernel.org Fixes: 6faea3422e3b ("arch, mm: streamline HIGHMEM freeing") Signed-off-by: Mike Rapoport (Microsoft) Reported-by: Markus Stockhausen Cc: Chris Packham Cc: Hauke Mehrtens Cc: Jonas Jelonek Cc: Thomas Bogendoerfer Cc: Thomas Gleinxer Signed-off-by: Andrew Morton Signed-off-by: Sasha Levin --- arch/mips/mm/init.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c index a673d3d68254b..8986048f9b110 100644 --- a/arch/mips/mm/init.c +++ b/arch/mips/mm/init.c @@ -425,6 +425,28 @@ void __init paging_init(void) static struct kcore_list kcore_kseg0; #endif +static inline void __init highmem_init(void) +{ +#ifdef CONFIG_HIGHMEM + unsigned long tmp; + + /* + * If CPU cannot support HIGHMEM discard the memory above highstart_pfn + */ + if (cpu_has_dc_aliases) { + memblock_remove(PFN_PHYS(highstart_pfn), -1); + return; + } + + for (tmp = highstart_pfn; tmp < highend_pfn; tmp++) { + struct page *page = pfn_to_page(tmp); + + if (!memblock_is_memory(PFN_PHYS(tmp))) + SetPageReserved(page); + } +#endif +} + void __init arch_mm_preinit(void) { /* @@ -435,6 +457,7 @@ void __init arch_mm_preinit(void) maar_init(); setup_zero_pages(); /* Setup zeroed pages. */ + highmem_init(); #ifdef CONFIG_64BIT if ((unsigned long) &_text > (unsigned long) CKSEG0) From 8bc6d92b9a3ed4aa94d944cd9cb2e7a2d2cf07a5 Mon Sep 17 00:00:00 2001 From: John Groves Date: Sat, 10 Jan 2026 13:18:04 -0600 Subject: [PATCH 2025/2333] drivers/dax: add some missing kerneldoc comment fields for struct dev_dax [ Upstream commit 3e8e590fd65d0572584ab7bba89a35e6d19931f1 ] Add the missing @align and @memmap_on_memory fields to kerneldoc comment header for struct dev_dax. Also, some other fields were followed by '-' and others by ':'. Fix all to be ':' for actual kerneldoc compliance. Link: https://lkml.kernel.org/r/20260110191804.5739-1-john@groves.net Fixes: 33cf94d71766 ("device-dax: make align a per-device property") Fixes: 4eca0ef49af9 ("dax/kmem: allow kmem to add memory with memmap_on_memory") Signed-off-by: John Groves Cc: Dan Williams Cc: Joao Martins Cc: Vishal Verma Signed-off-by: Andrew Morton Signed-off-by: Sasha Levin --- drivers/dax/dax-private.h | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/dax/dax-private.h b/drivers/dax/dax-private.h index 0867115aeef2e..c6ae27c982f43 100644 --- a/drivers/dax/dax-private.h +++ b/drivers/dax/dax-private.h @@ -67,14 +67,16 @@ struct dev_dax_range { /** * struct dev_dax - instance data for a subdivision of a dax region, and * data while the device is activated in the driver. - * @region - parent region - * @dax_dev - core dax functionality + * @region: parent region + * @dax_dev: core dax functionality + * @align: alignment of this instance * @target_node: effective numa node if dev_dax memory range is onlined * @dyn_id: is this a dynamic or statically created instance * @id: ida allocated id when the dax_region is not static * @ida: mapping id allocator - * @dev - device core - * @pgmap - pgmap for memmap setup / lifetime (driver owned) + * @dev: device core + * @pgmap: pgmap for memmap setup / lifetime (driver owned) + * @memmap_on_memory: allow kmem to put the memmap in the memory * @nr_range: size of @ranges * @ranges: range tuples of memory used */ From 94413a84067c31a787c8973c9b150088601ff4e7 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sat, 10 Jan 2026 18:53:34 -0500 Subject: [PATCH 2026/2333] NFS: Fix size read races in truncate, fallocate and copy offload [ Upstream commit d5811e6297f3fd9020ac31f51fc317dfdb260cb0 ] If the pre-operation file size is read before locking the inode and quiescing O_DIRECT writes, then nfs_truncate_last_folio() might end up overwriting valid file data. Fixes: b1817b18ff20 ("NFS: Protect against 'eof page pollution'") Signed-off-by: Trond Myklebust Signed-off-by: Sasha Levin --- fs/nfs/inode.c | 10 ++++++---- fs/nfs/io.c | 2 ++ fs/nfs/nfs42proc.c | 29 +++++++++++++++++++---------- 3 files changed, 27 insertions(+), 14 deletions(-) diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 13ad70fc00d84..8c2bfcc323e02 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -716,7 +716,7 @@ nfs_setattr(struct mnt_idmap *idmap, struct dentry *dentry, { struct inode *inode = d_inode(dentry); struct nfs_fattr *fattr; - loff_t oldsize = i_size_read(inode); + loff_t oldsize; int error = 0; kuid_t task_uid = current_fsuid(); kuid_t owner_uid = inode->i_uid; @@ -727,6 +727,10 @@ nfs_setattr(struct mnt_idmap *idmap, struct dentry *dentry, if (attr->ia_valid & (ATTR_KILL_SUID | ATTR_KILL_SGID)) attr->ia_valid &= ~ATTR_MODE; + if (S_ISREG(inode->i_mode)) + nfs_file_block_o_direct(NFS_I(inode)); + + oldsize = i_size_read(inode); if (attr->ia_valid & ATTR_SIZE) { BUG_ON(!S_ISREG(inode->i_mode)); @@ -774,10 +778,8 @@ nfs_setattr(struct mnt_idmap *idmap, struct dentry *dentry, trace_nfs_setattr_enter(inode); /* Write all dirty data */ - if (S_ISREG(inode->i_mode)) { - nfs_file_block_o_direct(NFS_I(inode)); + if (S_ISREG(inode->i_mode)) nfs_sync_inode(inode); - } fattr = nfs_alloc_fattr_with_label(NFS_SERVER(inode)); if (fattr == NULL) { diff --git a/fs/nfs/io.c b/fs/nfs/io.c index d275b0a250bf3..8337f0ae852d4 100644 --- a/fs/nfs/io.c +++ b/fs/nfs/io.c @@ -84,6 +84,7 @@ nfs_start_io_write(struct inode *inode) nfs_file_block_o_direct(NFS_I(inode)); return err; } +EXPORT_SYMBOL_GPL(nfs_start_io_write); /** * nfs_end_io_write - declare that the buffered write operation is done @@ -97,6 +98,7 @@ nfs_end_io_write(struct inode *inode) { up_write(&inode->i_rwsem); } +EXPORT_SYMBOL_GPL(nfs_end_io_write); /* Call with exclusively locked inode->i_rwsem */ static void nfs_block_buffered(struct nfs_inode *nfsi, struct inode *inode) diff --git a/fs/nfs/nfs42proc.c b/fs/nfs/nfs42proc.c index d537fb0c230e8..c08520828708b 100644 --- a/fs/nfs/nfs42proc.c +++ b/fs/nfs/nfs42proc.c @@ -114,7 +114,6 @@ static int nfs42_proc_fallocate(struct rpc_message *msg, struct file *filep, exception.inode = inode; exception.state = lock->open_context->state; - nfs_file_block_o_direct(NFS_I(inode)); err = nfs_sync_inode(inode); if (err) goto out; @@ -138,13 +137,17 @@ int nfs42_proc_allocate(struct file *filep, loff_t offset, loff_t len) .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_ALLOCATE], }; struct inode *inode = file_inode(filep); - loff_t oldsize = i_size_read(inode); + loff_t oldsize; int err; if (!nfs_server_capable(inode, NFS_CAP_ALLOCATE)) return -EOPNOTSUPP; - inode_lock(inode); + err = nfs_start_io_write(inode); + if (err) + return err; + + oldsize = i_size_read(inode); err = nfs42_proc_fallocate(&msg, filep, offset, len); @@ -155,7 +158,7 @@ int nfs42_proc_allocate(struct file *filep, loff_t offset, loff_t len) NFS_SERVER(inode)->caps &= ~(NFS_CAP_ALLOCATE | NFS_CAP_ZERO_RANGE); - inode_unlock(inode); + nfs_end_io_write(inode); return err; } @@ -170,7 +173,9 @@ int nfs42_proc_deallocate(struct file *filep, loff_t offset, loff_t len) if (!nfs_server_capable(inode, NFS_CAP_DEALLOCATE)) return -EOPNOTSUPP; - inode_lock(inode); + err = nfs_start_io_write(inode); + if (err) + return err; err = nfs42_proc_fallocate(&msg, filep, offset, len); if (err == 0) @@ -179,7 +184,7 @@ int nfs42_proc_deallocate(struct file *filep, loff_t offset, loff_t len) NFS_SERVER(inode)->caps &= ~(NFS_CAP_DEALLOCATE | NFS_CAP_ZERO_RANGE); - inode_unlock(inode); + nfs_end_io_write(inode); return err; } @@ -189,14 +194,17 @@ int nfs42_proc_zero_range(struct file *filep, loff_t offset, loff_t len) .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_ZERO_RANGE], }; struct inode *inode = file_inode(filep); - loff_t oldsize = i_size_read(inode); + loff_t oldsize; int err; if (!nfs_server_capable(inode, NFS_CAP_ZERO_RANGE)) return -EOPNOTSUPP; - inode_lock(inode); + err = nfs_start_io_write(inode); + if (err) + return err; + oldsize = i_size_read(inode); err = nfs42_proc_fallocate(&msg, filep, offset, len); if (err == 0) { nfs_truncate_last_folio(inode->i_mapping, oldsize, @@ -205,7 +213,7 @@ int nfs42_proc_zero_range(struct file *filep, loff_t offset, loff_t len) } else if (err == -EOPNOTSUPP) NFS_SERVER(inode)->caps &= ~NFS_CAP_ZERO_RANGE; - inode_unlock(inode); + nfs_end_io_write(inode); return err; } @@ -416,7 +424,7 @@ static ssize_t _nfs42_proc_copy(struct file *src, struct nfs_server *src_server = NFS_SERVER(src_inode); loff_t pos_src = args->src_pos; loff_t pos_dst = args->dst_pos; - loff_t oldsize_dst = i_size_read(dst_inode); + loff_t oldsize_dst; size_t count = args->count; ssize_t status; @@ -461,6 +469,7 @@ static ssize_t _nfs42_proc_copy(struct file *src, &src_lock->open_context->state->flags); set_bit(NFS_CLNT_DST_SSC_COPY_STATE, &dst_lock->open_context->state->flags); + oldsize_dst = i_size_read(dst_inode); status = nfs4_call_sync(dst_server->client, dst_server, &msg, &args->seq_args, &res->seq_res, 0); From 974f241095aaf62293b6a98d515ca4bd3b08fbb0 Mon Sep 17 00:00:00 2001 From: Guodong Xu Date: Thu, 18 Sep 2025 22:27:27 +0800 Subject: [PATCH 2027/2333] dmaengine: mmp_pdma: fix DMA mask handling [ Upstream commit 49400b701eca849c1b53717b1f5d779a8d066ec0 ] The driver's existing logic for setting the DMA mask for "marvell,pdma-1.0" was flawed. It incorrectly relied on pdev->dev->coherent_dma_mask instead of declaring the hardware's fixed addressing capability. A cleaner and more correct approach is to define the mask directly based on the hardware limitations. The MMP/PXA PDMA controller is a 32-bit DMA engine. This is supported by datasheets and various dtsi files for PXA25x, PXA27x, PXA3xx, and MMP2, all of which are 32-bit systems. This patch simplifies the driver's logic by replacing the 'u64 dma_mask' field with a simpler 'u32 dma_width' to store the addressing capability in bits. The complex if/else block in probe() is then replaced with a single, clear call to dma_set_mask_and_coherent(). This sets a fixed 32-bit DMA mask for "marvell,pdma-1.0" and a 64-bit mask for "spacemit,k1-pdma," matching each device's hardware capabilities. Finally, this change also works around a specific build error encountered with clang-20 on x86_64 allyesconfig. The shift-count-overflow error is caused by a known clang compiler issue where the DMA_BIT_MASK(n) macro's ternary operator is not correctly evaluated in static initializers. By moving the macro's evaluation into the probe() function, the driver avoids this compiler bug. Fixes: 5cfe585d8624 ("dmaengine: mmp_pdma: Add SpacemiT K1 PDMA support with 64-bit addressing") Reported-by: Naresh Kamboju Closes: https://lore.kernel.org/lkml/CA+G9fYsPcMfW-e_0_TRqu4cnwqOqYF3aJOeKUYk6Z4qRStdFvg@mail.gmail.com Suggested-by: Arnd Bergmann Signed-off-by: Guodong Xu Reviewed-by: Arnd Bergmann Tested-by: Nathan Chancellor # build Tested-by: Naresh Kamboju Signed-off-by: Vinod Koul Signed-off-by: Sasha Levin --- drivers/dma/mmp_pdma.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/drivers/dma/mmp_pdma.c b/drivers/dma/mmp_pdma.c index d07229a748868..86661eb3cde1f 100644 --- a/drivers/dma/mmp_pdma.c +++ b/drivers/dma/mmp_pdma.c @@ -152,8 +152,8 @@ struct mmp_pdma_phy { * * Controller Configuration: * @run_bits: Control bits in DCSR register for channel start/stop - * @dma_mask: DMA addressing capability of controller. 0 to use OF/platform - * settings, or explicit mask like DMA_BIT_MASK(32/64) + * @dma_width: DMA addressing width in bits (32 or 64). Determines the + * DMA mask capability of the controller hardware. */ struct mmp_pdma_ops { /* Hardware Register Operations */ @@ -173,7 +173,7 @@ struct mmp_pdma_ops { /* Controller Configuration */ u32 run_bits; - u64 dma_mask; + u32 dma_width; }; struct mmp_pdma_device { @@ -1172,7 +1172,7 @@ static const struct mmp_pdma_ops marvell_pdma_v1_ops = { .get_desc_src_addr = get_desc_src_addr_32, .get_desc_dst_addr = get_desc_dst_addr_32, .run_bits = (DCSR_RUN), - .dma_mask = 0, /* let OF/platform set DMA mask */ + .dma_width = 32, }; static const struct mmp_pdma_ops spacemit_k1_pdma_ops = { @@ -1185,7 +1185,7 @@ static const struct mmp_pdma_ops spacemit_k1_pdma_ops = { .get_desc_src_addr = get_desc_src_addr_64, .get_desc_dst_addr = get_desc_dst_addr_64, .run_bits = (DCSR_RUN | DCSR_LPAEEN), - .dma_mask = DMA_BIT_MASK(64), /* force 64-bit DMA addr capability */ + .dma_width = 64, }; static const struct of_device_id mmp_pdma_dt_ids[] = { @@ -1314,13 +1314,9 @@ static int mmp_pdma_probe(struct platform_device *op) pdev->device.directions = BIT(DMA_MEM_TO_DEV) | BIT(DMA_DEV_TO_MEM); pdev->device.residue_granularity = DMA_RESIDUE_GRANULARITY_DESCRIPTOR; - /* Set DMA mask based on ops->dma_mask, or OF/platform */ - if (pdev->ops->dma_mask) - dma_set_mask(pdev->dev, pdev->ops->dma_mask); - else if (pdev->dev->coherent_dma_mask) - dma_set_mask(pdev->dev, pdev->dev->coherent_dma_mask); - else - dma_set_mask(pdev->dev, DMA_BIT_MASK(64)); + /* Set DMA mask based on controller hardware capabilities */ + dma_set_mask_and_coherent(pdev->dev, + DMA_BIT_MASK(pdev->ops->dma_width)); ret = dma_async_device_register(&pdev->device); if (ret) { From 5e7ad329d259cf5bed7530d6d2525bcf7cb487a1 Mon Sep 17 00:00:00 2001 From: Anthony Brandon Date: Mon, 13 Oct 2025 17:48:49 +0200 Subject: [PATCH 2028/2333] dmaengine: xilinx: xdma: Fix regmap max_register [ Upstream commit c7d436a6c1a274c1ac28d5fb3b8eb8f03b6d0e10 ] The max_register field is assigned the size of the register memory region instead of the offset of the last register. The result is that reading from the regmap via debugfs can cause a segmentation fault: tail /sys/kernel/debug/regmap/xdma.1.auto/registers Unable to handle kernel paging request at virtual address ffff800082f70000 Mem abort info: ESR = 0x0000000096000007 EC = 0x25: DABT (current EL), IL = 32 bits SET = 0, FnV = 0 EA = 0, S1PTW = 0 FSC = 0x07: level 3 translation fault [...] Call trace: regmap_mmio_read32le+0x10/0x30 _regmap_bus_reg_read+0x74/0xc0 _regmap_read+0x68/0x198 regmap_read+0x54/0x88 regmap_read_debugfs+0x140/0x380 regmap_map_read_file+0x30/0x48 full_proxy_read+0x68/0xc8 vfs_read+0xcc/0x310 ksys_read+0x7c/0x120 __arm64_sys_read+0x24/0x40 invoke_syscall.constprop.0+0x64/0x108 do_el0_svc+0xb0/0xd8 el0_svc+0x38/0x130 el0t_64_sync_handler+0x120/0x138 el0t_64_sync+0x194/0x198 Code: aa1e03e9 d503201f f9400000 8b214000 (b9400000) ---[ end trace 0000000000000000 ]--- note: tail[1217] exited with irqs disabled note: tail[1217] exited with preempt_count 1 Segmentation fault Fixes: 17ce252266c7 ("dmaengine: xilinx: xdma: Add xilinx xdma driver") Reviewed-by: Lizhi Hou Reviewed-by: Radhey Shyam Pandey Reviewed-by: Alexander Stein Signed-off-by: Anthony Brandon Signed-off-by: Vinod Koul Signed-off-by: Sasha Levin --- drivers/dma/xilinx/xdma-regs.h | 1 + drivers/dma/xilinx/xdma.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/dma/xilinx/xdma-regs.h b/drivers/dma/xilinx/xdma-regs.h index 6ad08878e9386..70bca92621aa4 100644 --- a/drivers/dma/xilinx/xdma-regs.h +++ b/drivers/dma/xilinx/xdma-regs.h @@ -9,6 +9,7 @@ /* The length of register space exposed to host */ #define XDMA_REG_SPACE_LEN 65536 +#define XDMA_MAX_REG_OFFSET (XDMA_REG_SPACE_LEN - 4) /* * maximum number of DMA channels for each direction: diff --git a/drivers/dma/xilinx/xdma.c b/drivers/dma/xilinx/xdma.c index 0d88b1a670e14..5ecf8223c112e 100644 --- a/drivers/dma/xilinx/xdma.c +++ b/drivers/dma/xilinx/xdma.c @@ -38,7 +38,7 @@ static const struct regmap_config xdma_regmap_config = { .reg_bits = 32, .val_bits = 32, .reg_stride = 4, - .max_register = XDMA_REG_SPACE_LEN, + .max_register = XDMA_MAX_REG_OFFSET, }; /** From be655c3736b3546f39bc8116ffbf2a3b6cac96c4 Mon Sep 17 00:00:00 2001 From: Sheetal Date: Mon, 10 Nov 2025 19:54:45 +0530 Subject: [PATCH 2029/2333] dmaengine: tegra-adma: Fix use-after-free [ Upstream commit 2efd07a7c36949e6fa36a69183df24d368bf9e96 ] A use-after-free bug exists in the Tegra ADMA driver when audio streams are terminated, particularly during XRUN conditions. The issue occurs when the DMA buffer is freed by tegra_adma_terminate_all() before the vchan completion tasklet finishes accessing it. The race condition follows this sequence: 1. DMA transfer completes, triggering an interrupt that schedules the completion tasklet (tasklet has not executed yet) 2. Audio playback stops, calling tegra_adma_terminate_all() which frees the DMA buffer memory via kfree() 3. The scheduled tasklet finally executes, calling vchan_complete() which attempts to access the already-freed memory Since tasklets can execute at any time after being scheduled, there is no guarantee that the buffer will remain valid when vchan_complete() runs. Fix this by properly synchronizing the virtual channel completion: - Calling vchan_terminate_vdesc() in tegra_adma_stop() to mark the descriptors as terminated instead of freeing the descriptor. - Add the callback tegra_adma_synchronize() that calls vchan_synchronize() which kills any pending tasklets and frees any terminated descriptors. Crash logs: [ 337.427523] BUG: KASAN: use-after-free in vchan_complete+0x124/0x3b0 [ 337.427544] Read of size 8 at addr ffff000132055428 by task swapper/0/0 [ 337.427562] Call trace: [ 337.427564] dump_backtrace+0x0/0x320 [ 337.427571] show_stack+0x20/0x30 [ 337.427575] dump_stack_lvl+0x68/0x84 [ 337.427584] print_address_description.constprop.0+0x74/0x2b8 [ 337.427590] kasan_report+0x1f4/0x210 [ 337.427598] __asan_load8+0xa0/0xd0 [ 337.427603] vchan_complete+0x124/0x3b0 [ 337.427609] tasklet_action_common.constprop.0+0x190/0x1d0 [ 337.427617] tasklet_action+0x30/0x40 [ 337.427623] __do_softirq+0x1a0/0x5c4 [ 337.427628] irq_exit+0x110/0x140 [ 337.427633] handle_domain_irq+0xa4/0xe0 [ 337.427640] gic_handle_irq+0x64/0x160 [ 337.427644] call_on_irq_stack+0x20/0x4c [ 337.427649] do_interrupt_handler+0x7c/0x90 [ 337.427654] el1_interrupt+0x30/0x80 [ 337.427659] el1h_64_irq_handler+0x18/0x30 [ 337.427663] el1h_64_irq+0x7c/0x80 [ 337.427667] cpuidle_enter_state+0xe4/0x540 [ 337.427674] cpuidle_enter+0x54/0x80 [ 337.427679] do_idle+0x2e0/0x380 [ 337.427685] cpu_startup_entry+0x2c/0x70 [ 337.427690] rest_init+0x114/0x130 [ 337.427695] arch_call_rest_init+0x18/0x24 [ 337.427702] start_kernel+0x380/0x3b4 [ 337.427706] __primary_switched+0xc0/0xc8 Fixes: f46b195799b5 ("dmaengine: tegra-adma: Add support for Tegra210 ADMA") Signed-off-by: Sheetal Acked-by: Thierry Reding Link: https://patch.msgid.link/20251110142445.3842036-1-sheetal@nvidia.com Signed-off-by: Vinod Koul Signed-off-by: Sasha Levin --- drivers/dma/tegra210-adma.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/dma/tegra210-adma.c b/drivers/dma/tegra210-adma.c index fad896ff29a2d..812f64569e6d8 100644 --- a/drivers/dma/tegra210-adma.c +++ b/drivers/dma/tegra210-adma.c @@ -429,10 +429,17 @@ static void tegra_adma_stop(struct tegra_adma_chan *tdc) return; } - kfree(tdc->desc); + vchan_terminate_vdesc(&tdc->desc->vd); tdc->desc = NULL; } +static void tegra_adma_synchronize(struct dma_chan *dc) +{ + struct tegra_adma_chan *tdc = to_tegra_adma_chan(dc); + + vchan_synchronize(&tdc->vc); +} + static void tegra_adma_start(struct tegra_adma_chan *tdc) { struct virt_dma_desc *vd = vchan_next_desc(&tdc->vc); @@ -1155,6 +1162,7 @@ static int tegra_adma_probe(struct platform_device *pdev) tdma->dma_dev.device_config = tegra_adma_slave_config; tdma->dma_dev.device_tx_status = tegra_adma_tx_status; tdma->dma_dev.device_terminate_all = tegra_adma_terminate_all; + tdma->dma_dev.device_synchronize = tegra_adma_synchronize; tdma->dma_dev.src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES); tdma->dma_dev.dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES); tdma->dma_dev.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV); From f93c7033689218698b5ebe5c763f2da36dec8eef Mon Sep 17 00:00:00 2001 From: Suraj Gupta Date: Wed, 22 Oct 2025 00:00:06 +0530 Subject: [PATCH 2030/2333] dmaengine: xilinx_dma: Fix uninitialized addr_width when "xlnx,addrwidth" property is missing [ Upstream commit c0732fe78728718c853ef8e7af5bbb05262acbd1 ] When device tree lacks optional "xlnx,addrwidth" property, the addr_width variable remained uninitialized with garbage values, causing incorrect DMA mask configuration and subsequent probe failure. The fix ensures a fallback to the default 32-bit address width when this property is missing. Signed-off-by: Suraj Gupta Fixes: b72db4005fe4 ("dmaengine: vdma: Add 64 bit addressing support to the driver") Reviewed-by: Radhey Shyam Pandey Reviewed-by: Folker Schwesinger Link: https://patch.msgid.link/20251021183006.3434495-1-suraj.gupta2@amd.com Signed-off-by: Vinod Koul Signed-off-by: Sasha Levin --- drivers/dma/xilinx/xilinx_dma.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/dma/xilinx/xilinx_dma.c b/drivers/dma/xilinx/xilinx_dma.c index fabff602065f6..89a8254d9cdc6 100644 --- a/drivers/dma/xilinx/xilinx_dma.c +++ b/drivers/dma/xilinx/xilinx_dma.c @@ -131,6 +131,7 @@ #define XILINX_MCDMA_MAX_CHANS_PER_DEVICE 0x20 #define XILINX_DMA_MAX_CHANS_PER_DEVICE 0x2 #define XILINX_CDMA_MAX_CHANS_PER_DEVICE 0x1 +#define XILINX_DMA_DFAULT_ADDRWIDTH 0x20 #define XILINX_DMA_DMAXR_ALL_IRQ_MASK \ (XILINX_DMA_DMASR_FRM_CNT_IRQ | \ @@ -3159,7 +3160,7 @@ static int xilinx_dma_probe(struct platform_device *pdev) struct device_node *node = pdev->dev.of_node; struct xilinx_dma_device *xdev; struct device_node *child, *np = pdev->dev.of_node; - u32 num_frames, addr_width, len_width; + u32 num_frames, addr_width = XILINX_DMA_DFAULT_ADDRWIDTH, len_width; int i, err; /* Allocate and initialize the DMA engine structure */ @@ -3235,7 +3236,9 @@ static int xilinx_dma_probe(struct platform_device *pdev) err = of_property_read_u32(node, "xlnx,addrwidth", &addr_width); if (err < 0) - dev_warn(xdev->dev, "missing xlnx,addrwidth property\n"); + dev_warn(xdev->dev, + "missing xlnx,addrwidth property, using default value %d\n", + XILINX_DMA_DFAULT_ADDRWIDTH); if (addr_width > 32) xdev->ext_addr = true; From d279f7e17b6d408f2fdbeba795abccabf352bd78 Mon Sep 17 00:00:00 2001 From: Stefano Radaelli Date: Fri, 19 Dec 2025 17:09:12 +0100 Subject: [PATCH 2031/2333] phy: fsl-imx8mq-usb: Clear the PCS_TX_SWING_FULL field before using it [ Upstream commit 8becf9179a4b45104a1701010ed666b55bf4b3a6 ] Clear the PCS_TX_SWING_FULL field mask before setting the new value in PHY_CTRL5 register. Without clearing the mask first, the OR operation could leave previously set bits, resulting in incorrect register configuration. Fixes: 63c85ad0cd81 ("phy: fsl-imx8mp-usb: add support for phy tuning") Suggested-by: Leonid Segal Acked-by: Pierluigi Passaro Signed-off-by: Stefano Radaelli Reviewed-by: Xu Yang Reviewed-by: Frank Li Reviewed-by: Fabio Estevam Reviewed-by: Ahmad Fatoum Link: https://patch.msgid.link/20251219160912.561431-1-stefano.r@variscite.com Signed-off-by: Vinod Koul Signed-off-by: Sasha Levin --- drivers/phy/freescale/phy-fsl-imx8mq-usb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/phy/freescale/phy-fsl-imx8mq-usb.c b/drivers/phy/freescale/phy-fsl-imx8mq-usb.c index b94f242420fc7..0c84f5f7a82cb 100644 --- a/drivers/phy/freescale/phy-fsl-imx8mq-usb.c +++ b/drivers/phy/freescale/phy-fsl-imx8mq-usb.c @@ -502,6 +502,7 @@ static void imx8m_phy_tune(struct imx8mq_usb_phy *imx_phy) if (imx_phy->pcs_tx_swing_full != PHY_TUNE_DEFAULT) { value = readl(imx_phy->base + PHY_CTRL5); + value &= ~PHY_CTRL5_PCS_TX_SWING_FULL_MASK; value |= FIELD_PREP(PHY_CTRL5_PCS_TX_SWING_FULL_MASK, imx_phy->pcs_tx_swing_full); writel(value, imx_phy->base + PHY_CTRL5); From 4ac15caa27ff842b068a54f1c6a8ff8b31f658e7 Mon Sep 17 00:00:00 2001 From: Loic Poulain Date: Fri, 19 Dec 2025 09:56:40 +0100 Subject: [PATCH 2032/2333] phy: qcom-qusb2: Fix NULL pointer dereference on early suspend [ Upstream commit 1ca52c0983c34fca506921791202ed5bdafd5306 ] Enabling runtime PM before attaching the QPHY instance as driver data can lead to a NULL pointer dereference in runtime PM callbacks that expect valid driver data. There is a small window where the suspend callback may run after PM runtime enabling and before runtime forbid. This causes a sporadic crash during boot: ``` Unable to handle kernel NULL pointer dereference at virtual address 00000000000000a1 [...] CPU: 0 UID: 0 PID: 11 Comm: kworker/0:1 Not tainted 6.16.7+ #116 PREEMPT Workqueue: pm pm_runtime_work pstate: 20000005 (nzCv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) pc : qusb2_phy_runtime_suspend+0x14/0x1e0 [phy_qcom_qusb2] lr : pm_generic_runtime_suspend+0x2c/0x44 [...] ``` Attach the QPHY instance as driver data before enabling runtime PM to prevent NULL pointer dereference in runtime PM callbacks. Reorder pm_runtime_enable() and pm_runtime_forbid() to prevent a short window where an unnecessary runtime suspend can occur. Use the devres-managed version to ensure PM runtime is symmetrically disabled during driver removal for proper cleanup. Fixes: 891a96f65ac3 ("phy: qcom-qusb2: Add support for runtime PM") Signed-off-by: Loic Poulain Reviewed-by: Dmitry Baryshkov Reviewed-by: Abel Vesa Link: https://patch.msgid.link/20251219085640.114473-1-loic.poulain@oss.qualcomm.com Signed-off-by: Vinod Koul Signed-off-by: Sasha Levin --- drivers/phy/qualcomm/phy-qcom-qusb2.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-qusb2.c b/drivers/phy/qualcomm/phy-qcom-qusb2.c index b5514a32ff8ff..eb93015be841f 100644 --- a/drivers/phy/qualcomm/phy-qcom-qusb2.c +++ b/drivers/phy/qualcomm/phy-qcom-qusb2.c @@ -1093,29 +1093,29 @@ static int qusb2_phy_probe(struct platform_device *pdev) or->hsdisc_trim.override = true; } - pm_runtime_set_active(dev); - pm_runtime_enable(dev); + dev_set_drvdata(dev, qphy); + /* - * Prevent runtime pm from being ON by default. Users can enable - * it using power/control in sysfs. + * Enable runtime PM support, but forbid it by default. + * Users can allow it again via the power/control attribute in sysfs. */ + pm_runtime_set_active(dev); pm_runtime_forbid(dev); + ret = devm_pm_runtime_enable(dev); + if (ret) + return ret; generic_phy = devm_phy_create(dev, NULL, &qusb2_phy_gen_ops); if (IS_ERR(generic_phy)) { ret = PTR_ERR(generic_phy); dev_err(dev, "failed to create phy, %d\n", ret); - pm_runtime_disable(dev); return ret; } qphy->phy = generic_phy; - dev_set_drvdata(dev, qphy); phy_set_drvdata(generic_phy, qphy); phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); - if (IS_ERR(phy_provider)) - pm_runtime_disable(dev); return PTR_ERR_OR_ZERO(phy_provider); } From 7c27eaf183563b86d815ff6e9cca0210b4cfa051 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 9 Dec 2025 09:53:36 +0300 Subject: [PATCH 2033/2333] phy: stm32-usphyc: Fix off by one in probe() [ Upstream commit cabd25b57216ddc132efbcc31f972baa03aad15a ] The "index" variable is used as an index into the usbphyc->phys[] array which has usbphyc->nphys elements. So if it is equal to usbphyc->nphys then it is one element out of bounds. The "index" comes from the device tree so it's data that we trust and it's unlikely to be wrong, however it's obviously still worth fixing the bug. Change the > to >=. Fixes: 94c358da3a05 ("phy: stm32: add support for STM32 USB PHY Controller (USBPHYC)") Signed-off-by: Dan Carpenter Reviewed-by: Amelie Delaunay Link: https://patch.msgid.link/aTfHcMJK1wFVnvEe@stanley.mountain Signed-off-by: Vinod Koul Signed-off-by: Sasha Levin --- drivers/phy/st/phy-stm32-usbphyc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/phy/st/phy-stm32-usbphyc.c b/drivers/phy/st/phy-stm32-usbphyc.c index 27fe92f73f331..b44afbff8616b 100644 --- a/drivers/phy/st/phy-stm32-usbphyc.c +++ b/drivers/phy/st/phy-stm32-usbphyc.c @@ -712,7 +712,7 @@ static int stm32_usbphyc_probe(struct platform_device *pdev) } ret = of_property_read_u32(child, "reg", &index); - if (ret || index > usbphyc->nphys) { + if (ret || index >= usbphyc->nphys) { dev_err(&phy->dev, "invalid reg property: %d\n", ret); if (!ret) ret = -EINVAL; From 15dfbe9079987eb517e842a444306b90927b4a69 Mon Sep 17 00:00:00 2001 From: Haotian Zhang Date: Mon, 24 Nov 2025 18:57:34 +0800 Subject: [PATCH 2034/2333] phy: ti: da8xx-usb: Handle devm_pm_runtime_enable() errors [ Upstream commit 08aa19de72110df8ac10c9e67349dd884eeed41d ] devm_pm_runtime_enable() can fail due to memory allocation. The current code ignores its return value after calling pm_runtime_set_active(), leaving the device in an inconsistent state if runtime PM initialization fails. Check the return value of devm_pm_runtime_enable() and return on failure. Also move the declaration of 'ret' to the function scope to support this check. Fixes: ee8e41b5044f ("phy: ti: phy-da8xx-usb: Add runtime PM support") Suggested-by: Neil Armstrong Signed-off-by: Haotian Zhang Reviewed-by: Neil Armstrong Link: https://patch.msgid.link/20251124105734.1027-1-vulab@iscas.ac.cn Signed-off-by: Vinod Koul Signed-off-by: Sasha Levin --- drivers/phy/ti/phy-da8xx-usb.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/phy/ti/phy-da8xx-usb.c b/drivers/phy/ti/phy-da8xx-usb.c index 1d81a1e6ec6b6..62fa6f89c0e61 100644 --- a/drivers/phy/ti/phy-da8xx-usb.c +++ b/drivers/phy/ti/phy-da8xx-usb.c @@ -180,6 +180,7 @@ static int da8xx_usb_phy_probe(struct platform_device *pdev) struct da8xx_usb_phy_platform_data *pdata = dev->platform_data; struct device_node *node = dev->of_node; struct da8xx_usb_phy *d_phy; + int ret; d_phy = devm_kzalloc(dev, sizeof(*d_phy), GFP_KERNEL); if (!d_phy) @@ -233,8 +234,6 @@ static int da8xx_usb_phy_probe(struct platform_device *pdev) return PTR_ERR(d_phy->phy_provider); } } else { - int ret; - ret = phy_create_lookup(d_phy->usb11_phy, "usb-phy", "ohci-da8xx"); if (ret) @@ -249,7 +248,9 @@ static int da8xx_usb_phy_probe(struct platform_device *pdev) PHY_INIT_BITS, PHY_INIT_BITS); pm_runtime_set_active(dev); - devm_pm_runtime_enable(dev); + ret = devm_pm_runtime_enable(dev); + if (ret) + return ret; /* * Prevent runtime pm from being ON by default. Users can enable * it using power/control in sysfs. From 75ef8c94d4303e53a85e51c2d437af5468dd0710 Mon Sep 17 00:00:00 2001 From: Matthieu Buffet Date: Mon, 27 Oct 2025 20:07:26 +0100 Subject: [PATCH 2035/2333] landlock: Fix TCP handling of short AF_UNSPEC addresses MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit e4d82cbce2258f454634307fdabf33aa46b61ab0 ] current_check_access_socket() treats AF_UNSPEC addresses as AF_INET ones, and only later adds special case handling to allow connect(AF_UNSPEC), and on IPv4 sockets bind(AF_UNSPEC+INADDR_ANY). This would be fine except AF_UNSPEC addresses can be as short as a bare AF_UNSPEC sa_family_t field, and nothing more. The AF_INET code path incorrectly enforces a length of sizeof(struct sockaddr_in) instead. Move AF_UNSPEC edge case handling up inside the switch-case, before the address is (potentially incorrectly) treated as AF_INET. Fixes: fff69fb03dde ("landlock: Support network rules with TCP bind and connect") Signed-off-by: Matthieu Buffet Link: https://lore.kernel.org/r/20251027190726.626244-4-matthieu@buffet.re Signed-off-by: Mickaël Salaün Signed-off-by: Sasha Levin --- security/landlock/net.c | 118 +++++++++++++++++++++++----------------- 1 file changed, 67 insertions(+), 51 deletions(-) diff --git a/security/landlock/net.c b/security/landlock/net.c index 1f3915a90a808..e6367e30e5b0e 100644 --- a/security/landlock/net.c +++ b/security/landlock/net.c @@ -71,6 +71,61 @@ static int current_check_access_socket(struct socket *const sock, switch (address->sa_family) { case AF_UNSPEC: + if (access_request == LANDLOCK_ACCESS_NET_CONNECT_TCP) { + /* + * Connecting to an address with AF_UNSPEC dissolves + * the TCP association, which have the same effect as + * closing the connection while retaining the socket + * object (i.e., the file descriptor). As for dropping + * privileges, closing connections is always allowed. + * + * For a TCP access control system, this request is + * legitimate. Let the network stack handle potential + * inconsistencies and return -EINVAL if needed. + */ + return 0; + } else if (access_request == LANDLOCK_ACCESS_NET_BIND_TCP) { + /* + * Binding to an AF_UNSPEC address is treated + * differently by IPv4 and IPv6 sockets. The socket's + * family may change under our feet due to + * setsockopt(IPV6_ADDRFORM), but that's ok: we either + * reject entirely or require + * %LANDLOCK_ACCESS_NET_BIND_TCP for the given port, so + * it cannot be used to bypass the policy. + * + * IPv4 sockets map AF_UNSPEC to AF_INET for + * retrocompatibility for bind accesses, only if the + * address is INADDR_ANY (cf. __inet_bind). IPv6 + * sockets always reject it. + * + * Checking the address is required to not wrongfully + * return -EACCES instead of -EAFNOSUPPORT or -EINVAL. + * We could return 0 and let the network stack handle + * these checks, but it is safer to return a proper + * error and test consistency thanks to kselftest. + */ + if (sock->sk->__sk_common.skc_family == AF_INET) { + const struct sockaddr_in *const sockaddr = + (struct sockaddr_in *)address; + + if (addrlen < sizeof(struct sockaddr_in)) + return -EINVAL; + + if (sockaddr->sin_addr.s_addr != + htonl(INADDR_ANY)) + return -EAFNOSUPPORT; + } else { + if (addrlen < SIN6_LEN_RFC2133) + return -EINVAL; + else + return -EAFNOSUPPORT; + } + } else { + WARN_ON_ONCE(1); + } + /* Only for bind(AF_UNSPEC+INADDR_ANY) on IPv4 socket. */ + fallthrough; case AF_INET: { const struct sockaddr_in *addr4; @@ -119,57 +174,18 @@ static int current_check_access_socket(struct socket *const sock, return 0; } - /* Specific AF_UNSPEC handling. */ - if (address->sa_family == AF_UNSPEC) { - /* - * Connecting to an address with AF_UNSPEC dissolves the TCP - * association, which have the same effect as closing the - * connection while retaining the socket object (i.e., the file - * descriptor). As for dropping privileges, closing - * connections is always allowed. - * - * For a TCP access control system, this request is legitimate. - * Let the network stack handle potential inconsistencies and - * return -EINVAL if needed. - */ - if (access_request == LANDLOCK_ACCESS_NET_CONNECT_TCP) - return 0; - - /* - * For compatibility reason, accept AF_UNSPEC for bind - * accesses (mapped to AF_INET) only if the address is - * INADDR_ANY (cf. __inet_bind). Checking the address is - * required to not wrongfully return -EACCES instead of - * -EAFNOSUPPORT. - * - * We could return 0 and let the network stack handle these - * checks, but it is safer to return a proper error and test - * consistency thanks to kselftest. - */ - if (access_request == LANDLOCK_ACCESS_NET_BIND_TCP) { - /* addrlen has already been checked for AF_UNSPEC. */ - const struct sockaddr_in *const sockaddr = - (struct sockaddr_in *)address; - - if (sock->sk->__sk_common.skc_family != AF_INET) - return -EINVAL; - - if (sockaddr->sin_addr.s_addr != htonl(INADDR_ANY)) - return -EAFNOSUPPORT; - } - } else { - /* - * Checks sa_family consistency to not wrongfully return - * -EACCES instead of -EINVAL. Valid sa_family changes are - * only (from AF_INET or AF_INET6) to AF_UNSPEC. - * - * We could return 0 and let the network stack handle this - * check, but it is safer to return a proper error and test - * consistency thanks to kselftest. - */ - if (address->sa_family != sock->sk->__sk_common.skc_family) - return -EINVAL; - } + /* + * Checks sa_family consistency to not wrongfully return + * -EACCES instead of -EINVAL. Valid sa_family changes are + * only (from AF_INET or AF_INET6) to AF_UNSPEC. + * + * We could return 0 and let the network stack handle this + * check, but it is safer to return a proper error and test + * consistency thanks to kselftest. + */ + if (address->sa_family != sock->sk->__sk_common.skc_family && + address->sa_family != AF_UNSPEC) + return -EINVAL; id.key.data = (__force uintptr_t)port; BUILD_BUG_ON(sizeof(port) > sizeof(id.key.data)); From c589bc64336672ebdc3fd83c563a6529aa138735 Mon Sep 17 00:00:00 2001 From: Matthieu Buffet Date: Mon, 27 Oct 2025 20:07:24 +0100 Subject: [PATCH 2036/2333] selftests/landlock: Fix TCP bind(AF_UNSPEC) test case MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit bd09d9a05cf04028f639e209b416bacaeffd4909 ] The nominal error code for bind(AF_UNSPEC) on an IPv6 socket is -EAFNOSUPPORT, not -EINVAL. -EINVAL is only returned when the supplied address struct is too short, which happens to be the case in current selftests because they treat AF_UNSPEC like IPv4 sockets do: as an alias for AF_INET (which is a 16-byte struct instead of the 24 bytes required by IPv6 sockets). Make the union large enough for any address (by adding struct sockaddr_storage to the union), and make AF_UNSPEC addresses large enough for any family. Test for -EAFNOSUPPORT instead, and add a dedicated test case for truncated inputs with -EINVAL. Fixes: a549d055a22e ("selftests/landlock: Add network tests") Signed-off-by: Matthieu Buffet Link: https://lore.kernel.org/r/20251027190726.626244-2-matthieu@buffet.re Signed-off-by: Mickaël Salaün Signed-off-by: Sasha Levin --- tools/testing/selftests/landlock/common.h | 1 + tools/testing/selftests/landlock/net_test.c | 16 +++++++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/landlock/common.h b/tools/testing/selftests/landlock/common.h index 9acecae36f51b..98c2362954e21 100644 --- a/tools/testing/selftests/landlock/common.h +++ b/tools/testing/selftests/landlock/common.h @@ -237,6 +237,7 @@ struct service_fixture { struct sockaddr_un unix_addr; socklen_t unix_addr_len; }; + struct sockaddr_storage _largest; }; }; diff --git a/tools/testing/selftests/landlock/net_test.c b/tools/testing/selftests/landlock/net_test.c index 2a45208551e61..3bbc0508420b1 100644 --- a/tools/testing/selftests/landlock/net_test.c +++ b/tools/testing/selftests/landlock/net_test.c @@ -121,6 +121,10 @@ static socklen_t get_addrlen(const struct service_fixture *const srv, { switch (srv->protocol.domain) { case AF_UNSPEC: + if (minimal) + return sizeof(sa_family_t); + return sizeof(struct sockaddr_storage); + case AF_INET: return sizeof(srv->ipv4_addr); @@ -758,6 +762,11 @@ TEST_F(protocol, bind_unspec) bind_fd = socket_variant(&self->srv0); ASSERT_LE(0, bind_fd); + /* Tries to bind with too small addrlen. */ + EXPECT_EQ(-EINVAL, bind_variant_addrlen( + bind_fd, &self->unspec_any0, + get_addrlen(&self->unspec_any0, true) - 1)); + /* Allowed bind on AF_UNSPEC/INADDR_ANY. */ ret = bind_variant(bind_fd, &self->unspec_any0); if (variant->prot.domain == AF_INET) { @@ -766,6 +775,8 @@ TEST_F(protocol, bind_unspec) TH_LOG("Failed to bind to unspec/any socket: %s", strerror(errno)); } + } else if (variant->prot.domain == AF_INET6) { + EXPECT_EQ(-EAFNOSUPPORT, ret); } else { EXPECT_EQ(-EINVAL, ret); } @@ -792,6 +803,8 @@ TEST_F(protocol, bind_unspec) } else { EXPECT_EQ(0, ret); } + } else if (variant->prot.domain == AF_INET6) { + EXPECT_EQ(-EAFNOSUPPORT, ret); } else { EXPECT_EQ(-EINVAL, ret); } @@ -801,7 +814,8 @@ TEST_F(protocol, bind_unspec) bind_fd = socket_variant(&self->srv0); ASSERT_LE(0, bind_fd); ret = bind_variant(bind_fd, &self->unspec_srv0); - if (variant->prot.domain == AF_INET) { + if (variant->prot.domain == AF_INET || + variant->prot.domain == AF_INET6) { EXPECT_EQ(-EAFNOSUPPORT, ret); } else { EXPECT_EQ(-EINVAL, ret) From a45001796aa004025c7c352c42362582a79f595d Mon Sep 17 00:00:00 2001 From: Matthieu Buffet Date: Mon, 1 Dec 2025 01:36:31 +0100 Subject: [PATCH 2037/2333] selftests/landlock: Remove invalid unix socket bind() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit e1a57c33590a50a6639798e60a597af4a23b0340 ] Remove bind() call on a client socket that doesn't make sense. Since strlen(cli_un.sun_path) returns a random value depending on stack garbage, that many uninitialized bytes are read from the stack as an unix socket address. This creates random test failures due to the bind address being invalid or already in use if the same stack value comes up twice. Fixes: f83d51a5bdfe ("selftests/landlock: Check IOCTL restrictions for named UNIX domain sockets") Signed-off-by: Matthieu Buffet Reviewed-by: Günther Noack Link: https://lore.kernel.org/r/20251201003631.190817-1-matthieu@buffet.re Signed-off-by: Mickaël Salaün Signed-off-by: Sasha Levin --- tools/testing/selftests/landlock/fs_test.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/tools/testing/selftests/landlock/fs_test.c b/tools/testing/selftests/landlock/fs_test.c index fa0f18ec62c41..a6eb9681791a5 100644 --- a/tools/testing/selftests/landlock/fs_test.c +++ b/tools/testing/selftests/landlock/fs_test.c @@ -4375,9 +4375,6 @@ TEST_F_FORK(layout1, named_unix_domain_socket_ioctl) cli_fd = socket(AF_UNIX, SOCK_STREAM, 0); ASSERT_LE(0, cli_fd); - size = offsetof(struct sockaddr_un, sun_path) + strlen(cli_un.sun_path); - ASSERT_EQ(0, bind(cli_fd, (struct sockaddr *)&cli_un, size)); - bzero(&cli_un, sizeof(cli_un)); cli_un.sun_family = AF_UNIX; strncpy(cli_un.sun_path, path, sizeof(cli_un.sun_path)); From f73f911a4cdf04d8a76181d8ce4765cf195c5527 Mon Sep 17 00:00:00 2001 From: Tingmao Wang Date: Sat, 6 Dec 2025 17:11:06 +0000 Subject: [PATCH 2038/2333] landlock: Fix wrong type usage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 29fbfa46e4287c596bdc77e2c599e3a1bbf8bb67 ] I think, based on my best understanding, that this type is likely a typo (even though in the end both are u16) Signed-off-by: Tingmao Wang Fixes: 2fc80c69df82 ("landlock: Log file-related denials") Reviewed-by: Günther Noack Link: https://lore.kernel.org/r/7339ad7b47f998affd84ca629a334a71f913616d.1765040503.git.m@maowtm.org Signed-off-by: Mickaël Salaün Signed-off-by: Sasha Levin --- security/landlock/audit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/security/landlock/audit.c b/security/landlock/audit.c index c52d079cdb77b..e899995f1fd59 100644 --- a/security/landlock/audit.c +++ b/security/landlock/audit.c @@ -191,7 +191,7 @@ static size_t get_denied_layer(const struct landlock_ruleset *const domain, long youngest_layer = -1; for_each_set_bit(access_bit, &access_req, layer_masks_size) { - const access_mask_t mask = (*layer_masks)[access_bit]; + const layer_mask_t mask = (*layer_masks)[access_bit]; long layer; if (!mask) From cdcaec67c55ef516666a5d9a1695750f037b1b2b Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 24 Dec 2025 12:55:34 +0100 Subject: [PATCH 2039/2333] phy: broadcom: ns-usb3: Fix Wvoid-pointer-to-enum-cast warning (again) [ Upstream commit fb21116099bbea1fc59efa9207e63c4be390ab72 ] "family" is an enum, thus cast of pointer on 64-bit compile test with clang W=1 causes: phy-bcm-ns-usb3.c:206:17: error: cast to smaller integer type 'enum bcm_ns_family' from 'const void *' [-Werror,-Wvoid-pointer-to-enum-cast] This was already fixed in commit bd6e74a2f0a0 ("phy: broadcom: ns-usb3: fix Wvoid-pointer-to-enum-cast warning") but then got bad in commit 21bf6fc47a1e ("phy: Use device_get_match_data()"). Note that after various discussions the preferred cast is via "unsigned long", not "uintptr_t". Fixes: 21bf6fc47a1e ("phy: Use device_get_match_data()") Signed-off-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20251224115533.154162-2-krzysztof.kozlowski@oss.qualcomm.com Signed-off-by: Vinod Koul Signed-off-by: Sasha Levin --- drivers/phy/broadcom/phy-bcm-ns-usb3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/phy/broadcom/phy-bcm-ns-usb3.c b/drivers/phy/broadcom/phy-bcm-ns-usb3.c index 9f995e156f755..6e56498d0644b 100644 --- a/drivers/phy/broadcom/phy-bcm-ns-usb3.c +++ b/drivers/phy/broadcom/phy-bcm-ns-usb3.c @@ -203,7 +203,7 @@ static int bcm_ns_usb3_mdio_probe(struct mdio_device *mdiodev) usb3->dev = dev; usb3->mdiodev = mdiodev; - usb3->family = (enum bcm_ns_family)device_get_match_data(dev); + usb3->family = (unsigned long)device_get_match_data(dev); syscon_np = of_parse_phandle(dev->of_node, "usb3-dmp-syscon", 0); err = of_address_to_resource(syscon_np, 0, &res); From d91cee31906a873bcc123d06eda4efa4835c8d0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=BCnther=20Noack?= Date: Thu, 1 Jan 2026 14:40:58 +0100 Subject: [PATCH 2040/2333] selftests/landlock: Properly close a file descriptor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 15e8d739fda1084d81f7d3813e9600eba6e0f134 ] Add a missing close(srv_fd) call, and use EXPECT_EQ() to check the result. Signed-off-by: Günther Noack Fixes: f83d51a5bdfe ("selftests/landlock: Check IOCTL restrictions for named UNIX domain sockets") Link: https://lore.kernel.org/r/20260101134102.25938-2-gnoack3000@gmail.com [mic: Use EXPECT_EQ() and update commit message] Signed-off-by: Mickaël Salaün Signed-off-by: Sasha Levin --- tools/testing/selftests/landlock/fs_test.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/landlock/fs_test.c b/tools/testing/selftests/landlock/fs_test.c index a6eb9681791a5..29cdbb8367358 100644 --- a/tools/testing/selftests/landlock/fs_test.c +++ b/tools/testing/selftests/landlock/fs_test.c @@ -4385,7 +4385,8 @@ TEST_F_FORK(layout1, named_unix_domain_socket_ioctl) /* FIONREAD and other IOCTLs should not be forbidden. */ EXPECT_EQ(0, test_fionread_ioctl(cli_fd)); - ASSERT_EQ(0, close(cli_fd)); + EXPECT_EQ(0, close(cli_fd)); + EXPECT_EQ(0, close(srv_fd)); } /* clang-format off */ From 829b00481734dd54e72f755fd6584bce6fbffbb0 Mon Sep 17 00:00:00 2001 From: Haotian Zhang Date: Mon, 3 Nov 2025 15:30:18 +0800 Subject: [PATCH 2041/2333] dmaengine: omap-dma: fix dma_pool resource leak in error paths [ Upstream commit 2e1136acf8a8887c29f52e35a77b537309af321f ] The dma_pool created by dma_pool_create() is not destroyed when dma_async_device_register() or of_dma_controller_register() fails, causing a resource leak in the probe error paths. Add dma_pool_destroy() in both error paths to properly release the allocated dma_pool resource. Fixes: 7bedaa553760 ("dmaengine: add OMAP DMA engine driver") Signed-off-by: Haotian Zhang Link: https://patch.msgid.link/20251103073018.643-1-vulab@iscas.ac.cn Signed-off-by: Vinod Koul Signed-off-by: Sasha Levin --- drivers/dma/ti/omap-dma.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/dma/ti/omap-dma.c b/drivers/dma/ti/omap-dma.c index 8c023c6e623a5..73ed4b7946304 100644 --- a/drivers/dma/ti/omap-dma.c +++ b/drivers/dma/ti/omap-dma.c @@ -1808,6 +1808,8 @@ static int omap_dma_probe(struct platform_device *pdev) if (rc) { pr_warn("OMAP-DMA: failed to register slave DMA engine device: %d\n", rc); + if (od->ll123_supported) + dma_pool_destroy(od->desc_pool); omap_dma_free(od); return rc; } @@ -1823,6 +1825,8 @@ static int omap_dma_probe(struct platform_device *pdev) if (rc) { pr_warn("OMAP-DMA: failed to register DMA controller\n"); dma_async_device_unregister(&od->ddev); + if (od->ll123_supported) + dma_pool_destroy(od->desc_pool); omap_dma_free(od); } } From 612cbe1aebb32e874798766b54987484c4cfc820 Mon Sep 17 00:00:00 2001 From: Harshit Mogalapalli Date: Sat, 10 Jan 2026 12:19:58 -0800 Subject: [PATCH 2042/2333] soundwire: bus: fix off-by-one when allocating slave IDs [ Upstream commit 12d4fd9a657174496677cff2841315090f1c11fc ] ida_alloc_max() interprets its max argument as inclusive. Using SDW_FW_MAX_DEVICES(16) therefore allows an ID of 16 to be allocated, but the IRQ domain created for the bus is sized for IDs 0-15. If 16 is returned, irq_create_mapping() fails and the driver ends up with an invalid IRQ mapping. Limit the allocation to 0-15 by passing SDW_FW_MAX_DEVICES - 1. Reported-by: kernel test robot Reported-by: Dan Carpenter Closes: https://lore.kernel.org/r/202512240450.hlDH3nCs-lkp@intel.com/ Fixes: aab12022b076 ("soundwire: bus: Add internal slave ID and use for IRQs") Signed-off-by: Harshit Mogalapalli Reviewed-by: Charles Keepax Link: https://patch.msgid.link/20260110201959.2523024-1-harshit.m.mogalapalli@oracle.com Signed-off-by: Vinod Koul Signed-off-by: Sasha Levin --- drivers/soundwire/bus_type.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/soundwire/bus_type.c b/drivers/soundwire/bus_type.c index 91e70cb46fb57..5c67c13e57357 100644 --- a/drivers/soundwire/bus_type.c +++ b/drivers/soundwire/bus_type.c @@ -105,7 +105,7 @@ static int sdw_drv_probe(struct device *dev) if (ret) return ret; - ret = ida_alloc_max(&slave->bus->slave_ida, SDW_FW_MAX_DEVICES, GFP_KERNEL); + ret = ida_alloc_max(&slave->bus->slave_ida, SDW_FW_MAX_DEVICES - 1, GFP_KERNEL); if (ret < 0) { dev_err(dev, "Failed to allocated ID: %d\n", ret); return ret; From 11ae04ebbe6e580ac769bd15382a0432e46a5c6f Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Wed, 29 Oct 2025 19:07:42 +0100 Subject: [PATCH 2043/2333] i2c: qcom-geni: make sure I2C hub controllers can't use SE DMA [ Upstream commit c0c50e3743e467ec4752c638e10e97f89c8644e2 ] The I2C Hub controller is a simpler GENI I2C variant that doesn't support DMA at all, add a no_dma flag to make sure it nevers selects the SE DMA mode with mappable 32bytes long transfers. Fixes: cacd9643eca7 ("i2c: qcom-geni: add support for I2C Master Hub variant") Signed-off-by: Neil Armstrong Reviewed-by: Konrad Dybcio Reviewed-by: Mukesh Kumar Savaliya > Signed-off-by: Wolfram Sang Signed-off-by: Sasha Levin --- drivers/i2c/busses/i2c-qcom-geni.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c index 43fdd89b8bebc..bfb352b04902c 100644 --- a/drivers/i2c/busses/i2c-qcom-geni.c +++ b/drivers/i2c/busses/i2c-qcom-geni.c @@ -97,6 +97,7 @@ struct geni_i2c_dev { dma_addr_t dma_addr; struct dma_chan *tx_c; struct dma_chan *rx_c; + bool no_dma; bool gpi_mode; bool abort_done; }; @@ -425,7 +426,7 @@ static int geni_i2c_rx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg, size_t len = msg->len; struct i2c_msg *cur; - dma_buf = i2c_get_dma_safe_msg_buf(msg, 32); + dma_buf = gi2c->no_dma ? NULL : i2c_get_dma_safe_msg_buf(msg, 32); if (dma_buf) geni_se_select_mode(se, GENI_SE_DMA); else @@ -464,7 +465,7 @@ static int geni_i2c_tx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg, size_t len = msg->len; struct i2c_msg *cur; - dma_buf = i2c_get_dma_safe_msg_buf(msg, 32); + dma_buf = gi2c->no_dma ? NULL : i2c_get_dma_safe_msg_buf(msg, 32); if (dma_buf) geni_se_select_mode(se, GENI_SE_DMA); else @@ -880,10 +881,12 @@ static int geni_i2c_probe(struct platform_device *pdev) goto err_resources; } - if (desc && desc->no_dma_support) + if (desc && desc->no_dma_support) { fifo_disable = false; - else + gi2c->no_dma = true; + } else { fifo_disable = readl_relaxed(gi2c->se.base + GENI_IF_DISABLE_RO) & FIFO_IF_DISABLE; + } if (fifo_disable) { /* FIFO is disabled, so we can only use GPI DMA */ From cf40c73ab25bcc9b2729c022f41866e44a029914 Mon Sep 17 00:00:00 2001 From: Carlos Song Date: Fri, 21 Nov 2025 11:00:30 +0800 Subject: [PATCH 2044/2333] i2c: imx-lpi2c: change to PIO mode in system-wide suspend/resume progress [ Upstream commit f2a3f51365bf672dab4b58d1e8954926a9196b44 ] EDMA resumes early and suspends late in the system power transition sequence, while LPI2C enters the NOIRQ stage for both suspend and resume. This means LPI2C resources become available before EDMA is fully resumed. Once IRQs are enabled, a slave device may immediately trigger an LPI2C transfer. If the transfer length meets DMA requirements, the driver will attempt to use EDMA even though EDMA may still be unavailable. This timing gap can lead to transfer failures. To prevent this, force LPI2C to use PIO mode during system-wide suspend and resume transitions. This reduces dependency on EDMA and avoids using an unready DMA resource. Fixes: a09c8b3f9047 ("i2c: imx-lpi2c: add eDMA mode support for LPI2C") Signed-off-by: Carlos Song Reviewed-by: Frank Li Signed-off-by: Wolfram Sang Signed-off-by: Sasha Levin --- drivers/i2c/busses/i2c-imx-lpi2c.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/i2c/busses/i2c-imx-lpi2c.c b/drivers/i2c/busses/i2c-imx-lpi2c.c index 2a0962a0b4417..d882126c1778c 100644 --- a/drivers/i2c/busses/i2c-imx-lpi2c.c +++ b/drivers/i2c/busses/i2c-imx-lpi2c.c @@ -592,6 +592,13 @@ static bool is_use_dma(struct lpi2c_imx_struct *lpi2c_imx, struct i2c_msg *msg) if (!lpi2c_imx->can_use_dma) return false; + /* + * A system-wide suspend or resume transition is in progress. LPI2C should use PIO to + * transfer data to avoid issue caused by no ready DMA HW resource. + */ + if (pm_suspend_in_progress()) + return false; + /* * When the length of data is less than I2C_DMA_THRESHOLD, * cpu mode is used directly to avoid low performance. From f32d9e475a41f521634a133f6bf98ee0e2aae445 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Tue, 13 Jan 2026 12:57:14 +0100 Subject: [PATCH 2045/2333] sched/deadline: Avoid double update_rq_clock() [ Upstream commit 4de9ff76067b40c3660df73efaea57389e62ea7a ] When setup_new_dl_entity() is called from enqueue_task_dl() -> enqueue_dl_entity(), the rq-clock should already be updated, and calling update_rq_clock() again is not right. Move the update_rq_clock() to the one other caller of setup_new_dl_entity(): sched_init_dl_server(). Fixes: 9f239df55546 ("sched/deadline: Initialize dl_servers after SMP") Reported-by: Pierre Gondois Signed-off-by: Peter Zijlstra (Intel) Tested-by: Pierre Gondois Link: https://patch.msgid.link/20260113115622.GA831285@noisy.programming.kicks-ass.net Signed-off-by: Sasha Levin --- kernel/sched/deadline.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/kernel/sched/deadline.c b/kernel/sched/deadline.c index d3be71d5a9ccc..465592fa530ef 100644 --- a/kernel/sched/deadline.c +++ b/kernel/sched/deadline.c @@ -761,8 +761,6 @@ static inline void setup_new_dl_entity(struct sched_dl_entity *dl_se) struct dl_rq *dl_rq = dl_rq_of_se(dl_se); struct rq *rq = rq_of_dl_rq(dl_rq); - update_rq_clock(rq); - WARN_ON(is_dl_boosted(dl_se)); WARN_ON(dl_time_before(rq_clock(rq), dl_se->deadline)); @@ -1623,6 +1621,7 @@ void sched_init_dl_servers(void) rq = cpu_rq(cpu); guard(rq_lock_irq)(rq); + update_rq_clock(rq); dl_se = &rq->fair_server; From 0754d5caac719f649dbb73365741dcb90fbf793a Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Thu, 15 Jan 2026 09:25:37 +0100 Subject: [PATCH 2046/2333] sched: Deadline has dynamic priority [ Upstream commit e008ec6c7904ed99d3b2cb634b6545b008a99288 ] While FIFO/RR have static priority, DEADLINE is a dynamic priority scheme. Notably it has static priority -1. Do not assume the priority doesn't change for deadline tasks just because the static priority doesn't change. This ensures DL always sees {DE,EN}QUEUE_MOVE where appropriate. Fixes: ff77e4685359 ("sched/rt: Fix PI handling vs. sched_setscheduler()") Signed-off-by: Peter Zijlstra (Intel) Tested-by: Pierre Gondois Tested-by: Juri Lelli Link: https://patch.msgid.link/20260114130528.GB831285@noisy.programming.kicks-ass.net Signed-off-by: Sasha Levin --- kernel/sched/core.c | 2 +- kernel/sched/syscalls.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/sched/core.c b/kernel/sched/core.c index eb47d294e2c5a..e460c22de8ad4 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -7383,7 +7383,7 @@ void rt_mutex_setprio(struct task_struct *p, struct task_struct *pi_task) trace_sched_pi_setprio(p, pi_task); oldprio = p->prio; - if (oldprio == prio) + if (oldprio == prio && !dl_prio(prio)) queue_flag &= ~DEQUEUE_MOVE; prev_class = p->sched_class; diff --git a/kernel/sched/syscalls.c b/kernel/sched/syscalls.c index bf360a6fbb800..6805a63d47af7 100644 --- a/kernel/sched/syscalls.c +++ b/kernel/sched/syscalls.c @@ -688,7 +688,7 @@ int __sched_setscheduler(struct task_struct *p, * itself. */ newprio = rt_effective_prio(p, newprio); - if (newprio == oldprio) + if (newprio == oldprio && !dl_prio(newprio)) queue_flags &= ~DEQUEUE_MOVE; } From f57953023f736a890076a8b7eda95c6b9478f55e Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Mon, 15 Dec 2025 12:57:21 +0100 Subject: [PATCH 2047/2333] HID: usbhid: paper over wrong bNumDescriptor field commit f28beb69c51517aec7067dfb2074e7c751542384 upstream. Some faulty devices (ZWO EFWmini) have a wrong optional HID class descriptor count compared to the provided length. Given that we plainly ignore those optional descriptor, we can attempt to fix the provided number so we do not lock out those devices. Signed-off-by: Benjamin Tissoires Cc: Salvatore Bonaccorso Signed-off-by: Greg Kroah-Hartman --- drivers/hid/usbhid/hid-core.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c index aac0051a2cf65..758eb21430cda 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c @@ -985,6 +985,7 @@ static int usbhid_parse(struct hid_device *hid) struct usb_device *dev = interface_to_usbdev (intf); struct hid_descriptor *hdesc; struct hid_class_descriptor *hcdesc; + __u8 fixed_opt_descriptors_size; u32 quirks = 0; unsigned int rsize = 0; char *rdesc; @@ -1015,7 +1016,21 @@ static int usbhid_parse(struct hid_device *hid) (hdesc->bNumDescriptors - 1) * sizeof(*hcdesc)) { dbg_hid("hid descriptor invalid, bLen=%hhu bNum=%hhu\n", hdesc->bLength, hdesc->bNumDescriptors); - return -EINVAL; + + /* + * Some devices may expose a wrong number of descriptors compared + * to the provided length. + * However, we ignore the optional hid class descriptors entirely + * so we can safely recompute the proper field. + */ + if (hdesc->bLength >= sizeof(*hdesc)) { + fixed_opt_descriptors_size = hdesc->bLength - sizeof(*hdesc); + + hid_warn(intf, "fixing wrong optional hid class descriptors count\n"); + hdesc->bNumDescriptors = fixed_opt_descriptors_size / sizeof(*hcdesc) + 1; + } else { + return -EINVAL; + } } hid->version = le16_to_cpu(hdesc->bcdHID); From 3667af036eeadd3ae261d6007ea2aa4c99878d7b Mon Sep 17 00:00:00 2001 From: Yonghong Song Date: Mon, 13 Oct 2025 22:16:39 -0700 Subject: [PATCH 2048/2333] selftests/bpf: Fix selftest verif_scale_strobemeta failure with llvm22 commit 4f8543b5f20f851cedbb23f8eade159871d84e2a upstream. With latest llvm22, I hit the verif_scale_strobemeta selftest failure below: $ ./test_progs -n 618 libbpf: prog 'on_event': BPF program load failed: -E2BIG libbpf: prog 'on_event': -- BEGIN PROG LOAD LOG -- BPF program is too large. Processed 1000001 insn verification time 7019091 usec stack depth 488 processed 1000001 insns (limit 1000000) max_states_per_insn 28 total_states 33927 peak_states 12813 mark_read 0 -- END PROG LOAD LOG -- libbpf: prog 'on_event': failed to load: -E2BIG libbpf: failed to load object 'strobemeta.bpf.o' scale_test:FAIL:expect_success unexpected error: -7 (errno 7) #618 verif_scale_strobemeta:FAIL But if I increase the verificaiton insn limit from 1M to 10M, the above test_progs run actually will succeed. The below is the result from veristat: $ ./veristat strobemeta.bpf.o Processing 'strobemeta.bpf.o'... File Program Verdict Duration (us) Insns States Program size Jited size ---------------- -------- ------- ------------- ------- ------ ------------ ---------- strobemeta.bpf.o on_event success 90250893 9777685 358230 15954 80794 ---------------- -------- ------- ------------- ------- ------ ------------ ---------- Done. Processed 1 files, 0 programs. Skipped 1 files, 0 programs. Further debugging shows the llvm commit [1] is responsible for the verificaiton failure as it tries to convert certain switch statement to if-condition. Such change may cause different transformation compared to original switch statement. In bpf program strobemeta.c case, the initial llvm ir for read_int_var() function is define internal void @read_int_var(ptr noundef %0, i64 noundef %1, ptr noundef %2, ptr noundef %3, ptr noundef %4) #2 !dbg !535 { %6 = alloca ptr, align 8 %7 = alloca i64, align 8 %8 = alloca ptr, align 8 %9 = alloca ptr, align 8 %10 = alloca ptr, align 8 %11 = alloca ptr, align 8 %12 = alloca i32, align 4 ... %20 = icmp ne ptr %19, null, !dbg !561 br i1 %20, label %22, label %21, !dbg !562 21: ; preds = %5 store i32 1, ptr %12, align 4 br label %48, !dbg !563 22: %23 = load ptr, ptr %9, align 8, !dbg !564 ... 47: ; preds = %38, %22 store i32 0, ptr %12, align 4, !dbg !588 br label %48, !dbg !588 48: ; preds = %47, %21 call void @llvm.lifetime.end.p0(ptr %11) #4, !dbg !588 %49 = load i32, ptr %12, align 4 switch i32 %49, label %51 [ i32 0, label %50 i32 1, label %50 ] 50: ; preds = %48, %48 ret void, !dbg !589 51: ; preds = %48 unreachable } Note that the above 'switch' statement is added by clang frontend. Without [1], the switch statement will survive until SelectionDag, so the switch statement acts like a 'barrier' and prevents some transformation involved with both 'before' and 'after' the switch statement. But with [1], the switch statement will be removed during middle end optimization and later middle end passes (esp. after inlining) have more freedom to reorder the code. The following is the related source code: static void *calc_location(struct strobe_value_loc *loc, void *tls_base): bpf_probe_read_user(&tls_ptr, sizeof(void *), dtv); /* if pointer has (void *)-1 value, then TLS wasn't initialized yet */ return tls_ptr && tls_ptr != (void *)-1 ? tls_ptr + tls_index.offset : NULL; In read_int_var() func, we have: void *location = calc_location(&cfg->int_locs[idx], tls_base); if (!location) return; bpf_probe_read_user(value, sizeof(struct strobe_value_generic), location); ... The static func calc_location() is called inside read_int_var(). The asm code without [1]: 77: .123....89 (85) call bpf_probe_read_user#112 78: ........89 (79) r1 = *(u64 *)(r10 -368) 79: .1......89 (79) r2 = *(u64 *)(r10 -8) 80: .12.....89 (bf) r3 = r2 81: .123....89 (0f) r3 += r1 82: ..23....89 (07) r2 += 1 83: ..23....89 (79) r4 = *(u64 *)(r10 -464) 84: ..234...89 (a5) if r2 < 0x2 goto pc+13 85: ...34...89 (15) if r3 == 0x0 goto pc+12 86: ...3....89 (bf) r1 = r10 87: .1.3....89 (07) r1 += -400 88: .1.3....89 (b4) w2 = 16 In this case, 'r2 < 0x2' and 'r3 == 0x0' go to null 'locaiton' place, so the verifier actually prefers to do verification first at 'r1 = r10' etc. The asm code with [1]: 119: .123....89 (85) call bpf_probe_read_user#112 120: ........89 (79) r1 = *(u64 *)(r10 -368) 121: .1......89 (79) r2 = *(u64 *)(r10 -8) 122: .12.....89 (bf) r3 = r2 123: .123....89 (0f) r3 += r1 124: ..23....89 (07) r2 += -1 125: ..23....89 (a5) if r2 < 0xfffffffe goto pc+6 126: ........89 (05) goto pc+17 ... 144: ........89 (b4) w1 = 0 145: .1......89 (6b) *(u16 *)(r8 +80) = r1 In this case, if 'r2 < 0xfffffffe' is true, the control will go to non-null 'location' branch, so 'goto pc+17' will actually go to null 'location' branch. This seems causing tremendous amount of verificaiton state. To fix the issue, rewrite the following code return tls_ptr && tls_ptr != (void *)-1 ? tls_ptr + tls_index.offset : NULL; to if/then statement and hopefully these explicit if/then statements are sticky during middle-end optimizations. Test with llvm20 and llvm21 as well and all strobemeta related selftests are passed. [1] https://github.com/llvm/llvm-project/pull/161000 Signed-off-by: Yonghong Song Link: https://lore.kernel.org/r/20251014051639.1996331-1-yonghong.song@linux.dev Signed-off-by: Alexei Starovoitov Signed-off-by: Shung-Hsi Yu Signed-off-by: Greg Kroah-Hartman --- tools/testing/selftests/bpf/progs/strobemeta.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/testing/selftests/bpf/progs/strobemeta.h b/tools/testing/selftests/bpf/progs/strobemeta.h index a5c74d31a2444..6e1918deaf262 100644 --- a/tools/testing/selftests/bpf/progs/strobemeta.h +++ b/tools/testing/selftests/bpf/progs/strobemeta.h @@ -330,9 +330,9 @@ static void *calc_location(struct strobe_value_loc *loc, void *tls_base) } bpf_probe_read_user(&tls_ptr, sizeof(void *), dtv); /* if pointer has (void *)-1 value, then TLS wasn't initialized yet */ - return tls_ptr && tls_ptr != (void *)-1 - ? tls_ptr + tls_index.offset - : NULL; + if (!tls_ptr || tls_ptr == (void *)-1) + return NULL; + return tls_ptr + tls_index.offset; } #ifdef SUBPROGS From 2674004ddc1fb1b940961b69f432c6f55f3290fc Mon Sep 17 00:00:00 2001 From: Brian Kao Date: Thu, 18 Dec 2025 03:17:23 +0000 Subject: [PATCH 2049/2333] scsi: core: Fix error handler encryption support commit 9a49157deeb23581fc5c8189b486340d7343264a upstream. Some low-level drivers (LLD) access block layer crypto fields, such as rq->crypt_keyslot and rq->crypt_ctx within `struct request`, to configure hardware for inline encryption. However, SCSI Error Handling (EH) commands (e.g., TEST UNIT READY, START STOP UNIT) should not involve any encryption setup. To prevent drivers from erroneously applying crypto settings during EH, this patch saves the original values of rq->crypt_keyslot and rq->crypt_ctx before an EH command is prepared via scsi_eh_prep_cmnd(). These fields in the 'struct request' are then set to NULL. The original values are restored in scsi_eh_restore_cmnd() after the EH command completes. This ensures that the block layer crypto context does not leak into EH command execution. Signed-off-by: Brian Kao Link: https://patch.msgid.link/20251218031726.2642834-1-powenkao@google.com Cc: stable@vger.kernel.org Reviewed-by: Bart Van Assche Signed-off-by: Martin K. Petersen Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/scsi_error.c | 24 ++++++++++++++++++++++++ include/scsi/scsi_eh.h | 6 ++++++ 2 files changed, 30 insertions(+) diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 1c13812a3f035..830429483319a 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -1060,6 +1060,9 @@ void scsi_eh_prep_cmnd(struct scsi_cmnd *scmd, struct scsi_eh_save *ses, unsigned char *cmnd, int cmnd_size, unsigned sense_bytes) { struct scsi_device *sdev = scmd->device; +#ifdef CONFIG_BLK_INLINE_ENCRYPTION + struct request *rq = scsi_cmd_to_rq(scmd); +#endif /* * We need saved copies of a number of fields - this is because @@ -1111,6 +1114,18 @@ void scsi_eh_prep_cmnd(struct scsi_cmnd *scmd, struct scsi_eh_save *ses, scmd->cmnd[1] = (scmd->cmnd[1] & 0x1f) | (sdev->lun << 5 & 0xe0); + /* + * Encryption must be disabled for the commands submitted by the error handler. + * Hence, clear the encryption context information. + */ +#ifdef CONFIG_BLK_INLINE_ENCRYPTION + ses->rq_crypt_keyslot = rq->crypt_keyslot; + ses->rq_crypt_ctx = rq->crypt_ctx; + + rq->crypt_keyslot = NULL; + rq->crypt_ctx = NULL; +#endif + /* * Zero the sense buffer. The scsi spec mandates that any * untransferred sense data should be interpreted as being zero. @@ -1128,6 +1143,10 @@ EXPORT_SYMBOL(scsi_eh_prep_cmnd); */ void scsi_eh_restore_cmnd(struct scsi_cmnd* scmd, struct scsi_eh_save *ses) { +#ifdef CONFIG_BLK_INLINE_ENCRYPTION + struct request *rq = scsi_cmd_to_rq(scmd); +#endif + /* * Restore original data */ @@ -1140,6 +1159,11 @@ void scsi_eh_restore_cmnd(struct scsi_cmnd* scmd, struct scsi_eh_save *ses) scmd->underflow = ses->underflow; scmd->prot_op = ses->prot_op; scmd->eh_eflags = ses->eh_eflags; + +#ifdef CONFIG_BLK_INLINE_ENCRYPTION + rq->crypt_keyslot = ses->rq_crypt_keyslot; + rq->crypt_ctx = ses->rq_crypt_ctx; +#endif } EXPORT_SYMBOL(scsi_eh_restore_cmnd); diff --git a/include/scsi/scsi_eh.h b/include/scsi/scsi_eh.h index 1ae08e81339fa..15679be90c5c3 100644 --- a/include/scsi/scsi_eh.h +++ b/include/scsi/scsi_eh.h @@ -41,6 +41,12 @@ struct scsi_eh_save { unsigned char cmnd[32]; struct scsi_data_buffer sdb; struct scatterlist sense_sgl; + + /* struct request fields */ +#ifdef CONFIG_BLK_INLINE_ENCRYPTION + struct bio_crypt_ctx *rq_crypt_ctx; + struct blk_crypto_keyslot *rq_crypt_keyslot; +#endif }; extern void scsi_eh_prep_cmnd(struct scsi_cmnd *scmd, From 580581bd4af55259e0b35157ee9f52960b165e57 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 24 Dec 2025 00:44:49 +0100 Subject: [PATCH 2050/2333] selftests: kvm: replace numbered sync points with actions commit a1025dcd377ef92d9a09af03b70ce80be281ee22 upstream. Rework the guest=>host syncs in the AMX test to use named actions instead of arbitrary, incrementing numbers. The "stage" of the test has no real meaning, what matters is what action the test wants the host to perform. The incrementing numbers are somewhat helpful for triaging failures, but fully debugging failures almost always requires a much deeper dive into the test (and KVM). Using named actions not only makes it easier to extend the test without having to shift all sync point numbers, it makes the code easier to read. [Commit message by Sean Christopherson] Cc: stable@vger.kernel.org Signed-off-by: Paolo Bonzini Signed-off-by: Greg Kroah-Hartman --- tools/testing/selftests/kvm/x86/amx_test.c | 88 +++++++++++----------- 1 file changed, 43 insertions(+), 45 deletions(-) diff --git a/tools/testing/selftests/kvm/x86/amx_test.c b/tools/testing/selftests/kvm/x86/amx_test.c index f4ce5a185a7dd..3de4402ac17de 100644 --- a/tools/testing/selftests/kvm/x86/amx_test.c +++ b/tools/testing/selftests/kvm/x86/amx_test.c @@ -124,6 +124,14 @@ static void set_tilecfg(struct tile_config *cfg) } } +enum { + /* Check TMM0 against tiledata */ + TEST_COMPARE_TILEDATA = 1, + + /* Full VM save/restore */ + TEST_SAVE_RESTORE = 2, +}; + static void __attribute__((__flatten__)) guest_code(struct tile_config *amx_cfg, struct tile_data *tiledata, struct xstate *xstate) @@ -131,20 +139,20 @@ static void __attribute__((__flatten__)) guest_code(struct tile_config *amx_cfg, GUEST_ASSERT(this_cpu_has(X86_FEATURE_XSAVE) && this_cpu_has(X86_FEATURE_OSXSAVE)); check_xtile_info(); - GUEST_SYNC(1); + GUEST_SYNC(TEST_SAVE_RESTORE); /* xfd=0, enable amx */ wrmsr(MSR_IA32_XFD, 0); - GUEST_SYNC(2); + GUEST_SYNC(TEST_SAVE_RESTORE); GUEST_ASSERT(rdmsr(MSR_IA32_XFD) == 0); set_tilecfg(amx_cfg); __ldtilecfg(amx_cfg); - GUEST_SYNC(3); + GUEST_SYNC(TEST_SAVE_RESTORE); /* Check save/restore when trap to userspace */ __tileloadd(tiledata); - GUEST_SYNC(4); + GUEST_SYNC(TEST_COMPARE_TILEDATA | TEST_SAVE_RESTORE); __tilerelease(); - GUEST_SYNC(5); + GUEST_SYNC(TEST_SAVE_RESTORE); /* * After XSAVEC, XTILEDATA is cleared in the xstate_bv but is set in * the xcomp_bv. @@ -154,6 +162,8 @@ static void __attribute__((__flatten__)) guest_code(struct tile_config *amx_cfg, GUEST_ASSERT(!(xstate->header.xstate_bv & XFEATURE_MASK_XTILE_DATA)); GUEST_ASSERT(xstate->header.xcomp_bv & XFEATURE_MASK_XTILE_DATA); + /* #NM test */ + /* xfd=0x40000, disable amx tiledata */ wrmsr(MSR_IA32_XFD, XFEATURE_MASK_XTILE_DATA); @@ -166,13 +176,13 @@ static void __attribute__((__flatten__)) guest_code(struct tile_config *amx_cfg, GUEST_ASSERT(!(xstate->header.xstate_bv & XFEATURE_MASK_XTILE_DATA)); GUEST_ASSERT((xstate->header.xcomp_bv & XFEATURE_MASK_XTILE_DATA)); - GUEST_SYNC(6); + GUEST_SYNC(TEST_SAVE_RESTORE); GUEST_ASSERT(rdmsr(MSR_IA32_XFD) == XFEATURE_MASK_XTILE_DATA); set_tilecfg(amx_cfg); __ldtilecfg(amx_cfg); /* Trigger #NM exception */ __tileloadd(tiledata); - GUEST_SYNC(10); + GUEST_SYNC(TEST_COMPARE_TILEDATA | TEST_SAVE_RESTORE); GUEST_DONE(); } @@ -180,18 +190,18 @@ static void __attribute__((__flatten__)) guest_code(struct tile_config *amx_cfg, void guest_nm_handler(struct ex_regs *regs) { /* Check if #NM is triggered by XFEATURE_MASK_XTILE_DATA */ - GUEST_SYNC(7); + GUEST_SYNC(TEST_SAVE_RESTORE); GUEST_ASSERT(!(get_cr0() & X86_CR0_TS)); GUEST_ASSERT(rdmsr(MSR_IA32_XFD_ERR) == XFEATURE_MASK_XTILE_DATA); GUEST_ASSERT(rdmsr(MSR_IA32_XFD) == XFEATURE_MASK_XTILE_DATA); - GUEST_SYNC(8); + GUEST_SYNC(TEST_SAVE_RESTORE); GUEST_ASSERT(rdmsr(MSR_IA32_XFD_ERR) == XFEATURE_MASK_XTILE_DATA); GUEST_ASSERT(rdmsr(MSR_IA32_XFD) == XFEATURE_MASK_XTILE_DATA); /* Clear xfd_err */ wrmsr(MSR_IA32_XFD_ERR, 0); /* xfd=0, enable amx */ wrmsr(MSR_IA32_XFD, 0); - GUEST_SYNC(9); + GUEST_SYNC(TEST_SAVE_RESTORE); } int main(int argc, char *argv[]) @@ -244,6 +254,7 @@ int main(int argc, char *argv[]) memset(addr_gva2hva(vm, xstate), 0, PAGE_SIZE * DIV_ROUND_UP(XSAVE_SIZE, PAGE_SIZE)); vcpu_args_set(vcpu, 3, amx_cfg, tiledata, xstate); + int iter = 0; for (;;) { vcpu_run(vcpu); TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO); @@ -253,20 +264,9 @@ int main(int argc, char *argv[]) REPORT_GUEST_ASSERT(uc); /* NOT REACHED */ case UCALL_SYNC: - switch (uc.args[1]) { - case 1: - case 2: - case 3: - case 5: - case 6: - case 7: - case 8: - fprintf(stderr, "GUEST_SYNC(%ld)\n", uc.args[1]); - break; - case 4: - case 10: - fprintf(stderr, - "GUEST_SYNC(%ld), check save/restore status\n", uc.args[1]); + ++iter; + if (uc.args[1] & TEST_COMPARE_TILEDATA) { + fprintf(stderr, "GUEST_SYNC #%d, check TMM0 contents\n", iter); /* Compacted mode, get amx offset by xsave area * size subtract 8K amx size. @@ -279,11 +279,25 @@ int main(int argc, char *argv[]) ret = memcmp(amx_start, tiles_data, TILE_SIZE); TEST_ASSERT(ret == 0, "memcmp failed, ret=%d", ret); kvm_x86_state_cleanup(state); - break; - case 9: - fprintf(stderr, - "GUEST_SYNC(%ld), #NM exception and enable amx\n", uc.args[1]); - break; + } + if (uc.args[1] & TEST_SAVE_RESTORE) { + fprintf(stderr, "GUEST_SYNC #%d, save/restore VM state\n", iter); + state = vcpu_save_state(vcpu); + memset(®s1, 0, sizeof(regs1)); + vcpu_regs_get(vcpu, ®s1); + + kvm_vm_release(vm); + + /* Restore state in a new VM. */ + vcpu = vm_recreate_with_one_vcpu(vm); + vcpu_load_state(vcpu, state); + kvm_x86_state_cleanup(state); + + memset(®s2, 0, sizeof(regs2)); + vcpu_regs_get(vcpu, ®s2); + TEST_ASSERT(!memcmp(®s1, ®s2, sizeof(regs2)), + "Unexpected register values after vcpu_load_state; rdi: %lx rsi: %lx", + (ulong) regs2.rdi, (ulong) regs2.rsi); } break; case UCALL_DONE: @@ -293,22 +307,6 @@ int main(int argc, char *argv[]) TEST_FAIL("Unknown ucall %lu", uc.cmd); } - state = vcpu_save_state(vcpu); - memset(®s1, 0, sizeof(regs1)); - vcpu_regs_get(vcpu, ®s1); - - kvm_vm_release(vm); - - /* Restore state in a new VM. */ - vcpu = vm_recreate_with_one_vcpu(vm); - vcpu_load_state(vcpu, state); - kvm_x86_state_cleanup(state); - - memset(®s2, 0, sizeof(regs2)); - vcpu_regs_get(vcpu, ®s2); - TEST_ASSERT(!memcmp(®s1, ®s2, sizeof(regs2)), - "Unexpected register values after vcpu_load_state; rdi: %lx rsi: %lx", - (ulong) regs2.rdi, (ulong) regs2.rsi); } done: kvm_vm_free(vm); From 522a38f455bffda228e2853ba6dab09ab7a6fcd4 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 31 Dec 2025 16:47:26 +0100 Subject: [PATCH 2051/2333] selftests: kvm: try getting XFD and XSAVE state out of sync commit 0383a8edef396cf0a6884b0be81d62bde60737b0 upstream. The host is allowed to set FPU state that includes a disabled xstate component. Check that this does not cause bad effects. Cc: stable@vger.kernel.org Signed-off-by: Paolo Bonzini Signed-off-by: Greg Kroah-Hartman --- tools/testing/selftests/kvm/x86/amx_test.c | 38 +++++++++++++++++----- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/tools/testing/selftests/kvm/x86/amx_test.c b/tools/testing/selftests/kvm/x86/amx_test.c index 3de4402ac17de..bee56c1f78339 100644 --- a/tools/testing/selftests/kvm/x86/amx_test.c +++ b/tools/testing/selftests/kvm/x86/amx_test.c @@ -125,11 +125,17 @@ static void set_tilecfg(struct tile_config *cfg) } enum { + /* Retrieve TMM0 from guest, stash it for TEST_RESTORE_TILEDATA */ + TEST_SAVE_TILEDATA = 1, + /* Check TMM0 against tiledata */ - TEST_COMPARE_TILEDATA = 1, + TEST_COMPARE_TILEDATA = 2, + + /* Restore TMM0 from earlier save */ + TEST_RESTORE_TILEDATA = 4, /* Full VM save/restore */ - TEST_SAVE_RESTORE = 2, + TEST_SAVE_RESTORE = 8, }; static void __attribute__((__flatten__)) guest_code(struct tile_config *amx_cfg, @@ -150,7 +156,16 @@ static void __attribute__((__flatten__)) guest_code(struct tile_config *amx_cfg, GUEST_SYNC(TEST_SAVE_RESTORE); /* Check save/restore when trap to userspace */ __tileloadd(tiledata); - GUEST_SYNC(TEST_COMPARE_TILEDATA | TEST_SAVE_RESTORE); + GUEST_SYNC(TEST_SAVE_TILEDATA | TEST_COMPARE_TILEDATA | TEST_SAVE_RESTORE); + + /* xfd=0x40000, disable amx tiledata */ + wrmsr(MSR_IA32_XFD, XFEATURE_MASK_XTILE_DATA); + + /* host tries setting tiledata while guest XFD is set */ + GUEST_SYNC(TEST_RESTORE_TILEDATA); + GUEST_SYNC(TEST_SAVE_RESTORE); + + wrmsr(MSR_IA32_XFD, 0); __tilerelease(); GUEST_SYNC(TEST_SAVE_RESTORE); /* @@ -210,10 +225,10 @@ int main(int argc, char *argv[]) struct kvm_vcpu *vcpu; struct kvm_vm *vm; struct kvm_x86_state *state; + struct kvm_x86_state *tile_state = NULL; int xsave_restore_size; vm_vaddr_t amx_cfg, tiledata, xstate; struct ucall uc; - u32 amx_offset; int ret; /* @@ -265,20 +280,27 @@ int main(int argc, char *argv[]) /* NOT REACHED */ case UCALL_SYNC: ++iter; + if (uc.args[1] & TEST_SAVE_TILEDATA) { + fprintf(stderr, "GUEST_SYNC #%d, save tiledata\n", iter); + tile_state = vcpu_save_state(vcpu); + } if (uc.args[1] & TEST_COMPARE_TILEDATA) { fprintf(stderr, "GUEST_SYNC #%d, check TMM0 contents\n", iter); /* Compacted mode, get amx offset by xsave area * size subtract 8K amx size. */ - amx_offset = xsave_restore_size - NUM_TILES*TILE_SIZE; - state = vcpu_save_state(vcpu); - void *amx_start = (void *)state->xsave + amx_offset; + u32 amx_offset = xsave_restore_size - NUM_TILES*TILE_SIZE; + void *amx_start = (void *)tile_state->xsave + amx_offset; void *tiles_data = (void *)addr_gva2hva(vm, tiledata); /* Only check TMM0 register, 1 tile */ ret = memcmp(amx_start, tiles_data, TILE_SIZE); TEST_ASSERT(ret == 0, "memcmp failed, ret=%d", ret); - kvm_x86_state_cleanup(state); + } + if (uc.args[1] & TEST_RESTORE_TILEDATA) { + fprintf(stderr, "GUEST_SYNC #%d, before KVM_SET_XSAVE\n", iter); + vcpu_xsave_set(vcpu, tile_state->xsave); + fprintf(stderr, "GUEST_SYNC #%d, after KVM_SET_XSAVE\n", iter); } if (uc.args[1] & TEST_SAVE_RESTORE) { fprintf(stderr, "GUEST_SYNC #%d, save/restore VM state\n", iter); From 670cd1c2384acd367da438032084429d1c131b2a Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 7 Jan 2026 22:36:42 +0100 Subject: [PATCH 2052/2333] ALSA: pcm: Improve the fix for race of buffer access at PCM OSS layer commit 47c27c9c9c720bc93fdc69605d0ecd9382e99047 upstream. Handle the error code from snd_pcm_buffer_access_lock() in snd_pcm_runtime_buffer_set_silence() function. Found by Alexandros Panagiotou Fixes: 93a81ca06577 ("ALSA: pcm: Fix race of buffer access at PCM OSS layer") Cc: stable@vger.kernel.org # 6.15 Signed-off-by: Jaroslav Kysela Link: https://patch.msgid.link/20260107213642.332954-1-perex@perex.cz Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- include/sound/pcm.h | 2 +- sound/core/oss/pcm_oss.c | 4 +++- sound/core/pcm_native.c | 9 +++++++-- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/include/sound/pcm.h b/include/sound/pcm.h index 58fd6e84f9613..a7860c047503a 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -1402,7 +1402,7 @@ int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream, struct vm_area_s #define snd_pcm_lib_mmap_iomem NULL #endif -void snd_pcm_runtime_buffer_set_silence(struct snd_pcm_runtime *runtime); +int snd_pcm_runtime_buffer_set_silence(struct snd_pcm_runtime *runtime); /** * snd_pcm_limit_isa_dma_size - Get the max size fitting with ISA DMA transfer diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index a82dd155e1d3a..b12df5b5ddfc1 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -1074,7 +1074,9 @@ static int snd_pcm_oss_change_params_locked(struct snd_pcm_substream *substream) runtime->oss.params = 0; runtime->oss.prepare = 1; runtime->oss.buffer_used = 0; - snd_pcm_runtime_buffer_set_silence(runtime); + err = snd_pcm_runtime_buffer_set_silence(runtime); + if (err < 0) + goto failure; runtime->oss.period_frames = snd_pcm_alsa_frames(substream, oss_period_size); diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 68bee40c9adaf..932a9bf98cbc0 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -730,13 +730,18 @@ static void snd_pcm_buffer_access_unlock(struct snd_pcm_runtime *runtime) } /* fill the PCM buffer with the current silence format; called from pcm_oss.c */ -void snd_pcm_runtime_buffer_set_silence(struct snd_pcm_runtime *runtime) +int snd_pcm_runtime_buffer_set_silence(struct snd_pcm_runtime *runtime) { - snd_pcm_buffer_access_lock(runtime); + int err; + + err = snd_pcm_buffer_access_lock(runtime); + if (err < 0) + return err; if (runtime->dma_area) snd_pcm_format_set_silence(runtime->format, runtime->dma_area, bytes_to_samples(runtime, runtime->dma_bytes)); snd_pcm_buffer_access_unlock(runtime); + return 0; } EXPORT_SYMBOL_GPL(snd_pcm_runtime_buffer_set_silence); From 819268882628fccedbf19796a64ea34402b85027 Mon Sep 17 00:00:00 2001 From: Matthew Schwartz Date: Thu, 8 Jan 2026 01:36:50 -0800 Subject: [PATCH 2053/2333] ALSA: hda/tas2781: Skip UEFI calibration on ASUS ROG Xbox Ally X commit b7e26c8bdae70832d7c4b31ec2995b1812a60169 upstream. There is currently an issue with UEFI calibration data parsing for some TAS devices, like the ASUS ROG Xbox Ally X (RC73XA), that causes audio quality issues such as gaps in playback. Until the issue is root caused and fixed, add a quirk to skip using the UEFI calibration data and fall back to using the calibration data provided by the DSP firmware, which restores full speaker functionality on affected devices. Cc: stable@vger.kernel.org # 6.18 Link: https://lore.kernel.org/all/160aef32646c4d5498cbfd624fd683cc@ti.com/ Closes: https://lore.kernel.org/all/0ba100d0-9b6f-4a3b-bffa-61abe1b46cd5@linux.dev/ Suggested-by: Baojun Xu Signed-off-by: Matthew Schwartz Reviewed-by: Antheas Kapenekakis Link: https://patch.msgid.link/20260108093650.1142176-1-matthew.schwartz@linux.dev Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/hda/codecs/side-codecs/tas2781_hda_i2c.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c b/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c index f7a7f216d5865..0e4bda3a544ea 100644 --- a/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c +++ b/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c @@ -60,6 +60,7 @@ struct tas2781_hda_i2c_priv { int (*save_calibration)(struct tas2781_hda *h); int hda_chip_id; + bool skip_calibration; }; static int tas2781_get_i2c_res(struct acpi_resource *ares, void *data) @@ -491,7 +492,8 @@ static void tasdevice_dspfw_init(void *context) /* If calibrated data occurs error, dsp will still works with default * calibrated data inside algo. */ - hda_priv->save_calibration(tas_hda); + if (!hda_priv->skip_calibration) + hda_priv->save_calibration(tas_hda); } static void tasdev_fw_ready(const struct firmware *fmw, void *context) @@ -548,6 +550,7 @@ static int tas2781_hda_bind(struct device *dev, struct device *master, void *master_data) { struct tas2781_hda *tas_hda = dev_get_drvdata(dev); + struct tas2781_hda_i2c_priv *hda_priv = tas_hda->hda_priv; struct hda_component_parent *parent = master_data; struct hda_component *comp; struct hda_codec *codec; @@ -573,6 +576,14 @@ static int tas2781_hda_bind(struct device *dev, struct device *master, break; } + /* + * Using ASUS ROG Xbox Ally X (RC73XA) UEFI calibration data + * causes audio dropouts during playback, use fallback data + * from DSP firmware as a workaround. + */ + if (codec->core.subsystem_id == 0x10431384) + hda_priv->skip_calibration = true; + pm_runtime_get_sync(dev); comp->dev = dev; From ded801af28a99df4bfbfef6d9b1696042b8787f8 Mon Sep 17 00:00:00 2001 From: Zhang Heng Date: Thu, 15 Jan 2026 09:58:44 +0800 Subject: [PATCH 2054/2333] ALSA: hda/realtek: Add quirk for HP Pavilion x360 to enable mute LED commit ab2be3af8c4ea57f779474cd2a2fe8dd4ad537a6 upstream. This quirk enables mute LED on HP Pavilion x360 2-in-1 Laptop 14-ek0xxx, which use ALC245 codec. Link: https://bugzilla.kernel.org/show_bug.cgi?id=220220 Cc: Signed-off-by: Zhang Heng Link: https://patch.msgid.link/20260115015844.3129890-1-zhangheng@kylinos.cn Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/hda/codecs/realtek/alc269.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/hda/codecs/realtek/alc269.c b/sound/hda/codecs/realtek/alc269.c index eb6197d19078c..b5aa8da1e50a8 100644 --- a/sound/hda/codecs/realtek/alc269.c +++ b/sound/hda/codecs/realtek/alc269.c @@ -6529,6 +6529,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x8a2e, "HP Envy 16", ALC287_FIXUP_CS35L41_I2C_2), SND_PCI_QUIRK(0x103c, 0x8a30, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2), SND_PCI_QUIRK(0x103c, 0x8a31, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x103c, 0x8a34, "HP Pavilion x360 2-in-1 Laptop 14-ek0xxx", ALC245_FIXUP_HP_MUTE_LED_COEFBIT), SND_PCI_QUIRK(0x103c, 0x8a4f, "HP Victus 15-fa0xxx (MB 8A4F)", ALC245_FIXUP_HP_MUTE_LED_COEFBIT), SND_PCI_QUIRK(0x103c, 0x8a6e, "HP EDNA 360", ALC287_FIXUP_CS35L41_I2C_4), SND_PCI_QUIRK(0x103c, 0x8a74, "HP ProBook 440 G8 Notebook PC", ALC236_FIXUP_HP_GPIO_LED), From f1718da051282698aa8fa150bebb9724f6389fda Mon Sep 17 00:00:00 2001 From: Nilay Shroff Date: Tue, 13 Jan 2026 12:27:22 +0530 Subject: [PATCH 2055/2333] null_blk: fix kmemleak by releasing references to fault configfs items commit 40b94ec7edbbb867c4e26a1a43d2b898f04b93c5 upstream. When CONFIG_BLK_DEV_NULL_BLK_FAULT_INJECTION is enabled, the null-blk driver sets up fault injection support by creating the timeout_inject, requeue_inject, and init_hctx_fault_inject configfs items as children of the top-level nullbX configfs group. However, when the nullbX device is removed, the references taken to these fault-config configfs items are not released. As a result, kmemleak reports a memory leak, for example: unreferenced object 0xc00000021ff25c40 (size 32): comm "mkdir", pid 10665, jiffies 4322121578 hex dump (first 32 bytes): 69 6e 69 74 5f 68 63 74 78 5f 66 61 75 6c 74 5f init_hctx_fault_ 69 6e 6a 65 63 74 00 88 00 00 00 00 00 00 00 00 inject.......... backtrace (crc 1a018c86): __kmalloc_node_track_caller_noprof+0x494/0xbd8 kvasprintf+0x74/0xf4 config_item_set_name+0xf0/0x104 config_group_init_type_name+0x48/0xfc fault_config_init+0x48/0xf0 0xc0080000180559e4 configfs_mkdir+0x304/0x814 vfs_mkdir+0x49c/0x604 do_mkdirat+0x314/0x3d0 sys_mkdir+0xa0/0xd8 system_call_exception+0x1b0/0x4f0 system_call_vectored_common+0x15c/0x2ec Fix this by explicitly releasing the references to the fault-config configfs items when dropping the reference to the top-level nullbX configfs group. Cc: stable@vger.kernel.org Reviewed-by: Chaitanya Kulkarni Fixes: bb4c19e030f4 ("block: null_blk: make fault-injection dynamically configurable per device") Signed-off-by: Nilay Shroff Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman --- drivers/block/null_blk/main.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/block/null_blk/main.c b/drivers/block/null_blk/main.c index 0ee55f889cfdd..50938881219bc 100644 --- a/drivers/block/null_blk/main.c +++ b/drivers/block/null_blk/main.c @@ -665,12 +665,22 @@ static void nullb_add_fault_config(struct nullb_device *dev) configfs_add_default_group(&dev->init_hctx_fault_config.group, &dev->group); } +static void nullb_del_fault_config(struct nullb_device *dev) +{ + config_item_put(&dev->init_hctx_fault_config.group.cg_item); + config_item_put(&dev->requeue_config.group.cg_item); + config_item_put(&dev->timeout_config.group.cg_item); +} + #else static void nullb_add_fault_config(struct nullb_device *dev) { } +static void nullb_del_fault_config(struct nullb_device *dev) +{ +} #endif static struct @@ -702,7 +712,7 @@ nullb_group_drop_item(struct config_group *group, struct config_item *item) null_del_dev(dev->nullb); mutex_unlock(&lock); } - + nullb_del_fault_config(dev); config_item_put(item); } From 9f669a38ca70839229b7ba0f851820850a2fe1f7 Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Tue, 23 Dec 2025 21:21:39 +0100 Subject: [PATCH 2056/2333] can: gs_usb: gs_usb_receive_bulk_callback(): fix URB memory leak commit 7352e1d5932a0e777e39fa4b619801191f57e603 upstream. In gs_can_open(), the URBs for USB-in transfers are allocated, added to the parent->rx_submitted anchor and submitted. In the complete callback gs_usb_receive_bulk_callback(), the URB is processed and resubmitted. In gs_can_close() the URBs are freed by calling usb_kill_anchored_urbs(parent->rx_submitted). However, this does not take into account that the USB framework unanchors the URB before the complete function is called. This means that once an in-URB has been completed, it is no longer anchored and is ultimately not released in gs_can_close(). Fix the memory leak by anchoring the URB in the gs_usb_receive_bulk_callback() to the parent->rx_submitted anchor. Fixes: d08e973a77d1 ("can: gs_usb: Added support for the GS_USB CAN devices") Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20260105-gs_usb-fix-memory-leak-v2-1-cc6ed6438034@pengutronix.de Signed-off-by: Marc Kleine-Budde Signed-off-by: Greg Kroah-Hartman --- drivers/net/can/usb/gs_usb.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/can/usb/gs_usb.c b/drivers/net/can/usb/gs_usb.c index db6885bcba28d..b14b132ad8e6a 100644 --- a/drivers/net/can/usb/gs_usb.c +++ b/drivers/net/can/usb/gs_usb.c @@ -751,6 +751,8 @@ static void gs_usb_receive_bulk_callback(struct urb *urb) hf, parent->hf_size_rx, gs_usb_receive_bulk_callback, parent); + usb_anchor_urb(urb, &parent->rx_submitted); + rc = usb_submit_urb(urb, GFP_ATOMIC); /* USB failure take down all interfaces */ From d922e7c5bb6424ea3b2c27d628af3cbbfb786d17 Mon Sep 17 00:00:00 2001 From: Ondrej Ille Date: Mon, 5 Jan 2026 12:16:20 +0100 Subject: [PATCH 2057/2333] can: ctucanfd: fix SSP_SRC in cases when bit-rate is higher than 1 MBit. commit e707c591a139d1bfa4ddc83036fc820ca006a140 upstream. The Secondary Sample Point Source field has been set to an incorrect value by some mistake in the past 0b01 - SSP_SRC_NO_SSP - SSP is not used. for data bitrates above 1 MBit/s. The correct/default value already used for lower bitrates is 0b00 - SSP_SRC_MEAS_N_OFFSET - SSP position = TRV_DELAY (Measured Transmitter delay) + SSP_OFFSET. The related configuration register structure is described in section 3.1.46 SSP_CFG of the CTU CAN FD IP CORE Datasheet. The analysis leading to the proper configuration is described in section 2.8.3 Secondary sampling point of the datasheet. The change has been tested on AMD/Xilinx Zynq with the next CTU CN FD IP core versions: - 2.6 aka master in the "integration with Zynq-7000 system" test 6.12.43-rt12+ #1 SMP PREEMPT_RT kernel with CTU CAN FD git driver (change already included in the driver repo) - older 2.5 snapshot with mainline kernels with this patch applied locally in the multiple CAN latency tester nightly runs 6.18.0-rc4-rt3-dut #1 SMP PREEMPT_RT 6.19.0-rc3-dut The logs, the datasheet and sources are available at https://canbus.pages.fel.cvut.cz/ Signed-off-by: Ondrej Ille Signed-off-by: Pavel Pisa Link: https://patch.msgid.link/20260105111620.16580-1-pisa@fel.cvut.cz Fixes: 2dcb8e8782d8 ("can: ctucanfd: add support for CTU CAN FD open-source IP core - bus independent part.") Cc: stable@vger.kernel.org Signed-off-by: Marc Kleine-Budde Signed-off-by: Greg Kroah-Hartman --- drivers/net/can/ctucanfd/ctucanfd_base.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/can/ctucanfd/ctucanfd_base.c b/drivers/net/can/ctucanfd/ctucanfd_base.c index 8bd3f0fc385c3..33a5ec4346278 100644 --- a/drivers/net/can/ctucanfd/ctucanfd_base.c +++ b/drivers/net/can/ctucanfd/ctucanfd_base.c @@ -310,7 +310,7 @@ static int ctucan_set_secondary_sample_point(struct net_device *ndev) } ssp_cfg = FIELD_PREP(REG_TRV_DELAY_SSP_OFFSET, ssp_offset); - ssp_cfg |= FIELD_PREP(REG_TRV_DELAY_SSP_SRC, 0x1); + ssp_cfg |= FIELD_PREP(REG_TRV_DELAY_SSP_SRC, 0x0); } ctucan_write32(priv, CTUCANFD_TRV_DELAY, ssp_cfg); From 6121b7564c725b632ffe4764abe85aa239d37703 Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Wed, 14 Jan 2026 00:28:47 +0900 Subject: [PATCH 2058/2333] net: can: j1939: j1939_xtp_rx_rts_session_active(): deactivate session upon receiving the second rts commit 1809c82aa073a11b7d335ae932d81ce51a588a4a upstream. Since j1939_session_deactivate_activate_next() in j1939_tp_rxtimer() is called only when the timer is enabled, we need to call j1939_session_deactivate_activate_next() if we cancelled the timer. Otherwise, refcount for j1939_session leaks, which will later appear as | unregister_netdevice: waiting for vcan0 to become free. Usage count = 2. problem. Reported-by: syzbot Closes: https://syzkaller.appspot.com/bug?extid=881d65229ca4f9ae8c84 Signed-off-by: Tetsuo Handa Tested-by: Oleksij Rempel Acked-by: Oleksij Rempel Fixes: 9d71dd0c7009 ("can: add support of SAE J1939 protocol") Link: https://patch.msgid.link/b1212653-8fa1-44e1-be9d-12f950fb3a07@I-love.SAKURA.ne.jp Cc: stable@vger.kernel.org Signed-off-by: Marc Kleine-Budde Signed-off-by: Greg Kroah-Hartman --- net/can/j1939/transport.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/net/can/j1939/transport.c b/net/can/j1939/transport.c index 613a911dda100..8656ab388c83e 100644 --- a/net/can/j1939/transport.c +++ b/net/can/j1939/transport.c @@ -1695,8 +1695,16 @@ static int j1939_xtp_rx_rts_session_active(struct j1939_session *session, j1939_session_timers_cancel(session); j1939_session_cancel(session, J1939_XTP_ABORT_BUSY); - if (session->transmission) + if (session->transmission) { j1939_session_deactivate_activate_next(session); + } else if (session->state == J1939_SESSION_WAITING_ABORT) { + /* Force deactivation for the receiver. + * If we rely on the timer starting in j1939_session_cancel, + * a second RTS call here will cancel that timer and fail + * to restart it because the state is already WAITING_ABORT. + */ + j1939_session_deactivate_activate_next(session); + } return -EBUSY; } From 6ca76572c6049787e4487953802d95d097292eb5 Mon Sep 17 00:00:00 2001 From: Lorenzo Stoakes Date: Mon, 5 Jan 2026 20:11:48 +0000 Subject: [PATCH 2059/2333] tools/testing/selftests: add tests for !tgt, src mremap() merges commit 0ace8f2db6b3b4b0677e559d1a7ab7fd625d61ec upstream. Test that mremap()'ing a VMA into a position such that the target VMA on merge is unfaulted and the source faulted is correctly performed. We cover 4 cases: 1. Previous VMA unfaulted: copied -----| v |-----------|.............| | unfaulted |(faulted VMA)| |-----------|.............| prev target = prev, expand prev to cover. 2. Next VMA unfaulted: copied -----| v |.............|-----------| |(faulted VMA)| unfaulted | |.............|-----------| next target = next, expand next to cover. 3. Both adjacent VMAs unfaulted: copied -----| v |-----------|.............|-----------| | unfaulted |(faulted VMA)| unfaulted | |-----------|.............|-----------| prev next target = prev, expand prev to cover. 4. prev unfaulted, next faulted: copied -----| v |-----------|.............|-----------| | unfaulted |(faulted VMA)| faulted | |-----------|.............|-----------| prev next target = prev, expand prev to cover. Essentially equivalent to 3, but with additional requirement that next's anon_vma is the same as the copied VMA's. Each of these are performed with MREMAP_DONTUNMAP set, which will cause a KASAN assert for UAF or an assert on zero refcount anon_vma if a bug exists with correctly propagating anon_vma state in each scenario. Link: https://lkml.kernel.org/r/f903af2930c7c2c6e0948c886b58d0f42d8e8ba3.1767638272.git.lorenzo.stoakes@oracle.com Fixes: 879bca0a2c4f ("mm/vma: fix incorrectly disallowed anonymous VMA merges") Signed-off-by: Lorenzo Stoakes Cc: David Hildenbrand (Red Hat) Cc: Jann Horn Cc: Jeongjun Park Cc: Liam Howlett Cc: Pedro Falcato Cc: Rik van Riel Cc: Vlastimil Babka Cc: Yeoreum Yun Cc: Harry Yoo Cc: Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- tools/testing/selftests/mm/merge.c | 232 +++++++++++++++++++++++++++++ 1 file changed, 232 insertions(+) diff --git a/tools/testing/selftests/mm/merge.c b/tools/testing/selftests/mm/merge.c index cc4253f47f10b..63cb0e8b937ae 100644 --- a/tools/testing/selftests/mm/merge.c +++ b/tools/testing/selftests/mm/merge.c @@ -1171,4 +1171,236 @@ TEST_F(merge, mremap_correct_placed_faulted) ASSERT_EQ(procmap->query.vma_end, (unsigned long)ptr + 15 * page_size); } +TEST_F(merge, mremap_faulted_to_unfaulted_prev) +{ + struct procmap_fd *procmap = &self->procmap; + unsigned int page_size = self->page_size; + char *ptr_a, *ptr_b; + + /* + * mremap() such that A and B merge: + * + * |------------| + * | \ | + * |-----------| | / |---------| + * | unfaulted | v \ | faulted | + * |-----------| / |---------| + * B \ A + */ + + /* Map VMA A into place. */ + ptr_a = mmap(&self->carveout[page_size + 3 * page_size], + 3 * page_size, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON | MAP_FIXED, -1, 0); + ASSERT_NE(ptr_a, MAP_FAILED); + /* Fault it in. */ + ptr_a[0] = 'x'; + + /* + * Now move it out of the way so we can place VMA B in position, + * unfaulted. + */ + ptr_a = mremap(ptr_a, 3 * page_size, 3 * page_size, + MREMAP_FIXED | MREMAP_MAYMOVE, &self->carveout[20 * page_size]); + ASSERT_NE(ptr_a, MAP_FAILED); + + /* Map VMA B into place. */ + ptr_b = mmap(&self->carveout[page_size], 3 * page_size, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON | MAP_FIXED, -1, 0); + ASSERT_NE(ptr_b, MAP_FAILED); + + /* + * Now move VMA A into position with MREMAP_DONTUNMAP to catch incorrect + * anon_vma propagation. + */ + ptr_a = mremap(ptr_a, 3 * page_size, 3 * page_size, + MREMAP_FIXED | MREMAP_MAYMOVE | MREMAP_DONTUNMAP, + &self->carveout[page_size + 3 * page_size]); + ASSERT_NE(ptr_a, MAP_FAILED); + + /* The VMAs should have merged. */ + ASSERT_TRUE(find_vma_procmap(procmap, ptr_b)); + ASSERT_EQ(procmap->query.vma_start, (unsigned long)ptr_b); + ASSERT_EQ(procmap->query.vma_end, (unsigned long)ptr_b + 6 * page_size); +} + +TEST_F(merge, mremap_faulted_to_unfaulted_next) +{ + struct procmap_fd *procmap = &self->procmap; + unsigned int page_size = self->page_size; + char *ptr_a, *ptr_b; + + /* + * mremap() such that A and B merge: + * + * |---------------------------| + * | \ | + * | |-----------| / |---------| + * v | unfaulted | \ | faulted | + * |-----------| / |---------| + * B \ A + * + * Then unmap VMA A to trigger the bug. + */ + + /* Map VMA A into place. */ + ptr_a = mmap(&self->carveout[page_size], 3 * page_size, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON | MAP_FIXED, -1, 0); + ASSERT_NE(ptr_a, MAP_FAILED); + /* Fault it in. */ + ptr_a[0] = 'x'; + + /* + * Now move it out of the way so we can place VMA B in position, + * unfaulted. + */ + ptr_a = mremap(ptr_a, 3 * page_size, 3 * page_size, + MREMAP_FIXED | MREMAP_MAYMOVE, &self->carveout[20 * page_size]); + ASSERT_NE(ptr_a, MAP_FAILED); + + /* Map VMA B into place. */ + ptr_b = mmap(&self->carveout[page_size + 3 * page_size], 3 * page_size, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON | MAP_FIXED, -1, 0); + ASSERT_NE(ptr_b, MAP_FAILED); + + /* + * Now move VMA A into position with MREMAP_DONTUNMAP to catch incorrect + * anon_vma propagation. + */ + ptr_a = mremap(ptr_a, 3 * page_size, 3 * page_size, + MREMAP_FIXED | MREMAP_MAYMOVE | MREMAP_DONTUNMAP, + &self->carveout[page_size]); + ASSERT_NE(ptr_a, MAP_FAILED); + + /* The VMAs should have merged. */ + ASSERT_TRUE(find_vma_procmap(procmap, ptr_a)); + ASSERT_EQ(procmap->query.vma_start, (unsigned long)ptr_a); + ASSERT_EQ(procmap->query.vma_end, (unsigned long)ptr_a + 6 * page_size); +} + +TEST_F(merge, mremap_faulted_to_unfaulted_prev_unfaulted_next) +{ + struct procmap_fd *procmap = &self->procmap; + unsigned int page_size = self->page_size; + char *ptr_a, *ptr_b, *ptr_c; + + /* + * mremap() with MREMAP_DONTUNMAP such that A, B and C merge: + * + * |---------------------------| + * | \ | + * |-----------| | |-----------| / |---------| + * | unfaulted | v | unfaulted | \ | faulted | + * |-----------| |-----------| / |---------| + * A C \ B + */ + + /* Map VMA B into place. */ + ptr_b = mmap(&self->carveout[page_size + 3 * page_size], 3 * page_size, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON | MAP_FIXED, -1, 0); + ASSERT_NE(ptr_b, MAP_FAILED); + /* Fault it in. */ + ptr_b[0] = 'x'; + + /* + * Now move it out of the way so we can place VMAs A, C in position, + * unfaulted. + */ + ptr_b = mremap(ptr_b, 3 * page_size, 3 * page_size, + MREMAP_FIXED | MREMAP_MAYMOVE, &self->carveout[20 * page_size]); + ASSERT_NE(ptr_b, MAP_FAILED); + + /* Map VMA A into place. */ + + ptr_a = mmap(&self->carveout[page_size], 3 * page_size, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON | MAP_FIXED, -1, 0); + ASSERT_NE(ptr_a, MAP_FAILED); + + /* Map VMA C into place. */ + ptr_c = mmap(&self->carveout[page_size + 3 * page_size + 3 * page_size], + 3 * page_size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON | MAP_FIXED, -1, 0); + ASSERT_NE(ptr_c, MAP_FAILED); + + /* + * Now move VMA B into position with MREMAP_DONTUNMAP to catch incorrect + * anon_vma propagation. + */ + ptr_b = mremap(ptr_b, 3 * page_size, 3 * page_size, + MREMAP_FIXED | MREMAP_MAYMOVE | MREMAP_DONTUNMAP, + &self->carveout[page_size + 3 * page_size]); + ASSERT_NE(ptr_b, MAP_FAILED); + + /* The VMAs should have merged. */ + ASSERT_TRUE(find_vma_procmap(procmap, ptr_a)); + ASSERT_EQ(procmap->query.vma_start, (unsigned long)ptr_a); + ASSERT_EQ(procmap->query.vma_end, (unsigned long)ptr_a + 9 * page_size); +} + +TEST_F(merge, mremap_faulted_to_unfaulted_prev_faulted_next) +{ + struct procmap_fd *procmap = &self->procmap; + unsigned int page_size = self->page_size; + char *ptr_a, *ptr_b, *ptr_bc; + + /* + * mremap() with MREMAP_DONTUNMAP such that A, B and C merge: + * + * |---------------------------| + * | \ | + * |-----------| | |-----------| / |---------| + * | unfaulted | v | faulted | \ | faulted | + * |-----------| |-----------| / |---------| + * A C \ B + */ + + /* + * Map VMA B and C into place. We have to map them together so their + * anon_vma is the same and the vma->vm_pgoff's are correctly aligned. + */ + ptr_bc = mmap(&self->carveout[page_size + 3 * page_size], + 3 * page_size + 3 * page_size, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON | MAP_FIXED, -1, 0); + ASSERT_NE(ptr_bc, MAP_FAILED); + + /* Fault it in. */ + ptr_bc[0] = 'x'; + + /* + * Now move VMA B out the way (splitting VMA BC) so we can place VMA A + * in position, unfaulted, and leave the remainder of the VMA we just + * moved in place, faulted, as VMA C. + */ + ptr_b = mremap(ptr_bc, 3 * page_size, 3 * page_size, + MREMAP_FIXED | MREMAP_MAYMOVE, &self->carveout[20 * page_size]); + ASSERT_NE(ptr_b, MAP_FAILED); + + /* Map VMA A into place. */ + ptr_a = mmap(&self->carveout[page_size], 3 * page_size, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON | MAP_FIXED, -1, 0); + ASSERT_NE(ptr_a, MAP_FAILED); + + /* + * Now move VMA B into position with MREMAP_DONTUNMAP to catch incorrect + * anon_vma propagation. + */ + ptr_b = mremap(ptr_b, 3 * page_size, 3 * page_size, + MREMAP_FIXED | MREMAP_MAYMOVE | MREMAP_DONTUNMAP, + &self->carveout[page_size + 3 * page_size]); + ASSERT_NE(ptr_b, MAP_FAILED); + + /* The VMAs should have merged. */ + ASSERT_TRUE(find_vma_procmap(procmap, ptr_a)); + ASSERT_EQ(procmap->query.vma_start, (unsigned long)ptr_a); + ASSERT_EQ(procmap->query.vma_end, (unsigned long)ptr_a + 9 * page_size); +} + TEST_HARNESS_MAIN From 3a1c3cd770f48cc437e7b42cb7ed3c02377a1d34 Mon Sep 17 00:00:00 2001 From: Lorenzo Stoakes Date: Mon, 5 Jan 2026 20:11:50 +0000 Subject: [PATCH 2060/2333] tools/testing/selftests: add forked (un)/faulted VMA merge tests commit fb39444732f02c32a8312c168d97e33d872c14d3 upstream. Now we correctly handle forked faulted/unfaulted merge on mremap(), exhaustively assert that we handle this correctly. Do this in the less duplicative way by adding a new merge_with_fork fixture and forked/unforked variants, and abstract the forking logic as necessary to avoid code duplication with this also. Link: https://lkml.kernel.org/r/1daf76d89fdb9d96f38a6a0152d8f3c2e9e30ac7.1767638272.git.lorenzo.stoakes@oracle.com Fixes: 879bca0a2c4f ("mm/vma: fix incorrectly disallowed anonymous VMA merges") Signed-off-by: Lorenzo Stoakes Cc: David Hildenbrand (Red Hat) Cc: Jann Horn Cc: Jeongjun Park Cc: Liam Howlett Cc: Pedro Falcato Cc: Rik van Riel Cc: Vlastimil Babka Cc: Yeoreum Yun Cc: Harry Yoo Cc: Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- tools/testing/selftests/mm/merge.c | 180 ++++++++++++++++++++++------- 1 file changed, 139 insertions(+), 41 deletions(-) diff --git a/tools/testing/selftests/mm/merge.c b/tools/testing/selftests/mm/merge.c index 63cb0e8b937ae..cd0e6cc06a025 100644 --- a/tools/testing/selftests/mm/merge.c +++ b/tools/testing/selftests/mm/merge.c @@ -22,12 +22,37 @@ FIXTURE(merge) struct procmap_fd procmap; }; +static char *map_carveout(unsigned int page_size) +{ + return mmap(NULL, 30 * page_size, PROT_NONE, + MAP_ANON | MAP_PRIVATE, -1, 0); +} + +static pid_t do_fork(struct procmap_fd *procmap) +{ + pid_t pid = fork(); + + if (pid == -1) + return -1; + if (pid != 0) { + wait(NULL); + return pid; + } + + /* Reopen for child. */ + if (close_procmap(procmap)) + return -1; + if (open_self_procmap(procmap)) + return -1; + + return 0; +} + FIXTURE_SETUP(merge) { self->page_size = psize(); /* Carve out PROT_NONE region to map over. */ - self->carveout = mmap(NULL, 30 * self->page_size, PROT_NONE, - MAP_ANON | MAP_PRIVATE, -1, 0); + self->carveout = map_carveout(self->page_size); ASSERT_NE(self->carveout, MAP_FAILED); /* Setup PROCMAP_QUERY interface. */ ASSERT_EQ(open_self_procmap(&self->procmap), 0); @@ -36,7 +61,8 @@ FIXTURE_SETUP(merge) FIXTURE_TEARDOWN(merge) { ASSERT_EQ(munmap(self->carveout, 30 * self->page_size), 0); - ASSERT_EQ(close_procmap(&self->procmap), 0); + /* May fail for parent of forked process. */ + close_procmap(&self->procmap); /* * Clear unconditionally, as some tests set this. It is no issue if this * fails (KSM may be disabled for instance). @@ -44,6 +70,44 @@ FIXTURE_TEARDOWN(merge) prctl(PR_SET_MEMORY_MERGE, 0, 0, 0, 0); } +FIXTURE(merge_with_fork) +{ + unsigned int page_size; + char *carveout; + struct procmap_fd procmap; +}; + +FIXTURE_VARIANT(merge_with_fork) +{ + bool forked; +}; + +FIXTURE_VARIANT_ADD(merge_with_fork, forked) +{ + .forked = true, +}; + +FIXTURE_VARIANT_ADD(merge_with_fork, unforked) +{ + .forked = false, +}; + +FIXTURE_SETUP(merge_with_fork) +{ + self->page_size = psize(); + self->carveout = map_carveout(self->page_size); + ASSERT_NE(self->carveout, MAP_FAILED); + ASSERT_EQ(open_self_procmap(&self->procmap), 0); +} + +FIXTURE_TEARDOWN(merge_with_fork) +{ + ASSERT_EQ(munmap(self->carveout, 30 * self->page_size), 0); + ASSERT_EQ(close_procmap(&self->procmap), 0); + /* See above. */ + prctl(PR_SET_MEMORY_MERGE, 0, 0, 0, 0); +} + TEST_F(merge, mprotect_unfaulted_left) { unsigned int page_size = self->page_size; @@ -322,8 +386,8 @@ TEST_F(merge, forked_target_vma) unsigned int page_size = self->page_size; char *carveout = self->carveout; struct procmap_fd *procmap = &self->procmap; - pid_t pid; char *ptr, *ptr2; + pid_t pid; int i; /* @@ -344,19 +408,10 @@ TEST_F(merge, forked_target_vma) */ ptr[0] = 'x'; - pid = fork(); + pid = do_fork(&self->procmap); ASSERT_NE(pid, -1); - - if (pid != 0) { - wait(NULL); + if (pid != 0) return; - } - - /* Child process below: */ - - /* Reopen for child. */ - ASSERT_EQ(close_procmap(&self->procmap), 0); - ASSERT_EQ(open_self_procmap(&self->procmap), 0); /* unCOWing everything does not cause the AVC to go away. */ for (i = 0; i < 5 * page_size; i += page_size) @@ -386,8 +441,8 @@ TEST_F(merge, forked_source_vma) unsigned int page_size = self->page_size; char *carveout = self->carveout; struct procmap_fd *procmap = &self->procmap; - pid_t pid; char *ptr, *ptr2; + pid_t pid; int i; /* @@ -408,19 +463,10 @@ TEST_F(merge, forked_source_vma) */ ptr[0] = 'x'; - pid = fork(); + pid = do_fork(&self->procmap); ASSERT_NE(pid, -1); - - if (pid != 0) { - wait(NULL); + if (pid != 0) return; - } - - /* Child process below: */ - - /* Reopen for child. */ - ASSERT_EQ(close_procmap(&self->procmap), 0); - ASSERT_EQ(open_self_procmap(&self->procmap), 0); /* unCOWing everything does not cause the AVC to go away. */ for (i = 0; i < 5 * page_size; i += page_size) @@ -1171,10 +1217,11 @@ TEST_F(merge, mremap_correct_placed_faulted) ASSERT_EQ(procmap->query.vma_end, (unsigned long)ptr + 15 * page_size); } -TEST_F(merge, mremap_faulted_to_unfaulted_prev) +TEST_F(merge_with_fork, mremap_faulted_to_unfaulted_prev) { struct procmap_fd *procmap = &self->procmap; unsigned int page_size = self->page_size; + unsigned long offset; char *ptr_a, *ptr_b; /* @@ -1197,6 +1244,14 @@ TEST_F(merge, mremap_faulted_to_unfaulted_prev) /* Fault it in. */ ptr_a[0] = 'x'; + if (variant->forked) { + pid_t pid = do_fork(&self->procmap); + + ASSERT_NE(pid, -1); + if (pid != 0) + return; + } + /* * Now move it out of the way so we can place VMA B in position, * unfaulted. @@ -1220,16 +1275,19 @@ TEST_F(merge, mremap_faulted_to_unfaulted_prev) &self->carveout[page_size + 3 * page_size]); ASSERT_NE(ptr_a, MAP_FAILED); - /* The VMAs should have merged. */ + /* The VMAs should have merged, if not forked. */ ASSERT_TRUE(find_vma_procmap(procmap, ptr_b)); ASSERT_EQ(procmap->query.vma_start, (unsigned long)ptr_b); - ASSERT_EQ(procmap->query.vma_end, (unsigned long)ptr_b + 6 * page_size); + + offset = variant->forked ? 3 * page_size : 6 * page_size; + ASSERT_EQ(procmap->query.vma_end, (unsigned long)ptr_b + offset); } -TEST_F(merge, mremap_faulted_to_unfaulted_next) +TEST_F(merge_with_fork, mremap_faulted_to_unfaulted_next) { struct procmap_fd *procmap = &self->procmap; unsigned int page_size = self->page_size; + unsigned long offset; char *ptr_a, *ptr_b; /* @@ -1253,6 +1311,14 @@ TEST_F(merge, mremap_faulted_to_unfaulted_next) /* Fault it in. */ ptr_a[0] = 'x'; + if (variant->forked) { + pid_t pid = do_fork(&self->procmap); + + ASSERT_NE(pid, -1); + if (pid != 0) + return; + } + /* * Now move it out of the way so we can place VMA B in position, * unfaulted. @@ -1276,16 +1342,18 @@ TEST_F(merge, mremap_faulted_to_unfaulted_next) &self->carveout[page_size]); ASSERT_NE(ptr_a, MAP_FAILED); - /* The VMAs should have merged. */ + /* The VMAs should have merged, if not forked. */ ASSERT_TRUE(find_vma_procmap(procmap, ptr_a)); ASSERT_EQ(procmap->query.vma_start, (unsigned long)ptr_a); - ASSERT_EQ(procmap->query.vma_end, (unsigned long)ptr_a + 6 * page_size); + offset = variant->forked ? 3 * page_size : 6 * page_size; + ASSERT_EQ(procmap->query.vma_end, (unsigned long)ptr_a + offset); } -TEST_F(merge, mremap_faulted_to_unfaulted_prev_unfaulted_next) +TEST_F(merge_with_fork, mremap_faulted_to_unfaulted_prev_unfaulted_next) { struct procmap_fd *procmap = &self->procmap; unsigned int page_size = self->page_size; + unsigned long offset; char *ptr_a, *ptr_b, *ptr_c; /* @@ -1307,6 +1375,14 @@ TEST_F(merge, mremap_faulted_to_unfaulted_prev_unfaulted_next) /* Fault it in. */ ptr_b[0] = 'x'; + if (variant->forked) { + pid_t pid = do_fork(&self->procmap); + + ASSERT_NE(pid, -1); + if (pid != 0) + return; + } + /* * Now move it out of the way so we can place VMAs A, C in position, * unfaulted. @@ -1337,13 +1413,21 @@ TEST_F(merge, mremap_faulted_to_unfaulted_prev_unfaulted_next) &self->carveout[page_size + 3 * page_size]); ASSERT_NE(ptr_b, MAP_FAILED); - /* The VMAs should have merged. */ + /* The VMAs should have merged, if not forked. */ ASSERT_TRUE(find_vma_procmap(procmap, ptr_a)); ASSERT_EQ(procmap->query.vma_start, (unsigned long)ptr_a); - ASSERT_EQ(procmap->query.vma_end, (unsigned long)ptr_a + 9 * page_size); + offset = variant->forked ? 3 * page_size : 9 * page_size; + ASSERT_EQ(procmap->query.vma_end, (unsigned long)ptr_a + offset); + + /* If forked, B and C should also not have merged. */ + if (variant->forked) { + ASSERT_TRUE(find_vma_procmap(procmap, ptr_b)); + ASSERT_EQ(procmap->query.vma_start, (unsigned long)ptr_b); + ASSERT_EQ(procmap->query.vma_end, (unsigned long)ptr_b + 3 * page_size); + } } -TEST_F(merge, mremap_faulted_to_unfaulted_prev_faulted_next) +TEST_F(merge_with_fork, mremap_faulted_to_unfaulted_prev_faulted_next) { struct procmap_fd *procmap = &self->procmap; unsigned int page_size = self->page_size; @@ -1373,6 +1457,14 @@ TEST_F(merge, mremap_faulted_to_unfaulted_prev_faulted_next) /* Fault it in. */ ptr_bc[0] = 'x'; + if (variant->forked) { + pid_t pid = do_fork(&self->procmap); + + ASSERT_NE(pid, -1); + if (pid != 0) + return; + } + /* * Now move VMA B out the way (splitting VMA BC) so we can place VMA A * in position, unfaulted, and leave the remainder of the VMA we just @@ -1397,10 +1489,16 @@ TEST_F(merge, mremap_faulted_to_unfaulted_prev_faulted_next) &self->carveout[page_size + 3 * page_size]); ASSERT_NE(ptr_b, MAP_FAILED); - /* The VMAs should have merged. */ - ASSERT_TRUE(find_vma_procmap(procmap, ptr_a)); - ASSERT_EQ(procmap->query.vma_start, (unsigned long)ptr_a); - ASSERT_EQ(procmap->query.vma_end, (unsigned long)ptr_a + 9 * page_size); + /* The VMAs should have merged. A,B,C if unforked, B, C if forked. */ + if (variant->forked) { + ASSERT_TRUE(find_vma_procmap(procmap, ptr_b)); + ASSERT_EQ(procmap->query.vma_start, (unsigned long)ptr_b); + ASSERT_EQ(procmap->query.vma_end, (unsigned long)ptr_b + 6 * page_size); + } else { + ASSERT_TRUE(find_vma_procmap(procmap, ptr_a)); + ASSERT_EQ(procmap->query.vma_start, (unsigned long)ptr_a); + ASSERT_EQ(procmap->query.vma_end, (unsigned long)ptr_a + 9 * page_size); + } } TEST_HARNESS_MAIN From ab09a7816c746376e8cf4cc37386c0f07962154f Mon Sep 17 00:00:00 2001 From: Lorenzo Stoakes Date: Tue, 6 Jan 2026 15:45:47 +0000 Subject: [PATCH 2061/2333] tools/testing/selftests: fix gup_longterm for unknown fs commit 21c68ad1d9771d331198cc73cbf6e908d7915f35 upstream. Commit 66bce7afbaca ("selftests/mm: fix test result reporting in gup_longterm") introduced a small bug causing unknown filesystems to always result in a test failure. This is because do_test() was updated to use a common reporting path, but this case appears to have been missed. This is problematic for e.g. virtme-ng which uses an overlayfs file system, causing gup_longterm to appear to fail each time due to a test count mismatch: # Planned tests != run tests (50 != 46) # Totals: pass:24 fail:0 xfail:0 xpass:0 skip:22 error:0 The fix is to simply change the return into a break. Link: https://lkml.kernel.org/r/20260106154547.214907-1-lorenzo.stoakes@oracle.com Fixes: 66bce7afbaca ("selftests/mm: fix test result reporting in gup_longterm") Signed-off-by: Lorenzo Stoakes Reviewed-by: David Hildenbrand (Red Hat) Cc: Jason Gunthorpe Cc: John Hubbard Cc: Liam Howlett Cc: "Liam R. Howlett" Cc: Mark Brown Cc: Michal Hocko Cc: Mike Rapoport Cc: Peter Xu Cc: Shuah Khan Cc: Suren Baghdasaryan Cc: Vlastimil Babka Cc: Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- tools/testing/selftests/mm/gup_longterm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/mm/gup_longterm.c b/tools/testing/selftests/mm/gup_longterm.c index 268dadb8ce438..e15fdd5c62d68 100644 --- a/tools/testing/selftests/mm/gup_longterm.c +++ b/tools/testing/selftests/mm/gup_longterm.c @@ -179,7 +179,7 @@ static void do_test(int fd, size_t size, enum test_type type, bool shared) if (rw && shared && fs_is_unknown(fs_type)) { ksft_print_msg("Unknown filesystem\n"); result = KSFT_SKIP; - return; + break; } /* * R/O pinning or pinning in a private mapping is always From 9aef476717994e96dadfb359641c4b82b521aa36 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Tue, 13 Jan 2026 07:22:42 -0800 Subject: [PATCH 2062/2333] ftrace: Do not over-allocate ftrace memory commit be55257fab181b93af38f8c4b1b3cb453a78d742 upstream. The pg_remaining calculation in ftrace_process_locs() assumes that ENTRIES_PER_PAGE multiplied by 2^order equals the actual capacity of the allocated page group. However, ENTRIES_PER_PAGE is PAGE_SIZE / ENTRY_SIZE (integer division). When PAGE_SIZE is not a multiple of ENTRY_SIZE (e.g. 4096 / 24 = 170 with remainder 16), high-order allocations (like 256 pages) have significantly more capacity than 256 * 170. This leads to pg_remaining being underestimated, which in turn makes skip (derived from skipped - pg_remaining) larger than expected, causing the WARN(skip != remaining) to trigger. Extra allocated pages for ftrace: 2 with 654 skipped WARNING: CPU: 0 PID: 0 at kernel/trace/ftrace.c:7295 ftrace_process_locs+0x5bf/0x5e0 A similar problem in ftrace_allocate_records() can result in allocating too many pages. This can trigger the second warning in ftrace_process_locs(). Extra allocated pages for ftrace WARNING: CPU: 0 PID: 0 at kernel/trace/ftrace.c:7276 ftrace_process_locs+0x548/0x580 Use the actual capacity of a page group to determine the number of pages to allocate. Have ftrace_allocate_pages() return the number of allocated pages to avoid having to calculate it. Use the actual page group capacity when validating the number of unused pages due to skipped entries. Drop the definition of ENTRIES_PER_PAGE since it is no longer used. Cc: stable@vger.kernel.org Fixes: 4a3efc6baff93 ("ftrace: Update the mcount_loc check of skipped entries") Link: https://patch.msgid.link/20260113152243.3557219-1-linux@roeck-us.net Signed-off-by: Guenter Roeck Signed-off-by: Steven Rostedt (Google) Signed-off-by: Greg Kroah-Hartman --- kernel/trace/ftrace.c | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 59cfacb8a5bbd..e95408a47c1d0 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -1122,7 +1122,6 @@ struct ftrace_page { }; #define ENTRY_SIZE sizeof(struct dyn_ftrace) -#define ENTRIES_PER_PAGE (PAGE_SIZE / ENTRY_SIZE) static struct ftrace_page *ftrace_pages_start; static struct ftrace_page *ftrace_pages; @@ -3808,7 +3807,8 @@ static int ftrace_update_code(struct module *mod, struct ftrace_page *new_pgs) return 0; } -static int ftrace_allocate_records(struct ftrace_page *pg, int count) +static int ftrace_allocate_records(struct ftrace_page *pg, int count, + unsigned long *num_pages) { int order; int pages; @@ -3818,7 +3818,7 @@ static int ftrace_allocate_records(struct ftrace_page *pg, int count) return -EINVAL; /* We want to fill as much as possible, with no empty pages */ - pages = DIV_ROUND_UP(count, ENTRIES_PER_PAGE); + pages = DIV_ROUND_UP(count * ENTRY_SIZE, PAGE_SIZE); order = fls(pages) - 1; again: @@ -3833,6 +3833,7 @@ static int ftrace_allocate_records(struct ftrace_page *pg, int count) } ftrace_number_of_pages += 1 << order; + *num_pages += 1 << order; ftrace_number_of_groups++; cnt = (PAGE_SIZE << order) / ENTRY_SIZE; @@ -3861,12 +3862,14 @@ static void ftrace_free_pages(struct ftrace_page *pages) } static struct ftrace_page * -ftrace_allocate_pages(unsigned long num_to_init) +ftrace_allocate_pages(unsigned long num_to_init, unsigned long *num_pages) { struct ftrace_page *start_pg; struct ftrace_page *pg; int cnt; + *num_pages = 0; + if (!num_to_init) return NULL; @@ -3880,7 +3883,7 @@ ftrace_allocate_pages(unsigned long num_to_init) * waste as little space as possible. */ for (;;) { - cnt = ftrace_allocate_records(pg, num_to_init); + cnt = ftrace_allocate_records(pg, num_to_init, num_pages); if (cnt < 0) goto free_pages; @@ -7148,8 +7151,6 @@ static int ftrace_process_locs(struct module *mod, if (!count) return 0; - pages = DIV_ROUND_UP(count, ENTRIES_PER_PAGE); - /* * Sorting mcount in vmlinux at build time depend on * CONFIG_BUILDTIME_MCOUNT_SORT, while mcount loc in @@ -7162,7 +7163,7 @@ static int ftrace_process_locs(struct module *mod, test_is_sorted(start, count); } - start_pg = ftrace_allocate_pages(count); + start_pg = ftrace_allocate_pages(count, &pages); if (!start_pg) return -ENOMEM; @@ -7261,27 +7262,27 @@ static int ftrace_process_locs(struct module *mod, /* We should have used all pages unless we skipped some */ if (pg_unuse) { unsigned long pg_remaining, remaining = 0; - unsigned long skip; + long skip; /* Count the number of entries unused and compare it to skipped. */ - pg_remaining = (ENTRIES_PER_PAGE << pg->order) - pg->index; + pg_remaining = (PAGE_SIZE << pg->order) / ENTRY_SIZE - pg->index; if (!WARN(skipped < pg_remaining, "Extra allocated pages for ftrace")) { skip = skipped - pg_remaining; - for (pg = pg_unuse; pg; pg = pg->next) + for (pg = pg_unuse; pg && skip > 0; pg = pg->next) { remaining += 1 << pg->order; + skip -= (PAGE_SIZE << pg->order) / ENTRY_SIZE; + } pages -= remaining; - skip = DIV_ROUND_UP(skip, ENTRIES_PER_PAGE); - /* * Check to see if the number of pages remaining would * just fit the number of entries skipped. */ - WARN(skip != remaining, "Extra allocated pages for ftrace: %lu with %lu skipped", + WARN(pg || skip > 0, "Extra allocated pages for ftrace: %lu with %lu skipped", remaining, skipped); } /* Need to synchronize with ftrace_location_range() */ From bca07e57e47291f8738ea757084b88bb6cc756fb Mon Sep 17 00:00:00 2001 From: Brian Foster Date: Fri, 9 Jan 2026 12:49:05 -0500 Subject: [PATCH 2063/2333] xfs: set max_agbno to allow sparse alloc of last full inode chunk commit c360004c0160dbe345870f59f24595519008926f upstream. Sparse inode cluster allocation sets min/max agbno values to avoid allocating an inode cluster that might map to an invalid inode chunk. For example, we can't have an inode record mapped to agbno 0 or that extends past the end of a runt AG of misaligned size. The initial calculation of max_agbno is unnecessarily conservative, however. This has triggered a corner case allocation failure where a small runt AG (i.e. 2063 blocks) is mostly full save for an extent to the EOFS boundary: [2050,13]. max_agbno is set to 2048 in this case, which happens to be the offset of the last possible valid inode chunk in the AG. In practice, we should be able to allocate the 4-block cluster at agbno 2052 to map to the parent inode record at agbno 2048, but the max_agbno value precludes it. Note that this can result in filesystem shutdown via dirty trans cancel on stable kernels prior to commit 9eb775968b68 ("xfs: walk all AGs if TRYLOCK passed to xfs_alloc_vextent_iterate_ags") because the tail AG selection by the allocator sets t_highest_agno on the transaction. If the inode allocator spins around and finds an inode chunk with free inodes in an earlier AG, the subsequent dir name creation path may still fail to allocate due to the AG restriction and cancel. To avoid this problem, update the max_agbno calculation to the agbno prior to the last chunk aligned agbno in the AG. This is not necessarily the last valid allocation target for a sparse chunk, but since inode chunks (i.e. records) are chunk aligned and sparse allocs are cluster sized/aligned, this allows the sb_spino_align alignment restriction to take over and round down the max effective agbno to within the last valid inode chunk in the AG. Note that even though the allocator improvements in the aforementioned commit seem to avoid this particular dirty trans cancel situation, the max_agbno logic improvement still applies as we should be able to allocate from an AG that has been appropriately selected. The more important target for this patch however are older/stable kernels prior to this allocator rework/improvement. Cc: stable@vger.kernel.org # v4.2 Fixes: 56d1115c9bc7 ("xfs: allocate sparse inode chunks on full chunk allocation failure") Signed-off-by: Brian Foster Reviewed-by: Darrick J. Wong Signed-off-by: Carlos Maiolino Signed-off-by: Greg Kroah-Hartman --- fs/xfs/libxfs/xfs_ialloc.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/fs/xfs/libxfs/xfs_ialloc.c b/fs/xfs/libxfs/xfs_ialloc.c index d97295eaebe63..c19d6d713780c 100644 --- a/fs/xfs/libxfs/xfs_ialloc.c +++ b/fs/xfs/libxfs/xfs_ialloc.c @@ -848,15 +848,16 @@ xfs_ialloc_ag_alloc( * invalid inode records, such as records that start at agbno 0 * or extend beyond the AG. * - * Set min agbno to the first aligned, non-zero agbno and max to - * the last aligned agbno that is at least one full chunk from - * the end of the AG. + * Set min agbno to the first chunk aligned, non-zero agbno and + * max to one less than the last chunk aligned agbno from the + * end of the AG. We subtract 1 from max so that the cluster + * allocation alignment takes over and allows allocation within + * the last full inode chunk in the AG. */ args.min_agbno = args.mp->m_sb.sb_inoalignmt; args.max_agbno = round_down(xfs_ag_block_count(args.mp, pag_agno(pag)), - args.mp->m_sb.sb_inoalignmt) - - igeo->ialloc_blks; + args.mp->m_sb.sb_inoalignmt) - 1; error = xfs_alloc_vextent_near_bno(&args, xfs_agbno_to_fsb(pag, From ccd18d250ad8f1b0bb4462bde905d90574c3593b Mon Sep 17 00:00:00 2001 From: "Nirjhar Roy (IBM)" Date: Mon, 12 Jan 2026 15:35:23 +0530 Subject: [PATCH 2064/2333] xfs: Fix the return value of xfs_rtcopy_summary() commit 6b2d155366581705a848833a9b626bfea41d5a8d upstream. xfs_rtcopy_summary() should return the appropriate error code instead of always returning 0. The caller of this function which is xfs_growfs_rt_bmblock() is already handling the error. Fixes: e94b53ff699c ("xfs: cache last bitmap block in realtime allocator") Signed-off-by: Nirjhar Roy (IBM) Reviewed-by: Darrick J. Wong Reviewed-by: Christoph Hellwig Cc: stable@vger.kernel.org # v6.7 Signed-off-by: Carlos Maiolino Signed-off-by: Greg Kroah-Hartman --- fs/xfs/xfs_rtalloc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/xfs/xfs_rtalloc.c b/fs/xfs/xfs_rtalloc.c index e063f4f2f2e61..59fad43063a78 100644 --- a/fs/xfs/xfs_rtalloc.c +++ b/fs/xfs/xfs_rtalloc.c @@ -126,7 +126,7 @@ xfs_rtcopy_summary( error = 0; out: xfs_rtbuf_cache_relse(oargs); - return 0; + return error; } /* * Mark an extent specified by start and len allocated. From ccc578d2e1540b97e0687b25f554ad5d2bee520e Mon Sep 17 00:00:00 2001 From: Bui Quang Minh Date: Tue, 6 Jan 2026 22:04:36 +0700 Subject: [PATCH 2065/2333] virtio-net: don't schedule delayed refill worker commit fcdef3bcbb2c04e06ae89f8faff2cd6416b3a467 upstream. When we fail to refill the receive buffers, we schedule a delayed worker to retry later. However, this worker creates some concurrency issues. For example, when the worker runs concurrently with virtnet_xdp_set, both need to temporarily disable queue's NAPI before enabling again. Without proper synchronization, a deadlock can happen when napi_disable() is called on an already disabled NAPI. That napi_disable() call will be stuck and so will the subsequent napi_enable() call. To simplify the logic and avoid further problems, we will instead retry refilling in the next NAPI poll. Fixes: 4bc12818b363 ("virtio-net: disable delayed refill when pausing rx") Reported-by: Paolo Abeni Closes: https://lore.kernel.org/526b5396-459d-4d02-8635-a222d07b46d7@redhat.com Cc: stable@vger.kernel.org Suggested-by: Xuan Zhuo Signed-off-by: Bui Quang Minh Acked-by: Michael S. Tsirkin Link: https://patch.msgid.link/20260106150438.7425-2-minhquangbui99@gmail.com Signed-off-by: Jakub Kicinski Signed-off-by: Greg Kroah-Hartman --- drivers/net/virtio_net.c | 47 ++++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 6b3115cefc248..b67dbe346c807 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -3037,16 +3037,16 @@ static int virtnet_receive(struct receive_queue *rq, int budget, else packets = virtnet_receive_packets(vi, rq, budget, xdp_xmit, &stats); + u64_stats_set(&stats.packets, packets); if (rq->vq->num_free > min((unsigned int)budget, virtqueue_get_vring_size(rq->vq)) / 2) { - if (!try_fill_recv(vi, rq, GFP_ATOMIC)) { - spin_lock(&vi->refill_lock); - if (vi->refill_enabled) - schedule_delayed_work(&vi->refill, 0); - spin_unlock(&vi->refill_lock); - } + if (!try_fill_recv(vi, rq, GFP_ATOMIC)) + /* We need to retry refilling in the next NAPI poll so + * we must return budget to make sure the NAPI is + * repolled. + */ + packets = budget; } - u64_stats_set(&stats.packets, packets); u64_stats_update_begin(&rq->stats.syncp); for (i = 0; i < ARRAY_SIZE(virtnet_rq_stats_desc); i++) { size_t offset = virtnet_rq_stats_desc[i].offset; @@ -3226,9 +3226,10 @@ static int virtnet_open(struct net_device *dev) for (i = 0; i < vi->max_queue_pairs; i++) { if (i < vi->curr_queue_pairs) - /* Make sure we have some buffers: if oom use wq. */ - if (!try_fill_recv(vi, &vi->rq[i], GFP_KERNEL)) - schedule_delayed_work(&vi->refill, 0); + /* Pre-fill rq agressively, to make sure we are ready to + * get packets immediately. + */ + try_fill_recv(vi, &vi->rq[i], GFP_KERNEL); err = virtnet_enable_queue_pair(vi, i); if (err < 0) @@ -3473,16 +3474,15 @@ static void __virtnet_rx_resume(struct virtnet_info *vi, struct receive_queue *rq, bool refill) { - bool running = netif_running(vi->dev); - bool schedule_refill = false; + if (netif_running(vi->dev)) { + /* Pre-fill rq agressively, to make sure we are ready to get + * packets immediately. + */ + if (refill) + try_fill_recv(vi, rq, GFP_KERNEL); - if (refill && !try_fill_recv(vi, rq, GFP_KERNEL)) - schedule_refill = true; - if (running) virtnet_napi_enable(rq); - - if (schedule_refill) - schedule_delayed_work(&vi->refill, 0); + } } static void virtnet_rx_resume_all(struct virtnet_info *vi) @@ -3827,11 +3827,12 @@ static int virtnet_set_queues(struct virtnet_info *vi, u16 queue_pairs) } succ: vi->curr_queue_pairs = queue_pairs; - /* virtnet_open() will refill when device is going to up. */ - spin_lock_bh(&vi->refill_lock); - if (dev->flags & IFF_UP && vi->refill_enabled) - schedule_delayed_work(&vi->refill, 0); - spin_unlock_bh(&vi->refill_lock); + if (dev->flags & IFF_UP) { + local_bh_disable(); + for (int i = 0; i < vi->curr_queue_pairs; ++i) + virtqueue_napi_schedule(&vi->rq[i].napi, vi->rq[i].vq); + local_bh_enable(); + } return 0; } From 568aeb3476c770a3863c755dd2a199c212434286 Mon Sep 17 00:00:00 2001 From: Shakeel Butt Date: Mon, 22 Dec 2025 12:58:59 -0800 Subject: [PATCH 2066/2333] lib/buildid: use __kernel_read() for sleepable context commit 777a8560fd29738350c5094d4166fe5499452409 upstream. Prevent a "BUG: unable to handle kernel NULL pointer dereference in filemap_read_folio". For the sleepable context, convert freader to use __kernel_read() instead of direct page cache access via read_cache_folio(). This simplifies the faultable code path by using the standard kernel file reading interface which handles all the complexity of reading file data. At the moment we are not changing the code for non-sleepable context which uses filemap_get_folio() and only succeeds if the target folios are already in memory and up-to-date. The reason is to keep the patch simple and easier to backport to stable kernels. Syzbot repro does not crash the kernel anymore and the selftests run successfully. In the follow up we will make __kernel_read() with IOCB_NOWAIT work for non-sleepable contexts. In addition, I would like to replace the secretmem check with a more generic approach and will add fstest for the buildid code. Link: https://lkml.kernel.org/r/20251222205859.3968077-1-shakeel.butt@linux.dev Fixes: ad41251c290d ("lib/buildid: implement sleepable build_id_parse() API") Reported-by: syzbot+09b7d050e4806540153d@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=09b7d050e4806540153d Signed-off-by: Shakeel Butt Reviewed-by: Christoph Hellwig Tested-by: Jinchao Wang Link: https://lkml.kernel.org/r/aUteBPWPYzVWIZFH@ndev Reviewed-by: Christian Brauner Cc: Alexei Starovoitov Cc: Andrii Nakryiko Cc: Daniel Borkman Cc: "Darrick J. Wong" Cc: Matthew Wilcox (Oracle) Cc: Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- lib/buildid.c | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/lib/buildid.c b/lib/buildid.c index c4b0f376fb341..a80592ddafd18 100644 --- a/lib/buildid.c +++ b/lib/buildid.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #define BUILD_ID 3 @@ -65,20 +66,9 @@ static int freader_get_folio(struct freader *r, loff_t file_off) freader_put_folio(r); - /* reject secretmem folios created with memfd_secret() */ - if (secretmem_mapping(r->file->f_mapping)) - return -EFAULT; - + /* only use page cache lookup - fail if not already cached */ r->folio = filemap_get_folio(r->file->f_mapping, file_off >> PAGE_SHIFT); - /* if sleeping is allowed, wait for the page, if necessary */ - if (r->may_fault && (IS_ERR(r->folio) || !folio_test_uptodate(r->folio))) { - filemap_invalidate_lock_shared(r->file->f_mapping); - r->folio = read_cache_folio(r->file->f_mapping, file_off >> PAGE_SHIFT, - NULL, r->file); - filemap_invalidate_unlock_shared(r->file->f_mapping); - } - if (IS_ERR(r->folio) || !folio_test_uptodate(r->folio)) { if (!IS_ERR(r->folio)) folio_put(r->folio); @@ -116,6 +106,24 @@ static const void *freader_fetch(struct freader *r, loff_t file_off, size_t sz) return r->data + file_off; } + /* reject secretmem folios created with memfd_secret() */ + if (secretmem_mapping(r->file->f_mapping)) { + r->err = -EFAULT; + return NULL; + } + + /* use __kernel_read() for sleepable context */ + if (r->may_fault) { + ssize_t ret; + + ret = __kernel_read(r->file, r->buf, sz, &file_off); + if (ret != sz) { + r->err = (ret < 0) ? ret : -EIO; + return NULL; + } + return r->buf; + } + /* fetch or reuse folio for given file offset */ r->err = freader_get_folio(r, file_off); if (r->err) From 5a08dc1d8de3fc48bd355885e943c78f931d9eba Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 6 Nov 2025 15:13:50 -0800 Subject: [PATCH 2067/2333] x86/kaslr: Recognize all ZONE_DEVICE users as physaddr consumers commit 269031b15c1433ff39e30fa7ea3ab8f0be9d6ae2 upstream. Commit 7ffb791423c7 ("x86/kaslr: Reduce KASLR entropy on most x86 systems") is too narrow. The effect being mitigated in that commit is caused by ZONE_DEVICE which PCI_P2PDMA has a dependency. ZONE_DEVICE, in general, lets any physical address be added to the direct-map. I.e. not only ACPI hotplug ranges, CXL Memory Windows, or EFI Specific Purpose Memory, but also any PCI MMIO range for the DEVICE_PRIVATE and PCI_P2PDMA cases. Update the mitigation, limit KASLR entropy, to apply in all ZONE_DEVICE=y cases. Distro kernels typically have PCI_P2PDMA=y, so the practical exposure of this problem is limited to the PCI_P2PDMA=n case. A potential path to recover entropy would be to walk ACPI and determine the limits for hotplug and PCI MMIO before kernel_randomize_memory(). On smaller systems that could yield some KASLR address bits. This needs additional investigation to determine if some limited ACPI table scanning can happen this early without an open coded solution like arch/x86/boot/compressed/acpi.c needs to deploy. Cc: Ingo Molnar Cc: Kees Cook Cc: Bjorn Helgaas Cc: Peter Zijlstra Cc: Andy Lutomirski Cc: Logan Gunthorpe Cc: Andrew Morton Cc: David Hildenbrand Cc: Lorenzo Stoakes Cc: "Liam R. Howlett" Cc: Vlastimil Babka Cc: Mike Rapoport Cc: Suren Baghdasaryan Cc: Michal Hocko Fixes: 7ffb791423c7 ("x86/kaslr: Reduce KASLR entropy on most x86 systems") Cc: Signed-off-by: Dan Williams Reviewed-by: Balbir Singh Tested-by: Yasunori Goto Acked-by: Dave Hansen Link: http://patch.msgid.link/692e08b2516d4_261c1100a3@dwillia2-mobl4.notmuch Signed-off-by: Dave Jiang Signed-off-by: Greg Kroah-Hartman --- arch/x86/mm/kaslr.c | 10 +++++----- drivers/pci/Kconfig | 6 ------ mm/Kconfig | 12 ++++++++---- 3 files changed, 13 insertions(+), 15 deletions(-) diff --git a/arch/x86/mm/kaslr.c b/arch/x86/mm/kaslr.c index 3c306de52fd4d..834641c6049a5 100644 --- a/arch/x86/mm/kaslr.c +++ b/arch/x86/mm/kaslr.c @@ -115,12 +115,12 @@ void __init kernel_randomize_memory(void) /* * Adapt physical memory region size based on available memory, - * except when CONFIG_PCI_P2PDMA is enabled. P2PDMA exposes the - * device BAR space assuming the direct map space is large enough - * for creating a ZONE_DEVICE mapping in the direct map corresponding - * to the physical BAR address. + * except when CONFIG_ZONE_DEVICE is enabled. ZONE_DEVICE wants to map + * any physical address into the direct-map. KASLR wants to reliably + * steal some physical address bits. Those design choices are in direct + * conflict. */ - if (!IS_ENABLED(CONFIG_PCI_P2PDMA) && (memory_tb < kaslr_regions[0].size_tb)) + if (!IS_ENABLED(CONFIG_ZONE_DEVICE) && (memory_tb < kaslr_regions[0].size_tb)) kaslr_regions[0].size_tb = memory_tb; /* diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index f94f5d384362e..47e466946bedb 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -207,12 +207,6 @@ config PCI_P2PDMA P2P DMA transactions must be between devices behind the same root port. - Enabling this option will reduce the entropy of x86 KASLR memory - regions. For example - on a 46 bit system, the entropy goes down - from 16 bits to 15 bits. The actual reduction in entropy depends - on the physical address bits, on processor features, kernel config - (5 level page table) and physical memory present on the system. - If unsure, say N. config PCI_LABEL diff --git a/mm/Kconfig b/mm/Kconfig index ca3f146bc7053..5033e2aa328e4 100644 --- a/mm/Kconfig +++ b/mm/Kconfig @@ -1135,10 +1135,14 @@ config ZONE_DEVICE Device memory hotplug support allows for establishing pmem, or other device driver discovered memory regions, in the memmap. This allows pfn_to_page() lookups of otherwise - "device-physical" addresses which is needed for using a DAX - mapping in an O_DIRECT operation, among other things. - - If FS_DAX is enabled, then say Y. + "device-physical" addresses which is needed for DAX, PCI_P2PDMA, and + DEVICE_PRIVATE features among others. + + Enabling this option will reduce the entropy of x86 KASLR memory + regions. For example - on a 46 bit system, the entropy goes down + from 16 bits to 15 bits. The actual reduction in entropy depends + on the physical address bits, on processor features, kernel config + (5 level page table) and physical memory present on the system. # # Helpers to mirror range of the CPU page tables of a process into device page From d51f1db5a5f8cb93cd4298f33d6e2e19708cb854 Mon Sep 17 00:00:00 2001 From: Luca Ceresoli Date: Thu, 27 Nov 2025 11:26:17 +0100 Subject: [PATCH 2068/2333] phy: rockchip: inno-usb2: fix communication disruption in gadget mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 7d8f725b79e35fa47e42c88716aad8711e1168d8 upstream. When the OTG USB port is used to power to SoC, configured as peripheral and used in gadget mode, communication stops without notice about 6 seconds after the gadget is configured and enumerated. The problem was observed on a Radxa Rock Pi S board, which can only be powered by the only USB-C connector. That connector is the only one usable in gadget mode. This implies the USB cable is connected from before boot and never disconnects while the kernel runs. The related code flow in the PHY driver code can be summarized as: * the first time chg_detect_work starts (6 seconds after gadget is configured and enumerated) -> rockchip_chg_detect_work(): if chg_state is UNDEFINED: property_enable(base, &rphy->phy_cfg->chg_det.opmode, false); [Y] * rockchip_chg_detect_work() changes state and re-triggers itself a few times until it reaches the DETECTED state: -> rockchip_chg_detect_work(): if chg_state is DETECTED: property_enable(base, &rphy->phy_cfg->chg_det.opmode, true); [Z] At [Y] all existing communications stop. E.g. using a CDC serial gadget, the /dev/tty* devices are still present on both host and device, but no data is transferred anymore. The later call with a 'true' argument at [Z] does not restore it. Due to the lack of documentation, what chg_det.opmode does exactly is not clear, however by code inspection it seems reasonable that is disables something needed to keep the communication working, and testing proves that disabling these lines lets gadget mode keep working. So prevent changes to chg_det.opmode when there is a cable connected (VBUS present). Fixes: 98898f3bc83c ("phy: rockchip-inno-usb2: support otg-port for rk3399") Cc: stable@vger.kernel.org Closes: https://lore.kernel.org/lkml/20250414185458.7767aabc@booty/ Signed-off-by: Luca Ceresoli Reviewed-by: Théo Lebrun Link: https://patch.msgid.link/20251127-rk3308-fix-usb-gadget-phy-disconnect-v2-2-dac8a02cd2ca@bootlin.com Signed-off-by: Vinod Koul Signed-off-by: Greg Kroah-Hartman --- drivers/phy/rockchip/phy-rockchip-inno-usb2.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c index b0f23690ec300..0b5d49b6f7aab 100644 --- a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c +++ b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c @@ -831,7 +831,8 @@ static void rockchip_chg_detect_work(struct work_struct *work) if (!rport->suspended) rockchip_usb2phy_power_off(rport->phy); /* put the controller in non-driving mode */ - property_enable(base, &rphy->phy_cfg->chg_det.opmode, false); + if (!vbus_attach) + property_enable(base, &rphy->phy_cfg->chg_det.opmode, false); /* Start DCD processing stage 1 */ rockchip_chg_enable_dcd(rphy, true); rphy->chg_state = USB_CHG_STATE_WAIT_FOR_DCD; @@ -894,7 +895,8 @@ static void rockchip_chg_detect_work(struct work_struct *work) fallthrough; case USB_CHG_STATE_DETECTED: /* put the controller in normal mode */ - property_enable(base, &rphy->phy_cfg->chg_det.opmode, true); + if (!vbus_attach) + property_enable(base, &rphy->phy_cfg->chg_det.opmode, true); rockchip_usb2phy_otg_sm_work(&rport->otg_sm_work.work); dev_dbg(&rport->phy->dev, "charger = %s\n", chg_to_string(rphy->chg_type)); From 8b125923f4ea51be02b0aa25ccfea1344e5d1406 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 27 Nov 2025 14:48:34 +0100 Subject: [PATCH 2069/2333] phy: ti: gmii-sel: fix regmap leak on probe failure commit 4914d67da947031d6f645c81c74f7879e0844d5d upstream. The mmio regmap that may be allocated during probe is never freed. Switch to using the device managed allocator so that the regmap is released on probe failures (e.g. probe deferral) and on driver unbind. Fixes: 5ab90f40121a ("phy: ti: gmii-sel: Do not use syscon helper to build regmap") Cc: stable@vger.kernel.org # 6.14 Cc: Andrew Davis Signed-off-by: Johan Hovold Acked-by: Andrew Davis Link: https://patch.msgid.link/20251127134834.2030-1-johan@kernel.org Signed-off-by: Vinod Koul Signed-off-by: Greg Kroah-Hartman --- drivers/phy/ti/phy-gmii-sel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/phy/ti/phy-gmii-sel.c b/drivers/phy/ti/phy-gmii-sel.c index 50adabb867cb1..26209a89703a8 100644 --- a/drivers/phy/ti/phy-gmii-sel.c +++ b/drivers/phy/ti/phy-gmii-sel.c @@ -512,7 +512,7 @@ static int phy_gmii_sel_probe(struct platform_device *pdev) return dev_err_probe(dev, PTR_ERR(base), "failed to get base memory resource\n"); - priv->regmap = regmap_init_mmio(dev, base, &phy_gmii_sel_regmap_cfg); + priv->regmap = devm_regmap_init_mmio(dev, base, &phy_gmii_sel_regmap_cfg); if (IS_ERR(priv->regmap)) return dev_err_probe(dev, PTR_ERR(priv->regmap), "Failed to get syscon\n"); From efe92ee7a111fe0f4d75f3ed6b7e3f86322279d5 Mon Sep 17 00:00:00 2001 From: Wentao Liang Date: Fri, 9 Jan 2026 15:46:26 +0000 Subject: [PATCH 2070/2333] phy: rockchip: inno-usb2: Fix a double free bug in rockchip_usb2phy_probe() commit e07dea3de508cd6950c937cec42de7603190e1ca upstream. The for_each_available_child_of_node() calls of_node_put() to release child_np in each success loop. After breaking from the loop with the child_np has been released, the code will jump to the put_child label and will call the of_node_put() again if the devm_request_threaded_irq() fails. These cause a double free bug. Fix by returning directly to avoid the duplicate of_node_put(). Fixes: ed2b5a8e6b98 ("phy: phy-rockchip-inno-usb2: support muxed interrupts") Cc: stable@vger.kernel.org Signed-off-by: Wentao Liang Reviewed-by: Neil Armstrong Link: https://patch.msgid.link/20260109154626.2452034-1-vulab@iscas.ac.cn Signed-off-by: Vinod Koul Signed-off-by: Greg Kroah-Hartman --- drivers/phy/rockchip/phy-rockchip-inno-usb2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c index 0b5d49b6f7aab..a53cc9c86b7c9 100644 --- a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c +++ b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c @@ -1493,7 +1493,7 @@ static int rockchip_usb2phy_probe(struct platform_device *pdev) rphy); if (ret) { dev_err_probe(rphy->dev, ret, "failed to request usb2phy irq handle\n"); - goto put_child; + return ret; } } From 33194f81b68677e89c9ac302a49c94193b3b8918 Mon Sep 17 00:00:00 2001 From: Rafael Beims Date: Tue, 23 Dec 2025 12:02:54 -0300 Subject: [PATCH 2071/2333] phy: freescale: imx8m-pcie: assert phy reset during power on commit f2ec4723defbc66a50e0abafa830ae9f8bceb0d7 upstream. After U-Boot initializes PCIe with "pcie enum", Linux fails to detect an NVMe disk on some boot cycles with: phy phy-32f00000.pcie-phy.0: phy poweron failed --> -110 Discussion with NXP identified that the iMX8MP PCIe PHY PLL may fail to lock when re-initialized without a reset cycle [1]. The issue reproduces on 7% of tested hardware platforms, with a 30-40% failure rate per affected device across boot cycles. Insert a reset cycle in the power-on routine to ensure the PHY is initialized from a known state. [1] https://community.nxp.com/t5/i-MX-Processors/iMX8MP-PCIe-initialization-in-U-Boot/m-p/2248437#M242401 Signed-off-by: Rafael Beims Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20251223150254.1075221-1-rafael@beims.me Signed-off-by: Vinod Koul Signed-off-by: Greg Kroah-Hartman --- drivers/phy/freescale/phy-fsl-imx8m-pcie.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/phy/freescale/phy-fsl-imx8m-pcie.c b/drivers/phy/freescale/phy-fsl-imx8m-pcie.c index 68fcc8114d750..7f5600103a001 100644 --- a/drivers/phy/freescale/phy-fsl-imx8m-pcie.c +++ b/drivers/phy/freescale/phy-fsl-imx8m-pcie.c @@ -89,7 +89,8 @@ static int imx8_pcie_phy_power_on(struct phy *phy) writel(imx8_phy->tx_deemph_gen2, imx8_phy->base + PCIE_PHY_TRSV_REG6); break; - case IMX8MP: /* Do nothing. */ + case IMX8MP: + reset_control_assert(imx8_phy->reset); break; } From e26755512623ffc643ccb6bffc595417e2d1c587 Mon Sep 17 00:00:00 2001 From: Louis Chauvet Date: Thu, 27 Nov 2025 11:26:16 +0100 Subject: [PATCH 2072/2333] phy: rockchip: inno-usb2: fix disconnection in gadget mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 028e8ca7b20fb7324f3e5db34ba8bd366d9d3acc upstream. When the OTG USB port is used to power the SoC, configured as peripheral and used in gadget mode, there is a disconnection about 6 seconds after the gadget is configured and enumerated. The problem was observed on a Radxa Rock Pi S board, which can only be powered by the only USB-C connector. That connector is the only one usable in gadget mode. This implies the USB cable is connected from before boot and never disconnects while the kernel runs. The problem happens because of the PHY driver code flow, summarized as: * UDC start code (triggered via configfs at any time after boot) -> phy_init -> rockchip_usb2phy_init -> schedule_delayed_work(otg_sm_work [A], 6 sec) -> phy_power_on -> rockchip_usb2phy_power_on -> enable clock -> rockchip_usb2phy_reset * Now the gadget interface is up and running. * 6 seconds later otg_sm_work starts [A] -> rockchip_usb2phy_otg_sm_work(): if (B_IDLE state && VBUS present && ...): schedule_delayed_work(&rport->chg_work [B], 0); * immediately the chg_detect_work starts [B] -> rockchip_chg_detect_work(): if chg_state is UNDEFINED: if (!rport->suspended): rockchip_usb2phy_power_off() <--- [X] At [X], the PHY is powered off, causing a disconnection. This quickly triggers a new connection and following re-enumeration, but any connection that had been established during the 6 seconds is broken. The code already checks for !rport->suspended (which, somewhat counter-intuitively, means the PHY is powered on), so add a guard for VBUS as well to avoid a disconnection when a cable is connected. Fixes: 98898f3bc83c ("phy: rockchip-inno-usb2: support otg-port for rk3399") Cc: stable@vger.kernel.org Closes: https://lore.kernel.org/lkml/20250414185458.7767aabc@booty/ Signed-off-by: Louis Chauvet Co-developed-by: Luca Ceresoli Signed-off-by: Luca Ceresoli Reviewed-by: Théo Lebrun Link: https://patch.msgid.link/20251127-rk3308-fix-usb-gadget-phy-disconnect-v2-1-dac8a02cd2ca@bootlin.com Signed-off-by: Vinod Koul Signed-off-by: Greg Kroah-Hartman --- drivers/phy/rockchip/phy-rockchip-inno-usb2.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c index a53cc9c86b7c9..8f4c08e599aa2 100644 --- a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c +++ b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c @@ -821,14 +821,16 @@ static void rockchip_chg_detect_work(struct work_struct *work) container_of(work, struct rockchip_usb2phy_port, chg_work.work); struct rockchip_usb2phy *rphy = dev_get_drvdata(rport->phy->dev.parent); struct regmap *base = get_reg_base(rphy); - bool is_dcd, tmout, vout; + bool is_dcd, tmout, vout, vbus_attach; unsigned long delay; + vbus_attach = property_enabled(rphy->grf, &rport->port_cfg->utmi_bvalid); + dev_dbg(&rport->phy->dev, "chg detection work state = %d\n", rphy->chg_state); switch (rphy->chg_state) { case USB_CHG_STATE_UNDEFINED: - if (!rport->suspended) + if (!rport->suspended && !vbus_attach) rockchip_usb2phy_power_off(rport->phy); /* put the controller in non-driving mode */ if (!vbus_attach) From b74edae2a0c7a234a50796e1eb6d4c01df2170d0 Mon Sep 17 00:00:00 2001 From: Franz Schnyder Date: Wed, 26 Nov 2025 15:01:33 +0100 Subject: [PATCH 2073/2333] phy: fsl-imx8mq-usb: fix typec orientation switch when built as module commit 49ccab4bedd4779899246107dc19fb01c5b6fea3 upstream. Currently, the PHY only registers the typec orientation switch when it is built in. If the typec driver is built as a module, the switch registration is skipped due to the preprocessor condition, causing orientation detection to fail. With commit 45fe729be9a6 ("usb: typec: Stub out typec_switch APIs when CONFIG_TYPEC=n") the preprocessor condition is not needed anymore and the orientation switch is correctly registered for both built-in and module builds. Fixes: b58f0f86fd61 ("phy: fsl-imx8mq-usb: add tca function driver for imx95") Cc: stable@vger.kernel.org Suggested-by: Xu Yang Signed-off-by: Franz Schnyder Reviewed-by: Frank Li Reviewed-by: Xu Yang Link: https://patch.msgid.link/20251126140136.1202241-1-fra.schnyder@gmail.com Signed-off-by: Vinod Koul Signed-off-by: Greg Kroah-Hartman --- drivers/phy/freescale/phy-fsl-imx8mq-usb.c | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/drivers/phy/freescale/phy-fsl-imx8mq-usb.c b/drivers/phy/freescale/phy-fsl-imx8mq-usb.c index 0c84f5f7a82cb..f6cac4c049c43 100644 --- a/drivers/phy/freescale/phy-fsl-imx8mq-usb.c +++ b/drivers/phy/freescale/phy-fsl-imx8mq-usb.c @@ -124,8 +124,6 @@ struct imx8mq_usb_phy { static void tca_blk_orientation_set(struct tca_blk *tca, enum typec_orientation orientation); -#ifdef CONFIG_TYPEC - static int tca_blk_typec_switch_set(struct typec_switch_dev *sw, enum typec_orientation orientation) { @@ -173,18 +171,6 @@ static void tca_blk_put_typec_switch(struct typec_switch_dev *sw) typec_switch_unregister(sw); } -#else - -static struct typec_switch_dev *tca_blk_get_typec_switch(struct platform_device *pdev, - struct imx8mq_usb_phy *imx_phy) -{ - return NULL; -} - -static void tca_blk_put_typec_switch(struct typec_switch_dev *sw) {} - -#endif /* CONFIG_TYPEC */ - static void tca_blk_orientation_set(struct tca_blk *tca, enum typec_orientation orientation) { From 69d1c05268a86a6df31e2484b8cca026300ae6d0 Mon Sep 17 00:00:00 2001 From: Wayne Chang Date: Fri, 12 Dec 2025 11:21:16 +0800 Subject: [PATCH 2074/2333] phy: tegra: xusb: Explicitly configure HS_DISCON_LEVEL to 0x7 commit b246caa68037aa495390a60d080acaeb84f45fff upstream. The USB2 Bias Pad Control register manages analog parameters for signal detection. Previously, the HS_DISCON_LEVEL relied on hardware reset values, which may lead to the detection failure. Explicitly configure HS_DISCON_LEVEL to 0x7. This ensures the disconnect threshold is sufficient to guarantee reliable detection. Fixes: bbf711682cd5 ("phy: tegra: xusb: Add Tegra186 support") Cc: stable@vger.kernel.org Signed-off-by: Wayne Chang Link: https://patch.msgid.link/20251212032116.768307-1-waynec@nvidia.com Signed-off-by: Vinod Koul Signed-off-by: Greg Kroah-Hartman --- drivers/phy/tegra/xusb-tegra186.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/phy/tegra/xusb-tegra186.c b/drivers/phy/tegra/xusb-tegra186.c index e818f6c3980e6..bec9616c4a2e0 100644 --- a/drivers/phy/tegra/xusb-tegra186.c +++ b/drivers/phy/tegra/xusb-tegra186.c @@ -84,6 +84,7 @@ #define XUSB_PADCTL_USB2_BIAS_PAD_CTL0 0x284 #define BIAS_PAD_PD BIT(11) #define HS_SQUELCH_LEVEL(x) (((x) & 0x7) << 0) +#define HS_DISCON_LEVEL(x) (((x) & 0x7) << 3) #define XUSB_PADCTL_USB2_BIAS_PAD_CTL1 0x288 #define USB2_TRK_START_TIMER(x) (((x) & 0x7f) << 12) @@ -623,6 +624,8 @@ static void tegra186_utmi_bias_pad_power_on(struct tegra_xusb_padctl *padctl) value &= ~BIAS_PAD_PD; value &= ~HS_SQUELCH_LEVEL(~0); value |= HS_SQUELCH_LEVEL(priv->calib.hs_squelch); + value &= ~HS_DISCON_LEVEL(~0); + value |= HS_DISCON_LEVEL(0x7); padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL0); udelay(1); From 11c82acb4876c7fc1fc1cbe1edfc0cc5a8ff27d0 Mon Sep 17 00:00:00 2001 From: Wayne Chang Date: Mon, 12 Jan 2026 22:56:53 +0800 Subject: [PATCH 2075/2333] usb: host: xhci-tegra: Use platform_get_irq_optional() for wake IRQs commit d13b6a128a12e528bb18f971f2969feb286f45c7 upstream. When some wake IRQs are disabled in the device tree, the corresponding interrupt entries are removed from DT. In such cases, the driver currently calls platform_get_irq(), which returns -ENXIO and logs an error like: tegra-xusb 3610000.usb: error -ENXIO: IRQ index 2 not found However, not all wake IRQs are mandatory. The hardware can operate normally even if some wake sources are not defined in DT. To avoid this false alarm and allow missing wake IRQs gracefully, use platform_get_irq_optional() instead of platform_get_irq(). Fixes: 5df186e2ef11 ("usb: xhci: tegra: Support USB wakeup function for Tegra234") Cc: stable Signed-off-by: Wayne Chang Signed-off-by: Wei-Cheng Chen Reviewed-by: Jon Hunter Tested-by: Jon Hunter Link: https://patch.msgid.link/20260112145653.95691-1-weichengc@nvidia.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-tegra.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/host/xhci-tegra.c b/drivers/usb/host/xhci-tegra.c index 5255b10028931..c78bed0aa844e 100644 --- a/drivers/usb/host/xhci-tegra.c +++ b/drivers/usb/host/xhci-tegra.c @@ -1564,7 +1564,7 @@ static int tegra_xusb_setup_wakeup(struct platform_device *pdev, struct tegra_xu for (i = 0; i < tegra->soc->max_num_wakes; i++) { struct irq_data *data; - tegra->wake_irqs[i] = platform_get_irq(pdev, i + WAKE_IRQ_START_INDEX); + tegra->wake_irqs[i] = platform_get_irq_optional(pdev, i + WAKE_IRQ_START_INDEX); if (tegra->wake_irqs[i] < 0) break; From 34f6634dba87ef72b3c3a3a524be663adef7ab42 Mon Sep 17 00:00:00 2001 From: Mathias Nyman Date: Fri, 16 Jan 2026 01:37:58 +0200 Subject: [PATCH 2076/2333] xhci: sideband: don't dereference freed ring when removing sideband endpoint MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit dd83dc1249737b837ac5d57c81f2b0977c613d9f upstream. xhci_sideband_remove_endpoint() incorrecly assumes that the endpoint is running and has a valid transfer ring. Lianqin reported a crash during suspend/wake-up stress testing, and found the cause to be dereferencing a non-existing transfer ring 'ep->ring' during xhci_sideband_remove_endpoint(). The endpoint and its ring may be in unknown state if this function is called after xHCI was reinitialized in resume (lost power), or if device is being re-enumerated, disconnected or endpoint already dropped. Fix this by both removing unnecessary ring access, and by checking ep->ring exists before dereferencing it. Also make sure endpoint is running before attempting to stop it. Remove the xhci_initialize_ring_info() call during sideband endpoint removal as is it only initializes ring structure enqueue, dequeue and cycle state values to their starting values without changing actual hardware enqueue, dequeue and cycle state. Leaving them out of sync is worse than leaving it as it is. The endpoint will get freed in after this in most usecases. If the (audio) class driver want's to reuse the endpoint after offload then it is up to the class driver to ensure endpoint is properly set up. Reported-by: 胡连勤 Closes: https://lore.kernel.org/linux-usb/TYUPR06MB6217B105B059A7730C4F6EC8D2B9A@TYUPR06MB6217.apcprd06.prod.outlook.com/ Tested-by: 胡连勤 Fixes: de66754e9f80 ("xhci: sideband: add initial api to register a secondary interrupter entity") Cc: stable@vger.kernel.org Signed-off-by: Mathias Nyman Link: https://patch.msgid.link/20260115233758.364097-2-mathias.nyman@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-sideband.c | 1 - drivers/usb/host/xhci.c | 15 ++++++++++++--- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/drivers/usb/host/xhci-sideband.c b/drivers/usb/host/xhci-sideband.c index a85f62a73313a..2bd77255032b9 100644 --- a/drivers/usb/host/xhci-sideband.c +++ b/drivers/usb/host/xhci-sideband.c @@ -210,7 +210,6 @@ xhci_sideband_remove_endpoint(struct xhci_sideband *sb, return -ENODEV; __xhci_sideband_remove_endpoint(sb, ep); - xhci_initialize_ring_info(ep->ring); return 0; } diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index a148a12801263..4161c8c7721dd 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -2891,16 +2891,25 @@ int xhci_stop_endpoint_sync(struct xhci_hcd *xhci, struct xhci_virt_ep *ep, int gfp_t gfp_flags) { struct xhci_command *command; + struct xhci_ep_ctx *ep_ctx; unsigned long flags; - int ret; + int ret = -ENODEV; command = xhci_alloc_command(xhci, true, gfp_flags); if (!command) return -ENOMEM; spin_lock_irqsave(&xhci->lock, flags); - ret = xhci_queue_stop_endpoint(xhci, command, ep->vdev->slot_id, - ep->ep_index, suspend); + + /* make sure endpoint exists and is running before stopping it */ + if (ep->ring) { + ep_ctx = xhci_get_ep_ctx(xhci, ep->vdev->out_ctx, ep->ep_index); + if (GET_EP_CTX_STATE(ep_ctx) == EP_STATE_RUNNING) + ret = xhci_queue_stop_endpoint(xhci, command, + ep->vdev->slot_id, + ep->ep_index, suspend); + } + if (ret < 0) { spin_unlock_irqrestore(&xhci->lock, flags); goto out; From aee473246134b33dbb5e2b58926b59632a84a223 Mon Sep 17 00:00:00 2001 From: Xu Yang Date: Tue, 13 Jan 2026 17:53:08 +0800 Subject: [PATCH 2077/2333] usb: gadget: uvc: fix interval_duration calculation commit 010dc57cb5163e5f4a32430dd5091cc29efd0471 upstream. According to USB specification: For full-/high-speed isochronous endpoints, the bInterval value is used as the exponent for a 2^(bInterval-1) value. To correctly convert bInterval as interval_duration: interval_duration = 2^(bInterval-1) * frame_interval Because the unit of video->interval is 100ns, add a comment info to make it clear. Fixes: 48dbe731171e ("usb: gadget: uvc: set req_size and n_requests based on the frame interval") Cc: stable@vger.kernel.org Reviewed-by: Frank Li Signed-off-by: Xu Yang Link: https://patch.msgid.link/20260113-uvc-gadget-fix-patch-v2-2-62950ef5bcb5@nxp.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/function/uvc.h | 2 +- drivers/usb/gadget/function/uvc_video.c | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/usb/gadget/function/uvc.h b/drivers/usb/gadget/function/uvc.h index 9e79cbe507157..791a3b956cf29 100644 --- a/drivers/usb/gadget/function/uvc.h +++ b/drivers/usb/gadget/function/uvc.h @@ -107,7 +107,7 @@ struct uvc_video { unsigned int width; unsigned int height; unsigned int imagesize; - unsigned int interval; + unsigned int interval; /* in 100ns units */ struct mutex mutex; /* protects frame parameters */ unsigned int uvc_num_requests; diff --git a/drivers/usb/gadget/function/uvc_video.c b/drivers/usb/gadget/function/uvc_video.c index fb77b0b217901..7f5690713bc0e 100644 --- a/drivers/usb/gadget/function/uvc_video.c +++ b/drivers/usb/gadget/function/uvc_video.c @@ -499,7 +499,7 @@ uvc_video_prep_requests(struct uvc_video *video) { struct uvc_device *uvc = container_of(video, struct uvc_device, video); struct usb_composite_dev *cdev = uvc->func.config->cdev; - unsigned int interval_duration = video->ep->desc->bInterval * 1250; + unsigned int interval_duration; unsigned int max_req_size, req_size, header_size; unsigned int nreq; @@ -515,8 +515,11 @@ uvc_video_prep_requests(struct uvc_video *video) return; } + interval_duration = 2 << (video->ep->desc->bInterval - 1); if (cdev->gadget->speed < USB_SPEED_HIGH) - interval_duration = video->ep->desc->bInterval * 10000; + interval_duration *= 10000; + else + interval_duration *= 1250; nreq = DIV_ROUND_UP(video->interval, interval_duration); From 01120b22c57c56c69f35dc7b803cd4b884bc8fbc Mon Sep 17 00:00:00 2001 From: Xu Yang Date: Tue, 13 Jan 2026 17:53:07 +0800 Subject: [PATCH 2078/2333] usb: gadget: uvc: fix req_payload_size calculation commit 2edc1acb1a2512843425aa19d0c6060a0a924605 upstream. Current req_payload_size calculation has 2 issue: (1) When the first time calculate req_payload_size for all the buffers, reqs_per_frame = 0 will be the divisor of DIV_ROUND_UP(). So the result is undefined. This happens because VIDIOC_STREAMON is always executed after VIDIOC_QBUF. So video->reqs_per_frame will be 0 until VIDIOC_STREAMON is run. (2) The buf->req_payload_size may be bigger than max_req_size. Take YUYV pixel format as example: If bInterval = 1, video->interval = 666666, high-speed: video->reqs_per_frame = 666666 / 1250 = 534 720p: buf->req_payload_size = 1843200 / 534 = 3452 1080p: buf->req_payload_size = 4147200 / 534 = 7766 Based on such req_payload_size, the controller can't run normally. To fix above issue, assign max_req_size to buf->req_payload_size when video->reqs_per_frame = 0. And limit buf->req_payload_size to video->req_size if it's large than video->req_size. Since max_req_size is used at many place, add it to struct uvc_video and set the value once endpoint is enabled. Fixes: 98ad03291560 ("usb: gadget: uvc: set req_length based on payload by nreqs instead of req_size") Cc: stable@vger.kernel.org Reviewed-by: Frank Li Signed-off-by: Xu Yang Link: https://patch.msgid.link/20260113-uvc-gadget-fix-patch-v2-1-62950ef5bcb5@nxp.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/function/f_uvc.c | 4 ++++ drivers/usb/gadget/function/uvc.h | 1 + drivers/usb/gadget/function/uvc_queue.c | 15 +++++++++++---- drivers/usb/gadget/function/uvc_video.c | 4 +--- 4 files changed, 17 insertions(+), 7 deletions(-) diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c index aa6ab666741a9..a96476507d2fd 100644 --- a/drivers/usb/gadget/function/f_uvc.c +++ b/drivers/usb/gadget/function/f_uvc.c @@ -362,6 +362,10 @@ uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt) return ret; usb_ep_enable(uvc->video.ep); + uvc->video.max_req_size = uvc->video.ep->maxpacket + * max_t(unsigned int, uvc->video.ep->maxburst, 1) + * (uvc->video.ep->mult); + memset(&v4l2_event, 0, sizeof(v4l2_event)); v4l2_event.type = UVC_EVENT_STREAMON; v4l2_event_queue(&uvc->vdev, &v4l2_event); diff --git a/drivers/usb/gadget/function/uvc.h b/drivers/usb/gadget/function/uvc.h index 791a3b956cf29..676419a049762 100644 --- a/drivers/usb/gadget/function/uvc.h +++ b/drivers/usb/gadget/function/uvc.h @@ -117,6 +117,7 @@ struct uvc_video { /* Requests */ bool is_enabled; /* tracks whether video stream is enabled */ unsigned int req_size; + unsigned int max_req_size; struct list_head ureqs; /* all uvc_requests allocated by uvc_video */ /* USB requests that the video pump thread can encode into */ diff --git a/drivers/usb/gadget/function/uvc_queue.c b/drivers/usb/gadget/function/uvc_queue.c index 9a1bbd79ff5af..21d80322cb614 100644 --- a/drivers/usb/gadget/function/uvc_queue.c +++ b/drivers/usb/gadget/function/uvc_queue.c @@ -86,10 +86,17 @@ static int uvc_buffer_prepare(struct vb2_buffer *vb) buf->bytesused = 0; } else { buf->bytesused = vb2_get_plane_payload(vb, 0); - buf->req_payload_size = - DIV_ROUND_UP(buf->bytesused + - (video->reqs_per_frame * UVCG_REQUEST_HEADER_LEN), - video->reqs_per_frame); + + if (video->reqs_per_frame != 0) { + buf->req_payload_size = + DIV_ROUND_UP(buf->bytesused + + (video->reqs_per_frame * UVCG_REQUEST_HEADER_LEN), + video->reqs_per_frame); + if (buf->req_payload_size > video->req_size) + buf->req_payload_size = video->req_size; + } else { + buf->req_payload_size = video->max_req_size; + } } return 0; diff --git a/drivers/usb/gadget/function/uvc_video.c b/drivers/usb/gadget/function/uvc_video.c index 7f5690713bc0e..9dc3af16e2f38 100644 --- a/drivers/usb/gadget/function/uvc_video.c +++ b/drivers/usb/gadget/function/uvc_video.c @@ -503,9 +503,7 @@ uvc_video_prep_requests(struct uvc_video *video) unsigned int max_req_size, req_size, header_size; unsigned int nreq; - max_req_size = video->ep->maxpacket - * max_t(unsigned int, video->ep->maxburst, 1) - * (video->ep->mult); + max_req_size = video->max_req_size; if (!usb_endpoint_xfer_isoc(video->ep->desc)) { video->req_size = max_req_size; From 5468051245c2309420a5b42aa2a22ee480221055 Mon Sep 17 00:00:00 2001 From: Thinh Nguyen Date: Fri, 2 Jan 2026 21:53:46 +0000 Subject: [PATCH 2079/2333] usb: dwc3: Check for USB4 IP_NAME commit 0ed91d47959cb7573c17e06487f0fb891d59dfb3 upstream. Synopsys renamed DWC_usb32 IP to DWC_usb4 as of IP version 1.30. No functional change except checking for the IP_NAME here. The driver will treat the new IP_NAME as if it's DWC_usb32. Additional features for USB4 will be introduced and checked separately. Cc: stable@vger.kernel.org Signed-off-by: Thinh Nguyen Link: https://patch.msgid.link/e6f1827754c7a7ddc5eb7382add20bfe3a9b312f.1767390747.git.Thinh.Nguyen@synopsys.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/core.c | 2 ++ drivers/usb/dwc3/core.h | 1 + 2 files changed, 3 insertions(+) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index c2ce2f5e60a19..eb10490a6d92c 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -991,6 +991,8 @@ static bool dwc3_core_is_valid(struct dwc3 *dwc) reg = dwc3_readl(dwc->regs, DWC3_GSNPSID); dwc->ip = DWC3_GSNPS_ID(reg); + if (dwc->ip == DWC4_IP) + dwc->ip = DWC32_IP; /* This should read as U3 followed by revision number */ if (DWC3_IP_IS(DWC3)) { diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index a5fc92c4ffa3b..45757169b672f 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -1265,6 +1265,7 @@ struct dwc3 { #define DWC3_IP 0x5533 #define DWC31_IP 0x3331 #define DWC32_IP 0x3332 +#define DWC4_IP 0x3430 u32 revision; From 6e4663c6ec273f05b8e78fd38d5713ce37afc627 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Br=C3=BCderl?= Date: Sun, 7 Dec 2025 10:02:20 +0100 Subject: [PATCH 2080/2333] usb: core: add USB_QUIRK_NO_BOS for devices that hang on BOS descriptor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 2740ac33c87b3d0dfa022efd6ba04c6261b1abbd upstream. Add USB_QUIRK_NO_BOS quirk flag to skip requesting the BOS descriptor for devices that cannot handle it. Add Elgato 4K X (0fd9:009b) to the quirk table. This device hangs when the BOS descriptor is requested at SuperSpeed Plus (10Gbps). Link: https://bugzilla.kernel.org/show_bug.cgi?id=220027 Cc: stable Signed-off-by: Johannes Brüderl Link: https://patch.msgid.link/20251207090220.14807-1-johannes.bruederl@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/config.c | 5 +++++ drivers/usb/core/quirks.c | 3 +++ include/linux/usb/quirks.h | 3 +++ 3 files changed, 11 insertions(+) diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c index baf5bc844b6ff..2bb1ceb9d621a 100644 --- a/drivers/usb/core/config.c +++ b/drivers/usb/core/config.c @@ -1040,6 +1040,11 @@ int usb_get_bos_descriptor(struct usb_device *dev) __u8 cap_type; int ret; + if (dev->quirks & USB_QUIRK_NO_BOS) { + dev_dbg(ddev, "skipping BOS descriptor\n"); + return -ENOMSG; + } + bos = kzalloc(sizeof(*bos), GFP_KERNEL); if (!bos) return -ENOMEM; diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index 47f589c4104a3..c4d85089d19b1 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -450,6 +450,9 @@ static const struct usb_device_id usb_quirk_list[] = { { USB_DEVICE(0x0c45, 0x7056), .driver_info = USB_QUIRK_IGNORE_REMOTE_WAKEUP }, + /* Elgato 4K X - BOS descriptor fetch hangs at SuperSpeed Plus */ + { USB_DEVICE(0x0fd9, 0x009b), .driver_info = USB_QUIRK_NO_BOS }, + /* Sony Xperia XZ1 Compact (lilac) smartphone in fastboot mode */ { USB_DEVICE(0x0fce, 0x0dde), .driver_info = USB_QUIRK_NO_LPM }, diff --git a/include/linux/usb/quirks.h b/include/linux/usb/quirks.h index 59409c1fc3dee..2f7bd2fdc6164 100644 --- a/include/linux/usb/quirks.h +++ b/include/linux/usb/quirks.h @@ -75,4 +75,7 @@ /* short SET_ADDRESS request timeout */ #define USB_QUIRK_SHORT_SET_ADDRESS_REQ_TIMEOUT BIT(16) +/* skip BOS descriptor request */ +#define USB_QUIRK_NO_BOS BIT(17) + #endif /* __LINUX_USB_QUIRKS_H */ From 525779e2df9e5ea4f11c98ab030910fbaf679b15 Mon Sep 17 00:00:00 2001 From: Huacai Chen Date: Mon, 12 Jan 2026 16:48:02 +0800 Subject: [PATCH 2081/2333] USB: OHCI/UHCI: Add soft dependencies on ehci_platform commit 01ef7f1b8713a78ab1a9512cf8096d2474c70633 upstream. Commit 9beeee6584b9aa4f ("USB: EHCI: log a warning if ehci-hcd is not loaded first") said that ehci-hcd should be loaded before ohci-hcd and uhci-hcd. However, commit 05c92da0c52494ca ("usb: ohci/uhci - add soft dependencies on ehci_pci") only makes ohci-pci/uhci-pci depend on ehci- pci, which is not enough and we may still see the warnings in boot log. To eliminate the warnings we should make ohci-hcd/uhci-hcd depend on ehci-hcd. But Alan said that the warning introduced by 9beeee6584b9aa4f is bogus, we only need the soft dependencies in the PCI level rather than the HCD level. However, there is really another neccessary soft dependencies between ohci-platform/uhci-platform and ehci-platform, which is added by this patch. The boot logs are below. 1. ohci-platform loaded before ehci-platform: ohci-platform 1f058000.usb: Generic Platform OHCI controller ohci-platform 1f058000.usb: new USB bus registered, assigned bus number 1 ohci-platform 1f058000.usb: irq 28, io mem 0x1f058000 hub 1-0:1.0: USB hub found hub 1-0:1.0: 4 ports detected Warning! ehci_hcd should always be loaded before uhci_hcd and ohci_hcd, not after usb 1-4: new low-speed USB device number 2 using ohci-platform ehci-platform 1f050000.usb: EHCI Host Controller ehci-platform 1f050000.usb: new USB bus registered, assigned bus number 2 ehci-platform 1f050000.usb: irq 29, io mem 0x1f050000 ehci-platform 1f050000.usb: USB 2.0 started, EHCI 1.00 usb 1-4: device descriptor read/all, error -62 hub 2-0:1.0: USB hub found hub 2-0:1.0: 4 ports detected usb 1-4: new low-speed USB device number 3 using ohci-platform input: YSPRINGTECH USB OPTICAL MOUSE as /devices/platform/bus@10000000/1f058000.usb/usb1/1-4/1-4:1.0/0003:10C4:8105.0001/input/input0 hid-generic 0003:10C4:8105.0001: input,hidraw0: USB HID v1.11 Mouse [YSPRINGTECH USB OPTICAL MOUSE] on usb-1f058000.usb-4/input0 2. ehci-platform loaded before ohci-platform: ehci-platform 1f050000.usb: EHCI Host Controller ehci-platform 1f050000.usb: new USB bus registered, assigned bus number 1 ehci-platform 1f050000.usb: irq 28, io mem 0x1f050000 ehci-platform 1f050000.usb: USB 2.0 started, EHCI 1.00 hub 1-0:1.0: USB hub found hub 1-0:1.0: 4 ports detected ohci-platform 1f058000.usb: Generic Platform OHCI controller ohci-platform 1f058000.usb: new USB bus registered, assigned bus number 2 ohci-platform 1f058000.usb: irq 29, io mem 0x1f058000 hub 2-0:1.0: USB hub found hub 2-0:1.0: 4 ports detected usb 2-4: new low-speed USB device number 2 using ohci-platform input: YSPRINGTECH USB OPTICAL MOUSE as /devices/platform/bus@10000000/1f058000.usb/usb2/2-4/2-4:1.0/0003:10C4:8105.0001/input/input0 hid-generic 0003:10C4:8105.0001: input,hidraw0: USB HID v1.11 Mouse [YSPRINGTECH USB OPTICAL MOUSE] on usb-1f058000.usb-4/input0 In the later case, there is no re-connection for USB-1.0/1.1 devices, which is expected. Cc: stable Reported-by: Shengwen Xiao Signed-off-by: Huacai Chen Reviewed-by: Alan Stern Link: https://patch.msgid.link/20260112084802.1995923-1-chenhuacai@loongson.cn Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-platform.c | 1 + drivers/usb/host/uhci-platform.c | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/usb/host/ohci-platform.c b/drivers/usb/host/ohci-platform.c index f47ae12cde6a2..059621210d2c2 100644 --- a/drivers/usb/host/ohci-platform.c +++ b/drivers/usb/host/ohci-platform.c @@ -376,3 +376,4 @@ MODULE_DESCRIPTION(DRIVER_DESC); MODULE_AUTHOR("Hauke Mehrtens"); MODULE_AUTHOR("Alan Stern"); MODULE_LICENSE("GPL"); +MODULE_SOFTDEP("pre: ehci_platform"); diff --git a/drivers/usb/host/uhci-platform.c b/drivers/usb/host/uhci-platform.c index 62318291f5664..be8cba0242892 100644 --- a/drivers/usb/host/uhci-platform.c +++ b/drivers/usb/host/uhci-platform.c @@ -191,3 +191,4 @@ static struct platform_driver uhci_platform_driver = { .of_match_table = platform_uhci_ids, }, }; +MODULE_SOFTDEP("pre: ehci_platform"); From 37bbcfa2bac9ba8087470329831603a1f94d5ef7 Mon Sep 17 00:00:00 2001 From: Ulrich Mohr Date: Tue, 9 Dec 2025 21:08:41 +0100 Subject: [PATCH 2082/2333] USB: serial: option: add Telit LE910 MBIM composition commit 8af4274ab5999831f4757dfd5bd11665ba3b1569 upstream. Add support for Telit LE910 module when operating in MBIM composition with additional ttys. This USB product ID is used by the module when AT#USBCFG is set to 7. 0x1252: MBIM + tty(NMEA) + tty(MODEM) + tty(MODEM) + SAP T: Bus=01 Lev=01 Prnt=01 Port=01 Cnt=01 Dev#= 2 Spd=480 MxCh= 0 D: Ver= 2.00 Cls=ef(misc ) Sub=02 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=1bc7 ProdID=1252 Rev=03.18 S: Manufacturer=Android S: Product=LE910C1-EU S: SerialNumber=0123456789ABCDEF C: #Ifs= 6 Cfg#= 1 Atr=a0 MxPwr=500mA I: If#= 0 Alt= 0 #EPs= 1 Cls=02(commc) Sub=0e Prot=00 Driver=cdc_mbim E: Ad=82(I) Atr=03(Int.) MxPS= 64 Ivl=32ms I: If#= 1 Alt= 1 #EPs= 2 Cls=0a(data ) Sub=00 Prot=02 Driver=cdc_mbim E: Ad=01(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=81(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms I: If#= 2 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=00 Prot=00 Driver=option E: Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=83(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=84(I) Atr=03(Int.) MxPS= 10 Ivl=32ms I: If#= 3 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=00 Prot=00 Driver=option E: Ad=03(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=85(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=86(I) Atr=03(Int.) MxPS= 10 Ivl=32ms I: If#= 4 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=00 Prot=00 Driver=option E: Ad=04(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=87(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=88(I) Atr=03(Int.) MxPS= 10 Ivl=32ms I: If#= 5 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=00 Prot=00 Driver=option E: Ad=05(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=89(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=8a(I) Atr=03(Int.) MxPS= 10 Ivl=32ms Signed-off-by: Ulrich Mohr Cc: stable@vger.kernel.org Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 4c0e5a3ab557b..9f2cc5fb9f456 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -1505,6 +1505,7 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1231, 0xff), /* Telit LE910Cx (RNDIS) */ .driver_info = NCTRL(2) | RSVD(3) }, { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x1250, 0xff, 0x00, 0x00) }, /* Telit LE910Cx (rmnet) */ + { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1252, 0xff) }, /* Telit LE910Cx (MBIM) */ { USB_DEVICE(TELIT_VENDOR_ID, 0x1260), .driver_info = NCTRL(0) | RSVD(1) | RSVD(2) }, { USB_DEVICE(TELIT_VENDOR_ID, 0x1261), From a045dab08049ea292db93888e0b017de54d9ee72 Mon Sep 17 00:00:00 2001 From: Ethan Nelson-Moore Date: Wed, 10 Dec 2025 18:01:17 -0800 Subject: [PATCH 2083/2333] USB: serial: ftdi_sio: add support for PICAXE AXE027 cable commit c0afe95e62984ceea171c3ea319beaf84a21181c upstream. The vendor provides instructions to write "0403 bd90" to /sys/bus/usb-serial/drivers/ftdi_sio/new_id; see: https://picaxe.com/docs/picaxe_linux_instructions.pdf Cc: stable@vger.kernel.org Signed-off-by: Ethan Nelson-Moore Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 1 + drivers/usb/serial/ftdi_sio_ids.h | 2 ++ 2 files changed, 3 insertions(+) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 9993a5123344e..ceddfb1852e16 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -850,6 +850,7 @@ static const struct usb_device_id id_table_combined[] = { { USB_DEVICE_INTERFACE_NUMBER(FTDI_VID, LMI_LM3S_DEVEL_BOARD_PID, 1) }, { USB_DEVICE_INTERFACE_NUMBER(FTDI_VID, LMI_LM3S_EVAL_BOARD_PID, 1) }, { USB_DEVICE_INTERFACE_NUMBER(FTDI_VID, LMI_LM3S_ICDI_BOARD_PID, 1) }, + { USB_DEVICE(FTDI_VID, FTDI_AXE027_PID) }, { USB_DEVICE_INTERFACE_NUMBER(FTDI_VID, FTDI_TURTELIZER_PID, 1) }, { USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID_USB60F) }, { USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID_SCU18) }, diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index 2539b9e2f712c..6c76cfebfd0e4 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -96,6 +96,8 @@ #define LMI_LM3S_EVAL_BOARD_PID 0xbcd9 #define LMI_LM3S_ICDI_BOARD_PID 0xbcda +#define FTDI_AXE027_PID 0xBD90 /* PICAXE AXE027 USB download cable */ + #define FTDI_TURTELIZER_PID 0xBDC8 /* JTAG/RS-232 adapter by egnite GmbH */ /* OpenDCC (www.opendcc.de) product id */ From 2de213de610315019cc81d763e6a025dab94fc15 Mon Sep 17 00:00:00 2001 From: Ilikara Zheng Date: Mon, 8 Dec 2025 21:23:40 +0800 Subject: [PATCH 2084/2333] nvme-pci: disable secondary temp for Wodposit WPBSNM8 commit 340f4fc5508c2905a1f30de229e2a4b299d55735 upstream. Secondary temperature thresholds (temp2_{min,max}) were not reported properly on this NVMe SSD. This resulted in an error while attempting to read these values with sensors(1): ERROR: Can't get value of subfeature temp2_min: I/O error ERROR: Can't get value of subfeature temp2_max: I/O error Add the device to the nvme_id_table with the NVME_QUIRK_NO_SECONDARY_TEMP_THRESH flag to suppress access to all non- composite temperature thresholds. Cc: stable@vger.kernel.org Tested-by: Wu Haotian Signed-off-by: Ilikara Zheng Signed-off-by: Keith Busch Signed-off-by: Greg Kroah-Hartman --- drivers/nvme/host/pci.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c index 72fb675a696f4..eeffdd7bb2297 100644 --- a/drivers/nvme/host/pci.c +++ b/drivers/nvme/host/pci.c @@ -3917,6 +3917,8 @@ static const struct pci_device_id nvme_id_table[] = { .driver_data = NVME_QUIRK_NO_DEEPEST_PS, }, { PCI_DEVICE(0x1e49, 0x0041), /* ZHITAI TiPro7000 NVMe SSD */ .driver_data = NVME_QUIRK_NO_DEEPEST_PS, }, + { PCI_DEVICE(0x1fa0, 0x2283), /* Wodposit WPBSNM8-256GTP */ + .driver_data = NVME_QUIRK_NO_SECONDARY_TEMP_THRESH, }, { PCI_DEVICE(0x025e, 0xf1ac), /* SOLIDIGM P44 pro SSDPFKKW020X7 */ .driver_data = NVME_QUIRK_NO_DEEPEST_PS, }, { PCI_DEVICE(0xc0a9, 0x540a), /* Crucial P2 */ From 5caac66da5ba8af82397c4f50c26025530db960c Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Fri, 2 Jan 2026 12:14:11 +0100 Subject: [PATCH 2085/2333] ASoC: codecs: wsa881x: fix unnecessary initialisation commit 29d71b8a5a40708b3eed9ba4953bfc2312c9c776 upstream. The soundwire update_status() callback may be called multiple times with the same ATTACHED status but initialisation should only be done when transitioning from UNATTACHED to ATTACHED. Fixes: a0aab9e1404a ("ASoC: codecs: add wsa881x amplifier support") Cc: stable@vger.kernel.org # 5.6 Cc: Srinivas Kandagatla Signed-off-by: Johan Hovold Reviewed-by: Krzysztof Kozlowski Reviewed-by: Srinivas Kandagatla Link: https://patch.msgid.link/20260102111413.9605-3-johan@kernel.org Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/codecs/wsa881x.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sound/soc/codecs/wsa881x.c b/sound/soc/codecs/wsa881x.c index 636e59abc3772..561950ecb8cc7 100644 --- a/sound/soc/codecs/wsa881x.c +++ b/sound/soc/codecs/wsa881x.c @@ -678,6 +678,7 @@ struct wsa881x_priv { */ unsigned int sd_n_val; int active_ports; + bool hw_init; bool port_prepared[WSA881X_MAX_SWR_PORTS]; bool port_enable[WSA881X_MAX_SWR_PORTS]; }; @@ -687,6 +688,9 @@ static void wsa881x_init(struct wsa881x_priv *wsa881x) struct regmap *rm = wsa881x->regmap; unsigned int val = 0; + if (wsa881x->hw_init) + return; + regmap_register_patch(wsa881x->regmap, wsa881x_rev_2_0, ARRAY_SIZE(wsa881x_rev_2_0)); @@ -724,6 +728,8 @@ static void wsa881x_init(struct wsa881x_priv *wsa881x) regmap_update_bits(rm, WSA881X_OTP_REG_28, 0x3F, 0x3A); regmap_update_bits(rm, WSA881X_BONGO_RESRV_REG1, 0xFF, 0xB2); regmap_update_bits(rm, WSA881X_BONGO_RESRV_REG2, 0xFF, 0x05); + + wsa881x->hw_init = true; } static int wsa881x_component_probe(struct snd_soc_component *comp) @@ -1067,6 +1073,9 @@ static int wsa881x_update_status(struct sdw_slave *slave, { struct wsa881x_priv *wsa881x = dev_get_drvdata(&slave->dev); + if (status == SDW_SLAVE_UNATTACHED) + wsa881x->hw_init = false; + if (status == SDW_SLAVE_ATTACHED && slave->dev_num > 0) wsa881x_init(wsa881x); From d1b24a57662b68c9637d62defc4acb41f28eccfc Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 4 Dec 2025 11:19:10 +0100 Subject: [PATCH 2086/2333] ext4: fix ext4_tune_sb_params padding commit cd16edba1c6a24af138e1a5ded2711231fffa99f upstream. The padding at the end of struct ext4_tune_sb_params is architecture specific and in particular is different between x86-32 and x86-64, since the __u64 member only enforces struct alignment on the latter. This shows up as a new warning when test-building the headers with -Wpadded: include/linux/ext4.h:144:1: error: padding struct size to alignment boundary with 4 bytes [-Werror=padded] All members inside the structure are naturally aligned, so the only difference here is the amount of padding at the end. Make the padding explicit, to have a consistent sizeof(struct ext4_tune_sb_params) of 232 on all architectures and avoid adding compat ioctl handling for EXT4_IOC_GET_TUNE_SB_PARAM/EXT4_IOC_SET_TUNE_SB_PARAM. This is an ABI break on x86-32 but hopefully this can go into 6.18.y early enough as a fixup so no actual users will be affected. Alternatively, the kernel could handle the ioctl commands for both sizes (232 and 228 bytes) on all architectures. Fixes: 04a91570ac67 ("ext4: implemet new ioctls to set and get superblock parameters") Signed-off-by: Arnd Bergmann Reviewed-by: Jan Kara Link: https://patch.msgid.link/20251204101914.1037148-1-arnd@kernel.org Signed-off-by: Theodore Ts'o Cc: stable@kernel.org Signed-off-by: Greg Kroah-Hartman --- include/uapi/linux/ext4.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/uapi/linux/ext4.h b/include/uapi/linux/ext4.h index 411dcc1e4a35c..9c683991c32f9 100644 --- a/include/uapi/linux/ext4.h +++ b/include/uapi/linux/ext4.h @@ -139,7 +139,7 @@ struct ext4_tune_sb_params { __u32 clear_feature_incompat_mask; __u32 clear_feature_ro_compat_mask; __u8 mount_opts[64]; - __u8 pad[64]; + __u8 pad[68]; }; #define EXT4_TUNE_FL_ERRORS_BEHAVIOR 0x00000001 From 06e26287f2e349a28ad363941ffd9076bfed8b2e Mon Sep 17 00:00:00 2001 From: Yang Erkun Date: Sat, 13 Dec 2025 13:57:06 +0800 Subject: [PATCH 2087/2333] ext4: fix iloc.bh leak in ext4_xattr_inode_update_ref commit d250bdf531d9cd4096fedbb9f172bb2ca660c868 upstream. The error branch for ext4_xattr_inode_update_ref forget to release the refcount for iloc.bh. Find this when review code. Fixes: 57295e835408 ("ext4: guard against EA inode refcount underflow in xattr update") Signed-off-by: Yang Erkun Reviewed-by: Baokun Li Reviewed-by: Zhang Yi Link: https://patch.msgid.link/20251213055706.3417529-1-yangerkun@huawei.com Signed-off-by: Theodore Ts'o Cc: stable@kernel.org Signed-off-by: Greg Kroah-Hartman --- fs/ext4/xattr.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c index 2e02efbddaacc..4ed8ddf2a60b3 100644 --- a/fs/ext4/xattr.c +++ b/fs/ext4/xattr.c @@ -1037,6 +1037,7 @@ static int ext4_xattr_inode_update_ref(handle_t *handle, struct inode *ea_inode, ext4_error_inode(ea_inode, __func__, __LINE__, 0, "EA inode %lu ref wraparound: ref_count=%lld ref_change=%d", ea_inode->i_ino, ref_count, ref_change); + brelse(iloc.bh); ret = -EFSCORRUPTED; goto out; } From d53b8e05be46aec274b0067590a0c4f989e00830 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Wed, 7 Jan 2026 11:39:24 +0100 Subject: [PATCH 2088/2333] hrtimer: Fix softirq base check in update_needs_ipi() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 05dc4a9fc8b36d4c99d76bbc02aa9ec0132de4c2 upstream. The 'clockid' field is not the correct way to check for a softirq base. Fix the check to correctly compare the base type instead of the clockid. Fixes: 1e7f7fbcd40c ("hrtimer: Avoid more SMP function calls in clock_was_set()") Signed-off-by: Thomas Weißschuh Signed-off-by: Thomas Gleixner Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20260107-hrtimer-clock-base-check-v1-1-afb5dbce94a1@linutronix.de Signed-off-by: Greg Kroah-Hartman --- kernel/time/hrtimer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c index 88aa062b8a556..e618addb58641 100644 --- a/kernel/time/hrtimer.c +++ b/kernel/time/hrtimer.c @@ -913,7 +913,7 @@ static bool update_needs_ipi(struct hrtimer_cpu_base *cpu_base, return true; /* Extra check for softirq clock bases */ - if (base->clockid < HRTIMER_BASE_MONOTONIC_SOFT) + if (base->index < HRTIMER_BASE_MONOTONIC_SOFT) continue; if (cpu_base->softirq_activated) continue; From 3981650922417ea3d2e96272d70b08ad534295be Mon Sep 17 00:00:00 2001 From: Haoxiang Li Date: Tue, 23 Dec 2025 20:43:50 +0800 Subject: [PATCH 2089/2333] EDAC/x38: Fix a resource leak in x38_probe1() commit 0ff7c44106b4715fc27a2e455d9f57f1dfcfd54f upstream. If edac_mc_alloc() fails, also unmap the window. [ bp: Use separate labels, turning it into the classic unwind pattern. ] Fixes: df8bc08c192f ("edac x38: new MC driver module") Signed-off-by: Haoxiang Li Signed-off-by: Borislav Petkov (AMD) Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20251223124350.1496325-1-lihaoxiang@isrc.iscas.ac.cn Signed-off-by: Greg Kroah-Hartman --- drivers/edac/x38_edac.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/edac/x38_edac.c b/drivers/edac/x38_edac.c index 49ab5721aab25..292dda754c236 100644 --- a/drivers/edac/x38_edac.c +++ b/drivers/edac/x38_edac.c @@ -341,9 +341,12 @@ static int x38_probe1(struct pci_dev *pdev, int dev_idx) layers[1].type = EDAC_MC_LAYER_CHANNEL; layers[1].size = x38_channel_num; layers[1].is_virt_csrow = false; + + + rc = -ENOMEM; mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers, 0); if (!mci) - return -ENOMEM; + goto unmap; edac_dbg(3, "MC: init mci\n"); @@ -403,9 +406,9 @@ static int x38_probe1(struct pci_dev *pdev, int dev_idx) return 0; fail: + edac_mc_free(mci); +unmap: iounmap(window); - if (mci) - edac_mc_free(mci); return rc; } From 51afd139fac44f56ba113a1cd9abdf3bc4b3a8d3 Mon Sep 17 00:00:00 2001 From: Haoxiang Li Date: Tue, 23 Dec 2025 20:32:02 +0800 Subject: [PATCH 2090/2333] EDAC/i3200: Fix a resource leak in i3200_probe1() commit d42d5715dcb559342ff356327b241c53a67584d9 upstream. If edac_mc_alloc() fails, also unmap the window. [ bp: Use separate labels, turning it into the classic unwind pattern. ] Fixes: dd8ef1db87a4 ("edac: i3200 memory controller driver") Signed-off-by: Haoxiang Li Signed-off-by: Borislav Petkov (AMD) Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20251223123202.1492038-1-lihaoxiang@isrc.iscas.ac.cn Signed-off-by: Greg Kroah-Hartman --- drivers/edac/i3200_edac.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/edac/i3200_edac.c b/drivers/edac/i3200_edac.c index afccdebf5ac1e..6cade6d7ceff6 100644 --- a/drivers/edac/i3200_edac.c +++ b/drivers/edac/i3200_edac.c @@ -358,10 +358,11 @@ static int i3200_probe1(struct pci_dev *pdev, int dev_idx) layers[1].type = EDAC_MC_LAYER_CHANNEL; layers[1].size = nr_channels; layers[1].is_virt_csrow = false; - mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers, - sizeof(struct i3200_priv)); + + rc = -ENOMEM; + mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers, sizeof(struct i3200_priv)); if (!mci) - return -ENOMEM; + goto unmap; edac_dbg(3, "MC: init mci\n"); @@ -421,9 +422,9 @@ static int i3200_probe1(struct pci_dev *pdev, int dev_idx) return 0; fail: + edac_mc_free(mci); +unmap: iounmap(window); - if (mci) - edac_mc_free(mci); return rc; } From bd4e97674582ae40b3af796b56bd890618423148 Mon Sep 17 00:00:00 2001 From: Arnaud Ferraris Date: Mon, 5 Jan 2026 09:43:23 +0100 Subject: [PATCH 2091/2333] tcpm: allow looking for role_sw device in the main node commit 1366cd228b0c67b60a2c0c26ef37fe9f7cfedb7f upstream. If ports are defined in the tcpc main node, fwnode_usb_role_switch_get() returns an error, meaning usb_role_switch_get() (which would succeed) never gets a chance to run as port->role_sw isn't NULL, causing a regression on devices where this is the case. Fix this by turning the NULL check into IS_ERR_OR_NULL(), so usb_role_switch_get() can actually run and the device get properly probed. Fixes: 2d8713f807a4 ("tcpm: switch check for role_sw device with fw_node") Cc: stable Reviewed-by: Heikki Krogerus Reviewed-by: Dragan Simic Signed-off-by: Arnaud Ferraris Link: https://patch.msgid.link/20260105-fix-ppp-power-v2-1-6924f5a41224@collabora.com Signed-off-by: Greg Kroah-Hartman Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/tcpm/tcpm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c index cc78770509dbc..37698204d48d2 100644 --- a/drivers/usb/typec/tcpm/tcpm.c +++ b/drivers/usb/typec/tcpm/tcpm.c @@ -7877,7 +7877,7 @@ struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc) port->partner_desc.identity = &port->partner_ident; port->role_sw = fwnode_usb_role_switch_get(tcpc->fwnode); - if (!port->role_sw) + if (IS_ERR_OR_NULL(port->role_sw)) port->role_sw = usb_role_switch_get(port->dev); if (IS_ERR(port->role_sw)) { err = PTR_ERR(port->role_sw); From 0b4c0fbbe00b7de76bdaea7fa771017d7a979b0d Mon Sep 17 00:00:00 2001 From: Tommaso Merciai Date: Thu, 18 Dec 2025 16:10:21 +0100 Subject: [PATCH 2092/2333] i2c: riic: Move suspend handling to NOIRQ phase commit e383f0961422f983451ac4dd6aed1a3d3311f2be upstream. Commit 53326135d0e0 ("i2c: riic: Add suspend/resume support") added suspend support for the Renesas I2C driver and following this change on RZ/G3E the following WARNING is seen on entering suspend ... [ 134.275704] Freezing remaining freezable tasks completed (elapsed 0.001 seconds) [ 134.285536] ------------[ cut here ]------------ [ 134.290298] i2c i2c-2: Transfer while suspended [ 134.295174] WARNING: drivers/i2c/i2c-core.h:56 at __i2c_smbus_xfer+0x1e4/0x214, CPU#0: systemd-sleep/388 [ 134.365507] Tainted: [W]=WARN [ 134.368485] Hardware name: Renesas SMARC EVK version 2 based on r9a09g047e57 (DT) [ 134.375961] pstate: 60400005 (nZCv daif +PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 134.382935] pc : __i2c_smbus_xfer+0x1e4/0x214 [ 134.387329] lr : __i2c_smbus_xfer+0x1e4/0x214 [ 134.391717] sp : ffff800083f23860 [ 134.395040] x29: ffff800083f23860 x28: 0000000000000000 x27: ffff800082ed5d60 [ 134.402226] x26: 0000001f4395fd74 x25: 0000000000000007 x24: 0000000000000001 [ 134.409408] x23: 0000000000000000 x22: 000000000000006f x21: ffff800083f23936 [ 134.416589] x20: ffff0000c090e140 x19: ffff0000c090e0d0 x18: 0000000000000006 [ 134.423771] x17: 6f63657320313030 x16: 2e30206465737061 x15: ffff800083f23280 [ 134.430953] x14: 0000000000000000 x13: ffff800082b16ce8 x12: 0000000000000f09 [ 134.438134] x11: 0000000000000503 x10: ffff800082b6ece8 x9 : ffff800082b16ce8 [ 134.445315] x8 : 00000000ffffefff x7 : ffff800082b6ece8 x6 : 80000000fffff000 [ 134.452495] x5 : 0000000000000504 x4 : 0000000000000000 x3 : 0000000000000000 [ 134.459672] x2 : 0000000000000000 x1 : 0000000000000000 x0 : ffff0000c9ee9e80 [ 134.466851] Call trace: [ 134.469311] __i2c_smbus_xfer+0x1e4/0x214 (P) [ 134.473715] i2c_smbus_xfer+0xbc/0x120 [ 134.477507] i2c_smbus_read_byte_data+0x4c/0x84 [ 134.482077] isl1208_i2c_read_time+0x44/0x178 [rtc_isl1208] [ 134.487703] isl1208_rtc_read_time+0x14/0x20 [rtc_isl1208] [ 134.493226] __rtc_read_time+0x44/0x88 [ 134.497012] rtc_read_time+0x3c/0x68 [ 134.500622] rtc_suspend+0x9c/0x170 The warning is triggered because I2C transfers can still be attempted while the controller is already suspended, due to inappropriate ordering of the system sleep callbacks. If the controller is autosuspended, there is no way to wake it up once runtime PM disabled (in suspend_late()). During system resume, the I2C controller will be available only after runtime PM is re-enabled (in resume_early()). However, this may be too late for some devices. Wake up the controller in the suspend() callback while runtime PM is still enabled. The I2C controller will remain available until the suspend_noirq() callback (pm_runtime_force_suspend()) is called. During resume, the I2C controller can be restored by the resume_noirq() callback (pm_runtime_force_resume()). Finally, the resume() callback re-enables autosuspend. As a result, the I2C controller can remain available until the system enters suspend_noirq() and from resume_noirq(). Cc: stable@vger.kernel.org Fixes: 53326135d0e0 ("i2c: riic: Add suspend/resume support") Signed-off-by: Tommaso Merciai Reviewed-by: Biju Das Tested-by: Biju Das Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/busses/i2c-riic.c | 46 +++++++++++++++++++++++++++++------ 1 file changed, 39 insertions(+), 7 deletions(-) diff --git a/drivers/i2c/busses/i2c-riic.c b/drivers/i2c/busses/i2c-riic.c index 3e8f126cb7f74..9e3595b3623e4 100644 --- a/drivers/i2c/busses/i2c-riic.c +++ b/drivers/i2c/busses/i2c-riic.c @@ -670,12 +670,39 @@ static const struct riic_of_data riic_rz_t2h_info = { static int riic_i2c_suspend(struct device *dev) { - struct riic_dev *riic = dev_get_drvdata(dev); - int ret; + /* + * Some I2C devices may need the I2C controller to remain active + * during resume_noirq() or suspend_noirq(). If the controller is + * autosuspended, there is no way to wake it up once runtime PM is + * disabled (in suspend_late()). + * + * During system resume, the I2C controller will be available only + * after runtime PM is re-enabled (in resume_early()). However, this + * may be too late for some devices. + * + * Wake up the controller in the suspend() callback while runtime PM + * is still enabled. The I2C controller will remain available until + * the suspend_noirq() callback (pm_runtime_force_suspend()) is + * called. During resume, the I2C controller can be restored by the + * resume_noirq() callback (pm_runtime_force_resume()). + * + * Finally, the resume() callback re-enables autosuspend, ensuring + * the I2C controller remains available until the system enters + * suspend_noirq() and from resume_noirq(). + */ + return pm_runtime_resume_and_get(dev); +} - ret = pm_runtime_resume_and_get(dev); - if (ret) - return ret; +static int riic_i2c_resume(struct device *dev) +{ + pm_runtime_put_autosuspend(dev); + + return 0; +} + +static int riic_i2c_suspend_noirq(struct device *dev) +{ + struct riic_dev *riic = dev_get_drvdata(dev); i2c_mark_adapter_suspended(&riic->adapter); @@ -683,12 +710,12 @@ static int riic_i2c_suspend(struct device *dev) riic_clear_set_bit(riic, ICCR1_ICE, 0, RIIC_ICCR1); pm_runtime_mark_last_busy(dev); - pm_runtime_put_sync(dev); + pm_runtime_force_suspend(dev); return reset_control_assert(riic->rstc); } -static int riic_i2c_resume(struct device *dev) +static int riic_i2c_resume_noirq(struct device *dev) { struct riic_dev *riic = dev_get_drvdata(dev); int ret; @@ -697,6 +724,10 @@ static int riic_i2c_resume(struct device *dev) if (ret) return ret; + ret = pm_runtime_force_resume(dev); + if (ret) + return ret; + ret = riic_init_hw(riic); if (ret) { /* @@ -714,6 +745,7 @@ static int riic_i2c_resume(struct device *dev) } static const struct dev_pm_ops riic_i2c_pm_ops = { + NOIRQ_SYSTEM_SLEEP_PM_OPS(riic_i2c_suspend_noirq, riic_i2c_resume_noirq) SYSTEM_SLEEP_PM_OPS(riic_i2c_suspend, riic_i2c_resume) }; From 1144298c1008963dd95b019ece25dce4fe4e3ffd Mon Sep 17 00:00:00 2001 From: Xiaochen Shen Date: Tue, 9 Dec 2025 14:26:49 +0800 Subject: [PATCH 2093/2333] x86/resctrl: Add missing resctrl initialization for Hygon commit 6ee98aabdc700b5705e4f1833e2edc82a826b53b upstream. Hygon CPUs supporting Platform QoS features currently undergo partial resctrl initialization through resctrl_cpu_detect() in the Hygon BSP init helper and AMD/Hygon common initialization code. However, several critical data structures remain uninitialized for Hygon CPUs in the following paths: - get_mem_config()-> __rdt_get_mem_config_amd(): rdt_resource::membw,alloc_capable hw_res::num_closid - rdt_init_res_defs()->rdt_init_res_defs_amd(): rdt_resource::cache hw_res::msr_base,msr_update Add the missing AMD/Hygon common initialization to ensure proper Platform QoS functionality on Hygon CPUs. Fixes: d8df126349da ("x86/cpu/hygon: Add missing resctrl_cpu_detect() in bsp_init helper") Signed-off-by: Xiaochen Shen Signed-off-by: Borislav Petkov (AMD) Reviewed-by: Reinette Chatre Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20251209062650.1536952-2-shenxiaochen@open-hieco.net Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/cpu/resctrl/core.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/x86/kernel/cpu/resctrl/core.c b/arch/x86/kernel/cpu/resctrl/core.c index 06ca5a30140c2..c0dfbb31394ef 100644 --- a/arch/x86/kernel/cpu/resctrl/core.c +++ b/arch/x86/kernel/cpu/resctrl/core.c @@ -818,7 +818,8 @@ static __init bool get_mem_config(void) if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) return __get_mem_config_intel(&hw_res->r_resctrl); - else if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) + else if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD || + boot_cpu_data.x86_vendor == X86_VENDOR_HYGON) return __rdt_get_mem_config_amd(&hw_res->r_resctrl); return false; @@ -978,7 +979,8 @@ static __init void rdt_init_res_defs(void) { if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) rdt_init_res_defs_intel(); - else if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) + else if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD || + boot_cpu_data.x86_vendor == X86_VENDOR_HYGON) rdt_init_res_defs_amd(); } From 43d8f1f001072718b5b42c624f00efcecd6aecc3 Mon Sep 17 00:00:00 2001 From: Xiaochen Shen Date: Tue, 9 Dec 2025 14:26:50 +0800 Subject: [PATCH 2094/2333] x86/resctrl: Fix memory bandwidth counter width for Hygon commit 7517e899e1b87b4c22a92c7e40d8733c48e4ec3c upstream. The memory bandwidth calculation relies on reading the hardware counter and measuring the delta between samples. To ensure accurate measurement, the software reads the counter frequently enough to prevent it from rolling over twice between reads. The default Memory Bandwidth Monitoring (MBM) counter width is 24 bits. Hygon CPUs provide a 32-bit width counter, but they do not support the MBM capability CPUID leaf (0xF.[ECX=1]:EAX) to report the width offset (from 24 bits). Consequently, the kernel falls back to the 24-bit default counter width, which causes incorrect overflow handling on Hygon CPUs. Fix this by explicitly setting the counter width offset to 8 bits (resulting in a 32-bit total counter width) for Hygon CPUs. Fixes: d8df126349da ("x86/cpu/hygon: Add missing resctrl_cpu_detect() in bsp_init helper") Signed-off-by: Xiaochen Shen Signed-off-by: Borislav Petkov (AMD) Reviewed-by: Tony Luck Reviewed-by: Reinette Chatre Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20251209062650.1536952-3-shenxiaochen@open-hieco.net Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/cpu/resctrl/core.c | 15 +++++++++++++-- arch/x86/kernel/cpu/resctrl/internal.h | 3 +++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/arch/x86/kernel/cpu/resctrl/core.c b/arch/x86/kernel/cpu/resctrl/core.c index c0dfbb31394ef..79a1f2d5f5019 100644 --- a/arch/x86/kernel/cpu/resctrl/core.c +++ b/arch/x86/kernel/cpu/resctrl/core.c @@ -1012,8 +1012,19 @@ void resctrl_cpu_detect(struct cpuinfo_x86 *c) c->x86_cache_occ_scale = ebx; c->x86_cache_mbm_width_offset = eax & 0xff; - if (c->x86_vendor == X86_VENDOR_AMD && !c->x86_cache_mbm_width_offset) - c->x86_cache_mbm_width_offset = MBM_CNTR_WIDTH_OFFSET_AMD; + if (!c->x86_cache_mbm_width_offset) { + switch (c->x86_vendor) { + case X86_VENDOR_AMD: + c->x86_cache_mbm_width_offset = MBM_CNTR_WIDTH_OFFSET_AMD; + break; + case X86_VENDOR_HYGON: + c->x86_cache_mbm_width_offset = MBM_CNTR_WIDTH_OFFSET_HYGON; + break; + default: + /* Leave c->x86_cache_mbm_width_offset as 0 */ + break; + } + } } } diff --git a/arch/x86/kernel/cpu/resctrl/internal.h b/arch/x86/kernel/cpu/resctrl/internal.h index 9f4c2f0aaf5c8..6da9bd1a188b9 100644 --- a/arch/x86/kernel/cpu/resctrl/internal.h +++ b/arch/x86/kernel/cpu/resctrl/internal.h @@ -14,6 +14,9 @@ #define MBM_CNTR_WIDTH_OFFSET_AMD 20 +/* Hygon MBM counter width as an offset from MBM_CNTR_WIDTH_BASE */ +#define MBM_CNTR_WIDTH_OFFSET_HYGON 8 + #define RMID_VAL_ERROR BIT_ULL(63) #define RMID_VAL_UNAVAIL BIT_ULL(62) From 17f95d348589b2d65b0799f35a3c617e61cc4a28 Mon Sep 17 00:00:00 2001 From: Nilay Shroff Date: Wed, 14 Jan 2026 12:54:13 +0530 Subject: [PATCH 2095/2333] nvme: fix PCIe subsystem reset controller state transition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 0edb475ac0a7d153318a24d4dca175a270a5cc4f upstream. The commit d2fe192348f9 (“nvme: only allow entering LIVE from CONNECTING state”) disallows controller state transitions directly from RESETTING to LIVE. However, the NVMe PCIe subsystem reset path relies on this transition to recover the controller on PowerPC (PPC) systems. On PPC systems, issuing a subsystem reset causes a temporary loss of communication with the NVMe adapter. A subsequent PCIe MMIO read then triggers EEH recovery, which restores the PCIe link and brings the controller back online. For EEH recovery to proceed correctly, the controller must transition back to the LIVE state. Due to the changes introduced by commit d2fe192348f9 (“nvme: only allow entering LIVE from CONNECTING state”), the controller can no longer transition directly from RESETTING to LIVE. As a result, EEH recovery exits prematurely, leaving the controller stuck in the RESETTING state. Fix this by explicitly transitioning the controller state from RESETTING to CONNECTING and then to LIVE. This satisfies the updated state transition rules and allows the controller to be successfully recovered on PPC systems following a PCIe subsystem reset. Cc: stable@vger.kernel.org Fixes: d2fe192348f9 ("nvme: only allow entering LIVE from CONNECTING state") Reviewed-by: Daniel Wagner Signed-off-by: Nilay Shroff Signed-off-by: Keith Busch Signed-off-by: Greg Kroah-Hartman --- drivers/nvme/host/pci.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c index eeffdd7bb2297..28f638413e122 100644 --- a/drivers/nvme/host/pci.c +++ b/drivers/nvme/host/pci.c @@ -1461,7 +1461,10 @@ static int nvme_pci_subsystem_reset(struct nvme_ctrl *ctrl) } writel(NVME_SUBSYS_RESET, dev->bar + NVME_REG_NSSR); - nvme_change_ctrl_state(ctrl, NVME_CTRL_LIVE); + + if (!nvme_change_ctrl_state(ctrl, NVME_CTRL_CONNECTING) || + !nvme_change_ctrl_state(ctrl, NVME_CTRL_LIVE)) + goto unlock; /* * Read controller status to flush the previous write and trigger a From b5cb343f0c3d071848452ca856a3bacef7943933 Mon Sep 17 00:00:00 2001 From: Ryan Roberts Date: Sun, 4 Jan 2026 13:43:47 +0000 Subject: [PATCH 2096/2333] mm: kmsan: fix poisoning of high-order non-compound pages commit 4795d205d78690a46b60164f44b8bb7b3e800865 upstream. kmsan_free_page() is called by the page allocator's free_pages_prepare() during page freeing. Its job is to poison all the memory covered by the page. It can be called with an order-0 page, a compound high-order page or a non-compound high-order page. But page_size() only works for order-0 and compound pages. For a non-compound high-order page it will incorrectly return PAGE_SIZE. The implication is that the tail pages of a high-order non-compound page do not get poisoned at free, so any invalid access while they are free could go unnoticed. It looks like the pages will be poisoned again at allocation time, so that would bookend the window. Fix this by using the order parameter to calculate the size. Link: https://lkml.kernel.org/r/20260104134348.3544298-1-ryan.roberts@arm.com Fixes: b073d7f8aee4 ("mm: kmsan: maintain KMSAN metadata for page operations") Signed-off-by: Ryan Roberts Reviewed-by: Alexander Potapenko Tested-by: Alexander Potapenko Cc: Dmitriy Vyukov Cc: Dmitry Vyukov Cc: Marco Elver Cc: Ryan Roberts Cc: Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- mm/kmsan/shadow.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/kmsan/shadow.c b/mm/kmsan/shadow.c index 55fdea199aaf0..8bd50f5b1092e 100644 --- a/mm/kmsan/shadow.c +++ b/mm/kmsan/shadow.c @@ -207,7 +207,7 @@ void kmsan_free_page(struct page *page, unsigned int order) if (!kmsan_enabled || kmsan_in_runtime()) return; kmsan_enter_runtime(); - kmsan_internal_poison_memory(page_address(page), page_size(page), + kmsan_internal_poison_memory(page_address(page), PAGE_SIZE << order, GFP_KERNEL & ~(__GFP_RECLAIM), KMSAN_POISON_CHECK | KMSAN_POISON_FREE); kmsan_leave_runtime(); From 2a0db14ff1bc7ecd32f581497fd3c9fdb8111ec3 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Thu, 8 Jan 2026 10:15:39 +0000 Subject: [PATCH 2097/2333] mm: numa,memblock: include for 'numa_nodes_parsed' commit f46c26f1bcd9164d7f3377f15ca75488a3e44362 upstream. The 'numa_nodes_parsed' is defined in but this file is not included in mm/numa_memblks.c (build x86_64) so add this to the incldues to fix the following sparse warning: mm/numa_memblks.c:13:12: warning: symbol 'numa_nodes_parsed' was not declared. Should it be static? Link: https://lkml.kernel.org/r/20260108101539.229192-1-ben.dooks@codethink.co.uk Fixes: 87482708210f ("mm: introduce numa_memblks") Signed-off-by: Ben Dooks Reviewed-by: Mike Rapoport (Microsoft) Cc: Ben Dooks Cc: Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- mm/numa_memblks.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mm/numa_memblks.c b/mm/numa_memblks.c index 5b009a9cd8b4c..8f5735fda0a21 100644 --- a/mm/numa_memblks.c +++ b/mm/numa_memblks.c @@ -7,6 +7,8 @@ #include #include +#include + int numa_distance_cnt; static u8 *numa_distance; From 2ff7e1d125f79d8db48ecb2c5ff50c8a5cddc155 Mon Sep 17 00:00:00 2001 From: Pavel Butsykin Date: Wed, 31 Dec 2025 11:46:38 +0400 Subject: [PATCH 2098/2333] mm/zswap: fix error pointer free in zswap_cpu_comp_prepare() commit 590b13669b813d55844fecd9142c56abd567914d upstream. crypto_alloc_acomp_node() may return ERR_PTR(), but the fail path checks only for NULL and can pass an error pointer to crypto_free_acomp(). Use IS_ERR_OR_NULL() to only free valid acomp instances. Link: https://lkml.kernel.org/r/20251231074638.2564302-1-pbutsykin@cloudlinux.com Fixes: 779b9955f643 ("mm: zswap: move allocations during CPU init outside the lock") Signed-off-by: Pavel Butsykin Reviewed-by: SeongJae Park Acked-by: Yosry Ahmed Acked-by: Nhat Pham Cc: Johannes Weiner Cc: Chengming Zhou Cc: Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- mm/zswap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/zswap.c b/mm/zswap.c index c1af782e54ec6..12fb0e3954129 100644 --- a/mm/zswap.c +++ b/mm/zswap.c @@ -787,7 +787,7 @@ static int zswap_cpu_comp_prepare(unsigned int cpu, struct hlist_node *node) return 0; fail: - if (acomp) + if (!IS_ERR_OR_NULL(acomp)) crypto_free_acomp(acomp); kfree(buffer); return ret; From 0e8838c91e24ffd2862728b5ac287a6f7c7f9684 Mon Sep 17 00:00:00 2001 From: Aboorva Devarajan Date: Mon, 1 Dec 2025 11:30:09 +0530 Subject: [PATCH 2099/2333] mm/page_alloc: make percpu_pagelist_high_fraction reads lock-free commit b9efe36b5e3eb2e91aa3d706066428648af034fc upstream. When page isolation loops indefinitely during memory offline, reading /proc/sys/vm/percpu_pagelist_high_fraction blocks on pcp_batch_high_lock, causing hung task warnings. Make procfs reads lock-free since percpu_pagelist_high_fraction is a simple integer with naturally atomic reads, writers still serialize via the mutex. This prevents hung task warnings when reading the procfs file during long-running memory offline operations. [akpm@linux-foundation.org: add comment, per Michal] Link: https://lkml.kernel.org/r/aS_y9AuJQFydLEXo@tiehlicka Link: https://lkml.kernel.org/r/20251201060009.1420792-1-aboorvad@linux.ibm.com Signed-off-by: Aboorva Devarajan Acked-by: Michal Hocko Cc: Brendan Jackman Cc: Johannes Weiner Cc: Suren Baghdasaryan Cc: Vlastimil Babka Cc: Zi Yan Cc: Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- mm/page_alloc.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 6e644f2744c2d..764b7aabaf69f 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -6611,11 +6611,19 @@ static int percpu_pagelist_high_fraction_sysctl_handler(const struct ctl_table * int old_percpu_pagelist_high_fraction; int ret; + /* + * Avoid using pcp_batch_high_lock for reads as the value is read + * atomically and a race with offlining is harmless. + */ + + if (!write) + return proc_dointvec_minmax(table, write, buffer, length, ppos); + mutex_lock(&pcp_batch_high_lock); old_percpu_pagelist_high_fraction = percpu_pagelist_high_fraction; ret = proc_dointvec_minmax(table, write, buffer, length, ppos); - if (!write || ret < 0) + if (ret < 0) goto out; /* Sanity checking to avoid pcp imbalance */ From 23b061f421eef03647b512f3df48861706c87db3 Mon Sep 17 00:00:00 2001 From: SeongJae Park Date: Tue, 30 Dec 2025 17:23:13 -0800 Subject: [PATCH 2100/2333] mm/damon/core: remove call_control in inactive contexts commit f9132fbc2e83baf2c45a77043672a63a675c9394 upstream. If damon_call() is executed against a DAMON context that is not running, the function returns error while keeping the damon_call_control object linked to the context's call_controls list. Let's suppose the object is deallocated after the damon_call(), and yet another damon_call() is executed against the same context. The function tries to add the new damon_call_control object to the call_controls list, which still has the pointer to the previous damon_call_control object, which is deallocated. As a result, use-after-free happens. This can actually be triggered using the DAMON sysfs interface. It is not easily exploitable since it requires the sysfs write permission and making a definitely weird file writes, though. Please refer to the report for more details about the issue reproduction steps. Fix the issue by making two changes. Firstly, move the final kdamond_call() for cancelling all existing damon_call() requests from terminating DAMON context to be done before the ctx->kdamond reset. This makes any code that sees NULL ctx->kdamond can safely assume the context may not access damon_call() requests anymore. Secondly, let damon_call() to cleanup the damon_call_control objects that were added to the already-terminated DAMON context, before returning the error. Link: https://lkml.kernel.org/r/20251231012315.75835-1-sj@kernel.org Fixes: 004ded6bee11 ("mm/damon: accept parallel damon_call() requests") Signed-off-by: SeongJae Park Reported-by: JaeJoon Jung Closes: https://lore.kernel.org/20251224094401.20384-1-rgbi3307@gmail.com Cc: # 6.17.x Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- mm/damon/core.c | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/mm/damon/core.c b/mm/damon/core.c index 109b050c795ad..b787cdb07cb25 100644 --- a/mm/damon/core.c +++ b/mm/damon/core.c @@ -1426,6 +1426,35 @@ bool damon_is_running(struct damon_ctx *ctx) return running; } +/* + * damon_call_handle_inactive_ctx() - handle DAMON call request that added to + * an inactive context. + * @ctx: The inactive DAMON context. + * @control: Control variable of the call request. + * + * This function is called in a case that @control is added to @ctx but @ctx is + * not running (inactive). See if @ctx handled @control or not, and cleanup + * @control if it was not handled. + * + * Returns 0 if @control was handled by @ctx, negative error code otherwise. + */ +static int damon_call_handle_inactive_ctx( + struct damon_ctx *ctx, struct damon_call_control *control) +{ + struct damon_call_control *c; + + mutex_lock(&ctx->call_controls_lock); + list_for_each_entry(c, &ctx->call_controls, list) { + if (c == control) { + list_del(&control->list); + mutex_unlock(&ctx->call_controls_lock); + return -EINVAL; + } + } + mutex_unlock(&ctx->call_controls_lock); + return 0; +} + /** * damon_call() - Invoke a given function on DAMON worker thread (kdamond). * @ctx: DAMON context to call the function for. @@ -1456,7 +1485,7 @@ int damon_call(struct damon_ctx *ctx, struct damon_call_control *control) list_add_tail(&control->list, &ctx->call_controls); mutex_unlock(&ctx->call_controls_lock); if (!damon_is_running(ctx)) - return -EINVAL; + return damon_call_handle_inactive_ctx(ctx, control); if (control->repeat) return 0; wait_for_completion(&control->completion); @@ -2704,13 +2733,13 @@ static int kdamond_fn(void *data) if (ctx->ops.cleanup) ctx->ops.cleanup(ctx); kfree(ctx->regions_score_histogram); + kdamond_call(ctx, true); pr_debug("kdamond (%d) finishes\n", current->pid); mutex_lock(&ctx->kdamond_lock); ctx->kdamond = NULL; mutex_unlock(&ctx->kdamond_lock); - kdamond_call(ctx, true); damos_walk_cancel(ctx); mutex_lock(&damon_lock); From 253b8f56667ff43826dc7236bdc0fc4aeff5f75e Mon Sep 17 00:00:00 2001 From: SeongJae Park Date: Wed, 24 Dec 2025 18:30:36 -0800 Subject: [PATCH 2101/2333] mm/damon/sysfs-scheme: cleanup quotas subdirs on scheme dir setup failure commit dc7e1d75fd8c505096d0cddeca9e2efb2b55aaf9 upstream. When a DAMOS-scheme DAMON sysfs directory setup fails after setup of quotas/ directory, subdirectories of quotas/ directory are not cleaned up. As a result, DAMON sysfs interface is nearly broken until the system reboots, and the memory for the unremoved directory is leaked. Cleanup the directories under such failures. Link: https://lkml.kernel.org/r/20251225023043.18579-4-sj@kernel.org Fixes: 1b32234ab087 ("mm/damon/sysfs: support DAMOS watermarks") Signed-off-by: SeongJae Park Cc: chongjiapeng Cc: # 5.18.x Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- mm/damon/sysfs-schemes.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mm/damon/sysfs-schemes.c b/mm/damon/sysfs-schemes.c index 6536f16006c90..2501380e26c35 100644 --- a/mm/damon/sysfs-schemes.c +++ b/mm/damon/sysfs-schemes.c @@ -2117,7 +2117,7 @@ static int damon_sysfs_scheme_add_dirs(struct damon_sysfs_scheme *scheme) goto put_dests_out; err = damon_sysfs_scheme_set_watermarks(scheme); if (err) - goto put_quotas_access_pattern_out; + goto rmdir_put_quotas_access_pattern_out; err = damos_sysfs_set_filter_dirs(scheme); if (err) goto put_watermarks_quotas_access_pattern_out; @@ -2142,7 +2142,8 @@ static int damon_sysfs_scheme_add_dirs(struct damon_sysfs_scheme *scheme) put_watermarks_quotas_access_pattern_out: kobject_put(&scheme->watermarks->kobj); scheme->watermarks = NULL; -put_quotas_access_pattern_out: +rmdir_put_quotas_access_pattern_out: + damon_sysfs_quotas_rm_dirs(scheme->quotas); kobject_put(&scheme->quotas->kobj); scheme->quotas = NULL; put_dests_out: From 725d4fdaa01bd1161782081f419e1568cc7432e0 Mon Sep 17 00:00:00 2001 From: SeongJae Park Date: Wed, 24 Dec 2025 18:30:37 -0800 Subject: [PATCH 2102/2333] mm/damon/sysfs-scheme: cleanup access_pattern subdirs on scheme dir setup failure commit 392b3d9d595f34877dd745b470c711e8ebcd225c upstream. When a DAMOS-scheme DAMON sysfs directory setup fails after setup of access_pattern/ directory, subdirectories of access_pattern/ directory are not cleaned up. As a result, DAMON sysfs interface is nearly broken until the system reboots, and the memory for the unremoved directory is leaked. Cleanup the directories under such failures. Link: https://lkml.kernel.org/r/20251225023043.18579-5-sj@kernel.org Fixes: 9bbb820a5bd5 ("mm/damon/sysfs: support DAMOS quotas") Signed-off-by: SeongJae Park Cc: chongjiapeng Cc: # 5.18.x Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- mm/damon/sysfs-schemes.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mm/damon/sysfs-schemes.c b/mm/damon/sysfs-schemes.c index 2501380e26c35..50d000d61c907 100644 --- a/mm/damon/sysfs-schemes.c +++ b/mm/damon/sysfs-schemes.c @@ -2111,7 +2111,7 @@ static int damon_sysfs_scheme_add_dirs(struct damon_sysfs_scheme *scheme) return err; err = damos_sysfs_set_dests(scheme); if (err) - goto put_access_pattern_out; + goto rmdir_put_access_pattern_out; err = damon_sysfs_scheme_set_quotas(scheme); if (err) goto put_dests_out; @@ -2149,7 +2149,8 @@ static int damon_sysfs_scheme_add_dirs(struct damon_sysfs_scheme *scheme) put_dests_out: kobject_put(&scheme->dests->kobj); scheme->dests = NULL; -put_access_pattern_out: +rmdir_put_access_pattern_out: + damon_sysfs_access_pattern_rm_dirs(scheme->access_pattern); kobject_put(&scheme->access_pattern->kobj); scheme->access_pattern = NULL; return err; From 9dc11b365e4eba41b5fe5808b7df2916283a5337 Mon Sep 17 00:00:00 2001 From: SeongJae Park Date: Wed, 24 Dec 2025 18:30:34 -0800 Subject: [PATCH 2103/2333] mm/damon/sysfs: cleanup intervals subdirs on attrs dir setup failure commit a24ca8ebb0cd5ea07a1462b77be0f0823c40f319 upstream. Patch series "mm/damon/sysfs: free setup failures generated zombie sub-sub dirs". Some DAMON sysfs directory setup functions generates its sub and sub-sub directories. For example, 'monitoring_attrs/' directory setup creates 'intervals/' and 'intervals/intervals_goal/' directories under 'monitoring_attrs/' directory. When such sub-sub directories are successfully made but followup setup is failed, the setup function should recursively clean up the subdirectories. However, such setup functions are only dereferencing sub directory reference counters. As a result, under certain setup failures, the sub-sub directories keep having non-zero reference counters. It means the directories cannot be removed like zombies, and the memory for the directories cannot be freed. The user impact of this issue is limited due to the following reasons. When the issue happens, the zombie directories are still taking the path. Hence attempts to generate the directories again will fail, without additional memory leak. This means the upper bound memory leak is limited. Nonetheless this also implies controlling DAMON with a feature that requires the setup-failed sysfs files will be impossible until the system reboots. Also, the setup operations are quite simple. The certain failures would hence only rarely happen, and are difficult to artificially trigger. This patch (of 4): When attrs/ DAMON sysfs directory setup is failed after setup of intervals/ directory, intervals/intervals_goal/ directory is not cleaned up. As a result, DAMON sysfs interface is nearly broken until the system reboots, and the memory for the unremoved directory is leaked. Cleanup the directory under such failures. Link: https://lkml.kernel.org/r/20251225023043.18579-1-sj@kernel.org Link: https://lkml.kernel.org/r/20251225023043.18579-2-sj@kernel.org Fixes: 8fbbcbeaafeb ("mm/damon/sysfs: implement intervals tuning goal directory") Signed-off-by: SeongJae Park Cc: chongjiapeng Cc: # 6.15.x Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- mm/damon/sysfs.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mm/damon/sysfs.c b/mm/damon/sysfs.c index 3c0d727788c87..2b4920a722e49 100644 --- a/mm/damon/sysfs.c +++ b/mm/damon/sysfs.c @@ -764,7 +764,7 @@ static int damon_sysfs_attrs_add_dirs(struct damon_sysfs_attrs *attrs) nr_regions_range = damon_sysfs_ul_range_alloc(10, 1000); if (!nr_regions_range) { err = -ENOMEM; - goto put_intervals_out; + goto rmdir_put_intervals_out; } err = kobject_init_and_add(&nr_regions_range->kobj, @@ -778,6 +778,8 @@ static int damon_sysfs_attrs_add_dirs(struct damon_sysfs_attrs *attrs) put_nr_regions_intervals_out: kobject_put(&nr_regions_range->kobj); attrs->nr_regions_range = NULL; +rmdir_put_intervals_out: + damon_sysfs_intervals_rm_dirs(intervals); put_intervals_out: kobject_put(&intervals->kobj); attrs->intervals = NULL; From 78b4eb99751ebd37ceade78810bf94de80f7fb3a Mon Sep 17 00:00:00 2001 From: SeongJae Park Date: Wed, 24 Dec 2025 18:30:35 -0800 Subject: [PATCH 2104/2333] mm/damon/sysfs: cleanup attrs subdirs on context dir setup failure commit 9814cc832b88bd040fc2a1817c2b5469d0f7e862 upstream. When a context DAMON sysfs directory setup is failed after setup of attrs/ directory, subdirectories of attrs/ directory are not cleaned up. As a result, DAMON sysfs interface is nearly broken until the system reboots, and the memory for the unremoved directory is leaked. Cleanup the directories under such failures. Link: https://lkml.kernel.org/r/20251225023043.18579-3-sj@kernel.org Fixes: c951cd3b8901 ("mm/damon: implement a minimal stub for sysfs-based DAMON interface") Signed-off-by: SeongJae Park Cc: chongjiapeng Cc: # 5.18.x Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- mm/damon/sysfs.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mm/damon/sysfs.c b/mm/damon/sysfs.c index 2b4920a722e49..2caeca5624ce8 100644 --- a/mm/damon/sysfs.c +++ b/mm/damon/sysfs.c @@ -922,7 +922,7 @@ static int damon_sysfs_context_add_dirs(struct damon_sysfs_context *context) err = damon_sysfs_context_set_targets(context); if (err) - goto put_attrs_out; + goto rmdir_put_attrs_out; err = damon_sysfs_context_set_schemes(context); if (err) @@ -932,7 +932,8 @@ static int damon_sysfs_context_add_dirs(struct damon_sysfs_context *context) put_targets_attrs_out: kobject_put(&context->targets->kobj); context->targets = NULL; -put_attrs_out: +rmdir_put_attrs_out: + damon_sysfs_attrs_rm_dirs(context->attrs); kobject_put(&context->attrs->kobj); context->attrs = NULL; return err; From 5b14ce4975a02e67ffdc6d9359f823f9b83602cf Mon Sep 17 00:00:00 2001 From: Lisa Robinson Date: Sat, 17 Jan 2026 10:56:43 +0800 Subject: [PATCH 2105/2333] LoongArch: Fix PMU counter allocation for mixed-type event groups commit a91f86e27087f250a5d9c89bb4a427b9c30fd815 upstream. When validating a perf event group, validate_group() unconditionally attempts to allocate hardware PMU counters for the leader, sibling events and the new event being added. This is incorrect for mixed-type groups. If a PERF_TYPE_SOFTWARE event is part of the group, the current code still tries to allocate a hardware PMU counter for it, which can wrongly consume hardware PMU resources and cause spurious allocation failures. Fix this by only allocating PMU counters for hardware events during group validation, and skipping software events. A trimmed down reproducer is as simple as this: #include #include #include #include #include #include int main (int argc, char *argv[]) { struct perf_event_attr attr = { 0 }; int fds[5]; attr.disabled = 1; attr.exclude_kernel = 1; attr.exclude_hv = 1; attr.read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | PERF_FORMAT_TOTAL_TIME_RUNNING | PERF_FORMAT_ID | PERF_FORMAT_GROUP; attr.size = sizeof (attr); attr.type = PERF_TYPE_SOFTWARE; attr.config = PERF_COUNT_SW_DUMMY; fds[0] = syscall (SYS_perf_event_open, &attr, 0, -1, -1, 0); assert (fds[0] >= 0); attr.type = PERF_TYPE_HARDWARE; attr.config = PERF_COUNT_HW_CPU_CYCLES; fds[1] = syscall (SYS_perf_event_open, &attr, 0, -1, fds[0], 0); assert (fds[1] >= 0); attr.type = PERF_TYPE_HARDWARE; attr.config = PERF_COUNT_HW_INSTRUCTIONS; fds[2] = syscall (SYS_perf_event_open, &attr, 0, -1, fds[0], 0); assert (fds[2] >= 0); attr.type = PERF_TYPE_HARDWARE; attr.config = PERF_COUNT_HW_BRANCH_MISSES; fds[3] = syscall (SYS_perf_event_open, &attr, 0, -1, fds[0], 0); assert (fds[3] >= 0); attr.type = PERF_TYPE_HARDWARE; attr.config = PERF_COUNT_HW_CACHE_REFERENCES; fds[4] = syscall (SYS_perf_event_open, &attr, 0, -1, fds[0], 0); assert (fds[4] >= 0); printf ("PASSED\n"); return 0; } Cc: stable@vger.kernel.org Fixes: b37042b2bb7c ("LoongArch: Add perf events support") Signed-off-by: Lisa Robinson Signed-off-by: Huacai Chen Signed-off-by: Greg Kroah-Hartman --- arch/loongarch/kernel/perf_event.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/arch/loongarch/kernel/perf_event.c b/arch/loongarch/kernel/perf_event.c index 9d257c8519c90..e34a6fb33e11c 100644 --- a/arch/loongarch/kernel/perf_event.c +++ b/arch/loongarch/kernel/perf_event.c @@ -626,6 +626,18 @@ static const struct loongarch_perf_event *loongarch_pmu_map_cache_event(u64 conf return pev; } +static inline bool loongarch_pmu_event_requires_counter(const struct perf_event *event) +{ + switch (event->attr.type) { + case PERF_TYPE_HARDWARE: + case PERF_TYPE_HW_CACHE: + case PERF_TYPE_RAW: + return true; + default: + return false; + } +} + static int validate_group(struct perf_event *event) { struct cpu_hw_events fake_cpuc; @@ -633,15 +645,18 @@ static int validate_group(struct perf_event *event) memset(&fake_cpuc, 0, sizeof(fake_cpuc)); - if (loongarch_pmu_alloc_counter(&fake_cpuc, &leader->hw) < 0) + if (loongarch_pmu_event_requires_counter(leader) && + loongarch_pmu_alloc_counter(&fake_cpuc, &leader->hw) < 0) return -EINVAL; for_each_sibling_event(sibling, leader) { - if (loongarch_pmu_alloc_counter(&fake_cpuc, &sibling->hw) < 0) + if (loongarch_pmu_event_requires_counter(sibling) && + loongarch_pmu_alloc_counter(&fake_cpuc, &sibling->hw) < 0) return -EINVAL; } - if (loongarch_pmu_alloc_counter(&fake_cpuc, &event->hw) < 0) + if (loongarch_pmu_event_requires_counter(event) && + loongarch_pmu_alloc_counter(&fake_cpuc, &event->hw) < 0) return -EINVAL; return 0; From c1cc55ea5e956f60ff54a03c9712285f82737065 Mon Sep 17 00:00:00 2001 From: Yao Zi Date: Sat, 17 Jan 2026 10:56:52 +0800 Subject: [PATCH 2106/2333] LoongArch: dts: Describe PCI sideband IRQ through interrupt-extended commit 762cf75bec2ad9d17899087899a34336b1757238 upstream. SoC integrated peripherals on LS2K1000 and LS2K2000 could be discovered as PCI devices, but require sideband interrupts to function, which are previously described by interrupts and interrupt-parent properties. However, pci/pci-device.yaml allows interrupts property to only specify PCI INTx interrupts, not sideband ones. Convert these devices to use interrupt-extended property, which describes sideband interrupts used by PCI devices since dt-schema commit e6ea659d2baa ("schemas: pci-device: Allow interrupts-extended for sideband interrupts"), eliminating dtbs_check warnings. Cc: stable@vger.kernel.org Fixes: 30a5532a3206 ("LoongArch: dts: DeviceTree for Loongson-2K1000") Signed-off-by: Yao Zi Signed-off-by: Binbin Zhou Signed-off-by: Huacai Chen Signed-off-by: Greg Kroah-Hartman --- arch/loongarch/boot/dts/loongson-2k1000.dtsi | 25 ++++++--------- arch/loongarch/boot/dts/loongson-2k2000.dtsi | 32 ++++++++------------ 2 files changed, 21 insertions(+), 36 deletions(-) diff --git a/arch/loongarch/boot/dts/loongson-2k1000.dtsi b/arch/loongarch/boot/dts/loongson-2k1000.dtsi index d8e01e2534dde..0f8a24d81f7c6 100644 --- a/arch/loongarch/boot/dts/loongson-2k1000.dtsi +++ b/arch/loongarch/boot/dts/loongson-2k1000.dtsi @@ -437,54 +437,47 @@ gmac0: ethernet@3,0 { reg = <0x1800 0x0 0x0 0x0 0x0>; - interrupt-parent = <&liointc0>; - interrupts = <12 IRQ_TYPE_LEVEL_HIGH>, - <13 IRQ_TYPE_LEVEL_HIGH>; + interrupts-extended = <&liointc0 12 IRQ_TYPE_LEVEL_HIGH>, + <&liointc0 13 IRQ_TYPE_LEVEL_HIGH>; interrupt-names = "macirq", "eth_lpi"; status = "disabled"; }; gmac1: ethernet@3,1 { reg = <0x1900 0x0 0x0 0x0 0x0>; - interrupt-parent = <&liointc0>; - interrupts = <14 IRQ_TYPE_LEVEL_HIGH>, - <15 IRQ_TYPE_LEVEL_HIGH>; + interrupts-extended = <&liointc0 14 IRQ_TYPE_LEVEL_HIGH>, + <&liointc0 15 IRQ_TYPE_LEVEL_HIGH>; interrupt-names = "macirq", "eth_lpi"; status = "disabled"; }; ehci0: usb@4,1 { reg = <0x2100 0x0 0x0 0x0 0x0>; - interrupt-parent = <&liointc1>; - interrupts = <18 IRQ_TYPE_LEVEL_HIGH>; + interrupts-extended = <&liointc1 18 IRQ_TYPE_LEVEL_HIGH>; status = "disabled"; }; ohci0: usb@4,2 { reg = <0x2200 0x0 0x0 0x0 0x0>; - interrupt-parent = <&liointc1>; - interrupts = <19 IRQ_TYPE_LEVEL_HIGH>; + interrupts-extended = <&liointc1 19 IRQ_TYPE_LEVEL_HIGH>; status = "disabled"; }; display@6,0 { reg = <0x3000 0x0 0x0 0x0 0x0>; - interrupt-parent = <&liointc0>; - interrupts = <28 IRQ_TYPE_LEVEL_HIGH>; + interrupts-extended = <&liointc0 28 IRQ_TYPE_LEVEL_HIGH>; status = "disabled"; }; hda@7,0 { reg = <0x3800 0x0 0x0 0x0 0x0>; - interrupt-parent = <&liointc0>; - interrupts = <4 IRQ_TYPE_LEVEL_HIGH>; + interrupts-extended = <&liointc0 4 IRQ_TYPE_LEVEL_HIGH>; status = "disabled"; }; sata: sata@8,0 { reg = <0x4000 0x0 0x0 0x0 0x0>; - interrupt-parent = <&liointc0>; - interrupts = <19 IRQ_TYPE_LEVEL_HIGH>; + interrupts-extended = <&liointc0 19 IRQ_TYPE_LEVEL_HIGH>; status = "disabled"; }; diff --git a/arch/loongarch/boot/dts/loongson-2k2000.dtsi b/arch/loongarch/boot/dts/loongson-2k2000.dtsi index 00cc485b753b1..18b192d8c93ce 100644 --- a/arch/loongarch/boot/dts/loongson-2k2000.dtsi +++ b/arch/loongarch/boot/dts/loongson-2k2000.dtsi @@ -291,65 +291,57 @@ gmac0: ethernet@3,0 { reg = <0x1800 0x0 0x0 0x0 0x0>; - interrupts = <12 IRQ_TYPE_LEVEL_HIGH>, - <13 IRQ_TYPE_LEVEL_HIGH>; + interrupts-extended = <&pic 12 IRQ_TYPE_LEVEL_HIGH>, + <&pic 13 IRQ_TYPE_LEVEL_HIGH>; interrupt-names = "macirq", "eth_lpi"; - interrupt-parent = <&pic>; status = "disabled"; }; gmac1: ethernet@3,1 { reg = <0x1900 0x0 0x0 0x0 0x0>; - interrupts = <14 IRQ_TYPE_LEVEL_HIGH>, - <15 IRQ_TYPE_LEVEL_HIGH>; + interrupts-extended = <&pic 14 IRQ_TYPE_LEVEL_HIGH>, + <&pic 15 IRQ_TYPE_LEVEL_HIGH>; interrupt-names = "macirq", "eth_lpi"; - interrupt-parent = <&pic>; status = "disabled"; }; gmac2: ethernet@3,2 { reg = <0x1a00 0x0 0x0 0x0 0x0>; - interrupts = <17 IRQ_TYPE_LEVEL_HIGH>, - <18 IRQ_TYPE_LEVEL_HIGH>; + interrupts-extended = <&pic 17 IRQ_TYPE_LEVEL_HIGH>, + <&pic 18 IRQ_TYPE_LEVEL_HIGH>; interrupt-names = "macirq", "eth_lpi"; - interrupt-parent = <&pic>; status = "disabled"; }; xhci0: usb@4,0 { reg = <0x2000 0x0 0x0 0x0 0x0>; - interrupts = <48 IRQ_TYPE_LEVEL_HIGH>; - interrupt-parent = <&pic>; + interrupts-extended = <&pic 48 IRQ_TYPE_LEVEL_HIGH>; status = "disabled"; }; xhci1: usb@19,0 { reg = <0xc800 0x0 0x0 0x0 0x0>; - interrupts = <22 IRQ_TYPE_LEVEL_HIGH>; - interrupt-parent = <&pic>; + interrupts-extended = <&pic 22 IRQ_TYPE_LEVEL_HIGH>; status = "disabled"; }; display@6,1 { reg = <0x3100 0x0 0x0 0x0 0x0>; - interrupts = <28 IRQ_TYPE_LEVEL_HIGH>; - interrupt-parent = <&pic>; + interrupts-extended = <&pic 28 IRQ_TYPE_LEVEL_HIGH>; status = "disabled"; }; i2s@7,0 { reg = <0x3800 0x0 0x0 0x0 0x0>; - interrupts = <78 IRQ_TYPE_LEVEL_HIGH>, - <79 IRQ_TYPE_LEVEL_HIGH>; + interrupts-extended = <&pic 78 IRQ_TYPE_LEVEL_HIGH>, + <&pic 79 IRQ_TYPE_LEVEL_HIGH>; interrupt-names = "tx", "rx"; - interrupt-parent = <&pic>; status = "disabled"; }; sata: sata@8,0 { reg = <0x4000 0x0 0x0 0x0 0x0>; - interrupts = <16 IRQ_TYPE_LEVEL_HIGH>; - interrupt-parent = <&pic>; + interrupts-extended = <&pic 16 IRQ_TYPE_LEVEL_HIGH>; status = "disabled"; }; From 26ed15a42b743c5a326834c4ad2c989a9a59bdbd Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Mon, 15 Dec 2025 14:08:30 -0600 Subject: [PATCH 2107/2333] drm/amd/display: Bump the HDMI clock to 340MHz commit fee50077656d8a58011f13bca48f743d1b6d6015 upstream. [Why] DP-HDMI dongles can execeed bandwidth requirements on high resolution monitors. This can lead to pruning the high resolution modes. HDMI 1.3 bumped the clock to 340MHz, but display code never matched it. [How] Set default to (DVI) 165MHz. Once HDMI display is identified update to 340MHz. Reported-by: Dianne Skoll Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/4780 Reviewed-by: Chris Park Signed-off-by: Mario Limonciello Signed-off-by: Matthew Stewart Tested-by: Dan Wheeler Signed-off-by: Alex Deucher (cherry picked from commit ac1e65d8ade46c09fb184579b81acadf36dcb91e) Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/amd/display/dc/dc_hdmi_types.h | 2 +- drivers/gpu/drm/amd/display/dc/link/link_detection.c | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dc_hdmi_types.h b/drivers/gpu/drm/amd/display/dc/dc_hdmi_types.h index b015e80672ec9..fcd3ab4b00459 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_hdmi_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_hdmi_types.h @@ -41,7 +41,7 @@ /* kHZ*/ #define DP_ADAPTOR_DVI_MAX_TMDS_CLK 165000 /* kHZ*/ -#define DP_ADAPTOR_HDMI_SAFE_MAX_TMDS_CLK 165000 +#define DP_ADAPTOR_HDMI_SAFE_MAX_TMDS_CLK 340000 struct dp_hdmi_dongle_signature_data { int8_t id[15];/* "DP-HDMI ADAPTOR"*/ diff --git a/drivers/gpu/drm/amd/display/dc/link/link_detection.c b/drivers/gpu/drm/amd/display/dc/link/link_detection.c index 1173c53359b00..31b404e9b9ae0 100644 --- a/drivers/gpu/drm/amd/display/dc/link/link_detection.c +++ b/drivers/gpu/drm/amd/display/dc/link/link_detection.c @@ -332,7 +332,7 @@ static void query_dp_dual_mode_adaptor( /* Assume we have no valid DP passive dongle connected */ *dongle = DISPLAY_DONGLE_NONE; - sink_cap->max_hdmi_pixel_clock = DP_ADAPTOR_HDMI_SAFE_MAX_TMDS_CLK; + sink_cap->max_hdmi_pixel_clock = DP_ADAPTOR_DVI_MAX_TMDS_CLK; /* Read DP-HDMI dongle I2c (no response interpreted as DP-DVI dongle)*/ if (!i2c_read( @@ -388,6 +388,8 @@ static void query_dp_dual_mode_adaptor( } } + if (is_valid_hdmi_signature) + sink_cap->max_hdmi_pixel_clock = DP_ADAPTOR_HDMI_SAFE_MAX_TMDS_CLK; if (is_type2_dongle) { uint32_t max_tmds_clk = From 568c29c7c7c830097ffc0b03a68af022380a54e5 Mon Sep 17 00:00:00 2001 From: Vivek Das Mohapatra Date: Mon, 12 Jan 2026 15:28:56 +0000 Subject: [PATCH 2108/2333] drm/amd/display: Initialise backlight level values from hw commit 52d3d115e9cc975b90b1fc49abf6d36ad5e8847a upstream. Internal backlight levels are initialised from ACPI but the values are sometimes out of sync with the levels in effect until there has been a read from hardware (eg triggered by reading from sysfs). This means that the first drm_commit can cause the levels to be set to a different value than the actual starting one, which results in a sudden change in brightness. This path shows the problem (when the values are out of sync): amdgpu_dm_atomic_commit_tail() -> amdgpu_dm_commit_streams() -> amdgpu_dm_backlight_set_level(..., dm->brightness[n]) This patch calls the backlight ops get_brightness explicitly at the end of backlight registration to make sure dm->brightness[n] is in sync with the actual hardware levels. Fixes: 2fe87f54abdc ("drm/amd/display: Set default brightness according to ACPI") Signed-off-by: Vivek Das Mohapatra Reviewed-by: Mario Limonciello (AMD) Signed-off-by: Alex Deucher (cherry picked from commit 318b1c36d82a0cd2b06a4bb43272fa6f1bc8adc1) Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) 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 f4381d44864f1..6252afd1d087f 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -5193,6 +5193,8 @@ amdgpu_dm_register_backlight_device(struct amdgpu_dm_connector *aconnector) struct amdgpu_dm_backlight_caps *caps; char bl_name[16]; int min, max; + int real_brightness; + int init_brightness; if (aconnector->bl_idx == -1) return; @@ -5217,6 +5219,8 @@ amdgpu_dm_register_backlight_device(struct amdgpu_dm_connector *aconnector) } else props.brightness = props.max_brightness = MAX_BACKLIGHT_LEVEL; + init_brightness = props.brightness; + if (caps->data_points && !(amdgpu_dc_debug_mask & DC_DISABLE_CUSTOM_BRIGHTNESS_CURVE)) { drm_info(drm, "Using custom brightness curve\n"); props.scale = BACKLIGHT_SCALE_NON_LINEAR; @@ -5235,8 +5239,20 @@ amdgpu_dm_register_backlight_device(struct amdgpu_dm_connector *aconnector) if (IS_ERR(dm->backlight_dev[aconnector->bl_idx])) { drm_err(drm, "DM: Backlight registration failed!\n"); dm->backlight_dev[aconnector->bl_idx] = NULL; - } else + } else { + /* + * dm->brightness[x] can be inconsistent just after startup until + * ops.get_brightness is called. + */ + real_brightness = + amdgpu_dm_backlight_ops.get_brightness(dm->backlight_dev[aconnector->bl_idx]); + + if (real_brightness != init_brightness) { + dm->actual_brightness[aconnector->bl_idx] = real_brightness; + dm->brightness[aconnector->bl_idx] = real_brightness; + } drm_dbg_driver(drm, "DM: Registered Backlight device: %s\n", bl_name); + } } static int initialize_plane(struct amdgpu_display_manager *dm, From b705daaf5f8c4ebcd5f963a1c98b159b5a1b103f Mon Sep 17 00:00:00 2001 From: "Mario Limonciello (AMD)" Date: Wed, 7 Jan 2026 15:37:28 -0600 Subject: [PATCH 2109/2333] drm/amd: Clean up kfd node on surprise disconnect commit 28695ca09d326461f8078332aa01db516983e8a2 upstream. When an eGPU is unplugged the KFD topology should also be destroyed for that GPU. This never happens because the fini_sw callbacks never get to run. Run them manually before calling amdgpu_device_ip_fini_early() when a device has already been disconnected. This location is intentionally chosen to make sure that the kfd locking refcount doesn't get incremented unintentionally. Cc: kent.russell@amd.com Closes: https://community.frame.work/t/amd-egpu-on-linux/8691/33 Signed-off-by: Mario Limonciello (AMD) Reviewed-by: Kent Russell Signed-off-by: Alex Deucher (cherry picked from commit 6a23e7b4332c10f8b56c33a9c5431b52ecff9aab) Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index 0cba31ec025c0..49107475af619 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -4985,6 +4985,14 @@ void amdgpu_device_fini_hw(struct amdgpu_device *adev) amdgpu_ttm_set_buffer_funcs_status(adev, false); + /* + * device went through surprise hotplug; we need to destroy topology + * before ip_fini_early to prevent kfd locking refcount issues by calling + * amdgpu_amdkfd_suspend() + */ + if (drm_dev_is_unplugged(adev_to_drm(adev))) + amdgpu_amdkfd_device_fini_sw(adev); + amdgpu_device_ip_fini_early(adev); amdgpu_irq_fini_hw(adev); From 531b1b83cfa0b8edefad8080d053f7f26877e988 Mon Sep 17 00:00:00 2001 From: Philip Yang Date: Thu, 4 Dec 2025 12:13:05 -0500 Subject: [PATCH 2110/2333] drm/amdgpu: Fix gfx9 update PTE mtype flag MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 292e5757b2229c0c6f1d059123a85f8a28f4464d upstream. Fix copy&paste error, that should have been an assignment instead of an or, otherwise MTYPE_UC 0x3 can not be updated to MTYPE_RW 0x1. Signed-off-by: Philip Yang Reviewed-by: Christian König Signed-off-by: Alex Deucher (cherry picked from commit fc1366016abe4103c0f0fac882811aea961ef213) Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c index 0d1dd587db5f4..fd9485e9dd193 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c @@ -1233,16 +1233,16 @@ static void gmc_v9_0_get_vm_pte(struct amdgpu_device *adev, *flags = AMDGPU_PTE_MTYPE_VG10(*flags, MTYPE_NC); break; case AMDGPU_VM_MTYPE_WC: - *flags |= AMDGPU_PTE_MTYPE_VG10(*flags, MTYPE_WC); + *flags = AMDGPU_PTE_MTYPE_VG10(*flags, MTYPE_WC); break; case AMDGPU_VM_MTYPE_RW: - *flags |= AMDGPU_PTE_MTYPE_VG10(*flags, MTYPE_RW); + *flags = AMDGPU_PTE_MTYPE_VG10(*flags, MTYPE_RW); break; case AMDGPU_VM_MTYPE_CC: - *flags |= AMDGPU_PTE_MTYPE_VG10(*flags, MTYPE_CC); + *flags = AMDGPU_PTE_MTYPE_VG10(*flags, MTYPE_CC); break; case AMDGPU_VM_MTYPE_UC: - *flags |= AMDGPU_PTE_MTYPE_VG10(*flags, MTYPE_UC); + *flags = AMDGPU_PTE_MTYPE_VG10(*flags, MTYPE_UC); break; } From 0080a3f3fd917327c36f9a4f2660b693004c21fc Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 9 Jan 2026 08:54:55 -0500 Subject: [PATCH 2111/2333] drm/amdgpu: make sure userqs are enabled in userq IOCTLs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit b6dff005fcf32dd072f6f2d08ca461394a21bd4f upstream. These IOCTLs shouldn't be called when userqs are not enabled. Make sure they are enabled before executing the IOCTLs. Reviewed-by: Christian König Signed-off-by: Alex Deucher (cherry picked from commit d967509651601cddce7ff2a9f09479f3636f684d) Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c | 16 ++++++++++++++++ drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h | 1 + drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c | 6 ++++++ 3 files changed, 23 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c index 79c7fa0a9ff7b..8c41951feb437 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c @@ -681,12 +681,28 @@ static int amdgpu_userq_input_args_validate(struct drm_device *dev, return 0; } +bool amdgpu_userq_enabled(struct drm_device *dev) +{ + struct amdgpu_device *adev = drm_to_adev(dev); + int i; + + for (i = 0; i < AMDGPU_HW_IP_NUM; i++) { + if (adev->userq_funcs[i]) + return true; + } + + return false; +} + int amdgpu_userq_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) { union drm_amdgpu_userq *args = data; int r; + if (!amdgpu_userq_enabled(dev)) + return -ENOTSUPP; + if (amdgpu_userq_input_args_validate(dev, args, filp) < 0) return -EINVAL; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h index dbc13a807ca82..d78532f9d507b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h @@ -135,6 +135,7 @@ uint64_t amdgpu_userq_get_doorbell_index(struct amdgpu_userq_mgr *uq_mgr, struct drm_file *filp); u32 amdgpu_userq_get_supported_ip_mask(struct amdgpu_device *adev); +bool amdgpu_userq_enabled(struct drm_device *dev); int amdgpu_userq_suspend(struct amdgpu_device *adev); int amdgpu_userq_resume(struct amdgpu_device *adev); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c index 53fe10931fab0..5c181ac75d548 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c @@ -472,6 +472,9 @@ int amdgpu_userq_signal_ioctl(struct drm_device *dev, void *data, struct drm_exec exec; u64 wptr; + if (!amdgpu_userq_enabled(dev)) + return -ENOTSUPP; + num_syncobj_handles = args->num_syncobj_handles; syncobj_handles = memdup_user(u64_to_user_ptr(args->syncobj_handles), size_mul(sizeof(u32), num_syncobj_handles)); @@ -654,6 +657,9 @@ int amdgpu_userq_wait_ioctl(struct drm_device *dev, void *data, int r, i, rentry, wentry, cnt; struct drm_exec exec; + if (!amdgpu_userq_enabled(dev)) + return -ENOTSUPP; + num_read_bo_handles = wait_info->num_bo_read_handles; bo_handles_read = memdup_user(u64_to_user_ptr(wait_info->bo_read_handles), size_mul(sizeof(u32), num_read_bo_handles)); From a92ef24071f395accb28a5cc7bf1223d38c50371 Mon Sep 17 00:00:00 2001 From: Haoxiang Li Date: Thu, 8 Jan 2026 15:18:22 +0800 Subject: [PATCH 2112/2333] drm/amdkfd: fix a memory leak in device_queue_manager_init() commit 80614c509810fc051312d1a7ccac8d0012d6b8d0 upstream. If dqm->ops.initialize() fails, add deallocate_hiq_sdma_mqd() to release the memory allocated by allocate_hiq_sdma_mqd(). Move deallocate_hiq_sdma_mqd() up to ensure proper function visibility at the point of use. Fixes: 11614c36bc8f ("drm/amdkfd: Allocate MQD trunk for HIQ and SDMA") Signed-off-by: Haoxiang Li Signed-off-by: Felix Kuehling Reviewed-by: Oak Zeng Reviewed-by: Felix Kuehling Signed-off-by: Alex Deucher (cherry picked from commit b7cccc8286bb9919a0952c812872da1dcfe9d390) Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- .../drm/amd/amdkfd/kfd_device_queue_manager.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c index 36fb3db16572a..58c5acf50a220 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c @@ -2905,6 +2905,14 @@ static int allocate_hiq_sdma_mqd(struct device_queue_manager *dqm) return retval; } +static void deallocate_hiq_sdma_mqd(struct kfd_node *dev, + struct kfd_mem_obj *mqd) +{ + WARN(!mqd, "No hiq sdma mqd trunk to free"); + + amdgpu_amdkfd_free_gtt_mem(dev->adev, &mqd->gtt_mem); +} + struct device_queue_manager *device_queue_manager_init(struct kfd_node *dev) { struct device_queue_manager *dqm; @@ -3028,19 +3036,14 @@ struct device_queue_manager *device_queue_manager_init(struct kfd_node *dev) return dqm; } + if (!dev->kfd->shared_resources.enable_mes) + deallocate_hiq_sdma_mqd(dev, &dqm->hiq_sdma_mqd); + out_free: kfree(dqm); return NULL; } -static void deallocate_hiq_sdma_mqd(struct kfd_node *dev, - struct kfd_mem_obj *mqd) -{ - WARN(!mqd, "No hiq sdma mqd trunk to free"); - - amdgpu_amdkfd_free_gtt_mem(dev->adev, &mqd->gtt_mem); -} - void device_queue_manager_uninit(struct device_queue_manager *dqm) { dqm->ops.stop(dqm); From d4373630fd3314b1d06c4f793504e3c8ba35dba6 Mon Sep 17 00:00:00 2001 From: Lyude Paul Date: Fri, 19 Dec 2025 16:52:02 -0500 Subject: [PATCH 2113/2333] drm/nouveau/disp/nv50-: Set lock_core in curs507a_prepare commit 9e9bc6be0fa0b6b6b73f4f831f3b77716d0a8d9e upstream. For a while, I've been seeing a strange issue where some (usually not all) of the display DMA channels will suddenly hang, particularly when there is a visible cursor on the screen that is being frequently updated, and especially when said cursor happens to go between two screens. While this brings back lovely memories of fixing Intel Skylake bugs, I would quite like to fix it :). It turns out the problem that's happening here is that we're managing to reach nv50_head_flush_set() in our atomic commit path without actually holding nv50_disp->mutex. This means that cursor updates happening in parallel (along with any other atomic updates that need to use the core channel) will race with eachother, which eventually causes us to corrupt the pushbuffer - leading to a plethora of various GSP errors, usually: nouveau 0000:c1:00.0: gsp: Xid:56 CMDre 00000000 00000218 00102680 00000004 00800003 nouveau 0000:c1:00.0: gsp: Xid:56 CMDre 00000000 0000021c 00040509 00000004 00000001 nouveau 0000:c1:00.0: gsp: Xid:56 CMDre 00000000 00000000 00000000 00000001 00000001 The reason this is happening is because generally we check whether we need to set nv50_atom->lock_core at the end of nv50_head_atomic_check(). However, curs507a_prepare is called from the fb_prepare callback, which happens after the atomic check phase. As a result, this can lead to commits that both touch the core channel but also don't grab nv50_disp->mutex. So, fix this by making sure that we set nv50_atom->lock_core in cus507a_prepare(). Reviewed-by: Dave Airlie Signed-off-by: Lyude Paul Fixes: 1590700d94ac ("drm/nouveau/kms/nv50-: split each resource type into their own source files") Cc: # v4.18+ Link: https://patch.msgid.link/20251219215344.170852-2-lyude@redhat.com Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/nouveau/dispnv50/curs507a.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/nouveau/dispnv50/curs507a.c b/drivers/gpu/drm/nouveau/dispnv50/curs507a.c index a95ee5dcc2e39..1a889139cb053 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/curs507a.c +++ b/drivers/gpu/drm/nouveau/dispnv50/curs507a.c @@ -84,6 +84,7 @@ curs507a_prepare(struct nv50_wndw *wndw, struct nv50_head_atom *asyh, asyh->curs.handle = handle; asyh->curs.offset = offset; asyh->set.curs = asyh->curs.visible; + nv50_atom(asyh->state.state)->lock_core = true; } } From f7940d3ec1dc6bf719eddc69d4b8e52cc2201896 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sat, 10 Jan 2026 16:27:28 +0100 Subject: [PATCH 2114/2333] drm/panel-simple: fix connector type for DataImage SCF0700C48GGU18 panel commit 6ab3d4353bf75005eaa375677c9fed31148154d6 upstream. The connector type for the DataImage SCF0700C48GGU18 panel is missing and devm_drm_panel_bridge_add() requires connector type to be set. This leads to a warning and a backtrace in the kernel log and panel does not work: " WARNING: CPU: 3 PID: 38 at drivers/gpu/drm/bridge/panel.c:379 devm_drm_of_get_bridge+0xac/0xb8 " The warning is triggered by a check for valid connector type in devm_drm_panel_bridge_add(). If there is no valid connector type set for a panel, the warning is printed and panel is not added. Fill in the missing connector type to fix the warning and make the panel operational once again. Cc: stable@vger.kernel.org Fixes: 97ceb1fb08b6 ("drm/panel: simple: Add support for DataImage SCF0700C48GGU18") Signed-off-by: Marek Vasut Reviewed-by: Neil Armstrong Signed-off-by: Neil Armstrong Link: https://patch.msgid.link/20260110152750.73848-1-marex@nabladev.com Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/panel/panel-simple.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index 0019de93be1b6..a0010c31d882d 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -1900,6 +1900,7 @@ static const struct panel_desc dataimage_scf0700c48ggu18 = { }, .bus_format = MEDIA_BUS_FMT_RGB888_1X24, .bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE, + .connector_type = DRM_MODE_CONNECTOR_DPI, }; static const struct display_timing dlc_dlc0700yzg_1_timing = { From 9c676c7a054bcc7764357024eb8a83d7695d799d Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Thu, 18 Dec 2025 14:34:43 +0100 Subject: [PATCH 2115/2333] drm/panel: simple: restore connector_type fallback commit 9380dc33cd6ae4a6857818fcefce31cf716f3fae upstream. The switch from devm_kzalloc() + drm_panel_init() to devm_drm_panel_alloc() introduced a regression. Several panel descriptors do not set connector_type. For those panels, panel_simple_probe() used to compute a connector type (currently DPI as a fallback) and pass that value to drm_panel_init(). After the conversion to devm_drm_panel_alloc(), the call unconditionally used desc->connector_type instead, ignoring the computed fallback and potentially passing DRM_MODE_CONNECTOR_Unknown, which drm_panel_bridge_add() does not allow. Move the connector_type validation / fallback logic before the devm_drm_panel_alloc() call and pass the computed connector_type to devm_drm_panel_alloc(), so panels without an explicit connector_type once again get the DPI default. Signed-off-by: Ludovic Desroches Fixes: de04bb0089a9 ("drm/panel/panel-simple: Use the new allocation in place of devm_kzalloc()") Cc: stable@vger.kernel.org Reviewed-by: Luca Ceresoli Link: https://lore.kernel.org/stable/20251126-lcd_panel_connector_type_fix-v2-1-c15835d1f7cb%40microchip.com Signed-off-by: Neil Armstrong Link: https://patch.msgid.link/20251218-lcd_panel_connector_type_fix-v3-1-ddcea6d8d7ef@microchip.com Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/panel/panel-simple.c | 89 ++++++++++++++-------------- 1 file changed, 44 insertions(+), 45 deletions(-) diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index a0010c31d882d..271f933991937 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -623,49 +623,6 @@ static struct panel_simple *panel_simple_probe(struct device *dev) if (IS_ERR(desc)) return ERR_CAST(desc); - panel = devm_drm_panel_alloc(dev, struct panel_simple, base, - &panel_simple_funcs, desc->connector_type); - if (IS_ERR(panel)) - return ERR_CAST(panel); - - panel->desc = desc; - - panel->supply = devm_regulator_get(dev, "power"); - if (IS_ERR(panel->supply)) - return ERR_CAST(panel->supply); - - panel->enable_gpio = devm_gpiod_get_optional(dev, "enable", - GPIOD_OUT_LOW); - if (IS_ERR(panel->enable_gpio)) - return dev_err_cast_probe(dev, panel->enable_gpio, - "failed to request GPIO\n"); - - err = of_drm_get_panel_orientation(dev->of_node, &panel->orientation); - if (err) { - dev_err(dev, "%pOF: failed to get orientation %d\n", dev->of_node, err); - return ERR_PTR(err); - } - - ddc = of_parse_phandle(dev->of_node, "ddc-i2c-bus", 0); - if (ddc) { - panel->ddc = of_find_i2c_adapter_by_node(ddc); - of_node_put(ddc); - - if (!panel->ddc) - return ERR_PTR(-EPROBE_DEFER); - } - - if (!of_device_is_compatible(dev->of_node, "panel-dpi") && - !of_get_display_timing(dev->of_node, "panel-timing", &dt)) - panel_simple_parse_panel_timing_node(dev, panel, &dt); - - if (desc->connector_type == DRM_MODE_CONNECTOR_LVDS) { - /* Optional data-mapping property for overriding bus format */ - err = panel_simple_override_nondefault_lvds_datamapping(dev, panel); - if (err) - goto free_ddc; - } - connector_type = desc->connector_type; /* Catch common mistakes for panels. */ switch (connector_type) { @@ -690,8 +647,7 @@ static struct panel_simple *panel_simple_probe(struct device *dev) break; case DRM_MODE_CONNECTOR_eDP: dev_warn(dev, "eDP panels moved to panel-edp\n"); - err = -EINVAL; - goto free_ddc; + return ERR_PTR(-EINVAL); case DRM_MODE_CONNECTOR_DSI: if (desc->bpc != 6 && desc->bpc != 8) dev_warn(dev, "Expected bpc in {6,8} but got: %u\n", desc->bpc); @@ -720,6 +676,49 @@ static struct panel_simple *panel_simple_probe(struct device *dev) break; } + panel = devm_drm_panel_alloc(dev, struct panel_simple, base, + &panel_simple_funcs, connector_type); + if (IS_ERR(panel)) + return ERR_CAST(panel); + + panel->desc = desc; + + panel->supply = devm_regulator_get(dev, "power"); + if (IS_ERR(panel->supply)) + return ERR_CAST(panel->supply); + + panel->enable_gpio = devm_gpiod_get_optional(dev, "enable", + GPIOD_OUT_LOW); + if (IS_ERR(panel->enable_gpio)) + return dev_err_cast_probe(dev, panel->enable_gpio, + "failed to request GPIO\n"); + + err = of_drm_get_panel_orientation(dev->of_node, &panel->orientation); + if (err) { + dev_err(dev, "%pOF: failed to get orientation %d\n", dev->of_node, err); + return ERR_PTR(err); + } + + ddc = of_parse_phandle(dev->of_node, "ddc-i2c-bus", 0); + if (ddc) { + panel->ddc = of_find_i2c_adapter_by_node(ddc); + of_node_put(ddc); + + if (!panel->ddc) + return ERR_PTR(-EPROBE_DEFER); + } + + if (!of_device_is_compatible(dev->of_node, "panel-dpi") && + !of_get_display_timing(dev->of_node, "panel-timing", &dt)) + panel_simple_parse_panel_timing_node(dev, panel, &dt); + + if (desc->connector_type == DRM_MODE_CONNECTOR_LVDS) { + /* Optional data-mapping property for overriding bus format */ + err = panel_simple_override_nondefault_lvds_datamapping(dev, panel); + if (err) + goto free_ddc; + } + dev_set_drvdata(dev, panel); /* From cf60e6b1bf0c3e0e76f86fc10f9820f2f4c03532 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Thu, 8 Jan 2026 15:19:46 +0100 Subject: [PATCH 2116/2333] drm/sysfb: Remove duplicate declarations commit b91a565ed14fcf900b4d95e86882b4b763860986 upstream. Commit 6046b49bafff ("drm/sysfb: Share helpers for integer validation") and commit e8c086880b2b ("drm/sysfb: Share helpers for screen_info validation") added duplicate function declarations. Remove the latter ones. Signed-off-by: Thomas Zimmermann Fixes: e8c086880b2b ("drm/sysfb: Share helpers for screen_info validation") Cc: Thomas Zimmermann Cc: Javier Martinez Canillas Cc: dri-devel@lists.freedesktop.org Cc: # v6.16+ Reviewed-by: Javier Martinez Canillas Link: https://patch.msgid.link/20260108145058.56943-7-tzimmermann@suse.de Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/sysfb/drm_sysfb_helper.h | 9 --------- 1 file changed, 9 deletions(-) diff --git a/drivers/gpu/drm/sysfb/drm_sysfb_helper.h b/drivers/gpu/drm/sysfb/drm_sysfb_helper.h index 89633e30ca625..265a1b8a93493 100644 --- a/drivers/gpu/drm/sysfb/drm_sysfb_helper.h +++ b/drivers/gpu/drm/sysfb/drm_sysfb_helper.h @@ -47,15 +47,6 @@ const struct drm_format_info *drm_sysfb_get_format_si(struct drm_device *dev, const struct screen_info *si); #endif -/* - * Input parsing - */ - -int drm_sysfb_get_validated_int(struct drm_device *dev, const char *name, - u64 value, u32 max); -int drm_sysfb_get_validated_int0(struct drm_device *dev, const char *name, - u64 value, u32 max); - /* * Display modes */ From 621fcd0aec180fea86f46be22d500cc3fbad46df Mon Sep 17 00:00:00 2001 From: Haoxiang Li Date: Wed, 24 Dec 2025 17:11:05 +0800 Subject: [PATCH 2117/2333] drm/vmwgfx: Fix an error return check in vmw_compat_shader_add() commit bf72b4b7bb7dbb643d204fa41e7463894a95999f upstream. In vmw_compat_shader_add(), the return value check of vmw_shader_alloc() is not proper. Modify the check for the return pointer 'res'. Found by code review and compiled on ubuntu 20.04. Fixes: 18e4a4669c50 ("drm/vmwgfx: Fix compat shader namespace") Cc: stable@vger.kernel.org Signed-off-by: Haoxiang Li Signed-off-by: Zack Rusin Link: https://patch.msgid.link/20251224091105.1569464-1-lihaoxiang@isrc.iscas.ac.cn Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/vmwgfx/vmwgfx_shader.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c b/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c index 69dfe69ce0f87..a8c8c9375d297 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c @@ -923,8 +923,10 @@ int vmw_compat_shader_add(struct vmw_private *dev_priv, ttm_bo_unreserve(&buf->tbo); res = vmw_shader_alloc(dev_priv, buf, size, 0, shader_type); - if (unlikely(ret != 0)) + if (IS_ERR(res)) { + ret = PTR_ERR(res); goto no_reserve; + } ret = vmw_cmdbuf_res_add(man, vmw_cmdbuf_res_shader, vmw_shader_key(user_key, shader_type), From aa866e4a130801056d8495d2851aa9b9b7331a68 Mon Sep 17 00:00:00 2001 From: Binbin Zhou Date: Sat, 17 Jan 2026 10:56:52 +0800 Subject: [PATCH 2118/2333] LoongArch: dts: loongson-2k0500: Add default interrupt controller address cells commit c4461754e6fe7e12a3ff198cce4707e3e20e43d4 upstream. Add missing address-cells 0 to the Local I/O and Extend I/O interrupt controller node to silence W=1 warning: loongson-2k0500.dtsi:513.5-51: Warning (interrupt_map): /bus@10000000/pcie@1a000000/pcie@0,0:interrupt-map: Missing property '#address-cells' in node /bus@10000000/interrupt-controller@1fe11600, using 0 as fallback Value '0' is correct because: 1. The Local I/O & Extend I/O interrupt controller do not have children, 2. interrupt-map property (in PCI node) consists of five components and the fourth component "parent unit address", which size is defined by '#address-cells' of the node pointed to by the interrupt-parent component, is not used (=0) Cc: stable@vger.kernel.org Signed-off-by: Binbin Zhou Signed-off-by: Huacai Chen Signed-off-by: Greg Kroah-Hartman --- arch/loongarch/boot/dts/loongson-2k0500.dtsi | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/loongarch/boot/dts/loongson-2k0500.dtsi b/arch/loongarch/boot/dts/loongson-2k0500.dtsi index 588ebc3bded40..51d990890803c 100644 --- a/arch/loongarch/boot/dts/loongson-2k0500.dtsi +++ b/arch/loongarch/boot/dts/loongson-2k0500.dtsi @@ -131,6 +131,7 @@ reg-names = "main", "isr0"; interrupt-controller; + #address-cells = <0>; #interrupt-cells = <2>; interrupt-parent = <&cpuintc>; interrupts = <2>; @@ -149,6 +150,7 @@ reg-names = "main", "isr0"; interrupt-controller; + #address-cells = <0>; #interrupt-cells = <2>; interrupt-parent = <&cpuintc>; interrupts = <4>; @@ -164,6 +166,7 @@ compatible = "loongson,ls2k0500-eiointc"; reg = <0x0 0x1fe11600 0x0 0xea00>; interrupt-controller; + #address-cells = <0>; #interrupt-cells = <1>; interrupt-parent = <&cpuintc>; interrupts = <3>; From dea25e8f6b7448c2db05d9e476688d6c94b60467 Mon Sep 17 00:00:00 2001 From: Binbin Zhou Date: Sat, 17 Jan 2026 10:56:53 +0800 Subject: [PATCH 2119/2333] LoongArch: dts: loongson-2k1000: Add default interrupt controller address cells commit 81e8cb7e504a5adbcc48f7f954bf3c2aa9b417f8 upstream. Add missing address-cells 0 to the Local I/O interrupt controller node to silence W=1 warning: loongson-2k1000.dtsi:498.5-55: Warning (interrupt_map): /bus@10000000/pcie@1a000000/pcie@9,0:interrupt-map: Missing property '#address-cells' in node /bus@10000000/interrupt-controller@1fe01440, using 0 as fallback Value '0' is correct because: 1. The Local I/O interrupt controller does not have children, 2. interrupt-map property (in PCI node) consists of five components and the fourth component "parent unit address", which size is defined by '#address-cells' of the node pointed to by the interrupt-parent component, is not used (=0) Cc: stable@vger.kernel.org Signed-off-by: Binbin Zhou Signed-off-by: Huacai Chen Signed-off-by: Greg Kroah-Hartman --- arch/loongarch/boot/dts/loongson-2k1000.dtsi | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/loongarch/boot/dts/loongson-2k1000.dtsi b/arch/loongarch/boot/dts/loongson-2k1000.dtsi index 0f8a24d81f7c6..a6d5acb5c1a2d 100644 --- a/arch/loongarch/boot/dts/loongson-2k1000.dtsi +++ b/arch/loongarch/boot/dts/loongson-2k1000.dtsi @@ -114,6 +114,7 @@ <0x0 0x1fe01140 0x0 0x8>; reg-names = "main", "isr0", "isr1"; interrupt-controller; + #address-cells = <0>; #interrupt-cells = <2>; interrupt-parent = <&cpuintc>; interrupts = <2>; @@ -131,6 +132,7 @@ <0x0 0x1fe01148 0x0 0x8>; reg-names = "main", "isr0", "isr1"; interrupt-controller; + #address-cells = <0>; #interrupt-cells = <2>; interrupt-parent = <&cpuintc>; interrupts = <3>; From 8a692ca14f4ca6b6f99fabe9bb186052697a9655 Mon Sep 17 00:00:00 2001 From: Binbin Zhou Date: Sat, 17 Jan 2026 10:56:53 +0800 Subject: [PATCH 2120/2333] LoongArch: dts: loongson-2k1000: Fix i2c-gpio node names commit 14ea5a3625881d79f75418c66e3a7d98db8518e1 upstream. The binding wants the node to be named "i2c-number", but those are named "i2c-gpio-number" instead. Thus rename those to i2c-0, i2c-1 to adhere to the binding and suppress dtbs_check warnings. Cc: stable@vger.kernel.org Reviewed-by: Krzysztof Kozlowski Signed-off-by: Binbin Zhou Signed-off-by: Huacai Chen Signed-off-by: Greg Kroah-Hartman --- arch/loongarch/boot/dts/loongson-2k1000.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/loongarch/boot/dts/loongson-2k1000.dtsi b/arch/loongarch/boot/dts/loongson-2k1000.dtsi index a6d5acb5c1a2d..830815a5da863 100644 --- a/arch/loongarch/boot/dts/loongson-2k1000.dtsi +++ b/arch/loongarch/boot/dts/loongson-2k1000.dtsi @@ -46,7 +46,7 @@ }; /* i2c of the dvi eeprom edid */ - i2c-gpio-0 { + i2c-0 { compatible = "i2c-gpio"; scl-gpios = <&gpio0 0 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; sda-gpios = <&gpio0 1 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; @@ -57,7 +57,7 @@ }; /* i2c of the eeprom edid */ - i2c-gpio-1 { + i2c-1 { compatible = "i2c-gpio"; scl-gpios = <&gpio0 33 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; sda-gpios = <&gpio0 32 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; From a227c3c98f092595a90eda7a71f485e09446b106 Mon Sep 17 00:00:00 2001 From: Binbin Zhou Date: Sat, 17 Jan 2026 10:56:53 +0800 Subject: [PATCH 2121/2333] LoongArch: dts: loongson-2k2000: Add default interrupt controller address cells commit e65df3f77ecd59d3a8647d19df82b22a6ce210a9 upstream. Add missing address-cells 0 to the Local I/O, Extend I/O and PCH-PIC Interrupt Controller node to silence W=1 warning: loongson-2k2000.dtsi:364.5-49: Warning (interrupt_map): /bus@10000000/pcie@1a000000/pcie@9,0:interrupt-map: Missing property '#address-cells' in node /bus@10000000/interrupt-controller@10000000, using 0 as fallback Value '0' is correct because: 1. The LIO/EIO/PCH interrupt controller does not have children, 2. interrupt-map property (in PCI node) consists of five components and the fourth component "parent unit address", which size is defined by '#address-cells' of the node pointed to by the interrupt-parent component, is not used (=0) Cc: stable@vger.kernel.org Signed-off-by: Binbin Zhou Signed-off-by: Huacai Chen Signed-off-by: Greg Kroah-Hartman --- arch/loongarch/boot/dts/loongson-2k2000.dtsi | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/loongarch/boot/dts/loongson-2k2000.dtsi b/arch/loongarch/boot/dts/loongson-2k2000.dtsi index 18b192d8c93ce..ff094e60af1c9 100644 --- a/arch/loongarch/boot/dts/loongson-2k2000.dtsi +++ b/arch/loongarch/boot/dts/loongson-2k2000.dtsi @@ -126,6 +126,7 @@ reg = <0x0 0x1fe01400 0x0 0x64>; interrupt-controller; + #address-cells = <0>; #interrupt-cells = <2>; interrupt-parent = <&cpuintc>; interrupts = <2>; @@ -140,6 +141,7 @@ compatible = "loongson,ls2k2000-eiointc"; reg = <0x0 0x1fe01600 0x0 0xea00>; interrupt-controller; + #address-cells = <0>; #interrupt-cells = <1>; interrupt-parent = <&cpuintc>; interrupts = <3>; @@ -149,6 +151,7 @@ compatible = "loongson,pch-pic-1.0"; reg = <0x0 0x10000000 0x0 0x400>; interrupt-controller; + #address-cells = <0>; #interrupt-cells = <2>; loongson,pic-base-vec = <0>; interrupt-parent = <&eiointc>; From e94ec9661c5820d157d2cc4b6cf4a6ab656a7b4d Mon Sep 17 00:00:00 2001 From: Qiang Ma Date: Sat, 17 Jan 2026 10:57:02 +0800 Subject: [PATCH 2122/2333] LoongArch: KVM: Fix kvm_device leak in kvm_eiointc_destroy() commit 7d8553fc75aefa7ec936af0cf8443ff90b51732e upstream. In kvm_ioctl_create_device(), kvm_device has allocated memory, kvm_device->destroy() seems to be supposed to free its kvm_device struct, but kvm_eiointc_destroy() is not currently doing this, that would lead to a memory leak. So, fix it. Cc: stable@vger.kernel.org Reviewed-by: Bibo Mao Signed-off-by: Qiang Ma Signed-off-by: Huacai Chen Signed-off-by: Greg Kroah-Hartman --- arch/loongarch/kvm/intc/eiointc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/loongarch/kvm/intc/eiointc.c b/arch/loongarch/kvm/intc/eiointc.c index a1cc116b4dace..945ce4ed7e0b7 100644 --- a/arch/loongarch/kvm/intc/eiointc.c +++ b/arch/loongarch/kvm/intc/eiointc.c @@ -679,6 +679,7 @@ static void kvm_eiointc_destroy(struct kvm_device *dev) kvm_io_bus_unregister_dev(kvm, KVM_IOCSR_BUS, &eiointc->device); kvm_io_bus_unregister_dev(kvm, KVM_IOCSR_BUS, &eiointc->device_vext); kfree(eiointc); + kfree(dev); } static struct kvm_device_ops kvm_eiointc_dev_ops = { From 5defcc2f9c22e6e09b5be68234ad10f4ba0292b7 Mon Sep 17 00:00:00 2001 From: Qiang Ma Date: Sat, 17 Jan 2026 10:57:02 +0800 Subject: [PATCH 2123/2333] LoongArch: KVM: Fix kvm_device leak in kvm_ipi_destroy() commit 0bf58cb7288a4d3de6d8ecbb3a65928a9362bf21 upstream. In kvm_ioctl_create_device(), kvm_device has allocated memory, kvm_device->destroy() seems to be supposed to free its kvm_device struct, but kvm_ipi_destroy() is not currently doing this, that would lead to a memory leak. So, fix it. Cc: stable@vger.kernel.org Reviewed-by: Bibo Mao Signed-off-by: Qiang Ma Signed-off-by: Huacai Chen Signed-off-by: Greg Kroah-Hartman --- arch/loongarch/kvm/intc/ipi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/loongarch/kvm/intc/ipi.c b/arch/loongarch/kvm/intc/ipi.c index 05cefd29282e8..1058c13dba7f4 100644 --- a/arch/loongarch/kvm/intc/ipi.c +++ b/arch/loongarch/kvm/intc/ipi.c @@ -459,6 +459,7 @@ static void kvm_ipi_destroy(struct kvm_device *dev) ipi = kvm->arch.ipi; kvm_io_bus_unregister_dev(kvm, KVM_IOCSR_BUS, &ipi->device); kfree(ipi); + kfree(dev); } static struct kvm_device_ops kvm_ipi_dev_ops = { From fc53a66227af08d868face4b33fa8b2e1ba187ed Mon Sep 17 00:00:00 2001 From: Qiang Ma Date: Sat, 17 Jan 2026 10:57:03 +0800 Subject: [PATCH 2124/2333] LoongArch: KVM: Fix kvm_device leak in kvm_pch_pic_destroy() commit 1cf342a7c3adc5877837b53bbceb5cc9eff60bbf upstream. In kvm_ioctl_create_device(), kvm_device has allocated memory, kvm_device->destroy() seems to be supposed to free its kvm_device struct, but kvm_pch_pic_destroy() is not currently doing this, that would lead to a memory leak. So, fix it. Cc: stable@vger.kernel.org Reviewed-by: Bibo Mao Signed-off-by: Qiang Ma Signed-off-by: Huacai Chen Signed-off-by: Greg Kroah-Hartman --- arch/loongarch/kvm/intc/pch_pic.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/loongarch/kvm/intc/pch_pic.c b/arch/loongarch/kvm/intc/pch_pic.c index a698a73de399b..4addb34bf432b 100644 --- a/arch/loongarch/kvm/intc/pch_pic.c +++ b/arch/loongarch/kvm/intc/pch_pic.c @@ -475,6 +475,7 @@ static void kvm_pch_pic_destroy(struct kvm_device *dev) /* unregister pch pic device and free it's memory */ kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS, &s->device); kfree(s); + kfree(dev); } static struct kvm_device_ops kvm_pch_pic_dev_ops = { From 3706be7cbcd5f9981dd9e0296edb6743596fdd10 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Wed, 31 Dec 2025 13:34:59 +0100 Subject: [PATCH 2125/2333] dmaengine: apple-admac: Add "apple,t8103-admac" compatible commit 76cba1e60b69c9cd53b9127d017a7dc5945455b1 upstream. After discussion with the devicetree maintainers we agreed to not extend lists with the generic compatible "apple,admac" anymore [1]. Use "apple,t8103-admac" as base compatible as it is the SoC the driver and bindings were written for. [1]: https://lore.kernel.org/asahi/12ab93b7-1fc2-4ce0-926e-c8141cfe81bf@kernel.org/ Fixes: b127315d9a78 ("dmaengine: apple-admac: Add Apple ADMAC driver") Cc: stable@vger.kernel.org Reviewed-by: Neal Gompa Signed-off-by: Janne Grunau Link: https://patch.msgid.link/20251231-apple-admac-t8103-base-compat-v1-1-ec24a3708f76@jannau.net Signed-off-by: Vinod Koul Signed-off-by: Greg Kroah-Hartman --- drivers/dma/apple-admac.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/dma/apple-admac.c b/drivers/dma/apple-admac.c index bd49f03742912..04bbd774b3b44 100644 --- a/drivers/dma/apple-admac.c +++ b/drivers/dma/apple-admac.c @@ -936,6 +936,7 @@ static void admac_remove(struct platform_device *pdev) } static const struct of_device_id admac_of_match[] = { + { .compatible = "apple,t8103-admac", }, { .compatible = "apple,admac", }, { } }; From f3c23b7e941349505c3d40de2cc0acd93d9ac057 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 17 Nov 2025 17:12:43 +0100 Subject: [PATCH 2126/2333] dmaengine: at_hdmac: fix device leak on of_dma_xlate() commit b9074b2d7a230b6e28caa23165e9d8bc0677d333 upstream. Make sure to drop the reference taken when looking up the DMA platform device during of_dma_xlate() when releasing channel resources. Note that commit 3832b78b3ec2 ("dmaengine: at_hdmac: add missing put_device() call in at_dma_xlate()") fixed the leak in a couple of error paths but the reference is still leaking on successful allocation. Fixes: bbe89c8e3d59 ("at_hdmac: move to generic DMA binding") Fixes: 3832b78b3ec2 ("dmaengine: at_hdmac: add missing put_device() call in at_dma_xlate()") Cc: stable@vger.kernel.org # 3.10: 3832b78b3ec2 Cc: Yu Kuai Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20251117161258.10679-2-johan@kernel.org Signed-off-by: Vinod Koul Signed-off-by: Greg Kroah-Hartman --- drivers/dma/at_hdmac.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c index 2d147712cbc69..dffe5becd6c3c 100644 --- a/drivers/dma/at_hdmac.c +++ b/drivers/dma/at_hdmac.c @@ -1765,6 +1765,7 @@ static int atc_alloc_chan_resources(struct dma_chan *chan) static void atc_free_chan_resources(struct dma_chan *chan) { struct at_dma_chan *atchan = to_at_dma_chan(chan); + struct at_dma_slave *atslave; BUG_ON(atc_chan_is_enabled(atchan)); @@ -1774,8 +1775,12 @@ static void atc_free_chan_resources(struct dma_chan *chan) /* * Free atslave allocated in at_dma_xlate() */ - kfree(chan->private); - chan->private = NULL; + atslave = chan->private; + if (atslave) { + put_device(atslave->dma_dev); + kfree(atslave); + chan->private = NULL; + } dev_vdbg(chan2dev(chan), "free_chan_resources: done\n"); } From 2ed1a9de1f2d727ccae5bc9cc7c63ee3519c0c8b Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 17 Nov 2025 17:12:45 +0100 Subject: [PATCH 2127/2333] dmaengine: bcm-sba-raid: fix device leak on probe commit 7c3a46ebf15a9796b763a54272407fdbf945bed8 upstream. Make sure to drop the reference taken when looking up the mailbox device during probe on probe failures and on driver unbind. Fixes: 743e1c8ffe4e ("dmaengine: Add Broadcom SBA RAID driver") Cc: stable@vger.kernel.org # 4.13 Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20251117161258.10679-4-johan@kernel.org Signed-off-by: Vinod Koul Signed-off-by: Greg Kroah-Hartman --- drivers/dma/bcm-sba-raid.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/dma/bcm-sba-raid.c b/drivers/dma/bcm-sba-raid.c index 7f0e76439ce58..ed037fa883f6f 100644 --- a/drivers/dma/bcm-sba-raid.c +++ b/drivers/dma/bcm-sba-raid.c @@ -1699,7 +1699,7 @@ static int sba_probe(struct platform_device *pdev) /* Prealloc channel resource */ ret = sba_prealloc_channel_resources(sba); if (ret) - goto fail_free_mchan; + goto fail_put_mbox; /* Check availability of debugfs */ if (!debugfs_initialized()) @@ -1729,6 +1729,8 @@ static int sba_probe(struct platform_device *pdev) fail_free_resources: debugfs_remove_recursive(sba->root); sba_freeup_channel_resources(sba); +fail_put_mbox: + put_device(sba->mbox_dev); fail_free_mchan: mbox_free_channel(sba->mchan); return ret; @@ -1744,6 +1746,8 @@ static void sba_remove(struct platform_device *pdev) sba_freeup_channel_resources(sba); + put_device(sba->mbox_dev); + mbox_free_channel(sba->mchan); } From 9b3cff9f4007a4bd1ac7092bfe9381ce4b7da156 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 17 Nov 2025 17:12:46 +0100 Subject: [PATCH 2128/2333] dmaengine: cv1800b-dmamux: fix device leak on route allocation commit 7bb7d696e0361bbfc1411462c784998cca0afcbb upstream. Make sure to drop the reference taken when looking up the DMA mux platform device during route allocation. Note that holding a reference to a device does not prevent its driver data from going away so there is no point in keeping the reference. Fixes: db7d07b5add4 ("dmaengine: add driver for Sophgo CV18XX/SG200X dmamux") Cc: stable@vger.kernel.org # 6.17 Cc: Inochi Amaoto Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20251117161258.10679-5-johan@kernel.org Signed-off-by: Vinod Koul Signed-off-by: Greg Kroah-Hartman --- drivers/dma/cv1800b-dmamux.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/drivers/dma/cv1800b-dmamux.c b/drivers/dma/cv1800b-dmamux.c index e900d65956171..f7a952fcbc7d7 100644 --- a/drivers/dma/cv1800b-dmamux.c +++ b/drivers/dma/cv1800b-dmamux.c @@ -102,11 +102,11 @@ static void *cv1800_dmamux_route_allocate(struct of_phandle_args *dma_spec, struct llist_node *node; unsigned long flags; unsigned int chid, devid, cpuid; - int ret; + int ret = -EINVAL; if (dma_spec->args_count != DMAMUX_NCELLS) { dev_err(&pdev->dev, "invalid number of dma mux args\n"); - return ERR_PTR(-EINVAL); + goto err_put_pdev; } devid = dma_spec->args[0]; @@ -115,18 +115,18 @@ static void *cv1800_dmamux_route_allocate(struct of_phandle_args *dma_spec, if (devid > MAX_DMA_MAPPING_ID) { dev_err(&pdev->dev, "invalid device id: %u\n", devid); - return ERR_PTR(-EINVAL); + goto err_put_pdev; } if (cpuid > MAX_DMA_CPU_ID) { dev_err(&pdev->dev, "invalid cpu id: %u\n", cpuid); - return ERR_PTR(-EINVAL); + goto err_put_pdev; } dma_spec->np = of_parse_phandle(ofdma->of_node, "dma-masters", 0); if (!dma_spec->np) { dev_err(&pdev->dev, "can't get dma master\n"); - return ERR_PTR(-EINVAL); + goto err_put_pdev; } spin_lock_irqsave(&dmamux->lock, flags); @@ -136,8 +136,6 @@ static void *cv1800_dmamux_route_allocate(struct of_phandle_args *dma_spec, if (map->peripheral == devid && map->cpu == cpuid) goto found; } - - ret = -EINVAL; goto failed; } else { node = llist_del_first(&dmamux->free_maps); @@ -171,12 +169,17 @@ static void *cv1800_dmamux_route_allocate(struct of_phandle_args *dma_spec, dev_dbg(&pdev->dev, "register channel %u for req %u (cpu %u)\n", chid, devid, cpuid); + put_device(&pdev->dev); + return map; failed: spin_unlock_irqrestore(&dmamux->lock, flags); of_node_put(dma_spec->np); dev_err(&pdev->dev, "errno %d\n", ret); +err_put_pdev: + put_device(&pdev->dev); + return ERR_PTR(ret); } From eabe40f8a53c29f531e92778ea243e379f4f7978 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 17 Nov 2025 17:12:47 +0100 Subject: [PATCH 2129/2333] dmaengine: dw: dmamux: fix OF node leak on route allocation failure commit ec25e60f9f95464aa11411db31d0906b3fb7b9f2 upstream. Make sure to drop the reference taken to the DMA master OF node also on late route allocation failures. Fixes: 134d9c52fca2 ("dmaengine: dw: dmamux: Introduce RZN1 DMA router support") Cc: stable@vger.kernel.org # 5.19 Cc: Miquel Raynal Signed-off-by: Johan Hovold Reviewed-by: Miquel Raynal Link: https://patch.msgid.link/20251117161258.10679-6-johan@kernel.org Signed-off-by: Vinod Koul Signed-off-by: Greg Kroah-Hartman --- drivers/dma/dw/rzn1-dmamux.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/dma/dw/rzn1-dmamux.c b/drivers/dma/dw/rzn1-dmamux.c index deadf135681b6..cbec277af4dd3 100644 --- a/drivers/dma/dw/rzn1-dmamux.c +++ b/drivers/dma/dw/rzn1-dmamux.c @@ -90,7 +90,7 @@ static void *rzn1_dmamux_route_allocate(struct of_phandle_args *dma_spec, if (test_and_set_bit(map->req_idx, dmamux->used_chans)) { ret = -EBUSY; - goto free_map; + goto put_dma_spec_np; } mask = BIT(map->req_idx); @@ -103,6 +103,8 @@ static void *rzn1_dmamux_route_allocate(struct of_phandle_args *dma_spec, clear_bitmap: clear_bit(map->req_idx, dmamux->used_chans); +put_dma_spec_np: + of_node_put(dma_spec->np); free_map: kfree(map); put_device: From dd5d96722a967da35806dba22988f00cfe092db2 Mon Sep 17 00:00:00 2001 From: Zhen Ni Date: Tue, 14 Oct 2025 17:05:22 +0800 Subject: [PATCH 2130/2333] dmaengine: fsl-edma: Fix clk leak on alloc_chan_resources failure commit b18cd8b210417f90537d914ffb96e390c85a7379 upstream. When fsl_edma_alloc_chan_resources() fails after clk_prepare_enable(), the error paths only free IRQs and destroy the TCD pool, but forget to call clk_disable_unprepare(). This causes the channel clock to remain enabled, leaking power and resources. Fix it by disabling the channel clock in the error unwind path. Fixes: d8d4355861d8 ("dmaengine: fsl-edma: add i.MX8ULP edma support") Cc: stable@vger.kernel.org Suggested-by: Frank Li Signed-off-by: Zhen Ni Reviewed-by: Frank Li Link: https://patch.msgid.link/20251014090522.827726-1-zhen.ni@easystack.cn Signed-off-by: Vinod Koul Signed-off-by: Greg Kroah-Hartman --- drivers/dma/fsl-edma-common.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/dma/fsl-edma-common.c b/drivers/dma/fsl-edma-common.c index 4976d7dde0809..11655dcc4d6c1 100644 --- a/drivers/dma/fsl-edma-common.c +++ b/drivers/dma/fsl-edma-common.c @@ -852,6 +852,7 @@ int fsl_edma_alloc_chan_resources(struct dma_chan *chan) free_irq(fsl_chan->txirq, fsl_chan); err_txirq: dma_pool_destroy(fsl_chan->tcd_pool); + clk_disable_unprepare(fsl_chan->clk); return ret; } From a7226fd61def74b60dd8e47ec84cabafc39d575b Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 17 Nov 2025 17:12:48 +0100 Subject: [PATCH 2131/2333] dmaengine: idxd: fix device leaks on compat bind and unbind commit 799900f01792cf8b525a44764f065f83fcafd468 upstream. Make sure to drop the reference taken when looking up the idxd device as part of the compat bind and unbind sysfs interface. Fixes: 6e7f3ee97bbe ("dmaengine: idxd: move dsa_drv support to compatible mode") Cc: stable@vger.kernel.org # 5.15 Cc: Dave Jiang Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20251117161258.10679-7-johan@kernel.org Signed-off-by: Vinod Koul Signed-off-by: Greg Kroah-Hartman --- drivers/dma/idxd/compat.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/drivers/dma/idxd/compat.c b/drivers/dma/idxd/compat.c index eff9943f1a42e..95b8ef9586338 100644 --- a/drivers/dma/idxd/compat.c +++ b/drivers/dma/idxd/compat.c @@ -20,11 +20,16 @@ static ssize_t unbind_store(struct device_driver *drv, const char *buf, size_t c int rc = -ENODEV; dev = bus_find_device_by_name(bus, NULL, buf); - if (dev && dev->driver) { + if (!dev) + return -ENODEV; + + if (dev->driver) { device_driver_detach(dev); rc = count; } + put_device(dev); + return rc; } static DRIVER_ATTR_IGNORE_LOCKDEP(unbind, 0200, NULL, unbind_store); @@ -38,9 +43,12 @@ static ssize_t bind_store(struct device_driver *drv, const char *buf, size_t cou struct idxd_dev *idxd_dev; dev = bus_find_device_by_name(bus, NULL, buf); - if (!dev || dev->driver || drv != &dsa_drv.drv) + if (!dev) return -ENODEV; + if (dev->driver || drv != &dsa_drv.drv) + goto err_put_dev; + idxd_dev = confdev_to_idxd_dev(dev); if (is_idxd_dev(idxd_dev)) { alt_drv = driver_find("idxd", bus); @@ -53,13 +61,20 @@ static ssize_t bind_store(struct device_driver *drv, const char *buf, size_t cou alt_drv = driver_find("user", bus); } if (!alt_drv) - return -ENODEV; + goto err_put_dev; rc = device_driver_attach(alt_drv, dev); if (rc < 0) - return rc; + goto err_put_dev; + + put_device(dev); return count; + +err_put_dev: + put_device(dev); + + return rc; } static DRIVER_ATTR_IGNORE_LOCKDEP(bind, 0200, NULL, bind_store); From 1e47d80f6720f0224efd19bcf081d39637569c10 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 17 Nov 2025 17:12:49 +0100 Subject: [PATCH 2132/2333] dmaengine: lpc18xx-dmamux: fix device leak on route allocation commit d4d63059dee7e7cae0c4d9a532ed558bc90efb55 upstream. Make sure to drop the reference taken when looking up the DMA mux platform device during route allocation. Note that holding a reference to a device does not prevent its driver data from going away so there is no point in keeping the reference. Fixes: e5f4ae84be74 ("dmaengine: add driver for lpc18xx dmamux") Cc: stable@vger.kernel.org # 4.3 Signed-off-by: Johan Hovold Reviewed-by: Vladimir Zapolskiy Link: https://patch.msgid.link/20251117161258.10679-8-johan@kernel.org Signed-off-by: Vinod Koul Signed-off-by: Greg Kroah-Hartman --- drivers/dma/lpc18xx-dmamux.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/drivers/dma/lpc18xx-dmamux.c b/drivers/dma/lpc18xx-dmamux.c index 2b6436f4b1937..d3ff521951b83 100644 --- a/drivers/dma/lpc18xx-dmamux.c +++ b/drivers/dma/lpc18xx-dmamux.c @@ -57,30 +57,31 @@ static void *lpc18xx_dmamux_reserve(struct of_phandle_args *dma_spec, struct lpc18xx_dmamux_data *dmamux = platform_get_drvdata(pdev); unsigned long flags; unsigned mux; + int ret = -EINVAL; if (dma_spec->args_count != 3) { dev_err(&pdev->dev, "invalid number of dma mux args\n"); - return ERR_PTR(-EINVAL); + goto err_put_pdev; } mux = dma_spec->args[0]; if (mux >= dmamux->dma_master_requests) { dev_err(&pdev->dev, "invalid mux number: %d\n", dma_spec->args[0]); - return ERR_PTR(-EINVAL); + goto err_put_pdev; } if (dma_spec->args[1] > LPC18XX_DMAMUX_MAX_VAL) { dev_err(&pdev->dev, "invalid dma mux value: %d\n", dma_spec->args[1]); - return ERR_PTR(-EINVAL); + goto err_put_pdev; } /* The of_node_put() will be done in the core for the node */ dma_spec->np = of_parse_phandle(ofdma->of_node, "dma-masters", 0); if (!dma_spec->np) { dev_err(&pdev->dev, "can't get dma master\n"); - return ERR_PTR(-EINVAL); + goto err_put_pdev; } spin_lock_irqsave(&dmamux->lock, flags); @@ -89,7 +90,8 @@ static void *lpc18xx_dmamux_reserve(struct of_phandle_args *dma_spec, dev_err(&pdev->dev, "dma request %u busy with %u.%u\n", mux, mux, dmamux->muxes[mux].value); of_node_put(dma_spec->np); - return ERR_PTR(-EBUSY); + ret = -EBUSY; + goto err_put_pdev; } dmamux->muxes[mux].busy = true; @@ -106,7 +108,14 @@ static void *lpc18xx_dmamux_reserve(struct of_phandle_args *dma_spec, dev_dbg(&pdev->dev, "mapping dmamux %u.%u to dma request %u\n", mux, dmamux->muxes[mux].value, mux); + put_device(&pdev->dev); + return &dmamux->muxes[mux]; + +err_put_pdev: + put_device(&pdev->dev); + + return ERR_PTR(ret); } static int lpc18xx_dmamux_probe(struct platform_device *pdev) From 9249462c55d56da2d093202db1d850a987d99d61 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 17 Nov 2025 17:12:50 +0100 Subject: [PATCH 2133/2333] dmaengine: lpc32xx-dmamux: fix device leak on route allocation commit d9847e6d1d91462890ba297f7888fa598d47e76e upstream. Make sure to drop the reference taken when looking up the DMA mux platform device during route allocation. Note that holding a reference to a device does not prevent its driver data from going away so there is no point in keeping the reference. Fixes: 5d318b595982 ("dmaengine: Add dma router for pl08x in LPC32XX SoC") Cc: stable@vger.kernel.org # 6.12 Cc: Piotr Wojtaszczyk Signed-off-by: Johan Hovold Reviewed-by: Vladimir Zapolskiy Link: https://patch.msgid.link/20251117161258.10679-9-johan@kernel.org Signed-off-by: Vinod Koul Signed-off-by: Greg Kroah-Hartman --- drivers/dma/lpc32xx-dmamux.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/drivers/dma/lpc32xx-dmamux.c b/drivers/dma/lpc32xx-dmamux.c index 351d7e23e6156..33be714740ddf 100644 --- a/drivers/dma/lpc32xx-dmamux.c +++ b/drivers/dma/lpc32xx-dmamux.c @@ -95,11 +95,12 @@ static void *lpc32xx_dmamux_reserve(struct of_phandle_args *dma_spec, struct lpc32xx_dmamux_data *dmamux = platform_get_drvdata(pdev); unsigned long flags; struct lpc32xx_dmamux *mux = NULL; + int ret = -EINVAL; int i; if (dma_spec->args_count != 3) { dev_err(&pdev->dev, "invalid number of dma mux args\n"); - return ERR_PTR(-EINVAL); + goto err_put_pdev; } for (i = 0; i < ARRAY_SIZE(lpc32xx_muxes); i++) { @@ -111,20 +112,20 @@ static void *lpc32xx_dmamux_reserve(struct of_phandle_args *dma_spec, if (!mux) { dev_err(&pdev->dev, "invalid mux request number: %d\n", dma_spec->args[0]); - return ERR_PTR(-EINVAL); + goto err_put_pdev; } if (dma_spec->args[2] > 1) { dev_err(&pdev->dev, "invalid dma mux value: %d\n", dma_spec->args[1]); - return ERR_PTR(-EINVAL); + goto err_put_pdev; } /* The of_node_put() will be done in the core for the node */ dma_spec->np = of_parse_phandle(ofdma->of_node, "dma-masters", 0); if (!dma_spec->np) { dev_err(&pdev->dev, "can't get dma master\n"); - return ERR_PTR(-EINVAL); + goto err_put_pdev; } spin_lock_irqsave(&dmamux->lock, flags); @@ -133,7 +134,8 @@ static void *lpc32xx_dmamux_reserve(struct of_phandle_args *dma_spec, dev_err(dev, "dma request signal %d busy, routed to %s\n", mux->signal, mux->muxval ? mux->name_sel1 : mux->name_sel1); of_node_put(dma_spec->np); - return ERR_PTR(-EBUSY); + ret = -EBUSY; + goto err_put_pdev; } mux->busy = true; @@ -148,7 +150,14 @@ static void *lpc32xx_dmamux_reserve(struct of_phandle_args *dma_spec, dev_dbg(dev, "dma request signal %d routed to %s\n", mux->signal, mux->muxval ? mux->name_sel1 : mux->name_sel1); + put_device(&pdev->dev); + return mux; + +err_put_pdev: + put_device(&pdev->dev); + + return ERR_PTR(ret); } static int lpc32xx_dmamux_probe(struct platform_device *pdev) From 55a67ba5ac4cebfd54cc8305d4d57a0f1dfe6a85 Mon Sep 17 00:00:00 2001 From: Miaoqian Lin Date: Wed, 29 Oct 2025 20:34:19 +0800 Subject: [PATCH 2134/2333] dmaengine: qcom: gpi: Fix memory leak in gpi_peripheral_config() commit 3f747004bbd641131d9396d87b5d2d3d1e182728 upstream. Fix a memory leak in gpi_peripheral_config() where the original memory pointed to by gchan->config could be lost if krealloc() fails. The issue occurs when: 1. gchan->config points to previously allocated memory 2. krealloc() fails and returns NULL 3. The function directly assigns NULL to gchan->config, losing the reference to the original memory 4. The original memory becomes unreachable and cannot be freed Fix this by using a temporary variable to hold the krealloc() result and only updating gchan->config when the allocation succeeds. Found via static analysis and code review. Fixes: 5d0c3533a19f ("dmaengine: qcom: Add GPI dma driver") Cc: stable@vger.kernel.org Signed-off-by: Miaoqian Lin Reviewed-by: Bjorn Andersson Link: https://patch.msgid.link/20251029123421.91973-1-linmq006@gmail.com Signed-off-by: Vinod Koul Signed-off-by: Greg Kroah-Hartman --- drivers/dma/qcom/gpi.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/dma/qcom/gpi.c b/drivers/dma/qcom/gpi.c index 8e87738086b25..8908b7c719007 100644 --- a/drivers/dma/qcom/gpi.c +++ b/drivers/dma/qcom/gpi.c @@ -1605,14 +1605,16 @@ static int gpi_peripheral_config(struct dma_chan *chan, struct dma_slave_config *config) { struct gchan *gchan = to_gchan(chan); + void *new_config; if (!config->peripheral_config) return -EINVAL; - gchan->config = krealloc(gchan->config, config->peripheral_size, GFP_NOWAIT); - if (!gchan->config) + new_config = krealloc(gchan->config, config->peripheral_size, GFP_NOWAIT); + if (!new_config) return -ENOMEM; + gchan->config = new_config; memcpy(gchan->config, config->peripheral_config, config->peripheral_size); return 0; From 926d1666420c227eab50962a8622c1b8444720e8 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 17 Nov 2025 17:12:51 +0100 Subject: [PATCH 2135/2333] dmaengine: sh: rz-dmac: fix device leak on probe failure commit 9fb490323997dcb6f749cd2660a17a39854600cd upstream. Make sure to drop the reference taken when looking up the ICU device during probe also on probe failures (e.g. probe deferral). Fixes: 7de873201c44 ("dmaengine: sh: rz-dmac: Add RZ/V2H(P) support") Cc: stable@vger.kernel.org # 6.16 Cc: Fabrizio Castro Signed-off-by: Johan Hovold Reviewed-by: Fabrizio Castro Link: https://patch.msgid.link/20251117161258.10679-10-johan@kernel.org Signed-off-by: Vinod Koul Signed-off-by: Greg Kroah-Hartman --- drivers/dma/sh/rz-dmac.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/dma/sh/rz-dmac.c b/drivers/dma/sh/rz-dmac.c index 1f687b08d6b86..38137e8d80b9f 100644 --- a/drivers/dma/sh/rz-dmac.c +++ b/drivers/dma/sh/rz-dmac.c @@ -854,6 +854,13 @@ static int rz_dmac_chan_probe(struct rz_dmac *dmac, return 0; } +static void rz_dmac_put_device(void *_dev) +{ + struct device *dev = _dev; + + put_device(dev); +} + static int rz_dmac_parse_of_icu(struct device *dev, struct rz_dmac *dmac) { struct device_node *np = dev->of_node; @@ -876,6 +883,10 @@ static int rz_dmac_parse_of_icu(struct device *dev, struct rz_dmac *dmac) return -ENODEV; } + ret = devm_add_action_or_reset(dev, rz_dmac_put_device, &dmac->icu.pdev->dev); + if (ret) + return ret; + dmac_index = args.args[0]; if (dmac_index > RZV2H_MAX_DMAC_INDEX) { dev_err(dev, "DMAC index %u invalid.\n", dmac_index); @@ -1055,8 +1066,6 @@ static void rz_dmac_remove(struct platform_device *pdev) reset_control_assert(dmac->rstc); pm_runtime_put(&pdev->dev); pm_runtime_disable(&pdev->dev); - - platform_device_put(dmac->icu.pdev); } static const struct of_device_id of_rz_dmac_match[] = { From 8dd65e98ce20985453c712b550566c6330774b5c Mon Sep 17 00:00:00 2001 From: Biju Das Date: Thu, 13 Nov 2025 19:50:48 +0000 Subject: [PATCH 2136/2333] dmaengine: sh: rz-dmac: Fix rz_dmac_terminate_all() commit 747213b08a1ab6a76e3e3b3e7a209cc1d402b5d0 upstream. After audio full duplex testing, playing the recorded file contains a few playback frames from the previous time. The rz_dmac_terminate_all() does not reset all the hardware descriptors queued previously, leading to the wrong descriptor being picked up during the next DMA transfer. Fix the above issue by resetting all the descriptor headers for a channel in rz_dmac_terminate_all() as rz_dmac_lmdesc_recycle() points to the proper descriptor header filled by the rz_dmac_prepare_descs_for_slave_sg(). Cc: stable@kernel.org Fixes: 5000d37042a6 ("dmaengine: sh: Add DMAC driver for RZ/G2L SoC") Reviewed-by: Geert Uytterhoeven Signed-off-by: Biju Das Reviewed-by: Claudiu Beznea Tested-by: Claudiu Beznea Link: https://patch.msgid.link/20251113195052.564338-1-biju.das.jz@bp.renesas.com Signed-off-by: Vinod Koul Signed-off-by: Greg Kroah-Hartman --- drivers/dma/sh/rz-dmac.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/dma/sh/rz-dmac.c b/drivers/dma/sh/rz-dmac.c index 38137e8d80b9f..9e5f088355e22 100644 --- a/drivers/dma/sh/rz-dmac.c +++ b/drivers/dma/sh/rz-dmac.c @@ -557,11 +557,16 @@ rz_dmac_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, static int rz_dmac_terminate_all(struct dma_chan *chan) { struct rz_dmac_chan *channel = to_rz_dmac_chan(chan); + struct rz_lmdesc *lmdesc = channel->lmdesc.base; unsigned long flags; + unsigned int i; LIST_HEAD(head); rz_dmac_disable_hw(channel); spin_lock_irqsave(&channel->vc.lock, flags); + for (i = 0; i < DMAC_NR_LMDESC; i++) + lmdesc[i].header = 0; + list_splice_tail_init(&channel->ld_active, &channel->ld_free); list_splice_tail_init(&channel->ld_queue, &channel->ld_free); vchan_get_all_descriptors(&channel->vc, &head); From 3ef52d31cce8ba816739085a61efe07b63c6cf27 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 17 Nov 2025 17:12:52 +0100 Subject: [PATCH 2137/2333] dmaengine: stm32: dmamux: fix device leak on route allocation commit dd6e4943889fb354efa3f700e42739da9bddb6ef upstream. Make sure to drop the reference taken when looking up the DMA mux platform device during route allocation. Note that holding a reference to a device does not prevent its driver data from going away so there is no point in keeping the reference. Fixes: df7e762db5f6 ("dmaengine: Add STM32 DMAMUX driver") Cc: stable@vger.kernel.org # 4.15 Cc: Pierre-Yves MORDRET Signed-off-by: Johan Hovold Reviewed-by: Amelie Delaunay Link: https://patch.msgid.link/20251117161258.10679-11-johan@kernel.org Signed-off-by: Vinod Koul Signed-off-by: Greg Kroah-Hartman --- drivers/dma/stm32/stm32-dmamux.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/drivers/dma/stm32/stm32-dmamux.c b/drivers/dma/stm32/stm32-dmamux.c index 8d77e2a7939a0..7911797607824 100644 --- a/drivers/dma/stm32/stm32-dmamux.c +++ b/drivers/dma/stm32/stm32-dmamux.c @@ -90,23 +90,25 @@ static void *stm32_dmamux_route_allocate(struct of_phandle_args *dma_spec, struct stm32_dmamux_data *dmamux = platform_get_drvdata(pdev); struct stm32_dmamux *mux; u32 i, min, max; - int ret; + int ret = -EINVAL; unsigned long flags; if (dma_spec->args_count != 3) { dev_err(&pdev->dev, "invalid number of dma mux args\n"); - return ERR_PTR(-EINVAL); + goto err_put_pdev; } if (dma_spec->args[0] > dmamux->dmamux_requests) { dev_err(&pdev->dev, "invalid mux request number: %d\n", dma_spec->args[0]); - return ERR_PTR(-EINVAL); + goto err_put_pdev; } mux = kzalloc(sizeof(*mux), GFP_KERNEL); - if (!mux) - return ERR_PTR(-ENOMEM); + if (!mux) { + ret = -ENOMEM; + goto err_put_pdev; + } spin_lock_irqsave(&dmamux->lock, flags); mux->chan_id = find_first_zero_bit(dmamux->dma_inuse, @@ -133,7 +135,6 @@ static void *stm32_dmamux_route_allocate(struct of_phandle_args *dma_spec, dma_spec->np = of_parse_phandle(ofdma->of_node, "dma-masters", i - 1); if (!dma_spec->np) { dev_err(&pdev->dev, "can't get dma master\n"); - ret = -EINVAL; goto error; } @@ -160,6 +161,8 @@ static void *stm32_dmamux_route_allocate(struct of_phandle_args *dma_spec, dev_dbg(&pdev->dev, "Mapping DMAMUX(%u) to DMA%u(%u)\n", mux->request, mux->master, mux->chan_id); + put_device(&pdev->dev); + return mux; error: @@ -167,6 +170,9 @@ static void *stm32_dmamux_route_allocate(struct of_phandle_args *dma_spec, error_chan_id: kfree(mux); +err_put_pdev: + put_device(&pdev->dev); + return ERR_PTR(ret); } From f45b1d8bf9d0a9b45ebadcb66b6f93017b10f7a1 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 17 Nov 2025 17:12:53 +0100 Subject: [PATCH 2138/2333] dmaengine: stm32: dmamux: fix OF node leak on route allocation failure commit b1b590a590af13ded598e70f0b72bc1e515787a1 upstream. Make sure to drop the reference taken to the DMA master OF node also on late route allocation failures. Fixes: df7e762db5f6 ("dmaengine: Add STM32 DMAMUX driver") Cc: stable@vger.kernel.org # 4.15 Cc: Pierre-Yves MORDRET Signed-off-by: Johan Hovold Reviewed-by: Amelie Delaunay Link: https://patch.msgid.link/20251117161258.10679-12-johan@kernel.org Signed-off-by: Vinod Koul Signed-off-by: Greg Kroah-Hartman --- drivers/dma/stm32/stm32-dmamux.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/dma/stm32/stm32-dmamux.c b/drivers/dma/stm32/stm32-dmamux.c index 7911797607824..2bd218dbabbb1 100644 --- a/drivers/dma/stm32/stm32-dmamux.c +++ b/drivers/dma/stm32/stm32-dmamux.c @@ -143,7 +143,7 @@ static void *stm32_dmamux_route_allocate(struct of_phandle_args *dma_spec, ret = pm_runtime_resume_and_get(&pdev->dev); if (ret < 0) { spin_unlock_irqrestore(&dmamux->lock, flags); - goto error; + goto err_put_dma_spec_np; } spin_unlock_irqrestore(&dmamux->lock, flags); @@ -165,6 +165,8 @@ static void *stm32_dmamux_route_allocate(struct of_phandle_args *dma_spec, return mux; +err_put_dma_spec_np: + of_node_put(dma_spec->np); error: clear_bit(mux->chan_id, dmamux->dma_inuse); From 61e8970b0de16f13df1a1fc60106f6d07a45f77d Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 17 Nov 2025 17:12:55 +0100 Subject: [PATCH 2139/2333] dmaengine: ti: dma-crossbar: fix device leak on dra7x route allocation commit dc7e44db01fc2498644e3106db3e62a9883a93d5 upstream. Make sure to drop the reference taken when looking up the crossbar platform device during dra7x route allocation. Note that commit 615a4bfc426e ("dmaengine: ti: Add missing put_device in ti_dra7_xbar_route_allocate") fixed the leak in the error paths but the reference is still leaking on successful allocation. Fixes: a074ae38f859 ("dmaengine: Add driver for TI DMA crossbar on DRA7x") Fixes: 615a4bfc426e ("dmaengine: ti: Add missing put_device in ti_dra7_xbar_route_allocate") Cc: stable@vger.kernel.org # 4.2: 615a4bfc426e Cc: Peter Ujfalusi Cc: Miaoqian Lin Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20251117161258.10679-14-johan@kernel.org Signed-off-by: Vinod Koul Signed-off-by: Greg Kroah-Hartman --- drivers/dma/ti/dma-crossbar.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/dma/ti/dma-crossbar.c b/drivers/dma/ti/dma-crossbar.c index 7f17ee87a6dce..e52b0e1399008 100644 --- a/drivers/dma/ti/dma-crossbar.c +++ b/drivers/dma/ti/dma-crossbar.c @@ -288,6 +288,8 @@ static void *ti_dra7_xbar_route_allocate(struct of_phandle_args *dma_spec, ti_dra7_xbar_write(xbar->iomem, map->xbar_out, map->xbar_in); + put_device(&pdev->dev); + return map; } From 30352277d8e09c972436f883a5efd1f1b763ac14 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 17 Nov 2025 17:12:56 +0100 Subject: [PATCH 2140/2333] dmaengine: ti: dma-crossbar: fix device leak on am335x route allocation commit 4fc17b1c6d2e04ad13fd6c21cfbac68043ec03f9 upstream. Make sure to drop the reference taken when looking up the crossbar platform device during am335x route allocation. Fixes: 42dbdcc6bf96 ("dmaengine: ti-dma-crossbar: Add support for crossbar on AM33xx/AM43xx") Cc: stable@vger.kernel.org # 4.4 Cc: Peter Ujfalusi Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20251117161258.10679-15-johan@kernel.org Signed-off-by: Vinod Koul Signed-off-by: Greg Kroah-Hartman --- drivers/dma/ti/dma-crossbar.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/drivers/dma/ti/dma-crossbar.c b/drivers/dma/ti/dma-crossbar.c index e52b0e1399008..ff05b150ad372 100644 --- a/drivers/dma/ti/dma-crossbar.c +++ b/drivers/dma/ti/dma-crossbar.c @@ -79,34 +79,35 @@ static void *ti_am335x_xbar_route_allocate(struct of_phandle_args *dma_spec, { struct platform_device *pdev = of_find_device_by_node(ofdma->of_node); struct ti_am335x_xbar_data *xbar = platform_get_drvdata(pdev); - struct ti_am335x_xbar_map *map; + struct ti_am335x_xbar_map *map = ERR_PTR(-EINVAL); if (dma_spec->args_count != 3) - return ERR_PTR(-EINVAL); + goto out_put_pdev; if (dma_spec->args[2] >= xbar->xbar_events) { dev_err(&pdev->dev, "Invalid XBAR event number: %d\n", dma_spec->args[2]); - return ERR_PTR(-EINVAL); + goto out_put_pdev; } if (dma_spec->args[0] >= xbar->dma_requests) { dev_err(&pdev->dev, "Invalid DMA request line number: %d\n", dma_spec->args[0]); - return ERR_PTR(-EINVAL); + goto out_put_pdev; } /* The of_node_put() will be done in the core for the node */ dma_spec->np = of_parse_phandle(ofdma->of_node, "dma-masters", 0); if (!dma_spec->np) { dev_err(&pdev->dev, "Can't get DMA master\n"); - return ERR_PTR(-EINVAL); + goto out_put_pdev; } map = kzalloc(sizeof(*map), GFP_KERNEL); if (!map) { of_node_put(dma_spec->np); - return ERR_PTR(-ENOMEM); + map = ERR_PTR(-ENOMEM); + goto out_put_pdev; } map->dma_line = (u16)dma_spec->args[0]; @@ -120,6 +121,9 @@ static void *ti_am335x_xbar_route_allocate(struct of_phandle_args *dma_spec, ti_am335x_xbar_write(xbar->iomem, map->dma_line, map->mux_val); +out_put_pdev: + put_device(&pdev->dev); + return map; } From b3bbbf9da38c2735dc25f50e62775216dfd756f6 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 17 Nov 2025 17:12:58 +0100 Subject: [PATCH 2141/2333] dmaengine: ti: k3-udma: fix device leak on udma lookup commit 430f7803b69cd5e5694e5dfc884c6628870af36e upstream. Make sure to drop the reference taken when looking up the UDMA platform device. Note that holding a reference to a platform device does not prevent its driver data from going away so there is no point in keeping the reference after the lookup helper returns. Fixes: d70241913413 ("dmaengine: ti: k3-udma: Add glue layer for non DMAengine users") Fixes: 1438cde8fe9c ("dmaengine: ti: k3-udma: add missing put_device() call in of_xudma_dev_get()") Cc: stable@vger.kernel.org # 5.6: 1438cde8fe9c Cc: Grygorii Strashko Cc: Yu Kuai Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20251117161258.10679-17-johan@kernel.org Signed-off-by: Vinod Koul Signed-off-by: Greg Kroah-Hartman --- drivers/dma/ti/k3-udma-private.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/dma/ti/k3-udma-private.c b/drivers/dma/ti/k3-udma-private.c index 05228bf000333..624360423ef17 100644 --- a/drivers/dma/ti/k3-udma-private.c +++ b/drivers/dma/ti/k3-udma-private.c @@ -42,9 +42,9 @@ struct udma_dev *of_xudma_dev_get(struct device_node *np, const char *property) } ud = platform_get_drvdata(pdev); + put_device(&pdev->dev); if (!ud) { pr_debug("UDMA has not been probed\n"); - put_device(&pdev->dev); return ERR_PTR(-EPROBE_DEFER); } From 1ca0f9e97f315348354b973ffaa3cc7c0328ab10 Mon Sep 17 00:00:00 2001 From: Dave Hansen Date: Wed, 22 Oct 2025 16:26:28 +0800 Subject: [PATCH 2142/2333] mm: add a ptdesc flag to mark kernel page tables commit 27bfafac65d87c58639f5d7af1353ec1e7886963 upstream. The page tables used to map the kernel and userspace often have very different handling rules. There are frequently *_kernel() variants of functions just for kernel page tables. That's not great and has lead to code duplication. Instead of having completely separate call paths, allow a 'ptdesc' to be marked as being for kernel mappings. Introduce helpers to set and clear this status. Note: this uses the PG_referenced bit. Page flags are a great fit for this since it is truly a single bit of information. Use PG_referenced itself because it's a fairly benign flag (as opposed to things like PG_lock). It's also (according to Willy) unlikely to go away any time soon. PG_referenced is not in PAGE_FLAGS_CHECK_AT_FREE. It does not need to be cleared before freeing the page, and pages coming out of the allocator should have it cleared. Regardless, introduce an API to clear it anyway. Having symmetry in the API makes it easier to change the underlying implementation later, like if there was a need to move to a PAGE_FLAGS_CHECK_AT_FREE bit. Link: https://lkml.kernel.org/r/20251022082635.2462433-3-baolu.lu@linux.intel.com Signed-off-by: Dave Hansen Signed-off-by: Lu Baolu Reviewed-by: Jason Gunthorpe Reviewed-by: Kevin Tian Acked-by: David Hildenbrand Acked-by: Mike Rapoport (Microsoft) Cc: Alistair Popple Cc: Andy Lutomirski Cc: Borislav Betkov Cc: Ingo Molnar Cc: Jann Horn Cc: Jean-Philippe Brucker Cc: Joerg Roedel Cc: Liam Howlett Cc: Lorenzo Stoakes Cc: Matthew Wilcox (Oracle) Cc: Michal Hocko Cc: Peter Zijlstra Cc: Robin Murohy Cc: Thomas Gleinxer Cc: "Uladzislau Rezki (Sony)" Cc: Vasant Hegde Cc: Vinicius Costa Gomes Cc: Vlastimil Babka Cc: Will Deacon Cc: Yi Lai Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- include/linux/mm.h | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/include/linux/mm.h b/include/linux/mm.h index 8631c9424987d..d622756f4e38b 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -2947,6 +2947,7 @@ static inline pmd_t *pmd_alloc(struct mm_struct *mm, pud_t *pud, unsigned long a #endif /* CONFIG_MMU */ enum pt_flags { + PT_kernel = PG_referenced, PT_reserved = PG_reserved, /* High bits are used for zone/node/section */ }; @@ -2972,6 +2973,46 @@ static inline bool pagetable_is_reserved(struct ptdesc *pt) return test_bit(PT_reserved, &pt->pt_flags.f); } +/** + * ptdesc_set_kernel - Mark a ptdesc used to map the kernel + * @ptdesc: The ptdesc to be marked + * + * Kernel page tables often need special handling. Set a flag so that + * the handling code knows this ptdesc will not be used for userspace. + */ +static inline void ptdesc_set_kernel(struct ptdesc *ptdesc) +{ + set_bit(PT_kernel, &ptdesc->pt_flags.f); +} + +/** + * ptdesc_clear_kernel - Mark a ptdesc as no longer used to map the kernel + * @ptdesc: The ptdesc to be unmarked + * + * Use when the ptdesc is no longer used to map the kernel and no longer + * needs special handling. + */ +static inline void ptdesc_clear_kernel(struct ptdesc *ptdesc) +{ + /* + * Note: the 'PG_referenced' bit does not strictly need to be + * cleared before freeing the page. But this is nice for + * symmetry. + */ + clear_bit(PT_kernel, &ptdesc->pt_flags.f); +} + +/** + * ptdesc_test_kernel - Check if a ptdesc is used to map the kernel + * @ptdesc: The ptdesc being tested + * + * Call to tell if the ptdesc used to map the kernel. + */ +static inline bool ptdesc_test_kernel(const struct ptdesc *ptdesc) +{ + return test_bit(PT_kernel, &ptdesc->pt_flags.f); +} + /** * pagetable_alloc - Allocate pagetables * @gfp: GFP flags From 83ce8bf84846a8e205473156ade89c823549cd06 Mon Sep 17 00:00:00 2001 From: Dave Hansen Date: Wed, 22 Oct 2025 16:26:29 +0800 Subject: [PATCH 2143/2333] mm: actually mark kernel page table pages commit 977870522af34359b461060597ee3a86f27450d6 upstream. Now that the API is in place, mark kernel page table pages just after they are allocated. Unmark them just before they are freed. Note: Unconditionally clearing the 'kernel' marking (via ptdesc_clear_kernel()) would be functionally identical to what is here. But having the if() makes it logically clear that this function can be used for kernel and non-kernel page tables. Link: https://lkml.kernel.org/r/20251022082635.2462433-4-baolu.lu@linux.intel.com Signed-off-by: Dave Hansen Signed-off-by: Lu Baolu Reviewed-by: Jason Gunthorpe Reviewed-by: Kevin Tian Acked-by: David Hildenbrand Acked-by: Mike Rapoport (Microsoft) Cc: Alistair Popple Cc: Andy Lutomirski Cc: Borislav Betkov Cc: Ingo Molnar Cc: Jann Horn Cc: Jean-Philippe Brucker Cc: Joerg Roedel Cc: Liam Howlett Cc: Lorenzo Stoakes Cc: Matthew Wilcox (Oracle) Cc: Michal Hocko Cc: Peter Zijlstra Cc: Robin Murohy Cc: Thomas Gleinxer Cc: "Uladzislau Rezki (Sony)" Cc: Vasant Hegde Cc: Vinicius Costa Gomes Cc: Vlastimil Babka Cc: Will Deacon Cc: Yi Lai Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- include/asm-generic/pgalloc.h | 18 ++++++++++++++++++ include/linux/mm.h | 3 +++ 2 files changed, 21 insertions(+) diff --git a/include/asm-generic/pgalloc.h b/include/asm-generic/pgalloc.h index 3c8ec3bfea447..b9d2a7c79b93a 100644 --- a/include/asm-generic/pgalloc.h +++ b/include/asm-generic/pgalloc.h @@ -28,6 +28,8 @@ static inline pte_t *__pte_alloc_one_kernel_noprof(struct mm_struct *mm) return NULL; } + ptdesc_set_kernel(ptdesc); + return ptdesc_address(ptdesc); } #define __pte_alloc_one_kernel(...) alloc_hooks(__pte_alloc_one_kernel_noprof(__VA_ARGS__)) @@ -146,6 +148,10 @@ static inline pmd_t *pmd_alloc_one_noprof(struct mm_struct *mm, unsigned long ad pagetable_free(ptdesc); return NULL; } + + if (mm == &init_mm) + ptdesc_set_kernel(ptdesc); + return ptdesc_address(ptdesc); } #define pmd_alloc_one(...) alloc_hooks(pmd_alloc_one_noprof(__VA_ARGS__)) @@ -179,6 +185,10 @@ static inline pud_t *__pud_alloc_one_noprof(struct mm_struct *mm, unsigned long return NULL; pagetable_pud_ctor(ptdesc); + + if (mm == &init_mm) + ptdesc_set_kernel(ptdesc); + return ptdesc_address(ptdesc); } #define __pud_alloc_one(...) alloc_hooks(__pud_alloc_one_noprof(__VA_ARGS__)) @@ -233,6 +243,10 @@ static inline p4d_t *__p4d_alloc_one_noprof(struct mm_struct *mm, unsigned long return NULL; pagetable_p4d_ctor(ptdesc); + + if (mm == &init_mm) + ptdesc_set_kernel(ptdesc); + return ptdesc_address(ptdesc); } #define __p4d_alloc_one(...) alloc_hooks(__p4d_alloc_one_noprof(__VA_ARGS__)) @@ -277,6 +291,10 @@ static inline pgd_t *__pgd_alloc_noprof(struct mm_struct *mm, unsigned int order return NULL; pagetable_pgd_ctor(ptdesc); + + if (mm == &init_mm) + ptdesc_set_kernel(ptdesc); + return ptdesc_address(ptdesc); } #define __pgd_alloc(...) alloc_hooks(__pgd_alloc_noprof(__VA_ARGS__)) diff --git a/include/linux/mm.h b/include/linux/mm.h index d622756f4e38b..1f4305693d0ff 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -3042,6 +3042,9 @@ static inline void pagetable_free(struct ptdesc *pt) { struct page *page = ptdesc_page(pt); + if (ptdesc_test_kernel(pt)) + ptdesc_clear_kernel(pt); + __free_pages(page, compound_order(page)); } From b63c129bc3adbc2110fbdcf87402e6712edbff13 Mon Sep 17 00:00:00 2001 From: Dave Hansen Date: Wed, 22 Oct 2025 16:26:30 +0800 Subject: [PATCH 2144/2333] x86/mm: use 'ptdesc' when freeing PMD pages commit 412d000346ea38ac4b9bb715a86c73ef89d90dea upstream. There are a billion ways to refer to a physical memory address. One of the x86 PMD freeing code location chooses to use a 'pte_t *' to point to a PMD page and then call a PTE-specific freeing function for it. That's a bit wonky. Just use a 'struct ptdesc *' instead. Its entire purpose is to refer to page table pages. It also means being able to remove an explicit cast. Right now, pte_free_kernel() is a one-liner that calls pagetable_dtor_free(). Effectively, all this patch does is remove one superfluous __pa(__va(paddr)) conversion and then call pagetable_dtor_free() directly instead of through a helper. Link: https://lkml.kernel.org/r/20251022082635.2462433-5-baolu.lu@linux.intel.com Signed-off-by: Dave Hansen Signed-off-by: Lu Baolu Reviewed-by: Jason Gunthorpe Reviewed-by: Kevin Tian Cc: Alistair Popple Cc: Andy Lutomirski Cc: Borislav Betkov Cc: David Hildenbrand Cc: Ingo Molnar Cc: Jann Horn Cc: Jean-Philippe Brucker Cc: Joerg Roedel Cc: Liam Howlett Cc: Lorenzo Stoakes Cc: Matthew Wilcox (Oracle) Cc: Michal Hocko Cc: Mike Rapoport (Microsoft) Cc: Peter Zijlstra Cc: Robin Murohy Cc: Thomas Gleinxer Cc: "Uladzislau Rezki (Sony)" Cc: Vasant Hegde Cc: Vinicius Costa Gomes Cc: Vlastimil Babka Cc: Will Deacon Cc: Yi Lai Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- arch/x86/mm/pgtable.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/x86/mm/pgtable.c b/arch/x86/mm/pgtable.c index ddf248c3ee7dc..2e5ecfdce73c3 100644 --- a/arch/x86/mm/pgtable.c +++ b/arch/x86/mm/pgtable.c @@ -729,7 +729,7 @@ int pmd_clear_huge(pmd_t *pmd) int pud_free_pmd_page(pud_t *pud, unsigned long addr) { pmd_t *pmd, *pmd_sv; - pte_t *pte; + struct ptdesc *pt; int i; pmd = pud_pgtable(*pud); @@ -750,8 +750,8 @@ int pud_free_pmd_page(pud_t *pud, unsigned long addr) for (i = 0; i < PTRS_PER_PMD; i++) { if (!pmd_none(pmd_sv[i])) { - pte = (pte_t *)pmd_page_vaddr(pmd_sv[i]); - pte_free_kernel(&init_mm, pte); + pt = page_ptdesc(pmd_page(pmd_sv[i])); + pagetable_dtor_free(pt); } } @@ -772,15 +772,15 @@ int pud_free_pmd_page(pud_t *pud, unsigned long addr) */ int pmd_free_pte_page(pmd_t *pmd, unsigned long addr) { - pte_t *pte; + struct ptdesc *pt; - pte = (pte_t *)pmd_page_vaddr(*pmd); + pt = page_ptdesc(pmd_page(*pmd)); pmd_clear(pmd); /* INVLPG to clear all paging-structure caches */ flush_tlb_kernel_range(addr, addr + PAGE_SIZE-1); - pte_free_kernel(&init_mm, pte); + pagetable_dtor_free(pt); return 1; } From c32806bf45b6224370bf74e001d9ea7f047e7b8b Mon Sep 17 00:00:00 2001 From: Dave Hansen Date: Wed, 22 Oct 2025 16:26:31 +0800 Subject: [PATCH 2145/2333] mm: introduce pure page table freeing function commit 01894295672335ff304beed4359f30d14d5765f2 upstream. The pages used for ptdescs are currently freed back to the allocator in a single location. They will shortly be freed from a second location. Create a simple helper that just frees them back to the allocator. Link: https://lkml.kernel.org/r/20251022082635.2462433-6-baolu.lu@linux.intel.com Signed-off-by: Dave Hansen Signed-off-by: Lu Baolu Reviewed-by: Jason Gunthorpe Reviewed-by: Kevin Tian Acked-by: David Hildenbrand Acked-by: Mike Rapoport (Microsoft) Cc: Alistair Popple Cc: Andy Lutomirski Cc: Borislav Betkov Cc: Ingo Molnar Cc: Jann Horn Cc: Jean-Philippe Brucker Cc: Joerg Roedel Cc: Liam Howlett Cc: Lorenzo Stoakes Cc: Matthew Wilcox (Oracle) Cc: Michal Hocko Cc: Peter Zijlstra Cc: Robin Murohy Cc: Thomas Gleinxer Cc: "Uladzislau Rezki (Sony)" Cc: Vasant Hegde Cc: Vinicius Costa Gomes Cc: Vlastimil Babka Cc: Will Deacon Cc: Yi Lai Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- include/linux/mm.h | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/include/linux/mm.h b/include/linux/mm.h index 1f4305693d0ff..525842553c1d4 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -3031,6 +3031,13 @@ static inline struct ptdesc *pagetable_alloc_noprof(gfp_t gfp, unsigned int orde } #define pagetable_alloc(...) alloc_hooks(pagetable_alloc_noprof(__VA_ARGS__)) +static inline void __pagetable_free(struct ptdesc *pt) +{ + struct page *page = ptdesc_page(pt); + + __free_pages(page, compound_order(page)); +} + /** * pagetable_free - Free pagetables * @pt: The page table descriptor @@ -3040,12 +3047,10 @@ static inline struct ptdesc *pagetable_alloc_noprof(gfp_t gfp, unsigned int orde */ static inline void pagetable_free(struct ptdesc *pt) { - struct page *page = ptdesc_page(pt); - if (ptdesc_test_kernel(pt)) ptdesc_clear_kernel(pt); - __free_pages(page, compound_order(page)); + __pagetable_free(pt); } #if defined(CONFIG_SPLIT_PTE_PTLOCKS) From a1593c90896babf33e947910c7aecb9f50bab993 Mon Sep 17 00:00:00 2001 From: Lu Baolu Date: Wed, 22 Oct 2025 16:26:32 +0800 Subject: [PATCH 2146/2333] x86/mm: use pagetable_free() commit bf9e4e30f3538391745a99bc2268ec4f5e4a401e upstream. The kernel's memory management subsystem provides a dedicated interface, pagetable_free(), for freeing page table pages. Updates two call sites to use pagetable_free() instead of the lower-level __free_page() or free_pages(). This improves code consistency and clarity, and ensures the correct freeing mechanism is used. Link: https://lkml.kernel.org/r/20251022082635.2462433-7-baolu.lu@linux.intel.com Signed-off-by: Lu Baolu Reviewed-by: Jason Gunthorpe Acked-by: David Hildenbrand Acked-by: Mike Rapoport (Microsoft) Cc: Alistair Popple Cc: Andy Lutomirski Cc: Borislav Betkov Cc: Dave Hansen Cc: Ingo Molnar Cc: Jann Horn Cc: Jean-Philippe Brucker Cc: Joerg Roedel Cc: Kevin Tian Cc: Liam Howlett Cc: Lorenzo Stoakes Cc: Matthew Wilcox (Oracle) Cc: Michal Hocko Cc: Peter Zijlstra Cc: Robin Murohy Cc: Thomas Gleinxer Cc: "Uladzislau Rezki (Sony)" Cc: Vasant Hegde Cc: Vinicius Costa Gomes Cc: Vlastimil Babka Cc: Will Deacon Cc: Yi Lai Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- arch/x86/mm/init_64.c | 2 +- arch/x86/mm/pat/set_memory.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c index 0e4270e20fadb..3d9a5e4ccaa43 100644 --- a/arch/x86/mm/init_64.c +++ b/arch/x86/mm/init_64.c @@ -1031,7 +1031,7 @@ static void __meminit free_pagetable(struct page *page, int order) free_reserved_pages(page, nr_pages); #endif } else { - __free_pages(page, order); + pagetable_free(page_ptdesc(page)); } } diff --git a/arch/x86/mm/pat/set_memory.c b/arch/x86/mm/pat/set_memory.c index 970981893c9b8..fffb6ef1997d2 100644 --- a/arch/x86/mm/pat/set_memory.c +++ b/arch/x86/mm/pat/set_memory.c @@ -429,7 +429,7 @@ static void cpa_collapse_large_pages(struct cpa_data *cpa) list_for_each_entry_safe(ptdesc, tmp, &pgtables, pt_list) { list_del(&ptdesc->pt_list); - __free_page(ptdesc_page(ptdesc)); + pagetable_free(ptdesc); } } From b3039c526f3e1744db0cbb7ae1f0213f5e27d3f4 Mon Sep 17 00:00:00 2001 From: Dave Hansen Date: Wed, 22 Oct 2025 16:26:33 +0800 Subject: [PATCH 2147/2333] mm: introduce deferred freeing for kernel page tables commit 5ba2f0a1556479638ac11a3c201421f5515e89f5 upstream. This introduces a conditional asynchronous mechanism, enabled by CONFIG_ASYNC_KERNEL_PGTABLE_FREE. When enabled, this mechanism defers the freeing of pages that are used as page tables for kernel address mappings. These pages are now queued to a work struct instead of being freed immediately. This deferred freeing allows for batch-freeing of page tables, providing a safe context for performing a single expensive operation (TLB flush) for a batch of kernel page tables instead of performing that expensive operation for each page table. Link: https://lkml.kernel.org/r/20251022082635.2462433-8-baolu.lu@linux.intel.com Signed-off-by: Dave Hansen Signed-off-by: Lu Baolu Reviewed-by: Jason Gunthorpe Reviewed-by: Kevin Tian Acked-by: David Hildenbrand Acked-by: Mike Rapoport (Microsoft) Cc: Alistair Popple Cc: Andy Lutomirski Cc: Borislav Betkov Cc: Ingo Molnar Cc: Jann Horn Cc: Jean-Philippe Brucker Cc: Joerg Roedel Cc: Liam Howlett Cc: Lorenzo Stoakes Cc: Matthew Wilcox (Oracle) Cc: Michal Hocko Cc: Peter Zijlstra Cc: Robin Murohy Cc: Thomas Gleinxer Cc: "Uladzislau Rezki (Sony)" Cc: Vasant Hegde Cc: Vinicius Costa Gomes Cc: Vlastimil Babka Cc: Will Deacon Cc: Yi Lai Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- include/linux/mm.h | 16 +++++++++++++--- mm/Kconfig | 3 +++ mm/pgtable-generic.c | 37 +++++++++++++++++++++++++++++++++++++ 3 files changed, 53 insertions(+), 3 deletions(-) diff --git a/include/linux/mm.h b/include/linux/mm.h index 525842553c1d4..86b60c2a98157 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -3038,6 +3038,14 @@ static inline void __pagetable_free(struct ptdesc *pt) __free_pages(page, compound_order(page)); } +#ifdef CONFIG_ASYNC_KERNEL_PGTABLE_FREE +void pagetable_free_kernel(struct ptdesc *pt); +#else +static inline void pagetable_free_kernel(struct ptdesc *pt) +{ + __pagetable_free(pt); +} +#endif /** * pagetable_free - Free pagetables * @pt: The page table descriptor @@ -3047,10 +3055,12 @@ static inline void __pagetable_free(struct ptdesc *pt) */ static inline void pagetable_free(struct ptdesc *pt) { - if (ptdesc_test_kernel(pt)) + if (ptdesc_test_kernel(pt)) { ptdesc_clear_kernel(pt); - - __pagetable_free(pt); + pagetable_free_kernel(pt); + } else { + __pagetable_free(pt); + } } #if defined(CONFIG_SPLIT_PTE_PTLOCKS) diff --git a/mm/Kconfig b/mm/Kconfig index 5033e2aa328e4..76001e9ba04f1 100644 --- a/mm/Kconfig +++ b/mm/Kconfig @@ -915,6 +915,9 @@ config HAVE_GIGANTIC_FOLIOS def_bool (HUGETLB_PAGE && ARCH_HAS_GIGANTIC_PAGE) || \ (ZONE_DEVICE && HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD) +config ASYNC_KERNEL_PGTABLE_FREE + def_bool n + # TODO: Allow to be enabled without THP config ARCH_SUPPORTS_HUGE_PFNMAP def_bool n diff --git a/mm/pgtable-generic.c b/mm/pgtable-generic.c index 567e2d084071e..1c7caa8ef164c 100644 --- a/mm/pgtable-generic.c +++ b/mm/pgtable-generic.c @@ -406,3 +406,40 @@ pte_t *__pte_offset_map_lock(struct mm_struct *mm, pmd_t *pmd, pte_unmap_unlock(pte, ptl); goto again; } + +#ifdef CONFIG_ASYNC_KERNEL_PGTABLE_FREE +static void kernel_pgtable_work_func(struct work_struct *work); + +static struct { + struct list_head list; + /* protect above ptdesc lists */ + spinlock_t lock; + struct work_struct work; +} kernel_pgtable_work = { + .list = LIST_HEAD_INIT(kernel_pgtable_work.list), + .lock = __SPIN_LOCK_UNLOCKED(kernel_pgtable_work.lock), + .work = __WORK_INITIALIZER(kernel_pgtable_work.work, kernel_pgtable_work_func), +}; + +static void kernel_pgtable_work_func(struct work_struct *work) +{ + struct ptdesc *pt, *next; + LIST_HEAD(page_list); + + spin_lock(&kernel_pgtable_work.lock); + list_splice_tail_init(&kernel_pgtable_work.list, &page_list); + spin_unlock(&kernel_pgtable_work.lock); + + list_for_each_entry_safe(pt, next, &page_list, pt_list) + __pagetable_free(pt); +} + +void pagetable_free_kernel(struct ptdesc *pt) +{ + spin_lock(&kernel_pgtable_work.lock); + list_add(&pt->pt_list, &kernel_pgtable_work.list); + spin_unlock(&kernel_pgtable_work.lock); + + schedule_work(&kernel_pgtable_work.work); +} +#endif From 9f0a7ab700f8620e433b05c57fbd26c92ea186d9 Mon Sep 17 00:00:00 2001 From: Lu Baolu Date: Wed, 22 Oct 2025 16:26:34 +0800 Subject: [PATCH 2148/2333] iommu/sva: invalidate stale IOTLB entries for kernel address space commit e37d5a2d60a338c5917c45296bac65da1382eda5 upstream. Introduce a new IOMMU interface to flush IOTLB paging cache entries for the CPU kernel address space. This interface is invoked from the x86 architecture code that manages combined user and kernel page tables, specifically before any kernel page table page is freed and reused. This addresses the main issue with vfree() which is a common occurrence and can be triggered by unprivileged users. While this resolves the primary problem, it doesn't address some extremely rare case related to memory unplug of memory that was present as reserved memory at boot, which cannot be triggered by unprivileged users. The discussion can be found at the link below. Enable SVA on x86 architecture since the IOMMU can now receive notification to flush the paging cache before freeing the CPU kernel page table pages. Link: https://lkml.kernel.org/r/20251022082635.2462433-9-baolu.lu@linux.intel.com Link: https://lore.kernel.org/linux-iommu/04983c62-3b1d-40d4-93ae-34ca04b827e5@intel.com/ Co-developed-by: Jason Gunthorpe Signed-off-by: Jason Gunthorpe Signed-off-by: Lu Baolu Suggested-by: Jann Horn Reviewed-by: Jason Gunthorpe Reviewed-by: Vasant Hegde Reviewed-by: Kevin Tian Cc: Alistair Popple Cc: Andy Lutomirski Cc: Borislav Betkov Cc: Dave Hansen Cc: David Hildenbrand Cc: Ingo Molnar Cc: Jean-Philippe Brucker Cc: Joerg Roedel Cc: Liam Howlett Cc: Lorenzo Stoakes Cc: Matthew Wilcox (Oracle) Cc: Michal Hocko Cc: Mike Rapoport (Microsoft) Cc: Peter Zijlstra Cc: Robin Murohy Cc: Thomas Gleinxer Cc: "Uladzislau Rezki (Sony)" Cc: Vinicius Costa Gomes Cc: Vlastimil Babka Cc: Will Deacon Cc: Yi Lai Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- arch/x86/Kconfig | 1 + drivers/iommu/iommu-sva.c | 32 ++++++++++++++++++++++++++++---- include/linux/iommu.h | 4 ++++ mm/pgtable-generic.c | 2 ++ 4 files changed, 35 insertions(+), 4 deletions(-) diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index fa3b616af03a2..a3700766a8c08 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -279,6 +279,7 @@ config X86 select HAVE_PCI select HAVE_PERF_REGS select HAVE_PERF_USER_STACK_DUMP + select ASYNC_KERNEL_PGTABLE_FREE if IOMMU_SVA select MMU_GATHER_RCU_TABLE_FREE select MMU_GATHER_MERGE_VMAS select HAVE_POSIX_CPU_TIMERS_TASK_WORK diff --git a/drivers/iommu/iommu-sva.c b/drivers/iommu/iommu-sva.c index a0442faad952c..d236aef80a8d5 100644 --- a/drivers/iommu/iommu-sva.c +++ b/drivers/iommu/iommu-sva.c @@ -10,6 +10,8 @@ #include "iommu-priv.h" static DEFINE_MUTEX(iommu_sva_lock); +static bool iommu_sva_present; +static LIST_HEAD(iommu_sva_mms); static struct iommu_domain *iommu_sva_domain_alloc(struct device *dev, struct mm_struct *mm); @@ -42,6 +44,7 @@ static struct iommu_mm_data *iommu_alloc_mm_data(struct mm_struct *mm, struct de return ERR_PTR(-ENOSPC); } iommu_mm->pasid = pasid; + iommu_mm->mm = mm; INIT_LIST_HEAD(&iommu_mm->sva_domains); /* * Make sure the write to mm->iommu_mm is not reordered in front of @@ -77,9 +80,6 @@ struct iommu_sva *iommu_sva_bind_device(struct device *dev, struct mm_struct *mm if (!group) return ERR_PTR(-ENODEV); - if (IS_ENABLED(CONFIG_X86)) - return ERR_PTR(-EOPNOTSUPP); - mutex_lock(&iommu_sva_lock); /* Allocate mm->pasid if necessary. */ @@ -135,8 +135,13 @@ struct iommu_sva *iommu_sva_bind_device(struct device *dev, struct mm_struct *mm if (ret) goto out_free_domain; domain->users = 1; - list_add(&domain->next, &mm->iommu_mm->sva_domains); + if (list_empty(&iommu_mm->sva_domains)) { + if (list_empty(&iommu_sva_mms)) + iommu_sva_present = true; + list_add(&iommu_mm->mm_list_elm, &iommu_sva_mms); + } + list_add(&domain->next, &iommu_mm->sva_domains); out: refcount_set(&handle->users, 1); mutex_unlock(&iommu_sva_lock); @@ -178,6 +183,13 @@ void iommu_sva_unbind_device(struct iommu_sva *handle) list_del(&domain->next); iommu_domain_free(domain); } + + if (list_empty(&iommu_mm->sva_domains)) { + list_del(&iommu_mm->mm_list_elm); + if (list_empty(&iommu_sva_mms)) + iommu_sva_present = false; + } + mutex_unlock(&iommu_sva_lock); kfree(handle); } @@ -315,3 +327,15 @@ static struct iommu_domain *iommu_sva_domain_alloc(struct device *dev, return domain; } + +void iommu_sva_invalidate_kva_range(unsigned long start, unsigned long end) +{ + struct iommu_mm_data *iommu_mm; + + guard(mutex)(&iommu_sva_lock); + if (!iommu_sva_present) + return; + + list_for_each_entry(iommu_mm, &iommu_sva_mms, mm_list_elm) + mmu_notifier_arch_invalidate_secondary_tlbs(iommu_mm->mm, start, end); +} diff --git a/include/linux/iommu.h b/include/linux/iommu.h index c30d12e16473d..66e4abb2df0dc 100644 --- a/include/linux/iommu.h +++ b/include/linux/iommu.h @@ -1134,7 +1134,9 @@ struct iommu_sva { struct iommu_mm_data { u32 pasid; + struct mm_struct *mm; struct list_head sva_domains; + struct list_head mm_list_elm; }; int iommu_fwspec_init(struct device *dev, struct fwnode_handle *iommu_fwnode); @@ -1615,6 +1617,7 @@ struct iommu_sva *iommu_sva_bind_device(struct device *dev, struct mm_struct *mm); void iommu_sva_unbind_device(struct iommu_sva *handle); u32 iommu_sva_get_pasid(struct iommu_sva *handle); +void iommu_sva_invalidate_kva_range(unsigned long start, unsigned long end); #else static inline struct iommu_sva * iommu_sva_bind_device(struct device *dev, struct mm_struct *mm) @@ -1639,6 +1642,7 @@ static inline u32 mm_get_enqcmd_pasid(struct mm_struct *mm) } static inline void mm_pasid_drop(struct mm_struct *mm) {} +static inline void iommu_sva_invalidate_kva_range(unsigned long start, unsigned long end) {} #endif /* CONFIG_IOMMU_SVA */ #ifdef CONFIG_IOMMU_IOPF diff --git a/mm/pgtable-generic.c b/mm/pgtable-generic.c index 1c7caa8ef164c..8c22be79b7343 100644 --- a/mm/pgtable-generic.c +++ b/mm/pgtable-generic.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -430,6 +431,7 @@ static void kernel_pgtable_work_func(struct work_struct *work) list_splice_tail_init(&kernel_pgtable_work.list, &page_list); spin_unlock(&kernel_pgtable_work.lock); + iommu_sva_invalidate_kva_range(PAGE_OFFSET, TLB_FLUSH_ALL); list_for_each_entry_safe(pt, next, &page_list, pt_list) __pagetable_free(pt); } From 3d72fadb764c47e37da7017ca52518bf283932e9 Mon Sep 17 00:00:00 2001 From: Zhang Lixu Date: Fri, 10 Oct 2025 13:52:54 +0800 Subject: [PATCH 2149/2333] HID: intel-ish-hid: Use dedicated unbound workqueues to prevent resume blocking commit 0d30dae38fe01cd1de358c6039a0b1184689fe51 upstream. During suspend/resume tests with S2IDLE, some ISH functional failures were observed because of delay in executing ISH resume handler. Here schedule_work() is used from resume handler to do actual work. schedule_work() uses system_wq, which is a per CPU work queue. Although the queuing is not bound to a CPU, but it prefers local CPU of the caller, unless prohibited. Users of this work queue are not supposed to queue long running work. But in practice, there are scenarios where long running work items are queued on other unbound workqueues, occupying the CPU. As a result, the ISH resume handler may not get a chance to execute in a timely manner. In one scenario, one of the ish_resume_handler() executions was delayed nearly 1 second because another work item on an unbound workqueue occupied the same CPU. This delay causes ISH functionality failures. A similar issue was previously observed where the ISH HID driver timed out while getting the HID descriptor during S4 resume in the recovery kernel, likely caused by the same workqueue contention problem. Create dedicated unbound workqueues for all ISH operations to allow work items to execute on any available CPU, eliminating CPU-specific bottlenecks and improving resume reliability under varying system loads. Also ISH has three different components, a bus driver which implements ISH protocols, a PCI interface layer and HID interface. Use one dedicated work queue for all of them. Signed-off-by: Zhang Lixu Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman --- drivers/hid/intel-ish-hid/ipc/ipc.c | 21 +++++++++++++++++++- drivers/hid/intel-ish-hid/ipc/pci-ish.c | 2 +- drivers/hid/intel-ish-hid/ishtp-hid-client.c | 4 ++-- drivers/hid/intel-ish-hid/ishtp/bus.c | 18 ++++++++++++++++- drivers/hid/intel-ish-hid/ishtp/hbm.c | 4 ++-- drivers/hid/intel-ish-hid/ishtp/ishtp-dev.h | 3 +++ include/linux/intel-ish-client-if.h | 2 ++ 7 files changed, 47 insertions(+), 7 deletions(-) diff --git a/drivers/hid/intel-ish-hid/ipc/ipc.c b/drivers/hid/intel-ish-hid/ipc/ipc.c index 3ddaa2cd39d55..9958f2968c4ff 100644 --- a/drivers/hid/intel-ish-hid/ipc/ipc.c +++ b/drivers/hid/intel-ish-hid/ipc/ipc.c @@ -628,7 +628,7 @@ static void recv_ipc(struct ishtp_device *dev, uint32_t doorbell_val) if (!ishtp_dev) { ishtp_dev = dev; } - schedule_work(&fw_reset_work); + queue_work(dev->unbound_wq, &fw_reset_work); break; case MNG_RESET_NOTIFY_ACK: @@ -933,6 +933,21 @@ static const struct ishtp_hw_ops ish_hw_ops = { .dma_no_cache_snooping = _dma_no_cache_snooping }; +static struct workqueue_struct *devm_ishtp_alloc_workqueue(struct device *dev) +{ + struct workqueue_struct *wq; + + wq = alloc_workqueue("ishtp_unbound_%d", WQ_UNBOUND, 0, dev->id); + if (!wq) + return NULL; + + if (devm_add_action_or_reset(dev, (void (*)(void *))destroy_workqueue, + wq)) + return NULL; + + return wq; +} + /** * ish_dev_init() -Initialize ISH devoce * @pdev: PCI device @@ -953,6 +968,10 @@ struct ishtp_device *ish_dev_init(struct pci_dev *pdev) if (!dev) return NULL; + dev->unbound_wq = devm_ishtp_alloc_workqueue(&pdev->dev); + if (!dev->unbound_wq) + return NULL; + dev->devc = &pdev->dev; ishtp_device_init(dev); diff --git a/drivers/hid/intel-ish-hid/ipc/pci-ish.c b/drivers/hid/intel-ish-hid/ipc/pci-ish.c index 9d150ce234f25..b748ac6fbfdc7 100644 --- a/drivers/hid/intel-ish-hid/ipc/pci-ish.c +++ b/drivers/hid/intel-ish-hid/ipc/pci-ish.c @@ -384,7 +384,7 @@ static int __maybe_unused ish_resume(struct device *device) ish_resume_device = device; dev->resume_flag = 1; - schedule_work(&resume_work); + queue_work(dev->unbound_wq, &resume_work); return 0; } diff --git a/drivers/hid/intel-ish-hid/ishtp-hid-client.c b/drivers/hid/intel-ish-hid/ishtp-hid-client.c index d8c3c54a8c0f2..f61add862b6b3 100644 --- a/drivers/hid/intel-ish-hid/ishtp-hid-client.c +++ b/drivers/hid/intel-ish-hid/ishtp-hid-client.c @@ -860,7 +860,7 @@ static int hid_ishtp_cl_reset(struct ishtp_cl_device *cl_device) hid_ishtp_trace(client_data, "%s hid_ishtp_cl %p\n", __func__, hid_ishtp_cl); - schedule_work(&client_data->work); + queue_work(ishtp_get_workqueue(cl_device), &client_data->work); return 0; } @@ -902,7 +902,7 @@ static int hid_ishtp_cl_resume(struct device *device) hid_ishtp_trace(client_data, "%s hid_ishtp_cl %p\n", __func__, hid_ishtp_cl); - schedule_work(&client_data->resume_work); + queue_work(ishtp_get_workqueue(cl_device), &client_data->resume_work); return 0; } diff --git a/drivers/hid/intel-ish-hid/ishtp/bus.c b/drivers/hid/intel-ish-hid/ishtp/bus.c index 93a0432e70581..c6ce37244e497 100644 --- a/drivers/hid/intel-ish-hid/ishtp/bus.c +++ b/drivers/hid/intel-ish-hid/ishtp/bus.c @@ -541,7 +541,7 @@ void ishtp_cl_bus_rx_event(struct ishtp_cl_device *device) return; if (device->event_cb) - schedule_work(&device->event_work); + queue_work(device->ishtp_dev->unbound_wq, &device->event_work); } /** @@ -876,6 +876,22 @@ struct device *ishtp_get_pci_device(struct ishtp_cl_device *device) } EXPORT_SYMBOL(ishtp_get_pci_device); +/** + * ishtp_get_workqueue - Retrieve the workqueue associated with an ISHTP device + * @cl_device: Pointer to the ISHTP client device structure + * + * Returns the workqueue_struct pointer (unbound_wq) associated with the given + * ISHTP client device. This workqueue is typically used for scheduling work + * related to the device. + * + * Return: Pointer to struct workqueue_struct. + */ +struct workqueue_struct *ishtp_get_workqueue(struct ishtp_cl_device *cl_device) +{ + return cl_device->ishtp_dev->unbound_wq; +} +EXPORT_SYMBOL(ishtp_get_workqueue); + /** * ishtp_trace_callback() - Return trace callback * @cl_device: ISH-TP client device instance diff --git a/drivers/hid/intel-ish-hid/ishtp/hbm.c b/drivers/hid/intel-ish-hid/ishtp/hbm.c index 8ee5467127d87..97c4fcd9e3c6f 100644 --- a/drivers/hid/intel-ish-hid/ishtp/hbm.c +++ b/drivers/hid/intel-ish-hid/ishtp/hbm.c @@ -573,7 +573,7 @@ void ishtp_hbm_dispatch(struct ishtp_device *dev, /* Start firmware loading process if it has loader capability */ if (version_res->host_version_supported & ISHTP_SUPPORT_CAP_LOADER) - schedule_work(&dev->work_fw_loader); + queue_work(dev->unbound_wq, &dev->work_fw_loader); dev->version.major_version = HBM_MAJOR_VERSION; dev->version.minor_version = HBM_MINOR_VERSION; @@ -864,7 +864,7 @@ void recv_hbm(struct ishtp_device *dev, struct ishtp_msg_hdr *ishtp_hdr) dev->rd_msg_fifo_tail = (dev->rd_msg_fifo_tail + IPC_PAYLOAD_SIZE) % (RD_INT_FIFO_SIZE * IPC_PAYLOAD_SIZE); spin_unlock_irqrestore(&dev->rd_msg_spinlock, flags); - schedule_work(&dev->bh_hbm_work); + queue_work(dev->unbound_wq, &dev->bh_hbm_work); eoi: return; } diff --git a/drivers/hid/intel-ish-hid/ishtp/ishtp-dev.h b/drivers/hid/intel-ish-hid/ishtp/ishtp-dev.h index 23db97ecf21cd..4b0596eadf1cc 100644 --- a/drivers/hid/intel-ish-hid/ishtp/ishtp-dev.h +++ b/drivers/hid/intel-ish-hid/ishtp/ishtp-dev.h @@ -175,6 +175,9 @@ struct ishtp_device { struct hbm_version version; int transfer_path; /* Choice of transfer path: IPC or DMA */ + /* Alloc a dedicated unbound workqueue for ishtp device */ + struct workqueue_struct *unbound_wq; + /* work structure for scheduling firmware loading tasks */ struct work_struct work_fw_loader; /* waitq for waiting for command response from the firmware loader */ diff --git a/include/linux/intel-ish-client-if.h b/include/linux/intel-ish-client-if.h index dfbf7d9d7bb5a..b235fd84f4780 100644 --- a/include/linux/intel-ish-client-if.h +++ b/include/linux/intel-ish-client-if.h @@ -87,6 +87,8 @@ bool ishtp_wait_resume(struct ishtp_device *dev); ishtp_print_log ishtp_trace_callback(struct ishtp_cl_device *cl_device); /* Get device pointer of PCI device for DMA acces */ struct device *ishtp_get_pci_device(struct ishtp_cl_device *cl_device); +/* Get the ISHTP workqueue */ +struct workqueue_struct *ishtp_get_workqueue(struct ishtp_cl_device *cl_device); struct ishtp_cl *ishtp_cl_allocate(struct ishtp_cl_device *cl_device); void ishtp_cl_free(struct ishtp_cl *cl); From 7e58addb8e05379e437e4722534a7cb1cabd767b Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Wed, 22 Oct 2025 00:49:08 +0200 Subject: [PATCH 2150/2333] HID: intel-ish-hid: Fix -Wcast-function-type-strict in devm_ishtp_alloc_workqueue() commit 3644f4411713f52bf231574aa8759e3d8e20b341 upstream. Clang warns (or errors with CONFIG_WERROR=y / W=e): drivers/hid/intel-ish-hid/ipc/ipc.c:935:36: error: cast from 'void (*)(struct workqueue_struct *)' to 'void (*)(void *)' converts to incompatible function type [-Werror,-Wcast-function-type-strict] 935 | if (devm_add_action_or_reset(dev, (void (*)(void *))destroy_workqueue, | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ include/linux/device/devres.h:168:34: note: expanded from macro 'devm_add_action_or_reset' 168 | __devm_add_action_or_ireset(dev, action, data, #action) | ^~~~~~ This warning is pointing out a kernel control flow integrity (kCFI / CONFIG_CFI=y) violation will occur due to this function cast when the destroy_workqueue() is indirectly called via devm_action_release() because the prototype of destroy_workqueue() does not match the prototype of (*action)(). Use a local function with the correct prototype to wrap destroy_workqueue() to resolve the warning and CFI violation. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202510190103.qTZvfdjj-lkp@intel.com/ Closes: https://github.com/ClangBuiltLinux/linux/issues/2139 Fixes: 0d30dae38fe0 ("HID: intel-ish-hid: Use dedicated unbound workqueues to prevent resume blocking") Signed-off-by: Nathan Chancellor Acked-by: Srinivas Pandruvada Reviewed-by: Zhang Lixu Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman --- drivers/hid/intel-ish-hid/ipc/ipc.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/hid/intel-ish-hid/ipc/ipc.c b/drivers/hid/intel-ish-hid/ipc/ipc.c index 9958f2968c4ff..3692d1db3bc76 100644 --- a/drivers/hid/intel-ish-hid/ipc/ipc.c +++ b/drivers/hid/intel-ish-hid/ipc/ipc.c @@ -933,6 +933,11 @@ static const struct ishtp_hw_ops ish_hw_ops = { .dma_no_cache_snooping = _dma_no_cache_snooping }; +static void ishtp_free_workqueue(void *wq) +{ + destroy_workqueue(wq); +} + static struct workqueue_struct *devm_ishtp_alloc_workqueue(struct device *dev) { struct workqueue_struct *wq; @@ -941,8 +946,7 @@ static struct workqueue_struct *devm_ishtp_alloc_workqueue(struct device *dev) if (!wq) return NULL; - if (devm_add_action_or_reset(dev, (void (*)(void *))destroy_workqueue, - wq)) + if (devm_add_action_or_reset(dev, ishtp_free_workqueue, wq)) return NULL; return wq; From 9ac63333d600732a56b35ee1fa46836da671eb50 Mon Sep 17 00:00:00 2001 From: Robbie Ko Date: Thu, 11 Dec 2025 13:30:33 +0800 Subject: [PATCH 2151/2333] btrfs: fix deadlock in wait_current_trans() due to ignored transaction type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 5037b342825df7094a4906d1e2a9674baab50cb2 upstream. When wait_current_trans() is called during start_transaction(), it currently waits for a blocked transaction without considering whether the given transaction type actually needs to wait for that particular transaction state. The btrfs_blocked_trans_types[] array already defines which transaction types should wait for which transaction states, but this check was missing in wait_current_trans(). This can lead to a deadlock scenario involving two transactions and pending ordered extents: 1. Transaction A is in TRANS_STATE_COMMIT_DOING state 2. A worker processing an ordered extent calls start_transaction() with TRANS_JOIN 3. join_transaction() returns -EBUSY because Transaction A is in TRANS_STATE_COMMIT_DOING 4. Transaction A moves to TRANS_STATE_UNBLOCKED and completes 5. A new Transaction B is created (TRANS_STATE_RUNNING) 6. The ordered extent from step 2 is added to Transaction B's pending ordered extents 7. Transaction B immediately starts commit by another task and enters TRANS_STATE_COMMIT_START 8. The worker finally reaches wait_current_trans(), sees Transaction B in TRANS_STATE_COMMIT_START (a blocked state), and waits unconditionally 9. However, TRANS_JOIN should NOT wait for TRANS_STATE_COMMIT_START according to btrfs_blocked_trans_types[] 10. Transaction B is waiting for pending ordered extents to complete 11. Deadlock: Transaction B waits for ordered extent, ordered extent waits for Transaction B This can be illustrated by the following call stacks: CPU0 CPU1 btrfs_finish_ordered_io() start_transaction(TRANS_JOIN) join_transaction() # -EBUSY (Transaction A is # TRANS_STATE_COMMIT_DOING) # Transaction A completes # Transaction B created # ordered extent added to # Transaction B's pending list btrfs_commit_transaction() # Transaction B enters # TRANS_STATE_COMMIT_START # waiting for pending ordered # extents wait_current_trans() # waits for Transaction B # (should not wait!) Task bstore_kv_sync in btrfs_commit_transaction waiting for ordered extents: __schedule+0x2e7/0x8a0 schedule+0x64/0xe0 btrfs_commit_transaction+0xbf7/0xda0 [btrfs] btrfs_sync_file+0x342/0x4d0 [btrfs] __x64_sys_fdatasync+0x4b/0x80 do_syscall_64+0x33/0x40 entry_SYSCALL_64_after_hwframe+0x44/0xa9 Task kworker in wait_current_trans waiting for transaction commit: Workqueue: btrfs-syno_nocow btrfs_work_helper [btrfs] __schedule+0x2e7/0x8a0 schedule+0x64/0xe0 wait_current_trans+0xb0/0x110 [btrfs] start_transaction+0x346/0x5b0 [btrfs] btrfs_finish_ordered_io.isra.0+0x49b/0x9c0 [btrfs] btrfs_work_helper+0xe8/0x350 [btrfs] process_one_work+0x1d3/0x3c0 worker_thread+0x4d/0x3e0 kthread+0x12d/0x150 ret_from_fork+0x1f/0x30 Fix this by passing the transaction type to wait_current_trans() and checking btrfs_blocked_trans_types[cur_trans->state] against the given type before deciding to wait. This ensures that transaction types which are allowed to join during certain blocked states will not unnecessarily wait and cause deadlocks. Reviewed-by: Filipe Manana Signed-off-by: Robbie Ko Signed-off-by: Filipe Manana Reviewed-by: David Sterba Signed-off-by: David Sterba Cc: Motiejus Jakštys Signed-off-by: Greg Kroah-Hartman --- fs/btrfs/transaction.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 89ae0c7a610aa..c457316c2788b 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c @@ -518,13 +518,14 @@ static inline int is_transaction_blocked(struct btrfs_transaction *trans) * when this is done, it is safe to start a new transaction, but the current * transaction might not be fully on disk. */ -static void wait_current_trans(struct btrfs_fs_info *fs_info) +static void wait_current_trans(struct btrfs_fs_info *fs_info, unsigned int type) { struct btrfs_transaction *cur_trans; spin_lock(&fs_info->trans_lock); cur_trans = fs_info->running_transaction; - if (cur_trans && is_transaction_blocked(cur_trans)) { + if (cur_trans && is_transaction_blocked(cur_trans) && + (btrfs_blocked_trans_types[cur_trans->state] & type)) { refcount_inc(&cur_trans->use_count); spin_unlock(&fs_info->trans_lock); @@ -699,12 +700,12 @@ start_transaction(struct btrfs_root *root, unsigned int num_items, sb_start_intwrite(fs_info->sb); if (may_wait_transaction(fs_info, type)) - wait_current_trans(fs_info); + wait_current_trans(fs_info, type); do { ret = join_transaction(fs_info, type); if (ret == -EBUSY) { - wait_current_trans(fs_info); + wait_current_trans(fs_info, type); if (unlikely(type == TRANS_ATTACH || type == TRANS_JOIN_NOSTART)) ret = -ENOENT; @@ -1001,7 +1002,7 @@ int btrfs_wait_for_commit(struct btrfs_fs_info *fs_info, u64 transid) void btrfs_throttle(struct btrfs_fs_info *fs_info) { - wait_current_trans(fs_info); + wait_current_trans(fs_info, TRANS_START); } bool btrfs_should_end_transaction(struct btrfs_trans_handle *trans) From 2a72a8ddf1888d56744ad7242be8f88d0c9df17b Mon Sep 17 00:00:00 2001 From: Joshua Hahn Date: Tue, 14 Oct 2025 07:50:08 -0700 Subject: [PATCH 2152/2333] mm/page_alloc/vmstat: simplify refresh_cpu_vm_stats change detection commit 0acc67c4030c39f39ac90413cc5d0abddd3a9527 upstream. Patch series "mm/page_alloc: Batch callers of free_pcppages_bulk", v5. Motivation & Approach ===================== While testing workloads with high sustained memory pressure on large machines in the Meta fleet (1Tb memory, 316 CPUs), we saw an unexpectedly high number of softlockups. Further investigation showed that the zone lock in free_pcppages_bulk was being held for a long time, and was called to free 2k+ pages over 100 times just during boot. This causes starvation in other processes for the zone lock, which can lead to the system stalling as multiple threads cannot make progress without the locks. We can see these issues manifesting as warnings: [ 4512.591979] rcu: INFO: rcu_sched self-detected stall on CPU [ 4512.604370] rcu: 20-....: (9312 ticks this GP) idle=a654/1/0x4000000000000000 softirq=309340/309344 fqs=5426 [ 4512.626401] rcu: hardirqs softirqs csw/system [ 4512.638793] rcu: number: 0 145 0 [ 4512.651177] rcu: cputime: 30 10410 174 ==> 10558(ms) [ 4512.666657] rcu: (t=21077 jiffies g=783665 q=1242213 ncpus=316) While these warnings don't indicate a crash or a kernel panic, they do point to the underlying issue of lock contention. To prevent starvation in both locks, batch the freeing of pages using pcp->batch. Because free_pcppages_bulk is called with the pcp lock and acquires the zone lock, relinquishing and reacquiring the locks are only effective when both of them are broken together (unless the system was built with queued spinlocks). Thus, instead of modifying free_pcppages_bulk to break both locks, batch the freeing from its callers instead. A similar fix has been implemented in the Meta fleet, and we have seen significantly less softlockups. Testing ======= The following are a few synthetic benchmarks, made on three machines. The first is a large machine with 754GiB memory and 316 processors. The second is a relatively smaller machine with 251GiB memory and 176 processors. The third and final is the smallest of the three, which has 62GiB memory and 36 processors. On all machines, I kick off a kernel build with -j$(nproc). Negative delta is better (faster compilation). Large machine (754GiB memory, 316 processors) make -j$(nproc) +------------+---------------+-----------+ | Metric (s) | Variation (%) | Delta(%) | +------------+---------------+-----------+ | real | 0.8070 | - 1.4865 | | user | 0.2823 | + 0.4081 | | sys | 5.0267 | -11.8737 | +------------+---------------+-----------+ Medium machine (251GiB memory, 176 processors) make -j$(nproc) +------------+---------------+----------+ | Metric (s) | Variation (%) | Delta(%) | +------------+---------------+----------+ | real | 0.2806 | +0.0351 | | user | 0.0994 | +0.3170 | | sys | 0.6229 | -0.6277 | +------------+---------------+----------+ Small machine (62GiB memory, 36 processors) make -j$(nproc) +------------+---------------+----------+ | Metric (s) | Variation (%) | Delta(%) | +------------+---------------+----------+ | real | 0.1503 | -2.6585 | | user | 0.0431 | -2.2984 | | sys | 0.1870 | -3.2013 | +------------+---------------+----------+ Here, variation is the coefficient of variation, i.e. standard deviation / mean. Based on these results, it seems like there are varying degrees to how much lock contention this reduces. For the largest and smallest machines that I ran the tests on, it seems like there is quite some significant reduction. There is also some performance increases visible from userspace. Interestingly, the performance gains don't scale with the size of the machine, but rather there seems to be a dip in the gain there is for the medium-sized machine. One possible theory is that because the high watermark depends on both memory and the number of local CPUs, what impacts zone contention the most is not these individual values, but rather the ratio of mem:processors. This patch (of 5): Currently, refresh_cpu_vm_stats returns an int, indicating how many changes were made during its updates. Using this information, callers like vmstat_update can heuristically determine if more work will be done in the future. However, all of refresh_cpu_vm_stats's callers either (a) ignore the result, only caring about performing the updates, or (b) only care about whether changes were made, but not *how many* changes were made. Simplify the code by returning a bool instead to indicate if updates were made. In addition, simplify fold_diff and decay_pcp_high to return a bool for the same reason. Link: https://lkml.kernel.org/r/20251014145011.3427205-1-joshua.hahnjy@gmail.com Link: https://lkml.kernel.org/r/20251014145011.3427205-2-joshua.hahnjy@gmail.com Signed-off-by: Joshua Hahn Reviewed-by: Vlastimil Babka Reviewed-by: SeongJae Park Cc: Brendan Jackman Cc: Chris Mason Cc: Johannes Weiner Cc: "Kirill A. Shutemov" Cc: Michal Hocko Cc: Suren Baghdasaryan Cc: Zi Yan Signed-off-by: Andrew Morton Stable-dep-of: 038a102535eb ("mm/page_alloc: prevent pcp corruption with SMP=n") Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- include/linux/gfp.h | 2 +- mm/page_alloc.c | 8 ++++---- mm/vmstat.c | 28 +++++++++++++++------------- 3 files changed, 20 insertions(+), 18 deletions(-) diff --git a/include/linux/gfp.h b/include/linux/gfp.h index 623bee335383e..b155929af5b11 100644 --- a/include/linux/gfp.h +++ b/include/linux/gfp.h @@ -387,7 +387,7 @@ extern void free_pages(unsigned long addr, unsigned int order); #define free_page(addr) free_pages((addr), 0) void page_alloc_init_cpuhp(void); -int decay_pcp_high(struct zone *zone, struct per_cpu_pages *pcp); +bool decay_pcp_high(struct zone *zone, struct per_cpu_pages *pcp); void drain_zone_pages(struct zone *zone, struct per_cpu_pages *pcp); void drain_all_pages(struct zone *zone); void drain_local_pages(struct zone *zone); diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 764b7aabaf69f..4db42673cd877 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -2552,10 +2552,10 @@ static int rmqueue_bulk(struct zone *zone, unsigned int order, * Called from the vmstat counter updater to decay the PCP high. * Return whether there are addition works to do. */ -int decay_pcp_high(struct zone *zone, struct per_cpu_pages *pcp) +bool decay_pcp_high(struct zone *zone, struct per_cpu_pages *pcp) { int high_min, to_drain, batch; - int todo = 0; + bool todo = false; high_min = READ_ONCE(pcp->high_min); batch = READ_ONCE(pcp->batch); @@ -2568,7 +2568,7 @@ int decay_pcp_high(struct zone *zone, struct per_cpu_pages *pcp) pcp->high = max3(pcp->count - (batch << CONFIG_PCP_BATCH_SCALE_MAX), pcp->high - (pcp->high >> 3), high_min); if (pcp->high > high_min) - todo++; + todo = true; } to_drain = pcp->count - pcp->high; @@ -2576,7 +2576,7 @@ int decay_pcp_high(struct zone *zone, struct per_cpu_pages *pcp) spin_lock(&pcp->lock); free_pcppages_bulk(zone, to_drain, pcp, 0); spin_unlock(&pcp->lock); - todo++; + todo = true; } return todo; diff --git a/mm/vmstat.c b/mm/vmstat.c index bb09c032eecfa..98855f31294dd 100644 --- a/mm/vmstat.c +++ b/mm/vmstat.c @@ -771,25 +771,25 @@ EXPORT_SYMBOL(dec_node_page_state); /* * Fold a differential into the global counters. - * Returns the number of counters updated. + * Returns whether counters were updated. */ static int fold_diff(int *zone_diff, int *node_diff) { int i; - int changes = 0; + bool changed = false; for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++) if (zone_diff[i]) { atomic_long_add(zone_diff[i], &vm_zone_stat[i]); - changes++; + changed = true; } for (i = 0; i < NR_VM_NODE_STAT_ITEMS; i++) if (node_diff[i]) { atomic_long_add(node_diff[i], &vm_node_stat[i]); - changes++; + changed = true; } - return changes; + return changed; } /* @@ -806,16 +806,16 @@ static int fold_diff(int *zone_diff, int *node_diff) * with the global counters. These could cause remote node cache line * bouncing and will have to be only done when necessary. * - * The function returns the number of global counters updated. + * The function returns whether global counters were updated. */ -static int refresh_cpu_vm_stats(bool do_pagesets) +static bool refresh_cpu_vm_stats(bool do_pagesets) { struct pglist_data *pgdat; struct zone *zone; int i; int global_zone_diff[NR_VM_ZONE_STAT_ITEMS] = { 0, }; int global_node_diff[NR_VM_NODE_STAT_ITEMS] = { 0, }; - int changes = 0; + bool changed = false; for_each_populated_zone(zone) { struct per_cpu_zonestat __percpu *pzstats = zone->per_cpu_zonestats; @@ -839,7 +839,8 @@ static int refresh_cpu_vm_stats(bool do_pagesets) if (do_pagesets) { cond_resched(); - changes += decay_pcp_high(zone, this_cpu_ptr(pcp)); + if (decay_pcp_high(zone, this_cpu_ptr(pcp))) + changed = true; #ifdef CONFIG_NUMA /* * Deal with draining the remote pageset of this @@ -861,13 +862,13 @@ static int refresh_cpu_vm_stats(bool do_pagesets) } if (__this_cpu_dec_return(pcp->expire)) { - changes++; + changed = true; continue; } if (__this_cpu_read(pcp->count)) { drain_zone_pages(zone, this_cpu_ptr(pcp)); - changes++; + changed = true; } #endif } @@ -887,8 +888,9 @@ static int refresh_cpu_vm_stats(bool do_pagesets) } } - changes += fold_diff(global_zone_diff, global_node_diff); - return changes; + if (fold_diff(global_zone_diff, global_node_diff)) + changed = true; + return changed; } /* From baea24956aea96546975f9fb55534abd04db5ad9 Mon Sep 17 00:00:00 2001 From: Joshua Hahn Date: Tue, 14 Oct 2025 07:50:09 -0700 Subject: [PATCH 2153/2333] mm/page_alloc: batch page freeing in decay_pcp_high commit fc4b909c368f3a7b08c895dd5926476b58e85312 upstream. It is possible for pcp->count - pcp->high to exceed pcp->batch by a lot. When this happens, we should perform batching to ensure that free_pcppages_bulk isn't called with too many pages to free at once and starve out other threads that need the pcp or zone lock. Since we are still only freeing the difference between the initial pcp->count and pcp->high values, there should be no change to how many pages are freed. Link: https://lkml.kernel.org/r/20251014145011.3427205-3-joshua.hahnjy@gmail.com Signed-off-by: Joshua Hahn Suggested-by: Chris Mason Suggested-by: Andrew Morton Co-developed-by: Johannes Weiner Reviewed-by: Vlastimil Babka Cc: Brendan Jackman Cc: "Kirill A. Shutemov" Cc: Michal Hocko Cc: SeongJae Park Cc: Suren Baghdasaryan Cc: Zi Yan Signed-off-by: Andrew Morton Stable-dep-of: 038a102535eb ("mm/page_alloc: prevent pcp corruption with SMP=n") Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- mm/page_alloc.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 4db42673cd877..33b881489727f 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -2554,7 +2554,7 @@ static int rmqueue_bulk(struct zone *zone, unsigned int order, */ bool decay_pcp_high(struct zone *zone, struct per_cpu_pages *pcp) { - int high_min, to_drain, batch; + int high_min, to_drain, to_drain_batched, batch; bool todo = false; high_min = READ_ONCE(pcp->high_min); @@ -2572,11 +2572,14 @@ bool decay_pcp_high(struct zone *zone, struct per_cpu_pages *pcp) } to_drain = pcp->count - pcp->high; - if (to_drain > 0) { + while (to_drain > 0) { + to_drain_batched = min(to_drain, batch); spin_lock(&pcp->lock); - free_pcppages_bulk(zone, to_drain, pcp, 0); + free_pcppages_bulk(zone, to_drain_batched, pcp, 0); spin_unlock(&pcp->lock); todo = true; + + to_drain -= to_drain_batched; } return todo; From 3098f8f7c7b0686c74827aec42a2c45e69801ff8 Mon Sep 17 00:00:00 2001 From: Vlastimil Babka Date: Mon, 5 Jan 2026 16:08:56 +0100 Subject: [PATCH 2154/2333] mm/page_alloc: prevent pcp corruption with SMP=n commit 038a102535eb49e10e93eafac54352fcc5d78847 upstream. The kernel test robot has reported: BUG: spinlock trylock failure on UP on CPU#0, kcompactd0/28 lock: 0xffff888807e35ef0, .magic: dead4ead, .owner: kcompactd0/28, .owner_cpu: 0 CPU: 0 UID: 0 PID: 28 Comm: kcompactd0 Not tainted 6.18.0-rc5-00127-ga06157804399 #1 PREEMPT 8cc09ef94dcec767faa911515ce9e609c45db470 Call Trace: __dump_stack (lib/dump_stack.c:95) dump_stack_lvl (lib/dump_stack.c:123) dump_stack (lib/dump_stack.c:130) spin_dump (kernel/locking/spinlock_debug.c:71) do_raw_spin_trylock (kernel/locking/spinlock_debug.c:?) _raw_spin_trylock (include/linux/spinlock_api_smp.h:89 kernel/locking/spinlock.c:138) __free_frozen_pages (mm/page_alloc.c:2973) ___free_pages (mm/page_alloc.c:5295) __free_pages (mm/page_alloc.c:5334) tlb_remove_table_rcu (include/linux/mm.h:? include/linux/mm.h:3122 include/asm-generic/tlb.h:220 mm/mmu_gather.c:227 mm/mmu_gather.c:290) ? __cfi_tlb_remove_table_rcu (mm/mmu_gather.c:289) ? rcu_core (kernel/rcu/tree.c:?) rcu_core (include/linux/rcupdate.h:341 kernel/rcu/tree.c:2607 kernel/rcu/tree.c:2861) rcu_core_si (kernel/rcu/tree.c:2879) handle_softirqs (arch/x86/include/asm/jump_label.h:36 include/trace/events/irq.h:142 kernel/softirq.c:623) __irq_exit_rcu (arch/x86/include/asm/jump_label.h:36 kernel/softirq.c:725) irq_exit_rcu (kernel/softirq.c:741) sysvec_apic_timer_interrupt (arch/x86/kernel/apic/apic.c:1052) RIP: 0010:_raw_spin_unlock_irqrestore (arch/x86/include/asm/preempt.h:95 include/linux/spinlock_api_smp.h:152 kernel/locking/spinlock.c:194) free_pcppages_bulk (mm/page_alloc.c:1494) drain_pages_zone (include/linux/spinlock.h:391 mm/page_alloc.c:2632) __drain_all_pages (mm/page_alloc.c:2731) drain_all_pages (mm/page_alloc.c:2747) kcompactd (mm/compaction.c:3115) kthread (kernel/kthread.c:465) ? __cfi_kcompactd (mm/compaction.c:3166) ? __cfi_kthread (kernel/kthread.c:412) ret_from_fork (arch/x86/kernel/process.c:164) ? __cfi_kthread (kernel/kthread.c:412) ret_from_fork_asm (arch/x86/entry/entry_64.S:255) Matthew has analyzed the report and identified that in drain_page_zone() we are in a section protected by spin_lock(&pcp->lock) and then get an interrupt that attempts spin_trylock() on the same lock. The code is designed to work this way without disabling IRQs and occasionally fail the trylock with a fallback. However, the SMP=n spinlock implementation assumes spin_trylock() will always succeed, and thus it's normally a no-op. Here the enabled lock debugging catches the problem, but otherwise it could cause a corruption of the pcp structure. The problem has been introduced by commit 574907741599 ("mm/page_alloc: leave IRQs enabled for per-cpu page allocations"). The pcp locking scheme recognizes the need for disabling IRQs to prevent nesting spin_trylock() sections on SMP=n, but the need to prevent the nesting in spin_lock() has not been recognized. Fix it by introducing local wrappers that change the spin_lock() to spin_lock_iqsave() with SMP=n and use them in all places that do spin_lock(&pcp->lock). [vbabka@suse.cz: add pcp_ prefix to the spin_lock_irqsave wrappers, per Steven] Link: https://lkml.kernel.org/r/20260105-fix-pcp-up-v1-1-5579662d2071@suse.cz Fixes: 574907741599 ("mm/page_alloc: leave IRQs enabled for per-cpu page allocations") Signed-off-by: Vlastimil Babka Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-lkp/202512101320.e2f2dd6f-lkp@intel.com Analyzed-by: Matthew Wilcox Link: https://lore.kernel.org/all/aUW05pyc9nZkvY-1@casper.infradead.org/ Acked-by: Mel Gorman Cc: Brendan Jackman Cc: Johannes Weiner Cc: Michal Hocko Cc: Sebastian Andrzej Siewior Cc: Steven Rostedt Cc: Suren Baghdasaryan Cc: Zi Yan Cc: Signed-off-by: Andrew Morton Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- mm/page_alloc.c | 47 +++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 39 insertions(+), 8 deletions(-) diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 33b881489727f..623f6e5b583ab 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -166,6 +166,33 @@ static DEFINE_MUTEX(pcp_batch_high_lock); #define pcp_spin_unlock(ptr) \ pcpu_spin_unlock(lock, ptr) +/* + * With the UP spinlock implementation, when we spin_lock(&pcp->lock) (for i.e. + * a potentially remote cpu drain) and get interrupted by an operation that + * attempts pcp_spin_trylock(), we can't rely on the trylock failure due to UP + * spinlock assumptions making the trylock a no-op. So we have to turn that + * spin_lock() to a spin_lock_irqsave(). This works because on UP there are no + * remote cpu's so we can only be locking the only existing local one. + */ +#if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT_RT) +static inline void __flags_noop(unsigned long *flags) { } +#define pcp_spin_lock_maybe_irqsave(ptr, flags) \ +({ \ + __flags_noop(&(flags)); \ + spin_lock(&(ptr)->lock); \ +}) +#define pcp_spin_unlock_maybe_irqrestore(ptr, flags) \ +({ \ + spin_unlock(&(ptr)->lock); \ + __flags_noop(&(flags)); \ +}) +#else +#define pcp_spin_lock_maybe_irqsave(ptr, flags) \ + spin_lock_irqsave(&(ptr)->lock, flags) +#define pcp_spin_unlock_maybe_irqrestore(ptr, flags) \ + spin_unlock_irqrestore(&(ptr)->lock, flags) +#endif + #ifdef CONFIG_USE_PERCPU_NUMA_NODE_ID DEFINE_PER_CPU(int, numa_node); EXPORT_PER_CPU_SYMBOL(numa_node); @@ -2555,6 +2582,7 @@ static int rmqueue_bulk(struct zone *zone, unsigned int order, bool decay_pcp_high(struct zone *zone, struct per_cpu_pages *pcp) { int high_min, to_drain, to_drain_batched, batch; + unsigned long UP_flags; bool todo = false; high_min = READ_ONCE(pcp->high_min); @@ -2574,9 +2602,9 @@ bool decay_pcp_high(struct zone *zone, struct per_cpu_pages *pcp) to_drain = pcp->count - pcp->high; while (to_drain > 0) { to_drain_batched = min(to_drain, batch); - spin_lock(&pcp->lock); + pcp_spin_lock_maybe_irqsave(pcp, UP_flags); free_pcppages_bulk(zone, to_drain_batched, pcp, 0); - spin_unlock(&pcp->lock); + pcp_spin_unlock_maybe_irqrestore(pcp, UP_flags); todo = true; to_drain -= to_drain_batched; @@ -2593,14 +2621,15 @@ bool decay_pcp_high(struct zone *zone, struct per_cpu_pages *pcp) */ void drain_zone_pages(struct zone *zone, struct per_cpu_pages *pcp) { + unsigned long UP_flags; int to_drain, batch; batch = READ_ONCE(pcp->batch); to_drain = min(pcp->count, batch); if (to_drain > 0) { - spin_lock(&pcp->lock); + pcp_spin_lock_maybe_irqsave(pcp, UP_flags); free_pcppages_bulk(zone, to_drain, pcp, 0); - spin_unlock(&pcp->lock); + pcp_spin_unlock_maybe_irqrestore(pcp, UP_flags); } } #endif @@ -2611,10 +2640,11 @@ void drain_zone_pages(struct zone *zone, struct per_cpu_pages *pcp) static void drain_pages_zone(unsigned int cpu, struct zone *zone) { struct per_cpu_pages *pcp = per_cpu_ptr(zone->per_cpu_pageset, cpu); + unsigned long UP_flags; int count; do { - spin_lock(&pcp->lock); + pcp_spin_lock_maybe_irqsave(pcp, UP_flags); count = pcp->count; if (count) { int to_drain = min(count, @@ -2623,7 +2653,7 @@ static void drain_pages_zone(unsigned int cpu, struct zone *zone) free_pcppages_bulk(zone, to_drain, pcp, 0); count -= to_drain; } - spin_unlock(&pcp->lock); + pcp_spin_unlock_maybe_irqrestore(pcp, UP_flags); } while (count); } @@ -6081,6 +6111,7 @@ static void zone_pcp_update_cacheinfo(struct zone *zone, unsigned int cpu) { struct per_cpu_pages *pcp; struct cpu_cacheinfo *cci; + unsigned long UP_flags; pcp = per_cpu_ptr(zone->per_cpu_pageset, cpu); cci = get_cpu_cacheinfo(cpu); @@ -6091,12 +6122,12 @@ static void zone_pcp_update_cacheinfo(struct zone *zone, unsigned int cpu) * This can reduce zone lock contention without hurting * cache-hot pages sharing. */ - spin_lock(&pcp->lock); + pcp_spin_lock_maybe_irqsave(pcp, UP_flags); if ((cci->per_cpu_data_slice_size >> PAGE_SHIFT) > 3 * pcp->batch) pcp->flags |= PCPF_FREE_HIGH_BATCH; else pcp->flags &= ~PCPF_FREE_HIGH_BATCH; - spin_unlock(&pcp->lock); + pcp_spin_unlock_maybe_irqrestore(pcp, UP_flags); } void setup_pcp_cacheinfo(unsigned int cpu) From 2d1bf4a7b8ed87ab32adaa40f53dfe332755451d Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 21 Jan 2026 18:21:16 +0100 Subject: [PATCH 2155/2333] Revert "functionfs: fix the open/removal races" This reverts commit b49c766856fb5901490de577e046149ebf15e39d which is commit e5bf5ee266633cb18fff6f98f0b7d59a62819eee upstream. It has been reported to cause test problems in Android devices. As the other functionfs changes were not also backported at the same time, something is out of sync. So just revert this one for now and it can come back in the future as a patch series if it is tested. Cc: Al Viro Cc: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/function/f_fs.c | 53 ++++++------------------------ 1 file changed, 10 insertions(+), 43 deletions(-) diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index 69f6e3c0f7e00..47cfbe41fdff8 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -640,22 +640,13 @@ static ssize_t ffs_ep0_read(struct file *file, char __user *buf, static int ffs_ep0_open(struct inode *inode, struct file *file) { - struct ffs_data *ffs = inode->i_sb->s_fs_info; - int ret; + struct ffs_data *ffs = inode->i_private; - /* Acquire mutex */ - ret = ffs_mutex_lock(&ffs->mutex, file->f_flags & O_NONBLOCK); - if (ret < 0) - return ret; - - ffs_data_opened(ffs); - if (ffs->state == FFS_CLOSING) { - ffs_data_closed(ffs); - mutex_unlock(&ffs->mutex); + if (ffs->state == FFS_CLOSING) return -EBUSY; - } - mutex_unlock(&ffs->mutex); + file->private_data = ffs; + ffs_data_opened(ffs); return stream_open(inode, file); } @@ -1202,33 +1193,14 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) static int ffs_epfile_open(struct inode *inode, struct file *file) { - struct ffs_data *ffs = inode->i_sb->s_fs_info; - struct ffs_epfile *epfile; - int ret; + struct ffs_epfile *epfile = inode->i_private; - /* Acquire mutex */ - ret = ffs_mutex_lock(&ffs->mutex, file->f_flags & O_NONBLOCK); - if (ret < 0) - return ret; - - if (!atomic_inc_not_zero(&ffs->opened)) { - mutex_unlock(&ffs->mutex); - return -ENODEV; - } - /* - * we want the state to be FFS_ACTIVE; FFS_ACTIVE alone is - * not enough, though - we might have been through FFS_CLOSING - * and back to FFS_ACTIVE, with our file already removed. - */ - epfile = smp_load_acquire(&inode->i_private); - if (unlikely(ffs->state != FFS_ACTIVE || !epfile)) { - mutex_unlock(&ffs->mutex); - ffs_data_closed(ffs); + if (WARN_ON(epfile->ffs->state != FFS_ACTIVE)) return -ENODEV; - } - mutex_unlock(&ffs->mutex); file->private_data = epfile; + ffs_data_opened(epfile->ffs); + return stream_open(inode, file); } @@ -1360,7 +1332,7 @@ static void ffs_dmabuf_put(struct dma_buf_attachment *attach) static int ffs_epfile_release(struct inode *inode, struct file *file) { - struct ffs_epfile *epfile = file->private_data; + struct ffs_epfile *epfile = inode->i_private; struct ffs_dmabuf_priv *priv, *tmp; struct ffs_data *ffs = epfile->ffs; @@ -2380,11 +2352,6 @@ static int ffs_epfiles_create(struct ffs_data *ffs) return 0; } -static void clear_one(struct dentry *dentry) -{ - smp_store_release(&dentry->d_inode->i_private, NULL); -} - static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count) { struct ffs_epfile *epfile = epfiles; @@ -2392,7 +2359,7 @@ static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count) for (; count; --count, ++epfile) { BUG_ON(mutex_is_locked(&epfile->mutex)); if (epfile->dentry) { - simple_recursive_removal(epfile->dentry, clear_one); + simple_recursive_removal(epfile->dentry, NULL); epfile->dentry = NULL; } } From d6a25e6ee3ec37a9bcba6ca00c4e7b397250acf7 Mon Sep 17 00:00:00 2001 From: Carlos Llamas Date: Mon, 5 Jan 2026 19:07:46 +0000 Subject: [PATCH 2156/2333] iommu/sva: include mmu_notifier.h header commit 4b5c493ff762bb0433529ca6870b284f0a2a5ca8 upstream. A call to mmu_notifier_arch_invalidate_secondary_tlbs() was introduced in commit e37d5a2d60a3 ("iommu/sva: invalidate stale IOTLB entries for kernel address space") but without explicitly adding its corresponding header file . This was evidenced while trying to enable compile testing support for IOMMU_SVA: config IOMMU_SVA select IOMMU_MM_DATA - bool + bool "Shared Virtual Addressing" if COMPILE_TEST The thing is for certain architectures this header file is indirectly included via . However, for others such as 32-bit arm the header is missing and it results in a build failure: $ make ARCH=arm allmodconfig [...] drivers/iommu/iommu-sva.c:340:3: error: call to undeclared function 'mmu_notifier_arch_invalidate_secondary_tlbs' [...] 340 | mmu_notifier_arch_invalidate_secondary_tlbs(iommu_mm->mm, start, end); | ^ Fix this by including the appropriate header file. Link: https://lkml.kernel.org/r/20260105190747.625082-1-cmllamas@google.com Fixes: e37d5a2d60a3 ("iommu/sva: invalidate stale IOTLB entries for kernel address space") Signed-off-by: Carlos Llamas Cc: Baolu Lu Cc: Jason Gunthorpe Cc: Joerg Roedel Cc: Kevin Tian Cc: Robin Murphy Cc: Vasant Hegde Cc: Will Deacon Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/iommu/iommu-sva.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/iommu/iommu-sva.c b/drivers/iommu/iommu-sva.c index d236aef80a8d5..e1e63c2be82b2 100644 --- a/drivers/iommu/iommu-sva.c +++ b/drivers/iommu/iommu-sva.c @@ -3,6 +3,7 @@ * Helpers for IOMMU drivers implementing SVA */ #include +#include #include #include #include From 5dfbc5357c34bdf81c84aa78bc8e3d6d9ba10aad Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 23 Jan 2026 11:21:37 +0100 Subject: [PATCH 2157/2333] Linux 6.18.7 Link: https://lore.kernel.org/r/20260121181418.537774329@linuxfoundation.org Tested-by: Salvatore Bonaccorso Tested-by: Ronald Warsow Tested-by: Shuah Khan Tested-by: Florian Fainelli Tested-by: Justin M. Forbes Tested-by: Takeshi Ogasawara Tested-by: Brett A C Sheffield Tested-by: Shung-Hsi Yu Tested-by: Jon Hunter Tested-by: Ron Economos Tested-by: Brett Mastbergen Tested-by: Peter Schneider Tested-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 23a575ce425cd..e3e3b82d94c01 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 VERSION = 6 PATCHLEVEL = 18 -SUBLEVEL = 6 +SUBLEVEL = 7 EXTRAVERSION = NAME = Baby Opossum Posse From 793e9547072be30721edb972421abcb396a7a998 Mon Sep 17 00:00:00 2001 From: Jie Gan Date: Fri, 23 Jan 2026 14:45:54 +0800 Subject: [PATCH 2158/2333] FROMLIST: arm64: dts: qcom: talos: add ETR device Add the TMC ETR device to store collected trace data in DDR memory. Link: https://lore.kernel.org/all/20260123-enable-etr-and-ctcu-devices-v1-1-5fbb3423a2d7@oss.qualcomm.com/ Signed-off-by: Jie Gan --- arch/arm64/boot/dts/qcom/talos.dtsi | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/talos.dtsi b/arch/arm64/boot/dts/qcom/talos.dtsi index 848dac5adc515..637f5783943f6 100644 --- a/arch/arm64/boot/dts/qcom/talos.dtsi +++ b/arch/arm64/boot/dts/qcom/talos.dtsi @@ -2385,6 +2385,14 @@ #address-cells = <1>; #size-cells = <0>; + port@0 { + reg = <0>; + + replicator0_out0: endpoint { + remote-endpoint = <&tmc_etr_in>; + }; + }; + port@1 { reg = <1>; @@ -2419,6 +2427,25 @@ }; }; + tmc_etr: tmc@6048000 { + compatible = "arm,coresight-tmc", "arm,primecell"; + reg = <0x0 0x06048000 0x0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + + iommus = <&apps_smmu 0x01e0 0x0>; + arm,scatter-gather; + + in-ports { + port { + tmc_etr_in: endpoint { + remote-endpoint = <&replicator0_out0>; + }; + }; + }; + }; + replicator@604a000 { compatible = "arm,coresight-dynamic-replicator", "arm,primecell"; reg = <0x0 0x0604a000 0x0 0x1000>; From 1b9b3f40f6b73a15d6b20cf5f83a6d4e16a873da Mon Sep 17 00:00:00 2001 From: Charan Teja Kalla Date: Tue, 9 Dec 2025 10:53:23 +0530 Subject: [PATCH 2159/2333] FROMGIT: iommu/arm-smmu-qcom: add actlr settings for mdss on Qualcomm platforms Add ACTLR settings for missing MDSS devices on Qualcomm platforms. These are QoS settings and are specific to per SoC thus different settings, eg: some have shallow prefetch while others have no prefetch. Aswell, this prefetch feature is not implemented for all the platforms, capturing to those are implemented to the best of my knowledge. Link: https://lore.kernel.org/all/20251209052323.1133495-1-bibek.patro@oss.qualcomm.com/ Reviewed-by: Dmitry Baryshkov Reviewed-by: Konrad Dybcio Signed-off-by: Charan Teja Kalla Signed-off-by: Bibek Kumar Patro --- drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c | 26 ++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c index 57c097e876130..c6645df97bbce 100644 --- a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c +++ b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c @@ -41,12 +41,38 @@ static const struct of_device_id qcom_smmu_actlr_client_of_match[] = { .data = (const void *) (PREFETCH_DEEP | CPRE | CMTLB) }, { .compatible = "qcom,fastrpc", .data = (const void *) (PREFETCH_DEEP | CPRE | CMTLB) }, + { .compatible = "qcom,qcm2290-mdss", + .data = (const void *) (PREFETCH_SHALLOW | CPRE | CMTLB) }, { .compatible = "qcom,sc7280-mdss", .data = (const void *) (PREFETCH_SHALLOW | CPRE | CMTLB) }, { .compatible = "qcom,sc7280-venus", .data = (const void *) (PREFETCH_SHALLOW | CPRE | CMTLB) }, + { .compatible = "qcom,sc8180x-mdss", + .data = (const void *) (PREFETCH_SHALLOW | CPRE | CMTLB) }, + { .compatible = "qcom,sc8280xp-mdss", + .data = (const void *) (PREFETCH_SHALLOW | CPRE | CMTLB) }, + { .compatible = "qcom,sm6115-mdss", + .data = (const void *) (PREFETCH_SHALLOW | CPRE | CMTLB) }, + { .compatible = "qcom,sm6125-mdss", + .data = (const void *) (PREFETCH_SHALLOW | CPRE | CMTLB) }, + { .compatible = "qcom,sm6350-mdss", + .data = (const void *) (PREFETCH_SHALLOW | CPRE | CMTLB) }, + { .compatible = "qcom,sm8150-mdss", + .data = (const void *) (PREFETCH_SHALLOW | CPRE | CMTLB) }, + { .compatible = "qcom,sm8250-mdss", + .data = (const void *) (PREFETCH_SHALLOW | CPRE | CMTLB) }, + { .compatible = "qcom,sm8350-mdss", + .data = (const void *) (PREFETCH_SHALLOW | CPRE | CMTLB) }, + { .compatible = "qcom,sm8450-mdss", + .data = (const void *) (PREFETCH_DEFAULT | CMTLB) }, { .compatible = "qcom,sm8550-mdss", .data = (const void *) (PREFETCH_DEFAULT | CMTLB) }, + { .compatible = "qcom,sm8650-mdss", + .data = (const void *) (PREFETCH_DEFAULT | CMTLB) }, + { .compatible = "qcom,sm8750-mdss", + .data = (const void *) (PREFETCH_DEFAULT | CMTLB) }, + { .compatible = "qcom,x1e80100-mdss", + .data = (const void *) (PREFETCH_DEFAULT | CMTLB) }, { } }; From 857833f9e5494579bbef5dd30001583edc67bc91 Mon Sep 17 00:00:00 2001 From: Bibek Kumar Patro Date: Sat, 10 Jan 2026 01:27:51 +0530 Subject: [PATCH 2160/2333] FROMLIST: iommu/arm-smmu-qcom: Restore ACTLR settings for MDSS on sa8775p The ACTLR configuration for the sa8775p MDSS client was inadvertently dropped while reworking the commit f91879fdf70b ("iommu/arm-smmu-qcom: Add actlr settings for mdss on Qualcomm platforms"). Without this entry, the sa8775p MDSS block does not receive the intended default ACTLR configuration. Restore the missing compatible entry so that the platform receives the expected behavior. Link: https://lore.kernel.org/all/20260120151105.614792-1-bibek.patro@oss.qualcomm.com/ Signed-off-by: Bibek Kumar Patro --- drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c index c6645df97bbce..7f2c30e6f659c 100644 --- a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c +++ b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c @@ -43,6 +43,8 @@ static const struct of_device_id qcom_smmu_actlr_client_of_match[] = { .data = (const void *) (PREFETCH_DEEP | CPRE | CMTLB) }, { .compatible = "qcom,qcm2290-mdss", .data = (const void *) (PREFETCH_SHALLOW | CPRE | CMTLB) }, + { .compatible = "qcom,sa8775p-mdss", + .data = (const void *) (PREFETCH_DEFAULT | CMTLB) }, { .compatible = "qcom,sc7280-mdss", .data = (const void *) (PREFETCH_SHALLOW | CPRE | CMTLB) }, { .compatible = "qcom,sc7280-venus", From e4ef07ad54d42fc17a03359848c7ed3d518e3151 Mon Sep 17 00:00:00 2001 From: Yuanjie Yang Date: Thu, 8 Jan 2026 17:25:41 +0800 Subject: [PATCH 2161/2333] FROMGIT: arm64: dts: qcom: talos: switch to interrupt-cells 4 to add PPI partitions The ARM PMUs shares the same per-cpu (PPI) interrupt, so we need to switch to interrupt-cells = <4> in the GIC node to allow adding an interrupt partition map phandle as the 4th cell value for GIC_PPI interrupts. Link: https://lore.kernel.org/all/20260108092542.1371-2-yuanjie.yang@oss.qualcomm.com/ Signed-off-by: Yuanjie Yang Reviewed-by: Konrad Dybcio --- arch/arm64/boot/dts/qcom/talos.dtsi | 308 ++++++++++++++-------------- 1 file changed, 154 insertions(+), 154 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/talos.dtsi b/arch/arm64/boot/dts/qcom/talos.dtsi index 848dac5adc515..bdca52af838b3 100644 --- a/arch/arm64/boot/dts/qcom/talos.dtsi +++ b/arch/arm64/boot/dts/qcom/talos.dtsi @@ -496,7 +496,7 @@ smp2p-adsp { compatible = "qcom,smp2p"; qcom,smem = <443>, <429>; - interrupts = ; + interrupts = ; /* On this platform, bit 26 (normally SLPI) is repurposed for ADSP */ mboxes = <&apss_shared 26>; @@ -518,7 +518,7 @@ smp2p-cdsp { compatible = "qcom,smp2p"; qcom,smem = <94>, <432>; - interrupts = ; + interrupts = ; mboxes = <&apss_shared 6>; qcom,local-pid = <0>; @@ -700,8 +700,8 @@ "cqhci", "ice"; - interrupts = , - ; + interrupts = , + ; interrupt-names = "hc_irq", "pwr_irq"; @@ -762,14 +762,14 @@ compatible = "qcom,qcs615-gpi-dma", "qcom,sdm845-gpi-dma"; reg = <0x0 0x800000 0x0 0x60000>; #dma-cells = <3>; - interrupts = , - , - , - , - , - , - , - ; + interrupts = , + , + , + , + , + , + , + ; dma-channels = <8>; dma-channel-mask = <0xf>; iommus = <&apps_smmu 0xd6 0x0>; @@ -796,7 +796,7 @@ clock-names = "se"; pinctrl-0 = <&qup_uart0_tx>, <&qup_uart0_rx>; pinctrl-names = "default"; - interrupts = ; + interrupts = ; interconnects = <&aggre1_noc MASTER_QUP_0 QCOM_ICC_TAG_ALWAYS &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>, <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS @@ -813,7 +813,7 @@ reg = <0x0 0x884000 0x0 0x4000>; #address-cells = <1>; #size-cells = <0>; - interrupts = ; + interrupts = ; clocks = <&gcc GCC_QUPV3_WRAP0_S1_CLK>; clock-names = "se"; pinctrl-0 = <&qup_i2c1_data_clk>; @@ -841,7 +841,7 @@ reg = <0x0 0x888000 0x0 0x4000>; #address-cells = <1>; #size-cells = <0>; - interrupts = ; + interrupts = ; clocks = <&gcc GCC_QUPV3_WRAP0_S2_CLK>; clock-names = "se"; pinctrl-0 = <&qup_i2c2_data_clk>; @@ -867,7 +867,7 @@ spi2: spi@888000 { compatible = "qcom,geni-spi"; reg = <0x0 0x00888000 0x0 0x4000>; - interrupts = ; + interrupts = ; clocks = <&gcc GCC_QUPV3_WRAP0_S2_CLK>; clock-names = "se"; pinctrl-0 = <&qup_spi2_data_clk>, <&qup_spi2_cs>; @@ -892,7 +892,7 @@ uart2: serial@888000 { compatible = "qcom,geni-uart"; reg = <0x0 0x00888000 0x0 0x4000>; - interrupts = ; + interrupts = ; clocks = <&gcc GCC_QUPV3_WRAP0_S2_CLK>; clock-names = "se"; pinctrl-0 = <&qup_uart2_cts>, <&qup_uart2_rts>, @@ -914,7 +914,7 @@ reg = <0x0 0x88c000 0x0 0x4000>; #address-cells = <1>; #size-cells = <0>; - interrupts = ; + interrupts = ; clocks = <&gcc GCC_QUPV3_WRAP0_S3_CLK>; clock-names = "se"; pinctrl-0 = <&qup_i2c3_data_clk>; @@ -942,14 +942,14 @@ compatible = "qcom,qcs615-gpi-dma", "qcom,sdm845-gpi-dma"; reg = <0x0 0xa00000 0x0 0x60000>; #dma-cells = <3>; - interrupts = , - , - , - , - , - , - , - ; + interrupts = , + , + , + , + , + , + , + ; dma-channels = <8>; dma-channel-mask = <0xf>; iommus = <&apps_smmu 0x376 0x0>; @@ -976,7 +976,7 @@ clock-names = "se"; pinctrl-0 = <&qup_i2c4_data_clk>; pinctrl-names = "default"; - interrupts = ; + interrupts = ; #address-cells = <1>; #size-cells = <0>; interconnects = <&aggre1_noc MASTER_BLSP_1 QCOM_ICC_TAG_ALWAYS @@ -1004,7 +1004,7 @@ clock-names = "se"; pinctrl-0 = <&qup_spi4_data_clk>, <&qup_spi4_cs>; pinctrl-names = "default"; - interrupts = ; + interrupts = ; #address-cells = <1>; #size-cells = <0>; interconnects = <&aggre1_noc MASTER_BLSP_1 QCOM_ICC_TAG_ALWAYS @@ -1030,7 +1030,7 @@ pinctrl-0 = <&qup_uart4_cts>, <&qup_uart4_rts>, <&qup_uart4_tx>, <&qup_uart4_rx>; pinctrl-names = "default"; - interrupts = ; + interrupts = ; interconnects = <&aggre1_noc MASTER_BLSP_1 QCOM_ICC_TAG_ALWAYS &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>, <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS @@ -1049,7 +1049,7 @@ clock-names = "se"; pinctrl-0 = <&qup_i2c5_data_clk>; pinctrl-names = "default"; - interrupts = ; + interrupts = ; #address-cells = <1>; #size-cells = <0>; interconnects = <&aggre1_noc MASTER_BLSP_1 QCOM_ICC_TAG_ALWAYS @@ -1077,7 +1077,7 @@ clock-names = "se"; pinctrl-0 = <&qup_i2c6_data_clk>; pinctrl-names = "default"; - interrupts = ; + interrupts = ; #address-cells = <1>; #size-cells = <0>; interconnects = <&aggre1_noc MASTER_BLSP_1 QCOM_ICC_TAG_ALWAYS @@ -1105,7 +1105,7 @@ clock-names = "se"; pinctrl-0 = <&qup_spi6_data_clk>, <&qup_spi6_cs>; pinctrl-names = "default"; - interrupts = ; + interrupts = ; #address-cells = <1>; #size-cells = <0>; interconnects = <&aggre1_noc MASTER_BLSP_1 QCOM_ICC_TAG_ALWAYS @@ -1131,7 +1131,7 @@ pinctrl-0 = <&qup_uart6_cts>, <&qup_uart6_rts>, <&qup_uart6_tx>, <&qup_uart6_rx>; pinctrl-names = "default"; - interrupts = ; + interrupts = ; interconnects = <&aggre1_noc MASTER_BLSP_1 QCOM_ICC_TAG_ALWAYS &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>, <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS @@ -1150,7 +1150,7 @@ clock-names = "se"; pinctrl-0 = <&qup_i2c7_data_clk>; pinctrl-names = "default"; - interrupts = ; + interrupts = ; #address-cells = <1>; #size-cells = <0>; interconnects = <&aggre1_noc MASTER_BLSP_1 QCOM_ICC_TAG_ALWAYS @@ -1178,7 +1178,7 @@ clock-names = "se"; pinctrl-0 = <&qup_spi7_data_clk>, <&qup_spi7_cs>; pinctrl-names = "default"; - interrupts = ; + interrupts = ; #address-cells = <1>; #size-cells = <0>; interconnects = <&aggre1_noc MASTER_BLSP_1 QCOM_ICC_TAG_ALWAYS @@ -1204,7 +1204,7 @@ pinctrl-0 = <&qup_uart7_cts>, <&qup_uart7_rts>, <&qup_uart7_tx>, <&qup_uart7_rx>; pinctrl-names = "default"; - interrupts = ; + interrupts = ; interconnects = <&aggre1_noc MASTER_BLSP_1 QCOM_ICC_TAG_ALWAYS &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>, <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS @@ -1271,15 +1271,15 @@ linux,pci-domain = <0>; num-lanes = <1>; - interrupts = , - , - , - , - , - , - , - , - ; + interrupts = , + , + , + , + , + , + , + , + ; interrupt-names = "msi0", "msi1", "msi2", @@ -1292,10 +1292,10 @@ #interrupt-cells = <1>; interrupt-map-mask = <0 0 0 0x7>; - interrupt-map = <0 0 0 1 &intc GIC_SPI 149 IRQ_TYPE_LEVEL_HIGH>, - <0 0 0 2 &intc GIC_SPI 150 IRQ_TYPE_LEVEL_HIGH>, - <0 0 0 3 &intc GIC_SPI 151 IRQ_TYPE_LEVEL_HIGH>, - <0 0 0 4 &intc GIC_SPI 152 IRQ_TYPE_LEVEL_HIGH>; + interrupt-map = <0 0 0 1 &intc GIC_SPI 149 IRQ_TYPE_LEVEL_HIGH 0>, + <0 0 0 2 &intc GIC_SPI 150 IRQ_TYPE_LEVEL_HIGH 0>, + <0 0 0 3 &intc GIC_SPI 151 IRQ_TYPE_LEVEL_HIGH 0>, + <0 0 0 4 &intc GIC_SPI 152 IRQ_TYPE_LEVEL_HIGH 0>; clocks = <&gcc GCC_PCIE_0_PIPE_CLK>, <&gcc GCC_PCIE_0_AUX_CLK>, @@ -1399,7 +1399,7 @@ reg-names = "std", "ice"; - interrupts = ; + interrupts = ; clocks = <&gcc GCC_UFS_PHY_AXI_CLK>, <&gcc GCC_AGGRE_UFS_PHY_AXI_CLK>, @@ -1508,7 +1508,7 @@ cryptobam: dma-controller@1dc4000 { compatible = "qcom,bam-v1.7.4", "qcom,bam-v1.7.0"; reg = <0x0 0x01dc4000 0x0 0x24000>; - interrupts = ; + interrupts = ; #dma-cells = <1>; qcom,ee = <0>; qcom,controlled-remotely; @@ -1547,7 +1547,7 @@ reg-names = "east", "west", "south"; - interrupts = ; + interrupts = ; gpio-ranges = <&tlmm 0 0 124>; gpio-controller; #gpio-cells = <2>; @@ -3604,7 +3604,7 @@ compatible = "qcom,qcs615-cdsp-pas", "qcom,sm8150-cdsp-pas"; reg = <0x0 0x08300000 0x0 0x4040>; - interrupts-extended = <&intc GIC_SPI 578 IRQ_TYPE_EDGE_RISING>, + interrupts-extended = <&intc GIC_SPI 578 IRQ_TYPE_EDGE_RISING 0>, <&cdsp_smp2p_in 0 IRQ_TYPE_EDGE_RISING>, <&cdsp_smp2p_in 1 IRQ_TYPE_EDGE_RISING>, <&cdsp_smp2p_in 2 IRQ_TYPE_EDGE_RISING>, @@ -3631,7 +3631,7 @@ status = "disabled"; glink-edge { - interrupts = ; + interrupts = ; mboxes = <&apss_shared 4>; label = "cdsp"; qcom,remote-pid = <5>; @@ -3699,7 +3699,7 @@ pmu@90b6300 { compatible = "qcom,qcs615-cpu-bwmon", "qcom,sdm845-bwmon"; reg = <0x0 0x090b6300 0x0 0x600>; - interrupts = ; + interrupts = ; interconnects = <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ACTIVE_ONLY &gem_noc SLAVE_LLCC QCOM_ICC_TAG_ACTIVE_ONLY>; @@ -3721,7 +3721,7 @@ pmu@90cd000 { compatible = "qcom,qcs615-llcc-bwmon", "qcom,sc7280-llcc-bwmon"; reg = <0x0 0x090cd000 0x0 0x1000>; - interrupts = ; + interrupts = ; interconnects = <&mc_virt MASTER_LLCC QCOM_ICC_TAG_ACTIVE_ONLY &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ACTIVE_ONLY>; @@ -3773,8 +3773,8 @@ reg = <0x0 0x08804000 0x0 0x1000>; reg-names = "hc"; - interrupts = , - ; + interrupts = , + ; interrupt-names = "hc_irq", "pwr_irq"; @@ -3847,7 +3847,7 @@ venus: video-codec@aa00000 { compatible = "qcom,qcs615-venus", "qcom,sc7180-venus"; reg = <0x0 0x0aa00000 0x0 0x100000>; - interrupts = ; + interrupts = ; clocks = <&videocc VIDEO_CC_VENUS_CTL_CORE_CLK>, <&videocc VIDEO_CC_VENUS_AHB_CLK>, @@ -3958,7 +3958,7 @@ <&gcc GCC_DISP_HF_AXI_CLK>, <&dispcc DISP_CC_MDSS_MDP_CLK>; - interrupts = ; + interrupts = ; interrupt-controller; #interrupt-cells = <1>; @@ -4231,7 +4231,7 @@ aoss_qmp: power-management@c300000 { compatible = "qcom,qcs615-aoss-qmp", "qcom,aoss-qmp"; reg = <0x0 0x0c300000 0x0 0x400>; - interrupts = ; + interrupts = ; mboxes = <&apss_shared 0>; #clock-cells = <0>; @@ -4263,71 +4263,71 @@ #global-interrupts = <1>; dma-coherent; - interrupts = , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - ; + interrupts = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; }; spmi_bus: spmi@c440000 { @@ -4356,9 +4356,9 @@ compatible = "arm,gic-v3"; reg = <0x0 0x17a00000 0x0 0x10000>, /* GICD */ <0x0 0x17a60000 0x0 0x100000>; /* GICR * 8 */ - interrupts = ; + interrupts = ; #address-cells = <0>; - #interrupt-cells = <3>; + #interrupt-cells = <4>; interrupt-controller; #redistributor-regions = <1>; redistributor-stride = <0x0 0x20000>; @@ -4374,7 +4374,7 @@ watchdog: watchdog@17c10000 { compatible = "qcom,apss-wdt-qcs615", "qcom,kpss-wdt"; reg = <0x0 0x17c10000 0x0 0x1000>; - interrupts = ; + interrupts = ; clocks = <&sleep_clk>; }; @@ -4389,49 +4389,49 @@ reg = <0x17c21000 0x1000>, <0x17c22000 0x1000>; frame-number = <0>; - interrupts = , - ; + interrupts = , + ; }; frame@17c23000 { reg = <0x17c23000 0x1000>; frame-number = <1>; - interrupts = ; + interrupts = ; status = "disabled"; }; frame@17c25000 { reg = <0x17c25000 0x1000>; frame-number = <2>; - interrupts = ; + interrupts = ; status = "disabled"; }; frame@17c27000 { reg = <0x17c27000 0x1000>; frame-number = <3>; - interrupts = ; + interrupts = ; status = "disabled"; }; frame@17c29000 { reg = <0x17c29000 0x1000>; frame-number = <4>; - interrupts = ; + interrupts = ; status = "disabled"; }; frame@17c2b000 { reg = <0x17c2b000 0x1000>; frame-number = <5>; - interrupts = ; + interrupts = ; status = "disabled"; }; frame@17c2d000 { reg = <0x17c2d000 0x1000>; frame-number = <6>; - interrupts = ; + interrupts = ; status = "disabled"; }; }; @@ -4445,9 +4445,9 @@ "drv-1", "drv-2"; - interrupts = , - , - ; + interrupts = , + , + ; qcom,drv-id = <2>; qcom,tcs-offset = <0xd00>; @@ -4637,8 +4637,8 @@ <&gcc GCC_USB30_PRIM_MASTER_CLK>; assigned-clock-rates = <19200000>, <200000000>; - interrupts-extended = <&intc GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>, - <&intc GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>, + interrupts-extended = <&intc GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH 0>, + <&intc GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH 0>, <&pdc 9 IRQ_TYPE_EDGE_BOTH>, <&pdc 8 IRQ_TYPE_EDGE_BOTH>, <&pdc 6 IRQ_TYPE_LEVEL_HIGH>; @@ -4664,7 +4664,7 @@ reg = <0x0 0x0a600000 0x0 0xcd00>; iommus = <&apps_smmu 0x140 0x0>; - interrupts = ; + interrupts = ; phys = <&usb_hsphy_1>, <&usb_qmpphy>; phy-names = "usb2-phy", "usb3-phy"; @@ -4701,8 +4701,8 @@ <&gcc GCC_USB20_SEC_MASTER_CLK>; assigned-clock-rates = <19200000>, <200000000>; - interrupts-extended = <&intc GIC_SPI 663 IRQ_TYPE_LEVEL_HIGH>, - <&intc GIC_SPI 662 IRQ_TYPE_LEVEL_HIGH>, + interrupts-extended = <&intc GIC_SPI 663 IRQ_TYPE_LEVEL_HIGH 0>, + <&intc GIC_SPI 662 IRQ_TYPE_LEVEL_HIGH 0>, <&pdc 11 IRQ_TYPE_EDGE_BOTH>, <&pdc 10 IRQ_TYPE_EDGE_BOTH>; interrupt-names = "pwr_event", @@ -4728,7 +4728,7 @@ reg = <0x0 0x0a800000 0x0 0xcd00>; iommus = <&apps_smmu 0xe0 0x0>; - interrupts = ; + interrupts = ; phys = <&usb_hsphy_2>; phy-names = "usb2-phy"; @@ -4747,8 +4747,8 @@ compatible = "qcom,qcs615-tsens", "qcom,tsens-v2"; reg = <0x0 0x0c263000 0x0 0x1000>, <0x0 0x0c222000 0x0 0x1000>; - interrupts = , - ; + interrupts = , + ; interrupt-names = "uplow", "critical"; #qcom,sensors = <16>; #thermal-sensor-cells = <1>; @@ -4758,7 +4758,7 @@ compatible = "qcom,qcs615-adsp-pas", "qcom,sm8150-adsp-pas"; reg = <0x0 0x62400000 0x0 0x4040>; - interrupts-extended = <&intc GIC_SPI 162 IRQ_TYPE_EDGE_RISING>, + interrupts-extended = <&intc GIC_SPI 162 IRQ_TYPE_EDGE_RISING 0>, <&adsp_smp2p_in 0 IRQ_TYPE_EDGE_RISING>, <&adsp_smp2p_in 1 IRQ_TYPE_EDGE_RISING>, <&adsp_smp2p_in 2 IRQ_TYPE_EDGE_RISING>, @@ -4785,7 +4785,7 @@ status = "disabled"; glink_edge: glink-edge { - interrupts = ; + interrupts = ; mboxes = <&apss_shared 24>; label = "lpass"; qcom,remote-pid = <2>; @@ -4844,10 +4844,10 @@ arch_timer: timer { compatible = "arm,armv8-timer"; - interrupts = , - , - , - ; + interrupts = , + , + , + ; }; thermal-zones { From 2728f2dd5be7f1e93e20305c249a938f5e9c8ada Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy Date: Fri, 17 Oct 2025 06:11:28 +0300 Subject: [PATCH 2162/2333] UPSTREAM: dt-bindings: media: Describe Qualcomm SM8650 CAMSS IP Add device tree bindings for Qualcomm SM8650 camera subsystem. Qualcomm SM8650 CAMSS IP contains the next subdevices: * 6 x CSIPHY, * 3 x CSID, 2 x CSID Lite, * 3 x IFE, 2 x IFE Lite. Link: https://lore.kernel.org/linux-media/20251017031131.2232687-2-vladimir.zapolskiy@linaro.org/ Signed-off-by: Vladimir Zapolskiy Reviewed-by: Bryan O'Donoghue Reviewed-by: Krzysztof Kozlowski Tested-by: Neil Armstrong # on SM8650-QRD --- .../bindings/media/qcom,sm8650-camss.yaml | 375 ++++++++++++++++++ 1 file changed, 375 insertions(+) create mode 100644 Documentation/devicetree/bindings/media/qcom,sm8650-camss.yaml diff --git a/Documentation/devicetree/bindings/media/qcom,sm8650-camss.yaml b/Documentation/devicetree/bindings/media/qcom,sm8650-camss.yaml new file mode 100644 index 0000000000000..9c8de722601ec --- /dev/null +++ b/Documentation/devicetree/bindings/media/qcom,sm8650-camss.yaml @@ -0,0 +1,375 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/qcom,sm8650-camss.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm SM8650 Camera Subsystem (CAMSS) + +maintainers: + - Vladimir Zapolskiy + +description: + The CAMSS IP is a CSI decoder and ISP present on Qualcomm platforms. + +properties: + compatible: + const: qcom,sm8650-camss + + reg: + maxItems: 17 + + reg-names: + items: + - const: csid_wrapper + - const: csid0 + - const: csid1 + - const: csid2 + - const: csid_lite0 + - const: csid_lite1 + - const: csiphy0 + - const: csiphy1 + - const: csiphy2 + - const: csiphy3 + - const: csiphy4 + - const: csiphy5 + - const: vfe0 + - const: vfe1 + - const: vfe2 + - const: vfe_lite0 + - const: vfe_lite1 + + clocks: + maxItems: 33 + + clock-names: + items: + - const: camnoc_axi + - const: cpas_ahb + - const: cpas_fast_ahb + - const: cpas_vfe0 + - const: cpas_vfe1 + - const: cpas_vfe2 + - const: cpas_vfe_lite + - const: csid + - const: csiphy0 + - const: csiphy0_timer + - const: csiphy1 + - const: csiphy1_timer + - const: csiphy2 + - const: csiphy2_timer + - const: csiphy3 + - const: csiphy3_timer + - const: csiphy4 + - const: csiphy4_timer + - const: csiphy5 + - const: csiphy5_timer + - const: csiphy_rx + - const: gcc_axi_hf + - const: qdss_debug_xo + - const: vfe0 + - const: vfe0_fast_ahb + - const: vfe1 + - const: vfe1_fast_ahb + - const: vfe2 + - const: vfe2_fast_ahb + - const: vfe_lite + - const: vfe_lite_ahb + - const: vfe_lite_cphy_rx + - const: vfe_lite_csid + + interrupts: + maxItems: 16 + + interrupt-names: + items: + - const: csid0 + - const: csid1 + - const: csid2 + - const: csid_lite0 + - const: csid_lite1 + - const: csiphy0 + - const: csiphy1 + - const: csiphy2 + - const: csiphy3 + - const: csiphy4 + - const: csiphy5 + - const: vfe0 + - const: vfe1 + - const: vfe2 + - const: vfe_lite0 + - const: vfe_lite1 + + interconnects: + maxItems: 2 + + interconnect-names: + items: + - const: ahb + - const: hf_mnoc + + iommus: + maxItems: 3 + + power-domains: + items: + - description: IFE0 GDSC - Image Front End, Global Distributed Switch Controller. + - description: IFE1 GDSC - Image Front End, Global Distributed Switch Controller. + - description: IFE2 GDSC - Image Front End, Global Distributed Switch Controller. + - description: Titan GDSC - Titan ISP Block, Global Distributed Switch Controller. + + power-domain-names: + items: + - const: ife0 + - const: ife1 + - const: ife2 + - const: top + + ports: + $ref: /schemas/graph.yaml#/properties/ports + + description: + CSI input ports. + + patternProperties: + "^port@[0-5]$": + $ref: /schemas/graph.yaml#/$defs/port-base + unevaluatedProperties: false + + description: + Input port for receiving CSI data from a CSIPHY. + + properties: + endpoint: + $ref: video-interfaces.yaml# + unevaluatedProperties: false + + properties: + data-lanes: + minItems: 1 + maxItems: 4 + + bus-type: + enum: + - 1 # MEDIA_BUS_TYPE_CSI2_CPHY + - 4 # MEDIA_BUS_TYPE_CSI2_DPHY + + required: + - data-lanes + + vdd-csiphy01-0p9-supply: + description: + Phandle to a 0.9V regulator supply to CSIPHY0 and CSIPHY1 IP blocks. + + vdd-csiphy01-1p2-supply: + description: + Phandle to a 1.2V regulator supply to CSIPHY0 and CSIPHY1 IP blocks. + + vdd-csiphy24-0p9-supply: + description: + Phandle to a 0.9V regulator supply to CSIPHY2 and CSIPHY4 IP blocks. + + vdd-csiphy24-1p2-supply: + description: + Phandle to a 1.2V regulator supply to CSIPHY2 and CSIPHY4 IP blocks. + + vdd-csiphy35-0p9-supply: + description: + Phandle to a 0.9V regulator supply to CSIPHY3 and CSIPHY5 IP blocks. + + vdd-csiphy35-1p2-supply: + description: + Phandle to a 1.2V regulator supply to CSIPHY3 and CSIPHY5 IP blocks. + +required: + - compatible + - reg + - reg-names + - clocks + - clock-names + - interconnects + - interconnect-names + - interrupts + - interrupt-names + - iommus + - power-domains + - power-domain-names + +additionalProperties: false + +examples: + - | + #include + #include + #include + #include + + soc { + #address-cells = <2>; + #size-cells = <2>; + + isp@acb6000 { + compatible = "qcom,sm8650-camss"; + reg = <0 0x0acb6000 0 0x1000>, + <0 0x0acb8000 0 0x1000>, + <0 0x0acba000 0 0x1000>, + <0 0x0acbc000 0 0x1000>, + <0 0x0accb000 0 0x1000>, + <0 0x0acd0000 0 0x1000>, + <0 0x0ace4000 0 0x2000>, + <0 0x0ace6000 0 0x2000>, + <0 0x0ace8000 0 0x2000>, + <0 0x0acea000 0 0x2000>, + <0 0x0acec000 0 0x2000>, + <0 0x0acee000 0 0x2000>, + <0 0x0ac62000 0 0xf000>, + <0 0x0ac71000 0 0xf000>, + <0 0x0ac80000 0 0xf000>, + <0 0x0accc000 0 0x2000>, + <0 0x0acd1000 0 0x2000>; + reg-names = "csid_wrapper", + "csid0", + "csid1", + "csid2", + "csid_lite0", + "csid_lite1", + "csiphy0", + "csiphy1", + "csiphy2", + "csiphy3", + "csiphy4", + "csiphy5", + "vfe0", + "vfe1", + "vfe2", + "vfe_lite0", + "vfe_lite1"; + clocks = <&camcc CAM_CC_CAMNOC_AXI_RT_CLK>, + <&camcc CAM_CC_CPAS_AHB_CLK>, + <&camcc CAM_CC_CPAS_FAST_AHB_CLK>, + <&camcc CAM_CC_CPAS_IFE_0_CLK>, + <&camcc CAM_CC_CPAS_IFE_1_CLK>, + <&camcc CAM_CC_CPAS_IFE_2_CLK>, + <&camcc CAM_CC_CPAS_IFE_LITE_CLK>, + <&camcc CAM_CC_CSID_CLK>, + <&camcc CAM_CC_CSIPHY0_CLK>, + <&camcc CAM_CC_CSI0PHYTIMER_CLK>, + <&camcc CAM_CC_CSI1PHYTIMER_CLK>, + <&camcc CAM_CC_CSIPHY1_CLK>, + <&camcc CAM_CC_CSI2PHYTIMER_CLK>, + <&camcc CAM_CC_CSIPHY2_CLK>, + <&camcc CAM_CC_CSI3PHYTIMER_CLK>, + <&camcc CAM_CC_CSIPHY3_CLK>, + <&camcc CAM_CC_CSI4PHYTIMER_CLK>, + <&camcc CAM_CC_CSIPHY4_CLK>, + <&camcc CAM_CC_CSI5PHYTIMER_CLK>, + <&camcc CAM_CC_CSIPHY5_CLK>, + <&camcc CAM_CC_CSID_CSIPHY_RX_CLK>, + <&gcc GCC_CAMERA_HF_AXI_CLK>, + <&camcc CAM_CC_QDSS_DEBUG_XO_CLK>, + <&camcc CAM_CC_IFE_0_CLK>, + <&camcc CAM_CC_IFE_0_FAST_AHB_CLK>, + <&camcc CAM_CC_IFE_1_CLK>, + <&camcc CAM_CC_IFE_1_FAST_AHB_CLK>, + <&camcc CAM_CC_IFE_2_CLK>, + <&camcc CAM_CC_IFE_2_FAST_AHB_CLK>, + <&camcc CAM_CC_IFE_LITE_CLK>, + <&camcc CAM_CC_IFE_LITE_AHB_CLK>, + <&camcc CAM_CC_IFE_LITE_CPHY_RX_CLK>, + <&camcc CAM_CC_IFE_LITE_CSID_CLK>; + clock-names = "camnoc_axi", + "cpas_ahb", + "cpas_fast_ahb", + "cpas_vfe0", + "cpas_vfe1", + "cpas_vfe2", + "cpas_vfe_lite", + "csid", + "csiphy0", + "csiphy0_timer", + "csiphy1", + "csiphy1_timer", + "csiphy2", + "csiphy2_timer", + "csiphy3", + "csiphy3_timer", + "csiphy4", + "csiphy4_timer", + "csiphy5", + "csiphy5_timer", + "csiphy_rx", + "gcc_axi_hf", + "qdss_debug_xo", + "vfe0", + "vfe0_fast_ahb", + "vfe1", + "vfe1_fast_ahb", + "vfe2", + "vfe2_fast_ahb", + "vfe_lite", + "vfe_lite_ahb", + "vfe_lite_cphy_rx", + "vfe_lite_csid"; + interrupts = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + interrupt-names = "csid0", + "csid1", + "csid2", + "csid_lite0", + "csid_lite1", + "csiphy0", + "csiphy1", + "csiphy2", + "csiphy3", + "csiphy4", + "csiphy5", + "vfe0", + "vfe1", + "vfe2", + "vfe_lite0", + "vfe_lite1"; + interconnects = <&gem_noc MASTER_APPSS_PROC 0 + &config_noc SLAVE_CAMERA_CFG 0>, + <&mmss_noc MASTER_CAMNOC_HF 0 + &mc_virt SLAVE_EBI1 0>; + interconnect-names = "ahb", "hf_mnoc"; + iommus = <&apps_smmu 0x800 0x20>, + <&apps_smmu 0x18a0 0x40>, + <&apps_smmu 0x1860 0x00>; + power-domains = <&camcc CAM_CC_IFE_0_GDSC>, + <&camcc CAM_CC_IFE_1_GDSC>, + <&camcc CAM_CC_IFE_2_GDSC>, + <&camcc CAM_CC_TITAN_TOP_GDSC>; + power-domain-names = "ife0", "ife1", "ife2", "top"; + vdd-csiphy01-0p9-supply = <&vreg_0p9>; + vdd-csiphy01-1p2-supply = <&vreg_1p2>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@1 { + reg = <1>; + + csiphy1_ep: endpoint { + data-lanes = <0 1>; + remote-endpoint = <&camera_sensor>; + }; + }; + }; + }; + }; From 638903e3dd1529443deaf3e07ae23545152f975b Mon Sep 17 00:00:00 2001 From: Vincent Knecht Date: Thu, 30 Oct 2025 08:59:12 +0100 Subject: [PATCH 2163/2333] UPSTREAM: media: dt-bindings: Add qcom,msm8939-camss MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add bindings for qcom,msm8939-camss in order to support the camera subsystem for MSM8939. Link: https://lore.kernel.org/all/20251030-camss-8x39-vbif-v8-1-754834937f5c@apitzsch.eu/ Signed-off-by: Vincent Knecht [André: Make order of items the same as in 8916] Reviewed-by: Krzysztof Kozlowski Reviewed-by: Bryan O'Donoghue Signed-off-by: André Apitzsch --- .../bindings/media/qcom,msm8939-camss.yaml | 254 ++++++++++++++++++ 1 file changed, 254 insertions(+) create mode 100644 Documentation/devicetree/bindings/media/qcom,msm8939-camss.yaml diff --git a/Documentation/devicetree/bindings/media/qcom,msm8939-camss.yaml b/Documentation/devicetree/bindings/media/qcom,msm8939-camss.yaml new file mode 100644 index 0000000000000..77b389d76a437 --- /dev/null +++ b/Documentation/devicetree/bindings/media/qcom,msm8939-camss.yaml @@ -0,0 +1,254 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/qcom,msm8939-camss.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm MSM8939 Camera Subsystem (CAMSS) + +maintainers: + - Vincent Knecht + +description: + The CAMSS IP is a CSI decoder and ISP present on Qualcomm platforms + +properties: + compatible: + const: qcom,msm8939-camss + + reg: + maxItems: 11 + + reg-names: + items: + - const: csiphy0 + - const: csiphy0_clk_mux + - const: csiphy1 + - const: csiphy1_clk_mux + - const: csid0 + - const: csid1 + - const: ispif + - const: csi_clk_mux + - const: vfe0 + - const: csid2 + - const: vfe0_vbif + + clocks: + maxItems: 24 + + clock-names: + items: + - const: top_ahb + - const: ispif_ahb + - const: csiphy0_timer + - const: csiphy1_timer + - const: csi0_ahb + - const: csi0 + - const: csi0_phy + - const: csi0_pix + - const: csi0_rdi + - const: csi1_ahb + - const: csi1 + - const: csi1_phy + - const: csi1_pix + - const: csi1_rdi + - const: ahb + - const: vfe0 + - const: csi_vfe0 + - const: vfe_ahb + - const: vfe_axi + - const: csi2_ahb + - const: csi2 + - const: csi2_phy + - const: csi2_pix + - const: csi2_rdi + + interrupts: + maxItems: 7 + + interrupt-names: + items: + - const: csiphy0 + - const: csiphy1 + - const: csid0 + - const: csid1 + - const: ispif + - const: vfe0 + - const: csid2 + + iommus: + maxItems: 1 + + power-domains: + items: + - description: VFE GDSC - Video Front End, Global Distributed Switch + Controller. + + vdda-supply: + description: + Definition of the regulator used as 1.2V analog power supply. + + ports: + $ref: /schemas/graph.yaml#/properties/ports + + description: + CSI input ports. + + patternProperties: + "^port@[0-1]$": + $ref: /schemas/graph.yaml#/$defs/port-base + unevaluatedProperties: false + + description: + Input port for receiving CSI data. + + properties: + endpoint: + $ref: video-interfaces.yaml# + unevaluatedProperties: false + + properties: + data-lanes: + minItems: 1 + maxItems: 4 + + bus-type: + enum: + - 4 # MEDIA_BUS_TYPE_CSI2_DPHY + + required: + - data-lanes + +required: + - compatible + - reg + - reg-names + - clocks + - clock-names + - interrupts + - interrupt-names + - iommus + - power-domains + - vdda-supply + - ports + +additionalProperties: false + +examples: + - | + #include + #include + + isp@1b0ac00 { + compatible = "qcom,msm8939-camss"; + + reg = <0x01b0ac00 0x200>, + <0x01b00030 0x4>, + <0x01b0b000 0x200>, + <0x01b00038 0x4>, + <0x01b08000 0x100>, + <0x01b08400 0x100>, + <0x01b0a000 0x500>, + <0x01b00020 0x10>, + <0x01b10000 0x1000>, + <0x01b08800 0x100>, + <0x01b40000 0x200>; + + reg-names = "csiphy0", + "csiphy0_clk_mux", + "csiphy1", + "csiphy1_clk_mux", + "csid0", + "csid1", + "ispif", + "csi_clk_mux", + "vfe0", + "csid2", + "vfe0_vbif"; + + clocks = <&gcc GCC_CAMSS_TOP_AHB_CLK>, + <&gcc GCC_CAMSS_ISPIF_AHB_CLK>, + <&gcc GCC_CAMSS_CSI0PHYTIMER_CLK>, + <&gcc GCC_CAMSS_CSI1PHYTIMER_CLK>, + <&gcc GCC_CAMSS_CSI0_AHB_CLK>, + <&gcc GCC_CAMSS_CSI0_CLK>, + <&gcc GCC_CAMSS_CSI0PHY_CLK>, + <&gcc GCC_CAMSS_CSI0PIX_CLK>, + <&gcc GCC_CAMSS_CSI0RDI_CLK>, + <&gcc GCC_CAMSS_CSI1_AHB_CLK>, + <&gcc GCC_CAMSS_CSI1_CLK>, + <&gcc GCC_CAMSS_CSI1PHY_CLK>, + <&gcc GCC_CAMSS_CSI1PIX_CLK>, + <&gcc GCC_CAMSS_CSI1RDI_CLK>, + <&gcc GCC_CAMSS_AHB_CLK>, + <&gcc GCC_CAMSS_VFE0_CLK>, + <&gcc GCC_CAMSS_CSI_VFE0_CLK>, + <&gcc GCC_CAMSS_VFE_AHB_CLK>, + <&gcc GCC_CAMSS_VFE_AXI_CLK>, + <&gcc GCC_CAMSS_CSI2_AHB_CLK>, + <&gcc GCC_CAMSS_CSI2_CLK>, + <&gcc GCC_CAMSS_CSI2PHY_CLK>, + <&gcc GCC_CAMSS_CSI2PIX_CLK>, + <&gcc GCC_CAMSS_CSI2RDI_CLK>; + + clock-names = "top_ahb", + "ispif_ahb", + "csiphy0_timer", + "csiphy1_timer", + "csi0_ahb", + "csi0", + "csi0_phy", + "csi0_pix", + "csi0_rdi", + "csi1_ahb", + "csi1", + "csi1_phy", + "csi1_pix", + "csi1_rdi", + "ahb", + "vfe0", + "csi_vfe0", + "vfe_ahb", + "vfe_axi", + "csi2_ahb", + "csi2", + "csi2_phy", + "csi2_pix", + "csi2_rdi"; + + interrupts = , + , + , + , + , + , + ; + + interrupt-names = "csiphy0", + "csiphy1", + "csid0", + "csid1", + "ispif", + "vfe0", + "csid2"; + + iommus = <&apps_iommu 3>; + + power-domains = <&gcc VFE_GDSC>; + + vdda-supply = <®_1v2>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@1 { + reg = <1>; + + csiphy1_ep: endpoint { + data-lanes = <0 2>; + remote-endpoint = <&sensor_ep>; + }; + }; + }; + }; From 5cbc629e65bd3954aa83d1c6d66a36f453a5c761 Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Tue, 28 Oct 2025 17:40:46 +0100 Subject: [PATCH 2164/2333] UPSTREAM: dt-bindings: i2c: qcom-cci: Document msm8953 compatible Add the msm8953 CCI device string compatible. Link: https://lore.kernel.org/all/20251028-msm8953-cci-v2-1-b5f9f7135326@lucaweiss.eu/ Signed-off-by: Luca Weiss Reviewed-by: Krzysztof Kozlowski --- Documentation/devicetree/bindings/i2c/qcom,i2c-cci.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/i2c/qcom,i2c-cci.yaml b/Documentation/devicetree/bindings/i2c/qcom,i2c-cci.yaml index 3a03ffffdc57f..f1919f59d521c 100644 --- a/Documentation/devicetree/bindings/i2c/qcom,i2c-cci.yaml +++ b/Documentation/devicetree/bindings/i2c/qcom,i2c-cci.yaml @@ -15,6 +15,7 @@ properties: oneOf: - enum: - qcom,msm8226-cci + - qcom,msm8953-cci - qcom,msm8974-cci - qcom,msm8996-cci @@ -150,6 +151,7 @@ allOf: - contains: enum: - qcom,msm8916-cci + - qcom,msm8953-cci - const: qcom,msm8996-cci then: From 58f0a252a972b548f72cb65f22cf4f0105bc1206 Mon Sep 17 00:00:00 2001 From: Hangxiang Ma Date: Wed, 26 Nov 2025 01:38:34 -0800 Subject: [PATCH 2165/2333] UPSTREAM: dt-bindings: i2c: qcom-cci: Document SM8750 compatible Add SM8750 compatible consistent with CAMSS CCI interfaces. Link: https://lore.kernel.org/r/20251126-add-support-for-camss-on-sm8750-v1-1-646fee2eb720@oss.qualcomm.com Signed-off-by: Hangxiang Ma Reviewed-by: Bryan O'Donoghue Reviewed-by: Krzysztof Kozlowski --- Documentation/devicetree/bindings/i2c/qcom,i2c-cci.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/i2c/qcom,i2c-cci.yaml b/Documentation/devicetree/bindings/i2c/qcom,i2c-cci.yaml index f1919f59d521c..399a09409e071 100644 --- a/Documentation/devicetree/bindings/i2c/qcom,i2c-cci.yaml +++ b/Documentation/devicetree/bindings/i2c/qcom,i2c-cci.yaml @@ -39,6 +39,7 @@ properties: - qcom,sm8450-cci - qcom,sm8550-cci - qcom,sm8650-cci + - qcom,sm8750-cci - qcom,x1e80100-cci - const: qcom,msm8996-cci # CCI v2 @@ -134,6 +135,7 @@ allOf: - qcom,kaanapali-cci - qcom,qcm2290-cci - qcom,qcs8300-cci + - qcom,sm8750-cci then: properties: clocks: From bc9c48e2e4952e65f5bca52dc928d0995587d66d Mon Sep 17 00:00:00 2001 From: Hangxiang Ma Date: Tue, 14 Oct 2025 19:42:30 -0700 Subject: [PATCH 2166/2333] UPSTREAM: media: qcom: camss: Use a macro to specify the initial buffer count Replace the hardcoded buffer count value with a macro to enable operating on these buffers elsewhere in the CAMSS driver based on this count. Some of the hardware architectures require deferring the AUP and REG update until after the CSID configuration and this macro is expected to be useful in such scenarios. Link: https://lore.kernel.org/all/20251014-use-marco-to-denote-image-buffer-number-v1-1-f782e4cc622d@oss.qualcomm.com/ Signed-off-by: Hangxiang Ma --- drivers/media/platform/qcom/camss/camss-vfe.c | 2 +- drivers/media/platform/qcom/camss/camss.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c index dff8d0a1e8c22..15a1524cd2df2 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe.c +++ b/drivers/media/platform/qcom/camss/camss-vfe.c @@ -541,7 +541,7 @@ int vfe_enable_output_v2(struct vfe_line *line) ops->vfe_wm_start(vfe, output->wm_idx[0], line); - for (i = 0; i < 2; i++) { + for (i = 0; i < CAMSS_INIT_BUF_COUNT; i++) { output->buf[i] = vfe_buf_get_pending(output); if (!output->buf[i]) break; diff --git a/drivers/media/platform/qcom/camss/camss.h b/drivers/media/platform/qcom/camss/camss.h index a70fbc78ccc30..901f84efaf7d2 100644 --- a/drivers/media/platform/qcom/camss/camss.h +++ b/drivers/media/platform/qcom/camss/camss.h @@ -41,6 +41,7 @@ (to_camss_index(ptr_module, index)->dev) #define CAMSS_RES_MAX 17 +#define CAMSS_INIT_BUF_COUNT 2 struct camss_subdev_resources { char *regulators[CAMSS_RES_MAX]; From ba3dcf6d217d14a29d9f7ccd6be28e26fa580590 Mon Sep 17 00:00:00 2001 From: Hangxiang Ma Date: Tue, 14 Oct 2025 19:43:15 -0700 Subject: [PATCH 2167/2333] UPSTREAM: media: qcom: camss: Enable setting the rate to camnoc_rt_axi clock On hardware architectures where a single CAMNOC module is split into two, one for each of the real time (RT) and non real time (NRT) modules within camera sub system, processing VFE output over the AXI bus requires enabling and setting the appropriate clock rate for the RT CAMNOC. This change lays the groundwork for supporting such configurations. Link: https://lore.kernel.org/all/20251014-add-new-clock-in-vfe-matching-list-v1-1-0d965ccc8a3a@oss.qualcomm.com/ Signed-off-by: Hangxiang Ma --- drivers/media/platform/qcom/camss/camss-vfe.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c index 15a1524cd2df2..55fb7547f84f1 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe.c +++ b/drivers/media/platform/qcom/camss/camss-vfe.c @@ -914,7 +914,8 @@ static int vfe_match_clock_names(struct vfe_device *vfe, return (!strcmp(clock->name, vfe_name) || !strcmp(clock->name, vfe_lite_name) || !strcmp(clock->name, "vfe_lite") || - !strcmp(clock->name, "camnoc_axi")); + !strcmp(clock->name, "camnoc_axi") || + !strcmp(clock->name, "camnoc_rt_axi")); } /* From bf3a5b48967b1d4e4aab711315b9982a624bc012 Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy Date: Fri, 17 Oct 2025 06:11:29 +0300 Subject: [PATCH 2168/2333] UPSTREAM: media: qcom: camss: Add Qualcomm SM8650 CAMSS support Add the basic support of CAMSS IP on Qualcomm SM8650 SoC powered boards. SM8650 CAMSS provides: - 6 x CSIPHY, - 3 x CSID, 2 x CSID Lite, - 3 x VFE, 2 x VFE Lite. Link: https://lore.kernel.org/all/20251017031131.2232687-3-vladimir.zapolskiy@linaro.org/ Signed-off-by: Vladimir Zapolskiy Reviewed-by: Bryan O'Donoghue Tested-by: Neil Armstrong # on SM8650-QRD --- drivers/media/platform/qcom/camss/camss-vfe.c | 2 + drivers/media/platform/qcom/camss/camss.c | 326 ++++++++++++++++++ drivers/media/platform/qcom/camss/camss.h | 1 + 3 files changed, 329 insertions(+) diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c index 55fb7547f84f1..ffa695a9cd94c 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe.c +++ b/drivers/media/platform/qcom/camss/camss-vfe.c @@ -348,6 +348,7 @@ static u32 vfe_src_pad_code(struct vfe_line *line, u32 sink_code, case CAMSS_8300: case CAMSS_845: case CAMSS_8550: + case CAMSS_8650: case CAMSS_8775P: case CAMSS_X1E80100: switch (sink_code) { @@ -1996,6 +1997,7 @@ static int vfe_bpl_align(struct vfe_device *vfe) case CAMSS_8300: case CAMSS_845: case CAMSS_8550: + case CAMSS_8650: case CAMSS_8775P: case CAMSS_X1E80100: ret = 16; diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c index 2fbcd0e343aac..06a184fb9ae3d 100644 --- a/drivers/media/platform/qcom/camss/camss.c +++ b/drivers/media/platform/qcom/camss/camss.c @@ -2617,6 +2617,317 @@ static const struct resources_icc icc_res_sm8550[] = { }, }; +static const struct camss_subdev_resources csiphy_res_sm8650[] = { + /* CSIPHY0 */ + { + .regulators = { "vdd-csiphy01-0p9", "vdd-csiphy01-1p2", }, + .clock = { "csiphy0", "csiphy0_timer" }, + .clock_rate = { { 400000000 }, + { 400000000 } }, + .reg = { "csiphy0" }, + .interrupt = { "csiphy0" }, + .csiphy = { + .id = 0, + .hw_ops = &csiphy_ops_3ph_1_0, + .formats = &csiphy_formats_sdm845, + }, + }, + /* CSIPHY1 */ + { + .regulators = { "vdd-csiphy01-0p9", "vdd-csiphy01-1p2", }, + .clock = { "csiphy1", "csiphy1_timer" }, + .clock_rate = { { 400000000 }, + { 400000000 } }, + .reg = { "csiphy1" }, + .interrupt = { "csiphy1" }, + .csiphy = { + .id = 1, + .hw_ops = &csiphy_ops_3ph_1_0, + .formats = &csiphy_formats_sdm845, + }, + }, + /* CSIPHY2 */ + { + .regulators = { "vdd-csiphy24-0p9", "vdd-csiphy24-1p2", }, + .clock = { "csiphy2", "csiphy2_timer" }, + .clock_rate = { { 400000000 }, + { 400000000 } }, + .reg = { "csiphy2" }, + .interrupt = { "csiphy2" }, + .csiphy = { + .id = 2, + .hw_ops = &csiphy_ops_3ph_1_0, + .formats = &csiphy_formats_sdm845, + }, + }, + /* CSIPHY3 */ + { + .regulators = { "vdd-csiphy35-0p9", "vdd-csiphy35-1p2", }, + .clock = { "csiphy3", "csiphy3_timer" }, + .clock_rate = { { 400000000 }, + { 400000000 } }, + .reg = { "csiphy3" }, + .interrupt = { "csiphy3" }, + .csiphy = { + .id = 3, + .hw_ops = &csiphy_ops_3ph_1_0, + .formats = &csiphy_formats_sdm845, + }, + }, + /* CSIPHY4 */ + { + .regulators = { "vdd-csiphy24-0p9", "vdd-csiphy24-1p2", }, + .clock = { "csiphy4", "csiphy4_timer" }, + .clock_rate = { { 400000000 }, + { 400000000 } }, + .reg = { "csiphy4" }, + .interrupt = { "csiphy4" }, + .csiphy = { + .id = 4, + .hw_ops = &csiphy_ops_3ph_1_0, + .formats = &csiphy_formats_sdm845, + }, + }, + /* CSIPHY5 */ + { + .regulators = { "vdd-csiphy35-0p9", "vdd-csiphy35-1p2", }, + .clock = { "csiphy5", "csiphy5_timer" }, + .clock_rate = { { 400000000 }, + { 400000000 } }, + .reg = { "csiphy5" }, + .interrupt = { "csiphy5" }, + .csiphy = { + .id = 5, + .hw_ops = &csiphy_ops_3ph_1_0, + .formats = &csiphy_formats_sdm845, + }, + }, +}; + +static const struct camss_subdev_resources csid_res_sm8650[] = { + /* CSID0 */ + { + .regulators = { }, + .clock = { "csid", "csiphy_rx" }, + .clock_rate = { { 400000000 }, + { 400000000, 480000000 } }, + .reg = { "csid0" }, + .interrupt = { "csid0" }, + .csid = { + .parent_dev_ops = &vfe_parent_dev_ops, + .hw_ops = &csid_ops_gen3, + .formats = &csid_formats_gen2, + }, + }, + /* CSID1 */ + { + .regulators = { }, + .clock = { "csid", "csiphy_rx" }, + .clock_rate = { { 400000000 }, + { 400000000, 480000000 } }, + .reg = { "csid1" }, + .interrupt = { "csid1" }, + .csid = { + .parent_dev_ops = &vfe_parent_dev_ops, + .hw_ops = &csid_ops_gen3, + .formats = &csid_formats_gen2, + }, + }, + /* CSID2 */ + { + .regulators = { }, + .clock = { "csid", "csiphy_rx" }, + .clock_rate = { { 400000000 }, + { 400000000, 480000000 } }, + .reg = { "csid2" }, + .interrupt = { "csid2" }, + .csid = { + .parent_dev_ops = &vfe_parent_dev_ops, + .hw_ops = &csid_ops_gen3, + .formats = &csid_formats_gen2, + }, + }, + /* CSID3 lite */ + { + .regulators = { }, + .clock = { "vfe_lite_ahb", "vfe_lite_csid", "vfe_lite_cphy_rx" }, + .clock_rate = { { 0 }, + { 400000000, 480000000 }, + { 0 } }, + .reg = { "csid_lite0" }, + .interrupt = { "csid_lite0" }, + .csid = { + .is_lite = true, + .parent_dev_ops = &vfe_parent_dev_ops, + .hw_ops = &csid_ops_gen3, + .formats = &csid_formats_gen2, + }, + }, + /* CSID4 lite */ + { + .regulators = { }, + .clock = { "vfe_lite_ahb", "vfe_lite_csid", "vfe_lite_cphy_rx" }, + .clock_rate = { { 0 }, + { 400000000, 480000000 }, + { 0 } }, + .reg = { "csid_lite1" }, + .interrupt = { "csid_lite1" }, + .csid = { + .is_lite = true, + .parent_dev_ops = &vfe_parent_dev_ops, + .hw_ops = &csid_ops_gen3, + .formats = &csid_formats_gen2, + }, + }, +}; + +static const struct camss_subdev_resources vfe_res_sm8650[] = { + /* VFE0 */ + { + .regulators = { }, + .clock = { "gcc_axi_hf", "cpas_ahb", "cpas_fast_ahb", + "camnoc_axi", "vfe0_fast_ahb", "vfe0", "cpas_vfe0", + "qdss_debug_xo", + }, + .clock_rate = { { 0 }, + { 80000000 }, + { 300000000, 400000000 }, + { 300000000, 400000000 }, + { 0 }, + { 466000000, 594000000, 675000000, 785000000 }, + { 0 }, + { 0 }, + }, + .reg = { "vfe0" }, + .interrupt = { "vfe0" }, + .vfe = { + .line_num = 3, + .has_pd = true, + .pd_name = "ife0", + .hw_ops = &vfe_ops_gen3, + .formats_rdi = &vfe_formats_rdi_845, + .formats_pix = &vfe_formats_pix_845 + }, + }, + /* VFE1 */ + { + .regulators = { }, + .clock = { "gcc_axi_hf", "cpas_ahb", "cpas_fast_ahb", + "camnoc_axi", "vfe1_fast_ahb", "vfe1", "cpas_vfe1", + "qdss_debug_xo", + }, + .clock_rate = { { 0 }, + { 80000000 }, + { 300000000, 400000000 }, + { 300000000, 400000000 }, + { 0 }, + { 466000000, 594000000, 675000000, 785000000 }, + { 0 }, + { 0 }, + }, + .reg = { "vfe1" }, + .interrupt = { "vfe1" }, + .vfe = { + .line_num = 3, + .has_pd = true, + .pd_name = "ife1", + .hw_ops = &vfe_ops_gen3, + .formats_rdi = &vfe_formats_rdi_845, + .formats_pix = &vfe_formats_pix_845 + }, + }, + /* VFE2 */ + { + .regulators = { }, + .clock = { "gcc_axi_hf", "cpas_ahb", "cpas_fast_ahb", + "camnoc_axi", "vfe2_fast_ahb", "vfe2", "cpas_vfe2", + "qdss_debug_xo", + }, + .clock_rate = { { 0 }, + { 80000000 }, + { 300000000, 400000000 }, + { 300000000, 400000000 }, + { 0 }, + { 466000000, 594000000, 675000000, 785000000 }, + { 0 }, + { 0 }, + }, + .reg = { "vfe2" }, + .interrupt = { "vfe2" }, + .vfe = { + .line_num = 3, + .has_pd = true, + .pd_name = "ife2", + .hw_ops = &vfe_ops_gen3, + .formats_rdi = &vfe_formats_rdi_845, + .formats_pix = &vfe_formats_pix_845 + }, + }, + /* VFE3 lite */ + { + .regulators = { }, + .clock = { "gcc_axi_hf", "cpas_ahb", "camnoc_axi", + "vfe_lite_ahb", "vfe_lite", "cpas_vfe_lite", + "qdss_debug_xo", + }, + .clock_rate = { { 0 }, + { 80000000 }, + { 300000000, 400000000 }, + { 0 }, + { 400000000, 480000000 }, + { 0 }, + { 0 }, + }, + .reg = { "vfe_lite0" }, + .interrupt = { "vfe_lite0" }, + .vfe = { + .line_num = 4, + .is_lite = true, + .hw_ops = &vfe_ops_gen3, + .formats_rdi = &vfe_formats_rdi_845, + .formats_pix = &vfe_formats_pix_845 + }, + }, + /* VFE4 lite */ + { + .regulators = { }, + .clock = { "gcc_axi_hf", "cpas_ahb", "camnoc_axi", + "vfe_lite_ahb", "vfe_lite", "cpas_vfe_lite", + "qdss_debug_xo", + }, + .clock_rate = { { 0 }, + { 80000000 }, + { 300000000, 400000000 }, + { 0 }, + { 400000000, 480000000 }, + { 0 }, + { 0 }, + }, + .reg = { "vfe_lite1" }, + .interrupt = { "vfe_lite1" }, + .vfe = { + .line_num = 4, + .is_lite = true, + .hw_ops = &vfe_ops_gen3, + .formats_rdi = &vfe_formats_rdi_845, + .formats_pix = &vfe_formats_pix_845 + }, + }, +}; + +static const struct resources_icc icc_res_sm8650[] = { + { + .name = "ahb", + .icc_bw_tbl.avg = 38400, + .icc_bw_tbl.peak = 76800, + }, + { + .name = "hf_mnoc", + .icc_bw_tbl.avg = 2097152, + .icc_bw_tbl.peak = 2097152, + }, +}; + static const struct camss_subdev_resources csiphy_res_8300[] = { /* CSIPHY0 */ { @@ -4452,6 +4763,20 @@ static const struct camss_resources sm8550_resources = { .vfe_num = ARRAY_SIZE(vfe_res_8550), }; +static const struct camss_resources sm8650_resources = { + .version = CAMSS_8650, + .pd_name = "top", + .csiphy_res = csiphy_res_sm8650, + .csid_res = csid_res_sm8650, + .csid_wrapper_res = &csid_wrapper_res_sm8550, + .vfe_res = vfe_res_sm8650, + .icc_res = icc_res_sm8650, + .icc_path_num = ARRAY_SIZE(icc_res_sm8650), + .csiphy_num = ARRAY_SIZE(csiphy_res_sm8650), + .csid_num = ARRAY_SIZE(csid_res_sm8650), + .vfe_num = ARRAY_SIZE(vfe_res_sm8650), +}; + static const struct camss_resources x1e80100_resources = { .version = CAMSS_X1E80100, .pd_name = "top", @@ -4480,6 +4805,7 @@ static const struct of_device_id camss_dt_match[] = { { .compatible = "qcom,sdm845-camss", .data = &sdm845_resources }, { .compatible = "qcom,sm8250-camss", .data = &sm8250_resources }, { .compatible = "qcom,sm8550-camss", .data = &sm8550_resources }, + { .compatible = "qcom,sm8650-camss", .data = &sm8650_resources }, { .compatible = "qcom,x1e80100-camss", .data = &x1e80100_resources }, { } }; diff --git a/drivers/media/platform/qcom/camss/camss.h b/drivers/media/platform/qcom/camss/camss.h index 901f84efaf7d2..205a37bb1ade9 100644 --- a/drivers/media/platform/qcom/camss/camss.h +++ b/drivers/media/platform/qcom/camss/camss.h @@ -89,6 +89,7 @@ enum camss_version { CAMSS_8300, CAMSS_845, CAMSS_8550, + CAMSS_8650, CAMSS_8775P, CAMSS_X1E80100, }; From 28a05a982f063af1c1146bbb6761aeaf4a37d18c Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy Date: Fri, 17 Oct 2025 06:11:30 +0300 Subject: [PATCH 2169/2333] UPSTREAM: media: qcom: camss: Add CSIPHY 2.2.0 lane configuration for SM8650 Add a configuration for all CSI lanes into D-PHY bus mode on Qualcomm SM8650 CAMSS CSIPHY IPs. Link: https://lore.kernel.org/all/20251017031131.2232687-4-vladimir.zapolskiy@linaro.org/ Signed-off-by: Vladimir Zapolskiy Reviewed-by: Bryan O'Donoghue Tested-by: Neil Armstrong # on SM8650-QRD --- .../qcom/camss/camss-csiphy-3ph-1-0.c | 102 ++++++++++++++++++ 1 file changed, 102 insertions(+) diff --git a/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c b/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c index a229ba04b1587..619abbf607813 100644 --- a/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c +++ b/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c @@ -587,6 +587,102 @@ csiphy_lane_regs lane_regs_sm8550[] = { {0x0C64, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, }; +/* GEN2 2.2.0 2PH 4 lane DPHY mode */ +static const struct +csiphy_lane_regs lane_regs_sm8650[] = { + {0x0e94, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0ea0, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0e90, 0x0f, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0e98, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0e94, 0x07, 0xd1, CSIPHY_DEFAULT_PARAMS}, + {0x0e30, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0e28, 0x04, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0e00, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0e0c, 0xff, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0e38, 0x1f, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0e2c, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0e34, 0x0f, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0e1c, 0x0a, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0e14, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0e3c, 0xb8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0e04, 0x0c, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0e20, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0e08, 0x19, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0e10, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + + {0x0094, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x00a0, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0090, 0x0f, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0098, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0094, 0x07, 0xd1, CSIPHY_DEFAULT_PARAMS}, + {0x0030, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0000, 0x8e, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0038, 0xfe, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x002c, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0034, 0x0f, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x001c, 0x0a, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0014, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x003c, 0xb8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0004, 0x0c, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0020, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0008, 0x19, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0010, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + + {0x0494, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x04a0, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0490, 0x0f, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0498, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0494, 0x07, 0xd1, CSIPHY_DEFAULT_PARAMS}, + {0x0430, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0400, 0x8e, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0438, 0xfe, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x042c, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0434, 0x0f, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x041c, 0x0a, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0414, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x043c, 0xb8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0404, 0x0c, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0420, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0408, 0x19, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0410, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + + {0x0894, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x08a0, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0890, 0x0f, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0898, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0894, 0x07, 0xd1, CSIPHY_DEFAULT_PARAMS}, + {0x0830, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x8e, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0838, 0xfe, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x082c, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0834, 0x0f, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x081c, 0x0a, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0814, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x083c, 0xb8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0804, 0x0c, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0820, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0808, 0x19, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0810, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + + {0x0c94, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0ca0, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0c90, 0x0f, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0c98, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0c94, 0x07, 0xd1, CSIPHY_DEFAULT_PARAMS}, + {0x0c30, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0c00, 0x8e, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0c38, 0xfe, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0c2c, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0c34, 0x0f, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0c1c, 0x0a, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0c14, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0c3c, 0xb8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0c04, 0x0c, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0c20, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0c08, 0x19, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0c10, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, +}; + /* 4nm 2PH v 2.1.2 2p5Gbps 4 lane DPHY mode */ static const struct csiphy_lane_regs lane_regs_x1e80100[] = { @@ -914,6 +1010,7 @@ static bool csiphy_is_gen2(u32 version) case CAMSS_8300: case CAMSS_845: case CAMSS_8550: + case CAMSS_8650: case CAMSS_8775P: case CAMSS_X1E80100: ret = true; @@ -1018,6 +1115,11 @@ static int csiphy_init(struct csiphy_device *csiphy) regs->lane_array_size = ARRAY_SIZE(lane_regs_sm8550); regs->offset = 0x1000; break; + case CAMSS_8650: + regs->lane_regs = &lane_regs_sm8650[0]; + regs->lane_array_size = ARRAY_SIZE(lane_regs_sm8650); + regs->offset = 0x1000; + break; case CAMSS_8300: case CAMSS_8775P: regs->lane_regs = &lane_regs_sa8775p[0]; From 0063420a3fd634879c301897664627ca34fb049a Mon Sep 17 00:00:00 2001 From: Vincent Knecht Date: Thu, 30 Oct 2025 08:59:13 +0100 Subject: [PATCH 2170/2333] UPSTREAM: media: qcom: camss: vfe: Add VBIF setting support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some devices need writing values to VFE VBIF registers. Add helper functions to do this. Link: https://lore.kernel.org/all/20251030-camss-8x39-vbif-v8-2-754834937f5c@apitzsch.eu/ Reviewed-by: Bryan O'Donoghue Signed-off-by: Vincent Knecht Signed-off-by: André Apitzsch --- drivers/media/platform/qcom/camss/Makefile | 1 + .../media/platform/qcom/camss/camss-vfe-4-1.c | 12 +++++++++ .../platform/qcom/camss/camss-vfe-vbif.c | 25 +++++++++++++++++++ .../platform/qcom/camss/camss-vfe-vbif.h | 19 ++++++++++++++ drivers/media/platform/qcom/camss/camss-vfe.c | 9 +++++++ drivers/media/platform/qcom/camss/camss-vfe.h | 3 +++ 6 files changed, 69 insertions(+) create mode 100644 drivers/media/platform/qcom/camss/camss-vfe-vbif.c create mode 100644 drivers/media/platform/qcom/camss/camss-vfe-vbif.h diff --git a/drivers/media/platform/qcom/camss/Makefile b/drivers/media/platform/qcom/camss/Makefile index 23960d02877de..5e349b4915130 100644 --- a/drivers/media/platform/qcom/camss/Makefile +++ b/drivers/media/platform/qcom/camss/Makefile @@ -23,6 +23,7 @@ qcom-camss-objs += \ camss-vfe-680.o \ camss-vfe-gen3.o \ camss-vfe-gen1.o \ + camss-vfe-vbif.o \ camss-vfe.o \ camss-video.o \ camss-format.o \ diff --git a/drivers/media/platform/qcom/camss/camss-vfe-4-1.c b/drivers/media/platform/qcom/camss/camss-vfe-4-1.c index 901677293d971..9cf1ccdb2fe7c 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe-4-1.c +++ b/drivers/media/platform/qcom/camss/camss-vfe-4-1.c @@ -15,6 +15,7 @@ #include "camss.h" #include "camss-vfe.h" #include "camss-vfe-gen1.h" +#include "camss-vfe-vbif.h" #define VFE_0_HW_VERSION 0x000 @@ -733,6 +734,7 @@ static void vfe_set_qos(struct vfe_device *vfe) { u32 val = VFE_0_BUS_BDG_QOS_CFG_0_CFG; u32 val7 = VFE_0_BUS_BDG_QOS_CFG_7_CFG; + int ret; writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_QOS_CFG_0); writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_QOS_CFG_1); @@ -742,6 +744,16 @@ static void vfe_set_qos(struct vfe_device *vfe) writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_QOS_CFG_5); writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_QOS_CFG_6); writel_relaxed(val7, vfe->base + VFE_0_BUS_BDG_QOS_CFG_7); + + /* SoC-specific VBIF settings */ + if (vfe->res->has_vbif) { + ret = vfe_vbif_apply_settings(vfe); + if (ret < 0) { + dev_err_ratelimited(vfe->camss->dev, + "VFE: VBIF error %d\n", + ret); + } + } } static void vfe_set_ds(struct vfe_device *vfe) diff --git a/drivers/media/platform/qcom/camss/camss-vfe-vbif.c b/drivers/media/platform/qcom/camss/camss-vfe-vbif.c new file mode 100644 index 0000000000000..691335f231a60 --- /dev/null +++ b/drivers/media/platform/qcom/camss/camss-vfe-vbif.c @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * camss-vfe-vbif.c + * + * Qualcomm MSM Camera Subsystem - VFE VBIF Module + * + * Copyright (c) 2025, The Linux Foundation. All rights reserved. + * + */ + +#include + +#include "camss.h" +#include "camss-vfe.h" +#include "camss-vfe-vbif.h" + +void vfe_vbif_write_reg(struct vfe_device *vfe, u32 reg, u32 val) +{ + writel_relaxed(val, vfe->vbif_base + reg); +} + +int vfe_vbif_apply_settings(struct vfe_device *vfe) +{ + return 0; +} diff --git a/drivers/media/platform/qcom/camss/camss-vfe-vbif.h b/drivers/media/platform/qcom/camss/camss-vfe-vbif.h new file mode 100644 index 0000000000000..502db629e961f --- /dev/null +++ b/drivers/media/platform/qcom/camss/camss-vfe-vbif.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * camss-vfe-vbif.h + * + * Qualcomm MSM Camera Subsystem - VFE VBIF Module + * + * Copyright (c) 2025, The Linux Foundation. All rights reserved. + * + */ +#ifndef QC_MSM_CAMSS_VFE_VBIF_H +#define QC_MSM_CAMSS_VFE_VBIF_H + +#include "camss-vfe.h" + +void vfe_vbif_write_reg(struct vfe_device *vfe, u32 reg, u32 val); + +int vfe_vbif_apply_settings(struct vfe_device *vfe); + +#endif /* QC_MSM_CAMSS_VFE_VBIF_H */ diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c index ffa695a9cd94c..92d1603283075 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe.c +++ b/drivers/media/platform/qcom/camss/camss-vfe.c @@ -1829,6 +1829,15 @@ int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe, return PTR_ERR(vfe->base); } + if (vfe->res->has_vbif) { + vfe->vbif_base = devm_platform_ioremap_resource_byname(pdev, + vfe->res->vbif_name); + if (IS_ERR(vfe->vbif_base)) { + dev_err(dev, "could not map vbif memory\n"); + return PTR_ERR(vfe->vbif_base); + } + } + /* Interrupt */ ret = platform_get_irq_byname(pdev, res->interrupt[0]); diff --git a/drivers/media/platform/qcom/camss/camss-vfe.h b/drivers/media/platform/qcom/camss/camss-vfe.h index 0300efdb1c46f..ae9dad353a378 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe.h +++ b/drivers/media/platform/qcom/camss/camss-vfe.h @@ -136,6 +136,8 @@ struct vfe_subdev_resources { u8 line_num; bool has_pd; char *pd_name; + bool has_vbif; + char *vbif_name; const struct vfe_hw_ops *hw_ops; const struct camss_formats *formats_rdi; const struct camss_formats *formats_pix; @@ -145,6 +147,7 @@ struct vfe_device { struct camss *camss; u8 id; void __iomem *base; + void __iomem *vbif_base; u32 irq; char irq_name[30]; struct camss_clock *clock; From efca7f821237bf79147bdbbb5b12098e96ab3f42 Mon Sep 17 00:00:00 2001 From: Vincent Knecht Date: Thu, 30 Oct 2025 08:59:14 +0100 Subject: [PATCH 2171/2333] UPSTREAM: media: qcom: camss: Add support for MSM8939 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The camera subsystem for the MSM8939 is the same as MSM8916 except with 3 CSID instead of 2, and some higher clock rates. As a quirk, this SoC needs writing values to 2 VFE VBIF registers (see downstream msm8939-camera.dtsi vbif-{regs,settings} properties). This fixes black stripes across sensor and garbage in CSID TPG outputs. Add support for the MSM8939 camera subsystem. Link: https://lore.kernel.org/all/20251030-camss-8x39-vbif-v8-3-754834937f5c@apitzsch.eu/ Reviewed-by: Bryan O'Donoghue Signed-off-by: Vincent Knecht Signed-off-by: André Apitzsch --- .../media/platform/qcom/camss/camss-csiphy.c | 1 + .../media/platform/qcom/camss/camss-ispif.c | 8 +- .../platform/qcom/camss/camss-vfe-vbif.c | 6 + drivers/media/platform/qcom/camss/camss-vfe.c | 1 + drivers/media/platform/qcom/camss/camss.c | 156 ++++++++++++++++++ drivers/media/platform/qcom/camss/camss.h | 1 + 6 files changed, 171 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/qcom/camss/camss-csiphy.c b/drivers/media/platform/qcom/camss/camss-csiphy.c index 2de97f58f9ae4..a734fb7dde0a4 100644 --- a/drivers/media/platform/qcom/camss/camss-csiphy.c +++ b/drivers/media/platform/qcom/camss/camss-csiphy.c @@ -600,6 +600,7 @@ int msm_csiphy_subdev_init(struct camss *camss, return PTR_ERR(csiphy->base); if (camss->res->version == CAMSS_8x16 || + camss->res->version == CAMSS_8x39 || camss->res->version == CAMSS_8x53 || camss->res->version == CAMSS_8x96) { csiphy->base_clk_mux = diff --git a/drivers/media/platform/qcom/camss/camss-ispif.c b/drivers/media/platform/qcom/camss/camss-ispif.c index 2dc585c6123dd..aaf3caa42d33d 100644 --- a/drivers/media/platform/qcom/camss/camss-ispif.c +++ b/drivers/media/platform/qcom/camss/camss-ispif.c @@ -1112,6 +1112,8 @@ int msm_ispif_subdev_init(struct camss *camss, /* Number of ISPIF lines - same as number of CSID hardware modules */ if (camss->res->version == CAMSS_8x16) ispif->line_num = 2; + else if (camss->res->version == CAMSS_8x39) + ispif->line_num = 3; else if (camss->res->version == CAMSS_8x96 || camss->res->version == CAMSS_8x53 || camss->res->version == CAMSS_660) @@ -1128,7 +1130,8 @@ int msm_ispif_subdev_init(struct camss *camss, ispif->line[i].ispif = ispif; ispif->line[i].id = i; - if (camss->res->version == CAMSS_8x16) { + if (camss->res->version == CAMSS_8x16 || + camss->res->version == CAMSS_8x39) { ispif->line[i].formats = ispif_formats_8x16; ispif->line[i].nformats = ARRAY_SIZE(ispif_formats_8x16); @@ -1162,7 +1165,8 @@ int msm_ispif_subdev_init(struct camss *camss, ispif->irq = ret; snprintf(ispif->irq_name, sizeof(ispif->irq_name), "%s_%s", dev_name(dev), MSM_ISPIF_NAME); - if (camss->res->version == CAMSS_8x16) + if (camss->res->version == CAMSS_8x16 || + camss->res->version == CAMSS_8x39) ret = devm_request_irq(dev, ispif->irq, ispif_isr_8x16, IRQF_TRIGGER_RISING, ispif->irq_name, ispif); else if (camss->res->version == CAMSS_8x96 || diff --git a/drivers/media/platform/qcom/camss/camss-vfe-vbif.c b/drivers/media/platform/qcom/camss/camss-vfe-vbif.c index 691335f231a60..911f8da02f1fb 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe-vbif.c +++ b/drivers/media/platform/qcom/camss/camss-vfe-vbif.c @@ -14,6 +14,9 @@ #include "camss-vfe.h" #include "camss-vfe-vbif.h" +#define VBIF_FIXED_SORT_EN 0x30 +#define VBIF_FIXED_SORT_SEL0 0x34 + void vfe_vbif_write_reg(struct vfe_device *vfe, u32 reg, u32 val) { writel_relaxed(val, vfe->vbif_base + reg); @@ -21,5 +24,8 @@ void vfe_vbif_write_reg(struct vfe_device *vfe, u32 reg, u32 val) int vfe_vbif_apply_settings(struct vfe_device *vfe) { + vfe_vbif_write_reg(vfe, VBIF_FIXED_SORT_EN, 0xfff); + vfe_vbif_write_reg(vfe, VBIF_FIXED_SORT_SEL0, 0x555000); + return 0; } diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c index 92d1603283075..9c7ad8aa40588 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe.c +++ b/drivers/media/platform/qcom/camss/camss-vfe.c @@ -290,6 +290,7 @@ static u32 vfe_src_pad_code(struct vfe_line *line, u32 sink_code, switch (vfe->camss->res->version) { case CAMSS_8x16: + case CAMSS_8x39: case CAMSS_8x53: switch (sink_code) { case MEDIA_BUS_FMT_YUYV8_1X16: diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c index 06a184fb9ae3d..41b82de7915f2 100644 --- a/drivers/media/platform/qcom/camss/camss.c +++ b/drivers/media/platform/qcom/camss/camss.c @@ -154,6 +154,149 @@ static const struct camss_subdev_resources vfe_res_8x16[] = { } }; +static const struct camss_subdev_resources csiphy_res_8x39[] = { + /* CSIPHY0 */ + { + .regulators = { "vdda" }, + .clock = { "top_ahb", "ispif_ahb", "ahb", "csiphy0_timer" }, + .clock_rate = { { 0 }, + { 40000000, 80000000 }, + { 0 }, + { 100000000, 200000000 } }, + .reg = { "csiphy0", "csiphy0_clk_mux" }, + .interrupt = { "csiphy0" }, + .csiphy = { + .id = 0, + .hw_ops = &csiphy_ops_2ph_1_0, + .formats = &csiphy_formats_8x16 + } + }, + + /* CSIPHY1 */ + { + .regulators = { "vdda" }, + .clock = { "top_ahb", "ispif_ahb", "ahb", "csiphy1_timer" }, + .clock_rate = { { 0 }, + { 40000000, 80000000 }, + { 0 }, + { 100000000, 200000000 } }, + .reg = { "csiphy1", "csiphy1_clk_mux" }, + .interrupt = { "csiphy1" }, + .csiphy = { + .id = 1, + .hw_ops = &csiphy_ops_2ph_1_0, + .formats = &csiphy_formats_8x16 + } + } +}; + +static const struct camss_subdev_resources csid_res_8x39[] = { + /* CSID0 */ + { + .regulators = {}, + .clock = { "top_ahb", "ispif_ahb", "csi0_ahb", "ahb", + "csi0", "csi0_phy", "csi0_pix", "csi0_rdi" }, + .clock_rate = { { 0 }, + { 40000000, 80000000 }, + { 0 }, + { 0 }, + { 100000000, 200000000 }, + { 0 }, + { 0 }, + { 0 } }, + .reg = { "csid0" }, + .interrupt = { "csid0" }, + .csid = { + .hw_ops = &csid_ops_4_1, + .parent_dev_ops = &vfe_parent_dev_ops, + .formats = &csid_formats_4_1 + } + }, + + /* CSID1 */ + { + .regulators = {}, + .clock = { "top_ahb", "ispif_ahb", "csi1_ahb", "ahb", + "csi1", "csi1_phy", "csi1_pix", "csi1_rdi" }, + .clock_rate = { { 0 }, + { 40000000, 80000000 }, + { 0 }, + { 0 }, + { 100000000, 200000000 }, + { 0 }, + { 0 }, + { 0 } }, + .reg = { "csid1" }, + .interrupt = { "csid1" }, + .csid = { + .hw_ops = &csid_ops_4_1, + .parent_dev_ops = &vfe_parent_dev_ops, + .formats = &csid_formats_4_1 + } + }, + + /* CSID2 */ + { + .regulators = {}, + .clock = { "top_ahb", "ispif_ahb", "csi2_ahb", "ahb", + "csi2", "csi2_phy", "csi2_pix", "csi2_rdi" }, + .clock_rate = { { 0 }, + { 40000000, 80000000 }, + { 0 }, + { 0 }, + { 100000000, 200000000 }, + { 0 }, + { 0 }, + { 0 } }, + .reg = { "csid2" }, + .interrupt = { "csid2" }, + .csid = { + .hw_ops = &csid_ops_4_1, + .parent_dev_ops = &vfe_parent_dev_ops, + .formats = &csid_formats_4_1 + } + }, +}; + +static const struct camss_subdev_resources ispif_res_8x39 = { + /* ISPIF */ + .clock = { "top_ahb", "ispif_ahb", "ahb", + "csi0", "csi0_pix", "csi0_rdi", + "csi1", "csi1_pix", "csi1_rdi", + "csi2", "csi2_pix", "csi2_rdi" }, + .clock_for_reset = { "vfe0", "csi_vfe0" }, + .reg = { "ispif", "csi_clk_mux" }, + .interrupt = { "ispif" }, +}; + +static const struct camss_subdev_resources vfe_res_8x39[] = { + /* VFE0 */ + { + .regulators = {}, + .clock = { "top_ahb", "ispif_ahb", "vfe0", "csi_vfe0", + "vfe_ahb", "vfe_axi", "ahb" }, + .clock_rate = { { 0 }, + { 40000000, 80000000 }, + { 50000000, 80000000, 100000000, 160000000, + 177780000, 200000000, 266670000, 320000000, + 400000000, 465000000, 480000000, 600000000 }, + { 0 }, + { 0 }, + { 0 }, + { 0 } }, + .reg = { "vfe0" }, + .interrupt = { "vfe0" }, + .vfe = { + .line_num = 3, + .has_vbif = true, + .vbif_name = "vfe0_vbif", + .hw_ops = &vfe_ops_4_1, + .formats_rdi = &vfe_formats_rdi_8x16, + .formats_pix = &vfe_formats_pix_8x16 + } + } +}; + static const struct camss_subdev_resources csid_res_8x53[] = { /* CSID0 */ { @@ -4482,6 +4625,7 @@ static int camss_probe(struct platform_device *pdev) return -ENOMEM; if (camss->res->version == CAMSS_8x16 || + camss->res->version == CAMSS_8x39 || camss->res->version == CAMSS_8x53 || camss->res->version == CAMSS_8x96) { camss->ispif = devm_kcalloc(dev, 1, sizeof(*camss->ispif), GFP_KERNEL); @@ -4613,6 +4757,17 @@ static const struct camss_resources msm8916_resources = { .vfe_num = ARRAY_SIZE(vfe_res_8x16), }; +static const struct camss_resources msm8939_resources = { + .version = CAMSS_8x39, + .csiphy_res = csiphy_res_8x39, + .csid_res = csid_res_8x39, + .ispif_res = &ispif_res_8x39, + .vfe_res = vfe_res_8x39, + .csiphy_num = ARRAY_SIZE(csiphy_res_8x39), + .csid_num = ARRAY_SIZE(csid_res_8x39), + .vfe_num = ARRAY_SIZE(vfe_res_8x39), +}; + static const struct camss_resources msm8953_resources = { .version = CAMSS_8x53, .icc_res = icc_res_8x53, @@ -4793,6 +4948,7 @@ static const struct camss_resources x1e80100_resources = { static const struct of_device_id camss_dt_match[] = { { .compatible = "qcom,msm8916-camss", .data = &msm8916_resources }, + { .compatible = "qcom,msm8939-camss", .data = &msm8939_resources }, { .compatible = "qcom,msm8953-camss", .data = &msm8953_resources }, { .compatible = "qcom,msm8996-camss", .data = &msm8996_resources }, { .compatible = "qcom,qcm2290-camss", .data = &qcm2290_resources }, diff --git a/drivers/media/platform/qcom/camss/camss.h b/drivers/media/platform/qcom/camss/camss.h index 205a37bb1ade9..9d9a62640e25d 100644 --- a/drivers/media/platform/qcom/camss/camss.h +++ b/drivers/media/platform/qcom/camss/camss.h @@ -82,6 +82,7 @@ enum camss_version { CAMSS_2290, CAMSS_7280, CAMSS_8x16, + CAMSS_8x39, CAMSS_8x53, CAMSS_8x96, CAMSS_8250, From f041f87bfb8e1ba5bcab2508e961e5e69b57dcba Mon Sep 17 00:00:00 2001 From: Hangxiang Ma Date: Mon, 12 Jan 2026 00:11:09 -0800 Subject: [PATCH 2172/2333] FROMGIT: media: camss: csiphy: Make CSIPHY status macro cross-platform The current value of '0xb0' that represents the offset to the status registers within the common registers of the CSIPHY has been changed on the newer SOCs and it requires generalizing the macro using a new variable 'common_status_offset'. This variable is initialized in the csiphy_init() function. Link: https://lore.kernel.org/all/20260112-camss-extended-csiphy-macro-v2-1-ee7342f2aaf5@oss.qualcomm.com/ Signed-off-by: Hangxiang Ma Reviewed-by: Bryan O'Donoghue --- .../qcom/camss/camss-csiphy-3ph-1-0.c | 19 +++++++++++++------ .../media/platform/qcom/camss/camss-csiphy.h | 1 + 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c b/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c index 619abbf607813..d70d4f6117988 100644 --- a/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c +++ b/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c @@ -46,7 +46,8 @@ #define CSIPHY_3PH_CMN_CSI_COMMON_CTRL5_CLK_ENABLE BIT(7) #define CSIPHY_3PH_CMN_CSI_COMMON_CTRL6_COMMON_PWRDN_B BIT(0) #define CSIPHY_3PH_CMN_CSI_COMMON_CTRL6_SHOW_REV_ID BIT(1) -#define CSIPHY_3PH_CMN_CSI_COMMON_STATUSn(offset, n) ((offset) + 0xb0 + 0x4 * (n)) +#define CSIPHY_3PH_CMN_CSI_COMMON_STATUSn(offset, common_status_offset, n) \ + ((offset) + (common_status_offset) + 0x4 * (n)) #define CSIPHY_DEFAULT_PARAMS 0 #define CSIPHY_LANE_ENABLE 1 @@ -810,13 +811,17 @@ static void csiphy_hw_version_read(struct csiphy_device *csiphy, CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(regs->offset, 6)); hw_version = readl_relaxed(csiphy->base + - CSIPHY_3PH_CMN_CSI_COMMON_STATUSn(regs->offset, 12)); + CSIPHY_3PH_CMN_CSI_COMMON_STATUSn(regs->offset, + regs->common_status_offset, 12)); hw_version |= readl_relaxed(csiphy->base + - CSIPHY_3PH_CMN_CSI_COMMON_STATUSn(regs->offset, 13)) << 8; + CSIPHY_3PH_CMN_CSI_COMMON_STATUSn(regs->offset, + regs->common_status_offset, 13)) << 8; hw_version |= readl_relaxed(csiphy->base + - CSIPHY_3PH_CMN_CSI_COMMON_STATUSn(regs->offset, 14)) << 16; + CSIPHY_3PH_CMN_CSI_COMMON_STATUSn(regs->offset, + regs->common_status_offset, 14)) << 16; hw_version |= readl_relaxed(csiphy->base + - CSIPHY_3PH_CMN_CSI_COMMON_STATUSn(regs->offset, 15)) << 24; + CSIPHY_3PH_CMN_CSI_COMMON_STATUSn(regs->offset, + regs->common_status_offset, 15)) << 24; dev_dbg(dev, "CSIPHY 3PH HW Version = 0x%08x\n", hw_version); } @@ -845,7 +850,8 @@ static irqreturn_t csiphy_isr(int irq, void *dev) for (i = 0; i < 11; i++) { int c = i + 22; u8 val = readl_relaxed(csiphy->base + - CSIPHY_3PH_CMN_CSI_COMMON_STATUSn(regs->offset, i)); + CSIPHY_3PH_CMN_CSI_COMMON_STATUSn(regs->offset, + regs->common_status_offset, i)); writel_relaxed(val, csiphy->base + CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(regs->offset, c)); @@ -1086,6 +1092,7 @@ static int csiphy_init(struct csiphy_device *csiphy) csiphy->regs = regs; regs->offset = 0x800; + regs->common_status_offset = 0xb0; switch (csiphy->camss->res->version) { case CAMSS_845: diff --git a/drivers/media/platform/qcom/camss/camss-csiphy.h b/drivers/media/platform/qcom/camss/camss-csiphy.h index 895f80003c441..2d5054819df7f 100644 --- a/drivers/media/platform/qcom/camss/camss-csiphy.h +++ b/drivers/media/platform/qcom/camss/camss-csiphy.h @@ -90,6 +90,7 @@ struct csiphy_device_regs { const struct csiphy_lane_regs *lane_regs; int lane_array_size; u32 offset; + u32 common_status_offset; }; struct csiphy_device { From 5b04eb3970d02734a2681066b4517f3a7290bbc5 Mon Sep 17 00:00:00 2001 From: Wenmeng Liu Date: Fri, 14 Nov 2025 16:26:49 +0800 Subject: [PATCH 2173/2333] FROMGIT: media: qcom: camss: Add support for regulator init_load_uA in CSIPHY Some Qualcomm regulators are configured with initial mode as HPM (High Power Mode), which may lead to higher power consumption. To reduce power usage, it's preferable to set the initial mode to LPM (Low Power Mode). To ensure the regulator can switch from LPM to HPM when needed, this patch adds current load configuration for CAMSS CSIPHY. This allows the regulator framework to scale the mode dynamically based on the load requirement. The current default value for current is uninitialized or random. To address this, initial current values are added for the following platforms: MSM8916, MSM8939, MSM8953, MSM8996, QCM2290, SDM670, SM8250, SC7280, SM8550, SM8650, QCS8300, SA8775P and X1E80100. For SDM660, SDM845, SC8280XP the value is set to 0, indicating that no default current value is configured, the other values are derived from the power grid. Link: https://lore.kernel.org/all/20251114082649.4240-1-wenmeng.liu@oss.qualcomm.com/ Signed-off-by: Wenmeng Liu --- .../media/platform/qcom/camss/camss-csid.c | 18 +- .../media/platform/qcom/camss/camss-csiphy.c | 19 +- drivers/media/platform/qcom/camss/camss.c | 328 ++++++++++++++---- drivers/media/platform/qcom/camss/camss.h | 2 +- 4 files changed, 265 insertions(+), 102 deletions(-) diff --git a/drivers/media/platform/qcom/camss/camss-csid.c b/drivers/media/platform/qcom/camss/camss-csid.c index 5284b5857368c..ed1820488c987 100644 --- a/drivers/media/platform/qcom/camss/camss-csid.c +++ b/drivers/media/platform/qcom/camss/camss-csid.c @@ -1187,24 +1187,12 @@ int msm_csid_subdev_init(struct camss *camss, struct csid_device *csid, /* Regulator */ for (i = 0; i < ARRAY_SIZE(res->regulators); i++) { - if (res->regulators[i]) + if (res->regulators[i].supply) csid->num_supplies++; } - if (csid->num_supplies) { - csid->supplies = devm_kmalloc_array(camss->dev, - csid->num_supplies, - sizeof(*csid->supplies), - GFP_KERNEL); - if (!csid->supplies) - return -ENOMEM; - } - - for (i = 0; i < csid->num_supplies; i++) - csid->supplies[i].supply = res->regulators[i]; - - ret = devm_regulator_bulk_get(camss->dev, csid->num_supplies, - csid->supplies); + ret = devm_regulator_bulk_get_const(camss->dev, csid->num_supplies, + res->regulators, &csid->supplies); if (ret) return ret; diff --git a/drivers/media/platform/qcom/camss/camss-csiphy.c b/drivers/media/platform/qcom/camss/camss-csiphy.c index a734fb7dde0a4..62623393f4144 100644 --- a/drivers/media/platform/qcom/camss/camss-csiphy.c +++ b/drivers/media/platform/qcom/camss/camss-csiphy.c @@ -695,24 +695,13 @@ int msm_csiphy_subdev_init(struct camss *camss, /* CSIPHY supplies */ for (i = 0; i < ARRAY_SIZE(res->regulators); i++) { - if (res->regulators[i]) + if (res->regulators[i].supply) csiphy->num_supplies++; } - if (csiphy->num_supplies) { - csiphy->supplies = devm_kmalloc_array(camss->dev, - csiphy->num_supplies, - sizeof(*csiphy->supplies), - GFP_KERNEL); - if (!csiphy->supplies) - return -ENOMEM; - } - - for (i = 0; i < csiphy->num_supplies; i++) - csiphy->supplies[i].supply = res->regulators[i]; - - ret = devm_regulator_bulk_get(camss->dev, csiphy->num_supplies, - csiphy->supplies); + if (csiphy->num_supplies > 0) + ret = devm_regulator_bulk_get_const(camss->dev, csiphy->num_supplies, + res->regulators, &csiphy->supplies); return ret; } diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c index 41b82de7915f2..5a97e69acb995 100644 --- a/drivers/media/platform/qcom/camss/camss.c +++ b/drivers/media/platform/qcom/camss/camss.c @@ -73,7 +73,9 @@ static const struct camss_subdev_resources csiphy_res_8x16[] = { static const struct camss_subdev_resources csid_res_8x16[] = { /* CSID0 */ { - .regulators = { "vdda" }, + .regulators = { + { .supply = "vdda", .init_load_uA = 40000 } + }, .clock = { "top_ahb", "ispif_ahb", "csi0_ahb", "ahb", "csi0", "csi0_phy", "csi0_pix", "csi0_rdi" }, .clock_rate = { { 0 }, @@ -95,7 +97,9 @@ static const struct camss_subdev_resources csid_res_8x16[] = { /* CSID1 */ { - .regulators = { "vdda" }, + .regulators = { + { .supply = "vdda", .init_load_uA = 40000 } + }, .clock = { "top_ahb", "ispif_ahb", "csi1_ahb", "ahb", "csi1", "csi1_phy", "csi1_pix", "csi1_rdi" }, .clock_rate = { { 0 }, @@ -157,7 +161,9 @@ static const struct camss_subdev_resources vfe_res_8x16[] = { static const struct camss_subdev_resources csiphy_res_8x39[] = { /* CSIPHY0 */ { - .regulators = { "vdda" }, + .regulators = { + { .supply = "vdda", .init_load_uA = 40000 } + }, .clock = { "top_ahb", "ispif_ahb", "ahb", "csiphy0_timer" }, .clock_rate = { { 0 }, { 40000000, 80000000 }, @@ -174,7 +180,9 @@ static const struct camss_subdev_resources csiphy_res_8x39[] = { /* CSIPHY1 */ { - .regulators = { "vdda" }, + .regulators = { + { .supply = "vdda", .init_load_uA = 40000 } + }, .clock = { "top_ahb", "ispif_ahb", "ahb", "csiphy1_timer" }, .clock_rate = { { 0 }, { 40000000, 80000000 }, @@ -300,7 +308,9 @@ static const struct camss_subdev_resources vfe_res_8x39[] = { static const struct camss_subdev_resources csid_res_8x53[] = { /* CSID0 */ { - .regulators = { "vdda" }, + .regulators = { + { .supply = "vdda", .init_load_uA = 9900 } + }, .clock = { "top_ahb", "ispif_ahb", "csi0_ahb", "ahb", "csi0", "csi0_phy", "csi0_pix", "csi0_rdi" }, .clock_rate = { { 0 }, @@ -323,7 +333,9 @@ static const struct camss_subdev_resources csid_res_8x53[] = { /* CSID1 */ { - .regulators = { "vdda" }, + .regulators = { + { .supply = "vdda", .init_load_uA = 9900 } + }, .clock = { "top_ahb", "ispif_ahb", "csi1_ahb", "ahb", "csi1", "csi1_phy", "csi1_pix", "csi1_rdi" }, .clock_rate = { { 0 }, @@ -346,7 +358,9 @@ static const struct camss_subdev_resources csid_res_8x53[] = { /* CSID2 */ { - .regulators = { "vdda" }, + .regulators = { + { .supply = "vdda", .init_load_uA = 9900 } + }, .clock = { "top_ahb", "ispif_ahb", "csi2_ahb", "ahb", "csi2", "csi2_phy", "csi2_pix", "csi2_rdi" }, .clock_rate = { { 0 }, @@ -507,7 +521,9 @@ static const struct camss_subdev_resources csiphy_res_8x96[] = { static const struct camss_subdev_resources csid_res_8x96[] = { /* CSID0 */ { - .regulators = { "vdda" }, + .regulators = { + { .supply = "vdda", .init_load_uA = 80160 } + }, .clock = { "top_ahb", "ispif_ahb", "csi0_ahb", "ahb", "csi0", "csi0_phy", "csi0_pix", "csi0_rdi" }, .clock_rate = { { 0 }, @@ -529,7 +545,9 @@ static const struct camss_subdev_resources csid_res_8x96[] = { /* CSID1 */ { - .regulators = { "vdda" }, + .regulators = { + { .supply = "vdda", .init_load_uA = 80160 } + }, .clock = { "top_ahb", "ispif_ahb", "csi1_ahb", "ahb", "csi1", "csi1_phy", "csi1_pix", "csi1_rdi" }, .clock_rate = { { 0 }, @@ -551,7 +569,9 @@ static const struct camss_subdev_resources csid_res_8x96[] = { /* CSID2 */ { - .regulators = { "vdda" }, + .regulators = { + { .supply = "vdda", .init_load_uA = 80160 } + }, .clock = { "top_ahb", "ispif_ahb", "csi2_ahb", "ahb", "csi2", "csi2_phy", "csi2_pix", "csi2_rdi" }, .clock_rate = { { 0 }, @@ -573,7 +593,9 @@ static const struct camss_subdev_resources csid_res_8x96[] = { /* CSID3 */ { - .regulators = { "vdda" }, + .regulators = { + { .supply = "vdda", .init_load_uA = 80160 } + }, .clock = { "top_ahb", "ispif_ahb", "csi3_ahb", "ahb", "csi3", "csi3_phy", "csi3_pix", "csi3_rdi" }, .clock_rate = { { 0 }, @@ -661,7 +683,10 @@ static const struct camss_subdev_resources vfe_res_8x96[] = { static const struct camss_subdev_resources csiphy_res_2290[] = { /* CSIPHY0 */ { - .regulators = { "vdd-csiphy-1p2", "vdd-csiphy-1p8" }, + .regulators = { + { .supply = "vdd-csiphy-1p2", .init_load_uA = 26700 }, + { .supply = "vdd-csiphy-1p8", .init_load_uA = 2600 } + }, .clock = { "top_ahb", "ahb", "csiphy0", "csiphy0_timer" }, .clock_rate = { { 0 }, { 0 }, @@ -678,7 +703,10 @@ static const struct camss_subdev_resources csiphy_res_2290[] = { /* CSIPHY1 */ { - .regulators = { "vdd-csiphy-1p2", "vdd-csiphy-1p8" }, + .regulators = { + { .supply = "vdd-csiphy-1p2", .init_load_uA = 26700 }, + { .supply = "vdd-csiphy-1p8", .init_load_uA = 2600 } + }, .clock = { "top_ahb", "ahb", "csiphy1", "csiphy1_timer" }, .clock_rate = { { 0 }, { 0 }, @@ -854,7 +882,10 @@ static const struct camss_subdev_resources csiphy_res_660[] = { static const struct camss_subdev_resources csid_res_660[] = { /* CSID0 */ { - .regulators = { "vdda", "vdd_sec" }, + .regulators = { + { .supply = "vdda", .init_load_uA = 0 }, + { .supply = "vdd_sec", .init_load_uA = 0 } + }, .clock = { "top_ahb", "ispif_ahb", "csi0_ahb", "ahb", "csi0", "csi0_phy", "csi0_pix", "csi0_rdi", "cphy_csid0" }, @@ -879,7 +910,10 @@ static const struct camss_subdev_resources csid_res_660[] = { /* CSID1 */ { - .regulators = { "vdda", "vdd_sec" }, + .regulators = { + { .supply = "vdda", .init_load_uA = 0 }, + { .supply = "vdd_sec", .init_load_uA = 0 } + }, .clock = { "top_ahb", "ispif_ahb", "csi1_ahb", "ahb", "csi1", "csi1_phy", "csi1_pix", "csi1_rdi", "cphy_csid1" }, @@ -904,7 +938,10 @@ static const struct camss_subdev_resources csid_res_660[] = { /* CSID2 */ { - .regulators = { "vdda", "vdd_sec" }, + .regulators = { + { .supply = "vdda", .init_load_uA = 0 }, + { .supply = "vdd_sec", .init_load_uA = 0 } + }, .clock = { "top_ahb", "ispif_ahb", "csi2_ahb", "ahb", "csi2", "csi2_phy", "csi2_pix", "csi2_rdi", "cphy_csid2" }, @@ -929,7 +966,10 @@ static const struct camss_subdev_resources csid_res_660[] = { /* CSID3 */ { - .regulators = { "vdda", "vdd_sec" }, + .regulators = { + { .supply = "vdda", .init_load_uA = 0 }, + { .supply = "vdd_sec", .init_load_uA = 0 } + }, .clock = { "top_ahb", "ispif_ahb", "csi3_ahb", "ahb", "csi3", "csi3_phy", "csi3_pix", "csi3_rdi", "cphy_csid3" }, @@ -1026,7 +1066,10 @@ static const struct camss_subdev_resources vfe_res_660[] = { static const struct camss_subdev_resources csiphy_res_670[] = { /* CSIPHY0 */ { - .regulators = { "vdda-phy", "vdda-pll" }, + .regulators = { + { .supply = "vdda-phy", .init_load_uA = 42800 }, + { .supply = "vdda-pll", .init_load_uA = 13900 } + }, .clock = { "soc_ahb", "cpas_ahb", "csiphy0", "csiphy0_timer" }, .clock_rate = { { 0 }, @@ -1044,7 +1087,10 @@ static const struct camss_subdev_resources csiphy_res_670[] = { /* CSIPHY1 */ { - .regulators = { "vdda-phy", "vdda-pll" }, + .regulators = { + { .supply = "vdda-phy", .init_load_uA = 42800 }, + { .supply = "vdda-pll", .init_load_uA = 13900 } + }, .clock = { "soc_ahb", "cpas_ahb", "csiphy1", "csiphy1_timer" }, .clock_rate = { { 0 }, @@ -1062,7 +1108,10 @@ static const struct camss_subdev_resources csiphy_res_670[] = { /* CSIPHY2 */ { - .regulators = { "vdda-phy", "vdda-pll" }, + .regulators = { + { .supply = "vdda-phy", .init_load_uA = 42800 }, + { .supply = "vdda-pll", .init_load_uA = 13900 } + }, .clock = { "soc_ahb", "cpas_ahb", "csiphy2", "csiphy2_timer" }, .clock_rate = { { 0 }, @@ -1302,7 +1351,10 @@ static const struct camss_subdev_resources csiphy_res_845[] = { static const struct camss_subdev_resources csid_res_845[] = { /* CSID0 */ { - .regulators = { "vdda-phy", "vdda-pll" }, + .regulators = { + { .supply = "vdda-phy", .init_load_uA = 0 }, + { .supply = "vdda-pll", .init_load_uA = 0 } + }, .clock = { "cpas_ahb", "cphy_rx_src", "slow_ahb_src", "soc_ahb", "vfe0", "vfe0_src", "vfe0_cphy_rx", "csi0", @@ -1327,7 +1379,10 @@ static const struct camss_subdev_resources csid_res_845[] = { /* CSID1 */ { - .regulators = { "vdda-phy", "vdda-pll" }, + .regulators = { + { .supply = "vdda-phy", .init_load_uA = 0 }, + { .supply = "vdda-pll", .init_load_uA = 0 } + }, .clock = { "cpas_ahb", "cphy_rx_src", "slow_ahb_src", "soc_ahb", "vfe1", "vfe1_src", "vfe1_cphy_rx", "csi1", @@ -1352,7 +1407,10 @@ static const struct camss_subdev_resources csid_res_845[] = { /* CSID2 */ { - .regulators = { "vdda-phy", "vdda-pll" }, + .regulators = { + { .supply = "vdda-phy", .init_load_uA = 0 }, + { .supply = "vdda-pll", .init_load_uA = 0 } + }, .clock = { "cpas_ahb", "cphy_rx_src", "slow_ahb_src", "soc_ahb", "vfe_lite", "vfe_lite_src", "vfe_lite_cphy_rx", "csi2", @@ -1464,7 +1522,10 @@ static const struct camss_subdev_resources vfe_res_845[] = { static const struct camss_subdev_resources csiphy_res_8250[] = { /* CSIPHY0 */ { - .regulators = { "vdda-phy", "vdda-pll" }, + .regulators = { + { .supply = "vdda-phy", .init_load_uA = 17500 }, + { .supply = "vdda-pll", .init_load_uA = 10000 } + }, .clock = { "csiphy0", "csiphy0_timer" }, .clock_rate = { { 400000000 }, { 300000000 } }, @@ -1478,7 +1539,10 @@ static const struct camss_subdev_resources csiphy_res_8250[] = { }, /* CSIPHY1 */ { - .regulators = { "vdda-phy", "vdda-pll" }, + .regulators = { + { .supply = "vdda-phy", .init_load_uA = 17500 }, + { .supply = "vdda-pll", .init_load_uA = 10000 } + }, .clock = { "csiphy1", "csiphy1_timer" }, .clock_rate = { { 400000000 }, { 300000000 } }, @@ -1492,7 +1556,10 @@ static const struct camss_subdev_resources csiphy_res_8250[] = { }, /* CSIPHY2 */ { - .regulators = { "vdda-phy", "vdda-pll" }, + .regulators = { + { .supply = "vdda-phy", .init_load_uA = 17500 }, + { .supply = "vdda-pll", .init_load_uA = 10000 } + }, .clock = { "csiphy2", "csiphy2_timer" }, .clock_rate = { { 400000000 }, { 300000000 } }, @@ -1506,7 +1573,10 @@ static const struct camss_subdev_resources csiphy_res_8250[] = { }, /* CSIPHY3 */ { - .regulators = { "vdda-phy", "vdda-pll" }, + .regulators = { + { .supply = "vdda-phy", .init_load_uA = 17500 }, + { .supply = "vdda-pll", .init_load_uA = 10000 } + }, .clock = { "csiphy3", "csiphy3_timer" }, .clock_rate = { { 400000000 }, { 300000000 } }, @@ -1520,7 +1590,10 @@ static const struct camss_subdev_resources csiphy_res_8250[] = { }, /* CSIPHY4 */ { - .regulators = { "vdda-phy", "vdda-pll" }, + .regulators = { + { .supply = "vdda-phy", .init_load_uA = 17500 }, + { .supply = "vdda-pll", .init_load_uA = 10000 } + }, .clock = { "csiphy4", "csiphy4_timer" }, .clock_rate = { { 400000000 }, { 300000000 } }, @@ -1534,7 +1607,10 @@ static const struct camss_subdev_resources csiphy_res_8250[] = { }, /* CSIPHY5 */ { - .regulators = { "vdda-phy", "vdda-pll" }, + .regulators = { + { .supply = "vdda-phy", .init_load_uA = 17500 }, + { .supply = "vdda-pll", .init_load_uA = 10000 } + }, .clock = { "csiphy5", "csiphy5_timer" }, .clock_rate = { { 400000000 }, { 300000000 } }, @@ -1748,7 +1824,10 @@ static const struct resources_icc icc_res_sm8250[] = { static const struct camss_subdev_resources csiphy_res_7280[] = { /* CSIPHY0 */ { - .regulators = { "vdda-phy", "vdda-pll" }, + .regulators = { + { .supply = "vdda-phy", .init_load_uA = 16100 }, + { .supply = "vdda-pll", .init_load_uA = 9000 } + }, .clock = { "csiphy0", "csiphy0_timer" }, .clock_rate = { { 300000000, 400000000 }, @@ -1763,7 +1842,10 @@ static const struct camss_subdev_resources csiphy_res_7280[] = { }, /* CSIPHY1 */ { - .regulators = { "vdda-phy", "vdda-pll" }, + .regulators = { + { .supply = "vdda-phy", .init_load_uA = 16100 }, + { .supply = "vdda-pll", .init_load_uA = 9000 } + }, .clock = { "csiphy1", "csiphy1_timer" }, .clock_rate = { { 300000000, 400000000 }, @@ -1778,7 +1860,10 @@ static const struct camss_subdev_resources csiphy_res_7280[] = { }, /* CSIPHY2 */ { - .regulators = { "vdda-phy", "vdda-pll" }, + .regulators = { + { .supply = "vdda-phy", .init_load_uA = 16100 }, + { .supply = "vdda-pll", .init_load_uA = 9000 } + }, .clock = { "csiphy2", "csiphy2_timer" }, .clock_rate = { { 300000000, 400000000 }, @@ -1793,7 +1878,10 @@ static const struct camss_subdev_resources csiphy_res_7280[] = { }, /* CSIPHY3 */ { - .regulators = { "vdda-phy", "vdda-pll" }, + .regulators = { + { .supply = "vdda-phy", .init_load_uA = 16100 }, + { .supply = "vdda-pll", .init_load_uA = 9000 } + }, .clock = { "csiphy3", "csiphy3_timer" }, .clock_rate = { { 300000000, 400000000 }, @@ -1808,7 +1896,10 @@ static const struct camss_subdev_resources csiphy_res_7280[] = { }, /* CSIPHY4 */ { - .regulators = { "vdda-phy", "vdda-pll" }, + .regulators = { + { .supply = "vdda-phy", .init_load_uA = 16100 }, + { .supply = "vdda-pll", .init_load_uA = 9000 } + }, .clock = { "csiphy4", "csiphy4_timer" }, .clock_rate = { { 300000000, 400000000 }, @@ -2121,7 +2212,10 @@ static const struct camss_subdev_resources csiphy_res_sc8280xp[] = { static const struct camss_subdev_resources csid_res_sc8280xp[] = { /* CSID0 */ { - .regulators = { "vdda-phy", "vdda-pll" }, + .regulators = { + { .supply = "vdda-phy", .init_load_uA = 0 }, + { .supply = "vdda-pll", .init_load_uA = 0 } + }, .clock = { "vfe0_csid", "vfe0_cphy_rx", "vfe0", "vfe0_axi" }, .clock_rate = { { 400000000, 480000000, 600000000 }, { 0 }, @@ -2137,7 +2231,10 @@ static const struct camss_subdev_resources csid_res_sc8280xp[] = { }, /* CSID1 */ { - .regulators = { "vdda-phy", "vdda-pll" }, + .regulators = { + { .supply = "vdda-phy", .init_load_uA = 0 }, + { .supply = "vdda-pll", .init_load_uA = 0 } + }, .clock = { "vfe1_csid", "vfe1_cphy_rx", "vfe1", "vfe1_axi" }, .clock_rate = { { 400000000, 480000000, 600000000 }, { 0 }, @@ -2153,7 +2250,10 @@ static const struct camss_subdev_resources csid_res_sc8280xp[] = { }, /* CSID2 */ { - .regulators = { "vdda-phy", "vdda-pll" }, + .regulators = { + { .supply = "vdda-phy", .init_load_uA = 0 }, + { .supply = "vdda-pll", .init_load_uA = 0 } + }, .clock = { "vfe2_csid", "vfe2_cphy_rx", "vfe2", "vfe2_axi" }, .clock_rate = { { 400000000, 480000000, 600000000 }, { 0 }, @@ -2169,7 +2269,10 @@ static const struct camss_subdev_resources csid_res_sc8280xp[] = { }, /* CSID3 */ { - .regulators = { "vdda-phy", "vdda-pll" }, + .regulators = { + { .supply = "vdda-phy", .init_load_uA = 0 }, + { .supply = "vdda-pll", .init_load_uA = 0 } + }, .clock = { "vfe3_csid", "vfe3_cphy_rx", "vfe3", "vfe3_axi" }, .clock_rate = { { 400000000, 480000000, 600000000 }, { 0 }, @@ -2185,7 +2288,10 @@ static const struct camss_subdev_resources csid_res_sc8280xp[] = { }, /* CSID_LITE0 */ { - .regulators = { "vdda-phy", "vdda-pll" }, + .regulators = { + { .supply = "vdda-phy", .init_load_uA = 0 }, + { .supply = "vdda-pll", .init_load_uA = 0 } + }, .clock = { "vfe_lite0_csid", "vfe_lite0_cphy_rx", "vfe_lite0" }, .clock_rate = { { 400000000, 480000000, 600000000 }, { 0 }, @@ -2201,7 +2307,10 @@ static const struct camss_subdev_resources csid_res_sc8280xp[] = { }, /* CSID_LITE1 */ { - .regulators = { "vdda-phy", "vdda-pll" }, + .regulators = { + { .supply = "vdda-phy", .init_load_uA = 0 }, + { .supply = "vdda-pll", .init_load_uA = 0 } + }, .clock = { "vfe_lite1_csid", "vfe_lite1_cphy_rx", "vfe_lite1" }, .clock_rate = { { 400000000, 480000000, 600000000 }, { 0 }, @@ -2217,7 +2326,10 @@ static const struct camss_subdev_resources csid_res_sc8280xp[] = { }, /* CSID_LITE2 */ { - .regulators = { "vdda-phy", "vdda-pll" }, + .regulators = { + { .supply = "vdda-phy", .init_load_uA = 0 }, + { .supply = "vdda-pll", .init_load_uA = 0 } + }, .clock = { "vfe_lite2_csid", "vfe_lite2_cphy_rx", "vfe_lite2" }, .clock_rate = { { 400000000, 480000000, 600000000 }, { 0 }, @@ -2233,7 +2345,10 @@ static const struct camss_subdev_resources csid_res_sc8280xp[] = { }, /* CSID_LITE3 */ { - .regulators = { "vdda-phy", "vdda-pll" }, + .regulators = { + { .supply = "vdda-phy", .init_load_uA = 0 }, + { .supply = "vdda-pll", .init_load_uA = 0 } + }, .clock = { "vfe_lite3_csid", "vfe_lite3_cphy_rx", "vfe_lite3" }, .clock_rate = { { 400000000, 480000000, 600000000 }, { 0 }, @@ -2434,7 +2549,10 @@ static const struct resources_icc icc_res_sc8280xp[] = { static const struct camss_subdev_resources csiphy_res_8550[] = { /* CSIPHY0 */ { - .regulators = { "vdda-phy", "vdda-pll" }, + .regulators = { + { .supply = "vdda-phy", .init_load_uA = 32200 }, + { .supply = "vdda-pll", .init_load_uA = 18000 } + }, .clock = { "csiphy0", "csiphy0_timer" }, .clock_rate = { { 400000000, 480000000 }, { 400000000 } }, @@ -2448,7 +2566,10 @@ static const struct camss_subdev_resources csiphy_res_8550[] = { }, /* CSIPHY1 */ { - .regulators = { "vdda-phy", "vdda-pll" }, + .regulators = { + { .supply = "vdda-phy", .init_load_uA = 32200 }, + { .supply = "vdda-pll", .init_load_uA = 18000 } + }, .clock = { "csiphy1", "csiphy1_timer" }, .clock_rate = { { 400000000, 480000000 }, { 400000000 } }, @@ -2462,7 +2583,10 @@ static const struct camss_subdev_resources csiphy_res_8550[] = { }, /* CSIPHY2 */ { - .regulators = { "vdda-phy", "vdda-pll" }, + .regulators = { + { .supply = "vdda-phy", .init_load_uA = 32200 }, + { .supply = "vdda-pll", .init_load_uA = 18000 } + }, .clock = { "csiphy2", "csiphy2_timer" }, .clock_rate = { { 400000000, 480000000 }, { 400000000 } }, @@ -2476,7 +2600,10 @@ static const struct camss_subdev_resources csiphy_res_8550[] = { }, /* CSIPHY3 */ { - .regulators = { "vdda-phy", "vdda-pll" }, + .regulators = { + { .supply = "vdda-phy", .init_load_uA = 32200 }, + { .supply = "vdda-pll", .init_load_uA = 18000 } + }, .clock = { "csiphy3", "csiphy3_timer" }, .clock_rate = { { 400000000, 480000000 }, { 400000000 } }, @@ -2490,7 +2617,10 @@ static const struct camss_subdev_resources csiphy_res_8550[] = { }, /* CSIPHY4 */ { - .regulators = { "vdda-phy", "vdda-pll" }, + .regulators = { + { .supply = "vdda-phy", .init_load_uA = 37900 }, + { .supply = "vdda-pll", .init_load_uA = 18600 } + }, .clock = { "csiphy4", "csiphy4_timer" }, .clock_rate = { { 400000000, 480000000 }, { 400000000 } }, @@ -2504,7 +2634,10 @@ static const struct camss_subdev_resources csiphy_res_8550[] = { }, /* CSIPHY5 */ { - .regulators = { "vdda-phy", "vdda-pll" }, + .regulators = { + { .supply = "vdda-phy", .init_load_uA = 32200 }, + { .supply = "vdda-pll", .init_load_uA = 18000 } + }, .clock = { "csiphy5", "csiphy5_timer" }, .clock_rate = { { 400000000, 480000000 }, { 400000000 } }, @@ -2518,7 +2651,10 @@ static const struct camss_subdev_resources csiphy_res_8550[] = { }, /* CSIPHY6 */ { - .regulators = { "vdda-phy", "vdda-pll" }, + .regulators = { + { .supply = "vdda-phy", .init_load_uA = 37900 }, + { .supply = "vdda-pll", .init_load_uA = 18600 } + }, .clock = { "csiphy6", "csiphy6_timer" }, .clock_rate = { { 400000000, 480000000 }, { 400000000 } }, @@ -2532,7 +2668,10 @@ static const struct camss_subdev_resources csiphy_res_8550[] = { }, /* CSIPHY7 */ { - .regulators = { "vdda-phy", "vdda-pll" }, + .regulators = { + { .supply = "vdda-phy", .init_load_uA = 32200 }, + { .supply = "vdda-pll", .init_load_uA = 18000 } + }, .clock = { "csiphy7", "csiphy7_timer" }, .clock_rate = { { 400000000, 480000000 }, { 400000000 } }, @@ -2763,7 +2902,10 @@ static const struct resources_icc icc_res_sm8550[] = { static const struct camss_subdev_resources csiphy_res_sm8650[] = { /* CSIPHY0 */ { - .regulators = { "vdd-csiphy01-0p9", "vdd-csiphy01-1p2", }, + .regulators = { + { .supply = "vdd-csiphy01-0p9", .init_load_uA = 88000 }, + { .supply = "vdd-csiphy01-1p2", .init_load_uA = 17800 }, + }, .clock = { "csiphy0", "csiphy0_timer" }, .clock_rate = { { 400000000 }, { 400000000 } }, @@ -2777,7 +2919,10 @@ static const struct camss_subdev_resources csiphy_res_sm8650[] = { }, /* CSIPHY1 */ { - .regulators = { "vdd-csiphy01-0p9", "vdd-csiphy01-1p2", }, + .regulators = { + { .supply = "vdd-csiphy01-0p9", .init_load_uA = 88000 }, + { .supply = "vdd-csiphy01-1p2", .init_load_uA = 17800 }, + }, .clock = { "csiphy1", "csiphy1_timer" }, .clock_rate = { { 400000000 }, { 400000000 } }, @@ -2791,7 +2936,10 @@ static const struct camss_subdev_resources csiphy_res_sm8650[] = { }, /* CSIPHY2 */ { - .regulators = { "vdd-csiphy24-0p9", "vdd-csiphy24-1p2", }, + .regulators = { + { .supply = "vdd-csiphy24-0p9", .init_load_uA = 147000 }, + { .supply = "vdd-csiphy24-1p2", .init_load_uA = 24400 }, + }, .clock = { "csiphy2", "csiphy2_timer" }, .clock_rate = { { 400000000 }, { 400000000 } }, @@ -2805,7 +2953,10 @@ static const struct camss_subdev_resources csiphy_res_sm8650[] = { }, /* CSIPHY3 */ { - .regulators = { "vdd-csiphy35-0p9", "vdd-csiphy35-1p2", }, + .regulators = { + { .supply = "vdd-csiphy35-0p9", .init_load_uA = 88000 }, + { .supply = "vdd-csiphy35-1p2", .init_load_uA = 17800 }, + }, .clock = { "csiphy3", "csiphy3_timer" }, .clock_rate = { { 400000000 }, { 400000000 } }, @@ -2819,7 +2970,10 @@ static const struct camss_subdev_resources csiphy_res_sm8650[] = { }, /* CSIPHY4 */ { - .regulators = { "vdd-csiphy24-0p9", "vdd-csiphy24-1p2", }, + .regulators = { + { .supply = "vdd-csiphy24-0p9", .init_load_uA = 147000 }, + { .supply = "vdd-csiphy24-1p2", .init_load_uA = 24400 }, + }, .clock = { "csiphy4", "csiphy4_timer" }, .clock_rate = { { 400000000 }, { 400000000 } }, @@ -2833,7 +2987,10 @@ static const struct camss_subdev_resources csiphy_res_sm8650[] = { }, /* CSIPHY5 */ { - .regulators = { "vdd-csiphy35-0p9", "vdd-csiphy35-1p2", }, + .regulators = { + { .supply = "vdd-csiphy35-0p9", .init_load_uA = 88000 }, + { .supply = "vdd-csiphy35-1p2", .init_load_uA = 17800 }, + }, .clock = { "csiphy5", "csiphy5_timer" }, .clock_rate = { { 400000000 }, { 400000000 } }, @@ -3074,7 +3231,10 @@ static const struct resources_icc icc_res_sm8650[] = { static const struct camss_subdev_resources csiphy_res_8300[] = { /* CSIPHY0 */ { - .regulators = { "vdda-phy", "vdda-pll" }, + .regulators = { + { .supply = "vdda-phy", .init_load_uA = 15900 }, + { .supply = "vdda-pll", .init_load_uA = 8900 } + }, .clock = { "csiphy_rx", "csiphy0", "csiphy0_timer" }, .clock_rate = { @@ -3092,7 +3252,10 @@ static const struct camss_subdev_resources csiphy_res_8300[] = { }, /* CSIPHY1 */ { - .regulators = { "vdda-phy", "vdda-pll" }, + .regulators = { + { .supply = "vdda-phy", .init_load_uA = 15900 }, + { .supply = "vdda-pll", .init_load_uA = 8900 } + }, .clock = { "csiphy_rx", "csiphy1", "csiphy1_timer" }, .clock_rate = { @@ -3110,7 +3273,10 @@ static const struct camss_subdev_resources csiphy_res_8300[] = { }, /* CSIPHY2 */ { - .regulators = { "vdda-phy", "vdda-pll" }, + .regulators = { + { .supply = "vdda-phy", .init_load_uA = 15900 }, + { .supply = "vdda-pll", .init_load_uA = 8900 } + }, .clock = { "csiphy_rx", "csiphy2", "csiphy2_timer" }, .clock_rate = { @@ -3131,7 +3297,10 @@ static const struct camss_subdev_resources csiphy_res_8300[] = { static const struct camss_subdev_resources csiphy_res_8775p[] = { /* CSIPHY0 */ { - .regulators = { "vdda-phy", "vdda-pll" }, + .regulators = { + { .supply = "vdda-phy", .init_load_uA = 15900 }, + { .supply = "vdda-pll", .init_load_uA = 8900 } + }, .clock = { "csiphy_rx", "csiphy0", "csiphy0_timer"}, .clock_rate = { { 400000000 }, @@ -3148,7 +3317,10 @@ static const struct camss_subdev_resources csiphy_res_8775p[] = { }, /* CSIPHY1 */ { - .regulators = { "vdda-phy", "vdda-pll" }, + .regulators = { + { .supply = "vdda-phy", .init_load_uA = 15900 }, + { .supply = "vdda-pll", .init_load_uA = 8900 } + }, .clock = { "csiphy_rx", "csiphy1", "csiphy1_timer"}, .clock_rate = { { 400000000 }, @@ -3165,7 +3337,10 @@ static const struct camss_subdev_resources csiphy_res_8775p[] = { }, /* CSIPHY2 */ { - .regulators = { "vdda-phy", "vdda-pll" }, + .regulators = { + { .supply = "vdda-phy", .init_load_uA = 15900 }, + { .supply = "vdda-pll", .init_load_uA = 8900 } + }, .clock = { "csiphy_rx", "csiphy2", "csiphy2_timer"}, .clock_rate = { { 400000000 }, @@ -3182,7 +3357,10 @@ static const struct camss_subdev_resources csiphy_res_8775p[] = { }, /* CSIPHY3 */ { - .regulators = { "vdda-phy", "vdda-pll" }, + .regulators = { + { .supply = "vdda-phy", .init_load_uA = 15900 }, + { .supply = "vdda-pll", .init_load_uA = 8900 } + }, .clock = { "csiphy_rx", "csiphy3", "csiphy3_timer"}, .clock_rate = { { 400000000 }, @@ -3535,8 +3713,10 @@ static const struct resources_icc icc_res_sa8775p[] = { static const struct camss_subdev_resources csiphy_res_x1e80100[] = { /* CSIPHY0 */ { - .regulators = { "vdd-csiphy-0p8", - "vdd-csiphy-1p2" }, + .regulators = { + { .supply = "vdd-csiphy-0p8", .init_load_uA = 105000 }, + { .supply = "vdd-csiphy-1p2", .init_load_uA = 58900 } + }, .clock = { "csiphy0", "csiphy0_timer" }, .clock_rate = { { 300000000, 400000000, 480000000 }, { 266666667, 400000000 } }, @@ -3550,8 +3730,10 @@ static const struct camss_subdev_resources csiphy_res_x1e80100[] = { }, /* CSIPHY1 */ { - .regulators = { "vdd-csiphy-0p8", - "vdd-csiphy-1p2" }, + .regulators = { + { .supply = "vdd-csiphy-0p8", .init_load_uA = 105000 }, + { .supply = "vdd-csiphy-1p2", .init_load_uA = 58900 } + }, .clock = { "csiphy1", "csiphy1_timer" }, .clock_rate = { { 300000000, 400000000, 480000000 }, { 266666667, 400000000 } }, @@ -3565,8 +3747,10 @@ static const struct camss_subdev_resources csiphy_res_x1e80100[] = { }, /* CSIPHY2 */ { - .regulators = { "vdd-csiphy-0p8", - "vdd-csiphy-1p2" }, + .regulators = { + { .supply = "vdd-csiphy-0p8", .init_load_uA = 105000 }, + { .supply = "vdd-csiphy-1p2", .init_load_uA = 58900 } + }, .clock = { "csiphy2", "csiphy2_timer" }, .clock_rate = { { 300000000, 400000000, 480000000 }, { 266666667, 400000000 } }, @@ -3580,8 +3764,10 @@ static const struct camss_subdev_resources csiphy_res_x1e80100[] = { }, /* CSIPHY4 */ { - .regulators = { "vdd-csiphy-0p8", - "vdd-csiphy-1p2" }, + .regulators = { + { .supply = "vdd-csiphy-0p8", .init_load_uA = 105000 }, + { .supply = "vdd-csiphy-1p2", .init_load_uA = 58900 } + }, .clock = { "csiphy4", "csiphy4_timer" }, .clock_rate = { { 300000000, 400000000, 480000000 }, { 266666667, 400000000 } }, diff --git a/drivers/media/platform/qcom/camss/camss.h b/drivers/media/platform/qcom/camss/camss.h index 9d9a62640e25d..e34f06b4e1536 100644 --- a/drivers/media/platform/qcom/camss/camss.h +++ b/drivers/media/platform/qcom/camss/camss.h @@ -44,7 +44,7 @@ #define CAMSS_INIT_BUF_COUNT 2 struct camss_subdev_resources { - char *regulators[CAMSS_RES_MAX]; + struct regulator_bulk_data regulators[CAMSS_RES_MAX]; char *clock[CAMSS_RES_MAX]; char *clock_for_reset[CAMSS_RES_MAX]; u32 clock_rate[CAMSS_RES_MAX][CAMSS_RES_MAX]; From 9bbe0ca320208de85718fe276cb451d80c21d9e4 Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy Date: Mon, 20 Oct 2025 17:02:27 +0300 Subject: [PATCH 2174/2333] FROMGIT: media: qcom: camss: Do not enable cpas fast ahb clock for SM8550 VFE lite The clock is needed to stream images over a full VFE IP on SM8550 CAMSS, and it should not be enabled, when an image stream is routed over any of two lite VFE IPs on the SoC. Link: https://lore.kernel.org/all/20251020140227.2264634-1-vladimir.zapolskiy@linaro.org/ Signed-off-by: Vladimir Zapolskiy Acked-by: Bryan O'Donoghue --- drivers/media/platform/qcom/camss/camss.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c index 5a97e69acb995..bb4449dd41f2f 100644 --- a/drivers/media/platform/qcom/camss/camss.c +++ b/drivers/media/platform/qcom/camss/camss.c @@ -2843,12 +2843,11 @@ static const struct camss_subdev_resources vfe_res_8550[] = { /* VFE3 lite */ { .regulators = {}, - .clock = { "gcc_axi_hf", "cpas_ahb", "cpas_fast_ahb_clk", "vfe_lite_ahb", + .clock = { "gcc_axi_hf", "cpas_ahb", "vfe_lite_ahb", "vfe_lite", "cpas_ife_lite", "camnoc_axi" }, .clock_rate = { { 0 }, { 80000000 }, { 300000000, 400000000 }, - { 300000000, 400000000 }, { 400000000, 480000000 }, { 300000000, 400000000 }, { 300000000, 400000000 } }, @@ -2865,12 +2864,11 @@ static const struct camss_subdev_resources vfe_res_8550[] = { /* VFE4 lite */ { .regulators = {}, - .clock = { "gcc_axi_hf", "cpas_ahb", "cpas_fast_ahb_clk", "vfe_lite_ahb", + .clock = { "gcc_axi_hf", "cpas_ahb", "vfe_lite_ahb", "vfe_lite", "cpas_ife_lite", "camnoc_axi" }, .clock_rate = { { 0 }, { 80000000 }, { 300000000, 400000000 }, - { 300000000, 400000000 }, { 400000000, 480000000 }, { 300000000, 400000000 }, { 300000000, 400000000 } }, From ba6fc5ad1bf3ea0b71f50e3b13262101112fbda9 Mon Sep 17 00:00:00 2001 From: Loic Poulain Date: Thu, 11 Dec 2025 14:59:39 +0100 Subject: [PATCH 2175/2333] FROMGIT: media: qcom: camss: csid-340: Fix unused variables The CSID driver has some unused variables and function parameters that are no longer needed (due to refactoring). Clean up those unused elements: - Remove the `vc` parameter from `__csid_configure_rx()`. - Drop the unused `lane_cnt` variable. - Adjust call to `__csid_configure_rx()` accordingly. Link: https://lore.kernel.org/all/20251211135939.1779544-1-loic.poulain@oss.qualcomm.com/ Signed-off-by: Loic Poulain Reviewed-by: Bryan O'Donoghue Reviewed-by: Vladimir Zapolskiy --- drivers/media/platform/qcom/camss/camss-csid-340.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/media/platform/qcom/camss/camss-csid-340.c b/drivers/media/platform/qcom/camss/camss-csid-340.c index 22a30510fb792..2b50f9b96a34e 100644 --- a/drivers/media/platform/qcom/camss/camss-csid-340.c +++ b/drivers/media/platform/qcom/camss/camss-csid-340.c @@ -55,8 +55,7 @@ #define CSID_RDI_CTRL_HALT_AT_FRAME_BOUNDARY 0 #define CSID_RDI_CTRL_RESUME_AT_FRAME_BOUNDARY 1 -static void __csid_configure_rx(struct csid_device *csid, - struct csid_phy_config *phy, int vc) +static void __csid_configure_rx(struct csid_device *csid, struct csid_phy_config *phy) { u32 val; @@ -81,13 +80,9 @@ static void __csid_configure_rdi_stream(struct csid_device *csid, u8 enable, u8 const struct csid_format_info *format = csid_get_fmt_entry(csid->res->formats->formats, csid->res->formats->nformats, input_format->code); - u8 lane_cnt = csid->phy.lane_cnt; u8 dt_id; u32 val; - if (!lane_cnt) - lane_cnt = 4; - /* * DT_ID is a two bit bitfield that is concatenated with * the four least significant bits of the five bit VC @@ -120,10 +115,11 @@ static void csid_configure_stream(struct csid_device *csid, u8 enable) { int i; + __csid_configure_rx(csid, &csid->phy); + for (i = 0; i < MSM_CSID_MAX_SRC_STREAMS; i++) { if (csid->phy.en_vc & BIT(i)) { __csid_configure_rdi_stream(csid, enable, i); - __csid_configure_rx(csid, &csid->phy, i); __csid_ctrl_rdi(csid, enable, i); } } From 5088c0ae11cf16480abc6fe24a1f004205200362 Mon Sep 17 00:00:00 2001 From: Alper Ak Date: Mon, 29 Dec 2025 10:52:17 +0300 Subject: [PATCH 2176/2333] FROMGIT: media: qcom: camss: vfe: Fix out-of-bounds access in vfe_isr_reg_update() vfe_isr() iterates using MSM_VFE_IMAGE_MASTERS_NUM(7) as the loop bound and passes the index to vfe_isr_reg_update(). However, vfe->line[] array is defined with VFE_LINE_NUM_MAX(4): struct vfe_line line[VFE_LINE_NUM_MAX]; When index is 4, 5, 6, the access to vfe->line[line_id] exceeds the array bounds and resulting in out-of-bounds memory access. Fix this by using separate loops for output lines and write masters. Fixes: 4edc8eae715c ("media: camss: Add initial support for VFE hardware version Titan 480") Link: https://lore.kernel.org/all/20251229075217.24679-1-alperyasinak1@gmail.com/ Signed-off-by: Alper Ak Reviewed-by: Bryan O'Donoghue --- drivers/media/platform/qcom/camss/camss-vfe-480.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/qcom/camss/camss-vfe-480.c b/drivers/media/platform/qcom/camss/camss-vfe-480.c index 4feea590a47bc..d73f733fde045 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe-480.c +++ b/drivers/media/platform/qcom/camss/camss-vfe-480.c @@ -202,11 +202,13 @@ static irqreturn_t vfe_isr(int irq, void *dev) writel_relaxed(status, vfe->base + VFE_BUS_IRQ_CLEAR(0)); writel_relaxed(1, vfe->base + VFE_BUS_IRQ_CLEAR_GLOBAL); - /* Loop through all WMs IRQs */ - for (i = 0; i < MSM_VFE_IMAGE_MASTERS_NUM; i++) { + for (i = 0; i < MAX_VFE_OUTPUT_LINES; i++) { if (status & BUS_IRQ_MASK_0_RDI_RUP(vfe, i)) vfe_isr_reg_update(vfe, i); + } + /* Loop through all WMs IRQs */ + for (i = 0; i < MSM_VFE_IMAGE_MASTERS_NUM; i++) { if (status & BUS_IRQ_MASK_0_COMP_DONE(vfe, RDI_COMP_GROUP(i))) vfe_buf_done(vfe, i); } From 97c513549c9a7f81fd2c505daee6963db469b5db Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy Date: Thu, 20 Nov 2025 02:46:03 +0200 Subject: [PATCH 2177/2333] FROMGIT: media: qcom: camss: change internals of endpoint parsing to fwnode handling Since a few called V4L2 functions operate with fwnode arguments the change from OF device nodes to fwnodes brings a simplification to the code. The camss_parse_endpoint_node() function is called once by camss_probe(), and there is no use of knowing a number of asynchronously registered remote devices, so it makes sense to remove the related computation from the function. Link: https://lore.kernel.org/all/20251120004604.2573803-2-vladimir.zapolskiy@linaro.org/ Tested-by: Loic Poulain Signed-off-by: Vladimir Zapolskiy --- drivers/media/platform/qcom/camss/camss.c | 49 +++++++++++------------ 1 file changed, 23 insertions(+), 26 deletions(-) diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c index bb4449dd41f2f..dd27d99242bc4 100644 --- a/drivers/media/platform/qcom/camss/camss.c +++ b/drivers/media/platform/qcom/camss/camss.c @@ -4206,16 +4206,16 @@ static const struct parent_dev_ops vfe_parent_dev_ops = { }; /* - * camss_of_parse_endpoint_node - Parse port endpoint node - * @dev: Device - * @node: Device node to be parsed + * camss_parse_endpoint_node - Parse port endpoint node + * @dev: CAMSS device + * @ep: Device endpoint to be parsed * @csd: Parsed data from port endpoint node * * Return 0 on success or a negative error code on failure */ -static int camss_of_parse_endpoint_node(struct device *dev, - struct device_node *node, - struct camss_async_subdev *csd) +static int camss_parse_endpoint_node(struct device *dev, + struct fwnode_handle *ep, + struct camss_async_subdev *csd) { struct csiphy_lanes_cfg *lncfg = &csd->interface.csi2.lane_cfg; struct v4l2_mbus_config_mipi_csi2 *mipi_csi2; @@ -4223,7 +4223,7 @@ static int camss_of_parse_endpoint_node(struct device *dev, unsigned int i; int ret; - ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(node), &vep); + ret = v4l2_fwnode_endpoint_parse(ep, &vep); if (ret) return ret; @@ -4258,49 +4258,46 @@ static int camss_of_parse_endpoint_node(struct device *dev, } /* - * camss_of_parse_ports - Parse ports node - * @dev: Device - * @notifier: v4l2_device notifier data + * camss_parse_ports - Parse ports node + * @dev: CAMSS device * - * Return number of "port" nodes found in "ports" node + * Return 0 on success or a negative error code on failure */ -static int camss_of_parse_ports(struct camss *camss) +static int camss_parse_ports(struct camss *camss) { struct device *dev = camss->dev; - struct device_node *node = NULL; - struct device_node *remote = NULL; - int ret, num_subdevs = 0; + struct fwnode_handle *fwnode = dev_fwnode(dev), *ep; + int ret; - for_each_endpoint_of_node(dev->of_node, node) { + fwnode_graph_for_each_endpoint(fwnode, ep) { struct camss_async_subdev *csd; + struct fwnode_handle *remote; - remote = of_graph_get_remote_port_parent(node); + remote = fwnode_graph_get_remote_port_parent(ep); if (!remote) { dev_err(dev, "Cannot get remote parent\n"); ret = -EINVAL; goto err_cleanup; } - csd = v4l2_async_nf_add_fwnode(&camss->notifier, - of_fwnode_handle(remote), + csd = v4l2_async_nf_add_fwnode(&camss->notifier, remote, struct camss_async_subdev); - of_node_put(remote); + fwnode_handle_put(remote); if (IS_ERR(csd)) { ret = PTR_ERR(csd); goto err_cleanup; } - ret = camss_of_parse_endpoint_node(dev, node, csd); + ret = camss_parse_endpoint_node(dev, ep, csd); if (ret < 0) goto err_cleanup; - - num_subdevs++; } - return num_subdevs; + return 0; err_cleanup: - of_node_put(node); + fwnode_handle_put(ep); + return ret; } @@ -4857,7 +4854,7 @@ static int camss_probe(struct platform_device *pdev) pm_runtime_enable(dev); - ret = camss_of_parse_ports(camss); + ret = camss_parse_ports(camss); if (ret < 0) goto err_v4l2_device_unregister; From 2a4662001dd1881b7dd4d40185f0457e0657373c Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy Date: Thu, 20 Nov 2025 02:46:04 +0200 Subject: [PATCH 2178/2333] FROMGIT: media: qcom: camss: use a handy v4l2_async_nf_add_fwnode_remote() function Another code simplification makes parsing of remote endpoints easy. Link: https://lore.kernel.org/all/20251120004604.2573803-3-vladimir.zapolskiy@linaro.org/ Tested-by: Loic Poulain Signed-off-by: Vladimir Zapolskiy --- drivers/media/platform/qcom/camss/camss.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c index dd27d99242bc4..3c8535141eaaf 100644 --- a/drivers/media/platform/qcom/camss/camss.c +++ b/drivers/media/platform/qcom/camss/camss.c @@ -4271,18 +4271,9 @@ static int camss_parse_ports(struct camss *camss) fwnode_graph_for_each_endpoint(fwnode, ep) { struct camss_async_subdev *csd; - struct fwnode_handle *remote; - remote = fwnode_graph_get_remote_port_parent(ep); - if (!remote) { - dev_err(dev, "Cannot get remote parent\n"); - ret = -EINVAL; - goto err_cleanup; - } - - csd = v4l2_async_nf_add_fwnode(&camss->notifier, remote, - struct camss_async_subdev); - fwnode_handle_put(remote); + csd = v4l2_async_nf_add_fwnode_remote(&camss->notifier, ep, + typeof(*csd)); if (IS_ERR(csd)) { ret = PTR_ERR(csd); goto err_cleanup; From eaffe887cbeac697c532a30df9dcba0bbc1455b5 Mon Sep 17 00:00:00 2001 From: Wenmeng Liu Date: Mon, 12 Jan 2026 16:04:52 +0800 Subject: [PATCH 2179/2333] FROMGIT: media: dt-bindings: Add qcom,sm6150-camss Add bindings for the Camera Subsystem on the SM6150 SoC The SM6150 platform provides: - 2 x VFE (version 170), each with 3 RDI - 1 x VFE Lite (version 170), each with 4 RDI - 2 x CSID (version 170) - 1 x CSID Lite (version 170) - 3 x CSIPHY (version 2.0.0) - 1 x BPS (Bayer Processing Segment) - 1 x ICP (Imaging Control Processor) - 1 x IPE (Image Postprocessing Engine) - 1 x JPEG Encoder/Decoder - 1 x LRME (Low Resolution Motion Estimation) Link: https://lore.kernel.org/all/20260112-sm6150-camss-v4-1-0cd576d627f7@oss.qualcomm.com/ Reviewed-by: Vladimir Zapolskiy Signed-off-by: Wenmeng Liu Reviewed-by: Krzysztof Kozlowski Reviewed-by: Bryan O'Donoghue --- .../bindings/media/qcom,sm6150-camss.yaml | 439 ++++++++++++++++++ 1 file changed, 439 insertions(+) create mode 100644 Documentation/devicetree/bindings/media/qcom,sm6150-camss.yaml diff --git a/Documentation/devicetree/bindings/media/qcom,sm6150-camss.yaml b/Documentation/devicetree/bindings/media/qcom,sm6150-camss.yaml new file mode 100644 index 0000000000000..ba7b0acb9128b --- /dev/null +++ b/Documentation/devicetree/bindings/media/qcom,sm6150-camss.yaml @@ -0,0 +1,439 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/qcom,sm6150-camss.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm SM6150 Camera Subsystem (CAMSS) + +maintainers: + - Wenmeng Liu + +description: + This binding describes the camera subsystem hardware found on SM6150 + Qualcomm SoCs. It includes submodules such as CSIPHY (CSI Physical layer) + and CSID (CSI Decoder), which comply with the MIPI CSI2 protocol. + + The subsystem also integrates a set of real-time image processing engines + and their associated configuration modules, as well as non-real-time engines. + +properties: + compatible: + const: qcom,sm6150-camss + + reg: + items: + - description: Registers for CSID 0 + - description: Registers for CSID 1 + - description: Registers for CSID Lite + - description: Registers for CSIPHY 0 + - description: Registers for CSIPHY 1 + - description: Registers for CSIPHY 2 + - description: Registers for VFE 0 + - description: Registers for VFE 1 + - description: Registers for VFE Lite + - description: Registers for BPS (Bayer Processing Segment) + - description: Registers for CAMNOC + - description: Registers for CPAS CDM + - description: Registers for CPAS TOP + - description: Registers for ICP (Imaging Control Processor) CSR (Control and Status Registers) + - description: Registers for ICP QGIC (Qualcomm Generic Interrupt Controller) + - description: Registers for ICP SIERRA ((A5 subsystem communication)) + - description: Registers for IPE (Image Postprocessing Engine) 0 + - description: Registers for JPEG DMA + - description: Registers for JPEG ENC + - description: Registers for LRME (Low Resolution Motion Estimation) + + reg-names: + items: + - const: csid0 + - const: csid1 + - const: csid_lite + - const: csiphy0 + - const: csiphy1 + - const: csiphy2 + - const: vfe0 + - const: vfe1 + - const: vfe_lite + - const: bps + - const: camnoc + - const: cpas_cdm + - const: cpas_top + - const: icp_csr + - const: icp_qgic + - const: icp_sierra + - const: ipe0 + - const: jpeg_dma + - const: jpeg_enc + - const: lrme + + clocks: + maxItems: 33 + + clock-names: + items: + - const: gcc_ahb + - const: gcc_axi_hf + - const: camnoc_axi + - const: cpas_ahb + - const: csiphy0 + - const: csiphy0_timer + - const: csiphy1 + - const: csiphy1_timer + - const: csiphy2 + - const: csiphy2_timer + - const: soc_ahb + - const: vfe0 + - const: vfe0_axi + - const: vfe0_cphy_rx + - const: vfe0_csid + - const: vfe1 + - const: vfe1_axi + - const: vfe1_cphy_rx + - const: vfe1_csid + - const: vfe_lite + - const: vfe_lite_cphy_rx + - const: vfe_lite_csid + - const: bps + - const: bps_ahb + - const: bps_axi + - const: bps_areg + - const: icp + - const: ipe0 + - const: ipe0_ahb + - const: ipe0_areg + - const: ipe0_axi + - const: jpeg + - const: lrme + + interrupts: + maxItems: 15 + + interrupt-names: + items: + - const: csid0 + - const: csid1 + - const: csid_lite + - const: csiphy0 + - const: csiphy1 + - const: csiphy2 + - const: vfe0 + - const: vfe1 + - const: vfe_lite + - const: camnoc + - const: cdm + - const: icp + - const: jpeg_dma + - const: jpeg_enc + - const: lrme + + interconnects: + maxItems: 4 + + interconnect-names: + items: + - const: ahb + - const: hf_0 + - const: hf_1 + - const: sf_mnoc + + iommus: + items: + - description: Camera IFE 0 non-protected stream + - description: Camera IFE 1 non-protected stream + - description: Camera IFE 3 non-protected stream + - description: Camera CDM non-protected stream + - description: Camera LRME read non-protected stream + - description: Camera IPE 0 read non-protected stream + - description: Camera BPS read non-protected stream + - description: Camera IPE 0 write non-protected stream + - description: Camera BPS write non-protected stream + - description: Camera LRME write non-protected stream + - description: Camera JPEG read non-protected stream + - description: Camera JPEG write non-protected stream + - description: Camera ICP stream + + power-domains: + items: + - description: + IFE0 GDSC - Image Front End, Global Distributed Switch Controller. + - description: + IFE1 GDSC - Image Front End, Global Distributed Switch Controller. + - description: + Titan GDSC - Titan ISP Block, Global Distributed Switch Controller. + - description: + Titan BPS - Bayer Processing Segment, Global Distributed Switch Controller. + - description: + IPE GDSC - Image Postprocessing Engine, Global Distributed Switch Controller. + + power-domain-names: + items: + - const: ife0 + - const: ife1 + - const: top + - const: bps + - const: ipe + + vdd-csiphy-1p2-supply: + description: + Phandle to a 1.2V regulator supply to CSI PHYs. + + vdd-csiphy-1p8-supply: + description: + Phandle to 1.8V regulator supply to CSI PHYs pll block. + + ports: + $ref: /schemas/graph.yaml#/properties/ports + + description: + CSI input ports. + + patternProperties: + "^port@[0-2]$": + $ref: /schemas/graph.yaml#/$defs/port-base + unevaluatedProperties: false + + description: + Input port for receiving CSI data from a CSIPHY. + + properties: + endpoint: + $ref: video-interfaces.yaml# + unevaluatedProperties: false + + properties: + data-lanes: + minItems: 1 + maxItems: 4 + + required: + - data-lanes + +required: + - compatible + - reg + - reg-names + - clocks + - clock-names + - interrupts + - interrupt-names + - interconnects + - interconnect-names + - iommus + - power-domains + - power-domain-names + +additionalProperties: false + +examples: + - | + #include + #include + #include + #include + #include + #include + #include + + soc { + #address-cells = <2>; + #size-cells = <2>; + + camss: isp@acb3000 { + compatible = "qcom,sm6150-camss"; + + reg = <0x0 0x0acb3000 0x0 0x1000>, + <0x0 0x0acba000 0x0 0x1000>, + <0x0 0x0acc8000 0x0 0x1000>, + <0x0 0x0ac65000 0x0 0x1000>, + <0x0 0x0ac66000 0x0 0x1000>, + <0x0 0x0ac67000 0x0 0x1000>, + <0x0 0x0acaf000 0x0 0x4000>, + <0x0 0x0acb6000 0x0 0x4000>, + <0x0 0x0acc4000 0x0 0x4000>, + <0x0 0x0ac6f000 0x0 0x3000>, + <0x0 0x0ac42000 0x0 0x5000>, + <0x0 0x0ac48000 0x0 0x1000>, + <0x0 0x0ac40000 0x0 0x1000>, + <0x0 0x0ac18000 0x0 0x3000>, + <0x0 0x0ac00000 0x0 0x6000>, + <0x0 0x0ac10000 0x0 0x8000>, + <0x0 0x0ac87000 0x0 0x3000>, + <0x0 0x0ac52000 0x0 0x4000>, + <0x0 0x0ac4e000 0x0 0x4000>, + <0x0 0x0ac6b000 0x0 0x0a00>; + reg-names = "csid0", + "csid1", + "csid_lite", + "csiphy0", + "csiphy1", + "csiphy2", + "vfe0", + "vfe1", + "vfe_lite", + "bps", + "camnoc", + "cpas_cdm", + "cpas_top", + "icp_csr", + "icp_qgic", + "icp_sierra", + "ipe0", + "jpeg_dma", + "jpeg_enc", + "lrme"; + + clocks = <&gcc GCC_CAMERA_AHB_CLK>, + <&gcc GCC_CAMERA_HF_AXI_CLK>, + <&camcc CAM_CC_CAMNOC_AXI_CLK>, + <&camcc CAM_CC_CPAS_AHB_CLK>, + <&camcc CAM_CC_CSIPHY0_CLK>, + <&camcc CAM_CC_CSI0PHYTIMER_CLK>, + <&camcc CAM_CC_CSIPHY1_CLK>, + <&camcc CAM_CC_CSI1PHYTIMER_CLK>, + <&camcc CAM_CC_CSIPHY2_CLK>, + <&camcc CAM_CC_CSI2PHYTIMER_CLK>, + <&camcc CAM_CC_SOC_AHB_CLK>, + <&camcc CAM_CC_IFE_0_CLK>, + <&camcc CAM_CC_IFE_0_AXI_CLK>, + <&camcc CAM_CC_IFE_0_CPHY_RX_CLK>, + <&camcc CAM_CC_IFE_0_CSID_CLK>, + <&camcc CAM_CC_IFE_1_CLK>, + <&camcc CAM_CC_IFE_1_AXI_CLK>, + <&camcc CAM_CC_IFE_1_CPHY_RX_CLK>, + <&camcc CAM_CC_IFE_1_CSID_CLK>, + <&camcc CAM_CC_IFE_LITE_CLK>, + <&camcc CAM_CC_IFE_LITE_CPHY_RX_CLK>, + <&camcc CAM_CC_IFE_LITE_CSID_CLK>, + <&camcc CAM_CC_BPS_CLK>, + <&camcc CAM_CC_BPS_AHB_CLK>, + <&camcc CAM_CC_BPS_AXI_CLK>, + <&camcc CAM_CC_BPS_AREG_CLK>, + <&camcc CAM_CC_ICP_CLK>, + <&camcc CAM_CC_IPE_0_CLK>, + <&camcc CAM_CC_IPE_0_AHB_CLK>, + <&camcc CAM_CC_IPE_0_AREG_CLK>, + <&camcc CAM_CC_IPE_0_AXI_CLK>, + <&camcc CAM_CC_JPEG_CLK>, + <&camcc CAM_CC_LRME_CLK>; + + clock-names = "gcc_ahb", + "gcc_axi_hf", + "camnoc_axi", + "cpas_ahb", + "csiphy0", + "csiphy0_timer", + "csiphy1", + "csiphy1_timer", + "csiphy2", + "csiphy2_timer", + "soc_ahb", + "vfe0", + "vfe0_axi", + "vfe0_cphy_rx", + "vfe0_csid", + "vfe1", + "vfe1_axi", + "vfe1_cphy_rx", + "vfe1_csid", + "vfe_lite", + "vfe_lite_cphy_rx", + "vfe_lite_csid", + "bps", + "bps_ahb", + "bps_axi", + "bps_areg", + "icp", + "ipe0", + "ipe0_ahb", + "ipe0_areg", + "ipe0_axi", + "jpeg", + "lrme"; + + interconnects = <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ACTIVE_ONLY + &config_noc SLAVE_CAMERA_CFG QCOM_ICC_TAG_ACTIVE_ONLY>, + <&mmss_noc MASTER_CAMNOC_HF0 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>, + <&mmss_noc MASTER_CAMNOC_HF1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>, + <&mmss_noc MASTER_CAMNOC_SF QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "ahb", + "hf_0", + "hf_1", + "sf_mnoc"; + + interrupts = , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + interrupt-names = "csid0", + "csid1", + "csid_lite", + "csiphy0", + "csiphy1", + "csiphy2", + "vfe0", + "vfe1", + "vfe_lite", + "camnoc", + "cdm", + "icp", + "jpeg_dma", + "jpeg_enc", + "lrme"; + + iommus = <&apps_smmu 0x0820 0x40>, + <&apps_smmu 0x0840 0x00>, + <&apps_smmu 0x0860 0x40>, + <&apps_smmu 0x0c00 0x00>, + <&apps_smmu 0x0cc0 0x00>, + <&apps_smmu 0x0c80 0x00>, + <&apps_smmu 0x0ca0 0x00>, + <&apps_smmu 0x0d00 0x00>, + <&apps_smmu 0x0d20 0x00>, + <&apps_smmu 0x0d40 0x00>, + <&apps_smmu 0x0d80 0x20>, + <&apps_smmu 0x0da0 0x20>, + <&apps_smmu 0x0de2 0x00>; + + power-domains = <&camcc IFE_0_GDSC>, + <&camcc IFE_1_GDSC>, + <&camcc TITAN_TOP_GDSC>, + <&camcc BPS_GDSC>, + <&camcc IPE_0_GDSC>; + power-domain-names = "ife0", + "ife1", + "top", + "bps", + "ipe"; + + vdd-csiphy-1p2-supply = <&vreg_l11a_1p2>; + vdd-csiphy-1p8-supply = <&vreg_l12a_1p8>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + csiphy_ep0: endpoint { + data-lanes = <0 1>; + remote-endpoint = <&sensor_ep>; + }; + }; + }; + }; + }; From 6bc18fc70e0380e10a9b958dae60997f2b980715 Mon Sep 17 00:00:00 2001 From: Wenmeng Liu Date: Mon, 12 Jan 2026 16:04:53 +0800 Subject: [PATCH 2180/2333] FROMGIT: media: qcom: camss: add support for SM6150 camss The camera subsystem for SM6150 which is based on Spectra 230. For SM6150: - VFE and CSID version: 170 (vfe170, csid170) - CSIPHY version: csiphy-v2.0.1 (14nm) Link: https://lore.kernel.org/all/20260112-sm6150-camss-v4-2-0cd576d627f7@oss.qualcomm.com/ Reviewed-by: Vladimir Zapolskiy Signed-off-by: Wenmeng Liu Reviewed-by: Bryan O'Donoghue --- .../qcom/camss/camss-csiphy-3ph-1-0.c | 2 + drivers/media/platform/qcom/camss/camss-vfe.c | 2 + drivers/media/platform/qcom/camss/camss.c | 198 ++++++++++++++++++ drivers/media/platform/qcom/camss/camss.h | 1 + 4 files changed, 203 insertions(+) diff --git a/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c b/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c index d70d4f6117988..4154832745525 100644 --- a/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c +++ b/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c @@ -1010,6 +1010,7 @@ static bool csiphy_is_gen2(u32 version) switch (version) { case CAMSS_2290: + case CAMSS_6150: case CAMSS_7280: case CAMSS_8250: case CAMSS_8280XP: @@ -1100,6 +1101,7 @@ static int csiphy_init(struct csiphy_device *csiphy) regs->lane_array_size = ARRAY_SIZE(lane_regs_sdm845); break; case CAMSS_2290: + case CAMSS_6150: regs->lane_regs = &lane_regs_qcm2290[0]; regs->lane_array_size = ARRAY_SIZE(lane_regs_qcm2290); break; diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c index 9c7ad8aa40588..5baf0e3d4bc46 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe.c +++ b/drivers/media/platform/qcom/camss/camss-vfe.c @@ -342,6 +342,7 @@ static u32 vfe_src_pad_code(struct vfe_line *line, u32 sink_code, break; case CAMSS_660: case CAMSS_2290: + case CAMSS_6150: case CAMSS_7280: case CAMSS_8x96: case CAMSS_8250: @@ -2001,6 +2002,7 @@ static int vfe_bpl_align(struct vfe_device *vfe) int ret = 8; switch (vfe->camss->res->version) { + case CAMSS_6150: case CAMSS_7280: case CAMSS_8250: case CAMSS_8280XP: diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c index 3c8535141eaaf..4ac23f4e4c00f 100644 --- a/drivers/media/platform/qcom/camss/camss.c +++ b/drivers/media/platform/qcom/camss/camss.c @@ -1519,6 +1519,190 @@ static const struct camss_subdev_resources vfe_res_845[] = { } }; +static const struct camss_subdev_resources csiphy_res_sm6150[] = { + /* CSIPHY0 */ + { + .regulators = { + { .supply = "vdd-csiphy-1p2", .init_load_uA = 35000 }, + { .supply = "vdd-csiphy-1p8", .init_load_uA = 5000 } + }, + .clock = { "csiphy0", "csiphy0_timer" }, + .clock_rate = { { 269333333, 384000000 }, + { 269333333 } }, + .reg = { "csiphy0" }, + .interrupt = { "csiphy0" }, + .csiphy = { + .id = 0, + .hw_ops = &csiphy_ops_3ph_1_0, + .formats = &csiphy_formats_sdm845 + } + }, + /* CSIPHY1 */ + { + .regulators = { + { .supply = "vdd-csiphy-1p2", .init_load_uA = 35000 }, + { .supply = "vdd-csiphy-1p8", .init_load_uA = 5000 } + }, + .clock = { "csiphy1", "csiphy1_timer" }, + .clock_rate = { { 269333333, 384000000 }, + { 269333333 } }, + .reg = { "csiphy1" }, + .interrupt = { "csiphy1" }, + .csiphy = { + .id = 1, + .hw_ops = &csiphy_ops_3ph_1_0, + .formats = &csiphy_formats_sdm845 + } + }, + /* CSIPHY2 */ + { + .regulators = { + { .supply = "vdd-csiphy-1p2", .init_load_uA = 35000 }, + { .supply = "vdd-csiphy-1p8", .init_load_uA = 5000 } + }, + .clock = { "csiphy2", "csiphy2_timer" }, + .clock_rate = { { 269333333, 384000000 }, + { 269333333 } }, + .reg = { "csiphy2" }, + .interrupt = { "csiphy2" }, + .csiphy = { + .id = 2, + .hw_ops = &csiphy_ops_3ph_1_0, + .formats = &csiphy_formats_sdm845 + } + }, +}; + +static const struct camss_subdev_resources csid_res_sm6150[] = { + /* CSID0 */ + { + .regulators = {}, + .clock = { "vfe0_cphy_rx", "vfe0_csid" }, + .clock_rate = { { 269333333, 384000000 }, + { 320000000, 540000000 } }, + .reg = { "csid0" }, + .interrupt = { "csid0" }, + .csid = { + .is_lite = false, + .hw_ops = &csid_ops_gen2, + .parent_dev_ops = &vfe_parent_dev_ops, + .formats = &csid_formats_gen2 + } + }, + /* CSID1 */ + { + .regulators = {}, + .clock = { "vfe1_cphy_rx", "vfe1_csid" }, + .clock_rate = { { 269333333, 384000000 }, + { 320000000, 540000000 } }, + .reg = { "csid1" }, + .interrupt = { "csid1" }, + .csid = { + .is_lite = false, + .hw_ops = &csid_ops_gen2, + .parent_dev_ops = &vfe_parent_dev_ops, + .formats = &csid_formats_gen2 + } + }, + /* CSID2 */ + { + .regulators = {}, + .clock = { "vfe_lite_cphy_rx", "vfe_lite_csid" }, + .clock_rate = { { 269333333, 384000000 }, + { 320000000, 540000000 } }, + .reg = { "csid_lite" }, + .interrupt = { "csid_lite" }, + .csid = { + .is_lite = true, + .hw_ops = &csid_ops_gen2, + .parent_dev_ops = &vfe_parent_dev_ops, + .formats = &csid_formats_gen2 + } + }, +}; + +static const struct camss_subdev_resources vfe_res_sm6150[] = { + /* VFE0 */ + { + .regulators = {}, + .clock = { "gcc_axi_hf", "camnoc_axi", "cpas_ahb", "soc_ahb", + "vfe0", "vfe0_axi"}, + .clock_rate = { { 0 }, + { 0 }, + { 80000000 }, + { 37500000, 40000000 }, + { 360000000, 432000000, 540000000, 600000000 }, + { 265000000, 426000000 } }, + .reg = { "vfe0" }, + .interrupt = { "vfe0" }, + .vfe = { + .line_num = 3, + .is_lite = false, + .has_pd = true, + .pd_name = "ife0", + .hw_ops = &vfe_ops_170, + .formats_rdi = &vfe_formats_rdi_845, + .formats_pix = &vfe_formats_pix_845 + } + }, + /* VFE1 */ + { + .regulators = {}, + .clock = { "gcc_axi_hf", "camnoc_axi", "cpas_ahb", "soc_ahb", + "vfe1", "vfe1_axi"}, + .clock_rate = { { 0 }, + { 0 }, + { 80000000 }, + { 37500000, 40000000 }, + { 360000000, 432000000, 540000000, 600000000 }, + { 265000000, 426000000 } }, + .reg = { "vfe1" }, + .interrupt = { "vfe1" }, + .vfe = { + .line_num = 3, + .is_lite = false, + .has_pd = true, + .pd_name = "ife1", + .hw_ops = &vfe_ops_170, + .formats_rdi = &vfe_formats_rdi_845, + .formats_pix = &vfe_formats_pix_845 + } + }, + /* VFE2 */ + { + .regulators = {}, + .clock = { "gcc_axi_hf", "camnoc_axi", "cpas_ahb", "soc_ahb", + "vfe_lite" }, + .clock_rate = { { 0 }, + { 0 }, + { 80000000 }, + { 37500000, 40000000 }, + { 360000000, 432000000, 540000000, 600000000 } }, + .reg = { "vfe_lite" }, + .interrupt = { "vfe_lite" }, + .vfe = { + .line_num = 4, + .is_lite = true, + .hw_ops = &vfe_ops_170, + .formats_rdi = &vfe_formats_rdi_845, + .formats_pix = &vfe_formats_pix_845 + } + }, +}; + +static const struct resources_icc icc_res_sm6150[] = { + { + .name = "ahb", + .icc_bw_tbl.avg = 38400, + .icc_bw_tbl.peak = 76800, + }, + { + .name = "hf_0", + .icc_bw_tbl.avg = 2097152, + .icc_bw_tbl.peak = 2097152, + }, +}; + static const struct camss_subdev_resources csiphy_res_8250[] = { /* CSIPHY0 */ { @@ -5036,6 +5220,19 @@ static const struct camss_resources sdm845_resources = { .vfe_num = ARRAY_SIZE(vfe_res_845), }; +static const struct camss_resources sm6150_resources = { + .version = CAMSS_6150, + .pd_name = "top", + .csiphy_res = csiphy_res_sm6150, + .csid_res = csid_res_sm6150, + .vfe_res = vfe_res_sm6150, + .icc_res = icc_res_sm6150, + .icc_path_num = ARRAY_SIZE(icc_res_sm6150), + .csiphy_num = ARRAY_SIZE(csiphy_res_sm6150), + .csid_num = ARRAY_SIZE(csid_res_sm6150), + .vfe_num = ARRAY_SIZE(vfe_res_sm6150), +}; + static const struct camss_resources sm8250_resources = { .version = CAMSS_8250, .pd_name = "top", @@ -5131,6 +5328,7 @@ static const struct of_device_id camss_dt_match[] = { { .compatible = "qcom,sdm660-camss", .data = &sdm660_resources }, { .compatible = "qcom,sdm670-camss", .data = &sdm670_resources }, { .compatible = "qcom,sdm845-camss", .data = &sdm845_resources }, + { .compatible = "qcom,sm6150-camss", .data = &sm6150_resources }, { .compatible = "qcom,sm8250-camss", .data = &sm8250_resources }, { .compatible = "qcom,sm8550-camss", .data = &sm8550_resources }, { .compatible = "qcom,sm8650-camss", .data = &sm8650_resources }, diff --git a/drivers/media/platform/qcom/camss/camss.h b/drivers/media/platform/qcom/camss/camss.h index e34f06b4e1536..6d048414c919e 100644 --- a/drivers/media/platform/qcom/camss/camss.h +++ b/drivers/media/platform/qcom/camss/camss.h @@ -80,6 +80,7 @@ enum pm_domain { enum camss_version { CAMSS_660, CAMSS_2290, + CAMSS_6150, CAMSS_7280, CAMSS_8x16, CAMSS_8x39, From 4746b41520140e17da2671ad4b3e97a02f85ee1f Mon Sep 17 00:00:00 2001 From: Wenmeng Liu Date: Thu, 22 Jan 2026 18:48:52 +0800 Subject: [PATCH 2181/2333] FROMLIST: arm64: dts: qcom: talos: Add camss node Add node for the SM6150 camera subsystem. Link: https://lore.kernel.org/all/20260122-sm6150_evk-v5-1-039b170450a3@oss.qualcomm.com/ Reviewed-by: Vladimir Zapolskiy Reviewed-by: Bryan O'Donoghue Signed-off-by: Wenmeng Liu --- arch/arm64/boot/dts/qcom/talos.dtsi | 200 ++++++++++++++++++++++++++++ 1 file changed, 200 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/talos.dtsi b/arch/arm64/boot/dts/qcom/talos.dtsi index bdca52af838b3..b08517507e813 100644 --- a/arch/arm64/boot/dts/qcom/talos.dtsi +++ b/arch/arm64/boot/dts/qcom/talos.dtsi @@ -3929,6 +3929,206 @@ #power-domain-cells = <1>; }; + camss: isp@acb3000 { + compatible = "qcom,sm6150-camss"; + + reg = <0x0 0x0acb3000 0x0 0x1000>, + <0x0 0x0acba000 0x0 0x1000>, + <0x0 0x0acc8000 0x0 0x1000>, + <0x0 0x0ac65000 0x0 0x1000>, + <0x0 0x0ac66000 0x0 0x1000>, + <0x0 0x0ac67000 0x0 0x1000>, + <0x0 0x0acaf000 0x0 0x4000>, + <0x0 0x0acb6000 0x0 0x4000>, + <0x0 0x0acc4000 0x0 0x4000>, + <0x0 0x0ac6f000 0x0 0x3000>, + <0x0 0x0ac42000 0x0 0x5000>, + <0x0 0x0ac48000 0x0 0x1000>, + <0x0 0x0ac40000 0x0 0x1000>, + <0x0 0x0ac18000 0x0 0x3000>, + <0x0 0x0ac00000 0x0 0x6000>, + <0x0 0x0ac10000 0x0 0x8000>, + <0x0 0x0ac87000 0x0 0x3000>, + <0x0 0x0ac52000 0x0 0x4000>, + <0x0 0x0ac4e000 0x0 0x4000>, + <0x0 0x0ac6b000 0x0 0x0a00>; + reg-names = "csid0", + "csid1", + "csid_lite", + "csiphy0", + "csiphy1", + "csiphy2", + "vfe0", + "vfe1", + "vfe_lite", + "bps", + "camnoc", + "cpas_cdm", + "cpas_top", + "icp_csr", + "icp_qgic", + "icp_sierra", + "ipe0", + "jpeg_dma", + "jpeg_enc", + "lrme"; + + clocks = <&gcc GCC_CAMERA_AHB_CLK>, + <&gcc GCC_CAMERA_HF_AXI_CLK>, + <&camcc CAM_CC_CAMNOC_AXI_CLK>, + <&camcc CAM_CC_CPAS_AHB_CLK>, + <&camcc CAM_CC_CSIPHY0_CLK>, + <&camcc CAM_CC_CSI0PHYTIMER_CLK>, + <&camcc CAM_CC_CSIPHY1_CLK>, + <&camcc CAM_CC_CSI1PHYTIMER_CLK>, + <&camcc CAM_CC_CSIPHY2_CLK>, + <&camcc CAM_CC_CSI2PHYTIMER_CLK>, + <&camcc CAM_CC_SOC_AHB_CLK>, + <&camcc CAM_CC_IFE_0_CLK>, + <&camcc CAM_CC_IFE_0_AXI_CLK>, + <&camcc CAM_CC_IFE_0_CPHY_RX_CLK>, + <&camcc CAM_CC_IFE_0_CSID_CLK>, + <&camcc CAM_CC_IFE_1_CLK>, + <&camcc CAM_CC_IFE_1_AXI_CLK>, + <&camcc CAM_CC_IFE_1_CPHY_RX_CLK>, + <&camcc CAM_CC_IFE_1_CSID_CLK>, + <&camcc CAM_CC_IFE_LITE_CLK>, + <&camcc CAM_CC_IFE_LITE_CPHY_RX_CLK>, + <&camcc CAM_CC_IFE_LITE_CSID_CLK>, + <&camcc CAM_CC_BPS_CLK>, + <&camcc CAM_CC_BPS_AHB_CLK>, + <&camcc CAM_CC_BPS_AXI_CLK>, + <&camcc CAM_CC_BPS_AREG_CLK>, + <&camcc CAM_CC_ICP_CLK>, + <&camcc CAM_CC_IPE_0_CLK>, + <&camcc CAM_CC_IPE_0_AHB_CLK>, + <&camcc CAM_CC_IPE_0_AREG_CLK>, + <&camcc CAM_CC_IPE_0_AXI_CLK>, + <&camcc CAM_CC_JPEG_CLK>, + <&camcc CAM_CC_LRME_CLK>; + clock-names = "gcc_ahb", + "gcc_axi_hf", + "camnoc_axi", + "cpas_ahb", + "csiphy0", + "csiphy0_timer", + "csiphy1", + "csiphy1_timer", + "csiphy2", + "csiphy2_timer", + "soc_ahb", + "vfe0", + "vfe0_axi", + "vfe0_cphy_rx", + "vfe0_csid", + "vfe1", + "vfe1_axi", + "vfe1_cphy_rx", + "vfe1_csid", + "vfe_lite", + "vfe_lite_cphy_rx", + "vfe_lite_csid", + "bps", + "bps_ahb", + "bps_axi", + "bps_areg", + "icp", + "ipe0", + "ipe0_ahb", + "ipe0_areg", + "ipe0_axi", + "jpeg", + "lrme"; + + interconnects = <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ACTIVE_ONLY + &config_noc SLAVE_CAMERA_CFG QCOM_ICC_TAG_ACTIVE_ONLY>, + <&mmss_noc MASTER_CAMNOC_HF0 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>, + <&mmss_noc MASTER_CAMNOC_HF1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>, + <&mmss_noc MASTER_CAMNOC_SF QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "ahb", + "hf_0", + "hf_1", + "sf_mnoc"; + + interrupts = , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + interrupt-names = "csid0", + "csid1", + "csid_lite", + "csiphy0", + "csiphy1", + "csiphy2", + "vfe0", + "vfe1", + "vfe_lite", + "camnoc", + "cdm", + "icp", + "jpeg_dma", + "jpeg_enc", + "lrme"; + + iommus = <&apps_smmu 0x0820 0x40>, + <&apps_smmu 0x0840 0x00>, + <&apps_smmu 0x0860 0x40>, + <&apps_smmu 0x0c00 0x00>, + <&apps_smmu 0x0cc0 0x00>, + <&apps_smmu 0x0c80 0x00>, + <&apps_smmu 0x0ca0 0x00>, + <&apps_smmu 0x0d00 0x00>, + <&apps_smmu 0x0d20 0x00>, + <&apps_smmu 0x0d40 0x00>, + <&apps_smmu 0x0d80 0x20>, + <&apps_smmu 0x0da0 0x20>, + <&apps_smmu 0x0de2 0x00>; + + power-domains = <&camcc IFE_0_GDSC>, + <&camcc IFE_1_GDSC>, + <&camcc TITAN_TOP_GDSC>, + <&camcc BPS_GDSC>, + <&camcc IPE_0_GDSC>; + power-domain-names = "ife0", + "ife1", + "top", + "bps", + "ipe"; + + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + }; + + port@1 { + reg = <1>; + }; + + port@2 { + reg = <2>; + }; + }; + }; + camcc: clock-controller@ad00000 { compatible = "qcom,qcs615-camcc"; reg = <0 0x0ad00000 0 0x10000>; From ecdc7e5b30634d3e9924d71df29caf6ebd4f07cf Mon Sep 17 00:00:00 2001 From: Wenmeng Liu Date: Thu, 22 Jan 2026 18:48:53 +0800 Subject: [PATCH 2182/2333] FROMLIST: dt-bindings: i2c: qcom-cci: Document sm6150 compatible Add the sm6150 CCI device string compatible. Link: https://lore.kernel.org/all/20260122-sm6150_evk-v5-2-039b170450a3@oss.qualcomm.com/ Reviewed-by: Vladimir Zapolskiy Signed-off-by: Wenmeng Liu Reviewed-by: Krzysztof Kozlowski Reviewed-by: Loic Poulain --- Documentation/devicetree/bindings/i2c/qcom,i2c-cci.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/i2c/qcom,i2c-cci.yaml b/Documentation/devicetree/bindings/i2c/qcom,i2c-cci.yaml index 399a09409e071..35d3a0685ac44 100644 --- a/Documentation/devicetree/bindings/i2c/qcom,i2c-cci.yaml +++ b/Documentation/devicetree/bindings/i2c/qcom,i2c-cci.yaml @@ -34,6 +34,7 @@ properties: - qcom,sc8280xp-cci - qcom,sdm670-cci - qcom,sdm845-cci + - qcom,sm6150-cci - qcom,sm6350-cci - qcom,sm8250-cci - qcom,sm8450-cci @@ -251,6 +252,7 @@ allOf: contains: enum: - qcom,sa8775p-cci + - qcom,sm6150-cci - qcom,sm8550-cci - qcom,sm8650-cci - qcom,x1e80100-cci From f50922526129c639edcf0b9565152e8324e6bae3 Mon Sep 17 00:00:00 2001 From: Wenmeng Liu Date: Thu, 22 Jan 2026 18:48:54 +0800 Subject: [PATCH 2183/2333] FROMLIST: arm64: dts: qcom: talos: Add CCI definitions Qualcomm Talos SoC contains single controller, containing 2 I2C hosts. Link: https://lore.kernel.org/all/20260122-sm6150_evk-v5-3-039b170450a3@oss.qualcomm.com/ Reviewed-by: Vladimir Zapolskiy Signed-off-by: Wenmeng Liu --- arch/arm64/boot/dts/qcom/talos.dtsi | 51 +++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/talos.dtsi b/arch/arm64/boot/dts/qcom/talos.dtsi index b08517507e813..d9e9401378ab2 100644 --- a/arch/arm64/boot/dts/qcom/talos.dtsi +++ b/arch/arm64/boot/dts/qcom/talos.dtsi @@ -1555,6 +1555,22 @@ #interrupt-cells = <2>; wakeup-parent = <&pdc>; + cci_i2c0_default: cci-i2c0-default-state { + /* SDA, SCL */ + pins = "gpio32", "gpio33"; + function = "cci_i2c"; + drive-strength = <2>; + bias-pull-up; + }; + + cci_i2c1_default: cci-i2c1-default-state { + /* SDA, SCL */ + pins = "gpio34", "gpio35"; + function = "cci_i2c"; + drive-strength = <2>; + bias-pull-up; + }; + qup_i2c1_data_clk: qup-i2c1-data-clk-state { pins = "gpio4", "gpio5"; function = "qup0"; @@ -3929,6 +3945,41 @@ #power-domain-cells = <1>; }; + cci: cci@ac4a000 { + compatible = "qcom,sm6150-cci", "qcom,msm8996-cci"; + + reg = <0x0 0x0ac4a000 0x0 0x4000>; + interrupts = ; + power-domains = <&camcc TITAN_TOP_GDSC>; + clocks = <&camcc CAM_CC_SOC_AHB_CLK>, + <&camcc CAM_CC_CPAS_AHB_CLK>, + <&camcc CAM_CC_CCI_CLK>; + clock-names = "camnoc_axi", + "cpas_ahb", + "cci"; + pinctrl-0 = <&cci_i2c0_default &cci_i2c1_default>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + + cci_i2c0: i2c-bus@0 { + reg = <0>; + clock-frequency = <1000000>; + #address-cells = <1>; + #size-cells = <0>; + }; + + cci_i2c1: i2c-bus@1 { + reg = <1>; + clock-frequency = <1000000>; + #address-cells = <1>; + #size-cells = <0>; + }; + }; + camss: isp@acb3000 { compatible = "qcom,sm6150-camss"; From dbb09d76ac620fa10d9467b088e78cfb1cb17b5f Mon Sep 17 00:00:00 2001 From: Wenmeng Liu Date: Thu, 22 Jan 2026 18:48:55 +0800 Subject: [PATCH 2184/2333] FROMLIST: arm64: dts: qcom: talos: Add camera MCLK pinctrl Define pinctrl definitions to enable camera master clocks on Talos. Link: https://lore.kernel.org/all/20260122-sm6150_evk-v5-4-039b170450a3@oss.qualcomm.com/ Reviewed-by: Konrad Dybcio Reviewed-by: Dmitry Baryshkov Reviewed-by: Vladimir Zapolskiy Signed-off-by: Wenmeng Liu --- arch/arm64/boot/dts/qcom/talos.dtsi | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/talos.dtsi b/arch/arm64/boot/dts/qcom/talos.dtsi index d9e9401378ab2..6a99c2df90ee6 100644 --- a/arch/arm64/boot/dts/qcom/talos.dtsi +++ b/arch/arm64/boot/dts/qcom/talos.dtsi @@ -1555,6 +1555,34 @@ #interrupt-cells = <2>; wakeup-parent = <&pdc>; + cam0_default: cam0-default-state { + pins = "gpio28"; + function = "cam_mclk"; + drive-strength = <2>; + bias-disable; + }; + + cam1_default: cam1-default-state { + pins = "gpio29"; + function = "cam_mclk"; + drive-strength = <2>; + bias-disable; + }; + + cam2_default: cam2-default-state { + pins = "gpio30"; + function = "cam_mclk"; + drive-strength = <2>; + bias-disable; + }; + + cam3_default: cam3-default-state { + pins = "gpio31"; + function = "cam_mclk"; + drive-strength = <2>; + bias-disable; + }; + cci_i2c0_default: cci-i2c0-default-state { /* SDA, SCL */ pins = "gpio32", "gpio33"; From c4d35c7dda1c73a228cbbc11deb379c045bfc488 Mon Sep 17 00:00:00 2001 From: Wenmeng Liu Date: Thu, 22 Jan 2026 18:48:56 +0800 Subject: [PATCH 2185/2333] FROMLIST: arm64: dts: qcom: talos-evk-camera: Add DT overlay Enable IMX577 via CCI on Taloss EVK Core Kit. The Talos EVK board does not include a camera sensor by default, this DTSO has enabled the Arducam 12.3MP IMX577 Mini Camera Module on the CSI-1 interface. Link: https://lore.kernel.org/all/20260122-sm6150_evk-v5-5-039b170450a3@oss.qualcomm.com/ Reviewed-by: Vladimir Zapolskiy Signed-off-by: Wenmeng Liu --- arch/arm64/boot/dts/qcom/Makefile | 3 + .../dts/qcom/talos-evk-camera-imx577.dtso | 63 +++++++++++++++++++ 2 files changed, 66 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/talos-evk-camera-imx577.dtso diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile index 4d9098501f3d7..480cc8b2884ba 100644 --- a/arch/arm64/boot/dts/qcom/Makefile +++ b/arch/arm64/boot/dts/qcom/Makefile @@ -365,8 +365,11 @@ dtb-$(CONFIG_ARCH_QCOM) += sm8650-qrd.dtb dtb-$(CONFIG_ARCH_QCOM) += sm8750-mtp.dtb dtb-$(CONFIG_ARCH_QCOM) += sm8750-qrd.dtb dtb-$(CONFIG_ARCH_QCOM) += talos-evk.dtb +dtb-$(CONFIG_ARCH_QCOM) += talos-evk-camera-imx577.dtbo +talos-evk-camera-imx577-dtbs := talos-evk.dtb talos-evk-camera-imx577.dtbo talos-evk-lvds-auo,g133han01-dtbs := \ talos-evk.dtb talos-evk-lvds-auo,g133han01.dtbo +dtb-$(CONFIG_ARCH_QCOM) += talos-evk-camera-imx577.dtb dtb-$(CONFIG_ARCH_QCOM) += talos-evk-lvds-auo,g133han01.dtb x1e001de-devkit-el2-dtbs := x1e001de-devkit.dtb x1-el2.dtbo dtb-$(CONFIG_ARCH_QCOM) += x1e001de-devkit.dtb x1e001de-devkit-el2.dtb diff --git a/arch/arm64/boot/dts/qcom/talos-evk-camera-imx577.dtso b/arch/arm64/boot/dts/qcom/talos-evk-camera-imx577.dtso new file mode 100644 index 0000000000000..53006a861878f --- /dev/null +++ b/arch/arm64/boot/dts/qcom/talos-evk-camera-imx577.dtso @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +/dts-v1/; +/plugin/; + +#include +#include + +&camss { + vdd-csiphy-1p2-supply = <&vreg_l11a>; + vdd-csiphy-1p8-supply = <&vreg_l12a>; + + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@1 { + reg = <1>; + + csiphy1_ep: endpoint { + data-lanes = <0 1 2 3>; + remote-endpoint = <&imx577_ep1>; + }; + }; + }; +}; + +&cci { + status = "okay"; +}; + +&cci_i2c1 { + #address-cells = <1>; + #size-cells = <0>; + + camera@1a { + compatible = "sony,imx577"; + reg = <0x1a>; + + reset-gpios = <&tlmm 29 GPIO_ACTIVE_LOW>; + pinctrl-0 = <&cam2_default>; + pinctrl-names = "default"; + + clocks = <&camcc CAM_CC_MCLK2_CLK>; + assigned-clocks = <&camcc CAM_CC_MCLK2_CLK>; + assigned-clock-rates = <24000000>; + + avdd-supply = <&vreg_s4a>; + + port { + imx577_ep1: endpoint { + link-frequencies = /bits/ 64 <600000000>; + data-lanes = <1 2 3 4>; + remote-endpoint = <&csiphy1_ep>; + }; + }; + }; +}; From 14326eba8ac4920cae4a528076551a808925bc2c Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Date: Mon, 13 Oct 2025 14:14:51 +0000 Subject: [PATCH 2186/2333] UPSTREAM: media: i2c: imx412: Use %pe format specifier The %pe format specifier is designed to print error pointers. It prints a symbolic error name (eg. -EINVAL) and it makes the code simpler by omitting PTR_ERR(). This patch fixes this cocci report: ./i2c/imx412.c:931:3-10: WARNING: Consider using %pe to print PTR_ERR() Link: https://lore.kernel.org/all/20251013-ptr_err-v1-11-2c5efbd82952@chromium.org/ Signed-off-by: Ricardo Ribalda Reviewed-by: Bryan O'Donoghue Acked-by: Sakari Ailus --- drivers/media/i2c/imx412.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/i2c/imx412.c b/drivers/media/i2c/imx412.c index 7bbd639a9ddfa..b3826f8035470 100644 --- a/drivers/media/i2c/imx412.c +++ b/drivers/media/i2c/imx412.c @@ -927,8 +927,8 @@ static int imx412_parse_hw_config(struct imx412 *imx412) imx412->reset_gpio = devm_gpiod_get_optional(imx412->dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(imx412->reset_gpio)) { - dev_err(imx412->dev, "failed to get reset gpio %ld\n", - PTR_ERR(imx412->reset_gpio)); + dev_err(imx412->dev, "failed to get reset gpio %pe\n", + imx412->reset_gpio); return PTR_ERR(imx412->reset_gpio); } From fce08b26da53b37524a1e8180f59ba12d2e9d28e Mon Sep 17 00:00:00 2001 From: Wenmeng Liu Date: Fri, 23 Jan 2026 17:19:55 +0800 Subject: [PATCH 2187/2333] FROMLIST: media: i2c: imx412: Assert reset GPIO during probe Assert the reset GPIO before first power up. This avoids a mismatch where the first power up (when the reset GPIO defaults deasserted) differs from subsequent cycles. Link: https://lore.kernel.org/all/20260123-imx412-v7-1-e58303f2b76b@oss.qualcomm.com/ Signed-off-by: Wenmeng Liu --- drivers/media/i2c/imx412.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/i2c/imx412.c b/drivers/media/i2c/imx412.c index b3826f8035470..aa63dfc349181 100644 --- a/drivers/media/i2c/imx412.c +++ b/drivers/media/i2c/imx412.c @@ -925,7 +925,7 @@ static int imx412_parse_hw_config(struct imx412 *imx412) /* Request optional reset pin */ imx412->reset_gpio = devm_gpiod_get_optional(imx412->dev, "reset", - GPIOD_OUT_LOW); + GPIOD_OUT_HIGH); if (IS_ERR(imx412->reset_gpio)) { dev_err(imx412->dev, "failed to get reset gpio %pe\n", imx412->reset_gpio); From deb0d35cd07828a6e4ad1130ea348d4cdcc1f4da Mon Sep 17 00:00:00 2001 From: Wenmeng Liu Date: Fri, 23 Jan 2026 17:19:56 +0800 Subject: [PATCH 2188/2333] FROMLIST: media: i2c: imx412: Extend the power-on waiting time MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Arducam IMX577 module requires a longer reset time than the 1000µs configured in the current driver. Increase the wait time after power-on to ensure proper initialization. Link: https://lore.kernel.org/all/20260123-imx412-v7-2-e58303f2b76b@oss.qualcomm.com/ Signed-off-by: Wenmeng Liu --- drivers/media/i2c/imx412.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/media/i2c/imx412.c b/drivers/media/i2c/imx412.c index aa63dfc349181..e25e0a9ff65c3 100644 --- a/drivers/media/i2c/imx412.c +++ b/drivers/media/i2c/imx412.c @@ -1037,7 +1037,11 @@ static int imx412_power_on(struct device *dev) goto error_reset; } - usleep_range(1000, 1200); + /* + * Certain Arducam IMX577 module variants require a longer reset settle + * time. Increasing the delay from 1ms to 10ms ensures reliable startup. + */ + usleep_range(10000, 12000); return 0; From 973ce45e08ddcb698f6998a64a0de5a677fdbfe4 Mon Sep 17 00:00:00 2001 From: Krishna Chaitanya Chundru Date: Fri, 23 Jan 2026 11:44:08 +0530 Subject: [PATCH 2189/2333] Workaround: PCI: Disable L1ss through quirk for Qualcomm SA8775P When PCIe L1ss is enabled, WLAN functionality is completly broken. There are some connectivity issues in this platform mostly with CLKREQ# pin. Disable L1ss as workaround untill actual issue get resolved. Signed-off-by: Krishna Chaitanya Chundru --- drivers/pci/quirks.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index b9c252aa6fe08..a51dab62ecef6 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -2527,6 +2527,12 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_FREESCALE, 0x0451, quirk_disable_aspm_l0s DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_PASEMI, 0xa002, quirk_disable_aspm_l0s_l1); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_HUAWEI, 0x1105, quirk_disable_aspm_l0s_l1); +static void quirk_disable_aspm_l1ss(struct pci_dev *dev) +{ + pci_disable_link_state(dev, PCIE_LINK_STATE_L1_1 | PCIE_LINK_STATE_L1_2); +} +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_QCOM, 0x1103, quirk_disable_aspm_l1ss); + /* * Some Pericom PCIe-to-PCI bridges in reverse mode need the PCIe Retrain * Link bit cleared after starting the link retrain process to allow this From 392c660ca2c06d74fb5bcfce12566040fd7925c7 Mon Sep 17 00:00:00 2001 From: Le Qi Date: Tue, 27 Jan 2026 20:26:11 +0800 Subject: [PATCH 2190/2333] FROMLIST: arm64: dts: qcom: talos: Add GPR node, audio services, and MI2S1 TLMM pins This patch adds the Generic Pack Router (GPR) node together with Audio Process Manager (APM) and Proxy Resource Manager (PRM) audio service nodes to the Talos device tree description. It also introduces MI2S1 pinctrl states for data0, data1, sck, and ws lines, grouped into a single entry at the SoC-level DTSI for better reuse and clarity. Link: https://lore.kernel.org/all/20251204083225.1190017-2-le.qi@oss.qualcomm.com/ Reviewed-by: Konrad Dybcio Signed-off-by: Le Qi --- arch/arm64/boot/dts/qcom/talos.dtsi | 47 +++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/talos.dtsi b/arch/arm64/boot/dts/qcom/talos.dtsi index 4ed140194004c..308e8e5ffb796 100644 --- a/arch/arm64/boot/dts/qcom/talos.dtsi +++ b/arch/arm64/boot/dts/qcom/talos.dtsi @@ -20,6 +20,7 @@ #include #include #include +#include / { interrupt-parent = <&intc>; @@ -1555,6 +1556,13 @@ #interrupt-cells = <2>; wakeup-parent = <&pdc>; + mi2s1_pins: mi2s1-state { + pins = "gpio108", "gpio109", "gpio110", "gpio111"; + function = "mi2s_1"; + drive-strength = <8>; + bias-disable; + }; + cam0_default: cam0-default-state { pins = "gpio28"; function = "cam_mclk"; @@ -5132,6 +5140,45 @@ dma-coherent; }; }; + + gpr: gpr { + compatible = "qcom,gpr"; + qcom,glink-channels = "adsp_apps"; + qcom,domain = ; + qcom,intents = <512 20>; + #address-cells = <1>; + #size-cells = <0>; + + q6apm: service@1 { + compatible = "qcom,q6apm"; + reg = ; + #sound-dai-cells = <0>; + qcom,protection-domain = "avs/audio", + "msm/adsp/audio_pd"; + + q6apmbedai: bedais { + compatible = "qcom,q6apm-lpass-dais"; + #sound-dai-cells = <1>; + }; + + q6apmdai: dais { + compatible = "qcom,q6apm-dais"; + iommus = <&apps_smmu 0x1721 0x0>; + }; + }; + + q6prm: service@2 { + compatible = "qcom,q6prm"; + reg = ; + qcom,protection-domain = "avs/audio", + "msm/adsp/audio_pd"; + + q6prmcc: clock-controller { + compatible = "qcom,q6prm-lpass-clocks"; + #clock-cells = <2>; + }; + }; + }; }; }; From 9b6d6100a71b2a98a30ada43d34edeb55a386236 Mon Sep 17 00:00:00 2001 From: Le Qi Date: Tue, 27 Jan 2026 20:30:18 +0800 Subject: [PATCH 2191/2333] FROMLIST: arm64: dts: qcom: talos-evk: Add sound card support with DA7212 codec Add the sound card node for QCS615 Talos EVK with DA7212 codec connected over the Primary MI2S interface. The configuration enables headphone playback and headset microphone capture, both of which have been tested to work. Link: https://lore.kernel.org/all/20251204083225.1190017-3-le.qi@oss.qualcomm.com/ Reviewed-by: Konrad Dybcio Reviewed-by: Dmitry Baryshkov Signed-off-by: Le Qi --- arch/arm64/boot/dts/qcom/talos-evk.dts | 52 ++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/talos-evk.dts b/arch/arm64/boot/dts/qcom/talos-evk.dts index af100e22beeec..42f8a3944b29b 100644 --- a/arch/arm64/boot/dts/qcom/talos-evk.dts +++ b/arch/arm64/boot/dts/qcom/talos-evk.dts @@ -5,6 +5,7 @@ /dts-v1/; #include "talos-evk-som.dtsi" +#include / { model = "Qualcomm QCS615 IQ 615 EVK"; @@ -40,6 +41,46 @@ }; }; + sound { + compatible = "qcom,qcs615-sndcard"; + model = "TALOS-EVK"; + + pinctrl-0 = <&mi2s1_pins>; + pinctrl-names = "default"; + + pri-mi2s-capture-dai-link { + link-name = "Primary MI2S Capture"; + + codec { + sound-dai = <&codec_da7212>; + }; + + cpu { + sound-dai = <&q6apmbedai PRIMARY_MI2S_TX>; + }; + + platform { + sound-dai = <&q6apm>; + }; + }; + + pri-mi2s-playback-dai-link { + link-name = "Primary MI2S Playback"; + + codec { + sound-dai = <&codec_da7212>; + }; + + cpu { + sound-dai = <&q6apmbedai PRIMARY_MI2S_RX>; + }; + + platform { + sound-dai = <&q6apm>; + }; + }; + }; + vreg_v1p8_out: regulator-v1p8-out { compatible = "regulator-fixed"; regulator-name = "vreg-v1p8-out"; @@ -109,6 +150,17 @@ }; }; +&i2c5 { + codec_da7212: codec@1a { + compatible = "dlg,da7212"; + reg = <0x1a>; + #sound-dai-cells = <0>; + VDDA-supply = <&vreg_v1p8_out>; + VDDIO-supply = <&vreg_v1p8_out>; + VDDMIC-supply = <&vreg_v3p3_out>; + }; +}; + &mdss_dsi0_out { remote-endpoint = <&adv7535_in>; data-lanes = <0 1 2 3>; From 5efb88f572e1dbfb80c358904246e8167aec4474 Mon Sep 17 00:00:00 2001 From: Mukesh Ojha Date: Tue, 27 Jan 2026 14:01:00 +0530 Subject: [PATCH 2192/2333] FROMLIST: arm64: dts: qcom: lemans: disable zap-shader for EL2 configuration We don't need to use zap shader in EL2 as Linux can zap the gpu on it's own. Lets disable zap-shader for Lemans EL2 configuration. Link: https://lore.kernel.org/lkml/20260127-talos-el2-overlay-v2-1-b6a2266532c4@oss.qualcomm.com/ Signed-off-by: Mukesh Ojha --- arch/arm64/boot/dts/qcom/lemans-el2.dtso | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/lemans-el2.dtso b/arch/arm64/boot/dts/qcom/lemans-el2.dtso index af35039946e30..7c1bd425cd5df 100644 --- a/arch/arm64/boot/dts/qcom/lemans-el2.dtso +++ b/arch/arm64/boot/dts/qcom/lemans-el2.dtso @@ -10,6 +10,10 @@ /dts-v1/; /plugin/; +&gpu_zap_shader { + status = "disabled"; +}; + &iris { /* More driver work is needed */ status = "disabled"; From 1cf62e53793edddec3be96b187101e168c16cca8 Mon Sep 17 00:00:00 2001 From: Mukesh Ojha Date: Mon, 19 Jan 2026 13:51:00 +0530 Subject: [PATCH 2193/2333] FROMLIST: arm64: dts: qcom: monaco: Add EL2 overlay All the Monaco IOT variants boards are using Gunyah hypervisor which means that, so far, Linux-based OS could only boot in EL1 on those devices. However, it is possible for us to boot Linux at EL2 on these devices [1]. When running under Gunyah, the remote processor firmware IOMMU streams are controlled by Gunyah. However, without Gunyah, the IOMMU is managed by the consumer of this DeviceTree. Therefore, describe the firmware streams for each remote processor. Add a EL2-specific DT overlay and apply it to Monaco IOT variant devices to create -el2.dtb for each of them alongside "normal" dtb. [1] https://docs.qualcomm.com/bundle/publicresource/topics/80-70020-4/boot-developer-touchpoints.html#uefi Link: https://lore.kernel.org/lkml/20260127-talos-el2-overlay-v2-2-b6a2266532c4@oss.qualcomm.com/ Signed-off-by: Mukesh Ojha --- arch/arm64/boot/dts/qcom/Makefile | 8 +++++++ arch/arm64/boot/dts/qcom/monaco-el2.dtso | 29 ++++++++++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/monaco-el2.dtso diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile index 480cc8b2884ba..484cb22b4c71f 100644 --- a/arch/arm64/boot/dts/qcom/Makefile +++ b/arch/arm64/boot/dts/qcom/Makefile @@ -46,6 +46,10 @@ dtb-$(CONFIG_ARCH_QCOM) += lemans-evk-camx.dtb dtb-$(CONFIG_ARCH_QCOM) += monaco-evk.dtb +monaco-evk-el2-dtbs := monaco-evk.dtb monaco-el2.dtbo + +dtb-$(CONFIG_ARCH_QCOM) += monaco-evk-el2.dtb + monaco-evk-camera-imx577-dtbs := monaco-evk.dtb monaco-evk-camera-imx577.dtbo dtb-$(CONFIG_ARCH_QCOM) += monaco-evk-camera-imx577.dtb monaco-evk-camx-dtbs := monaco-evk.dtb monaco-evk-camx.dtbo @@ -157,6 +161,10 @@ dtb-$(CONFIG_ARCH_QCOM) += qcs6490-rb3gen2-vision-mezzanine-camx.dtb dtb-$(CONFIG_ARCH_QCOM) += qcs8300-ride.dtb +qcs8300-ride-el2-dtbs := qcs8300-ride.dtb monaco-el2.dtbo + +dtb-$(CONFIG_ARCH_QCOM) += qcs8300-ride-el2.dtb + qcs8300-ride-camx-dtbs:= qcs8300-ride.dtb qcs8300-ride-camx.dtbo dtb-$(CONFIG_ARCH_QCOM) += qcs8300-ride-camx.dtb diff --git a/arch/arm64/boot/dts/qcom/monaco-el2.dtso b/arch/arm64/boot/dts/qcom/monaco-el2.dtso new file mode 100644 index 0000000000000..a7e3270f86090 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/monaco-el2.dtso @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * + * Monaco specific modifications required to boot in EL2. + */ + +/dts-v1/; +/plugin/; + +&gpu_zap_shader { + status = "disabled"; +}; + +&iris { + status = "disabled"; +}; + +&remoteproc_adsp { + iommus = <&apps_smmu 0x2000 0x0>; +}; + +&remoteproc_cdsp { + iommus = <&apps_smmu 0x19c0 0x0400>; +}; + +&remoteproc_gpdsp { + iommus = <&apps_smmu 0x28a0 0x0>; +}; From b706d5c29e4695e72412cf39f40e9bbaf155bd81 Mon Sep 17 00:00:00 2001 From: Mukesh Ojha Date: Mon, 19 Jan 2026 14:24:54 +0530 Subject: [PATCH 2194/2333] FROMLIST: arm64: dts: qcom: talos: Add EL2 overlay All the existing variants Talos boards are using Gunyah hypervisor which means that, so far, Linux-based OS could only boot in EL1 on those devices. However, it is possible for us to boot Linux at EL2 on these devices [1]. When running under Gunyah, the remote processor firmware IOMMU streams are controlled by Gunyah. However, without Gunyah, the IOMMU is managed by the consumer of this DeviceTree. Therefore, describe the firmware streams for each remote processor. Add a EL2-specific DT overlay and apply it to Talos IOT variant devices to create -el2.dtb for each of them alongside "normal" dtb. [1] https://docs.qualcomm.com/bundle/publicresource/topics/80-70020-4/boot-developer-touchpoints.html#uefi Link: https://lore.kernel.org/lkml/20260127-talos-el2-overlay-v2-3-b6a2266532c4@oss.qualcomm.com/ Reviewed-by: Konrad Dybcio Signed-off-by: Mukesh Ojha --- arch/arm64/boot/dts/qcom/Makefile | 5 +++++ arch/arm64/boot/dts/qcom/talos-el2.dtso | 25 +++++++++++++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/talos-el2.dtso diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile index 484cb22b4c71f..21db2a35186cc 100644 --- a/arch/arm64/boot/dts/qcom/Makefile +++ b/arch/arm64/boot/dts/qcom/Makefile @@ -146,6 +146,11 @@ dtb-$(CONFIG_ARCH_QCOM) += qcm6490-shift-otter.dtb dtb-$(CONFIG_ARCH_QCOM) += qcs404-evb-1000.dtb dtb-$(CONFIG_ARCH_QCOM) += qcs404-evb-4000.dtb dtb-$(CONFIG_ARCH_QCOM) += qcs615-ride.dtb + +qcs615-ride-el2-dtbs := qcs615-ride.dtb talos-el2.dtbo + +dtb-$(CONFIG_ARCH_QCOM) += qcs615-ride-el2.dtb + dtb-$(CONFIG_ARCH_QCOM) += qcs6490-rb3gen2.dtb qcs6490-rb3gen2-vision-mezzanine-dtbs := qcs6490-rb3gen2.dtb qcs6490-rb3gen2-vision-mezzanine.dtbo diff --git a/arch/arm64/boot/dts/qcom/talos-el2.dtso b/arch/arm64/boot/dts/qcom/talos-el2.dtso new file mode 100644 index 0000000000000..f6818c058d724 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/talos-el2.dtso @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + + * Talos specific modifications required to boot in EL2. + */ + +/dts-v1/; +/plugin/; + +&gpu_zap_shader { + status = "disabled"; +}; + +&remoteproc_adsp { + iommus = <&apps_smmu 0x1720 0x0>; +}; + +&remoteproc_cdsp { + iommus = <&apps_smmu 0x1080 0x0>; +}; + +&venus { + status = "disabled"; +}; From 59d5881f1a7cd80d01ad4b97d61f1937bb069fc9 Mon Sep 17 00:00:00 2001 From: Abhinaba Rakshit Date: Mon, 19 Jan 2026 13:45:15 +0530 Subject: [PATCH 2195/2333] FROMGIT: arm64: dts: qcom: lemans: add QCrypto node Add Qualcomm Crypto Engine device node for LeMans platform. QCE and Crypto DMA nodes patch was applied as part of the commit 7ff3da43ef44 ("arm64: dts: qcom: sa8775p: add QCrypto nodes"), however was partially reverted by commit 92979f12a201 ("arm64: dts: qcom: sa8775p: Partially revert "arm64: dts: qcom: sa8775p: add QCrypto nodes"") due to compatible-string being miss-matched against schema. Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/all/20251224-enable-qualcomm-crypto-engine-for-lemans-v2-1-a707e3d38765@oss.qualcomm.com/ Signed-off-by: Abhinaba Rakshit --- arch/arm64/boot/dts/qcom/lemans.dtsi | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/lemans.dtsi b/arch/arm64/boot/dts/qcom/lemans.dtsi index fa2caa46e5d26..eb277a620059c 100644 --- a/arch/arm64/boot/dts/qcom/lemans.dtsi +++ b/arch/arm64/boot/dts/qcom/lemans.dtsi @@ -2790,6 +2790,18 @@ <&apps_smmu 0x481 0x00>; }; + crypto: crypto@1dfa000 { + compatible = "qcom,sa8775p-qce", "qcom,sm8150-qce", "qcom,qce"; + reg = <0x0 0x01dfa000 0x0 0x6000>; + dmas = <&cryptobam 4>, <&cryptobam 5>; + dma-names = "rx", "tx"; + iommus = <&apps_smmu 0x480 0x0>, + <&apps_smmu 0x481 0x0>; + interconnects = <&aggre2_noc MASTER_CRYPTO_CORE0 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "memory"; + }; + ctcu@4001000 { compatible = "qcom,sa8775p-ctcu"; reg = <0x0 0x04001000 0x0 0x1000>; From a5c71f2e1c4acacb55bd8db9203978783cb2a37f Mon Sep 17 00:00:00 2001 From: Salendarsingh Gaud Date: Wed, 28 Jan 2026 14:47:15 +0530 Subject: [PATCH 2196/2333] Revert "QCLINUX: Revert "arm64: dts: qcom: sm8750-mtp: Add WiFi and Bluetooth"" This reverts commit 75121cdb51475d7f7f25fbd2b3e8c2e14e835145. Fix for bootup crash on sm8750-mtp is merged in 6.18 stable branch. https://lore.kernel.org/all/e9cdd9c4-4ce8-4d92-b337-1539e566c03a@linaro.org/ Signed-off-by: Salendarsingh Gaud --- arch/arm64/boot/dts/qcom/sm8750-mtp.dts | 147 +++++++++++++++++++++++- 1 file changed, 143 insertions(+), 4 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm8750-mtp.dts b/arch/arm64/boot/dts/qcom/sm8750-mtp.dts index 3ffa50947dd8b..1b526d96fba82 100644 --- a/arch/arm64/boot/dts/qcom/sm8750-mtp.dts +++ b/arch/arm64/boot/dts/qcom/sm8750-mtp.dts @@ -201,6 +201,74 @@ regulator-always-on; regulator-boot-on; }; + + /* + * MTPs rev 2.0 (power grid v8) come with two different WiFi chips: + * WCN7850 and WCN786x. + * Device nodes here for the PMU, WiFi and Bluetooth describe the MTP + * variant with WCN7850. + */ + wcn7850-pmu { + compatible = "qcom,wcn7850-pmu"; + + pinctrl-names = "default"; + pinctrl-0 = <&wlan_en>, <&bt_default>; + + wlan-enable-gpios = <&tlmm 16 GPIO_ACTIVE_HIGH>; + bt-enable-gpios = <&pm8550ve_f_gpios 3 GPIO_ACTIVE_HIGH>; + + vdd-supply = <&vreg_s5f_0p85>; + vddio-supply = <&vreg_l3f_1p8>; + vddio1p2-supply = <&vreg_l2f_1p2>; + vddaon-supply = <&vreg_s4d_0p85>; + vdddig-supply = <&vreg_s1d_0p97>; + vddrfa1p2-supply = <&vreg_s7i_1p2>; + vddrfa1p8-supply = <&vreg_s3g_1p8>; + + clocks = <&rpmhcc RPMH_RF_CLK1>; + + regulators { + vreg_pmu_rfa_cmn: ldo0 { + regulator-name = "vreg_pmu_rfa_cmn"; + }; + + vreg_pmu_aon_0p59: ldo1 { + regulator-name = "vreg_pmu_aon_0p59"; + }; + + vreg_pmu_wlcx_0p8: ldo2 { + regulator-name = "vreg_pmu_wlcx_0p8"; + }; + + vreg_pmu_wlmx_0p85: ldo3 { + regulator-name = "vreg_pmu_wlmx_0p85"; + }; + + vreg_pmu_btcmx_0p85: ldo4 { + regulator-name = "vreg_pmu_btcmx_0p85"; + }; + + vreg_pmu_rfa_0p8: ldo5 { + regulator-name = "vreg_pmu_rfa_0p8"; + }; + + vreg_pmu_rfa_1p2: ldo6 { + regulator-name = "vreg_pmu_rfa_1p2"; + }; + + vreg_pmu_rfa_1p8: ldo7 { + regulator-name = "vreg_pmu_rfa_1p8"; + }; + + vreg_pmu_pcie_0p9: ldo8 { + regulator-name = "vreg_pmu_pcie_0p9"; + }; + + vreg_pmu_pcie_1p8: ldo9 { + regulator-name = "vreg_pmu_pcie_1p8"; + }; + }; + }; }; &apps_rsc { @@ -426,7 +494,7 @@ vreg_s4d_0p85: smps4 { regulator-name = "vreg_s4d_0p85"; - regulator-min-microvolt = <500000>; + regulator-min-microvolt = <852000>; regulator-max-microvolt = <1036000>; regulator-initial-mode = ; }; @@ -472,9 +540,9 @@ qcom,pmic-id = "f"; - vreg_s5f_0p5: smps5 { - regulator-name = "vreg_s5f_0p5"; - regulator-min-microvolt = <500000>; + vreg_s5f_0p85: smps5 { + regulator-name = "vreg_s5f_0p85"; + regulator-min-microvolt = <852000>; regulator-max-microvolt = <1000000>; regulator-initial-mode = ; }; @@ -891,6 +959,40 @@ status = "okay"; }; +&pcie0 { + wake-gpios = <&tlmm 104 GPIO_ACTIVE_HIGH>; + perst-gpios = <&tlmm 102 GPIO_ACTIVE_LOW>; + + pinctrl-0 = <&pcie0_default_state>; + pinctrl-names = "default"; + + status = "okay"; +}; + +&pcie0_phy { + vdda-phy-supply = <&vreg_l1f_0p88>; + vdda-pll-supply = <&vreg_l3g_1p2>; + + status = "okay"; +}; + +&pcieport0 { + wifi@0 { + compatible = "pci17cb,1107"; + reg = <0x10000 0x0 0x0 0x0 0x0>; + + vddrfacmn-supply = <&vreg_pmu_rfa_cmn>; + vddaon-supply = <&vreg_pmu_aon_0p59>; + vddwlcx-supply = <&vreg_pmu_wlcx_0p8>; + vddwlmx-supply = <&vreg_pmu_wlmx_0p85>; + vddrfa0p8-supply = <&vreg_pmu_rfa_0p8>; + vddrfa1p2-supply = <&vreg_pmu_rfa_1p2>; + vddrfa1p8-supply = <&vreg_pmu_rfa_1p8>; + vddpcie0p9-supply = <&vreg_pmu_pcie_0p9>; + vddpcie1p8-supply = <&vreg_pmu_pcie_1p8>; + }; +}; + &pmih0108_eusb2_repeater { status = "okay"; @@ -902,6 +1004,10 @@ status = "okay"; }; +&qupv3_2 { + status = "okay"; +}; + &remoteproc_adsp { firmware-name = "qcom/sm8750/adsp.mbn", "qcom/sm8750/adsp_dtb.mbn"; @@ -1035,6 +1141,14 @@ }; &tlmm { + bt_default: bt-default-state { + sw-ctrl-pins { + pins = "gpio18"; + function = "gpio"; + bias-pull-down; + }; + }; + wcd_default: wcd-reset-n-active-state { pins = "gpio101"; function = "gpio"; @@ -1042,6 +1156,31 @@ bias-disable; output-low; }; + + wlan_en: wlan-en-state { + pins = "gpio16"; + function = "gpio"; + drive-strength = <8>; + bias-pull-down; + }; +}; + +&uart14 { + status = "okay"; + + bluetooth { + compatible = "qcom,wcn7850-bt"; + + vddrfacmn-supply = <&vreg_pmu_rfa_cmn>; + vddaon-supply = <&vreg_pmu_aon_0p59>; + vddwlcx-supply = <&vreg_pmu_wlcx_0p8>; + vddwlmx-supply = <&vreg_pmu_wlmx_0p85>; + vddrfa0p8-supply = <&vreg_pmu_rfa_0p8>; + vddrfa1p2-supply = <&vreg_pmu_rfa_1p2>; + vddrfa1p8-supply = <&vreg_pmu_rfa_1p8>; + + max-speed = <3200000>; + }; }; &ufs_mem_phy { From 8a8d90662632b6826d13dde21c8e2fa90b691b3c Mon Sep 17 00:00:00 2001 From: Le Qi Date: Fri, 30 Jan 2026 14:04:19 +0800 Subject: [PATCH 2197/2333] FROMLIST: arm64: qcom: pd-mapper: Add QCS615 power domain mappings Add the QCS615 domain table to the in-kernel pd-mapper so that audio subsystems no longer rely on the userspace pd-mapper daemon. This enables proper initialization of ADSP and CDSP domains directly from the kernel. Link: https://lore.kernel.org/all/20260130061231.310113-1-le.qi@oss.qualcomm.com/ Signed-off-by: Le Qi --- drivers/soc/qcom/qcom_pd_mapper.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/soc/qcom/qcom_pd_mapper.c b/drivers/soc/qcom/qcom_pd_mapper.c index 6384f271953d4..0357be8bf3ad5 100644 --- a/drivers/soc/qcom/qcom_pd_mapper.c +++ b/drivers/soc/qcom/qcom_pd_mapper.c @@ -392,6 +392,16 @@ static const struct qcom_pdm_domain_data *qcs404_domains[] = { NULL, }; +static const struct qcom_pdm_domain_data *qcs615_domains[] = { + &adsp_audio_pd, + &adsp_root_pd, + &adsp_sensor_pd, + &cdsp_root_pd, + &mpss_root_pd, + &mpss_wlan_pd, + NULL, +}; + static const struct qcom_pdm_domain_data *sc7180_domains[] = { &adsp_audio_pd, &adsp_root_pd_pdr, @@ -562,6 +572,7 @@ static const struct of_device_id qcom_pdm_domains[] __maybe_unused = { { .compatible = "qcom,qcm2290", .data = qcm2290_domains, }, { .compatible = "qcom,qcm6490", .data = sc7280_domains, }, { .compatible = "qcom,qcs404", .data = qcs404_domains, }, + { .compatible = "qcom,qcs615", .data = qcs615_domains, }, { .compatible = "qcom,sc7180", .data = sc7180_domains, }, { .compatible = "qcom,sc7280", .data = sc7280_domains, }, { .compatible = "qcom,sc8180x", .data = sc8180x_domains, }, From e212aa595b334f70ace00372eb0e27c3bca0667b Mon Sep 17 00:00:00 2001 From: Wei Deng Date: Mon, 2 Feb 2026 08:30:57 +0530 Subject: [PATCH 2198/2333] WORKAROUND: arm64: dts: qcom: Remove WCN6855 PMU node to bypass pwrseq flow There is a conflict between the current DTS configuration and the driver behavior for the WCN6855 Bluetooth path. With the PMU node in place, the driver takes the pwrseq code path unintentionally, which leads to Bluetooth failing to power up during an on -> off -> on transition. To unblock function, temporarily remove the WCN6855 PMU node so that the driver follows the non-pwrseq path and avoids the unexpected sequence. This is a TEMPORARY WORKAROUND. Once a proper M.2 binding/solution is upstreamed, will re-submit both DTS and driver changes aligned with the M.2 model. Signed-off-by: Wei Deng --- arch/arm64/boot/dts/qcom/lemans-evk.dts | 73 +++---------------------- arch/arm64/boot/dts/qcom/monaco-evk.dts | 73 +++---------------------- 2 files changed, 16 insertions(+), 130 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/lemans-evk.dts b/arch/arm64/boot/dts/qcom/lemans-evk.dts index 64e3d231d837a..ccd998d7de637 100644 --- a/arch/arm64/boot/dts/qcom/lemans-evk.dts +++ b/arch/arm64/boot/dts/qcom/lemans-evk.dts @@ -147,63 +147,6 @@ regulator-boot-on; }; - - wcn6855-pmu { - compatible = "qcom,wcn6855-pmu"; - - vddio-supply = <&vreg_wcn_3p3>; - vddaon-supply = <&vreg_wcn_3p3>; - vddpmu-supply = <&vreg_wcn_3p3>; - vddpmumx-supply = <&vreg_wcn_3p3>; - vddpmucx-supply = <&vreg_wcn_3p3>; - vddrfa0p95-supply = <&vreg_wcn_3p3>; - vddrfa1p3-supply = <&vreg_wcn_3p3>; - vddrfa1p9-supply = <&vreg_wcn_3p3>; - vddpcielp3-supply = <&vreg_wcn_3p3>; - vddpcielp9-supply = <&vreg_wcn_3p3>; - - regulators { - vreg_pmu_rfa_cmn: ldo0 { - regulator-name = "vreg_pmu_rfa_cmn"; - }; - - vreg_pmu_aon_0p59: ldo1 { - regulator-name = "vreg_pmu_aon_0p59"; - }; - - vreg_pmu_wlcx_0p8: ldo2 { - regulator-name = "vreg_pmu_wlcx_0p8"; - }; - - vreg_pmu_wlmx_0p85: ldo3 { - regulator-name = "vreg_pmu_wlmx_0p85"; - }; - - vreg_pmu_btcmx_0p85: ldo4 { - regulator-name = "vreg_pmu_btcmx_0p85"; - }; - - vreg_pmu_rfa_0p8: ldo5 { - regulator-name = "vreg_pmu_rfa_0p8"; - }; - - vreg_pmu_rfa_1p2: ldo6 { - regulator-name = "vreg_pmu_rfa_1p2"; - }; - - vreg_pmu_rfa_1p8: ldo7 { - regulator-name = "vreg_pmu_rfa_1p8"; - }; - - vreg_pmu_pcie_0p9: ldo8 { - regulator-name = "vreg_pmu_pcie_0p9"; - }; - - vreg_pmu_pcie_1p8: ldo9 { - regulator-name = "vreg_pmu_pcie_1p8"; - }; - }; - }; }; &apps_rsc { @@ -870,14 +813,14 @@ compatible = "qcom,wcn6855-bt"; max-speed = <3200000>; - vddrfacmn-supply = <&vreg_pmu_rfa_cmn>; - vddaon-supply = <&vreg_pmu_aon_0p59>; - vddwlcx-supply = <&vreg_pmu_wlcx_0p8>; - vddwlmx-supply = <&vreg_pmu_wlmx_0p85>; - vddbtcmx-supply = <&vreg_pmu_btcmx_0p85>; - vddrfa0p8-supply = <&vreg_pmu_rfa_0p8>; - vddrfa1p2-supply = <&vreg_pmu_rfa_1p2>; - vddrfa1p8-supply = <&vreg_pmu_rfa_1p8>; + vddrfacmn-supply = <&vreg_wcn_3p3>; + vddaon-supply = <&vreg_wcn_3p3>; + vddwlcx-supply = <&vreg_wcn_3p3>; + vddwlmx-supply = <&vreg_wcn_3p3>; + vddbtcmx-supply = <&vreg_wcn_3p3>; + vddrfa0p8-supply = <&vreg_wcn_3p3>; + vddrfa1p2-supply = <&vreg_wcn_3p3>; + vddrfa1p8-supply = <&vreg_wcn_3p3>; }; }; diff --git a/arch/arm64/boot/dts/qcom/monaco-evk.dts b/arch/arm64/boot/dts/qcom/monaco-evk.dts index 697a30a9a4755..5e1581e1f2711 100644 --- a/arch/arm64/boot/dts/qcom/monaco-evk.dts +++ b/arch/arm64/boot/dts/qcom/monaco-evk.dts @@ -101,63 +101,6 @@ regulator-boot-on; }; - - wcn6855-pmu { - compatible = "qcom,wcn6855-pmu"; - - vddio-supply = <&vreg_wcn_3p3>; - vddaon-supply = <&vreg_wcn_3p3>; - vddpmu-supply = <&vreg_wcn_3p3>; - vddpmumx-supply = <&vreg_wcn_3p3>; - vddpmucx-supply = <&vreg_wcn_3p3>; - vddrfa0p95-supply = <&vreg_wcn_3p3>; - vddrfa1p3-supply = <&vreg_wcn_3p3>; - vddrfa1p9-supply = <&vreg_wcn_3p3>; - vddpcielp3-supply = <&vreg_wcn_3p3>; - vddpcielp9-supply = <&vreg_wcn_3p3>; - - regulators { - vreg_pmu_rfa_cmn: ldo0 { - regulator-name = "vreg_pmu_rfa_cmn"; - }; - - vreg_pmu_aon_0p59: ldo1 { - regulator-name = "vreg_pmu_aon_0p59"; - }; - - vreg_pmu_wlcx_0p8: ldo2 { - regulator-name = "vreg_pmu_wlcx_0p8"; - }; - - vreg_pmu_wlmx_0p85: ldo3 { - regulator-name = "vreg_pmu_wlmx_0p85"; - }; - - vreg_pmu_btcmx_0p85: ldo4 { - regulator-name = "vreg_pmu_btcmx_0p85"; - }; - - vreg_pmu_rfa_0p8: ldo5 { - regulator-name = "vreg_pmu_rfa_0p8"; - }; - - vreg_pmu_rfa_1p2: ldo6 { - regulator-name = "vreg_pmu_rfa_1p2"; - }; - - vreg_pmu_rfa_1p8: ldo7 { - regulator-name = "vreg_pmu_rfa_1p8"; - }; - - vreg_pmu_pcie_0p9: ldo8 { - regulator-name = "vreg_pmu_pcie_0p9"; - }; - - vreg_pmu_pcie_1p8: ldo9 { - regulator-name = "vreg_pmu_pcie_1p8"; - }; - }; - }; }; &apps_rsc { @@ -711,14 +654,14 @@ compatible = "qcom,wcn6855-bt"; max-speed = <3200000>; - vddrfacmn-supply = <&vreg_pmu_rfa_cmn>; - vddaon-supply = <&vreg_pmu_aon_0p59>; - vddwlcx-supply = <&vreg_pmu_wlcx_0p8>; - vddwlmx-supply = <&vreg_pmu_wlmx_0p85>; - vddbtcmx-supply = <&vreg_pmu_btcmx_0p85>; - vddrfa0p8-supply = <&vreg_pmu_rfa_0p8>; - vddrfa1p2-supply = <&vreg_pmu_rfa_1p2>; - vddrfa1p8-supply = <&vreg_pmu_rfa_1p8>; + vddrfacmn-supply = <&vreg_wcn_3p3>; + vddaon-supply = <&vreg_wcn_3p3>; + vddwlcx-supply = <&vreg_wcn_3p3>; + vddwlmx-supply = <&vreg_wcn_3p3>; + vddbtcmx-supply = <&vreg_wcn_3p3>; + vddrfa0p8-supply = <&vreg_wcn_3p3>; + vddrfa1p2-supply = <&vreg_wcn_3p3>; + vddrfa1p8-supply = <&vreg_wcn_3p3>; }; }; From 659389d7914786775d0f638d12d4165de71a42fa Mon Sep 17 00:00:00 2001 From: Yuanjie Yang Date: Thu, 8 Jan 2026 17:25:42 +0800 Subject: [PATCH 2199/2333] BACKPORT: arm64: dts: qcom: talos: Add PMU support Add the PMU node for talos platforms. Signed-off-by: Yuanjie Yang Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20260108092542.1371-3-yuanjie.yang@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/talos.dtsi | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/talos.dtsi b/arch/arm64/boot/dts/qcom/talos.dtsi index 308e8e5ffb796..094482e77dd0e 100644 --- a/arch/arm64/boot/dts/qcom/talos.dtsi +++ b/arch/arm64/boot/dts/qcom/talos.dtsi @@ -557,6 +557,16 @@ }; }; + pmu-a55 { + compatible = "arm,cortex-a55-pmu"; + interrupts = ; + }; + + pmu-a76 { + compatible = "arm,cortex-a76-pmu"; + interrupts = ; + }; + psci: psci { compatible = "arm,psci-1.0"; method = "smc"; @@ -4676,6 +4686,16 @@ interrupt-controller; #redistributor-regions = <1>; redistributor-stride = <0x0 0x20000>; + + ppi-partitions { + ppi_cluster0: interrupt-partition-0 { + affinity = <&cpu0 &cpu1 &cpu2 &cpu3 &cpu4 &cpu5>; + }; + + ppi_cluster1: interrupt-partition-1 { + affinity = <&cpu6 &cpu7>; + }; + }; }; apss_shared: mailbox@17c00000 { From 34f1dd20200e42e977ad5d9ef4c14d36653d3c74 Mon Sep 17 00:00:00 2001 From: Xin Liu Date: Wed, 24 Dec 2025 14:00:56 +0800 Subject: [PATCH 2200/2333] QCLINUX: arm64: dts: qcom: change pil camera memory map Add the pil camera carveout region based on v2 memory map. Signed-off-by: Qingqing Zhou Signed-off-by: Yuanjie Yang --- arch/arm64/boot/dts/qcom/talos.dtsi | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/talos.dtsi b/arch/arm64/boot/dts/qcom/talos.dtsi index 308e8e5ffb796..41c26e0caf5bb 100644 --- a/arch/arm64/boot/dts/qcom/talos.dtsi +++ b/arch/arm64/boot/dts/qcom/talos.dtsi @@ -654,6 +654,11 @@ reg = <0x0 0x97715000 0x0 0x2000>; no-map; }; + + pil_camera_mem: pil-camera-region@97717000 { + reg = <0x0 0x97717000 0x0 0x800000>; + no-map; + }; }; soc: soc@0 { From 349e69ae6682986a6791131f957c0f9135a4cdc4 Mon Sep 17 00:00:00 2001 From: Mukesh Ojha Date: Mon, 2 Feb 2026 16:06:40 +0530 Subject: [PATCH 2201/2333] FROMLIST: soc: qcom: pd-mapper: Fix element length in servreg_loc_pfr_req_ei It looks element length declared in servreg_loc_pfr_req_ei for reason not matching servreg_loc_pfr_req's reason field due which we could observe decoding error on PD crash. qmi_decode_string_elem: String len 81 >= Max Len 65 Fix this by matching with servreg_loc_pfr_req's reason field. Cc: stable@vger.kernel.org Fixes: 1ebcde047c54 ("soc: qcom: add pd-mapper implementation") Reviewed-by: Dmitry Baryshkov Co-developed-by: Gokul Krishnakumar Signed-off-by: Gokul Krishnakumar Signed-off-by: Mukesh Ojha Signed-off-by: Xin Liu Link: https://lore.kernel.org/all/20260202103641.3003867-1-mukesh.ojha@oss.qualcomm.com/ --- drivers/soc/qcom/pdr_internal.h | 2 +- drivers/soc/qcom/qcom_pdr_msg.c | 2 +- include/linux/soc/qcom/pdr.h | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/soc/qcom/pdr_internal.h b/drivers/soc/qcom/pdr_internal.h index 039508c1bbf7d..047c0160b6178 100644 --- a/drivers/soc/qcom/pdr_internal.h +++ b/drivers/soc/qcom/pdr_internal.h @@ -84,7 +84,7 @@ struct servreg_set_ack_resp { struct servreg_loc_pfr_req { char service[SERVREG_NAME_LENGTH + 1]; - char reason[257]; + char reason[SERVREG_PFR_LENGTH + 1]; }; struct servreg_loc_pfr_resp { diff --git a/drivers/soc/qcom/qcom_pdr_msg.c b/drivers/soc/qcom/qcom_pdr_msg.c index ca98932140d87..02022b11ecf05 100644 --- a/drivers/soc/qcom/qcom_pdr_msg.c +++ b/drivers/soc/qcom/qcom_pdr_msg.c @@ -325,7 +325,7 @@ const struct qmi_elem_info servreg_loc_pfr_req_ei[] = { }, { .data_type = QMI_STRING, - .elem_len = SERVREG_NAME_LENGTH + 1, + .elem_len = SERVREG_PFR_LENGTH + 1, .elem_size = sizeof(char), .array_type = VAR_LEN_ARRAY, .tlv_type = 0x02, diff --git a/include/linux/soc/qcom/pdr.h b/include/linux/soc/qcom/pdr.h index 83a8ea612e69a..2b7691e47c2a9 100644 --- a/include/linux/soc/qcom/pdr.h +++ b/include/linux/soc/qcom/pdr.h @@ -5,6 +5,7 @@ #include #define SERVREG_NAME_LENGTH 64 +#define SERVREG_PFR_LENGTH 256 struct pdr_service; struct pdr_handle; From 42c7a1ca2132e6904542956d2ff81c536257a895 Mon Sep 17 00:00:00 2001 From: Mukesh Ojha Date: Mon, 2 Feb 2026 16:06:41 +0530 Subject: [PATCH 2202/2333] FROMLIST: soc: qcom: qmi: Print error codes in failure paths Few error paths in the qmi_interface module log a failure message but do not include the actual error code. Include the error value in the log so debugging failures becomes easier. Reviewed-by: Dmitry Baryshkov Signed-off-by: Mukesh Ojha Signed-off-by: Xin Liu Link: https://lore.kernel.org/all/20260202103641.3003867-2-mukesh.ojha@oss.qualcomm.com/ --- drivers/soc/qcom/qmi_interface.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/soc/qcom/qmi_interface.c b/drivers/soc/qcom/qmi_interface.c index 6500f863aae5c..941612b1bd2e6 100644 --- a/drivers/soc/qcom/qmi_interface.c +++ b/drivers/soc/qcom/qmi_interface.c @@ -321,7 +321,7 @@ int qmi_txn_init(struct qmi_handle *qmi, struct qmi_txn *txn, mutex_lock(&qmi->txn_lock); ret = idr_alloc_cyclic(&qmi->txns, txn, 0, U16_MAX, GFP_KERNEL); if (ret < 0) - pr_err("failed to allocate transaction id\n"); + pr_err("failed to allocate transaction id: %d\n", ret); txn->id = ret; mutex_unlock(&qmi->txn_lock); @@ -413,7 +413,7 @@ static void qmi_invoke_handler(struct qmi_handle *qmi, struct sockaddr_qrtr *sq, ret = qmi_decode_message(buf, len, handler->ei, dest); if (ret < 0) - pr_err("failed to decode incoming message\n"); + pr_err("failed to decode incoming message: %d\n", ret); else handler->fn(qmi, sq, txn, dest); @@ -502,7 +502,7 @@ static void qmi_handle_message(struct qmi_handle *qmi, if (txn->dest && txn->ei) { ret = qmi_decode_message(buf, len, txn->ei, txn->dest); if (ret < 0) - pr_err("failed to decode incoming message\n"); + pr_err("failed to decode incoming message: %d\n", ret); txn->result = ret; complete(&txn->completion); @@ -661,8 +661,8 @@ int qmi_handle_init(struct qmi_handle *qmi, size_t recv_buf_size, if (PTR_ERR(qmi->sock) == -EAFNOSUPPORT) { ret = -EPROBE_DEFER; } else { - pr_err("failed to create QMI socket\n"); ret = PTR_ERR(qmi->sock); + pr_err("failed to create QMI socket: %d\n", ret); } goto err_destroy_wq; } @@ -766,7 +766,7 @@ static ssize_t qmi_send_message(struct qmi_handle *qmi, if (qmi->sock) { ret = kernel_sendmsg(qmi->sock, &msghdr, &iv, 1, len); if (ret < 0) - pr_err("failed to send QMI message\n"); + pr_err("failed to send QMI message: %d\n", ret); } else { ret = -EPIPE; } From d921928559e1e0c4039cc4d7898baeb12baa09b1 Mon Sep 17 00:00:00 2001 From: Chandan Kumar Jha Date: Tue, 3 Feb 2026 10:54:54 +0530 Subject: [PATCH 2203/2333] QCLINUX: arm64: dts: qcom: Add camx overlay fixes for KLM The following changes are backported from the 6.19 kernel into the 6.18.y stable branch. - Fix the indentation issue. - Update DT clock property name after clock. - Short DT nodes. - Fix indexing issue. - Update gpios shared pin. - Change the path for the camera firmware. - Enable imx577 sensor on lemans boards from slot0 to slot3. Signed-off-by: Chandan Kumar Jha --- arch/arm64/boot/dts/qcom/lemans-camera.dtsi | 51 +-- .../dts/qcom/lemans-evk-camera-sensor.dtsi | 384 ++++++++++++++++++ .../boot/dts/qcom/monaco-camera-sensor.dtsi | 2 +- arch/arm64/boot/dts/qcom/monaco-camera.dtsi | 212 +++++----- arch/arm64/boot/dts/qcom/qcs6490-camera.dtsi | 8 +- 5 files changed, 514 insertions(+), 143 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/lemans-camera.dtsi b/arch/arm64/boot/dts/qcom/lemans-camera.dtsi index 18d78926b1f17..d6cce86922c26 100644 --- a/arch/arm64/boot/dts/qcom/lemans-camera.dtsi +++ b/arch/arm64/boot/dts/qcom/lemans-camera.dtsi @@ -667,7 +667,7 @@ status = "ok"; }; - qcom,cam-cpas { + cam_cpas: qcom,cam-cpas { compatible = "qcom,cam-cpas"; label = "cpas"; arch-compat = "cpas_top"; @@ -743,8 +743,7 @@ "ife5", "ife6", "ipe0", "sfe0", "sfe1", "cam-cdm-intf0", "rt-cdm0", "rt-cdm1", "rt-cdm2", "rt-cdm3", "icp0", "tpg17", "tpg18", "tpg19"; - - enable-secure-qos-update; + enable-secure-qos-update = <1>; cell-index = <0>; status = "ok"; @@ -817,7 +816,6 @@ parent-node = <&level1_rt_wr0>; }; - ife_1_wr_1: ife-1-wr-1 { cell-index = <4>; node-name = "ife-1-wr-1"; @@ -958,8 +956,7 @@ node-name = "rt-cdm2-all-rd-2"; client-name = "rt-cdm2"; traffic-data = ; - traffic-transaction-type = - ; + traffic-transaction-type = ; parent-node = <&level1_nrt_rd2>; }; @@ -1086,8 +1083,7 @@ level3_nrt0_rd_wr_sum: level3-nrt0-rd-wr-sum { cell-index = <30>; node-name = "level3-nrt0-rd-wr-sum"; - traffic-merge-type = - ; + traffic-merge-type = ; qcom,axi-port-mnoc { cam-icc-path-names = "cam_sf_0"; @@ -1097,8 +1093,7 @@ level3_nrt1_rd_wr_sum: level3-nrt1-rd-wr-sum { cell-index = <31>; node-name = "level3-nrt1-rd-wr-sum"; - traffic-merge-type = - ; + traffic-merge-type = ; qcom,axi-port-mnoc { cam-icc-path-names = "cam_sf_icp"; @@ -1108,8 +1103,7 @@ level3_rt_rd_wr_sum: level3-rt-rd-wr-sum { cell-index = <32>; node-name = "level3-rt-rd-wr-sum"; - traffic-merge-type = - ; + traffic-merge-type = ; ib-bw-voting-needed; qcom,axi-port-mnoc { @@ -1120,7 +1114,7 @@ }; }; - qcom,cam-icp { + cam_icp_firmware: qcom,cam-icp { compatible = "qcom,cam-icp"; compat-hw-name = "qcom,icp", "qcom,ipe0"; num-icp = <1>; @@ -1148,8 +1142,8 @@ status = "ok"; }; - qcom,cam-sync { - compatible = "qcom,cam-sync"; + qcom,camera-main { + compatible = "qcom,camera"; status = "ok"; }; @@ -1274,8 +1268,8 @@ }; }; - qcom,camera-main { - compatible = "qcom,camera"; + qcom,cam-sync { + compatible = "qcom,cam-sync"; status = "ok"; }; @@ -1544,13 +1538,6 @@ interrupts = ; interrupt-names = "csid-lite4"; power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; - clock-names = "cam_cc_cpas_ife_lite_clk", - "cam_cc_ife_lite_ahb_clk", - "cam_cc_ife_lite_csid_clk_src", - "cam_cc_ife_lite_csid_clk", - "cam_cc_ife_lite_cphy_rx_clk", - "cam_cc_ife_lite_clk_src", - "cam_cc_ife_lite_clk"; clocks = <&camcc CAM_CC_CPAS_IFE_LITE_CLK>, <&camcc CAM_CC_IFE_LITE_AHB_CLK>, <&camcc CAM_CC_IFE_LITE_CSID_CLK_SRC>, @@ -1558,6 +1545,13 @@ <&camcc CAM_CC_IFE_LITE_CPHY_RX_CLK>, <&camcc CAM_CC_IFE_LITE_CLK_SRC>, <&camcc CAM_CC_IFE_LITE_CLK>; + clock-names = "cam_cc_cpas_ife_lite_clk", + "cam_cc_ife_lite_ahb_clk", + "cam_cc_ife_lite_csid_clk_src", + "cam_cc_ife_lite_csid_clk", + "cam_cc_ife_lite_cphy_rx_clk", + "cam_cc_ife_lite_clk_src", + "cam_cc_ife_lite_clk"; clock-rates = <0 0 400000000 0 0 400000000 0>, <0 0 400000000 0 0 480000000 0>; clock-cntl-level = "svs_l1", "nominal"; @@ -1606,7 +1600,7 @@ <400000000 0 600000000 0>; clock-cntl-level = "svs_l1", "nominal"; nrt-device; - fw_name = "CAMERA_ICP"; + fw_name = "qcom/sa8775p/CAMERA_ICP"; ubwc-ipe-fetch-cfg = <0x707b 0x7083>; ubwc-ipe-write-cfg = <0x161ef 0x1620f>; qos-val = <0xa0a>; @@ -2000,7 +1994,6 @@ required-opps = <&rpmhpd_opp_nom>; }; }; - }; qcom,rt-cdm0 { @@ -2140,12 +2133,12 @@ interrupts = ; interrupt-names = "sfe-lite0"; power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; - clock-names = "cam_cc_sfe_lite_0_fast_ahb_clk", - "cam_cc_sfe_lite_0_clk", - "cam_cc_cpas_sfe_lite_0_clk"; clocks = <&camcc CAM_CC_SFE_LITE_0_FAST_AHB_CLK>, <&camcc CAM_CC_SFE_LITE_0_CLK>, <&camcc CAM_CC_CPAS_SFE_LITE_0_CLK>; + clock-names = "cam_cc_sfe_lite_0_fast_ahb_clk", + "cam_cc_sfe_lite_0_clk", + "cam_cc_cpas_sfe_lite_0_clk"; clock-rates = <0 480000000 300000000>, <0 600000000 400000000>; clock-cntl-level = "svs_l1", "nominal"; diff --git a/arch/arm64/boot/dts/qcom/lemans-evk-camera-sensor.dtsi b/arch/arm64/boot/dts/qcom/lemans-evk-camera-sensor.dtsi index 8eb1026e7da1b..decd2e8c3d192 100644 --- a/arch/arm64/boot/dts/qcom/lemans-evk-camera-sensor.dtsi +++ b/arch/arm64/boot/dts/qcom/lemans-evk-camera-sensor.dtsi @@ -205,6 +205,47 @@ status = "ok"; }; + /*cam0-cmk_imx577*/ + qcom,cam-sensor27 { + compatible = "qcom,cam-sensor"; + csiphy-sd-index = <0>; + sensor-position-roll = <0>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + eeprom-src = <&eeprom_cam27>; + cam_vio-supply = <&vreg_s4a>; + regulator-names = "cam_vio"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000>; + rgltr-max-voltage = <1800000>; + rgltr-load-current = <120000>; + gpio-no-mux = <0>; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_active_rst0>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_suspend_rst0>; + pinctrl-names = "cam_default", "cam_suspend"; + gpios = <&tlmm 72 0>, + <&tlmm 132 0>, + <&pmm8654au_0_gpios 7 0>; + gpio-reset = <1>; + gpio-custom1 = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAM_MCLK0", + "CAMIF_RESET0", + "CAM_CUSTOM1"; + cci-master = <0>; + clocks = <&camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "nominal"; + clock-rates = <24000000>; + cell-index = <27>; + status = "ok"; + }; + eeprom_cam24: qcom,eeprom24 { compatible = "qcom,eeprom"; cam_vio-supply = <&vreg_s4a>; @@ -239,6 +280,41 @@ cell-index = <24>; status = "ok"; }; + + eeprom_cam27: qcom,eeprom27 { + compatible = "qcom,eeprom"; + cam_vio-supply = <&vreg_s4a>; + regulator-names = "cam_vio"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000>; + rgltr-max-voltage = <1800000>; + rgltr-load-current = <120000>; + gpio-no-mux = <0>; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_active_rst0>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_suspend_rst0>; + gpios = <&tlmm 72 0>, + <&tlmm 132 0>, + <&pmm8654au_0_gpios 7 0>; + gpio-reset = <1>; + gpio-custom1 = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAM_MCLK0", + "CAMIF_RESET0", + "CAM_CUSTOM1"; + sensor-mode = <0>; + cci-master = <0>; + clocks = <&camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "nominal"; + clock-rates = <24000000>; + cell-index = <27>; + status = "ok"; + }; }; &cam_cci1 { @@ -401,6 +477,160 @@ cell-index = <21>; status = "ok"; }; + + /*cam1-imx577*/ + qcom,cam-sensor26 { + compatible = "qcom,cam-sensor"; + csiphy-sd-index = <1>; + sensor-position-roll = <0>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + eeprom-src = <&eeprom_cam26>; + cam_vio-supply = <&vreg_s4a>; + regulator-names = "cam_vio"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000>; + rgltr-max-voltage = <1800000>; + rgltr-load-current = <120000>; + gpio-no-mux = <0>; + pinctrl-0 = <&cam_sensor_mclk1_active + &cam_sensor_active_rst1>; + pinctrl-1 = <&cam_sensor_mclk1_suspend + &cam_sensor_suspend_rst1>; + pinctrl-names = "cam_default", "cam_suspend"; + gpios = <&tlmm 73 0>, + <&tlmm 133 0>, + <&pmm8654au_0_gpios 8 0>; + gpio-reset = <1>; + gpio-custom1 = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAM_MCLK1", + "CAMIF_RESET1", + "CAM_CUSTOM1"; + cci-master = <0>; + clocks = <&camcc CAM_CC_MCLK1_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "nominal"; + clock-rates = <24000000>; + cell-index = <26>; + status = "ok"; + }; + + /*cam1-cmk_imx577*/ + qcom,cam-sensor28 { + compatible = "qcom,cam-sensor"; + csiphy-sd-index = <1>; + sensor-position-roll = <0>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + eeprom-src = <&eeprom_cam28>; + cam_vio-supply = <&vreg_s4a>; + regulator-names = "cam_vio"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000>; + rgltr-max-voltage = <1800000>; + rgltr-load-current = <120000>; + gpio-no-mux = <0>; + pinctrl-0 = <&cam_sensor_mclk1_active + &cam_sensor_active_rst1>; + pinctrl-1 = <&cam_sensor_mclk1_suspend + &cam_sensor_suspend_rst1>; + pinctrl-names = "cam_default", "cam_suspend"; + gpios = <&tlmm 73 0>, + <&tlmm 133 0>, + <&pmm8654au_0_gpios 8 0>; + gpio-reset = <1>; + gpio-custom1 = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAM_MCLK1", + "CAMIF_RESET1", + "CAM_CUSTOM1"; + cci-master = <0>; + clocks = <&camcc CAM_CC_MCLK1_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "nominal"; + clock-rates = <24000000>; + cell-index = <28>; + status = "ok"; + }; + + eeprom_cam26: qcom,eeprom26 { + compatible = "qcom,eeprom"; + cam_vio-supply = <&vreg_s4a>; + regulator-names = "cam_vio"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000>; + rgltr-max-voltage = <1800000>; + rgltr-load-current = <120000>; + gpio-no-mux = <0>; + pinctrl-0 = <&cam_sensor_mclk1_active + &cam_sensor_active_rst1>; + pinctrl-1 = <&cam_sensor_mclk1_suspend + &cam_sensor_suspend_rst1>; + pinctrl-names = "cam_default", "cam_suspend"; + gpios = <&tlmm 73 0>, + <&tlmm 133 0>, + <&pmm8654au_0_gpios 8 0>; + gpio-reset = <1>; + gpio-custom1 = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAMIF_MCLK1", + "CAM_RESET1", + "CAM_CUSTOM1"; + sensor-mode = <0>; + cci-master = <0>; + clocks = <&camcc CAM_CC_MCLK1_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "nominal"; + clock-rates = <24000000>; + cell-index = <26>; + status = "ok"; + }; + + eeprom_cam28: qcom,eeprom28 { + compatible = "qcom,eeprom"; + cam_vio-supply = <&vreg_s4a>; + regulator-names = "cam_vio"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000>; + rgltr-max-voltage = <1800000>; + rgltr-load-current = <120000>; + gpio-no-mux = <0>; + pinctrl-0 = <&cam_sensor_mclk1_active + &cam_sensor_active_rst1>; + pinctrl-1 = <&cam_sensor_mclk1_suspend + &cam_sensor_suspend_rst1>; + pinctrl-names = "cam_default", "cam_suspend"; + gpios = <&tlmm 73 0>, + <&tlmm 133 0>, + <&pmm8654au_0_gpios 8 0>; + gpio-reset = <1>; + gpio-custom1 = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAMIF_MCLK1", + "CAM_RESET1", + "CAM_CUSTOM1"; + sensor-mode = <0>; + cci-master = <0>; + clocks = <&camcc CAM_CC_MCLK1_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "nominal"; + clock-rates = <24000000>; + cell-index = <28>; + status = "ok"; + }; }; &cam_cci2 { @@ -563,6 +793,83 @@ cell-index = <22>; status = "ok"; }; + + /*cam2-cmk_imx577*/ + qcom,cam-sensor29 { + compatible = "qcom,cam-sensor"; + csiphy-sd-index = <2>; + sensor-position-roll = <0>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + eeprom-src = <&eeprom_cam29>; + cam_vio-supply = <&vreg_s4a>; + regulator-names = "cam_vio"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000>; + rgltr-max-voltage = <1800000>; + rgltr-load-current = <120000>; + gpio-no-mux = <0>; + pinctrl-0 = <&cam_sensor_mclk2_active + &cam_sensor_active_rst2>; + pinctrl-1 = <&cam_sensor_mclk2_suspend + &cam_sensor_suspend_rst2>; + pinctrl-names = "cam_default", "cam_suspend"; + gpios = <&tlmm 74 0>, + <&tlmm 134 0>, + <&pmm8654au_0_gpios 9 0>; + gpio-reset = <1>; + gpio-custom1 = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAM_MCLK2", + "CAMIF_RESET2", + "CAM_CUSTOM1"; + cci-master = <0>; + clocks = <&camcc CAM_CC_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "nominal"; + clock-rates = <24000000>; + cell-index = <29>; + status = "ok"; + }; + + eeprom_cam29: qcom,eeprom29 { + compatible = "qcom,eeprom"; + cam_vio-supply = <&vreg_s4a>; + regulator-names = "cam_vio"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000>; + rgltr-max-voltage = <1800000>; + rgltr-load-current = <120000>; + gpio-no-mux = <0>; + pinctrl-0 = <&cam_sensor_mclk2_active + &cam_sensor_active_rst2>; + pinctrl-1 = <&cam_sensor_mclk2_suspend + &cam_sensor_suspend_rst2>; + pinctrl-names = "cam_default", "cam_suspend"; + gpios = <&tlmm 74 0>, + <&tlmm 134 0>, + <&pmm8654au_0_gpios 9 0>; + gpio-reset = <1>; + gpio-custom1 = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET2", + "CAM_CUSTOM1"; + sensor-mode = <0>; + cci-master = <0>; + clocks = <&camcc CAM_CC_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "nominal"; + clock-rates = <24000000>; + cell-index = <29>; + status = "ok"; + }; }; &cam_cci3 { @@ -725,6 +1032,83 @@ cell-index = <23>; status = "ok"; }; + + /*cam3-cmk_imx577*/ + qcom,cam-sensor30 { + compatible = "qcom,cam-sensor"; + csiphy-sd-index = <3>; + sensor-position-roll = <0>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + eeprom-src = <&eeprom_cam30>; + cam_vio-supply = <&vreg_s4a>; + regulator-names = "cam_vio"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000>; + rgltr-max-voltage = <1800000>; + rgltr-load-current = <120000>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk3_active + &cam_sensor_active_rst3>; + pinctrl-1 = <&cam_sensor_mclk3_suspend + &cam_sensor_suspend_rst3>; + gpios = <&tlmm 75 0>, + <&tlmm 135 0>, + <&pmm8654au_0_gpios 10 0>; + gpio-reset = <1>; + gpio-custom1 = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAM_MCLK3", + "CAMIF_RESET3", + "CAM_CUSTOM1"; + cci-master = <0>; + clocks = <&camcc CAM_CC_MCLK3_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "nominal"; + clock-rates = <24000000>; + cell-index = <30>; + status = "ok"; + }; + + eeprom_cam30: qcom,eeprom30 { + compatible = "qcom,eeprom"; + cam_vio-supply = <&vreg_s4a>; + regulator-names = "cam_vio"; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000>; + rgltr-max-voltage = <1800000>; + rgltr-load-current = <120000>; + gpio-no-mux = <0>; + pinctrl-0 = <&cam_sensor_mclk3_active + &cam_sensor_active_rst3>; + pinctrl-1 = <&cam_sensor_mclk3_suspend + &cam_sensor_suspend_rst3>; + gpios = <&tlmm 75 0>, + <&tlmm 135 0>, + <&pmm8654au_0_gpios 10 0>; + pinctrl-names = "cam_default", "cam_suspend"; + gpio-reset = <1>; + gpio-custom1 = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAMIF_MCLK3", + "CAM_RESET3", + "CAM_CUSTOM1"; + sensor-mode = <0>; + cci-master = <0>; + clocks = <&camcc CAM_CC_MCLK3_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "nominal"; + clock-rates = <24000000>; + cell-index = <30>; + status = "ok"; + }; }; &soc { diff --git a/arch/arm64/boot/dts/qcom/monaco-camera-sensor.dtsi b/arch/arm64/boot/dts/qcom/monaco-camera-sensor.dtsi index 0023c97edce91..a2a2cd0a27a3a 100644 --- a/arch/arm64/boot/dts/qcom/monaco-camera-sensor.dtsi +++ b/arch/arm64/boot/dts/qcom/monaco-camera-sensor.dtsi @@ -374,7 +374,7 @@ &soc { qcom,cam-res-mgr { compatible = "qcom,cam-res-mgr"; - gpios-shared = <518 519 520 521>; + gpios-shared = <609 610 611>; status = "ok"; }; }; diff --git a/arch/arm64/boot/dts/qcom/monaco-camera.dtsi b/arch/arm64/boot/dts/qcom/monaco-camera.dtsi index bd619b507831f..8250f66c34526 100644 --- a/arch/arm64/boot/dts/qcom/monaco-camera.dtsi +++ b/arch/arm64/boot/dts/qcom/monaco-camera.dtsi @@ -528,7 +528,7 @@ status = "ok"; }; - qcom,cam-cpas { + cam_cpas: qcom,cam-cpas { compatible = "qcom,cam-cpas"; label = "cpas"; arch-compat = "cpas_top"; @@ -565,8 +565,8 @@ "cam_cc_qdss_debug_xo_clk"; src-clock-name = "cam_cc_fast_ahb_clk_src"; clock-rates = <0 0 0 0 0 0 0 0 0 0 0>, - <0 0 0 80000000 0 0 300000000 0 400000000 0 0>, - <0 0 0 80000000 0 0 400000000 0 400000000 0 0>; + <0 0 0 80000000 0 0 300000000 0 400000000 0 0>, + <0 0 0 80000000 0 0 400000000 0 400000000 0 0>; clock-cntl-level = "suspend", "svs_l1", "nominal"; clock-names-option = "cam_icp_clk"; clocks-option = <&camcc CAM_CC_ICP_CLK>; @@ -605,7 +605,7 @@ "ife5", "ife6", "ipe0", "sfe0", "sfe1", "cam-cdm-intf0", "rt-cdm0", "rt-cdm1", "rt-cdm2", "rt-cdm3", "icp0", "tpg13", "tpg14", "tpg15"; - enable-secure-qos-update; + enable-secure-qos-update = <1>; cell-index = <0>; status = "ok"; @@ -679,7 +679,7 @@ }; ife_1_wr_1: ife-1-wr-1 { - cell-index = <3>; + cell-index = <4>; node-name = "ife-1-wr-1"; client-name = "ife1"; traffic-data = ; @@ -693,7 +693,7 @@ }; ife_lite_0_wr_0: ife-lite-0-wr-0 { - cell-index = <4>; + cell-index = <5>; node-name = "ife-lite-0-wr-0"; client-name = "ife2"; traffic-data = ; @@ -707,7 +707,7 @@ }; ife_lite_1_wr_0: ife-lite-1-wr-0 { - cell-index = <5>; + cell-index = <6>; node-name = "ife-lite-1-wr-0"; client-name = "ife3"; traffic-data = ; @@ -721,7 +721,7 @@ }; ife_lite_2_wr_0: ife-lite-2-wr-0 { - cell-index = <6>; + cell-index = <7>; node-name = "ife-lite-2-wr-0"; client-name = "ife4"; traffic-data = ; @@ -735,7 +735,7 @@ }; ife_lite_3_wr_0: ife-lite-3-wr-0 { - cell-index = <7>; + cell-index = <8>; node-name = "ife-lite-3-wr-0"; client-name = "ife5"; traffic-data = ; @@ -749,7 +749,7 @@ }; ife_lite_4_wr_0: ife-lite-4-wr-0 { - cell-index = <8>; + cell-index = <9>; node-name = "ife-lite-4-wr-0"; client-name = "ife6"; traffic-data = ; @@ -763,7 +763,7 @@ }; ipe_0_rd_all: ipe-0-rd-all { - cell-index = <9>; + cell-index = <10>; node-name = "ipe-0-rd-all"; client-name = "ipe0"; traffic-data = ; @@ -774,7 +774,7 @@ }; ipe_0_wr_2: ipe-0-wr-2 { - cell-index = <10>; + cell-index = <11>; node-name = "ipe-0-wr-2"; client-name = "ipe0"; traffic-data = ; @@ -787,7 +787,7 @@ }; ipe_cdm0_all_rd: ipe-cdm0-all-rd { - cell-index = <11>; + cell-index = <12>; node-name = "ipe-cdm0-all-rd"; client-name = "ipe0"; traffic-data = ; @@ -796,7 +796,7 @@ }; rt_cdm0_all_rd_2: rt-cdm0-all-rd-2 { - cell-index = <12>; + cell-index = <13>; node-name = "rt-cdm0-all-rd-2"; client-name = "rt-cdm0"; traffic-data = ; @@ -805,7 +805,7 @@ }; rt_cdm1_all_rd_2: rt-cdm1-all-rd-2 { - cell-index = <13>; + cell-index = <14>; node-name = "rt-cdm1-all-rd-2"; client-name = "rt-cdm1"; traffic-data = ; @@ -814,7 +814,7 @@ }; rt_cdm2_all_rd_2: rt-cdm2-all-rd-2 { - cell-index = <14>; + cell-index = <15>; node-name = "rt-cdm2-all-rd-2"; client-name = "rt-cdm2"; traffic-data = ; @@ -823,7 +823,7 @@ }; rt_cdm3_all_rd_2: rt-cdm3-all-rd-2 { - cell-index = <15>; + cell-index = <16>; node-name = "rt-cdm3-all-rd-2"; client-name = "rt-cdm3"; traffic-data = ; @@ -832,7 +832,7 @@ }; sfe_0_rd_0: sfe-0-rd-0 { - cell-index = <16>; + cell-index = <17>; node-name = "sfe-0-rd-0"; client-name = "sfe0"; traffic-data = ; @@ -842,7 +842,7 @@ }; sfe_1_rd_0: sfe-1-rd-0 { - cell-index = <17>; + cell-index = <18>; node-name = "sfe-1-rd-0"; client-name = "sfe1"; traffic-data = ; @@ -857,28 +857,28 @@ camnoc-max-needed; level1_nrt_rd2: level1-nrt-rd2 { - cell-index = <22>; + cell-index = <19>; node-name = "level1-nrt-rd2"; parent-node = <&level2_nrt_rd2>; traffic-merge-type = ; }; level1_rt_rd0: level1-rt-read0 { - cell-index = <21>; + cell-index = <20>; node-name = "level1-rt-rd0"; parent-node = <&level2_rt_rd0>; traffic-merge-type = ; }; level1_rt_wr0: level1-rt-wr0 { - cell-index = <19>; + cell-index = <21>; node-name = "level1-rt-wr0"; parent-node = <&level2_rt_wr0>; traffic-merge-type = ; }; level1_rt_wr1: level1-rt-wr1 { - cell-index = <20>; + cell-index = <22>; node-name = "level1-rt-wr1"; parent-node = <&level2_rt_wr1>; traffic-merge-type = ; @@ -976,10 +976,9 @@ }; }; - qcom,cam-icp { + cam_icp_firmware: qcom,cam-icp { compatible = "qcom,cam-icp"; - compat-hw-name = "qcom,icp", - "qcom,ipe0"; + compat-hw-name = "qcom,icp", "qcom,ipe0"; num-icp = <1>; num-ipe = <1>; icp_use_pil; @@ -1023,6 +1022,7 @@ cam-smmu-label = "rt-cdm"; dma-coherent; multiple-client-devices; + rt_cdm_iova_mem_map: iova-mem-map { iova-mem-region-io { /* IO region is approximately 4.0 GB */ @@ -1059,6 +1059,7 @@ iova-region-id = <0x6>; subregion_support; status = "ok"; + /* Used for HFI queues/sec heap */ iova-mem-region-generic-region { iova-region-name = "icp_hfi"; @@ -1096,7 +1097,6 @@ iova-region-id = <0x1>; status = "ok"; }; - }; }; @@ -1298,49 +1298,46 @@ }; }; - cam_csid_lite3: qcom,csid-lite3 { - cell-index = <5>; + cam_csid_lite2: qcom,csid-lite2 { compatible = "qcom,csid-lite692"; - reg-names = "csid-lite3"; - reg = <0x0 0xac90000 0x0 0xf01>; - reg-cam-base = <0x90000>; + reg = <0x0 0xac8c000 0x0 0xf01>; + reg-names = "csid-lite2"; + reg-cam-base = <0x8c000>; rt-wrapper-base = <0x83000>; - interrupt-names = "csid-lite3"; - interrupts = ; + interrupts = ; + interrupt-names = "csid-lite2"; power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; - clock-names = - "cam_cc_cpas_ife_lite_clk", - "cam_cc_ife_lite_ahb_clk", - "cam_cc_ife_lite_csid_clk_src", - "cam_cc_ife_lite_csid_clk", - "cam_cc_ife_lite_cphy_rx_clk", - "cam_cc_ife_lite_clk_src", - "cam_cc_ife_lite_clk"; - clocks = - <&camcc CAM_CC_CPAS_IFE_LITE_CLK>, - <&camcc CAM_CC_IFE_LITE_AHB_CLK>, - <&camcc CAM_CC_IFE_LITE_CSID_CLK_SRC>, - <&camcc CAM_CC_IFE_LITE_CSID_CLK>, - <&camcc CAM_CC_IFE_LITE_CPHY_RX_CLK>, - <&camcc CAM_CC_IFE_LITE_CLK_SRC>, - <&camcc CAM_CC_IFE_LITE_CLK>; - clock-rates = - <0 0 400000000 0 0 400000000 0>, - <0 0 400000000 0 0 480000000 0>; + clocks = <&camcc CAM_CC_CPAS_IFE_LITE_CLK>, + <&camcc CAM_CC_IFE_LITE_AHB_CLK>, + <&camcc CAM_CC_IFE_LITE_CSID_CLK_SRC>, + <&camcc CAM_CC_IFE_LITE_CSID_CLK>, + <&camcc CAM_CC_IFE_LITE_CPHY_RX_CLK>, + <&camcc CAM_CC_IFE_LITE_CLK_SRC>, + <&camcc CAM_CC_IFE_LITE_CLK>; + clock-names = "cam_cc_cpas_ife_lite_clk", + "cam_cc_ife_lite_ahb_clk", + "cam_cc_ife_lite_csid_clk_src", + "cam_cc_ife_lite_csid_clk", + "cam_cc_ife_lite_cphy_rx_clk", + "cam_cc_ife_lite_clk_src", + "cam_cc_ife_lite_clk"; + clock-rates = <0 0 400000000 0 0 400000000 0>, + <0 0 400000000 0 0 480000000 0>; clock-cntl-level = "svs_l1", "nominal"; src-clock-name = "cam_cc_ife_lite_csid_clk_src"; - operating-points-v2 = <&csid_lite3_opp_table>; - + operating-points-v2 = <&csid_lite2_opp_table>; clock-control-debugfs = "true"; + cell-index = <4>; status = "ok"; - csid_lite3_opp_table: opp-table { + csid_lite2_opp_table: opp-table { compatible = "operating-points-v2"; opp-400000000 { opp-hz = /bits/ 64 <400000000>; required-opps = <&rpmhpd_opp_svs_l1>; }; + opp-480000000 { opp-hz = /bits/ 64 <480000000>; required-opps = <&rpmhpd_opp_nom>; @@ -1348,49 +1345,46 @@ }; }; - cam_csid_lite2: qcom,csid-lite2 { - cell-index = <4>; + cam_csid_lite3: qcom,csid-lite3 { compatible = "qcom,csid-lite692"; - reg-names = "csid-lite2"; - reg = <0x0 0xac8c000 0x0 0xf01>; - reg-cam-base = <0x8c000>; + reg = <0x0 0xac90000 0x0 0xf01>; + reg-names = "csid-lite3"; + reg-cam-base = <0x90000>; rt-wrapper-base = <0x83000>; - interrupt-names = "csid-lite2"; - interrupts = ; + interrupts = ; + interrupt-names = "csid-lite3"; power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; - clock-names = - "cam_cc_cpas_ife_lite_clk", - "cam_cc_ife_lite_ahb_clk", - "cam_cc_ife_lite_csid_clk_src", - "cam_cc_ife_lite_csid_clk", - "cam_cc_ife_lite_cphy_rx_clk", - "cam_cc_ife_lite_clk_src", - "cam_cc_ife_lite_clk"; - clocks = - <&camcc CAM_CC_CPAS_IFE_LITE_CLK>, - <&camcc CAM_CC_IFE_LITE_AHB_CLK>, - <&camcc CAM_CC_IFE_LITE_CSID_CLK_SRC>, - <&camcc CAM_CC_IFE_LITE_CSID_CLK>, - <&camcc CAM_CC_IFE_LITE_CPHY_RX_CLK>, - <&camcc CAM_CC_IFE_LITE_CLK_SRC>, - <&camcc CAM_CC_IFE_LITE_CLK>; - clock-rates = - <0 0 400000000 0 0 400000000 0>, - <0 0 400000000 0 0 480000000 0>; + clocks = <&camcc CAM_CC_CPAS_IFE_LITE_CLK>, + <&camcc CAM_CC_IFE_LITE_AHB_CLK>, + <&camcc CAM_CC_IFE_LITE_CSID_CLK_SRC>, + <&camcc CAM_CC_IFE_LITE_CSID_CLK>, + <&camcc CAM_CC_IFE_LITE_CPHY_RX_CLK>, + <&camcc CAM_CC_IFE_LITE_CLK_SRC>, + <&camcc CAM_CC_IFE_LITE_CLK>; + clock-names = "cam_cc_cpas_ife_lite_clk", + "cam_cc_ife_lite_ahb_clk", + "cam_cc_ife_lite_csid_clk_src", + "cam_cc_ife_lite_csid_clk", + "cam_cc_ife_lite_cphy_rx_clk", + "cam_cc_ife_lite_clk_src", + "cam_cc_ife_lite_clk"; + clock-rates = <0 0 400000000 0 0 400000000 0>, + <0 0 400000000 0 0 480000000 0>; clock-cntl-level = "svs_l1", "nominal"; src-clock-name = "cam_cc_ife_lite_csid_clk_src"; - operating-points-v2 = <&csid_lite2_opp_table>; - + operating-points-v2 = <&csid_lite3_opp_table>; clock-control-debugfs = "true"; + cell-index = <5>; status = "ok"; - csid_lite2_opp_table: opp-table { + csid_lite3_opp_table: opp-table { compatible = "operating-points-v2"; opp-400000000 { opp-hz = /bits/ 64 <400000000>; required-opps = <&rpmhpd_opp_svs_l1>; }; + opp-480000000 { opp-hz = /bits/ 64 <480000000>; required-opps = <&rpmhpd_opp_nom>; @@ -1399,39 +1393,35 @@ }; cam_csid_lite4: qcom,csid-lite4 { - cell-index = <6>; compatible = "qcom,csid-lite692"; - reg-names = "csid-lite4"; reg = <0x0 0xac94000 0x0 0xf01>; + reg-names = "csid-lite4"; reg-cam-base = <0x94000>; rt-wrapper-base = <0x83000>; - interrupt-names = "csid-lite4"; interrupts = ; + interrupt-names = "csid-lite4"; power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; - clock-names = - "cam_cc_cpas_ife_lite_clk", - "cam_cc_ife_lite_ahb_clk", - "cam_cc_ife_lite_csid_clk_src", - "cam_cc_ife_lite_csid_clk", - "cam_cc_ife_lite_cphy_rx_clk", - "cam_cc_ife_lite_clk_src", - "cam_cc_ife_lite_clk"; - clocks = - <&camcc CAM_CC_CPAS_IFE_LITE_CLK>, - <&camcc CAM_CC_IFE_LITE_AHB_CLK>, - <&camcc CAM_CC_IFE_LITE_CSID_CLK_SRC>, - <&camcc CAM_CC_IFE_LITE_CSID_CLK>, - <&camcc CAM_CC_IFE_LITE_CPHY_RX_CLK>, - <&camcc CAM_CC_IFE_LITE_CLK_SRC>, - <&camcc CAM_CC_IFE_LITE_CLK>; - clock-rates = - <0 0 400000000 0 0 400000000 0>, - <0 0 400000000 0 0 480000000 0>; + clocks = <&camcc CAM_CC_CPAS_IFE_LITE_CLK>, + <&camcc CAM_CC_IFE_LITE_AHB_CLK>, + <&camcc CAM_CC_IFE_LITE_CSID_CLK_SRC>, + <&camcc CAM_CC_IFE_LITE_CSID_CLK>, + <&camcc CAM_CC_IFE_LITE_CPHY_RX_CLK>, + <&camcc CAM_CC_IFE_LITE_CLK_SRC>, + <&camcc CAM_CC_IFE_LITE_CLK>; + clock-names = "cam_cc_cpas_ife_lite_clk", + "cam_cc_ife_lite_ahb_clk", + "cam_cc_ife_lite_csid_clk_src", + "cam_cc_ife_lite_csid_clk", + "cam_cc_ife_lite_cphy_rx_clk", + "cam_cc_ife_lite_clk_src", + "cam_cc_ife_lite_clk"; + clock-rates = <0 0 400000000 0 0 400000000 0>, + <0 0 400000000 0 0 480000000 0>; clock-cntl-level = "svs_l1", "nominal"; src-clock-name = "cam_cc_ife_lite_csid_clk_src"; operating-points-v2 = <&csid_lite4_opp_table>; - clock-control-debugfs = "true"; + cell-index = <6>; status = "ok"; csid_lite4_opp_table: opp-table { @@ -1441,6 +1431,7 @@ opp-hz = /bits/ 64 <400000000>; required-opps = <&rpmhpd_opp_svs_l1>; }; + opp-480000000 { opp-hz = /bits/ 64 <480000000>; required-opps = <&rpmhpd_opp_nom>; @@ -1472,7 +1463,7 @@ <400000000 0 600000000 0>; clock-cntl-level = "svs_l1", "nominal"; nrt-device; - fw_name = "CAMERA_ICP"; + fw_name = "qcom/qcs8300/CAMERA_ICP"; ubwc-ipe-fetch-cfg = <0x707b 0x7083>; ubwc-ipe-write-cfg = <0x161ef 0x1620f>; qos-val = <0xa0a>; @@ -1489,6 +1480,7 @@ opp-hz = /bits/ 64 <480000000>; required-opps = <&rpmhpd_opp_svs_l1>; }; + opp-600000000 { opp-hz = /bits/ 64 <600000000>; required-opps = <&rpmhpd_opp_nom>; @@ -1532,6 +1524,7 @@ opp-hz = /bits/ 64 <480000000>; required-opps = <&rpmhpd_opp_svs_l1>; }; + opp-600000000 { opp-hz = /bits/ 64 <600000000>; required-opps = <&rpmhpd_opp_nom>; @@ -1575,6 +1568,7 @@ opp-hz = /bits/ 64 <480000000>; required-opps = <&rpmhpd_opp_svs_l1>; }; + opp-600000000 { opp-hz = /bits/ 64 <600000000>; required-opps = <&rpmhpd_opp_nom>; diff --git a/arch/arm64/boot/dts/qcom/qcs6490-camera.dtsi b/arch/arm64/boot/dts/qcom/qcs6490-camera.dtsi index f6af6827784bd..2fadfb9de1fee 100644 --- a/arch/arm64/boot/dts/qcom/qcs6490-camera.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs6490-camera.dtsi @@ -32,7 +32,7 @@ clock-cntl-level = "lowsvs", "svs", "svs_l1", "nominal"; src-clock-name = "soc_fast_ahb"; operating-points-v2 = <&a5_opp_table>; - fw_name = "CAMERA_ICP_170.elf"; + fw_name = "qcom/qcm6490/CAMERA_ICP_170.elf"; ubwc-ipe-fetch-cfg = <0x7073 0x707b>; ubwc-ipe-write-cfg = <0x161cf 0x161ef>; ubwc-bps-fetch-cfg = <0x7073 0x707b>; @@ -620,8 +620,8 @@ qcom,cam-icp { compatible = "qcom,cam-icp"; compat-hw-name = "qcom,a5", - "qcom,ipe0", - "qcom,bps"; + "qcom,ipe0", + "qcom,bps"; num-a5 = <1>; num-ipe = <1>; num-bps = <1>; @@ -643,7 +643,7 @@ qcom,cam-jpeg { compatible = "qcom,cam-jpeg"; compat-hw-name = "qcom,jpegenc", - "qcom,jpegdma"; + "qcom,jpegdma"; num-jpeg-enc = <1>; num-jpeg-dma = <1>; status = "ok"; From a1cd8acb2f51bd745470f92c8fcf4ce0dc7db958 Mon Sep 17 00:00:00 2001 From: Vikram Sharma Date: Fri, 30 Jan 2026 14:29:40 +0530 Subject: [PATCH 2204/2333] QCLINUX: arm64: dts: qcom: add camx overlay for talos evk - Move all camx overlay to end of file to avoid conflicts. - Add camx overlay for talos evk. Signed-off-by: Vikram Sharma --- arch/arm64/boot/dts/qcom/Makefile | 73 +- .../arm64/boot/dts/qcom/qcs615-ride-camx.dtso | 16 + .../boot/dts/qcom/talos-camera-sensor.dtsi | 152 ++ arch/arm64/boot/dts/qcom/talos-camera.dtsi | 1985 +++++++++++++++++ arch/arm64/boot/dts/qcom/talos-evk-camx.dtso | 16 + 5 files changed, 2210 insertions(+), 32 deletions(-) create mode 100644 arch/arm64/boot/dts/qcom/qcs615-ride-camx.dtso create mode 100644 arch/arm64/boot/dts/qcom/talos-camera-sensor.dtsi create mode 100644 arch/arm64/boot/dts/qcom/talos-camera.dtsi create mode 100644 arch/arm64/boot/dts/qcom/talos-evk-camx.dtso diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile index 21db2a35186cc..bce08f77d037e 100644 --- a/arch/arm64/boot/dts/qcom/Makefile +++ b/arch/arm64/boot/dts/qcom/Makefile @@ -40,10 +40,6 @@ lemans-evk-el2-dtbs := lemans-evk.dtb lemans-el2.dtbo dtb-$(CONFIG_ARCH_QCOM) += lemans-evk-camera-csi1-imx577.dtb dtb-$(CONFIG_ARCH_QCOM) += lemans-evk-el2.dtb -lemans-evk-camx-dtbs := lemans-evk.dtb lemans-evk-camx.dtbo - -dtb-$(CONFIG_ARCH_QCOM) += lemans-evk-camx.dtb - dtb-$(CONFIG_ARCH_QCOM) += monaco-evk.dtb monaco-evk-el2-dtbs := monaco-evk.dtb monaco-el2.dtbo @@ -52,10 +48,6 @@ dtb-$(CONFIG_ARCH_QCOM) += monaco-evk-el2.dtb monaco-evk-camera-imx577-dtbs := monaco-evk.dtb monaco-evk-camera-imx577.dtbo dtb-$(CONFIG_ARCH_QCOM) += monaco-evk-camera-imx577.dtb -monaco-evk-camx-dtbs := monaco-evk.dtb monaco-evk-camx.dtbo - -dtb-$(CONFIG_ARCH_QCOM) += monaco-evk-camx.dtb - dtb-$(CONFIG_ARCH_QCOM) += msm8216-samsung-fortuna3g.dtb dtb-$(CONFIG_ARCH_QCOM) += msm8916-acer-a1-724.dtb dtb-$(CONFIG_ARCH_QCOM) += msm8916-alcatel-idol347.dtb @@ -159,37 +151,21 @@ qcs6490-rb3gen2-industrial-mezzanine-dtbs := qcs6490-rb3gen2.dtb qcs6490-rb3gen2 dtb-$(CONFIG_ARCH_QCOM) += qcs6490-rb3gen2-industrial-mezzanine.dtb dtb-$(CONFIG_ARCH_QCOM) += qcs6490-rb3gen2-vision-mezzanine.dtb -qcs6490-rb3gen2-vision-mezzanine-camx-dtbs := qcs6490-rb3gen2-vision-mezzanine.dtb \ - qcs6490-rb3gen2-vision-mezzanine-camx.dtbo - -dtb-$(CONFIG_ARCH_QCOM) += qcs6490-rb3gen2-vision-mezzanine-camx.dtb - dtb-$(CONFIG_ARCH_QCOM) += qcs8300-ride.dtb qcs8300-ride-el2-dtbs := qcs8300-ride.dtb monaco-el2.dtbo dtb-$(CONFIG_ARCH_QCOM) += qcs8300-ride-el2.dtb -qcs8300-ride-camx-dtbs:= qcs8300-ride.dtb qcs8300-ride-camx.dtbo - -dtb-$(CONFIG_ARCH_QCOM) += qcs8300-ride-camx.dtb - dtb-$(CONFIG_ARCH_QCOM) += qcs8550-aim300-aiot.dtb dtb-$(CONFIG_ARCH_QCOM) += qcs9100-ride.dtb dtb-$(CONFIG_ARCH_QCOM) += qcs9100-ride-r3.dtb -qcs9100-ride-camx-dtbs:= qcs9100-ride.dtb sa8775p-ride-camx.dtbo qcs9100-ride-el2-dtbs := qcs9100-ride.dtb lemans-el2.dtbo qcs9100-ride-r3-el2-dtbs := qcs9100-ride-r3.dtb lemans-el2.dtbo -dtb-$(CONFIG_ARCH_QCOM) += qcs9100-ride-camx.dtb - dtb-$(CONFIG_ARCH_QCOM) += qcs9100-ride-r3.dtb -qcs9100-ride-r3-camx-dtbs:= qcs9100-ride-r3.dtb sa8775p-ride-camx.dtbo - -dtb-$(CONFIG_ARCH_QCOM) += qcs9100-ride-r3-camx.dtb - dtb-$(CONFIG_ARCH_QCOM) += qcs9100-ride-el2.dtb dtb-$(CONFIG_ARCH_QCOM) += qcs9100-ride-r3-el2.dtb dtb-$(CONFIG_ARCH_QCOM) += qdu1000-idp.dtb @@ -206,16 +182,8 @@ dtb-$(CONFIG_ARCH_QCOM) += sa8295p-adp.dtb dtb-$(CONFIG_ARCH_QCOM) += sa8540p-ride.dtb dtb-$(CONFIG_ARCH_QCOM) += sa8775p-ride.dtb -sa8775p-ride-camx-dtbs:= sa8775p-ride.dtb sa8775p-ride-camx.dtbo - -dtb-$(CONFIG_ARCH_QCOM) += sa8775p-ride-camx.dtb - dtb-$(CONFIG_ARCH_QCOM) += sa8775p-ride-r3.dtb -sa8775p-ride-r3-camx-dtbs:= sa8775p-ride-r3.dtb sa8775p-ride-camx.dtbo - -dtb-$(CONFIG_ARCH_QCOM) += sa8775p-ride-r3-camx.dtb - sc7180-acer-aspire1-el2-dtbs := sc7180-acer-aspire1.dtb sc7180-el2.dtbo dtb-$(CONFIG_ARCH_QCOM) += sc7180-acer-aspire1.dtb sc7180-acer-aspire1-el2.dtb dtb-$(CONFIG_ARCH_QCOM) += sc7180-idp.dtb @@ -422,3 +390,44 @@ x1p42100-hp-omnibook-x14-el2-dtbs := x1p42100-hp-omnibook-x14.dtb x1-el2.dtbo dtb-$(CONFIG_ARCH_QCOM) += x1p42100-hp-omnibook-x14.dtb x1p42100-hp-omnibook-x14-el2.dtb x1p42100-lenovo-thinkbook-16-el2-dtbs := x1p42100-lenovo-thinkbook-16.dtb x1-el2.dtbo dtb-$(CONFIG_ARCH_QCOM) += x1p42100-lenovo-thinkbook-16.dtb x1p42100-lenovo-thinkbook-16-el2.dtb + +lemans-evk-camx-dtbs := lemans-evk.dtb lemans-evk-camx.dtbo + +dtb-$(CONFIG_ARCH_QCOM) += lemans-evk-camx.dtb + +monaco-evk-camx-dtbs := monaco-evk.dtb monaco-evk-camx.dtbo + +dtb-$(CONFIG_ARCH_QCOM) += monaco-evk-camx.dtb + +qcs615-ride-camx-dtbs := qcs615-ride.dtb qcs615-ride-camx.dtbo + +dtb-$(CONFIG_ARCH_QCOM) += qcs615-ride-camx.dtb + +qcs6490-rb3gen2-vision-mezzanine-camx-dtbs := qcs6490-rb3gen2-vision-mezzanine.dtb \ + qcs6490-rb3gen2-vision-mezzanine-camx.dtbo + +dtb-$(CONFIG_ARCH_QCOM) += qcs6490-rb3gen2-vision-mezzanine-camx.dtb + +qcs8300-ride-camx-dtbs:= qcs8300-ride.dtb qcs8300-ride-camx.dtbo + +dtb-$(CONFIG_ARCH_QCOM) += qcs8300-ride-camx.dtb + +qcs9100-ride-camx-dtbs:= qcs9100-ride.dtb sa8775p-ride-camx.dtbo + +dtb-$(CONFIG_ARCH_QCOM) += qcs9100-ride-camx.dtb + +qcs9100-ride-r3-camx-dtbs:= qcs9100-ride-r3.dtb sa8775p-ride-camx.dtbo + +dtb-$(CONFIG_ARCH_QCOM) += qcs9100-ride-r3-camx.dtb + +sa8775p-ride-camx-dtbs:= sa8775p-ride.dtb sa8775p-ride-camx.dtbo + +dtb-$(CONFIG_ARCH_QCOM) += sa8775p-ride-camx.dtb + +sa8775p-ride-r3-camx-dtbs:= sa8775p-ride-r3.dtb sa8775p-ride-camx.dtbo + +dtb-$(CONFIG_ARCH_QCOM) += sa8775p-ride-r3-camx.dtb + +talos-evk-camx-dtbs := talos-evk.dtb talos-evk-camx.dtbo + +dtb-$(CONFIG_ARCH_QCOM) += talos-evk-camx.dtb diff --git a/arch/arm64/boot/dts/qcom/qcs615-ride-camx.dtso b/arch/arm64/boot/dts/qcom/qcs615-ride-camx.dtso new file mode 100644 index 0000000000000..a40d8817a7a20 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcs615-ride-camx.dtso @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +/dts-v1/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "talos-camera.dtsi" +#include "talos-camera-sensor.dtsi" diff --git a/arch/arm64/boot/dts/qcom/talos-camera-sensor.dtsi b/arch/arm64/boot/dts/qcom/talos-camera-sensor.dtsi new file mode 100644 index 0000000000000..006b345cc0023 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/talos-camera-sensor.dtsi @@ -0,0 +1,152 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#include + +&cam_cci { + /*cam0-imx577*/ + tl_slot0: qcom,cam-sensor0 { + compatible = "qcom,cam-sensor"; + csiphy-sd-index = <0>; + sensor-position-roll = <0>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + eeprom-src = <&eeprom_cam0>; + cam_vio-supply = <&vreg_s4a>; + regulator-names = "cam_vio"; + power-domains = <&camcc TITAN_TOP_GDSC>; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000>; + rgltr-max-voltage = <1800000>; + rgltr-load-current = <120000>; + gpio-no-mux = <0>; + pinctrl-0 = <&cam_sensor_mclk3_active + &cam_sensor_active_rst0>; + pinctrl-1 = <&cam_sensor_mclk3_suspend + &cam_sensor_suspend_rst0>; + pinctrl-names = "cam_default", "cam_suspend"; + gpios = <&tlmm 28 0>, + <&tlmm 75 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAM_MCLK0", "CAMIF_RESET0"; + cci-master = <0>; + clocks = <&camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "nominal"; + clock-rates = <24000000>; + cell-index = <0>; + status = "okay"; + }; + + /*cam1-imx577*/ + t1_slot1: qcom,cam-sensor1 { + compatible = "qcom,cam-sensor"; + csiphy-sd-index = <1>; + sensor-position-roll = <0>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + eeprom-src = <&eeprom_cam1>; + cam_vio-supply = <&vreg_s4a>; + regulator-names = "cam_vio"; + power-domains = <&camcc TITAN_TOP_GDSC>; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000>; + rgltr-max-voltage = <1800000>; + rgltr-load-current = <120000>; + gpio-no-mux = <0>; + pinctrl-0 = <&cam_sensor_mclk2_active + &cam_sensor_active_rst1>; + pinctrl-1 = <&cam_sensor_mclk2_suspend + &cam_sensor_suspend_rst1>; + gpios = <&tlmm 30 0>, + <&tlmm 29 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAM_MCLK1", "CAMIF_RESET1"; + cci-master = <1>; + clocks = <&camcc CAM_CC_MCLK1_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "nominal"; + clock-rates = <24000000>; + cell-index = <1>; + status = "okay"; + }; + + /*cam0-imx577-eeprom*/ + eeprom_cam0: qcom,eeprom0 { + compatible = "qcom,eeprom"; + cam_vio-supply = <&vreg_s4a>; + regulator-names = "cam_vio"; + power-domains = <&camcc TITAN_TOP_GDSC>; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000>; + rgltr-max-voltage = <1800000>; + rgltr-load-current = <120000>; + gpio-no-mux = <0>; + pinctrl-0 = <&cam_sensor_mclk3_active + &cam_sensor_active_rst0>; + pinctrl-1 = <&cam_sensor_mclk3_suspend + &cam_sensor_suspend_rst0>; + pinctrl-names = "cam_default", "cam_suspend"; + gpios = <&tlmm 28 0>, + <&tlmm 75 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAM_MCLK0", "CAMIF_RESET0"; + cci-master = <0>; + clocks = <&camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "nominal"; + clock-rates = <24000000>; + cell-index = <0>; + status = "okay"; + }; + + /*cam1-imx577-eeprom*/ + eeprom_cam1: qcom,eeprom1 { + compatible = "qcom,eeprom"; + cam_vio-supply = <&vreg_s4a>; + regulator-names = "cam_vio"; + power-domains = <&camcc TITAN_TOP_GDSC>; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000>; + rgltr-max-voltage = <1800000>; + rgltr-load-current = <120000>; + gpio-no-mux = <0>; + pinctrl-0 = <&cam_sensor_mclk2_active + &cam_sensor_active_rst1>; + pinctrl-1 = <&cam_sensor_mclk2_suspend + &cam_sensor_suspend_rst1>; + pinctrl-names = "cam_default", "cam_suspend"; + gpios = <&tlmm 30 0>, + <&tlmm 29 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAM_MCLK1", "CAMIF_RESET1"; + cci-master = <1>; + clocks = <&camcc CAM_CC_MCLK1_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "nominal"; + clock-rates = <24000000>; + cell-index = <1>; + status = "okay"; + }; +}; + +&soc { + qcom,cam-res-mgr { + compatible = "qcom,cam-res-mgr"; + status = "ok"; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/talos-camera.dtsi b/arch/arm64/boot/dts/qcom/talos-camera.dtsi new file mode 100644 index 0000000000000..9a869b4546499 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/talos-camera.dtsi @@ -0,0 +1,1985 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#include +#include + +&soc { + cam_icp: qcom,icp@ac00000 { + compatible = "qcom,cam-icp_v1"; + icp-version = <0x0100>; + reg = <0x0 0xac00000 0x0 0x6000>, + <0x0 0xac10000 0x0 0x8000>, + <0x0 0xac18000 0x0 0x3000>; + reg-names = "icp_qgic", "icp_sierra", "icp_csr"; + reg-cam-base = <0x00000 0x10000 0x18000>; + interrupts = ; + interrupt-names = "a5"; + power-domains = <&camcc TITAN_TOP_GDSC>; + clocks = <&gcc GCC_CAMERA_AHB_CLK>, + <&gcc GCC_CAMERA_HF_AXI_CLK>, + <&camcc CAM_CC_FAST_AHB_CLK_SRC>, + <&camcc CAM_CC_SOC_AHB_CLK>, + <&camcc CAM_CC_CPAS_AHB_CLK>, + <&camcc CAM_CC_CAMNOC_AXI_CLK>, + <&camcc CAM_CC_ICP_CLK>, + <&camcc CAM_CC_ICP_CLK_SRC>; + clock-names = "gcc_camera_ahb_clk", + "gcc_camera_hf_axi_clk", + "cam_cc_fast_ahb_clk_src", + "cam_cc_soc_ahb_clk", + "cam_cc_cpas_ahb_clk", + "cam_cc_camnoc_axi_clk", + "cam_cc_icp_clk", + "cam_cc_icp_clk_src"; + clock-rates = <0 0 100000000 0 0 0 0 240000000>, + <0 0 200000000 0 0 0 0 360000000>, + <0 0 300000000 0 0 0 0 432000000>, + <0 0 404000000 0 0 0 0 480000000>, + <0 0 404000000 0 0 0 0 540000000>, + <0 0 404000000 0 0 0 0 600000000>; + clock-cntl-level = "lowsvs", "svs", "svs_l1", "nominal", "nominal_l1", "turbo"; + src-clock-name = "cam_cc_icp_clk_src"; + operating-points-v2 = <&a5_opp_table>; + fw_name = "qcom/qcs615/CAMERA_ICP.elf"; + ubwc-cfg = <0x73 0x1CF>; + cam_hw_pid = <15>; + cell-index = <0>; + status = "okay"; + + a5_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-240000000 { + opp-hz = /bits/ 64 <240000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + + opp-360000000 { + opp-hz = /bits/ 64 <360000000>; + required-opps = <&rpmhpd_opp_svs>; + }; + + opp-432000000 { + opp-hz = /bits/ 64 <432000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-480000000 { + opp-hz = /bits/ 64 <480000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + + opp-540000000 { + opp-hz = /bits/ 64 <540000000>; + required-opps = <&rpmhpd_opp_nom_l1>; + }; + + opp-600000000 { + opp-hz = /bits/ 64 <600000000>; + required-opps = <&rpmhpd_opp_turbo>; + }; + }; + }; + + qcom,cam-cpas@ac40000 { + compatible = "qcom,cam-cpas"; + label = "cpas"; + arch-compat = "cpas_top"; + reg = <0x0 0xac40000 0x0 0x1000>, + <0x0 0xac42000 0x0 0x5000>; + reg-names = "cam_cpas_top", "cam_camnoc"; + reg-cam-base = <0x40000 0x42000>; + interrupts = ; + interrupt-names = "cpas_camnoc"; + camnoc-axi-min-ib-bw = <3000000000>; + power-domains = <&camcc TITAN_TOP_GDSC>; + clocks = <&gcc GCC_CAMERA_AHB_CLK>, + <&gcc GCC_CAMERA_HF_AXI_CLK>, + <&camcc CAM_CC_SOC_AHB_CLK>, + <&camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&camcc CAM_CC_CPAS_AHB_CLK>, + <&camcc CAM_CC_CAMNOC_AXI_CLK>; + clock-names = "gcc_camera_ahb_clk", + "gcc_camera_hf_axi_clk", + "cam_cc_soc_ahb_clk", + "cam_cc_slow_ahb_clk_src", + "cam_cc_cpas_ahb_clk", + "cam_cc_camnoc_axi_clk"; + clock-rates = <0 0 0 0 0 0>, + <0 0 0 80000000 0 150000000>, + <0 0 0 80000000 0 240000000>, + <0 0 0 80000000 0 265000000>, + <0 0 0 80000000 0 355000000>, + <0 0 0 80000000 0 426000000>; + clock-cntl-level = "suspend", "lowsvs", "svs", + "svs_l1", "nominal", "turbo"; + src-clock-name = "cam_cc_camnoc_axi_clk"; + operating-points-v2 = <&cpas_opp_table>; + control-camnoc-axi-clk; + camnoc-bus-width = <32>; + camnoc-axi-clk-bw-margin-perc = <20>; + cam-icc-path-names = "cam_ahb"; + interconnects = <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ACTIVE_ONLY + &config_noc SLAVE_CAMERA_CFG QCOM_ICC_TAG_ACTIVE_ONLY>, + <&mmss_noc MASTER_CAMNOC_HF0 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>, + <&mmss_noc MASTER_CAMNOC_HF1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>, + <&mmss_noc MASTER_CAMNOC_SF QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "cam_ahb", + "cam_hf_0_mnoc", + "cam_hf_1_mnoc", + "cam_sf_0_mnoc"; + cam-ahb-num-cases = <9>; + cam-ahb-bw-KBps = <0 0>, <0 76800>, <0 150000>, <0 150000>, + <0 300000>, <0 300000>, <0 300000>, + <0 300000>, <0 300000>; + vdd-corners = ; + vdd-corner-ahb-mapping = "suspend", "lowsvs", "lowsvs", "svs", + "svs_l1", "nominal", "nominal", + "nominal", "turbo", "turbo"; + client-id-based; + client-names = "csiphy0", "csiphy1", "csiphy2", "cci0", + "csid0", "csid1", "csid2","ife0", + "ife1", "ife2", "ipe0", "cam-cdm-intf0", + "cpas-cdm0", "bps0", "icp0", "jpeg-dma0", + "jpeg-enc0", "lrmecpas0"; + cell-index = <0>; + status = "okay"; + + cpas_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-150000000 { + opp-hz = /bits/ 64 <150000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + + opp-240000000 { + opp-hz = /bits/ 64 <240000000>; + required-opps = <&rpmhpd_opp_svs>; + }; + + opp-265000000 { + opp-hz = /bits/ 64 <265000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-355000000 { + opp-hz = /bits/ 64 <355000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + + opp-426000000 { + opp-hz = /bits/ 64 <426000000>; + required-opps = <&rpmhpd_opp_turbo>; + }; + }; + + camera-bus-nodes { + level0-nodes { + level-index = <0>; + + bps0_all_rd: bps0-all-rd { + cell-index = <0>; + node-name = "bps0-all-rd"; + client-name = "bps0"; + traffic-data = ; + traffic-transaction-type = ; + parent-node = <&level1_nrt0_read0>; + }; + + bps0_all_wr: bps0-all-wr { + cell-index = <1>; + node-name = "bps0-all-wr"; + client-name = "bps0"; + traffic-data = ; + traffic-transaction-type = ; + parent-node = <&level1_nrt0_write0>; + }; + + cpas_cdm0_all_rd: cpas-cdm0-all-rd { + cell-index = <2>; + node-name = "cpas-cdm0-all-rd"; + client-name = "cpas-cdm0"; + traffic-data = ; + traffic-transaction-type = ; + parent-node = <&level1_nrt0_read2>; + }; + + icp0_all_rd: icp0-all-rd { + cell-index = <3>; + node-name = "icp0-all-rd"; + client-name = "icp0"; + traffic-data = ; + traffic-transaction-type = ; + parent-node = <&level1_nrt0_read3>; + }; + + ife0_linear_pdaf_wr: ife0-linear-pdaf-wr { + cell-index = <4>; + node-name = "ife0-linear-pdaf-wr"; + client-name = "ife0"; + traffic-data = ; + traffic-transaction-type = ; + constituent-paths = ; + parent-node = <&level1_rt0_write0>; + }; + + ife0_rdi_pixel_raw_wr: ife0-rdi-pixel-raw-wr { + cell-index = <5>; + node-name = "ife0-rdi-pixel-raw-wr"; + client-name = "ife0"; + traffic-data = ; + traffic-transaction-type = ; + constituent-paths = ; + parent-node = <&level1_rt0_write0>; + }; + + ife0_ubwc_stats_wr: ife0-ubwc-stats-wr { + cell-index = <6>; + node-name = "ife0-ubwc-stats-wr"; + client-name = "ife0"; + traffic-data = ; + traffic-transaction-type = ; + constituent-paths = ; + parent-node = <&level1_rt0_write0>; + }; + + ife1_linear_pdaf_wr: ife1-linear-pdaf-wr { + cell-index = <7>; + node-name = "ife1-linear-pdaf-wr"; + client-name = "ife1"; + traffic-data = ; + traffic-transaction-type = ; + constituent-paths = ; + parent-node = <&level1_rt1_write0>; + }; + + ife1_rdi_pixel_raw_wr: ife1-rdi-pixel-raw-wr { + cell-index = <8>; + node-name = "ife1-rdi-pixel-raw-wr"; + client-name = "ife1"; + traffic-data = ; + traffic-transaction-type = ; + constituent-paths = ; + parent-node = <&level1_rt1_write0>; + }; + + ife1_ubwc_stats_wr: ife1-ubwc-stats-wr { + cell-index = <9>; + node-name = "ife1-ubwc-stats-wr"; + client-name = "ife1"; + traffic-data = ; + traffic-transaction-type = ; + constituent-paths = ; + parent-node = <&level1_rt1_write0>; + }; + + ife2_rdi_wr: ife2-rdi-wr { + cell-index = <10>; + node-name = "ife2-rdi-wr"; + client-name = "ife2"; + traffic-data = ; + traffic-transaction-type = ; + constituent-paths = ; + parent-node = <&level1_rt0_write0>; + }; + + ipe0_all_rd: ipe0-all-rd { + cell-index = <11>; + node-name = "ipe0-all-rd"; + client-name = "ipe0"; + traffic-data = ; + traffic-transaction-type = ; + constituent-paths = ; + parent-node = <&level1_nrt0_read0>; + }; + + ipe0_ref_wr: ipe0-ref-wr { + cell-index = <12>; + node-name = "ipe0-ref-wr"; + client-name = "ipe0"; + traffic-data = ; + traffic-transaction-type = ; + parent-node = <&level1_nrt0_write0>; + }; + + ipe0_viddisp_wr: ipe0-viddisp-wr { + cell-index = <13>; + node-name = "ipe0-viddisp-wr"; + client-name = "ipe0"; + traffic-data = ; + traffic-transaction-type = ; + constituent-paths = ; + parent-node = <&level1_nrt0_write0>; + }; + + jpeg_dma0_all_rd: jpeg-dma0-all-rd { + cell-index = <14>; + node-name = "jpeg-dma0-all-rd"; + client-name = "jpeg-dma0"; + traffic-data = ; + traffic-transaction-type = + ; + parent-node = <&level1_nrt0_read1>; + }; + + jpeg_dma0_all_wr: jpeg-dma0-all-wr { + cell-index = <15>; + node-name = "jpeg-dma0-all-wr"; + client-name = "jpeg-dma0"; + traffic-data = ; + traffic-transaction-type = ; + parent-node = <&level1_nrt0_write1>; + }; + + jpeg_enc0_all_rd: jpeg-enc0-all-rd { + cell-index = <16>; + node-name = "jpeg-enc0-all-rd"; + client-name = "jpeg-enc0"; + traffic-data = ; + traffic-transaction-type = ; + parent-node = <&level1_nrt0_read1>; + }; + + jpeg_enc0_all_wr: jpeg-enc0-all-wr { + cell-index = <17>; + node-name = "jpeg-enc0-all-wr"; + client-name = "jpeg-enc0"; + traffic-data = ; + traffic-transaction-type = ; + parent-node = <&level1_nrt0_write1>; + }; + + lrme0_all_rd: lrme0-all-rd { + cell-index = <18>; + node-name = "lrme0-all-rd"; + client-name = "lrmecpas0"; + traffic-data = ; + traffic-transaction-type = ; + parent-node = <&level1_nrt0_read0>; + }; + + lrme0_all_wr: lrme0-all-wr { + cell-index = <19>; + node-name = "lrme0-all-wr"; + client-name = "lrmecpas0"; + traffic-data = ; + traffic-transaction-type = ; + parent-node = <&level1_nrt0_write0>; + }; + }; + + level1-nodes { + level-index = <1>; + camnoc-max-needed; + + level1_nrt0_read0: level1-nrt0-read0 { + cell-index = <20>; + node-name = "level1-nrt0-read0"; + parent-node = <&level2_nrt0_rd_wr_sum>; + traffic-merge-type = ; + }; + + level1_nrt0_read1: level1-nrt0-read1 { + cell-index = <21>; + node-name = "level1-nrt0-read1"; + parent-node = <&level2_nrt0_rd_wr_sum>; + traffic-merge-type = ; + }; + + level1_nrt0_read2: level1-nrt0-read2 { + cell-index = <22>; + node-name = "level1-nrt0-read2"; + parent-node = <&level2_nrt0_rd_wr_sum>; + traffic-merge-type = ; + }; + + level1_nrt0_read3: level1-nrt0-read3 { + cell-index = <23>; + node-name = "level1-nrt0-read3"; + parent-node = <&level2_nrt0_rd_wr_sum>; + traffic-merge-type = ; + }; + + level1_nrt0_write0: level1-nrt0-write0 { + cell-index = <24>; + node-name = "level1-nrt0-write0"; + parent-node = <&level2_nrt0_rd_wr_sum>; + traffic-merge-type = ; + }; + + level1_nrt0_write1: level1-nrt0-write1 { + cell-index = <25>; + node-name = "level1-nrt0-write1"; + parent-node = <&level2_nrt0_rd_wr_sum>; + traffic-merge-type = ; + }; + + level1_rt0_write0: level1-rt0-write0 { + cell-index = <26>; + node-name = "level1-rt0-write0"; + parent-node = <&level2_rt0_rd_wr_sum>; + traffic-merge-type = ; + }; + + level1_rt1_write0: level1-rt1-write0 { + cell-index = <27>; + node-name = "level1-rt1-write0"; + parent-node = <&level2_rt1_rd_wr_sum>; + traffic-merge-type = ; + }; + }; + + level2-nodes { + level-index = <2>; + + level2_nrt0_rd_wr_sum: level2-nrt0-rd-wr-sum { + cell-index = <28>; + node-name = "level2-nrt0-rd-wr-sum"; + traffic-merge-type = ; + + qcom,axi-port-mnoc { + cam-icc-path-names = "cam_sf_0_mnoc"; + }; + }; + + level2_rt0_rd_wr_sum: level2-rt0-rd-wr-sum { + cell-index = <29>; + node-name = "level2-rt0-rd-wr-sum"; + traffic-merge-type = ; + ib-bw-voting-needed; + + qcom,axi-port-mnoc { + cam-icc-path-names = "cam_hf_0_mnoc"; + }; + }; + + level2_rt1_rd_wr_sum: level2-rt1-rd-wr-sum { + cell-index = <30>; + node-name = "level3-rt1-rd-wr-sum"; + traffic-merge-type = ; + + qcom,axi-port-mnoc { + cam-icc-path-names = "cam_hf_1_mnoc"; + }; + }; + }; + }; + }; + + qcom,cpas-cdm0@ac48000 { + compatible = "qcom,cam170-cpas-cdm0"; + label = "cpas-cdm"; + reg = <0x0 0xac48000 0x0 0x1000>; + reg-names = "cpas-cdm"; + reg-cam-base = <0x48000>; + interrupts = ; + interrupt-names = "cpas-cdm"; + power-domains = <&camcc TITAN_TOP_GDSC>; + clocks = <&gcc GCC_CAMERA_AHB_CLK>, + <&gcc GCC_CAMERA_HF_AXI_CLK>, + <&camcc CAM_CC_SOC_AHB_CLK>, + <&camcc CAM_CC_CPAS_AHB_CLK>, + <&camcc CAM_CC_CAMNOC_AXI_CLK>, + <&camcc CAM_CC_SLOW_AHB_CLK_SRC>; + clock-names = "gcc_camera_ahb_clk", + "gcc_camera_hf_axi_clk", + "cam_cc_soc_ahb_clk", + "cam_cc_cpas_ahb_clk", + "cam_cc_camnoc_axi_clk", + "cam_cc_slow_ahb_clk_src"; + clock-rates = <0 0 0 0 0 80000000>; + src-clock-name = "cam_cc_slow_ahb_clk_src"; + operating-points-v2 = <&cpas_cdm_opp_table>; + clock-cntl-level = "svs"; + cdm-client-names = "ife0", "ife1", "ife2", + "ife3", "dualife"; + single-context-cdm; + cell-index = <0>; + status = "okay"; + + cpas_cdm_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-80000000 { + opp-hz = /bits/ 64 <80000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + }; + }; + + cam_cci: qcom,cci@ac4a000 { + compatible = "qcom,cci", "simple-bus"; + reg = <0x0 0xac4a000 0x0 0x4000>; + reg-names = "cci"; + reg-cam-base = <0x4a000>; + interrupts = ; + interrupt-names = "CCI"; + operating-points-v2 = <&cci_opp_table>; + power-domains = <&camcc TITAN_TOP_GDSC>; + clocks = <&camcc CAM_CC_CCI_CLK_SRC>, + <&camcc CAM_CC_CCI_CLK>; + clock-names = "cci_clk_src", + "cci_clk"; + clock-rates = <37500000 0>; + clock-cntl-level = "lowsvs"; + src-clock-name = "cci_clk_src"; + pctrl-idx-mapping = ; + pctrl-map-names = "m0", "m1"; + pinctrl-0 = <&cci_i2c_scl0_active &cci_i2c_sda0_active>; + pinctrl-1 = <&cci_i2c_scl0_suspend &cci_i2c_sda0_suspend>; + pinctrl-2 = <&cci_i2c_scl1_active &cci_i2c_sda1_active>; + pinctrl-3 = <&cci_i2c_scl1_suspend &cci_i2c_sda1_suspend>; + pinctrl-names = "m0_active", "m0_suspend", + "m1_active", "m1_suspend"; + cell-index = <0>; + status = "okay"; + + cci_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-37500000 { + opp-hz = /bits/ 64 <37500000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + }; + + i2c_freq_custom_cci: qcom,i2c-custom-mode { + hw-thigh = <38>; + hw-tlow = <56>; + hw-tsu-sto = <40>; + hw-tsu-sta = <40>; + hw-thd-dat = <22>; + hw-thd-sta = <35>; + hw-tbuf = <62>; + hw-scl-stretch-en = <1>; + hw-trdhld = <6>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "okay"; + }; + + i2c_freq_400Khz_cci: qcom,i2c-fast-mode { + hw-thigh = <38>; + hw-tlow = <56>; + hw-tsu-sto = <40>; + hw-tsu-sta = <40>; + hw-thd-dat = <22>; + hw-thd-sta = <35>; + hw-tbuf = <62>; + hw-scl-stretch-en = <0>; + hw-trdhld = <6>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "okay"; + }; + + i2c_freq_1Mhz_cci: qcom,i2c-fast-plus-mode { + hw-thigh = <16>; + hw-tlow = <22>; + hw-tsu-sto = <17>; + hw-tsu-sta = <18>; + hw-thd-dat = <16>; + hw-thd-sta = <15>; + hw-tbuf = <24>; + hw-scl-stretch-en = <0>; + hw-trdhld = <3>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "okay"; + }; + + i2c_freq_100Khz_cci: qcom,i2c-standard-mode { + hw-thigh = <201>; + hw-tlow = <174>; + hw-tsu-sto = <204>; + hw-tsu-sta = <231>; + hw-thd-dat = <22>; + hw-thd-sta = <162>; + hw-tbuf = <227>; + hw-scl-stretch-en = <0>; + hw-trdhld = <6>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "okay"; + }; + }; + + cam_jpeg_enc: qcom,jpegenc@ac4e000 { + compatible = "qcom,cam_jpeg_enc_170"; + reg = <0x0 0xac4e000 0x0 0x4000>; + reg-names = "jpege_hw"; + reg-cam-base = <0x4e000>; + interrupts = ; + interrupt-names = "jpeg"; + power-domains = <&camcc TITAN_TOP_GDSC>; + clocks = <&gcc GCC_CAMERA_AHB_CLK>, + <&gcc GCC_CAMERA_HF_AXI_CLK>, + <&camcc CAM_CC_SOC_AHB_CLK>, + <&camcc CAM_CC_CPAS_AHB_CLK>, + <&camcc CAM_CC_CAMNOC_AXI_CLK>, + <&camcc CAM_CC_JPEG_CLK_SRC>, + <&camcc CAM_CC_JPEG_CLK>; + clock-names = "gcc_camera_ahb_clk", + "gcc_camera_hf_axi_clk", + "cam_cc_soc_ahb_clk", + "cam_cc_cpas_ahb_clk", + "cam_cc_camnoc_axi_clk", + "cam_cc_jpeg_clk_src", + "cam_cc_jpeg_clk"; + clock-rates = <0 0 0 0 0 600000000 0>; + src-clock-name = "cam_cc_jpeg_clk_src"; + operating-points-v2 = <&jpeg_enc_opp_table>; + clock-cntl-level = "turbo"; + cell-index = <0>; + status = "okay"; + + jpeg_enc_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-600000000 { + opp-hz = /bits/ 64 <600000000>; + required-opps = <&rpmhpd_opp_turbo>; + }; + }; + }; + + cam_jpeg_dma: qcom,jpegdma@ac52000{ + compatible = "qcom,cam_jpeg_dma_170"; + reg = <0x0 0xac52000 0x0 0x4000>; + reg-names = "jpegdma_hw"; + reg-cam-base = <0x52000>; + interrupts = ; + interrupt-names = "jpegdma"; + power-domains = <&camcc TITAN_TOP_GDSC>; + clocks = <&gcc GCC_CAMERA_AHB_CLK>, + <&gcc GCC_CAMERA_HF_AXI_CLK>, + <&camcc CAM_CC_SOC_AHB_CLK>, + <&camcc CAM_CC_CPAS_AHB_CLK>, + <&camcc CAM_CC_CAMNOC_AXI_CLK>, + <&camcc CAM_CC_JPEG_CLK_SRC>, + <&camcc CAM_CC_JPEG_CLK>; + clock-names = "gcc_camera_ahb_clk", + "gcc_camera_hf_axi_clk", + "cam_cc_soc_ahb_clk", + "cam_cc_cpas_ahb_clk", + "cam_cc_camnoc_axi_clk", + "cam_cc_jpeg_clk_src", + "cam_cc_jpeg_clk"; + clock-rates = <0 0 0 0 0 600000000 0>; + src-clock-name = "cam_cc_jpeg_clk_src"; + operating-points-v2 = <&jpeg_dma_opp_table>; + clock-cntl-level = "turbo"; + cell-index = <0>; + status = "okay"; + + jpeg_dma_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-600000000 { + opp-hz = /bits/ 64 <600000000>; + required-opps = <&rpmhpd_opp_turbo>; + }; + }; + }; + + cam_csiphy0: qcom,csiphy@ac65000 { + compatible = "qcom,csiphy-v2.0.0", "qcom,csiphy"; + reg = <0x0 0x0ac65000 0x0 0x1000>; + reg-names = "csiphy"; + operating-points-v2 = <&csiphy0_opp_table>; + reg-cam-base = <0x65000>; + interrupts = ; + interrupt-names = "CSIPHY0"; + csi-vdd-voltage = <1200000>; + mipi-csi-vdd-supply = <&vreg_l11a>; + power-domains = <&camcc TITAN_TOP_GDSC>; + clocks = <&camcc CAM_CC_CAMNOC_AXI_CLK>, + <&camcc CAM_CC_SOC_AHB_CLK>, + <&camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&camcc CAM_CC_CPAS_AHB_CLK>, + <&camcc CAM_CC_CPHY_RX_CLK_SRC>, + <&camcc CAM_CC_CSIPHY0_CLK>, + <&camcc CAM_CC_CSI0PHYTIMER_CLK_SRC>, + <&camcc CAM_CC_CSI0PHYTIMER_CLK>; + clock-names = "camnoc_axi_clk", + "soc_ahb_clk", + "slow_ahb_src_clk", + "cpas_ahb_clk", + "cphy_rx_clk_src", + "csiphy0_clk", + "csi0phytimer_clk_src", + "csi0phytimer_clk"; + src-clock-name = "csi0phytimer_clk_src"; + clock-cntl-level = "svs_l1", "turbo"; + clock-rates = <0 0 0 0 269333333 0 269333333 0>, + <0 0 0 0 384000000 0 269333333 0>; + cell-index = <0>; + status = "okay"; + + csiphy0_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-269333333 { + opp-hz = /bits/ 64 <269333333>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-384000000 { + opp-hz = /bits/ 64 <384000000>; + required-opps = <&rpmhpd_opp_turbo>; + }; + }; + }; + + cam_csiphy1: qcom,csiphy@ac66000 { + compatible = "qcom,csiphy-v2.0.0", "qcom,csiphy"; + reg = <0x0 0xac66000 0x0 0x1000>; + reg-names = "csiphy"; + operating-points-v2 = <&csiphy1_opp_table>; + reg-cam-base = <0x66000>; + interrupts = ; + interrupt-names = "CSIPHY1"; + csi-vdd-voltage = <1200000>; + mipi-csi-vdd-supply = <&vreg_l11a>; + power-domains = <&camcc TITAN_TOP_GDSC>; + clocks = <&camcc CAM_CC_CAMNOC_AXI_CLK>, + <&camcc CAM_CC_SOC_AHB_CLK>, + <&camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&camcc CAM_CC_CPAS_AHB_CLK>, + <&camcc CAM_CC_CPHY_RX_CLK_SRC>, + <&camcc CAM_CC_CSIPHY1_CLK>, + <&camcc CAM_CC_CSI1PHYTIMER_CLK_SRC>, + <&camcc CAM_CC_CSI1PHYTIMER_CLK>; + clock-names = "camnoc_axi_clk", + "soc_ahb_clk", + "slow_ahb_src_clk", + "cpas_ahb_clk", + "cphy_rx_clk_src", + "csiphy1_clk", + "csi1phytimer_clk_src", + "csi1phytimer_clk"; + src-clock-name = "csi1phytimer_clk_src"; + clock-cntl-level = "svs_l1", "turbo"; + clock-rates = <0 0 0 0 269333333 0 269333333 0>, + <0 0 0 0 384000000 0 269333333 0>; + cell-index = <1>; + status = "okay"; + + csiphy1_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-269333333 { + opp-hz = /bits/ 64 <269333333>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-384000000 { + opp-hz = /bits/ 64 <384000000>; + required-opps = <&rpmhpd_opp_turbo>; + }; + }; + }; + + cam_csiphy2: qcom,csiphy@ac67000 { + compatible = "qcom,csiphy-v2.0.0", "qcom,csiphy"; + reg = <0x0 0xac67000 0x0 0x1000>; + reg-names = "csiphy"; + operating-points-v2 = <&csiphy2_opp_table>; + reg-cam-base = <0x67000>; + interrupts = ; + interrupt-names = "CSIPHY2"; + csi-vdd-voltage = <1200000>; + mipi-csi-vdd-supply = <&vreg_l11a>; + power-domains = <&camcc TITAN_TOP_GDSC>; + clocks = <&camcc CAM_CC_CAMNOC_AXI_CLK>, + <&camcc CAM_CC_SOC_AHB_CLK>, + <&camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&camcc CAM_CC_CPAS_AHB_CLK>, + <&camcc CAM_CC_CPHY_RX_CLK_SRC>, + <&camcc CAM_CC_CSIPHY2_CLK>, + <&camcc CAM_CC_CSI2PHYTIMER_CLK_SRC>, + <&camcc CAM_CC_CSI2PHYTIMER_CLK>; + clock-names = "camnoc_axi_clk", + "soc_ahb_clk", + "slow_ahb_src_clk", + "cpas_ahb_clk", + "cphy_rx_clk_src", + "csiphy2_clk", + "csi2phytimer_clk_src", + "csi2phytimer_clk"; + src-clock-name = "csi2phytimer_clk_src"; + clock-cntl-level = "svs_l1", "turbo"; + clock-rates = <0 0 0 0 269333333 0 269333333 0>, + <0 0 0 0 384000000 0 269333333 0>; + cell-index = <2>; + status = "okay"; + + csiphy2_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-269333333 { + opp-hz = /bits/ 64 <269333333>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-384000000 { + opp-hz = /bits/ 64 <384000000>; + required-opps = <&rpmhpd_opp_turbo>; + }; + }; + }; + + cam_lrme: qcom,lrme@ac6b000 { + compatible = "qcom,lrme"; + reg = <0x0 0xac6b000 0x0 0xa00>; + reg-names = "lrme"; + reg-cam-base = <0x6b000>; + interrupts = ; + interrupt-names = "lrme"; + power-domains = <&camcc TITAN_TOP_GDSC>; + clocks = <&gcc GCC_CAMERA_AHB_CLK>, + <&gcc GCC_CAMERA_HF_AXI_CLK>, + <&camcc CAM_CC_SOC_AHB_CLK>, + <&camcc CAM_CC_CPAS_AHB_CLK>, + <&camcc CAM_CC_CAMNOC_AXI_CLK>, + <&camcc CAM_CC_LRME_CLK_SRC>, + <&camcc CAM_CC_LRME_CLK>; + clock-names = "gcc_camera_ahb_clk", + "gcc_camera_hf_axi_clk", + "cam_cc_soc_ahb_clk", + "cam_cc_cpas_ahb_clk", + "cam_cc_camnoc_axi_clk", + "cam_cc_lrme_clk_src", + "cam_cc_lrme_clk"; + clock-rates = <0 0 0 0 0 200000000 0>, + <0 0 0 0 0 216000000 0>, + <0 0 0 0 0 300000000 0>, + <0 0 0 0 0 404000000 0>; + clock-cntl-level = "lowsvs", "svs", "svs_l1", "nominal"; + src-clock-name = "cam_cc_lrme_clk_src"; + operating-points-v2 = <&lrme_opp_table>; + cam_hw_pid = <6 10>; + cell-index = <0>; + status = "okay"; + + lrme_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-200000000 { + opp-hz = /bits/ 64 <200000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + + opp-216000000 { + opp-hz = /bits/ 64 <216000000>; + required-opps = <&rpmhpd_opp_svs>; + }; + + opp-300000000 { + opp-hz = /bits/ 64 <300000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-404000000 { + opp-hz = /bits/ 64 <404000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + }; + }; + + cam_bps: qcom,bps@0x0ac6f000 { + compatible = "qcom,cam-bps"; + reg = <0x0 0xac6f000 0x0 0x3000>; + reg-names = "bps_top"; + reg-cam-base = <0x6f000>; + power-domains = <&camcc BPS_GDSC>; + clocks = <&camcc CAM_CC_BPS_AHB_CLK>, + <&camcc CAM_CC_BPS_AREG_CLK>, + <&camcc CAM_CC_BPS_AXI_CLK>, + <&camcc CAM_CC_BPS_CLK>, + <&camcc CAM_CC_BPS_CLK_SRC>; + clock-names = "cam_cc_bps_ahb_clk", + "cam_cc_bps_areg_clk", + "cam_cc_bps_axi_clk", + "cam_cc_bps_clk", + "cam_cc_bps_clk_src"; + clock-rates = <0 0 0 0 200000000>, + <0 0 0 0 360000000>, + <0 0 0 0 432000000>, + <0 0 0 0 480000000>, + <0 0 0 0 540000000>, + <0 0 0 0 600000000>; + clock-cntl-level = "lowsvs", "svs", "svs_l1", + "nominal", "nominal_l1", "turbo"; + src-clock-name = "cam_cc_bps_clk_src"; + operating-points-v2 = <&bps_opp_table>; + cam_hw_pid = <5 9>; + cell-index = <0>; + status = "okay"; + + bps_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-200000000 { + opp-hz = /bits/ 64 <200000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + + opp-360000000 { + opp-hz = /bits/ 64 <360000000>; + required-opps = <&rpmhpd_opp_svs>; + }; + + opp-432000000 { + opp-hz = /bits/ 64 <432000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-480000000 { + opp-hz = /bits/ 64 <480000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + + opp-540000000 { + opp-hz = /bits/ 64 <540000000>; + required-opps = <&rpmhpd_opp_nom_l1>; + }; + + opp-600000000 { + opp-hz = /bits/ 64 <600000000>; + required-opps = <&rpmhpd_opp_turbo>; + }; + }; + }; + + cam_ipe0: qcom,ipe0@0x0ac87000 { + compatible = "qcom,cam-ipe"; + reg = <0x0 0xac87000 0x0 0x3000>; + reg-names = "ipe0_top"; + reg-cam-base = <0x87000>; + power-domains = <&camcc IPE_0_GDSC>; + clock-names = "cam_cc_ipe_0_ahb_clk", + "cam_cc_ipe_0_areg_clk", + "cam_cc_ipe_0_axi_clk", + "cam_cc_ipe_0_clk", + "cam_cc_ipe_0_clk_src"; + clocks = <&camcc CAM_CC_IPE_0_AHB_CLK>, + <&camcc CAM_CC_IPE_0_AREG_CLK>, + <&camcc CAM_CC_IPE_0_AXI_CLK>, + <&camcc CAM_CC_IPE_0_CLK>, + <&camcc CAM_CC_IPE_0_CLK_SRC>; + clock-rates = <0 0 0 0 240000000>, + <0 0 0 0 360000000>, + <0 0 0 0 432000000>, + <0 0 0 0 480000000>, + <0 0 0 0 540000000>, + <0 0 0 0 600000000>; + clock-cntl-level = "lowsvs","svs", "svs_l1", + "nominal", "nominal_l1", "turbo"; + src-clock-name = "cam_cc_ipe_0_clk_src"; + operating-points-v2 = <&ipe0_opp_table>; + cam_hw_pid = <4 8>; + cell-index = <0>; + status = "okay"; + + ipe0_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-240000000 { + opp-hz = /bits/ 64 <240000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + + opp-360000000 { + opp-hz = /bits/ 64 <360000000>; + required-opps = <&rpmhpd_opp_svs>; + }; + + opp-432000000 { + opp-hz = /bits/ 64 <432000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-480000000 { + opp-hz = /bits/ 64 <480000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + + opp-540000000 { + opp-hz = /bits/ 64 <540000000>; + required-opps = <&rpmhpd_opp_nom_l1>; + }; + + opp-600000000 { + opp-hz = /bits/ 64 <600000000>; + required-opps = <&rpmhpd_opp_turbo>; + }; + }; + }; + + cam_vfe0: qcom,vfe0@acaf000 { + compatible = "qcom,vfe170"; + reg = <0x0 0xacaf000 0x0 0x4000>, + <0x0 0xac42000 0x0 0x5000>; + reg-names = "ife0", "cam_camnoc"; + reg-cam-base = <0xaf000 0x42000>; + interrupts = ; + interrupt-names = "ife0"; + power-domains = <&camcc IFE_0_GDSC>; + clocks = <&gcc GCC_CAMERA_AHB_CLK>, + <&gcc GCC_CAMERA_HF_AXI_CLK>, + <&camcc CAM_CC_SOC_AHB_CLK>, + <&camcc CAM_CC_CPAS_AHB_CLK>, + <&camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&camcc CAM_CC_IFE_0_CLK>, + <&camcc CAM_CC_IFE_0_CLK_SRC>, + <&camcc CAM_CC_CAMNOC_AXI_CLK>, + <&camcc CAM_CC_IFE_0_AXI_CLK>; + clock-names = "gcc_camera_ahb_clk", + "gcc_camera_hf_axi_clk", + "cam_cc_soc_ahb_clk", + "cam_cc_cpas_ahb_clk", + "cam_cc_slow_ahb_clk_src", + "cam_cc_ife_0_clk", + "cam_cc_ife_0_clk_src", + "cam_cc_camnoc_axi_clk", + "cam_cc_ife_0_axi_clk"; + clock-rates = <0 0 0 0 0 0 240000000 0 0>, + <0 0 0 0 0 0 360000000 0 0>, + <0 0 0 0 0 0 432000000 0 0>, + <0 0 0 0 0 0 540000000 0 0>, + <0 0 0 0 0 0 600000000 0 0>; + clock-cntl-level = "lowsvs", "svs", "svs_l1", "nominal", "turbo"; + src-clock-name = "cam_cc_ife_0_clk_src"; + operating-points-v2 = <&vfe0_opp_table>; + clock-names-option = "cam_cc_ife_0_dsp_clk"; + clocks-option = <&camcc CAM_CC_IFE_0_DSP_CLK>; + clock-rates-option = <600000000>; + cam_hw_pid = <1>; + clock-control-debugfs = "true"; + cell-index = <0>; + status = "okay"; + + vfe0_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-240000000 { + opp-hz = /bits/ 64 <240000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + + opp-360000000 { + opp-hz = /bits/ 64 <360000000>; + required-opps = <&rpmhpd_opp_svs>; + }; + + opp-432000000 { + opp-hz = /bits/ 64 <432000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-540000000 { + opp-hz = /bits/ 64 <540000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + + opp-600000000 { + opp-hz = /bits/ 64 <600000000>; + required-opps = <&rpmhpd_opp_turbo>; + }; + }; + }; + + cam_csid0: qcom,csid0@acb3000 { + compatible = "qcom,csid170"; + reg = <0x0 0xacb3000 0x0 0x1000>; + reg-names = "csid0"; + reg-cam-base = <0xb3000>; + interrupts = ; + interrupt-names = "csid0"; + power-domains = <&camcc IFE_0_GDSC>; + clocks = <&gcc GCC_CAMERA_AHB_CLK>, + <&gcc GCC_CAMERA_HF_AXI_CLK>, + <&camcc CAM_CC_SOC_AHB_CLK>, + <&camcc CAM_CC_CPAS_AHB_CLK>, + <&camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&camcc CAM_CC_IFE_0_CSID_CLK>, + <&camcc CAM_CC_IFE_0_CSID_CLK_SRC>, + <&camcc CAM_CC_IFE_0_CPHY_RX_CLK>, + <&camcc CAM_CC_CPHY_RX_CLK_SRC>, + <&camcc CAM_CC_IFE_0_CLK>, + <&camcc CAM_CC_IFE_0_CLK_SRC>, + <&camcc CAM_CC_CAMNOC_AXI_CLK>, + <&camcc CAM_CC_IFE_0_AXI_CLK>; + clock-names = "gcc_camera_ahb_clk", + "gcc_camera_hf_axi_clk", + "cam_cc_soc_ahb_clk", + "cam_cc_cpas_ahb_clk", + "cam_cc_slow_ahb_clk_src", + "cam_cc_ife_0_csid_clk", + "cam_cc_ife_0_csid_clk_src", + "cam_cc_ife_0_cphy_rx_clk", + "cam_cc_cphy_rx_clk_src", + "cam_cc_ife_0_clk", + "cam_cc_ife_0_clk_src", + "cam_cc_camnoc_axi_clk", + "cam_cc_ife_0_axi_clk"; + clock-rates = <0 0 0 0 0 0 100000000 0 0 0 240000000 0 0>, + <0 0 0 0 0 0 200000000 0 0 0 360000000 0 0>, + <0 0 0 0 0 0 320000000 0 0 0 432000000 0 0>, + <0 0 0 0 0 0 404000000 0 0 0 540000000 0 0>, + <0 0 0 0 0 0 480000000 0 0 0 540000000 0 0>, + <0 0 0 0 0 0 540000000 0 0 0 600000000 0 0>; + clock-cntl-level = "lowsvs", "svs", "svs_l1", "nominal", "nominal_l1", "turbo"; + operating-points-v2 = <&csid0_opp_table>; + src-clock-name = "cam_cc_ife_0_csid_clk_src"; + clock-control-debugfs = "true"; + cell-index = <0>; + status = "okay"; + + csid0_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-100000000 { + opp-hz = /bits/ 64 <100000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + + opp-200000000 { + opp-hz = /bits/ 64 <200000000>; + required-opps = <&rpmhpd_opp_svs>; + }; + + opp-320000000 { + opp-hz = /bits/ 64 <320000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-404000000 { + opp-hz = /bits/ 64 <404000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + + opp-480000000 { + opp-hz = /bits/ 64 <480000000>; + required-opps = <&rpmhpd_opp_nom_l1>; + }; + + opp-540000000 { + opp-hz = /bits/ 64 <540000000>; + required-opps = <&rpmhpd_opp_turbo>; + }; + }; + }; + + cam_vfe1: qcom,vfe1@acb6000 { + compatible = "qcom,vfe170"; + reg = <0x0 0xacb6000 0x0 0x4000>, + <0x0 0xac42000 0x0 0x5000>; + reg-names = "ife1", "cam_camnoc"; + reg-cam-base = <0xb6000 0x42000>; + interrupts = ; + interrupt-names = "ife1"; + power-domains = <&camcc IFE_1_GDSC>; + clocks = <&gcc GCC_CAMERA_AHB_CLK>, + <&gcc GCC_CAMERA_HF_AXI_CLK>, + <&camcc CAM_CC_SOC_AHB_CLK>, + <&camcc CAM_CC_CPAS_AHB_CLK>, + <&camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&camcc CAM_CC_IFE_1_CLK>, + <&camcc CAM_CC_IFE_1_CLK_SRC>, + <&camcc CAM_CC_CAMNOC_AXI_CLK>, + <&camcc CAM_CC_IFE_1_AXI_CLK>; + clock-names = "gcc_camera_ahb_clk", + "gcc_camera_hf_axi_clk", + "cam_cc_soc_ahb_clk", + "cam_cc_cpas_ahb_clk", + "cam_cc_slow_ahb_clk_src", + "cam_cc_ife_1_clk", + "cam_cc_ife_1_clk_src", + "cam_cc_camnoc_axi_clk", + "cam_cc_ife_1_axi_clk"; + clock-rates = <0 0 0 0 0 0 240000000 0 0>, + <0 0 0 0 0 0 360000000 0 0>, + <0 0 0 0 0 0 432000000 0 0>, + <0 0 0 0 0 0 540000000 0 0>, + <0 0 0 0 0 0 600000000 0 0>; + clock-cntl-level = "lowsvs", "svs", "svs_l1", "nominal", "turbo"; + src-clock-name = "cam_cc_ife_1_clk_src"; + operating-points-v2 = <&vfe1_opp_table>; + clock-names-option = "cam_cc_ife_1_dsp_clk"; + clocks-option = <&camcc CAM_CC_IFE_1_DSP_CLK>; + clock-rates-option = <600000000>; + cam_hw_pid = <2>; + clock-control-debugfs = "true"; + cell-index = <1>; + status = "okay"; + + vfe1_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-240000000 { + opp-hz = /bits/ 64 <240000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + + opp-360000000 { + opp-hz = /bits/ 64 <360000000>; + required-opps = <&rpmhpd_opp_svs>; + }; + + opp-432000000 { + opp-hz = /bits/ 64 <432000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-540000000 { + opp-hz = /bits/ 64 <540000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + + opp-600000000 { + opp-hz = /bits/ 64 <600000000>; + required-opps = <&rpmhpd_opp_turbo>; + }; + }; + }; + + cam_csid1: qcom,csid1@acba000 { + compatible = "qcom,csid170"; + reg = <0x0 0xacba000 0x0 0x1000>; + reg-names = "csid1"; + reg-cam-base = <0xba000>; + interrupts = ; + interrupt-names = "csid1"; + power-domains = <&camcc IFE_1_GDSC>; + clocks = <&gcc GCC_CAMERA_AHB_CLK>, + <&gcc GCC_CAMERA_HF_AXI_CLK>, + <&camcc CAM_CC_SOC_AHB_CLK>, + <&camcc CAM_CC_CPAS_AHB_CLK>, + <&camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&camcc CAM_CC_IFE_1_CSID_CLK>, + <&camcc CAM_CC_IFE_1_CSID_CLK_SRC>, + <&camcc CAM_CC_IFE_1_CPHY_RX_CLK>, + <&camcc CAM_CC_CPHY_RX_CLK_SRC>, + <&camcc CAM_CC_IFE_1_CLK>, + <&camcc CAM_CC_IFE_1_CLK_SRC>, + <&camcc CAM_CC_CAMNOC_AXI_CLK>, + <&camcc CAM_CC_IFE_1_AXI_CLK>; + clock-names = "gcc_camera_ahb_clk", + "gcc_camera_hf_axi_clk", + "cam_cc_soc_ahb_clk", + "cam_cc_cpas_ahb_clk", + "cam_cc_slow_ahb_clk_src", + "cam_cc_ife_1_csid_clk", + "cam_cc_ife_1_csid_clk_src", + "cam_cc_ife_1_cphy_rx_clk", + "cam_cc_cphy_rx_clk_src", + "cam_cc_ife_1_clk", + "cam_cc_ife_1_clk_src", + "cam_cc_camnoc_axi_clk", + "cam_cc_ife_1_axi_clk"; + clock-rates = <0 0 0 0 0 0 100000000 0 0 0 240000000 0 0>, + <0 0 0 0 0 0 200000000 0 0 0 360000000 0 0>, + <0 0 0 0 0 0 320000000 0 0 0 432000000 0 0>, + <0 0 0 0 0 0 404000000 0 0 0 540000000 0 0>, + <0 0 0 0 0 0 480000000 0 0 0 540000000 0 0>, + <0 0 0 0 0 0 540000000 0 0 0 600000000 0 0>; + clock-cntl-level = "lowsvs", "svs", "svs_l1", "nominal", "nominal_l1", "turbo"; + src-clock-name = "cam_cc_ife_1_csid_clk_src"; + operating-points-v2 = <&csid1_opp_table>; + clock-control-debugfs = "true"; + cell-index = <1>; + status = "okay"; + + csid1_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-100000000 { + opp-hz = /bits/ 64 <100000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + + opp-200000000 { + opp-hz = /bits/ 64 <200000000>; + required-opps = <&rpmhpd_opp_svs>; + }; + + opp-320000000 { + opp-hz = /bits/ 64 <320000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-404000000 { + opp-hz = /bits/ 64 <404000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + + opp-480000000 { + opp-hz = /bits/ 64 <480000000>; + required-opps = <&rpmhpd_opp_nom_l1>; + }; + + opp-540000000 { + opp-hz = /bits/ 64 <540000000>; + required-opps = <&rpmhpd_opp_turbo>; + }; + }; + }; + + cam_vfe_lite: qcom,vfe-lite@acc4000 { + compatible = "qcom,vfe-lite170"; + reg = <0x0 0xacc4000 0x0 0x4000>; + reg-names = "ife-lite0"; + reg-cam-base = <0xc4000>; + interrupts = ; + interrupt-names = "ife-lite0"; + power-domains = <&camcc TITAN_TOP_GDSC>; + clocks = <&gcc GCC_CAMERA_AHB_CLK>, + <&gcc GCC_CAMERA_HF_AXI_CLK>, + <&camcc CAM_CC_SOC_AHB_CLK>, + <&camcc CAM_CC_CPAS_AHB_CLK>, + <&camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&camcc CAM_CC_IFE_LITE_CLK>, + <&camcc CAM_CC_IFE_LITE_CLK_SRC>, + <&camcc CAM_CC_CAMNOC_AXI_CLK>; + clock-names = "gcc_camera_ahb_clk", + "gcc_camera_hf_axi_clk", + "cam_cc_soc_ahb_clk", + "cam_cc_cpas_ahb_clk", + "cam_cc_slow_ahb_clk_src", + "cam_cc_ife_lite_clk", + "cam_cc_ife_lite_clk_src", + "cam_cc_camnoc_axi_clk"; + clock-rates = <0 0 0 0 0 0 240000000 0>, + <0 0 0 0 0 0 360000000 0>, + <0 0 0 0 0 0 432000000 0>, + <0 0 0 0 0 0 540000000 0>, + <0 0 0 0 0 0 600000000 0>; + clock-cntl-level = "lowsvs", "svs", "svs_l1", "nominal", "turbo"; + src-clock-name = "cam_cc_ife_lite_clk_src"; + operating-points-v2 = <&vfe_lite0_opp_table>; + cam_hw_pid = <3>; + clock-control-debugfs = "true"; + cell-index = <2>; + status = "okay"; + + vfe_lite0_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-240000000 { + opp-hz = /bits/ 64 <240000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + + opp-360000000 { + opp-hz = /bits/ 64 <360000000>; + required-opps = <&rpmhpd_opp_svs>; + }; + + opp-432000000 { + opp-hz = /bits/ 64 <432000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-540000000 { + opp-hz = /bits/ 64 <540000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + + opp-600000000 { + opp-hz = /bits/ 64 <600000000>; + required-opps = <&rpmhpd_opp_turbo>; + }; + }; + }; + + cam_csid_lite: qcom,csid-lite@acc8000 { + compatible = "qcom,csid-lite170"; + reg = <0x0 0xacc8000 0x0 0x1000>; + reg-names = "csid-lite0"; + reg-cam-base = <0xc8000>; + interrupts = ; + interrupt-names = "csid-lite0"; + power-domains = <&camcc TITAN_TOP_GDSC>; + clocks = <&gcc GCC_CAMERA_AHB_CLK>, + <&gcc GCC_CAMERA_HF_AXI_CLK>, + <&camcc CAM_CC_SOC_AHB_CLK>, + <&camcc CAM_CC_CPAS_AHB_CLK>, + <&camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&camcc CAM_CC_IFE_LITE_CSID_CLK>, + <&camcc CAM_CC_IFE_LITE_CSID_CLK_SRC>, + <&camcc CAM_CC_IFE_LITE_CPHY_RX_CLK>, + <&camcc CAM_CC_CPHY_RX_CLK_SRC>, + <&camcc CAM_CC_IFE_LITE_CLK>, + <&camcc CAM_CC_IFE_LITE_CLK_SRC>, + <&camcc CAM_CC_CAMNOC_AXI_CLK>; + clock-names = "gcc_camera_ahb_clk", + "gcc_camera_hf_axi_clk", + "cam_cc_soc_ahb_clk", + "cam_cc_cpas_ahb_clk", + "cam_cc_slow_ahb_clk_src", + "cam_cc_ife_lite_csid_clk", + "cam_cc_ife_lite_csid_clk_src", + "cam_cc_ife_lite_cphy_rx_clk", + "cam_cc_cphy_rx_clk_src", + "cam_cc_ife_lite_clk", + "cam_cc_ife_lite_clk_src", + "cam_cc_camnoc_axi_clk"; + clock-rates = <0 0 0 0 0 0 100000000 0 0 0 240000000 0>, + <0 0 0 0 0 0 200000000 0 0 0 360000000 0>, + <0 0 0 0 0 0 320000000 0 0 0 432000000 0>, + <0 0 0 0 0 0 404000000 0 0 0 540000000 0>, + <0 0 0 0 0 0 480000000 0 0 0 540000000 0>, + <0 0 0 0 0 0 540000000 0 0 0 600000000 0>; + clock-cntl-level = "lowsvs", "svs", "svs_l1", "nominal", "nominal_l1", "turbo"; + src-clock-name = "cam_cc_ife_lite_csid_clk_src"; + operating-points-v2 = <&csid_lite0_opp_table>; + clock-control-debugfs = "true"; + cell-index = <2>; + status = "okay"; + + csid_lite0_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-100000000 { + opp-hz = /bits/ 64 <100000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + + opp-200000000 { + opp-hz = /bits/ 64 <200000000>; + required-opps = <&rpmhpd_opp_svs>; + }; + + opp-320000000 { + opp-hz = /bits/ 64 <320000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-404000000 { + opp-hz = /bits/ 64 <404000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + + opp-480000000 { + opp-hz = /bits/ 64 <480000000>; + required-opps = <&rpmhpd_opp_nom_l1>; + }; + + opp-540000000 { + opp-hz = /bits/ 64 <540000000>; + required-opps = <&rpmhpd_opp_turbo>; + }; + }; + }; + + qcom,cam-cdm-intf { + compatible = "qcom,cam-cdm-intf"; + cell-index = <0>; + label = "cam-cdm-intf"; + num-hw-cdm = <1>; + cdm-client-names = "vfe", "jpegdma", + "jpegenc", "lrmecdm"; + status = "okay"; + }; + + qcom,cam-icp { + compatible = "qcom,cam-icp"; + compat-hw-name = "qcom,icp", + "qcom,ipe0", + "qcom,bps"; + num-icp = <1>; + num-ipe = <1>; + num-bps = <1>; + ipe0-mask = <0x1000>; + icp_pc_en; + status = "okay"; + }; + + cam_isp_mgr: qcom,cam-isp { + compatible = "qcom,cam-isp"; + arch-compat = "ife"; + status = "okay"; + }; + + cam_jpeg_mgr: qcom,cam-jpeg { + compatible = "qcom,cam-jpeg"; + compat-hw-name = "qcom,jpegenc", + "qcom,jpegdma"; + num-jpeg-enc = <1>; + num-jpeg-dma = <1>; + status = "okay"; + }; + + cam_lrme_mgr: qcom,cam-lrme { + compatible = "qcom,cam-lrme"; + arch-compat = "lrme"; + status = "okay"; + }; + + qcom,camera-main { + compatible = "qcom,camera_qcs615"; + status = "okay"; + }; + + qcom,cam-req-mgr { + compatible = "qcom,cam-req-mgr"; + status = "okay"; + }; + + cam_smmu: qcom,cam-smmu { + compatible = "qcom,msm-cam-smmu", "simple-bus"; + status = "okay"; + + msm-cam-icp-fw { + compatible = "qcom,msm-cam-smmu-fw-dev"; + label="icp"; + memory-region = <&pil_camera_mem>; + }; + + msm-cam-smmu-cpas-cdm { + compatible = "qcom,msm-cam-smmu-cb"; + iommus = <&apps_smmu 0x0c00 0x0>; + cam-smmu-label = "cpas-cdm"; + + cpas_cdm_iova_mem_map: iova-mem-map { + iova-mem-region-io { + /* IO region is approximately 3.4 GB */ + iova-region-name = "io"; + iova-region-start = <0x7400000>; + iova-region-len = <0xd8c00000>; + iova-region-id = <0x3>; + status = "okay"; + }; + }; + }; + + msm-cam-smmu-icp { + compatible = "qcom,msm-cam-smmu-cb"; + iommus = <&apps_smmu 0x0de2 0x0>, + <&apps_smmu 0x0c80 0x0>, + <&apps_smmu 0x0ca0 0x0>, + <&apps_smmu 0x0d00 0x0>, + <&apps_smmu 0x0d20 0x0>; + cam-smmu-label = "icp"; + + icp_iova_mem_map: iova-mem-map { + iova-mem-region-firmware { + /* Firmware region is 8MB */ + iova-region-name = "firmware"; + iova-region-start = <0x0>; + iova-region-len = <0x800000>; + iova-region-id = <0x0>; + status = "okay"; + }; + + iova-mem-region-io { + /* IO region is approximately 3.3 GB */ + iova-region-name = "io"; + iova-region-start = <0x10C00000>; + iova-region-len = <0xCF300000>; + iova-region-id = <0x3>; + status = "okay"; + }; + + iova-mem-qdss-region { + /* qdss region is approximately 1MB */ + iova-region-name = "qdss"; + iova-region-start = <0x10B00000>; + iova-region-len = <0x100000>; + iova-region-id = <0x5>; + qdss-phy-addr = <0x16790000>; + status = "okay"; + }; + + iova-mem-region-secondary-heap { + /* Secondary heap region is 1MB long */ + iova-region-name = "secheap"; + iova-region-start = <0x10A00000>; + iova-region-len = <0x100000>; + iova-region-id = <0x4>; + status = "okay"; + }; + + iova-mem-region-shared { + /* Shared region is 150MB long */ + iova-region-name = "shared"; + iova-region-start = <0x7400000>; + iova-region-len = <0x9600000>; + iova-region-id = <0x1>; + iova-granularity = <0x15>; + status = "okay"; + }; + }; + }; + + msm-cam-smmu-ife { + compatible = "qcom,msm-cam-smmu-cb"; + iommus = <&apps_smmu 0x0820 0x40>, + <&apps_smmu 0x0840 0x00>, + <&apps_smmu 0x0860 0x40>; + cam-smmu-label = "ife"; + multiple-client-devices; + com,iommu-faults = "stall-disable", "non-fatal"; + + ife_iova_mem_map: iova-mem-map { + /* IO region is approximately 3.4 GB */ + iova-mem-region-io { + iova-region-name = "io"; + iova-region-start = <0x7400000>; + iova-region-len = <0xd8c00000>; + iova-region-id = <0x3>; + status = "okay"; + }; + }; + }; + + msm-cam-smmu-jpeg { + compatible = "qcom,msm-cam-smmu-cb"; + iommus = <&apps_smmu 0xd80 0x20>, + <&apps_smmu 0xda0 0x20>; + cam-smmu-label = "jpeg"; + + jpeg_iova_mem_map: iova-mem-map { + /* IO region is approximately 3.4 GB */ + iova-mem-region-io { + iova-region-name = "io"; + iova-region-start = <0x7400000>; + iova-region-len = <0xd8c00000>; + iova-region-id = <0x3>; + status = "okay"; + }; + }; + }; + + msm-cam-smmu-lrme { + compatible = "qcom,msm-cam-smmu-cb"; + iommus = <&apps_smmu 0x0cc0 0x0>, + <&apps_smmu 0x0d40 0x0>; + cam-smmu-label = "lrme"; + + lrme_iova_mem_map: iova-mem-map { + iova-mem-region-shared { + /* Shared region is 100MB long */ + iova-region-name = "shared"; + iova-region-start = <0x7400000>; + iova-region-len = <0x6400000>; + iova-region-id = <0x1>; + status = "okay"; + }; + + /* IO region is approximately 3.3 GB */ + iova-mem-region-io { + iova-region-name = "io"; + iova-region-start = <0xd800000>; + iova-region-len = <0xd2800000>; + iova-region-id = <0x3>; + status = "okay"; + }; + }; + }; + + msm-cam-smmu-secure { + compatible = "qcom,msm-cam-smmu-cb"; + cam-smmu-label = "cam-secure"; + qcom,secure-cb; + }; + }; + + qcom,cam-sync { + compatible = "qcom,cam-sync"; + status = "okay"; + }; +}; + +&tlmm { + cam_sensor_active_rst0: cam-sensor-active-rst0 { + /* RESET */ + mux { + pins = "gpio75"; + function = "gpio"; + }; + + config { + pins = "gpio75"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_active_rst1: cam-sensor-active-rst1 { + /* RESET */ + mux { + pins = "gpio29"; + function = "gpio"; + }; + + config { + pins = "gpio29"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_active_rst2: cam-sensor-active-rst2 { + /* RESET */ + mux { + pins = "gpio37"; + function = "gpio"; + }; + + config { + pins = "gpio37"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk2_active: cam-sensor-mclk2-active { + /* MCLK2 */ + mux { + pins = "gpio30"; + function = "cam_mclk"; + }; + + config { + pins = "gpio30"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk2_suspend: cam-sensor-mclk2-suspend { + /* MCLK2 */ + mux { + pins = "gpio30"; + function = "cam_mclk"; + }; + + config { + pins = "gpio30"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk3_active: cam-sensor-mclk3-active { + /* MCLK3 */ + mux { + pins = "gpio28"; + function = "cam_mclk"; + }; + + config { + pins = "gpio28"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk3_suspend: cam-sensor-mclk3-suspend { + /* MCLK3 */ + mux { + pins = "gpio28"; + function = "cam_mclk"; + }; + + config { + pins = "gpio28"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_suspend_rst0: cam-sensor-suspend-rst0 { + /* RESET */ + mux { + pins = "gpio75"; + function = "gpio"; + }; + + config { + pins = "gpio75"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; + }; + + cam_sensor_suspend_rst1: cam-sensor-suspend-rst1 { + /* RESET */ + mux { + pins = "gpio29"; + function = "gpio"; + }; + + config { + pins = "gpio29"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; + }; + + cam_sensor_suspend_rst2: cam-sensor-suspend-rst2 { + /* RESET */ + mux { + pins = "gpio37"; + function = "gpio"; + }; + + config { + pins = "gpio37"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; + }; + + cci_i2c_scl0_active: cci-i2c-scl0-active { + mux { + /* CLK, DATA */ + pins = "gpio33"; + function = "cci_i2c"; + }; + + config { + pins = "gpio33"; + bias-pull-up; /* PULL UP*/ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cci_i2c_scl0_suspend: cci-i2c-scl0-suspend { + mux { + /* CLK, DATA */ + pins = "gpio33"; + function = "cci_i2c"; + }; + + config { + pins = "gpio33"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cci_i2c_scl1_active: cci-i2c-scl1-active { + mux { + /* CLK, DATA */ + pins = "gpio35"; + function = "cci_i2c"; + }; + + config { + pins = "gpio35"; + bias-pull-up; /* PULL UP*/ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cci_i2c_scl1_suspend: cci-i2c-scl1-suspend { + mux { + /* CLK, DATA */ + pins = "gpio35"; + function = "cci_i2c"; + }; + + config { + pins = "gpio35"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + + cci_i2c_sda0_active: cci-i2c-sda0-active { + mux { + /* CLK, DATA */ + pins = "gpio32"; + function = "cci_i2c"; + }; + + config { + pins = "gpio32"; + bias-pull-up; /* PULL UP*/ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cci_i2c_sda0_suspend: cci-i2c-sda0-suspend { + mux { + /* CLK, DATA */ + pins = "gpio32"; + function = "cci_i2c"; + }; + + config { + pins = "gpio32"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cci_i2c_sda1_active: cci-i2c-sda1-active { + mux { + /* CLK, DATA */ + pins = "gpio34"; + function = "cci_i2c"; + }; + + config { + pins = "gpio34"; + bias-pull-up; /* PULL UP*/ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cci_i2c_sda1_suspend: cci-i2c-sda1-suspend { + mux { + /* CLK, DATA */ + pins = "gpio34"; + function = "cci_i2c"; + }; + + config { + pins = "gpio34"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/talos-evk-camx.dtso b/arch/arm64/boot/dts/qcom/talos-evk-camx.dtso new file mode 100644 index 0000000000000..a40d8817a7a20 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/talos-evk-camx.dtso @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +/dts-v1/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "talos-camera.dtsi" +#include "talos-camera-sensor.dtsi" From b698a9ad858ef788aa3d6ebe4052858ce3901ba3 Mon Sep 17 00:00:00 2001 From: Vishnu Saini Date: Thu, 22 Jan 2026 15:33:41 +0530 Subject: [PATCH 2205/2333] FROMLIST: Revert "arm64: dts: qcom: monaco-evk: add lt8713sx bridge for iq8" This reverts commit b017ba7f45d9b2a059da09d19d90bed0b3731c23. Reverting v1 patch, will be adding v3 patch. Signed-off-by: Vishnu Saini --- arch/arm64/boot/dts/qcom/monaco-evk.dts | 44 ------------------------- 1 file changed, 44 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/monaco-evk.dts b/arch/arm64/boot/dts/qcom/monaco-evk.dts index 697a30a9a4755..0138e295baa82 100644 --- a/arch/arm64/boot/dts/qcom/monaco-evk.dts +++ b/arch/arm64/boot/dts/qcom/monaco-evk.dts @@ -399,20 +399,6 @@ firmware-name = "qcom/qcs8300/a623_zap.mbn"; }; -&i2c0 { - pinctrl-0 = <&qup_i2c0_default>; - pinctrl-names = "default"; - - status = "okay"; - - lt8713sx: lt8713sx@4f { - /*Display bridge chip, DP1.4/HDMI2.0/DP++ hub*/ - compatible = "lontium,lt8713sx"; - reg = <0x4f>; - reset-gpios = <&expander5 6 GPIO_ACTIVE_HIGH>; - }; -}; - &i2c1 { pinctrl-0 = <&qup_i2c1_default>; pinctrl-names = "default"; @@ -502,23 +488,6 @@ }; }; -&mdss { - status = "okay"; -}; - -&mdss_dp0 { - status = "okay"; -}; - -&mdss_dp0_out { - data-lanes = <0 1 2 3>; - link-frequencies = /bits/ 64 <1620000000 2700000000 5400000000 8100000000>; -}; - -&mdss_dp0_phy { - status = "okay"; -}; - &iris { status = "okay"; }; @@ -614,12 +583,6 @@ }; &tlmm { - dp_hot_plug_det: dp-hot-plug-det-state { - pins = "gpio94"; - function = "edp0_hot"; - bias-disable; - }; - ethernet0_default: ethernet0-default-state { ethernet0_mdc: ethernet0-mdc-pins { pins = "gpio5"; @@ -682,13 +645,6 @@ }; }; - qup_i2c0_default: qup-i2c0-state { - pins = "gpio17", "gpio18"; - function = "qup0_se0"; - drive-strength = <2>; - bias-pull-up; - }; - qup_i2c1_default: qup-i2c1-state { pins = "gpio19", "gpio20"; function = "qup0_se1"; From a9153cfaba1316732751c1d8223d4ced2519dc70 Mon Sep 17 00:00:00 2001 From: Vishnu Saini Date: Thu, 22 Jan 2026 15:34:24 +0530 Subject: [PATCH 2206/2333] FROMLIST: Revert "defconfig: qcom: Enable lt8713sx bridge driver" This reverts commit b566557de8519d64ae0022c235cbbe51c01e7495. Reverting v1 patch, will be adding v3 patch. Signed-off-by: Vishnu Saini --- arch/arm64/configs/defconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig index 3ecc20978dc1d..15a7635ce8ac1 100644 --- a/arch/arm64/configs/defconfig +++ b/arch/arm64/configs/defconfig @@ -952,7 +952,6 @@ CONFIG_DRM_PANEL_VISIONOX_VTDR6130=m CONFIG_DRM_DISPLAY_CONNECTOR=m CONFIG_DRM_FSL_LDB=m CONFIG_DRM_ITE_IT6263=m -CONFIG_DRM_LONTIUM_LT8713SX=m CONFIG_DRM_LONTIUM_LT8912B=m CONFIG_DRM_LONTIUM_LT9611=m CONFIG_DRM_LONTIUM_LT9611UXC=m From 45ad6efe538729f2d04b2f3a002f55532d895b80 Mon Sep 17 00:00:00 2001 From: Vishnu Saini Date: Thu, 22 Jan 2026 15:34:53 +0530 Subject: [PATCH 2207/2333] FROMLIST: Revert "drm/bridge: add support for lontium lt8713sx bridge driver" This reverts commit ac23e7e5a8e6f12d4fe3d759ed38a5e0bfcff4bc. Reverting v1 patch, will be adding v3 patch. Signed-off-by: Vishnu Saini --- drivers/gpu/drm/bridge/Kconfig | 10 - drivers/gpu/drm/bridge/Makefile | 1 - drivers/gpu/drm/bridge/lontium-lt8713sx.c | 713 ---------------------- 3 files changed, 724 deletions(-) delete mode 100644 drivers/gpu/drm/bridge/lontium-lt8713sx.c diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig index 7fef383ed7cb7..a250afd8d6622 100644 --- a/drivers/gpu/drm/bridge/Kconfig +++ b/drivers/gpu/drm/bridge/Kconfig @@ -184,16 +184,6 @@ config DRM_LONTIUM_LT9611UXC HDMI signals Please say Y if you have such hardware. -config DRM_LONTIUM_LT8713SX - tristate "Lontium LT8713SX DP MST bridge" - depends on OF - select REGMAP_I2C - help - Driver for Lontium LT8713SX DP MST bridge - chip firmware upgrade, which converts Type-C/DP1.4 - to 3 configurable Type-C/DP1.4/HDMI2.0 outputs - Please say Y if you have such hardware. - config DRM_ITE_IT66121 tristate "ITE IT66121 HDMI bridge" depends on OF diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile index 07eeb13fa4978..c7dc03182e592 100644 --- a/drivers/gpu/drm/bridge/Makefile +++ b/drivers/gpu/drm/bridge/Makefile @@ -16,7 +16,6 @@ obj-$(CONFIG_DRM_LONTIUM_LT8912B) += lontium-lt8912b.o obj-$(CONFIG_DRM_LONTIUM_LT9211) += lontium-lt9211.o obj-$(CONFIG_DRM_LONTIUM_LT9611) += lontium-lt9611.o obj-$(CONFIG_DRM_LONTIUM_LT9611UXC) += lontium-lt9611uxc.o -obj-$(CONFIG_DRM_LONTIUM_LT8713SX) += lontium-lt8713sx.o obj-$(CONFIG_DRM_LVDS_CODEC) += lvds-codec.o obj-$(CONFIG_DRM_MEGACHIPS_STDPXXXX_GE_B850V3_FW) += megachips-stdpxxxx-ge-b850v3-fw.o obj-$(CONFIG_DRM_MICROCHIP_LVDS_SERIALIZER) += microchip-lvds.o diff --git a/drivers/gpu/drm/bridge/lontium-lt8713sx.c b/drivers/gpu/drm/bridge/lontium-lt8713sx.c deleted file mode 100644 index a5aed2474a2e9..0000000000000 --- a/drivers/gpu/drm/bridge/lontium-lt8713sx.c +++ /dev/null @@ -1,713 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define FW_FILE "lt8713sx_fw.bin" - -#define LT8713SX_PAGE_SIZE 256 -#define FW_12K_SIZE (12 * 1024) -#define FW_64K_SIZE (64 * 1024) -#define FW_256K_SIZE (256 * 1024) - -struct crc_config { - u8 width; - u32 poly; - u32 crc_init; - u32 xor_out; - bool ref_in; - bool ref_out; -}; - -struct lt8713sx { - struct device *dev; - - struct regmap *regmap; - /* Protects all accesses to registers by stopping the on-chip MCU */ - struct mutex ocm_lock; - - struct gpio_desc *reset_gpio; - struct gpio_desc *enable_gpio; - - struct regulator_bulk_data supplies[2]; - - struct i2c_client *client; - const struct firmware *fw; - - u8 *fw_buffer; - - u32 main_crc_value; - u32 bank_crc_value[17]; - - int bank_num; -}; - -static void lt8713sx_reset(struct lt8713sx *lt8713sx); - -static const struct regmap_range lt8713sx_ranges[] = { - { - .range_min = 0, - .range_max = 0xffff - }, -}; - -static const struct regmap_access_table lt8713sx_table = { - .yes_ranges = lt8713sx_ranges, - .n_yes_ranges = ARRAY_SIZE(lt8713sx_ranges), -}; - -static const struct regmap_config lt8713sx_regmap_config = { - .reg_bits = 8, - .val_bits = 8, - .volatile_table = <8713sx_table, - .cache_type = REGCACHE_NONE, -}; - -static void lt8713sx_i2c_enable(struct lt8713sx *lt8713sx) -{ - regmap_write(lt8713sx->regmap, 0xff, 0xe0); - regmap_write(lt8713sx->regmap, 0xee, 0x01); -} - -static void lt8713sx_i2c_disable(struct lt8713sx *lt8713sx) -{ - regmap_write(lt8713sx->regmap, 0xff, 0xe0); - regmap_write(lt8713sx->regmap, 0xee, 0x00); -} - -static unsigned int bits_reverse(u32 in_val, u8 bits) -{ - u32 out_val = 0; - u8 i; - - for (i = 0; i < bits; i++) { - if (in_val & (1 << i)) - out_val |= 1 << (bits - 1 - i); - } - - return out_val; -} - -static unsigned int get_crc(struct crc_config crc_cfg, const u8 *buf, u64 buf_len) -{ - u8 width = crc_cfg.width; - u32 poly = crc_cfg.poly; - u32 crc = crc_cfg.crc_init; - u32 xorout = crc_cfg.xor_out; - bool refin = crc_cfg.ref_in; - bool refout = crc_cfg.ref_out; - u8 n; - u32 bits; - u32 data; - u8 i; - - n = (width < 8) ? 0 : (width - 8); - crc = (width < 8) ? (crc << (8 - width)) : crc; - bits = (width < 8) ? 0x80 : (1 << (width - 1)); - poly = (width < 8) ? (poly << (8 - width)) : poly; - - while (buf_len--) { - data = *(buf++); - if (refin) - data = bits_reverse(data, 8); - crc ^= (data << n); - for (i = 0; i < 8; i++) { - if (crc & bits) - crc = (crc << 1) ^ poly; - else - crc = crc << 1; - } - } - crc = (width < 8) ? (crc >> (8 - width)) : crc; - if (refout) - crc = bits_reverse(crc, width); - crc ^= xorout; - - return (crc & ((2 << (width - 1)) - 1)); -} - -static u32 calculate_64K_crc(const u8 *upgrade_data, u64 len) -{ - struct crc_config crc_cfg = { - .width = 8, - .poly = 0x31, - .crc_init = 0, - .xor_out = 0, - .ref_out = false, - .ref_in = false, - }; - u64 crc_size = FW_64K_SIZE - 1; - u8 default_val = 0xFF; - - crc_cfg.crc_init = get_crc(crc_cfg, upgrade_data, len); - - crc_size -= len; - while (crc_size--) - crc_cfg.crc_init = get_crc(crc_cfg, &default_val, 1); - - return crc_cfg.crc_init; -} - -static u32 calculate_12K_crc(const u8 *upgrade_data, u64 len) -{ - struct crc_config crc_cfg = { - .width = 8, - .poly = 0x31, - .crc_init = 0, - .xor_out = 0, - .ref_out = false, - .ref_in = false, - }; - u64 crc_size = FW_12K_SIZE; - u8 default_val = 0xFF; - - crc_cfg.crc_init = get_crc(crc_cfg, upgrade_data, len); - - crc_size -= len; - while (crc_size--) - crc_cfg.crc_init = get_crc(crc_cfg, &default_val, 1); - - return crc_cfg.crc_init; -} - -static int lt8713sx_prepare_firmware_data(struct lt8713sx *lt8713sx) -{ - int ret = 0; - - ret = request_firmware(<8713sx->fw, FW_FILE, lt8713sx->dev); - if (ret < 0) { - pr_err("request firmware failed\n"); - return ret; - } - - pr_debug("Firmware size: %zu bytes\n", lt8713sx->fw->size); - - if (lt8713sx->fw->size > FW_256K_SIZE - 1) { - pr_err("Firmware size exceeds 256KB limit\n"); - release_firmware(lt8713sx->fw); - return -EINVAL; - } - - lt8713sx->fw_buffer = kzalloc(FW_256K_SIZE, GFP_KERNEL); - if (!lt8713sx->fw_buffer) { - release_firmware(lt8713sx->fw); - return -ENOMEM; - } - - memset(lt8713sx->fw_buffer, 0xFF, FW_256K_SIZE); - - if (lt8713sx->fw->size < FW_64K_SIZE) { - /*TODO: CRC should be calculated with 0xff also */ - memcpy(lt8713sx->fw_buffer, lt8713sx->fw->data, lt8713sx->fw->size); - lt8713sx->fw_buffer[FW_64K_SIZE - 1] = - calculate_64K_crc(lt8713sx->fw->data, lt8713sx->fw->size); - lt8713sx->main_crc_value = lt8713sx->fw_buffer[FW_64K_SIZE - 1]; - pr_debug("Main Firmware Data Crc=0x%02X\n", lt8713sx->main_crc_value); - - } else { - //main firmware - memcpy(lt8713sx->fw_buffer, lt8713sx->fw->data, FW_64K_SIZE - 1); - lt8713sx->fw_buffer[FW_64K_SIZE - 1] = - calculate_64K_crc(lt8713sx->fw_buffer, FW_64K_SIZE - 1); - lt8713sx->main_crc_value = lt8713sx->fw_buffer[FW_64K_SIZE - 1]; - pr_debug("Main Firmware Data Crc=0x%02X\n", lt8713sx->main_crc_value); - - //bank firmware - memcpy(lt8713sx->fw_buffer + FW_64K_SIZE, - lt8713sx->fw->data + FW_64K_SIZE, - lt8713sx->fw->size - FW_64K_SIZE); - - lt8713sx->bank_num = (lt8713sx->fw->size - FW_64K_SIZE + FW_12K_SIZE - 1) / - FW_12K_SIZE; - pr_debug("Bank Number Total is %d.\n", lt8713sx->bank_num); - - for (int i = 0; i < lt8713sx->bank_num; i++) { - lt8713sx->bank_crc_value[i] = - calculate_12K_crc(lt8713sx->fw_buffer + FW_64K_SIZE + - i * FW_12K_SIZE, - FW_12K_SIZE); - pr_debug("Bank number:%d; Firmware Data Crc:0x%02X\n", - i, lt8713sx->bank_crc_value[i]); - } - } - return 0; -} - -static void lt8713sx_config_parameters(struct lt8713sx *lt8713sx) -{ - regmap_write(lt8713sx->regmap, 0xFF, 0xE0); - regmap_write(lt8713sx->regmap, 0xEE, 0x01); - regmap_write(lt8713sx->regmap, 0x5E, 0xC1); - regmap_write(lt8713sx->regmap, 0x58, 0x00); - regmap_write(lt8713sx->regmap, 0x59, 0x50); - regmap_write(lt8713sx->regmap, 0x5A, 0x10); - regmap_write(lt8713sx->regmap, 0x5A, 0x00); - regmap_write(lt8713sx->regmap, 0x58, 0x21); -} - -static void lt8713sx_wren(struct lt8713sx *lt8713sx) -{ - regmap_write(lt8713sx->regmap, 0xff, 0xe1); - regmap_write(lt8713sx->regmap, 0x03, 0xbf); - regmap_write(lt8713sx->regmap, 0x03, 0xff); - regmap_write(lt8713sx->regmap, 0xff, 0xe0); - regmap_write(lt8713sx->regmap, 0x5a, 0x04); - regmap_write(lt8713sx->regmap, 0x5a, 0x00); -} - -static void lt8713sx_wrdi(struct lt8713sx *lt8713sx) -{ - regmap_write(lt8713sx->regmap, 0x5A, 0x08); - regmap_write(lt8713sx->regmap, 0x5A, 0x00); -} - -static void lt8713sx_fifo_reset(struct lt8713sx *lt8713sx) -{ - regmap_write(lt8713sx->regmap, 0xff, 0xe1); - regmap_write(lt8713sx->regmap, 0x03, 0xbf); - regmap_write(lt8713sx->regmap, 0x03, 0xff); -} - -static void lt8713sx_disable_sram_write(struct lt8713sx *lt8713sx) -{ - regmap_write(lt8713sx->regmap, 0xff, 0xe0); - regmap_write(lt8713sx->regmap, 0x55, 0x00); -} - -static void lt8713sx_sram_to_flash(struct lt8713sx *lt8713sx) -{ - regmap_write(lt8713sx->regmap, 0x5a, 0x30); - regmap_write(lt8713sx->regmap, 0x5a, 0x00); -} - -static void lt8713sx_i2c_to_sram(struct lt8713sx *lt8713sx) -{ - regmap_write(lt8713sx->regmap, 0x55, 0x80); - regmap_write(lt8713sx->regmap, 0x5e, 0xc0); - regmap_write(lt8713sx->regmap, 0x58, 0x21); -} - -static u8 lt8713sx_read_flash_status(struct lt8713sx *lt8713sx) -{ - u32 flash_status = 0; - - regmap_write(lt8713sx->regmap, 0xFF, 0xE1);//fifo_rst_n - regmap_write(lt8713sx->regmap, 0x03, 0x3F); - regmap_write(lt8713sx->regmap, 0x03, 0xFF); - - regmap_write(lt8713sx->regmap, 0xFF, 0xE0); - regmap_write(lt8713sx->regmap, 0x5e, 0x40); - regmap_write(lt8713sx->regmap, 0x56, 0x05);//opcode=read status register - regmap_write(lt8713sx->regmap, 0x55, 0x25); - regmap_write(lt8713sx->regmap, 0x55, 0x01); - regmap_write(lt8713sx->regmap, 0x58, 0x21); - - regmap_read(lt8713sx->regmap, 0x5f, &flash_status); - pr_debug("flash_status:%x\n", flash_status); - - return flash_status; -} - -static void lt8713sx_block_erase(struct lt8713sx *lt8713sx) -{ - u32 i = 0; - u8 flash_status = 0; - u8 blocknum = 0x00; - u32 flashaddr = 0x00; - - for (blocknum = 0; blocknum < 8; blocknum++) { - flashaddr = blocknum * 0x008000; - regmap_write(lt8713sx->regmap, 0xFF, 0xE0); - regmap_write(lt8713sx->regmap, 0xEE, 0x01); - regmap_write(lt8713sx->regmap, 0x5A, 0x04); - regmap_write(lt8713sx->regmap, 0x5A, 0x00); - regmap_write(lt8713sx->regmap, 0x5B, flashaddr >> 16);//set flash address[23:16] - regmap_write(lt8713sx->regmap, 0x5C, flashaddr >> 8);//set flash address[15:8] - regmap_write(lt8713sx->regmap, 0x5D, flashaddr);//set flash address[7:0] - regmap_write(lt8713sx->regmap, 0x5A, 0x01); - regmap_write(lt8713sx->regmap, 0x5A, 0x00); - msleep(100); //delay 100ms - i = 0; - while (1) { - flash_status = lt8713sx_read_flash_status(lt8713sx); //wait erase finish - if ((flash_status & 0x01) == 0) - break; - - if (i > 50) - break; - - i++; - msleep(50); //delay 50ms - } - } - pr_debug("erase flash done.\n"); -} - -static void lt8713sx_load_main_fw_to_sram(struct lt8713sx *lt8713sx) -{ - regmap_write(lt8713sx->regmap, 0xff, 0xe0); - regmap_write(lt8713sx->regmap, 0xee, 0x01); - regmap_write(lt8713sx->regmap, 0x68, 0x00); - regmap_write(lt8713sx->regmap, 0x69, 0x00); - regmap_write(lt8713sx->regmap, 0x6a, 0x00); - regmap_write(lt8713sx->regmap, 0x65, 0x00); - regmap_write(lt8713sx->regmap, 0x66, 0xff); - regmap_write(lt8713sx->regmap, 0x67, 0xff); - regmap_write(lt8713sx->regmap, 0x6b, 0x00); - regmap_write(lt8713sx->regmap, 0x6c, 0x00); - regmap_write(lt8713sx->regmap, 0x60, 0x01); - msleep(200); - regmap_write(lt8713sx->regmap, 0x60, 0x00); -} - -static void lt8713sx_load_bank_fw_to_sram(struct lt8713sx *lt8713sx, u64 addr) -{ - regmap_write(lt8713sx->regmap, 0xff, 0xe0); - regmap_write(lt8713sx->regmap, 0xee, 0x01); - regmap_write(lt8713sx->regmap, 0x68, ((addr & 0xFF0000) >> 16)); - regmap_write(lt8713sx->regmap, 0x69, ((addr & 0x00FF00) >> 8)); - regmap_write(lt8713sx->regmap, 0x6a, (addr & 0x0000FF)); - regmap_write(lt8713sx->regmap, 0x65, 0x00); - regmap_write(lt8713sx->regmap, 0x66, 0x30); - regmap_write(lt8713sx->regmap, 0x67, 0x00); - regmap_write(lt8713sx->regmap, 0x6b, 0x00); - regmap_write(lt8713sx->regmap, 0x6c, 0x00); - regmap_write(lt8713sx->regmap, 0x60, 0x01); - msleep(50); - regmap_write(lt8713sx->regmap, 0x60, 0x00); -} - -static int lt8713sx_write_data(struct lt8713sx *lt8713sx, const u8 *data, u64 filesize) -{ - int page = 0, num = 0, i = 0, val; - - page = (filesize % LT8713SX_PAGE_SIZE) ? - ((filesize / LT8713SX_PAGE_SIZE) + 1) : (filesize / LT8713SX_PAGE_SIZE); - - pr_debug("Writing to Sram=%u pages, total size = %llu bytes\n", page, filesize); - - for (num = 0; num < page; num++) { - pr_debug("page[%d]\n", num); - lt8713sx_i2c_to_sram(lt8713sx); - - for (i = 0; i < LT8713SX_PAGE_SIZE; i++) { - if ((num * LT8713SX_PAGE_SIZE + i) < filesize) - val = *(data + (num * LT8713SX_PAGE_SIZE + i)); - else - val = 0xFF; - regmap_write(lt8713sx->regmap, 0x59, val); - } - - lt8713sx_wren(lt8713sx); - lt8713sx_sram_to_flash(lt8713sx); - } - - lt8713sx_wrdi(lt8713sx); - lt8713sx_disable_sram_write(lt8713sx); - - return 0; -} - -static void lt8713sx_main_upgrade_result(struct lt8713sx *lt8713sx) -{ - u32 main_crc_result; - - regmap_write(lt8713sx->regmap, 0xff, 0xe0); - regmap_read(lt8713sx->regmap, 0x23, &main_crc_result); - - pr_debug("Main CRC HW: 0x%02X\n", main_crc_result); - pr_debug("Main CRC FW: 0x%02X\n", lt8713sx->main_crc_value); - - if (main_crc_result == lt8713sx->main_crc_value) - pr_debug("Main Firmware Upgrade Success.\n"); - else - pr_err("Main Firmware Upgrade Failed.\n"); -} - -static void lt8713sx_bank_upgrade_result(struct lt8713sx *lt8713sx, u8 banknum) -{ - u32 bank_crc_result; - - regmap_write(lt8713sx->regmap, 0xff, 0xe0); - - regmap_read(lt8713sx->regmap, 0x23, &bank_crc_result); - - pr_debug("Bank %d CRC Result: 0x%02X\n", banknum, bank_crc_result); - - if (bank_crc_result == lt8713sx->bank_crc_value[banknum]) - pr_debug("Bank %d Firmware Upgrade Success.\n", banknum); - else - pr_err("Bank %d Firmware Upgrade Failed.\n", banknum); -} - -static void lt8713sx_bank_result_check(struct lt8713sx *lt8713sx) -{ - int i; - u64 addr = 0x010000; - - for (i = 0; i < lt8713sx->bank_num; i++) { - lt8713sx_load_bank_fw_to_sram(lt8713sx, addr); - lt8713sx_bank_upgrade_result(lt8713sx, i); - addr += 0x3000; - } -} - -static int lt8713sx_firmware_upgrade(struct lt8713sx *lt8713sx) -{ - int ret; - - lt8713sx_config_parameters(lt8713sx); - - lt8713sx_block_erase(lt8713sx); - - if (lt8713sx->fw->size < FW_64K_SIZE) { - ret = lt8713sx_write_data(lt8713sx, lt8713sx->fw_buffer, FW_64K_SIZE); - if (ret < 0) { - pr_err("Failed to write firmware data: %d\n", ret); - return ret; - } - } else { - ret = lt8713sx_write_data(lt8713sx, lt8713sx->fw_buffer, lt8713sx->fw->size); - if (ret < 0) { - pr_err("Failed to write firmware data: %d\n", ret); - return ret; - } - } - - pr_debug("Write Data done.\n"); - - return 0; -} - -static int lt8713sx_firmware_update(struct lt8713sx *lt8713sx) -{ - int ret = 0; - - mutex_lock(<8713sx->ocm_lock); - lt8713sx_i2c_enable(lt8713sx); - - ret = lt8713sx_prepare_firmware_data(lt8713sx); - if (ret < 0) { - pr_err("Failed to prepare firmware data: %d\n", ret); - goto error; - } - - ret = lt8713sx_firmware_upgrade(lt8713sx); - if (ret < 0) { - pr_err("Upgrade failure.\n"); - goto error; - } else { - /* Validate CRC */ - lt8713sx_load_main_fw_to_sram(lt8713sx); - lt8713sx_main_upgrade_result(lt8713sx); - lt8713sx_wrdi(lt8713sx); - lt8713sx_fifo_reset(lt8713sx); - lt8713sx_bank_result_check(lt8713sx); - lt8713sx_wrdi(lt8713sx); - } - -error: - lt8713sx_i2c_disable(lt8713sx); - if (!ret) - lt8713sx_reset(lt8713sx); - - kfree(lt8713sx->fw_buffer); - lt8713sx->fw_buffer = NULL; - - if (lt8713sx->fw) { - release_firmware(lt8713sx->fw); - lt8713sx->fw = NULL; - } - mutex_unlock(<8713sx->ocm_lock); - - return ret; -} - -static void lt8713sx_reset(struct lt8713sx *lt8713sx) -{ - pr_debug("reset bridge.\n"); - gpiod_set_value_cansleep(lt8713sx->reset_gpio, 1); - msleep(20); - - gpiod_set_value_cansleep(lt8713sx->reset_gpio, 0); - msleep(20); - - gpiod_set_value_cansleep(lt8713sx->reset_gpio, 1); - msleep(20); - pr_debug("reset done.\n"); -} - -static int lt8713sx_regulator_init(struct lt8713sx *lt8713sx) -{ - int ret; - - lt8713sx->supplies[0].supply = "vdd"; - lt8713sx->supplies[1].supply = "vcc"; - - ret = devm_regulator_bulk_get(lt8713sx->dev, 2, lt8713sx->supplies); - if (ret < 0) - return dev_err_probe(lt8713sx->dev, ret, "failed to get regulators\n"); - - ret = regulator_set_load(lt8713sx->supplies[0].consumer, 200000); - if (ret < 0) - return dev_err_probe(lt8713sx->dev, ret, "failed to set regulator load\n"); - - return 0; -} - -static int lt8713sx_regulator_enable(struct lt8713sx *lt8713sx) -{ - int ret; - - ret = regulator_enable(lt8713sx->supplies[0].consumer); - if (ret < 0) - return dev_err_probe(lt8713sx->dev, ret, "failed to enable vdd regulator\n"); - - usleep_range(1000, 10000); - - ret = regulator_enable(lt8713sx->supplies[1].consumer); - if (ret < 0) { - regulator_disable(lt8713sx->supplies[0].consumer); - return dev_err_probe(lt8713sx->dev, ret, "failed to enable vcc regulator\n"); - } - return 0; -} - -static int lt8713sx_gpio_init(struct lt8713sx *lt8713sx) -{ - struct device *dev = lt8713sx->dev; - - lt8713sx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); - if (IS_ERR(lt8713sx->reset_gpio)) - return dev_err_probe(dev, PTR_ERR(lt8713sx->reset_gpio), - "failed to acquire reset gpio\n"); - - /* power enable gpio */ - lt8713sx->enable_gpio = devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_HIGH); - if (IS_ERR(lt8713sx->enable_gpio)) - return dev_err_probe(dev, PTR_ERR(lt8713sx->enable_gpio), - "failed to acquire enable gpio\n"); - return 0; -} - -static ssize_t lt8713sx_firmware_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) -{ - struct lt8713sx *lt8713sx = dev_get_drvdata(dev); - int ret; - - ret = lt8713sx_firmware_update(lt8713sx); - if (ret < 0) - return ret; - return len; -} - -static DEVICE_ATTR_WO(lt8713sx_firmware); - -static struct attribute *lt8713sx_attrs[] = { - &dev_attr_lt8713sx_firmware.attr, - NULL, -}; - -static const struct attribute_group lt8713sx_attr_group = { - .attrs = lt8713sx_attrs, -}; - -static const struct attribute_group *lt8713sx_attr_groups[] = { - <8713sx_attr_group, - NULL, -}; - -static int lt8713sx_probe(struct i2c_client *client) -{ - struct lt8713sx *lt8713sx; - struct device *dev = &client->dev; - int ret; - - if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) - return dev_err_probe(dev, -ENODEV, "device doesn't support I2C\n"); - - lt8713sx = devm_kzalloc(dev, sizeof(*lt8713sx), GFP_KERNEL); - if (!lt8713sx) - return dev_err_probe(dev, -ENOMEM, "failed to allocate lt8713sx struct\n"); - - lt8713sx->dev = dev; - lt8713sx->client = client; - i2c_set_clientdata(client, lt8713sx); - - mutex_init(<8713sx->ocm_lock); - - lt8713sx->regmap = devm_regmap_init_i2c(client, <8713sx_regmap_config); - if (IS_ERR(lt8713sx->regmap)) - return dev_err_probe(dev, PTR_ERR(lt8713sx->regmap), "regmap i2c init failed\n"); - - ret = lt8713sx_gpio_init(lt8713sx); - if (ret < 0) - goto err_of_put; - - ret = lt8713sx_regulator_init(lt8713sx); - if (ret < 0) - goto err_of_put; - - ret = lt8713sx_regulator_enable(lt8713sx); - if (ret) - goto err_of_put; - - lt8713sx_reset(lt8713sx); - - return 0; - -err_of_put: - return ret; -} - -static void lt8713sx_remove(struct i2c_client *client) -{ - struct lt8713sx *lt8713sx = i2c_get_clientdata(client); - - mutex_destroy(<8713sx->ocm_lock); - - regulator_bulk_disable(ARRAY_SIZE(lt8713sx->supplies), lt8713sx->supplies); -} - -static struct i2c_device_id lt8713sx_id[] = { - { "lontium,lt8713sx", 0 }, - { /* sentinel */ } -}; - -static const struct of_device_id lt8713sx_match_table[] = { - { .compatible = "lontium,lt8713sx" }, - { /* sentinel */ } -}; -MODULE_DEVICE_TABLE(of, lt8713sx_match_table); - -static struct i2c_driver lt8713sx_driver = { - .driver = { - .name = "lt8713sx", - .of_match_table = lt8713sx_match_table, - .dev_groups = lt8713sx_attr_groups, - }, - .probe = lt8713sx_probe, - .remove = lt8713sx_remove, - .id_table = lt8713sx_id, -}; - -module_i2c_driver(lt8713sx_driver); -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("lt8713sx drm bridge driver"); -MODULE_AUTHOR("Tony "); -MODULE_FIRMWARE(FW_FILE); From 7f486e97cef9a967ab437683fb083b2beb6a741d Mon Sep 17 00:00:00 2001 From: Vishnu Saini Date: Thu, 22 Jan 2026 15:35:32 +0530 Subject: [PATCH 2208/2333] FROMLIST: Revert "dt-bindings: bridge: lt8713sx: Add bindings" This reverts commit f562df8e56dedc2e91f268ae1daebc4359bd4e25. Reverting v1 patch, will be adding v3 patch. Signed-off-by: Vishnu Saini --- .../display/bridge/lontium,lt8713sx.yaml | 52 ------------------- 1 file changed, 52 deletions(-) delete mode 100644 Documentation/devicetree/bindings/display/bridge/lontium,lt8713sx.yaml diff --git a/Documentation/devicetree/bindings/display/bridge/lontium,lt8713sx.yaml b/Documentation/devicetree/bindings/display/bridge/lontium,lt8713sx.yaml deleted file mode 100644 index 3fb7e042c6887..0000000000000 --- a/Documentation/devicetree/bindings/display/bridge/lontium,lt8713sx.yaml +++ /dev/null @@ -1,52 +0,0 @@ -# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) -%YAML 1.2 ---- -$id: http://devicetree.org/schemas/display/bridge/lontium,lt8713sx.yaml# -$schema: http://devicetree.org/meta-schemas/core.yaml# - -title: Lontium LT8713SX Type-C/DP1.4 to Type-C/DP1.4/HDMI2.0/DP++ bridge-hub - -maintainers: - - Tony - -description: - The Lontium LT8713SX is a Type-C/DP1.4 to Type-C/DP1.4/HDMI2.0 converter - that integrates one DP input and up to three configurable output interfaces - (DP1.4 / HDMI2.0 / DP++), with SST/MST functionality and audio support. - -properties: - compatible: - enum: - - lontium,lt8713sx - - reg: - maxItems: 1 - - vcc-supply: - description: Regulator for 3.3V vcc. - - vdd-supply: - description: Regulator for 1.1V vdd. - - reset-gpios: - description: GPIO connected to active high RESET pin. - -required: - - compatible - - reg - -additionalProperties: false - -examples: - - | - #include - - i2c { - #address-cells = <1>; - #size-cells = <0>; - bridge@4f { - compatible = "lontium,lt8713sx"; - reg = <0x4f>; - reset-gpios = <&tlmm 6 GPIO_ACTIVE_HIGH>; - }; - }; From ce436a54d529529cb30003172ecfc22db13ad12d Mon Sep 17 00:00:00 2001 From: Vishnu Saini Date: Thu, 22 Jan 2026 15:36:05 +0530 Subject: [PATCH 2209/2333] FROMLIST: dt-bindings: bridge: lt8713sx: Add bindings Add bindings for lt8713sx. Link: https://lore.kernel.org/all/20251228-lt8713sx-bridge-driver-v3-1-9169fbef0e5b@oss.qualcomm.com/ Co-developed-by: Prahlad Valluru Signed-off-by: Prahlad Valluru Signed-off-by: Vishnu Saini Reviewed-by: Krzysztof Kozlowski --- .../display/bridge/lontium,lt8713sx.yaml | 101 ++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/bridge/lontium,lt8713sx.yaml diff --git a/Documentation/devicetree/bindings/display/bridge/lontium,lt8713sx.yaml b/Documentation/devicetree/bindings/display/bridge/lontium,lt8713sx.yaml new file mode 100644 index 0000000000000..0a6dc56e337cb --- /dev/null +++ b/Documentation/devicetree/bindings/display/bridge/lontium,lt8713sx.yaml @@ -0,0 +1,101 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/bridge/lontium,lt8713sx.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Lontium LT8713SX Type-C/DP1.4 to Type-C/DP1.4/HDMI2.0/DP++ bridge-hub + +maintainers: + - Tony + +description: + The Lontium LT8713SX is a Type-C/DP1.4 to Type-C/DP1.4/HDMI2.0 converter + that integrates one DP input and up to three configurable output interfaces + (DP1.4 / HDMI2.0 / DP++), with SST/MST functionality and audio support. + +properties: + compatible: + enum: + - lontium,lt8713sx + + reg: + maxItems: 1 + + vcc-supply: + description: Regulator for 3.3V vcc. + + vdd-supply: + description: Regulator for 1.1V vdd. + + reset-gpios: + description: GPIO connected to active low RESET pin. + + ports: + $ref: /schemas/graph.yaml#/properties/ports + + properties: + port@0: + $ref: /schemas/graph.yaml#/properties/port + description: + DP port for DP input from soc to bridge chip + + port@1: + $ref: /schemas/graph.yaml#/properties/port + description: + DP port for DP output from bridge + + port@2: + $ref: /schemas/graph.yaml#/properties/port + description: + Additional DP port for DP output from bridge + + required: + - port@0 + +required: + - compatible + - reg + - ports + +additionalProperties: false + +examples: + - | + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + bridge@4f { + compatible = "lontium,lt8713sx"; + reg = <0x4f>; + reset-gpios = <&tlmm 6 GPIO_ACTIVE_LOW>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + lt8713sx_dp_in: endpoint { + remote-endpoint = <&mdss_dp0_out>; + }; + }; + + port@1 { + reg = <1>; + lt8713sx_dp0_out: endpoint { + remote-endpoint = <&dp0_connector_in>; + }; + }; + + port@2 { + reg = <2>; + lt8713sx_dp1_out: endpoint { + remote-endpoint = <&dp1_connector_in>; + }; + }; + }; + }; + }; From 60f738abe79e37bf065145c97bdd74506010baa1 Mon Sep 17 00:00:00 2001 From: Vishnu Saini Date: Thu, 22 Jan 2026 15:37:09 +0530 Subject: [PATCH 2210/2333] FROMLIST: drm/bridge: add support for lontium lt8713sx bridge driver The lt8713sx is a Type-C/DP1.4 to Type-C/DP1.4/HDMI2.0 converter, with three configurable DP1.4/HDMI2.0/DP++ output interfaces and audio output interface. Driver is required for firmware upgrade in the bridge chip. Link: https://lore.kernel.org/all/20251228-lt8713sx-bridge-driver-v3-2-9169fbef0e5b@oss.qualcomm.com/ Co-developed-by: Prahlad Valluru Signed-off-by: Prahlad Valluru Signed-off-by: Vishnu Saini --- drivers/gpu/drm/bridge/Kconfig | 10 + drivers/gpu/drm/bridge/Makefile | 1 + drivers/gpu/drm/bridge/lontium-lt8713sx.c | 682 ++++++++++++++++++++++ 3 files changed, 693 insertions(+) create mode 100644 drivers/gpu/drm/bridge/lontium-lt8713sx.c diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig index a250afd8d6622..7fef383ed7cb7 100644 --- a/drivers/gpu/drm/bridge/Kconfig +++ b/drivers/gpu/drm/bridge/Kconfig @@ -184,6 +184,16 @@ config DRM_LONTIUM_LT9611UXC HDMI signals Please say Y if you have such hardware. +config DRM_LONTIUM_LT8713SX + tristate "Lontium LT8713SX DP MST bridge" + depends on OF + select REGMAP_I2C + help + Driver for Lontium LT8713SX DP MST bridge + chip firmware upgrade, which converts Type-C/DP1.4 + to 3 configurable Type-C/DP1.4/HDMI2.0 outputs + Please say Y if you have such hardware. + config DRM_ITE_IT66121 tristate "ITE IT66121 HDMI bridge" depends on OF diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile index c7dc03182e592..07eeb13fa4978 100644 --- a/drivers/gpu/drm/bridge/Makefile +++ b/drivers/gpu/drm/bridge/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_DRM_LONTIUM_LT8912B) += lontium-lt8912b.o obj-$(CONFIG_DRM_LONTIUM_LT9211) += lontium-lt9211.o obj-$(CONFIG_DRM_LONTIUM_LT9611) += lontium-lt9611.o obj-$(CONFIG_DRM_LONTIUM_LT9611UXC) += lontium-lt9611uxc.o +obj-$(CONFIG_DRM_LONTIUM_LT8713SX) += lontium-lt8713sx.o obj-$(CONFIG_DRM_LVDS_CODEC) += lvds-codec.o obj-$(CONFIG_DRM_MEGACHIPS_STDPXXXX_GE_B850V3_FW) += megachips-stdpxxxx-ge-b850v3-fw.o obj-$(CONFIG_DRM_MICROCHIP_LVDS_SERIALIZER) += microchip-lvds.o diff --git a/drivers/gpu/drm/bridge/lontium-lt8713sx.c b/drivers/gpu/drm/bridge/lontium-lt8713sx.c new file mode 100644 index 0000000000000..6ea54ff3733d4 --- /dev/null +++ b/drivers/gpu/drm/bridge/lontium-lt8713sx.c @@ -0,0 +1,682 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define FW_FILE "lt8713sx_fw.bin" + +#define REG_PAGE_CONTROL 0xff + +#define MAX_OUTPUT_PORTS 3 +#define LT8713SX_PAGE_SIZE 256 + +DECLARE_CRC8_TABLE(lt8713sx_crc_table); + +struct lt8713sx { + struct device *dev; + struct drm_bridge bridge; + struct drm_bridge *next_bridge[MAX_OUTPUT_PORTS]; + int num_outputs; + + struct regmap *regmap; + /* Protects all accesses to registers by stopping the on-chip MCU */ + struct mutex ocm_lock; + + struct gpio_desc *reset_gpio; + struct gpio_desc *enable_gpio; + + struct i2c_client *client; + const struct firmware *fw; + + u8 *fw_buffer; + + u32 main_crc_value; + u32 bank_crc_value[17]; + + int bank_num; +}; + +static void lt8713sx_reset(struct lt8713sx *lt8713sx); + +static const struct regmap_range lt8713sx_ranges[] = { + { + .range_min = 0x0000, + .range_max = 0xffff + }, +}; + +static const struct regmap_access_table lt8713sx_table = { + .yes_ranges = lt8713sx_ranges, + .n_yes_ranges = ARRAY_SIZE(lt8713sx_ranges), +}; + +static const struct regmap_range_cfg lt8713sx_range_cfg = { + .name = "lt8713sx", + .range_min = 0x0000, + .range_max = 0xffff, + .selector_reg = REG_PAGE_CONTROL, + .selector_mask = 0xff, + .selector_shift = 0, + .window_start = 0, + .window_len = 0x100, +}; + +static const struct regmap_config lt8713sx_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .volatile_table = <8713sx_table, + .ranges = <8713sx_range_cfg, + .num_ranges = 1, + .cache_type = REGCACHE_NONE, + .max_register = 0xffff, +}; + +static void lt8713sx_i2c_enable(struct lt8713sx *lt8713sx) +{ + regmap_write(lt8713sx->regmap, 0xe0ee, 0x01); +} + +static void lt8713sx_i2c_disable(struct lt8713sx *lt8713sx) +{ + regmap_write(lt8713sx->regmap, 0xe0ee, 0x00); +} + +static u32 calculate_crc(const u8 *upgrade_data, u64 len, u64 crc_size) +{ + u8 crc = 0x00; + u8 pad = 0xff; + + crc = crc8(lt8713sx_crc_table, upgrade_data, len, crc); + + /* pad remaining bytes */ + crc_size -= len; + while (crc_size--) + crc = crc8(lt8713sx_crc_table, &pad, 1, crc); + + return crc; +} + +static int lt8713sx_prepare_firmware_data(struct lt8713sx *lt8713sx) +{ + int ret = 0; + u64 sz_12k = 12 * SZ_1K; + + ret = request_firmware(<8713sx->fw, FW_FILE, lt8713sx->dev); + if (ret < 0) { + dev_err(lt8713sx->dev, "request firmware failed\n"); + return ret; + } + + dev_dbg(lt8713sx->dev, "Firmware size: %zu bytes\n", lt8713sx->fw->size); + + if (lt8713sx->fw->size > SZ_256K - 1) { + dev_err(lt8713sx->dev, "Firmware size exceeds 256KB limit\n"); + release_firmware(lt8713sx->fw); + return -EINVAL; + } + + lt8713sx->fw_buffer = kvmalloc(SZ_256K, GFP_KERNEL); + if (!lt8713sx->fw_buffer) { + release_firmware(lt8713sx->fw); + return -ENOMEM; + } + + memset(lt8713sx->fw_buffer, 0xff, SZ_256K); + + if (lt8713sx->fw->size < SZ_64K) { + memcpy(lt8713sx->fw_buffer, lt8713sx->fw->data, lt8713sx->fw->size); + lt8713sx->fw_buffer[SZ_64K - 1] = + calculate_crc(lt8713sx->fw->data, lt8713sx->fw->size, SZ_64K - 1); + lt8713sx->main_crc_value = lt8713sx->fw_buffer[SZ_64K - 1]; + dev_dbg(lt8713sx->dev, + "Main Firmware Data Crc=0x%02X\n", lt8713sx->main_crc_value); + + } else { + /* main firmware */ + memcpy(lt8713sx->fw_buffer, lt8713sx->fw->data, SZ_64K - 1); + lt8713sx->fw_buffer[SZ_64K - 1] = + calculate_crc(lt8713sx->fw_buffer, SZ_64K - 1, SZ_64K - 1); + lt8713sx->main_crc_value = lt8713sx->fw_buffer[SZ_64K - 1]; + dev_dbg(lt8713sx->dev, + "Main Firmware Data Crc=0x%02X\n", lt8713sx->main_crc_value); + + /* bank firmware */ + memcpy(lt8713sx->fw_buffer + SZ_64K, + lt8713sx->fw->data + SZ_64K, + lt8713sx->fw->size - SZ_64K); + + lt8713sx->bank_num = (lt8713sx->fw->size - SZ_64K + sz_12k - 1) / sz_12k; + dev_dbg(lt8713sx->dev, "Bank Number Total is %d.\n", lt8713sx->bank_num); + + for (int i = 0; i < lt8713sx->bank_num; i++) { + lt8713sx->bank_crc_value[i] = + calculate_crc(lt8713sx->fw_buffer + SZ_64K + i * sz_12k, + sz_12k, sz_12k); + dev_dbg(lt8713sx->dev, "Bank number:%d; Firmware Data Crc:0x%02X\n", + i, lt8713sx->bank_crc_value[i]); + } + } + return 0; +} + +static void lt8713sx_config_parameters(struct lt8713sx *lt8713sx) +{ + regmap_write(lt8713sx->regmap, 0xe0ee, 0x01); + regmap_write(lt8713sx->regmap, 0xe05e, 0xc1); + regmap_write(lt8713sx->regmap, 0xe058, 0x00); + regmap_write(lt8713sx->regmap, 0xe059, 0x50); + regmap_write(lt8713sx->regmap, 0xe05a, 0x10); + regmap_write(lt8713sx->regmap, 0xe05a, 0x00); + regmap_write(lt8713sx->regmap, 0xe058, 0x21); +} + +static void lt8713sx_wren(struct lt8713sx *lt8713sx) +{ + regmap_write(lt8713sx->regmap, 0xe103, 0xbf); + regmap_write(lt8713sx->regmap, 0xe103, 0xff); + regmap_write(lt8713sx->regmap, 0xe05a, 0x04); + regmap_write(lt8713sx->regmap, 0xe05a, 0x00); +} + +static void lt8713sx_wrdi(struct lt8713sx *lt8713sx) +{ + regmap_write(lt8713sx->regmap, 0xe05a, 0x08); + regmap_write(lt8713sx->regmap, 0xe05a, 0x00); +} + +static void lt8713sx_fifo_reset(struct lt8713sx *lt8713sx) +{ + regmap_write(lt8713sx->regmap, 0xe103, 0xbf); + regmap_write(lt8713sx->regmap, 0xe103, 0xff); +} + +static void lt8713sx_disable_sram_write(struct lt8713sx *lt8713sx) +{ + regmap_write(lt8713sx->regmap, 0xe055, 0x00); +} + +static void lt8713sx_sram_to_flash(struct lt8713sx *lt8713sx) +{ + regmap_write(lt8713sx->regmap, 0xe05a, 0x30); + regmap_write(lt8713sx->regmap, 0xe05a, 0x00); +} + +static void lt8713sx_i2c_to_sram(struct lt8713sx *lt8713sx) +{ + regmap_write(lt8713sx->regmap, 0xe055, 0x80); + regmap_write(lt8713sx->regmap, 0xe05e, 0xc0); + regmap_write(lt8713sx->regmap, 0xe058, 0x21); +} + +static u8 lt8713sx_read_flash_status(struct lt8713sx *lt8713sx) +{ + u32 flash_status = 0; + + regmap_write(lt8713sx->regmap, 0xe103, 0x3f); + regmap_write(lt8713sx->regmap, 0xe103, 0xff); + + regmap_write(lt8713sx->regmap, 0xe05e, 0x40); + regmap_write(lt8713sx->regmap, 0xe056, 0x05); /* opcode=read status register */ + regmap_write(lt8713sx->regmap, 0xe055, 0x25); + regmap_write(lt8713sx->regmap, 0xe055, 0x01); + regmap_write(lt8713sx->regmap, 0xe058, 0x21); + + regmap_read(lt8713sx->regmap, 0xe05f, &flash_status); + dev_dbg(lt8713sx->dev, "flash_status:%x\n", flash_status); + + return flash_status; +} + +static void lt8713sx_block_erase(struct lt8713sx *lt8713sx) +{ + u32 i = 0; + u8 flash_status = 0; + u8 blocknum = 0x00; + u32 flashaddr = 0x00; + + for (blocknum = 0; blocknum < 8; blocknum++) { + flashaddr = blocknum * SZ_32K; + regmap_write(lt8713sx->regmap, 0xe0ee, 0x01); + regmap_write(lt8713sx->regmap, 0xe05a, 0x04); + regmap_write(lt8713sx->regmap, 0xe05a, 0x00); + regmap_write(lt8713sx->regmap, 0xe05b, flashaddr >> 16); + regmap_write(lt8713sx->regmap, 0xe05c, flashaddr >> 8); + regmap_write(lt8713sx->regmap, 0xe05d, flashaddr); + regmap_write(lt8713sx->regmap, 0xe05a, 0x01); + regmap_write(lt8713sx->regmap, 0xe05a, 0x00); + msleep(100); + i = 0; + while (1) { + flash_status = lt8713sx_read_flash_status(lt8713sx); + if ((flash_status & 0x01) == 0) + break; + + if (i > 50) + break; + + i++; + msleep(50); + } + } + dev_dbg(lt8713sx->dev, "erase flash done.\n"); +} + +static void lt8713sx_load_main_fw_to_sram(struct lt8713sx *lt8713sx) +{ + regmap_write(lt8713sx->regmap, 0xe0ee, 0x01); + regmap_write(lt8713sx->regmap, 0xe068, 0x00); + regmap_write(lt8713sx->regmap, 0xe069, 0x00); + regmap_write(lt8713sx->regmap, 0xe06a, 0x00); + regmap_write(lt8713sx->regmap, 0xe065, 0x00); + regmap_write(lt8713sx->regmap, 0xe066, 0xff); + regmap_write(lt8713sx->regmap, 0xe067, 0xff); + regmap_write(lt8713sx->regmap, 0xe06b, 0x00); + regmap_write(lt8713sx->regmap, 0xe06c, 0x00); + regmap_write(lt8713sx->regmap, 0xe060, 0x01); + msleep(200); + regmap_write(lt8713sx->regmap, 0xe060, 0x00); +} + +static void lt8713sx_load_bank_fw_to_sram(struct lt8713sx *lt8713sx, u64 addr) +{ + regmap_write(lt8713sx->regmap, 0xe0ee, 0x01); + regmap_write(lt8713sx->regmap, 0xe068, ((addr & 0xff0000) >> 16)); + regmap_write(lt8713sx->regmap, 0xe069, ((addr & 0x00ff00) >> 8)); + regmap_write(lt8713sx->regmap, 0xe06a, (addr & 0x0000ff)); + regmap_write(lt8713sx->regmap, 0xe065, 0x00); + regmap_write(lt8713sx->regmap, 0xe066, 0x30); + regmap_write(lt8713sx->regmap, 0xe067, 0x00); + regmap_write(lt8713sx->regmap, 0xe06b, 0x00); + regmap_write(lt8713sx->regmap, 0xe06c, 0x00); + regmap_write(lt8713sx->regmap, 0xe060, 0x01); + msleep(50); + regmap_write(lt8713sx->regmap, 0xe060, 0x00); +} + +static int lt8713sx_write_data(struct lt8713sx *lt8713sx, const u8 *data, u64 filesize) +{ + int page = 0, num = 0, i = 0, val; + + page = (filesize % LT8713SX_PAGE_SIZE) ? + ((filesize / LT8713SX_PAGE_SIZE) + 1) : (filesize / LT8713SX_PAGE_SIZE); + + dev_dbg(lt8713sx->dev, + "Writing to Sram=%u pages, total size = %llu bytes\n", page, filesize); + + for (num = 0; num < page; num++) { + dev_dbg(lt8713sx->dev, "page[%d]\n", num); + lt8713sx_i2c_to_sram(lt8713sx); + + for (i = 0; i < LT8713SX_PAGE_SIZE; i++) { + if ((num * LT8713SX_PAGE_SIZE + i) < filesize) + val = *(data + (num * LT8713SX_PAGE_SIZE + i)); + else + val = 0xff; + regmap_write(lt8713sx->regmap, 0xe059, val); + } + + lt8713sx_wren(lt8713sx); + lt8713sx_sram_to_flash(lt8713sx); + } + + lt8713sx_wrdi(lt8713sx); + lt8713sx_disable_sram_write(lt8713sx); + + return 0; +} + +static void lt8713sx_main_upgrade_result(struct lt8713sx *lt8713sx) +{ + u32 main_crc_result; + + regmap_read(lt8713sx->regmap, 0xe023, &main_crc_result); + + dev_dbg(lt8713sx->dev, "Main CRC HW: 0x%02X\n", main_crc_result); + dev_dbg(lt8713sx->dev, "Main CRC FW: 0x%02X\n", lt8713sx->main_crc_value); + + if (main_crc_result == lt8713sx->main_crc_value) + dev_dbg(lt8713sx->dev, "Main Firmware Upgrade Success.\n"); + else + dev_err(lt8713sx->dev, "Main Firmware Upgrade Failed.\n"); +} + +static void lt8713sx_bank_upgrade_result(struct lt8713sx *lt8713sx, u8 banknum) +{ + u32 bank_crc_result; + + regmap_read(lt8713sx->regmap, 0xe023, &bank_crc_result); + + dev_dbg(lt8713sx->dev, "Bank %d CRC Result: 0x%02X\n", banknum, bank_crc_result); + + if (bank_crc_result == lt8713sx->bank_crc_value[banknum]) + dev_dbg(lt8713sx->dev, "Bank %d Firmware Upgrade Success.\n", banknum); + else + dev_err(lt8713sx->dev, "Bank %d Firmware Upgrade Failed.\n", banknum); +} + +static void lt8713sx_bank_result_check(struct lt8713sx *lt8713sx) +{ + int i; + u64 addr = 0x010000; + + for (i = 0; i < lt8713sx->bank_num; i++) { + lt8713sx_load_bank_fw_to_sram(lt8713sx, addr); + lt8713sx_bank_upgrade_result(lt8713sx, i); + addr += 0x3000; + } +} + +static int lt8713sx_firmware_upgrade(struct lt8713sx *lt8713sx) +{ + int ret; + + lt8713sx_config_parameters(lt8713sx); + + lt8713sx_block_erase(lt8713sx); + + if (lt8713sx->fw->size < SZ_64K) { + ret = lt8713sx_write_data(lt8713sx, lt8713sx->fw_buffer, SZ_64K); + if (ret < 0) { + dev_err(lt8713sx->dev, "Failed to write firmware data: %d\n", ret); + return ret; + } + } else { + ret = lt8713sx_write_data(lt8713sx, lt8713sx->fw_buffer, lt8713sx->fw->size); + if (ret < 0) { + dev_err(lt8713sx->dev, "Failed to write firmware data: %d\n", ret); + return ret; + } + } + dev_dbg(lt8713sx->dev, "Write Data done.\n"); + + return 0; +} + +static int lt8713sx_firmware_update(struct lt8713sx *lt8713sx) +{ + int ret = 0; + + mutex_lock(<8713sx->ocm_lock); + lt8713sx_i2c_enable(lt8713sx); + + ret = lt8713sx_prepare_firmware_data(lt8713sx); + if (ret < 0) { + dev_err(lt8713sx->dev, "Failed to prepare firmware data: %d\n", ret); + goto error; + } + + ret = lt8713sx_firmware_upgrade(lt8713sx); + if (ret < 0) { + dev_err(lt8713sx->dev, "Upgrade failure.\n"); + goto error; + } else { + /* Validate CRC */ + lt8713sx_load_main_fw_to_sram(lt8713sx); + lt8713sx_main_upgrade_result(lt8713sx); + lt8713sx_wrdi(lt8713sx); + lt8713sx_fifo_reset(lt8713sx); + lt8713sx_bank_result_check(lt8713sx); + lt8713sx_wrdi(lt8713sx); + } + +error: + lt8713sx_i2c_disable(lt8713sx); + if (!ret) + lt8713sx_reset(lt8713sx); + + kvfree(lt8713sx->fw_buffer); + lt8713sx->fw_buffer = NULL; + + if (lt8713sx->fw) { + release_firmware(lt8713sx->fw); + lt8713sx->fw = NULL; + } + mutex_unlock(<8713sx->ocm_lock); + + return ret; +} + +static void lt8713sx_reset(struct lt8713sx *lt8713sx) +{ + dev_dbg(lt8713sx->dev, "reset bridge.\n"); + gpiod_set_value_cansleep(lt8713sx->reset_gpio, 1); + msleep(20); + + gpiod_set_value_cansleep(lt8713sx->reset_gpio, 0); + msleep(20); + + dev_dbg(lt8713sx->dev, "reset done.\n"); +} + +static int lt8713sx_regulator_enable(struct lt8713sx *lt8713sx) +{ + int ret; + + ret = devm_regulator_get_enable(lt8713sx->dev, "vdd"); + if (ret < 0) + return dev_err_probe(lt8713sx->dev, ret, "failed to enable vdd regulator\n"); + + usleep_range(1000, 10000); + + ret = devm_regulator_get_enable(lt8713sx->dev, "vcc"); + if (ret < 0) + return dev_err_probe(lt8713sx->dev, ret, "failed to enable vcc regulator\n"); + return 0; +} + +static int lt8713sx_bridge_attach(struct drm_bridge *bridge, + struct drm_encoder *encoder, + enum drm_bridge_attach_flags flags) +{ + struct lt8713sx *lt8713sx = container_of(bridge, struct lt8713sx, bridge); + int i, ret; + + for (i = 0; i < lt8713sx->num_outputs; i++) { + if (!lt8713sx->next_bridge[i]) + continue; + + ret = drm_bridge_attach(encoder, + lt8713sx->next_bridge[i], + bridge, flags); + if (ret) + return ret; + } + + return 0; +} + +static int lt8713sx_get_ports(struct lt8713sx *lt8713sx) +{ + struct device *dev = lt8713sx->dev; + struct device_node *port, *ports, *ep, *remote; + int i = 0; + u32 reg; + + ports = of_get_child_by_name(dev->of_node, "ports"); + if (!ports) + return -ENODEV; + + for_each_child_of_node(ports, port) { + if (of_property_read_u32(port, "reg", ®)) + continue; + + if (reg == 0) + continue; + + if (i >= ARRAY_SIZE(lt8713sx->next_bridge)) { + of_node_put(port); + break; + } + + ep = of_graph_get_next_endpoint(port, NULL); + if (!ep) + continue; + + remote = of_graph_get_remote_port_parent(ep); + of_node_put(ep); + + if (!remote) + continue; + + lt8713sx->next_bridge[i] = of_drm_find_bridge(remote); + of_node_put(remote); + if (lt8713sx->next_bridge[i]) + i++; + } + lt8713sx->num_outputs = i; + dev_dbg(dev, "Enabled %d output ports", i); + + of_node_put(ports); + return 0; +}; + +static int lt8713sx_gpio_init(struct lt8713sx *lt8713sx) +{ + struct device *dev = lt8713sx->dev; + + lt8713sx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(lt8713sx->reset_gpio)) + return dev_err_probe(dev, PTR_ERR(lt8713sx->reset_gpio), + "failed to acquire reset gpio\n"); + + /* power enable gpio */ + lt8713sx->enable_gpio = devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_HIGH); + if (IS_ERR(lt8713sx->enable_gpio)) + return dev_err_probe(dev, PTR_ERR(lt8713sx->enable_gpio), + "failed to acquire enable gpio\n"); + return 0; +} + +static ssize_t lt8713sx_firmware_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct lt8713sx *lt8713sx = dev_get_drvdata(dev); + int ret; + + ret = lt8713sx_firmware_update(lt8713sx); + if (ret < 0) + return ret; + return len; +} + +static DEVICE_ATTR_WO(lt8713sx_firmware); + +static struct attribute *lt8713sx_attrs[] = { + &dev_attr_lt8713sx_firmware.attr, + NULL, +}; + +static const struct attribute_group lt8713sx_attr_group = { + .attrs = lt8713sx_attrs, +}; + +static const struct attribute_group *lt8713sx_attr_groups[] = { + <8713sx_attr_group, + NULL, +}; + +static const struct drm_bridge_funcs lt8713sx_bridge_funcs = { + .attach = lt8713sx_bridge_attach, +}; + +static int lt8713sx_probe(struct i2c_client *client) +{ + struct lt8713sx *lt8713sx; + struct device *dev = &client->dev; + int ret; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) + return dev_err_probe(dev, -ENODEV, "device doesn't support I2C\n"); + + lt8713sx = devm_drm_bridge_alloc(dev, struct lt8713sx, bridge, <8713sx_bridge_funcs); + if (IS_ERR(lt8713sx)) + return PTR_ERR(lt8713sx); + + lt8713sx->dev = dev; + lt8713sx->client = client; + i2c_set_clientdata(client, lt8713sx); + + ret = devm_mutex_init(lt8713sx->dev, <8713sx->ocm_lock); + if (ret) + return ret; + + lt8713sx->regmap = devm_regmap_init_i2c(client, <8713sx_regmap_config); + if (IS_ERR(lt8713sx->regmap)) + return dev_err_probe(dev, PTR_ERR(lt8713sx->regmap), "regmap i2c init failed\n"); + + ret = lt8713sx_get_ports(lt8713sx); + if (ret < 0) + return ret; + + ret = lt8713sx_gpio_init(lt8713sx); + if (ret < 0) + return ret; + + ret = lt8713sx_regulator_enable(lt8713sx); + if (ret) + return ret; + + lt8713sx_reset(lt8713sx); + + lt8713sx->bridge.funcs = <8713sx_bridge_funcs; + lt8713sx->bridge.of_node = dev->of_node; + lt8713sx->bridge.type = DRM_MODE_CONNECTOR_DisplayPort; + drm_bridge_add(<8713sx->bridge); + + crc8_populate_msb(lt8713sx_crc_table, 0x31); + + return 0; +} + +static void lt8713sx_remove(struct i2c_client *client) +{ + struct lt8713sx *lt8713sx = i2c_get_clientdata(client); + + drm_bridge_remove(<8713sx->bridge); +} + +static struct i2c_device_id lt8713sx_id[] = { + { "lontium,lt8713sx", 0 }, + { /* sentinel */ } +}; + +static const struct of_device_id lt8713sx_match_table[] = { + { .compatible = "lontium,lt8713sx" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, lt8713sx_match_table); + +static struct i2c_driver lt8713sx_driver = { + .driver = { + .name = "lt8713sx", + .of_match_table = lt8713sx_match_table, + .dev_groups = lt8713sx_attr_groups, + }, + .probe = lt8713sx_probe, + .remove = lt8713sx_remove, + .id_table = lt8713sx_id, +}; + +module_i2c_driver(lt8713sx_driver); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("lt8713sx drm bridge driver"); +MODULE_AUTHOR("Tony "); +MODULE_FIRMWARE(FW_FILE); From 800766b7c5882dc1b39d25072f5b9a281790d135 Mon Sep 17 00:00:00 2001 From: Vishnu Saini Date: Thu, 22 Jan 2026 15:37:30 +0530 Subject: [PATCH 2211/2333] FROMLIST: arm64: dts: qcom: monaco: add lt8713sx bridge with displayport Monaco-evk has LT8713sx which act as DP to 3 DP output converter. Edp PHY from monaco soc is connected to lt8713sx as input and output of lt8713sx is connected to 3 mini DP ports. Two ports are available in mainboard and one port is available on Mezz board. lt8713sx is connected to soc over i2c0 and with reset gpio connected to pin6 of ioexpander5. Enable the edp nodes from monaco and enable lontium lt8713sx bridge node. Link: https://lore.kernel.org/all/20251228-lt8713sx-bridge-linux-for-next-v3-1-3f77ad84d7d1@oss.qualcomm.com/ Co-developed-by: Prahlad Valluru Signed-off-by: Prahlad Valluru Signed-off-by: Vishnu Saini --- arch/arm64/boot/dts/qcom/monaco-evk.dts | 89 +++++++++++++++++++++++++ arch/arm64/boot/dts/qcom/qcs8300.dtsi | 6 ++ 2 files changed, 95 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/monaco-evk.dts b/arch/arm64/boot/dts/qcom/monaco-evk.dts index 0138e295baa82..a734292802b40 100644 --- a/arch/arm64/boot/dts/qcom/monaco-evk.dts +++ b/arch/arm64/boot/dts/qcom/monaco-evk.dts @@ -28,6 +28,30 @@ stdout-path = "serial0:115200n8"; }; + dp-connector0 { + compatible = "dp-connector"; + label = "DP"; + type = "mini"; + + port { + dp0_connector_in: endpoint { + remote-endpoint = <<8713sx_dp0_out>; + }; + }; + }; + + dp-connector1 { + compatible = "dp-connector"; + label = "DP"; + type = "mini"; + + port { + dp1_connector_in: endpoint { + remote-endpoint = <<8713sx_dp1_out>; + }; + }; + }; + dmic: audio-codec-0 { compatible = "dmic-codec"; #sound-dai-cells = <0>; @@ -399,6 +423,42 @@ firmware-name = "qcom/qcs8300/a623_zap.mbn"; }; +&i2c0 { + status = "okay"; + + bridge@4f { + compatible = "lontium,lt8713sx"; + reg = <0x4f>; + reset-gpios = <&expander5 6 GPIO_ACTIVE_LOW>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + lt8713sx_dp_in: endpoint { + remote-endpoint = <&mdss_dp0_out>; + }; + }; + + port@1 { + reg = <1>; + lt8713sx_dp0_out: endpoint { + remote-endpoint = <&dp0_connector_in>; + }; + }; + + port@2 { + reg = <2>; + lt8713sx_dp1_out: endpoint { + remote-endpoint = <&dp1_connector_in>; + }; + }; + }; + }; +}; + &i2c1 { pinctrl-0 = <&qup_i2c1_default>; pinctrl-names = "default"; @@ -492,6 +552,30 @@ status = "okay"; }; +&mdss { + status = "okay"; +}; + +&mdss_dp0 { + pinctrl-0 = <&dp_hot_plug_det>; + pinctrl-names = "default"; + + status = "okay"; +}; + +&mdss_dp0_out { + data-lanes = <0 1 2 3>; + link-frequencies = /bits/ 64 <1620000000 2700000000 5400000000 8100000000>; + remote-endpoint = <<8713sx_dp_in>; +}; + +&mdss_dp0_phy { + vdda-phy-supply = <&vreg_l5a>; + vdda-pll-supply = <&vreg_l4a>; + + status = "okay"; +}; + &psci { reboot-mode { mode-bootloader = <0x10001 0x2>; @@ -499,6 +583,11 @@ }; }; +&qup_i2c0_data_clk { + drive-strength = <2>; + bias-pull-up; +}; + &qupv3_id_0 { firmware-name = "qcom/qcs8300/qupv3fw.elf"; status = "okay"; diff --git a/arch/arm64/boot/dts/qcom/qcs8300.dtsi b/arch/arm64/boot/dts/qcom/qcs8300.dtsi index 04d1fea53ea1e..2783b3525e43c 100644 --- a/arch/arm64/boot/dts/qcom/qcs8300.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs8300.dtsi @@ -5995,6 +5995,12 @@ }; }; + dp_hot_plug_det: dp-hot-plug-det-state { + pins = "gpio94"; + function = "edp0_hot"; + bias-disable; + }; + hs0_mi2s_active: hs0-mi2s-active-state { pins = "gpio106", "gpio107", "gpio108", "gpio109"; function = "hs0_mi2s"; From 1555df1f96f338fc1a8c47bd2367d557956b81ff Mon Sep 17 00:00:00 2001 From: Vishnu Saini Date: Thu, 22 Jan 2026 15:32:16 +0530 Subject: [PATCH 2212/2333] FROMLIST: arm64: defconfig: Enable Lontium LT8713sx driver Lontium LT8713sx DP bridge hub can be found on a Qualcomm Monaco EVK board for converting 1 DP to 3 DP output. Link: https://lore.kernel.org/all/20251228-lt8713sx-bridge-linux-for-next-v3-2-3f77ad84d7d1@oss.qualcomm.com/ Signed-off-by: Vishnu Saini --- arch/arm64/configs/defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig index 15a7635ce8ac1..3ecc20978dc1d 100644 --- a/arch/arm64/configs/defconfig +++ b/arch/arm64/configs/defconfig @@ -952,6 +952,7 @@ CONFIG_DRM_PANEL_VISIONOX_VTDR6130=m CONFIG_DRM_DISPLAY_CONNECTOR=m CONFIG_DRM_FSL_LDB=m CONFIG_DRM_ITE_IT6263=m +CONFIG_DRM_LONTIUM_LT8713SX=m CONFIG_DRM_LONTIUM_LT8912B=m CONFIG_DRM_LONTIUM_LT9611=m CONFIG_DRM_LONTIUM_LT9611UXC=m From 8a8d5bb655a77b34c2c45f34ce8b6190c84597e6 Mon Sep 17 00:00:00 2001 From: Mukesh Ojha Date: Fri, 6 Feb 2026 17:31:17 +0530 Subject: [PATCH 2213/2333] Revert "FROMLIST: remoteproc: qcom: pas: Enable Secure PAS support with IOMMU managed by Linux" This reverts commit 464fb78ea02cf616d58464b045264e52c5f756cb as latest versionv v10 of commit is available Signed-off-by: Mukesh Ojha --- drivers/remoteproc/qcom_q6v5_pas.c | 48 ++++-------------------------- 1 file changed, 5 insertions(+), 43 deletions(-) diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c index 2df3b06f8157f..186a90d6c83a8 100644 --- a/drivers/remoteproc/qcom_q6v5_pas.c +++ b/drivers/remoteproc/qcom_q6v5_pas.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include @@ -257,22 +256,6 @@ static int qcom_pas_load(struct rproc *rproc, const struct firmware *fw) return ret; } -static void qcom_pas_unmap_carveout(struct rproc *rproc, phys_addr_t mem_phys, size_t size) -{ - if (rproc->has_iommu) - iommu_unmap(rproc->domain, mem_phys, size); -} - -static int qcom_pas_map_carveout(struct rproc *rproc, phys_addr_t mem_phys, size_t size) -{ - int ret = 0; - - if (rproc->has_iommu) - ret = iommu_map(rproc->domain, mem_phys, mem_phys, size, - IOMMU_READ | IOMMU_WRITE, GFP_KERNEL); - return ret; -} - static int qcom_pas_start(struct rproc *rproc) { struct qcom_pas *pas = rproc->priv; @@ -307,15 +290,11 @@ static int qcom_pas_start(struct rproc *rproc) } if (pas->dtb_pas_id) { - ret = qcom_pas_map_carveout(rproc, pas->dtb_mem_phys, pas->dtb_mem_size); - if (ret) - goto disable_px_supply; - - ret = qcom_scm_pas_prepare_and_auth_reset(pas->dtb_pas_ctx); + ret = qcom_scm_pas_auth_and_reset(pas->dtb_pas_id); if (ret) { dev_err(pas->dev, "failed to authenticate dtb image and release reset\n"); - goto unmap_dtb_carveout; + goto disable_px_supply; } } @@ -326,22 +305,18 @@ static int qcom_pas_start(struct rproc *rproc) qcom_pil_info_store(pas->info_name, pas->mem_phys, pas->mem_size); - ret = qcom_pas_map_carveout(rproc, pas->mem_phys, pas->mem_size); - if (ret) - goto release_pas_metadata; - - ret = qcom_scm_pas_prepare_and_auth_reset(pas->pas_ctx); + ret = qcom_scm_pas_auth_and_reset(pas->pas_id); if (ret) { dev_err(pas->dev, "failed to authenticate image and release reset\n"); - goto unmap_carveout; + goto release_pas_metadata; } ret = qcom_q6v5_wait_for_start(&pas->q6v5, msecs_to_jiffies(5000)); if (ret == -ETIMEDOUT) { dev_err(pas->dev, "start timed out\n"); qcom_scm_pas_shutdown(pas->pas_id); - goto unmap_carveout; + goto release_pas_metadata; } qcom_scm_pas_metadata_release(pas->pas_ctx); @@ -353,16 +328,10 @@ static int qcom_pas_start(struct rproc *rproc) return 0; -unmap_carveout: - qcom_pas_unmap_carveout(rproc, pas->mem_phys, pas->mem_size); release_pas_metadata: qcom_scm_pas_metadata_release(pas->pas_ctx); if (pas->dtb_pas_id) qcom_scm_pas_metadata_release(pas->dtb_pas_ctx); - -unmap_dtb_carveout: - if (pas->dtb_pas_id) - qcom_pas_unmap_carveout(rproc, pas->dtb_mem_phys, pas->dtb_mem_size); disable_px_supply: if (pas->px_supply) regulator_disable(pas->px_supply); @@ -418,12 +387,8 @@ static int qcom_pas_stop(struct rproc *rproc) ret = qcom_scm_pas_shutdown(pas->dtb_pas_id); if (ret) dev_err(pas->dev, "failed to shutdown dtb: %d\n", ret); - - qcom_pas_unmap_carveout(rproc, pas->dtb_mem_phys, pas->dtb_mem_size); } - qcom_pas_unmap_carveout(rproc, pas->mem_phys, pas->mem_size); - handover = qcom_q6v5_unprepare(&pas->q6v5); if (handover) qcom_pas_handover(&pas->q6v5); @@ -793,7 +758,6 @@ static int qcom_pas_probe(struct platform_device *pdev) return -ENOMEM; } - rproc->has_iommu = of_property_present(pdev->dev.of_node, "iommus"); rproc->auto_boot = desc->auto_boot; rproc_coredump_set_elf_info(rproc, ELFCLASS32, EM_NONE); @@ -873,8 +837,6 @@ static int qcom_pas_probe(struct platform_device *pdev) goto remove_ssr_sysmon; } - pas->pas_ctx->has_iommu = rproc->has_iommu; - pas->dtb_pas_ctx->has_iommu = rproc->has_iommu; ret = rproc_add(rproc); if (ret) goto remove_ssr_sysmon; From a0cc4475286b539633bede0cefaeb74c193aceb4 Mon Sep 17 00:00:00 2001 From: Mukesh Ojha Date: Fri, 6 Feb 2026 17:31:29 +0530 Subject: [PATCH 2214/2333] Revert "FROMLIST: remoteproc: pas: Extend parse_fw callback to fetch resources via SMC call" This reverts commit a570d5bcf588bb98a374938246707a445617a360. as latest version of the commit is available. Signed-off-by: Mukesh Ojha --- drivers/remoteproc/qcom_q6v5_pas.c | 60 +----------------------------- 1 file changed, 2 insertions(+), 58 deletions(-) diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c index 186a90d6c83a8..9feee2cb18835 100644 --- a/drivers/remoteproc/qcom_q6v5_pas.c +++ b/drivers/remoteproc/qcom_q6v5_pas.c @@ -34,7 +34,6 @@ #define QCOM_PAS_DECRYPT_SHUTDOWN_DELAY_MS 100 #define MAX_ASSIGN_COUNT 3 -#define MAX_RSCTABLE_SIZE SZ_16K struct qcom_pas_data { int crash_reason_smem; @@ -414,61 +413,6 @@ static void *qcom_pas_da_to_va(struct rproc *rproc, u64 da, size_t len, bool *is return pas->mem_region + offset; } -static int qcom_pas_parse_firmware(struct rproc *rproc, const struct firmware *fw) -{ - size_t output_rt_size = MAX_RSCTABLE_SIZE; - struct qcom_pas *pas = rproc->priv; - struct resource_table *table = NULL; - void *output_rt; - size_t table_sz; - int ret; - - ret = qcom_register_dump_segments(rproc, fw); - if (ret) { - dev_err(pas->dev, "Error in registering dump segments\n"); - return ret; - } - - if (!rproc->has_iommu) - return 0; - - ret = rproc_elf_load_rsc_table(rproc, fw); - if (ret) - dev_dbg(&rproc->dev, "Failed to load resource table from firmware\n"); - - table = rproc->table_ptr; - table_sz = rproc->table_sz; - - /* - * The resources consumed by Qualcomm remote processors fall into two categories: - * static (such as the memory carveouts for the rproc firmware) and dynamic (like - * shared memory pools). Both are managed by a Qualcomm hypervisor (such as QHEE - * or Gunyah), if one is present. Otherwise, a resource table must be retrieved - * via an SCM call. That table will list all dynamic resources (if any) and possibly - * the static ones. The static resources may also come from a resource table embedded - * in the rproc firmware instead. - * - * Here, we call rproc_elf_load_rsc_table() to check firmware binary has resources - * or not and if it is not having then we pass NULL and zero as input resource - * table pointer and size respectively to the argument of qcom_scm_pas_get_rsc_table() - * and this is even true for Qualcomm remote processor who does follow remoteproc - * framework. - */ - ret = qcom_scm_pas_get_rsc_table(pas->pas_ctx, table, table_sz, &output_rt, - &output_rt_size); - if (ret) { - dev_err(pas->dev, "Error in getting resource table: %d\n", ret); - return ret; - } - - kfree(rproc->cached_table); - rproc->cached_table = output_rt; - rproc->table_ptr = rproc->cached_table; - rproc->table_sz = output_rt_size; - - return ret; -} - static unsigned long qcom_pas_panic(struct rproc *rproc) { struct qcom_pas *pas = rproc->priv; @@ -481,7 +425,7 @@ static const struct rproc_ops qcom_pas_ops = { .start = qcom_pas_start, .stop = qcom_pas_stop, .da_to_va = qcom_pas_da_to_va, - .parse_fw = qcom_pas_parse_firmware, + .parse_fw = qcom_register_dump_segments, .load = qcom_pas_load, .panic = qcom_pas_panic, }; @@ -491,7 +435,7 @@ static const struct rproc_ops qcom_pas_minidump_ops = { .start = qcom_pas_start, .stop = qcom_pas_stop, .da_to_va = qcom_pas_da_to_va, - .parse_fw = qcom_pas_parse_firmware, + .parse_fw = qcom_register_dump_segments, .load = qcom_pas_load, .panic = qcom_pas_panic, .coredump = qcom_pas_minidump, From b818fdd4d9c7092c9bad19ddbde67ad3d60af982 Mon Sep 17 00:00:00 2001 From: Mukesh Ojha Date: Fri, 6 Feb 2026 17:31:55 +0530 Subject: [PATCH 2215/2333] Revert "FROMLIST: firmware: qcom_scm: Add qcom_scm_pas_get_rsc_table() to get resource table" This reverts commit 1ec84858aab15f248caf7e6a2a843926c400e554. as latest version v10 of the commit is available. Signed-off-by: Mukesh Ojha --- drivers/firmware/qcom/qcom_scm.c | 158 ------------------------- drivers/firmware/qcom/qcom_scm.h | 1 - include/linux/firmware/qcom/qcom_scm.h | 4 - 3 files changed, 163 deletions(-) diff --git a/drivers/firmware/qcom/qcom_scm.c b/drivers/firmware/qcom/qcom_scm.c index 83dad6e4c5386..0a3c40a1afc10 100644 --- a/drivers/firmware/qcom/qcom_scm.c +++ b/drivers/firmware/qcom/qcom_scm.c @@ -27,7 +27,6 @@ #include #include #include -#include #include #include @@ -112,10 +111,6 @@ enum qcom_scm_qseecom_tz_cmd_info { QSEECOM_TZ_CMD_INFO_VERSION = 3, }; -enum qcom_scm_rsctable_resp_type { - RSCTABLE_BUFFER_NOT_SUFFICIENT = 20, -}; - #define QSEECOM_MAX_APP_NAME_SIZE 64 #define SHMBRIDGE_RESULT_NOTSUPP 4 @@ -771,159 +766,6 @@ int qcom_scm_pas_mem_setup(u32 pas_id, phys_addr_t addr, phys_addr_t size) } EXPORT_SYMBOL_GPL(qcom_scm_pas_mem_setup); -static int __qcom_scm_pas_get_rsc_table(u32 pas_id, void *input_rt, size_t input_rt_size, - void **output_rt, size_t *output_rt_size) -{ - struct qcom_scm_desc desc = { - .svc = QCOM_SCM_SVC_PIL, - .cmd = QCOM_SCM_PIL_PAS_GET_RSCTABLE, - .arginfo = QCOM_SCM_ARGS(5, QCOM_SCM_VAL, QCOM_SCM_RO, QCOM_SCM_VAL, - QCOM_SCM_RW, QCOM_SCM_VAL), - .args[0] = pas_id, - .owner = ARM_SMCCC_OWNER_SIP, - }; - void *input_rt_buf, *output_rt_buf; - struct resource_table *rsc; - struct qcom_scm_res res; - int ret; - - ret = qcom_scm_clk_enable(); - if (ret) - return ret; - - ret = qcom_scm_bw_enable(); - if (ret) - goto disable_clk; - - /* - * TrustZone can not accept buffer as NULL value as argument Hence, - * we need to pass a input buffer indicating that subsystem firmware - * does not have resource table by filling resource table structure. - */ - if (!input_rt) - input_rt_size = sizeof(*rsc); - - input_rt_buf = qcom_tzmem_alloc(__scm->mempool, input_rt_size, GFP_KERNEL); - if (!input_rt_buf) { - ret = -ENOMEM; - goto disable_scm_bw; - } - - if (!input_rt) { - rsc = input_rt_buf; - rsc->num = 0; - } else { - memcpy(input_rt_buf, input_rt, input_rt_size); - } - - output_rt_buf = qcom_tzmem_alloc(__scm->mempool, *output_rt_size, GFP_KERNEL); - if (!output_rt_buf) { - ret = -ENOMEM; - goto free_input_rt_buf; - } - - desc.args[1] = qcom_tzmem_to_phys(input_rt_buf); - desc.args[2] = input_rt_size; - desc.args[3] = qcom_tzmem_to_phys(output_rt_buf); - desc.args[4] = *output_rt_size; - - /* - * Whether SMC fail or pass, res.result[2] will hold actual resource table - * size. - * - * if passed 'output_rt_size' buffer size is not sufficient to hold the - * resource table TrustZone sends, response code in res.result[1] as - * RSCTABLE_BUFFER_NOT_SUFFICIENT so that caller can retry this SMC call with - * output_rt buffer with res.result[2] size. - */ - ret = qcom_scm_call(__scm->dev, &desc, &res); - *output_rt_size = res.result[2]; - if (!ret) - memcpy(*output_rt, output_rt_buf, *output_rt_size); - - if (ret && res.result[1] == RSCTABLE_BUFFER_NOT_SUFFICIENT) - ret = -EAGAIN; - - qcom_tzmem_free(output_rt_buf); - -free_input_rt_buf: - qcom_tzmem_free(input_rt_buf); - -disable_scm_bw: - qcom_scm_bw_disable(); - -disable_clk: - qcom_scm_clk_disable(); - - return ret ? : res.result[0]; -} - -/** - * qcom_scm_pas_get_rsc_table() - Retrieve the resource table in passed output buffer - * for a given peripheral. - * - * Qualcomm remote processor may rely on both static and dynamic resources for - * its functionality. Static resources typically refer to memory-mapped addresses - * required by the subsystem and are often embedded within the firmware binary - * and dynamic resources, such as shared memory in DDR etc., are determined at - * runtime during the boot process. - * - * On Qualcomm Technologies devices, it's possible that static resources are not - * embedded in the firmware binary and instead are provided by TrustZone However, - * dynamic resources are always expected to come from TrustZone. This indicates - * that for Qualcomm devices, all resources (static and dynamic) will be provided - * by TrustZone via the SMC call. - * - * If the remote processor firmware binary does contain static resources, they - * should be passed in input_rt. These will be forwarded to TrustZone for - * authentication. TrustZone will then append the dynamic resources and return - * the complete resource table in output_rt. - * - * If the remote processor firmware binary does not include a resource table, - * the caller of this function should set input_rt as NULL and input_rt_size - * as zero respectively. - * - * More about documentation on resource table data structures can be found in - * include/linux/remoteproc.h - * - * @ctx: PAS context - * @pas_id: peripheral authentication service id - * @input_rt: resource table buffer which is present in firmware binary - * @input_rt_size: size of the resource table present in firmware binary - * @output_rt: buffer to which the both static and dynamic resources will - * be returned. - * @output_rt_size: TrustZone expects caller should pass worst case size for - * the output_rt. - * - * Return: 0 on success and nonzero on failure. - * - * Upon successful return, output_rt will have the resource table and output_rt_size - * will have actual resource table size, - */ -int qcom_scm_pas_get_rsc_table(struct qcom_scm_pas_context *ctx, void *input_rt, - size_t input_rt_size, void **output_rt, - size_t *output_rt_size) -{ - unsigned int retry_num = 5; - int ret; - - do { - *output_rt = kzalloc(*output_rt_size, GFP_KERNEL); - if (!*output_rt) - return -ENOMEM; - - ret = __qcom_scm_pas_get_rsc_table(ctx->pas_id, input_rt, - input_rt_size, output_rt, - output_rt_size); - if (ret) - kfree(*output_rt); - - } while (ret == -EAGAIN && --retry_num); - - return ret; -} -EXPORT_SYMBOL_GPL(qcom_scm_pas_get_rsc_table); - /** * qcom_scm_pas_auth_and_reset() - Authenticate the given peripheral firmware * and reset the remote processor diff --git a/drivers/firmware/qcom/qcom_scm.h b/drivers/firmware/qcom/qcom_scm.h index de7e8ce6a7b21..48f2cb83228d6 100644 --- a/drivers/firmware/qcom/qcom_scm.h +++ b/drivers/firmware/qcom/qcom_scm.h @@ -105,7 +105,6 @@ int qcom_scm_shm_bridge_enable(struct device *scm_dev); #define QCOM_SCM_PIL_PAS_SHUTDOWN 0x06 #define QCOM_SCM_PIL_PAS_IS_SUPPORTED 0x07 #define QCOM_SCM_PIL_PAS_MSS_RESET 0x0a -#define QCOM_SCM_PIL_PAS_GET_RSCTABLE 0x21 #define QCOM_SCM_SVC_IO 0x05 #define QCOM_SCM_IO_READ 0x01 diff --git a/include/linux/firmware/qcom/qcom_scm.h b/include/linux/firmware/qcom/qcom_scm.h index 9a027deb6e145..3093d3af68511 100644 --- a/include/linux/firmware/qcom/qcom_scm.h +++ b/include/linux/firmware/qcom/qcom_scm.h @@ -99,10 +99,6 @@ int qcom_scm_pas_mem_setup(u32 pas_id, phys_addr_t addr, phys_addr_t size); int qcom_scm_pas_auth_and_reset(u32 pas_id); int qcom_scm_pas_shutdown(u32 pas_id); bool qcom_scm_pas_supported(u32 pas_id); -int qcom_scm_pas_get_rsc_table(struct qcom_scm_pas_context *ctx, void *input_rt, - size_t input_rt_size, void **output_rt, - size_t *output_rt_size); - int qcom_scm_pas_prepare_and_auth_reset(struct qcom_scm_pas_context *ctx); int qcom_scm_io_readl(phys_addr_t addr, unsigned int *val); From 357a3153436e9cc6b4dff08f50a9ba83af126cc8 Mon Sep 17 00:00:00 2001 From: Mukesh Ojha Date: Fri, 6 Feb 2026 17:32:24 +0530 Subject: [PATCH 2216/2333] Revert "FROMLIST: firmware: qcom_scm: Add SHM bridge handling for PAS when running without QHEE" This reverts commit 81c76282fd6f056f448f42c1ae7423fedebc5897. as latest version v10 of the commit is available. Signed-off-by: Mukesh Ojha --- drivers/firmware/qcom/qcom_scm.c | 32 +------------------------------- 1 file changed, 1 insertion(+), 31 deletions(-) diff --git a/drivers/firmware/qcom/qcom_scm.c b/drivers/firmware/qcom/qcom_scm.c index 0a3c40a1afc10..a3627aec40423 100644 --- a/drivers/firmware/qcom/qcom_scm.c +++ b/drivers/firmware/qcom/qcom_scm.c @@ -623,30 +623,6 @@ static int __qcom_scm_pas_init_image(u32 pas_id, dma_addr_t mdata_phys, return ret; } -static int qcom_scm_pas_prep_and_init_image(struct qcom_scm_pas_context *ctx, - const void *metadata, size_t size) -{ - struct qcom_scm_res res; - phys_addr_t mdata_phys; - void *mdata_buf; - int ret; - - mdata_buf = qcom_tzmem_alloc(__scm->mempool, size, GFP_KERNEL); - if (!mdata_buf) - return -ENOMEM; - - memcpy(mdata_buf, metadata, size); - mdata_phys = qcom_tzmem_to_phys(mdata_buf); - - ret = __qcom_scm_pas_init_image(ctx->pas_id, mdata_phys, &res); - if (ret < 0) - qcom_tzmem_free(mdata_buf); - else - ctx->ptr = mdata_buf; - - return ret ? : res.result[0]; -} - /** * qcom_scm_pas_init_image() - Initialize peripheral authentication service * state machine for a given peripheral, using the @@ -672,9 +648,6 @@ int qcom_scm_pas_init_image(u32 pas_id, const void *metadata, size_t size, void *mdata_buf; int ret; - if (ctx && ctx->has_iommu) - return qcom_scm_pas_prep_and_init_image(ctx, metadata, size); - /* * During the scm call memory protection will be enabled for the meta * data blob, so make sure it's physically contiguous, 4K aligned and @@ -716,10 +689,7 @@ void qcom_scm_pas_metadata_release(struct qcom_scm_pas_context *ctx) if (!ctx->ptr) return; - if (ctx->has_iommu) - qcom_tzmem_free(ctx->ptr); - else - dma_free_coherent(__scm->dev, ctx->size, ctx->ptr, ctx->phys); + dma_free_coherent(__scm->dev, ctx->size, ctx->ptr, ctx->phys); ctx->ptr = NULL; } From ab51875ae2a46905fd86daf3aa474ff879bb70bf Mon Sep 17 00:00:00 2001 From: Mukesh Ojha Date: Fri, 6 Feb 2026 17:32:58 +0530 Subject: [PATCH 2217/2333] Revert "FROMLIST: firmware: qcom_scm: Refactor qcom_scm_pas_init_image()" This reverts commit 10bdb189f779aee6be89e9962fe5a18fbcb9ad05. as latest version v10 of the commit is available. Signed-off-by: Mukesh Ojha --- drivers/firmware/qcom/qcom_scm.c | 58 ++++++++++++++------------------ 1 file changed, 25 insertions(+), 33 deletions(-) diff --git a/drivers/firmware/qcom/qcom_scm.c b/drivers/firmware/qcom/qcom_scm.c index a3627aec40423..c5b9110a54095 100644 --- a/drivers/firmware/qcom/qcom_scm.c +++ b/drivers/firmware/qcom/qcom_scm.c @@ -592,37 +592,6 @@ struct qcom_scm_pas_context *devm_qcom_scm_pas_context_init(struct device *dev, } EXPORT_SYMBOL_GPL(devm_qcom_scm_pas_context_init); -static int __qcom_scm_pas_init_image(u32 pas_id, dma_addr_t mdata_phys, - struct qcom_scm_res *res) -{ - struct qcom_scm_desc desc = { - .svc = QCOM_SCM_SVC_PIL, - .cmd = QCOM_SCM_PIL_PAS_INIT_IMAGE, - .arginfo = QCOM_SCM_ARGS(2, QCOM_SCM_VAL, QCOM_SCM_RW), - .args[0] = pas_id, - .owner = ARM_SMCCC_OWNER_SIP, - }; - int ret; - - ret = qcom_scm_clk_enable(); - if (ret) - return ret; - - ret = qcom_scm_bw_enable(); - if (ret) - goto disable_clk; - - desc.args[1] = mdata_phys; - - ret = qcom_scm_call(__scm->dev, &desc, res); - qcom_scm_bw_disable(); - -disable_clk: - qcom_scm_clk_disable(); - - return ret; -} - /** * qcom_scm_pas_init_image() - Initialize peripheral authentication service * state machine for a given peripheral, using the @@ -643,10 +612,17 @@ static int __qcom_scm_pas_init_image(u32 pas_id, dma_addr_t mdata_phys, int qcom_scm_pas_init_image(u32 pas_id, const void *metadata, size_t size, struct qcom_scm_pas_context *ctx) { - struct qcom_scm_res res; dma_addr_t mdata_phys; void *mdata_buf; int ret; + struct qcom_scm_desc desc = { + .svc = QCOM_SCM_SVC_PIL, + .cmd = QCOM_SCM_PIL_PAS_INIT_IMAGE, + .arginfo = QCOM_SCM_ARGS(2, QCOM_SCM_VAL, QCOM_SCM_RW), + .args[0] = pas_id, + .owner = ARM_SMCCC_OWNER_SIP, + }; + struct qcom_scm_res res; /* * During the scm call memory protection will be enabled for the meta @@ -667,7 +643,23 @@ int qcom_scm_pas_init_image(u32 pas_id, const void *metadata, size_t size, memcpy(mdata_buf, metadata, size); - ret = __qcom_scm_pas_init_image(pas_id, mdata_phys, &res); + ret = qcom_scm_clk_enable(); + if (ret) + goto out; + + ret = qcom_scm_bw_enable(); + if (ret) + goto disable_clk; + + desc.args[1] = mdata_phys; + + ret = qcom_scm_call(__scm->dev, &desc, &res); + qcom_scm_bw_disable(); + +disable_clk: + qcom_scm_clk_disable(); + +out: if (ret < 0 || !ctx) { dma_free_coherent(__scm->dev, size, mdata_buf, mdata_phys); } else if (ctx) { From 47ad75a790ca6b02d3af98f07a9c402d8eb34dbd Mon Sep 17 00:00:00 2001 From: Mukesh Ojha Date: Fri, 6 Feb 2026 17:33:05 +0530 Subject: [PATCH 2218/2333] Revert "FROMLIST: firmware: qcom_scm: Add a prep version of auth_and_reset function" This reverts commit 158f16f07d028da14b026d362a6e10c8e7156731. as latest version v10 of the commit is available. Signed-off-by: Mukesh Ojha --- drivers/firmware/qcom/qcom_scm.c | 48 -------------------------- include/linux/firmware/qcom/qcom_scm.h | 2 -- 2 files changed, 50 deletions(-) diff --git a/drivers/firmware/qcom/qcom_scm.c b/drivers/firmware/qcom/qcom_scm.c index c5b9110a54095..88ca24bbf85d8 100644 --- a/drivers/firmware/qcom/qcom_scm.c +++ b/drivers/firmware/qcom/qcom_scm.c @@ -765,54 +765,6 @@ int qcom_scm_pas_auth_and_reset(u32 pas_id) } EXPORT_SYMBOL_GPL(qcom_scm_pas_auth_and_reset); -/** - * qcom_scm_pas_prepare_and_auth_reset() - Prepare, authenticate, and reset the - * remote processor - * - * @ctx: Context saved during call to qcom_scm_pas_context_init() - * - * This function performs the necessary steps to prepare a PAS subsystem, - * authenticate it using the provided metadata, and initiate a reset sequence. - * - * It should be used when Linux is in control setting up the IOMMU hardware - * for remote subsystem during secure firmware loading processes. The preparation - * step sets up a shmbridge over the firmware memory before TrustZone accesses the - * firmware memory region for authentication. The authentication step verifies - * the integrity and authenticity of the firmware or configuration using secure - * metadata. Finally, the reset step ensures the subsystem starts in a clean and - * sane state. - * - * Return: 0 on success, negative errno on failure. - */ -int qcom_scm_pas_prepare_and_auth_reset(struct qcom_scm_pas_context *ctx) -{ - u64 handle; - int ret; - - if (!ctx->has_iommu) - return qcom_scm_pas_auth_and_reset(ctx->pas_id); - - /* - * When Linux running @ EL1, Gunyah hypervisor running @ EL2 traps the - * auth_and_reset call and create an shmbridge on the remote subsystem - * memory region and then invokes a call to TrustZone to authenticate. - * When Linux runs @ EL2 Linux must create the shmbridge itself and then - * subsequently call TrustZone for authenticate and reset. - */ - ret = qcom_tzmem_shm_bridge_create(ctx->mem_phys, ctx->mem_size, &handle); - if (ret) { - dev_err(__scm->dev, "Failed to create shmbridge for PAS ID (%u): %d\n", - ctx->pas_id, ret); - return ret; - } - - ret = qcom_scm_pas_auth_and_reset(ctx->pas_id); - qcom_tzmem_shm_bridge_delete(handle); - - return ret; -} -EXPORT_SYMBOL_GPL(qcom_scm_pas_prepare_and_auth_reset); - /** * qcom_scm_pas_shutdown() - Shut down the remote processor * @pas_id: peripheral authentication service id diff --git a/include/linux/firmware/qcom/qcom_scm.h b/include/linux/firmware/qcom/qcom_scm.h index 3093d3af68511..48a40b6622e87 100644 --- a/include/linux/firmware/qcom/qcom_scm.h +++ b/include/linux/firmware/qcom/qcom_scm.h @@ -76,7 +76,6 @@ struct qcom_scm_pas_context { void *ptr; dma_addr_t phys; ssize_t size; - bool has_iommu; }; struct qcom_scm_camera_qos { @@ -99,7 +98,6 @@ int qcom_scm_pas_mem_setup(u32 pas_id, phys_addr_t addr, phys_addr_t size); int qcom_scm_pas_auth_and_reset(u32 pas_id); int qcom_scm_pas_shutdown(u32 pas_id); bool qcom_scm_pas_supported(u32 pas_id); -int qcom_scm_pas_prepare_and_auth_reset(struct qcom_scm_pas_context *ctx); int qcom_scm_io_readl(phys_addr_t addr, unsigned int *val); int qcom_scm_io_writel(phys_addr_t addr, unsigned int val); From d5f398e68def605d5f090f7a0e9128fe4e8afb6c Mon Sep 17 00:00:00 2001 From: Mukesh Ojha Date: Fri, 6 Feb 2026 17:33:28 +0530 Subject: [PATCH 2219/2333] Revert "FROMLIST: soc: qcom: mdtloader: Remove qcom_mdt_pas_init() from exported symbols" This reverts commit 55a4474e0a8f9e0c5e6d0336336225b45ed8a707. as latest version v10 of the commit is available. Signed-off-by: Mukesh Ojha --- drivers/soc/qcom/mdt_loader.c | 11 ++++++----- include/linux/soc/qcom/mdt_loader.h | 10 ++++++++++ 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/drivers/soc/qcom/mdt_loader.c b/drivers/soc/qcom/mdt_loader.c index 1b426a16389b0..847941d232f74 100644 --- a/drivers/soc/qcom/mdt_loader.c +++ b/drivers/soc/qcom/mdt_loader.c @@ -238,9 +238,9 @@ EXPORT_SYMBOL_GPL(qcom_mdt_read_metadata); * * Returns 0 on success, negative errno otherwise. */ -static int __qcom_mdt_pas_init(struct device *dev, const struct firmware *fw, - const char *fw_name, int pas_id, phys_addr_t mem_phys, - struct qcom_scm_pas_context *ctx) +int qcom_mdt_pas_init(struct device *dev, const struct firmware *fw, + const char *fw_name, int pas_id, phys_addr_t mem_phys, + struct qcom_scm_pas_context *ctx) { const struct elf32_phdr *phdrs; const struct elf32_phdr *phdr; @@ -302,6 +302,7 @@ static int __qcom_mdt_pas_init(struct device *dev, const struct firmware *fw, out: return ret; } +EXPORT_SYMBOL_GPL(qcom_mdt_pas_init); static bool qcom_mdt_bins_are_split(const struct firmware *fw) { @@ -455,7 +456,7 @@ int qcom_mdt_load(struct device *dev, const struct firmware *fw, { int ret; - ret = __qcom_mdt_pas_init(dev, fw, firmware, pas_id, mem_phys, NULL); + ret = qcom_mdt_pas_init(dev, fw, firmware, pas_id, mem_phys, NULL); if (ret) return ret; @@ -507,7 +508,7 @@ int qcom_mdt_pas_load(struct qcom_scm_pas_context *ctx, const struct firmware *f { int ret; - ret = __qcom_mdt_pas_init(ctx->dev, fw, firmware, ctx->pas_id, ctx->mem_phys, ctx); + ret = qcom_mdt_pas_init(ctx->dev, fw, firmware, ctx->pas_id, ctx->mem_phys, ctx); if (ret) return ret; diff --git a/include/linux/soc/qcom/mdt_loader.h b/include/linux/soc/qcom/mdt_loader.h index 82372e0db0a18..7d57746fbbfa5 100644 --- a/include/linux/soc/qcom/mdt_loader.h +++ b/include/linux/soc/qcom/mdt_loader.h @@ -15,6 +15,9 @@ struct qcom_scm_pas_context; #if IS_ENABLED(CONFIG_QCOM_MDT_LOADER) ssize_t qcom_mdt_get_size(const struct firmware *fw); +int qcom_mdt_pas_init(struct device *dev, const struct firmware *fw, + const char *fw_name, int pas_id, phys_addr_t mem_phys, + struct qcom_scm_pas_context *pas_ctx); int qcom_mdt_load(struct device *dev, const struct firmware *fw, const char *fw_name, int pas_id, void *mem_region, phys_addr_t mem_phys, size_t mem_size, @@ -37,6 +40,13 @@ static inline ssize_t qcom_mdt_get_size(const struct firmware *fw) return -ENODEV; } +static inline int qcom_mdt_pas_init(struct device *dev, const struct firmware *fw, + const char *fw_name, int pas_id, phys_addr_t mem_phys, + struct qcom_scm_pas_context *pas_ctx) +{ + return -ENODEV; +} + static inline int qcom_mdt_load(struct device *dev, const struct firmware *fw, const char *fw_name, int pas_id, void *mem_region, phys_addr_t mem_phys, From 3164956a41fee5e2eeed9b194b8ddeb56d22abb5 Mon Sep 17 00:00:00 2001 From: Mukesh Ojha Date: Fri, 6 Feb 2026 17:33:42 +0530 Subject: [PATCH 2220/2333] Revert "FROMLIST: soc: qcom: mdtloader: Add PAS context aware qcom_mdt_pas_load() function" This reverts commit f4bf32151398e435fdbadb50f50bb98a83d2def0. as latest version v10 of the commit is available. Signed-off-by: Mukesh Ojha --- drivers/remoteproc/qcom_q6v5_pas.c | 24 +++++++++++++++++----- drivers/soc/qcom/mdt_loader.c | 31 ----------------------------- include/linux/soc/qcom/mdt_loader.h | 10 ---------- 3 files changed, 19 insertions(+), 46 deletions(-) diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c index 9feee2cb18835..729e7b9bc1831 100644 --- a/drivers/remoteproc/qcom_q6v5_pas.c +++ b/drivers/remoteproc/qcom_q6v5_pas.c @@ -239,9 +239,15 @@ static int qcom_pas_load(struct rproc *rproc, const struct firmware *fw) return ret; } - ret = qcom_mdt_pas_load(pas->dtb_pas_ctx, pas->dtb_firmware, - pas->dtb_firmware_name, pas->dtb_mem_region, - &pas->dtb_mem_reloc); + ret = qcom_mdt_pas_init(pas->dev, pas->dtb_firmware, pas->dtb_firmware_name, + pas->dtb_pas_id, pas->dtb_mem_phys, + pas->dtb_pas_ctx); + if (ret) + goto release_dtb_firmware; + + ret = qcom_mdt_load_no_init(pas->dev, pas->dtb_firmware, pas->dtb_firmware_name, + pas->dtb_mem_region, pas->dtb_mem_phys, + pas->dtb_mem_size, &pas->dtb_mem_reloc); if (ret) goto release_dtb_metadata; } @@ -250,6 +256,8 @@ static int qcom_pas_load(struct rproc *rproc, const struct firmware *fw) release_dtb_metadata: qcom_scm_pas_metadata_release(pas->dtb_pas_ctx); + +release_dtb_firmware: release_firmware(pas->dtb_firmware); return ret; @@ -297,8 +305,14 @@ static int qcom_pas_start(struct rproc *rproc) } } - ret = qcom_mdt_pas_load(pas->pas_ctx, pas->firmware, rproc->firmware, - pas->mem_region, &pas->mem_reloc); + ret = qcom_mdt_pas_init(pas->dev, pas->firmware, rproc->firmware, pas->pas_id, + pas->mem_phys, pas->pas_ctx); + if (ret) + goto disable_px_supply; + + ret = qcom_mdt_load_no_init(pas->dev, pas->firmware, rproc->firmware, + pas->mem_region, pas->mem_phys, pas->mem_size, + &pas->mem_reloc); if (ret) goto release_pas_metadata; diff --git a/drivers/soc/qcom/mdt_loader.c b/drivers/soc/qcom/mdt_loader.c index 847941d232f74..fe35038c5342e 100644 --- a/drivers/soc/qcom/mdt_loader.c +++ b/drivers/soc/qcom/mdt_loader.c @@ -486,36 +486,5 @@ int qcom_mdt_load_no_init(struct device *dev, const struct firmware *fw, } EXPORT_SYMBOL_GPL(qcom_mdt_load_no_init); -/** - * qcom_mdt_pas_load - Loads and authenticates the metadata of the firmware - * (typically contained in the .mdt file), followed by loading the actual - * firmware segments (e.g., .bXX files). Authentication of the segments done - * by a separate call. - * - * The PAS context must be initialized using qcom_scm_pas_context_init() - * prior to invoking this function. - * - * @ctx: Pointer to the PAS (Peripheral Authentication Service) context - * @fw: Firmware object representing the .mdt file - * @firmware: Name of the firmware used to construct segment file names - * @mem_region: Memory region allocated for loading the firmware - * @reloc_base: Physical address adjusted after relocation - * - * Return: 0 on success or a negative error code on failure. - */ -int qcom_mdt_pas_load(struct qcom_scm_pas_context *ctx, const struct firmware *fw, - const char *firmware, void *mem_region, phys_addr_t *reloc_base) -{ - int ret; - - ret = qcom_mdt_pas_init(ctx->dev, fw, firmware, ctx->pas_id, ctx->mem_phys, ctx); - if (ret) - return ret; - - return qcom_mdt_load_no_init(ctx->dev, fw, firmware, mem_region, ctx->mem_phys, - ctx->mem_size, reloc_base); -} -EXPORT_SYMBOL_GPL(qcom_mdt_pas_load); - MODULE_DESCRIPTION("Firmware parser for Qualcomm MDT format"); MODULE_LICENSE("GPL v2"); diff --git a/include/linux/soc/qcom/mdt_loader.h b/include/linux/soc/qcom/mdt_loader.h index 7d57746fbbfa5..07c2788418166 100644 --- a/include/linux/soc/qcom/mdt_loader.h +++ b/include/linux/soc/qcom/mdt_loader.h @@ -23,9 +23,6 @@ int qcom_mdt_load(struct device *dev, const struct firmware *fw, phys_addr_t mem_phys, size_t mem_size, phys_addr_t *reloc_base); -int qcom_mdt_pas_load(struct qcom_scm_pas_context *ctx, const struct firmware *fw, - const char *firmware, void *mem_region, phys_addr_t *reloc_base); - int qcom_mdt_load_no_init(struct device *dev, const struct firmware *fw, const char *fw_name, void *mem_region, phys_addr_t mem_phys, size_t mem_size, @@ -55,13 +52,6 @@ static inline int qcom_mdt_load(struct device *dev, const struct firmware *fw, return -ENODEV; } -static inline int qcom_mdt_pas_load(struct qcom_scm_pas_context *ctx, - const struct firmware *fw, const char *firmware, - void *mem_region, phys_addr_t *reloc_base) -{ - return -ENODEV; -} - static inline int qcom_mdt_load_no_init(struct device *dev, const struct firmware *fw, const char *fw_name, void *mem_region, From dd99b684351f56c780e6635f42aed93761b06e9b Mon Sep 17 00:00:00 2001 From: Mukesh Ojha Date: Fri, 6 Feb 2026 17:33:54 +0530 Subject: [PATCH 2221/2333] Revert "FROMLIST: remoteproc: pas: Replace metadata context with PAS context structure" This reverts commit 81beeeb47330130c98c456e756c7181483dc6dbb. as latest version v10 of the commit is available. Signed-off-by: Mukesh Ojha --- drivers/firmware/qcom/qcom_scm.c | 8 +++--- drivers/remoteproc/qcom_q6v5_pas.c | 38 ++++++++------------------ drivers/soc/qcom/mdt_loader.c | 4 +-- include/linux/firmware/qcom/qcom_scm.h | 10 +++++-- include/linux/soc/qcom/mdt_loader.h | 6 ++-- 5 files changed, 28 insertions(+), 38 deletions(-) diff --git a/drivers/firmware/qcom/qcom_scm.c b/drivers/firmware/qcom/qcom_scm.c index 88ca24bbf85d8..00d9546f8f2a0 100644 --- a/drivers/firmware/qcom/qcom_scm.c +++ b/drivers/firmware/qcom/qcom_scm.c @@ -601,7 +601,7 @@ EXPORT_SYMBOL_GPL(devm_qcom_scm_pas_context_init); * and optional blob of data used for authenticating the metadata * and the rest of the firmware * @size: size of the metadata - * @ctx: optional pas context + * @ctx: optional metadata context * * Return: 0 on success. * @@ -610,7 +610,7 @@ EXPORT_SYMBOL_GPL(devm_qcom_scm_pas_context_init); * qcom_scm_pas_metadata_release() by the caller. */ int qcom_scm_pas_init_image(u32 pas_id, const void *metadata, size_t size, - struct qcom_scm_pas_context *ctx) + struct qcom_scm_pas_metadata *ctx) { dma_addr_t mdata_phys; void *mdata_buf; @@ -674,9 +674,9 @@ EXPORT_SYMBOL_GPL(qcom_scm_pas_init_image); /** * qcom_scm_pas_metadata_release() - release metadata context - * @ctx: pas context + * @ctx: metadata context */ -void qcom_scm_pas_metadata_release(struct qcom_scm_pas_context *ctx) +void qcom_scm_pas_metadata_release(struct qcom_scm_pas_metadata *ctx) { if (!ctx->ptr) return; diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c index 729e7b9bc1831..158bcd6cc85c5 100644 --- a/drivers/remoteproc/qcom_q6v5_pas.c +++ b/drivers/remoteproc/qcom_q6v5_pas.c @@ -117,8 +117,8 @@ struct qcom_pas { struct qcom_rproc_ssr ssr_subdev; struct qcom_sysmon *sysmon; - struct qcom_scm_pas_context *pas_ctx; - struct qcom_scm_pas_context *dtb_pas_ctx; + struct qcom_scm_pas_metadata pas_metadata; + struct qcom_scm_pas_metadata dtb_pas_metadata; }; static void qcom_pas_segment_dump(struct rproc *rproc, @@ -211,9 +211,9 @@ static int qcom_pas_unprepare(struct rproc *rproc) * auth_and_reset() was successful, but in other cases clean it up * here. */ - qcom_scm_pas_metadata_release(pas->pas_ctx); + qcom_scm_pas_metadata_release(&pas->pas_metadata); if (pas->dtb_pas_id) - qcom_scm_pas_metadata_release(pas->dtb_pas_ctx); + qcom_scm_pas_metadata_release(&pas->dtb_pas_metadata); return 0; } @@ -241,7 +241,7 @@ static int qcom_pas_load(struct rproc *rproc, const struct firmware *fw) ret = qcom_mdt_pas_init(pas->dev, pas->dtb_firmware, pas->dtb_firmware_name, pas->dtb_pas_id, pas->dtb_mem_phys, - pas->dtb_pas_ctx); + &pas->dtb_pas_metadata); if (ret) goto release_dtb_firmware; @@ -255,7 +255,7 @@ static int qcom_pas_load(struct rproc *rproc, const struct firmware *fw) return 0; release_dtb_metadata: - qcom_scm_pas_metadata_release(pas->dtb_pas_ctx); + qcom_scm_pas_metadata_release(&pas->dtb_pas_metadata); release_dtb_firmware: release_firmware(pas->dtb_firmware); @@ -306,7 +306,7 @@ static int qcom_pas_start(struct rproc *rproc) } ret = qcom_mdt_pas_init(pas->dev, pas->firmware, rproc->firmware, pas->pas_id, - pas->mem_phys, pas->pas_ctx); + pas->mem_phys, &pas->pas_metadata); if (ret) goto disable_px_supply; @@ -332,9 +332,9 @@ static int qcom_pas_start(struct rproc *rproc) goto release_pas_metadata; } - qcom_scm_pas_metadata_release(pas->pas_ctx); + qcom_scm_pas_metadata_release(&pas->pas_metadata); if (pas->dtb_pas_id) - qcom_scm_pas_metadata_release(pas->dtb_pas_ctx); + qcom_scm_pas_metadata_release(&pas->dtb_pas_metadata); /* firmware is used to pass reference from qcom_pas_start(), drop it now */ pas->firmware = NULL; @@ -342,9 +342,9 @@ static int qcom_pas_start(struct rproc *rproc) return 0; release_pas_metadata: - qcom_scm_pas_metadata_release(pas->pas_ctx); + qcom_scm_pas_metadata_release(&pas->pas_metadata); if (pas->dtb_pas_id) - qcom_scm_pas_metadata_release(pas->dtb_pas_ctx); + qcom_scm_pas_metadata_release(&pas->dtb_pas_metadata); disable_px_supply: if (pas->px_supply) regulator_disable(pas->px_supply); @@ -779,22 +779,6 @@ static int qcom_pas_probe(struct platform_device *pdev) } qcom_add_ssr_subdev(rproc, &pas->ssr_subdev, desc->ssr_name); - - pas->pas_ctx = devm_qcom_scm_pas_context_init(pas->dev, pas->pas_id, - pas->mem_phys, pas->mem_size); - if (IS_ERR(pas->pas_ctx)) { - ret = PTR_ERR(pas->pas_ctx); - goto remove_ssr_sysmon; - } - - pas->dtb_pas_ctx = devm_qcom_scm_pas_context_init(pas->dev, pas->dtb_pas_id, - pas->dtb_mem_phys, - pas->dtb_mem_size); - if (IS_ERR(pas->dtb_pas_ctx)) { - ret = PTR_ERR(pas->dtb_pas_ctx); - goto remove_ssr_sysmon; - } - ret = rproc_add(rproc); if (ret) goto remove_ssr_sysmon; diff --git a/drivers/soc/qcom/mdt_loader.c b/drivers/soc/qcom/mdt_loader.c index fe35038c5342e..a5c80d4fcc366 100644 --- a/drivers/soc/qcom/mdt_loader.c +++ b/drivers/soc/qcom/mdt_loader.c @@ -234,13 +234,13 @@ EXPORT_SYMBOL_GPL(qcom_mdt_read_metadata); * @fw_name: name of the firmware, for construction of segment file names * @pas_id: PAS identifier * @mem_phys: physical address of allocated memory region - * @ctx: PAS context, ctx->metadata to be released by caller + * @ctx: PAS metadata context, to be released by caller * * Returns 0 on success, negative errno otherwise. */ int qcom_mdt_pas_init(struct device *dev, const struct firmware *fw, const char *fw_name, int pas_id, phys_addr_t mem_phys, - struct qcom_scm_pas_context *ctx) + struct qcom_scm_pas_metadata *ctx) { const struct elf32_phdr *phdrs; const struct elf32_phdr *phdr; diff --git a/include/linux/firmware/qcom/qcom_scm.h b/include/linux/firmware/qcom/qcom_scm.h index 48a40b6622e87..abda944700994 100644 --- a/include/linux/firmware/qcom/qcom_scm.h +++ b/include/linux/firmware/qcom/qcom_scm.h @@ -68,6 +68,12 @@ int qcom_scm_set_warm_boot_addr(void *entry); void qcom_scm_cpu_power_down(u32 flags); int qcom_scm_set_remote_state(u32 state, u32 id); +struct qcom_scm_pas_metadata { + void *ptr; + dma_addr_t phys; + ssize_t size; +}; + struct qcom_scm_pas_context { struct device *dev; u32 pas_id; @@ -92,8 +98,8 @@ struct qcom_scm_pas_context *devm_qcom_scm_pas_context_init(struct device *dev, phys_addr_t mem_phys, size_t mem_size); int qcom_scm_pas_init_image(u32 pas_id, const void *metadata, size_t size, - struct qcom_scm_pas_context *ctx); -void qcom_scm_pas_metadata_release(struct qcom_scm_pas_context *ctx); + struct qcom_scm_pas_metadata *ctx); +void qcom_scm_pas_metadata_release(struct qcom_scm_pas_metadata *ctx); int qcom_scm_pas_mem_setup(u32 pas_id, phys_addr_t addr, phys_addr_t size); int qcom_scm_pas_auth_and_reset(u32 pas_id); int qcom_scm_pas_shutdown(u32 pas_id); diff --git a/include/linux/soc/qcom/mdt_loader.h b/include/linux/soc/qcom/mdt_loader.h index 07c2788418166..8ea8230579a20 100644 --- a/include/linux/soc/qcom/mdt_loader.h +++ b/include/linux/soc/qcom/mdt_loader.h @@ -10,14 +10,14 @@ struct device; struct firmware; -struct qcom_scm_pas_context; +struct qcom_scm_pas_metadata; #if IS_ENABLED(CONFIG_QCOM_MDT_LOADER) ssize_t qcom_mdt_get_size(const struct firmware *fw); int qcom_mdt_pas_init(struct device *dev, const struct firmware *fw, const char *fw_name, int pas_id, phys_addr_t mem_phys, - struct qcom_scm_pas_context *pas_ctx); + struct qcom_scm_pas_metadata *pas_metadata_ctx); int qcom_mdt_load(struct device *dev, const struct firmware *fw, const char *fw_name, int pas_id, void *mem_region, phys_addr_t mem_phys, size_t mem_size, @@ -39,7 +39,7 @@ static inline ssize_t qcom_mdt_get_size(const struct firmware *fw) static inline int qcom_mdt_pas_init(struct device *dev, const struct firmware *fw, const char *fw_name, int pas_id, phys_addr_t mem_phys, - struct qcom_scm_pas_context *pas_ctx) + struct qcom_scm_pas_metadata *pas_metadata_ctx) { return -ENODEV; } From c395d1667808241386f69aee9cdd66c80cd739db Mon Sep 17 00:00:00 2001 From: Mukesh Ojha Date: Fri, 6 Feb 2026 17:35:18 +0530 Subject: [PATCH 2222/2333] Revert "FROMLIST: firmware: qcom_scm: Introduce PAS context initialization helper function" This reverts commit f966b3af0c4c100e9313917535d2f13d4dca95ad. as latest version v10 of the commit is available. Signed-off-by: Mukesh Ojha --- drivers/firmware/qcom/qcom_scm.c | 34 -------------------------- include/linux/firmware/qcom/qcom_scm.h | 15 ------------ 2 files changed, 49 deletions(-) diff --git a/drivers/firmware/qcom/qcom_scm.c b/drivers/firmware/qcom/qcom_scm.c index 00d9546f8f2a0..88f9181914d38 100644 --- a/drivers/firmware/qcom/qcom_scm.c +++ b/drivers/firmware/qcom/qcom_scm.c @@ -558,40 +558,6 @@ static void qcom_scm_set_download_mode(u32 dload_mode) dev_err(__scm->dev, "failed to set download mode: %d\n", ret); } -/** - * devm_qcom_scm_pas_context_init() - Initialize peripheral authentication service - * context for a given peripheral - * - * PAS context is device-resource managed, so the caller does not need - * to worry about freeing the context memory. - * - * @dev: PAS firmware device - * @pas_id: peripheral authentication service id - * @mem_phys: Subsystem reserve memory start address - * @mem_size: Subsystem reserve memory size - * - * Upon successful, returns the PAS context or ERR_PTR() of the error otherwise. - */ -struct qcom_scm_pas_context *devm_qcom_scm_pas_context_init(struct device *dev, - u32 pas_id, - phys_addr_t mem_phys, - size_t mem_size) -{ - struct qcom_scm_pas_context *ctx; - - ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return ERR_PTR(-ENOMEM); - - ctx->dev = dev; - ctx->pas_id = pas_id; - ctx->mem_phys = mem_phys; - ctx->mem_size = mem_size; - - return ctx; -} -EXPORT_SYMBOL_GPL(devm_qcom_scm_pas_context_init); - /** * qcom_scm_pas_init_image() - Initialize peripheral authentication service * state machine for a given peripheral, using the diff --git a/include/linux/firmware/qcom/qcom_scm.h b/include/linux/firmware/qcom/qcom_scm.h index abda944700994..a60e261af6855 100644 --- a/include/linux/firmware/qcom/qcom_scm.h +++ b/include/linux/firmware/qcom/qcom_scm.h @@ -74,16 +74,6 @@ struct qcom_scm_pas_metadata { ssize_t size; }; -struct qcom_scm_pas_context { - struct device *dev; - u32 pas_id; - phys_addr_t mem_phys; - size_t mem_size; - void *ptr; - dma_addr_t phys; - ssize_t size; -}; - struct qcom_scm_camera_qos { u32 offset; u32 val; @@ -92,11 +82,6 @@ struct qcom_scm_camera_qos { int qcom_scm_camera_update_camnoc_qos(uint32_t use_case_id, uint32_t qos_cnt, struct qcom_scm_camera_qos *scm_buf); - -struct qcom_scm_pas_context *devm_qcom_scm_pas_context_init(struct device *dev, - u32 pas_id, - phys_addr_t mem_phys, - size_t mem_size); int qcom_scm_pas_init_image(u32 pas_id, const void *metadata, size_t size, struct qcom_scm_pas_metadata *ctx); void qcom_scm_pas_metadata_release(struct qcom_scm_pas_metadata *ctx); From f98da882fcdde881f2e8cb4b1f91da1dde498367 Mon Sep 17 00:00:00 2001 From: Mukesh Ojha Date: Fri, 6 Feb 2026 17:36:21 +0530 Subject: [PATCH 2223/2333] Revert "FROMLIST: firmware: qcom_scm: Rename peripheral as pas_id" This reverts commit 43fc6b4fc625dfd2082c1554f951328483eeb655. as latest version v10 of the commit is available. Signed-off-by: Mukesh Ojha --- drivers/firmware/qcom/qcom_scm.c | 30 +++++++++++++------------- include/linux/firmware/qcom/qcom_scm.h | 10 ++++----- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/drivers/firmware/qcom/qcom_scm.c b/drivers/firmware/qcom/qcom_scm.c index 88f9181914d38..f29f3c3038556 100644 --- a/drivers/firmware/qcom/qcom_scm.c +++ b/drivers/firmware/qcom/qcom_scm.c @@ -562,7 +562,7 @@ static void qcom_scm_set_download_mode(u32 dload_mode) * qcom_scm_pas_init_image() - Initialize peripheral authentication service * state machine for a given peripheral, using the * metadata - * @pas_id: peripheral authentication service id + * @peripheral: peripheral id * @metadata: pointer to memory containing ELF header, program header table * and optional blob of data used for authenticating the metadata * and the rest of the firmware @@ -575,7 +575,7 @@ static void qcom_scm_set_download_mode(u32 dload_mode) * track the metadata allocation, this needs to be released by invoking * qcom_scm_pas_metadata_release() by the caller. */ -int qcom_scm_pas_init_image(u32 pas_id, const void *metadata, size_t size, +int qcom_scm_pas_init_image(u32 peripheral, const void *metadata, size_t size, struct qcom_scm_pas_metadata *ctx) { dma_addr_t mdata_phys; @@ -585,7 +585,7 @@ int qcom_scm_pas_init_image(u32 pas_id, const void *metadata, size_t size, .svc = QCOM_SCM_SVC_PIL, .cmd = QCOM_SCM_PIL_PAS_INIT_IMAGE, .arginfo = QCOM_SCM_ARGS(2, QCOM_SCM_VAL, QCOM_SCM_RW), - .args[0] = pas_id, + .args[0] = peripheral, .owner = ARM_SMCCC_OWNER_SIP, }; struct qcom_scm_res res; @@ -656,20 +656,20 @@ EXPORT_SYMBOL_GPL(qcom_scm_pas_metadata_release); /** * qcom_scm_pas_mem_setup() - Prepare the memory related to a given peripheral * for firmware loading - * @pas_id: peripheral authentication service id + * @peripheral: peripheral id * @addr: start address of memory area to prepare * @size: size of the memory area to prepare * * Returns 0 on success. */ -int qcom_scm_pas_mem_setup(u32 pas_id, phys_addr_t addr, phys_addr_t size) +int qcom_scm_pas_mem_setup(u32 peripheral, phys_addr_t addr, phys_addr_t size) { int ret; struct qcom_scm_desc desc = { .svc = QCOM_SCM_SVC_PIL, .cmd = QCOM_SCM_PIL_PAS_MEM_SETUP, .arginfo = QCOM_SCM_ARGS(3), - .args[0] = pas_id, + .args[0] = peripheral, .args[1] = addr, .args[2] = size, .owner = ARM_SMCCC_OWNER_SIP, @@ -697,18 +697,18 @@ EXPORT_SYMBOL_GPL(qcom_scm_pas_mem_setup); /** * qcom_scm_pas_auth_and_reset() - Authenticate the given peripheral firmware * and reset the remote processor - * @pas_id: peripheral authentication service id + * @peripheral: peripheral id * * Return 0 on success. */ -int qcom_scm_pas_auth_and_reset(u32 pas_id) +int qcom_scm_pas_auth_and_reset(u32 peripheral) { int ret; struct qcom_scm_desc desc = { .svc = QCOM_SCM_SVC_PIL, .cmd = QCOM_SCM_PIL_PAS_AUTH_AND_RESET, .arginfo = QCOM_SCM_ARGS(1), - .args[0] = pas_id, + .args[0] = peripheral, .owner = ARM_SMCCC_OWNER_SIP, }; struct qcom_scm_res res; @@ -733,18 +733,18 @@ EXPORT_SYMBOL_GPL(qcom_scm_pas_auth_and_reset); /** * qcom_scm_pas_shutdown() - Shut down the remote processor - * @pas_id: peripheral authentication service id + * @peripheral: peripheral id * * Returns 0 on success. */ -int qcom_scm_pas_shutdown(u32 pas_id) +int qcom_scm_pas_shutdown(u32 peripheral) { int ret; struct qcom_scm_desc desc = { .svc = QCOM_SCM_SVC_PIL, .cmd = QCOM_SCM_PIL_PAS_SHUTDOWN, .arginfo = QCOM_SCM_ARGS(1), - .args[0] = pas_id, + .args[0] = peripheral, .owner = ARM_SMCCC_OWNER_SIP, }; struct qcom_scm_res res; @@ -770,18 +770,18 @@ EXPORT_SYMBOL_GPL(qcom_scm_pas_shutdown); /** * qcom_scm_pas_supported() - Check if the peripheral authentication service is * available for the given peripherial - * @pas_id: peripheral authentication service id + * @peripheral: peripheral id * * Returns true if PAS is supported for this peripheral, otherwise false. */ -bool qcom_scm_pas_supported(u32 pas_id) +bool qcom_scm_pas_supported(u32 peripheral) { int ret; struct qcom_scm_desc desc = { .svc = QCOM_SCM_SVC_PIL, .cmd = QCOM_SCM_PIL_PAS_IS_SUPPORTED, .arginfo = QCOM_SCM_ARGS(1), - .args[0] = pas_id, + .args[0] = peripheral, .owner = ARM_SMCCC_OWNER_SIP, }; struct qcom_scm_res res; diff --git a/include/linux/firmware/qcom/qcom_scm.h b/include/linux/firmware/qcom/qcom_scm.h index a60e261af6855..6c29540ffeeec 100644 --- a/include/linux/firmware/qcom/qcom_scm.h +++ b/include/linux/firmware/qcom/qcom_scm.h @@ -82,13 +82,13 @@ struct qcom_scm_camera_qos { int qcom_scm_camera_update_camnoc_qos(uint32_t use_case_id, uint32_t qos_cnt, struct qcom_scm_camera_qos *scm_buf); -int qcom_scm_pas_init_image(u32 pas_id, const void *metadata, size_t size, +int qcom_scm_pas_init_image(u32 peripheral, const void *metadata, size_t size, struct qcom_scm_pas_metadata *ctx); void qcom_scm_pas_metadata_release(struct qcom_scm_pas_metadata *ctx); -int qcom_scm_pas_mem_setup(u32 pas_id, phys_addr_t addr, phys_addr_t size); -int qcom_scm_pas_auth_and_reset(u32 pas_id); -int qcom_scm_pas_shutdown(u32 pas_id); -bool qcom_scm_pas_supported(u32 pas_id); +int qcom_scm_pas_mem_setup(u32 peripheral, phys_addr_t addr, phys_addr_t size); +int qcom_scm_pas_auth_and_reset(u32 peripheral); +int qcom_scm_pas_shutdown(u32 peripheral); +bool qcom_scm_pas_supported(u32 peripheral); int qcom_scm_io_readl(phys_addr_t addr, unsigned int *val); int qcom_scm_io_writel(phys_addr_t addr, unsigned int val); From 444a697fe1b198c2f31a4d7f129f4c7e3a6488a9 Mon Sep 17 00:00:00 2001 From: Mukesh Ojha Date: Fri, 6 Feb 2026 17:36:32 +0530 Subject: [PATCH 2224/2333] Revert "FROMLIST: firmware: qcom_scm: Remove redundant piece of code" This reverts commit d329c414ca91ace81ee36ac434be8e28075d6a6e. as latest version v10 of the commit is available. Signed-off-by: Mukesh Ojha --- drivers/firmware/qcom/qcom_scm.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/firmware/qcom/qcom_scm.c b/drivers/firmware/qcom/qcom_scm.c index f29f3c3038556..cbef05a4833dd 100644 --- a/drivers/firmware/qcom/qcom_scm.c +++ b/drivers/firmware/qcom/qcom_scm.c @@ -650,6 +650,8 @@ void qcom_scm_pas_metadata_release(struct qcom_scm_pas_metadata *ctx) dma_free_coherent(__scm->dev, ctx->size, ctx->ptr, ctx->phys); ctx->ptr = NULL; + ctx->phys = 0; + ctx->size = 0; } EXPORT_SYMBOL_GPL(qcom_scm_pas_metadata_release); From d0623c1d3af5b2925a93e2c132a142da6429e11d Mon Sep 17 00:00:00 2001 From: Mukesh Ojha Date: Fri, 6 Feb 2026 17:36:36 +0530 Subject: [PATCH 2225/2333] Revert "FROMLIST: dt-bindings: remoteproc: qcom,pas: Add iommus property" This reverts commit b1966182caa723b36e0885eb2e5af3b07a62970e. as latest version v10 of the commit is available. Signed-off-by: Mukesh Ojha --- .../devicetree/bindings/remoteproc/qcom,pas-common.yaml | 3 --- 1 file changed, 3 deletions(-) diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml index 6a736161d5aed..bbc82253f76b3 100644 --- a/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml +++ b/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml @@ -44,9 +44,6 @@ properties: - const: stop-ack - const: shutdown-ack - iommus: - maxItems: 1 - power-domains: minItems: 1 maxItems: 3 From 0be1050ff577b21d7a1a8357fec62857a954f7c3 Mon Sep 17 00:00:00 2001 From: Mukesh Ojha Date: Mon, 5 Jan 2026 18:52:49 +0530 Subject: [PATCH 2226/2333] FROMLIST: dt-bindings: remoteproc: qcom,pas: Add iommus property On most Qualcomm platforms, the Qualcomm Hypervisor Execution Environment (QHEE) is either used as a standalone hypervisor or co-exists as a module with the Gunyah hypervisor. When QHEE is present, it configures firmware streams for remote processors. If QHEE is not available, the operating system must perform these configurations instead and for that remote processor firmware stream should be presented to the operating system. To support this, add the iommus property as an optional property for PAS-supported devices. Acked-by: Rob Herring (Arm) Reviewed-by: Bryan O'Donoghue Signed-off-by: Mukesh Ojha Link: https://lore.kernel.org/r/20260105-kvmrprocv10-v10-1-022e96815380@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- .../devicetree/bindings/remoteproc/qcom,pas-common.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml index bbc82253f76b3..6a736161d5aed 100644 --- a/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml +++ b/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml @@ -44,6 +44,9 @@ properties: - const: stop-ack - const: shutdown-ack + iommus: + maxItems: 1 + power-domains: minItems: 1 maxItems: 3 From 1738cbc3b2a05317480360475fdad5ad43496549 Mon Sep 17 00:00:00 2001 From: Mukesh Ojha Date: Mon, 5 Jan 2026 18:52:50 +0530 Subject: [PATCH 2227/2333] FROMLIST: firmware: qcom_scm: Remove redundant piece of code The qcom_scm_pas_metadata_release() function already frees the allocated memory and sets ctx->ptr to NULL. Resetting ctx->phys and ctx->size to zero is unnecessary because the context is expected to be discarded after release. Lets removes redundant assignments. Signed-off-by: Mukesh Ojha Link: https://lore.kernel.org/r/20260105-kvmrprocv10-v10-2-022e96815380@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- drivers/firmware/qcom/qcom_scm.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/firmware/qcom/qcom_scm.c b/drivers/firmware/qcom/qcom_scm.c index cbef05a4833dd..f29f3c3038556 100644 --- a/drivers/firmware/qcom/qcom_scm.c +++ b/drivers/firmware/qcom/qcom_scm.c @@ -650,8 +650,6 @@ void qcom_scm_pas_metadata_release(struct qcom_scm_pas_metadata *ctx) dma_free_coherent(__scm->dev, ctx->size, ctx->ptr, ctx->phys); ctx->ptr = NULL; - ctx->phys = 0; - ctx->size = 0; } EXPORT_SYMBOL_GPL(qcom_scm_pas_metadata_release); From 32ee583545a95584b79ce0f921555e64e0d1209b Mon Sep 17 00:00:00 2001 From: Mukesh Ojha Date: Mon, 5 Jan 2026 18:52:51 +0530 Subject: [PATCH 2228/2333] FROMLIST: firmware: qcom_scm: Rename peripheral as pas_id Peripheral and pas_id refers to unique id for a subsystem and used only when peripheral authentication service from secure world is utilized. Lets rename peripheral to pas_id to reflect closer to its meaning. Reviewed-by: Bryan O'Donoghue Reviewed-by: Konrad Dybcio Signed-off-by: Mukesh Ojha Link: https://lore.kernel.org/r/20260105-kvmrprocv10-v10-3-022e96815380@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- drivers/firmware/qcom/qcom_scm.c | 30 +++++++++++++------------- include/linux/firmware/qcom/qcom_scm.h | 10 ++++----- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/drivers/firmware/qcom/qcom_scm.c b/drivers/firmware/qcom/qcom_scm.c index f29f3c3038556..88f9181914d38 100644 --- a/drivers/firmware/qcom/qcom_scm.c +++ b/drivers/firmware/qcom/qcom_scm.c @@ -562,7 +562,7 @@ static void qcom_scm_set_download_mode(u32 dload_mode) * qcom_scm_pas_init_image() - Initialize peripheral authentication service * state machine for a given peripheral, using the * metadata - * @peripheral: peripheral id + * @pas_id: peripheral authentication service id * @metadata: pointer to memory containing ELF header, program header table * and optional blob of data used for authenticating the metadata * and the rest of the firmware @@ -575,7 +575,7 @@ static void qcom_scm_set_download_mode(u32 dload_mode) * track the metadata allocation, this needs to be released by invoking * qcom_scm_pas_metadata_release() by the caller. */ -int qcom_scm_pas_init_image(u32 peripheral, const void *metadata, size_t size, +int qcom_scm_pas_init_image(u32 pas_id, const void *metadata, size_t size, struct qcom_scm_pas_metadata *ctx) { dma_addr_t mdata_phys; @@ -585,7 +585,7 @@ int qcom_scm_pas_init_image(u32 peripheral, const void *metadata, size_t size, .svc = QCOM_SCM_SVC_PIL, .cmd = QCOM_SCM_PIL_PAS_INIT_IMAGE, .arginfo = QCOM_SCM_ARGS(2, QCOM_SCM_VAL, QCOM_SCM_RW), - .args[0] = peripheral, + .args[0] = pas_id, .owner = ARM_SMCCC_OWNER_SIP, }; struct qcom_scm_res res; @@ -656,20 +656,20 @@ EXPORT_SYMBOL_GPL(qcom_scm_pas_metadata_release); /** * qcom_scm_pas_mem_setup() - Prepare the memory related to a given peripheral * for firmware loading - * @peripheral: peripheral id + * @pas_id: peripheral authentication service id * @addr: start address of memory area to prepare * @size: size of the memory area to prepare * * Returns 0 on success. */ -int qcom_scm_pas_mem_setup(u32 peripheral, phys_addr_t addr, phys_addr_t size) +int qcom_scm_pas_mem_setup(u32 pas_id, phys_addr_t addr, phys_addr_t size) { int ret; struct qcom_scm_desc desc = { .svc = QCOM_SCM_SVC_PIL, .cmd = QCOM_SCM_PIL_PAS_MEM_SETUP, .arginfo = QCOM_SCM_ARGS(3), - .args[0] = peripheral, + .args[0] = pas_id, .args[1] = addr, .args[2] = size, .owner = ARM_SMCCC_OWNER_SIP, @@ -697,18 +697,18 @@ EXPORT_SYMBOL_GPL(qcom_scm_pas_mem_setup); /** * qcom_scm_pas_auth_and_reset() - Authenticate the given peripheral firmware * and reset the remote processor - * @peripheral: peripheral id + * @pas_id: peripheral authentication service id * * Return 0 on success. */ -int qcom_scm_pas_auth_and_reset(u32 peripheral) +int qcom_scm_pas_auth_and_reset(u32 pas_id) { int ret; struct qcom_scm_desc desc = { .svc = QCOM_SCM_SVC_PIL, .cmd = QCOM_SCM_PIL_PAS_AUTH_AND_RESET, .arginfo = QCOM_SCM_ARGS(1), - .args[0] = peripheral, + .args[0] = pas_id, .owner = ARM_SMCCC_OWNER_SIP, }; struct qcom_scm_res res; @@ -733,18 +733,18 @@ EXPORT_SYMBOL_GPL(qcom_scm_pas_auth_and_reset); /** * qcom_scm_pas_shutdown() - Shut down the remote processor - * @peripheral: peripheral id + * @pas_id: peripheral authentication service id * * Returns 0 on success. */ -int qcom_scm_pas_shutdown(u32 peripheral) +int qcom_scm_pas_shutdown(u32 pas_id) { int ret; struct qcom_scm_desc desc = { .svc = QCOM_SCM_SVC_PIL, .cmd = QCOM_SCM_PIL_PAS_SHUTDOWN, .arginfo = QCOM_SCM_ARGS(1), - .args[0] = peripheral, + .args[0] = pas_id, .owner = ARM_SMCCC_OWNER_SIP, }; struct qcom_scm_res res; @@ -770,18 +770,18 @@ EXPORT_SYMBOL_GPL(qcom_scm_pas_shutdown); /** * qcom_scm_pas_supported() - Check if the peripheral authentication service is * available for the given peripherial - * @peripheral: peripheral id + * @pas_id: peripheral authentication service id * * Returns true if PAS is supported for this peripheral, otherwise false. */ -bool qcom_scm_pas_supported(u32 peripheral) +bool qcom_scm_pas_supported(u32 pas_id) { int ret; struct qcom_scm_desc desc = { .svc = QCOM_SCM_SVC_PIL, .cmd = QCOM_SCM_PIL_PAS_IS_SUPPORTED, .arginfo = QCOM_SCM_ARGS(1), - .args[0] = peripheral, + .args[0] = pas_id, .owner = ARM_SMCCC_OWNER_SIP, }; struct qcom_scm_res res; diff --git a/include/linux/firmware/qcom/qcom_scm.h b/include/linux/firmware/qcom/qcom_scm.h index 6c29540ffeeec..a60e261af6855 100644 --- a/include/linux/firmware/qcom/qcom_scm.h +++ b/include/linux/firmware/qcom/qcom_scm.h @@ -82,13 +82,13 @@ struct qcom_scm_camera_qos { int qcom_scm_camera_update_camnoc_qos(uint32_t use_case_id, uint32_t qos_cnt, struct qcom_scm_camera_qos *scm_buf); -int qcom_scm_pas_init_image(u32 peripheral, const void *metadata, size_t size, +int qcom_scm_pas_init_image(u32 pas_id, const void *metadata, size_t size, struct qcom_scm_pas_metadata *ctx); void qcom_scm_pas_metadata_release(struct qcom_scm_pas_metadata *ctx); -int qcom_scm_pas_mem_setup(u32 peripheral, phys_addr_t addr, phys_addr_t size); -int qcom_scm_pas_auth_and_reset(u32 peripheral); -int qcom_scm_pas_shutdown(u32 peripheral); -bool qcom_scm_pas_supported(u32 peripheral); +int qcom_scm_pas_mem_setup(u32 pas_id, phys_addr_t addr, phys_addr_t size); +int qcom_scm_pas_auth_and_reset(u32 pas_id); +int qcom_scm_pas_shutdown(u32 pas_id); +bool qcom_scm_pas_supported(u32 pas_id); int qcom_scm_io_readl(phys_addr_t addr, unsigned int *val); int qcom_scm_io_writel(phys_addr_t addr, unsigned int val); From d90a3c260ff2b3b9033ffd129badfd38155f2faf Mon Sep 17 00:00:00 2001 From: Mukesh Ojha Date: Mon, 5 Jan 2026 18:52:52 +0530 Subject: [PATCH 2229/2333] FROMLIST: firmware: qcom_scm: Introduce PAS context allocator helper function When the Peripheral Authentication Service (PAS) method runs on a SoC where Linux operates at EL2 (i.e., without the Gunyah hypervisor), the reset sequences are handled by TrustZone. In such cases, Linux must perform additional steps before invoking PAS SMC calls, such as creating a SHM bridge. Therefore, PAS SMC calls require awareness and handling of these additional steps when Linux runs at EL2. To support this, there is a need for a data structure that can be initialized prior to invoking any SMC or MDT functions. This structure allows those functions to determine whether they are operating in the presence or absence of the Gunyah hypervisor and behave accordingly. Currently, remoteproc and non-remoteproc subsystems use different variants of the MDT loader helper API, primarily due to differences in metadata context handling. Remoteproc subsystems retain the metadata context until authentication and reset are completed, while non-remoteproc subsystems (e.g., video, graphics, IPA, etc.) do not retain the metadata context and can free it within the qcom_scm_pas_init() call by passing a NULL context parameter and due to these differences, it is not possible to extend metadata context handling to support remoteproc and non remoteproc subsystem use PAS operations, when Linux operates at EL2. Add PAS context data structure allocator helper function. Signed-off-by: Mukesh Ojha Link: https://lore.kernel.org/r/20260105-kvmrprocv10-v10-4-022e96815380@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- drivers/firmware/qcom/qcom_scm.c | 34 ++++++++++++++++++++++++++ include/linux/firmware/qcom/qcom_scm.h | 14 +++++++++++ 2 files changed, 48 insertions(+) diff --git a/drivers/firmware/qcom/qcom_scm.c b/drivers/firmware/qcom/qcom_scm.c index 88f9181914d38..57721ab739017 100644 --- a/drivers/firmware/qcom/qcom_scm.c +++ b/drivers/firmware/qcom/qcom_scm.c @@ -558,6 +558,40 @@ static void qcom_scm_set_download_mode(u32 dload_mode) dev_err(__scm->dev, "failed to set download mode: %d\n", ret); } +/** + * devm_qcom_scm_pas_context_alloc() - Allocate peripheral authentication service + * context for a given peripheral + * + * PAS context is device-resource managed, so the caller does not need + * to worry about freeing the context memory. + * + * @dev: PAS firmware device + * @pas_id: peripheral authentication service id + * @mem_phys: Subsystem reserve memory start address + * @mem_size: Subsystem reserve memory size + * + * Returns: The new PAS context, or ERR_PTR() on failure. + */ +struct qcom_scm_pas_context *devm_qcom_scm_pas_context_alloc(struct device *dev, + u32 pas_id, + phys_addr_t mem_phys, + size_t mem_size) +{ + struct qcom_scm_pas_context *ctx; + + ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return ERR_PTR(-ENOMEM); + + ctx->dev = dev; + ctx->pas_id = pas_id; + ctx->mem_phys = mem_phys; + ctx->mem_size = mem_size; + + return ctx; +} +EXPORT_SYMBOL_GPL(devm_qcom_scm_pas_context_alloc); + /** * qcom_scm_pas_init_image() - Initialize peripheral authentication service * state machine for a given peripheral, using the diff --git a/include/linux/firmware/qcom/qcom_scm.h b/include/linux/firmware/qcom/qcom_scm.h index a60e261af6855..c4f8b345a499d 100644 --- a/include/linux/firmware/qcom/qcom_scm.h +++ b/include/linux/firmware/qcom/qcom_scm.h @@ -82,6 +82,20 @@ struct qcom_scm_camera_qos { int qcom_scm_camera_update_camnoc_qos(uint32_t use_case_id, uint32_t qos_cnt, struct qcom_scm_camera_qos *scm_buf); +struct qcom_scm_pas_context { + struct device *dev; + u32 pas_id; + phys_addr_t mem_phys; + size_t mem_size; + void *ptr; + dma_addr_t phys; + ssize_t size; +}; + +struct qcom_scm_pas_context *devm_qcom_scm_pas_context_alloc(struct device *dev, + u32 pas_id, + phys_addr_t mem_phys, + size_t mem_size); int qcom_scm_pas_init_image(u32 pas_id, const void *metadata, size_t size, struct qcom_scm_pas_metadata *ctx); void qcom_scm_pas_metadata_release(struct qcom_scm_pas_metadata *ctx); From 291e71d4f6ac0897d32eb064c8c03265dfc53ed3 Mon Sep 17 00:00:00 2001 From: Mukesh Ojha Date: Mon, 5 Jan 2026 18:52:53 +0530 Subject: [PATCH 2230/2333] FROMLIST: remoteproc: pas: Replace metadata context with PAS context structure As a superset of the existing metadata context, the PAS context structure enables both remoteproc and non-remoteproc subsystems to better support scenarios where the SoC runs with or without the Gunyah hypervisor. To reflect this, relevant SCM and metadata functions are updated to incorporate PAS context awareness and remove metadata context data structure completely. Signed-off-by: Mukesh Ojha Link: https://lore.kernel.org/r/20260105-kvmrprocv10-v10-5-022e96815380@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- drivers/firmware/qcom/qcom_scm.c | 8 +++--- drivers/remoteproc/qcom_q6v5_pas.c | 38 ++++++++++++++++++-------- drivers/soc/qcom/mdt_loader.c | 4 +-- include/linux/firmware/qcom/qcom_scm.h | 10 ++----- include/linux/soc/qcom/mdt_loader.h | 6 ++-- 5 files changed, 38 insertions(+), 28 deletions(-) diff --git a/drivers/firmware/qcom/qcom_scm.c b/drivers/firmware/qcom/qcom_scm.c index 57721ab739017..f42ff02ddfc9a 100644 --- a/drivers/firmware/qcom/qcom_scm.c +++ b/drivers/firmware/qcom/qcom_scm.c @@ -601,7 +601,7 @@ EXPORT_SYMBOL_GPL(devm_qcom_scm_pas_context_alloc); * and optional blob of data used for authenticating the metadata * and the rest of the firmware * @size: size of the metadata - * @ctx: optional metadata context + * @ctx: optional pas context * * Return: 0 on success. * @@ -610,7 +610,7 @@ EXPORT_SYMBOL_GPL(devm_qcom_scm_pas_context_alloc); * qcom_scm_pas_metadata_release() by the caller. */ int qcom_scm_pas_init_image(u32 pas_id, const void *metadata, size_t size, - struct qcom_scm_pas_metadata *ctx) + struct qcom_scm_pas_context *ctx) { dma_addr_t mdata_phys; void *mdata_buf; @@ -674,9 +674,9 @@ EXPORT_SYMBOL_GPL(qcom_scm_pas_init_image); /** * qcom_scm_pas_metadata_release() - release metadata context - * @ctx: metadata context + * @ctx: pas context */ -void qcom_scm_pas_metadata_release(struct qcom_scm_pas_metadata *ctx) +void qcom_scm_pas_metadata_release(struct qcom_scm_pas_context *ctx) { if (!ctx->ptr) return; diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c index 158bcd6cc85c5..5f90976e5b418 100644 --- a/drivers/remoteproc/qcom_q6v5_pas.c +++ b/drivers/remoteproc/qcom_q6v5_pas.c @@ -117,8 +117,8 @@ struct qcom_pas { struct qcom_rproc_ssr ssr_subdev; struct qcom_sysmon *sysmon; - struct qcom_scm_pas_metadata pas_metadata; - struct qcom_scm_pas_metadata dtb_pas_metadata; + struct qcom_scm_pas_context *pas_ctx; + struct qcom_scm_pas_context *dtb_pas_ctx; }; static void qcom_pas_segment_dump(struct rproc *rproc, @@ -211,9 +211,9 @@ static int qcom_pas_unprepare(struct rproc *rproc) * auth_and_reset() was successful, but in other cases clean it up * here. */ - qcom_scm_pas_metadata_release(&pas->pas_metadata); + qcom_scm_pas_metadata_release(pas->pas_ctx); if (pas->dtb_pas_id) - qcom_scm_pas_metadata_release(&pas->dtb_pas_metadata); + qcom_scm_pas_metadata_release(pas->dtb_pas_ctx); return 0; } @@ -241,7 +241,7 @@ static int qcom_pas_load(struct rproc *rproc, const struct firmware *fw) ret = qcom_mdt_pas_init(pas->dev, pas->dtb_firmware, pas->dtb_firmware_name, pas->dtb_pas_id, pas->dtb_mem_phys, - &pas->dtb_pas_metadata); + pas->dtb_pas_ctx); if (ret) goto release_dtb_firmware; @@ -255,7 +255,7 @@ static int qcom_pas_load(struct rproc *rproc, const struct firmware *fw) return 0; release_dtb_metadata: - qcom_scm_pas_metadata_release(&pas->dtb_pas_metadata); + qcom_scm_pas_metadata_release(pas->dtb_pas_ctx); release_dtb_firmware: release_firmware(pas->dtb_firmware); @@ -306,7 +306,7 @@ static int qcom_pas_start(struct rproc *rproc) } ret = qcom_mdt_pas_init(pas->dev, pas->firmware, rproc->firmware, pas->pas_id, - pas->mem_phys, &pas->pas_metadata); + pas->mem_phys, pas->pas_ctx); if (ret) goto disable_px_supply; @@ -332,9 +332,9 @@ static int qcom_pas_start(struct rproc *rproc) goto release_pas_metadata; } - qcom_scm_pas_metadata_release(&pas->pas_metadata); + qcom_scm_pas_metadata_release(pas->pas_ctx); if (pas->dtb_pas_id) - qcom_scm_pas_metadata_release(&pas->dtb_pas_metadata); + qcom_scm_pas_metadata_release(pas->dtb_pas_ctx); /* firmware is used to pass reference from qcom_pas_start(), drop it now */ pas->firmware = NULL; @@ -342,9 +342,9 @@ static int qcom_pas_start(struct rproc *rproc) return 0; release_pas_metadata: - qcom_scm_pas_metadata_release(&pas->pas_metadata); + qcom_scm_pas_metadata_release(pas->pas_ctx); if (pas->dtb_pas_id) - qcom_scm_pas_metadata_release(&pas->dtb_pas_metadata); + qcom_scm_pas_metadata_release(pas->dtb_pas_ctx); disable_px_supply: if (pas->px_supply) regulator_disable(pas->px_supply); @@ -779,6 +779,22 @@ static int qcom_pas_probe(struct platform_device *pdev) } qcom_add_ssr_subdev(rproc, &pas->ssr_subdev, desc->ssr_name); + + pas->pas_ctx = devm_qcom_scm_pas_context_alloc(pas->dev, pas->pas_id, + pas->mem_phys, pas->mem_size); + if (IS_ERR(pas->pas_ctx)) { + ret = PTR_ERR(pas->pas_ctx); + goto remove_ssr_sysmon; + } + + pas->dtb_pas_ctx = devm_qcom_scm_pas_context_alloc(pas->dev, pas->dtb_pas_id, + pas->dtb_mem_phys, + pas->dtb_mem_size); + if (IS_ERR(pas->dtb_pas_ctx)) { + ret = PTR_ERR(pas->dtb_pas_ctx); + goto remove_ssr_sysmon; + } + ret = rproc_add(rproc); if (ret) goto remove_ssr_sysmon; diff --git a/drivers/soc/qcom/mdt_loader.c b/drivers/soc/qcom/mdt_loader.c index a5c80d4fcc366..fe35038c5342e 100644 --- a/drivers/soc/qcom/mdt_loader.c +++ b/drivers/soc/qcom/mdt_loader.c @@ -234,13 +234,13 @@ EXPORT_SYMBOL_GPL(qcom_mdt_read_metadata); * @fw_name: name of the firmware, for construction of segment file names * @pas_id: PAS identifier * @mem_phys: physical address of allocated memory region - * @ctx: PAS metadata context, to be released by caller + * @ctx: PAS context, ctx->metadata to be released by caller * * Returns 0 on success, negative errno otherwise. */ int qcom_mdt_pas_init(struct device *dev, const struct firmware *fw, const char *fw_name, int pas_id, phys_addr_t mem_phys, - struct qcom_scm_pas_metadata *ctx) + struct qcom_scm_pas_context *ctx) { const struct elf32_phdr *phdrs; const struct elf32_phdr *phdr; diff --git a/include/linux/firmware/qcom/qcom_scm.h b/include/linux/firmware/qcom/qcom_scm.h index c4f8b345a499d..c8409743b36ff 100644 --- a/include/linux/firmware/qcom/qcom_scm.h +++ b/include/linux/firmware/qcom/qcom_scm.h @@ -68,12 +68,6 @@ int qcom_scm_set_warm_boot_addr(void *entry); void qcom_scm_cpu_power_down(u32 flags); int qcom_scm_set_remote_state(u32 state, u32 id); -struct qcom_scm_pas_metadata { - void *ptr; - dma_addr_t phys; - ssize_t size; -}; - struct qcom_scm_camera_qos { u32 offset; u32 val; @@ -97,8 +91,8 @@ struct qcom_scm_pas_context *devm_qcom_scm_pas_context_alloc(struct device *dev, phys_addr_t mem_phys, size_t mem_size); int qcom_scm_pas_init_image(u32 pas_id, const void *metadata, size_t size, - struct qcom_scm_pas_metadata *ctx); -void qcom_scm_pas_metadata_release(struct qcom_scm_pas_metadata *ctx); + struct qcom_scm_pas_context *ctx); +void qcom_scm_pas_metadata_release(struct qcom_scm_pas_context *ctx); int qcom_scm_pas_mem_setup(u32 pas_id, phys_addr_t addr, phys_addr_t size); int qcom_scm_pas_auth_and_reset(u32 pas_id); int qcom_scm_pas_shutdown(u32 pas_id); diff --git a/include/linux/soc/qcom/mdt_loader.h b/include/linux/soc/qcom/mdt_loader.h index 8ea8230579a20..07c2788418166 100644 --- a/include/linux/soc/qcom/mdt_loader.h +++ b/include/linux/soc/qcom/mdt_loader.h @@ -10,14 +10,14 @@ struct device; struct firmware; -struct qcom_scm_pas_metadata; +struct qcom_scm_pas_context; #if IS_ENABLED(CONFIG_QCOM_MDT_LOADER) ssize_t qcom_mdt_get_size(const struct firmware *fw); int qcom_mdt_pas_init(struct device *dev, const struct firmware *fw, const char *fw_name, int pas_id, phys_addr_t mem_phys, - struct qcom_scm_pas_metadata *pas_metadata_ctx); + struct qcom_scm_pas_context *pas_ctx); int qcom_mdt_load(struct device *dev, const struct firmware *fw, const char *fw_name, int pas_id, void *mem_region, phys_addr_t mem_phys, size_t mem_size, @@ -39,7 +39,7 @@ static inline ssize_t qcom_mdt_get_size(const struct firmware *fw) static inline int qcom_mdt_pas_init(struct device *dev, const struct firmware *fw, const char *fw_name, int pas_id, phys_addr_t mem_phys, - struct qcom_scm_pas_metadata *pas_metadata_ctx) + struct qcom_scm_pas_context *pas_ctx) { return -ENODEV; } From 6ca8c713230a9de741e05a4665e9b279b673ed27 Mon Sep 17 00:00:00 2001 From: Mukesh Ojha Date: Mon, 5 Jan 2026 18:52:54 +0530 Subject: [PATCH 2231/2333] FROMLIST: soc: qcom: mdtloader: Add PAS context aware qcom_mdt_pas_load() function Introduce a new PAS context-aware function, qcom_mdt_pas_load(), for remote processor drivers. This function utilizes the PAS context pointer returned from qcom_scm_pas_ctx_init() to perform firmware metadata verification and memory setup via SMC calls. The qcom_mdt_pas_load() and qcom_mdt_load() functions are largely similar, but the former is designed for clients using the PAS context-based data structure. Over time, all users of qcom_mdt_load() can be migrated to use qcom_mdt_pas_load() for consistency and improved abstraction. As the remoteproc PAS driver (qcom_q6v5_pas) has already adopted the PAS context-based approach, update it to use qcom_mdt_pas_load(). Reviewed-by: Konrad Dybcio Signed-off-by: Mukesh Ojha Link: https://lore.kernel.org/r/20260105-kvmrprocv10-v10-6-022e96815380@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- drivers/remoteproc/qcom_q6v5_pas.c | 24 +++++----------------- drivers/soc/qcom/mdt_loader.c | 31 +++++++++++++++++++++++++++++ include/linux/soc/qcom/mdt_loader.h | 10 ++++++++++ 3 files changed, 46 insertions(+), 19 deletions(-) diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c index 5f90976e5b418..0c4ec72352e3e 100644 --- a/drivers/remoteproc/qcom_q6v5_pas.c +++ b/drivers/remoteproc/qcom_q6v5_pas.c @@ -239,15 +239,9 @@ static int qcom_pas_load(struct rproc *rproc, const struct firmware *fw) return ret; } - ret = qcom_mdt_pas_init(pas->dev, pas->dtb_firmware, pas->dtb_firmware_name, - pas->dtb_pas_id, pas->dtb_mem_phys, - pas->dtb_pas_ctx); - if (ret) - goto release_dtb_firmware; - - ret = qcom_mdt_load_no_init(pas->dev, pas->dtb_firmware, pas->dtb_firmware_name, - pas->dtb_mem_region, pas->dtb_mem_phys, - pas->dtb_mem_size, &pas->dtb_mem_reloc); + ret = qcom_mdt_pas_load(pas->dtb_pas_ctx, pas->dtb_firmware, + pas->dtb_firmware_name, pas->dtb_mem_region, + &pas->dtb_mem_reloc); if (ret) goto release_dtb_metadata; } @@ -256,8 +250,6 @@ static int qcom_pas_load(struct rproc *rproc, const struct firmware *fw) release_dtb_metadata: qcom_scm_pas_metadata_release(pas->dtb_pas_ctx); - -release_dtb_firmware: release_firmware(pas->dtb_firmware); return ret; @@ -305,14 +297,8 @@ static int qcom_pas_start(struct rproc *rproc) } } - ret = qcom_mdt_pas_init(pas->dev, pas->firmware, rproc->firmware, pas->pas_id, - pas->mem_phys, pas->pas_ctx); - if (ret) - goto disable_px_supply; - - ret = qcom_mdt_load_no_init(pas->dev, pas->firmware, rproc->firmware, - pas->mem_region, pas->mem_phys, pas->mem_size, - &pas->mem_reloc); + ret = qcom_mdt_pas_load(pas->pas_ctx, pas->firmware, rproc->firmware, + pas->mem_region, &pas->mem_reloc); if (ret) goto release_pas_metadata; diff --git a/drivers/soc/qcom/mdt_loader.c b/drivers/soc/qcom/mdt_loader.c index fe35038c5342e..847941d232f74 100644 --- a/drivers/soc/qcom/mdt_loader.c +++ b/drivers/soc/qcom/mdt_loader.c @@ -486,5 +486,36 @@ int qcom_mdt_load_no_init(struct device *dev, const struct firmware *fw, } EXPORT_SYMBOL_GPL(qcom_mdt_load_no_init); +/** + * qcom_mdt_pas_load - Loads and authenticates the metadata of the firmware + * (typically contained in the .mdt file), followed by loading the actual + * firmware segments (e.g., .bXX files). Authentication of the segments done + * by a separate call. + * + * The PAS context must be initialized using qcom_scm_pas_context_init() + * prior to invoking this function. + * + * @ctx: Pointer to the PAS (Peripheral Authentication Service) context + * @fw: Firmware object representing the .mdt file + * @firmware: Name of the firmware used to construct segment file names + * @mem_region: Memory region allocated for loading the firmware + * @reloc_base: Physical address adjusted after relocation + * + * Return: 0 on success or a negative error code on failure. + */ +int qcom_mdt_pas_load(struct qcom_scm_pas_context *ctx, const struct firmware *fw, + const char *firmware, void *mem_region, phys_addr_t *reloc_base) +{ + int ret; + + ret = qcom_mdt_pas_init(ctx->dev, fw, firmware, ctx->pas_id, ctx->mem_phys, ctx); + if (ret) + return ret; + + return qcom_mdt_load_no_init(ctx->dev, fw, firmware, mem_region, ctx->mem_phys, + ctx->mem_size, reloc_base); +} +EXPORT_SYMBOL_GPL(qcom_mdt_pas_load); + MODULE_DESCRIPTION("Firmware parser for Qualcomm MDT format"); MODULE_LICENSE("GPL v2"); diff --git a/include/linux/soc/qcom/mdt_loader.h b/include/linux/soc/qcom/mdt_loader.h index 07c2788418166..7d57746fbbfa5 100644 --- a/include/linux/soc/qcom/mdt_loader.h +++ b/include/linux/soc/qcom/mdt_loader.h @@ -23,6 +23,9 @@ int qcom_mdt_load(struct device *dev, const struct firmware *fw, phys_addr_t mem_phys, size_t mem_size, phys_addr_t *reloc_base); +int qcom_mdt_pas_load(struct qcom_scm_pas_context *ctx, const struct firmware *fw, + const char *firmware, void *mem_region, phys_addr_t *reloc_base); + int qcom_mdt_load_no_init(struct device *dev, const struct firmware *fw, const char *fw_name, void *mem_region, phys_addr_t mem_phys, size_t mem_size, @@ -52,6 +55,13 @@ static inline int qcom_mdt_load(struct device *dev, const struct firmware *fw, return -ENODEV; } +static inline int qcom_mdt_pas_load(struct qcom_scm_pas_context *ctx, + const struct firmware *fw, const char *firmware, + void *mem_region, phys_addr_t *reloc_base) +{ + return -ENODEV; +} + static inline int qcom_mdt_load_no_init(struct device *dev, const struct firmware *fw, const char *fw_name, void *mem_region, From 7b1787865b65f38fac3da72715ebf12a3e4b95ff Mon Sep 17 00:00:00 2001 From: Mukesh Ojha Date: Mon, 5 Jan 2026 18:52:55 +0530 Subject: [PATCH 2232/2333] FROMLIST: soc: qcom: mdtloader: Remove qcom_mdt_pas_init() from exported symbols qcom_mdt_pas_init() was previously used only by the remoteproc driver (drivers/remoteproc/qcom_q6v5_pas.c). Since that driver has now transitioned to using PAS context-based qcom_mdt_pas_load() function, making qcom_mdt_pas_init() obsolete for external use. Removes qcom_mdt_pas_init() from the list of exported symbols and make it static to limit its scope to internal use within mdtloader. Reviewed-by: Konrad Dybcio Signed-off-by: Mukesh Ojha Link: https://lore.kernel.org/r/20260105-kvmrprocv10-v10-7-022e96815380@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/mdt_loader.c | 22 +++++----------------- include/linux/soc/qcom/mdt_loader.h | 10 ---------- 2 files changed, 5 insertions(+), 27 deletions(-) diff --git a/drivers/soc/qcom/mdt_loader.c b/drivers/soc/qcom/mdt_loader.c index 847941d232f74..1ca03472552cd 100644 --- a/drivers/soc/qcom/mdt_loader.c +++ b/drivers/soc/qcom/mdt_loader.c @@ -227,20 +227,9 @@ void *qcom_mdt_read_metadata(const struct firmware *fw, size_t *data_len, } EXPORT_SYMBOL_GPL(qcom_mdt_read_metadata); -/** - * qcom_mdt_pas_init() - initialize PAS region for firmware loading - * @dev: device handle to associate resources with - * @fw: firmware object for the mdt file - * @fw_name: name of the firmware, for construction of segment file names - * @pas_id: PAS identifier - * @mem_phys: physical address of allocated memory region - * @ctx: PAS context, ctx->metadata to be released by caller - * - * Returns 0 on success, negative errno otherwise. - */ -int qcom_mdt_pas_init(struct device *dev, const struct firmware *fw, - const char *fw_name, int pas_id, phys_addr_t mem_phys, - struct qcom_scm_pas_context *ctx) +static int __qcom_mdt_pas_init(struct device *dev, const struct firmware *fw, + const char *fw_name, int pas_id, phys_addr_t mem_phys, + struct qcom_scm_pas_context *ctx) { const struct elf32_phdr *phdrs; const struct elf32_phdr *phdr; @@ -302,7 +291,6 @@ int qcom_mdt_pas_init(struct device *dev, const struct firmware *fw, out: return ret; } -EXPORT_SYMBOL_GPL(qcom_mdt_pas_init); static bool qcom_mdt_bins_are_split(const struct firmware *fw) { @@ -456,7 +444,7 @@ int qcom_mdt_load(struct device *dev, const struct firmware *fw, { int ret; - ret = qcom_mdt_pas_init(dev, fw, firmware, pas_id, mem_phys, NULL); + ret = __qcom_mdt_pas_init(dev, fw, firmware, pas_id, mem_phys, NULL); if (ret) return ret; @@ -508,7 +496,7 @@ int qcom_mdt_pas_load(struct qcom_scm_pas_context *ctx, const struct firmware *f { int ret; - ret = qcom_mdt_pas_init(ctx->dev, fw, firmware, ctx->pas_id, ctx->mem_phys, ctx); + ret = __qcom_mdt_pas_init(ctx->dev, fw, firmware, ctx->pas_id, ctx->mem_phys, ctx); if (ret) return ret; diff --git a/include/linux/soc/qcom/mdt_loader.h b/include/linux/soc/qcom/mdt_loader.h index 7d57746fbbfa5..82372e0db0a18 100644 --- a/include/linux/soc/qcom/mdt_loader.h +++ b/include/linux/soc/qcom/mdt_loader.h @@ -15,9 +15,6 @@ struct qcom_scm_pas_context; #if IS_ENABLED(CONFIG_QCOM_MDT_LOADER) ssize_t qcom_mdt_get_size(const struct firmware *fw); -int qcom_mdt_pas_init(struct device *dev, const struct firmware *fw, - const char *fw_name, int pas_id, phys_addr_t mem_phys, - struct qcom_scm_pas_context *pas_ctx); int qcom_mdt_load(struct device *dev, const struct firmware *fw, const char *fw_name, int pas_id, void *mem_region, phys_addr_t mem_phys, size_t mem_size, @@ -40,13 +37,6 @@ static inline ssize_t qcom_mdt_get_size(const struct firmware *fw) return -ENODEV; } -static inline int qcom_mdt_pas_init(struct device *dev, const struct firmware *fw, - const char *fw_name, int pas_id, phys_addr_t mem_phys, - struct qcom_scm_pas_context *pas_ctx) -{ - return -ENODEV; -} - static inline int qcom_mdt_load(struct device *dev, const struct firmware *fw, const char *fw_name, int pas_id, void *mem_region, phys_addr_t mem_phys, From 8785b5e68b79112d0f7518510aad930694ce1c31 Mon Sep 17 00:00:00 2001 From: Mukesh Ojha Date: Mon, 5 Jan 2026 18:52:56 +0530 Subject: [PATCH 2233/2333] FROMLIST: firmware: qcom_scm: Add a prep version of auth_and_reset function For memory passed to TrustZone (TZ), it must either be part of a pool registered with TZ or explicitly registered via SHMbridge SMC calls. When Gunyah hypervisor is present, PAS SMC calls from Linux running at EL1 are trapped by Gunyah running @ EL2, which handles SHMbridge creation for both metadata and remoteproc carveout memory before invoking the calls to TZ. On SoCs running with a non-Gunyah-based hypervisor, Linux must take responsibility for creating the SHM bridge before invoking PAS SMC calls. For the auth_and_reset() call, the remoteproc carveout memory must first be registered with TZ via a SHMbridge SMC call and once authentication and reset are complete, the SHMbridge memory can be deregistered. Introduce qcom_scm_pas_prepare_and_auth_reset(), which sets up the SHM bridge over the remoteproc carveout memory when Linux operates at EL2. This behavior is indicated by a new field added to the PAS context data structure. The function then invokes the auth_and_reset SMC call. Signed-off-by: Mukesh Ojha Link: https://lore.kernel.org/r/20260105-kvmrprocv10-v10-8-022e96815380@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- drivers/firmware/qcom/qcom_scm.c | 47 ++++++++++++++++++++++++++ include/linux/firmware/qcom/qcom_scm.h | 2 ++ 2 files changed, 49 insertions(+) diff --git a/drivers/firmware/qcom/qcom_scm.c b/drivers/firmware/qcom/qcom_scm.c index f42ff02ddfc9a..abf6b7ccf5054 100644 --- a/drivers/firmware/qcom/qcom_scm.c +++ b/drivers/firmware/qcom/qcom_scm.c @@ -765,6 +765,53 @@ int qcom_scm_pas_auth_and_reset(u32 pas_id) } EXPORT_SYMBOL_GPL(qcom_scm_pas_auth_and_reset); +/** + * qcom_scm_pas_prepare_and_auth_reset() - Prepare, authenticate, and reset the + * remote processor + * + * @ctx: Context saved during call to qcom_scm_pas_context_init() + * + * This function performs the necessary steps to prepare a PAS subsystem, + * authenticate it using the provided metadata, and initiate a reset sequence. + * + * It should be used when Linux is in control setting up the IOMMU hardware + * for remote subsystem during secure firmware loading processes. The preparation + * step sets up a shmbridge over the firmware memory before TrustZone accesses the + * firmware memory region for authentication. The authentication step verifies + * the integrity and authenticity of the firmware or configuration using secure + * metadata. Finally, the reset step ensures the subsystem starts in a clean and + * sane state. + * + * Return: 0 on success, negative errno on failure. + */ +int qcom_scm_pas_prepare_and_auth_reset(struct qcom_scm_pas_context *ctx) +{ + u64 handle; + int ret; + + /* + * When Linux running @ EL1, Gunyah hypervisor running @ EL2 traps the + * auth_and_reset call and create an shmbridge on the remote subsystem + * memory region and then invokes a call to TrustZone to authenticate. + */ + if (!ctx->use_tzmem) + return qcom_scm_pas_auth_and_reset(ctx->pas_id); + + /* + * When Linux runs @ EL2 Linux must create the shmbridge itself and then + * subsequently call TrustZone for authenticate and reset. + */ + ret = qcom_tzmem_shm_bridge_create(ctx->mem_phys, ctx->mem_size, &handle); + if (ret) + return ret; + + ret = qcom_scm_pas_auth_and_reset(ctx->pas_id); + qcom_tzmem_shm_bridge_delete(handle); + + return ret; +} +EXPORT_SYMBOL_GPL(qcom_scm_pas_prepare_and_auth_reset); + /** * qcom_scm_pas_shutdown() - Shut down the remote processor * @pas_id: peripheral authentication service id diff --git a/include/linux/firmware/qcom/qcom_scm.h b/include/linux/firmware/qcom/qcom_scm.h index c8409743b36ff..3d568b3b24d6d 100644 --- a/include/linux/firmware/qcom/qcom_scm.h +++ b/include/linux/firmware/qcom/qcom_scm.h @@ -84,6 +84,7 @@ struct qcom_scm_pas_context { void *ptr; dma_addr_t phys; ssize_t size; + bool use_tzmem; }; struct qcom_scm_pas_context *devm_qcom_scm_pas_context_alloc(struct device *dev, @@ -97,6 +98,7 @@ int qcom_scm_pas_mem_setup(u32 pas_id, phys_addr_t addr, phys_addr_t size); int qcom_scm_pas_auth_and_reset(u32 pas_id); int qcom_scm_pas_shutdown(u32 pas_id); bool qcom_scm_pas_supported(u32 pas_id); +int qcom_scm_pas_prepare_and_auth_reset(struct qcom_scm_pas_context *ctx); int qcom_scm_io_readl(phys_addr_t addr, unsigned int *val); int qcom_scm_io_writel(phys_addr_t addr, unsigned int val); From 19cef75bb69422db104f9e116e3c7db143a5390e Mon Sep 17 00:00:00 2001 From: Mukesh Ojha Date: Mon, 5 Jan 2026 18:52:57 +0530 Subject: [PATCH 2234/2333] FROMLIST: firmware: qcom_scm: Refactor qcom_scm_pas_init_image() Refactor qcom_scm_pas_init_image() by moving the memory allocation, copy, and free operations to a higher-level function, and isolate the actual SMC call in a separate function. The main intention is to allow flexibility for different allocators and to respect any constraints that the allocator API may impose before invoking the actual SCM function. Reviewed-by: Bryan O'Donoghue Reviewed-by: Konrad Dybcio Signed-off-by: Mukesh Ojha Link: https://lore.kernel.org/r/20260105-kvmrprocv10-v10-9-022e96815380@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- drivers/firmware/qcom/qcom_scm.c | 58 ++++++++++++++++++-------------- 1 file changed, 33 insertions(+), 25 deletions(-) diff --git a/drivers/firmware/qcom/qcom_scm.c b/drivers/firmware/qcom/qcom_scm.c index abf6b7ccf5054..c06ace66f7aae 100644 --- a/drivers/firmware/qcom/qcom_scm.c +++ b/drivers/firmware/qcom/qcom_scm.c @@ -592,6 +592,37 @@ struct qcom_scm_pas_context *devm_qcom_scm_pas_context_alloc(struct device *dev, } EXPORT_SYMBOL_GPL(devm_qcom_scm_pas_context_alloc); +static int __qcom_scm_pas_init_image(u32 pas_id, dma_addr_t mdata_phys, + struct qcom_scm_res *res) +{ + struct qcom_scm_desc desc = { + .svc = QCOM_SCM_SVC_PIL, + .cmd = QCOM_SCM_PIL_PAS_INIT_IMAGE, + .arginfo = QCOM_SCM_ARGS(2, QCOM_SCM_VAL, QCOM_SCM_RW), + .args[0] = pas_id, + .owner = ARM_SMCCC_OWNER_SIP, + }; + int ret; + + ret = qcom_scm_clk_enable(); + if (ret) + return ret; + + ret = qcom_scm_bw_enable(); + if (ret) + goto disable_clk; + + desc.args[1] = mdata_phys; + + ret = qcom_scm_call(__scm->dev, &desc, res); + qcom_scm_bw_disable(); + +disable_clk: + qcom_scm_clk_disable(); + + return ret; +} + /** * qcom_scm_pas_init_image() - Initialize peripheral authentication service * state machine for a given peripheral, using the @@ -612,17 +643,10 @@ EXPORT_SYMBOL_GPL(devm_qcom_scm_pas_context_alloc); int qcom_scm_pas_init_image(u32 pas_id, const void *metadata, size_t size, struct qcom_scm_pas_context *ctx) { + struct qcom_scm_res res; dma_addr_t mdata_phys; void *mdata_buf; int ret; - struct qcom_scm_desc desc = { - .svc = QCOM_SCM_SVC_PIL, - .cmd = QCOM_SCM_PIL_PAS_INIT_IMAGE, - .arginfo = QCOM_SCM_ARGS(2, QCOM_SCM_VAL, QCOM_SCM_RW), - .args[0] = pas_id, - .owner = ARM_SMCCC_OWNER_SIP, - }; - struct qcom_scm_res res; /* * During the scm call memory protection will be enabled for the meta @@ -643,23 +667,7 @@ int qcom_scm_pas_init_image(u32 pas_id, const void *metadata, size_t size, memcpy(mdata_buf, metadata, size); - ret = qcom_scm_clk_enable(); - if (ret) - goto out; - - ret = qcom_scm_bw_enable(); - if (ret) - goto disable_clk; - - desc.args[1] = mdata_phys; - - ret = qcom_scm_call(__scm->dev, &desc, &res); - qcom_scm_bw_disable(); - -disable_clk: - qcom_scm_clk_disable(); - -out: + ret = __qcom_scm_pas_init_image(pas_id, mdata_phys, &res); if (ret < 0 || !ctx) { dma_free_coherent(__scm->dev, size, mdata_buf, mdata_phys); } else if (ctx) { From 56304a4f957bb01c504ce1cb609e8f67388443fc Mon Sep 17 00:00:00 2001 From: Mukesh Ojha Date: Mon, 5 Jan 2026 18:52:58 +0530 Subject: [PATCH 2235/2333] FROMLIST: firmware: qcom_scm: Add SHM bridge handling for PAS when running without QHEE On SoCs running with a non-Gunyah-based hypervisor, Linux must take responsibility for creating the SHM bridge both for metadata (before calling qcom_scm_pas_init_image()) and for remoteproc memory (before calling qcom_scm_pas_auth_and_reset()). We have taken care the things required for qcom_scm_pas_auth_and_reset(). Lets put these awareness of above conditions into qcom_scm_pas_init_image() and qcom_scm_pas_metadata_release(). Reviewed-by: Konrad Dybcio Signed-off-by: Mukesh Ojha Link: https://lore.kernel.org/r/20260105-kvmrprocv10-v10-10-022e96815380@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- drivers/firmware/qcom/qcom_scm.c | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/drivers/firmware/qcom/qcom_scm.c b/drivers/firmware/qcom/qcom_scm.c index c06ace66f7aae..ca0ce2f55642d 100644 --- a/drivers/firmware/qcom/qcom_scm.c +++ b/drivers/firmware/qcom/qcom_scm.c @@ -623,6 +623,30 @@ static int __qcom_scm_pas_init_image(u32 pas_id, dma_addr_t mdata_phys, return ret; } +static int qcom_scm_pas_prep_and_init_image(struct qcom_scm_pas_context *ctx, + const void *metadata, size_t size) +{ + struct qcom_scm_res res; + phys_addr_t mdata_phys; + void *mdata_buf; + int ret; + + mdata_buf = qcom_tzmem_alloc(__scm->mempool, size, GFP_KERNEL); + if (!mdata_buf) + return -ENOMEM; + + memcpy(mdata_buf, metadata, size); + mdata_phys = qcom_tzmem_to_phys(mdata_buf); + + ret = __qcom_scm_pas_init_image(ctx->pas_id, mdata_phys, &res); + if (ret < 0) + qcom_tzmem_free(mdata_buf); + else + ctx->ptr = mdata_buf; + + return ret ? : res.result[0]; +} + /** * qcom_scm_pas_init_image() - Initialize peripheral authentication service * state machine for a given peripheral, using the @@ -648,6 +672,9 @@ int qcom_scm_pas_init_image(u32 pas_id, const void *metadata, size_t size, void *mdata_buf; int ret; + if (ctx && ctx->use_tzmem) + return qcom_scm_pas_prep_and_init_image(ctx, metadata, size); + /* * During the scm call memory protection will be enabled for the meta * data blob, so make sure it's physically contiguous, 4K aligned and @@ -689,7 +716,10 @@ void qcom_scm_pas_metadata_release(struct qcom_scm_pas_context *ctx) if (!ctx->ptr) return; - dma_free_coherent(__scm->dev, ctx->size, ctx->ptr, ctx->phys); + if (ctx->use_tzmem) + qcom_tzmem_free(ctx->ptr); + else + dma_free_coherent(__scm->dev, ctx->size, ctx->ptr, ctx->phys); ctx->ptr = NULL; } From 458b7f6bc33d2c74b2a987d4c06623f0505c7818 Mon Sep 17 00:00:00 2001 From: Mukesh Ojha Date: Mon, 5 Jan 2026 18:52:59 +0530 Subject: [PATCH 2236/2333] FROMLIST: firmware: qcom_scm: Add qcom_scm_pas_get_rsc_table() to get resource table Qualcomm remote processor may rely on Static and Dynamic resources for it to be functional. Static resources are fixed like for example, memory-mapped addresses required by the subsystem and dynamic resources, such as shared memory in DDR etc., are determined at runtime during the boot process. For most of the Qualcomm SoCs, when run with Gunyah or older QHEE hypervisor, all the resources whether it is static or dynamic, is managed by the hypervisor. Dynamic resources if it is present for a remote processor will always be coming from secure world via SMC call while static resources may be present in remote processor firmware binary or it may be coming qcom_scm_pas_get_rsc_table() SMC call along with dynamic resources. Some of the remote processor drivers, such as video, GPU, IPA, etc., do not check whether resources are present in their remote processor firmware binary. In such cases, the caller of this function should set input_rt and input_rt_size as NULL and zero respectively. Remoteproc framework has method to check whether firmware binary contain resources or not and they should be pass resource table pointer to input_rt and resource table size to input_rt_size and this will be forwarded to TrustZone for authentication. TrustZone will then append the dynamic resources and return the complete resource table in the passed output buffer. More about documentation on resource table format can be found in include/linux/remoteproc.h Signed-off-by: Mukesh Ojha Link: https://lore.kernel.org/r/20260105-kvmrprocv10-v10-11-022e96815380@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- drivers/firmware/qcom/qcom_scm.c | 171 +++++++++++++++++++++++++ drivers/firmware/qcom/qcom_scm.h | 1 + include/linux/firmware/qcom/qcom_scm.h | 4 + 3 files changed, 176 insertions(+) diff --git a/drivers/firmware/qcom/qcom_scm.c b/drivers/firmware/qcom/qcom_scm.c index ca0ce2f55642d..0d53aedbba80d 100644 --- a/drivers/firmware/qcom/qcom_scm.c +++ b/drivers/firmware/qcom/qcom_scm.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -111,6 +112,8 @@ enum qcom_scm_qseecom_tz_cmd_info { QSEECOM_TZ_CMD_INFO_VERSION = 3, }; +#define RSCTABLE_BUFFER_NOT_SUFFICIENT 20 + #define QSEECOM_MAX_APP_NAME_SIZE 64 #define SHMBRIDGE_RESULT_NOTSUPP 4 @@ -766,6 +769,174 @@ int qcom_scm_pas_mem_setup(u32 pas_id, phys_addr_t addr, phys_addr_t size) } EXPORT_SYMBOL_GPL(qcom_scm_pas_mem_setup); +static void *__qcom_scm_pas_get_rsc_table(u32 pas_id, void *input_rt_tzm, + size_t input_rt_size, + size_t *output_rt_size) +{ + struct qcom_scm_desc desc = { + .svc = QCOM_SCM_SVC_PIL, + .cmd = QCOM_SCM_PIL_PAS_GET_RSCTABLE, + .arginfo = QCOM_SCM_ARGS(5, QCOM_SCM_VAL, QCOM_SCM_RO, QCOM_SCM_VAL, + QCOM_SCM_RW, QCOM_SCM_VAL), + .args[0] = pas_id, + .owner = ARM_SMCCC_OWNER_SIP, + }; + struct qcom_scm_res res; + void *output_rt_tzm; + int ret; + + output_rt_tzm = qcom_tzmem_alloc(__scm->mempool, *output_rt_size, GFP_KERNEL); + if (!output_rt_tzm) + return ERR_PTR(-ENOMEM); + + desc.args[1] = qcom_tzmem_to_phys(input_rt_tzm); + desc.args[2] = input_rt_size; + desc.args[3] = qcom_tzmem_to_phys(output_rt_tzm); + desc.args[4] = *output_rt_size; + + /* + * Whether SMC fail or pass, res.result[2] will hold actual resource table + * size. + * + * If passed 'output_rt_size' buffer size is not sufficient to hold the + * resource table TrustZone sends, response code in res.result[1] as + * RSCTABLE_BUFFER_NOT_SUFFICIENT so that caller can retry this SMC call + * with output_rt_tzm buffer with res.result[2] size however, It should not + * be of unresonable size. + */ + ret = qcom_scm_call(__scm->dev, &desc, &res); + if (!ret && res.result[2] > SZ_1G) { + ret = -E2BIG; + goto free_output_rt; + } + + *output_rt_size = res.result[2]; + if (ret && res.result[1] == RSCTABLE_BUFFER_NOT_SUFFICIENT) + ret = -EOVERFLOW; + +free_output_rt: + if (ret) + qcom_tzmem_free(output_rt_tzm); + + return ret ? ERR_PTR(ret) : output_rt_tzm; +} + +/** + * qcom_scm_pas_get_rsc_table() - Retrieve the resource table in passed output buffer + * for a given peripheral. + * + * Qualcomm remote processor may rely on both static and dynamic resources for + * its functionality. Static resources typically refer to memory-mapped addresses + * required by the subsystem and are often embedded within the firmware binary + * and dynamic resources, such as shared memory in DDR etc., are determined at + * runtime during the boot process. + * + * On Qualcomm Technologies devices, it's possible that static resources are not + * embedded in the firmware binary and instead are provided by TrustZone However, + * dynamic resources are always expected to come from TrustZone. This indicates + * that for Qualcomm devices, all resources (static and dynamic) will be provided + * by TrustZone via the SMC call. + * + * If the remote processor firmware binary does contain static resources, they + * should be passed in input_rt. These will be forwarded to TrustZone for + * authentication. TrustZone will then append the dynamic resources and return + * the complete resource table in output_rt_tzm. + * + * If the remote processor firmware binary does not include a resource table, + * the caller of this function should set input_rt as NULL and input_rt_size + * as zero respectively. + * + * More about documentation on resource table data structures can be found in + * include/linux/remoteproc.h + * + * @ctx: PAS context + * @pas_id: peripheral authentication service id + * @input_rt: resource table buffer which is present in firmware binary + * @input_rt_size: size of the resource table present in firmware binary + * @output_rt_size: TrustZone expects caller should pass worst case size for + * the output_rt_tzm. + * + * Return: + * On success, returns a pointer to the allocated buffer containing the final + * resource table and output_rt_size will have actual resource table size from + * TrustZone. The caller is responsible for freeing the buffer. On failure, + * returns ERR_PTR(-errno). + */ +struct resource_table *qcom_scm_pas_get_rsc_table(struct qcom_scm_pas_context *ctx, + void *input_rt, + size_t input_rt_size, + size_t *output_rt_size) +{ + struct resource_table empty_rsc = {}; + size_t size = SZ_16K; + void *output_rt_tzm; + void *input_rt_tzm; + void *tbl_ptr; + int ret; + + ret = qcom_scm_clk_enable(); + if (ret) + return ERR_PTR(ret); + + ret = qcom_scm_bw_enable(); + if (ret) + goto disable_clk; + + /* + * TrustZone can not accept buffer as NULL value as argument hence, + * we need to pass a input buffer indicating that subsystem firmware + * does not have resource table by filling resource table structure. + */ + if (!input_rt) { + input_rt = &empty_rsc; + input_rt_size = sizeof(empty_rsc); + } + + input_rt_tzm = qcom_tzmem_alloc(__scm->mempool, input_rt_size, GFP_KERNEL); + if (!input_rt_tzm) { + ret = -ENOMEM; + goto disable_scm_bw; + } + + memcpy(input_rt_tzm, input_rt, input_rt_size); + + output_rt_tzm = __qcom_scm_pas_get_rsc_table(ctx->pas_id, input_rt_tzm, + input_rt_size, &size); + if (PTR_ERR(output_rt_tzm) == -EOVERFLOW) + /* Try again with the size requested by the TZ */ + output_rt_tzm = __qcom_scm_pas_get_rsc_table(ctx->pas_id, + input_rt_tzm, + input_rt_size, + &size); + if (IS_ERR(output_rt_tzm)) { + ret = PTR_ERR(output_rt_tzm); + goto free_input_rt; + } + + tbl_ptr = kzalloc(size, GFP_KERNEL); + if (!tbl_ptr) { + qcom_tzmem_free(output_rt_tzm); + ret = -ENOMEM; + goto free_input_rt; + } + + memcpy(tbl_ptr, output_rt_tzm, size); + *output_rt_size = size; + qcom_tzmem_free(output_rt_tzm); + +free_input_rt: + qcom_tzmem_free(input_rt_tzm); + +disable_scm_bw: + qcom_scm_bw_disable(); + +disable_clk: + qcom_scm_clk_disable(); + + return ret ? ERR_PTR(ret) : tbl_ptr; +} +EXPORT_SYMBOL_GPL(qcom_scm_pas_get_rsc_table); + /** * qcom_scm_pas_auth_and_reset() - Authenticate the given peripheral firmware * and reset the remote processor diff --git a/drivers/firmware/qcom/qcom_scm.h b/drivers/firmware/qcom/qcom_scm.h index 48f2cb83228d6..de7e8ce6a7b21 100644 --- a/drivers/firmware/qcom/qcom_scm.h +++ b/drivers/firmware/qcom/qcom_scm.h @@ -105,6 +105,7 @@ int qcom_scm_shm_bridge_enable(struct device *scm_dev); #define QCOM_SCM_PIL_PAS_SHUTDOWN 0x06 #define QCOM_SCM_PIL_PAS_IS_SUPPORTED 0x07 #define QCOM_SCM_PIL_PAS_MSS_RESET 0x0a +#define QCOM_SCM_PIL_PAS_GET_RSCTABLE 0x21 #define QCOM_SCM_SVC_IO 0x05 #define QCOM_SCM_IO_READ 0x01 diff --git a/include/linux/firmware/qcom/qcom_scm.h b/include/linux/firmware/qcom/qcom_scm.h index 3d568b3b24d6d..e505e9b6f49e9 100644 --- a/include/linux/firmware/qcom/qcom_scm.h +++ b/include/linux/firmware/qcom/qcom_scm.h @@ -98,6 +98,10 @@ int qcom_scm_pas_mem_setup(u32 pas_id, phys_addr_t addr, phys_addr_t size); int qcom_scm_pas_auth_and_reset(u32 pas_id); int qcom_scm_pas_shutdown(u32 pas_id); bool qcom_scm_pas_supported(u32 pas_id); +struct resource_table *qcom_scm_pas_get_rsc_table(struct qcom_scm_pas_context *ctx, + void *input_rt, size_t input_rt_size, + size_t *output_rt_size); + int qcom_scm_pas_prepare_and_auth_reset(struct qcom_scm_pas_context *ctx); int qcom_scm_io_readl(phys_addr_t addr, unsigned int *val); From 21dea3538f8eb5686b9ab1bc36d3d575f4fe2b00 Mon Sep 17 00:00:00 2001 From: Mukesh Ojha Date: Mon, 5 Jan 2026 18:53:00 +0530 Subject: [PATCH 2237/2333] FROMLIST: remoteproc: pas: Extend parse_fw callback to fetch resources via SMC call Qualcomm remote processor may rely on static and dynamic resources for it to be functional. For most of the Qualcomm SoCs, when run with Gunyah or older QHEE hypervisor, all the resources whether it is static or dynamic, is managed by the hypervisor. Dynamic resources if it is present for a remote processor will always be coming from secure world via SMC call while static resources may be present in remote processor firmware binary or it may be coming from SMC call along with dynamic resources. Remoteproc already has method like rproc_elf_load_rsc_table() to check firmware binary has resources or not and if it is not having then we pass NULL and zero as input resource table and its size argument respectively to qcom_scm_pas_get_rsc_table() and while it has resource present then it should pass the present resources to Trustzone(TZ) so that it could authenticate the present resources and append dynamic resource to return in output_rt argument along with authenticated resources. Extend parse_fw callback to include SMC call to get resources from Trustzone and to leverage resource table parsing and mapping and unmapping code from the remoteproc framework. Reviewed-by: Konrad Dybcio Signed-off-by: Mukesh Ojha Link: https://lore.kernel.org/r/20260105-kvmrprocv10-v10-12-022e96815380@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- drivers/remoteproc/qcom_q6v5_pas.c | 59 +++++++++++++++++++++++++++++- 1 file changed, 57 insertions(+), 2 deletions(-) diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c index 0c4ec72352e3e..dc0e1878e6b47 100644 --- a/drivers/remoteproc/qcom_q6v5_pas.c +++ b/drivers/remoteproc/qcom_q6v5_pas.c @@ -413,6 +413,61 @@ static void *qcom_pas_da_to_va(struct rproc *rproc, u64 da, size_t len, bool *is return pas->mem_region + offset; } +static int qcom_pas_parse_firmware(struct rproc *rproc, const struct firmware *fw) +{ + struct qcom_pas *pas = rproc->priv; + struct resource_table *table = NULL; + size_t output_rt_size; + void *output_rt; + size_t table_sz; + int ret; + + ret = qcom_register_dump_segments(rproc, fw); + if (ret) { + dev_err(pas->dev, "Error in registering dump segments\n"); + return ret; + } + + if (!rproc->has_iommu) + return 0; + + ret = rproc_elf_load_rsc_table(rproc, fw); + if (ret) + dev_dbg(&rproc->dev, "Failed to load resource table from firmware\n"); + + table = rproc->table_ptr; + table_sz = rproc->table_sz; + + /* + * The resources consumed by Qualcomm remote processors fall into two categories: + * static (such as the memory carveouts for the rproc firmware) and dynamic (like + * shared memory pools). Both are managed by a Qualcomm hypervisor (such as QHEE + * or Gunyah), if one is present. Otherwise, a resource table must be retrieved + * via an SCM call. That table will list all dynamic resources (if any) and possibly + * the static ones. The static resources may also come from a resource table embedded + * in the rproc firmware instead. + * + * Here, we call rproc_elf_load_rsc_table() to check firmware binary has resources + * or not and if it is not having then we pass NULL and zero as input resource + * table pointer and size respectively to the argument of qcom_scm_pas_get_rsc_table() + * and this is even true for Qualcomm remote processor who does follow remoteproc + * framework. + */ + output_rt = qcom_scm_pas_get_rsc_table(pas->pas_ctx, table, table_sz, &output_rt_size); + ret = IS_ERR(output_rt) ? PTR_ERR(output_rt) : 0; + if (ret) { + dev_err(pas->dev, "Error in getting resource table: %d\n", ret); + return ret; + } + + kfree(rproc->cached_table); + rproc->cached_table = output_rt; + rproc->table_ptr = rproc->cached_table; + rproc->table_sz = output_rt_size; + + return ret; +} + static unsigned long qcom_pas_panic(struct rproc *rproc) { struct qcom_pas *pas = rproc->priv; @@ -425,7 +480,7 @@ static const struct rproc_ops qcom_pas_ops = { .start = qcom_pas_start, .stop = qcom_pas_stop, .da_to_va = qcom_pas_da_to_va, - .parse_fw = qcom_register_dump_segments, + .parse_fw = qcom_pas_parse_firmware, .load = qcom_pas_load, .panic = qcom_pas_panic, }; @@ -435,7 +490,7 @@ static const struct rproc_ops qcom_pas_minidump_ops = { .start = qcom_pas_start, .stop = qcom_pas_stop, .da_to_va = qcom_pas_da_to_va, - .parse_fw = qcom_register_dump_segments, + .parse_fw = qcom_pas_parse_firmware, .load = qcom_pas_load, .panic = qcom_pas_panic, .coredump = qcom_pas_minidump, From 73e52bd766afc05bf77d718ce53e1160cdac2d9f Mon Sep 17 00:00:00 2001 From: Mukesh Ojha Date: Mon, 5 Jan 2026 18:53:01 +0530 Subject: [PATCH 2238/2333] FROMLIST: remoteproc: qcom: pas: Enable Secure PAS support with IOMMU managed by Linux Most Qualcomm platforms feature Gunyah hypervisor, which typically handles IOMMU configuration. This includes mapping memory regions and device memory resources for remote processors by intercepting qcom_scm_pas_auth_and_reset() calls. These mappings are later removed during teardown. Additionally, SHM bridge setup is required to enable memory protection for both remoteproc metadata and its memory regions. When the aforementioned hypervisor is absent, the operating system must perform these configurations instead. When Linux runs as the hypervisor (@ EL2) on a SoC, it will have its own device tree overlay file that specifies the firmware stream ID now managed by Linux for a particular remote processor. If the iommus property is specified in the remoteproc device tree node, it indicates that IOMMU configuration must be handled by Linux. In this case, the has_iommu flag is set for the remote processor, which ensures that the resource table, carveouts, and SHM bridge are properly configured before memory is passed to TrustZone for authentication. Otherwise, the has_iommu flag remains unset, which indicates default behavior. Enables Secure PAS support for remote processors when IOMMU configuration is managed by Linux. Signed-off-by: Mukesh Ojha Link: https://lore.kernel.org/r/20260105-kvmrprocv10-v10-13-022e96815380@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- drivers/remoteproc/qcom_q6v5_pas.c | 48 ++++++++++++++++++++++++++---- 1 file changed, 43 insertions(+), 5 deletions(-) diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c index dc0e1878e6b47..f8516739736d5 100644 --- a/drivers/remoteproc/qcom_q6v5_pas.c +++ b/drivers/remoteproc/qcom_q6v5_pas.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -255,6 +256,22 @@ static int qcom_pas_load(struct rproc *rproc, const struct firmware *fw) return ret; } +static void qcom_pas_unmap_carveout(struct rproc *rproc, phys_addr_t mem_phys, size_t size) +{ + if (rproc->has_iommu) + iommu_unmap(rproc->domain, mem_phys, size); +} + +static int qcom_pas_map_carveout(struct rproc *rproc, phys_addr_t mem_phys, size_t size) +{ + int ret = 0; + + if (rproc->has_iommu) + ret = iommu_map(rproc->domain, mem_phys, mem_phys, size, + IOMMU_READ | IOMMU_WRITE, GFP_KERNEL); + return ret; +} + static int qcom_pas_start(struct rproc *rproc) { struct qcom_pas *pas = rproc->priv; @@ -289,11 +306,15 @@ static int qcom_pas_start(struct rproc *rproc) } if (pas->dtb_pas_id) { - ret = qcom_scm_pas_auth_and_reset(pas->dtb_pas_id); + ret = qcom_pas_map_carveout(rproc, pas->dtb_mem_phys, pas->dtb_mem_size); + if (ret) + goto disable_px_supply; + + ret = qcom_scm_pas_prepare_and_auth_reset(pas->dtb_pas_ctx); if (ret) { dev_err(pas->dev, "failed to authenticate dtb image and release reset\n"); - goto disable_px_supply; + goto unmap_dtb_carveout; } } @@ -304,18 +325,22 @@ static int qcom_pas_start(struct rproc *rproc) qcom_pil_info_store(pas->info_name, pas->mem_phys, pas->mem_size); - ret = qcom_scm_pas_auth_and_reset(pas->pas_id); + ret = qcom_pas_map_carveout(rproc, pas->mem_phys, pas->mem_size); + if (ret) + goto release_pas_metadata; + + ret = qcom_scm_pas_prepare_and_auth_reset(pas->pas_ctx); if (ret) { dev_err(pas->dev, "failed to authenticate image and release reset\n"); - goto release_pas_metadata; + goto unmap_carveout; } ret = qcom_q6v5_wait_for_start(&pas->q6v5, msecs_to_jiffies(5000)); if (ret == -ETIMEDOUT) { dev_err(pas->dev, "start timed out\n"); qcom_scm_pas_shutdown(pas->pas_id); - goto release_pas_metadata; + goto unmap_carveout; } qcom_scm_pas_metadata_release(pas->pas_ctx); @@ -327,10 +352,16 @@ static int qcom_pas_start(struct rproc *rproc) return 0; +unmap_carveout: + qcom_pas_unmap_carveout(rproc, pas->mem_phys, pas->mem_size); release_pas_metadata: qcom_scm_pas_metadata_release(pas->pas_ctx); if (pas->dtb_pas_id) qcom_scm_pas_metadata_release(pas->dtb_pas_ctx); + +unmap_dtb_carveout: + if (pas->dtb_pas_id) + qcom_pas_unmap_carveout(rproc, pas->dtb_mem_phys, pas->dtb_mem_size); disable_px_supply: if (pas->px_supply) regulator_disable(pas->px_supply); @@ -386,8 +417,12 @@ static int qcom_pas_stop(struct rproc *rproc) ret = qcom_scm_pas_shutdown(pas->dtb_pas_id); if (ret) dev_err(pas->dev, "failed to shutdown dtb: %d\n", ret); + + qcom_pas_unmap_carveout(rproc, pas->dtb_mem_phys, pas->dtb_mem_size); } + qcom_pas_unmap_carveout(rproc, pas->mem_phys, pas->mem_size); + handover = qcom_q6v5_unprepare(&pas->q6v5); if (handover) qcom_pas_handover(&pas->q6v5); @@ -757,6 +792,7 @@ static int qcom_pas_probe(struct platform_device *pdev) return -ENOMEM; } + rproc->has_iommu = of_property_present(pdev->dev.of_node, "iommus"); rproc->auto_boot = desc->auto_boot; rproc_coredump_set_elf_info(rproc, ELFCLASS32, EM_NONE); @@ -836,6 +872,8 @@ static int qcom_pas_probe(struct platform_device *pdev) goto remove_ssr_sysmon; } + pas->pas_ctx->use_tzmem = rproc->has_iommu; + pas->dtb_pas_ctx->use_tzmem = rproc->has_iommu; ret = rproc_add(rproc); if (ret) goto remove_ssr_sysmon; From 23d94475ff33921d2a1a77dac0e1b3dad44f2f1b Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Tue, 23 Sep 2025 14:01:55 +0300 Subject: [PATCH 2239/2333] FROMLIST: arm64: dts: qcom: rename x1e80100 to hamoa The X1E80100 and several other similar names (X1E78100, X1E001DE) all belong to the platform now known as 'hamoa'. Follow the example of 'lemans' and rename the x1e80100.dtsi to hamoa.dtsi and x1e80100-pmics.dtsi to hamoa-pmics.dtsi. Signed-off-by: Dmitry Baryshkov Signed-off-by: Xin Liu Link: https://lore.kernel.org/lkml/20250923-rename-dts-v1-2-21888b68c781@oss.qualcomm.com/ --- arch/arm64/boot/dts/qcom/hamoa-iot-som.dtsi | 4 ++-- .../boot/dts/qcom/{x1e80100-pmics.dtsi => hamoa-pmics.dtsi} | 0 arch/arm64/boot/dts/qcom/{x1e80100.dtsi => hamoa.dtsi} | 0 arch/arm64/boot/dts/qcom/x1-asus-zenbook-a14.dtsi | 2 +- arch/arm64/boot/dts/qcom/x1-crd.dtsi | 2 +- arch/arm64/boot/dts/qcom/x1-dell-thena.dtsi | 2 +- arch/arm64/boot/dts/qcom/x1e001de-devkit.dts | 4 ++-- arch/arm64/boot/dts/qcom/x1e78100-lenovo-thinkpad-t14s.dtsi | 4 ++-- arch/arm64/boot/dts/qcom/x1e80100-asus-vivobook-s15.dts | 4 ++-- arch/arm64/boot/dts/qcom/x1e80100-asus-zenbook-a14.dts | 2 +- arch/arm64/boot/dts/qcom/x1e80100-crd.dts | 2 +- .../boot/dts/qcom/x1e80100-dell-inspiron-14-plus-7441.dts | 2 +- arch/arm64/boot/dts/qcom/x1e80100-dell-latitude-7455.dts | 2 +- arch/arm64/boot/dts/qcom/x1e80100-dell-xps13-9345.dts | 4 ++-- arch/arm64/boot/dts/qcom/x1e80100-hp-omnibook-x14.dts | 4 ++-- arch/arm64/boot/dts/qcom/x1e80100-lenovo-yoga-slim7x.dts | 4 ++-- arch/arm64/boot/dts/qcom/x1e80100-microsoft-romulus.dtsi | 4 ++-- arch/arm64/boot/dts/qcom/x1e80100-qcp.dts | 4 ++-- arch/arm64/boot/dts/qcom/x1p42100-hp-omnibook-x14.dts | 2 +- arch/arm64/boot/dts/qcom/x1p42100-lenovo-thinkbook-16.dts | 2 +- arch/arm64/boot/dts/qcom/x1p42100.dtsi | 4 ++-- 21 files changed, 29 insertions(+), 29 deletions(-) rename arch/arm64/boot/dts/qcom/{x1e80100-pmics.dtsi => hamoa-pmics.dtsi} (100%) rename arch/arm64/boot/dts/qcom/{x1e80100.dtsi => hamoa.dtsi} (100%) diff --git a/arch/arm64/boot/dts/qcom/hamoa-iot-som.dtsi b/arch/arm64/boot/dts/qcom/hamoa-iot-som.dtsi index 8bb43e4e1dcbc..1a9e930c0496b 100644 --- a/arch/arm64/boot/dts/qcom/hamoa-iot-som.dtsi +++ b/arch/arm64/boot/dts/qcom/hamoa-iot-som.dtsi @@ -3,8 +3,8 @@ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ -#include "x1e80100.dtsi" -#include "x1e80100-pmics.dtsi" +#include "hamoa.dtsi" +#include "hamoa-pmics.dtsi" #include #include diff --git a/arch/arm64/boot/dts/qcom/x1e80100-pmics.dtsi b/arch/arm64/boot/dts/qcom/hamoa-pmics.dtsi similarity index 100% rename from arch/arm64/boot/dts/qcom/x1e80100-pmics.dtsi rename to arch/arm64/boot/dts/qcom/hamoa-pmics.dtsi diff --git a/arch/arm64/boot/dts/qcom/x1e80100.dtsi b/arch/arm64/boot/dts/qcom/hamoa.dtsi similarity index 100% rename from arch/arm64/boot/dts/qcom/x1e80100.dtsi rename to arch/arm64/boot/dts/qcom/hamoa.dtsi diff --git a/arch/arm64/boot/dts/qcom/x1-asus-zenbook-a14.dtsi b/arch/arm64/boot/dts/qcom/x1-asus-zenbook-a14.dtsi index ee3c8c5e2c50c..69eccad1a09c2 100644 --- a/arch/arm64/boot/dts/qcom/x1-asus-zenbook-a14.dtsi +++ b/arch/arm64/boot/dts/qcom/x1-asus-zenbook-a14.dtsi @@ -11,7 +11,7 @@ #include #include -#include "x1e80100-pmics.dtsi" +#include "hamoa-pmics.dtsi" / { model = "ASUS Zenbook A14"; diff --git a/arch/arm64/boot/dts/qcom/x1-crd.dtsi b/arch/arm64/boot/dts/qcom/x1-crd.dtsi index 3c9455fede5c0..5e324f35547a4 100644 --- a/arch/arm64/boot/dts/qcom/x1-crd.dtsi +++ b/arch/arm64/boot/dts/qcom/x1-crd.dtsi @@ -9,7 +9,7 @@ #include #include -#include "x1e80100-pmics.dtsi" +#include "hamoa-pmics.dtsi" / { model = "Qualcomm Technologies, Inc. X1E80100 CRD"; diff --git a/arch/arm64/boot/dts/qcom/x1-dell-thena.dtsi b/arch/arm64/boot/dts/qcom/x1-dell-thena.dtsi index 847b678f040c0..bf04a12b16bc9 100644 --- a/arch/arm64/boot/dts/qcom/x1-dell-thena.dtsi +++ b/arch/arm64/boot/dts/qcom/x1-dell-thena.dtsi @@ -12,7 +12,7 @@ #include #include -#include "x1e80100-pmics.dtsi" +#include "hamoa-pmics.dtsi" / { chassis-type = "laptop"; diff --git a/arch/arm64/boot/dts/qcom/x1e001de-devkit.dts b/arch/arm64/boot/dts/qcom/x1e001de-devkit.dts index bfc649d4b643c..701f35af7d5cd 100644 --- a/arch/arm64/boot/dts/qcom/x1e001de-devkit.dts +++ b/arch/arm64/boot/dts/qcom/x1e001de-devkit.dts @@ -8,8 +8,8 @@ #include #include -#include "x1e80100.dtsi" -#include "x1e80100-pmics.dtsi" +#include "hamoa.dtsi" +#include "hamoa-pmics.dtsi" / { model = "Qualcomm Technologies, Inc. X1E001DE Snapdragon Devkit for Windows"; diff --git a/arch/arm64/boot/dts/qcom/x1e78100-lenovo-thinkpad-t14s.dtsi b/arch/arm64/boot/dts/qcom/x1e78100-lenovo-thinkpad-t14s.dtsi index 654cbce9d6ecb..169726984d3b0 100644 --- a/arch/arm64/boot/dts/qcom/x1e78100-lenovo-thinkpad-t14s.dtsi +++ b/arch/arm64/boot/dts/qcom/x1e78100-lenovo-thinkpad-t14s.dtsi @@ -12,8 +12,8 @@ #include #include -#include "x1e80100.dtsi" -#include "x1e80100-pmics.dtsi" +#include "hamoa.dtsi" +#include "hamoa-pmics.dtsi" / { model = "Lenovo ThinkPad T14s Gen 6"; diff --git a/arch/arm64/boot/dts/qcom/x1e80100-asus-vivobook-s15.dts b/arch/arm64/boot/dts/qcom/x1e80100-asus-vivobook-s15.dts index 0113d856b3ad4..f2960953e608f 100644 --- a/arch/arm64/boot/dts/qcom/x1e80100-asus-vivobook-s15.dts +++ b/arch/arm64/boot/dts/qcom/x1e80100-asus-vivobook-s15.dts @@ -11,8 +11,8 @@ #include #include -#include "x1e80100.dtsi" -#include "x1e80100-pmics.dtsi" +#include "hamoa.dtsi" +#include "hamoa-pmics.dtsi" / { model = "ASUS Vivobook S 15"; diff --git a/arch/arm64/boot/dts/qcom/x1e80100-asus-zenbook-a14.dts b/arch/arm64/boot/dts/qcom/x1e80100-asus-zenbook-a14.dts index 0d0bcc50207d7..c3cd04c9703d3 100644 --- a/arch/arm64/boot/dts/qcom/x1e80100-asus-zenbook-a14.dts +++ b/arch/arm64/boot/dts/qcom/x1e80100-asus-zenbook-a14.dts @@ -6,7 +6,7 @@ /dts-v1/; -#include "x1e80100.dtsi" +#include "hamoa.dtsi" #include "x1-asus-zenbook-a14.dtsi" / { diff --git a/arch/arm64/boot/dts/qcom/x1e80100-crd.dts b/arch/arm64/boot/dts/qcom/x1e80100-crd.dts index dfc378e1a056a..429deffcf3e9d 100644 --- a/arch/arm64/boot/dts/qcom/x1e80100-crd.dts +++ b/arch/arm64/boot/dts/qcom/x1e80100-crd.dts @@ -5,7 +5,7 @@ /dts-v1/; -#include "x1e80100.dtsi" +#include "hamoa.dtsi" #include "x1-crd.dtsi" / { diff --git a/arch/arm64/boot/dts/qcom/x1e80100-dell-inspiron-14-plus-7441.dts b/arch/arm64/boot/dts/qcom/x1e80100-dell-inspiron-14-plus-7441.dts index cf2a7c2628881..75e10d97c3867 100644 --- a/arch/arm64/boot/dts/qcom/x1e80100-dell-inspiron-14-plus-7441.dts +++ b/arch/arm64/boot/dts/qcom/x1e80100-dell-inspiron-14-plus-7441.dts @@ -4,7 +4,7 @@ */ /dts-v1/; -#include "x1e80100.dtsi" +#include "hamoa.dtsi" #include "x1-dell-thena.dtsi" / { diff --git a/arch/arm64/boot/dts/qcom/x1e80100-dell-latitude-7455.dts b/arch/arm64/boot/dts/qcom/x1e80100-dell-latitude-7455.dts index 32ad9679550ef..a8ff7ef258a13 100644 --- a/arch/arm64/boot/dts/qcom/x1e80100-dell-latitude-7455.dts +++ b/arch/arm64/boot/dts/qcom/x1e80100-dell-latitude-7455.dts @@ -4,7 +4,7 @@ */ /dts-v1/; -#include "x1e80100.dtsi" +#include "hamoa.dtsi" #include "x1-dell-thena.dtsi" / { diff --git a/arch/arm64/boot/dts/qcom/x1e80100-dell-xps13-9345.dts b/arch/arm64/boot/dts/qcom/x1e80100-dell-xps13-9345.dts index 58f8caaa72580..c1f49cba61fc4 100644 --- a/arch/arm64/boot/dts/qcom/x1e80100-dell-xps13-9345.dts +++ b/arch/arm64/boot/dts/qcom/x1e80100-dell-xps13-9345.dts @@ -12,8 +12,8 @@ #include #include -#include "x1e80100.dtsi" -#include "x1e80100-pmics.dtsi" +#include "hamoa.dtsi" +#include "hamoa-pmics.dtsi" / { model = "Dell XPS 13 9345"; diff --git a/arch/arm64/boot/dts/qcom/x1e80100-hp-omnibook-x14.dts b/arch/arm64/boot/dts/qcom/x1e80100-hp-omnibook-x14.dts index e5a839d458402..b79e59e1c413a 100644 --- a/arch/arm64/boot/dts/qcom/x1e80100-hp-omnibook-x14.dts +++ b/arch/arm64/boot/dts/qcom/x1e80100-hp-omnibook-x14.dts @@ -6,8 +6,8 @@ /dts-v1/; -#include "x1e80100.dtsi" -#include "x1e80100-pmics.dtsi" +#include "hamoa.dtsi" +#include "hamoa-pmics.dtsi" #include "x1-hp-omnibook-x14.dtsi" / { diff --git a/arch/arm64/boot/dts/qcom/x1e80100-lenovo-yoga-slim7x.dts b/arch/arm64/boot/dts/qcom/x1e80100-lenovo-yoga-slim7x.dts index e0642fe8343f6..56e4d13cca111 100644 --- a/arch/arm64/boot/dts/qcom/x1e80100-lenovo-yoga-slim7x.dts +++ b/arch/arm64/boot/dts/qcom/x1e80100-lenovo-yoga-slim7x.dts @@ -9,8 +9,8 @@ #include #include -#include "x1e80100.dtsi" -#include "x1e80100-pmics.dtsi" +#include "hamoa.dtsi" +#include "hamoa-pmics.dtsi" / { model = "Lenovo Yoga Slim 7x"; diff --git a/arch/arm64/boot/dts/qcom/x1e80100-microsoft-romulus.dtsi b/arch/arm64/boot/dts/qcom/x1e80100-microsoft-romulus.dtsi index ed468b93ba50e..3b319f65dde1e 100644 --- a/arch/arm64/boot/dts/qcom/x1e80100-microsoft-romulus.dtsi +++ b/arch/arm64/boot/dts/qcom/x1e80100-microsoft-romulus.dtsi @@ -9,8 +9,8 @@ #include #include -#include "x1e80100.dtsi" -#include "x1e80100-pmics.dtsi" +#include "hamoa.dtsi" +#include "hamoa-pmics.dtsi" / { aliases { diff --git a/arch/arm64/boot/dts/qcom/x1e80100-qcp.dts b/arch/arm64/boot/dts/qcom/x1e80100-qcp.dts index 4a9b6d791e7f4..5a121fc449401 100644 --- a/arch/arm64/boot/dts/qcom/x1e80100-qcp.dts +++ b/arch/arm64/boot/dts/qcom/x1e80100-qcp.dts @@ -8,8 +8,8 @@ #include #include -#include "x1e80100.dtsi" -#include "x1e80100-pmics.dtsi" +#include "hamoa.dtsi" +#include "hamoa-pmics.dtsi" / { model = "Qualcomm Technologies, Inc. X1E80100 QCP"; diff --git a/arch/arm64/boot/dts/qcom/x1p42100-hp-omnibook-x14.dts b/arch/arm64/boot/dts/qcom/x1p42100-hp-omnibook-x14.dts index 6696cab2de3ec..47ab0c5b30341 100644 --- a/arch/arm64/boot/dts/qcom/x1p42100-hp-omnibook-x14.dts +++ b/arch/arm64/boot/dts/qcom/x1p42100-hp-omnibook-x14.dts @@ -3,7 +3,7 @@ /dts-v1/; #include "x1p42100.dtsi" -#include "x1e80100-pmics.dtsi" +#include "hamoa-pmics.dtsi" #include "x1-hp-omnibook-x14.dtsi" /delete-node/ &pmc8380_6; /delete-node/ &pmc8380_6_thermal; diff --git a/arch/arm64/boot/dts/qcom/x1p42100-lenovo-thinkbook-16.dts b/arch/arm64/boot/dts/qcom/x1p42100-lenovo-thinkbook-16.dts index 1ac46cdc43861..f7d372d2e9612 100644 --- a/arch/arm64/boot/dts/qcom/x1p42100-lenovo-thinkbook-16.dts +++ b/arch/arm64/boot/dts/qcom/x1p42100-lenovo-thinkbook-16.dts @@ -14,7 +14,7 @@ #include #include "x1p42100.dtsi" -#include "x1e80100-pmics.dtsi" +#include "hamoa-pmics.dtsi" /delete-node/ &pmc8380_6; /delete-node/ &pmc8380_6_thermal; diff --git a/arch/arm64/boot/dts/qcom/x1p42100.dtsi b/arch/arm64/boot/dts/qcom/x1p42100.dtsi index 686b3a6b82cf5..38f2df9e42b60 100644 --- a/arch/arm64/boot/dts/qcom/x1p42100.dtsi +++ b/arch/arm64/boot/dts/qcom/x1p42100.dtsi @@ -3,8 +3,8 @@ * Copyright (c) 2025 Qualcomm Innovation Center, Inc. All rights reserved. */ -/* X1P42100 is heavily based on X1E80100, with some meaningful differences */ -#include "x1e80100.dtsi" +/* X1P42100 is heavily based on hamoa, with some meaningful differences */ +#include "hamoa.dtsi" /delete-node/ &bwmon_cluster0; /delete-node/ &cluster_pd2; From 3381cecca8dedf040b8d77952e3eb7728d48593d Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Tue, 23 Sep 2025 14:01:54 +0300 Subject: [PATCH 2240/2333] FROMLIST: arm64: dts: qcom: rename qcs8300 to monaco The QCS8300 and QCS8275 are two variants of the same die with no difference visible to the Linux kernel, which are collectively named as 'monaco'. Rather than trying to using the name, which is not always relevant, follow the example of 'lemans' and rename qcs8300.dtsi to monaco.dtsi (and qcs8300-pmics.dtsi to monaco-pmics.dtsi). Signed-off-by: Dmitry Baryshkov Signed-off-by: Xin Liu Link: https://lore.kernel.org/lkml/20250923-rename-dts-v1-1-21888b68c781@oss.qualcomm.com/ --- arch/arm64/boot/dts/qcom/monaco-evk.dts | 4 ++-- .../boot/dts/qcom/{qcs8300-pmics.dtsi => monaco-pmics.dtsi} | 0 arch/arm64/boot/dts/qcom/{qcs8300.dtsi => monaco.dtsi} | 0 arch/arm64/boot/dts/qcom/qcs8300-ride.dts | 4 ++-- 4 files changed, 4 insertions(+), 4 deletions(-) rename arch/arm64/boot/dts/qcom/{qcs8300-pmics.dtsi => monaco-pmics.dtsi} (100%) rename arch/arm64/boot/dts/qcom/{qcs8300.dtsi => monaco.dtsi} (100%) diff --git a/arch/arm64/boot/dts/qcom/monaco-evk.dts b/arch/arm64/boot/dts/qcom/monaco-evk.dts index dd55254e460a8..6aa84e11f2bc6 100644 --- a/arch/arm64/boot/dts/qcom/monaco-evk.dts +++ b/arch/arm64/boot/dts/qcom/monaco-evk.dts @@ -10,8 +10,8 @@ #include #include -#include "qcs8300.dtsi" -#include "qcs8300-pmics.dtsi" +#include "monaco.dtsi" +#include "monaco-pmics.dtsi" / { model = "Qualcomm Technologies, Inc. Monaco EVK"; diff --git a/arch/arm64/boot/dts/qcom/qcs8300-pmics.dtsi b/arch/arm64/boot/dts/qcom/monaco-pmics.dtsi similarity index 100% rename from arch/arm64/boot/dts/qcom/qcs8300-pmics.dtsi rename to arch/arm64/boot/dts/qcom/monaco-pmics.dtsi diff --git a/arch/arm64/boot/dts/qcom/qcs8300.dtsi b/arch/arm64/boot/dts/qcom/monaco.dtsi similarity index 100% rename from arch/arm64/boot/dts/qcom/qcs8300.dtsi rename to arch/arm64/boot/dts/qcom/monaco.dtsi diff --git a/arch/arm64/boot/dts/qcom/qcs8300-ride.dts b/arch/arm64/boot/dts/qcom/qcs8300-ride.dts index 010209b0eadb9..0c2cb2d3ded82 100644 --- a/arch/arm64/boot/dts/qcom/qcs8300-ride.dts +++ b/arch/arm64/boot/dts/qcom/qcs8300-ride.dts @@ -8,8 +8,8 @@ #include #include -#include "qcs8300.dtsi" -#include "qcs8300-pmics.dtsi" +#include "monaco.dtsi" +#include "monaco-pmics.dtsi" / { model = "Qualcomm Technologies, Inc. QCS8300 Ride"; compatible = "qcom,qcs8300-ride", "qcom,qcs8300"; From 3f690b08821960b75c06770605465fed1aa00c1c Mon Sep 17 00:00:00 2001 From: Krishna Chaitanya Chundru Date: Fri, 23 Jan 2026 17:42:27 +0530 Subject: [PATCH 2241/2333] FROMLIST: arm64: dts: qcom: kodiak: Fix PCIe1 PHY ref clock voting GCC_PCIE_CLKREF_EN controls a repeater that provides the reference clock only to the PCIe0 PHY. PCIe1 PHY receives its refclk directly from the CXO source. If the PCIe1 driver in HLOS votes for or against GCC_PCIE_CLKREF_EN, it will inadvertently modify the refclk to PCIe0 as well. Since PCIe0 is managed by WPSS while PCIe1 is managed in HLOS, there is no mechanism to coordinate these votes. As a result, HLOS may disable this repeater during suspend and cut off the PCIe0 PHY refclk while PCIe0 is still active. Replace the unused GCC_PCIE_CLKREF_EN clock entry with RPMH_CXO_CLK to reflect the actual hardware wiring and prevent unintended changes to PCIe0 clocking. Fixes: 92e0ee9f83b3 ("arm64: dts: qcom: sc7280: Add PCIe and PHY related nodes") Cc: stable@vger.kernel.org Reviewed-by: Dmitry Baryshkov Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20260123-fix_pcie1_phy_clk-v1-1-38f82ea01792@oss.qualcomm.com Signed-off-by: Krishna Chaitanya Chundru --- arch/arm64/boot/dts/qcom/sc7280.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sc7280.dtsi b/arch/arm64/boot/dts/qcom/sc7280.dtsi index 68ed072389372..9f757221fcebc 100644 --- a/arch/arm64/boot/dts/qcom/sc7280.dtsi +++ b/arch/arm64/boot/dts/qcom/sc7280.dtsi @@ -2445,7 +2445,7 @@ reg = <0 0x01c0e000 0 0x1000>; clocks = <&gcc GCC_PCIE_1_AUX_CLK>, <&gcc GCC_PCIE_1_CFG_AHB_CLK>, - <&gcc GCC_PCIE_CLKREF_EN>, + <&rpmhcc RPMH_CXO_CLK>, <&gcc GCC_PCIE1_PHY_RCHNG_CLK>, <&gcc GCC_PCIE_1_PIPE_CLK>; clock-names = "aux", From bebcbc13c0616d6eee8e06fe302c22db2fe9eea7 Mon Sep 17 00:00:00 2001 From: Krishna Chaitanya Chundru Date: Wed, 28 Jan 2026 17:10:41 +0530 Subject: [PATCH 2242/2333] FROMLIST: PCI: host-common: Add shared D3cold eligibility helper for host bridges Add a common helper, pci_host_common_can_enter_d3cold(), to determine whether a PCI host bridge can safely transition to D3cold. The helper walks all devices on the bridge's bus and only allows the host bridge to enter D3cold if all PCIe endpoints are already in PCI_D3hot. For devices that may wake the system, it additionally requires that the device supports PME wakeup from D3cold(with WAKE#). Devices without wakeup enabled are not restricted by this check and can be allowed to keep device in D3cold. Link: https://lore.kernel.org/all/20260128-d3cold-v1-1-dd8f3f0ce824@oss.qualcomm.com/ Signed-off-by: Krishna Chaitanya Chundru --- drivers/pci/controller/pci-host-common.c | 29 ++++++++++++++++++++++++ drivers/pci/controller/pci-host-common.h | 2 ++ 2 files changed, 31 insertions(+) diff --git a/drivers/pci/controller/pci-host-common.c b/drivers/pci/controller/pci-host-common.c index 810d1c8de24e9..aed69fc95241f 100644 --- a/drivers/pci/controller/pci-host-common.c +++ b/drivers/pci/controller/pci-host-common.c @@ -105,5 +105,34 @@ void pci_host_common_remove(struct platform_device *pdev) } EXPORT_SYMBOL_GPL(pci_host_common_remove); +static int pci_host_common_check_d3cold(struct pci_dev *pdev, void *userdata) +{ + bool *d3cold_allow = userdata; + + if (pci_pcie_type(pdev) != PCI_EXP_TYPE_ENDPOINT) + return 0; + + if (pdev->current_state != PCI_D3hot) + goto exit; + + if (device_may_wakeup(&pdev->dev) && !pci_pme_capable(pdev, PCI_D3cold)) + goto exit; + + return 0; +exit: + *d3cold_allow = false; + return -EBUSY; +} + +bool pci_host_common_can_enter_d3cold(struct pci_host_bridge *bridge) +{ + bool d3cold_allow = true; + + pci_walk_bus(bridge->bus, pci_host_common_check_d3cold, &d3cold_allow); + + return d3cold_allow; +} +EXPORT_SYMBOL_GPL(pci_host_common_can_enter_d3cold); + MODULE_DESCRIPTION("Common library for PCI host controller drivers"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/pci/controller/pci-host-common.h b/drivers/pci/controller/pci-host-common.h index 51c35ec0cf37d..5ec7e6929f4e0 100644 --- a/drivers/pci/controller/pci-host-common.h +++ b/drivers/pci/controller/pci-host-common.h @@ -19,4 +19,6 @@ void pci_host_common_remove(struct platform_device *pdev); struct pci_config_window *pci_host_common_ecam_create(struct device *dev, struct pci_host_bridge *bridge, const struct pci_ecam_ops *ops); + +bool pci_host_common_can_enter_d3cold(struct pci_host_bridge *bridge); #endif From 9a87666b62e050c772a346c01eba2ba08e49ef82 Mon Sep 17 00:00:00 2001 From: Krishna Chaitanya Chundru Date: Wed, 28 Jan 2026 17:10:42 +0530 Subject: [PATCH 2243/2333] FROMLIST: PCI: dwc: Use common D3cold eligibility helper in suspend path Previously, the driver skipped putting the link into L2/device state in D3cold whenever L1 ASPM was enabled, since some devices (e.g. NVMe) expect low resume latency and may not tolerate deeper power states. However, such devices typically remain in D0 and are already covered by the new helper's requirement that all endpoints be in D3hot before the host bridge may enter D3cold. So, replace the local L1/L1SS-based check in dw_pcie_suspend_noirq() with the shared pci_host_common_can_enter_d3cold() helper to decide whether the DesignWare host bridge can safely transition to D3cold. Link: https://lore.kernel.org/all/20260128-d3cold-v1-2-dd8f3f0ce824@oss.qualcomm.com/ Signed-off-by: Krishna Chaitanya Chundru --- drivers/pci/controller/dwc/pcie-designware-host.c | 7 +------ drivers/pci/controller/dwc/pcie-designware.h | 1 + 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c index 4bca571309e3f..bea1a2b883477 100644 --- a/drivers/pci/controller/dwc/pcie-designware-host.c +++ b/drivers/pci/controller/dwc/pcie-designware-host.c @@ -1163,15 +1163,10 @@ static int dw_pcie_pme_turn_off(struct dw_pcie *pci) int dw_pcie_suspend_noirq(struct dw_pcie *pci) { - u8 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP); u32 val; int ret; - /* - * If L1SS is supported, then do not put the link into L2 as some - * devices such as NVMe expect low resume latency. - */ - if (dw_pcie_readw_dbi(pci, offset + PCI_EXP_LNKCTL) & PCI_EXP_LNKCTL_ASPM_L1) + if (!pci_host_common_can_enter_d3cold(pci->pp.bridge)) return 0; if (pci->pp.ops->pme_turn_off) { diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index 5f5574a82224b..64656371a5b50 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -26,6 +26,7 @@ #include #include +#include "../pci-host-common.h" #include "../../pci.h" /* DWC PCIe IP-core versions (native support since v4.70a) */ From 6fe6cc60bf89fef46fdf09c80ba257af37a4f7df Mon Sep 17 00:00:00 2001 From: Krishna Chaitanya Chundru Date: Wed, 28 Jan 2026 17:10:43 +0530 Subject: [PATCH 2244/2333] FROMLIST: PCI: qcom: Add D3cold support Add pme_turn_off() support and use DWC common suspend resume methods for device D3cold entry & exit. If the device is not kept in D3cold use existing methods like keeping icc votes, opp votes etc.. intact. In qcom_pcie_deinit_2_7_0(), explicitly disable PCIe clocks and resets in the controller. Remove suspended flag from qcom_pcie structure as it is no longer needed. Link: https://lore.kernel.org/all/20260128-d3cold-v1-2-dd8f3f0ce824@oss.qualcomm.com/ Signed-off-by: Krishna Chaitanya Chundru --- drivers/pci/controller/dwc/pcie-qcom.c | 116 +++++++++++++++---------- 1 file changed, 69 insertions(+), 47 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c index d81a479e49ef2..44085f329d6be 100644 --- a/drivers/pci/controller/dwc/pcie-qcom.c +++ b/drivers/pci/controller/dwc/pcie-qcom.c @@ -150,6 +150,7 @@ /* ELBI_SYS_CTRL register fields */ #define ELBI_SYS_CTRL_LT_ENABLE BIT(0) +#define ELBI_SYS_CTRL_PME_TURNOFF_MSG BIT(4) /* AXI_MSTR_RESP_COMP_CTRL0 register fields */ #define CFG_REMOTE_RD_REQ_BRIDGE_SIZE_2K 0x4 @@ -284,7 +285,6 @@ struct qcom_pcie { const struct qcom_pcie_cfg *cfg; struct dentry *debugfs; struct list_head ports; - bool suspended; bool use_pm_opp; }; @@ -1093,6 +1093,12 @@ static void qcom_pcie_host_post_init_2_7_0(struct qcom_pcie *pcie) static void qcom_pcie_deinit_2_7_0(struct qcom_pcie *pcie) { struct qcom_pcie_resources_2_7_0 *res = &pcie->res.v2_7_0; + u32 val; + + /* Disable PCIe clocks and resets */ + val = readl(pcie->parf + PARF_PHY_CTRL); + val |= PHY_TEST_PWR_DOWN; + writel(val, pcie->parf + PARF_PHY_CTRL); clk_bulk_disable_unprepare(res->num_clks, res->clks); @@ -1373,10 +1379,18 @@ static void qcom_pcie_host_post_init(struct dw_pcie_rp *pp) pcie->cfg->ops->host_post_init(pcie); } +static void qcom_pcie_host_pme_turn_off(struct dw_pcie_rp *pp) +{ + struct dw_pcie *pci = to_dw_pcie_from_pp(pp); + + writel(ELBI_SYS_CTRL_PME_TURNOFF_MSG, pci->elbi_base + ELBI_SYS_CTRL); +} + static const struct dw_pcie_host_ops qcom_pcie_dw_ops = { .init = qcom_pcie_host_init, .deinit = qcom_pcie_host_deinit, .post_init = qcom_pcie_host_post_init, + .pme_turn_off = qcom_pcie_host_pme_turn_off, }; /* Qcom IP rev.: 2.1.0 Synopsys IP rev.: 4.01a */ @@ -2023,53 +2037,51 @@ static int qcom_pcie_suspend_noirq(struct device *dev) if (!pcie) return 0; - /* - * Set minimum bandwidth required to keep data path functional during - * suspend. - */ - if (pcie->icc_mem) { - ret = icc_set_bw(pcie->icc_mem, 0, kBps_to_icc(1)); - if (ret) { - dev_err(dev, - "Failed to set bandwidth for PCIe-MEM interconnect path: %d\n", - ret); - return ret; - } - } + ret = dw_pcie_suspend_noirq(pcie->pci); + if (ret) + return ret; - /* - * Turn OFF the resources only for controllers without active PCIe - * devices. For controllers with active devices, the resources are kept - * ON and the link is expected to be in L0/L1 (sub)states. - * - * Turning OFF the resources for controllers with active PCIe devices - * will trigger access violation during the end of the suspend cycle, - * as kernel tries to access the PCIe devices config space for masking - * MSIs. - * - * Also, it is not desirable to put the link into L2/L3 state as that - * implies VDD supply will be removed and the devices may go into - * powerdown state. This will affect the lifetime of the storage devices - * like NVMe. - */ - if (!dw_pcie_link_up(pcie->pci)) { - qcom_pcie_host_deinit(&pcie->pci->pp); - pcie->suspended = true; - } + if (pcie->pci->suspended) { + ret = icc_disable(pcie->icc_mem); + if (ret) + dev_err(dev, "Failed to disable PCIe-MEM interconnect path: %d\n", ret); - /* - * Only disable CPU-PCIe interconnect path if the suspend is non-S2RAM. - * Because on some platforms, DBI access can happen very late during the - * S2RAM and a non-active CPU-PCIe interconnect path may lead to NoC - * error. - */ - if (pm_suspend_target_state != PM_SUSPEND_MEM) { ret = icc_disable(pcie->icc_cpu); if (ret) dev_err(dev, "Failed to disable CPU-PCIe interconnect path: %d\n", ret); if (pcie->use_pm_opp) dev_pm_opp_set_opp(pcie->pci->dev, NULL); + } else { + /* + * Set minimum bandwidth required to keep data path functional during + * suspend. + */ + if (pcie->icc_mem) { + ret = icc_set_bw(pcie->icc_mem, 0, kBps_to_icc(1)); + if (ret) { + dev_err(dev, + "Failed to set bandwidth for PCIe-MEM interconnect path: %d\n", + ret); + return ret; + } + } + + /* + * Only disable CPU-PCIe interconnect path if the suspend is non-S2RAM. + * Because on some platforms, DBI access can happen very late during the + * S2RAM and a non-active CPU-PCIe interconnect path may lead to NoC + * error. + */ + if (pm_suspend_target_state != PM_SUSPEND_MEM) { + ret = icc_disable(pcie->icc_cpu); + if (ret) + dev_err(dev, "Failed to disable CPU-PCIe interconnect path: %d\n", + ret); + + if (pcie->use_pm_opp) + dev_pm_opp_set_opp(pcie->pci->dev, NULL); + } } return ret; } @@ -2083,20 +2095,30 @@ static int qcom_pcie_resume_noirq(struct device *dev) if (!pcie) return 0; - if (pm_suspend_target_state != PM_SUSPEND_MEM) { + if (pcie->pci->suspended) { ret = icc_enable(pcie->icc_cpu); if (ret) { dev_err(dev, "Failed to enable CPU-PCIe interconnect path: %d\n", ret); return ret; } - } - if (pcie->suspended) { - ret = qcom_pcie_host_init(&pcie->pci->pp); - if (ret) + ret = icc_enable(pcie->icc_mem); + if (ret) { + dev_err(dev, "Failed to enable PCIe-MEM interconnect path: %d\n", ret); return ret; - - pcie->suspended = false; + } + ret = dw_pcie_resume_noirq(pcie->pci); + if (ret && (ret != -ETIMEDOUT)) + return ret; + } else { + if (pm_suspend_target_state != PM_SUSPEND_MEM) { + ret = icc_enable(pcie->icc_cpu); + if (ret) { + dev_err(dev, "Failed to enable CPU-PCIe interconnect path: %d\n", + ret); + return ret; + } + } } qcom_pcie_icc_opp_update(pcie); From c6c36f106f40f82d5ca0b1191e31ed20787989c1 Mon Sep 17 00:00:00 2001 From: Krishna Chaitanya Chundru Date: Wed, 28 Jan 2026 17:52:42 +0530 Subject: [PATCH 2245/2333] FROMLIST: PCI: qcom: Prevent GDSC power down on suspend Currently, the driver expects the devices to remain in D0 across system suspend, but the genpd framework may still power down the associated GDSC during suspend. When that happens, the PCIe link goes down and cannot be recovered on resume. Prevent genpd from turning off the PCIe GDSC by using dev_pm_genpd_rpm_always_on() so that the power domain stays on while the controller is suspended. This preserves the link state across suspend/resume and avoids unrecoverable link failures. Link: https://lore.kernel.org/all/20260128-genpd_fix-v1-1-cd45a249d12f@oss.qualcomm.com/ Fixes: 82a823833f4e ("PCI: qcom: Add Qualcomm PCIe controller driver") Cc: stable@vger.kernel.org Signed-off-by: Krishna Chaitanya Chundru --- drivers/pci/controller/dwc/pcie-qcom.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c index 44085f329d6be..ee84031b8361d 100644 --- a/drivers/pci/controller/dwc/pcie-qcom.c +++ b/drivers/pci/controller/dwc/pcie-qcom.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -2041,6 +2042,11 @@ static int qcom_pcie_suspend_noirq(struct device *dev) if (ret) return ret; + if (pcie->pci->suspended) + dev_pm_genpd_rpm_always_on(dev, false); + else + dev_pm_genpd_rpm_always_on(dev, true); + if (pcie->pci->suspended) { ret = icc_disable(pcie->icc_mem); if (ret) From 662bac5f59384963f67d7b6f137cb1a2aed2fdfd Mon Sep 17 00:00:00 2001 From: Krishna Chaitanya Chundru Date: Mon, 9 Feb 2026 17:34:10 +0530 Subject: [PATCH 2246/2333] WORKAROUND: arm64: dts: qcom: Add qref supply for QCS8300 The QMP PCIe PHYs on QCS8300 require a dedicated qref voltage supply for stable operation. Add the vdda-qref-supply for both PCIe PHY instances on the QCS8300-RIDE Monaco-evk. Without this supply, the system may occasionally crash mainly in system resume case. Signed-off-by: Krishna Chaitanya Chundru --- arch/arm64/boot/dts/qcom/monaco-evk.dts | 2 ++ arch/arm64/boot/dts/qcom/qcs8300-ride.dts | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/monaco-evk.dts b/arch/arm64/boot/dts/qcom/monaco-evk.dts index dd55254e460a8..79530c15839cc 100644 --- a/arch/arm64/boot/dts/qcom/monaco-evk.dts +++ b/arch/arm64/boot/dts/qcom/monaco-evk.dts @@ -556,6 +556,7 @@ &pcie0_phy { vdda-phy-supply = <&vreg_l6a>; vdda-pll-supply = <&vreg_l5a>; + vdda-qref-supply = <&vreg_l4a>; status = "okay"; }; @@ -575,6 +576,7 @@ &pcie1_phy { vdda-phy-supply = <&vreg_l6a>; vdda-pll-supply = <&vreg_l5a>; + vdda-qref-supply = <&vreg_l4a>; status = "okay"; }; diff --git a/arch/arm64/boot/dts/qcom/qcs8300-ride.dts b/arch/arm64/boot/dts/qcom/qcs8300-ride.dts index 010209b0eadb9..faf21337b9816 100644 --- a/arch/arm64/boot/dts/qcom/qcs8300-ride.dts +++ b/arch/arm64/boot/dts/qcom/qcs8300-ride.dts @@ -602,7 +602,8 @@ &pcie0_phy { vdda-phy-supply = <&vreg_l6a>; - vdda-pll-supply = <&vreg_l4a>; + vdda-pll-supply = <&vreg_l5a>; + vdda-qref-supply = <&vreg_l4a>; status = "okay"; }; @@ -622,6 +623,7 @@ &pcie1_phy { vdda-phy-supply = <&vreg_l6a>; vdda-pll-supply = <&vreg_l5a>; + vdda-qref-supply = <&vreg_l4a>; status = "okay"; }; From 0dd71caa74551e7a65c1d63d7eef7bfa5b552948 Mon Sep 17 00:00:00 2001 From: Krishna Chaitanya Chundru Date: Mon, 9 Feb 2026 17:39:03 +0530 Subject: [PATCH 2247/2333] WORKAROUND: phy: qcom: qmp-pcie: Add qref regulator vote for QCS8300 Include qref regulator in the vreg list to improve PCIe PHY stability on QCS8300 platform. Reuse sm8550_qmp_phy_vreg_l for QCS8300 PHY to include qref regulator. Signed-off-by: Krishna Chaitanya Chundru --- drivers/phy/qualcomm/phy-qcom-qmp-pcie.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c index 5b53f03771d8f..d9571af517061 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c @@ -3572,8 +3572,8 @@ static const struct qmp_phy_cfg qcs8300_qmp_gen4x2_pciephy_cfg = { .reset_list = sdm845_pciephy_reset_l, .num_resets = ARRAY_SIZE(sdm845_pciephy_reset_l), - .vreg_list = qmp_phy_vreg_l, - .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), + .vreg_list = sm8550_qmp_phy_vreg_l, + .num_vregs = ARRAY_SIZE(sm8550_qmp_phy_vreg_l), .regs = pciephy_v5_regs_layout, .pwrdn_ctrl = SW_PWRDN | REFCLK_DRV_DSBL, @@ -4323,8 +4323,8 @@ static const struct qmp_phy_cfg sa8775p_qmp_gen4x4_pciephy_cfg = { .reset_list = sdm845_pciephy_reset_l, .num_resets = ARRAY_SIZE(sdm845_pciephy_reset_l), - .vreg_list = qmp_phy_vreg_l, - .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), + .vreg_list = sm8550_qmp_phy_vreg_l, + .num_vregs = ARRAY_SIZE(sm8550_qmp_phy_vreg_l), .regs = pciephy_v5_regs_layout, .pwrdn_ctrl = SW_PWRDN | REFCLK_DRV_DSBL, From d077d8568f2db28882b917b7bb829d354711c313 Mon Sep 17 00:00:00 2001 From: Krishna Chaitanya Chundru Date: Mon, 9 Feb 2026 17:49:38 +0530 Subject: [PATCH 2248/2333] WORKAROUND: pci: quirks: Disable L1.1 and L1.2 for USB hub attach When ASPM L1.1/L1.2 is enabled on the upstream link of QPS615 switch,and Renesas uPD720201 USB 3.0 Controller is connected to one of the switch downstream ports, then uPD dies down and stops responding to host commands. Disabling l1 sub-states on the upstream link in uPD attach case helps mitigate this issue. Signed-off-by: Krishna Chaitanya Chundru --- drivers/pci/quirks.c | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index a51dab62ecef6..a0c91e1a6cca6 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -2533,6 +2533,49 @@ static void quirk_disable_aspm_l1ss(struct pci_dev *dev) } DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_QCOM, 0x1103, quirk_disable_aspm_l1ss); +static int disable_aspm_l1ss(struct pci_dev *dev, void *data) +{ + pci_disable_link_state(dev, PCIE_LINK_STATE_L1_1 | PCIE_LINK_STATE_L1_2); + return 0; +} + +static void quirk_disable_l1ss(struct pci_dev *dev) +{ + struct pci_dev *root_port; + struct pci_dev *upstream; + + pci_info(dev, "Disabling ASPM L1ss\n"); + + upstream = dev->bus->self; + while (upstream) { + if (pci_pcie_type(upstream) == PCI_EXP_TYPE_ROOT_PORT) { + root_port = upstream; + break; + } + + /* Move further up the hierarchy */ + upstream = upstream->bus->self; + } + + if (!root_port) { + pci_err(dev, "Could not find root port, cannot disable L1ss\n"); + return; + } + + pci_info(dev, "Found root-port with VID: %04x PID: %04x, disabling l1ss\n", + root_port->vendor, root_port->device); + + pci_walk_bus(root_port->subordinate, disable_aspm_l1ss, NULL); +} + +/* + * When ASPM L1.1/L1.2 is enabled on the upstream link of QPS615 switch, + * and Renesas uPD720201 USB 3.0 Controller is connected to one of the switch + * downstream ports, then uPD dies down and stops responding to host commands; + * disabling l1 sub-states in uPD attach case helps mitigate this issue. + */ +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_RENESAS, 0x0014, quirk_disable_l1ss); + /* * Some Pericom PCIe-to-PCI bridges in reverse mode need the PCIe Retrain * Link bit cleared after starting the link retrain process to allow this From 3f4a09a1ad2fa35e7c8bea11e11f74d6c507bbed Mon Sep 17 00:00:00 2001 From: Mohd Ayaan Anwar Date: Sun, 14 Sep 2025 20:36:48 +0530 Subject: [PATCH 2249/2333] FROMLIST: net: phy: qcom: qca808x: Add .get_rate_matching support Add support for rate matching to the QCA8081 PHY driver to correctly report its capabilities. Some boards[0][1] with this PHY currently report support only for 2.5G. Implement the .get_rate_matching callback to allow phylink to determine the actual PHY capabilities and report them accurately. Before: # ethtool eth0 Settings for eth0: Supported ports: [ ] Supported link modes: 2500baseT/Full Supported pause frame use: Symmetric Receive-only ... After: # ethtool eth0 Settings for eth0: Supported ports: [ ] Supported link modes: 10baseT/Half 10baseT/Full 100baseT/Half 100baseT/Full 1000baseT/Full 2500baseT/Full Supported pause frame use: Symmetric Receive-only ... [0] https://lore.kernel.org/all/20250905192350.1223812-3-umang.chheda@oss.qualcomm.com/ [1] https://lore.kernel.org/all/20250908-lemans-evk-bu-v4-12-5c319c696a7d@oss.qualcomm.com/ (cherry picked from commit d02d17363623cf15ba4ea228c8d7753d8675571e) Link: https://lore.kernel.org/netdev/20250914-qca808x_rate_match-v1-1-0f9e6a331c3b@oss.qualcomm.com/ Signed-off-by: Mohd Ayaan Anwar --- drivers/net/phy/qcom/qca808x.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/net/phy/qcom/qca808x.c b/drivers/net/phy/qcom/qca808x.c index 8eb51b1a006c4..f22ebb1ac3328 100644 --- a/drivers/net/phy/qcom/qca808x.c +++ b/drivers/net/phy/qcom/qca808x.c @@ -643,6 +643,15 @@ static void qca808x_get_phy_stats(struct phy_device *phydev, qcom_phy_get_stats(stats, priv->hw_stats); } +static int qca808x_get_rate_matching(struct phy_device *phydev, + phy_interface_t iface) +{ + if (iface == PHY_INTERFACE_MODE_2500BASEX) + return RATE_MATCH_PAUSE; + + return RATE_MATCH_NONE; +} + static struct phy_driver qca808x_driver[] = { { /* Qualcomm QCA8081 */ @@ -674,6 +683,7 @@ static struct phy_driver qca808x_driver[] = { .led_polarity_set = qca808x_led_polarity_set, .update_stats = qca808x_update_stats, .get_phy_stats = qca808x_get_phy_stats, + .get_rate_matching = qca808x_get_rate_matching, }, }; module_phy_driver(qca808x_driver); From 9882fb8c4df746b02029aa1a6f5c558bade8fc3d Mon Sep 17 00:00:00 2001 From: Jie Zhang Date: Mon, 9 Feb 2026 12:07:35 +0800 Subject: [PATCH 2250/2333] Revert "FROMLIST: arm64: dts: qcom: talos: add the GPU SMMU node" This reverts commit 5f825a2145c3d9f274b1e1c70e2698dcaf5db7d3. as latest version v7 of the commit is available. Signed-off-by: Jie Zhang --- arch/arm64/boot/dts/qcom/talos.dtsi | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/talos.dtsi b/arch/arm64/boot/dts/qcom/talos.dtsi index 41c26e0caf5bb..3bf5a51da71dd 100644 --- a/arch/arm64/boot/dts/qcom/talos.dtsi +++ b/arch/arm64/boot/dts/qcom/talos.dtsi @@ -2007,31 +2007,6 @@ #power-domain-cells = <1>; }; - adreno_smmu: iommu@50a0000 { - compatible = "qcom,qcs615-smmu-500", "qcom,adreno-smmu", - "qcom,smmu-500", "arm,mmu-500"; - reg = <0x0 0x050a0000 0x0 0x40000>; - #iommu-cells = <2>; - #global-interrupts = <1>; - interrupts = , - , - , - , - , - , - , - , - ; - clocks = <&gcc GCC_GPU_MEMNOC_GFX_CLK>, - <&gpucc GPU_CC_HLOS1_VOTE_GPU_SMMU_CLK>, - <&gcc GCC_GPU_SNOC_DVM_GFX_CLK>; - clock-names = "mem", - "hlos", - "iface"; - power-domains = <&gpucc CX_GDSC>; - dma-coherent; - }; - stm@6002000 { compatible = "arm,coresight-stm", "arm,primecell"; reg = <0x0 0x06002000 0x0 0x1000>, From 5bc55ad74cb11890e55a831b8c0bfaf8a164ba9d Mon Sep 17 00:00:00 2001 From: Jie Zhang Date: Mon, 9 Feb 2026 12:22:43 +0800 Subject: [PATCH 2251/2333] Revert "FROMLIST: arm64: dts: qcom: qcs615-ride: Enable Adreno 612 GPU" This reverts commit fd40a59c5dd8a09bff57513fce3259b68f92bae5. as latest version v7 of the commit is available. Signed-off-by: Jie Zhang --- arch/arm64/boot/dts/qcom/qcs615-ride.dts | 8 -------- arch/arm64/boot/dts/qcom/talos.dtsi | 2 +- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/qcs615-ride.dts b/arch/arm64/boot/dts/qcom/qcs615-ride.dts index 851ff7de4d464..39544c04e65a1 100644 --- a/arch/arm64/boot/dts/qcom/qcs615-ride.dts +++ b/arch/arm64/boot/dts/qcom/qcs615-ride.dts @@ -372,14 +372,6 @@ }; }; -&gpu { - status = "okay"; -}; - -&gpu_zap_shader { - firmware-name = "qcom/qcs615/a612_zap.mbn"; -}; - &i2c2 { clock-frequency = <400000>; status = "okay"; diff --git a/arch/arm64/boot/dts/qcom/talos.dtsi b/arch/arm64/boot/dts/qcom/talos.dtsi index 3bf5a51da71dd..3f5a94e04c6e9 100644 --- a/arch/arm64/boot/dts/qcom/talos.dtsi +++ b/arch/arm64/boot/dts/qcom/talos.dtsi @@ -1959,7 +1959,7 @@ gmu: gmu@506a000 { compatible = "qcom,adreno-rgmu-612.0", "qcom,adreno-rgmu"; - reg = <0x0 0x0506d000 0x0 0x2c000>; + reg = <0x0 0x0506a000 0x0 0x34000>; clocks = <&gpucc GPU_CC_CX_GMU_CLK>, <&gpucc GPU_CC_CXO_CLK>, From 26441f5a13ece439866c19933ed8547d73caa382 Mon Sep 17 00:00:00 2001 From: Jie Zhang Date: Mon, 9 Feb 2026 12:28:23 +0800 Subject: [PATCH 2252/2333] Revert "FROMLIST: arm64: dts: qcom: talos: Add gpu and rgmu nodes" This reverts commit 22b9fb659a19c90272ec715af9e0444324d79907. as latest version v7 of the commit is available. Signed-off-by: Jie Zhang --- arch/arm64/boot/dts/qcom/talos.dtsi | 110 ---------------------------- 1 file changed, 110 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/talos.dtsi b/arch/arm64/boot/dts/qcom/talos.dtsi index 3f5a94e04c6e9..89a668dfeb494 100644 --- a/arch/arm64/boot/dts/qcom/talos.dtsi +++ b/arch/arm64/boot/dts/qcom/talos.dtsi @@ -650,11 +650,6 @@ no-map; }; - pil_gpu_mem: pil-gpu@97715000 { - reg = <0x0 0x97715000 0x0 0x2000>; - no-map; - }; - pil_camera_mem: pil-camera-region@97717000 { reg = <0x0 0x97717000 0x0 0x800000>; no-map; @@ -1889,111 +1884,6 @@ }; }; - gpu: gpu@5000000 { - compatible = "qcom,adreno-612.0", "qcom,adreno"; - reg = <0x0 0x05000000 0x0 0x40000>, - <0x0 0x0509e000 0x0 0x1000>, - <0x0 0x05061000 0x0 0x800>; - reg-names = "kgsl_3d0_reg_memory", - "cx_mem", - "cx_dbgc"; - - clocks = <&gpucc GPU_CC_GX_GFX3D_CLK>; - clock-names = "core"; - - interrupts = ; - - interconnects = <&gem_noc MASTER_GFX3D QCOM_ICC_TAG_ALWAYS - &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; - interconnect-names = "gfx-mem"; - - iommus = <&adreno_smmu 0x0 0x401>; - - operating-points-v2 = <&gpu_opp_table>; - power-domains = <&rpmhpd RPMHPD_CX>; - - qcom,gmu = <&gmu>; - - #cooling-cells = <2>; - - status = "disabled"; - - gpu_zap_shader: zap-shader { - memory-region = <&pil_gpu_mem>; - }; - - gpu_opp_table: opp-table { - compatible = "operating-points-v2"; - - opp-845000000 { - opp-hz = /bits/ 64 <845000000>; - required-opps = <&rpmhpd_opp_turbo>; - opp-peak-kBps = <7050000>; - }; - - opp-745000000 { - opp-hz = /bits/ 64 <745000000>; - required-opps = <&rpmhpd_opp_nom_l1>; - opp-peak-kBps = <6075000>; - }; - - opp-650000000 { - opp-hz = /bits/ 64 <650000000>; - required-opps = <&rpmhpd_opp_nom>; - opp-peak-kBps = <5287500>; - }; - - opp-500000000 { - opp-hz = /bits/ 64 <500000000>; - required-opps = <&rpmhpd_opp_svs_l1>; - opp-peak-kBps = <3975000>; - }; - - opp-435000000 { - opp-hz = /bits/ 64 <435000000>; - required-opps = <&rpmhpd_opp_svs>; - opp-peak-kBps = <3000000>; - }; - }; - }; - - gmu: gmu@506a000 { - compatible = "qcom,adreno-rgmu-612.0", "qcom,adreno-rgmu"; - reg = <0x0 0x0506a000 0x0 0x34000>; - - clocks = <&gpucc GPU_CC_CX_GMU_CLK>, - <&gpucc GPU_CC_CXO_CLK>, - <&gcc GCC_DDRSS_GPU_AXI_CLK>, - <&gcc GCC_GPU_MEMNOC_GFX_CLK>, - <&gpucc GPU_CC_HLOS1_VOTE_GPU_SMMU_CLK>; - clock-names = "gmu", - "cxo", - "axi", - "memnoc", - "smmu_vote"; - - power-domains = <&gpucc CX_GDSC>, - <&gpucc GX_GDSC>; - power-domain-names = "cx", - "gx"; - - interrupts = , - ; - interrupt-names = "oob", - "gmu"; - - operating-points-v2 = <&gmu_opp_table>; - - gmu_opp_table: opp-table { - compatible = "operating-points-v2"; - - opp-200000000 { - opp-hz = /bits/ 64 <200000000>; - required-opps = <&rpmhpd_opp_low_svs>; - }; - }; - }; - gpucc: clock-controller@5090000 { compatible = "qcom,qcs615-gpucc"; reg = <0 0x05090000 0 0x9000>; From f2f1d004b2108bf05e622eac49028b1c44b0b463 Mon Sep 17 00:00:00 2001 From: Qingqing Zhou Date: Wed, 21 Jan 2026 03:35:52 +0530 Subject: [PATCH 2253/2333] FROMLIST: arm64: dts: qcom: talos: add the GPU SMMU node Add the Adreno GPU SMMU node for Talos chipset. Signed-off-by: Qingqing Zhou Signed-off-by: Jie Zhang Signed-off-by: Akhil P Oommen Reviewed-by: Dmitry Baryshkov Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20260121-qcs615-spin-2-v7-1-52419b263e92@oss.qualcomm.com --- arch/arm64/boot/dts/qcom/talos.dtsi | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/talos.dtsi b/arch/arm64/boot/dts/qcom/talos.dtsi index 89a668dfeb494..2edc4dfbd4421 100644 --- a/arch/arm64/boot/dts/qcom/talos.dtsi +++ b/arch/arm64/boot/dts/qcom/talos.dtsi @@ -1897,6 +1897,31 @@ #power-domain-cells = <1>; }; + adreno_smmu: iommu@50a0000 { + compatible = "qcom,qcs615-smmu-500", "qcom,adreno-smmu", + "qcom,smmu-500", "arm,mmu-500"; + reg = <0x0 0x050a0000 0x0 0x40000>; + #iommu-cells = <2>; + #global-interrupts = <1>; + interrupts = , + , + , + , + , + , + , + , + ; + clocks = <&gcc GCC_GPU_MEMNOC_GFX_CLK>, + <&gpucc GPU_CC_HLOS1_VOTE_GPU_SMMU_CLK>, + <&gcc GCC_GPU_SNOC_DVM_GFX_CLK>; + clock-names = "mem", + "hlos", + "iface"; + power-domains = <&gpucc CX_GDSC>; + dma-coherent; + }; + stm@6002000 { compatible = "arm,coresight-stm", "arm,primecell"; reg = <0x0 0x06002000 0x0 0x1000>, From 980a825f471ef3ae6bbcd3522d3dcb5c38973557 Mon Sep 17 00:00:00 2001 From: Jie Zhang Date: Mon, 9 Feb 2026 12:47:18 +0800 Subject: [PATCH 2254/2333] FROMLIST: arm64: dts: qcom: talos: Add gpu and rgmu nodes Add gpu and rgmu nodes for Talos chipset. Signed-off-by: Jie Zhang Reviewed-by: Dmitry Baryshkov Reviewed-by: Konrad Dybcio Signed-off-by: Akhil P Oommen Link: https://lore.kernel.org/r/20260121-qcs615-spin-2-v7-2-52419b263e92@oss.qualcomm.com --- arch/arm64/boot/dts/qcom/talos.dtsi | 110 ++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/talos.dtsi b/arch/arm64/boot/dts/qcom/talos.dtsi index 2edc4dfbd4421..1a78603c56571 100644 --- a/arch/arm64/boot/dts/qcom/talos.dtsi +++ b/arch/arm64/boot/dts/qcom/talos.dtsi @@ -650,6 +650,11 @@ no-map; }; + pil_gpu_mem: pil-gpu@97715000 { + reg = <0x0 0x97715000 0x0 0x2000>; + no-map; + }; + pil_camera_mem: pil-camera-region@97717000 { reg = <0x0 0x97717000 0x0 0x800000>; no-map; @@ -1884,6 +1889,111 @@ }; }; + gpu: gpu@5000000 { + compatible = "qcom,adreno-612.0", "qcom,adreno"; + reg = <0x0 0x05000000 0x0 0x40000>, + <0x0 0x0509e000 0x0 0x1000>, + <0x0 0x05061000 0x0 0x800>; + reg-names = "kgsl_3d0_reg_memory", + "cx_mem", + "cx_dbgc"; + + clocks = <&gpucc GPU_CC_GX_GFX3D_CLK>; + clock-names = "core"; + + interrupts = ; + + interconnects = <&gem_noc MASTER_GFX3D QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "gfx-mem"; + + iommus = <&adreno_smmu 0x0 0x401>; + + operating-points-v2 = <&gpu_opp_table>; + power-domains = <&rpmhpd RPMHPD_CX>; + + qcom,gmu = <&gmu>; + + #cooling-cells = <2>; + + status = "disabled"; + + gpu_zap_shader: zap-shader { + memory-region = <&pil_gpu_mem>; + }; + + gpu_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-845000000 { + opp-hz = /bits/ 64 <845000000>; + required-opps = <&rpmhpd_opp_turbo>; + opp-peak-kBps = <7050000>; + }; + + opp-745000000 { + opp-hz = /bits/ 64 <745000000>; + required-opps = <&rpmhpd_opp_nom_l1>; + opp-peak-kBps = <6075000>; + }; + + opp-650000000 { + opp-hz = /bits/ 64 <650000000>; + required-opps = <&rpmhpd_opp_nom>; + opp-peak-kBps = <5287500>; + }; + + opp-500000000 { + opp-hz = /bits/ 64 <500000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + opp-peak-kBps = <3975000>; + }; + + opp-435000000 { + opp-hz = /bits/ 64 <435000000>; + required-opps = <&rpmhpd_opp_svs>; + opp-peak-kBps = <3000000>; + }; + }; + }; + + gmu: gmu@506a000 { + compatible = "qcom,adreno-rgmu-612.0", "qcom,adreno-rgmu"; + reg = <0x0 0x0506d000 0x0 0x2c000>; + + clocks = <&gpucc GPU_CC_CX_GMU_CLK>, + <&gpucc GPU_CC_CXO_CLK>, + <&gcc GCC_DDRSS_GPU_AXI_CLK>, + <&gcc GCC_GPU_MEMNOC_GFX_CLK>, + <&gpucc GPU_CC_HLOS1_VOTE_GPU_SMMU_CLK>; + clock-names = "gmu", + "cxo", + "axi", + "memnoc", + "smmu_vote"; + + power-domains = <&gpucc CX_GDSC>, + <&gpucc GX_GDSC>; + power-domain-names = "cx", + "gx"; + + interrupts = , + ; + interrupt-names = "oob", + "gmu"; + + operating-points-v2 = <&gmu_opp_table>; + + gmu_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-200000000 { + opp-hz = /bits/ 64 <200000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + }; + }; + gpucc: clock-controller@5090000 { compatible = "qcom,qcs615-gpucc"; reg = <0 0x05090000 0 0x9000>; From 68990febd72a5b01bc9e6b16d0b6e5f6b0abda79 Mon Sep 17 00:00:00 2001 From: Jie Zhang Date: Wed, 21 Jan 2026 03:35:55 +0530 Subject: [PATCH 2255/2333] FROMLIST: arm64: dts: qcom: qcs615-ride: Enable Adreno 612 GPU Enable GPU for qcs615-ride platform and provide path for zap shader. Signed-off-by: Jie Zhang Signed-off-by: Akhil P Oommen Reviewed-by: Konrad Dybcio Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20260121-qcs615-spin-2-v7-4-52419b263e92@oss.qualcomm.com --- arch/arm64/boot/dts/qcom/qcs615-ride.dts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/qcs615-ride.dts b/arch/arm64/boot/dts/qcom/qcs615-ride.dts index 39544c04e65a1..851ff7de4d464 100644 --- a/arch/arm64/boot/dts/qcom/qcs615-ride.dts +++ b/arch/arm64/boot/dts/qcom/qcs615-ride.dts @@ -372,6 +372,14 @@ }; }; +&gpu { + status = "okay"; +}; + +&gpu_zap_shader { + firmware-name = "qcom/qcs615/a612_zap.mbn"; +}; + &i2c2 { clock-frequency = <400000>; status = "okay"; From f9ec2ac842fb6ea80141e1bd488bc3c8040683e2 Mon Sep 17 00:00:00 2001 From: Jie Zhang Date: Tue, 3 Feb 2026 17:32:31 +0800 Subject: [PATCH 2256/2333] PENDING: arm64: dts: qcom: talos-evk-som: Enable Adreno 612 GPU Enable GPU for talos-evk-som platform and provide path for zap shader. Signed-off-by: Jie Zhang --- arch/arm64/boot/dts/qcom/talos-evk-som.dtsi | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/talos-evk-som.dtsi b/arch/arm64/boot/dts/qcom/talos-evk-som.dtsi index e63f88da8ff6f..8a599ed25f76e 100644 --- a/arch/arm64/boot/dts/qcom/talos-evk-som.dtsi +++ b/arch/arm64/boot/dts/qcom/talos-evk-som.dtsi @@ -340,6 +340,14 @@ status = "okay"; }; +&gpu { + status = "okay"; +}; + +&gpu_zap_shader { + firmware-name = "qcom/qcs615/a612_zap.mbn"; +}; + &i2c5 { clock-frequency = <400000>; status = "okay"; From 9244aa234ea6d73578af3bea7473ca68b79b89e2 Mon Sep 17 00:00:00 2001 From: Janaki Ramaiah Thota Date: Tue, 3 Feb 2026 12:48:07 +0530 Subject: [PATCH 2257/2333] FROMLIST: arm64: dts: qcom: qcm6490-idp: add and enable BT node Add the PMU node for WCN6750 present on the qcm6490-idp board and assign its power outputs to the Bluetooth module. In WCN6750 module sw_ctrl and wifi-enable pins are handled in the wifi controller firmware. Therefore, it is not required to have those pins' entries in the PMU node. Link: https://lore.kernel.org/r/20260203071807.764036-1-janaki.thota@oss.qualcomm.com Reviewed-by: Konrad Dybcio Signed-off-by: Janaki Ramaiah Thota CRs-Fixed: 4435063 --- arch/arm64/boot/dts/qcom/qcm6490-idp.dts | 169 +++++++++++++++++++++++ 1 file changed, 169 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/qcm6490-idp.dts b/arch/arm64/boot/dts/qcom/qcm6490-idp.dts index 84322b74917f3..a65ec8dc873e5 100644 --- a/arch/arm64/boot/dts/qcom/qcm6490-idp.dts +++ b/arch/arm64/boot/dts/qcom/qcm6490-idp.dts @@ -36,6 +36,7 @@ aliases { serial0 = &uart5; + serial1 = &uart7; }; pm8350c_pwm_backlight: backlight { @@ -194,6 +195,63 @@ #sound-dai-cells = <1>; }; + + wcn6750-pmu { + compatible = "qcom,wcn6750-pmu"; + pinctrl-0 = <&bt_en>; + pinctrl-names = "default"; + vddaon-supply = <&vreg_s7b_0p972>; + vddasd-supply = <&vreg_l11c_2p8>; + vddpmu-supply = <&vreg_s7b_0p972>; + vddrfa0p8-supply = <&vreg_s7b_0p972>; + vddrfa1p2-supply = <&vreg_s8b_1p272>; + vddrfa1p7-supply = <&vreg_s1b_1p872>; + vddrfa2p2-supply = <&vreg_s1c_2p19>; + + bt-enable-gpios = <&tlmm 85 GPIO_ACTIVE_HIGH>; + + regulators { + vreg_pmu_rfa_cmn: ldo0 { + regulator-name = "vreg_pmu_rfa_cmn"; + }; + + vreg_pmu_aon_0p59: ldo1 { + regulator-name = "vreg_pmu_aon_0p59"; + }; + + vreg_pmu_wlcx_0p8: ldo2 { + regulator-name = "vreg_pmu_wlcx_0p8"; + }; + + vreg_pmu_wlmx_0p85: ldo3 { + regulator-name = "vreg_pmu_wlmx_0p85"; + }; + + vreg_pmu_btcmx_0p85: ldo4 { + regulator-name = "vreg_pmu_btcmx_0p85"; + }; + + vreg_pmu_rfa_0p8: ldo5 { + regulator-name = "vreg_pmu_rfa_0p8"; + }; + + vreg_pmu_rfa_1p2: ldo6 { + regulator-name = "vreg_pmu_rfa_1p2"; + }; + + vreg_pmu_rfa_1p7: ldo7 { + regulator-name = "vreg_pmu_rfa_1p7"; + }; + + vreg_pmu_pcie_0p9: ldo8 { + regulator-name = "vreg_pmu_pcie_0p9"; + }; + + vreg_pmu_pcie_1p8: ldo9 { + regulator-name = "vreg_pmu_pcie_1p8"; + }; + }; + }; }; &apps_rsc { @@ -702,6 +760,39 @@ }; }; +&qup_uart7_cts { + /* + * Configure a bias-bus-hold on CTS to lower power + * usage when Bluetooth is turned off. Bus hold will + * maintain a low power state regardless of whether + * the Bluetooth module drives the pin in either + * direction or leaves the pin fully unpowered. + */ + bias-bus-hold; +}; + +&qup_uart7_rts { + /* We'll drive RTS, so no pull */ + drive-strength = <2>; + bias-disable; +}; + +&qup_uart7_rx { + /* + * Configure a pull-up on RX. This is needed to avoid + * garbage data when the TX pin of the Bluetooth module is + * in tri-state (module powered off or not driving the + * signal yet). + */ + bias-pull-up; +}; + +&qup_uart7_tx { + /* We'll drive TX, so no pull */ + drive-strength = <2>; + bias-disable; +}; + &qupv3_id_0 { status = "okay"; }; @@ -927,6 +1018,59 @@ gpio-reserved-ranges = <32 2>, /* ADSP */ <48 4>; /* NFC */ + bt_en: bt-en-state { + pins = "gpio85"; + function = "gpio"; + output-low; + bias-disable; + }; + + qup_uart7_sleep_cts: qup-uart7-sleep-cts-state { + pins = "gpio28"; + function = "gpio"; + /* + * Configure a bias-bus-hold on CTS to lower power + * usage when Bluetooth is turned off. Bus hold will + * maintain a low power state regardless of whether + * the Bluetooth module drives the pin in either + * direction or leaves the pin fully unpowered. + */ + bias-bus-hold; + }; + + qup_uart7_sleep_rts: qup-uart7-sleep-rts-state { + pins = "gpio29"; + function = "gpio"; + /* + * Configure pull-down on RTS. As RTS is active low + * signal, pull it low to indicate the BT SoC that it + * can wakeup the system anytime from suspend state by + * pulling RX low (by sending wakeup bytes). + */ + bias-pull-down; + }; + + qup_uart7_sleep_rx: qup-uart7-sleep-rx-state { + pins = "gpio31"; + function = "gpio"; + /* + * Configure a pull-up on RX. This is needed to avoid + * garbage data when the TX pin of the Bluetooth module + * is floating which may cause spurious wakeups. + */ + bias-pull-up; + }; + + qup_uart7_sleep_tx: qup-uart7-sleep-tx-state { + pins = "gpio30"; + function = "gpio"; + /* + * Configure pull-up on TX when it isn't actively driven + * to prevent BT SoC from receiving garbage during sleep. + */ + bias-pull-up; + }; + sd_cd: sd-cd-state { pins = "gpio91"; function = "gpio"; @@ -945,6 +1089,31 @@ status = "okay"; }; +&uart7 { + /delete-property/ interrupts; + interrupts-extended = <&intc GIC_SPI 608 IRQ_TYPE_LEVEL_HIGH>, + <&tlmm 31 IRQ_TYPE_EDGE_FALLING>; + pinctrl-1 = <&qup_uart7_sleep_cts>, + <&qup_uart7_sleep_rts>, + <&qup_uart7_sleep_tx>, + <&qup_uart7_sleep_rx>; + pinctrl-names = "default", + "sleep"; + + status = "okay"; + + bluetooth: bluetooth { + compatible = "qcom,wcn6750-bt"; + vddrfacmn-supply = <&vreg_pmu_rfa_cmn>; + vddaon-supply = <&vreg_pmu_aon_0p59>; + vddbtcmx-supply = <&vreg_pmu_btcmx_0p85>; + vddrfa0p8-supply = <&vreg_pmu_rfa_0p8>; + vddrfa1p7-supply = <&vreg_pmu_rfa_1p7>; + vddrfa1p2-supply = <&vreg_pmu_rfa_1p2>; + max-speed = <3200000>; + }; +}; + &ufs_mem_hc { reset-gpios = <&tlmm 175 GPIO_ACTIVE_LOW>; vcc-supply = <&vreg_l7b_2p952>; From 06997ee39f30680bea1e430c91093578f7c7a4e1 Mon Sep 17 00:00:00 2001 From: Harshal Dev Date: Fri, 6 Feb 2026 16:52:54 +0530 Subject: [PATCH 2258/2333] FROMLIST: dt-bindings: crypto: qcom,ice: Require power-domain and iface clk Update the inline-crypto engine DT binding to reflect that power-domain and clock-names are now mandatory. Also update the maximum number of clocks that can be specified to two. These new fields are mandatory because ICE needs to vote on the power domain before it attempts to vote on the core and iface clocks to avoid clock 'stuck' issues. Link: https://lore.kernel.org/all/20260123-qcom_ice_power_and_clk_vote-v1-1-e9059776f85c@qti.qualcomm.com/ Signed-off-by: Harshal Dev Signed-off-by: Abhinaba Rakshit --- .../bindings/crypto/qcom,inline-crypto-engine.yaml | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/crypto/qcom,inline-crypto-engine.yaml b/Documentation/devicetree/bindings/crypto/qcom,inline-crypto-engine.yaml index c3408dcf5d205..1c2416117d4ce 100644 --- a/Documentation/devicetree/bindings/crypto/qcom,inline-crypto-engine.yaml +++ b/Documentation/devicetree/bindings/crypto/qcom,inline-crypto-engine.yaml @@ -28,12 +28,20 @@ properties: maxItems: 1 clocks: + maxItems: 2 + + clock-names: + maxItems: 2 + + power-domains: maxItems: 1 required: - compatible - reg - clocks + - clock-names + - power-domains additionalProperties: false @@ -45,6 +53,10 @@ examples: compatible = "qcom,sm8550-inline-crypto-engine", "qcom,inline-crypto-engine"; reg = <0x01d88000 0x8000>; - clocks = <&gcc GCC_UFS_PHY_ICE_CORE_CLK>; + clocks = <&gcc GCC_UFS_PHY_ICE_CORE_CLK>, + <&gcc GCC_UFS_PHY_AHB_CLK>; + clock-names = "ice_core_clk", + "iface_clk"; + power-domains = <&gcc UFS_PHY_GDSC>; }; ... From a56ad585c68ba7917a473355d6325afce7936429 Mon Sep 17 00:00:00 2001 From: Harshal Dev Date: Fri, 6 Feb 2026 16:57:30 +0530 Subject: [PATCH 2259/2333] FROMLIST: arm64: dts: qcom: lemans: Add power-domain and iface clk for ice node Qualcomm in-line crypto engine (ICE) platform driver specifies and votes for it's own resources. Before accessing ICE hardware, the 'core' and 'iface' clocks must be turned on by the driver. This can only be done if the UFS_PHY_GDSC power domain is enabled. Specify both the UFS_PHY_GDSC power domain and 'core' and 'iface' clocks in the ICE node for lemans. Link: https://lore.kernel.org/all/20260123-qcom_ice_power_and_clk_vote-v1-3-e9059776f85c@qti.qualcomm.com/ Signed-off-by: Harshal Dev Signed-off-by: Abhinaba Rakshit --- arch/arm64/boot/dts/qcom/lemans.dtsi | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/lemans.dtsi b/arch/arm64/boot/dts/qcom/lemans.dtsi index 32ab3312970a7..033c017ebaa0d 100644 --- a/arch/arm64/boot/dts/qcom/lemans.dtsi +++ b/arch/arm64/boot/dts/qcom/lemans.dtsi @@ -2774,7 +2774,11 @@ compatible = "qcom,sa8775p-inline-crypto-engine", "qcom,inline-crypto-engine"; reg = <0x0 0x01d88000 0x0 0x18000>; - clocks = <&gcc GCC_UFS_PHY_ICE_CORE_CLK>; + clocks = <&gcc GCC_UFS_PHY_ICE_CORE_CLK>, + <&gcc GCC_UFS_PHY_AHB_CLK>; + clock-names = "ice_core_clk", + "iface_clk"; + power-domains = <&gcc UFS_PHY_GDSC>; }; cryptobam: dma-controller@1dc4000 { From 5eb6bf2a778e5ebe5ec8193b3ae3d967ca15e57c Mon Sep 17 00:00:00 2001 From: Harshal Dev Date: Fri, 6 Feb 2026 17:00:06 +0530 Subject: [PATCH 2260/2333] FROMLIST: arm64: dts: qcom: monaco: Add power-domain and iface clk for ice node Qualcomm in-line crypto engine (ICE) platform driver specifies and votes for it's own resources. Before accessing ICE hardware, the 'core' and 'iface' clocks must be turned on by the driver. This can only be done if the GCC_UFS_PHY_GDSC power domain is enabled. Specify both the GCC_UFS_PHY_GDSC power domain and 'core' and 'iface' clocks in the ICE node for monaco. Link: https://lore.kernel.org/all/20260123-qcom_ice_power_and_clk_vote-v1-4-e9059776f85c@qti.qualcomm.com/ Signed-off-by: Harshal Dev Signed-off-by: Abhinaba Rakshit --- arch/arm64/boot/dts/qcom/monaco.dtsi | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/monaco.dtsi b/arch/arm64/boot/dts/qcom/monaco.dtsi index 3ec76c2c942a0..c7fd5409db406 100644 --- a/arch/arm64/boot/dts/qcom/monaco.dtsi +++ b/arch/arm64/boot/dts/qcom/monaco.dtsi @@ -2662,7 +2662,11 @@ compatible = "qcom,qcs8300-inline-crypto-engine", "qcom,inline-crypto-engine"; reg = <0x0 0x01d88000 0x0 0x18000>; - clocks = <&gcc GCC_UFS_PHY_ICE_CORE_CLK>; + clocks = <&gcc GCC_UFS_PHY_ICE_CORE_CLK>, + <&gcc GCC_UFS_PHY_AHB_CLK>; + clock-names = "ice_core_clk", + "iface_clk"; + power-domains = <&gcc GCC_UFS_PHY_GDSC>; }; crypto: crypto@1dfa000 { From ad4b5f429872acd550a36bfd4308304f333c756b Mon Sep 17 00:00:00 2001 From: Harshal Dev Date: Fri, 6 Feb 2026 17:02:02 +0530 Subject: [PATCH 2261/2333] FROMLIST: arm64: dts: qcom: sc7180: Add power-domain and iface clk for ice node Qualcomm in-line crypto engine (ICE) platform driver specifies and votes for it's own resources. Before accessing ICE hardware, the 'core' and 'iface' clocks must be turned on by the driver. This can only be done if the UFS_PHY_GDSC power domain is enabled. Specify both the UFS_PHY_GDSC power domain and 'core' and 'iface' clocks in the ICE node for sc7180. Link: https://lore.kernel.org/all/20260123-qcom_ice_power_and_clk_vote-v1-5-e9059776f85c@qti.qualcomm.com/ Signed-off-by: Harshal Dev Signed-off-by: Abhinaba Rakshit --- arch/arm64/boot/dts/qcom/sc7180.dtsi | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sc7180.dtsi b/arch/arm64/boot/dts/qcom/sc7180.dtsi index a0df10a97c7f8..62af817475e7e 100644 --- a/arch/arm64/boot/dts/qcom/sc7180.dtsi +++ b/arch/arm64/boot/dts/qcom/sc7180.dtsi @@ -1599,7 +1599,11 @@ compatible = "qcom,sc7180-inline-crypto-engine", "qcom,inline-crypto-engine"; reg = <0 0x01d90000 0 0x8000>; - clocks = <&gcc GCC_UFS_PHY_ICE_CORE_CLK>; + clocks = <&gcc GCC_UFS_PHY_ICE_CORE_CLK>, + <&gcc GCC_UFS_PHY_AHB_CLK>; + clock-names = "ice_core_clk", + "iface_clk"; + power-domains = <&gcc UFS_PHY_GDSC>; }; ipa: ipa@1e40000 { From d28c004ae338c461f567496e8fdf517d753f6140 Mon Sep 17 00:00:00 2001 From: Harshal Dev Date: Fri, 6 Feb 2026 17:03:46 +0530 Subject: [PATCH 2262/2333] FROMLIST: arm64: dts: qcom: kodiak: Add power-domain and iface clk for ice node Qualcomm in-line crypto engine (ICE) platform driver specifies and votes for it's own resources. Before accessing ICE hardware, the 'core' and 'iface' clocks must be turned on by the driver. This can only be done if the GCC_UFS_PHY_GDSC power domain is enabled. Specify both the GCC_UFS_PHY_GDSC power domain and 'core' and 'iface' clocks in the ICE node for kodiak. Link: https://lore.kernel.org/all/20260123-qcom_ice_power_and_clk_vote-v1-6-e9059776f85c@qti.qualcomm.com/ Signed-off-by: Harshal Dev Signed-off-by: Abhinaba Rakshit --- arch/arm64/boot/dts/qcom/sc7280.dtsi | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sc7280.dtsi b/arch/arm64/boot/dts/qcom/sc7280.dtsi index 68ed072389372..0dfae23c74191 100644 --- a/arch/arm64/boot/dts/qcom/sc7280.dtsi +++ b/arch/arm64/boot/dts/qcom/sc7280.dtsi @@ -2579,7 +2579,11 @@ compatible = "qcom,sc7280-inline-crypto-engine", "qcom,inline-crypto-engine"; reg = <0 0x01d88000 0 0x8000>; - clocks = <&gcc GCC_UFS_PHY_ICE_CORE_CLK>; + clocks = <&gcc GCC_UFS_PHY_ICE_CORE_CLK>, + <&gcc GCC_UFS_PHY_AHB_CLK>; + clock-names = "ice_core_clk", + "iface_clk"; + power-domains = <&gcc GCC_UFS_PHY_GDSC>; }; cryptobam: dma-controller@1dc4000 { From c7344f4e892d1b4e398c3e07cdb50089533f08d6 Mon Sep 17 00:00:00 2001 From: Harshal Dev Date: Fri, 6 Feb 2026 17:06:00 +0530 Subject: [PATCH 2263/2333] FROMLIST: arm64: dts: qcom: sm8450: Add power-domain and iface clk for ice node Qualcomm in-line crypto engine (ICE) platform driver specifies and votes for it's own resources. Before accessing ICE hardware, the 'core' and 'iface' clocks must be turned on by the driver. This can only be done if the UFS_PHY_GDSC power domain is enabled. Specify both the UFS_PHY_GDSC power domain and 'core' and 'iface' clocks in the ICE node for sm8450. Link: https://lore.kernel.org/all/20260123-qcom_ice_power_and_clk_vote-v1-7-e9059776f85c@qti.qualcomm.com/ Signed-off-by: Harshal Dev Signed-off-by: Abhinaba Rakshit --- arch/arm64/boot/dts/qcom/sm8450.dtsi | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sm8450.dtsi b/arch/arm64/boot/dts/qcom/sm8450.dtsi index 23420e6924728..6ea7917798b86 100644 --- a/arch/arm64/boot/dts/qcom/sm8450.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8450.dtsi @@ -5349,7 +5349,11 @@ compatible = "qcom,sm8450-inline-crypto-engine", "qcom,inline-crypto-engine"; reg = <0 0x01d88000 0 0x8000>; - clocks = <&gcc GCC_UFS_PHY_ICE_CORE_CLK>; + clocks = <&gcc GCC_UFS_PHY_ICE_CORE_CLK>, + <&gcc GCC_UFS_PHY_AHB_CLK>; + clock-names = "ice_core_clk", + "iface_clk"; + power-domains = <&gcc UFS_PHY_GDSC>; }; cryptobam: dma-controller@1dc4000 { From bf5281f90fa8cd15730031ed66f896575c7c934c Mon Sep 17 00:00:00 2001 From: Harshal Dev Date: Fri, 6 Feb 2026 17:07:29 +0530 Subject: [PATCH 2264/2333] FROMLIST: arm64: dts: qcom: sm8550: Add power-domain and iface clk for ice node Qualcomm in-line crypto engine (ICE) platform driver specifies and votes for it's own resources. Before accessing ICE hardware, the 'core' and 'iface' clocks must be turned on by the driver. This can only be done if the UFS_PHY_GDSC power domain is enabled. Specify both the UFS_PHY_GDSC power domain and 'core' and 'iface' clocks in the ICE node for sm8550. Link: https://lore.kernel.org/all/20260123-qcom_ice_power_and_clk_vote-v1-8-e9059776f85c@qti.qualcomm.com/ Signed-off-by: Harshal Dev Signed-off-by: Abhinaba Rakshit --- arch/arm64/boot/dts/qcom/sm8550.dtsi | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sm8550.dtsi b/arch/arm64/boot/dts/qcom/sm8550.dtsi index 7724dba75db79..383c6c9073ab8 100644 --- a/arch/arm64/boot/dts/qcom/sm8550.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8550.dtsi @@ -2414,7 +2414,11 @@ "qcom,inline-crypto-engine"; reg = <0 0x01d88000 0 0x18000>; - clocks = <&gcc GCC_UFS_PHY_ICE_CORE_CLK>; + clocks = <&gcc GCC_UFS_PHY_ICE_CORE_CLK>, + <&gcc GCC_UFS_PHY_AHB_CLK>; + clock-names = "ice_core_clk", + "iface_clk"; + power-domains = <&gcc UFS_PHY_GDSC>; }; tcsr_mutex: hwlock@1f40000 { From d061cc2ba97988c89378d30cd75c2193b0a80147 Mon Sep 17 00:00:00 2001 From: Harshal Dev Date: Fri, 6 Feb 2026 17:08:50 +0530 Subject: [PATCH 2265/2333] FROMLIST: arm64: dts: qcom: sm8650: Add power-domain and iface clk for ice node Qualcomm in-line crypto engine (ICE) platform driver specifies and votes for it's own resources. Before accessing ICE hardware, the 'core' and 'iface' clocks must be turned on by the driver. This can only be done if the UFS_PHY_GDSC power domain is enabled. Specify both the UFS_PHY_GDSC power domain and 'core' and 'iface' clocks in the ICE node for sm8650. Link: https://lore.kernel.org/all/20260123-qcom_ice_power_and_clk_vote-v1-9-e9059776f85c@qti.qualcomm.com/ Signed-off-by: Harshal Dev Signed-off-by: Abhinaba Rakshit --- arch/arm64/boot/dts/qcom/sm8650.dtsi | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sm8650.dtsi b/arch/arm64/boot/dts/qcom/sm8650.dtsi index 3b03c13539386..8147f7078859e 100644 --- a/arch/arm64/boot/dts/qcom/sm8650.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8650.dtsi @@ -4046,7 +4046,11 @@ "qcom,inline-crypto-engine"; reg = <0 0x01d88000 0 0x18000>; - clocks = <&gcc GCC_UFS_PHY_ICE_CORE_CLK>; + clocks = <&gcc GCC_UFS_PHY_ICE_CORE_CLK>, + <&gcc GCC_UFS_PHY_AHB_CLK>; + clock-names = "ice_core_clk", + "iface_clk"; + power-domains = <&gcc UFS_PHY_GDSC>; }; cryptobam: dma-controller@1dc4000 { From 646184aead7d98f472efde2cd546d8f790c25b48 Mon Sep 17 00:00:00 2001 From: Harshal Dev Date: Fri, 6 Feb 2026 17:10:09 +0530 Subject: [PATCH 2266/2333] FROMLIST: arm64: dts: qcom: sm8750: Add power-domain and iface clk for ice node Qualcomm in-line crypto engine (ICE) platform driver specifies and votes for it's own resources. Before accessing ICE hardware, the 'core' and 'iface' clocks must be turned on by the driver. This can only be done if the GCC_UFS_PHY_GDSC power domain is enabled. Specify both the GCC_UFS_PHY_GDSC power domain and 'core' and 'iface' clocks in the ICE node for sm8750. Link: https://lore.kernel.org/all/20260123-qcom_ice_power_and_clk_vote-v1-10-e9059776f85c@qti.qualcomm.com/ Signed-off-by: Harshal Dev Signed-off-by: Abhinaba Rakshit --- arch/arm64/boot/dts/qcom/sm8750.dtsi | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sm8750.dtsi b/arch/arm64/boot/dts/qcom/sm8750.dtsi index ee7781a48c464..67027cd70277c 100644 --- a/arch/arm64/boot/dts/qcom/sm8750.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8750.dtsi @@ -2058,7 +2058,11 @@ "qcom,inline-crypto-engine"; reg = <0x0 0x01d88000 0x0 0x18000>; - clocks = <&gcc GCC_UFS_PHY_ICE_CORE_CLK>; + clocks = <&gcc GCC_UFS_PHY_ICE_CORE_CLK>, + <&gcc GCC_UFS_PHY_AHB_CLK>; + clock-names = "ice_core_clk", + "iface_clk"; + power-domains = <&gcc GCC_UFS_PHY_GDSC>; }; cryptobam: dma-controller@1dc4000 { From 7cb627041c5dc67c02d972c9c40093eabc7f770e Mon Sep 17 00:00:00 2001 From: Harshal Dev Date: Fri, 6 Feb 2026 17:19:02 +0530 Subject: [PATCH 2267/2333] FROMLIST: soc: qcom: ice: Add explicit power-domain and clock voting calls for ICE Since Qualcomm inline-crypto engine (ICE) is now a dedicated driver de-coupled from the QCOM UFS driver, it should explicitly vote for it's needed resources during probe, specifically the UFS_PHY_GDSC power-domain and the 'core' and 'iface' clocks. Also updated the suspend and resume callbacks to handle votes on these resources. Link: https://lore.kernel.org/all/20260123-qcom_ice_power_and_clk_vote-v1-11-e9059776f85c@qti.qualcomm.com/ Signed-off-by: Harshal Dev Signed-off-by: Abhinaba Rakshit --- drivers/soc/qcom/ice.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/drivers/soc/qcom/ice.c b/drivers/soc/qcom/ice.c index b203bc685cadd..4b50d05ca02a3 100644 --- a/drivers/soc/qcom/ice.c +++ b/drivers/soc/qcom/ice.c @@ -16,6 +16,8 @@ #include #include #include +#include +#include #include @@ -108,6 +110,7 @@ struct qcom_ice { void __iomem *base; struct clk *core_clk; + struct clk *iface_clk; bool use_hwkm; bool hwkm_init_complete; u8 hwkm_version; @@ -310,12 +313,20 @@ int qcom_ice_resume(struct qcom_ice *ice) struct device *dev = ice->dev; int err; + pm_runtime_get_sync(dev); err = clk_prepare_enable(ice->core_clk); if (err) { dev_err(dev, "failed to enable core clock (%d)\n", err); return err; } + + err = clk_prepare_enable(ice->iface_clk); + if (err) { + dev_err(dev, "failed to enable iface clock (%d)\n", + err); + return err; + } qcom_ice_hwkm_init(ice); return qcom_ice_wait_bist_status(ice); } @@ -323,7 +334,9 @@ EXPORT_SYMBOL_GPL(qcom_ice_resume); int qcom_ice_suspend(struct qcom_ice *ice) { + clk_disable_unprepare(ice->iface_clk); clk_disable_unprepare(ice->core_clk); + pm_runtime_put_sync(ice->dev); ice->hwkm_init_complete = false; return 0; @@ -584,6 +597,10 @@ static struct qcom_ice *qcom_ice_create(struct device *dev, if (IS_ERR(engine->core_clk)) return ERR_CAST(engine->core_clk); + engine->iface_clk = devm_clk_get_enabled(dev, "iface_clk"); + if (IS_ERR(engine->iface_clk)) + return ERR_CAST(engine->iface_clk); + if (!qcom_ice_check_supported(engine)) return ERR_PTR(-EOPNOTSUPP); @@ -725,6 +742,9 @@ static int qcom_ice_probe(struct platform_device *pdev) return PTR_ERR(base); } + devm_pm_runtime_enable(&pdev->dev); + pm_runtime_get_sync(&pdev->dev); + engine = qcom_ice_create(&pdev->dev, base); if (IS_ERR(engine)) return PTR_ERR(engine); From 4e54bc51277596f9161e686ee28fdcfe916b2570 Mon Sep 17 00:00:00 2001 From: Jie Gan Date: Thu, 8 Jan 2026 10:00:04 +0800 Subject: [PATCH 2268/2333] QCLINUX: qcom-dcc: Add driver support for Data Capture and Compare unit(DCC) The DCC is a DMA Engine designed to capture and store data during system crash or software triggers. The DCC operates based on user inputs via the debugfs interface. The user gives addresses as inputs and these addresses are stored in the dcc sram. In case of a system crash or a manual software trigger by the user through the debugfs interface, the dcc captures and stores the values at these addresses. This patch contains the driver which has all the methods pertaining to the debugfs interface, auxiliary functions to support all the four fundamental operations of dcc namely read, write, read/modify/write and loop. The probe method here instantiates all the resources necessary for dcc to operate mainly the dedicated dcc sram where it stores the values. The DCC driver can be used for debugging purposes without going for a reboot since it can perform software triggers as well based on user inputs. Also add the documentation for debugfs entries which explains the functionalities of each debugfs file that has been created for dcc. The following is the justification of using debugfs interface over the other alternatives like sysfs/ioctls i) As can be seen from the debugfs attribute descriptions, some of the debugfs attribute files here contains multiple arguments which needs to be accepted from the user. This goes against the design style of sysfs. ii) The user input patterns have been made simple and convenient in this case with the use of debugfs interface as user doesn't need to shuffle between different files to execute one instruction as was the case on using other alternatives. Signed-off-by: Jie Gan --- drivers/misc/Kconfig | 8 + drivers/misc/Makefile | 1 + drivers/misc/qcom-dcc.c | 1610 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 1619 insertions(+) create mode 100644 drivers/misc/qcom-dcc.c diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index b9c11f67315f0..133b854166958 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -310,6 +310,14 @@ config QCOM_FASTRPC applications DSP processor. Say M if you want to enable this module. +config QCOM_DCC + tristate "Qualcomm Technologies, Inc. Data Capture and Compare (DCC) engine driver" + depends on ARCH_QCOM || COMPILE_TEST + help + This option enables the driver for the Data Capture and Compare engine. DCC + driver provides interfaces to configure DCC block and read back the captured + data from the DCC's internal SRAM. The module name for this is qcom-dcc. + config SGI_GRU tristate "SGI GRU driver" depends on X86_UV && SMP diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index b32a2597d2467..338ed270b7cfc 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -75,3 +75,4 @@ obj-$(CONFIG_MCHP_LAN966X_PCI) += lan966x-pci.o obj-y += keba/ obj-y += amd-sbi/ obj-$(CONFIG_MISC_RP1) += rp1/ +obj-$(CONFIG_QCOM_DCC) += qcom-dcc.o diff --git a/drivers/misc/qcom-dcc.c b/drivers/misc/qcom-dcc.c new file mode 100644 index 0000000000000..a511faac5d4b0 --- /dev/null +++ b/drivers/misc/qcom-dcc.c @@ -0,0 +1,1610 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +/* + * DCC(Data Capture and Compare) is a DMA engine designed for debugging + * purposes. + * In case of a system crash or manual software triggers by the user the + * DCC hardware stores the value at the register addresses which can be + * used for debugging purposes. + * The DCC driver provides the user with debugfs interface to configure the + * register addresses. The options that the DCC hardware provides include + * reading from registers, writing to registers, first reading and then + * writing to registers and looping through the values of the same + * register. + * + * In certain cases a register write needs to be executed for accessing the + * rest of the registers, also the user might want to record the changing + * values of a register with time for which he has the option to use the + * loop feature. + * + * The options mentioned above are exposed to the user by debugfs files + * once the driver is probed. The details and usage of this debugfs files + * are documented in Documentation/ABI/testing/debugfs-driver-dcc. + * + * As an example let us consider a couple of debug scenarios where DCC has + * been proved to be effective for debugging purposes:- + * + * i)TimeStamp Related Issue + * + * On SC7180, there was a coresight timestamp issue where it would + * occasionally be all 0 instead of proper timestamp values. + * + * Proper timestamp: + * Idx:3373; ID:10; I_TIMESTAMP : Timestamp.; Updated val = + * 0x13004d8f5b7aa; CC=0x9e + * + * Zero timestamp: + * Idx:3387; ID:10; I_TIMESTAMP : Timestamp.; Updated val = 0x0; CC=0xa2 + * + * Now this is a non-fatal issue and doesn't need a system reset, but still + * needs to be rootcaused and fixed for those who do care about coresight + * etm traces. + * Since this is a timestamp issue, we would be looking for any timestamp + * related clocks and such. + * + * We get all the clk register details from IP documentation and configure + * it via DCC config debugfs node. Before that we set the current + * linked list. + * + * Program the linked list with the addresses + * echo R 0x10c004 > /sys/kernel/debug/qcom-dcc/../3/config + * echo R 0x10c008 > /sys/kernel/debug/qcom-dcc/../3/config + * echo R 0x10c00c > /sys/kernel/debug/qcom-dcc/../3/config + * echo R 0x10c010 > /sys/kernel/debug/qcom-dcc/../3/config + * ..... and so on for other timestamp related clk registers + * + * Other way of specifying is in "addr len" pair, in below case it + * specifies to capture 4 words starting 0x10C004 + * + * echo R 0x10C004 4 > /sys/kernel/debug/qcom-dcc/../3/config + * + * Configuration can be saved to a file and reuse it later. + * cat /sys/kernel/debug/qcom-dcc/../3/config > config_3 + * Post reboot, write the file to config. + * echo config_3 > /sys/kernel/debug/qcom-dcc/../3/config + * + * Enable DCC + * echo 1 > /sys/kernel/debug/qcom-dcc/../3/enable + * + * Run the timestamp test for working case + * + * Send SW trigger + * echo 1 > /sys/kernel/debug/qcom-dcc/../trigger + * + * Read SRAM + * cat /dev/dcc_sram > dcc_sram1.bin + * + * Run the timestamp test for non-working case + * + * Send SW trigger + * echo 1 > /sys/kernel/debug/qcom-dcc/../trigger + * + * Read SRAM + * cat /dev/dcc_sram > dcc_sram2.bin + * + * Get the parser from + * https://git.codelinaro.org/clo/le/platform/vendor/qcom-opensource/tools/-/tree/opensource-tools.lnx.1.0.r176-rel/dcc_parser + * + * Parse the SRAM bin + * python dcc_parser.py -s dcc_sram1.bin --v2 -o output/ python + * dcc_parser.py -s dcc_sram2.bin --v2 -o output/ + * + * Sample parsed output of dcc_sram1.bin: + * + * + * 03/14/21 + * Linux DCC Parser + * + * + * + * + * + * + * next_ll_offset : 0x1c + * + * ii)NOC register errors + * + * A particular class of registers called NOC which are functional + * registers was reporting errors while logging the values.To trace these + * errors the DCC has been used effectively. + * The steps followed were similar to the ones mentioned above. + * In addition to NOC registers a few other dependent registers were + * configured in DCC to monitor it's values during a crash. A look at the + * dependent register values revealed that the crash was happening due to a + * secured access to one of these dependent registers. + * All these debugging activity and finding the root cause was achieved + * using DCC. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define STATUS_READY_TIMEOUT 5000 /* microseconds */ + +/* DCC registers */ +#define DCC_HW_INFO 0x04 +#define DCC_LL_NUM_INFO 0x10 +#define DCC_LL_LOCK 0x00 +#define DCC_LL_CFG 0x04 +#define DCC_LL_BASE 0x08 +#define DCC_FD_BASE 0x0c +#define DCC_LL_OFFSET 0x80 +#define DCC_LL_TIMEOUT 0x10 +#define DCC_LL_INT_ENABLE 0x18 +#define DCC_LL_INT_STATUS 0x1c +#define DCC_LL_SW_TRIGGER 0x2c +#define DCC_LL_BUS_ACCESS_STATUS 0x30 + +/* Default value used if a bit 6 in the HW_INFO register is set. */ +#define DCC_FIX_LOOP_OFFSET 16 + +/* Mask to find version info from HW_Info register */ +#define DCC_VER_INFO_MASK BIT(9) + +#define MAX_DCC_OFFSET GENMASK(9, 2) +#define MAX_DCC_LEN GENMASK(6, 0) +#define MAX_LOOP_CNT GENMASK(7, 0) +#define MAX_LOOP_ADDR 10 + +#define DCC_ADDR_DESCRIPTOR 0x00 +#define DCC_ADDR_LIMIT 27 +#define DCC_WORD_SIZE sizeof(u32) +#define DCC_ADDR_RANGE_MASK GENMASK(31, 4) +#define DCC_LOOP_DESCRIPTOR BIT(30) +#define DCC_RD_MOD_WR_DESCRIPTOR BIT(31) +#define DCC_LINK_DESCRIPTOR GENMASK(31, 30) +#define DCC_STATUS_MASK GENMASK(1, 0) +#define DCC_LOCK_MASK BIT(0) +#define DCC_LOOP_OFFSET_MASK BIT(6) +#define DCC_TRIGGER_MASK BIT(9) + +#define DCC_WRITE_MASK BIT(15) +#define DCC_WRITE_OFF_MASK GENMASK(7, 0) +#define DCC_WRITE_LEN_MASK GENMASK(14, 8) + +#define DCC_READ_IND 0x00 +#define DCC_WRITE_IND (BIT(28)) + +#define DCC_AHB_IND 0x00 +#define DCC_APB_IND BIT(29) + +#define DCC_MAX_LINK_LIST 8 + +#define DCC_VER_MASK2 GENMASK(5, 0) + +#define DCC_SRAM_WORD_LENGTH 4 + +#define DCC_RD_MOD_WR_ADDR 0xC105E + +#define MEM_MAP_VER1 0x1 +#define MEM_MAP_VER2 0x2 +#define MEM_MAP_VER3 0x3 + +#define LINE_BUFFER_MAX_SZ 50 +enum dcc_descriptor_type { + DCC_READ_TYPE, + DCC_LOOP_TYPE, + DCC_READ_WRITE_TYPE, + DCC_WRITE_TYPE +}; + +/** + * struct dcc_config_entry - configuration information related to each dcc instruction + * @base: Base address of the register to be configured in dcc + * @offset: Offset to the base address to be configured in dcc + * @len: Length of the address in words of 4 bytes to be configured in dcc + * @loop_cnt: The number of times to loop on the register address in case + of loop instructions + * @write_val: The value to be written on the register address in case of + write instructions + * @mask: Mask corresponding to the value to be written in case of + write instructions + * @apb_bus: Type of bus to be used for the instruction, can be either + 'apb' if 1 or 'ahb' if 0 + * @desc_type: Stores the type of dcc instruction + * @list: This is used to append this instruction to the list of + instructions + */ +struct dcc_config_entry { + u32 base; + u32 offset; + u32 len; + u32 loop_cnt; + u32 write_val; + u32 mask; + bool apb_bus; + enum dcc_descriptor_type desc_type; + struct list_head list; +}; + +/** + * struct dcc_drvdata - configuration information related to a dcc device + * @base: Base Address of the dcc device + * @dev: The device attached to the driver data + * @mutex: Lock to protect access and manipulation of dcc_drvdata + * @ram_base: Base address for the SRAM dedicated for the dcc device + * @ram_size: Total size of the SRAM dedicated for the dcc device + * @ram_offset: Offset to the SRAM dedicated for dcc device + * @ram_cfg: Used for address limit calculation for dcc + * @ram_start: Starting address of DCC SRAM + * @mem_map_ver: Memory map version of DCC hardware + * @sram_dev: Miscellaneous device equivalent of dcc SRAM + * @cfg_head: Points to the head of the linked list of addresses + * @dbg_dir: The dcc debugfs directory under which all the debugfs files are placed + * @max_link_list: Total number of linkedlists supported by the DCC configuration + * @loop_shift: Loop offset bits range for the addresses + * @enable_bitmap: Bitmap to capture the enabled status of each linked list of addresses + */ +struct dcc_drvdata { + void __iomem *base; + void __iomem *ram_base; + struct device *dev; + /* Lock to protect access and manipulation of dcc_drvdata */ + struct mutex mutex; + size_t ram_size; + u32 ram_offset; + unsigned int ram_cfg; + unsigned int ram_start; + u64 mem_map_ver; + struct miscdevice sram_dev; + struct list_head *cfg_head; + struct dentry *dbg_dir; + size_t max_link_list; + u8 loop_shift; + unsigned long *enable_bitmap; + char **temp_buff_ptr; +}; + +struct dcc_cfg_attr { + u32 addr; + u32 prev_addr; + u32 prev_off; + u32 link; + u32 sram_offset; +}; + +struct dcc_cfg_loop_attr { + u32 loop_cnt; + u32 loop_len; + u32 loop_off; + bool loop_start; +}; + +static inline u32 dcc_status(int version) +{ + return version == 1 ? 0x0c : 0x1c; +} + +static inline u32 dcc_list_offset(int version) +{ + if (version == 1) + return 0x1c; + else if (version == 2) + return 0x2c; + else + return 0x34; +} + +static inline void dcc_list_writel(struct dcc_drvdata *drvdata, + u32 val, u32 ll, u32 off) +{ + u32 offset = dcc_list_offset(drvdata->mem_map_ver) + off; + + writel(val, drvdata->base + ll * DCC_LL_OFFSET + offset); +} + +static inline u32 dcc_list_readl(struct dcc_drvdata *drvdata, u32 ll, u32 off) +{ + u32 offset = dcc_list_offset(drvdata->mem_map_ver) + off; + + return readl(drvdata->base + ll * DCC_LL_OFFSET + offset); +} + +static void dcc_sram_write_auto(struct dcc_drvdata *drvdata, + u32 val, u32 *off) +{ + /* If the overflow condition is met increment the offset + * and return to indicate that overflow has occurred + */ + if (*off > drvdata->ram_size - 4) { + *off += 4; + return; + } + + writel(val, drvdata->ram_base + *off); + + *off += 4; +} + +static int dcc_sw_trigger(struct dcc_drvdata *drvdata) +{ + void __iomem *addr; + int i; + u32 status; + u32 ll_cfg; + u32 tmp_ll_cfg; + u32 val; + int ret = 0; + + mutex_lock(&drvdata->mutex); + + for (i = 0; i < drvdata->max_link_list; i++) { + if (!test_bit(i, drvdata->enable_bitmap)) + continue; + ll_cfg = dcc_list_readl(drvdata, i, DCC_LL_CFG); + if (drvdata->mem_map_ver == MEM_MAP_VER3) + tmp_ll_cfg = ll_cfg & ~BIT(8); + else + tmp_ll_cfg = ll_cfg & ~DCC_TRIGGER_MASK; + + dcc_list_writel(drvdata, tmp_ll_cfg, i, DCC_LL_CFG); + dcc_list_writel(drvdata, 1, i, DCC_LL_SW_TRIGGER); + dcc_list_writel(drvdata, ll_cfg, i, DCC_LL_CFG); + } + + addr = drvdata->base + dcc_status(drvdata->mem_map_ver); + if (readl_poll_timeout(addr, val, !FIELD_GET(DCC_STATUS_MASK, val), + 1, STATUS_READY_TIMEOUT)) { + dev_err(drvdata->dev, "DCC is busy after receiving sw trigger\n"); + ret = -EBUSY; + goto out_unlock; + } + + for (i = 0; i < drvdata->max_link_list; i++) { + if (!test_bit(i, drvdata->enable_bitmap)) + continue; + + status = dcc_list_readl(drvdata, i, DCC_LL_BUS_ACCESS_STATUS); + if (!status) + continue; + + dev_err(drvdata->dev, "Read access error for list %d err: 0x%x\n", + i, status); + ll_cfg = dcc_list_readl(drvdata, i, DCC_LL_CFG); + if (drvdata->mem_map_ver == MEM_MAP_VER3) + tmp_ll_cfg = ll_cfg & ~BIT(8); + else + tmp_ll_cfg = ll_cfg & ~DCC_TRIGGER_MASK; + + dcc_list_writel(drvdata, tmp_ll_cfg, i, DCC_LL_CFG); + dcc_list_writel(drvdata, DCC_STATUS_MASK, i, DCC_LL_BUS_ACCESS_STATUS); + dcc_list_writel(drvdata, ll_cfg, i, DCC_LL_CFG); + ret = -ENODATA; + break; + } + +out_unlock: + mutex_unlock(&drvdata->mutex); + return ret; +} + +static void dcc_ll_cfg_reset_link(struct dcc_cfg_attr *cfg) +{ + cfg->addr = 0x00; + cfg->link = 0; + cfg->prev_off = 0; + cfg->prev_addr = cfg->addr; +} + +static void dcc_emit_read_write(struct dcc_drvdata *drvdata, + struct dcc_config_entry *entry, + struct dcc_cfg_attr *cfg) +{ + if (cfg->link) { + /* + * write new offset = 1 to continue + * processing the list + */ + + dcc_sram_write_auto(drvdata, cfg->link, &cfg->sram_offset); + + /* Reset link and prev_off */ + dcc_ll_cfg_reset_link(cfg); + } + + cfg->addr = DCC_RD_MOD_WR_DESCRIPTOR; + dcc_sram_write_auto(drvdata, cfg->addr, &cfg->sram_offset); + + dcc_sram_write_auto(drvdata, entry->mask, &cfg->sram_offset); + + dcc_sram_write_auto(drvdata, entry->write_val, &cfg->sram_offset); + + cfg->addr = 0; +} + +static void dcc_emit_loop(struct dcc_drvdata *drvdata, struct dcc_config_entry *entry, + struct dcc_cfg_attr *cfg, + struct dcc_cfg_loop_attr *cfg_loop, + u32 *total_len) +{ + int loop; + + /* Check if we need to write link of prev entry */ + if (cfg->link) + dcc_sram_write_auto(drvdata, cfg->link, &cfg->sram_offset); + + if (cfg_loop->loop_start) { + loop = (cfg->sram_offset - cfg_loop->loop_off) / 4; + loop |= (cfg_loop->loop_cnt << drvdata->loop_shift) & + GENMASK(DCC_ADDR_LIMIT, drvdata->loop_shift); + loop |= DCC_LOOP_DESCRIPTOR; + *total_len += (*total_len - cfg_loop->loop_len) * cfg_loop->loop_cnt; + + dcc_sram_write_auto(drvdata, loop, &cfg->sram_offset); + + cfg_loop->loop_start = false; + cfg_loop->loop_len = 0; + cfg_loop->loop_off = 0; + } else { + cfg_loop->loop_start = true; + cfg_loop->loop_cnt = entry->loop_cnt - 1; + cfg_loop->loop_len = *total_len; + cfg_loop->loop_off = cfg->sram_offset; + } + + /* Reset link and prev_off */ + dcc_ll_cfg_reset_link(cfg); +} + +static void dcc_emit_write(struct dcc_drvdata *drvdata, + struct dcc_config_entry *entry, + struct dcc_cfg_attr *cfg) +{ + u32 off; + + if (cfg->link) { + /* + * write new offset = 1 to continue + * processing the list + */ + dcc_sram_write_auto(drvdata, cfg->link, &cfg->sram_offset); + + /* Reset link and prev_off */ + cfg->addr = 0x00; + cfg->prev_off = 0; + cfg->prev_addr = cfg->addr; + } + + off = entry->offset / 4; + /* write new offset-length pair to correct position */ + cfg->link |= ((off & DCC_WRITE_OFF_MASK) | DCC_WRITE_MASK | + FIELD_PREP(DCC_WRITE_LEN_MASK, entry->len)); + cfg->link |= DCC_LINK_DESCRIPTOR; + + /* Address type */ + cfg->addr = (entry->base >> 4) & GENMASK(DCC_ADDR_LIMIT, 0); + if (entry->apb_bus) + cfg->addr |= DCC_ADDR_DESCRIPTOR | DCC_WRITE_IND | DCC_APB_IND; + else + cfg->addr |= DCC_ADDR_DESCRIPTOR | DCC_WRITE_IND | DCC_AHB_IND; + dcc_sram_write_auto(drvdata, cfg->addr, &cfg->sram_offset); + + dcc_sram_write_auto(drvdata, cfg->link, &cfg->sram_offset); + + dcc_sram_write_auto(drvdata, entry->write_val, &cfg->sram_offset); + + cfg->addr = 0x00; + cfg->link = 0; +} + +static int dcc_emit_read(struct dcc_drvdata *drvdata, + struct dcc_config_entry *entry, + struct dcc_cfg_attr *cfg, + u32 *pos, u32 *total_len) +{ + u32 off; + u32 temp_off; + + cfg->addr = (entry->base >> 4) & GENMASK(27, 0); + + if (entry->apb_bus) + cfg->addr |= DCC_ADDR_DESCRIPTOR | DCC_READ_IND | DCC_APB_IND; + else + cfg->addr |= DCC_ADDR_DESCRIPTOR | DCC_READ_IND | DCC_AHB_IND; + + off = entry->offset / 4; + + *total_len += entry->len * 4; + + if (!cfg->prev_addr || cfg->prev_addr != cfg->addr || cfg->prev_off > off) { + /* Check if we need to write prev link entry */ + if (cfg->link) + dcc_sram_write_auto(drvdata, cfg->link, &cfg->sram_offset); + dev_dbg(drvdata->dev, "DCC: sram address 0x%x\n", cfg->sram_offset); + + /* Write address */ + dcc_sram_write_auto(drvdata, cfg->addr, &cfg->sram_offset); + + /* Reset link and prev_off */ + cfg->link = 0; + cfg->prev_off = 0; + } + + if ((off - cfg->prev_off) > 0xff || entry->len > MAX_DCC_LEN) { + dev_err(drvdata->dev, "DCC: Programming error Base: 0x%x, offset 0x%x\n", + entry->base, entry->offset); + return -EINVAL; + } + + if (cfg->link) { + /* + * link already has one offset-length so new + * offset-length needs to be placed at + * bits [29:15] + */ + *pos = 15; + + /* Clear bits [31:16] */ + cfg->link &= GENMASK(14, 0); + } else { + /* + * link is empty, so new offset-length needs + * to be placed at bits [15:0] + */ + *pos = 0; + cfg->link = 1 << 15; + } + + /* write new offset-length pair to correct position */ + temp_off = (off - cfg->prev_off) & GENMASK(7, 0); + cfg->link |= (temp_off | ((entry->len << 8) & GENMASK(14, 8))) << *pos; + + cfg->link |= DCC_LINK_DESCRIPTOR; + + if (*pos) { + dcc_sram_write_auto(drvdata, cfg->link, &cfg->sram_offset); + cfg->link = 0; + } + + cfg->prev_off = off + entry->len - 1; + cfg->prev_addr = cfg->addr; + return 0; +} + +static int dcc_emit_config(struct dcc_drvdata *drvdata, unsigned int curr_list) +{ + int ret; + u32 total_len, pos; + struct dcc_config_entry *entry; + struct dcc_cfg_attr cfg = {0}; + struct dcc_cfg_loop_attr cfg_loop = {0}; + + cfg.sram_offset = drvdata->ram_cfg * 4; + total_len = 0; + + list_for_each_entry(entry, &drvdata->cfg_head[curr_list], list) { + switch (entry->desc_type) { + case DCC_READ_WRITE_TYPE: + dcc_emit_read_write(drvdata, entry, &cfg); + break; + + case DCC_LOOP_TYPE: + dcc_emit_loop(drvdata, entry, &cfg, &cfg_loop, &total_len); + break; + + case DCC_WRITE_TYPE: + dcc_emit_write(drvdata, entry, &cfg); + break; + + case DCC_READ_TYPE: + ret = dcc_emit_read(drvdata, entry, &cfg, &pos, &total_len); + if (ret) + goto err; + break; + } + } + + if (cfg.link) + dcc_sram_write_auto(drvdata, cfg.link, &cfg.sram_offset); + + if (cfg_loop.loop_start) { + dev_err(drvdata->dev, "DCC: Programming error: Loop unterminated\n"); + ret = -EINVAL; + goto err; + } + + /* Handling special case of list ending with a rd_mod_wr */ + if (cfg.addr == DCC_RD_MOD_WR_DESCRIPTOR) { + cfg.addr = (DCC_RD_MOD_WR_ADDR) & GENMASK(27, 0); + cfg.addr |= DCC_ADDR_DESCRIPTOR; + dcc_sram_write_auto(drvdata, cfg.addr, &cfg.sram_offset); + } + + /* Setting zero to indicate end of the list */ + cfg.link = DCC_LINK_DESCRIPTOR; + dcc_sram_write_auto(drvdata, cfg.link, &cfg.sram_offset); + + /* Check if sram offset exceeds the ram size */ + if (cfg.sram_offset > drvdata->ram_size) + goto overstep; + + /* Update ram_cfg and check if the data will overstep */ + drvdata->ram_cfg = (cfg.sram_offset + total_len) / 4; + + if (cfg.sram_offset + total_len > drvdata->ram_size) { + cfg.sram_offset += total_len; + goto overstep; + } + + drvdata->ram_start = cfg.sram_offset / 4; + return 0; +overstep: + ret = -EINVAL; + memset_io(drvdata->ram_base, 0, drvdata->ram_size); + +err: + return ret; +} + +static bool dcc_valid_list(struct dcc_drvdata *drvdata, unsigned int curr_list) +{ + u32 lock_reg; + + if (list_empty(&drvdata->cfg_head[curr_list])) + return false; + + if (test_bit(curr_list, drvdata->enable_bitmap)) { + dev_err(drvdata->dev, "List %d is already enabled\n", curr_list); + return false; + } + + lock_reg = dcc_list_readl(drvdata, curr_list, DCC_LL_LOCK); + if (lock_reg & DCC_LOCK_MASK) { + dev_err(drvdata->dev, "List %d is already locked\n", curr_list); + return false; + } + + return true; +} + +static bool is_dcc_enabled(struct dcc_drvdata *drvdata) +{ + int list; + + for (list = 0; list < drvdata->max_link_list; list++) + if (test_bit(list, drvdata->enable_bitmap)) + return true; + + return false; +} + +static int dcc_enable(struct dcc_drvdata *drvdata, unsigned int curr_list) +{ + int ret; + u32 ram_cfg_base; + + mutex_lock(&drvdata->mutex); + + if (!dcc_valid_list(drvdata, curr_list)) { + ret = -EINVAL; + goto out_unlock; + } + + /* Fill dcc sram with the poison value. + * This helps in understanding bus + * hang from registers returning a zero + */ + if (!is_dcc_enabled(drvdata)) + memset_io(drvdata->ram_base, 0xde, drvdata->ram_size); + + /* 1. Take ownership of the list */ + dcc_list_writel(drvdata, DCC_LOCK_MASK, curr_list, DCC_LL_LOCK); + + /* 2. Program linked-list in the SRAM */ + ram_cfg_base = drvdata->ram_cfg; + ret = dcc_emit_config(drvdata, curr_list); + if (ret) { + dcc_list_writel(drvdata, 0, curr_list, DCC_LL_LOCK); + goto out_unlock; + } + + /* 3. Program DCC_RAM_CFG reg */ + dcc_list_writel(drvdata, ram_cfg_base + + drvdata->ram_offset / 4, curr_list, DCC_LL_BASE); + dcc_list_writel(drvdata, drvdata->ram_start + + drvdata->ram_offset / 4, curr_list, DCC_FD_BASE); + dcc_list_writel(drvdata, 0xFFF, curr_list, DCC_LL_TIMEOUT); + + /* 4. Clears interrupt status register */ + dcc_list_writel(drvdata, 0, curr_list, DCC_LL_INT_ENABLE); + dcc_list_writel(drvdata, (BIT(0) | BIT(1) | BIT(2)), + curr_list, DCC_LL_INT_STATUS); + + set_bit(curr_list, drvdata->enable_bitmap); + + /* 5. Configure trigger */ + if (drvdata->mem_map_ver == MEM_MAP_VER3) + dcc_list_writel(drvdata, BIT(8), + curr_list, DCC_LL_CFG); + else + dcc_list_writel(drvdata, DCC_TRIGGER_MASK, + curr_list, DCC_LL_CFG); + +out_unlock: + mutex_unlock(&drvdata->mutex); + return ret; +} + +static void dcc_disable(struct dcc_drvdata *drvdata, int curr_list) +{ + mutex_lock(&drvdata->mutex); + + if (!test_bit(curr_list, drvdata->enable_bitmap)) + goto out_unlock; + dcc_list_writel(drvdata, 0, curr_list, DCC_LL_CFG); + dcc_list_writel(drvdata, 0, curr_list, DCC_LL_BASE); + dcc_list_writel(drvdata, 0, curr_list, DCC_FD_BASE); + dcc_list_writel(drvdata, 0, curr_list, DCC_LL_LOCK); + clear_bit(curr_list, drvdata->enable_bitmap); +out_unlock: + mutex_unlock(&drvdata->mutex); +} + +static u32 dcc_filp_curr_list(const struct file *filp) +{ + struct dentry *dentry = file_dentry(filp); + int curr_list, ret; + + ret = kstrtoint(dentry->d_parent->d_name.name, 0, &curr_list); + if (ret) + return ret; + + return curr_list; +} + +static ssize_t enable_read(struct file *filp, char __user *userbuf, + size_t count, loff_t *ppos) +{ + char *buf; + int curr_list = dcc_filp_curr_list(filp); + struct dcc_drvdata *drvdata = filp->private_data; + + if (curr_list < 0) + return curr_list; + + mutex_lock(&drvdata->mutex); + if (test_bit(curr_list, drvdata->enable_bitmap)) + buf = "Y\n"; + else + buf = "N\n"; + mutex_unlock(&drvdata->mutex); + + return simple_read_from_buffer(userbuf, count, ppos, buf, strlen(buf)); +} + +static ssize_t enable_write(struct file *filp, const char __user *userbuf, + size_t count, loff_t *ppos) +{ + int ret = 0, curr_list; + bool val; + struct dcc_drvdata *drvdata = filp->private_data; + + curr_list = dcc_filp_curr_list(filp); + if (curr_list < 0) + return curr_list; + + ret = kstrtobool_from_user(userbuf, count, &val); + if (ret < 0) + return ret; + + if (val) { + ret = dcc_enable(drvdata, curr_list); + if (ret) + return ret; + } else { + dcc_disable(drvdata, curr_list); + } + + return count; +} + +static const struct file_operations enable_fops = { + .read = enable_read, + .write = enable_write, + .open = simple_open, + .llseek = generic_file_llseek, +}; + +static ssize_t trigger_write(struct file *filp, + const char __user *user_buf, size_t count, + loff_t *ppos) +{ + int ret; + unsigned int val; + struct dcc_drvdata *drvdata = filp->private_data; + + ret = kstrtouint_from_user(user_buf, count, 0, &val); + if (ret < 0) + return ret; + + if (val != 1) + return -EINVAL; + + ret = dcc_sw_trigger(drvdata); + if (ret < 0) + return ret; + + return count; +} + +static const struct file_operations trigger_fops = { + .write = trigger_write, + .open = simple_open, + .llseek = generic_file_llseek, +}; + +static int dcc_config_add(struct dcc_drvdata *drvdata, unsigned int addr, + unsigned int len, bool apb_bus, int curr_list) +{ + int ret = 0; + struct dcc_config_entry *entry, *pentry; + unsigned int base, offset; + + mutex_lock(&drvdata->mutex); + + if (!len || len > drvdata->ram_size / DCC_WORD_SIZE) { + dev_err(drvdata->dev, "DCC: Invalid length\n"); + ret = -EINVAL; + goto out_unlock; + } + + base = addr & DCC_ADDR_RANGE_MASK; + + if (!list_empty(&drvdata->cfg_head[curr_list])) { + pentry = list_last_entry(&drvdata->cfg_head[curr_list], + struct dcc_config_entry, list); + + if (pentry->desc_type == DCC_READ_TYPE && + addr >= (pentry->base + pentry->offset) && + addr <= (pentry->base + pentry->offset + MAX_DCC_OFFSET)) { + /* Re-use base address from last entry */ + base = pentry->base; + + if ((pentry->len * 4 + pentry->base + pentry->offset) + == addr) { + len += pentry->len; + + if (len > MAX_DCC_LEN) + pentry->len = MAX_DCC_LEN; + else + pentry->len = len; + + addr = pentry->base + pentry->offset + + pentry->len * 4; + len -= pentry->len; + } + } + } + + offset = addr - base; + + while (len) { + entry = kzalloc(sizeof(*entry), GFP_KERNEL); + if (!entry) { + ret = -ENOMEM; + goto out_unlock; + } + + entry->base = base; + entry->offset = offset; + entry->len = min_t(u32, len, MAX_DCC_LEN); + entry->desc_type = DCC_READ_TYPE; + entry->apb_bus = apb_bus; + INIT_LIST_HEAD(&entry->list); + list_add_tail(&entry->list, + &drvdata->cfg_head[curr_list]); + + len -= entry->len; + offset += MAX_DCC_LEN * 4; + } + +out_unlock: + mutex_unlock(&drvdata->mutex); + return ret; +} + +static ssize_t dcc_config_add_read(struct dcc_drvdata *drvdata, char *buf, int curr_list) +{ + bool bus; + int len, nval; + unsigned int base; + char apb_bus[4]; + + nval = sscanf(buf, "%x %i %3s", &base, &len, apb_bus); + if (nval <= 0 || nval > 3) + return -EINVAL; + + if (nval == 1) { + len = 1; + bus = false; + } else if (nval == 2) { + bus = false; + } else if (!strcmp("apb", apb_bus)) { + bus = true; + } else if (!strcmp("ahb", apb_bus)) { + bus = false; + } else { + return -EINVAL; + } + + return dcc_config_add(drvdata, base, len, bus, curr_list); +} + +static void dcc_config_reset(struct dcc_drvdata *drvdata) +{ + struct dcc_config_entry *entry, *temp; + int curr_list; + + mutex_lock(&drvdata->mutex); + + for (curr_list = 0; curr_list < drvdata->max_link_list; curr_list++) { + list_for_each_entry_safe(entry, temp, + &drvdata->cfg_head[curr_list], list) { + list_del(&entry->list); + } + } + drvdata->ram_start = 0; + drvdata->ram_cfg = 0; + mutex_unlock(&drvdata->mutex); +} + +static ssize_t config_reset_write(struct file *filp, + const char __user *user_buf, size_t count, + loff_t *ppos) +{ + unsigned int val; + int ret; + struct dcc_drvdata *drvdata = filp->private_data; + + ret = kstrtouint_from_user(user_buf, count, 0, &val); + if (ret < 0) + return ret; + + if (val) + dcc_config_reset(drvdata); + + return count; +} + +static const struct file_operations config_reset_fops = { + .write = config_reset_write, + .open = simple_open, + .llseek = generic_file_llseek, +}; + +static ssize_t ready_read(struct file *filp, char __user *userbuf, + size_t count, loff_t *ppos) +{ + char *buf; + struct dcc_drvdata *drvdata = filp->private_data; + + if (!is_dcc_enabled(drvdata)) + return -EINVAL; + + if (!FIELD_GET(BIT(1), readl(drvdata->base + dcc_status(drvdata->mem_map_ver)))) + buf = "Y\n"; + else + buf = "N\n"; + + return simple_read_from_buffer(userbuf, count, ppos, buf, strlen(buf) + 1); +} + +static const struct file_operations ready_fops = { + .read = ready_read, + .open = simple_open, + .llseek = generic_file_llseek, +}; + +static ssize_t loop_offset_read(struct file *filp, char __user *userbuf, + size_t count, loff_t *ppos) +{ + char buf[4]; + struct dcc_drvdata *drvdata = filp->private_data; + + snprintf(buf, sizeof(buf), "%d", drvdata->loop_shift); + return simple_read_from_buffer(userbuf, count, ppos, buf, strlen(buf) + 1); +} + +static const struct file_operations loop_offset_fops = { + .read = loop_offset_read, + .open = simple_open, + .llseek = generic_file_llseek, +}; +static int dcc_add_loop(struct dcc_drvdata *drvdata, unsigned long loop_cnt, int curr_list) +{ + struct dcc_config_entry *entry; + + entry = kzalloc(sizeof(*entry), GFP_KERNEL); + if (!entry) + return -ENOMEM; + + entry->loop_cnt = min_t(u32, loop_cnt, MAX_LOOP_CNT); + entry->desc_type = DCC_LOOP_TYPE; + INIT_LIST_HEAD(&entry->list); + list_add_tail(&entry->list, &drvdata->cfg_head[curr_list]); + + return 0; +} + +static ssize_t dcc_config_add_loop(struct dcc_drvdata *drvdata, char *buf, int curr_list) +{ + int ret, i = 0; + char *token, *input; + char delim[2] = " "; + unsigned int val[MAX_LOOP_ADDR]; + + input = buf; + + while ((token = strsep(&input, delim)) && i < MAX_LOOP_ADDR) { + ret = kstrtouint(token, 0, &val[i++]); + if (ret) + return ret; + } + + if (token) { + dev_err(drvdata->dev, "Max limit %u of loop address exceeded\n", + MAX_LOOP_ADDR); + return -EINVAL; + } + + if (val[1] < 1 || val[1] > 8 || val[1] > (i - 2)) + return -EINVAL; + + ret = dcc_add_loop(drvdata, val[0], curr_list); + if (ret) + return ret; + + for (i = 0; i < val[1]; i++) + dcc_config_add(drvdata, val[i + 2], 1, false, curr_list); + + return dcc_add_loop(drvdata, 1, curr_list); +} + +static int dcc_rd_mod_wr_add(struct dcc_drvdata *drvdata, unsigned int mask, + unsigned int val, int curr_list) +{ + int ret = 0; + struct dcc_config_entry *entry; + + mutex_lock(&drvdata->mutex); + + if (list_empty(&drvdata->cfg_head[curr_list])) { + dev_err(drvdata->dev, "DCC: No read address programmed\n"); + ret = -EPERM; + goto out_unlock; + } + + entry = devm_kzalloc(drvdata->dev, sizeof(*entry), GFP_KERNEL); + if (!entry) { + ret = -ENOMEM; + goto out_unlock; + } + + entry->desc_type = DCC_READ_WRITE_TYPE; + entry->mask = mask; + entry->write_val = val; + list_add_tail(&entry->list, &drvdata->cfg_head[curr_list]); +out_unlock: + mutex_unlock(&drvdata->mutex); + return ret; +} + +static ssize_t dcc_config_add_read_write(struct dcc_drvdata *drvdata, char *buf, int curr_list) +{ + int ret; + int nval; + unsigned int addr, mask, val; + + nval = sscanf(buf, "%x %x %x", &addr, &mask, &val); + + if (nval <= 1 || nval > 3) + return -EINVAL; + + ret = dcc_config_add(drvdata, addr, 1, false, curr_list); + if (ret) + return ret; + + return dcc_rd_mod_wr_add(drvdata, mask, val, curr_list); +} + +static int dcc_add_write(struct dcc_drvdata *drvdata, unsigned int addr, + unsigned int write_val, int apb_bus, int curr_list) +{ + struct dcc_config_entry *entry; + + entry = devm_kzalloc(drvdata->dev, sizeof(*entry), GFP_KERNEL); + if (!entry) + return -ENOMEM; + + entry->desc_type = DCC_WRITE_TYPE; + entry->base = addr & GENMASK(31, 4); + entry->offset = addr - entry->base; + entry->write_val = write_val; + entry->len = 1; + entry->apb_bus = apb_bus; + list_add_tail(&entry->list, &drvdata->cfg_head[curr_list]); + + return 0; +} + +static ssize_t dcc_config_add_write(struct dcc_drvdata *drvdata, char *buf, int curr_list) +{ + bool bus; + int nval; + unsigned int addr, write_val; + char apb_bus[4]; + + nval = sscanf(buf, "%x %x %3s", &addr, &write_val, apb_bus); + + if (nval <= 1 || nval > 3) + return -EINVAL; + + if (nval == 2) + bus = false; + + if (nval == 3) { + if (!strcmp("apb", apb_bus)) + bus = true; + else if (!strcmp("ahb", apb_bus)) + bus = false; + else + return -EINVAL; + } + + return dcc_add_write(drvdata, addr, write_val, bus, curr_list); +} + +static int config_show(struct seq_file *m, void *data) +{ + struct dcc_drvdata *drvdata = m->private; + struct dcc_config_entry *entry, *next_entry, *prev_entry, *loop_entry; + int index = 0, curr_list, i; + unsigned int loop_val[MAX_LOOP_ADDR]; + + curr_list = dcc_filp_curr_list(m->file); + if (curr_list < 0) + return curr_list; + + mutex_lock(&drvdata->mutex); + + list_for_each_entry(entry, &drvdata->cfg_head[curr_list], list) { + index++; + switch (entry->desc_type) { + case DCC_READ_WRITE_TYPE: + prev_entry = list_prev_entry(entry, list); + seq_printf(m, "RW 0x%x 0x%x 0x%x\n", + prev_entry->base + prev_entry->offset, + entry->mask, + entry->write_val); + break; + case DCC_LOOP_TYPE: + loop_entry = entry; + loop_val[0] = loop_entry->loop_cnt; + loop_entry = list_next_entry(loop_entry, list); + for (i = 0; i < (MAX_LOOP_ADDR-2); + i++, loop_entry = list_next_entry(loop_entry, list)) { + if (loop_entry->desc_type == DCC_READ_TYPE) { + loop_val[i+2] = loop_entry->base + loop_entry->offset; + } else if (loop_entry->desc_type == DCC_LOOP_TYPE) { + loop_val[i+2] = loop_entry->loop_cnt; + loop_val[1] = i; + entry = loop_entry; + break; + } + } + seq_printf(m, "L 0x%x 0x%x", loop_val[0], loop_val[1]); + for (i = 0; i < loop_val[1]; i++) + seq_printf(m, " 0x%x", loop_val[i+2]); + seq_puts(m, "\n"); + break; + case DCC_WRITE_TYPE: + seq_printf(m, "W 0x%x 0x%x %s\n", + entry->base + entry->offset, + entry->write_val, + entry->apb_bus ? "apb":"ahb"); + break; + case DCC_READ_TYPE: + if (entry->len == 1) { + next_entry = list_next_entry(entry, list); + if (next_entry && next_entry->desc_type == DCC_READ_WRITE_TYPE) + continue; + } + seq_printf(m, "R 0x%x 0x%x %s\n", + entry->base + entry->offset, + entry->len, + entry->apb_bus ? "apb":"ahb"); + } + } + mutex_unlock(&drvdata->mutex); + return 0; +} + +static int config_open(struct inode *inode, struct file *file) +{ + struct dcc_drvdata *drvdata = inode->i_private; + + return single_open(file, config_show, drvdata); +} + +static ssize_t config_write(struct file *filp, + const char __user *user_buf, size_t count, + loff_t *ppos) +{ + int ret, curr_list; + char *token, *line; + char *buf, *bufp, *temp_buff; + char *delim = " "; + struct dcc_drvdata *drvdata = filp->f_inode->i_private; + ssize_t processed_len = 0; + + if (count == 0) + return -EINVAL; + buf = kzalloc(count+1, GFP_KERNEL); + if (buf) + bufp = buf; + else + return -ENOMEM; + + ret = copy_from_user(buf, user_buf, count); + if (ret) + goto err; + + curr_list = dcc_filp_curr_list(filp); + if (curr_list < 0) { + ret = curr_list; + goto err; + } + + while (bufp[0] != '\0') { + /* Parse line by line */ + line = strsep(&bufp, "\n"); + /* When one complete line could be parsed */ + if (line && bufp) { + processed_len += strlen(line) + 1; + if (drvdata->temp_buff_ptr && drvdata->temp_buff_ptr[curr_list]) { + temp_buff = drvdata->temp_buff_ptr[curr_list]; + /* Size of combined string must not be greater than + * allowed line size. + */ + if (strlen(line) + strlen(temp_buff) + 1 > LINE_BUFFER_MAX_SZ) { + dev_err(drvdata->dev, "Invalid input\n"); + ret = -EINVAL; + goto err; + } + strlcat(temp_buff, line, PAGE_SIZE); + line = temp_buff; + kfree(temp_buff); + drvdata->temp_buff_ptr[curr_list] = NULL; + } + + token = strsep(&line, delim); + + if (!strcmp("R", token)) { + ret = dcc_config_add_read(drvdata, line, curr_list); + } else if (!strcmp("W", token)) { + ret = dcc_config_add_write(drvdata, line, curr_list); + } else if (!strcmp("RW", token)) { + ret = dcc_config_add_read_write(drvdata, line, curr_list); + } else if (!strcmp("L", token)) { + ret = dcc_config_add_loop(drvdata, line, curr_list); + } else { + dev_err(drvdata->dev, "%s is not a correct input\n", token); + ret = -EINVAL; + } + + if (ret) + goto err; + } else { + /* Save the incomplete line to a temporary buffer and rejoin it later */ + if (!drvdata->temp_buff_ptr) { + drvdata->temp_buff_ptr = devm_kcalloc(drvdata->dev, + drvdata->max_link_list, + sizeof(char *), + GFP_KERNEL); + if (!drvdata->temp_buff_ptr) { + ret = -ENOMEM; + goto err; + } + } + drvdata->temp_buff_ptr[curr_list] = kzalloc(LINE_BUFFER_MAX_SZ, + GFP_KERNEL); + temp_buff = drvdata->temp_buff_ptr[curr_list]; + if (!temp_buff) { + ret = -ENOMEM; + goto err; + } + if ((count - processed_len) >= LINE_BUFFER_MAX_SZ) { + dev_err(drvdata->dev, "Invalid input\n"); + ret = -EINVAL; + goto err; + } + memcpy(temp_buff, line, count - processed_len); + temp_buff[count - processed_len + 1] = '\0'; + processed_len += (strlen(temp_buff) + 1); + break; + } + } + + kfree(buf); + return processed_len; + +err: + kfree(buf); + if (drvdata->temp_buff_ptr && drvdata->temp_buff_ptr[curr_list]) { + kfree(drvdata->temp_buff_ptr[curr_list]); + drvdata->temp_buff_ptr[curr_list] = NULL; + } + return ret; +} + +static const struct file_operations config_fops = { + .open = config_open, + .read = seq_read, + .write = config_write, + .llseek = seq_lseek, + .release = single_release, +}; + +static void dcc_delete_debug_dir(struct dcc_drvdata *drvdata) +{ + debugfs_remove_recursive(drvdata->dbg_dir); +}; + +static void dcc_create_debug_dir(struct dcc_drvdata *drvdata) +{ + int i; + char list_num[10]; + struct dentry *dcc_dev, *list; + struct device *dev = drvdata->dev; + + drvdata->dbg_dir = debugfs_create_dir(KBUILD_MODNAME, NULL); + dcc_dev = debugfs_create_dir(dev_name(dev), drvdata->dbg_dir); + + for (i = 0; i < drvdata->max_link_list; i++) { + snprintf(list_num, sizeof(list_num), "%d", i); + list = debugfs_create_dir(list_num, dcc_dev); + debugfs_create_file("enable", 0600, list, drvdata, &enable_fops); + debugfs_create_file("config", 0600, list, drvdata, &config_fops); + } + + debugfs_create_file("trigger", 0200, drvdata->dbg_dir, drvdata, &trigger_fops); + debugfs_create_file("ready", 0400, drvdata->dbg_dir, drvdata, &ready_fops); + debugfs_create_file("config_reset", 0200, drvdata->dbg_dir, drvdata, &config_reset_fops); + debugfs_create_file("loop_offset", 0400, drvdata->dbg_dir, drvdata, &loop_offset_fops); +} + +static ssize_t dcc_sram_read(struct file *file, char __user *data, + size_t len, loff_t *ppos) +{ + unsigned char *buf; + struct dcc_drvdata *drvdata; + + drvdata = container_of(file->private_data, struct dcc_drvdata, + sram_dev); + + /* EOF check */ + if (*ppos >= drvdata->ram_size) + return 0; + + if ((*ppos + len) > drvdata->ram_size) + len = (drvdata->ram_size - *ppos); + + buf = kzalloc(len, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + memcpy_fromio(buf, drvdata->ram_base + *ppos, len); + + if (copy_to_user(data, buf, len)) { + kfree(buf); + return -EFAULT; + } + + *ppos += len; + + kfree(buf); + + return len; +} + +static void dcc_configure_list(struct dcc_drvdata *drvdata, struct device_node *np) +{ + const char *prop; + int ret, curr_list, index = 0; + char *token, *bufp; + char *delim = " "; + u32 len, processed_len = 0; + + ret = of_property_read_u32(np, "qcom,curr-link-list", + &curr_list); + if (ret) + return; + + if(!of_get_property(np, "qcom,link-list", &len)) + return; + + bufp = kzalloc(len+1, GFP_KERNEL); + if (!bufp) + return; + + while (!of_property_read_string_index(np, "qcom,link-list", index, &prop)) { + strncpy(bufp, prop, strlen(prop)); + bufp[strlen(prop)] = '\0'; + + processed_len += strlen(bufp) + 1; + + token = strsep(&bufp, delim); + + if (!strcmp("R", token)) { + ret = dcc_config_add_read(drvdata, bufp, curr_list); + } else if (!strcmp("W", token)) { + ret = dcc_config_add_write(drvdata, bufp, curr_list); + } else if (!strcmp("RW", token)) { + ret = dcc_config_add_read_write(drvdata, bufp, curr_list); + } else if (!strcmp("L", token)) { + ret = dcc_config_add_loop(drvdata, bufp, curr_list); + } else { + dev_err(drvdata->dev, "%s is not a correct input\n", token); + ret = -EINVAL; + } + + if (ret < 0) + dev_err(drvdata->dev, "Configure line %s failed\n", prop); + + index++; + } + + dcc_enable(drvdata, curr_list); + kfree(bufp); +} + +static const struct file_operations dcc_sram_fops = { + .owner = THIS_MODULE, + .read = dcc_sram_read, +}; + +static int dcc_sram_dev_init(struct dcc_drvdata *drvdata) +{ + drvdata->sram_dev.minor = MISC_DYNAMIC_MINOR; + drvdata->sram_dev.name = "dcc_sram"; + drvdata->sram_dev.fops = &dcc_sram_fops; + + return misc_register(&drvdata->sram_dev); +} + +static void dcc_sram_dev_exit(struct dcc_drvdata *drvdata) +{ + misc_deregister(&drvdata->sram_dev); +} + +static int dcc_probe(struct platform_device *pdev) +{ + u32 val; + int ret = 0, i; + struct device *dev = &pdev->dev; + struct dcc_drvdata *drvdata; + struct resource *res; + + drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL); + if (!drvdata) + return -ENOMEM; + + drvdata->dev = &pdev->dev; + platform_set_drvdata(pdev, drvdata); + + drvdata->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(drvdata->base)) + return PTR_ERR(drvdata->base); + + drvdata->ram_base = devm_platform_get_and_ioremap_resource(pdev, 1, &res); + if (IS_ERR(drvdata->ram_base)) + return PTR_ERR(drvdata->ram_base); + + drvdata->ram_size = resource_size(res); + ret = of_property_read_u32(pdev->dev.of_node, "qcom,dcc-offset", + &drvdata->ram_offset); + if (ret) + return -EINVAL; + + drvdata->mem_map_ver = (u64)of_device_get_match_data(&pdev->dev); + + switch (drvdata->mem_map_ver) { + case MEM_MAP_VER3: + case MEM_MAP_VER2: + drvdata->max_link_list = readl(drvdata->base + DCC_LL_NUM_INFO); + if (!drvdata->max_link_list) + return -EINVAL; + break; + case MEM_MAP_VER1: + drvdata->max_link_list = DCC_MAX_LINK_LIST; + break; + default: + dev_err(drvdata->dev, "Unsupported memory map version.\n"); + return -EINVAL; + } + + val = readl(drvdata->base + DCC_HW_INFO); + /* Either set the fixed loop offset or calculate + * it from the total number of words in dcc_sram. + * Max consecutive addresses dcc can loop is + * equivalent to the words in dcc_sram. + */ + if (val & DCC_LOOP_OFFSET_MASK) + drvdata->loop_shift = DCC_FIX_LOOP_OFFSET; + else + drvdata->loop_shift = get_bitmask_order((drvdata->ram_offset + + drvdata->ram_size) / DCC_SRAM_WORD_LENGTH - 1); + + mutex_init(&drvdata->mutex); + + drvdata->enable_bitmap = devm_kcalloc(dev, BITS_TO_LONGS(drvdata->max_link_list), + sizeof(*drvdata->enable_bitmap), GFP_KERNEL); + if (!drvdata->enable_bitmap) + return -ENOMEM; + + drvdata->cfg_head = devm_kcalloc(dev, drvdata->max_link_list, + sizeof(*drvdata->cfg_head), GFP_KERNEL); + if (!drvdata->cfg_head) + return -ENOMEM; + + for (i = 0; i < drvdata->max_link_list; i++) + INIT_LIST_HEAD(&drvdata->cfg_head[i]); + + ret = dcc_sram_dev_init(drvdata); + if (ret) { + dev_err(drvdata->dev, "DCC: sram node not registered.\n"); + return ret; + } + + dcc_create_debug_dir(drvdata); + dcc_configure_list(drvdata, pdev->dev.of_node); + + return 0; +} + +static void dcc_remove(struct platform_device *pdev) +{ + struct dcc_drvdata *drvdata = platform_get_drvdata(pdev); + + dcc_delete_debug_dir(drvdata); + dcc_sram_dev_exit(drvdata); + dcc_config_reset(drvdata); +} + +static const struct of_device_id dcc_match_table[] = { + { .compatible = "qcom,dcc-v1", .data = (void *)MEM_MAP_VER1 }, + { .compatible = "qcom,dcc-v2", .data = (void *)MEM_MAP_VER2 }, + { .compatible = "qcom,dcc-v3", .data = (void *)MEM_MAP_VER3 }, + { } +}; +MODULE_DEVICE_TABLE(of, dcc_match_table); + +static struct platform_driver dcc_driver = { + .probe = dcc_probe, + .remove = dcc_remove, + .driver = { + .name = "qcom-dcc", + .of_match_table = dcc_match_table, + }, +}; + +module_platform_driver(dcc_driver); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Qualcomm Technologies Inc. DCC driver"); From 63edcd53fb1a21156429c551c0b9c7027c49d99f Mon Sep 17 00:00:00 2001 From: Jie Gan Date: Thu, 8 Jan 2026 11:28:06 +0800 Subject: [PATCH 2269/2333] QCLINUX: add qcom_debug.config for debug features The config file is created to contain specific debug features such as DCC/memory dump driver. Signed-off-by: Jie Gan --- arch/arm64/configs/qcom_debug.config | 1 + 1 file changed, 1 insertion(+) create mode 100644 arch/arm64/configs/qcom_debug.config diff --git a/arch/arm64/configs/qcom_debug.config b/arch/arm64/configs/qcom_debug.config new file mode 100644 index 0000000000000..874f80f29d314 --- /dev/null +++ b/arch/arm64/configs/qcom_debug.config @@ -0,0 +1 @@ +CONFIG_QCOM_DCC=m From 5565111b91419475464d219bc869e00f98ff77ab Mon Sep 17 00:00:00 2001 From: Jie Gan Date: Thu, 8 Jan 2026 17:47:45 +0800 Subject: [PATCH 2270/2333] QCLINUX: qcom-dcc: add qcom-dcc dev driver Create qcom-dcc dev driver for matching the qcom-dcc driver without DT. Signed-off-by: Jie Gan --- arch/arm64/configs/qcom_debug.config | 1 + drivers/misc/Kconfig | 8 +- drivers/misc/Makefile | 1 + drivers/misc/qcom-dcc-dev.c | 116 +++++++++++++++++++++++++++ drivers/misc/qcom-dcc.c | 79 ++---------------- drivers/misc/qcom-dcc.h | 20 +++++ 6 files changed, 153 insertions(+), 72 deletions(-) create mode 100644 drivers/misc/qcom-dcc-dev.c create mode 100644 drivers/misc/qcom-dcc.h diff --git a/arch/arm64/configs/qcom_debug.config b/arch/arm64/configs/qcom_debug.config index 874f80f29d314..eb2b32af3b40b 100644 --- a/arch/arm64/configs/qcom_debug.config +++ b/arch/arm64/configs/qcom_debug.config @@ -1 +1,2 @@ CONFIG_QCOM_DCC=m +CONFIG_QCOM_DCC_DEV=m diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 133b854166958..7b19dd2f28e64 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -311,13 +311,19 @@ config QCOM_FASTRPC module. config QCOM_DCC - tristate "Qualcomm Technologies, Inc. Data Capture and Compare (DCC) engine driver" + tristate "Qualcomm Data Capture and Compare (DCC) engine driver" depends on ARCH_QCOM || COMPILE_TEST help This option enables the driver for the Data Capture and Compare engine. DCC driver provides interfaces to configure DCC block and read back the captured data from the DCC's internal SRAM. The module name for this is qcom-dcc. +config QCOM_DCC_DEV + tristate "Qualcomm Data Capture and Compare (DCC) engine device instance" + depends on QCOM_DCC + help + This is the device instance of the QCOM DCC driver. + config SGI_GRU tristate "SGI GRU driver" depends on X86_UV && SMP diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 338ed270b7cfc..812746940d628 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -76,3 +76,4 @@ obj-y += keba/ obj-y += amd-sbi/ obj-$(CONFIG_MISC_RP1) += rp1/ obj-$(CONFIG_QCOM_DCC) += qcom-dcc.o +obj-$(CONFIG_QCOM_DCC_DEV) += qcom-dcc-dev.o diff --git a/drivers/misc/qcom-dcc-dev.c b/drivers/misc/qcom-dcc-dev.c new file mode 100644 index 0000000000000..e0eb2e61d652b --- /dev/null +++ b/drivers/misc/qcom-dcc-dev.c @@ -0,0 +1,116 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#include +#include +#include +#include "qcom-dcc.h" + +#define DEV_NAME "qcom-dcc" + +static struct platform_device *dcc_pdev; + +static const struct dcc_pdata talos_pdata = { + .base = 0x010a2000, + .size = 0x00001000, + .ram_base = 0x010ae000, + .ram_size = 0x00002000, + .dcc_offset = 0x6000, + .map_ver = 0x1, +}; + +static const struct dcc_pdata lemans_pdata = { + .base = 0x040ff000, + .size = 0x00001000, + .ram_base = 0x040b8800, + .ram_size = 0x00006000, + .dcc_offset = 0x38800, + .map_ver = 0x3, +}; + +static const struct dcc_pdata kodiak_pdata = { + .base = 0x0117f000, + .size = 0x00001000, + .ram_base = 0x01112000, + .ram_size = 0x00006000, + .dcc_offset = 0x12000, + .map_ver = 0x2, +}; + +static int __init dcc_dev_init(void) +{ + int ret; + u32 soc_id; + + dcc_pdev = platform_device_alloc(DEV_NAME, -1); + if (!dcc_pdev) + return -ENOMEM; + + ret = qcom_smem_get_soc_id(&soc_id); + if (ret) + goto fail; + + switch (soc_id) { + case 475: + case 497: + case 498: + case 515: + ret = platform_device_add_data(dcc_pdev, &kodiak_pdata, sizeof(kodiak_pdata)); + if (ret) + goto fail; + + break; + case 534: + case 606: + case 667: + case 674: + case 675: + case 676: + ret = platform_device_add_data(dcc_pdev, &lemans_pdata, sizeof(lemans_pdata)); + if (ret) + goto fail; + + break; + case 377: + case 380: + case 384: + case 401: + case 406: + case 680: + ret = platform_device_add_data(dcc_pdev, &talos_pdata, sizeof(talos_pdata)); + if (ret) + goto fail; + + break; + default: + pr_err("DCC: Invalid SoC ID\n"); + ret = -EINVAL; + goto fail; + } + + ret = platform_device_add(dcc_pdev); + if (ret) + goto fail; + + pr_info("DCC platform device has registered\n"); + + return 0; + +fail: + pr_err("Failed to register DCC platform device\n"); + platform_device_put(dcc_pdev); + + return ret; +} + +static void __exit dcc_dev_exit(void) +{ + platform_device_unregister(dcc_pdev); +} + +module_init(dcc_dev_init); +module_exit(dcc_dev_exit); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Qualcomm Technologies Inc. DCC driver, device stub"); diff --git a/drivers/misc/qcom-dcc.c b/drivers/misc/qcom-dcc.c index a511faac5d4b0..e75f98b90d8f7 100644 --- a/drivers/misc/qcom-dcc.c +++ b/drivers/misc/qcom-dcc.c @@ -135,6 +135,8 @@ #include #include +#include "qcom-dcc.h" + #define STATUS_READY_TIMEOUT 5000 /* microseconds */ /* DCC registers */ @@ -1423,57 +1425,6 @@ static ssize_t dcc_sram_read(struct file *file, char __user *data, return len; } -static void dcc_configure_list(struct dcc_drvdata *drvdata, struct device_node *np) -{ - const char *prop; - int ret, curr_list, index = 0; - char *token, *bufp; - char *delim = " "; - u32 len, processed_len = 0; - - ret = of_property_read_u32(np, "qcom,curr-link-list", - &curr_list); - if (ret) - return; - - if(!of_get_property(np, "qcom,link-list", &len)) - return; - - bufp = kzalloc(len+1, GFP_KERNEL); - if (!bufp) - return; - - while (!of_property_read_string_index(np, "qcom,link-list", index, &prop)) { - strncpy(bufp, prop, strlen(prop)); - bufp[strlen(prop)] = '\0'; - - processed_len += strlen(bufp) + 1; - - token = strsep(&bufp, delim); - - if (!strcmp("R", token)) { - ret = dcc_config_add_read(drvdata, bufp, curr_list); - } else if (!strcmp("W", token)) { - ret = dcc_config_add_write(drvdata, bufp, curr_list); - } else if (!strcmp("RW", token)) { - ret = dcc_config_add_read_write(drvdata, bufp, curr_list); - } else if (!strcmp("L", token)) { - ret = dcc_config_add_loop(drvdata, bufp, curr_list); - } else { - dev_err(drvdata->dev, "%s is not a correct input\n", token); - ret = -EINVAL; - } - - if (ret < 0) - dev_err(drvdata->dev, "Configure line %s failed\n", prop); - - index++; - } - - dcc_enable(drvdata, curr_list); - kfree(bufp); -} - static const struct file_operations dcc_sram_fops = { .owner = THIS_MODULE, .read = dcc_sram_read, @@ -1499,7 +1450,7 @@ static int dcc_probe(struct platform_device *pdev) int ret = 0, i; struct device *dev = &pdev->dev; struct dcc_drvdata *drvdata; - struct resource *res; + const struct dcc_pdata *pdata = dev_get_platdata(dev); drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL); if (!drvdata) @@ -1508,21 +1459,17 @@ static int dcc_probe(struct platform_device *pdev) drvdata->dev = &pdev->dev; platform_set_drvdata(pdev, drvdata); - drvdata->base = devm_platform_ioremap_resource(pdev, 0); + drvdata->base = devm_ioremap(dev, pdata->base, pdata->size); if (IS_ERR(drvdata->base)) return PTR_ERR(drvdata->base); - drvdata->ram_base = devm_platform_get_and_ioremap_resource(pdev, 1, &res); + drvdata->ram_base = devm_ioremap(dev, pdata->ram_base, pdata->ram_size); if (IS_ERR(drvdata->ram_base)) return PTR_ERR(drvdata->ram_base); - drvdata->ram_size = resource_size(res); - ret = of_property_read_u32(pdev->dev.of_node, "qcom,dcc-offset", - &drvdata->ram_offset); - if (ret) - return -EINVAL; - - drvdata->mem_map_ver = (u64)of_device_get_match_data(&pdev->dev); + drvdata->ram_size = pdata->ram_size; + drvdata->ram_offset = pdata->dcc_offset; + drvdata->mem_map_ver = pdata->map_ver; switch (drvdata->mem_map_ver) { case MEM_MAP_VER3: @@ -1573,7 +1520,6 @@ static int dcc_probe(struct platform_device *pdev) } dcc_create_debug_dir(drvdata); - dcc_configure_list(drvdata, pdev->dev.of_node); return 0; } @@ -1587,20 +1533,11 @@ static void dcc_remove(struct platform_device *pdev) dcc_config_reset(drvdata); } -static const struct of_device_id dcc_match_table[] = { - { .compatible = "qcom,dcc-v1", .data = (void *)MEM_MAP_VER1 }, - { .compatible = "qcom,dcc-v2", .data = (void *)MEM_MAP_VER2 }, - { .compatible = "qcom,dcc-v3", .data = (void *)MEM_MAP_VER3 }, - { } -}; -MODULE_DEVICE_TABLE(of, dcc_match_table); - static struct platform_driver dcc_driver = { .probe = dcc_probe, .remove = dcc_remove, .driver = { .name = "qcom-dcc", - .of_match_table = dcc_match_table, }, }; diff --git a/drivers/misc/qcom-dcc.h b/drivers/misc/qcom-dcc.h new file mode 100644 index 0000000000000..513c95dc742b5 --- /dev/null +++ b/drivers/misc/qcom-dcc.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#ifndef _QCOM_DCC_H +#define _QCOM_DCC_H + +#include + +struct dcc_pdata { + phys_addr_t base; + resource_size_t size; + phys_addr_t ram_base; + resource_size_t ram_size; + u32 dcc_offset; + u8 map_ver; +}; + +#endif From 81310bb45bb7569abedd0f687abbbba4034413f1 Mon Sep 17 00:00:00 2001 From: Jie Gan Date: Fri, 9 Jan 2026 14:42:21 +0800 Subject: [PATCH 2271/2333] QCLINUX: memory-dump: add QCOM memory dump driver The memory dump driver allows various client subsystems to register respective dump regions. At the time of deadlocks or cpu hangs these dump regions are captured to give a snapshot of the system at the time of the crash. Signed-off-by: Jie Gan --- arch/arm64/configs/qcom_debug.config | 1 + drivers/firmware/qcom/Kconfig | 9 + drivers/firmware/qcom/Makefile | 1 + drivers/firmware/qcom/memory_dump_v2.c | 1143 +++++++++++++++++++++ include/linux/firmware/qcom/memory_dump.h | 136 +++ 5 files changed, 1290 insertions(+) create mode 100644 drivers/firmware/qcom/memory_dump_v2.c create mode 100644 include/linux/firmware/qcom/memory_dump.h diff --git a/arch/arm64/configs/qcom_debug.config b/arch/arm64/configs/qcom_debug.config index eb2b32af3b40b..2e85e8df0469b 100644 --- a/arch/arm64/configs/qcom_debug.config +++ b/arch/arm64/configs/qcom_debug.config @@ -1,2 +1,3 @@ CONFIG_QCOM_DCC=m CONFIG_QCOM_DCC_DEV=m +CONFIG_QCOM_MEMORY_DUMP_V2=m diff --git a/drivers/firmware/qcom/Kconfig b/drivers/firmware/qcom/Kconfig index b477d54b495a6..531c6d2598ce0 100644 --- a/drivers/firmware/qcom/Kconfig +++ b/drivers/firmware/qcom/Kconfig @@ -74,4 +74,13 @@ config QCOM_QSEECOM_UEFISECAPP Select Y here to provide access to EFI variables on the aforementioned platforms. +config QCOM_MEMORY_DUMP_V2 + tristate "QCOM Memory Dump V2 Support" + depends on QCOM_TZMEM + help + This enables memory dump feature. It allows various client + subsystems to register respective dump regions. At the time + of deadlocks or cpu hangs these dump regions are captured to + give a snapshot of the system at the time of the crash. + endmenu diff --git a/drivers/firmware/qcom/Makefile b/drivers/firmware/qcom/Makefile index 0be40a1abc13c..c5e17ba255937 100644 --- a/drivers/firmware/qcom/Makefile +++ b/drivers/firmware/qcom/Makefile @@ -8,3 +8,4 @@ qcom-scm-objs += qcom_scm.o qcom_scm-smc.o qcom_scm-legacy.o obj-$(CONFIG_QCOM_TZMEM) += qcom_tzmem.o obj-$(CONFIG_QCOM_QSEECOM) += qcom_qseecom.o obj-$(CONFIG_QCOM_QSEECOM_UEFISECAPP) += qcom_qseecom_uefisecapp.o +obj-$(CONFIG_QCOM_MEMORY_DUMP_V2) += memory_dump_v2.o diff --git a/drivers/firmware/qcom/memory_dump_v2.c b/drivers/firmware/qcom/memory_dump_v2.c new file mode 100644 index 0000000000000..baf4c980f39fb --- /dev/null +++ b/drivers/firmware/qcom/memory_dump_v2.c @@ -0,0 +1,1143 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2014-2017, 2019-2021, The Linux Foundation. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MSM_DUMP_TABLE_VERSION MSM_DUMP_MAKE_VERSION(2, 0) + +#define SCM_CMD_DEBUG_LAR_UNLOCK 0x4 + +#define CPUSS_REGDUMP 0xEF +#define SPR_DUMP_CPU0 0x1F0 +#define SPR_DUMP_CPU1 0x1F1 +#define SPR_DUMP_CPU2 0x1F2 +#define SPR_DUMP_CPU3 0x1F3 +#define SPR_DUMP_CPU4 0x1F4 +#define SPR_DUMP_CPU5 0x1F5 +#define SPR_DUMP_CPU6 0x1F6 +#define SPR_DUMP_CPU7 0x1F7 +#define SPR_DATA_HEADER_SIZE 5 +#define SPR_DATA_HEADER_TAIL_SIZE 1 +#define SPR_INPUT_DATA_TAIL_SIZE 1 +#define SPR_INPUT_DATA_SIZE 1 +#define SPR_OUTPUT_DATA_SIZE 2 +#define MAX_CORE_NUM 8 + +#define INPUT_DATA_BY_HLOS 0x00C0FFEE +#define FORMAT_VERSION_1 0x1 +#define FORMAT_VERSION_2 0x2 +#define CORE_REG_NUM_DEFAULT 0x1 + +#define MAGIC_INDEX 0 +#define FORMAT_VERSION_INDEX 1 +#define SYS_REG_INPUT_INDEX 2 +#define OUTPUT_DUMP_INDEX 3 +#define PERCORE_INDEX 4 +#define SYSTEM_REGS_INPUT_INDEX 5 + +#define CMD_REPEAT_READ (0x2 << 24) +#define CMD_DELAY (0x1 << 24) +#define CMD_READ 0x0 +#define CMD_READ_WORD 0x1 +#define CMD_WRITE 0x2 +#define CMD_EXTRA 0x3 + +#define CMD_MASK 0x3 +#define OFFSET_MASK GENMASK(31, 2) +#define EXTRA_CMD_MASK GENMASK(31, 24) +#define EXTRA_VALUE_MASK GENMASK(23, 0) +#define MAX_EXTRA_VALUE 0xffffff + +struct sprs_dump_data { + void *dump_vaddr; + u32 size; + u32 sprs_data_index; + u32 used_memory; +}; + +struct cpuss_regdump_data { + void *dump_vaddr; + u32 size; + u32 core_reg_num; + u32 core_reg_used_num; + u32 core_reg_end_index; + u32 sys_reg_size; + u32 used_memory; +}; + +struct cpuss_dump_data { + struct mutex mutex; + struct cpuss_regdump_data *cpussregdata; + struct sprs_dump_data *sprdata[MAX_CORE_NUM]; +}; + +struct reg_dump_data { + uint32_t magic; + uint32_t version; + uint32_t system_regs_input_index; + uint32_t regdump_output_byte_offset; +}; + +struct msm_dump_table { + uint32_t version; + uint32_t num_entries; + struct msm_dump_entry entries[MAX_NUM_ENTRIES]; +}; + +struct msm_memory_dump { + uint64_t table_phys; + struct msm_dump_table *table; +}; + +/** + * Set bit 0 if percore reg dump initialized. + * Set bit 1 if spr dump initialized. + */ +#define PERCORE_REG_INITIALIZED BIT(0) +#define SPRS_INITIALIZED BIT(1) + +static struct msm_memory_dump memdump; + +/** + * reset_sprs_dump_table - reset the sprs dump table + * + * This function calculates system_regs_input_index and + * regdump_output_byte_offset to store into the dump memory. + * It also updates members of cpudata by the parameter core_reg_num. + * + * Returns 0 on success, or -ENOMEM on error of no enough memory. + */ +static int reset_sprs_dump_table(struct device *dev) +{ + int ret = 0; + struct reg_dump_data *p; + struct cpuss_dump_data *cpudata = dev_get_drvdata(dev); + int i = 0; + + if (!cpudata) + return -EFAULT; + + mutex_lock(&cpudata->mutex); + + for (i = 0; i < MAX_CORE_NUM; i++) { + if (cpudata->sprdata[i]) { + cpudata->sprdata[i]->sprs_data_index = 0; + cpudata->sprdata[i]->used_memory = (SPR_DATA_HEADER_SIZE + + SPR_INPUT_DATA_TAIL_SIZE) * sizeof(uint32_t); + memset(cpudata->sprdata[i]->dump_vaddr, 0xDE, + cpudata->sprdata[i]->size); + p = (struct reg_dump_data *)cpudata->sprdata[i]->dump_vaddr; + p->magic = INPUT_DATA_BY_HLOS; + p->version = FORMAT_VERSION_1; + p->system_regs_input_index = SYSTEM_REGS_INPUT_INDEX; + p->regdump_output_byte_offset = (SPR_DATA_HEADER_SIZE + + SPR_INPUT_DATA_TAIL_SIZE) * sizeof(uint32_t); + memset((uint32_t *)cpudata->sprdata[i]->dump_vaddr + + PERCORE_INDEX, 0x0, (SPR_DATA_HEADER_TAIL_SIZE + + SPR_INPUT_DATA_TAIL_SIZE) * sizeof(uint32_t)); + } + } + + mutex_unlock(&cpudata->mutex); + return ret; +} + + +/** + * update_reg_dump_table - update the register dump table + * @core_reg_num: the number of per-core registers + * + * This function calculates system_regs_input_index and + * regdump_output_byte_offset to store into the dump memory. + * It also updates members of cpudata by the parameter core_reg_num. + * + * Returns 0 on success, or -ENOMEM on error of no enough memory. + */ +static int update_reg_dump_table(struct device *dev, u32 core_reg_num) +{ + int ret = 0; + u32 system_regs_input_index = SYSTEM_REGS_INPUT_INDEX + + core_reg_num * 2; + u32 regdump_output_byte_offset = (system_regs_input_index + 1) + * sizeof(uint32_t); + struct reg_dump_data *p; + struct cpuss_dump_data *cpudata = dev_get_drvdata(dev); + + mutex_lock(&cpudata->mutex); + + if (regdump_output_byte_offset >= cpudata->cpussregdata->size || + regdump_output_byte_offset / sizeof(uint32_t) + < system_regs_input_index + 1) { + ret = -ENOMEM; + goto err; + } + + cpudata->cpussregdata->core_reg_num = core_reg_num; + cpudata->cpussregdata->core_reg_used_num = 0; + cpudata->cpussregdata->core_reg_end_index = PERCORE_INDEX; + cpudata->cpussregdata->sys_reg_size = 0; + cpudata->cpussregdata->used_memory = regdump_output_byte_offset; + + memset(cpudata->cpussregdata->dump_vaddr, 0xDE, cpudata->cpussregdata->size); + p = (struct reg_dump_data *)cpudata->cpussregdata->dump_vaddr; + p->magic = INPUT_DATA_BY_HLOS; + p->version = FORMAT_VERSION_2; + p->system_regs_input_index = system_regs_input_index; + p->regdump_output_byte_offset = regdump_output_byte_offset; + memset((uint32_t *)cpudata->cpussregdata->dump_vaddr + PERCORE_INDEX, 0x0, + (system_regs_input_index - PERCORE_INDEX + 1) + * sizeof(uint32_t)); + +err: + mutex_unlock(&cpudata->mutex); + return ret; +} + +static ssize_t core_reg_num_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret; + struct cpuss_dump_data *cpudata = dev_get_drvdata(dev); + + if (!cpudata) + return -EFAULT; + + mutex_lock(&cpudata->mutex); + + ret = scnprintf(buf, PAGE_SIZE, "%u\n", cpudata->cpussregdata->core_reg_num); + + mutex_unlock(&cpudata->mutex); + return ret; +} + +static ssize_t core_reg_num_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + int ret; + unsigned int val; + struct cpuss_dump_data *cpudata = dev_get_drvdata(dev); + + if (kstrtouint(buf, 16, &val)) + return -EINVAL; + + mutex_lock(&cpudata->mutex); + + if (cpudata->cpussregdata->core_reg_used_num || cpudata->cpussregdata->sys_reg_size) { + dev_err(dev, "Couldn't set core_reg_num, register available in list\n"); + ret = -EPERM; + goto err; + } + if (val == cpudata->cpussregdata->core_reg_num) { + mutex_unlock(&cpudata->mutex); + return size; + } + + mutex_unlock(&cpudata->mutex); + + ret = update_reg_dump_table(dev, val); + if (ret) { + dev_err(dev, "Couldn't set core_reg_num, no enough memory\n"); + return ret; + } + + return size; + +err: + mutex_unlock(&cpudata->mutex); + return ret; +} +static DEVICE_ATTR_RW(core_reg_num); + +/** + * This function shows configs of per-core and system registers. + */ +static ssize_t register_config_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + char local_buf[64]; + int len = 0, count = 0; + int index, system_index_start, index_end; + uint32_t register_offset, val; + uint32_t *p, cmd; + struct cpuss_dump_data *cpudata = dev_get_drvdata(dev); + + buf[0] = '\0'; + + if (!cpudata) + return -EFAULT; + + mutex_lock(&cpudata->mutex); + + p = (uint32_t *)cpudata->cpussregdata->dump_vaddr; + + /* print per-core & system registers */ + len = scnprintf(local_buf, 64, "per-core registers:\n"); + strlcat(buf, local_buf, PAGE_SIZE); + count += len; + + system_index_start = *(p + SYS_REG_INPUT_INDEX); + index_end = system_index_start + + cpudata->cpussregdata->sys_reg_size / sizeof(uint32_t) + 1; + for (index = PERCORE_INDEX; index < index_end;) { + if (index == system_index_start) { + len = scnprintf(local_buf, 64, "system registers:\n"); + if ((count + len) > PAGE_SIZE) { + dev_err(dev, "Couldn't write complete config\n"); + break; + } + + strlcat(buf, local_buf, PAGE_SIZE); + count += len; + } + + register_offset = *(p + index); + if (register_offset == 0) { + index++; + continue; + } + + cmd = register_offset & CMD_MASK; + register_offset &= OFFSET_MASK; + + switch (cmd) { + case CMD_READ: + val = *(p + index + 1); + len = scnprintf(local_buf, 64, + "0x%x, 0x%x, r\n", + register_offset, val); + index += 2; + break; + case CMD_READ_WORD: + len = scnprintf(local_buf, 64, + "0x%x, 0x%x, r\n", + register_offset, 0x4); + index++; + break; + case CMD_WRITE: + val = *(p + index + 1); + len = scnprintf(local_buf, 64, + "0x%x, 0x%x, w\n", + register_offset, val); + index += 2; + break; + case CMD_EXTRA: + val = *(p + index + 1); + cmd = val & EXTRA_CMD_MASK; + val &= EXTRA_VALUE_MASK; + if (cmd == CMD_DELAY) + len = scnprintf(local_buf, 64, + "0x%x, 0x%x, d\n", + register_offset, val); + else + len = scnprintf(local_buf, 64, + "0x%x, 0x%x, R\n", + register_offset, val); + index += 2; + break; + } + + if ((count + len) > PAGE_SIZE) { + dev_err(dev, "Couldn't write complete config\n"); + break; + } + + strlcat(buf, local_buf, PAGE_SIZE); + count += len; + } + + mutex_unlock(&cpudata->mutex); + return count; +} + +static int config_cpuss_register(struct device *dev, + uint32_t *p, uint32_t index, char cmd, + uint32_t register_offset, uint32_t val) +{ + int ret = 0; + + switch (cmd) { + case 'r': + if (val > 4) { + *(p + index) = register_offset; + *(p + index + 1) = val; + } else { + *(p + index) = register_offset | CMD_READ_WORD; + } + break; + case 'R': + if (val > MAX_EXTRA_VALUE) { + dev_err(dev, "repeat read time exceeded the limit\n"); + ret = -EINVAL; + return ret; + } + *(p + index) = register_offset | CMD_EXTRA; + *(p + index + 1) = val | CMD_REPEAT_READ; + break; + case 'd': + if (val > MAX_EXTRA_VALUE) { + dev_err(dev, "sleep time exceeded the limit\n"); + ret = -EINVAL; + return ret; + } + *(p + index) = CMD_EXTRA; + *(p + index + 1) = val | CMD_DELAY; + break; + case 'w': + *(p + index) = register_offset | CMD_WRITE; + *(p + index + 1) = val; + break; + default: + dev_err(dev, "Don't support this command\n"); + ret = -EINVAL; + } + return ret; +} +/** + * This function sets configs of per-core or system registers. + */ +static ssize_t register_config_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + int ret; + uint32_t register_offset, val, reserve_size = 4, per_core = 0; + int nval; + char cmd; + uint32_t num_cores; + u32 extra_memory; + u32 used_memory; + u32 system_reg_end_index; + uint32_t *p; + struct cpuss_dump_data *cpudata = dev_get_drvdata(dev); + + nval = sscanf(buf, "%x %x %c %u", ®ister_offset, + &val, &cmd, &per_core); + if (nval < 2) + return -EINVAL; + if (nval == 2) + cmd = 'r'; + if (per_core > 1) + return -EINVAL; + if (register_offset & 0x3) { + dev_err(dev, "Invalid address, must be 4 byte aligned\n"); + return -EINVAL; + } + + if (cmd == 'r' || cmd == 'R') { + if (val == 0) { + dev_err(dev, "Invalid length of 0\n"); + return -EINVAL; + } + if (cmd == 'r' && val & 0x3) { + dev_err(dev, "Invalid length, must be 4 byte aligned\n"); + return -EINVAL; + } + if (cmd == 'R') + reserve_size = val * 4; + else + reserve_size = val; + } + + mutex_lock(&cpudata->mutex); + + p = (uint32_t *)cpudata->cpussregdata->dump_vaddr; + if (per_core) { /* per-core register */ + if (cpudata->cpussregdata->core_reg_used_num == + cpudata->cpussregdata->core_reg_num) { + dev_err(dev, "Couldn't add per-core config, out of range\n"); + ret = -EINVAL; + goto err; + } + + num_cores = num_possible_cpus(); + extra_memory = reserve_size * num_cores; + used_memory = cpudata->cpussregdata->used_memory + extra_memory; + if (extra_memory / num_cores < reserve_size || + used_memory > cpudata->cpussregdata->size || + used_memory < cpudata->cpussregdata->used_memory) { + dev_err(dev, "Couldn't add per-core reg config, no enough memory\n"); + ret = -ENOMEM; + goto err; + } + + ret = config_cpuss_register(dev, p, cpudata->cpussregdata->core_reg_end_index, + cmd, register_offset, val); + if (ret) + goto err; + + if (cmd == 'r' && val == 4) + cpudata->cpussregdata->core_reg_end_index++; + else + cpudata->cpussregdata->core_reg_end_index += 2; + + cpudata->cpussregdata->core_reg_used_num++; + cpudata->cpussregdata->used_memory = used_memory; + } else { /* system register */ + system_reg_end_index = *(p + SYS_REG_INPUT_INDEX) + + cpudata->cpussregdata->sys_reg_size / sizeof(uint32_t); + + if (cmd == 'r' && reserve_size == 4) + extra_memory = sizeof(uint32_t) + reserve_size; + else + extra_memory = sizeof(uint32_t) * 2 + reserve_size; + + used_memory = cpudata->cpussregdata->used_memory + extra_memory; + if (extra_memory < reserve_size || + used_memory > cpudata->cpussregdata->size || + used_memory < cpudata->cpussregdata->used_memory) { + dev_err(dev, "Couldn't add system reg config, no enough memory\n"); + ret = -ENOMEM; + goto err; + } + + ret = config_cpuss_register(dev, p, system_reg_end_index, + cmd, register_offset, val); + if (ret) + goto err; + + if (cmd == 'r' && val == 4) { + system_reg_end_index++; + cpudata->cpussregdata->sys_reg_size += sizeof(uint32_t); + } else { + system_reg_end_index += 2; + cpudata->cpussregdata->sys_reg_size += sizeof(uint32_t) * 2; + } + + cpudata->cpussregdata->used_memory = used_memory; + *(p + system_reg_end_index) = 0x0; + *(p + OUTPUT_DUMP_INDEX) = (system_reg_end_index + 1) + * sizeof(uint32_t); + } + + ret = size; + +err: + mutex_unlock(&cpudata->mutex); + return ret; +} +static DEVICE_ATTR_RW(register_config); + +static ssize_t format_version_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret; + struct reg_dump_data *p; + struct cpuss_dump_data *cpudata = dev_get_drvdata(dev); + + if (!cpudata) + return -EFAULT; + + mutex_lock(&cpudata->mutex); + p = (struct reg_dump_data *)cpudata->cpussregdata->dump_vaddr; + ret = scnprintf(buf, PAGE_SIZE, "%u\n", p->version); + + mutex_unlock(&cpudata->mutex); + return ret; +} +static DEVICE_ATTR_RO(format_version); +/** + * This function resets the register dump table. + */ +static ssize_t register_reset_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + unsigned int val; + + if (kstrtouint(buf, 16, &val)) + return -EINVAL; + if (val != 1) + return -EINVAL; + + update_reg_dump_table(dev, CORE_REG_NUM_DEFAULT); + + return size; +} +static DEVICE_ATTR_WO(register_reset); + +/** + * This function shows configs of per-core spr dump. + */ +static ssize_t spr_config_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + char local_buf[64]; + int len = 0, count = 0; + struct cpuss_dump_data *cpudata = dev_get_drvdata(dev); + int i = 0, index = 0; + uint32_t *p; + + buf[0] = '\0'; + + if (!cpudata) + return -EFAULT; + + mutex_lock(&cpudata->mutex); + + len = scnprintf(local_buf, 64, "spr data list below:\n"); + strlcat(buf, local_buf, PAGE_SIZE); + count += len; + + for (i = 0; i < MAX_CORE_NUM; i++) { + if (count > PAGE_SIZE) { + dev_err(dev, "Couldn't write complete config\n"); + break; + } + if (!cpudata->sprdata[i]) { + dev_err(dev, "SPR data pinter for CPU%d is empty\n", i); + continue; + } + p = (uint32_t *)cpudata->sprdata[i]->dump_vaddr; + len = scnprintf(local_buf, 64, "spr data for CPU[%d] below:\n", i); + strlcat(buf, local_buf, PAGE_SIZE); + count += len; + index = 0; + while (index < cpudata->sprdata[i]->sprs_data_index) { + if (count > PAGE_SIZE) { + dev_err(dev, "Couldn't write complete config\n"); + break; + } + len = scnprintf(local_buf, 64, "%d\n", *(p + SPR_DATA_HEADER_SIZE + index)); + strlcat(buf, local_buf, PAGE_SIZE); + count += len; + index++; + } + } + + mutex_unlock(&cpudata->mutex); + return count; +} + +/** + * This function sets configs for sprs dump. + */ +static ssize_t spr_config_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + int ret = 0; + uint32_t spr_data, cpu_num; + uint32_t index; + int nval; + uint32_t *p; + u32 reserved = 0; + struct cpuss_dump_data *cpudata = dev_get_drvdata(dev); + + nval = sscanf(buf, "%d %d", &spr_data, &cpu_num); + if (nval != 2) + return -EINVAL; + if (!cpudata) + return -EFAULT; + + if (cpu_num >= MAX_CORE_NUM) { + dev_err(dev, "Input the wrong CPU number\n"); + return -EINVAL; + } + reserved = (SPR_INPUT_DATA_SIZE + SPR_OUTPUT_DATA_SIZE) * sizeof(uint32_t); + + mutex_lock(&cpudata->mutex); + if (cpudata->sprdata[cpu_num]) { + p = (uint32_t *)cpudata->sprdata[cpu_num]->dump_vaddr; + index = cpudata->sprdata[cpu_num]->sprs_data_index; + + if (cpudata->sprdata[cpu_num]->size > + cpudata->sprdata[cpu_num]->used_memory + reserved) { + p = (uint32_t *)cpudata->sprdata[cpu_num]->dump_vaddr; + *(p + OUTPUT_DUMP_INDEX) = (SPR_DATA_HEADER_SIZE + + index + SPR_INPUT_DATA_TAIL_SIZE + 1) * sizeof(uint32_t); + *(p + SPR_DATA_HEADER_SIZE + index) = spr_data; + *(p + SPR_DATA_HEADER_SIZE + index + 1) = 0; + cpudata->sprdata[cpu_num]->sprs_data_index++; + cpudata->sprdata[cpu_num]->used_memory = + cpudata->sprdata[cpu_num]->used_memory + reserved; + } else { + dev_err(dev, "Couldn't add SPR config, no enough memory\n"); + ret = -ENOMEM; + goto err; + } + } + ret = size; + +err: + mutex_unlock(&cpudata->mutex); + return ret; +} +static DEVICE_ATTR_RW(spr_config); + +/** + * This function resets the sprs dump table. + */ +static ssize_t sprs_register_reset_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + unsigned int val; + + if (kstrtouint(buf, 16, &val)) + return -EINVAL; + if (val != 1) + return -EINVAL; + + reset_sprs_dump_table(dev); + + return size; +} +static DEVICE_ATTR_WO(sprs_register_reset); + +static ssize_t sprs_format_version_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + char local_buf[64]; + int len = 0, count = 0, i = 0; + struct reg_dump_data *p; + struct cpuss_dump_data *cpudata = dev_get_drvdata(dev); + + buf[0] = '\0'; + + if (!cpudata) + return -EFAULT; + + mutex_lock(&cpudata->mutex); + + for (i = 0; i < MAX_CORE_NUM; i++) { + if (cpudata->sprdata[i]) { + p = (struct reg_dump_data *)cpudata->sprdata[i]->dump_vaddr; + len = scnprintf(local_buf, 64, + "SPR data format version for cpu%d is %d\n", i, p->version); + strlcat(buf, local_buf, PAGE_SIZE); + count += len; + } + } + + mutex_unlock(&cpudata->mutex); + return count; +} +static DEVICE_ATTR_RO(sprs_format_version); + + +static const struct device_attribute *register_dump_attrs[] = { + &dev_attr_core_reg_num, + &dev_attr_register_config, + &dev_attr_register_reset, + &dev_attr_format_version, + NULL, +}; + +static const struct device_attribute *spr_dump_attrs[] = { + &dev_attr_spr_config, + &dev_attr_sprs_register_reset, + &dev_attr_sprs_format_version, + NULL, +}; + +static int memory_dump_create_files(struct device *dev, + const struct device_attribute **attrs) +{ + int ret = 0; + int i, j; + + for (i = 0; attrs[i] != NULL; i++) { + ret = device_create_file(dev, attrs[i]); + if (ret) { + dev_err(dev, "Couldn't create sysfs attribute: %s\n", + attrs[i]->attr.name); + for (j = 0; j < i; j++) + device_remove_file(dev, attrs[j]); + break; + } + } + return ret; +} + +static void cpuss_create_nodes(struct platform_device *pdev, + int initialized) +{ + if (initialized & PERCORE_REG_INITIALIZED) { + if (memory_dump_create_files(&pdev->dev, register_dump_attrs)) + dev_err(&pdev->dev, "Fail to create files for cpuss register dump\n"); + } + if (initialized & SPRS_INITIALIZED) { + if (memory_dump_create_files(&pdev->dev, spr_dump_attrs)) + dev_err(&pdev->dev, "Fail to create files for spr dump\n"); + } +} + +uint32_t msm_dump_table_version(void) +{ + return MSM_DUMP_TABLE_VERSION; +} +EXPORT_SYMBOL_GPL(msm_dump_table_version); + +static int msm_dump_table_register(struct msm_dump_entry *entry) +{ + struct msm_dump_entry *e; + struct msm_dump_table *table = memdump.table; + + if (!table || table->num_entries >= MAX_NUM_ENTRIES) + return -EINVAL; + + e = &table->entries[table->num_entries]; + e->id = entry->id; + e->type = MSM_DUMP_TYPE_TABLE; + e->addr = entry->addr; + table->num_entries++; + + return 0; +} + +static struct msm_dump_table *msm_dump_get_table(enum msm_dump_table_ids id) +{ + struct msm_dump_table *table = memdump.table; + int i; + unsigned long offset; + + if (!table) { + pr_err("mem dump base table does not exist\n"); + return ERR_PTR(-EINVAL); + } + + for (i = 0; i < MAX_NUM_ENTRIES; i++) { + if (table->entries[i].id == id) + break; + } + if (i == MAX_NUM_ENTRIES || !table->entries[i].addr) { + pr_err("mem dump base table entry %d invalid\n", id); + return ERR_PTR(-EINVAL); + } + + offset = table->entries[i].addr - memdump.table_phys; + /* Get the apps table pointer */ + table = (void *)memdump.table + offset; + + return table; +} + +static int register_dump_table_entry(enum msm_dump_table_ids id, + struct msm_dump_entry *entry) +{ + struct msm_dump_entry *e; + struct msm_dump_table *table; + + table = msm_dump_get_table(id); + if (IS_ERR(table)) + return PTR_ERR(table); + + if (!table || table->num_entries >= MAX_NUM_ENTRIES) + return -EINVAL; + + e = &table->entries[table->num_entries]; + e->id = entry->id; + e->type = MSM_DUMP_TYPE_DATA; + e->addr = entry->addr; + table->num_entries++; + + return 0; +} + +/** + * msm_dump_data_register_nominidump - register to dump data framework + * @id: ID of the dump table. + * @entry: dump entry to be registered + * This api will register the entry passed to dump table only + */ +int msm_dump_data_register_nominidump(enum msm_dump_table_ids id, + struct msm_dump_entry *entry) +{ + return register_dump_table_entry(id, entry); +} +EXPORT_SYMBOL_GPL(msm_dump_data_register_nominidump); + +#define MSM_DUMP_TOTAL_SIZE_OFFSET 0x724 +static int init_memdump_imem_area(size_t size) +{ + struct device_node *np; + void __iomem *imem_base; + + np = of_find_compatible_node(NULL, NULL, + "qcom,msm-imem-mem-dump-table"); + if (!np) { + pr_err("mem dump base table DT node does not exist\n"); + return -ENODEV; + } + + imem_base = of_iomap(np, 0); + if (!imem_base) { + pr_err("mem dump base table imem offset mapping failed\n"); + return -ENOMEM; + } + + memcpy_toio(imem_base, &memdump.table_phys, + sizeof(memdump.table_phys)); + memcpy_toio(imem_base + MSM_DUMP_TOTAL_SIZE_OFFSET, + &size, sizeof(size_t)); + + /* Ensure write to imem_base is complete before unmapping */ + mb(); + pr_info("MSM Memory Dump base table set up in IMEM\n"); + + iounmap(imem_base); + return 0; +} + +static int init_memory_dump(void *dump_vaddr, phys_addr_t phys_addr) +{ + struct msm_dump_table *table; + struct msm_dump_entry entry; + int ret; + + memdump.table = dump_vaddr; + memdump.table->version = MSM_DUMP_TABLE_VERSION; + memdump.table_phys = phys_addr; + dump_vaddr += sizeof(*table); + phys_addr += sizeof(*table); + table = dump_vaddr; + table->version = MSM_DUMP_TABLE_VERSION; + entry.id = MSM_DUMP_TABLE_APPS; + entry.addr = phys_addr; + ret = msm_dump_table_register(&entry); + if (ret) { + pr_err("mem dump apps data table register failed\n"); + return ret; + } + pr_info("MSM Memory Dump apps data table set up\n"); + + return 0; +} + +static int mem_dump_reserve_mem(struct device *dev) +{ + struct device_node *mem_node; + int ret; + + mem_node = of_parse_phandle(dev->of_node, "memory-region", 0); + if (mem_node) { + ret = of_reserved_mem_device_init_by_idx(dev, + dev->of_node, 0); + of_node_put(dev->of_node); + if (ret) { + dev_err(dev, + "Failed to initialize reserved mem, ret %d\n", + ret); + return ret; + } + } + return 0; +} + +static int cpuss_regdump_init(struct device *dev, + void *dump_vaddr, u32 size) +{ + struct cpuss_dump_data *cpudata = dev_get_drvdata(dev); + + cpudata->cpussregdata = devm_kzalloc(dev, + sizeof(struct cpuss_regdump_data), GFP_KERNEL); + + if (cpudata->cpussregdata) { + cpudata->cpussregdata->dump_vaddr = dump_vaddr; + cpudata->cpussregdata->size = size; + return 0; + } + return -ENOMEM; +} + +static int sprs_dump_init(struct device *dev, + void *dump_vaddr, u32 size, u32 id) +{ + struct cpuss_dump_data *cpudata = dev_get_drvdata(dev); + int core_num = 0; + + core_num = id - SPR_DUMP_CPU0; + + cpudata->sprdata[core_num] = devm_kzalloc(dev, + sizeof(struct sprs_dump_data), GFP_KERNEL); + if (cpudata->sprdata[core_num]) { + cpudata->sprdata[core_num]->dump_vaddr = dump_vaddr; + cpudata->sprdata[core_num]->size = size; + return 0; + } + return -ENOMEM; +} + +static int cpuss_dump_init(struct platform_device *pdev, + void *dump_vaddr, u32 size, u32 id) +{ + struct cpuss_dump_data *cpudata = dev_get_drvdata(&pdev->dev); + static int initialized; + + if (!cpudata) { + cpudata = devm_kzalloc(&pdev->dev, + sizeof(struct cpuss_dump_data), GFP_KERNEL); + if (cpudata) { + mutex_init(&cpudata->mutex); + platform_set_drvdata(pdev, cpudata); + } else + return initialized; + } + + if (id == CPUSS_REGDUMP) { + if (!cpuss_regdump_init(&pdev->dev, dump_vaddr, size)) + initialized |= PERCORE_REG_INITIALIZED; + } else { + if (!sprs_dump_init(&pdev->dev, dump_vaddr, size, id)) + initialized |= SPRS_INITIALIZED; + } + + return initialized; +} + +#define MSM_DUMP_DATA_SIZE sizeof(struct msm_dump_data) +static int mem_dump_alloc(struct platform_device *pdev) +{ + struct device_node *child_node; + const struct device_node *node = pdev->dev.of_node; + struct msm_dump_data *dump_data; + struct msm_dump_entry dump_entry; + size_t total_size; + u32 size, id; + int ret, no_of_nodes; + dma_addr_t dma_handle; + phys_addr_t phys_addr; + struct sg_table mem_dump_sgt; + void *dump_vaddr; + u64 shm_bridge_handle; + int initialized = 0; + + if (mem_dump_reserve_mem(&pdev->dev) != 0) + return -ENOMEM; + total_size = size = ret = no_of_nodes = 0; + /* For dump table registration with IMEM */ + total_size = sizeof(struct msm_dump_table) * 2; + for_each_available_child_of_node(node, child_node) { + ret = of_property_read_u32(child_node, "qcom,dump-size", &size); + if (ret) { + dev_err(&pdev->dev, "Unable to find size for %s\n", + child_node->name); + continue; + } + + total_size += size; + no_of_nodes++; + } + + total_size += (MSM_DUMP_DATA_SIZE * no_of_nodes); + total_size = ALIGN(total_size, SZ_4K); + dump_vaddr = dmam_alloc_coherent(&pdev->dev, total_size, + &dma_handle, GFP_KERNEL); + if (!dump_vaddr) + return -ENOMEM; + + dma_get_sgtable(&pdev->dev, &mem_dump_sgt, dump_vaddr, + dma_handle, total_size); + phys_addr = page_to_phys(sg_page(mem_dump_sgt.sgl)); + sg_free_table(&mem_dump_sgt); + + memset(dump_vaddr, 0x0, total_size); + ret = qcom_tzmem_shm_bridge_create(phys_addr, total_size, &shm_bridge_handle); + if (ret) { + dev_err(&pdev->dev, "Failed to create shm bridge.ret=%d\n", ret); + return ret; + } + + ret = init_memory_dump(dump_vaddr, phys_addr); + if (ret) { + dev_err(&pdev->dev, "Memory Dump table set up is failed\n"); + qcom_tzmem_shm_bridge_delete(shm_bridge_handle); + return ret; + } + + ret = init_memdump_imem_area(total_size); + if (ret) { + qcom_tzmem_shm_bridge_delete(shm_bridge_handle); + return ret; + } + + dump_vaddr += (sizeof(struct msm_dump_table) * 2); + phys_addr += (sizeof(struct msm_dump_table) * 2); + for_each_available_child_of_node(node, child_node) { + ret = of_property_read_u32(child_node, "qcom,dump-size", &size); + if (ret) + continue; + + ret = of_property_read_u32(child_node, "qcom,dump-id", &id); + if (ret) { + dev_err(&pdev->dev, "Unable to find id for %s\n", + child_node->name); + continue; + } + + dump_data = dump_vaddr; + dump_data->addr = phys_addr + MSM_DUMP_DATA_SIZE; + dump_data->len = size; + dump_entry.id = id; + strscpy(dump_data->name, child_node->name, + sizeof(dump_data->name)); + dump_entry.addr = phys_addr; + ret = msm_dump_data_register_nominidump(MSM_DUMP_TABLE_APPS, + &dump_entry); + if (ret) + dev_err(&pdev->dev, "Data dump setup failed, id = %d\n", + id); + + if ((id == CPUSS_REGDUMP) || + ((id >= SPR_DUMP_CPU0) && (id <= SPR_DUMP_CPU7))) + initialized = cpuss_dump_init(pdev, + (dump_vaddr + MSM_DUMP_DATA_SIZE), size, id); + + dump_vaddr += (size + MSM_DUMP_DATA_SIZE); + phys_addr += (size + MSM_DUMP_DATA_SIZE); + } + + cpuss_create_nodes(pdev, initialized); + + if (initialized & SPRS_INITIALIZED) + reset_sprs_dump_table(&pdev->dev); + + return ret; +} + +static int mem_dump_probe(struct platform_device *pdev) +{ + int ret; + + ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); + if (ret < 0) + return ret; + + ret = mem_dump_alloc(pdev); + return ret; +} + +static const struct of_device_id mem_dump_match_table[] = { + {.compatible = "qcom,mem-dump",}, + {} +}; + +static struct platform_driver mem_dump_driver = { + .probe = mem_dump_probe, + .driver = { + .name = "msm_mem_dump", + .of_match_table = mem_dump_match_table, + }, +}; + +module_platform_driver(mem_dump_driver); + +MODULE_DESCRIPTION("Memory Dump V2 Driver"); +MODULE_LICENSE("GPL"); diff --git a/include/linux/firmware/qcom/memory_dump.h b/include/linux/firmware/qcom/memory_dump.h new file mode 100644 index 0000000000000..ebb7c89d2f243 --- /dev/null +++ b/include/linux/firmware/qcom/memory_dump.h @@ -0,0 +1,136 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2012, 2014-2017, 2019-2021, The Linux Foundation. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#ifndef __MSM_MEMORY_DUMP_H +#define __MSM_MEMORY_DUMP_H + +#include +#include + +enum dump_client_type { + MSM_CPU_CTXT = 0, + MSM_L1_CACHE, + MSM_L2_CACHE, + MSM_OCMEM, + MSM_TMC_ETFETB, + MSM_ETM0_REG, + MSM_ETM1_REG, + MSM_ETM2_REG, + MSM_ETM3_REG, + MSM_TMC0_REG, /* TMC_ETR */ + MSM_TMC1_REG, /* TMC_ETF */ + MSM_LOG_BUF, + MSM_LOG_BUF_FIRST_IDX, + MAX_NUM_CLIENTS, +}; + +struct msm_client_dump { + enum dump_client_type id; + unsigned long start_addr; + unsigned long end_addr; +}; + +#ifdef CONFIG_QCOM_MEMORY_DUMP +extern int msm_dump_tbl_register(struct msm_client_dump *client_entry); +#else +static inline int msm_dump_tbl_register(struct msm_client_dump *entry) +{ + return -EIO; +} +#endif + + +#if IS_ENABLED(CONFIG_QCOM_MEMORY_DUMP_V2) +extern uint32_t msm_dump_table_version(void); +#else +static inline uint32_t msm_dump_table_version(void) +{ + return 0; +} +#endif + +#define MSM_DUMP_MAKE_VERSION(ma, mi) ((ma << 20) | mi) +#define MSM_DUMP_MAJOR(val) (val >> 20) +#define MSM_DUMP_MINOR(val) (val & 0xFFFFF) + + +#define MAX_NUM_ENTRIES 0x150 + +enum msm_dump_data_ids { + MSM_DUMP_DATA_CPU_CTX = 0x00, + MSM_DUMP_DATA_L1_INST_CACHE = 0x60, + MSM_DUMP_DATA_L1_DATA_CACHE = 0x80, + MSM_DUMP_DATA_ETM_REG = 0xA0, + MSM_DUMP_DATA_L2_CACHE = 0xC0, + MSM_DUMP_DATA_L3_CACHE = 0xD0, + MSM_DUMP_DATA_OCMEM = 0xE0, + MSM_DUMP_DATA_CNSS_WLAN = 0xE1, + MSM_DUMP_DATA_WIGIG = 0xE2, + MSM_DUMP_DATA_PMIC = 0xE4, + MSM_DUMP_DATA_DBGUI_REG = 0xE5, + MSM_DUMP_DATA_DCC_REG = 0xE6, + MSM_DUMP_DATA_DCC_SRAM = 0xE7, + MSM_DUMP_DATA_MISC = 0xE8, + MSM_DUMP_DATA_VSENSE = 0xE9, + MSM_DUMP_DATA_RPM = 0xEA, + MSM_DUMP_DATA_SCANDUMP = 0xEB, + MSM_DUMP_DATA_RPMH = 0xEC, + MSM_DUMP_DATA_TMC_ETF = 0xF0, + MSM_DUMP_DATA_TMC_ETF_SWAO = 0xF1, + MSM_DUMP_DATA_TMC_REG = 0x100, + MSM_DUMP_DATA_TMC_ETF_SWAO_REG = 0x102, + MSM_DUMP_DATA_LOG_BUF = 0x110, + MSM_DUMP_DATA_LOG_BUF_FIRST_IDX = 0x111, + MSM_DUMP_DATA_SCANDUMP_PER_CPU = 0x130, + MSM_DUMP_DATA_LLCC_PER_INSTANCE = 0x140, + MSM_DUMP_DATA_MAX = MAX_NUM_ENTRIES, +}; + +enum msm_dump_table_ids { + MSM_DUMP_TABLE_APPS, + MSM_DUMP_TABLE_MAX = MAX_NUM_ENTRIES, +}; + +enum msm_dump_type { + MSM_DUMP_TYPE_DATA, + MSM_DUMP_TYPE_TABLE, +}; + +struct msm_dump_data { + uint32_t version; + uint32_t magic; + char name[32]; + uint64_t addr; + uint64_t len; + uint32_t reserved; +}; + +struct msm_dump_entry { + uint32_t id; + char name[32]; + uint32_t type; + uint64_t addr; +}; + +#if IS_ENABLED(CONFIG_QCOM_MEMORY_DUMP_V2) +extern int msm_dump_data_register(enum msm_dump_table_ids id, + struct msm_dump_entry *entry); +extern int msm_dump_data_register_nominidump(enum msm_dump_table_ids id, + struct msm_dump_entry *entry); +#else +static inline int msm_dump_data_register(enum msm_dump_table_ids id, + struct msm_dump_entry *entry) +{ + return -EINVAL; +} +static inline int msm_dump_data_register_nominidump(enum msm_dump_table_ids id, + struct msm_dump_entry *entry) +{ + return -EINVAL; +} +#endif + +#endif From 202126a7ee02476a215ebbc58afe3b2a5b260be8 Mon Sep 17 00:00:00 2001 From: Jie Gan Date: Mon, 12 Jan 2026 11:30:00 +0800 Subject: [PATCH 2272/2333] QCLINUX: mem-dump: add memory dump device driver Create memory dump device driver for matching the memory dump v2 driver without DT configuration. Signed-off-by: Jie Gan --- arch/arm64/configs/qcom_debug.config | 1 + drivers/firmware/qcom/Kconfig | 6 + drivers/firmware/qcom/Makefile | 1 + drivers/firmware/qcom/memory_dump_dev.c | 379 ++++++++++++++++++++++ drivers/firmware/qcom/memory_dump_v2.c | 67 ++-- include/linux/firmware/qcom/memory_dump.h | 13 + 6 files changed, 420 insertions(+), 47 deletions(-) create mode 100644 drivers/firmware/qcom/memory_dump_dev.c diff --git a/arch/arm64/configs/qcom_debug.config b/arch/arm64/configs/qcom_debug.config index 2e85e8df0469b..d50f78f3a3ea2 100644 --- a/arch/arm64/configs/qcom_debug.config +++ b/arch/arm64/configs/qcom_debug.config @@ -1,3 +1,4 @@ CONFIG_QCOM_DCC=m CONFIG_QCOM_DCC_DEV=m CONFIG_QCOM_MEMORY_DUMP_V2=m +CONFIG_QCOM_MEMORY_DUMP_DEV=m diff --git a/drivers/firmware/qcom/Kconfig b/drivers/firmware/qcom/Kconfig index 531c6d2598ce0..39f63ef92e01a 100644 --- a/drivers/firmware/qcom/Kconfig +++ b/drivers/firmware/qcom/Kconfig @@ -83,4 +83,10 @@ config QCOM_MEMORY_DUMP_V2 of deadlocks or cpu hangs these dump regions are captured to give a snapshot of the system at the time of the crash. +config QCOM_MEMORY_DUMP_DEV + tristate "QCOM Memory Dump V2 device stub" + depends on QCOM_MEMORY_DUMP_V2 + help + Device stub for memory dump V2 driver. + endmenu diff --git a/drivers/firmware/qcom/Makefile b/drivers/firmware/qcom/Makefile index c5e17ba255937..01b293cae79ed 100644 --- a/drivers/firmware/qcom/Makefile +++ b/drivers/firmware/qcom/Makefile @@ -9,3 +9,4 @@ obj-$(CONFIG_QCOM_TZMEM) += qcom_tzmem.o obj-$(CONFIG_QCOM_QSEECOM) += qcom_qseecom.o obj-$(CONFIG_QCOM_QSEECOM_UEFISECAPP) += qcom_qseecom_uefisecapp.o obj-$(CONFIG_QCOM_MEMORY_DUMP_V2) += memory_dump_v2.o +obj-$(CONFIG_QCOM_MEMORY_DUMP_DEV) += memory_dump_dev.o diff --git a/drivers/firmware/qcom/memory_dump_dev.c b/drivers/firmware/qcom/memory_dump_dev.c new file mode 100644 index 0000000000000..556ebafae5280 --- /dev/null +++ b/drivers/firmware/qcom/memory_dump_dev.c @@ -0,0 +1,379 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#include +#include +#include +#include +#include + +#define DEV_NAME "msm_mem_dump" + +static struct platform_device *mem_dump_pdev; + +enum dump_ids { + C0_CONTEXT = 0x0, + C100_CONTEXT = 0x1, + C200_CONTEXT = 0x2, + C300_CONTEXT = 0x3, + C400_CONTEXT = 0x4, + C500_CONTEXT = 0x5, + C600_CONTEXT = 0x6, + C700_CONTEXT = 0x7, + L1_ITLB10000 = 0x24, + L1_ITLB10100 = 0x25, + L1_ITLB10200 = 0x26, + L1_ITLB10300 = 0x27, + L1_DTLB10000 = 0x44, + L1_DTLB10100 = 0x45, + L1_DTLB10200 = 0x46, + L1_DTLB10300 = 0x47, + L1_ICACHE0 = 0x60, + L1_ICACHE100 = 0x61, + L1_ICACHE200 = 0x62, + L1_ICACHE300 = 0x63, + L1_ICACHE10000 = 0x64, + L1_ICACHE10100 = 0x65, + L1_ICACHE10200 = 0x66, + L1_ICACHE10300 = 0x67, + L1_DCACHE0 = 0x80, + L1_DCACHE100 = 0x81, + L1_DCACHE200 = 0x82, + L1_DCACHE300 = 0x83, + L1_DCACHE10000 = 0x84, + L1_DCACHE10100 = 0x85, + L1_DCACHE10200 = 0x86, + L1_DCACHE10300 = 0x87, + L2_CACHE10000 = 0xc4, + L2_CACHE10100 = 0xc5, + L2_CACHE10200 = 0xc6, + L2_CACHE10300 = 0xc7, + PMIC = 0xe4, + MISC_DATA = 0xe8, + RPM_SW = 0xea, + RPMH = 0xec, + CPUSS_REG = 0xef, + TMC_ETF = 0xf0, + ETF_SWAO = 0xf1, + ETF_LPASS = 0xf4, + FCM = 0xee, + ETR_REG = 0x100, + ETF_REG = 0x101, + ETFSWAO_REG = 0x102, + ETFLPASS_REG = 0x104, + L2_TLB0 = 0x120, + L2_TLB100 = 0x121, + L2_TLB200 = 0x122, + L2_TLB300 = 0x123, + L2_TLB10000 = 0x124, + L2_TLB10100 = 0x125, + L2_TLB10200 = 0x126, + L2_TLB10300 = 0x127, + C0_SCANDUMP = 0x130, + C100_SCANDUMP = 0x131, + C200_SCANDUMP = 0x132, + C300_SCANDUMP = 0x133, + C10000_SCANDUMP = 0x134, + C10100_SCANDUMP = 0x135, + C10200_SCANDUMP = 0x136, + C10300_SCANDUMP = 0x137, + LLCC1_D_CACHE = 0x140, + LLCC2_D_CACHE = 0x141, + MHM_SCAN = 0x161, + GEMNOC = 0x162, + OSM_REG = 0x163, + PCU_REG = 0x164, + FSM_DATA = 0x165, +}; + +static const struct dump_item lemans_items[] = { + { C0_CONTEXT, 0x800, "c0-context" }, + { C0_SCANDUMP, 0x40000, "c0-scandump" }, + { C100_CONTEXT, 0x800, "c100-context" }, + { C100_SCANDUMP, 0x40000, "c100-scandump" }, + { C200_CONTEXT, 0x800, "c200-context" }, + { C200_SCANDUMP, 0x40000, "c200-scandump" }, + { C300_CONTEXT, 0x800, "c300-context" }, + { C300_SCANDUMP, 0x40000, "c300-scandump" }, + { C400_CONTEXT, 0x800, "c400-context" }, + { C500_CONTEXT, 0x800, "c500-context" }, + { C600_CONTEXT, 0x800, "c600-context" }, + { C700_CONTEXT, 0x800, "c700-context" }, + { C10000_SCANDUMP, 0x40000, "c10000-scandump" }, + { C10100_SCANDUMP, 0x40000, "c10100-scandump" }, + { C10200_SCANDUMP, 0x40000, "c10200-scandump" }, + { C10300_SCANDUMP, 0x40000, "c10300-scandump" }, + { CPUSS_REG, 0x20000, "cpuss-reg" }, + { ETF_SWAO, 0x10000, "etf-swao" }, + { ETFSWAO_REG, 0x1000, "etfswao-reg" }, + { ETR_REG, 0x1000, "etr-reg" }, + { FCM, 0x8400, "fcm" }, + { L1_DCACHE0, 0x12100, "l1-dcache0" }, + { L1_DCACHE100, 0x12100, "l1-dcache100" }, + { L1_DCACHE200, 0x12100, "l1-dcache200" }, + { L1_DCACHE300, 0x12100, "l1-dcache300" }, + { L1_DCACHE10000, 0x12100, "l1-dcache10000" }, + { L1_DCACHE10100, 0x12100, "l1-dcache10100" }, + { L1_DCACHE10200, 0x12100, "l1-dcache10200" }, + { L1_DCACHE10300, 0x12100, "l1-dcache10300" }, + { L1_DTLB10000, 0x300, "l1-dtlb10000" }, + { L1_DTLB10100, 0x300, "l1-dtlb10100" }, + { L1_DTLB10200, 0x300, "l1-dtlb10200" }, + { L1_DTLB10300, 0x300, "l1-dtlb10300" }, + { L1_ICACHE0, 0x26100, "l1-icache0" }, + { L1_ICACHE100, 0x26100, "l1-icache100" }, + { L1_ICACHE200, 0x26100, "l1-icache200" }, + { L1_ICACHE300, 0x26100, "l1-icache300" }, + { L1_ICACHE10000, 0x26100, "l1-icache10000" }, + { L1_ICACHE10100, 0x26100, "l1-icache10100" }, + { L1_ICACHE10200, 0x26100, "l1-icache10200" }, + { L1_ICACHE10300, 0x26100, "l1-icache10300" }, + { L1_ITLB10000, 0x300, "l1-itlb10000" }, + { L1_ITLB10100, 0x300, "l1-itlb10100" }, + { L1_ITLB10200, 0x300, "l1-itlb10200" }, + { L1_ITLB10300, 0x300, "l1-itlb10300" }, + { L2_CACHE10000, 0x90100, "l2-cache10000" }, + { L2_CACHE10100, 0x90100, "l2-cache10100" }, + { L2_CACHE10200, 0x90100, "l2-cache10200" }, + { L2_CACHE10300, 0x90100, "l2-cache10300" }, + { L2_TLB0, 0x6100, "l2-tlb0" }, + { L2_TLB100, 0x6100, "l2-tlb100" }, + { L2_TLB200, 0x6100, "l2-tlb200" }, + { L2_TLB300, 0x6100, "l2-tlb300" }, + { L2_TLB10000, 0x6100, "l2-tlb10000" }, + { L2_TLB10100, 0x6100, "l2-tlb10100" }, + { L2_TLB10200, 0x6100, "l2-tlb10200" }, + { L2_TLB10300, 0x6100, "l2-tlb10300" }, + { MISC_DATA, 0x1000, "misc-data" }, + { PMIC, 0x80000, "pmic" }, + { RPM_SW, 0x28000, "rpm-sw" }, + { RPMH, 0x2000000, "rpmh" }, +}; + +static const struct dump_item talos_items[] = { + { C0_CONTEXT, 0x800, "c0-context" }, + { C100_CONTEXT, 0x800, "c100-context" }, + { C200_CONTEXT, 0x800, "c200-context" }, + { C300_CONTEXT, 0x800, "c300-context" }, + { C400_CONTEXT, 0x800, "c400-context" }, + { C500_CONTEXT, 0x800, "c500-context" }, + { C600_CONTEXT, 0x800, "c600-context" }, + { C700_CONTEXT, 0x800, "c700-context" }, + { RPMH, 0x2000000, "rpmh" }, + { RPM_SW, 0x28000, "rpm-sw" }, + { PMIC, 0x10000, "pmic" }, + { FCM, 0x8400, "fcm" }, + { TMC_ETF, 0x8000, "tmc-etf" }, + { ETF_SWAO, 0x8000, "etf-swao" }, + { ETR_REG, 0x1000, "etr-reg" }, + { ETF_REG, 0x1000, "etf-reg" }, + { ETFSWAO_REG, 0x1000, "etfswao-reg" }, + { MISC_DATA, 0x1000, "misc-data" }, + { L1_ICACHE0, 0x8800, "l1-icache0" }, + { L1_ICACHE100, 0x8800, "l1-icache100" }, + { L1_ICACHE200, 0x8800, "l1-icache200" }, + { L1_ICACHE300, 0x8800, "l1-icache300" }, + { L1_ICACHE10000, 0x8800, "l1-icache400" }, + { L1_ICACHE10100, 0x8800, "l1-icache500" }, + { L1_ICACHE10200, 0x11000, "l1-icache600" }, + { L1_ICACHE10300, 0x11000, "l1-icache700" }, + { L1_DCACHE0, 0x9000, "l1-dcache0" }, + { L1_DCACHE100, 0x9000, "l1-dcache100" }, + { L1_DCACHE200, 0x9000, "l1-dcache200" }, + { L1_DCACHE300, 0x9000, "l1-dcache300" }, + { L1_DCACHE10000, 0x9000, "l1-dcache400" }, + { L1_DCACHE10100, 0x9000, "l1-dcache500" }, + { L1_DCACHE10200, 0x12000, "l1-dcache600" }, + { L1_DCACHE10300, 0x12000, "l1-dcache700" }, + { L1_ITLB10200, 0x300, "l1-itlb600" }, + { L1_ITLB10300, 0x300, "l1-itlb700" }, + { L1_DTLB10200, 0x480, "l1-dtlb600" }, + { L1_DTLB10300, 0x480, "l1-dtlb700" }, + { L2_CACHE10200, 0x48000, "l2-cache600" }, + { L2_CACHE10300, 0x48000, "l2-cache700" }, + { L2_TLB0, 0x5000, "l2-tlb0" }, + { L2_TLB100, 0x5000, "l2-tlb100" }, + { L2_TLB200, 0x5000, "l2-tlb200" }, + { L2_TLB300, 0x5000, "l2-tlb300" }, + { L2_TLB10000, 0x5000, "l2-tlb400" }, + { L2_TLB10100, 0x5000, "l2-tlb500" }, + { L2_TLB10200, 0x7800, "l2-tlb600" }, + { L2_TLB10300, 0x7800, "l2-tlb700" }, + { LLCC1_D_CACHE, 0x6c000, "llcc1-d-cache" }, +}; + +static const struct dump_item kodiak_items[] = { + { C0_CONTEXT, 0x800, "c0-context" }, + { C0_SCANDUMP, 0x10100, "c0-scandump" }, + { C100_CONTEXT, 0x800, "c100-context" }, + { C100_SCANDUMP, 0x10100, "c100-scandump" }, + { C200_CONTEXT, 0x800, "c200-context" }, + { C200_SCANDUMP, 0x10100, "c200-scandump" }, + { C300_CONTEXT, 0x800, "c300-context" }, + { C300_SCANDUMP, 0x10100, "c300-scandump" }, + { C400_CONTEXT, 0x800, "c400-context" }, + { C10000_SCANDUMP, 0x40000, "c400-scandump" }, + { C500_CONTEXT, 0x800, "c500-context" }, + { C10100_SCANDUMP, 0x40000, "c500-scandump" }, + { C600_CONTEXT, 0x800, "c600-context" }, + { C10200_SCANDUMP, 0x40000, "c600-scandump" }, + { C700_CONTEXT, 0x800, "c700-context" }, + { C10300_SCANDUMP, 0x40000, "c700-scandump" }, + { CPUSS_REG, 0x30000, "cpuss-reg" }, + { ETF_LPASS, 0x4000, "etf-lpass" }, + { ETFLPASS_REG, 0x1000, "etflpass-reg" }, + { ETF_SWAO, 0x10000, "etf-swao" }, + { ETFSWAO_REG, 0x1000, "etfswao-reg" }, + { ETR_REG, 0x1000, "etr-reg" }, + { FCM, 0x8400, "fcm" }, + { FSM_DATA, 0x400, "fsm-data" }, + { GEMNOC, 0x100000, "gemnoc" }, + { L1_DCACHE0, 0x9100, "l1-dcache0" }, + { L1_DCACHE100, 0x9100, "l1-dcache100" }, + { L1_DCACHE200, 0x9100, "l1-dcache200" }, + { L1_DCACHE300, 0x9100, "l1-dcache300" }, + { L1_DCACHE10000, 0x9100, "l1-dcache400" }, + { L1_DCACHE10100, 0x9100, "l1-dcache500" }, + { L1_DCACHE10200, 0x9100, "l1-dcache600" }, + { L1_DCACHE10300, 0x12100, "l1-dcache700" }, + { L1_DTLB10000, 0x300, "l1-dtlb400" }, + { L1_DTLB10100, 0x300, "l1-dtlb500" }, + { L1_DTLB10200, 0x300, "l1-dtlb600" }, + { L1_DTLB10300, 0x3a0, "l1-dtlb700" }, + { L1_ICACHE0, 0x10900, "l1-icache0" }, + { L1_ICACHE100, 0x10900, "l1-icache100" }, + { L1_ICACHE200, 0x10900, "l1-icache200" }, + { L1_ICACHE300, 0x10900, "l1-icache300" }, + { L1_ICACHE10000, 0x15100, "l1-icache400" }, + { L1_ICACHE10100, 0x15100, "l1-icache500" }, + { L1_ICACHE10200, 0x15100, "l1-icache600" }, + { L1_ICACHE10300, 0x32100, "l1-icache700" }, + { L1_ITLB10000, 0x300, "l1-itlb400" }, + { L1_ITLB10100, 0x300, "l1-itlb500" }, + { L1_ITLB10200, 0x300, "l1-itlb600" }, + { L1_ITLB10300, 0x400, "l1-itlb700" }, + { L2_CACHE10000, 0x90100, "l2-cache400" }, + { L2_CACHE10100, 0x90100, "l2-cache500" }, + { L2_CACHE10200, 0x90100, "l2-cache600" }, + { L2_CACHE10300, 0x120100, "l2-cache700" }, + { L2_TLB0, 0x5b00, "l2-tlb0" }, + { L2_TLB100, 0x5b00, "l2-tlb100" }, + { L2_TLB200, 0x5b00, "l2-tlb200" }, + { L2_TLB300, 0x5b00, "l2-tlb300" }, + { L2_TLB10000, 0x6100, "l2-tlb400" }, + { L2_TLB10100, 0x6100, "l2-tlb500" }, + { L2_TLB10200, 0x6100, "l2-tlb600" }, + { L2_TLB10300, 0xc100, "l2-tlb700" }, + { LLCC1_D_CACHE, 0x1141c0, "llcc1-d-cache" }, + { LLCC2_D_CACHE, 0x1141c0, "llcc2-d-cache" }, + { MHM_SCAN, 0x20000, "mhm-scan" }, + { MISC_DATA, 0x1000, "misc-data" }, + { OSM_REG, 0x400, "osm-reg" }, + { PCU_REG, 0x400, "pcu-reg" }, + { PMIC, 0x200000, "pmic" }, + { RPM_SW, 0x28000, "rpm-sw" }, + { RPMH, 0x2000000, "rpmh" }, +}; + +static const struct dump_table lemans_dump_table = { + .items = lemans_items, + .num_of_items = ARRAY_SIZE(lemans_items), + .imem_base = 0x146d8010, + .imem_size = 0x8, +}; + +static const struct dump_table talos_dump_table = { + .items = talos_items, + .num_of_items = ARRAY_SIZE(lemans_items), + .imem_base = 0x146aa010, + .imem_size = 0x8, +}; + +static const struct dump_table kodiak_dump_table = { + .items = kodiak_items, + .num_of_items = ARRAY_SIZE(kodiak_items), + .imem_base = 0x146aa010, + .imem_size = 0x8, +}; + +static int __init mem_dump_dev_init(void) +{ + int ret; + u32 soc_id; + + mem_dump_pdev = platform_device_alloc(DEV_NAME, -1); + if (!mem_dump_pdev) + return -ENOMEM; + + ret = qcom_smem_get_soc_id(&soc_id); + if (ret) + goto fail; + + switch (soc_id) { + case 377: + case 380: + case 384: + case 401: + case 406: + case 680: + ret = platform_device_add_data(mem_dump_pdev, + &talos_dump_table, sizeof(talos_dump_table)); + if (ret) + goto fail; + + break; + case 534: + case 606: + case 667: + case 674: + case 675: + case 676: + ret = platform_device_add_data(mem_dump_pdev, + &lemans_dump_table, sizeof(lemans_dump_table)); + if (ret) + goto fail; + + break; + case 475: + case 497: + case 498: + case 515: + ret = platform_device_add_data(mem_dump_pdev, + &kodiak_dump_table, sizeof(kodiak_dump_table)); + if (ret) + goto fail; + + break; + default: + dev_err(&mem_dump_pdev->dev, "Invalid SoC ID\n"); + ret = -EINVAL; + goto fail; + } + + ret = platform_device_add(mem_dump_pdev); + if (ret) + goto fail; + + dev_info(&mem_dump_pdev->dev, "Register platform device successfully\n"); + + return 0; + +fail: + dev_err(&mem_dump_pdev->dev, + "Failed to register memory dump platform device\n"); + platform_device_put(mem_dump_pdev); + + return ret; +} + +static void __exit mem_dump_dev_exit(void) +{ + platform_device_unregister(mem_dump_pdev); +} + +module_init(mem_dump_dev_init); +module_exit(mem_dump_dev_exit); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Qualcomm Technologies Inc. Memory Dump driver V2, device stub"); diff --git a/drivers/firmware/qcom/memory_dump_v2.c b/drivers/firmware/qcom/memory_dump_v2.c index baf4c980f39fb..470d6047ee656 100644 --- a/drivers/firmware/qcom/memory_dump_v2.c +++ b/drivers/firmware/qcom/memory_dump_v2.c @@ -865,19 +865,11 @@ int msm_dump_data_register_nominidump(enum msm_dump_table_ids id, EXPORT_SYMBOL_GPL(msm_dump_data_register_nominidump); #define MSM_DUMP_TOTAL_SIZE_OFFSET 0x724 -static int init_memdump_imem_area(size_t size) +static int init_memdump_imem_area(const struct dump_table *table, size_t size) { - struct device_node *np; void __iomem *imem_base; - np = of_find_compatible_node(NULL, NULL, - "qcom,msm-imem-mem-dump-table"); - if (!np) { - pr_err("mem dump base table DT node does not exist\n"); - return -ENODEV; - } - - imem_base = of_iomap(np, 0); + imem_base = ioremap(table->imem_base, table->imem_size); if (!imem_base) { pr_err("mem dump base table imem offset mapping failed\n"); return -ENOMEM; @@ -924,13 +916,17 @@ static int init_memory_dump(void *dump_vaddr, phys_addr_t phys_addr) static int mem_dump_reserve_mem(struct device *dev) { struct device_node *mem_node; + struct reserved_mem *rmem; int ret; - mem_node = of_parse_phandle(dev->of_node, "memory-region", 0); + mem_node = of_find_node_by_path("/reserved-memory/mem-dump-region"); if (mem_node) { - ret = of_reserved_mem_device_init_by_idx(dev, - dev->of_node, 0); - of_node_put(dev->of_node); + rmem = of_reserved_mem_lookup(mem_node); + of_node_put(mem_node); + if (!rmem || !rmem->ops || !rmem->ops->device_init) + return -EINVAL; + + ret = rmem->ops->device_init(rmem, dev); if (ret) { dev_err(dev, "Failed to initialize reserved mem, ret %d\n", @@ -1005,34 +1001,26 @@ static int cpuss_dump_init(struct platform_device *pdev, #define MSM_DUMP_DATA_SIZE sizeof(struct msm_dump_data) static int mem_dump_alloc(struct platform_device *pdev) { - struct device_node *child_node; - const struct device_node *node = pdev->dev.of_node; struct msm_dump_data *dump_data; struct msm_dump_entry dump_entry; size_t total_size; u32 size, id; - int ret, no_of_nodes; + int i, ret, no_of_nodes; dma_addr_t dma_handle; phys_addr_t phys_addr; struct sg_table mem_dump_sgt; void *dump_vaddr; u64 shm_bridge_handle; int initialized = 0; + const struct dump_table *table = dev_get_platdata(&pdev->dev); if (mem_dump_reserve_mem(&pdev->dev) != 0) return -ENOMEM; total_size = size = ret = no_of_nodes = 0; /* For dump table registration with IMEM */ total_size = sizeof(struct msm_dump_table) * 2; - for_each_available_child_of_node(node, child_node) { - ret = of_property_read_u32(child_node, "qcom,dump-size", &size); - if (ret) { - dev_err(&pdev->dev, "Unable to find size for %s\n", - child_node->name); - continue; - } - - total_size += size; + for (i = 0; i < table->num_of_items; i++) { + total_size += table->items[i].size; no_of_nodes++; } @@ -1062,7 +1050,7 @@ static int mem_dump_alloc(struct platform_device *pdev) return ret; } - ret = init_memdump_imem_area(total_size); + ret = init_memdump_imem_area(table, total_size); if (ret) { qcom_tzmem_shm_bridge_delete(shm_bridge_handle); return ret; @@ -1070,24 +1058,15 @@ static int mem_dump_alloc(struct platform_device *pdev) dump_vaddr += (sizeof(struct msm_dump_table) * 2); phys_addr += (sizeof(struct msm_dump_table) * 2); - for_each_available_child_of_node(node, child_node) { - ret = of_property_read_u32(child_node, "qcom,dump-size", &size); - if (ret) - continue; - - ret = of_property_read_u32(child_node, "qcom,dump-id", &id); - if (ret) { - dev_err(&pdev->dev, "Unable to find id for %s\n", - child_node->name); - continue; - } - + for (i = 0; i < table->num_of_items; i++) { + size = table->items[i].size; + id = table->items[i].dump_id; dump_data = dump_vaddr; dump_data->addr = phys_addr + MSM_DUMP_DATA_SIZE; dump_data->len = size; dump_entry.id = id; - strscpy(dump_data->name, child_node->name, - sizeof(dump_data->name)); + strscpy(dump_data->name, table->items[i].name, + sizeof(table->items[i].name)); dump_entry.addr = phys_addr; ret = msm_dump_data_register_nominidump(MSM_DUMP_TABLE_APPS, &dump_entry); @@ -1124,16 +1103,10 @@ static int mem_dump_probe(struct platform_device *pdev) return ret; } -static const struct of_device_id mem_dump_match_table[] = { - {.compatible = "qcom,mem-dump",}, - {} -}; - static struct platform_driver mem_dump_driver = { .probe = mem_dump_probe, .driver = { .name = "msm_mem_dump", - .of_match_table = mem_dump_match_table, }, }; diff --git a/include/linux/firmware/qcom/memory_dump.h b/include/linux/firmware/qcom/memory_dump.h index ebb7c89d2f243..e72436feb0544 100644 --- a/include/linux/firmware/qcom/memory_dump.h +++ b/include/linux/firmware/qcom/memory_dump.h @@ -115,6 +115,19 @@ struct msm_dump_entry { uint64_t addr; }; +struct dump_item { + u32 dump_id; + size_t size; + const char *name; +}; + +struct dump_table { + const struct dump_item *items; + u32 num_of_items; + phys_addr_t imem_base; + resource_size_t imem_size; +}; + #if IS_ENABLED(CONFIG_QCOM_MEMORY_DUMP_V2) extern int msm_dump_data_register(enum msm_dump_table_ids id, struct msm_dump_entry *entry); From bfdf95cd42cd00ca67de337ae2c88fcec4bd1b5c Mon Sep 17 00:00:00 2001 From: Jie Gan Date: Mon, 2 Feb 2026 18:16:25 +0800 Subject: [PATCH 2273/2333] QCLINUX: memory-dump: add logic for reserving CMA memory Memory dump driver needs a large CMA memory zone for storing memory dump table. Add codes for reserving CMA memory during the init stage. Signed-off-by: Jie Gan --- arch/arm64/configs/qcom_debug.config | 2 +- arch/arm64/mm/init.c | 4 ++ drivers/firmware/qcom/Kconfig | 1 + drivers/firmware/qcom/memory_dump_v2.c | 58 +++++++++-------------- include/linux/firmware/qcom/memory_dump.h | 4 +- 5 files changed, 31 insertions(+), 38 deletions(-) diff --git a/arch/arm64/configs/qcom_debug.config b/arch/arm64/configs/qcom_debug.config index d50f78f3a3ea2..48ae2fb9737ac 100644 --- a/arch/arm64/configs/qcom_debug.config +++ b/arch/arm64/configs/qcom_debug.config @@ -1,4 +1,4 @@ CONFIG_QCOM_DCC=m CONFIG_QCOM_DCC_DEV=m -CONFIG_QCOM_MEMORY_DUMP_V2=m +CONFIG_QCOM_MEMORY_DUMP_V2=y CONFIG_QCOM_MEMORY_DUMP_DEV=m diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c index 524d34a0e9219..c1742eb63ddde 100644 --- a/arch/arm64/mm/init.c +++ b/arch/arm64/mm/init.c @@ -48,6 +48,7 @@ #include #include #include +#include /* * We need to be able to catch inadvertent references to memstart_addr @@ -331,6 +332,9 @@ void __init bootmem_init(void) * reserved, so do it here. */ arch_reserve_crashkernel(); +#if defined(CONFIG_QCOM_MEMORY_DUMP_V2) + reserve_memdump_cma(); +#endif memblock_dump_all(); } diff --git a/drivers/firmware/qcom/Kconfig b/drivers/firmware/qcom/Kconfig index 39f63ef92e01a..dd20fed163e3f 100644 --- a/drivers/firmware/qcom/Kconfig +++ b/drivers/firmware/qcom/Kconfig @@ -77,6 +77,7 @@ config QCOM_QSEECOM_UEFISECAPP config QCOM_MEMORY_DUMP_V2 tristate "QCOM Memory Dump V2 Support" depends on QCOM_TZMEM + depends on CMA help This enables memory dump feature. It allows various client subsystems to register respective dump regions. At the time diff --git a/drivers/firmware/qcom/memory_dump_v2.c b/drivers/firmware/qcom/memory_dump_v2.c index 470d6047ee656..831d1aea86e09 100644 --- a/drivers/firmware/qcom/memory_dump_v2.c +++ b/drivers/firmware/qcom/memory_dump_v2.c @@ -18,6 +18,10 @@ #include #include #include +#include +#include +#include +#include #define MSM_DUMP_TABLE_VERSION MSM_DUMP_MAKE_VERSION(2, 0) @@ -913,30 +917,6 @@ static int init_memory_dump(void *dump_vaddr, phys_addr_t phys_addr) return 0; } -static int mem_dump_reserve_mem(struct device *dev) -{ - struct device_node *mem_node; - struct reserved_mem *rmem; - int ret; - - mem_node = of_find_node_by_path("/reserved-memory/mem-dump-region"); - if (mem_node) { - rmem = of_reserved_mem_lookup(mem_node); - of_node_put(mem_node); - if (!rmem || !rmem->ops || !rmem->ops->device_init) - return -EINVAL; - - ret = rmem->ops->device_init(rmem, dev); - if (ret) { - dev_err(dev, - "Failed to initialize reserved mem, ret %d\n", - ret); - return ret; - } - } - return 0; -} - static int cpuss_regdump_init(struct device *dev, void *dump_vaddr, u32 size) { @@ -998,6 +978,18 @@ static int cpuss_dump_init(struct platform_device *pdev, return initialized; } +struct cma *memdump_cma; +void __init reserve_memdump_cma(void) +{ + unsigned long long cma_size = 0x3000000; + unsigned long long request_size = roundup(cma_size, PAGE_SIZE); + + if (cma_declare_contiguous(0, request_size, 0, 0, 0, false, + "memdump", &memdump_cma)) { + pr_warn("memdump CMA reservation failed\n"); + } +} + #define MSM_DUMP_DATA_SIZE sizeof(struct msm_dump_data) static int mem_dump_alloc(struct platform_device *pdev) { @@ -1006,16 +998,13 @@ static int mem_dump_alloc(struct platform_device *pdev) size_t total_size; u32 size, id; int i, ret, no_of_nodes; - dma_addr_t dma_handle; phys_addr_t phys_addr; - struct sg_table mem_dump_sgt; void *dump_vaddr; u64 shm_bridge_handle; int initialized = 0; const struct dump_table *table = dev_get_platdata(&pdev->dev); + struct page *reserved_page; - if (mem_dump_reserve_mem(&pdev->dev) != 0) - return -ENOMEM; total_size = size = ret = no_of_nodes = 0; /* For dump table registration with IMEM */ total_size = sizeof(struct msm_dump_table) * 2; @@ -1026,15 +1015,12 @@ static int mem_dump_alloc(struct platform_device *pdev) total_size += (MSM_DUMP_DATA_SIZE * no_of_nodes); total_size = ALIGN(total_size, SZ_4K); - dump_vaddr = dmam_alloc_coherent(&pdev->dev, total_size, - &dma_handle, GFP_KERNEL); - if (!dump_vaddr) + reserved_page = cma_alloc(memdump_cma, total_size >> PAGE_SHIFT, + 0, false); + if (!reserved_page) return -ENOMEM; - - dma_get_sgtable(&pdev->dev, &mem_dump_sgt, dump_vaddr, - dma_handle, total_size); - phys_addr = page_to_phys(sg_page(mem_dump_sgt.sgl)); - sg_free_table(&mem_dump_sgt); + phys_addr = page_to_phys(reserved_page); + dump_vaddr = page_to_virt(reserved_page); memset(dump_vaddr, 0x0, total_size); ret = qcom_tzmem_shm_bridge_create(phys_addr, total_size, &shm_bridge_handle); diff --git a/include/linux/firmware/qcom/memory_dump.h b/include/linux/firmware/qcom/memory_dump.h index e72436feb0544..ead7add4265c5 100644 --- a/include/linux/firmware/qcom/memory_dump.h +++ b/include/linux/firmware/qcom/memory_dump.h @@ -33,6 +33,9 @@ struct msm_client_dump { unsigned long end_addr; }; +void __init reserve_memdump_cma(void); +extern struct cma *memdump_cma; + #ifdef CONFIG_QCOM_MEMORY_DUMP extern int msm_dump_tbl_register(struct msm_client_dump *client_entry); #else @@ -42,7 +45,6 @@ static inline int msm_dump_tbl_register(struct msm_client_dump *entry) } #endif - #if IS_ENABLED(CONFIG_QCOM_MEMORY_DUMP_V2) extern uint32_t msm_dump_table_version(void); #else From b76f4a832d5a0e21e69882688305c77c5a9c944c Mon Sep 17 00:00:00 2001 From: Jie Gan Date: Mon, 9 Feb 2026 13:44:34 +0800 Subject: [PATCH 2274/2333] QCLINUX: qcom-dcc: add device configuration for Pakala Add device configuration to enable DCC on Pakala platform. Signed-off-by: Jie Gan --- drivers/misc/qcom-dcc-dev.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/drivers/misc/qcom-dcc-dev.c b/drivers/misc/qcom-dcc-dev.c index e0eb2e61d652b..0c2369a4843ae 100644 --- a/drivers/misc/qcom-dcc-dev.c +++ b/drivers/misc/qcom-dcc-dev.c @@ -39,6 +39,15 @@ static const struct dcc_pdata kodiak_pdata = { .map_ver = 0x2, }; +static const struct dcc_pdata pakala_pdata = { + .base = 0x100ff000, + .size = 0x00001000, + .ram_base = 0x10084000, + .ram_size = 0x4000, + .dcc_offset = 0x4000, + .map_ver = 0x3, +}; + static int __init dcc_dev_init(void) { int ret; @@ -83,6 +92,15 @@ static int __init dcc_dev_init(void) if (ret) goto fail; + break; + case 618: + case 639: + case 705: + case 706: + ret = platform_device_add_data(dcc_pdev, &pakala_pdata, sizeof(pakala_pdata)); + if (ret) + goto fail; + break; default: pr_err("DCC: Invalid SoC ID\n"); From a1c6cc59d499c3af497691cad124b53066069b41 Mon Sep 17 00:00:00 2001 From: Jie Gan Date: Mon, 9 Feb 2026 14:10:29 +0800 Subject: [PATCH 2275/2333] QCLINUX: memory-dump: add memory dump table for Pakala Add memory dump table configuration to enable memory dump function on Pakala platform. Signed-off-by: Jie Gan --- drivers/firmware/qcom/memory_dump_dev.c | 50 +++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/drivers/firmware/qcom/memory_dump_dev.c b/drivers/firmware/qcom/memory_dump_dev.c index 556ebafae5280..1626a67017990 100644 --- a/drivers/firmware/qcom/memory_dump_dev.c +++ b/drivers/firmware/qcom/memory_dump_dev.c @@ -57,12 +57,15 @@ enum dump_ids { CPUSS_REG = 0xef, TMC_ETF = 0xf0, ETF_SWAO = 0xf1, + ETF_SLPI = 0xf3, ETF_LPASS = 0xf4, FCM = 0xee, ETR_REG = 0x100, ETF_REG = 0x101, ETFSWAO_REG = 0x102, + ETFSLPI_REG = 0x103, ETFLPASS_REG = 0x104, + ETR1_REG = 0x105, L2_TLB0 = 0x120, L2_TLB100 = 0x121, L2_TLB200 = 0x122, @@ -86,6 +89,7 @@ enum dump_ids { OSM_REG = 0x163, PCU_REG = 0x164, FSM_DATA = 0x165, + SCANDUMP_SMMU = 0x220, }; static const struct dump_item lemans_items[] = { @@ -277,6 +281,35 @@ static const struct dump_item kodiak_items[] = { { RPMH, 0x2000000, "rpmh" }, }; +static const struct dump_item pakala_items[] = { + { C0_CONTEXT, 0x800, "c0-context" }, + { C100_CONTEXT, 0x800, "c100-context" }, + { C200_CONTEXT, 0x800, "c200-context" }, + { C300_CONTEXT, 0x800, "c300-context" }, + { C400_CONTEXT, 0x800, "c400-context" }, + { C500_CONTEXT, 0x800, "c500-context" }, + { C600_CONTEXT, 0x800, "c600-context" }, + { C700_CONTEXT, 0x800, "c700-context" }, + { RPMH, 0x400000, "rpmh" }, + { RPM_SW, 0x28000, "rpm-sw" }, + { PMIC, 0x200000, "pmic" }, + { FCM, 0x8400, "fcm" }, + { MISC_DATA, 0x1000, "misc-data" }, + { ETF_SWAO, 0x10000, "etf-swao" }, + { ETR_REG, 0x1000, "etr-reg" }, + { ETFSWAO_REG, 0x1000, "etfswao-reg" }, + { ETR1_REG, 0x1000, "etr1-reg" }, + { ETF_SLPI, 0x4000, "etf-slpi" }, + { ETFSLPI_REG, 0x1000, "etfslpi-reg" }, + { ETF_LPASS, 0x4000, "etf-lpass" }, + { ETFLPASS_REG, 0x1000, "etflpass-reg" }, + { OSM_REG, 0x400, "osm-reg" }, + { PCU_REG, 0x400, "pcu-reg" }, + { FSM_DATA, 0x400, "fsm-data" }, + { SCANDUMP_SMMU, 0x40000, "scandump-smmu" }, + { C0_SCANDUMP, 0x380000, "apps-scandump" }, +}; + static const struct dump_table lemans_dump_table = { .items = lemans_items, .num_of_items = ARRAY_SIZE(lemans_items), @@ -298,6 +331,13 @@ static const struct dump_table kodiak_dump_table = { .imem_size = 0x8, }; +static const struct dump_table pakala_dump_table = { + .items = pakala_items, + .num_of_items = ARRAY_SIZE(pakala_items), + .imem_base = 0x14680010, + .imem_size = 0x8, +}; + static int __init mem_dump_dev_init(void) { int ret; @@ -345,6 +385,16 @@ static int __init mem_dump_dev_init(void) if (ret) goto fail; + break; + case 618: + case 639: + case 705: + case 706: + ret = platform_device_add_data(mem_dump_pdev, + &pakala_dump_table, sizeof(pakala_dump_table)); + if (ret) + goto fail; + break; default: dev_err(&mem_dump_pdev->dev, "Invalid SoC ID\n"); From 0e74447c41fe7aa1f1fbb818e7cbbcc122ae03b3 Mon Sep 17 00:00:00 2001 From: Jie Gan Date: Mon, 9 Feb 2026 14:58:04 +0800 Subject: [PATCH 2276/2333] QCLINUX: qcom-dcc: add device configuration for Kaanapali Add device configuration to enable DCC on Kaanapali platform. Signed-off-by: Jie Gan --- drivers/misc/qcom-dcc-dev.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/drivers/misc/qcom-dcc-dev.c b/drivers/misc/qcom-dcc-dev.c index 0c2369a4843ae..5ed2a117b9e81 100644 --- a/drivers/misc/qcom-dcc-dev.c +++ b/drivers/misc/qcom-dcc-dev.c @@ -48,6 +48,15 @@ static const struct dcc_pdata pakala_pdata = { .map_ver = 0x3, }; +static const struct dcc_pdata kaanapali_pdata = { + .base = 0x100ff000, + .size = 0x1000, + .ram_base = 0x10080000, + .ram_size = 0x8000, + .dcc_offset = 0x0, + .map_ver = 0x3, +}; + static int __init dcc_dev_init(void) { int ret; @@ -101,6 +110,18 @@ static int __init dcc_dev_init(void) if (ret) goto fail; + break; + case 660: + case 661: + case 704: + case 722: + case 723: + case 730: + case 743: + ret = platform_device_add_data(dcc_pdev, &kaanapali_pdata, sizeof(kaanapali_pdata)); + if (ret) + goto fail; + break; default: pr_err("DCC: Invalid SoC ID\n"); From 1799cc6fe2fd6af5dcc3689124a1f8b6127ef2a9 Mon Sep 17 00:00:00 2001 From: Jie Gan Date: Mon, 9 Feb 2026 15:16:19 +0800 Subject: [PATCH 2277/2333] QCLINUX: memory-dump: add memory dump table for Kaanapali Add memory dump table configuration to enable memory dump function on Kaanapali platform. Signed-off-by: Jie Gan --- drivers/firmware/qcom/memory_dump_dev.c | 49 +++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/drivers/firmware/qcom/memory_dump_dev.c b/drivers/firmware/qcom/memory_dump_dev.c index 1626a67017990..d02e6af6c03a0 100644 --- a/drivers/firmware/qcom/memory_dump_dev.c +++ b/drivers/firmware/qcom/memory_dump_dev.c @@ -310,6 +310,35 @@ static const struct dump_item pakala_items[] = { { C0_SCANDUMP, 0x380000, "apps-scandump" }, }; +static const struct dump_item kaanapali_items[] = { + { C0_CONTEXT, 0x800, "c0-context" }, + { C100_CONTEXT, 0x800, "c100-context" }, + { C200_CONTEXT, 0x800, "c200-context" }, + { C300_CONTEXT, 0x800, "c300-context" }, + { C400_CONTEXT, 0x800, "c400-context" }, + { C500_CONTEXT, 0x800, "c500-context" }, + { C600_CONTEXT, 0x800, "c600-context" }, + { C700_CONTEXT, 0x800, "c700-context" }, + { RPMH, 0x400000, "rpmh" }, + { RPM_SW, 0x28000, "rpm-sw" }, + { PMIC, 0x200000, "pmic" }, + { FCM, 0x8400, "fcm" }, + { MISC_DATA, 0x1000, "misc-data" }, + { ETF_SWAO, 0x10000, "etf-swao" }, + { ETR_REG, 0x1000, "etr-reg" }, + { ETFSWAO_REG, 0x1000, "etfswao-reg" }, + { ETR1_REG, 0x1000, "etr1-reg" }, + { ETF_SLPI, 0x4000, "etf-slpi" }, + { ETFSLPI_REG, 0x1000, "etfslpi-reg" }, + { ETF_LPASS, 0x4000, "etf-lpass" }, + { ETFLPASS_REG, 0x1000, "etflpass-reg" }, + { OSM_REG, 0x400, "osm-reg" }, + { PCU_REG, 0x400, "pcu-reg" }, + { FSM_DATA, 0x400, "fsm-data" }, + { SCANDUMP_SMMU, 0x40000, "scandump-smmu" }, + { C0_SCANDUMP, 0x380000, "apps-scandump" }, +}; + static const struct dump_table lemans_dump_table = { .items = lemans_items, .num_of_items = ARRAY_SIZE(lemans_items), @@ -338,6 +367,13 @@ static const struct dump_table pakala_dump_table = { .imem_size = 0x8, }; +static const struct dump_table kaanapali_dump_table = { + .items = kaanapali_items, + .num_of_items = ARRAY_SIZE(kaanapali_items), + .imem_base = 0x14680010, + .imem_size = 0x8, +}; + static int __init mem_dump_dev_init(void) { int ret; @@ -395,6 +431,19 @@ static int __init mem_dump_dev_init(void) if (ret) goto fail; + break; + case 660: + case 661: + case 704: + case 722: + case 723: + case 730: + case 743: + ret = platform_device_add_data(mem_dump_pdev, + &kaanapali_dump_table, sizeof(kaanapali_dump_table)); + if (ret) + goto fail; + break; default: dev_err(&mem_dump_pdev->dev, "Invalid SoC ID\n"); From fcd68b6fa14ddd3371601a63864673976a83466b Mon Sep 17 00:00:00 2001 From: Jie Gan Date: Mon, 9 Feb 2026 15:32:10 +0800 Subject: [PATCH 2278/2333] QCLINUX: qcom-dcc: add device configuration for Hamoa Add device configuration to enable DCC on Hamoa platform. Signed-off-by: Jie Gan --- drivers/misc/qcom-dcc-dev.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/drivers/misc/qcom-dcc-dev.c b/drivers/misc/qcom-dcc-dev.c index 5ed2a117b9e81..ff19dac70011f 100644 --- a/drivers/misc/qcom-dcc-dev.c +++ b/drivers/misc/qcom-dcc-dev.c @@ -57,6 +57,15 @@ static const struct dcc_pdata kaanapali_pdata = { .map_ver = 0x3, }; +static const struct dcc_pdata hamoa_pdata = { + .base = 0x100ff000, + .size = 0x1000, + .ram_base = 0x10080000, + .ram_size = 0x18000, + .dcc_offset = 0x0, + .map_ver = 0x3, +}; + static int __init dcc_dev_init(void) { int ret; @@ -122,6 +131,16 @@ static int __init dcc_dev_init(void) if (ret) goto fail; + break; + case 555: + case 615: + case 616: + case 709: + case 710: + ret = platform_device_add_data(dcc_pdev, &hamoa_pdata, sizeof(hamoa_pdata)); + if (ret) + goto fail; + break; default: pr_err("DCC: Invalid SoC ID\n"); From 4ee4e17677ef4fe392cdfcbc9ac55d01cae87784 Mon Sep 17 00:00:00 2001 From: Jie Gan Date: Mon, 9 Feb 2026 15:45:31 +0800 Subject: [PATCH 2279/2333] QCLINUX: memory-dump: add memory dump table for Hamoa Add memory dump table configuration to enable memory dump function on Hamoa platform. Signed-off-by: Jie Gan --- drivers/firmware/qcom/memory_dump_dev.c | 34 +++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/drivers/firmware/qcom/memory_dump_dev.c b/drivers/firmware/qcom/memory_dump_dev.c index d02e6af6c03a0..0f89cb201b783 100644 --- a/drivers/firmware/qcom/memory_dump_dev.c +++ b/drivers/firmware/qcom/memory_dump_dev.c @@ -339,6 +339,22 @@ static const struct dump_item kaanapali_items[] = { { C0_SCANDUMP, 0x380000, "apps-scandump" }, }; +static const struct dump_item hamoa_items[] = { + { C0_CONTEXT, 0x800, "c0-context" }, + { C100_CONTEXT, 0x800, "c100-context" }, + { C200_CONTEXT, 0x800, "c200-context" }, + { C300_CONTEXT, 0x800, "c300-context" }, + { C400_CONTEXT, 0x800, "c400-context" }, + { C500_CONTEXT, 0x800, "c500-context" }, + { C600_CONTEXT, 0x800, "c600-context" }, + { C700_CONTEXT, 0x800, "c700-context" }, + { RPMH, 0xc10000, "rpmh" }, + { PMIC, 0x200000, "pmic" }, + { ETF_SWAO, 0x10000, "etf-swao" }, + { ETR_REG, 0x1000, "etr-reg" }, + { ETFSWAO_REG, 0x1000, "etfswao-reg" }, +}; + static const struct dump_table lemans_dump_table = { .items = lemans_items, .num_of_items = ARRAY_SIZE(lemans_items), @@ -374,6 +390,13 @@ static const struct dump_table kaanapali_dump_table = { .imem_size = 0x8, }; +static const struct dump_table hamoa_dump_table = { + .items = hamoa_items, + .num_of_items = ARRAY_SIZE(hamoa_items), + .imem_base = 0x146aa010, + .imem_size = 0x8, +}; + static int __init mem_dump_dev_init(void) { int ret; @@ -444,6 +467,17 @@ static int __init mem_dump_dev_init(void) if (ret) goto fail; + break; + case 555: + case 615: + case 616: + case 709: + case 710: + ret = platform_device_add_data(mem_dump_pdev, + &hamoa_dump_table, sizeof(hamoa_dump_table)); + if (ret) + goto fail; + break; default: dev_err(&mem_dump_pdev->dev, "Invalid SoC ID\n"); From 98806b0dd7408a7c79c614e9a86f81914dd11dc4 Mon Sep 17 00:00:00 2001 From: Krishna Chaitanya Chundru Date: Wed, 11 Feb 2026 15:36:43 +0530 Subject: [PATCH 2280/2333] Revert "FROMLIST: dt-bindings: PCI: Add binding for Toshiba TC9563 PCIe switch" This reverts commit aef67efa5220448137126e06b4824d48a2943132. --- .../bindings/pci/toshiba,tc9563.yaml | 178 ------------------ 1 file changed, 178 deletions(-) delete mode 100644 Documentation/devicetree/bindings/pci/toshiba,tc9563.yaml diff --git a/Documentation/devicetree/bindings/pci/toshiba,tc9563.yaml b/Documentation/devicetree/bindings/pci/toshiba,tc9563.yaml deleted file mode 100644 index 82c902b67852d..0000000000000 --- a/Documentation/devicetree/bindings/pci/toshiba,tc9563.yaml +++ /dev/null @@ -1,178 +0,0 @@ -# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) -%YAML 1.2 ---- -$id: http://devicetree.org/schemas/pci/toshiba,tc9563.yaml# -$schema: http://devicetree.org/meta-schemas/core.yaml# - -title: Toshiba TC9563 PCIe switch - -maintainers: - - Krishna chaitanya chundru - -description: | - Toshiba TC9563 PCIe switch has one upstream and three downstream ports. - The 3rd downstream port has integrated endpoint device of Ethernet MAC. - Other two downstream ports are supposed to connect to external device. - - The TC9563 PCIe switch can be configured through I2C interface before - PCIe link is established to change FTS, ASPM related entry delays, - tx amplitude etc for better power efficiency and functionality. - -properties: - compatible: - enum: - - pci1179,0623 - - reg: - maxItems: 1 - - reset-gpios: - maxItems: 1 - description: - GPIO controlling the RESX# pin. - - vdd18-supply: true - - vdd09-supply: true - - vddc-supply: true - - vddio1-supply: true - - vddio2-supply: true - - vddio18-supply: true - - i2c-parent: - $ref: /schemas/types.yaml#/definitions/phandle-array - description: - A phandle to the parent I2C node and the slave address of the device - used to do configure tc9563 to change FTS, tx amplitude etc. - items: - - description: Phandle to the I2C controller node - - description: I2C slave address - -patternProperties: - "^pcie@[1-3],0$": - description: - child nodes describing the internal downstream ports - the tc9563 switch. - type: object - allOf: - - $ref: "#/$defs/tc9563-node" - - $ref: /schemas/pci/pci-pci-bridge.yaml# - unevaluatedProperties: false - -$defs: - tc9563-node: - type: object - - properties: - toshiba,tx-amplitude-microvolt: - description: - Change Tx Margin setting for low power consumption. - - toshiba,no-dfe-support: - type: boolean - description: - Disable DFE (Decision Feedback Equalizer), which mitigates - intersymbol interference and some reflections caused by impedance mismatches. - -required: - - reset-gpios - - vdd18-supply - - vdd09-supply - - vddc-supply - - vddio1-supply - - vddio2-supply - - vddio18-supply - - i2c-parent - -allOf: - - $ref: "#/$defs/tc9563-node" - - $ref: /schemas/pci/pci-bus-common.yaml# - -unevaluatedProperties: false - -examples: - - | - #include - - pcie { - #address-cells = <3>; - #size-cells = <2>; - - pcie@0 { - device_type = "pci"; - reg = <0x0 0x0 0x0 0x0 0x0>; - - #address-cells = <3>; - #size-cells = <2>; - ranges; - bus-range = <0x01 0xff>; - - pcie@0,0 { - compatible = "pci1179,0623"; - - reg = <0x10000 0x0 0x0 0x0 0x0>; - device_type = "pci"; - #address-cells = <3>; - #size-cells = <2>; - ranges; - bus-range = <0x02 0xff>; - - i2c-parent = <&qup_i2c 0x77>; - - vdd18-supply = <&vdd>; - vdd09-supply = <&vdd>; - vddc-supply = <&vdd>; - vddio1-supply = <&vdd>; - vddio2-supply = <&vdd>; - vddio18-supply = <&vdd>; - - reset-gpios = <&gpio 1 GPIO_ACTIVE_LOW>; - - pcie@1,0 { - compatible = "pciclass,0604"; - reg = <0x20800 0x0 0x0 0x0 0x0>; - #address-cells = <3>; - #size-cells = <2>; - device_type = "pci"; - ranges; - bus-range = <0x03 0xff>; - - toshiba,no-dfe-support; - }; - - pcie@2,0 { - compatible = "pciclass,0604"; - reg = <0x21000 0x0 0x0 0x0 0x0>; - #address-cells = <3>; - #size-cells = <2>; - device_type = "pci"; - ranges; - bus-range = <0x04 0xff>; - }; - - pcie@3,0 { - compatible = "pciclass,0604"; - reg = <0x21800 0x0 0x0 0x0 0x0>; - #address-cells = <3>; - #size-cells = <2>; - device_type = "pci"; - ranges; - bus-range = <0x05 0xff>; - - toshiba,tx-amplitude-microvolt = <10>; - - ethernet@0,0 { - reg = <0x50000 0x0 0x0 0x0 0x0>; - }; - - ethernet@0,1 { - reg = <0x50100 0x0 0x0 0x0 0x0>; - }; - }; - }; - }; - }; From 5a25b4d7249576fee8aed33af7e414556a41c8aa Mon Sep 17 00:00:00 2001 From: Krishna Chaitanya Chundru Date: Wed, 11 Feb 2026 15:38:11 +0530 Subject: [PATCH 2281/2333] Revert "FROMLIST: PCI: Add new start_link() & stop_link function ops" This reverts commit fa9614f3861a8afa3fe8c7d81d009e8b55f628bb. --- include/linux/pci.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/linux/pci.h b/include/linux/pci.h index 3b15524f75949..bf97d49c23cf5 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -831,8 +831,6 @@ struct pci_ops { void __iomem *(*map_bus)(struct pci_bus *bus, unsigned int devfn, int where); int (*read)(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *val); int (*write)(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 val); - int (*start_link)(struct pci_bus *bus); - void (*stop_link)(struct pci_bus *bus); }; /* From c37579d697234e7800006ab1160efc3dbb9efa43 Mon Sep 17 00:00:00 2001 From: Krishna Chaitanya Chundru Date: Wed, 11 Feb 2026 15:39:12 +0530 Subject: [PATCH 2282/2333] Revert "FROMLIST: PCI: dwc: Add host_start_link() & host_start_link() hooks for dwc glue drivers" This reverts commit cbaab6d2a992776385dbbe2a55f5b4e6e70fa9df. --- drivers/pci/controller/dwc/pcie-designware.h | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index 5f5574a82224b..24bfa5231923a 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -485,8 +485,6 @@ struct dw_pcie_ops { enum dw_pcie_ltssm (*get_ltssm)(struct dw_pcie *pcie); int (*start_link)(struct dw_pcie *pcie); void (*stop_link)(struct dw_pcie *pcie); - int (*host_start_link)(struct dw_pcie *pcie); - void (*host_stop_link)(struct dw_pcie *pcie); }; struct debugfs_info { @@ -789,20 +787,6 @@ static inline void dw_pcie_stop_link(struct dw_pcie *pci) pci->ops->stop_link(pci); } -static inline int dw_pcie_host_start_link(struct dw_pcie *pci) -{ - if (pci->ops && pci->ops->host_start_link) - return pci->ops->host_start_link(pci); - - return 0; -} - -static inline void dw_pcie_host_stop_link(struct dw_pcie *pci) -{ - if (pci->ops && pci->ops->host_stop_link) - pci->ops->host_stop_link(pci); -} - static inline enum dw_pcie_ltssm dw_pcie_get_ltssm(struct dw_pcie *pci) { u32 val; From 1ac2800691e38f3b5d6502052c237a8eb238ea72 Mon Sep 17 00:00:00 2001 From: Krishna Chaitanya Chundru Date: Wed, 11 Feb 2026 15:41:03 +0530 Subject: [PATCH 2283/2333] Revert "FROMLIST: PCI: dwc: Implement .start_link(), .stop_link() hooks" This reverts commit eab34c8d7710f4e847e60cbba2da9ca383f55376. --- .../pci/controller/dwc/pcie-designware-host.c | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c index 4bca571309e3f..e92513c5bda51 100644 --- a/drivers/pci/controller/dwc/pcie-designware-host.c +++ b/drivers/pci/controller/dwc/pcie-designware-host.c @@ -856,28 +856,10 @@ static void __iomem *dw_pcie_ecam_conf_map_bus(struct pci_bus *bus, unsigned int return pci->dbi_base + where; } -static int dw_pcie_op_start_link(struct pci_bus *bus) -{ - struct dw_pcie_rp *pp = bus->sysdata; - struct dw_pcie *pci = to_dw_pcie_from_pp(pp); - - return dw_pcie_host_start_link(pci); -} - -static void dw_pcie_op_stop_link(struct pci_bus *bus) -{ - struct dw_pcie_rp *pp = bus->sysdata; - struct dw_pcie *pci = to_dw_pcie_from_pp(pp); - - dw_pcie_host_stop_link(pci); -} - static struct pci_ops dw_pcie_ops = { .map_bus = dw_pcie_own_conf_map_bus, .read = pci_generic_config_read, .write = pci_generic_config_write, - .start_link = dw_pcie_op_start_link, - .stop_link = dw_pcie_op_stop_link, }; static struct pci_ops dw_pcie_ecam_ops = { From 35452e1e9d13d28cc8a7f52a5017028979311988 Mon Sep 17 00:00:00 2001 From: Krishna Chaitanya Chundru Date: Wed, 11 Feb 2026 15:41:37 +0530 Subject: [PATCH 2284/2333] Revert "FROMLIST: PCI: qcom: Add support for host_stop_link() & host_start_link()" This reverts commit fddebfa200a0637c5f2115c59d4cfec927cc411a. --- drivers/pci/controller/dwc/pcie-qcom.c | 35 -------------------------- 1 file changed, 35 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c index d81a479e49ef2..c48a20602d7fa 100644 --- a/drivers/pci/controller/dwc/pcie-qcom.c +++ b/drivers/pci/controller/dwc/pcie-qcom.c @@ -250,7 +250,6 @@ struct qcom_pcie_ops { void (*host_post_init)(struct qcom_pcie *pcie); void (*deinit)(struct qcom_pcie *pcie); void (*ltssm_enable)(struct qcom_pcie *pcie); - void (*ltssm_disable)(struct qcom_pcie *pcie); int (*config_sid)(struct qcom_pcie *pcie); }; @@ -642,37 +641,6 @@ static int qcom_pcie_post_init_1_0_0(struct qcom_pcie *pcie) return 0; } -static int qcom_pcie_host_start_link(struct dw_pcie *pci) -{ - struct qcom_pcie *pcie = to_qcom_pcie(pci); - - qcom_ep_reset_deassert(pcie); - - if (pcie->cfg->ops->ltssm_enable) - pcie->cfg->ops->ltssm_enable(pcie); - - return 0; -} - -static void qcom_pcie_host_stop_link(struct dw_pcie *pci) -{ - struct qcom_pcie *pcie = to_qcom_pcie(pci); - - qcom_ep_reset_assert(pcie); - - if (pcie->cfg->ops->ltssm_disable) - pcie->cfg->ops->ltssm_disable(pcie); -} - -static void qcom_pcie_2_3_2_ltssm_disable(struct qcom_pcie *pcie) -{ - u32 val; - - val = readl(pcie->parf + PARF_LTSSM); - val &= ~LTSSM_EN; - writel(val, pcie->parf + PARF_LTSSM); -} - static void qcom_pcie_2_3_2_ltssm_enable(struct qcom_pcie *pcie) { u32 val; @@ -1441,7 +1409,6 @@ static const struct qcom_pcie_ops ops_1_9_0 = { .host_post_init = qcom_pcie_host_post_init_2_7_0, .deinit = qcom_pcie_deinit_2_7_0, .ltssm_enable = qcom_pcie_2_3_2_ltssm_enable, - .ltssm_disable = qcom_pcie_2_3_2_ltssm_disable, .config_sid = qcom_pcie_config_sid_1_9_0, }; @@ -1513,8 +1480,6 @@ static const struct qcom_pcie_cfg cfg_fw_managed = { static const struct dw_pcie_ops dw_pcie_ops = { .link_up = qcom_pcie_link_up, .start_link = qcom_pcie_start_link, - .host_start_link = qcom_pcie_host_start_link, - .host_stop_link = qcom_pcie_host_stop_link, }; static int qcom_pcie_icc_init(struct qcom_pcie *pcie) From 260127eb2a4412208ee6dbf6e3026ed44bdb130d Mon Sep 17 00:00:00 2001 From: Krishna Chaitanya Chundru Date: Wed, 11 Feb 2026 15:42:12 +0530 Subject: [PATCH 2285/2333] Revert "FROMLIST: PCI: Add pcie_link_is_active() to determine if the link is active" This reverts commit 499dae1ccbb3ee9422363dfd183c20a83b201793. --- drivers/pci/hotplug/pciehp.h | 1 + drivers/pci/hotplug/pciehp_ctrl.c | 2 +- drivers/pci/hotplug/pciehp_hpc.c | 35 +++++++++++++++++++++++++++---- drivers/pci/pci.c | 28 +++---------------------- drivers/pci/pci.h | 1 - 5 files changed, 36 insertions(+), 31 deletions(-) diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h index 79df49cc99463..debc79b0adfb2 100644 --- a/drivers/pci/hotplug/pciehp.h +++ b/drivers/pci/hotplug/pciehp.h @@ -186,6 +186,7 @@ int pciehp_query_power_fault(struct controller *ctrl); int pciehp_card_present(struct controller *ctrl); int pciehp_card_present_or_link_active(struct controller *ctrl); int pciehp_check_link_status(struct controller *ctrl); +int pciehp_check_link_active(struct controller *ctrl); bool pciehp_device_replaced(struct controller *ctrl); void pciehp_release_ctrl(struct controller *ctrl); diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c index 6cc1b27b3b11a..bcc938d4420f3 100644 --- a/drivers/pci/hotplug/pciehp_ctrl.c +++ b/drivers/pci/hotplug/pciehp_ctrl.c @@ -260,7 +260,7 @@ void pciehp_handle_presence_or_link_change(struct controller *ctrl, u32 events) /* Turn the slot on if it's occupied or link is up */ mutex_lock(&ctrl->state_lock); present = pciehp_card_present(ctrl); - link_active = pcie_link_is_active(ctrl->pcie->port); + link_active = pciehp_check_link_active(ctrl); if (present <= 0 && link_active <= 0) { if (ctrl->state == BLINKINGON_STATE) { ctrl->state = OFF_STATE; diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index 2905ae7c9bbf7..bcc51b26d03d5 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -221,6 +221,33 @@ static void pcie_write_cmd_nowait(struct controller *ctrl, u16 cmd, u16 mask) pcie_do_write_cmd(ctrl, cmd, mask, false); } +/** + * pciehp_check_link_active() - Is the link active + * @ctrl: PCIe hotplug controller + * + * Check whether the downstream link is currently active. Note it is + * possible that the card is removed immediately after this so the + * caller may need to take it into account. + * + * If the hotplug controller itself is not available anymore returns + * %-ENODEV. + */ +int pciehp_check_link_active(struct controller *ctrl) +{ + struct pci_dev *pdev = ctrl_dev(ctrl); + u16 lnk_status; + int ret; + + ret = pcie_capability_read_word(pdev, PCI_EXP_LNKSTA, &lnk_status); + if (ret == PCIBIOS_DEVICE_NOT_FOUND || PCI_POSSIBLE_ERROR(lnk_status)) + return -ENODEV; + + ret = !!(lnk_status & PCI_EXP_LNKSTA_DLLLA); + ctrl_dbg(ctrl, "%s: lnk_status = %x\n", __func__, lnk_status); + + return ret; +} + static bool pci_bus_check_dev(struct pci_bus *bus, int devfn) { u32 l; @@ -440,7 +467,7 @@ int pciehp_card_present_or_link_active(struct controller *ctrl) if (ret) return ret; - return pcie_link_is_active(ctrl_dev(ctrl)); + return pciehp_check_link_active(ctrl); } int pciehp_query_power_fault(struct controller *ctrl) @@ -587,8 +614,8 @@ static void pciehp_ignore_link_change(struct controller *ctrl, * Synthesize it to ensure that it is acted on. */ down_read_nested(&ctrl->reset_lock, ctrl->depth); - if (!pcie_link_is_active(ctrl_dev(ctrl)) || pciehp_device_replaced(ctrl)) - pciehp_request(ctrl, PCI_EXP_SLTSTA_DLLSC); + if (!pciehp_check_link_active(ctrl) || pciehp_device_replaced(ctrl)) + pciehp_request(ctrl, ignored_events); up_read(&ctrl->reset_lock); } @@ -894,7 +921,7 @@ int pciehp_slot_reset(struct pcie_device *dev) pcie_capability_write_word(dev->port, PCI_EXP_SLTSTA, PCI_EXP_SLTSTA_DLLSC); - if (!pcie_link_is_active(ctrl_dev(ctrl))) + if (!pciehp_check_link_active(ctrl)) pciehp_request(ctrl, PCI_EXP_SLTSTA_DLLSC); return 0; diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 4cd2a214088e2..b14dd064006cc 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -4868,6 +4868,7 @@ int pci_bridge_wait_for_secondary_bus(struct pci_dev *dev, char *reset_type) return 0; if (pcie_get_speed_cap(dev) <= PCIE_SPEED_5_0GT) { + u16 status; pci_dbg(dev, "waiting %d ms for downstream link\n", delay); msleep(delay); @@ -4883,7 +4884,8 @@ int pci_bridge_wait_for_secondary_bus(struct pci_dev *dev, char *reset_type) if (!dev->link_active_reporting) return -ENOTTY; - if (pcie_link_is_active(dev) <= 0) + pcie_capability_read_word(dev, PCI_EXP_LNKSTA, &status); + if (!(status & PCI_EXP_LNKSTA_DLLLA)) return -ENOTTY; return pci_dev_wait(child, reset_type, @@ -6192,30 +6194,6 @@ void pcie_print_link_status(struct pci_dev *dev) } EXPORT_SYMBOL(pcie_print_link_status); -/** - * pcie_link_is_active() - Checks if the link is active or not - * @pdev: PCI device to query - * - * Check whether the downstream link is currently active. Note it is - * possible that the card is removed immediately after this so the - * caller may need to take it into account. - * - * Return: true if link is active, or -ENODEV if the config read fails. - */ -int pcie_link_is_active(struct pci_dev *pdev) -{ - u16 lnk_status; - int ret; - - ret = pcie_capability_read_word(pdev, PCI_EXP_LNKSTA, &lnk_status); - if (ret == PCIBIOS_DEVICE_NOT_FOUND || PCI_POSSIBLE_ERROR(lnk_status)) - return -ENODEV; - - pci_dbg(pdev, "lnk_status = %#06x\n", lnk_status); - return !!(lnk_status & PCI_EXP_LNKSTA_DLLLA); -} -EXPORT_SYMBOL(pcie_link_is_active); - /** * pci_select_bars - Make BAR mask from the type of resource * @dev: the PCI device for which BAR mask is made diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 212340d4b76f1..36f8c0985430a 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -320,7 +320,6 @@ static inline int pci_proc_detach_bus(struct pci_bus *bus) { return 0; } /* Functions for PCI Hotplug drivers to use */ int pci_hp_add_bridge(struct pci_dev *dev); bool pci_hp_spurious_link_change(struct pci_dev *pdev); -int pcie_link_is_active(struct pci_dev *dev); #if defined(CONFIG_SYSFS) && defined(HAVE_PCI_LEGACY) void pci_create_legacy_files(struct pci_bus *bus); From 7d894ce97415c55d5bb30785ec8d8b1d99ea354c Mon Sep 17 00:00:00 2001 From: Krishna Chaitanya Chundru Date: Wed, 11 Feb 2026 15:42:39 +0530 Subject: [PATCH 2286/2333] Revert "FROMLIST: PCI: pwrctrl: Add power control driver for tc9563" This reverts commit c36944ebc50ed5d40b3c550cbe5792b93c32dc27. --- drivers/pci/pwrctrl/Kconfig | 13 - drivers/pci/pwrctrl/Makefile | 2 - drivers/pci/pwrctrl/pci-pwrctrl-tc9563.c | 637 ----------------------- 3 files changed, 652 deletions(-) delete mode 100644 drivers/pci/pwrctrl/pci-pwrctrl-tc9563.c diff --git a/drivers/pci/pwrctrl/Kconfig b/drivers/pci/pwrctrl/Kconfig index 32e3c72755293..6956c18548114 100644 --- a/drivers/pci/pwrctrl/Kconfig +++ b/drivers/pci/pwrctrl/Kconfig @@ -22,19 +22,6 @@ config PCI_PWRCTRL_SLOT PCI slots. The voltage regulators powering the rails of the PCI slots are expected to be defined in the devicetree node of the PCI bridge. -config PCI_PWRCTRL_TC9563 - tristate "PCI Power Control driver for TC9563 PCIe switch" - select PCI_PWRCTRL - help - Say Y here to enable the PCI Power Control driver of TC9563 PCIe - switch. - - This driver enables power and configures the TC9563 PCIe switch - through i2c.TC9563 is a PCIe switch which has one upstream and three - downstream ports. To one of the downstream ports integrated ethernet - MAC is connected as endpoint device. Other two downstream ports are - supposed to connect to external device. - # deprecated config HAVE_PWRCTL bool diff --git a/drivers/pci/pwrctrl/Makefile b/drivers/pci/pwrctrl/Makefile index 13b02282106c2..a4e5808d7850c 100644 --- a/drivers/pci/pwrctrl/Makefile +++ b/drivers/pci/pwrctrl/Makefile @@ -7,5 +7,3 @@ obj-$(CONFIG_PCI_PWRCTRL_PWRSEQ) += pci-pwrctrl-pwrseq.o obj-$(CONFIG_PCI_PWRCTRL_SLOT) += pci-pwrctrl-slot.o pci-pwrctrl-slot-y := slot.o - -obj-$(CONFIG_PCI_PWRCTRL_TC9563) += pci-pwrctrl-tc9563.o diff --git a/drivers/pci/pwrctrl/pci-pwrctrl-tc9563.c b/drivers/pci/pwrctrl/pci-pwrctrl-tc9563.c deleted file mode 100644 index 63e719fa3589a..0000000000000 --- a/drivers/pci/pwrctrl/pci-pwrctrl-tc9563.c +++ /dev/null @@ -1,637 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "../pci.h" - -#define TC9563_GPIO_CONFIG 0x801208 -#define TC9563_RESET_GPIO 0x801210 - -#define TC9563_PORT_L0S_DELAY 0x82496c -#define TC9563_PORT_L1_DELAY 0x824970 - -#define TC9563_EMBEDDED_ETH_DELAY 0x8200d8 -#define TC9563_ETH_L1_DELAY_MASK GENMASK(27, 18) -#define TC9563_ETH_L1_DELAY_VALUE(x) FIELD_PREP(TC9563_ETH_L1_DELAY_MASK, x) -#define TC9563_ETH_L0S_DELAY_MASK GENMASK(17, 13) -#define TC9563_ETH_L0S_DELAY_VALUE(x) FIELD_PREP(TC9563_ETH_L0S_DELAY_MASK, x) - -#define TC9563_NFTS_2_5_GT 0x824978 -#define TC9563_NFTS_5_GT 0x82497c - -#define TC9563_PORT_LANE_ACCESS_ENABLE 0x828000 - -#define TC9563_PHY_RATE_CHANGE_OVERRIDE 0x828040 -#define TC9563_PHY_RATE_CHANGE 0x828050 - -#define TC9563_TX_MARGIN 0x828234 - -#define TC9563_DFE_ENABLE 0x828a04 -#define TC9563_DFE_EQ0_MODE 0x828a08 -#define TC9563_DFE_EQ1_MODE 0x828a0c -#define TC9563_DFE_EQ2_MODE 0x828a14 -#define TC9563_DFE_PD_MASK 0x828254 - -#define TC9563_PORT_SELECT 0x82c02c -#define TC9563_PORT_ACCESS_ENABLE 0x82c030 - -#define TC9563_POWER_CONTROL 0x82b09c -#define TC9563_POWER_CONTROL_OVREN 0x82b2c8 - -#define TC9563_GPIO_MASK 0xfffffff3 - -#define TC9563_TX_MARGIN_MIN_VAL 400000 - -struct tc9563_pwrctrl_reg_setting { - unsigned int offset; - unsigned int val; -}; - -enum tc9563_pwrctrl_ports { - TC9563_USP, - TC9563_DSP1, - TC9563_DSP2, - TC9563_DSP3, - TC9563_ETHERNET, - TC9563_MAX -}; - -struct tc9563_pwrctrl_cfg { - u32 l0s_delay; - u32 l1_delay; - u32 tx_amp; - u8 nfts[2]; /* GEN1 & GEN2 */ - bool disable_dfe; - bool disable_port; -}; - -#define TC9563_PWRCTL_MAX_SUPPLY 6 - -static const char *const tc9563_supply_names[TC9563_PWRCTL_MAX_SUPPLY] = { - "vddc", - "vdd18", - "vdd09", - "vddio1", - "vddio2", - "vddio18", -}; - -struct tc9563_pwrctrl_ctx { - struct regulator_bulk_data supplies[TC9563_PWRCTL_MAX_SUPPLY]; - struct tc9563_pwrctrl_cfg cfg[TC9563_MAX]; - struct gpio_desc *reset_gpio; - struct i2c_adapter *adapter; - struct i2c_client *client; - struct pci_pwrctrl pwrctrl; -}; - -/* - * downstream port power off sequence, hardcoding the address - * as we don't know register names for these register offsets. - */ -static const struct tc9563_pwrctrl_reg_setting common_pwroff_seq[] = { - {0x82900c, 0x1}, - {0x829010, 0x1}, - {0x829018, 0x0}, - {0x829020, 0x1}, - {0x82902c, 0x1}, - {0x829030, 0x1}, - {0x82903c, 0x1}, - {0x829058, 0x0}, - {0x82905c, 0x1}, - {0x829060, 0x1}, - {0x8290cc, 0x1}, - {0x8290d0, 0x1}, - {0x8290d8, 0x1}, - {0x8290e0, 0x1}, - {0x8290e8, 0x1}, - {0x8290ec, 0x1}, - {0x8290f4, 0x1}, - {0x82910c, 0x1}, - {0x829110, 0x1}, - {0x829114, 0x1}, -}; - -static const struct tc9563_pwrctrl_reg_setting dsp1_pwroff_seq[] = { - {TC9563_PORT_ACCESS_ENABLE, 0x2}, - {TC9563_PORT_LANE_ACCESS_ENABLE, 0x3}, - {TC9563_POWER_CONTROL, 0x014f4804}, - {TC9563_POWER_CONTROL_OVREN, 0x1}, - {TC9563_PORT_ACCESS_ENABLE, 0x4}, -}; - -static const struct tc9563_pwrctrl_reg_setting dsp2_pwroff_seq[] = { - {TC9563_PORT_ACCESS_ENABLE, 0x8}, - {TC9563_PORT_LANE_ACCESS_ENABLE, 0x1}, - {TC9563_POWER_CONTROL, 0x014f4804}, - {TC9563_POWER_CONTROL_OVREN, 0x1}, - {TC9563_PORT_ACCESS_ENABLE, 0x8}, -}; - -/* - * Since all transfers are initiated by the probe, no locks are necessary, - * as there are no concurrent calls. - */ -static int tc9563_pwrctrl_i2c_write(struct i2c_client *client, - u32 reg_addr, u32 reg_val) -{ - struct i2c_msg msg; - u8 msg_buf[7]; - int ret; - - msg.addr = client->addr; - msg.len = 7; - msg.flags = 0; - - /* Big Endian for reg addr */ - put_unaligned_be24(reg_addr, &msg_buf[0]); - - /* Little Endian for reg val */ - put_unaligned_le32(reg_val, &msg_buf[3]); - - msg.buf = msg_buf; - ret = i2c_transfer(client->adapter, &msg, 1); - return ret == 1 ? 0 : ret; -} - -static int tc9563_pwrctrl_i2c_read(struct i2c_client *client, - u32 reg_addr, u32 *reg_val) -{ - struct i2c_msg msg[2]; - u8 wr_data[3]; - u32 rd_data; - int ret; - - msg[0].addr = client->addr; - msg[0].len = 3; - msg[0].flags = 0; - - /* Big Endian for reg addr */ - put_unaligned_be24(reg_addr, &wr_data[0]); - - msg[0].buf = wr_data; - - msg[1].addr = client->addr; - msg[1].len = 4; - msg[1].flags = I2C_M_RD; - - msg[1].buf = (u8 *)&rd_data; - - ret = i2c_transfer(client->adapter, &msg[0], 2); - if (ret == 2) { - *reg_val = get_unaligned_le32(&rd_data); - return 0; - } - - /* If only one message successfully completed, return -EIO */ - return ret == 1 ? -EIO : ret; -} - -static int tc9563_pwrctrl_i2c_bulk_write(struct i2c_client *client, - const struct tc9563_pwrctrl_reg_setting *seq, int len) -{ - int ret, i; - - for (i = 0; i < len; i++) { - ret = tc9563_pwrctrl_i2c_write(client, seq[i].offset, seq[i].val); - if (ret) - return ret; - } - - return 0; -} - -static int tc9563_pwrctrl_disable_port(struct tc9563_pwrctrl_ctx *ctx, - enum tc9563_pwrctrl_ports port) -{ - struct tc9563_pwrctrl_cfg *cfg = &ctx->cfg[port]; - const struct tc9563_pwrctrl_reg_setting *seq; - int ret, len; - - if (!cfg->disable_port) - return 0; - - if (port == TC9563_DSP1) { - seq = dsp1_pwroff_seq; - len = ARRAY_SIZE(dsp1_pwroff_seq); - } else { - seq = dsp2_pwroff_seq; - len = ARRAY_SIZE(dsp2_pwroff_seq); - } - - ret = tc9563_pwrctrl_i2c_bulk_write(ctx->client, seq, len); - if (ret) - return ret; - - return tc9563_pwrctrl_i2c_bulk_write(ctx->client, - common_pwroff_seq, ARRAY_SIZE(common_pwroff_seq)); -} - -static int tc9563_pwrctrl_set_l0s_l1_entry_delay(struct tc9563_pwrctrl_ctx *ctx, - enum tc9563_pwrctrl_ports port, bool is_l1, u32 ns) -{ - u32 rd_val, units; - int ret; - - if (ns < 256) - return 0; - - /* convert to units of 256ns */ - units = ns / 256; - - if (port == TC9563_ETHERNET) { - ret = tc9563_pwrctrl_i2c_read(ctx->client, TC9563_EMBEDDED_ETH_DELAY, &rd_val); - if (ret) - return ret; - - if (is_l1) - rd_val = u32_replace_bits(rd_val, units, TC9563_ETH_L1_DELAY_MASK); - else - rd_val = u32_replace_bits(rd_val, units, TC9563_ETH_L0S_DELAY_MASK); - - return tc9563_pwrctrl_i2c_write(ctx->client, TC9563_EMBEDDED_ETH_DELAY, rd_val); - } - - ret = tc9563_pwrctrl_i2c_write(ctx->client, TC9563_PORT_SELECT, BIT(port)); - if (ret) - return ret; - - return tc9563_pwrctrl_i2c_write(ctx->client, - is_l1 ? TC9563_PORT_L1_DELAY : TC9563_PORT_L0S_DELAY, units); -} - -static int tc9563_pwrctrl_set_tx_amplitude(struct tc9563_pwrctrl_ctx *ctx, - enum tc9563_pwrctrl_ports port, u32 amp) -{ - int port_access; - - if (amp < TC9563_TX_MARGIN_MIN_VAL) - return 0; - - /* txmargin = (Amp(uV) - 400000) / 3125 */ - amp = (amp - TC9563_TX_MARGIN_MIN_VAL) / 3125; - - switch (port) { - case TC9563_USP: - port_access = 0x1; - break; - case TC9563_DSP1: - port_access = 0x2; - break; - case TC9563_DSP2: - port_access = 0x8; - break; - default: - return -EINVAL; - }; - - struct tc9563_pwrctrl_reg_setting tx_amp_seq[] = { - {TC9563_PORT_ACCESS_ENABLE, port_access}, - {TC9563_PORT_LANE_ACCESS_ENABLE, 0x3}, - {TC9563_TX_MARGIN, amp}, - }; - - return tc9563_pwrctrl_i2c_bulk_write(ctx->client, tx_amp_seq, ARRAY_SIZE(tx_amp_seq)); -} - -static int tc9563_pwrctrl_disable_dfe(struct tc9563_pwrctrl_ctx *ctx, - enum tc9563_pwrctrl_ports port) -{ - struct tc9563_pwrctrl_cfg *cfg = &ctx->cfg[port]; - int port_access, lane_access = 0x3; - u32 phy_rate = 0x21; - - if (!cfg->disable_dfe) - return 0; - - switch (port) { - case TC9563_USP: - phy_rate = 0x1; - port_access = 0x1; - break; - case TC9563_DSP1: - port_access = 0x2; - break; - case TC9563_DSP2: - port_access = 0x8; - lane_access = 0x1; - break; - default: - return -EINVAL; - }; - - struct tc9563_pwrctrl_reg_setting disable_dfe_seq[] = { - {TC9563_PORT_ACCESS_ENABLE, port_access}, - {TC9563_PORT_LANE_ACCESS_ENABLE, lane_access}, - {TC9563_DFE_ENABLE, 0x0}, - {TC9563_DFE_EQ0_MODE, 0x411}, - {TC9563_DFE_EQ1_MODE, 0x11}, - {TC9563_DFE_EQ2_MODE, 0x11}, - {TC9563_DFE_PD_MASK, 0x7}, - {TC9563_PHY_RATE_CHANGE_OVERRIDE, 0x10}, - {TC9563_PHY_RATE_CHANGE, phy_rate}, - {TC9563_PHY_RATE_CHANGE, 0x0}, - {TC9563_PHY_RATE_CHANGE_OVERRIDE, 0x0}, - }; - - return tc9563_pwrctrl_i2c_bulk_write(ctx->client, - disable_dfe_seq, ARRAY_SIZE(disable_dfe_seq)); -} - -static int tc9563_pwrctrl_set_nfts(struct tc9563_pwrctrl_ctx *ctx, - enum tc9563_pwrctrl_ports port, u8 *nfts) -{ - struct tc9563_pwrctrl_reg_setting nfts_seq[] = { - {TC9563_NFTS_2_5_GT, nfts[0]}, - {TC9563_NFTS_5_GT, nfts[1]}, - }; - int ret; - - if (!nfts[0]) - return 0; - - ret = tc9563_pwrctrl_i2c_write(ctx->client, TC9563_PORT_SELECT, BIT(port)); - if (ret) - return ret; - - return tc9563_pwrctrl_i2c_bulk_write(ctx->client, nfts_seq, ARRAY_SIZE(nfts_seq)); -} - -static int tc9563_pwrctrl_assert_deassert_reset(struct tc9563_pwrctrl_ctx *ctx, bool deassert) -{ - int ret, val; - - ret = tc9563_pwrctrl_i2c_write(ctx->client, TC9563_GPIO_CONFIG, TC9563_GPIO_MASK); - if (ret) - return ret; - - val = deassert ? 0xc : 0; - - return tc9563_pwrctrl_i2c_write(ctx->client, TC9563_RESET_GPIO, val); -} - -static int tc9563_pwrctrl_parse_device_dt(struct tc9563_pwrctrl_ctx *ctx, struct device_node *node, - enum tc9563_pwrctrl_ports port) -{ - struct tc9563_pwrctrl_cfg *cfg; - int ret; - - cfg = &ctx->cfg[port]; - - /* Disable port if the status of the port is disabled. */ - if (!of_device_is_available(node)) { - cfg->disable_port = true; - return 0; - }; - - ret = of_property_read_u32(node, "aspm-l0s-entry-delay-ns", &cfg->l0s_delay); - if (ret && ret != -EINVAL) - return ret; - - ret = of_property_read_u32(node, "aspm-l1-entry-delay-ns", &cfg->l1_delay); - if (ret && ret != -EINVAL) - return ret; - - ret = of_property_read_u32(node, "qcom,tx-amplitude-microvolt", &cfg->tx_amp); - if (ret && ret != -EINVAL) - return ret; - - ret = of_property_read_u8_array(node, "n-fts", cfg->nfts, 2); - if (ret && ret != -EINVAL) - return ret; - - cfg->disable_dfe = of_property_read_bool(node, "qcom,no-dfe-support"); - - return 0; -} - -static void tc9563_pwrctrl_power_off(struct tc9563_pwrctrl_ctx *ctx) -{ - gpiod_set_value(ctx->reset_gpio, 1); - - regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies); -} - -static int tc9563_pwrctrl_bring_up(struct tc9563_pwrctrl_ctx *ctx) -{ - struct tc9563_pwrctrl_cfg *cfg; - int ret, i; - - ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies); - if (ret < 0) - return dev_err_probe(ctx->pwrctrl.dev, ret, "cannot enable regulators\n"); - - gpiod_set_value(ctx->reset_gpio, 0); - - /* - * From TC9563 PORSYS rev 0.2, figure 1.1 POR boot sequence - * wait for 10ms for the internal osc frequency to stabilize. - */ - usleep_range(10000, 10500); - - ret = tc9563_pwrctrl_assert_deassert_reset(ctx, false); - if (ret) - goto power_off; - - for (i = 0; i < TC9563_MAX; i++) { - cfg = &ctx->cfg[i]; - ret = tc9563_pwrctrl_disable_port(ctx, i); - if (ret) { - dev_err(ctx->pwrctrl.dev, "Disabling port failed\n"); - goto power_off; - } - - ret = tc9563_pwrctrl_set_l0s_l1_entry_delay(ctx, i, false, cfg->l0s_delay); - if (ret) { - dev_err(ctx->pwrctrl.dev, "Setting L0s entry delay failed\n"); - goto power_off; - } - - ret = tc9563_pwrctrl_set_l0s_l1_entry_delay(ctx, i, true, cfg->l1_delay); - if (ret) { - dev_err(ctx->pwrctrl.dev, "Setting L1 entry delay failed\n"); - goto power_off; - } - - ret = tc9563_pwrctrl_set_tx_amplitude(ctx, i, cfg->tx_amp); - if (ret) { - dev_err(ctx->pwrctrl.dev, "Setting Tx amplitude failed\n"); - goto power_off; - } - - ret = tc9563_pwrctrl_set_nfts(ctx, i, cfg->nfts); - if (ret) { - dev_err(ctx->pwrctrl.dev, "Setting N_FTS failed\n"); - goto power_off; - } - - ret = tc9563_pwrctrl_disable_dfe(ctx, i); - if (ret) { - dev_err(ctx->pwrctrl.dev, "Disabling DFE failed\n"); - goto power_off; - } - } - - ret = tc9563_pwrctrl_assert_deassert_reset(ctx, true); - if (!ret) - return 0; - -power_off: - tc9563_pwrctrl_power_off(ctx); - return ret; -} - -static int tc9563_pwrctrl_probe(struct platform_device *pdev) -{ - struct pci_host_bridge *bridge = to_pci_host_bridge(pdev->dev.parent); - struct pci_dev *pci_dev = to_pci_dev(pdev->dev.parent); - struct pci_bus *bus = bridge->bus; - struct device *dev = &pdev->dev; - enum tc9563_pwrctrl_ports port; - struct tc9563_pwrctrl_ctx *ctx; - struct device_node *i2c_node; - int ret, addr; - - ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; - - ret = of_property_read_u32_index(pdev->dev.of_node, "i2c-parent", 1, &addr); - if (ret) - return dev_err_probe(dev, ret, "Failed to read i2c-parent property\n"); - - i2c_node = of_parse_phandle(dev->of_node, "i2c-parent", 0); - ctx->adapter = of_find_i2c_adapter_by_node(i2c_node); - of_node_put(i2c_node); - if (!ctx->adapter) - return dev_err_probe(dev, -EPROBE_DEFER, "Failed to find I2C adapter\n"); - - ctx->client = i2c_new_dummy_device(ctx->adapter, addr); - if (IS_ERR(ctx->client)) { - dev_err(dev, "Failed to create I2C client\n"); - i2c_put_adapter(ctx->adapter); - return PTR_ERR(ctx->client); - } - - for (int i = 0; i < TC9563_PWRCTL_MAX_SUPPLY; i++) - ctx->supplies[i].supply = tc9563_supply_names[i]; - - ret = devm_regulator_bulk_get(dev, TC9563_PWRCTL_MAX_SUPPLY, ctx->supplies); - if (ret) { - dev_err_probe(dev, ret, - "failed to get supply regulator\n"); - goto remove_i2c; - } - - ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); - if (IS_ERR(ctx->reset_gpio)) { - ret = dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), "failed to get reset GPIO\n"); - goto remove_i2c; - } - - pci_pwrctrl_init(&ctx->pwrctrl, dev); - - port = TC9563_USP; - ret = tc9563_pwrctrl_parse_device_dt(ctx, pdev->dev.of_node, port); - if (ret) { - dev_err(dev, "failed to parse device tree properties: %d\n", ret); - goto remove_i2c; - } - - /* - * Downstream ports are always children of the upstream port. - * The first node represents DSP1, the second node represents DSP2, and so on. - */ - for_each_child_of_node_scoped(pdev->dev.of_node, child) { - ret = tc9563_pwrctrl_parse_device_dt(ctx, child, port++); - if (ret) - break; - /* Embedded ethernet device are under DSP3 */ - if (port == TC9563_DSP3) - for_each_child_of_node_scoped(child, child1) { - ret = tc9563_pwrctrl_parse_device_dt(ctx, child1, port++); - if (ret) - break; - } - } - if (ret) { - dev_err(dev, "failed to parse device tree properties: %d\n", ret); - goto remove_i2c; - } - - if (!pcie_link_is_active(pci_dev) && bridge->ops->stop_link) - bridge->ops->stop_link(bus); - - ret = tc9563_pwrctrl_bring_up(ctx); - if (ret) - goto remove_i2c; - - if (!pcie_link_is_active(pci_dev) && bridge->ops->start_link) { - ret = bridge->ops->start_link(bus); - if (ret) - goto power_off; - } - - ret = devm_pci_pwrctrl_device_set_ready(dev, &ctx->pwrctrl); - if (ret) - goto power_off; - - platform_set_drvdata(pdev, ctx); - - return 0; - -power_off: - tc9563_pwrctrl_power_off(ctx); -remove_i2c: - i2c_unregister_device(ctx->client); - i2c_put_adapter(ctx->adapter); - return ret; -} - -static void tc9563_pwrctrl_remove(struct platform_device *pdev) -{ - struct tc9563_pwrctrl_ctx *ctx = platform_get_drvdata(pdev); - - tc9563_pwrctrl_power_off(ctx); - i2c_unregister_device(ctx->client); - i2c_put_adapter(ctx->adapter); -} - -static const struct of_device_id tc9563_pwrctrl_of_match[] = { - { .compatible = "pci1179,0623"}, - { } -}; -MODULE_DEVICE_TABLE(of, tc9563_pwrctrl_of_match); - -static struct platform_driver tc9563_pwrctrl_driver = { - .driver = { - .name = "pwrctrl-tc9563", - .of_match_table = tc9563_pwrctrl_of_match, - .probe_type = PROBE_PREFER_ASYNCHRONOUS, - }, - .probe = tc9563_pwrctrl_probe, - .remove = tc9563_pwrctrl_remove, -}; -module_platform_driver(tc9563_pwrctrl_driver); - -MODULE_AUTHOR("Krishna chaitanya chundru "); -MODULE_DESCRIPTION("TC956x power control driver"); -MODULE_LICENSE("GPL"); From d9f0c2be93d476704424d1d36e993f37a2995444 Mon Sep 17 00:00:00 2001 From: Krishna Chaitanya Chundru Date: Sat, 1 Nov 2025 09:29:32 +0530 Subject: [PATCH 2287/2333] BACKPORT: dt-bindings: PCI: Add binding for Toshiba TC9563 PCIe switch Add a device tree binding for the Toshiba TC9563 PCIe switch, which provides an Ethernet MAC integrated to the 3rd downstream port and two downstream PCIe ports. Reviewed-by: Rob Herring (Arm) Acked-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/20251101-tc9563-v9-1-de3429f7787a@oss.qualcomm.com Signed-off-by: Krishna Chaitanya Chundru --- .../bindings/pci/toshiba,tc9563.yaml | 179 ++++++++++++++++++ 1 file changed, 179 insertions(+) create mode 100644 Documentation/devicetree/bindings/pci/toshiba,tc9563.yaml diff --git a/Documentation/devicetree/bindings/pci/toshiba,tc9563.yaml b/Documentation/devicetree/bindings/pci/toshiba,tc9563.yaml new file mode 100644 index 0000000000000..fae4660647809 --- /dev/null +++ b/Documentation/devicetree/bindings/pci/toshiba,tc9563.yaml @@ -0,0 +1,179 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/pci/toshiba,tc9563.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Toshiba TC9563 PCIe switch + +maintainers: + - Krishna Chaitanya Chundru + +description: | + Toshiba TC9563 PCIe switch has one upstream and three downstream ports. + The 3rd downstream port has integrated endpoint device of Ethernet MAC. + Other two downstream ports are supposed to connect to external device. + + The TC9563 PCIe switch can be configured through I2C interface before + PCIe link is established to change FTS, ASPM related entry delays, + tx amplitude etc for better power efficiency and functionality. + +properties: + compatible: + enum: + - pci1179,0623 + + reg: + maxItems: 1 + + resx-gpios: + maxItems: 1 + description: + GPIO controlling the RESX# pin. + + vdd18-supply: true + + vdd09-supply: true + + vddc-supply: true + + vddio1-supply: true + + vddio2-supply: true + + vddio18-supply: true + + i2c-parent: + $ref: /schemas/types.yaml#/definitions/phandle-array + description: + A phandle to the parent I2C node and the slave address of the device + used to configure tc9563 to change FTS, tx amplitude etc. + items: + - description: Phandle to the I2C controller node + - description: I2C slave address + +patternProperties: + "^pcie@[1-3],0$": + description: + child nodes describing the internal downstream ports of + the tc9563 switch. + type: object + allOf: + - $ref: "#/$defs/tc9563-node" + - $ref: /schemas/pci/pci-pci-bridge.yaml# + unevaluatedProperties: false + +$defs: + tc9563-node: + type: object + + properties: + toshiba,tx-amplitude-microvolt: + description: + Change Tx Margin setting for low power consumption. + + toshiba,no-dfe-support: + type: boolean + description: + Disable DFE (Decision Feedback Equalizer), which mitigates + intersymbol interference and some reflections caused by + impedance mismatches. + +required: + - resx-gpios + - vdd18-supply + - vdd09-supply + - vddc-supply + - vddio1-supply + - vddio2-supply + - vddio18-supply + - i2c-parent + +allOf: + - $ref: "#/$defs/tc9563-node" + - $ref: /schemas/pci/pci-bus-common.yaml# + +unevaluatedProperties: false + +examples: + - | + #include + + pcie { + #address-cells = <3>; + #size-cells = <2>; + + pcie@0 { + device_type = "pci"; + reg = <0x0 0x0 0x0 0x0 0x0>; + + #address-cells = <3>; + #size-cells = <2>; + ranges; + bus-range = <0x01 0xff>; + + pcie@0,0 { + compatible = "pci1179,0623"; + + reg = <0x10000 0x0 0x0 0x0 0x0>; + device_type = "pci"; + #address-cells = <3>; + #size-cells = <2>; + ranges; + bus-range = <0x02 0xff>; + + i2c-parent = <&qup_i2c 0x77>; + + vdd18-supply = <&vdd>; + vdd09-supply = <&vdd>; + vddc-supply = <&vdd>; + vddio1-supply = <&vdd>; + vddio2-supply = <&vdd>; + vddio18-supply = <&vdd>; + + resx-gpios = <&gpio 1 GPIO_ACTIVE_LOW>; + + pcie@1,0 { + compatible = "pciclass,0604"; + reg = <0x20800 0x0 0x0 0x0 0x0>; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + ranges; + bus-range = <0x03 0xff>; + + toshiba,no-dfe-support; + }; + + pcie@2,0 { + compatible = "pciclass,0604"; + reg = <0x21000 0x0 0x0 0x0 0x0>; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + ranges; + bus-range = <0x04 0xff>; + }; + + pcie@3,0 { + compatible = "pciclass,0604"; + reg = <0x21800 0x0 0x0 0x0 0x0>; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + ranges; + bus-range = <0x05 0xff>; + + toshiba,tx-amplitude-microvolt = <10>; + + ethernet@0,0 { + reg = <0x50000 0x0 0x0 0x0 0x0>; + }; + + ethernet@0,1 { + reg = <0x50100 0x0 0x0 0x0 0x0>; + }; + }; + }; + }; + }; From eca824fcc7a2c70dcc882256d63b098ae4d777af Mon Sep 17 00:00:00 2001 From: Krishna Chaitanya Chundru Date: Sat, 1 Nov 2025 09:29:33 +0530 Subject: [PATCH 2288/2333] BACKPORT: PCI: Add assert_perst() operation to control PCIe PERST# Controller driver probes firsts, enables link training and scans the bus. When the PCI bridge is found, its child DT nodes will be scanned and pwrctrl devices will be created if needed. By the time pwrctrl driver probe gets called link training is already enabled by controller driver. Certain devices like TC9563 which uses PCI pwrctl framework needs to configure the device before PCI link is up. As the controller driver already enables link training as part of its probe, the moment device is powered on, controller and device participates in the link training and link can come up immediately and may not have time to configure the device. So we need to stop the link training by using assert_perst() by asserting the PERST# and de-assert the PERST# after device is configured. Acked-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/20251101-tc9563-v9-2-de3429f7787a@oss.qualcomm.com Signed-off-by: Krishna Chaitanya Chundru --- include/linux/pci.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/pci.h b/include/linux/pci.h index bf97d49c23cf5..e6a03367658d5 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -831,6 +831,7 @@ struct pci_ops { void __iomem *(*map_bus)(struct pci_bus *bus, unsigned int devfn, int where); int (*read)(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *val); int (*write)(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 val); + int (*assert_perst)(struct pci_bus *bus, bool assert); }; /* From 04db9b46ab53157b3fe2f2d72cd15025ccc03499 Mon Sep 17 00:00:00 2001 From: Krishna Chaitanya Chundru Date: Sat, 1 Nov 2025 09:29:34 +0530 Subject: [PATCH 2289/2333] BACKPORT: PCI: dwc: Add assert_perst() hook for dwc glue drivers Add assert_perst() function hook for dwc glue drivers to register with assert_perst() of pci ops, allowing for better control over the link initialization and shutdown process. Link: https://lore.kernel.org/r/20251101-tc9563-v9-3-de3429f7787a@oss.qualcomm.com Signed-off-by: Krishna Chaitanya Chundru --- drivers/pci/controller/dwc/pcie-designware.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index 24bfa5231923a..0721c15d92831 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -485,6 +485,7 @@ struct dw_pcie_ops { enum dw_pcie_ltssm (*get_ltssm)(struct dw_pcie *pcie); int (*start_link)(struct dw_pcie *pcie); void (*stop_link)(struct dw_pcie *pcie); + int (*assert_perst)(struct dw_pcie *pcie, bool assert); }; struct debugfs_info { @@ -787,6 +788,14 @@ static inline void dw_pcie_stop_link(struct dw_pcie *pci) pci->ops->stop_link(pci); } +static inline int dw_pcie_assert_perst(struct dw_pcie *pci, bool assert) +{ + if (pci->ops && pci->ops->assert_perst) + return pci->ops->assert_perst(pci, assert); + + return 0; +} + static inline enum dw_pcie_ltssm dw_pcie_get_ltssm(struct dw_pcie *pci) { u32 val; From 845e008d68db8f07b95d47e557399d07bba63a3c Mon Sep 17 00:00:00 2001 From: Krishna Chaitanya Chundru Date: Sat, 1 Nov 2025 09:29:35 +0530 Subject: [PATCH 2290/2333] BACKPORT: PCI: dwc: Implement .assert_perst() hook Implement assert_perst() function op for dwc drivers. Acked-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/20251101-tc9563-v9-4-de3429f7787a@oss.qualcomm.com Signed-off-by: Krishna Chaitanya Chundru --- drivers/pci/controller/dwc/pcie-designware-host.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c index e92513c5bda51..3d1a9dc829b34 100644 --- a/drivers/pci/controller/dwc/pcie-designware-host.c +++ b/drivers/pci/controller/dwc/pcie-designware-host.c @@ -856,10 +856,19 @@ static void __iomem *dw_pcie_ecam_conf_map_bus(struct pci_bus *bus, unsigned int return pci->dbi_base + where; } +static int dw_pcie_op_assert_perst(struct pci_bus *bus, bool assert) +{ + struct dw_pcie_rp *pp = bus->sysdata; + struct dw_pcie *pci = to_dw_pcie_from_pp(pp); + + return dw_pcie_assert_perst(pci, assert); +} + static struct pci_ops dw_pcie_ops = { .map_bus = dw_pcie_own_conf_map_bus, .read = pci_generic_config_read, .write = pci_generic_config_write, + .assert_perst = dw_pcie_op_assert_perst, }; static struct pci_ops dw_pcie_ecam_ops = { From c15ac077bb0b476d4555bc192282d63ef0295039 Mon Sep 17 00:00:00 2001 From: Krishna Chaitanya Chundru Date: Sat, 1 Nov 2025 09:29:36 +0530 Subject: [PATCH 2291/2333] BACKPORT: PCI: qcom: Add support for assert_perst() Add support for assert_perst() for switches like TC9563, which require configuration before the PCIe link is established. Such devices use this function op to assert the PERST# before configuring the device and once the configuration is done they de-assert the PERST#. Acked-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/20251101-tc9563-v9-5-de3429f7787a@oss.qualcomm.com Signed-off-by: Krishna Chaitanya Chundru --- drivers/pci/controller/dwc/pcie-qcom.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c index c48a20602d7fa..32bb9ed58bf7a 100644 --- a/drivers/pci/controller/dwc/pcie-qcom.c +++ b/drivers/pci/controller/dwc/pcie-qcom.c @@ -641,6 +641,18 @@ static int qcom_pcie_post_init_1_0_0(struct qcom_pcie *pcie) return 0; } +static int qcom_pcie_assert_perst(struct dw_pcie *pci, bool assert) +{ + struct qcom_pcie *pcie = to_qcom_pcie(pci); + + if (assert) + qcom_ep_reset_assert(pcie); + else + qcom_ep_reset_deassert(pcie); + + return 0; +} + static void qcom_pcie_2_3_2_ltssm_enable(struct qcom_pcie *pcie) { u32 val; @@ -1480,6 +1492,7 @@ static const struct qcom_pcie_cfg cfg_fw_managed = { static const struct dw_pcie_ops dw_pcie_ops = { .link_up = qcom_pcie_link_up, .start_link = qcom_pcie_start_link, + .assert_perst = qcom_pcie_assert_perst, }; static int qcom_pcie_icc_init(struct qcom_pcie *pcie) From 68615ecd8ff96ed3dae311774e0c5fd066722c9c Mon Sep 17 00:00:00 2001 From: Krishna Chaitanya Chundru Date: Sat, 1 Nov 2025 09:29:37 +0530 Subject: [PATCH 2292/2333] BACKPORT: PCI: pwrctrl: Add power control driver for TC9563 TC9563 is a PCIe switch which has one upstream and three downstream ports. To one of the downstream ports integrated ethernet MAC is connected as endpoint device. Other two downstream ports are supposed to connect to external device. One Host can connect to TC9563 by upstream port. TC9563 switch needs to be configured after powering on and before the PCIe link was up. The PCIe controller driver already enables link training at the host side even before this driver probe happens, due to this when driver enables power to the switch it participates in the link training and PCIe link may come up before configuring the switch through I2C. Once the link is up the configuration done through I2C will not have any effect. To prevent the host from participating in link training, disable link training on the host side to ensure the link does not come up before the switch is configured via I2C. Based on dt property and type of the port, TC9563 is configured through I2C. Reviewed-by: Bjorn Andersson Reviewed-by: Bartosz Golaszewski Reviewed-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/20251101-tc9563-v9-6-de3429f7787a@oss.qualcomm.com Signed-off-by: Krishna Chaitanya Chundru --- drivers/pci/pwrctrl/Kconfig | 14 + drivers/pci/pwrctrl/Makefile | 2 + drivers/pci/pwrctrl/pci-pwrctrl-tc9563.c | 648 +++++++++++++++++++++++ 3 files changed, 664 insertions(+) create mode 100644 drivers/pci/pwrctrl/pci-pwrctrl-tc9563.c diff --git a/drivers/pci/pwrctrl/Kconfig b/drivers/pci/pwrctrl/Kconfig index 6956c18548114..b43fdf052d376 100644 --- a/drivers/pci/pwrctrl/Kconfig +++ b/drivers/pci/pwrctrl/Kconfig @@ -22,6 +22,20 @@ config PCI_PWRCTRL_SLOT PCI slots. The voltage regulators powering the rails of the PCI slots are expected to be defined in the devicetree node of the PCI bridge. +config PCI_PWRCTRL_TC9563 + tristate "PCI Power Control driver for TC9563 PCIe switch" + select PCI_PWRCTRL + default m if ARCH_QCOM + help + Say Y here to enable the PCI Power Control driver of TC9563 PCIe + switch. + + This driver enables power and configures the TC9563 PCIe switch + through i2c. TC9563 is a PCIe switch which has one upstream and three + downstream ports. To one of the downstream ports integrated ethernet + MAC is connected as endpoint device. Other two downstream ports are + supposed to connect to external device. + # deprecated config HAVE_PWRCTL bool diff --git a/drivers/pci/pwrctrl/Makefile b/drivers/pci/pwrctrl/Makefile index a4e5808d7850c..13b02282106c2 100644 --- a/drivers/pci/pwrctrl/Makefile +++ b/drivers/pci/pwrctrl/Makefile @@ -7,3 +7,5 @@ obj-$(CONFIG_PCI_PWRCTRL_PWRSEQ) += pci-pwrctrl-pwrseq.o obj-$(CONFIG_PCI_PWRCTRL_SLOT) += pci-pwrctrl-slot.o pci-pwrctrl-slot-y := slot.o + +obj-$(CONFIG_PCI_PWRCTRL_TC9563) += pci-pwrctrl-tc9563.o diff --git a/drivers/pci/pwrctrl/pci-pwrctrl-tc9563.c b/drivers/pci/pwrctrl/pci-pwrctrl-tc9563.c new file mode 100644 index 0000000000000..46339a23204f6 --- /dev/null +++ b/drivers/pci/pwrctrl/pci-pwrctrl-tc9563.c @@ -0,0 +1,648 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../pci.h" + +#define TC9563_GPIO_CONFIG 0x801208 +#define TC9563_RESET_GPIO 0x801210 + +#define TC9563_PORT_L0S_DELAY 0x82496c +#define TC9563_PORT_L1_DELAY 0x824970 + +#define TC9563_EMBEDDED_ETH_DELAY 0x8200d8 +#define TC9563_ETH_L1_DELAY_MASK GENMASK(27, 18) +#define TC9563_ETH_L1_DELAY_VALUE(x) FIELD_PREP(TC9563_ETH_L1_DELAY_MASK, x) +#define TC9563_ETH_L0S_DELAY_MASK GENMASK(17, 13) +#define TC9563_ETH_L0S_DELAY_VALUE(x) FIELD_PREP(TC9563_ETH_L0S_DELAY_MASK, x) + +#define TC9563_NFTS_2_5_GT 0x824978 +#define TC9563_NFTS_5_GT 0x82497c + +#define TC9563_PORT_LANE_ACCESS_ENABLE 0x828000 + +#define TC9563_PHY_RATE_CHANGE_OVERRIDE 0x828040 +#define TC9563_PHY_RATE_CHANGE 0x828050 + +#define TC9563_TX_MARGIN 0x828234 + +#define TC9563_DFE_ENABLE 0x828a04 +#define TC9563_DFE_EQ0_MODE 0x828a08 +#define TC9563_DFE_EQ1_MODE 0x828a0c +#define TC9563_DFE_EQ2_MODE 0x828a14 +#define TC9563_DFE_PD_MASK 0x828254 + +#define TC9563_PORT_SELECT 0x82c02c +#define TC9563_PORT_ACCESS_ENABLE 0x82c030 + +#define TC9563_POWER_CONTROL 0x82b09c +#define TC9563_POWER_CONTROL_OVREN 0x82b2c8 + +#define TC9563_GPIO_MASK 0xfffffff3 +#define TC9563_GPIO_DEASSERT_BITS 0xc /* Bits to clear for GPIO deassert */ + +#define TC9563_TX_MARGIN_MIN_UA 400000 + +/* + * From TC9563 PORSYS rev 0.2, figure 1.1 POR boot sequence + * wait for 10ms for the internal osc frequency to stabilize. + */ +#define TC9563_OSC_STAB_DELAY_US (10 * USEC_PER_MSEC) + +#define TC9563_L0S_L1_DELAY_UNIT_NS 256 /* Each unit represents 256 nanoseconds */ + +struct tc9563_pwrctrl_reg_setting { + unsigned int offset; + unsigned int val; +}; + +enum tc9563_pwrctrl_ports { + TC9563_USP, + TC9563_DSP1, + TC9563_DSP2, + TC9563_DSP3, + TC9563_ETHERNET, + TC9563_MAX +}; + +struct tc9563_pwrctrl_cfg { + u32 l0s_delay; + u32 l1_delay; + u32 tx_amp; + u8 nfts[2]; /* GEN1 & GEN2 */ + bool disable_dfe; + bool disable_port; +}; + +#define TC9563_PWRCTL_MAX_SUPPLY 6 + +static const char *const tc9563_supply_names[TC9563_PWRCTL_MAX_SUPPLY] = { + "vddc", + "vdd18", + "vdd09", + "vddio1", + "vddio2", + "vddio18", +}; + +struct tc9563_pwrctrl_ctx { + struct regulator_bulk_data supplies[TC9563_PWRCTL_MAX_SUPPLY]; + struct tc9563_pwrctrl_cfg cfg[TC9563_MAX]; + struct gpio_desc *reset_gpio; + struct i2c_adapter *adapter; + struct i2c_client *client; + struct pci_pwrctrl pwrctrl; +}; + +/* + * downstream port power off sequence, hardcoding the address + * as we don't know register names for these register offsets. + */ +static const struct tc9563_pwrctrl_reg_setting common_pwroff_seq[] = { + {0x82900c, 0x1}, + {0x829010, 0x1}, + {0x829018, 0x0}, + {0x829020, 0x1}, + {0x82902c, 0x1}, + {0x829030, 0x1}, + {0x82903c, 0x1}, + {0x829058, 0x0}, + {0x82905c, 0x1}, + {0x829060, 0x1}, + {0x8290cc, 0x1}, + {0x8290d0, 0x1}, + {0x8290d8, 0x1}, + {0x8290e0, 0x1}, + {0x8290e8, 0x1}, + {0x8290ec, 0x1}, + {0x8290f4, 0x1}, + {0x82910c, 0x1}, + {0x829110, 0x1}, + {0x829114, 0x1}, +}; + +static const struct tc9563_pwrctrl_reg_setting dsp1_pwroff_seq[] = { + {TC9563_PORT_ACCESS_ENABLE, 0x2}, + {TC9563_PORT_LANE_ACCESS_ENABLE, 0x3}, + {TC9563_POWER_CONTROL, 0x014f4804}, + {TC9563_POWER_CONTROL_OVREN, 0x1}, + {TC9563_PORT_ACCESS_ENABLE, 0x4}, +}; + +static const struct tc9563_pwrctrl_reg_setting dsp2_pwroff_seq[] = { + {TC9563_PORT_ACCESS_ENABLE, 0x8}, + {TC9563_PORT_LANE_ACCESS_ENABLE, 0x1}, + {TC9563_POWER_CONTROL, 0x014f4804}, + {TC9563_POWER_CONTROL_OVREN, 0x1}, + {TC9563_PORT_ACCESS_ENABLE, 0x8}, +}; + +/* + * Since all transfers are initiated by the probe, no locks are necessary, + * as there are no concurrent calls. + */ +static int tc9563_pwrctrl_i2c_write(struct i2c_client *client, + u32 reg_addr, u32 reg_val) +{ + struct i2c_msg msg; + u8 msg_buf[7]; + int ret; + + msg.addr = client->addr; + msg.len = 7; + msg.flags = 0; + + /* Big Endian for reg addr */ + put_unaligned_be24(reg_addr, &msg_buf[0]); + + /* Little Endian for reg val */ + put_unaligned_le32(reg_val, &msg_buf[3]); + + msg.buf = msg_buf; + ret = i2c_transfer(client->adapter, &msg, 1); + return ret == 1 ? 0 : ret; +} + +static int tc9563_pwrctrl_i2c_read(struct i2c_client *client, + u32 reg_addr, u32 *reg_val) +{ + struct i2c_msg msg[2]; + u8 wr_data[3]; + u32 rd_data; + int ret; + + msg[0].addr = client->addr; + msg[0].len = 3; + msg[0].flags = 0; + + /* Big Endian for reg addr */ + put_unaligned_be24(reg_addr, &wr_data[0]); + + msg[0].buf = wr_data; + + msg[1].addr = client->addr; + msg[1].len = 4; + msg[1].flags = I2C_M_RD; + + msg[1].buf = (u8 *)&rd_data; + + ret = i2c_transfer(client->adapter, &msg[0], 2); + if (ret == 2) { + *reg_val = get_unaligned_le32(&rd_data); + return 0; + } + + /* If only one message successfully completed, return -EIO */ + return ret == 1 ? -EIO : ret; +} + +static int tc9563_pwrctrl_i2c_bulk_write(struct i2c_client *client, + const struct tc9563_pwrctrl_reg_setting *seq, int len) +{ + int ret, i; + + for (i = 0; i < len; i++) { + ret = tc9563_pwrctrl_i2c_write(client, seq[i].offset, seq[i].val); + if (ret) + return ret; + } + + return 0; +} + +static int tc9563_pwrctrl_disable_port(struct tc9563_pwrctrl_ctx *ctx, + enum tc9563_pwrctrl_ports port) +{ + struct tc9563_pwrctrl_cfg *cfg = &ctx->cfg[port]; + const struct tc9563_pwrctrl_reg_setting *seq; + int ret, len; + + if (!cfg->disable_port) + return 0; + + if (port == TC9563_DSP1) { + seq = dsp1_pwroff_seq; + len = ARRAY_SIZE(dsp1_pwroff_seq); + } else { + seq = dsp2_pwroff_seq; + len = ARRAY_SIZE(dsp2_pwroff_seq); + } + + ret = tc9563_pwrctrl_i2c_bulk_write(ctx->client, seq, len); + if (ret) + return ret; + + return tc9563_pwrctrl_i2c_bulk_write(ctx->client, + common_pwroff_seq, ARRAY_SIZE(common_pwroff_seq)); +} + +static int tc9563_pwrctrl_set_l0s_l1_entry_delay(struct tc9563_pwrctrl_ctx *ctx, + enum tc9563_pwrctrl_ports port, bool is_l1, u32 ns) +{ + u32 rd_val, units; + int ret; + + if (ns < TC9563_L0S_L1_DELAY_UNIT_NS) + return 0; + + /* convert to units of 256ns */ + units = ns / TC9563_L0S_L1_DELAY_UNIT_NS; + + if (port == TC9563_ETHERNET) { + ret = tc9563_pwrctrl_i2c_read(ctx->client, TC9563_EMBEDDED_ETH_DELAY, &rd_val); + if (ret) + return ret; + + if (is_l1) + rd_val = u32_replace_bits(rd_val, units, TC9563_ETH_L1_DELAY_MASK); + else + rd_val = u32_replace_bits(rd_val, units, TC9563_ETH_L0S_DELAY_MASK); + + return tc9563_pwrctrl_i2c_write(ctx->client, TC9563_EMBEDDED_ETH_DELAY, rd_val); + } + + ret = tc9563_pwrctrl_i2c_write(ctx->client, TC9563_PORT_SELECT, BIT(port)); + if (ret) + return ret; + + return tc9563_pwrctrl_i2c_write(ctx->client, + is_l1 ? TC9563_PORT_L1_DELAY : TC9563_PORT_L0S_DELAY, units); +} + +static int tc9563_pwrctrl_set_tx_amplitude(struct tc9563_pwrctrl_ctx *ctx, + enum tc9563_pwrctrl_ports port) +{ + u32 amp = ctx->cfg[port].tx_amp; + int port_access; + + if (amp < TC9563_TX_MARGIN_MIN_UA) + return 0; + + /* txmargin = (Amp(uV) - 400000) / 3125 */ + amp = (amp - TC9563_TX_MARGIN_MIN_UA) / 3125; + + switch (port) { + case TC9563_USP: + port_access = 0x1; + break; + case TC9563_DSP1: + port_access = 0x2; + break; + case TC9563_DSP2: + port_access = 0x8; + break; + default: + return -EINVAL; + }; + + struct tc9563_pwrctrl_reg_setting tx_amp_seq[] = { + {TC9563_PORT_ACCESS_ENABLE, port_access}, + {TC9563_PORT_LANE_ACCESS_ENABLE, 0x3}, + {TC9563_TX_MARGIN, amp}, + }; + + return tc9563_pwrctrl_i2c_bulk_write(ctx->client, tx_amp_seq, ARRAY_SIZE(tx_amp_seq)); +} + +static int tc9563_pwrctrl_disable_dfe(struct tc9563_pwrctrl_ctx *ctx, + enum tc9563_pwrctrl_ports port) +{ + struct tc9563_pwrctrl_cfg *cfg = &ctx->cfg[port]; + int port_access, lane_access = 0x3; + u32 phy_rate = 0x21; + + if (!cfg->disable_dfe) + return 0; + + switch (port) { + case TC9563_USP: + phy_rate = 0x1; + port_access = 0x1; + break; + case TC9563_DSP1: + port_access = 0x2; + break; + case TC9563_DSP2: + port_access = 0x8; + lane_access = 0x1; + break; + default: + return -EINVAL; + }; + + struct tc9563_pwrctrl_reg_setting disable_dfe_seq[] = { + {TC9563_PORT_ACCESS_ENABLE, port_access}, + {TC9563_PORT_LANE_ACCESS_ENABLE, lane_access}, + {TC9563_DFE_ENABLE, 0x0}, + {TC9563_DFE_EQ0_MODE, 0x411}, + {TC9563_DFE_EQ1_MODE, 0x11}, + {TC9563_DFE_EQ2_MODE, 0x11}, + {TC9563_DFE_PD_MASK, 0x7}, + {TC9563_PHY_RATE_CHANGE_OVERRIDE, 0x10}, + {TC9563_PHY_RATE_CHANGE, phy_rate}, + {TC9563_PHY_RATE_CHANGE, 0x0}, + {TC9563_PHY_RATE_CHANGE_OVERRIDE, 0x0}, + }; + + return tc9563_pwrctrl_i2c_bulk_write(ctx->client, + disable_dfe_seq, ARRAY_SIZE(disable_dfe_seq)); +} + +static int tc9563_pwrctrl_set_nfts(struct tc9563_pwrctrl_ctx *ctx, + enum tc9563_pwrctrl_ports port) +{ + u8 *nfts = ctx->cfg[port].nfts; + struct tc9563_pwrctrl_reg_setting nfts_seq[] = { + {TC9563_NFTS_2_5_GT, nfts[0]}, + {TC9563_NFTS_5_GT, nfts[1]}, + }; + int ret; + + if (!nfts[0]) + return 0; + + ret = tc9563_pwrctrl_i2c_write(ctx->client, TC9563_PORT_SELECT, BIT(port)); + if (ret) + return ret; + + return tc9563_pwrctrl_i2c_bulk_write(ctx->client, nfts_seq, ARRAY_SIZE(nfts_seq)); +} + +static int tc9563_pwrctrl_assert_deassert_reset(struct tc9563_pwrctrl_ctx *ctx, bool deassert) +{ + int ret, val; + + ret = tc9563_pwrctrl_i2c_write(ctx->client, TC9563_GPIO_CONFIG, TC9563_GPIO_MASK); + if (ret) + return ret; + + val = deassert ? TC9563_GPIO_DEASSERT_BITS : 0; + + return tc9563_pwrctrl_i2c_write(ctx->client, TC9563_RESET_GPIO, val); +} + +static int tc9563_pwrctrl_parse_device_dt(struct tc9563_pwrctrl_ctx *ctx, struct device_node *node, + enum tc9563_pwrctrl_ports port) +{ + struct tc9563_pwrctrl_cfg *cfg = &ctx->cfg[port]; + int ret; + + /* Disable port if the status of the port is disabled. */ + if (!of_device_is_available(node)) { + cfg->disable_port = true; + return 0; + }; + + ret = of_property_read_u32(node, "aspm-l0s-entry-delay-ns", &cfg->l0s_delay); + if (ret && ret != -EINVAL) + return ret; + + ret = of_property_read_u32(node, "aspm-l1-entry-delay-ns", &cfg->l1_delay); + if (ret && ret != -EINVAL) + return ret; + + ret = of_property_read_u32(node, "toshiba,tx-amplitude-microvolt", &cfg->tx_amp); + if (ret && ret != -EINVAL) + return ret; + + ret = of_property_read_u8_array(node, "n-fts", cfg->nfts, ARRAY_SIZE(cfg->nfts)); + if (ret && ret != -EINVAL) + return ret; + + cfg->disable_dfe = of_property_read_bool(node, "toshiba,no-dfe-support"); + + return 0; +} + +static void tc9563_pwrctrl_power_off(struct tc9563_pwrctrl_ctx *ctx) +{ + gpiod_set_value(ctx->reset_gpio, 1); + + regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies); +} + +static int tc9563_pwrctrl_bring_up(struct tc9563_pwrctrl_ctx *ctx) +{ + struct tc9563_pwrctrl_cfg *cfg; + int ret, i; + + ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies); + if (ret < 0) + return dev_err_probe(ctx->pwrctrl.dev, ret, "cannot enable regulators\n"); + + gpiod_set_value(ctx->reset_gpio, 0); + + fsleep(TC9563_OSC_STAB_DELAY_US); + + ret = tc9563_pwrctrl_assert_deassert_reset(ctx, false); + if (ret) + goto power_off; + + for (i = 0; i < TC9563_MAX; i++) { + cfg = &ctx->cfg[i]; + ret = tc9563_pwrctrl_disable_port(ctx, i); + if (ret) { + dev_err(ctx->pwrctrl.dev, "Disabling port failed\n"); + goto power_off; + } + + ret = tc9563_pwrctrl_set_l0s_l1_entry_delay(ctx, i, false, cfg->l0s_delay); + if (ret) { + dev_err(ctx->pwrctrl.dev, "Setting L0s entry delay failed\n"); + goto power_off; + } + + ret = tc9563_pwrctrl_set_l0s_l1_entry_delay(ctx, i, true, cfg->l1_delay); + if (ret) { + dev_err(ctx->pwrctrl.dev, "Setting L1 entry delay failed\n"); + goto power_off; + } + + ret = tc9563_pwrctrl_set_tx_amplitude(ctx, i); + if (ret) { + dev_err(ctx->pwrctrl.dev, "Setting Tx amplitude failed\n"); + goto power_off; + } + + ret = tc9563_pwrctrl_set_nfts(ctx, i); + if (ret) { + dev_err(ctx->pwrctrl.dev, "Setting N_FTS failed\n"); + goto power_off; + } + + ret = tc9563_pwrctrl_disable_dfe(ctx, i); + if (ret) { + dev_err(ctx->pwrctrl.dev, "Disabling DFE failed\n"); + goto power_off; + } + } + + ret = tc9563_pwrctrl_assert_deassert_reset(ctx, true); + if (!ret) + return 0; + +power_off: + tc9563_pwrctrl_power_off(ctx); + return ret; +} + +static int tc9563_pwrctrl_probe(struct platform_device *pdev) +{ + struct pci_host_bridge *bridge = to_pci_host_bridge(pdev->dev.parent); + struct pci_bus *bus = bridge->bus; + struct device *dev = &pdev->dev; + enum tc9563_pwrctrl_ports port; + struct tc9563_pwrctrl_ctx *ctx; + struct device_node *i2c_node; + int ret, addr; + + ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + ret = of_property_read_u32_index(pdev->dev.of_node, "i2c-parent", 1, &addr); + if (ret) + return dev_err_probe(dev, ret, "Failed to read i2c-parent property\n"); + + i2c_node = of_parse_phandle(dev->of_node, "i2c-parent", 0); + ctx->adapter = of_find_i2c_adapter_by_node(i2c_node); + of_node_put(i2c_node); + if (!ctx->adapter) + return dev_err_probe(dev, -EPROBE_DEFER, "Failed to find I2C adapter\n"); + + ctx->client = i2c_new_dummy_device(ctx->adapter, addr); + if (IS_ERR(ctx->client)) { + dev_err(dev, "Failed to create I2C client\n"); + i2c_put_adapter(ctx->adapter); + return PTR_ERR(ctx->client); + } + + for (int i = 0; i < ARRAY_SIZE(tc9563_supply_names); i++) + ctx->supplies[i].supply = tc9563_supply_names[i]; + + ret = devm_regulator_bulk_get(dev, TC9563_PWRCTL_MAX_SUPPLY, ctx->supplies); + if (ret) { + dev_err_probe(dev, ret, "failed to get supply regulator\n"); + goto remove_i2c; + } + + ctx->reset_gpio = devm_gpiod_get(dev, "resx", GPIOD_OUT_HIGH); + if (IS_ERR(ctx->reset_gpio)) { + ret = dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), "failed to get resx GPIO\n"); + goto remove_i2c; + } + + pci_pwrctrl_init(&ctx->pwrctrl, dev); + + port = TC9563_USP; + ret = tc9563_pwrctrl_parse_device_dt(ctx, pdev->dev.of_node, port); + if (ret) { + dev_err(dev, "failed to parse device tree properties: %d\n", ret); + goto remove_i2c; + } + + /* + * Downstream ports are always children of the upstream port. + * The first node represents DSP1, the second node represents DSP2, and so on. + */ + for_each_child_of_node_scoped(pdev->dev.of_node, child) { + port++; + ret = tc9563_pwrctrl_parse_device_dt(ctx, child, port); + if (ret) + break; + /* Embedded ethernet device are under DSP3 */ + if (port == TC9563_DSP3) { + for_each_child_of_node_scoped(child, child1) { + port++; + ret = tc9563_pwrctrl_parse_device_dt(ctx, child1, port); + if (ret) + break; + } + } + } + if (ret) { + dev_err(dev, "failed to parse device tree properties: %d\n", ret); + goto remove_i2c; + } + + if (bridge->ops->assert_perst) { + ret = bridge->ops->assert_perst(bus, true); + if (ret) + goto remove_i2c; + } + + ret = tc9563_pwrctrl_bring_up(ctx); + if (ret) + goto remove_i2c; + + if (bridge->ops->assert_perst) { + ret = bridge->ops->assert_perst(bus, false); + if (ret) + goto power_off; + } + + ret = devm_pci_pwrctrl_device_set_ready(dev, &ctx->pwrctrl); + if (ret) + goto power_off; + + platform_set_drvdata(pdev, ctx); + + return 0; + +power_off: + tc9563_pwrctrl_power_off(ctx); +remove_i2c: + i2c_unregister_device(ctx->client); + i2c_put_adapter(ctx->adapter); + return ret; +} + +static void tc9563_pwrctrl_remove(struct platform_device *pdev) +{ + struct tc9563_pwrctrl_ctx *ctx = platform_get_drvdata(pdev); + + tc9563_pwrctrl_power_off(ctx); + i2c_unregister_device(ctx->client); + i2c_put_adapter(ctx->adapter); +} + +static const struct of_device_id tc9563_pwrctrl_of_match[] = { + { .compatible = "pci1179,0623"}, + { } +}; +MODULE_DEVICE_TABLE(of, tc9563_pwrctrl_of_match); + +static struct platform_driver tc9563_pwrctrl_driver = { + .driver = { + .name = "pwrctrl-tc9563", + .of_match_table = tc9563_pwrctrl_of_match, + .probe_type = PROBE_PREFER_ASYNCHRONOUS, + }, + .probe = tc9563_pwrctrl_probe, + .remove = tc9563_pwrctrl_remove, +}; +module_platform_driver(tc9563_pwrctrl_driver); + +MODULE_AUTHOR("Krishna chaitanya chundru "); +MODULE_DESCRIPTION("TC956x power control driver"); +MODULE_LICENSE("GPL"); From 99cf5e15d12dd84549e67cdaaa83eab2ebda9127 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Thu, 20 Nov 2025 12:21:15 +0530 Subject: [PATCH 2293/2333] BACKPORT: PCI/pwrctrl: tc9563: Enforce I2C dependency This driver depends on the I2C interface to configure the switch. So enforce the dependency in Kconfig so that the I2C interface is selected appropriately. This also avoids the build issues like the one reported by the LKP bot: alpha-linux-ld: alpha-linux-ld: DWARF error: could not find abbrev number 14070 drivers/pci/pwrctrl/pci-pwrctrl-tc9563.o: in function `tc9563_pwrctrl_remove': >> (.text+0x4c): undefined reference to `i2c_unregister_device' >> alpha-linux-ld: (.text+0x50): undefined reference to `i2c_unregister_device' >> alpha-linux-ld: (.text+0x60): undefined reference to `i2c_put_adapter' alpha-linux-ld: (.text+0x64): undefined reference to `i2c_put_adapter' Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202511200555.M4TX84jK-lkp@intel.com Signed-off-by: Manivannan Sadhasivam Acked-by: Bartosz Golaszewski --- drivers/pci/pwrctrl/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/pci/pwrctrl/Kconfig b/drivers/pci/pwrctrl/Kconfig index b43fdf052d376..e0f999f299bb9 100644 --- a/drivers/pci/pwrctrl/Kconfig +++ b/drivers/pci/pwrctrl/Kconfig @@ -26,6 +26,7 @@ config PCI_PWRCTRL_TC9563 tristate "PCI Power Control driver for TC9563 PCIe switch" select PCI_PWRCTRL default m if ARCH_QCOM + depends on I2C help Say Y here to enable the PCI Power Control driver of TC9563 PCIe switch. From 98d8e200c4fa41cc919f87516faa74fbf6997099 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Thu, 20 Nov 2025 12:21:16 +0530 Subject: [PATCH 2294/2333] BACKPORT: PCI/pwrctrl: tc9563: Remove unnecessary semicolons As reported by the LKP bot, semicolons are not needed at the end of the switch and if blocks. Hence, remove them. This fixes the below cocci warnings: cocci warnings: (new ones prefixed by >>) >> drivers/pci/pwrctrl/pci-pwrctrl-tc9563.c:351:2-3: Unneeded semicolon drivers/pci/pwrctrl/pci-pwrctrl-tc9563.c:414:2-3: Unneeded semicolon drivers/pci/pwrctrl/pci-pwrctrl-tc9563.c:316:2-3: Unneeded semicolon Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202511200555.M4TX84jK-lkp@intel.com Signed-off-by: Manivannan Sadhasivam Acked-by: Bartosz Golaszewski --- drivers/pci/pwrctrl/pci-pwrctrl-tc9563.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/pci/pwrctrl/pci-pwrctrl-tc9563.c b/drivers/pci/pwrctrl/pci-pwrctrl-tc9563.c index 46339a23204f6..ec423432ac655 100644 --- a/drivers/pci/pwrctrl/pci-pwrctrl-tc9563.c +++ b/drivers/pci/pwrctrl/pci-pwrctrl-tc9563.c @@ -313,7 +313,7 @@ static int tc9563_pwrctrl_set_tx_amplitude(struct tc9563_pwrctrl_ctx *ctx, break; default: return -EINVAL; - }; + } struct tc9563_pwrctrl_reg_setting tx_amp_seq[] = { {TC9563_PORT_ACCESS_ENABLE, port_access}, @@ -348,7 +348,7 @@ static int tc9563_pwrctrl_disable_dfe(struct tc9563_pwrctrl_ctx *ctx, break; default: return -EINVAL; - }; + } struct tc9563_pwrctrl_reg_setting disable_dfe_seq[] = { {TC9563_PORT_ACCESS_ENABLE, port_access}, @@ -411,7 +411,7 @@ static int tc9563_pwrctrl_parse_device_dt(struct tc9563_pwrctrl_ctx *ctx, struct if (!of_device_is_available(node)) { cfg->disable_port = true; return 0; - }; + } ret = of_property_read_u32(node, "aspm-l0s-entry-delay-ns", &cfg->l0s_delay); if (ret && ret != -EINVAL) From dd9954b36d4c36d66c4207fe287a3a94edb1582f Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Thu, 15 Jan 2026 12:58:53 +0530 Subject: [PATCH 2295/2333] FROMLIST: PCI/pwrctrl: pwrseq: Rename private struct and pointers for consistency Previously the pwrseq, tc9563, and slot pwrctrl drivers used different naming conventions for their private data structs and pointers to them, which makes patches hard to read: Previous names New names ------------------------------------ ---------------------------------- struct pci_pwrctrl_pwrseq_data { struct pci_pwrctrl_pwrseq { struct pci_pwrctrl ctx; struct pci_pwrctrl pwrctrl; struct pci_pwrctrl_pwrseq_data *data struct pci_pwrctrl_pwrseq *pwrseq struct tc9563_pwrctrl_ctx { struct pci_pwrctrl_tc9563 { struct tc9563_pwrctrl_ctx *ctx struct pci_pwrctrl_tc9563 *tc9563 struct pci_pwrctrl_slot_data { struct pci_pwrctrl_slot { struct pci_pwrctrl ctx; struct pci_pwrctrl pwrctrl; struct pci_pwrctrl_slot_data *slot struct pci_pwrctrl_slot *slot Rename "struct pci_pwrctrl_pwrseq_data" to "pci_pwrctrl_pwrseq". Rename the "struct pci_pwrctrl ctx" member to "struct pci_pwrctrl pwrctrl". Rename pointers from "struct pci_pwrctrl_pwrseq_data *data" to "struct pci_pwrctrl_pwrseq *pwrseq". No functional change intended. Link: https://lore.kernel.org/all/20260115-pci-pwrctrl-rework-v5-1-9d26da3ce903@oss.qualcomm.com/ Signed-off-by: Bjorn Helgaas Signed-off-by: Manivannan Sadhasivam Reviewed-by: Bartosz Golaszewski --- drivers/pci/pwrctrl/pci-pwrctrl-pwrseq.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/pci/pwrctrl/pci-pwrctrl-pwrseq.c b/drivers/pci/pwrctrl/pci-pwrctrl-pwrseq.c index 4e664e7b8dd23..c0d22dc3a8561 100644 --- a/drivers/pci/pwrctrl/pci-pwrctrl-pwrseq.c +++ b/drivers/pci/pwrctrl/pci-pwrctrl-pwrseq.c @@ -13,8 +13,8 @@ #include #include -struct pci_pwrctrl_pwrseq_data { - struct pci_pwrctrl ctx; +struct pci_pwrctrl_pwrseq { + struct pci_pwrctrl pwrctrl; struct pwrseq_desc *pwrseq; }; @@ -62,7 +62,7 @@ static void devm_pci_pwrctrl_pwrseq_power_off(void *data) static int pci_pwrctrl_pwrseq_probe(struct platform_device *pdev) { const struct pci_pwrctrl_pwrseq_pdata *pdata; - struct pci_pwrctrl_pwrseq_data *data; + struct pci_pwrctrl_pwrseq *pwrseq; struct device *dev = &pdev->dev; int ret; @@ -76,28 +76,28 @@ static int pci_pwrctrl_pwrseq_probe(struct platform_device *pdev) return ret; } - data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); - if (!data) + pwrseq = devm_kzalloc(dev, sizeof(*pwrseq), GFP_KERNEL); + if (!pwrseq) return -ENOMEM; - data->pwrseq = devm_pwrseq_get(dev, pdata->target); - if (IS_ERR(data->pwrseq)) - return dev_err_probe(dev, PTR_ERR(data->pwrseq), + pwrseq->pwrseq = devm_pwrseq_get(dev, pdata->target); + if (IS_ERR(pwrseq->pwrseq)) + return dev_err_probe(dev, PTR_ERR(pwrseq->pwrseq), "Failed to get the power sequencer\n"); - ret = pwrseq_power_on(data->pwrseq); + ret = pwrseq_power_on(pwrseq->pwrseq); if (ret) return dev_err_probe(dev, ret, "Failed to power-on the device\n"); ret = devm_add_action_or_reset(dev, devm_pci_pwrctrl_pwrseq_power_off, - data->pwrseq); + pwrseq->pwrseq); if (ret) return ret; - pci_pwrctrl_init(&data->ctx, dev); + pci_pwrctrl_init(&pwrseq->pwrctrl, dev); - ret = devm_pci_pwrctrl_device_set_ready(dev, &data->ctx); + ret = devm_pci_pwrctrl_device_set_ready(dev, &pwrseq->pwrctrl); if (ret) return dev_err_probe(dev, ret, "Failed to register the pwrctrl wrapper\n"); From 465c21457d266abed36f5f92b7c880d159ba3021 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Thu, 15 Jan 2026 12:58:54 +0530 Subject: [PATCH 2296/2333] FROMLIST: PCI/pwrctrl: slot: Rename private struct and pointers for consistency Previously the pwrseq, tc9563, and slot pwrctrl drivers used different naming conventions for their private data structs and pointers to them, which makes patches hard to read: Previous names New names ------------------------------------ ---------------------------------- struct pci_pwrctrl_pwrseq_data { struct pci_pwrctrl_pwrseq { struct pci_pwrctrl ctx; struct pci_pwrctrl pwrctrl; struct pci_pwrctrl_pwrseq_data *data struct pci_pwrctrl_pwrseq *pwrseq struct tc9563_pwrctrl_ctx { struct pci_pwrctrl_tc9563 { struct tc9563_pwrctrl_ctx *ctx struct pci_pwrctrl_tc9563 *tc9563 struct pci_pwrctrl_slot_data { struct pci_pwrctrl_slot { struct pci_pwrctrl ctx; struct pci_pwrctrl pwrctrl; struct pci_pwrctrl_slot_data *slot struct pci_pwrctrl_slot *slot Rename "struct pci_pwrctrl_slot_data" to "struct pci_pwrctrl_slot". Rename the "struct pci_pwrctrl ctx" member to "struct pci_pwrctrl pwrctrl". No functional change intended. Link: https://lore.kernel.org/all/20260115-pci-pwrctrl-rework-v5-2-9d26da3ce903@oss.qualcomm.com/ Signed-off-by: Bjorn Helgaas Signed-off-by: Manivannan Sadhasivam Reviewed-by: Bartosz Golaszewski --- drivers/pci/pwrctrl/slot.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/pci/pwrctrl/slot.c b/drivers/pci/pwrctrl/slot.c index 3320494b62d89..5ddae4ae34315 100644 --- a/drivers/pci/pwrctrl/slot.c +++ b/drivers/pci/pwrctrl/slot.c @@ -13,15 +13,15 @@ #include #include -struct pci_pwrctrl_slot_data { - struct pci_pwrctrl ctx; +struct pci_pwrctrl_slot { + struct pci_pwrctrl pwrctrl; struct regulator_bulk_data *supplies; int num_supplies; }; static void devm_pci_pwrctrl_slot_power_off(void *data) { - struct pci_pwrctrl_slot_data *slot = data; + struct pci_pwrctrl_slot *slot = data; regulator_bulk_disable(slot->num_supplies, slot->supplies); regulator_bulk_free(slot->num_supplies, slot->supplies); @@ -29,7 +29,7 @@ static void devm_pci_pwrctrl_slot_power_off(void *data) static int pci_pwrctrl_slot_probe(struct platform_device *pdev) { - struct pci_pwrctrl_slot_data *slot; + struct pci_pwrctrl_slot *slot; struct device *dev = &pdev->dev; struct clk *clk; int ret; @@ -64,9 +64,9 @@ static int pci_pwrctrl_slot_probe(struct platform_device *pdev) "Failed to enable slot clock\n"); } - pci_pwrctrl_init(&slot->ctx, dev); + pci_pwrctrl_init(&slot->pwrctrl, dev); - ret = devm_pci_pwrctrl_device_set_ready(dev, &slot->ctx); + ret = devm_pci_pwrctrl_device_set_ready(dev, &slot->pwrctrl); if (ret) return dev_err_probe(dev, ret, "Failed to register pwrctrl driver\n"); From 19ff27d284939777b6da487e627e57dd1d7da2ef Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Thu, 15 Jan 2026 12:58:55 +0530 Subject: [PATCH 2297/2333] FROMLIST: PCI/pwrctrl: tc9563: Use put_device() instead of i2c_put_adapter() The API comment for of_find_i2c_adapter_by_node() recommends using put_device() to drop the reference count of I2C adapter instead of using i2c_put_adapter(). So replace i2c_put_adapter() with put_device(). Link: https://lore.kernel.org/all/20260115-pci-pwrctrl-rework-v5-3-9d26da3ce903@oss.qualcomm.com/ Fixes: 4c9c7be47310 ("PCI: pwrctrl: Add power control driver for TC9563") Signed-off-by: Bjorn Helgaas Signed-off-by: Manivannan Sadhasivam Reviewed-by: Bartosz Golaszewski --- drivers/pci/pwrctrl/pci-pwrctrl-tc9563.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/pci/pwrctrl/pci-pwrctrl-tc9563.c b/drivers/pci/pwrctrl/pci-pwrctrl-tc9563.c index ec423432ac655..0a63add84d095 100644 --- a/drivers/pci/pwrctrl/pci-pwrctrl-tc9563.c +++ b/drivers/pci/pwrctrl/pci-pwrctrl-tc9563.c @@ -533,7 +533,7 @@ static int tc9563_pwrctrl_probe(struct platform_device *pdev) ctx->client = i2c_new_dummy_device(ctx->adapter, addr); if (IS_ERR(ctx->client)) { dev_err(dev, "Failed to create I2C client\n"); - i2c_put_adapter(ctx->adapter); + put_device(&ctx->adapter->dev); return PTR_ERR(ctx->client); } @@ -613,7 +613,7 @@ static int tc9563_pwrctrl_probe(struct platform_device *pdev) tc9563_pwrctrl_power_off(ctx); remove_i2c: i2c_unregister_device(ctx->client); - i2c_put_adapter(ctx->adapter); + put_device(&ctx->adapter->dev); return ret; } @@ -623,7 +623,7 @@ static void tc9563_pwrctrl_remove(struct platform_device *pdev) tc9563_pwrctrl_power_off(ctx); i2c_unregister_device(ctx->client); - i2c_put_adapter(ctx->adapter); + put_device(&ctx->adapter->dev); } static const struct of_device_id tc9563_pwrctrl_of_match[] = { From 5d6d896365cc3dac436090d366560c024a23aa85 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Thu, 15 Jan 2026 12:58:56 +0530 Subject: [PATCH 2298/2333] FROMLIST: PCI/pwrctrl: tc9563: Clean up whitespace Most of pci-pwrctrl-tc9563.c fits in 80 columns. Wrap lines that are gratuitously longer. Whitespace changes only. Signed-off-by: Bjorn Helgaas Signed-off-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/20260115-pci-pwrctrl-rework-v5-4-9d26da3ce903@oss.qualcomm.com --- drivers/pci/pwrctrl/pci-pwrctrl-tc9563.c | 65 +++++++++++++++--------- 1 file changed, 42 insertions(+), 23 deletions(-) diff --git a/drivers/pci/pwrctrl/pci-pwrctrl-tc9563.c b/drivers/pci/pwrctrl/pci-pwrctrl-tc9563.c index 0a63add84d095..efc4d2054bfda 100644 --- a/drivers/pci/pwrctrl/pci-pwrctrl-tc9563.c +++ b/drivers/pci/pwrctrl/pci-pwrctrl-tc9563.c @@ -59,7 +59,7 @@ #define TC9563_POWER_CONTROL_OVREN 0x82b2c8 #define TC9563_GPIO_MASK 0xfffffff3 -#define TC9563_GPIO_DEASSERT_BITS 0xc /* Bits to clear for GPIO deassert */ +#define TC9563_GPIO_DEASSERT_BITS 0xc /* Clear to deassert GPIO */ #define TC9563_TX_MARGIN_MIN_UA 400000 @@ -69,7 +69,7 @@ */ #define TC9563_OSC_STAB_DELAY_US (10 * USEC_PER_MSEC) -#define TC9563_L0S_L1_DELAY_UNIT_NS 256 /* Each unit represents 256 nanoseconds */ +#define TC9563_L0S_L1_DELAY_UNIT_NS 256 /* Each unit represents 256 ns */ struct tc9563_pwrctrl_reg_setting { unsigned int offset; @@ -217,7 +217,8 @@ static int tc9563_pwrctrl_i2c_read(struct i2c_client *client, } static int tc9563_pwrctrl_i2c_bulk_write(struct i2c_client *client, - const struct tc9563_pwrctrl_reg_setting *seq, int len) + const struct tc9563_pwrctrl_reg_setting *seq, + int len) { int ret, i; @@ -252,12 +253,13 @@ static int tc9563_pwrctrl_disable_port(struct tc9563_pwrctrl_ctx *ctx, if (ret) return ret; - return tc9563_pwrctrl_i2c_bulk_write(ctx->client, - common_pwroff_seq, ARRAY_SIZE(common_pwroff_seq)); + return tc9563_pwrctrl_i2c_bulk_write(ctx->client, common_pwroff_seq, + ARRAY_SIZE(common_pwroff_seq)); } static int tc9563_pwrctrl_set_l0s_l1_entry_delay(struct tc9563_pwrctrl_ctx *ctx, - enum tc9563_pwrctrl_ports port, bool is_l1, u32 ns) + enum tc9563_pwrctrl_ports port, + bool is_l1, u32 ns) { u32 rd_val, units; int ret; @@ -269,24 +271,32 @@ static int tc9563_pwrctrl_set_l0s_l1_entry_delay(struct tc9563_pwrctrl_ctx *ctx, units = ns / TC9563_L0S_L1_DELAY_UNIT_NS; if (port == TC9563_ETHERNET) { - ret = tc9563_pwrctrl_i2c_read(ctx->client, TC9563_EMBEDDED_ETH_DELAY, &rd_val); + ret = tc9563_pwrctrl_i2c_read(ctx->client, + TC9563_EMBEDDED_ETH_DELAY, + &rd_val); if (ret) return ret; if (is_l1) - rd_val = u32_replace_bits(rd_val, units, TC9563_ETH_L1_DELAY_MASK); + rd_val = u32_replace_bits(rd_val, units, + TC9563_ETH_L1_DELAY_MASK); else - rd_val = u32_replace_bits(rd_val, units, TC9563_ETH_L0S_DELAY_MASK); + rd_val = u32_replace_bits(rd_val, units, + TC9563_ETH_L0S_DELAY_MASK); - return tc9563_pwrctrl_i2c_write(ctx->client, TC9563_EMBEDDED_ETH_DELAY, rd_val); + return tc9563_pwrctrl_i2c_write(ctx->client, + TC9563_EMBEDDED_ETH_DELAY, + rd_val); } - ret = tc9563_pwrctrl_i2c_write(ctx->client, TC9563_PORT_SELECT, BIT(port)); + ret = tc9563_pwrctrl_i2c_write(ctx->client, TC9563_PORT_SELECT, + BIT(port)); if (ret) return ret; return tc9563_pwrctrl_i2c_write(ctx->client, - is_l1 ? TC9563_PORT_L1_DELAY : TC9563_PORT_L0S_DELAY, units); + is_l1 ? TC9563_PORT_L1_DELAY : TC9563_PORT_L0S_DELAY, + units); } static int tc9563_pwrctrl_set_tx_amplitude(struct tc9563_pwrctrl_ctx *ctx, @@ -321,7 +331,8 @@ static int tc9563_pwrctrl_set_tx_amplitude(struct tc9563_pwrctrl_ctx *ctx, {TC9563_TX_MARGIN, amp}, }; - return tc9563_pwrctrl_i2c_bulk_write(ctx->client, tx_amp_seq, ARRAY_SIZE(tx_amp_seq)); + return tc9563_pwrctrl_i2c_bulk_write(ctx->client, tx_amp_seq, + ARRAY_SIZE(tx_amp_seq)); } static int tc9563_pwrctrl_disable_dfe(struct tc9563_pwrctrl_ctx *ctx, @@ -364,8 +375,8 @@ static int tc9563_pwrctrl_disable_dfe(struct tc9563_pwrctrl_ctx *ctx, {TC9563_PHY_RATE_CHANGE_OVERRIDE, 0x0}, }; - return tc9563_pwrctrl_i2c_bulk_write(ctx->client, - disable_dfe_seq, ARRAY_SIZE(disable_dfe_seq)); + return tc9563_pwrctrl_i2c_bulk_write(ctx->client, disable_dfe_seq, + ARRAY_SIZE(disable_dfe_seq)); } static int tc9563_pwrctrl_set_nfts(struct tc9563_pwrctrl_ctx *ctx, @@ -381,18 +392,22 @@ static int tc9563_pwrctrl_set_nfts(struct tc9563_pwrctrl_ctx *ctx, if (!nfts[0]) return 0; - ret = tc9563_pwrctrl_i2c_write(ctx->client, TC9563_PORT_SELECT, BIT(port)); + ret = tc9563_pwrctrl_i2c_write(ctx->client, TC9563_PORT_SELECT, + BIT(port)); if (ret) return ret; - return tc9563_pwrctrl_i2c_bulk_write(ctx->client, nfts_seq, ARRAY_SIZE(nfts_seq)); + return tc9563_pwrctrl_i2c_bulk_write(ctx->client, nfts_seq, + ARRAY_SIZE(nfts_seq)); } -static int tc9563_pwrctrl_assert_deassert_reset(struct tc9563_pwrctrl_ctx *ctx, bool deassert) +static int tc9563_pwrctrl_assert_deassert_reset(struct tc9563_pwrctrl_ctx *ctx, + bool deassert) { int ret, val; - ret = tc9563_pwrctrl_i2c_write(ctx->client, TC9563_GPIO_CONFIG, TC9563_GPIO_MASK); + ret = tc9563_pwrctrl_i2c_write(ctx->client, TC9563_GPIO_CONFIG, + TC9563_GPIO_MASK); if (ret) return ret; @@ -401,7 +416,8 @@ static int tc9563_pwrctrl_assert_deassert_reset(struct tc9563_pwrctrl_ctx *ctx, return tc9563_pwrctrl_i2c_write(ctx->client, TC9563_RESET_GPIO, val); } -static int tc9563_pwrctrl_parse_device_dt(struct tc9563_pwrctrl_ctx *ctx, struct device_node *node, +static int tc9563_pwrctrl_parse_device_dt(struct tc9563_pwrctrl_ctx *ctx, + struct device_node *node, enum tc9563_pwrctrl_ports port) { struct tc9563_pwrctrl_cfg *cfg = &ctx->cfg[port]; @@ -540,7 +556,8 @@ static int tc9563_pwrctrl_probe(struct platform_device *pdev) for (int i = 0; i < ARRAY_SIZE(tc9563_supply_names); i++) ctx->supplies[i].supply = tc9563_supply_names[i]; - ret = devm_regulator_bulk_get(dev, TC9563_PWRCTL_MAX_SUPPLY, ctx->supplies); + ret = devm_regulator_bulk_get(dev, TC9563_PWRCTL_MAX_SUPPLY, + ctx->supplies); if (ret) { dev_err_probe(dev, ret, "failed to get supply regulator\n"); goto remove_i2c; @@ -563,7 +580,8 @@ static int tc9563_pwrctrl_probe(struct platform_device *pdev) /* * Downstream ports are always children of the upstream port. - * The first node represents DSP1, the second node represents DSP2, and so on. + * The first node represents DSP1, the second node represents DSP2, + * and so on. */ for_each_child_of_node_scoped(pdev->dev.of_node, child) { port++; @@ -574,7 +592,8 @@ static int tc9563_pwrctrl_probe(struct platform_device *pdev) if (port == TC9563_DSP3) { for_each_child_of_node_scoped(child, child1) { port++; - ret = tc9563_pwrctrl_parse_device_dt(ctx, child1, port); + ret = tc9563_pwrctrl_parse_device_dt(ctx, + child1, port); if (ret) break; } From fbe8c529e0c4a93ee57da1d986650cb2fe71e97b Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Thu, 15 Jan 2026 12:58:57 +0530 Subject: [PATCH 2299/2333] FROMLIST: PCI/pwrctrl: tc9563: Add local variables to reduce repetition Add local struct device * and struct device_node * variables to reduce repetitive pointer chasing. No functional changes intended. Signed-off-by: Bjorn Helgaas Signed-off-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/20260115-pci-pwrctrl-rework-v5-5-9d26da3ce903@oss.qualcomm.com --- drivers/pci/pwrctrl/pci-pwrctrl-tc9563.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/drivers/pci/pwrctrl/pci-pwrctrl-tc9563.c b/drivers/pci/pwrctrl/pci-pwrctrl-tc9563.c index efc4d2054bfda..90480e35e968f 100644 --- a/drivers/pci/pwrctrl/pci-pwrctrl-tc9563.c +++ b/drivers/pci/pwrctrl/pci-pwrctrl-tc9563.c @@ -459,12 +459,13 @@ static void tc9563_pwrctrl_power_off(struct tc9563_pwrctrl_ctx *ctx) static int tc9563_pwrctrl_bring_up(struct tc9563_pwrctrl_ctx *ctx) { + struct device *dev = ctx->pwrctrl.dev; struct tc9563_pwrctrl_cfg *cfg; int ret, i; ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies); if (ret < 0) - return dev_err_probe(ctx->pwrctrl.dev, ret, "cannot enable regulators\n"); + return dev_err_probe(dev, ret, "cannot enable regulators\n"); gpiod_set_value(ctx->reset_gpio, 0); @@ -478,37 +479,37 @@ static int tc9563_pwrctrl_bring_up(struct tc9563_pwrctrl_ctx *ctx) cfg = &ctx->cfg[i]; ret = tc9563_pwrctrl_disable_port(ctx, i); if (ret) { - dev_err(ctx->pwrctrl.dev, "Disabling port failed\n"); + dev_err(dev, "Disabling port failed\n"); goto power_off; } ret = tc9563_pwrctrl_set_l0s_l1_entry_delay(ctx, i, false, cfg->l0s_delay); if (ret) { - dev_err(ctx->pwrctrl.dev, "Setting L0s entry delay failed\n"); + dev_err(dev, "Setting L0s entry delay failed\n"); goto power_off; } ret = tc9563_pwrctrl_set_l0s_l1_entry_delay(ctx, i, true, cfg->l1_delay); if (ret) { - dev_err(ctx->pwrctrl.dev, "Setting L1 entry delay failed\n"); + dev_err(dev, "Setting L1 entry delay failed\n"); goto power_off; } ret = tc9563_pwrctrl_set_tx_amplitude(ctx, i); if (ret) { - dev_err(ctx->pwrctrl.dev, "Setting Tx amplitude failed\n"); + dev_err(dev, "Setting Tx amplitude failed\n"); goto power_off; } ret = tc9563_pwrctrl_set_nfts(ctx, i); if (ret) { - dev_err(ctx->pwrctrl.dev, "Setting N_FTS failed\n"); + dev_err(dev, "Setting N_FTS failed\n"); goto power_off; } ret = tc9563_pwrctrl_disable_dfe(ctx, i); if (ret) { - dev_err(ctx->pwrctrl.dev, "Disabling DFE failed\n"); + dev_err(dev, "Disabling DFE failed\n"); goto power_off; } } @@ -525,6 +526,7 @@ static int tc9563_pwrctrl_bring_up(struct tc9563_pwrctrl_ctx *ctx) static int tc9563_pwrctrl_probe(struct platform_device *pdev) { struct pci_host_bridge *bridge = to_pci_host_bridge(pdev->dev.parent); + struct device_node *node = pdev->dev.of_node; struct pci_bus *bus = bridge->bus; struct device *dev = &pdev->dev; enum tc9563_pwrctrl_ports port; @@ -536,7 +538,7 @@ static int tc9563_pwrctrl_probe(struct platform_device *pdev) if (!ctx) return -ENOMEM; - ret = of_property_read_u32_index(pdev->dev.of_node, "i2c-parent", 1, &addr); + ret = of_property_read_u32_index(node, "i2c-parent", 1, &addr); if (ret) return dev_err_probe(dev, ret, "Failed to read i2c-parent property\n"); @@ -572,7 +574,7 @@ static int tc9563_pwrctrl_probe(struct platform_device *pdev) pci_pwrctrl_init(&ctx->pwrctrl, dev); port = TC9563_USP; - ret = tc9563_pwrctrl_parse_device_dt(ctx, pdev->dev.of_node, port); + ret = tc9563_pwrctrl_parse_device_dt(ctx, node, port); if (ret) { dev_err(dev, "failed to parse device tree properties: %d\n", ret); goto remove_i2c; @@ -583,7 +585,7 @@ static int tc9563_pwrctrl_probe(struct platform_device *pdev) * The first node represents DSP1, the second node represents DSP2, * and so on. */ - for_each_child_of_node_scoped(pdev->dev.of_node, child) { + for_each_child_of_node_scoped(node, child) { port++; ret = tc9563_pwrctrl_parse_device_dt(ctx, child, port); if (ret) From 41a2cdaa9909521611b6c88e39512ef8eb394a04 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Thu, 15 Jan 2026 12:58:58 +0530 Subject: [PATCH 2300/2333] FROMLIST: PCI/pwrctrl: tc9563: Rename private struct and pointers for consistency Previously the pwrseq, tc9563, and slot pwrctrl drivers used different naming conventions for their private data structs and pointers to them, which makes patches hard to read: Previous names New names ------------------------------------ ---------------------------------- struct pci_pwrctrl_pwrseq_data { struct pci_pwrctrl_pwrseq { struct pci_pwrctrl ctx; struct pci_pwrctrl pwrctrl; struct pci_pwrctrl_pwrseq_data *data struct pci_pwrctrl_pwrseq *pwrseq struct tc9563_pwrctrl_ctx { struct pci_pwrctrl_tc9563 { struct tc9563_pwrctrl_ctx *ctx struct pci_pwrctrl_tc9563 *tc9563 struct pci_pwrctrl_slot_data { struct pci_pwrctrl_slot { struct pci_pwrctrl ctx; struct pci_pwrctrl pwrctrl; struct pci_pwrctrl_slot_data *slot struct pci_pwrctrl_slot *slot Rename "struct tc9563_pwrctrl_ctx" to "pci_pwrctrl_tc9563". Move the struct pci_pwrctrl member to be the first element in struct pci_pwrctrl_tc9563, as it is in the other drivers. Rename pointers from "struct tc9563_pwrctrl_ctx *ctx" to "struct pci_pwrctrl_tc9563 *tc9563". No functional change intended. Signed-off-by: Bjorn Helgaas Signed-off-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/20260115-pci-pwrctrl-rework-v5-6-9d26da3ce903@oss.qualcomm.com --- drivers/pci/pwrctrl/pci-pwrctrl-tc9563.c | 143 ++++++++++++----------- 1 file changed, 72 insertions(+), 71 deletions(-) diff --git a/drivers/pci/pwrctrl/pci-pwrctrl-tc9563.c b/drivers/pci/pwrctrl/pci-pwrctrl-tc9563.c index 90480e35e968f..8ae27abdf3620 100644 --- a/drivers/pci/pwrctrl/pci-pwrctrl-tc9563.c +++ b/drivers/pci/pwrctrl/pci-pwrctrl-tc9563.c @@ -105,13 +105,13 @@ static const char *const tc9563_supply_names[TC9563_PWRCTL_MAX_SUPPLY] = { "vddio18", }; -struct tc9563_pwrctrl_ctx { +struct pci_pwrctrl_tc9563 { + struct pci_pwrctrl pwrctrl; struct regulator_bulk_data supplies[TC9563_PWRCTL_MAX_SUPPLY]; struct tc9563_pwrctrl_cfg cfg[TC9563_MAX]; struct gpio_desc *reset_gpio; struct i2c_adapter *adapter; struct i2c_client *client; - struct pci_pwrctrl pwrctrl; }; /* @@ -231,10 +231,10 @@ static int tc9563_pwrctrl_i2c_bulk_write(struct i2c_client *client, return 0; } -static int tc9563_pwrctrl_disable_port(struct tc9563_pwrctrl_ctx *ctx, +static int tc9563_pwrctrl_disable_port(struct pci_pwrctrl_tc9563 *tc9563, enum tc9563_pwrctrl_ports port) { - struct tc9563_pwrctrl_cfg *cfg = &ctx->cfg[port]; + struct tc9563_pwrctrl_cfg *cfg = &tc9563->cfg[port]; const struct tc9563_pwrctrl_reg_setting *seq; int ret, len; @@ -249,15 +249,15 @@ static int tc9563_pwrctrl_disable_port(struct tc9563_pwrctrl_ctx *ctx, len = ARRAY_SIZE(dsp2_pwroff_seq); } - ret = tc9563_pwrctrl_i2c_bulk_write(ctx->client, seq, len); + ret = tc9563_pwrctrl_i2c_bulk_write(tc9563->client, seq, len); if (ret) return ret; - return tc9563_pwrctrl_i2c_bulk_write(ctx->client, common_pwroff_seq, + return tc9563_pwrctrl_i2c_bulk_write(tc9563->client, common_pwroff_seq, ARRAY_SIZE(common_pwroff_seq)); } -static int tc9563_pwrctrl_set_l0s_l1_entry_delay(struct tc9563_pwrctrl_ctx *ctx, +static int tc9563_pwrctrl_set_l0s_l1_entry_delay(struct pci_pwrctrl_tc9563 *tc9563, enum tc9563_pwrctrl_ports port, bool is_l1, u32 ns) { @@ -271,7 +271,7 @@ static int tc9563_pwrctrl_set_l0s_l1_entry_delay(struct tc9563_pwrctrl_ctx *ctx, units = ns / TC9563_L0S_L1_DELAY_UNIT_NS; if (port == TC9563_ETHERNET) { - ret = tc9563_pwrctrl_i2c_read(ctx->client, + ret = tc9563_pwrctrl_i2c_read(tc9563->client, TC9563_EMBEDDED_ETH_DELAY, &rd_val); if (ret) @@ -284,25 +284,25 @@ static int tc9563_pwrctrl_set_l0s_l1_entry_delay(struct tc9563_pwrctrl_ctx *ctx, rd_val = u32_replace_bits(rd_val, units, TC9563_ETH_L0S_DELAY_MASK); - return tc9563_pwrctrl_i2c_write(ctx->client, + return tc9563_pwrctrl_i2c_write(tc9563->client, TC9563_EMBEDDED_ETH_DELAY, rd_val); } - ret = tc9563_pwrctrl_i2c_write(ctx->client, TC9563_PORT_SELECT, + ret = tc9563_pwrctrl_i2c_write(tc9563->client, TC9563_PORT_SELECT, BIT(port)); if (ret) return ret; - return tc9563_pwrctrl_i2c_write(ctx->client, + return tc9563_pwrctrl_i2c_write(tc9563->client, is_l1 ? TC9563_PORT_L1_DELAY : TC9563_PORT_L0S_DELAY, units); } -static int tc9563_pwrctrl_set_tx_amplitude(struct tc9563_pwrctrl_ctx *ctx, +static int tc9563_pwrctrl_set_tx_amplitude(struct pci_pwrctrl_tc9563 *tc9563, enum tc9563_pwrctrl_ports port) { - u32 amp = ctx->cfg[port].tx_amp; + u32 amp = tc9563->cfg[port].tx_amp; int port_access; if (amp < TC9563_TX_MARGIN_MIN_UA) @@ -331,14 +331,14 @@ static int tc9563_pwrctrl_set_tx_amplitude(struct tc9563_pwrctrl_ctx *ctx, {TC9563_TX_MARGIN, amp}, }; - return tc9563_pwrctrl_i2c_bulk_write(ctx->client, tx_amp_seq, + return tc9563_pwrctrl_i2c_bulk_write(tc9563->client, tx_amp_seq, ARRAY_SIZE(tx_amp_seq)); } -static int tc9563_pwrctrl_disable_dfe(struct tc9563_pwrctrl_ctx *ctx, +static int tc9563_pwrctrl_disable_dfe(struct pci_pwrctrl_tc9563 *tc9563, enum tc9563_pwrctrl_ports port) { - struct tc9563_pwrctrl_cfg *cfg = &ctx->cfg[port]; + struct tc9563_pwrctrl_cfg *cfg = &tc9563->cfg[port]; int port_access, lane_access = 0x3; u32 phy_rate = 0x21; @@ -375,14 +375,14 @@ static int tc9563_pwrctrl_disable_dfe(struct tc9563_pwrctrl_ctx *ctx, {TC9563_PHY_RATE_CHANGE_OVERRIDE, 0x0}, }; - return tc9563_pwrctrl_i2c_bulk_write(ctx->client, disable_dfe_seq, + return tc9563_pwrctrl_i2c_bulk_write(tc9563->client, disable_dfe_seq, ARRAY_SIZE(disable_dfe_seq)); } -static int tc9563_pwrctrl_set_nfts(struct tc9563_pwrctrl_ctx *ctx, +static int tc9563_pwrctrl_set_nfts(struct pci_pwrctrl_tc9563 *tc9563, enum tc9563_pwrctrl_ports port) { - u8 *nfts = ctx->cfg[port].nfts; + u8 *nfts = tc9563->cfg[port].nfts; struct tc9563_pwrctrl_reg_setting nfts_seq[] = { {TC9563_NFTS_2_5_GT, nfts[0]}, {TC9563_NFTS_5_GT, nfts[1]}, @@ -392,35 +392,35 @@ static int tc9563_pwrctrl_set_nfts(struct tc9563_pwrctrl_ctx *ctx, if (!nfts[0]) return 0; - ret = tc9563_pwrctrl_i2c_write(ctx->client, TC9563_PORT_SELECT, + ret = tc9563_pwrctrl_i2c_write(tc9563->client, TC9563_PORT_SELECT, BIT(port)); if (ret) return ret; - return tc9563_pwrctrl_i2c_bulk_write(ctx->client, nfts_seq, + return tc9563_pwrctrl_i2c_bulk_write(tc9563->client, nfts_seq, ARRAY_SIZE(nfts_seq)); } -static int tc9563_pwrctrl_assert_deassert_reset(struct tc9563_pwrctrl_ctx *ctx, +static int tc9563_pwrctrl_assert_deassert_reset(struct pci_pwrctrl_tc9563 *tc9563, bool deassert) { int ret, val; - ret = tc9563_pwrctrl_i2c_write(ctx->client, TC9563_GPIO_CONFIG, + ret = tc9563_pwrctrl_i2c_write(tc9563->client, TC9563_GPIO_CONFIG, TC9563_GPIO_MASK); if (ret) return ret; val = deassert ? TC9563_GPIO_DEASSERT_BITS : 0; - return tc9563_pwrctrl_i2c_write(ctx->client, TC9563_RESET_GPIO, val); + return tc9563_pwrctrl_i2c_write(tc9563->client, TC9563_RESET_GPIO, val); } -static int tc9563_pwrctrl_parse_device_dt(struct tc9563_pwrctrl_ctx *ctx, +static int tc9563_pwrctrl_parse_device_dt(struct pci_pwrctrl_tc9563 *tc9563, struct device_node *node, enum tc9563_pwrctrl_ports port) { - struct tc9563_pwrctrl_cfg *cfg = &ctx->cfg[port]; + struct tc9563_pwrctrl_cfg *cfg = &tc9563->cfg[port]; int ret; /* Disable port if the status of the port is disabled. */ @@ -450,76 +450,77 @@ static int tc9563_pwrctrl_parse_device_dt(struct tc9563_pwrctrl_ctx *ctx, return 0; } -static void tc9563_pwrctrl_power_off(struct tc9563_pwrctrl_ctx *ctx) +static void tc9563_pwrctrl_power_off(struct pci_pwrctrl_tc9563 *tc9563) { - gpiod_set_value(ctx->reset_gpio, 1); + gpiod_set_value(tc9563->reset_gpio, 1); - regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies); + regulator_bulk_disable(ARRAY_SIZE(tc9563->supplies), tc9563->supplies); } -static int tc9563_pwrctrl_bring_up(struct tc9563_pwrctrl_ctx *ctx) +static int tc9563_pwrctrl_bring_up(struct pci_pwrctrl_tc9563 *tc9563) { - struct device *dev = ctx->pwrctrl.dev; + struct device *dev = tc9563->pwrctrl.dev; struct tc9563_pwrctrl_cfg *cfg; int ret, i; - ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies); + ret = regulator_bulk_enable(ARRAY_SIZE(tc9563->supplies), + tc9563->supplies); if (ret < 0) return dev_err_probe(dev, ret, "cannot enable regulators\n"); - gpiod_set_value(ctx->reset_gpio, 0); + gpiod_set_value(tc9563->reset_gpio, 0); fsleep(TC9563_OSC_STAB_DELAY_US); - ret = tc9563_pwrctrl_assert_deassert_reset(ctx, false); + ret = tc9563_pwrctrl_assert_deassert_reset(tc9563, false); if (ret) goto power_off; for (i = 0; i < TC9563_MAX; i++) { - cfg = &ctx->cfg[i]; - ret = tc9563_pwrctrl_disable_port(ctx, i); + cfg = &tc9563->cfg[i]; + ret = tc9563_pwrctrl_disable_port(tc9563, i); if (ret) { dev_err(dev, "Disabling port failed\n"); goto power_off; } - ret = tc9563_pwrctrl_set_l0s_l1_entry_delay(ctx, i, false, cfg->l0s_delay); + ret = tc9563_pwrctrl_set_l0s_l1_entry_delay(tc9563, i, false, cfg->l0s_delay); if (ret) { dev_err(dev, "Setting L0s entry delay failed\n"); goto power_off; } - ret = tc9563_pwrctrl_set_l0s_l1_entry_delay(ctx, i, true, cfg->l1_delay); + ret = tc9563_pwrctrl_set_l0s_l1_entry_delay(tc9563, i, true, cfg->l1_delay); if (ret) { dev_err(dev, "Setting L1 entry delay failed\n"); goto power_off; } - ret = tc9563_pwrctrl_set_tx_amplitude(ctx, i); + ret = tc9563_pwrctrl_set_tx_amplitude(tc9563, i); if (ret) { dev_err(dev, "Setting Tx amplitude failed\n"); goto power_off; } - ret = tc9563_pwrctrl_set_nfts(ctx, i); + ret = tc9563_pwrctrl_set_nfts(tc9563, i); if (ret) { dev_err(dev, "Setting N_FTS failed\n"); goto power_off; } - ret = tc9563_pwrctrl_disable_dfe(ctx, i); + ret = tc9563_pwrctrl_disable_dfe(tc9563, i); if (ret) { dev_err(dev, "Disabling DFE failed\n"); goto power_off; } } - ret = tc9563_pwrctrl_assert_deassert_reset(ctx, true); + ret = tc9563_pwrctrl_assert_deassert_reset(tc9563, true); if (!ret) return 0; power_off: - tc9563_pwrctrl_power_off(ctx); + tc9563_pwrctrl_power_off(tc9563); return ret; } @@ -530,12 +531,12 @@ static int tc9563_pwrctrl_probe(struct platform_device *pdev) struct pci_bus *bus = bridge->bus; struct device *dev = &pdev->dev; enum tc9563_pwrctrl_ports port; - struct tc9563_pwrctrl_ctx *ctx; + struct pci_pwrctrl_tc9563 *tc9563; struct device_node *i2c_node; int ret, addr; - ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) + tc9563 = devm_kzalloc(dev, sizeof(*tc9563), GFP_KERNEL); + if (!tc9563) return -ENOMEM; ret = of_property_read_u32_index(node, "i2c-parent", 1, &addr); @@ -543,38 +544,38 @@ static int tc9563_pwrctrl_probe(struct platform_device *pdev) return dev_err_probe(dev, ret, "Failed to read i2c-parent property\n"); i2c_node = of_parse_phandle(dev->of_node, "i2c-parent", 0); - ctx->adapter = of_find_i2c_adapter_by_node(i2c_node); + tc9563->adapter = of_find_i2c_adapter_by_node(i2c_node); of_node_put(i2c_node); - if (!ctx->adapter) + if (!tc9563->adapter) return dev_err_probe(dev, -EPROBE_DEFER, "Failed to find I2C adapter\n"); - ctx->client = i2c_new_dummy_device(ctx->adapter, addr); - if (IS_ERR(ctx->client)) { + tc9563->client = i2c_new_dummy_device(tc9563->adapter, addr); + if (IS_ERR(tc9563->client)) { dev_err(dev, "Failed to create I2C client\n"); - put_device(&ctx->adapter->dev); - return PTR_ERR(ctx->client); + put_device(&tc9563->adapter->dev); + return PTR_ERR(tc9563->client); } for (int i = 0; i < ARRAY_SIZE(tc9563_supply_names); i++) - ctx->supplies[i].supply = tc9563_supply_names[i]; + tc9563->supplies[i].supply = tc9563_supply_names[i]; ret = devm_regulator_bulk_get(dev, TC9563_PWRCTL_MAX_SUPPLY, - ctx->supplies); + tc9563->supplies); if (ret) { dev_err_probe(dev, ret, "failed to get supply regulator\n"); goto remove_i2c; } - ctx->reset_gpio = devm_gpiod_get(dev, "resx", GPIOD_OUT_HIGH); - if (IS_ERR(ctx->reset_gpio)) { - ret = dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), "failed to get resx GPIO\n"); + tc9563->reset_gpio = devm_gpiod_get(dev, "resx", GPIOD_OUT_HIGH); + if (IS_ERR(tc9563->reset_gpio)) { + ret = dev_err_probe(dev, PTR_ERR(tc9563->reset_gpio), "failed to get resx GPIO\n"); goto remove_i2c; } - pci_pwrctrl_init(&ctx->pwrctrl, dev); + pci_pwrctrl_init(&tc9563->pwrctrl, dev); port = TC9563_USP; - ret = tc9563_pwrctrl_parse_device_dt(ctx, node, port); + ret = tc9563_pwrctrl_parse_device_dt(tc9563, node, port); if (ret) { dev_err(dev, "failed to parse device tree properties: %d\n", ret); goto remove_i2c; @@ -587,14 +588,14 @@ static int tc9563_pwrctrl_probe(struct platform_device *pdev) */ for_each_child_of_node_scoped(node, child) { port++; - ret = tc9563_pwrctrl_parse_device_dt(ctx, child, port); + ret = tc9563_pwrctrl_parse_device_dt(tc9563, child, port); if (ret) break; /* Embedded ethernet device are under DSP3 */ if (port == TC9563_DSP3) { for_each_child_of_node_scoped(child, child1) { port++; - ret = tc9563_pwrctrl_parse_device_dt(ctx, + ret = tc9563_pwrctrl_parse_device_dt(tc9563, child1, port); if (ret) break; @@ -612,7 +613,7 @@ static int tc9563_pwrctrl_probe(struct platform_device *pdev) goto remove_i2c; } - ret = tc9563_pwrctrl_bring_up(ctx); + ret = tc9563_pwrctrl_bring_up(tc9563); if (ret) goto remove_i2c; @@ -622,29 +623,29 @@ static int tc9563_pwrctrl_probe(struct platform_device *pdev) goto power_off; } - ret = devm_pci_pwrctrl_device_set_ready(dev, &ctx->pwrctrl); + ret = devm_pci_pwrctrl_device_set_ready(dev, &tc9563->pwrctrl); if (ret) goto power_off; - platform_set_drvdata(pdev, ctx); + platform_set_drvdata(pdev, tc9563); return 0; power_off: - tc9563_pwrctrl_power_off(ctx); + tc9563_pwrctrl_power_off(tc9563); remove_i2c: - i2c_unregister_device(ctx->client); - put_device(&ctx->adapter->dev); + i2c_unregister_device(tc9563->client); + put_device(&tc9563->adapter->dev); return ret; } static void tc9563_pwrctrl_remove(struct platform_device *pdev) { - struct tc9563_pwrctrl_ctx *ctx = platform_get_drvdata(pdev); + struct pci_pwrctrl_tc9563 *tc9563 = platform_get_drvdata(pdev); - tc9563_pwrctrl_power_off(ctx); - i2c_unregister_device(ctx->client); - put_device(&ctx->adapter->dev); + tc9563_pwrctrl_power_off(tc9563); + i2c_unregister_device(tc9563->client); + put_device(&tc9563->adapter->dev); } static const struct of_device_id tc9563_pwrctrl_of_match[] = { From eeb58b72463158844380e95f266dd8445d513871 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Thu, 15 Jan 2026 12:58:59 +0530 Subject: [PATCH 2301/2333] FROMLIST: PCI/pwrctrl: slot: Factor out power on/off code to helpers In order to allow the pwrctrl core to control the power on/off logic of the pwrctrl slot driver, move the power on/off code to pci_pwrctrl_slot_power_{off/on} helper functions. Link: https://lore.kernel.org/all/20260115-pci-pwrctrl-rework-v5-7-9d26da3ce903@oss.qualcomm.com/ Signed-off-by: Manivannan Sadhasivam --- drivers/pci/pwrctrl/slot.c | 49 +++++++++++++++++++++++++++----------- 1 file changed, 35 insertions(+), 14 deletions(-) diff --git a/drivers/pci/pwrctrl/slot.c b/drivers/pci/pwrctrl/slot.c index 5ddae4ae34315..5d0ec880c0ecf 100644 --- a/drivers/pci/pwrctrl/slot.c +++ b/drivers/pci/pwrctrl/slot.c @@ -17,13 +17,40 @@ struct pci_pwrctrl_slot { struct pci_pwrctrl pwrctrl; struct regulator_bulk_data *supplies; int num_supplies; + struct clk *clk; }; -static void devm_pci_pwrctrl_slot_power_off(void *data) +static int pci_pwrctrl_slot_power_on(struct pci_pwrctrl *pwrctrl) { - struct pci_pwrctrl_slot *slot = data; + struct pci_pwrctrl_slot *slot = container_of(pwrctrl, + struct pci_pwrctrl_slot, pwrctrl); + int ret; + + ret = regulator_bulk_enable(slot->num_supplies, slot->supplies); + if (ret < 0) { + dev_err(slot->pwrctrl.dev, "Failed to enable slot regulators\n"); + return ret; + } + + return clk_prepare_enable(slot->clk); +} + +static int pci_pwrctrl_slot_power_off(struct pci_pwrctrl *pwrctrl) +{ + struct pci_pwrctrl_slot *slot = container_of(pwrctrl, + struct pci_pwrctrl_slot, pwrctrl); regulator_bulk_disable(slot->num_supplies, slot->supplies); + clk_disable_unprepare(slot->clk); + + return 0; +} + +static void devm_pci_pwrctrl_slot_release(void *data) +{ + struct pci_pwrctrl_slot *slot = data; + + pci_pwrctrl_slot_power_off(&slot->pwrctrl); regulator_bulk_free(slot->num_supplies, slot->supplies); } @@ -31,7 +58,6 @@ static int pci_pwrctrl_slot_probe(struct platform_device *pdev) { struct pci_pwrctrl_slot *slot; struct device *dev = &pdev->dev; - struct clk *clk; int ret; slot = devm_kzalloc(dev, sizeof(*slot), GFP_KERNEL); @@ -46,23 +72,18 @@ static int pci_pwrctrl_slot_probe(struct platform_device *pdev) } slot->num_supplies = ret; - ret = regulator_bulk_enable(slot->num_supplies, slot->supplies); - if (ret < 0) { - dev_err_probe(dev, ret, "Failed to enable slot regulators\n"); - regulator_bulk_free(slot->num_supplies, slot->supplies); - return ret; - } - ret = devm_add_action_or_reset(dev, devm_pci_pwrctrl_slot_power_off, + ret = devm_add_action_or_reset(dev, devm_pci_pwrctrl_slot_release, slot); if (ret) return ret; - clk = devm_clk_get_optional_enabled(dev, NULL); - if (IS_ERR(clk)) { - return dev_err_probe(dev, PTR_ERR(clk), + slot->clk = devm_clk_get_optional(dev, NULL); + if (IS_ERR(slot->clk)) + return dev_err_probe(dev, PTR_ERR(slot->clk), "Failed to enable slot clock\n"); - } + + pci_pwrctrl_slot_power_on(&slot->pwrctrl); pci_pwrctrl_init(&slot->pwrctrl, dev); From f5b81d8f5bb6961da972060c61ec1f29a772da17 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Thu, 15 Jan 2026 12:59:00 +0530 Subject: [PATCH 2302/2333] FROMLIST: PCI/pwrctrl: pwrseq: Factor out power on/off code to helpers In order to allow the pwrctrl core to control the power on/off logic of the pwrctrl pwrseq driver, move the power on/off code to pci_pwrctrl_pwrseq_power_{off/on} helper functions. Link: https://lore.kernel.org/all/20260115-pci-pwrctrl-rework-v5-8-9d26da3ce903@oss.qualcomm.com/ Signed-off-by: Manivannan Sadhasivam --- drivers/pci/pwrctrl/pci-pwrctrl-pwrseq.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/drivers/pci/pwrctrl/pci-pwrctrl-pwrseq.c b/drivers/pci/pwrctrl/pci-pwrctrl-pwrseq.c index c0d22dc3a8561..d2c261b09030f 100644 --- a/drivers/pci/pwrctrl/pci-pwrctrl-pwrseq.c +++ b/drivers/pci/pwrctrl/pci-pwrctrl-pwrseq.c @@ -52,11 +52,27 @@ static const struct pci_pwrctrl_pwrseq_pdata pci_pwrctrl_pwrseq_qcom_wcn_pdata = .validate_device = pci_pwrctrl_pwrseq_qcm_wcn_validate_device, }; +static int pci_pwrctrl_pwrseq_power_on(struct pci_pwrctrl *pwrctrl) +{ + struct pci_pwrctrl_pwrseq *pwrseq = container_of(pwrctrl, + struct pci_pwrctrl_pwrseq, pwrctrl); + + return pwrseq_power_on(pwrseq->pwrseq); +} + +static int pci_pwrctrl_pwrseq_power_off(struct pci_pwrctrl *pwrctrl) +{ + struct pci_pwrctrl_pwrseq *pwrseq = container_of(pwrctrl, + struct pci_pwrctrl_pwrseq, pwrctrl); + + return pwrseq_power_off(pwrseq->pwrseq); +} + static void devm_pci_pwrctrl_pwrseq_power_off(void *data) { - struct pwrseq_desc *pwrseq = data; + struct pci_pwrctrl_pwrseq *pwrseq = data; - pwrseq_power_off(pwrseq); + pci_pwrctrl_pwrseq_power_off(&pwrseq->pwrctrl); } static int pci_pwrctrl_pwrseq_probe(struct platform_device *pdev) @@ -85,13 +101,13 @@ static int pci_pwrctrl_pwrseq_probe(struct platform_device *pdev) return dev_err_probe(dev, PTR_ERR(pwrseq->pwrseq), "Failed to get the power sequencer\n"); - ret = pwrseq_power_on(pwrseq->pwrseq); + ret = pci_pwrctrl_pwrseq_power_on(&pwrseq->pwrctrl); if (ret) return dev_err_probe(dev, ret, "Failed to power-on the device\n"); ret = devm_add_action_or_reset(dev, devm_pci_pwrctrl_pwrseq_power_off, - pwrseq->pwrseq); + pwrseq); if (ret) return ret; From 44376a356be45eccafabcf0178496d67dd290b7f Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Thu, 15 Jan 2026 12:59:01 +0530 Subject: [PATCH 2303/2333] FROMLIST: PCI/pwrctrl: Add 'struct pci_pwrctrl::power_{on/off}' callbacks To allow the pwrctrl core to control the power on/off sequences of the pwrctrl drivers, add the 'struct pci_pwrctrl::power_{on/off}' callbacks and populate them in the respective pwrctrl drivers. The pwrctrl drivers still power on the resources on their own now. So there is no functional change. Co-developed-by: Krishna Chaitanya Chundru Signed-off-by: Manivannan Sadhasivam Signed-off-by: Bjorn Helgaas Tested-by: Chen-Yu Tsai Reviewed-by: Bartosz Golaszewski Link: https://lore.kernel.org/r/20260115-pci-pwrctrl-rework-v5-9-9d26da3ce903@oss.qualcomm.com Signed-off-by: Krishna Chaitanya Chundru --- drivers/pci/pwrctrl/pci-pwrctrl-pwrseq.c | 3 +++ drivers/pci/pwrctrl/pci-pwrctrl-tc9563.c | 22 ++++++++++++++++------ drivers/pci/pwrctrl/slot.c | 3 +++ include/linux/pci-pwrctrl.h | 4 ++++ 4 files changed, 26 insertions(+), 6 deletions(-) diff --git a/drivers/pci/pwrctrl/pci-pwrctrl-pwrseq.c b/drivers/pci/pwrctrl/pci-pwrctrl-pwrseq.c index d2c261b09030f..2ee02edd55a31 100644 --- a/drivers/pci/pwrctrl/pci-pwrctrl-pwrseq.c +++ b/drivers/pci/pwrctrl/pci-pwrctrl-pwrseq.c @@ -111,6 +111,9 @@ static int pci_pwrctrl_pwrseq_probe(struct platform_device *pdev) if (ret) return ret; + pwrseq->pwrctrl.power_on = pci_pwrctrl_pwrseq_power_on; + pwrseq->pwrctrl.power_off = pci_pwrctrl_pwrseq_power_off; + pci_pwrctrl_init(&pwrseq->pwrctrl, dev); ret = devm_pci_pwrctrl_device_set_ready(dev, &pwrseq->pwrctrl); diff --git a/drivers/pci/pwrctrl/pci-pwrctrl-tc9563.c b/drivers/pci/pwrctrl/pci-pwrctrl-tc9563.c index 8ae27abdf3620..a71d7ef2d4b89 100644 --- a/drivers/pci/pwrctrl/pci-pwrctrl-tc9563.c +++ b/drivers/pci/pwrctrl/pci-pwrctrl-tc9563.c @@ -450,15 +450,22 @@ static int tc9563_pwrctrl_parse_device_dt(struct pci_pwrctrl_tc9563 *tc9563, return 0; } -static void tc9563_pwrctrl_power_off(struct pci_pwrctrl_tc9563 *tc9563) +static int tc9563_pwrctrl_power_off(struct pci_pwrctrl *pwrctrl) { + struct pci_pwrctrl_tc9563 *tc9563 = container_of(pwrctrl, + struct pci_pwrctrl_tc9563, pwrctrl); + gpiod_set_value(tc9563->reset_gpio, 1); regulator_bulk_disable(ARRAY_SIZE(tc9563->supplies), tc9563->supplies); + + return 0; } -static int tc9563_pwrctrl_bring_up(struct pci_pwrctrl_tc9563 *tc9563) +static int tc9563_pwrctrl_power_on(struct pci_pwrctrl *pwrctrl) { + struct pci_pwrctrl_tc9563 *tc9563 = container_of(pwrctrl, + struct pci_pwrctrl_tc9563, pwrctrl); struct device *dev = tc9563->pwrctrl.dev; struct tc9563_pwrctrl_cfg *cfg; int ret, i; @@ -520,7 +527,7 @@ static int tc9563_pwrctrl_bring_up(struct pci_pwrctrl_tc9563 *tc9563) return 0; power_off: - tc9563_pwrctrl_power_off(tc9563); + tc9563_pwrctrl_power_off(&tc9563->pwrctrl); return ret; } @@ -613,7 +620,7 @@ static int tc9563_pwrctrl_probe(struct platform_device *pdev) goto remove_i2c; } - ret = tc9563_pwrctrl_bring_up(tc9563); + ret = tc9563_pwrctrl_power_on(&tc9563->pwrctrl); if (ret) goto remove_i2c; @@ -623,6 +630,9 @@ static int tc9563_pwrctrl_probe(struct platform_device *pdev) goto power_off; } + tc9563->pwrctrl.power_on = tc9563_pwrctrl_power_on; + tc9563->pwrctrl.power_off = tc9563_pwrctrl_power_off; + ret = devm_pci_pwrctrl_device_set_ready(dev, &tc9563->pwrctrl); if (ret) goto power_off; @@ -632,7 +642,7 @@ static int tc9563_pwrctrl_probe(struct platform_device *pdev) return 0; power_off: - tc9563_pwrctrl_power_off(tc9563); + tc9563_pwrctrl_power_off(&tc9563->pwrctrl); remove_i2c: i2c_unregister_device(tc9563->client); put_device(&tc9563->adapter->dev); @@ -643,7 +653,7 @@ static void tc9563_pwrctrl_remove(struct platform_device *pdev) { struct pci_pwrctrl_tc9563 *tc9563 = platform_get_drvdata(pdev); - tc9563_pwrctrl_power_off(tc9563); + tc9563_pwrctrl_power_off(&tc9563->pwrctrl); i2c_unregister_device(tc9563->client); put_device(&tc9563->adapter->dev); } diff --git a/drivers/pci/pwrctrl/slot.c b/drivers/pci/pwrctrl/slot.c index 5d0ec880c0ecf..55828aec24862 100644 --- a/drivers/pci/pwrctrl/slot.c +++ b/drivers/pci/pwrctrl/slot.c @@ -85,6 +85,9 @@ static int pci_pwrctrl_slot_probe(struct platform_device *pdev) pci_pwrctrl_slot_power_on(&slot->pwrctrl); + slot->pwrctrl.power_on = pci_pwrctrl_slot_power_on; + slot->pwrctrl.power_off = pci_pwrctrl_slot_power_off; + pci_pwrctrl_init(&slot->pwrctrl, dev); ret = devm_pci_pwrctrl_device_set_ready(dev, &slot->pwrctrl); diff --git a/include/linux/pci-pwrctrl.h b/include/linux/pci-pwrctrl.h index 4aefc7901cd18..435b822c841ea 100644 --- a/include/linux/pci-pwrctrl.h +++ b/include/linux/pci-pwrctrl.h @@ -31,6 +31,8 @@ struct device_link; /** * struct pci_pwrctrl - PCI device power control context. * @dev: Address of the power controlling device. + * @power_on: Callback to power on the power controlling device. + * @power_off: Callback to power off the power controlling device. * * An object of this type must be allocated by the PCI power control device and * passed to the pwrctrl subsystem to trigger a bus rescan and setup a device @@ -38,6 +40,8 @@ struct device_link; */ struct pci_pwrctrl { struct device *dev; + int (*power_on)(struct pci_pwrctrl *pwrctrl); + int (*power_off)(struct pci_pwrctrl *pwrctrl); /* private: internal use only */ struct notifier_block nb; From 94b60d91949d3ac074652e1ec499e9b70aae46e5 Mon Sep 17 00:00:00 2001 From: Krishna Chaitanya Chundru Date: Thu, 15 Jan 2026 12:59:02 +0530 Subject: [PATCH 2304/2333] FROMLIST: PCI/pwrctrl: Add APIs to create, destroy pwrctrl devices Previously, the PCI core created pwrctrl devices during pci_scan_device() on its own and then skipped enumeration of those devices, hoping the pwrctrl driver would power them on and trigger a bus rescan. This approach works for endpoint devices directly connected to Root Ports, but it fails for PCIe switches acting as bus extenders. When the switch requires pwrctrl support and the pwrctrl driver is not available during the pwrctrl device creation, its enumeration will be skipped during the initial PCI bus scan. This premature scan leads the PCI core to allocate resources (bridge windows, bus numbers) for the upstream bridge based on available downstream buses at scan time. For non-hotplug capable bridges, PCI core typically allocates resources based on the number of buses available during the initial bus scan, which happens to be just one if the switch is not powered on and enumerated at that time. When the switch gets enumerated later on, it will fail due to the lack of upstream resources. As a result, a PCIe switch powered on by the pwrctrl driver cannot be reliably enumerated currently. Either the switch has to be enabled in the bootloader or the switch pwrctrl driver has to be loaded during the pwrctrl device creation time to work around these issues. Introduce new APIs to explicitly create and destroy pwrctrl devices from controller drivers by recursively scanning the PCI child nodes of the controller. These APIs allow creating pwrctrl devices based on the original criteria and are intended to be called during controller probe and removal. These APIs, together with the upcoming APIs for power on/off will allow the controller drivers to power on all the devices before starting the initial bus scan, thereby solving the resource allocation issue. Link: https://lore.kernel.org/all/20260115-pci-pwrctrl-rework-v5-10-9d26da3ce903@oss.qualcomm.com/ Signed-off-by: Krishna Chaitanya Chundru [mani: splitted the patch, cleaned up the code, and rewrote description] Reviewed-by: Bartosz Golaszewski Signed-off-by: Manivannan Sadhasivam Signed-off-by: Bjorn Helgaas Tested-by: Chen-Yu Tsai --- drivers/pci/of.c | 1 + drivers/pci/pwrctrl/core.c | 114 ++++++++++++++++++++++++++++++++++++ include/linux/pci-pwrctrl.h | 8 ++- 3 files changed, 122 insertions(+), 1 deletion(-) diff --git a/drivers/pci/of.c b/drivers/pci/of.c index 3579265f11984..9bb5f258759be 100644 --- a/drivers/pci/of.c +++ b/drivers/pci/of.c @@ -867,6 +867,7 @@ bool of_pci_supply_present(struct device_node *np) return false; } +EXPORT_SYMBOL_GPL(of_pci_supply_present); #endif /* CONFIG_PCI */ diff --git a/drivers/pci/pwrctrl/core.c b/drivers/pci/pwrctrl/core.c index 6bdbfed584d6d..b423768cc477c 100644 --- a/drivers/pci/pwrctrl/core.c +++ b/drivers/pci/pwrctrl/core.c @@ -3,14 +3,21 @@ * Copyright (C) 2024 Linaro Ltd. */ +#define dev_fmt(fmt) "pwrctrl: " fmt + #include #include #include +#include +#include #include #include +#include #include #include +#include "../pci.h" + static int pci_pwrctrl_notify(struct notifier_block *nb, unsigned long action, void *data) { @@ -145,6 +152,113 @@ int devm_pci_pwrctrl_device_set_ready(struct device *dev, } EXPORT_SYMBOL_GPL(devm_pci_pwrctrl_device_set_ready); +static int pci_pwrctrl_create_device(struct device_node *np, + struct device *parent) +{ + struct platform_device *pdev; + int ret; + + for_each_available_child_of_node_scoped(np, child) { + ret = pci_pwrctrl_create_device(child, parent); + if (ret) + return ret; + } + + /* Bail out if the platform device is already available for the node */ + pdev = of_find_device_by_node(np); + if (pdev) { + platform_device_put(pdev); + return 0; + } + + /* + * Sanity check to make sure that the node has the compatible property + * to allow driver binding. + */ + if (!of_property_present(np, "compatible")) + return 0; + + /* + * Check whether the pwrctrl device really needs to be created or not. + * This is decided based on at least one of the power supplies being + * defined in the devicetree node of the device. + */ + if (!of_pci_supply_present(np)) { + dev_dbg(parent, "Skipping OF node: %s\n", np->name); + return 0; + } + + /* Now create the pwrctrl device */ + pdev = of_platform_device_create(np, NULL, parent); + if (!pdev) { + dev_err(parent, "Failed to create pwrctrl device for node: %s\n", np->name); + return -EINVAL; + } + + return 0; +} + +/** + * pci_pwrctrl_create_devices - Create pwrctrl devices + * + * @parent: PCI host controller device + * + * Recursively create pwrctrl devices for the devicetree hierarchy below + * the specified PCI host controller in a depth first manner. On error, all + * created devices will be destroyed. + * + * Return: 0 on success, negative error number on error. + */ +int pci_pwrctrl_create_devices(struct device *parent) +{ + int ret; + + for_each_available_child_of_node_scoped(parent->of_node, child) { + ret = pci_pwrctrl_create_device(child, parent); + if (ret) { + pci_pwrctrl_destroy_devices(parent); + return ret; + } + } + + return 0; +} +EXPORT_SYMBOL_GPL(pci_pwrctrl_create_devices); + +static void pci_pwrctrl_destroy_device(struct device_node *np) +{ + struct platform_device *pdev; + + for_each_available_child_of_node_scoped(np, child) + pci_pwrctrl_destroy_device(child); + + pdev = of_find_device_by_node(np); + if (!pdev) + return; + + of_device_unregister(pdev); + platform_device_put(pdev); + + of_node_clear_flag(np, OF_POPULATED); +} + +/** + * pci_pwrctrl_destroy_devices - Destroy pwrctrl devices + * + * @parent: PCI host controller device + * + * Recursively destroy pwrctrl devices for the devicetree hierarchy below + * the specified PCI host controller in a depth first manner. + */ +void pci_pwrctrl_destroy_devices(struct device *parent) +{ + struct device_node *np = parent->of_node; + + for_each_available_child_of_node_scoped(np, child) + pci_pwrctrl_destroy_device(child); +} +EXPORT_SYMBOL_GPL(pci_pwrctrl_destroy_devices); + MODULE_AUTHOR("Bartosz Golaszewski "); MODULE_DESCRIPTION("PCI Device Power Control core driver"); MODULE_LICENSE("GPL"); diff --git a/include/linux/pci-pwrctrl.h b/include/linux/pci-pwrctrl.h index 435b822c841ea..44f66872d0901 100644 --- a/include/linux/pci-pwrctrl.h +++ b/include/linux/pci-pwrctrl.h @@ -54,5 +54,11 @@ int pci_pwrctrl_device_set_ready(struct pci_pwrctrl *pwrctrl); void pci_pwrctrl_device_unset_ready(struct pci_pwrctrl *pwrctrl); int devm_pci_pwrctrl_device_set_ready(struct device *dev, struct pci_pwrctrl *pwrctrl); - +#if IS_ENABLED(CONFIG_PCI_PWRCTRL) +int pci_pwrctrl_create_devices(struct device *parent); +void pci_pwrctrl_destroy_devices(struct device *parent); +#else +static inline int pci_pwrctrl_create_devices(struct device *parent) { return 0; } +static void pci_pwrctrl_destroy_devices(struct device *parent) { } +#endif #endif /* __PCI_PWRCTRL_H__ */ From c88c181ddc9119d7ab898d3997e7cc408577b388 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Thu, 15 Jan 2026 12:59:03 +0530 Subject: [PATCH 2305/2333] FROMLIST: PCI/pwrctrl: Add APIs to power on/off pwrctrl devices To fix bridge resource allocation issues when powering PCI bridges with the pwrctrl driver, introduce APIs to explicitly power on and off all related devices simultaneously. Previously, the individual pwrctrl drivers powered on/off the PCI devices autonomously, without any control from the controller drivers. But to enforce ordering with respect to powering on the devices, these APIs will power on/off all the devices at the same time. The pci_pwrctrl_power_on_devices() API recursively scans the PCI child nodes, makes sure that pwrctrl drivers are bound to devices, and calls their power_on() callbacks. If any pwrctrl driver is not bound, it will return -EPROBE_DEFER. Similarly, pci_pwrctrl_power_off_devices() API powers off devices recursively via their power_off() callbacks. These APIs are expected to be called during the controller probe and suspend/resume time to power on/off the devices. But before calling these APIs, the pwrctrl devices should be created using the pci_pwrctrl_{create/destroy}_devices() APIs. Link: https://lore.kernel.org/all/20260115-pci-pwrctrl-rework-v5-11-9d26da3ce903@oss.qualcomm.com/ Co-developed-by: Krishna Chaitanya Chundru Signed-off-by: Krishna Chaitanya Chundru Signed-off-by: Manivannan Sadhasivam [bhelgaas: return early when !pdev and unindent, move ctx.power_on/off here] Signed-off-by: Bjorn Helgaas Tested-by: Chen-Yu Tsai Reviewed-by: Bartosz Golaszewski --- drivers/pci/pwrctrl/core.c | 130 ++++++++++++++++++++++++++++++++++++ include/linux/pci-pwrctrl.h | 4 ++ 2 files changed, 134 insertions(+) diff --git a/drivers/pci/pwrctrl/core.c b/drivers/pci/pwrctrl/core.c index b423768cc477c..fef5243d94458 100644 --- a/drivers/pci/pwrctrl/core.c +++ b/drivers/pci/pwrctrl/core.c @@ -65,6 +65,7 @@ void pci_pwrctrl_init(struct pci_pwrctrl *pwrctrl, struct device *dev) { pwrctrl->dev = dev; INIT_WORK(&pwrctrl->work, rescan_work_func); + dev_set_drvdata(dev, pwrctrl); } EXPORT_SYMBOL_GPL(pci_pwrctrl_init); @@ -152,6 +153,135 @@ int devm_pci_pwrctrl_device_set_ready(struct device *dev, } EXPORT_SYMBOL_GPL(devm_pci_pwrctrl_device_set_ready); +static int __pci_pwrctrl_power_off_device(struct device *dev) +{ + struct pci_pwrctrl *pwrctrl = dev_get_drvdata(dev); + + if (!pwrctrl) + return 0; + + return pwrctrl->power_off(pwrctrl); +} + +static void pci_pwrctrl_power_off_device(struct device_node *np) +{ + struct platform_device *pdev; + int ret; + + for_each_available_child_of_node_scoped(np, child) + pci_pwrctrl_power_off_device(child); + + pdev = of_find_device_by_node(np); + if (!pdev) + return; + + if (device_is_bound(&pdev->dev)) { + ret = __pci_pwrctrl_power_off_device(&pdev->dev); + if (ret) + dev_err(&pdev->dev, "Failed to power off device: %d", ret); + } + + platform_device_put(pdev); +} + +/** + * pci_pwrctrl_power_off_devices - Power off pwrctrl devices + * + * @parent: PCI host controller device + * + * Recursively traverse all pwrctrl devices for the devicetree hierarchy + * below the specified PCI host controller and power them off in a depth + * first manner. + */ +void pci_pwrctrl_power_off_devices(struct device *parent) +{ + struct device_node *np = parent->of_node; + + for_each_available_child_of_node_scoped(np, child) + pci_pwrctrl_power_off_device(child); +} +EXPORT_SYMBOL_GPL(pci_pwrctrl_power_off_devices); + +static int __pci_pwrctrl_power_on_device(struct device *dev) +{ + struct pci_pwrctrl *pwrctrl = dev_get_drvdata(dev); + + if (!pwrctrl) + return 0; + + return pwrctrl->power_on(pwrctrl); +} + +/* + * Power on the devices in a depth first manner. Before powering on the device, + * make sure its driver is bound. + */ +static int pci_pwrctrl_power_on_device(struct device_node *np) +{ + struct platform_device *pdev; + int ret; + + for_each_available_child_of_node_scoped(np, child) { + ret = pci_pwrctrl_power_on_device(child); + if (ret) + return ret; + } + + pdev = of_find_device_by_node(np); + if (!pdev) + return 0; + + if (device_is_bound(&pdev->dev)) { + ret = __pci_pwrctrl_power_on_device(&pdev->dev); + } else { + /* FIXME: Use blocking wait instead of probe deferral */ + dev_dbg(&pdev->dev, "driver is not bound\n"); + ret = -EPROBE_DEFER; + } + + platform_device_put(pdev); + + return ret; +} + +/** + * pci_pwrctrl_power_on_devices - Power on pwrctrl devices + * + * @parent: PCI host controller device + * + * Recursively traverse all pwrctrl devices for the devicetree hierarchy + * below the specified PCI host controller and power them on in a depth + * first manner. On error, all powered on devices will be powered off. + * + * Return: 0 on success, -EPROBE_DEFER if any pwrctrl driver is not bound, an + * appropriate error code otherwise. + */ +int pci_pwrctrl_power_on_devices(struct device *parent) +{ + struct device_node *np = parent->of_node; + struct device_node *child = NULL; + int ret; + + for_each_available_child_of_node(np, child) { + ret = pci_pwrctrl_power_on_device(child); + if (ret) + goto err_power_off; + } + + return 0; + +err_power_off: + for_each_available_child_of_node_scoped(np, tmp) { + if (tmp == child) + break; + pci_pwrctrl_power_off_device(tmp); + } + of_node_put(child); + + return ret; +} +EXPORT_SYMBOL_GPL(pci_pwrctrl_power_on_devices); + static int pci_pwrctrl_create_device(struct device_node *np, struct device *parent) { diff --git a/include/linux/pci-pwrctrl.h b/include/linux/pci-pwrctrl.h index 44f66872d0901..1192a2527521d 100644 --- a/include/linux/pci-pwrctrl.h +++ b/include/linux/pci-pwrctrl.h @@ -57,8 +57,12 @@ int devm_pci_pwrctrl_device_set_ready(struct device *dev, #if IS_ENABLED(CONFIG_PCI_PWRCTRL) int pci_pwrctrl_create_devices(struct device *parent); void pci_pwrctrl_destroy_devices(struct device *parent); +int pci_pwrctrl_power_on_devices(struct device *parent); +void pci_pwrctrl_power_off_devices(struct device *parent); #else static inline int pci_pwrctrl_create_devices(struct device *parent) { return 0; } static void pci_pwrctrl_destroy_devices(struct device *parent) { } +static inline int pci_pwrctrl_power_on_devices(struct device *parent) { return 0; } +static void pci_pwrctrl_power_off_devices(struct device *parent) { } #endif #endif /* __PCI_PWRCTRL_H__ */ From a538351331def514e607888abc17514327a9d0d4 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Thu, 15 Jan 2026 12:59:04 +0530 Subject: [PATCH 2306/2333] FROMLIST: PCI/pwrctrl: Switch to pwrctrl create, power on/off, destroy APIs Adopt pwrctrl APIs to create, power on/off, and destroy pwrctrl devices. In qcom_pcie_host_init(), call pci_pwrctrl_create_devices() to create devices, then pci_pwrctrl_power_on_devices() to power them on, both after controller resource initialization. Once successful, deassert PERST# for all devices. In qcom_pcie_host_deinit(), call pci_pwrctrl_power_off_devices() after asserting PERST#. Note that pci_pwrctrl_destroy_devices() is not called here, as deinit is only invoked during system suspend where device destruction is unnecessary. If the driver becomes removable in future, pci_pwrctrl_destroy_devices() should be called in the remove() handler. Remove the old pwrctrl framework code from the PCI core (including devlinks) as the new APIs are now the sole consumer of pwrctrl functionality. And also do not power on the pwrctrl drivers during probe() as this is now handled by the APIs. Co-developed-by: Krishna Chaitanya Chundru Signed-off-by: Manivannan Sadhasivam Signed-off-by: Bjorn Helgaas Tested-by: Chen-Yu Tsai Reviewed-by: Bartosz Golaszewski Link: https://lore.kernel.org/r/20260115-pci-pwrctrl-rework-v5-12-9d26da3ce903@oss.qualcomm.com Signed-off-by: Krishna Chaitanya Chundru --- drivers/pci/bus.c | 19 -------- drivers/pci/controller/dwc/pcie-qcom.c | 24 +++++++++- drivers/pci/probe.c | 59 ------------------------ drivers/pci/pwrctrl/core.c | 15 ------ drivers/pci/pwrctrl/pci-pwrctrl-pwrseq.c | 5 -- drivers/pci/pwrctrl/pci-pwrctrl-tc9563.c | 24 ++-------- drivers/pci/pwrctrl/slot.c | 2 - drivers/pci/remove.c | 20 -------- 8 files changed, 25 insertions(+), 143 deletions(-) diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c index f26aec6ff5889..04bd9deefc8b5 100644 --- a/drivers/pci/bus.c +++ b/drivers/pci/bus.c @@ -343,7 +343,6 @@ void __weak pcibios_bus_add_device(struct pci_dev *pdev) { } void pci_bus_add_device(struct pci_dev *dev) { struct device_node *dn = dev->dev.of_node; - struct platform_device *pdev; /* * Can not put in pci_device_add yet because resources @@ -357,24 +356,6 @@ void pci_bus_add_device(struct pci_dev *dev) pci_proc_attach_device(dev); pci_bridge_d3_update(dev); - /* - * If the PCI device is associated with a pwrctrl device with a - * power supply, create a device link between the PCI device and - * pwrctrl device. This ensures that pwrctrl drivers are probed - * before PCI client drivers. - */ - pdev = of_find_device_by_node(dn); - if (pdev) { - if (of_pci_supply_present(dn)) { - if (!device_link_add(&dev->dev, &pdev->dev, - DL_FLAG_AUTOREMOVE_CONSUMER)) { - pci_err(dev, "failed to add device link to power control device %s\n", - pdev->name); - } - } - put_device(&pdev->dev); - } - if (!dn || of_device_is_available(dn)) pci_dev_allow_binding(dev); diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c index 32bb9ed58bf7a..926557cada428 100644 --- a/drivers/pci/controller/dwc/pcie-qcom.c +++ b/drivers/pci/controller/dwc/pcie-qcom.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -1308,10 +1309,18 @@ static int qcom_pcie_host_init(struct dw_pcie_rp *pp) if (ret) goto err_deinit; + ret = pci_pwrctrl_create_devices(pci->dev); + if (ret) + goto err_disable_phy; + + ret = pci_pwrctrl_power_on_devices(pci->dev); + if (ret) + goto err_pwrctrl_destroy; + if (pcie->cfg->ops->post_init) { ret = pcie->cfg->ops->post_init(pcie); if (ret) - goto err_disable_phy; + goto err_pwrctrl_power_off; } qcom_ep_reset_deassert(pcie); @@ -1326,6 +1335,11 @@ static int qcom_pcie_host_init(struct dw_pcie_rp *pp) err_assert_reset: qcom_ep_reset_assert(pcie); +err_pwrctrl_power_off: + pci_pwrctrl_power_off_devices(pci->dev); +err_pwrctrl_destroy: + if (ret != -EPROBE_DEFER) + pci_pwrctrl_destroy_devices(pci->dev); err_disable_phy: qcom_pcie_phy_power_off(pcie); err_deinit: @@ -1340,6 +1354,12 @@ static void qcom_pcie_host_deinit(struct dw_pcie_rp *pp) struct qcom_pcie *pcie = to_qcom_pcie(pci); qcom_ep_reset_assert(pcie); + + /* + * No need to destroy pwrctrl devices as this function only gets called + * during system suspend as of now. + */ + pci_pwrctrl_power_off_devices(pci->dev); qcom_pcie_phy_power_off(pcie); pcie->cfg->ops->deinit(pcie); } @@ -1946,7 +1966,7 @@ static int qcom_pcie_probe(struct platform_device *pdev) ret = dw_pcie_host_init(pp); if (ret) { - dev_err(dev, "cannot initialize host\n"); + dev_err_probe(dev, ret, "cannot initialize host\n"); goto err_phy_exit; } diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 9cd032dff31e5..4ba6b7b5ebfef 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -2533,56 +2533,6 @@ bool pci_bus_read_dev_vendor_id(struct pci_bus *bus, int devfn, u32 *l, } EXPORT_SYMBOL(pci_bus_read_dev_vendor_id); -#if IS_ENABLED(CONFIG_PCI_PWRCTRL) -static struct platform_device *pci_pwrctrl_create_device(struct pci_bus *bus, int devfn) -{ - struct pci_host_bridge *host = pci_find_host_bridge(bus); - struct platform_device *pdev; - struct device_node *np; - - np = of_pci_find_child_device(dev_of_node(&bus->dev), devfn); - if (!np) - return NULL; - - pdev = of_find_device_by_node(np); - if (pdev) { - put_device(&pdev->dev); - goto err_put_of_node; - } - - /* - * First check whether the pwrctrl device really needs to be created or - * not. This is decided based on at least one of the power supplies - * being defined in the devicetree node of the device. - */ - if (!of_pci_supply_present(np)) { - pr_debug("PCI/pwrctrl: Skipping OF node: %s\n", np->name); - goto err_put_of_node; - } - - /* Now create the pwrctrl device */ - pdev = of_platform_device_create(np, NULL, &host->dev); - if (!pdev) { - pr_err("PCI/pwrctrl: Failed to create pwrctrl device for node: %s\n", np->name); - goto err_put_of_node; - } - - of_node_put(np); - - return pdev; - -err_put_of_node: - of_node_put(np); - - return NULL; -} -#else -static struct platform_device *pci_pwrctrl_create_device(struct pci_bus *bus, int devfn) -{ - return NULL; -} -#endif - /* * Read the config data for a PCI device, sanity-check it, * and fill in the dev structure. @@ -2592,15 +2542,6 @@ static struct pci_dev *pci_scan_device(struct pci_bus *bus, int devfn) struct pci_dev *dev; u32 l; - /* - * Create pwrctrl device (if required) for the PCI device to handle the - * power state. If the pwrctrl device is created, then skip scanning - * further as the pwrctrl core will rescan the bus after powering on - * the device. - */ - if (pci_pwrctrl_create_device(bus, devfn)) - return NULL; - if (!pci_bus_read_dev_vendor_id(bus, devfn, &l, 60*1000)) return NULL; diff --git a/drivers/pci/pwrctrl/core.c b/drivers/pci/pwrctrl/core.c index fef5243d94458..1b91375738a08 100644 --- a/drivers/pci/pwrctrl/core.c +++ b/drivers/pci/pwrctrl/core.c @@ -45,16 +45,6 @@ static int pci_pwrctrl_notify(struct notifier_block *nb, unsigned long action, return NOTIFY_DONE; } -static void rescan_work_func(struct work_struct *work) -{ - struct pci_pwrctrl *pwrctrl = container_of(work, - struct pci_pwrctrl, work); - - pci_lock_rescan_remove(); - pci_rescan_bus(to_pci_host_bridge(pwrctrl->dev->parent)->bus); - pci_unlock_rescan_remove(); -} - /** * pci_pwrctrl_init() - Initialize the PCI power control context struct * @@ -64,7 +54,6 @@ static void rescan_work_func(struct work_struct *work) void pci_pwrctrl_init(struct pci_pwrctrl *pwrctrl, struct device *dev) { pwrctrl->dev = dev; - INIT_WORK(&pwrctrl->work, rescan_work_func); dev_set_drvdata(dev, pwrctrl); } EXPORT_SYMBOL_GPL(pci_pwrctrl_init); @@ -95,8 +84,6 @@ int pci_pwrctrl_device_set_ready(struct pci_pwrctrl *pwrctrl) if (ret) return ret; - schedule_work(&pwrctrl->work); - return 0; } EXPORT_SYMBOL_GPL(pci_pwrctrl_device_set_ready); @@ -109,8 +96,6 @@ EXPORT_SYMBOL_GPL(pci_pwrctrl_device_set_ready); */ void pci_pwrctrl_device_unset_ready(struct pci_pwrctrl *pwrctrl) { - cancel_work_sync(&pwrctrl->work); - /* * We don't have to delete the link here. Typically, this function * is only called when the power control device is being detached. If diff --git a/drivers/pci/pwrctrl/pci-pwrctrl-pwrseq.c b/drivers/pci/pwrctrl/pci-pwrctrl-pwrseq.c index 2ee02edd55a31..1df0cd73b416e 100644 --- a/drivers/pci/pwrctrl/pci-pwrctrl-pwrseq.c +++ b/drivers/pci/pwrctrl/pci-pwrctrl-pwrseq.c @@ -101,11 +101,6 @@ static int pci_pwrctrl_pwrseq_probe(struct platform_device *pdev) return dev_err_probe(dev, PTR_ERR(pwrseq->pwrseq), "Failed to get the power sequencer\n"); - ret = pci_pwrctrl_pwrseq_power_on(&pwrseq->pwrctrl); - if (ret) - return dev_err_probe(dev, ret, - "Failed to power-on the device\n"); - ret = devm_add_action_or_reset(dev, devm_pci_pwrctrl_pwrseq_power_off, pwrseq); if (ret) diff --git a/drivers/pci/pwrctrl/pci-pwrctrl-tc9563.c b/drivers/pci/pwrctrl/pci-pwrctrl-tc9563.c index a71d7ef2d4b89..38008d03903f2 100644 --- a/drivers/pci/pwrctrl/pci-pwrctrl-tc9563.c +++ b/drivers/pci/pwrctrl/pci-pwrctrl-tc9563.c @@ -533,9 +533,7 @@ static int tc9563_pwrctrl_power_on(struct pci_pwrctrl *pwrctrl) static int tc9563_pwrctrl_probe(struct platform_device *pdev) { - struct pci_host_bridge *bridge = to_pci_host_bridge(pdev->dev.parent); struct device_node *node = pdev->dev.of_node; - struct pci_bus *bus = bridge->bus; struct device *dev = &pdev->dev; enum tc9563_pwrctrl_ports port; struct pci_pwrctrl_tc9563 *tc9563; @@ -614,22 +612,6 @@ static int tc9563_pwrctrl_probe(struct platform_device *pdev) goto remove_i2c; } - if (bridge->ops->assert_perst) { - ret = bridge->ops->assert_perst(bus, true); - if (ret) - goto remove_i2c; - } - - ret = tc9563_pwrctrl_power_on(&tc9563->pwrctrl); - if (ret) - goto remove_i2c; - - if (bridge->ops->assert_perst) { - ret = bridge->ops->assert_perst(bus, false); - if (ret) - goto power_off; - } - tc9563->pwrctrl.power_on = tc9563_pwrctrl_power_on; tc9563->pwrctrl.power_off = tc9563_pwrctrl_power_off; @@ -637,8 +619,6 @@ static int tc9563_pwrctrl_probe(struct platform_device *pdev) if (ret) goto power_off; - platform_set_drvdata(pdev, tc9563); - return 0; power_off: @@ -651,7 +631,9 @@ static int tc9563_pwrctrl_probe(struct platform_device *pdev) static void tc9563_pwrctrl_remove(struct platform_device *pdev) { - struct pci_pwrctrl_tc9563 *tc9563 = platform_get_drvdata(pdev); + struct pci_pwrctrl *pwrctrl = dev_get_drvdata(&pdev->dev); + struct pci_pwrctrl_tc9563 *tc9563 = container_of(pwrctrl, + struct pci_pwrctrl_tc9563, pwrctrl); tc9563_pwrctrl_power_off(&tc9563->pwrctrl); i2c_unregister_device(tc9563->client); diff --git a/drivers/pci/pwrctrl/slot.c b/drivers/pci/pwrctrl/slot.c index 55828aec24862..a36e5dd424427 100644 --- a/drivers/pci/pwrctrl/slot.c +++ b/drivers/pci/pwrctrl/slot.c @@ -83,8 +83,6 @@ static int pci_pwrctrl_slot_probe(struct platform_device *pdev) return dev_err_probe(dev, PTR_ERR(slot->clk), "Failed to enable slot clock\n"); - pci_pwrctrl_slot_power_on(&slot->pwrctrl); - slot->pwrctrl.power_on = pci_pwrctrl_slot_power_on; slot->pwrctrl.power_off = pci_pwrctrl_slot_power_off; diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c index ce5c25adef551..2a22595f38af6 100644 --- a/drivers/pci/remove.c +++ b/drivers/pci/remove.c @@ -17,25 +17,6 @@ static void pci_free_resources(struct pci_dev *dev) } } -static void pci_pwrctrl_unregister(struct device *dev) -{ - struct device_node *np; - struct platform_device *pdev; - - np = dev_of_node(dev); - if (!np) - return; - - pdev = of_find_device_by_node(np); - if (!pdev) - return; - - of_device_unregister(pdev); - put_device(&pdev->dev); - - of_node_clear_flag(np, OF_POPULATED); -} - static void pci_stop_dev(struct pci_dev *dev) { pci_pme_active(dev, false); @@ -66,7 +47,6 @@ static void pci_destroy_dev(struct pci_dev *dev) pci_doe_destroy(dev); pcie_aspm_exit_link_state(dev); pci_bridge_d3_update(dev); - pci_pwrctrl_unregister(&dev->dev); pci_free_resources(dev); put_device(&dev->dev); } From e72d9a5baa444060ed16aa2b3fe9aa58210680ad Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Thu, 15 Jan 2026 12:59:05 +0530 Subject: [PATCH 2307/2333] FROMLIST: PCI: qcom: Drop the assert_perst() callbacks Previously, the pcie-qcom driver probed first, deasserted PERST#, enabled link training and scanned the bus. By the time the pwrctrl driver probe got called, link training was already enabled by the controller driver. Thus the pwrctrl drivers had to call the .assert_perst() callback, to assert PERST#, power on the needed resources, and then call the .assert_perst() callback to deassert PERST#. Now since all pwrctrl drivers and this controller driver have been converted to the new pwrctrl design where the pwrctrl drivers will first power on the devices before this driver deasserts PERST# and scan the bus. So there is no longer a need for .assert_perst() callback in this driver and in DWC core driver. Hence, drop them. Signed-off-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/20260115-pci-pwrctrl-rework-v5-13-9d26da3ce903@oss.qualcomm.com --- drivers/pci/controller/dwc/pcie-designware-host.c | 9 --------- drivers/pci/controller/dwc/pcie-designware.h | 9 --------- drivers/pci/controller/dwc/pcie-qcom.c | 13 ------------- 3 files changed, 31 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c index 3d1a9dc829b34..e92513c5bda51 100644 --- a/drivers/pci/controller/dwc/pcie-designware-host.c +++ b/drivers/pci/controller/dwc/pcie-designware-host.c @@ -856,19 +856,10 @@ static void __iomem *dw_pcie_ecam_conf_map_bus(struct pci_bus *bus, unsigned int return pci->dbi_base + where; } -static int dw_pcie_op_assert_perst(struct pci_bus *bus, bool assert) -{ - struct dw_pcie_rp *pp = bus->sysdata; - struct dw_pcie *pci = to_dw_pcie_from_pp(pp); - - return dw_pcie_assert_perst(pci, assert); -} - static struct pci_ops dw_pcie_ops = { .map_bus = dw_pcie_own_conf_map_bus, .read = pci_generic_config_read, .write = pci_generic_config_write, - .assert_perst = dw_pcie_op_assert_perst, }; static struct pci_ops dw_pcie_ecam_ops = { diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index 0721c15d92831..24bfa5231923a 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -485,7 +485,6 @@ struct dw_pcie_ops { enum dw_pcie_ltssm (*get_ltssm)(struct dw_pcie *pcie); int (*start_link)(struct dw_pcie *pcie); void (*stop_link)(struct dw_pcie *pcie); - int (*assert_perst)(struct dw_pcie *pcie, bool assert); }; struct debugfs_info { @@ -788,14 +787,6 @@ static inline void dw_pcie_stop_link(struct dw_pcie *pci) pci->ops->stop_link(pci); } -static inline int dw_pcie_assert_perst(struct dw_pcie *pci, bool assert) -{ - if (pci->ops && pci->ops->assert_perst) - return pci->ops->assert_perst(pci, assert); - - return 0; -} - static inline enum dw_pcie_ltssm dw_pcie_get_ltssm(struct dw_pcie *pci) { u32 val; diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c index 926557cada428..872058e2e664a 100644 --- a/drivers/pci/controller/dwc/pcie-qcom.c +++ b/drivers/pci/controller/dwc/pcie-qcom.c @@ -642,18 +642,6 @@ static int qcom_pcie_post_init_1_0_0(struct qcom_pcie *pcie) return 0; } -static int qcom_pcie_assert_perst(struct dw_pcie *pci, bool assert) -{ - struct qcom_pcie *pcie = to_qcom_pcie(pci); - - if (assert) - qcom_ep_reset_assert(pcie); - else - qcom_ep_reset_deassert(pcie); - - return 0; -} - static void qcom_pcie_2_3_2_ltssm_enable(struct qcom_pcie *pcie) { u32 val; @@ -1512,7 +1500,6 @@ static const struct qcom_pcie_cfg cfg_fw_managed = { static const struct dw_pcie_ops dw_pcie_ops = { .link_up = qcom_pcie_link_up, .start_link = qcom_pcie_start_link, - .assert_perst = qcom_pcie_assert_perst, }; static int qcom_pcie_icc_init(struct qcom_pcie *pcie) From f7a5f96c6d4b2b774f0992c54fd6886bf9e38401 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Thu, 15 Jan 2026 12:59:06 +0530 Subject: [PATCH 2308/2333] FROMLIST: PCI: Drop the assert_perst() callback Now since all .assert_callback() implementations have been removed from the controller drivers, drop the .assert_callback callback from pci.h. Reviewed-by: Bartosz Golaszewski Signed-off-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/20260115-pci-pwrctrl-rework-v5-14-9d26da3ce903@oss.qualcomm.com --- include/linux/pci.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/linux/pci.h b/include/linux/pci.h index e6a03367658d5..bf97d49c23cf5 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -831,7 +831,6 @@ struct pci_ops { void __iomem *(*map_bus)(struct pci_bus *bus, unsigned int devfn, int where); int (*read)(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *val); int (*write)(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 val); - int (*assert_perst)(struct pci_bus *bus, bool assert); }; /* From 5d29f823d60444a67dbc797062664e522b728ca6 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Thu, 15 Jan 2026 12:59:07 +0530 Subject: [PATCH 2309/2333] FROMLIST: PCI: qcom: Rename PERST# assert/deassert helpers for uniformity Rename the PERST# assert/deassert helpers from qcom_ep_reset_{assert/deassert}() to qcom_pcie_perst_{assert/deassert}() to maintain uniformity. Reviewed-by: Bartosz Golaszewski Signed-off-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/20260115-pci-pwrctrl-rework-v5-15-9d26da3ce903@oss.qualcomm.com --- drivers/pci/controller/dwc/pcie-qcom.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c index 872058e2e664a..e3ca40c36b6ab 100644 --- a/drivers/pci/controller/dwc/pcie-qcom.c +++ b/drivers/pci/controller/dwc/pcie-qcom.c @@ -290,7 +290,7 @@ struct qcom_pcie { #define to_qcom_pcie(x) dev_get_drvdata((x)->dev) -static void qcom_perst_assert(struct qcom_pcie *pcie, bool assert) +static void __qcom_pcie_perst_assert(struct qcom_pcie *pcie, bool assert) { struct qcom_pcie_port *port; int val = assert ? 1 : 0; @@ -301,16 +301,16 @@ static void qcom_perst_assert(struct qcom_pcie *pcie, bool assert) usleep_range(PERST_DELAY_US, PERST_DELAY_US + 500); } -static void qcom_ep_reset_assert(struct qcom_pcie *pcie) +static void qcom_pcie_perst_assert(struct qcom_pcie *pcie) { - qcom_perst_assert(pcie, true); + __qcom_pcie_perst_assert(pcie, true); } -static void qcom_ep_reset_deassert(struct qcom_pcie *pcie) +static void qcom_pcie_perst_deassert(struct qcom_pcie *pcie) { /* Ensure that PERST has been asserted for at least 100 ms */ msleep(PCIE_T_PVPERL_MS); - qcom_perst_assert(pcie, false); + __qcom_pcie_perst_assert(pcie, false); } static int qcom_pcie_start_link(struct dw_pcie *pci) @@ -1287,7 +1287,7 @@ static int qcom_pcie_host_init(struct dw_pcie_rp *pp) struct qcom_pcie *pcie = to_qcom_pcie(pci); int ret; - qcom_ep_reset_assert(pcie); + qcom_pcie_perst_assert(pcie); ret = pcie->cfg->ops->init(pcie); if (ret) @@ -1311,7 +1311,7 @@ static int qcom_pcie_host_init(struct dw_pcie_rp *pp) goto err_pwrctrl_power_off; } - qcom_ep_reset_deassert(pcie); + qcom_pcie_perst_deassert(pcie); if (pcie->cfg->ops->config_sid) { ret = pcie->cfg->ops->config_sid(pcie); @@ -1322,7 +1322,7 @@ static int qcom_pcie_host_init(struct dw_pcie_rp *pp) return 0; err_assert_reset: - qcom_ep_reset_assert(pcie); + qcom_pcie_perst_assert(pcie); err_pwrctrl_power_off: pci_pwrctrl_power_off_devices(pci->dev); err_pwrctrl_destroy: @@ -1341,7 +1341,7 @@ static void qcom_pcie_host_deinit(struct dw_pcie_rp *pp) struct dw_pcie *pci = to_dw_pcie_from_pp(pp); struct qcom_pcie *pcie = to_qcom_pcie(pci); - qcom_ep_reset_assert(pcie); + qcom_pcie_perst_assert(pcie); /* * No need to destroy pwrctrl devices as this function only gets called From 4e3e55723f3898a551ac41eba7a36f9dac557b7d Mon Sep 17 00:00:00 2001 From: Umang Chheda Date: Wed, 4 Feb 2026 01:08:48 +0530 Subject: [PATCH 2310/2333] FROMLIST: arm64: dts: qcom: lemans-evk: Add Mezzanine The Mezzanine is an hardware expansion add-on board designed to be stacked on top of Lemans EVK. It has following peripherals : - 4x Type A USB ports in host mode. - TC9563 PCIe switch, which has following three downstream ports (DSP) : - 1st DSP connects M.2 E-key connector for connecting WLAN endpoints. - 2nd DSP connects M.2 B-key connector for connecting cellular modems. - 3rd DSP with support for Dual Ethernet ports. - eMMC. - Additional 2.5GbE Ethernet PHY connected to native EMAC with support for MAC Address configuration via NVMEM. - EEPROM. - LVDS Display. - 2*mini DP. Add support for following peripherals : - TC9563 PCIe Switch. - Additional 2.5GbE Ethernet Port. - EEPROM. Written with inputs from : Mohd Ayaan Anwar - Ethernet. Krishna Chaitanya Chundru - PCIe Monish Chunara - EEPROM. Signed-off-by: Umang Chheda Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20260203193848.123307-2-umang.chheda@oss.qualcomm.com --- arch/arm64/boot/dts/qcom/Makefile | 3 + .../boot/dts/qcom/lemans-evk-mezzanine.dtso | 301 ++++++++++++++++++ 2 files changed, 304 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/lemans-evk-mezzanine.dtso diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile index bce08f77d037e..a62d0b310fd9a 100644 --- a/arch/arm64/boot/dts/qcom/Makefile +++ b/arch/arm64/boot/dts/qcom/Makefile @@ -40,6 +40,9 @@ lemans-evk-el2-dtbs := lemans-evk.dtb lemans-el2.dtbo dtb-$(CONFIG_ARCH_QCOM) += lemans-evk-camera-csi1-imx577.dtb dtb-$(CONFIG_ARCH_QCOM) += lemans-evk-el2.dtb +lemans-evk-mezzanine-dtbs := lemans-evk.dtb lemans-evk-mezzanine.dtbo + +dtb-$(CONFIG_ARCH_QCOM) += lemans-evk-mezzanine.dtb dtb-$(CONFIG_ARCH_QCOM) += monaco-evk.dtb monaco-evk-el2-dtbs := monaco-evk.dtb monaco-el2.dtbo diff --git a/arch/arm64/boot/dts/qcom/lemans-evk-mezzanine.dtso b/arch/arm64/boot/dts/qcom/lemans-evk-mezzanine.dtso new file mode 100644 index 0000000000000..4fab96ba873c2 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/lemans-evk-mezzanine.dtso @@ -0,0 +1,301 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +/dts-v1/; +/plugin/; + +#include + +&{/} { + model = "Qualcomm Technologies, Inc. Lemans-evk Mezzanine"; + + vreg_0p9: regulator-vreg-0p9 { + compatible = "regulator-fixed"; + regulator-name = "VREG_0P9"; + + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <900000>; + regulator-always-on; + regulator-boot-on; + + vin-supply = <&vreg_3p3>; + }; + + vreg_1p8: regulator-vreg-1p8 { + compatible = "regulator-fixed"; + regulator-name = "VREG_1P8"; + + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + regulator-boot-on; + + vin-supply = <&vreg_4p2>; + }; + + vreg_3p3: regulator-vreg-3p3 { + compatible = "regulator-fixed"; + regulator-name = "VREG_3P3"; + + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + regulator-boot-on; + + vin-supply = <&vreg_4p2>; + }; + + vreg_4p2: regulator-vreg-4p2 { + compatible = "regulator-fixed"; + regulator-name = "VREG_4P2"; + + regulator-min-microvolt = <4200000>; + regulator-max-microvolt = <4200000>; + regulator-always-on; + regulator-boot-on; + + vin-supply = <&vreg_sys_pwr>; + }; + + vreg_sys_pwr: regulator-vreg-sys-pwr { + compatible = "regulator-fixed"; + regulator-name = "VREG_SYS_PWR"; + + regulator-min-microvolt = <24000000>; + regulator-max-microvolt = <24000000>; + regulator-always-on; + regulator-boot-on; + }; +}; + +ðernet1 { + phy-handle = <&hsgmii_phy1>; + phy-mode = "2500base-x"; + + pinctrl-0 = <ðernet1_default>; + pinctrl-names = "default"; + + snps,mtl-rx-config = <&mtl_rx_setup1>; + snps,mtl-tx-config = <&mtl_tx_setup1>; + + nvmem-cells = <&mac_addr1>; + nvmem-cell-names = "mac-address"; + + status = "okay"; + + mdio { + compatible = "snps,dwmac-mdio"; + #address-cells = <1>; + #size-cells = <0>; + + hsgmii_phy1: ethernet-phy@18 { + compatible = "ethernet-phy-id004d.d101"; + reg = <0x18>; + reset-gpios = <&pmm8654au_2_gpios 9 GPIO_ACTIVE_LOW>; + reset-assert-us = <11000>; + reset-deassert-us = <70000>; + }; + }; + + mtl_rx_setup1: rx-queues-config { + snps,rx-queues-to-use = <4>; + snps,rx-sched-sp; + + queue0 { + snps,dcb-algorithm; + snps,map-to-dma-channel = <0x0>; + snps,route-up; + snps,priority = <0x1>; + }; + + queue1 { + snps,dcb-algorithm; + snps,map-to-dma-channel = <0x1>; + snps,route-ptp; + }; + + queue2 { + snps,avb-algorithm; + snps,map-to-dma-channel = <0x2>; + snps,route-avcp; + }; + + queue3 { + snps,avb-algorithm; + snps,map-to-dma-channel = <0x3>; + snps,priority = <0xc>; + }; + }; + + mtl_tx_setup1: tx-queues-config { + snps,tx-queues-to-use = <4>; + + queue0 { + snps,dcb-algorithm; + }; + + queue1 { + snps,dcb-algorithm; + }; + + queue2 { + snps,avb-algorithm; + snps,send_slope = <0x1000>; + snps,idle_slope = <0x1000>; + snps,high_credit = <0x3e800>; + snps,low_credit = <0xffc18000>; + }; + + queue3 { + snps,avb-algorithm; + snps,send_slope = <0x1000>; + snps,idle_slope = <0x1000>; + snps,high_credit = <0x3e800>; + snps,low_credit = <0xffc18000>; + }; + }; +}; + +&i2c18 { + #address-cells = <1>; + #size-cells = <0>; + + eeprom@52 { + compatible = "giantec,gt24c256c", "atmel,24c256"; + reg = <0x52>; + pagesize = <64>; + + nvmem-layout { + compatible = "fixed-layout"; + #address-cells = <1>; + #size-cells = <1>; + + mac_addr1: mac-addr@0 { + reg = <0x0 0x6>; + }; + }; + }; +}; + +&pcie0 { + iommu-map = <0x0 &pcie_smmu 0x0 0x1>, + <0x100 &pcie_smmu 0x1 0x1>, + <0x208 &pcie_smmu 0x2 0x1>, + <0x210 &pcie_smmu 0x3 0x1>, + <0x218 &pcie_smmu 0x4 0x1>, + <0x300 &pcie_smmu 0x5 0x1>, + <0x400 &pcie_smmu 0x6 0x1>, + <0x500 &pcie_smmu 0x7 0x1>, + <0x501 &pcie_smmu 0x8 0x1>; +}; + +&pcieport0 { + #address-cells = <3>; + #size-cells = <2>; + + pcie@0,0 { + compatible = "pci1179,0623"; + reg = <0x10000 0x0 0x0 0x0 0x0>; + #address-cells = <3>; + #size-cells = <2>; + + device_type = "pci"; + ranges; + bus-range = <0x2 0xff>; + + vddc-supply = <&vreg_0p9>; + vdd18-supply = <&vreg_1p8>; + vdd09-supply = <&vreg_0p9>; + vddio1-supply = <&vreg_1p8>; + vddio2-supply = <&vreg_1p8>; + vddio18-supply = <&vreg_1p8>; + + i2c-parent = <&i2c18 0x77>; + + resx-gpios = <&tlmm 140 GPIO_ACTIVE_LOW>; + + pinctrl-0 = <&tc9563_resx_n>; + pinctrl-names = "default"; + + pcie@1,0 { + reg = <0x20800 0x0 0x0 0x0 0x0>; + #address-cells = <3>; + #size-cells = <2>; + + device_type = "pci"; + ranges; + bus-range = <0x3 0xff>; + }; + + pcie@2,0 { + reg = <0x21000 0x0 0x0 0x0 0x0>; + #address-cells = <3>; + #size-cells = <2>; + + device_type = "pci"; + ranges; + bus-range = <0x4 0xff>; + }; + + pcie@3,0 { + reg = <0x21800 0x0 0x0 0x0 0x0>; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + ranges; + bus-range = <0x5 0xff>; + + pci@0,0 { + reg = <0x50000 0x0 0x0 0x0 0x0>; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + ranges; + }; + + pci@0,1 { + reg = <0x50100 0x0 0x0 0x0 0x0>; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + ranges; + }; + }; + }; +}; + +&serdes1 { + phy-supply = <&vreg_l5a>; + + status = "okay"; +}; + +&tlmm { + ethernet1_default: ethernet1-default-state { + ethernet1-mdc-pins { + pins = "gpio20"; + function = "emac1_mdc"; + drive-strength = <16>; + bias-pull-up; + }; + + ethernet1-mdio-pins { + pins = "gpio21"; + function = "emac1_mdio"; + drive-strength = <16>; + bias-pull-up; + }; + }; + + tc9563_resx_n: tc9563-resx-state { + pins = "gpio140"; + function = "gpio"; + + bias-disable; + input-disable; + output-enable; + power-source = <0>; + }; +}; From c60e979e0546b67bb06a5120deabc83504679795 Mon Sep 17 00:00:00 2001 From: Wenjia Zhang Date: Tue, 27 Jan 2026 12:26:53 +0530 Subject: [PATCH 2311/2333] QCLINUX: qcom.config: add crypto corresponding config Enable crypto api for user test. The configs are for testapp that's why the kernel upstream team would suggest having this enabled for clients who needs it and not by default since in qcom we need this, we should be enabling ideally in qcom-next. Signed-off-by: Wenjia Zhang Signed-off-by: Abhinaba Rakshit --- arch/arm64/configs/qcom.config | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/arm64/configs/qcom.config b/arch/arm64/configs/qcom.config index 5f379c86ee4d2..a0fedb2ccb7e0 100644 --- a/arch/arm64/configs/qcom.config +++ b/arch/arm64/configs/qcom.config @@ -68,3 +68,8 @@ CONFIG_WATCHDOG_PRETIMEOUT_GOV_PANIC=y CONFIG_WATCHDOG_PRETIMEOUT_GOV_SEL=m CONFIG_WATCHDOG_PRETIMEOUT_GOV=y CONFIG_ZRAM=y +# Support CRYPTO APIs +CONFIG_CRYPTO_USER_API=y +CONFIG_CRYPTO_USER_API_HASH=y +CONFIG_CRYPTO_USER_API_SKCIPHER=y +CONFIG_CRYPTO_USER_API_AEAD=y \ No newline at end of file From 215be9961589637adfc91388efed6b51ed5fe840 Mon Sep 17 00:00:00 2001 From: Shuai Zhang Date: Wed, 11 Feb 2026 16:51:01 +0800 Subject: [PATCH 2312/2333] BACKPORT: driver: bluetooth: hci_qca: Fix SSR (SubSystem Restart) fail when BT_EN is pulled up by hw On QCS9075 and QCA8275 platforms, the BT_EN pin is always pulled up by hw and cannot be controlled by the host. As a result, in case of a firmware crash, the host cannot trigger a cold reset. Instead, the BT controller performs a warm restart on its own, without reloading the firmware. This leads to the controller remaining in IBS_WAKE state, while the host expects it to be in sleep mode. The mismatch causes HCI reset commands to time out. Additionally, the driver does not clear internal flags QCA_SSR_TRIGGERED and QCA_IBS_DISABLED, which blocks the reset sequence. If the SSR duration exceeds 2 seconds, the host may enter TX sleep mode due to tx_idle_timeout, further preventing recovery. Also, memcoredump_flag is not cleared, so only the first SSR generates a coredump. Tell the driver that the BT controller has undergone a proper restart sequence: - Clear QCA_SSR_TRIGGERED and QCA_IBS_DISABLED flags after SSR. - Add a 50ms delay to allow the controller to complete its warm reset. - Reset tx_idle_timer to prevent the host from entering TX sleep mode. - Clear memcoredump_flag to allow multiple coredump captures. Apply these steps only when HCI_QUIRK_NON_PERSISTENT_SETUP is not set, which indicates that BT_EN is defined in DTS and cannot be toggled. Refer to the comment in include/net/bluetooth/hci.h for details on HCI_QUIRK_NON_PERSISTENT_SETUP. Reviewed-by: Dmitry Baryshkov Signed-off-by: Shuai Zhang link: https://lore.kernel.org/all/20251203033712.446632-1-shuai.zhang@oss.qualcomm.com/ --- drivers/bluetooth/hci_qca.c | 35 +++++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c index ec3850ee8f23d..a3c217571c3c4 100644 --- a/drivers/bluetooth/hci_qca.c +++ b/drivers/bluetooth/hci_qca.c @@ -1653,25 +1653,40 @@ static void qca_hw_error(struct hci_dev *hdev, u8 code) skb_queue_purge(&qca->rx_memdump_q); } - clear_bit(QCA_HW_ERROR_EVENT, &qca->flags); - /* - * If the SoC always enables the bt_en pin via hardware and the driver - * cannot control the bt_en pin of the SoC chip, then during SSR, - * the QCA_SSR_TRIGGERED and QCA_IBS_DISABLED bits cannot be cleared. - * This leads to a reset command timeout failure. + * If the BT chip's bt_en pin is connected to a 3.3V power supply via + * hardware and always stays high, driver cannot control the bt_en pin. + * As a result, during SSR (SubSystem Restart), QCA_SSR_TRIGGERED and + * QCA_IBS_DISABLED flags cannot be cleared, which leads to a reset + * command timeout. + * Add an msleep delay to ensure controller completes the SSR process. + * + * Host will not download the firmware after SSR, controller to remain + * in the IBS_WAKE state, and the host needs to synchronize with it * - * To address this, clear QCA_SSR_TRIGGERED and QCA_IBS_DISABLED bits - * after the coredump collection is complete. - * Also, add msleep delay to wait for controller to complete SSR. + * Since the bluetooth chip has been reset, clear the memdump state. */ if (!hci_test_quirk(hu->hdev, HCI_QUIRK_NON_PERSISTENT_SETUP)) { + /* + * When the SSR (SubSystem Restart) duration exceeds 2 seconds, + * it triggers host tx_idle_delay, which sets host TX state + * to sleep. Reset tx_idle_timer after SSR to prevent + * host enter TX IBS_Sleep mode. + */ + mod_timer(&qca->tx_idle_timer, jiffies + + msecs_to_jiffies(qca->tx_idle_delay)); + + /* Controller reset completion time is 50ms */ + msleep(50); + clear_bit(QCA_SSR_TRIGGERED, &qca->flags); clear_bit(QCA_IBS_DISABLED, &qca->flags); + qca->tx_ibs_state = HCI_IBS_TX_AWAKE; qca->memdump_state = QCA_MEMDUMP_IDLE; - msleep(50); } + + clear_bit(QCA_HW_ERROR_EVENT, &qca->flags); } static void qca_reset(struct hci_dev *hdev) From d4311674610c173c0464164532ef6e72fbc5a441 Mon Sep 17 00:00:00 2001 From: Umang Chheda Date: Tue, 10 Feb 2026 16:08:21 +0530 Subject: [PATCH 2313/2333] FROMLIST: arm64: dts: qcom: monaco-evk: Add Mezzanine The Mezzanine is an hardware expansion add-on board designed to be stacked on top of Monaco EVK. It has following peripherals : - 4x Type A USB ports in host mode. - TC9563 PCIe switch, which has following three downstream ports (DSP) : - 1st DSP connects M.2 E-key connector for connecting WLAN endpoints. - 2nd DSP connects M.2 B-key connector for connecting cellular modems. - 3rd DSP with support for Dual Ethernet ports. - EEPROM. - LVDS Display. - 2*mini DP. Add support for following peripherals : - TC9563 PCIe Switch. - EEPROM. Written with inputs from : Krishna Chaitanya Chundru - PCIe Monish Chunara - EEPROM. Signed-off-by: Umang Chheda Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20260210103821.4169-2-umang.chheda@oss.qualcomm.com --- arch/arm64/boot/dts/qcom/Makefile | 4 + .../boot/dts/qcom/monaco-evk-mezzanine.dtso | 189 ++++++++++++++++++ 2 files changed, 193 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/monaco-evk-mezzanine.dtso diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile index bce08f77d037e..dcc72068ec0ec 100644 --- a/arch/arm64/boot/dts/qcom/Makefile +++ b/arch/arm64/boot/dts/qcom/Makefile @@ -48,6 +48,10 @@ dtb-$(CONFIG_ARCH_QCOM) += monaco-evk-el2.dtb monaco-evk-camera-imx577-dtbs := monaco-evk.dtb monaco-evk-camera-imx577.dtbo dtb-$(CONFIG_ARCH_QCOM) += monaco-evk-camera-imx577.dtb + +monaco-evk-mezzanine-dtbs := monaco-evk.dtb monaco-evk-mezzanine.dtbo + +dtb-$(CONFIG_ARCH_QCOM) += monaco-evk-mezzanine.dtb dtb-$(CONFIG_ARCH_QCOM) += msm8216-samsung-fortuna3g.dtb dtb-$(CONFIG_ARCH_QCOM) += msm8916-acer-a1-724.dtb dtb-$(CONFIG_ARCH_QCOM) += msm8916-alcatel-idol347.dtb diff --git a/arch/arm64/boot/dts/qcom/monaco-evk-mezzanine.dtso b/arch/arm64/boot/dts/qcom/monaco-evk-mezzanine.dtso new file mode 100644 index 0000000000000..701494d4dd7f0 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/monaco-evk-mezzanine.dtso @@ -0,0 +1,189 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +/dts-v1/; +/plugin/; + +#include + +&{/} { + model = "Qualcomm Technologies, Inc. Monaco-EVK Mezzanine"; + + vreg_0p9: regulator-vreg-0p9 { + compatible = "regulator-fixed"; + regulator-name = "VREG_0P9"; + + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <900000>; + regulator-always-on; + regulator-boot-on; + + vin-supply = <&vreg_3p3>; + }; + + vreg_1p8: regulator-vreg-1p8 { + compatible = "regulator-fixed"; + regulator-name = "VREG_1P8"; + + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + regulator-boot-on; + + vin-supply = <&vreg_4p2>; + }; + + vreg_3p3: regulator-vreg-3p3 { + compatible = "regulator-fixed"; + regulator-name = "VREG_3P3"; + + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + regulator-boot-on; + + vin-supply = <&vreg_4p2>; + }; + + vreg_4p2: regulator-vreg-4p2 { + compatible = "regulator-fixed"; + regulator-name = "VREG_4P2"; + + regulator-min-microvolt = <4200000>; + regulator-max-microvolt = <4200000>; + regulator-always-on; + regulator-boot-on; + + vin-supply = <&vreg_sys_pwr>; + }; + + vreg_sys_pwr: regulator-vreg-sys-pwr { + compatible = "regulator-fixed"; + regulator-name = "VREG_SYS_PWR"; + + regulator-min-microvolt = <24000000>; + regulator-max-microvolt = <24000000>; + regulator-always-on; + regulator-boot-on; + }; +}; + +&i2c15 { + #address-cells = <1>; + #size-cells = <0>; + + status = "okay"; + + eeprom1: eeprom@52 { + compatible = "giantec,gt24c256c", "atmel,24c256"; + reg = <0x52>; + pagesize = <64>; + + nvmem-layout { + compatible = "fixed-layout"; + #address-cells = <1>; + #size-cells = <1>; + }; + }; +}; + +&pcie0 { + iommu-map = <0x0 &pcie_smmu 0x0 0x1>, + <0x100 &pcie_smmu 0x1 0x1>, + <0x208 &pcie_smmu 0x2 0x1>, + <0x210 &pcie_smmu 0x3 0x1>, + <0x218 &pcie_smmu 0x4 0x1>, + <0x300 &pcie_smmu 0x5 0x1>, + <0x400 &pcie_smmu 0x6 0x1>, + <0x500 &pcie_smmu 0x7 0x1>, + <0x501 &pcie_smmu 0x8 0x1>; +}; + +&pcieport0 { + #address-cells = <3>; + #size-cells = <2>; + + pcie@0,0 { + compatible = "pci1179,0623"; + reg = <0x10000 0x0 0x0 0x0 0x0>; + #address-cells = <3>; + #size-cells = <2>; + + device_type = "pci"; + ranges; + bus-range = <0x2 0xff>; + + vddc-supply = <&vreg_0p9>; + vdd18-supply = <&vreg_1p8>; + vdd09-supply = <&vreg_0p9>; + vddio1-supply = <&vreg_1p8>; + vddio2-supply = <&vreg_1p8>; + vddio18-supply = <&vreg_1p8>; + + i2c-parent = <&i2c15 0x77>; + + resx-gpios = <&tlmm 124 GPIO_ACTIVE_LOW>; + + pinctrl-0 = <&tc9563_resx_n>; + pinctrl-names = "default"; + + pcie@1,0 { + reg = <0x20800 0x0 0x0 0x0 0x0>; + #address-cells = <3>; + #size-cells = <2>; + + device_type = "pci"; + ranges; + bus-range = <0x3 0xff>; + }; + + pcie@2,0 { + reg = <0x21000 0x0 0x0 0x0 0x0>; + #address-cells = <3>; + #size-cells = <2>; + + device_type = "pci"; + ranges; + bus-range = <0x4 0xff>; + }; + + pcie@3,0 { + reg = <0x21800 0x0 0x0 0x0 0x0>; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + ranges; + bus-range = <0x5 0xff>; + + pci@0,0 { + reg = <0x50000 0x0 0x0 0x0 0x0>; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + ranges; + }; + + pci@0,1 { + reg = <0x50100 0x0 0x0 0x0 0x0>; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + ranges; + }; + }; + }; +}; + +&tlmm { + tc9563_resx_n: tc9563-resx-state { + pins = "gpio124"; + function = "gpio"; + + bias-disable; + input-disable; + output-enable; + power-source = <0>; + }; +}; From 154d65ed501d3959822364a1dcea5c0e90c6f72b Mon Sep 17 00:00:00 2001 From: Sushrut Shree Trivedi Date: Thu, 12 Feb 2026 17:36:29 +0530 Subject: [PATCH 2314/2333] FROMLIST: arm64: dts: qcom: qcm6490-idp: Enable PCIe1 Remove PCIe1 clocks from protected-list and enable PCIe1 controller and its corresponding PHY nodes on qcm6490-idp platform. PCIe1 is used to connect NVMe based SSD's on this platform. Signed-off-by: Sushrut Shree Trivedi Link: https://lore.kernel.org/all/20260212-qcm6490-idp-v1-1-80a45bd46ac5@oss.qualcomm.com/ --- arch/arm64/boot/dts/qcom/qcm6490-idp.dts | 39 ++++++++++++++++++++---- 1 file changed, 33 insertions(+), 6 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/qcm6490-idp.dts b/arch/arm64/boot/dts/qcom/qcm6490-idp.dts index a65ec8dc873e5..c28e607304d5e 100644 --- a/arch/arm64/boot/dts/qcom/qcm6490-idp.dts +++ b/arch/arm64/boot/dts/qcom/qcm6490-idp.dts @@ -591,12 +591,7 @@ }; &gcc { - protected-clocks = ,, - , , - , , - , , - , , - , , + protected-clocks = , , ,, , , , @@ -673,6 +668,22 @@ status = "okay"; }; +&pcie1 { + perst-gpios = <&tlmm 2 GPIO_ACTIVE_LOW>; + + pinctrl-0 = <&pcie1_reset_n>, <&pcie1_wake_n>, <&pcie1_clkreq_n>; + pinctrl-names = "default"; + + status = "okay"; +}; + +&pcie1_phy { + vdda-phy-supply = <&vreg_l10c_0p88>; + vdda-pll-supply = <&vreg_l6b_1p2>; + + status = "okay"; +}; + &pm7250b_gpios { lcd_disp_bias_en: lcd-disp-bias-en-state { pins = "gpio2"; @@ -1071,6 +1082,22 @@ bias-pull-up; }; + pcie1_reset_n: pcie1-reset-n-state { + pins = "gpio2"; + function = "gpio"; + drive-strength = <16>; + output-low; + bias-disable; + }; + + pcie1_wake_n: pcie1-wake-n-state { + pins = "gpio3"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + + sd_cd: sd-cd-state { pins = "gpio91"; function = "gpio"; From 0cc14a562173cf86e179889849c56f62073e63ee Mon Sep 17 00:00:00 2001 From: Krishna Chaitanya Chundru Date: Mon, 2 Feb 2026 12:55:21 +0530 Subject: [PATCH 2315/2333] WORKAROUND: PCI: Disable L1ss through quirk for HMT & Cologne When PCIe L1ss is enabled, WLAN functionality is completly broken. There are some connectivity issues in this platform mostly with CLKREQ# pin. Disable L1ss as workaround untill actual issue get resolved. Signed-off-by: Krishna Chaitanya Chundru --- drivers/pci/quirks.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index a51dab62ecef6..dac87453177fa 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -2532,6 +2532,8 @@ static void quirk_disable_aspm_l1ss(struct pci_dev *dev) pci_disable_link_state(dev, PCIE_LINK_STATE_L1_1 | PCIE_LINK_STATE_L1_2); } DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_QCOM, 0x1103, quirk_disable_aspm_l1ss); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_QCOM, 0x1107, quirk_disable_aspm_l1ss); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_QCOM, 0x1112, quirk_disable_aspm_l1ss); /* * Some Pericom PCIe-to-PCI bridges in reverse mode need the PCIe Retrain From b61b388f282c6bf30b41a239a43a1a6823e1f84e Mon Sep 17 00:00:00 2001 From: Jinwang Li Date: Mon, 5 Jan 2026 20:25:05 +0800 Subject: [PATCH 2316/2333] FROMLIST: driver: bluetooth: hci_qca: Cleanup on all setup failures The setup process previously combined error handling and retry gating under one condition. As a result, the final failed attempt exited without performing cleanup. Update the failure path to always perform power cleanup onsetup failure, and reopen the port only when retrying. Fixes: 9e80587aba4c ("Bluetooth: hci_qca: Enhance retry logic in qca_setup") Signed-off-by: Jinwang Li Reviewed-by: Bartosz Golaszewski Link: https://lore.kernel.org/all/20260205062600.590342-1-jinwang.li@oss.qualcomm.com/ CRs-Fixed: 4378012 --- drivers/bluetooth/hci_qca.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c index ec3850ee8f23d..2f24ed6f8b16d 100644 --- a/drivers/bluetooth/hci_qca.c +++ b/drivers/bluetooth/hci_qca.c @@ -2030,19 +2030,23 @@ static int qca_setup(struct hci_uart *hu) } out: - if (ret && retries < MAX_INIT_RETRIES) { - bt_dev_warn(hdev, "Retry BT power ON:%d", retries); + if (ret) { qca_power_shutdown(hu); - if (hu->serdev) { - serdev_device_close(hu->serdev); - ret = serdev_device_open(hu->serdev); - if (ret) { - bt_dev_err(hdev, "failed to open port"); - return ret; + + if (retries < MAX_INIT_RETRIES) { + bt_dev_warn(hdev, "Retry BT power ON:%d", retries); + if (hu->serdev) { + serdev_device_close(hu->serdev); + ret = serdev_device_open(hu->serdev); + if (ret) { + bt_dev_err(hdev, "failed to open port"); + return ret; + } } + retries++; + goto retry; } - retries++; - goto retry; + return ret; } /* Setup bdaddr */ From 257523dc1436635ca763159bb678f72dc95f3d93 Mon Sep 17 00:00:00 2001 From: Mukesh Ojha Date: Thu, 12 Feb 2026 15:36:44 +0530 Subject: [PATCH 2317/2333] FROMLIST: media: iris: Enable Secure PAS support with IOMMU managed by Linux Most Qualcomm platforms feature a inhouse hypervisor (such as Gunyah or QHEE), which typically handles IOMMU configuration. This includes mapping memory regions and device memory resources for remote processors by intercepting qcom_scm_pas_auth_and_reset() calls. These mappings are later removed during teardown. Additionally, SHM bridge setup is required to enable memory protection for both remoteproc metadata and its memory regions. When the hypervisor is absent, the operating system must perform these configurations instead. Support for handling IOMMU and SHM setup in the absence of a hypervisor is now in place. Extend the Iris driver to enable this functionality on platforms where IOMMU is managed by Linux (i.e., non-Gunyah, non-QHEE). Additionally, the Iris driver must map the firmware and its required resources to the firmware SID, which is now specified via the device tree. Link: https://lore.kernel.org/lkml/20250819165447.4149674-12-mukesh.ojha@oss.qualcomm.com/ Signed-off-by: Vikash Garodia Signed-off-by: Mukesh Ojha --- drivers/media/platform/qcom/iris/iris_core.c | 9 +- drivers/media/platform/qcom/iris/iris_core.h | 5 + .../media/platform/qcom/iris/iris_firmware.c | 129 ++++++++++++++++-- .../media/platform/qcom/iris/iris_firmware.h | 2 + 4 files changed, 134 insertions(+), 11 deletions(-) diff --git a/drivers/media/platform/qcom/iris/iris_core.c b/drivers/media/platform/qcom/iris/iris_core.c index 8406c48d635b6..62a9e15b47372 100644 --- a/drivers/media/platform/qcom/iris/iris_core.c +++ b/drivers/media/platform/qcom/iris/iris_core.c @@ -18,6 +18,7 @@ void iris_core_deinit(struct iris_core *core) if (core->state != IRIS_CORE_DEINIT) { iris_fw_unload(core); iris_vpu_power_off(core); + iris_fw_deinit(core); iris_hfi_queues_deinit(core); core->state = IRIS_CORE_DEINIT; } @@ -67,10 +68,14 @@ int iris_core_init(struct iris_core *core) if (ret) goto error_queue_deinit; - ret = iris_fw_load(core); + ret = iris_fw_init(core); if (ret) goto error_power_off; + ret = iris_fw_load(core); + if (ret) + goto error_firmware_deinit; + ret = iris_vpu_boot_firmware(core); if (ret) goto error_unload_fw; @@ -85,6 +90,8 @@ int iris_core_init(struct iris_core *core) error_unload_fw: iris_fw_unload(core); +error_firmware_deinit: + iris_fw_deinit(core); error_power_off: iris_vpu_power_off(core); error_queue_deinit: diff --git a/drivers/media/platform/qcom/iris/iris_core.h b/drivers/media/platform/qcom/iris/iris_core.h index fb194c967ad4f..ef081ccc3429d 100644 --- a/drivers/media/platform/qcom/iris/iris_core.h +++ b/drivers/media/platform/qcom/iris/iris_core.h @@ -82,6 +82,11 @@ struct iris_core { struct v4l2_device v4l2_dev; struct video_device *vdev_dec; struct video_device *vdev_enc; + struct video_firmware { + struct device *dev; + struct qcom_scm_pas_context *ctx; + struct iommu_domain *iommu_domain; + } fw; const struct v4l2_file_operations *iris_v4l2_file_ops; const struct v4l2_ioctl_ops *iris_v4l2_ioctl_ops_dec; const struct v4l2_ioctl_ops *iris_v4l2_ioctl_ops_enc; diff --git a/drivers/media/platform/qcom/iris/iris_firmware.c b/drivers/media/platform/qcom/iris/iris_firmware.c index 9ab499fad9464..fd1d70d1d4d72 100644 --- a/drivers/media/platform/qcom/iris/iris_firmware.c +++ b/drivers/media/platform/qcom/iris/iris_firmware.c @@ -3,10 +3,15 @@ * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ +#include #include #include +#include +#include #include +#include #include +#include #include #include "iris_core.h" @@ -17,6 +22,7 @@ static int iris_load_fw_to_memory(struct iris_core *core, const char *fw_name) { u32 pas_id = core->iris_platform_data->pas_id; + struct qcom_scm_pas_context *ctx; const struct firmware *firmware = NULL; struct device *dev = core->dev; struct reserved_mem *rmem; @@ -42,6 +48,14 @@ static int iris_load_fw_to_memory(struct iris_core *core, const char *fw_name) mem_phys = rmem->base; res_size = rmem->size; + dev = core->fw.dev ? : core->dev; + + ctx = devm_qcom_scm_pas_context_alloc(dev, pas_id, mem_phys, res_size); + if (!ctx) + return -ENOMEM; + + ctx->use_tzmem = core->fw.dev; + ret = request_firmware(&firmware, fw_name, dev); if (ret) return ret; @@ -58,9 +72,29 @@ static int iris_load_fw_to_memory(struct iris_core *core, const char *fw_name) goto err_release_fw; } - ret = qcom_mdt_load(dev, firmware, fw_name, - pas_id, mem_virt, mem_phys, res_size, NULL); + ret = qcom_mdt_pas_load(ctx, firmware, fw_name, mem_virt, NULL); + qcom_scm_pas_metadata_release(ctx); + if (ret) + goto err_mem_unmap; + + if (core->fw.iommu_domain) { + ret = iommu_map(core->fw.iommu_domain, 0, mem_phys, res_size, + IOMMU_READ | IOMMU_WRITE | IOMMU_PRIV, GFP_KERNEL); + if (ret) + goto err_mem_unmap; + } + ret = qcom_scm_pas_prepare_and_auth_reset(ctx); + if (ret) + goto err_iommu_unmap; + + core->fw.ctx = ctx; + + return ret; + +err_iommu_unmap: + iommu_unmap(core->fw.iommu_domain, 0, res_size); +err_mem_unmap: memunmap(mem_virt); err_release_fw: release_firmware(firmware); @@ -85,19 +119,13 @@ int iris_fw_load(struct iris_core *core) return -ENOMEM; } - ret = qcom_scm_pas_auth_and_reset(core->iris_platform_data->pas_id); - if (ret) { - dev_err(core->dev, "auth and reset failed: %d\n", ret); - return ret; - } - ret = qcom_scm_mem_protect_video_var(cp_config->cp_start, cp_config->cp_size, cp_config->cp_nonpixel_start, cp_config->cp_nonpixel_size); if (ret) { dev_err(core->dev, "protect memory failed\n"); - qcom_scm_pas_shutdown(core->iris_platform_data->pas_id); + iris_fw_unload(core); return ret; } @@ -106,10 +134,91 @@ int iris_fw_load(struct iris_core *core) int iris_fw_unload(struct iris_core *core) { - return qcom_scm_pas_shutdown(core->iris_platform_data->pas_id); + struct qcom_scm_pas_context *ctx = core->fw.ctx; + int ret; + + if (!ctx) + return -EINVAL; + + ret = qcom_scm_pas_shutdown(ctx->pas_id); + if (core->fw.iommu_domain) + iommu_unmap(core->fw.iommu_domain, 0, ctx->mem_size); + + core->fw.ctx = NULL; + return ret; } int iris_set_hw_state(struct iris_core *core, bool resume) { return qcom_scm_set_remote_state(resume, 0); } + +int iris_fw_init(struct iris_core *core) +{ + struct platform_device_info info; + struct iommu_domain *iommu_dom; + struct platform_device *pdev; + struct device_node *np; + int ret; + + np = of_get_child_by_name(core->dev->of_node, "video-firmware"); + if (!np) + return 0; + + memset(&info, 0, sizeof(info)); + info.fwnode = &np->fwnode; + info.parent = core->dev; + info.name = np->name; + info.dma_mask = DMA_BIT_MASK(32); + + pdev = platform_device_register_full(&info); + if (IS_ERR(pdev)) { + of_node_put(np); + return PTR_ERR(pdev); + } + + pdev->dev.of_node = np; + + ret = of_dma_configure(&pdev->dev, np, true); + if (ret) + goto err_unregister; + + core->fw.dev = &pdev->dev; + + iommu_dom = iommu_get_domain_for_dev(core->fw.dev); + if (!iommu_dom) { + ret = -EINVAL; + goto err_unset_fw_dev; + } + + ret = iommu_attach_device(iommu_dom, core->fw.dev); + if (ret) + goto err_unset_fw_dev; + + core->fw.iommu_domain = iommu_dom; + + of_node_put(np); + + return 0; + +err_unset_fw_dev: + core->fw.dev = NULL; +err_unregister: + platform_device_unregister(pdev); + of_node_put(np); + return ret; +} + +void iris_fw_deinit(struct iris_core *core) +{ + if (!core->fw.dev) + return; + + if (core->fw.iommu_domain) { + iommu_detach_device(core->fw.iommu_domain, core->fw.dev); + core->fw.iommu_domain = NULL; + } + + platform_device_unregister(to_platform_device(core->fw.dev)); + core->fw.dev = NULL; +} diff --git a/drivers/media/platform/qcom/iris/iris_firmware.h b/drivers/media/platform/qcom/iris/iris_firmware.h index e833ecd348871..adde461099667 100644 --- a/drivers/media/platform/qcom/iris/iris_firmware.h +++ b/drivers/media/platform/qcom/iris/iris_firmware.h @@ -11,5 +11,7 @@ struct iris_core; int iris_fw_load(struct iris_core *core); int iris_fw_unload(struct iris_core *core); int iris_set_hw_state(struct iris_core *core, bool resume); +int iris_fw_init(struct iris_core *core); +void iris_fw_deinit(struct iris_core *core); #endif From 012a484a0d1c3c3f2692983171a4a6d7be4cf927 Mon Sep 17 00:00:00 2001 From: Mukesh Ojha Date: Thu, 12 Feb 2026 15:51:56 +0530 Subject: [PATCH 2318/2333] PENDING: arm64: dts: qcom: Add EL2 support for Iris for lemans Add support for IRIS on lemans when Linux host running at EL2. Signed-off-by: Vikash Garodia Signed-off-by: Mukesh Ojha --- arch/arm64/boot/dts/qcom/lemans-el2.dtso | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/lemans-el2.dtso b/arch/arm64/boot/dts/qcom/lemans-el2.dtso index 7c1bd425cd5df..98153a06b4bbf 100644 --- a/arch/arm64/boot/dts/qcom/lemans-el2.dtso +++ b/arch/arm64/boot/dts/qcom/lemans-el2.dtso @@ -15,8 +15,9 @@ }; &iris { - /* More driver work is needed */ - status = "disabled"; + video-firmware { + iommus = <&apps_smmu 0x0882 0x0400>; + }; }; /* From 9a19448ca6d7280fa138b6865bc4096829938fea Mon Sep 17 00:00:00 2001 From: Pradeep P V K Date: Wed, 26 Nov 2025 18:41:46 +0530 Subject: [PATCH 2319/2333] UPSTREAM: arm64: dts: qcom: talos: Correct UFS clocks ordering The current UFS clocks does not align with their respective names, causing the ref_clk to be set to an incorrect frequency as below, which results in command timeouts. ufshcd-qcom 1d84000.ufshc: invalid ref_clk setting = 300000000 This commit fixes the issue by properly reordering the UFS clocks to match their names. CRs-Fixed: 4439641 Fixes: ea172f61f4fd ("arm64: dts: qcom: qcs615: Fix up UFS clocks") Cc: stable@vger.kernel.org Reviewed-by: Dmitry Baryshkov Signed-off-by: Pradeep P V K Link: https://lore.kernel.org/all/20251126131146.16146-1-pradeep.pragallapati@oss.qualcomm.com/ --- arch/arm64/boot/dts/qcom/talos.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/talos.dtsi b/arch/arm64/boot/dts/qcom/talos.dtsi index 4f9fd435acd81..ca1f899a9c3fe 100644 --- a/arch/arm64/boot/dts/qcom/talos.dtsi +++ b/arch/arm64/boot/dts/qcom/talos.dtsi @@ -1421,10 +1421,10 @@ <&gcc GCC_AGGRE_UFS_PHY_AXI_CLK>, <&gcc GCC_UFS_PHY_AHB_CLK>, <&gcc GCC_UFS_PHY_UNIPRO_CORE_CLK>, - <&gcc GCC_UFS_PHY_ICE_CORE_CLK>, <&rpmhcc RPMH_CXO_CLK>, <&gcc GCC_UFS_PHY_TX_SYMBOL_0_CLK>, - <&gcc GCC_UFS_PHY_RX_SYMBOL_0_CLK>; + <&gcc GCC_UFS_PHY_RX_SYMBOL_0_CLK>, + <&gcc GCC_UFS_PHY_ICE_CORE_CLK>; clock-names = "core_clk", "bus_aggr_clk", "iface_clk", From 9c47fe9517d7e7be00d9ae14b09490d596a98088 Mon Sep 17 00:00:00 2001 From: Yijie Yang Date: Wed, 11 Feb 2026 21:24:23 +0530 Subject: [PATCH 2320/2333] FROMLIST: net: stmmac: Inverse the phy-mode definition In the initial device tree submission, the definitions of rgmii and rgmii-id in the phy-mode property were inverted compared to the conventions used by the upstream Linux kernel community. Only QCS-EVB-400 and SA8155-ADP platforms are affected due to the incorrect PHY mode configuration: 'rgmii' was used instead of the correct 'rgmii-id'. This change results in an ABI compatibility break, but it is acceptable as these platforms are not actively used by any customers, based on current observations. Qualcomm expects the MAC, not the PHY, to introduce the timing delay, and the driver is designed accordingly. This is due to specific SoC hardware that handles delay and sampling internally. Link: https://lore.kernel.org/netdev/20250819-qcs615_eth-v4-2-5050ed3402cb@oss.qualcomm.com/ Signed-off-by: Yijie Yang Signed-off-by: Mohd Ayaan Anwar --- .../ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c index d8fd4d8f6ced7..7117559ddaf14 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c @@ -387,14 +387,11 @@ static int ethqos_dll_configure(struct qcom_ethqos *ethqos) static int ethqos_rgmii_macro_init(struct qcom_ethqos *ethqos, int speed) { struct device *dev = ðqos->pdev->dev; - int phase_shift; + int phase_shift = 0; int loopback; /* Determine if the PHY adds a 2 ns TX delay or the MAC handles it */ - if (ethqos->phy_mode == PHY_INTERFACE_MODE_RGMII_ID || - ethqos->phy_mode == PHY_INTERFACE_MODE_RGMII_TXID) - phase_shift = 0; - else + if (ethqos->phy_mode == PHY_INTERFACE_MODE_RGMII_ID) phase_shift = RGMII_CONFIG2_TX_CLK_PHASE_SHIFT_EN; /* Disable loopback mode */ @@ -789,7 +786,14 @@ static int qcom_ethqos_probe(struct platform_device *pdev) if (!ethqos) return -ENOMEM; + /* Qualcomm configures the MAC to introduce delay; instruct the + * PHY not to add additional delay. + */ + if (plat_dat->phy_interface == PHY_INTERFACE_MODE_RGMII_ID) + plat_dat->phy_interface = PHY_INTERFACE_MODE_RGMII; + ethqos->phy_mode = plat_dat->phy_interface; + switch (ethqos->phy_mode) { case PHY_INTERFACE_MODE_RGMII: case PHY_INTERFACE_MODE_RGMII_ID: From 773ee6e7f6d40cf2de493c6fef5e3e493b497009 Mon Sep 17 00:00:00 2001 From: Yijie Yang Date: Wed, 11 Feb 2026 21:27:53 +0530 Subject: [PATCH 2321/2333] FROMLIST: arm64: dts: qcom: talos: add ethernet node Add an ethernet controller node for QCS615 SoC to enable ethernet functionality. Link: https://lore.kernel.org/netdev/20250819-qcs615_eth-v4-3-5050ed3402cb@oss.qualcomm.com/ Signed-off-by: Yijie Yang Signed-off-by: Mohd Ayaan Anwar --- arch/arm64/boot/dts/qcom/talos.dtsi | 34 +++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/talos.dtsi b/arch/arm64/boot/dts/qcom/talos.dtsi index ca1f899a9c3fe..bcffaf1327f00 100644 --- a/arch/arm64/boot/dts/qcom/talos.dtsi +++ b/arch/arm64/boot/dts/qcom/talos.dtsi @@ -678,6 +678,40 @@ #address-cells = <2>; #size-cells = <2>; + ethernet: ethernet@20000 { + compatible = "qcom,qcs615-ethqos", "qcom,qcs404-ethqos"; + reg = <0x0 0x00020000 0x0 0x10000>, + <0x0 0x00036000 0x0 0x100>; + reg-names = "stmmaceth", + "rgmii"; + + clocks = <&gcc GCC_EMAC_AXI_CLK>, + <&gcc GCC_EMAC_SLV_AHB_CLK>, + <&gcc GCC_EMAC_PTP_CLK>, + <&gcc GCC_EMAC_RGMII_CLK>; + clock-names = "stmmaceth", + "pclk", + "ptp_ref", + "rgmii"; + + interrupts = , + ; + interrupt-names = "macirq", + "eth_lpi"; + + power-domains = <&gcc EMAC_GDSC>; + resets = <&gcc GCC_EMAC_BCR>; + + iommus = <&apps_smmu 0x1c0 0x0>; + + snps,tso; + snps,pbl = <32>; + rx-fifo-depth = <16384>; + tx-fifo-depth = <20480>; + + status = "disabled"; + }; + gcc: clock-controller@100000 { compatible = "qcom,qcs615-gcc"; reg = <0 0x00100000 0 0x1f0000>; From 361fefe14011099f914ae71db232462e7b268a38 Mon Sep 17 00:00:00 2001 From: Yijie Yang Date: Wed, 11 Feb 2026 21:30:18 +0530 Subject: [PATCH 2322/2333] FROMLIST: arm64: dts: qcom: qcs615-ride: Enable ethernet node Enable the ethernet node, add the phy node and pinctrl for ethernet. Link: https://lore.kernel.org/netdev/20250819-qcs615_eth-v4-4-5050ed3402cb@oss.qualcomm.com/ Signed-off-by: Yijie Yang Signed-off-by: Mohd Ayaan Anwar --- arch/arm64/boot/dts/qcom/qcs615-ride.dts | 102 +++++++++++++++++++++++ 1 file changed, 102 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/qcs615-ride.dts b/arch/arm64/boot/dts/qcom/qcs615-ride.dts index 851ff7de4d464..59ef546008539 100644 --- a/arch/arm64/boot/dts/qcom/qcs615-ride.dts +++ b/arch/arm64/boot/dts/qcom/qcs615-ride.dts @@ -372,6 +372,59 @@ }; }; +ðernet { + pinctrl-0 = <ðernet_defaults>; + pinctrl-names = "default"; + + phy-handle = <&rgmii_phy>; + phy-mode = "rgmii-id"; + + snps,mtl-rx-config = <&mtl_rx_setup>; + snps,mtl-tx-config = <&mtl_tx_setup>; + + status = "okay"; + + mdio: mdio { + compatible = "snps,dwmac-mdio"; + #address-cells = <1>; + #size-cells = <0>; + + rgmii_phy: phy@7 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <0x7>; + + interrupts-extended = <&tlmm 121 IRQ_TYPE_EDGE_FALLING>; + device_type = "ethernet-phy"; + reset-gpios = <&tlmm 104 GPIO_ACTIVE_LOW>; + reset-assert-us = <11000>; + reset-deassert-us = <70000>; + }; + }; + + mtl_rx_setup: rx-queues-config { + snps,rx-queues-to-use = <1>; + snps,rx-sched-sp; + + queue0 { + snps,dcb-algorithm; + snps,map-to-dma-channel = <0x0>; + snps,route-up; + snps,priority = <0x1>; + }; + }; + + mtl_tx_setup: tx-queues-config { + snps,tx-queues-to-use = <1>; + snps,tx-sched-wrr; + + queue0 { + snps,weight = <0x10>; + snps,dcb-algorithm; + snps,priority = <0x0>; + }; + }; +}; + &gpu { status = "okay"; }; @@ -552,6 +605,55 @@ }; &tlmm { + ethernet_defaults: ethernet-defaults-state { + mdc-pins { + pins = "gpio113"; + function = "rgmii"; + bias-pull-up; + }; + + mdio-pins { + pins = "gpio114"; + function = "rgmii"; + bias-pull-up; + }; + + rgmii-rx-pins { + pins = "gpio81", "gpio82", "gpio83", "gpio102", "gpio103", "gpio112"; + function = "rgmii"; + bias-disable; + drive-strength = <2>; + }; + + rgmii-tx-pins { + pins = "gpio92", "gpio93", "gpio94", "gpio95", "gpio96", "gpio97"; + function = "rgmii"; + bias-pull-up; + drive-strength = <16>; + }; + + phy-intr-pins { + pins = "gpio121"; + function = "gpio"; + bias-disable; + drive-strength = <8>; + }; + + pps-pins { + pins = "gpio91"; + function = "rgmii"; + bias-disable; + drive-strength = <8>; + }; + + phy-reset-pins { + pins = "gpio104"; + function = "gpio"; + bias-pull-up; + drive-strength = <16>; + }; + }; + bt_en_state: bt-en-state { pins = "gpio85"; function = "gpio"; From 4d6244b845687a8e76205b9a407aaaefe99c45fb Mon Sep 17 00:00:00 2001 From: Krishna Chaitanya Chundru Date: Wed, 4 Feb 2026 15:55:37 +0530 Subject: [PATCH 2323/2333] Revert "FROMLIST: arm64: dts: qcom: qcs6490-rb3gen2: Add TC9563 PCIe switch node" This reverts commit 90671a19c6c95f4acd18702dde28e82212cfd5d5. There is difference between fromlist version and merged version of this change, this version is not compatible with merged dtbindings and driver changes so reverting the fromlist version. Signed-off-by: Krishna Chaitanya Chundru --- arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts | 128 ------------------- arch/arm64/boot/dts/qcom/sc7280.dtsi | 2 +- 2 files changed, 1 insertion(+), 129 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts b/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts index b66bbdc561d05..ede28094a46ea 100644 --- a/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts +++ b/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts @@ -262,30 +262,6 @@ regulator-max-microvolt = <3700000>; }; - vdd_ntn_0p9: regulator-vdd-ntn-0p9 { - compatible = "regulator-fixed"; - regulator-name = "VDD_NTN_0P9"; - gpio = <&pm8350c_gpios 2 GPIO_ACTIVE_HIGH>; - regulator-min-microvolt = <899400>; - regulator-max-microvolt = <899400>; - enable-active-high; - pinctrl-0 = <&ntn_0p9_en>; - pinctrl-names = "default"; - regulator-enable-ramp-delay = <4300>; - }; - - vdd_ntn_1p8: regulator-vdd-ntn-1p8 { - compatible = "regulator-fixed"; - regulator-name = "VDD_NTN_1P8"; - gpio = <&pm8350c_gpios 3 GPIO_ACTIVE_HIGH>; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; - enable-active-high; - pinctrl-0 = <&ntn_1p8_en>; - pinctrl-names = "default"; - regulator-enable-ramp-delay = <10000>; - }; - wcn6750-pmu { compatible = "qcom,wcn6750-pmu"; pinctrl-0 = <&bt_en>; @@ -867,78 +843,6 @@ status = "okay"; }; -&pcie1_port0 { - pcie@0,0 { - compatible = "pci1179,0623"; - reg = <0x10000 0x0 0x0 0x0 0x0>; - #address-cells = <3>; - #size-cells = <2>; - - device_type = "pci"; - ranges; - bus-range = <0x2 0xff>; - - vddc-supply = <&vdd_ntn_0p9>; - vdd18-supply = <&vdd_ntn_1p8>; - vdd09-supply = <&vdd_ntn_0p9>; - vddio1-supply = <&vdd_ntn_1p8>; - vddio2-supply = <&vdd_ntn_1p8>; - vddio18-supply = <&vdd_ntn_1p8>; - - i2c-parent = <&i2c0 0x77>; - - reset-gpios = <&pm8350c_gpios 1 GPIO_ACTIVE_LOW>; - - pinctrl-0 = <&tc9563_rsex_n>; - pinctrl-names = "default"; - - pcie@1,0 { - reg = <0x20800 0x0 0x0 0x0 0x0>; - #address-cells = <3>; - #size-cells = <2>; - - device_type = "pci"; - ranges; - bus-range = <0x3 0xff>; - }; - - pcie@2,0 { - reg = <0x21000 0x0 0x0 0x0 0x0>; - #address-cells = <3>; - #size-cells = <2>; - - device_type = "pci"; - ranges; - bus-range = <0x4 0xff>; - }; - - pcie@3,0 { - reg = <0x21800 0x0 0x0 0x0 0x0>; - #address-cells = <3>; - #size-cells = <2>; - device_type = "pci"; - ranges; - bus-range = <0x5 0xff>; - - pci@0,0 { - reg = <0x50000 0x0 0x0 0x0 0x0>; - #address-cells = <3>; - #size-cells = <2>; - device_type = "pci"; - ranges; - }; - - pci@0,1 { - reg = <0x50100 0x0 0x0 0x0 0x0>; - #address-cells = <3>; - #size-cells = <2>; - device_type = "pci"; - ranges; - }; - }; - }; -}; - &pm7325_gpios { kypd_vol_up_n: kypd-vol-up-n-state { pins = "gpio6"; @@ -949,38 +853,6 @@ }; }; -&pm8350c_gpios { - ntn_0p9_en: ntn-0p9-en-state { - pins = "gpio2"; - function = "normal"; - - bias-disable; - input-disable; - output-enable; - power-source = <0>; - }; - - ntn_1p8_en: ntn-1p8-en-state { - pins = "gpio3"; - function = "normal"; - - bias-disable; - input-disable; - output-enable; - power-source = <0>; - }; - - tc9563_rsex_n: tc9563-resx-state { - pins = "gpio1"; - function = "normal"; - - bias-disable; - input-disable; - output-enable; - power-source = <0>; - }; -}; - &pm7325_temp_alarm { io-channels = <&pmk8350_vadc PM7325_ADC7_DIE_TEMP>; io-channel-names = "thermal"; diff --git a/arch/arm64/boot/dts/qcom/sc7280.dtsi b/arch/arm64/boot/dts/qcom/sc7280.dtsi index 68ed072389372..2dacd98d26cb6 100644 --- a/arch/arm64/boot/dts/qcom/sc7280.dtsi +++ b/arch/arm64/boot/dts/qcom/sc7280.dtsi @@ -2429,7 +2429,7 @@ status = "disabled"; - pcie1_port0: pcie@0 { + pcie@0 { device_type = "pci"; reg = <0x0 0x0 0x0 0x0 0x0>; bus-range = <0x01 0xff>; From 6293ef1b63ef1df8b4ef3be9e8d595fc5c018112 Mon Sep 17 00:00:00 2001 From: Krishna Chaitanya Chundru Date: Mon, 5 Jan 2026 15:55:24 +0530 Subject: [PATCH 2324/2333] BACKPORT: arm64: dts: qcom: qcs6490-rb3gen2: Add TC9563 PCIe switch nodei Add a node for the TC9563 PCIe switch, which has three downstream ports. Two embedded Ethernet devices are present on one of the downstream ports. As all these ports are present in the node represent the downstream ports and embedded endpoints. Power to the TC9563 is supplied through two LDO regulators, controlled by two GPIOs, which are added as fixed regulators. Configure the TC9563 through I2C. Reviewed-by: Bjorn Andersson Acked-by: Manivannan Sadhasivam Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20260105-tc9563-v1-1-642fd1fe7893@oss.qualcomm.com Signed-off-by: Krishna Chaitanya Chundru --- arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts | 128 +++++++++++++++++++ arch/arm64/boot/dts/qcom/sc7280.dtsi | 2 +- 2 files changed, 129 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts b/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts index ede28094a46ea..d6eeda945c3d5 100644 --- a/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts +++ b/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts @@ -262,6 +262,30 @@ regulator-max-microvolt = <3700000>; }; + vdd_ntn_0p9: regulator-vdd-ntn-0p9 { + compatible = "regulator-fixed"; + regulator-name = "VDD_NTN_0P9"; + gpio = <&pm8350c_gpios 2 GPIO_ACTIVE_HIGH>; + regulator-min-microvolt = <899400>; + regulator-max-microvolt = <899400>; + enable-active-high; + pinctrl-0 = <&ntn_0p9_en>; + pinctrl-names = "default"; + regulator-enable-ramp-delay = <4300>; + }; + + vdd_ntn_1p8: regulator-vdd-ntn-1p8 { + compatible = "regulator-fixed"; + regulator-name = "VDD_NTN_1P8"; + gpio = <&pm8350c_gpios 3 GPIO_ACTIVE_HIGH>; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + enable-active-high; + pinctrl-0 = <&ntn_1p8_en>; + pinctrl-names = "default"; + regulator-enable-ramp-delay = <10000>; + }; + wcn6750-pmu { compatible = "qcom,wcn6750-pmu"; pinctrl-0 = <&bt_en>; @@ -843,6 +867,78 @@ status = "okay"; }; +&pcie1_port0 { + pcie@0,0 { + compatible = "pci1179,0623"; + reg = <0x10000 0x0 0x0 0x0 0x0>; + #address-cells = <3>; + #size-cells = <2>; + + device_type = "pci"; + ranges; + bus-range = <0x2 0xff>; + + vddc-supply = <&vdd_ntn_0p9>; + vdd18-supply = <&vdd_ntn_1p8>; + vdd09-supply = <&vdd_ntn_0p9>; + vddio1-supply = <&vdd_ntn_1p8>; + vddio2-supply = <&vdd_ntn_1p8>; + vddio18-supply = <&vdd_ntn_1p8>; + + i2c-parent = <&i2c0 0x77>; + + resx-gpios = <&pm8350c_gpios 1 GPIO_ACTIVE_LOW>; + + pinctrl-0 = <&tc9563_resx_n>; + pinctrl-names = "default"; + + pcie@1,0 { + reg = <0x20800 0x0 0x0 0x0 0x0>; + #address-cells = <3>; + #size-cells = <2>; + + device_type = "pci"; + ranges; + bus-range = <0x3 0xff>; + }; + + pcie@2,0 { + reg = <0x21000 0x0 0x0 0x0 0x0>; + #address-cells = <3>; + #size-cells = <2>; + + device_type = "pci"; + ranges; + bus-range = <0x4 0xff>; + }; + + pcie@3,0 { + reg = <0x21800 0x0 0x0 0x0 0x0>; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + ranges; + bus-range = <0x5 0xff>; + + pci@0,0 { + reg = <0x50000 0x0 0x0 0x0 0x0>; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + ranges; + }; + + pci@0,1 { + reg = <0x50100 0x0 0x0 0x0 0x0>; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + ranges; + }; + }; + }; +}; + &pm7325_gpios { kypd_vol_up_n: kypd-vol-up-n-state { pins = "gpio6"; @@ -1462,6 +1558,38 @@ }; }; +&pm8350c_gpios { + ntn_0p9_en: ntn-0p9-en-state { + pins = "gpio2"; + function = "normal"; + + bias-disable; + input-disable; + output-enable; + power-source = <0>; + }; + + ntn_1p8_en: ntn-1p8-en-state { + pins = "gpio3"; + function = "normal"; + + bias-disable; + input-disable; + output-enable; + power-source = <0>; + }; + + tc9563_resx_n: tc9563-resx-state { + pins = "gpio1"; + function = "normal"; + + bias-disable; + input-disable; + output-enable; + power-source = <0>; + }; +}; + &tlmm { gpio-reserved-ranges = <32 2>, /* ADSP */ <48 4>; /* NFC */ diff --git a/arch/arm64/boot/dts/qcom/sc7280.dtsi b/arch/arm64/boot/dts/qcom/sc7280.dtsi index 2dacd98d26cb6..68ed072389372 100644 --- a/arch/arm64/boot/dts/qcom/sc7280.dtsi +++ b/arch/arm64/boot/dts/qcom/sc7280.dtsi @@ -2429,7 +2429,7 @@ status = "disabled"; - pcie@0 { + pcie1_port0: pcie@0 { device_type = "pci"; reg = <0x0 0x0 0x0 0x0 0x0>; bus-range = <0x01 0xff>; From 3b63e41fa8064755b651ab80fb93b26c2cccfab2 Mon Sep 17 00:00:00 2001 From: Shiraz Hashim Date: Sat, 7 Feb 2026 17:55:39 +0530 Subject: [PATCH 2325/2333] WORKAROUND: scsi: ufs: core: Set uic_cmd_timeout to max It is obsrved that qcs9100-ride fails to boot intermittently due to ufs cmd timeouts. The timeout happens as the ufs threaded-irq fails to schedule within the default UIC_CMD_TIMEOUT_DEFAULT (500 msec) due to console logs spewing at the same moment. Increase timeout to max for now to UIC_CMD_TIMEOUT_MAX (5000 msecs) to allow ufs cmd sequences to complete. Signed-off-by: Shiraz Hashim --- drivers/ufs/core/ufshcd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 022810b524e96..2747f378ba5ed 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -117,7 +117,7 @@ static bool is_mcq_supported(struct ufs_hba *hba) module_param(use_mcq_mode, bool, 0644); MODULE_PARM_DESC(use_mcq_mode, "Control MCQ mode for controllers starting from UFSHCI 4.0. 1 - enable MCQ, 0 - disable MCQ. MCQ is enabled by default"); -static unsigned int uic_cmd_timeout = UIC_CMD_TIMEOUT_DEFAULT; +static unsigned int uic_cmd_timeout = UIC_CMD_TIMEOUT_MAX; static int uic_cmd_timeout_set(const char *val, const struct kernel_param *kp) { From 414cec638af7ca3296ef12de97f34f8e51c7992f Mon Sep 17 00:00:00 2001 From: Xin Liu Date: Tue, 28 Oct 2025 19:31:35 -0700 Subject: [PATCH 2326/2333] BACKPORT: arm64: dts: qcom: qcs615: Update 'model' string for qcs615 ride Update the 'model' property in the QCS615-ride device tree to include the public board name "IQ-615 Beta EVK". This ensures consistency with official documentation and release notes. Signed-off-by: Xin Liu Link: https://lore.kernel.org/all/20251029023137.381386-1-xin.liu@oss.qualcomm.com/ --- arch/arm64/boot/dts/qcom/qcs615-ride.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/qcs615-ride.dts b/arch/arm64/boot/dts/qcom/qcs615-ride.dts index 851ff7de4d464..96b23afa390c7 100644 --- a/arch/arm64/boot/dts/qcom/qcs615-ride.dts +++ b/arch/arm64/boot/dts/qcom/qcs615-ride.dts @@ -10,7 +10,7 @@ #include "talos.dtsi" #include "pm8150.dtsi" / { - model = "Qualcomm Technologies, Inc. QCS615 Ride"; + model = "Qualcomm Technologies, Inc. QCS615 Ride (IQ-615 Beta EVK)"; compatible = "qcom,qcs615-ride", "qcom,qcs615", "qcom,sm6150"; chassis-type = "embedded"; From c0e2d7dcdef1b8b175274bda80b9c8c360f069ae Mon Sep 17 00:00:00 2001 From: Mohd Ayaan Anwar Date: Tue, 17 Feb 2026 10:50:00 +0530 Subject: [PATCH 2327/2333] WORKAROUND: arm64: dts: qcom: talos-evk-som: Enable ethernet node Enable the ethernet node, add the phy node and pinctrl for ethernet. Signed-off-by: Mohd Ayaan Anwar --- arch/arm64/boot/dts/qcom/talos-evk-som.dtsi | 95 +++++++++++++++++++++ 1 file changed, 95 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/talos-evk-som.dtsi b/arch/arm64/boot/dts/qcom/talos-evk-som.dtsi index 8a599ed25f76e..590c95b5ad277 100644 --- a/arch/arm64/boot/dts/qcom/talos-evk-som.dtsi +++ b/arch/arm64/boot/dts/qcom/talos-evk-som.dtsi @@ -340,6 +340,59 @@ status = "okay"; }; +ðernet { + pinctrl-0 = <ðernet_defaults>; + pinctrl-names = "default"; + + phy-handle = <&rgmii_phy>; + phy-mode = "rgmii-id"; + + snps,mtl-rx-config = <&mtl_rx_setup>; + snps,mtl-tx-config = <&mtl_tx_setup>; + + status = "okay"; + + mdio: mdio { + compatible = "snps,dwmac-mdio"; + #address-cells = <1>; + #size-cells = <0>; + + rgmii_phy: phy@1 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <0x1>; + + interrupts-extended = <&tlmm 121 IRQ_TYPE_EDGE_FALLING>; + device_type = "ethernet-phy"; + reset-gpios = <&tlmm 105 GPIO_ACTIVE_LOW>; + reset-assert-us = <11000>; + reset-deassert-us = <70000>; + }; + }; + + mtl_rx_setup: rx-queues-config { + snps,rx-queues-to-use = <1>; + snps,rx-sched-sp; + + queue0 { + snps,dcb-algorithm; + snps,map-to-dma-channel = <0x0>; + snps,route-up; + snps,priority = <0x1>; + }; + }; + + mtl_tx_setup: tx-queues-config { + snps,tx-queues-to-use = <1>; + snps,tx-sched-wrr; + + queue0 { + snps,weight = <0x10>; + snps,dcb-algorithm; + snps,priority = <0x0>; + }; + }; +}; + &gpu { status = "okay"; }; @@ -494,6 +547,48 @@ bias-pull-down; }; + ethernet_defaults: ethernet-defaults-state { + mdc-pins { + pins = "gpio113"; + function = "rgmii"; + bias-pull-up; + }; + + mdio-pins { + pins = "gpio114"; + function = "rgmii"; + bias-pull-up; + }; + + rgmii-rx-pins { + pins = "gpio81", "gpio82", "gpio83", "gpio102", "gpio103", "gpio112"; + function = "rgmii"; + bias-disable; + drive-strength = <2>; + }; + + rgmii-tx-pins { + pins = "gpio92", "gpio93", "gpio94", "gpio95", "gpio96", "gpio97"; + function = "rgmii"; + bias-pull-up; + drive-strength = <16>; + }; + + phy-intr-pins { + pins = "gpio121"; + function = "gpio"; + bias-disable; + drive-strength = <8>; + }; + + phy-reset-pins { + pins = "gpio105"; + function = "gpio"; + bias-pull-up; + drive-strength = <16>; + }; + }; + pcie_default_state: pcie-default-state { clkreq-pins { pins = "gpio90"; From d3ec08b6a30abd62174284a6bd98a99c1b3fc729 Mon Sep 17 00:00:00 2001 From: Venkateswara Naralasetty Date: Fri, 6 Mar 2026 13:11:15 +0800 Subject: [PATCH 2328/2333] FROMGIT: wifi: ath11k: Add initialization and deinitialization sequence for CFR module Channel Frequency Response (CFR) module will be initialized only when the following criteria passes: * Enabled CFR support for the hardware through the hardware param 'cfr_support' * WMI service enabled for the CFR support 'WMI_TLV_SERVICE_CFR_CAPTURE_SUPPORT' Also, provide a configuration option CONFIG_ATH11K_CFR to enable CFR feature support during the compilation time. CFR module initialization includes Direct Buffer(DB) ring initialization where hardware uses the DB ring buffers to copy CFR data to host. Number of buffers and buffer size of the ring is based on the DB ring capabilities advertised by the firmware through WMI service ready. Also ring configurations are sent to firmware through ath11k_dbring_wmi_cfg_setup(). Predefine ath11k_cfr_dma_hdr, ath11k_look_up_table, and ath11k_cfr structs and fields for subsequent patches. Tested-on: IPQ8074 hw2.0 PCI IPQ8074 WLAN.HK.2.5.0.1-00991-QCAHKSWPL_SILICONZ-1 Tested-on: WCN6855 hw2.1 PCI WLAN.HSP.1.1-04685-QCAHSPSWPL_V1_V2_SILICONZ_IOE-1 Signed-off-by: Venkateswara Naralasetty Co-developed-by: Yu Zhang (Yuriy) Signed-off-by: Yu Zhang (Yuriy) Reviewed-by: Vasanthakumar Thiagarajan Reviewed-by: Baochen Qiang Signed-off-by: Qian Zhang Link: https://patch.msgid.link/20251230082520.3401007-2-qian.zhang@oss.qualcomm.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath11k/Kconfig | 11 ++ drivers/net/wireless/ath/ath11k/Makefile | 1 + drivers/net/wireless/ath/ath11k/cfr.c | 170 +++++++++++++++++++++++ drivers/net/wireless/ath/ath11k/cfr.h | 85 ++++++++++++ drivers/net/wireless/ath/ath11k/core.c | 40 ++++++ drivers/net/wireless/ath/ath11k/core.h | 6 + drivers/net/wireless/ath/ath11k/dbring.c | 40 ++++-- drivers/net/wireless/ath/ath11k/dbring.h | 6 +- drivers/net/wireless/ath/ath11k/hal.c | 3 +- drivers/net/wireless/ath/ath11k/hw.h | 5 +- drivers/net/wireless/ath/ath11k/wmi.h | 1 + 11 files changed, 353 insertions(+), 15 deletions(-) create mode 100644 drivers/net/wireless/ath/ath11k/cfr.c create mode 100644 drivers/net/wireless/ath/ath11k/cfr.h diff --git a/drivers/net/wireless/ath/ath11k/Kconfig b/drivers/net/wireless/ath/ath11k/Kconfig index 659ef134ef168..47dfd39caa89a 100644 --- a/drivers/net/wireless/ath/ath11k/Kconfig +++ b/drivers/net/wireless/ath/ath11k/Kconfig @@ -58,3 +58,14 @@ config ATH11K_SPECTRAL Enable ath11k spectral scan support Say Y to enable access to the FFT/spectral data via debugfs. + +config ATH11K_CFR + bool "ath11k channel frequency response support" + depends on ATH11K_DEBUGFS + depends on RELAY + help + Enable ath11k channel frequency response dump support. + This option exposes debugfs nodes that will allow the user + to enable, disable, and dump data. + + Say Y to enable CFR data dump collection via debugfs. diff --git a/drivers/net/wireless/ath/ath11k/Makefile b/drivers/net/wireless/ath/ath11k/Makefile index d9092414b362d..b1435fcf3e1bf 100644 --- a/drivers/net/wireless/ath/ath11k/Makefile +++ b/drivers/net/wireless/ath/ath11k/Makefile @@ -28,6 +28,7 @@ ath11k-$(CONFIG_THERMAL) += thermal.o ath11k-$(CONFIG_ATH11K_SPECTRAL) += spectral.o ath11k-$(CONFIG_PM) += wow.o ath11k-$(CONFIG_DEV_COREDUMP) += coredump.o +ath11k-$(CONFIG_ATH11K_CFR) += cfr.o obj-$(CONFIG_ATH11K_AHB) += ath11k_ahb.o ath11k_ahb-y += ahb.o diff --git a/drivers/net/wireless/ath/ath11k/cfr.c b/drivers/net/wireless/ath/ath11k/cfr.c new file mode 100644 index 0000000000000..78e356672ebad --- /dev/null +++ b/drivers/net/wireless/ath/ath11k/cfr.c @@ -0,0 +1,170 @@ +// SPDX-License-Identifier: BSD-3-Clause-Clear +/* + * Copyright (c) 2020-2021 The Linux Foundation. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#include +#include "core.h" +#include "debug.h" + +static int ath11k_cfr_process_data(struct ath11k *ar, + struct ath11k_dbring_data *param) +{ + return 0; +} + +void ath11k_cfr_lut_update_paddr(struct ath11k *ar, dma_addr_t paddr, + u32 buf_id) +{ + struct ath11k_cfr *cfr = &ar->cfr; + + if (cfr->lut) + cfr->lut[buf_id].dbr_address = paddr; +} + +static void ath11k_cfr_ring_free(struct ath11k *ar) +{ + struct ath11k_cfr *cfr = &ar->cfr; + + ath11k_dbring_buf_cleanup(ar, &cfr->rx_ring); + ath11k_dbring_srng_cleanup(ar, &cfr->rx_ring); +} + +static int ath11k_cfr_ring_alloc(struct ath11k *ar, + struct ath11k_dbring_cap *db_cap) +{ + struct ath11k_cfr *cfr = &ar->cfr; + int ret; + + ret = ath11k_dbring_srng_setup(ar, &cfr->rx_ring, + ATH11K_CFR_NUM_RING_ENTRIES, + db_cap->min_elem); + if (ret) { + ath11k_warn(ar->ab, "failed to setup db ring: %d\n", ret); + return ret; + } + + ath11k_dbring_set_cfg(ar, &cfr->rx_ring, + ATH11K_CFR_NUM_RESP_PER_EVENT, + ATH11K_CFR_EVENT_TIMEOUT_MS, + ath11k_cfr_process_data); + + ret = ath11k_dbring_buf_setup(ar, &cfr->rx_ring, db_cap); + if (ret) { + ath11k_warn(ar->ab, "failed to setup db ring buffer: %d\n", ret); + goto srng_cleanup; + } + + ret = ath11k_dbring_wmi_cfg_setup(ar, &cfr->rx_ring, WMI_DIRECT_BUF_CFR); + if (ret) { + ath11k_warn(ar->ab, "failed to setup db ring cfg: %d\n", ret); + goto buffer_cleanup; + } + + return 0; + +buffer_cleanup: + ath11k_dbring_buf_cleanup(ar, &cfr->rx_ring); +srng_cleanup: + ath11k_dbring_srng_cleanup(ar, &cfr->rx_ring); + return ret; +} + +void ath11k_cfr_deinit(struct ath11k_base *ab) +{ + struct ath11k_cfr *cfr; + struct ath11k *ar; + int i; + + if (!test_bit(WMI_TLV_SERVICE_CFR_CAPTURE_SUPPORT, ab->wmi_ab.svc_map) || + !ab->hw_params.cfr_support) + return; + + for (i = 0; i < ab->num_radios; i++) { + ar = ab->pdevs[i].ar; + cfr = &ar->cfr; + + if (!cfr->enabled) + continue; + + ath11k_cfr_ring_free(ar); + + spin_lock_bh(&cfr->lut_lock); + kfree(cfr->lut); + cfr->lut = NULL; + cfr->enabled = false; + spin_unlock_bh(&cfr->lut_lock); + } +} + +int ath11k_cfr_init(struct ath11k_base *ab) +{ + struct ath11k_dbring_cap db_cap; + struct ath11k_cfr *cfr; + u32 num_lut_entries; + struct ath11k *ar; + int i, ret; + + if (!test_bit(WMI_TLV_SERVICE_CFR_CAPTURE_SUPPORT, ab->wmi_ab.svc_map) || + !ab->hw_params.cfr_support) + return 0; + + for (i = 0; i < ab->num_radios; i++) { + ar = ab->pdevs[i].ar; + cfr = &ar->cfr; + + ret = ath11k_dbring_get_cap(ar->ab, ar->pdev_idx, + WMI_DIRECT_BUF_CFR, &db_cap); + if (ret) + continue; + + idr_init(&cfr->rx_ring.bufs_idr); + spin_lock_init(&cfr->rx_ring.idr_lock); + spin_lock_init(&cfr->lock); + spin_lock_init(&cfr->lut_lock); + + num_lut_entries = min_t(u32, CFR_MAX_LUT_ENTRIES, db_cap.min_elem); + cfr->lut = kcalloc(num_lut_entries, sizeof(*cfr->lut), + GFP_KERNEL); + if (!cfr->lut) { + ret = -ENOMEM; + goto err; + } + + ret = ath11k_cfr_ring_alloc(ar, &db_cap); + if (ret) { + ath11k_warn(ab, "failed to init cfr ring for pdev %d: %d\n", + i, ret); + spin_lock_bh(&cfr->lut_lock); + kfree(cfr->lut); + cfr->lut = NULL; + cfr->enabled = false; + spin_unlock_bh(&cfr->lut_lock); + goto err; + } + + cfr->lut_num = num_lut_entries; + cfr->enabled = true; + } + + return 0; + +err: + for (i = i - 1; i >= 0; i--) { + ar = ab->pdevs[i].ar; + cfr = &ar->cfr; + + if (!cfr->enabled) + continue; + + ath11k_cfr_ring_free(ar); + + spin_lock_bh(&cfr->lut_lock); + kfree(cfr->lut); + cfr->lut = NULL; + cfr->enabled = false; + spin_unlock_bh(&cfr->lut_lock); + } + return ret; +} diff --git a/drivers/net/wireless/ath/ath11k/cfr.h b/drivers/net/wireless/ath/ath11k/cfr.h new file mode 100644 index 0000000000000..3534176c3e013 --- /dev/null +++ b/drivers/net/wireless/ath/ath11k/cfr.h @@ -0,0 +1,85 @@ +/* SPDX-License-Identifier: BSD-3-Clause-Clear */ +/* + * Copyright (c) 2020-2021 The Linux Foundation. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#ifndef ATH11K_CFR_H +#define ATH11K_CFR_H + +#include "dbring.h" +#include "wmi.h" + +#define ATH11K_CFR_NUM_RESP_PER_EVENT 1 +#define ATH11K_CFR_EVENT_TIMEOUT_MS 1 +#define ATH11K_CFR_NUM_RING_ENTRIES 1 + +#define CFR_MAX_LUT_ENTRIES 136 + +#define HOST_MAX_CHAINS 8 + +struct ath11k_cfr_dma_hdr { + u16 info0; + u16 info1; + u16 sw_peer_id; + u16 phy_ppdu_id; +}; + +struct ath11k_look_up_table { + bool dbr_recv; + bool tx_recv; + u8 *data; + u32 data_len; + u16 dbr_ppdu_id; + u16 tx_ppdu_id; + dma_addr_t dbr_address; + struct ath11k_cfr_dma_hdr hdr; + u64 txrx_tstamp; + u64 dbr_tstamp; + u32 header_length; + u32 payload_length; + struct ath11k_dbring_element *buff; +}; + +struct ath11k_cfr { + struct ath11k_dbring rx_ring; + /* Protects cfr data */ + spinlock_t lock; + /* Protect for lut entries */ + spinlock_t lut_lock; + struct ath11k_look_up_table *lut; + u32 lut_num; + u64 tx_evt_cnt; + u64 dbr_evt_cnt; + u64 release_cnt; + u64 tx_peer_status_cfr_fail; + u64 tx_evt_status_cfr_fail; + u64 tx_dbr_lookup_fail; + u64 last_success_tstamp; + u64 flush_dbr_cnt; + u64 clear_txrx_event; + u64 cfr_dma_aborts; + bool enabled; +}; + +#ifdef CONFIG_ATH11K_CFR +int ath11k_cfr_init(struct ath11k_base *ab); +void ath11k_cfr_deinit(struct ath11k_base *ab); +void ath11k_cfr_lut_update_paddr(struct ath11k *ar, dma_addr_t paddr, + u32 buf_id); +#else +static inline int ath11k_cfr_init(struct ath11k_base *ab) +{ + return 0; +} + +static inline void ath11k_cfr_deinit(struct ath11k_base *ab) +{ +} + +static inline void ath11k_cfr_lut_update_paddr(struct ath11k *ar, + dma_addr_t paddr, u32 buf_id) +{ +} +#endif /* CONFIG_ATH11K_CFR */ +#endif /* ATH11K_CFR_H */ diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c index a4a3a65c77526..9996219295656 100644 --- a/drivers/net/wireless/ath/ath11k/core.c +++ b/drivers/net/wireless/ath/ath11k/core.c @@ -125,6 +125,9 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .smp2p_wow_exit = false, .support_dual_stations = false, .pdev_suspend = false, + .cfr_support = true, + .cfr_num_stream_bufs = 255, + .cfr_stream_buf_size = 8200, }, { .hw_rev = ATH11K_HW_IPQ6018_HW10, @@ -210,6 +213,9 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .support_fw_mac_sequence = false, .support_dual_stations = false, .pdev_suspend = false, + .cfr_support = false, + .cfr_num_stream_bufs = 0, + .cfr_stream_buf_size = 0, }, { .name = "qca6390 hw2.0", @@ -300,6 +306,9 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .support_fw_mac_sequence = true, .support_dual_stations = true, .pdev_suspend = false, + .cfr_support = false, + .cfr_num_stream_bufs = 0, + .cfr_stream_buf_size = 0, }, { .name = "qcn9074 hw1.0", @@ -384,6 +393,9 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .support_fw_mac_sequence = false, .support_dual_stations = false, .pdev_suspend = false, + .cfr_support = false, + .cfr_num_stream_bufs = 0, + .cfr_stream_buf_size = 0, }, { .name = "wcn6855 hw2.0", @@ -474,6 +486,9 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .support_fw_mac_sequence = true, .support_dual_stations = true, .pdev_suspend = false, + .cfr_support = false, + .cfr_num_stream_bufs = 0, + .cfr_stream_buf_size = 0, }, { .name = "wcn6855 hw2.1", @@ -562,6 +577,9 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .support_fw_mac_sequence = true, .support_dual_stations = true, .pdev_suspend = false, + .cfr_support = true, + .cfr_num_stream_bufs = 255, + .cfr_stream_buf_size = 8200, }, { .name = "wcn6750 hw1.0", @@ -645,6 +663,9 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .support_fw_mac_sequence = true, .support_dual_stations = false, .pdev_suspend = true, + .cfr_support = false, + .cfr_num_stream_bufs = 0, + .cfr_stream_buf_size = 0, }, { .hw_rev = ATH11K_HW_IPQ5018_HW10, @@ -728,6 +749,9 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .support_fw_mac_sequence = false, .support_dual_stations = false, .pdev_suspend = false, + .cfr_support = false, + .cfr_num_stream_bufs = 0, + .cfr_stream_buf_size = 0, }, { .name = "qca2066 hw2.1", @@ -817,6 +841,9 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .smp2p_wow_exit = false, .support_fw_mac_sequence = true, .support_dual_stations = true, + .cfr_support = false, + .cfr_num_stream_bufs = 0, + .cfr_stream_buf_size = 0, }, { .name = "qca6698aq hw2.1", @@ -905,6 +932,9 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .support_fw_mac_sequence = true, .support_dual_stations = true, .pdev_suspend = false, + .cfr_support = true, + .cfr_num_stream_bufs = 255, + .cfr_stream_buf_size = 8200, }, }; @@ -2022,8 +2052,16 @@ static int ath11k_core_pdev_create(struct ath11k_base *ab) goto err_thermal_unregister; } + ret = ath11k_cfr_init(ab); + if (ret) { + ath11k_err(ab, "failed to init cfr %d\n", ret); + goto err_spectral_unregister; + } + return 0; +err_spectral_unregister: + ath11k_spectral_deinit(ab); err_thermal_unregister: ath11k_thermal_unregister(ab); err_mac_unregister: @@ -2073,6 +2111,7 @@ static void ath11k_core_pdev_suspend_target(struct ath11k_base *ab) static void ath11k_core_pdev_destroy(struct ath11k_base *ab) { + ath11k_cfr_deinit(ab); ath11k_spectral_deinit(ab); ath11k_thermal_unregister(ab); ath11k_mac_unregister(ab); @@ -2285,6 +2324,7 @@ static int ath11k_core_reconfigure_on_crash(struct ath11k_base *ab) mutex_lock(&ab->core_lock); ath11k_thermal_unregister(ab); ath11k_dp_pdev_free(ab); + ath11k_cfr_deinit(ab); ath11k_spectral_deinit(ab); ath11k_ce_cleanup_pipes(ab); ath11k_wmi_detach(ab); diff --git a/drivers/net/wireless/ath/ath11k/core.h b/drivers/net/wireless/ath/ath11k/core.h index f8fcd897ebd26..dd646f2c621b4 100644 --- a/drivers/net/wireless/ath/ath11k/core.h +++ b/drivers/net/wireless/ath/ath11k/core.h @@ -35,6 +35,7 @@ #include "wow.h" #include "fw.h" #include "coredump.h" +#include "cfr.h" #define SM(_v, _f) (((_v) << _f##_LSB) & _f##_MASK) @@ -795,6 +796,11 @@ struct ath11k { bool ps_state_enable; bool ps_timekeeper_enable; s8 max_allowed_tx_power; + +#ifdef CONFIG_ATH11K_CFR + struct ath11k_cfr cfr; +#endif + bool cfr_enabled; }; struct ath11k_band_cap { diff --git a/drivers/net/wireless/ath/ath11k/dbring.c b/drivers/net/wireless/ath/ath11k/dbring.c index 520d8b8662a28..ed2b781a6bab6 100644 --- a/drivers/net/wireless/ath/ath11k/dbring.c +++ b/drivers/net/wireless/ath/ath11k/dbring.c @@ -1,7 +1,6 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ @@ -37,10 +36,10 @@ static void ath11k_dbring_fill_magic_value(struct ath11k *ar, memset32(buffer, ATH11K_DB_MAGIC_VALUE, size); } -static int ath11k_dbring_bufs_replenish(struct ath11k *ar, - struct ath11k_dbring *ring, - struct ath11k_dbring_element *buff, - enum wmi_direct_buffer_module id) +int ath11k_dbring_bufs_replenish(struct ath11k *ar, + struct ath11k_dbring *ring, + struct ath11k_dbring_element *buff, + enum wmi_direct_buffer_module id) { struct ath11k_base *ab = ar->ab; struct hal_srng *srng; @@ -80,6 +79,9 @@ static int ath11k_dbring_bufs_replenish(struct ath11k *ar, goto err_idr_remove; } + if (id == WMI_DIRECT_BUF_CFR) + ath11k_cfr_lut_update_paddr(ar, paddr, buf_id); + buff->paddr = paddr; cookie = FIELD_PREP(DP_RXDMA_BUF_COOKIE_PDEV_ID, ar->pdev_idx) | @@ -155,12 +157,11 @@ int ath11k_dbring_wmi_cfg_setup(struct ath11k *ar, enum wmi_direct_buffer_module id) { struct ath11k_wmi_pdev_dma_ring_cfg_req_cmd param = {}; - int ret; + int ret, i; if (id >= WMI_DIRECT_BUF_MAX) return -EINVAL; - param.pdev_id = DP_SW2HW_MACID(ring->pdev_id); param.module_id = id; param.base_paddr_lo = lower_32_bits(ring->refill_srng.paddr); param.base_paddr_hi = upper_32_bits(ring->refill_srng.paddr); @@ -173,10 +174,23 @@ int ath11k_dbring_wmi_cfg_setup(struct ath11k *ar, param.num_resp_per_event = ring->num_resp_per_event; param.event_timeout_ms = ring->event_timeout_ms; - ret = ath11k_wmi_pdev_dma_ring_cfg(ar, ¶m); - if (ret) { - ath11k_warn(ar->ab, "failed to setup db ring cfg\n"); - return ret; + /* For single pdev, 2GHz and 5GHz use one DBR. */ + if (ar->ab->hw_params.single_pdev_only) { + for (i = 0; i < ar->ab->target_pdev_count; i++) { + param.pdev_id = ar->ab->target_pdev_ids[i].pdev_id; + ret = ath11k_wmi_pdev_dma_ring_cfg(ar, ¶m); + if (ret) { + ath11k_warn(ar->ab, "failed to setup db ring cfg\n"); + return ret; + } + } + } else { + param.pdev_id = DP_SW2HW_MACID(ring->pdev_id); + ret = ath11k_wmi_pdev_dma_ring_cfg(ar, ¶m); + if (ret) { + ath11k_warn(ar->ab, "failed to setup db ring cfg\n"); + return ret; + } } return 0; @@ -285,6 +299,10 @@ int ath11k_dbring_buffer_release_event(struct ath11k_base *ab, pdev_idx = ev->fixed.pdev_id; module_id = ev->fixed.module_id; + if (ab->hw_params.single_pdev_only && + pdev_idx < ab->target_pdev_count) + pdev_idx = 0; + if (pdev_idx >= ab->num_radios) { ath11k_warn(ab, "Invalid pdev id %d\n", pdev_idx); return -EINVAL; diff --git a/drivers/net/wireless/ath/ath11k/dbring.h b/drivers/net/wireless/ath/ath11k/dbring.h index 2f93b78a50df0..0a380120f7a0e 100644 --- a/drivers/net/wireless/ath/ath11k/dbring.h +++ b/drivers/net/wireless/ath/ath11k/dbring.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved. - * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #ifndef ATH11K_DBRING_H @@ -61,6 +61,10 @@ int ath11k_dbring_set_cfg(struct ath11k *ar, u32 event_timeout_ms, int (*handler)(struct ath11k *, struct ath11k_dbring_data *)); +int ath11k_dbring_bufs_replenish(struct ath11k *ar, + struct ath11k_dbring *ring, + struct ath11k_dbring_element *buff, + enum wmi_direct_buffer_module id); int ath11k_dbring_wmi_cfg_setup(struct ath11k *ar, struct ath11k_dbring *ring, enum wmi_direct_buffer_module id); diff --git a/drivers/net/wireless/ath/ath11k/hal.c b/drivers/net/wireless/ath/ath11k/hal.c index 0c797b8d0a276..e821e5a62c1c0 100644 --- a/drivers/net/wireless/ath/ath11k/hal.c +++ b/drivers/net/wireless/ath/ath11k/hal.c @@ -1,7 +1,6 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include @@ -184,7 +183,7 @@ static const struct hal_srng_config hw_srng_config_template[] = { }, { /* RXDMA DIR BUF */ .start_ring_id = HAL_SRNG_RING_ID_RXDMA_DIR_BUF, - .max_rings = 1, + .max_rings = 2, .entry_size = 8 >> 2, /* TODO: Define the struct */ .lmac_ring = true, .ring_dir = HAL_SRNG_DIR_SRC, diff --git a/drivers/net/wireless/ath/ath11k/hw.h b/drivers/net/wireless/ath/ath11k/hw.h index 52d9f4c13b136..e13ca02a9d057 100644 --- a/drivers/net/wireless/ath/ath11k/hw.h +++ b/drivers/net/wireless/ath/ath11k/hw.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #ifndef ATH11K_HW_H @@ -228,6 +228,9 @@ struct ath11k_hw_params { bool support_fw_mac_sequence; bool support_dual_stations; bool pdev_suspend; + bool cfr_support; + u32 cfr_num_stream_bufs; + u32 cfr_stream_buf_size; }; struct ath11k_hw_ops { diff --git a/drivers/net/wireless/ath/ath11k/wmi.h b/drivers/net/wireless/ath/ath11k/wmi.h index 6e9354297e71d..4c2c7d8432588 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.h +++ b/drivers/net/wireless/ath/ath11k/wmi.h @@ -981,6 +981,7 @@ enum wmi_tlv_pdev_param { WMI_PDEV_PARAM_RADIO_CHAN_STATS_ENABLE, WMI_PDEV_PARAM_RADIO_DIAGNOSIS_ENABLE, WMI_PDEV_PARAM_MESH_MCAST_ENABLE, + WMI_PDEV_PARAM_PER_PEER_CFR_ENABLE = 0xa8, WMI_PDEV_PARAM_SET_CMD_OBSS_PD_THRESHOLD = 0xbc, WMI_PDEV_PARAM_SET_CMD_OBSS_PD_PER_AC = 0xbe, WMI_PDEV_PARAM_ENABLE_SR_PROHIBIT = 0xc6, From 0f2c6efb480318ef45c9e96e033ff68cf08ec9f3 Mon Sep 17 00:00:00 2001 From: Venkateswara Naralasetty Date: Wed, 5 Nov 2025 09:22:22 -0800 Subject: [PATCH 2329/2333] FROMGIT: wifi: ath11k: Register debugfs for CFR configuration Provide debugfs interfaces support to config CFR from the user space. To enable/disable cfr feature use command, echo > /sys/kernel/debug/ieee80211/phyX/ath11k/enable_cfr where, val: 0 to disable CFR and 1 to enable CFR. To enable CFR capture for associated peers, echo " " > /sys/kernel/debug/ieee80211/phyX/netdev\:wlanx/stations//cfr_capture val: 0 - stop CFR capture 1 - start CFR capture bw: CFR capture bandwidth 0 - 20MHZ 1 - 40MHZ 2 - 80MHZ Periodicity: Periodicity at which hardware is expected to collect CFR dump. 0 - single shot capture. non zero - for Periodic captures (value must be multiple of 10 ms) method: Method used by hardware to collect the CFR dump. 0 - from the ACKs of QOS NULL packets. Also, send the required WMI commands to the firmware based on the CFR configurations. Tested-on: IPQ8074 hw2.0 PCI IPQ8074 WLAN.HK.2.5.0.1-00991-QCAHKSWPL_SILICONZ-1 Tested-on: WCN6855 hw2.1 PCI WLAN.HSP.1.1-04685-QCAHSPSWPL_V1_V2_SILICONZ_IOE-1 Signed-off-by: Venkateswara Naralasetty Co-developed-by: Yu Zhang (Yuriy) Signed-off-by: Yu Zhang (Yuriy) Reviewed-by: Vasanthakumar Thiagarajan Reviewed-by: Baochen Qiang Signed-off-by: Qian Zhang Link: https://patch.msgid.link/20251230082520.3401007-3-qian.zhang@oss.qualcomm.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath11k/cfr.c | 191 ++++++++++++++++++ drivers/net/wireless/ath/ath11k/cfr.h | 41 ++++ drivers/net/wireless/ath/ath11k/core.h | 11 + drivers/net/wireless/ath/ath11k/debugfs_sta.c | 142 ++++++++++++- drivers/net/wireless/ath/ath11k/mac.c | 2 + drivers/net/wireless/ath/ath11k/wmi.c | 41 ++++ drivers/net/wireless/ath/ath11k/wmi.h | 50 ++++- 7 files changed, 475 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/cfr.c b/drivers/net/wireless/ath/ath11k/cfr.c index 78e356672ebad..bf0b880e87466 100644 --- a/drivers/net/wireless/ath/ath11k/cfr.c +++ b/drivers/net/wireless/ath/ath11k/cfr.c @@ -14,6 +14,193 @@ static int ath11k_cfr_process_data(struct ath11k *ar, return 0; } +void ath11k_cfr_decrement_peer_count(struct ath11k *ar, + struct ath11k_sta *arsta) +{ + struct ath11k_cfr *cfr = &ar->cfr; + + spin_lock_bh(&cfr->lock); + + if (arsta->cfr_capture.cfr_enable) + cfr->cfr_enabled_peer_cnt--; + + spin_unlock_bh(&cfr->lock); +} + +static enum ath11k_wmi_cfr_capture_bw +ath11k_cfr_bw_to_fw_cfr_bw(enum ath11k_cfr_capture_bw bw) +{ + switch (bw) { + case ATH11K_CFR_CAPTURE_BW_20: + return WMI_PEER_CFR_CAPTURE_BW_20; + case ATH11K_CFR_CAPTURE_BW_40: + return WMI_PEER_CFR_CAPTURE_BW_40; + case ATH11K_CFR_CAPTURE_BW_80: + return WMI_PEER_CFR_CAPTURE_BW_80; + default: + return WMI_PEER_CFR_CAPTURE_BW_MAX; + } +} + +static enum ath11k_wmi_cfr_capture_method +ath11k_cfr_method_to_fw_cfr_method(enum ath11k_cfr_capture_method method) +{ + switch (method) { + case ATH11K_CFR_CAPTURE_METHOD_NULL_FRAME: + return WMI_CFR_CAPTURE_METHOD_NULL_FRAME; + case ATH11K_CFR_CAPTURE_METHOD_NULL_FRAME_WITH_PHASE: + return WMI_CFR_CAPTURE_METHOD_NULL_FRAME_WITH_PHASE; + case ATH11K_CFR_CAPTURE_METHOD_PROBE_RESP: + return WMI_CFR_CAPTURE_METHOD_PROBE_RESP; + default: + return WMI_CFR_CAPTURE_METHOD_MAX; + } +} + +int ath11k_cfr_send_peer_cfr_capture_cmd(struct ath11k *ar, + struct ath11k_sta *arsta, + struct ath11k_per_peer_cfr_capture *params, + const u8 *peer_mac) +{ + struct ath11k_cfr *cfr = &ar->cfr; + struct wmi_peer_cfr_capture_conf_arg arg; + enum ath11k_wmi_cfr_capture_bw bw; + enum ath11k_wmi_cfr_capture_method method; + int ret = 0; + + if (cfr->cfr_enabled_peer_cnt >= ATH11K_MAX_CFR_ENABLED_CLIENTS && + !arsta->cfr_capture.cfr_enable) { + ath11k_err(ar->ab, "CFR enable peer threshold reached %u\n", + cfr->cfr_enabled_peer_cnt); + return -ENOSPC; + } + + if (params->cfr_enable == arsta->cfr_capture.cfr_enable && + params->cfr_period == arsta->cfr_capture.cfr_period && + params->cfr_method == arsta->cfr_capture.cfr_method && + params->cfr_bw == arsta->cfr_capture.cfr_bw) + return ret; + + if (!params->cfr_enable && !arsta->cfr_capture.cfr_enable) + return ret; + + bw = ath11k_cfr_bw_to_fw_cfr_bw(params->cfr_bw); + if (bw >= WMI_PEER_CFR_CAPTURE_BW_MAX) { + ath11k_warn(ar->ab, "FW doesn't support configured bw %d\n", + params->cfr_bw); + return -EINVAL; + } + + method = ath11k_cfr_method_to_fw_cfr_method(params->cfr_method); + if (method >= WMI_CFR_CAPTURE_METHOD_MAX) { + ath11k_warn(ar->ab, "FW doesn't support configured method %d\n", + params->cfr_method); + return -EINVAL; + } + + arg.request = params->cfr_enable; + arg.periodicity = params->cfr_period; + arg.bw = bw; + arg.method = method; + + ret = ath11k_wmi_peer_set_cfr_capture_conf(ar, arsta->arvif->vdev_id, + peer_mac, &arg); + if (ret) { + ath11k_warn(ar->ab, + "failed to send cfr capture info: vdev_id %u peer %pM: %d\n", + arsta->arvif->vdev_id, peer_mac, ret); + return ret; + } + + spin_lock_bh(&cfr->lock); + + if (params->cfr_enable && + params->cfr_enable != arsta->cfr_capture.cfr_enable) + cfr->cfr_enabled_peer_cnt++; + else if (!params->cfr_enable) + cfr->cfr_enabled_peer_cnt--; + + spin_unlock_bh(&cfr->lock); + + arsta->cfr_capture.cfr_enable = params->cfr_enable; + arsta->cfr_capture.cfr_period = params->cfr_period; + arsta->cfr_capture.cfr_method = params->cfr_method; + arsta->cfr_capture.cfr_bw = params->cfr_bw; + + return ret; +} + +static ssize_t ath11k_read_file_enable_cfr(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath11k *ar = file->private_data; + char buf[32] = {}; + size_t len; + + mutex_lock(&ar->conf_mutex); + len = scnprintf(buf, sizeof(buf), "%d\n", ar->cfr_enabled); + mutex_unlock(&ar->conf_mutex); + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static ssize_t ath11k_write_file_enable_cfr(struct file *file, + const char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct ath11k *ar = file->private_data; + u32 enable_cfr; + int ret; + + if (kstrtouint_from_user(ubuf, count, 0, &enable_cfr)) + return -EINVAL; + + guard(mutex)(&ar->conf_mutex); + + if (ar->state != ATH11K_STATE_ON) + return -ENETDOWN; + + if (enable_cfr > 1) + return -EINVAL; + + if (ar->cfr_enabled == enable_cfr) + return count; + + ret = ath11k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_PER_PEER_CFR_ENABLE, + enable_cfr, ar->pdev->pdev_id); + if (ret) { + ath11k_warn(ar->ab, + "Failed to enable/disable per peer cfr %d\n", ret); + return ret; + } + + ar->cfr_enabled = enable_cfr; + + return count; +} + +static const struct file_operations fops_enable_cfr = { + .read = ath11k_read_file_enable_cfr, + .write = ath11k_write_file_enable_cfr, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +static void ath11k_cfr_debug_unregister(struct ath11k *ar) +{ + debugfs_remove(ar->cfr.enable_cfr); + ar->cfr.enable_cfr = NULL; +} + +static void ath11k_cfr_debug_register(struct ath11k *ar) +{ + ar->cfr.enable_cfr = debugfs_create_file("enable_cfr", 0600, + ar->debug.debugfs_pdev, ar, + &fops_enable_cfr); +} + void ath11k_cfr_lut_update_paddr(struct ath11k *ar, dma_addr_t paddr, u32 buf_id) { @@ -88,6 +275,7 @@ void ath11k_cfr_deinit(struct ath11k_base *ab) if (!cfr->enabled) continue; + ath11k_cfr_debug_unregister(ar); ath11k_cfr_ring_free(ar); spin_lock_bh(&cfr->lut_lock); @@ -146,6 +334,8 @@ int ath11k_cfr_init(struct ath11k_base *ab) cfr->lut_num = num_lut_entries; cfr->enabled = true; + + ath11k_cfr_debug_register(ar); } return 0; @@ -158,6 +348,7 @@ int ath11k_cfr_init(struct ath11k_base *ab) if (!cfr->enabled) continue; + ath11k_cfr_debug_unregister(ar); ath11k_cfr_ring_free(ar); spin_lock_bh(&cfr->lut_lock); diff --git a/drivers/net/wireless/ath/ath11k/cfr.h b/drivers/net/wireless/ath/ath11k/cfr.h index 3534176c3e013..7d161f7f7be84 100644 --- a/drivers/net/wireless/ath/ath11k/cfr.h +++ b/drivers/net/wireless/ath/ath11k/cfr.h @@ -14,10 +14,14 @@ #define ATH11K_CFR_EVENT_TIMEOUT_MS 1 #define ATH11K_CFR_NUM_RING_ENTRIES 1 +#define ATH11K_MAX_CFR_ENABLED_CLIENTS 10 #define CFR_MAX_LUT_ENTRIES 136 #define HOST_MAX_CHAINS 8 +struct ath11k_sta; +struct ath11k_per_peer_cfr_capture; + struct ath11k_cfr_dma_hdr { u16 info0; u16 info1; @@ -48,6 +52,8 @@ struct ath11k_cfr { /* Protect for lut entries */ spinlock_t lut_lock; struct ath11k_look_up_table *lut; + struct dentry *enable_cfr; + u8 cfr_enabled_peer_cnt; u32 lut_num; u64 tx_evt_cnt; u64 dbr_evt_cnt; @@ -62,11 +68,32 @@ struct ath11k_cfr { bool enabled; }; +enum ath11k_cfr_capture_method { + ATH11K_CFR_CAPTURE_METHOD_NULL_FRAME, + ATH11K_CFR_CAPTURE_METHOD_NULL_FRAME_WITH_PHASE, + ATH11K_CFR_CAPTURE_METHOD_PROBE_RESP, + ATH11K_CFR_CAPTURE_METHOD_MAX, +}; + +enum ath11k_cfr_capture_bw { + ATH11K_CFR_CAPTURE_BW_20, + ATH11K_CFR_CAPTURE_BW_40, + ATH11K_CFR_CAPTURE_BW_80, + ATH11K_CFR_CAPTURE_BW_MAX, +}; + #ifdef CONFIG_ATH11K_CFR int ath11k_cfr_init(struct ath11k_base *ab); void ath11k_cfr_deinit(struct ath11k_base *ab); void ath11k_cfr_lut_update_paddr(struct ath11k *ar, dma_addr_t paddr, u32 buf_id); +void ath11k_cfr_decrement_peer_count(struct ath11k *ar, + struct ath11k_sta *arsta); +int ath11k_cfr_send_peer_cfr_capture_cmd(struct ath11k *ar, + struct ath11k_sta *arsta, + struct ath11k_per_peer_cfr_capture *params, + const u8 *peer_mac); + #else static inline int ath11k_cfr_init(struct ath11k_base *ab) { @@ -81,5 +108,19 @@ static inline void ath11k_cfr_lut_update_paddr(struct ath11k *ar, dma_addr_t paddr, u32 buf_id) { } + +static inline void ath11k_cfr_decrement_peer_count(struct ath11k *ar, + struct ath11k_sta *arsta) +{ +} + +static inline int +ath11k_cfr_send_peer_cfr_capture_cmd(struct ath11k *ar, + struct ath11k_sta *arsta, + struct ath11k_per_peer_cfr_capture *params, + const u8 *peer_mac) +{ + return 0; +} #endif /* CONFIG_ATH11K_CFR */ #endif /* ATH11K_CFR_H */ diff --git a/drivers/net/wireless/ath/ath11k/core.h b/drivers/net/wireless/ath/ath11k/core.h index dd646f2c621b4..bb8356c4e5106 100644 --- a/drivers/net/wireless/ath/ath11k/core.h +++ b/drivers/net/wireless/ath/ath11k/core.h @@ -532,6 +532,13 @@ struct ath11k_per_ppdu_tx_stats { DECLARE_EWMA(avg_rssi, 10, 8) +struct ath11k_per_peer_cfr_capture { + enum ath11k_cfr_capture_method cfr_method; + enum ath11k_cfr_capture_bw cfr_bw; + u32 cfr_enable; + u32 cfr_period; +}; + struct ath11k_sta { struct ath11k_vif *arvif; @@ -572,6 +579,10 @@ struct ath11k_sta { bool peer_current_ps_valid; u32 bw_prev; + +#ifdef CONFIG_ATH11K_CFR + struct ath11k_per_peer_cfr_capture cfr_capture; +#endif }; #define ATH11K_MIN_5G_FREQ 4150 diff --git a/drivers/net/wireless/ath/ath11k/debugfs_sta.c b/drivers/net/wireless/ath/ath11k/debugfs_sta.c index d89d0f28d890b..621a8a8df4b86 100644 --- a/drivers/net/wireless/ath/ath11k/debugfs_sta.c +++ b/drivers/net/wireless/ath/ath11k/debugfs_sta.c @@ -1,7 +1,6 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ @@ -240,6 +239,140 @@ static const struct file_operations fops_tx_stats = { .llseek = default_llseek, }; +#ifdef CONFIG_ATH11K_CFR +static ssize_t ath11k_dbg_sta_write_cfr_capture(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ieee80211_sta *sta = file->private_data; + struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta); + struct ath11k *ar = arsta->arvif->ar; + struct ath11k_cfr *cfr = &ar->cfr; + struct wmi_peer_cfr_capture_conf_arg arg; + u32 cfr_capture_enable = 0, cfr_capture_bw = 0; + u32 cfr_capture_method = 0, cfr_capture_period = 0; + char buf[64] = {}; + int ret; + + simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count); + + guard(mutex)(&ar->conf_mutex); + + if (ar->state != ATH11K_STATE_ON) + return -ENETDOWN; + + if (!ar->cfr_enabled) + return -EINVAL; + + ret = sscanf(buf, "%u %u %u %u", &cfr_capture_enable, &cfr_capture_bw, + &cfr_capture_period, &cfr_capture_method); + + if (ret < 1 || (cfr_capture_enable && ret != 4)) + return -EINVAL; + + if (cfr_capture_enable == arsta->cfr_capture.cfr_enable && + (cfr_capture_period && + cfr_capture_period == arsta->cfr_capture.cfr_period) && + cfr_capture_bw == arsta->cfr_capture.cfr_bw && + cfr_capture_method == arsta->cfr_capture.cfr_method) + return count; + + if (!cfr_capture_enable && + cfr_capture_enable == arsta->cfr_capture.cfr_enable) + return count; + + if (cfr_capture_enable > WMI_PEER_CFR_CAPTURE_ENABLE || + cfr_capture_bw > WMI_PEER_CFR_CAPTURE_BW_80 || + cfr_capture_method > ATH11K_CFR_CAPTURE_METHOD_NULL_FRAME_WITH_PHASE || + cfr_capture_period > WMI_PEER_CFR_PERIODICITY_MAX) + return -EINVAL; + + /* Target expects cfr period in multiple of 10 */ + if (cfr_capture_period % 10) { + ath11k_err(ar->ab, "periodicity should be 10x\n"); + return -EINVAL; + } + + if (ar->cfr.cfr_enabled_peer_cnt >= ATH11K_MAX_CFR_ENABLED_CLIENTS && + !arsta->cfr_capture.cfr_enable) { + ath11k_err(ar->ab, "CFR enable peer threshold reached %u\n", + ar->cfr.cfr_enabled_peer_cnt); + return -EINVAL; + } + + if (!cfr_capture_enable) { + cfr_capture_bw = arsta->cfr_capture.cfr_bw; + cfr_capture_period = arsta->cfr_capture.cfr_period; + cfr_capture_method = arsta->cfr_capture.cfr_method; + } + + arg.request = cfr_capture_enable; + arg.periodicity = cfr_capture_period; + arg.bw = cfr_capture_bw; + arg.method = cfr_capture_method; + + ret = ath11k_wmi_peer_set_cfr_capture_conf(ar, arsta->arvif->vdev_id, + sta->addr, &arg); + if (ret) { + ath11k_warn(ar->ab, + "failed to send cfr capture info: vdev_id %u peer %pM: %d\n", + arsta->arvif->vdev_id, sta->addr, ret); + return ret; + } + + spin_lock_bh(&ar->cfr.lock); + + if (cfr_capture_enable && + cfr_capture_enable != arsta->cfr_capture.cfr_enable) + cfr->cfr_enabled_peer_cnt++; + else if (!cfr_capture_enable) + cfr->cfr_enabled_peer_cnt--; + + spin_unlock_bh(&ar->cfr.lock); + + arsta->cfr_capture.cfr_enable = cfr_capture_enable; + arsta->cfr_capture.cfr_period = cfr_capture_period; + arsta->cfr_capture.cfr_bw = cfr_capture_bw; + arsta->cfr_capture.cfr_method = cfr_capture_method; + + return count; +} + +static ssize_t ath11k_dbg_sta_read_cfr_capture(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ieee80211_sta *sta = file->private_data; + struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta); + struct ath11k *ar = arsta->arvif->ar; + char buf[512] = {}; + int len = 0; + + mutex_lock(&ar->conf_mutex); + + len += scnprintf(buf + len, sizeof(buf) - len, "cfr_enabled = %d\n", + arsta->cfr_capture.cfr_enable); + len += scnprintf(buf + len, sizeof(buf) - len, "bandwidth = %d\n", + arsta->cfr_capture.cfr_bw); + len += scnprintf(buf + len, sizeof(buf) - len, "period = %d\n", + arsta->cfr_capture.cfr_period); + len += scnprintf(buf + len, sizeof(buf) - len, "cfr_method = %d\n", + arsta->cfr_capture.cfr_method); + + mutex_unlock(&ar->conf_mutex); + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static const struct file_operations fops_peer_cfr_capture = { + .write = ath11k_dbg_sta_write_cfr_capture, + .read = ath11k_dbg_sta_read_cfr_capture, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; +#endif /* CONFIG_ATH11K_CFR */ + static ssize_t ath11k_dbg_sta_dump_rx_stats(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) @@ -877,6 +1010,13 @@ void ath11k_debugfs_sta_op_add(struct ieee80211_hw *hw, struct ieee80211_vif *vi debugfs_create_file("htt_peer_stats_reset", 0600, dir, sta, &fops_htt_peer_stats_reset); +#ifdef CONFIG_ATH11K_CFR + if (test_bit(WMI_TLV_SERVICE_CFR_CAPTURE_SUPPORT, + ar->ab->wmi_ab.svc_map)) + debugfs_create_file("cfr_capture", 0600, dir, sta, + &fops_peer_cfr_capture); +#endif/* CONFIG_ATH11K_CFR */ + debugfs_create_file("peer_ps_state", 0400, dir, sta, &fops_peer_ps_state); diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index f142c17aa9aa7..bb7e0eb487c6c 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -9804,6 +9804,8 @@ static int ath11k_mac_op_sta_state(struct ieee80211_hw *hw, } spin_unlock_bh(&ar->ab->base_lock); mutex_unlock(&ar->ab->tbl_mtx_lock); + + ath11k_cfr_decrement_peer_count(ar, arsta); } else if (old_state == IEEE80211_STA_AUTH && new_state == IEEE80211_STA_ASSOC && (vif->type == NL80211_IFTYPE_AP || diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c index 110035dae8a61..b14edc0820a24 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.c +++ b/drivers/net/wireless/ath/ath11k/wmi.c @@ -3941,6 +3941,47 @@ int ath11k_wmi_fils_discovery_tmpl(struct ath11k *ar, u32 vdev_id, return 0; } +int ath11k_wmi_peer_set_cfr_capture_conf(struct ath11k *ar, + u32 vdev_id, const u8 *mac_addr, + struct wmi_peer_cfr_capture_conf_arg *arg) +{ + struct ath11k_pdev_wmi *wmi = ar->wmi; + struct wmi_peer_cfr_capture_cmd_fixed_param *cmd; + struct sk_buff *skb; + int ret; + + skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd)); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_peer_cfr_capture_cmd_fixed_param *)skb->data; + cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, + WMI_TAG_PEER_CFR_CAPTURE_CMD) | + FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE); + + memcpy(&cmd->mac_addr, mac_addr, ETH_ALEN); + cmd->request = arg->request; + cmd->vdev_id = vdev_id; + cmd->periodicity = arg->periodicity; + cmd->bandwidth = arg->bw; + cmd->capture_method = arg->method; + + ret = ath11k_wmi_cmd_send(ar->wmi, skb, WMI_PEER_CFR_CAPTURE_CMDID); + if (ret) { + ath11k_warn(ar->ab, + "WMI vdev %d failed to send peer cfr capture cmd: %d\n", + vdev_id, ret); + dev_kfree_skb(skb); + } + + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, + "WMI peer CFR capture cmd req %u id %u period %u bw %u mode %u\n", + arg->request, vdev_id, arg->periodicity, + arg->bw, arg->method); + + return ret; +} + int ath11k_wmi_probe_resp_tmpl(struct ath11k *ar, u32 vdev_id, struct sk_buff *tmpl) { diff --git a/drivers/net/wireless/ath/ath11k/wmi.h b/drivers/net/wireless/ath/ath11k/wmi.h index 4c2c7d8432588..d54eba8561e21 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.h +++ b/drivers/net/wireless/ath/ath11k/wmi.h @@ -362,6 +362,10 @@ enum wmi_tlv_cmd_id { WMI_PEER_REORDER_QUEUE_REMOVE_CMDID, WMI_PEER_SET_RX_BLOCKSIZE_CMDID, WMI_PEER_ANTDIV_INFO_REQ_CMDID, + WMI_PEER_RESERVED0_CMDID, + WMI_PEER_TID_MSDUQ_QDEPTH_THRESH_UPDATE_CMDID, + WMI_PEER_TID_CONFIGURATIONS_CMDID, + WMI_PEER_CFR_CAPTURE_CMDID, WMI_BCN_TX_CMDID = WMI_TLV_CMD(WMI_GRP_MGMT), WMI_PDEV_SEND_BCN_CMDID, WMI_BCN_TMPL_CMDID, @@ -3847,7 +3851,8 @@ struct wmi_scan_prob_req_oui_cmd { #define WMI_TX_PARAMS_DWORD1_BW_MASK GENMASK(14, 8) #define WMI_TX_PARAMS_DWORD1_PREAMBLE_TYPE GENMASK(19, 15) #define WMI_TX_PARAMS_DWORD1_FRAME_TYPE BIT(20) -#define WMI_TX_PARAMS_DWORD1_RSVD GENMASK(31, 21) +#define WMI_TX_PARAMS_DWORD1_CFR_CAPTURE BIT(21) +#define WMI_TX_PARAMS_DWORD1_RSVD GENMASK(31, 22) struct wmi_mgmt_send_params { u32 tlv_header; @@ -4232,6 +4237,45 @@ enum cc_setting_code { */ }; +enum ath11k_wmi_cfr_capture_bw { + WMI_PEER_CFR_CAPTURE_BW_20, + WMI_PEER_CFR_CAPTURE_BW_40, + WMI_PEER_CFR_CAPTURE_BW_80, + WMI_PEER_CFR_CAPTURE_BW_MAX, +}; + +enum ath11k_wmi_cfr_capture_method { + WMI_CFR_CAPTURE_METHOD_NULL_FRAME, + WMI_CFR_CAPTURE_METHOD_NULL_FRAME_WITH_PHASE, + WMI_CFR_CAPTURE_METHOD_PROBE_RESP, + WMI_CFR_CAPTURE_METHOD_MAX, +}; + +struct wmi_peer_cfr_capture_conf_arg { + enum ath11k_wmi_cfr_capture_bw bw; + enum ath11k_wmi_cfr_capture_method method; + u32 request; + u32 periodicity; +}; + +struct wmi_peer_cfr_capture_cmd_fixed_param { + u32 tlv_header; + u32 request; + struct wmi_mac_addr mac_addr; + u32 vdev_id; + u32 periodicity; + /* BW of measurement - of type enum ath11k_wmi_cfr_capture_bw */ + u32 bandwidth; + /* Method used to capture CFR - of type enum ath11k_wmi_cfr_capture_method */ + u32 capture_method; +} __packed; + +#define WMI_PEER_CFR_CAPTURE_ENABLE 1 +#define WMI_PEER_CFR_CAPTURE_DISABLE 0 + +/*periodicity in ms */ +#define WMI_PEER_CFR_PERIODICITY_MAX 600000 + static inline enum cc_setting_code ath11k_wmi_cc_setting_code_to_reg(enum wmi_reg_cc_setting_code status_code) { @@ -6546,5 +6590,7 @@ bool ath11k_wmi_supports_6ghz_cc_ext(struct ath11k *ar); int ath11k_wmi_send_vdev_set_tpc_power(struct ath11k *ar, u32 vdev_id, struct ath11k_reg_tpc_power_info *param); - +int ath11k_wmi_peer_set_cfr_capture_conf(struct ath11k *ar, + u32 vdev_id, const u8 *mac, + struct wmi_peer_cfr_capture_conf_arg *arg); #endif From 0cb9749fd4ae28fb320c7ebc8e37dde0b6123c0a Mon Sep 17 00:00:00 2001 From: Venkateswara Naralasetty Date: Wed, 5 Nov 2025 09:22:23 -0800 Subject: [PATCH 2330/2333] FROMGIT: wifi: ath11k: Add support unassociated client CFR Provide debugfs interfaces support to config unassociated client CFR from the user space. To enable CFR capture for unassociated clients, echo " " > /sys/kernel/debug/ieee80211/phyX/ath11k/cfr_unassoc Mac address: mac address of the client. Val: 0 - start CFR capture 1 - stop CFR capture Periodicity: Periodicity at which hardware is expected to collect CFR dump. 0 - single shot capture. non zero - for Periodic captures (value must be multiple of 10 ms) Tested-on: IPQ8074 hw2.0 PCI IPQ8074 WLAN.HK.2.5.0.1-00991-QCAHKSWPL_SILICONZ-1 Tested-on: WCN6855 hw2.1 PCI WLAN.HSP.1.1-04685-QCAHSPSWPL_V1_V2_SILICONZ_IOE-1 Signed-off-by: Venkateswara Naralasetty Co-developed-by: Yu Zhang (Yuriy) Signed-off-by: Yu Zhang (Yuriy) Reviewed-by: Vasanthakumar Thiagarajan Reviewed-by: Baochen Qiang Signed-off-by: Qian Zhang Link: https://patch.msgid.link/20251230082520.3401007-3-qian.zhang@oss.qualcomm.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath11k/cfr.c | 228 ++++++++++++++++++++++++++ drivers/net/wireless/ath/ath11k/cfr.h | 33 ++++ drivers/net/wireless/ath/ath11k/mac.c | 15 +- drivers/net/wireless/ath/ath11k/wmi.c | 16 +- drivers/net/wireless/ath/ath11k/wmi.h | 2 +- 5 files changed, 290 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/cfr.c b/drivers/net/wireless/ath/ath11k/cfr.c index bf0b880e87466..e22b0151833ca 100644 --- a/drivers/net/wireless/ath/ath11k/cfr.c +++ b/drivers/net/wireless/ath/ath11k/cfr.c @@ -14,6 +14,60 @@ static int ath11k_cfr_process_data(struct ath11k *ar, return 0; } +/* Helper function to check whether the given peer mac address + * is in unassociated peer pool or not. + */ +bool ath11k_cfr_peer_is_in_cfr_unassoc_pool(struct ath11k *ar, const u8 *peer_mac) +{ + struct ath11k_cfr *cfr = &ar->cfr; + struct cfr_unassoc_pool_entry *entry; + int i; + + if (!ar->cfr_enabled) + return false; + + spin_lock_bh(&cfr->lock); + for (i = 0; i < ATH11K_MAX_CFR_ENABLED_CLIENTS; i++) { + entry = &cfr->unassoc_pool[i]; + if (!entry->is_valid) + continue; + + if (ether_addr_equal(peer_mac, entry->peer_mac)) { + spin_unlock_bh(&cfr->lock); + return true; + } + } + + spin_unlock_bh(&cfr->lock); + + return false; +} + +void ath11k_cfr_update_unassoc_pool_entry(struct ath11k *ar, + const u8 *peer_mac) +{ + struct ath11k_cfr *cfr = &ar->cfr; + struct cfr_unassoc_pool_entry *entry; + int i; + + spin_lock_bh(&cfr->lock); + for (i = 0; i < ATH11K_MAX_CFR_ENABLED_CLIENTS; i++) { + entry = &cfr->unassoc_pool[i]; + if (!entry->is_valid) + continue; + + if (ether_addr_equal(peer_mac, entry->peer_mac) && + entry->period == 0) { + memset(entry->peer_mac, 0, ETH_ALEN); + entry->is_valid = false; + cfr->cfr_enabled_peer_cnt--; + break; + } + } + + spin_unlock_bh(&cfr->lock); +} + void ath11k_cfr_decrement_peer_count(struct ath11k *ar, struct ath11k_sta *arsta) { @@ -130,6 +184,59 @@ int ath11k_cfr_send_peer_cfr_capture_cmd(struct ath11k *ar, return ret; } +void ath11k_cfr_update_unassoc_pool(struct ath11k *ar, + struct ath11k_per_peer_cfr_capture *params, + u8 *peer_mac) +{ + struct ath11k_cfr *cfr = &ar->cfr; + struct cfr_unassoc_pool_entry *entry; + int available_idx = -1; + int i; + + guard(spinlock_bh)(&cfr->lock); + + if (!params->cfr_enable) { + for (i = 0; i < ATH11K_MAX_CFR_ENABLED_CLIENTS; i++) { + entry = &cfr->unassoc_pool[i]; + if (ether_addr_equal(peer_mac, entry->peer_mac)) { + memset(entry->peer_mac, 0, ETH_ALEN); + entry->is_valid = false; + cfr->cfr_enabled_peer_cnt--; + break; + } + } + return; + } + + if (cfr->cfr_enabled_peer_cnt >= ATH11K_MAX_CFR_ENABLED_CLIENTS) { + ath11k_info(ar->ab, "Max cfr peer threshold reached\n"); + return; + } + + for (i = 0; i < ATH11K_MAX_CFR_ENABLED_CLIENTS; i++) { + entry = &cfr->unassoc_pool[i]; + + if (ether_addr_equal(peer_mac, entry->peer_mac)) { + ath11k_info(ar->ab, + "peer entry already present updating params\n"); + entry->period = params->cfr_period; + available_idx = -1; + break; + } + + if (available_idx < 0 && !entry->is_valid) + available_idx = i; + } + + if (available_idx >= 0) { + entry = &cfr->unassoc_pool[available_idx]; + ether_addr_copy(entry->peer_mac, peer_mac); + entry->period = params->cfr_period; + entry->is_valid = true; + cfr->cfr_enabled_peer_cnt++; + } +} + static ssize_t ath11k_read_file_enable_cfr(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) @@ -188,10 +295,127 @@ static const struct file_operations fops_enable_cfr = { .llseek = default_llseek, }; +static ssize_t ath11k_write_file_cfr_unassoc(struct file *file, + const char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct ath11k *ar = file->private_data; + struct ath11k_cfr *cfr = &ar->cfr; + struct cfr_unassoc_pool_entry *entry; + char buf[64] = {}; + u8 peer_mac[6]; + u32 cfr_capture_enable; + u32 cfr_capture_period; + int available_idx = -1; + int ret, i; + + simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, ubuf, count); + + guard(mutex)(&ar->conf_mutex); + guard(spinlock_bh)(&cfr->lock); + + if (ar->state != ATH11K_STATE_ON) + return -ENETDOWN; + + if (!ar->cfr_enabled) { + ath11k_err(ar->ab, "CFR is not enabled on this pdev %d\n", + ar->pdev_idx); + return -EINVAL; + } + + ret = sscanf(buf, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx %u %u", + &peer_mac[0], &peer_mac[1], &peer_mac[2], &peer_mac[3], + &peer_mac[4], &peer_mac[5], &cfr_capture_enable, + &cfr_capture_period); + + if (ret < 1) + return -EINVAL; + + if (cfr_capture_enable && ret != 8) + return -EINVAL; + + if (!cfr_capture_enable) { + for (i = 0; i < ATH11K_MAX_CFR_ENABLED_CLIENTS; i++) { + entry = &cfr->unassoc_pool[i]; + if (ether_addr_equal(peer_mac, entry->peer_mac)) { + memset(entry->peer_mac, 0, ETH_ALEN); + entry->is_valid = false; + cfr->cfr_enabled_peer_cnt--; + } + } + + return count; + } + + if (cfr->cfr_enabled_peer_cnt >= ATH11K_MAX_CFR_ENABLED_CLIENTS) { + ath11k_info(ar->ab, "Max cfr peer threshold reached\n"); + return count; + } + + for (i = 0; i < ATH11K_MAX_CFR_ENABLED_CLIENTS; i++) { + entry = &cfr->unassoc_pool[i]; + + if (available_idx < 0 && !entry->is_valid) + available_idx = i; + + if (ether_addr_equal(peer_mac, entry->peer_mac)) { + ath11k_info(ar->ab, + "peer entry already present updating params\n"); + entry->period = cfr_capture_period; + return count; + } + } + + if (available_idx >= 0) { + entry = &cfr->unassoc_pool[available_idx]; + ether_addr_copy(entry->peer_mac, peer_mac); + entry->period = cfr_capture_period; + entry->is_valid = true; + cfr->cfr_enabled_peer_cnt++; + } + + return count; +} + +static ssize_t ath11k_read_file_cfr_unassoc(struct file *file, + char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct ath11k *ar = file->private_data; + struct ath11k_cfr *cfr = &ar->cfr; + struct cfr_unassoc_pool_entry *entry; + char buf[512] = {}; + int len = 0, i; + + spin_lock_bh(&cfr->lock); + + for (i = 0; i < ATH11K_MAX_CFR_ENABLED_CLIENTS; i++) { + entry = &cfr->unassoc_pool[i]; + if (entry->is_valid) + len += scnprintf(buf + len, sizeof(buf) - len, + "peer: %pM period: %u\n", + entry->peer_mac, entry->period); + } + + spin_unlock_bh(&cfr->lock); + + return simple_read_from_buffer(ubuf, count, ppos, buf, len); +} + +static const struct file_operations fops_configure_cfr_unassoc = { + .write = ath11k_write_file_cfr_unassoc, + .read = ath11k_read_file_cfr_unassoc, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + static void ath11k_cfr_debug_unregister(struct ath11k *ar) { debugfs_remove(ar->cfr.enable_cfr); ar->cfr.enable_cfr = NULL; + debugfs_remove(ar->cfr.cfr_unassoc); + ar->cfr.cfr_unassoc = NULL; } static void ath11k_cfr_debug_register(struct ath11k *ar) @@ -199,6 +423,10 @@ static void ath11k_cfr_debug_register(struct ath11k *ar) ar->cfr.enable_cfr = debugfs_create_file("enable_cfr", 0600, ar->debug.debugfs_pdev, ar, &fops_enable_cfr); + + ar->cfr.cfr_unassoc = debugfs_create_file("cfr_unassoc", 0600, + ar->debug.debugfs_pdev, ar, + &fops_configure_cfr_unassoc); } void ath11k_cfr_lut_update_paddr(struct ath11k *ar, dma_addr_t paddr, diff --git a/drivers/net/wireless/ath/ath11k/cfr.h b/drivers/net/wireless/ath/ath11k/cfr.h index 7d161f7f7be84..e7b69e98cbf53 100644 --- a/drivers/net/wireless/ath/ath11k/cfr.h +++ b/drivers/net/wireless/ath/ath11k/cfr.h @@ -45,6 +45,12 @@ struct ath11k_look_up_table { struct ath11k_dbring_element *buff; }; +struct cfr_unassoc_pool_entry { + u8 peer_mac[ETH_ALEN]; + u32 period; + bool is_valid; +}; + struct ath11k_cfr { struct ath11k_dbring rx_ring; /* Protects cfr data */ @@ -53,6 +59,7 @@ struct ath11k_cfr { spinlock_t lut_lock; struct ath11k_look_up_table *lut; struct dentry *enable_cfr; + struct dentry *cfr_unassoc; u8 cfr_enabled_peer_cnt; u32 lut_num; u64 tx_evt_cnt; @@ -66,6 +73,7 @@ struct ath11k_cfr { u64 clear_txrx_event; u64 cfr_dma_aborts; bool enabled; + struct cfr_unassoc_pool_entry unassoc_pool[ATH11K_MAX_CFR_ENABLED_CLIENTS]; }; enum ath11k_cfr_capture_method { @@ -89,6 +97,13 @@ void ath11k_cfr_lut_update_paddr(struct ath11k *ar, dma_addr_t paddr, u32 buf_id); void ath11k_cfr_decrement_peer_count(struct ath11k *ar, struct ath11k_sta *arsta); +void ath11k_cfr_update_unassoc_pool_entry(struct ath11k *ar, + const u8 *peer_mac); +bool ath11k_cfr_peer_is_in_cfr_unassoc_pool(struct ath11k *ar, + const u8 *peer_mac); +void ath11k_cfr_update_unassoc_pool(struct ath11k *ar, + struct ath11k_per_peer_cfr_capture *params, + u8 *peer_mac); int ath11k_cfr_send_peer_cfr_capture_cmd(struct ath11k *ar, struct ath11k_sta *arsta, struct ath11k_per_peer_cfr_capture *params, @@ -114,6 +129,24 @@ static inline void ath11k_cfr_decrement_peer_count(struct ath11k *ar, { } +static inline void ath11k_cfr_update_unassoc_pool_entry(struct ath11k *ar, + const u8 *peer_mac) +{ +} + +static inline bool +ath11k_cfr_peer_is_in_cfr_unassoc_pool(struct ath11k *ar, const u8 *peer_mac) +{ + return false; +} + +static inline void +ath11k_cfr_update_unassoc_pool(struct ath11k *ar, + struct ath11k_per_peer_cfr_capture *params, + u8 *peer_mac) +{ +} + static inline int ath11k_cfr_send_peer_cfr_capture_cmd(struct ath11k *ar, struct ath11k_sta *arsta, diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index bb7e0eb487c6c..3a80b351083f4 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -6042,6 +6042,8 @@ static int ath11k_mac_mgmt_tx_wmi(struct ath11k *ar, struct ath11k_vif *arvif, dma_addr_t paddr; int buf_id; int ret; + bool tx_params_valid = false; + bool peer_in_unassoc_pool; ATH11K_SKB_CB(skb)->ar = ar; @@ -6080,7 +6082,18 @@ static int ath11k_mac_mgmt_tx_wmi(struct ath11k *ar, struct ath11k_vif *arvif, ATH11K_SKB_CB(skb)->paddr = paddr; - ret = ath11k_wmi_mgmt_send(ar, arvif->vdev_id, buf_id, skb); + peer_in_unassoc_pool = ath11k_cfr_peer_is_in_cfr_unassoc_pool(ar, hdr->addr1); + + if (ar->cfr_enabled && + ieee80211_is_probe_resp(hdr->frame_control) && + peer_in_unassoc_pool) + tx_params_valid = true; + + if (peer_in_unassoc_pool) + ath11k_cfr_update_unassoc_pool_entry(ar, hdr->addr1); + + ret = ath11k_wmi_mgmt_send(ar, arvif->vdev_id, buf_id, skb, + tx_params_valid); if (ret) { ath11k_warn(ar->ab, "failed to send mgmt frame: %d\n", ret); goto err_unmap_buf; diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c index b14edc0820a24..b40a31414a471 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.c +++ b/drivers/net/wireless/ath/ath11k/wmi.c @@ -651,11 +651,12 @@ static u32 ath11k_wmi_mgmt_get_freq(struct ath11k *ar, } int ath11k_wmi_mgmt_send(struct ath11k *ar, u32 vdev_id, u32 buf_id, - struct sk_buff *frame) + struct sk_buff *frame, bool tx_params_valid) { struct ath11k_pdev_wmi *wmi = ar->wmi; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(frame); struct wmi_mgmt_send_cmd *cmd; + struct wmi_mgmt_send_params *params; struct wmi_tlv *frame_tlv; struct sk_buff *skb; u32 buf_len; @@ -665,6 +666,8 @@ int ath11k_wmi_mgmt_send(struct ath11k *ar, u32 vdev_id, u32 buf_id, frame->len : WMI_MGMT_SEND_DOWNLD_LEN; len = sizeof(*cmd) + sizeof(*frame_tlv) + roundup(buf_len, 4); + if (tx_params_valid) + len += sizeof(*params); skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, len); if (!skb) @@ -680,7 +683,7 @@ int ath11k_wmi_mgmt_send(struct ath11k *ar, u32 vdev_id, u32 buf_id, cmd->paddr_hi = upper_32_bits(ATH11K_SKB_CB(frame)->paddr); cmd->frame_len = frame->len; cmd->buf_len = buf_len; - cmd->tx_params_valid = 0; + cmd->tx_params_valid = !!tx_params_valid; frame_tlv = (struct wmi_tlv *)(skb->data + sizeof(*cmd)); frame_tlv->header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ARRAY_BYTE) | @@ -690,6 +693,15 @@ int ath11k_wmi_mgmt_send(struct ath11k *ar, u32 vdev_id, u32 buf_id, ath11k_ce_byte_swap(frame_tlv->value, buf_len); + if (tx_params_valid) { + params = + (struct wmi_mgmt_send_params *)(skb->data + (len - sizeof(*params))); + params->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_TX_SEND_PARAMS) | + FIELD_PREP(WMI_TLV_LEN, + sizeof(*params) - TLV_HDR_SIZE); + params->tx_params_dword1 |= WMI_TX_PARAMS_DWORD1_CFR_CAPTURE; + } + ret = ath11k_wmi_cmd_send(wmi, skb, WMI_MGMT_TX_SEND_CMDID); if (ret) { ath11k_warn(ar->ab, diff --git a/drivers/net/wireless/ath/ath11k/wmi.h b/drivers/net/wireless/ath/ath11k/wmi.h index d54eba8561e21..0c80d99e464d4 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.h +++ b/drivers/net/wireless/ath/ath11k/wmi.h @@ -6405,7 +6405,7 @@ int ath11k_wmi_cmd_send(struct ath11k_pdev_wmi *wmi, struct sk_buff *skb, u32 cmd_id); struct sk_buff *ath11k_wmi_alloc_skb(struct ath11k_wmi_base *wmi_sc, u32 len); int ath11k_wmi_mgmt_send(struct ath11k *ar, u32 vdev_id, u32 buf_id, - struct sk_buff *frame); + struct sk_buff *frame, bool tx_params_valid); int ath11k_wmi_p2p_go_bcn_ie(struct ath11k *ar, u32 vdev_id, const u8 *p2p_ie); int ath11k_wmi_bcn_tmpl(struct ath11k *ar, u32 vdev_id, From 02650b4fae6790877172c4cf712a4224a27feae2 Mon Sep 17 00:00:00 2001 From: Venkateswara Naralasetty Date: Wed, 5 Nov 2025 09:22:24 -0800 Subject: [PATCH 2331/2333] FROMGIT: wifi: ath11k: Register relayfs entries for CFR dump Provide a relayfs interface to collect the CFR dump from the user space. '/sys/kernel/debug/ieee80211/phyX/ath11k/cfr_capture' is exposed to user space to get CFR data. CFR format to user space: ___________________________________________ | CFR header | CFR payload | CFR tail data | |____________|_____________|_______________| CFR header contains the following fields, * Start magic number 0xDEADBEAF - 4 bytes * vendor id - 4 bytes * cfr metadata version - 1 byte * cfr data version - 1 byte * device type - 1 byte * platform type - 1 byte * CFR metadata length - 4 bytes * metadata - 92 bytes peer mac - 6 bytes capture status - 1 byte (1 for success 0 for failure) capture_bw - 1 byte channel_bw - 1 byte phy_mode - 1 byte prim20_chan - 2 bytes center_freq1 - 2 bytes center_freq2 - 2 bytes capture_mode - 1 byte capture_type - 1 byte sts_count - 1 byte num_rx_chain - 1 byte timestamp - 4 bytes length - 4 bytes chain_rssi - 32 bytes (4 bytes for each chain) chain_phase - 16 bytes (2 bytes for each chain) cfo_measurement - 4 bytes agc_gain - 8 bytes (1 bytes for each chain) rx_start_ts - 4 bytes CFR payload: CFR payload contains 8bytes of ucode header followed by the tone information. Tone order is positive tones, followed by PHY memory garbage, followed by negative tones. Dummy tones are uploaded to make number of tones always integer number of 64. Number of tones is not preamble type dependent. Each CFR tone has 14-bit I component and 14-bit Q component and is sign extended to 16-bit I/Q. Two tones are packed into one 64-bit unit as: [63:0] = [Tone1_Q(63:48) Tone1_I(47:32) Tone0_Q(31:16) Tone0_I(15:0)] CFR tail: end magic number 0xBEAFDEAD Tested-on: IPQ8074 hw2.0 PCI IPQ8074 WLAN.HK.2.5.0.1-00991-QCAHKSWPL_SILICONZ-1 Tested-on: WCN6855 hw2.1 PCI WLAN.HSP.1.1-04685-QCAHSPSWPL_V1_V2_SILICONZ_IOE-1 Signed-off-by: Venkateswara Naralasetty Co-developed-by: Yu Zhang (Yuriy) Signed-off-by: Yu Zhang (Yuriy) Reviewed-by: Vasanthakumar Thiagarajan Reviewed-by: Baochen Qiang Signed-off-by: Qian Zhang Link: https://patch.msgid.link/20251230082520.3401007-3-qian.zhang@oss.qualcomm.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath11k/cfr.c | 35 +++++++++++++++++++++++++++ drivers/net/wireless/ath/ath11k/cfr.h | 1 + 2 files changed, 36 insertions(+) diff --git a/drivers/net/wireless/ath/ath11k/cfr.c b/drivers/net/wireless/ath/ath11k/cfr.c index e22b0151833ca..495b2c6742aaf 100644 --- a/drivers/net/wireless/ath/ath11k/cfr.c +++ b/drivers/net/wireless/ath/ath11k/cfr.c @@ -416,10 +416,45 @@ static void ath11k_cfr_debug_unregister(struct ath11k *ar) ar->cfr.enable_cfr = NULL; debugfs_remove(ar->cfr.cfr_unassoc); ar->cfr.cfr_unassoc = NULL; + + relay_close(ar->cfr.rfs_cfr_capture); + ar->cfr.rfs_cfr_capture = NULL; } +static struct dentry *ath11k_cfr_create_buf_file_handler(const char *filename, + struct dentry *parent, + umode_t mode, + struct rchan_buf *buf, + int *is_global) +{ + struct dentry *buf_file; + + buf_file = debugfs_create_file(filename, mode, parent, buf, + &relay_file_operations); + *is_global = 1; + return buf_file; +} + +static int ath11k_cfr_remove_buf_file_handler(struct dentry *dentry) +{ + debugfs_remove(dentry); + + return 0; +} + +static const struct rchan_callbacks rfs_cfr_capture_cb = { + .create_buf_file = ath11k_cfr_create_buf_file_handler, + .remove_buf_file = ath11k_cfr_remove_buf_file_handler, +}; + static void ath11k_cfr_debug_register(struct ath11k *ar) { + ar->cfr.rfs_cfr_capture = relay_open("cfr_capture", + ar->debug.debugfs_pdev, + ar->ab->hw_params.cfr_stream_buf_size, + ar->ab->hw_params.cfr_num_stream_bufs, + &rfs_cfr_capture_cb, NULL); + ar->cfr.enable_cfr = debugfs_create_file("enable_cfr", 0600, ar->debug.debugfs_pdev, ar, &fops_enable_cfr); diff --git a/drivers/net/wireless/ath/ath11k/cfr.h b/drivers/net/wireless/ath/ath11k/cfr.h index e7b69e98cbf53..19f136d34c65b 100644 --- a/drivers/net/wireless/ath/ath11k/cfr.h +++ b/drivers/net/wireless/ath/ath11k/cfr.h @@ -60,6 +60,7 @@ struct ath11k_cfr { struct ath11k_look_up_table *lut; struct dentry *enable_cfr; struct dentry *cfr_unassoc; + struct rchan *rfs_cfr_capture; u8 cfr_enabled_peer_cnt; u32 lut_num; u64 tx_evt_cnt; From f40c10e3151cc6a3d5a2c14193f9a5c06cd4e360 Mon Sep 17 00:00:00 2001 From: Venkateswara Naralasetty Date: Wed, 5 Nov 2025 09:22:25 -0800 Subject: [PATCH 2332/2333] FROMGIT: wifi: ath11k: Register DBR event handler for CFR data Add handler for WMI_PDEV_DMA_RING_BUF_RELEASE_EVENT which indicates CFR data availability in the DB ring. Add CFR data processing from DB ring buffers. Use correlate_and_relay API to match CFR data with metadata from WMI_PEER_CFR_CAPTURE_EVENT. Release buffer to userspace through relayfs on successful correlation, otherwise hold buffer waiting for matching WMI event from firmware. Add new debug masks: - ATH11K_DBG_CFR: Enables CFR-related debug logs. - ATH11K_DBG_CFR_DUMP: Enables detailed CFR data dump for analysis. Tested-on: IPQ8074 hw2.0 PCI IPQ8074 WLAN.HK.2.5.0.1-00991-QCAHKSWPL_SILICONZ-1 Tested-on: WCN6855 hw2.1 PCI WLAN.HSP.1.1-04685-QCAHSPSWPL_V1_V2_SILICONZ_IOE-1 Signed-off-by: Venkateswara Naralasetty Co-developed-by: Yu Zhang (Yuriy) Signed-off-by: Yu Zhang (Yuriy) Reviewed-by: Vasanthakumar Thiagarajan Reviewed-by: Baochen Qiang Signed-off-by: Qian Zhang Link: https://patch.msgid.link/20251230082520.3401007-3-qian.zhang@oss.qualcomm.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath11k/cfr.c | 240 ++++++++++++++++++++++- drivers/net/wireless/ath/ath11k/cfr.h | 82 ++++++++ drivers/net/wireless/ath/ath11k/dbring.c | 10 +- drivers/net/wireless/ath/ath11k/dbring.h | 2 + drivers/net/wireless/ath/ath11k/debug.h | 8 +- 5 files changed, 339 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/cfr.c b/drivers/net/wireless/ath/ath11k/cfr.c index 495b2c6742aaf..ee7626bd4b1a5 100644 --- a/drivers/net/wireless/ath/ath11k/cfr.c +++ b/drivers/net/wireless/ath/ath11k/cfr.c @@ -8,10 +8,248 @@ #include "core.h" #include "debug.h" +struct ath11k_dbring *ath11k_cfr_get_dbring(struct ath11k *ar) +{ + if (ar->cfr_enabled) + return &ar->cfr.rx_ring; + + return NULL; +} + +static int ath11k_cfr_calculate_tones_from_dma_hdr(struct ath11k_cfr_dma_hdr *hdr) +{ + u8 bw = FIELD_GET(CFIR_DMA_HDR_INFO1_UPLOAD_PKT_BW, hdr->info1); + u8 preamble = FIELD_GET(CFIR_DMA_HDR_INFO1_PREAMBLE_TYPE, hdr->info1); + + switch (preamble) { + case ATH11K_CFR_PREAMBLE_TYPE_LEGACY: + fallthrough; + case ATH11K_CFR_PREAMBLE_TYPE_VHT: + switch (bw) { + case 0: + return TONES_IN_20MHZ; + case 1: /* DUP40/VHT40 */ + return TONES_IN_40MHZ; + case 2: /* DUP80/VHT80 */ + return TONES_IN_80MHZ; + case 3: /* DUP160/VHT160 */ + return TONES_IN_160MHZ; + default: + return TONES_INVALID; + } + case ATH11K_CFR_PREAMBLE_TYPE_HT: + switch (bw) { + case 0: + return TONES_IN_20MHZ; + case 1: + return TONES_IN_40MHZ; + default: + return TONES_INVALID; + } + default: + return TONES_INVALID; + } +} + +void ath11k_cfr_release_lut_entry(struct ath11k_look_up_table *lut) +{ + memset(lut, 0, sizeof(*lut)); +} + +static void ath11k_cfr_rfs_write(struct ath11k *ar, const void *head, + u32 head_len, const void *data, u32 data_len, + const void *tail, int tail_data) +{ + struct ath11k_cfr *cfr = &ar->cfr; + + if (!cfr->rfs_cfr_capture) + return; + + relay_write(cfr->rfs_cfr_capture, head, head_len); + relay_write(cfr->rfs_cfr_capture, data, data_len); + relay_write(cfr->rfs_cfr_capture, tail, tail_data); + relay_flush(cfr->rfs_cfr_capture); +} + +static void ath11k_cfr_free_pending_dbr_events(struct ath11k *ar) +{ + struct ath11k_cfr *cfr = &ar->cfr; + struct ath11k_look_up_table *lut; + int i; + + if (!cfr->lut) + return; + + for (i = 0; i < cfr->lut_num; i++) { + lut = &cfr->lut[i]; + if (lut->dbr_recv && !lut->tx_recv && + lut->dbr_tstamp < cfr->last_success_tstamp) { + ath11k_dbring_bufs_replenish(ar, &cfr->rx_ring, lut->buff, + WMI_DIRECT_BUF_CFR); + ath11k_cfr_release_lut_entry(lut); + cfr->flush_dbr_cnt++; + } + } +} + +/** + * ath11k_cfr_correlate_and_relay() - Correlate and relay CFR events + * @ar: Pointer to ath11k structure + * @lut: Lookup table for correlation + * @event_type: Type of event received (TX or DBR) + * + * Correlates WMI_PDEV_DMA_RING_BUF_RELEASE_EVENT (DBR) and + * WMI_PEER_CFR_CAPTURE_EVENT (TX capture) by PPDU ID. If both events + * are present and the PPDU IDs match, returns CORRELATE_STATUS_RELEASE + * to relay thecorrelated data to userspace. Otherwise returns + * CORRELATE_STATUS_HOLD to wait for the other event. + * + * Also checks pending DBR events and clears them when no corresponding TX + * capture event is received for the PPDU. + * + * Return: CORRELATE_STATUS_RELEASE or CORRELATE_STATUS_HOLD + */ + +static enum ath11k_cfr_correlate_status +ath11k_cfr_correlate_and_relay(struct ath11k *ar, + struct ath11k_look_up_table *lut, + u8 event_type) +{ + enum ath11k_cfr_correlate_status status; + struct ath11k_cfr *cfr = &ar->cfr; + u64 diff; + + if (event_type == ATH11K_CORRELATE_TX_EVENT) { + if (lut->tx_recv) + cfr->cfr_dma_aborts++; + cfr->tx_evt_cnt++; + lut->tx_recv = true; + } else if (event_type == ATH11K_CORRELATE_DBR_EVENT) { + cfr->dbr_evt_cnt++; + lut->dbr_recv = true; + } + + if (lut->dbr_recv && lut->tx_recv) { + if (lut->dbr_ppdu_id == lut->tx_ppdu_id) { + /* + * 64-bit counters make wraparound highly improbable, + * wraparound handling is omitted. + */ + cfr->last_success_tstamp = lut->dbr_tstamp; + if (lut->dbr_tstamp > lut->txrx_tstamp) { + diff = lut->dbr_tstamp - lut->txrx_tstamp; + ath11k_dbg(ar->ab, ATH11K_DBG_CFR, + "txrx event -> dbr event delay = %u ms", + jiffies_to_msecs(diff)); + } else if (lut->txrx_tstamp > lut->dbr_tstamp) { + diff = lut->txrx_tstamp - lut->dbr_tstamp; + ath11k_dbg(ar->ab, ATH11K_DBG_CFR, + "dbr event -> txrx event delay = %u ms", + jiffies_to_msecs(diff)); + } + + ath11k_cfr_free_pending_dbr_events(ar); + + cfr->release_cnt++; + status = ATH11K_CORRELATE_STATUS_RELEASE; + } else { + /* + * Discard TXRX event on PPDU ID mismatch because multiple PPDUs + * may share the same DMA address due to ucode aborts. + */ + + ath11k_dbg(ar->ab, ATH11K_DBG_CFR, + "Received dbr event twice for the same lut entry"); + lut->tx_recv = false; + lut->tx_ppdu_id = 0; + cfr->clear_txrx_event++; + cfr->cfr_dma_aborts++; + status = ATH11K_CORRELATE_STATUS_HOLD; + } + } else { + status = ATH11K_CORRELATE_STATUS_HOLD; + } + + return status; +} + static int ath11k_cfr_process_data(struct ath11k *ar, struct ath11k_dbring_data *param) { - return 0; + u32 end_magic = ATH11K_CFR_END_MAGIC; + struct ath11k_csi_cfr_header *header; + struct ath11k_cfr_dma_hdr *dma_hdr; + struct ath11k_cfr *cfr = &ar->cfr; + struct ath11k_look_up_table *lut; + struct ath11k_base *ab = ar->ab; + u32 buf_id, tones, length; + u8 num_chains; + int status; + u8 *data; + + data = param->data; + buf_id = param->buf_id; + + if (param->data_sz < sizeof(*dma_hdr)) + return -EINVAL; + + dma_hdr = (struct ath11k_cfr_dma_hdr *)data; + + tones = ath11k_cfr_calculate_tones_from_dma_hdr(dma_hdr); + if (tones == TONES_INVALID) { + ath11k_warn(ar->ab, "Number of tones received is invalid\n"); + return -EINVAL; + } + + num_chains = FIELD_GET(CFIR_DMA_HDR_INFO1_NUM_CHAINS, + dma_hdr->info1); + + length = sizeof(*dma_hdr); + length += tones * (num_chains + 1); + + spin_lock_bh(&cfr->lut_lock); + + if (!cfr->lut) { + spin_unlock_bh(&cfr->lut_lock); + return -EINVAL; + } + + lut = &cfr->lut[buf_id]; + + ath11k_dbg_dump(ab, ATH11K_DBG_CFR_DUMP, "data_from_buf_rel:", "", + data, length); + + lut->buff = param->buff; + lut->data = data; + lut->data_len = length; + lut->dbr_ppdu_id = dma_hdr->phy_ppdu_id; + lut->dbr_tstamp = jiffies; + + memcpy(&lut->hdr, dma_hdr, sizeof(*dma_hdr)); + + header = &lut->header; + header->meta_data.channel_bw = FIELD_GET(CFIR_DMA_HDR_INFO1_UPLOAD_PKT_BW, + dma_hdr->info1); + header->meta_data.length = length; + + status = ath11k_cfr_correlate_and_relay(ar, lut, + ATH11K_CORRELATE_DBR_EVENT); + if (status == ATH11K_CORRELATE_STATUS_RELEASE) { + ath11k_dbg(ab, ATH11K_DBG_CFR, + "releasing CFR data to user space"); + ath11k_cfr_rfs_write(ar, &lut->header, + sizeof(struct ath11k_csi_cfr_header), + lut->data, lut->data_len, + &end_magic, sizeof(u32)); + ath11k_cfr_release_lut_entry(lut); + } else if (status == ATH11K_CORRELATE_STATUS_HOLD) { + ath11k_dbg(ab, ATH11K_DBG_CFR, + "tx event is not yet received holding the buf"); + } + + spin_unlock_bh(&cfr->lut_lock); + + return status; } /* Helper function to check whether the given peer mac address diff --git a/drivers/net/wireless/ath/ath11k/cfr.h b/drivers/net/wireless/ath/ath11k/cfr.h index 19f136d34c65b..c8e5086674d28 100644 --- a/drivers/net/wireless/ath/ath11k/cfr.h +++ b/drivers/net/wireless/ath/ath11k/cfr.h @@ -19,9 +19,78 @@ #define HOST_MAX_CHAINS 8 +enum ath11k_cfr_correlate_event_type { + ATH11K_CORRELATE_DBR_EVENT, + ATH11K_CORRELATE_TX_EVENT, +}; + struct ath11k_sta; struct ath11k_per_peer_cfr_capture; +#define ATH11K_CFR_END_MAGIC 0xBEAFDEAD + +enum ath11k_cfr_correlate_status { + ATH11K_CORRELATE_STATUS_RELEASE, + ATH11K_CORRELATE_STATUS_HOLD, + ATH11K_CORRELATE_STATUS_ERR, +}; + +enum ath11k_cfr_preamble_type { + ATH11K_CFR_PREAMBLE_TYPE_LEGACY, + ATH11K_CFR_PREAMBLE_TYPE_HT, + ATH11K_CFR_PREAMBLE_TYPE_VHT, +}; + +struct cfr_metadata { + u8 peer_addr[ETH_ALEN]; + u8 status; + u8 capture_bw; + u8 channel_bw; + u8 phy_mode; + u16 prim20_chan; + u16 center_freq1; + u16 center_freq2; + u8 capture_mode; + u8 capture_type; + u8 sts_count; + u8 num_rx_chain; + u32 timestamp; + u32 length; + u32 chain_rssi[HOST_MAX_CHAINS]; + u16 chain_phase[HOST_MAX_CHAINS]; + u32 cfo_measurement; + u8 agc_gain[HOST_MAX_CHAINS]; + u32 rx_start_ts; +} __packed; + +struct ath11k_csi_cfr_header { + u32 start_magic_num; + u32 vendorid; + u8 cfr_metadata_version; + u8 cfr_data_version; + u8 chip_type; + u8 platform_type; + u32 reserved; + struct cfr_metadata meta_data; +} __packed; + +#define TONES_IN_20MHZ 256 +#define TONES_IN_40MHZ 512 +#define TONES_IN_80MHZ 1024 +#define TONES_IN_160MHZ 2048 /* 160 MHz isn't supported yet */ +#define TONES_INVALID 0 + +#define CFIR_DMA_HDR_INFO0_TAG GENMASK(7, 0) +#define CFIR_DMA_HDR_INFO0_LEN GENMASK(13, 8) + +#define CFIR_DMA_HDR_INFO1_UPLOAD_DONE GENMASK(0, 0) +#define CFIR_DMA_HDR_INFO1_CAPTURE_TYPE GENMASK(3, 1) +#define CFIR_DMA_HDR_INFO1_PREAMBLE_TYPE GENMASK(5, 4) +#define CFIR_DMA_HDR_INFO1_NSS GENMASK(8, 6) +#define CFIR_DMA_HDR_INFO1_NUM_CHAINS GENMASK(11, 9) +#define CFIR_DMA_HDR_INFO1_UPLOAD_PKT_BW GENMASK(14, 12) +#define CFIR_DMA_HDR_INFO1_SW_PEER_ID_VALID GENMASK(15, 15) + struct ath11k_cfr_dma_hdr { u16 info0; u16 info1; @@ -37,6 +106,7 @@ struct ath11k_look_up_table { u16 dbr_ppdu_id; u16 tx_ppdu_id; dma_addr_t dbr_address; + struct ath11k_csi_cfr_header header; struct ath11k_cfr_dma_hdr hdr; u64 txrx_tstamp; u64 dbr_tstamp; @@ -109,6 +179,8 @@ int ath11k_cfr_send_peer_cfr_capture_cmd(struct ath11k *ar, struct ath11k_sta *arsta, struct ath11k_per_peer_cfr_capture *params, const u8 *peer_mac); +struct ath11k_dbring *ath11k_cfr_get_dbring(struct ath11k *ar); +void ath11k_cfr_release_lut_entry(struct ath11k_look_up_table *lut); #else static inline int ath11k_cfr_init(struct ath11k_base *ab) @@ -156,5 +228,15 @@ ath11k_cfr_send_peer_cfr_capture_cmd(struct ath11k *ar, { return 0; } + +static inline void ath11k_cfr_release_lut_entry(struct ath11k_look_up_table *lut) +{ +} + +static inline +struct ath11k_dbring *ath11k_cfr_get_dbring(struct ath11k *ar) +{ + return NULL; +} #endif /* CONFIG_ATH11K_CFR */ #endif /* ATH11K_CFR_H */ diff --git a/drivers/net/wireless/ath/ath11k/dbring.c b/drivers/net/wireless/ath/ath11k/dbring.c index ed2b781a6bab6..d6994ce6ebff4 100644 --- a/drivers/net/wireless/ath/ath11k/dbring.c +++ b/drivers/net/wireless/ath/ath11k/dbring.c @@ -295,6 +295,7 @@ int ath11k_dbring_buffer_release_event(struct ath11k_base *ab, int size; dma_addr_t paddr; int ret = 0; + int status; pdev_idx = ev->fixed.pdev_id; module_id = ev->fixed.module_id; @@ -328,6 +329,9 @@ int ath11k_dbring_buffer_release_event(struct ath11k_base *ab, case WMI_DIRECT_BUF_SPECTRAL: ring = ath11k_spectral_get_dbring(ar); break; + case WMI_DIRECT_BUF_CFR: + ring = ath11k_cfr_get_dbring(ar); + break; default: ring = NULL; ath11k_warn(ab, "Recv dma buffer release ev on unsupp module %d\n", @@ -378,8 +382,12 @@ int ath11k_dbring_buffer_release_event(struct ath11k_base *ab, handler_data.data = PTR_ALIGN(vaddr_unalign, ring->buf_align); handler_data.data_sz = ring->buf_sz; + handler_data.buff = buff; + handler_data.buf_id = buf_id; - ring->handler(ar, &handler_data); + status = ring->handler(ar, &handler_data); + if (status == ATH11K_CORRELATE_STATUS_HOLD) + continue; } buff->paddr = 0; diff --git a/drivers/net/wireless/ath/ath11k/dbring.h b/drivers/net/wireless/ath/ath11k/dbring.h index 0a380120f7a0e..e5f244dfa9631 100644 --- a/drivers/net/wireless/ath/ath11k/dbring.h +++ b/drivers/net/wireless/ath/ath11k/dbring.h @@ -21,6 +21,8 @@ struct ath11k_dbring_data { void *data; u32 data_sz; struct wmi_dma_buf_release_meta_data meta; + struct ath11k_dbring_element *buff; + u32 buf_id; }; struct ath11k_dbring_buf_release_event { diff --git a/drivers/net/wireless/ath/ath11k/debug.h b/drivers/net/wireless/ath/ath11k/debug.h index cc8934d156977..aaa0034527a59 100644 --- a/drivers/net/wireless/ath/ath11k/debug.h +++ b/drivers/net/wireless/ath/ath11k/debug.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #ifndef _ATH11K_DEBUG_H_ @@ -27,6 +27,8 @@ enum ath11k_debug_mask { ATH11K_DBG_DP_TX = 0x00002000, ATH11K_DBG_DP_RX = 0x00004000, ATH11K_DBG_CE = 0x00008000, + ATH11K_DBG_CFR = 0x00010000, + ATH11K_DBG_CFR_DUMP = 0x00020000, }; static inline const char *ath11k_dbg_str(enum ath11k_debug_mask mask) @@ -64,6 +66,10 @@ static inline const char *ath11k_dbg_str(enum ath11k_debug_mask mask) return "dp_rx"; case ATH11K_DBG_CE: return "ce"; + case ATH11K_DBG_CFR: + return "cfr"; + case ATH11K_DBG_CFR_DUMP: + return "cfr_dump"; /* no default handler to allow compiler to check that the * enum is fully handled From e5ce8abb172b58c9ddafb8e85b97ff23f97762f8 Mon Sep 17 00:00:00 2001 From: Venkateswara Naralasetty Date: Wed, 5 Nov 2025 09:22:26 -0800 Subject: [PATCH 2333/2333] FROMGIT: wifi: ath11k: Register handler for CFR capture event Firmware sends CFR meta data through the WMI event WMI_PEER_CFR_CAPTURE_EVENT. Parse the meta data coming from the firmware and invoke correlate_and_relay function to correlate the CFR meta data with the CFR payload coming from the other WMI event WMI_PDEV_DMA_RING_BUF_RELEASE_EVENT. Release the buffer to user space once correlate and relay return success. Tested-on: IPQ8074 hw2.0 PCI IPQ8074 WLAN.HK.2.5.0.1-00991-QCAHKSWPL_SILICONZ-1 Tested-on: WCN6855 hw2.1 PCI WLAN.HSP.1.1-04685-QCAHSPSWPL_V1_V2_SILICONZ_IOE-1 Signed-off-by: Venkateswara Naralasetty Co-developed-by: Yu Zhang (Yuriy) Signed-off-by: Yu Zhang (Yuriy) Reviewed-by: Vasanthakumar Thiagarajan Reviewed-by: Baochen Qiang Signed-off-by: Qian Zhang Link: https://patch.msgid.link/20251230082520.3401007-3-qian.zhang@oss.qualcomm.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath11k/cfr.c | 160 ++++++++++++++++++++++++++ drivers/net/wireless/ath/ath11k/cfr.h | 70 ++++++++++- drivers/net/wireless/ath/ath11k/mac.c | 2 + drivers/net/wireless/ath/ath11k/wmi.c | 90 +++++++++++++++ drivers/net/wireless/ath/ath11k/wmi.h | 44 +++++++ 5 files changed, 364 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/cfr.c b/drivers/net/wireless/ath/ath11k/cfr.c index ee7626bd4b1a5..6568edd5d600f 100644 --- a/drivers/net/wireless/ath/ath11k/cfr.c +++ b/drivers/net/wireless/ath/ath11k/cfr.c @@ -252,6 +252,160 @@ static int ath11k_cfr_process_data(struct ath11k *ar, return status; } +static void ath11k_cfr_fill_hdr_info(struct ath11k *ar, + struct ath11k_csi_cfr_header *header, + struct ath11k_cfr_peer_tx_param *params) +{ + struct ath11k_cfr *cfr; + + cfr = &ar->cfr; + header->cfr_metadata_version = ATH11K_CFR_META_VERSION_4; + header->cfr_data_version = ATH11K_CFR_DATA_VERSION_1; + header->cfr_metadata_len = sizeof(struct cfr_metadata); + header->chip_type = ar->ab->hw_rev; + header->meta_data.status = FIELD_GET(WMI_CFR_PEER_CAPTURE_STATUS, + params->status); + header->meta_data.capture_bw = params->bandwidth; + + /* + * FW reports phymode will always be HE mode. + * Replace it with cached phy mode during peer assoc + */ + header->meta_data.phy_mode = cfr->phymode; + + header->meta_data.prim20_chan = params->primary_20mhz_chan; + header->meta_data.center_freq1 = params->band_center_freq1; + header->meta_data.center_freq2 = params->band_center_freq2; + + /* + * CFR capture is triggered by the ACK of a QoS Null frame: + * - 20 MHz: Legacy ACK + * - 40/80/160 MHz: DUP Legacy ACK + */ + header->meta_data.capture_mode = params->bandwidth ? + ATH11K_CFR_CAPTURE_DUP_LEGACY_ACK : ATH11K_CFR_CAPTURE_LEGACY_ACK; + header->meta_data.capture_type = params->capture_method; + header->meta_data.num_rx_chain = ar->num_rx_chains; + header->meta_data.sts_count = params->spatial_streams; + header->meta_data.timestamp = params->timestamp_us; + ether_addr_copy(header->meta_data.peer_addr, params->peer_mac_addr); + memcpy(header->meta_data.chain_rssi, params->chain_rssi, + sizeof(params->chain_rssi)); + memcpy(header->meta_data.chain_phase, params->chain_phase, + sizeof(params->chain_phase)); + memcpy(header->meta_data.agc_gain, params->agc_gain, + sizeof(params->agc_gain)); +} + +int ath11k_process_cfr_capture_event(struct ath11k_base *ab, + struct ath11k_cfr_peer_tx_param *params) +{ + struct ath11k_look_up_table *lut = NULL; + u32 end_magic = ATH11K_CFR_END_MAGIC; + struct ath11k_csi_cfr_header *header; + struct ath11k_dbring_element *buff; + struct ath11k_cfr *cfr; + dma_addr_t buf_addr; + struct ath11k *ar; + u8 tx_status; + int status; + int i; + + rcu_read_lock(); + ar = ath11k_mac_get_ar_by_vdev_id(ab, params->vdev_id); + if (!ar) { + rcu_read_unlock(); + ath11k_warn(ab, "Failed to get ar for vdev id %d\n", + params->vdev_id); + return -ENOENT; + } + + cfr = &ar->cfr; + rcu_read_unlock(); + + if (WMI_CFR_CAPTURE_STATUS_PEER_PS & params->status) { + ath11k_warn(ab, "CFR capture failed as peer %pM is in powersave", + params->peer_mac_addr); + return -EINVAL; + } + + if (!(WMI_CFR_PEER_CAPTURE_STATUS & params->status)) { + ath11k_warn(ab, "CFR capture failed for the peer : %pM", + params->peer_mac_addr); + cfr->tx_peer_status_cfr_fail++; + return -EINVAL; + } + + tx_status = FIELD_GET(WMI_CFR_FRAME_TX_STATUS, params->status); + if (tx_status != WMI_FRAME_TX_STATUS_OK) { + ath11k_warn(ab, "WMI tx status %d for the peer %pM", + tx_status, params->peer_mac_addr); + cfr->tx_evt_status_cfr_fail++; + return -EINVAL; + } + + buf_addr = (((u64)FIELD_GET(WMI_CFR_CORRELATION_INFO2_BUF_ADDR_HIGH, + params->correlation_info_2)) << 32) | + params->correlation_info_1; + + spin_lock_bh(&cfr->lut_lock); + + if (!cfr->lut) { + spin_unlock_bh(&cfr->lut_lock); + return -EINVAL; + } + + for (i = 0; i < cfr->lut_num; i++) { + struct ath11k_look_up_table *temp = &cfr->lut[i]; + + if (temp->dbr_address == buf_addr) { + lut = &cfr->lut[i]; + break; + } + } + + if (!lut) { + spin_unlock_bh(&cfr->lut_lock); + ath11k_warn(ab, "lut failure to process tx event\n"); + cfr->tx_dbr_lookup_fail++; + return -EINVAL; + } + + lut->tx_ppdu_id = FIELD_GET(WMI_CFR_CORRELATION_INFO2_PPDU_ID, + params->correlation_info_2); + lut->txrx_tstamp = jiffies; + + header = &lut->header; + header->start_magic_num = ATH11K_CFR_START_MAGIC; + header->vendorid = VENDOR_QCA; + header->platform_type = PLATFORM_TYPE_ARM; + + ath11k_cfr_fill_hdr_info(ar, header, params); + + status = ath11k_cfr_correlate_and_relay(ar, lut, + ATH11K_CORRELATE_TX_EVENT); + if (status == ATH11K_CORRELATE_STATUS_RELEASE) { + ath11k_dbg(ab, ATH11K_DBG_CFR, + "Releasing CFR data to user space"); + ath11k_cfr_rfs_write(ar, &lut->header, + sizeof(struct ath11k_csi_cfr_header), + lut->data, lut->data_len, + &end_magic, sizeof(u32)); + buff = lut->buff; + ath11k_cfr_release_lut_entry(lut); + + ath11k_dbring_bufs_replenish(ar, &cfr->rx_ring, buff, + WMI_DIRECT_BUF_CFR); + } else if (status == ATH11K_CORRELATE_STATUS_HOLD) { + ath11k_dbg(ab, ATH11K_DBG_CFR, + "dbr event is not yet received holding buf\n"); + } + + spin_unlock_bh(&cfr->lut_lock); + + return 0; +} + /* Helper function to check whether the given peer mac address * is in unassociated peer pool or not. */ @@ -711,6 +865,12 @@ void ath11k_cfr_lut_update_paddr(struct ath11k *ar, dma_addr_t paddr, cfr->lut[buf_id].dbr_address = paddr; } +void ath11k_cfr_update_phymode(struct ath11k *ar, enum wmi_phy_mode phymode) +{ + struct ath11k_cfr *cfr = &ar->cfr; + cfr->phymode = phymode; +} + static void ath11k_cfr_ring_free(struct ath11k *ar) { struct ath11k_cfr *cfr = &ar->cfr; diff --git a/drivers/net/wireless/ath/ath11k/cfr.h b/drivers/net/wireless/ath/ath11k/cfr.h index c8e5086674d28..94fcb706f2ef2 100644 --- a/drivers/net/wireless/ath/ath11k/cfr.h +++ b/drivers/net/wireless/ath/ath11k/cfr.h @@ -27,8 +27,37 @@ enum ath11k_cfr_correlate_event_type { struct ath11k_sta; struct ath11k_per_peer_cfr_capture; +#define ATH11K_CFR_START_MAGIC 0xDEADBEAF #define ATH11K_CFR_END_MAGIC 0xBEAFDEAD +#define VENDOR_QCA 0x8cfdf0 +#define PLATFORM_TYPE_ARM 2 + +enum ath11k_cfr_meta_version { + ATH11K_CFR_META_VERSION_NONE, + ATH11K_CFR_META_VERSION_1, + ATH11K_CFR_META_VERSION_2, + ATH11K_CFR_META_VERSION_3, + ATH11K_CFR_META_VERSION_4, + ATH11K_CFR_META_VERSION_MAX = 0xFF, +}; + +enum ath11k_cfr_data_version { + ATH11K_CFR_DATA_VERSION_NONE, + ATH11K_CFR_DATA_VERSION_1, + ATH11K_CFR_DATA_VERSION_MAX = 0xFF, +}; + +enum ath11k_cfr_capture_ack_mode { + ATH11K_CFR_CAPTURE_LEGACY_ACK, + ATH11K_CFR_CAPTURE_DUP_LEGACY_ACK, + ATH11K_CFR_CAPTURE_HT_ACK, + ATH11K_CFR_CAPTURE_VHT_ACK, + + /*Always keep this at last*/ + ATH11K_CFR_CAPTURE_INVALID_ACK +}; + enum ath11k_cfr_correlate_status { ATH11K_CORRELATE_STATUS_RELEASE, ATH11K_CORRELATE_STATUS_HOLD, @@ -41,6 +70,28 @@ enum ath11k_cfr_preamble_type { ATH11K_CFR_PREAMBLE_TYPE_VHT, }; +struct ath11k_cfr_peer_tx_param { + u32 capture_method; + u32 vdev_id; + u8 peer_mac_addr[ETH_ALEN]; + u32 primary_20mhz_chan; + u32 bandwidth; + u32 phy_mode; + u32 band_center_freq1; + u32 band_center_freq2; + u32 spatial_streams; + u32 correlation_info_1; + u32 correlation_info_2; + u32 status; + u32 timestamp_us; + u32 counter; + u32 chain_rssi[WMI_MAX_CHAINS]; + u16 chain_phase[WMI_MAX_CHAINS]; + u32 cfo_measurement; + u8 agc_gain[HOST_MAX_CHAINS]; + u32 rx_start_ts; +}; + struct cfr_metadata { u8 peer_addr[ETH_ALEN]; u8 status; @@ -70,7 +121,7 @@ struct ath11k_csi_cfr_header { u8 cfr_data_version; u8 chip_type; u8 platform_type; - u32 reserved; + u32 cfr_metadata_len; struct cfr_metadata meta_data; } __packed; @@ -144,6 +195,7 @@ struct ath11k_cfr { u64 clear_txrx_event; u64 cfr_dma_aborts; bool enabled; + enum wmi_phy_mode phymode; struct cfr_unassoc_pool_entry unassoc_pool[ATH11K_MAX_CFR_ENABLED_CLIENTS]; }; @@ -181,8 +233,15 @@ int ath11k_cfr_send_peer_cfr_capture_cmd(struct ath11k *ar, const u8 *peer_mac); struct ath11k_dbring *ath11k_cfr_get_dbring(struct ath11k *ar); void ath11k_cfr_release_lut_entry(struct ath11k_look_up_table *lut); - +int ath11k_process_cfr_capture_event(struct ath11k_base *ab, + struct ath11k_cfr_peer_tx_param *params); +void ath11k_cfr_update_phymode(struct ath11k *ar, enum wmi_phy_mode phymode); #else +static inline void ath11k_cfr_update_phymode(struct ath11k *ar, + enum wmi_phy_mode phymode) +{ +} + static inline int ath11k_cfr_init(struct ath11k_base *ab) { return 0; @@ -238,5 +297,12 @@ struct ath11k_dbring *ath11k_cfr_get_dbring(struct ath11k *ar) { return NULL; } + +static inline +int ath11k_process_cfr_capture_event(struct ath11k_base *ab, + struct ath11k_cfr_peer_tx_param *params) +{ + return 0; +} #endif /* CONFIG_ATH11K_CFR */ #endif /* ATH11K_CFR_H */ diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index 3a80b351083f4..861d83b976e08 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -2911,6 +2911,8 @@ static void ath11k_peer_assoc_h_phymode(struct ath11k *ar, arg->peer_phymode = phymode; WARN_ON(phymode == MODE_UNKNOWN); + + ath11k_cfr_update_phymode(ar, phymode); } static void ath11k_peer_assoc_prepare(struct ath11k *ar, diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c index b40a31414a471..451cc4c719aec 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.c +++ b/drivers/net/wireless/ath/ath11k/wmi.c @@ -8805,6 +8805,93 @@ static void ath11k_wmi_p2p_noa_event(struct ath11k_base *ab, kfree(tb); } +static void ath11k_wmi_tlv_cfr_capture_event_fixed_param(const void *ptr, + void *data) +{ + struct ath11k_cfr_peer_tx_param *tx_params = data; + const struct ath11k_wmi_cfr_peer_tx_event_param *params = ptr; + + tx_params->capture_method = params->capture_method; + tx_params->vdev_id = params->vdev_id; + ether_addr_copy(tx_params->peer_mac_addr, params->mac_addr.addr); + tx_params->primary_20mhz_chan = params->chan_mhz; + tx_params->bandwidth = params->bandwidth; + tx_params->phy_mode = params->phy_mode; + tx_params->band_center_freq1 = params->band_center_freq1; + tx_params->band_center_freq2 = params->band_center_freq2; + tx_params->spatial_streams = params->sts_count; + tx_params->correlation_info_1 = params->correlation_info_1; + tx_params->correlation_info_2 = params->correlation_info_2; + tx_params->status = params->status; + tx_params->timestamp_us = params->timestamp_us; + tx_params->counter = params->counter; + tx_params->rx_start_ts = params->rx_start_ts; + + memcpy(tx_params->chain_rssi, params->chain_rssi, + sizeof(tx_params->chain_rssi)); + + if (WMI_CFR_CFO_MEASUREMENT_VALID & params->cfo_measurement) + tx_params->cfo_measurement = FIELD_GET(WMI_CFR_CFO_MEASUREMENT_RAW_DATA, + params->cfo_measurement); +} + +static void ath11k_wmi_tlv_cfr_capture_phase_fixed_param(const void *ptr, + void *data) +{ + struct ath11k_cfr_peer_tx_param *tx_params = data; + const struct ath11k_wmi_cfr_peer_tx_event_phase_param *params = ptr; + int i; + + for (i = 0; i < WMI_MAX_CHAINS; i++) { + tx_params->chain_phase[i] = params->chain_phase[i]; + tx_params->agc_gain[i] = params->agc_gain[i]; + } +} + +static int ath11k_wmi_tlv_cfr_capture_evt_parse(struct ath11k_base *ab, + u16 tag, u16 len, + const void *ptr, void *data) +{ + switch (tag) { + case WMI_TAG_PEER_CFR_CAPTURE_EVENT: + ath11k_wmi_tlv_cfr_capture_event_fixed_param(ptr, data); + break; + case WMI_TAG_CFR_CAPTURE_PHASE_PARAM: + ath11k_wmi_tlv_cfr_capture_phase_fixed_param(ptr, data); + break; + default: + ath11k_warn(ab, "Invalid tag received tag %d len %d\n", + tag, len); + return -EINVAL; + } + + return 0; +} + +static void ath11k_wmi_parse_cfr_capture_event(struct ath11k_base *ab, + struct sk_buff *skb) +{ + struct ath11k_cfr_peer_tx_param params = {}; + int ret; + + ath11k_dbg_dump(ab, ATH11K_DBG_CFR_DUMP, "cfr_dump:", "", + skb->data, skb->len); + + ret = ath11k_wmi_tlv_iter(ab, skb->data, skb->len, + ath11k_wmi_tlv_cfr_capture_evt_parse, + ¶ms); + if (ret) { + ath11k_warn(ab, "failed to parse cfr capture event tlv %d\n", + ret); + return; + } + + ret = ath11k_process_cfr_capture_event(ab, ¶ms); + if (ret) + ath11k_dbg(ab, ATH11K_DBG_CFR, + "failed to process cfr capture ret = %d\n", ret); +} + static void ath11k_wmi_tlv_op_rx(struct ath11k_base *ab, struct sk_buff *skb) { struct wmi_cmd_hdr *cmd_hdr; @@ -8935,6 +9022,9 @@ static void ath11k_wmi_tlv_op_rx(struct ath11k_base *ab, struct sk_buff *skb) case WMI_P2P_NOA_EVENTID: ath11k_wmi_p2p_noa_event(ab, skb); break; + case WMI_PEER_CFR_CAPTURE_EVENTID: + ath11k_wmi_parse_cfr_capture_event(ab, skb); + break; default: ath11k_dbg(ab, ATH11K_DBG_WMI, "unsupported event id 0x%x\n", id); break; diff --git a/drivers/net/wireless/ath/ath11k/wmi.h b/drivers/net/wireless/ath/ath11k/wmi.h index 0c80d99e464d4..24b8f867c60dc 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.h +++ b/drivers/net/wireless/ath/ath11k/wmi.h @@ -1889,6 +1889,8 @@ enum wmi_tlv_tag { WMI_TAG_NDP_EVENT, WMI_TAG_PDEV_PEER_PKTLOG_FILTER_CMD = 0x301, WMI_TAG_PDEV_PEER_PKTLOG_FILTER_INFO, + WMI_TAG_PEER_CFR_CAPTURE_EVENT = 0x317, + WMI_TAG_CFR_CAPTURE_PHASE_PARAM = 0x33b, WMI_TAG_FILS_DISCOVERY_TMPL_CMD = 0x344, WMI_TAG_PDEV_SRG_BSS_COLOR_BITMAP_CMD = 0x37b, WMI_TAG_PDEV_SRG_PARTIAL_BSSID_BITMAP_CMD, @@ -4251,6 +4253,48 @@ enum ath11k_wmi_cfr_capture_method { WMI_CFR_CAPTURE_METHOD_MAX, }; +#define WMI_CFR_FRAME_TX_STATUS GENMASK(1, 0) +#define WMI_CFR_CAPTURE_STATUS_PEER_PS BIT(30) +#define WMI_CFR_PEER_CAPTURE_STATUS BIT(31) + +#define WMI_CFR_CORRELATION_INFO2_BUF_ADDR_HIGH GENMASK(3, 0) +#define WMI_CFR_CORRELATION_INFO2_PPDU_ID GENMASK(31, 16) + +#define WMI_CFR_CFO_MEASUREMENT_VALID BIT(0) +#define WMI_CFR_CFO_MEASUREMENT_RAW_DATA GENMASK(14, 1) + +struct ath11k_wmi_cfr_peer_tx_event_param { + u32 capture_method; + u32 vdev_id; + struct wmi_mac_addr mac_addr; + u32 chan_mhz; + u32 bandwidth; + u32 phy_mode; + u32 band_center_freq1; + u32 band_center_freq2; + u32 sts_count; + u32 correlation_info_1; + u32 correlation_info_2; + u32 status; + u32 timestamp_us; + u32 counter; + u32 chain_rssi[WMI_MAX_CHAINS]; + u32 cfo_measurement; + u32 rx_start_ts; +} __packed; + +struct ath11k_wmi_cfr_peer_tx_event_phase_param { + u32 chain_phase[WMI_MAX_CHAINS]; + u8 agc_gain[WMI_MAX_CHAINS]; +} __packed; + +enum ath11k_wmi_frame_tx_status { + WMI_FRAME_TX_STATUS_OK, + WMI_FRAME_TX_STATUS_XRETRY, + WMI_FRAME_TX_STATUS_DROP, + WMI_FRAME_TX_STATUS_FILTERED, +}; + struct wmi_peer_cfr_capture_conf_arg { enum ath11k_wmi_cfr_capture_bw bw; enum ath11k_wmi_cfr_capture_method method;