diff options
| author | Thomas Gleixner <tglx@linutronix.de> | 2007-02-16 04:27:58 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-02-16 11:13:58 -0500 |
| commit | e05d723f98595b2f4d368f63636a997d98703304 (patch) | |
| tree | 53642dafc66ff9b61d2162b879860b6a038ce4ba | |
| parent | d66bea57e779cd592657cca6e61345ae899b78d9 (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.c | 1553 | ||||
| -rw-r--r-- | arch/i386/kernel/io_apic.c | 2 | ||||
| -rw-r--r-- | arch/i386/kernel/irq.c | 22 | ||||
| -rw-r--r-- | arch/i386/kernel/smpboot.c | 4 | ||||
| -rw-r--r-- | include/asm-i386/apic.h | 2 |
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 | */ |
| 56 | static int enable_local_apic __initdata = 0; /* -1=force-disable, +1=force-enable */ | 65 | static int enable_local_apic __initdata = 0; |
| 66 | |||
| 67 | /* | ||
| 68 | * Debug level, exported for io_apic.c | ||
| 69 | */ | ||
| 70 | int apic_verbosity; | ||
| 71 | |||
| 72 | static void apic_pm_activate(void); | ||
| 57 | 73 | ||
| 58 | static inline void lapic_disable(void) | 74 | |
| 75 | /* Using APIC to generate smp_local_timer_interrupt? */ | ||
| 76 | int using_apic_timer __read_mostly = 0; | ||
| 77 | |||
| 78 | /* Local APIC was disabled by the BIOS and enabled by the kernel */ | ||
| 79 | static int enabled_via_apicbase; | ||
| 80 | |||
| 81 | /* | ||
| 82 | * Get the LAPIC version | ||
| 83 | */ | ||
| 84 | static 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 | ||
| 64 | static inline void lapic_enable(void) | 89 | /* |
| 90 | * Check, if the APIC is integrated or a seperate chip | ||
| 91 | */ | ||
| 92 | static 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 | */ |
| 72 | int apic_verbosity; | ||
| 73 | |||
| 74 | |||
| 75 | static void apic_pm_activate(void); | ||
| 76 | |||
| 77 | static int modern_apic(void) | 100 | static 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 | */ | ||
| 112 | void 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 | */ | ||
| 125 | int 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 | */ | ||
| 133 | int 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 | */ |
| 93 | void ack_bad_irq(unsigned int irq) | 159 | static 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 */ | ||
| 177 | static 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 | */ | ||
| 197 | void (*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 | ||
