Commit 88d7d8b0 authored by Ayaz Abdulla's avatar Ayaz Abdulla Committed by David S. Miller

forcedeth: add clock gating feature <resend>

This patch adds new logic to support a clock gating feature found on the
latest set of chipsets. The clock gating is performed on the tx/rx
engines when the link is disconnected. Clock gating helps in reducing
power consumption.

* modified based on comments from netdev
Signed-off-by: default avatarAyaz Abdulla <aabdulla@nvidia.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 1aec5bdf
...@@ -343,6 +343,7 @@ enum { ...@@ -343,6 +343,7 @@ enum {
#define NVREG_POWERSTATE2_POWERUP_MASK 0x0F15 #define NVREG_POWERSTATE2_POWERUP_MASK 0x0F15
#define NVREG_POWERSTATE2_POWERUP_REV_A3 0x0001 #define NVREG_POWERSTATE2_POWERUP_REV_A3 0x0001
#define NVREG_POWERSTATE2_PHY_RESET 0x0004 #define NVREG_POWERSTATE2_PHY_RESET 0x0004
#define NVREG_POWERSTATE2_GATE_CLOCKS 0x0F00
}; };
/* Big endian: should work, but is untested */ /* Big endian: should work, but is untested */
...@@ -1017,6 +1018,23 @@ static int using_multi_irqs(struct net_device *dev) ...@@ -1017,6 +1018,23 @@ static int using_multi_irqs(struct net_device *dev)
return 1; return 1;
} }
static void nv_txrx_gate(struct net_device *dev, bool gate)
{
struct fe_priv *np = get_nvpriv(dev);
u8 __iomem *base = get_hwbase(dev);
u32 powerstate;
if (!np->mac_in_use &&
(np->driver_data & DEV_HAS_POWER_CNTRL)) {
powerstate = readl(base + NvRegPowerState2);
if (gate)
powerstate |= NVREG_POWERSTATE2_GATE_CLOCKS;
else
powerstate &= ~NVREG_POWERSTATE2_GATE_CLOCKS;
writel(powerstate, base + NvRegPowerState2);
}
}
static void nv_enable_irq(struct net_device *dev) static void nv_enable_irq(struct net_device *dev)
{ {
struct fe_priv *np = get_nvpriv(dev); struct fe_priv *np = get_nvpriv(dev);
...@@ -3394,12 +3412,14 @@ static void nv_linkchange(struct net_device *dev) ...@@ -3394,12 +3412,14 @@ static void nv_linkchange(struct net_device *dev)
if (!netif_carrier_ok(dev)) { if (!netif_carrier_ok(dev)) {
netif_carrier_on(dev); netif_carrier_on(dev);
printk(KERN_INFO "%s: link up.\n", dev->name); printk(KERN_INFO "%s: link up.\n", dev->name);
nv_txrx_gate(dev, false);
nv_start_rx(dev); nv_start_rx(dev);
} }
} else { } else {
if (netif_carrier_ok(dev)) { if (netif_carrier_ok(dev)) {
netif_carrier_off(dev); netif_carrier_off(dev);
printk(KERN_INFO "%s: link down.\n", dev->name); printk(KERN_INFO "%s: link down.\n", dev->name);
nv_txrx_gate(dev, true);
nv_stop_rx(dev); nv_stop_rx(dev);
} }
} }
...@@ -5327,6 +5347,7 @@ static int nv_open(struct net_device *dev) ...@@ -5327,6 +5347,7 @@ static int nv_open(struct net_device *dev)
mii_rw(dev, np->phyaddr, MII_BMCR, mii_rw(dev, np->phyaddr, MII_BMCR,
mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ) & ~BMCR_PDOWN); mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ) & ~BMCR_PDOWN);
nv_txrx_gate(dev, false);
/* erase previous misconfiguration */ /* erase previous misconfiguration */
if (np->driver_data & DEV_HAS_POWER_CNTRL) if (np->driver_data & DEV_HAS_POWER_CNTRL)
nv_mac_reset(dev); nv_mac_reset(dev);
...@@ -5514,12 +5535,14 @@ static int nv_close(struct net_device *dev) ...@@ -5514,12 +5535,14 @@ static int nv_close(struct net_device *dev)
nv_drain_rxtx(dev); nv_drain_rxtx(dev);
if (np->wolenabled) { if (np->wolenabled) {
nv_txrx_gate(dev, false);
writel(NVREG_PFF_ALWAYS|NVREG_PFF_MYADDR, base + NvRegPacketFilterFlags); writel(NVREG_PFF_ALWAYS|NVREG_PFF_MYADDR, base + NvRegPacketFilterFlags);
nv_start_rx(dev); nv_start_rx(dev);
} else { } else {
/* power down phy */ /* power down phy */
mii_rw(dev, np->phyaddr, MII_BMCR, mii_rw(dev, np->phyaddr, MII_BMCR,
mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ)|BMCR_PDOWN); mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ)|BMCR_PDOWN);
nv_txrx_gate(dev, true);
} }
/* FIXME: power down nic */ /* FIXME: power down nic */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment