aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRajat Jain <rajatja@google.com>2017-01-03 01:34:12 -0500
committerBjorn Helgaas <bhelgaas@google.com>2017-02-14 18:44:12 -0500
commitb5a0a9b59c8185aebcd9a717e2e6258b58c72c06 (patch)
tree5965432f559df890e710532bfc6c8ad0472c59d2
parentb2103ccbb67e3ef0f7a75d21c989f9614ddbcaca (diff)
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 <rajatja@google.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
-rw-r--r--drivers/pci/pcie/aspm.c59
1 files changed, 58 insertions, 1 deletions
diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c
index a74fb3a8333f..1cd53203abbd 100644
--- a/drivers/pci/pcie/aspm.c
+++ b/drivers/pci/pcie/aspm.c
@@ -49,6 +49,7 @@ struct aspm_latency {
49 49
50struct pcie_link_state { 50struct pcie_link_state {
51 struct pci_dev *pdev; /* Upstream component of the Link */ 51 struct pci_dev *pdev; /* Upstream component of the Link */
52 struct pci_dev *downstream; /* Downstream component, function 0 */
52 struct pcie_link_state *root; /* pointer to the root port link */ 53 struct pcie_link_state *root; /* pointer to the root port link */
53 struct pcie_link_state *parent; /* pointer to the parent Link state */ 54 struct pcie_link_state *parent; /* pointer to the parent Link state */
54 struct list_head sibling; /* node in link_list */ 55 struct list_head sibling; /* node in link_list */
@@ -300,6 +301,12 @@ struct aspm_register_info {
300 u32 enabled:2; 301 u32 enabled:2;
301 u32 latency_encoding_l0s; 302 u32 latency_encoding_l0s;
302 u32 latency_encoding_l1; 303 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;
303}; 310};
304 311
305static void pcie_get_aspm_reg(struct pci_dev *pdev, 312static void pcie_get_aspm_reg(struct pci_dev *pdev,
@@ -314,6 +321,22 @@ static void pcie_get_aspm_reg(struct pci_dev *pdev,
314 info->latency_encoding_l1 = (reg32 & PCI_EXP_LNKCAP_L1EL) >> 15; 321 info->latency_encoding_l1 = (reg32 & PCI_EXP_LNKCAP_L1EL) >> 15;
315 pcie_capability_read_word(pdev, PCI_EXP_LNKCTL, &reg16); 322 pcie_capability_read_word(pdev, PCI_EXP_LNKCTL, &reg16);
316 info->enabled = reg16 & PCI_EXP_LNKCTL_ASPMC; 323 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);
317} 340}
318 341
319static void pcie_aspm_check_latency(struct pci_dev *endpoint) 342static void pcie_aspm_check_latency(struct pci_dev *endpoint)
@@ -355,6 +378,20 @@ static void pcie_aspm_check_latency(struct pci_dev *endpoint)
355 } 378 }
356} 379}
357 380
381/*
382 * The L1 PM substate capability is only implemented in function 0 in a
383 * multi function device.
384 */
385static 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
358static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist) 395static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist)
359{ 396{
360 struct pci_dev *child, *parent = link->pdev; 397 struct pci_dev *child, *parent = link->pdev;
@@ -370,8 +407,9 @@ static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist)
370 407
371 /* Get upstream/downstream components' register state */ 408 /* Get upstream/downstream components' register state */
372 pcie_get_aspm_reg(parent, &upreg); 409 pcie_get_aspm_reg(parent, &upreg);
373 child = list_entry(linkbus->devices.next, struct pci_dev, bus_list); 410 child = pci_function_0(linkbus);
374 pcie_get_aspm_reg(child, &dwreg); 411 pcie_get_aspm_reg(child, &dwreg);
412 link->downstream = child;
375 413
376 /* 414 /*
377 * If ASPM not supported, don't mess with the clocks and link, 415 * 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)
414 link->latency_up.l1 = calc_l1_latency(upreg.latency_encoding_l1); 452 link->latency_up.l1 = calc_l1_latency(upreg.latency_encoding_l1);
415 link->latency_dw.l1 = calc_l1_latency(dwreg.latency_encoding_l1); 453 link->latency_dw.l1 = calc_l1_latency(dwreg.latency_encoding_l1);
416 454
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
417 /* Save default state */ 474 /* Save default state */
418 link->aspm_default = link->aspm_enabled; 475 link->aspm_default = link->aspm_enabled;
419 476