diff options
author | Linus Torvalds <torvalds@macmini.osdl.org> | 2006-11-01 13:05:35 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@macmini.osdl.org> | 2006-11-01 13:06:52 -0500 |
commit | f9dadfa71bc594df09044da61d1c72701121d802 (patch) | |
tree | ffbd7d1b53b5393f078476e3dbe78284d7d847d4 /arch/i386/kernel/io_apic.c | |
parent | 130fe05dbc0114609cfef9815c0c5580b42decfa (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/io_apic.c')
-rw-r--r-- | arch/i386/kernel/io_apic.c | 26 |
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 | */ | ||
150 | static void ioapic_write_entry(int apic, int pin, struct IO_APIC_route_entry e) | 156 | static 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 | */ | ||
172 | static 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 | ||
282 | static void clear_IO_APIC (void) | 302 | static void clear_IO_APIC (void) |