Skip to content

Commit 681eb2b

Browse files
rogerqkuba-moo
authored andcommitted
net: ethernet: ti: am65-cpsw: ensure proper channel cleanup in error path
We are missing netif_napi_del() and am65_cpsw_nuss_free_tx/rx_chns() in error path when am65_cpsw_nuss_init_tx/rx_chns() is used anywhere other than at probe(). i.e. am65_cpsw_nuss_update_tx_rx_chns and am65_cpsw_nuss_resume() As reported, in am65_cpsw_nuss_update_tx_rx_chns(), if am65_cpsw_nuss_init_tx_chns() partially fails then devm_add_action(dev, am65_cpsw_nuss_free_tx_chns,..) is added but the cleanup via am65_cpsw_nuss_free_tx_chns() will not run. Same issue exists for am65_cpsw_nuss_init_tx/rx_chns() failures in am65_cpsw_nuss_resume() as well. This would otherwise require more instances of devm_add/remove_action and is clearly more of a distraction than any benefit. So, drop devm_add/remove_action for am65_cpsw_nuss_free_tx/rx_chns() and call am65_cpsw_nuss_free_tx/rx_chns() and netif_napi_del() where required. Reported-by: Siddharth Vadapalli <s-vadapalli@ti.com> Closes: https://lore.kernel.org/all/m4rhkzcr7dlylxr54udyt6lal5s2q4krrvmyay6gzgzhcu4q2c@r34snfumzqxy/ Signed-off-by: Roger Quadros <rogerq@kernel.org> Link: https://patch.msgid.link/20250117-am65-cpsw-streamline-v2-1-91a29c97e569@kernel.org Signed-off-by: Jakub Kicinski <kuba@kernel.org>
1 parent b115243 commit 681eb2b

File tree

1 file changed

+44
-23
lines changed

1 file changed

+44
-23
lines changed

drivers/net/ethernet/ti/am65-cpsw-nuss.c

Lines changed: 44 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2252,8 +2252,6 @@ static void am65_cpsw_nuss_remove_tx_chns(struct am65_cpsw_common *common)
22522252
struct device *dev = common->dev;
22532253
int i;
22542254

2255-
devm_remove_action(dev, am65_cpsw_nuss_free_tx_chns, common);
2256-
22572255
common->tx_ch_rate_msk = 0;
22582256
for (i = 0; i < common->tx_ch_num; i++) {
22592257
struct am65_cpsw_tx_chn *tx_chn = &common->tx_chns[i];
@@ -2275,8 +2273,6 @@ static int am65_cpsw_nuss_ndev_add_tx_napi(struct am65_cpsw_common *common)
22752273
for (i = 0; i < common->tx_ch_num; i++) {
22762274
struct am65_cpsw_tx_chn *tx_chn = &common->tx_chns[i];
22772275

2278-
netif_napi_add_tx(common->dma_ndev, &tx_chn->napi_tx,
2279-
am65_cpsw_nuss_tx_poll);
22802276
hrtimer_init(&tx_chn->tx_hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_PINNED);
22812277
tx_chn->tx_hrtimer.function = &am65_cpsw_nuss_tx_timer_callback;
22822278

@@ -2289,9 +2285,21 @@ static int am65_cpsw_nuss_ndev_add_tx_napi(struct am65_cpsw_common *common)
22892285
tx_chn->id, tx_chn->irq, ret);
22902286
goto err;
22912287
}
2288+
2289+
netif_napi_add_tx(common->dma_ndev, &tx_chn->napi_tx,
2290+
am65_cpsw_nuss_tx_poll);
22922291
}
22932292

2293+
return 0;
2294+
22942295
err:
2296+
for (--i ; i >= 0 ; i--) {
2297+
struct am65_cpsw_tx_chn *tx_chn = &common->tx_chns[i];
2298+
2299+
netif_napi_del(&tx_chn->napi_tx);
2300+
devm_free_irq(dev, tx_chn->irq, tx_chn);
2301+
}
2302+
22952303
return ret;
22962304
}
22972305

@@ -2372,12 +2380,10 @@ static int am65_cpsw_nuss_init_tx_chns(struct am65_cpsw_common *common)
23722380
goto err;
23732381
}
23742382

2383+
return 0;
2384+
23752385
err:
2376-
i = devm_add_action(dev, am65_cpsw_nuss_free_tx_chns, common);
2377-
if (i) {
2378-
dev_err(dev, "Failed to add free_tx_chns action %d\n", i);
2379-
return i;
2380-
}
2386+
am65_cpsw_nuss_free_tx_chns(common);
23812387

23822388
return ret;
23832389
}
@@ -2405,7 +2411,6 @@ static void am65_cpsw_nuss_remove_rx_chns(struct am65_cpsw_common *common)
24052411

24062412
rx_chn = &common->rx_chns;
24072413
flows = rx_chn->flows;
2408-
devm_remove_action(dev, am65_cpsw_nuss_free_rx_chns, common);
24092414

24102415
for (i = 0; i < common->rx_ch_num_flows; i++) {
24112416
if (!(flows[i].irq < 0))
@@ -2504,7 +2509,7 @@ static int am65_cpsw_nuss_init_rx_chns(struct am65_cpsw_common *common)
25042509
i, &rx_flow_cfg);
25052510
if (ret) {
25062511
dev_err(dev, "Failed to init rx flow%d %d\n", i, ret);
2507-
goto err;
2512+
goto err_flow;
25082513
}
25092514
if (!i)
25102515
fdqring_id =
@@ -2516,14 +2521,12 @@ static int am65_cpsw_nuss_init_rx_chns(struct am65_cpsw_common *common)
25162521
dev_err(dev, "Failed to get rx dma irq %d\n",
25172522
flow->irq);
25182523
ret = flow->irq;
2519-
goto err;
2524+
goto err_flow;
25202525
}
25212526

25222527
snprintf(flow->name,
25232528
sizeof(flow->name), "%s-rx%d",
25242529
dev_name(dev), i);
2525-
netif_napi_add(common->dma_ndev, &flow->napi_rx,
2526-
am65_cpsw_nuss_rx_poll);
25272530
hrtimer_init(&flow->rx_hrtimer, CLOCK_MONOTONIC,
25282531
HRTIMER_MODE_REL_PINNED);
25292532
flow->rx_hrtimer.function = &am65_cpsw_nuss_rx_timer_callback;
@@ -2536,20 +2539,28 @@ static int am65_cpsw_nuss_init_rx_chns(struct am65_cpsw_common *common)
25362539
dev_err(dev, "failure requesting rx %d irq %u, %d\n",
25372540
i, flow->irq, ret);
25382541
flow->irq = -EINVAL;
2539-
goto err;
2542+
goto err_flow;
25402543
}
2544+
2545+
netif_napi_add(common->dma_ndev, &flow->napi_rx,
2546+
am65_cpsw_nuss_rx_poll);
25412547
}
25422548

25432549
/* setup classifier to route priorities to flows */
25442550
cpsw_ale_classifier_setup_default(common->ale, common->rx_ch_num_flows);
25452551

2546-
err:
2547-
i = devm_add_action(dev, am65_cpsw_nuss_free_rx_chns, common);
2548-
if (i) {
2549-
dev_err(dev, "Failed to add free_rx_chns action %d\n", i);
2550-
return i;
2552+
return 0;
2553+
2554+
err_flow:
2555+
for (--i; i >= 0 ; i--) {
2556+
flow = &rx_chn->flows[i];
2557+
netif_napi_del(&flow->napi_rx);
2558+
devm_free_irq(dev, flow->irq, flow);
25512559
}
25522560

2561+
err:
2562+
am65_cpsw_nuss_free_rx_chns(common);
2563+
25532564
return ret;
25542565
}
25552566

@@ -3354,7 +3365,7 @@ static int am65_cpsw_nuss_register_ndevs(struct am65_cpsw_common *common)
33543365
return ret;
33553366
ret = am65_cpsw_nuss_init_rx_chns(common);
33563367
if (ret)
3357-
return ret;
3368+
goto err_remove_tx;
33583369

33593370
/* The DMA Channels are not guaranteed to be in a clean state.
33603371
* Reset and disable them to ensure that they are back to the
@@ -3375,7 +3386,7 @@ static int am65_cpsw_nuss_register_ndevs(struct am65_cpsw_common *common)
33753386

33763387
ret = am65_cpsw_nuss_register_devlink(common);
33773388
if (ret)
3378-
return ret;
3389+
goto err_remove_rx;
33793390

33803391
for (i = 0; i < common->port_num; i++) {
33813392
port = &common->ports[i];
@@ -3406,6 +3417,10 @@ static int am65_cpsw_nuss_register_ndevs(struct am65_cpsw_common *common)
34063417
err_cleanup_ndev:
34073418
am65_cpsw_nuss_cleanup_ndev(common);
34083419
am65_cpsw_unregister_devlink(common);
3420+
err_remove_rx:
3421+
am65_cpsw_nuss_remove_rx_chns(common);
3422+
err_remove_tx:
3423+
am65_cpsw_nuss_remove_tx_chns(common);
34093424

34103425
return ret;
34113426
}
@@ -3425,6 +3440,8 @@ int am65_cpsw_nuss_update_tx_rx_chns(struct am65_cpsw_common *common,
34253440
return ret;
34263441

34273442
ret = am65_cpsw_nuss_init_rx_chns(common);
3443+
if (ret)
3444+
am65_cpsw_nuss_remove_tx_chns(common);
34283445

34293446
return ret;
34303447
}
@@ -3683,6 +3700,8 @@ static void am65_cpsw_nuss_remove(struct platform_device *pdev)
36833700
*/
36843701
am65_cpsw_nuss_cleanup_ndev(common);
36853702
am65_cpsw_unregister_devlink(common);
3703+
am65_cpsw_nuss_remove_rx_chns(common);
3704+
am65_cpsw_nuss_remove_tx_chns(common);
36863705
am65_cpsw_nuss_phylink_cleanup(common);
36873706
am65_cpts_release(common->cpts);
36883707
am65_cpsw_disable_serdes_phy(common);
@@ -3744,8 +3763,10 @@ static int am65_cpsw_nuss_resume(struct device *dev)
37443763
if (ret)
37453764
return ret;
37463765
ret = am65_cpsw_nuss_init_rx_chns(common);
3747-
if (ret)
3766+
if (ret) {
3767+
am65_cpsw_nuss_remove_tx_chns(common);
37483768
return ret;
3769+
}
37493770

37503771
/* If RX IRQ was disabled before suspend, keep it disabled */
37513772
for (i = 0; i < common->rx_ch_num_flows; i++) {

0 commit comments

Comments
 (0)