diff options
author | Stephen Hemminger <shemminger@osdl.org> | 2006-12-20 16:06:36 -0500 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2007-02-05 16:58:45 -0500 |
commit | ae306cca3ada3c84f3e30e1091a98d99ee1d0557 (patch) | |
tree | 3cb3db2afd55f42023821b2ffd7235aa6638d381 /drivers/net/sky2.c | |
parent | 1d39ed565cfcc7c4fe586de621aef495c4f94ffb (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/net/sky2.c')
-rw-r--r-- | drivers/net/sky2.c | 140 |
1 files changed, 57 insertions, 83 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 | ||
195 | static 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; | 196 | static 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); | 225 | static 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 | ||
267 | static void sky2_gmac_reset(struct sky2_hw *hw, unsigned port) | 243 | static 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; | ||
3639 | out: | 3611 | out: |
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 |