diff options
Diffstat (limited to 'arch/x86/kernel/io_apic.c')
-rw-r--r-- | arch/x86/kernel/io_apic.c | 142 |
1 files changed, 141 insertions, 1 deletions
diff --git a/arch/x86/kernel/io_apic.c b/arch/x86/kernel/io_apic.c index 60bb8b19f4cd..6bd51ce3ce32 100644 --- a/arch/x86/kernel/io_apic.c +++ b/arch/x86/kernel/io_apic.c | |||
@@ -141,6 +141,9 @@ struct irq_cfg { | |||
141 | unsigned move_cleanup_count; | 141 | unsigned move_cleanup_count; |
142 | u8 vector; | 142 | u8 vector; |
143 | u8 move_in_progress : 1; | 143 | u8 move_in_progress : 1; |
144 | #ifdef CONFIG_NUMA_MIGRATE_IRQ_DESC | ||
145 | u8 move_desc_pending : 1; | ||
146 | #endif | ||
144 | }; | 147 | }; |
145 | 148 | ||
146 | /* irq_cfg is indexed by the sum of all RTEs in all I/O APICs. */ | 149 | /* irq_cfg is indexed by the sum of all RTEs in all I/O APICs. */ |
@@ -241,6 +244,121 @@ void arch_init_chip_data(struct irq_desc *desc, int cpu) | |||
241 | } | 244 | } |
242 | } | 245 | } |
243 | 246 | ||
247 | #ifdef CONFIG_NUMA_MIGRATE_IRQ_DESC | ||
248 | |||
249 | static void | ||
250 | init_copy_irq_2_pin(struct irq_cfg *old_cfg, struct irq_cfg *cfg, int cpu) | ||
251 | { | ||
252 | struct irq_pin_list *old_entry, *head, *tail, *entry; | ||
253 | |||
254 | cfg->irq_2_pin = NULL; | ||
255 | old_entry = old_cfg->irq_2_pin; | ||
256 | if (!old_entry) | ||
257 | return; | ||
258 | |||
259 | entry = get_one_free_irq_2_pin(cpu); | ||
260 | if (!entry) | ||
261 | return; | ||
262 | |||
263 | entry->apic = old_entry->apic; | ||
264 | entry->pin = old_entry->pin; | ||
265 | head = entry; | ||
266 | tail = entry; | ||
267 | old_entry = old_entry->next; | ||
268 | while (old_entry) { | ||
269 | entry = get_one_free_irq_2_pin(cpu); | ||
270 | if (!entry) { | ||
271 | entry = head; | ||
272 | while (entry) { | ||
273 | head = entry->next; | ||
274 | kfree(entry); | ||
275 | entry = head; | ||
276 | } | ||
277 | /* still use the old one */ | ||
278 | return; | ||
279 | } | ||
280 | entry->apic = old_entry->apic; | ||
281 | entry->pin = old_entry->pin; | ||
282 | tail->next = entry; | ||
283 | tail = entry; | ||
284 | old_entry = old_entry->next; | ||
285 | } | ||
286 | |||
287 | tail->next = NULL; | ||
288 | cfg->irq_2_pin = head; | ||
289 | } | ||
290 | |||
291 | static void free_irq_2_pin(struct irq_cfg *old_cfg, struct irq_cfg *cfg) | ||
292 | { | ||
293 | struct irq_pin_list *entry, *next; | ||
294 | |||
295 | if (old_cfg->irq_2_pin == cfg->irq_2_pin) | ||
296 | return; | ||
297 | |||
298 | entry = old_cfg->irq_2_pin; | ||
299 | |||
300 | while (entry) { | ||
301 | next = entry->next; | ||
302 | kfree(entry); | ||
303 | entry = next; | ||
304 | } | ||
305 | old_cfg->irq_2_pin = NULL; | ||
306 | } | ||
307 | |||
308 | void arch_init_copy_chip_data(struct irq_desc *old_desc, | ||
309 | struct irq_desc *desc, int cpu) | ||
310 | { | ||
311 | struct irq_cfg *cfg; | ||
312 | struct irq_cfg *old_cfg; | ||
313 | |||
314 | cfg = get_one_free_irq_cfg(cpu); | ||
315 | |||
316 | if (!cfg) | ||
317 | return; | ||
318 | |||
319 | desc->chip_data = cfg; | ||
320 | |||
321 | old_cfg = old_desc->chip_data; | ||
322 | |||
323 | memcpy(cfg, old_cfg, sizeof(struct irq_cfg)); | ||
324 | |||
325 | init_copy_irq_2_pin(old_cfg, cfg, cpu); | ||
326 | } | ||
327 | |||
328 | static void free_irq_cfg(struct irq_cfg *old_cfg) | ||
329 | { | ||
330 | kfree(old_cfg); | ||
331 | } | ||
332 | |||
333 | void arch_free_chip_data(struct irq_desc *old_desc, struct irq_desc *desc) | ||
334 | { | ||
335 | struct irq_cfg *old_cfg, *cfg; | ||
336 | |||
337 | old_cfg = old_desc->chip_data; | ||
338 | cfg = desc->chip_data; | ||
339 | |||
340 | if (old_cfg == cfg) | ||
341 | return; | ||
342 | |||
343 | if (old_cfg) { | ||
344 | free_irq_2_pin(old_cfg, cfg); | ||
345 | free_irq_cfg(old_cfg); | ||
346 | old_desc->chip_data = NULL; | ||
347 | } | ||
348 | } | ||
349 | |||
350 | static void set_extra_move_desc(struct irq_desc *desc, cpumask_t mask) | ||
351 | { | ||
352 | struct irq_cfg *cfg = desc->chip_data; | ||
353 | |||
354 | if (!cfg->move_in_progress) { | ||
355 | /* it means that domain is not changed */ | ||
356 | if (!cpus_intersects(desc->affinity, mask)) | ||
357 | cfg->move_desc_pending = 1; | ||
358 | } | ||
359 | } | ||
360 | #endif | ||
361 | |||
244 | #else | 362 | #else |
245 | static struct irq_cfg *irq_cfg(unsigned int irq) | 363 | static struct irq_cfg *irq_cfg(unsigned int irq) |
246 | { | 364 | { |
@@ -249,10 +367,12 @@ static struct irq_cfg *irq_cfg(unsigned int irq) | |||
249 | 367 | ||
250 | #endif | 368 | #endif |
251 | 369 | ||
370 | #ifndef CONFIG_NUMA_MIGRATE_IRQ_DESC | ||
252 | static inline void | 371 | static inline void |
253 | set_extra_move_desc(struct irq_desc *desc, const struct cpumask *mask) | 372 | set_extra_move_desc(struct irq_desc *desc, const struct cpumask *mask) |
254 | { | 373 | { |
255 | } | 374 | } |
375 | #endif | ||
256 | 376 | ||
257 | struct io_apic { | 377 | struct io_apic { |
258 | unsigned int index; | 378 | unsigned int index; |
@@ -2397,11 +2517,31 @@ static void irq_complete_move(struct irq_desc **descp) | |||
2397 | struct irq_cfg *cfg = desc->chip_data; | 2517 | struct irq_cfg *cfg = desc->chip_data; |
2398 | unsigned vector, me; | 2518 | unsigned vector, me; |
2399 | 2519 | ||
2400 | if (likely(!cfg->move_in_progress)) | 2520 | if (likely(!cfg->move_in_progress)) { |
2521 | #ifdef CONFIG_NUMA_MIGRATE_IRQ_DESC | ||
2522 | if (likely(!cfg->move_desc_pending)) | ||
2523 | return; | ||
2524 | |||
2525 | /* domain is not change, but affinity is changed */ | ||
2526 | me = smp_processor_id(); | ||
2527 | if (cpu_isset(me, desc->affinity)) { | ||
2528 | *descp = desc = move_irq_desc(desc, me); | ||
2529 | /* get the new one */ | ||
2530 | cfg = desc->chip_data; | ||
2531 | cfg->move_desc_pending = 0; | ||
2532 | } | ||
2533 | #endif | ||
2401 | return; | 2534 | return; |
2535 | } | ||
2402 | 2536 | ||
2403 | vector = ~get_irq_regs()->orig_ax; | 2537 | vector = ~get_irq_regs()->orig_ax; |
2404 | me = smp_processor_id(); | 2538 | me = smp_processor_id(); |
2539 | #ifdef CONFIG_NUMA_MIGRATE_IRQ_DESC | ||
2540 | *descp = desc = move_irq_desc(desc, me); | ||
2541 | /* get the new one */ | ||
2542 | cfg = desc->chip_data; | ||
2543 | #endif | ||
2544 | |||
2405 | if (vector == cfg->vector && cpumask_test_cpu(me, cfg->domain)) | 2545 | if (vector == cfg->vector && cpumask_test_cpu(me, cfg->domain)) |
2406 | send_cleanup_vector(cfg); | 2546 | send_cleanup_vector(cfg); |
2407 | } | 2547 | } |