x86: tsc: Try hardware calibration first
authorBin Meng <bmeng.cn@gmail.com>
Fri, 10 Aug 2018 09:39:36 +0000 (02:39 -0700)
committerBin Meng <bmeng.cn@gmail.com>
Mon, 20 Aug 2018 05:52:49 +0000 (13:52 +0800)
At present if TSC frequency is provided in the device tree, it takes
precedence over hardware calibration result. This swaps the order to
try hardware calibration first and uses device tree as last resort.

This can be helpful when a generic dts (eg: coreboot/efi payload) is
supposed to work on as many hardware as possible, including emulators
like QEMU where TSC hardware calibration sometimes fails.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Christian Gmeiner <christian.gmeiner@gmail.com>
drivers/timer/tsc_timer.c

index 747f190d3845a60fac6d1e1e5d90071525d9b028..6473de20f1300019f3539f767d741b1c5ac7a6f9 100644 (file)
@@ -341,16 +341,12 @@ static int tsc_timer_get_count(struct udevice *dev, u64 *count)
        return 0;
 }
 
-static void tsc_timer_ensure_setup(void)
+static void tsc_timer_ensure_setup(bool stop)
 {
        if (gd->arch.tsc_base)
                return;
        gd->arch.tsc_base = rdtsc();
 
-       /*
-        * If there is no clock frequency specified in the device tree,
-        * calibrate it by ourselves.
-        */
        if (!gd->arch.clock_rate) {
                unsigned long fast_calibrate;
 
@@ -366,7 +362,10 @@ static void tsc_timer_ensure_setup(void)
                if (fast_calibrate)
                        goto done;
 
-               panic("TSC frequency is ZERO");
+               if (stop)
+                       panic("TSC frequency is ZERO");
+               else
+                       return;
 
 done:
                gd->arch.clock_rate = fast_calibrate * 1000000;
@@ -377,11 +376,17 @@ static int tsc_timer_probe(struct udevice *dev)
 {
        struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
 
-       if (!uc_priv->clock_rate) {
-               tsc_timer_ensure_setup();
-               uc_priv->clock_rate = gd->arch.clock_rate;
+       /* Try hardware calibration first */
+       tsc_timer_ensure_setup(false);
+       if (!gd->arch.clock_rate) {
+               /*
+                * Use the clock frequency specified in the
+                * device tree as last resort
+                */
+               if (!uc_priv->clock_rate)
+                       panic("TSC frequency is ZERO");
        } else {
-               gd->arch.tsc_base = rdtsc();
+               uc_priv->clock_rate = gd->arch.clock_rate;
        }
 
        return 0;
@@ -394,7 +399,7 @@ unsigned long notrace timer_early_get_rate(void)
         * clock rate can only be calibrated via some hardware ways. Specifying
         * it in the device tree won't work for the early timer.
         */
-       tsc_timer_ensure_setup();
+       tsc_timer_ensure_setup(true);
 
        return gd->arch.clock_rate;
 }