Felix Singer would like Nico Huber to review this change.

View Change

libpayload/x86: Try to discover invariant TSC rate

We can skip the PIT-based TSC calibration if we can derive the invariant
TSC rate from platform data. This is also necessary if the PIT is dis-
abled, which is the default, for instance, on Coffee Lake CPUs.

Change-Id: I34eed1cbf14a8bf3fe6d58f51a4be139f4d30759
Signed-off-by: Nico Huber <nico.huber@secunet.com>
---
M payloads/libpayload/arch/x86/timer.c
1 file changed, 58 insertions(+), 2 deletions(-)

git pull ssh://review.coreboot.org:29418/coreboot refs/changes/30/39830/1
diff --git a/payloads/libpayload/arch/x86/timer.c b/payloads/libpayload/arch/x86/timer.c
index bf0c30a..6b07e17 100644
--- a/payloads/libpayload/arch/x86/timer.c
+++ b/payloads/libpayload/arch/x86/timer.c
@@ -34,6 +34,10 @@

#include <libpayload.h>
#include <arch/rdtsc.h>
+#include <arch/cpuid.h>
+#include <arch/msr.h>
+
+#define MSR_PLATFORM_INFO 0xce

/**
* @ingroup arch
@@ -46,7 +50,7 @@
*
* @return The CPU speed in kHz.
*/
-unsigned int get_cpu_speed(void)
+static unsigned int calibrate_pit(void)
{
unsigned long long start, end;
const uint32_t clock_rate = 1193182; // 1.193182 MHz
@@ -72,7 +76,59 @@
* clock_rate / (interval * 1000). Multiply that by the number of
* measured clocks to get the kHz value.
*/
- cpu_khz = (end - start) * clock_rate / (1000 * interval);
+ return (end - start) * clock_rate / (1000 * interval);
+}
+
+/**
+ * @brief Returns three times the bus clock in MHz
+ *
+ * The result of calculations with the returned value shall be divided by 3.
+ * This helps to avoid rounding errors.
+ */
+static int get_bus_khz_x3(void)
+{
+ uint32_t eax, ebx, ecx, edx;
+ cpuid(1, eax, ebx, ecx, edx);
+
+ /* Check for family 6 */
+ if (((eax & 0xff00000) >> (20 - 4)) | ((eax & 0xf00) >> 8 != 6))
+ return -1;
+
+ switch (((eax & 0xf0000) >> (16 - 4)) | ((eax & 0xf0) >> 4)) {
+ case 0x25: /* Nehalem */
+ return 400 * 1000; /* 133 MHz */
+ case 0x2a: /* SandyBridge */
+ case 0x3a: /* IvyBridge */
+ case 0x3c: /* Haswell */
+ case 0x45: /* Haswell-ULT */
+ case 0x9e: /* Coffee Lake H */
+ return 300 * 1000; /* 100 MHz */
+ default:
+ return -1;
+ }
+}
+
+/*
+ * Systems with an invariant TSC report the multiplier (maximum
+ * non-turbo ratio) in MSR_PLATFORM_INFO[15:8].
+ */
+static int get_cpu_khz_fast(void)
+{
+ const int bus_x3 = get_bus_khz_x3();
+ if (bus_x3 <= 0)
+ return -1;
+
+ const unsigned int mult = _rdmsr(MSR_PLATFORM_INFO) >> 8 & 0xff;
+ return (bus_x3 * mult) / 3;
+}
+
+unsigned int get_cpu_speed(void)
+{
+ const int cpu_khz_fast = get_cpu_khz_fast();
+ if (cpu_khz_fast > 0)
+ cpu_khz = (unsigned int)cpu_khz_fast;
+ else
+ cpu_khz = calibrate_pit();

return cpu_khz;
}

To view, visit change 39830. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: coreboot
Gerrit-Branch: master
Gerrit-Change-Id: I34eed1cbf14a8bf3fe6d58f51a4be139f4d30759
Gerrit-Change-Number: 39830
Gerrit-PatchSet: 1
Gerrit-Owner: Felix Singer <felixsinger@posteo.net>
Gerrit-Reviewer: Nico Huber <nico.h@gmx.de>
Gerrit-MessageType: newchange