aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/dm9000.c143
-rw-r--r--drivers/net/dm9000.h7
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
575static 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
586static 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
571static const struct ethtool_ops dm9000_ethtool_ops = { 623static 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
1110static 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