aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/freescale
diff options
context:
space:
mode:
authorLothar Waßmann <LW@KARO-electronics.de>2011-12-07 16:59:31 -0500
committerDavid S. Miller <davem@davemloft.net>2011-12-08 19:51:20 -0500
commite163cc97f9ac169f00e86df57bee365e82e9c365 (patch)
tree9c0071c6fc4e8add7055829fe7c9e1519deb40f7 /drivers/net/ethernet/freescale
parent42431dc24de343d62bb8fb885586de7f408919c8 (diff)
net/fec: fix the .remove code
The .remove code is broken in several ways. - mdiobus_unregister() is called twice for the same object in case of dual FEC - phy_disconnect() is being called when the PHY is already disconnected - the requested IRQ(s) are not freed - fec_stop() is being called with the inteface already stopped All of those lead to kernel crashes if the remove function is actually used. Signed-off-by: Lothar Waßmann <LW@KARO-electronics.de> Tested-by: Shawn Guo <shawn.guo@linaro.org> Acked-by: Shawn Guo <shawn.guo@linaro.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/freescale')
-rw-r--r--drivers/net/ethernet/freescale/fec.c31
1 files changed, 22 insertions, 9 deletions
diff --git a/drivers/net/ethernet/freescale/fec.c b/drivers/net/ethernet/freescale/fec.c
index ab0afb5961f6..01ee9cc417b2 100644
--- a/drivers/net/ethernet/freescale/fec.c
+++ b/drivers/net/ethernet/freescale/fec.c
@@ -259,6 +259,8 @@ struct fec_enet_private {
259/* Transmitter timeout */ 259/* Transmitter timeout */
260#define TX_TIMEOUT (2 * HZ) 260#define TX_TIMEOUT (2 * HZ)
261 261
262static int mii_cnt;
263
262static void *swap_buffer(void *bufaddr, int len) 264static void *swap_buffer(void *bufaddr, int len)
263{ 265{
264 int i; 266 int i;
@@ -1040,8 +1042,12 @@ static int fec_enet_mii_init(struct platform_device *pdev)
1040 */ 1042 */
1041 if ((id_entry->driver_data & FEC_QUIRK_ENET_MAC) && pdev->id > 0) { 1043 if ((id_entry->driver_data & FEC_QUIRK_ENET_MAC) && pdev->id > 0) {
1042 /* fec1 uses fec0 mii_bus */ 1044 /* fec1 uses fec0 mii_bus */
1043 fep->mii_bus = fec0_mii_bus; 1045 if (mii_cnt && fec0_mii_bus) {
1044 return 0; 1046 fep->mii_bus = fec0_mii_bus;
1047 mii_cnt++;
1048 return 0;
1049 }
1050 return -ENOENT;
1045 } 1051 }
1046 1052
1047 fep->mii_timeout = 0; 1053 fep->mii_timeout = 0;
@@ -1086,6 +1092,8 @@ static int fec_enet_mii_init(struct platform_device *pdev)
1086 if (mdiobus_register(fep->mii_bus)) 1092 if (mdiobus_register(fep->mii_bus))
1087 goto err_out_free_mdio_irq; 1093 goto err_out_free_mdio_irq;
1088 1094
1095 mii_cnt++;
1096
1089 /* save fec0 mii_bus */ 1097 /* save fec0 mii_bus */
1090 if (id_entry->driver_data & FEC_QUIRK_ENET_MAC) 1098 if (id_entry->driver_data & FEC_QUIRK_ENET_MAC)
1091 fec0_mii_bus = fep->mii_bus; 1099 fec0_mii_bus = fep->mii_bus;
@@ -1102,11 +1110,11 @@ err_out:
1102 1110
1103static void fec_enet_mii_remove(struct fec_enet_private *fep) 1111static void fec_enet_mii_remove(struct fec_enet_private *fep)
1104{ 1112{
1105 if (fep->phy_dev) 1113 if (--mii_cnt == 0) {
1106 phy_disconnect(fep->phy_dev); 1114 mdiobus_unregister(fep->mii_bus);
1107 mdiobus_unregister(fep->mii_bus); 1115 kfree(fep->mii_bus->irq);
1108 kfree(fep->mii_bus->irq); 1116 mdiobus_free(fep->mii_bus);
1109 mdiobus_free(fep->mii_bus); 1117 }
1110} 1118}
1111 1119
1112static int fec_enet_get_settings(struct net_device *ndev, 1120static int fec_enet_get_settings(struct net_device *ndev,
@@ -1646,13 +1654,18 @@ fec_drv_remove(struct platform_device *pdev)
1646 struct net_device *ndev = platform_get_drvdata(pdev); 1654 struct net_device *ndev = platform_get_drvdata(pdev);
1647 struct fec_enet_private *fep = netdev_priv(ndev); 1655 struct fec_enet_private *fep = netdev_priv(ndev);
1648 struct resource *r; 1656 struct resource *r;
1657 int i;
1649 1658
1650 fec_stop(ndev); 1659 unregister_netdev(ndev);
1651 fec_enet_mii_remove(fep); 1660 fec_enet_mii_remove(fep);
1661 for (i = 0; i < FEC_IRQ_NUM; i++) {
1662 int irq = platform_get_irq(pdev, i);
1663 if (irq > 0)
1664 free_irq(irq, ndev);
1665 }
1652 clk_disable(fep->clk); 1666 clk_disable(fep->clk);
1653 clk_put(fep->clk); 1667 clk_put(fep->clk);
1654 iounmap(fep->hwp); 1668 iounmap(fep->hwp);
1655 unregister_netdev(ndev);
1656 free_netdev(ndev); 1669 free_netdev(ndev);
1657 1670
1658 r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 1671 r = platform_get_resource(pdev, IORESOURCE_MEM, 0);