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 | |
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')
-rw-r--r-- | drivers/net/e1000e/82571.c | 1 | ||||
-rw-r--r-- | drivers/net/e1000e/e1000.h | 1 | ||||
-rw-r--r-- | drivers/net/e1000e/netdev.c | 30 | ||||
-rw-r--r-- | drivers/net/e1000e/param.c | 7 |
4 files changed, 30 insertions, 9 deletions
diff --git a/drivers/net/e1000e/82571.c b/drivers/net/e1000e/82571.c index b6401abc17d6..45f5ee29343f 100644 --- a/drivers/net/e1000e/82571.c +++ b/drivers/net/e1000e/82571.c | |||
@@ -1343,7 +1343,6 @@ struct e1000_info e1000_82573_info = { | |||
1343 | | FLAG_HAS_STATS_ICR_ICT | 1343 | | FLAG_HAS_STATS_ICR_ICT |
1344 | | FLAG_HAS_SMART_POWER_DOWN | 1344 | | FLAG_HAS_SMART_POWER_DOWN |
1345 | | FLAG_HAS_AMT | 1345 | | FLAG_HAS_AMT |
1346 | | FLAG_HAS_ASPM | ||
1347 | | FLAG_HAS_ERT | 1346 | | FLAG_HAS_ERT |
1348 | | FLAG_HAS_SWSM_ON_LOAD, | 1347 | | FLAG_HAS_SWSM_ON_LOAD, |
1349 | .pba = 20, | 1348 | .pba = 20, |
diff --git a/drivers/net/e1000e/e1000.h b/drivers/net/e1000e/e1000.h index 473f78de4be0..8b88c226e858 100644 --- a/drivers/net/e1000e/e1000.h +++ b/drivers/net/e1000e/e1000.h | |||
@@ -288,7 +288,6 @@ struct e1000_info { | |||
288 | #define FLAG_HAS_CTRLEXT_ON_LOAD (1 << 5) | 288 | #define FLAG_HAS_CTRLEXT_ON_LOAD (1 << 5) |
289 | #define FLAG_HAS_SWSM_ON_LOAD (1 << 6) | 289 | #define FLAG_HAS_SWSM_ON_LOAD (1 << 6) |
290 | #define FLAG_HAS_JUMBO_FRAMES (1 << 7) | 290 | #define FLAG_HAS_JUMBO_FRAMES (1 << 7) |
291 | #define FLAG_HAS_ASPM (1 << 8) | ||
292 | #define FLAG_HAS_STATS_ICR_ICT (1 << 9) | 291 | #define FLAG_HAS_STATS_ICR_ICT (1 << 9) |
293 | #define FLAG_HAS_STATS_PTC_PRC (1 << 10) | 292 | #define FLAG_HAS_STATS_PTC_PRC (1 << 10) |
294 | #define FLAG_HAS_SMART_POWER_DOWN (1 << 11) | 293 | #define FLAG_HAS_SMART_POWER_DOWN (1 << 11) |
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; |
diff --git a/drivers/net/e1000e/param.c b/drivers/net/e1000e/param.c index 332789238b9c..df266c32ac4b 100644 --- a/drivers/net/e1000e/param.c +++ b/drivers/net/e1000e/param.c | |||
@@ -262,13 +262,6 @@ void __devinit e1000e_check_options(struct e1000_adapter *adapter) | |||
262 | .max = MAX_RXDELAY } } | 262 | .max = MAX_RXDELAY } } |
263 | }; | 263 | }; |
264 | 264 | ||
265 | /* modify min and default if 82573 for slow ping w/a, | ||
266 | * a value greater than 8 needs to be set for RDTR */ | ||
267 | if (adapter->flags & FLAG_HAS_ASPM) { | ||
268 | opt.def = 32; | ||
269 | opt.arg.r.min = 8; | ||
270 | } | ||
271 | |||
272 | if (num_RxIntDelay > bd) { | 265 | if (num_RxIntDelay > bd) { |
273 | adapter->rx_int_delay = RxIntDelay[bd]; | 266 | adapter->rx_int_delay = RxIntDelay[bd]; |
274 | e1000_validate_option(&adapter->rx_int_delay, &opt, | 267 | e1000_validate_option(&adapter->rx_int_delay, &opt, |