Loading arch/x86/Kconfig +10 −1 Original line number Diff line number Diff line Loading @@ -243,7 +243,7 @@ config X86_HAS_BOOT_CPU_ID config SPARSE_IRQ bool "Support sparse irq numbering" depends on (PCI_MSI || HT_IRQ) && SMP depends on PCI_MSI || HT_IRQ default y help This enables support for sparse irq, esp for msi/msi-x. You may need Loading @@ -251,6 +251,15 @@ config SPARSE_IRQ If you don't know what to do here, say Y. config NUMA_MIGRATE_IRQ_DESC bool "Move irq desc when changing irq smp_affinity" depends on SPARSE_IRQ && SMP default n help This enables moving irq_desc to cpu/node that irq will use handled. If you don't know what to do here, say N. config X86_FIND_SMP_CONFIG def_bool y depends on X86_MPPARSE || X86_VOYAGER Loading arch/x86/kernel/io_apic.c +141 −1 Original line number Diff line number Diff line Loading @@ -141,6 +141,9 @@ struct irq_cfg { unsigned move_cleanup_count; u8 vector; u8 move_in_progress : 1; #ifdef CONFIG_NUMA_MIGRATE_IRQ_DESC u8 move_desc_pending : 1; #endif }; /* irq_cfg is indexed by the sum of all RTEs in all I/O APICs. */ Loading Loading @@ -241,6 +244,121 @@ void arch_init_chip_data(struct irq_desc *desc, int cpu) } } #ifdef CONFIG_NUMA_MIGRATE_IRQ_DESC static void init_copy_irq_2_pin(struct irq_cfg *old_cfg, struct irq_cfg *cfg, int cpu) { struct irq_pin_list *old_entry, *head, *tail, *entry; cfg->irq_2_pin = NULL; old_entry = old_cfg->irq_2_pin; if (!old_entry) return; entry = get_one_free_irq_2_pin(cpu); if (!entry) return; entry->apic = old_entry->apic; entry->pin = old_entry->pin; head = entry; tail = entry; old_entry = old_entry->next; while (old_entry) { entry = get_one_free_irq_2_pin(cpu); if (!entry) { entry = head; while (entry) { head = entry->next; kfree(entry); entry = head; } /* still use the old one */ return; } entry->apic = old_entry->apic; entry->pin = old_entry->pin; tail->next = entry; tail = entry; old_entry = old_entry->next; } tail->next = NULL; cfg->irq_2_pin = head; } static void free_irq_2_pin(struct irq_cfg *old_cfg, struct irq_cfg *cfg) { struct irq_pin_list *entry, *next; if (old_cfg->irq_2_pin == cfg->irq_2_pin) return; entry = old_cfg->irq_2_pin; while (entry) { next = entry->next; kfree(entry); entry = next; } old_cfg->irq_2_pin = NULL; } void arch_init_copy_chip_data(struct irq_desc *old_desc, struct irq_desc *desc, int cpu) { struct irq_cfg *cfg; struct irq_cfg *old_cfg; cfg = get_one_free_irq_cfg(cpu); if (!cfg) return; desc->chip_data = cfg; old_cfg = old_desc->chip_data; memcpy(cfg, old_cfg, sizeof(struct irq_cfg)); init_copy_irq_2_pin(old_cfg, cfg, cpu); } static void free_irq_cfg(struct irq_cfg *old_cfg) { kfree(old_cfg); } void arch_free_chip_data(struct irq_desc *old_desc, struct irq_desc *desc) { struct irq_cfg *old_cfg, *cfg; old_cfg = old_desc->chip_data; cfg = desc->chip_data; if (old_cfg == cfg) return; if (old_cfg) { free_irq_2_pin(old_cfg, cfg); free_irq_cfg(old_cfg); old_desc->chip_data = NULL; } } static void set_extra_move_desc(struct irq_desc *desc, cpumask_t mask) { struct irq_cfg *cfg = desc->chip_data; if (!cfg->move_in_progress) { /* it means that domain is not changed */ if (!cpus_intersects(desc->affinity, mask)) cfg->move_desc_pending = 1; } } #endif #else static struct irq_cfg *irq_cfg(unsigned int irq) { Loading @@ -249,10 +367,12 @@ static struct irq_cfg *irq_cfg(unsigned int irq) #endif #ifndef CONFIG_NUMA_MIGRATE_IRQ_DESC static inline void set_extra_move_desc(struct irq_desc *desc, const struct cpumask *mask) { } #endif struct io_apic { unsigned int index; Loading Loading @@ -2397,11 +2517,31 @@ static void irq_complete_move(struct irq_desc **descp) struct irq_cfg *cfg = desc->chip_data; unsigned vector, me; if (likely(!cfg->move_in_progress)) if (likely(!cfg->move_in_progress)) { #ifdef CONFIG_NUMA_MIGRATE_IRQ_DESC if (likely(!cfg->move_desc_pending)) return; /* domain is not change, but affinity is changed */ me = smp_processor_id(); if (cpu_isset(me, desc->affinity)) { *descp = desc = move_irq_desc(desc, me); /* get the new one */ cfg = desc->chip_data; cfg->move_desc_pending = 0; } #endif return; } vector = ~get_irq_regs()->orig_ax; me = smp_processor_id(); #ifdef CONFIG_NUMA_MIGRATE_IRQ_DESC *descp = desc = move_irq_desc(desc, me); /* get the new one */ cfg = desc->chip_data; #endif if (vector == cfg->vector && cpumask_test_cpu(me, cfg->domain)) send_cleanup_vector(cfg); } Loading drivers/pci/intr_remapping.c +1 −0 Original line number Diff line number Diff line Loading @@ -5,6 +5,7 @@ #include <linux/pci.h> #include <linux/irq.h> #include <asm/io_apic.h> #include <asm/smp.h> #include <linux/intel-iommu.h> #include "intr_remapping.h" Loading fs/proc/stat.c +2 −5 Original line number Diff line number Diff line Loading @@ -27,7 +27,6 @@ static int show_stat(struct seq_file *p, void *v) u64 sum = 0; struct timespec boottime; unsigned int per_irq_sum; struct irq_desc *desc; user = nice = system = idle = iowait = irq = softirq = steal = cputime64_zero; Loading @@ -47,8 +46,7 @@ static int show_stat(struct seq_file *p, void *v) guest = cputime64_add(guest, kstat_cpu(i).cpustat.guest); for_each_irq_nr(j) { #ifdef CONFIG_SPARSE_IRQ desc = irq_to_desc(j); if (!desc) if (!irq_to_desc(j)) continue; #endif sum += kstat_irqs_cpu(j, i); Loading Loading @@ -98,8 +96,7 @@ static int show_stat(struct seq_file *p, void *v) for_each_irq_nr(j) { per_irq_sum = 0; #ifdef CONFIG_SPARSE_IRQ desc = irq_to_desc(j); if (!desc) { if (!irq_to_desc(j)) { seq_printf(p, " %u", per_irq_sum); continue; } Loading include/linux/irq.h +10 −0 Original line number Diff line number Diff line Loading @@ -228,6 +228,16 @@ extern struct irq_desc *move_irq_desc(struct irq_desc *old_desc, int cpu); #endif static inline struct irq_desc * irq_remap_to_desc(unsigned int irq, struct irq_desc *desc) { #ifdef CONFIG_NUMA_MIGRATE_IRQ_DESC return irq_to_desc(irq); #else return desc; #endif } /* * Migration helpers for obsolete names, they will go away: */ Loading Loading
arch/x86/Kconfig +10 −1 Original line number Diff line number Diff line Loading @@ -243,7 +243,7 @@ config X86_HAS_BOOT_CPU_ID config SPARSE_IRQ bool "Support sparse irq numbering" depends on (PCI_MSI || HT_IRQ) && SMP depends on PCI_MSI || HT_IRQ default y help This enables support for sparse irq, esp for msi/msi-x. You may need Loading @@ -251,6 +251,15 @@ config SPARSE_IRQ If you don't know what to do here, say Y. config NUMA_MIGRATE_IRQ_DESC bool "Move irq desc when changing irq smp_affinity" depends on SPARSE_IRQ && SMP default n help This enables moving irq_desc to cpu/node that irq will use handled. If you don't know what to do here, say N. config X86_FIND_SMP_CONFIG def_bool y depends on X86_MPPARSE || X86_VOYAGER Loading
arch/x86/kernel/io_apic.c +141 −1 Original line number Diff line number Diff line Loading @@ -141,6 +141,9 @@ struct irq_cfg { unsigned move_cleanup_count; u8 vector; u8 move_in_progress : 1; #ifdef CONFIG_NUMA_MIGRATE_IRQ_DESC u8 move_desc_pending : 1; #endif }; /* irq_cfg is indexed by the sum of all RTEs in all I/O APICs. */ Loading Loading @@ -241,6 +244,121 @@ void arch_init_chip_data(struct irq_desc *desc, int cpu) } } #ifdef CONFIG_NUMA_MIGRATE_IRQ_DESC static void init_copy_irq_2_pin(struct irq_cfg *old_cfg, struct irq_cfg *cfg, int cpu) { struct irq_pin_list *old_entry, *head, *tail, *entry; cfg->irq_2_pin = NULL; old_entry = old_cfg->irq_2_pin; if (!old_entry) return; entry = get_one_free_irq_2_pin(cpu); if (!entry) return; entry->apic = old_entry->apic; entry->pin = old_entry->pin; head = entry; tail = entry; old_entry = old_entry->next; while (old_entry) { entry = get_one_free_irq_2_pin(cpu); if (!entry) { entry = head; while (entry) { head = entry->next; kfree(entry); entry = head; } /* still use the old one */ return; } entry->apic = old_entry->apic; entry->pin = old_entry->pin; tail->next = entry; tail = entry; old_entry = old_entry->next; } tail->next = NULL; cfg->irq_2_pin = head; } static void free_irq_2_pin(struct irq_cfg *old_cfg, struct irq_cfg *cfg) { struct irq_pin_list *entry, *next; if (old_cfg->irq_2_pin == cfg->irq_2_pin) return; entry = old_cfg->irq_2_pin; while (entry) { next = entry->next; kfree(entry); entry = next; } old_cfg->irq_2_pin = NULL; } void arch_init_copy_chip_data(struct irq_desc *old_desc, struct irq_desc *desc, int cpu) { struct irq_cfg *cfg; struct irq_cfg *old_cfg; cfg = get_one_free_irq_cfg(cpu); if (!cfg) return; desc->chip_data = cfg; old_cfg = old_desc->chip_data; memcpy(cfg, old_cfg, sizeof(struct irq_cfg)); init_copy_irq_2_pin(old_cfg, cfg, cpu); } static void free_irq_cfg(struct irq_cfg *old_cfg) { kfree(old_cfg); } void arch_free_chip_data(struct irq_desc *old_desc, struct irq_desc *desc) { struct irq_cfg *old_cfg, *cfg; old_cfg = old_desc->chip_data; cfg = desc->chip_data; if (old_cfg == cfg) return; if (old_cfg) { free_irq_2_pin(old_cfg, cfg); free_irq_cfg(old_cfg); old_desc->chip_data = NULL; } } static void set_extra_move_desc(struct irq_desc *desc, cpumask_t mask) { struct irq_cfg *cfg = desc->chip_data; if (!cfg->move_in_progress) { /* it means that domain is not changed */ if (!cpus_intersects(desc->affinity, mask)) cfg->move_desc_pending = 1; } } #endif #else static struct irq_cfg *irq_cfg(unsigned int irq) { Loading @@ -249,10 +367,12 @@ static struct irq_cfg *irq_cfg(unsigned int irq) #endif #ifndef CONFIG_NUMA_MIGRATE_IRQ_DESC static inline void set_extra_move_desc(struct irq_desc *desc, const struct cpumask *mask) { } #endif struct io_apic { unsigned int index; Loading Loading @@ -2397,11 +2517,31 @@ static void irq_complete_move(struct irq_desc **descp) struct irq_cfg *cfg = desc->chip_data; unsigned vector, me; if (likely(!cfg->move_in_progress)) if (likely(!cfg->move_in_progress)) { #ifdef CONFIG_NUMA_MIGRATE_IRQ_DESC if (likely(!cfg->move_desc_pending)) return; /* domain is not change, but affinity is changed */ me = smp_processor_id(); if (cpu_isset(me, desc->affinity)) { *descp = desc = move_irq_desc(desc, me); /* get the new one */ cfg = desc->chip_data; cfg->move_desc_pending = 0; } #endif return; } vector = ~get_irq_regs()->orig_ax; me = smp_processor_id(); #ifdef CONFIG_NUMA_MIGRATE_IRQ_DESC *descp = desc = move_irq_desc(desc, me); /* get the new one */ cfg = desc->chip_data; #endif if (vector == cfg->vector && cpumask_test_cpu(me, cfg->domain)) send_cleanup_vector(cfg); } Loading
drivers/pci/intr_remapping.c +1 −0 Original line number Diff line number Diff line Loading @@ -5,6 +5,7 @@ #include <linux/pci.h> #include <linux/irq.h> #include <asm/io_apic.h> #include <asm/smp.h> #include <linux/intel-iommu.h> #include "intr_remapping.h" Loading
fs/proc/stat.c +2 −5 Original line number Diff line number Diff line Loading @@ -27,7 +27,6 @@ static int show_stat(struct seq_file *p, void *v) u64 sum = 0; struct timespec boottime; unsigned int per_irq_sum; struct irq_desc *desc; user = nice = system = idle = iowait = irq = softirq = steal = cputime64_zero; Loading @@ -47,8 +46,7 @@ static int show_stat(struct seq_file *p, void *v) guest = cputime64_add(guest, kstat_cpu(i).cpustat.guest); for_each_irq_nr(j) { #ifdef CONFIG_SPARSE_IRQ desc = irq_to_desc(j); if (!desc) if (!irq_to_desc(j)) continue; #endif sum += kstat_irqs_cpu(j, i); Loading Loading @@ -98,8 +96,7 @@ static int show_stat(struct seq_file *p, void *v) for_each_irq_nr(j) { per_irq_sum = 0; #ifdef CONFIG_SPARSE_IRQ desc = irq_to_desc(j); if (!desc) { if (!irq_to_desc(j)) { seq_printf(p, " %u", per_irq_sum); continue; } Loading
include/linux/irq.h +10 −0 Original line number Diff line number Diff line Loading @@ -228,6 +228,16 @@ extern struct irq_desc *move_irq_desc(struct irq_desc *old_desc, int cpu); #endif static inline struct irq_desc * irq_remap_to_desc(unsigned int irq, struct irq_desc *desc) { #ifdef CONFIG_NUMA_MIGRATE_IRQ_DESC return irq_to_desc(irq); #else return desc; #endif } /* * Migration helpers for obsolete names, they will go away: */ Loading