Merge branch 'pci/aspm' into next

* pci/aspm:
  PCI/ASPM: Add comment about L1 substate latency
  PCI/ASPM: Configure L1 substate settings
  PCI/ASPM: Calculate and save the L1.2 timing parameters
  PCI/ASPM: Read and set up L1 substate capabilities
  PCI/ASPM: Add support for L1 substates
  PCI/ASPM: Add L1 substate capability structure register definitions
This commit is contained in:
Bjorn Helgaas 2017-02-15 11:56:07 -06:00
commit 8f417ca9eb
3 changed files with 302 additions and 13 deletions

View File

@ -71,6 +71,14 @@ config PCIEASPM_POWERSAVE
Enable PCI Express ASPM L0s and L1 where possible, even if the Enable PCI Express ASPM L0s and L1 where possible, even if the
BIOS did not. BIOS did not.
config PCIEASPM_POWER_SUPERSAVE
bool "Power Supersave"
depends on PCIEASPM
help
Same as PCIEASPM_POWERSAVE, except it also enables L1 substates where
possible. This would result in higher power savings while staying in L1
where the components support it.
config PCIEASPM_PERFORMANCE config PCIEASPM_PERFORMANCE
bool "Performance" bool "Performance"
depends on PCIEASPM depends on PCIEASPM

View File

@ -30,8 +30,29 @@
#define ASPM_STATE_L0S_UP (1) /* Upstream direction L0s state */ #define ASPM_STATE_L0S_UP (1) /* Upstream direction L0s state */
#define ASPM_STATE_L0S_DW (2) /* Downstream direction L0s state */ #define ASPM_STATE_L0S_DW (2) /* Downstream direction L0s state */
#define ASPM_STATE_L1 (4) /* L1 state */ #define ASPM_STATE_L1 (4) /* L1 state */
#define ASPM_STATE_L1_1 (8) /* ASPM L1.1 state */
#define ASPM_STATE_L1_2 (0x10) /* ASPM L1.2 state */
#define ASPM_STATE_L1_1_PCIPM (0x20) /* PCI PM L1.1 state */
#define ASPM_STATE_L1_2_PCIPM (0x40) /* PCI PM L1.2 state */
#define ASPM_STATE_L1_SS_PCIPM (ASPM_STATE_L1_1_PCIPM | ASPM_STATE_L1_2_PCIPM)
#define ASPM_STATE_L1_2_MASK (ASPM_STATE_L1_2 | ASPM_STATE_L1_2_PCIPM)
#define ASPM_STATE_L1SS (ASPM_STATE_L1_1 | ASPM_STATE_L1_1_PCIPM |\
ASPM_STATE_L1_2_MASK)
#define ASPM_STATE_L0S (ASPM_STATE_L0S_UP | ASPM_STATE_L0S_DW) #define ASPM_STATE_L0S (ASPM_STATE_L0S_UP | ASPM_STATE_L0S_DW)
#define ASPM_STATE_ALL (ASPM_STATE_L0S | ASPM_STATE_L1) #define ASPM_STATE_ALL (ASPM_STATE_L0S | ASPM_STATE_L1 | \
ASPM_STATE_L1SS)
/*
* When L1 substates are enabled, the LTR L1.2 threshold is a timing parameter
* that decides whether L1.1 or L1.2 is entered (Refer PCIe spec for details).
* Not sure is there is a way to "calculate" this on the fly, but maybe we
* could turn it into a parameter in future. This value has been taken from
* the following files from Intel's coreboot (which is the only code I found
* to have used this):
* https://www.coreboot.org/pipermail/coreboot-gerrit/2015-March/021134.html
* https://review.coreboot.org/#/c/8832/
*/
#define LTR_L1_2_THRESHOLD_BITS ((1 << 21) | (1 << 23) | (1 << 30))
struct aspm_latency { struct aspm_latency {
u32 l0s; /* L0s latency (nsec) */ u32 l0s; /* L0s latency (nsec) */
@ -40,6 +61,7 @@ struct aspm_latency {
struct pcie_link_state { struct pcie_link_state {
struct pci_dev *pdev; /* Upstream component of the Link */ 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 *root; /* pointer to the root port link */
struct pcie_link_state *parent; /* pointer to the parent Link state */ struct pcie_link_state *parent; /* pointer to the parent Link state */
struct list_head sibling; /* node in link_list */ struct list_head sibling; /* node in link_list */
@ -47,11 +69,11 @@ struct pcie_link_state {
struct list_head link; /* node in parent's children list */ struct list_head link; /* node in parent's children list */
/* ASPM state */ /* ASPM state */
u32 aspm_support:3; /* Supported ASPM state */ u32 aspm_support:7; /* Supported ASPM state */
u32 aspm_enabled:3; /* Enabled ASPM state */ u32 aspm_enabled:7; /* Enabled ASPM state */
u32 aspm_capable:3; /* Capable ASPM state with latency */ u32 aspm_capable:7; /* Capable ASPM state with latency */
u32 aspm_default:3; /* Default ASPM state by BIOS */ u32 aspm_default:7; /* Default ASPM state by BIOS */
u32 aspm_disable:3; /* Disabled ASPM state */ u32 aspm_disable:7; /* Disabled ASPM state */
/* Clock PM state */ /* Clock PM state */
u32 clkpm_capable:1; /* Clock PM capable? */ u32 clkpm_capable:1; /* Clock PM capable? */
@ -66,6 +88,14 @@ struct pcie_link_state {
* has one slot under it, so at most there are 8 functions. * has one slot under it, so at most there are 8 functions.
*/ */
struct aspm_latency acceptable[8]; struct aspm_latency acceptable[8];
/* L1 PM Substate info */
struct {
u32 up_cap_ptr; /* L1SS cap ptr in upstream dev */
u32 dw_cap_ptr; /* L1SS cap ptr in downstream dev */
u32 ctl1; /* value to be programmed in ctl1 */
u32 ctl2; /* value to be programmed in ctl2 */
} l1ss;
}; };
static int aspm_disabled, aspm_force; static int aspm_disabled, aspm_force;
@ -76,11 +106,14 @@ static LIST_HEAD(link_list);
#define POLICY_DEFAULT 0 /* BIOS default setting */ #define POLICY_DEFAULT 0 /* BIOS default setting */
#define POLICY_PERFORMANCE 1 /* high performance */ #define POLICY_PERFORMANCE 1 /* high performance */
#define POLICY_POWERSAVE 2 /* high power saving */ #define POLICY_POWERSAVE 2 /* high power saving */
#define POLICY_POWER_SUPERSAVE 3 /* possibly even more power saving */
#ifdef CONFIG_PCIEASPM_PERFORMANCE #ifdef CONFIG_PCIEASPM_PERFORMANCE
static int aspm_policy = POLICY_PERFORMANCE; static int aspm_policy = POLICY_PERFORMANCE;
#elif defined CONFIG_PCIEASPM_POWERSAVE #elif defined CONFIG_PCIEASPM_POWERSAVE
static int aspm_policy = POLICY_POWERSAVE; static int aspm_policy = POLICY_POWERSAVE;
#elif defined CONFIG_PCIEASPM_POWER_SUPERSAVE
static int aspm_policy = POLICY_POWER_SUPERSAVE;
#else #else
static int aspm_policy; static int aspm_policy;
#endif #endif
@ -88,7 +121,8 @@ static int aspm_policy;
static const char *policy_str[] = { static const char *policy_str[] = {
[POLICY_DEFAULT] = "default", [POLICY_DEFAULT] = "default",
[POLICY_PERFORMANCE] = "performance", [POLICY_PERFORMANCE] = "performance",
[POLICY_POWERSAVE] = "powersave" [POLICY_POWERSAVE] = "powersave",
[POLICY_POWER_SUPERSAVE] = "powersupersave"
}; };
#define LINK_RETRAIN_TIMEOUT HZ #define LINK_RETRAIN_TIMEOUT HZ
@ -101,6 +135,9 @@ static int policy_to_aspm_state(struct pcie_link_state *link)
return 0; return 0;
case POLICY_POWERSAVE: case POLICY_POWERSAVE:
/* Enable ASPM L0s/L1 */ /* Enable ASPM L0s/L1 */
return (ASPM_STATE_L0S | ASPM_STATE_L1);
case POLICY_POWER_SUPERSAVE:
/* Enable Everything */
return ASPM_STATE_ALL; return ASPM_STATE_ALL;
case POLICY_DEFAULT: case POLICY_DEFAULT:
return link->aspm_default; return link->aspm_default;
@ -115,7 +152,8 @@ static int policy_to_clkpm_state(struct pcie_link_state *link)
/* Disable ASPM and Clock PM */ /* Disable ASPM and Clock PM */
return 0; return 0;
case POLICY_POWERSAVE: case POLICY_POWERSAVE:
/* Disable Clock PM */ case POLICY_POWER_SUPERSAVE:
/* Enable Clock PM */
return 1; return 1;
case POLICY_DEFAULT: case POLICY_DEFAULT:
return link->clkpm_default; return link->clkpm_default;
@ -278,11 +316,33 @@ static u32 calc_l1_acceptable(u32 encoding)
return (1000 << encoding); return (1000 << encoding);
} }
/* Convert L1SS T_pwr encoding to usec */
static u32 calc_l1ss_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;
}
dev_err(&pdev->dev, "%s: Invalid T_PwrOn scale: %u\n",
__func__, scale);
return 0;
}
struct aspm_register_info { struct aspm_register_info {
u32 support:2; u32 support:2;
u32 enabled:2; u32 enabled:2;
u32 latency_encoding_l0s; u32 latency_encoding_l0s;
u32 latency_encoding_l1; u32 latency_encoding_l1;
/* L1 substates */
u32 l1ss_cap_ptr;
u32 l1ss_cap;
u32 l1ss_ctl1;
u32 l1ss_ctl2;
}; };
static void pcie_get_aspm_reg(struct pci_dev *pdev, static void pcie_get_aspm_reg(struct pci_dev *pdev,
@ -297,6 +357,22 @@ static void pcie_get_aspm_reg(struct pci_dev *pdev,
info->latency_encoding_l1 = (reg32 & PCI_EXP_LNKCAP_L1EL) >> 15; info->latency_encoding_l1 = (reg32 & PCI_EXP_LNKCAP_L1EL) >> 15;
pcie_capability_read_word(pdev, PCI_EXP_LNKCTL, &reg16); pcie_capability_read_word(pdev, PCI_EXP_LNKCTL, &reg16);
info->enabled = reg16 & PCI_EXP_LNKCTL_ASPMC; info->enabled = reg16 & PCI_EXP_LNKCTL_ASPMC;
/* Read L1 PM substate capabilities */
info->l1ss_cap = info->l1ss_ctl1 = info->l1ss_ctl2 = 0;
info->l1ss_cap_ptr = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_L1SS);
if (!info->l1ss_cap_ptr)
return;
pci_read_config_dword(pdev, info->l1ss_cap_ptr + PCI_L1SS_CAP,
&info->l1ss_cap);
if (!(info->l1ss_cap & PCI_L1SS_CAP_L1_PM_SS)) {
info->l1ss_cap = 0;
return;
}
pci_read_config_dword(pdev, info->l1ss_cap_ptr + PCI_L1SS_CTL1,
&info->l1ss_ctl1);
pci_read_config_dword(pdev, info->l1ss_cap_ptr + PCI_L1SS_CTL2,
&info->l1ss_ctl2);
} }
static void pcie_aspm_check_latency(struct pci_dev *endpoint) static void pcie_aspm_check_latency(struct pci_dev *endpoint)
@ -327,6 +403,14 @@ static void pcie_aspm_check_latency(struct pci_dev *endpoint)
* Check L1 latency. * Check L1 latency.
* Every switch on the path to root complex need 1 * Every switch on the path to root complex need 1
* more microsecond for L1. Spec doesn't mention L0s. * 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, link->latency_up.l1, link->latency_dw.l1); latency = max_t(u32, link->latency_up.l1, link->latency_dw.l1);
if ((link->aspm_capable & ASPM_STATE_L1) && if ((link->aspm_capable & ASPM_STATE_L1) &&
@ -338,6 +422,60 @@ static void pcie_aspm_check_latency(struct pci_dev *endpoint)
} }
} }
/*
* The L1 PM substate capability is only implemented in function 0 in a
* multi function device.
*/
static struct pci_dev *pci_function_0(struct pci_bus *linkbus)
{
struct pci_dev *child;
list_for_each_entry(child, &linkbus->devices, bus_list)
if (PCI_FUNC(child->devfn) == 0)
return child;
return NULL;
}
/* Calculate L1.2 PM substate timing parameters */
static void aspm_calc_l1ss_info(struct pcie_link_state *link,
struct aspm_register_info *upreg,
struct aspm_register_info *dwreg)
{
u32 val1, val2, scale1, scale2;
link->l1ss.up_cap_ptr = upreg->l1ss_cap_ptr;
link->l1ss.dw_cap_ptr = dwreg->l1ss_cap_ptr;
link->l1ss.ctl1 = link->l1ss.ctl2 = 0;
if (!(link->aspm_support & ASPM_STATE_L1_2_MASK))
return;
/* Choose the greater of the two T_cmn_mode_rstr_time */
val1 = (upreg->l1ss_cap >> 8) & 0xFF;
val2 = (upreg->l1ss_cap >> 8) & 0xFF;
if (val1 > val2)
link->l1ss.ctl1 |= val1 << 8;
else
link->l1ss.ctl1 |= val2 << 8;
/*
* We currently use LTR L1.2 threshold to be fixed constant picked from
* Intel's coreboot.
*/
link->l1ss.ctl1 |= LTR_L1_2_THRESHOLD_BITS;
/* Choose the greater of the two T_pwr_on */
val1 = (upreg->l1ss_cap >> 19) & 0x1F;
scale1 = (upreg->l1ss_cap >> 16) & 0x03;
val2 = (dwreg->l1ss_cap >> 19) & 0x1F;
scale2 = (dwreg->l1ss_cap >> 16) & 0x03;
if (calc_l1ss_pwron(link->pdev, scale1, val1) >
calc_l1ss_pwron(link->downstream, scale2, val2))
link->l1ss.ctl2 |= scale1 | (val1 << 3);
else
link->l1ss.ctl2 |= scale2 | (val2 << 3);
}
static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist) static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist)
{ {
struct pci_dev *child, *parent = link->pdev; struct pci_dev *child, *parent = link->pdev;
@ -353,8 +491,9 @@ static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist)
/* Get upstream/downstream components' register state */ /* Get upstream/downstream components' register state */
pcie_get_aspm_reg(parent, &upreg); pcie_get_aspm_reg(parent, &upreg);
child = list_entry(linkbus->devices.next, struct pci_dev, bus_list); child = pci_function_0(linkbus);
pcie_get_aspm_reg(child, &dwreg); pcie_get_aspm_reg(child, &dwreg);
link->downstream = child;
/* /*
* If ASPM not supported, don't mess with the clocks and link, * If ASPM not supported, don't mess with the clocks and link,
@ -397,6 +536,28 @@ static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist)
link->latency_up.l1 = calc_l1_latency(upreg.latency_encoding_l1); link->latency_up.l1 = calc_l1_latency(upreg.latency_encoding_l1);
link->latency_dw.l1 = calc_l1_latency(dwreg.latency_encoding_l1); link->latency_dw.l1 = calc_l1_latency(dwreg.latency_encoding_l1);
/* Setup L1 substate */
if (upreg.l1ss_cap & dwreg.l1ss_cap & PCI_L1SS_CAP_ASPM_L1_1)
link->aspm_support |= ASPM_STATE_L1_1;
if (upreg.l1ss_cap & dwreg.l1ss_cap & PCI_L1SS_CAP_ASPM_L1_2)
link->aspm_support |= ASPM_STATE_L1_2;
if (upreg.l1ss_cap & dwreg.l1ss_cap & PCI_L1SS_CAP_PCIPM_L1_1)
link->aspm_support |= ASPM_STATE_L1_1_PCIPM;
if (upreg.l1ss_cap & dwreg.l1ss_cap & PCI_L1SS_CAP_PCIPM_L1_2)
link->aspm_support |= ASPM_STATE_L1_2_PCIPM;
if (upreg.l1ss_ctl1 & dwreg.l1ss_ctl1 & PCI_L1SS_CTL1_ASPM_L1_1)
link->aspm_enabled |= ASPM_STATE_L1_1;
if (upreg.l1ss_ctl1 & dwreg.l1ss_ctl1 & PCI_L1SS_CTL1_ASPM_L1_2)
link->aspm_enabled |= ASPM_STATE_L1_2;
if (upreg.l1ss_ctl1 & dwreg.l1ss_ctl1 & PCI_L1SS_CTL1_PCIPM_L1_1)
link->aspm_enabled |= ASPM_STATE_L1_1_PCIPM;
if (upreg.l1ss_ctl1 & dwreg.l1ss_ctl1 & PCI_L1SS_CTL1_PCIPM_L1_2)
link->aspm_enabled |= ASPM_STATE_L1_2_PCIPM;
if (link->aspm_support & ASPM_STATE_L1SS)
aspm_calc_l1ss_info(link, &upreg, &dwreg);
/* Save default state */ /* Save default state */
link->aspm_default = link->aspm_enabled; link->aspm_default = link->aspm_enabled;
@ -435,6 +596,92 @@ static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist)
} }
} }
static void pci_clear_and_set_dword(struct pci_dev *pdev, int pos,
u32 clear, u32 set)
{
u32 val;
pci_read_config_dword(pdev, pos, &val);
val &= ~clear;
val |= set;
pci_write_config_dword(pdev, pos, val);
}
/* Configure the ASPM L1 substates */
static void pcie_config_aspm_l1ss(struct pcie_link_state *link, u32 state)
{
u32 val, enable_req;
struct pci_dev *child = link->downstream, *parent = link->pdev;
u32 up_cap_ptr = link->l1ss.up_cap_ptr;
u32 dw_cap_ptr = link->l1ss.dw_cap_ptr;
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_dword(child, dw_cap_ptr + PCI_L1SS_CTL1,
PCI_L1SS_CTL1_L1SS_MASK, 0);
pci_clear_and_set_dword(parent, up_cap_ptr + 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 & (ASPM_STATE_L1_1 | ASPM_STATE_L1_2)) {
pcie_capability_clear_and_set_word(child, PCI_EXP_LNKCTL,
PCI_EXP_LNKCTL_ASPM_L1, 0);
pcie_capability_clear_and_set_word(parent, PCI_EXP_LNKCTL,
PCI_EXP_LNKCTL_ASPM_L1, 0);
}
if (enable_req & ASPM_STATE_L1_2_MASK) {
/* Program T_pwr_on in both ports */
pci_write_config_dword(parent, up_cap_ptr + PCI_L1SS_CTL2,
link->l1ss.ctl2);
pci_write_config_dword(child, dw_cap_ptr + PCI_L1SS_CTL2,
link->l1ss.ctl2);
/* Program T_cmn_mode in parent */
pci_clear_and_set_dword(parent, up_cap_ptr + PCI_L1SS_CTL1,
0xFF00, link->l1ss.ctl1);
/* Program LTR L1.2 threshold in both ports */
pci_clear_and_set_dword(parent, dw_cap_ptr + PCI_L1SS_CTL1,
0xE3FF0000, link->l1ss.ctl1);
pci_clear_and_set_dword(child, dw_cap_ptr + PCI_L1SS_CTL1,
0xE3FF0000, link->l1ss.ctl1);
}
val = 0;
if (state & ASPM_STATE_L1_1)
val |= PCI_L1SS_CTL1_ASPM_L1_1;
if (state & ASPM_STATE_L1_2)
val |= PCI_L1SS_CTL1_ASPM_L1_2;
if (state & ASPM_STATE_L1_1_PCIPM)
val |= PCI_L1SS_CTL1_PCIPM_L1_1;
if (state & ASPM_STATE_L1_2_PCIPM)
val |= PCI_L1SS_CTL1_PCIPM_L1_2;
/* Enable what we need to enable */
pci_clear_and_set_dword(parent, up_cap_ptr + PCI_L1SS_CTL1,
PCI_L1SS_CAP_L1_PM_SS, val);
pci_clear_and_set_dword(child, dw_cap_ptr + PCI_L1SS_CTL1,
PCI_L1SS_CAP_L1_PM_SS, val);
}
static void pcie_config_aspm_dev(struct pci_dev *pdev, u32 val) static void pcie_config_aspm_dev(struct pci_dev *pdev, u32 val)
{ {
pcie_capability_clear_and_set_word(pdev, PCI_EXP_LNKCTL, pcie_capability_clear_and_set_word(pdev, PCI_EXP_LNKCTL,
@ -444,11 +691,23 @@ static void pcie_config_aspm_dev(struct pci_dev *pdev, u32 val)
static void pcie_config_aspm_link(struct pcie_link_state *link, u32 state) static void pcie_config_aspm_link(struct pcie_link_state *link, u32 state)
{ {
u32 upstream = 0, dwstream = 0; u32 upstream = 0, dwstream = 0;
struct pci_dev *child, *parent = link->pdev; struct pci_dev *child = link->downstream, *parent = link->pdev;
struct pci_bus *linkbus = parent->subordinate; struct pci_bus *linkbus = parent->subordinate;
/* Nothing to do if the link is already in the requested state */ /* Enable only the states that were not explicitly disabled */
state &= (link->aspm_capable & ~link->aspm_disable); state &= (link->aspm_capable & ~link->aspm_disable);
/* Can't enable any substates if L1 is not enabled */
if (!(state & ASPM_STATE_L1))
state &= ~ASPM_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 &= ~ASPM_STATE_L1_SS_PCIPM;
state |= (link->aspm_enabled & ASPM_STATE_L1_SS_PCIPM);
}
/* Nothing to do if the link is already in the requested state */
if (link->aspm_enabled == state) if (link->aspm_enabled == state)
return; return;
/* Convert ASPM state to upstream/downstream ASPM register state */ /* Convert ASPM state to upstream/downstream ASPM register state */
@ -460,6 +719,10 @@ static void pcie_config_aspm_link(struct pcie_link_state *link, u32 state)
upstream |= PCI_EXP_LNKCTL_ASPM_L1; upstream |= PCI_EXP_LNKCTL_ASPM_L1;
dwstream |= PCI_EXP_LNKCTL_ASPM_L1; dwstream |= PCI_EXP_LNKCTL_ASPM_L1;
} }
if (link->aspm_capable & ASPM_STATE_L1SS)
pcie_config_aspm_l1ss(link, state);
/* /*
* Spec 2.0 suggests all functions should be configured the * Spec 2.0 suggests all functions should be configured the
* same setting for ASPM. Enabling ASPM L1 should be done in * same setting for ASPM. Enabling ASPM L1 should be done in
@ -612,7 +875,8 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev)
* the BIOS's expectation, we'll do so once pci_enable_device() is * the BIOS's expectation, we'll do so once pci_enable_device() is
* called. * called.
*/ */
if (aspm_policy != POLICY_POWERSAVE) { if (aspm_policy != POLICY_POWERSAVE &&
aspm_policy != POLICY_POWER_SUPERSAVE) {
pcie_config_aspm_path(link); pcie_config_aspm_path(link);
pcie_set_clkpm(link, policy_to_clkpm_state(link)); pcie_set_clkpm(link, policy_to_clkpm_state(link));
} }
@ -712,7 +976,8 @@ void pcie_aspm_powersave_config_link(struct pci_dev *pdev)
if (aspm_disabled || !link) if (aspm_disabled || !link)
return; return;
if (aspm_policy != POLICY_POWERSAVE) if (aspm_policy != POLICY_POWERSAVE &&
aspm_policy != POLICY_POWER_SUPERSAVE)
return; return;
down_read(&pci_bus_sem); down_read(&pci_bus_sem);

View File

@ -682,6 +682,7 @@
#define PCI_EXT_CAP_ID_PMUX 0x1A /* Protocol Multiplexing */ #define PCI_EXT_CAP_ID_PMUX 0x1A /* Protocol Multiplexing */
#define PCI_EXT_CAP_ID_PASID 0x1B /* Process Address Space ID */ #define PCI_EXT_CAP_ID_PASID 0x1B /* Process Address Space ID */
#define PCI_EXT_CAP_ID_DPC 0x1D /* Downstream Port Containment */ #define PCI_EXT_CAP_ID_DPC 0x1D /* Downstream Port Containment */
#define PCI_EXT_CAP_ID_L1SS 0x1E /* L1 PM Substates */
#define PCI_EXT_CAP_ID_PTM 0x1F /* Precision Time Measurement */ #define PCI_EXT_CAP_ID_PTM 0x1F /* Precision Time Measurement */
#define PCI_EXT_CAP_ID_MAX PCI_EXT_CAP_ID_PTM #define PCI_EXT_CAP_ID_MAX PCI_EXT_CAP_ID_PTM
@ -985,4 +986,19 @@
#define PCI_PTM_CTRL_ENABLE 0x00000001 /* PTM enable */ #define PCI_PTM_CTRL_ENABLE 0x00000001 /* PTM enable */
#define PCI_PTM_CTRL_ROOT 0x00000002 /* Root select */ #define PCI_PTM_CTRL_ROOT 0x00000002 /* Root select */
/* L1 PM Substates */
#define PCI_L1SS_CAP 4 /* capability register */
#define PCI_L1SS_CAP_PCIPM_L1_2 1 /* PCI PM L1.2 Support */
#define PCI_L1SS_CAP_PCIPM_L1_1 2 /* PCI PM L1.1 Support */
#define PCI_L1SS_CAP_ASPM_L1_2 4 /* ASPM L1.2 Support */
#define PCI_L1SS_CAP_ASPM_L1_1 8 /* ASPM L1.1 Support */
#define PCI_L1SS_CAP_L1_PM_SS 16 /* L1 PM Substates Support */
#define PCI_L1SS_CTL1 8 /* Control Register 1 */
#define PCI_L1SS_CTL1_PCIPM_L1_2 1 /* PCI PM L1.2 Enable */
#define PCI_L1SS_CTL1_PCIPM_L1_1 2 /* PCI PM L1.1 Support */
#define PCI_L1SS_CTL1_ASPM_L1_2 4 /* ASPM L1.2 Support */
#define PCI_L1SS_CTL1_ASPM_L1_1 8 /* ASPM L1.1 Support */
#define PCI_L1SS_CTL1_L1SS_MASK 0x0000000F
#define PCI_L1SS_CTL2 0xC /* Control Register 2 */
#endif /* LINUX_PCI_REGS_H */ #endif /* LINUX_PCI_REGS_H */