e1000e: Disable L1 ASPM power savings for 82573 mobile variants
authorAuke Kok <auke-jan.h.kok@intel.com>
Wed, 31 Oct 2007 22:22:00 +0000 (15:22 -0700)
committerDavid S. Miller <davem@davemloft.net>
Mon, 28 Jan 2008 23:03:43 +0000 (15:03 -0800)
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>
drivers/net/e1000e/82571.c
drivers/net/e1000e/e1000.h
drivers/net/e1000e/netdev.c
drivers/net/e1000e/param.c

index b6401abc17d6d742bbdc2351a0a2f9ac467335d8..45f5ee29343ff36b8926eb6991fae48182c11cfd 100644 (file)
@@ -1343,7 +1343,6 @@ struct e1000_info e1000_82573_info = {
                                  | FLAG_HAS_STATS_ICR_ICT
                                  | FLAG_HAS_SMART_POWER_DOWN
                                  | FLAG_HAS_AMT
-                                 | FLAG_HAS_ASPM
                                  | FLAG_HAS_ERT
                                  | FLAG_HAS_SWSM_ON_LOAD,
        .pba                    = 20,
index 473f78de4be0d0bce40f3ed370a64f77ff692341..8b88c226e8581908f2d19dfec380ed1cff35ae00 100644 (file)
@@ -288,7 +288,6 @@ struct e1000_info {
 #define FLAG_HAS_CTRLEXT_ON_LOAD          (1 << 5)
 #define FLAG_HAS_SWSM_ON_LOAD             (1 << 6)
 #define FLAG_HAS_JUMBO_FRAMES             (1 << 7)
-#define FLAG_HAS_ASPM                     (1 << 8)
 #define FLAG_HAS_STATS_ICR_ICT            (1 << 9)
 #define FLAG_HAS_STATS_PTC_PRC            (1 << 10)
 #define FLAG_HAS_SMART_POWER_DOWN         (1 << 11)
index 9cc5a6b01bc1dcfb73ca17ec11a476e586837951..5450ef8bf881bf535bc4cf0970a35dd7cde7a2f0 100644 (file)
@@ -3509,6 +3509,33 @@ static int e1000_suspend(struct pci_dev *pdev, pm_message_t state)
        return 0;
 }
 
+static void e1000e_disable_l1aspm(struct pci_dev *pdev)
+{
+       int pos;
+       u32 cap;
+       u16 val;
+
+       /*
+        * 82573 workaround - disable L1 ASPM on mobile chipsets
+        *
+        * L1 ASPM on various mobile (ich7) chipsets do not behave properly
+        * resulting in lost data or garbage information on the pci-e link
+        * level. This could result in (false) bad EEPROM checksum errors,
+        * long ping times (up to 2s) or even a system freeze/hang.
+        *
+        * Unfortunately this feature saves about 1W power consumption when
+        * active.
+        */
+       pos = pci_find_capability(pdev, PCI_CAP_ID_EXP);
+       pci_read_config_dword(pdev, pos + PCI_EXP_LNKCAP, &cap);
+       pci_read_config_word(pdev, pos + PCI_EXP_LNKCTL, &val);
+       if (val & 0x2) {
+               dev_warn(&pdev->dev, "Disabling L1 ASPM\n");
+               val &= ~0x2;
+               pci_write_config_word(pdev, pos + PCI_EXP_LNKCTL, val);
+       }
+}
+
 #ifdef CONFIG_PM
 static int e1000_resume(struct pci_dev *pdev)
 {
@@ -3519,6 +3546,7 @@ static int e1000_resume(struct pci_dev *pdev)
 
        pci_set_power_state(pdev, PCI_D0);
        pci_restore_state(pdev);
+       e1000e_disable_l1aspm(pdev);
        err = pci_enable_device(pdev);
        if (err) {
                dev_err(&pdev->dev,
@@ -3619,6 +3647,7 @@ static pci_ers_result_t e1000_io_slot_reset(struct pci_dev *pdev)
        struct e1000_adapter *adapter = netdev_priv(netdev);
        struct e1000_hw *hw = &adapter->hw;
 
+       e1000e_disable_l1aspm(pdev);
        if (pci_enable_device(pdev)) {
                dev_err(&pdev->dev,
                        "Cannot re-enable PCI device after reset.\n");
@@ -3720,6 +3749,7 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
        u16 eeprom_data = 0;
        u16 eeprom_apme_mask = E1000_EEPROM_APME;
 
+       e1000e_disable_l1aspm(pdev);
        err = pci_enable_device(pdev);
        if (err)
                return err;
index 332789238b9c9309a63210877700b021b3c9acfd..df266c32ac4bc022fa6f5b75877e4ebd707315f5 100644 (file)
@@ -262,13 +262,6 @@ void __devinit e1000e_check_options(struct e1000_adapter *adapter)
                                         .max = MAX_RXDELAY } }
                };
 
-               /* modify min and default if 82573 for slow ping w/a,
-                * a value greater than 8 needs to be set for RDTR */
-               if (adapter->flags & FLAG_HAS_ASPM) {
-                       opt.def = 32;
-                       opt.arg.r.min = 8;
-               }
-
                if (num_RxIntDelay > bd) {
                        adapter->rx_int_delay = RxIntDelay[bd];
                        e1000_validate_option(&adapter->rx_int_delay, &opt,