Use plain C in timer_rdtsc for division instead of inline asssembly.
[people/sha0/gpxe.git] / src / arch / i386 / drivers / timer_rdtsc.c
1
2 #include <gpxe/init.h>
3 #include <gpxe/timer.h>
4 #include <errno.h>
5 #include <stdio.h>
6 #include <bits/cpu.h>
7 #include <bits/timer2.h>
8 #include <io.h>
9
10
11 #define rdtsc(low,high) \
12      __asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high))
13
14 #define rdtscll(val) \
15      __asm__ __volatile__ ("rdtsc" : "=A" (val))
16
17
18 /* Measure how many clocks we get in one microsecond */
19 static inline uint64_t calibrate_tsc(void)
20 {
21
22         uint64_t rdtsc_start;
23         uint64_t rdtsc_end;
24
25         rdtscll(rdtsc_start);
26         i386_timer2_udelay(USECS_IN_MSEC);
27         rdtscll(rdtsc_end);
28         
29         return (rdtsc_end - rdtsc_start) / USECS_IN_MSEC;
30 }
31
32 static uint32_t clocks_per_usec = 0;
33
34 /* We measure time in microseconds. */
35 static tick_t rdtsc_currticks(void)
36 {
37         uint64_t clocks;
38
39         /* Read the Time Stamp Counter */
40         rdtscll(clocks);
41
42         return clocks / clocks_per_usec;
43 }
44
45 static int rdtsc_ts_init(void)
46 {
47
48         struct cpuinfo_x86 cpu_info;
49
50         get_cpuinfo(&cpu_info);
51         if (cpu_info.features & X86_FEATURE_TSC) {
52                 clocks_per_usec= calibrate_tsc();
53                 if (clocks_per_usec) {
54                         DBG("RDTSC ticksource installed. CPU running at %ld Mhz\n",
55                                 clocks_per_usec);
56                         return 0;
57                 }
58         }
59
60         DBG("RDTSC ticksource not available on this machine.\n");
61         return -ENODEV;
62 }
63
64 struct timer rdtsc_ts __timer (01) = {
65         .init = rdtsc_ts_init,
66         .udelay = generic_currticks_udelay,
67         .currticks = rdtsc_currticks,
68 };
69