Commit a0c9259d authored by Thomas Gleixner's avatar Thomas Gleixner

irq/matrix: Spread interrupts on allocation

Keith reported an issue with vector space exhaustion on a server machine
which is caused by the i40e driver allocating 168 MSI interrupts when the
driver is initialized, even when most of these interrupts are not used at
all.

The x86 vector allocation code tries to avoid the immediate allocation with
the reservation mode, but the card uses MSI and does not support MSI entry
masking, which prevents reservation mode and requires immediate vector
allocation.

The matrix allocator is a bit naive and prefers the first CPU in the
cpumask which describes the possible target CPUs for an allocation. That
results in allocating all 168 vectors on CPU0 which later causes vector
space exhaustion when the NVMe driver tries to allocate managed interrupts
on each CPU for the per CPU queues.

Avoid this by finding the CPU which has the lowest vector allocation count
to spread out the non managed interrupt accross the possible target CPUs.

Fixes: 2f75d9e1 ("genirq: Implement bitmap matrix allocator")
Reported-by: default avatarKeith Busch <keith.busch@intel.com>
Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
Tested-by: default avatarKeith Busch <keith.busch@intel.com>
Link: https://lkml.kernel.org/r/alpine.DEB.2.20.1801171557330.1777@nanos
parent 1d966eb4
...@@ -321,15 +321,23 @@ void irq_matrix_remove_reserved(struct irq_matrix *m) ...@@ -321,15 +321,23 @@ void irq_matrix_remove_reserved(struct irq_matrix *m)
int irq_matrix_alloc(struct irq_matrix *m, const struct cpumask *msk, int irq_matrix_alloc(struct irq_matrix *m, const struct cpumask *msk,
bool reserved, unsigned int *mapped_cpu) bool reserved, unsigned int *mapped_cpu)
{ {
unsigned int cpu; unsigned int cpu, best_cpu, maxavl = 0;
struct cpumap *cm;
unsigned int bit;
best_cpu = UINT_MAX;
for_each_cpu(cpu, msk) { for_each_cpu(cpu, msk) {
struct cpumap *cm = per_cpu_ptr(m->maps, cpu); cm = per_cpu_ptr(m->maps, cpu);
unsigned int bit;
if (!cm->online) if (!cm->online || cm->available <= maxavl)
continue; continue;
best_cpu = cpu;
maxavl = cm->available;
}
if (maxavl) {
cm = per_cpu_ptr(m->maps, best_cpu);
bit = matrix_alloc_area(m, cm, 1, false); bit = matrix_alloc_area(m, cm, 1, false);
if (bit < m->alloc_end) { if (bit < m->alloc_end) {
cm->allocated++; cm->allocated++;
...@@ -338,8 +346,8 @@ int irq_matrix_alloc(struct irq_matrix *m, const struct cpumask *msk, ...@@ -338,8 +346,8 @@ int irq_matrix_alloc(struct irq_matrix *m, const struct cpumask *msk,
m->global_available--; m->global_available--;
if (reserved) if (reserved)
m->global_reserved--; m->global_reserved--;
*mapped_cpu = cpu; *mapped_cpu = best_cpu;
trace_irq_matrix_alloc(bit, cpu, m, cm); trace_irq_matrix_alloc(bit, best_cpu, m, cm);
return bit; return bit;
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment