aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86_64/kernel/apic.c38
-rw-r--r--arch/x86_64/kernel/io_apic.c36
-rw-r--r--include/asm-x86_64/apic.h2
3 files changed, 72 insertions, 4 deletions
diff --git a/arch/x86_64/kernel/apic.c b/arch/x86_64/kernel/apic.c
index 2a6c893ccf60..375d369570ca 100644
--- a/arch/x86_64/kernel/apic.c
+++ b/arch/x86_64/kernel/apic.c
@@ -133,7 +133,7 @@ void __init connect_bsp_APIC(void)
133 } 133 }
134} 134}
135 135
136void disconnect_bsp_APIC(void) 136void disconnect_bsp_APIC(int virt_wire_setup)
137{ 137{
138 if (pic_mode) { 138 if (pic_mode) {
139 /* 139 /*
@@ -146,6 +146,42 @@ void disconnect_bsp_APIC(void)
146 outb(0x70, 0x22); 146 outb(0x70, 0x22);
147 outb(0x00, 0x23); 147 outb(0x00, 0x23);
148 } 148 }
149 else {
150 /* Go back to Virtual Wire compatibility mode */
151 unsigned long value;
152
153 /* For the spurious interrupt use vector F, and enable it */
154 value = apic_read(APIC_SPIV);
155 value &= ~APIC_VECTOR_MASK;
156 value |= APIC_SPIV_APIC_ENABLED;
157 value |= 0xf;
158 apic_write_around(APIC_SPIV, value);
159
160 if (!virt_wire_setup) {
161 /* For LVT0 make it edge triggered, active high, external and enabled */
162 value = apic_read(APIC_LVT0);
163 value &= ~(APIC_MODE_MASK | APIC_SEND_PENDING |
164 APIC_INPUT_POLARITY | APIC_LVT_REMOTE_IRR |
165 APIC_LVT_LEVEL_TRIGGER | APIC_LVT_MASKED );
166 value |= APIC_LVT_REMOTE_IRR | APIC_SEND_PENDING;
167 value = SET_APIC_DELIVERY_MODE(value, APIC_MODE_EXTINT);
168 apic_write_around(APIC_LVT0, value);
169 }
170 else {
171 /* Disable LVT0 */
172 apic_write_around(APIC_LVT0, APIC_LVT_MASKED);
173 }
174
175 /* For LVT1 make it edge triggered, active high, nmi and enabled */
176 value = apic_read(APIC_LVT1);
177 value &= ~(
178 APIC_MODE_MASK | APIC_SEND_PENDING |
179 APIC_INPUT_POLARITY | APIC_LVT_REMOTE_IRR |
180 APIC_LVT_LEVEL_TRIGGER | APIC_LVT_MASKED);
181 value |= APIC_LVT_REMOTE_IRR | APIC_SEND_PENDING;
182 value = SET_APIC_DELIVERY_MODE(value, APIC_MODE_NMI);
183 apic_write_around(APIC_LVT1, value);
184 }
149} 185}
150 186
151void disable_local_APIC(void) 187void disable_local_APIC(void)
diff --git a/arch/x86_64/kernel/io_apic.c b/arch/x86_64/kernel/io_apic.c
index afd87e64d0a8..157190d986bb 100644
--- a/arch/x86_64/kernel/io_apic.c
+++ b/arch/x86_64/kernel/io_apic.c
@@ -330,7 +330,7 @@ static int find_irq_entry(int apic, int pin, int type)
330/* 330/*
331 * Find the pin to which IRQ[irq] (ISA) is connected 331 * Find the pin to which IRQ[irq] (ISA) is connected
332 */ 332 */
333static int __init find_isa_irq_pin(int irq, int type) 333static int find_isa_irq_pin(int irq, int type)
334{ 334{
335 int i; 335 int i;
336 336
@@ -1132,12 +1132,44 @@ static void __init enable_IO_APIC(void)
1132 */ 1132 */
1133void disable_IO_APIC(void) 1133void disable_IO_APIC(void)
1134{ 1134{
1135 int pin;
1135 /* 1136 /*
1136 * Clear the IO-APIC before rebooting: 1137 * Clear the IO-APIC before rebooting:
1137 */ 1138 */
1138 clear_IO_APIC(); 1139 clear_IO_APIC();
1139 1140
1140 disconnect_bsp_APIC(); 1141 /*
1142 * If the i82559 is routed through an IOAPIC
1143 * Put that IOAPIC in virtual wire mode
1144 * so legacy interrups can be delivered.
1145 */
1146 pin = find_isa_irq_pin(0, mp_ExtINT);
1147 if (pin != -1) {
1148 struct IO_APIC_route_entry entry;
1149 unsigned long flags;
1150
1151 memset(&entry, 0, sizeof(entry));
1152 entry.mask = 0; /* Enabled */
1153 entry.trigger = 0; /* Edge */
1154 entry.irr = 0;
1155 entry.polarity = 0; /* High */
1156 entry.delivery_status = 0;
1157 entry.dest_mode = 0; /* Physical */
1158 entry.delivery_mode = 7; /* ExtInt */
1159 entry.vector = 0;
1160 entry.dest.physical.physical_dest = 0;
1161
1162
1163 /*
1164 * Add it to the IO-APIC irq-routing table:
1165 */
1166 spin_lock_irqsave(&ioapic_lock, flags);
1167 io_apic_write(0, 0x11+2*pin, *(((int *)&entry)+1));
1168 io_apic_write(0, 0x10+2*pin, *(((int *)&entry)+0));
1169 spin_unlock_irqrestore(&ioapic_lock, flags);
1170 }
1171
1172 disconnect_bsp_APIC(pin != -1);
1141} 1173}
1142 1174
1143/* 1175/*
diff --git a/include/asm-x86_64/apic.h b/include/asm-x86_64/apic.h
index e4b1017b8b2b..16ec82e16b21 100644
--- a/include/asm-x86_64/apic.h
+++ b/include/asm-x86_64/apic.h
@@ -77,7 +77,7 @@ static inline void ack_APIC_irq(void)
77extern int get_maxlvt (void); 77extern int get_maxlvt (void);
78extern void clear_local_APIC (void); 78extern void clear_local_APIC (void);
79extern void connect_bsp_APIC (void); 79extern void connect_bsp_APIC (void);
80extern void disconnect_bsp_APIC (void); 80extern void disconnect_bsp_APIC (int virt_wire_setup);
81extern void disable_local_APIC (void); 81extern void disable_local_APIC (void);
82extern int verify_local_APIC (void); 82extern int verify_local_APIC (void);
83extern void cache_APIC_registers (void); 83extern void cache_APIC_registers (void);