The patch below does not apply to the 5.4-stable tree. If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to stable@vger.kernel.org.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-5.4.y git checkout FETCH_HEAD git cherry-pick -x daeb4037adf7d3349b4a1fb792f4bc9824686a4b # <resolve conflicts, build, test, etc.> git commit -s git send-email --to 'stable@vger.kernel.org' --in-reply-to '2025102701-scabby-entrust-a162@gregkh' --subject-prefix 'PATCH 5.4.y' HEAD^..
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From daeb4037adf7d3349b4a1fb792f4bc9824686a4b Mon Sep 17 00:00:00 2001 From: Artem Shimko a.shimko.dev@gmail.com Date: Sun, 19 Oct 2025 12:51:31 +0300 Subject: [PATCH] serial: 8250_dw: handle reset control deassert error
Check the return value of reset_control_deassert() in the probe function to prevent continuing probe when reset deassertion fails.
Previously, reset_control_deassert() was called without checking its return value, which could lead to probe continuing even when the device reset wasn't properly deasserted.
The fix checks the return value and returns an error with dev_err_probe() if reset deassertion fails, providing better error handling and diagnostics.
Fixes: acbdad8dd1ab ("serial: 8250_dw: simplify optional reset handling") Cc: stable stable@kernel.org Signed-off-by: Artem Shimko a.shimko.dev@gmail.com Link: https://patch.msgid.link/20251019095131.252848-1-a.shimko.dev@gmail.com Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index a53ba04d9770..710ae4d40aec 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -635,7 +635,9 @@ static int dw8250_probe(struct platform_device *pdev) if (IS_ERR(data->rst)) return PTR_ERR(data->rst);
- reset_control_deassert(data->rst); + err = reset_control_deassert(data->rst); + if (err) + return dev_err_probe(dev, err, "failed to deassert resets\n");
err = devm_add_action_or_reset(dev, dw8250_reset_control_assert, data->rst); if (err)
From: Andy Shevchenko andriy.shevchenko@linux.intel.com
[ Upstream commit a8afc193558a42d5df724c84436ae3b2446d8a30 ]
Simplify the code which fetches the input clock by using devm_clk_get_optional(). This comes with a small functional change: previously all errors were ignored except deferred probe. Now all errors are treated as errors. If no input clock is present devm_clk_get_optional() will return NULL instead of an error which matches the behavior of the old code.
Signed-off-by: Andy Shevchenko andriy.shevchenko@linux.intel.com Link: https://lore.kernel.org/r/20190925162617.30368-1-andriy.shevchenko@linux.int... Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Stable-dep-of: daeb4037adf7 ("serial: 8250_dw: handle reset control deassert error") Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/tty/serial/8250/8250_dw.c | 75 +++++++++++++------------------ 1 file changed, 32 insertions(+), 43 deletions(-)
diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index 2d5a039229acf..bd2901798f316 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -283,9 +283,6 @@ static void dw8250_set_termios(struct uart_port *p, struct ktermios *termios, long rate; int ret;
- if (IS_ERR(d->clk)) - goto out; - clk_disable_unprepare(d->clk); rate = clk_round_rate(d->clk, baud * 16); if (rate < 0) @@ -296,8 +293,10 @@ static void dw8250_set_termios(struct uart_port *p, struct ktermios *termios, ret = clk_set_rate(d->clk, rate); clk_prepare_enable(d->clk);
- if (!ret) - p->uartclk = rate; + if (ret) + goto out; + + p->uartclk = rate;
out: p->status &= ~UPSTAT_AUTOCTS; @@ -473,19 +472,18 @@ static int dw8250_probe(struct platform_device *pdev) device_property_read_u32(dev, "clock-frequency", &p->uartclk);
/* If there is separate baudclk, get the rate from it. */ - data->clk = devm_clk_get(dev, "baudclk"); - if (IS_ERR(data->clk) && PTR_ERR(data->clk) != -EPROBE_DEFER) - data->clk = devm_clk_get(dev, NULL); - if (IS_ERR(data->clk) && PTR_ERR(data->clk) == -EPROBE_DEFER) - return -EPROBE_DEFER; - if (!IS_ERR_OR_NULL(data->clk)) { - err = clk_prepare_enable(data->clk); - if (err) - dev_warn(dev, "could not enable optional baudclk: %d\n", - err); - else - p->uartclk = clk_get_rate(data->clk); - } + data->clk = devm_clk_get_optional(dev, "baudclk"); + if (data->clk == NULL) + data->clk = devm_clk_get_optional(dev, NULL); + if (IS_ERR(data->clk)) + return PTR_ERR(data->clk); + + err = clk_prepare_enable(data->clk); + if (err) + dev_warn(dev, "could not enable optional baudclk: %d\n", err); + + if (data->clk) + p->uartclk = clk_get_rate(data->clk);
/* If no clock rate is defined, fail. */ if (!p->uartclk) { @@ -494,17 +492,16 @@ static int dw8250_probe(struct platform_device *pdev) goto err_clk; }
- data->pclk = devm_clk_get(dev, "apb_pclk"); - if (IS_ERR(data->pclk) && PTR_ERR(data->pclk) == -EPROBE_DEFER) { - err = -EPROBE_DEFER; + data->pclk = devm_clk_get_optional(dev, "apb_pclk"); + if (IS_ERR(data->pclk)) { + err = PTR_ERR(data->pclk); goto err_clk; } - if (!IS_ERR(data->pclk)) { - err = clk_prepare_enable(data->pclk); - if (err) { - dev_err(dev, "could not enable apb_pclk\n"); - goto err_clk; - } + + err = clk_prepare_enable(data->pclk); + if (err) { + dev_err(dev, "could not enable apb_pclk\n"); + goto err_clk; }
data->rst = devm_reset_control_get_optional_exclusive(dev, NULL); @@ -547,12 +544,10 @@ static int dw8250_probe(struct platform_device *pdev) reset_control_assert(data->rst);
err_pclk: - if (!IS_ERR(data->pclk)) - clk_disable_unprepare(data->pclk); + clk_disable_unprepare(data->pclk);
err_clk: - if (!IS_ERR(data->clk)) - clk_disable_unprepare(data->clk); + clk_disable_unprepare(data->clk);
return err; } @@ -568,11 +563,9 @@ static int dw8250_remove(struct platform_device *pdev)
reset_control_assert(data->rst);
- if (!IS_ERR(data->pclk)) - clk_disable_unprepare(data->pclk); + clk_disable_unprepare(data->pclk);
- if (!IS_ERR(data->clk)) - clk_disable_unprepare(data->clk); + clk_disable_unprepare(data->clk);
pm_runtime_disable(dev); pm_runtime_put_noidle(dev); @@ -605,11 +598,9 @@ static int dw8250_runtime_suspend(struct device *dev) { struct dw8250_data *data = dev_get_drvdata(dev);
- if (!IS_ERR(data->clk)) - clk_disable_unprepare(data->clk); + clk_disable_unprepare(data->clk);
- if (!IS_ERR(data->pclk)) - clk_disable_unprepare(data->pclk); + clk_disable_unprepare(data->pclk);
return 0; } @@ -618,11 +609,9 @@ static int dw8250_runtime_resume(struct device *dev) { struct dw8250_data *data = dev_get_drvdata(dev);
- if (!IS_ERR(data->pclk)) - clk_prepare_enable(data->pclk); + clk_prepare_enable(data->pclk);
- if (!IS_ERR(data->clk)) - clk_prepare_enable(data->clk); + clk_prepare_enable(data->clk);
return 0; }
From: Andy Shevchenko andriy.shevchenko@linux.intel.com
[ Upstream commit 295b09128d12fb1a7a67f771cc0ae0df869eafaf ]
Slightly simplify ->probe() and drop a few goto labels by using devm_add_action_or_reset() for clock and reset cleanup.
Signed-off-by: Andy Shevchenko andriy.shevchenko@linux.intel.com Link: https://lore.kernel.org/r/20220509172129.37770-1-andriy.shevchenko@linux.int... Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Stable-dep-of: daeb4037adf7 ("serial: 8250_dw: handle reset control deassert error") Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/tty/serial/8250/8250_dw.c | 63 +++++++++++++++---------------- 1 file changed, 31 insertions(+), 32 deletions(-)
diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index bd2901798f316..56506668a10c8 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -384,6 +384,16 @@ static void dw8250_quirks(struct uart_port *p, struct dw8250_data *data) } }
+static void dw8250_clk_disable_unprepare(void *data) +{ + clk_disable_unprepare(data); +} + +static void dw8250_reset_control_assert(void *data) +{ + reset_control_assert(data); +} + static int dw8250_probe(struct platform_device *pdev) { struct uart_8250_port uart = {}, *up = &uart; @@ -482,35 +492,43 @@ static int dw8250_probe(struct platform_device *pdev) if (err) dev_warn(dev, "could not enable optional baudclk: %d\n", err);
+ err = devm_add_action_or_reset(dev, dw8250_clk_disable_unprepare, data->clk); + if (err) + return err; + if (data->clk) p->uartclk = clk_get_rate(data->clk);
/* If no clock rate is defined, fail. */ if (!p->uartclk) { dev_err(dev, "clock rate not defined\n"); - err = -EINVAL; - goto err_clk; + return -EINVAL; }
data->pclk = devm_clk_get_optional(dev, "apb_pclk"); - if (IS_ERR(data->pclk)) { - err = PTR_ERR(data->pclk); - goto err_clk; - } + if (IS_ERR(data->pclk)) + return PTR_ERR(data->pclk);
err = clk_prepare_enable(data->pclk); if (err) { dev_err(dev, "could not enable apb_pclk\n"); - goto err_clk; + return err; }
+ err = devm_add_action_or_reset(dev, dw8250_clk_disable_unprepare, data->pclk); + if (err) + return err; + data->rst = devm_reset_control_get_optional_exclusive(dev, NULL); - if (IS_ERR(data->rst)) { - err = PTR_ERR(data->rst); - goto err_pclk; - } + if (IS_ERR(data->rst)) + return PTR_ERR(data->rst); + reset_control_deassert(data->rst);
+ err = devm_add_action_or_reset(dev, dw8250_reset_control_assert, data->rst); + if (err) + return err; + dw8250_quirks(p, data);
/* If the Busy Functionality is not implemented, don't handle it */ @@ -528,10 +546,8 @@ static int dw8250_probe(struct platform_device *pdev) }
data->data.line = serial8250_register_8250_port(up); - if (data->data.line < 0) { - err = data->data.line; - goto err_reset; - } + if (data->data.line < 0) + return data->data.line;
platform_set_drvdata(pdev, data);
@@ -539,17 +555,6 @@ static int dw8250_probe(struct platform_device *pdev) pm_runtime_enable(dev);
return 0; - -err_reset: - reset_control_assert(data->rst); - -err_pclk: - clk_disable_unprepare(data->pclk); - -err_clk: - clk_disable_unprepare(data->clk); - - return err; }
static int dw8250_remove(struct platform_device *pdev) @@ -561,12 +566,6 @@ static int dw8250_remove(struct platform_device *pdev)
serial8250_unregister_port(data->data.line);
- reset_control_assert(data->rst); - - clk_disable_unprepare(data->pclk); - - clk_disable_unprepare(data->clk); - pm_runtime_disable(dev); pm_runtime_put_noidle(dev);
From: Artem Shimko a.shimko.dev@gmail.com
[ Upstream commit daeb4037adf7d3349b4a1fb792f4bc9824686a4b ]
Check the return value of reset_control_deassert() in the probe function to prevent continuing probe when reset deassertion fails.
Previously, reset_control_deassert() was called without checking its return value, which could lead to probe continuing even when the device reset wasn't properly deasserted.
The fix checks the return value and returns an error with dev_err_probe() if reset deassertion fails, providing better error handling and diagnostics.
Fixes: acbdad8dd1ab ("serial: 8250_dw: simplify optional reset handling") Cc: stable stable@kernel.org Signed-off-by: Artem Shimko a.shimko.dev@gmail.com Link: https://patch.msgid.link/20251019095131.252848-1-a.shimko.dev@gmail.com Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/tty/serial/8250/8250_dw.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index 56506668a10c8..1521a743cc906 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -523,7 +523,9 @@ static int dw8250_probe(struct platform_device *pdev) if (IS_ERR(data->rst)) return PTR_ERR(data->rst);
- reset_control_deassert(data->rst); + err = reset_control_deassert(data->rst); + if (err) + return dev_err_probe(dev, err, "failed to deassert resets\n");
err = devm_add_action_or_reset(dev, dw8250_reset_control_assert, data->rst); if (err)
linux-stable-mirror@lists.linaro.org