mirror of
https://github.com/torvalds/linux.git
synced 2026-05-26 08:02:27 +02:00
Merge branch 'pci/aspm'
- Disable ASPM L1 before touching L1 PM Substates to follow the spec closer and avoid a CPU load timeout on some platforms (Ajay Agarwal) - Set devices below Intel VMD to D0 before enabling ASPM L1 Substates (Jian-Hong Pan) * pci/aspm: PCI: vmd: Set devices to D0 before enabling PM L1 Substates PCI/ASPM: Add notes about enabling PCI-PM L1SS to pci_enable_link_state(_locked) PCI/ASPM: Disable L1 before disabling L1 PM Substates
This commit is contained in:
commit
018247100d
|
|
@ -740,11 +740,9 @@ static int vmd_pm_enable_quirk(struct pci_dev *pdev, void *userdata)
|
|||
if (!(features & VMD_FEAT_BIOS_PM_QUIRK))
|
||||
return 0;
|
||||
|
||||
pci_enable_link_state_locked(pdev, PCIE_LINK_STATE_ALL);
|
||||
|
||||
pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_LTR);
|
||||
if (!pos)
|
||||
return 0;
|
||||
goto out_state_change;
|
||||
|
||||
/*
|
||||
* Skip if the max snoop LTR is non-zero, indicating BIOS has set it
|
||||
|
|
@ -752,7 +750,7 @@ static int vmd_pm_enable_quirk(struct pci_dev *pdev, void *userdata)
|
|||
*/
|
||||
pci_read_config_dword(pdev, pos + PCI_LTR_MAX_SNOOP_LAT, <r_reg);
|
||||
if (!!(ltr_reg & (PCI_LTR_VALUE_MASK | PCI_LTR_SCALE_MASK)))
|
||||
return 0;
|
||||
goto out_state_change;
|
||||
|
||||
/*
|
||||
* Set the default values to the maximum required by the platform to
|
||||
|
|
@ -764,6 +762,13 @@ static int vmd_pm_enable_quirk(struct pci_dev *pdev, void *userdata)
|
|||
pci_write_config_dword(pdev, pos + PCI_LTR_MAX_SNOOP_LAT, ltr_reg);
|
||||
pci_info(pdev, "VMD: Default LTR value set by driver\n");
|
||||
|
||||
out_state_change:
|
||||
/*
|
||||
* Ensure devices are in D0 before enabling PCI-PM L1 PM Substates, per
|
||||
* PCIe r6.0, sec 5.5.4.
|
||||
*/
|
||||
pci_set_power_state_locked(pdev, PCI_D0);
|
||||
pci_enable_link_state_locked(pdev, PCIE_LINK_STATE_ALL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -805,6 +805,15 @@ static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist)
|
|||
pcie_capability_read_word(parent, PCI_EXP_LNKCTL, &parent_lnkctl);
|
||||
pcie_capability_read_word(child, PCI_EXP_LNKCTL, &child_lnkctl);
|
||||
|
||||
/* Disable L0s/L1 before updating L1SS config */
|
||||
if (FIELD_GET(PCI_EXP_LNKCTL_ASPMC, child_lnkctl) ||
|
||||
FIELD_GET(PCI_EXP_LNKCTL_ASPMC, parent_lnkctl)) {
|
||||
pcie_capability_write_word(child, PCI_EXP_LNKCTL,
|
||||
child_lnkctl & ~PCI_EXP_LNKCTL_ASPMC);
|
||||
pcie_capability_write_word(parent, PCI_EXP_LNKCTL,
|
||||
parent_lnkctl & ~PCI_EXP_LNKCTL_ASPMC);
|
||||
}
|
||||
|
||||
/*
|
||||
* Setup L0s state
|
||||
*
|
||||
|
|
@ -829,6 +838,13 @@ static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist)
|
|||
|
||||
aspm_l1ss_init(link);
|
||||
|
||||
/* Restore L0s/L1 if they were enabled */
|
||||
if (FIELD_GET(PCI_EXP_LNKCTL_ASPMC, child_lnkctl) ||
|
||||
FIELD_GET(PCI_EXP_LNKCTL_ASPMC, parent_lnkctl)) {
|
||||
pcie_capability_write_word(parent, PCI_EXP_LNKCTL, parent_lnkctl);
|
||||
pcie_capability_write_word(child, PCI_EXP_LNKCTL, child_lnkctl);
|
||||
}
|
||||
|
||||
/* Save default state */
|
||||
link->aspm_default = link->aspm_enabled;
|
||||
|
||||
|
|
@ -845,43 +861,12 @@ static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist)
|
|||
}
|
||||
}
|
||||
|
||||
/* Configure the ASPM L1 substates */
|
||||
/* Configure the ASPM L1 substates. Caller must disable L1 first. */
|
||||
static void pcie_config_aspm_l1ss(struct pcie_link_state *link, u32 state)
|
||||
{
|
||||
u32 val, enable_req;
|
||||
u32 val;
|
||||
struct pci_dev *child = link->downstream, *parent = link->pdev;
|
||||
|
||||
enable_req = (link->aspm_enabled ^ state) & state;
|
||||
|
||||
/*
|
||||
* Here are the rules specified in the PCIe spec for enabling L1SS:
|
||||
* - When enabling L1.x, enable bit at parent first, then at child
|
||||
* - When disabling L1.x, disable bit at child first, then at parent
|
||||
* - When enabling ASPM L1.x, need to disable L1
|
||||
* (at child followed by parent).
|
||||
* - The ASPM/PCIPM L1.2 must be disabled while programming timing
|
||||
* parameters
|
||||
*
|
||||
* To keep it simple, disable all L1SS bits first, and later enable
|
||||
* what is needed.
|
||||
*/
|
||||
|
||||
/* Disable all L1 substates */
|
||||
pci_clear_and_set_config_dword(child, child->l1ss + PCI_L1SS_CTL1,
|
||||
PCI_L1SS_CTL1_L1SS_MASK, 0);
|
||||
pci_clear_and_set_config_dword(parent, parent->l1ss + PCI_L1SS_CTL1,
|
||||
PCI_L1SS_CTL1_L1SS_MASK, 0);
|
||||
/*
|
||||
* If needed, disable L1, and it gets enabled later
|
||||
* in pcie_config_aspm_link().
|
||||
*/
|
||||
if (enable_req & (PCIE_LINK_STATE_L1_1 | PCIE_LINK_STATE_L1_2)) {
|
||||
pcie_capability_clear_word(child, PCI_EXP_LNKCTL,
|
||||
PCI_EXP_LNKCTL_ASPM_L1);
|
||||
pcie_capability_clear_word(parent, PCI_EXP_LNKCTL,
|
||||
PCI_EXP_LNKCTL_ASPM_L1);
|
||||
}
|
||||
|
||||
val = 0;
|
||||
if (state & PCIE_LINK_STATE_L1_1)
|
||||
val |= PCI_L1SS_CTL1_ASPM_L1_1;
|
||||
|
|
@ -892,6 +877,20 @@ static void pcie_config_aspm_l1ss(struct pcie_link_state *link, u32 state)
|
|||
if (state & PCIE_LINK_STATE_L1_2_PCIPM)
|
||||
val |= PCI_L1SS_CTL1_PCIPM_L1_2;
|
||||
|
||||
/*
|
||||
* PCIe r6.2, sec 5.5.4, rules for enabling L1 PM Substates:
|
||||
* - Clear L1.x enable bits at child first, then at parent
|
||||
* - Set L1.x enable bits at parent first, then at child
|
||||
* - ASPM/PCIPM L1.2 must be disabled while programming timing
|
||||
* parameters
|
||||
*/
|
||||
|
||||
/* Disable all L1 substates */
|
||||
pci_clear_and_set_config_dword(child, child->l1ss + PCI_L1SS_CTL1,
|
||||
PCI_L1SS_CTL1_L1SS_MASK, 0);
|
||||
pci_clear_and_set_config_dword(parent, parent->l1ss + PCI_L1SS_CTL1,
|
||||
PCI_L1SS_CTL1_L1SS_MASK, 0);
|
||||
|
||||
/* Enable what we need to enable */
|
||||
pci_clear_and_set_config_dword(parent, parent->l1ss + PCI_L1SS_CTL1,
|
||||
PCI_L1SS_CTL1_L1SS_MASK, val);
|
||||
|
|
@ -937,21 +936,30 @@ static void pcie_config_aspm_link(struct pcie_link_state *link, u32 state)
|
|||
dwstream |= PCI_EXP_LNKCTL_ASPM_L1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Per PCIe r6.2, sec 5.5.4, setting either or both of the enable
|
||||
* bits for ASPM L1 PM Substates must be done while ASPM L1 is
|
||||
* disabled. Disable L1 here and apply new configuration after L1SS
|
||||
* configuration has been completed.
|
||||
*
|
||||
* Per sec 7.5.3.7, when disabling ASPM L1, software must disable
|
||||
* it in the Downstream component prior to disabling it in the
|
||||
* Upstream component, and ASPM L1 must be enabled in the Upstream
|
||||
* component prior to enabling it in the Downstream component.
|
||||
*
|
||||
* Sec 7.5.3.7 also recommends programming the same ASPM Control
|
||||
* value for all functions of a multi-function device.
|
||||
*/
|
||||
list_for_each_entry(child, &linkbus->devices, bus_list)
|
||||
pcie_config_aspm_dev(child, 0);
|
||||
pcie_config_aspm_dev(parent, 0);
|
||||
|
||||
if (link->aspm_capable & PCIE_LINK_STATE_L1SS)
|
||||
pcie_config_aspm_l1ss(link, state);
|
||||
|
||||
/*
|
||||
* Spec 2.0 suggests all functions should be configured the
|
||||
* same setting for ASPM. Enabling ASPM L1 should be done in
|
||||
* upstream component first and then downstream, and vice
|
||||
* versa for disabling ASPM L1. Spec doesn't mention L0S.
|
||||
*/
|
||||
if (state & PCIE_LINK_STATE_L1)
|
||||
pcie_config_aspm_dev(parent, upstream);
|
||||
pcie_config_aspm_dev(parent, upstream);
|
||||
list_for_each_entry(child, &linkbus->devices, bus_list)
|
||||
pcie_config_aspm_dev(child, dwstream);
|
||||
if (!(state & PCIE_LINK_STATE_L1))
|
||||
pcie_config_aspm_dev(parent, upstream);
|
||||
|
||||
link->aspm_enabled = state;
|
||||
|
||||
|
|
@ -1442,6 +1450,9 @@ static int __pci_enable_link_state(struct pci_dev *pdev, int state, bool locked)
|
|||
* touch the LNKCTL register. Also note that this does not enable states
|
||||
* disabled by pci_disable_link_state(). Return 0 or a negative errno.
|
||||
*
|
||||
* Note: Ensure devices are in D0 before enabling PCI-PM L1 PM Substates, per
|
||||
* PCIe r6.0, sec 5.5.4.
|
||||
*
|
||||
* @pdev: PCI device
|
||||
* @state: Mask of ASPM link states to enable
|
||||
*/
|
||||
|
|
@ -1458,6 +1469,9 @@ EXPORT_SYMBOL(pci_enable_link_state);
|
|||
* can't touch the LNKCTL register. Also note that this does not enable states
|
||||
* disabled by pci_disable_link_state(). Return 0 or a negative errno.
|
||||
*
|
||||
* Note: Ensure devices are in D0 before enabling PCI-PM L1 PM Substates, per
|
||||
* PCIe r6.0, sec 5.5.4.
|
||||
*
|
||||
* @pdev: PCI device
|
||||
* @state: Mask of ASPM link states to enable
|
||||
*
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user