diff options
author | Sebastian Siewior <bigeasy@linutronix.de> | 2013-04-24 04:48:23 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-04-25 04:12:29 -0400 |
commit | d1bd9acfa3419dc9d5c32589b34a370ca6ae100e (patch) | |
tree | 71f1e076abd4d043f5eadb83b8c252fd5d6c02b5 /drivers/net/ethernet/ti | |
parent | 4bc21d4162366bb892dc1a4a92110c656e2622ca (diff) |
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: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Acked-by: Mugunthan V N <mugunthanvnm@ti.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/ti')
-rw-r--r-- | drivers/net/ethernet/ti/cpsw.c | 23 |
1 files changed, 16 insertions, 7 deletions
diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index d9f5e74cdcfc..93a60e238146 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c | |||
@@ -1632,7 +1632,7 @@ static int cpsw_probe_dual_emac(struct platform_device *pdev, | |||
1632 | 1632 | ||
1633 | static int cpsw_probe(struct platform_device *pdev) | 1633 | static int cpsw_probe(struct platform_device *pdev) |
1634 | { | 1634 | { |
1635 | struct cpsw_platform_data *data = pdev->dev.platform_data; | 1635 | struct cpsw_platform_data *data; |
1636 | struct net_device *ndev; | 1636 | struct net_device *ndev; |
1637 | struct cpsw_priv *priv; | 1637 | struct cpsw_priv *priv; |
1638 | struct cpdma_params dma_params; | 1638 | struct cpdma_params dma_params; |
@@ -1845,7 +1845,7 @@ static int cpsw_probe(struct platform_device *pdev) | |||
1845 | goto clean_ale_ret; | 1845 | goto clean_ale_ret; |
1846 | } | 1846 | } |
1847 | priv->irqs_table[k] = i; | 1847 | priv->irqs_table[k] = i; |
1848 | priv->num_irqs = k; | 1848 | priv->num_irqs = k + 1; |
1849 | } | 1849 | } |
1850 | k++; | 1850 | k++; |
1851 | } | 1851 | } |
@@ -1883,7 +1883,8 @@ static int cpsw_probe(struct platform_device *pdev) | |||
1883 | return 0; | 1883 | return 0; |
1884 | 1884 | ||
1885 | clean_irq_ret: | 1885 | clean_irq_ret: |
1886 | free_irq(ndev->irq, priv); | 1886 | for (i = 0; i < priv->num_irqs; i++) |
1887 | free_irq(priv->irqs_table[i], priv); | ||
1887 | clean_ale_ret: | 1888 | clean_ale_ret: |
1888 | cpsw_ale_destroy(priv->ale); | 1889 | cpsw_ale_destroy(priv->ale); |
1889 | clean_dma_ret: | 1890 | clean_dma_ret: |
@@ -1906,7 +1907,8 @@ clean_slave_ret: | |||
1906 | pm_runtime_disable(&pdev->dev); | 1907 | pm_runtime_disable(&pdev->dev); |
1907 | kfree(priv->slaves); | 1908 | kfree(priv->slaves); |
1908 | clean_ndev_ret: | 1909 | clean_ndev_ret: |
1909 | free_netdev(ndev); | 1910 | kfree(priv->data.slave_data); |
1911 | free_netdev(priv->ndev); | ||
1910 | return ret; | 1912 | return ret; |
1911 | } | 1913 | } |
1912 | 1914 | ||
@@ -1914,12 +1916,17 @@ static int cpsw_remove(struct platform_device *pdev) | |||
1914 | { | 1916 | { |
1915 | struct net_device *ndev = platform_get_drvdata(pdev); | 1917 | struct net_device *ndev = platform_get_drvdata(pdev); |
1916 | struct cpsw_priv *priv = netdev_priv(ndev); | 1918 | struct cpsw_priv *priv = netdev_priv(ndev); |
1919 | int i; | ||
1917 | 1920 | ||
1918 | pr_info("removing device"); | ||
1919 | platform_set_drvdata(pdev, NULL); | 1921 | platform_set_drvdata(pdev, NULL); |
1922 | if (priv->data.dual_emac) | ||
1923 | unregister_netdev(cpsw_get_slave_ndev(priv, 1)); | ||
1924 | unregister_netdev(ndev); | ||
1920 | 1925 | ||
1921 | cpts_unregister(priv->cpts); | 1926 | cpts_unregister(priv->cpts); |
1922 | free_irq(ndev->irq, priv); | 1927 | for (i = 0; i < priv->num_irqs; i++) |
1928 | free_irq(priv->irqs_table[i], priv); | ||
1929 | |||
1923 | cpsw_ale_destroy(priv->ale); | 1930 | cpsw_ale_destroy(priv->ale); |
1924 | cpdma_chan_destroy(priv->txch); | 1931 | cpdma_chan_destroy(priv->txch); |
1925 | cpdma_chan_destroy(priv->rxch); | 1932 | cpdma_chan_destroy(priv->rxch); |
@@ -1933,8 +1940,10 @@ static int cpsw_remove(struct platform_device *pdev) | |||
1933 | pm_runtime_disable(&pdev->dev); | 1940 | pm_runtime_disable(&pdev->dev); |
1934 | clk_put(priv->clk); | 1941 | clk_put(priv->clk); |
1935 | kfree(priv->slaves); | 1942 | kfree(priv->slaves); |
1943 | kfree(priv->data.slave_data); | ||
1944 | if (priv->data.dual_emac) | ||
1945 | free_netdev(cpsw_get_slave_ndev(priv, 1)); | ||
1936 | free_netdev(ndev); | 1946 | free_netdev(ndev); |
1937 | |||
1938 | return 0; | 1947 | return 0; |
1939 | } | 1948 | } |
1940 | 1949 | ||