Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d1bd9acf authored by Sebastian Siewior's avatar Sebastian Siewior Committed by David S. Miller
Browse files

net/cpsw: make sure modules remove does not leak any ressources



This driver does not clean up properly after leaving. Here is a list:
- Use unregister_netdev(). free_netdev() is good but not enough
- Use the above also on the other ndev in case of dual mac
- Free data.slave_data. The name of the strucre makes it look like
  it is platform_data but it is not. It is just a trick!
- Free all irqs. Again: freeing one irq is good start, but freeing all
  of them is better.

With this rmmod & modprobe of cpsw seems to work. The remaining issue
is:
|WARNING: at fs/sysfs/dir.c:536 sysfs_add_one+0x9c/0xd4()
|sysfs: cannot create duplicate filename '/devices/ocp.2/4a100000.ethernet/4a101000.mdio'
|WARNING: at lib/kobject.c:196 kobject_add_internal+0x1a4/0x1c8()

comming from of_platform_populate() and I am not sure that this belongs
here.

Signed-off-by: default avatarSebastian Andrzej Siewior <bigeasy@linutronix.de>
Acked-by: default avatarMugunthan V N <mugunthanvnm@ti.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 4bc21d41
Loading
Loading
Loading
Loading
+16 −7
Original line number Original line Diff line number Diff line
@@ -1632,7 +1632,7 @@ static int cpsw_probe_dual_emac(struct platform_device *pdev,


static int cpsw_probe(struct platform_device *pdev)
static int cpsw_probe(struct platform_device *pdev)
{
{
	struct cpsw_platform_data	*data = pdev->dev.platform_data;
	struct cpsw_platform_data	*data;
	struct net_device		*ndev;
	struct net_device		*ndev;
	struct cpsw_priv		*priv;
	struct cpsw_priv		*priv;
	struct cpdma_params		dma_params;
	struct cpdma_params		dma_params;
@@ -1845,7 +1845,7 @@ static int cpsw_probe(struct platform_device *pdev)
				goto clean_ale_ret;
				goto clean_ale_ret;
			}
			}
			priv->irqs_table[k] = i;
			priv->irqs_table[k] = i;
			priv->num_irqs = k;
			priv->num_irqs = k + 1;
		}
		}
		k++;
		k++;
	}
	}
@@ -1883,7 +1883,8 @@ static int cpsw_probe(struct platform_device *pdev)
	return 0;
	return 0;


clean_irq_ret:
clean_irq_ret:
	free_irq(ndev->irq, priv);
	for (i = 0; i < priv->num_irqs; i++)
		free_irq(priv->irqs_table[i], priv);
clean_ale_ret:
clean_ale_ret:
	cpsw_ale_destroy(priv->ale);
	cpsw_ale_destroy(priv->ale);
clean_dma_ret:
clean_dma_ret:
@@ -1906,7 +1907,8 @@ clean_slave_ret:
	pm_runtime_disable(&pdev->dev);
	pm_runtime_disable(&pdev->dev);
	kfree(priv->slaves);
	kfree(priv->slaves);
clean_ndev_ret:
clean_ndev_ret:
	free_netdev(ndev);
	kfree(priv->data.slave_data);
	free_netdev(priv->ndev);
	return ret;
	return ret;
}
}


@@ -1914,12 +1916,17 @@ static int cpsw_remove(struct platform_device *pdev)
{
{
	struct net_device *ndev = platform_get_drvdata(pdev);
	struct net_device *ndev = platform_get_drvdata(pdev);
	struct cpsw_priv *priv = netdev_priv(ndev);
	struct cpsw_priv *priv = netdev_priv(ndev);
	int i;


	pr_info("removing device");
	platform_set_drvdata(pdev, NULL);
	platform_set_drvdata(pdev, NULL);
	if (priv->data.dual_emac)
		unregister_netdev(cpsw_get_slave_ndev(priv, 1));
	unregister_netdev(ndev);


	cpts_unregister(priv->cpts);
	cpts_unregister(priv->cpts);
	free_irq(ndev->irq, priv);
	for (i = 0; i < priv->num_irqs; i++)
		free_irq(priv->irqs_table[i], priv);

	cpsw_ale_destroy(priv->ale);
	cpsw_ale_destroy(priv->ale);
	cpdma_chan_destroy(priv->txch);
	cpdma_chan_destroy(priv->txch);
	cpdma_chan_destroy(priv->rxch);
	cpdma_chan_destroy(priv->rxch);
@@ -1933,8 +1940,10 @@ static int cpsw_remove(struct platform_device *pdev)
	pm_runtime_disable(&pdev->dev);
	pm_runtime_disable(&pdev->dev);
	clk_put(priv->clk);
	clk_put(priv->clk);
	kfree(priv->slaves);
	kfree(priv->slaves);
	kfree(priv->data.slave_data);
	if (priv->data.dual_emac)
		free_netdev(cpsw_get_slave_ndev(priv, 1));
	free_netdev(ndev);
	free_netdev(ndev);

	return 0;
	return 0;
}
}