aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephen Hemminger <shemminger@vyatta.com>2008-05-14 20:04:17 -0400
committerJeff Garzik <jgarzik@redhat.com>2008-05-30 22:19:17 -0400
commita068c0adf2fe28b324bca87f85d27af7f993cdaf (patch)
tree0c7685f8061825641d153abd738222ca05f52fac
parentdb99b98885e717454feef1c6868b27d3f23c2e7c (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>
-rw-r--r--drivers/net/sky2.c98
-rw-r--r--drivers/net/sky2.h16
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
287static 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
287static void sky2_gmac_reset(struct sky2_hw *hw, unsigned port) 367static 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
4497static struct pci_driver sky2_driver = { 4583static 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
33enum pci_dev_reg_2 { 38enum 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) */
47enum pci_dev_reg_4 { 52enum 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};
466enum 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;