From: Sasha Levin Date: Sat, 3 Aug 2024 14:48:12 +0000 (-0400) Subject: Fixes for 6.1 X-Git-Tag: v6.1.104~32 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=386a373fb4e022276017842cdf1b82346f6885b4;p=thirdparty%2Fkernel%2Fstable-queue.git Fixes for 6.1 Signed-off-by: Sasha Levin --- diff --git a/queue-6.1/arm64-dts-qcom-ipq8074-disable-ss-instance-in-parkmo.patch b/queue-6.1/arm64-dts-qcom-ipq8074-disable-ss-instance-in-parkmo.patch new file mode 100644 index 00000000000..b6ac113e2e1 --- /dev/null +++ b/queue-6.1/arm64-dts-qcom-ipq8074-disable-ss-instance-in-parkmo.patch @@ -0,0 +1,53 @@ +From ad6522cb8844d205f3f16fa111f7857900599149 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Jul 2024 20:58:42 +0530 +Subject: arm64: dts: qcom: ipq8074: Disable SS instance in Parkmode for USB + +From: Krishna Kurapati + +[ Upstream commit dc6ba95c6c4400a84cca5b419b34ae852a08cfb5 ] + +For Gen-1 targets like IPQ8074, it is seen that stressing out the +controller in host mode results in HC died error: + + xhci-hcd.12.auto: xHCI host not responding to stop endpoint command + xhci-hcd.12.auto: xHCI host controller not responding, assume dead + xhci-hcd.12.auto: HC died; cleaning up + +And at this instant only restarting the host mode fixes it. Disable +SuperSpeed instance in park mode for IPQ8074 to mitigate this issue. + +Cc: stable@vger.kernel.org +Fixes: 5e09bc51d07b ("arm64: dts: ipq8074: enable USB support") +Signed-off-by: Krishna Kurapati +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20240704152848.3380602-3-quic_kriskura@quicinc.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/ipq8074.dtsi | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/arch/arm64/boot/dts/qcom/ipq8074.dtsi b/arch/arm64/boot/dts/qcom/ipq8074.dtsi +index 3d8e5ba51ce0d..2f53c099634b5 100644 +--- a/arch/arm64/boot/dts/qcom/ipq8074.dtsi ++++ b/arch/arm64/boot/dts/qcom/ipq8074.dtsi +@@ -593,6 +593,7 @@ dwc_0: usb@8a00000 { + interrupts = ; + phys = <&qusb_phy_0>, <&usb0_ssphy>; + phy-names = "usb2-phy", "usb3-phy"; ++ snps,parkmode-disable-ss-quirk; + snps,is-utmi-l1-suspend; + snps,hird-threshold = /bits/ 8 <0x0>; + snps,dis_u2_susphy_quirk; +@@ -635,6 +636,7 @@ dwc_1: usb@8c00000 { + interrupts = ; + phys = <&qusb_phy_1>, <&usb1_ssphy>; + phy-names = "usb2-phy", "usb3-phy"; ++ snps,parkmode-disable-ss-quirk; + snps,is-utmi-l1-suspend; + snps,hird-threshold = /bits/ 8 <0x0>; + snps,dis_u2_susphy_quirk; +-- +2.43.0 + diff --git a/queue-6.1/arm64-dts-qcom-msm8998-disable-ss-instance-in-parkmo.patch b/queue-6.1/arm64-dts-qcom-msm8998-disable-ss-instance-in-parkmo.patch new file mode 100644 index 00000000000..42d9395f7a5 --- /dev/null +++ b/queue-6.1/arm64-dts-qcom-msm8998-disable-ss-instance-in-parkmo.patch @@ -0,0 +1,45 @@ +From 55dfc71f98c390ee4a3d5ce0eea51b6893a3c7ef Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Jul 2024 20:58:43 +0530 +Subject: arm64: dts: qcom: msm8998: Disable SS instance in Parkmode for USB + +From: Krishna Kurapati + +[ Upstream commit 0046325ae52079b46da13a7f84dd7b2a6f7c38f8 ] + +For Gen-1 targets like MSM8998, it is seen that stressing out the +controller in host mode results in HC died error: + + xhci-hcd.12.auto: xHCI host not responding to stop endpoint command + xhci-hcd.12.auto: xHCI host controller not responding, assume dead + xhci-hcd.12.auto: HC died; cleaning up + +And at this instant only restarting the host mode fixes it. Disable +SuperSpeed instance in park mode for MSM8998 to mitigate this issue. + +Cc: stable@vger.kernel.org +Fixes: 026dad8f5873 ("arm64: dts: qcom: msm8998: Add USB-related nodes") +Signed-off-by: Krishna Kurapati +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20240704152848.3380602-4-quic_kriskura@quicinc.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/msm8998.dtsi | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/arm64/boot/dts/qcom/msm8998.dtsi b/arch/arm64/boot/dts/qcom/msm8998.dtsi +index c19fb8ae2da2a..4de9ff045ff52 100644 +--- a/arch/arm64/boot/dts/qcom/msm8998.dtsi ++++ b/arch/arm64/boot/dts/qcom/msm8998.dtsi +@@ -2029,6 +2029,7 @@ usb3_dwc3: usb@a800000 { + interrupts = ; + snps,dis_u2_susphy_quirk; + snps,dis_enblslpm_quirk; ++ snps,parkmode-disable-ss-quirk; + phys = <&qusb2phy>, <&usb3phy>; + phy-names = "usb2-phy", "usb3-phy"; + snps,has-lpm-erratum; +-- +2.43.0 + diff --git a/queue-6.1/arm64-dts-qcom-msm8998-switch-usb-qmp-phy-to-new-sty.patch b/queue-6.1/arm64-dts-qcom-msm8998-switch-usb-qmp-phy-to-new-sty.patch new file mode 100644 index 00000000000..1dd2ab4d915 --- /dev/null +++ b/queue-6.1/arm64-dts-qcom-msm8998-switch-usb-qmp-phy-to-new-sty.patch @@ -0,0 +1,85 @@ +From 66b93700e98677fef7b62e72aa31d617829a1d58 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 25 Aug 2023 00:19:46 +0300 +Subject: arm64: dts: qcom: msm8998: switch USB QMP PHY to new style of + bindings + +From: Dmitry Baryshkov + +[ Upstream commit b7efebfeb2e8ad8187cdabba5f0212ba2e6c1069 ] + +Change the USB QMP PHY to use newer style of QMP PHY bindings (single +resource region, no per-PHY subnodes). + +Signed-off-by: Dmitry Baryshkov +Link: https://lore.kernel.org/r/20230824211952.1397699-11-dmitry.baryshkov@linaro.org +Signed-off-by: Bjorn Andersson +Stable-dep-of: 0046325ae520 ("arm64: dts: qcom: msm8998: Disable SS instance in Parkmode for USB") +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/msm8998.dtsi | 35 +++++++++++---------------- + 1 file changed, 14 insertions(+), 21 deletions(-) + +diff --git a/arch/arm64/boot/dts/qcom/msm8998.dtsi b/arch/arm64/boot/dts/qcom/msm8998.dtsi +index 3d4941dc31d74..c19fb8ae2da2a 100644 +--- a/arch/arm64/boot/dts/qcom/msm8998.dtsi ++++ b/arch/arm64/boot/dts/qcom/msm8998.dtsi +@@ -2029,7 +2029,7 @@ usb3_dwc3: usb@a800000 { + interrupts = ; + snps,dis_u2_susphy_quirk; + snps,dis_enblslpm_quirk; +- phys = <&qusb2phy>, <&usb1_ssphy>; ++ phys = <&qusb2phy>, <&usb3phy>; + phy-names = "usb2-phy", "usb3-phy"; + snps,has-lpm-erratum; + snps,hird-threshold = /bits/ 8 <0x10>; +@@ -2038,33 +2038,26 @@ usb3_dwc3: usb@a800000 { + + usb3phy: phy@c010000 { + compatible = "qcom,msm8998-qmp-usb3-phy"; +- reg = <0x0c010000 0x18c>; +- status = "disabled"; +- #address-cells = <1>; +- #size-cells = <1>; +- ranges; ++ reg = <0x0c010000 0x1000>; + + clocks = <&gcc GCC_USB3_PHY_AUX_CLK>, ++ <&gcc GCC_USB3_CLKREF_CLK>, + <&gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>, +- <&gcc GCC_USB3_CLKREF_CLK>; +- clock-names = "aux", "cfg_ahb", "ref"; ++ <&gcc GCC_USB3_PHY_PIPE_CLK>; ++ clock-names = "aux", ++ "ref", ++ "cfg_ahb", ++ "pipe"; ++ clock-output-names = "usb3_phy_pipe_clk_src"; ++ #clock-cells = <0>; ++ #phy-cells = <0>; + + resets = <&gcc GCC_USB3_PHY_BCR>, + <&gcc GCC_USB3PHY_PHY_BCR>; +- reset-names = "phy", "common"; ++ reset-names = "phy", ++ "phy_phy"; + +- usb1_ssphy: phy@c010200 { +- reg = <0xc010200 0x128>, +- <0xc010400 0x200>, +- <0xc010c00 0x20c>, +- <0xc010600 0x128>, +- <0xc010800 0x200>; +- #phy-cells = <0>; +- #clock-cells = <0>; +- clocks = <&gcc GCC_USB3_PHY_PIPE_CLK>; +- clock-names = "pipe0"; +- clock-output-names = "usb3_phy_pipe_clk_src"; +- }; ++ status = "disabled"; + }; + + qusb2phy: phy@c012000 { +-- +2.43.0 + diff --git a/queue-6.1/cpufreq-qcom-nvmem-convert-to-platform-remove-callba.patch b/queue-6.1/cpufreq-qcom-nvmem-convert-to-platform-remove-callba.patch new file mode 100644 index 00000000000..2c60ef58d74 --- /dev/null +++ b/queue-6.1/cpufreq-qcom-nvmem-convert-to-platform-remove-callba.patch @@ -0,0 +1,64 @@ +From 7c36ec163d96c4d00ff210fd15cdf8f369e1429f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 12 Jul 2023 17:33:18 +0800 +Subject: cpufreq: qcom-nvmem: Convert to platform remove callback returning + void +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Yangtao Li + +[ Upstream commit 402732324b17a31f7e5dce9659d1b1f049fd65d3 ] + +The .remove() callback for a platform driver returns an int which makes +many driver authors wrongly assume it's possible to do error handling by +returning an error code. However the value returned is (mostly) ignored +and this typically results in resource leaks. To improve here there is a +quest to make the remove callback return void. In the first step of this +quest all drivers are converted to .remove_new() which already returns +void. + +Trivially convert this driver from always returning zero in the remove +callback to the void returning variant. + +Cc: Uwe Kleine-König +Signed-off-by: Yangtao Li +Signed-off-by: Viresh Kumar +Stable-dep-of: d01c84b97f19 ("cpufreq: qcom-nvmem: fix memory leaks in probe error paths") +Signed-off-by: Sasha Levin +--- + drivers/cpufreq/qcom-cpufreq-nvmem.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/drivers/cpufreq/qcom-cpufreq-nvmem.c b/drivers/cpufreq/qcom-cpufreq-nvmem.c +index cb03bfb0435ea..91634b84baa87 100644 +--- a/drivers/cpufreq/qcom-cpufreq-nvmem.c ++++ b/drivers/cpufreq/qcom-cpufreq-nvmem.c +@@ -374,7 +374,7 @@ static int qcom_cpufreq_probe(struct platform_device *pdev) + return ret; + } + +-static int qcom_cpufreq_remove(struct platform_device *pdev) ++static void qcom_cpufreq_remove(struct platform_device *pdev) + { + struct qcom_cpufreq_drv *drv = platform_get_drvdata(pdev); + unsigned int cpu; +@@ -386,13 +386,11 @@ static int qcom_cpufreq_remove(struct platform_device *pdev) + + kfree(drv->opp_tokens); + kfree(drv); +- +- return 0; + } + + static struct platform_driver qcom_cpufreq_driver = { + .probe = qcom_cpufreq_probe, +- .remove = qcom_cpufreq_remove, ++ .remove_new = qcom_cpufreq_remove, + .driver = { + .name = "qcom-cpufreq-nvmem", + }, +-- +2.43.0 + diff --git a/queue-6.1/cpufreq-qcom-nvmem-fix-memory-leaks-in-probe-error-p.patch b/queue-6.1/cpufreq-qcom-nvmem-fix-memory-leaks-in-probe-error-p.patch new file mode 100644 index 00000000000..b6b44305d57 --- /dev/null +++ b/queue-6.1/cpufreq-qcom-nvmem-fix-memory-leaks-in-probe-error-p.patch @@ -0,0 +1,65 @@ +From 686316ae33c275ffc1e8e209b221e11a2492d227 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 May 2024 23:24:59 +0200 +Subject: cpufreq: qcom-nvmem: fix memory leaks in probe error paths + +From: Javier Carrasco + +[ Upstream commit d01c84b97f19f1137211e90b0a910289a560019e ] + +The code refactoring added new error paths between the np device node +allocation and the call to of_node_put(), which leads to memory leaks if +any of those errors occur. + +Add the missing of_node_put() in the error paths that require it. + +Cc: stable@vger.kernel.org +Fixes: 57f2f8b4aa0c ("cpufreq: qcom: Refactor the driver to make it easier to extend") +Signed-off-by: Javier Carrasco +Signed-off-by: Viresh Kumar +Signed-off-by: Sasha Levin +--- + drivers/cpufreq/qcom-cpufreq-nvmem.c | 13 ++++++++++--- + 1 file changed, 10 insertions(+), 3 deletions(-) + +diff --git a/drivers/cpufreq/qcom-cpufreq-nvmem.c b/drivers/cpufreq/qcom-cpufreq-nvmem.c +index 983991c0afd5c..2edb66097cdb9 100644 +--- a/drivers/cpufreq/qcom-cpufreq-nvmem.c ++++ b/drivers/cpufreq/qcom-cpufreq-nvmem.c +@@ -290,23 +290,30 @@ static int qcom_cpufreq_probe(struct platform_device *pdev) + + drv = devm_kzalloc(&pdev->dev, struct_size(drv, cpus, num_possible_cpus()), + GFP_KERNEL); +- if (!drv) ++ if (!drv) { ++ of_node_put(np); + return -ENOMEM; ++ } + + match = pdev->dev.platform_data; + drv->data = match->data; +- if (!drv->data) ++ if (!drv->data) { ++ of_node_put(np); + return -ENODEV; ++ } + + if (drv->data->get_version) { + speedbin_nvmem = of_nvmem_cell_get(np, NULL); +- if (IS_ERR(speedbin_nvmem)) ++ if (IS_ERR(speedbin_nvmem)) { ++ of_node_put(np); + return dev_err_probe(cpu_dev, PTR_ERR(speedbin_nvmem), + "Could not get nvmem cell\n"); ++ } + + ret = drv->data->get_version(cpu_dev, + speedbin_nvmem, &pvs_name, drv); + if (ret) { ++ of_node_put(np); + nvmem_cell_put(speedbin_nvmem); + return ret; + } +-- +2.43.0 + diff --git a/queue-6.1/cpufreq-qcom-nvmem-simplify-driver-data-allocation.patch b/queue-6.1/cpufreq-qcom-nvmem-simplify-driver-data-allocation.patch new file mode 100644 index 00000000000..6f85c18938a --- /dev/null +++ b/queue-6.1/cpufreq-qcom-nvmem-simplify-driver-data-allocation.patch @@ -0,0 +1,135 @@ +From c4ebe3ac348552471d25a8edb1ea0b8df6aaf730 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Oct 2023 10:06:02 +0200 +Subject: cpufreq: qcom-nvmem: Simplify driver data allocation + +From: Stephan Gerhold + +[ Upstream commit 2a5d46c3ad6b0e62d2b04356ad999d504fb564e0 ] + +Simplify the allocation and cleanup of driver data by using devm +together with a flexible array. Prepare for adding additional per-CPU +data by defining a struct qcom_cpufreq_drv_cpu instead of storing the +opp_tokens directly. + +Signed-off-by: Stephan Gerhold +Reviewed-by: Konrad Dybcio +Signed-off-by: Viresh Kumar +Stable-dep-of: d01c84b97f19 ("cpufreq: qcom-nvmem: fix memory leaks in probe error paths") +Signed-off-by: Sasha Levin +--- + drivers/cpufreq/qcom-cpufreq-nvmem.c | 49 ++++++++++------------------ + 1 file changed, 18 insertions(+), 31 deletions(-) + +diff --git a/drivers/cpufreq/qcom-cpufreq-nvmem.c b/drivers/cpufreq/qcom-cpufreq-nvmem.c +index 91634b84baa87..983991c0afd5c 100644 +--- a/drivers/cpufreq/qcom-cpufreq-nvmem.c ++++ b/drivers/cpufreq/qcom-cpufreq-nvmem.c +@@ -53,10 +53,14 @@ struct qcom_cpufreq_match_data { + const char **genpd_names; + }; + ++struct qcom_cpufreq_drv_cpu { ++ int opp_token; ++}; ++ + struct qcom_cpufreq_drv { +- int *opp_tokens; + u32 versions; + const struct qcom_cpufreq_match_data *data; ++ struct qcom_cpufreq_drv_cpu cpus[]; + }; + + static struct platform_device *cpufreq_dt_pdev, *cpufreq_pdev; +@@ -284,42 +288,32 @@ static int qcom_cpufreq_probe(struct platform_device *pdev) + return -ENOENT; + } + +- drv = kzalloc(sizeof(*drv), GFP_KERNEL); ++ drv = devm_kzalloc(&pdev->dev, struct_size(drv, cpus, num_possible_cpus()), ++ GFP_KERNEL); + if (!drv) + return -ENOMEM; + + match = pdev->dev.platform_data; + drv->data = match->data; +- if (!drv->data) { +- ret = -ENODEV; +- goto free_drv; +- } ++ if (!drv->data) ++ return -ENODEV; + + if (drv->data->get_version) { + speedbin_nvmem = of_nvmem_cell_get(np, NULL); +- if (IS_ERR(speedbin_nvmem)) { +- ret = dev_err_probe(cpu_dev, PTR_ERR(speedbin_nvmem), +- "Could not get nvmem cell\n"); +- goto free_drv; +- } ++ if (IS_ERR(speedbin_nvmem)) ++ return dev_err_probe(cpu_dev, PTR_ERR(speedbin_nvmem), ++ "Could not get nvmem cell\n"); + + ret = drv->data->get_version(cpu_dev, + speedbin_nvmem, &pvs_name, drv); + if (ret) { + nvmem_cell_put(speedbin_nvmem); +- goto free_drv; ++ return ret; + } + nvmem_cell_put(speedbin_nvmem); + } + of_node_put(np); + +- drv->opp_tokens = kcalloc(num_possible_cpus(), sizeof(*drv->opp_tokens), +- GFP_KERNEL); +- if (!drv->opp_tokens) { +- ret = -ENOMEM; +- goto free_drv; +- } +- + for_each_possible_cpu(cpu) { + struct dev_pm_opp_config config = { + .supported_hw = NULL, +@@ -345,9 +339,9 @@ static int qcom_cpufreq_probe(struct platform_device *pdev) + } + + if (config.supported_hw || config.genpd_names) { +- drv->opp_tokens[cpu] = dev_pm_opp_set_config(cpu_dev, &config); +- if (drv->opp_tokens[cpu] < 0) { +- ret = drv->opp_tokens[cpu]; ++ drv->cpus[cpu].opp_token = dev_pm_opp_set_config(cpu_dev, &config); ++ if (drv->cpus[cpu].opp_token < 0) { ++ ret = drv->cpus[cpu].opp_token; + dev_err(cpu_dev, "Failed to set OPP config\n"); + goto free_opp; + } +@@ -366,11 +360,7 @@ static int qcom_cpufreq_probe(struct platform_device *pdev) + + free_opp: + for_each_possible_cpu(cpu) +- dev_pm_opp_clear_config(drv->opp_tokens[cpu]); +- kfree(drv->opp_tokens); +-free_drv: +- kfree(drv); +- ++ dev_pm_opp_clear_config(drv->cpus[cpu].opp_token); + return ret; + } + +@@ -382,10 +372,7 @@ static void qcom_cpufreq_remove(struct platform_device *pdev) + platform_device_unregister(cpufreq_dt_pdev); + + for_each_possible_cpu(cpu) +- dev_pm_opp_clear_config(drv->opp_tokens[cpu]); +- +- kfree(drv->opp_tokens); +- kfree(drv); ++ dev_pm_opp_clear_config(drv->cpus[cpu].opp_token); + } + + static struct platform_driver qcom_cpufreq_driver = { +-- +2.43.0 + diff --git a/queue-6.1/drm-i915-dp-don-t-switch-the-lttpr-mode-on-an-active.patch b/queue-6.1/drm-i915-dp-don-t-switch-the-lttpr-mode-on-an-active.patch new file mode 100644 index 00000000000..3a799a62066 --- /dev/null +++ b/queue-6.1/drm-i915-dp-don-t-switch-the-lttpr-mode-on-an-active.patch @@ -0,0 +1,134 @@ +From d239c5bf3eec4d7d87800fd37803960aa613f5b6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 8 Jul 2024 22:00:25 +0300 +Subject: drm/i915/dp: Don't switch the LTTPR mode on an active link +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Imre Deak + +[ Upstream commit 509580fad7323b6a5da27e8365cd488f3b57210e ] + +Switching to transparent mode leads to a loss of link synchronization, +so prevent doing this on an active link. This happened at least on an +Intel N100 system / DELL UD22 dock, the LTTPR residing either on the +host or the dock. To fix the issue, keep the current mode on an active +link, adjusting the LTTPR count accordingly (resetting it to 0 in +transparent mode). + +v2: Adjust code comment during link training about reiniting the LTTPRs. + (Ville) + +Fixes: 7b2a4ab8b0ef ("drm/i915: Switch to LTTPR transparent mode link training") +Reported-and-tested-by: Gareth Yu +Closes: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/10902 +Cc: # v5.15+ +Cc: Ville Syrjälä +Reviewed-by: Ville Syrjälä +Reviewed-by: Ankit Nautiyal +Signed-off-by: Imre Deak +Link: https://patchwork.freedesktop.org/patch/msgid/20240708190029.271247-3-imre.deak@intel.com +(cherry picked from commit 211ad49cf8ccfdc798a719b4d1e000d0a8a9e588) +Signed-off-by: Tvrtko Ursulin +Signed-off-by: Sasha Levin +--- + .../drm/i915/display/intel_dp_link_training.c | 54 ++++++++++++++++--- + 1 file changed, 48 insertions(+), 6 deletions(-) + +diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.c b/drivers/gpu/drm/i915/display/intel_dp_link_training.c +index 3d3efcf02011e..1d9e4534287bb 100644 +--- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c ++++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c +@@ -103,12 +103,26 @@ intel_dp_set_lttpr_transparent_mode(struct intel_dp *intel_dp, bool enable) + return drm_dp_dpcd_write(&intel_dp->aux, DP_PHY_REPEATER_MODE, &val, 1) == 1; + } + +-static int intel_dp_init_lttpr(struct intel_dp *intel_dp, const u8 dpcd[DP_RECEIVER_CAP_SIZE]) ++static bool intel_dp_lttpr_transparent_mode_enabled(struct intel_dp *intel_dp) ++{ ++ return intel_dp->lttpr_common_caps[DP_PHY_REPEATER_MODE - ++ DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV] == ++ DP_PHY_REPEATER_MODE_TRANSPARENT; ++} ++ ++/* ++ * Read the LTTPR common capabilities and switch the LTTPR PHYs to ++ * non-transparent mode if this is supported. Preserve the ++ * transparent/non-transparent mode on an active link. ++ * ++ * Return the number of detected LTTPRs in non-transparent mode or 0 if the ++ * LTTPRs are in transparent mode or the detection failed. ++ */ ++static int intel_dp_init_lttpr_phys(struct intel_dp *intel_dp, const u8 dpcd[DP_RECEIVER_CAP_SIZE]) + { + struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base; + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + int lttpr_count; +- int i; + + if (!intel_dp_read_lttpr_common_caps(intel_dp, dpcd)) + return 0; +@@ -122,6 +136,19 @@ static int intel_dp_init_lttpr(struct intel_dp *intel_dp, const u8 dpcd[DP_RECEI + if (lttpr_count == 0) + return 0; + ++ /* ++ * Don't change the mode on an active link, to prevent a loss of link ++ * synchronization. See DP Standard v2.0 3.6.7. about the LTTPR ++ * resetting its internal state when the mode is changed from ++ * non-transparent to transparent. ++ */ ++ if (intel_dp->link_trained) { ++ if (lttpr_count < 0 || intel_dp_lttpr_transparent_mode_enabled(intel_dp)) ++ goto out_reset_lttpr_count; ++ ++ return lttpr_count; ++ } ++ + /* + * See DP Standard v2.0 3.6.6.1. about the explicit disabling of + * non-transparent mode and the disable->enable non-transparent mode +@@ -143,11 +170,25 @@ static int intel_dp_init_lttpr(struct intel_dp *intel_dp, const u8 dpcd[DP_RECEI + encoder->base.base.id, encoder->base.name); + + intel_dp_set_lttpr_transparent_mode(intel_dp, true); +- intel_dp_reset_lttpr_count(intel_dp); + +- return 0; ++ goto out_reset_lttpr_count; + } + ++ return lttpr_count; ++ ++out_reset_lttpr_count: ++ intel_dp_reset_lttpr_count(intel_dp); ++ ++ return 0; ++} ++ ++static int intel_dp_init_lttpr(struct intel_dp *intel_dp, const u8 dpcd[DP_RECEIVER_CAP_SIZE]) ++{ ++ int lttpr_count; ++ int i; ++ ++ lttpr_count = intel_dp_init_lttpr_phys(intel_dp, dpcd); ++ + for (i = 0; i < lttpr_count; i++) + intel_dp_read_lttpr_phy_caps(intel_dp, dpcd, DP_PHY_LTTPR(i)); + +@@ -1435,8 +1476,9 @@ void intel_dp_start_link_train(struct intel_dp *intel_dp, + { + bool passed; + /* +- * TODO: Reiniting LTTPRs here won't be needed once proper connector +- * HW state readout is added. ++ * Reinit the LTTPRs here to ensure that they are switched to ++ * non-transparent mode. During an earlier LTTPR detection this ++ * could've been prevented by an active link. + */ + int lttpr_count = intel_dp_init_lttpr_and_dprx_caps(intel_dp); + +-- +2.43.0 + diff --git a/queue-6.1/drm-udl-move-connector-to-modesetting-code.patch b/queue-6.1/drm-udl-move-connector-to-modesetting-code.patch new file mode 100644 index 00000000000..cf35749f460 --- /dev/null +++ b/queue-6.1/drm-udl-move-connector-to-modesetting-code.patch @@ -0,0 +1,372 @@ +From a2860b78ab12115e5aa70d3afbe9cbd1289a15da Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 6 Oct 2022 11:53:44 +0200 +Subject: drm/udl: Move connector to modesetting code + +From: Thomas Zimmermann + +[ Upstream commit 0862cfd3e22f3f936927f2f7381c2519ba034c6e ] + +Move the connector next to the rest of the modesetting code. No +functional changes. + +Signed-off-by: Thomas Zimmermann +Reviewed-by: Javier Martinez Canillas +Link: https://patchwork.freedesktop.org/patch/msgid/20221006095355.23579-6-tzimmermann@suse.de +Stable-dep-of: 5aed213c7c6c ("drm/udl: Remove DRM_CONNECTOR_POLL_HPD") +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/udl/Makefile | 2 +- + drivers/gpu/drm/udl/udl_connector.c | 132 ---------------------------- + drivers/gpu/drm/udl/udl_connector.h | 21 ----- + drivers/gpu/drm/udl/udl_drv.h | 11 +++ + drivers/gpu/drm/udl/udl_modeset.c | 122 +++++++++++++++++++++++++ + 5 files changed, 134 insertions(+), 154 deletions(-) + delete mode 100644 drivers/gpu/drm/udl/udl_connector.c + delete mode 100644 drivers/gpu/drm/udl/udl_connector.h + +diff --git a/drivers/gpu/drm/udl/Makefile b/drivers/gpu/drm/udl/Makefile +index 24d61f61d7db2..3f6db179455d1 100644 +--- a/drivers/gpu/drm/udl/Makefile ++++ b/drivers/gpu/drm/udl/Makefile +@@ -1,4 +1,4 @@ + # SPDX-License-Identifier: GPL-2.0-only +-udl-y := udl_drv.o udl_modeset.o udl_connector.o udl_main.o udl_transfer.o ++udl-y := udl_drv.o udl_modeset.o udl_main.o udl_transfer.o + + obj-$(CONFIG_DRM_UDL) := udl.o +diff --git a/drivers/gpu/drm/udl/udl_connector.c b/drivers/gpu/drm/udl/udl_connector.c +deleted file mode 100644 +index 538b47ffa67fa..0000000000000 +--- a/drivers/gpu/drm/udl/udl_connector.c ++++ /dev/null +@@ -1,132 +0,0 @@ +-// SPDX-License-Identifier: GPL-2.0-only +-/* +- * Copyright (C) 2012 Red Hat +- * based in parts on udlfb.c: +- * Copyright (C) 2009 Roberto De Ioris +- * Copyright (C) 2009 Jaya Kumar +- * Copyright (C) 2009 Bernie Thompson +- */ +- +-#include +-#include +-#include +-#include +- +-#include "udl_connector.h" +-#include "udl_drv.h" +- +-static int udl_get_edid_block(void *data, u8 *buf, unsigned int block, size_t len) +-{ +- struct udl_device *udl = data; +- struct drm_device *dev = &udl->drm; +- struct usb_device *udev = udl_to_usb_device(udl); +- u8 *read_buff; +- int ret; +- size_t i; +- +- read_buff = kmalloc(2, GFP_KERNEL); +- if (!read_buff) +- return -ENOMEM; +- +- for (i = 0; i < len; i++) { +- int bval = (i + block * EDID_LENGTH) << 8; +- +- ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), +- 0x02, (0x80 | (0x02 << 5)), bval, +- 0xA1, read_buff, 2, USB_CTRL_GET_TIMEOUT); +- if (ret < 0) { +- drm_err(dev, "Read EDID byte %zu failed err %x\n", i, ret); +- goto err_kfree; +- } else if (ret < 1) { +- ret = -EIO; +- drm_err(dev, "Read EDID byte %zu failed\n", i); +- goto err_kfree; +- } +- +- buf[i] = read_buff[1]; +- } +- +- kfree(read_buff); +- +- return 0; +- +-err_kfree: +- kfree(read_buff); +- return ret; +-} +- +-static int udl_connector_helper_get_modes(struct drm_connector *connector) +-{ +- struct udl_connector *udl_connector = to_udl_connector(connector); +- +- drm_connector_update_edid_property(connector, udl_connector->edid); +- if (udl_connector->edid) +- return drm_add_edid_modes(connector, udl_connector->edid); +- +- return 0; +-} +- +-static enum drm_connector_status udl_connector_detect(struct drm_connector *connector, bool force) +-{ +- struct udl_device *udl = to_udl(connector->dev); +- struct udl_connector *udl_connector = to_udl_connector(connector); +- +- /* cleanup previous EDID */ +- kfree(udl_connector->edid); +- +- udl_connector->edid = drm_do_get_edid(connector, udl_get_edid_block, udl); +- if (!udl_connector->edid) +- return connector_status_disconnected; +- +- return connector_status_connected; +-} +- +-static void udl_connector_destroy(struct drm_connector *connector) +-{ +- struct udl_connector *udl_connector = to_udl_connector(connector); +- +- drm_connector_cleanup(connector); +- kfree(udl_connector->edid); +- kfree(udl_connector); +-} +- +-static const struct drm_connector_helper_funcs udl_connector_helper_funcs = { +- .get_modes = udl_connector_helper_get_modes, +-}; +- +-static const struct drm_connector_funcs udl_connector_funcs = { +- .reset = drm_atomic_helper_connector_reset, +- .detect = udl_connector_detect, +- .fill_modes = drm_helper_probe_single_connector_modes, +- .destroy = udl_connector_destroy, +- .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, +- .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, +-}; +- +-struct drm_connector *udl_connector_init(struct drm_device *dev) +-{ +- struct udl_connector *udl_connector; +- struct drm_connector *connector; +- int ret; +- +- udl_connector = kzalloc(sizeof(*udl_connector), GFP_KERNEL); +- if (!udl_connector) +- return ERR_PTR(-ENOMEM); +- +- connector = &udl_connector->connector; +- ret = drm_connector_init(dev, connector, &udl_connector_funcs, DRM_MODE_CONNECTOR_VGA); +- if (ret) +- goto err_kfree; +- +- drm_connector_helper_add(connector, &udl_connector_helper_funcs); +- +- connector->polled = DRM_CONNECTOR_POLL_HPD | +- DRM_CONNECTOR_POLL_CONNECT | +- DRM_CONNECTOR_POLL_DISCONNECT; +- +- return connector; +- +-err_kfree: +- kfree(udl_connector); +- return ERR_PTR(ret); +-} +diff --git a/drivers/gpu/drm/udl/udl_connector.h b/drivers/gpu/drm/udl/udl_connector.h +deleted file mode 100644 +index 74ad68fd3cc9f..0000000000000 +--- a/drivers/gpu/drm/udl/udl_connector.h ++++ /dev/null +@@ -1,21 +0,0 @@ +-#ifndef __UDL_CONNECTOR_H__ +-#define __UDL_CONNECTOR_H__ +- +-#include +- +-#include +- +-struct edid; +- +-struct udl_connector { +- struct drm_connector connector; +- /* last udl_detect edid */ +- struct edid *edid; +-}; +- +-static inline struct udl_connector *to_udl_connector(struct drm_connector *connector) +-{ +- return container_of(connector, struct udl_connector, connector); +-} +- +-#endif //__UDL_CONNECTOR_H__ +diff --git a/drivers/gpu/drm/udl/udl_drv.h b/drivers/gpu/drm/udl/udl_drv.h +index b4cc7cc568c74..d7a3d495f2e7e 100644 +--- a/drivers/gpu/drm/udl/udl_drv.h ++++ b/drivers/gpu/drm/udl/udl_drv.h +@@ -46,6 +46,17 @@ struct urb_list { + size_t size; + }; + ++struct udl_connector { ++ struct drm_connector connector; ++ /* last udl_detect edid */ ++ struct edid *edid; ++}; ++ ++static inline struct udl_connector *to_udl_connector(struct drm_connector *connector) ++{ ++ return container_of(connector, struct udl_connector, connector); ++} ++ + struct udl_device { + struct drm_device drm; + struct device *dev; +diff --git a/drivers/gpu/drm/udl/udl_modeset.c b/drivers/gpu/drm/udl/udl_modeset.c +index c7adc29a53a18..93e7554e83fa3 100644 +--- a/drivers/gpu/drm/udl/udl_modeset.c ++++ b/drivers/gpu/drm/udl/udl_modeset.c +@@ -11,11 +11,13 @@ + #include + #include + #include ++#include + #include + #include + #include + #include + #include ++#include + #include + + #include "udl_drv.h" +@@ -403,6 +405,126 @@ static const struct drm_simple_display_pipe_funcs udl_simple_display_pipe_funcs + DRM_GEM_SIMPLE_DISPLAY_PIPE_SHADOW_PLANE_FUNCS, + }; + ++/* ++ * Connector ++ */ ++ ++static int udl_connector_helper_get_modes(struct drm_connector *connector) ++{ ++ struct udl_connector *udl_connector = to_udl_connector(connector); ++ ++ drm_connector_update_edid_property(connector, udl_connector->edid); ++ if (udl_connector->edid) ++ return drm_add_edid_modes(connector, udl_connector->edid); ++ ++ return 0; ++} ++ ++static const struct drm_connector_helper_funcs udl_connector_helper_funcs = { ++ .get_modes = udl_connector_helper_get_modes, ++}; ++ ++static int udl_get_edid_block(void *data, u8 *buf, unsigned int block, size_t len) ++{ ++ struct udl_device *udl = data; ++ struct drm_device *dev = &udl->drm; ++ struct usb_device *udev = udl_to_usb_device(udl); ++ u8 *read_buff; ++ int ret; ++ size_t i; ++ ++ read_buff = kmalloc(2, GFP_KERNEL); ++ if (!read_buff) ++ return -ENOMEM; ++ ++ for (i = 0; i < len; i++) { ++ int bval = (i + block * EDID_LENGTH) << 8; ++ ++ ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), ++ 0x02, (0x80 | (0x02 << 5)), bval, ++ 0xA1, read_buff, 2, USB_CTRL_GET_TIMEOUT); ++ if (ret < 0) { ++ drm_err(dev, "Read EDID byte %zu failed err %x\n", i, ret); ++ goto err_kfree; ++ } else if (ret < 1) { ++ ret = -EIO; ++ drm_err(dev, "Read EDID byte %zu failed\n", i); ++ goto err_kfree; ++ } ++ ++ buf[i] = read_buff[1]; ++ } ++ ++ kfree(read_buff); ++ ++ return 0; ++ ++err_kfree: ++ kfree(read_buff); ++ return ret; ++} ++ ++static enum drm_connector_status udl_connector_detect(struct drm_connector *connector, bool force) ++{ ++ struct udl_device *udl = to_udl(connector->dev); ++ struct udl_connector *udl_connector = to_udl_connector(connector); ++ ++ /* cleanup previous EDID */ ++ kfree(udl_connector->edid); ++ ++ udl_connector->edid = drm_do_get_edid(connector, udl_get_edid_block, udl); ++ if (!udl_connector->edid) ++ return connector_status_disconnected; ++ ++ return connector_status_connected; ++} ++ ++static void udl_connector_destroy(struct drm_connector *connector) ++{ ++ struct udl_connector *udl_connector = to_udl_connector(connector); ++ ++ drm_connector_cleanup(connector); ++ kfree(udl_connector->edid); ++ kfree(udl_connector); ++} ++ ++static const struct drm_connector_funcs udl_connector_funcs = { ++ .reset = drm_atomic_helper_connector_reset, ++ .detect = udl_connector_detect, ++ .fill_modes = drm_helper_probe_single_connector_modes, ++ .destroy = udl_connector_destroy, ++ .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, ++ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, ++}; ++ ++struct drm_connector *udl_connector_init(struct drm_device *dev) ++{ ++ struct udl_connector *udl_connector; ++ struct drm_connector *connector; ++ int ret; ++ ++ udl_connector = kzalloc(sizeof(*udl_connector), GFP_KERNEL); ++ if (!udl_connector) ++ return ERR_PTR(-ENOMEM); ++ ++ connector = &udl_connector->connector; ++ ret = drm_connector_init(dev, connector, &udl_connector_funcs, DRM_MODE_CONNECTOR_VGA); ++ if (ret) ++ goto err_kfree; ++ ++ drm_connector_helper_add(connector, &udl_connector_helper_funcs); ++ ++ connector->polled = DRM_CONNECTOR_POLL_HPD | ++ DRM_CONNECTOR_POLL_CONNECT | ++ DRM_CONNECTOR_POLL_DISCONNECT; ++ ++ return connector; ++ ++err_kfree: ++ kfree(udl_connector); ++ return ERR_PTR(ret); ++} ++ + /* + * Modesetting + */ +-- +2.43.0 + diff --git a/queue-6.1/drm-udl-remove-drm_connector_poll_hpd.patch b/queue-6.1/drm-udl-remove-drm_connector_poll_hpd.patch new file mode 100644 index 00000000000..07b2ed3dec2 --- /dev/null +++ b/queue-6.1/drm-udl-remove-drm_connector_poll_hpd.patch @@ -0,0 +1,46 @@ +From 53090b4c8a0018354e37be6994e8e0e5b068f1d6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 May 2024 17:47:08 +0200 +Subject: drm/udl: Remove DRM_CONNECTOR_POLL_HPD + +From: Thomas Zimmermann + +[ Upstream commit 5aed213c7c6c4f5dcb1a3ef146f493f18fe703dc ] + +DisplayLink devices do not generate hotplug events. Remove the poll +flag DRM_CONNECTOR_POLL_HPD, as it may not be specified together with +DRM_CONNECTOR_POLL_CONNECT or DRM_CONNECTOR_POLL_DISCONNECT. + +Signed-off-by: Thomas Zimmermann +Fixes: afdfc4c6f55f ("drm/udl: Fixed problem with UDL adpater reconnection") +Reviewed-by: Jani Nikula +Cc: Robert Tarasov +Cc: Alex Deucher +Cc: Dave Airlie +Cc: Sean Paul +Cc: Thomas Zimmermann +Cc: dri-devel@lists.freedesktop.org +Cc: # v4.15+ +Link: https://patchwork.freedesktop.org/patch/msgid/20240510154841.11370-2-tzimmermann@suse.de +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/udl/udl_modeset.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/udl/udl_modeset.c b/drivers/gpu/drm/udl/udl_modeset.c +index 93e7554e83fa3..8f4c4a857b6e8 100644 +--- a/drivers/gpu/drm/udl/udl_modeset.c ++++ b/drivers/gpu/drm/udl/udl_modeset.c +@@ -514,8 +514,7 @@ struct drm_connector *udl_connector_init(struct drm_device *dev) + + drm_connector_helper_add(connector, &udl_connector_helper_funcs); + +- connector->polled = DRM_CONNECTOR_POLL_HPD | +- DRM_CONNECTOR_POLL_CONNECT | ++ connector->polled = DRM_CONNECTOR_POLL_CONNECT | + DRM_CONNECTOR_POLL_DISCONNECT; + + return connector; +-- +2.43.0 + diff --git a/queue-6.1/drm-udl-rename-struct-udl_drm_connector-to-struct-ud.patch b/queue-6.1/drm-udl-rename-struct-udl_drm_connector-to-struct-ud.patch new file mode 100644 index 00000000000..c3c1aad364b --- /dev/null +++ b/queue-6.1/drm-udl-rename-struct-udl_drm_connector-to-struct-ud.patch @@ -0,0 +1,106 @@ +From 1c3b6b1e090363f4bbc4a502cb26ea7a5beb4d5f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 6 Oct 2022 11:53:40 +0200 +Subject: drm/udl: Rename struct udl_drm_connector to struct udl_connector + +From: Thomas Zimmermann + +[ Upstream commit 59a811faa74f4326fe2d48d2b334c0ee95922628 ] + +Remove the _drm_ infix from struct udl_drm_connector and introduce a +macro for upcasting from struct drm_connector. No functional changes. + +Signed-off-by: Thomas Zimmermann +Reviewed-by: Javier Martinez Canillas +Link: https://patchwork.freedesktop.org/patch/msgid/20221006095355.23579-2-tzimmermann@suse.de +Stable-dep-of: 5aed213c7c6c ("drm/udl: Remove DRM_CONNECTOR_POLL_HPD") +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/udl/udl_connector.c | 19 +++++-------------- + drivers/gpu/drm/udl/udl_connector.h | 10 ++++++++-- + 2 files changed, 13 insertions(+), 16 deletions(-) + +diff --git a/drivers/gpu/drm/udl/udl_connector.c b/drivers/gpu/drm/udl/udl_connector.c +index fade4c7adbf78..3c80686263848 100644 +--- a/drivers/gpu/drm/udl/udl_connector.c ++++ b/drivers/gpu/drm/udl/udl_connector.c +@@ -46,10 +46,7 @@ static int udl_get_edid_block(void *data, u8 *buf, unsigned int block, + + static int udl_get_modes(struct drm_connector *connector) + { +- struct udl_drm_connector *udl_connector = +- container_of(connector, +- struct udl_drm_connector, +- connector); ++ struct udl_connector *udl_connector = to_udl_connector(connector); + + drm_connector_update_edid_property(connector, udl_connector->edid); + if (udl_connector->edid) +@@ -74,10 +71,7 @@ static enum drm_connector_status + udl_detect(struct drm_connector *connector, bool force) + { + struct udl_device *udl = to_udl(connector->dev); +- struct udl_drm_connector *udl_connector = +- container_of(connector, +- struct udl_drm_connector, +- connector); ++ struct udl_connector *udl_connector = to_udl_connector(connector); + + /* cleanup previous edid */ + if (udl_connector->edid != NULL) { +@@ -94,10 +88,7 @@ udl_detect(struct drm_connector *connector, bool force) + + static void udl_connector_destroy(struct drm_connector *connector) + { +- struct udl_drm_connector *udl_connector = +- container_of(connector, +- struct udl_drm_connector, +- connector); ++ struct udl_connector *udl_connector = to_udl_connector(connector); + + drm_connector_cleanup(connector); + kfree(udl_connector->edid); +@@ -120,10 +111,10 @@ static const struct drm_connector_funcs udl_connector_funcs = { + + struct drm_connector *udl_connector_init(struct drm_device *dev) + { +- struct udl_drm_connector *udl_connector; ++ struct udl_connector *udl_connector; + struct drm_connector *connector; + +- udl_connector = kzalloc(sizeof(struct udl_drm_connector), GFP_KERNEL); ++ udl_connector = kzalloc(sizeof(*udl_connector), GFP_KERNEL); + if (!udl_connector) + return ERR_PTR(-ENOMEM); + +diff --git a/drivers/gpu/drm/udl/udl_connector.h b/drivers/gpu/drm/udl/udl_connector.h +index 7f2d392df1737..74ad68fd3cc9f 100644 +--- a/drivers/gpu/drm/udl/udl_connector.h ++++ b/drivers/gpu/drm/udl/udl_connector.h +@@ -1,15 +1,21 @@ + #ifndef __UDL_CONNECTOR_H__ + #define __UDL_CONNECTOR_H__ + +-#include ++#include ++ ++#include + + struct edid; + +-struct udl_drm_connector { ++struct udl_connector { + struct drm_connector connector; + /* last udl_detect edid */ + struct edid *edid; + }; + ++static inline struct udl_connector *to_udl_connector(struct drm_connector *connector) ++{ ++ return container_of(connector, struct udl_connector, connector); ++} + + #endif //__UDL_CONNECTOR_H__ +-- +2.43.0 + diff --git a/queue-6.1/drm-udl-test-pixel-limit-in-mode-config-s-mode-valid.patch b/queue-6.1/drm-udl-test-pixel-limit-in-mode-config-s-mode-valid.patch new file mode 100644 index 00000000000..a23e4b2cbe7 --- /dev/null +++ b/queue-6.1/drm-udl-test-pixel-limit-in-mode-config-s-mode-valid.patch @@ -0,0 +1,85 @@ +From 7ba5f10fd34a5b341e456b032811a03fa512cf91 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 6 Oct 2022 11:53:41 +0200 +Subject: drm/udl: Test pixel limit in mode-config's mode-valid function + +From: Thomas Zimmermann + +[ Upstream commit c020f66013b6136a68a3a4ad74cc7af3b3310586 ] + +The sku_pixel_limit is a per-device property, similar to the amount +of available video memory. Move the respective mode-valid test from +the connector to the mode-config structure. + +Signed-off-by: Thomas Zimmermann +Reviewed-by: Javier Martinez Canillas +Link: https://patchwork.freedesktop.org/patch/msgid/20221006095355.23579-3-tzimmermann@suse.de +Stable-dep-of: 5aed213c7c6c ("drm/udl: Remove DRM_CONNECTOR_POLL_HPD") +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/udl/udl_connector.c | 14 -------------- + drivers/gpu/drm/udl/udl_modeset.c | 14 ++++++++++++++ + 2 files changed, 14 insertions(+), 14 deletions(-) + +diff --git a/drivers/gpu/drm/udl/udl_connector.c b/drivers/gpu/drm/udl/udl_connector.c +index 3c80686263848..e9539829032c5 100644 +--- a/drivers/gpu/drm/udl/udl_connector.c ++++ b/drivers/gpu/drm/udl/udl_connector.c +@@ -54,19 +54,6 @@ static int udl_get_modes(struct drm_connector *connector) + return 0; + } + +-static enum drm_mode_status udl_mode_valid(struct drm_connector *connector, +- struct drm_display_mode *mode) +-{ +- struct udl_device *udl = to_udl(connector->dev); +- if (!udl->sku_pixel_limit) +- return 0; +- +- if (mode->vdisplay * mode->hdisplay > udl->sku_pixel_limit) +- return MODE_VIRTUAL_Y; +- +- return 0; +-} +- + static enum drm_connector_status + udl_detect(struct drm_connector *connector, bool force) + { +@@ -97,7 +84,6 @@ static void udl_connector_destroy(struct drm_connector *connector) + + static const struct drm_connector_helper_funcs udl_connector_helper_funcs = { + .get_modes = udl_get_modes, +- .mode_valid = udl_mode_valid, + }; + + static const struct drm_connector_funcs udl_connector_funcs = { +diff --git a/drivers/gpu/drm/udl/udl_modeset.c b/drivers/gpu/drm/udl/udl_modeset.c +index ec6876f449f31..c7adc29a53a18 100644 +--- a/drivers/gpu/drm/udl/udl_modeset.c ++++ b/drivers/gpu/drm/udl/udl_modeset.c +@@ -407,8 +407,22 @@ static const struct drm_simple_display_pipe_funcs udl_simple_display_pipe_funcs + * Modesetting + */ + ++static enum drm_mode_status udl_mode_config_mode_valid(struct drm_device *dev, ++ const struct drm_display_mode *mode) ++{ ++ struct udl_device *udl = to_udl(dev); ++ ++ if (udl->sku_pixel_limit) { ++ if (mode->vdisplay * mode->hdisplay > udl->sku_pixel_limit) ++ return MODE_MEM; ++ } ++ ++ return MODE_OK; ++} ++ + static const struct drm_mode_config_funcs udl_mode_funcs = { + .fb_create = drm_gem_fb_create_with_dirty, ++ .mode_valid = udl_mode_config_mode_valid, + .atomic_check = drm_atomic_helper_check, + .atomic_commit = drm_atomic_helper_commit, + }; +-- +2.43.0 + diff --git a/queue-6.1/drm-udl-use-usb-timeout-constant-when-reading-edid.patch b/queue-6.1/drm-udl-use-usb-timeout-constant-when-reading-edid.patch new file mode 100644 index 00000000000..184d50d20d9 --- /dev/null +++ b/queue-6.1/drm-udl-use-usb-timeout-constant-when-reading-edid.patch @@ -0,0 +1,38 @@ +From a78979d508a4b80aeff706b3926df0d0679fa414 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 6 Oct 2022 11:53:42 +0200 +Subject: drm/udl: Use USB timeout constant when reading EDID + +From: Thomas Zimmermann + +[ Upstream commit 2c1eafc40e53312864bf2fdccb55052dcbd9e8b2 ] + +Set the USB control-message timeout to the USB default of 5 seconds. +Done for consistency with other uses of usb_control_msg() in udl and +other drivers. + +Signed-off-by: Thomas Zimmermann +Reviewed-by: Javier Martinez Canillas +Link: https://patchwork.freedesktop.org/patch/msgid/20221006095355.23579-4-tzimmermann@suse.de +Stable-dep-of: 5aed213c7c6c ("drm/udl: Remove DRM_CONNECTOR_POLL_HPD") +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/udl/udl_connector.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/udl/udl_connector.c b/drivers/gpu/drm/udl/udl_connector.c +index e9539829032c5..cb3d6820eaf93 100644 +--- a/drivers/gpu/drm/udl/udl_connector.c ++++ b/drivers/gpu/drm/udl/udl_connector.c +@@ -31,7 +31,7 @@ static int udl_get_edid_block(void *data, u8 *buf, unsigned int block, + int bval = (i + block * EDID_LENGTH) << 8; + ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), + 0x02, (0x80 | (0x02 << 5)), bval, +- 0xA1, read_buff, 2, 1000); ++ 0xA1, read_buff, 2, USB_CTRL_GET_TIMEOUT); + if (ret < 1) { + DRM_ERROR("Read EDID byte %d failed err %x\n", i, ret); + kfree(read_buff); +-- +2.43.0 + diff --git a/queue-6.1/drm-udl-various-improvements-to-the-connector.patch b/queue-6.1/drm-udl-various-improvements-to-the-connector.patch new file mode 100644 index 00000000000..217e071d909 --- /dev/null +++ b/queue-6.1/drm-udl-various-improvements-to-the-connector.patch @@ -0,0 +1,165 @@ +From a1cdaed90a551dc1873f502cfc77881352d5509b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 6 Oct 2022 11:53:43 +0200 +Subject: drm/udl: Various improvements to the connector + +From: Thomas Zimmermann + +[ Upstream commit 43858eb41e0dde6e48565c13cdabac95b5d9df90 ] + +Add style fixes, better error handling and reporting, and minor +clean-up changes to the connector code before moving the code to +the rest of the modesetting pipeline. + +Signed-off-by: Thomas Zimmermann +Reviewed-by: Javier Martinez Canillas +Link: https://patchwork.freedesktop.org/patch/msgid/20221006095355.23579-5-tzimmermann@suse.de +Stable-dep-of: 5aed213c7c6c ("drm/udl: Remove DRM_CONNECTOR_POLL_HPD") +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/udl/udl_connector.c | 64 ++++++++++++++++++----------- + 1 file changed, 40 insertions(+), 24 deletions(-) + +diff --git a/drivers/gpu/drm/udl/udl_connector.c b/drivers/gpu/drm/udl/udl_connector.c +index cb3d6820eaf93..538b47ffa67fa 100644 +--- a/drivers/gpu/drm/udl/udl_connector.c ++++ b/drivers/gpu/drm/udl/udl_connector.c +@@ -15,56 +15,64 @@ + #include "udl_connector.h" + #include "udl_drv.h" + +-static int udl_get_edid_block(void *data, u8 *buf, unsigned int block, +- size_t len) ++static int udl_get_edid_block(void *data, u8 *buf, unsigned int block, size_t len) + { +- int ret, i; +- u8 *read_buff; + struct udl_device *udl = data; ++ struct drm_device *dev = &udl->drm; + struct usb_device *udev = udl_to_usb_device(udl); ++ u8 *read_buff; ++ int ret; ++ size_t i; + + read_buff = kmalloc(2, GFP_KERNEL); + if (!read_buff) +- return -1; ++ return -ENOMEM; + + for (i = 0; i < len; i++) { + int bval = (i + block * EDID_LENGTH) << 8; ++ + ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), + 0x02, (0x80 | (0x02 << 5)), bval, + 0xA1, read_buff, 2, USB_CTRL_GET_TIMEOUT); +- if (ret < 1) { +- DRM_ERROR("Read EDID byte %d failed err %x\n", i, ret); +- kfree(read_buff); +- return -1; ++ if (ret < 0) { ++ drm_err(dev, "Read EDID byte %zu failed err %x\n", i, ret); ++ goto err_kfree; ++ } else if (ret < 1) { ++ ret = -EIO; ++ drm_err(dev, "Read EDID byte %zu failed\n", i); ++ goto err_kfree; + } ++ + buf[i] = read_buff[1]; + } + + kfree(read_buff); ++ + return 0; ++ ++err_kfree: ++ kfree(read_buff); ++ return ret; + } + +-static int udl_get_modes(struct drm_connector *connector) ++static int udl_connector_helper_get_modes(struct drm_connector *connector) + { + struct udl_connector *udl_connector = to_udl_connector(connector); + + drm_connector_update_edid_property(connector, udl_connector->edid); + if (udl_connector->edid) + return drm_add_edid_modes(connector, udl_connector->edid); ++ + return 0; + } + +-static enum drm_connector_status +-udl_detect(struct drm_connector *connector, bool force) ++static enum drm_connector_status udl_connector_detect(struct drm_connector *connector, bool force) + { + struct udl_device *udl = to_udl(connector->dev); + struct udl_connector *udl_connector = to_udl_connector(connector); + +- /* cleanup previous edid */ +- if (udl_connector->edid != NULL) { +- kfree(udl_connector->edid); +- udl_connector->edid = NULL; +- } ++ /* cleanup previous EDID */ ++ kfree(udl_connector->edid); + + udl_connector->edid = drm_do_get_edid(connector, udl_get_edid_block, udl); + if (!udl_connector->edid) +@@ -79,38 +87,46 @@ static void udl_connector_destroy(struct drm_connector *connector) + + drm_connector_cleanup(connector); + kfree(udl_connector->edid); +- kfree(connector); ++ kfree(udl_connector); + } + + static const struct drm_connector_helper_funcs udl_connector_helper_funcs = { +- .get_modes = udl_get_modes, ++ .get_modes = udl_connector_helper_get_modes, + }; + + static const struct drm_connector_funcs udl_connector_funcs = { + .reset = drm_atomic_helper_connector_reset, +- .detect = udl_detect, ++ .detect = udl_connector_detect, + .fill_modes = drm_helper_probe_single_connector_modes, + .destroy = udl_connector_destroy, + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, +- .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, ++ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, + }; + + struct drm_connector *udl_connector_init(struct drm_device *dev) + { + struct udl_connector *udl_connector; + struct drm_connector *connector; ++ int ret; + + udl_connector = kzalloc(sizeof(*udl_connector), GFP_KERNEL); + if (!udl_connector) + return ERR_PTR(-ENOMEM); + + connector = &udl_connector->connector; +- drm_connector_init(dev, connector, &udl_connector_funcs, +- DRM_MODE_CONNECTOR_VGA); ++ ret = drm_connector_init(dev, connector, &udl_connector_funcs, DRM_MODE_CONNECTOR_VGA); ++ if (ret) ++ goto err_kfree; ++ + drm_connector_helper_add(connector, &udl_connector_helper_funcs); + + connector->polled = DRM_CONNECTOR_POLL_HPD | +- DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT; ++ DRM_CONNECTOR_POLL_CONNECT | ++ DRM_CONNECTOR_POLL_DISCONNECT; + + return connector; ++ ++err_kfree: ++ kfree(udl_connector); ++ return ERR_PTR(ret); + } +-- +2.43.0 + diff --git a/queue-6.1/ext4-check-the-extent-status-again-before-inserting-.patch b/queue-6.1/ext4-check-the-extent-status-again-before-inserting-.patch new file mode 100644 index 00000000000..d907e0cc867 --- /dev/null +++ b/queue-6.1/ext4-check-the-extent-status-again-before-inserting-.patch @@ -0,0 +1,100 @@ +From a09d8dcb497ba74e761a0f0fcd8302c03a61ea1c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 May 2024 20:39:57 +0800 +Subject: ext4: check the extent status again before inserting delalloc block + +From: Zhang Yi + +[ Upstream commit 0ea6560abb3bac1ffcfa4bf6b2c4d344fdc27b3c ] + +ext4_da_map_blocks looks up for any extent entry in the extent status +tree (w/o i_data_sem) and then the looks up for any ondisk extent +mapping (with i_data_sem in read mode). + +If it finds a hole in the extent status tree or if it couldn't find any +entry at all, it then takes the i_data_sem in write mode to add a da +entry into the extent status tree. This can actually race with page +mkwrite & fallocate path. + +Note that this is ok between +1. ext4 buffered-write path v/s ext4_page_mkwrite(), because of the + folio lock +2. ext4 buffered write path v/s ext4 fallocate because of the inode + lock. + +But this can race between ext4_page_mkwrite() & ext4 fallocate path + +ext4_page_mkwrite() ext4_fallocate() + block_page_mkwrite() + ext4_da_map_blocks() + //find hole in extent status tree + ext4_alloc_file_blocks() + ext4_map_blocks() + //allocate block and unwritten extent + ext4_insert_delayed_block() + ext4_da_reserve_space() + //reserve one more block + ext4_es_insert_delayed_block() + //drop unwritten extent and add delayed extent by mistake + +Then, the delalloc extent is wrong until writeback and the extra +reserved block can't be released any more and it triggers below warning: + + EXT4-fs (pmem2): Inode 13 (00000000bbbd4d23): i_reserved_data_blocks(1) not cleared! + +Fix the problem by looking up extent status tree again while the +i_data_sem is held in write mode. If it still can't find any entry, then +we insert a new da entry into the extent status tree. + +Cc: stable@vger.kernel.org +Signed-off-by: Zhang Yi +Reviewed-by: Jan Kara +Link: https://patch.msgid.link/20240517124005.347221-3-yi.zhang@huaweicloud.com +Signed-off-by: Theodore Ts'o +Signed-off-by: Sasha Levin +--- + fs/ext4/inode.c | 21 +++++++++++++++++++++ + 1 file changed, 21 insertions(+) + +diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c +index a0c6a173c14d5..93a1c22048de6 100644 +--- a/fs/ext4/inode.c ++++ b/fs/ext4/inode.c +@@ -1772,6 +1772,7 @@ static int ext4_da_map_blocks(struct inode *inode, sector_t iblock, + if (ext4_es_is_hole(&es)) + goto add_delayed; + ++found: + /* + * Delayed extent could be allocated by fallocate. + * So we need to check it. +@@ -1816,6 +1817,26 @@ static int ext4_da_map_blocks(struct inode *inode, sector_t iblock, + + add_delayed: + down_write(&EXT4_I(inode)->i_data_sem); ++ /* ++ * Page fault path (ext4_page_mkwrite does not take i_rwsem) ++ * and fallocate path (no folio lock) can race. Make sure we ++ * lookup the extent status tree here again while i_data_sem ++ * is held in write mode, before inserting a new da entry in ++ * the extent status tree. ++ */ ++ if (ext4_es_lookup_extent(inode, iblock, NULL, &es)) { ++ if (!ext4_es_is_hole(&es)) { ++ up_write(&EXT4_I(inode)->i_data_sem); ++ goto found; ++ } ++ } else if (!ext4_has_inline_data(inode)) { ++ retval = ext4_map_query_blocks(NULL, inode, map); ++ if (retval) { ++ up_write(&EXT4_I(inode)->i_data_sem); ++ return retval; ++ } ++ } ++ + retval = ext4_insert_delayed_block(inode, map->m_lblk); + up_write(&EXT4_I(inode)->i_data_sem); + if (retval) +-- +2.43.0 + diff --git a/queue-6.1/ext4-convert-to-exclusive-lock-while-inserting-delal.patch b/queue-6.1/ext4-convert-to-exclusive-lock-while-inserting-delal.patch new file mode 100644 index 00000000000..847e02ef01f --- /dev/null +++ b/queue-6.1/ext4-convert-to-exclusive-lock-while-inserting-delal.patch @@ -0,0 +1,114 @@ +From f55733e3df97e5c9a292b773ac397145d03c3eac Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 27 Jan 2024 09:58:01 +0800 +Subject: ext4: convert to exclusive lock while inserting delalloc extents + +From: Zhang Yi + +[ Upstream commit acf795dc161f3cf481db20f05db4250714e375e5 ] + +ext4_da_map_blocks() only hold i_data_sem in shared mode and i_rwsem +when inserting delalloc extents, it could be raced by another querying +path of ext4_map_blocks() without i_rwsem, .e.g buffered read path. +Suppose we buffered read a file containing just a hole, and without any +cached extents tree, then it is raced by another delayed buffered write +to the same area or the near area belongs to the same hole, and the new +delalloc extent could be overwritten to a hole extent. + + pread() pwrite() + filemap_read_folio() + ext4_mpage_readpages() + ext4_map_blocks() + down_read(i_data_sem) + ext4_ext_determine_hole() + //find hole + ext4_ext_put_gap_in_cache() + ext4_es_find_extent_range() + //no delalloc extent + ext4_da_map_blocks() + down_read(i_data_sem) + ext4_insert_delayed_block() + //insert delalloc extent + ext4_es_insert_extent() + //overwrite delalloc extent to hole + +This race could lead to inconsistent delalloc extents tree and +incorrect reserved space counter. Fix this by converting to hold +i_data_sem in exclusive mode when adding a new delalloc extent in +ext4_da_map_blocks(). + +Cc: stable@vger.kernel.org +Signed-off-by: Zhang Yi +Suggested-by: Jan Kara +Reviewed-by: Jan Kara +Link: https://lore.kernel.org/r/20240127015825.1608160-3-yi.zhang@huaweicloud.com +Signed-off-by: Theodore Ts'o +Stable-dep-of: 0ea6560abb3b ("ext4: check the extent status again before inserting delalloc block") +Signed-off-by: Sasha Levin +--- + fs/ext4/inode.c | 25 +++++++++++-------------- + 1 file changed, 11 insertions(+), 14 deletions(-) + +diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c +index eab9aefe96ce6..d6f7525a796c0 100644 +--- a/fs/ext4/inode.c ++++ b/fs/ext4/inode.c +@@ -1740,10 +1740,8 @@ static int ext4_da_map_blocks(struct inode *inode, sector_t iblock, + + /* Lookup extent status tree firstly */ + if (ext4_es_lookup_extent(inode, iblock, NULL, &es)) { +- if (ext4_es_is_hole(&es)) { +- down_read(&EXT4_I(inode)->i_data_sem); ++ if (ext4_es_is_hole(&es)) + goto add_delayed; +- } + + /* + * Delayed extent could be allocated by fallocate. +@@ -1785,8 +1783,10 @@ static int ext4_da_map_blocks(struct inode *inode, sector_t iblock, + retval = ext4_ext_map_blocks(NULL, inode, map, 0); + else + retval = ext4_ind_map_blocks(NULL, inode, map, 0); +- if (retval < 0) +- goto out_unlock; ++ if (retval < 0) { ++ up_read(&EXT4_I(inode)->i_data_sem); ++ return retval; ++ } + if (retval > 0) { + unsigned int status; + +@@ -1802,24 +1802,21 @@ static int ext4_da_map_blocks(struct inode *inode, sector_t iblock, + EXTENT_STATUS_UNWRITTEN : EXTENT_STATUS_WRITTEN; + ext4_es_insert_extent(inode, map->m_lblk, map->m_len, + map->m_pblk, status); +- goto out_unlock; ++ up_read(&EXT4_I(inode)->i_data_sem); ++ return retval; + } ++ up_read(&EXT4_I(inode)->i_data_sem); + + add_delayed: +- /* +- * XXX: __block_prepare_write() unmaps passed block, +- * is it OK? +- */ ++ down_write(&EXT4_I(inode)->i_data_sem); + retval = ext4_insert_delayed_block(inode, map->m_lblk); ++ up_write(&EXT4_I(inode)->i_data_sem); + if (retval) +- goto out_unlock; ++ return retval; + + map_bh(bh, inode->i_sb, invalid_block); + set_buffer_new(bh); + set_buffer_delay(bh); +- +-out_unlock: +- up_read((&EXT4_I(inode)->i_data_sem)); + return retval; + } + +-- +2.43.0 + diff --git a/queue-6.1/ext4-factor-out-a-common-helper-to-query-extent-map.patch b/queue-6.1/ext4-factor-out-a-common-helper-to-query-extent-map.patch new file mode 100644 index 00000000000..0e1e7ba02c6 --- /dev/null +++ b/queue-6.1/ext4-factor-out-a-common-helper-to-query-extent-map.patch @@ -0,0 +1,104 @@ +From 4a85c2032f2e5bd2d1f148f2402c8b292bf50cc0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 May 2024 20:39:56 +0800 +Subject: ext4: factor out a common helper to query extent map + +From: Zhang Yi + +[ Upstream commit 8e4e5cdf2fdeb99445a468b6b6436ad79b9ecb30 ] + +Factor out a new common helper ext4_map_query_blocks() from the +ext4_da_map_blocks(), it query and return the extent map status on the +inode's extent path, no logic changes. + +Signed-off-by: Zhang Yi +Reviewed-by: Jan Kara +Reviewed-by: Ritesh Harjani (IBM) +Link: https://patch.msgid.link/20240517124005.347221-2-yi.zhang@huaweicloud.com +Signed-off-by: Theodore Ts'o +Stable-dep-of: 0ea6560abb3b ("ext4: check the extent status again before inserting delalloc block") +Signed-off-by: Sasha Levin +--- + fs/ext4/inode.c | 57 +++++++++++++++++++++++++++---------------------- + 1 file changed, 32 insertions(+), 25 deletions(-) + +diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c +index d6f7525a796c0..a0c6a173c14d5 100644 +--- a/fs/ext4/inode.c ++++ b/fs/ext4/inode.c +@@ -481,6 +481,35 @@ static void ext4_map_blocks_es_recheck(handle_t *handle, + } + #endif /* ES_AGGRESSIVE_TEST */ + ++static int ext4_map_query_blocks(handle_t *handle, struct inode *inode, ++ struct ext4_map_blocks *map) ++{ ++ unsigned int status; ++ int retval; ++ ++ if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) ++ retval = ext4_ext_map_blocks(handle, inode, map, 0); ++ else ++ retval = ext4_ind_map_blocks(handle, inode, map, 0); ++ ++ if (retval <= 0) ++ return retval; ++ ++ if (unlikely(retval != map->m_len)) { ++ ext4_warning(inode->i_sb, ++ "ES len assertion failed for inode " ++ "%lu: retval %d != map->m_len %d", ++ inode->i_ino, retval, map->m_len); ++ WARN_ON(1); ++ } ++ ++ status = map->m_flags & EXT4_MAP_UNWRITTEN ? ++ EXTENT_STATUS_UNWRITTEN : EXTENT_STATUS_WRITTEN; ++ ext4_es_insert_extent(inode, map->m_lblk, map->m_len, ++ map->m_pblk, status); ++ return retval; ++} ++ + /* + * The ext4_map_blocks() function tries to look up the requested blocks, + * and returns if the blocks are already mapped. +@@ -1779,33 +1808,11 @@ static int ext4_da_map_blocks(struct inode *inode, sector_t iblock, + down_read(&EXT4_I(inode)->i_data_sem); + if (ext4_has_inline_data(inode)) + retval = 0; +- else if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) +- retval = ext4_ext_map_blocks(NULL, inode, map, 0); + else +- retval = ext4_ind_map_blocks(NULL, inode, map, 0); +- if (retval < 0) { +- up_read(&EXT4_I(inode)->i_data_sem); +- return retval; +- } +- if (retval > 0) { +- unsigned int status; +- +- if (unlikely(retval != map->m_len)) { +- ext4_warning(inode->i_sb, +- "ES len assertion failed for inode " +- "%lu: retval %d != map->m_len %d", +- inode->i_ino, retval, map->m_len); +- WARN_ON(1); +- } +- +- status = map->m_flags & EXT4_MAP_UNWRITTEN ? +- EXTENT_STATUS_UNWRITTEN : EXTENT_STATUS_WRITTEN; +- ext4_es_insert_extent(inode, map->m_lblk, map->m_len, +- map->m_pblk, status); +- up_read(&EXT4_I(inode)->i_data_sem); +- return retval; +- } ++ retval = ext4_map_query_blocks(NULL, inode, map); + up_read(&EXT4_I(inode)->i_data_sem); ++ if (retval) ++ return retval; + + add_delayed: + down_write(&EXT4_I(inode)->i_data_sem); +-- +2.43.0 + diff --git a/queue-6.1/ext4-make-ext4_es_insert_extent-return-void.patch b/queue-6.1/ext4-make-ext4_es_insert_extent-return-void.patch new file mode 100644 index 00000000000..dcc967d6cf1 --- /dev/null +++ b/queue-6.1/ext4-make-ext4_es_insert_extent-return-void.patch @@ -0,0 +1,158 @@ +From 728bbdc362f8b07fa57ca604320666f97bd67026 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 24 Apr 2023 11:38:45 +0800 +Subject: ext4: make ext4_es_insert_extent() return void + +From: Baokun Li + +[ Upstream commit 6c120399cde6b1b5cf65ce403765c579fb3d3e50 ] + +Now ext4_es_insert_extent() never return error, so make it return void. + +Signed-off-by: Baokun Li +Reviewed-by: Jan Kara +Link: https://lore.kernel.org/r/20230424033846.4732-12-libaokun1@huawei.com +Signed-off-by: Theodore Ts'o +Stable-dep-of: 0ea6560abb3b ("ext4: check the extent status again before inserting delalloc block") +Signed-off-by: Sasha Levin +--- + fs/ext4/extents.c | 5 +++-- + fs/ext4/extents_status.c | 14 ++++++-------- + fs/ext4/extents_status.h | 6 +++--- + fs/ext4/inode.c | 21 ++++++--------------- + 4 files changed, 18 insertions(+), 28 deletions(-) + +diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c +index 67af684e44e6e..5cbe5ae5ad4a2 100644 +--- a/fs/ext4/extents.c ++++ b/fs/ext4/extents.c +@@ -3113,8 +3113,9 @@ static int ext4_zeroout_es(struct inode *inode, struct ext4_extent *ex) + if (ee_len == 0) + return 0; + +- return ext4_es_insert_extent(inode, ee_block, ee_len, ee_pblock, +- EXTENT_STATUS_WRITTEN); ++ ext4_es_insert_extent(inode, ee_block, ee_len, ee_pblock, ++ EXTENT_STATUS_WRITTEN); ++ return 0; + } + + /* FIXME!! we need to try to merge to left or right after zero-out */ +diff --git a/fs/ext4/extents_status.c b/fs/ext4/extents_status.c +index 9766d3b21ca2e..592229027af72 100644 +--- a/fs/ext4/extents_status.c ++++ b/fs/ext4/extents_status.c +@@ -847,12 +847,10 @@ static int __es_insert_extent(struct inode *inode, struct extent_status *newes, + /* + * ext4_es_insert_extent() adds information to an inode's extent + * status tree. +- * +- * Return 0 on success, error code on failure. + */ +-int ext4_es_insert_extent(struct inode *inode, ext4_lblk_t lblk, +- ext4_lblk_t len, ext4_fsblk_t pblk, +- unsigned int status) ++void ext4_es_insert_extent(struct inode *inode, ext4_lblk_t lblk, ++ ext4_lblk_t len, ext4_fsblk_t pblk, ++ unsigned int status) + { + struct extent_status newes; + ext4_lblk_t end = lblk + len - 1; +@@ -864,13 +862,13 @@ int ext4_es_insert_extent(struct inode *inode, ext4_lblk_t lblk, + bool revise_pending = false; + + if (EXT4_SB(inode->i_sb)->s_mount_state & EXT4_FC_REPLAY) +- return 0; ++ return; + + es_debug("add [%u/%u) %llu %x to extent status tree of inode %lu\n", + lblk, len, pblk, status, inode->i_ino); + + if (!len) +- return 0; ++ return; + + BUG_ON(end < lblk); + +@@ -939,7 +937,7 @@ int ext4_es_insert_extent(struct inode *inode, ext4_lblk_t lblk, + goto retry; + + ext4_es_print_tree(inode); +- return 0; ++ return; + } + + /* +diff --git a/fs/ext4/extents_status.h b/fs/ext4/extents_status.h +index 4ec30a7982605..481ec4381bee6 100644 +--- a/fs/ext4/extents_status.h ++++ b/fs/ext4/extents_status.h +@@ -127,9 +127,9 @@ extern int __init ext4_init_es(void); + extern void ext4_exit_es(void); + extern void ext4_es_init_tree(struct ext4_es_tree *tree); + +-extern int ext4_es_insert_extent(struct inode *inode, ext4_lblk_t lblk, +- ext4_lblk_t len, ext4_fsblk_t pblk, +- unsigned int status); ++extern void ext4_es_insert_extent(struct inode *inode, ext4_lblk_t lblk, ++ ext4_lblk_t len, ext4_fsblk_t pblk, ++ unsigned int status); + extern void ext4_es_cache_extent(struct inode *inode, ext4_lblk_t lblk, + ext4_lblk_t len, ext4_fsblk_t pblk, + unsigned int status); +diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c +index 2479508deab3b..6dc15ad45ac95 100644 +--- a/fs/ext4/inode.c ++++ b/fs/ext4/inode.c +@@ -595,10 +595,8 @@ int ext4_map_blocks(handle_t *handle, struct inode *inode, + ext4_es_scan_range(inode, &ext4_es_is_delayed, map->m_lblk, + map->m_lblk + map->m_len - 1)) + status |= EXTENT_STATUS_DELAYED; +- ret = ext4_es_insert_extent(inode, map->m_lblk, +- map->m_len, map->m_pblk, status); +- if (ret < 0) +- retval = ret; ++ ext4_es_insert_extent(inode, map->m_lblk, map->m_len, ++ map->m_pblk, status); + } + up_read((&EXT4_I(inode)->i_data_sem)); + +@@ -707,12 +705,8 @@ int ext4_map_blocks(handle_t *handle, struct inode *inode, + ext4_es_scan_range(inode, &ext4_es_is_delayed, map->m_lblk, + map->m_lblk + map->m_len - 1)) + status |= EXTENT_STATUS_DELAYED; +- ret = ext4_es_insert_extent(inode, map->m_lblk, map->m_len, +- map->m_pblk, status); +- if (ret < 0) { +- retval = ret; +- goto out_sem; +- } ++ ext4_es_insert_extent(inode, map->m_lblk, map->m_len, ++ map->m_pblk, status); + } + + out_sem: +@@ -1812,7 +1806,6 @@ static int ext4_da_map_blocks(struct inode *inode, sector_t iblock, + set_buffer_new(bh); + set_buffer_delay(bh); + } else if (retval > 0) { +- int ret; + unsigned int status; + + if (unlikely(retval != map->m_len)) { +@@ -1825,10 +1818,8 @@ static int ext4_da_map_blocks(struct inode *inode, sector_t iblock, + + status = map->m_flags & EXT4_MAP_UNWRITTEN ? + EXTENT_STATUS_UNWRITTEN : EXTENT_STATUS_WRITTEN; +- ret = ext4_es_insert_extent(inode, map->m_lblk, map->m_len, +- map->m_pblk, status); +- if (ret != 0) +- retval = ret; ++ ext4_es_insert_extent(inode, map->m_lblk, map->m_len, ++ map->m_pblk, status); + } + + out_unlock: +-- +2.43.0 + diff --git a/queue-6.1/ext4-refactor-ext4_da_map_blocks.patch b/queue-6.1/ext4-refactor-ext4_da_map_blocks.patch new file mode 100644 index 00000000000..5ca8a01f3d7 --- /dev/null +++ b/queue-6.1/ext4-refactor-ext4_da_map_blocks.patch @@ -0,0 +1,93 @@ +From aa2b2a1a2af2ae7add3b722840ccf9f8ef50d833 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 27 Jan 2024 09:58:00 +0800 +Subject: ext4: refactor ext4_da_map_blocks() + +From: Zhang Yi + +[ Upstream commit 3fcc2b887a1ba4c1f45319cd8c54daa263ecbc36 ] + +Refactor and cleanup ext4_da_map_blocks(), reduce some unnecessary +parameters and branches, no logic changes. + +Signed-off-by: Zhang Yi +Reviewed-by: Jan Kara +Link: https://lore.kernel.org/r/20240127015825.1608160-2-yi.zhang@huaweicloud.com +Signed-off-by: Theodore Ts'o +Stable-dep-of: 0ea6560abb3b ("ext4: check the extent status again before inserting delalloc block") +Signed-off-by: Sasha Levin +--- + fs/ext4/inode.c | 39 +++++++++++++++++---------------------- + 1 file changed, 17 insertions(+), 22 deletions(-) + +diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c +index 6dc15ad45ac95..eab9aefe96ce6 100644 +--- a/fs/ext4/inode.c ++++ b/fs/ext4/inode.c +@@ -1741,7 +1741,6 @@ static int ext4_da_map_blocks(struct inode *inode, sector_t iblock, + /* Lookup extent status tree firstly */ + if (ext4_es_lookup_extent(inode, iblock, NULL, &es)) { + if (ext4_es_is_hole(&es)) { +- retval = 0; + down_read(&EXT4_I(inode)->i_data_sem); + goto add_delayed; + } +@@ -1786,26 +1785,9 @@ static int ext4_da_map_blocks(struct inode *inode, sector_t iblock, + retval = ext4_ext_map_blocks(NULL, inode, map, 0); + else + retval = ext4_ind_map_blocks(NULL, inode, map, 0); +- +-add_delayed: +- if (retval == 0) { +- int ret; +- +- /* +- * XXX: __block_prepare_write() unmaps passed block, +- * is it OK? +- */ +- +- ret = ext4_insert_delayed_block(inode, map->m_lblk); +- if (ret != 0) { +- retval = ret; +- goto out_unlock; +- } +- +- map_bh(bh, inode->i_sb, invalid_block); +- set_buffer_new(bh); +- set_buffer_delay(bh); +- } else if (retval > 0) { ++ if (retval < 0) ++ goto out_unlock; ++ if (retval > 0) { + unsigned int status; + + if (unlikely(retval != map->m_len)) { +@@ -1820,11 +1802,24 @@ static int ext4_da_map_blocks(struct inode *inode, sector_t iblock, + EXTENT_STATUS_UNWRITTEN : EXTENT_STATUS_WRITTEN; + ext4_es_insert_extent(inode, map->m_lblk, map->m_len, + map->m_pblk, status); ++ goto out_unlock; + } + ++add_delayed: ++ /* ++ * XXX: __block_prepare_write() unmaps passed block, ++ * is it OK? ++ */ ++ retval = ext4_insert_delayed_block(inode, map->m_lblk); ++ if (retval) ++ goto out_unlock; ++ ++ map_bh(bh, inode->i_sb, invalid_block); ++ set_buffer_new(bh); ++ set_buffer_delay(bh); ++ + out_unlock: + up_read((&EXT4_I(inode)->i_data_sem)); +- + return retval; + } + +-- +2.43.0 + diff --git a/queue-6.1/f2fs-assign-curseg_all_data_atgc-if-blkaddr-is-valid.patch b/queue-6.1/f2fs-assign-curseg_all_data_atgc-if-blkaddr-is-valid.patch new file mode 100644 index 00000000000..2e81c25a781 --- /dev/null +++ b/queue-6.1/f2fs-assign-curseg_all_data_atgc-if-blkaddr-is-valid.patch @@ -0,0 +1,59 @@ +From 6cea387d3292b7c667433802f34b3048962453f9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 18 Jun 2024 02:15:38 +0000 +Subject: f2fs: assign CURSEG_ALL_DATA_ATGC if blkaddr is valid + +From: Jaegeuk Kim + +[ Upstream commit 8cb1f4080dd91c6e6b01dbea013a3f42341cb6a1 ] + +mkdir /mnt/test/comp +f2fs_io setflags compression /mnt/test/comp +dd if=/dev/zero of=/mnt/test/comp/testfile bs=16k count=1 +truncate --size 13 /mnt/test/comp/testfile + +In the above scenario, we can get a BUG_ON. + kernel BUG at fs/f2fs/segment.c:3589! + Call Trace: + do_write_page+0x78/0x390 [f2fs] + f2fs_outplace_write_data+0x62/0xb0 [f2fs] + f2fs_do_write_data_page+0x275/0x740 [f2fs] + f2fs_write_single_data_page+0x1dc/0x8f0 [f2fs] + f2fs_write_multi_pages+0x1e5/0xae0 [f2fs] + f2fs_write_cache_pages+0xab1/0xc60 [f2fs] + f2fs_write_data_pages+0x2d8/0x330 [f2fs] + do_writepages+0xcf/0x270 + __writeback_single_inode+0x44/0x350 + writeback_sb_inodes+0x242/0x530 + __writeback_inodes_wb+0x54/0xf0 + wb_writeback+0x192/0x310 + wb_workfn+0x30d/0x400 + +The reason is we gave CURSEG_ALL_DATA_ATGC to COMPR_ADDR where the +page was set the gcing flag by set_cluster_dirty(). + +Cc: stable@vger.kernel.org +Fixes: 4961acdd65c9 ("f2fs: fix to tag gcing flag on page during block migration") +Reviewed-by: Chao Yu +Tested-by: Will McVicker +Signed-off-by: Jaegeuk Kim +Signed-off-by: Sasha Levin +--- + fs/f2fs/segment.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c +index 99391ee4c28c4..1264a350d4d75 100644 +--- a/fs/f2fs/segment.c ++++ b/fs/f2fs/segment.c +@@ -3186,6 +3186,7 @@ static int __get_segment_type_6(struct f2fs_io_info *fio) + if (fio->sbi->am.atgc_enabled && + (fio->io_type == FS_DATA_IO) && + (fio->sbi->gc_mode != GC_URGENT_HIGH) && ++ __is_valid_data_blkaddr(fio->old_blkaddr) && + !is_inode_flag_set(inode, FI_OPU_WRITE)) + return CURSEG_ALL_DATA_ATGC; + else +-- +2.43.0 + diff --git a/queue-6.1/f2fs-fix-to-avoid-use-ssr-allocate-when-do-defragmen.patch b/queue-6.1/f2fs-fix-to-avoid-use-ssr-allocate-when-do-defragmen.patch new file mode 100644 index 00000000000..02f1249ab47 --- /dev/null +++ b/queue-6.1/f2fs-fix-to-avoid-use-ssr-allocate-when-do-defragmen.patch @@ -0,0 +1,75 @@ +From cc6b3e97782c5daa2869dbeacceea26aad4a6b6e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 29 May 2024 17:47:00 +0800 +Subject: f2fs: fix to avoid use SSR allocate when do defragment + +From: Zhiguo Niu + +[ Upstream commit 21327a042dd94bc73181d7300e688699cb1f467e ] + +SSR allocate mode will be used when doing file defragment +if ATGC is working at the same time, that is because +set_page_private_gcing may make CURSEG_ALL_DATA_ATGC segment +type got in f2fs_allocate_data_block when defragment page +is writeback, which may cause file fragmentation is worse. + +A file with 2 fragmentations is changed as following after defragment: + +----------------file info------------------- +sensorsdata : +-------------------------------------------- +dev [254:48] +ino [0x 3029 : 12329] +mode [0x 81b0 : 33200] +nlink [0x 1 : 1] +uid [0x 27e6 : 10214] +gid [0x 27e6 : 10214] +size [0x 242000 : 2367488] +blksize [0x 1000 : 4096] +blocks [0x 1210 : 4624] +-------------------------------------------- + +file_pos start_blk end_blk blks + 0 11361121 11361207 87 + 356352 11361215 11361216 2 + 364544 11361218 11361218 1 + 368640 11361220 11361221 2 + 376832 11361224 11361225 2 + 385024 11361227 11361238 12 + 434176 11361240 11361252 13 + 487424 11361254 11361254 1 + 491520 11361271 11361279 9 + 528384 3681794 3681795 2 + 536576 3681797 3681797 1 + 540672 3681799 3681799 1 + 544768 3681803 3681803 1 + 548864 3681805 3681805 1 + 552960 3681807 3681807 1 + 557056 3681809 3681809 1 + +Signed-off-by: Zhiguo Niu +Reviewed-by: Chao Yu +Signed-off-by: Jaegeuk Kim +Stable-dep-of: 8cb1f4080dd9 ("f2fs: assign CURSEG_ALL_DATA_ATGC if blkaddr is valid") +Signed-off-by: Sasha Levin +--- + fs/f2fs/segment.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c +index e19b569d938d8..99391ee4c28c4 100644 +--- a/fs/f2fs/segment.c ++++ b/fs/f2fs/segment.c +@@ -3185,7 +3185,8 @@ static int __get_segment_type_6(struct f2fs_io_info *fio) + if (page_private_gcing(fio->page)) { + if (fio->sbi->am.atgc_enabled && + (fio->io_type == FS_DATA_IO) && +- (fio->sbi->gc_mode != GC_URGENT_HIGH)) ++ (fio->sbi->gc_mode != GC_URGENT_HIGH) && ++ !is_inode_flag_set(inode, FI_OPU_WRITE)) + return CURSEG_ALL_DATA_ATGC; + else + return CURSEG_COLD_DATA; +-- +2.43.0 + diff --git a/queue-6.1/irqdomain-fixed-unbalanced-fwnode-get-and-put.patch b/queue-6.1/irqdomain-fixed-unbalanced-fwnode-get-and-put.patch new file mode 100644 index 00000000000..0faceee08bc --- /dev/null +++ b/queue-6.1/irqdomain-fixed-unbalanced-fwnode-get-and-put.patch @@ -0,0 +1,70 @@ +From 86149a873868c55caf9575063b939c46b3ebea0f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 14 Jun 2024 19:32:04 +0200 +Subject: irqdomain: Fixed unbalanced fwnode get and put + +From: Herve Codina + +[ Upstream commit 6ce3e98184b625d2870991880bf9586ded7ea7f9 ] + +fwnode_handle_get(fwnode) is called when a domain is created with fwnode +passed as a function parameter. fwnode_handle_put(domain->fwnode) is called +when the domain is destroyed but during the creation a path exists that +does not set domain->fwnode. + +If this path is taken, the fwnode get will never be put. + +To avoid the unbalanced get and put, set domain->fwnode unconditionally. + +Fixes: d59f6617eef0 ("genirq: Allow fwnode to carry name information only") +Signed-off-by: Herve Codina +Signed-off-by: Thomas Gleixner +Cc: stable@vger.kernel.org +Link: https://lore.kernel.org/r/20240614173232.1184015-4-herve.codina@bootlin.com +Signed-off-by: Sasha Levin +--- + kernel/irq/irqdomain.c | 7 ++----- + 1 file changed, 2 insertions(+), 5 deletions(-) + +diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c +index e03baca901e76..b1ed088b23640 100644 +--- a/kernel/irq/irqdomain.c ++++ b/kernel/irq/irqdomain.c +@@ -154,7 +154,6 @@ static struct irq_domain *__irq_domain_create(struct fwnode_handle *fwnode, + switch (fwid->type) { + case IRQCHIP_FWNODE_NAMED: + case IRQCHIP_FWNODE_NAMED_ID: +- domain->fwnode = fwnode; + domain->name = kstrdup(fwid->name, GFP_KERNEL); + if (!domain->name) { + kfree(domain); +@@ -163,7 +162,6 @@ static struct irq_domain *__irq_domain_create(struct fwnode_handle *fwnode, + domain->flags |= IRQ_DOMAIN_NAME_ALLOCATED; + break; + default: +- domain->fwnode = fwnode; + domain->name = fwid->name; + break; + } +@@ -183,7 +181,6 @@ static struct irq_domain *__irq_domain_create(struct fwnode_handle *fwnode, + } + + domain->name = strreplace(name, '/', ':'); +- domain->fwnode = fwnode; + domain->flags |= IRQ_DOMAIN_NAME_ALLOCATED; + } + +@@ -199,8 +196,8 @@ static struct irq_domain *__irq_domain_create(struct fwnode_handle *fwnode, + domain->flags |= IRQ_DOMAIN_NAME_ALLOCATED; + } + +- fwnode_handle_get(fwnode); +- fwnode_dev_initialized(fwnode, true); ++ domain->fwnode = fwnode_handle_get(fwnode); ++ fwnode_dev_initialized(domain->fwnode, true); + + /* Fill structure */ + INIT_RADIX_TREE(&domain->revmap_tree, GFP_KERNEL); +-- +2.43.0 + diff --git a/queue-6.1/irqdomain-use-return-value-of-strreplace.patch b/queue-6.1/irqdomain-use-return-value-of-strreplace.patch new file mode 100644 index 00000000000..2aea8968c9f --- /dev/null +++ b/queue-6.1/irqdomain-use-return-value-of-strreplace.patch @@ -0,0 +1,39 @@ +From 75d4494abda65fead10f8060be8a200a8960a25f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jun 2023 18:02:51 +0300 +Subject: irqdomain: Use return value of strreplace() + +From: Andy Shevchenko + +[ Upstream commit 67a4e1a3bf7c68ed3fbefc4213648165d912cabb ] + +Since strreplace() returns the pointer to the string itself, use it +directly. + +Signed-off-by: Andy Shevchenko +Signed-off-by: Thomas Gleixner +Link: https://lore.kernel.org/r/20230628150251.17832-1-andriy.shevchenko@linux.intel.com +Stable-dep-of: 6ce3e98184b6 ("irqdomain: Fixed unbalanced fwnode get and put") +Signed-off-by: Sasha Levin +--- + kernel/irq/irqdomain.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c +index 607c0c3d3f5e1..e03baca901e76 100644 +--- a/kernel/irq/irqdomain.c ++++ b/kernel/irq/irqdomain.c +@@ -182,9 +182,7 @@ static struct irq_domain *__irq_domain_create(struct fwnode_handle *fwnode, + return NULL; + } + +- strreplace(name, '/', ':'); +- +- domain->name = name; ++ domain->name = strreplace(name, '/', ':'); + domain->fwnode = fwnode; + domain->flags |= IRQ_DOMAIN_NAME_ALLOCATED; + } +-- +2.43.0 + diff --git a/queue-6.1/leds-trigger-call-synchronize_rcu-before-calling-tri.patch b/queue-6.1/leds-trigger-call-synchronize_rcu-before-calling-tri.patch new file mode 100644 index 00000000000..d854288a2a3 --- /dev/null +++ b/queue-6.1/leds-trigger-call-synchronize_rcu-before-calling-tri.patch @@ -0,0 +1,60 @@ +From 67f293b9da62af08280dbb84887bee012aacd942 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 31 May 2024 14:01:24 +0200 +Subject: leds: trigger: Call synchronize_rcu() before calling trig->activate() + +From: Hans de Goede + +[ Upstream commit b1bbd20f35e19774ea01989320495e09ac44fba3 ] + +Some triggers call led_trigger_event() from their activate() callback +to initialize the brightness of the LED for which the trigger is being +activated. + +In order for the LED's initial state to be set correctly this requires that +the led_trigger_event() call uses the new version of trigger->led_cdevs, +which has the new LED. + +AFAICT led_trigger_event() will always use the new version when it is +running on the same CPU as where the list_add_tail_rcu() call was made, +which is why the missing synchronize_rcu() has not lead to bug reports. +But if activate() is pre-empted, sleeps or uses a worker then +the led_trigger_event() call may run on another CPU which may still use +the old trigger->led_cdevs list. + +Add a synchronize_rcu() call to ensure that any led_trigger_event() calls +done from activate() always use the new list. + +Triggers using led_trigger_event() from their activate() callback are: +net/bluetooth/leds.c, net/rfkill/core.c and drivers/tty/vt/keyboard.c. + +Signed-off-by: Hans de Goede +Link: https://lore.kernel.org/r/20240531120124.75662-1-hdegoede@redhat.com +Signed-off-by: Lee Jones +Stable-dep-of: ab477b766edd ("leds: triggers: Flush pending brightness before activating trigger") +Signed-off-by: Sasha Levin +--- + drivers/leds/led-triggers.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/leds/led-triggers.c b/drivers/leds/led-triggers.c +index cdb446cb84af2..fe7fb2e7149c5 100644 +--- a/drivers/leds/led-triggers.c ++++ b/drivers/leds/led-triggers.c +@@ -193,6 +193,13 @@ int led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trig) + spin_unlock(&trig->leddev_list_lock); + led_cdev->trigger = trig; + ++ /* ++ * Some activate() calls use led_trigger_event() to initialize ++ * the brightness of the LED for which the trigger is being set. ++ * Ensure the led_cdev is visible on trig->led_cdevs for this. ++ */ ++ synchronize_rcu(); ++ + ret = 0; + if (trig->activate) + ret = trig->activate(led_cdev); +-- +2.43.0 + diff --git a/queue-6.1/leds-trigger-remove-unused-function-led_trigger_rena.patch b/queue-6.1/leds-trigger-remove-unused-function-led_trigger_rena.patch new file mode 100644 index 00000000000..c3f16683424 --- /dev/null +++ b/queue-6.1/leds-trigger-remove-unused-function-led_trigger_rena.patch @@ -0,0 +1,77 @@ +From a08d090901ca83b148970d6d9a1f9aef60767a7e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 8 Dec 2023 23:56:41 +0100 +Subject: leds: trigger: Remove unused function led_trigger_rename_static() + +From: Heiner Kallweit + +[ Upstream commit c82a1662d4548c454de5343b88f69b9fc82266b3 ] + +This function was added with a8df7b1ab70b ("leds: add led_trigger_rename +function") 11 yrs ago, but it has no users. So remove it. + +Signed-off-by: Heiner Kallweit +Link: https://lore.kernel.org/r/d90f30be-f661-4db7-b0b5-d09d07a78a68@gmail.com +Signed-off-by: Lee Jones +Stable-dep-of: ab477b766edd ("leds: triggers: Flush pending brightness before activating trigger") +Signed-off-by: Sasha Levin +--- + drivers/leds/led-triggers.c | 13 ------------- + include/linux/leds.h | 17 ----------------- + 2 files changed, 30 deletions(-) + +diff --git a/drivers/leds/led-triggers.c b/drivers/leds/led-triggers.c +index 024b73f84ce0c..dddfc301d3414 100644 +--- a/drivers/leds/led-triggers.c ++++ b/drivers/leds/led-triggers.c +@@ -268,19 +268,6 @@ void led_trigger_set_default(struct led_classdev *led_cdev) + } + EXPORT_SYMBOL_GPL(led_trigger_set_default); + +-void led_trigger_rename_static(const char *name, struct led_trigger *trig) +-{ +- /* new name must be on a temporary string to prevent races */ +- BUG_ON(name == trig->name); +- +- down_write(&triggers_list_lock); +- /* this assumes that trig->name was originaly allocated to +- * non constant storage */ +- strcpy((char *)trig->name, name); +- up_write(&triggers_list_lock); +-} +-EXPORT_SYMBOL_GPL(led_trigger_rename_static); +- + /* LED Trigger Interface */ + + int led_trigger_register(struct led_trigger *trig) +diff --git a/include/linux/leds.h b/include/linux/leds.h +index ba4861ec73d30..2bbff7519b731 100644 +--- a/include/linux/leds.h ++++ b/include/linux/leds.h +@@ -409,23 +409,6 @@ static inline void *led_get_trigger_data(struct led_classdev *led_cdev) + return led_cdev->trigger_data; + } + +-/** +- * led_trigger_rename_static - rename a trigger +- * @name: the new trigger name +- * @trig: the LED trigger to rename +- * +- * Change a LED trigger name by copying the string passed in +- * name into current trigger name, which MUST be large +- * enough for the new string. +- * +- * Note that name must NOT point to the same string used +- * during LED registration, as that could lead to races. +- * +- * This is meant to be used on triggers with statically +- * allocated name. +- */ +-void led_trigger_rename_static(const char *name, struct led_trigger *trig); +- + #define module_led_trigger(__led_trigger) \ + module_driver(__led_trigger, led_trigger_register, \ + led_trigger_unregister) +-- +2.43.0 + diff --git a/queue-6.1/leds-trigger-store-brightness-set-by-led_trigger_eve.patch b/queue-6.1/leds-trigger-store-brightness-set-by-led_trigger_eve.patch new file mode 100644 index 00000000000..a8e74da0e9a --- /dev/null +++ b/queue-6.1/leds-trigger-store-brightness-set-by-led_trigger_eve.patch @@ -0,0 +1,98 @@ +From c149da8d9db43c4a715739a3d7bb9ecc26af186f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 4 Mar 2024 21:57:30 +0100 +Subject: leds: trigger: Store brightness set by led_trigger_event() + +From: Heiner Kallweit + +[ Upstream commit 822c91e72eac568ed8d83765634f00decb45666c ] + +If a simple trigger is assigned to a LED, then the LED may be off until +the next led_trigger_event() call. This may be an issue for simple +triggers with rare led_trigger_event() calls, e.g. power supply +charging indicators (drivers/power/supply/power_supply_leds.c). +Therefore persist the brightness value of the last led_trigger_event() +call and use this value if the trigger is assigned to a LED. +In addition add a getter for the trigger brightness value. + +Signed-off-by: Heiner Kallweit +Reviewed-by: Takashi Iwai +Link: https://lore.kernel.org/r/b1358b25-3f30-458d-8240-5705ae007a8a@gmail.com +Signed-off-by: Lee Jones +Stable-dep-of: ab477b766edd ("leds: triggers: Flush pending brightness before activating trigger") +Signed-off-by: Sasha Levin +--- + drivers/leds/led-triggers.c | 6 ++++-- + include/linux/leds.h | 15 +++++++++++++++ + 2 files changed, 19 insertions(+), 2 deletions(-) + +diff --git a/drivers/leds/led-triggers.c b/drivers/leds/led-triggers.c +index dddfc301d3414..cdb446cb84af2 100644 +--- a/drivers/leds/led-triggers.c ++++ b/drivers/leds/led-triggers.c +@@ -193,11 +193,11 @@ int led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trig) + spin_unlock(&trig->leddev_list_lock); + led_cdev->trigger = trig; + ++ ret = 0; + if (trig->activate) + ret = trig->activate(led_cdev); + else +- ret = 0; +- ++ led_set_brightness(led_cdev, trig->brightness); + if (ret) + goto err_activate; + +@@ -372,6 +372,8 @@ void led_trigger_event(struct led_trigger *trig, + if (!trig) + return; + ++ trig->brightness = brightness; ++ + rcu_read_lock(); + list_for_each_entry_rcu(led_cdev, &trig->led_cdevs, trig_list) + led_set_brightness(led_cdev, brightness); +diff --git a/include/linux/leds.h b/include/linux/leds.h +index 2bbff7519b731..79ab2dfd3c72f 100644 +--- a/include/linux/leds.h ++++ b/include/linux/leds.h +@@ -356,6 +356,9 @@ struct led_trigger { + int (*activate)(struct led_classdev *led_cdev); + void (*deactivate)(struct led_classdev *led_cdev); + ++ /* Brightness set by led_trigger_event */ ++ enum led_brightness brightness; ++ + /* LED-private triggers have this set */ + struct led_hw_trigger_type *trigger_type; + +@@ -409,6 +412,12 @@ static inline void *led_get_trigger_data(struct led_classdev *led_cdev) + return led_cdev->trigger_data; + } + ++static inline enum led_brightness ++led_trigger_get_brightness(const struct led_trigger *trigger) ++{ ++ return trigger ? trigger->brightness : LED_OFF; ++} ++ + #define module_led_trigger(__led_trigger) \ + module_driver(__led_trigger, led_trigger_register, \ + led_trigger_unregister) +@@ -445,6 +454,12 @@ static inline void *led_get_trigger_data(struct led_classdev *led_cdev) + return NULL; + } + ++static inline enum led_brightness ++led_trigger_get_brightness(const struct led_trigger *trigger) ++{ ++ return LED_OFF; ++} ++ + #endif /* CONFIG_LEDS_TRIGGERS */ + + /* Trigger specific functions */ +-- +2.43.0 + diff --git a/queue-6.1/leds-triggers-flush-pending-brightness-before-activa.patch b/queue-6.1/leds-triggers-flush-pending-brightness-before-activa.patch new file mode 100644 index 00000000000..e145dc720c5 --- /dev/null +++ b/queue-6.1/leds-triggers-flush-pending-brightness-before-activa.patch @@ -0,0 +1,66 @@ +From 798aeb2d5853ac8f89476db89a455f965ee6be6e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 13 Jun 2024 17:24:51 +0200 +Subject: leds: triggers: Flush pending brightness before activating trigger +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Thomas Weißschuh + +[ Upstream commit ab477b766edd3bfb6321a6e3df4c790612613fae ] + +The race fixed in timer_trig_activate() between a blocking +set_brightness() call and trigger->activate() can affect any trigger. +So move the call to flush_work() into led_trigger_set() where it can +avoid the race for all triggers. + +Fixes: 0db37915d912 ("leds: avoid races with workqueue") +Fixes: 8c0f693c6eff ("leds: avoid flush_work in atomic context") +Cc: stable@vger.kernel.org +Tested-by: Dustin L. Howett +Signed-off-by: Thomas Weißschuh +Link: https://lore.kernel.org/r/20240613-led-trigger-flush-v2-1-f4f970799d77@weissschuh.net +Signed-off-by: Lee Jones +Signed-off-by: Sasha Levin +--- + drivers/leds/led-triggers.c | 6 ++++++ + drivers/leds/trigger/ledtrig-timer.c | 5 ----- + 2 files changed, 6 insertions(+), 5 deletions(-) + +diff --git a/drivers/leds/led-triggers.c b/drivers/leds/led-triggers.c +index fe7fb2e7149c5..3d3673c197e38 100644 +--- a/drivers/leds/led-triggers.c ++++ b/drivers/leds/led-triggers.c +@@ -200,6 +200,12 @@ int led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trig) + */ + synchronize_rcu(); + ++ /* ++ * If "set brightness to 0" is pending in workqueue, ++ * we don't want that to be reordered after ->activate() ++ */ ++ flush_work(&led_cdev->set_brightness_work); ++ + ret = 0; + if (trig->activate) + ret = trig->activate(led_cdev); +diff --git a/drivers/leds/trigger/ledtrig-timer.c b/drivers/leds/trigger/ledtrig-timer.c +index b4688d1d9d2b2..1d213c999d40a 100644 +--- a/drivers/leds/trigger/ledtrig-timer.c ++++ b/drivers/leds/trigger/ledtrig-timer.c +@@ -110,11 +110,6 @@ static int timer_trig_activate(struct led_classdev *led_cdev) + led_cdev->flags &= ~LED_INIT_DEFAULT_TRIGGER; + } + +- /* +- * If "set brightness to 0" is pending in workqueue, we don't +- * want that to be reordered after blink_set() +- */ +- flush_work(&led_cdev->set_brightness_work); + led_blink_set(led_cdev, &led_cdev->blink_delay_on, + &led_cdev->blink_delay_off); + +-- +2.43.0 + diff --git a/queue-6.1/mips-dts-loongson-fix-liointc-irq-polarity.patch b/queue-6.1/mips-dts-loongson-fix-liointc-irq-polarity.patch new file mode 100644 index 00000000000..c6085ce34c5 --- /dev/null +++ b/queue-6.1/mips-dts-loongson-fix-liointc-irq-polarity.patch @@ -0,0 +1,172 @@ +From 68059f4dafdd45336f5c8e3dc1ea7f65290d1aab Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 14 Jun 2024 16:40:10 +0100 +Subject: MIPS: dts: loongson: Fix liointc IRQ polarity + +From: Jiaxun Yang + +[ Upstream commit dbb69b9d6234aad23b3ecd33e5bc8a8ae1485b7d ] + +All internal liointc interrupts are high level triggered. + +Fixes: b1a792601f26 ("MIPS: Loongson64: DeviceTree for Loongson-2K1000") +Cc: stable@vger.kernel.org +Signed-off-by: Jiaxun Yang +Signed-off-by: Thomas Bogendoerfer +Signed-off-by: Sasha Levin +--- + .../boot/dts/loongson/loongson64-2k1000.dtsi | 42 +++++++++---------- + 1 file changed, 21 insertions(+), 21 deletions(-) + +diff --git a/arch/mips/boot/dts/loongson/loongson64-2k1000.dtsi b/arch/mips/boot/dts/loongson/loongson64-2k1000.dtsi +index c1d3092fdd870..eec8243be6499 100644 +--- a/arch/mips/boot/dts/loongson/loongson64-2k1000.dtsi ++++ b/arch/mips/boot/dts/loongson/loongson64-2k1000.dtsi +@@ -100,7 +100,7 @@ rtc0: rtc@1fe07800 { + compatible = "loongson,ls2k1000-rtc"; + reg = <0 0x1fe07800 0 0x78>; + interrupt-parent = <&liointc0>; +- interrupts = <60 IRQ_TYPE_LEVEL_LOW>; ++ interrupts = <60 IRQ_TYPE_LEVEL_HIGH>; + }; + + uart0: serial@1fe00000 { +@@ -108,7 +108,7 @@ uart0: serial@1fe00000 { + reg = <0 0x1fe00000 0 0x8>; + clock-frequency = <125000000>; + interrupt-parent = <&liointc0>; +- interrupts = <0 IRQ_TYPE_LEVEL_LOW>; ++ interrupts = <0 IRQ_TYPE_LEVEL_HIGH>; + no-loopback-test; + }; + +@@ -131,8 +131,8 @@ gmac@3,0 { + "pciclass0c03"; + + reg = <0x1800 0x0 0x0 0x0 0x0>; +- interrupts = <12 IRQ_TYPE_LEVEL_LOW>, +- <13 IRQ_TYPE_LEVEL_LOW>; ++ interrupts = <12 IRQ_TYPE_LEVEL_HIGH>, ++ <13 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "macirq", "eth_lpi"; + interrupt-parent = <&liointc0>; + phy-mode = "rgmii-id"; +@@ -155,8 +155,8 @@ gmac@3,1 { + "loongson, pci-gmac"; + + reg = <0x1900 0x0 0x0 0x0 0x0>; +- interrupts = <14 IRQ_TYPE_LEVEL_LOW>, +- <15 IRQ_TYPE_LEVEL_LOW>; ++ interrupts = <14 IRQ_TYPE_LEVEL_HIGH>, ++ <15 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "macirq", "eth_lpi"; + interrupt-parent = <&liointc0>; + phy-mode = "rgmii-id"; +@@ -178,7 +178,7 @@ ehci@4,1 { + "pciclass0c03"; + + reg = <0x2100 0x0 0x0 0x0 0x0>; +- interrupts = <18 IRQ_TYPE_LEVEL_LOW>; ++ interrupts = <18 IRQ_TYPE_LEVEL_HIGH>; + interrupt-parent = <&liointc1>; + }; + +@@ -189,7 +189,7 @@ ohci@4,2 { + "pciclass0c03"; + + reg = <0x2200 0x0 0x0 0x0 0x0>; +- interrupts = <19 IRQ_TYPE_LEVEL_LOW>; ++ interrupts = <19 IRQ_TYPE_LEVEL_HIGH>; + interrupt-parent = <&liointc1>; + }; + +@@ -200,7 +200,7 @@ sata@8,0 { + "pciclass0106"; + + reg = <0x4000 0x0 0x0 0x0 0x0>; +- interrupts = <19 IRQ_TYPE_LEVEL_LOW>; ++ interrupts = <19 IRQ_TYPE_LEVEL_HIGH>; + interrupt-parent = <&liointc0>; + }; + +@@ -215,10 +215,10 @@ pcie@9,0 { + #size-cells = <2>; + device_type = "pci"; + #interrupt-cells = <1>; +- interrupts = <0 IRQ_TYPE_LEVEL_LOW>; ++ interrupts = <0 IRQ_TYPE_LEVEL_HIGH>; + interrupt-parent = <&liointc1>; + interrupt-map-mask = <0 0 0 0>; +- interrupt-map = <0 0 0 0 &liointc1 0 IRQ_TYPE_LEVEL_LOW>; ++ interrupt-map = <0 0 0 0 &liointc1 0 IRQ_TYPE_LEVEL_HIGH>; + ranges; + external-facing; + }; +@@ -234,10 +234,10 @@ pcie@a,0 { + #size-cells = <2>; + device_type = "pci"; + #interrupt-cells = <1>; +- interrupts = <1 IRQ_TYPE_LEVEL_LOW>; ++ interrupts = <1 IRQ_TYPE_LEVEL_HIGH>; + interrupt-parent = <&liointc1>; + interrupt-map-mask = <0 0 0 0>; +- interrupt-map = <0 0 0 0 &liointc1 1 IRQ_TYPE_LEVEL_LOW>; ++ interrupt-map = <0 0 0 0 &liointc1 1 IRQ_TYPE_LEVEL_HIGH>; + ranges; + external-facing; + }; +@@ -253,10 +253,10 @@ pcie@b,0 { + #size-cells = <2>; + device_type = "pci"; + #interrupt-cells = <1>; +- interrupts = <2 IRQ_TYPE_LEVEL_LOW>; ++ interrupts = <2 IRQ_TYPE_LEVEL_HIGH>; + interrupt-parent = <&liointc1>; + interrupt-map-mask = <0 0 0 0>; +- interrupt-map = <0 0 0 0 &liointc1 2 IRQ_TYPE_LEVEL_LOW>; ++ interrupt-map = <0 0 0 0 &liointc1 2 IRQ_TYPE_LEVEL_HIGH>; + ranges; + external-facing; + }; +@@ -272,10 +272,10 @@ pcie@c,0 { + #size-cells = <2>; + device_type = "pci"; + #interrupt-cells = <1>; +- interrupts = <3 IRQ_TYPE_LEVEL_LOW>; ++ interrupts = <3 IRQ_TYPE_LEVEL_HIGH>; + interrupt-parent = <&liointc1>; + interrupt-map-mask = <0 0 0 0>; +- interrupt-map = <0 0 0 0 &liointc1 3 IRQ_TYPE_LEVEL_LOW>; ++ interrupt-map = <0 0 0 0 &liointc1 3 IRQ_TYPE_LEVEL_HIGH>; + ranges; + external-facing; + }; +@@ -291,10 +291,10 @@ pcie@d,0 { + #size-cells = <2>; + device_type = "pci"; + #interrupt-cells = <1>; +- interrupts = <4 IRQ_TYPE_LEVEL_LOW>; ++ interrupts = <4 IRQ_TYPE_LEVEL_HIGH>; + interrupt-parent = <&liointc1>; + interrupt-map-mask = <0 0 0 0>; +- interrupt-map = <0 0 0 0 &liointc1 4 IRQ_TYPE_LEVEL_LOW>; ++ interrupt-map = <0 0 0 0 &liointc1 4 IRQ_TYPE_LEVEL_HIGH>; + ranges; + external-facing; + }; +@@ -310,10 +310,10 @@ pcie@e,0 { + #size-cells = <2>; + device_type = "pci"; + #interrupt-cells = <1>; +- interrupts = <5 IRQ_TYPE_LEVEL_LOW>; ++ interrupts = <5 IRQ_TYPE_LEVEL_HIGH>; + interrupt-parent = <&liointc1>; + interrupt-map-mask = <0 0 0 0>; +- interrupt-map = <0 0 0 0 &liointc1 5 IRQ_TYPE_LEVEL_LOW>; ++ interrupt-map = <0 0 0 0 &liointc1 5 IRQ_TYPE_LEVEL_HIGH>; + ranges; + external-facing; + }; +-- +2.43.0 + diff --git a/queue-6.1/mips-dts-loongson-fix-ls2k1000-rtc-interrupt.patch b/queue-6.1/mips-dts-loongson-fix-ls2k1000-rtc-interrupt.patch new file mode 100644 index 00000000000..0bfb762b3cd --- /dev/null +++ b/queue-6.1/mips-dts-loongson-fix-ls2k1000-rtc-interrupt.patch @@ -0,0 +1,38 @@ +From 281d66564ecb9d1452542e25bd67443e14b7bb32 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 14 Jun 2024 16:40:11 +0100 +Subject: MIPS: dts: loongson: Fix ls2k1000-rtc interrupt + +From: Jiaxun Yang + +[ Upstream commit f70fd92df7529e7283e02a6c3a2510075f13ba30 ] + +The correct interrupt line for RTC is line 8 on liointc1. + +Fixes: e47084e116fc ("MIPS: Loongson64: DTS: Add RTC support to Loongson-2K1000") +Cc: stable@vger.kernel.org +Signed-off-by: Jiaxun Yang +Signed-off-by: Thomas Bogendoerfer +Signed-off-by: Sasha Levin +--- + arch/mips/boot/dts/loongson/loongson64-2k1000.dtsi | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/mips/boot/dts/loongson/loongson64-2k1000.dtsi b/arch/mips/boot/dts/loongson/loongson64-2k1000.dtsi +index eec8243be6499..cc7747c5f21f3 100644 +--- a/arch/mips/boot/dts/loongson/loongson64-2k1000.dtsi ++++ b/arch/mips/boot/dts/loongson/loongson64-2k1000.dtsi +@@ -99,8 +99,8 @@ liointc1: interrupt-controller@1fe11440 { + rtc0: rtc@1fe07800 { + compatible = "loongson,ls2k1000-rtc"; + reg = <0 0x1fe07800 0 0x78>; +- interrupt-parent = <&liointc0>; +- interrupts = <60 IRQ_TYPE_LEVEL_HIGH>; ++ interrupt-parent = <&liointc1>; ++ interrupts = <8 IRQ_TYPE_LEVEL_HIGH>; + }; + + uart0: serial@1fe00000 { +-- +2.43.0 + diff --git a/queue-6.1/mips-loongson64-dts-add-rtc-support-to-loongson-2k10.patch b/queue-6.1/mips-loongson64-dts-add-rtc-support-to-loongson-2k10.patch new file mode 100644 index 00000000000..a899f8e94ab --- /dev/null +++ b/queue-6.1/mips-loongson64-dts-add-rtc-support-to-loongson-2k10.patch @@ -0,0 +1,42 @@ +From 296c4889df72ddd4565cd795e5ae170991c9d154 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 2 Jun 2023 17:50:50 +0800 +Subject: MIPS: Loongson64: DTS: Add RTC support to Loongson-2K1000 + +From: Binbin Zhou + +[ Upstream commit e47084e116fccaa43644360d7c0b997979abce3e ] + +The module is now supported, enable it. + +Acked-by: Jiaxun Yang +Signed-off-by: Binbin Zhou +Signed-off-by: WANG Xuerui +Signed-off-by: Thomas Bogendoerfer +Stable-dep-of: dbb69b9d6234 ("MIPS: dts: loongson: Fix liointc IRQ polarity") +Signed-off-by: Sasha Levin +--- + arch/mips/boot/dts/loongson/loongson64-2k1000.dtsi | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/arch/mips/boot/dts/loongson/loongson64-2k1000.dtsi b/arch/mips/boot/dts/loongson/loongson64-2k1000.dtsi +index 9089d1e4f3fee..c0be84a6e81fd 100644 +--- a/arch/mips/boot/dts/loongson/loongson64-2k1000.dtsi ++++ b/arch/mips/boot/dts/loongson/loongson64-2k1000.dtsi +@@ -96,6 +96,13 @@ liointc1: interrupt-controller@1fe11440 { + <0x00000000>; /* int3 */ + }; + ++ rtc0: rtc@1fe07800 { ++ compatible = "loongson,ls2k1000-rtc"; ++ reg = <0 0x1fe07800 0 0x78>; ++ interrupt-parent = <&liointc0>; ++ interrupts = <60 IRQ_TYPE_LEVEL_LOW>; ++ }; ++ + uart0: serial@1fe00000 { + compatible = "ns16550a"; + reg = <0 0x1fe00000 0 0x8>; +-- +2.43.0 + diff --git a/queue-6.1/mips-loongson64-dts-fix-pcie-port-nodes-for-ls7a.patch b/queue-6.1/mips-loongson64-dts-fix-pcie-port-nodes-for-ls7a.patch new file mode 100644 index 00000000000..c34b575cceb --- /dev/null +++ b/queue-6.1/mips-loongson64-dts-fix-pcie-port-nodes-for-ls7a.patch @@ -0,0 +1,161 @@ +From 4423d6e7e4c5da7d588124b8f7fbf568774b391e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 May 2024 19:51:22 +0100 +Subject: MIPS: Loongson64: DTS: Fix PCIe port nodes for ls7a + +From: Jiaxun Yang + +[ Upstream commit d89a415ff8d5e0aad4963f2d8ebb0f9e8110b7fa ] + +Add various required properties to silent warnings: + +arch/mips/boot/dts/loongson/loongson64-2k1000.dtsi:116.16-297.5: Warning (interrupt_provider): /bus@10000000/pci@1a000000: '#interrupt-cells' found, but node is not an interrupt provider +arch/mips/boot/dts/loongson/loongson64_2core_2k1000.dtb: Warning (interrupt_map): Failed prerequisite 'interrupt_provider' + +Signed-off-by: Jiaxun Yang +Signed-off-by: Thomas Bogendoerfer +Stable-dep-of: dbb69b9d6234 ("MIPS: dts: loongson: Fix liointc IRQ polarity") +Signed-off-by: Sasha Levin +--- + .../boot/dts/loongson/loongson64-2k1000.dtsi | 37 +++++++++++++++---- + 1 file changed, 30 insertions(+), 7 deletions(-) + +diff --git a/arch/mips/boot/dts/loongson/loongson64-2k1000.dtsi b/arch/mips/boot/dts/loongson/loongson64-2k1000.dtsi +index c0be84a6e81fd..c1d3092fdd870 100644 +--- a/arch/mips/boot/dts/loongson/loongson64-2k1000.dtsi ++++ b/arch/mips/boot/dts/loongson/loongson64-2k1000.dtsi +@@ -117,7 +117,6 @@ pci@1a000000 { + device_type = "pci"; + #address-cells = <3>; + #size-cells = <2>; +- #interrupt-cells = <2>; + + reg = <0 0x1a000000 0 0x02000000>, + <0xfe 0x00000000 0 0x20000000>; +@@ -205,93 +204,117 @@ sata@8,0 { + interrupt-parent = <&liointc0>; + }; + +- pci_bridge@9,0 { ++ pcie@9,0 { + compatible = "pci0014,7a19.0", + "pci0014,7a19", + "pciclass060400", + "pciclass0604"; + + reg = <0x4800 0x0 0x0 0x0 0x0>; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ device_type = "pci"; + #interrupt-cells = <1>; + interrupts = <0 IRQ_TYPE_LEVEL_LOW>; + interrupt-parent = <&liointc1>; + interrupt-map-mask = <0 0 0 0>; + interrupt-map = <0 0 0 0 &liointc1 0 IRQ_TYPE_LEVEL_LOW>; ++ ranges; + external-facing; + }; + +- pci_bridge@a,0 { ++ pcie@a,0 { + compatible = "pci0014,7a09.0", + "pci0014,7a09", + "pciclass060400", + "pciclass0604"; + + reg = <0x5000 0x0 0x0 0x0 0x0>; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ device_type = "pci"; + #interrupt-cells = <1>; + interrupts = <1 IRQ_TYPE_LEVEL_LOW>; + interrupt-parent = <&liointc1>; + interrupt-map-mask = <0 0 0 0>; + interrupt-map = <0 0 0 0 &liointc1 1 IRQ_TYPE_LEVEL_LOW>; ++ ranges; + external-facing; + }; + +- pci_bridge@b,0 { ++ pcie@b,0 { + compatible = "pci0014,7a09.0", + "pci0014,7a09", + "pciclass060400", + "pciclass0604"; + + reg = <0x5800 0x0 0x0 0x0 0x0>; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ device_type = "pci"; + #interrupt-cells = <1>; + interrupts = <2 IRQ_TYPE_LEVEL_LOW>; + interrupt-parent = <&liointc1>; + interrupt-map-mask = <0 0 0 0>; + interrupt-map = <0 0 0 0 &liointc1 2 IRQ_TYPE_LEVEL_LOW>; ++ ranges; + external-facing; + }; + +- pci_bridge@c,0 { ++ pcie@c,0 { + compatible = "pci0014,7a09.0", + "pci0014,7a09", + "pciclass060400", + "pciclass0604"; + + reg = <0x6000 0x0 0x0 0x0 0x0>; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ device_type = "pci"; + #interrupt-cells = <1>; + interrupts = <3 IRQ_TYPE_LEVEL_LOW>; + interrupt-parent = <&liointc1>; + interrupt-map-mask = <0 0 0 0>; + interrupt-map = <0 0 0 0 &liointc1 3 IRQ_TYPE_LEVEL_LOW>; ++ ranges; + external-facing; + }; + +- pci_bridge@d,0 { ++ pcie@d,0 { + compatible = "pci0014,7a19.0", + "pci0014,7a19", + "pciclass060400", + "pciclass0604"; + + reg = <0x6800 0x0 0x0 0x0 0x0>; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ device_type = "pci"; + #interrupt-cells = <1>; + interrupts = <4 IRQ_TYPE_LEVEL_LOW>; + interrupt-parent = <&liointc1>; + interrupt-map-mask = <0 0 0 0>; + interrupt-map = <0 0 0 0 &liointc1 4 IRQ_TYPE_LEVEL_LOW>; ++ ranges; + external-facing; + }; + +- pci_bridge@e,0 { ++ pcie@e,0 { + compatible = "pci0014,7a09.0", + "pci0014,7a09", + "pciclass060400", + "pciclass0604"; + + reg = <0x7000 0x0 0x0 0x0 0x0>; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ device_type = "pci"; + #interrupt-cells = <1>; + interrupts = <5 IRQ_TYPE_LEVEL_LOW>; + interrupt-parent = <&liointc1>; + interrupt-map-mask = <0 0 0 0>; + interrupt-map = <0 0 0 0 &liointc1 5 IRQ_TYPE_LEVEL_LOW>; ++ ranges; + external-facing; + }; + +-- +2.43.0 + diff --git a/queue-6.1/mm-page_alloc-control-latency-caused-by-zone-pcp-dra.patch b/queue-6.1/mm-page_alloc-control-latency-caused-by-zone-pcp-dra.patch new file mode 100644 index 00000000000..a25281df17f --- /dev/null +++ b/queue-6.1/mm-page_alloc-control-latency-caused-by-zone-pcp-dra.patch @@ -0,0 +1,118 @@ +From 458b05c581cf671aa8ed527858c142ba78ebf8c0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 18 Mar 2024 21:07:36 +0100 +Subject: mm: page_alloc: control latency caused by zone PCP draining + +From: Lucas Stach + +[ Upstream commit 55f77df7d715110299f12c27f4365bd6332d1adb ] + +Patch series "mm/treewide: Remove pXd_huge() API", v2. + +In previous work [1], we removed the pXd_large() API, which is arch +specific. This patchset further removes the hugetlb pXd_huge() API. + +Hugetlb was never special on creating huge mappings when compared with +other huge mappings. Having a standalone API just to detect such pgtable +entries is more or less redundant, especially after the pXd_leaf() API set +is introduced with/without CONFIG_HUGETLB_PAGE. + +When looking at this problem, a few issues are also exposed that we don't +have a clear definition of the *_huge() variance API. This patchset +started by cleaning these issues first, then replace all *_huge() users to +use *_leaf(), then drop all *_huge() code. + +On x86/sparc, swap entries will be reported "true" in pXd_huge(), while +for all the rest archs they're reported "false" instead. This part is +done in patch 1-5, in which I suspect patch 1 can be seen as a bug fix, +but I'll leave that to hmm experts to decide. + +Besides, there are three archs (arm, arm64, powerpc) that have slightly +different definitions between the *_huge() v.s. *_leaf() variances. I +tackled them separately so that it'll be easier for arch experts to chim +in when necessary. This part is done in patch 6-9. + +The final patches 10-14 do the rest on the final removal, since *_leaf() +will be the ultimate API in the future, and we seem to have quite some +confusions on how *_huge() APIs can be defined, provide a rich comment for +*_leaf() API set to define them properly to avoid future misuse, and +hopefully that'll also help new archs to start support huge mappings and +avoid traps (like either swap entries, or PROT_NONE entry checks). + +[1] https://lore.kernel.org/r/20240305043750.93762-1-peterx@redhat.com + +This patch (of 14): + +When the complete PCP is drained a much larger number of pages than the +usual batch size might be freed at once, causing large IRQ and preemption +latency spikes, as they are all freed while holding the pcp and zone +spinlocks. + +To avoid those latency spikes, limit the number of pages freed in a single +bulk operation to common batch limits. + +Link: https://lkml.kernel.org/r/20240318200404.448346-1-peterx@redhat.com +Link: https://lkml.kernel.org/r/20240318200736.2835502-1-l.stach@pengutronix.de +Signed-off-by: Lucas Stach +Signed-off-by: Peter Xu +Cc: Christophe Leroy +Cc: Jason Gunthorpe +Cc: "Matthew Wilcox (Oracle)" +Cc: Mike Rapoport (IBM) +Cc: Muchun Song +Cc: Alistair Popple +Cc: Andreas Larsson +Cc: "Aneesh Kumar K.V" +Cc: Arnd Bergmann +Cc: Bjorn Andersson +Cc: Borislav Petkov +Cc: Catalin Marinas +Cc: Dave Hansen +Cc: David S. Miller +Cc: Fabio Estevam +Cc: Ingo Molnar +Cc: Konrad Dybcio +Cc: Krzysztof Kozlowski +Cc: Mark Salter +Cc: Michael Ellerman +Cc: Naoya Horiguchi +Cc: "Naveen N. Rao" +Cc: Nicholas Piggin +Cc: Russell King +Cc: Shawn Guo +Cc: Thomas Gleixner +Cc: Will Deacon +Signed-off-by: Andrew Morton +Stable-dep-of: 66eca1021a42 ("mm/page_alloc: fix pcp->count race between drain_pages_zone() vs __rmqueue_pcplist()") +Signed-off-by: Sasha Levin +--- + mm/page_alloc.c | 11 +++++++---- + 1 file changed, 7 insertions(+), 4 deletions(-) + +diff --git a/mm/page_alloc.c b/mm/page_alloc.c +index 8eaf51257db5f..4029d13636ece 100644 +--- a/mm/page_alloc.c ++++ b/mm/page_alloc.c +@@ -3176,12 +3176,15 @@ void drain_zone_pages(struct zone *zone, struct per_cpu_pages *pcp) + */ + static void drain_pages_zone(unsigned int cpu, struct zone *zone) + { +- struct per_cpu_pages *pcp; ++ struct per_cpu_pages *pcp = per_cpu_ptr(zone->per_cpu_pageset, cpu); ++ int count = READ_ONCE(pcp->count); ++ ++ while (count) { ++ int to_drain = min(count, pcp->batch << CONFIG_PCP_BATCH_SCALE_MAX); ++ count -= to_drain; + +- pcp = per_cpu_ptr(zone->per_cpu_pageset, cpu); +- if (pcp->count) { + spin_lock(&pcp->lock); +- free_pcppages_bulk(zone, pcp->count, pcp, 0); ++ free_pcppages_bulk(zone, to_drain, pcp, 0); + spin_unlock(&pcp->lock); + } + } +-- +2.43.0 + diff --git a/queue-6.1/mm-page_alloc-fix-pcp-count-race-between-drain_pages.patch b/queue-6.1/mm-page_alloc-fix-pcp-count-race-between-drain_pages.patch new file mode 100644 index 00000000000..884d217cad6 --- /dev/null +++ b/queue-6.1/mm-page_alloc-fix-pcp-count-race-between-drain_pages.patch @@ -0,0 +1,99 @@ +From 1ca2834a9e51f776b251ede5bb86c7fcba7c7466 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 23 Jul 2024 14:44:28 +0800 +Subject: mm/page_alloc: fix pcp->count race between drain_pages_zone() vs + __rmqueue_pcplist() + +From: Li Zhijian + +[ Upstream commit 66eca1021a42856d6af2a9802c99e160278aed91 ] + +It's expected that no page should be left in pcp_list after calling +zone_pcp_disable() in offline_pages(). Previously, it's observed that +offline_pages() gets stuck [1] due to some pages remaining in pcp_list. + +Cause: +There is a race condition between drain_pages_zone() and __rmqueue_pcplist() +involving the pcp->count variable. See below scenario: + + CPU0 CPU1 + ---------------- --------------- + spin_lock(&pcp->lock); + __rmqueue_pcplist() { +zone_pcp_disable() { + /* list is empty */ + if (list_empty(list)) { + /* add pages to pcp_list */ + alloced = rmqueue_bulk() + mutex_lock(&pcp_batch_high_lock) + ... + __drain_all_pages() { + drain_pages_zone() { + /* read pcp->count, it's 0 here */ + count = READ_ONCE(pcp->count) + /* 0 means nothing to drain */ + /* update pcp->count */ + pcp->count += alloced << order; + ... + ... + spin_unlock(&pcp->lock); + +In this case, after calling zone_pcp_disable() though, there are still some +pages in pcp_list. And these pages in pcp_list are neither movable nor +isolated, offline_pages() gets stuck as a result. + +Solution: +Expand the scope of the pcp->lock to also protect pcp->count in +drain_pages_zone(), to ensure no pages are left in the pcp list after +zone_pcp_disable() + +[1] https://lore.kernel.org/linux-mm/6a07125f-e720-404c-b2f9-e55f3f166e85@fujitsu.com/ + +Link: https://lkml.kernel.org/r/20240723064428.1179519-1-lizhijian@fujitsu.com +Fixes: 4b23a68f9536 ("mm/page_alloc: protect PCP lists with a spinlock") +Signed-off-by: Li Zhijian +Reported-by: Yao Xingtao +Reviewed-by: Vlastimil Babka +Cc: David Hildenbrand +Cc: +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + mm/page_alloc.c | 18 +++++++++++------- + 1 file changed, 11 insertions(+), 7 deletions(-) + +diff --git a/mm/page_alloc.c b/mm/page_alloc.c +index 4029d13636ece..a905b850d31c4 100644 +--- a/mm/page_alloc.c ++++ b/mm/page_alloc.c +@@ -3177,16 +3177,20 @@ 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); +- int count = READ_ONCE(pcp->count); +- +- while (count) { +- int to_drain = min(count, pcp->batch << CONFIG_PCP_BATCH_SCALE_MAX); +- count -= to_drain; ++ int count; + ++ do { + spin_lock(&pcp->lock); +- free_pcppages_bulk(zone, to_drain, pcp, 0); ++ count = pcp->count; ++ if (count) { ++ int to_drain = min(count, ++ pcp->batch << CONFIG_PCP_BATCH_SCALE_MAX); ++ ++ free_pcppages_bulk(zone, to_drain, pcp, 0); ++ count -= to_drain; ++ } + spin_unlock(&pcp->lock); +- } ++ } while (count); + } + + /* +-- +2.43.0 + diff --git a/queue-6.1/mm-restrict-the-pcp-batch-scale-factor-to-avoid-too-.patch b/queue-6.1/mm-restrict-the-pcp-batch-scale-factor-to-avoid-too-.patch new file mode 100644 index 00000000000..feaff034181 --- /dev/null +++ b/queue-6.1/mm-restrict-the-pcp-batch-scale-factor-to-avoid-too-.patch @@ -0,0 +1,181 @@ +From 51188ccd359ebdfa65d97541fe77adad6c6417c6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Oct 2023 13:29:57 +0800 +Subject: mm: restrict the pcp batch scale factor to avoid too long latency + +From: Huang Ying + +[ Upstream commit 52166607ecc980391b1fffbce0be3074a96d0c7b ] + +In page allocator, PCP (Per-CPU Pageset) is refilled and drained in +batches to increase page allocation throughput, reduce page +allocation/freeing latency per page, and reduce zone lock contention. But +too large batch size will cause too long maximal allocation/freeing +latency, which may punish arbitrary users. So the default batch size is +chosen carefully (in zone_batchsize(), the value is 63 for zone > 1GB) to +avoid that. + +In commit 3b12e7e97938 ("mm/page_alloc: scale the number of pages that are +batch freed"), the batch size will be scaled for large number of page +freeing to improve page freeing performance and reduce zone lock +contention. Similar optimization can be used for large number of pages +allocation too. + +To find out a suitable max batch scale factor (that is, max effective +batch size), some tests and measurement on some machines were done as +follows. + +A set of debug patches are implemented as follows, + +- Set PCP high to be 2 * batch to reduce the effect of PCP high + +- Disable free batch size scaling to get the raw performance. + +- The code with zone lock held is extracted from rmqueue_bulk() and + free_pcppages_bulk() to 2 separate functions to make it easy to + measure the function run time with ftrace function_graph tracer. + +- The batch size is hard coded to be 63 (default), 127, 255, 511, + 1023, 2047, 4095. + +Then will-it-scale/page_fault1 is used to generate the page +allocation/freeing workload. The page allocation/freeing throughput +(page/s) is measured via will-it-scale. The page allocation/freeing +average latency (alloc/free latency avg, in us) and allocation/freeing +latency at 99 percentile (alloc/free latency 99%, in us) are measured with +ftrace function_graph tracer. + +The test results are as follows, + +Sapphire Rapids Server +====================== +Batch throughput free latency free latency alloc latency alloc latency + page/s avg / us 99% / us avg / us 99% / us +----- ---------- ------------ ------------ ------------- ------------- + 63 513633.4 2.33 3.57 2.67 6.83 + 127 517616.7 4.35 6.65 4.22 13.03 + 255 520822.8 8.29 13.32 7.52 25.24 + 511 524122.0 15.79 23.42 14.02 49.35 +1023 525980.5 30.25 44.19 25.36 94.88 +2047 526793.6 59.39 84.50 45.22 140.81 + +Ice Lake Server +=============== +Batch throughput free latency free latency alloc latency alloc latency + page/s avg / us 99% / us avg / us 99% / us +----- ---------- ------------ ------------ ------------- ------------- + 63 620210.3 2.21 3.68 2.02 4.35 + 127 627003.0 4.09 6.86 3.51 8.28 + 255 630777.5 7.70 13.50 6.17 15.97 + 511 633651.5 14.85 22.62 11.66 31.08 +1023 637071.1 28.55 42.02 20.81 54.36 +2047 638089.7 56.54 84.06 39.28 91.68 + +Cascade Lake Server +=================== +Batch throughput free latency free latency alloc latency alloc latency + page/s avg / us 99% / us avg / us 99% / us +----- ---------- ------------ ------------ ------------- ------------- + 63 404706.7 3.29 5.03 3.53 4.75 + 127 422475.2 6.12 9.09 6.36 8.76 + 255 411522.2 11.68 16.97 10.90 16.39 + 511 428124.1 22.54 31.28 19.86 32.25 +1023 414718.4 43.39 62.52 40.00 66.33 +2047 429848.7 86.64 120.34 71.14 106.08 + +Commet Lake Desktop +=================== +Batch throughput free latency free latency alloc latency alloc latency + page/s avg / us 99% / us avg / us 99% / us +----- ---------- ------------ ------------ ------------- ------------- + + 63 795183.13 2.18 3.55 2.03 3.05 + 127 803067.85 3.91 6.56 3.85 5.52 + 255 812771.10 7.35 10.80 7.14 10.20 + 511 817723.48 14.17 27.54 13.43 30.31 +1023 818870.19 27.72 40.10 27.89 46.28 + +Coffee Lake Desktop +=================== +Batch throughput free latency free latency alloc latency alloc latency + page/s avg / us 99% / us avg / us 99% / us +----- ---------- ------------ ------------ ------------- ------------- + 63 510542.8 3.13 4.40 2.48 3.43 + 127 514288.6 5.97 7.89 4.65 6.04 + 255 516889.7 11.86 15.58 8.96 12.55 + 511 519802.4 23.10 28.81 16.95 26.19 +1023 520802.7 45.30 52.51 33.19 45.95 +2047 519997.1 90.63 104.00 65.26 81.74 + +From the above data, to restrict the allocation/freeing latency to be less +than 100 us in most times, the max batch scale factor needs to be less +than or equal to 5. + +Although it is reasonable to use 5 as max batch scale factor for the +systems tested, there are also slower systems. Where smaller value should +be used to constrain the page allocation/freeing latency. + +So, in this patch, a new kconfig option (PCP_BATCH_SCALE_MAX) is added to +set the max batch scale factor. Whose default value is 5, and users can +reduce it when necessary. + +Link: https://lkml.kernel.org/r/20231016053002.756205-5-ying.huang@intel.com +Signed-off-by: "Huang, Ying" +Acked-by: Andrew Morton +Acked-by: Mel Gorman +Cc: Vlastimil Babka +Cc: David Hildenbrand +Cc: Johannes Weiner +Cc: Dave Hansen +Cc: Michal Hocko +Cc: Pavel Tatashin +Cc: Matthew Wilcox +Cc: Christoph Lameter +Cc: Arjan van de Ven +Cc: Sudeep Holla +Signed-off-by: Andrew Morton +Stable-dep-of: 66eca1021a42 ("mm/page_alloc: fix pcp->count race between drain_pages_zone() vs __rmqueue_pcplist()") +Signed-off-by: Sasha Levin +--- + mm/Kconfig | 11 +++++++++++ + mm/page_alloc.c | 2 +- + 2 files changed, 12 insertions(+), 1 deletion(-) + +diff --git a/mm/Kconfig b/mm/Kconfig +index 35109a4a2f7ce..a65145fe89f2b 100644 +--- a/mm/Kconfig ++++ b/mm/Kconfig +@@ -627,6 +627,17 @@ config HUGETLB_PAGE_SIZE_VARIABLE + config CONTIG_ALLOC + def_bool (MEMORY_ISOLATION && COMPACTION) || CMA + ++config PCP_BATCH_SCALE_MAX ++ int "Maximum scale factor of PCP (Per-CPU pageset) batch allocate/free" ++ default 5 ++ range 0 6 ++ help ++ In page allocator, PCP (Per-CPU pageset) is refilled and drained in ++ batches. The batch number is scaled automatically to improve page ++ allocation/free throughput. But too large scale factor may hurt ++ latency. This option sets the upper limit of scale factor to limit ++ the maximum latency. ++ + config PHYS_ADDR_T_64BIT + def_bool 64BIT + +diff --git a/mm/page_alloc.c b/mm/page_alloc.c +index 12412263d131e..8eaf51257db5f 100644 +--- a/mm/page_alloc.c ++++ b/mm/page_alloc.c +@@ -3389,7 +3389,7 @@ static int nr_pcp_free(struct per_cpu_pages *pcp, int high, int batch, + * freeing of pages without any allocation. + */ + batch <<= pcp->free_factor; +- if (batch < max_nr_free) ++ if (batch < max_nr_free && pcp->free_factor < CONFIG_PCP_BATCH_SCALE_MAX) + pcp->free_factor++; + batch = clamp(batch, min_nr_free, max_nr_free); + +-- +2.43.0 + diff --git a/queue-6.1/series b/queue-6.1/series new file mode 100644 index 00000000000..c8c16a50bd1 --- /dev/null +++ b/queue-6.1/series @@ -0,0 +1,37 @@ +arm64-dts-qcom-msm8998-switch-usb-qmp-phy-to-new-sty.patch +arm64-dts-qcom-msm8998-disable-ss-instance-in-parkmo.patch +arm64-dts-qcom-ipq8074-disable-ss-instance-in-parkmo.patch +sysctl-allow-change-system-v-ipc-sysctls-inside-ipc-.patch +sysctl-allow-to-change-limits-for-posix-messages-que.patch +sysctl-treewide-drop-unused-argument-ctl_table_root-.patch +sysctl-always-initialize-i_uid-i_gid.patch +ext4-make-ext4_es_insert_extent-return-void.patch +ext4-refactor-ext4_da_map_blocks.patch +ext4-convert-to-exclusive-lock-while-inserting-delal.patch +ext4-factor-out-a-common-helper-to-query-extent-map.patch +ext4-check-the-extent-status-again-before-inserting-.patch +cpufreq-qcom-nvmem-convert-to-platform-remove-callba.patch +cpufreq-qcom-nvmem-simplify-driver-data-allocation.patch +cpufreq-qcom-nvmem-fix-memory-leaks-in-probe-error-p.patch +leds-trigger-remove-unused-function-led_trigger_rena.patch +leds-trigger-store-brightness-set-by-led_trigger_eve.patch +leds-trigger-call-synchronize_rcu-before-calling-tri.patch +leds-triggers-flush-pending-brightness-before-activa.patch +mm-restrict-the-pcp-batch-scale-factor-to-avoid-too-.patch +mm-page_alloc-control-latency-caused-by-zone-pcp-dra.patch +mm-page_alloc-fix-pcp-count-race-between-drain_pages.patch +f2fs-fix-to-avoid-use-ssr-allocate-when-do-defragmen.patch +f2fs-assign-curseg_all_data_atgc-if-blkaddr-is-valid.patch +irqdomain-use-return-value-of-strreplace.patch +irqdomain-fixed-unbalanced-fwnode-get-and-put.patch +drm-udl-rename-struct-udl_drm_connector-to-struct-ud.patch +drm-udl-test-pixel-limit-in-mode-config-s-mode-valid.patch +drm-udl-use-usb-timeout-constant-when-reading-edid.patch +drm-udl-various-improvements-to-the-connector.patch +drm-udl-move-connector-to-modesetting-code.patch +drm-udl-remove-drm_connector_poll_hpd.patch +drm-i915-dp-don-t-switch-the-lttpr-mode-on-an-active.patch +mips-loongson64-dts-add-rtc-support-to-loongson-2k10.patch +mips-loongson64-dts-fix-pcie-port-nodes-for-ls7a.patch +mips-dts-loongson-fix-liointc-irq-polarity.patch +mips-dts-loongson-fix-ls2k1000-rtc-interrupt.patch diff --git a/queue-6.1/sysctl-allow-change-system-v-ipc-sysctls-inside-ipc-.patch b/queue-6.1/sysctl-allow-change-system-v-ipc-sysctls-inside-ipc-.patch new file mode 100644 index 00000000000..27714ba16eb --- /dev/null +++ b/queue-6.1/sysctl-allow-change-system-v-ipc-sysctls-inside-ipc-.patch @@ -0,0 +1,140 @@ +From 884df3a11b1cfd4e10bf9287c450052c9da7b56a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 15 Jan 2024 15:46:41 +0000 +Subject: sysctl: allow change system v ipc sysctls inside ipc namespace + +From: Alexey Gladkov + +[ Upstream commit 50ec499b9a43e46200c9f7b7d723ab2e4af540b3 ] + +Patch series "Allow to change ipc/mq sysctls inside ipc namespace", v3. + +Right now ipc and mq limits count as per ipc namespace, but only real root +can change them. By default, the current values of these limits are such +that it can only be reduced. Since only root can change the values, it is +impossible to reduce these limits in the rootless container. + +We can allow limit changes within ipc namespace because mq parameters are +limited by RLIMIT_MSGQUEUE and ipc parameters are not limited to anything +other than cgroups. + +This patch (of 3): + +Rootless containers are not allowed to modify kernel IPC parameters. + +All default limits are set to such high values that in fact there are no +limits at all. All limits are not inherited and are initialized to +default values when a new ipc_namespace is created. + +For new ipc_namespace: + +size_t ipc_ns.shm_ctlmax = SHMMAX; // (ULONG_MAX - (1UL << 24)) +size_t ipc_ns.shm_ctlall = SHMALL; // (ULONG_MAX - (1UL << 24)) +int ipc_ns.shm_ctlmni = IPCMNI; // (1 << 15) +int ipc_ns.shm_rmid_forced = 0; +unsigned int ipc_ns.msg_ctlmax = MSGMAX; // 8192 +unsigned int ipc_ns.msg_ctlmni = MSGMNI; // 32000 +unsigned int ipc_ns.msg_ctlmnb = MSGMNB; // 16384 + +The shm_tot (total amount of shared pages) has also ceased to be global, +it is located in ipc_namespace and is not inherited from anywhere. + +In such conditions, it cannot be said that these limits limit anything. +The real limiter for them is cgroups. + +If we allow rootless containers to change these parameters, then it can +only be reduced. + +Link: https://lkml.kernel.org/r/cover.1705333426.git.legion@kernel.org +Link: https://lkml.kernel.org/r/d2f4603305cbfed58a24755aa61d027314b73a45.1705333426.git.legion@kernel.org +Signed-off-by: Alexey Gladkov +Signed-off-by: Eric W. Biederman +Link: https://lkml.kernel.org/r/e2d84d3ec0172cfff759e6065da84ce0cc2736f8.1663756794.git.legion@kernel.org +Cc: Christian Brauner +Cc: Joel Granados +Cc: Kees Cook +Cc: Luis Chamberlain +Cc: Manfred Spraul +Cc: Davidlohr Bueso +Signed-off-by: Andrew Morton +Stable-dep-of: 98ca62ba9e2b ("sysctl: always initialize i_uid/i_gid") +Signed-off-by: Sasha Levin +--- + ipc/ipc_sysctl.c | 37 +++++++++++++++++++++++++++++++++++-- + 1 file changed, 35 insertions(+), 2 deletions(-) + +diff --git a/ipc/ipc_sysctl.c b/ipc/ipc_sysctl.c +index ef313ecfb53a1..29c1d3ae2a5c8 100644 +--- a/ipc/ipc_sysctl.c ++++ b/ipc/ipc_sysctl.c +@@ -14,6 +14,7 @@ + #include + #include + #include ++#include + #include "util.h" + + static int proc_ipc_dointvec_minmax_orphans(struct ctl_table *table, int write, +@@ -190,25 +191,57 @@ static int set_is_seen(struct ctl_table_set *set) + return ¤t->nsproxy->ipc_ns->ipc_set == set; + } + ++static void ipc_set_ownership(struct ctl_table_header *head, ++ struct ctl_table *table, ++ kuid_t *uid, kgid_t *gid) ++{ ++ struct ipc_namespace *ns = ++ container_of(head->set, struct ipc_namespace, ipc_set); ++ ++ kuid_t ns_root_uid = make_kuid(ns->user_ns, 0); ++ kgid_t ns_root_gid = make_kgid(ns->user_ns, 0); ++ ++ *uid = uid_valid(ns_root_uid) ? ns_root_uid : GLOBAL_ROOT_UID; ++ *gid = gid_valid(ns_root_gid) ? ns_root_gid : GLOBAL_ROOT_GID; ++} ++ + static int ipc_permissions(struct ctl_table_header *head, struct ctl_table *table) + { + int mode = table->mode; + + #ifdef CONFIG_CHECKPOINT_RESTORE +- struct ipc_namespace *ns = current->nsproxy->ipc_ns; ++ struct ipc_namespace *ns = ++ container_of(head->set, struct ipc_namespace, ipc_set); + + if (((table->data == &ns->ids[IPC_SEM_IDS].next_id) || + (table->data == &ns->ids[IPC_MSG_IDS].next_id) || + (table->data == &ns->ids[IPC_SHM_IDS].next_id)) && + checkpoint_restore_ns_capable(ns->user_ns)) + mode = 0666; ++ else + #endif +- return mode; ++ { ++ kuid_t ns_root_uid; ++ kgid_t ns_root_gid; ++ ++ ipc_set_ownership(head, table, &ns_root_uid, &ns_root_gid); ++ ++ if (uid_eq(current_euid(), ns_root_uid)) ++ mode >>= 6; ++ ++ else if (in_egroup_p(ns_root_gid)) ++ mode >>= 3; ++ } ++ ++ mode &= 7; ++ ++ return (mode << 6) | (mode << 3) | mode; + } + + static struct ctl_table_root set_root = { + .lookup = set_lookup, + .permissions = ipc_permissions, ++ .set_ownership = ipc_set_ownership, + }; + + bool setup_ipc_sysctls(struct ipc_namespace *ns) +-- +2.43.0 + diff --git a/queue-6.1/sysctl-allow-to-change-limits-for-posix-messages-que.patch b/queue-6.1/sysctl-allow-to-change-limits-for-posix-messages-que.patch new file mode 100644 index 00000000000..5e845746514 --- /dev/null +++ b/queue-6.1/sysctl-allow-to-change-limits-for-posix-messages-que.patch @@ -0,0 +1,95 @@ +From b0543641855de8e889045e0cac33319f705a8749 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 15 Jan 2024 15:46:43 +0000 +Subject: sysctl: allow to change limits for posix messages queues + +From: Alexey Gladkov + +[ Upstream commit f9436a5d0497f759330d07e1189565edd4456be8 ] + +All parameters of posix messages queues (queues_max/msg_max/msgsize_max) +end up being limited by RLIMIT_MSGQUEUE. The code in mqueue_get_inode is +where that limiting happens. + +The RLIMIT_MSGQUEUE is bound to the user namespace and is counted +hierarchically. + +We can allow root in the user namespace to modify the posix messages +queues parameters. + +Link: https://lkml.kernel.org/r/6ad67f23d1459a4f4339f74aa73bac0ecf3995e1.1705333426.git.legion@kernel.org +Signed-off-by: Alexey Gladkov +Signed-off-by: Eric W. Biederman +Link: https://lkml.kernel.org/r/7eb21211c8622e91d226e63416b1b93c079f60ee.1663756794.git.legion@kernel.org +Cc: Christian Brauner +Cc: Davidlohr Bueso +Cc: Joel Granados +Cc: Kees Cook +Cc: Luis Chamberlain +Cc: Manfred Spraul +Signed-off-by: Andrew Morton +Stable-dep-of: 98ca62ba9e2b ("sysctl: always initialize i_uid/i_gid") +Signed-off-by: Sasha Levin +--- + ipc/mq_sysctl.c | 36 ++++++++++++++++++++++++++++++++++++ + 1 file changed, 36 insertions(+) + +diff --git a/ipc/mq_sysctl.c b/ipc/mq_sysctl.c +index fbf6a8b93a265..ce03930aced55 100644 +--- a/ipc/mq_sysctl.c ++++ b/ipc/mq_sysctl.c +@@ -12,6 +12,7 @@ + #include + #include + #include ++#include + + static int msg_max_limit_min = MIN_MSGMAX; + static int msg_max_limit_max = HARD_MSGMAX; +@@ -76,8 +77,43 @@ static int set_is_seen(struct ctl_table_set *set) + return ¤t->nsproxy->ipc_ns->mq_set == set; + } + ++static void mq_set_ownership(struct ctl_table_header *head, ++ struct ctl_table *table, ++ kuid_t *uid, kgid_t *gid) ++{ ++ struct ipc_namespace *ns = ++ container_of(head->set, struct ipc_namespace, mq_set); ++ ++ kuid_t ns_root_uid = make_kuid(ns->user_ns, 0); ++ kgid_t ns_root_gid = make_kgid(ns->user_ns, 0); ++ ++ *uid = uid_valid(ns_root_uid) ? ns_root_uid : GLOBAL_ROOT_UID; ++ *gid = gid_valid(ns_root_gid) ? ns_root_gid : GLOBAL_ROOT_GID; ++} ++ ++static int mq_permissions(struct ctl_table_header *head, struct ctl_table *table) ++{ ++ int mode = table->mode; ++ kuid_t ns_root_uid; ++ kgid_t ns_root_gid; ++ ++ mq_set_ownership(head, table, &ns_root_uid, &ns_root_gid); ++ ++ if (uid_eq(current_euid(), ns_root_uid)) ++ mode >>= 6; ++ ++ else if (in_egroup_p(ns_root_gid)) ++ mode >>= 3; ++ ++ mode &= 7; ++ ++ return (mode << 6) | (mode << 3) | mode; ++} ++ + static struct ctl_table_root set_root = { + .lookup = set_lookup, ++ .permissions = mq_permissions, ++ .set_ownership = mq_set_ownership, + }; + + bool setup_mq_sysctls(struct ipc_namespace *ns) +-- +2.43.0 + diff --git a/queue-6.1/sysctl-always-initialize-i_uid-i_gid.patch b/queue-6.1/sysctl-always-initialize-i_uid-i_gid.patch new file mode 100644 index 00000000000..f493d98e376 --- /dev/null +++ b/queue-6.1/sysctl-always-initialize-i_uid-i_gid.patch @@ -0,0 +1,52 @@ +From b4c197c0c5ff48298e9bfd35df42ba749b9a0ef8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 2 Apr 2024 23:10:34 +0200 +Subject: sysctl: always initialize i_uid/i_gid +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Thomas Weißschuh + +[ Upstream commit 98ca62ba9e2be5863c7d069f84f7166b45a5b2f4 ] + +Always initialize i_uid/i_gid inside the sysfs core so set_ownership() +can safely skip setting them. + +Commit 5ec27ec735ba ("fs/proc/proc_sysctl.c: fix the default values of +i_uid/i_gid on /proc/sys inodes.") added defaults for i_uid/i_gid when +set_ownership() was not implemented. It also missed adjusting +net_ctl_set_ownership() to use the same default values in case the +computation of a better value failed. + +Fixes: 5ec27ec735ba ("fs/proc/proc_sysctl.c: fix the default values of i_uid/i_gid on /proc/sys inodes.") +Cc: stable@vger.kernel.org +Signed-off-by: Thomas Weißschuh +Signed-off-by: Joel Granados +Signed-off-by: Sasha Levin +--- + fs/proc/proc_sysctl.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c +index c468cc0f6d69b..df77a7bcce498 100644 +--- a/fs/proc/proc_sysctl.c ++++ b/fs/proc/proc_sysctl.c +@@ -483,12 +483,10 @@ static struct inode *proc_sys_make_inode(struct super_block *sb, + make_empty_dir_inode(inode); + } + ++ inode->i_uid = GLOBAL_ROOT_UID; ++ inode->i_gid = GLOBAL_ROOT_GID; + if (root->set_ownership) + root->set_ownership(head, &inode->i_uid, &inode->i_gid); +- else { +- inode->i_uid = GLOBAL_ROOT_UID; +- inode->i_gid = GLOBAL_ROOT_GID; +- } + + return inode; + } +-- +2.43.0 + diff --git a/queue-6.1/sysctl-treewide-drop-unused-argument-ctl_table_root-.patch b/queue-6.1/sysctl-treewide-drop-unused-argument-ctl_table_root-.patch new file mode 100644 index 00000000000..eb620d9d779 --- /dev/null +++ b/queue-6.1/sysctl-treewide-drop-unused-argument-ctl_table_root-.patch @@ -0,0 +1,127 @@ +From d1357307fcca327d023b05a7edf79914cc811755 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 15 Mar 2024 19:11:30 +0100 +Subject: sysctl: treewide: drop unused argument + ctl_table_root::set_ownership(table) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Thomas Weißschuh + +[ Upstream commit 520713a93d550406dae14d49cdb8778d70cecdfd ] + +Remove the 'table' argument from set_ownership as it is never used. This +change is a step towards putting "struct ctl_table" into .rodata and +eventually having sysctl core only use "const struct ctl_table". + +The patch was created with the following coccinelle script: + + @@ + identifier func, head, table, uid, gid; + @@ + + void func( + struct ctl_table_header *head, + - struct ctl_table *table, + kuid_t *uid, kgid_t *gid) + { ... } + +No additional occurrences of 'set_ownership' were found after doing a +tree-wide search. + +Reviewed-by: Joel Granados +Signed-off-by: Thomas Weißschuh +Signed-off-by: Joel Granados +Stable-dep-of: 98ca62ba9e2b ("sysctl: always initialize i_uid/i_gid") +Signed-off-by: Sasha Levin +--- + fs/proc/proc_sysctl.c | 2 +- + include/linux/sysctl.h | 1 - + ipc/ipc_sysctl.c | 3 +-- + ipc/mq_sysctl.c | 3 +-- + net/sysctl_net.c | 1 - + 5 files changed, 3 insertions(+), 7 deletions(-) + +diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c +index 4a4c04a3b1a0a..c468cc0f6d69b 100644 +--- a/fs/proc/proc_sysctl.c ++++ b/fs/proc/proc_sysctl.c +@@ -484,7 +484,7 @@ static struct inode *proc_sys_make_inode(struct super_block *sb, + } + + if (root->set_ownership) +- root->set_ownership(head, table, &inode->i_uid, &inode->i_gid); ++ root->set_ownership(head, &inode->i_uid, &inode->i_gid); + else { + inode->i_uid = GLOBAL_ROOT_UID; + inode->i_gid = GLOBAL_ROOT_GID; +diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h +index a207c7ed41bd2..9f24feb94b24d 100644 +--- a/include/linux/sysctl.h ++++ b/include/linux/sysctl.h +@@ -185,7 +185,6 @@ struct ctl_table_root { + struct ctl_table_set default_set; + struct ctl_table_set *(*lookup)(struct ctl_table_root *root); + void (*set_ownership)(struct ctl_table_header *head, +- struct ctl_table *table, + kuid_t *uid, kgid_t *gid); + int (*permissions)(struct ctl_table_header *head, struct ctl_table *table); + }; +diff --git a/ipc/ipc_sysctl.c b/ipc/ipc_sysctl.c +index 29c1d3ae2a5c8..d7ca2bdae9e82 100644 +--- a/ipc/ipc_sysctl.c ++++ b/ipc/ipc_sysctl.c +@@ -192,7 +192,6 @@ static int set_is_seen(struct ctl_table_set *set) + } + + static void ipc_set_ownership(struct ctl_table_header *head, +- struct ctl_table *table, + kuid_t *uid, kgid_t *gid) + { + struct ipc_namespace *ns = +@@ -224,7 +223,7 @@ static int ipc_permissions(struct ctl_table_header *head, struct ctl_table *tabl + kuid_t ns_root_uid; + kgid_t ns_root_gid; + +- ipc_set_ownership(head, table, &ns_root_uid, &ns_root_gid); ++ ipc_set_ownership(head, &ns_root_uid, &ns_root_gid); + + if (uid_eq(current_euid(), ns_root_uid)) + mode >>= 6; +diff --git a/ipc/mq_sysctl.c b/ipc/mq_sysctl.c +index ce03930aced55..c960691fc24d9 100644 +--- a/ipc/mq_sysctl.c ++++ b/ipc/mq_sysctl.c +@@ -78,7 +78,6 @@ static int set_is_seen(struct ctl_table_set *set) + } + + static void mq_set_ownership(struct ctl_table_header *head, +- struct ctl_table *table, + kuid_t *uid, kgid_t *gid) + { + struct ipc_namespace *ns = +@@ -97,7 +96,7 @@ static int mq_permissions(struct ctl_table_header *head, struct ctl_table *table + kuid_t ns_root_uid; + kgid_t ns_root_gid; + +- mq_set_ownership(head, table, &ns_root_uid, &ns_root_gid); ++ mq_set_ownership(head, &ns_root_uid, &ns_root_gid); + + if (uid_eq(current_euid(), ns_root_uid)) + mode >>= 6; +diff --git a/net/sysctl_net.c b/net/sysctl_net.c +index 4b45ed631eb8b..2edb8040eb6c7 100644 +--- a/net/sysctl_net.c ++++ b/net/sysctl_net.c +@@ -54,7 +54,6 @@ static int net_ctl_permissions(struct ctl_table_header *head, + } + + static void net_ctl_set_ownership(struct ctl_table_header *head, +- struct ctl_table *table, + kuid_t *uid, kgid_t *gid) + { + struct net *net = container_of(head->set, struct net, sysctls); +-- +2.43.0 +