mirror of
https://github.com/torvalds/linux.git
synced 2025-12-07 20:06:24 +00:00
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>
This commit is contained in:
committed by
Jakub Kicinski
parent
b115243ab8
commit
681eb2beb3
@@ -2252,8 +2252,6 @@ static void am65_cpsw_nuss_remove_tx_chns(struct am65_cpsw_common *common)
|
|||||||
struct device *dev = common->dev;
|
struct device *dev = common->dev;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
devm_remove_action(dev, am65_cpsw_nuss_free_tx_chns, common);
|
|
||||||
|
|
||||||
common->tx_ch_rate_msk = 0;
|
common->tx_ch_rate_msk = 0;
|
||||||
for (i = 0; i < common->tx_ch_num; i++) {
|
for (i = 0; i < common->tx_ch_num; i++) {
|
||||||
struct am65_cpsw_tx_chn *tx_chn = &common->tx_chns[i];
|
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)
|
|||||||
for (i = 0; i < common->tx_ch_num; i++) {
|
for (i = 0; i < common->tx_ch_num; i++) {
|
||||||
struct am65_cpsw_tx_chn *tx_chn = &common->tx_chns[i];
|
struct am65_cpsw_tx_chn *tx_chn = &common->tx_chns[i];
|
||||||
|
|
||||||
netif_napi_add_tx(common->dma_ndev, &tx_chn->napi_tx,
|
|
||||||
am65_cpsw_nuss_tx_poll);
|
|
||||||
hrtimer_init(&tx_chn->tx_hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_PINNED);
|
hrtimer_init(&tx_chn->tx_hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_PINNED);
|
||||||
tx_chn->tx_hrtimer.function = &am65_cpsw_nuss_tx_timer_callback;
|
tx_chn->tx_hrtimer.function = &am65_cpsw_nuss_tx_timer_callback;
|
||||||
|
|
||||||
@@ -2289,9 +2285,21 @@ static int am65_cpsw_nuss_ndev_add_tx_napi(struct am65_cpsw_common *common)
|
|||||||
tx_chn->id, tx_chn->irq, ret);
|
tx_chn->id, tx_chn->irq, ret);
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
netif_napi_add_tx(common->dma_ndev, &tx_chn->napi_tx,
|
||||||
|
am65_cpsw_nuss_tx_poll);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
|
for (--i ; i >= 0 ; i--) {
|
||||||
|
struct am65_cpsw_tx_chn *tx_chn = &common->tx_chns[i];
|
||||||
|
|
||||||
|
netif_napi_del(&tx_chn->napi_tx);
|
||||||
|
devm_free_irq(dev, tx_chn->irq, tx_chn);
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2372,12 +2380,10 @@ static int am65_cpsw_nuss_init_tx_chns(struct am65_cpsw_common *common)
|
|||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
i = devm_add_action(dev, am65_cpsw_nuss_free_tx_chns, common);
|
am65_cpsw_nuss_free_tx_chns(common);
|
||||||
if (i) {
|
|
||||||
dev_err(dev, "Failed to add free_tx_chns action %d\n", i);
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -2405,7 +2411,6 @@ static void am65_cpsw_nuss_remove_rx_chns(struct am65_cpsw_common *common)
|
|||||||
|
|
||||||
rx_chn = &common->rx_chns;
|
rx_chn = &common->rx_chns;
|
||||||
flows = rx_chn->flows;
|
flows = rx_chn->flows;
|
||||||
devm_remove_action(dev, am65_cpsw_nuss_free_rx_chns, common);
|
|
||||||
|
|
||||||
for (i = 0; i < common->rx_ch_num_flows; i++) {
|
for (i = 0; i < common->rx_ch_num_flows; i++) {
|
||||||
if (!(flows[i].irq < 0))
|
if (!(flows[i].irq < 0))
|
||||||
@@ -2504,7 +2509,7 @@ static int am65_cpsw_nuss_init_rx_chns(struct am65_cpsw_common *common)
|
|||||||
i, &rx_flow_cfg);
|
i, &rx_flow_cfg);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(dev, "Failed to init rx flow%d %d\n", i, ret);
|
dev_err(dev, "Failed to init rx flow%d %d\n", i, ret);
|
||||||
goto err;
|
goto err_flow;
|
||||||
}
|
}
|
||||||
if (!i)
|
if (!i)
|
||||||
fdqring_id =
|
fdqring_id =
|
||||||
@@ -2516,14 +2521,12 @@ static int am65_cpsw_nuss_init_rx_chns(struct am65_cpsw_common *common)
|
|||||||
dev_err(dev, "Failed to get rx dma irq %d\n",
|
dev_err(dev, "Failed to get rx dma irq %d\n",
|
||||||
flow->irq);
|
flow->irq);
|
||||||
ret = flow->irq;
|
ret = flow->irq;
|
||||||
goto err;
|
goto err_flow;
|
||||||
}
|
}
|
||||||
|
|
||||||
snprintf(flow->name,
|
snprintf(flow->name,
|
||||||
sizeof(flow->name), "%s-rx%d",
|
sizeof(flow->name), "%s-rx%d",
|
||||||
dev_name(dev), i);
|
dev_name(dev), i);
|
||||||
netif_napi_add(common->dma_ndev, &flow->napi_rx,
|
|
||||||
am65_cpsw_nuss_rx_poll);
|
|
||||||
hrtimer_init(&flow->rx_hrtimer, CLOCK_MONOTONIC,
|
hrtimer_init(&flow->rx_hrtimer, CLOCK_MONOTONIC,
|
||||||
HRTIMER_MODE_REL_PINNED);
|
HRTIMER_MODE_REL_PINNED);
|
||||||
flow->rx_hrtimer.function = &am65_cpsw_nuss_rx_timer_callback;
|
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)
|
|||||||
dev_err(dev, "failure requesting rx %d irq %u, %d\n",
|
dev_err(dev, "failure requesting rx %d irq %u, %d\n",
|
||||||
i, flow->irq, ret);
|
i, flow->irq, ret);
|
||||||
flow->irq = -EINVAL;
|
flow->irq = -EINVAL;
|
||||||
goto err;
|
goto err_flow;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
netif_napi_add(common->dma_ndev, &flow->napi_rx,
|
||||||
|
am65_cpsw_nuss_rx_poll);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* setup classifier to route priorities to flows */
|
/* setup classifier to route priorities to flows */
|
||||||
cpsw_ale_classifier_setup_default(common->ale, common->rx_ch_num_flows);
|
cpsw_ale_classifier_setup_default(common->ale, common->rx_ch_num_flows);
|
||||||
|
|
||||||
err:
|
return 0;
|
||||||
i = devm_add_action(dev, am65_cpsw_nuss_free_rx_chns, common);
|
|
||||||
if (i) {
|
err_flow:
|
||||||
dev_err(dev, "Failed to add free_rx_chns action %d\n", i);
|
for (--i; i >= 0 ; i--) {
|
||||||
return i;
|
flow = &rx_chn->flows[i];
|
||||||
|
netif_napi_del(&flow->napi_rx);
|
||||||
|
devm_free_irq(dev, flow->irq, flow);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err:
|
||||||
|
am65_cpsw_nuss_free_rx_chns(common);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3354,7 +3365,7 @@ static int am65_cpsw_nuss_register_ndevs(struct am65_cpsw_common *common)
|
|||||||
return ret;
|
return ret;
|
||||||
ret = am65_cpsw_nuss_init_rx_chns(common);
|
ret = am65_cpsw_nuss_init_rx_chns(common);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
goto err_remove_tx;
|
||||||
|
|
||||||
/* The DMA Channels are not guaranteed to be in a clean state.
|
/* The DMA Channels are not guaranteed to be in a clean state.
|
||||||
* Reset and disable them to ensure that they are back to the
|
* 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)
|
|||||||
|
|
||||||
ret = am65_cpsw_nuss_register_devlink(common);
|
ret = am65_cpsw_nuss_register_devlink(common);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
goto err_remove_rx;
|
||||||
|
|
||||||
for (i = 0; i < common->port_num; i++) {
|
for (i = 0; i < common->port_num; i++) {
|
||||||
port = &common->ports[i];
|
port = &common->ports[i];
|
||||||
@@ -3406,6 +3417,10 @@ static int am65_cpsw_nuss_register_ndevs(struct am65_cpsw_common *common)
|
|||||||
err_cleanup_ndev:
|
err_cleanup_ndev:
|
||||||
am65_cpsw_nuss_cleanup_ndev(common);
|
am65_cpsw_nuss_cleanup_ndev(common);
|
||||||
am65_cpsw_unregister_devlink(common);
|
am65_cpsw_unregister_devlink(common);
|
||||||
|
err_remove_rx:
|
||||||
|
am65_cpsw_nuss_remove_rx_chns(common);
|
||||||
|
err_remove_tx:
|
||||||
|
am65_cpsw_nuss_remove_tx_chns(common);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -3425,6 +3440,8 @@ int am65_cpsw_nuss_update_tx_rx_chns(struct am65_cpsw_common *common,
|
|||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
ret = am65_cpsw_nuss_init_rx_chns(common);
|
ret = am65_cpsw_nuss_init_rx_chns(common);
|
||||||
|
if (ret)
|
||||||
|
am65_cpsw_nuss_remove_tx_chns(common);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -3683,6 +3700,8 @@ static void am65_cpsw_nuss_remove(struct platform_device *pdev)
|
|||||||
*/
|
*/
|
||||||
am65_cpsw_nuss_cleanup_ndev(common);
|
am65_cpsw_nuss_cleanup_ndev(common);
|
||||||
am65_cpsw_unregister_devlink(common);
|
am65_cpsw_unregister_devlink(common);
|
||||||
|
am65_cpsw_nuss_remove_rx_chns(common);
|
||||||
|
am65_cpsw_nuss_remove_tx_chns(common);
|
||||||
am65_cpsw_nuss_phylink_cleanup(common);
|
am65_cpsw_nuss_phylink_cleanup(common);
|
||||||
am65_cpts_release(common->cpts);
|
am65_cpts_release(common->cpts);
|
||||||
am65_cpsw_disable_serdes_phy(common);
|
am65_cpsw_disable_serdes_phy(common);
|
||||||
@@ -3744,8 +3763,10 @@ static int am65_cpsw_nuss_resume(struct device *dev)
|
|||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
ret = am65_cpsw_nuss_init_rx_chns(common);
|
ret = am65_cpsw_nuss_init_rx_chns(common);
|
||||||
if (ret)
|
if (ret) {
|
||||||
|
am65_cpsw_nuss_remove_tx_chns(common);
|
||||||
return ret;
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/* If RX IRQ was disabled before suspend, keep it disabled */
|
/* If RX IRQ was disabled before suspend, keep it disabled */
|
||||||
for (i = 0; i < common->rx_ch_num_flows; i++) {
|
for (i = 0; i < common->rx_ch_num_flows; i++) {
|
||||||
|
|||||||
Reference in New Issue
Block a user