diff options
Diffstat (limited to 'drivers/net/ethernet/dlink/sundance.c')
-rw-r--r-- | drivers/net/ethernet/dlink/sundance.c | 95 |
1 files changed, 87 insertions, 8 deletions
diff --git a/drivers/net/ethernet/dlink/sundance.c b/drivers/net/ethernet/dlink/sundance.c index 3b83588e51f6..28fc11b2f1ea 100644 --- a/drivers/net/ethernet/dlink/sundance.c +++ b/drivers/net/ethernet/dlink/sundance.c @@ -102,7 +102,7 @@ static char *media[MAX_UNITS]; #include <linux/mii.h> /* These identify the driver base version and may not be removed. */ -static const char version[] __devinitconst = +static const char version[] = KERN_INFO DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " Written by Donald Becker\n"; @@ -218,7 +218,7 @@ enum { struct pci_id_info { const char *name; }; -static const struct pci_id_info pci_id_tbl[] __devinitconst = { +static const struct pci_id_info pci_id_tbl[] = { {"D-Link DFE-550TX FAST Ethernet Adapter"}, {"D-Link DFE-550FX 100Mbps Fiber-optics Adapter"}, {"D-Link DFE-580TX 4 port Server Adapter"}, @@ -259,6 +259,7 @@ enum alta_offsets { EECtrl = 0x36, FlashAddr = 0x40, FlashData = 0x44, + WakeEvent = 0x45, TxStatus = 0x46, TxFrameId = 0x47, DownCounter = 0x18, @@ -333,6 +334,14 @@ enum mac_ctrl1_bits { RxEnable=0x0800, RxDisable=0x1000, RxEnabled=0x2000, }; +/* Bits in WakeEvent register. */ +enum wake_event_bits { + WakePktEnable = 0x01, + MagicPktEnable = 0x02, + LinkEventEnable = 0x04, + WolEnable = 0x80, +}; + /* The Rx and Tx buffer descriptors. */ /* Note that using only 32 bit fields simplifies conversion to big-endian architectures. */ @@ -392,6 +401,7 @@ struct netdev_private { unsigned int default_port:4; /* Last dev->if_port value. */ unsigned int an_enable:1; unsigned int speed; + unsigned int wol_enabled:1; /* Wake on LAN enabled */ struct tasklet_struct rx_tasklet; struct tasklet_struct tx_tasklet; int budget; @@ -472,8 +482,8 @@ static const struct net_device_ops netdev_ops = { .ndo_validate_addr = eth_validate_addr, }; -static int __devinit sundance_probe1 (struct pci_dev *pdev, - const struct pci_device_id *ent) +static int sundance_probe1(struct pci_dev *pdev, + const struct pci_device_id *ent) { struct net_device *dev; struct netdev_private *np; @@ -701,7 +711,7 @@ static int change_mtu(struct net_device *dev, int new_mtu) #define eeprom_delay(ee_addr) ioread32(ee_addr) /* Read the EEPROM and MII Management Data I/O (MDIO) interfaces. */ -static int __devinit eeprom_read(void __iomem *ioaddr, int location) +static int eeprom_read(void __iomem *ioaddr, int location) { int boguscnt = 10000; /* Typical 1900 ticks. */ iowrite16(0x0200 | (location & 0xff), ioaddr + EECtrl); @@ -829,7 +839,7 @@ static int netdev_open(struct net_device *dev) unsigned long flags; int i; - /* Do we need to reset the chip??? */ + sundance_reset(dev, 0x00ff << 16); i = request_irq(irq, intr_handler, IRQF_SHARED, dev->name, dev); if (i) @@ -877,6 +887,10 @@ static int netdev_open(struct net_device *dev) iowrite16 (StatsEnable | RxEnable | TxEnable, ioaddr + MACCtrl1); + /* Disable Wol */ + iowrite8(ioread8(ioaddr + WakeEvent) | 0x00, ioaddr + WakeEvent); + np->wol_enabled = 0; + if (netif_msg_ifup(np)) printk(KERN_DEBUG "%s: Done netdev_open(), status: Rx %x Tx %x " "MAC Control %x, %4.4x %4.4x.\n", @@ -1715,6 +1729,60 @@ static void get_ethtool_stats(struct net_device *dev, data[i++] = np->xstats.rx_mcasts; } +#ifdef CONFIG_PM + +static void sundance_get_wol(struct net_device *dev, + struct ethtool_wolinfo *wol) +{ + struct netdev_private *np = netdev_priv(dev); + void __iomem *ioaddr = np->base; + u8 wol_bits; + + wol->wolopts = 0; + + wol->supported = (WAKE_PHY | WAKE_MAGIC); + if (!np->wol_enabled) + return; + + wol_bits = ioread8(ioaddr + WakeEvent); + if (wol_bits & MagicPktEnable) + wol->wolopts |= WAKE_MAGIC; + if (wol_bits & LinkEventEnable) + wol->wolopts |= WAKE_PHY; +} + +static int sundance_set_wol(struct net_device *dev, + struct ethtool_wolinfo *wol) +{ + struct netdev_private *np = netdev_priv(dev); + void __iomem *ioaddr = np->base; + u8 wol_bits; + + if (!device_can_wakeup(&np->pci_dev->dev)) + return -EOPNOTSUPP; + + np->wol_enabled = !!(wol->wolopts); + wol_bits = ioread8(ioaddr + WakeEvent); + wol_bits &= ~(WakePktEnable | MagicPktEnable | + LinkEventEnable | WolEnable); + + if (np->wol_enabled) { + if (wol->wolopts & WAKE_MAGIC) + wol_bits |= (MagicPktEnable | WolEnable); + if (wol->wolopts & WAKE_PHY) + wol_bits |= (LinkEventEnable | WolEnable); + } + iowrite8(wol_bits, ioaddr + WakeEvent); + + device_set_wakeup_enable(&np->pci_dev->dev, np->wol_enabled); + + return 0; +} +#else +#define sundance_get_wol NULL +#define sundance_set_wol NULL +#endif /* CONFIG_PM */ + static const struct ethtool_ops ethtool_ops = { .begin = check_if_running, .get_drvinfo = get_drvinfo, @@ -1722,6 +1790,8 @@ static const struct ethtool_ops ethtool_ops = { .set_settings = set_settings, .nway_reset = nway_reset, .get_link = get_link, + .get_wol = sundance_get_wol, + .set_wol = sundance_set_wol, .get_msglevel = get_msglevel, .set_msglevel = set_msglevel, .get_strings = get_strings, @@ -1844,7 +1914,7 @@ static int netdev_close(struct net_device *dev) return 0; } -static void __devexit sundance_remove1 (struct pci_dev *pdev) +static void sundance_remove1(struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); @@ -1867,6 +1937,8 @@ static void __devexit sundance_remove1 (struct pci_dev *pdev) static int sundance_suspend(struct pci_dev *pci_dev, pm_message_t state) { struct net_device *dev = pci_get_drvdata(pci_dev); + struct netdev_private *np = netdev_priv(dev); + void __iomem *ioaddr = np->base; if (!netif_running(dev)) return 0; @@ -1875,6 +1947,12 @@ static int sundance_suspend(struct pci_dev *pci_dev, pm_message_t state) netif_device_detach(dev); pci_save_state(pci_dev); + if (np->wol_enabled) { + iowrite8(AcceptBroadcast | AcceptMyPhys, ioaddr + RxMode); + iowrite16(RxEnable, ioaddr + MACCtrl1); + } + pci_enable_wake(pci_dev, pci_choose_state(pci_dev, state), + np->wol_enabled); pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state)); return 0; @@ -1890,6 +1968,7 @@ static int sundance_resume(struct pci_dev *pci_dev) pci_set_power_state(pci_dev, PCI_D0); pci_restore_state(pci_dev); + pci_enable_wake(pci_dev, PCI_D0, 0); err = netdev_open(dev); if (err) { @@ -1910,7 +1989,7 @@ static struct pci_driver sundance_driver = { .name = DRV_NAME, .id_table = sundance_pci_tbl, .probe = sundance_probe1, - .remove = __devexit_p(sundance_remove1), + .remove = sundance_remove1, #ifdef CONFIG_PM .suspend = sundance_suspend, .resume = sundance_resume, |