aboutsummaryrefslogtreecommitdiffstats
path: root/arch/i386/kernel
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@macmini.osdl.org>2006-11-01 13:05:35 -0500
committerLinus Torvalds <torvalds@macmini.osdl.org>2006-11-01 13:06:52 -0500
commitf9dadfa71bc594df09044da61d1c72701121d802 (patch)
treeffbd7d1b53b5393f078476e3dbe78284d7d847d4 /arch/i386/kernel
parent130fe05dbc0114609cfef9815c0c5580b42decfa (diff)
i386: write IO APIC irq routing entries in correct order
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/i386/kernel')
-rw-r--r--arch/i386/kernel/io_apic.c26
1 files changed, 23 insertions, 3 deletions
diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c
index eb10bd5da64e..507983c513c3 100644
--- a/arch/i386/kernel/io_apic.c
+++ b/arch/i386/kernel/io_apic.c
@@ -147,12 +147,34 @@ static struct IO_APIC_route_entry ioapic_read_entry(int apic, int pin)
147 return eu.entry; 147 return eu.entry;
148} 148}
149 149
150/*
151 * When we write a new IO APIC routing entry, we need to write the high
152 * word first! If the mask bit in the low word is clear, we will enable
153 * the interrupt, and we need to make sure the entry is fully populated
154 * before that happens.
155 */
150static void ioapic_write_entry(int apic, int pin, struct IO_APIC_route_entry e) 156static void ioapic_write_entry(int apic, int pin, struct IO_APIC_route_entry e)
151{ 157{
152 unsigned long flags; 158 unsigned long flags;
153 union entry_union eu; 159 union entry_union eu;
154 eu.entry = e; 160 eu.entry = e;
155 spin_lock_irqsave(&ioapic_lock, flags); 161 spin_lock_irqsave(&ioapic_lock, flags);
162 io_apic_write(apic, 0x11 + 2*pin, eu.w2);
163 io_apic_write(apic, 0x10 + 2*pin, eu.w1);
164 spin_unlock_irqrestore(&ioapic_lock, flags);
165}
166
167/*
168 * When we mask an IO APIC routing entry, we need to write the low
169 * word first, in order to set the mask bit before we change the
170 * high bits!
171 */
172static void ioapic_mask_entry(int apic, int pin)
173{
174 unsigned long flags;
175 union entry_union eu = { .entry.mask = 1 };
176
177 spin_lock_irqsave(&ioapic_lock, flags);
156 io_apic_write(apic, 0x10 + 2*pin, eu.w1); 178 io_apic_write(apic, 0x10 + 2*pin, eu.w1);
157 io_apic_write(apic, 0x11 + 2*pin, eu.w2); 179 io_apic_write(apic, 0x11 + 2*pin, eu.w2);
158 spin_unlock_irqrestore(&ioapic_lock, flags); 180 spin_unlock_irqrestore(&ioapic_lock, flags);
@@ -274,9 +296,7 @@ static void clear_IO_APIC_pin(unsigned int apic, unsigned int pin)
274 /* 296 /*
275 * Disable it in the IO-APIC irq-routing table: 297 * Disable it in the IO-APIC irq-routing table:
276 */ 298 */
277 memset(&entry, 0, sizeof(entry)); 299 ioapic_mask_entry(apic, pin);
278 entry.mask = 1;
279 ioapic_write_entry(apic, pin, entry);
280} 300}
281 301
282static void clear_IO_APIC (void) 302static void clear_IO_APIC (void)