diff options
Diffstat (limited to 'drivers/net/e1000e/netdev.c')
-rw-r--r-- | drivers/net/e1000e/netdev.c | 73 |
1 files changed, 45 insertions, 28 deletions
diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index 5f70c437fa4..2476f8c24c5 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c @@ -4310,6 +4310,14 @@ static int e1000_change_mtu(struct net_device *netdev, int new_mtu) return -EINVAL; } + /* 82573 Errata 17 */ + if (((adapter->hw.mac.type == e1000_82573) || + (adapter->hw.mac.type == e1000_82574)) && + (max_frame > ETH_FRAME_LEN + ETH_FCS_LEN)) { + adapter->flags2 |= FLAG2_DISABLE_ASPM_L1; + e1000e_disable_aspm(adapter->pdev, PCIE_LINK_STATE_L1); + } + while (test_and_set_bit(__E1000_RESETTING, &adapter->state)) msleep(1); /* e1000e_down -> e1000e_reset dependent on max_frame_size & mtu */ @@ -4634,29 +4642,39 @@ static void e1000_complete_shutdown(struct pci_dev *pdev, bool sleep, } } -static void e1000e_disable_l1aspm(struct pci_dev *pdev) +#ifdef CONFIG_PCIEASPM +static void __e1000e_disable_aspm(struct pci_dev *pdev, u16 state) +{ + pci_disable_link_state(pdev, state); +} +#else +static void __e1000e_disable_aspm(struct pci_dev *pdev, u16 state) { int pos; - u16 val; + u16 reg16; /* - * 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. + * Both device and parent should have the same ASPM setting. + * Disable ASPM in downstream component first and then upstream. */ - pos = pci_find_capability(pdev, PCI_CAP_ID_EXP); - 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); - } + pos = pci_pcie_cap(pdev); + pci_read_config_word(pdev, pos + PCI_EXP_LNKCTL, ®16); + reg16 &= ~state; + pci_write_config_word(pdev, pos + PCI_EXP_LNKCTL, reg16); + + pos = pci_pcie_cap(pdev->bus->self); + pci_read_config_word(pdev->bus->self, pos + PCI_EXP_LNKCTL, ®16); + reg16 &= ~state; + pci_write_config_word(pdev->bus->self, pos + PCI_EXP_LNKCTL, reg16); +} +#endif +void e1000e_disable_aspm(struct pci_dev *pdev, u16 state) +{ + dev_info(&pdev->dev, "Disabling ASPM %s %s\n", + (state & PCIE_LINK_STATE_L0S) ? "L0s" : "", + (state & PCIE_LINK_STATE_L1) ? "L1" : ""); + + __e1000e_disable_aspm(pdev, state); } #ifdef CONFIG_PM_OPS @@ -4672,7 +4690,11 @@ static int __e1000_resume(struct pci_dev *pdev) struct e1000_hw *hw = &adapter->hw; u32 err; - e1000e_disable_l1aspm(pdev); + pci_set_power_state(pdev, PCI_D0); + pci_restore_state(pdev); + pci_save_state(pdev); + if (adapter->flags2 & FLAG2_DISABLE_ASPM_L1) + e1000e_disable_aspm(pdev, PCIE_LINK_STATE_L1); e1000e_set_interrupt_capability(adapter); if (netif_running(netdev)) { @@ -4877,7 +4899,8 @@ static pci_ers_result_t e1000_io_slot_reset(struct pci_dev *pdev) int err; pci_ers_result_t result; - e1000e_disable_l1aspm(pdev); + if (adapter->flags2 & FLAG2_DISABLE_ASPM_L1) + e1000e_disable_aspm(pdev, PCIE_LINK_STATE_L1); err = pci_enable_device_mem(pdev); if (err) { dev_err(&pdev->dev, @@ -4971,13 +4994,6 @@ static void e1000_eeprom_checks(struct e1000_adapter *adapter) dev_warn(&adapter->pdev->dev, "Warning: detected DSPD enabled in EEPROM\n"); } - - ret_val = e1000_read_nvm(hw, NVM_INIT_3GIO_3, 1, &buf); - if (!ret_val && (le16_to_cpu(buf) & (3 << 2))) { - /* ASPM enable */ - dev_warn(&adapter->pdev->dev, - "Warning: detected ASPM enabled in EEPROM\n"); - } } static const struct net_device_ops e1000e_netdev_ops = { @@ -5026,7 +5042,8 @@ static int __devinit e1000_probe(struct pci_dev *pdev, u16 eeprom_data = 0; u16 eeprom_apme_mask = E1000_EEPROM_APME; - e1000e_disable_l1aspm(pdev); + if (ei->flags2 & FLAG2_DISABLE_ASPM_L1) + e1000e_disable_aspm(pdev, PCIE_LINK_STATE_L1); err = pci_enable_device_mem(pdev); if (err) |