Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 171516
b: refs/heads/master
c: c029f44
h: refs/heads/master
v: v3
  • Loading branch information
Ben Dooks authored and David S. Miller committed Nov 12, 2009
1 parent 4956b6a commit 9e5e776
Show file tree
Hide file tree
Showing 3 changed files with 143 additions and 9 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: f9254edaabfc48f5a28bb5a88c6db48704cc058d
refs/heads/master: c029f4440fd3f0dcc6923f917536fd62d6ef5d1d
143 changes: 135 additions & 8 deletions trunk/drivers/net/dm9000.c
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ typedef struct board_info {

unsigned int flags;
unsigned int in_suspend :1;
unsigned int wake_supported :1;
int debug_level;

enum dm9000_type type;
Expand All @@ -116,6 +117,8 @@ typedef struct board_info {
struct resource *data_req;
struct resource *irq_res;

int irq_wake;

struct mutex addr_lock; /* phy and eeprom access lock */

struct delayed_work phy_poll;
Expand All @@ -125,6 +128,7 @@ typedef struct board_info {

struct mii_if_info mii;
u32 msg_enable;
u32 wake_state;

int rx_csum;
int can_csum;
Expand Down Expand Up @@ -568,6 +572,54 @@ static int dm9000_set_eeprom(struct net_device *dev,
return 0;
}

static void dm9000_get_wol(struct net_device *dev, struct ethtool_wolinfo *w)
{
board_info_t *dm = to_dm9000_board(dev);

memset(w, 0, sizeof(struct ethtool_wolinfo));

/* note, we could probably support wake-phy too */
w->supported = dm->wake_supported ? WAKE_MAGIC : 0;
w->wolopts = dm->wake_state;
}

static int dm9000_set_wol(struct net_device *dev, struct ethtool_wolinfo *w)
{
board_info_t *dm = to_dm9000_board(dev);
unsigned long flags;
u32 opts = w->wolopts;
u32 wcr = 0;

if (!dm->wake_supported)
return -EOPNOTSUPP;

if (opts & ~WAKE_MAGIC)
return -EINVAL;

if (opts & WAKE_MAGIC)
wcr |= WCR_MAGICEN;

mutex_lock(&dm->addr_lock);

spin_lock_irqsave(&dm->lock, flags);
iow(dm, DM9000_WCR, wcr);
spin_unlock_irqrestore(&dm->lock, flags);

mutex_unlock(&dm->addr_lock);

if (dm->wake_state != opts) {
/* change in wol state, update IRQ state */

if (!dm->wake_state)
set_irq_wake(dm->irq_wake, 1);
else if (dm->wake_state & !opts)
set_irq_wake(dm->irq_wake, 0);
}

dm->wake_state = opts;
return 0;
}

static const struct ethtool_ops dm9000_ethtool_ops = {
.get_drvinfo = dm9000_get_drvinfo,
.get_settings = dm9000_get_settings,
Expand All @@ -576,6 +628,8 @@ static const struct ethtool_ops dm9000_ethtool_ops = {
.set_msglevel = dm9000_set_msglevel,
.nway_reset = dm9000_nway_reset,
.get_link = dm9000_get_link,
.get_wol = dm9000_get_wol,
.set_wol = dm9000_set_wol,
.get_eeprom_len = dm9000_get_eeprom_len,
.get_eeprom = dm9000_get_eeprom,
.set_eeprom = dm9000_set_eeprom,
Expand Down Expand Up @@ -722,6 +776,7 @@ dm9000_init_dm9000(struct net_device *dev)
{
board_info_t *db = netdev_priv(dev);
unsigned int imr;
unsigned int ncr;

dm9000_dbg(db, 1, "entering %s\n", __func__);

Expand All @@ -736,8 +791,15 @@ dm9000_init_dm9000(struct net_device *dev)
iow(db, DM9000_GPCR, GPCR_GEP_CNTL); /* Let GPIO0 output */
iow(db, DM9000_GPR, 0); /* Enable PHY */

if (db->flags & DM9000_PLATF_EXT_PHY)
iow(db, DM9000_NCR, NCR_EXT_PHY);
ncr = (db->flags & DM9000_PLATF_EXT_PHY) ? NCR_EXT_PHY : 0;

/* if wol is needed, then always set NCR_WAKEEN otherwise we end
* up dumping the wake events if we disable this. There is already
* a wake-mask in DM9000_WCR */
if (db->wake_supported)
ncr |= NCR_WAKEEN;

iow(db, DM9000_NCR, ncr);

/* Program operating register */
iow(db, DM9000_TCR, 0); /* TX Polling clear */
Expand Down Expand Up @@ -1045,6 +1107,41 @@ static irqreturn_t dm9000_interrupt(int irq, void *dev_id)
return IRQ_HANDLED;
}

static irqreturn_t dm9000_wol_interrupt(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
board_info_t *db = netdev_priv(dev);
unsigned long flags;
unsigned nsr, wcr;

spin_lock_irqsave(&db->lock, flags);

nsr = ior(db, DM9000_NSR);
wcr = ior(db, DM9000_WCR);

dev_dbg(db->dev, "%s: NSR=0x%02x, WCR=0x%02x\n", __func__, nsr, wcr);

if (nsr & NSR_WAKEST) {
/* clear, so we can avoid */
iow(db, DM9000_NSR, NSR_WAKEST);

if (wcr & WCR_LINKST)
dev_info(db->dev, "wake by link status change\n");
if (wcr & WCR_SAMPLEST)
dev_info(db->dev, "wake by sample packet\n");
if (wcr & WCR_MAGICST )
dev_info(db->dev, "wake by magic packet\n");
if (!(wcr & (WCR_LINKST | WCR_SAMPLEST | WCR_MAGICST)))
dev_err(db->dev, "wake signalled with no reason? "
"NSR=0x%02x, WSR=0x%02x\n", nsr, wcr);

}

spin_unlock_irqrestore(&db->lock, flags);

return (nsr & NSR_WAKEST) ? IRQ_HANDLED : IRQ_NONE;
}

#ifdef CONFIG_NET_POLL_CONTROLLER
/*
*Used by netconsole
Expand Down Expand Up @@ -1299,6 +1396,29 @@ dm9000_probe(struct platform_device *pdev)
goto out;
}

db->irq_wake = platform_get_irq(pdev, 1);
if (db->irq_wake >= 0) {
dev_dbg(db->dev, "wakeup irq %d\n", db->irq_wake);

ret = request_irq(db->irq_wake, dm9000_wol_interrupt,
IRQF_SHARED, dev_name(db->dev), ndev);
if (ret) {
dev_err(db->dev, "cannot get wakeup irq (%d)\n", ret);
} else {

/* test to see if irq is really wakeup capable */
ret = set_irq_wake(db->irq_wake, 1);
if (ret) {
dev_err(db->dev, "irq %d cannot set wakeup (%d)\n",
db->irq_wake, ret);
ret = 0;
} else {
set_irq_wake(db->irq_wake, 0);
db->wake_supported = 1;
}
}
}

iosize = resource_size(db->addr_res);
db->addr_req = request_mem_region(db->addr_res->start, iosize,
pdev->name);
Expand Down Expand Up @@ -1490,10 +1610,14 @@ dm9000_drv_suspend(struct device *dev)
db = netdev_priv(ndev);
db->in_suspend = 1;

if (netif_running(ndev)) {
netif_device_detach(ndev);
if (!netif_running(ndev))
return 0;

netif_device_detach(ndev);

/* only shutdown if not using WoL */
if (!db->wake_state)
dm9000_shutdown(ndev);
}
}
return 0;
}
Expand All @@ -1506,10 +1630,13 @@ dm9000_drv_resume(struct device *dev)
board_info_t *db = netdev_priv(ndev);

if (ndev) {

if (netif_running(ndev)) {
dm9000_reset(db);
dm9000_init_dm9000(ndev);
/* reset if we were not in wake mode to ensure if
* the device was powered off it is in a known state */
if (!db->wake_state) {
dm9000_reset(db);
dm9000_init_dm9000(ndev);
}

netif_device_attach(ndev);
}
Expand Down
7 changes: 7 additions & 0 deletions trunk/drivers/net/dm9000.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,13 @@
#define RSR_CE (1<<1)
#define RSR_FOE (1<<0)

#define WCR_LINKEN (1 << 5)
#define WCR_SAMPLEEN (1 << 4)
#define WCR_MAGICEN (1 << 3)
#define WCR_LINKST (1 << 2)
#define WCR_SAMPLEST (1 << 1)
#define WCR_MAGICST (1 << 0)

#define FCTR_HWOT(ot) (( ot & 0xf ) << 4 )
#define FCTR_LWOT(ot) ( ot & 0xf )

Expand Down

0 comments on commit 9e5e776

Please sign in to comment.