aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorStephen Hemminger <shemminger@linux-foundation.org>2007-02-02 11:22:53 -0500
committerJeff Garzik <jeff@garzik.org>2007-02-06 19:07:44 -0500
commita504e64ab42bcc27074ea37405d06833ed6e0820 (patch)
treeb7c9b772969bd72a2f3f1636943db18718fc41b9 /drivers/net
parent1479d13cb5304c452e6d7398c7771974c1014846 (diff)
skge: WOL support
Add WOL support for Yukon chipsets in skge device. Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org> Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/skge.c158
-rw-r--r--drivers/net/skge.h2
2 files changed, 125 insertions, 35 deletions
diff --git a/drivers/net/skge.c b/drivers/net/skge.c
index 9135602e157d..7e687ca4789a 100644
--- a/drivers/net/skge.c
+++ b/drivers/net/skge.c
@@ -132,18 +132,93 @@ static void skge_get_regs(struct net_device *dev, struct ethtool_regs *regs,
132} 132}
133 133
134/* Wake on Lan only supported on Yukon chips with rev 1 or above */ 134/* Wake on Lan only supported on Yukon chips with rev 1 or above */
135static int wol_supported(const struct skge_hw *hw) 135static u32 wol_supported(const struct skge_hw *hw)
136{ 136{
137 return !((hw->chip_id == CHIP_ID_GENESIS || 137 if (hw->chip_id == CHIP_ID_YUKON && hw->chip_rev != 0)
138 (hw->chip_id == CHIP_ID_YUKON && hw->chip_rev == 0))); 138 return WAKE_MAGIC | WAKE_PHY;
139 else
140 return 0;
141}
142
143static u32 pci_wake_enabled(struct pci_dev *dev)
144{
145 int pm = pci_find_capability(dev, PCI_CAP_ID_PM);
146 u16 value;
147
148 /* If device doesn't support PM Capabilities, but request is to disable
149 * wake events, it's a nop; otherwise fail */
150 if (!pm)
151 return 0;
152
153 pci_read_config_word(dev, pm + PCI_PM_PMC, &value);
154
155 value &= PCI_PM_CAP_PME_MASK;
156 value >>= ffs(PCI_PM_CAP_PME_MASK) - 1; /* First bit of mask */
157
158 return value != 0;
159}
160
161static void skge_wol_init(struct skge_port *skge)
162{
163 struct skge_hw *hw = skge->hw;
164 int port = skge->port;
165 enum pause_control save_mode;
166 u32 ctrl;
167
168 /* Bring hardware out of reset */
169 skge_write16(hw, B0_CTST, CS_RST_CLR);
170 skge_write16(hw, SK_REG(port, GMAC_LINK_CTRL), GMLC_RST_CLR);
171
172 skge_write8(hw, SK_REG(port, GPHY_CTRL), GPC_RST_CLR);
173 skge_write8(hw, SK_REG(port, GMAC_CTRL), GMC_RST_CLR);
174
175 /* Force to 10/100 skge_reset will re-enable on resume */
176 save_mode = skge->flow_control;
177 skge->flow_control = FLOW_MODE_SYMMETRIC;
178
179 ctrl = skge->advertising;
180 skge->advertising &= ~(ADVERTISED_1000baseT_Half|ADVERTISED_1000baseT_Full);
181
182 skge_phy_reset(skge);
183
184 skge->flow_control = save_mode;
185 skge->advertising = ctrl;
186
187 /* Set GMAC to no flow control and auto update for speed/duplex */
188 gma_write16(hw, port, GM_GP_CTRL,
189 GM_GPCR_FC_TX_DIS|GM_GPCR_TX_ENA|GM_GPCR_RX_ENA|
190 GM_GPCR_DUP_FULL|GM_GPCR_FC_RX_DIS|GM_GPCR_AU_FCT_DIS);
191
192 /* Set WOL address */
193 memcpy_toio(hw->regs + WOL_REGS(port, WOL_MAC_ADDR),
194 skge->netdev->dev_addr, ETH_ALEN);
195
196 /* Turn on appropriate WOL control bits */
197 skge_write16(hw, WOL_REGS(port, WOL_CTRL_STAT), WOL_CTL_CLEAR_RESULT);
198 ctrl = 0;
199 if (skge->wol & WAKE_PHY)
200 ctrl |= WOL_CTL_ENA_PME_ON_LINK_CHG|WOL_CTL_ENA_LINK_CHG_UNIT;
201 else
202 ctrl |= WOL_CTL_DIS_PME_ON_LINK_CHG|WOL_CTL_DIS_LINK_CHG_UNIT;
203
204 if (skge->wol & WAKE_MAGIC)
205 ctrl |= WOL_CTL_ENA_PME_ON_MAGIC_PKT|WOL_CTL_ENA_MAGIC_PKT_UNIT;
206 else
207 ctrl |= WOL_CTL_DIS_PME_ON_MAGIC_PKT|WOL_CTL_DIS_MAGIC_PKT_UNIT;;
208
209 ctrl |= WOL_CTL_DIS_PME_ON_PATTERN|WOL_CTL_DIS_PATTERN_UNIT;
210 skge_write16(hw, WOL_REGS(port, WOL_CTRL_STAT), ctrl);
211
212 /* block receiver */
213 skge_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_SET);
139} 214}
140 215
141static void skge_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) 216static void skge_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
142{ 217{
143 struct skge_port *skge = netdev_priv(dev); 218 struct skge_port *skge = netdev_priv(dev);
144 219
145 wol->supported = wol_supported(skge->hw) ? WAKE_MAGIC : 0; 220 wol->supported = wol_supported(skge->hw);
146 wol->wolopts = skge->wol ? WAKE_MAGIC : 0; 221 wol->wolopts = skge->wol;
147} 222}
148 223
149static int skge_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) 224static int skge_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
@@ -151,23 +226,12 @@ static int skge_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
151 struct skge_port *skge = netdev_priv(dev); 226 struct skge_port *skge = netdev_priv(dev);
152 struct skge_hw *hw = skge->hw; 227 struct skge_hw *hw = skge->hw;
153 228
154 if (wol->wolopts != WAKE_MAGIC && wol->wolopts != 0) 229 if (wol->wolopts & wol_supported(hw))
155 return -EOPNOTSUPP;
156
157 if (wol->wolopts == WAKE_MAGIC && !wol_supported(hw))
158 return -EOPNOTSUPP; 230 return -EOPNOTSUPP;
159 231
160 skge->wol = wol->wolopts == WAKE_MAGIC; 232 skge->wol = wol->wolopts;
161 233 if (!netif_running(dev))
162 if (skge->wol) { 234 skge_wol_init(skge);
163 memcpy_toio(hw->regs + WOL_MAC_ADDR, dev->dev_addr, ETH_ALEN);
164
165 skge_write16(hw, WOL_CTRL_STAT,
166 WOL_CTL_ENA_PME_ON_MAGIC_PKT |
167 WOL_CTL_ENA_MAGIC_PKT_UNIT);
168 } else
169 skge_write16(hw, WOL_CTRL_STAT, WOL_CTL_DEFAULT);
170
171 return 0; 235 return 0;
172} 236}
173 237
@@ -3456,6 +3520,7 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port,
3456 skge->duplex = -1; 3520 skge->duplex = -1;
3457 skge->speed = -1; 3521 skge->speed = -1;
3458 skge->advertising = skge_supported_modes(hw); 3522 skge->advertising = skge_supported_modes(hw);
3523 skge->wol = pci_wake_enabled(hw->pdev) ? wol_supported(hw) : 0;
3459 3524
3460 hw->dev[port] = dev; 3525 hw->dev[port] = dev;
3461 3526
@@ -3654,28 +3719,46 @@ static void __devexit skge_remove(struct pci_dev *pdev)
3654} 3719}
3655 3720
3656#ifdef CONFIG_PM 3721#ifdef CONFIG_PM
3722static int vaux_avail(struct pci_dev *pdev)
3723{
3724 int pm_cap;
3725
3726 pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM);
3727 if (pm_cap) {
3728 u16 ctl;
3729 pci_read_config_word(pdev, pm_cap + PCI_PM_PMC, &ctl);
3730 if (ctl & PCI_PM_CAP_AUX_POWER)
3731 return 1;
3732 }
3733 return 0;
3734}
3735
3736
3657static int skge_suspend(struct pci_dev *pdev, pm_message_t state) 3737static int skge_suspend(struct pci_dev *pdev, pm_message_t state)
3658{ 3738{
3659 struct skge_hw *hw = pci_get_drvdata(pdev); 3739 struct skge_hw *hw = pci_get_drvdata(pdev);
3660 int i, wol = 0; 3740 int i, err, wol = 0;
3741
3742 err = pci_save_state(pdev);
3743 if (err)
3744 return err;
3661 3745
3662 pci_save_state(pdev);
3663 for (i = 0; i < hw->ports; i++) { 3746 for (i = 0; i < hw->ports; i++) {
3664 struct net_device *dev = hw->dev[i]; 3747 struct net_device *dev = hw->dev[i];
3748 struct skge_port *skge = netdev_priv(dev);
3665 3749
3666 if (netif_running(dev)) { 3750 if (netif_running(dev))
3667 struct skge_port *skge = netdev_priv(dev); 3751 skge_down(dev);
3752 if (skge->wol)
3753 skge_wol_init(skge);
3668 3754
3669 netif_carrier_off(dev); 3755 wol |= skge->wol;
3670 if (skge->wol)
3671 netif_stop_queue(dev);
3672 else
3673 skge_down(dev);
3674 wol |= skge->wol;
3675 }
3676 netif_device_detach(dev);
3677 } 3756 }
3678 3757
3758 if (wol && vaux_avail(pdev))
3759 skge_write8(hw, B0_POWER_CTRL,
3760 PC_VAUX_ENA | PC_VCC_ENA | PC_VAUX_ON | PC_VCC_OFF);
3761
3679 skge_write32(hw, B0_IMSK, 0); 3762 skge_write32(hw, B0_IMSK, 0);
3680 pci_enable_wake(pdev, pci_choose_state(pdev, state), wol); 3763 pci_enable_wake(pdev, pci_choose_state(pdev, state), wol);
3681 pci_set_power_state(pdev, pci_choose_state(pdev, state)); 3764 pci_set_power_state(pdev, pci_choose_state(pdev, state));
@@ -3688,8 +3771,14 @@ static int skge_resume(struct pci_dev *pdev)
3688 struct skge_hw *hw = pci_get_drvdata(pdev); 3771 struct skge_hw *hw = pci_get_drvdata(pdev);
3689 int i, err; 3772 int i, err;
3690 3773
3691 pci_set_power_state(pdev, PCI_D0); 3774 err = pci_set_power_state(pdev, PCI_D0);
3692 pci_restore_state(pdev); 3775 if (err)
3776 goto out;
3777
3778 err = pci_restore_state(pdev);
3779 if (err)
3780 goto out;
3781
3693 pci_enable_wake(pdev, PCI_D0, 0); 3782 pci_enable_wake(pdev, PCI_D0, 0);
3694 3783
3695 err = skge_reset(hw); 3784 err = skge_reset(hw);
@@ -3699,7 +3788,6 @@ static int skge_resume(struct pci_dev *pdev)
3699 for (i = 0; i < hw->ports; i++) { 3788 for (i = 0; i < hw->ports; i++) {
3700 struct net_device *dev = hw->dev[i]; 3789 struct net_device *dev = hw->dev[i];
3701 3790
3702 netif_device_attach(dev);
3703 if (netif_running(dev)) { 3791 if (netif_running(dev)) {
3704 err = skge_up(dev); 3792 err = skge_up(dev);
3705 3793
diff --git a/drivers/net/skge.h b/drivers/net/skge.h
index f6223c533c01..17b1b479dff5 100644
--- a/drivers/net/skge.h
+++ b/drivers/net/skge.h
@@ -876,11 +876,13 @@ enum {
876 WOL_PATT_CNT_0 = 0x0f38,/* 32 bit WOL Pattern Counter 3..0 */ 876 WOL_PATT_CNT_0 = 0x0f38,/* 32 bit WOL Pattern Counter 3..0 */
877 WOL_PATT_CNT_4 = 0x0f3c,/* 24 bit WOL Pattern Counter 6..4 */ 877 WOL_PATT_CNT_4 = 0x0f3c,/* 24 bit WOL Pattern Counter 6..4 */
878}; 878};
879#define WOL_REGS(port, x) (x + (port)*0x80)
879 880
880enum { 881enum {
881 WOL_PATT_RAM_1 = 0x1000,/* WOL Pattern RAM Link 1 */ 882 WOL_PATT_RAM_1 = 0x1000,/* WOL Pattern RAM Link 1 */
882 WOL_PATT_RAM_2 = 0x1400,/* WOL Pattern RAM Link 2 */ 883 WOL_PATT_RAM_2 = 0x1400,/* WOL Pattern RAM Link 2 */
883}; 884};
885#define WOL_PATT_RAM_BASE(port) (WOL_PATT_RAM_1 + (port)*0x400)
884 886
885enum { 887enum {
886 BASE_XMAC_1 = 0x2000,/* XMAC 1 registers */ 888 BASE_XMAC_1 = 0x2000,/* XMAC 1 registers */