diff options
-rw-r--r-- | arch/x86/Kconfig | 11 | ||||
-rw-r--r-- | arch/x86/kernel/io_apic.c | 142 | ||||
-rw-r--r-- | drivers/pci/intr_remapping.c | 1 | ||||
-rw-r--r-- | fs/proc/stat.c | 7 | ||||
-rw-r--r-- | include/linux/irq.h | 10 | ||||
-rw-r--r-- | kernel/irq/Makefile | 1 | ||||
-rw-r--r-- | kernel/irq/chip.c | 12 | ||||
-rw-r--r-- | kernel/irq/handle.c | 15 | ||||
-rw-r--r-- | kernel/irq/internals.h | 5 | ||||
-rw-r--r-- | kernel/irq/numa_migrate.c | 127 |
10 files changed, 317 insertions, 14 deletions
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 4a3f5851ec64..0ca2eb7573cd 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig | |||
@@ -243,7 +243,7 @@ config X86_HAS_BOOT_CPU_ID | |||
243 | 243 | ||
244 | config SPARSE_IRQ | 244 | config SPARSE_IRQ |
245 | bool "Support sparse irq numbering" | 245 | bool "Support sparse irq numbering" |
246 | depends on (PCI_MSI || HT_IRQ) && SMP | 246 | depends on PCI_MSI || HT_IRQ |
247 | default y | 247 | default y |
248 | help | 248 | help |
249 | This enables support for sparse irq, esp for msi/msi-x. You may need | 249 | This enables support for sparse irq, esp for msi/msi-x. You may need |
@@ -251,6 +251,15 @@ config SPARSE_IRQ | |||
251 | 251 | ||
252 | If you don't know what to do here, say Y. | 252 | If you don't know what to do here, say Y. |
253 | 253 | ||
254 | config NUMA_MIGRATE_IRQ_DESC | ||
255 | bool "Move irq desc when changing irq smp_affinity" | ||
256 | depends on SPARSE_IRQ && SMP | ||
257 | default n | ||
258 | help | ||
259 | This enables moving irq_desc to cpu/node that irq will use handled. | ||
260 | |||
261 | If you don't know what to do here, say N. | ||
262 | |||
254 | config X86_FIND_SMP_CONFIG | 263 | config X86_FIND_SMP_CONFIG |
255 | def_bool y | 264 | def_bool y |
256 | depends on X86_MPPARSE || X86_VOYAGER | 265 | depends on X86_MPPARSE || X86_VOYAGER |
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 | } |
diff --git a/drivers/pci/intr_remapping.c b/drivers/pci/intr_remapping.c index c9958ec5e25e..f78371b22529 100644 --- a/drivers/pci/intr_remapping.c +++ b/drivers/pci/intr_remapping.c | |||
@@ -5,6 +5,7 @@ | |||
5 | #include <linux/pci.h> | 5 | #include <linux/pci.h> |
6 | #include <linux/irq.h> | 6 | #include <linux/irq.h> |
7 | #include <asm/io_apic.h> | 7 | #include <asm/io_apic.h> |
8 | #include <asm/smp.h> | ||
8 | #include <linux/intel-iommu.h> | 9 | #include <linux/intel-iommu.h> |
9 | #include "intr_remapping.h" | 10 | #include "intr_remapping.h" |
10 | 11 | ||
diff --git a/fs/proc/stat.c b/fs/proc/stat.c index 3cb9492801c0..3bb1cf1e7425 100644 --- a/fs/proc/stat.c +++ b/fs/proc/stat.c | |||
@@ -27,7 +27,6 @@ static int show_stat(struct seq_file *p, void *v) | |||
27 | u64 sum = 0; | 27 | u64 sum = 0; |
28 | struct timespec boottime; | 28 | struct timespec boottime; |
29 | unsigned int per_irq_sum; | 29 | unsigned int per_irq_sum; |
30 | struct irq_desc *desc; | ||
31 | 30 | ||
32 | user = nice = system = idle = iowait = | 31 | user = nice = system = idle = iowait = |
33 | irq = softirq = steal = cputime64_zero; | 32 | irq = softirq = steal = cputime64_zero; |
@@ -47,8 +46,7 @@ static int show_stat(struct seq_file *p, void *v) | |||
47 | guest = cputime64_add(guest, kstat_cpu(i).cpustat.guest); | 46 | guest = cputime64_add(guest, kstat_cpu(i).cpustat.guest); |
48 | for_each_irq_nr(j) { | 47 | for_each_irq_nr(j) { |
49 | #ifdef CONFIG_SPARSE_IRQ | 48 | #ifdef CONFIG_SPARSE_IRQ |
50 | desc = irq_to_desc(j); | 49 | if (!irq_to_desc(j)) |
51 | if (!desc) | ||
52 | continue; | 50 | continue; |
53 | #endif | 51 | #endif |
54 | sum += kstat_irqs_cpu(j, i); | 52 | sum += kstat_irqs_cpu(j, i); |
@@ -98,8 +96,7 @@ static int show_stat(struct seq_file *p, void *v) | |||
98 | for_each_irq_nr(j) { | 96 | for_each_irq_nr(j) { |
99 | per_irq_sum = 0; | 97 | per_irq_sum = 0; |
100 | #ifdef CONFIG_SPARSE_IRQ | 98 | #ifdef CONFIG_SPARSE_IRQ |
101 | desc = irq_to_desc(j); | 99 | if (!irq_to_desc(j)) { |
102 | if (!desc) { | ||
103 | seq_printf(p, " %u", per_irq_sum); | 100 | seq_printf(p, " %u", per_irq_sum); |
104 | continue; | 101 | continue; |
105 | } | 102 | } |
diff --git a/include/linux/irq.h b/include/linux/irq.h index 59525b74979f..fde5e6132018 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h | |||
@@ -228,6 +228,16 @@ extern struct irq_desc *move_irq_desc(struct irq_desc *old_desc, int cpu); | |||
228 | 228 | ||
229 | #endif | 229 | #endif |
230 | 230 | ||
231 | static inline struct irq_desc * | ||
232 | irq_remap_to_desc(unsigned int irq, struct irq_desc *desc) | ||
233 | { | ||
234 | #ifdef CONFIG_NUMA_MIGRATE_IRQ_DESC | ||
235 | return irq_to_desc(irq); | ||
236 | #else | ||
237 | return desc; | ||
238 | #endif | ||
239 | } | ||
240 | |||
231 | /* | 241 | /* |
232 | * Migration helpers for obsolete names, they will go away: | 242 | * Migration helpers for obsolete names, they will go away: |
233 | */ | 243 | */ |
diff --git a/kernel/irq/Makefile b/kernel/irq/Makefile index 681c52dbfe22..4dd5b1edac98 100644 --- a/kernel/irq/Makefile +++ b/kernel/irq/Makefile | |||
@@ -3,3 +3,4 @@ obj-y := handle.o manage.o spurious.o resend.o chip.o devres.o | |||
3 | obj-$(CONFIG_GENERIC_IRQ_PROBE) += autoprobe.o | 3 | obj-$(CONFIG_GENERIC_IRQ_PROBE) += autoprobe.o |
4 | obj-$(CONFIG_PROC_FS) += proc.o | 4 | obj-$(CONFIG_PROC_FS) += proc.o |
5 | obj-$(CONFIG_GENERIC_PENDING_IRQ) += migration.o | 5 | obj-$(CONFIG_GENERIC_PENDING_IRQ) += migration.o |
6 | obj-$(CONFIG_NUMA_MIGRATE_IRQ_DESC) += numa_migrate.o | ||
diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index 0af16aeee8b6..b343deedae91 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c | |||
@@ -353,6 +353,7 @@ handle_level_irq(unsigned int irq, struct irq_desc *desc) | |||
353 | 353 | ||
354 | spin_lock(&desc->lock); | 354 | spin_lock(&desc->lock); |
355 | mask_ack_irq(desc, irq); | 355 | mask_ack_irq(desc, irq); |
356 | desc = irq_remap_to_desc(irq, desc); | ||
356 | 357 | ||
357 | if (unlikely(desc->status & IRQ_INPROGRESS)) | 358 | if (unlikely(desc->status & IRQ_INPROGRESS)) |
358 | goto out_unlock; | 359 | goto out_unlock; |
@@ -430,6 +431,7 @@ handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc) | |||
430 | desc->status &= ~IRQ_INPROGRESS; | 431 | desc->status &= ~IRQ_INPROGRESS; |
431 | out: | 432 | out: |
432 | desc->chip->eoi(irq); | 433 | desc->chip->eoi(irq); |
434 | desc = irq_remap_to_desc(irq, desc); | ||
433 | 435 | ||
434 | spin_unlock(&desc->lock); | 436 | spin_unlock(&desc->lock); |
435 | } | 437 | } |
@@ -466,12 +468,14 @@ handle_edge_irq(unsigned int irq, struct irq_desc *desc) | |||
466 | !desc->action)) { | 468 | !desc->action)) { |
467 | desc->status |= (IRQ_PENDING | IRQ_MASKED); | 469 | desc->status |= (IRQ_PENDING | IRQ_MASKED); |
468 | mask_ack_irq(desc, irq); | 470 | mask_ack_irq(desc, irq); |
471 | desc = irq_remap_to_desc(irq, desc); | ||
469 | goto out_unlock; | 472 | goto out_unlock; |
470 | } | 473 | } |
471 | kstat_incr_irqs_this_cpu(irq, desc); | 474 | kstat_incr_irqs_this_cpu(irq, desc); |
472 | 475 | ||
473 | /* Start handling the irq */ | 476 | /* Start handling the irq */ |
474 | desc->chip->ack(irq); | 477 | desc->chip->ack(irq); |
478 | desc = irq_remap_to_desc(irq, desc); | ||
475 | 479 | ||
476 | /* Mark the IRQ currently in progress.*/ | 480 | /* Mark the IRQ currently in progress.*/ |
477 | desc->status |= IRQ_INPROGRESS; | 481 | desc->status |= IRQ_INPROGRESS; |
@@ -532,8 +536,10 @@ handle_percpu_irq(unsigned int irq, struct irq_desc *desc) | |||
532 | if (!noirqdebug) | 536 | if (!noirqdebug) |
533 | note_interrupt(irq, desc, action_ret); | 537 | note_interrupt(irq, desc, action_ret); |
534 | 538 | ||
535 | if (desc->chip->eoi) | 539 | if (desc->chip->eoi) { |
536 | desc->chip->eoi(irq); | 540 | desc->chip->eoi(irq); |
541 | desc = irq_remap_to_desc(irq, desc); | ||
542 | } | ||
537 | } | 543 | } |
538 | 544 | ||
539 | void | 545 | void |
@@ -568,8 +574,10 @@ __set_irq_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained, | |||
568 | 574 | ||
569 | /* Uninstall? */ | 575 | /* Uninstall? */ |
570 | if (handle == handle_bad_irq) { | 576 | if (handle == handle_bad_irq) { |
571 | if (desc->chip != &no_irq_chip) | 577 | if (desc->chip != &no_irq_chip) { |
572 | mask_ack_irq(desc, irq); | 578 | mask_ack_irq(desc, irq); |
579 | desc = irq_remap_to_desc(irq, desc); | ||
580 | } | ||
573 | desc->status |= IRQ_DISABLED; | 581 | desc->status |= IRQ_DISABLED; |
574 | desc->depth = 1; | 582 | desc->depth = 1; |
575 | } | 583 | } |
diff --git a/kernel/irq/handle.c b/kernel/irq/handle.c index 8aa09547f5ef..f1a23069c20a 100644 --- a/kernel/irq/handle.c +++ b/kernel/irq/handle.c | |||
@@ -23,7 +23,7 @@ | |||
23 | /* | 23 | /* |
24 | * lockdep: we want to handle all irq_desc locks as a single lock-class: | 24 | * lockdep: we want to handle all irq_desc locks as a single lock-class: |
25 | */ | 25 | */ |
26 | static struct lock_class_key irq_desc_lock_class; | 26 | struct lock_class_key irq_desc_lock_class; |
27 | 27 | ||
28 | /** | 28 | /** |
29 | * handle_bad_irq - handle spurious and unhandled irqs | 29 | * handle_bad_irq - handle spurious and unhandled irqs |
@@ -73,7 +73,7 @@ static struct irq_desc irq_desc_init = { | |||
73 | #endif | 73 | #endif |
74 | }; | 74 | }; |
75 | 75 | ||
76 | static void init_kstat_irqs(struct irq_desc *desc, int cpu, int nr) | 76 | void init_kstat_irqs(struct irq_desc *desc, int cpu, int nr) |
77 | { | 77 | { |
78 | unsigned long bytes; | 78 | unsigned long bytes; |
79 | char *ptr; | 79 | char *ptr; |
@@ -113,7 +113,7 @@ static void init_one_irq_desc(int irq, struct irq_desc *desc, int cpu) | |||
113 | /* | 113 | /* |
114 | * Protect the sparse_irqs: | 114 | * Protect the sparse_irqs: |
115 | */ | 115 | */ |
116 | static DEFINE_SPINLOCK(sparse_irq_lock); | 116 | DEFINE_SPINLOCK(sparse_irq_lock); |
117 | 117 | ||
118 | struct irq_desc *irq_desc_ptrs[NR_IRQS] __read_mostly; | 118 | struct irq_desc *irq_desc_ptrs[NR_IRQS] __read_mostly; |
119 | 119 | ||
@@ -337,8 +337,11 @@ unsigned int __do_IRQ(unsigned int irq) | |||
337 | /* | 337 | /* |
338 | * No locking required for CPU-local interrupts: | 338 | * No locking required for CPU-local interrupts: |
339 | */ | 339 | */ |
340 | if (desc->chip->ack) | 340 | if (desc->chip->ack) { |
341 | desc->chip->ack(irq); | 341 | desc->chip->ack(irq); |
342 | /* get new one */ | ||
343 | desc = irq_remap_to_desc(irq, desc); | ||
344 | } | ||
342 | if (likely(!(desc->status & IRQ_DISABLED))) { | 345 | if (likely(!(desc->status & IRQ_DISABLED))) { |
343 | action_ret = handle_IRQ_event(irq, desc->action); | 346 | action_ret = handle_IRQ_event(irq, desc->action); |
344 | if (!noirqdebug) | 347 | if (!noirqdebug) |
@@ -349,8 +352,10 @@ unsigned int __do_IRQ(unsigned int irq) | |||
349 | } | 352 | } |
350 | 353 | ||
351 | spin_lock(&desc->lock); | 354 | spin_lock(&desc->lock); |
352 | if (desc->chip->ack) | 355 | if (desc->chip->ack) { |
353 | desc->chip->ack(irq); | 356 | desc->chip->ack(irq); |
357 | desc = irq_remap_to_desc(irq, desc); | ||
358 | } | ||
354 | /* | 359 | /* |
355 | * REPLAY is when Linux resends an IRQ that was dropped earlier | 360 | * REPLAY is when Linux resends an IRQ that was dropped earlier |
356 | * WAITING is used by probe to mark irqs that are being tested | 361 | * WAITING is used by probe to mark irqs that are being tested |
diff --git a/kernel/irq/internals.h b/kernel/irq/internals.h index 64c1c7253dae..e6d0a43cc125 100644 --- a/kernel/irq/internals.h +++ b/kernel/irq/internals.h | |||
@@ -13,6 +13,11 @@ extern void compat_irq_chip_set_default_handler(struct irq_desc *desc); | |||
13 | extern int __irq_set_trigger(struct irq_desc *desc, unsigned int irq, | 13 | extern int __irq_set_trigger(struct irq_desc *desc, unsigned int irq, |
14 | unsigned long flags); | 14 | unsigned long flags); |
15 | 15 | ||
16 | extern struct lock_class_key irq_desc_lock_class; | ||
17 | extern void init_kstat_irqs(struct irq_desc *desc, int cpu, int nr); | ||
18 | extern spinlock_t sparse_irq_lock; | ||
19 | extern struct irq_desc *irq_desc_ptrs[NR_IRQS]; | ||
20 | |||
16 | #ifdef CONFIG_PROC_FS | 21 | #ifdef CONFIG_PROC_FS |
17 | extern void register_irq_proc(unsigned int irq, struct irq_desc *desc); | 22 | extern void register_irq_proc(unsigned int irq, struct irq_desc *desc); |
18 | extern void register_handler_proc(unsigned int irq, struct irqaction *action); | 23 | extern void register_handler_proc(unsigned int irq, struct irqaction *action); |
diff --git a/kernel/irq/numa_migrate.c b/kernel/irq/numa_migrate.c new file mode 100644 index 000000000000..0178e2296990 --- /dev/null +++ b/kernel/irq/numa_migrate.c | |||
@@ -0,0 +1,127 @@ | |||
1 | /* | ||
2 | * linux/kernel/irq/handle.c | ||
3 | * | ||
4 | * Copyright (C) 1992, 1998-2006 Linus Torvalds, Ingo Molnar | ||
5 | * Copyright (C) 2005-2006, Thomas Gleixner, Russell King | ||
6 | * | ||
7 | * This file contains the core interrupt handling code. | ||
8 | * | ||
9 | * Detailed information is available in Documentation/DocBook/genericirq | ||
10 | * | ||
11 | */ | ||
12 | |||
13 | #include <linux/irq.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/random.h> | ||
16 | #include <linux/interrupt.h> | ||
17 | #include <linux/kernel_stat.h> | ||
18 | |||
19 | #include "internals.h" | ||
20 | |||
21 | static void init_copy_kstat_irqs(struct irq_desc *old_desc, | ||
22 | struct irq_desc *desc, | ||
23 | int cpu, int nr) | ||
24 | { | ||
25 | unsigned long bytes; | ||
26 | |||
27 | init_kstat_irqs(desc, cpu, nr); | ||
28 | |||
29 | if (desc->kstat_irqs != old_desc->kstat_irqs) { | ||
30 | /* Compute how many bytes we need per irq and allocate them */ | ||
31 | bytes = nr * sizeof(unsigned int); | ||
32 | |||
33 | memcpy(desc->kstat_irqs, old_desc->kstat_irqs, bytes); | ||
34 | } | ||
35 | } | ||
36 | |||
37 | static void free_kstat_irqs(struct irq_desc *old_desc, struct irq_desc *desc) | ||
38 | { | ||
39 | if (old_desc->kstat_irqs == desc->kstat_irqs) | ||
40 | return; | ||
41 | |||
42 | kfree(old_desc->kstat_irqs); | ||
43 | old_desc->kstat_irqs = NULL; | ||
44 | } | ||
45 | |||
46 | static void init_copy_one_irq_desc(int irq, struct irq_desc *old_desc, | ||
47 | struct irq_desc *desc, int cpu) | ||
48 | { | ||
49 | memcpy(desc, old_desc, sizeof(struct irq_desc)); | ||
50 | desc->cpu = cpu; | ||
51 | lockdep_set_class(&desc->lock, &irq_desc_lock_class); | ||
52 | init_copy_kstat_irqs(old_desc, desc, cpu, nr_cpu_ids); | ||
53 | arch_init_copy_chip_data(old_desc, desc, cpu); | ||
54 | } | ||
55 | |||
56 | static void free_one_irq_desc(struct irq_desc *old_desc, struct irq_desc *desc) | ||
57 | { | ||
58 | free_kstat_irqs(old_desc, desc); | ||
59 | arch_free_chip_data(old_desc, desc); | ||
60 | } | ||
61 | |||
62 | static struct irq_desc *__real_move_irq_desc(struct irq_desc *old_desc, | ||
63 | int cpu) | ||
64 | { | ||
65 | struct irq_desc *desc; | ||
66 | unsigned int irq; | ||
67 | unsigned long flags; | ||
68 | int node; | ||
69 | |||
70 | irq = old_desc->irq; | ||
71 | |||
72 | spin_lock_irqsave(&sparse_irq_lock, flags); | ||
73 | |||
74 | /* We have to check it to avoid races with another CPU */ | ||
75 | desc = irq_desc_ptrs[irq]; | ||
76 | |||
77 | if (desc && old_desc != desc) | ||
78 | goto out_unlock; | ||
79 | |||
80 | node = cpu_to_node(cpu); | ||
81 | desc = kzalloc_node(sizeof(*desc), GFP_ATOMIC, node); | ||
82 | printk(KERN_DEBUG " move irq_desc for %d to cpu %d node %d\n", | ||
83 | irq, cpu, node); | ||
84 | if (!desc) { | ||
85 | printk(KERN_ERR "can not get new irq_desc for moving\n"); | ||
86 | /* still use old one */ | ||
87 | desc = old_desc; | ||
88 | goto out_unlock; | ||
89 | } | ||
90 | init_copy_one_irq_desc(irq, old_desc, desc, cpu); | ||
91 | |||
92 | irq_desc_ptrs[irq] = desc; | ||
93 | |||
94 | /* free the old one */ | ||
95 | free_one_irq_desc(old_desc, desc); | ||
96 | kfree(old_desc); | ||
97 | |||
98 | out_unlock: | ||
99 | spin_unlock_irqrestore(&sparse_irq_lock, flags); | ||
100 | |||
101 | return desc; | ||
102 | } | ||
103 | |||
104 | struct irq_desc *move_irq_desc(struct irq_desc *desc, int cpu) | ||
105 | { | ||
106 | int old_cpu; | ||
107 | int node, old_node; | ||
108 | |||
109 | /* those all static, do move them */ | ||
110 | if (desc->irq < NR_IRQS_LEGACY) | ||
111 | return desc; | ||
112 | |||
113 | old_cpu = desc->cpu; | ||
114 | printk(KERN_DEBUG | ||
115 | "try to move irq_desc from cpu %d to %d\n", old_cpu, cpu); | ||
116 | if (old_cpu != cpu) { | ||
117 | node = cpu_to_node(cpu); | ||
118 | old_node = cpu_to_node(old_cpu); | ||
119 | if (old_node != node) | ||
120 | desc = __real_move_irq_desc(desc, cpu); | ||
121 | else | ||
122 | desc->cpu = cpu; | ||
123 | } | ||
124 | |||
125 | return desc; | ||
126 | } | ||
127 | |||