From f210e87b6d3aab1fb3eb51a006f4502c1a7a2494 Mon Sep 17 00:00:00 2001 From: Denis Kirjanov Date: Sat, 1 Dec 2012 08:39:19 +0000 Subject: [PATCH] sundance: Enable WoL support Enable WoL support. Signed-off-by: Denis Kirjanov Signed-off-by: David S. Miller --- drivers/net/ethernet/dlink/sundance.c | 81 ++++++++++++++++++++++++++++++++++- 1 file changed, 80 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/dlink/sundance.c b/drivers/net/ethernet/dlink/sundance.c index 3b83588e51f6..bbeb4c7a85ba 100644 --- a/drivers/net/ethernet/dlink/sundance.c +++ b/drivers/net/ethernet/dlink/sundance.c @@ -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; @@ -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, @@ -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) { -- 2.11.0