local_irq_save(flags);
 
-       /* run 3 times to ensure the cache is warm */
+       /* run 3 times to ensure the cache is warm and to get an accurate reading */
        for (i = 0; i < 3; i++) {
                mach_prepare_counter();
                rdtscll(start);
                mach_countup(&count);
                rdtscll(end);
+
+               /*
+                * Error: ECTCNEVERSET
+                * The CTC wasn't reliable: we got a hit on the very first read,
+                * or the CPU was so fast/slow that the quotient wouldn't fit in
+                * 32 bits..
+                */
+               if (count <= 1)
+                       continue;
+
+               /* cpu freq too slow: */
+               if ((end - start) <= CALIBRATE_TIME_MSEC)
+                       continue;
+
+               /*
+                * We want the minimum time of all runs in case one of them
+                * is inaccurate due to SMI or other delay
+                */
                delta64 = min(delta64, (end - start));
        }
-       /*
-        * Error: ECTCNEVERSET
-        * The CTC wasn't reliable: we got a hit on the very first read,
-        * or the CPU was so fast/slow that the quotient wouldn't fit in
-        * 32 bits..
-        */
-       if (count <= 1)
-               goto err;
 
-       /* cpu freq too fast: */
+       /* cpu freq too fast (or every run was bad): */
        if (delta64 > (1ULL<<32))
                goto err;
 
-       /* cpu freq too slow: */
-       if (delta64 <= CALIBRATE_TIME_MSEC)
-               goto err;
-
        delta64 += CALIBRATE_TIME_MSEC/2; /* round for do_div */
        do_div(delta64,CALIBRATE_TIME_MSEC);