diff options
-rw-r--r-- | drivers/net/sundance.c | 95 |
1 files changed, 62 insertions, 33 deletions
diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c index 7d5561b8241c..f860ea150395 100644 --- a/drivers/net/sundance.c +++ b/drivers/net/sundance.c | |||
@@ -409,6 +409,7 @@ static int change_mtu(struct net_device *dev, int new_mtu); | |||
409 | static int eeprom_read(void __iomem *ioaddr, int location); | 409 | static int eeprom_read(void __iomem *ioaddr, int location); |
410 | static int mdio_read(struct net_device *dev, int phy_id, int location); | 410 | static int mdio_read(struct net_device *dev, int phy_id, int location); |
411 | static void mdio_write(struct net_device *dev, int phy_id, int location, int value); | 411 | static void mdio_write(struct net_device *dev, int phy_id, int location, int value); |
412 | static int mdio_wait_link(struct net_device *dev, int wait); | ||
412 | static int netdev_open(struct net_device *dev); | 413 | static int netdev_open(struct net_device *dev); |
413 | static void check_duplex(struct net_device *dev); | 414 | static void check_duplex(struct net_device *dev); |
414 | static void netdev_timer(unsigned long data); | 415 | static void netdev_timer(unsigned long data); |
@@ -785,6 +786,24 @@ static void mdio_write(struct net_device *dev, int phy_id, int location, int val | |||
785 | return; | 786 | return; |
786 | } | 787 | } |
787 | 788 | ||
789 | static int mdio_wait_link(struct net_device *dev, int wait) | ||
790 | { | ||
791 | int bmsr; | ||
792 | int phy_id; | ||
793 | struct netdev_private *np; | ||
794 | |||
795 | np = netdev_priv(dev); | ||
796 | phy_id = np->phys[0]; | ||
797 | |||
798 | do { | ||
799 | bmsr = mdio_read(dev, phy_id, MII_BMSR); | ||
800 | if (bmsr & 0x0004) | ||
801 | return 0; | ||
802 | mdelay(1); | ||
803 | } while (--wait > 0); | ||
804 | return -1; | ||
805 | } | ||
806 | |||
788 | static int netdev_open(struct net_device *dev) | 807 | static int netdev_open(struct net_device *dev) |
789 | { | 808 | { |
790 | struct netdev_private *np = netdev_priv(dev); | 809 | struct netdev_private *np = netdev_priv(dev); |
@@ -1393,41 +1412,51 @@ static void netdev_error(struct net_device *dev, int intr_status) | |||
1393 | int speed; | 1412 | int speed; |
1394 | 1413 | ||
1395 | if (intr_status & LinkChange) { | 1414 | if (intr_status & LinkChange) { |
1396 | if (np->an_enable) { | 1415 | if (mdio_wait_link(dev, 10) == 0) { |
1397 | mii_advertise = mdio_read (dev, np->phys[0], MII_ADVERTISE); | 1416 | printk(KERN_INFO "%s: Link up\n", dev->name); |
1398 | mii_lpa= mdio_read (dev, np->phys[0], MII_LPA); | 1417 | if (np->an_enable) { |
1399 | mii_advertise &= mii_lpa; | 1418 | mii_advertise = mdio_read(dev, np->phys[0], |
1400 | printk (KERN_INFO "%s: Link changed: ", dev->name); | 1419 | MII_ADVERTISE); |
1401 | if (mii_advertise & ADVERTISE_100FULL) { | 1420 | mii_lpa = mdio_read(dev, np->phys[0], MII_LPA); |
1402 | np->speed = 100; | 1421 | mii_advertise &= mii_lpa; |
1403 | printk ("100Mbps, full duplex\n"); | 1422 | printk(KERN_INFO "%s: Link changed: ", |
1404 | } else if (mii_advertise & ADVERTISE_100HALF) { | 1423 | dev->name); |
1405 | np->speed = 100; | 1424 | if (mii_advertise & ADVERTISE_100FULL) { |
1406 | printk ("100Mbps, half duplex\n"); | 1425 | np->speed = 100; |
1407 | } else if (mii_advertise & ADVERTISE_10FULL) { | 1426 | printk("100Mbps, full duplex\n"); |
1408 | np->speed = 10; | 1427 | } else if (mii_advertise & ADVERTISE_100HALF) { |
1409 | printk ("10Mbps, full duplex\n"); | 1428 | np->speed = 100; |
1410 | } else if (mii_advertise & ADVERTISE_10HALF) { | 1429 | printk("100Mbps, half duplex\n"); |
1411 | np->speed = 10; | 1430 | } else if (mii_advertise & ADVERTISE_10FULL) { |
1412 | printk ("10Mbps, half duplex\n"); | 1431 | np->speed = 10; |
1413 | } else | 1432 | printk("10Mbps, full duplex\n"); |
1414 | printk ("\n"); | 1433 | } else if (mii_advertise & ADVERTISE_10HALF) { |
1434 | np->speed = 10; | ||
1435 | printk("10Mbps, half duplex\n"); | ||
1436 | } else | ||
1437 | printk("\n"); | ||
1415 | 1438 | ||
1439 | } else { | ||
1440 | mii_ctl = mdio_read(dev, np->phys[0], MII_BMCR); | ||
1441 | speed = (mii_ctl & BMCR_SPEED100) ? 100 : 10; | ||
1442 | np->speed = speed; | ||
1443 | printk(KERN_INFO "%s: Link changed: %dMbps ,", | ||
1444 | dev->name, speed); | ||
1445 | printk("%s duplex.\n", | ||
1446 | (mii_ctl & BMCR_FULLDPLX) ? | ||
1447 | "full" : "half"); | ||
1448 | } | ||
1449 | check_duplex(dev); | ||
1450 | if (np->flowctrl && np->mii_if.full_duplex) { | ||
1451 | iowrite16(ioread16(ioaddr + MulticastFilter1+2) | 0x0200, | ||
1452 | ioaddr + MulticastFilter1+2); | ||
1453 | iowrite16(ioread16(ioaddr + MACCtrl0) | EnbFlowCtrl, | ||
1454 | ioaddr + MACCtrl0); | ||
1455 | } | ||
1456 | netif_carrier_on(dev); | ||
1416 | } else { | 1457 | } else { |
1417 | mii_ctl = mdio_read (dev, np->phys[0], MII_BMCR); | 1458 | printk(KERN_INFO "%s: Link down\n", dev->name); |
1418 | speed = (mii_ctl & BMCR_SPEED100) ? 100 : 10; | 1459 | netif_carrier_off(dev); |
1419 | np->speed = speed; | ||
1420 | printk (KERN_INFO "%s: Link changed: %dMbps ,", | ||
1421 | dev->name, speed); | ||
1422 | printk ("%s duplex.\n", (mii_ctl & BMCR_FULLDPLX) ? | ||
1423 | "full" : "half"); | ||
1424 | } | ||
1425 | check_duplex (dev); | ||
1426 | if (np->flowctrl && np->mii_if.full_duplex) { | ||
1427 | iowrite16(ioread16(ioaddr + MulticastFilter1+2) | 0x0200, | ||
1428 | ioaddr + MulticastFilter1+2); | ||
1429 | iowrite16(ioread16(ioaddr + MACCtrl0) | EnbFlowCtrl, | ||
1430 | ioaddr + MACCtrl0); | ||
1431 | } | 1460 | } |
1432 | } | 1461 | } |
1433 | if (intr_status & StatsMax) { | 1462 | if (intr_status & StatsMax) { |