diff options
author | Thomas Gleixner <tglx@linutronix.de> | 2007-10-12 17:04:07 -0400 |
---|---|---|
committer | Thomas Gleixner <tglx@inhelltoy.tec.linutronix.de> | 2007-10-12 17:04:07 -0400 |
commit | b8ce33590687888ebb900d09557b8807c4539022 (patch) | |
tree | 0e51543c7d4febff8ff6ad7660268bea2035f9ce /arch/x86/kernel/time_64.c | |
parent | ba7eda4c60e1d070b2f6586d42719ec1d5302d3b (diff) |
x86_64: convert to clock events
Finally switch to the clockevents code. Share code with i386 for
hpet and PIT.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Chris Wright <chrisw@sous-sol.org>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Arjan van de Ven <arjan@linux.intel.com>
Diffstat (limited to 'arch/x86/kernel/time_64.c')
-rw-r--r-- | arch/x86/kernel/time_64.c | 107 |
1 files changed, 13 insertions, 94 deletions
diff --git a/arch/x86/kernel/time_64.c b/arch/x86/kernel/time_64.c index d899216e01ca..7781df1d50e3 100644 --- a/arch/x86/kernel/time_64.c +++ b/arch/x86/kernel/time_64.c | |||
@@ -28,6 +28,8 @@ | |||
28 | #include <linux/cpu.h> | 28 | #include <linux/cpu.h> |
29 | #include <linux/kallsyms.h> | 29 | #include <linux/kallsyms.h> |
30 | #include <linux/acpi.h> | 30 | #include <linux/acpi.h> |
31 | #include <linux/clockchips.h> | ||
32 | |||
31 | #ifdef CONFIG_ACPI | 33 | #ifdef CONFIG_ACPI |
32 | #include <acpi/achware.h> /* for PM timer frequency */ | 34 | #include <acpi/achware.h> /* for PM timer frequency */ |
33 | #include <acpi/acpi_bus.h> | 35 | #include <acpi/acpi_bus.h> |
@@ -46,12 +48,8 @@ | |||
46 | #include <asm/nmi.h> | 48 | #include <asm/nmi.h> |
47 | #include <asm/vgtod.h> | 49 | #include <asm/vgtod.h> |
48 | 50 | ||
49 | static char *timename = NULL; | ||
50 | |||
51 | DEFINE_SPINLOCK(rtc_lock); | 51 | DEFINE_SPINLOCK(rtc_lock); |
52 | EXPORT_SYMBOL(rtc_lock); | 52 | EXPORT_SYMBOL(rtc_lock); |
53 | DEFINE_SPINLOCK(i8253_lock); | ||
54 | EXPORT_SYMBOL(i8253_lock); | ||
55 | 53 | ||
56 | volatile unsigned long __jiffies __section_jiffies = INITIAL_JIFFIES; | 54 | volatile unsigned long __jiffies __section_jiffies = INITIAL_JIFFIES; |
57 | 55 | ||
@@ -194,6 +192,13 @@ static irqreturn_t timer_interrupt(int irq, void *dev_id) | |||
194 | return IRQ_HANDLED; | 192 | return IRQ_HANDLED; |
195 | } | 193 | } |
196 | 194 | ||
195 | static irqreturn_t timer_event_interrupt(int irq, void *dev_id) | ||
196 | { | ||
197 | global_clock_event->event_handler(global_clock_event); | ||
198 | |||
199 | return IRQ_HANDLED; | ||
200 | } | ||
201 | |||
197 | unsigned long read_persistent_clock(void) | 202 | unsigned long read_persistent_clock(void) |
198 | { | 203 | { |
199 | unsigned int year, mon, day, hour, min, sec; | 204 | unsigned int year, mon, day, hour, min, sec; |
@@ -291,42 +296,8 @@ static unsigned int __init tsc_calibrate_cpu_khz(void) | |||
291 | return pmc_now * tsc_khz / (tsc_now - tsc_start); | 296 | return pmc_now * tsc_khz / (tsc_now - tsc_start); |
292 | } | 297 | } |
293 | 298 | ||
294 | static void __pit_init(int val, u8 mode) | ||
295 | { | ||
296 | unsigned long flags; | ||
297 | |||
298 | spin_lock_irqsave(&i8253_lock, flags); | ||
299 | outb_p(mode, PIT_MODE); | ||
300 | outb_p(val & 0xff, PIT_CH0); /* LSB */ | ||
301 | outb_p(val >> 8, PIT_CH0); /* MSB */ | ||
302 | spin_unlock_irqrestore(&i8253_lock, flags); | ||
303 | } | ||
304 | |||
305 | void __init pit_init(void) | ||
306 | { | ||
307 | __pit_init(LATCH, 0x34); /* binary, mode 2, LSB/MSB, ch 0 */ | ||
308 | } | ||
309 | |||
310 | void pit_stop_interrupt(void) | ||
311 | { | ||
312 | __pit_init(0, 0x30); /* mode 0 */ | ||
313 | } | ||
314 | |||
315 | void stop_timer_interrupt(void) | ||
316 | { | ||
317 | char *name; | ||
318 | if (hpet_address) { | ||
319 | name = "HPET"; | ||
320 | hpet_timer_stop_set_go(0); | ||
321 | } else { | ||
322 | name = "PIT"; | ||
323 | pit_stop_interrupt(); | ||
324 | } | ||
325 | printk(KERN_INFO "timer: %s interrupt stopped.\n", name); | ||
326 | } | ||
327 | |||
328 | static struct irqaction irq0 = { | 299 | static struct irqaction irq0 = { |
329 | .handler = timer_interrupt, | 300 | .handler = timer_event_interrupt, |
330 | .flags = IRQF_DISABLED | IRQF_IRQPOLL | IRQF_NOBALANCING, | 301 | .flags = IRQF_DISABLED | IRQF_IRQPOLL | IRQF_NOBALANCING, |
331 | .mask = CPU_MASK_NONE, | 302 | .mask = CPU_MASK_NONE, |
332 | .name = "timer" | 303 | .name = "timer" |
@@ -334,20 +305,10 @@ static struct irqaction irq0 = { | |||
334 | 305 | ||
335 | void __init time_init(void) | 306 | void __init time_init(void) |
336 | { | 307 | { |
337 | if (nohpet) | 308 | if (!hpet_enable()) |
338 | hpet_address = 0; | 309 | setup_pit_timer(); |
339 | |||
340 | if (hpet_arch_init()) | ||
341 | hpet_address = 0; | ||
342 | 310 | ||
343 | if (hpet_use_timer) { | 311 | setup_irq(0, &irq0); |
344 | /* set tick_nsec to use the proper rate for HPET */ | ||
345 | tick_nsec = TICK_NSEC_HPET; | ||
346 | timename = "HPET"; | ||
347 | } else { | ||
348 | pit_init(); | ||
349 | timename = "PIT"; | ||
350 | } | ||
351 | 312 | ||
352 | tsc_calibrate(); | 313 | tsc_calibrate(); |
353 | 314 | ||
@@ -369,46 +330,4 @@ void __init time_init(void) | |||
369 | printk(KERN_INFO "time.c: Detected %d.%03d MHz processor.\n", | 330 | printk(KERN_INFO "time.c: Detected %d.%03d MHz processor.\n", |
370 | cpu_khz / 1000, cpu_khz % 1000); | 331 | cpu_khz / 1000, cpu_khz % 1000); |
371 | init_tsc_clocksource(); | 332 | init_tsc_clocksource(); |
372 | |||
373 | setup_irq(0, &irq0); | ||
374 | } | ||
375 | |||
376 | /* | ||
377 | * sysfs support for the timer. | ||
378 | */ | ||
379 | |||
380 | static int timer_suspend(struct sys_device *dev, pm_message_t state) | ||
381 | { | ||
382 | return 0; | ||
383 | } | 333 | } |
384 | |||
385 | static int timer_resume(struct sys_device *dev) | ||
386 | { | ||
387 | if (hpet_address) | ||
388 | hpet_reenable(); | ||
389 | else | ||
390 | i8254_timer_resume(); | ||
391 | return 0; | ||
392 | } | ||
393 | |||
394 | static struct sysdev_class timer_sysclass = { | ||
395 | .resume = timer_resume, | ||
396 | .suspend = timer_suspend, | ||
397 | set_kset_name("timer"), | ||
398 | }; | ||
399 | |||
400 | /* XXX this sysfs stuff should probably go elsewhere later -john */ | ||
401 | static struct sys_device device_timer = { | ||
402 | .id = 0, | ||
403 | .cls = &timer_sysclass, | ||
404 | }; | ||
405 | |||
406 | static int time_init_device(void) | ||
407 | { | ||
408 | int error = sysdev_class_register(&timer_sysclass); | ||
409 | if (!error) | ||
410 | error = sysdev_register(&device_timer); | ||
411 | return error; | ||
412 | } | ||
413 | |||
414 | device_initcall(time_init_device); | ||