2 * This code largely moved from arch/i386/kernel/time.c.
3 * See comments there for proper credits.
6 #include <linux/spinlock.h>
7 #include <linux/init.h>
8 #include <linux/timex.h>
9 #include <linux/errno.h>
10 #include <linux/string.h>
11 #include <linux/jiffies.h>
13 #include <asm/timer.h>
15 #include <asm/processor.h>
18 #include "mach_timer.h"
21 static unsigned long hpet_usec_quotient
; /* convert hpet clks to usec */
22 static unsigned long tsc_hpet_quotient
; /* convert tsc to hpet clks */
23 static unsigned long hpet_last
; /* hpet counter value at last tick*/
24 static unsigned long last_tsc_low
; /* lsb 32 bits of Time Stamp Counter */
25 static unsigned long last_tsc_high
; /* msb 32 bits of Time Stamp Counter */
26 static unsigned long long monotonic_base
;
27 static seqlock_t monotonic_lock
= SEQLOCK_UNLOCKED
;
29 /* convert from cycles(64bits) => nanoseconds (64bits)
31 * ns = cycles / (freq / ns_per_sec)
32 * ns = cycles * (ns_per_sec / freq)
33 * ns = cycles * (10^9 / (cpu_mhz * 10^6))
34 * ns = cycles * (10^3 / cpu_mhz)
36 * Then we use scaling math (suggested by george@mvista.com) to get:
37 * ns = cycles * (10^3 * SC / cpu_mhz) / SC
38 * ns = cycles * cyc2ns_scale / SC
40 * And since SC is a constant power of two, we can convert the div
42 * -johnstul@us.ibm.com "math is hard, lets go shopping!"
44 static unsigned long cyc2ns_scale
;
45 #define CYC2NS_SCALE_FACTOR 10 /* 2^10, carefully chosen */
47 static inline void set_cyc2ns_scale(unsigned long cpu_mhz
)
49 cyc2ns_scale
= (1000 << CYC2NS_SCALE_FACTOR
)/cpu_mhz
;
52 static inline unsigned long long cycles_2_ns(unsigned long long cyc
)
54 return (cyc
* cyc2ns_scale
) >> CYC2NS_SCALE_FACTOR
;
57 static unsigned long long monotonic_clock_hpet(void)
59 unsigned long long last_offset
, this_offset
, base
;
62 /* atomically read monotonic base & last_offset */
64 seq
= read_seqbegin(&monotonic_lock
);
65 last_offset
= ((unsigned long long)last_tsc_high
<<32)|last_tsc_low
;
66 base
= monotonic_base
;
67 } while (read_seqretry(&monotonic_lock
, seq
));
69 /* Read the Time Stamp Counter */
72 /* return the value in ns */
73 return base
+ cycles_2_ns(this_offset
- last_offset
);
76 static unsigned long get_offset_hpet(void)
78 register unsigned long eax
, edx
;
80 eax
= hpet_readl(HPET_COUNTER
);
81 eax
-= hpet_last
; /* hpet delta */
82 eax
= min(hpet_tick
, eax
);
84 * Time offset = (hpet delta) * ( usecs per HPET clock )
85 * = (hpet delta) * ( usecs per tick / HPET clocks per tick)
86 * = (hpet delta) * ( hpet_usec_quotient ) / (2^32)
89 * hpet_usec_quotient = (2^32 * usecs per tick)/HPET clocks per tick
91 * Using a mull instead of a divl saves some cycles in critical path.
93 ASM_MUL64_REG(eax
, edx
, hpet_usec_quotient
, eax
);
95 /* our adjusted time offset in microseconds */
99 static void mark_offset_hpet(void)
101 unsigned long long this_offset
, last_offset
;
102 unsigned long offset
;
104 write_seqlock(&monotonic_lock
);
105 last_offset
= ((unsigned long long)last_tsc_high
<<32)|last_tsc_low
;
106 rdtsc(last_tsc_low
, last_tsc_high
);
109 offset
= hpet_readl(HPET_T0_CMP
) - hpet_tick
;
111 offset
= hpet_readl(HPET_COUNTER
);
112 if (unlikely(((offset
- hpet_last
) >= (2*hpet_tick
)) && (hpet_last
!= 0))) {
113 int lost_ticks
= ((offset
- hpet_last
) / hpet_tick
) - 1;
114 jiffies_64
+= lost_ticks
;
118 /* update the monotonic base value */
119 this_offset
= ((unsigned long long)last_tsc_high
<<32)|last_tsc_low
;
120 monotonic_base
+= cycles_2_ns(this_offset
- last_offset
);
121 write_sequnlock(&monotonic_lock
);
124 static void delay_hpet(unsigned long loops
)
126 unsigned long hpet_start
, hpet_end
;
129 /* loops is the number of cpu cycles. Convert it to hpet clocks */
130 ASM_MUL64_REG(eax
, loops
, tsc_hpet_quotient
, loops
);
132 hpet_start
= hpet_readl(HPET_COUNTER
);
135 hpet_end
= hpet_readl(HPET_COUNTER
);
136 } while ((hpet_end
- hpet_start
) < (loops
));
139 static int __init
init_hpet(char* override
)
141 unsigned long result
, remain
;
143 /* check clock override */
144 if (override
[0] && strncmp(override
,"hpet",4))
147 if (!is_hpet_enabled())
150 printk("Using HPET for gettimeofday\n");
152 unsigned long tsc_quotient
= calibrate_tsc_hpet(&tsc_hpet_quotient
);
154 /* report CPU clock rate in Hz.
155 * The formula is (10^6 * 2^32) / (2^32 * 1 / (clocks/us)) =
156 * clock/second. Our precision is about 100 ppm.
158 { unsigned long eax
=0, edx
=1000;
159 ASM_DIV64_REG(cpu_khz
, edx
, tsc_quotient
,
161 printk("Detected %lu.%03lu MHz processor.\n",
162 cpu_khz
/ 1000, cpu_khz
% 1000);
164 set_cyc2ns_scale(cpu_khz
/1000);
169 * Math to calculate hpet to usec multiplier
170 * Look for the comments at get_offset_hpet()
172 ASM_DIV64_REG(result
, remain
, hpet_tick
, 0, KERNEL_TICK_USEC
);
173 if (remain
> (hpet_tick
>> 1))
174 result
++; /* rounding the result */
175 hpet_usec_quotient
= result
;
180 /************************************************************/
182 /* tsc timer_opts struct */
183 static struct timer_opts timer_hpet
= {
185 .mark_offset
= mark_offset_hpet
,
186 .get_offset
= get_offset_hpet
,
187 .monotonic_clock
= monotonic_clock_hpet
,
191 struct init_timer_opts __initdata timer_hpet_init
= {