Cleanups
[people/mdeck/gpxe.git] / src / arch / i386 / drivers / timer_rtdsc.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 static unsigned long long calibrate_tsc(void)
18 {
19         uint32_t startlow, starthigh;
20         uint32_t endlow, endhigh;
21
22         rdtsc(startlow,starthigh);
23         i386_timer2_udelay(USECS_IN_MSEC/2);
24         rdtsc(endlow,endhigh);
25
26         /* 64-bit subtract - gcc just messes up with long longs */
27         /* XXX ORLY? Check it. */
28         __asm__("subl %2,%0\n\t"
29                 "sbbl %3,%1"
30                 :"=a" (endlow), "=d" (endhigh)
31                 :"g" (startlow), "g" (starthigh),
32                 "0" (endlow), "1" (endhigh));
33
34         /* Error: ECPUTOOFAST */
35         if (endhigh)
36                 goto bad_ctc;
37
38         endlow *= MSECS_IN_SEC*2;
39         return endlow;
40
41         /*
42          * The CTC wasn't reliable: we got a hit on the very first read,
43          * or the CPU was so fast/slow that the quotient wouldn't fit in
44          * 32 bits..
45          */
46 bad_ctc:
47         return 0;
48 }
49 static uint32_t clocks_per_second = 0;
50
51 static tick_t rtdsc_currticks(void)
52 {
53         uint32_t clocks_high, clocks_low;
54         uint32_t currticks;
55
56         /* Read the Time Stamp Counter */
57         rdtsc(clocks_low, clocks_high);
58
59         /* currticks = clocks / clocks_per_tick; */
60         __asm__("divl %1"
61                 :"=a" (currticks)
62                 :"r" (clocks_per_second/USECS_IN_SEC), "0" (clocks_low), "d" (clocks_high));
63
64         return currticks;
65 }
66
67 static int rtdsc_ts_init(void)
68 {
69
70         struct cpuinfo_x86 cpu_info;
71
72         get_cpuinfo(&cpu_info);
73         if (cpu_info.features & X86_FEATURE_TSC) {
74                 clocks_per_second = calibrate_tsc();
75                 if (clocks_per_second) {
76                         DBG("RTDSC Ticksource installed. CPU running at %ld Mhz\n",
77                                 clocks_per_second/(1000*1000));
78                         return 0;
79                 }
80         }
81
82         DBG("RTDSC timer not available on this machine.\n");
83         return -ENODEV;
84 }
85
86 struct timer rtdsc_ts __timer (01) = {
87         .init = rtdsc_ts_init,
88         .udelay = generic_currticks_udelay,
89         .currticks = rtdsc_currticks,
90 };
91