ltr = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_LTR); if (!ltr) return;
save_state = pci_find_saved_ext_cap(dev, PCI_EXT_CAP_ID_LTR); if (!save_state) {
pci_err(dev, "no suspend buffer for LTR; ASPM issues possible after resume\n"); return;
}
/* Some broken devices only support dword access to LTR */
cap = &save_state->cap.data[0];
pci_read_config_dword(dev, ltr + PCI_LTR_MAX_SNOOP_LAT, cap);
}
/* Some broken devices only support dword access to LTR */
cap = &save_state->cap.data[0];
pci_write_config_dword(dev, ltr + PCI_LTR_MAX_SNOOP_LAT, *cap);
}
void pci_configure_aspm_l1ss(struct pci_dev *pdev)
{ int rc;
/* * If this is a Downstream Port, we never restore the L1SS state * directly; we only restore it when we restore the state of the * Upstream Port below it.
*/ if (pcie_downstream_port(pdev) || !parent) return;
if (!pdev->l1ss || !parent->l1ss) return;
/* * Save L1 substate configuration. The ASPM L0s/L1 configuration * in PCI_EXP_LNKCTL_ASPMC is saved by pci_save_pcie_state().
*/
save_state = pci_find_saved_ext_cap(pdev, PCI_EXT_CAP_ID_L1SS); if (!save_state) return;
/* * Save parent's L1 substate configuration so we have it for * pci_restore_aspm_l1ss_state(pdev) to restore.
*/
save_state = pci_find_saved_ext_cap(parent, PCI_EXT_CAP_ID_L1SS); if (!save_state) return;
/* * In case BIOS enabled L1.2 when resuming, we need to disable it first * on the downstream component before the upstream. So, don't attempt to * restore either until we are at the downstream component.
*/ if (pcie_downstream_port(pdev) || !parent) return;
cap = &cl_save_state->cap.data[0];
cl_ctl2 = *cap++;
cl_ctl1 = *cap;
cap = &pl_save_state->cap.data[0];
pl_ctl2 = *cap++;
pl_ctl1 = *cap;
/* Make sure L0s/L1 are disabled before updating L1SS config */
pcie_capability_read_word(pdev, PCI_EXP_LNKCTL, &clnkctl);
pcie_capability_read_word(parent, PCI_EXP_LNKCTL, &plnkctl); if (FIELD_GET(PCI_EXP_LNKCTL_ASPMC, clnkctl) ||
FIELD_GET(PCI_EXP_LNKCTL_ASPMC, plnkctl)) {
pcie_capability_write_word(pdev, PCI_EXP_LNKCTL,
clnkctl & ~PCI_EXP_LNKCTL_ASPMC);
pcie_capability_write_word(parent, PCI_EXP_LNKCTL,
plnkctl & ~PCI_EXP_LNKCTL_ASPMC);
}
/* * Disable L1.2 on this downstream endpoint device first, followed * by the upstream
*/
pci_clear_and_set_config_dword(pdev, pdev->l1ss + PCI_L1SS_CTL1,
PCI_L1SS_CTL1_L1_2_MASK, 0);
pci_clear_and_set_config_dword(parent, parent->l1ss + PCI_L1SS_CTL1,
PCI_L1SS_CTL1_L1_2_MASK, 0);
/* * In addition, Common_Mode_Restore_Time and LTR_L1.2_THRESHOLD * in PCI_L1SS_CTL1 must be programmed *before* setting the L1.2 * enable bits, even though they're all in PCI_L1SS_CTL1.
*/
pl_l1_2_enable = pl_ctl1 & PCI_L1SS_CTL1_L1_2_MASK;
pl_ctl1 &= ~PCI_L1SS_CTL1_L1_2_MASK;
cl_l1_2_enable = cl_ctl1 & PCI_L1SS_CTL1_L1_2_MASK;
cl_ctl1 &= ~PCI_L1SS_CTL1_L1_2_MASK;
/* Write back without enables first (above we cleared them in ctl1) */
pci_write_config_dword(parent, parent->l1ss + PCI_L1SS_CTL2, pl_ctl2);
pci_write_config_dword(pdev, pdev->l1ss + PCI_L1SS_CTL2, cl_ctl2);
pci_write_config_dword(parent, parent->l1ss + PCI_L1SS_CTL1, pl_ctl1);
pci_write_config_dword(pdev, pdev->l1ss + PCI_L1SS_CTL1, cl_ctl1);
/* Then write back the enables */ if (pl_l1_2_enable || cl_l1_2_enable) {
pci_write_config_dword(parent, parent->l1ss + PCI_L1SS_CTL1,
pl_ctl1 | pl_l1_2_enable);
pci_write_config_dword(pdev, pdev->l1ss + PCI_L1SS_CTL1,
cl_ctl1 | cl_l1_2_enable);
}
/* Restore L0s/L1 if they were enabled */ if (FIELD_GET(PCI_EXP_LNKCTL_ASPMC, clnkctl) ||
FIELD_GET(PCI_EXP_LNKCTL_ASPMC, plnkctl)) {
pcie_capability_write_word(parent, PCI_EXP_LNKCTL, plnkctl);
pcie_capability_write_word(pdev, PCI_EXP_LNKCTL, clnkctl);
}
}
/* Note: these are not register definitions */ #define PCIE_LINK_STATE_L0S_UP BIT(0) /* Upstream direction L0s state */ #define PCIE_LINK_STATE_L0S_DW BIT(1) /* Downstream direction L0s state */
static_assert(PCIE_LINK_STATE_L0S == (PCIE_LINK_STATE_L0S_UP | PCIE_LINK_STATE_L0S_DW));
struct pcie_link_state { struct pci_dev *pdev; /* Upstream component of the Link */ struct pci_dev *downstream; /* Downstream component, function 0 */ struct pcie_link_state *root; /* pointer to the root port link */ struct pcie_link_state *parent; /* pointer to the parent Link state */ struct list_head sibling; /* node in link_list */
/* ASPM state */
u32 aspm_support:7; /* Supported ASPM state */
u32 aspm_enabled:7; /* Enabled ASPM state */
u32 aspm_capable:7; /* Capable ASPM state with latency */
u32 aspm_default:7; /* Default ASPM state by BIOS */
u32 aspm_disable:7; /* Disabled ASPM state */
/* Clock PM state */
u32 clkpm_capable:1; /* Clock PM capable? */
u32 clkpm_enabled:1; /* Current Clock PM state */
u32 clkpm_default:1; /* Default Clock PM state by BIOS */
u32 clkpm_disable:1; /* Clock PM disabled */
};
/* * The L1 PM substate capability is only implemented in function 0 in a * multi function device.
*/ staticstruct pci_dev *pci_function_0(struct pci_bus *linkbus)
{ struct pci_dev *child;
/* * Update ASPM and CLKREQ bits of LNKCTL in save_state. We only * write PCI_EXP_LNKCTL_CCC during enumeration, so it shouldn't * change after being captured in save_state.
*/
aspm_ctl = lnkctl & (PCI_EXP_LNKCTL_ASPMC | PCI_EXP_LNKCTL_CLKREQ_EN);
lnkctl &= ~(PCI_EXP_LNKCTL_ASPMC | PCI_EXP_LNKCTL_CLKREQ_EN);
/* Depends on pci_save_pcie_state(): cap[1] is LNKCTL */
cap = (u16 *)&save_state->cap.data[0];
cap[1] = lnkctl | aspm_ctl;
}
staticvoid pcie_set_clkpm(struct pcie_link_state *link, int enable)
{ /* * Don't enable Clock PM if the link is not Clock PM capable * or Clock PM is disabled
*/ if (!link->clkpm_capable || link->clkpm_disable)
enable = 0; /* Need nothing if the specified equals to current state */ if (link->clkpm_enabled == enable) return;
pcie_set_clkpm_nocheck(link, enable);
}
/* All functions should have the same cap and state, take the worst */
list_for_each_entry(child, &linkbus->devices, bus_list) {
pcie_capability_read_dword(child, PCI_EXP_LNKCAP, ®32); if (!(reg32 & PCI_EXP_LNKCAP_CLKPM)) {
capable = 0;
enabled = 0; break;
}
pcie_capability_read_word(child, PCI_EXP_LNKCTL, ®16); if (!(reg16 & PCI_EXP_LNKCTL_CLKREQ_EN))
enabled = 0;
}
link->clkpm_enabled = enabled;
link->clkpm_default = enabled;
link->clkpm_capable = capable;
link->clkpm_disable = blacklist ? 1 : 0;
}
/* * pcie_aspm_configure_common_clock: check if the 2 ends of a link * could use common clock. If they are, configure them to use the * common clock. That will reduce the ASPM state exit latency.
*/ staticvoid pcie_aspm_configure_common_clock(struct pcie_link_state *link)
{ int same_clock = 1;
u16 reg16, ccc, parent_old_ccc, child_old_ccc[8]; struct pci_dev *child, *parent = link->pdev; struct pci_bus *linkbus = parent->subordinate; /* * All functions of a slot should have the same Slot Clock * Configuration, so just check one function
*/
child = list_entry(linkbus->devices.next, struct pci_dev, bus_list);
BUG_ON(!pci_is_pcie(child));
/* Check downstream component if bit Slot Clock Configuration is 1 */
pcie_capability_read_word(child, PCI_EXP_LNKSTA, ®16); if (!(reg16 & PCI_EXP_LNKSTA_SLC))
same_clock = 0;
/* Check upstream component if bit Slot Clock Configuration is 1 */
pcie_capability_read_word(parent, PCI_EXP_LNKSTA, ®16); if (!(reg16 & PCI_EXP_LNKSTA_SLC))
same_clock = 0;
/* Port might be already in common clock mode */
pcie_capability_read_word(parent, PCI_EXP_LNKCTL, ®16);
parent_old_ccc = reg16 & PCI_EXP_LNKCTL_CCC; if (same_clock && (reg16 & PCI_EXP_LNKCTL_CCC)) { bool consistent = true;
list_for_each_entry(child, &linkbus->devices, bus_list) {
pcie_capability_read_word(child, PCI_EXP_LNKCTL,
®16); if (!(reg16 & PCI_EXP_LNKCTL_CCC)) {
consistent = false; break;
}
} if (consistent) return;
pci_info(parent, "ASPM: current common clock configuration is inconsistent, reconfiguring\n");
}
/* Convert L1SS T_pwr encoding to usec */ static u32 calc_l12_pwron(struct pci_dev *pdev, u32 scale, u32 val)
{ switch (scale) { case 0: return val * 2; case 1: return val * 10; case 2: return val * 100;
}
pci_err(pdev, "%s: Invalid T_PwrOn scale: %u\n", __func__, scale); return 0;
}
/* * Encode an LTR_L1.2_THRESHOLD value for the L1 PM Substates Control 1 * register. Ports enter L1.2 when the most recent LTR value is greater * than or equal to LTR_L1.2_THRESHOLD, so we round up to make sure we * don't enter L1.2 too aggressively. * * See PCIe r6.0, sec 5.5.1, 6.18, 7.8.3.3.
*/ staticvoid encode_l12_threshold(u32 threshold_us, u32 *scale, u32 *value)
{
u64 threshold_ns = (u64)threshold_us * NSEC_PER_USEC;
/* * LTR_L1.2_THRESHOLD_Value ("value") is a 10-bit field with max * value of 0x3ff.
*/ if (threshold_ns <= 1 * FIELD_MAX(PCI_L1SS_CTL1_LTR_L12_TH_VALUE)) {
*scale = 0; /* Value times 1ns */
*value = threshold_ns;
} elseif (threshold_ns <= 32 * FIELD_MAX(PCI_L1SS_CTL1_LTR_L12_TH_VALUE)) {
*scale = 1; /* Value times 32ns */
*value = roundup(threshold_ns, 32) / 32;
} elseif (threshold_ns <= 1024 * FIELD_MAX(PCI_L1SS_CTL1_LTR_L12_TH_VALUE)) {
*scale = 2; /* Value times 1024ns */
*value = roundup(threshold_ns, 1024) / 1024;
} elseif (threshold_ns <= 32768 * FIELD_MAX(PCI_L1SS_CTL1_LTR_L12_TH_VALUE)) {
*scale = 3; /* Value times 32768ns */
*value = roundup(threshold_ns, 32768) / 32768;
} elseif (threshold_ns <= 1048576 * FIELD_MAX(PCI_L1SS_CTL1_LTR_L12_TH_VALUE)) {
*scale = 4; /* Value times 1048576ns */
*value = roundup(threshold_ns, 1048576) / 1048576;
} elseif (threshold_ns <= (u64)33554432 * FIELD_MAX(PCI_L1SS_CTL1_LTR_L12_TH_VALUE)) {
*scale = 5; /* Value times 33554432ns */
*value = roundup(threshold_ns, 33554432) / 33554432;
} else {
*scale = 5;
*value = FIELD_MAX(PCI_L1SS_CTL1_LTR_L12_TH_VALUE);
}
}
/* Check upstream direction L0s latency */ if ((link->aspm_capable & PCIE_LINK_STATE_L0S_UP) &&
(latency_up_l0s > acceptable_l0s))
link->aspm_capable &= ~PCIE_LINK_STATE_L0S_UP;
/* Check downstream direction L0s latency */ if ((link->aspm_capable & PCIE_LINK_STATE_L0S_DW) &&
(latency_dw_l0s > acceptable_l0s))
link->aspm_capable &= ~PCIE_LINK_STATE_L0S_DW; /* * Check L1 latency. * Every switch on the path to root complex need 1 * more microsecond for L1. Spec doesn't mention L0s. * * The exit latencies for L1 substates are not advertised * by a device. Since the spec also doesn't mention a way * to determine max latencies introduced by enabling L1 * substates on the components, it is not clear how to do * a L1 substate exit latency check. We assume that the * L1 exit latencies advertised by a device include L1 * substate latencies (and hence do not do any check).
*/
latency = max_t(u32, latency_up_l1, latency_dw_l1); if ((link->aspm_capable & PCIE_LINK_STATE_L1) &&
(latency + l1_switch_latency > acceptable_l1))
link->aspm_capable &= ~PCIE_LINK_STATE_L1;
l1_switch_latency += NSEC_PER_USEC;
/* Choose the greater of the two Port Common_Mode_Restore_Times */
val1 = FIELD_GET(PCI_L1SS_CAP_CM_RESTORE_TIME, parent_l1ss_cap);
val2 = FIELD_GET(PCI_L1SS_CAP_CM_RESTORE_TIME, child_l1ss_cap);
t_common_mode = max(val1, val2);
/* Choose the greater of the two Port T_POWER_ON times */
val1 = FIELD_GET(PCI_L1SS_CAP_P_PWR_ON_VALUE, parent_l1ss_cap);
scale1 = FIELD_GET(PCI_L1SS_CAP_P_PWR_ON_SCALE, parent_l1ss_cap);
val2 = FIELD_GET(PCI_L1SS_CAP_P_PWR_ON_VALUE, child_l1ss_cap);
scale2 = FIELD_GET(PCI_L1SS_CAP_P_PWR_ON_SCALE, child_l1ss_cap);
/* * Set LTR_L1.2_THRESHOLD to the time required to transition the * Link from L0 to L1.2 and back to L0 so we enter L1.2 only if * downstream devices report (via LTR) that they can tolerate at * least that much latency. * * Based on PCIe r3.1, sec 5.5.3.3.1, Figures 5-16 and 5-17, and * Table 5-11. T(POWER_OFF) is at most 2us and T(L1.2) is at * least 4us.
*/
l1_2_threshold = 2 + 4 + t_common_mode + t_power_on;
encode_l12_threshold(l1_2_threshold, &scale, &value);
ctl1 |= FIELD_PREP(PCI_L1SS_CTL1_CM_RESTORE_TIME, t_common_mode) |
FIELD_PREP(PCI_L1SS_CTL1_LTR_L12_TH_VALUE, value) |
FIELD_PREP(PCI_L1SS_CTL1_LTR_L12_TH_SCALE, scale);
/* Some broken devices only support dword access to L1 SS */
pci_read_config_dword(parent, parent->l1ss + PCI_L1SS_CTL1, &pctl1);
pci_read_config_dword(parent, parent->l1ss + PCI_L1SS_CTL2, &pctl2);
pci_read_config_dword(child, child->l1ss + PCI_L1SS_CTL1, &cctl1);
pci_read_config_dword(child, child->l1ss + PCI_L1SS_CTL2, &cctl2);
/* Program T_POWER_ON times in both ports */
pci_write_config_dword(parent, parent->l1ss + PCI_L1SS_CTL2, ctl2);
pci_write_config_dword(child, child->l1ss + PCI_L1SS_CTL2, ctl2);
/* Program Common_Mode_Restore_Time in upstream device */
pci_clear_and_set_config_dword(parent, parent->l1ss + PCI_L1SS_CTL1,
PCI_L1SS_CTL1_CM_RESTORE_TIME, ctl1);
/* Program LTR_L1.2_THRESHOLD time in both ports */
pci_clear_and_set_config_dword(parent, parent->l1ss + PCI_L1SS_CTL1,
PCI_L1SS_CTL1_LTR_L12_TH_VALUE |
PCI_L1SS_CTL1_LTR_L12_TH_SCALE,
ctl1);
pci_clear_and_set_config_dword(child, child->l1ss + PCI_L1SS_CTL1,
PCI_L1SS_CTL1_LTR_L12_TH_VALUE |
PCI_L1SS_CTL1_LTR_L12_TH_SCALE,
ctl1);
if (!(parent_l1ss_cap & PCI_L1SS_CAP_L1_PM_SS))
parent_l1ss_cap = 0; if (!(child_l1ss_cap & PCI_L1SS_CAP_L1_PM_SS))
child_l1ss_cap = 0;
/* * If we don't have LTR for the entire path from the Root Complex * to this device, we can't use ASPM L1.2 because it relies on the * LTR_L1.2_THRESHOLD. See PCIe r4.0, secs 5.5.4, 6.18.
*/ if (!child->ltr_path)
child_l1ss_cap &= ~PCI_L1SS_CAP_ASPM_L1_2;
if (parent_l1ss_cap & child_l1ss_cap & PCI_L1SS_CAP_ASPM_L1_1)
link->aspm_support |= PCIE_LINK_STATE_L1_1; if (parent_l1ss_cap & child_l1ss_cap & PCI_L1SS_CAP_ASPM_L1_2)
link->aspm_support |= PCIE_LINK_STATE_L1_2; if (parent_l1ss_cap & child_l1ss_cap & PCI_L1SS_CAP_PCIPM_L1_1)
link->aspm_support |= PCIE_LINK_STATE_L1_1_PCIPM; if (parent_l1ss_cap & child_l1ss_cap & PCI_L1SS_CAP_PCIPM_L1_2)
link->aspm_support |= PCIE_LINK_STATE_L1_2_PCIPM;
if (parent_l1ss_cap)
pci_read_config_dword(parent, parent->l1ss + PCI_L1SS_CTL1,
&parent_l1ss_ctl1); if (child_l1ss_cap)
pci_read_config_dword(child, child->l1ss + PCI_L1SS_CTL1,
&child_l1ss_ctl1);
if (parent_l1ss_ctl1 & child_l1ss_ctl1 & PCI_L1SS_CTL1_ASPM_L1_1)
link->aspm_enabled |= PCIE_LINK_STATE_L1_1; if (parent_l1ss_ctl1 & child_l1ss_ctl1 & PCI_L1SS_CTL1_ASPM_L1_2)
link->aspm_enabled |= PCIE_LINK_STATE_L1_2; if (parent_l1ss_ctl1 & child_l1ss_ctl1 & PCI_L1SS_CTL1_PCIPM_L1_1)
link->aspm_enabled |= PCIE_LINK_STATE_L1_1_PCIPM; if (parent_l1ss_ctl1 & child_l1ss_ctl1 & PCI_L1SS_CTL1_PCIPM_L1_2)
link->aspm_enabled |= PCIE_LINK_STATE_L1_2_PCIPM;
if (link->aspm_support & PCIE_LINK_STATE_L1_2_MASK)
aspm_calc_l12_info(link, parent_l1ss_cap, child_l1ss_cap);
}
if (blacklist) { /* Set enabled/disable so that we will disable ASPM later */
link->aspm_enabled = PCIE_LINK_STATE_ASPM_ALL;
link->aspm_disable = PCIE_LINK_STATE_ASPM_ALL; return;
}
/* * If ASPM not supported, don't mess with the clocks and link, * bail out now.
*/
pcie_capability_read_dword(parent, PCI_EXP_LNKCAP, &parent_lnkcap);
pcie_capability_read_dword(child, PCI_EXP_LNKCAP, &child_lnkcap); if (!(parent_lnkcap & child_lnkcap & PCI_EXP_LNKCAP_ASPMS)) return;
/* Configure common clock before checking latencies */
pcie_aspm_configure_common_clock(link);
/* * Re-read upstream/downstream components' register state after * clock configuration. L0s & L1 exit latencies in the otherwise * read-only Link Capabilities may change depending on common clock * configuration (PCIe r5.0, sec 7.5.3.6).
*/
pcie_capability_read_dword(parent, PCI_EXP_LNKCAP, &parent_lnkcap);
pcie_capability_read_dword(child, PCI_EXP_LNKCAP, &child_lnkcap);
pcie_capability_read_word(parent, PCI_EXP_LNKCTL, &parent_lnkctl);
pcie_capability_read_word(child, PCI_EXP_LNKCTL, &child_lnkctl);
/* * Setup L0s state * * Note that we must not enable L0s in either direction on a * given link unless components on both sides of the link each * support L0s.
*/ if (parent_lnkcap & child_lnkcap & PCI_EXP_LNKCAP_ASPM_L0S)
link->aspm_support |= PCIE_LINK_STATE_L0S;
if (child_lnkctl & PCI_EXP_LNKCTL_ASPM_L0S)
link->aspm_enabled |= PCIE_LINK_STATE_L0S_UP; if (parent_lnkctl & PCI_EXP_LNKCTL_ASPM_L0S)
link->aspm_enabled |= PCIE_LINK_STATE_L0S_DW;
/* Setup L1 state */ if (parent_lnkcap & child_lnkcap & PCI_EXP_LNKCAP_ASPM_L1)
link->aspm_support |= PCIE_LINK_STATE_L1;
if (parent_lnkctl & child_lnkctl & PCI_EXP_LNKCTL_ASPM_L1)
link->aspm_enabled |= PCIE_LINK_STATE_L1;
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;
/* Setup initial capable state. Will be updated later */
link->aspm_capable = link->aspm_support;
/* Get and check endpoint acceptable latencies */
list_for_each_entry(child, &linkbus->devices, bus_list) { if (pci_pcie_type(child) != PCI_EXP_TYPE_ENDPOINT &&
pci_pcie_type(child) != PCI_EXP_TYPE_LEG_END) continue;
if (state & PCIE_LINK_STATE_L1_1)
val |= PCI_L1SS_CTL1_ASPM_L1_1; if (state & PCIE_LINK_STATE_L1_2)
val |= PCI_L1SS_CTL1_ASPM_L1_2; if (state & PCIE_LINK_STATE_L1_1_PCIPM)
val |= PCI_L1SS_CTL1_PCIPM_L1_1; 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
*/
/* Enable only the states that were not explicitly disabled */
state &= (link->aspm_capable & ~link->aspm_disable);
/* Can't enable any substates if L1 is not enabled */ if (!(state & PCIE_LINK_STATE_L1))
state &= ~PCIE_LINK_STATE_L1SS;
/* Spec says both ports must be in D0 before enabling PCI PM substates*/ if (parent->current_state != PCI_D0 || child->current_state != PCI_D0) {
state &= ~PCIE_LINK_STATE_L1_SS_PCIPM;
state |= (link->aspm_enabled & PCIE_LINK_STATE_L1_SS_PCIPM);
}
/* Nothing to do if the link is already in the requested state */ if (link->aspm_enabled == state) return; /* Convert ASPM state to upstream/downstream ASPM register state */ if (state & PCIE_LINK_STATE_L0S_UP)
dwstream |= PCI_EXP_LNKCTL_ASPM_L0S; if (state & PCIE_LINK_STATE_L0S_DW)
upstream |= PCI_EXP_LNKCTL_ASPM_L0S; if (state & PCIE_LINK_STATE_L1) {
upstream |= PCI_EXP_LNKCTL_ASPM_L1;
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);
/* * Some functions in a slot might not all be PCIe functions, * very strange. Disable ASPM for the whole slot
*/
list_for_each_entry(child, &pdev->subordinate->devices, bus_list) { if (!pci_is_pcie(child)) return -EINVAL;
/* * If ASPM is disabled then we're not going to change * the BIOS state. It's safe to continue even if it's a * pre-1.1 device
*/
if (aspm_disabled) continue;
/* * Disable ASPM for pre-1.1 PCIe device, we follow MS to use * RBER bit to determine if a function is 1.1 version device
*/
pcie_capability_read_dword(child, PCI_EXP_DEVCAP, ®32); if (!(reg32 & PCI_EXP_DEVCAP_RBER) && !aspm_force) {
pci_info(child, "disabling ASPM on pre-1.1 PCIe device. You can enable it with 'pcie_aspm=force'\n"); return -EINVAL;
}
} return 0;
}
/* * Root Ports and PCI/PCI-X to PCIe Bridges are roots of PCIe * hierarchies. Note that some PCIe host implementations omit * the root ports entirely, in which case a downstream port on * a switch may become the root of the link state chain for all * its subordinate endpoints.
*/ if (pci_pcie_type(pdev) == PCI_EXP_TYPE_ROOT_PORT ||
pci_pcie_type(pdev) == PCI_EXP_TYPE_PCIE_BRIDGE ||
!pdev->bus->parent->self) {
link->root = link;
} else { struct pcie_link_state *parent;
parent = pdev->bus->parent->self->link_state; if (!parent) {
kfree(link); return NULL;
}
/* * pcie_aspm_init_link_state: Initiate PCI express link state. * It is called after the pcie and its children devices are scanned. * @pdev: the root port or switch downstream port
*/ void pcie_aspm_init_link_state(struct pci_dev *pdev)
{ struct pcie_link_state *link; int blacklist = !!pcie_aspm_sanity_check(pdev);
if (!aspm_support_enabled) return;
if (pdev->link_state) return;
/* * We allocate pcie_link_state for the component on the upstream * end of a Link, so there's nothing to do unless this device is * downstream port.
*/ if (!pcie_downstream_port(pdev)) return;
/* VIA has a strange chipset, root port is under a bridge */ if (pci_pcie_type(pdev) == PCI_EXP_TYPE_ROOT_PORT &&
pdev->bus->self) return;
down_read(&pci_bus_sem); if (list_empty(&pdev->subordinate->devices)) goto out;
mutex_lock(&aspm_lock);
link = alloc_pcie_link_state(pdev); if (!link) goto unlock; /* * Setup initial ASPM state. Note that we need to configure * upstream links also because capable state of them can be * update through pcie_aspm_cap_init().
*/
pcie_aspm_cap_init(link, blacklist);
/* Setup initial Clock PM state */
pcie_clkpm_cap_init(link, blacklist);
/* * At this stage drivers haven't had an opportunity to change the * link policy setting. Enabling ASPM on broken hardware can cripple * it even before the driver has had a chance to disable ASPM, so * default to a safe level right now. If we're enabling ASPM beyond * the BIOS's expectation, we'll do so once pci_enable_device() is * called.
*/ if (aspm_policy != POLICY_POWERSAVE &&
aspm_policy != POLICY_POWER_SUPERSAVE) {
pcie_config_aspm_path(link);
pcie_set_clkpm(link, policy_to_clkpm_state(link));
}
pcie_capability_read_dword(pdev, PCI_EXP_DEVCAP2, &cap); if (!(cap & PCI_EXP_DEVCAP2_LTR)) return;
pcie_capability_read_dword(pdev, PCI_EXP_DEVCTL2, &ctl); if (ctl & PCI_EXP_DEVCTL2_LTR_EN) { if (pci_pcie_type(pdev) == PCI_EXP_TYPE_ROOT_PORT) {
pdev->ltr_path = 1; return;
}
bridge = pci_upstream_bridge(pdev); if (bridge && bridge->ltr_path)
pdev->ltr_path = 1;
return;
}
if (!host->native_ltr) return;
/* * Software must not enable LTR in an Endpoint unless the Root * Complex and all intermediate Switches indicate support for LTR. * PCIe r4.0, sec 6.18.
*/ if (pci_pcie_type(pdev) == PCI_EXP_TYPE_ROOT_PORT) {
pcie_capability_set_word(pdev, PCI_EXP_DEVCTL2,
PCI_EXP_DEVCTL2_LTR_EN);
pdev->ltr_path = 1; return;
}
/* * If we're configuring a hot-added device, LTR was likely * disabled in the upstream bridge, so re-enable it before enabling * it in the new device.
*/
bridge = pci_upstream_bridge(pdev); if (bridge && bridge->ltr_path) {
pci_bridge_reconfigure_ltr(pdev);
pcie_capability_set_word(pdev, PCI_EXP_DEVCTL2,
PCI_EXP_DEVCTL2_LTR_EN);
pdev->ltr_path = 1;
}
}
/* Recheck latencies and update aspm_capable for links under the root */ staticvoid pcie_update_aspm_capable(struct pcie_link_state *root)
{ struct pcie_link_state *link;
BUG_ON(root->parent);
list_for_each_entry(link, &link_list, sibling) { if (link->root != root) continue;
link->aspm_capable = link->aspm_support;
}
list_for_each_entry(link, &link_list, sibling) { struct pci_dev *child; struct pci_bus *linkbus = link->pdev->subordinate; if (link->root != root) continue;
list_for_each_entry(child, &linkbus->devices, bus_list) { if ((pci_pcie_type(child) != PCI_EXP_TYPE_ENDPOINT) &&
(pci_pcie_type(child) != PCI_EXP_TYPE_LEG_END)) continue;
pcie_aspm_check_latency(child);
}
}
}
link = parent->link_state;
root = link->root;
parent_link = link->parent;
/* * Free the parent link state, no later than function 0 (i.e. * link->downstream) being removed. * * Do not free the link state any earlier. If function 0 is a * switch upstream port, this link state is parent_link to all * subordinate ones.
*/ if (pdev != link->downstream) goto out;
/* * @pdev: the root port or switch downstream port * @locked: whether pci_bus_sem is held
*/ void pcie_aspm_pm_state_change(struct pci_dev *pdev, bool locked)
{ struct pcie_link_state *link = pdev->link_state;
if (aspm_disabled || !link) return; /* * Devices changed PM state, we should recheck if latency * meets all functions' requirement
*/ if (!locked)
down_read(&pci_bus_sem);
mutex_lock(&aspm_lock);
pcie_update_aspm_capable(link->root);
pcie_config_aspm_path(link);
mutex_unlock(&aspm_lock); if (!locked)
up_read(&pci_bus_sem);
}
if (!link) return -EINVAL; /* * A driver requested that ASPM be disabled on this device, but * if we don't have permission to manage ASPM (e.g., on ACPI * systems we have to observe the FADT ACPI_FADT_NO_ASPM bit and * the _OSC method), we can't honor that request. Windows has * a similar mechanism using "PciASPMOptOut", which is also * ignored in this situation.
*/ if (aspm_disabled) {
pci_warn(pdev, "can't disable ASPM; OS doesn't have ASPM control\n"); return -EPERM;
}
if (!locked)
down_read(&pci_bus_sem);
mutex_lock(&aspm_lock);
link->aspm_disable |= pci_calc_aspm_disable_mask(state);
pcie_config_aspm_link(link, policy_to_aspm_state(link));
if (state & PCIE_LINK_STATE_CLKPM)
link->clkpm_disable = 1;
pcie_set_clkpm(link, policy_to_clkpm_state(link));
mutex_unlock(&aspm_lock); if (!locked)
up_read(&pci_bus_sem);
return 0;
}
int pci_disable_link_state_locked(struct pci_dev *pdev, int state)
{
lockdep_assert_held_read(&pci_bus_sem);
/** * pci_disable_link_state - Disable device's link state, so the link will * never enter specific states. Note that if the BIOS didn't grant ASPM * control to the OS, this does nothing because we can't touch the LNKCTL * register. Returns 0 or a negative errno. * * @pdev: PCI device * @state: ASPM link state to disable
*/ int pci_disable_link_state(struct pci_dev *pdev, int state)
{ return __pci_disable_link_state(pdev, state, false);
}
EXPORT_SYMBOL(pci_disable_link_state);
if (!link) return -EINVAL; /* * A driver requested that ASPM be enabled on this device, but * if we don't have permission to manage ASPM (e.g., on ACPI * systems we have to observe the FADT ACPI_FADT_NO_ASPM bit and * the _OSC method), we can't honor that request.
*/ if (aspm_disabled) {
pci_warn(pdev, "can't override BIOS ASPM; OS doesn't have ASPM control\n"); return -EPERM;
}
if (!locked)
down_read(&pci_bus_sem);
mutex_lock(&aspm_lock);
link->aspm_default = pci_calc_aspm_enable_mask(state);
pcie_config_aspm_link(link, policy_to_aspm_state(link));
/** * pci_enable_link_state - Clear and set the default device link state so that * the link may be allowed to enter the specified states. Note that if the * BIOS didn't grant ASPM control to the OS, this does nothing because we 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
*/ int pci_enable_link_state(struct pci_dev *pdev, int state)
{ return __pci_enable_link_state(pdev, state, false);
}
EXPORT_SYMBOL(pci_enable_link_state);
/** * pci_enable_link_state_locked - Clear and set the default device link state * so that the link may be allowed to enter the specified states. Note that if * the BIOS didn't grant ASPM control to the OS, this does nothing because we * 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 * * Context: Caller holds pci_bus_sem read lock.
*/ int pci_enable_link_state_locked(struct pci_dev *pdev, int state)
{
lockdep_assert_held_read(&pci_bus_sem);
/** * pcie_aspm_enabled - Check if PCIe ASPM has been enabled for a device. * @pdev: Target device. * * Relies on the upstream bridge's link_state being valid. The link_state * is deallocated only when the last child of the bridge (i.e., @pdev or a * sibling) is removed, and the caller should be holding a reference to * @pdev, so this should be safe.
*/ bool pcie_aspm_enabled(struct pci_dev *pdev)
{ struct pcie_link_state *link = pcie_aspm_get_link(pdev);
void pcie_no_aspm(void)
{ /* * Disabling ASPM is intended to prevent the kernel from modifying * existing hardware state, not to clear existing state. To that end: * (a) set policy to POLICY_DEFAULT in order to avoid changing state * (b) prevent userspace from changing policy
*/ if (!aspm_force) {
aspm_policy = POLICY_DEFAULT;
aspm_disabled = true;
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.