fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / arch / x86_64 / kernel / apic-xen.c
1 /*
2  *      Local APIC handling, local APIC timers
3  *
4  *      (c) 1999, 2000 Ingo Molnar <mingo@redhat.com>
5  *
6  *      Fixes
7  *      Maciej W. Rozycki       :       Bits for genuine 82489DX APICs;
8  *                                      thanks to Eric Gilmore
9  *                                      and Rolf G. Tews
10  *                                      for testing these extensively.
11  *      Maciej W. Rozycki       :       Various updates and fixes.
12  *      Mikael Pettersson       :       Power Management for UP-APIC.
13  *      Pavel Machek and
14  *      Mikael Pettersson       :       PM converted to driver model.
15  */
16
17 #include <linux/init.h>
18
19 #include <linux/mm.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>
29
30 #include <asm/atomic.h>
31 #include <asm/smp.h>
32 #include <asm/mtrr.h>
33 #include <asm/mpspec.h>
34 #include <asm/pgalloc.h>
35 #include <asm/mach_apic.h>
36 #include <asm/nmi.h>
37 #include <asm/idle.h>
38 #include <asm/proto.h>
39 #include <asm/timex.h>
40 #include <asm/apic.h>
41
42 int apic_mapped;
43 int apic_verbosity;
44
45 /*
46  * 'what should we do if we get a hw irq event on an illegal vector'.
47  * each architecture has to answer this themselves.
48  */
49 void ack_bad_irq(unsigned int irq)
50 {
51         printk("unexpected IRQ trap at vector %02x\n", irq);
52         /*
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
58          * completely.
59          * But don't ack when the APIC is disabled. -AK
60          */
61         if (!disable_apic)
62                 ack_APIC_irq();
63 }
64
65 int setup_profiling_timer(unsigned int multiplier)
66 {
67         return -EINVAL;
68 }
69
70 void smp_local_timer_interrupt(void)
71 {
72         profile_tick(CPU_PROFILING);
73 #ifndef CONFIG_XEN
74 #ifdef CONFIG_SMP
75         update_process_times(user_mode(get_irq_regs()));
76 #endif
77         if (apic_runs_main_timer > 1 && smp_processor_id() == boot_cpu_id)
78                 main_timer_handler();
79 #endif
80         /*
81          * We take the 'long' return path, and there every subsystem
82          * grabs the appropriate locks (kernel lock/ irq lock).
83          *
84          * We might want to decouple profiling from the 'long path',
85          * and do the profiling totally in assembly.
86          *
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.
89          */
90 }
91
92 /*
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]
96  *
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 ... ]
99  */
100 void smp_apic_timer_interrupt(struct pt_regs *regs)
101 {
102         struct pt_regs *old_regs = set_irq_regs(regs);
103
104         /*
105          * the NMI deadlock-detector uses this.
106          */
107         add_pda(apic_timer_irqs, 1);
108
109         /*
110          * NOTE! We'd better ACK the irq immediately,
111          * because timer handling can be slow.
112          */
113         ack_APIC_irq();
114         /*
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.
118          */
119         exit_idle();
120         irq_enter();
121         smp_local_timer_interrupt();
122         irq_exit();
123         set_irq_regs(old_regs);
124 }
125
126 /*
127  * This interrupt should _never_ happen with our APIC/SMP architecture
128  */
129 asmlinkage void smp_spurious_interrupt(void)
130 {
131         unsigned int v;
132         exit_idle();
133         irq_enter();
134         /*
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.
138          */
139         v = apic_read(APIC_ISR + ((SPURIOUS_APIC_VECTOR & ~0x1f) >> 1));
140         if (v & (1 << (SPURIOUS_APIC_VECTOR & 0x1f)))
141                 ack_APIC_irq();
142
143 #if 0
144         static unsigned long last_warning; 
145         static unsigned long skipped; 
146
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; 
152                 skipped = 0;
153         } else { 
154                 skipped++; 
155         } 
156 #endif 
157         irq_exit();
158 }
159
160 /*
161  * This interrupt should never happen with our APIC/SMP architecture
162  */
163
164 asmlinkage void smp_error_interrupt(void)
165 {
166         unsigned int v, v1;
167
168         exit_idle();
169         irq_enter();
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);
174         ack_APIC_irq();
175         atomic_inc(&irq_err_count);
176
177         /* Here is what the APIC error bits mean:
178            0: Send CS error
179            1: Receive CS error
180            2: Send accept error
181            3: Receive accept error
182            4: Reserved
183            5: Send illegal vector
184            6: Received illegal vector
185            7: Illegal register address
186         */
187         if (num_online_cpus() > 1)
188                 printk (KERN_DEBUG "APIC error on CPU%d: %02x(%02x)\n",
189                 smp_processor_id(), v , v1);
190         irq_exit();
191 }
192
193 int disable_apic; 
194
195 /*
196  * This initializes the IO-APIC and APIC hardware if this is
197  * a UP kernel.
198  */
199 int __init APIC_init_uniprocessor (void)
200 {
201         if (smp_found_config && !skip_ioapic_setup && nr_ioapics)
202                 setup_IO_APIC();
203         return 0;
204 }
205
206 #ifndef CONFIG_XEN
207 static __init int setup_disableapic(char *str) 
208
209         disable_apic = 1;
210         clear_bit(X86_FEATURE_APIC, boot_cpu_data.x86_capability);
211         return 0;
212 }
213 early_param("disableapic", setup_disableapic);
214
215 /* same as disableapic, for compatibility */
216 static __init int setup_nolapic(char *str) 
217
218         return setup_disableapic(str);
219
220 early_param("nolapic", setup_nolapic);
221
222 static __init int setup_noapictimer(char *str) 
223
224         if (str[0] != ' ' && str[0] != 0)
225                 return 0;
226         disable_apic_timer = 1;
227         return 1;
228
229
230 static __init int setup_apicmaintimer(char *str)
231 {
232         apic_runs_main_timer = 1;
233         nohpet = 1;
234         return 1;
235 }
236 __setup("apicmaintimer", setup_apicmaintimer);
237
238 static __init int setup_noapicmaintimer(char *str)
239 {
240         apic_runs_main_timer = -1;
241         return 1;
242 }
243 __setup("noapicmaintimer", setup_noapicmaintimer);
244
245 static __init int setup_apicpmtimer(char *s)
246 {
247         apic_calibrate_pmtmr = 1;
248         notsc_setup(NULL);
249         return setup_apicmaintimer(NULL);
250 }
251 __setup("apicpmtimer", setup_apicpmtimer);
252
253 __setup("noapictimer", setup_noapictimer); 
254
255 #endif