aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/time_64.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/kernel/time_64.c')
-rw-r--r--arch/x86/kernel/time_64.c177
1 files changed, 11 insertions, 166 deletions
diff --git a/arch/x86/kernel/time_64.c b/arch/x86/kernel/time_64.c
index 6d48a4e826d9..e0134d6c88da 100644
--- a/arch/x86/kernel/time_64.c
+++ b/arch/x86/kernel/time_64.c
@@ -28,11 +28,12 @@
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>
34#endif 36#endif
35#include <asm/8253pit.h>
36#include <asm/i8253.h> 37#include <asm/i8253.h>
37#include <asm/pgtable.h> 38#include <asm/pgtable.h>
38#include <asm/vsyscall.h> 39#include <asm/vsyscall.h>
@@ -47,12 +48,8 @@
47#include <asm/nmi.h> 48#include <asm/nmi.h>
48#include <asm/vgtod.h> 49#include <asm/vgtod.h>
49 50
50static char *timename = NULL;
51
52DEFINE_SPINLOCK(rtc_lock); 51DEFINE_SPINLOCK(rtc_lock);
53EXPORT_SYMBOL(rtc_lock); 52EXPORT_SYMBOL(rtc_lock);
54DEFINE_SPINLOCK(i8253_lock);
55EXPORT_SYMBOL(i8253_lock);
56 53
57volatile unsigned long __jiffies __section_jiffies = INITIAL_JIFFIES; 54volatile unsigned long __jiffies __section_jiffies = INITIAL_JIFFIES;
58 55
@@ -153,45 +150,12 @@ int update_persistent_clock(struct timespec now)
153 return set_rtc_mmss(now.tv_sec); 150 return set_rtc_mmss(now.tv_sec);
154} 151}
155 152
156void main_timer_handler(void) 153static irqreturn_t timer_event_interrupt(int irq, void *dev_id)
157{ 154{
158/* 155 add_pda(irq0_irqs, 1);
159 * Here we are in the timer irq handler. We have irqs locally disabled (so we
160 * don't need spin_lock_irqsave()) but we don't know if the timer_bh is running
161 * on the other CPU, so we need a lock. We also need to lock the vsyscall
162 * variables, because both do_timer() and us change them -arca+vojtech
163 */
164
165 write_seqlock(&xtime_lock);
166 156
167/* 157 global_clock_event->event_handler(global_clock_event);
168 * Do the timer stuff.
169 */
170
171 do_timer(1);
172#ifndef CONFIG_SMP
173 update_process_times(user_mode(get_irq_regs()));
174#endif
175 158
176/*
177 * In the SMP case we use the local APIC timer interrupt to do the profiling,
178 * except when we simulate SMP mode on a uniprocessor system, in that case we
179 * have to call the local interrupt handler.
180 */
181
182 if (!using_apic_timer)
183 smp_local_timer_interrupt();
184
185 write_sequnlock(&xtime_lock);
186}
187
188static irqreturn_t timer_interrupt(int irq, void *dev_id)
189{
190 if (apic_runs_main_timer > 1)
191 return IRQ_HANDLED;
192 main_timer_handler();
193 if (using_apic_timer)
194 smp_send_timer_broadcast_ipi();
195 return IRQ_HANDLED; 159 return IRQ_HANDLED;
196} 160}
197 161
@@ -292,97 +256,21 @@ static unsigned int __init tsc_calibrate_cpu_khz(void)
292 return pmc_now * tsc_khz / (tsc_now - tsc_start); 256 return pmc_now * tsc_khz / (tsc_now - tsc_start);
293} 257}
294 258
295/*
296 * pit_calibrate_tsc() uses the speaker output (channel 2) of
297 * the PIT. This is better than using the timer interrupt output,
298 * because we can read the value of the speaker with just one inb(),
299 * where we need three i/o operations for the interrupt channel.
300 * We count how many ticks the TSC does in 50 ms.
301 */
302
303static unsigned int __init pit_calibrate_tsc(void)
304{
305 unsigned long start, end;
306 unsigned long flags;
307
308 spin_lock_irqsave(&i8253_lock, flags);
309
310 outb((inb(0x61) & ~0x02) | 0x01, 0x61);
311
312 outb(0xb0, 0x43);
313 outb((PIT_TICK_RATE / (1000 / 50)) & 0xff, 0x42);
314 outb((PIT_TICK_RATE / (1000 / 50)) >> 8, 0x42);
315 start = get_cycles_sync();
316 while ((inb(0x61) & 0x20) == 0);
317 end = get_cycles_sync();
318
319 spin_unlock_irqrestore(&i8253_lock, flags);
320
321 return (end - start) / 50;
322}
323
324#define PIT_MODE 0x43
325#define PIT_CH0 0x40
326
327static void __pit_init(int val, u8 mode)
328{
329 unsigned long flags;
330
331 spin_lock_irqsave(&i8253_lock, flags);
332 outb_p(mode, PIT_MODE);
333 outb_p(val & 0xff, PIT_CH0); /* LSB */
334 outb_p(val >> 8, PIT_CH0); /* MSB */
335 spin_unlock_irqrestore(&i8253_lock, flags);
336}
337
338void __init pit_init(void)
339{
340 __pit_init(LATCH, 0x34); /* binary, mode 2, LSB/MSB, ch 0 */
341}
342
343void pit_stop_interrupt(void)
344{
345 __pit_init(0, 0x30); /* mode 0 */
346}
347
348void stop_timer_interrupt(void)
349{
350 char *name;
351 if (hpet_address) {
352 name = "HPET";
353 hpet_timer_stop_set_go(0);
354 } else {
355 name = "PIT";
356 pit_stop_interrupt();
357 }
358 printk(KERN_INFO "timer: %s interrupt stopped.\n", name);
359}
360
361static struct irqaction irq0 = { 259static struct irqaction irq0 = {
362 .handler = timer_interrupt, 260 .handler = timer_event_interrupt,
363 .flags = IRQF_DISABLED | IRQF_IRQPOLL, 261 .flags = IRQF_DISABLED | IRQF_IRQPOLL | IRQF_NOBALANCING,
364 .mask = CPU_MASK_NONE, 262 .mask = CPU_MASK_NONE,
365 .name = "timer" 263 .name = "timer"
366}; 264};
367 265
368void __init time_init(void) 266void __init time_init(void)
369{ 267{
370 if (nohpet) 268 if (!hpet_enable())
371 hpet_address = 0; 269 setup_pit_timer();
372 270
373 if (hpet_arch_init()) 271 setup_irq(0, &irq0);
374 hpet_address = 0;
375 272
376 if (hpet_use_timer) { 273 tsc_calibrate();
377 /* set tick_nsec to use the proper rate for HPET */
378 tick_nsec = TICK_NSEC_HPET;
379 tsc_khz = hpet_calibrate_tsc();
380 timename = "HPET";
381 } else {
382 pit_init();
383 tsc_khz = pit_calibrate_tsc();
384 timename = "PIT";
385 }
386 274
387 cpu_khz = tsc_khz; 275 cpu_khz = tsc_khz;
388 if (cpu_has(&boot_cpu_data, X86_FEATURE_CONSTANT_TSC) && 276 if (cpu_has(&boot_cpu_data, X86_FEATURE_CONSTANT_TSC) &&
@@ -398,50 +286,7 @@ void __init time_init(void)
398 else 286 else
399 vgetcpu_mode = VGETCPU_LSL; 287 vgetcpu_mode = VGETCPU_LSL;
400 288
401 set_cyc2ns_scale(tsc_khz);
402 printk(KERN_INFO "time.c: Detected %d.%03d MHz processor.\n", 289 printk(KERN_INFO "time.c: Detected %d.%03d MHz processor.\n",
403 cpu_khz / 1000, cpu_khz % 1000); 290 cpu_khz / 1000, cpu_khz % 1000);
404 init_tsc_clocksource(); 291 init_tsc_clocksource();
405
406 setup_irq(0, &irq0);
407}
408
409/*
410 * sysfs support for the timer.
411 */
412
413static int timer_suspend(struct sys_device *dev, pm_message_t state)
414{
415 return 0;
416}
417
418static int timer_resume(struct sys_device *dev)
419{
420 if (hpet_address)
421 hpet_reenable();
422 else
423 i8254_timer_resume();
424 return 0;
425} 292}
426
427static struct sysdev_class timer_sysclass = {
428 .resume = timer_resume,
429 .suspend = timer_suspend,
430 set_kset_name("timer"),
431};
432
433/* XXX this sysfs stuff should probably go elsewhere later -john */
434static struct sys_device device_timer = {
435 .id = 0,
436 .cls = &timer_sysclass,
437};
438
439static int time_init_device(void)
440{
441 int error = sysdev_class_register(&timer_sysclass);
442 if (!error)
443 error = sysdev_register(&device_timer);
444 return error;
445}
446
447device_initcall(time_init_device);