e1000e: Add code to check for failure of pci_disable_link_state call
This patch attempts to work around a problem found with some systems where the call to pci_diable_link_state_locked() fails. As a result, ASPM is not, in fact, disabled. Changing disable ASPM code to check if state actually is disabled after the call and, if not, try another way to disable it. Signed-off-by: Carolyn Wyborny <carolyn.wyborny@intel.com> Acked-by: Bruce W. Allan <bruce.w.allan@intel.com> Tested-by: Pavel Machek <pavel@ucw.cz> Tested-by: Aaron Brown <aaron.f.brown@intel.com> Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
This commit is contained in:
Родитель
0cf04597b4
Коммит
13129d9b61
|
@ -64,8 +64,6 @@ static int debug = -1;
|
|||
module_param(debug, int, 0);
|
||||
MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
|
||||
|
||||
static void e1000e_disable_aspm(struct pci_dev *pdev, u16 state);
|
||||
|
||||
static const struct e1000_info *e1000_info_tbl[] = {
|
||||
[board_82571] = &e1000_82571_info,
|
||||
[board_82572] = &e1000_82572_info,
|
||||
|
@ -6019,38 +6017,73 @@ static int __e1000_shutdown(struct pci_dev *pdev, bool runtime)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PCIEASPM
|
||||
static void __e1000e_disable_aspm(struct pci_dev *pdev, u16 state)
|
||||
/**
|
||||
* e1000e_disable_aspm - Disable ASPM states
|
||||
* @pdev: pointer to PCI device struct
|
||||
* @state: bit-mask of ASPM states to disable
|
||||
*
|
||||
* Some devices *must* have certain ASPM states disabled per hardware errata.
|
||||
**/
|
||||
static void e1000e_disable_aspm(struct pci_dev *pdev, u16 state)
|
||||
{
|
||||
pci_disable_link_state_locked(pdev, state);
|
||||
}
|
||||
#else
|
||||
static void __e1000e_disable_aspm(struct pci_dev *pdev, u16 state)
|
||||
{
|
||||
u16 aspm_ctl = 0;
|
||||
struct pci_dev *parent = pdev->bus->self;
|
||||
u16 aspm_dis_mask = 0;
|
||||
u16 pdev_aspmc, parent_aspmc;
|
||||
|
||||
if (state & PCIE_LINK_STATE_L0S)
|
||||
aspm_ctl |= PCI_EXP_LNKCTL_ASPM_L0S;
|
||||
if (state & PCIE_LINK_STATE_L1)
|
||||
aspm_ctl |= PCI_EXP_LNKCTL_ASPM_L1;
|
||||
switch (state) {
|
||||
case PCIE_LINK_STATE_L0S:
|
||||
case PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1:
|
||||
aspm_dis_mask |= PCI_EXP_LNKCTL_ASPM_L0S;
|
||||
/* fall-through - can't have L1 without L0s */
|
||||
case PCIE_LINK_STATE_L1:
|
||||
aspm_dis_mask |= PCI_EXP_LNKCTL_ASPM_L1;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
pcie_capability_read_word(pdev, PCI_EXP_LNKCTL, &pdev_aspmc);
|
||||
pdev_aspmc &= PCI_EXP_LNKCTL_ASPMC;
|
||||
|
||||
if (parent) {
|
||||
pcie_capability_read_word(parent, PCI_EXP_LNKCTL,
|
||||
&parent_aspmc);
|
||||
parent_aspmc &= PCI_EXP_LNKCTL_ASPMC;
|
||||
}
|
||||
|
||||
/* Nothing to do if the ASPM states to be disabled already are */
|
||||
if (!(pdev_aspmc & aspm_dis_mask) &&
|
||||
(!parent || !(parent_aspmc & aspm_dis_mask)))
|
||||
return;
|
||||
|
||||
dev_info(&pdev->dev, "Disabling ASPM %s %s\n",
|
||||
(aspm_dis_mask & pdev_aspmc & PCI_EXP_LNKCTL_ASPM_L0S) ?
|
||||
"L0s" : "",
|
||||
(aspm_dis_mask & pdev_aspmc & PCI_EXP_LNKCTL_ASPM_L1) ?
|
||||
"L1" : "");
|
||||
|
||||
#ifdef CONFIG_PCIEASPM
|
||||
pci_disable_link_state_locked(pdev, state);
|
||||
|
||||
/* Double-check ASPM control. If not disabled by the above, the
|
||||
* BIOS is preventing that from happening (or CONFIG_PCIEASPM is
|
||||
* not enabled); override by writing PCI config space directly.
|
||||
*/
|
||||
pcie_capability_read_word(pdev, PCI_EXP_LNKCTL, &pdev_aspmc);
|
||||
pdev_aspmc &= PCI_EXP_LNKCTL_ASPMC;
|
||||
|
||||
if (!(aspm_dis_mask & pdev_aspmc))
|
||||
return;
|
||||
#endif
|
||||
|
||||
/* Both device and parent should have the same ASPM setting.
|
||||
* Disable ASPM in downstream component first and then upstream.
|
||||
*/
|
||||
pcie_capability_clear_word(pdev, PCI_EXP_LNKCTL, aspm_ctl);
|
||||
pcie_capability_clear_word(pdev, PCI_EXP_LNKCTL, aspm_dis_mask);
|
||||
|
||||
if (pdev->bus->self)
|
||||
pcie_capability_clear_word(pdev->bus->self, PCI_EXP_LNKCTL,
|
||||
aspm_ctl);
|
||||
}
|
||||
#endif
|
||||
static 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);
|
||||
if (parent)
|
||||
pcie_capability_clear_word(parent, PCI_EXP_LNKCTL,
|
||||
aspm_dis_mask);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
|
|
Загрузка…
Ссылка в новой задаче