aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86_64/kernel/apic.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86_64/kernel/apic.c')
-rw-r--r--arch/x86_64/kernel/apic.c89
1 files changed, 80 insertions, 9 deletions
diff --git a/arch/x86_64/kernel/apic.c b/arch/x86_64/kernel/apic.c
index 5d3c5b07b8db..6147770b4347 100644
--- a/arch/x86_64/kernel/apic.c
+++ b/arch/x86_64/kernel/apic.c
@@ -35,8 +35,12 @@
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;
43int apic_calibrate_pmtmr __initdata;
40 44
41int disable_apic_timer __initdata; 45int disable_apic_timer __initdata;
42 46
@@ -68,6 +72,26 @@ int get_maxlvt(void)
68 return maxlvt; 72 return maxlvt;
69} 73}
70 74
75/*
76 * 'what should we do if we get a hw irq event on an illegal vector'.
77 * each architecture has to answer this themselves.
78 */
79void ack_bad_irq(unsigned int irq)
80{
81 printk("unexpected IRQ trap at vector %02x\n", irq);
82 /*
83 * Currently unexpected vectors happen only on SMP and APIC.
84 * We _must_ ack these because every local APIC has only N
85 * irq slots per priority level, and a 'hanging, unacked' IRQ
86 * holds up an irq slot - in excessive cases (when multiple
87 * unexpected vectors occur) that might lock up the APIC
88 * completely.
89 * But don't ack when the APIC is disabled. -AK
90 */
91 if (!disable_apic)
92 ack_APIC_irq();
93}
94
71void clear_local_APIC(void) 95void clear_local_APIC(void)
72{ 96{
73 int maxlvt; 97 int maxlvt;
@@ -702,9 +726,17 @@ static void setup_APIC_timer(unsigned int clocks)
702 c2 |= inb_p(0x40) << 8; 726 c2 |= inb_p(0x40) << 8;
703 } while (c2 - c1 < 300); 727 } while (c2 - c1 < 300);
704 } 728 }
705
706 __setup_APIC_LVTT(clocks); 729 __setup_APIC_LVTT(clocks);
707 730 /* Turn off PIT interrupt if we use APIC timer as main timer.
731 Only works with the PM timer right now
732 TBD fix it for HPET too. */
733 if (vxtime.mode == VXTIME_PMTMR &&
734 smp_processor_id() == boot_cpu_id &&
735 apic_runs_main_timer == 1 &&
736 !cpu_isset(boot_cpu_id, timer_interrupt_broadcast_ipi_mask)) {
737 stop_timer_interrupt();
738 apic_runs_main_timer++;
739 }
708 local_irq_restore(flags); 740 local_irq_restore(flags);
709} 741}
710 742
@@ -735,14 +767,27 @@ static int __init calibrate_APIC_clock(void)
735 __setup_APIC_LVTT(1000000000); 767 __setup_APIC_LVTT(1000000000);
736 768
737 apic_start = apic_read(APIC_TMCCT); 769 apic_start = apic_read(APIC_TMCCT);
738 rdtscl(tsc_start); 770#ifdef CONFIG_X86_PM_TIMER
739 771 if (apic_calibrate_pmtmr && pmtmr_ioport) {
740 do { 772 pmtimer_wait(5000); /* 5ms wait */
741 apic = apic_read(APIC_TMCCT); 773 apic = apic_read(APIC_TMCCT);
742 rdtscl(tsc); 774 result = (apic_start - apic) * 1000L / 5;
743 } while ((tsc - tsc_start) < TICK_COUNT && (apic - apic_start) < TICK_COUNT); 775 } else
776#endif
777 {
778 rdtscl(tsc_start);
779
780 do {
781 apic = apic_read(APIC_TMCCT);
782 rdtscl(tsc);
783 } while ((tsc - tsc_start) < TICK_COUNT &&
784 (apic - apic_start) < TICK_COUNT);
785
786 result = (apic_start - apic) * 1000L * cpu_khz /
787 (tsc - tsc_start);
788 }
789 printk("result %d\n", result);
744 790
745 result = (apic_start - apic) * 1000L * cpu_khz / (tsc - tsc_start);
746 791
747 printk(KERN_INFO "Detected %d.%03d MHz APIC timer.\n", 792 printk(KERN_INFO "Detected %d.%03d MHz APIC timer.\n",
748 result / 1000 / 1000, result / 1000 % 1000); 793 result / 1000 / 1000, result / 1000 % 1000);
@@ -872,6 +917,8 @@ void smp_local_timer_interrupt(struct pt_regs *regs)
872#ifdef CONFIG_SMP 917#ifdef CONFIG_SMP
873 update_process_times(user_mode(regs)); 918 update_process_times(user_mode(regs));
874#endif 919#endif
920 if (apic_runs_main_timer > 1 && smp_processor_id() == boot_cpu_id)
921 main_timer_handler(regs);
875 /* 922 /*
876 * We take the 'long' return path, and there every subsystem 923 * We take the 'long' return path, and there every subsystem
877 * grabs the appropriate locks (kernel lock/ irq lock). 924 * grabs the appropriate locks (kernel lock/ irq lock).
@@ -924,7 +971,7 @@ void smp_apic_timer_interrupt(struct pt_regs *regs)
924 * multi-chassis. Use available data to take a good guess. 971 * multi-chassis. Use available data to take a good guess.
925 * If in doubt, go HPET. 972 * If in doubt, go HPET.
926 */ 973 */
927__init int oem_force_hpet_timer(void) 974__cpuinit int oem_force_hpet_timer(void)
928{ 975{
929 int i, clusters, zeros; 976 int i, clusters, zeros;
930 unsigned id; 977 unsigned id;
@@ -1081,10 +1128,34 @@ static __init int setup_nolapic(char *str)
1081 1128
1082static __init int setup_noapictimer(char *str) 1129static __init int setup_noapictimer(char *str)
1083{ 1130{
1131 if (str[0] != ' ' && str[0] != 0)
1132 return -1;
1084 disable_apic_timer = 1; 1133 disable_apic_timer = 1;
1085 return 0; 1134 return 0;
1086} 1135}
1087 1136
1137static __init int setup_apicmaintimer(char *str)
1138{
1139 apic_runs_main_timer = 1;
1140 nohpet = 1;
1141 return 0;
1142}
1143__setup("apicmaintimer", setup_apicmaintimer);
1144
1145static __init int setup_noapicmaintimer(char *str)
1146{
1147 apic_runs_main_timer = -1;
1148 return 0;
1149}
1150__setup("noapicmaintimer", setup_noapicmaintimer);
1151
1152static __init int setup_apicpmtimer(char *s)
1153{
1154 apic_calibrate_pmtmr = 1;
1155 return setup_apicmaintimer(NULL);
1156}
1157__setup("apicpmtimer", setup_apicpmtimer);
1158
1088/* dummy parsing: see setup.c */ 1159/* dummy parsing: see setup.c */
1089 1160
1090__setup("disableapic", setup_disableapic); 1161__setup("disableapic", setup_disableapic);