Commit bc1c7567 authored by Michael Chan's avatar Michael Chan Committed by David S. Miller

[TG3]: Support shutdown WoL.

Support WoL during shutdown by calling
tg3_set_power_state(tp, PCI_D3hot) during tg3_close().

Change the power state parameter to pci_power_t type and use
constants defined in pci.h.

Certain ethtool operations cannot be performed after tg3_close()
because the device will go to low power state. Add return -EAGAIN
in such cases where appropriate.
Signed-off-by: default avatarMichael Chan <mchan@broadcom.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 4e3a7aaa
...@@ -1042,9 +1042,11 @@ static void tg3_frob_aux_power(struct tg3 *tp) ...@@ -1042,9 +1042,11 @@ static void tg3_frob_aux_power(struct tg3 *tp)
struct net_device *dev_peer; struct net_device *dev_peer;
dev_peer = pci_get_drvdata(tp->pdev_peer); dev_peer = pci_get_drvdata(tp->pdev_peer);
/* remove_one() may have been run on the peer. */
if (!dev_peer) if (!dev_peer)
BUG(); tp_peer = tp;
tp_peer = netdev_priv(dev_peer); else
tp_peer = netdev_priv(dev_peer);
} }
if ((tp->tg3_flags & TG3_FLAG_WOL_ENABLE) != 0 || if ((tp->tg3_flags & TG3_FLAG_WOL_ENABLE) != 0 ||
...@@ -1135,7 +1137,7 @@ static int tg3_halt_cpu(struct tg3 *, u32); ...@@ -1135,7 +1137,7 @@ static int tg3_halt_cpu(struct tg3 *, u32);
static int tg3_nvram_lock(struct tg3 *); static int tg3_nvram_lock(struct tg3 *);
static void tg3_nvram_unlock(struct tg3 *); static void tg3_nvram_unlock(struct tg3 *);
static int tg3_set_power_state(struct tg3 *tp, int state) static int tg3_set_power_state(struct tg3 *tp, pci_power_t state)
{ {
u32 misc_host_ctrl; u32 misc_host_ctrl;
u16 power_control, power_caps; u16 power_control, power_caps;
...@@ -1154,7 +1156,7 @@ static int tg3_set_power_state(struct tg3 *tp, int state) ...@@ -1154,7 +1156,7 @@ static int tg3_set_power_state(struct tg3 *tp, int state)
power_control |= PCI_PM_CTRL_PME_STATUS; power_control |= PCI_PM_CTRL_PME_STATUS;
power_control &= ~(PCI_PM_CTRL_STATE_MASK); power_control &= ~(PCI_PM_CTRL_STATE_MASK);
switch (state) { switch (state) {
case 0: case PCI_D0:
power_control |= 0; power_control |= 0;
pci_write_config_word(tp->pdev, pci_write_config_word(tp->pdev,
pm + PCI_PM_CTRL, pm + PCI_PM_CTRL,
...@@ -1167,15 +1169,15 @@ static int tg3_set_power_state(struct tg3 *tp, int state) ...@@ -1167,15 +1169,15 @@ static int tg3_set_power_state(struct tg3 *tp, int state)
return 0; return 0;
case 1: case PCI_D1:
power_control |= 1; power_control |= 1;
break; break;
case 2: case PCI_D2:
power_control |= 2; power_control |= 2;
break; break;
case 3: case PCI_D3hot:
power_control |= 3; power_control |= 3;
break; break;
...@@ -6206,7 +6208,7 @@ static int tg3_init_hw(struct tg3 *tp) ...@@ -6206,7 +6208,7 @@ static int tg3_init_hw(struct tg3 *tp)
int err; int err;
/* Force the chip into D0. */ /* Force the chip into D0. */
err = tg3_set_power_state(tp, 0); err = tg3_set_power_state(tp, PCI_D0);
if (err) if (err)
goto out; goto out;
...@@ -6493,6 +6495,10 @@ static int tg3_open(struct net_device *dev) ...@@ -6493,6 +6495,10 @@ static int tg3_open(struct net_device *dev)
tg3_full_lock(tp, 0); tg3_full_lock(tp, 0);
err = tg3_set_power_state(tp, PCI_D0);
if (err)
return err;
tg3_disable_ints(tp); tg3_disable_ints(tp);
tp->tg3_flags &= ~TG3_FLAG_INIT_COMPLETE; tp->tg3_flags &= ~TG3_FLAG_INIT_COMPLETE;
...@@ -6872,7 +6878,6 @@ static int tg3_close(struct net_device *dev) ...@@ -6872,7 +6878,6 @@ static int tg3_close(struct net_device *dev)
tp->tg3_flags &= tp->tg3_flags &=
~(TG3_FLAG_INIT_COMPLETE | ~(TG3_FLAG_INIT_COMPLETE |
TG3_FLAG_GOT_SERDES_FLOWCTL); TG3_FLAG_GOT_SERDES_FLOWCTL);
netif_carrier_off(tp->dev);
tg3_full_unlock(tp); tg3_full_unlock(tp);
...@@ -6889,6 +6894,10 @@ static int tg3_close(struct net_device *dev) ...@@ -6889,6 +6894,10 @@ static int tg3_close(struct net_device *dev)
tg3_free_consistent(tp); tg3_free_consistent(tp);
tg3_set_power_state(tp, PCI_D3hot);
netif_carrier_off(tp->dev);
return 0; return 0;
} }
...@@ -7207,6 +7216,9 @@ static void tg3_get_regs(struct net_device *dev, ...@@ -7207,6 +7216,9 @@ static void tg3_get_regs(struct net_device *dev,
memset(p, 0, TG3_REGDUMP_LEN); memset(p, 0, TG3_REGDUMP_LEN);
if (tp->link_config.phy_is_low_power)
return;
tg3_full_lock(tp, 0); tg3_full_lock(tp, 0);
#define __GET_REG32(reg) (*(p)++ = tr32(reg)) #define __GET_REG32(reg) (*(p)++ = tr32(reg))
...@@ -7281,6 +7293,9 @@ static int tg3_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, ...@@ -7281,6 +7293,9 @@ static int tg3_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
u8 *pd; u8 *pd;
u32 i, offset, len, val, b_offset, b_count; u32 i, offset, len, val, b_offset, b_count;
if (tp->link_config.phy_is_low_power)
return -EAGAIN;
offset = eeprom->offset; offset = eeprom->offset;
len = eeprom->len; len = eeprom->len;
eeprom->len = 0; eeprom->len = 0;
...@@ -7342,6 +7357,9 @@ static int tg3_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, ...@@ -7342,6 +7357,9 @@ static int tg3_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
u32 offset, len, b_offset, odd_len, start, end; u32 offset, len, b_offset, odd_len, start, end;
u8 *buf; u8 *buf;
if (tp->link_config.phy_is_low_power)
return -EAGAIN;
if (eeprom->magic != TG3_EEPROM_MAGIC) if (eeprom->magic != TG3_EEPROM_MAGIC)
return -EINVAL; return -EINVAL;
...@@ -8262,6 +8280,9 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest, ...@@ -8262,6 +8280,9 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest,
{ {
struct tg3 *tp = netdev_priv(dev); struct tg3 *tp = netdev_priv(dev);
if (tp->link_config.phy_is_low_power)
tg3_set_power_state(tp, PCI_D0);
memset(data, 0, sizeof(u64) * TG3_NUM_TEST); memset(data, 0, sizeof(u64) * TG3_NUM_TEST);
if (tg3_test_nvram(tp) != 0) { if (tg3_test_nvram(tp) != 0) {
...@@ -8319,6 +8340,9 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest, ...@@ -8319,6 +8340,9 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest,
tg3_full_unlock(tp); tg3_full_unlock(tp);
} }
if (tp->link_config.phy_is_low_power)
tg3_set_power_state(tp, PCI_D3hot);
} }
static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
...@@ -8338,6 +8362,9 @@ static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) ...@@ -8338,6 +8362,9 @@ static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)
break; /* We have no PHY */ break; /* We have no PHY */
if (tp->link_config.phy_is_low_power)
return -EAGAIN;
spin_lock_bh(&tp->lock); spin_lock_bh(&tp->lock);
err = tg3_readphy(tp, data->reg_num & 0x1f, &mii_regval); err = tg3_readphy(tp, data->reg_num & 0x1f, &mii_regval);
spin_unlock_bh(&tp->lock); spin_unlock_bh(&tp->lock);
...@@ -8354,6 +8381,9 @@ static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) ...@@ -8354,6 +8381,9 @@ static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
if (!capable(CAP_NET_ADMIN)) if (!capable(CAP_NET_ADMIN))
return -EPERM; return -EPERM;
if (tp->link_config.phy_is_low_power)
return -EAGAIN;
spin_lock_bh(&tp->lock); spin_lock_bh(&tp->lock);
err = tg3_writephy(tp, data->reg_num & 0x1f, data->val_in); err = tg3_writephy(tp, data->reg_num & 0x1f, data->val_in);
spin_unlock_bh(&tp->lock); spin_unlock_bh(&tp->lock);
...@@ -9805,7 +9835,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) ...@@ -9805,7 +9835,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
tp->grc_local_ctrl |= GRC_LCLCTRL_GPIO_OE3; tp->grc_local_ctrl |= GRC_LCLCTRL_GPIO_OE3;
/* Force the chip into D0. */ /* Force the chip into D0. */
err = tg3_set_power_state(tp, 0); err = tg3_set_power_state(tp, PCI_D0);
if (err) { if (err) {
printk(KERN_ERR PFX "(%s) transition to D0 failed\n", printk(KERN_ERR PFX "(%s) transition to D0 failed\n",
pci_name(tp->pdev)); pci_name(tp->pdev));
...@@ -11078,7 +11108,7 @@ static int tg3_resume(struct pci_dev *pdev) ...@@ -11078,7 +11108,7 @@ static int tg3_resume(struct pci_dev *pdev)
pci_restore_state(tp->pdev); pci_restore_state(tp->pdev);
err = tg3_set_power_state(tp, 0); err = tg3_set_power_state(tp, PCI_D0);
if (err) if (err)
return err; return err;
......
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