aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/apic_64.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/kernel/apic_64.c')
-rw-r--r--arch/x86/kernel/apic_64.c90
1 files changed, 50 insertions, 40 deletions
diff --git a/arch/x86/kernel/apic_64.c b/arch/x86/kernel/apic_64.c
index 2c2807abe1d..b0237caff71 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