diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/i386/kernel/hpet.c | 80 | ||||
-rw-r--r-- | arch/i386/kernel/i8253.c | 2 | ||||
-rw-r--r-- | arch/i386/kernel/setup.c | 1 | ||||
-rw-r--r-- | arch/i386/kernel/time.c | 1 | ||||
-rw-r--r-- | arch/i386/kernel/tsc.c | 83 | ||||
-rw-r--r-- | arch/x86_64/kernel/hpet.c | 109 | ||||
-rw-r--r-- | arch/x86_64/kernel/time.c | 2 | ||||
-rw-r--r-- | arch/x86_64/kernel/tsc.c | 7 |
8 files changed, 124 insertions, 161 deletions
diff --git a/arch/i386/kernel/hpet.c b/arch/i386/kernel/hpet.c index e1006b7acc9e..f3ab61ee7498 100644 --- a/arch/i386/kernel/hpet.c +++ b/arch/i386/kernel/hpet.c | |||
@@ -201,12 +201,30 @@ static int hpet_next_event(unsigned long delta, | |||
201 | } | 201 | } |
202 | 202 | ||
203 | /* | 203 | /* |
204 | * Clock source related code | ||
205 | */ | ||
206 | static cycle_t read_hpet(void) | ||
207 | { | ||
208 | return (cycle_t)hpet_readl(HPET_COUNTER); | ||
209 | } | ||
210 | |||
211 | static struct clocksource clocksource_hpet = { | ||
212 | .name = "hpet", | ||
213 | .rating = 250, | ||
214 | .read = read_hpet, | ||
215 | .mask = HPET_MASK, | ||
216 | .shift = HPET_SHIFT, | ||
217 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, | ||
218 | }; | ||
219 | |||
220 | /* | ||
204 | * Try to setup the HPET timer | 221 | * Try to setup the HPET timer |
205 | */ | 222 | */ |
206 | int __init hpet_enable(void) | 223 | int __init hpet_enable(void) |
207 | { | 224 | { |
208 | unsigned long id; | 225 | unsigned long id; |
209 | uint64_t hpet_freq; | 226 | uint64_t hpet_freq; |
227 | u64 tmp; | ||
210 | 228 | ||
211 | if (!is_hpet_capable()) | 229 | if (!is_hpet_capable()) |
212 | return 0; | 230 | return 0; |
@@ -253,6 +271,25 @@ int __init hpet_enable(void) | |||
253 | /* Start the counter */ | 271 | /* Start the counter */ |
254 | hpet_start_counter(); | 272 | hpet_start_counter(); |
255 | 273 | ||
274 | /* Initialize and register HPET clocksource | ||
275 | * | ||
276 | * hpet period is in femto seconds per cycle | ||
277 | * so we need to convert this to ns/cyc units | ||
278 | * aproximated by mult/2^shift | ||
279 | * | ||
280 | * fsec/cyc * 1nsec/1000000fsec = nsec/cyc = mult/2^shift | ||
281 | * fsec/cyc * 1ns/1000000fsec * 2^shift = mult | ||
282 | * fsec/cyc * 2^shift * 1nsec/1000000fsec = mult | ||
283 | * (fsec/cyc << shift)/1000000 = mult | ||
284 | * (hpet_period << shift)/FSEC_PER_NSEC = mult | ||
285 | */ | ||
286 | tmp = (u64)hpet_period << HPET_SHIFT; | ||
287 | do_div(tmp, FSEC_PER_NSEC); | ||
288 | clocksource_hpet.mult = (u32)tmp; | ||
289 | |||
290 | clocksource_register(&clocksource_hpet); | ||
291 | |||
292 | |||
256 | if (id & HPET_ID_LEGSUP) { | 293 | if (id & HPET_ID_LEGSUP) { |
257 | hpet_enable_int(); | 294 | hpet_enable_int(); |
258 | hpet_reserve_platform_timers(id); | 295 | hpet_reserve_platform_timers(id); |
@@ -273,49 +310,6 @@ out_nohpet: | |||
273 | return 0; | 310 | return 0; |
274 | } | 311 | } |
275 | 312 | ||
276 | /* | ||
277 | * Clock source related code | ||
278 | */ | ||
279 | static cycle_t read_hpet(void) | ||
280 | { | ||
281 | return (cycle_t)hpet_readl(HPET_COUNTER); | ||
282 | } | ||
283 | |||
284 | static struct clocksource clocksource_hpet = { | ||
285 | .name = "hpet", | ||
286 | .rating = 250, | ||
287 | .read = read_hpet, | ||
288 | .mask = HPET_MASK, | ||
289 | .shift = HPET_SHIFT, | ||
290 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, | ||
291 | }; | ||
292 | |||
293 | static int __init init_hpet_clocksource(void) | ||
294 | { | ||
295 | u64 tmp; | ||
296 | |||
297 | if (!hpet_virt_address) | ||
298 | return -ENODEV; | ||
299 | |||
300 | /* | ||
301 | * hpet period is in femto seconds per cycle | ||
302 | * so we need to convert this to ns/cyc units | ||
303 | * aproximated by mult/2^shift | ||
304 | * | ||
305 | * fsec/cyc * 1nsec/1000000fsec = nsec/cyc = mult/2^shift | ||
306 | * fsec/cyc * 1ns/1000000fsec * 2^shift = mult | ||
307 | * fsec/cyc * 2^shift * 1nsec/1000000fsec = mult | ||
308 | * (fsec/cyc << shift)/1000000 = mult | ||
309 | * (hpet_period << shift)/FSEC_PER_NSEC = mult | ||
310 | */ | ||
311 | tmp = (u64)hpet_period << HPET_SHIFT; | ||
312 | do_div(tmp, FSEC_PER_NSEC); | ||
313 | clocksource_hpet.mult = (u32)tmp; | ||
314 | |||
315 | return clocksource_register(&clocksource_hpet); | ||
316 | } | ||
317 | |||
318 | module_init(init_hpet_clocksource); | ||
319 | 313 | ||
320 | #ifdef CONFIG_HPET_EMULATE_RTC | 314 | #ifdef CONFIG_HPET_EMULATE_RTC |
321 | 315 | ||
diff --git a/arch/i386/kernel/i8253.c b/arch/i386/kernel/i8253.c index a6bc7bb38834..5cbb776b3089 100644 --- a/arch/i386/kernel/i8253.c +++ b/arch/i386/kernel/i8253.c | |||
@@ -195,4 +195,4 @@ static int __init init_pit_clocksource(void) | |||
195 | clocksource_pit.mult = clocksource_hz2mult(CLOCK_TICK_RATE, 20); | 195 | clocksource_pit.mult = clocksource_hz2mult(CLOCK_TICK_RATE, 20); |
196 | return clocksource_register(&clocksource_pit); | 196 | return clocksource_register(&clocksource_pit); |
197 | } | 197 | } |
198 | module_init(init_pit_clocksource); | 198 | arch_initcall(init_pit_clocksource); |
diff --git a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c index 122623dcc6e1..698c24fe482e 100644 --- a/arch/i386/kernel/setup.c +++ b/arch/i386/kernel/setup.c | |||
@@ -657,5 +657,4 @@ void __init setup_arch(char **cmdline_p) | |||
657 | conswitchp = &dummy_con; | 657 | conswitchp = &dummy_con; |
658 | #endif | 658 | #endif |
659 | #endif | 659 | #endif |
660 | tsc_init(); | ||
661 | } | 660 | } |
diff --git a/arch/i386/kernel/time.c b/arch/i386/kernel/time.c index ccd3734edb8f..94e5cb091104 100644 --- a/arch/i386/kernel/time.c +++ b/arch/i386/kernel/time.c | |||
@@ -279,5 +279,6 @@ void __init hpet_time_init(void) | |||
279 | */ | 279 | */ |
280 | void __init time_init(void) | 280 | void __init time_init(void) |
281 | { | 281 | { |
282 | tsc_init(); | ||
282 | late_time_init = choose_time_init(); | 283 | late_time_init = choose_time_init(); |
283 | } | 284 | } |
diff --git a/arch/i386/kernel/tsc.c b/arch/i386/kernel/tsc.c index 59222a04234b..875d8a6ecc02 100644 --- a/arch/i386/kernel/tsc.c +++ b/arch/i386/kernel/tsc.c | |||
@@ -184,34 +184,6 @@ int recalibrate_cpu_khz(void) | |||
184 | 184 | ||
185 | EXPORT_SYMBOL(recalibrate_cpu_khz); | 185 | EXPORT_SYMBOL(recalibrate_cpu_khz); |
186 | 186 | ||
187 | void __init tsc_init(void) | ||
188 | { | ||
189 | if (!cpu_has_tsc || tsc_disable) | ||
190 | goto out_no_tsc; | ||
191 | |||
192 | cpu_khz = calculate_cpu_khz(); | ||
193 | tsc_khz = cpu_khz; | ||
194 | |||
195 | if (!cpu_khz) | ||
196 | goto out_no_tsc; | ||
197 | |||
198 | printk("Detected %lu.%03lu MHz processor.\n", | ||
199 | (unsigned long)cpu_khz / 1000, | ||
200 | (unsigned long)cpu_khz % 1000); | ||
201 | |||
202 | set_cyc2ns_scale(cpu_khz); | ||
203 | use_tsc_delay(); | ||
204 | return; | ||
205 | |||
206 | out_no_tsc: | ||
207 | /* | ||
208 | * Set the tsc_disable flag if there's no TSC support, this | ||
209 | * makes it a fast flag for the kernel to see whether it | ||
210 | * should be using the TSC. | ||
211 | */ | ||
212 | tsc_disable = 1; | ||
213 | } | ||
214 | |||
215 | #ifdef CONFIG_CPU_FREQ | 187 | #ifdef CONFIG_CPU_FREQ |
216 | 188 | ||
217 | /* | 189 | /* |
@@ -381,28 +353,47 @@ static void __init check_geode_tsc_reliable(void) | |||
381 | static inline void check_geode_tsc_reliable(void) { } | 353 | static inline void check_geode_tsc_reliable(void) { } |
382 | #endif | 354 | #endif |
383 | 355 | ||
384 | static int __init init_tsc_clocksource(void) | 356 | |
357 | void __init tsc_init(void) | ||
385 | { | 358 | { |
359 | if (!cpu_has_tsc || tsc_disable) | ||
360 | goto out_no_tsc; | ||
386 | 361 | ||
387 | if (cpu_has_tsc && tsc_khz && !tsc_disable) { | 362 | cpu_khz = calculate_cpu_khz(); |
388 | /* check blacklist */ | 363 | tsc_khz = cpu_khz; |
389 | dmi_check_system(bad_tsc_dmi_table); | ||
390 | 364 | ||
391 | unsynchronized_tsc(); | 365 | if (!cpu_khz) |
392 | check_geode_tsc_reliable(); | 366 | goto out_no_tsc; |
393 | current_tsc_khz = tsc_khz; | ||
394 | clocksource_tsc.mult = clocksource_khz2mult(current_tsc_khz, | ||
395 | clocksource_tsc.shift); | ||
396 | /* lower the rating if we already know its unstable: */ | ||
397 | if (check_tsc_unstable()) { | ||
398 | clocksource_tsc.rating = 0; | ||
399 | clocksource_tsc.flags &= ~CLOCK_SOURCE_IS_CONTINUOUS; | ||
400 | } | ||
401 | 367 | ||
402 | return clocksource_register(&clocksource_tsc); | 368 | printk("Detected %lu.%03lu MHz processor.\n", |
369 | (unsigned long)cpu_khz / 1000, | ||
370 | (unsigned long)cpu_khz % 1000); | ||
371 | |||
372 | set_cyc2ns_scale(cpu_khz); | ||
373 | use_tsc_delay(); | ||
374 | |||
375 | /* Check and install the TSC clocksource */ | ||
376 | dmi_check_system(bad_tsc_dmi_table); | ||
377 | |||
378 | unsynchronized_tsc(); | ||
379 | check_geode_tsc_reliable(); | ||
380 | current_tsc_khz = tsc_khz; | ||
381 | clocksource_tsc.mult = clocksource_khz2mult(current_tsc_khz, | ||
382 | clocksource_tsc.shift); | ||
383 | /* lower the rating if we already know its unstable: */ | ||
384 | if (check_tsc_unstable()) { | ||
385 | clocksource_tsc.rating = 0; | ||
386 | clocksource_tsc.flags &= ~CLOCK_SOURCE_IS_CONTINUOUS; | ||
403 | } | 387 | } |
388 | clocksource_register(&clocksource_tsc); | ||
404 | 389 | ||
405 | return 0; | 390 | return; |
406 | } | ||
407 | 391 | ||
408 | module_init(init_tsc_clocksource); | 392 | out_no_tsc: |
393 | /* | ||
394 | * Set the tsc_disable flag if there's no TSC support, this | ||
395 | * makes it a fast flag for the kernel to see whether it | ||
396 | * should be using the TSC. | ||
397 | */ | ||
398 | tsc_disable = 1; | ||
399 | } | ||
diff --git a/arch/x86_64/kernel/hpet.c b/arch/x86_64/kernel/hpet.c index 65a0edd71a17..8cf0b8a13778 100644 --- a/arch/x86_64/kernel/hpet.c +++ b/arch/x86_64/kernel/hpet.c | |||
@@ -12,6 +12,12 @@ | |||
12 | #include <asm/timex.h> | 12 | #include <asm/timex.h> |
13 | #include <asm/hpet.h> | 13 | #include <asm/hpet.h> |
14 | 14 | ||
15 | #define HPET_MASK 0xFFFFFFFF | ||
16 | #define HPET_SHIFT 22 | ||
17 | |||
18 | /* FSEC = 10^-15 NSEC = 10^-9 */ | ||
19 | #define FSEC_PER_NSEC 1000000 | ||
20 | |||
15 | int nohpet __initdata; | 21 | int nohpet __initdata; |
16 | 22 | ||
17 | unsigned long hpet_address; | 23 | unsigned long hpet_address; |
@@ -106,9 +112,31 @@ int hpet_timer_stop_set_go(unsigned long tick) | |||
106 | return 0; | 112 | return 0; |
107 | } | 113 | } |
108 | 114 | ||
115 | static cycle_t read_hpet(void) | ||
116 | { | ||
117 | return (cycle_t)hpet_readl(HPET_COUNTER); | ||
118 | } | ||
119 | |||
120 | static cycle_t __vsyscall_fn vread_hpet(void) | ||
121 | { | ||
122 | return readl((void __iomem *)fix_to_virt(VSYSCALL_HPET) + 0xf0); | ||
123 | } | ||
124 | |||
125 | struct clocksource clocksource_hpet = { | ||
126 | .name = "hpet", | ||
127 | .rating = 250, | ||
128 | .read = read_hpet, | ||
129 | .mask = (cycle_t)HPET_MASK, | ||
130 | .mult = 0, /* set below */ | ||
131 | .shift = HPET_SHIFT, | ||
132 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, | ||
133 | .vread = vread_hpet, | ||
134 | }; | ||
135 | |||
109 | int hpet_arch_init(void) | 136 | int hpet_arch_init(void) |
110 | { | 137 | { |
111 | unsigned int id; | 138 | unsigned int id; |
139 | u64 tmp; | ||
112 | 140 | ||
113 | if (!hpet_address) | 141 | if (!hpet_address) |
114 | return -1; | 142 | return -1; |
@@ -132,6 +160,22 @@ int hpet_arch_init(void) | |||
132 | 160 | ||
133 | hpet_use_timer = (id & HPET_ID_LEGSUP); | 161 | hpet_use_timer = (id & HPET_ID_LEGSUP); |
134 | 162 | ||
163 | /* | ||
164 | * hpet period is in femto seconds per cycle | ||
165 | * so we need to convert this to ns/cyc units | ||
166 | * aproximated by mult/2^shift | ||
167 | * | ||
168 | * fsec/cyc * 1nsec/1000000fsec = nsec/cyc = mult/2^shift | ||
169 | * fsec/cyc * 1ns/1000000fsec * 2^shift = mult | ||
170 | * fsec/cyc * 2^shift * 1nsec/1000000fsec = mult | ||
171 | * (fsec/cyc << shift)/1000000 = mult | ||
172 | * (hpet_period << shift)/FSEC_PER_NSEC = mult | ||
173 | */ | ||
174 | tmp = (u64)hpet_period << HPET_SHIFT; | ||
175 | do_div(tmp, FSEC_PER_NSEC); | ||
176 | clocksource_hpet.mult = (u32)tmp; | ||
177 | clocksource_register(&clocksource_hpet); | ||
178 | |||
135 | return hpet_timer_stop_set_go(hpet_tick); | 179 | return hpet_timer_stop_set_go(hpet_tick); |
136 | } | 180 | } |
137 | 181 | ||
@@ -444,68 +488,3 @@ static int __init nohpet_setup(char *s) | |||
444 | } | 488 | } |
445 | 489 | ||
446 | __setup("nohpet", nohpet_setup); | 490 | __setup("nohpet", nohpet_setup); |
447 | |||
448 | #define HPET_MASK 0xFFFFFFFF | ||
449 | #define HPET_SHIFT 22 | ||
450 | |||
451 | /* FSEC = 10^-15 NSEC = 10^-9 */ | ||
452 | #define FSEC_PER_NSEC 1000000 | ||
453 | |||
454 | static void *hpet_ptr; | ||
455 | |||
456 | static cycle_t read_hpet(void) | ||
457 | { | ||
458 | return (cycle_t)readl(hpet_ptr); | ||
459 | } | ||
460 | |||
461 | static cycle_t __vsyscall_fn vread_hpet(void) | ||
462 | { | ||
463 | return readl((void __iomem *)fix_to_virt(VSYSCALL_HPET) + 0xf0); | ||
464 | } | ||
465 | |||
466 | struct clocksource clocksource_hpet = { | ||
467 | .name = "hpet", | ||
468 | .rating = 250, | ||
469 | .read = read_hpet, | ||
470 | .mask = (cycle_t)HPET_MASK, | ||
471 | .mult = 0, /* set below */ | ||
472 | .shift = HPET_SHIFT, | ||
473 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, | ||
474 | .vread = vread_hpet, | ||
475 | }; | ||
476 | |||
477 | static int __init init_hpet_clocksource(void) | ||
478 | { | ||
479 | unsigned long hpet_period; | ||
480 | void __iomem *hpet_base; | ||
481 | u64 tmp; | ||
482 | |||
483 | if (!hpet_address) | ||
484 | return -ENODEV; | ||
485 | |||
486 | /* calculate the hpet address: */ | ||
487 | hpet_base = ioremap_nocache(hpet_address, HPET_MMAP_SIZE); | ||
488 | hpet_ptr = hpet_base + HPET_COUNTER; | ||
489 | |||
490 | /* calculate the frequency: */ | ||
491 | hpet_period = readl(hpet_base + HPET_PERIOD); | ||
492 | |||
493 | /* | ||
494 | * hpet period is in femto seconds per cycle | ||
495 | * so we need to convert this to ns/cyc units | ||
496 | * aproximated by mult/2^shift | ||
497 | * | ||
498 | * fsec/cyc * 1nsec/1000000fsec = nsec/cyc = mult/2^shift | ||
499 | * fsec/cyc * 1ns/1000000fsec * 2^shift = mult | ||
500 | * fsec/cyc * 2^shift * 1nsec/1000000fsec = mult | ||
501 | * (fsec/cyc << shift)/1000000 = mult | ||
502 | * (hpet_period << shift)/FSEC_PER_NSEC = mult | ||
503 | */ | ||
504 | tmp = (u64)hpet_period << HPET_SHIFT; | ||
505 | do_div(tmp, FSEC_PER_NSEC); | ||
506 | clocksource_hpet.mult = (u32)tmp; | ||
507 | |||
508 | return clocksource_register(&clocksource_hpet); | ||
509 | } | ||
510 | |||
511 | module_init(init_hpet_clocksource); | ||
diff --git a/arch/x86_64/kernel/time.c b/arch/x86_64/kernel/time.c index c9addcfb96dc..75d73a9aa9ff 100644 --- a/arch/x86_64/kernel/time.c +++ b/arch/x86_64/kernel/time.c | |||
@@ -358,6 +358,8 @@ void __init time_init(void) | |||
358 | set_cyc2ns_scale(cpu_khz); | 358 | set_cyc2ns_scale(cpu_khz); |
359 | printk(KERN_INFO "time.c: Detected %d.%03d MHz processor.\n", | 359 | printk(KERN_INFO "time.c: Detected %d.%03d MHz processor.\n", |
360 | cpu_khz / 1000, cpu_khz % 1000); | 360 | cpu_khz / 1000, cpu_khz % 1000); |
361 | init_tsc_clocksource(); | ||
362 | |||
361 | setup_irq(0, &irq0); | 363 | setup_irq(0, &irq0); |
362 | } | 364 | } |
363 | 365 | ||
diff --git a/arch/x86_64/kernel/tsc.c b/arch/x86_64/kernel/tsc.c index 895831865019..1a0edbbffaa0 100644 --- a/arch/x86_64/kernel/tsc.c +++ b/arch/x86_64/kernel/tsc.c | |||
@@ -210,7 +210,7 @@ void mark_tsc_unstable(void) | |||
210 | } | 210 | } |
211 | EXPORT_SYMBOL_GPL(mark_tsc_unstable); | 211 | EXPORT_SYMBOL_GPL(mark_tsc_unstable); |
212 | 212 | ||
213 | static int __init init_tsc_clocksource(void) | 213 | void __init init_tsc_clocksource(void) |
214 | { | 214 | { |
215 | if (!notsc) { | 215 | if (!notsc) { |
216 | clocksource_tsc.mult = clocksource_khz2mult(cpu_khz, | 216 | clocksource_tsc.mult = clocksource_khz2mult(cpu_khz, |
@@ -218,9 +218,6 @@ static int __init init_tsc_clocksource(void) | |||
218 | if (check_tsc_unstable()) | 218 | if (check_tsc_unstable()) |
219 | clocksource_tsc.rating = 0; | 219 | clocksource_tsc.rating = 0; |
220 | 220 | ||
221 | return clocksource_register(&clocksource_tsc); | 221 | clocksource_register(&clocksource_tsc); |
222 | } | 222 | } |
223 | return 0; | ||
224 | } | 223 | } |
225 | |||
226 | module_init(init_tsc_clocksource); | ||