aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/sundance.c
diff options
context:
space:
mode:
authorDan Nicholson <dbn.lists@gmail.com>2008-08-20 19:51:59 -0400
committerJeff Garzik <jgarzik@redhat.com>2008-09-24 18:59:01 -0400
commit5050015597efb5e52a0b21e30a8adb2f7d7b7fba (patch)
tree21e5f3ce483a362e5d55a8a9ba448a89b451ec50 /drivers/net/sundance.c
parentb39d66a81fb4f5ab555f86a2e49f3714f8369a3d (diff)
sundance: set carrier status on link change events
Check if the link is available when a changed interrupt has been received and set the carrier status appropriately. The code is copied nearly verbatim from the dl2k module. The link status could be used in more places in the driver, but this is enough to get the carrier status reported to userspace. Fixes kernel bug #7487: http://bugzilla.kernel.org/show_bug.cgi?id=7487 [akpm@linux-foundation.org: coding-style fixes] Signed-off-by: Dan Nicholson <dbn.lists@gmail.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
Diffstat (limited to 'drivers/net/sundance.c')
-rw-r--r--drivers/net/sundance.c95
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);
409static int eeprom_read(void __iomem *ioaddr, int location); 409static int eeprom_read(void __iomem *ioaddr, int location);
410static int mdio_read(struct net_device *dev, int phy_id, int location); 410static int mdio_read(struct net_device *dev, int phy_id, int location);
411static void mdio_write(struct net_device *dev, int phy_id, int location, int value); 411static void mdio_write(struct net_device *dev, int phy_id, int location, int value);
412static int mdio_wait_link(struct net_device *dev, int wait);
412static int netdev_open(struct net_device *dev); 413static int netdev_open(struct net_device *dev);
413static void check_duplex(struct net_device *dev); 414static void check_duplex(struct net_device *dev);
414static void netdev_timer(unsigned long data); 415static 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
789static 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
788static int netdev_open(struct net_device *dev) 807static 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) {