aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2007-10-12 17:04:07 -0400
committerThomas Gleixner <tglx@inhelltoy.tec.linutronix.de>2007-10-12 17:04:07 -0400
commitb8ce33590687888ebb900d09557b8807c4539022 (patch)
tree0e51543c7d4febff8ff6ad7660268bea2035f9ce /arch/x86
parentba7eda4c60e1d070b2f6586d42719ec1d5302d3b (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')
-rw-r--r--arch/x86/kernel/Makefile_644
-rw-r--r--arch/x86/kernel/apic_64.c90
-rw-r--r--arch/x86/kernel/i8259_64.c46
-rw-r--r--arch/x86/kernel/smpboot_64.c4
-rw-r--r--arch/x86/kernel/time_64.c107
5 files changed, 65 insertions, 186 deletions
diff --git a/arch/x86/kernel/Makefile_64 b/arch/x86/kernel/Makefile_64
index 3ab017a0a3b9..080154e31502 100644
--- a/arch/x86/kernel/Makefile_64
+++ b/arch/x86/kernel/Makefile_64
@@ -8,8 +8,8 @@ obj-y := process_64.o signal_64.o entry_64.o traps_64.o irq_64.o \
8 ptrace_64.o time_64.o ioport_64.o ldt_64.o setup_64.o i8259_64.o sys_x86_64.o \ 8 ptrace_64.o time_64.o ioport_64.o ldt_64.o setup_64.o i8259_64.o sys_x86_64.o \
9 x8664_ksyms_64.o i387_64.o syscall_64.o vsyscall_64.o \ 9 x8664_ksyms_64.o i387_64.o syscall_64.o vsyscall_64.o \
10 setup64.o bootflag.o e820_64.o reboot_64.o quirks.o i8237.o \ 10 setup64.o bootflag.o e820_64.o reboot_64.o quirks.o i8237.o \
11 pci-dma_64.o pci-nommu_64.o alternative.o hpet_64.o tsc_64.o bugs_64.o \ 11 pci-dma_64.o pci-nommu_64.o alternative.o hpet_32.o tsc_64.o bugs_64.o \
12 perfctr-watchdog.o 12 perfctr-watchdog.o i8253_32.o
13 13
14obj-$(CONFIG_STACKTRACE) += stacktrace.o 14obj-$(CONFIG_STACKTRACE) += stacktrace.o
15obj-$(CONFIG_X86_MCE) += mce_64.o therm_throt.o 15obj-$(CONFIG_X86_MCE) += mce_64.o therm_throt.o
diff --git a/arch/x86/kernel/apic_64.c b/arch/x86/kernel/apic_64.c
index 2c2807abe1d4..b0237caff712 100644
--- a/arch/x86/kernel/apic_64.c
+++ b/arch/x86/kernel/apic_64.c
@@ -857,25 +857,12 @@ static void __setup_APIC_LVTT(unsigned int clocks, int oneshot, int irqen)
857 857
858static void setup_APIC_timer(void) 858static void setup_APIC_timer(void)
859{ 859{
860 unsigned long flags; 860 struct clock_event_device *levt = &__get_cpu_var(lapic_events);
861 int irqen;
862 861
863 local_irq_save(flags); 862 memcpy(levt, &lapic_clockevent, sizeof(*levt));
863 levt->cpumask = cpumask_of_cpu(smp_processor_id());
864 864
865 irqen = ! cpu_isset(smp_processor_id(), 865 clockevents_register_device(levt);
866 timer_interrupt_broadcast_ipi_mask);
867 __setup_APIC_LVTT(calibration_result, 0, irqen);
868 /* Turn off PIT interrupt if we use APIC timer as main timer.
869 Only works with the PM timer right now
870 TBD fix it for HPET too. */
871 if ((pmtmr_ioport != 0) &&
872 smp_processor_id() == boot_cpu_id &&
873 apic_runs_main_timer == 1 &&
874 !cpu_isset(boot_cpu_id, timer_interrupt_broadcast_ipi_mask)) {
875 stop_timer_interrupt();
876 apic_runs_main_timer++;
877 }
878 local_irq_restore(flags);
879} 866}
880 867
881/* 868/*
@@ -950,18 +937,34 @@ static void __init calibrate_APIC_clock(void)
950 937
951void __init setup_boot_APIC_clock (void) 938void __init setup_boot_APIC_clock (void)
952{ 939{
940 /*
941 * The local apic timer can be disabled via the kernel commandline.
942 * Register the lapic timer as a dummy clock event source on SMP
943 * systems, so the broadcast mechanism is used. On UP systems simply
944 * ignore it.
945 */
953 if (disable_apic_timer) { 946 if (disable_apic_timer) {
954 printk(KERN_INFO "Disabling APIC timer\n"); 947 printk(KERN_INFO "Disabling APIC timer\n");
948 /* No broadcast on UP ! */
949 if (num_possible_cpus() > 1)
950 setup_APIC_timer();
955 return; 951 return;
956 } 952 }
957 953
958 printk(KERN_INFO "Using local APIC timer interrupts.\n"); 954 printk(KERN_INFO "Using local APIC timer interrupts.\n");
959 using_apic_timer = 1;
960
961 calibrate_APIC_clock(); 955 calibrate_APIC_clock();
956
962 /* 957 /*
963 * Now set up the timer for real. 958 * If nmi_watchdog is set to IO_APIC, we need the
959 * PIT/HPET going. Otherwise register lapic as a dummy
960 * device.
964 */ 961 */
962 if (nmi_watchdog != NMI_IO_APIC)
963 lapic_clockevent.features &= ~CLOCK_EVT_FEAT_DUMMY;
964 else
965 printk(KERN_WARNING "APIC timer registered as dummy,"
966 " due to nmi_watchdog=1!\n");
967
965 setup_APIC_timer(); 968 setup_APIC_timer();
966} 969}
967 970
@@ -1073,22 +1076,34 @@ void setup_APIC_extended_lvt(unsigned char lvt_off, unsigned char vector,
1073 1076
1074void smp_local_timer_interrupt(void) 1077void smp_local_timer_interrupt(void)
1075{ 1078{
1076 profile_tick(CPU_PROFILING); 1079 int cpu = smp_processor_id();
1077#ifdef CONFIG_SMP 1080 struct clock_event_device *evt = &per_cpu(lapic_events, cpu);
1078 update_process_times(user_mode(get_irq_regs())); 1081
1079#endif
1080 if (apic_runs_main_timer > 1 && smp_processor_id() == boot_cpu_id)
1081 main_timer_handler();
1082 /* 1082 /*
1083 * We take the 'long' return path, and there every subsystem 1083 * Normally we should not be here till LAPIC has been initialized but
1084 * grabs the appropriate locks (kernel lock/ irq lock). 1084 * in some cases like kdump, its possible that there is a pending LAPIC
1085 * 1085 * timer interrupt from previous kernel's context and is delivered in
1086 * We might want to decouple profiling from the 'long path', 1086 * new kernel the moment interrupts are enabled.
1087 * and do the profiling totally in assembly.
1088 * 1087 *
1089 * Currently this isn't too much of an issue (performance wise), 1088 * Interrupts are enabled early and LAPIC is setup much later, hence
1090 * we can take more than 100K local irqs per second on a 100 MHz P5. 1089 * its possible that when we get here evt->event_handler is NULL.
1090 * Check for event_handler being NULL and discard the interrupt as
1091 * spurious.
1091 */ 1092 */
1093 if (!evt->event_handler) {
1094 printk(KERN_WARNING
1095 "Spurious LAPIC timer interrupt on cpu %d\n", cpu);
1096 /* Switch it off */
1097 lapic_timer_setup(CLOCK_EVT_MODE_SHUTDOWN, evt);
1098 return;
1099 }
1100
1101 /*
1102 * the NMI deadlock-detector uses this.
1103 */
1104 add_pda(apic_timer_irqs, 1);
1105
1106 evt->event_handler(evt);
1092} 1107}
1093 1108
1094/* 1109/*
@@ -1104,11 +1119,6 @@ void smp_apic_timer_interrupt(struct pt_regs *regs)
1104 struct pt_regs *old_regs = set_irq_regs(regs); 1119 struct pt_regs *old_regs = set_irq_regs(regs);
1105 1120
1106 /* 1121 /*
1107 * the NMI deadlock-detector uses this.
1108 */
1109 add_pda(apic_timer_irqs, 1);
1110
1111 /*
1112 * NOTE! We'd better ACK the irq immediately, 1122 * NOTE! We'd better ACK the irq immediately,
1113 * because timer handling can be slow. 1123 * because timer handling can be slow.
1114 */ 1124 */
@@ -1291,7 +1301,7 @@ static __init int setup_noapictimer(char *str)
1291static __init int setup_apicmaintimer(char *str) 1301static __init int setup_apicmaintimer(char *str)
1292{ 1302{
1293 apic_runs_main_timer = 1; 1303 apic_runs_main_timer = 1;
1294 nohpet = 1; 1304
1295 return 1; 1305 return 1;
1296} 1306}
1297__setup("apicmaintimer", setup_apicmaintimer); 1307__setup("apicmaintimer", setup_apicmaintimer);
@@ -1307,7 +1317,7 @@ static __init int setup_apicpmtimer(char *s)
1307{ 1317{
1308 apic_calibrate_pmtmr = 1; 1318 apic_calibrate_pmtmr = 1;
1309 notsc_setup(NULL); 1319 notsc_setup(NULL);
1310 return setup_apicmaintimer(NULL); 1320 return 0;
1311} 1321}
1312__setup("apicpmtimer", setup_apicpmtimer); 1322__setup("apicpmtimer", setup_apicpmtimer);
1313 1323
diff --git a/arch/x86/kernel/i8259_64.c b/arch/x86/kernel/i8259_64.c
index 948cae646099..eb72976cc13c 100644
--- a/arch/x86/kernel/i8259_64.c
+++ b/arch/x86/kernel/i8259_64.c
@@ -444,46 +444,6 @@ void __init init_ISA_irqs (void)
444 } 444 }
445} 445}
446 446
447static void setup_timer_hardware(void)
448{
449 outb_p(0x34,0x43); /* binary, mode 2, LSB/MSB, ch 0 */
450 udelay(10);
451 outb_p(LATCH & 0xff , 0x40); /* LSB */
452 udelay(10);
453 outb(LATCH >> 8 , 0x40); /* MSB */
454}
455
456static int timer_resume(struct sys_device *dev)
457{
458 setup_timer_hardware();
459 return 0;
460}
461
462void i8254_timer_resume(void)
463{
464 setup_timer_hardware();
465}
466
467static struct sysdev_class timer_sysclass = {
468 set_kset_name("timer_pit"),
469 .resume = timer_resume,
470};
471
472static struct sys_device device_timer = {
473 .id = 0,
474 .cls = &timer_sysclass,
475};
476
477static int __init init_timer_sysfs(void)
478{
479 int error = sysdev_class_register(&timer_sysclass);
480 if (!error)
481 error = sysdev_register(&device_timer);
482 return error;
483}
484
485device_initcall(init_timer_sysfs);
486
487void __init init_IRQ(void) 447void __init init_IRQ(void)
488{ 448{
489 int i; 449 int i;
@@ -533,12 +493,6 @@ void __init init_IRQ(void)
533 set_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt); 493 set_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt);
534 set_intr_gate(ERROR_APIC_VECTOR, error_interrupt); 494 set_intr_gate(ERROR_APIC_VECTOR, error_interrupt);
535 495
536 /*
537 * Set the clock to HZ Hz, we already have a valid
538 * vector now:
539 */
540 setup_timer_hardware();
541
542 if (!acpi_ioapic) 496 if (!acpi_ioapic)
543 setup_irq(2, &irq2); 497 setup_irq(2, &irq2);
544} 498}
diff --git a/arch/x86/kernel/smpboot_64.c b/arch/x86/kernel/smpboot_64.c
index 32f50783edc8..57ccf7cb6b91 100644
--- a/arch/x86/kernel/smpboot_64.c
+++ b/arch/x86/kernel/smpboot_64.c
@@ -223,8 +223,6 @@ void __cpuinit smp_callin(void)
223 local_irq_disable(); 223 local_irq_disable();
224 Dprintk("Stack at about %p\n",&cpuid); 224 Dprintk("Stack at about %p\n",&cpuid);
225 225
226 disable_APIC_timer();
227
228 /* 226 /*
229 * Save our processor parameters 227 * Save our processor parameters
230 */ 228 */
@@ -348,8 +346,6 @@ void __cpuinit start_secondary(void)
348 enable_8259A_irq(0); 346 enable_8259A_irq(0);
349 } 347 }
350 348
351 enable_APIC_timer();
352
353 /* 349 /*
354 * The sibling maps must be set before turing the online map on for 350 * The sibling maps must be set before turing the online map on for
355 * this cpu 351 * this cpu
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
49static char *timename = NULL;
50
51DEFINE_SPINLOCK(rtc_lock); 51DEFINE_SPINLOCK(rtc_lock);
52EXPORT_SYMBOL(rtc_lock); 52EXPORT_SYMBOL(rtc_lock);
53DEFINE_SPINLOCK(i8253_lock);
54EXPORT_SYMBOL(i8253_lock);
55 53
56volatile unsigned long __jiffies __section_jiffies = INITIAL_JIFFIES; 54volatile 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
195static 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
197unsigned long read_persistent_clock(void) 202unsigned 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
294static 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
305void __init pit_init(void)
306{
307 __pit_init(LATCH, 0x34); /* binary, mode 2, LSB/MSB, ch 0 */
308}
309
310void pit_stop_interrupt(void)
311{
312 __pit_init(0, 0x30); /* mode 0 */
313}
314
315void 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
328static struct irqaction irq0 = { 299static 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
335void __init time_init(void) 306void __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
380static int timer_suspend(struct sys_device *dev, pm_message_t state)
381{
382 return 0;
383} 333}
384
385static 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
394static 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 */
401static struct sys_device device_timer = {
402 .id = 0,
403 .cls = &timer_sysclass,
404};
405
406static 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
414device_initcall(time_init_device);