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