diff options
author | Stephen Hemminger <shemminger@vyatta.com> | 2008-05-14 20:04:17 -0400 |
---|---|---|
committer | Jeff Garzik <jgarzik@redhat.com> | 2008-05-30 22:19:17 -0400 |
commit | a068c0adf2fe28b324bca87f85d27af7f993cdaf (patch) | |
tree | 0c7685f8061825641d153abd738222ca05f52fac /drivers/net | |
parent | db99b98885e717454feef1c6868b27d3f23c2e7c (diff) |
sky2: pci power savings
Turn on special bits to save more power when device is shutdown.
Tested on a limited range of hardware, some of the bits are for hardware
that probably isn't even in production (like Yukon Supreme) and was ported
from the vendor driver.
Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/sky2.c | 98 | ||||
-rw-r--r-- | drivers/net/sky2.h | 16 |
2 files changed, 107 insertions, 7 deletions
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 59cb9cd00ad2..c83406f4f2a7 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c | |||
@@ -284,6 +284,86 @@ static void sky2_power_aux(struct sky2_hw *hw) | |||
284 | PC_VAUX_ON | PC_VCC_OFF)); | 284 | PC_VAUX_ON | PC_VCC_OFF)); |
285 | } | 285 | } |
286 | 286 | ||
287 | static void sky2_power_state(struct sky2_hw *hw, pci_power_t state) | ||
288 | { | ||
289 | u16 power_control = sky2_pci_read16(hw, hw->pm_cap + PCI_PM_CTRL); | ||
290 | int pex = pci_find_capability(hw->pdev, PCI_CAP_ID_EXP); | ||
291 | u32 reg; | ||
292 | |||
293 | sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON); | ||
294 | |||
295 | switch (state) { | ||
296 | case PCI_D0: | ||
297 | break; | ||
298 | |||
299 | case PCI_D1: | ||
300 | power_control |= 1; | ||
301 | break; | ||
302 | |||
303 | case PCI_D2: | ||
304 | power_control |= 2; | ||
305 | break; | ||
306 | |||
307 | case PCI_D3hot: | ||
308 | case PCI_D3cold: | ||
309 | power_control |= 3; | ||
310 | if (hw->flags & SKY2_HW_ADV_POWER_CTL) { | ||
311 | /* additional power saving measurements */ | ||
312 | reg = sky2_pci_read32(hw, PCI_DEV_REG4); | ||
313 | |||
314 | /* set gating core clock for LTSSM in L1 state */ | ||
315 | reg |= P_PEX_LTSSM_STAT(P_PEX_LTSSM_L1_STAT) | | ||
316 | /* auto clock gated scheme controlled by CLKREQ */ | ||
317 | P_ASPM_A1_MODE_SELECT | | ||
318 | /* enable Gate Root Core Clock */ | ||
319 | P_CLK_GATE_ROOT_COR_ENA; | ||
320 | |||
321 | if (pex && (hw->flags & SKY2_HW_CLK_POWER)) { | ||
322 | /* enable Clock Power Management (CLKREQ) */ | ||
323 | u16 ctrl = sky2_pci_read16(hw, pex + PCI_EXP_DEVCTL); | ||
324 | |||
325 | ctrl |= PCI_EXP_DEVCTL_AUX_PME; | ||
326 | sky2_pci_write16(hw, pex + PCI_EXP_DEVCTL, ctrl); | ||
327 | } else | ||
328 | /* force CLKREQ Enable in Our4 (A1b only) */ | ||
329 | reg |= P_ASPM_FORCE_CLKREQ_ENA; | ||
330 | |||
331 | /* set Mask Register for Release/Gate Clock */ | ||
332 | sky2_pci_write32(hw, PCI_DEV_REG5, | ||
333 | P_REL_PCIE_EXIT_L1_ST | P_GAT_PCIE_ENTER_L1_ST | | ||
334 | P_REL_PCIE_RX_EX_IDLE | P_GAT_PCIE_RX_EL_IDLE | | ||
335 | P_REL_GPHY_LINK_UP | P_GAT_GPHY_LINK_DOWN); | ||
336 | } else | ||
337 | sky2_write8(hw, B28_Y2_ASF_STAT_CMD, Y2_ASF_CLK_HALT); | ||
338 | |||
339 | /* put CPU into reset state */ | ||
340 | sky2_write8(hw, B28_Y2_ASF_STAT_CMD, HCU_CCSR_ASF_RESET); | ||
341 | if (hw->chip_id == CHIP_ID_YUKON_SUPR && hw->chip_rev == CHIP_REV_YU_SU_A0) | ||
342 | /* put CPU into halt state */ | ||
343 | sky2_write8(hw, B28_Y2_ASF_STAT_CMD, HCU_CCSR_ASF_HALTED); | ||
344 | |||
345 | if (pex && !(hw->flags & SKY2_HW_RAM_BUFFER)) { | ||
346 | reg = sky2_pci_read32(hw, PCI_DEV_REG1); | ||
347 | /* force to PCIe L1 */ | ||
348 | reg |= PCI_FORCE_PEX_L1; | ||
349 | sky2_pci_write32(hw, PCI_DEV_REG1, reg); | ||
350 | } | ||
351 | break; | ||
352 | |||
353 | default: | ||
354 | dev_warn(&hw->pdev->dev, PFX "Invalid power state (%d) ", | ||
355 | state); | ||
356 | return; | ||
357 | } | ||
358 | |||
359 | power_control |= PCI_PM_CTRL_PME_ENABLE; | ||
360 | /* Finally, set the new power state. */ | ||
361 | sky2_pci_write32(hw, hw->pm_cap + PCI_PM_CTRL, power_control); | ||
362 | |||
363 | sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF); | ||
364 | sky2_pci_read32(hw, B0_CTST); | ||
365 | } | ||
366 | |||
287 | static void sky2_gmac_reset(struct sky2_hw *hw, unsigned port) | 367 | static void sky2_gmac_reset(struct sky2_hw *hw, unsigned port) |
288 | { | 368 | { |
289 | u16 reg; | 369 | u16 reg; |
@@ -2786,6 +2866,10 @@ static int __devinit sky2_init(struct sky2_hw *hw) | |||
2786 | hw->flags = SKY2_HW_GIGABIT | 2866 | hw->flags = SKY2_HW_GIGABIT |
2787 | | SKY2_HW_NEWER_PHY | 2867 | | SKY2_HW_NEWER_PHY |
2788 | | SKY2_HW_ADV_POWER_CTL; | 2868 | | SKY2_HW_ADV_POWER_CTL; |
2869 | |||
2870 | /* check for Rev. A1 dev 4200 */ | ||
2871 | if (sky2_read16(hw, Q_ADDR(Q_XA1, Q_WM)) == 0) | ||
2872 | hw->flags |= SKY2_HW_CLK_POWER; | ||
2789 | break; | 2873 | break; |
2790 | 2874 | ||
2791 | case CHIP_ID_YUKON_EX: | 2875 | case CHIP_ID_YUKON_EX: |
@@ -2836,6 +2920,11 @@ static int __devinit sky2_init(struct sky2_hw *hw) | |||
2836 | if (hw->pmd_type == 'L' || hw->pmd_type == 'S' || hw->pmd_type == 'P') | 2920 | if (hw->pmd_type == 'L' || hw->pmd_type == 'S' || hw->pmd_type == 'P') |
2837 | hw->flags |= SKY2_HW_FIBRE_PHY; | 2921 | hw->flags |= SKY2_HW_FIBRE_PHY; |
2838 | 2922 | ||
2923 | hw->pm_cap = pci_find_capability(hw->pdev, PCI_CAP_ID_PM); | ||
2924 | if (hw->pm_cap == 0) { | ||
2925 | dev_err(&hw->pdev->dev, "cannot find PowerManagement capability\n"); | ||
2926 | return -EIO; | ||
2927 | } | ||
2839 | 2928 | ||
2840 | hw->ports = 1; | 2929 | hw->ports = 1; |
2841 | t8 = sky2_read8(hw, B2_Y2_HW_RES); | 2930 | t8 = sky2_read8(hw, B2_Y2_HW_RES); |
@@ -4407,7 +4496,7 @@ static int sky2_suspend(struct pci_dev *pdev, pm_message_t state) | |||
4407 | 4496 | ||
4408 | pci_save_state(pdev); | 4497 | pci_save_state(pdev); |
4409 | pci_enable_wake(pdev, pci_choose_state(pdev, state), wol); | 4498 | pci_enable_wake(pdev, pci_choose_state(pdev, state), wol); |
4410 | pci_set_power_state(pdev, pci_choose_state(pdev, state)); | 4499 | sky2_power_state(hw, pci_choose_state(pdev, state)); |
4411 | 4500 | ||
4412 | return 0; | 4501 | return 0; |
4413 | } | 4502 | } |
@@ -4420,9 +4509,7 @@ static int sky2_resume(struct pci_dev *pdev) | |||
4420 | if (!hw) | 4509 | if (!hw) |
4421 | return 0; | 4510 | return 0; |
4422 | 4511 | ||
4423 | err = pci_set_power_state(pdev, PCI_D0); | 4512 | sky2_power_state(hw, PCI_D0); |
4424 | if (err) | ||
4425 | goto out; | ||
4426 | 4513 | ||
4427 | err = pci_restore_state(pdev); | 4514 | err = pci_restore_state(pdev); |
4428 | if (err) | 4515 | if (err) |
@@ -4490,8 +4577,7 @@ static void sky2_shutdown(struct pci_dev *pdev) | |||
4490 | pci_enable_wake(pdev, PCI_D3cold, wol); | 4577 | pci_enable_wake(pdev, PCI_D3cold, wol); |
4491 | 4578 | ||
4492 | pci_disable_device(pdev); | 4579 | pci_disable_device(pdev); |
4493 | pci_set_power_state(pdev, PCI_D3hot); | 4580 | sky2_power_state(hw, PCI_D3hot); |
4494 | |||
4495 | } | 4581 | } |
4496 | 4582 | ||
4497 | static struct pci_driver sky2_driver = { | 4583 | static struct pci_driver sky2_driver = { |
diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h index d63106cd74ba..1fa82bf029d9 100644 --- a/drivers/net/sky2.h +++ b/drivers/net/sky2.h | |||
@@ -28,6 +28,11 @@ enum pci_dev_reg_1 { | |||
28 | PCI_Y2_PHY2_POWD = 1<<27, /* Set PHY 2 to Power Down (YUKON-2) */ | 28 | PCI_Y2_PHY2_POWD = 1<<27, /* Set PHY 2 to Power Down (YUKON-2) */ |
29 | PCI_Y2_PHY1_POWD = 1<<26, /* Set PHY 1 to Power Down (YUKON-2) */ | 29 | PCI_Y2_PHY1_POWD = 1<<26, /* Set PHY 1 to Power Down (YUKON-2) */ |
30 | PCI_Y2_PME_LEGACY= 1<<15, /* PCI Express legacy power management mode */ | 30 | PCI_Y2_PME_LEGACY= 1<<15, /* PCI Express legacy power management mode */ |
31 | |||
32 | PCI_PHY_LNK_TIM_MSK= 3L<<8,/* Bit 9.. 8: GPHY Link Trigger Timer */ | ||
33 | PCI_ENA_L1_EVENT = 1<<7, /* Enable PEX L1 Event */ | ||
34 | PCI_ENA_GPHY_LNK = 1<<6, /* Enable PEX L1 on GPHY Link down */ | ||
35 | PCI_FORCE_PEX_L1 = 1<<5, /* Force to PEX L1 */ | ||
31 | }; | 36 | }; |
32 | 37 | ||
33 | enum pci_dev_reg_2 { | 38 | enum pci_dev_reg_2 { |
@@ -45,7 +50,11 @@ enum pci_dev_reg_2 { | |||
45 | 50 | ||
46 | /* PCI_OUR_REG_4 32 bit Our Register 4 (Yukon-ECU only) */ | 51 | /* PCI_OUR_REG_4 32 bit Our Register 4 (Yukon-ECU only) */ |
47 | enum pci_dev_reg_4 { | 52 | enum pci_dev_reg_4 { |
48 | /* (Link Training & Status State Machine) */ | 53 | /* (Link Training & Status State Machine) */ |
54 | P_PEX_LTSSM_STAT_MSK = 0x7fL<<25, /* Bit 31..25: PEX LTSSM Mask */ | ||
55 | #define P_PEX_LTSSM_STAT(x) ((x << 25) & P_PEX_LTSSM_STAT_MSK) | ||
56 | P_PEX_LTSSM_L1_STAT = 0x34, | ||
57 | P_PEX_LTSSM_DET_STAT = 0x01, | ||
49 | P_TIMER_VALUE_MSK = 0xffL<<16, /* Bit 23..16: Timer Value Mask */ | 58 | P_TIMER_VALUE_MSK = 0xffL<<16, /* Bit 23..16: Timer Value Mask */ |
50 | /* (Active State Power Management) */ | 59 | /* (Active State Power Management) */ |
51 | P_FORCE_ASPM_REQUEST = 1<<15, /* Force ASPM Request (A1 only) */ | 60 | P_FORCE_ASPM_REQUEST = 1<<15, /* Force ASPM Request (A1 only) */ |
@@ -454,6 +463,9 @@ enum yukon_ex_rev { | |||
454 | CHIP_REV_YU_EX_A0 = 1, | 463 | CHIP_REV_YU_EX_A0 = 1, |
455 | CHIP_REV_YU_EX_B0 = 2, | 464 | CHIP_REV_YU_EX_B0 = 2, |
456 | }; | 465 | }; |
466 | enum yukon_supr_rev { | ||
467 | CHIP_REV_YU_SU_A0 = 0, | ||
468 | }; | ||
457 | 469 | ||
458 | 470 | ||
459 | /* B2_Y2_CLK_GATE 8 bit Clock Gating (Yukon-2 only) */ | 471 | /* B2_Y2_CLK_GATE 8 bit Clock Gating (Yukon-2 only) */ |
@@ -2059,7 +2071,9 @@ struct sky2_hw { | |||
2059 | #define SKY2_HW_NEW_LE 0x00000020 /* new LSOv2 format */ | 2071 | #define SKY2_HW_NEW_LE 0x00000020 /* new LSOv2 format */ |
2060 | #define SKY2_HW_AUTO_TX_SUM 0x00000040 /* new IP decode for Tx */ | 2072 | #define SKY2_HW_AUTO_TX_SUM 0x00000040 /* new IP decode for Tx */ |
2061 | #define SKY2_HW_ADV_POWER_CTL 0x00000080 /* additional PHY power regs */ | 2073 | #define SKY2_HW_ADV_POWER_CTL 0x00000080 /* additional PHY power regs */ |
2074 | #define SKY2_HW_CLK_POWER 0x00000100 /* clock power management */ | ||
2062 | 2075 | ||
2076 | int pm_cap; | ||
2063 | u8 chip_id; | 2077 | u8 chip_id; |
2064 | u8 chip_rev; | 2078 | u8 chip_rev; |
2065 | u8 pmd_type; | 2079 | u8 pmd_type; |