Skip to content

Commit 03c4271

Browse files
fschrempfmarckleinebudde
authored andcommitted
can: mcp251x: fix resume from sleep before interface was brought up
Since 8ce8c0a the driver queues work via priv->restart_work when resuming after suspend, even when the interface was not previously enabled. This causes a null dereference error as the workqueue is only allocated and initialized in mcp251x_open(). To fix this we move the workqueue init to mcp251x_can_probe() as there is no reason to do it later and repeat it whenever mcp251x_open() is called. Fixes: 8ce8c0a ("can: mcp251x: only reset hardware as required") Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Frieder Schrempf <[email protected]> Reviewed-by: Andy Shevchenko <[email protected]> [mkl: fix error handling in mcp251x_stop()] Signed-off-by: Marc Kleine-Budde <[email protected]>
1 parent 4376ea4 commit 03c4271

File tree

1 file changed

+18
-17
lines changed

1 file changed

+18
-17
lines changed

drivers/net/can/spi/mcp251x.c

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -956,8 +956,6 @@ static int mcp251x_stop(struct net_device *net)
956956

957957
priv->force_quit = 1;
958958
free_irq(spi->irq, priv);
959-
destroy_workqueue(priv->wq);
960-
priv->wq = NULL;
961959

962960
mutex_lock(&priv->mcp_lock);
963961

@@ -1224,24 +1222,15 @@ static int mcp251x_open(struct net_device *net)
12241222
goto out_close;
12251223
}
12261224

1227-
priv->wq = alloc_workqueue("mcp251x_wq", WQ_FREEZABLE | WQ_MEM_RECLAIM,
1228-
0);
1229-
if (!priv->wq) {
1230-
ret = -ENOMEM;
1231-
goto out_clean;
1232-
}
1233-
INIT_WORK(&priv->tx_work, mcp251x_tx_work_handler);
1234-
INIT_WORK(&priv->restart_work, mcp251x_restart_work_handler);
1235-
12361225
ret = mcp251x_hw_wake(spi);
12371226
if (ret)
1238-
goto out_free_wq;
1227+
goto out_free_irq;
12391228
ret = mcp251x_setup(net, spi);
12401229
if (ret)
1241-
goto out_free_wq;
1230+
goto out_free_irq;
12421231
ret = mcp251x_set_normal_mode(spi);
12431232
if (ret)
1244-
goto out_free_wq;
1233+
goto out_free_irq;
12451234

12461235
can_led_event(net, CAN_LED_EVENT_OPEN);
12471236

@@ -1250,9 +1239,7 @@ static int mcp251x_open(struct net_device *net)
12501239

12511240
return 0;
12521241

1253-
out_free_wq:
1254-
destroy_workqueue(priv->wq);
1255-
out_clean:
1242+
out_free_irq:
12561243
free_irq(spi->irq, priv);
12571244
mcp251x_hw_sleep(spi);
12581245
out_close:
@@ -1373,6 +1360,15 @@ static int mcp251x_can_probe(struct spi_device *spi)
13731360
if (ret)
13741361
goto out_clk;
13751362

1363+
priv->wq = alloc_workqueue("mcp251x_wq", WQ_FREEZABLE | WQ_MEM_RECLAIM,
1364+
0);
1365+
if (!priv->wq) {
1366+
ret = -ENOMEM;
1367+
goto out_clk;
1368+
}
1369+
INIT_WORK(&priv->tx_work, mcp251x_tx_work_handler);
1370+
INIT_WORK(&priv->restart_work, mcp251x_restart_work_handler);
1371+
13761372
priv->spi = spi;
13771373
mutex_init(&priv->mcp_lock);
13781374

@@ -1417,6 +1413,8 @@ static int mcp251x_can_probe(struct spi_device *spi)
14171413
return 0;
14181414

14191415
error_probe:
1416+
destroy_workqueue(priv->wq);
1417+
priv->wq = NULL;
14201418
mcp251x_power_enable(priv->power, 0);
14211419

14221420
out_clk:
@@ -1438,6 +1436,9 @@ static int mcp251x_can_remove(struct spi_device *spi)
14381436

14391437
mcp251x_power_enable(priv->power, 0);
14401438

1439+
destroy_workqueue(priv->wq);
1440+
priv->wq = NULL;
1441+
14411442
clk_disable_unprepare(priv->clk);
14421443

14431444
free_candev(net);

0 commit comments

Comments
 (0)