* [RESEND #3/patch 2.6.26-rc6] net/enc28j60: low power mode
@ 2008-06-13 4:38 David Brownell
2008-06-13 9:40 ` Jeff Garzik
2008-06-18 3:26 ` Jeff Garzik
0 siblings, 2 replies; 4+ messages in thread
From: David Brownell @ 2008-06-13 4:38 UTC (permalink / raw)
To: netdev; +Cc: Claudio Lanconelli, lkml
Keep enc28j60 chips in low-power mode when they're not in use.
At typically 120 mA, these chips run hot even when idle; this
low power mode cuts that power usage by a factor of around 100.
This version provides a generic routine to poll a register until
its masked value equals some value ... e.g. bit set or cleared.
It's basically what the previous wait_phy_ready() did, but this
version is generalized to support the handshaking needed to
enter and exit low power mode.
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Claudio Lanconelli <lanconelli.claudio@eptar.com>
---
Previously sent: 18-May, 19-February; there were several
previous iterations too ...
drivers/net/enc28j60.c | 82 ++++++++++++++++++++++++++++++++++---------------
1 file changed, 58 insertions(+), 24 deletions(-)
--- g26.orig/drivers/net/enc28j60.c 2008-02-22 19:48:14.000000000 -0800
+++ g26/drivers/net/enc28j60.c 2008-02-22 19:48:21.000000000 -0800
@@ -400,26 +400,31 @@ enc28j60_packet_write(struct enc28j60_ne
mutex_unlock(&priv->lock);
}
-/*
- * Wait until the PHY operation is complete.
- */
-static int wait_phy_ready(struct enc28j60_net *priv)
+static unsigned long msec20_to_jiffies;
+
+static int poll_ready(struct enc28j60_net *priv, u8 reg, u8 mask, u8 val)
{
- unsigned long timeout = jiffies + 20 * HZ / 1000;
- int ret = 1;
+ unsigned long timeout = jiffies + msec20_to_jiffies;
/* 20 msec timeout read */
- while (nolock_regb_read(priv, MISTAT) & MISTAT_BUSY) {
+ while ((nolock_regb_read(priv, reg) & mask) != val) {
if (time_after(jiffies, timeout)) {
if (netif_msg_drv(priv))
- printk(KERN_DEBUG DRV_NAME
- ": PHY ready timeout!\n");
- ret = 0;
- break;
+ dev_dbg(&priv->spi->dev,
+ "reg %02x ready timeout!\n", reg);
+ return -ETIMEDOUT;
}
cpu_relax();
}
- return ret;
+ return 0;
+}
+
+/*
+ * Wait until the PHY operation is complete.
+ */
+static int wait_phy_ready(struct enc28j60_net *priv)
+{
+ return poll_ready(priv, MISTAT, MISTAT_BUSY, 0) ? 0 : 1;
}
/*
@@ -594,6 +599,32 @@ static void nolock_txfifo_init(struct en
nolock_regw_write(priv, ETXNDL, end);
}
+/*
+ * Low power mode shrinks power consumption about 100x, so we'd like
+ * the chip to be in that mode whenever it's inactive. (However, we
+ * can't stay in lowpower mode during suspend with WOL active.)
+ */
+static void enc28j60_lowpower(struct enc28j60_net *priv, bool is_low)
+{
+ if (netif_msg_drv(priv))
+ dev_dbg(&priv->spi->dev, "%s power...\n",
+ is_low ? "low" : "high");
+
+ mutex_lock(&priv->lock);
+ if (is_low) {
+ nolock_reg_bfclr(priv, ECON1, ECON1_RXEN);
+ poll_ready(priv, ESTAT, ESTAT_RXBUSY, 0);
+ poll_ready(priv, ECON1, ECON1_TXRTS, 0);
+ /* ECON2_VRPS was set during initialization */
+ nolock_reg_bfset(priv, ECON2, ECON2_PWRSV);
+ } else {
+ nolock_reg_bfclr(priv, ECON2, ECON2_PWRSV);
+ poll_ready(priv, ESTAT, ESTAT_CLKRDY, ESTAT_CLKRDY);
+ /* caller sets ECON1_RXEN */
+ }
+ mutex_unlock(&priv->lock);
+}
+
static int enc28j60_hw_init(struct enc28j60_net *priv)
{
u8 reg;
@@ -612,8 +643,8 @@ static int enc28j60_hw_init(struct enc28
priv->tx_retry_count = 0;
priv->max_pk_counter = 0;
priv->rxfilter = RXFILTER_NORMAL;
- /* enable address auto increment */
- nolock_regb_write(priv, ECON2, ECON2_AUTOINC);
+ /* enable address auto increment and voltage regulator powersave */
+ nolock_regb_write(priv, ECON2, ECON2_AUTOINC | ECON2_VRPS);
nolock_rxfifo_init(priv, RXSTART_INIT, RXEND_INIT);
nolock_txfifo_init(priv, TXSTART_INIT, TXEND_INIT);
@@ -690,7 +721,7 @@ static int enc28j60_hw_init(struct enc28
static void enc28j60_hw_enable(struct enc28j60_net *priv)
{
- /* enable interrutps */
+ /* enable interrupts */
if (netif_msg_hw(priv))
printk(KERN_DEBUG DRV_NAME ": %s() enabling interrupts.\n",
__FUNCTION__);
@@ -726,15 +757,12 @@ enc28j60_setlink(struct net_device *ndev
int ret = 0;
if (!priv->hw_enable) {
- if (autoneg == AUTONEG_DISABLE && speed == SPEED_10) {
+ /* link is in low power mode now; duplex setting
+ * will take effect on next enc28j60_hw_init().
+ */
+ if (autoneg == AUTONEG_DISABLE && speed == SPEED_10)
priv->full_duplex = (duplex == DUPLEX_FULL);
- if (!enc28j60_hw_init(priv)) {
- if (netif_msg_drv(priv))
- dev_err(&ndev->dev,
- "hw_reset() failed\n");
- ret = -EINVAL;
- }
- } else {
+ else {
if (netif_msg_link(priv))
dev_warn(&ndev->dev,
"unsupported link setting\n");
@@ -1307,7 +1335,8 @@ static int enc28j60_net_open(struct net_
}
return -EADDRNOTAVAIL;
}
- /* Reset the hardware here */
+ /* Reset the hardware here (and take it out of low power mode) */
+ enc28j60_lowpower(priv, false);
enc28j60_hw_disable(priv);
if (!enc28j60_hw_init(priv)) {
if (netif_msg_ifup(priv))
@@ -1337,6 +1366,7 @@ static int enc28j60_net_close(struct net
printk(KERN_DEBUG DRV_NAME ": %s() enter\n", __FUNCTION__);
enc28j60_hw_disable(priv);
+ enc28j60_lowpower(priv, true);
netif_stop_queue(dev);
return 0;
@@ -1537,6 +1567,8 @@ static int __devinit enc28j60_probe(stru
dev->watchdog_timeo = TX_TIMEOUT;
SET_ETHTOOL_OPS(dev, &enc28j60_ethtool_ops);
+ enc28j60_lowpower(priv, true);
+
ret = register_netdev(dev);
if (ret) {
if (netif_msg_probe(priv))
@@ -1581,6 +1613,8 @@ static struct spi_driver enc28j60_driver
static int __init enc28j60_init(void)
{
+ msec20_to_jiffies = msecs_to_jiffies(20);
+
return spi_register_driver(&enc28j60_driver);
}
^ permalink raw reply [flat|nested] 4+ messages in thread* Re: [RESEND #3/patch 2.6.26-rc6] net/enc28j60: low power mode
2008-06-13 4:38 [RESEND #3/patch 2.6.26-rc6] net/enc28j60: low power mode David Brownell
@ 2008-06-13 9:40 ` Jeff Garzik
2008-06-13 18:21 ` David Brownell
2008-06-18 3:26 ` Jeff Garzik
1 sibling, 1 reply; 4+ messages in thread
From: Jeff Garzik @ 2008-06-13 9:40 UTC (permalink / raw)
To: David Brownell; +Cc: netdev, Claudio Lanconelli, lkml, Andrew Morton
David Brownell wrote:
> Keep enc28j60 chips in low-power mode when they're not in use.
> At typically 120 mA, these chips run hot even when idle; this
> low power mode cuts that power usage by a factor of around 100.
>
> This version provides a generic routine to poll a register until
> its masked value equals some value ... e.g. bit set or cleared.
> It's basically what the previous wait_phy_ready() did, but this
> version is generalized to support the handshaking needed to
> enter and exit low power mode.
>
> Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
> Signed-off-by: Claudio Lanconelli <lanconelli.claudio@eptar.com>
> ---
> Previously sent: 18-May, 19-February; there were several
> previous iterations too ...
>
> drivers/net/enc28j60.c | 82 ++++++++++++++++++++++++++++++++++---------------
> 1 file changed, 58 insertions(+), 24 deletions(-)
I've put these two into my queue, so they are definitely in process now.
For netdev patches it helps to CC me, since not every patch sent solely
to netdev@ is a to-be-applied patch, and might be missed -- or quite
often, assumed to be a patch that warrants discussion.
Jeff
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [RESEND #3/patch 2.6.26-rc6] net/enc28j60: low power mode
2008-06-13 9:40 ` Jeff Garzik
@ 2008-06-13 18:21 ` David Brownell
0 siblings, 0 replies; 4+ messages in thread
From: David Brownell @ 2008-06-13 18:21 UTC (permalink / raw)
To: Jeff Garzik; +Cc: netdev, Claudio Lanconelli, lkml, Andrew Morton
On Friday 13 June 2008, Jeff Garzik wrote:
> I've put these two into my queue, so they are definitely in process now.
Thanks..
> For netdev patches it helps to CC me, since not every patch sent solely
> to netdev@ is a to-be-applied patch, and might be missed -- or quite
> often, assumed to be a patch that warrants discussion.
Ah. I was more used to the convention that all patches should go to
the relevant mailing list (or LKML), and were assumed to be ready to
merge unless they were flagged as "RFC" or the relevant maintainer(s)
issued a NAK or other negative feedback. When there was an ack or
signoff from the driver maintainer, it was ready to go.
- Dave
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [RESEND #3/patch 2.6.26-rc6] net/enc28j60: low power mode
2008-06-13 4:38 [RESEND #3/patch 2.6.26-rc6] net/enc28j60: low power mode David Brownell
2008-06-13 9:40 ` Jeff Garzik
@ 2008-06-18 3:26 ` Jeff Garzik
1 sibling, 0 replies; 4+ messages in thread
From: Jeff Garzik @ 2008-06-18 3:26 UTC (permalink / raw)
To: David Brownell; +Cc: netdev, Claudio Lanconelli, lkml
David Brownell wrote:
> Keep enc28j60 chips in low-power mode when they're not in use.
> At typically 120 mA, these chips run hot even when idle; this
> low power mode cuts that power usage by a factor of around 100.
>
> This version provides a generic routine to poll a register until
> its masked value equals some value ... e.g. bit set or cleared.
> It's basically what the previous wait_phy_ready() did, but this
> version is generalized to support the handshaking needed to
> enter and exit low power mode.
>
> Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
> Signed-off-by: Claudio Lanconelli <lanconelli.claudio@eptar.com>
> ---
> Previously sent: 18-May, 19-February; there were several
> previous iterations too ...
>
> drivers/net/enc28j60.c | 82 ++++++++++++++++++++++++++++++++++---------------
> 1 file changed, 58 insertions(+), 24 deletions(-)
applied
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2008-06-18 3:26 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-06-13 4:38 [RESEND #3/patch 2.6.26-rc6] net/enc28j60: low power mode David Brownell
2008-06-13 9:40 ` Jeff Garzik
2008-06-13 18:21 ` David Brownell
2008-06-18 3:26 ` Jeff Garzik
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).