aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorStephen Hemminger <shemminger@osdl.org>2006-12-20 16:06:36 -0500
committerJeff Garzik <jeff@garzik.org>2007-02-05 16:58:45 -0500
commitae306cca3ada3c84f3e30e1091a98d99ee1d0557 (patch)
tree3cb3db2afd55f42023821b2ffd7235aa6638d381 /drivers
parent1d39ed565cfcc7c4fe586de621aef495c4f94ffb (diff)
sky2: better power state management
Improve power management and error handling by using pci_set_power_state(), instead of driver doing PCI PM register changes in the driver. Signed-off-by: Stephen Hemminger <shemminger@osdl.org> Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/sky2.c140
-rw-r--r--drivers/net/sky2.h1
2 files changed, 57 insertions, 84 deletions
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
index 822dd0b13133..09b94af3e65b 100644
--- a/drivers/net/sky2.c
+++ b/drivers/net/sky2.c
@@ -192,76 +192,52 @@ static u16 gm_phy_read(struct sky2_hw *hw, unsigned port, u16 reg)
192 return v; 192 return v;
193} 193}
194 194
195static void sky2_set_power_state(struct sky2_hw *hw, pci_power_t state)
196{
197 u16 power_control;
198 int vaux;
199
200 pr_debug("sky2_set_power_state %d\n", state);
201 sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
202
203 power_control = sky2_pci_read16(hw, hw->pm_cap + PCI_PM_PMC);
204 vaux = (sky2_read16(hw, B0_CTST) & Y2_VAUX_AVAIL) &&
205 (power_control & PCI_PM_CAP_PME_D3cold);
206
207 power_control = sky2_pci_read16(hw, hw->pm_cap + PCI_PM_CTRL);
208 195
209 power_control |= PCI_PM_CTRL_PME_STATUS; 196static void sky2_power_on(struct sky2_hw *hw)
210 power_control &= ~(PCI_PM_CTRL_STATE_MASK); 197{
211 198 /* switch power to VCC (WA for VAUX problem) */
212 switch (state) { 199 sky2_write8(hw, B0_POWER_CTRL,
213 case PCI_D0: 200 PC_VAUX_ENA | PC_VCC_ENA | PC_VAUX_OFF | PC_VCC_ON);
214 /* switch power to VCC (WA for VAUX problem) */
215 sky2_write8(hw, B0_POWER_CTRL,
216 PC_VAUX_ENA | PC_VCC_ENA | PC_VAUX_OFF | PC_VCC_ON);
217
218 /* disable Core Clock Division, */
219 sky2_write32(hw, B2_Y2_CLK_CTRL, Y2_CLK_DIV_DIS);
220
221 if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1)
222 /* enable bits are inverted */
223 sky2_write8(hw, B2_Y2_CLK_GATE,
224 Y2_PCI_CLK_LNK1_DIS | Y2_COR_CLK_LNK1_DIS |
225 Y2_CLK_GAT_LNK1_DIS | Y2_PCI_CLK_LNK2_DIS |
226 Y2_COR_CLK_LNK2_DIS | Y2_CLK_GAT_LNK2_DIS);
227 else
228 sky2_write8(hw, B2_Y2_CLK_GATE, 0);
229 201
230 if (hw->chip_id == CHIP_ID_YUKON_EC_U) { 202 /* disable Core Clock Division, */
231 u32 reg1; 203 sky2_write32(hw, B2_Y2_CLK_CTRL, Y2_CLK_DIV_DIS);
232 204
233 sky2_pci_write32(hw, PCI_DEV_REG3, 0); 205 if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1)
234 reg1 = sky2_pci_read32(hw, PCI_DEV_REG4); 206 /* enable bits are inverted */
235 reg1 &= P_ASPM_CONTROL_MSK; 207 sky2_write8(hw, B2_Y2_CLK_GATE,
236 sky2_pci_write32(hw, PCI_DEV_REG4, reg1); 208 Y2_PCI_CLK_LNK1_DIS | Y2_COR_CLK_LNK1_DIS |
237 sky2_pci_write32(hw, PCI_DEV_REG5, 0); 209 Y2_CLK_GAT_LNK1_DIS | Y2_PCI_CLK_LNK2_DIS |
238 } 210 Y2_COR_CLK_LNK2_DIS | Y2_CLK_GAT_LNK2_DIS);
211 else
212 sky2_write8(hw, B2_Y2_CLK_GATE, 0);
239 213
240 break; 214 if (hw->chip_id == CHIP_ID_YUKON_EC_U) {
215 u32 reg1;
241 216
242 case PCI_D3hot: 217 sky2_pci_write32(hw, PCI_DEV_REG3, 0);
243 case PCI_D3cold: 218 reg1 = sky2_pci_read32(hw, PCI_DEV_REG4);
244 if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1) 219 reg1 &= P_ASPM_CONTROL_MSK;
245 sky2_write8(hw, B2_Y2_CLK_GATE, 0); 220 sky2_pci_write32(hw, PCI_DEV_REG4, reg1);
246 else 221 sky2_pci_write32(hw, PCI_DEV_REG5, 0);
247 /* enable bits are inverted */
248 sky2_write8(hw, B2_Y2_CLK_GATE,
249 Y2_PCI_CLK_LNK1_DIS | Y2_COR_CLK_LNK1_DIS |
250 Y2_CLK_GAT_LNK1_DIS | Y2_PCI_CLK_LNK2_DIS |
251 Y2_COR_CLK_LNK2_DIS | Y2_CLK_GAT_LNK2_DIS);
252
253 /* switch power to VAUX */
254 if (vaux && state != PCI_D3cold)
255 sky2_write8(hw, B0_POWER_CTRL,
256 (PC_VAUX_ENA | PC_VCC_ENA |
257 PC_VAUX_ON | PC_VCC_OFF));
258 break;
259 default:
260 printk(KERN_ERR PFX "Unknown power state %d\n", state);
261 } 222 }
223}
262 224
263 sky2_pci_write16(hw, hw->pm_cap + PCI_PM_CTRL, power_control); 225static void sky2_power_aux(struct sky2_hw *hw)
264 sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF); 226{
227 if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1)
228 sky2_write8(hw, B2_Y2_CLK_GATE, 0);
229 else
230 /* enable bits are inverted */
231 sky2_write8(hw, B2_Y2_CLK_GATE,
232 Y2_PCI_CLK_LNK1_DIS | Y2_COR_CLK_LNK1_DIS |
233 Y2_CLK_GAT_LNK1_DIS | Y2_PCI_CLK_LNK2_DIS |
234 Y2_COR_CLK_LNK2_DIS | Y2_CLK_GAT_LNK2_DIS);
235
236 /* switch power to VAUX */
237 if (sky2_read16(hw, B0_CTST) & Y2_VAUX_AVAIL)
238 sky2_write8(hw, B0_POWER_CTRL,
239 (PC_VAUX_ENA | PC_VCC_ENA |
240 PC_VAUX_ON | PC_VCC_OFF));
265} 241}
266 242
267static void sky2_gmac_reset(struct sky2_hw *hw, unsigned port) 243static void sky2_gmac_reset(struct sky2_hw *hw, unsigned port)
@@ -2480,7 +2456,7 @@ static int sky2_reset(struct sky2_hw *hw)
2480 ++hw->ports; 2456 ++hw->ports;
2481 } 2457 }
2482 2458
2483 sky2_set_power_state(hw, PCI_D0); 2459 sky2_power_on(hw);
2484 2460
2485 for (i = 0; i < hw->ports; i++) { 2461 for (i = 0; i < hw->ports; i++) {
2486 sky2_write8(hw, SK_REG(i, GMAC_LINK_CTRL), GMLC_RST_SET); 2462 sky2_write8(hw, SK_REG(i, GMAC_LINK_CTRL), GMLC_RST_SET);
@@ -3376,7 +3352,7 @@ static int __devinit sky2_probe(struct pci_dev *pdev,
3376{ 3352{
3377 struct net_device *dev, *dev1 = NULL; 3353 struct net_device *dev, *dev1 = NULL;
3378 struct sky2_hw *hw; 3354 struct sky2_hw *hw;
3379 int err, pm_cap, using_dac = 0; 3355 int err, using_dac = 0;
3380 3356
3381 err = pci_enable_device(pdev); 3357 err = pci_enable_device(pdev);
3382 if (err) { 3358 if (err) {
@@ -3394,15 +3370,6 @@ static int __devinit sky2_probe(struct pci_dev *pdev,
3394 3370
3395 pci_set_master(pdev); 3371 pci_set_master(pdev);
3396 3372
3397 /* Find power-management capability. */
3398 pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM);
3399 if (pm_cap == 0) {
3400 printk(KERN_ERR PFX "Cannot find PowerManagement capability, "
3401 "aborting.\n");
3402 err = -EIO;
3403 goto err_out_free_regions;
3404 }
3405
3406 if (sizeof(dma_addr_t) > sizeof(u32) && 3373 if (sizeof(dma_addr_t) > sizeof(u32) &&
3407 !(err = pci_set_dma_mask(pdev, DMA_64BIT_MASK))) { 3374 !(err = pci_set_dma_mask(pdev, DMA_64BIT_MASK))) {
3408 using_dac = 1; 3375 using_dac = 1;
@@ -3438,7 +3405,6 @@ static int __devinit sky2_probe(struct pci_dev *pdev,
3438 pci_name(pdev)); 3405 pci_name(pdev));
3439 goto err_out_free_hw; 3406 goto err_out_free_hw;
3440 } 3407 }
3441 hw->pm_cap = pm_cap;
3442 3408
3443#ifdef __BIG_ENDIAN 3409#ifdef __BIG_ENDIAN
3444 /* The sk98lin vendor driver uses hardware byte swapping but 3410 /* The sk98lin vendor driver uses hardware byte swapping but
@@ -3555,7 +3521,8 @@ static void __devexit sky2_remove(struct pci_dev *pdev)
3555 unregister_netdev(dev1); 3521 unregister_netdev(dev1);
3556 unregister_netdev(dev0); 3522 unregister_netdev(dev0);
3557 3523
3558 sky2_set_power_state(hw, PCI_D3hot); 3524 sky2_power_aux(hw);
3525
3559 sky2_write16(hw, B0_Y2LED, LED_STAT_OFF); 3526 sky2_write16(hw, B0_Y2LED, LED_STAT_OFF);
3560 sky2_write8(hw, B0_CTST, CS_RST_SET); 3527 sky2_write8(hw, B0_CTST, CS_RST_SET);
3561 sky2_read8(hw, B0_CTST); 3528 sky2_read8(hw, B0_CTST);
@@ -3581,10 +3548,6 @@ static int sky2_suspend(struct pci_dev *pdev, pm_message_t state)
3581{ 3548{
3582 struct sky2_hw *hw = pci_get_drvdata(pdev); 3549 struct sky2_hw *hw = pci_get_drvdata(pdev);
3583 int i; 3550 int i;
3584 pci_power_t pstate = pci_choose_state(pdev, state);
3585
3586 if (!(pstate == PCI_D3hot || pstate == PCI_D3cold))
3587 return -EINVAL;
3588 3551
3589 del_timer_sync(&hw->idle_timer); 3552 del_timer_sync(&hw->idle_timer);
3590 netif_poll_disable(hw->dev[0]); 3553 netif_poll_disable(hw->dev[0]);
@@ -3599,8 +3562,10 @@ static int sky2_suspend(struct pci_dev *pdev, pm_message_t state)
3599 } 3562 }
3600 3563
3601 sky2_write32(hw, B0_IMSK, 0); 3564 sky2_write32(hw, B0_IMSK, 0);
3565 sky2_power_aux(hw);
3602 pci_save_state(pdev); 3566 pci_save_state(pdev);
3603 sky2_set_power_state(hw, pstate); 3567 pci_set_power_state(pdev, pci_choose_state(pdev, state));
3568
3604 return 0; 3569 return 0;
3605} 3570}
3606 3571
@@ -3609,9 +3574,15 @@ static int sky2_resume(struct pci_dev *pdev)
3609 struct sky2_hw *hw = pci_get_drvdata(pdev); 3574 struct sky2_hw *hw = pci_get_drvdata(pdev);
3610 int i, err; 3575 int i, err;
3611 3576
3612 pci_restore_state(pdev); 3577 err = pci_set_power_state(pdev, PCI_D0);
3578 if (err)
3579 goto out;
3580
3581 err = pci_restore_state(pdev);
3582 if (err)
3583 goto out;
3584
3613 pci_enable_wake(pdev, PCI_D0, 0); 3585 pci_enable_wake(pdev, PCI_D0, 0);
3614 sky2_set_power_state(hw, PCI_D0);
3615 3586
3616 err = sky2_reset(hw); 3587 err = sky2_reset(hw);
3617 if (err) 3588 if (err)
@@ -3636,7 +3607,10 @@ static int sky2_resume(struct pci_dev *pdev)
3636 3607
3637 netif_poll_enable(hw->dev[0]); 3608 netif_poll_enable(hw->dev[0]);
3638 sky2_idle_start(hw); 3609 sky2_idle_start(hw);
3610 return 0;
3639out: 3611out:
3612 printk(KERN_ERR PFX "%s: resume failed (%d)\n", pci_name(pdev), err);
3613 pci_disable_device(pdev);
3640 return err; 3614 return err;
3641} 3615}
3642#endif 3616#endif
diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h
index 6ed1d47dbbd3..1f56600aad86 100644
--- a/drivers/net/sky2.h
+++ b/drivers/net/sky2.h
@@ -1887,7 +1887,6 @@ struct sky2_hw {
1887 struct pci_dev *pdev; 1887 struct pci_dev *pdev;
1888 struct net_device *dev[2]; 1888 struct net_device *dev[2];
1889 1889
1890 int pm_cap;
1891 u8 chip_id; 1890 u8 chip_id;
1892 u8 chip_rev; 1891 u8 chip_rev;
1893 u8 pmd_type; 1892 u8 pmd_type;