ia64/xen-unstable

view linux-2.6-xen-sparse/arch/xen/x86_64/kernel/apic.c @ 6538:84ee014ebd41

Merge xen-vtx-unstable.hg
author adsharma@los-vmm.sc.intel.com
date Wed Aug 17 12:34:38 2005 -0800 (2005-08-17)
parents 23979fb12c49 a42bf05b188c
children 99914b54f7bf
line source
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 */
17 #include <linux/config.h>
18 #include <linux/init.h>
20 #include <linux/mm.h>
21 #include <linux/irq.h>
22 #include <linux/delay.h>
23 #include <linux/bootmem.h>
24 #include <linux/smp_lock.h>
25 #include <linux/interrupt.h>
26 #include <linux/mc146818rtc.h>
27 #include <linux/kernel_stat.h>
28 #include <linux/sysdev.h>
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>
38 #include "io_ports.h"
40 /*
41 * Debug level
42 */
43 int apic_verbosity;
44 int disable_apic;
46 void smp_local_timer_interrupt(struct pt_regs *regs)
47 {
49 profile_tick(CPU_PROFILING, regs);
50 #ifndef CONFIG_XEN
51 int cpu = smp_processor_id();
53 if (--per_cpu(prof_counter, cpu) <= 0) {
54 /*
55 * The multiplier may have changed since the last time we got
56 * to this point as a result of the user writing to
57 * /proc/profile. In this case we need to adjust the APIC
58 * timer accordingly.
59 *
60 * Interrupts are already masked off at this point.
61 */
62 per_cpu(prof_counter, cpu) = per_cpu(prof_multiplier, cpu);
63 if (per_cpu(prof_counter, cpu) !=
64 per_cpu(prof_old_multiplier, cpu)) {
65 __setup_APIC_LVTT(calibration_result/
66 per_cpu(prof_counter, cpu));
67 per_cpu(prof_old_multiplier, cpu) =
68 per_cpu(prof_counter, cpu);
69 }
71 #ifdef CONFIG_SMP
72 update_process_times(user_mode(regs));
73 #endif
74 }
75 #endif
77 /*
78 * We take the 'long' return path, and there every subsystem
79 * grabs the appropriate locks (kernel lock/ irq lock).
80 *
81 * we might want to decouple profiling from the 'long path',
82 * and do the profiling totally in assembly.
83 *
84 * Currently this isn't too much of an issue (performance wise),
85 * we can take more than 100K local irqs per second on a 100 MHz P5.
86 */
87 }
89 /*
90 * Local APIC timer interrupt. This is the most natural way for doing
91 * local interrupts, but local timer interrupts can be emulated by
92 * broadcast interrupts too. [in case the hw doesn't support APIC timers]
93 *
94 * [ if a single-CPU system runs an SMP kernel then we call the local
95 * interrupt as well. Thus we cannot inline the local irq ... ]
96 */
97 void smp_apic_timer_interrupt(struct pt_regs *regs)
98 {
99 /*
100 * the NMI deadlock-detector uses this.
101 */
102 add_pda(apic_timer_irqs, 1);
104 /*
105 * NOTE! We'd better ACK the irq immediately,
106 * because timer handling can be slow.
107 */
108 ack_APIC_irq();
109 /*
110 * update_process_times() expects us to have done irq_enter().
111 * Besides, if we don't timer interrupts ignore the global
112 * interrupt lock, which is the WrongThing (tm) to do.
113 */
114 irq_enter();
115 smp_local_timer_interrupt(regs);
116 irq_exit();
117 }
119 /*
120 * This interrupt should _never_ happen with our APIC/SMP architecture
121 */
122 asmlinkage void smp_spurious_interrupt(void)
123 {
124 unsigned int v;
125 irq_enter();
126 /*
127 * Check if this really is a spurious interrupt and ACK it
128 * if it is a vectored one. Just in case...
129 * Spurious interrupts should not be ACKed.
130 */
131 v = apic_read(APIC_ISR + ((SPURIOUS_APIC_VECTOR & ~0x1f) >> 1));
132 if (v & (1 << (SPURIOUS_APIC_VECTOR & 0x1f)))
133 ack_APIC_irq();
135 #if 0
136 static unsigned long last_warning;
137 static unsigned long skipped;
139 /* see sw-dev-man vol 3, chapter 7.4.13.5 */
140 if (time_before(last_warning+30*HZ,jiffies)) {
141 printk(KERN_INFO "spurious APIC interrupt on CPU#%d, %ld skipped.\n",
142 smp_processor_id(), skipped);
143 last_warning = jiffies;
144 skipped = 0;
145 } else {
146 skipped++;
147 }
148 #endif
149 irq_exit();
150 }
152 /*
153 * This interrupt should never happen with our APIC/SMP architecture
154 */
156 asmlinkage void smp_error_interrupt(void)
157 {
158 unsigned int v, v1;
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);
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 }
183 int get_physical_broadcast(void)
184 {
185 return 0xff;
186 }
188 /*
189 * This initializes the IO-APIC and APIC hardware if this is
190 * a UP kernel.
191 */
192 int __init APIC_init_uniprocessor (void)
193 {
194 #ifdef CONFIG_X86_IO_APIC
195 if (smp_found_config)
196 if (!skip_ioapic_setup && nr_ioapics)
197 setup_IO_APIC();
198 #endif
200 return 0;
201 }