tsc: Change default tsc calibration method to pmtimer on EFI systems
[grub.git] / grub-core / kern / i386 / tsc.c
1 /* kern/i386/tsc.c - x86 TSC time source implementation
2  * Requires Pentium or better x86 CPU that supports the RDTSC instruction.
3  * This module calibrates the TSC to real time.
4  *
5  *  GRUB  --  GRand Unified Bootloader
6  *  Copyright (C) 2008  Free Software Foundation, Inc.
7  *
8  *  GRUB is free software: you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation, either version 3 of the License, or
11  *  (at your option) any later version.
12  *
13  *  GRUB is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
20  */
21
22 #include <grub/types.h>
23 #include <grub/time.h>
24 #include <grub/misc.h>
25 #include <grub/i386/tsc.h>
26 #include <grub/i386/cpuid.h>
27
28 /* This defines the value TSC had at the epoch (that is, when we calibrated it). */
29 static grub_uint64_t tsc_boot_time;
30
31 /* Calibrated TSC rate.  (In ms per 2^32 ticks) */
32 /* We assume that the tick is less than 1 ms and hence this value fits
33    in 32-bit.  */
34 grub_uint32_t grub_tsc_rate;
35
36 static grub_uint64_t
37 grub_tsc_get_time_ms (void)
38 {
39   grub_uint64_t a = grub_get_tsc () - tsc_boot_time;
40   grub_uint64_t ah = a >> 32;
41   grub_uint64_t al = a & 0xffffffff;
42
43   return ((al * grub_tsc_rate) >> 32) + ah * grub_tsc_rate;
44 }
45
46 static int
47 calibrate_tsc_hardcode (void)
48 {
49   grub_tsc_rate = 5368;/* 800 MHz */
50   return 1;
51 }
52
53 void
54 grub_tsc_init (void)
55 {
56   if (!grub_cpu_is_tsc_supported ())
57     {
58 #if defined (GRUB_MACHINE_PCBIOS) || defined (GRUB_MACHINE_IEEE1275)
59       grub_install_get_time_ms (grub_rtc_get_time_ms);
60 #else
61       grub_fatal ("no TSC found");
62 #endif
63       return;
64     }
65
66   tsc_boot_time = grub_get_tsc ();
67
68 #ifdef GRUB_MACHINE_XEN
69   (void) (grub_tsc_calibrate_from_xen () || calibrate_tsc_hardcode());
70 #elif defined (GRUB_MACHINE_EFI)
71   (void) (grub_tsc_calibrate_from_pmtimer () || grub_tsc_calibrate_from_pit () || grub_tsc_calibrate_from_efi() || calibrate_tsc_hardcode());
72 #elif defined (GRUB_MACHINE_COREBOOT)
73   (void) (grub_tsc_calibrate_from_pmtimer () || grub_tsc_calibrate_from_pit () || calibrate_tsc_hardcode());
74 #else
75   (void) (grub_tsc_calibrate_from_pit () || calibrate_tsc_hardcode());
76 #endif
77   grub_install_get_time_ms (grub_tsc_get_time_ms);
78 }