mirror of
https://github.com/torvalds/linux.git
synced 2026-05-27 16:44:58 +02:00
Merge branch 'pci/aspm'
- Collect ASPM-related code into aspm.c (David E. Box) - Save and restore ASPM L1 PM Substates configuration so these states continue working after suspend/resume (David E. Box) - Move the ASPM L1.2-related LTR save/restore next to the ASPM save/restore (David E. Box) - Move the required L1 disable before L1 Substate configuration into pci_restore_aspm_l1ss_state() (Bjorn Helgaas) - Update save_save when ASPM config is changed, so a .slot_reset() during error recovery restores the changed config, not the .probe()-time config (Vidya Sagar) * pci/aspm: PCI/ASPM: Update save_state when configuration changes PCI/ASPM: Disable L1 before configuring L1 Substates PCI/ASPM: Call pci_save_ltr_state() from pci_save_pcie_state() PCI/ASPM: Save L1 PM Substates Capability for suspend/resume PCI/ASPM: Move pci_save_ltr_state() to aspm.c PCI/ASPM: Always build aspm.c PCI/ASPM: Move pci_configure_ltr() to aspm.c
This commit is contained in:
commit
239981b669
|
|
@ -1651,33 +1651,25 @@ static int pci_save_pcie_state(struct pci_dev *dev)
|
|||
pcie_capability_read_word(dev, PCI_EXP_LNKCTL2, &cap[i++]);
|
||||
pcie_capability_read_word(dev, PCI_EXP_SLTCTL2, &cap[i++]);
|
||||
|
||||
pci_save_aspm_l1ss_state(dev);
|
||||
pci_save_ltr_state(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void pci_bridge_reconfigure_ltr(struct pci_dev *dev)
|
||||
{
|
||||
#ifdef CONFIG_PCIEASPM
|
||||
struct pci_dev *bridge;
|
||||
u32 ctl;
|
||||
|
||||
bridge = pci_upstream_bridge(dev);
|
||||
if (bridge && bridge->ltr_path) {
|
||||
pcie_capability_read_dword(bridge, PCI_EXP_DEVCTL2, &ctl);
|
||||
if (!(ctl & PCI_EXP_DEVCTL2_LTR_EN)) {
|
||||
pci_dbg(bridge, "re-enabling LTR\n");
|
||||
pcie_capability_set_word(bridge, PCI_EXP_DEVCTL2,
|
||||
PCI_EXP_DEVCTL2_LTR_EN);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void pci_restore_pcie_state(struct pci_dev *dev)
|
||||
{
|
||||
int i = 0;
|
||||
struct pci_cap_saved_state *save_state;
|
||||
u16 *cap;
|
||||
|
||||
/*
|
||||
* Restore max latencies (in the LTR capability) before enabling
|
||||
* LTR itself in PCI_EXP_DEVCTL2.
|
||||
*/
|
||||
pci_restore_ltr_state(dev);
|
||||
pci_restore_aspm_l1ss_state(dev);
|
||||
|
||||
save_state = pci_find_saved_cap(dev, PCI_CAP_ID_EXP);
|
||||
if (!save_state)
|
||||
return;
|
||||
|
|
@ -1735,46 +1727,6 @@ static void pci_restore_pcix_state(struct pci_dev *dev)
|
|||
pci_write_config_word(dev, pos + PCI_X_CMD, cap[i++]);
|
||||
}
|
||||
|
||||
static void pci_save_ltr_state(struct pci_dev *dev)
|
||||
{
|
||||
int ltr;
|
||||
struct pci_cap_saved_state *save_state;
|
||||
u32 *cap;
|
||||
|
||||
if (!pci_is_pcie(dev))
|
||||
return;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static void pci_restore_ltr_state(struct pci_dev *dev)
|
||||
{
|
||||
struct pci_cap_saved_state *save_state;
|
||||
int ltr;
|
||||
u32 *cap;
|
||||
|
||||
save_state = pci_find_saved_ext_cap(dev, PCI_EXT_CAP_ID_LTR);
|
||||
ltr = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_LTR);
|
||||
if (!save_state || !ltr)
|
||||
return;
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* pci_save_state - save the PCI configuration space of a device before
|
||||
* suspending
|
||||
|
|
@ -1799,7 +1751,6 @@ int pci_save_state(struct pci_dev *dev)
|
|||
if (i != 0)
|
||||
return i;
|
||||
|
||||
pci_save_ltr_state(dev);
|
||||
pci_save_dpc_state(dev);
|
||||
pci_save_aer_state(dev);
|
||||
pci_save_ptm_state(dev);
|
||||
|
|
@ -1900,12 +1851,6 @@ void pci_restore_state(struct pci_dev *dev)
|
|||
if (!dev->state_saved)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Restore max latencies (in the LTR capability) before enabling
|
||||
* LTR itself (in the PCIe capability).
|
||||
*/
|
||||
pci_restore_ltr_state(dev);
|
||||
|
||||
pci_restore_pcie_state(dev);
|
||||
pci_restore_pasid_state(dev);
|
||||
pci_restore_pri_state(dev);
|
||||
|
|
|
|||
|
|
@ -97,7 +97,6 @@ void pci_msi_init(struct pci_dev *dev);
|
|||
void pci_msix_init(struct pci_dev *dev);
|
||||
bool pci_bridge_d3_possible(struct pci_dev *dev);
|
||||
void pci_bridge_d3_update(struct pci_dev *dev);
|
||||
void pci_bridge_reconfigure_ltr(struct pci_dev *dev);
|
||||
int pci_bridge_wait_for_secondary_bus(struct pci_dev *dev, char *reset_type);
|
||||
|
||||
static inline void pci_wakeup_event(struct pci_dev *dev)
|
||||
|
|
@ -568,16 +567,28 @@ pci_ers_result_t pcie_do_recovery(struct pci_dev *dev,
|
|||
|
||||
bool pcie_wait_for_link(struct pci_dev *pdev, bool active);
|
||||
int pcie_retrain_link(struct pci_dev *pdev, bool use_lt);
|
||||
|
||||
/* ASPM-related functionality we need even without CONFIG_PCIEASPM */
|
||||
void pci_save_ltr_state(struct pci_dev *dev);
|
||||
void pci_restore_ltr_state(struct pci_dev *dev);
|
||||
void pci_configure_aspm_l1ss(struct pci_dev *dev);
|
||||
void pci_save_aspm_l1ss_state(struct pci_dev *dev);
|
||||
void pci_restore_aspm_l1ss_state(struct pci_dev *dev);
|
||||
|
||||
#ifdef CONFIG_PCIEASPM
|
||||
void pcie_aspm_init_link_state(struct pci_dev *pdev);
|
||||
void pcie_aspm_exit_link_state(struct pci_dev *pdev);
|
||||
void pcie_aspm_pm_state_change(struct pci_dev *pdev);
|
||||
void pcie_aspm_powersave_config_link(struct pci_dev *pdev);
|
||||
void pci_configure_ltr(struct pci_dev *pdev);
|
||||
void pci_bridge_reconfigure_ltr(struct pci_dev *pdev);
|
||||
#else
|
||||
static inline void pcie_aspm_init_link_state(struct pci_dev *pdev) { }
|
||||
static inline void pcie_aspm_exit_link_state(struct pci_dev *pdev) { }
|
||||
static inline void pcie_aspm_pm_state_change(struct pci_dev *pdev) { }
|
||||
static inline void pcie_aspm_powersave_config_link(struct pci_dev *pdev) { }
|
||||
static inline void pci_configure_ltr(struct pci_dev *pdev) { }
|
||||
static inline void pci_bridge_reconfigure_ltr(struct pci_dev *pdev) { }
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PCIE_ECRC
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ pcieportdrv-y := portdrv.o rcec.o
|
|||
|
||||
obj-$(CONFIG_PCIEPORTBUS) += pcieportdrv.o
|
||||
|
||||
obj-$(CONFIG_PCIEASPM) += aspm.o
|
||||
obj-y += aspm.o
|
||||
obj-$(CONFIG_PCIEAER) += aer.o err.o
|
||||
obj-$(CONFIG_PCIEAER_INJECT) += aer_inject.o
|
||||
obj-$(CONFIG_PCIE_PME) += pme.o
|
||||
|
|
|
|||
|
|
@ -24,6 +24,166 @@
|
|||
|
||||
#include "../pci.h"
|
||||
|
||||
void pci_save_ltr_state(struct pci_dev *dev)
|
||||
{
|
||||
int ltr;
|
||||
struct pci_cap_saved_state *save_state;
|
||||
u32 *cap;
|
||||
|
||||
if (!pci_is_pcie(dev))
|
||||
return;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void pci_restore_ltr_state(struct pci_dev *dev)
|
||||
{
|
||||
struct pci_cap_saved_state *save_state;
|
||||
int ltr;
|
||||
u32 *cap;
|
||||
|
||||
save_state = pci_find_saved_ext_cap(dev, PCI_EXT_CAP_ID_LTR);
|
||||
ltr = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_LTR);
|
||||
if (!save_state || !ltr)
|
||||
return;
|
||||
|
||||
/* 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;
|
||||
|
||||
pdev->l1ss = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_L1SS);
|
||||
|
||||
rc = pci_add_ext_cap_save_buffer(pdev, PCI_EXT_CAP_ID_L1SS,
|
||||
2 * sizeof(u32));
|
||||
if (rc)
|
||||
pci_err(pdev, "unable to allocate ASPM L1SS save buffer (%pe)\n",
|
||||
ERR_PTR(rc));
|
||||
}
|
||||
|
||||
void pci_save_aspm_l1ss_state(struct pci_dev *pdev)
|
||||
{
|
||||
struct pci_cap_saved_state *save_state;
|
||||
u16 l1ss = pdev->l1ss;
|
||||
u32 *cap;
|
||||
|
||||
/*
|
||||
* Save L1 substate configuration. The ASPM L0s/L1 configuration
|
||||
* in PCI_EXP_LNKCTL_ASPMC is saved by pci_save_pcie_state().
|
||||
*/
|
||||
if (!l1ss)
|
||||
return;
|
||||
|
||||
save_state = pci_find_saved_ext_cap(pdev, PCI_EXT_CAP_ID_L1SS);
|
||||
if (!save_state)
|
||||
return;
|
||||
|
||||
cap = &save_state->cap.data[0];
|
||||
pci_read_config_dword(pdev, l1ss + PCI_L1SS_CTL2, cap++);
|
||||
pci_read_config_dword(pdev, l1ss + PCI_L1SS_CTL1, cap++);
|
||||
}
|
||||
|
||||
void pci_restore_aspm_l1ss_state(struct pci_dev *pdev)
|
||||
{
|
||||
struct pci_cap_saved_state *pl_save_state, *cl_save_state;
|
||||
struct pci_dev *parent = pdev->bus->self;
|
||||
u32 *cap, pl_ctl1, pl_ctl2, pl_l1_2_enable;
|
||||
u32 cl_ctl1, cl_ctl2, cl_l1_2_enable;
|
||||
u16 clnkctl, plnkctl;
|
||||
|
||||
/*
|
||||
* 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;
|
||||
|
||||
if (!pdev->l1ss || !parent->l1ss)
|
||||
return;
|
||||
|
||||
cl_save_state = pci_find_saved_ext_cap(pdev, PCI_EXT_CAP_ID_L1SS);
|
||||
pl_save_state = pci_find_saved_ext_cap(parent, PCI_EXT_CAP_ID_L1SS);
|
||||
if (!cl_save_state || !pl_save_state)
|
||||
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, clnkctl);
|
||||
pcie_capability_write_word(pdev, PCI_EXP_LNKCTL, plnkctl);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PCIEASPM
|
||||
|
||||
#ifdef MODULE_PARAM_PREFIX
|
||||
#undef MODULE_PARAM_PREFIX
|
||||
#endif
|
||||
|
|
@ -141,16 +301,42 @@ static int policy_to_clkpm_state(struct pcie_link_state *link)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void pci_update_aspm_saved_state(struct pci_dev *dev)
|
||||
{
|
||||
struct pci_cap_saved_state *save_state;
|
||||
u16 *cap, lnkctl, aspm_ctl;
|
||||
|
||||
save_state = pci_find_saved_cap(dev, PCI_CAP_ID_EXP);
|
||||
if (!save_state)
|
||||
return;
|
||||
|
||||
pcie_capability_read_word(dev, PCI_EXP_LNKCTL, &lnkctl);
|
||||
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
static void pcie_set_clkpm_nocheck(struct pcie_link_state *link, int enable)
|
||||
{
|
||||
struct pci_dev *child;
|
||||
struct pci_bus *linkbus = link->pdev->subordinate;
|
||||
u32 val = enable ? PCI_EXP_LNKCTL_CLKREQ_EN : 0;
|
||||
|
||||
list_for_each_entry(child, &linkbus->devices, bus_list)
|
||||
list_for_each_entry(child, &linkbus->devices, bus_list) {
|
||||
pcie_capability_clear_and_set_word(child, PCI_EXP_LNKCTL,
|
||||
PCI_EXP_LNKCTL_CLKREQ_EN,
|
||||
val);
|
||||
pci_update_aspm_saved_state(child);
|
||||
}
|
||||
link->clkpm_enabled = !!enable;
|
||||
}
|
||||
|
||||
|
|
@ -769,6 +955,12 @@ static void pcie_config_aspm_link(struct pcie_link_state *link, u32 state)
|
|||
pcie_config_aspm_dev(parent, upstream);
|
||||
|
||||
link->aspm_enabled = state;
|
||||
|
||||
/* Update latest ASPM configuration in saved context */
|
||||
pci_save_aspm_l1ss_state(link->downstream);
|
||||
pci_update_aspm_saved_state(link->downstream);
|
||||
pci_save_aspm_l1ss_state(parent);
|
||||
pci_update_aspm_saved_state(parent);
|
||||
}
|
||||
|
||||
static void pcie_config_aspm_path(struct pcie_link_state *link)
|
||||
|
|
@ -938,6 +1130,78 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev)
|
|||
up_read(&pci_bus_sem);
|
||||
}
|
||||
|
||||
void pci_bridge_reconfigure_ltr(struct pci_dev *pdev)
|
||||
{
|
||||
struct pci_dev *bridge;
|
||||
u32 ctl;
|
||||
|
||||
bridge = pci_upstream_bridge(pdev);
|
||||
if (bridge && bridge->ltr_path) {
|
||||
pcie_capability_read_dword(bridge, PCI_EXP_DEVCTL2, &ctl);
|
||||
if (!(ctl & PCI_EXP_DEVCTL2_LTR_EN)) {
|
||||
pci_dbg(bridge, "re-enabling LTR\n");
|
||||
pcie_capability_set_word(bridge, PCI_EXP_DEVCTL2,
|
||||
PCI_EXP_DEVCTL2_LTR_EN);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void pci_configure_ltr(struct pci_dev *pdev)
|
||||
{
|
||||
struct pci_host_bridge *host = pci_find_host_bridge(pdev->bus);
|
||||
struct pci_dev *bridge;
|
||||
u32 cap, ctl;
|
||||
|
||||
if (!pci_is_pcie(pdev))
|
||||
return;
|
||||
|
||||
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 */
|
||||
static void pcie_update_aspm_capable(struct pcie_link_state *root)
|
||||
{
|
||||
|
|
@ -1442,3 +1706,5 @@ bool pcie_aspm_support_enabled(void)
|
|||
{
|
||||
return aspm_support_enabled;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_PCIEASPM */
|
||||
|
|
|
|||
|
|
@ -2209,67 +2209,6 @@ static void pci_configure_relaxed_ordering(struct pci_dev *dev)
|
|||
}
|
||||
}
|
||||
|
||||
static void pci_configure_ltr(struct pci_dev *dev)
|
||||
{
|
||||
#ifdef CONFIG_PCIEASPM
|
||||
struct pci_host_bridge *host = pci_find_host_bridge(dev->bus);
|
||||
struct pci_dev *bridge;
|
||||
u32 cap, ctl;
|
||||
|
||||
if (!pci_is_pcie(dev))
|
||||
return;
|
||||
|
||||
/* Read L1 PM substate capabilities */
|
||||
dev->l1ss = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_L1SS);
|
||||
|
||||
pcie_capability_read_dword(dev, PCI_EXP_DEVCAP2, &cap);
|
||||
if (!(cap & PCI_EXP_DEVCAP2_LTR))
|
||||
return;
|
||||
|
||||
pcie_capability_read_dword(dev, PCI_EXP_DEVCTL2, &ctl);
|
||||
if (ctl & PCI_EXP_DEVCTL2_LTR_EN) {
|
||||
if (pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT) {
|
||||
dev->ltr_path = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
bridge = pci_upstream_bridge(dev);
|
||||
if (bridge && bridge->ltr_path)
|
||||
dev->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(dev) == PCI_EXP_TYPE_ROOT_PORT) {
|
||||
pcie_capability_set_word(dev, PCI_EXP_DEVCTL2,
|
||||
PCI_EXP_DEVCTL2_LTR_EN);
|
||||
dev->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(dev);
|
||||
if (bridge && bridge->ltr_path) {
|
||||
pci_bridge_reconfigure_ltr(dev);
|
||||
pcie_capability_set_word(dev, PCI_EXP_DEVCTL2,
|
||||
PCI_EXP_DEVCTL2_LTR_EN);
|
||||
dev->ltr_path = 1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void pci_configure_eetlp_prefix(struct pci_dev *dev)
|
||||
{
|
||||
#ifdef CONFIG_PCI_PASID
|
||||
|
|
@ -2320,6 +2259,7 @@ static void pci_configure_device(struct pci_dev *dev)
|
|||
pci_configure_extended_tags(dev, NULL);
|
||||
pci_configure_relaxed_ordering(dev);
|
||||
pci_configure_ltr(dev);
|
||||
pci_configure_aspm_l1ss(dev);
|
||||
pci_configure_eetlp_prefix(dev);
|
||||
pci_configure_serr(dev);
|
||||
|
||||
|
|
|
|||
|
|
@ -390,9 +390,9 @@ struct pci_dev {
|
|||
unsigned int d3hot_delay; /* D3hot->D0 transition time in ms */
|
||||
unsigned int d3cold_delay; /* D3cold->D0 transition time in ms */
|
||||
|
||||
u16 l1ss; /* L1SS Capability pointer */
|
||||
#ifdef CONFIG_PCIEASPM
|
||||
struct pcie_link_state *link_state; /* ASPM link state */
|
||||
u16 l1ss; /* L1SS Capability pointer */
|
||||
unsigned int ltr_path:1; /* Latency Tolerance Reporting
|
||||
supported from root to here */
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user