netdev
[Top] [All Lists]

Re: [9/9][PATCH 2.6] Add WOL support

To: Roger Luethi <rl@xxxxxxxxxxx>
Subject: Re: [9/9][PATCH 2.6] Add WOL support
From: Jeff Garzik <jgarzik@xxxxxxxxx>
Date: Sat, 19 Jun 2004 17:29:45 -0400
Cc: Andrew Morton <akpm@xxxxxxxx>, netdev@xxxxxxxxxxx
In-reply-to: <20040615175003.GA11382@k3.hellgate.ch>
References: <20040615175003.GA11382@k3.hellgate.ch>
Sender: netdev-bounce@xxxxxxxxxxx
User-agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040510
Roger Luethi wrote:
Add rhine_shutdown callback to prepare Rhine power registers for
shutdown.

Add rhine_get_wol/rhine_set_wol for ethtool ioctl.

Signed-off-by: Roger Luethi <rl@xxxxxxxxxxx>

--- 2.6-mm/drivers/net/via-rhine.c.orig 2004-06-15 18:34:21.000000000 +0200
+++ 2.6-mm/drivers/net/via-rhine.c 2004-06-15 18:36:12.000000000 +0200
@@ -394,8 +394,8 @@
ConfigA=0x78, ConfigB=0x79, ConfigC=0x7A, ConfigD=0x7B,
RxMissed=0x7C, RxCRCErrs=0x7E, MiscCmd=0x81,
StickyHW=0x83, IntrStatus2=0x84,
- WOLcrSet=0xA0, WOLcrClr=0xA4, WOLcrClr1=0xA6,
- WOLcgClr=0xA7,
+ WOLcrSet=0xA0, PwcfgSet=0xA1, WOLcgSet=0xA3, WOLcrClr=0xA4,
+ WOLcrClr1=0xA6, WOLcgClr=0xA7,
PwrcsrSet=0xA8, PwrcsrSet1=0xA9, PwrcsrClr=0xAC, PwrcsrClr1=0xAD,
};
@@ -427,6 +427,15 @@
IntrTxErrSummary=0x082218,
};
+/* Bits in WOLcrSet/WOLcrClr and PwrcsrSet/PwrcsrClr */
+enum wol_bits {
+ WOLucast = 0x10,
+ WOLmagic = 0x20,
+ WOLbmcast = 0x30,
+ WOLlnkon = 0x40,
+ WOLlnkoff = 0x80,
+};
+
/* The Rx and Tx buffer descriptors. */
struct rx_desc {
s32 rx_status;
@@ -491,8 +500,8 @@
unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */
unsigned int cur_tx, dirty_tx;
unsigned int rx_buf_sz; /* Based on MTU+slack. */
+ u8 wolopts;
- /* These values are keep track of the transceiver/media in use. */
u8 tx_thresh, rx_thresh;
struct mii_if_info mii_if;
@@ -512,6 +521,7 @@
static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
static struct ethtool_ops netdev_ethtool_ops;
static int rhine_close(struct net_device *dev);
+static void rhine_shutdown (struct device *gdev);
#define RHINE_WAIT_FOR(condition) do { \
int i=1024; \
@@ -537,12 +547,13 @@
/*
* Get power related registers into sane state.
- * Returns content of power-event (WOL) registers.
+ * Notify user about past WOL event.
*/
static void rhine_power_init(struct net_device *dev)
{
long ioaddr = dev->base_addr;
struct rhine_private *rp = netdev_priv(dev);
+ u16 wolstat;
if (rp->quirks & rqWOL) {
/* Make sure chip is in power state D0 */
@@ -557,10 +568,40 @@
if (rp->quirks & rq6patterns)
writeb(0x03, ioaddr + WOLcrClr1);
+ /* Save power-event status bits */
+ wolstat = readb(ioaddr + PwrcsrSet);
+ if (rp->quirks & rq6patterns)
+ wolstat |= (readb(ioaddr + PwrcsrSet1) & 0x03) << 8;
+
/* Clear power-event status bits */
writeb(0xFF, ioaddr + PwrcsrClr);
if (rp->quirks & rq6patterns)
writeb(0x03, ioaddr + PwrcsrClr1);
+
+ if (wolstat) {
+ char *reason;
+ switch (wolstat) {
+ case WOLmagic:
+ reason = "Magic packet";
+ break;
+ case WOLlnkon:
+ reason = "Link went up";
+ break;
+ case WOLlnkoff:
+ reason = "Link went down";
+ break;
+ case WOLucast:
+ reason = "Unicast packet";
+ break;
+ case WOLbmcast:
+ reason = "Multicast/broadcast packet";
+ break;
+ default:
+ reason = "Unknown";
+ }
+ printk("%s: Woke system up. Reason: %s.\n",
+ DRV_NAME, reason);

printk needs KERN_xxx prefix

also, use dev->name rather than DRV_NAME, since we are past the probe phase.


+ }
}
}
@@ -1766,6 +1807,39 @@
debug = value;
}
+static void rhine_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+ struct rhine_private *rp = netdev_priv(dev);
+
+ if (!(rp->quirks & rqWOL))
+ return;

is WOL really considered a quirk? ;-)


+ spin_lock_irq(&rp->lock);
+ wol->supported = WAKE_PHY | WAKE_MAGIC |
+ WAKE_UCAST | WAKE_MCAST | WAKE_BCAST; /* Untested */
+ wol->wolopts = rp->wolopts;
+ spin_unlock_irq(&rp->lock);
+}
+
+static int rhine_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+ struct rhine_private *rp = netdev_priv(dev);
+ u32 support = WAKE_PHY | WAKE_MAGIC |
+ WAKE_UCAST | WAKE_MCAST | WAKE_BCAST; /* Untested */
+
+ if (!(rp->quirks & rqWOL))
+ return -EINVAL;
+
+ if (wol->wolopts & ~support)
+ return -EINVAL;
+
+ spin_lock_irq(&rp->lock);
+ rp->wolopts = wol->wolopts;
+ spin_unlock_irq(&rp->lock);
+
+ return 0;
+}
+
static struct ethtool_ops netdev_ethtool_ops = {
.get_drvinfo = netdev_get_drvinfo,
.get_settings = netdev_get_settings,
@@ -1774,6 +1848,8 @@
.get_link = netdev_get_link,
.get_msglevel = netdev_get_msglevel,
.set_msglevel = netdev_set_msglevel,
+ .get_wol = rhine_get_wol,
+ .set_wol = rhine_set_wol,
.get_sg = ethtool_op_get_sg,
.get_tx_csum = ethtool_op_get_tx_csum,
};
@@ -1844,12 +1920,51 @@
pci_set_drvdata(pdev, NULL);
}
+static void rhine_shutdown (struct device *gendev)
+{
+ struct pci_dev *pdev = to_pci_dev(gendev);
+ struct net_device *dev = pci_get_drvdata(pdev);
+ struct rhine_private *rp = netdev_priv(dev);
+
+ long ioaddr = dev->base_addr;
+
+ rhine_power_init(dev);
+
+ /* Make sure we use pattern 0, 1 and not 4, 5 */
+ if (rp->quirks & rq6patterns)
+ writeb(0x04, ioaddr + 0xA7);
+
+ if (rp->wolopts & WAKE_MAGIC)
+ writeb(WOLmagic, ioaddr + WOLcrSet);
+
+ if (rp->wolopts & (WAKE_BCAST|WAKE_MCAST))
+ writeb(WOLbmcast, ioaddr + WOLcgSet);
+
+ if (rp->wolopts & WAKE_PHY)
+ writeb(WOLlnkon | WOLlnkoff, ioaddr + WOLcrSet);
+
+ if (rp->wolopts & WAKE_UCAST)
+ writeb(WOLucast, ioaddr + WOLcrSet);
+
+ /* Enable legacy WOL (for old motherboards) */
+ writeb(0x01, ioaddr + PwcfgSet);
+ writeb(readb(ioaddr + StickyHW) | 0x04, ioaddr + StickyHW);
+
+ /* Hit power state D3 (sleep) */
+ writeb(readb(ioaddr + StickyHW) | 0x03, ioaddr + StickyHW);

would be nice to eliminate these magic numbers (0x04, 0x04), ...



+ /* TODO: Check use of pci_enable_wake() */
+
+}
static struct pci_driver rhine_driver = {
.name = DRV_NAME,
.id_table = rhine_pci_tbl,
.probe = rhine_init_one,
.remove = __devexit_p(rhine_remove_one),
+ .driver = {
+ .shutdown = rhine_shutdown,
+ }
};





<Prev in Thread] Current Thread [Next in Thread>