aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorAndi Kleen <ak@suse.de>2006-02-03 15:50:50 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2006-02-04 19:43:13 -0500
commit73dea47faeb96d54a984b9d7f4de564816966354 (patch)
tree6b1f090e9071e281367bc106c1b2ab05cb43e459 /arch
parent76b461c21468f41837283b7888d55f1c0671f719 (diff)
[PATCH] x86_64: Allow to run main time keeping from the local APIC interrupt
Another piece from the no-idle-tick patch. This can be enabled with the "apicmaintimer" option. This is mainly useful when the PIT/HPET interrupt is unreliable. Note there are some systems that are known to stop the APIC timer in C3. For those it will never work, but this case should be automatically detected. It also only works with PM timer right now. When HPET is used the way the main timer handler computes the delay doesn't work. It should be a bit more efficient because there is one less regular interrupt to process on the boot processor. Requires earlier bugfix from Venkatesh Signed-off-by: Andi Kleen <ak@suse.de> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch')
-rw-r--r--arch/x86_64/kernel/apic.c34
-rw-r--r--arch/x86_64/kernel/time.c45
2 files changed, 70 insertions, 9 deletions
diff --git a/arch/x86_64/kernel/apic.c b/arch/x86_64/kernel/apic.c
index 5d3c5b07b8db..14751dda7dcf 100644
--- a/arch/x86_64/kernel/apic.c
+++ b/arch/x86_64/kernel/apic.c
@@ -35,8 +35,11 @@
35#include <asm/mach_apic.h> 35#include <asm/mach_apic.h>
36#include <asm/nmi.h> 36#include <asm/nmi.h>
37#include <asm/idle.h> 37#include <asm/idle.h>
38#include <asm/proto.h>
39#include <asm/timex.h>
38 40
39int apic_verbosity; 41int apic_verbosity;
42int apic_runs_main_timer;
40 43
41int disable_apic_timer __initdata; 44int disable_apic_timer __initdata;
42 45
@@ -702,9 +705,17 @@ static void setup_APIC_timer(unsigned int clocks)
702 c2 |= inb_p(0x40) << 8; 705 c2 |= inb_p(0x40) << 8;
703 } while (c2 - c1 < 300); 706 } while (c2 - c1 < 300);
704 } 707 }
705
706 __setup_APIC_LVTT(clocks); 708 __setup_APIC_LVTT(clocks);
707 709 /* Turn off PIT interrupt if we use APIC timer as main timer.
710 Only works with the PM timer right now
711 TBD fix it for HPET too. */
712 if (vxtime.mode == VXTIME_PMTMR &&
713 smp_processor_id() == boot_cpu_id &&
714 apic_runs_main_timer == 1 &&
715 !cpu_isset(boot_cpu_id, timer_interrupt_broadcast_ipi_mask)) {
716 stop_timer_interrupt();
717 apic_runs_main_timer++;
718 }
708 local_irq_restore(flags); 719 local_irq_restore(flags);
709} 720}
710 721
@@ -872,6 +883,8 @@ void smp_local_timer_interrupt(struct pt_regs *regs)
872#ifdef CONFIG_SMP 883#ifdef CONFIG_SMP
873 update_process_times(user_mode(regs)); 884 update_process_times(user_mode(regs));
874#endif 885#endif
886 if (apic_runs_main_timer > 1 && smp_processor_id() == boot_cpu_id)
887 main_timer_handler(regs);
875 /* 888 /*
876 * We take the 'long' return path, and there every subsystem 889 * We take the 'long' return path, and there every subsystem
877 * grabs the appropriate locks (kernel lock/ irq lock). 890 * grabs the appropriate locks (kernel lock/ irq lock).
@@ -1081,10 +1094,27 @@ static __init int setup_nolapic(char *str)
1081 1094
1082static __init int setup_noapictimer(char *str) 1095static __init int setup_noapictimer(char *str)
1083{ 1096{
1097 if (str[0] != ' ' && str[0] != 0)
1098 return -1;
1084 disable_apic_timer = 1; 1099 disable_apic_timer = 1;
1085 return 0; 1100 return 0;
1086} 1101}
1087 1102
1103static __init int setup_apicmaintimer(char *str)
1104{
1105 apic_runs_main_timer = 1;
1106 nohpet = 1;
1107 return 0;
1108}
1109__setup("apicmaintimer", setup_apicmaintimer);
1110
1111static __init int setup_noapicmaintimer(char *str)
1112{
1113 apic_runs_main_timer = -1;
1114 return 0;
1115}
1116__setup("noapicmaintimer", setup_noapicmaintimer);
1117
1088/* dummy parsing: see setup.c */ 1118/* dummy parsing: see setup.c */
1089 1119
1090__setup("disableapic", setup_disableapic); 1120__setup("disableapic", setup_disableapic);
diff --git a/arch/x86_64/kernel/time.c b/arch/x86_64/kernel/time.c
index f8c47c688443..91a448a86ebd 100644
--- a/arch/x86_64/kernel/time.c
+++ b/arch/x86_64/kernel/time.c
@@ -51,7 +51,7 @@ extern int using_apic_timer;
51DEFINE_SPINLOCK(rtc_lock); 51DEFINE_SPINLOCK(rtc_lock);
52DEFINE_SPINLOCK(i8253_lock); 52DEFINE_SPINLOCK(i8253_lock);
53 53
54static int nohpet __initdata = 0; 54int nohpet __initdata = 0;
55static int notsc __initdata = 0; 55static int notsc __initdata = 0;
56 56
57#undef HPET_HACK_ENABLE_DANGEROUS 57#undef HPET_HACK_ENABLE_DANGEROUS
@@ -345,7 +345,7 @@ static noinline void handle_lost_ticks(int lost, struct pt_regs *regs)
345#endif 345#endif
346} 346}
347 347
348static irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) 348void main_timer_handler(struct pt_regs *regs)
349{ 349{
350 static unsigned long rtc_update = 0; 350 static unsigned long rtc_update = 0;
351 unsigned long tsc; 351 unsigned long tsc;
@@ -458,12 +458,17 @@ static irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
458 } 458 }
459 459
460 write_sequnlock(&xtime_lock); 460 write_sequnlock(&xtime_lock);
461}
461 462
463static irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
464{
465 if (apic_runs_main_timer > 1)
466 return IRQ_HANDLED;
467 main_timer_handler(regs);
462#ifdef CONFIG_X86_LOCAL_APIC 468#ifdef CONFIG_X86_LOCAL_APIC
463 if (using_apic_timer) 469 if (using_apic_timer)
464 smp_send_timer_broadcast_ipi(); 470 smp_send_timer_broadcast_ipi();
465#endif 471#endif
466
467 return IRQ_HANDLED; 472 return IRQ_HANDLED;
468} 473}
469 474
@@ -843,17 +848,43 @@ static int hpet_reenable(void)
843 return hpet_timer_stop_set_go(hpet_tick); 848 return hpet_timer_stop_set_go(hpet_tick);
844} 849}
845 850
846void __init pit_init(void) 851#define PIT_MODE 0x43
852#define PIT_CH0 0x40
853
854static void __init __pit_init(int val, u8 mode)
847{ 855{
848 unsigned long flags; 856 unsigned long flags;
849 857
850 spin_lock_irqsave(&i8253_lock, flags); 858 spin_lock_irqsave(&i8253_lock, flags);
851 outb_p(0x34, 0x43); /* binary, mode 2, LSB/MSB, ch 0 */ 859 outb_p(mode, PIT_MODE);
852 outb_p(LATCH & 0xff, 0x40); /* LSB */ 860 outb_p(val & 0xff, PIT_CH0); /* LSB */
853 outb_p(LATCH >> 8, 0x40); /* MSB */ 861 outb_p(val >> 8, PIT_CH0); /* MSB */
854 spin_unlock_irqrestore(&i8253_lock, flags); 862 spin_unlock_irqrestore(&i8253_lock, flags);
855} 863}
856 864
865void __init pit_init(void)
866{
867 __pit_init(LATCH, 0x34); /* binary, mode 2, LSB/MSB, ch 0 */
868}
869
870void __init pit_stop_interrupt(void)
871{
872 __pit_init(0, 0x30); /* mode 0 */
873}
874
875void __init stop_timer_interrupt(void)
876{
877 char *name;
878 if (vxtime.hpet_address) {
879 name = "HPET";
880 hpet_timer_stop_set_go(0);
881 } else {
882 name = "PIT";
883 pit_stop_interrupt();
884 }
885 printk(KERN_INFO "timer: %s interrupt stopped.\n", name);
886}
887
857int __init time_setup(char *str) 888int __init time_setup(char *str)
858{ 889{
859 report_lost_ticks = 1; 890 report_lost_ticks = 1;