]> www.infradead.org Git - users/hch/dma-mapping.git/commitdiff
net: ethernet: ti: am65-cpsw: avoid devm_alloc_etherdev, fix module removal
authorNicolas Pitre <npitre@baylibre.com>
Fri, 4 Oct 2024 04:10:34 +0000 (00:10 -0400)
committerPaolo Abeni <pabeni@redhat.com>
Tue, 8 Oct 2024 08:30:30 +0000 (10:30 +0200)
Usage of devm_alloc_etherdev_mqs() conflicts with
am65_cpsw_nuss_cleanup_ndev() as the same struct net_device instances
get unregistered twice. Switch to alloc_etherdev_mqs() and make sure
am65_cpsw_nuss_cleanup_ndev() unregisters and frees those net_device
instances properly.

With this, it is finally possible to rmmod the driver without oopsing
the kernel.

Fixes: 93a76530316a ("net: ethernet: ti: introduce am65x/j721e gigabit eth subsystem driver")
Signed-off-by: Nicolas Pitre <npitre@baylibre.com>
Reviewed-by: Roger Quadros <roger@kernel.org>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
drivers/net/ethernet/ti/am65-cpsw-nuss.c

index 3fec2cd45f5ef8f6b98760c81a2b55e6e1ab48f7..0520e9f4bea7009c006908f4093ced816db37e01 100644 (file)
@@ -2744,10 +2744,9 @@ am65_cpsw_nuss_init_port_ndev(struct am65_cpsw_common *common, u32 port_idx)
                return 0;
 
        /* alloc netdev */
-       port->ndev = devm_alloc_etherdev_mqs(common->dev,
-                                            sizeof(struct am65_cpsw_ndev_priv),
-                                            AM65_CPSW_MAX_QUEUES,
-                                            AM65_CPSW_MAX_QUEUES);
+       port->ndev = alloc_etherdev_mqs(sizeof(struct am65_cpsw_ndev_priv),
+                                       AM65_CPSW_MAX_QUEUES,
+                                       AM65_CPSW_MAX_QUEUES);
        if (!port->ndev) {
                dev_err(dev, "error allocating slave net_device %u\n",
                        port->port_id);
@@ -2868,8 +2867,12 @@ static void am65_cpsw_nuss_cleanup_ndev(struct am65_cpsw_common *common)
 
        for (i = 0; i < common->port_num; i++) {
                port = &common->ports[i];
-               if (port->ndev && port->ndev->reg_state == NETREG_REGISTERED)
+               if (!port->ndev)
+                       continue;
+               if (port->ndev->reg_state == NETREG_REGISTERED)
                        unregister_netdev(port->ndev);
+               free_netdev(port->ndev);
+               port->ndev = NULL;
        }
 }
 
@@ -3613,16 +3616,17 @@ static int am65_cpsw_nuss_probe(struct platform_device *pdev)
 
        ret = am65_cpsw_nuss_init_ndevs(common);
        if (ret)
-               goto err_free_phylink;
+               goto err_ndevs_clear;
 
        ret = am65_cpsw_nuss_register_ndevs(common);
        if (ret)
-               goto err_free_phylink;
+               goto err_ndevs_clear;
 
        pm_runtime_put(dev);
        return 0;
 
-err_free_phylink:
+err_ndevs_clear:
+       am65_cpsw_nuss_cleanup_ndev(common);
        am65_cpsw_nuss_phylink_cleanup(common);
        am65_cpts_release(common->cpts);
 err_of_clear: