diff options
-rw-r--r-- | drivers/net/dm9000.c | 143 | ||||
-rw-r--r-- | drivers/net/dm9000.h | 7 |
2 files changed, 142 insertions, 8 deletions
diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c index 31b8bef49d2e..3aab2e466008 100644 --- a/drivers/net/dm9000.c +++ b/drivers/net/dm9000.c | |||
@@ -100,6 +100,7 @@ typedef struct board_info { | |||
100 | 100 | ||
101 | unsigned int flags; | 101 | unsigned int flags; |
102 | unsigned int in_suspend :1; | 102 | unsigned int in_suspend :1; |
103 | unsigned int wake_supported :1; | ||
103 | int debug_level; | 104 | int debug_level; |
104 | 105 | ||
105 | enum dm9000_type type; | 106 | enum dm9000_type type; |
@@ -116,6 +117,8 @@ typedef struct board_info { | |||
116 | struct resource *data_req; | 117 | struct resource *data_req; |
117 | struct resource *irq_res; | 118 | struct resource *irq_res; |
118 | 119 | ||
120 | int irq_wake; | ||
121 | |||
119 | struct mutex addr_lock; /* phy and eeprom access lock */ | 122 | struct mutex addr_lock; /* phy and eeprom access lock */ |
120 | 123 | ||
121 | struct delayed_work phy_poll; | 124 | struct delayed_work phy_poll; |
@@ -125,6 +128,7 @@ typedef struct board_info { | |||
125 | 128 | ||
126 | struct mii_if_info mii; | 129 | struct mii_if_info mii; |
127 | u32 msg_enable; | 130 | u32 msg_enable; |
131 | u32 wake_state; | ||
128 | 132 | ||
129 | int rx_csum; | 133 | int rx_csum; |
130 | int can_csum; | 134 | int can_csum; |
@@ -568,6 +572,54 @@ static int dm9000_set_eeprom(struct net_device *dev, | |||
568 | return 0; | 572 | return 0; |
569 | } | 573 | } |
570 | 574 | ||
575 | static void dm9000_get_wol(struct net_device *dev, struct ethtool_wolinfo *w) | ||
576 | { | ||
577 | board_info_t *dm = to_dm9000_board(dev); | ||
578 | |||
579 | memset(w, 0, sizeof(struct ethtool_wolinfo)); | ||
580 | |||
581 | /* note, we could probably support wake-phy too */ | ||
582 | w->supported = dm->wake_supported ? WAKE_MAGIC : 0; | ||
583 | w->wolopts = dm->wake_state; | ||
584 | } | ||
585 | |||
586 | static int dm9000_set_wol(struct net_device *dev, struct ethtool_wolinfo *w) | ||
587 | { | ||
588 | board_info_t *dm = to_dm9000_board(dev); | ||
589 | unsigned long flags; | ||
590 | u32 opts = w->wolopts; | ||
591 | u32 wcr = 0; | ||
592 | |||
593 | if (!dm->wake_supported) | ||
594 | return -EOPNOTSUPP; | ||
595 | |||
596 | if (opts & ~WAKE_MAGIC) | ||
597 | return -EINVAL; | ||
598 | |||
599 | if (opts & WAKE_MAGIC) | ||
600 | wcr |= WCR_MAGICEN; | ||
601 | |||
602 | mutex_lock(&dm->addr_lock); | ||
603 | |||
604 | spin_lock_irqsave(&dm->lock, flags); | ||
605 | iow(dm, DM9000_WCR, wcr); | ||
606 | spin_unlock_irqrestore(&dm->lock, flags); | ||
607 | |||
608 | mutex_unlock(&dm->addr_lock); | ||
609 | |||
610 | if (dm->wake_state != opts) { | ||
611 | /* change in wol state, update IRQ state */ | ||
612 | |||
613 | if (!dm->wake_state) | ||
614 | set_irq_wake(dm->irq_wake, 1); | ||
615 | else if (dm->wake_state & !opts) | ||
616 | set_irq_wake(dm->irq_wake, 0); | ||
617 | } | ||
618 | |||
619 | dm->wake_state = opts; | ||
620 | return 0; | ||
621 | } | ||
622 | |||
571 | static const struct ethtool_ops dm9000_ethtool_ops = { | 623 | static const struct ethtool_ops dm9000_ethtool_ops = { |
572 | .get_drvinfo = dm9000_get_drvinfo, | 624 | .get_drvinfo = dm9000_get_drvinfo, |
573 | .get_settings = dm9000_get_settings, | 625 | .get_settings = dm9000_get_settings, |
@@ -576,6 +628,8 @@ static const struct ethtool_ops dm9000_ethtool_ops = { | |||
576 | .set_msglevel = dm9000_set_msglevel, | 628 | .set_msglevel = dm9000_set_msglevel, |
577 | .nway_reset = dm9000_nway_reset, | 629 | .nway_reset = dm9000_nway_reset, |
578 | .get_link = dm9000_get_link, | 630 | .get_link = dm9000_get_link, |
631 | .get_wol = dm9000_get_wol, | ||
632 | .set_wol = dm9000_set_wol, | ||
579 | .get_eeprom_len = dm9000_get_eeprom_len, | 633 | .get_eeprom_len = dm9000_get_eeprom_len, |
580 | .get_eeprom = dm9000_get_eeprom, | 634 | .get_eeprom = dm9000_get_eeprom, |
581 | .set_eeprom = dm9000_set_eeprom, | 635 | .set_eeprom = dm9000_set_eeprom, |
@@ -722,6 +776,7 @@ dm9000_init_dm9000(struct net_device *dev) | |||
722 | { | 776 | { |
723 | board_info_t *db = netdev_priv(dev); | 777 | board_info_t *db = netdev_priv(dev); |
724 | unsigned int imr; | 778 | unsigned int imr; |
779 | unsigned int ncr; | ||
725 | 780 | ||
726 | dm9000_dbg(db, 1, "entering %s\n", __func__); | 781 | dm9000_dbg(db, 1, "entering %s\n", __func__); |
727 | 782 | ||
@@ -736,8 +791,15 @@ dm9000_init_dm9000(struct net_device *dev) | |||
736 | iow(db, DM9000_GPCR, GPCR_GEP_CNTL); /* Let GPIO0 output */ | 791 | iow(db, DM9000_GPCR, GPCR_GEP_CNTL); /* Let GPIO0 output */ |
737 | iow(db, DM9000_GPR, 0); /* Enable PHY */ | 792 | iow(db, DM9000_GPR, 0); /* Enable PHY */ |
738 | 793 | ||
739 | if (db->flags & DM9000_PLATF_EXT_PHY) | 794 | ncr = (db->flags & DM9000_PLATF_EXT_PHY) ? NCR_EXT_PHY : 0; |
740 | iow(db, DM9000_NCR, NCR_EXT_PHY); | 795 | |
796 | /* if wol is needed, then always set NCR_WAKEEN otherwise we end | ||
797 | * up dumping the wake events if we disable this. There is already | ||
798 | * a wake-mask in DM9000_WCR */ | ||
799 | if (db->wake_supported) | ||
800 | ncr |= NCR_WAKEEN; | ||
801 | |||
802 | iow(db, DM9000_NCR, ncr); | ||
741 | 803 | ||
742 | /* Program operating register */ | 804 | /* Program operating register */ |
743 | iow(db, DM9000_TCR, 0); /* TX Polling clear */ | 805 | iow(db, DM9000_TCR, 0); /* TX Polling clear */ |
@@ -1045,6 +1107,41 @@ static irqreturn_t dm9000_interrupt(int irq, void *dev_id) | |||
1045 | return IRQ_HANDLED; | 1107 | return IRQ_HANDLED; |
1046 | } | 1108 | } |
1047 | 1109 | ||
1110 | static irqreturn_t dm9000_wol_interrupt(int irq, void *dev_id) | ||
1111 | { | ||
1112 | struct net_device *dev = dev_id; | ||
1113 | board_info_t *db = netdev_priv(dev); | ||
1114 | unsigned long flags; | ||
1115 | unsigned nsr, wcr; | ||
1116 | |||
1117 | spin_lock_irqsave(&db->lock, flags); | ||
1118 | |||
1119 | nsr = ior(db, DM9000_NSR); | ||
1120 | wcr = ior(db, DM9000_WCR); | ||
1121 | |||
1122 | dev_dbg(db->dev, "%s: NSR=0x%02x, WCR=0x%02x\n", __func__, nsr, wcr); | ||
1123 | |||
1124 | if (nsr & NSR_WAKEST) { | ||
1125 | /* clear, so we can avoid */ | ||
1126 | iow(db, DM9000_NSR, NSR_WAKEST); | ||
1127 | |||
1128 | if (wcr & WCR_LINKST) | ||
1129 | dev_info(db->dev, "wake by link status change\n"); | ||
1130 | if (wcr & WCR_SAMPLEST) | ||
1131 | dev_info(db->dev, "wake by sample packet\n"); | ||
1132 | if (wcr & WCR_MAGICST ) | ||
1133 | dev_info(db->dev, "wake by magic packet\n"); | ||
1134 | if (!(wcr & (WCR_LINKST | WCR_SAMPLEST | WCR_MAGICST))) | ||
1135 | dev_err(db->dev, "wake signalled with no reason? " | ||
1136 | "NSR=0x%02x, WSR=0x%02x\n", nsr, wcr); | ||
1137 | |||
1138 | } | ||
1139 | |||
1140 | spin_unlock_irqrestore(&db->lock, flags); | ||
1141 | |||
1142 | return (nsr & NSR_WAKEST) ? IRQ_HANDLED : IRQ_NONE; | ||
1143 | } | ||
1144 | |||
1048 | #ifdef CONFIG_NET_POLL_CONTROLLER | 1145 | #ifdef CONFIG_NET_POLL_CONTROLLER |
1049 | /* | 1146 | /* |
1050 | *Used by netconsole | 1147 | *Used by netconsole |
@@ -1299,6 +1396,29 @@ dm9000_probe(struct platform_device *pdev) | |||
1299 | goto out; | 1396 | goto out; |
1300 | } | 1397 | } |
1301 | 1398 | ||
1399 | db->irq_wake = platform_get_irq(pdev, 1); | ||
1400 | if (db->irq_wake >= 0) { | ||
1401 | dev_dbg(db->dev, "wakeup irq %d\n", db->irq_wake); | ||
1402 | |||
1403 | ret = request_irq(db->irq_wake, dm9000_wol_interrupt, | ||
1404 | IRQF_SHARED, dev_name(db->dev), ndev); | ||
1405 | if (ret) { | ||
1406 | dev_err(db->dev, "cannot get wakeup irq (%d)\n", ret); | ||
1407 | } else { | ||
1408 | |||
1409 | /* test to see if irq is really wakeup capable */ | ||
1410 | ret = set_irq_wake(db->irq_wake, 1); | ||
1411 | if (ret) { | ||
1412 | dev_err(db->dev, "irq %d cannot set wakeup (%d)\n", | ||
1413 | db->irq_wake, ret); | ||
1414 | ret = 0; | ||
1415 | } else { | ||
1416 | set_irq_wake(db->irq_wake, 0); | ||
1417 | db->wake_supported = 1; | ||
1418 | } | ||
1419 | } | ||
1420 | } | ||
1421 | |||
1302 | iosize = resource_size(db->addr_res); | 1422 | iosize = resource_size(db->addr_res); |
1303 | db->addr_req = request_mem_region(db->addr_res->start, iosize, | 1423 | db->addr_req = request_mem_region(db->addr_res->start, iosize, |
1304 | pdev->name); | 1424 | pdev->name); |
@@ -1490,10 +1610,14 @@ dm9000_drv_suspend(struct device *dev) | |||
1490 | db = netdev_priv(ndev); | 1610 | db = netdev_priv(ndev); |
1491 | db->in_suspend = 1; | 1611 | db->in_suspend = 1; |
1492 | 1612 | ||
1493 | if (netif_running(ndev)) { | 1613 | if (!netif_running(ndev)) |
1494 | netif_device_detach(ndev); | 1614 | return 0; |
1615 | |||
1616 | netif_device_detach(ndev); | ||
1617 | |||
1618 | /* only shutdown if not using WoL */ | ||
1619 | if (!db->wake_state) | ||
1495 | dm9000_shutdown(ndev); | 1620 | dm9000_shutdown(ndev); |
1496 | } | ||
1497 | } | 1621 | } |
1498 | return 0; | 1622 | return 0; |
1499 | } | 1623 | } |
@@ -1506,10 +1630,13 @@ dm9000_drv_resume(struct device *dev) | |||
1506 | board_info_t *db = netdev_priv(ndev); | 1630 | board_info_t *db = netdev_priv(ndev); |
1507 | 1631 | ||
1508 | if (ndev) { | 1632 | if (ndev) { |
1509 | |||
1510 | if (netif_running(ndev)) { | 1633 | if (netif_running(ndev)) { |
1511 | dm9000_reset(db); | 1634 | /* reset if we were not in wake mode to ensure if |
1512 | dm9000_init_dm9000(ndev); | 1635 | * the device was powered off it is in a known state */ |
1636 | if (!db->wake_state) { | ||
1637 | dm9000_reset(db); | ||
1638 | dm9000_init_dm9000(ndev); | ||
1639 | } | ||
1513 | 1640 | ||
1514 | netif_device_attach(ndev); | 1641 | netif_device_attach(ndev); |
1515 | } | 1642 | } |
diff --git a/drivers/net/dm9000.h b/drivers/net/dm9000.h index fb1c924d79b4..55688bd1a3ef 100644 --- a/drivers/net/dm9000.h +++ b/drivers/net/dm9000.h | |||
@@ -111,6 +111,13 @@ | |||
111 | #define RSR_CE (1<<1) | 111 | #define RSR_CE (1<<1) |
112 | #define RSR_FOE (1<<0) | 112 | #define RSR_FOE (1<<0) |
113 | 113 | ||
114 | #define WCR_LINKEN (1 << 5) | ||
115 | #define WCR_SAMPLEEN (1 << 4) | ||
116 | #define WCR_MAGICEN (1 << 3) | ||
117 | #define WCR_LINKST (1 << 2) | ||
118 | #define WCR_SAMPLEST (1 << 1) | ||
119 | #define WCR_MAGICST (1 << 0) | ||
120 | |||
114 | #define FCTR_HWOT(ot) (( ot & 0xf ) << 4 ) | 121 | #define FCTR_HWOT(ot) (( ot & 0xf ) << 4 ) |
115 | #define FCTR_LWOT(ot) ( ot & 0xf ) | 122 | #define FCTR_LWOT(ot) ( ot & 0xf ) |
116 | 123 | ||