aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2007-02-16 04:27:58 -0500
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-02-16 11:13:58 -0500
commite05d723f98595b2f4d368f63636a997d98703304 (patch)
tree53642dafc66ff9b61d2162b879860b6a038ce4ba
parentd66bea57e779cd592657cca6e61345ae899b78d9 (diff)
[PATCH] i386, apic: clean up the APIC code
The apic code is quite unstructured and missing a lot of comments. - Restructure the code into helper functions, timer, setup/shutdown, interrupt and power management blocks. - Fixup comments. - Namespace fixups - Inline helpers for version and is_integrated - Combine the ack_bad_irq functions No functional changes. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Ingo Molnar <mingo@elte.hu> Cc: Zachary Amsden <zach@vmware.com> Cc: "Eric W. Biederman" <ebiederm@xmission.com> Cc: Rohit Seth <rohitseth@google.com> Cc: Andi Kleen <ak@suse.de> Cc: john stultz <johnstul@us.ibm.com> Cc: Roman Zippel <zippel@linux-m68k.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--arch/i386/kernel/apic.c1553
-rw-r--r--arch/i386/kernel/io_apic.c2
-rw-r--r--arch/i386/kernel/irq.c22
-rw-r--r--arch/i386/kernel/smpboot.c4
-rw-r--r--include/asm-i386/apic.h2
5 files changed, 816 insertions, 767 deletions
diff --git a/arch/i386/kernel/apic.c b/arch/i386/kernel/apic.c
index f4159e0a7ae9..b56448f214a7 100644
--- a/arch/i386/kernel/apic.c
+++ b/arch/i386/kernel/apic.c
@@ -45,6 +45,13 @@
45#include "io_ports.h" 45#include "io_ports.h"
46 46
47/* 47/*
48 * Sanity check
49 */
50#if (SPURIOUS_APIC_VECTOR & 0x0F) != 0x0F
51# error SPURIOUS_APIC_VECTOR definition error
52#endif
53
54/*
48 * cpu_mask that denotes the CPUs that needs timer interrupt coming in as 55 * cpu_mask that denotes the CPUs that needs timer interrupt coming in as
49 * IPIs in place of local APIC timers 56 * IPIs in place of local APIC timers
50 */ 57 */
@@ -52,121 +59,472 @@ static cpumask_t timer_bcast_ipi;
52 59
53/* 60/*
54 * Knob to control our willingness to enable the local APIC. 61 * Knob to control our willingness to enable the local APIC.
62 *
63 * -1=force-disable, +1=force-enable
55 */ 64 */
56static int enable_local_apic __initdata = 0; /* -1=force-disable, +1=force-enable */ 65static int enable_local_apic __initdata = 0;
66
67/*
68 * Debug level, exported for io_apic.c
69 */
70int apic_verbosity;
71
72static void apic_pm_activate(void);
57 73
58static inline void lapic_disable(void) 74
75/* Using APIC to generate smp_local_timer_interrupt? */
76int using_apic_timer __read_mostly = 0;
77
78/* Local APIC was disabled by the BIOS and enabled by the kernel */
79static int enabled_via_apicbase;
80
81/*
82 * Get the LAPIC version
83 */
84static inline int lapic_get_version(void)
59{ 85{
60 enable_local_apic = -1; 86 return GET_APIC_VERSION(apic_read(APIC_LVR));
61 clear_bit(X86_FEATURE_APIC, boot_cpu_data.x86_capability);
62} 87}
63 88
64static inline void lapic_enable(void) 89/*
90 * Check, if the APIC is integrated or a seperate chip
91 */
92static inline int lapic_is_integrated(void)
65{ 93{
66 enable_local_apic = 1; 94 return APIC_INTEGRATED(lapic_get_version());
67} 95}
68 96
69/* 97/*
70 * Debug level 98 * Check, whether this is a modern or a first generation APIC
71 */ 99 */
72int apic_verbosity;
73
74
75static void apic_pm_activate(void);
76
77static int modern_apic(void) 100static int modern_apic(void)
78{ 101{
79 unsigned int lvr, version;
80 /* AMD systems use old APIC versions, so check the CPU */ 102 /* AMD systems use old APIC versions, so check the CPU */
81 if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD && 103 if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD &&
82 boot_cpu_data.x86 >= 0xf) 104 boot_cpu_data.x86 >= 0xf)
83 return 1; 105 return 1;
84 lvr = apic_read(APIC_LVR); 106 return lapic_get_version() >= 0x14;
85 version = GET_APIC_VERSION(lvr); 107}
86 return version >= 0x14; 108
109/**
110 * enable_NMI_through_LVT0 - enable NMI through local vector table 0
111 */
112void enable_NMI_through_LVT0 (void * dummy)
113{
114 unsigned int v = APIC_DM_NMI;
115
116 /* Level triggered for 82489DX */
117 if (!lapic_is_integrated())
118 v |= APIC_LVT_LEVEL_TRIGGER;
119 apic_write_around(APIC_LVT0, v);
120}
121
122/**
123 * get_physical_broadcast - Get number of physical broadcast IDs
124 */
125int get_physical_broadcast(void)
126{
127 return modern_apic() ? 0xff : 0xf;
128}
129
130/**
131 * lapic_get_maxlvt - get the maximum number of local vector table entries
132 */
133int lapic_get_maxlvt(void)
134{
135 unsigned int v = apic_read(APIC_LVR);
136
137 /* 82489DXs do not report # of LVT entries. */
138 return APIC_INTEGRATED(GET_APIC_VERSION(v)) ? GET_APIC_MAXLVT(v) : 2;
87} 139}
88 140
89/* 141/*
90 * 'what should we do if we get a hw irq event on an illegal vector'. 142 * Local APIC timer
91 * each architecture has to answer this themselves. 143 */
144
145/*
146 * This part sets up the APIC 32 bit clock in LVTT1, with HZ interrupts
147 * per second. We assume that the caller has already set up the local
148 * APIC.
149 *
150 * The APIC timer is not exactly sync with the external timer chip, it
151 * closely follows bus clocks.
152 */
153
154/*
155 * The timer chip is already set up at HZ interrupts per second here,
156 * but we do not accept timer interrupts yet. We only allow the BP
157 * to calibrate.
92 */ 158 */
93void ack_bad_irq(unsigned int irq) 159static unsigned int __devinit get_8254_timer_count(void)
160{
161 unsigned long flags;
162
163 unsigned int count;
164
165 spin_lock_irqsave(&i8253_lock, flags);
166
167 outb_p(0x00, PIT_MODE);
168 count = inb_p(PIT_CH0);
169 count |= inb_p(PIT_CH0) << 8;
170
171 spin_unlock_irqrestore(&i8253_lock, flags);
172
173 return count;
174}
175
176/* next tick in 8254 can be caught by catching timer wraparound */
177static void __devinit wait_8254_wraparound(void)
94{ 178{
95 printk("unexpected IRQ trap at vector %02x\n", irq); 179 unsigned int curr_count, prev_count;
180
181 curr_count = get_8254_timer_count();
182 do {
183 prev_count = curr_count;
184 curr_count = get_8254_timer_count();
185
186 /* workaround for broken Mercury/Neptune */
187 if (prev_count >= curr_count + 0x100)
188 curr_count = get_8254_timer_count();
189
190 } while (prev_count >= curr_count);
191}
192
193/*
194 * Default initialization for 8254 timers. If we use other timers like HPET,
195 * we override this later
196 */
197void (*wait_timer_tick)(void) __devinitdata = wait_8254_wraparound;
198
199/*
200 * This function sets up the local APIC timer, with a timeout of
201 * 'clocks' APIC bus clock. During calibration we actually call
202 * this function twice on the boot CPU, once with a bogus timeout
203 * value, second time for real. The other (noncalibrating) CPUs
204 * call this function only once, with the real, calibrated value.
205 *
206 * We do reads before writes even if unnecessary, to get around the