Skip to content

Commit 7afeb84

Browse files
committed
PCI/ASPM: Correct LTR_L1.2_THRESHOLD computation
80d7d7a ("PCI/ASPM: Calculate LTR_L1.2_THRESHOLD from device characteristics") replaced a fixed value (163840ns) with one computed from T_POWER_OFF, Common_Mode_Restore_Time, etc., but it encoded the LTR_L1.2_THRESHOLD value incorrectly. This is especially a problem for small thresholds, e.g., 63ns fell into the "threshold_ns < 1024" case and was encoded as 32ns: LTR_L1.2_THRESHOLD_Scale = 1 (multiplier is 32ns) LTR_L1.2_THRESHOLD_Value = 63 >> 5 = 1 LTR_L1.2_THRESHOLD = multiplier * value = 32ns * 1 = 32ns Correct the algorithm to encode all times of 1023ns (0x3ff) or smaller exactly and larger times conservatively (the encoded threshold is never smaller than was requested). This reduces the chance of entering L1.2 when the device can't tolerate the exit latency. Fixes: 80d7d7a ("PCI/ASPM: Calculate LTR_L1.2_THRESHOLD from device characteristics") Link: https://lore.kernel.org/r/20221005025809.2247547-4-helgaas@kernel.org Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Reviewed-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
1 parent cfc0028 commit 7afeb84

File tree

1 file changed

+32
-17
lines changed

1 file changed

+32
-17
lines changed

drivers/pci/pcie/aspm.c

Lines changed: 32 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
*/
99

1010
#include <linux/kernel.h>
11+
#include <linux/math.h>
1112
#include <linux/module.h>
1213
#include <linux/moduleparam.h>
1314
#include <linux/pci.h>
@@ -350,29 +351,43 @@ static u32 calc_l1ss_pwron(struct pci_dev *pdev, u32 scale, u32 val)
350351
return 0;
351352
}
352353

354+
/*
355+
* Encode an LTR_L1.2_THRESHOLD value for the L1 PM Substates Control 1
356+
* register. Ports enter L1.2 when the most recent LTR value is greater
357+
* than or equal to LTR_L1.2_THRESHOLD, so we round up to make sure we
358+
* don't enter L1.2 too aggressively.
359+
*
360+
* See PCIe r6.0, sec 5.5.1, 6.18, 7.8.3.3.
361+
*/
353362
static void encode_l12_threshold(u32 threshold_us, u32 *scale, u32 *value)
354363
{
355-
u32 threshold_ns = threshold_us * 1000;
364+
u64 threshold_ns = (u64) threshold_us * 1000;
356365

357-
/* See PCIe r3.1, sec 7.33.3 and sec 6.18 */
358-
if (threshold_ns < 32) {
359-
*scale = 0;
366+
/*
367+
* LTR_L1.2_THRESHOLD_Value ("value") is a 10-bit field with max
368+
* value of 0x3ff.
369+
*/
370+
if (threshold_ns <= 0x3ff * 1) {
371+
*scale = 0; /* Value times 1ns */
360372
*value = threshold_ns;
361-
} else if (threshold_ns < 1024) {
362-
*scale = 1;
363-
*value = threshold_ns >> 5;
364-
} else if (threshold_ns < 32768) {
365-
*scale = 2;
366-
*value = threshold_ns >> 10;
367-
} else if (threshold_ns < 1048576) {
368-
*scale = 3;
369-
*value = threshold_ns >> 15;
370-
} else if (threshold_ns < 33554432) {
371-
*scale = 4;
372-
*value = threshold_ns >> 20;
373+
} else if (threshold_ns <= 0x3ff * 32) {
374+
*scale = 1; /* Value times 32ns */
375+
*value = roundup(threshold_ns, 32) / 32;
376+
} else if (threshold_ns <= 0x3ff * 1024) {
377+
*scale = 2; /* Value times 1024ns */
378+
*value = roundup(threshold_ns, 1024) / 1024;
379+
} else if (threshold_ns <= 0x3ff * 32768) {
380+
*scale = 3; /* Value times 32768ns */
381+
*value = roundup(threshold_ns, 32768) / 32768;
382+
} else if (threshold_ns <= 0x3ff * 1048576) {
383+
*scale = 4; /* Value times 1048576ns */
384+
*value = roundup(threshold_ns, 1048576) / 1048576;
385+
} else if (threshold_ns <= 0x3ff * (u64) 33554432) {
386+
*scale = 5; /* Value times 33554432ns */
387+
*value = roundup(threshold_ns, 33554432) / 33554432;
373388
} else {
374389
*scale = 5;
375-
*value = threshold_ns >> 25;
390+
*value = 0x3ff; /* Max representable value */
376391
}
377392
}
378393

0 commit comments

Comments
 (0)