diff options
author | Auke Kok <auke-jan.h.kok@intel.com> | 2007-10-31 18:22:00 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-01-28 18:03:43 -0500 |
commit | 1eae4eb2a1c784bf35ee4f8f158cd21cf8c387c1 (patch) | |
tree | 4e9de1ad1d24b201647376a21862a110e462c831 /drivers/net/e1000e/netdev.c | |
parent | 93ca161027eb6a1761fb674ad7b995aedccf5f6e (diff) |
e1000e: Disable L1 ASPM power savings for 82573 mobile variants
L1 ASPM link (pci-e link power savings) has significant benefits
(~1W savings when link is active) but unfortunately does not work
correctly on any of the chipsets that have 82573 on mobile platforms
which causes various nuisances:
- eeprom reads return garbage information leading to bad eeprom
checksums
- long ping times (up to 2 seconds)
- complete system hangs (freeze/lockup)
A lot of T60 owners have been plagued by this, but other mobile
solutions also suffer from these symptoms.
Disabling L1 ASPM before we activate the PCI-E link fixes all of
these issues at the cost of some power consumption.
Remove a workaround RDTR adjustment that is no longer needed with
this new one.
Signed-off-by: Auke Kok <auke-jan.h.kok@intel.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers/net/e1000e/netdev.c')
-rw-r--r-- | drivers/net/e1000e/netdev.c | 30 |
1 files changed, 30 insertions, 0 deletions
diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index 9cc5a6b01bc1..5450ef8bf881 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c | |||
@@ -3509,6 +3509,33 @@ static int e1000_suspend(struct pci_dev *pdev, pm_message_t state) | |||
3509 | return 0; | 3509 | return 0; |
3510 | } | 3510 | } |
3511 | 3511 | ||
3512 | static void e1000e_disable_l1aspm(struct pci_dev *pdev) | ||
3513 | { | ||
3514 | int pos; | ||
3515 | u32 cap; | ||
3516 | u16 val; | ||
3517 | |||
3518 | /* | ||
3519 | * 82573 workaround - disable L1 ASPM on mobile chipsets | ||
3520 | * | ||
3521 | * L1 ASPM on various mobile (ich7) chipsets do not behave properly | ||
3522 | * resulting in lost data or garbage information on the pci-e link | ||
3523 | * level. This could result in (false) bad EEPROM checksum errors, | ||
3524 | * long ping times (up to 2s) or even a system freeze/hang. | ||
3525 | * | ||
3526 | * Unfortunately this feature saves about 1W power consumption when | ||
3527 | * active. | ||
3528 | */ | ||
3529 | pos = pci_find_capability(pdev, PCI_CAP_ID_EXP); | ||
3530 | pci_read_config_dword(pdev, pos + PCI_EXP_LNKCAP, &cap); | ||
3531 | pci_read_config_word(pdev, pos + PCI_EXP_LNKCTL, &val); | ||
3532 | if (val & 0x2) { | ||
3533 | dev_warn(&pdev->dev, "Disabling L1 ASPM\n"); | ||
3534 | val &= ~0x2; | ||
3535 | pci_write_config_word(pdev, pos + PCI_EXP_LNKCTL, val); | ||
3536 | } | ||
3537 | } | ||
3538 | |||
3512 | #ifdef CONFIG_PM | 3539 | #ifdef CONFIG_PM |
3513 | static int e1000_resume(struct pci_dev *pdev) | 3540 | static int e1000_resume(struct pci_dev *pdev) |
3514 | { | 3541 | { |
@@ -3519,6 +3546,7 @@ static int e1000_resume(struct pci_dev *pdev) | |||
3519 | 3546 | ||
3520 | pci_set_power_state(pdev, PCI_D0); | 3547 | pci_set_power_state(pdev, PCI_D0); |
3521 | pci_restore_state(pdev); | 3548 | pci_restore_state(pdev); |
3549 | e1000e_disable_l1aspm(pdev); | ||
3522 | err = pci_enable_device(pdev); | 3550 | err = pci_enable_device(pdev); |
3523 | if (err) { | 3551 | if (err) { |
3524 | dev_err(&pdev->dev, | 3552 | dev_err(&pdev->dev, |
@@ -3619,6 +3647,7 @@ static pci_ers_result_t e1000_io_slot_reset(struct pci_dev *pdev) | |||
3619 | struct e1000_adapter *adapter = netdev_priv(netdev); | 3647 | struct e1000_adapter *adapter = netdev_priv(netdev); |
3620 | struct e1000_hw *hw = &adapter->hw; | 3648 | struct e1000_hw *hw = &adapter->hw; |
3621 | 3649 | ||
3650 | e1000e_disable_l1aspm(pdev); | ||
3622 | if (pci_enable_device(pdev)) { | 3651 | if (pci_enable_device(pdev)) { |
3623 | dev_err(&pdev->dev, | 3652 | dev_err(&pdev->dev, |
3624 | "Cannot re-enable PCI device after reset.\n"); | 3653 | "Cannot re-enable PCI device after reset.\n"); |
@@ -3720,6 +3749,7 @@ static int __devinit e1000_probe(struct pci_dev *pdev, | |||
3720 | u16 eeprom_data = 0; | 3749 | u16 eeprom_data = 0; |
3721 | u16 eeprom_apme_mask = E1000_EEPROM_APME; | 3750 | u16 eeprom_apme_mask = E1000_EEPROM_APME; |
3722 | 3751 | ||
3752 | e1000e_disable_l1aspm(pdev); | ||
3723 | err = pci_enable_device(pdev); | 3753 | err = pci_enable_device(pdev); |
3724 | if (err) | 3754 | if (err) |
3725 | return err; | 3755 | return err; |