aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86_64
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@merom.osdl.org>2006-11-08 13:27:54 -0500
committerLinus Torvalds <torvalds@merom.osdl.org>2006-11-08 13:27:54 -0500
commit48797ebd9e8b16fddcd4ef062f792314a6b9219a (patch)
treea192a4d6d2158da763def73627362169963dc4d0 /arch/x86_64
parent6c0ffb9d2fd987c79c6cbb81c3f3011c63749b1a (diff)
x86-64: write IO APIC irq routing entries in correct order
This is the x86-64 version of f9dadfa71bc594df09044da61d1c72701121d802 that did the same thing on i386. Since the "mask" bit is in the low word, when we write a new entry, we need to write the high word first, before we potentially unmask it. The exception is when we actually want to mask the interrupt, in which case we want to write the low word first to make sure that the high word doesn't change while the interrupt routing is still active. Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch/x86_64')
-rw-r--r--arch/x86_64/kernel/io_apic.c26
1 files changed, 23 insertions, 3 deletions
diff --git a/arch/x86_64/kernel/io_apic.c b/arch/x86_64/kernel/io_apic.c
index 96e02d845716..3b8f9c68ad3c 100644
--- a/arch/x86_64/kernel/io_apic.c
+++ b/arch/x86_64/kernel/io_apic.c
@@ -172,12 +172,34 @@ static struct IO_APIC_route_entry ioapic_read_entry(int apic, int pin)
172 return eu.entry; 172 return eu.entry;
173} 173}
174 174
175/*
176 * When we write a new IO APIC routing entry, we need to write the high
177 * word first! If the mask bit in the low word is clear, we will enable
178 * the interrupt, and we need to make sure the entry is fully populated
179 * before that happens.
180 */
175static void ioapic_write_entry(int apic, int pin, struct IO_APIC_route_entry e) 181static void ioapic_write_entry(int apic, int pin, struct IO_APIC_route_entry e)
176{ 182{
177 unsigned long flags; 183 unsigned long flags;
178 union entry_union eu; 184 union entry_union eu;
179 eu.entry = e; 185 eu.entry = e;
180 spin_lock_irqsave(&ioapic_lock, flags); 186 spin_lock_irqsave(&ioapic_lock, flags);
187 io_apic_write(apic, 0x11 + 2*pin, eu.w2);
188 io_apic_write(apic, 0x10 + 2*pin, eu.w1);
189 spin_unlock_irqrestore(&ioapic_lock, flags);
190}
191
192/*
193 * When we mask an IO APIC routing entry, we need to write the low
194 * word first, in order to set the mask bit before we change the
195 * high bits!
196 */
197static void ioapic_mask_entry(int apic, int pin)
198{
199 unsigned long flags;
200 union entry_union eu = { .entry.mask = 1 };
201
202 spin_lock_irqsave(&ioapic_lock, flags);
181 io_apic_write(apic, 0x10 + 2*pin, eu.w1); 203 io_apic_write(apic, 0x10 + 2*pin, eu.w1);
182 io_apic_write(apic, 0x11 + 2*pin, eu.w2); 204 io_apic_write(apic, 0x11 + 2*pin, eu.w2);
183 spin_unlock_irqrestore(&ioapic_lock, flags); 205 spin_unlock_irqrestore(&ioapic_lock, flags);
@@ -302,9 +324,7 @@ static void clear_IO_APIC_pin(unsigned int apic, unsigned int pin)
302 /* 324 /*
303 * Disable it in the IO-APIC irq-routing table: 325 * Disable it in the IO-APIC irq-routing table:
304 */ 326 */
305 memset(&entry, 0, sizeof(entry)); 327 ioapic_mask_entry(apic, pin);
306 entry.mask = 1;
307 ioapic_write_entry(apic, pin, entry);
308} 328}
309 329
310static void clear_IO_APIC (void) 330static void clear_IO_APIC (void)