Merge to Fedora kernel-2.6.18-1.2224_FC5 patched with stable patch-2.6.18.1-vs2.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
29 #include <asm/atomic.h>
30 #include <asm/smp.h>
31 #include <asm/mtrr.h>
32 #include <asm/mpspec.h>
33 #include <asm/desc.h>
34 #include <asm/arch_hooks.h>
35 #include <asm/hpet.h>
36 #include <asm/idle.h>
37
38 int apic_verbosity;
39
40 /*
41  * 'what should we do if we get a hw irq event on an illegal vector'.
42  * each architecture has to answer this themselves.
43  */
44 void ack_bad_irq(unsigned int irq)
45 {
46         printk("unexpected IRQ trap at vector %02x\n", irq);
47         /*
48          * Currently unexpected vectors happen only on SMP and APIC.
49          * We _must_ ack these because every local APIC has only N
50          * irq slots per priority level, and a 'hanging, unacked' IRQ
51          * holds up an irq slot - in excessive cases (when multiple
52          * unexpected vectors occur) that might lock up the APIC
53          * completely.
54          * But don't ack when the APIC is disabled. -AK
55          */
56         if (!disable_apic)
57                 ack_APIC_irq();
58 }
59
60 int setup_profiling_timer(unsigned int multiplier)
61 {
62         return -EINVAL;
63 }
64
65 void smp_local_timer_interrupt(struct pt_regs *regs)
66 {
67         profile_tick(CPU_PROFILING, regs);
68 #ifndef CONFIG_XEN
69 #ifdef CONFIG_SMP
70                 update_process_times(user_mode(regs));
71 #endif
72 #endif
73         /*
74          * We take the 'long' return path, and there every subsystem
75          * grabs the appropriate locks (kernel lock/ irq lock).
76          *
77          * we might want to decouple profiling from the 'long path',
78          * and do the profiling totally in assembly.
79          *
80          * Currently this isn't too much of an issue (performance wise),
81          * we can take more than 100K local irqs per second on a 100 MHz P5.
82          */
83 }
84
85 /*
86  * Local APIC timer interrupt. This is the most natural way for doing
87  * local interrupts, but local timer interrupts can be emulated by
88  * broadcast interrupts too. [in case the hw doesn't support APIC timers]
89  *
90  * [ if a single-CPU system runs an SMP kernel then we call the local
91  *   interrupt as well. Thus we cannot inline the local irq ... ]
92  */
93 void smp_apic_timer_interrupt(struct pt_regs *regs)
94 {
95         /*
96          * the NMI deadlock-detector uses this.
97          */
98         add_pda(apic_timer_irqs, 1);
99
100         /*
101          * NOTE! We'd better ACK the irq immediately,
102          * because timer handling can be slow.
103          */
104         ack_APIC_irq();
105         /*
106          * update_process_times() expects us to have done irq_enter().
107          * Besides, if we don't timer interrupts ignore the global
108          * interrupt lock, which is the WrongThing (tm) to do.
109          */
110         exit_idle();
111         irq_enter();
112         smp_local_timer_interrupt(regs);
113         irq_exit();
114 }
115
116 /*
117  * This interrupt should _never_ happen with our APIC/SMP architecture
118  */
119 asmlinkage void smp_spurious_interrupt(void)
120 {
121         unsigned int v;
122         exit_idle();
123         irq_enter();
124         /*
125          * Check if this really is a spurious interrupt and ACK it
126          * if it is a vectored one.  Just in case...
127          * Spurious interrupts should not be ACKed.
128          */
129         v = apic_read(APIC_ISR + ((SPURIOUS_APIC_VECTOR & ~0x1f) >> 1));
130         if (v & (1 << (SPURIOUS_APIC_VECTOR & 0x1f)))
131                 ack_APIC_irq();
132
133 #if 0
134         static unsigned long last_warning; 
135         static unsigned long skipped; 
136
137         /* see sw-dev-man vol 3, chapter 7.4.13.5 */
138         if (time_before(last_warning+30*HZ,jiffies)) { 
139                 printk(KERN_INFO "spurious APIC interrupt on CPU#%d, %ld skipped.\n",
140                        smp_processor_id(), skipped);
141                 last_warning = jiffies; 
142                 skipped = 0;
143         } else { 
144                 skipped++; 
145         } 
146 #endif 
147         irq_exit();
148 }
149
150 /*
151  * This interrupt should never happen with our APIC/SMP architecture
152  */
153
154 asmlinkage void smp_error_interrupt(void)
155 {
156         unsigned int v, v1;
157
158         exit_idle();
159         irq_enter();
160         /* First tickle the hardware, only then report what went on. -- REW */
161         v = apic_read(APIC_ESR);
162         apic_write(APIC_ESR, 0);
163         v1 = apic_read(APIC_ESR);
164         ack_APIC_irq();
165         atomic_inc(&irq_err_count);
166
167         /* Here is what the APIC error bits mean:
168            0: Send CS error
169            1: Receive CS error
170            2: Send accept error
171            3: Receive accept error
172            4: Reserved
173            5: Send illegal vector
174            6: Received illegal vector
175            7: Illegal register address
176         */
177         if (num_online_cpus() > 1)
178                 printk (KERN_DEBUG "APIC error on CPU%d: %02x(%02x)\n",
179                 smp_processor_id(), v , v1);
180         irq_exit();
181 }
182
183 int disable_apic;
184
185 /*
186  * This initializes the IO-APIC and APIC hardware if this is
187  * a UP kernel.
188  */
189 int __init APIC_init_uniprocessor (void)
190 {
191 #ifdef CONFIG_X86_IO_APIC
192         if (smp_found_config)
193                 if (!skip_ioapic_setup && nr_ioapics)
194                         setup_IO_APIC();
195 #endif
196
197         return 1;
198 }