]> Git Repo - J-u-boot.git/blobdiff - drivers/timer/tsc_timer.c
x86: Avoid timer-clock overflow
[J-u-boot.git] / drivers / timer / tsc_timer.c
index 813817f467265e04e750aee930c5fcab7e19c846..2f2c2f27b7ff07af38c12d4780e9b486906baa09 100644 (file)
@@ -6,17 +6,20 @@
  * arch/x86/kernel/tsc_msr.c and arch/x86/kernel/tsc.c
  */
 
-#include <common.h>
+#include <bootstage.h>
 #include <dm.h>
+#include <log.h>
 #include <malloc.h>
 #include <time.h>
 #include <timer.h>
 #include <asm/cpu.h>
+#include <asm/global_data.h>
 #include <asm/io.h>
 #include <asm/i8254.h>
 #include <asm/ibmpc.h>
 #include <asm/msr.h>
 #include <asm/u-boot-x86.h>
+#include <linux/delay.h>
 
 #define MAX_NUM_FREQS  9
 
@@ -50,8 +53,7 @@ static unsigned long native_calibrate_tsc(void)
                return 0;
 
        crystal_freq = tsc_info.ecx / 1000;
-
-       if (!crystal_freq) {
+       if (!CONFIG_IS_ENABLED(X86_TSC_TIMER_NATIVE) && !crystal_freq) {
                switch (gd->arch.x86_model) {
                case INTEL_FAM6_SKYLAKE_MOBILE:
                case INTEL_FAM6_SKYLAKE_DESKTOP:
@@ -370,7 +372,7 @@ void __udelay(unsigned long usec)
        u64 now = get_ticks();
        u64 stop;
 
-       stop = now + usec * get_tbclk_mhz();
+       stop = now + (u64)usec * get_tbclk_mhz();
 
        while ((int64_t)(stop - get_ticks()) > 0)
 #if defined(CONFIG_QEMU) && defined(CONFIG_SMP)
@@ -384,13 +386,11 @@ void __udelay(unsigned long usec)
 #endif
 }
 
-static int tsc_timer_get_count(struct udevice *dev, u64 *count)
+static u64 tsc_timer_get_count(struct udevice *dev)
 {
        u64 now_tick = rdtsc();
 
-       *count = now_tick - gd->arch.tsc_base;
-
-       return 0;
+       return now_tick - gd->arch.tsc_base;
 }
 
 static void tsc_timer_ensure_setup(bool early)
@@ -403,10 +403,27 @@ static void tsc_timer_ensure_setup(bool early)
        if (!gd->arch.clock_rate) {
                unsigned long fast_calibrate;
 
+               /* deal with this being called before x86_cpu_init_f() */
+               if (!gd->arch.x86_vendor)
+                       x86_get_identity_for_timer();
+
+               /**
+                * There is no obvious way to obtain this information from EFI
+                * boot services. This value was measured on a Framework Laptop
+                * which has a 12th Gen Intel Core
+                */
+               if (IS_ENABLED(CONFIG_EFI_APP)) {
+                       fast_calibrate = 2750;
+                       goto done;
+               }
                fast_calibrate = native_calibrate_tsc();
                if (fast_calibrate)
                        goto done;
 
+               /* Reduce code size by dropping other methods */
+               if (CONFIG_IS_ENABLED(X86_TSC_TIMER_NATIVE))
+                       panic("no timer");
+
                fast_calibrate = cpu_mhz_from_cpuid();
                if (fast_calibrate)
                        goto done;
@@ -420,12 +437,14 @@ static void tsc_timer_ensure_setup(bool early)
                        goto done;
 
                if (early)
-                       fast_calibrate = CONFIG_X86_TSC_TIMER_EARLY_FREQ;
+                       gd->arch.clock_rate = CONFIG_X86_TSC_TIMER_FREQ;
                else
                        return;
 
 done:
-               gd->arch.clock_rate = fast_calibrate * 1000000;
+               fast_calibrate = min(fast_calibrate, 4000UL);
+               if (!gd->arch.clock_rate)
+                       gd->arch.clock_rate = fast_calibrate * 1000000;
        }
        gd->arch.tsc_inited = true;
 }
@@ -473,15 +492,17 @@ static const struct timer_ops tsc_timer_ops = {
        .get_count = tsc_timer_get_count,
 };
 
+#if CONFIG_IS_ENABLED(OF_REAL)
 static const struct udevice_id tsc_timer_ids[] = {
        { .compatible = "x86,tsc-timer", },
        { }
 };
+#endif
 
-U_BOOT_DRIVER(tsc_timer) = {
-       .name   = "tsc_timer",
+U_BOOT_DRIVER(x86_tsc_timer) = {
+       .name   = "x86_tsc_timer",
        .id     = UCLASS_TIMER,
-       .of_match = tsc_timer_ids,
+       .of_match = of_match_ptr(tsc_timer_ids),
        .probe = tsc_timer_probe,
        .ops    = &tsc_timer_ops,
 };
This page took 0.029218 seconds and 4 git commands to generate.