|
8 | 8 | */
|
9 | 9 |
|
10 | 10 | #include <linux/kernel.h>
|
| 11 | +#include <linux/math.h> |
11 | 12 | #include <linux/module.h>
|
12 | 13 | #include <linux/moduleparam.h>
|
13 | 14 | #include <linux/pci.h>
|
@@ -350,29 +351,43 @@ static u32 calc_l1ss_pwron(struct pci_dev *pdev, u32 scale, u32 val)
|
350 | 351 | return 0;
|
351 | 352 | }
|
352 | 353 |
|
| 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 | + */ |
353 | 362 | static void encode_l12_threshold(u32 threshold_us, u32 *scale, u32 *value)
|
354 | 363 | {
|
355 |
| - u32 threshold_ns = threshold_us * 1000; |
| 364 | + u64 threshold_ns = (u64) threshold_us * 1000; |
356 | 365 |
|
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 */ |
360 | 372 | *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; |
373 | 388 | } else {
|
374 | 389 | *scale = 5;
|
375 |
| - *value = threshold_ns >> 25; |
| 390 | + *value = 0x3ff; /* Max representable value */ |
376 | 391 | }
|
377 | 392 | }
|
378 | 393 |
|
|
0 commit comments