2 * Local APIC handling, local APIC timers
4 * (c) 1999, 2000 Ingo Molnar <mingo@redhat.com>
7 * Maciej W. Rozycki : Bits for genuine 82489DX APICs;
8 * thanks to Eric Gilmore
10 * for testing these extensively.
11 * Maciej W. Rozycki : Various updates and fixes.
12 * Mikael Pettersson : Power Management for UP-APIC.
14 * Mikael Pettersson : PM converted to driver model.
17 #include <linux/init.h>
20 #include <linux/delay.h>
21 #include <linux/bootmem.h>
22 #include <linux/smp_lock.h>
23 #include <linux/interrupt.h>
24 #include <linux/mc146818rtc.h>
25 #include <linux/kernel_stat.h>
26 #include <linux/sysdev.h>
27 #include <linux/module.h>
28 #include <linux/ioport.h>
30 #include <asm/atomic.h>
33 #include <asm/mpspec.h>
34 #include <asm/pgalloc.h>
35 #include <asm/mach_apic.h>
38 #include <asm/proto.h>
39 #include <asm/timex.h>
46 * 'what should we do if we get a hw irq event on an illegal vector'.
47 * each architecture has to answer this themselves.
49 void ack_bad_irq(unsigned int irq)
51 printk("unexpected IRQ trap at vector %02x\n", irq);
53 * Currently unexpected vectors happen only on SMP and APIC.
54 * We _must_ ack these because every local APIC has only N
55 * irq slots per priority level, and a 'hanging, unacked' IRQ
56 * holds up an irq slot - in excessive cases (when multiple
57 * unexpected vectors occur) that might lock up the APIC
59 * But don't ack when the APIC is disabled. -AK
65 int setup_profiling_timer(unsigned int multiplier)
70 void smp_local_timer_interrupt(void)
72 profile_tick(CPU_PROFILING);
75 update_process_times(user_mode(get_irq_regs()));
77 if (apic_runs_main_timer > 1 && smp_processor_id() == boot_cpu_id)
81 * We take the 'long' return path, and there every subsystem
82 * grabs the appropriate locks (kernel lock/ irq lock).
84 * We might want to decouple profiling from the 'long path',
85 * and do the profiling totally in assembly.
87 * Currently this isn't too much of an issue (performance wise),
88 * we can take more than 100K local irqs per second on a 100 MHz P5.
93 * Local APIC timer interrupt. This is the most natural way for doing
94 * local interrupts, but local timer interrupts can be emulated by
95 * broadcast interrupts too. [in case the hw doesn't support APIC timers]
97 * [ if a single-CPU system runs an SMP kernel then we call the local
98 * interrupt as well. Thus we cannot inline the local irq ... ]
100 void smp_apic_timer_interrupt(struct pt_regs *regs)
102 struct pt_regs *old_regs = set_irq_regs(regs);
105 * the NMI deadlock-detector uses this.
107 add_pda(apic_timer_irqs, 1);
110 * NOTE! We'd better ACK the irq immediately,
111 * because timer handling can be slow.
115 * update_process_times() expects us to have done irq_enter().
116 * Besides, if we don't timer interrupts ignore the global
117 * interrupt lock, which is the WrongThing (tm) to do.
121 smp_local_timer_interrupt();
123 set_irq_regs(old_regs);
127 * This interrupt should _never_ happen with our APIC/SMP architecture
129 asmlinkage void smp_spurious_interrupt(void)
135 * Check if this really is a spurious interrupt and ACK it
136 * if it is a vectored one. Just in case...
137 * Spurious interrupts should not be ACKed.
139 v = apic_read(APIC_ISR + ((SPURIOUS_APIC_VECTOR & ~0x1f) >> 1));
140 if (v & (1 << (SPURIOUS_APIC_VECTOR & 0x1f)))
144 static unsigned long last_warning;
145 static unsigned long skipped;
147 /* see sw-dev-man vol 3, chapter 7.4.13.5 */
148 if (time_before(last_warning+30*HZ,jiffies)) {
149 printk(KERN_INFO "spurious APIC interrupt on CPU#%d, %ld skipped.\n",
150 smp_processor_id(), skipped);
151 last_warning = jiffies;
161 * This interrupt should never happen with our APIC/SMP architecture
164 asmlinkage void smp_error_interrupt(void)
170 /* First tickle the hardware, only then report what went on. -- REW */
171 v = apic_read(APIC_ESR);
172 apic_write(APIC_ESR, 0);
173 v1 = apic_read(APIC_ESR);
175 atomic_inc(&irq_err_count);
177 /* Here is what the APIC error bits mean:
181 3: Receive accept error
183 5: Send illegal vector
184 6: Received illegal vector
185 7: Illegal register address
187 if (num_online_cpus() > 1)
188 printk (KERN_DEBUG "APIC error on CPU%d: %02x(%02x)\n",
189 smp_processor_id(), v , v1);
196 * This initializes the IO-APIC and APIC hardware if this is
199 int __init APIC_init_uniprocessor (void)
201 if (smp_found_config && !skip_ioapic_setup && nr_ioapics)
207 static __init int setup_disableapic(char *str)
210 clear_bit(X86_FEATURE_APIC, boot_cpu_data.x86_capability);
213 early_param("disableapic", setup_disableapic);
215 /* same as disableapic, for compatibility */
216 static __init int setup_nolapic(char *str)
218 return setup_disableapic(str);
220 early_param("nolapic", setup_nolapic);
222 static __init int setup_noapictimer(char *str)
224 if (str[0] != ' ' && str[0] != 0)
226 disable_apic_timer = 1;
230 static __init int setup_apicmaintimer(char *str)
232 apic_runs_main_timer = 1;
236 __setup("apicmaintimer", setup_apicmaintimer);
238 static __init int setup_noapicmaintimer(char *str)
240 apic_runs_main_timer = -1;
243 __setup("noapicmaintimer", setup_noapicmaintimer);
245 static __init int setup_apicpmtimer(char *s)
247 apic_calibrate_pmtmr = 1;
249 return setup_apicmaintimer(NULL);
251 __setup("apicpmtimer", setup_apicpmtimer);
253 __setup("noapictimer", setup_noapictimer);