diff options
| author | Bryan Wu <bryan.wu@canonical.com> | 2010-05-28 06:40:39 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2010-05-28 06:40:39 -0400 |
| commit | 418bd0d4dfbff25ffe4365ddd3e7cba8c70ccba8 (patch) | |
| tree | 7366addfff922e8a0508054101c09a4593540a34 | |
| parent | b58ffb41fc09d1ffaca97e5ae801233575be2a7f (diff) | |
netdev/fec: fix ifconfig eth0 down hang issue
BugLink: http://bugs.launchpad.net/bugs/559065
In fec open/close function, we need to use phy_connect and phy_disconnect
operation before we start/stop phy. Otherwise it will cause system hang.
Only call fec_enet_mii_probe() in open function, because the first open
action will cause NULL pointer error.
Signed-off-by: Bryan Wu <bryan.wu@canonical.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
| -rw-r--r-- | drivers/net/fec.c | 28 |
1 files changed, 16 insertions, 12 deletions
diff --git a/drivers/net/fec.c b/drivers/net/fec.c index 326465ffbb23..ddf7a86cd466 100644 --- a/drivers/net/fec.c +++ b/drivers/net/fec.c | |||
| @@ -681,6 +681,8 @@ static int fec_enet_mii_probe(struct net_device *dev) | |||
| 681 | struct phy_device *phy_dev = NULL; | 681 | struct phy_device *phy_dev = NULL; |
| 682 | int phy_addr; | 682 | int phy_addr; |
| 683 | 683 | ||
| 684 | fep->phy_dev = NULL; | ||
| 685 | |||
| 684 | /* find the first phy */ | 686 | /* find the first phy */ |
| 685 | for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) { | 687 | for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) { |
| 686 | if (fep->mii_bus->phy_map[phy_addr]) { | 688 | if (fep->mii_bus->phy_map[phy_addr]) { |
| @@ -711,6 +713,11 @@ static int fec_enet_mii_probe(struct net_device *dev) | |||
| 711 | fep->link = 0; | 713 | fep->link = 0; |
| 712 | fep->full_duplex = 0; | 714 | fep->full_duplex = 0; |
| 713 | 715 | ||
| 716 | printk(KERN_INFO "%s: Freescale FEC PHY driver [%s] " | ||
| 717 | "(mii_bus:phy_addr=%s, irq=%d)\n", dev->name, | ||
| 718 | fep->phy_dev->drv->name, dev_name(&fep->phy_dev->dev), | ||
| 719 | fep->phy_dev->irq); | ||
| 720 | |||
| 714 | return 0; | 721 | return 0; |
| 715 | } | 722 | } |
| 716 | 723 | ||
| @@ -756,13 +763,8 @@ static int fec_enet_mii_init(struct platform_device *pdev) | |||
| 756 | if (mdiobus_register(fep->mii_bus)) | 763 | if (mdiobus_register(fep->mii_bus)) |
| 757 | goto err_out_free_mdio_irq; | 764 | goto err_out_free_mdio_irq; |
| 758 | 765 | ||
| 759 | if (fec_enet_mii_probe(dev) != 0) | ||
| 760 | goto err_out_unregister_bus; | ||
| 761 | |||
| 762 | return 0; | 766 | return 0; |
| 763 | 767 | ||
| 764 | err_out_unregister_bus: | ||
| 765 | mdiobus_unregister(fep->mii_bus); | ||
| 766 | err_out_free_mdio_irq: | 768 | err_out_free_mdio_irq: |
| 767 | kfree(fep->mii_bus->irq); | 769 | kfree(fep->mii_bus->irq); |
| 768 | err_out_free_mdiobus: | 770 | err_out_free_mdiobus: |
| @@ -915,7 +917,12 @@ fec_enet_open(struct net_device *dev) | |||
| 915 | if (ret) | 917 | if (ret) |
| 916 | return ret; | 918 | return ret; |
| 917 | 919 | ||
| 918 | /* schedule a link state check */ | 920 | /* Probe and connect to PHY when open the interface */ |
| 921 | ret = fec_enet_mii_probe(dev); | ||
| 922 | if (ret) { | ||
| 923 | fec_enet_free_buffers(dev); | ||
| 924 | return ret; | ||
| 925 | } | ||
| 919 | phy_start(fep->phy_dev); | 926 | phy_start(fep->phy_dev); |
| 920 | netif_start_queue(dev); | 927 | netif_start_queue(dev); |
| 921 | fep->opened = 1; | 928 | fep->opened = 1; |
| @@ -929,10 +936,12 @@ fec_enet_close(struct net_device *dev) | |||
| 929 | 936 | ||
| 930 | /* Don't know what to do yet. */ | 937 | /* Don't know what to do yet. */ |
| 931 | fep->opened = 0; | 938 | fep->opened = 0; |
| 932 | phy_stop(fep->phy_dev); | ||
| 933 | netif_stop_queue(dev); | 939 | netif_stop_queue(dev); |
| 934 | fec_stop(dev); | 940 | fec_stop(dev); |
| 935 | 941 | ||
| 942 | if (fep->phy_dev) | ||
| 943 | phy_disconnect(fep->phy_dev); | ||
| 944 | |||
| 936 | fec_enet_free_buffers(dev); | 945 | fec_enet_free_buffers(dev); |
| 937 | 946 | ||
| 938 | return 0; | 947 | return 0; |
| @@ -1316,11 +1325,6 @@ fec_probe(struct platform_device *pdev) | |||
| 1316 | if (ret) | 1325 | if (ret) |
| 1317 | goto failed_register; | 1326 | goto failed_register; |
| 1318 | 1327 | ||
| 1319 | printk(KERN_INFO "%s: Freescale FEC PHY driver [%s] " | ||
| 1320 | "(mii_bus:phy_addr=%s, irq=%d)\n", ndev->name, | ||
| 1321 | fep->phy_dev->drv->name, dev_name(&fep->phy_dev->dev), | ||
| 1322 | fep->phy_dev->irq); | ||
| 1323 | |||
| 1324 | return 0; | 1328 | return 0; |
| 1325 | 1329 | ||
| 1326 | failed_register: | 1330 | failed_register: |
