diff options
author | Thomas Gleixner <tglx@linutronix.de> | 2007-02-16 04:28:04 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-02-16 11:13:59 -0500 |
commit | e9e2cdb412412326c4827fc78ba27f410d837e6e (patch) | |
tree | cd4ca03e6bdc3691619024492fb9414427b2f813 /arch/i386/kernel/time.c | |
parent | 79bf2bb335b85db25d27421c798595a2fa2a0e82 (diff) |
[PATCH] clockevents: i386 drivers
Add clockevent drivers for i386: lapic (local) and PIT/HPET (global). Update
the timer IRQ to call into the PIT/HPET driver's event handler and the
lapic-timer IRQ to call into the lapic clockevent driver. The assignement of
timer functionality is delegated to the core framework code and replaces the
compile and runtime evalution in do_timer_interrupt_hook()
Use the clockevents broadcast support and implement the lapic_broadcast
function for ACPI.
No changes to existing functionality.
[ kdump fix from Vivek Goyal <vgoyal@in.ibm.com> ]
[ fixes based on review feedback from Arjan van de Ven <arjan@infradead.org> ]
Cleanups-from: Adrian Bunk <bunk@stusta.de>
Build-fixes-from: Andrew Morton <akpm@osdl.org>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Cc: john stultz <johnstul@us.ibm.com>
Cc: Roman Zippel <zippel@linux-m68k.org>
Cc: Andi Kleen <ak@suse.de>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'arch/i386/kernel/time.c')
-rw-r--r-- | arch/i386/kernel/time.c | 70 |
1 files changed, 3 insertions, 67 deletions
diff --git a/arch/i386/kernel/time.c b/arch/i386/kernel/time.c index 044c17572ee..a5350059557 100644 --- a/arch/i386/kernel/time.c +++ b/arch/i386/kernel/time.c | |||
@@ -159,15 +159,6 @@ EXPORT_SYMBOL(profile_pc); | |||
159 | */ | 159 | */ |
160 | irqreturn_t timer_interrupt(int irq, void *dev_id) | 160 | irqreturn_t timer_interrupt(int irq, void *dev_id) |
161 | { | 161 | { |
162 | /* | ||
163 | * Here we are in the timer irq handler. We just have irqs locally | ||
164 | * disabled but we don't know if the timer_bh is running on the other | ||
165 | * CPU. We need to avoid to SMP race with it. NOTE: we don' t need | ||
166 | * the irq version of write_lock because as just said we have irq | ||
167 | * locally disabled. -arca | ||
168 | */ | ||
169 | write_seqlock(&xtime_lock); | ||
170 | |||
171 | #ifdef CONFIG_X86_IO_APIC | 162 | #ifdef CONFIG_X86_IO_APIC |
172 | if (timer_ack) { | 163 | if (timer_ack) { |
173 | /* | 164 | /* |
@@ -186,7 +177,6 @@ irqreturn_t timer_interrupt(int irq, void *dev_id) | |||
186 | 177 | ||
187 | do_timer_interrupt_hook(); | 178 | do_timer_interrupt_hook(); |
188 | 179 | ||
189 | |||
190 | if (MCA_bus) { | 180 | if (MCA_bus) { |
191 | /* The PS/2 uses level-triggered interrupts. You can't | 181 | /* The PS/2 uses level-triggered interrupts. You can't |
192 | turn them off, nor would you want to (any attempt to | 182 | turn them off, nor would you want to (any attempt to |
@@ -201,13 +191,6 @@ irqreturn_t timer_interrupt(int irq, void *dev_id) | |||
201 | outb_p( irq_v|0x80, 0x61 ); /* reset the IRQ */ | 191 | outb_p( irq_v|0x80, 0x61 ); /* reset the IRQ */ |
202 | } | 192 | } |
203 | 193 | ||
204 | write_sequnlock(&xtime_lock); | ||
205 | |||
206 | #ifdef CONFIG_X86_LOCAL_APIC | ||
207 | if (using_apic_timer) | ||
208 | smp_send_timer_broadcast_ipi(); | ||
209 | #endif | ||
210 | |||
211 | return IRQ_HANDLED; | 194 | return IRQ_HANDLED; |
212 | } | 195 | } |
213 | 196 | ||
@@ -277,63 +260,16 @@ void notify_arch_cmos_timer(void) | |||
277 | mod_timer(&sync_cmos_timer, jiffies + 1); | 260 | mod_timer(&sync_cmos_timer, jiffies + 1); |
278 | } | 261 | } |
279 | 262 | ||
280 | static int timer_resume(struct sys_device *dev) | ||
281 | { | ||
282 | #ifdef CONFIG_HPET_TIMER | ||
283 | if (is_hpet_enabled()) | ||
284 | hpet_reenable(); | ||
285 | #endif | ||
286 | setup_pit_timer(); | ||
287 | touch_softlockup_watchdog(); | ||
288 | return 0; | ||
289 | } | ||
290 | |||
291 | static struct sysdev_class timer_sysclass = { | ||
292 | .resume = timer_resume, | ||
293 | set_kset_name("timer"), | ||
294 | }; | ||
295 | |||
296 | |||
297 | /* XXX this driverfs stuff should probably go elsewhere later -john */ | ||
298 | static struct sys_device device_timer = { | ||
299 | .id = 0, | ||
300 | .cls = &timer_sysclass, | ||
301 | }; | ||
302 | |||
303 | static int time_init_device(void) | ||
304 | { | ||
305 | int error = sysdev_class_register(&timer_sysclass); | ||
306 | if (!error) | ||
307 | error = sysdev_register(&device_timer); | ||
308 | return error; | ||
309 | } | ||
310 | |||
311 | device_initcall(time_init_device); | ||
312 | |||
313 | #ifdef CONFIG_HPET_TIMER | ||
314 | extern void (*late_time_init)(void); | 263 | extern void (*late_time_init)(void); |
315 | /* Duplicate of time_init() below, with hpet_enable part added */ | 264 | /* Duplicate of time_init() below, with hpet_enable part added */ |
316 | static void __init hpet_time_init(void) | 265 | static void __init hpet_time_init(void) |
317 | { | 266 | { |
318 | if ((hpet_enable() >= 0) && hpet_use_timer) { | 267 | if (!hpet_enable()) |
319 | printk("Using HPET for base-timer\n"); | 268 | setup_pit_timer(); |
320 | } | ||
321 | |||
322 | do_time_init(); | 269 | do_time_init(); |
323 | } | 270 | } |
324 | #endif | ||
325 | 271 | ||
326 | void __init time_init(void) | 272 | void __init time_init(void) |
327 | { | 273 | { |
328 | #ifdef CONFIG_HPET_TIMER | 274 | late_time_init = hpet_time_init; |
329 | if (is_hpet_capable()) { | ||
330 | /* | ||
331 | * HPET initialization needs to do memory-mapped io. So, let | ||
332 | * us do a late initialization after mem_init(). | ||
333 | */ | ||
334 | late_time_init = hpet_time_init; | ||
335 | return; | ||
336 | } | ||
337 | #endif | ||
338 | do_time_init(); | ||
339 | } | 275 | } |