diff options
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; |