diff --git a/arch/x86_64/kernel/io_apic.c b/arch/x86_64/kernel/io_apic.c index fe429e5..51535e8 100644 --- a/arch/x86_64/kernel/io_apic.c +++ b/arch/x86_64/kernel/io_apic.c @@ -613,8 +613,9 @@ static int __assign_irq_vector(int irq, * 0x80, because int 0x80 is hm, kind of importantish. ;) */ static int current_vector = FIRST_DEVICE_VECTOR, current_offset = 0; - int old_vector = -1; - int cpu; + int vector = -1, old_vector = -1; + cpumask_t domain, new_mask; + int cpu, new_cpu; BUG_ON((unsigned)irq >= NR_IRQ_VECTORS); @@ -624,15 +625,38 @@ static int __assign_irq_vector(int irq, if (irq_vector[irq] > 0) old_vector = irq_vector[irq]; if (old_vector > 0) { - cpus_and(*result, irq_domain[irq], mask); - if (!cpus_empty(*result)) - return old_vector; + /* try to reuse vector */ + for_each_cpu_mask(cpu, mask) { + int can_reuse = 1; + + domain = vector_allocation_domain(cpu); + cpus_and(new_mask, domain, cpu_online_map); + + if (cpus_equal(domain, irq_domain[irq])) { + cpus_and(*result, irq_domain[irq], mask); + if (!cpus_empty(*result)) + return old_vector; + } + + for_each_cpu_mask(new_cpu, new_mask) { + int old_irq; + old_irq = per_cpu(vector_irq, new_cpu)[old_vector]; + if ( (old_irq != irq) && (old_irq != -1)) { + can_reuse = 0; + break; + } + } + + if(!can_reuse) + continue; + + vector = old_vector; + goto found_one; + } } for_each_cpu_mask(cpu, mask) { - cpumask_t domain, new_mask; - int new_cpu; - int vector, offset; + int offset; domain = vector_allocation_domain(cpu); cpus_and(new_mask, domain, cpu_online_map); @@ -656,21 +680,27 @@ next: /* Found one! */ current_vector = vector; current_offset = offset; - if (old_vector >= 0) { - cpumask_t old_mask; - int old_cpu; - cpus_and(old_mask, irq_domain[irq], cpu_online_map); - for_each_cpu_mask(old_cpu, old_mask) - per_cpu(vector_irq, old_cpu)[old_vector] = -1; - } - for_each_cpu_mask(new_cpu, new_mask) - per_cpu(vector_irq, new_cpu)[vector] = irq; - irq_vector[irq] = vector; - irq_domain[irq] = domain; - cpus_and(*result, domain, mask); - return vector; + + goto found_one; } + return -ENOSPC; + +found_one: + if (old_vector >= 0) { + cpumask_t old_mask; + int old_cpu; + cpus_and(old_mask, irq_domain[irq], cpu_online_map); + for_each_cpu_mask(old_cpu, old_mask) + per_cpu(vector_irq, old_cpu)[old_vector] = -1; + } + for_each_cpu_mask(new_cpu, new_mask) + per_cpu(vector_irq, new_cpu)[vector] = irq; + irq_vector[irq] = vector; + irq_domain[irq] = domain; + cpus_and(*result, domain, mask); + return vector; + } static int assign_irq_vector(int irq, cpumask_t mask, cpumask_t *result)