Browse Source

net: ethernet: ti: am65-cpsw-nuss: fix race between netif down and rx napi

The kernel crashes when AM654x CPSW NUSS network interface is going down
under high pressure of ingress traffic due to the race between
am65_cpsw_nuss_common_stop() and NAPI RX handler - they both trying to free
the same UDMA descriptor.

	kernel BUG at lib/genalloc.c:391!
	Internal error: Oops - BUG: 0 [ #1] PREEMPT SMP
	...
	Call trace:
	gen_pool_free+0xc8/0xd8
	k3_knav_pool_free+0x14/0x20
	am65_cpsw_nuss_rx_poll+0x224/0x420
	net_rx_action+0x10c/0x2d0
	__do_softirq+0x114/0x210
	run_ksoftirqd+0x30/0x40
	smpboot_thread_fn+0x168/0x268
	kthread+0x128/0x130
	ret_from_fork+0x10/0x18

Fix it by ensuring that NAPI is stopped at am65_cpsw_nuss_common_stop()
before cleaning up RX UDMA channels/rings.

Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com>
Signed-off-by: Sekhar Nori <nsekhar@ti.com>
Grygorii Strashko 6 years ago
parent
commit
815497a655
1 changed files with 2 additions and 3 deletions
  1. 2 3
      drivers/net/ethernet/ti/am65-cpsw-nuss.c

+ 2 - 3
drivers/net/ethernet/ti/am65-cpsw-nuss.c

@@ -523,6 +523,7 @@ static int am65_cpsw_nuss_common_stop(struct am65_cpsw_common *common)
 					msecs_to_jiffies(1000));
 	if (!i)
 		dev_err(common->dev, "tx timeout\n");
+	napi_disable(&common->napi_tx);
 
 	for (i = 0; i < AM65_CPSW_MAX_TX_QUEUES; i++) {
 		k3_nav_udmax_reset_tx_chn(common->tx_chns[i].tx_chn,
@@ -532,6 +533,7 @@ static int am65_cpsw_nuss_common_stop(struct am65_cpsw_common *common)
 	}
 
 	k3_nav_udmax_tdown_rx_chn(common->rx_chns.rx_chn, true);
+	napi_disable(&common->napi_rx);
 
 	for (i = 0; i < AM65_CPSW_MAX_RX_FLOWS; i++)
 		k3_nav_udmax_reset_rx_chn(common->rx_chns.rx_chn, i,
@@ -540,9 +542,6 @@ static int am65_cpsw_nuss_common_stop(struct am65_cpsw_common *common)
 
 	k3_nav_udmax_disable_rx_chn(common->rx_chns.rx_chn);
 
-	napi_disable(&common->napi_rx);
-	napi_disable(&common->napi_tx);
-
 	cpsw_ale_stop(common->ale);
 
 	writel(0, common->cpsw_base + AM65_CPSW_REG_CTL);