Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'net-cpsw-execute-ndo_set_rx_mode-callback-in-a-work-queue'

Kevin Hao says:

====================
net: cpsw: Execute ndo_set_rx_mode callback in a work queue

These two patches resolve an RTNL assertion call trace issue
in both the legacy and new cpsw drivers.
====================

Link: https://patch.msgid.link/20260203-bbb-v5-0-ea0ea217a85c@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

+65 -11
+35 -6
drivers/net/ethernet/ti/cpsw.c
··· 305 305 return 0; 306 306 } 307 307 308 - static void cpsw_ndo_set_rx_mode(struct net_device *ndev) 308 + static void cpsw_ndo_set_rx_mode_work(struct work_struct *work) 309 309 { 310 - struct cpsw_priv *priv = netdev_priv(ndev); 310 + struct cpsw_priv *priv = container_of(work, struct cpsw_priv, rx_mode_work); 311 311 struct cpsw_common *cpsw = priv->cpsw; 312 + struct net_device *ndev = priv->ndev; 312 313 int slave_port = -1; 314 + 315 + rtnl_lock(); 316 + if (!netif_running(ndev)) 317 + goto unlock_rtnl; 318 + 319 + netif_addr_lock_bh(ndev); 313 320 314 321 if (cpsw->data.dual_emac) 315 322 slave_port = priv->emac_port + 1; ··· 325 318 /* Enable promiscuous mode */ 326 319 cpsw_set_promiscious(ndev, true); 327 320 cpsw_ale_set_allmulti(cpsw->ale, IFF_ALLMULTI, slave_port); 328 - return; 321 + goto unlock_addr; 329 322 } else { 330 323 /* Disable promiscuous mode */ 331 324 cpsw_set_promiscious(ndev, false); ··· 338 331 /* add/remove mcast address either for real netdev or for vlan */ 339 332 __hw_addr_ref_sync_dev(&ndev->mc, ndev, cpsw_add_mc_addr, 340 333 cpsw_del_mc_addr); 334 + 335 + unlock_addr: 336 + netif_addr_unlock_bh(ndev); 337 + unlock_rtnl: 338 + rtnl_unlock(); 339 + } 340 + 341 + static void cpsw_ndo_set_rx_mode(struct net_device *ndev) 342 + { 343 + struct cpsw_priv *priv = netdev_priv(ndev); 344 + 345 + schedule_work(&priv->rx_mode_work); 341 346 } 342 347 343 348 static unsigned int cpsw_rxbuf_total_len(unsigned int len) ··· 1491 1472 priv_sl2->ndev = ndev; 1492 1473 priv_sl2->dev = &ndev->dev; 1493 1474 priv_sl2->msg_enable = netif_msg_init(debug_level, CPSW_DEBUG); 1475 + INIT_WORK(&priv_sl2->rx_mode_work, cpsw_ndo_set_rx_mode_work); 1494 1476 1495 1477 if (is_valid_ether_addr(data->slave_data[1].mac_addr)) { 1496 1478 memcpy(priv_sl2->mac_addr, data->slave_data[1].mac_addr, ··· 1673 1653 priv->dev = dev; 1674 1654 priv->msg_enable = netif_msg_init(debug_level, CPSW_DEBUG); 1675 1655 priv->emac_port = 0; 1656 + INIT_WORK(&priv->rx_mode_work, cpsw_ndo_set_rx_mode_work); 1676 1657 1677 1658 if (is_valid_ether_addr(data->slave_data[0].mac_addr)) { 1678 1659 memcpy(priv->mac_addr, data->slave_data[0].mac_addr, ETH_ALEN); ··· 1779 1758 static void cpsw_remove(struct platform_device *pdev) 1780 1759 { 1781 1760 struct cpsw_common *cpsw = platform_get_drvdata(pdev); 1761 + struct net_device *ndev; 1762 + struct cpsw_priv *priv; 1782 1763 int i, ret; 1783 1764 1784 1765 ret = pm_runtime_resume_and_get(&pdev->dev); ··· 1793 1770 return; 1794 1771 } 1795 1772 1796 - for (i = 0; i < cpsw->data.slaves; i++) 1797 - if (cpsw->slaves[i].ndev) 1798 - unregister_netdev(cpsw->slaves[i].ndev); 1773 + for (i = 0; i < cpsw->data.slaves; i++) { 1774 + ndev = cpsw->slaves[i].ndev; 1775 + if (!ndev) 1776 + continue; 1777 + 1778 + priv = netdev_priv(ndev); 1779 + unregister_netdev(ndev); 1780 + disable_work_sync(&priv->rx_mode_work); 1781 + } 1799 1782 1800 1783 cpts_release(cpsw->cpts); 1801 1784 cpdma_ctlr_destroy(cpsw->dma);
+29 -5
drivers/net/ethernet/ti/cpsw_new.c
··· 248 248 return 0; 249 249 } 250 250 251 - static void cpsw_ndo_set_rx_mode(struct net_device *ndev) 251 + static void cpsw_ndo_set_rx_mode_work(struct work_struct *work) 252 252 { 253 - struct cpsw_priv *priv = netdev_priv(ndev); 253 + struct cpsw_priv *priv = container_of(work, struct cpsw_priv, rx_mode_work); 254 254 struct cpsw_common *cpsw = priv->cpsw; 255 + struct net_device *ndev = priv->ndev; 255 256 257 + rtnl_lock(); 258 + if (!netif_running(ndev)) 259 + goto unlock_rtnl; 260 + 261 + netif_addr_lock_bh(ndev); 256 262 if (ndev->flags & IFF_PROMISC) { 257 263 /* Enable promiscuous mode */ 258 264 cpsw_set_promiscious(ndev, true); 259 265 cpsw_ale_set_allmulti(cpsw->ale, IFF_ALLMULTI, priv->emac_port); 260 - return; 266 + goto unlock_addr; 261 267 } 262 268 263 269 /* Disable promiscuous mode */ ··· 276 270 /* add/remove mcast address either for real netdev or for vlan */ 277 271 __hw_addr_ref_sync_dev(&ndev->mc, ndev, cpsw_add_mc_addr, 278 272 cpsw_del_mc_addr); 273 + 274 + unlock_addr: 275 + netif_addr_unlock_bh(ndev); 276 + unlock_rtnl: 277 + rtnl_unlock(); 278 + } 279 + 280 + static void cpsw_ndo_set_rx_mode(struct net_device *ndev) 281 + { 282 + struct cpsw_priv *priv = netdev_priv(ndev); 283 + 284 + schedule_work(&priv->rx_mode_work); 279 285 } 280 286 281 287 static unsigned int cpsw_rxbuf_total_len(unsigned int len) ··· 1416 1398 priv->msg_enable = netif_msg_init(debug_level, CPSW_DEBUG); 1417 1399 priv->emac_port = i + 1; 1418 1400 priv->tx_packet_min = CPSW_MIN_PACKET_SIZE; 1401 + INIT_WORK(&priv->rx_mode_work, cpsw_ndo_set_rx_mode_work); 1419 1402 1420 1403 if (is_valid_ether_addr(slave_data->mac_addr)) { 1421 1404 ether_addr_copy(priv->mac_addr, slave_data->mac_addr); ··· 1466 1447 1467 1448 static void cpsw_unregister_ports(struct cpsw_common *cpsw) 1468 1449 { 1450 + struct net_device *ndev; 1451 + struct cpsw_priv *priv; 1469 1452 int i = 0; 1470 1453 1471 1454 for (i = 0; i < cpsw->data.slaves; i++) { 1472 - if (!cpsw->slaves[i].ndev) 1455 + ndev = cpsw->slaves[i].ndev; 1456 + if (!ndev) 1473 1457 continue; 1474 1458 1475 - unregister_netdev(cpsw->slaves[i].ndev); 1459 + priv = netdev_priv(ndev); 1460 + unregister_netdev(ndev); 1461 + disable_work_sync(&priv->rx_mode_work); 1476 1462 } 1477 1463 } 1478 1464
+1
drivers/net/ethernet/ti/cpsw_priv.h
··· 391 391 u32 tx_packet_min; 392 392 struct cpsw_ale_ratelimit ale_bc_ratelimit; 393 393 struct cpsw_ale_ratelimit ale_mc_ratelimit; 394 + struct work_struct rx_mode_work; 394 395 }; 395 396 396 397 #define ndev_to_cpsw(ndev) (((struct cpsw_priv *)netdev_priv(ndev))->cpsw)