diff options
-rw-r--r-- | arch/i386/kernel/apic.c | 38 | ||||
-rw-r--r-- | arch/i386/kernel/io_apic.c | 33 | ||||
-rw-r--r-- | include/asm-i386/apic.h | 2 | ||||
-rw-r--r-- | include/asm-i386/apicdef.h | 1 |
4 files changed, 71 insertions, 3 deletions
diff --git a/arch/i386/kernel/apic.c b/arch/i386/kernel/apic.c index cf45bed96d08..93df90bbb87e 100644 --- a/arch/i386/kernel/apic.c +++ b/arch/i386/kernel/apic.c | |||
@@ -211,7 +211,7 @@ void __init connect_bsp_APIC(void) | |||
211 | enable_apic_mode(); | 211 | enable_apic_mode(); |
212 | } | 212 | } |
213 | 213 | ||
214 | void disconnect_bsp_APIC(void) | 214 | void disconnect_bsp_APIC(int virt_wire_setup) |
215 | { | 215 | { |
216 | if (pic_mode) { | 216 | if (pic_mode) { |
217 | /* | 217 | /* |
@@ -225,6 +225,42 @@ void disconnect_bsp_APIC(void) | |||
225 | outb(0x70, 0x22); | 225 | outb(0x70, 0x22); |
226 | outb(0x00, 0x23); | 226 | outb(0x00, 0x23); |
227 | } | 227 | } |
228 | else { | ||
229 | /* Go back to Virtual Wire compatibility mode */ | ||
230 | unsigned long value; | ||
231 | |||
232 | /* For the spurious interrupt use vector F, and enable it */ | ||
233 | value = apic_read(APIC_SPIV); | ||
234 | value &= ~APIC_VECTOR_MASK; | ||
235 | value |= APIC_SPIV_APIC_ENABLED; | ||
236 | value |= 0xf; | ||
237 | apic_write_around(APIC_SPIV, value); | ||
238 | |||
239 | if (!virt_wire_setup) { | ||
240 | /* For LVT0 make it edge triggered, active high, external and enabled */ | ||
241 | value = apic_read(APIC_LVT0); | ||
242 | value &= ~(APIC_MODE_MASK | APIC_SEND_PENDING | | ||
243 | APIC_INPUT_POLARITY | APIC_LVT_REMOTE_IRR | | ||
244 | APIC_LVT_LEVEL_TRIGGER | APIC_LVT_MASKED ); | ||
245 | value |= APIC_LVT_REMOTE_IRR | APIC_SEND_PENDING; | ||
246 | value = SET_APIC_DELIVERY_MODE(value, APIC_MODE_EXTINT); | ||
247 | apic_write_around(APIC_LVT0, value); | ||
248 | } | ||
249 | else { | ||
250 | /* Disable LVT0 */ | ||
251 | apic_write_around(APIC_LVT0, APIC_LVT_MASKED); | ||
252 | } | ||
253 | |||
254 | /* For LVT1 make it edge triggered, active high, nmi and enabled */ | ||
255 | value = apic_read(APIC_LVT1); | ||
256 | value &= ~( | ||
257 | APIC_MODE_MASK | APIC_SEND_PENDING | | ||
258 | APIC_INPUT_POLARITY | APIC_LVT_REMOTE_IRR | | ||
259 | APIC_LVT_LEVEL_TRIGGER | APIC_LVT_MASKED); | ||
260 | value |= APIC_LVT_REMOTE_IRR | APIC_SEND_PENDING; | ||
261 | value = SET_APIC_DELIVERY_MODE(value, APIC_MODE_NMI); | ||
262 | apic_write_around(APIC_LVT1, value); | ||
263 | } | ||
228 | } | 264 | } |
229 | 265 | ||
230 | void disable_local_APIC(void) | 266 | void disable_local_APIC(void) |
diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c index 3c2b3bdfc807..fc81c8cddd22 100644 --- a/arch/i386/kernel/io_apic.c +++ b/arch/i386/kernel/io_apic.c | |||
@@ -1636,12 +1636,43 @@ static void __init enable_IO_APIC(void) | |||
1636 | */ | 1636 | */ |
1637 | void disable_IO_APIC(void) | 1637 | void disable_IO_APIC(void) |
1638 | { | 1638 | { |
1639 | int pin; | ||
1639 | /* | 1640 | /* |
1640 | * Clear the IO-APIC before rebooting: | 1641 | * Clear the IO-APIC before rebooting: |
1641 | */ | 1642 | */ |
1642 | clear_IO_APIC(); | 1643 | clear_IO_APIC(); |
1643 | 1644 | ||
1644 | disconnect_bsp_APIC(); | 1645 | /* |
1646 | * If the i82559 is routed through an IOAPIC | ||
1647 | * Put that IOAPIC in virtual wire mode | ||
1648 | * so legacy interrups can be delivered. | ||
1649 | */ | ||
1650 | pin = find_isa_irq_pin(0, mp_ExtINT); | ||
1651 | if (pin != -1) { | ||
1652 | struct IO_APIC_route_entry entry; | ||
1653 | unsigned long flags; | ||
1654 | |||
1655 | memset(&entry, 0, sizeof(entry)); | ||
1656 | entry.mask = 0; /* Enabled */ | ||
1657 | entry.trigger = 0; /* Edge */ | ||
1658 | entry.irr = 0; | ||
1659 | entry.polarity = 0; /* High */ | ||
1660 | entry.delivery_status = 0; | ||
1661 | entry.dest_mode = 0; /* Physical */ | ||
1662 | entry.delivery_mode = 7; /* ExtInt */ | ||
1663 | entry.vector = 0; | ||
1664 | entry.dest.physical.physical_dest = 0; | ||
1665 | |||
1666 | |||
1667 | /* | ||
1668 | * Add it to the IO-APIC irq-routing table: | ||
1669 | */ | ||
1670 | spin_lock_irqsave(&ioapic_lock, flags); | ||
1671 | io_apic_write(0, 0x11+2*pin, *(((int *)&entry)+1)); | ||
1672 | io_apic_write(0, 0x10+2*pin, *(((int *)&entry)+0)); | ||
1673 | spin_unlock_irqrestore(&ioapic_lock, flags); | ||
1674 | } | ||
1675 | disconnect_bsp_APIC(pin != -1); | ||
1645 | } | 1676 | } |
1646 | 1677 | ||
1647 | /* | 1678 | /* |
diff --git a/include/asm-i386/apic.h b/include/asm-i386/apic.h index 53268cd9306e..6a1b1882285c 100644 --- a/include/asm-i386/apic.h +++ b/include/asm-i386/apic.h | |||
@@ -100,7 +100,7 @@ extern void (*wait_timer_tick)(void); | |||
100 | extern int get_maxlvt(void); | 100 | extern int get_maxlvt(void); |
101 | extern void clear_local_APIC(void); | 101 | extern void clear_local_APIC(void); |
102 | extern void connect_bsp_APIC (void); | 102 | extern void connect_bsp_APIC (void); |
103 | extern void disconnect_bsp_APIC (void); | 103 | extern void disconnect_bsp_APIC (int virt_wire_setup); |
104 | extern void disable_local_APIC (void); | 104 | extern void disable_local_APIC (void); |
105 | extern void lapic_shutdown (void); | 105 | extern void lapic_shutdown (void); |
106 | extern int verify_local_APIC (void); | 106 | extern int verify_local_APIC (void); |
diff --git a/include/asm-i386/apicdef.h b/include/asm-i386/apicdef.h index 41e8d2d918e0..0fed5e3c699c 100644 --- a/include/asm-i386/apicdef.h +++ b/include/asm-i386/apicdef.h | |||
@@ -86,6 +86,7 @@ | |||
86 | #define APIC_LVT_REMOTE_IRR (1<<14) | 86 | #define APIC_LVT_REMOTE_IRR (1<<14) |
87 | #define APIC_INPUT_POLARITY (1<<13) | 87 | #define APIC_INPUT_POLARITY (1<<13) |
88 | #define APIC_SEND_PENDING (1<<12) | 88 | #define APIC_SEND_PENDING (1<<12) |
89 | #define APIC_MODE_MASK 0x700 | ||
89 | #define GET_APIC_DELIVERY_MODE(x) (((x)>>8)&0x7) | 90 | #define GET_APIC_DELIVERY_MODE(x) (((x)>>8)&0x7) |
90 | #define SET_APIC_DELIVERY_MODE(x,y) (((x)&~0x700)|((y)<<8)) | 91 | #define SET_APIC_DELIVERY_MODE(x,y) (((x)&~0x700)|((y)<<8)) |
91 | #define APIC_MODE_FIXED 0x0 | 92 | #define APIC_MODE_FIXED 0x0 |