Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 13129d9b authored by Carolyn Wyborny's avatar Carolyn Wyborny Committed by Jeff Kirsher
Browse files

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: default avatarCarolyn Wyborny <carolyn.wyborny@intel.com>
Acked-by: default avatarBruce W. Allan <bruce.w.allan@intel.com>
Tested-by: default avatarPavel Machek <pavel@ucw.cz>
Tested-by: default avatarAaron Brown <aaron.f.brown@intel.com>
Signed-off-by: default avatarJeff Kirsher <jeffrey.t.kirsher@intel.com>
parent 0cf04597
Loading
Loading
Loading
Loading
+59 −26
Original line number Diff line number Diff line
@@ -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);
	struct pci_dev *parent = pdev->bus->self;
	u16 aspm_dis_mask = 0;
	u16 pdev_aspmc, parent_aspmc;

	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;
	}
#else
static void __e1000e_disable_aspm(struct pci_dev *pdev, u16 state)
{
	u16 aspm_ctl = 0;

	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;
	pcie_capability_read_word(pdev, PCI_EXP_LNKCTL, &pdev_aspmc);
	pdev_aspmc &= PCI_EXP_LNKCTL_ASPMC;

	/* Both device and parent should have the same ASPM setting.
	 * Disable ASPM in downstream component first and then upstream.
	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_clear_word(pdev, PCI_EXP_LNKCTL, aspm_ctl);
	pcie_capability_read_word(pdev, PCI_EXP_LNKCTL, &pdev_aspmc);
	pdev_aspmc &= PCI_EXP_LNKCTL_ASPMC;

	if (pdev->bus->self)
		pcie_capability_clear_word(pdev->bus->self, PCI_EXP_LNKCTL,
					   aspm_ctl);
}
	if (!(aspm_dis_mask & pdev_aspmc))
		return;
#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);
	/* 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_dis_mask);

	if (parent)
		pcie_capability_clear_word(parent, PCI_EXP_LNKCTL,
					   aspm_dis_mask);
}

#ifdef CONFIG_PM