drivers/net/can/spi/mcp251x.c | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-)
Add missing error handling for mcp251x_power_enable() calls in both
mcp251x_open() and mcp251x_can_resume() functions.
In mcp251x_open(), if power enable fails, the driver should not continue
with device initialization. Add proper error checking and jump to
existing out_close label.
In mcp251x_can_resume(), if power enable fails during system resume,
propagate the error to PM framework and log the error with dev_err()
for debugging.
This ensures the driver properly handles power control failures and
maintains correct device state.
Signed-off-by: Wenyuan Li <2063309626@qq.com>
Add missing error handling for mcp251x_power_enable() calls in both
mcp251x_open() and mcp251x_can_resume() functions.
In mcp251x_open(), if power enable fails, jump to error path to close
candev without attempting to disable power again.
In mcp251x_can_resume(), properly check return values of power enable
calls for both power and transceiver regulators. If any fails, return
the error code to the PM framework and log the failure.
This ensures the driver properly handles power control failures and
maintains correct device state.
Signed-off-by: Wenyuan Li <2063309626@qq.com>
---
drivers/net/can/spi/mcp251x.c | 33 +++++++++++++++++++++++++++------
1 file changed, 27 insertions(+), 6 deletions(-)
diff --git a/drivers/net/can/spi/mcp251x.c b/drivers/net/can/spi/mcp251x.c
index bb7782582f40..6e17133a4e03 100644
--- a/drivers/net/can/spi/mcp251x.c
+++ b/drivers/net/can/spi/mcp251x.c
@@ -1225,7 +1225,11 @@ static int mcp251x_open(struct net_device *net)
}
mutex_lock(&priv->mcp_lock);
- mcp251x_power_enable(priv->transceiver, 1);
+ ret = mcp251x_power_enable(priv->transceiver, 1);
+ if (ret) {
+ dev_err(&spi->dev, "failed to enable transceiver power: %pe\n", ERR_PTR(ret));
+ goto out_close_candev;
+ }
priv->force_quit = 0;
priv->tx_skb = NULL;
@@ -1272,6 +1276,7 @@ static int mcp251x_open(struct net_device *net)
mcp251x_hw_sleep(spi);
out_close:
mcp251x_power_enable(priv->transceiver, 0);
+out_close_candev:
close_candev(net);
mutex_unlock(&priv->mcp_lock);
if (release_irq)
@@ -1516,11 +1521,26 @@ static int __maybe_unused mcp251x_can_resume(struct device *dev)
{
struct spi_device *spi = to_spi_device(dev);
struct mcp251x_priv *priv = spi_get_drvdata(spi);
+ int ret = 0;
- if (priv->after_suspend & AFTER_SUSPEND_POWER)
- mcp251x_power_enable(priv->power, 1);
- if (priv->after_suspend & AFTER_SUSPEND_UP)
- mcp251x_power_enable(priv->transceiver, 1);
+ if (priv->after_suspend & AFTER_SUSPEND_POWER) {
+ ret = mcp251x_power_enable(priv->power, 1);
+ if (ret) {
+ dev_err(dev, "Failed to restore power: %pe\n", ERR_PTR(ret));
+ goto out;
+ }
+ }
+
+ if (priv->after_suspend & AFTER_SUSPEND_UP) {
+ ret = mcp251x_power_enable(priv->transceiver, 1);
+ if (ret) {
+ dev_err(dev, "Failed to restore transceiver power: %pe\n", ERR_PTR(ret));
+ /* If the transceiver fails to be enabled, turn off the power that has been enabled.*/
+ if (priv->after_suspend & AFTER_SUSPEND_POWER)
+ mcp251x_power_enable(priv->power, 0);
+ goto out;
+ }
+ }
if (priv->after_suspend & (AFTER_SUSPEND_POWER | AFTER_SUSPEND_UP))
queue_work(priv->wq, &priv->restart_work);
@@ -1529,7 +1549,8 @@ static int __maybe_unused mcp251x_can_resume(struct device *dev)
priv->force_quit = 0;
enable_irq(spi->irq);
- return 0;
+out:
+ return ret;
}
static SIMPLE_DEV_PM_OPS(mcp251x_can_pm_ops, mcp251x_can_suspend,
--
2.43.0
Hello Wenyuan Li,
the patch looks almost perfect, good work! Some minor nitpicks inside.
A small tip for the v4, use "git send-email -v4", so that the "v4" goes
to the correct place in the subject. For you next patches have a look at
the great tool b4: https://b4.docs.kernel.org/en/latest/
On 15.03.2026 23:14:45, Wenyuan Li wrote:
> Add missing error handling for mcp251x_power_enable() calls in both
> mcp251x_open() and mcp251x_can_resume() functions.
>
> In mcp251x_open(), if power enable fails, the driver should not continue
> with device initialization. Add proper error checking and jump to
> existing out_close label.
>
> In mcp251x_can_resume(), if power enable fails during system resume,
> propagate the error to PM framework and log the error with dev_err()
> for debugging.
>
> This ensures the driver properly handles power control failures and
> maintains correct device state.
> Signed-off-by: Wenyuan Li <2063309626@qq.com>
>
> Add missing error handling for mcp251x_power_enable() calls in both
> mcp251x_open() and mcp251x_can_resume() functions.
>
> In mcp251x_open(), if power enable fails, jump to error path to close
> candev without attempting to disable power again.
>
> In mcp251x_can_resume(), properly check return values of power enable
> calls for both power and transceiver regulators. If any fails, return
> the error code to the PM framework and log the failure.
>
> This ensures the driver properly handles power control failures and
> maintains correct device state.
>
> Signed-off-by: Wenyuan Li <2063309626@qq.com>
> ---
> drivers/net/can/spi/mcp251x.c | 33 +++++++++++++++++++++++++++------
> 1 file changed, 27 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/net/can/spi/mcp251x.c b/drivers/net/can/spi/mcp251x.c
> index bb7782582f40..6e17133a4e03 100644
> --- a/drivers/net/can/spi/mcp251x.c
> +++ b/drivers/net/can/spi/mcp251x.c
> @@ -1225,7 +1225,11 @@ static int mcp251x_open(struct net_device *net)
> }
>
> mutex_lock(&priv->mcp_lock);
> - mcp251x_power_enable(priv->transceiver, 1);
> + ret = mcp251x_power_enable(priv->transceiver, 1);
> + if (ret) {
> + dev_err(&spi->dev, "failed to enable transceiver power: %pe\n", ERR_PTR(ret));
> + goto out_close_candev;
> + }
>
> priv->force_quit = 0;
> priv->tx_skb = NULL;
> @@ -1272,6 +1276,7 @@ static int mcp251x_open(struct net_device *net)
> mcp251x_hw_sleep(spi);
> out_close:
> mcp251x_power_enable(priv->transceiver, 0);
> +out_close_candev:
> close_candev(net);
> mutex_unlock(&priv->mcp_lock);
> if (release_irq)
> @@ -1516,11 +1521,26 @@ static int __maybe_unused mcp251x_can_resume(struct device *dev)
> {
> struct spi_device *spi = to_spi_device(dev);
> struct mcp251x_priv *priv = spi_get_drvdata(spi);
> + int ret = 0;
>
> - if (priv->after_suspend & AFTER_SUSPEND_POWER)
> - mcp251x_power_enable(priv->power, 1);
> - if (priv->after_suspend & AFTER_SUSPEND_UP)
> - mcp251x_power_enable(priv->transceiver, 1);
> + if (priv->after_suspend & AFTER_SUSPEND_POWER) {
> + ret = mcp251x_power_enable(priv->power, 1);
> + if (ret) {
> + dev_err(dev, "Failed to restore power: %pe\n", ERR_PTR(ret));
> + goto out;
As we don't do any cleanups you can do a "return ret;" instead of the
goto.
Please use "failed" or "Failed" consistently in the patch.
> + }
> + }
> +
> + if (priv->after_suspend & AFTER_SUSPEND_UP) {
> + ret = mcp251x_power_enable(priv->transceiver, 1);
> + if (ret) {
> + dev_err(dev, "Failed to restore transceiver power: %pe\n", ERR_PTR(ret));
> + /* If the transceiver fails to be enabled, turn off the power that has been enabled.*/
IMHO that comment states the obvious, please remove.
> + if (priv->after_suspend & AFTER_SUSPEND_POWER)
> + mcp251x_power_enable(priv->power, 0);
> + goto out;
> + }
> + }
>
> if (priv->after_suspend & (AFTER_SUSPEND_POWER | AFTER_SUSPEND_UP))
> queue_work(priv->wq, &priv->restart_work);
> @@ -1529,7 +1549,8 @@ static int __maybe_unused mcp251x_can_resume(struct device *dev)
>
> priv->force_quit = 0;
> enable_irq(spi->irq);
> - return 0;
> +out:
> + return ret;
> }
>
> static SIMPLE_DEV_PM_OPS(mcp251x_can_pm_ops, mcp251x_can_suspend,
regards,
Marc
--
Pengutronix e.K. | Marc Kleine-Budde |
Embedded Linux | https://www.pengutronix.de |
Vertretung Nürnberg | Phone: +49-5121-206917-129 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-9 |
© 2016 - 2026 Red Hat, Inc.