Skip to content

Commit b5a0a9b

Browse files
Rajat Jainbjorn-helgaas
Rajat Jain
authored andcommitted
PCI/ASPM: Read and set up L1 substate capabilities
The PCIe spec (r3.1, sec 7.33) says the L1 PM Substates Capability may be implemented only in function 0. Read the L1 substate capability structures of upstream and downstream components of the link and set it up in the device structure. [bhelgaas: add specific spec reference] Signed-off-by: Rajat Jain <[email protected]> Signed-off-by: Bjorn Helgaas <[email protected]>
1 parent b2103cc commit b5a0a9b

File tree

1 file changed

+58
-1
lines changed

1 file changed

+58
-1
lines changed

drivers/pci/pcie/aspm.c

+58-1
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ struct aspm_latency {
4949

5050
struct pcie_link_state {
5151
struct pci_dev *pdev; /* Upstream component of the Link */
52+
struct pci_dev *downstream; /* Downstream component, function 0 */
5253
struct pcie_link_state *root; /* pointer to the root port link */
5354
struct pcie_link_state *parent; /* pointer to the parent Link state */
5455
struct list_head sibling; /* node in link_list */
@@ -300,6 +301,12 @@ struct aspm_register_info {
300301
u32 enabled:2;
301302
u32 latency_encoding_l0s;
302303
u32 latency_encoding_l1;
304+
305+
/* L1 substates */
306+
u32 l1ss_cap_ptr;
307+
u32 l1ss_cap;
308+
u32 l1ss_ctl1;
309+
u32 l1ss_ctl2;
303310
};
304311

305312
static void pcie_get_aspm_reg(struct pci_dev *pdev,
@@ -314,6 +321,22 @@ static void pcie_get_aspm_reg(struct pci_dev *pdev,
314321
info->latency_encoding_l1 = (reg32 & PCI_EXP_LNKCAP_L1EL) >> 15;
315322
pcie_capability_read_word(pdev, PCI_EXP_LNKCTL, &reg16);
316323
info->enabled = reg16 & PCI_EXP_LNKCTL_ASPMC;
324+
325+
/* Read L1 PM substate capabilities */
326+
info->l1ss_cap = info->l1ss_ctl1 = info->l1ss_ctl2 = 0;
327+
info->l1ss_cap_ptr = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_L1SS);
328+
if (!info->l1ss_cap_ptr)
329+
return;
330+
pci_read_config_dword(pdev, info->l1ss_cap_ptr + PCI_L1SS_CAP,
331+
&info->l1ss_cap);
332+
if (!(info->l1ss_cap & PCI_L1SS_CAP_L1_PM_SS)) {
333+
info->l1ss_cap = 0;
334+
return;
335+
}
336+
pci_read_config_dword(pdev, info->l1ss_cap_ptr + PCI_L1SS_CTL1,
337+
&info->l1ss_ctl1);
338+
pci_read_config_dword(pdev, info->l1ss_cap_ptr + PCI_L1SS_CTL2,
339+
&info->l1ss_ctl2);
317340
}
318341

319342
static void pcie_aspm_check_latency(struct pci_dev *endpoint)
@@ -355,6 +378,20 @@ static void pcie_aspm_check_latency(struct pci_dev *endpoint)
355378
}
356379
}
357380

381+
/*
382+
* The L1 PM substate capability is only implemented in function 0 in a
383+
* multi function device.
384+
*/
385+
static struct pci_dev *pci_function_0(struct pci_bus *linkbus)
386+
{
387+
struct pci_dev *child;
388+
389+
list_for_each_entry(child, &linkbus->devices, bus_list)
390+
if (PCI_FUNC(child->devfn) == 0)
391+
return child;
392+
return NULL;
393+
}
394+
358395
static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist)
359396
{
360397
struct pci_dev *child, *parent = link->pdev;
@@ -370,8 +407,9 @@ static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist)
370407

371408
/* Get upstream/downstream components' register state */
372409
pcie_get_aspm_reg(parent, &upreg);
373-
child = list_entry(linkbus->devices.next, struct pci_dev, bus_list);
410+
child = pci_function_0(linkbus);
374411
pcie_get_aspm_reg(child, &dwreg);
412+
link->downstream = child;
375413

376414
/*
377415
* If ASPM not supported, don't mess with the clocks and link,
@@ -414,6 +452,25 @@ static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist)
414452
link->latency_up.l1 = calc_l1_latency(upreg.latency_encoding_l1);
415453
link->latency_dw.l1 = calc_l1_latency(dwreg.latency_encoding_l1);
416454

455+
/* Setup L1 substate */
456+
if (upreg.l1ss_cap & dwreg.l1ss_cap & PCI_L1SS_CAP_ASPM_L1_1)
457+
link->aspm_support |= ASPM_STATE_L1_1;
458+
if (upreg.l1ss_cap & dwreg.l1ss_cap & PCI_L1SS_CAP_ASPM_L1_2)
459+
link->aspm_support |= ASPM_STATE_L1_2;
460+
if (upreg.l1ss_cap & dwreg.l1ss_cap & PCI_L1SS_CAP_PCIPM_L1_1)
461+
link->aspm_support |= ASPM_STATE_L1_1_PCIPM;
462+
if (upreg.l1ss_cap & dwreg.l1ss_cap & PCI_L1SS_CAP_PCIPM_L1_2)
463+
link->aspm_support |= ASPM_STATE_L1_2_PCIPM;
464+
465+
if (upreg.l1ss_ctl1 & dwreg.l1ss_ctl1 & PCI_L1SS_CTL1_ASPM_L1_1)
466+
link->aspm_enabled |= ASPM_STATE_L1_1;
467+
if (upreg.l1ss_ctl1 & dwreg.l1ss_ctl1 & PCI_L1SS_CTL1_ASPM_L1_2)
468+
link->aspm_enabled |= ASPM_STATE_L1_2;
469+
if (upreg.l1ss_ctl1 & dwreg.l1ss_ctl1 & PCI_L1SS_CTL1_PCIPM_L1_1)
470+
link->aspm_enabled |= ASPM_STATE_L1_1_PCIPM;
471+
if (upreg.l1ss_ctl1 & dwreg.l1ss_ctl1 & PCI_L1SS_CTL1_PCIPM_L1_2)
472+
link->aspm_enabled |= ASPM_STATE_L1_2_PCIPM;
473+
417474
/* Save default state */
418475
link->aspm_default = link->aspm_enabled;
419476

0 commit comments

Comments
 (0)