aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86_64/kernel/apic.c
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/x86_64/kernel/apic.c
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/x86_64/kernel/apic.c')
-rw-r--r--arch/x86_64/kernel/apic.c34
1 files changed, 32 insertions, 2 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);