aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorAuke Kok <auke-jan.h.kok@intel.com>2007-10-31 18:22:00 -0400
committerDavid S. Miller <davem@davemloft.net>2008-01-28 18:03:43 -0500
commit1eae4eb2a1c784bf35ee4f8f158cd21cf8c387c1 (patch)
tree4e9de1ad1d24b201647376a21862a110e462c831 /drivers/net
parent93ca161027eb6a1761fb674ad7b995aedccf5f6e (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')
-rw-r--r--drivers/net/e1000e/82571.c1
-rw-r--r--drivers/net/e1000e/e1000.h1
-rw-r--r--drivers/net/e1000e/netdev.c30
-rw-r--r--drivers/net/e1000e/param.c7
4 files changed, 30 insertions, 9 deletions
diff --git a/drivers/net/e1000e/82571.c b/drivers/net/e1000e/82571.c
index b6401abc17d..45f5ee29343 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 473f78de4be..8b88c226e85 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 9cc5a6b01bc..5450ef8bf88 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
3512static 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
3513static int e1000_resume(struct pci_dev *pdev) 3540static 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 332789238b9..df266c32ac4 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,