diff options
-rw-r--r-- | arch/x86_64/kernel/apic.c | 38 | ||||
-rw-r--r-- | arch/x86_64/kernel/io_apic.c | 36 | ||||
-rw-r--r-- | include/asm-x86_64/apic.h | 2 |
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 | ||
136 | void disconnect_bsp_APIC(void) | 136 | void 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 | ||
151 | void disable_local_APIC(void) | 187 | void 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 | */ |
333 | static int __init find_isa_irq_pin(int irq, int type) | 333 | static 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 | */ |
1133 | void disable_IO_APIC(void) | 1133 | void 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) | |||
77 | extern int get_maxlvt (void); | 77 | extern int get_maxlvt (void); |
78 | extern void clear_local_APIC (void); | 78 | extern void clear_local_APIC (void); |
79 | extern void connect_bsp_APIC (void); | 79 | extern void connect_bsp_APIC (void); |
80 | extern void disconnect_bsp_APIC (void); | 80 | extern void disconnect_bsp_APIC (int virt_wire_setup); |
81 | extern void disable_local_APIC (void); | 81 | extern void disable_local_APIC (void); |
82 | extern int verify_local_APIC (void); | 82 | extern int verify_local_APIC (void); |
83 | extern void cache_APIC_registers (void); | 83 | extern void cache_APIC_registers (void); |