Merge branch 'pci/aspm'
- Remove struct aspm_register_info (Saheed O. Bolarinwa) - Remove struct pcie_link_state.l1ss (Saheed O. Bolarinwa) * pci/aspm: PCI/ASPM: Remove struct pcie_link_state.l1ss PCI/ASPM: Remove struct aspm_register_info.l1ss_cap PCI/ASPM: Pass L1SS Capabilities value, not struct aspm_register_info PCI/ASPM: Remove struct aspm_register_info.l1ss_ctl1 PCI/ASPM: Remove struct aspm_register_info.l1ss_ctl2 (unused) PCI/ASPM: Remove struct aspm_register_info.l1ss_cap_ptr PCI/ASPM: Remove struct aspm_register_info.latency_encoding PCI/ASPM: Remove struct aspm_register_info.enabled PCI/ASPM: Remove struct aspm_register_info.support PCI/ASPM: Use 'parent' and 'child' for readability PCI/ASPM: Move LTR path check to where it's used PCI/ASPM: Move pci_clear_and_set_dword() earlier
This commit is contained in:
commit
a9f379068c
@ -74,14 +74,6 @@ struct pcie_link_state {
|
||||
* has one slot under it, so at most there are 8 functions.
|
||||
*/
|
||||
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;
|
||||
@ -308,8 +300,10 @@ static void pcie_aspm_configure_common_clock(struct pcie_link_state *link)
|
||||
}
|
||||
|
||||
/* Convert L0s latency encoding to ns */
|
||||
static u32 calc_l0s_latency(u32 encoding)
|
||||
static u32 calc_l0s_latency(u32 lnkcap)
|
||||
{
|
||||
u32 encoding = (lnkcap & PCI_EXP_LNKCAP_L0SEL) >> 12;
|
||||
|
||||
if (encoding == 0x7)
|
||||
return (5 * 1000); /* > 4us */
|
||||
return (64 << encoding);
|
||||
@ -324,8 +318,10 @@ static u32 calc_l0s_acceptable(u32 encoding)
|
||||
}
|
||||
|
||||
/* Convert L1 latency encoding to ns */
|
||||
static u32 calc_l1_latency(u32 encoding)
|
||||
static u32 calc_l1_latency(u32 lnkcap)
|
||||
{
|
||||
u32 encoding = (lnkcap & PCI_EXP_LNKCAP_L1EL) >> 15;
|
||||
|
||||
if (encoding == 0x7)
|
||||
return (65 * 1000); /* > 64us */
|
||||
return (1000 << encoding);
|
||||
@ -380,58 +376,6 @@ static void encode_l12_threshold(u32 threshold_us, u32 *scale, u32 *value)
|
||||
}
|
||||
}
|
||||
|
||||
struct aspm_register_info {
|
||||
u32 support:2;
|
||||
u32 enabled:2;
|
||||
u32 latency_encoding_l0s;
|
||||
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,
|
||||
struct aspm_register_info *info)
|
||||
{
|
||||
u16 reg16;
|
||||
u32 reg32;
|
||||
|
||||
pcie_capability_read_dword(pdev, PCI_EXP_LNKCAP, ®32);
|
||||
info->support = (reg32 & PCI_EXP_LNKCAP_ASPMS) >> 10;
|
||||
info->latency_encoding_l0s = (reg32 & PCI_EXP_LNKCAP_L0SEL) >> 12;
|
||||
info->latency_encoding_l1 = (reg32 & PCI_EXP_LNKCAP_L1EL) >> 15;
|
||||
pcie_capability_read_word(pdev, PCI_EXP_LNKCTL, ®16);
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 (!pdev->ltr_path)
|
||||
info->l1ss_cap &= ~PCI_L1SS_CAP_ASPM_L1_2;
|
||||
|
||||
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)
|
||||
{
|
||||
u32 latency, l1_switch_latency = 0;
|
||||
@ -493,39 +437,49 @@ static struct pci_dev *pci_function_0(struct pci_bus *linkbus)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/* 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 parent_l1ss_cap, u32 child_l1ss_cap)
|
||||
{
|
||||
struct pci_dev *child = link->downstream, *parent = link->pdev;
|
||||
u32 val1, val2, scale1, scale2;
|
||||
u32 t_common_mode, t_power_on, l1_2_threshold, scale, value;
|
||||
|
||||
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;
|
||||
u32 ctl1 = 0, ctl2 = 0;
|
||||
u32 pctl1, pctl2, cctl1, cctl2;
|
||||
u32 pl1_2_enables, cl1_2_enables;
|
||||
|
||||
if (!(link->aspm_support & ASPM_STATE_L1_2_MASK))
|
||||
return;
|
||||
|
||||
/* Choose the greater of the two Port Common_Mode_Restore_Times */
|
||||
val1 = (upreg->l1ss_cap & PCI_L1SS_CAP_CM_RESTORE_TIME) >> 8;
|
||||
val2 = (dwreg->l1ss_cap & PCI_L1SS_CAP_CM_RESTORE_TIME) >> 8;
|
||||
val1 = (parent_l1ss_cap & PCI_L1SS_CAP_CM_RESTORE_TIME) >> 8;
|
||||
val2 = (child_l1ss_cap & PCI_L1SS_CAP_CM_RESTORE_TIME) >> 8;
|
||||
t_common_mode = max(val1, val2);
|
||||
|
||||
/* Choose the greater of the two Port T_POWER_ON times */
|
||||
val1 = (upreg->l1ss_cap & PCI_L1SS_CAP_P_PWR_ON_VALUE) >> 19;
|
||||
scale1 = (upreg->l1ss_cap & PCI_L1SS_CAP_P_PWR_ON_SCALE) >> 16;
|
||||
val2 = (dwreg->l1ss_cap & PCI_L1SS_CAP_P_PWR_ON_VALUE) >> 19;
|
||||
scale2 = (dwreg->l1ss_cap & PCI_L1SS_CAP_P_PWR_ON_SCALE) >> 16;
|
||||
val1 = (parent_l1ss_cap & PCI_L1SS_CAP_P_PWR_ON_VALUE) >> 19;
|
||||
scale1 = (parent_l1ss_cap & PCI_L1SS_CAP_P_PWR_ON_SCALE) >> 16;
|
||||
val2 = (child_l1ss_cap & PCI_L1SS_CAP_P_PWR_ON_VALUE) >> 19;
|
||||
scale2 = (child_l1ss_cap & PCI_L1SS_CAP_P_PWR_ON_SCALE) >> 16;
|
||||
|
||||
if (calc_l1ss_pwron(link->pdev, scale1, val1) >
|
||||
calc_l1ss_pwron(link->downstream, scale2, val2)) {
|
||||
link->l1ss.ctl2 |= scale1 | (val1 << 3);
|
||||
t_power_on = calc_l1ss_pwron(link->pdev, scale1, val1);
|
||||
if (calc_l1ss_pwron(parent, scale1, val1) >
|
||||
calc_l1ss_pwron(child, scale2, val2)) {
|
||||
ctl2 |= scale1 | (val1 << 3);
|
||||
t_power_on = calc_l1ss_pwron(parent, scale1, val1);
|
||||
} else {
|
||||
link->l1ss.ctl2 |= scale2 | (val2 << 3);
|
||||
t_power_on = calc_l1ss_pwron(link->downstream, scale2, val2);
|
||||
ctl2 |= scale2 | (val2 << 3);
|
||||
t_power_on = calc_l1ss_pwron(child, scale2, val2);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -540,14 +494,60 @@ static void aspm_calc_l1ss_info(struct pcie_link_state *link,
|
||||
*/
|
||||
l1_2_threshold = 2 + 4 + t_common_mode + t_power_on;
|
||||
encode_l12_threshold(l1_2_threshold, &scale, &value);
|
||||
link->l1ss.ctl1 |= t_common_mode << 8 | scale << 29 | value << 16;
|
||||
ctl1 |= t_common_mode << 8 | scale << 29 | value << 16;
|
||||
|
||||
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);
|
||||
|
||||
if (ctl1 == pctl1 && ctl1 == cctl1 &&
|
||||
ctl2 == pctl2 && ctl2 == cctl2)
|
||||
return;
|
||||
|
||||
/* Disable L1.2 while updating. See PCIe r5.0, sec 5.5.4, 7.8.3.3 */
|
||||
pl1_2_enables = pctl1 & PCI_L1SS_CTL1_L1_2_MASK;
|
||||
cl1_2_enables = cctl1 & PCI_L1SS_CTL1_L1_2_MASK;
|
||||
|
||||
if (pl1_2_enables || cl1_2_enables) {
|
||||
pci_clear_and_set_dword(child, child->l1ss + PCI_L1SS_CTL1,
|
||||
PCI_L1SS_CTL1_L1_2_MASK, 0);
|
||||
pci_clear_and_set_dword(parent, parent->l1ss + PCI_L1SS_CTL1,
|
||||
PCI_L1SS_CTL1_L1_2_MASK, 0);
|
||||
}
|
||||
|
||||
/* 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_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_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_dword(child, child->l1ss + PCI_L1SS_CTL1,
|
||||
PCI_L1SS_CTL1_LTR_L12_TH_VALUE |
|
||||
PCI_L1SS_CTL1_LTR_L12_TH_SCALE, ctl1);
|
||||
|
||||
if (pl1_2_enables || cl1_2_enables) {
|
||||
pci_clear_and_set_dword(parent, parent->l1ss + PCI_L1SS_CTL1, 0,
|
||||
pl1_2_enables);
|
||||
pci_clear_and_set_dword(child, child->l1ss + PCI_L1SS_CTL1, 0,
|
||||
cl1_2_enables);
|
||||
}
|
||||
}
|
||||
|
||||
static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist)
|
||||
{
|
||||
struct pci_dev *child = link->downstream, *parent = link->pdev;
|
||||
u32 parent_lnkcap, child_lnkcap;
|
||||
u16 parent_lnkctl, child_lnkctl;
|
||||
u32 parent_l1ss_cap, child_l1ss_cap;
|
||||
u32 parent_l1ss_ctl1 = 0, child_l1ss_ctl1 = 0;
|
||||
struct pci_bus *linkbus = parent->subordinate;
|
||||
struct aspm_register_info upreg, dwreg;
|
||||
|
||||
if (blacklist) {
|
||||
/* Set enabled/disable so that we will disable ASPM later */
|
||||
@ -556,26 +556,28 @@ static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist)
|
||||
return;
|
||||
}
|
||||
|
||||
/* Get upstream/downstream components' register state */
|
||||
pcie_get_aspm_reg(parent, &upreg);
|
||||
pcie_get_aspm_reg(child, &dwreg);
|
||||
|
||||
/*
|
||||
* If ASPM not supported, don't mess with the clocks and link,
|
||||
* bail out now.
|
||||
*/
|
||||
if (!(upreg.support & dwreg.support))
|
||||
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
|
||||
* 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_get_aspm_reg(parent, &upreg);
|
||||
pcie_get_aspm_reg(child, &dwreg);
|
||||
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
|
||||
@ -584,44 +586,71 @@ static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist)
|
||||
* given link unless components on both sides of the link each
|
||||
* support L0s.
|
||||
*/
|
||||
if (dwreg.support & upreg.support & PCIE_LINK_STATE_L0S)
|
||||
if (parent_lnkcap & child_lnkcap & PCI_EXP_LNKCAP_ASPM_L0S)
|
||||
link->aspm_support |= ASPM_STATE_L0S;
|
||||
if (dwreg.enabled & PCIE_LINK_STATE_L0S)
|
||||
|
||||
if (child_lnkctl & PCI_EXP_LNKCTL_ASPM_L0S)
|
||||
link->aspm_enabled |= ASPM_STATE_L0S_UP;
|
||||
if (upreg.enabled & PCIE_LINK_STATE_L0S)
|
||||
if (parent_lnkctl & PCI_EXP_LNKCTL_ASPM_L0S)
|
||||
link->aspm_enabled |= ASPM_STATE_L0S_DW;
|
||||
link->latency_up.l0s = calc_l0s_latency(upreg.latency_encoding_l0s);
|
||||
link->latency_dw.l0s = calc_l0s_latency(dwreg.latency_encoding_l0s);
|
||||
link->latency_up.l0s = calc_l0s_latency(parent_lnkcap);
|
||||
link->latency_dw.l0s = calc_l0s_latency(child_lnkcap);
|
||||
|
||||
/* Setup L1 state */
|
||||
if (upreg.support & dwreg.support & PCIE_LINK_STATE_L1)
|
||||
if (parent_lnkcap & child_lnkcap & PCI_EXP_LNKCAP_ASPM_L1)
|
||||
link->aspm_support |= ASPM_STATE_L1;
|
||||
if (upreg.enabled & dwreg.enabled & PCIE_LINK_STATE_L1)
|
||||
|
||||
if (parent_lnkctl & child_lnkctl & PCI_EXP_LNKCTL_ASPM_L1)
|
||||
link->aspm_enabled |= ASPM_STATE_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_up.l1 = calc_l1_latency(parent_lnkcap);
|
||||
link->latency_dw.l1 = calc_l1_latency(child_lnkcap);
|
||||
|
||||
/* Setup L1 substate */
|
||||
if (upreg.l1ss_cap & dwreg.l1ss_cap & PCI_L1SS_CAP_ASPM_L1_1)
|
||||
pci_read_config_dword(parent, parent->l1ss + PCI_L1SS_CAP,
|
||||
&parent_l1ss_cap);
|
||||
pci_read_config_dword(child, child->l1ss + PCI_L1SS_CAP,
|
||||
&child_l1ss_cap);
|
||||
|
||||
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 |= ASPM_STATE_L1_1;
|
||||
if (upreg.l1ss_cap & dwreg.l1ss_cap & PCI_L1SS_CAP_ASPM_L1_2)
|
||||
if (parent_l1ss_cap & child_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)
|
||||
if (parent_l1ss_cap & child_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)
|
||||
if (parent_l1ss_cap & child_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)
|
||||
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 |= ASPM_STATE_L1_1;
|
||||
if (upreg.l1ss_ctl1 & dwreg.l1ss_ctl1 & PCI_L1SS_CTL1_ASPM_L1_2)
|
||||
if (parent_l1ss_ctl1 & child_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)
|
||||
if (parent_l1ss_ctl1 & child_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)
|
||||
if (parent_l1ss_ctl1 & child_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);
|
||||
aspm_calc_l1ss_info(link, parent_l1ss_cap, child_l1ss_cap);
|
||||
|
||||
/* Save default state */
|
||||
link->aspm_default = link->aspm_enabled;
|
||||
@ -651,24 +680,11 @@ 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;
|
||||
|
||||
@ -686,9 +702,9 @@ static void pcie_config_aspm_l1ss(struct pcie_link_state *link, u32 state)
|
||||
*/
|
||||
|
||||
/* Disable all L1 substates */
|
||||
pci_clear_and_set_dword(child, dw_cap_ptr + PCI_L1SS_CTL1,
|
||||
pci_clear_and_set_dword(child, child->l1ss + PCI_L1SS_CTL1,
|
||||
PCI_L1SS_CTL1_L1SS_MASK, 0);
|
||||
pci_clear_and_set_dword(parent, up_cap_ptr + PCI_L1SS_CTL1,
|
||||
pci_clear_and_set_dword(parent, parent->l1ss + PCI_L1SS_CTL1,
|
||||
PCI_L1SS_CTL1_L1SS_MASK, 0);
|
||||
/*
|
||||
* If needed, disable L1, and it gets enabled later
|
||||
@ -701,30 +717,6 @@ static void pcie_config_aspm_l1ss(struct pcie_link_state *link, u32 state)
|
||||
PCI_EXP_LNKCTL_ASPM_L1, 0);
|
||||
}
|
||||
|
||||
if (enable_req & ASPM_STATE_L1_2_MASK) {
|
||||
|
||||
/* Program T_POWER_ON times 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 Common_Mode_Restore_Time in upstream device */
|
||||
pci_clear_and_set_dword(parent, up_cap_ptr + PCI_L1SS_CTL1,
|
||||
PCI_L1SS_CTL1_CM_RESTORE_TIME,
|
||||
link->l1ss.ctl1);
|
||||
|
||||
/* Program LTR_L1.2_THRESHOLD time in both ports */
|
||||
pci_clear_and_set_dword(parent, up_cap_ptr + PCI_L1SS_CTL1,
|
||||
PCI_L1SS_CTL1_LTR_L12_TH_VALUE |
|
||||
PCI_L1SS_CTL1_LTR_L12_TH_SCALE,
|
||||
link->l1ss.ctl1);
|
||||
pci_clear_and_set_dword(child, dw_cap_ptr + PCI_L1SS_CTL1,
|
||||
PCI_L1SS_CTL1_LTR_L12_TH_VALUE |
|
||||
PCI_L1SS_CTL1_LTR_L12_TH_SCALE,
|
||||
link->l1ss.ctl1);
|
||||
}
|
||||
|
||||
val = 0;
|
||||
if (state & ASPM_STATE_L1_1)
|
||||
val |= PCI_L1SS_CTL1_ASPM_L1_1;
|
||||
@ -736,9 +728,9 @@ static void pcie_config_aspm_l1ss(struct pcie_link_state *link, u32 state)
|
||||
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_clear_and_set_dword(parent, parent->l1ss + PCI_L1SS_CTL1,
|
||||
PCI_L1SS_CTL1_L1SS_MASK, val);
|
||||
pci_clear_and_set_dword(child, dw_cap_ptr + PCI_L1SS_CTL1,
|
||||
pci_clear_and_set_dword(child, child->l1ss + PCI_L1SS_CTL1,
|
||||
PCI_L1SS_CTL1_L1SS_MASK, val);
|
||||
}
|
||||
|
||||
|
@ -2106,6 +2106,9 @@ static void pci_configure_ltr(struct pci_dev *dev)
|
||||
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;
|
||||
|
@ -380,6 +380,7 @@ struct pci_dev {
|
||||
struct pcie_link_state *link_state; /* ASPM link state */
|
||||
unsigned int ltr_path:1; /* Latency Tolerance Reporting
|
||||
supported from root to here */
|
||||
int l1ss; /* L1SS Capability pointer */
|
||||
#endif
|
||||
unsigned int eetlp_prefix_path:1; /* End-to-End TLP Prefix */
|
||||
|
||||
|
@ -532,6 +532,8 @@
|
||||
#define PCI_EXP_LNKCAP_SLS_32_0GB 0x00000005 /* LNKCAP2 SLS Vector bit 4 */
|
||||
#define PCI_EXP_LNKCAP_MLW 0x000003f0 /* Maximum Link Width */
|
||||
#define PCI_EXP_LNKCAP_ASPMS 0x00000c00 /* ASPM Support */
|
||||
#define PCI_EXP_LNKCAP_ASPM_L0S 0x00000400 /* ASPM L0s Support */
|
||||
#define PCI_EXP_LNKCAP_ASPM_L1 0x00000800 /* ASPM L1 Support */
|
||||
#define PCI_EXP_LNKCAP_L0SEL 0x00007000 /* L0s Exit Latency */
|
||||
#define PCI_EXP_LNKCAP_L1EL 0x00038000 /* L1 Exit Latency */
|
||||
#define PCI_EXP_LNKCAP_CLKPM 0x00040000 /* Clock Power Management */
|
||||
@ -1056,6 +1058,7 @@
|
||||
#define PCI_L1SS_CTL1_PCIPM_L1_1 0x00000002 /* PCI-PM L1.1 Enable */
|
||||
#define PCI_L1SS_CTL1_ASPM_L1_2 0x00000004 /* ASPM L1.2 Enable */
|
||||
#define PCI_L1SS_CTL1_ASPM_L1_1 0x00000008 /* ASPM L1.1 Enable */
|
||||
#define PCI_L1SS_CTL1_L1_2_MASK 0x00000005
|
||||
#define PCI_L1SS_CTL1_L1SS_MASK 0x0000000f
|
||||
#define PCI_L1SS_CTL1_CM_RESTORE_TIME 0x0000ff00 /* Common_Mode_Restore_Time */
|
||||
#define PCI_L1SS_CTL1_LTR_L12_TH_VALUE 0x03ff0000 /* LTR_L1.2_THRESHOLD_Value */
|
||||
|
Loading…
Reference in New Issue
Block a user