aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRajat Jain <rajatja@google.com>2017-01-03 01:34:13 -0500
committerBjorn Helgaas <bhelgaas@google.com>2017-02-14 18:44:25 -0500
commitf1f0366dd6be9624f7d355b72cc909ab821eb4c0 (patch)
tree272dd86f5011286fc17097b6279f6c4918f4d7c9
parentb5a0a9b59c8185aebcd9a717e2e6258b58c72c06 (diff)
PCI/ASPM: Calculate and save the L1.2 timing parameters
Calculate and save the timing parameters that need to be programmed if we need to enable L1.2 substates later. We use the same logic (and a constant value for 1 of the parameters) as used by Intel's coreboot: https://www.coreboot.org/pipermail/coreboot-gerrit/2015-March/021134.html https://review.coreboot.org/#/c/8832/ Signed-off-by: Rajat Jain <rajatja@google.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
-rw-r--r--drivers/pci/pcie/aspm.c79
1 files changed, 79 insertions, 0 deletions
diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c
index 1cd53203abbd..b3451cb0472b 100644
--- a/drivers/pci/pcie/aspm.c
+++ b/drivers/pci/pcie/aspm.c
@@ -42,6 +42,18 @@
42#define ASPM_STATE_ALL (ASPM_STATE_L0S | ASPM_STATE_L1 | \ 42#define ASPM_STATE_ALL (ASPM_STATE_L0S | ASPM_STATE_L1 | \
43 ASPM_STATE_L1SS) 43 ASPM_STATE_L1SS)
44 44
45/*
46 * When L1 substates are enabled, the LTR L1.2 threshold is a timing parameter
47 * that decides whether L1.1 or L1.2 is entered (Refer PCIe spec for details).
48 * Not sure is there is a way to "calculate" this on the fly, but maybe we
49 * could turn it into a parameter in future. This value has been taken from
50 * the following files from Intel's coreboot (which is the only code I found
51 * to have used this):
52 * https://www.coreboot.org/pipermail/coreboot-gerrit/2015-March/021134.html
53 * https://review.coreboot.org/#/c/8832/
54 */
55#define LTR_L1_2_THRESHOLD_BITS ((1 << 21) | (1 << 23) | (1 << 30))
56
45struct aspm_latency { 57struct aspm_latency {
46 u32 l0s; /* L0s latency (nsec) */ 58 u32 l0s; /* L0s latency (nsec) */
47 u32 l1; /* L1 latency (nsec) */ 59 u32 l1; /* L1 latency (nsec) */
@@ -76,6 +88,14 @@ struct pcie_link_state {
76 * has one slot under it, so at most there are 8 functions. 88 * has one slot under it, so at most there are 8 functions.
77 */ 89 */
78 struct aspm_latency acceptable[8]; 90 struct aspm_latency acceptable[8];
91
92 /* L1 PM Substate info */
93 struct {
94 u32 up_cap_ptr; /* L1SS cap ptr in upstream dev */
95 u32 dw_cap_ptr; /* L1SS cap ptr in downstream dev */
96 u32 ctl1; /* value to be programmed in ctl1 */
97 u32 ctl2; /* value to be programmed in ctl2 */
98 } l1ss;
79}; 99};
80 100
81static int aspm_disabled, aspm_force; 101static int aspm_disabled, aspm_force;
@@ -296,6 +316,22 @@ static u32 calc_l1_acceptable(u32 encoding)
296 return (1000 << encoding); 316 return (1000 << encoding);
297} 317}
298 318
319/* Convert L1SS T_pwr encoding to usec */
320static u32 calc_l1ss_pwron(struct pci_dev *pdev, u32 scale, u32 val)
321{
322 switch (scale) {
323 case 0:
324 return val * 2;
325 case 1:
326 return val * 10;
327 case 2:
328 return val * 100;
329 }
330 dev_err(&pdev->dev, "%s: Invalid T_PwrOn scale: %u\n",
331 __func__, scale);
332 return 0;
333}
334
299struct aspm_register_info { 335struct aspm_register_info {
300 u32 support:2; 336 u32 support:2;
301 u32 enabled:2; 337 u32 enabled:2;
@@ -392,6 +428,46 @@ static struct pci_dev *pci_function_0(struct pci_bus *linkbus)
392 return NULL; 428 return NULL;
393} 429}
394 430
431/* Calculate L1.2 PM substate timing parameters */
432static void aspm_calc_l1ss_info(struct pcie_link_state *link,
433 struct aspm_register_info *upreg,
434 struct aspm_register_info *dwreg)
435{
436 u32 val1, val2, scale1, scale2;
437
438 link->l1ss.up_cap_ptr = upreg->l1ss_cap_ptr;
439 link->l1ss.dw_cap_ptr = dwreg->l1ss_cap_ptr;
440 link->l1ss.ctl1 = link->l1ss.ctl2 = 0;
441
442 if (!(link->aspm_support & ASPM_STATE_L1_2_MASK))
443 return;
444
445 /* Choose the greater of the two T_cmn_mode_rstr_time */
446 val1 = (upreg->l1ss_cap >> 8) & 0xFF;
447 val2 = (upreg->l1ss_cap >> 8) & 0xFF;
448 if (val1 > val2)
449 link->l1ss.ctl1 |= val1 << 8;
450 else
451 link->l1ss.ctl1 |= val2 << 8;
452 /*
453 * We currently use LTR L1.2 threshold to be fixed constant picked from
454 * Intel's coreboot.
455 */
456 link->l1ss.ctl1 |= LTR_L1_2_THRESHOLD_BITS;
457
458 /* Choose the greater of the two T_pwr_on */
459 val1 = (upreg->l1ss_cap >> 19) & 0x1F;
460 scale1 = (upreg->l1ss_cap >> 16) & 0x03;
461 val2 = (dwreg->l1ss_cap >> 19) & 0x1F;
462 scale2 = (dwreg->l1ss_cap >> 16) & 0x03;
463
464 if (calc_l1ss_pwron(link->pdev, scale1, val1) >
465 calc_l1ss_pwron(link->downstream, scale2, val2))
466 link->l1ss.ctl2 |= scale1 | (val1 << 3);
467 else
468 link->l1ss.ctl2 |= scale2 | (val2 << 3);
469}
470
395static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist) 471static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist)
396{ 472{
397 struct pci_dev *child, *parent = link->pdev; 473 struct pci_dev *child, *parent = link->pdev;
@@ -471,6 +547,9 @@ static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist)
471 if (upreg.l1ss_ctl1 & dwreg.l1ss_ctl1 & PCI_L1SS_CTL1_PCIPM_L1_2) 547 if (upreg.l1ss_ctl1 & dwreg.l1ss_ctl1 & PCI_L1SS_CTL1_PCIPM_L1_2)
472 link->aspm_enabled |= ASPM_STATE_L1_2_PCIPM; 548 link->aspm_enabled |= ASPM_STATE_L1_2_PCIPM;
473 549
550 if (link->aspm_support & ASPM_STATE_L1SS)
551 aspm_calc_l1ss_info(link, &upreg, &dwreg);
552
474 /* Save default state */ 553 /* Save default state */
475 link->aspm_default = link->aspm_enabled; 554 link->aspm_default = link->aspm_enabled;
476 555